aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/.gitignore470
-rw-r--r--lib/Makefile15
-rw-r--r--lib/asn1/c_src/asn1_erl_nif.c10
-rw-r--r--lib/asn1/doc/src/Makefile11
-rw-r--r--lib/asn1/doc/src/asn1ct.xml14
-rw-r--r--lib/asn1/doc/src/notes.xml120
-rw-r--r--lib/asn1/src/asn1ct.erl11
-rw-r--r--lib/asn1/src/asn1ct_check.erl43
-rw-r--r--lib/asn1/src/asn1ct_gen.erl9
-rw-r--r--lib/asn1/src/asn1rtt_real_common.erl6
-rw-r--r--lib/asn1/test/Makefile2
-rw-r--r--lib/asn1/test/asn1_SUITE.erl78
-rw-r--r--lib/asn1/test/asn1_SUITE_data/ChoExtension.asn12
-rw-r--r--lib/asn1/test/asn1_SUITE_data/DefaultOctetString.asn15
-rw-r--r--lib/asn1/test/asn1_SUITE_data/IN-CS-1-Datatypes.asn2
-rw-r--r--lib/asn1/test/asn1_SUITE_data/SeqOfChoExt.asn127
-rw-r--r--lib/asn1/test/testChoExtension.erl1
-rw-r--r--lib/asn1/test/testDefaultOctetString.erl34
-rw-r--r--lib/asn1/test/testSeqOfChoExt.erl15
-rw-r--r--lib/asn1/test/testUniqueObjectSets.erl5
-rw-r--r--lib/asn1/test/test_modified_x420.erl2
-rw-r--r--lib/asn1/vsn.mk2
-rw-r--r--lib/common_test/doc/src/Makefile3
-rw-r--r--lib/common_test/doc/src/basics_chapter.xml2
-rw-r--r--lib/common_test/doc/src/common_test_app.xml43
-rw-r--r--lib/common_test/doc/src/ct.xml154
-rw-r--r--lib/common_test/doc/src/ct_cover.xml8
-rw-r--r--lib/common_test/doc/src/ct_ftp.xml34
-rw-r--r--lib/common_test/doc/src/ct_hooks.xml165
-rw-r--r--lib/common_test/doc/src/ct_hooks_chapter.xml45
-rw-r--r--lib/common_test/doc/src/ct_master.xml26
-rw-r--r--lib/common_test/doc/src/ct_netconfc.xml110
-rw-r--r--lib/common_test/doc/src/ct_property_test.xml6
-rw-r--r--lib/common_test/doc/src/ct_rpc.xml18
-rw-r--r--lib/common_test/doc/src/ct_slave.xml12
-rw-r--r--lib/common_test/doc/src/ct_snmp.xml38
-rw-r--r--lib/common_test/doc/src/ct_ssh.xml152
-rw-r--r--lib/common_test/doc/src/ct_telnet.xml63
-rw-r--r--lib/common_test/doc/src/ct_testspec.xml4
-rw-r--r--lib/common_test/doc/src/event_handler_chapter.xml2
-rw-r--r--lib/common_test/doc/src/notes.xml327
-rw-r--r--lib/common_test/doc/src/run_test_chapter.xml2
-rw-r--r--lib/common_test/doc/src/unix_telnet.xml6
-rw-r--r--lib/common_test/doc/src/write_test_chapter.xml18
-rw-r--r--lib/common_test/src/Makefile4
-rw-r--r--lib/common_test/src/common_test.app.src5
-rw-r--r--lib/common_test/src/ct.erl957
-rw-r--r--lib/common_test/src/ct_config.erl14
-rw-r--r--lib/common_test/src/ct_config_plain.erl4
-rw-r--r--lib/common_test/src/ct_conn_log_h.erl4
-rw-r--r--lib/common_test/src/ct_cover.erl47
-rw-r--r--lib/common_test/src/ct_default_gl.erl2
-rw-r--r--lib/common_test/src/ct_event.erl8
-rw-r--r--lib/common_test/src/ct_framework.erl399
-rw-r--r--lib/common_test/src/ct_ftp.erl143
-rw-r--r--lib/common_test/src/ct_gen_conn.erl97
-rw-r--r--lib/common_test/src/ct_groups.erl93
-rw-r--r--lib/common_test/src/ct_hooks.erl95
-rw-r--r--lib/common_test/src/ct_hooks_lock.erl14
-rw-r--r--lib/common_test/src/ct_logs.erl356
-rw-r--r--lib/common_test/src/ct_master.erl118
-rw-r--r--lib/common_test/src/ct_master_event.erl8
-rw-r--r--lib/common_test/src/ct_master_logs.erl26
-rw-r--r--lib/common_test/src/ct_master_status.erl8
-rw-r--r--lib/common_test/src/ct_netconfc.erl12
-rw-r--r--lib/common_test/src/ct_netconfc.hrl6
-rw-r--r--lib/common_test/src/ct_property_test.erl63
-rw-r--r--lib/common_test/src/ct_release_test.erl178
-rw-r--r--lib/common_test/src/ct_repeat.erl10
-rw-r--r--lib/common_test/src/ct_rpc.erl112
-rw-r--r--lib/common_test/src/ct_run.erl100
-rw-r--r--lib/common_test/src/ct_slave.erl189
-rw-r--r--lib/common_test/src/ct_snmp.erl289
-rw-r--r--lib/common_test/src/ct_ssh.erl619
-rw-r--r--lib/common_test/src/ct_telnet.erl555
-rw-r--r--lib/common_test/src/ct_telnet_client.erl6
-rw-r--r--lib/common_test/src/ct_testspec.erl6
-rw-r--r--lib/common_test/src/ct_util.erl133
-rw-r--r--lib/common_test/src/ct_util.hrl1
-rw-r--r--lib/common_test/src/ct_webtool.erl4
-rw-r--r--lib/common_test/src/ct_webtool_sup.erl2
-rw-r--r--lib/common_test/src/cth_log_redirect.erl265
-rw-r--r--lib/common_test/src/cth_surefire.erl21
-rw-r--r--lib/common_test/src/test_server.erl321
-rw-r--r--lib/common_test/src/test_server_ctrl.erl222
-rw-r--r--lib/common_test/src/test_server_node.erl134
-rw-r--r--lib/common_test/src/test_server_sup.erl8
-rw-r--r--lib/common_test/src/unix_telnet.erl65
-rw-r--r--lib/common_test/src/vts.erl4
-rw-r--r--lib/common_test/test/Makefile4
-rw-r--r--lib/common_test/test/ct_auto_clean_SUITE.erl2
-rw-r--r--lib/common_test/test/ct_auto_clean_SUITE_data/ac_SUITE.erl2
-rw-r--r--lib/common_test/test/ct_auto_clean_SUITE_data/cth_auto_clean.erl2
-rw-r--r--lib/common_test/test/ct_auto_compile_SUITE.erl4
-rw-r--r--lib/common_test/test/ct_config_SUITE.erl12
-rw-r--r--lib/common_test/test/ct_cover_SUITE_data/cover_SUITE.erl6
-rw-r--r--lib/common_test/test/ct_error_SUITE.erl49
-rw-r--r--lib/common_test/test/ct_error_SUITE_data/error/test/verify_config.erl38
-rw-r--r--lib/common_test/test/ct_event_handler_SUITE_data/eh_A.erl8
-rw-r--r--lib/common_test/test/ct_hooks_SUITE.erl476
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/all_and_groups_SUITE.erl47
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/all_and_groups_cth.erl100
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_cth_update_result_post_end_tc_SUITE.erl101
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_match_state_cth.erl58
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_scope_per_tc_cth_SUITE.erl22
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_scope_suite_group_only_cth_SUITE.erl54
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/cth_log_SUITE.erl4
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl70
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/update_result_post_end_tc_cth.erl98
-rw-r--r--lib/common_test/test/ct_log_SUITE.erl4
-rw-r--r--lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl18
-rw-r--r--lib/common_test/test/ct_netconfc_SUITE_data/ns.erl5
-rw-r--r--lib/common_test/test/ct_pre_post_test_io_SUITE.erl10
-rw-r--r--lib/common_test/test/ct_priv_dir_SUITE_data/priv_dir_SUITE.erl6
-rw-r--r--lib/common_test/test/ct_repeat_testrun_SUITE_data/a_test/r1_SUITE.erl10
-rw-r--r--lib/common_test/test/ct_repeat_testrun_SUITE_data/b_test/r2_SUITE.erl10
-rw-r--r--lib/common_test/test/ct_snmp_SUITE_data/snmp_SUITE.erl6
-rw-r--r--lib/common_test/test/ct_surefire_SUITE_data/surefire_SUITE.erl6
-rw-r--r--lib/common_test/test/ct_tc_repeat_SUITE.erl438
-rw-r--r--lib/common_test/test/ct_tc_repeat_SUITE_data/tc_repeat_SUITE.erl85
-rw-r--r--lib/common_test/test/ct_telnet_SUITE.erl39
-rw-r--r--lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_faulty_regexp_SUITE.erl79
-rw-r--r--lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl11
-rw-r--r--lib/common_test/test/ct_test_support.erl18
-rw-r--r--lib/common_test/test/ct_test_support_eh.erl8
-rw-r--r--lib/common_test/test/ct_unicode_SUITE.erl2
-rw-r--r--lib/common_test/test/ct_unicode_SUITE_data/unicode_atoms_SUITE.erl4
-rw-r--r--lib/common_test/test/ct_userconfig_callback.erl4
-rw-r--r--lib/common_test/test/ct_util_SUITE.erl490
-rw-r--r--lib/common_test/test/ct_util_SUITE_data/ct_util_cth.erl105
-rw-r--r--lib/common_test/test/ct_util_SUITE_data/curr_tc_SUITE.erl59
-rw-r--r--lib/common_test/test/ct_verbosity_SUITE_data/simple_evh.erl8
-rw-r--r--lib/common_test/test/erl2html2_SUITE.erl4
-rw-r--r--lib/common_test/test/telnet_server.erl20
-rw-r--r--lib/common_test/test/test_server_SUITE.erl19
-rw-r--r--lib/common_test/test/test_server_test_lib.erl6
-rw-r--r--lib/common_test/test_server/configure.in31
-rw-r--r--lib/common_test/test_server/ts.erl4
-rw-r--r--lib/common_test/test_server/ts_autoconf_win32.erl14
-rw-r--r--lib/common_test/test_server/ts_benchmark.erl2
-rw-r--r--lib/common_test/test_server/ts_erl_config.erl30
-rw-r--r--lib/common_test/test_server/ts_install.erl58
-rw-r--r--lib/common_test/test_server/ts_install_cth.erl37
-rw-r--r--lib/common_test/test_server/ts_lib.erl10
-rw-r--r--lib/common_test/test_server/ts_run.erl18
-rw-r--r--lib/common_test/vsn.mk2
-rw-r--r--lib/compiler/doc/src/Makefile14
-rw-r--r--lib/compiler/doc/src/book.xml3
-rw-r--r--lib/compiler/doc/src/compile.xml99
-rw-r--r--lib/compiler/doc/src/internal.xml38
-rw-r--r--lib/compiler/doc/src/notes.xml617
-rw-r--r--lib/compiler/internal_doc/cerl-notes.md75
-rw-r--r--lib/compiler/scripts/.gitignore1
-rwxr-xr-xlib/compiler/scripts/smoke123
-rw-r--r--lib/compiler/scripts/smoke-mix.exs103
-rw-r--r--lib/compiler/src/Makefile57
-rw-r--r--lib/compiler/src/beam_a.erl57
-rw-r--r--lib/compiler/src/beam_asm.erl85
-rw-r--r--lib/compiler/src/beam_block.erl432
-rw-r--r--lib/compiler/src/beam_bs.erl281
-rw-r--r--lib/compiler/src/beam_bsm.erl702
-rw-r--r--lib/compiler/src/beam_clean.erl255
-rw-r--r--lib/compiler/src/beam_dead.erl927
-rw-r--r--lib/compiler/src/beam_dict.erl15
-rw-r--r--lib/compiler/src/beam_disasm.erl128
-rw-r--r--lib/compiler/src/beam_disasm.hrl5
-rw-r--r--lib/compiler/src/beam_except.erl173
-rw-r--r--lib/compiler/src/beam_flatten.erl78
-rw-r--r--lib/compiler/src/beam_jump.erl445
-rw-r--r--lib/compiler/src/beam_kernel_to_ssa.erl1312
-rw-r--r--lib/compiler/src/beam_listing.erl91
-rw-r--r--lib/compiler/src/beam_peep.erl82
-rw-r--r--lib/compiler/src/beam_receive.erl415
-rw-r--r--lib/compiler/src/beam_record.erl106
-rw-r--r--lib/compiler/src/beam_reorder.erl151
-rw-r--r--lib/compiler/src/beam_split.erl95
-rw-r--r--lib/compiler/src/beam_ssa.erl890
-rw-r--r--lib/compiler/src/beam_ssa.hrl66
-rw-r--r--lib/compiler/src/beam_ssa_bsm.erl1046
-rw-r--r--lib/compiler/src/beam_ssa_codegen.erl2077
-rw-r--r--lib/compiler/src/beam_ssa_dead.erl1076
-rw-r--r--lib/compiler/src/beam_ssa_funs.erl149
-rw-r--r--lib/compiler/src/beam_ssa_lint.erl349
-rw-r--r--lib/compiler/src/beam_ssa_opt.erl2279
-rw-r--r--lib/compiler/src/beam_ssa_opt.hrl53
-rw-r--r--lib/compiler/src/beam_ssa_pp.erl238
-rw-r--r--lib/compiler/src/beam_ssa_pre_codegen.erl2850
-rw-r--r--lib/compiler/src/beam_ssa_recv.erl278
-rw-r--r--lib/compiler/src/beam_ssa_share.erl370
-rw-r--r--lib/compiler/src/beam_ssa_type.erl1956
-rw-r--r--lib/compiler/src/beam_trim.erl326
-rw-r--r--lib/compiler/src/beam_type.erl937
-rw-r--r--lib/compiler/src/beam_utils.erl857
-rw-r--r--lib/compiler/src/beam_validator.erl2991
-rw-r--r--lib/compiler/src/beam_z.erl66
-rw-r--r--lib/compiler/src/cerl.erl18
-rw-r--r--lib/compiler/src/cerl_clauses.erl6
-rw-r--r--lib/compiler/src/cerl_inline.erl17
-rw-r--r--lib/compiler/src/cerl_sets.erl2
-rw-r--r--lib/compiler/src/cerl_trees.erl116
-rw-r--r--lib/compiler/src/compile.erl343
-rw-r--r--lib/compiler/src/compiler.app.src27
-rw-r--r--lib/compiler/src/core_lint.erl18
-rw-r--r--lib/compiler/src/core_parse.hrl107
-rw-r--r--lib/compiler/src/core_parse.yrl10
-rw-r--r--lib/compiler/src/core_pp.erl10
-rw-r--r--lib/compiler/src/core_scan.erl4
-rw-r--r--lib/compiler/src/erl_bifs.erl25
-rwxr-xr-xlib/compiler/src/genop.tab57
-rw-r--r--lib/compiler/src/sys_core_alias.erl307
-rw-r--r--lib/compiler/src/sys_core_bsm.erl340
-rw-r--r--lib/compiler/src/sys_core_dsetel.erl361
-rw-r--r--lib/compiler/src/sys_core_fold.erl725
-rw-r--r--lib/compiler/src/sys_core_fold_lists.erl101
-rw-r--r--lib/compiler/src/sys_core_inline.erl9
-rw-r--r--lib/compiler/src/v3_codegen.erl2298
-rw-r--r--lib/compiler/src/v3_core.erl144
-rw-r--r--lib/compiler/src/v3_kernel.erl320
-rw-r--r--lib/compiler/src/v3_kernel.hrl4
-rw-r--r--lib/compiler/src/v3_kernel_pp.erl11
-rw-r--r--lib/compiler/src/v3_life.erl468
-rw-r--r--lib/compiler/src/v3_life.hrl29
-rw-r--r--lib/compiler/test/Makefile46
-rw-r--r--lib/compiler/test/andor_SUITE.erl4
-rw-r--r--lib/compiler/test/apply_SUITE.erl12
-rw-r--r--lib/compiler/test/beam_block_SUITE.erl76
-rw-r--r--lib/compiler/test/beam_except_SUITE.erl53
-rw-r--r--lib/compiler/test/beam_jump_SUITE.erl144
-rw-r--r--lib/compiler/test/beam_reorder_SUITE.erl4
-rw-r--r--lib/compiler/test/beam_ssa_SUITE.erl497
-rw-r--r--lib/compiler/test/beam_type_SUITE.erl277
-rw-r--r--lib/compiler/test/beam_utils_SUITE.erl222
-rw-r--r--lib/compiler/test/beam_validator_SUITE.erl240
-rw-r--r--lib/compiler/test/beam_validator_SUITE_data/bad_bin_match.S2
-rw-r--r--lib/compiler/test/beam_validator_SUITE_data/bad_try_catch_nesting.S64
-rw-r--r--lib/compiler/test/beam_validator_SUITE_data/bad_tuples.S88
-rw-r--r--lib/compiler/test/beam_validator_SUITE_data/merge_undefined.S4
-rw-r--r--lib/compiler/test/beam_validator_SUITE_data/receive_stacked.S390
-rw-r--r--lib/compiler/test/beam_validator_SUITE_data/receive_stacked.erl92
-rw-r--r--lib/compiler/test/bif_SUITE.erl11
-rw-r--r--lib/compiler/test/bs_bincomp_SUITE.erl15
-rw-r--r--lib/compiler/test/bs_bit_binaries_SUITE.erl6
-rw-r--r--lib/compiler/test/bs_construct_SUITE.erl40
-rw-r--r--lib/compiler/test/bs_match_SUITE.erl460
-rw-r--r--lib/compiler/test/bs_utf_SUITE.erl4
-rw-r--r--lib/compiler/test/compilation_SUITE.erl10
-rw-r--r--lib/compiler/test/compilation_SUITE_data/opt_crash.erl8
-rw-r--r--lib/compiler/test/compile_SUITE.erl439
-rw-r--r--lib/compiler/test/compile_SUITE_data/big.erl6
-rw-r--r--lib/compiler/test/compiler.cover5
-rw-r--r--lib/compiler/test/core_SUITE.erl10
-rw-r--r--lib/compiler/test/core_SUITE_data/fun_letrec_effect.core25
-rw-r--r--lib/compiler/test/core_SUITE_data/name_capture.core110
-rw-r--r--lib/compiler/test/core_alias_SUITE.erl195
-rw-r--r--lib/compiler/test/core_fold_SUITE.erl132
-rw-r--r--lib/compiler/test/error_SUITE.erl4
-rw-r--r--lib/compiler/test/float_SUITE.erl38
-rw-r--r--lib/compiler/test/fun_SUITE.erl22
-rw-r--r--lib/compiler/test/guard_SUITE.erl91
-rw-r--r--lib/compiler/test/guard_SUITE_data/guard_SUITE_tuple_size.S30
-rw-r--r--lib/compiler/test/inline_SUITE.erl44
-rw-r--r--lib/compiler/test/inline_SUITE_data/barnes2.erl2
-rw-r--r--lib/compiler/test/lc_SUITE.erl37
-rw-r--r--lib/compiler/test/map_SUITE.erl305
-rw-r--r--lib/compiler/test/match_SUITE.erl323
-rw-r--r--lib/compiler/test/misc_SUITE.erl164
-rw-r--r--lib/compiler/test/overridden_bif_SUITE.erl4
-rw-r--r--lib/compiler/test/receive_SUITE.erl143
-rw-r--r--lib/compiler/test/receive_SUITE_data/ref_opt/no_5.erl38
-rw-r--r--lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.S71
-rw-r--r--lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.erl27
-rw-r--r--lib/compiler/test/record_SUITE.erl4
-rw-r--r--lib/compiler/test/regressions_SUITE.erl21
-rw-r--r--lib/compiler/test/test_lib.erl76
-rw-r--r--lib/compiler/test/trycatch_SUITE.erl285
-rw-r--r--lib/compiler/test/warnings_SUITE.erl88
-rw-r--r--lib/compiler/test/z_SUITE.erl7
-rw-r--r--lib/compiler/vsn.mk2
-rw-r--r--lib/configure.in.src62
-rw-r--r--lib/cosEvent/AUTHORS5
-rw-r--r--lib/cosEvent/Makefile42
-rw-r--r--lib/cosEvent/doc/src/CosEventChannelAdmin.xml78
-rw-r--r--lib/cosEvent/doc/src/CosEventChannelAdmin_ConsumerAdmin.xml73
-rw-r--r--lib/cosEvent/doc/src/CosEventChannelAdmin_EventChannel.xml95
-rw-r--r--lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPullConsumer.xml85
-rw-r--r--lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPullSupplier.xml112
-rw-r--r--lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPushConsumer.xml99
-rw-r--r--lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPushSupplier.xml85
-rw-r--r--lib/cosEvent/doc/src/CosEventChannelAdmin_SupplierAdmin.xml73
-rw-r--r--lib/cosEvent/doc/src/Makefile145
-rw-r--r--lib/cosEvent/doc/src/book.xml50
-rw-r--r--lib/cosEvent/doc/src/ch_contents.xml71
-rw-r--r--lib/cosEvent/doc/src/ch_event_service.xml222
-rw-r--r--lib/cosEvent/doc/src/ch_introduction.xml57
-rw-r--r--lib/cosEvent/doc/src/cosEventApp.xml169
-rw-r--r--lib/cosEvent/doc/src/e_s_components.gifbin4458 -> 0 bytes
-rw-r--r--lib/cosEvent/doc/src/e_s_models.gifbin10354 -> 0 bytes
-rw-r--r--lib/cosEvent/doc/src/notes.xml348
-rw-r--r--lib/cosEvent/doc/src/part.xml40
-rw-r--r--lib/cosEvent/doc/src/ref_man.xml46
-rw-r--r--lib/cosEvent/info2
-rw-r--r--lib/cosEvent/src/CosEventChannelAdmin.cfg6
-rw-r--r--lib/cosEvent/src/CosEventChannelAdmin.idl66
-rw-r--r--lib/cosEvent/src/CosEventChannelAdmin_ProxyPullConsumer_impl.erl206
-rw-r--r--lib/cosEvent/src/CosEventChannelAdmin_ProxyPushConsumer_impl.erl170
-rw-r--r--lib/cosEvent/src/CosEventChannelAdmin_SupplierAdmin_impl.erl160
-rw-r--r--lib/cosEvent/src/CosEventComm.idl37
-rw-r--r--lib/cosEvent/src/Makefile217
-rw-r--r--lib/cosEvent/src/cosEvent.app.src46
-rw-r--r--lib/cosEvent/src/cosEvent.appup.src6
-rw-r--r--lib/cosEvent/src/cosEventApp.cfg15
-rw-r--r--lib/cosEvent/src/cosEventApp.erl301
-rw-r--r--lib/cosEvent/src/cosEventApp.hrl63
-rw-r--r--lib/cosEvent/src/cosEventApp.idl26
-rw-r--r--lib/cosEvent/src/oe_CosEventComm_CAdmin_impl.erl234
-rw-r--r--lib/cosEvent/src/oe_CosEventComm_Channel_impl.erl247
-rw-r--r--lib/cosEvent/src/oe_CosEventComm_PullerS_impl.erl282
-rw-r--r--lib/cosEvent/src/oe_CosEventComm_PusherS_impl.erl218
-rw-r--r--lib/cosEvent/test/Makefile150
-rw-r--r--lib/cosEvent/test/cosEvent.cover2
-rw-r--r--lib/cosEvent/test/cosEvent.spec1
-rw-r--r--lib/cosEvent/test/event_channel_SUITE.erl326
-rw-r--r--lib/cosEvent/test/event_test_PullC_impl.erl44
-rw-r--r--lib/cosEvent/test/event_test_PullS_impl.erl58
-rw-r--r--lib/cosEvent/test/event_test_PushC_impl.erl47
-rw-r--r--lib/cosEvent/test/event_test_PushS_impl.erl42
-rw-r--r--lib/cosEvent/test/event_test_server.idl48
-rw-r--r--lib/cosEvent/test/generated_SUITE.erl473
-rw-r--r--lib/cosEvent/vsn.mk2
-rw-r--r--lib/cosEventDomain/AUTHORS4
-rw-r--r--lib/cosEventDomain/Makefile42
-rw-r--r--lib/cosEventDomain/doc/pdf/.gitignore0
-rw-r--r--lib/cosEventDomain/doc/src/CosEventDomainAdmin.xml93
-rw-r--r--lib/cosEventDomain/doc/src/CosEventDomainAdmin_EventDomain.xml627
-rw-r--r--lib/cosEventDomain/doc/src/CosEventDomainAdmin_EventDomainFactory.xml88
-rw-r--r--lib/cosEventDomain/doc/src/Makefile137
-rw-r--r--lib/cosEventDomain/doc/src/book.xml49
-rw-r--r--lib/cosEventDomain/doc/src/ch_QoS.xml118
-rw-r--r--lib/cosEventDomain/doc/src/ch_contents.xml69
-rw-r--r--lib/cosEventDomain/doc/src/ch_event_domain_service.xml111
-rw-r--r--lib/cosEventDomain/doc/src/ch_introduction.xml53
-rw-r--r--lib/cosEventDomain/doc/src/cosEventDomainApp.xml150
-rw-r--r--lib/cosEventDomain/doc/src/notes.xml331
-rw-r--r--lib/cosEventDomain/doc/src/part.xml40
-rw-r--r--lib/cosEventDomain/doc/src/ref_man.xml40
-rw-r--r--lib/cosEventDomain/ebin/.gitignore0
-rw-r--r--lib/cosEventDomain/example/.gitignore0
-rw-r--r--lib/cosEventDomain/include/.gitignore0
-rw-r--r--lib/cosEventDomain/info2
-rw-r--r--lib/cosEventDomain/src/CosEventDomainAdmin.cfg4
-rw-r--r--lib/cosEventDomain/src/CosEventDomainAdmin.idl280
-rw-r--r--lib/cosEventDomain/src/CosEventDomainAdmin_EventDomainFactory_impl.erl183
-rw-r--r--lib/cosEventDomain/src/CosEventDomainAdmin_EventDomain_impl.erl1426
-rw-r--r--lib/cosEventDomain/src/Makefile185
-rw-r--r--lib/cosEventDomain/src/cosEventDomain.app.src33
-rw-r--r--lib/cosEventDomain/src/cosEventDomain.appup.src6
-rw-r--r--lib/cosEventDomain/src/cosEventDomainApp.erl341
-rw-r--r--lib/cosEventDomain/src/cosEventDomainApp.hrl70
-rw-r--r--lib/cosEventDomain/test/Makefile104
-rw-r--r--lib/cosEventDomain/test/cosEventDomain.cover2
-rw-r--r--lib/cosEventDomain/test/cosEventDomain.spec1
-rw-r--r--lib/cosEventDomain/test/event_domain_SUITE.erl464
-rw-r--r--lib/cosEventDomain/test/generated_SUITE.erl384
-rw-r--r--lib/cosEventDomain/vsn.mk2
-rw-r--r--lib/cosFileTransfer/AUTHORS4
-rw-r--r--lib/cosFileTransfer/Makefile42
-rw-r--r--lib/cosFileTransfer/doc/html/.gitignore0
-rw-r--r--lib/cosFileTransfer/doc/man3/.gitignore0
-rw-r--r--lib/cosFileTransfer/doc/man6/.gitignore0
-rw-r--r--lib/cosFileTransfer/doc/pdf/.gitignore0
-rw-r--r--lib/cosFileTransfer/doc/src/CosFileTransfer.gifbin10889 -> 0 bytes
-rw-r--r--lib/cosFileTransfer/doc/src/CosFileTransfer_Directory.xml69
-rw-r--r--lib/cosFileTransfer/doc/src/CosFileTransfer_File.xml94
-rw-r--r--lib/cosFileTransfer/doc/src/CosFileTransfer_FileIterator.xml86
-rw-r--r--lib/cosFileTransfer/doc/src/CosFileTransfer_FileTransferSession.xml191
-rw-r--r--lib/cosFileTransfer/doc/src/CosFileTransfer_VirtualFileSystem.xml83
-rw-r--r--lib/cosFileTransfer/doc/src/Makefile142
-rw-r--r--lib/cosFileTransfer/doc/src/book.xml49
-rw-r--r--lib/cosFileTransfer/doc/src/ch_contents.xml75
-rw-r--r--lib/cosFileTransfer/doc/src/ch_example.xml96
-rw-r--r--lib/cosFileTransfer/doc/src/ch_install.xml58
-rw-r--r--lib/cosFileTransfer/doc/src/ch_introduction.xml57
-rw-r--r--lib/cosFileTransfer/doc/src/ch_system.xml138
-rw-r--r--lib/cosFileTransfer/doc/src/cosFileTransferApp.xml173
-rw-r--r--lib/cosFileTransfer/doc/src/notes.xml379
-rw-r--r--lib/cosFileTransfer/doc/src/part.xml41
-rw-r--r--lib/cosFileTransfer/doc/src/ref_man.xml42
-rw-r--r--lib/cosFileTransfer/ebin/.gitignore0
-rw-r--r--lib/cosFileTransfer/examples/.gitignore0
-rw-r--r--lib/cosFileTransfer/include/.gitignore0
-rw-r--r--lib/cosFileTransfer/info3
-rw-r--r--lib/cosFileTransfer/priv/.gitignore0
-rw-r--r--lib/cosFileTransfer/src/CosFileTransfer.cfg10
-rw-r--r--lib/cosFileTransfer/src/CosFileTransfer.idl157
-rw-r--r--lib/cosFileTransfer/src/CosFileTransfer_Directory_impl.erl453
-rw-r--r--lib/cosFileTransfer/src/CosFileTransfer_FileIterator_impl.erl158
-rw-r--r--lib/cosFileTransfer/src/CosFileTransfer_FileTransferSession_impl.erl1061
-rw-r--r--lib/cosFileTransfer/src/CosFileTransfer_File_impl.erl385
-rw-r--r--lib/cosFileTransfer/src/CosFileTransfer_VirtualFileSystem_impl.erl217
-rw-r--r--lib/cosFileTransfer/src/Makefile188
-rw-r--r--lib/cosFileTransfer/src/cosFileTransfer.app.src43
-rw-r--r--lib/cosFileTransfer/src/cosFileTransfer.appup.src7
-rw-r--r--lib/cosFileTransfer/src/cosFileTransferApp.erl471
-rw-r--r--lib/cosFileTransfer/src/cosFileTransferApp.hrl69
-rw-r--r--lib/cosFileTransfer/src/cosFileTransferNATIVE_file.erl359
-rw-r--r--lib/cosFileTransfer/test/Makefile132
-rw-r--r--lib/cosFileTransfer/test/cosFileTransfer.cover2
-rw-r--r--lib/cosFileTransfer/test/cosFileTransfer.spec1
-rw-r--r--lib/cosFileTransfer/test/fileTransfer_SUITE.erl938
-rw-r--r--lib/cosFileTransfer/vsn.mk1
-rw-r--r--lib/cosNotification/AUTHORS4
-rw-r--r--lib/cosNotification/Makefile42
-rw-r--r--lib/cosNotification/doc/html/.gitignore0
-rw-r--r--lib/cosNotification/doc/man3/.gitignore0
-rw-r--r--lib/cosNotification/doc/man6/.gitignore0
-rw-r--r--lib/cosNotification/doc/pdf/.gitignore0
-rw-r--r--lib/cosNotification/doc/src/CosNotification.xml235
-rw-r--r--lib/cosNotification/doc/src/CosNotification_AdminPropertiesAdmin.xml79
-rw-r--r--lib/cosNotification/doc/src/CosNotification_QoSAdmin.xml107
-rw-r--r--lib/cosNotification/doc/src/CosNotifyChannelAdmin_ConsumerAdmin.xml242
-rw-r--r--lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannel.xml226
-rw-r--r--lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannelFactory.xml89
-rw-r--r--lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyConsumer.xml128
-rw-r--r--lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullConsumer.xml113
-rw-r--r--lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullSupplier.xml112
-rw-r--r--lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushConsumer.xml98
-rw-r--r--lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushSupplier.xml110
-rw-r--r--lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxySupplier.xml175
-rw-r--r--lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullConsumer.xml112
-rw-r--r--lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullSupplier.xml146
-rw-r--r--lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushConsumer.xml109
-rw-r--r--lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushSupplier.xml111
-rw-r--r--lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullConsumer.xml110
-rw-r--r--lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullSupplier.xml140
-rw-r--r--lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushConsumer.xml110
-rw-r--r--lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushSupplier.xml110
-rw-r--r--lib/cosNotification/doc/src/CosNotifyChannelAdmin_SupplierAdmin.xml195
-rw-r--r--lib/cosNotification/doc/src/CosNotifyComm_NotifyPublish.xml66
-rw-r--r--lib/cosNotification/doc/src/CosNotifyComm_NotifySubscribe.xml64
-rw-r--r--lib/cosNotification/doc/src/CosNotifyFilter_Filter.xml223
-rw-r--r--lib/cosNotification/doc/src/CosNotifyFilter_FilterAdmin.xml112
-rw-r--r--lib/cosNotification/doc/src/CosNotifyFilter_FilterFactory.xml74
-rw-r--r--lib/cosNotification/doc/src/CosNotifyFilter_MappingFilter.xml228
-rw-r--r--lib/cosNotification/doc/src/Makefile167
-rw-r--r--lib/cosNotification/doc/src/book.xml49
-rw-r--r--lib/cosNotification/doc/src/ch_BNF.xml457
-rw-r--r--lib/cosNotification/doc/src/ch_QoS.xml252
-rw-r--r--lib/cosNotification/doc/src/ch_contents.xml75
-rw-r--r--lib/cosNotification/doc/src/ch_example.xml170
-rw-r--r--lib/cosNotification/doc/src/ch_install.xml147
-rw-r--r--lib/cosNotification/doc/src/ch_introduction.xml58
-rw-r--r--lib/cosNotification/doc/src/ch_system.xml84
-rw-r--r--lib/cosNotification/doc/src/cosNotificationApp.xml309
-rw-r--r--lib/cosNotification/doc/src/eventstructure.gifbin89760 -> 0 bytes
-rw-r--r--lib/cosNotification/doc/src/notes.xml632
-rw-r--r--lib/cosNotification/doc/src/notificationFlow.gifbin167734 -> 0 bytes
-rw-r--r--lib/cosNotification/doc/src/part.xml43
-rw-r--r--lib/cosNotification/doc/src/ref_man.xml64
-rw-r--r--lib/cosNotification/ebin/.gitignore0
-rw-r--r--lib/cosNotification/examples/.gitignore0
-rw-r--r--lib/cosNotification/include/.gitignore0
-rw-r--r--lib/cosNotification/info3
-rw-r--r--lib/cosNotification/priv/.gitignore0
-rw-r--r--lib/cosNotification/src/CosEvent.cfg20
-rw-r--r--lib/cosNotification/src/CosNotification.cfg0
-rw-r--r--lib/cosNotification/src/CosNotification.idl146
-rw-r--r--lib/cosNotification/src/CosNotification_Common.erl1240
-rw-r--r--lib/cosNotification/src/CosNotification_Definitions.hrl343
-rw-r--r--lib/cosNotification/src/CosNotifyChannelAdmin.cfg60
-rw-r--r--lib/cosNotification/src/CosNotifyChannelAdmin.idl275
-rw-r--r--lib/cosNotification/src/CosNotifyChannelAdmin_ConsumerAdmin_impl.erl671
-rw-r--r--lib/cosNotification/src/CosNotifyChannelAdmin_EventChannelFactory_impl.erl143
-rw-r--r--lib/cosNotification/src/CosNotifyChannelAdmin_EventChannel_impl.erl722
-rw-r--r--lib/cosNotification/src/CosNotifyChannelAdmin_SupplierAdmin_impl.erl580
-rw-r--r--lib/cosNotification/src/CosNotifyComm.cfg0
-rw-r--r--lib/cosNotification/src/CosNotifyComm.idl83
-rw-r--r--lib/cosNotification/src/CosNotifyFilter.cfg6
-rw-r--r--lib/cosNotification/src/CosNotifyFilter.idl140
-rw-r--r--lib/cosNotification/src/CosNotifyFilter_FilterFactory_impl.erl126
-rw-r--r--lib/cosNotification/src/CosNotifyFilter_Filter_impl.erl672
-rw-r--r--lib/cosNotification/src/CosNotifyFilter_MappingFilter_impl.erl580
-rw-r--r--lib/cosNotification/src/CosTypedEvent.idl57
-rw-r--r--lib/cosNotification/src/CosTypedNotification.idl109
-rw-r--r--lib/cosNotification/src/Makefile379
-rw-r--r--lib/cosNotification/src/PullerConsumer_impl.erl774
-rw-r--r--lib/cosNotification/src/PullerSupplier_impl.erl915
-rw-r--r--lib/cosNotification/src/PusherConsumer_impl.erl730
-rw-r--r--lib/cosNotification/src/PusherSupplier_impl.erl1053
-rw-r--r--lib/cosNotification/src/cosNotification.app.src122
-rw-r--r--lib/cosNotification/src/cosNotification.appup.src7
-rw-r--r--lib/cosNotification/src/cosNotificationApp.erl436
-rw-r--r--lib/cosNotification/src/cosNotificationAppComm.idl17
-rw-r--r--lib/cosNotification/src/cosNotificationComm.cfg3
-rw-r--r--lib/cosNotification/src/cosNotification_Filter.erl965
-rw-r--r--lib/cosNotification/src/cosNotification_Grammar.yrl168
-rw-r--r--lib/cosNotification/src/cosNotification_Scanner.erl269
-rw-r--r--lib/cosNotification/src/cosNotification_eventDB.erl1351
-rw-r--r--lib/cosNotification/test/Makefile192
-rw-r--r--lib/cosNotification/test/cosNotification.cover2
-rw-r--r--lib/cosNotification/test/cosNotification.spec1
-rw-r--r--lib/cosNotification/test/eventDB_SUITE.erl896
-rw-r--r--lib/cosNotification/test/generated_SUITE.erl1928
-rw-r--r--lib/cosNotification/test/grammar_SUITE.erl1091
-rw-r--r--lib/cosNotification/test/notification_SUITE.erl2163
-rw-r--r--lib/cosNotification/test/notify_test_impl.erl300
-rw-r--r--lib/cosNotification/test/notify_test_server.cfg55
-rw-r--r--lib/cosNotification/test/notify_test_server.idl114
-rw-r--r--lib/cosNotification/vsn.mk2
-rw-r--r--lib/cosProperty/AUTHORS4
-rw-r--r--lib/cosProperty/Makefile42
-rw-r--r--lib/cosProperty/doc/html/.gitignore0
-rw-r--r--lib/cosProperty/doc/man3/.gitignore0
-rw-r--r--lib/cosProperty/doc/man6/.gitignore0
-rw-r--r--lib/cosProperty/doc/pdf/.gitignore0
-rw-r--r--lib/cosProperty/doc/src/CosPropertyService_PropertiesIterator.xml95
-rw-r--r--lib/cosProperty/doc/src/CosPropertyService_PropertyNamesIterator.xml97
-rw-r--r--lib/cosProperty/doc/src/CosPropertyService_PropertySet.xml201
-rw-r--r--lib/cosProperty/doc/src/CosPropertyService_PropertySetDef.xml168
-rw-r--r--lib/cosProperty/doc/src/CosPropertyService_PropertySetDefFactory.xml95
-rw-r--r--lib/cosProperty/doc/src/CosPropertyService_PropertySetFactory.xml93
-rw-r--r--lib/cosProperty/doc/src/Makefile144
-rw-r--r--lib/cosProperty/doc/src/book.xml49
-rw-r--r--lib/cosProperty/doc/src/ch_contents.xml75
-rw-r--r--lib/cosProperty/doc/src/ch_example.xml76
-rw-r--r--lib/cosProperty/doc/src/ch_install.xml56
-rw-r--r--lib/cosProperty/doc/src/ch_introduction.xml54
-rw-r--r--lib/cosProperty/doc/src/cosProperty.xml150
-rw-r--r--lib/cosProperty/doc/src/notes.xml377
-rw-r--r--lib/cosProperty/doc/src/part.xml40
-rw-r--r--lib/cosProperty/doc/src/ref_man.xml43
-rw-r--r--lib/cosProperty/ebin/.gitignore0
-rw-r--r--lib/cosProperty/examples/.gitignore0
-rw-r--r--lib/cosProperty/include/.gitignore0
-rw-r--r--lib/cosProperty/info2
-rw-r--r--lib/cosProperty/priv/.gitignore0
-rw-r--r--lib/cosProperty/src/CosProperty.cfg5
-rw-r--r--lib/cosProperty/src/CosProperty.idl192
-rw-r--r--lib/cosProperty/src/CosPropertyService_PropertiesIterator_impl.erl167
-rw-r--r--lib/cosProperty/src/CosPropertyService_PropertyNamesIterator_impl.erl159
-rw-r--r--lib/cosProperty/src/CosPropertyService_PropertySetDefFactory_impl.erl186
-rw-r--r--lib/cosProperty/src/CosPropertyService_PropertySetDef_impl.erl1042
-rw-r--r--lib/cosProperty/src/CosPropertyService_PropertySetFactory_impl.erl183
-rw-r--r--lib/cosProperty/src/Makefile188
-rw-r--r--lib/cosProperty/src/cosProperty.app.src47
-rw-r--r--lib/cosProperty/src/cosProperty.appup.src6
-rw-r--r--lib/cosProperty/src/cosProperty.erl416
-rw-r--r--lib/cosProperty/src/cosProperty.hrl82
-rw-r--r--lib/cosProperty/test/Makefile129
-rw-r--r--lib/cosProperty/test/cosProperty.cover2
-rw-r--r--lib/cosProperty/test/cosProperty.spec1
-rw-r--r--lib/cosProperty/test/generated_SUITE.erl546
-rw-r--r--lib/cosProperty/test/property_SUITE.erl736
-rw-r--r--lib/cosProperty/vsn.mk2
-rw-r--r--lib/cosTime/AUTHORS4
-rw-r--r--lib/cosTime/Makefile42
-rw-r--r--lib/cosTime/doc/html/.gitignore0
-rw-r--r--lib/cosTime/doc/man3/.gitignore0
-rw-r--r--lib/cosTime/doc/man6/.gitignore0
-rw-r--r--lib/cosTime/doc/pdf/.gitignore0
-rw-r--r--lib/cosTime/doc/src/CosTime_TIO.xml109
-rw-r--r--lib/cosTime/doc/src/CosTime_TimeService.xml104
-rw-r--r--lib/cosTime/doc/src/CosTime_UTO.xml156
-rw-r--r--lib/cosTime/doc/src/CosTimerEvent_TimerEventHandler.xml125
-rw-r--r--lib/cosTime/doc/src/CosTimerEvent_TimerEventService.xml84
-rw-r--r--lib/cosTime/doc/src/Makefile138
-rw-r--r--lib/cosTime/doc/src/book.xml49
-rw-r--r--lib/cosTime/doc/src/ch_contents.xml75
-rw-r--r--lib/cosTime/doc/src/ch_example.xml113
-rw-r--r--lib/cosTime/doc/src/ch_install.xml56
-rw-r--r--lib/cosTime/doc/src/ch_introduction.xml59
-rw-r--r--lib/cosTime/doc/src/cosTime.xml175
-rw-r--r--lib/cosTime/doc/src/notes.xml360
-rw-r--r--lib/cosTime/doc/src/part.xml40
-rw-r--r--lib/cosTime/doc/src/ref_man.xml42
-rw-r--r--lib/cosTime/ebin/.gitignore0
-rw-r--r--lib/cosTime/examples/.gitignore0
-rw-r--r--lib/cosTime/include/.gitignore0
-rw-r--r--lib/cosTime/info12
-rw-r--r--lib/cosTime/priv/.gitignore0
-rw-r--r--lib/cosTime/src/CosTime.cfg6
-rw-r--r--lib/cosTime/src/CosTime.idl59
-rw-r--r--lib/cosTime/src/CosTime_TIO_impl.erl201
-rw-r--r--lib/cosTime/src/CosTime_TimeService_impl.erl182
-rw-r--r--lib/cosTime/src/CosTime_UTO_impl.erl242
-rw-r--r--lib/cosTime/src/CosTimerEvent.cfg4
-rw-r--r--lib/cosTime/src/CosTimerEvent.idl45
-rw-r--r--lib/cosTime/src/CosTimerEvent_TimerEventHandler_impl.erl305
-rw-r--r--lib/cosTime/src/CosTimerEvent_TimerEventService_impl.erl119
-rw-r--r--lib/cosTime/src/Makefile207
-rw-r--r--lib/cosTime/src/TimeBase.idl22
-rw-r--r--lib/cosTime/src/cosTime.app.src32
-rw-r--r--lib/cosTime/src/cosTime.appup.src6
-rw-r--r--lib/cosTime/src/cosTime.erl343
-rw-r--r--lib/cosTime/src/cosTimeApp.hrl77
-rw-r--r--lib/cosTime/test/Makefile135
-rw-r--r--lib/cosTime/test/cosTime.cover2
-rw-r--r--lib/cosTime/test/cosTime.spec1
-rw-r--r--lib/cosTime/test/generated_SUITE.erl289
-rw-r--r--lib/cosTime/test/time_SUITE.erl301
-rw-r--r--lib/cosTime/vsn.mk2
-rw-r--r--lib/cosTransactions/AUTHORS4
-rw-r--r--lib/cosTransactions/Makefile42
-rw-r--r--lib/cosTransactions/doc/html/.gitignore0
-rw-r--r--lib/cosTransactions/doc/man3/.gitignore0
-rw-r--r--lib/cosTransactions/doc/man6/.gitignore0
-rw-r--r--lib/cosTransactions/doc/pdf/.gitignore0
-rw-r--r--lib/cosTransactions/doc/src/CosTransactions_Control.xml74
-rw-r--r--lib/cosTransactions/doc/src/CosTransactions_Coordinator.xml230
-rw-r--r--lib/cosTransactions/doc/src/CosTransactions_RecoveryCoordinator.xml82
-rw-r--r--lib/cosTransactions/doc/src/CosTransactions_Resource.xml129
-rw-r--r--lib/cosTransactions/doc/src/CosTransactions_SubtransactionAwareResource.xml75
-rw-r--r--lib/cosTransactions/doc/src/CosTransactions_Synchronization.xml70
-rw-r--r--lib/cosTransactions/doc/src/CosTransactions_Terminator.xml73
-rw-r--r--lib/cosTransactions/doc/src/CosTransactions_TransactionFactory.xml64
-rw-r--r--lib/cosTransactions/doc/src/CosTransactions_TransactionalObject.xml43
-rw-r--r--lib/cosTransactions/doc/src/Makefile142
-rw-r--r--lib/cosTransactions/doc/src/book.xml49
-rw-r--r--lib/cosTransactions/doc/src/ch_contents.xml75
-rw-r--r--lib/cosTransactions/doc/src/ch_example.xml283
-rw-r--r--lib/cosTransactions/doc/src/ch_install.xml104
-rw-r--r--lib/cosTransactions/doc/src/ch_introduction.xml65
-rw-r--r--lib/cosTransactions/doc/src/ch_skeletons.xml214
-rw-r--r--lib/cosTransactions/doc/src/cosTransactions.xml142
-rw-r--r--lib/cosTransactions/doc/src/notes.xml407
-rw-r--r--lib/cosTransactions/doc/src/part.xml41
-rw-r--r--lib/cosTransactions/doc/src/ref_man.xml44
-rw-r--r--lib/cosTransactions/ebin/.gitignore0
-rw-r--r--lib/cosTransactions/examples/Makefile158
-rw-r--r--lib/cosTransactions/include/.gitignore0
-rw-r--r--lib/cosTransactions/info2
-rw-r--r--lib/cosTransactions/priv/.gitignore0
-rw-r--r--lib/cosTransactions/src/CosTransactions.cfg15
-rw-r--r--lib/cosTransactions/src/CosTransactions.idl193
-rw-r--r--lib/cosTransactions/src/CosTransactions_Terminator_impl.erl363
-rw-r--r--lib/cosTransactions/src/CosTransactions_TransactionFactory_impl.erl180
-rw-r--r--lib/cosTransactions/src/ETraP_Common.erl187
-rw-r--r--lib/cosTransactions/src/ETraP_Common.hrl341
-rw-r--r--lib/cosTransactions/src/ETraP_Server_impl.erl1745
-rw-r--r--lib/cosTransactions/src/Makefile181
-rw-r--r--lib/cosTransactions/src/cosTransactions.app.src44
-rw-r--r--lib/cosTransactions/src/cosTransactions.appup.src6
-rw-r--r--lib/cosTransactions/src/cosTransactions.erl116
-rw-r--r--lib/cosTransactions/src/etrap_logmgr.erl201
-rw-r--r--lib/cosTransactions/test/Makefile151
-rw-r--r--lib/cosTransactions/test/cosTransactions.cover2
-rw-r--r--lib/cosTransactions/test/cosTransactions.spec1
-rw-r--r--lib/cosTransactions/test/etrap_test.cfg21
-rw-r--r--lib/cosTransactions/test/etrap_test.idl39
-rw-r--r--lib/cosTransactions/test/etrap_test_lib.erl126
-rw-r--r--lib/cosTransactions/test/etrap_test_lib.hrl101
-rw-r--r--lib/cosTransactions/test/etrap_test_server_impl.erl211
-rw-r--r--lib/cosTransactions/test/generated_SUITE.erl543
-rw-r--r--lib/cosTransactions/test/transactions_SUITE.erl396
-rw-r--r--lib/cosTransactions/vsn.mk1
-rw-r--r--lib/crypto/c_src/Makefile.in107
-rw-r--r--lib/crypto/c_src/aead.c182
-rw-r--r--lib/crypto/c_src/aead.h28
-rw-r--r--lib/crypto/c_src/aes.c302
-rw-r--r--lib/crypto/c_src/aes.h38
-rw-r--r--lib/crypto/c_src/algorithms.c320
-rw-r--r--lib/crypto/c_src/algorithms.h35
-rw-r--r--lib/crypto/c_src/api_ng.c569
-rw-r--r--lib/crypto/c_src/api_ng.h30
-rw-r--r--lib/crypto/c_src/atoms.c252
-rw-r--r--lib/crypto/c_src/atoms.h134
-rw-r--r--lib/crypto/c_src/bn.c186
-rw-r--r--lib/crypto/c_src/bn.h36
-rw-r--r--lib/crypto/c_src/check_erlang.cocci196
-rw-r--r--lib/crypto/c_src/check_openssl.cocci281
-rw-r--r--lib/crypto/c_src/cipher.c344
-rw-r--r--lib/crypto/c_src/cipher.h84
-rw-r--r--lib/crypto/c_src/cmac.c88
-rw-r--r--lib/crypto/c_src/cmac.h28
-rw-r--r--lib/crypto/c_src/common.h52
-rw-r--r--lib/crypto/c_src/crypto.c5471
-rw-r--r--lib/crypto/c_src/crypto_callback.c52
-rw-r--r--lib/crypto/c_src/dh.c302
-rw-r--r--lib/crypto/c_src/dh.h29
-rw-r--r--lib/crypto/c_src/digest.c156
-rw-r--r--lib/crypto/c_src/digest.h40
-rw-r--r--lib/crypto/c_src/dss.c148
-rw-r--r--lib/crypto/c_src/dss.h31
-rw-r--r--lib/crypto/c_src/ec.c414
-rw-r--r--lib/crypto/c_src/ec.h35
-rw-r--r--lib/crypto/c_src/ecdh.c94
-rw-r--r--lib/crypto/c_src/ecdh.h28
-rw-r--r--lib/crypto/c_src/eddsa.c63
-rw-r--r--lib/crypto/c_src/eddsa.h30
-rw-r--r--lib/crypto/c_src/engine.c840
-rw-r--r--lib/crypto/c_src/engine.h49
-rw-r--r--lib/crypto/c_src/evp.c164
-rw-r--r--lib/crypto/c_src/evp.h29
-rw-r--r--lib/crypto/c_src/evp_compat.h210
-rw-r--r--lib/crypto/c_src/fips.c52
-rw-r--r--lib/crypto/c_src/fips.h29
-rw-r--r--lib/crypto/c_src/hash.c549
-rw-r--r--lib/crypto/c_src/hash.h34
-rw-r--r--lib/crypto/c_src/hmac.c270
-rw-r--r--lib/crypto/c_src/hmac.h33
-rw-r--r--lib/crypto/c_src/info.c107
-rw-r--r--lib/crypto/c_src/info.h35
-rw-r--r--lib/crypto/c_src/math.c53
-rw-r--r--lib/crypto/c_src/math.h28
-rw-r--r--lib/crypto/c_src/openssl_config.h405
-rw-r--r--lib/crypto/c_src/otp_test_engine.c328
-rw-r--r--lib/crypto/c_src/pkey.c1486
-rw-r--r--lib/crypto/c_src/pkey.h31
-rw-r--r--lib/crypto/c_src/poly1305.c90
-rw-r--r--lib/crypto/c_src/poly1305.h28
-rw-r--r--lib/crypto/c_src/rand.c149
-rw-r--r--lib/crypto/c_src/rand.h31
-rw-r--r--lib/crypto/c_src/rsa.c282
-rw-r--r--lib/crypto/c_src/rsa.h31
-rw-r--r--lib/crypto/c_src/srp.c307
-rw-r--r--lib/crypto/c_src/srp.h30
-rw-r--r--lib/crypto/configure.in775
-rw-r--r--lib/crypto/doc/specs/.gitignore1
-rw-r--r--lib/crypto/doc/src/Makefile11
-rw-r--r--lib/crypto/doc/src/algorithm_details.xml355
-rw-r--r--lib/crypto/doc/src/crypto.xml2048
-rw-r--r--lib/crypto/doc/src/crypto_app.xml18
-rw-r--r--lib/crypto/doc/src/engine_keys.xml8
-rw-r--r--lib/crypto/doc/src/engine_load.xml33
-rw-r--r--lib/crypto/doc/src/new_api.xml260
-rw-r--r--lib/crypto/doc/src/notes.xml461
-rw-r--r--lib/crypto/doc/src/specs.xml4
-rw-r--r--lib/crypto/doc/src/usersguide.xml4
-rw-r--r--lib/crypto/src/Makefile2
-rw-r--r--lib/crypto/src/crypto.app.src2
-rw-r--r--lib/crypto/src/crypto.erl2162
-rw-r--r--lib/crypto/src/crypto_ec_curves.erl36
-rw-r--r--lib/crypto/test/Makefile4
-rw-r--r--lib/crypto/test/blowfish_SUITE.erl300
-rw-r--r--lib/crypto/test/crypto.spec5
-rw-r--r--lib/crypto/test/crypto_SUITE.erl2335
-rw-r--r--lib/crypto/test/crypto_SUITE_data/VADT128.rsp1823
-rw-r--r--lib/crypto/test/crypto_SUITE_data/VADT192.rsp1823
-rw-r--r--lib/crypto/test/crypto_SUITE_data/VADT256.rsp1823
-rw-r--r--lib/crypto/test/crypto_SUITE_data/VNT128.rsp456
-rw-r--r--lib/crypto/test/crypto_SUITE_data/VNT192.rsp456
-rw-r--r--lib/crypto/test/crypto_SUITE_data/VNT256.rsp456
-rw-r--r--lib/crypto/test/crypto_SUITE_data/VPT128.rsp1383
-rw-r--r--lib/crypto/test/crypto_SUITE_data/VPT192.rsp1383
-rw-r--r--lib/crypto/test/crypto_SUITE_data/VPT256.rsp1383
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT128.rsp1589
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT128.txt1589
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT192.rsp1589
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT192.txt1589
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT256.rsp1589
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT256.txt1589
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/Readme.txt9
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VADT128.rsp1823
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VADT192.rsp1823
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VADT256.rsp1823
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VNT128.rsp456
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VNT192.rsp456
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VNT256.rsp456
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VPT128.rsp1383
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VPT192.rsp1383
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VPT256.rsp1383
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VTT128.rsp393
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VTT192.rsp393
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VTT256.rsp393
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/ccmtestvectors.zipbin0 -> 319267 bytes
-rw-r--r--lib/crypto/test/crypto_bench.spec3
-rw-r--r--lib/crypto/test/crypto_bench_SUITE.erl400
-rw-r--r--lib/crypto/test/engine_SUITE.erl467
-rw-r--r--lib/crypto/vsn.mk2
-rw-r--r--lib/debugger/doc/src/Makefile6
-rw-r--r--lib/debugger/doc/src/debugger.xml12
-rw-r--r--lib/debugger/doc/src/i.xml64
-rw-r--r--lib/debugger/doc/src/int.xml64
-rw-r--r--lib/debugger/doc/src/notes.xml49
-rw-r--r--lib/debugger/src/dbg_debugged.erl40
-rw-r--r--lib/debugger/src/dbg_icmd.erl6
-rw-r--r--lib/debugger/src/dbg_ieval.erl7
-rw-r--r--lib/debugger/src/dbg_wx_mon.erl6
-rw-r--r--lib/debugger/src/dbg_wx_trace.erl10
-rw-r--r--lib/debugger/src/dbg_wx_win.erl4
-rw-r--r--lib/debugger/src/debugger.app.src2
-rw-r--r--lib/debugger/src/i.erl2
-rw-r--r--lib/debugger/test/guard_SUITE.erl7
-rw-r--r--lib/debugger/test/int_eval_SUITE.erl16
-rw-r--r--lib/debugger/test/int_eval_SUITE_data/my_int_eval_module.erl6
-rw-r--r--lib/debugger/vsn.mk2
-rw-r--r--lib/dialyzer/doc/src/Makefile1
-rw-r--r--lib/dialyzer/doc/src/dialyzer.xml38
-rw-r--r--lib/dialyzer/doc/src/notes.xml147
-rw-r--r--lib/dialyzer/src/Makefile4
-rw-r--r--lib/dialyzer/src/dialyzer.erl452
-rw-r--r--lib/dialyzer/src/dialyzer.hrl4
-rw-r--r--lib/dialyzer/src/dialyzer_cl.erl14
-rw-r--r--lib/dialyzer/src/dialyzer_cl_parse.erl14
-rw-r--r--lib/dialyzer/src/dialyzer_codeserver.erl8
-rw-r--r--lib/dialyzer/src/dialyzer_contracts.erl226
-rw-r--r--lib/dialyzer/src/dialyzer_dataflow.erl67
-rw-r--r--lib/dialyzer/src/dialyzer_gui_wx.erl8
-rw-r--r--lib/dialyzer/src/dialyzer_options.erl2
-rw-r--r--lib/dialyzer/src/dialyzer_plt.erl20
-rw-r--r--lib/dialyzer/src/dialyzer_races.erl66
-rw-r--r--lib/dialyzer/src/dialyzer_typesig.erl10
-rw-r--r--lib/dialyzer/src/dialyzer_utils.erl190
-rw-r--r--lib/dialyzer/src/typer.erl8
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/dialyzer_options2
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_incorrect_args2
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/proper/proper_typeserver.erl10
-rw-r--r--lib/dialyzer/test/callgraph_SUITE_data/dialyzer_options2
-rw-r--r--lib/dialyzer/test/dialyzer_common.erl13
-rw-r--r--lib/dialyzer/test/indent2_SUITE_data/dialyzer_options1
-rw-r--r--lib/dialyzer/test/indent2_SUITE_data/results/arr15
-rw-r--r--lib/dialyzer/test/indent2_SUITE_data/results/iodata24
-rw-r--r--lib/dialyzer/test/indent2_SUITE_data/results/remote25
-rw-r--r--lib/dialyzer/test/indent2_SUITE_data/src/arr.erl41
-rw-r--r--lib/dialyzer/test/indent2_SUITE_data/src/iodata.erl41
-rw-r--r--lib/dialyzer/test/indent2_SUITE_data/src/remote/remotes1.erl61
-rw-r--r--lib/dialyzer/test/indent2_SUITE_data/src/remote/some_known_remote.erl5
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/dialyzer_options1
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/abs13
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/app_call9
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/arr4
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/blame_contract_range8
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/bs_fail_constr9
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/callbacks_and_specs23
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/contract33
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/contracts_with_subtypes142
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/dict_use48
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/fun_app7
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/fun_app_args5
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/guard_update6
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/guard_warnings134
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/map_galore713
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/order23
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/queue_use34
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/rec15
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/record_construct11
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/record_creation_diffs4
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/record_match4
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/record_pat4
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/record_send_test6
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/record_test6
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/record_update3
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/sample_behaviour23
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/simple289
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/suppress_request11
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/trec10
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/results/whereis_control_flow14
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/abs.erl78
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/app_call.erl17
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/blame_contract_range.erl16
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/bs_fail_constr.erl15
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/callbacks_and_specs/my_behaviour.erl11
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/callbacks_and_specs/my_callbacks_correct.erl59
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/callbacks_and_specs/my_callbacks_wrong.erl61
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/contract3.erl40
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/contracts_with_subtypes.erl300
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/dict_use.erl82
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/fun_app.erl41
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/fun_app_args.erl12
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/guard_update.erl18
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/guard_warnings.erl118
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/map_galore.erl2800
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/order.erl56
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/queue_use.erl65
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/rec/rec_adt.erl22
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/rec/rec_use.erl30
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/record_construct.erl21
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/record_creation_diffs.erl11
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/record_match.erl17
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/record_pat.erl15
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/record_send_test.erl32
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/record_test.erl22
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/record_update.erl10
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/sample_behaviour/sample_behaviour.erl13
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/sample_behaviour/sample_callback_correct.erl32
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/sample_behaviour/sample_callback_correct_2.erl38
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/sample_behaviour/sample_callback_wrong.erl26
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/simple/exact_adt.erl17
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/simple/exact_api.erl60
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/simple/is_rec.erl65
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/simple/rec_adt.erl28
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/simple/rec_api.erl123
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/simple/simple1_adt.erl138
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/simple/simple1_api.erl571
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/simple/simple2_api.erl125
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/suppress_request.erl50
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/trec.erl39
-rw-r--r--lib/dialyzer/test/indent_SUITE_data/src/whereis_control_flow1.erl17
-rw-r--r--lib/dialyzer/test/map_SUITE_data/dialyzer_options2
-rw-r--r--lib/dialyzer/test/map_SUITE_data/results/contract6
-rw-r--r--lib/dialyzer/test/map_SUITE_data/results/guard_update2
-rw-r--r--lib/dialyzer/test/map_SUITE_data/results/map_galore10
-rw-r--r--lib/dialyzer/test/map_SUITE_data/results/typesig2
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/dialyzer_options2
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/dict6
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/para1
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/queue6
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/simple6
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/para/para4.erl11
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/para/para4_adt.erl12
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/proper/proper_typeserver.erl10
-rw-r--r--lib/dialyzer/test/options1_SUITE_data/dialyzer_options2
-rw-r--r--lib/dialyzer/test/options1_SUITE_data/results/compiler6
-rw-r--r--lib/dialyzer/test/options1_SUITE_data/src/compiler/beam_validator.erl4
-rw-r--r--lib/dialyzer/test/options1_SUITE_data/src/compiler/compile.erl6
-rw-r--r--lib/dialyzer/test/options2_SUITE_data/dialyzer_options2
-rw-r--r--lib/dialyzer/test/overspecs_SUITE_data/dialyzer_options1
-rw-r--r--lib/dialyzer/test/overspecs_SUITE_data/results/iodata2
-rw-r--r--lib/dialyzer/test/overspecs_SUITE_data/results/iolist2
-rw-r--r--lib/dialyzer/test/overspecs_SUITE_data/src/iodata.erl41
-rw-r--r--lib/dialyzer/test/overspecs_SUITE_data/src/iolist.erl41
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/dialyzer_options2
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/results/asn14
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/results/inets6
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber.erl4
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber_bin_v2.erl4
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/src/inets/mod_esi.erl2
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/src/inets/mod_responsecontrol.erl2
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_lib.erl2
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_tm.erl4
-rw-r--r--lib/dialyzer/test/race_SUITE_data/dialyzer_options2
-rw-r--r--lib/dialyzer/test/race_SUITE_data/results/ets_insert_double12
-rw-r--r--lib/dialyzer/test/small_SUITE_data/dialyzer_options2
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/bs_fail_constr6
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/chars6
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes22
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes22
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/extra_range4
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/failing_guard14
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/fun_app_args3
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/fun_arity32
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/guard_warnings74
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/left_assoc2
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/maps_sum2
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/pretty_bitstring2
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/stacktrace5
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/tuple_set_crash10
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/union_paren7
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/unused_funs5
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/chars.erl18
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/extra_range.erl59
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/fun_app_args.erl12
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/left_assoc.erl96
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/lists_key_bug.erl75
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/stacktrace.erl73
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/union_paren.erl24
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/unused_funs.erl21
-rw-r--r--lib/dialyzer/test/specdiffs_SUITE_data/dialyzer_options1
-rw-r--r--lib/dialyzer/test/specdiffs_SUITE_data/results/iodata3
-rw-r--r--lib/dialyzer/test/specdiffs_SUITE_data/results/iolist2
-rw-r--r--lib/dialyzer/test/specdiffs_SUITE_data/src/iodata.erl41
-rw-r--r--lib/dialyzer/test/specdiffs_SUITE_data/src/iolist.erl41
-rw-r--r--lib/dialyzer/test/underspecs_SUITE_data/dialyzer_options2
-rw-r--r--lib/dialyzer/test/unmatched_returns_SUITE_data/dialyzer_options2
-rw-r--r--lib/dialyzer/test/user_SUITE_data/dialyzer_options2
-rw-r--r--lib/dialyzer/vsn.mk2
-rwxr-xr-xlib/diameter/bin/diameterc6
-rw-r--r--lib/diameter/doc/src/Makefile3
-rw-r--r--lib/diameter/doc/src/diameter.xml58
-rw-r--r--lib/diameter/doc/src/diameter_app.xml18
-rw-r--r--lib/diameter/doc/src/diameter_codec.xml8
-rw-r--r--lib/diameter/doc/src/diameter_dict.xml6
-rw-r--r--lib/diameter/doc/src/diameter_make.xml10
-rw-r--r--lib/diameter/doc/src/diameter_sctp.xml4
-rw-r--r--lib/diameter/doc/src/diameter_soc.xml2
-rw-r--r--lib/diameter/doc/src/diameter_tcp.xml4
-rw-r--r--lib/diameter/doc/src/diameter_transport.xml35
-rw-r--r--lib/diameter/doc/src/notes.xml109
-rw-r--r--lib/diameter/examples/code/node.erl2
-rw-r--r--lib/diameter/src/Makefile7
-rw-r--r--lib/diameter/src/app.sed41
-rw-r--r--lib/diameter/src/base/diameter.erl4
-rw-r--r--lib/diameter/src/base/diameter_callback.erl4
-rw-r--r--lib/diameter/src/base/diameter_codec.erl14
-rw-r--r--lib/diameter/src/base/diameter_config.erl14
-rw-r--r--lib/diameter/src/base/diameter_dist.erl535
-rw-r--r--lib/diameter/src/base/diameter_gen.erl19
-rw-r--r--lib/diameter/src/base/diameter_internal.hrl5
-rw-r--r--lib/diameter/src/base/diameter_lib.erl15
-rw-r--r--lib/diameter/src/base/diameter_misc_sup.erl3
-rw-r--r--lib/diameter/src/base/diameter_peer_fsm.erl4
-rw-r--r--lib/diameter/src/base/diameter_service.erl20
-rw-r--r--lib/diameter/src/base/diameter_traffic.erl99
-rw-r--r--lib/diameter/src/compiler/diameter_exprecs.erl2
-rw-r--r--lib/diameter/src/compiler/diameter_make.erl6
-rw-r--r--lib/diameter/src/diameter.app.src17
-rw-r--r--lib/diameter/src/diameter.appup.src16
-rw-r--r--lib/diameter/src/modules.mk3
-rw-r--r--lib/diameter/src/transport/diameter_tcp.erl14
-rw-r--r--lib/diameter/test/diameter_app_SUITE.erl14
-rw-r--r--lib/diameter/test/diameter_dist_SUITE.erl332
-rw-r--r--lib/diameter/test/diameter_distribution_SUITE.erl7
-rw-r--r--lib/diameter/test/diameter_pool_SUITE.erl3
-rw-r--r--lib/diameter/test/diameter_traffic_SUITE.erl9
-rw-r--r--lib/diameter/test/diameter_watchdog_SUITE.erl9
-rw-r--r--lib/diameter/test/modules.mk3
-rw-r--r--lib/diameter/vsn.mk2
l---------lib/edoc/doc/edoc.dtd1
l---------lib/edoc/doc/edoc_doclet.hrl1
-rw-r--r--lib/edoc/doc/src/Makefile22
-rw-r--r--lib/edoc/doc/src/notes.xml74
-rw-r--r--lib/edoc/include/edoc_doclet.hrl2
-rw-r--r--lib/edoc/src/edoc.erl19
-rw-r--r--lib/edoc/src/edoc_data.erl2
-rw-r--r--lib/edoc/src/edoc_doclet.erl8
-rw-r--r--lib/edoc/src/edoc_layout.erl8
-rw-r--r--lib/edoc/src/edoc_specs.erl2
-rw-r--r--lib/edoc/vsn.mk2
-rw-r--r--lib/eldap/README2
-rw-r--r--lib/eldap/doc/src/Makefile1
-rw-r--r--lib/eldap/doc/src/eldap.xml68
-rw-r--r--lib/eldap/doc/src/notes.xml117
-rw-r--r--lib/eldap/src/eldap.erl25
-rw-r--r--lib/eldap/test/eldap_basic_SUITE.erl2
-rw-r--r--lib/eldap/test/make_certs.erl4
-rw-r--r--lib/eldap/vsn.mk2
-rw-r--r--lib/erl_docgen/doc/src/Makefile1
-rw-r--r--lib/erl_docgen/doc/src/doc-build.xml2
-rw-r--r--lib/erl_docgen/doc/src/docgen_xml_check.xml4
-rw-r--r--lib/erl_docgen/doc/src/notes.xml97
-rwxr-xr-xlib/erl_docgen/priv/bin/codeline_preprocessing.escript5
-rwxr-xr-xlib/erl_docgen/priv/bin/github_link.escript51
-rwxr-xr-xlib/erl_docgen/priv/bin/xml_from_edoc.escript9
-rw-r--r--lib/erl_docgen/priv/css/otp_doc.css60
-rw-r--r--lib/erl_docgen/priv/dtd/book.dtd3
-rw-r--r--lib/erl_docgen/priv/dtd/chapter.dtd1
-rw-r--r--lib/erl_docgen/priv/dtd/common.dtd2
-rw-r--r--lib/erl_docgen/priv/dtd/common.image.dtd4
-rw-r--r--lib/erl_docgen/priv/dtd/common.refs.dtd7
-rw-r--r--lib/erl_docgen/priv/dtd/cref.dtd2
-rw-r--r--lib/erl_docgen/priv/dtd/erlref.dtd3
-rw-r--r--lib/erl_docgen/priv/xsl/Makefile5
-rw-r--r--lib/erl_docgen/priv/xsl/db_eix.xsl81
-rw-r--r--lib/erl_docgen/priv/xsl/db_html.xsl474
-rw-r--r--lib/erl_docgen/priv/xsl/db_man.xsl8
-rw-r--r--lib/erl_docgen/priv/xsl/db_pdf.xsl19
-rw-r--r--lib/erl_docgen/priv/xsl/db_pdf_params.xsl3
-rw-r--r--lib/erl_docgen/src/docgen_edoc_xml_cb.erl19
-rw-r--r--lib/erl_docgen/src/docgen_otp_specs.erl10
-rw-r--r--lib/erl_docgen/src/docgen_xmerl_xml_cb.erl1
-rw-r--r--lib/erl_docgen/vsn.mk2
-rw-r--r--lib/erl_interface/configure.in41
-rw-r--r--lib/erl_interface/doc/src/Makefile3
-rw-r--r--lib/erl_interface/doc/src/ei.xml329
-rw-r--r--lib/erl_interface/doc/src/ei_connect.xml417
-rw-r--r--lib/erl_interface/doc/src/ei_users_guide.xml30
-rw-r--r--lib/erl_interface/doc/src/erl_connect.xml59
-rw-r--r--lib/erl_interface/doc/src/erl_error.xml10
-rw-r--r--lib/erl_interface/doc/src/erl_eterm.xml67
-rw-r--r--lib/erl_interface/doc/src/erl_format.xml4
-rw-r--r--lib/erl_interface/doc/src/erl_global.xml17
-rw-r--r--lib/erl_interface/doc/src/erl_interface.xml12
-rw-r--r--lib/erl_interface/doc/src/erl_malloc.xml24
-rw-r--r--lib/erl_interface/doc/src/erl_marshal.xml26
-rw-r--r--lib/erl_interface/doc/src/notes.xml340
-rw-r--r--lib/erl_interface/doc/src/ref_man.xml8
-rw-r--r--lib/erl_interface/doc/src/ref_man_ei.xml10
-rw-r--r--lib/erl_interface/doc/src/ref_man_erl_interface.xml8
-rw-r--r--lib/erl_interface/doc/src/registry.xml40
-rw-r--r--lib/erl_interface/include/ei.h114
-rw-r--r--lib/erl_interface/include/erl_interface.h213
-rw-r--r--lib/erl_interface/src/INSTALL4
-rw-r--r--lib/erl_interface/src/Makefile4
-rw-r--r--lib/erl_interface/src/Makefile.in44
-rw-r--r--lib/erl_interface/src/README.internal8
-rw-r--r--lib/erl_interface/src/connect/ei_connect.c1267
-rw-r--r--lib/erl_interface/src/connect/ei_connect_int.h2
-rw-r--r--lib/erl_interface/src/connect/ei_resolve.c29
-rw-r--r--lib/erl_interface/src/connect/ei_resolve.h2
-rw-r--r--lib/erl_interface/src/connect/eirecv.c62
-rw-r--r--lib/erl_interface/src/connect/send.c74
-rw-r--r--lib/erl_interface/src/connect/send_exit.c25
-rw-r--r--lib/erl_interface/src/connect/send_reg.c64
-rw-r--r--lib/erl_interface/src/decode/decode_atom.c64
-rw-r--r--lib/erl_interface/src/decode/decode_binary.c37
-rw-r--r--lib/erl_interface/src/decode/decode_fun.c98
-rw-r--r--lib/erl_interface/src/decode/decode_skip.c8
-rw-r--r--lib/erl_interface/src/depend.mk1133
-rw-r--r--lib/erl_interface/src/encode/encode_binary.c107
-rw-r--r--lib/erl_interface/src/encode/encode_fun.c114
-rw-r--r--lib/erl_interface/src/epmd/epmd_port.c85
-rw-r--r--lib/erl_interface/src/epmd/epmd_publish.c36
-rw-r--r--lib/erl_interface/src/epmd/epmd_unpublish.c33
-rw-r--r--lib/erl_interface/src/legacy/erl_connect.c9
-rw-r--r--lib/erl_interface/src/legacy/erl_eterm.c16
-rw-r--r--lib/erl_interface/src/legacy/erl_marshal.c6
-rw-r--r--lib/erl_interface/src/misc/ei_compat.c17
-rw-r--r--lib/erl_interface/src/misc/ei_decode_term.c8
-rw-r--r--lib/erl_interface/src/misc/ei_init.c32
-rw-r--r--lib/erl_interface/src/misc/ei_internal.h22
-rw-r--r--lib/erl_interface/src/misc/ei_portio.c865
-rw-r--r--lib/erl_interface/src/misc/ei_portio.h95
-rw-r--r--lib/erl_interface/src/misc/ei_printterm.c32
-rw-r--r--lib/erl_interface/src/misc/ei_pthreads.c5
-rw-r--r--lib/erl_interface/src/misc/ei_x_encode.c10
-rw-r--r--lib/erl_interface/src/misc/get_type.c11
-rw-r--r--lib/erl_interface/src/misc/show_msg.c8
-rw-r--r--lib/erl_interface/src/not_used/send_link.c3
-rw-r--r--lib/erl_interface/src/prog/ei_fake_prog.c12
-rw-r--r--lib/erl_interface/src/prog/erl_call.c69
-rw-r--r--lib/erl_interface/src/prog/erl_start.c4
-rw-r--r--lib/erl_interface/src/registry/reg_dump.c2
-rw-r--r--lib/erl_interface/test/Makefile1
-rw-r--r--lib/erl_interface/test/all_SUITE_data/ei_runner.h1
-rw-r--r--lib/erl_interface/test/ei_accept_SUITE.erl141
-rw-r--r--lib/erl_interface/test/ei_accept_SUITE_data/ei_accept_test.c104
-rw-r--r--lib/erl_interface/test/ei_accept_SUITE_data/eiaccnode.c88
-rw-r--r--lib/erl_interface/test/ei_connect_SUITE.erl23
-rw-r--r--lib/erl_interface/test/ei_connect_SUITE_data/ei_connect_test.c30
-rw-r--r--lib/erl_interface/test/ei_decode_SUITE.erl25
-rw-r--r--lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c218
-rw-r--r--lib/erl_interface/test/ei_decode_encode_SUITE.erl30
-rw-r--r--lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c105
-rw-r--r--lib/erl_interface/test/ei_encode_SUITE.erl24
-rw-r--r--lib/erl_interface/test/ei_encode_SUITE_data/ei_encode_test.c14
-rw-r--r--lib/erl_interface/test/ei_format_SUITE.erl14
-rw-r--r--lib/erl_interface/test/ei_format_SUITE_data/ei_format_test.c8
-rw-r--r--lib/erl_interface/test/ei_print_SUITE.erl14
-rw-r--r--lib/erl_interface/test/ei_print_SUITE_data/ei_print_test.c8
-rw-r--r--lib/erl_interface/test/ei_tmo_SUITE.erl30
-rw-r--r--lib/erl_interface/test/ei_tmo_SUITE_data/ei_tmo_test.c11
-rw-r--r--lib/erl_interface/test/erl_call_SUITE.erl96
-rw-r--r--lib/erl_interface/test/erl_connect_SUITE.erl12
-rw-r--r--lib/erl_interface/test/erl_eterm_SUITE.erl80
-rw-r--r--lib/erl_interface/test/erl_eterm_SUITE_data/cnode.c42
-rw-r--r--lib/erl_interface/test/erl_ext_SUITE.erl15
-rw-r--r--lib/erl_interface/test/erl_ext_SUITE_data/ext_test.c14
-rw-r--r--lib/erl_interface/test/erl_format_SUITE.erl12
-rw-r--r--lib/erl_interface/test/erl_global_SUITE.erl11
-rw-r--r--lib/erl_interface/test/erl_match_SUITE.erl9
-rw-r--r--lib/erl_interface/test/port_call_SUITE.erl8
-rw-r--r--lib/erl_interface/test/runner.erl65
-rw-r--r--lib/erl_interface/vsn.mk2
-rw-r--r--lib/et/doc/src/Makefile8
-rw-r--r--lib/et/doc/src/et.xml14
-rw-r--r--lib/et/doc/src/et_collector.xml56
-rw-r--r--lib/et/doc/src/et_selector.xml14
-rw-r--r--lib/et/doc/src/et_viewer.xml14
-rw-r--r--lib/et/doc/src/files.mk9
-rw-r--r--lib/et/doc/src/notes.xml49
-rw-r--r--lib/et/src/et.app.src2
-rw-r--r--lib/et/src/et_collector.erl6
-rw-r--r--lib/et/src/et_wx_contents_viewer.erl6
-rw-r--r--lib/et/src/et_wx_viewer.erl37
-rw-r--r--lib/et/test/et_test_lib.erl2
-rw-r--r--lib/et/test/ett.erl2
-rw-r--r--lib/et/vsn.mk2
-rw-r--r--lib/eunit/doc/src/Makefile14
-rw-r--r--lib/eunit/doc/src/notes.xml32
-rw-r--r--lib/eunit/src/eunit_lib.erl6
-rw-r--r--lib/eunit/src/eunit_listener.erl3
-rw-r--r--lib/eunit/src/eunit_proc.erl2
-rw-r--r--lib/eunit/src/eunit_test.erl51
-rw-r--r--lib/eunit/vsn.mk2
-rw-r--r--lib/ftp/AUTHORS11
-rw-r--r--lib/ftp/Makefile78
-rw-r--r--lib/ftp/doc/archive/rfc2428.txt (renamed from lib/inets/doc/archive/rfc2428.txt)0
-rw-r--r--lib/ftp/doc/archive/rfc2577.txt (renamed from lib/inets/doc/archive/rfc2577.txt)0
-rw-r--r--lib/ftp/doc/archive/rfc959.txt (renamed from lib/inets/doc/archive/rfc959.txt)0
-rw-r--r--lib/ftp/doc/html/.gitignore (renamed from lib/cosEvent/doc/html/.gitignore)0
-rw-r--r--lib/ftp/doc/man3/.gitignore (renamed from lib/cosEvent/doc/man3/.gitignore)0
-rw-r--r--lib/ftp/doc/man6/.gitignore (renamed from lib/cosEvent/doc/man6/.gitignore)0
-rw-r--r--lib/ftp/doc/pdf/.gitignore (renamed from lib/cosEvent/doc/pdf/.gitignore)0
-rw-r--r--lib/ftp/doc/src/Makefile155
-rw-r--r--lib/ftp/doc/src/book.xml49
-rw-r--r--lib/ftp/doc/src/ftp.xml983
-rw-r--r--lib/ftp/doc/src/ftp_client.xml86
-rw-r--r--lib/ftp/doc/src/introduction.xml46
-rw-r--r--lib/ftp/doc/src/notes.xml84
-rw-r--r--lib/ftp/doc/src/part.xml37
-rw-r--r--lib/ftp/doc/src/ref_man.xml36
-rw-r--r--lib/ftp/ebin/.gitignore (renamed from lib/cosEvent/ebin/.gitignore)0
-rw-r--r--lib/ftp/info2
-rw-r--r--lib/ftp/src/Makefile118
-rw-r--r--lib/ftp/src/ftp.app.src19
-rw-r--r--lib/ftp/src/ftp.appup.src26
-rw-r--r--lib/ftp/src/ftp.erl2619
-rw-r--r--lib/ftp/src/ftp_app.erl47
-rw-r--r--lib/ftp/src/ftp_internal.hrl35
-rw-r--r--lib/ftp/src/ftp_progress.erl136
-rw-r--r--lib/ftp/src/ftp_response.erl203
-rw-r--r--lib/ftp/src/ftp_sup.erl68
-rw-r--r--lib/ftp/test/Makefile251
-rw-r--r--lib/ftp/test/erl_make_certs.erl475
-rw-r--r--lib/ftp/test/ftp.config1
-rw-r--r--lib/ftp/test/ftp.cover2
-rw-r--r--lib/ftp/test/ftp.spec1
-rw-r--r--lib/ftp/test/ftp_SUITE.erl1274
-rw-r--r--lib/ftp/test/ftp_SUITE_data/ftpd_hosts.skel (renamed from lib/inets/test/ftp_SUITE_data/ftpd_hosts.skel)0
-rw-r--r--lib/ftp/test/ftp_SUITE_data/vsftpd.conf33
-rw-r--r--lib/ftp/test/ftp_bench.spec1
-rw-r--r--lib/ftp/test/ftp_format_SUITE.erl328
l---------lib/ftp/test/ftp_internal.hrl1
-rw-r--r--lib/ftp/test/ftp_property_test_SUITE.erl55
-rw-r--r--lib/ftp/test/ftp_test_lib.erl126
-rw-r--r--lib/ftp/test/property_test/README12
-rw-r--r--lib/ftp/test/property_test/ftp_simple_client_server.erl307
-rw-r--r--lib/ftp/test/property_test/ftp_simple_client_server_data/vsftpd.conf26
-rw-r--r--lib/ftp/vsn.mk24
-rw-r--r--lib/hipe/cerl/Makefile9
-rw-r--r--lib/hipe/cerl/cerl_messagean.erl1095
-rw-r--r--lib/hipe/cerl/erl_bif_types.erl45
-rw-r--r--lib/hipe/cerl/erl_types.erl341
-rw-r--r--lib/hipe/doc/src/Makefile3
-rw-r--r--lib/hipe/doc/src/hipe_app.xml93
-rw-r--r--lib/hipe/doc/src/notes.xml139
-rw-r--r--lib/hipe/icode/hipe_beam_to_icode.erl111
-rw-r--r--lib/hipe/icode/hipe_icode.erl30
-rw-r--r--lib/hipe/icode/hipe_icode.hrl8
-rw-r--r--lib/hipe/icode/hipe_icode_inline_bifs.erl22
-rw-r--r--lib/hipe/icode/hipe_icode_liveness.erl1
-rw-r--r--lib/hipe/icode/hipe_icode_pp.erl5
-rw-r--r--lib/hipe/icode/hipe_icode_primops.erl23
-rw-r--r--lib/hipe/icode/hipe_icode_range.erl8
-rw-r--r--lib/hipe/llvm/Makefile5
-rw-r--r--lib/hipe/llvm/hipe_llvm.erl11
-rw-r--r--lib/hipe/llvm/hipe_llvm_main.erl14
-rw-r--r--lib/hipe/llvm/hipe_rtl_to_llvm.erl4
-rw-r--r--lib/hipe/main/hipe.app.src4
-rw-r--r--lib/hipe/main/hipe.erl191
-rw-r--r--lib/hipe/main/hipe_main.erl5
-rw-r--r--lib/hipe/opt/hipe_schedule.erl1483
-rw-r--r--lib/hipe/opt/hipe_schedule_prio.erl53
-rw-r--r--lib/hipe/opt/hipe_target_machine.erl87
-rw-r--r--lib/hipe/opt/hipe_ultra_mod2.erl233
-rw-r--r--lib/hipe/opt/hipe_ultra_prio.erl298
-rw-r--r--lib/hipe/rtl/Makefile7
-rw-r--r--lib/hipe/rtl/hipe_icode2rtl.erl2
-rw-r--r--lib/hipe/rtl/hipe_rtl.erl5
-rw-r--r--lib/hipe/rtl/hipe_rtl_arith.inc4
-rw-r--r--lib/hipe/rtl/hipe_rtl_binary_construct.erl22
-rw-r--r--lib/hipe/rtl/hipe_rtl_binary_match.erl10
-rw-r--r--lib/hipe/rtl/hipe_rtl_cleanup_const.erl4
-rw-r--r--lib/hipe/rtl/hipe_rtl_lcm.erl110
-rw-r--r--lib/hipe/rtl/hipe_rtl_primops.erl29
-rw-r--r--lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl6
-rw-r--r--lib/hipe/rtl/hipe_rtl_varmap.erl2
-rw-r--r--lib/hipe/rtl/hipe_rtl_verify_gcsafe.erl89
-rw-r--r--lib/hipe/rtl/hipe_tagscheme.erl141
-rw-r--r--lib/hipe/ssa/hipe_ssa.inc28
-rw-r--r--lib/hipe/test/Makefile4
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_exceptions.erl215
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_inline_function.erl73
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_issues_hipe.erl28
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_receive.erl89
-rw-r--r--lib/hipe/test/erl_types_SUITE.erl197
-rw-r--r--lib/hipe/test/hipe_testsuite_driver.erl18
-rw-r--r--lib/hipe/test/opt_verify_SUITE.erl6
-rw-r--r--lib/hipe/vsn.mk2
-rw-r--r--lib/hipe/x86/hipe_rtl_to_x86.erl24
-rw-r--r--lib/hipe/x86/hipe_x86_assemble.erl1
-rw-r--r--lib/ic/AUTHORS8
-rw-r--r--lib/ic/Makefile42
-rw-r--r--lib/ic/c_src/Makefile25
-rw-r--r--lib/ic/c_src/Makefile.in165
-rw-r--r--lib/ic/c_src/Makefile.win32109
-rw-r--r--lib/ic/c_src/ic.c613
-rw-r--r--lib/ic/c_src/ic_tmo.c136
-rw-r--r--lib/ic/c_src/oe_ei_code_erlang_binary.c106
-rw-r--r--lib/ic/c_src/oe_ei_decode_longlong.c26
-rw-r--r--lib/ic/c_src/oe_ei_decode_ulonglong.c26
-rw-r--r--lib/ic/c_src/oe_ei_decode_wchar.c26
-rw-r--r--lib/ic/c_src/oe_ei_decode_wstring.c108
-rw-r--r--lib/ic/c_src/oe_ei_encode_atom.c47
-rw-r--r--lib/ic/c_src/oe_ei_encode_char.c45
-rw-r--r--lib/ic/c_src/oe_ei_encode_double.c44
-rw-r--r--lib/ic/c_src/oe_ei_encode_list_header.c42
-rw-r--r--lib/ic/c_src/oe_ei_encode_long.c45
-rw-r--r--lib/ic/c_src/oe_ei_encode_longlong.c45
-rw-r--r--lib/ic/c_src/oe_ei_encode_pid.c46
-rw-r--r--lib/ic/c_src/oe_ei_encode_port.c47
-rw-r--r--lib/ic/c_src/oe_ei_encode_ref.c47
-rw-r--r--lib/ic/c_src/oe_ei_encode_string.c48
-rw-r--r--lib/ic/c_src/oe_ei_encode_term.c49
-rw-r--r--lib/ic/c_src/oe_ei_encode_tuple_header.c45
-rw-r--r--lib/ic/c_src/oe_ei_encode_ulong.c44
-rw-r--r--lib/ic/c_src/oe_ei_encode_ulonglong.c45
-rw-r--r--lib/ic/c_src/oe_ei_encode_version.c43
-rw-r--r--lib/ic/c_src/oe_ei_encode_wchar.c28
-rw-r--r--lib/ic/c_src/oe_ei_encode_wstring.c63
-rw-r--r--lib/ic/doc/html/.gitignore0
-rw-r--r--lib/ic/doc/man1/.gitignore0
-rw-r--r--lib/ic/doc/man3/.gitignore0
-rw-r--r--lib/ic/doc/pdf/.gitignore0
-rw-r--r--lib/ic/doc/src/CORBA_Environment_alloc.xml143
-rw-r--r--lib/ic/doc/src/Makefile227
-rw-r--r--lib/ic/doc/src/book.xml50
-rw-r--r--lib/ic/doc/src/c-part.xml39
-rw-r--r--lib/ic/doc/src/ch_basic_idl.xml164
-rw-r--r--lib/ic/doc/src/ch_c_client.xml150
-rw-r--r--lib/ic/doc/src/ch_c_corba_env.xml386
-rw-r--r--lib/ic/doc/src/ch_c_mapping.xml893
-rw-r--r--lib/ic/doc/src/ch_c_server.xml149
-rw-r--r--lib/ic/doc/src/ch_erl_genserv.xml206
-rw-r--r--lib/ic/doc/src/ch_erl_plain.xml176
-rw-r--r--lib/ic/doc/src/ch_ic_protocol.xml234
-rw-r--r--lib/ic/doc/src/ch_introduction.xml149
-rw-r--r--lib/ic/doc/src/ch_java.xml738
-rw-r--r--lib/ic/doc/src/erl-part.xml37
-rw-r--r--lib/ic/doc/src/ic.xml468
-rw-r--r--lib/ic/doc/src/ic_c_protocol.xml157
-rw-r--r--lib/ic/doc/src/ic_clib.xml247
-rw-r--r--lib/ic/doc/src/java-part.xml36
-rw-r--r--lib/ic/doc/src/notes.xml791
-rw-r--r--lib/ic/doc/src/part.xml46
-rw-r--r--lib/ic/doc/src/ref_man.xml39
-rw-r--r--lib/ic/ebin/.gitignore0
-rw-r--r--lib/ic/examples/all-against-all/Makefile118
-rw-r--r--lib/ic/examples/all-against-all/Makefile.win32139
-rw-r--r--lib/ic/examples/all-against-all/ReadMe122
-rw-r--r--lib/ic/examples/all-against-all/callbacks.c46
-rw-r--r--lib/ic/examples/all-against-all/client.c154
-rw-r--r--lib/ic/examples/all-against-all/client.erl54
-rw-r--r--lib/ic/examples/all-against-all/client.java61
-rw-r--r--lib/ic/examples/all-against-all/random.idl51
-rw-r--r--lib/ic/examples/all-against-all/rmod_random_impl.erl49
-rw-r--r--lib/ic/examples/all-against-all/server.c262
-rw-r--r--lib/ic/examples/all-against-all/server.erl41
-rw-r--r--lib/ic/examples/all-against-all/server.java83
-rw-r--r--lib/ic/examples/all-against-all/serverImpl.java43
-rw-r--r--lib/ic/examples/c-client/Makefile87
-rw-r--r--lib/ic/examples/c-client/ReadMe46
-rw-r--r--lib/ic/examples/c-client/client.c131
-rw-r--r--lib/ic/examples/c-client/random.idl52
-rw-r--r--lib/ic/examples/c-client/rmod_random_impl.erl53
-rw-r--r--lib/ic/examples/c-client/test.erl44
-rw-r--r--lib/ic/examples/c-server/Makefile90
-rw-r--r--lib/ic/examples/c-server/ReadMe45
-rw-r--r--lib/ic/examples/c-server/callbacks.c46
-rw-r--r--lib/ic/examples/c-server/client.c125
-rw-r--r--lib/ic/examples/c-server/client.erl45
-rw-r--r--lib/ic/examples/c-server/random.idl50
-rw-r--r--lib/ic/examples/c-server/server.c246
-rw-r--r--lib/ic/examples/erl-genserv/ReadMe30
-rw-r--r--lib/ic/examples/erl-genserv/random.idl51
-rw-r--r--lib/ic/examples/erl-genserv/rmod_random_impl.erl64
-rw-r--r--lib/ic/examples/erl-plain/ReadMe27
-rw-r--r--lib/ic/examples/erl-plain/random.idl53
-rw-r--r--lib/ic/examples/erl-plain/rmod_random_impl.erl33
-rw-r--r--lib/ic/examples/java-client-server/ReadMe69
-rw-r--r--lib/ic/examples/java-client-server/client.java61
-rw-r--r--lib/ic/examples/java-client-server/random.idl50
-rw-r--r--lib/ic/examples/java-client-server/server.java83
-rw-r--r--lib/ic/examples/java-client-server/serverImpl.java43
-rw-r--r--lib/ic/examples/pre_post_condition/Makefile135
-rw-r--r--lib/ic/examples/pre_post_condition/ReadMe.txt74
-rw-r--r--lib/ic/examples/pre_post_condition/ex.idl30
-rw-r--r--lib/ic/examples/pre_post_condition/m_i_impl.erl50
-rw-r--r--lib/ic/examples/pre_post_condition/tracer.erl57
-rw-r--r--lib/ic/include/erlang.idl58
-rw-r--r--lib/ic/include/ic.h432
-rw-r--r--lib/ic/info2
-rw-r--r--lib/ic/internal_doc/c-improvements-1.txt84
-rw-r--r--lib/ic/internal_doc/protocol.txt182
-rw-r--r--lib/ic/java_src/Makefile42
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/Any.java1026
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/AnyHelper.java79
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/AnyHolder.java61
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/BooleanHolder.java63
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/ByteHolder.java62
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/CharHolder.java64
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/DoubleHolder.java62
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/Environment.java480
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/FloatHolder.java63
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/Holder.java34
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/IntHolder.java63
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/LongHolder.java61
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/Makefile122
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/Pid.java56
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/PidHelper.java145
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/PidHolder.java55
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/Port.java49
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/PortHelper.java141
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/PortHolder.java57
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/Ref.java61
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/RefHelper.java142
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/RefHolder.java55
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/ShortHolder.java62
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/StringHolder.java63
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/TCKind.java200
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/Term.java1113
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/TermHelper.java142
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/TermHolder.java59
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/TypeCode.java883
-rw-r--r--lib/ic/prebuild.skip1
-rw-r--r--lib/ic/priv/lib/.gitignore0
-rw-r--r--lib/ic/priv/obj/.gitignore0
-rw-r--r--lib/ic/src/Makefile219
-rw-r--r--lib/ic/src/ic.app.src53
-rw-r--r--lib/ic/src/ic.erl415
-rw-r--r--lib/ic/src/ic.hrl159
-rw-r--r--lib/ic/src/ic_array_java.erl296
-rw-r--r--lib/ic/src/ic_attribute_java.erl413
-rw-r--r--lib/ic/src/ic_cbe.erl1307
-rw-r--r--lib/ic/src/ic_cclient.erl1210
-rw-r--r--lib/ic/src/ic_code.erl585
-rw-r--r--lib/ic/src/ic_codegen.erl423
-rw-r--r--lib/ic/src/ic_constant_java.erl100
-rw-r--r--lib/ic/src/ic_cserver.erl2420
-rw-r--r--lib/ic/src/ic_debug.hrl38
-rw-r--r--lib/ic/src/ic_enum_java.erl313
-rw-r--r--lib/ic/src/ic_erl_template.erl640
-rw-r--r--lib/ic/src/ic_erlbe.erl1142
-rw-r--r--lib/ic/src/ic_error.erl376
-rw-r--r--lib/ic/src/ic_fetch.erl389
-rw-r--r--lib/ic/src/ic_file.erl448
-rw-r--r--lib/ic/src/ic_forms.erl442
-rw-r--r--lib/ic/src/ic_genobj.erl245
-rw-r--r--lib/ic/src/ic_java_type.erl1214
-rw-r--r--lib/ic/src/ic_jbe.erl1488
-rw-r--r--lib/ic/src/ic_noc.erl1117
-rw-r--r--lib/ic/src/ic_options.erl364
-rw-r--r--lib/ic/src/ic_plainbe.erl356
-rw-r--r--lib/ic/src/ic_pp.erl2245
-rw-r--r--lib/ic/src/ic_pragma.erl1957
-rw-r--r--lib/ic/src/ic_sequence_java.erl240
-rw-r--r--lib/ic/src/ic_struct_java.erl315
-rw-r--r--lib/ic/src/ic_symtab.erl235
-rw-r--r--lib/ic/src/ic_union_java.erl755
-rw-r--r--lib/ic/src/ic_util.erl314
-rw-r--r--lib/ic/src/icenum.erl206
-rw-r--r--lib/ic/src/iceval.erl556
-rw-r--r--lib/ic/src/icforms.hrl70
-rw-r--r--lib/ic/src/icparse.yrl872
-rw-r--r--lib/ic/src/icpreproc.erl112
-rw-r--r--lib/ic/src/icscan.erl453
-rw-r--r--lib/ic/src/icstruct.erl1917
-rw-r--r--lib/ic/src/ictk.erl874
-rw-r--r--lib/ic/src/ictype.erl1417
-rw-r--r--lib/ic/src/icunion.erl1491
-rw-r--r--lib/ic/src/icyeccpre.hrl125
-rw-r--r--lib/ic/test/Makefile276
-rw-r--r--lib/ic/test/c_client_erl_server_SUITE.erl265
-rw-r--r--lib/ic/test/c_client_erl_server_SUITE_data/Makefile.src155
-rw-r--r--lib/ic/test/c_client_erl_server_SUITE_data/c_client.c1760
-rw-r--r--lib/ic/test/c_client_erl_server_SUITE_data/c_erl_test.idl175
-rw-r--r--lib/ic/test/c_client_erl_server_SUITE_data/erl_server.erl29
-rw-r--r--lib/ic/test/c_client_erl_server_SUITE_data/m_i_impl.erl162
-rw-r--r--lib/ic/test/c_client_erl_server_proto_SUITE.erl265
-rw-r--r--lib/ic/test/c_client_erl_server_proto_SUITE_data/Makefile.src156
-rw-r--r--lib/ic/test/c_client_erl_server_proto_SUITE_data/c_client.c1764
-rw-r--r--lib/ic/test/c_client_erl_server_proto_SUITE_data/c_erl_test.idl174
-rw-r--r--lib/ic/test/c_client_erl_server_proto_SUITE_data/erl_server.erl29
-rw-r--r--lib/ic/test/c_client_erl_server_proto_SUITE_data/m_i_impl.erl162
-rw-r--r--lib/ic/test/c_client_erl_server_proto_SUITE_data/my.c51
-rw-r--r--lib/ic/test/c_client_erl_server_proto_tmo_SUITE.erl265
-rw-r--r--lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/Makefile.src155
-rw-r--r--lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/c_client.c1764
-rw-r--r--lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/c_erl_test.idl174
-rw-r--r--lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/erl_server.erl29
-rw-r--r--lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/m_i_impl.erl162
-rw-r--r--lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/my.c52
-rw-r--r--lib/ic/test/erl_client_c_server_SUITE.erl298
-rw-r--r--lib/ic/test/erl_client_c_server_SUITE_data/Makefile.src160
-rw-r--r--lib/ic/test/erl_client_c_server_SUITE_data/c_server.c300
-rw-r--r--lib/ic/test/erl_client_c_server_SUITE_data/callbacks.c611
-rw-r--r--lib/ic/test/erl_client_c_server_SUITE_data/erl_c_test.idl175
-rw-r--r--lib/ic/test/erl_client_c_server_SUITE_data/erl_client.erl332
-rw-r--r--lib/ic/test/erl_client_c_server_proto_SUITE.erl298
-rw-r--r--lib/ic/test/erl_client_c_server_proto_SUITE_data/Makefile.src160
-rw-r--r--lib/ic/test/erl_client_c_server_proto_SUITE_data/c_server.c300
-rw-r--r--lib/ic/test/erl_client_c_server_proto_SUITE_data/callbacks.c611
-rw-r--r--lib/ic/test/erl_client_c_server_proto_SUITE_data/erl_c_test.idl175
-rw-r--r--lib/ic/test/erl_client_c_server_proto_SUITE_data/erl_client.erl332
-rw-r--r--lib/ic/test/erl_client_c_server_proto_SUITE_data/my.c35
-rw-r--r--lib/ic/test/ic.cover2
-rw-r--r--lib/ic/test/ic.spec1
-rw-r--r--lib/ic/test/ic.spec.vxworks2
-rw-r--r--lib/ic/test/ic_SUITE.erl894
-rw-r--r--lib/ic/test/ic_SUITE_data/Corba.idl1013
-rw-r--r--lib/ic/test/ic_SUITE_data/Coss.idl1537
-rw-r--r--lib/ic/test/ic_SUITE_data/attr.idl30
-rw-r--r--lib/ic/test/ic_SUITE_data/c_err1.idl64
-rw-r--r--lib/ic/test/ic_SUITE_data/c_err2.idl31
-rw-r--r--lib/ic/test/ic_SUITE_data/c_err3.idl29
-rw-r--r--lib/ic/test/ic_SUITE_data/c_norm.idl164
-rw-r--r--lib/ic/test/ic_SUITE_data/enum.idl33
-rw-r--r--lib/ic/test/ic_SUITE_data/forward.idl35
-rw-r--r--lib/ic/test/ic_SUITE_data/include.idl31
-rw-r--r--lib/ic/test/ic_SUITE_data/include2.idl27
-rw-r--r--lib/ic/test/ic_SUITE_data/include3.idl26
-rw-r--r--lib/ic/test/ic_SUITE_data/inherit.idl69
-rw-r--r--lib/ic/test/ic_SUITE_data/inherit_err.idl72
-rw-r--r--lib/ic/test/ic_SUITE_data/inherit_warn.idl65
-rw-r--r--lib/ic/test/ic_SUITE_data/mult_ids.idl93
-rw-r--r--lib/ic/test/ic_SUITE_data/nasty.idl61
-rw-r--r--lib/ic/test/ic_SUITE_data/one.idl30
-rw-r--r--lib/ic/test/ic_SUITE_data/one_followed.idl55
-rw-r--r--lib/ic/test/ic_SUITE_data/one_out.idl29
-rw-r--r--lib/ic/test/ic_SUITE_data/one_raises.idl33
-rw-r--r--lib/ic/test/ic_SUITE_data/one_void.idl31
-rw-r--r--lib/ic/test/ic_SUITE_data/raises_reg.idl53
-rw-r--r--lib/ic/test/ic_SUITE_data/struct.idl54
-rw-r--r--lib/ic/test/ic_SUITE_data/syntax1.idl29
-rw-r--r--lib/ic/test/ic_SUITE_data/syntax2.idl28
-rw-r--r--lib/ic/test/ic_SUITE_data/syntax3.idl21
-rw-r--r--lib/ic/test/ic_SUITE_data/syntax4.idl24
-rw-r--r--lib/ic/test/ic_SUITE_data/syntax5.idl23
-rw-r--r--lib/ic/test/ic_SUITE_data/syntax6.idl21
-rw-r--r--lib/ic/test/ic_SUITE_data/type.idl191
-rw-r--r--lib/ic/test/ic_SUITE_data/typeid.idl29
-rw-r--r--lib/ic/test/ic_SUITE_data/u_case_mult.idl55
-rw-r--r--lib/ic/test/ic_SUITE_data/u_default.idl52
-rw-r--r--lib/ic/test/ic_SUITE_data/u_mult.idl62
-rw-r--r--lib/ic/test/ic_SUITE_data/u_norm.idl64
-rw-r--r--lib/ic/test/ic_SUITE_data/u_type.idl83
-rw-r--r--lib/ic/test/ic_SUITE_data/undef_id.idl64
-rw-r--r--lib/ic/test/ic_be_SUITE.erl75
-rw-r--r--lib/ic/test/ic_be_SUITE_data/plain.idl34
-rw-r--r--lib/ic/test/ic_pp_SUITE.erl569
-rw-r--r--lib/ic/test/ic_pp_SUITE_data/arg.idl39
-rw-r--r--lib/ic/test/ic_pp_SUITE_data/cascade.idl30
-rw-r--r--lib/ic/test/ic_pp_SUITE_data/comment.idl73
-rw-r--r--lib/ic/test/ic_pp_SUITE_data/concat.idl61
-rw-r--r--lib/ic/test/ic_pp_SUITE_data/define.idl42
-rw-r--r--lib/ic/test/ic_pp_SUITE_data/if.idl33
-rw-r--r--lib/ic/test/ic_pp_SUITE_data/if_zero.idl32
-rw-r--r--lib/ic/test/ic_pp_SUITE_data/improp_nest_constr.idl31
-rw-r--r--lib/ic/test/ic_pp_SUITE_data/inc.idl69
-rw-r--r--lib/ic/test/ic_pp_SUITE_data/included1.idl36
-rw-r--r--lib/ic/test/ic_pp_SUITE_data/included2.idl42
-rw-r--r--lib/ic/test/ic_pp_SUITE_data/includer.idl46
-rw-r--r--lib/ic/test/ic_pp_SUITE_data/line.idl46
-rw-r--r--lib/ic/test/ic_pp_SUITE_data/misc.idl45
-rw-r--r--lib/ic/test/ic_pp_SUITE_data/nopara.idl36
-rw-r--r--lib/ic/test/ic_pp_SUITE_data/predef.idl34
-rw-r--r--lib/ic/test/ic_pp_SUITE_data/predef_time.idl25
-rw-r--r--lib/ic/test/ic_pp_SUITE_data/self_ref.idl27
-rw-r--r--lib/ic/test/ic_pp_SUITE_data/separate.idl38
-rw-r--r--lib/ic/test/ic_pp_SUITE_data/swallow_sc.idl38
-rw-r--r--lib/ic/test/ic_pp_SUITE_data/unintended_grp.idl30
-rw-r--r--lib/ic/test/ic_pragma_SUITE.erl301
-rw-r--r--lib/ic/test/ic_pragma_SUITE_data/reg_m0.idl78
-rw-r--r--lib/ic/test/ic_pragma_SUITE_data/reg_m1.idl76
-rw-r--r--lib/ic/test/ic_pragma_SUITE_data/reg_m2.idl41
-rw-r--r--lib/ic/test/ic_pragma_SUITE_data/reg_m3.idl39
-rw-r--r--lib/ic/test/ic_pragma_SUITE_data/reg_m4.idl65
-rw-r--r--lib/ic/test/ic_pragma_SUITE_data/reg_m5.idl29
-rw-r--r--lib/ic/test/ic_pragma_SUITE_data/reg_m6.idl39
-rw-r--r--lib/ic/test/ic_pragma_SUITE_data/reg_m7.idl63
-rw-r--r--lib/ic/test/ic_pragma_SUITE_data/uggly.idl205
-rw-r--r--lib/ic/test/ic_register_SUITE.erl422
-rw-r--r--lib/ic/test/ic_register_SUITE_data/reg_m10.idl38
-rw-r--r--lib/ic/test/ic_register_SUITE_data/reg_m11.idl33
-rw-r--r--lib/ic/test/ic_register_SUITE_data/reg_m12.idl41
-rw-r--r--lib/ic/test/ic_register_SUITE_data/reg_m8.idl33
-rw-r--r--lib/ic/test/ic_register_SUITE_data/reg_m9.idl33
-rw-r--r--lib/ic/test/ic_smoke.spec1
-rw-r--r--lib/ic/test/java_client_erl_server_SUITE.erl319
-rw-r--r--lib/ic/test/java_client_erl_server_SUITE_data/JavaClient.java760
-rw-r--r--lib/ic/test/java_client_erl_server_SUITE_data/Makefile.src101
-rw-r--r--lib/ic/test/java_client_erl_server_SUITE_data/java_erl_test.idl69
-rw-r--r--lib/ic/test/java_client_erl_server_SUITE_data/m_i_impl.erl170
-rw-r--r--lib/ic/vsn.mk1
-rw-r--r--lib/inets/doc/src/Makefile6
-rw-r--r--lib/inets/doc/src/ftp.xml948
-rw-r--r--lib/inets/doc/src/ftp_client.xml86
-rw-r--r--lib/inets/doc/src/http_client.xml2
-rw-r--r--lib/inets/doc/src/http_uri.xml14
-rw-r--r--lib/inets/doc/src/httpc.xml85
-rw-r--r--lib/inets/doc/src/httpd.xml30
-rw-r--r--lib/inets/doc/src/httpd_custom_api.xml8
-rw-r--r--lib/inets/doc/src/httpd_socket.xml8
-rw-r--r--lib/inets/doc/src/httpd_util.xml55
-rw-r--r--lib/inets/doc/src/inets.xml29
-rw-r--r--lib/inets/doc/src/introduction.xml10
-rw-r--r--lib/inets/doc/src/mod_alias.xml10
-rw-r--r--lib/inets/doc/src/mod_auth.xml58
-rw-r--r--lib/inets/doc/src/mod_esi.xml10
-rw-r--r--lib/inets/doc/src/mod_security.xml39
-rw-r--r--lib/inets/doc/src/notes.xml381
-rw-r--r--lib/inets/doc/src/notes_history.xml4
-rw-r--r--lib/inets/doc/src/part.xml9
-rw-r--r--lib/inets/doc/src/ref_man.xml12
-rw-r--r--lib/inets/doc/src/tftp.xml647
-rw-r--r--lib/inets/examples/httpd_load_test/hdlt_slave.erl11
-rw-r--r--lib/inets/src/ftp/Makefile104
-rw-r--r--lib/inets/src/ftp/ftp.erl2596
-rw-r--r--lib/inets/src/ftp/ftp_internal.hrl33
-rw-r--r--lib/inets/src/ftp/ftp_progress.erl136
-rw-r--r--lib/inets/src/ftp/ftp_response.erl203
-rw-r--r--lib/inets/src/ftp/ftp_sup.erl60
-rw-r--r--lib/inets/src/http_client/httpc.erl118
-rw-r--r--lib/inets/src/http_client/httpc_cookie.erl2
-rw-r--r--lib/inets/src/http_client/httpc_handler.erl98
-rw-r--r--lib/inets/src/http_client/httpc_internal.hrl2
-rw-r--r--lib/inets/src/http_client/httpc_manager.erl36
-rw-r--r--lib/inets/src/http_client/httpc_request.erl84
-rw-r--r--lib/inets/src/http_client/httpc_response.erl234
-rw-r--r--lib/inets/src/http_lib/http_request.erl8
-rw-r--r--lib/inets/src/http_lib/http_uri.erl4
-rw-r--r--lib/inets/src/http_lib/http_util.erl32
-rw-r--r--lib/inets/src/http_server/httpd.erl31
-rw-r--r--lib/inets/src/http_server/httpd_esi.erl2
-rw-r--r--lib/inets/src/http_server/httpd_example.erl31
-rw-r--r--lib/inets/src/http_server/httpd_file.erl5
-rw-r--r--lib/inets/src/http_server/httpd_request.erl8
-rw-r--r--lib/inets/src/http_server/httpd_response.erl14
-rw-r--r--lib/inets/src/http_server/httpd_script_env.erl2
-rw-r--r--lib/inets/src/http_server/mod_alias.erl24
-rw-r--r--lib/inets/src/http_server/mod_disk_log.erl2
-rw-r--r--lib/inets/src/http_server/mod_esi.erl27
-rw-r--r--lib/inets/src/http_server/mod_log.erl2
-rw-r--r--lib/inets/src/http_server/mod_responsecontrol.erl2
-rw-r--r--lib/inets/src/inets_app/Makefile6
-rw-r--r--lib/inets/src/inets_app/inets.app.src17
-rw-r--r--lib/inets/src/inets_app/inets.appup.src4
-rw-r--r--lib/inets/src/inets_app/inets.erl16
-rw-r--r--lib/inets/src/inets_app/inets_ftp_wrapper.erl48
-rw-r--r--lib/inets/src/inets_app/inets_internal.hrl4
-rw-r--r--lib/inets/src/inets_app/inets_sup.erl30
-rw-r--r--lib/inets/src/inets_app/inets_tftp_wrapper.erl48
-rw-r--r--lib/inets/src/subdirs.mk2
-rw-r--r--lib/inets/src/tftp/Makefile109
-rw-r--r--lib/inets/src/tftp/tftp.erl398
-rw-r--r--lib/inets/src/tftp/tftp.hrl69
-rw-r--r--lib/inets/src/tftp/tftp_binary.erl239
-rw-r--r--lib/inets/src/tftp/tftp_engine.erl1422
-rw-r--r--lib/inets/src/tftp/tftp_file.erl390
-rw-r--r--lib/inets/src/tftp/tftp_lib.erl474
-rw-r--r--lib/inets/src/tftp/tftp_logger.erl99
-rw-r--r--lib/inets/src/tftp/tftp_sup.erl111
-rw-r--r--lib/inets/test/Makefile57
-rw-r--r--lib/inets/test/ftp_SUITE.erl1180
-rw-r--r--lib/inets/test/ftp_SUITE_data/vsftpd.conf26
-rw-r--r--lib/inets/test/ftp_format_SUITE.erl328
l---------lib/inets/test/ftp_internal.hrl1
-rw-r--r--lib/inets/test/ftp_property_test_SUITE.erl53
-rw-r--r--lib/inets/test/http_format_SUITE.erl4
-rw-r--r--lib/inets/test/httpc_SUITE.erl512
-rw-r--r--lib/inets/test/httpc_proxy_SUITE.erl2
-rw-r--r--lib/inets/test/httpd_SUITE.erl413
-rw-r--r--lib/inets/test/httpd_basic_SUITE.erl5
-rw-r--r--lib/inets/test/httpd_bench_SUITE.erl13
-rw-r--r--lib/inets/test/httpd_mod.erl2
-rw-r--r--lib/inets/test/inets_SUITE.erl79
-rw-r--r--lib/inets/test/inets_socketwrap_SUITE.erl36
-rw-r--r--lib/inets/test/inets_sup_SUITE.erl54
-rw-r--r--lib/inets/test/inets_test_lib.erl158
-rw-r--r--lib/inets/test/tftp_SUITE.erl949
-rw-r--r--lib/inets/test/tftp_test_lib.erl308
-rw-r--r--lib/inets/test/tftp_test_lib.hrl44
-rw-r--r--lib/inets/test/uri_SUITE.erl23
-rw-r--r--lib/inets/vsn.mk4
-rw-r--r--lib/jinterface/doc/src/Makefile13
-rw-r--r--lib/jinterface/doc/src/jinterface_users_guide.xml8
-rw-r--r--lib/jinterface/doc/src/notes.xml70
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/AbstractNode.java3
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile2
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/OtpEpmd.java2
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/OtpInputStream.java12
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java4
-rw-r--r--lib/jinterface/java_src/pom.xml.src11
-rw-r--r--lib/jinterface/test/jinterface_SUITE.erl2
-rw-r--r--lib/jinterface/test/nc_SUITE.erl20
-rw-r--r--lib/jinterface/vsn.mk2
-rw-r--r--lib/kernel/doc/src/.gitignore1
-rw-r--r--lib/kernel/doc/src/Makefile48
-rw-r--r--lib/kernel/doc/src/application.xml123
-rw-r--r--lib/kernel/doc/src/auth.xml18
-rw-r--r--lib/kernel/doc/src/book.xml5
-rw-r--r--lib/kernel/doc/src/code.xml108
-rw-r--r--lib/kernel/doc/src/config.xml15
-rw-r--r--lib/kernel/doc/src/disk_log.xml74
-rw-r--r--lib/kernel/doc/src/erl_boot_server.xml12
-rw-r--r--lib/kernel/doc/src/erl_ddll.xml36
-rw-r--r--lib/kernel/doc/src/erl_epmd.xml104
-rw-r--r--lib/kernel/doc/src/error_handler.xml8
-rw-r--r--lib/kernel/doc/src/error_logger.xml371
-rw-r--r--lib/kernel/doc/src/file.xml399
-rw-r--r--lib/kernel/doc/src/gen_sctp.xml113
-rw-r--r--lib/kernel/doc/src/gen_tcp.xml58
-rw-r--r--lib/kernel/doc/src/gen_udp.xml51
-rw-r--r--lib/kernel/doc/src/global.xml42
-rw-r--r--lib/kernel/doc/src/global_group.xml22
-rw-r--r--lib/kernel/doc/src/heart.xml25
-rw-r--r--lib/kernel/doc/src/inet.xml511
-rw-r--r--lib/kernel/doc/src/inet_res.xml46
-rw-r--r--lib/kernel/doc/src/introduction_chapter.xml63
-rw-r--r--lib/kernel/doc/src/kernel_app.xml238
-rw-r--r--lib/kernel/doc/src/logger.xml1353
-rw-r--r--lib/kernel/doc/src/logger_arch.diabin0 -> 2527 bytes
-rw-r--r--lib/kernel/doc/src/logger_arch.pngbin0 -> 117205 bytes
-rw-r--r--lib/kernel/doc/src/logger_chapter.xml1399
-rw-r--r--lib/kernel/doc/src/logger_disk_log_h.xml168
-rw-r--r--lib/kernel/doc/src/logger_filters.xml254
-rw-r--r--lib/kernel/doc/src/logger_formatter.xml354
-rw-r--r--lib/kernel/doc/src/logger_std_h.xml217
-rw-r--r--lib/kernel/doc/src/net_adm.xml22
-rw-r--r--lib/kernel/doc/src/net_kernel.xml45
-rw-r--r--lib/kernel/doc/src/notes.xml871
-rw-r--r--lib/kernel/doc/src/os.xml130
-rw-r--r--lib/kernel/doc/src/part.xml37
-rw-r--r--lib/kernel/doc/src/pg2.xml22
-rw-r--r--lib/kernel/doc/src/ref_man.xml12
-rw-r--r--lib/kernel/doc/src/rpc.xml67
-rw-r--r--lib/kernel/doc/src/seq_trace.xml31
-rw-r--r--lib/kernel/doc/src/specs.xml6
-rw-r--r--lib/kernel/doc/src/wrap_log_reader.xml12
-rw-r--r--lib/kernel/examples/Makefile2
-rw-r--r--lib/kernel/examples/gen_tcp_dist/Makefile18
-rw-r--r--lib/kernel/examples/gen_tcp_dist/ebin/.gitignore (renamed from lib/cosEvent/example/.gitignore)0
-rw-r--r--lib/kernel/examples/gen_tcp_dist/src/gen_tcp_dist.erl788
-rw-r--r--lib/kernel/include/dist.hrl10
-rw-r--r--lib/kernel/include/dist_util.hrl14
-rw-r--r--lib/kernel/include/logger.hrl53
-rw-r--r--lib/kernel/src/Makefile61
-rw-r--r--lib/kernel/src/application.erl22
-rw-r--r--lib/kernel/src/application_controller.erl182
-rw-r--r--lib/kernel/src/application_master.erl6
-rw-r--r--lib/kernel/src/auth.erl8
-rw-r--r--lib/kernel/src/code.erl11
-rw-r--r--lib/kernel/src/code_server.erl22
-rw-r--r--lib/kernel/src/disk_log_1.erl4
-rw-r--r--lib/kernel/src/dist_util.erl478
-rw-r--r--lib/kernel/src/erl_boot_server.erl4
-rw-r--r--lib/kernel/src/erl_distribution.erl6
-rw-r--r--lib/kernel/src/erl_epmd.erl74
-rw-r--r--lib/kernel/src/erl_reply.erl4
-rw-r--r--lib/kernel/src/erl_signal_handler.erl13
-rw-r--r--lib/kernel/src/error_handler.erl6
-rw-r--r--lib/kernel/src/error_logger.erl615
-rw-r--r--lib/kernel/src/erts_debug.erl224
-rw-r--r--lib/kernel/src/file.erl96
-rw-r--r--lib/kernel/src/file_int.hrl33
-rw-r--r--lib/kernel/src/file_io_server.erl73
-rw-r--r--lib/kernel/src/file_server.erl143
-rw-r--r--lib/kernel/src/gen_sctp.erl22
-rw-r--r--lib/kernel/src/gen_tcp.erl28
-rw-r--r--lib/kernel/src/gen_udp.erl29
-rw-r--r--lib/kernel/src/global.erl85
-rw-r--r--lib/kernel/src/group.erl301
-rw-r--r--lib/kernel/src/hipe_unified_loader.erl3
-rw-r--r--lib/kernel/src/inet.erl136
-rw-r--r--lib/kernel/src/inet6_tcp.erl8
-rw-r--r--lib/kernel/src/inet_config.erl6
-rw-r--r--lib/kernel/src/inet_db.erl8
-rw-r--r--lib/kernel/src/inet_dns.erl8
-rw-r--r--lib/kernel/src/inet_hosts.erl5
-rw-r--r--lib/kernel/src/inet_int.hrl16
-rw-r--r--lib/kernel/src/inet_parse.erl4
-rw-r--r--lib/kernel/src/inet_res.erl40
-rw-r--r--lib/kernel/src/inet_tcp.erl8
-rw-r--r--lib/kernel/src/inet_tcp_dist.erl151
-rw-r--r--lib/kernel/src/kernel.app.src35
-rw-r--r--lib/kernel/src/kernel.appup.src41
-rw-r--r--lib/kernel/src/kernel.erl125
-rw-r--r--lib/kernel/src/kernel_config.erl9
-rw-r--r--lib/kernel/src/kernel_refc.erl139
-rw-r--r--lib/kernel/src/logger.erl1146
-rw-r--r--lib/kernel/src/logger_backend.erl133
-rw-r--r--lib/kernel/src/logger_config.erl160
-rw-r--r--lib/kernel/src/logger_disk_log_h.erl252
-rw-r--r--lib/kernel/src/logger_filters.erl127
-rw-r--r--lib/kernel/src/logger_formatter.erl563
-rw-r--r--lib/kernel/src/logger_h_common.erl463
-rw-r--r--lib/kernel/src/logger_h_common.hrl127
-rw-r--r--lib/kernel/src/logger_handler_watcher.erl113
-rw-r--r--lib/kernel/src/logger_internal.hrl104
-rw-r--r--lib/kernel/src/logger_olp.erl627
-rw-r--r--lib/kernel/src/logger_olp.hrl185
-rw-r--r--lib/kernel/src/logger_proxy.erl165
-rw-r--r--lib/kernel/src/logger_server.erl617
-rw-r--r--lib/kernel/src/logger_simple_h.erl215
-rw-r--r--lib/kernel/src/logger_std_h.erl643
-rw-r--r--lib/kernel/src/logger_sup.erl59
-rw-r--r--lib/kernel/src/net.erl40
-rw-r--r--lib/kernel/src/net_kernel.erl374
-rw-r--r--lib/kernel/src/os.erl125
-rw-r--r--lib/kernel/src/raw_file_io.erl75
-rw-r--r--lib/kernel/src/raw_file_io_compressed.erl134
-rw-r--r--lib/kernel/src/raw_file_io_deflate.erl159
-rw-r--r--lib/kernel/src/raw_file_io_delayed.erl320
-rw-r--r--lib/kernel/src/raw_file_io_inflate.erl261
-rw-r--r--lib/kernel/src/raw_file_io_list.erl128
-rw-r--r--lib/kernel/src/raw_file_io_raw.erl25
-rw-r--r--lib/kernel/src/rpc.erl15
-rw-r--r--lib/kernel/src/seq_trace.erl10
-rw-r--r--lib/kernel/src/standard_error.erl3
-rw-r--r--lib/kernel/src/user.erl3
-rw-r--r--lib/kernel/src/user_drv.erl17
-rw-r--r--lib/kernel/test/Makefile34
-rw-r--r--lib/kernel/test/application_SUITE.erl148
-rw-r--r--lib/kernel/test/code_SUITE.erl54
-rw-r--r--lib/kernel/test/disk_log_SUITE.erl218
-rw-r--r--lib/kernel/test/erl_distribution_SUITE.erl355
-rw-r--r--lib/kernel/test/erl_distribution_wb_SUITE.erl16
-rw-r--r--lib/kernel/test/erl_prim_loader_SUITE.erl5
-rw-r--r--lib/kernel/test/error_logger_SUITE.erl64
-rw-r--r--lib/kernel/test/error_logger_warn_SUITE.erl16
-rw-r--r--lib/kernel/test/file_SUITE.erl378
-rw-r--r--lib/kernel/test/file_name_SUITE.erl39
-rw-r--r--lib/kernel/test/gen_sctp_SUITE.erl18
-rw-r--r--lib/kernel/test/gen_tcp_api_SUITE.erl6
-rw-r--r--lib/kernel/test/gen_tcp_api_SUITE_data/gen_tcp_api_SUITE.c1
-rw-r--r--lib/kernel/test/gen_tcp_misc_SUITE.erl503
-rw-r--r--lib/kernel/test/gen_udp_SUITE.erl302
-rw-r--r--lib/kernel/test/global_SUITE.erl30
-rw-r--r--lib/kernel/test/heart_SUITE.erl23
-rw-r--r--lib/kernel/test/inet_SUITE.erl230
-rw-r--r--lib/kernel/test/inet_res_SUITE.erl15
-rw-r--r--lib/kernel/test/inet_sockopt_SUITE.erl9
-rw-r--r--lib/kernel/test/init_SUITE.erl88
-rw-r--r--lib/kernel/test/kernel.spec1
-rw-r--r--lib/kernel/test/kernel_SUITE.erl71
-rw-r--r--lib/kernel/test/kernel_bench.spec2
-rw-r--r--lib/kernel/test/kernel_config_SUITE.erl25
-rw-r--r--lib/kernel/test/logger.cover17
-rw-r--r--lib/kernel/test/logger.spec13
-rw-r--r--lib/kernel/test/logger_SUITE.erl1390
-rw-r--r--lib/kernel/test/logger_disk_log_h_SUITE.erl1668
-rw-r--r--lib/kernel/test/logger_env_var_SUITE.erl697
-rw-r--r--lib/kernel/test/logger_filters_SUITE.erl227
-rw-r--r--lib/kernel/test/logger_formatter_SUITE.erl886
-rw-r--r--lib/kernel/test/logger_legacy_SUITE.erl288
-rw-r--r--lib/kernel/test/logger_olp_SUITE.erl90
-rw-r--r--lib/kernel/test/logger_proxy_SUITE.erl274
-rw-r--r--lib/kernel/test/logger_simple_h_SUITE.erl209
-rw-r--r--lib/kernel/test/logger_std_h_SUITE.erl2135
-rw-r--r--lib/kernel/test/logger_stress_SUITE.erl550
-rw-r--r--lib/kernel/test/logger_test_lib.erl88
-rw-r--r--lib/kernel/test/os_SUITE.erl22
-rw-r--r--lib/kernel/test/pdict_SUITE.erl34
-rw-r--r--lib/kernel/test/prim_file_SUITE.erl742
-rw-r--r--lib/kernel/test/sendfile_SUITE.erl164
-rw-r--r--lib/kernel/test/seq_trace_SUITE.erl167
-rw-r--r--lib/kernel/test/wrap_log_reader_SUITE.erl19
-rw-r--r--lib/kernel/test/wrap_log_reader_SUITE_data/wrap_log_test.erl26
-rw-r--r--lib/kernel/test/zlib_SUITE.erl49
-rw-r--r--lib/kernel/test/zzz_SUITE.erl37
-rw-r--r--lib/kernel/vsn.mk2
-rw-r--r--lib/megaco/configure.in115
-rw-r--r--lib/megaco/doc/src/Makefile3
-rw-r--r--lib/megaco/doc/src/book.xml2
-rw-r--r--lib/megaco/doc/src/megaco.xml102
-rw-r--r--lib/megaco/doc/src/megaco_codec_meas.xml6
-rw-r--r--lib/megaco/doc/src/megaco_codec_mstone1.xml26
-rw-r--r--lib/megaco/doc/src/megaco_codec_mstone2.xml6
-rw-r--r--lib/megaco/doc/src/megaco_codec_transform.xml6
-rw-r--r--lib/megaco/doc/src/megaco_edist_compress.xml6
-rw-r--r--lib/megaco/doc/src/megaco_encoder.xml14
-rw-r--r--lib/megaco/doc/src/megaco_flex_scanner.xml12
-rw-r--r--lib/megaco/doc/src/megaco_tcp.xml30
-rw-r--r--lib/megaco/doc/src/megaco_transport.xml8
-rw-r--r--lib/megaco/doc/src/megaco_udp.xml30
-rw-r--r--lib/megaco/doc/src/megaco_user.xml48
-rw-r--r--lib/megaco/doc/src/notes.xml40
-rw-r--r--lib/megaco/src/flex/Makefile.in40
-rw-r--r--lib/megaco/vsn.mk2
-rw-r--r--lib/mnesia/doc/src/Makefile13
-rw-r--r--lib/mnesia/doc/src/Mnesia_chap2.xmlsrc2
-rw-r--r--lib/mnesia/doc/src/Mnesia_chap5.xmlsrc8
-rw-r--r--lib/mnesia/doc/src/company.erl2
-rw-r--r--lib/mnesia/doc/src/company_o.erl2
-rw-r--r--lib/mnesia/doc/src/mnesia.xml243
-rw-r--r--lib/mnesia/doc/src/mnesia_frag_hash.xml16
-rw-r--r--lib/mnesia/doc/src/mnesia_registry.xml6
-rw-r--r--lib/mnesia/doc/src/notes.xml154
-rw-r--r--lib/mnesia/examples/bench/README6
-rw-r--r--lib/mnesia/src/mnesia.erl146
-rw-r--r--lib/mnesia/src/mnesia.hrl6
-rw-r--r--lib/mnesia/src/mnesia_bup.erl10
-rw-r--r--lib/mnesia/src/mnesia_checkpoint.erl10
-rw-r--r--lib/mnesia/src/mnesia_controller.erl37
-rw-r--r--lib/mnesia/src/mnesia_dumper.erl50
-rw-r--r--lib/mnesia/src/mnesia_frag.erl7
-rw-r--r--lib/mnesia/src/mnesia_index.erl48
-rw-r--r--lib/mnesia/src/mnesia_late_loader.erl2
-rw-r--r--lib/mnesia/src/mnesia_lib.erl20
-rw-r--r--lib/mnesia/src/mnesia_loader.erl21
-rw-r--r--lib/mnesia/src/mnesia_locker.erl9
-rw-r--r--lib/mnesia/src/mnesia_log.erl2
-rw-r--r--lib/mnesia/src/mnesia_recover.erl8
-rw-r--r--lib/mnesia/src/mnesia_schema.erl11
-rw-r--r--lib/mnesia/src/mnesia_subscr.erl2
-rw-r--r--lib/mnesia/src/mnesia_text.erl2
-rw-r--r--lib/mnesia/src/mnesia_tm.erl31
-rw-r--r--lib/mnesia/test/Makefile3
-rw-r--r--lib/mnesia/test/README6
-rw-r--r--lib/mnesia/test/mnesia_SUITE.erl5
-rw-r--r--lib/mnesia/test/mnesia_atomicity_test.erl2
-rw-r--r--lib/mnesia/test/mnesia_bench_SUITE.erl2
-rw-r--r--lib/mnesia/test/mnesia_consistency_test.erl2
-rw-r--r--lib/mnesia/test/mnesia_cost.erl2
-rw-r--r--lib/mnesia/test/mnesia_dirty_access_test.erl36
-rw-r--r--lib/mnesia/test/mnesia_durability_test.erl109
-rw-r--r--lib/mnesia/test/mnesia_evil_coverage_test.erl107
-rw-r--r--lib/mnesia/test/mnesia_examples_test.erl2
-rw-r--r--lib/mnesia/test/mnesia_frag_test.erl2
-rw-r--r--lib/mnesia/test/mnesia_index_plugin_test.erl261
-rw-r--r--lib/mnesia/test/mnesia_install_test.erl2
-rw-r--r--lib/mnesia/test/mnesia_isolation_test.erl13
-rw-r--r--lib/mnesia/test/mnesia_majority_test.erl2
-rw-r--r--lib/mnesia/test/mnesia_measure_test.erl2
-rw-r--r--lib/mnesia/test/mnesia_nice_coverage_test.erl2
-rw-r--r--lib/mnesia/test/mnesia_qlc_test.erl2
-rw-r--r--lib/mnesia/test/mnesia_recovery_test.erl3
-rw-r--r--lib/mnesia/test/mnesia_registry_test.erl2
-rw-r--r--lib/mnesia/test/mnesia_schema_recovery_test.erl2
-rw-r--r--lib/mnesia/test/mnesia_test_lib.erl8
-rw-r--r--lib/mnesia/test/mnesia_test_lib.hrl14
-rw-r--r--lib/mnesia/test/mnesia_trans_access_test.erl2
-rw-r--r--lib/mnesia/test/mt.erl1
-rw-r--r--lib/mnesia/vsn.mk2
-rw-r--r--lib/observer/doc/src/Makefile1
-rw-r--r--lib/observer/doc/src/crashdump.xml8
-rw-r--r--lib/observer/doc/src/etop.xml14
-rw-r--r--lib/observer/doc/src/notes.xml139
-rw-r--r--lib/observer/doc/src/observer.xml4
-rw-r--r--lib/observer/doc/src/ttb.xml47
-rw-r--r--lib/observer/include/etop.hrl2
-rw-r--r--lib/observer/src/Makefile1
-rw-r--r--lib/observer/src/cdv_atom_cb.erl2
-rw-r--r--lib/observer/src/cdv_bin_cb.erl4
-rw-r--r--lib/observer/src/cdv_detail_wx.erl5
-rw-r--r--lib/observer/src/cdv_dist_cb.erl4
-rw-r--r--lib/observer/src/cdv_html_wx.erl41
-rw-r--r--lib/observer/src/cdv_info_wx.erl2
-rw-r--r--lib/observer/src/cdv_mem_cb.erl6
-rw-r--r--lib/observer/src/cdv_multi_wx.erl2
-rw-r--r--lib/observer/src/cdv_persistent_cb.erl32
-rw-r--r--lib/observer/src/cdv_port_cb.erl2
-rw-r--r--lib/observer/src/cdv_proc_cb.erl2
-rw-r--r--lib/observer/src/cdv_sched_cb.erl2
-rw-r--r--lib/observer/src/cdv_table_wx.erl5
-rw-r--r--lib/observer/src/cdv_term_cb.erl4
-rw-r--r--lib/observer/src/cdv_virtual_list_wx.erl5
-rw-r--r--lib/observer/src/cdv_wx.erl32
-rw-r--r--lib/observer/src/crashdump_viewer.erl333
-rw-r--r--lib/observer/src/crashdump_viewer.hrl2
-rw-r--r--lib/observer/src/etop_tr.erl2
-rw-r--r--lib/observer/src/multitrace.erl2
-rw-r--r--lib/observer/src/observer.app.src8
-rw-r--r--lib/observer/src/observer_alloc_wx.erl9
-rw-r--r--lib/observer/src/observer_app_wx.erl11
-rw-r--r--lib/observer/src/observer_html_lib.erl15
-rw-r--r--lib/observer/src/observer_lib.erl6
-rw-r--r--lib/observer/src/observer_perf_wx.erl21
-rw-r--r--lib/observer/src/observer_port_wx.erl16
-rw-r--r--lib/observer/src/observer_pro_wx.erl50
-rw-r--r--lib/observer/src/observer_procinfo.erl15
-rw-r--r--lib/observer/src/observer_trace_wx.erl17
-rw-r--r--lib/observer/src/observer_traceoptions_wx.erl15
-rw-r--r--lib/observer/src/observer_tv_table.erl3
-rw-r--r--lib/observer/src/observer_tv_wx.erl19
-rw-r--r--lib/observer/src/observer_wx.erl24
-rw-r--r--lib/observer/src/ttb.erl6
-rw-r--r--lib/observer/src/ttb_et.erl2
-rw-r--r--lib/observer/test/crashdump_helper.erl70
-rw-r--r--lib/observer/test/crashdump_viewer_SUITE.erl42
-rw-r--r--lib/observer/test/crashdump_viewer_SUITE_data/old_format.dump24
-rw-r--r--lib/observer/test/observer_SUITE.erl7
-rw-r--r--lib/observer/test/ttb_SUITE.erl8
-rw-r--r--lib/observer/vsn.mk2
-rw-r--r--lib/odbc/c_src/Makefile.in2
-rw-r--r--lib/odbc/c_src/odbcserver.c5
-rw-r--r--lib/odbc/configure.in6
-rw-r--r--lib/odbc/doc/src/Makefile3
-rw-r--r--lib/odbc/doc/src/databases.xml2
-rw-r--r--lib/odbc/doc/src/error_handling.xml2
-rw-r--r--lib/odbc/doc/src/getting_started.xml2
-rw-r--r--lib/odbc/doc/src/notes.xml50
-rw-r--r--lib/odbc/doc/src/notes_history.xml4
-rw-r--r--lib/odbc/doc/src/odbc.xml54
-rw-r--r--lib/odbc/test/odbc_connect_SUITE.erl2
-rw-r--r--lib/odbc/vsn.mk2
-rw-r--r--lib/orber/AUTHORS8
-rw-r--r--lib/orber/COSS/CosNaming/CosNaming_BindingIterator_impl.erl94
-rw-r--r--lib/orber/COSS/CosNaming/CosNaming_NamingContextExt_impl.erl756
-rw-r--r--lib/orber/COSS/CosNaming/Makefile153
-rw-r--r--lib/orber/COSS/CosNaming/cos_naming.idl77
-rw-r--r--lib/orber/COSS/CosNaming/cos_naming_ext.idl37
-rw-r--r--lib/orber/COSS/CosNaming/lname.erl134
-rw-r--r--lib/orber/COSS/CosNaming/lname.hrl34
-rw-r--r--lib/orber/COSS/CosNaming/lname_component.erl84
-rw-r--r--lib/orber/COSS/CosNaming/orber_cosnaming.hrl64
-rw-r--r--lib/orber/COSS/CosNaming/orber_cosnaming_utils.erl762
-rw-r--r--lib/orber/Makefile42
-rw-r--r--lib/orber/c_src/InitialReference.cc206
-rw-r--r--lib/orber/c_src/InitialReference.hh60
-rw-r--r--lib/orber/c_src/Makefile24
-rw-r--r--lib/orber/c_src/Makefile.in100
-rw-r--r--lib/orber/c_src/main.cc32
-rw-r--r--lib/orber/doc/etc/.gitignore0
-rw-r--r--lib/orber/doc/html/.gitignore0
-rw-r--r--lib/orber/doc/javadoc/.gitignore0
-rw-r--r--lib/orber/doc/man1/.gitignore0
-rw-r--r--lib/orber/doc/man3/.gitignore0
-rw-r--r--lib/orber/doc/pdf/.gitignore0
-rw-r--r--lib/orber/doc/src/CosNaming.xml71
-rw-r--r--lib/orber/doc/src/CosNaming_BindingIterator.xml99
-rw-r--r--lib/orber/doc/src/CosNaming_NamingContext.xml243
-rw-r--r--lib/orber/doc/src/CosNaming_NamingContextExt.xml102
-rw-r--r--lib/orber/doc/src/Makefile172
-rw-r--r--lib/orber/doc/src/Module_Interface.xml356
-rw-r--r--lib/orber/doc/src/Orber/InitialReference.java131
-rw-r--r--lib/orber/doc/src/Orber/Makefile71
-rw-r--r--lib/orber/doc/src/any.xml114
-rw-r--r--lib/orber/doc/src/book.xml49
-rw-r--r--lib/orber/doc/src/ch_contents.xml173
-rw-r--r--lib/orber/doc/src/ch_debugging.xml210
-rw-r--r--lib/orber/doc/src/ch_exceptions.xml238
-rw-r--r--lib/orber/doc/src/ch_idl_to_erlang_mapping.xml1504
-rw-r--r--lib/orber/doc/src/ch_ifr.xml50
-rw-r--r--lib/orber/doc/src/ch_install.xml1001
-rw-r--r--lib/orber/doc/src/ch_interceptors.xml278
-rw-r--r--lib/orber/doc/src/ch_introduction.xml145
-rw-r--r--lib/orber/doc/src/ch_naming_service.xml465
-rw-r--r--lib/orber/doc/src/ch_orber_kernel.xml103
-rw-r--r--lib/orber/doc/src/ch_orberweb.xml221
-rw-r--r--lib/orber/doc/src/ch_security.xml96
-rw-r--r--lib/orber/doc/src/ch_stubs.xml284
-rw-r--r--lib/orber/doc/src/corba.xml454
-rw-r--r--lib/orber/doc/src/corba_object.xml194
-rw-r--r--lib/orber/doc/src/dataframe1.gifbin21074 -> 0 bytes
-rw-r--r--lib/orber/doc/src/dataframe2.gifbin27848 -> 0 bytes
-rw-r--r--lib/orber/doc/src/dataframe3.gifbin30290 -> 0 bytes
-rw-r--r--lib/orber/doc/src/dataframe4.gifbin40114 -> 0 bytes
-rw-r--r--lib/orber/doc/src/dataframe5.gifbin11184 -> 0 bytes
-rw-r--r--lib/orber/doc/src/dataframe6.gifbin12331 -> 0 bytes
-rw-r--r--lib/orber/doc/src/dataframe7.gifbin12768 -> 0 bytes
-rw-r--r--lib/orber/doc/src/dataframe8.gifbin29939 -> 0 bytes
-rw-r--r--lib/orber/doc/src/dependent.gifbin1936 -> 0 bytes
-rw-r--r--lib/orber/doc/src/example_part.xml36
-rw-r--r--lib/orber/doc/src/firewall_nat.gifbin11939 -> 0 bytes
-rw-r--r--lib/orber/doc/src/fixed.xml160
-rw-r--r--lib/orber/doc/src/ifr_notes.txt53
-rw-r--r--lib/orber/doc/src/iiop.gifbin5899 -> 0 bytes
-rw-r--r--lib/orber/doc/src/images/GridBagEx.gifbin2453 -> 0 bytes
-rw-r--r--lib/orber/doc/src/images/OpenBookIcon.gifbin2241 -> 0 bytes
-rw-r--r--lib/orber/doc/src/images/blue-ball-small.gifbin255 -> 0 bytes
-rw-r--r--lib/orber/doc/src/images/blue-ball.gifbin925 -> 0 bytes
-rw-r--r--lib/orber/doc/src/images/class-index.gifbin1497 -> 0 bytes
-rw-r--r--lib/orber/doc/src/images/constructor-index.gifbin1711 -> 0 bytes
-rw-r--r--lib/orber/doc/src/images/constructors.gifbin1565 -> 0 bytes
-rw-r--r--lib/orber/doc/src/images/cyan-ball-small.gifbin255 -> 0 bytes
-rw-r--r--lib/orber/doc/src/images/cyan-ball.gifbin925 -> 0 bytes
-rw-r--r--lib/orber/doc/src/images/error-index.gifbin1438 -> 0 bytes
-rw-r--r--lib/orber/doc/src/images/exception-index.gifbin1707 -> 0 bytes
-rw-r--r--lib/orber/doc/src/images/green-ball-small.gifbin102 -> 0 bytes
-rw-r--r--lib/orber/doc/src/images/green-ball.gifbin886 -> 0 bytes
-rw-r--r--lib/orber/doc/src/images/interface-index.gifbin1648 -> 0 bytes
-rw-r--r--lib/orber/doc/src/images/magenta-ball-small.gifbin104 -> 0 bytes
-rw-r--r--lib/orber/doc/src/images/magenta-ball.gifbin896 -> 0 bytes
-rw-r--r--lib/orber/doc/src/images/method-index.gifbin1588 -> 0 bytes
-rw-r--r--lib/orber/doc/src/images/methods.gifbin1403 -> 0 bytes
-rw-r--r--lib/orber/doc/src/images/package-index.gifbin1607 -> 0 bytes
-rw-r--r--lib/orber/doc/src/images/red-ball-small.gifbin255 -> 0 bytes
-rw-r--r--lib/orber/doc/src/images/red-ball.gifbin527 -> 0 bytes
-rw-r--r--lib/orber/doc/src/images/variable-index.gifbin1576 -> 0 bytes
-rw-r--r--lib/orber/doc/src/images/variables.gifbin1380 -> 0 bytes
-rw-r--r--lib/orber/doc/src/images/yellow-ball-small.gifbin255 -> 0 bytes
-rw-r--r--lib/orber/doc/src/images/yellow-ball.gifbin925 -> 0 bytes
-rw-r--r--lib/orber/doc/src/interceptor_operations.gifbin14537 -> 0 bytes
-rw-r--r--lib/orber/doc/src/interceptors.xml284
-rw-r--r--lib/orber/doc/src/intro_part.xml41
-rw-r--r--lib/orber/doc/src/lname.xml166
-rw-r--r--lib/orber/doc/src/lname_component.xml113
-rw-r--r--lib/orber/doc/src/menuframe.gifbin12007 -> 0 bytes
-rw-r--r--lib/orber/doc/src/name.gifbin5015 -> 0 bytes
-rw-r--r--lib/orber/doc/src/notes.xml860
-rw-r--r--lib/orber/doc/src/orber.xml653
-rw-r--r--lib/orber/doc/src/orber_acl.xml107
-rw-r--r--lib/orber/doc/src/orber_diagnostics.xml81
-rw-r--r--lib/orber/doc/src/orber_ifr.xml1035
-rw-r--r--lib/orber/doc/src/orber_tc.xml259
-rw-r--r--lib/orber/doc/src/orbs.gifbin2817 -> 0 bytes
-rw-r--r--lib/orber/doc/src/part.xml49
-rw-r--r--lib/orber/doc/src/ref_man.xml53
-rw-r--r--lib/orber/doc/src/theORB.gifbin4706 -> 0 bytes
-rw-r--r--lib/orber/doc/src/tools_debugging_part.xml40
-rw-r--r--lib/orber/ebin/.gitignore0
-rw-r--r--lib/orber/examples/Makefile42
-rw-r--r--lib/orber/examples/Stack/InitialReferences.idl12
-rw-r--r--lib/orber/examples/Stack/Makefile128
-rw-r--r--lib/orber/examples/Stack/StackClient.cc97
-rw-r--r--lib/orber/examples/Stack/StackClient.java73
-rw-r--r--lib/orber/examples/Stack/StackModule_StackFactory_impl.erl41
-rw-r--r--lib/orber/examples/Stack/StackModule_Stack_impl.erl47
-rw-r--r--lib/orber/examples/Stack/stack.idl27
-rw-r--r--lib/orber/examples/Stack/stack_client.erl56
-rw-r--r--lib/orber/examples/Stack/stack_factory.erl38
-rw-r--r--lib/orber/include/corba.hrl149
-rw-r--r--lib/orber/include/ifr_types.hrl73
-rw-r--r--lib/orber/include/orber_pi.hrl77
-rw-r--r--lib/orber/info2
-rw-r--r--lib/orber/java_src/Makefile42
-rw-r--r--lib/orber/java_src/Orber/InitialReference.java131
-rw-r--r--lib/orber/java_src/Orber/Makefile71
-rw-r--r--lib/orber/prebuild.skip5
-rw-r--r--lib/orber/priv/Makefile67
-rw-r--r--lib/orber/priv/Orber/.gitignore0
-rw-r--r--lib/orber/priv/bin/.gitignore0
-rw-r--r--lib/orber/priv/blank.html6
-rw-r--r--lib/orber/priv/info_frames.html9
-rw-r--r--lib/orber/priv/main_frame.html9
-rw-r--r--lib/orber/priv/obj/.gitignore0
-rw-r--r--lib/orber/priv/orber.tool2
-rw-r--r--lib/orber/priv/orber_help.txt42
-rw-r--r--lib/orber/priv/start_info.html31
-rw-r--r--lib/orber/src/CORBA.idl22
-rw-r--r--lib/orber/src/Makefile263
-rw-r--r--lib/orber/src/OrberApp_IFR_impl.erl102
-rw-r--r--lib/orber/src/OrberCSIv2.asn145
-rw-r--r--lib/orber/src/OrberCSIv2.set.asn5
-rw-r--r--lib/orber/src/OrberIFR.idl12
-rw-r--r--lib/orber/src/PKIX1Algorithms88.asn1274
-rw-r--r--lib/orber/src/PKIX1Explicit88.asn1619
-rw-r--r--lib/orber/src/PKIX1Implicit88.asn1349
-rw-r--r--lib/orber/src/PKIXAttributeCertificate.asn1189
-rw-r--r--lib/orber/src/any.erl74
-rw-r--r--lib/orber/src/cdr_decode.erl1536
-rw-r--r--lib/orber/src/cdr_encode.erl1172
-rw-r--r--lib/orber/src/cdrlib.erl415
-rw-r--r--lib/orber/src/corba.erl2206
-rw-r--r--lib/orber/src/corba_boa.erl135
-rw-r--r--lib/orber/src/corba_nvlist.erl98
-rw-r--r--lib/orber/src/corba_object.erl221
-rw-r--r--lib/orber/src/fixed.erl306
-rw-r--r--lib/orber/src/ifr_objects.hrl422
-rw-r--r--lib/orber/src/iop_ior.erl1717
-rw-r--r--lib/orber/src/orber.app.src111
-rw-r--r--lib/orber/src/orber.appup.src7
-rw-r--r--lib/orber/src/orber.erl1238
-rw-r--r--lib/orber/src/orber_acl.erl397
-rw-r--r--lib/orber/src/orber_diagnostics.erl241
-rw-r--r--lib/orber/src/orber_env.erl1545
-rw-r--r--lib/orber/src/orber_exceptions.erl718
-rw-r--r--lib/orber/src/orber_ifr.erl1820
-rw-r--r--lib/orber/src/orber_ifr.hrl35
-rw-r--r--lib/orber/src/orber_ifr_aliasdef.erl135
-rw-r--r--lib/orber/src/orber_ifr_arraydef.erl104
-rw-r--r--lib/orber/src/orber_ifr_attributedef.erl138
-rw-r--r--lib/orber/src/orber_ifr_constantdef.erl148
-rw-r--r--lib/orber/src/orber_ifr_contained.erl248
-rw-r--r--lib/orber/src/orber_ifr_container.erl464
-rw-r--r--lib/orber/src/orber_ifr_enumdef.erl130
-rw-r--r--lib/orber/src/orber_ifr_exceptiondef.erl145
-rw-r--r--lib/orber/src/orber_ifr_fixeddef.erl80
-rw-r--r--lib/orber/src/orber_ifr_idltype.erl75
-rw-r--r--lib/orber/src/orber_ifr_interfacedef.erl340
-rw-r--r--lib/orber/src/orber_ifr_irobject.erl73
-rw-r--r--lib/orber/src/orber_ifr_moduledef.erl184
-rw-r--r--lib/orber/src/orber_ifr_operationdef.erl192
-rw-r--r--lib/orber/src/orber_ifr_orb.erl100
-rw-r--r--lib/orber/src/orber_ifr_primitivedef.erl70
-rw-r--r--lib/orber/src/orber_ifr_repository.erl288
-rw-r--r--lib/orber/src/orber_ifr_sequencedef.erl104
-rw-r--r--lib/orber/src/orber_ifr_stringdef.erl75
-rw-r--r--lib/orber/src/orber_ifr_structdef.erl156
-rw-r--r--lib/orber/src/orber_ifr_typecode.erl108
-rw-r--r--lib/orber/src/orber_ifr_typedef.erl125
-rw-r--r--lib/orber/src/orber_ifr_uniondef.erl176
-rw-r--r--lib/orber/src/orber_ifr_utils.erl437
-rw-r--r--lib/orber/src/orber_ifr_wstringdef.erl73
-rw-r--r--lib/orber/src/orber_iiop.erl551
-rw-r--r--lib/orber/src/orber_iiop.hrl1016
-rw-r--r--lib/orber/src/orber_iiop_inproxy.erl399
-rw-r--r--lib/orber/src/orber_iiop_inrequest.erl541
-rw-r--r--lib/orber/src/orber_iiop_insup.erl86
-rw-r--r--lib/orber/src/orber_iiop_net.erl511
-rw-r--r--lib/orber/src/orber_iiop_net_accept.erl95
-rw-r--r--lib/orber/src/orber_iiop_outproxy.erl511
-rw-r--r--lib/orber/src/orber_iiop_outsup.erl88
-rw-r--r--lib/orber/src/orber_iiop_pm.erl894
-rw-r--r--lib/orber/src/orber_iiop_socketsup.erl86
-rw-r--r--lib/orber/src/orber_iiop_tracer.erl232
-rw-r--r--lib/orber/src/orber_iiop_tracer_silent.erl191
-rw-r--r--lib/orber/src/orber_iiop_tracer_stealth.erl187
-rw-r--r--lib/orber/src/orber_initial_references.erl328
-rw-r--r--lib/orber/src/orber_interceptors.erl154
-rw-r--r--lib/orber/src/orber_objectkeys.erl571
-rw-r--r--lib/orber/src/orber_pi.erl1213
-rw-r--r--lib/orber/src/orber_request_number.erl83
-rw-r--r--lib/orber/src/orber_socket.erl530
-rw-r--r--lib/orber/src/orber_tb.erl222
-rw-r--r--lib/orber/src/orber_tc.erl284
-rw-r--r--lib/orber/src/orber_typedefs.erl83
-rw-r--r--lib/orber/src/orber_web.erl864
-rw-r--r--lib/orber/src/orber_web_server.erl190
-rw-r--r--lib/orber/test/Makefile220
-rw-r--r--lib/orber/test/cdrcoding_10_SUITE.erl587
-rw-r--r--lib/orber/test/cdrcoding_11_SUITE.erl587
-rw-r--r--lib/orber/test/cdrcoding_12_SUITE.erl575
-rw-r--r--lib/orber/test/cdrlib_SUITE.erl479
-rw-r--r--lib/orber/test/corba_SUITE.erl897
-rw-r--r--lib/orber/test/csiv2_SUITE.erl889
-rw-r--r--lib/orber/test/data_types_SUITE.erl187
-rw-r--r--lib/orber/test/generated_SUITE.erl372
-rw-r--r--lib/orber/test/idl_output/.gitignore0
-rw-r--r--lib/orber/test/iiop_module_do_test_impl.erl113
-rw-r--r--lib/orber/test/iiop_module_test_impl.erl129
-rw-r--r--lib/orber/test/iiop_test.idl112
-rw-r--r--lib/orber/test/iiop_test_impl.erl35
-rw-r--r--lib/orber/test/interceptors_SUITE.erl349
-rw-r--r--lib/orber/test/iop_ior_10_SUITE.erl184
-rw-r--r--lib/orber/test/iop_ior_11_SUITE.erl203
-rw-r--r--lib/orber/test/iop_ior_12_SUITE.erl204
-rw-r--r--lib/orber/test/ip_v4v6_interop_SUITE.erl199
-rw-r--r--lib/orber/test/lname_SUITE.erl213
-rw-r--r--lib/orber/test/multi_ORB_SUITE.erl2286
-rw-r--r--lib/orber/test/naming_context_SUITE.erl390
-rw-r--r--lib/orber/test/orber.cover2
-rw-r--r--lib/orber/test/orber.spec1
-rw-r--r--lib/orber/test/orber_SUITE.erl213
-rw-r--r--lib/orber/test/orber_acl_SUITE.erl299
-rw-r--r--lib/orber/test/orber_firewall_ipv4_in_SUITE.erl284
-rw-r--r--lib/orber/test/orber_firewall_ipv4_out_SUITE.erl229
-rw-r--r--lib/orber/test/orber_firewall_ipv6_in_SUITE.erl315
-rw-r--r--lib/orber/test/orber_firewall_ipv6_out_SUITE.erl236
-rw-r--r--lib/orber/test/orber_nat_SUITE.erl364
-rw-r--r--lib/orber/test/orber_test.idl96
-rw-r--r--lib/orber/test/orber_test_lib.erl1564
-rw-r--r--lib/orber/test/orber_test_server.cfg28
-rw-r--r--lib/orber/test/orber_test_server.idl177
-rw-r--r--lib/orber/test/orber_test_server_impl.erl276
-rw-r--r--lib/orber/test/orber_test_timeout_server_impl.erl66
-rw-r--r--lib/orber/test/orber_web_SUITE.erl440
-rw-r--r--lib/orber/test/tc_SUITE.erl605
-rw-r--r--lib/orber/vsn.mk1
-rw-r--r--lib/os_mon/Makefile6
-rw-r--r--lib/os_mon/c_src/cpu_sup.c50
-rw-r--r--lib/os_mon/doc/src/Makefile2
-rw-r--r--lib/os_mon/doc/src/cpu_sup.xml14
-rw-r--r--lib/os_mon/doc/src/disksup.xml12
-rw-r--r--lib/os_mon/doc/src/memsup.xml24
-rw-r--r--lib/os_mon/doc/src/notes.xml80
-rw-r--r--lib/os_mon/doc/src/nteventlog.xml8
-rw-r--r--lib/os_mon/doc/src/os_mon_app.xml27
-rw-r--r--lib/os_mon/doc/src/os_mon_mib.xml71
-rw-r--r--lib/os_mon/doc/src/os_sup.xml10
-rw-r--r--lib/os_mon/doc/src/ref_man.xml1
-rw-r--r--lib/os_mon/mibs/Makefile101
-rw-r--r--lib/os_mon/mibs/OTP-OS-MON-MIB.funcs5
-rw-r--r--lib/os_mon/mibs/OTP-OS-MON-MIB.mib423
-rw-r--r--lib/os_mon/mibs/v1/.gitignore0
-rw-r--r--lib/os_mon/src/Makefile3
-rw-r--r--lib/os_mon/src/cpu_sup.erl34
-rw-r--r--lib/os_mon/src/disksup.erl100
-rw-r--r--lib/os_mon/src/memsup.erl5
-rw-r--r--lib/os_mon/src/os_mon.app.src6
-rw-r--r--lib/os_mon/src/os_mon_mib.erl251
-rw-r--r--lib/os_mon/test/Makefile2
-rw-r--r--lib/os_mon/test/cpu_sup_SUITE.erl11
-rw-r--r--lib/os_mon/test/disksup_SUITE.erl40
-rw-r--r--lib/os_mon/test/os_mon.spec1
-rw-r--r--lib/os_mon/test/os_mon_mib_SUITE.cfg8
-rw-r--r--lib/os_mon/test/os_mon_mib_SUITE.erl578
-rw-r--r--lib/os_mon/vsn.mk2
-rw-r--r--lib/otp_mibs/AUTHORS8
-rw-r--r--lib/otp_mibs/Makefile37
-rw-r--r--lib/otp_mibs/doc/html/.gitignore0
-rw-r--r--lib/otp_mibs/doc/man3/.gitignore0
-rw-r--r--lib/otp_mibs/doc/pdf/.gitignore0
-rw-r--r--lib/otp_mibs/doc/src/Makefile115
-rw-r--r--lib/otp_mibs/doc/src/book.xml49
-rw-r--r--lib/otp_mibs/doc/src/introduction.xml47
-rw-r--r--lib/otp_mibs/doc/src/mibs.xml71
-rw-r--r--lib/otp_mibs/doc/src/notes.xml296
-rw-r--r--lib/otp_mibs/doc/src/otp_mib.xml70
-rw-r--r--lib/otp_mibs/doc/src/part.xml39
-rw-r--r--lib/otp_mibs/doc/src/ref_man.xml38
-rw-r--r--lib/otp_mibs/ebin/.gitignore0
-rw-r--r--lib/otp_mibs/include/.gitignore0
-rw-r--r--lib/otp_mibs/info2
-rw-r--r--lib/otp_mibs/mibs/Makefile89
-rw-r--r--lib/otp_mibs/mibs/OTP-EVA-MIB.mib569
-rw-r--r--lib/otp_mibs/mibs/OTP-MIB.funcs2
-rw-r--r--lib/otp_mibs/mibs/OTP-MIB.mib318
-rw-r--r--lib/otp_mibs/mibs/v1/.gitignore0
-rw-r--r--lib/otp_mibs/priv/bin/.gitignore0
-rw-r--r--lib/otp_mibs/priv/mibs/.gitignore0
-rw-r--r--lib/otp_mibs/priv/obj/.gitignore0
-rw-r--r--lib/otp_mibs/src/Makefile106
-rw-r--r--lib/otp_mibs/src/otp_mib.erl216
-rw-r--r--lib/otp_mibs/src/otp_mibs.app.src30
-rw-r--r--lib/otp_mibs/src/otp_mibs.appup.src22
-rw-r--r--lib/otp_mibs/test/Makefile85
-rw-r--r--lib/otp_mibs/test/otp_mibs_SUITE.cfg15
-rw-r--r--lib/otp_mibs/test/otp_mibs_SUITE.erl255
-rw-r--r--lib/otp_mibs/vsn.mk5
-rw-r--r--lib/parsetools/doc/src/Makefile3
-rw-r--r--lib/parsetools/doc/src/leex.xml19
-rw-r--r--lib/parsetools/doc/src/notes.xml32
-rw-r--r--lib/parsetools/doc/src/yecc.xml6
-rw-r--r--lib/parsetools/include/yeccpre.hrl5
-rw-r--r--lib/parsetools/src/leex.erl34
-rw-r--r--lib/parsetools/src/yecc.erl22
-rw-r--r--lib/parsetools/src/yeccparser.erl16
-rw-r--r--lib/parsetools/test/leex_SUITE.erl7
-rw-r--r--lib/parsetools/test/yecc_SUITE.erl5
-rw-r--r--lib/parsetools/vsn.mk2
-rw-r--r--lib/public_key/asn1/OTP-PKIX.asn132
-rw-r--r--lib/public_key/asn1/PKCS-7.asn110
-rw-r--r--lib/public_key/doc/specs/.gitignore1
-rw-r--r--lib/public_key/doc/src/Makefile10
-rw-r--r--lib/public_key/doc/src/notes.xml235
-rw-r--r--lib/public_key/doc/src/public_key.xml807
-rw-r--r--lib/public_key/doc/src/public_key_records.xml2
-rw-r--r--lib/public_key/doc/src/specs.xml4
-rw-r--r--lib/public_key/doc/src/using_public_key.xml6
-rw-r--r--lib/public_key/include/public_key.hrl2
-rw-r--r--lib/public_key/priv/moduli429
-rw-r--r--lib/public_key/src/pubkey_cert.erl101
-rw-r--r--lib/public_key/src/pubkey_crl.erl2
-rw-r--r--lib/public_key/src/pubkey_moduli.hrl502
-rw-r--r--lib/public_key/src/pubkey_pbe.erl32
-rw-r--r--lib/public_key/src/pubkey_pem.erl19
-rw-r--r--lib/public_key/src/pubkey_ssh.erl119
-rw-r--r--lib/public_key/src/public_key.app.src2
-rw-r--r--lib/public_key/src/public_key.erl558
-rw-r--r--lib/public_key/test/pbe_SUITE.erl50
-rw-r--r--lib/public_key/test/pbe_SUITE_data/old_aes_128_cbc.pem (renamed from lib/public_key/test/pbe_SUITE_data/old_aes_128_cbc_enc_key.pem)0
-rw-r--r--lib/public_key/test/pbe_SUITE_data/old_aes_256_cbc.pem30
-rw-r--r--lib/public_key/test/public_key_SUITE.erl93
-rw-r--r--lib/public_key/test/public_key_SUITE_data/dsa_key_pkcs8.pem9
-rw-r--r--lib/public_key/test/public_key_SUITE_data/ec_key_pkcs8.pem5
-rw-r--r--lib/public_key/test/public_key_SUITE_data/pkix_verify_hostname_subjAltName.pem24
-rw-r--r--lib/public_key/test/public_key_SUITE_data/rsa_key_pkcs8.pem10
-rw-r--r--lib/public_key/test/public_key_SUITE_data/verify_hostname.conf3
-rw-r--r--lib/public_key/vsn.mk2
-rw-r--r--lib/reltool/doc/src/Makefile3
-rw-r--r--lib/reltool/doc/src/notes.xml85
-rw-r--r--lib/reltool/doc/src/reltool.xml38
-rw-r--r--lib/reltool/doc/src/reltool_examples.xml71
-rw-r--r--lib/reltool/src/reltool.app.src2
-rw-r--r--lib/reltool/src/reltool.erl2
-rw-r--r--lib/reltool/src/reltool.hrl7
-rw-r--r--lib/reltool/src/reltool_app_win.erl6
-rw-r--r--lib/reltool/src/reltool_fgraph_win.erl2
-rw-r--r--lib/reltool/src/reltool_mod_win.erl8
-rw-r--r--lib/reltool/src/reltool_server.erl20
-rw-r--r--lib/reltool/src/reltool_sys_win.erl8
-rw-r--r--lib/reltool/src/reltool_target.erl39
-rw-r--r--lib/reltool/src/reltool_utils.erl22
-rw-r--r--lib/reltool/test/reltool_app_SUITE.erl2
-rw-r--r--lib/reltool/test/reltool_manual_gui_SUITE.erl2
-rw-r--r--lib/reltool/test/reltool_server_SUITE.erl212
-rw-r--r--lib/reltool/test/reltool_test_lib.erl5
-rw-r--r--lib/reltool/test/reltool_wx_SUITE.erl9
-rw-r--r--lib/reltool/test/rtt.erl2
-rw-r--r--lib/reltool/vsn.mk2
-rw-r--r--lib/runtime_tools/c_src/Makefile.in8
-rw-r--r--lib/runtime_tools/doc/src/LTTng.xml38
-rw-r--r--lib/runtime_tools/doc/src/Makefile18
-rw-r--r--lib/runtime_tools/doc/src/dbg.xml122
-rw-r--r--lib/runtime_tools/doc/src/dyntrace.xml32
-rw-r--r--lib/runtime_tools/doc/src/erts_alloc_config.xml10
-rw-r--r--lib/runtime_tools/doc/src/msacc.xml32
-rw-r--r--lib/runtime_tools/doc/src/notes.xml66
-rw-r--r--lib/runtime_tools/doc/src/ref_man.xml3
-rw-r--r--lib/runtime_tools/doc/src/scheduler.xml135
-rw-r--r--lib/runtime_tools/doc/src/specs.xml1
-rw-r--r--lib/runtime_tools/doc/src/system_information.xml6
-rw-r--r--lib/runtime_tools/examples/dist.systemtap26
-rw-r--r--lib/runtime_tools/examples/driver1.systemtap44
-rw-r--r--lib/runtime_tools/examples/efile_drv.d105
-rw-r--r--lib/runtime_tools/examples/efile_drv.systemtap113
-rw-r--r--lib/runtime_tools/examples/function-calls.systemtap22
-rw-r--r--lib/runtime_tools/examples/garbage-collection.systemtap16
-rw-r--r--lib/runtime_tools/examples/memory1.systemtap16
-rw-r--r--lib/runtime_tools/examples/messages.systemtap16
-rw-r--r--lib/runtime_tools/examples/port1.systemtap28
-rw-r--r--lib/runtime_tools/examples/process-scheduling.systemtap14
-rw-r--r--lib/runtime_tools/examples/spawn-exit.systemtap16
-rw-r--r--lib/runtime_tools/examples/user-probe-n.systemtap13
-rw-r--r--lib/runtime_tools/examples/user-probe.systemtap12
-rw-r--r--lib/runtime_tools/src/Makefile3
-rw-r--r--lib/runtime_tools/src/appmon_info.erl4
-rw-r--r--lib/runtime_tools/src/erts_alloc_config.erl30
-rw-r--r--lib/runtime_tools/src/msacc.erl5
-rw-r--r--lib/runtime_tools/src/observer_backend.erl12
-rw-r--r--lib/runtime_tools/src/runtime_tools.app.src3
-rw-r--r--lib/runtime_tools/src/scheduler.erl152
-rw-r--r--lib/runtime_tools/src/system_information.erl5
-rw-r--r--lib/runtime_tools/test/Makefile4
-rw-r--r--lib/runtime_tools/test/dbg_SUITE.erl102
-rw-r--r--lib/runtime_tools/test/dyntrace_SUITE.erl8
-rw-r--r--lib/runtime_tools/test/scheduler_SUITE.erl104
-rw-r--r--lib/runtime_tools/test/system_information_SUITE_data/information_test_report.dat2
-rw-r--r--lib/runtime_tools/test/zzz_SUITE.erl37
-rw-r--r--lib/runtime_tools/vsn.mk2
-rw-r--r--lib/sasl/doc/src/Makefile1
-rw-r--r--lib/sasl/doc/src/alarm_handler.xml8
-rw-r--r--lib/sasl/doc/src/appup.xml16
-rw-r--r--lib/sasl/doc/src/error_logging.xml55
-rw-r--r--lib/sasl/doc/src/notes.xml153
-rw-r--r--lib/sasl/doc/src/rb.xml38
-rw-r--r--lib/sasl/doc/src/release_handler.xml46
-rw-r--r--lib/sasl/doc/src/sasl_app.xml184
-rw-r--r--lib/sasl/doc/src/systools.xml22
-rw-r--r--lib/sasl/src/Makefile8
-rw-r--r--lib/sasl/src/erlsrv.erl25
-rw-r--r--lib/sasl/src/format_lib_supp.erl6
-rw-r--r--lib/sasl/src/rb.erl8
-rw-r--r--lib/sasl/src/rb_format_supp.erl2
-rw-r--r--lib/sasl/src/release_handler.erl38
-rw-r--r--lib/sasl/src/release_handler_1.erl2
-rw-r--r--lib/sasl/src/sasl.app.src9
-rw-r--r--lib/sasl/src/sasl.appup.src31
-rw-r--r--lib/sasl/src/sasl.erl100
-rw-r--r--lib/sasl/src/sasl_report_file_h.erl2
-rw-r--r--lib/sasl/src/si.erl169
-rw-r--r--lib/sasl/src/si_sasl_supp.erl380
-rw-r--r--lib/sasl/src/systools.erl6
-rw-r--r--lib/sasl/src/systools_make.erl239
-rw-r--r--lib/sasl/src/systools_relup.erl2
-rw-r--r--lib/sasl/test/installer.erl2
-rw-r--r--lib/sasl/test/rb_SUITE.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE.erl92
-rw-r--r--lib/sasl/test/sasl_SUITE.erl16
-rw-r--r--lib/sasl/test/sasl_report_SUITE.erl98
-rw-r--r--lib/sasl/test/systools_SUITE.erl71
-rw-r--r--lib/sasl/test/test_lib.hrl4
-rw-r--r--lib/sasl/vsn.mk2
-rw-r--r--lib/snmp/doc/src/Makefile3
-rw-r--r--lib/snmp/doc/src/notes.xml101
-rw-r--r--lib/snmp/doc/src/snmp.xml99
-rw-r--r--lib/snmp/doc/src/snmp_community_mib.xml12
-rw-r--r--lib/snmp/doc/src/snmp_framework_mib.xml10
-rw-r--r--lib/snmp/doc/src/snmp_generic.xml30
-rw-r--r--lib/snmp/doc/src/snmp_impl_example_agent.xml2
-rw-r--r--lib/snmp/doc/src/snmp_index.xml18
-rw-r--r--lib/snmp/doc/src/snmp_notification_mib.xml10
-rw-r--r--lib/snmp/doc/src/snmp_pdus.xml26
-rw-r--r--lib/snmp/doc/src/snmp_standard_mib.xml14
-rw-r--r--lib/snmp/doc/src/snmp_target_mib.xml16
-rw-r--r--lib/snmp/doc/src/snmp_user_based_sm_mib.xml10
-rw-r--r--lib/snmp/doc/src/snmp_view_based_acm_mib.xml18
-rw-r--r--lib/snmp/doc/src/snmpa.xml260
-rw-r--r--lib/snmp/doc/src/snmpa_conf.xml112
-rw-r--r--lib/snmp/doc/src/snmpa_discovery_handler.xml4
-rw-r--r--lib/snmp/doc/src/snmpa_error.xml6
-rw-r--r--lib/snmp/doc/src/snmpa_error_io.xml6
-rw-r--r--lib/snmp/doc/src/snmpa_error_logger.xml6
-rw-r--r--lib/snmp/doc/src/snmpa_error_report.xml6
-rw-r--r--lib/snmp/doc/src/snmpa_local_db.xml24
-rw-r--r--lib/snmp/doc/src/snmpa_mib_data.xml34
-rw-r--r--lib/snmp/doc/src/snmpa_mib_storage.xml26
-rw-r--r--lib/snmp/doc/src/snmpa_mpd.xml20
-rw-r--r--lib/snmp/doc/src/snmpa_network_interface.xml12
-rw-r--r--lib/snmp/doc/src/snmpa_network_interface_filter.xml10
-rw-r--r--lib/snmp/doc/src/snmpa_notification_delivery_info_receiver.xml6
-rw-r--r--lib/snmp/doc/src/snmpa_notification_filter.xml4
-rw-r--r--lib/snmp/doc/src/snmpa_supervisor.xml10
-rw-r--r--lib/snmp/doc/src/snmpc.xml10
-rw-r--r--lib/snmp/doc/src/snmpm.xml232
-rw-r--r--lib/snmp/doc/src/snmpm_conf.xml48
-rw-r--r--lib/snmp/doc/src/snmpm_mpd.xml10
-rw-r--r--lib/snmp/doc/src/snmpm_network_interface.xml20
-rw-r--r--lib/snmp/doc/src/snmpm_network_interface_filter.xml10
-rw-r--r--lib/snmp/doc/src/snmpm_user.xml16
-rw-r--r--lib/snmp/include/snmp_types.hrl5
-rw-r--r--lib/snmp/mibs/Makefile.in36
-rw-r--r--lib/snmp/mibs/OTP-REG.mib (renamed from lib/otp_mibs/mibs/OTP-REG.mib)0
-rw-r--r--lib/snmp/mibs/OTP-TC.mib (renamed from lib/otp_mibs/mibs/OTP-TC.mib)0
-rw-r--r--lib/snmp/src/agent/depend.mk19
-rw-r--r--lib/snmp/src/agent/modules.mk26
-rw-r--r--lib/snmp/src/agent/snmp_view_based_acm_mib.erl16
-rw-r--r--lib/snmp/src/agent/snmpa_agent.erl1253
-rw-r--r--lib/snmp/src/agent/snmpa_app.erl4
-rw-r--r--lib/snmp/src/agent/snmpa_get.erl1150
-rw-r--r--lib/snmp/src/agent/snmpa_get_lib.erl254
-rw-r--r--lib/snmp/src/agent/snmpa_get_mechanism.erl79
-rw-r--r--lib/snmp/src/agent/snmpa_local_db.erl9
-rw-r--r--lib/snmp/src/agent/snmpa_net_if.erl111
-rw-r--r--lib/snmp/src/agent/snmpa_set_lib.erl8
-rw-r--r--lib/snmp/src/agent/snmpa_supervisor.erl64
-rw-r--r--lib/snmp/src/agent/snmpa_trap.erl6
-rw-r--r--lib/snmp/src/app/snmp.app.src3
-rw-r--r--lib/snmp/src/app/snmp.config1
-rw-r--r--lib/snmp/src/app/snmp.erl24
-rw-r--r--lib/snmp/src/compile/snmpc.erl72
-rw-r--r--lib/snmp/src/misc/snmp_log.erl334
-rw-r--r--lib/snmp/src/misc/snmp_misc.erl112
-rw-r--r--lib/snmp/src/misc/snmp_verbosity.erl16
-rw-r--r--lib/snmp/test/modules.mk1
-rw-r--r--lib/snmp/test/snmp_agent_test.erl42
-rw-r--r--lib/snmp/test/snmp_agent_test_get.erl58
-rw-r--r--lib/snmp/test/snmp_agent_test_lib.erl349
-rw-r--r--lib/snmp/test/snmp_compiler_test.erl56
-rw-r--r--lib/snmp/test/snmp_manager_test.erl192
-rw-r--r--lib/snmp/test/snmp_test_data/OTP14196-MIB.mib47
-rw-r--r--lib/snmp/test/snmp_test_lib.erl98
-rw-r--r--lib/snmp/test/snmp_test_lib.hrl25
-rw-r--r--lib/snmp/test/snmp_test_mgr.erl74
-rw-r--r--lib/snmp/test/snmp_test_mgr_misc.erl291
-rw-r--r--lib/snmp/test/snmp_to_snmpnet_SUITE.erl2
-rw-r--r--lib/snmp/test/test-mibs/ALARM-MIB.mib2
-rw-r--r--lib/snmp/test/test-mibs/SNMPv2-TC.mib4
-rw-r--r--lib/snmp/vsn.mk4
-rw-r--r--lib/ssh/doc/specs/.gitignore1
-rw-r--r--lib/ssh/doc/src/Makefile29
-rw-r--r--lib/ssh/doc/src/configure_algos.xml7
-rw-r--r--lib/ssh/doc/src/introduction.xml4
-rw-r--r--lib/ssh/doc/src/notes.xml557
-rw-r--r--lib/ssh/doc/src/ref_man.xml6
-rw-r--r--lib/ssh/doc/src/specs.xml14
-rw-r--r--lib/ssh/doc/src/ssh.xml1727
-rw-r--r--lib/ssh/doc/src/ssh_app.xml85
-rw-r--r--lib/ssh/doc/src/ssh_channel.xml443
-rw-r--r--lib/ssh/doc/src/ssh_client_channel.xml440
-rw-r--r--lib/ssh/doc/src/ssh_client_key_api.xml57
-rw-r--r--lib/ssh/doc/src/ssh_connection.xml152
-rw-r--r--lib/ssh/doc/src/ssh_file.xml285
-rw-r--r--lib/ssh/doc/src/ssh_protocol.xml8
-rw-r--r--lib/ssh/doc/src/ssh_server_channel.xml176
-rw-r--r--lib/ssh/doc/src/ssh_server_key_api.xml49
-rw-r--r--lib/ssh/doc/src/ssh_sftp.xml123
-rw-r--r--lib/ssh/doc/src/ssh_sftpd.xml9
-rw-r--r--lib/ssh/doc/src/terminology.xml185
-rw-r--r--lib/ssh/doc/src/usersguide.xml3
-rw-r--r--lib/ssh/doc/src/using_ssh.xml18
-rw-r--r--lib/ssh/src/Makefile48
-rw-r--r--lib/ssh/src/ssh.app.src14
-rw-r--r--lib/ssh/src/ssh.erl259
-rw-r--r--lib/ssh/src/ssh.hrl331
-rw-r--r--lib/ssh/src/ssh_acceptor.erl50
-rw-r--r--lib/ssh/src/ssh_acceptor_sup.erl4
-rw-r--r--lib/ssh/src/ssh_auth.erl147
-rw-r--r--lib/ssh/src/ssh_channel.erl317
-rw-r--r--lib/ssh/src/ssh_channel_sup.erl64
-rw-r--r--lib/ssh/src/ssh_cli.erl311
-rw-r--r--lib/ssh/src/ssh_client_channel.erl458
-rw-r--r--lib/ssh/src/ssh_client_key.erl35
-rw-r--r--lib/ssh/src/ssh_client_key_api.erl33
-rw-r--r--lib/ssh/src/ssh_connect.hrl6
-rw-r--r--lib/ssh/src/ssh_connection.erl788
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl1254
-rw-r--r--lib/ssh/src/ssh_connection_sup.erl2
-rw-r--r--lib/ssh/src/ssh_daemon_channel.erl38
-rw-r--r--lib/ssh/src/ssh_dbg.erl803
-rw-r--r--lib/ssh/src/ssh_dbg.hrl27
-rw-r--r--lib/ssh/src/ssh_file.erl52
-rw-r--r--lib/ssh/src/ssh_info.erl10
-rw-r--r--lib/ssh/src/ssh_message.erl103
-rw-r--r--lib/ssh/src/ssh_no_io.erl29
-rw-r--r--lib/ssh/src/ssh_options.erl82
-rw-r--r--lib/ssh/src/ssh_server_channel.erl55
-rw-r--r--lib/ssh/src/ssh_server_channel_sup.erl62
-rw-r--r--lib/ssh/src/ssh_server_key.erl34
-rw-r--r--lib/ssh/src/ssh_server_key_api.erl14
-rw-r--r--lib/ssh/src/ssh_sftp.erl78
-rw-r--r--lib/ssh/src/ssh_sftpd.erl58
-rw-r--r--lib/ssh/src/ssh_shell.erl43
-rw-r--r--lib/ssh/src/ssh_subsystem_sup.erl14
-rw-r--r--lib/ssh/src/ssh_sup.erl2
-rw-r--r--lib/ssh/src/ssh_system_sup.erl6
-rw-r--r--lib/ssh/src/ssh_transport.erl980
-rw-r--r--lib/ssh/src/ssh_transport.hrl5
-rw-r--r--lib/ssh/src/ssh_xfer.erl4
-rw-r--r--lib/ssh/src/sshc_sup.erl11
-rw-r--r--lib/ssh/src/sshd_sup.erl2
-rw-r--r--lib/ssh/test/.gitignore5
-rw-r--r--lib/ssh/test/Makefile9
-rw-r--r--lib/ssh/test/property_test/ssh_eqc_client_info_timing.erl22
-rw-r--r--lib/ssh/test/property_test/ssh_eqc_client_server.erl230
-rw-r--r--lib/ssh/test/property_test/ssh_eqc_subsys.erl4
-rw-r--r--lib/ssh/test/ssh_algorithms_SUITE.erl29
-rw-r--r--lib/ssh/test/ssh_algorithms_SUITE_data/id_ed255197
-rw-r--r--lib/ssh/test/ssh_algorithms_SUITE_data/id_ed25519.pub1
-rw-r--r--lib/ssh/test/ssh_algorithms_SUITE_data/id_ed44810
-rw-r--r--lib/ssh/test/ssh_algorithms_SUITE_data/id_ed448.pub1
-rw-r--r--lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ed25519_key7
-rw-r--r--lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ed25519_key.pub1
-rw-r--r--lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ed448_key10
-rw-r--r--lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ed448_key.pub1
-rw-r--r--lib/ssh/test/ssh_basic_SUITE.erl557
-rw-r--r--lib/ssh/test/ssh_basic_SUITE_data/id_ed255197
-rw-r--r--lib/ssh/test/ssh_basic_SUITE_data/id_ed25519.pub1
-rw-r--r--lib/ssh/test/ssh_basic_SUITE_data/id_ed44810
-rw-r--r--lib/ssh/test/ssh_basic_SUITE_data/id_ed448.pub1
-rw-r--r--lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ed25519_key7
-rw-r--r--lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ed25519_key.pub1
-rw-r--r--lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ed448_key10
-rw-r--r--lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ed448_key.pub1
-rw-r--r--lib/ssh/test/ssh_bench_SUITE.erl83
-rw-r--r--lib/ssh/test/ssh_bench_dev_null.erl4
-rw-r--r--lib/ssh/test/ssh_chan_behaviours_SUITE.erl152
-rw-r--r--lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_dsa_key (renamed from lib/ssh/test/ssh_renegotiate_SUITE_data/ssh_host_dsa_key)0
-rw-r--r--lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_dsa_key.pub (renamed from lib/ssh/test/ssh_renegotiate_SUITE_data/ssh_host_dsa_key.pub)0
-rw-r--r--lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_ecdsa_key6
-rw-r--r--lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_ecdsa_key.pub1
-rw-r--r--lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_rsa_key (renamed from lib/ssh/test/ssh_renegotiate_SUITE_data/ssh_host_rsa_key)0
-rw-r--r--lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_rsa_key.pub (renamed from lib/ssh/test/ssh_renegotiate_SUITE_data/ssh_host_rsa_key.pub)0
-rw-r--r--lib/ssh/test/ssh_chan_behaviours_client.erl143
-rw-r--r--lib/ssh/test/ssh_chan_behaviours_server.erl96
-rw-r--r--lib/ssh/test/ssh_compat_SUITE.erl59
-rwxr-xr-xlib/ssh/test/ssh_compat_SUITE_data/build_scripts/create_all6
-rw-r--r--lib/ssh/test/ssh_compat_SUITE_data/host_keys/ssh_host_ed25519_key7
-rw-r--r--lib/ssh/test/ssh_compat_SUITE_data/host_keys/ssh_host_ed25519_key.pub1
-rw-r--r--lib/ssh/test/ssh_compat_SUITE_data/host_keys/ssh_host_ed448_key10
-rw-r--r--lib/ssh/test/ssh_compat_SUITE_data/host_keys/ssh_host_ed448_key.pub1
-rw-r--r--lib/ssh/test/ssh_compat_SUITE_data/users_keys/id_ed255197
-rw-r--r--lib/ssh/test/ssh_compat_SUITE_data/users_keys/id_ed25519.pub1
-rw-r--r--lib/ssh/test/ssh_compat_SUITE_data/users_keys/id_ed44810
-rw-r--r--lib/ssh/test/ssh_compat_SUITE_data/users_keys/id_ed448.pub1
-rw-r--r--lib/ssh/test/ssh_connection_SUITE.erl106
-rw-r--r--lib/ssh/test/ssh_dbg_SUITE.erl465
-rw-r--r--lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_dsa_key13
-rw-r--r--lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_dsa_key.pub11
-rw-r--r--lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_ecdsa_key2565
-rw-r--r--lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_ecdsa_key256.pub1
-rw-r--r--lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_ecdsa_key3846
-rw-r--r--lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_ecdsa_key384.pub1
-rw-r--r--lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_ecdsa_key5217
-rw-r--r--lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_ecdsa_key521.pub1
-rw-r--r--lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_rsa_key16
-rw-r--r--lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_rsa_key.pub5
-rw-r--r--lib/ssh/test/ssh_echo_server.erl4
-rw-r--r--lib/ssh/test/ssh_engine_SUITE.erl13
-rw-r--r--lib/ssh/test/ssh_options_SUITE.erl53
-rw-r--r--lib/ssh/test/ssh_peername_sockname_server.erl4
-rw-r--r--lib/ssh/test/ssh_property_test_SUITE.erl7
-rw-r--r--lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_dsa_key13
-rw-r--r--lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_dsa_key.pub11
-rw-r--r--lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_ecdsa_key5
-rw-r--r--lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_ecdsa_key.pub1
-rw-r--r--lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_rsa_key16
-rw-r--r--lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_rsa_key.pub5
-rw-r--r--lib/ssh/test/ssh_protocol_SUITE.erl6
-rw-r--r--lib/ssh/test/ssh_renegotiate_SUITE.erl237
-rw-r--r--lib/ssh/test/ssh_renegotiate_SUITE_data/id_dsa13
-rw-r--r--lib/ssh/test/ssh_renegotiate_SUITE_data/id_rsa15
-rw-r--r--lib/ssh/test/ssh_sup_SUITE.erl45
-rw-r--r--lib/ssh/test/ssh_test_lib.erl31
-rw-r--r--lib/ssh/test/ssh_to_openssh_SUITE.erl2
-rw-r--r--lib/ssh/test/ssh_trpt_test_lib.erl146
-rw-r--r--lib/ssh/vsn.mk2
-rw-r--r--lib/ssl/doc/specs/.gitignore1
-rw-r--r--lib/ssl/doc/src/Makefile12
-rw-r--r--lib/ssl/doc/src/notes.xml803
-rw-r--r--lib/ssl/doc/src/specs.xml9
-rw-r--r--lib/ssl/doc/src/ssl.xml2000
-rw-r--r--lib/ssl/doc/src/ssl_app.xml76
-rw-r--r--lib/ssl/doc/src/ssl_crl_cache.xml37
-rw-r--r--lib/ssl/doc/src/ssl_crl_cache_api.xml71
-rw-r--r--lib/ssl/doc/src/ssl_distribution.xml52
-rw-r--r--lib/ssl/doc/src/ssl_introduction.xml7
-rw-r--r--lib/ssl/doc/src/ssl_protocol.xml26
-rw-r--r--lib/ssl/doc/src/ssl_session_cache_api.xml109
-rw-r--r--lib/ssl/doc/src/standards_compliance.xml2338
-rw-r--r--lib/ssl/doc/src/usersguide.xml1
-rw-r--r--lib/ssl/doc/src/using_ssl.xml42
-rw-r--r--lib/ssl/examples/src/client_server.erl14
-rw-r--r--lib/ssl/src/Makefile144
-rw-r--r--lib/ssl/src/dtls.erl113
-rw-r--r--lib/ssl/src/dtls_connection.erl747
-rw-r--r--lib/ssl/src/dtls_handshake.erl230
-rw-r--r--lib/ssl/src/dtls_handshake.hrl20
-rw-r--r--lib/ssl/src/dtls_listener_sup.erl62
-rw-r--r--lib/ssl/src/dtls_packet_demux.erl328
-rw-r--r--lib/ssl/src/dtls_record.erl108
-rw-r--r--lib/ssl/src/dtls_socket.erl95
-rw-r--r--lib/ssl/src/dtls_udp_listener.erl307
-rw-r--r--lib/ssl/src/dtls_udp_sup.erl62
-rw-r--r--lib/ssl/src/dtls_v1.erl10
-rw-r--r--lib/ssl/src/inet6_tls_dist.erl7
-rw-r--r--lib/ssl/src/inet_tls_dist.erl942
-rw-r--r--lib/ssl/src/ssl.app.src22
-rw-r--r--lib/ssl/src/ssl.appup.src4
-rw-r--r--lib/ssl/src/ssl.erl1335
-rw-r--r--lib/ssl/src/ssl_alert.erl91
-rw-r--r--lib/ssl/src/ssl_alert.hrl7
-rw-r--r--lib/ssl/src/ssl_api.hrl43
-rw-r--r--lib/ssl/src/ssl_app.erl17
-rw-r--r--lib/ssl/src/ssl_certificate.erl119
-rw-r--r--lib/ssl/src/ssl_cipher.erl2493
-rw-r--r--lib/ssl/src/ssl_cipher.hrl154
-rw-r--r--lib/ssl/src/ssl_cipher_format.erl1919
-rw-r--r--lib/ssl/src/ssl_config.erl16
-rw-r--r--lib/ssl/src/ssl_connection.erl2265
-rw-r--r--lib/ssl/src/ssl_connection.hrl204
-rw-r--r--lib/ssl/src/ssl_connection_sup.erl12
-rw-r--r--lib/ssl/src/ssl_crl_cache.erl16
-rw-r--r--lib/ssl/src/ssl_crl_cache_api.erl15
-rw-r--r--lib/ssl/src/ssl_crl_hash_dir.erl5
-rw-r--r--lib/ssl/src/ssl_dh_groups.erl467
-rw-r--r--lib/ssl/src/ssl_dist_sup.erl12
-rw-r--r--lib/ssl/src/ssl_handshake.erl1453
-rw-r--r--lib/ssl/src/ssl_handshake.hrl101
-rw-r--r--lib/ssl/src/ssl_internal.hrl124
-rw-r--r--lib/ssl/src/ssl_logger.erl446
-rw-r--r--lib/ssl/src/ssl_manager.erl64
-rw-r--r--lib/ssl/src/ssl_pem_cache.erl37
-rw-r--r--lib/ssl/src/ssl_pkix_db.erl22
-rw-r--r--lib/ssl/src/ssl_record.erl149
-rw-r--r--lib/ssl/src/ssl_record.hrl12
-rw-r--r--lib/ssl/src/ssl_session.erl17
-rw-r--r--lib/ssl/src/ssl_session_cache_api.erl24
-rw-r--r--lib/ssl/src/ssl_tls_dist_proxy.erl493
-rw-r--r--lib/ssl/src/ssl_v2.erl38
-rw-r--r--lib/ssl/src/ssl_v3.erl4
-rw-r--r--lib/ssl/src/tls.erl112
-rw-r--r--lib/ssl/src/tls_connection.erl1093
-rw-r--r--lib/ssl/src/tls_connection.hrl1
-rw-r--r--lib/ssl/src/tls_connection_1_3.erl192
-rw-r--r--lib/ssl/src/tls_handshake.erl263
-rw-r--r--lib/ssl/src/tls_handshake.hrl1
-rw-r--r--lib/ssl/src/tls_handshake_1_3.erl1343
-rw-r--r--lib/ssl/src/tls_handshake_1_3.hrl238
-rw-r--r--lib/ssl/src/tls_record.erl492
-rw-r--r--lib/ssl/src/tls_record_1_3.erl311
-rw-r--r--lib/ssl/src/tls_record_1_3.hrl58
-rw-r--r--lib/ssl/src/tls_sender.erl524
-rw-r--r--lib/ssl/src/tls_socket.erl75
-rw-r--r--lib/ssl/src/tls_v1.erl467
-rw-r--r--lib/ssl/test/Makefile23
-rw-r--r--lib/ssl/test/inet_crypto_dist.erl1541
-rw-r--r--lib/ssl/test/make_certs.erl48
-rw-r--r--lib/ssl/test/openssl_server_cipher_suite_SUITE.erl774
-rw-r--r--lib/ssl/test/property_test/ssl_eqc_cipher_format.erl96
-rw-r--r--lib/ssl/test/property_test/ssl_eqc_handshake.erl812
-rw-r--r--lib/ssl/test/ssl.spec17
-rw-r--r--lib/ssl/test/ssl_ECC.erl172
-rw-r--r--lib/ssl/test/ssl_ECC_SUITE.erl636
-rw-r--r--lib/ssl/test/ssl_ECC_openssl_SUITE.erl132
-rw-r--r--lib/ssl/test/ssl_alpn_handshake_SUITE.erl92
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl2888
-rw-r--r--lib/ssl/test/ssl_bench.spec3
-rw-r--r--lib/ssl/test/ssl_bench_SUITE.erl130
-rw-r--r--lib/ssl/test/ssl_bench_test_lib.erl75
-rw-r--r--lib/ssl/test/ssl_certificate_verify_SUITE.erl328
-rw-r--r--lib/ssl/test/ssl_cipher_suite_SUITE.erl759
-rw-r--r--lib/ssl/test/ssl_crl_SUITE.erl32
-rw-r--r--lib/ssl/test/ssl_dist_SUITE.erl328
-rw-r--r--lib/ssl/test/ssl_dist_bench_SUITE.erl874
-rw-r--r--lib/ssl/test/ssl_dist_test_lib.erl346
-rw-r--r--lib/ssl/test/ssl_dist_test_lib.hrl26
-rw-r--r--lib/ssl/test/ssl_engine_SUITE.erl47
-rw-r--r--lib/ssl/test/ssl_eqc_SUITE.erl70
-rw-r--r--lib/ssl/test/ssl_handshake_SUITE.erl159
-rw-r--r--lib/ssl/test/ssl_npn_handshake_SUITE.erl64
-rw-r--r--lib/ssl/test/ssl_npn_hello_SUITE.erl42
-rw-r--r--lib/ssl/test/ssl_packet_SUITE.erl75
-rw-r--r--lib/ssl/test/ssl_payload_SUITE.erl634
-rw-r--r--lib/ssl/test/ssl_pem_cache_SUITE.erl58
-rw-r--r--lib/ssl/test/ssl_rfc_5869_SUITE.erl316
-rw-r--r--lib/ssl/test/ssl_session_cache_SUITE.erl128
-rw-r--r--lib/ssl/test/ssl_sni_SUITE.erl10
-rw-r--r--lib/ssl/test/ssl_test_lib.erl1137
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl1063
-rw-r--r--lib/ssl/test/ssl_upgrade_SUITE.erl13
-rw-r--r--lib/ssl/test/x509_test.erl2
-rw-r--r--lib/ssl/vsn.mk2
-rw-r--r--lib/stdlib/doc/src/Makefile7
-rw-r--r--lib/stdlib/doc/src/array.xml60
-rw-r--r--lib/stdlib/doc/src/assert_hrl.xml4
-rw-r--r--lib/stdlib/doc/src/base64.xml14
-rw-r--r--lib/stdlib/doc/src/beam_lib.xml77
-rw-r--r--lib/stdlib/doc/src/binary.xml56
-rw-r--r--lib/stdlib/doc/src/c.xml79
-rw-r--r--lib/stdlib/doc/src/calendar.xml151
-rw-r--r--lib/stdlib/doc/src/dets.xml94
-rw-r--r--lib/stdlib/doc/src/dict.xml44
-rw-r--r--lib/stdlib/doc/src/digraph.xml68
-rw-r--r--lib/stdlib/doc/src/digraph_utils.xml40
-rw-r--r--lib/stdlib/doc/src/epp.xml42
-rw-r--r--lib/stdlib/doc/src/erl_anno.xml36
-rw-r--r--lib/stdlib/doc/src/erl_eval.xml32
-rw-r--r--lib/stdlib/doc/src/erl_expand_records.xml4
-rw-r--r--lib/stdlib/doc/src/erl_id_trans.xml4
-rw-r--r--lib/stdlib/doc/src/erl_internal.xml22
-rw-r--r--lib/stdlib/doc/src/erl_lint.xml12
-rw-r--r--lib/stdlib/doc/src/erl_parse.xml32
-rw-r--r--lib/stdlib/doc/src/erl_pp.xml38
-rw-r--r--lib/stdlib/doc/src/erl_scan.xml30
-rw-r--r--lib/stdlib/doc/src/erl_tar.xml77
-rw-r--r--lib/stdlib/doc/src/ets.xml384
-rw-r--r--lib/stdlib/doc/src/file_sorter.xml30
-rw-r--r--lib/stdlib/doc/src/filelib.xml59
-rw-r--r--lib/stdlib/doc/src/filename.xml104
-rw-r--r--lib/stdlib/doc/src/gb_sets.xml76
-rw-r--r--lib/stdlib/doc/src/gb_trees.xml61
-rw-r--r--lib/stdlib/doc/src/gen_event.xml61
-rw-r--r--lib/stdlib/doc/src/gen_server.xml114
-rw-r--r--lib/stdlib/doc/src/gen_statem.xml593
-rw-r--r--lib/stdlib/doc/src/io.xml222
-rw-r--r--lib/stdlib/doc/src/io_lib.xml103
-rw-r--r--lib/stdlib/doc/src/lib.xml103
-rw-r--r--lib/stdlib/doc/src/lists.xml168
-rw-r--r--lib/stdlib/doc/src/log_mf_h.xml6
-rw-r--r--lib/stdlib/doc/src/maps.xml166
-rw-r--r--lib/stdlib/doc/src/math.xml52
-rw-r--r--lib/stdlib/doc/src/ms_transform.xml8
-rw-r--r--lib/stdlib/doc/src/notes.xml950
-rw-r--r--lib/stdlib/doc/src/orddict.xml44
-rw-r--r--lib/stdlib/doc/src/ordsets.xml47
-rw-r--r--lib/stdlib/doc/src/pool.xml18
-rw-r--r--lib/stdlib/doc/src/proc_lib.xml109
-rw-r--r--lib/stdlib/doc/src/proplists.xml45
-rw-r--r--lib/stdlib/doc/src/qlc.xml135
-rw-r--r--lib/stdlib/doc/src/queue.xml64
-rw-r--r--lib/stdlib/doc/src/rand.xml262
-rw-r--r--lib/stdlib/doc/src/random.xml18
-rw-r--r--lib/stdlib/doc/src/re.xml22
-rw-r--r--lib/stdlib/doc/src/ref_man.xml4
-rw-r--r--lib/stdlib/doc/src/sets.xml47
-rw-r--r--lib/stdlib/doc/src/shell.xml16
-rw-r--r--lib/stdlib/doc/src/slave.xml45
-rw-r--r--lib/stdlib/doc/src/sofs.xml168
-rw-r--r--lib/stdlib/doc/src/specs.xml2
-rw-r--r--lib/stdlib/doc/src/string.xml152
-rw-r--r--lib/stdlib/doc/src/supervisor.xml38
-rw-r--r--lib/stdlib/doc/src/supervisor_bridge.xml10
-rw-r--r--lib/stdlib/doc/src/sys.xml259
-rw-r--r--lib/stdlib/doc/src/timer.xml50
-rw-r--r--lib/stdlib/doc/src/unicode.xml32
-rw-r--r--lib/stdlib/doc/src/unicode_usage.xml8
-rw-r--r--lib/stdlib/doc/src/uri_string.xml359
-rw-r--r--lib/stdlib/doc/src/win32reg.xml28
-rw-r--r--lib/stdlib/doc/src/zip.xml44
-rw-r--r--lib/stdlib/include/assert.hrl28
-rw-r--r--lib/stdlib/src/Makefile17
-rw-r--r--lib/stdlib/src/array.erl23
-rw-r--r--lib/stdlib/src/base64.erl623
-rw-r--r--lib/stdlib/src/beam_lib.erl82
-rw-r--r--lib/stdlib/src/binary.erl30
-rw-r--r--lib/stdlib/src/c.erl28
-rw-r--r--lib/stdlib/src/calendar.erl246
-rw-r--r--lib/stdlib/src/dets.erl37
-rw-r--r--lib/stdlib/src/dets_utils.erl5
-rw-r--r--lib/stdlib/src/edlin.erl2
-rw-r--r--lib/stdlib/src/epp.erl145
-rw-r--r--lib/stdlib/src/erl_compile.erl3
-rw-r--r--lib/stdlib/src/erl_error.erl421
-rw-r--r--lib/stdlib/src/erl_eval.erl408
-rw-r--r--lib/stdlib/src/erl_internal.erl6
-rw-r--r--lib/stdlib/src/erl_lint.erl187
-rw-r--r--lib/stdlib/src/erl_parse.yrl97
-rw-r--r--lib/stdlib/src/erl_posix_msg.erl11
-rw-r--r--lib/stdlib/src/erl_pp.erl241
-rw-r--r--lib/stdlib/src/erl_scan.erl6
-rw-r--r--lib/stdlib/src/erl_tar.erl84
-rw-r--r--lib/stdlib/src/erl_tar.hrl16
-rw-r--r--lib/stdlib/src/escript.erl34
-rw-r--r--lib/stdlib/src/ets.erl51
-rw-r--r--lib/stdlib/src/eval_bits.erl21
-rw-r--r--lib/stdlib/src/file_sorter.erl10
-rw-r--r--lib/stdlib/src/filelib.erl42
-rw-r--r--lib/stdlib/src/filename.erl137
-rw-r--r--lib/stdlib/src/gen.erl87
-rw-r--r--lib/stdlib/src/gen_event.erl93
-rw-r--r--lib/stdlib/src/gen_fsm.erl233
-rw-r--r--lib/stdlib/src/gen_server.erl217
-rw-r--r--lib/stdlib/src/gen_statem.erl2472
-rw-r--r--lib/stdlib/src/io.erl13
-rw-r--r--lib/stdlib/src/io_lib.erl276
-rw-r--r--lib/stdlib/src/io_lib_format.erl393
-rw-r--r--lib/stdlib/src/io_lib_pretty.erl691
-rw-r--r--lib/stdlib/src/lib.erl746
-rw-r--r--lib/stdlib/src/lists.erl19
-rw-r--r--lib/stdlib/src/maps.erl237
-rw-r--r--lib/stdlib/src/ms_transform.erl17
-rw-r--r--lib/stdlib/src/ordsets.erl11
-rw-r--r--lib/stdlib/src/otp_internal.erl192
-rw-r--r--lib/stdlib/src/pool.erl8
-rw-r--r--lib/stdlib/src/proc_lib.erl140
-rw-r--r--lib/stdlib/src/qlc.erl63
-rw-r--r--lib/stdlib/src/rand.erl822
-rw-r--r--lib/stdlib/src/sets.erl10
-rw-r--r--lib/stdlib/src/shell.erl15
-rw-r--r--lib/stdlib/src/slave.erl35
-rw-r--r--lib/stdlib/src/stdlib.app.src7
-rw-r--r--lib/stdlib/src/stdlib.appup.src41
-rw-r--r--lib/stdlib/src/string.erl249
-rw-r--r--lib/stdlib/src/supervisor.erl997
-rw-r--r--lib/stdlib/src/supervisor_bridge.erl29
-rw-r--r--lib/stdlib/src/sys.erl227
-rw-r--r--lib/stdlib/src/uri_string.erl2153
-rw-r--r--lib/stdlib/src/zip.erl5
-rw-r--r--lib/stdlib/test/Makefile18
-rw-r--r--lib/stdlib/test/array_SUITE.erl10
-rw-r--r--lib/stdlib/test/base64_SUITE.erl109
-rw-r--r--lib/stdlib/test/beam_lib_SUITE.erl102
-rw-r--r--lib/stdlib/test/binary_module_SUITE.erl20
-rw-r--r--lib/stdlib/test/c_SUITE.erl2
-rw-r--r--lib/stdlib/test/calendar_SUITE.erl177
-rw-r--r--lib/stdlib/test/dets_SUITE.erl21
-rw-r--r--lib/stdlib/test/epp_SUITE.erl185
-rw-r--r--lib/stdlib/test/epp_SUITE_data/source_name.erl27
-rw-r--r--lib/stdlib/test/erl_eval_SUITE.erl278
-rw-r--r--lib/stdlib/test/erl_internal_SUITE.erl4
-rw-r--r--lib/stdlib/test/erl_lint_SUITE.erl216
-rw-r--r--lib/stdlib/test/erl_pp_SUITE.erl117
-rw-r--r--lib/stdlib/test/error_logger_h_SUITE.erl10
-rw-r--r--lib/stdlib/test/ets_SUITE.erl2567
-rw-r--r--lib/stdlib/test/ets_SUITE_data/visualize_throughput.html253
-rw-r--r--lib/stdlib/test/filelib_SUITE.erl55
-rw-r--r--lib/stdlib/test/gen_fsm_SUITE.erl14
-rw-r--r--lib/stdlib/test/gen_server_SUITE.erl111
-rw-r--r--lib/stdlib/test/gen_server_SUITE_data/oc_server.erl12
-rw-r--r--lib/stdlib/test/gen_statem_SUITE.erl173
-rw-r--r--lib/stdlib/test/id_transform_SUITE.erl2
-rw-r--r--lib/stdlib/test/io_SUITE.erl344
-rw-r--r--lib/stdlib/test/lists_SUITE.erl85
-rw-r--r--lib/stdlib/test/maps_SUITE.erl48
-rw-r--r--lib/stdlib/test/proc_lib_SUITE.erl19
-rw-r--r--lib/stdlib/test/property_test/README12
-rw-r--r--lib/stdlib/test/property_test/uri_string_recompose.erl571
-rw-r--r--lib/stdlib/test/qlc_SUITE.erl105
-rw-r--r--lib/stdlib/test/rand_SUITE.erl1215
-rw-r--r--lib/stdlib/test/rand_Xoroshiro928ss_dev.txt343
-rw-r--r--lib/stdlib/test/re_SUITE.erl2
-rw-r--r--lib/stdlib/test/re_SUITE_data/testoutput216
-rw-r--r--lib/stdlib/test/re_SUITE_data/testoutput58
-rw-r--r--lib/stdlib/test/sets_SUITE.erl17
-rw-r--r--lib/stdlib/test/sets_test_lib.erl15
-rw-r--r--lib/stdlib/test/shell_SUITE.erl12
-rw-r--r--lib/stdlib/test/stdlib.spec6
-rw-r--r--lib/stdlib/test/stdlib_bench.spec11
-rw-r--r--lib/stdlib/test/stdlib_bench_SUITE.erl592
-rw-r--r--lib/stdlib/test/stdlib_bench_SUITE_data/generic_fsm.erl59
-rw-r--r--lib/stdlib/test/stdlib_bench_SUITE_data/generic_server.erl31
-rw-r--r--lib/stdlib/test/stdlib_bench_SUITE_data/generic_server_timer.erl31
-rw-r--r--lib/stdlib/test/stdlib_bench_SUITE_data/generic_statem.erl60
-rw-r--r--lib/stdlib/test/stdlib_bench_SUITE_data/generic_statem_complex.erl66
-rw-r--r--lib/stdlib/test/stdlib_bench_SUITE_data/simple_server.erl31
-rw-r--r--lib/stdlib/test/stdlib_bench_SUITE_data/simple_server_mon.erl33
-rw-r--r--lib/stdlib/test/stdlib_bench_SUITE_data/simple_server_timer.erl33
-rw-r--r--lib/stdlib/test/stdlib_bench_SUITE_data/simple_server_timer_mon.erl35
-rw-r--r--lib/stdlib/test/string_SUITE.erl159
-rw-r--r--lib/stdlib/test/supervisor_1.erl4
-rw-r--r--lib/stdlib/test/supervisor_SUITE.erl373
-rw-r--r--lib/stdlib/test/supervisor_deadlock.erl2
-rw-r--r--lib/stdlib/test/sys_SUITE.erl45
-rw-r--r--lib/stdlib/test/tar_SUITE.erl30
-rw-r--r--lib/stdlib/test/unicode_util_SUITE.erl105
-rw-r--r--lib/stdlib/test/unicode_util_SUITE_data/GraphemeBreakTest.txt1159
-rw-r--r--lib/stdlib/test/unicode_util_SUITE_data/LineBreakTest.txt263
-rw-r--r--lib/stdlib/test/unicode_util_SUITE_data/NormalizationTest.txt76
-rw-r--r--lib/stdlib/test/uri_string_SUITE.erl1168
-rw-r--r--lib/stdlib/test/uri_string_property_test_SUITE.erl44
-rw-r--r--lib/stdlib/test/zip_SUITE.erl5
-rw-r--r--lib/stdlib/test/zzz_SUITE.erl37
-rw-r--r--lib/stdlib/uc_spec/CaseFolding.txt87
-rw-r--r--lib/stdlib/uc_spec/CompositionExclusions.txt6
-rw-r--r--lib/stdlib/uc_spec/GraphemeBreakProperty.txt119
-rw-r--r--lib/stdlib/uc_spec/PropList.txt124
-rw-r--r--lib/stdlib/uc_spec/README-UPDATE.txt8
-rw-r--r--lib/stdlib/uc_spec/SpecialCasing.txt10
-rw-r--r--lib/stdlib/uc_spec/UnicodeData.txt1800
-rw-r--r--lib/stdlib/uc_spec/emoji-data.txt714
-rw-r--r--[-rwxr-xr-x]lib/stdlib/uc_spec/gen_unicode_mod.escript371
-rw-r--r--lib/stdlib/vsn.mk2
l---------lib/syntax_tools/doc/demo.erl1
-rw-r--r--lib/syntax_tools/doc/overview.edoc2
-rw-r--r--lib/syntax_tools/doc/src/Makefile23
-rw-r--r--lib/syntax_tools/doc/src/notes.xml121
-rw-r--r--lib/syntax_tools/src/Makefile2
-rw-r--r--lib/syntax_tools/src/epp_dodger.erl36
-rw-r--r--lib/syntax_tools/src/erl_comment_scan.erl2
-rw-r--r--lib/syntax_tools/src/erl_prettypr.erl25
-rw-r--r--lib/syntax_tools/src/erl_syntax.erl114
-rw-r--r--lib/syntax_tools/src/erl_syntax_lib.erl4
-rw-r--r--lib/syntax_tools/src/igor.erl2
-rw-r--r--lib/syntax_tools/src/merl_transform.erl2
-rw-r--r--lib/syntax_tools/test/merl_SUITE.erl14
-rw-r--r--lib/syntax_tools/test/syntax_tools_SUITE.erl148
-rw-r--r--lib/syntax_tools/test/syntax_tools_SUITE_data/specs_and_funs.erl18
-rw-r--r--lib/syntax_tools/vsn.mk2
-rw-r--r--lib/tftp/AUTHORS11
-rw-r--r--lib/tftp/Makefile78
-rw-r--r--lib/tftp/doc/html/.gitignore (renamed from lib/cosEvent/include/.gitignore)0
-rw-r--r--lib/tftp/doc/man3/.gitignore (renamed from lib/cosEvent/test/idl_output/.gitignore)0
-rw-r--r--lib/tftp/doc/man6/.gitignore (renamed from lib/cosEventDomain/doc/html/.gitignore)0
-rw-r--r--lib/tftp/doc/pdf/.gitignore (renamed from lib/cosEventDomain/doc/man3/.gitignore)0
-rw-r--r--lib/tftp/doc/src/Makefile155
-rw-r--r--lib/tftp/doc/src/book.xml49
-rw-r--r--lib/tftp/doc/src/getting_started.xml81
-rw-r--r--lib/tftp/doc/src/introduction.xml62
-rw-r--r--lib/tftp/doc/src/notes.xml68
-rw-r--r--lib/tftp/doc/src/ref_man.xml36
-rw-r--r--lib/tftp/doc/src/tftp.xml599
-rw-r--r--lib/tftp/doc/src/usersguide.xml37
-rw-r--r--lib/tftp/ebin/.gitignore (renamed from lib/cosEventDomain/doc/man6/.gitignore)0
-rw-r--r--lib/tftp/info2
-rw-r--r--lib/tftp/src/Makefile110
-rw-r--r--lib/tftp/src/tftp.app.src22
-rw-r--r--lib/tftp/src/tftp.appup.src26
-rw-r--r--lib/tftp/src/tftp.erl409
-rw-r--r--lib/tftp/src/tftp.hrl69
-rw-r--r--lib/tftp/src/tftp_app.erl56
-rw-r--r--lib/tftp/src/tftp_binary.erl239
-rw-r--r--lib/tftp/src/tftp_engine.erl1422
-rw-r--r--lib/tftp/src/tftp_file.erl390
-rw-r--r--lib/tftp/src/tftp_lib.erl474
-rw-r--r--lib/tftp/src/tftp_logger.erl99
-rw-r--r--lib/tftp/src/tftp_sup.erl111
-rw-r--r--lib/tftp/test/Makefile250
-rw-r--r--lib/tftp/test/tftp.config1
-rw-r--r--lib/tftp/test/tftp.cover2
-rw-r--r--lib/tftp/test/tftp.spec1
-rw-r--r--lib/tftp/test/tftp_SUITE.erl1001
-rw-r--r--lib/tftp/test/tftp_bench.spec1
-rw-r--r--lib/tftp/test/tftp_test_lib.erl308
-rw-r--r--lib/tftp/test/tftp_test_lib.hrl44
-rw-r--r--lib/tftp/vsn.mk24
-rw-r--r--lib/tools/c_src/Makefile.in7
-rw-r--r--lib/tools/doc/specs/.gitignore1
-rw-r--r--lib/tools/doc/src/Makefile17
-rw-r--r--lib/tools/doc/src/cover.xml104
-rw-r--r--lib/tools/doc/src/cprof.xml42
-rw-r--r--lib/tools/doc/src/eprof.xml38
-rw-r--r--lib/tools/doc/src/fprof.xml62
-rw-r--r--lib/tools/doc/src/instrument.xml532
-rw-r--r--lib/tools/doc/src/lcnt.xml70
-rw-r--r--lib/tools/doc/src/make.xml15
-rw-r--r--lib/tools/doc/src/notes.xml158
-rw-r--r--lib/tools/doc/src/specs.xml12
-rw-r--r--lib/tools/doc/src/tags.xml16
-rw-r--r--lib/tools/doc/src/xref.xml64
-rw-r--r--lib/tools/emacs/Makefile1
-rw-r--r--lib/tools/emacs/erlang-edoc.el1
-rw-r--r--lib/tools/emacs/erlang-eunit.el10
-rw-r--r--lib/tools/emacs/erlang-pkg.el3
-rw-r--r--lib/tools/emacs/erlang-skels.el2
-rw-r--r--lib/tools/emacs/erlang-test.el84
-rw-r--r--lib/tools/emacs/erlang.el646
-rw-r--r--lib/tools/emacs/erlang_appwiz.el13
-rw-r--r--lib/tools/emacs/erldoc.el38
-rw-r--r--lib/tools/priv/styles.css96
-rw-r--r--lib/tools/src/Makefile7
-rw-r--r--lib/tools/src/cover.erl619
-rw-r--r--lib/tools/src/eprof.erl52
-rw-r--r--lib/tools/src/fprof.erl5
-rw-r--r--lib/tools/src/instrument.erl538
-rw-r--r--lib/tools/src/lcnt.erl7
-rw-r--r--lib/tools/src/tools.app.src2
-rw-r--r--lib/tools/src/xref.erl6
-rw-r--r--lib/tools/src/xref_utils.erl9
-rw-r--r--lib/tools/test/Makefile3
-rw-r--r--lib/tools/test/cover_SUITE.erl40
-rw-r--r--lib/tools/test/emacs_SUITE.erl200
-rw-r--r--lib/tools/test/eprof_SUITE_data/eed.erl6
-rw-r--r--lib/tools/test/fprof_SUITE.erl4
-rw-r--r--lib/tools/test/instrument_SUITE.erl421
-rw-r--r--lib/tools/test/lcnt_SUITE.erl2
-rw-r--r--lib/tools/test/prof_bench_SUITE.erl126
-rw-r--r--lib/tools/test/prof_bench_SUITE_data/sofs_copy.erl2809
-rw-r--r--lib/tools/test/tools_bench.spec1
-rw-r--r--lib/tools/test/xref_SUITE.erl30
-rw-r--r--lib/tools/vsn.mk2
-rw-r--r--lib/wx/api_gen/gen_util.erl6
-rw-r--r--lib/wx/api_gen/gl_gen.erl6
-rw-r--r--lib/wx/api_gen/gl_gen_erl.erl10
-rw-r--r--lib/wx/api_gen/gl_scan_doc.erl2
-rw-r--r--lib/wx/api_gen/wx_extra/added_func.h6
-rw-r--r--lib/wx/api_gen/wx_extra/wxGraphicsRenderer.c_src58
-rw-r--r--lib/wx/api_gen/wx_gen.erl20
-rw-r--r--lib/wx/api_gen/wx_gen_cpp.erl28
-rw-r--r--lib/wx/api_gen/wx_gen_erl.erl9
-rw-r--r--lib/wx/api_gen/wxapi.conf63
-rw-r--r--lib/wx/c_src/Makefile.in1
-rw-r--r--lib/wx/c_src/gen/wxe_derived_dest.h10
-rw-r--r--lib/wx/c_src/gen/wxe_events.cpp4
-rw-r--r--lib/wx/c_src/gen/wxe_funcs.cpp159
-rw-r--r--lib/wx/c_src/gen/wxe_init.cpp180
-rw-r--r--lib/wx/c_src/gen/wxe_macros.h20
-rw-r--r--lib/wx/c_src/wxe_driver.c167
-rw-r--r--lib/wx/c_src/wxe_driver.h4
-rw-r--r--lib/wx/c_src/wxe_helpers.cpp3
-rw-r--r--lib/wx/c_src/wxe_helpers.h2
-rw-r--r--lib/wx/c_src/wxe_impl.cpp24
-rw-r--r--lib/wx/c_src/wxe_impl.h2
-rw-r--r--lib/wx/c_src/wxe_main.cpp15
-rw-r--r--lib/wx/c_src/wxe_ps_init.c27
-rw-r--r--lib/wx/doc/overview.edoc2
-rw-r--r--lib/wx/doc/src/Makefile43
-rw-r--r--lib/wx/doc/src/notes.xml85
-rw-r--r--lib/wx/examples/demo/demo.erl2
-rw-r--r--lib/wx/examples/demo/ex_aui.erl5
-rw-r--r--lib/wx/examples/demo/ex_graphicsContext.erl2
-rw-r--r--lib/wx/examples/simple/hello.erl2
-rw-r--r--lib/wx/examples/simple/hello2.erl4
-rw-r--r--lib/wx/examples/simple/menu.erl2
-rw-r--r--lib/wx/examples/simple/minimal.erl2
-rw-r--r--lib/wx/examples/sudoku/sudoku.erl2
-rw-r--r--lib/wx/examples/sudoku/sudoku_game.erl2
-rw-r--r--lib/wx/examples/sudoku/sudoku_gui.erl2
-rw-r--r--lib/wx/examples/xrc/xrc.erl2
-rw-r--r--lib/wx/include/wx.hrl34
-rw-r--r--lib/wx/src/Makefile4
-rw-r--r--lib/wx/src/gen/wxDisplay.erl131
-rw-r--r--lib/wx/src/gen/wxGCDC.erl287
-rw-r--r--lib/wx/src/gen/wxe_debug.hrl18
-rw-r--r--lib/wx/src/gen/wxe_funcs.hrl18
-rw-r--r--lib/wx/src/wx.erl12
-rw-r--r--lib/wx/src/wxe_master.erl15
-rw-r--r--lib/wx/src/wxe_server.erl10
-rw-r--r--lib/wx/test/wx_app_SUITE.erl2
-rw-r--r--lib/wx/test/wx_class_SUITE.erl4
-rw-r--r--lib/wx/test/wx_event_SUITE.erl6
-rw-r--r--lib/wx/test/wx_opengl_SUITE.erl2
-rw-r--r--lib/wx/test/wx_test_lib.erl2
-rw-r--r--lib/wx/test/wx_xtra_SUITE.erl2
-rwxr-xr-xlib/wx/test/wxt6
-rw-r--r--lib/wx/test/wxt.erl2
-rw-r--r--lib/wx/vsn.mk2
-rw-r--r--lib/xmerl/doc/src/Makefile17
-rw-r--r--lib/xmerl/doc/src/notes.xml100
-rw-r--r--lib/xmerl/doc/src/xmerl_sax_parser.xml10
-rw-r--r--lib/xmerl/src/xmerl_sax_parser.erl136
-rw-r--r--lib/xmerl/src/xmerl_sax_parser_base.erlsrc2
-rw-r--r--lib/xmerl/src/xmerl_scan.erl19
-rw-r--r--lib/xmerl/src/xmerl_xsd.erl4
-rw-r--r--lib/xmerl/test/xmerl_SUITE_data/eventp/CMOM.xml28
-rw-r--r--lib/xmerl/test/xmerl_SUITE_data/eventp/CelloMOM.xml28
-rw-r--r--lib/xmerl/test/xmerl_xsd_lib.erl7
-rw-r--r--lib/xmerl/vsn.mk2
3109 files changed, 226372 insertions, 274084 deletions
diff --git a/lib/.gitignore b/lib/.gitignore
index 283393faa9..07a94c7ae6 100644
--- a/lib/.gitignore
+++ b/lib/.gitignore
@@ -1,32 +1,3 @@
-# common test
-
-/common_test/doc/src/ct.xml
-/common_test/doc/src/ct_cover.xml
-/common_test/doc/src/ct_ftp.xml
-/common_test/doc/src/ct_master.xml
-/common_test/doc/src/ct_rpc.xml
-/common_test/doc/src/ct_snmp.xml
-/common_test/doc/src/ct_ssh.xml
-/common_test/doc/src/ct_netconfc.xml
-/common_test/doc/src/ct_telnet.xml
-/common_test/doc/src/unix_telnet.xml
-
-# edoc
-
-/edoc/doc/src/chapter.xml
-/edoc/doc/src/edoc.xml
-/edoc/doc/src/edoc_doclet.xml
-/edoc/doc/src/edoc_extract.xml
-/edoc/doc/src/edoc_layout.xml
-/edoc/doc/src/edoc_lib.xml
-/edoc/doc/src/edoc_run.xml
-
-# eunit
-
-/eunit/doc/src/chapter.xml
-/eunit/doc/src/eunit.xml
-/eunit/doc/src/eunit_surefire.xml
-
# erl_interface
/erl_interface/bin
@@ -34,15 +5,6 @@
/erl_interface/obj.st
/erl_interface/obj
-# gs
-
-/gs/doc/src/gs_chapter2.xml
-/gs/doc/src/gs_chapter4.xml
-/gs/doc/src/gs_chapter5.xml
-/gs/doc/src/gs_chapter6.xml
-/gs/doc/src/gs_chapter7.xml
-/gs/doc/src/gs_chapter8.xml
-
# megaco
/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3a.erl
@@ -129,435 +91,3 @@
/megaco/src/text/megaco_text_parser_v1.erl
/megaco/src/text/megaco_text_parser_v2.erl
/megaco/src/text/megaco_text_parser_v3.erl
-/megaco/doc/html/mstone1.jpg
-
-# mnesia
-
-/mnesia/doc/src/Mnesia_App_A.xml
-/mnesia/doc/src/Mnesia_App_B.xml
-/mnesia/doc/src/Mnesia_App_C.xml
-/mnesia/doc/src/Mnesia_App_D.xml
-/mnesia/doc/src/Mnesia_chap2.xml
-/mnesia/doc/src/Mnesia_chap3.xml
-/mnesia/doc/src/Mnesia_chap4.xml
-/mnesia/doc/src/Mnesia_chap5.xml
-/mnesia/doc/src/Mnesia_chap7.xml
-
-# orber & cos* applications
-
-/orber/test/idl_output
-/cosEvent/test/idl_output
-/cosNotification/test/idl_output
-/cosTransactions/test/idl_output
-
-/cosEvent/include/CosEventChannelAdmin.hrl
-/cosEvent/include/CosEventChannelAdmin_ConsumerAdmin.hrl
-/cosEvent/include/CosEventChannelAdmin_EventChannel.hrl
-/cosEvent/include/CosEventChannelAdmin_ProxyPullConsumer.hrl
-/cosEvent/include/CosEventChannelAdmin_ProxyPullSupplier.hrl
-/cosEvent/include/CosEventChannelAdmin_ProxyPushConsumer.hrl
-/cosEvent/include/CosEventChannelAdmin_ProxyPushSupplier.hrl
-/cosEvent/include/CosEventChannelAdmin_SupplierAdmin.hrl
-/cosEvent/include/CosEventComm.hrl
-/cosEvent/include/CosEventComm_PullConsumer.hrl
-/cosEvent/include/CosEventComm_PullSupplier.hrl
-/cosEvent/include/CosEventComm_PushConsumer.hrl
-/cosEvent/include/CosEventComm_PushSupplier.hrl
-/cosEvent/include/oe_CosEventChannelAdmin.hrl
-/cosEvent/include/oe_CosEventComm.hrl
-/cosEvent/src/CosEventChannelAdmin_AlreadyConnected.erl
-/cosEvent/src/CosEventChannelAdmin_ConsumerAdmin.erl
-/cosEvent/src/CosEventChannelAdmin_EventChannel.erl
-/cosEvent/src/CosEventChannelAdmin_ProxyPullConsumer.erl
-/cosEvent/src/CosEventChannelAdmin_ProxyPullSupplier.erl
-/cosEvent/src/CosEventChannelAdmin_ProxyPushConsumer.erl
-/cosEvent/src/CosEventChannelAdmin_ProxyPushSupplier.erl
-/cosEvent/src/CosEventChannelAdmin_SupplierAdmin.erl
-/cosEvent/src/CosEventChannelAdmin_TypeError.erl
-/cosEvent/src/CosEventComm_Disconnected.erl
-/cosEvent/src/CosEventComm_PullConsumer.erl
-/cosEvent/src/CosEventComm_PullSupplier.erl
-/cosEvent/src/CosEventComm_PushConsumer.erl
-/cosEvent/src/CosEventComm_PushSupplier.erl
-/cosEvent/src/oe_CosEventChannelAdmin.erl
-/cosEvent/src/oe_CosEventComm.erl
-/cosEvent/src/oe_CosEventComm_CAdmin.erl
-/cosEvent/src/oe_CosEventComm_CAdmin.hrl
-/cosEvent/src/oe_CosEventComm_Channel.erl
-/cosEvent/src/oe_CosEventComm_Channel.hrl
-/cosEvent/src/oe_CosEventComm_Event.erl
-/cosEvent/src/oe_CosEventComm_Event.hrl
-/cosEvent/src/oe_CosEventComm_PullerS.erl
-/cosEvent/src/oe_CosEventComm_PullerS.hrl
-/cosEvent/src/oe_CosEventComm_PusherS.erl
-/cosEvent/src/oe_CosEventComm_PusherS.hrl
-/cosEvent/src/oe_cosEventApp.erl
-/cosEvent/src/oe_cosEventApp.hrl
-/cosEventDomain/include/CosEventDomainAdmin.hrl
-/cosEventDomain/include/CosEventDomainAdmin_EventDomain.hrl
-/cosEventDomain/include/CosEventDomainAdmin_EventDomainFactory.hrl
-/cosEventDomain/include/oe_CosEventDomainAdmin.hrl
-/cosEventDomain/src/CosEventDomainAdmin.erl
-/cosEventDomain/src/CosEventDomainAdmin_AlreadyExists.erl
-/cosEventDomain/src/CosEventDomainAdmin_Connection.erl
-/cosEventDomain/src/CosEventDomainAdmin_ConnectionIDSeq.erl
-/cosEventDomain/src/CosEventDomainAdmin_ConnectionNotFound.erl
-/cosEventDomain/src/CosEventDomainAdmin_CycleCreationForbidden.erl
-/cosEventDomain/src/CosEventDomainAdmin_CycleSeq.erl
-/cosEventDomain/src/CosEventDomainAdmin_DiamondCreationForbidden.erl
-/cosEventDomain/src/CosEventDomainAdmin_DiamondSeq.erl
-/cosEventDomain/src/CosEventDomainAdmin_DomainIDSeq.erl
-/cosEventDomain/src/CosEventDomainAdmin_DomainNotFound.erl
-/cosEventDomain/src/CosEventDomainAdmin_EventDomain.erl
-/cosEventDomain/src/CosEventDomainAdmin_EventDomainFactory.erl
-/cosEventDomain/src/CosEventDomainAdmin_MemberIDSeq.erl
-/cosEventDomain/src/CosEventDomainAdmin_RouteSeq.erl
-/cosEventDomain/src/oe_CosEventDomainAdmin.erl
-/cosFileTransfer/include/CosFileTransfer.hrl
-/cosFileTransfer/include/CosFileTransfer_Directory.hrl
-/cosFileTransfer/include/CosFileTransfer_File.hrl
-/cosFileTransfer/include/CosFileTransfer_FileIterator.hrl
-/cosFileTransfer/include/CosFileTransfer_FileTransferSession.hrl
-/cosFileTransfer/include/CosFileTransfer_VirtualFileSystem.hrl
-/cosFileTransfer/include/oe_CosFileTransfer.hrl
-/cosFileTransfer/src/CosFileTransfer.erl
-/cosFileTransfer/src/CosFileTransfer_AccessLevel.erl
-/cosFileTransfer/src/CosFileTransfer_CommandNotImplementedException.erl
-/cosFileTransfer/src/CosFileTransfer_Directory.erl
-/cosFileTransfer/src/CosFileTransfer_File.erl
-/cosFileTransfer/src/CosFileTransfer_FileIterator.erl
-/cosFileTransfer/src/CosFileTransfer_FileList.erl
-/cosFileTransfer/src/CosFileTransfer_FileNameList.erl
-/cosFileTransfer/src/CosFileTransfer_FileNotFoundException.erl
-/cosFileTransfer/src/CosFileTransfer_FileTransferSession.erl
-/cosFileTransfer/src/CosFileTransfer_FileWrapper.erl
-/cosFileTransfer/src/CosFileTransfer_IllegalOperationException.erl
-/cosFileTransfer/src/CosFileTransfer_ProtocolAddressList.erl
-/cosFileTransfer/src/CosFileTransfer_ProtocolSupport.erl
-/cosFileTransfer/src/CosFileTransfer_RequestFailureException.erl
-/cosFileTransfer/src/CosFileTransfer_SessionException.erl
-/cosFileTransfer/src/CosFileTransfer_SupportedProtocolAddresses.erl
-/cosFileTransfer/src/CosFileTransfer_TransferException.erl
-/cosFileTransfer/src/CosFileTransfer_VirtualFileSystem.erl
-/cosFileTransfer/src/CosFileTransfer_VirtualFileSystem_ContentList.erl
-/cosFileTransfer/src/oe_CosFileTransfer.erl
-/cosNotification/include/CosNotification.hrl
-/cosNotification/include/CosNotification_AdminPropertiesAdmin.hrl
-/cosNotification/include/CosNotification_QoSAdmin.hrl
-/cosNotification/include/CosNotifyChannelAdmin.hrl
-/cosNotification/include/CosNotifyChannelAdmin_ConsumerAdmin.hrl
-/cosNotification/include/CosNotifyChannelAdmin_EventChannel.hrl
-/cosNotification/include/CosNotifyChannelAdmin_EventChannelFactory.hrl
-/cosNotification/include/CosNotifyChannelAdmin_ProxyConsumer.hrl
-/cosNotification/include/CosNotifyChannelAdmin_ProxyPullConsumer.hrl
-/cosNotification/include/CosNotifyChannelAdmin_ProxyPullSupplier.hrl
-/cosNotification/include/CosNotifyChannelAdmin_ProxyPushConsumer.hrl
-/cosNotification/include/CosNotifyChannelAdmin_ProxyPushSupplier.hrl
-/cosNotification/include/CosNotifyChannelAdmin_ProxySupplier.hrl
-/cosNotification/include/CosNotifyChannelAdmin_SequenceProxyPullConsumer.hrl
-/cosNotification/include/CosNotifyChannelAdmin_SequenceProxyPullSupplier.hrl
-/cosNotification/include/CosNotifyChannelAdmin_SequenceProxyPushConsumer.hrl
-/cosNotification/include/CosNotifyChannelAdmin_SequenceProxyPushSupplier.hrl
-/cosNotification/include/CosNotifyChannelAdmin_StructuredProxyPullConsumer.hrl
-/cosNotification/include/CosNotifyChannelAdmin_StructuredProxyPullSupplier.hrl
-/cosNotification/include/CosNotifyChannelAdmin_StructuredProxyPushConsumer.hrl
-/cosNotification/include/CosNotifyChannelAdmin_StructuredProxyPushSupplier.hrl
-/cosNotification/include/CosNotifyChannelAdmin_SupplierAdmin.hrl
-/cosNotification/include/CosNotifyComm.hrl
-/cosNotification/include/CosNotifyComm_NotifyPublish.hrl
-/cosNotification/include/CosNotifyComm_NotifySubscribe.hrl
-/cosNotification/include/CosNotifyComm_PullConsumer.hrl
-/cosNotification/include/CosNotifyComm_PullSupplier.hrl
-/cosNotification/include/CosNotifyComm_PushConsumer.hrl
-/cosNotification/include/CosNotifyComm_PushSupplier.hrl
-/cosNotification/include/CosNotifyComm_SequencePullConsumer.hrl
-/cosNotification/include/CosNotifyComm_SequencePullSupplier.hrl
-/cosNotification/include/CosNotifyComm_SequencePushConsumer.hrl
-/cosNotification/include/CosNotifyComm_SequencePushSupplier.hrl
-/cosNotification/include/CosNotifyComm_StructuredPullConsumer.hrl
-/cosNotification/include/CosNotifyComm_StructuredPullSupplier.hrl
-/cosNotification/include/CosNotifyComm_StructuredPushConsumer.hrl
-/cosNotification/include/CosNotifyComm_StructuredPushSupplier.hrl
-/cosNotification/include/CosNotifyFilter.hrl
-/cosNotification/include/CosNotifyFilter_Filter.hrl
-/cosNotification/include/CosNotifyFilter_FilterAdmin.hrl
-/cosNotification/include/CosNotifyFilter_FilterFactory.hrl
-/cosNotification/include/CosNotifyFilter_MappingFilter.hrl
-/cosNotification/include/oe_CosNotification.hrl
-/cosNotification/include/oe_CosNotifyChannelAdmin.hrl
-/cosNotification/include/oe_CosNotifyComm.hrl
-/cosNotification/include/oe_CosNotifyFilter.hrl
-/cosNotification/src/CosNotification.erl
-/cosNotification/src/CosNotification_AdminPropertiesAdmin.erl
-/cosNotification/src/CosNotification_EventBatch.erl
-/cosNotification/src/CosNotification_EventHeader.erl
-/cosNotification/src/CosNotification_EventType.erl
-/cosNotification/src/CosNotification_EventTypeSeq.erl
-/cosNotification/src/CosNotification_FixedEventHeader.erl
-/cosNotification/src/CosNotification_NamedPropertyRange.erl
-/cosNotification/src/CosNotification_NamedPropertyRangeSeq.erl
-/cosNotification/src/CosNotification_Property.erl
-/cosNotification/src/CosNotification_PropertyError.erl
-/cosNotification/src/CosNotification_PropertyErrorSeq.erl
-/cosNotification/src/CosNotification_PropertyRange.erl
-/cosNotification/src/CosNotification_PropertySeq.erl
-/cosNotification/src/CosNotification_QoSAdmin.erl
-/cosNotification/src/CosNotification_StructuredEvent.erl
-/cosNotification/src/CosNotification_UnsupportedAdmin.erl
-/cosNotification/src/CosNotification_UnsupportedQoS.erl
-/cosNotification/src/CosNotifyChannelAdmin_AdminIDSeq.erl
-/cosNotification/src/CosNotifyChannelAdmin_AdminLimit.erl
-/cosNotification/src/CosNotifyChannelAdmin_AdminLimitExceeded.erl
-/cosNotification/src/CosNotifyChannelAdmin_AdminNotFound.erl
-/cosNotification/src/CosNotifyChannelAdmin_ChannelIDSeq.erl
-/cosNotification/src/CosNotifyChannelAdmin_ChannelNotFound.erl
-/cosNotification/src/CosNotifyChannelAdmin_ConnectionAlreadyActive.erl
-/cosNotification/src/CosNotifyChannelAdmin_ConnectionAlreadyInactive.erl
-/cosNotification/src/CosNotifyChannelAdmin_ConsumerAdmin.erl
-/cosNotification/src/CosNotifyChannelAdmin_EventChannel.erl
-/cosNotification/src/CosNotifyChannelAdmin_EventChannelFactory.erl
-/cosNotification/src/CosNotifyChannelAdmin_NotConnected.erl
-/cosNotification/src/CosNotifyChannelAdmin_ProxyConsumer.erl
-/cosNotification/src/CosNotifyChannelAdmin_ProxyIDSeq.erl
-/cosNotification/src/CosNotifyChannelAdmin_ProxyNotFound.erl
-/cosNotification/src/CosNotifyChannelAdmin_ProxyPullConsumer.erl
-/cosNotification/src/CosNotifyChannelAdmin_ProxyPullSupplier.erl
-/cosNotification/src/CosNotifyChannelAdmin_ProxyPushConsumer.erl
-/cosNotification/src/CosNotifyChannelAdmin_ProxyPushSupplier.erl
-/cosNotification/src/CosNotifyChannelAdmin_ProxySupplier.erl
-/cosNotification/src/CosNotifyChannelAdmin_SequenceProxyPullConsumer.erl
-/cosNotification/src/CosNotifyChannelAdmin_SequenceProxyPullSupplier.erl
-/cosNotification/src/CosNotifyChannelAdmin_SequenceProxyPushConsumer.erl
-/cosNotification/src/CosNotifyChannelAdmin_SequenceProxyPushSupplier.erl
-/cosNotification/src/CosNotifyChannelAdmin_StructuredProxyPullConsumer.erl
-/cosNotification/src/CosNotifyChannelAdmin_StructuredProxyPullSupplier.erl
-/cosNotification/src/CosNotifyChannelAdmin_StructuredProxyPushConsumer.erl
-/cosNotification/src/CosNotifyChannelAdmin_StructuredProxyPushSupplier.erl
-/cosNotification/src/CosNotifyChannelAdmin_SupplierAdmin.erl
-/cosNotification/src/CosNotifyComm_InvalidEventType.erl
-/cosNotification/src/CosNotifyComm_NotifyPublish.erl
-/cosNotification/src/CosNotifyComm_NotifySubscribe.erl
-/cosNotification/src/CosNotifyComm_PullConsumer.erl
-/cosNotification/src/CosNotifyComm_PullSupplier.erl
-/cosNotification/src/CosNotifyComm_PushConsumer.erl
-/cosNotification/src/CosNotifyComm_PushSupplier.erl
-/cosNotification/src/CosNotifyComm_SequencePullConsumer.erl
-/cosNotification/src/CosNotifyComm_SequencePullSupplier.erl
-/cosNotification/src/CosNotifyComm_SequencePushConsumer.erl
-/cosNotification/src/CosNotifyComm_SequencePushSupplier.erl
-/cosNotification/src/CosNotifyComm_StructuredPullConsumer.erl
-/cosNotification/src/CosNotifyComm_StructuredPullSupplier.erl
-/cosNotification/src/CosNotifyComm_StructuredPushConsumer.erl
-/cosNotification/src/CosNotifyComm_StructuredPushSupplier.erl
-/cosNotification/src/CosNotifyFilter_CallbackIDSeq.erl
-/cosNotification/src/CosNotifyFilter_CallbackNotFound.erl
-/cosNotification/src/CosNotifyFilter_ConstraintExp.erl
-/cosNotification/src/CosNotifyFilter_ConstraintExpSeq.erl
-/cosNotification/src/CosNotifyFilter_ConstraintIDSeq.erl
-/cosNotification/src/CosNotifyFilter_ConstraintInfo.erl
-/cosNotification/src/CosNotifyFilter_ConstraintInfoSeq.erl
-/cosNotification/src/CosNotifyFilter_ConstraintNotFound.erl
-/cosNotification/src/CosNotifyFilter_DuplicateConstraintID.erl
-/cosNotification/src/CosNotifyFilter_Filter.erl
-/cosNotification/src/CosNotifyFilter_FilterAdmin.erl
-/cosNotification/src/CosNotifyFilter_FilterFactory.erl
-/cosNotification/src/CosNotifyFilter_FilterIDSeq.erl
-/cosNotification/src/CosNotifyFilter_FilterNotFound.erl
-/cosNotification/src/CosNotifyFilter_InvalidConstraint.erl
-/cosNotification/src/CosNotifyFilter_InvalidGrammar.erl
-/cosNotification/src/CosNotifyFilter_InvalidValue.erl
-/cosNotification/src/CosNotifyFilter_MappingConstraintInfo.erl
-/cosNotification/src/CosNotifyFilter_MappingConstraintInfoSeq.erl
-/cosNotification/src/CosNotifyFilter_MappingConstraintPair.erl
-/cosNotification/src/CosNotifyFilter_MappingConstraintPairSeq.erl
-/cosNotification/src/CosNotifyFilter_MappingFilter.erl
-/cosNotification/src/CosNotifyFilter_UnsupportedFilterableData.erl
-/cosNotification/src/cosNotification_Grammar.erl
-/cosNotification/src/oe_CosNotification.erl
-/cosNotification/src/oe_CosNotificationComm.hrl
-/cosNotification/src/oe_CosNotificationComm_Event.erl
-/cosNotification/src/oe_CosNotificationComm_Event.hrl
-/cosNotification/src/oe_CosNotifyChannelAdmin.erl
-/cosNotification/src/oe_CosNotifyComm.erl
-/cosNotification/src/oe_CosNotifyFilter.erl
-/cosNotification/src/oe_cosNotificationAppComm.erl
-/cosNotification/src/oe_cosNotificationAppComm.hrl
-/cosProperty/include/CosPropertyService.hrl
-/cosProperty/include/CosPropertyService_PropertiesIterator.hrl
-/cosProperty/include/CosPropertyService_PropertyNamesIterator.hrl
-/cosProperty/include/CosPropertyService_PropertySet.hrl
-/cosProperty/include/CosPropertyService_PropertySetDef.hrl
-/cosProperty/include/CosPropertyService_PropertySetDefFactory.hrl
-/cosProperty/include/CosPropertyService_PropertySetFactory.hrl
-/cosProperty/include/oe_CosProperty.hrl
-/cosProperty/src/CosPropertyService_ConflictingProperty.erl
-/cosProperty/src/CosPropertyService_ConstraintNotSupported.erl
-/cosProperty/src/CosPropertyService_FixedProperty.erl
-/cosProperty/src/CosPropertyService_InvalidPropertyName.erl
-/cosProperty/src/CosPropertyService_MultipleExceptions.erl
-/cosProperty/src/CosPropertyService_Properties.erl
-/cosProperty/src/CosPropertyService_PropertiesIterator.erl
-/cosProperty/src/CosPropertyService_Property.erl
-/cosProperty/src/CosPropertyService_PropertyDef.erl
-/cosProperty/src/CosPropertyService_PropertyDefs.erl
-/cosProperty/src/CosPropertyService_PropertyException.erl
-/cosProperty/src/CosPropertyService_PropertyExceptions.erl
-/cosProperty/src/CosPropertyService_PropertyMode.erl
-/cosProperty/src/CosPropertyService_PropertyModes.erl
-/cosProperty/src/CosPropertyService_PropertyNames.erl
-/cosProperty/src/CosPropertyService_PropertyNamesIterator.erl
-/cosProperty/src/CosPropertyService_PropertyNotFound.erl
-/cosProperty/src/CosPropertyService_PropertySet.erl
-/cosProperty/src/CosPropertyService_PropertySetDef.erl
-/cosProperty/src/CosPropertyService_PropertySetDefFactory.erl
-/cosProperty/src/CosPropertyService_PropertySetFactory.erl
-/cosProperty/src/CosPropertyService_PropertyTypes.erl
-/cosProperty/src/CosPropertyService_ReadOnlyProperty.erl
-/cosProperty/src/CosPropertyService_UnsupportedMode.erl
-/cosProperty/src/CosPropertyService_UnsupportedProperty.erl
-/cosProperty/src/CosPropertyService_UnsupportedTypeCode.erl
-/cosProperty/src/oe_CosProperty.erl
-/cosTime/include/CosTime.hrl
-/cosTime/include/CosTime_TIO.hrl
-/cosTime/include/CosTime_TimeService.hrl
-/cosTime/include/CosTime_UTO.hrl
-/cosTime/include/CosTimerEvent.hrl
-/cosTime/include/CosTimerEvent_TimerEventHandler.hrl
-/cosTime/include/CosTimerEvent_TimerEventService.hrl
-/cosTime/include/TimeBase.hrl
-/cosTime/include/oe_CosTime.hrl
-/cosTime/include/oe_CosTimerEvent.hrl
-/cosTime/include/oe_TimeBase.hrl
-/cosTime/src/CosTime_TIO.erl
-/cosTime/src/CosTime_TimeService.erl
-/cosTime/src/CosTime_TimeUnavailable.erl
-/cosTime/src/CosTime_UTO.erl
-/cosTime/src/CosTimerEvent_TimerEventHandler.erl
-/cosTime/src/CosTimerEvent_TimerEventService.erl
-/cosTime/src/CosTimerEvent_TimerEventT.erl
-/cosTime/src/TimeBase_IntervalT.erl
-/cosTime/src/TimeBase_UtcT.erl
-/cosTime/src/oe_CosTime.erl
-/cosTime/src/oe_CosTimerEvent.erl
-/cosTime/src/oe_TimeBase.erl
-/cosTransactions/include/CosTransactions.hrl
-/cosTransactions/include/CosTransactions_Control.hrl
-/cosTransactions/include/CosTransactions_Coordinator.hrl
-/cosTransactions/include/CosTransactions_RecoveryCoordinator.hrl
-/cosTransactions/include/CosTransactions_Resource.hrl
-/cosTransactions/include/CosTransactions_SubtransactionAwareResource.hrl
-/cosTransactions/include/CosTransactions_Terminator.hrl
-/cosTransactions/include/CosTransactions_TransactionFactory.hrl
-/cosTransactions/include/ETraP.hrl
-/cosTransactions/include/ETraP_Server.hrl
-/cosTransactions/include/oe_CosTransactions.hrl
-/cosTransactions/src/CosTransactions_Control.erl
-/cosTransactions/src/CosTransactions_Coordinator.erl
-/cosTransactions/src/CosTransactions_HeuristicCommit.erl
-/cosTransactions/src/CosTransactions_HeuristicHazard.erl
-/cosTransactions/src/CosTransactions_HeuristicMixed.erl
-/cosTransactions/src/CosTransactions_HeuristicRollback.erl
-/cosTransactions/src/CosTransactions_Inactive.erl
-/cosTransactions/src/CosTransactions_InvalidControl.erl
-/cosTransactions/src/CosTransactions_NoTransaction.erl
-/cosTransactions/src/CosTransactions_NotPrepared.erl
-/cosTransactions/src/CosTransactions_NotSubtransaction.erl
-/cosTransactions/src/CosTransactions_PropagationContext.erl
-/cosTransactions/src/CosTransactions_RecoveryCoordinator.erl
-/cosTransactions/src/CosTransactions_Resource.erl
-/cosTransactions/src/CosTransactions_SubtransactionAwareResource.erl
-/cosTransactions/src/CosTransactions_SubtransactionsUnavailable.erl
-/cosTransactions/src/CosTransactions_SynchronizationUnavailable.erl
-/cosTransactions/src/CosTransactions_Terminator.erl
-/cosTransactions/src/CosTransactions_TransIdentity.erl
-/cosTransactions/src/CosTransactions_TransactionFactory.erl
-/cosTransactions/src/CosTransactions_Unavailable.erl
-/cosTransactions/src/CosTransactions_WrongTransaction.erl
-/cosTransactions/src/CosTransactions_otid_t.erl
-/cosTransactions/src/ETraP_Server.erl
-/cosTransactions/src/oe_CosTransactions.erl
-/orber/COSS/CosNaming/CosNaming.hrl
-/orber/COSS/CosNaming/CosNaming_Binding.erl
-/orber/COSS/CosNaming/CosNaming_BindingIterator.erl
-/orber/COSS/CosNaming/CosNaming_BindingIterator.hrl
-/orber/COSS/CosNaming/CosNaming_BindingList.erl
-/orber/COSS/CosNaming/CosNaming_Name.erl
-/orber/COSS/CosNaming/CosNaming_NameComponent.erl
-/orber/COSS/CosNaming/CosNaming_NamingContext.erl
-/orber/COSS/CosNaming/CosNaming_NamingContext.hrl
-/orber/COSS/CosNaming/CosNaming_NamingContextExt.erl
-/orber/COSS/CosNaming/CosNaming_NamingContextExt.hrl
-/orber/COSS/CosNaming/CosNaming_NamingContextExt_AlreadyBound.erl
-/orber/COSS/CosNaming/CosNaming_NamingContextExt_CannotProceed.erl
-/orber/COSS/CosNaming/CosNaming_NamingContextExt_InvalidAddress.erl
-/orber/COSS/CosNaming/CosNaming_NamingContextExt_InvalidName.erl
-/orber/COSS/CosNaming/CosNaming_NamingContextExt_NotEmpty.erl
-/orber/COSS/CosNaming/CosNaming_NamingContextExt_NotFound.erl
-/orber/COSS/CosNaming/CosNaming_NamingContext_AlreadyBound.erl
-/orber/COSS/CosNaming/CosNaming_NamingContext_CannotProceed.erl
-/orber/COSS/CosNaming/CosNaming_NamingContext_InvalidName.erl
-/orber/COSS/CosNaming/CosNaming_NamingContext_NotEmpty.erl
-/orber/COSS/CosNaming/CosNaming_NamingContext_NotFound.erl
-/orber/COSS/CosNaming/oe_cos_naming.erl
-/orber/COSS/CosNaming/oe_cos_naming.hrl
-/orber/COSS/CosNaming/oe_cos_naming_ext.erl
-/orber/COSS/CosNaming/oe_cos_naming_ext.hrl
-/orber/examples/Stack/StackModule.hrl
-/orber/examples/Stack/StackModule_EmptyStack.erl
-/orber/examples/Stack/StackModule_Stack.erl
-/orber/examples/Stack/StackModule_Stack.hrl
-/orber/examples/Stack/StackModule_StackFactory.erl
-/orber/examples/Stack/StackModule_StackFactory.hrl
-/orber/examples/Stack/oe_stack.erl
-/orber/examples/Stack/oe_stack.hrl
-/orber/src/CORBA.hrl
-/orber/src/OrberApp.hrl
-/orber/src/OrberApp_IFR.erl
-/orber/src/OrberApp_IFR.hrl
-/orber/src/erlang.hrl
-/orber/src/erlang_binary.erl
-/orber/src/erlang_pid.erl
-/orber/src/erlang_port.erl
-/orber/src/erlang_ref.erl
-/orber/src/oe_CORBA.erl
-/orber/src/oe_CORBA.hrl
-/orber/src/oe_OrberIFR.erl
-/orber/src/oe_OrberIFR.hrl
-/orber/src/oe_erlang.erl
-/orber/src/oe_erlang.hrl
-
-# snmp
-
-snmp/doc/intex.html
-
-# syntax_tools
-
-/syntax_tools/doc/src/chapter.xml
-/syntax_tools/doc/src/epp_dodger.xml
-/syntax_tools/doc/src/erl_comment_scan.xml
-/syntax_tools/doc/src/erl_prettypr.xml
-/syntax_tools/doc/src/erl_recomment.xml
-/syntax_tools/doc/src/erl_syntax.xml
-/syntax_tools/doc/src/erl_syntax_lib.xml
-/syntax_tools/doc/src/erl_tidy.xml
-/syntax_tools/doc/src/merl.xml
-/syntax_tools/doc/src/merl_transform.xml
-/syntax_tools/doc/src/igor.xml
-/syntax_tools/doc/src/prettypr.xml
-
-# wx
-
-/wx/doc/src/chapter.xml
-/wx/doc/src/gl.xml
-/wx/doc/src/glu.xml
-/wx/doc/src/ref_man.xml
-
-# xmerl
-
-/xmerl/doc/src/xmerl.xml
-/xmerl/doc/src/xmerl_eventp.xml
-/xmerl/doc/src/xmerl_scan.xml
-/xmerl/doc/src/xmerl_ug.xml
-/xmerl/doc/src/xmerl_xpath.xml
-/xmerl/doc/src/xmerl_xs.xml
-/xmerl/doc/src/xmerl_xsd.xml
diff --git a/lib/Makefile b/lib/Makefile
index ae466ed518..ea2827bef0 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2016. All Rights Reserved.
+# Copyright Ericsson AB 1996-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -28,14 +28,13 @@ ERTS_APPLICATIONS = stdlib sasl kernel compiler
ERLANG_APPLICATIONS = tools common_test runtime_tools inets parsetools
# These are only build if -a is given to otp_build or make is used directly
-ALL_ERLANG_APPLICATIONS = xmerl edoc erl_docgen snmp otp_mibs erl_interface \
+ALL_ERLANG_APPLICATIONS = xmerl edoc erl_docgen snmp erl_interface \
asn1 jinterface \
wx debugger reltool \
- ic mnesia crypto orber os_mon syntax_tools \
+ mnesia crypto os_mon syntax_tools \
public_key ssl observer odbc diameter \
- cosTransactions cosEvent cosTime cosNotification \
- cosProperty cosFileTransfer cosEventDomain et megaco \
- eunit ssh eldap dialyzer hipe
+ et megaco \
+ eunit ssh eldap dialyzer hipe ftp tftp
ifdef BUILD_ALL
ERLANG_APPLICATIONS += $(ALL_ERLANG_APPLICATIONS)
@@ -59,10 +58,10 @@ else
SUB_DIRECTORIES = hipe parsetools asn1/src
else
ifdef TERTIARY_BOOTSTRAP
- SUB_DIRECTORIES = snmp sasl jinterface ic syntax_tools wx
+ SUB_DIRECTORIES = snmp sasl erl_interface jinterface syntax_tools wx
else
ifdef DOC_BOOTSTRAP
- SUB_DIRECTORIES = xmerl edoc erl_docgen
+ SUB_DIRECTORIES = xmerl edoc erl_docgen public_key
else # Not bootstrap build
SUB_DIRECTORIES = $(ERTS_APPLICATIONS) \
$(ERLANG_APPLICATIONS) \
diff --git a/lib/asn1/c_src/asn1_erl_nif.c b/lib/asn1/c_src/asn1_erl_nif.c
index d5aaadb89b..da43af3405 100644
--- a/lib/asn1/c_src/asn1_erl_nif.c
+++ b/lib/asn1/c_src/asn1_erl_nif.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2002-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2002-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -949,6 +949,12 @@ static int ber_decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char *
unsigned char *tmp_out_buff;
ERL_NIF_TERM term = 0, curr_head = 0;
+ /* Recursion depth limitation, borrow a signed int: maybe_ret */
+ maybe_ret = (int) (ErlNifSInt) ((char *)value - (char *)ib_index);
+ maybe_ret = maybe_ret < 0 ? -maybe_ret : maybe_ret;
+ if (maybe_ret >= sizeof(void *) * 8192) /* 8 k pointer words */
+ return ASN1_ERROR;
+
if (((in_buf[*ib_index]) & 0x80) == ASN1_SHORT_DEFINITE_LENGTH) {
len = in_buf[*ib_index];
} else if (in_buf[*ib_index] == ASN1_INDEFINITE_LENGTH) {
@@ -993,7 +999,7 @@ static int ber_decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char *
while (*ib_index < end_index) {
if ((maybe_ret = ber_decode(env, &term, in_buf, ib_index,
- in_buf_len)) <= ASN1_ERROR
+ end_index )) <= ASN1_ERROR
)
return maybe_ret;
curr_head = enif_make_list_cell(env, term, curr_head);
diff --git a/lib/asn1/doc/src/Makefile b/lib/asn1/doc/src/Makefile
index 9a388e4e8a..9c0d865884 100644
--- a/lib/asn1/doc/src/Makefile
+++ b/lib/asn1/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -51,13 +51,14 @@ XML_CHAPTER_FILES = \
asn1_introduction.xml \
asn1_getting_started.xml \
asn1_overview.xml \
- asn1_spec.xml \
notes.xml
BOOK_FILES = book.xml
XML_FILES = $(BOOK_FILES) $(XML_APPLICATION_FILES) $(XML_REF3_FILES) \
- $(GEN_XML) $(XML_PART_FILES) $(XML_CHAPTER_FILES)
+ $(XML_PART_FILES) $(XML_CHAPTER_FILES)
+
+XML_GEN_FILES = $(GEN_XML:%=$(XMLDIR)/%)
GIF_FILES = \
exclusive_Win_But.gif \
@@ -75,7 +76,8 @@ EXTRA_FILES = \
$(DEFAULT_HTML_FILES) \
$(ASN1_FILES) \
$(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html) \
- $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html)
+ $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html) \
+ $(GEN_XML:%.xml=$(HTMLDIR)/%.html) \
MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
@@ -105,6 +107,7 @@ html: gifs $(HTML_REF_MAN_FILE)
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f $(GEN_XML) errs core *~
diff --git a/lib/asn1/doc/src/asn1ct.xml b/lib/asn1/doc/src/asn1ct.xml
index ccf07a9cc1..e86dbd9f5e 100644
--- a/lib/asn1/doc/src/asn1ct.xml
+++ b/lib/asn1/doc/src/asn1ct.xml
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>asn1.sgml</file>
</header>
- <module>asn1ct</module>
+ <module since="">asn1ct</module>
<modulesummary>ASN.1 compiler and compile-time support functions</modulesummary>
<description>
<p>The ASN.1 compiler takes an ASN.1 module as input and generates a
@@ -72,8 +72,8 @@
<funcs>
<func>
- <name>compile(Asn1module) -> ok | {error, Reason}</name>
- <name>compile(Asn1module, Options) -> ok | {error, Reason}</name>
+ <name since="">compile(Asn1module) -> ok | {error, Reason}</name>
+ <name since="">compile(Asn1module, Options) -> ok | {error, Reason}</name>
<fsummary>Compiles an ASN.1 module and generates encode/decode functions according to encoding rules BER or PER.</fsummary>
<type>
<v>Asn1module = atom() | string()</v>
@@ -336,7 +336,7 @@ File3.asn</pre>
</func>
<func>
- <name>value(Module, Type) -> {ok, Value} | {error, Reason}</name>
+ <name since="">value(Module, Type) -> {ok, Value} | {error, Reason}</name>
<fsummary>Creates an ASN.1 value for test purposes.</fsummary>
<type>
<v>Module = Type = atom()</v>
@@ -361,9 +361,9 @@ File3.asn</pre>
</func>
<func>
- <name>test(Module) -> ok | {error, Reason}</name>
- <name>test(Module, Type | Options) -> ok | {error, Reason}</name>
- <name>test(Module, Type, Value | Options) -> ok | {error, Reason}</name>
+ <name since="">test(Module) -> ok | {error, Reason}</name>
+ <name since="">test(Module, Type | Options) -> ok | {error, Reason}</name>
+ <name since="">test(Module, Type, Value | Options) -> ok | {error, Reason}</name>
<fsummary>Performs a test of encode and decode for types in an ASN.1 module.</fsummary>
<type>
<v>Module = Type = atom()</v>
diff --git a/lib/asn1/doc/src/notes.xml b/lib/asn1/doc/src/notes.xml
index bb15c9ff5f..284a2b4ce5 100644
--- a/lib/asn1/doc/src/notes.xml
+++ b/lib/asn1/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,6 +32,123 @@
<p>This document describes the changes made to the asn1 application.</p>
+<section><title>Asn1 5.0.9</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ All incorrect (that is, all) uses of "can not" has been
+ corrected to "cannot" in source code comments,
+ documentation, examples, and so on.</p>
+ <p>
+ Own Id: OTP-14282 Aux Id: PR-1891 </p>
+ </item>
+ <item>
+ <p>Corrected problems with the following value
+ definitions:</p> <list> <item>value of SEQUENCE OF CHOICE
+ with extensions</item> <item>value of CHOICE with
+ extensions</item> <item>DEFAULT used with OCTET
+ STRING</item> </list>
+ <p>
+ Own Id: OTP-15697 Aux Id: PR-2159 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Asn1 5.0.8</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Handle erroneous length during decode (BER only) without
+ crashing.</p>
+ <p>
+ Own Id: OTP-15470 Aux Id: ERIERL-278 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Asn1 5.0.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>A bug in ASN.1 BER decoding has been fixed. When
+ decoding a recursively enclosed term the length was not
+ propagated to that term decoding, so if the length of the
+ enclosed term was longer than the enclosing that error
+ was not detected.</p> <p>A hard coded C stack limitation
+ for decoding recursive ASN.1 terms has been introduced.
+ This is currently set to 8 kWords giving a nesting depth
+ of about 1000 levels. Deeper terms can not be decoded,
+ which should not be much of a real world limitation.</p>
+ <p>
+ Own Id: OTP-14440 Aux Id: ERIERL-220 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Asn1 5.0.6</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Update to use the new string api instead of the old.</p>
+ <p>
+ Own Id: OTP-15036</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Asn1 5.0.5.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Handle erroneous length during decode (BER only) without
+ crashing.</p>
+ <p>
+ Own Id: OTP-15470 Aux Id: ERIERL-278 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Asn1 5.0.5.1</title>
+
+ <section><title>Known Bugs and Problems</title>
+ <list>
+ <item>
+ <p>A bug in ASN.1 BER decoding has been fixed. When
+ decoding a recursively enclosed term the length was not
+ propagated to that term decoding, so if the length of the
+ enclosed term was longer than the enclosing that error
+ was not dectected</p> <p>A hard coded C stack limitation
+ for decoding recursive ASN.1 terms has been introduced.
+ This is currently set to 8 kWords giving a nesting depth
+ of about 1000 levels. Deeper terms can not be decoded,
+ which should not be much of a real world limitation.</p>
+ <p>
+ Own Id: OTP-14440 Aux Id: ERIERL-220 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Asn1 5.0.5</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -1921,4 +2038,3 @@
<!-- p>There are also release notes for <url href="notes_history.html">older versions</url>.</p -->
</section>
</chapter>
-
diff --git a/lib/asn1/src/asn1ct.erl b/lib/asn1/src/asn1ct.erl
index 81a2735a0d..cd50d30aa8 100644
--- a/lib/asn1/src/asn1ct.erl
+++ b/lib/asn1/src/asn1ct.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -292,8 +292,7 @@ run_passes_1([{pass,Name,Pass}|Passes], #st{run=Run}=St0)
done ->
ok
catch
- Class:Error ->
- Stk = erlang:get_stacktrace(),
+ Class:Error:Stk ->
io:format("Internal error: ~p:~p\n~p\n",
[Class,Error,Stk]),
{error,{internal_error,{Class,Error}}}
@@ -2390,13 +2389,13 @@ in_process(Fun) ->
receive
{Pid, Result} -> Result;
{Pid, Class, Reason, Stack} ->
- ST = try throw(x) catch throw:x -> erlang:get_stacktrace() end,
+ ST = try throw(x) catch throw:x:Stk -> Stk end,
erlang:raise(Class, Reason, Stack ++ ST)
end.
process(Parent, Fun) ->
try
Parent ! {self(), Fun()}
- catch Class:Reason ->
- Parent ! {self(), Class, Reason, erlang:get_stacktrace()}
+ catch Class:Reason:Stack ->
+ Parent ! {self(), Class, Reason, Stack}
end.
diff --git a/lib/asn1/src/asn1ct_check.erl b/lib/asn1/src/asn1ct_check.erl
index 83d12600b7..9eec05abd1 100644
--- a/lib/asn1/src/asn1ct_check.erl
+++ b/lib/asn1/src/asn1ct_check.erl
@@ -1576,13 +1576,15 @@ printable_string_1(#'Externalvaluereference'{value=Type}) ->
printable_string_1({Atom,Line}) when is_atom(Atom), is_integer(Line) ->
q(Atom);
printable_string_1({object,definedsyntax,L}) ->
- q(string:join([printable_string_1(Item) || Item <- L], " "));
+ Str = lists:join($\s, [printable_string_1(Item) || Item <- L]),
+ q(lists:flatten(Str));
printable_string_1([_|_]=Def) ->
case lists:all(fun is_integer/1, Def) of
true ->
lists:flatten(io_lib:format("~p", [Def]));
false ->
- q(string:join([printable_string_1(Item) || Item <- Def], " "))
+ Str = lists:join($\s, [printable_string_1(Item) || Item <- Def]),
+ q(lists:flatten(Str))
end;
printable_string_1(Def) ->
lists:flatten(io_lib:format("~p", [Def])).
@@ -1708,7 +1710,7 @@ check_value(S,#valuedef{pos=Pos,name=Name,type=Type,
{valueset,
check_type(S,#typedef{pos=Pos,name=Name,typespec=NewType},NewType)};
check_value(S, #valuedef{}=V) ->
- ?dbg("check_value, V: ~p~n",[V0]),
+ ?dbg("check_value, V: ~p~n",[V]),
case V of
#valuedef{checked=true} ->
V;
@@ -1719,7 +1721,8 @@ check_value(S, #valuedef{}=V) ->
check_valuedef(#state{recordtopname=TopName}=S0, V0) ->
#valuedef{name=Name,type=Vtype0,value=Value,module=ModName} = V0,
V = V0#valuedef{checked=true},
- Vtype = check_type(S0, #typedef{name=Name,typespec=Vtype0},Vtype0),
+ Vtype1 = expand_valuedef_type(Vtype0),
+ Vtype = check_type(S0, #typedef{name=Name,typespec=Vtype1},Vtype1),
Def = Vtype#type.def,
S1 = S0#state{tname=Def},
SVal = update_state(S1, ModName),
@@ -1765,6 +1768,27 @@ check_valuedef(#state{recordtopname=TopName}=S0, V0) ->
V#valuedef{value=normalize_value(SVal, Vtype, Value, TopName)}
end.
+expand_valuedef_type(#type{def=Seq}=Type)
+ when is_record(Seq,'SEQUENCE') ->
+ NewComponents = case Seq#'SEQUENCE'.components of
+ {R1,_Ext,R2} -> R1 ++ R2;
+ {Root,_Ext} -> Root;
+ Root -> take_only_rootset(Root)
+ end,
+ NewSeq = Seq#'SEQUENCE'{components = NewComponents},
+ Type#type{def=NewSeq};
+expand_valuedef_type(#type{def=Set}=Type)
+ when is_record(Set,'SET') ->
+ NewComponents = case Set#'SET'.components of
+ {R1,_Ext,R2} -> R1 ++ R2;
+ {Root,_Ext} -> Root;
+ Root -> take_only_rootset(Root)
+ end,
+ NewSet = Set#'SET'{components = NewComponents},
+ Type#type{def=NewSet};
+expand_valuedef_type(Type) ->
+ Type.
+
is_contextswitchtype(#typedef{name='EXTERNAL'})->
true;
is_contextswitchtype(#typedef{name='EMBEDDED PDV'}) ->
@@ -1996,7 +2020,8 @@ normalize_value(S, Type, {'DEFAULT',Value}, NameList) ->
{'ENUMERATED',CType,_} ->
normalize_enumerated(S,Value,CType);
{'CHOICE',CType,NewNameList} ->
- normalize_choice(S,Value,CType,NewNameList);
+ ChoiceComponents = get_choice_components(S, {'CHOICE',CType}),
+ normalize_choice(S,Value,ChoiceComponents,NewNameList);
{'SEQUENCE',CType,NewNameList} ->
normalize_sequence(S,Value,CType,NewNameList);
{'SEQUENCE OF',CType,NewNameList} ->
@@ -2138,6 +2163,9 @@ normalize_octetstring(S, Value) ->
_ ->
asn1_error(S, illegal_octet_string_value)
end;
+ Val when is_binary(Val) ->
+ %% constant default value
+ Val;
_ ->
asn1_error(S, illegal_octet_string_value)
end.
@@ -2749,8 +2777,9 @@ check_type(S=#state{recordtopname=TopName},Type,Ts) when is_record(Ts,type) ->
TempNewDef#newt{type={'SEQUENCE OF',check_sequenceof(S,Type,Components)},
tag=
merge_tags(Tag,?TAG_CONSTRUCTED(?N_SEQUENCE))};
- {'CHOICE',Components} ->
+ {'CHOICE',_} = Choice->
Ct = maybe_illicit_implicit_tag(S, choice, Tag),
+ Components = get_choice_components(S, Choice),
TempNewDef#newt{type={'CHOICE',check_choice(S,Type,Components)},tag=Ct};
Set when is_record(Set,'SET') ->
RecordName=
@@ -5768,7 +5797,7 @@ format_error({missing_ocft,Component}) ->
format_error(multiple_uniqs) ->
"implementation limitation: only one UNIQUE field is allowed in CLASS";
format_error({namelist_redefinition,Name}) ->
- io_lib:format("the name '~s' can not be redefined", [Name]);
+ io_lib:format("the name '~s' cannot be redefined", [Name]);
format_error({param_bad_type, Ref}) ->
io_lib:format("'~p' is not a parameterized type", [Ref]);
format_error(param_wrong_number_of_arguments) ->
diff --git a/lib/asn1/src/asn1ct_gen.erl b/lib/asn1/src/asn1ct_gen.erl
index da9f6ac559..28836ff264 100644
--- a/lib/asn1/src/asn1ct_gen.erl
+++ b/lib/asn1/src/asn1ct_gen.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -811,12 +811,11 @@ result_line(NoOkWrapper, Items) ->
result_line_1([SingleItem]) ->
SingleItem;
result_line_1(Items) ->
- ["{",string:join(Items, ","),"}"].
+ ["{",lists:join(",",Items),"}"].
try_catch() ->
[" catch",nl,
- " Class:Exception when Class =:= error; Class =:= exit ->",nl,
- " Stk = erlang:get_stacktrace(),",nl,
+ " Class:Exception:Stk when Class =:= error; Class =:= exit ->",nl,
" case Exception of",nl,
" {error,{asn1,Reason}} ->",nl,
" {error,{asn1,{Reason,Stk}}};",nl,
@@ -958,7 +957,7 @@ open_hrl(OutFile,Module) ->
hrl_protector(OutFile) ->
BaseName = filename:basename(OutFile),
- P = "_" ++ string:to_upper(BaseName) ++ "_HRL_",
+ P = "_" ++ string:uppercase(BaseName) ++ "_HRL_",
[if
$A =< C, C =< $Z -> C;
$a =< C, C =< $a -> C;
diff --git a/lib/asn1/src/asn1rtt_real_common.erl b/lib/asn1/src/asn1rtt_real_common.erl
index 3a79209015..0d53447eb7 100644
--- a/lib/asn1/src/asn1rtt_real_common.erl
+++ b/lib/asn1/src/asn1rtt_real_common.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -125,7 +125,7 @@ encode_real(_C, {_,Base,_}) ->
encode_real(C, Real) when is_list(Real) ->
%% The Real string may come in as a NR1, NR2 or NR3 string.
{Mantissa, Exponent} =
- case string:tokens(Real,"Ee") of
+ case string:lexemes(Real,"Ee") of
[NR2] ->
{NR2,0};
[NR3MB,NR3E] ->
@@ -144,7 +144,7 @@ encode_real(C, Real) when is_list(Real) ->
NewMan = remove_trailing_zeros(Dec),
{NewMan,length(ZeroDecimal(NewMan))};
_ ->
- case string:tokens(Mantissa,",.") of
+ case string:lexemes(Mantissa,",.") of
[Num] -> %% No decimal-mark
{integer_to_list(list_to_integer(Num)),0};
[Num,Dec] ->
diff --git a/lib/asn1/test/Makefile b/lib/asn1/test/Makefile
index c38d1c6ebd..6ff4aa8d0f 100644
--- a/lib/asn1/test/Makefile
+++ b/lib/asn1/test/Makefile
@@ -60,6 +60,7 @@ MODULES= \
testSeqOf \
testSeqOfIndefinite \
testSeqOfCho \
+ testSeqOfChoExt \
testSeqOfExternal \
testSeqOfTag \
testSetDefault \
@@ -72,6 +73,7 @@ MODULES= \
testSetTypeRefPrim \
testSetTypeRefSeq \
testSetTypeRefSet \
+ testDefaultOctetString \
testChoiceIndefinite \
testSetOf \
testSetOfCho \
diff --git a/lib/asn1/test/asn1_SUITE.erl b/lib/asn1/test/asn1_SUITE.erl
index bfeffa969f..a88e464996 100644
--- a/lib/asn1/test/asn1_SUITE.erl
+++ b/lib/asn1/test/asn1_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -63,7 +63,8 @@ groups() ->
constraint_equivalence]},
{ber, Parallel,
- [ber_choiceinseq,
+ [ber_decode_invalid_length,
+ ber_choiceinseq,
% Uses 'SOpttest'
ber_optional,
tagdefault_automatic]},
@@ -98,6 +99,7 @@ groups() ->
testChoTypeRefPrim,
testChoTypeRefSeq,
testChoTypeRefSet,
+ testDefaultOctetString,
testMultipleLevels,
testOpt,
testSeqDefault,
@@ -117,6 +119,7 @@ groups() ->
{group, [], [testSeqOf,
testSeqOfIndefinite]}, % Uses 'Mvrasn*'
testSeqOfCho,
+ testSeqOfChoExt,
testSetDefault,
testExtensionAdditionGroup,
testSetOptional,
@@ -132,7 +135,8 @@ groups() ->
testSeq2738,
% Uses 'Constructed'
{group, [], [constructed,
- ber_decode_error]},
+ ber_decode_error,
+ otp_14440]},
testSeqSetIndefinite,
testChoiceIndefinite,
per_open_type,
@@ -227,10 +231,9 @@ test(Config, TestF, Rules) ->
try
TestF(C, R, O)
catch
- Class:Reason ->
+ Class:Reason:Stk ->
NewReason = {Reason, [{rule, R}, {options, O}]},
- erlang:raise(Class, NewReason,
- erlang:get_stacktrace())
+ erlang:raise(Class, NewReason, Stk)
end
end,
Result = [run_case(Config, Fun, rule(Rule), opts(Rule)) || Rule <- Rules],
@@ -429,6 +432,11 @@ testChoTypeRefSet(Config, Rule, Opts) ->
asn1_test_lib:compile("ChoTypeRefSet", Config, [Rule|Opts]),
testChoTypeRefSet:set(Rule).
+testDefaultOctetString(Config) -> test(Config, fun testDefaultOctetString/3).
+testDefaultOctetString(Config, Rule, Opts) ->
+ asn1_test_lib:compile("DefaultOctetString", Config, [Rule|Opts]),
+ testDefaultOctetString:dos(Rule).
+
testMultipleLevels(Config) -> test(Config, fun testMultipleLevels/3).
testMultipleLevels(Config, Rule, Opts) ->
asn1_test_lib:compile("MultipleLevels", Config, [Rule|Opts]),
@@ -534,6 +542,11 @@ testSeqOfCho(Config, Rule, Opts) ->
asn1_test_lib:compile("SeqOfCho", Config, [Rule|Opts]),
testSeqOfCho:main(Rule).
+testSeqOfChoExt(Config) -> test(Config, fun testSeqOfChoExt/3).
+testSeqOfChoExt(Config, Rule, Opts) ->
+ asn1_test_lib:compile("SeqOfChoExt", Config, [Rule|Opts]),
+ testSeqOfChoExt:main(Rule).
+
testSeqOfIndefinite(Config) ->
test(Config, fun testSeqOfIndefinite/3, [ber]).
testSeqOfIndefinite(Config, Rule, Opts) ->
@@ -665,6 +678,19 @@ module_test(M0, Config, Rule, Opts) ->
end
end.
+ber_decode_invalid_length(_Config) ->
+ Bin = <<48,129,157,48,0,2,1,2,164,0,48,129,154,49,24,48,22,6,
+ 3,85,4,10,19,15,69,120,97,109,112,108,101,32,67,111,
+ 109,112,97,110,121,49,29,48,27,6,9,42,134,72,134,247,
+ 13,1,9,1,22,14,99,97,64,101,120,97,109,112,108,101,46,
+ 99,111,109,49,13,48,11,6,3,85,4,7,19,4,79,117,108,117,
+ 49,26,48,24,6,3,85,4,8,19,17,80,111,104,106,111,105,
+ 115,45,80,111,104,106,97,110,109,97,97,49,11,48,9,6,3,
+ 85,4,6,19,2,70,73,49,19,48,17,6,3,85,4,3,19,10,69,120,
+ 97,109,112,108,101,32,67,65,49,11,48,16,6,3,85,4,11,
+ 19,9,84,101>>,
+ {'EXIT',{error,{asn1,{invalid_value,12}}}} = (catch asn1rt_nif:decode_ber_tlv(Bin)),
+ ok.
ber_choiceinseq(Config) ->
test(Config, fun ber_choiceinseq/3, [ber]).
@@ -737,6 +763,36 @@ ber_decode_error(Config, Rule, Opts) ->
asn1_test_lib:compile("Constructed", Config, [Rule|Opts]),
ber_decode_error:run(Opts).
+otp_14440(_Config) ->
+ Args = " -pa \"" ++ filename:dirname(code:which(?MODULE)) ++ "\"",
+ {ok,N} = slave:start(hostname(), otp_14440, Args),
+ Result = rpc:call(N, ?MODULE, otp_14440_decode, []),
+ io:format("Decode result = ~p~n", [Result]),
+ case Result of
+ {exit,{error,{asn1,{invalid_value,5}}}} ->
+ ok = slave:stop(N);
+ %% We get this if stack depth limit kicks in:
+ {exit,{error,{asn1,{unknown,_}}}} ->
+ ok = slave:stop(N);
+ _ ->
+ _ = slave:stop(N),
+ ?t:fail(Result)
+ end.
+%%
+otp_14440_decode() ->
+ Data =
+ iolist_to_binary(
+ lists:duplicate(
+ 32, list_to_binary(lists:duplicate(1024, 16#7f)))),
+ try asn1rt_nif:decode_ber_tlv(Data) of
+ Result ->
+ {unexpected_return,Result}
+ catch
+ Class:Reason ->
+ {Class,Reason}
+ end.
+
+
h323test(Config) -> test(Config, fun h323test/3).
h323test(Config, Rule, Opts) ->
Files = ["H235-SECURITY-MESSAGES", "H323-MESSAGES",
@@ -1351,7 +1407,7 @@ xref_export_all(_Config) ->
{ok,_} = xref:q(S, Def),
{ok,Unused} = xref:q(S, "X - Called - range (closure E | Called)"),
xref:stop(S),
- case Unused of
+ case Unused -- [{?MODULE,otp_14440_decode,0}] of
[] ->
ok;
[_|_] ->
@@ -1386,3 +1442,11 @@ all_called_1([F|T]) when is_atom(F) ->
L ++ all_called_1(T);
all_called_1([]) ->
[].
+
+hostname() ->
+ hostname(atom_to_list(node())).
+
+hostname([$@ | Hostname]) ->
+ list_to_atom(Hostname);
+hostname([_C | Cs]) ->
+ hostname(Cs).
diff --git a/lib/asn1/test/asn1_SUITE_data/ChoExtension.asn1 b/lib/asn1/test/asn1_SUITE_data/ChoExtension.asn1
index 18473bae30..c488704196 100644
--- a/lib/asn1/test/asn1_SUITE_data/ChoExtension.asn1
+++ b/lib/asn1/test/asn1_SUITE_data/ChoExtension.asn1
@@ -41,4 +41,6 @@ ChoExt4 ::= CHOICE
str OCTET STRING
}
+choExt1 ChoExt1 ::= int : 1
+
END
diff --git a/lib/asn1/test/asn1_SUITE_data/DefaultOctetString.asn b/lib/asn1/test/asn1_SUITE_data/DefaultOctetString.asn
new file mode 100644
index 0000000000..076e965d58
--- /dev/null
+++ b/lib/asn1/test/asn1_SUITE_data/DefaultOctetString.asn
@@ -0,0 +1,15 @@
+DefaultOctetString
+DEFINITIONS
+AUTOMATIC TAGS
+ ::=
+BEGIN
+Dos ::= SEQUENCE {
+ opt [2] OCTET STRING (SIZE(2..4)) OPTIONAL,
+ def [10] OCTET STRING (SIZE (1)) DEFAULT '05'H
+}
+
+dos Dos ::= {
+ opt '1234'H
+}
+
+END
diff --git a/lib/asn1/test/asn1_SUITE_data/IN-CS-1-Datatypes.asn b/lib/asn1/test/asn1_SUITE_data/IN-CS-1-Datatypes.asn
index ff0361f5c5..fb092f3f9c 100644
--- a/lib/asn1/test/asn1_SUITE_data/IN-CS-1-Datatypes.asn
+++ b/lib/asn1/test/asn1_SUITE_data/IN-CS-1-Datatypes.asn
@@ -1152,7 +1152,7 @@ FilteringCriteria ::= CHOICE {
-- In case calledAddressValue is specified, the numbers to be filtered are from calledAddressValue
-- up to and including calledAddressValue + maximumNumberOfCounters-1.
--- The last two digits of calledAddressvalue can not exceed 100-maximumNumberOfCounters.
+-- The last two digits of calledAddressvalue cannot exceed 100-maximumNumberOfCounters.
FilteringTimeOut ::= CHOICE {
duration [0] Duration,
stopTime [1] DateAndTime
diff --git a/lib/asn1/test/asn1_SUITE_data/SeqOfChoExt.asn1 b/lib/asn1/test/asn1_SUITE_data/SeqOfChoExt.asn1
new file mode 100644
index 0000000000..51077754fd
--- /dev/null
+++ b/lib/asn1/test/asn1_SUITE_data/SeqOfChoExt.asn1
@@ -0,0 +1,27 @@
+SeqOfChoExt DEFINITIONS AUTOMATIC TAGS EXTENSIBILITY IMPLIED ::=
+BEGIN
+
+Seq2 ::= SEQUENCE {
+ octstr [PRIVATE 6] OCTET STRING OPTIONAL
+}
+
+SeqOfCho ::= SEQUENCE OF CHOICE {
+ nullable NULL,
+ seq2 Seq2
+}
+
+Seq1 ::= SEQUENCE {
+ int INTEGER,
+ soc SeqOfCho
+}
+
+seq1 Seq1 ::= {
+ int 10,
+ soc {
+ seq2 : {
+ octstr '01020A'H
+ }
+ }
+}
+
+END
diff --git a/lib/asn1/test/testChoExtension.erl b/lib/asn1/test/testChoExtension.erl
index 4c632aab81..cfb28be5c7 100644
--- a/lib/asn1/test/testChoExtension.erl
+++ b/lib/asn1/test/testChoExtension.erl
@@ -28,6 +28,7 @@
extension(_Rules) ->
roundtrip('ChoExt1', {bool,true}),
roundtrip('ChoExt1', {int,33}),
+ {int, 1} = 'ChoExtension':choExt1(),
%% A trick to encode with another compatible CHOICE type to test reception
%% extension alternative
diff --git a/lib/asn1/test/testDefaultOctetString.erl b/lib/asn1/test/testDefaultOctetString.erl
new file mode 100644
index 0000000000..82cd5810e5
--- /dev/null
+++ b/lib/asn1/test/testDefaultOctetString.erl
@@ -0,0 +1,34 @@
+-module(testDefaultOctetString).
+
+-export([dos/1]).
+
+-include_lib("common_test/include/ct.hrl").
+
+-record('Dos', {
+ opt = asn1_NOVALUE,
+ def = asn1_DEFAULT
+}).
+
+-define(def_DEFAULT, <<5>>).
+
+dos(Rules) ->
+ %% test roundtrip default
+ E1 = roundtrip(#'Dos'{}, #'Dos'{def = ?def_DEFAULT}),
+ %% test the value dos defined in the .asn file
+ E2 = roundtrip('DefaultOctetString':dos()),
+ %% sanity test a fully specified SEQUENCE
+ E3 = roundtrip(#'Dos'{opt = <<1,2,3>>, def = <<6>>}),
+ %% test def is/isn't encoded according to the value
+ if Rules == ber ->
+ <<48, 0>> = E1,
+ <<48, 4, 16#82, 2, 16#12, 16#34>> = E2,
+ <<48, 8, 16#82, 3, 1, 2, 3, 16#8A, 1, 6>> = E3;
+ true ->
+ ignore
+ end,
+ ok.
+
+roundtrip(Value) ->
+ roundtrip(Value, Value).
+roundtrip(Value, Exp) ->
+ asn1_test_lib:roundtrip('DefaultOctetString', 'Dos', Value, Exp).
diff --git a/lib/asn1/test/testSeqOfChoExt.erl b/lib/asn1/test/testSeqOfChoExt.erl
new file mode 100644
index 0000000000..1e72c60841
--- /dev/null
+++ b/lib/asn1/test/testSeqOfChoExt.erl
@@ -0,0 +1,15 @@
+-module(testSeqOfChoExt).
+
+-export([main/1]).
+
+%-record('Seq2', { octstr = asn1_NOVALUE }).
+%-record('Seq1', { int, soc }).
+
+main(_Rules) ->
+ roundtrip('SeqOfChoExt':seq1()).
+
+roundtrip(Value) ->
+ roundtrip(Value, Value).
+roundtrip(Value, Exp) ->
+ Type = element(1,Value),
+ asn1_test_lib:roundtrip('SeqOfChoExt', Type, Value, Exp).
diff --git a/lib/asn1/test/testUniqueObjectSets.erl b/lib/asn1/test/testUniqueObjectSets.erl
index cabdb44a0c..0c61da96a1 100644
--- a/lib/asn1/test/testUniqueObjectSets.erl
+++ b/lib/asn1/test/testUniqueObjectSets.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2014-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2014-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -30,8 +30,7 @@ seq_roundtrip(I, D0) ->
asn1_test_lib:map_roundtrip(M, 'Seq', Enc),
{ok,{'Seq',I,D}} = M:decode('Seq', Enc),
D
- catch C:E ->
- Stk = erlang:get_stacktrace(),
+ catch C:E:Stk ->
io:format("FAILED: ~p ~p\n", [I,D0]),
erlang:raise(C, E, Stk)
end.
diff --git a/lib/asn1/test/test_modified_x420.erl b/lib/asn1/test/test_modified_x420.erl
index 15f7c70978..a4b335026d 100644
--- a/lib/asn1/test/test_modified_x420.erl
+++ b/lib/asn1/test/test_modified_x420.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/asn1/vsn.mk b/lib/asn1/vsn.mk
index 39dfe8f4fb..018beda307 100644
--- a/lib/asn1/vsn.mk
+++ b/lib/asn1/vsn.mk
@@ -1 +1 @@
-ASN1_VSN = 5.0.5
+ASN1_VSN = 5.0.9
diff --git a/lib/common_test/doc/src/Makefile b/lib/common_test/doc/src/Makefile
index 293ef591cb..b5acdc6f95 100644
--- a/lib/common_test/doc/src/Makefile
+++ b/lib/common_test/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2003-2017. All Rights Reserved.
+# Copyright Ericsson AB 2003-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -140,6 +140,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN1DIR)/*
rm -f $(MAN3DIR)/*
rm -f $(MAN6DIR)/*
diff --git a/lib/common_test/doc/src/basics_chapter.xml b/lib/common_test/doc/src/basics_chapter.xml
index 95599ca1f1..899a52fa31 100644
--- a/lib/common_test/doc/src/basics_chapter.xml
+++ b/lib/common_test/doc/src/basics_chapter.xml
@@ -125,7 +125,7 @@
The test case is the smallest unit that the <c>Common Test</c> test server deals with.
</p>
<p>
- Subsets of test cases, called test case groups, can also be defined. A test case
+ Sets of test cases, called test case groups, can also be defined. A test case
group can have execution properties associated with it. Execution properties
specify if the test cases in the group are to be executed in
random order, in parallel, or in sequence, and if the execution of the group
diff --git a/lib/common_test/doc/src/common_test_app.xml b/lib/common_test/doc/src/common_test_app.xml
index a3b3f927eb..081adeaec7 100644
--- a/lib/common_test/doc/src/common_test_app.xml
+++ b/lib/common_test/doc/src/common_test_app.xml
@@ -32,7 +32,7 @@
<rev>PA1</rev>
<file>common_test_app.sgml</file>
</header>
- <module>common_test</module>
+ <module since="">common_test</module>
<modulesummary>A framework for automated testing of any target nodes.</modulesummary>
<description>
@@ -68,18 +68,19 @@
<funcs>
<func>
- <name>Module:all() -> Tests | {skip,Reason} </name>
+ <name since="">Module:all() -> Tests | {skip,Reason} </name>
<fsummary>Returns the list of all test case groups and test cases
in the module.</fsummary>
<type>
- <v>Tests = [TestCase | {group,GroupName} | {group,GroupName,Properties} | {group,GroupName,Properties,SubGroups}]</v>
+ <v>Tests = [TestCase | {testcase,TestCase,TCRepeatProps} | {group,GroupName} | {group,GroupName,Properties} | {group,GroupName,Properties,SubGroups}]</v>
<v>TestCase = atom()</v>
+ <v>TCRepeatProps = [{repeat,N} | {repeat_until_ok,N} | {repeat_until_fail,N}]</v>
<v>GroupName = atom()</v>
- <v>Properties = [parallel | sequence | Shuffle | {RepeatType,N}] | default</v>
+ <v>Properties = [parallel | sequence | Shuffle | {GroupRepeatType,N}] | default</v>
<v>SubGroups = [{GroupName,Properties} | {GroupName,Properties,SubGroups}]</v>
<v>Shuffle = shuffle | {shuffle,Seed}</v>
<v>Seed = {integer(),integer(),integer()}</v>
- <v>RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | repeat_until_any_ok | repeat_until_any_fail</v>
+ <v>GroupRepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | repeat_until_any_ok | repeat_until_any_fail</v>
<v>N = integer() | forever</v>
<v>Reason = term()</v>
</type>
@@ -91,7 +92,8 @@
test suite module to be executed. This list also specifies the
order the cases and groups are executed by <c>Common Test</c>.
A test case is represented by an atom,
- the name of the test case function. A test case group is
+ the name of the test case function, or a <c>testcase</c> tuple
+ indicating that the test case shall be repeated. A test case group is
represented by a <c>group</c> tuple, where <c>GroupName</c>,
an atom, is the name of the group (defined in
<seealso marker="#Module:groups-0"><c>groups/0</c></seealso>).
@@ -115,18 +117,19 @@
</func>
<func>
- <name>Module:groups() -> GroupDefs</name>
+ <name since="">Module:groups() -> GroupDefs</name>
<fsummary>Returns a list of test case group definitions.</fsummary>
<type>
<v>GroupDefs = [Group]</v>
<v>Group = {GroupName,Properties,GroupsAndTestCases}</v>
<v>GroupName = atom()</v>
- <v>Properties = [parallel | sequence | Shuffle | {RepeatType,N}]</v>
- <v>GroupsAndTestCases = [Group | {group,GroupName} | TestCase]</v>
+ <v>Properties = [parallel | sequence | Shuffle | {GroupRepeatType,N}]</v>
+ <v>GroupsAndTestCases = [Group | {group,GroupName} | TestCase | {testcase,TestCase,TCRepeatProps}]</v>
<v>TestCase = atom()</v>
+ <v>TCRepeatProps = [{repeat,N} | {repeat_until_ok,N} | {repeat_until_fail,N}]</v>
<v>Shuffle = shuffle | {shuffle,Seed}</v>
<v>Seed = {integer(),integer(),integer()}</v>
- <v>RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | repeat_until_any_ok | repeat_until_any_fail</v>
+ <v>GroupRepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | repeat_until_any_ok | repeat_until_any_fail</v>
<v>N = integer() | forever</v>
</type>
@@ -140,7 +143,7 @@
</func>
<func>
- <name>Module:suite() -> [Info] </name>
+ <name since="">Module:suite() -> [Info] </name>
<fsummary>Test suite info function (providing default data
for the suite).</fsummary>
<type>
@@ -213,7 +216,7 @@
</func>
<func>
- <name>Module:init_per_suite(Config) -> NewConfig | {skip,Reason} |
+ <name since="">Module:init_per_suite(Config) -> NewConfig | {skip,Reason} |
{skip_and_save,Reason,SaveConfig}</name>
<fsummary>Test suite initializations.</fsummary>
<type>
@@ -248,7 +251,7 @@
</func>
<func>
- <name>Module:end_per_suite(Config) -> term() |
+ <name since="">Module:end_per_suite(Config) -> term() |
{save_config,SaveConfig}</name>
<fsummary>Test suite finalization.</fsummary>
<type>
@@ -272,7 +275,7 @@
</func>
<func>
- <name>Module:group(GroupName) -> [Info] </name>
+ <name since="OTP R15B">Module:group(GroupName) -> [Info] </name>
<fsummary>Test case group information function (providing default data
for a test case group, that is, its test cases and
subgroups).</fsummary>
@@ -352,7 +355,7 @@
</func>
<func>
- <name>Module:init_per_group(GroupName, Config) -> NewConfig |
+ <name since="">Module:init_per_group(GroupName, Config) -> NewConfig |
{skip,Reason}</name>
<fsummary>Test case group initializations.</fsummary>
<type>
@@ -390,7 +393,7 @@
</func>
<func>
- <name>Module:end_per_group(GroupName, Config) -> term() |
+ <name since="">Module:end_per_group(GroupName, Config) -> term() |
{return_group_result,Status}</name>
<fsummary>Test case group finalization.</fsummary>
<type>
@@ -424,7 +427,7 @@
</func>
<func>
- <name>Module:init_per_testcase(TestCase, Config) -> NewConfig | {fail,Reason} | {skip,Reason}</name>
+ <name since="">Module:init_per_testcase(TestCase, Config) -> NewConfig | {fail,Reason} | {skip,Reason}</name>
<fsummary>Test case initializations.</fsummary>
<type>
<v> TestCase = atom()</v>
@@ -454,7 +457,7 @@
</func>
<func>
- <name>Module:end_per_testcase(TestCase, Config) -> term() | {fail,Reason} | {save_config,SaveConfig}</name>
+ <name since="">Module:end_per_testcase(TestCase, Config) -> term() | {fail,Reason} | {save_config,SaveConfig}</name>
<fsummary>Test case finalization.</fsummary>
<type>
<v>TestCase = atom()</v>
@@ -486,7 +489,7 @@
</func>
<func>
- <name>Module:Testcase() -> [Info] </name>
+ <name since="OTP R14B">Module:Testcase() -> [Info] </name>
<fsummary>Test case information function.</fsummary>
<type>
<v>Info = {timetrap,Time} | {require,Required} | {require,Name,Required} | {userdata,UserData} | {silent_connections,Conns}</v>
@@ -560,7 +563,7 @@
</func>
<func>
- <name>Module:Testcase(Config) -> term() | {skip,Reason} | {comment,Comment} | {save_config,SaveConfig} | {skip_and_save,Reason,SaveConfig} | exit() </name>
+ <name since="OTP R14B">Module:Testcase(Config) -> term() | {skip,Reason} | {comment,Comment} | {save_config,SaveConfig} | {skip_and_save,Reason,SaveConfig} | exit() </name>
<fsummary>A test case.</fsummary>
<type>
<v>Config = SaveConfig = [{Key,Value}]</v>
diff --git a/lib/common_test/doc/src/ct.xml b/lib/common_test/doc/src/ct.xml
index afd8741cd1..83c0ecb309 100644
--- a/lib/common_test/doc/src/ct.xml
+++ b/lib/common_test/doc/src/ct.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2010</year><year>2017</year>
+ <year>2010</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>ct.xml</file>
</header>
- <module>ct</module>
+ <module since="">ct</module>
<modulesummary>Main user interface for the Common Test framework.</modulesummary>
<description>
@@ -139,7 +139,7 @@
<funcs>
<func>
- <name>abort_current_testcase(Reason) -&gt; ok | {error, ErrorReason}</name>
+ <name since="">abort_current_testcase(Reason) -&gt; ok | {error, ErrorReason}</name>
<fsummary>Aborts the currently executing test case.</fsummary>
<type>
<v>Reason = term()</v>
@@ -157,7 +157,7 @@
</func>
<func>
- <name>add_config(Callback, Config) -&gt; ok | {error, Reason}</name>
+ <name since="OTP R14B">add_config(Callback, Config) -&gt; ok | {error, Reason}</name>
<fsummary>Loads configuration variables using the specified callback
module and configuration string.</fsummary>
<type>
@@ -176,7 +176,7 @@
</func>
<func>
- <name>break(Comment) -&gt; ok | {error, Reason}</name>
+ <name since="OTP R15B02">break(Comment) -&gt; ok | {error, Reason}</name>
<fsummary>Cancels any active timetrap and pause the execution of the
current test case until the user calls function continue/0.</fsummary>
<type>
@@ -206,7 +206,7 @@
</func>
<func>
- <name>break(TestCase, Comment) -&gt; ok | {error, Reason}</name>
+ <name since="OTP R15B02">break(TestCase, Comment) -&gt; ok | {error, Reason}</name>
<fsummary>Works the same way as break/1, only argument TestCase makes it
possible to pause a test case executing in a parallel group.</fsummary>
<type>
@@ -228,7 +228,7 @@
</func>
<func>
- <name>capture_get() -&gt; ListOfStrings</name>
+ <name since="OTP R15B">capture_get() -&gt; ListOfStrings</name>
<fsummary>Equivalent to capture_get([default]).</fsummary>
<type>
<v>ListOfStrings = [string()]</v>
@@ -240,7 +240,7 @@
</func>
<func>
- <name>capture_get(ExclCategories) -&gt; ListOfStrings</name>
+ <name since="OTP R15B">capture_get(ExclCategories) -&gt; ListOfStrings</name>
<fsummary>Returns and purges the list of text strings buffered during
the latest session of capturing printouts to stdout.</fsummary>
<type>
@@ -262,7 +262,7 @@
</func>
<func>
- <name>capture_start() -&gt; ok</name>
+ <name since="OTP R15B">capture_start() -&gt; ok</name>
<fsummary>Starts capturing all text strings printed to stdout
during execution of the test case.</fsummary>
<desc><marker id="capture_start-0"/>
@@ -276,7 +276,7 @@
</func>
<func>
- <name>capture_stop() -&gt; ok</name>
+ <name since="OTP R15B">capture_stop() -&gt; ok</name>
<fsummary>Stops capturing text strings (a session started with
capture_start/0).</fsummary>
<desc><marker id="capture_stop-0"/>
@@ -290,7 +290,7 @@
</func>
<func>
- <name>comment(Comment) -&gt; ok</name>
+ <name since="">comment(Comment) -&gt; ok</name>
<fsummary>Prints the specified Comment in the comment field in the
table on the test suite result page.</fsummary>
<type>
@@ -307,7 +307,7 @@
</func>
<func>
- <name>comment(Format, Args) -&gt; ok</name>
+ <name since="OTP R15B">comment(Format, Args) -&gt; ok</name>
<fsummary>Prints the formatted string in the comment field in the
table on the test suite result page.</fsummary>
<type>
@@ -326,7 +326,7 @@
</func>
<func>
- <name>continue() -&gt; ok</name>
+ <name since="OTP R15B02">continue() -&gt; ok</name>
<fsummary>This function must be called to continue after a test
case (not executing in a parallel group) has called break/1.</fsummary>
<desc><marker id="continue-0"/>
@@ -337,7 +337,7 @@
</func>
<func>
- <name>continue(TestCase) -&gt; ok</name>
+ <name since="OTP R15B02">continue(TestCase) -&gt; ok</name>
<fsummary>This function must be called to continue after a test case
has called break/2.</fsummary>
<type>
@@ -353,7 +353,7 @@
</func>
<func>
- <name>decrypt_config_file(EncryptFileName, TargetFileName) -&gt; ok | {error, Reason}</name>
+ <name since="">decrypt_config_file(EncryptFileName, TargetFileName) -&gt; ok | {error, Reason}</name>
<fsummary>Decrypts EncryptFileName, previously generated with
encrypt_config_file/2,3.</fsummary>
<type>
@@ -372,7 +372,7 @@
</func>
<func>
- <name>decrypt_config_file(EncryptFileName, TargetFileName, KeyOrFile) -&gt; ok | {error, Reason}</name>
+ <name since="">decrypt_config_file(EncryptFileName, TargetFileName, KeyOrFile) -&gt; ok | {error, Reason}</name>
<fsummary>Decrypts EncryptFileName, previously generated with
encrypt_config_file/2,3.</fsummary>
<type>
@@ -390,7 +390,7 @@
</func>
<func>
- <name>encrypt_config_file(SrcFileName, EncryptFileName) -&gt; ok | {error, Reason}</name>
+ <name since="">encrypt_config_file(SrcFileName, EncryptFileName) -&gt; ok | {error, Reason}</name>
<fsummary>Encrypts the source configuration file with DES3 and saves the
result in file EncryptFileName.</fsummary>
<type>
@@ -416,7 +416,7 @@
</func>
<func>
- <name>encrypt_config_file(SrcFileName, EncryptFileName, KeyOrFile) -&gt; ok | {error, Reason}</name>
+ <name since="">encrypt_config_file(SrcFileName, EncryptFileName, KeyOrFile) -&gt; ok | {error, Reason}</name>
<fsummary>Encrypts the source configuration file with DES3 and saves the
result in the target file EncryptFileName.</fsummary>
<type>
@@ -442,7 +442,7 @@
</func>
<func>
- <name>fail(Reason) -&gt; ok</name>
+ <name since="">fail(Reason) -&gt; ok</name>
<fsummary>Terminates a test case with the specified error
Reason.</fsummary>
<type>
@@ -454,7 +454,7 @@
</func>
<func>
- <name>fail(Format, Args) -&gt; ok</name>
+ <name since="OTP R15B">fail(Format, Args) -&gt; ok</name>
<fsummary>Terminates a test case with an error message specified by
a format string and a list of values (used as arguments to
io_lib:format/2).</fsummary>
@@ -470,7 +470,7 @@
</func>
<func>
- <name>get_config(Required) -&gt; Value</name>
+ <name since="">get_config(Required) -&gt; Value</name>
<fsummary>Equivalent to get_config(Required, undefined, []).</fsummary>
<desc><marker id="get_config-1"/>
<p>Equivalent to <seealso marker="#get_config-3"><c>ct:get_config(Required,
@@ -479,7 +479,7 @@
</func>
<func>
- <name>get_config(Required, Default) -&gt; Value</name>
+ <name since="">get_config(Required, Default) -&gt; Value</name>
<fsummary>Equivalent to get_config(Required, Default, []).</fsummary>
<desc><marker id="get_config-2"/>
<p>Equivalent to <seealso marker="#get_config-3"><c>ct:get_config(Required,
@@ -488,7 +488,7 @@
</func>
<func>
- <name>get_config(Required, Default, Opts) -&gt; ValueOrElement</name>
+ <name since="">get_config(Required, Default, Opts) -&gt; ValueOrElement</name>
<fsummary>Reads configuration data values.</fsummary>
<type>
<v>Required = KeyOrName | {KeyOrName, SubKey} | {KeyOrName, SubKey, SubKey}</v>
@@ -554,7 +554,7 @@
</func>
<func>
- <name>get_event_mgr_ref() -&gt; EvMgrRef</name>
+ <name since="OTP 17.5">get_event_mgr_ref() -&gt; EvMgrRef</name>
<fsummary>Gets a reference to the <c>Common Test</c> event manager.</fsummary>
<type>
<v>EvMgrRef = atom()</v>
@@ -572,7 +572,17 @@
</func>
<func>
- <name>get_status() -&gt; TestStatus | {error, Reason} | no_tests_running</name>
+ <name since="OTP 21.0">get_progname() -&gt; string()</name>
+ <fsummary>Returns the command used to start this Erlang instance.</fsummary>
+ <desc><marker id="get_progname-0"/>
+ <p>Returns the command used to start this Erlang instance.
+ If this information could not be found, the string
+ <c>"no_prog_name"</c> is returned.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">get_status() -&gt; TestStatus | {error, Reason} | no_tests_running</name>
<fsummary>Returns status of ongoing test.</fsummary>
<type>
<v>TestStatus = [StatusElem]</v>
@@ -598,7 +608,7 @@
</func>
<func>
- <name>get_target_name(Handle) -&gt; {ok, TargetName} | {error, Reason}</name>
+ <name since="">get_target_name(Handle) -&gt; {ok, TargetName} | {error, Reason}</name>
<fsummary>Returns the name of the target that the specified connection
belongs to.</fsummary>
<type>
@@ -612,7 +622,7 @@
</func>
<func>
- <name>get_testspec_terms() -&gt; TestSpecTerms | undefined</name>
+ <name since="OTP 18.0">get_testspec_terms() -&gt; TestSpecTerms | undefined</name>
<fsummary>Gets a list of all test specification terms used to
configure and run this test.</fsummary>
<type>
@@ -626,7 +636,7 @@
</func>
<func>
- <name>get_testspec_terms(Tags) -&gt; TestSpecTerms | undefined</name>
+ <name since="OTP 18.0">get_testspec_terms(Tags) -&gt; TestSpecTerms | undefined</name>
<fsummary>Reads one or more terms from the test specification used to
configure and run this test.</fsummary>
<type>
@@ -653,7 +663,7 @@
</func>
<func>
- <name>get_timetrap_info() -&gt; {Time, {Scaling,ScaleVal}}</name>
+ <name since="OTP R15B">get_timetrap_info() -&gt; {Time, {Scaling,ScaleVal}}</name>
<fsummary>Reads information about the timetrap set for the current
test case.</fsummary>
<type>
@@ -672,7 +682,7 @@
</func>
<func>
- <name>get_verbosity(Category) -&gt; Level | undefined</name>
+ <name since="OTP 19.1">get_verbosity(Category) -&gt; Level | undefined</name>
<fsummary>Read the verbosity level for a logging category.</fsummary>
<type>
<v>Category = default | atom()</v>
@@ -687,7 +697,7 @@
</func>
<func>
- <name>install(Opts) -&gt; ok | {error, Reason}</name>
+ <name since="">install(Opts) -&gt; ok | {error, Reason}</name>
<fsummary>Installs configuration files and event handlers.</fsummary>
<type>
<v>Opts = [Opt]</v>
@@ -714,7 +724,7 @@
</func>
<func>
- <name>listenv(Telnet) -&gt; [Env]</name>
+ <name since="">listenv(Telnet) -&gt; [Env]</name>
<fsummary>Performs command listenv on the specified Telnet connection
and returns the result as a list of key-value pairs.</fsummary>
<type>
@@ -730,7 +740,7 @@
</func>
<func>
- <name>log(Format) -&gt; ok</name>
+ <name since="">log(Format) -&gt; ok</name>
<fsummary>Equivalent to log(default, 50, Format, [], []).</fsummary>
<desc><marker id="log-1"/>
<p>Equivalent to
@@ -739,7 +749,7 @@
</func>
<func>
- <name>log(X1, X2) -&gt; ok</name>
+ <name since="">log(X1, X2) -&gt; ok</name>
<fsummary>Equivalent to log(Category, Importance, Format,
FormatArgs, []).</fsummary>
<type>
@@ -753,7 +763,7 @@
</func>
<func>
- <name>log(X1, X2, X3) -&gt; ok</name>
+ <name since="">log(X1, X2, X3) -&gt; ok</name>
<fsummary>Equivalent to log(Category, Importance, Format,
FormatArgs, Opts).</fsummary>
<type>
@@ -768,7 +778,7 @@
</func>
<func>
- <name>log(X1, X2, X3, X4) -&gt; ok</name>
+ <name since="OTP R15B02">log(X1, X2, X3, X4) -&gt; ok</name>
<fsummary>Equivalent to log(Category, Importance, Format,
FormatArgs, Opts).</fsummary>
<type>
@@ -784,7 +794,7 @@
</func>
<func>
- <name>log(Category, Importance, Format, FormatArgs, Opts) -&gt; ok</name>
+ <name since="OTP 18.3">log(Category, Importance, Format, FormatArgs, Opts) -&gt; ok</name>
<fsummary>Prints from a test case to the log file.</fsummary>
<type>
<v>Category = atom()</v>
@@ -815,7 +825,7 @@
</func>
<func>
- <name>make_priv_dir() -&gt; ok | {error, Reason}</name>
+ <name since="OTP R15B01">make_priv_dir() -&gt; ok | {error, Reason}</name>
<fsummary>If the test has been started with option create_priv_dir
set to manual_per_tc, in order for the test case to use the private
directory, it must first create it by calling this function.</fsummary>
@@ -831,7 +841,7 @@
</func>
<func>
- <name>notify(Name, Data) -&gt; ok</name>
+ <name since="OTP R15B02">notify(Name, Data) -&gt; ok</name>
<fsummary>Sends an asynchronous notification of type Name with Data
to the <c>Common Test</c> event manager.</fsummary>
<type>
@@ -849,7 +859,7 @@
</func>
<func>
- <name>pal(Format) -&gt; ok</name>
+ <name since="">pal(Format) -&gt; ok</name>
<fsummary>Equivalent to pal(default, 50, Format, [], []).</fsummary>
<desc><marker id="pal-1"/>
<p>Equivalent to
@@ -859,7 +869,7 @@
</func>
<func>
- <name>pal(X1, X2) -&gt; ok</name>
+ <name since="">pal(X1, X2) -&gt; ok</name>
<fsummary>Equivalent to pal(Category, Importance, Format,
FormatArgs, []).</fsummary>
<type>
@@ -873,7 +883,7 @@
</func>
<func>
- <name>pal(X1, X2, X3) -&gt; ok</name>
+ <name since="">pal(X1, X2, X3) -&gt; ok</name>
<fsummary>Equivalent to pal(Category, Importance, Format,
FormatArgs, Opts).</fsummary>
<type>
@@ -888,7 +898,7 @@
</func>
<func>
- <name>pal(X1, X2, X3, X4) -&gt; ok</name>
+ <name since="OTP R15B02">pal(X1, X2, X3, X4) -&gt; ok</name>
<fsummary>Equivalent to pal(Category, Importance, Format,
FormatArgs, Opts).</fsummary>
<type>
@@ -904,7 +914,7 @@
</func>
<func>
- <name>pal(Category, Importance, Format, FormatArgs, Opts) -&gt; ok</name>
+ <name since="OTP 19.2">pal(Category, Importance, Format, FormatArgs, Opts) -&gt; ok</name>
<fsummary>Prints and logs from a test case.</fsummary>
<type>
<v>Category = atom()</v>
@@ -935,7 +945,7 @@
</func>
<func>
- <name>parse_table(Data) -&gt; {Heading, Table}</name>
+ <name since="">parse_table(Data) -&gt; {Heading, Table}</name>
<fsummary>Parses the printout from an SQL table and returns a list of
tuples.</fsummary>
<type>
@@ -957,7 +967,7 @@
</func>
<func>
- <name>print(Format) -&gt; ok</name>
+ <name since="">print(Format) -&gt; ok</name>
<fsummary>Equivalent to print(default, 50, Format, [], []).</fsummary>
<desc><marker id="print-1"/>
<p>Equivalent to <seealso marker="#print-5"><c>ct:print(default,
@@ -966,7 +976,7 @@
</func>
<func>
- <name>print(X1, X2) -&gt; ok</name>
+ <name since="OTP R15B02">print(X1, X2) -&gt; ok</name>
<fsummary>Equivalent to print(Category, Importance, Format,
FormatArgs, []).</fsummary>
<type>
@@ -980,7 +990,7 @@
</func>
<func>
- <name>print(X1, X2, X3) -&gt; ok</name>
+ <name since="">print(X1, X2, X3) -&gt; ok</name>
<fsummary>Equivalent to print(Category, Importance, Format,
FormatArgs, Opts).</fsummary>
<type>
@@ -995,7 +1005,7 @@
</func>
<func>
- <name>print(X1, X2, X3, X4) -&gt; ok</name>
+ <name since="OTP R15B02">print(X1, X2, X3, X4) -&gt; ok</name>
<fsummary>Equivalent to print(Category, Importance, Format,
FormatArgs, Opts).</fsummary>
<type>
@@ -1011,7 +1021,7 @@
</func>
<func>
- <name>print(Category, Importance, Format, FormatArgs, Opts) -&gt; ok</name>
+ <name since="OTP 19.2">print(Category, Importance, Format, FormatArgs, Opts) -&gt; ok</name>
<fsummary>Prints from a test case to the console.</fsummary>
<type>
<v>Category = atom()</v>
@@ -1038,7 +1048,7 @@
</func>
<func>
- <name>reload_config(Required) -&gt; ValueOrElement | {error, Reason}</name>
+ <name since="OTP R14B">reload_config(Required) -&gt; ValueOrElement | {error, Reason}</name>
<fsummary>Reloads configuration file containing specified configuration
key.</fsummary>
<type>
@@ -1061,7 +1071,7 @@
</func>
<func>
- <name>remaining_test_procs() -&gt; {TestProcs,SharedGL,OtherGLs}</name>
+ <name since="OTP 20.2">remaining_test_procs() -&gt; {TestProcs,SharedGL,OtherGLs}</name>
<fsummary>>This function will return the identity of test- and group
leader processes that are still running at the time of this call.</fsummary>
<type>
@@ -1097,7 +1107,7 @@
</func>
<func>
- <name>remove_config(Callback, Config) -&gt; ok</name>
+ <name since="OTP R14B">remove_config(Callback, Config) -&gt; ok</name>
<fsummary>Removes configuration variables (together with
their aliases) that were loaded with specified callback module and
configuration string.</fsummary>
@@ -1114,7 +1124,7 @@
</func>
<func>
- <name>require(Required) -&gt; ok | {error, Reason}</name>
+ <name since="">require(Required) -&gt; ok | {error, Reason}</name>
<fsummary>Checks if the required configuration is available.</fsummary>
<type>
<v>Required = Key | {Key, SubKeys} | {Key, SubKey, SubKeys}</v>
@@ -1168,7 +1178,7 @@
</func>
<func>
- <name>require(Name, Required) -&gt; ok | {error, Reason}</name>
+ <name since="">require(Name, Required) -&gt; ok | {error, Reason}</name>
<fsummary>Checks if the required configuration is available and gives
it a name.</fsummary>
<type>
@@ -1227,7 +1237,7 @@
</func>
<func>
- <name>run(TestDirs) -&gt; Result</name>
+ <name since="">run(TestDirs) -&gt; Result</name>
<fsummary>Runs all test cases in all suites in the specified
directories.</fsummary>
<type>
@@ -1241,7 +1251,7 @@
</func>
<func>
- <name>run(TestDir, Suite) -&gt; Result</name>
+ <name since="">run(TestDir, Suite) -&gt; Result</name>
<fsummary>Runs all test cases in the specified suite.</fsummary>
<desc><marker id="run-2"/>
<p>Runs all test cases in the specified suite.</p>
@@ -1251,7 +1261,7 @@
</func>
<func>
- <name>run(TestDir, Suite, Cases) -&gt; Result</name>
+ <name since="">run(TestDir, Suite, Cases) -&gt; Result</name>
<fsummary>Runs the specified test cases.</fsummary>
<type>
<v>TestDir = string()</v>
@@ -1273,7 +1283,7 @@
</func>
<func>
- <name>run_test(Opts) -&gt; Result</name>
+ <name since="">run_test(Opts) -&gt; Result</name>
<fsummary>Runs tests as specified by the combination of options in
Opts.</fsummary>
<type>
@@ -1345,7 +1355,7 @@
</func>
<func>
- <name>run_testspec(TestSpec) -&gt; Result</name>
+ <name since="">run_testspec(TestSpec) -&gt; Result</name>
<fsummary>Runs a test specified by TestSpec.</fsummary>
<type>
<v>TestSpec = [term()]</v>
@@ -1365,7 +1375,7 @@
</func>
<func>
- <name>set_verbosity(Category, Level) -&gt; ok</name>
+ <name since="OTP 19.1">set_verbosity(Category, Level) -&gt; ok</name>
<fsummary>Set the verbosity level for a logging category.</fsummary>
<type>
<v>Category = default | atom()</v>
@@ -1380,7 +1390,7 @@
</func>
<func>
- <name>sleep(Time) -&gt; ok</name>
+ <name since="OTP R14B">sleep(Time) -&gt; ok</name>
<fsummary>This function, similar to timer:sleep/1, suspends the
test case for a specified time.</fsummary>
<type>
@@ -1402,7 +1412,7 @@
</func>
<func>
- <name>start_interactive() -&gt; ok</name>
+ <name since="">start_interactive() -&gt; ok</name>
<fsummary>Starts <c>Common Test</c> in interactive mode.</fsummary>
<desc><marker id="start_interactive-0"/>
<p>Starts <c>Common Test</c> in interactive mode.</p>
@@ -1430,7 +1440,7 @@
</func>
<func>
- <name>step(TestDir, Suite, Case) -&gt; Result</name>
+ <name since="">step(TestDir, Suite, Case) -&gt; Result</name>
<fsummary>Steps through a test case with the debugger.</fsummary>
<type>
<v>Case = atom()</v>
@@ -1443,7 +1453,7 @@
</func>
<func>
- <name>step(TestDir, Suite, Case, Opts) -&gt; Result</name>
+ <name since="">step(TestDir, Suite, Case, Opts) -&gt; Result</name>
<fsummary>Steps through a test case with the debugger.</fsummary>
<type>
<v>Case = atom()</v>
@@ -1460,7 +1470,7 @@
</func>
<func>
- <name>stop_interactive() -&gt; ok</name>
+ <name since="">stop_interactive() -&gt; ok</name>
<fsummary>Exits the interactive mode.</fsummary>
<desc><marker id="stop_interactive-0"/>
<p>Exits the interactive mode.</p>
@@ -1472,7 +1482,7 @@
</func>
<func>
- <name>sync_notify(Name, Data) -&gt; ok</name>
+ <name since="OTP R15B02">sync_notify(Name, Data) -&gt; ok</name>
<fsummary>Sends a synchronous notification of type Name with Data to
the <c>Common Test</c> event manager.</fsummary>
<type>
@@ -1491,7 +1501,7 @@
</func>
<func>
- <name>testcases(TestDir, Suite) -&gt; Testcases | {error, Reason}</name>
+ <name since="">testcases(TestDir, Suite) -&gt; Testcases | {error, Reason}</name>
<fsummary>Returns all test cases in the specified suite.</fsummary>
<type>
<v>TestDir = string()</v>
@@ -1505,14 +1515,14 @@
</func>
<func>
- <name>timetrap(Time) -&gt; ok</name>
+ <name since="OTP R14B">timetrap(Time) -&gt; ok</name>
<fsummary>Sets a new timetrap for the running test case.</fsummary>
<type>
<v>Time = {hours, Hours} | {minutes, Mins} | {seconds, Secs} | Millisecs | infinity | Func</v>
<v>Hours = integer()</v>
<v>Mins = integer()</v>
<v>Secs = integer()</v>
- <v>Millisecs = integer() | float()</v>
+ <v>Millisecs = integer()</v>
<v>Func = {M, F, A} | function()</v>
<v>M = atom()</v>
<v>F = atom()</v>
@@ -1529,7 +1539,7 @@
</func>
<func>
- <name>userdata(TestDir, Suite) -&gt; SuiteUserData | {error, Reason}</name>
+ <name since="">userdata(TestDir, Suite) -&gt; SuiteUserData | {error, Reason}</name>
<fsummary>Returns any data specified with tag userdata in the list of
tuples returned from Suite:suite/0.</fsummary>
<type>
@@ -1546,7 +1556,7 @@
</func>
<func>
- <name>userdata(TestDir, Suite, Case::GroupOrCase) -&gt; TCUserData | {error, Reason}</name>
+ <name since="">userdata(TestDir, Suite, Case::GroupOrCase) -&gt; TCUserData | {error, Reason}</name>
<fsummary>Returns any data specified with tag userdata in the list of
tuples returned from Suite:group(GroupName) or Suite:Case().</fsummary>
<type>
diff --git a/lib/common_test/doc/src/ct_cover.xml b/lib/common_test/doc/src/ct_cover.xml
index 89d944acbe..61365d3522 100644
--- a/lib/common_test/doc/src/ct_cover.xml
+++ b/lib/common_test/doc/src/ct_cover.xml
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>ct_cover.xml</file>
</header>
- <module>ct_cover</module>
+ <module since="">ct_cover</module>
<modulesummary>Common Test framework code coverage support module.
</modulesummary>
@@ -47,7 +47,7 @@
<funcs>
<func>
- <name>add_nodes(Nodes) -&gt; {ok, StartedNodes} | {error, Reason}</name>
+ <name since="">add_nodes(Nodes) -&gt; {ok, StartedNodes} | {error, Reason}</name>
<fsummary>Adds nodes to current cover test (only works if cover support
is active).</fsummary>
<type>
@@ -67,7 +67,7 @@
</func>
<func>
- <name>cross_cover_analyse(Level, Tests) -&gt; ok</name>
+ <name since="OTP R16B">cross_cover_analyse(Level, Tests) -&gt; ok</name>
<fsummary>Accumulates cover results over multiple tests.</fsummary>
<type>
<v>Level = overview | details</v>
@@ -83,7 +83,7 @@
</func>
<func>
- <name>remove_nodes(Nodes) -&gt; ok | {error, Reason}</name>
+ <name since="">remove_nodes(Nodes) -&gt; ok | {error, Reason}</name>
<fsummary>Removes nodes from the current cover test.</fsummary>
<type>
<v>Nodes = [atom()]</v>
diff --git a/lib/common_test/doc/src/ct_ftp.xml b/lib/common_test/doc/src/ct_ftp.xml
index e8c6f72db7..7ee6049486 100644
--- a/lib/common_test/doc/src/ct_ftp.xml
+++ b/lib/common_test/doc/src/ct_ftp.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2010</year><year>2016</year>
+ <year>2010</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,14 +32,12 @@
<rev>A</rev>
<file>ct_ftp.xml</file>
</header>
- <module>ct_ftp</module>
- <modulesummary>FTP client module (based on the FTP support of the Inets
- application).</modulesummary>
+ <module since="">ct_ftp</module>
+ <modulesummary>FTP client module (based on the FTP application).</modulesummary>
<description>
- <p>FTP client module (based on the FTP support of the <c>Inets</c>
- application).</p>
+ <p>FTP client module (based on the <c>ftp</c> application).</p>
</description>
@@ -61,7 +59,7 @@
<funcs>
<func>
- <name>cd(Connection, Dir) -&gt; ok | {error, Reason}</name>
+ <name since="">cd(Connection, Dir) -&gt; ok | {error, Reason}</name>
<fsummary>Changes directory on remote host.</fsummary>
<type>
<v>Connection = connection()</v>
@@ -73,7 +71,7 @@
</func>
<func>
- <name>close(Connection) -&gt; ok | {error, Reason}</name>
+ <name since="">close(Connection) -&gt; ok | {error, Reason}</name>
<fsummary>Closes the FTP connection.</fsummary>
<type>
<v>Connection = connection()</v>
@@ -84,7 +82,7 @@
</func>
<func>
- <name>delete(Connection, File) -&gt; ok | {error, Reason}</name>
+ <name since="">delete(Connection, File) -&gt; ok | {error, Reason}</name>
<fsummary>Deletes a file on remote host.</fsummary>
<type>
<v>Connection = connection()</v>
@@ -96,7 +94,7 @@
</func>
<func>
- <name>get(KeyOrName, RemoteFile, LocalFile) -&gt; ok | {error, Reason}</name>
+ <name since="">get(KeyOrName, RemoteFile, LocalFile) -&gt; ok | {error, Reason}</name>
<fsummary>Opens an FTP connection and fetches a file from the remote
host.</fsummary>
<type>
@@ -124,7 +122,7 @@
</func>
<func>
- <name>ls(Connection, Dir) -&gt; {ok, Listing} | {error, Reason}</name>
+ <name since="">ls(Connection, Dir) -&gt; {ok, Listing} | {error, Reason}</name>
<fsummary>Lists directory Dir.</fsummary>
<type>
<v>Connection = connection()</v>
@@ -137,7 +135,7 @@
</func>
<func>
- <name>open(KeyOrName) -&gt; {ok, Handle} | {error, Reason}</name>
+ <name since="">open(KeyOrName) -&gt; {ok, Handle} | {error, Reason}</name>
<fsummary>Opens an FTP connection to the specified node.</fsummary>
<type>
<v>KeyOrName = Key | Name</v>
@@ -166,7 +164,7 @@
</func>
<func>
- <name>put(KeyOrName, LocalFile, RemoteFile) -&gt; ok | {error, Reason}</name>
+ <name since="">put(KeyOrName, LocalFile, RemoteFile) -&gt; ok | {error, Reason}</name>
<fsummary>Opens an FTP connection and sends a file to the remote
host.</fsummary>
<type>
@@ -205,7 +203,7 @@
</func>
<func>
- <name>recv(Connection, RemoteFile) -&gt; ok | {error, Reason}</name>
+ <name since="">recv(Connection, RemoteFile) -&gt; ok | {error, Reason}</name>
<fsummary>Fetches a file over FTP.</fsummary>
<desc><marker id="recv-2"/>
<p>Fetches a file over FTP.</p>
@@ -217,7 +215,7 @@
</func>
<func>
- <name>recv(Connection, RemoteFile, LocalFile) -&gt; ok | {error, Reason}</name>
+ <name since="">recv(Connection, RemoteFile, LocalFile) -&gt; ok | {error, Reason}</name>
<fsummary>Fetches a file over FTP.</fsummary>
<type>
<v>Connection = connection()</v>
@@ -232,7 +230,7 @@
</func>
<func>
- <name>send(Connection, LocalFile) -&gt; ok | {error, Reason}</name>
+ <name since="">send(Connection, LocalFile) -&gt; ok | {error, Reason}</name>
<fsummary>Sends a file over FTP.</fsummary>
<desc><marker id="send-2"/>
<p>Sends a file over FTP.</p>
@@ -245,7 +243,7 @@
</func>
<func>
- <name>send(Connection, LocalFile, RemoteFile) -&gt; ok | {error, Reason}</name>
+ <name since="">send(Connection, LocalFile, RemoteFile) -&gt; ok | {error, Reason}</name>
<fsummary>Sends a file over FTP.</fsummary>
<type>
<v>Connection = connection()</v>
@@ -260,7 +258,7 @@
</func>
<func>
- <name>type(Connection, Type) -&gt; ok | {error, Reason}</name>
+ <name since="">type(Connection, Type) -&gt; ok | {error, Reason}</name>
<fsummary>Changes the file transfer type.</fsummary>
<type>
<v>Connection = connection()</v>
diff --git a/lib/common_test/doc/src/ct_hooks.xml b/lib/common_test/doc/src/ct_hooks.xml
index 954be0ffba..100be85cac 100644
--- a/lib/common_test/doc/src/ct_hooks.xml
+++ b/lib/common_test/doc/src/ct_hooks.xml
@@ -32,7 +32,7 @@
<rev>PA1</rev>
<file>ct_hooks.sgml</file>
</header>
- <module>ct_hooks</module>
+ <module since="OTP R14B02">ct_hooks</module>
<modulesummary>A callback interface on top of Common Test.</modulesummary>
<description>
@@ -75,7 +75,7 @@
<funcs>
<func>
- <name>Module:init(Id, Opts) -&gt; {ok, State} | {ok, State, Priority}</name>
+ <name since="OTP R14B02">Module:init(Id, Opts) -&gt; {ok, State} | {ok, State, Priority}</name>
<fsummary>Initiates the Common Test Hook.</fsummary>
<type>
<v>Id = reference() | term()</v>
@@ -109,7 +109,132 @@
</func>
<func>
- <name>Module:pre_init_per_suite(SuiteName, InitData, CTHState) -&gt; Result</name>
+ <name since="OTP 21.3.8">Module:post_groups(SuiteName, GroupDefs) -&gt; NewGroupDefs</name>
+ <fsummary>Called after groups/0.</fsummary>
+ <type>
+ <v>SuiteName = atom()</v>
+ <v>GroupDefs = NewGroupDefs = [Group]</v>
+ <v>Group = {GroupName,Properties,GroupsAndTestCases}</v>
+ <v>GroupName = atom()</v>
+ <v>Properties = [parallel | sequence | Shuffle | {GroupRepeatType,N}]</v>
+ <v>GroupsAndTestCases = [Group | {group,GroupName} | TestCase | {testcase,TestCase,TCRepeatProps}]</v>
+ <v>TestCase = atom()</v>
+ <v>TCRepeatProps = [{repeat,N} | {repeat_until_ok,N} | {repeat_until_fail,N}]</v>
+ <v>Shuffle = shuffle | {shuffle,Seed}</v>
+ <v>Seed = {integer(),integer(),integer()}</v>
+ <v>GroupRepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | repeat_until_any_ok | repeat_until_any_fail</v>
+ <v>N = integer() | forever</v>
+ </type>
+ <desc>
+ <p>OPTIONAL</p>
+
+ <p>This function is called after
+ <seealso marker="common_test#Module:groups-0"><c>groups/0</c></seealso>.
+ It is used to modify the test group definitions, for
+ instance to add or remove groups or change group properties.</p>
+
+ <p><c>GroupDefs</c> is what
+ <seealso marker="common_test#Module:groups-0"><c>groups/0</c></seealso>
+ returned, that is, a list of group definitions.</p>
+
+ <p><c>NewGroupDefs</c> is the possibly modified version of this list.</p>
+
+ <p>This function is called only if the CTH is added before
+ <c>init_per_suite</c> is run. For details, see section
+ <seealso marker="ct_hooks_chapter#scope">CTH Scope</seealso>
+ in the User's Guide.</p>
+
+ <p>Notice that for CTHs that are installed by means of the
+ <seealso marker="common_test#Module:suite-0"><c>suite/0</c></seealso>
+ function, <c>post_groups/2</c> is called before
+ the <seealso marker="#Module:init-2"><c>init/2</c></seealso>
+ hook function. However, for CTHs that are installed by means
+ of the CT start flag,
+ the <seealso marker="#Module:init-2"><c>init/2</c></seealso>
+ function is called first.</p>
+
+ <note>
+ <p>Prior to each test execution, Common Test does a
+ simulated test run in order to count test suites, groups
+ and cases for logging purposes. This causes
+ the <c>post_groups/2</c> hook function to always be called
+ twice. For this reason, side effects are best avoided in
+ this callback.</p>
+ </note>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.3.8">Module:post_all(SuiteName, Return, GroupDefs) -&gt; NewReturn</name>
+ <fsummary>Called after all/0.</fsummary>
+ <type>
+ <v>SuiteName = atom()</v>
+ <v>Return = NewReturn = Tests | {skip,Reason}</v>
+ <v>Tests = [TestCase | {testcase,TestCase,TCRepeatProps} | {group,GroupName} | {group,GroupName,Properties} | {group,GroupName,Properties,SubGroups}]</v>
+ <v>TestCase = atom()</v>
+ <v>TCRepeatProps = [{repeat,N} | {repeat_until_ok,N} | {repeat_until_fail,N}]</v>
+ <v>GroupName = atom()</v>
+ <v>Properties = GroupProperties | default</v>
+ <v>SubGroups = [{GroupName,Properties} | {GroupName,Properties,SubGroups}]</v>
+ <v>Shuffle = shuffle | {shuffle,Seed}</v>
+ <v>Seed = {integer(),integer(),integer()}</v>
+ <v>GroupRepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | repeat_until_any_ok | repeat_until_any_fail</v>
+ <v>N = integer() | forever</v>
+ <v>GroupDefs = NewGroupDefs = [Group]</v>
+ <v>Group = {GroupName,GroupProperties,GroupsAndTestCases}</v>
+ <v>GroupProperties = [parallel | sequence | Shuffle | {GroupRepeatType,N}]</v>
+ <v>GroupsAndTestCases = [Group | {group,GroupName} | TestCase]</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>OPTIONAL</p>
+
+ <p>This function is called after
+ <seealso marker="common_test#Module:all-0"><c>all/0</c></seealso>.
+ It is used to modify the set of test cases and test group to
+ be executed, for instance to add or remove test cases and
+ groups, change group properties, or even skip all tests in
+ the suite.</p>
+
+ <p><c>Return</c> is what
+ <seealso marker="common_test#Module:all-0"><c>all/0</c></seealso>
+ returned, that is, a list of test cases and groups to be
+ executed, or a tuple <c>{skip,Reason}</c>.</p>
+
+ <p><c>GroupDefs</c> is what
+ <seealso marker="common_test#Module:groups-0"><c>groups/0</c></seealso>
+ or the <c>post_groups/2</c> hook returned, that is, a list
+ of group definitions.</p>
+
+ <p><c>NewReturn</c> is the possibly modified version of <c>Return</c>.</p>
+
+ <p>This function is called only if the CTH is added before
+ <c>init_per_suite</c> is run. For details, see section
+ <seealso marker="ct_hooks_chapter#scope">CTH Scope</seealso>
+ in the User's Guide.</p>
+
+ <p>Notice that for CTHs that are installed by means of the
+ <seealso marker="common_test#Module:suite-0"><c>suite/0</c></seealso>
+ function, <c>post_all/2</c> is called before
+ the <seealso marker="#Module:init-2"><c>init/2</c></seealso>
+ hook function. However, for CTHs that are installed by means
+ of the CT start flag,
+ the <seealso marker="#Module:init-2"><c>init/2</c></seealso>
+ function is called first.</p>
+
+ <note>
+ <p>Prior to each test execution, Common Test does a
+ simulated test run in order to count test suites, groups
+ and cases for logging purposes. This causes
+ the <c>post_all/3</c> hook function to always be called
+ twice. For this reason, side effects are best avoided in
+ this callback.</p>
+ </note>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP R14B02">Module:pre_init_per_suite(SuiteName, InitData, CTHState) -&gt; Result</name>
<fsummary>Called before init_per_suite.</fsummary>
<type>
<v>SuiteName = atom()</v>
@@ -161,7 +286,7 @@
</func>
<func>
- <name>Module:post_init_per_suite(SuiteName, Config, Return, CTHState) -&gt; Result</name>
+ <name since="OTP R14B02">Module:post_init_per_suite(SuiteName, Config, Return, CTHState) -&gt; Result</name>
<fsummary>Called after init_per_suite.</fsummary>
<type>
<v>SuiteName = atom()</v>
@@ -208,7 +333,7 @@
</func>
<func>
- <name>Module:pre_init_per_group(SuiteName, GroupName, InitData, CTHState) -&gt; Result</name>
+ <name since="OTP 19.3">Module:pre_init_per_group(SuiteName, GroupName, InitData, CTHState) -&gt; Result</name>
<fsummary>Called before init_per_group.</fsummary>
<type>
<v>SuiteName = atom()</v>
@@ -241,7 +366,7 @@
</func>
<func>
- <name>Module:post_init_per_group(SuiteName, GroupName, Config, Return, CTHState) -&gt; Result</name>
+ <name since="OTP 19.3">Module:post_init_per_group(SuiteName, GroupName, Config, Return, CTHState) -&gt; Result</name>
<fsummary>Called after init_per_group.</fsummary>
<type>
<v>SuiteName = atom()</v>
@@ -274,7 +399,7 @@
</func>
<func>
- <name>Module:pre_init_per_testcase(SuiteName, TestcaseName, InitData, CTHState) -&gt; Result</name>
+ <name since="OTP 19.3">Module:pre_init_per_testcase(SuiteName, TestcaseName, InitData, CTHState) -&gt; Result</name>
<fsummary>Called before init_per_testcase.</fsummary>
<type>
<v>SuiteName = atom()</v>
@@ -311,7 +436,7 @@
</func>
<func>
- <name>Module:post_init_per_testcase(SuiteName, TestcaseName, Config, Return, CTHState) -&gt; Result</name>
+ <name since="OTP 19.3">Module:post_init_per_testcase(SuiteName, TestcaseName, Config, Return, CTHState) -&gt; Result</name>
<fsummary>Called after init_per_testcase.</fsummary>
<type>
<v>SuiteName = atom()</v>
@@ -344,7 +469,7 @@
</func>
<func>
- <name>Module:pre_end_per_testcase(SuiteName, TestcaseName, EndData, CTHState) -&gt; Result</name>
+ <name since="OTP 19.3">Module:pre_end_per_testcase(SuiteName, TestcaseName, EndData, CTHState) -&gt; Result</name>
<fsummary>Called before end_per_testcase.</fsummary>
<type>
<v>SuiteName = atom()</v>
@@ -368,7 +493,7 @@
<seealso marker="common_test#Module:end_per_testcase-2"><c>end_per_testcase</c></seealso>
instead.</p>
- <p>This function can not change the result of the test case by returning skip or fail
+ <p>This function cannot change the result of the test case by returning skip or fail
tuples, but it may insert items in <c>Config</c> that can be read in
<c>end_per_testcase/2</c> or in <c>post_end_per_testcase/5</c>.</p>
@@ -380,7 +505,7 @@
</func>
<func>
- <name>Module:post_end_per_testcase(SuiteName, TestcaseName, Config, Return, CTHState) -&gt; Result</name>
+ <name since="OTP 19.3">Module:post_end_per_testcase(SuiteName, TestcaseName, Config, Return, CTHState) -&gt; Result</name>
<fsummary>Called after end_per_testcase.</fsummary>
<type>
<v>SuiteName = atom()</v>
@@ -413,7 +538,7 @@
</func>
<func>
- <name>Module:pre_end_per_group(SuiteName, GroupName, EndData, CTHState) -&gt; Result</name>
+ <name since="OTP 19.3">Module:pre_end_per_group(SuiteName, GroupName, EndData, CTHState) -&gt; Result</name>
<fsummary>Called before end_per_group.</fsummary>
<type>
<v>SuiteName = atom()</v>
@@ -446,7 +571,7 @@
</func>
<func>
- <name>Module:post_end_per_group(SuiteName, GroupName, Config, Return, CTHState) -&gt; Result</name>
+ <name since="OTP 19.3">Module:post_end_per_group(SuiteName, GroupName, Config, Return, CTHState) -&gt; Result</name>
<fsummary>Called after end_per_group.</fsummary>
<type>
<v>SuiteName = atom()</v>
@@ -479,7 +604,7 @@
</func>
<func>
- <name>Module:pre_end_per_suite(SuiteName, EndData, CTHState) -&gt; Result</name>
+ <name since="OTP R14B02">Module:pre_end_per_suite(SuiteName, EndData, CTHState) -&gt; Result</name>
<fsummary>Called before end_per_suite.</fsummary>
<type>
<v>SuiteName = atom()</v>
@@ -506,7 +631,7 @@
</func>
<func>
- <name>Module:post_end_per_suite(SuiteName, Config, Return, CTHState) -&gt; Result</name>
+ <name since="OTP R14B02">Module:post_end_per_suite(SuiteName, Config, Return, CTHState) -&gt; Result</name>
<fsummary>Called after end_per_suite.</fsummary>
<type>
<v>SuiteName = atom()</v>
@@ -533,7 +658,7 @@
</func>
<func>
- <name>Module:on_tc_fail(SuiteName, TestName, Reason, CTHState) -&gt; NewCTHState</name>
+ <name since="OTP 19.3">Module:on_tc_fail(SuiteName, TestName, Reason, CTHState) -&gt; NewCTHState</name>
<fsummary>Called after the CTH scope ends.</fsummary>
<type>
<v>SuiteName = atom()</v>
@@ -577,7 +702,7 @@
</func>
<func>
- <name>Module:on_tc_skip(SuiteName, TestName, Reason, CTHState) -&gt; NewCTHState</name>
+ <name since="OTP 19.3">Module:on_tc_skip(SuiteName, TestName, Reason, CTHState) -&gt; NewCTHState</name>
<fsummary>Called after the CTH scope ends.</fsummary>
<type>
<v>SuiteName = atom()</v>
@@ -623,7 +748,7 @@
</func>
<func>
- <name>Module:terminate(CTHState)</name>
+ <name since="OTP R14B02">Module:terminate(CTHState)</name>
<fsummary>Called after the CTH scope ends.</fsummary>
<type>
<v>CTHState = term()</v>
@@ -637,7 +762,7 @@
</func>
<func>
- <name>Module:id(Opts) -&gt; Id</name>
+ <name since="OTP R14B02">Module:id(Opts) -&gt; Id</name>
<fsummary>Called before the init function of a CTH.</fsummary>
<type>
<v>Opts = term()</v>
@@ -662,5 +787,3 @@
</funcs>
</erlref>
-
-
diff --git a/lib/common_test/doc/src/ct_hooks_chapter.xml b/lib/common_test/doc/src/ct_hooks_chapter.xml
index 7ecc2e4298..ea4b67be08 100644
--- a/lib/common_test/doc/src/ct_hooks_chapter.xml
+++ b/lib/common_test/doc/src/ct_hooks_chapter.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2011</year><year>2017</year>
+ <year>2011</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -379,7 +379,7 @@
(in Kernel):
</p>
<code>
- %%% @doc Common Test Example Common Test Hook module.
+ %%% Common Test Example Common Test Hook module.
-module(example_cth).
%% Callbacks
@@ -408,51 +408,51 @@
-record(state, { file_handle, total, suite_total, ts, tcs, data }).
- %% @doc Return a unique id for this CTH.
+ %% Return a unique id for this CTH.
id(Opts) ->
proplists:get_value(filename, Opts, "/tmp/file.log").
- %% @doc Always called before any other callback function. Use this to initiate
+ %% Always called before any other callback function. Use this to initiate
%% any common state.
init(Id, Opts) ->
{ok,D} = file:open(Id,[write]),
{ok, #state{ file_handle = D, total = 0, data = [] }}.
- %% @doc Called before init_per_suite is called.
+ %% Called before init_per_suite is called.
pre_init_per_suite(Suite,Config,State) ->
{Config, State#state{ suite_total = 0, tcs = [] }}.
- %% @doc Called after init_per_suite.
+ %% Called after init_per_suite.
post_init_per_suite(Suite,Config,Return,State) ->
{Return, State}.
- %% @doc Called before end_per_suite.
+ %% Called before end_per_suite.
pre_end_per_suite(Suite,Config,State) ->
{Config, State}.
- %% @doc Called after end_per_suite.
+ %% Called after end_per_suite.
post_end_per_suite(Suite,Config,Return,State) ->
Data = {suites, Suite, State#state.suite_total, lists:reverse(State#state.tcs)},
{Return, State#state{ data = [Data | State#state.data] ,
total = State#state.total + State#state.suite_total } }.
- %% @doc Called before each init_per_group.
+ %% Called before each init_per_group.
pre_init_per_group(Suite,Group,Config,State) ->
{Config, State}.
- %% @doc Called after each init_per_group.
+ %% Called after each init_per_group.
post_init_per_group(Suite,Group,Config,Return,State) ->
{Return, State}.
- %% @doc Called before each end_per_group.
+ %% Called before each end_per_group.
pre_end_per_group(Suite,Group,Config,State) ->
{Config, State}.
- %% @doc Called after each end_per_group.
+ %% Called after each end_per_group.
post_end_per_group(Suite,Group,Config,Return,State) ->
{Return, State}.
- %% @doc Called before each init_per_testcase.
+ %% Called before each init_per_testcase.
pre_init_per_testcase(Suite,TC,Config,State) ->
{Config, State#state{ ts = now(), total = State#state.suite_total + 1 } }.
@@ -460,26 +460,26 @@
post_init_per_testcase(Suite,TC,Config,Return,State) ->
{Return, State}
-%% @doc Called before each end_per_testcase (immediately after the test case).
+%% Called before each end_per_testcase (immediately after the test case).
pre_end_per_testcase(Suite,TC,Config,State) ->
{Config, State}.
- %% @doc Called after each end_per_testcase.
+ %% Called after each end_per_testcase.
post_end_per_testcase(Suite,TC,Config,Return,State) ->
TCInfo = {testcase, Suite, TC, Return, timer:now_diff(now(), State#state.ts)},
{Return, State#state{ ts = undefined, tcs = [TCInfo | State#state.tcs] } }.
- %% @doc Called after post_init_per_suite, post_end_per_suite, post_init_per_group,
+ %% Called after post_init_per_suite, post_end_per_suite, post_init_per_group,
%% post_end_per_group and post_end_per_testcase if the suite, group or test case failed.
on_tc_fail(Suite, TC, Reason, State) ->
State.
- %% @doc Called when a test case is skipped by either user action
+ %% Called when a test case is skipped by either user action
%% or due to an init function failing.
on_tc_skip(Suite, TC, Reason, State) ->
State.
- %% @doc Called when the scope of the CTH is done
+ %% Called when the scope of the CTH is done
terminate(State) ->
io:format(State#state.file_handle, "~p.~n",
[{test_run, State#state.total, State#state.data}]),
@@ -501,12 +501,13 @@
<tag><c>cth_log_redirect</c></tag>
<item>
<p>Built-in</p>
- <p>Captures all <c>error_logger</c> and SASL logging
- events and prints them to the current test case log. If an event cannot be
- associated with a test case, it is printed in the <c>Common Test</c> framework log.
+ <p>Captures all log events that would normally be printed by the default
+ logger handler, and prints them to the current test case log.
+ If an event cannot be associated with a test case, it is printed in
+ the <c>Common Test</c> framework log.
This happens for test cases running in parallel and events occuring
in-between test cases. You can configure the level of
- <seealso marker="sasl:sasl_app">SASL</seealso> events report
+ <seealso marker="sasl:sasl_app">SASL</seealso> reports
using the normal SASL mechanisms.</p>
</item>
<tag><c>cth_surefire</c></tag>
diff --git a/lib/common_test/doc/src/ct_master.xml b/lib/common_test/doc/src/ct_master.xml
index 6bde4644c6..f003b7de11 100644
--- a/lib/common_test/doc/src/ct_master.xml
+++ b/lib/common_test/doc/src/ct_master.xml
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>ct_master.xml</file>
</header>
- <module>ct_master</module>
+ <module since="">ct_master</module>
<modulesummary>Distributed test execution control for Common Test.</modulesummary>
<description>
@@ -46,7 +46,7 @@
<funcs>
<func>
- <name>abort() -&gt; ok</name>
+ <name since="">abort() -&gt; ok</name>
<fsummary>Stops all running tests.</fsummary>
<desc><marker id="abort-0"/>
<p>Stops all running tests.</p>
@@ -54,7 +54,7 @@
</func>
<func>
- <name>abort(Nodes) -&gt; ok</name>
+ <name since="">abort(Nodes) -&gt; ok</name>
<fsummary>Stops tests on specified nodes.</fsummary>
<type>
<v>Nodes = atom() | [atom()]</v>
@@ -65,7 +65,7 @@
</func>
<func>
- <name>basic_html(Bool) -&gt; ok</name>
+ <name since="OTP R15B01">basic_html(Bool) -&gt; ok</name>
<fsummary>If set to true, the ct_master logs are written on a primitive
HTML format, not using the <c>Common Test</c> CSS style sheet.</fsummary>
<type>
@@ -79,7 +79,7 @@
</func>
<func>
- <name>get_event_mgr_ref() -&gt; MasterEvMgrRef</name>
+ <name since="OTP 17.5">get_event_mgr_ref() -&gt; MasterEvMgrRef</name>
<fsummary>Gets a reference to the <c>Common Test</c> master event
manager.</fsummary>
<type>
@@ -98,7 +98,7 @@
</func>
<func>
- <name>progress() -&gt; [{Node, Status}]</name>
+ <name since="">progress() -&gt; [{Node, Status}]</name>
<fsummary>Returns test progress.</fsummary>
<type>
<v>Node = atom()</v>
@@ -112,7 +112,7 @@
</func>
<func>
- <name>run(TestSpecs) -&gt; ok</name>
+ <name since="">run(TestSpecs) -&gt; ok</name>
<fsummary>Equivalent to run(TestSpecs, false, [], []).</fsummary>
<type>
<v>TestSpecs = string() | [SeparateOrMerged]</v>
@@ -124,7 +124,7 @@
</func>
<func>
- <name>run(TestSpecs, InclNodes, ExclNodes) -&gt; ok</name>
+ <name since="">run(TestSpecs, InclNodes, ExclNodes) -&gt; ok</name>
<fsummary>Equivalent to run(TestSpecs, false, InclNodes, ExclNodes).
</fsummary>
<type>
@@ -140,7 +140,7 @@
</func>
<func>
- <name>run(TestSpecs, AllowUserTerms, InclNodes, ExclNodes) -&gt; ok</name>
+ <name since="">run(TestSpecs, AllowUserTerms, InclNodes, ExclNodes) -&gt; ok</name>
<fsummary>Tests are spawned on the nodes as specified in TestSpecs.
</fsummary>
<type>
@@ -162,7 +162,7 @@
</func>
<func>
- <name>run_on_node(TestSpecs, Node) -&gt; ok</name>
+ <name since="">run_on_node(TestSpecs, Node) -&gt; ok</name>
<fsummary>Equivalent to run_on_node(TestSpecs, false, Node).</fsummary>
<type>
<v>TestSpecs = string() | [SeparateOrMerged]</v>
@@ -177,7 +177,7 @@
</func>
<func>
- <name>run_on_node(TestSpecs, AllowUserTerms, Node) -&gt; ok</name>
+ <name since="">run_on_node(TestSpecs, AllowUserTerms, Node) -&gt; ok</name>
<fsummary>Tests are spawned on Node according to TestSpecs.</fsummary>
<type>
<v>TestSpecs = string() | [SeparateOrMerged]</v>
@@ -191,7 +191,7 @@
</func>
<func>
- <name>run_test(Node, Opts) -&gt; ok</name>
+ <name since="">run_test(Node, Opts) -&gt; ok</name>
<fsummary>Tests are spawned on Node using ct:run_test/1.</fsummary>
<type>
<v>Node = atom()</v>
@@ -210,7 +210,7 @@
</type>
<desc><marker id="run_test-2"/>
<p>Tests are spawned on <c>Node</c> using
- <seealso marker="ct:run_test-1"><c>ct:run_test/1</c></seealso></p>
+ <seealso marker="ct#run_test-1"><c>ct:run_test/1</c></seealso></p>
</desc>
</func>
</funcs>
diff --git a/lib/common_test/doc/src/ct_netconfc.xml b/lib/common_test/doc/src/ct_netconfc.xml
index 7ec8f23073..8fbe5f3df6 100644
--- a/lib/common_test/doc/src/ct_netconfc.xml
+++ b/lib/common_test/doc/src/ct_netconfc.xml
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>ct_netconfc.xml</file>
</header>
- <module>ct_netconfc</module>
+ <module since="OTP R15B02">ct_netconfc</module>
<modulesummary>NETCONF client module.</modulesummary>
<description>
@@ -312,8 +312,8 @@
<funcs>
<func>
- <name name="action" arity="2"/>
- <name name="action" arity="3"/>
+ <name name="action" arity="2" since="OTP R15B02"/>
+ <name name="action" arity="3" since="OTP R15B02"/>
<fsummary>Executes an action.</fsummary>
<desc>
<p>Executes an action. If the return type is void, <c>ok</c> is
@@ -322,8 +322,8 @@
</func>
<func>
- <name name="close_session" arity="1"/>
- <name name="close_session" arity="2"/>
+ <name name="close_session" arity="1" since="OTP R15B02"/>
+ <name name="close_session" arity="2" since="OTP R15B02"/>
<fsummary>Requests graceful termination of the session associated with
the client.</fsummary>
<desc>
@@ -339,7 +339,7 @@
</func>
<func>
- <name name="connect" arity="1"/>
+ <name name="connect" arity="1" since="OTP 20.0"/>
<fsummary>Opens an SSH connection to a NETCONF server.</fsummary>
<desc>
<p>Opens an SSH connection to a NETCONF server.</p>
@@ -361,7 +361,7 @@
</func>
<func>
- <name name="connect" arity="2"/>
+ <name name="connect" arity="2" since="OTP 20.0"/>
<fsummary>Opens an SSH connection to a named NETCONF server.</fsummary>
<desc>
<p>Open an SSH connection to a named NETCONF server.</p>
@@ -399,8 +399,8 @@
</func>
<func>
- <name name="copy_config" arity="3"/>
- <name name="copy_config" arity="4"/>
+ <name name="copy_config" arity="3" since="OTP R15B02"/>
+ <name name="copy_config" arity="4" since="OTP R15B02"/>
<fsummary>Copies configuration data.</fsummary>
<desc>
<p>Copies configuration data.</p>
@@ -412,12 +412,12 @@
</func>
<func>
- <name>create_subscription(Client) -> Result</name>
- <name>create_subscription(Client, Stream) -> Result</name>
- <name>create_subscription(Client, Stream, Filter) -> Result</name>
- <name>create_subscription(Client, Stream, Filter, Timeout) -> Result</name>
- <name name="create_subscription" arity="5" clause_i="2"/>
- <name name="create_subscription" arity="6"/>
+ <name since="OTP R15B02">create_subscription(Client) -> Result</name>
+ <name since="OTP R15B02">create_subscription(Client, Stream) -> Result</name>
+ <name since="OTP R15B02">create_subscription(Client, Stream, Filter) -> Result</name>
+ <name since="OTP R15B02">create_subscription(Client, Stream, Filter, Timeout) -> Result</name>
+ <name name="create_subscription" arity="5" clause_i="2" since="OTP R15B02"/>
+ <name name="create_subscription" arity="6" since="OTP R15B02"/>
<fsummary>Creates a subscription for event notifications.</fsummary>
<desc>
<p>Creates a subscription for event notifications.</p>
@@ -490,8 +490,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre>
</func>
<func>
- <name name="delete_config" arity="2"/>
- <name name="delete_config" arity="3"/>
+ <name name="delete_config" arity="2" since="OTP R15B02"/>
+ <name name="delete_config" arity="3" since="OTP R15B02"/>
<fsummary>Deletes configuration data.</fsummary>
<desc>
<p>Deletes configuration data.</p>
@@ -502,7 +502,7 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre>
</func>
<func>
- <name name="disconnect" arity="1"/>
+ <name name="disconnect" arity="1" since="OTP 20.0"/>
<fsummary>Closes the given SSH connection.</fsummary>
<desc>
<p>Closes the given SSH connection.</p>
@@ -514,10 +514,10 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre>
</func>
<func>
- <name name="edit_config" arity="3"/>
- <name name="edit_config" arity="4" clause_i="1"/>
- <name name="edit_config" arity="4" clause_i="2"/>
- <name name="edit_config" arity="5"/>
+ <name name="edit_config" arity="3" since="OTP R15B02"/>
+ <name name="edit_config" arity="4" clause_i="1" since="OTP 18.0"/>
+ <name name="edit_config" arity="4" clause_i="2" since="OTP R15B02"/>
+ <name name="edit_config" arity="5" since="OTP 18.0"/>
<fsummary>Edits configuration data.</fsummary>
<desc>
<p>Edits configuration data.</p>
@@ -542,8 +542,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre>
</func>
<func>
- <name name="get" arity="2"/>
- <name name="get" arity="3"/>
+ <name name="get" arity="2" since="OTP R15B02"/>
+ <name name="get" arity="3" since="OTP R15B02"/>
<fsummary>Gets data.</fsummary>
<desc>
<p>Gets data.</p>
@@ -557,8 +557,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre>
</func>
<func>
- <name name="get_capabilities" arity="1"/>
- <name name="get_capabilities" arity="2"/>
+ <name name="get_capabilities" arity="1" since="OTP R15B02"/>
+ <name name="get_capabilities" arity="2" since="OTP R15B02"/>
<fsummary>Returns the server side capabilities.</fsummary>
<desc>
<p>Returns the server side capabilities.</p>
@@ -582,8 +582,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre>
</func>
<func>
- <name name="get_config" arity="3"/>
- <name name="get_config" arity="4"/>
+ <name name="get_config" arity="3" since="OTP R15B02"/>
+ <name name="get_config" arity="4" since="OTP R15B02"/>
<fsummary>Gets configuration data.</fsummary>
<desc>
<p>Gets configuration data.</p>
@@ -597,10 +597,10 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre>
</func>
<func>
- <name name="get_event_streams" arity="1"/>
- <name name="get_event_streams" arity="2" clause_i="1"/>
- <name name="get_event_streams" arity="2" clause_i="2"/>
- <name name="get_event_streams" arity="3"/>
+ <name name="get_event_streams" arity="1" since="OTP 20.0"/>
+ <name name="get_event_streams" arity="2" clause_i="1" since="OTP R15B02"/>
+ <name name="get_event_streams" arity="2" clause_i="2" since="OTP 20.0"/>
+ <name name="get_event_streams" arity="3" since="OTP R15B02"/>
<fsummary>Sends a request to get the specified event streams.</fsummary>
<desc>
<p>Sends a request to get the specified event streams.</p>
@@ -637,8 +637,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre>
</func>
<func>
- <name name="get_session_id" arity="1"/>
- <name name="get_session_id" arity="2"/>
+ <name name="get_session_id" arity="1" since="OTP R15B02"/>
+ <name name="get_session_id" arity="2" since="OTP R15B02"/>
<fsummary>Returns the session Id associated with the specified
client.</fsummary>
<desc>
@@ -647,9 +647,9 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre>
</func>
<func>
- <name name="hello" arity="1"/>
- <name name="hello" arity="2"/>
- <name name="hello" arity="3"/>
+ <name name="hello" arity="1" since="OTP R15B02"/>
+ <name name="hello" arity="2" since="OTP R15B02"/>
+ <name name="hello" arity="3" since="OTP 17.5.3"/>
<fsummary>Exchanges hello messages with the server.</fsummary>
<desc>
<p>Exchanges <c>hello</c> messages with the server.</p>
@@ -660,8 +660,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre>
</func>
<func>
- <name name="kill_session" arity="2"/>
- <name name="kill_session" arity="3"/>
+ <name name="kill_session" arity="2" since="OTP R15B02"/>
+ <name name="kill_session" arity="3" since="OTP R15B02"/>
<fsummary>Forces termination of the session associated with the supplied
session Id.</fsummary>
<desc>
@@ -682,8 +682,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre>
</func>
<func>
- <name name="lock" arity="2"/>
- <name name="lock" arity="3"/>
+ <name name="lock" arity="2" since="OTP R15B02"/>
+ <name name="lock" arity="3" since="OTP R15B02"/>
<fsummary>Locks the configuration target.</fsummary>
<desc>
<p>Locks the configuration target.</p>
@@ -703,7 +703,7 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre>
</func>
<func>
- <name name="only_open" arity="1"/>
+ <name name="only_open" arity="1" since="OTP R15B02"/>
<fsummary>Opens a NETCONF session, but does not send hello.</fsummary>
<desc>
<p>Opens a NETCONF session, but does not send <c>hello</c>.</p>
@@ -714,7 +714,7 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre>
</func>
<func>
- <name name="only_open" arity="2"/>
+ <name name="only_open" arity="2" since="OTP R15B02"/>
<fsummary>Opens a named NETCONF session, but does not send hello.</fsummary>
<desc>
<p>Opens a named NETCONF session, but does not send <c>hello</c>.</p>
@@ -725,7 +725,7 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre>
</func>
<func>
- <name name="open" arity="1"/>
+ <name name="open" arity="1" since="OTP R15B02"/>
<fsummary>Opens a NETCONF session and exchanges hello messages.</fsummary>
<desc>
<p>Opens a NETCONF session and exchanges <c>hello</c> messages.</p>
@@ -749,7 +749,7 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre>
</func>
<func>
- <name name="open" arity="2"/>
+ <name name="open" arity="2" since="OTP R15B02"/>
<fsummary>Opens a named NETCONF session and exchanges hello
messages.</fsummary>
<desc>
@@ -791,8 +791,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre>
</func>
<func>
- <name name="send" arity="2"/>
- <name name="send" arity="3"/>
+ <name name="send" arity="2" since="OTP R16B02"/>
+ <name name="send" arity="3" since="OTP R16B02"/>
<fsummary>Sends an XML document to the server.</fsummary>
<desc>
<p>Sends an XML document to the server.</p>
@@ -804,8 +804,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre>
</func>
<func>
- <name name="send_rpc" arity="2"/>
- <name name="send_rpc" arity="3"/>
+ <name name="send_rpc" arity="2" since="OTP R16B02"/>
+ <name name="send_rpc" arity="3" since="OTP R16B02"/>
<fsummary>Sends a NETCONF rpc request to the server.</fsummary>
<desc>
<p>Sends a NETCONF <c>rpc</c> request to the server.</p>
@@ -820,10 +820,10 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre>
</func>
<func>
- <name name="session" arity="1"/>
- <name name="session" arity="2" clause_i="1"/>
- <name name="session" arity="2" clause_i="2"/>
- <name name="session" arity="3"/>
+ <name name="session" arity="1" since="OTP 20.0"/>
+ <name name="session" arity="2" clause_i="1" since="OTP 20.0"/>
+ <name name="session" arity="2" clause_i="2" since="OTP 20.0"/>
+ <name name="session" arity="3" since="OTP 20.0"/>
<fsummary>Opens a NETCONF session as a channel on the given SSH
connection, and exchanges hello messages with the
server.</fsummary>
@@ -848,8 +848,8 @@ create_subscription(Client, Stream, Filter, StartTime, StopTime, Timeout)</pre>
</func>
<func>
- <name name="unlock" arity="2"/>
- <name name="unlock" arity="3"/>
+ <name name="unlock" arity="2" since="OTP R15B02"/>
+ <name name="unlock" arity="3" since="OTP R15B02"/>
<fsummary>Unlocks the configuration target.</fsummary>
<desc>
<p>Unlocks the configuration target.</p>
diff --git a/lib/common_test/doc/src/ct_property_test.xml b/lib/common_test/doc/src/ct_property_test.xml
index 028e5eb69f..1e01d9a5d7 100644
--- a/lib/common_test/doc/src/ct_property_test.xml
+++ b/lib/common_test/doc/src/ct_property_test.xml
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>ct_property_test.xml</file>
</header>
- <module>ct_property_test</module>
+ <module since="OTP 17.3">ct_property_test</module>
<modulesummary>EXPERIMENTAL support in Common Test for calling
property-based tests.</modulesummary>
@@ -79,7 +79,7 @@
<funcs>
<func>
- <name>init_per_suite(Config) -&gt; Config | {skip, Reason}</name>
+ <name since="OTP 17.3">init_per_suite(Config) -&gt; Config | {skip, Reason}</name>
<fsummary>Initializes Config for property testing.</fsummary>
<desc><marker id="init_per_suite-1"/>
<p>Initializes <c>Config</c> for property testing.</p>
@@ -98,7 +98,7 @@
</func>
<func>
- <name>quickcheck(Property, Config) -&gt; true | {fail, Reason}</name>
+ <name since="OTP 17.3">quickcheck(Property, Config) -&gt; true | {fail, Reason}</name>
<fsummary>Calls quickcheck and returns the result in a form suitable for
Common Test.</fsummary>
<desc><marker id="quickcheck-2"/>
diff --git a/lib/common_test/doc/src/ct_rpc.xml b/lib/common_test/doc/src/ct_rpc.xml
index 90e6b833f7..00a4dcec08 100644
--- a/lib/common_test/doc/src/ct_rpc.xml
+++ b/lib/common_test/doc/src/ct_rpc.xml
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>ct_rpc.xml</file>
</header>
- <module>ct_rpc</module>
+ <module since="">ct_rpc</module>
<modulesummary>Common Test specific layer on Erlang/OTP rpc.</modulesummary>
<description>
@@ -43,7 +43,7 @@
<funcs>
<func>
- <name>app_node(App, Candidates) -&gt; NodeName</name>
+ <name since="">app_node(App, Candidates) -&gt; NodeName</name>
<fsummary>From a set of candidate nodes determines which of them is
running the application App.</fsummary>
<type>
@@ -61,7 +61,7 @@
</func>
<func>
- <name>app_node(App, Candidates, FailOnBadRPC) -&gt; NodeName</name>
+ <name since="">app_node(App, Candidates, FailOnBadRPC) -&gt; NodeName</name>
<fsummary>Same as app_node/2, except that argument FailOnBadRPC
determines if the search for a candidate node is to stop if
badrpc is received at some point.</fsummary>
@@ -81,7 +81,7 @@
</func>
<func>
- <name>app_node(App, Candidates, FailOnBadRPC, Cookie) -&gt; NodeName</name>
+ <name since="">app_node(App, Candidates, FailOnBadRPC, Cookie) -&gt; NodeName</name>
<fsummary>Same as app_node/2, except that argument FailOnBadRPC
determines if the search for a candidate node is to stop if badrpc is
received at some point.</fsummary>
@@ -105,7 +105,7 @@
</func>
<func>
- <name>call(Node, Module, Function, Args) -&gt; term() | {badrpc, Reason}</name>
+ <name since="">call(Node, Module, Function, Args) -&gt; term() | {badrpc, Reason}</name>
<fsummary>Same as call(Node, Module, Function, Args, infinity).</fsummary>
<desc><marker id="call-4"/>
<p>Same as <c>call(Node, Module, Function, Args, infinity)</c>.</p>
@@ -113,7 +113,7 @@
</func>
<func>
- <name>call(Node, Module, Function, Args, TimeOut) -&gt; term() | {badrpc, Reason}</name>
+ <name since="">call(Node, Module, Function, Args, TimeOut) -&gt; term() | {badrpc, Reason}</name>
<fsummary>Evaluates apply(Module, Function, Args) on the node
Node.</fsummary>
<type>
@@ -136,7 +136,7 @@
</func>
<func>
- <name>call(Node, Module, Function, Args, TimeOut, Cookie) -&gt; term() | {badrpc, Reason}</name>
+ <name since="">call(Node, Module, Function, Args, TimeOut, Cookie) -&gt; term() | {badrpc, Reason}</name>
<fsummary>Evaluates apply(Module, Function, Args) on the node
Node.</fsummary>
<type>
@@ -163,7 +163,7 @@
</func>
<func>
- <name>cast(Node, Module, Function, Args) -&gt; ok</name>
+ <name since="">cast(Node, Module, Function, Args) -&gt; ok</name>
<fsummary>Evaluates apply(Module, Function, Args) on the node
Node.</fsummary>
<type>
@@ -187,7 +187,7 @@
</func>
<func>
- <name>cast(Node, Module, Function, Args, Cookie) -&gt; ok</name>
+ <name since="">cast(Node, Module, Function, Args, Cookie) -&gt; ok</name>
<fsummary>Evaluates apply(Module, Function, Args) on the node
Node.</fsummary>
<type>
diff --git a/lib/common_test/doc/src/ct_slave.xml b/lib/common_test/doc/src/ct_slave.xml
index 9d9aa50051..84e619482d 100644
--- a/lib/common_test/doc/src/ct_slave.xml
+++ b/lib/common_test/doc/src/ct_slave.xml
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>ct_slave.xml</file>
</header>
- <module>ct_slave</module>
+ <module since="OTP R14B">ct_slave</module>
<modulesummary>Common Test framework functions for starting and stopping
nodes for Large-Scale Testing.</modulesummary>
@@ -50,7 +50,7 @@
<funcs>
<func>
- <name>start(Node) -&gt; Result</name>
+ <name since="OTP R14B">start(Node) -&gt; Result</name>
<fsummary>Starts an Erlang node with name Node on the local
host.</fsummary>
<type>
@@ -68,7 +68,7 @@
</func>
<func>
- <name>start(HostOrNode, NodeOrOpts) -&gt; Result</name>
+ <name since="OTP R14B">start(HostOrNode, NodeOrOpts) -&gt; Result</name>
<fsummary>Starts an Erlang node with default options on a specified
host, or on the local host with specified options.</fsummary>
<type>
@@ -90,7 +90,7 @@
</func>
<func>
- <name>start(Host, Node, Opts) -&gt; Result</name>
+ <name since="OTP R14B">start(Host, Node, Opts) -&gt; Result</name>
<fsummary>Starts an Erlang node with name Node on host Host as
specified by the combination of options in Opts.</fsummary>
<type>
@@ -184,7 +184,7 @@
</func>
<func>
- <name>stop(Node) -&gt; Result</name>
+ <name since="OTP R14B">stop(Node) -&gt; Result</name>
<fsummary>Stops the running Erlang node with name Node on the local
host.</fsummary>
<type>
@@ -199,7 +199,7 @@
</func>
<func>
- <name>stop(Host, Node) -&gt; Result</name>
+ <name since="OTP R14B">stop(Host, Node) -&gt; Result</name>
<fsummary>Stops the running Erlang node with name Node on host
Host.</fsummary>
<type>
diff --git a/lib/common_test/doc/src/ct_snmp.xml b/lib/common_test/doc/src/ct_snmp.xml
index 0a5e52b16c..343781814a 100644
--- a/lib/common_test/doc/src/ct_snmp.xml
+++ b/lib/common_test/doc/src/ct_snmp.xml
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>ct_snmp.xml</file>
</header>
- <module>ct_snmp</module>
+ <module since="">ct_snmp</module>
<modulesummary>Common Test user interface module for the SNMP application.</modulesummary>
<description>
@@ -240,7 +240,7 @@
<funcs>
<func>
- <name>get_next_values(Agent, Oids, MgrAgentConfName) -&gt; SnmpReply</name>
+ <name since="">get_next_values(Agent, Oids, MgrAgentConfName) -&gt; SnmpReply</name>
<fsummary>Issues a synchronous SNMP get next request.</fsummary>
<type>
<v>Agent = agent_name()</v>
@@ -254,7 +254,7 @@
</func>
<func>
- <name>get_values(Agent, Oids, MgrAgentConfName) -&gt; SnmpReply</name>
+ <name since="">get_values(Agent, Oids, MgrAgentConfName) -&gt; SnmpReply</name>
<fsummary>Issues a synchronous SNMP get request.</fsummary>
<type>
<v>Agent = agent_name()</v>
@@ -268,7 +268,7 @@
</func>
<func>
- <name>load_mibs(Mibs) -&gt; ok | {error, Reason}</name>
+ <name since="">load_mibs(Mibs) -&gt; ok | {error, Reason}</name>
<fsummary>Loads the MIBs into agent snmp_master_agent.</fsummary>
<type>
<v>Mibs = [MibName]</v>
@@ -281,7 +281,7 @@
</func>
<func>
- <name>register_agents(MgrAgentConfName, ManagedAgents) -&gt; ok | {error, Reason}</name>
+ <name since="">register_agents(MgrAgentConfName, ManagedAgents) -&gt; ok | {error, Reason}</name>
<fsummary>Explicitly instructs the manager to handle this
agent.</fsummary>
<type>
@@ -300,7 +300,7 @@
</func>
<func>
- <name>register_users(MgrAgentConfName, Users) -&gt; ok | {error, Reason}</name>
+ <name since="">register_users(MgrAgentConfName, Users) -&gt; ok | {error, Reason}</name>
<fsummary>Registers the manager entity (=user) responsible for specific
agent(s).</fsummary>
<type>
@@ -319,7 +319,7 @@
</func>
<func>
- <name>register_usm_users(MgrAgentConfName, UsmUsers) -&gt; ok | {error, Reason}</name>
+ <name since="">register_usm_users(MgrAgentConfName, UsmUsers) -&gt; ok | {error, Reason}</name>
<fsummary>Explicitly instructs the manager to handle this USM user.</fsummary>
<type>
<v>MgrAgentConfName = atom()</v>
@@ -337,7 +337,7 @@
</func>
<func>
- <name>set_info(Config) -&gt; [{Agent, OldVarsAndVals, NewVarsAndVals}]</name>
+ <name since="">set_info(Config) -&gt; [{Agent, OldVarsAndVals, NewVarsAndVals}]</name>
<fsummary>Returns a list of all successful set requests performed in the
test case in reverse order.</fsummary>
<type>
@@ -357,7 +357,7 @@
</func>
<func>
- <name>set_values(Agent, VarsAndVals, MgrAgentConfName, Config) -&gt; SnmpReply</name>
+ <name since="">set_values(Agent, VarsAndVals, MgrAgentConfName, Config) -&gt; SnmpReply</name>
<fsummary>Issues a synchronous SNMP set request.</fsummary>
<type>
<v>Agent = agent_name()</v>
@@ -372,7 +372,7 @@
</func>
<func>
- <name>start(Config, MgrAgentConfName) -&gt; ok</name>
+ <name since="">start(Config, MgrAgentConfName) -&gt; ok</name>
<fsummary>Equivalent to start(Config, MgrAgentConfName,
undefined).</fsummary>
<desc><marker id="start-2"/>
@@ -383,7 +383,7 @@
</func>
<func>
- <name>start(Config, MgrAgentConfName, SnmpAppConfName) -&gt; ok</name>
+ <name since="">start(Config, MgrAgentConfName, SnmpAppConfName) -&gt; ok</name>
<fsummary>Starts an SNMP manager and/or agent.</fsummary>
<type>
<v>Config = [{Key, Value}]</v>
@@ -415,7 +415,7 @@
</func>
<func>
- <name>stop(Config) -&gt; ok</name>
+ <name since="">stop(Config) -&gt; ok</name>
<fsummary>Stops the SNMP manager and/or agent, and removes all files
created.</fsummary>
<type>
@@ -430,7 +430,7 @@
</func>
<func>
- <name>unload_mibs(Mibs) -&gt; ok | {error, Reason}</name>
+ <name since="OTP R16B">unload_mibs(Mibs) -&gt; ok | {error, Reason}</name>
<fsummary>Unloads the MIBs from agent snmp_master_agent.</fsummary>
<type>
<v>Mibs = [MibName]</v>
@@ -443,7 +443,7 @@
</func>
<func>
- <name>unregister_agents(MgrAgentConfName) -&gt; ok</name>
+ <name since="">unregister_agents(MgrAgentConfName) -&gt; ok</name>
<fsummary>Unregisters all managed agents.</fsummary>
<type>
<v>MgrAgentConfName = atom()</v>
@@ -455,7 +455,7 @@
</func>
<func>
- <name>unregister_agents(MgrAgentConfName, ManagedAgents) -&gt; ok</name>
+ <name since="OTP R16B">unregister_agents(MgrAgentConfName, ManagedAgents) -&gt; ok</name>
<fsummary>Unregisters the specified managed agents.</fsummary>
<type>
<v>MgrAgentConfName = atom()</v>
@@ -468,7 +468,7 @@
</func>
<func>
- <name>unregister_users(MgrAgentConfName) -&gt; ok</name>
+ <name since="">unregister_users(MgrAgentConfName) -&gt; ok</name>
<fsummary>Unregisters all users.</fsummary>
<type>
<v>MgrAgentConfName = atom()</v>
@@ -480,7 +480,7 @@
</func>
<func>
- <name>unregister_users(MgrAgentConfName, Users) -&gt; ok</name>
+ <name since="OTP R16B">unregister_users(MgrAgentConfName, Users) -&gt; ok</name>
<fsummary>Unregisters the specified users.</fsummary>
<type>
<v>MgrAgentConfName = atom()</v>
@@ -493,7 +493,7 @@
</func>
<func>
- <name>unregister_usm_users(MgrAgentConfName) -&gt; ok</name>
+ <name since="OTP R16B">unregister_usm_users(MgrAgentConfName) -&gt; ok</name>
<fsummary>Unregisters all USM users.</fsummary>
<type>
<v>MgrAgentConfName = atom()</v>
@@ -505,7 +505,7 @@
</func>
<func>
- <name>unregister_usm_users(MgrAgentConfName, UsmUsers) -&gt; ok</name>
+ <name since="OTP R16B">unregister_usm_users(MgrAgentConfName, UsmUsers) -&gt; ok</name>
<fsummary>Unregisters the specified USM users.</fsummary>
<type>
<v>MgrAgentConfName = atom()</v>
diff --git a/lib/common_test/doc/src/ct_ssh.xml b/lib/common_test/doc/src/ct_ssh.xml
index 0c7efed154..8d9f31aff8 100644
--- a/lib/common_test/doc/src/ct_ssh.xml
+++ b/lib/common_test/doc/src/ct_ssh.xml
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>ct_ssh.xml</file>
</header>
- <module>ct_ssh</module>
+ <module since="">ct_ssh</module>
<modulesummary>SSH/SFTP client module.</modulesummary>
<description>
@@ -95,7 +95,7 @@
<funcs>
<func>
- <name>apread(SSH, Handle, Position, Length) -&gt; Result</name>
+ <name since="">apread(SSH, Handle, Position, Length) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -109,7 +109,7 @@
</func>
<func>
- <name>apread(SSH, Server, Handle, Position, Length) -&gt; Result</name>
+ <name since="">apread(SSH, Server, Handle, Position, Length) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -123,7 +123,7 @@
</func>
<func>
- <name>apwrite(SSH, Handle, Position, Data) -&gt; Result</name>
+ <name since="">apwrite(SSH, Handle, Position, Data) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -137,7 +137,7 @@
</func>
<func>
- <name>apwrite(SSH, Server, Handle, Position, Data) -&gt; Result</name>
+ <name since="">apwrite(SSH, Server, Handle, Position, Data) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -151,7 +151,7 @@
</func>
<func>
- <name>aread(SSH, Handle, Len) -&gt; Result</name>
+ <name since="">aread(SSH, Handle, Len) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -165,7 +165,7 @@
</func>
<func>
- <name>aread(SSH, Server, Handle, Len) -&gt; Result</name>
+ <name since="">aread(SSH, Server, Handle, Len) -&gt; Result</name>
<fsummary>For inforamtion and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -179,7 +179,7 @@
</func>
<func>
- <name>awrite(SSH, Handle, Data) -&gt; Result</name>
+ <name since="">awrite(SSH, Handle, Data) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -193,7 +193,7 @@
</func>
<func>
- <name>awrite(SSH, Server, Handle, Data) -&gt; Result</name>
+ <name since="">awrite(SSH, Server, Handle, Data) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -207,7 +207,7 @@
</func>
<func>
- <name>close(SSH, Handle) -&gt; Result</name>
+ <name since="">close(SSH, Handle) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -221,7 +221,7 @@
</func>
<func>
- <name>close(SSH, Server, Handle) -&gt; Result</name>
+ <name since="">close(SSH, Server, Handle) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -235,7 +235,7 @@
</func>
<func>
- <name>connect(KeyOrName) -&gt; {ok, Handle} | {error, Reason}</name>
+ <name since="">connect(KeyOrName) -&gt; {ok, Handle} | {error, Reason}</name>
<fsummary>Equivalent to connect(KeyOrName, host, []).</fsummary>
<desc><marker id="connect-1"/>
<p>Equivalent to
@@ -245,7 +245,7 @@
</func>
<func>
- <name>connect(KeyOrName, ConnType) -&gt; {ok, Handle} | {error, Reason}</name>
+ <name since="">connect(KeyOrName, ConnType) -&gt; {ok, Handle} | {error, Reason}</name>
<fsummary>Equivalent to connect(KeyOrName, ConnType, []).</fsummary>
<desc><marker id="connect-2"/>
<p>Equivalent to
@@ -255,7 +255,7 @@
</func>
<func>
- <name>connect(KeyOrName, ConnType, ExtraOpts) -&gt; {ok, Handle} | {error, Reason}</name>
+ <name since="">connect(KeyOrName, ConnType, ExtraOpts) -&gt; {ok, Handle} | {error, Reason}</name>
<fsummary>Opens an SSH or SFTP connection using the information
associated with KeyOrName.</fsummary>
<type>
@@ -301,7 +301,7 @@
</func>
<func>
- <name>del_dir(SSH, Name) -&gt; Result</name>
+ <name since="">del_dir(SSH, Name) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -315,7 +315,7 @@
</func>
<func>
- <name>del_dir(SSH, Server, Name) -&gt; Result</name>
+ <name since="">del_dir(SSH, Server, Name) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -329,7 +329,7 @@
</func>
<func>
- <name>delete(SSH, Name) -&gt; Result</name>
+ <name since="">delete(SSH, Name) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -343,7 +343,7 @@
</func>
<func>
- <name>delete(SSH, Server, Name) -&gt; Result</name>
+ <name since="">delete(SSH, Server, Name) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -357,7 +357,7 @@
</func>
<func>
- <name>disconnect(SSH) -&gt; ok | {error, Reason}</name>
+ <name since="">disconnect(SSH) -&gt; ok | {error, Reason}</name>
<fsummary>Closes an SSH/SFTP connection.</fsummary>
<type>
<v>SSH = connection()</v>
@@ -369,7 +369,7 @@
</func>
<func>
- <name>exec(SSH, Command) -&gt; {ok, Data} | {error, Reason}</name>
+ <name since="">exec(SSH, Command) -&gt; {ok, Data} | {error, Reason}</name>
<fsummary>Equivalent to exec(SSH, Command, DefaultTimeout).</fsummary>
<desc><marker id="exec-2"/>
<p>Equivalent to
@@ -379,7 +379,7 @@
</func>
<func>
- <name>exec(SSH, Command, Timeout) -&gt; {ok, Data} | {error, Reason}</name>
+ <name since="">exec(SSH, Command, Timeout) -&gt; {ok, Data} | {error, Reason}</name>
<fsummary>Requests server to perform Command.</fsummary>
<type>
<v>SSH = connection()</v>
@@ -396,7 +396,7 @@
</func>
<func>
- <name>exec(SSH, ChannelId, Command, Timeout) -&gt; {ok, Data} | {error, Reason}</name>
+ <name since="">exec(SSH, ChannelId, Command, Timeout) -&gt; {ok, Data} | {error, Reason}</name>
<fsummary>Requests server to perform Command.</fsummary>
<type>
<v>SSH = connection()</v>
@@ -414,7 +414,7 @@
</func>
<func>
- <name>get_file_info(SSH, Handle) -&gt; Result</name>
+ <name since="">get_file_info(SSH, Handle) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -428,7 +428,7 @@
</func>
<func>
- <name>get_file_info(SSH, Server, Handle) -&gt; Result</name>
+ <name since="">get_file_info(SSH, Server, Handle) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -442,7 +442,7 @@
</func>
<func>
- <name>list_dir(SSH, Path) -&gt; Result</name>
+ <name since="">list_dir(SSH, Path) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -456,7 +456,7 @@
</func>
<func>
- <name>list_dir(SSH, Server, Path) -&gt; Result</name>
+ <name since="">list_dir(SSH, Server, Path) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -470,7 +470,7 @@
</func>
<func>
- <name>make_dir(SSH, Name) -&gt; Result</name>
+ <name since="">make_dir(SSH, Name) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -484,7 +484,7 @@
</func>
<func>
- <name>make_dir(SSH, Server, Name) -&gt; Result</name>
+ <name since="">make_dir(SSH, Server, Name) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -498,7 +498,7 @@
</func>
<func>
- <name>make_symlink(SSH, Name, Target) -&gt; Result</name>
+ <name since="">make_symlink(SSH, Name, Target) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -512,7 +512,7 @@
</func>
<func>
- <name>make_symlink(SSH, Server, Name, Target) -&gt; Result</name>
+ <name since="">make_symlink(SSH, Server, Name, Target) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -526,7 +526,7 @@
</func>
<func>
- <name>open(SSH, File, Mode) -&gt; Result</name>
+ <name since="">open(SSH, File, Mode) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -540,7 +540,7 @@
</func>
<func>
- <name>open(SSH, Server, File, Mode) -&gt; Result</name>
+ <name since="">open(SSH, Server, File, Mode) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -554,7 +554,7 @@
</func>
<func>
- <name>opendir(SSH, Path) -&gt; Result</name>
+ <name since="">opendir(SSH, Path) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -568,7 +568,7 @@
</func>
<func>
- <name>opendir(SSH, Server, Path) -&gt; Result</name>
+ <name since="">opendir(SSH, Server, Path) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -582,7 +582,7 @@
</func>
<func>
- <name>position(SSH, Handle, Location) -&gt; Result</name>
+ <name since="">position(SSH, Handle, Location) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -596,7 +596,7 @@
</func>
<func>
- <name>position(SSH, Server, Handle, Location) -&gt; Result</name>
+ <name since="">position(SSH, Server, Handle, Location) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -610,7 +610,7 @@
</func>
<func>
- <name>pread(SSH, Handle, Position, Length) -&gt; Result</name>
+ <name since="">pread(SSH, Handle, Position, Length) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -624,7 +624,7 @@
</func>
<func>
- <name>pread(SSH, Server, Handle, Position, Length) -&gt; Result</name>
+ <name since="">pread(SSH, Server, Handle, Position, Length) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -638,7 +638,7 @@
</func>
<func>
- <name>pwrite(SSH, Handle, Position, Data) -&gt; Result</name>
+ <name since="">pwrite(SSH, Handle, Position, Data) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -652,7 +652,7 @@
</func>
<func>
- <name>pwrite(SSH, Server, Handle, Position, Data) -&gt; Result</name>
+ <name since="">pwrite(SSH, Server, Handle, Position, Data) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -666,7 +666,7 @@
</func>
<func>
- <name>read(SSH, Handle, Len) -&gt; Result</name>
+ <name since="">read(SSH, Handle, Len) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -680,7 +680,7 @@
</func>
<func>
- <name>read(SSH, Server, Handle, Len) -&gt; Result</name>
+ <name since="">read(SSH, Server, Handle, Len) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -694,7 +694,7 @@
</func>
<func>
- <name>read_file(SSH, File) -&gt; Result</name>
+ <name since="">read_file(SSH, File) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -708,7 +708,7 @@
</func>
<func>
- <name>read_file(SSH, Server, File) -&gt; Result</name>
+ <name since="">read_file(SSH, Server, File) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -722,7 +722,7 @@
</func>
<func>
- <name>read_file_info(SSH, Name) -&gt; Result</name>
+ <name since="">read_file_info(SSH, Name) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -736,7 +736,7 @@
</func>
<func>
- <name>read_file_info(SSH, Server, Name) -&gt; Result</name>
+ <name since="">read_file_info(SSH, Server, Name) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -750,7 +750,7 @@
</func>
<func>
- <name>read_link(SSH, Name) -&gt; Result</name>
+ <name since="">read_link(SSH, Name) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -764,7 +764,7 @@
</func>
<func>
- <name>read_link(SSH, Server, Name) -&gt; Result</name>
+ <name since="">read_link(SSH, Server, Name) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -778,7 +778,7 @@
</func>
<func>
- <name>read_link_info(SSH, Name) -&gt; Result</name>
+ <name since="">read_link_info(SSH, Name) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -792,7 +792,7 @@
</func>
<func>
- <name>read_link_info(SSH, Server, Name) -&gt; Result</name>
+ <name since="">read_link_info(SSH, Server, Name) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -806,7 +806,7 @@
</func>
<func>
- <name>receive_response(SSH, ChannelId) -&gt; {ok, Data} | {error, Reason}</name>
+ <name since="">receive_response(SSH, ChannelId) -&gt; {ok, Data} | {error, Reason}</name>
<fsummary>Equivalent to receive_response(SSH, ChannelId,
close).</fsummary>
<desc><marker id="receive_response-2"/>
@@ -817,7 +817,7 @@ ChannelId, close)</c></seealso>.</p>
</func>
<func>
- <name>receive_response(SSH, ChannelId, End) -&gt; {ok, Data} | {error, Reason}</name>
+ <name since="">receive_response(SSH, ChannelId, End) -&gt; {ok, Data} | {error, Reason}</name>
<fsummary>Equivalent to receive_response(SSH, ChannelId, End,
DefaultTimeout).</fsummary>
<desc><marker id="receive_response-3"/>
@@ -828,7 +828,7 @@ ChannelId, End, DefaultTimeout)</c></seealso>.</p>
</func>
<func>
- <name>receive_response(SSH, ChannelId, End, Timeout) -&gt; {ok, Data} | {timeout, Data} | {error, Reason}</name>
+ <name since="">receive_response(SSH, ChannelId, End, Timeout) -&gt; {ok, Data} | {timeout, Data} | {error, Reason}</name>
<fsummary>Receives expected data from server on the specified session
channel.</fsummary>
<type>
@@ -863,7 +863,7 @@ ChannelId, End, DefaultTimeout)</c></seealso>.</p>
</func>
<func>
- <name>rename(SSH, OldName, NewName) -&gt; Result</name>
+ <name since="">rename(SSH, OldName, NewName) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -877,7 +877,7 @@ ChannelId, End, DefaultTimeout)</c></seealso>.</p>
</func>
<func>
- <name>rename(SSH, Server, OldName, NewName) -&gt; Result</name>
+ <name since="">rename(SSH, Server, OldName, NewName) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -891,7 +891,7 @@ ChannelId, End, DefaultTimeout)</c></seealso>.</p>
</func>
<func>
- <name>send(SSH, ChannelId, Data) -&gt; ok | {error, Reason}</name>
+ <name since="">send(SSH, ChannelId, Data) -&gt; ok | {error, Reason}</name>
<fsummary>Equivalent to send(SSH, ChannelId, 0, Data,
DefaultTimeout).</fsummary>
<desc><marker id="send-3"/>
@@ -901,7 +901,7 @@ ChannelId, End, DefaultTimeout)</c></seealso>.</p>
</func>
<func>
- <name>send(SSH, ChannelId, Data, Timeout) -&gt; ok | {error, Reason}</name>
+ <name since="">send(SSH, ChannelId, Data, Timeout) -&gt; ok | {error, Reason}</name>
<fsummary>Equivalent to send(SSH, ChannelId, 0, Data, Timeout).</fsummary>
<desc><marker id="send-4"/>
<p>Equivalent to <seealso marker="#send-5"><c>ct_ssh:send(SSH,
@@ -910,7 +910,7 @@ ChannelId, End, DefaultTimeout)</c></seealso>.</p>
</func>
<func>
- <name>send(SSH, ChannelId, Type, Data, Timeout) -&gt; ok | {error, Reason}</name>
+ <name since="">send(SSH, ChannelId, Type, Data, Timeout) -&gt; ok | {error, Reason}</name>
<fsummary>Sends data to server on specified session channel.</fsummary>
<type>
<v>SSH = connection()</v>
@@ -926,7 +926,7 @@ ChannelId, End, DefaultTimeout)</c></seealso>.</p>
</func>
<func>
- <name>send_and_receive(SSH, ChannelId, Data) -&gt; {ok, Data} | {error, Reason}</name>
+ <name since="">send_and_receive(SSH, ChannelId, Data) -&gt; {ok, Data} | {error, Reason}</name>
<fsummary>Equivalent to send_and_receive(SSH, ChannelId, Data,
close).</fsummary>
<desc><marker id="send_and_receive-3"/>
@@ -937,7 +937,7 @@ ChannelId, End, DefaultTimeout)</c></seealso>.</p>
</func>
<func>
- <name>send_and_receive(SSH, ChannelId, Data, End) -&gt; {ok, Data} | {error, Reason}</name>
+ <name since="">send_and_receive(SSH, ChannelId, Data, End) -&gt; {ok, Data} | {error, Reason}</name>
<fsummary>Equivalent to send_and_receive(SSH, ChannelId, 0, Data, End,
DefaultTimeout).</fsummary>
<desc><marker id="send_and_receive-4"/>
@@ -948,7 +948,7 @@ ChannelId, 0, Data, End, DefaultTimeout)</c></seealso>.</p>
</func>
<func>
- <name>send_and_receive(SSH, ChannelId, Data, End, Timeout) -&gt; {ok, Data} | {error, Reason}</name>
+ <name since="">send_and_receive(SSH, ChannelId, Data, End, Timeout) -&gt; {ok, Data} | {error, Reason}</name>
<fsummary>Equivalent to send_and_receive(SSH, ChannelId, 0, Data, End,
Timeout).</fsummary>
<desc><marker id="send_and_receive-5"/>
@@ -959,7 +959,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p>
</func>
<func>
- <name>send_and_receive(SSH, ChannelId, Type, Data, End, Timeout) -&gt; {ok, Data} | {error, Reason}</name>
+ <name since="">send_and_receive(SSH, ChannelId, Type, Data, End, Timeout) -&gt; {ok, Data} | {error, Reason}</name>
<fsummary>Sends data to server on specified session channel and waits
to receive the server response.</fsummary>
<type>
@@ -981,7 +981,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p>
</func>
<func>
- <name>session_close(SSH, ChannelId) -&gt; ok | {error, Reason}</name>
+ <name since="">session_close(SSH, ChannelId) -&gt; ok | {error, Reason}</name>
<fsummary>Closes an SSH session channel.</fsummary>
<type>
<v>SSH = connection()</v>
@@ -994,7 +994,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p>
</func>
<func>
- <name>session_open(SSH) -&gt; {ok, ChannelId} | {error, Reason}</name>
+ <name since="">session_open(SSH) -&gt; {ok, ChannelId} | {error, Reason}</name>
<fsummary>Equivalent to session_open(SSH, DefaultTimeout).</fsummary>
<desc><marker id="session_open-1"/>
<p>Equivalent to
@@ -1004,7 +1004,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p>
</func>
<func>
- <name>session_open(SSH, Timeout) -&gt; {ok, ChannelId} | {error, Reason}</name>
+ <name since="">session_open(SSH, Timeout) -&gt; {ok, ChannelId} | {error, Reason}</name>
<fsummary>Opens a channel for an SSH session.</fsummary>
<type>
<v>SSH = connection()</v>
@@ -1018,7 +1018,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p>
</func>
<func>
- <name>sftp_connect(SSH) -&gt; {ok, Server} | {error, Reason}</name>
+ <name since="">sftp_connect(SSH) -&gt; {ok, Server} | {error, Reason}</name>
<fsummary>Starts an SFTP session on an already existing SSH
connection.</fsummary>
<type>
@@ -1034,7 +1034,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p>
</func>
<func>
- <name>shell(SSH, ChannelId) -&gt; ok | {error, Reason}</name>
+ <name since="OTP 20.0">shell(SSH, ChannelId) -&gt; ok | {error, Reason}</name>
<fsummary>Equivalent to shell(SSH, ChannelId, DefaultTimeout).</fsummary>
<desc><marker id="shell-2"/>
<p>Equivalent to
@@ -1044,7 +1044,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p>
</func>
<func>
- <name>shell(SSH, ChannelId, Timeout) -&gt; ok | {error, Reason}</name>
+ <name since="OTP 20.0">shell(SSH, ChannelId, Timeout) -&gt; ok | {error, Reason}</name>
<fsummary>Requests that the user default shell is executed at the
server end.</fsummary>
<type>
@@ -1061,7 +1061,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p>
</func>
<func>
- <name>subsystem(SSH, ChannelId, Subsystem) -&gt; Status | {error, Reason}</name>
+ <name since="">subsystem(SSH, ChannelId, Subsystem) -&gt; Status | {error, Reason}</name>
<fsummary>Equivalent to subsystem(SSH, ChannelId, Subsystem,
DefaultTimeout).</fsummary>
<desc><marker id="subsystem-3"/>
@@ -1072,7 +1072,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p>
</func>
<func>
- <name>subsystem(SSH, ChannelId, Subsystem, Timeout) -&gt; Status | {error, Reason}</name>
+ <name since="">subsystem(SSH, ChannelId, Subsystem, Timeout) -&gt; Status | {error, Reason}</name>
<fsummary>Sends a request to execute a predefined subsystem.</fsummary>
<type>
<v>SSH = connection()</v>
@@ -1088,7 +1088,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p>
</func>
<func>
- <name>write(SSH, Handle, Data) -&gt; Result</name>
+ <name since="">write(SSH, Handle, Data) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -1102,7 +1102,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p>
</func>
<func>
- <name>write(SSH, Server, Handle, Data) -&gt; Result</name>
+ <name since="">write(SSH, Server, Handle, Data) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -1116,7 +1116,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p>
</func>
<func>
- <name>write_file(SSH, File, Iolist) -&gt; Result</name>
+ <name since="">write_file(SSH, File, Iolist) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -1130,7 +1130,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p>
</func>
<func>
- <name>write_file(SSH, Server, File, Iolist) -&gt; Result</name>
+ <name since="">write_file(SSH, Server, File, Iolist) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -1144,7 +1144,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p>
</func>
<func>
- <name>write_file_info(SSH, Name, Info) -&gt; Result</name>
+ <name since="">write_file_info(SSH, Name, Info) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
@@ -1158,7 +1158,7 @@ ChannelId, 0, Data, End, Timeout)</c></seealso>.</p>
</func>
<func>
- <name>write_file_info(SSH, Server, Name, Info) -&gt; Result</name>
+ <name since="">write_file_info(SSH, Server, Name, Info) -&gt; Result</name>
<fsummary>For information and other types, see ssh_sftp(3).</fsummary>
<type>
<v>SSH = connection()</v>
diff --git a/lib/common_test/doc/src/ct_telnet.xml b/lib/common_test/doc/src/ct_telnet.xml
index 8e85cccc99..76f5305c46 100644
--- a/lib/common_test/doc/src/ct_telnet.xml
+++ b/lib/common_test/doc/src/ct_telnet.xml
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>ct_telnet.xml</file>
</header>
- <module>ct_telnet</module>
+ <module since="">ct_telnet</module>
<modulesummary>Common Test specific layer on top of Telnet client ct_telnet_client.erl</modulesummary>
<description>
@@ -205,7 +205,7 @@
<funcs>
<func>
- <name>close(Connection) -&gt; ok | {error, Reason}</name>
+ <name since="">close(Connection) -&gt; ok | {error, Reason}</name>
<fsummary>Closes the Telnet connection and stops the process managing
it.</fsummary>
<type>
@@ -223,7 +223,7 @@
</func>
<func>
- <name>cmd(Connection, Cmd) -&gt; {ok, Data} | {error, Reason}</name>
+ <name since="">cmd(Connection, Cmd) -&gt; {ok, Data} | {error, Reason}</name>
<fsummary>Equivalent to cmd(Connection, Cmd, []).</fsummary>
<desc><marker id="cmd-2"/>
<p>Equivalent to
@@ -233,24 +233,27 @@
</func>
<func>
- <name>cmd(Connection, Cmd, Opts) -&gt; {ok, Data} | {error, Reason}</name>
+ <name since="">cmd(Connection, Cmd, Opts) -&gt; {ok, Data} | {error, Reason}</name>
<fsummary>Sends a command through Telnet and waits for prompt.</fsummary>
<type>
<v>Connection = connection()</v>
<v>Cmd = string()</v>
<v>Opts = [Opt]</v>
- <v>Opt = {timeout, timeout()} | {newline, boolean()}</v>
+ <v>Opt = {timeout, timeout()} | {newline, boolean() | string()}</v>
<v>Data = [string()]</v>
<v>Reason = term()</v>
</type>
<desc><marker id="cmd-3"/>
<p>Sends a command through Telnet and waits for prompt.</p>
- <p>By default, this function adds a new line to the end of the
+ <p>By default, this function adds "\n" to the end of the
specified command. If this is not desired, use option
<c>{newline,false}</c>. This is necessary, for example, when
sending Telnet command sequences prefixed with character
- Interprete As Command (IAC).</p>
+ Interpret As Command (IAC). Option <c>{newline,string()}</c>
+ can also be used if a different line end than "\n" is
+ required, for instance <c>{newline,"\r\n"}</c>, to add both
+ carriage return and newline characters.</p>
<p>Option <c>timeout</c> specifies how long the client must wait
for prompt. If the time expires, the function returns
@@ -262,7 +265,7 @@
</func>
<func>
- <name>cmdf(Connection, CmdFormat, Args) -&gt; {ok, Data} | {error, Reason}</name>
+ <name since="">cmdf(Connection, CmdFormat, Args) -&gt; {ok, Data} | {error, Reason}</name>
<fsummary>Equivalent to cmdf(Connection, CmdFormat, Args, []).</fsummary>
<desc><marker id="cmdf-3"/>
<p>Equivalent to
@@ -272,7 +275,7 @@
</func>
<func>
- <name>cmdf(Connection, CmdFormat, Args, Opts) -&gt; {ok, Data} | {error, Reason}</name>
+ <name since="">cmdf(Connection, CmdFormat, Args, Opts) -&gt; {ok, Data} | {error, Reason}</name>
<fsummary>Sends a Telnet command and waits for prompt (uses a format
string and a list of arguments to build the command).</fsummary>
<type>
@@ -280,7 +283,7 @@
<v>CmdFormat = string()</v>
<v>Args = list()</v>
<v>Opts = [Opt]</v>
- <v>Opt = {timeout, timeout()} | {newline, boolean()}</v>
+ <v>Opt = {timeout, timeout()} | {newline, boolean() | string()}</v>
<v>Data = [string()]</v>
<v>Reason = term()</v>
</type>
@@ -294,7 +297,7 @@
</func>
<func>
- <name>expect(Connection, Patterns) -&gt; term()</name>
+ <name since="">expect(Connection, Patterns) -&gt; term()</name>
<fsummary>Equivalent to expect(Connections, Patterns, []).</fsummary>
<desc><marker id="expect-2"/>
<p>Equivalent to
@@ -304,7 +307,7 @@
</func>
<func>
- <name>expect(Connection, Patterns, Opts) -&gt; {ok, Match} | {ok, MatchList, HaltReason} | {error, Reason}</name>
+ <name since="">expect(Connection, Patterns, Opts) -&gt; {ok, Match} | {ok, MatchList, HaltReason} | {error, Reason}</name>
<fsummary>Gets data from Telnet and waits for the expected
pattern.</fsummary>
<type>
@@ -339,7 +342,7 @@
subexpression number <c>N</c>. Subexpressions are denoted with
<c>'(' ')'</c> in the regular expression.</p>
- <p>If a <c>Tag</c> is speciifed, the returned <c>Match</c> also
+ <p>If a <c>Tag</c> is specified, the returned <c>Match</c> also
includes the matched <c>Tag</c>. Otherwise, only <c>RxMatch</c>
is returned.</p>
@@ -382,7 +385,7 @@
can abort the operation of waiting for prompt.</p></item>
<tag><c>repeat | repeat, N</c></tag>
<item><p>The pattern(s) must be matched multiple times. If <c>N</c>
- is speciified, the pattern(s) are matched <c>N</c> times, and
+ is specified, the pattern(s) are matched <c>N</c> times, and
the function returns <c>HaltReason = done</c>. This option can be
interrupted by one or more <c>HaltPatterns</c>. <c>MatchList</c>
is always returned, that is, a list of <c>Match</c> instead of
@@ -422,7 +425,7 @@
</func>
<func>
- <name>get_data(Connection) -&gt; {ok, Data} | {error, Reason}</name>
+ <name since="">get_data(Connection) -&gt; {ok, Data} | {error, Reason}</name>
<fsummary>Gets all data received by the Telnet client since the last
command was sent.</fsummary>
<type>
@@ -446,7 +449,7 @@
</func>
<func>
- <name>open(Name) -&gt; {ok, Handle} | {error, Reason}</name>
+ <name since="">open(Name) -&gt; {ok, Handle} | {error, Reason}</name>
<fsummary>Equivalent to open(Name, telnet).</fsummary>
<desc><marker id="open-1"/>
<p>Equivalent to
@@ -456,7 +459,7 @@
</func>
<func>
- <name>open(Name, ConnType) -&gt; {ok, Handle} | {error, Reason}</name>
+ <name since="">open(Name, ConnType) -&gt; {ok, Handle} | {error, Reason}</name>
<fsummary>Opens a Telnet connection to the specified target
host.</fsummary>
<type>
@@ -471,7 +474,7 @@
</func>
<func>
- <name>open(KeyOrName, ConnType, TargetMod) -&gt; {ok, Handle} | {error, Reason}</name>
+ <name since="">open(KeyOrName, ConnType, TargetMod) -&gt; {ok, Handle} | {error, Reason}</name>
<fsummary>Equivalent to open(KeyOrName, ConnType, TargetMod, []).</fsummary>
<desc><marker id="open-3"/>
<p>Equivalent to
@@ -481,7 +484,7 @@
</func>
<func>
- <name>open(KeyOrName, ConnType, TargetMod, Extra) -&gt; {ok, Handle} | {error, Reason}</name>
+ <name since="">open(KeyOrName, ConnType, TargetMod, Extra) -&gt; {ok, Handle} | {error, Reason}</name>
<fsummary>Opens a Telnet connection to the specified target
host.</fsummary>
<type>
@@ -531,7 +534,7 @@
</func>
<func>
- <name>send(Connection, Cmd) -&gt; ok | {error, Reason}</name>
+ <name since="">send(Connection, Cmd) -&gt; ok | {error, Reason}</name>
<fsummary>Equivalent to send(Connection, Cmd, []).</fsummary>
<desc><marker id="send-2"/>
<p>Equivalent to
@@ -541,23 +544,26 @@
</func>
<func>
- <name>send(Connection, Cmd, Opts) -&gt; ok | {error, Reason}</name>
+ <name since="OTP 17.4">send(Connection, Cmd, Opts) -&gt; ok | {error, Reason}</name>
<fsummary>Sends a Telnet command and returns immediately.</fsummary>
<type>
<v>Connection = connection()</v>
<v>Cmd = string()</v>
<v>Opts = [Opt]</v>
- <v>Opt = {newline, boolean()}</v>
+ <v>Opt = {newline, boolean() | string()}</v>
<v>Reason = term()</v>
</type>
<desc><marker id="send-3"/>
<p>Sends a Telnet command and returns immediately.</p>
- <p>By default, this function adds a newline to the end of the
+ <p>By default, this function adds "\n" to the end of the
specified command. If this is not desired, option
<c>{newline,false}</c> can be used. This is necessary, for example,
when sending Telnet command sequences prefixed with character
- Interprete As Command (IAC).</p>
+ Interpret As Command (IAC). Option <c>{newline,string()}</c>
+ can also be used if a different line end than "\n" is
+ required, for instance <c>{newline,"\r\n"}</c>, to add both
+ carriage return and newline characters.</p>
<p>The resulting output from the command can be read with
<seealso marker="#get_data-1"><c>ct_telnet:get_data/2</c></seealso> or
@@ -566,7 +572,7 @@
</func>
<func>
- <name>sendf(Connection, CmdFormat, Args) -&gt; ok | {error, Reason}</name>
+ <name since="">sendf(Connection, CmdFormat, Args) -&gt; ok | {error, Reason}</name>
<fsummary>Equivalent to sendf(Connection, CmdFormat, Args, []).</fsummary>
<desc><marker id="sendf-3"/>
<p>Equivalent to
@@ -576,7 +582,7 @@
</func>
<func>
- <name>sendf(Connection, CmdFormat, Args, Opts) -&gt; ok | {error, Reason}</name>
+ <name since="OTP 17.4">sendf(Connection, CmdFormat, Args, Opts) -&gt; ok | {error, Reason}</name>
<fsummary>Sends a Telnet command and returns immediately (uses a format
string and a list of arguments to build the command).</fsummary>
<type>
@@ -584,12 +590,15 @@
<v>CmdFormat = string()</v>
<v>Args = list()</v>
<v>Opts = [Opt]</v>
- <v>Opt = {newline, boolean()}</v>
+ <v>Opt = {newline, boolean() | string()}</v>
<v>Reason = term()</v>
</type>
<desc><marker id="sendf-4"/>
<p>Sends a Telnet command and returns immediately (uses a format
string and a list of arguments to build the command).</p>
+
+ <p>For details, see
+ <seealso marker="#send-3"><c>ct_telnet:send/3</c></seealso>.</p>
</desc>
</func>
</funcs>
diff --git a/lib/common_test/doc/src/ct_testspec.xml b/lib/common_test/doc/src/ct_testspec.xml
index 36893f66cf..9cb9a2ae9f 100644
--- a/lib/common_test/doc/src/ct_testspec.xml
+++ b/lib/common_test/doc/src/ct_testspec.xml
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>ct_testspec.xml</file>
</header>
- <module>ct_testspec</module>
+ <module since="OTP 19.3">ct_testspec</module>
<modulesummary>Parsing of test specifications for Common Test.
</modulesummary>
@@ -46,7 +46,7 @@
<funcs>
<func>
- <name>get_tests(SpecsIn) -&gt; {ok, [{Specs,Tests}]} | {error, Reason}</name>
+ <name since="OTP 19.3">get_tests(SpecsIn) -&gt; {ok, [{Specs,Tests}]} | {error, Reason}</name>
<fsummary>Parse the given test specification files and return the tests to run and skip.</fsummary>
<type>
<v>SpecsIn = [string()] | [[string()]]</v>
diff --git a/lib/common_test/doc/src/event_handler_chapter.xml b/lib/common_test/doc/src/event_handler_chapter.xml
index bd9ed21cb4..182abba7ca 100644
--- a/lib/common_test/doc/src/event_handler_chapter.xml
+++ b/lib/common_test/doc/src/event_handler_chapter.xml
@@ -378,7 +378,7 @@
<note><p>To ensure that printouts to <c>stdout</c> (or printouts made with
<seealso marker="ct#log-2"><c>ct:log/2,3</c></seealso> or
- <seealso marker="ct:pal-2"><c>ct:pal,2,3</c></seealso>) get written to the test case log
+ <seealso marker="ct#pal-2"><c>ct:pal,2,3</c></seealso>) get written to the test case log
file, and not to the <c>Common Test</c> framework log, you can synchronize
with the <c>Common Test</c> server by matching on evvents <c>tc_start</c> and <c>tc_done</c>.
In the period between these events, all I/O is directed to the
diff --git a/lib/common_test/doc/src/notes.xml b/lib/common_test/doc/src/notes.xml
index 7e909b24cd..a64818da7b 100644
--- a/lib/common_test/doc/src/notes.xml
+++ b/lib/common_test/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -33,6 +33,316 @@
<file>notes.xml</file>
</header>
+<section><title>Common_Test 1.17.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ All incorrect (that is, all) uses of "can not" has been
+ corrected to "cannot" in source code comments,
+ documentation, examples, and so on.</p>
+ <p>
+ Own Id: OTP-14282 Aux Id: PR-1891 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> Use <c>ssh</c> instead of <c>rsh</c> as the default
+ remote shell. </p>
+ <p>
+ Own Id: OTP-15633 Aux Id: PR-1787 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Common_Test 1.17.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The test result when a hook function fails is in general
+ the same as if the function that the hook is associated
+ with fails. For example, if <c>post_init_per_testcase</c>
+ fails the result is that the test case is skipped, as is
+ the case when <c>init_per_testcase</c> fails.This,
+ however, was earlier not true for timetrap timeouts or
+ other error situations where the process running the hook
+ function was killed. This is now corrected, so the error
+ handling should be the same no matter how the hook
+ function fails.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15717 Aux Id: ERIERL-334 </p>
+ </item>
+ <item>
+ <p>
+ In some rare cases, when two common_test nodes used the
+ same log directory, a timing problem could occur which
+ caused common_test to crash because it's log cache file
+ was unexpectedly empty. This is now corrected.</p>
+ <p>
+ Own Id: OTP-15758 Aux Id: ERIERL-342 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Two new common_test hook functions are introduced:</p>
+ <p>
+ <c>post_groups/2</c>, which is called after
+ <c>Suite:groups/0</c><br/> <c>post_all/3</c>, which is
+ called after <c>Suite:all/0</c></p>
+ <p>
+ These functions allow modifying the return values from
+ the <c>groups/0</c> and <c>all/0</c> functions,
+ respectively.</p>
+ <p>
+ A new term, <c>{testcase,TestCase,RepeatProperties}</c>
+ is now also allowed in the return from <c>all/0</c>. This
+ can be used for repeating a single test case a specific
+ number of times, or until it fails or succeeds once.</p>
+ <p>
+ Own Id: OTP-14746 Aux Id: ERIERL-143 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Common_Test 1.17.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ OTP internal test improvements.</p>
+ <p>
+ Own Id: OTP-15716</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Common_Test 1.17</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A bug caused <c>ct:encrypt_config_file/3</c> and
+ <c>ct:decrypt_config_file/3</c> to fail with
+ <c>badmatch</c> if input parameter <c>KeyOrFile</c> was
+ <c>{key,string()}</c>. This is now corrected.</p>
+ <p>
+ Own Id: OTP-15540</p>
+ </item>
+ <item>
+ <p>
+ The status of a test case which failed with timetrap
+ timeout in <c>end_per_testcase</c> could not be modified
+ by returning <c>{fail,Reason}</c> from a
+ <c>post_end_per_testcase</c> hook function. This is now
+ corrected.</p>
+ <p>
+ Own Id: OTP-15584 Aux Id: ERIERL-282 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ A new variant of the <c>newline</c> option to
+ <c>ct_telnet:cmd/3</c> and <c>ct_telnet:send/3</c> is
+ added, which allows to specify a string to append as
+ newline indicator on a command. By default, the value is
+ "\n", but in some cases it is required to be "\r\n",
+ which this option allows.</p>
+ <p>
+ A faulty regular expression given as parameter to
+ <c>ct_telnet:expect/2,3</c> would earlier crash and look
+ like an internal error in common_test. A better error
+ indication is now given, but the test case will still
+ fail.</p>
+ <p>
+ Own Id: OTP-15229 Aux Id: ERIERL-203 </p>
+ </item>
+ <item>
+ <p>
+ Since the yang RFC allows more than one top element of
+ config data in an <c>edit-config</c> element,
+ <c>ct_netconfc:edit_config/3,4,5</c> can now take a list
+ of XML elements.</p>
+ <p>
+ Own Id: OTP-15298</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Common_Test 1.16.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The Logger handler cth_log_redirect earlier called the
+ report callback (report_cb) before calling the logger
+ formatter. In some cases this would fail, since
+ cth_log_redirect could not handle report callbacks with
+ two arguments. This is now corrected, so only the
+ formatter will call the report callback.</p>
+ <p>
+ Own Id: OTP-15307</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Common_Test 1.16</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>Use the compiler option <c>nowarn_export_all</c> to
+ disable <c>export_all</c> warnings when automatically
+ compiling test suites.</p>
+ <p>
+ Own Id: OTP-14810</p>
+ </item>
+ <item>
+ <p>
+ Use uri_string module instead of http_uri.</p>
+ <p>
+ Own Id: OTP-14902</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Common_Test 1.15.4.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The test result when a hook function fails is in general
+ the same as if the function that the hook is associated
+ with fails. For example, if <c>post_init_per_testcase</c>
+ fails the result is that the test case is skipped, as is
+ the case when <c>init_per_testcase</c> fails.This,
+ however, was earlier not true for timetrap timeouts or
+ other error situations where the process running the hook
+ function was killed. This is now corrected, so the error
+ handling should be the same no matter how the hook
+ function fails.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15717 Aux Id: ERIERL-334 </p>
+ </item>
+ <item>
+ <p>
+ In some rare cases, when two common_test nodes used the
+ same log directory, a timing problem could occur which
+ caused common_test to crash because it's log cache file
+ was unexpectedly empty. This is now corrected.</p>
+ <p>
+ Own Id: OTP-15758 Aux Id: ERIERL-342 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Two new common_test hook functions are introduced:</p>
+ <p>
+ <c>post_groups/2</c>, which is called after
+ <c>Suite:groups/0</c><br/> <c>post_all/3</c>, which is
+ called after <c>Suite:all/0</c></p>
+ <p>
+ These functions allow modifying the return values from
+ the <c>groups/0</c> and <c>all/0</c> functions,
+ respectively.</p>
+ <p>
+ A new term, <c>{testcase,TestCase,RepeatProperties}</c>
+ is now also allowed in the return from <c>all/0</c>. This
+ can be used for repeating a single test case a specific
+ number of times, or until it fails or succeeds once.</p>
+ <p>
+ Own Id: OTP-14746 Aux Id: ERIERL-143 </p>
+ </item>
+ <item>
+ <p>
+ OTP internal test improvements.</p>
+ <p>
+ Own Id: OTP-15716</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Common_Test 1.15.4.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The status of a test case which failed with timetrap
+ timeout in <c>end_per_testcase</c> could not be modified
+ by returning <c>{fail,Reason}</c> from a
+ <c>post_end_per_testcase</c> hook function. This is now
+ corrected.</p>
+ <p>
+ Own Id: OTP-15584 Aux Id: ERIERL-282 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Common_Test 1.15.4.0.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The status of a test case which failed with timetrap
+ timeout in <c>end_per_testcase</c> could not be modified
+ by returning <c>{fail,Reason}</c> from a
+ <c>post_end_per_testcase</c> hook function. This is now
+ corrected.</p>
+ <p>
+ Own Id: OTP-15584 Aux Id: ERIERL-282 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Common_Test 1.15.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -2067,7 +2377,7 @@
ct_netconfc:close_session sometimes returned
{error,closed} because the ssh connection was closed
(from the server side) before the rpc-reply was received
- by the client. This is normal and can not be helped. It
+ by the client. This is normal and cannot be helped. It
has been corrected so the return will be 'ok' in this
case. Other error situations will still give
{error,Reason}.</p>
@@ -2081,7 +2391,7 @@
{error,{process_down,Pid,normal}} because the ssh
connection was closed (from the server side) before the
rpc-reply was received by the client. This is normal and
- can not be helped. It has been corrected so the return
+ cannot be helped. It has been corrected so the return
will be 'ok' in this situation.</p>
<p>
Own Id: OTP-10570</p>
@@ -2733,8 +3043,8 @@
The info function for <c>init/end_per_suite(Config)</c>
is <c>init/end_per_suite()</c>, and for
<c>init/end_per_group(GroupName,Config)</c> it's
- <c>init/end_per_group(GroupName)</c>. Info functions can
- not be used with <c>init/end_per_testcase(TestCase,
+ <c>init/end_per_group(GroupName)</c>. Info functions
+ cannot be used with <c>init/end_per_testcase(TestCase,
Config)</c>, since these configuration functions execute
on the test case process and will use the same properties
as the test case (i.e. properties set by the test case
@@ -3818,7 +4128,7 @@
If the Erlang runtime system was started without access
to an erlang shell (e.g. -noshell), compilation errors
would cause a crash in the Common Test application.
- Without access to a shell, Common Test can not prompt the
+ Without access to a shell, Common Test cannot prompt the
user to choose to continue or abort the test session, but
must assume that the session should proceed.</p>
<p>
@@ -3984,8 +4294,3 @@
<section><title>common_test 1.3.0</title>
</section>
</chapter>
-
-
-
-
-
diff --git a/lib/common_test/doc/src/run_test_chapter.xml b/lib/common_test/doc/src/run_test_chapter.xml
index 56f6f7bcc4..2695e597cf 100644
--- a/lib/common_test/doc/src/run_test_chapter.xml
+++ b/lib/common_test/doc/src/run_test_chapter.xml
@@ -1297,7 +1297,7 @@
</taglist>
<p>For example, if a test is started with:</p>
- <p><c>$ ct_run -suite my_SUITE -logopts no_src</c></p>
+ <p><c>$ ct_run -suite my_SUITE -logopts no_nl</c></p>
<p>then printouts during the test made by successive calls to <c>io:format("x")</c>,
appears in the test case log as:</p>
<p><c>xxx</c></p>
diff --git a/lib/common_test/doc/src/unix_telnet.xml b/lib/common_test/doc/src/unix_telnet.xml
index b2314a53ec..03d91b7dbe 100644
--- a/lib/common_test/doc/src/unix_telnet.xml
+++ b/lib/common_test/doc/src/unix_telnet.xml
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>unix_telnet.xml</file>
</header>
- <module>unix_telnet</module>
+ <module since="">unix_telnet</module>
<modulesummary>Callback module for ct_telnet, for connecting to a Telnet
server on a UNIX host.</modulesummary>
@@ -80,7 +80,7 @@
<funcs>
<func>
- <name>connect(ConnName, Ip, Port, Timeout, KeepAlive, TCPNoDelay, Extra) -&gt; {ok, Handle} | {error, Reason}</name>
+ <name since="OTP 18.3.3">connect(ConnName, Ip, Port, Timeout, KeepAlive, TCPNoDelay, Extra) -&gt; {ok, Handle} | {error, Reason}</name>
<fsummary>Callback for ct_telnet.erl.</fsummary>
<type>
<v>ConnName = target_name()</v>
@@ -107,7 +107,7 @@
</func>
<func>
- <name>get_prompt_regexp() -&gt; PromptRegexp</name>
+ <name since="">get_prompt_regexp() -&gt; PromptRegexp</name>
<fsummary>Callback for ct_telnet.erl.</fsummary>
<type>
<v>PromptRegexp = prompt_regexp()</v>
diff --git a/lib/common_test/doc/src/write_test_chapter.xml b/lib/common_test/doc/src/write_test_chapter.xml
index 82dc06834f..5eed748b08 100644
--- a/lib/common_test/doc/src/write_test_chapter.xml
+++ b/lib/common_test/doc/src/write_test_chapter.xml
@@ -455,8 +455,10 @@
GroupDefs = [GroupDef]
GroupDef = {GroupName,Properties,GroupsAndTestCases}
GroupName = atom()
- GroupsAndTestCases = [GroupDef | {group,GroupName} | TestCase]
- TestCase = atom()</pre>
+ GroupsAndTestCases = [GroupDef | {group,GroupName} | TestCase |
+ {testcase,TestCase,TCRepeatProps}]
+ TestCase = atom()
+ TCRepeatProps = [{repeat,N} | {repeat_until_ok,N} | {repeat_until_fail,N}]</pre>
<p><c>GroupName</c> is the name of the group and must be unique within
the test suite module. Groups can be nested, by including a group definition
@@ -464,11 +466,11 @@
<c>Properties</c> is the list of execution
properties for the group. The possible values are as follows:</p>
<pre>
- Properties = [parallel | sequence | Shuffle | {RepeatType,N}]
+ Properties = [parallel | sequence | Shuffle | {GroupRepeatType,N}]
Shuffle = shuffle | {shuffle,Seed}
Seed = {integer(),integer(),integer()}
- RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail |
- repeat_until_any_ok | repeat_until_any_fail
+ GroupRepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail |
+ repeat_until_any_ok | repeat_until_any_fail
N = integer() | forever</pre>
<p><em>Explanations:</em></p>
@@ -481,8 +483,8 @@
Dependencies Between Test Cases and Suites.</p></item>
<tag><c>shuffle</c></tag>
<item><p>The cases in the group are executed in random order.</p></item>
- <tag><c>repeat</c></tag>
- <item><p>Orders <c>Common Test</c> to repeat execution of the cases in the
+ <tag><c>repeat, repeat_until_*</c></tag>
+ <item><p>Orders <c>Common Test</c> to repeat execution of all the cases in the
group a given number of times, or until any, or all, cases fail or succeed.</p></item>
</taglist>
@@ -496,7 +498,7 @@
<c>{group,GroupName}</c> to the <c>all/0</c> list.</p>
<p><em>Example:</em></p>
<pre>
- all() -> [testcase1, {group,group1}, testcase2, {group,group2}].</pre>
+ all() -> [testcase1, {group,group1}, {testcase,testcase2,[{repeat,10}]}, {group,group2}].</pre>
<p>Execution properties with a group tuple in
<c>all/0</c>: <c>{group,GroupName,Properties}</c> can also be specified.
diff --git a/lib/common_test/src/Makefile b/lib/common_test/src/Makefile
index 9d751996ad..80eaed70bd 100644
--- a/lib/common_test/src/Makefile
+++ b/lib/common_test/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2003-2016. All Rights Reserved.
+# Copyright Ericsson AB 2003-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -165,3 +165,5 @@ release_tests_spec: opt
release_docs_spec: docs
+# Include dependencies -- list below added by Kostis Sagonas
+$(EBIN)/cth_log_redirect.beam: ../../kernel/include/logger.hrl ../../kernel/src/logger_internal.hrl
diff --git a/lib/common_test/src/common_test.app.src b/lib/common_test/src/common_test.app.src
index 0aa4aacf16..efebea896c 100644
--- a/lib/common_test/src/common_test.app.src
+++ b/lib/common_test/src/common_test.app.src
@@ -1,7 +1,7 @@
% This is an -*- erlang -*- file.
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -85,6 +85,7 @@
"crypto-3.6",
"debugger-4.1",
"erts-7.0",
+ "ftp-1.0.0",
"inets-6.0",
"kernel-4.0",
"observer-2.1",
@@ -92,7 +93,7 @@
"sasl-2.4.2",
"snmp-5.1.2",
"ssh-4.0",
- "stdlib-3.4",
+ "stdlib-3.5",
"syntax_tools-1.7",
"tools-2.8",
"xmerl-1.3.8"
diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl
index 4c4dc8bede..bfa7b25862 100644
--- a/lib/common_test/src/ct.erl
+++ b/lib/common_test/src/ct.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,38 +18,6 @@
%% %CopyrightEnd%
%%
-%%% @doc Main user interface for the Common Test framework.
-%%%
-%%% <p> This module implements the command line interface for running
-%%% tests and some basic functions for common test case issues
-%%% such as configuration and logging. </p>
-%%%
-%%% <p><strong>Test Suite Support Macros</strong></p>
-%%%
-%%% <p>The <c>config</c> macro is defined in <c>ct.hrl</c>. This
-%%% macro should be used to retrieve information from the
-%%% <c>Config</c> variable sent to all test cases. It is used with two
-%%% arguments, where the first is the name of the configuration
-%%% variable you wish to retrieve, and the second is the <c>Config</c>
-%%% variable supplied to the test case.</p>
-%%%
-%%% <p>Possible configuration variables include:</p>
-%%% <ul>
-%%% <li><c>data_dir</c> - Data file directory.</li>
-%%% <li><c>priv_dir</c> - Scratch file directory.</li>
-%%% <li>Whatever added by <c>init_per_suite/1</c> or
-%%% <c>init_per_testcase/2</c> in the test suite.</li>
-%%% </ul>
-
-%%% @type var_name() = atom(). A variable name which is specified when
-%%% <c>ct:require/2</c> is called,
-%%% e.g. <c>ct:require(mynodename,{node,[telnet]})</c>
-%%%
-%%% @type target_name() = var_name(). The name of a target.
-%%%
-%%% @type handle() = ct_gen_conn:handle() | term(). The identity of a
-%%% specific connection.
-
-module(ct).
-include("ct.hrl").
@@ -87,6 +55,7 @@
decrypt_config_file/2, decrypt_config_file/3]).
-export([get_target_name/1]).
+-export([get_progname/0]).
-export([parse_table/1, listenv/1]).
-export([remaining_test_procs/0]).
@@ -120,209 +89,34 @@
%%----------------------------------------------------------------------
-
-%%%-----------------------------------------------------------------
-%%% @spec install(Opts) -> ok | {error,Reason}
-%%% Opts = [Opt]
-%%% Opt = {config,ConfigFiles} | {event_handler,Modules} |
-%%% {decrypt,KeyOrFile}
-%%% ConfigFiles = [ConfigFile]
-%%% ConfigFile = string()
-%%% Modules = [atom()]
-%%% KeyOrFile = {key,Key} | {file,KeyFile}
-%%% Key = string()
-%%% KeyFile = string()
-%%% @doc Install config files and event handlers.
-%%%
-%%% <p>Run this function once before first test.</p>
-%%%
-%%% <p>Example:<br/>
-%%% <c>install([{config,["config_node.ctc","config_user.ctc"]}])</c>.</p>
-%%%
-%%% <p>Note that this function is automatically run by the
-%%% <c>ct_run</c> program.</p>
install(Opts) ->
ct_run:install(Opts).
-%%%-----------------------------------------------------------------
-%%% @spec run(TestDir,Suite,Cases) -> Result
-%%% TestDir = string()
-%%% Suite = atom()
-%%% Cases = atom() | [atom()]
-%%% Result = [TestResult] | {error,Reason}
-%%%
-%%% @doc Run the given test case(s).
-%%%
-%%% <p>Requires that <c>ct:install/1</c> has been run first.</p>
-%%%
-%%% <p>Suites (*_SUITE.erl) files must be stored in
-%%% <c>TestDir</c> or <c>TestDir/test</c>. All suites
-%%% will be compiled when test is run.</p>
run(TestDir,Suite,Cases) ->
ct_run:run(TestDir,Suite,Cases).
-%%%-----------------------------------------------------------------
-%%% @spec run(TestDir,Suite) -> Result
-%%%
-%%% @doc Run all test cases in the given suite.
-%%% @see run/3.
run(TestDir,Suite) ->
ct_run:run(TestDir,Suite).
-%%%-----------------------------------------------------------------
-%%% @spec run(TestDirs) -> Result
-%%% TestDirs = TestDir | [TestDir]
-%%%
-%%% @doc Run all test cases in all suites in the given directories.
-%%% @see run/3.
run(TestDirs) ->
ct_run:run(TestDirs).
-%%%-----------------------------------------------------------------
-%%% @spec run_test(Opts) -> Result
-%%% Opts = [OptTuples]
-%%% OptTuples = {dir,TestDirs} | {suite,Suites} | {group,Groups} |
-%%% {testcase,Cases} | {spec,TestSpecs} | {join_specs,Bool} |
-%%% {label,Label} | {config,CfgFiles} | {userconfig, UserConfig} |
-%%% {allow_user_terms,Bool} | {logdir,LogDir} |
-%%% {silent_connections,Conns} | {stylesheet,CSSFile} |
-%%% {cover,CoverSpecFile} | {cover_stop,Bool} | {step,StepOpts} |
-%%% {event_handler,EventHandlers} | {include,InclDirs} |
-%%% {auto_compile,Bool} | {abort_if_missing_suites,Bool} |
-%%% {create_priv_dir,CreatePrivDir} |
-%%% {multiply_timetraps,M} | {scale_timetraps,Bool} |
-%%% {repeat,N} | {duration,DurTime} | {until,StopTime} |
-%%% {force_stop,ForceStop} | {decrypt,DecryptKeyOrFile} |
-%%% {refresh_logs,LogDir} | {logopts,LogOpts} |
-%%% {verbosity,VLevels} | {basic_html,Bool} |
-%%% {esc_chars,Bool} | {ct_hooks, CTHs} |
-%%% {enable_builtin_hooks,Bool} | {release_shell,Bool}
-%%% TestDirs = [string()] | string()
-%%% Suites = [string()] | [atom()] | string() | atom()
-%%% Cases = [atom()] | atom()
-%%% Groups = GroupNameOrPath | [GroupNameOrPath]
-%%% GroupNameOrPath = [atom()] | atom() | all
-%%% TestSpecs = [string()] | string()
-%%% Label = string() | atom()
-%%% CfgFiles = [string()] | string()
-%%% UserConfig = [{CallbackMod,CfgStrings}] | {CallbackMod,CfgStrings}
-%%% CallbackMod = atom()
-%%% CfgStrings = [string()] | string()
-%%% LogDir = string()
-%%% Conns = all | [atom()]
-%%% CSSFile = string()
-%%% CoverSpecFile = string()
-%%% StepOpts = [StepOpt] | []
-%%% StepOpt = config | keep_inactive
-%%% EventHandlers = EH | [EH]
-%%% EH = atom() | {atom(),InitArgs} | {[atom()],InitArgs}
-%%% InitArgs = [term()]
-%%% InclDirs = [string()] | string()
-%%% CreatePrivDir = auto_per_run | auto_per_tc | manual_per_tc
-%%% M = integer()
-%%% N = integer()
-%%% DurTime = string(HHMMSS)
-%%% StopTime = string(YYMoMoDDHHMMSS) | string(HHMMSS)
-%%% ForceStop = skip_rest | Bool
-%%% DecryptKeyOrFile = {key,DecryptKey} | {file,DecryptFile}
-%%% DecryptKey = string()
-%%% DecryptFile = string()
-%%% LogOpts = [LogOpt]
-%%% LogOpt = no_nl | no_src
-%%% VLevels = VLevel | [{Category,VLevel}]
-%%% VLevel = integer()
-%%% Category = atom()
-%%% CTHs = [CTHModule | {CTHModule, CTHInitArgs}]
-%%% CTHModule = atom()
-%%% CTHInitArgs = term()
-%%% Result = {Ok,Failed,{UserSkipped,AutoSkipped}} | TestRunnerPid | {error,Reason}
-%%% Ok = integer()
-%%% Failed = integer()
-%%% UserSkipped = integer()
-%%% AutoSkipped = integer()
-%%% TestRunnerPid = pid()
-%%% Reason = term()
-%%% @doc <p>Run tests as specified by the combination of options in <c>Opts</c>.
-%%% The options are the same as those used with the
-%%% <seealso marker="ct_run#ct_run"><c>ct_run</c></seealso> program.
-%%% Note that here a <c>TestDir</c> can be used to point out the path to
-%%% a <c>Suite</c>. Note also that the option <c>testcase</c>
-%%% corresponds to the <c>-case</c> option in the <c>ct_run</c>
-%%% program. Configuration files specified in <c>Opts</c> will be
-%%% installed automatically at startup.</p>
-%%% <p><c>TestRunnerPid</c> is returned if <c>release_shell == true</c>
-%%% (see <c>break/1</c> for details).</p>
-%%% <p><c>Reason</c> indicates what type of error has been encountered.</p>
run_test(Opts) ->
ct_run:run_test(Opts).
-%%%-----------------------------------------------------------------
-%%% @spec run_testspec(TestSpec) -> Result
-%%% TestSpec = [term()]
-%%% Result = {Ok,Failed,{UserSkipped,AutoSkipped}} | {error,Reason}
-%%% Ok = integer()
-%%% Failed = integer()
-%%% UserSkipped = integer()
-%%% AutoSkipped = integer()
-%%% Reason = term()
-%%% @doc Run test specified by <c>TestSpec</c>. The terms are
-%%% the same as those used in test specification files.
-%%% <p><c>Reason</c> indicates what type of error has been encountered.</p>
run_testspec(TestSpec) ->
ct_run:run_testspec(TestSpec).
-%%%-----------------------------------------------------------------
-%%% @spec step(TestDir,Suite,Case) -> Result
-%%% Case = atom()
-%%%
-%%% @doc Step through a test case with the debugger.
-%%% @see run/3
step(TestDir,Suite,Case) ->
ct_run:step(TestDir,Suite,Case).
-%%%-----------------------------------------------------------------
-%%% @spec step(TestDir,Suite,Case,Opts) -> Result
-%%% Case = atom()
-%%% Opts = [Opt] | []
-%%% Opt = config | keep_inactive
-%%%
-%%% @doc Step through a test case with the debugger. If the
-%%% <c>config</c> option has been given, breakpoints will
-%%% be set also on the configuration functions in <c>Suite</c>.
-%%% @see run/3
step(TestDir,Suite,Case,Opts) ->
ct_run:step(TestDir,Suite,Case,Opts).
-%%%-----------------------------------------------------------------
-%%% @spec start_interactive() -> ok
-%%%
-%%% @doc Start CT in interactive mode.
-%%%
-%%% <p>From this mode all test case support functions can be executed
-%%% directly from the erlang shell. The interactive mode can also be
-%%% started from the OS command line with <c>ct_run -shell
-%%% [-config File...]</c>.</p>
-%%%
-%%% <p>If any functions using "required config data" (e.g. telnet or
-%%% ftp functions) are to be called from the erlang shell, config data
-%%% must first be required with <c>ct:require/2</c>.</p>
-%%%
-%%% <p>Example:<br/>
-%%% <c>&gt; ct:require(unix_telnet, unix).</c><br/>
-%%% <c>ok</c><br/>
-%%% <c>&gt; ct_telnet:open(unix_telnet).</c><br/>
-%%% <c>{ok,&lt;0.105.0&gt;}</c><br/>
-%%% <c>&gt; ct_telnet:cmd(unix_telnet, "ls .").</c><br/>
-%%% <c>{ok,["ls","file1 ...",...]}</c></p>
start_interactive() ->
_ = ct_util:start(interactive),
ok.
-%%%-----------------------------------------------------------------
-%%% @spec stop_interactive() -> ok
-%%%
-%%% @doc Exit the interactive mode.
-%%% @see start_interactive/0
stop_interactive() ->
ct_util:stop(normal),
ok.
@@ -331,181 +125,24 @@ stop_interactive() ->
%%% MISC INTERFACE
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%-----------------------------------------------------------------
-%%% @spec require(Required) -> ok | {error,Reason}
-%%% Required = Key | {Key,SubKeys} | {Key,SubKey,SubKeys}
-%%% Key = atom()
-%%% SubKeys = SubKey | [SubKey]
-%%% SubKey = atom()
-%%%
-%%% @doc Check if the required configuration is available. It is possible
-%%% to specify arbitrarily deep tuples as <c>Required</c>. Note that it is
-%%% only the last element of the tuple which can be a list of <c>SubKey</c>s.
-%%%
-%%% <p>Example 1: require the variable <c>myvar</c>:</p>
-%%% <pre>ok = ct:require(myvar).</pre>
-%%%
-%%% <p>In this case the config file must at least contain:</p>
-%%% <pre>{myvar,Value}.</pre>
-%%%
-%%% <p>Example 2: require the key <c>myvar</c> with
-%%% subkeys <c>sub1</c> and <c>sub2</c>:</p>
-%%% <pre>ok = ct:require({myvar,[sub1,sub2]}).</pre>
-%%%
-%%% <p>In this case the config file must at least contain:</p>
-%%% <pre>{myvar,[{sub1,Value},{sub2,Value}]}.</pre>
-%%%
-%%% <p>Example 3: require the key <c>myvar</c> with
-%%% subkey <c>sub1</c> with <c>subsub1</c>:</p>
-%%% <pre>ok = ct:require({myvar,sub1,sub2}).</pre>
-%%%
-%%% <p>In this case the config file must at least contain:</p>
-%%% <pre>{myvar,[{sub1,[{sub2,Value}]}]}.</pre>
-%%%
-%%% @see require/2
-%%% @see get_config/1
-%%% @see get_config/2
-%%% @see get_config/3
require(Required) ->
ct_config:require(Required).
-%%%-----------------------------------------------------------------
-%%% @spec require(Name,Required) -> ok | {error,Reason}
-%%% Name = atom()
-%%% Required = Key | {Key,SubKey} | {Key,SubKey,SubKey}
-%%% SubKey = Key
-%%% Key = atom()
-%%%
-%%% @doc Check if the required configuration is available, and give it
-%%% a name. The semantics for <c>Required</c> is the same as in
-%%% <c>required/1</c> except that it is not possible to specify a list
-%%% of <c>SubKey</c>s.
-%%%
-%%% <p>If the requested data is available, the sub entry will be
-%%% associated with <c>Name</c> so that the value of the element
-%%% can be read with <c>get_config/1,2</c> provided
-%%% <c>Name</c> instead of the whole <c>Required</c> term.</p>
-%%%
-%%% <p>Example: Require one node with a telnet connection and an
-%%% ftp connection. Name the node <c>a</c>:
-%%% <pre>ok = ct:require(a,{machine,node}).</pre>
-%%% All references to this node may then use the node name.
-%%% E.g. you can fetch a file over ftp like this:</p>
-%%% <pre>ok = ct:ftp_get(a,RemoteFile,LocalFile).</pre>
-%%%
-%%% <p>For this to work, the config file must at least contain:</p>
-%%% <pre>{machine,[{node,[{telnet,IpAddr},{ftp,IpAddr}]}]}.</pre>
-%%%
-%%% <note><p>The behaviour of this function changed radically in common_test
-%%% 1.6.2. In order too keep some backwards compatability it is still possible
-%%% to do: <br/><c>ct:require(a,{node,[telnet,ftp]}).</c><br/>
-%%% This will associate the name <c>a</c> with the top level <c>node</c> entry.
-%%% For this to work, the config file must at least contain:<br/>
-%%% <c>{node,[{telnet,IpAddr},{ftp,IpAddr}]}.</c></p></note>
-%%%
-%%% @see require/1
-%%% @see get_config/1
-%%% @see get_config/2
-%%% @see get_config/3
require(Name,Required) ->
ct_config:require(Name,Required).
-%%%-----------------------------------------------------------------
-%%% @spec get_config(Required) -> Value
-%%% @equiv get_config(Required,undefined,[])
get_config(Required) ->
ct_config:get_config(Required,undefined,[]).
-%%%-----------------------------------------------------------------
-%%% @spec get_config(Required,Default) -> Value
-%%% @equiv get_config(Required,Default,[])
get_config(Required,Default) ->
ct_config:get_config(Required,Default,[]).
-%%%-----------------------------------------------------------------
-%%% @spec get_config(Required,Default,Opts) -> ValueOrElement
-%%% Required = KeyOrName | {KeyOrName,SubKey} | {KeyOrName,SubKey,SubKey}
-%%% KeyOrName = atom()
-%%% SubKey = atom()
-%%% Default = term()
-%%% Opts = [Opt] | []
-%%% Opt = element | all
-%%% ValueOrElement = term() | Default
-%%%
-%%% @doc Read config data values.
-%%%
-%%% <p>This function returns the matching value(s) or config element(s),
-%%% given a config variable key or its associated name
-%%% (if one has been specified with <c>require/2</c> or a
-%%% require statement).</p>
-%%%
-%%% <p>Example, given the following config file:</p>
-%%% <pre>
-%%% {unix,[{telnet,IpAddr},
-%%% {user,[{username,Username},
-%%% {password,Password}]}]}.</pre>
-%%% <p><c>ct:get_config(unix,Default) ->
-%%% [{telnet,IpAddr},
-%%% {user, [{username,Username},
-%%% {password,Password}]}]</c><br/>
-%%% <c>ct:get_config({unix,telnet},Default) -> IpAddr</c><br/>
-%%% <c>ct:get_config({unix,user,username},Default) -> Username</c><br/>
-%%% <c>ct:get_config({unix,ftp},Default) -> Default</c><br/>
-%%% <c>ct:get_config(unknownkey,Default) -> Default</c></p>
-%%%
-%%% <p>If a config variable key has been associated with a name (by
-%%% means of <c>require/2</c> or a require statement), the name
-%%% may be used instead of the key to read the value:</p>
-%%%
-%%% <p><c>ct:require(myuser,{unix,user}) -> ok.</c><br/>
-%%% <c>ct:get_config(myuser,Default) ->
-%%% [{username,Username},
-%%% {password,Password}]</c></p>
-%%%
-%%% <p>If a config variable is defined in multiple files and you want to
-%%% access all possible values, use the <c>all</c> option. The
-%%% values will be returned in a list and the order of the elements
-%%% corresponds to the order that the config files were specified at
-%%% startup.</p>
-%%%
-%%% <p>If you want config elements (key-value tuples) returned as result
-%%% instead of values, use the <c>element</c> option.
-%%% The returned elements will then be on the form <c>{Required,Value}</c></p>
-%%%
-%%% @see get_config/1
-%%% @see get_config/2
-%%% @see require/1
-%%% @see require/2
get_config(Required,Default,Opts) ->
ct_config:get_config(Required,Default,Opts).
-%%%-----------------------------------------------------------------
-%%% @spec reload_config(Required) -> ValueOrElement
-%%% Required = KeyOrName | {KeyOrName,SubKey} | {KeyOrName,SubKey,SubKey}
-%%% KeyOrName = atom()
-%%% SubKey = atom()
-%%% ValueOrElement = term()
-%%%
-%%% @doc Reload config file which contains specified configuration key.
-%%%
-%%% <p>This function performs updating of the configuration data from which the
-%%% given configuration variable was read, and returns the (possibly) new
-%%% value of this variable.</p>
-%%% <p>Note that if some variables were present in the configuration but are not loaded
-%%% using this function, they will be removed from the configuration table together
-%%% with their aliases.</p>
-%%%
reload_config(Required)->
ct_config:reload_config(Required).
-%%%-----------------------------------------------------------------
-%%% @spec get_testspec_terms() -> TestSpecTerms | undefined
-%%% TestSpecTerms = [{Tag,Value}]
-%%% Value = [term()]
-%%%
-%%% @doc Get a list of all test specification terms used to
-%%% configure and run this test.
-%%%
get_testspec_terms() ->
case ct_util:get_testdata(testspec) of
undefined ->
@@ -514,25 +151,6 @@ get_testspec_terms() ->
ct_testspec:testspec_rec2list(CurrSpecRec)
end.
-%%%-----------------------------------------------------------------
-%%% @spec get_testspec_terms(Tags) -> TestSpecTerms | undefined
-%%% Tags = [Tag] | Tag
-%%% Tag = atom()
-%%% TestSpecTerms = [{Tag,Value}] | {Tag,Value}
-%%% Value = [{Node,term()}] | [term()]
-%%% Node = atom()
-%%%
-%%% @doc Read one or more terms from the test specification used
-%%% to configure and run this test. Tag is any valid test specification
-%%% tag, such as e.g. <c>label</c>, <c>config</c>, <c>logdir</c>.
-%%% User specific terms are also available to read if the
-%%% <c>allow_user_terms</c> option has been set. Note that all value tuples
-%%% returned, except user terms, will have the node name as first element.
-%%% Note also that in order to read test terms, use <c>Tag = tests</c>
-%%% (rather than <c>suites</c>, <c>groups</c> or <c>cases</c>). Value is
-%%% then the list of *all* tests on the form:
-%%% <c>[{Node,Dir,[{TestSpec,GroupsAndCases1},...]},...], where
-%%% GroupsAndCases = [{Group,[Case]}] | [Case]</c>.
get_testspec_terms(Tags) ->
case ct_util:get_testdata(testspec) of
undefined ->
@@ -541,24 +159,9 @@ get_testspec_terms(Tags) ->
ct_testspec:testspec_rec2list(Tags, CurrSpecRec)
end.
-
-%%%-----------------------------------------------------------------
-%%% @spec escape_chars(IoList1) -> IoList2 | {error,Reason}
-%%% IoList1 = iolist()
-%%% IoList2 = iolist()
-%%%
-%%% @doc Escape special characters to be printed in html log
-%%%
escape_chars(IoList) ->
ct_logs:escape_chars(IoList).
-%%%-----------------------------------------------------------------
-%%% @spec escape_chars(Format, Args) -> IoList | {error,Reason}
-%%% Format = string()
-%%% Args = list()
-%%%
-%%% @doc Escape special characters to be printed in html log
-%%%
escape_chars(Format, Args) ->
try io_lib:format(Format, Args) of
IoList ->
@@ -568,17 +171,9 @@ escape_chars(Format, Args) ->
{error,Reason}
end.
-%%%-----------------------------------------------------------------
-%%% @spec log(Format) -> ok
-%%% @equiv log(default,50,Format,[],[])
log(Format) ->
log(default,?STD_IMPORTANCE,Format,[],[]).
-%%%-----------------------------------------------------------------
-%%% @spec log(X1,X2) -> ok
-%%% X1 = Category | Importance | Format
-%%% X2 = Format | Args
-%%% @equiv log(Category,Importance,Format,Args,[])
log(X1,X2) ->
{Category,Importance,Format,Args} =
if is_atom(X1) -> {X1,?STD_IMPORTANCE,X2,[]};
@@ -587,12 +182,6 @@ log(X1,X2) ->
end,
log(Category,Importance,Format,Args,[]).
-%%%-----------------------------------------------------------------
-%%% @spec log(X1,X2,X3) -> ok
-%%% X1 = Category | Importance | Format
-%%% X2 = Importance | Format | Args
-%%% X3 = Format | Args | Opts
-%%% @equiv log(Category,Importance,Format,Args,Opts)
log(X1,X2,X3) ->
{Category,Importance,Format,Args,Opts} =
if is_atom(X1), is_integer(X2) -> {X1,X2,X3,[],[]};
@@ -602,13 +191,6 @@ log(X1,X2,X3) ->
end,
log(Category,Importance,Format,Args,Opts).
-%%%-----------------------------------------------------------------
-%%% @spec log(X1,X2,X3,X4) -> ok
-%%% X1 = Category | Importance
-%%% X2 = Importance | Format
-%%% X3 = Format | Args
-%%% X4 = Args | Opts
-%%% @equiv log(Category,Importance,Format,Args,Opts)
log(X1,X2,X3,X4) ->
{Category,Importance,Format,Args,Opts} =
if is_atom(X1), is_integer(X2) -> {X1,X2,X3,X4,[]};
@@ -617,40 +199,12 @@ log(X1,X2,X3,X4) ->
end,
log(Category,Importance,Format,Args,Opts).
-%%%-----------------------------------------------------------------
-%%% @spec log(Category,Importance,Format,Args,Opts) -> ok
-%%% Category = atom()
-%%% Importance = integer()
-%%% Format = string()
-%%% Args = list()
-%%% Opts = [Opt]
-%%% Opt = {heading,string()} | esc_chars | no_css
-%%%
-%%% @doc Printout from a test case to the log file.
-%%%
-%%% <p>This function is meant for printing a string directly from a
-%%% test case to the test case log file.</p>
-%%%
-%%% <p>Default <c>Category</c> is <c>default</c>,
-%%% default <c>Importance</c> is <c>?STD_IMPORTANCE</c>,
-%%% and default value for <c>Args</c> is <c>[]</c>.</p>
-%%% <p>Please see the User's Guide for details on <c>Category</c>
-%%% and <c>Importance</c>.</p>
log(Category,Importance,Format,Args,Opts) ->
ct_logs:tc_log(Category,Importance,Format,Args,Opts).
-
-%%%-----------------------------------------------------------------
-%%% @spec print(Format) -> ok
-%%% @equiv print(default,50,Format,[],[])
print(Format) ->
print(default,?STD_IMPORTANCE,Format,[],[]).
-%%%-----------------------------------------------------------------
-%%% @spec print(X1,X2) -> ok
-%%% X1 = Category | Importance | Format
-%%% X2 = Format | Args
-%%% @equiv print(Category,Importance,Format,Args,[])
print(X1,X2) ->
{Category,Importance,Format,Args} =
if is_atom(X1) -> {X1,?STD_IMPORTANCE,X2,[]};
@@ -659,12 +213,6 @@ print(X1,X2) ->
end,
print(Category,Importance,Format,Args,[]).
-%%%-----------------------------------------------------------------
-%%% @spec print(X1,X2,X3) -> ok
-%%% X1 = Category | Importance | Format
-%%% X2 = Importance | Format | Args
-%%% X3 = Format | Args | Opts
-%%% @equiv print(Category,Importance,Format,Args,Opts)
print(X1,X2,X3) ->
{Category,Importance,Format,Args,Opts} =
if is_atom(X1), is_integer(X2) -> {X1,X2,X3,[],[]};
@@ -674,13 +222,6 @@ print(X1,X2,X3) ->
end,
print(Category,Importance,Format,Args,Opts).
-%%%-----------------------------------------------------------------
-%%% @spec print(X1,X2,X3,X4) -> ok
-%%% X1 = Category | Importance
-%%% X2 = Importance | Format
-%%% X3 = Format | Args
-%%% X4 = Args | Opts
-%%% @equiv print(Category,Importance,Format,Args,Opts)
print(X1,X2,X3,X4) ->
{Category,Importance,Format,Args,Opts} =
if is_atom(X1), is_integer(X2) -> {X1,X2,X3,X4,[]};
@@ -689,40 +230,12 @@ print(X1,X2,X3,X4) ->
end,
print(Category,Importance,Format,Args,Opts).
-%%%-----------------------------------------------------------------
-%%% @spec print(Category,Importance,Format,Args,Opts) -> ok
-%%% Category = atom()
-%%% Importance = integer()
-%%% Format = string()
-%%% Args = list()
-%%% Opts = [Opt]
-%%% Opt = {heading,string()}
-%%%
-%%% @doc Printout from a test case to the console.
-%%%
-%%% <p>This function is meant for printing a string from a test case
-%%% to the console.</p>
-%%%
-%%% <p>Default <c>Category</c> is <c>default</c>,
-%%% default <c>Importance</c> is <c>?STD_IMPORTANCE</c>,
-%%% and default value for <c>Args</c> is <c>[]</c>.</p>
-%%% <p>Please see the User's Guide for details on <c>Category</c>
-%%% and <c>Importance</c>.</p>
print(Category,Importance,Format,Args,Opts) ->
ct_logs:tc_print(Category,Importance,Format,Args,Opts).
-
-%%%-----------------------------------------------------------------
-%%% @spec pal(Format) -> ok
-%%% @equiv pal(default,50,Format,[],[])
pal(Format) ->
pal(default,?STD_IMPORTANCE,Format,[]).
-%%%-----------------------------------------------------------------
-%%% @spec pal(X1,X2) -> ok
-%%% X1 = Category | Importance | Format
-%%% X2 = Format | Args
-%%% @equiv pal(Category,Importance,Format,Args,[])
pal(X1,X2) ->
{Category,Importance,Format,Args} =
if is_atom(X1) -> {X1,?STD_IMPORTANCE,X2,[]};
@@ -731,12 +244,6 @@ pal(X1,X2) ->
end,
pal(Category,Importance,Format,Args,[]).
-%%%-----------------------------------------------------------------
-%%% @spec pal(X1,X2,X3) -> ok
-%%% X1 = Category | Importance | Format
-%%% X2 = Importance | Format | Args
-%%% X3 = Format | Args | Opts
-%%% @equiv pal(Category,Importance,Format,Args,Opts)
pal(X1,X2,X3) ->
{Category,Importance,Format,Args,Opts} =
if is_atom(X1), is_integer(X2) -> {X1,X2,X3,[],[]};
@@ -746,13 +253,6 @@ pal(X1,X2,X3) ->
end,
pal(Category,Importance,Format,Args,Opts).
-%%%-----------------------------------------------------------------
-%%% @spec pal(X1,X2,X3,X4) -> ok
-%%% X1 = Category | Importance
-%%% X2 = Importance | Format
-%%% X3 = Format | Args
-%%% X4 = Args | Opts
-%%% @equiv pal(Category,Importance,Format,Args,Opts)
pal(X1,X2,X3,X4) ->
{Category,Importance,Format,Args,Opts} =
if is_atom(X1), is_integer(X2) -> {X1,X2,X3,X4,[]};
@@ -761,91 +261,25 @@ pal(X1,X2,X3,X4) ->
end,
pal(Category,Importance,Format,Args,Opts).
-%%%-----------------------------------------------------------------
-%%% @spec pal(Category,Importance,Format,Args,Opts) -> ok
-%%% Category = atom()
-%%% Importance = integer()
-%%% Format = string()
-%%% Args = list()
-%%% Opts = [Opt]
-%%% Opt = {heading,string()} | no_css
-%%%
-%%% @doc Print and log from a test case.
-%%%
-%%% <p>This function is meant for printing a string from a test case,
-%%% both to the test case log file and to the console.</p>
-%%%
-%%% <p>Default <c>Category</c> is <c>default</c>,
-%%% default <c>Importance</c> is <c>?STD_IMPORTANCE</c>,
-%%% and default value for <c>Args</c> is <c>[]</c>.</p>
-%%% <p>Please see the User's Guide for details on <c>Category</c>
-%%% and <c>Importance</c>.</p>
pal(Category,Importance,Format,Args,Opts) ->
ct_logs:tc_pal(Category,Importance,Format,Args,Opts).
-%%%-----------------------------------------------------------------
-%%% @spec set_verbosity(Category, Level) -> ok
-%%% Category = default | atom()
-%%% Level = integer()
-%%%
-%%% @doc Set the verbosity level for a category
set_verbosity(Category, Level) ->
ct_util:set_verbosity({Category,Level}).
-%%%-----------------------------------------------------------------
-%%% @spec get_verbosity(Category) -> Level | undefined
-%%% Category = default | atom()
-%%% Level = integer()
-%%%
-%%% @doc Read the verbosity level for a category
get_verbosity(Category) ->
ct_util:get_verbosity(Category).
-%%%-----------------------------------------------------------------
-%%% @spec capture_start() -> ok
-%%%
-%%% @doc Start capturing all text strings printed to stdout during
-%%% execution of the test case.
-%%%
-%%% @see capture_stop/0
-%%% @see capture_get/1
capture_start() ->
test_server:capture_start().
-%%%-----------------------------------------------------------------
-%%% @spec capture_stop() -> ok
-%%%
-%%% @doc Stop capturing text strings (a session started with
-%%% <c>capture_start/0</c>).
-%%%
-%%% @see capture_start/0
-%%% @see capture_get/1
capture_stop() ->
test_server:capture_stop().
-%%%-----------------------------------------------------------------
-%%% @spec capture_get() -> ListOfStrings
-%%% ListOfStrings = [string()]
-%%%
-%%% @equiv capture_get([default])
capture_get() ->
%% remove default log printouts (e.g. ct:log/2 printouts)
capture_get([default]).
-%%%-----------------------------------------------------------------
-%%% @spec capture_get(ExclCategories) -> ListOfStrings
-%%% ExclCategories = [atom()]
-%%% ListOfStrings = [string()]
-%%%
-%%% @doc Return and purge the list of text strings buffered
-%%% during the latest session of capturing printouts to stdout.
-%%% With <c>ExclCategories</c> it's possible to specify
-%%% log categories that should be ignored in <c>ListOfStrings</c>.
-%%% If <c>ExclCategories = []</c>, no filtering takes place.
-%%%
-%%% @see capture_start/0
-%%% @see capture_stop/0
-%%% @see log/3
capture_get([ExclCat | ExclCategories]) ->
Strs = test_server:capture_get(),
CatsStr = [atom_to_list(ExclCat) |
@@ -862,40 +296,26 @@ capture_get([ExclCat | ExclCategories]) ->
capture_get([]) ->
test_server:capture_get().
-%%%-----------------------------------------------------------------
-%%% @spec fail(Reason) -> ok
-%%% Reason = term()
-%%%
-%%% @doc Terminate a test case with the given error
-%%% <c>Reason</c>.
fail(Reason) ->
try
exit({test_case_failed,Reason})
catch
- Class:R ->
- case erlang:get_stacktrace() of
+ Class:R:S ->
+ case S of
[{?MODULE,fail,1,_}|Stk] -> ok;
Stk -> ok
end,
erlang:raise(Class, R, Stk)
end.
-%%%-----------------------------------------------------------------
-%%% @spec fail(Format, Args) -> ok
-%%% Format = string()
-%%% Args = list()
-%%%
-%%% @doc Terminate a test case with an error message specified
-%%% by a format string and a list of values (used as arguments to
-%%% <c>io_lib:format/2</c>).
fail(Format, Args) ->
try io_lib:format(Format, Args) of
Str ->
try
exit({test_case_failed,lists:flatten(Str)})
catch
- Class:R ->
- case erlang:get_stacktrace() of
+ Class:R:S ->
+ case S of
[{?MODULE,fail,2,_}|Stk] -> ok;
Stk -> ok
end,
@@ -906,16 +326,6 @@ fail(Format, Args) ->
exit({BadArgs,{?MODULE,fail,[Format,Args]}})
end.
-%%%-----------------------------------------------------------------
-%%% @spec comment(Comment) -> ok
-%%% Comment = term()
-%%%
-%%% @doc Print the given <c>Comment</c> in the comment field in
-%%% the table on the test suite result page.
-%%%
-%%% <p>If called several times, only the last comment is printed.
-%%% The test case return value <c>{comment,Comment}</c>
-%%% overwrites the string set by this function.</p>
comment(Comment) when is_list(Comment) ->
Formatted =
case (catch io_lib:format("~ts",[Comment])) of
@@ -929,19 +339,6 @@ comment(Comment) ->
Formatted = io_lib:format("~tp",[Comment]),
send_html_comment(lists:flatten(Formatted)).
-%%%-----------------------------------------------------------------
-%%% @spec comment(Format, Args) -> ok
-%%% Format = string()
-%%% Args = list()
-%%%
-%%% @doc Print the formatted string in the comment field in
-%%% the table on the test suite result page.
-%%%
-%%% <p>The <c>Format</c> and <c>Args</c> arguments are
-%%% used in call to <c>io_lib:format/2</c> in order to create
-%%% the comment string. The behaviour of <c>comment/2</c> is
-%%% otherwise the same as the <c>comment/1</c> function (see
-%%% above for details).</p>
comment(Format, Args) when is_list(Format), is_list(Args) ->
Formatted =
case (catch io_lib:format(Format, Args)) of
@@ -957,64 +354,28 @@ send_html_comment(Comment) ->
ct_util:set_testdata({{comment,group_leader()},Html}),
test_server:comment(Html).
-%%%-----------------------------------------------------------------
-%%% @spec make_priv_dir() -> ok | {error,Reason}
-%%% Reason = term()
-%%% @doc If the test has been started with the create_priv_dir
-%%% option set to manual_per_tc, in order for the test case to use
-%%% the private directory, it must first create it by calling
-%%% this function.
make_priv_dir() ->
test_server:make_priv_dir().
-%%%-----------------------------------------------------------------
-%%% @spec get_target_name(Handle) -> {ok,TargetName} | {error,Reason}
-%%% Handle = handle()
-%%% TargetName = target_name()
-%%% @doc Return the name of the target that the given connection
-%%% belongs to.
get_target_name(Handle) ->
ct_util:get_target_name(Handle).
-
-%%%-----------------------------------------------------------------
-%%% @spec parse_table(Data) -> {Heading,Table}
-%%% Data = [string()]
-%%% Heading = tuple()
-%%% Table = [tuple()]
-%%%
-%%% @doc Parse the printout from an SQL table and return a list of tuples.
-%%%
-%%% <p>The printout to parse would typically be the result of a
-%%% <c>select</c> command in SQL. The returned
-%%% <c>Table</c> is a list of tuples, where each tuple is a row
-%%% in the table.</p>
-%%%
-%%% <p><c>Heading</c> is a tuple of strings representing the
-%%% headings of each column in the table.</p>
+
+-spec get_progname() -> string().
+
+get_progname() ->
+ case init:get_argument(progname) of
+ {ok, [[Prog]]} ->
+ Prog;
+ _Other ->
+ "no_prog_name"
+ end.
+
parse_table(Data) ->
ct_util:parse_table(Data).
-%%%-----------------------------------------------------------------
-%%% @spec listenv(Telnet) -> [Env]
-%%% Telnet = term()
-%%% Env = {Key,Value}
-%%% Key = string()
-%%% Value = string()
-%%%
-%%% @doc Performs the listenv command on the given telnet connection
-%%% and returns the result as a list of Key-Value pairs.
listenv(Telnet) ->
ct_util:listenv(Telnet).
-
-%%%-----------------------------------------------------------------
-%%% @spec testcases(TestDir, Suite) -> Testcases | {error,Reason}
-%%% TestDir = string()
-%%% Suite = atom()
-%%% Testcases = list()
-%%% Reason = term()
-%%%
-%%% @doc Returns all test cases in the specified suite.
testcases(TestDir, Suite) ->
case make_and_load(TestDir, Suite) of
E = {error,_} ->
@@ -1029,11 +390,7 @@ testcases(TestDir, Suite) ->
end.
make_and_load(Dir, Suite) ->
- EnvInclude =
- case os:getenv("CT_INCLUDE_PATH") of
- false -> [];
- CtInclPath -> string:tokens(CtInclPath, [$:,$ ,$,])
- end,
+ EnvInclude = string:lexemes(os:getenv("CT_INCLUDE_PATH", ""), [$:,$ ,$,]),
StartInclude =
case init:get_argument(include) of
{ok,[Dirs]} -> Dirs;
@@ -1054,15 +411,6 @@ make_and_load(Dir, Suite) ->
end
end.
-%%%-----------------------------------------------------------------
-%%% @spec userdata(TestDir, Suite) -> SuiteUserData | {error,Reason}
-%%% TestDir = string()
-%%% Suite = atom()
-%%% SuiteUserData = [term()]
-%%% Reason = term()
-%%%
-%%% @doc Returns any data specified with the tag <c>userdata</c>
-%%% in the list of tuples returned from <c>Suite:suite/0</c>.
userdata(TestDir, Suite) ->
case make_and_load(TestDir, Suite) of
E = {error,_} ->
@@ -1088,18 +436,6 @@ get_userdata(List, _) when is_list(List) ->
get_userdata(_BadTerm, Spec) ->
{error,list_to_atom(Spec ++ " must return a list")}.
-%%%-----------------------------------------------------------------
-%%% @spec userdata(TestDir, Suite, GroupOrCase) -> TCUserData | {error,Reason}
-%%% TestDir = string()
-%%% Suite = atom()
-%%% GroupOrCase = {group,GroupName} | atom()
-%%% GroupName = atom()
-%%% TCUserData = [term()]
-%%% Reason = term()
-%%%
-%%% @doc Returns any data specified with the tag <c>userdata</c>
-%%% in the list of tuples returned from <c>Suite:group(GroupName)</c>
-%%% or <c>Suite:Case()</c>.
userdata(TestDir, Suite, {group,GroupName}) ->
case make_and_load(TestDir, Suite) of
E = {error,_} ->
@@ -1118,27 +454,6 @@ userdata(TestDir, Suite, Case) when is_atom(Case) ->
get_userdata(Info, atom_to_list(Case)++"/0")
end.
-
-%%%-----------------------------------------------------------------
-%%% @spec get_status() -> TestStatus | {error,Reason} | no_tests_running
-%%% TestStatus = [StatusElem]
-%%% StatusElem = {current,TestCaseInfo} | {successful,Successful} |
-%%% {failed,Failed} | {skipped,Skipped} | {total,Total}
-%%% TestCaseInfo = {Suite,TestCase} | [{Suite,TestCase}]
-%%% Suite = atom()
-%%% TestCase = atom()
-%%% Successful = integer()
-%%% Failed = integer()
-%%% Skipped = {UserSkipped,AutoSkipped}
-%%% UserSkipped = integer()
-%%% AutoSkipped = integer()
-%%% Total = integer()
-%%% Reason = term()
-%%%
-%%% @doc Returns status of ongoing test. The returned list contains info about
-%%% which test case is currently executing (a list of cases when a
-%%% parallel test case group is executing), as well as counters for
-%%% successful, failed, skipped, and total test cases so far.
get_status() ->
case get_testdata(curr_tc) of
{ok,TestCase} ->
@@ -1170,176 +485,37 @@ get_testdata(Key) ->
{ok,Data}
end.
-%%%-----------------------------------------------------------------
-%%% @spec abort_current_testcase(Reason) -> ok | {error,ErrorReason}
-%%% Reason = term()
-%%% ErrorReason = no_testcase_running | parallel_group
-%%%
-%%% @doc <p>When calling this function, the currently executing test case will be aborted.
-%%% It is the user's responsibility to know for sure which test case is currently
-%%% executing. The function is therefore only safe to call from a function which
-%%% has been called (or synchronously invoked) by the test case.</p>
-%%%
-%%% <p><c>Reason</c>, the reason for aborting the test case, is printed
-%%% in the test case log.</p>
abort_current_testcase(Reason) ->
test_server_ctrl:abort_current_testcase(Reason).
-%%%-----------------------------------------------------------------
-%%% @spec get_event_mgr_ref() -> EvMgrRef
-%%% EvMgrRef = atom()
-%%%
-%%% @doc <p>Call this function in order to get a reference to the
-%%% CT event manager. The reference can be used to e.g. add
-%%% a user specific event handler while tests are running.
-%%% Example:
-%%% <c>gen_event:add_handler(ct:get_event_mgr_ref(), my_ev_h, [])</c></p>
get_event_mgr_ref() ->
?CT_EVMGR_REF.
-%%%-----------------------------------------------------------------
-%%% @spec encrypt_config_file(SrcFileName, EncryptFileName) ->
-%%% ok | {error,Reason}
-%%% SrcFileName = string()
-%%% EncryptFileName = string()
-%%% Reason = term()
-%%%
-%%% @doc <p>This function encrypts the source config file with DES3 and
-%%% saves the result in file <c>EncryptFileName</c>. The key,
-%%% a string, must be available in a text file named
-%%% <c>.ct_config.crypt</c> in the current directory, or the
-%%% home directory of the user (it is searched for in that order).</p>
-%%% <p>See the Common Test User's Guide for information about using
-%%% encrypted config files when running tests.</p>
-%%% <p>See the <c>crypto</c> application for details on DES3
-%%% encryption/decryption.</p>
encrypt_config_file(SrcFileName, EncryptFileName) ->
ct_config:encrypt_config_file(SrcFileName, EncryptFileName).
-%%%-----------------------------------------------------------------
-%%% @spec encrypt_config_file(SrcFileName, EncryptFileName, KeyOrFile) ->
-%%% ok | {error,Reason}
-%%% SrcFileName = string()
-%%% EncryptFileName = string()
-%%% KeyOrFile = {key,string()} | {file,string()}
-%%% Reason = term()
-%%%
-%%% @doc <p>This function encrypts the source config file with DES3 and
-%%% saves the result in the target file <c>EncryptFileName</c>.
-%%% The encryption key to use is either the value in
-%%% <c>{key,Key}</c> or the value stored in the file specified
-%%% by <c>{file,File}</c>.</p>
-%%% <p>See the Common Test User's Guide for information about using
-%%% encrypted config files when running tests.</p>
-%%% <p>See the <c>crypto</c> application for details on DES3
-%%% encryption/decryption.</p>
encrypt_config_file(SrcFileName, EncryptFileName, KeyOrFile) ->
ct_config:encrypt_config_file(SrcFileName, EncryptFileName, KeyOrFile).
-%%%-----------------------------------------------------------------
-%%% @spec decrypt_config_file(EncryptFileName, TargetFileName) ->
-%%% ok | {error,Reason}
-%%% EncryptFileName = string()
-%%% TargetFileName = string()
-%%% Reason = term()
-%%%
-%%% @doc <p>This function decrypts <c>EncryptFileName</c>, previously
-%%% generated with <c>encrypt_config_file/2/3</c>. The original
-%%% file contents is saved in the target file. The encryption key, a
-%%% string, must be available in a text file named
-%%% <c>.ct_config.crypt</c> in the current directory, or the
-%%% home directory of the user (it is searched for in that order).</p>
decrypt_config_file(EncryptFileName, TargetFileName) ->
ct_config:decrypt_config_file(EncryptFileName, TargetFileName).
-%%%-----------------------------------------------------------------
-%%% @spec decrypt_config_file(EncryptFileName, TargetFileName, KeyOrFile) ->
-%%% ok | {error,Reason}
-%%% EncryptFileName = string()
-%%% TargetFileName = string()
-%%% KeyOrFile = {key,string()} | {file,string()}
-%%% Reason = term()
-%%%
-%%% @doc <p>This function decrypts <c>EncryptFileName</c>, previously
-%%% generated with <c>encrypt_config_file/2/3</c>. The original
-%%% file contents is saved in the target file. The key must have the
-%%% the same value as that used for encryption.</p>
decrypt_config_file(EncryptFileName, TargetFileName, KeyOrFile) ->
ct_config:decrypt_config_file(EncryptFileName, TargetFileName, KeyOrFile).
-
-%%%-----------------------------------------------------------------
-%%% @spec add_config(Callback, Config) -> ok | {error, Reason}
-%%% Callback = atom()
-%%% Config = string()
-%%% Reason = term()
-%%%
-%%% @doc <p>This function loads configuration variables using the
-%%% given callback module and configuration string. Callback module
-%%% should be either loaded or present in the code part. Loaded
-%%% configuration variables can later be removed using
-%%% <c>remove_config/2</c> function.</p>
add_config(Callback, Config)->
ct_config:add_config(Callback, Config).
-%%%-----------------------------------------------------------------
-%%% @spec remove_config(Callback, Config) -> ok
-%%% Callback = atom()
-%%% Config = string()
-%%% Reason = term()
-%%%
-%%% @doc <p>This function removes configuration variables (together with
-%%% their aliases) which were loaded with specified callback module and
-%%% configuration string.</p>
remove_config(Callback, Config) ->
ct_config:remove_config(Callback, Config).
-%%%-----------------------------------------------------------------
-%%% @spec timetrap(Time) -> ok
-%%% Time = {hours,Hours} | {minutes,Mins} | {seconds,Secs} | Millisecs | infinity | Func
-%%% Hours = integer()
-%%% Mins = integer()
-%%% Secs = integer()
-%%% Millisecs = integer() | float()
-%%% Func = {M,F,A} | fun()
-%%% M = atom()
-%%% F = atom()
-%%% A = list()
-%%%
-%%% @doc <p>Use this function to set a new timetrap for the running test case.
-%%% If the argument is <c>Func</c>, the timetrap will be triggered
-%%% when this function returns. <c>Func</c> may also return a new
-%%% <c>Time</c> value, which in that case will be the value for the
-%%% new timetrap.</p>
timetrap(Time) ->
test_server:timetrap_cancel(),
test_server:timetrap(Time).
-%%%-----------------------------------------------------------------
-%%% @spec get_timetrap_info() -> {Time,Scale}
-%%% Time = integer() | infinity
-%%% Scale = true | false
-%%%
-%%% @doc <p>Read info about the timetrap set for the current test case.
-%%% <c>Scale</c> indicates if Common Test will attempt to automatically
-%%% compensate timetraps for runtime delays introduced by e.g. tools like
-%%% cover.</p>
get_timetrap_info() ->
test_server:get_timetrap_info().
-%%%-----------------------------------------------------------------
-%%% @spec sleep(Time) -> ok
-%%% Time = {hours,Hours} | {minutes,Mins} | {seconds,Secs} | Millisecs | infinity
-%%% Hours = integer()
-%%% Mins = integer()
-%%% Secs = integer()
-%%% Millisecs = integer() | float()
-%%%
-%%% @doc <p>This function, similar to <c>timer:sleep/1</c>, suspends the test
-%%% case for specified time. However, this function also multiplies
-%%% <c>Time</c> with the 'multiply_timetraps' value (if set) and under
-%%% certain circumstances also scales up the time automatically
-%%% if 'scale_timetraps' is set to true (default is false).</p>
sleep({hours,Hs}) ->
sleep(trunc(Hs * 1000 * 60 * 60));
sleep({minutes,Ms}) ->
@@ -1349,52 +525,12 @@ sleep({seconds,Ss}) ->
sleep(Time) ->
test_server:adjusted_sleep(Time).
-%%%-----------------------------------------------------------------
-%%% @spec notify(Name,Data) -> ok
-%%% Name = atom()
-%%% Data = term()
-%%%
-%%% @doc <p>Sends a asynchronous notification of type <c>Name</c> with
-%%% <c>Data</c>to the common_test event manager. This can later be
-%%% caught by any installed event manager. </p>
-%%% @see //stdlib/gen_event
notify(Name,Data) ->
ct_event:notify(Name, Data).
-%%%-----------------------------------------------------------------
-%%% @spec sync_notify(Name,Data) -> ok
-%%% Name = atom()
-%%% Data = term()
-%%%
-%%% @doc <p>Sends a synchronous notification of type <c>Name</c> with
-%%% <c>Data</c>to the common_test event manager. This can later be
-%%% caught by any installed event manager. </p>
-%%% @see //stdlib/gen_event
sync_notify(Name,Data) ->
ct_event:sync_notify(Name, Data).
-%%%-----------------------------------------------------------------
-%%% @spec break(Comment) -> ok | {error,Reason}
-%%% Comment = string()
-%%% Reason = {multiple_cases_running,TestCases} |
-%%% 'enable break with release_shell option'
-%%% TestCases = [atom()]
-%%%
-%%% @doc <p>This function will cancel any active timetrap and pause the
-%%% execution of the current test case until the user calls the
-%%% <c>continue/0</c> function. It gives the user the opportunity
-%%% to interact with the erlang node running the tests, e.g. for
-%%% debugging purposes or for manually executing a part of the
-%%% test case. If a parallel group is executing, <c>break/2</c>
-%%% should be called instead.</p>
-%%% <p>A cancelled timetrap will not be automatically
-%%% reactivated after the break, but must be started exlicitly with
-%%% <c>ct:timetrap/1</c></p>
-%%% <p>In order for the break/continue functionality to work,
-%%% Common Test must release the shell process controlling stdin.
-%%% This is done by setting the <c>release_shell</c> start option
-%%% to <c>true</c>. See the User's Guide for more information.</p>
-
break(Comment) ->
case {ct_util:get_testdata(starter),
ct_util:get_testdata(release_shell)} of
@@ -1417,19 +553,6 @@ break(Comment) ->
end
end.
-%%%-----------------------------------------------------------------
-%%% @spec break(TestCase, Comment) -> ok | {error,Reason}
-%%% TestCase = atom()
-%%% Comment = string()
-%%% Reason = 'test case not running' |
-%%% 'enable break with release_shell option'
-%%%
-%%% @doc <p>This function works the same way as <c>break/1</c>,
-%%% only the <c>TestCase</c> argument makes it possible to
-%%% pause a test case executing in a parallel group. The
-%%% <c>continue/1</c> function should be used to resume
-%%% execution of <c>TestCase</c>.</p>
-%%% <p>See <c>break/1</c> for more details.</p>
break(TestCase, Comment) ->
case {ct_util:get_testdata(starter),
ct_util:get_testdata(release_shell)} of
@@ -1456,56 +579,12 @@ break(TestCase, Comment) ->
end
end.
-%%%-----------------------------------------------------------------
-%%% @spec continue() -> ok
-%%%
-%%% @doc <p>This function must be called in order to continue after a
-%%% test case (not executing in a parallel group) has called
-%%% <c>break/1</c>.</p>
continue() ->
test_server:continue().
-%%%-----------------------------------------------------------------
-%%% @spec continue(TestCase) -> ok
-%%% TestCase = atom()
-%%%
-%%% @doc <p>This function must be called in order to continue after a
-%%% test case has called <c>break/2</c>. If the paused test case,
-%%% <c>TestCase</c>, executes in a parallel group, this
-%%% function - rather than <c>continue/0</c> - must be used
-%%% in order to let the test case proceed.</p>
continue(TestCase) ->
test_server:continue(TestCase).
-%%%-----------------------------------------------------------------
-%%% @spec remaining_test_procs() -> {TestProcs,SharedGL,OtherGLs}
-%%% TestProcs = [{pid(),GL}]
-%%% GL = SharedGL = pid()
-%%% OtherGLs = [pid()]
-%%%
-%%% @doc <p>This function will return the identity of test- and group
-%%% leader processes that are still running at the time of this call.
-%%% TestProcs are processes in the system that have a Common Test IO
-%%% process as group leader. SharedGL is the central Common Test
-%%% IO process, responsible for printing to log files for configuration
-%%% functions and sequentially executing test cases. OtherGLs are
-%%% Common Test IO processes that print to log files for test cases
-%%% in parallel test case groups.</p>
-%%% <p>The process information returned by this function may be
-%%% used to locate and terminate remaining processes after tests have
-%%% finished executing. The function would typically by called from
-%%% Common Test Hook functions.</p>
-%%% <p>Note that processes that execute configuration functions or
-%%% test cases are never included in TestProcs. It is therefore safe
-%%% to use post configuration hook functions (such as post_end_per_suite,
-%%% post_end_per_group, post_end_per_testcase) to terminate all processes
-%%% in TestProcs that have the current group leader process as its group
-%%% leader.</p>
-%%% <p>Note also that the shared group leader (SharedGL) must never be
-%%% terminated by the user, only by Common Test. Group leader processes
-%%% for parallel test case groups (OtherGLs) may however be terminated
-%%% in post_end_per_group hook functions.</p>
-%%%
remaining_test_procs() ->
ct_util:remaining_test_procs().
diff --git a/lib/common_test/src/ct_config.erl b/lib/common_test/src/ct_config.erl
index 9cb9b0ba16..a07e61199b 100644
--- a/lib/common_test/src/ct_config.erl
+++ b/lib/common_test/src/ct_config.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -592,7 +592,7 @@ encrypt_config_file(SrcFileName, EncryptFileName, {file,KeyFile}) ->
encrypt_config_file(SrcFileName, EncryptFileName, {key,Key}) ->
_ = crypto:start(),
- {Key,IVec} = make_crypto_key(Key),
+ {CryptoKey,IVec} = make_crypto_key(Key),
case file:read_file(SrcFileName) of
{ok,Bin0} ->
Bin1 = term_to_binary({SrcFileName,Bin0}),
@@ -600,7 +600,7 @@ encrypt_config_file(SrcFileName, EncryptFileName, {key,Key}) ->
0 -> Bin1;
N -> list_to_binary([Bin1,random_bytes(8-N)])
end,
- EncBin = crypto:block_encrypt(des3_cbc, Key, IVec, Bin2),
+ EncBin = crypto:block_encrypt(des3_cbc, CryptoKey, IVec, Bin2),
case file:write_file(EncryptFileName, EncBin) of
ok ->
io:format("~ts --(encrypt)--> ~ts~n",
@@ -631,10 +631,10 @@ decrypt_config_file(EncryptFileName, TargetFileName, {file,KeyFile}) ->
decrypt_config_file(EncryptFileName, TargetFileName, {key,Key}) ->
_ = crypto:start(),
- {Key,IVec} = make_crypto_key(Key),
+ {CryptoKey,IVec} = make_crypto_key(Key),
case file:read_file(EncryptFileName) of
{ok,Bin} ->
- DecBin = crypto:block_decrypt(des3_cbc, Key, IVec, Bin),
+ DecBin = crypto:block_decrypt(des3_cbc, CryptoKey, IVec, Bin),
case catch binary_to_term(DecBin) of
{'EXIT',_} ->
{error,bad_file};
@@ -660,7 +660,7 @@ decrypt_config_file(EncryptFileName, TargetFileName, {key,Key}) ->
get_crypt_key_from_file(File) ->
case file:read_file(File) of
{ok,Bin} ->
- case catch string:tokens(binary_to_list(Bin), [$\n,$\r]) of
+ case catch string:lexemes(binary_to_list(Bin), [$\n, [$\r,$\n]]) of
[Key] ->
Key;
_ ->
@@ -694,7 +694,7 @@ get_crypt_key_from_file() ->
noent ->
Result;
_ ->
- case catch string:tokens(binary_to_list(Result), [$\n,$\r]) of
+ case catch string:lexemes(binary_to_list(Result), [$\n, [$\r,$\n]]) of
[Key] ->
io:format("~nCrypt key file: ~ts~n", [FullName]),
Key;
diff --git a/lib/common_test/src/ct_config_plain.erl b/lib/common_test/src/ct_config_plain.erl
index e72b55971b..7b68ac6597 100644
--- a/lib/common_test/src/ct_config_plain.erl
+++ b/lib/common_test/src/ct_config_plain.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -106,7 +106,7 @@ read_config_terms1({done,{eof,EL},_}, L, _, _) ->
read_config_terms1({done,{error,Info,EL},_}, L, _, _) ->
{error,{Info,{L,EL}}};
read_config_terms1({more,_}, L, Terms, Rest) ->
- case string:tokens(Rest, [$\n,$\r,$\t]) of
+ case string:lexemes(Rest, [$\n,[$\r,$\n],$\t]) of
[] ->
lists:reverse(Terms);
_ ->
diff --git a/lib/common_test/src/ct_conn_log_h.erl b/lib/common_test/src/ct_conn_log_h.erl
index cf0a228e1b..3e83020f45 100644
--- a/lib/common_test/src/ct_conn_log_h.erl
+++ b/lib/common_test/src/ct_conn_log_h.erl
@@ -224,7 +224,7 @@ now_to_time({_,_,MicroS}=Now) ->
{calendar:now_to_local_time(Now),MicroS}.
pretty_head({{{Y,Mo,D},{H,Mi,S}},MicroS},ConnMod,Text0) ->
- Text = string:to_upper(atom_to_list(ConnMod) ++ Text0),
+ Text = string:uppercase(atom_to_list(ConnMod) ++ Text0),
io_lib:format("= ~s ==== ~s-~s-~w::~s:~s:~s,~s ",
[Text,t(D),month(Mo),Y,t(H),t(Mi),t(S),
micro2milli(MicroS)]).
@@ -275,7 +275,7 @@ pad0(N,Str) ->
lists:duplicate(N-M,$0) ++ Str.
pad_char_end(N,Str,Char) ->
- case length(lists:flatten(Str)) of
+ case string:length(Str) of
M when M<N -> Str ++ lists:duplicate(N-M,Char);
_ -> Str
end.
diff --git a/lib/common_test/src/ct_cover.erl b/lib/common_test/src/ct_cover.erl
index c258516915..bcd98dcc58 100644
--- a/lib/common_test/src/ct_cover.erl
+++ b/lib/common_test/src/ct_cover.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,11 +18,6 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Framework code coverage support module.
-%%%
-%%% <p>This module exports help functions for performing code
-%%% coverage analysis.</p>
-
-module(ct_cover).
-export([get_spec/1, add_nodes/1, remove_nodes/1, cross_cover_analyse/2]).
@@ -31,16 +26,6 @@
-include_lib("kernel/include/file.hrl").
-%%%-----------------------------------------------------------------
-%%% @spec add_nodes(Nodes) -> {ok,StartedNodes} | {error,Reason}
-%%% Nodes = [atom()]
-%%% StartedNodes = [atom()]
-%%% Reason = cover_not_running | not_main_node
-%%%
-%%% @doc Add nodes to current cover test (only works if cover support
-%%% is active!). To have effect, this function should be called
-%%% from init_per_suite/1 before any actual tests are performed.
-%%%
add_nodes([]) ->
{ok,[]};
add_nodes(Nodes) ->
@@ -67,17 +52,6 @@ add_nodes(Nodes) ->
end
end.
-
-%%%-----------------------------------------------------------------
-%%% @spec remove_nodes(Nodes) -> ok | {error,Reason}
-%%% Nodes = [atom()]
-%%% Reason = cover_not_running | not_main_node
-%%%
-%%% @doc Remove nodes from current cover test. Call this function
-%%% to stop cover test on nodes previously added with add_nodes/1.
-%%% Results on the remote node are transferred to the Common Test
-%%% node.
-%%%
remove_nodes([]) ->
ok;
remove_nodes(Nodes) ->
@@ -103,25 +77,11 @@ remove_nodes(Nodes) ->
end
end.
-
-%%%-----------------------------------------------------------------
-%%% @spec cross_cover_analyse(Level,Tests) -> ok
-%%% Level = overview | details
-%%% Tests = [{Tag,Dir}]
-%%% Tag = atom()
-%%% Dir = string()
-%%%
-%%% @doc Accumulate cover results over multiple tests.
-%%% See the chapter about <seealso
-%%% marker="cover_chapter#cross_cover">cross cover
-%%% analysis</seealso> in the users's guide.
-%%%
cross_cover_analyse(Level,Tests) ->
test_server_ctrl:cross_cover_analyse(Level,Tests).
%%%-----------------------------------------------------------------
-%%% @hidden
%% Read cover specification file and return the parsed info.
%% -> CoverSpec: {CoverFile,Nodes,Import,Export,AppCoverInfo}
@@ -302,6 +262,11 @@ get_app_info(App=#cover{app=Name}, [{src_files,Name,Src1}|Terms], Dir) ->
Src = App#cover.src,
get_app_info(App#cover{src=Src++Src1},Terms,Dir);
+get_app_info(App=#cover{app=none}, [{local_only,Bool}|Terms], Dir) ->
+ get_app_info(App, [{local_only,none,Bool}|Terms], Dir);
+get_app_info(App=#cover{app=Name}, [{local_only,Name,Bool}|Terms], Dir) ->
+ get_app_info(App#cover{local_only=Bool},Terms,Dir);
+
get_app_info(App, [_|Terms], Dir) ->
get_app_info(App, Terms, Dir);
diff --git a/lib/common_test/src/ct_default_gl.erl b/lib/common_test/src/ct_default_gl.erl
index 9ae430c546..cf1bcc058d 100644
--- a/lib/common_test/src/ct_default_gl.erl
+++ b/lib/common_test/src/ct_default_gl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/src/ct_event.erl b/lib/common_test/src/ct_event.erl
index 8b5bba7600..3689c6bc45 100644
--- a/lib/common_test/src/ct_event.erl
+++ b/lib/common_test/src/ct_event.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,14 +18,14 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Framework Event Handler
+%%% doc Common Test Framework Event Handler
%%%
-%%% <p>This module implements an event handler that CT uses to
+%%% This module implements an event handler that CT uses to
%%% handle status and progress notifications during test runs.
%%% The notifications are handled locally (per node) and passed
%%% on to ct_master when CT runs in distributed mode. This
%%% module may be used as a template for other event handlers
-%%% that can be plugged in to handle local logging and reporting.</p>
+%%% that can be plugged in to handle local logging and reporting.
-module(ct_event).
-behaviour(gen_event).
diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl
index 6066470233..bce6420042 100644
--- a/lib/common_test/src/ct_framework.erl
+++ b/lib/common_test/src/ct_framework.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,10 +18,10 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Framework callback module.
+%%% Common Test Framework callback module.
%%%
-%%% <p>This module exports framework callback functions which are
-%%% called from the test_server.</p>
+%%% This module exports framework callback functions which are
+%%% called from the test_server.
-module(ct_framework).
@@ -42,7 +42,7 @@
-define(rev(L), lists:reverse(L)).
%%%-----------------------------------------------------------------
-%%% @spec init_tc(Mod,Func,Args) -> {ok,NewArgs} | {error,Reason} |
+%%% -spec init_tc(Mod,Func,Args) -> {ok,NewArgs} | {error,Reason} |
%%% {skip,Reason} | {auto_skip,Reason}
%%% Mod = atom()
%%% Func = atom()
@@ -50,7 +50,7 @@
%%% NewArgs = list()
%%% Reason = term()
%%%
-%%% @doc Test server framework callback, called by the test_server
+%%% Test server framework callback, called by the test_server
%%% when a new test case is started.
init_tc(_,{end_per_testcase_not_run,_},[Config]) ->
%% Testcase is completed (skipped or failed), but end_per_testcase
@@ -314,8 +314,8 @@ add_defaults(Mod,Func, GroupPath) ->
ErrStr = io_lib:format("~n*** ERROR *** "
"~w:suite/0 failed: ~tp~n",
[Suite,Reason]),
- io:format(ErrStr, []),
- io:format(?def_gl, ErrStr, []),
+ io:format("~ts", [ErrStr]),
+ io:format(?def_gl, "~ts", [ErrStr]),
{suite0_failed,{exited,Reason}};
SuiteInfo when is_list(SuiteInfo) ->
case lists:all(fun(E) when is_tuple(E) -> true;
@@ -337,16 +337,16 @@ add_defaults(Mod,Func, GroupPath) ->
"Invalid return value from "
"~w:suite/0: ~tp~n",
[Suite,SuiteInfo]),
- io:format(ErrStr, []),
- io:format(?def_gl, ErrStr, []),
+ io:format("~ts", [ErrStr]),
+ io:format(?def_gl, "~ts", [ErrStr]),
{suite0_failed,bad_return_value}
end;
SuiteInfo ->
ErrStr = io_lib:format("~n*** ERROR *** "
"Invalid return value from "
"~w:suite/0: ~tp~n", [Suite,SuiteInfo]),
- io:format(ErrStr, []),
- io:format(?def_gl, ErrStr, []),
+ io:format("~ts", [ErrStr]),
+ io:format(?def_gl, "~ts", [ErrStr]),
{suite0_failed,bad_return_value}
end.
@@ -373,8 +373,8 @@ add_defaults1(Mod,Func, GroupPath, SuiteInfo) ->
"Invalid return value from "
"~w:group(~tw): ~tp~n",
[Mod,GrName,BadGr0Val]),
- io:format(Gr0ErrStr, []),
- io:format(?def_gl, Gr0ErrStr, []),
+ io:format("~ts", [Gr0ErrStr]),
+ io:format(?def_gl, "~ts", [Gr0ErrStr]),
{group0_failed,bad_return_value};
_ ->
Args = if Func == init_per_group ; Func == end_per_group ->
@@ -395,8 +395,8 @@ add_defaults1(Mod,Func, GroupPath, SuiteInfo) ->
"Invalid return value from "
"~w:~tw/0: ~tp~n",
[Mod,Func,BadTC0Val]),
- io:format(TC0ErrStr, []),
- io:format(?def_gl, TC0ErrStr, []),
+ io:format("~ts", [TC0ErrStr]),
+ io:format(?def_gl, "~ts", [TC0ErrStr]),
{testcase0_failed,bad_return_value};
_ ->
%% let test case info (also for all config funcs) override
@@ -649,7 +649,7 @@ try_set_default(Name,Key,Info,Where) ->
%%%-----------------------------------------------------------------
-%%% @spec end_tc(Mod,Func,Args) -> {ok,NewArgs}| {error,Reason} |
+%%% -spec end_tc(Mod,Func,Args) -> {ok,NewArgs}| {error,Reason} |
%%% {skip,Reason} | {auto_skip,Reason}
%%% Mod = atom()
%%% Func = atom()
@@ -657,7 +657,7 @@ try_set_default(Name,Key,Info,Where) ->
%%% NewArgs = list()
%%% Reason = term()
%%%
-%%% @doc Test server framework callback, called by the test_server
+%%% Test server framework callback, called by the test_server
%%% when a test case is finished.
end_tc(Mod, Fun, Args) ->
%% Have to keep end_tc/3 for backwards compatibility issues
@@ -696,9 +696,16 @@ end_tc(Mod,IPTC={init_per_testcase,_Func},_TCPid,Result,Args,Return) ->
end
end;
-end_tc(Mod,Func0,TCPid,Result,Args,Return) ->
+end_tc(Mod,Func00,TCPid,Result,Args,Return) ->
%% in case Mod == ct_framework, lookup the suite name
Suite = get_suite_name(Mod, Args),
+ {OnlyCleanup,Func0} =
+ case Func00 of
+ {cleanup,F0} ->
+ {true,F0};
+ _ ->
+ {false,Func00}
+ end,
{Func,FuncSpec,HookFunc} =
case Func0 of
{end_per_testcase_not_run,F} ->
@@ -742,6 +749,8 @@ end_tc(Mod,Func0,TCPid,Result,Args,Return) ->
case HookFunc of
undefined ->
{ok,Result};
+ _ when OnlyCleanup ->
+ {ok,Result};
_ ->
case ct_hooks:end_tc(Suite,HookFunc,Args,Result,Return) of
'$ct_no_change' ->
@@ -752,6 +761,8 @@ end_tc(Mod,Func0,TCPid,Result,Args,Return) ->
end,
FinalResult =
case get('$test_server_framework_test') of
+ _ when OnlyCleanup ->
+ Result1;
undefined ->
%% send sync notification so that event handlers may print
%% in the log file before it gets closed
@@ -903,15 +914,15 @@ tag(_Other) ->
ok.
%%%-----------------------------------------------------------------
-%%% @spec error_notification(Mod,Func,Args,Error) -> ok
+%%% -spec error_notification(Mod,Func,Args,Error) -> ok
%%% Mod = atom()
%%% Func = atom()
%%% Args = list()
%%% Error = term()
%%%
-%%% @doc This function is called as the result of testcase
-%%% <code>Func</code> in suite <code>Mod</code> crashing.
-%%% <code>Error</code> specifies the reason for failing.
+%%% This function is called as the result of testcase
+%%% Func in suite Mod crashing.
+%%% Error specifies the reason for failing.
error_notification(Mod,Func,_Args,{Error,Loc}) ->
ErrorSpec = case Error of
{What={_E,_R},Trace} when is_list(Trace) ->
@@ -921,9 +932,10 @@ error_notification(Mod,Func,_Args,{Error,Loc}) ->
end,
ErrorStr = case ErrorSpec of
{badmatch,Descr} ->
- Descr1 = lists:flatten(io_lib:format("~tP",[Descr,10])),
- if length(Descr1) > 50 ->
- Descr2 = string:substr(Descr1,1,50),
+ Descr1 = io_lib:format("~tP",[Descr,10]),
+ DescrLength = string:length(Descr1),
+ if DescrLength > 50 ->
+ Descr2 = string:slice(Descr1,0,50),
io_lib:format("{badmatch,~ts...}",[Descr2]);
true ->
io_lib:format("{badmatch,~ts}",[Descr1])
@@ -971,11 +983,10 @@ error_notification(Mod,Func,_Args,{Error,Loc}) ->
end,
PrintError = fun(ErrorFormat, ErrorArgs) ->
- Div = "~n- - - - - - - - - - - - - - - - - - - "
- "- - - - - - - - - - - - - - - - - - - - -~n",
+ Div = "\n- - - - - - - - - - - - - - - - - - - "
+ "- - - - - - - - - - - - - - - - - - - - -\n",
ErrorStr2 = io_lib:format(ErrorFormat, ErrorArgs),
- io:format(?def_gl, lists:concat([Div,ErrorStr2,Div,"~n"]),
- []),
+ io:format(?def_gl, "~ts~n", [lists:concat([Div,ErrorStr2,Div])]),
Link =
"\n\n<a href=\"#end\">"
"Full error description and stacktrace"
@@ -984,7 +995,8 @@ error_notification(Mod,Func,_Args,{Error,Loc}) ->
ct_logs:tc_log(ct_error_notify,
?MAX_IMPORTANCE,
"CT Error Notification",
- ErrorHtml2++Link, [], [])
+ "~ts", [ErrorHtml2++Link],
+ [])
end,
case Loc of
[{?MODULE,error_in_suite}] ->
@@ -1048,28 +1060,47 @@ group_or_func(Func, _Config) ->
Func.
%%%-----------------------------------------------------------------
-%%% @spec get_suite(Mod, Func) -> Tests
+%%% -spec get_suite(Mod, Func) -> Tests
%%%
-%%% @doc Called from test_server for every suite (<code>Func==all</code>)
-%%% and every test case. If the former, all test cases in the suite
-%%% should be returned.
+%%% Called from test_server for every suite (Func==all)
+%%% and every test case. If the former, all test cases in the suite
+%%% should be returned.
get_suite(Mod, all) ->
- case catch apply(Mod, groups, []) of
- {'EXIT',_} ->
- get_all(Mod, []);
- GroupDefs when is_list(GroupDefs) ->
- case catch ct_groups:find_groups(Mod, all, all, GroupDefs) of
- {error,_} = Error ->
- %% this makes test_server call error_in_suite as first
- %% (and only) test case so we can report Error properly
- [{?MODULE,error_in_suite,[[Error]]}];
- ConfTests ->
- get_all(Mod, ConfTests)
- end;
- _ ->
+ case safe_apply_groups_0(Mod,{ok,[]}) of
+ {ok,GroupDefs} ->
+ try ct_groups:find_groups(Mod, all, all, GroupDefs) of
+ ConfTests when is_list(ConfTests) ->
+ get_all(Mod, ConfTests)
+ catch
+ throw:{error,Error} ->
+ [{?MODULE,error_in_suite,[[{error,Error}]]}];
+ _:Error:S ->
+ [{?MODULE,error_in_suite,[[{error,{Error,S}}]]}]
+ end;
+ {error,{bad_return,_Bad}} ->
E = "Bad return value from "++atom_to_list(Mod)++":groups/0",
- [{?MODULE,error_in_suite,[[{error,list_to_atom(E)}]]}]
+ [{?MODULE,error_in_suite,[[{error,list_to_atom(E)}]]}];
+ {error,{bad_hook_return,Bad}} ->
+ E = "Bad return value from post_groups/2 hook function",
+ [{?MODULE,error_in_suite,[[{error,{list_to_atom(E),Bad}}]]}];
+ {error,{failed,ExitReason}} ->
+ case ct_util:get_testdata({error_in_suite,Mod}) of
+ undefined ->
+ ErrStr = io_lib:format("~n*** ERROR *** "
+ "~w:groups/0 failed: ~p~n",
+ [Mod,ExitReason]),
+ io:format(?def_gl, ErrStr, []),
+ %% save the error info so it doesn't get printed twice
+ ct_util:set_testdata_async({{error_in_suite,Mod},
+ ExitReason});
+ _ExitReason ->
+ ct_util:delete_testdata({error_in_suite,Mod})
+ end,
+ Reason = list_to_atom(atom_to_list(Mod)++":groups/0 failed"),
+ [{?MODULE,error_in_suite,[[{error,Reason}]]}];
+ {error,What} ->
+ [{?MODULE,error_in_suite,[[{error,What}]]}]
end;
%%!============================================================
@@ -1079,54 +1110,74 @@ get_suite(Mod, all) ->
%% group
get_suite(Mod, Group={conf,Props,_Init,TCs,_End}) ->
- Name = ?val(name, Props),
- case catch apply(Mod, groups, []) of
- {'EXIT',_} ->
- [Group];
- GroupDefs when is_list(GroupDefs) ->
- case catch ct_groups:find_groups(Mod, Name, TCs, GroupDefs) of
- {error,_} = Error ->
- %% this makes test_server call error_in_suite as first
- %% (and only) test case so we can report Error properly
- [{?MODULE,error_in_suite,[[Error]]}];
- [] ->
- [];
- ConfTests ->
- case lists:member(skipped, Props) of
- true ->
- %% a *subgroup* specified *only* as skipped (and not
- %% as an explicit test) should not be returned, or
- %% init/end functions for top groups will be executed
- case catch ?val(name, element(2, hd(ConfTests))) of
- Name -> % top group
- ct_groups:delete_subs(ConfTests, ConfTests);
- _ ->
- []
- end;
- false ->
- ConfTests1 = ct_groups:delete_subs(ConfTests,
- ConfTests),
- case ?val(override, Props) of
- undefined ->
- ConfTests1;
- [] ->
- ConfTests1;
- ORSpec ->
- ORSpec1 = if is_tuple(ORSpec) -> [ORSpec];
- true -> ORSpec end,
- ct_groups:search_and_override(ConfTests1,
- ORSpec1, Mod)
- end
- end
- end;
- _ ->
+ case safe_apply_groups_0(Mod,{ok,[Group]}) of
+ {ok,GroupDefs} ->
+ Name = ?val(name, Props),
+ try ct_groups:find_groups(Mod, Name, TCs, GroupDefs) of
+ [] ->
+ [];
+ ConfTests when is_list(ConfTests) ->
+ case lists:member(skipped, Props) of
+ true ->
+ %% a *subgroup* specified *only* as skipped (and not
+ %% as an explicit test) should not be returned, or
+ %% init/end functions for top groups will be executed
+ try ?val(name, element(2, hd(ConfTests))) of
+ Name -> % top group
+ ct_groups:delete_subs(ConfTests, ConfTests);
+ _ -> []
+ catch
+ _:_ -> []
+ end;
+ false ->
+ ConfTests1 = ct_groups:delete_subs(ConfTests,
+ ConfTests),
+ case ?val(override, Props) of
+ undefined ->
+ ConfTests1;
+ [] ->
+ ConfTests1;
+ ORSpec ->
+ ORSpec1 = if is_tuple(ORSpec) -> [ORSpec];
+ true -> ORSpec end,
+ ct_groups:search_and_override(ConfTests1,
+ ORSpec1, Mod)
+ end
+ end
+ catch
+ throw:{error,Error} ->
+ [{?MODULE,error_in_suite,[[{error,Error}]]}];
+ _:Error:S ->
+ [{?MODULE,error_in_suite,[[{error,{Error,S}}]]}]
+ end;
+ {error,{bad_return,_Bad}} ->
E = "Bad return value from "++atom_to_list(Mod)++":groups/0",
- [{?MODULE,error_in_suite,[[{error,list_to_atom(E)}]]}]
+ [{?MODULE,error_in_suite,[[{error,list_to_atom(E)}]]}];
+ {error,{bad_hook_return,Bad}} ->
+ E = "Bad return value from post_groups/2 hook function",
+ [{?MODULE,error_in_suite,[[{error,{list_to_atom(E),Bad}}]]}];
+ {error,{failed,ExitReason}} ->
+ case ct_util:get_testdata({error_in_suite,Mod}) of
+ undefined ->
+ ErrStr = io_lib:format("~n*** ERROR *** "
+ "~w:groups/0 failed: ~p~n",
+ [Mod,ExitReason]),
+ io:format(?def_gl, ErrStr, []),
+ %% save the error info so it doesn't get printed twice
+ ct_util:set_testdata_async({{error_in_suite,Mod},
+ ExitReason});
+ _ExitReason ->
+ ct_util:delete_testdata({error_in_suite,Mod})
+ end,
+ Reason = list_to_atom(atom_to_list(Mod)++":groups/0 failed"),
+ [{?MODULE,error_in_suite,[[{error,Reason}]]}];
+ {error,What} ->
+ [{?MODULE,error_in_suite,[[{error,What}]]}]
end;
%% testcase
get_suite(Mod, Name) ->
- get_seq(Mod, Name).
+ get_seq(Mod, Name).
%%%-----------------------------------------------------------------
@@ -1160,27 +1211,54 @@ get_all_cases1(_, []) ->
%%%-----------------------------------------------------------------
-get_all(Mod, ConfTests) ->
- case catch apply(Mod, all, []) of
- {'EXIT',{undef,[{Mod,all,[],_} | _]}} ->
+get_all(Mod, ConfTests) ->
+ case safe_apply_all_0(Mod) of
+ {ok,AllTCs} ->
+ %% expand group references using ConfTests
+ try ct_groups:expand_groups(AllTCs, ConfTests, Mod) of
+ {error,_} = Error ->
+ [{?MODULE,error_in_suite,[[Error]]}];
+ Tests0 ->
+ Tests = ct_groups:delete_subs(Tests0, Tests0),
+ expand_tests(Mod, Tests)
+ catch
+ throw:{error,Error} ->
+ [{?MODULE,error_in_suite,[[{error,Error}]]}];
+ _:Error:S ->
+ [{?MODULE,error_in_suite,[[{error,{Error,S}}]]}]
+ end;
+ Skip = {skip,_Reason} ->
+ Skip;
+ {error,undef} ->
+ Reason =
+ case code:which(Mod) of
+ non_existing ->
+ list_to_atom(
+ atom_to_list(Mod)++
+ " cannot be compiled or loaded");
+ _ ->
+ list_to_atom(
+ atom_to_list(Mod)++":all/0 is missing")
+ end,
+ %% this makes test_server call error_in_suite as first
+ %% (and only) test case so we can report Reason properly
+ [{?MODULE,error_in_suite,[[{error,Reason}]]}];
+ {error,{bad_return,_Bad}} ->
Reason =
- case code:which(Mod) of
- non_existing ->
- list_to_atom(atom_to_list(Mod)++
- " can not be compiled or loaded");
- _ ->
- list_to_atom(atom_to_list(Mod)++":all/0 is missing")
- end,
- %% this makes test_server call error_in_suite as first
- %% (and only) test case so we can report Reason properly
+ list_to_atom("Bad return value from "++
+ atom_to_list(Mod)++":all/0"),
[{?MODULE,error_in_suite,[[{error,Reason}]]}];
- {'EXIT',ExitReason} ->
+ {error,{bad_hook_return,Bad}} ->
+ Reason =
+ list_to_atom("Bad return value from post_all/3 hook function"),
+ [{?MODULE,error_in_suite,[[{error,{Reason,Bad}}]]}];
+ {error,{failed,ExitReason}} ->
case ct_util:get_testdata({error_in_suite,Mod}) of
undefined ->
ErrStr = io_lib:format("~n*** ERROR *** "
"~w:all/0 failed: ~tp~n",
[Mod,ExitReason]),
- io:format(?def_gl, ErrStr, []),
+ io:format(?def_gl, "~ts", [ErrStr]),
%% save the error info so it doesn't get printed twice
ct_util:set_testdata_async({{error_in_suite,Mod},
ExitReason});
@@ -1191,28 +1269,8 @@ get_all(Mod, ConfTests) ->
%% this makes test_server call error_in_suite as first
%% (and only) test case so we can report Reason properly
[{?MODULE,error_in_suite,[[{error,Reason}]]}];
- AllTCs when is_list(AllTCs) ->
- case catch save_seqs(Mod,AllTCs) of
- {error,What} ->
- [{?MODULE,error_in_suite,[[{error,What}]]}];
- SeqsAndTCs ->
- %% expand group references in all() using ConfTests
- case catch ct_groups:expand_groups(SeqsAndTCs,
- ConfTests,
- Mod) of
- {error,_} = Error ->
- [{?MODULE,error_in_suite,[[Error]]}];
- Tests ->
- ct_groups:delete_subs(Tests, Tests)
- end
- end;
- Skip = {skip,_Reason} ->
- Skip;
- _ ->
- Reason =
- list_to_atom("Bad return value from "++
- atom_to_list(Mod)++":all/0"),
- [{?MODULE,error_in_suite,[[{error,Reason}]]}]
+ {error,What} ->
+ [{?MODULE,error_in_suite,[[{error,What}]]}]
end.
%%!============================================================
@@ -1354,7 +1412,7 @@ end_per_group(GroupName, _) ->
ok.
%%%-----------------------------------------------------------------
-%%% @spec report(What,Data) -> ok
+%%% -spec report(What,Data) -> ok
report(What,Data) ->
case What of
loginfo ->
@@ -1518,14 +1576,14 @@ add_to_stats(Result) ->
ct_util:update_testdata(stats, Update).
%%%-----------------------------------------------------------------
-%%% @spec warn(What) -> true | false
+%%% -spec warn(What) -> true | false
warn(What) when What==nodes; What==processes ->
false;
warn(_What) ->
true.
%%%-----------------------------------------------------------------
-%%% @spec add_data_dir(File0, Config) -> File1
+%%% -spec add_data_dir(File0, Config) -> File1
add_data_dir(File,Config) when is_atom(File) ->
add_data_dir(atom_to_list(File),Config);
@@ -1544,7 +1602,7 @@ add_data_dir(File,Config) when is_list(File) ->
end.
%%%-----------------------------------------------------------------
-%%% @spec get_logopts() -> [LogOpt]
+%%% -spec get_logopts() -> [LogOpt]
get_logopts() ->
case ct_util:get_testdata(logopts) of
undefined ->
@@ -1554,12 +1612,12 @@ get_logopts() ->
end.
%%%-----------------------------------------------------------------
-%%% @spec format_comment(Comment) -> HtmlComment
+%%% -spec format_comment(Comment) -> HtmlComment
format_comment(Comment) ->
"<font color=\"green\">" ++ Comment ++ "</font>".
%%%-----------------------------------------------------------------
-%%% @spec get_html_wrapper(TestName, PrintLabel, Cwd) -> Header
+%%% -spec get_html_wrapper(TestName, PrintLabel, Cwd) -> Header
get_html_wrapper(TestName, PrintLabel, Cwd, TableCols) ->
get_html_wrapper(TestName, PrintLabel, Cwd, TableCols, utf8).
@@ -1567,6 +1625,77 @@ get_html_wrapper(TestName, PrintLabel, Cwd, TableCols, Encoding) ->
ct_logs:get_ts_html_wrapper(TestName, PrintLabel, Cwd, TableCols, Encoding).
%%%-----------------------------------------------------------------
-%%% @spec get_log_dir() -> {ok,LogDir}
+%%% -spec get_log_dir() -> {ok,LogDir}
get_log_dir() ->
ct_logs:get_log_dir(true).
+
+%%%-----------------------------------------------------------------
+%%% Call all and group callbacks and post_* hooks with error handling
+safe_apply_all_0(Mod) ->
+ try apply(Mod, all, []) of
+ AllTCs0 when is_list(AllTCs0) ->
+ try save_seqs(Mod,AllTCs0) of
+ SeqsAndTCs when is_list(SeqsAndTCs) ->
+ all_hook(Mod,SeqsAndTCs)
+ catch throw:{error,What} ->
+ {error,What}
+ end;
+ {skip,_}=Skip ->
+ all_hook(Mod,Skip);
+ Bad ->
+ {error,{bad_return,Bad}}
+ catch
+ _:Reason:Stacktrace ->
+ handle_callback_crash(Reason,Stacktrace,Mod,all,{error,undef})
+ end.
+
+all_hook(Mod, All) ->
+ case ct_hooks:all(Mod, All) of
+ AllTCs when is_list(AllTCs) ->
+ {ok,AllTCs};
+ {skip,_}=Skip ->
+ Skip;
+ {fail,Reason} ->
+ {error,Reason};
+ Bad ->
+ {error,{bad_hook_return,Bad}}
+ end.
+
+safe_apply_groups_0(Mod,Default) ->
+ try apply(Mod, groups, []) of
+ GroupDefs when is_list(GroupDefs) ->
+ case ct_hooks:groups(Mod, GroupDefs) of
+ GroupDefs1 when is_list(GroupDefs1) ->
+ {ok,GroupDefs1};
+ {fail,Reason} ->
+ {error,Reason};
+ Bad ->
+ {error,{bad_hook_return,Bad}}
+ end;
+ Bad ->
+ {error,{bad_return,Bad}}
+ catch
+ _:Reason:Stacktrace ->
+ handle_callback_crash(Reason,Stacktrace,Mod,groups,Default)
+ end.
+
+handle_callback_crash(undef,[{Mod,Func,[],_}|_],Mod,Func,Default) ->
+ case ct_hooks:Func(Mod, []) of
+ [] ->
+ Default;
+ List when is_list(List) ->
+ {ok,List};
+ {fail,Reason} ->
+ {error,Reason};
+ Bad ->
+ {error,{bad_hook_return,Bad}}
+ end;
+handle_callback_crash(Reason,Stacktrace,_Mod,_Func,_Default) ->
+ {error,{failed,{Reason,Stacktrace}}}.
+
+expand_tests(Mod, [{testcase,Case,[Prop]}|Tests]) ->
+ [{repeat,{Mod,Case},Prop}|expand_tests(Mod,Tests)];
+expand_tests(Mod,[Test|Tests]) ->
+ [Test|expand_tests(Mod,Tests)];
+expand_tests(_Mod,[]) ->
+ [].
diff --git a/lib/common_test/src/ct_ftp.erl b/lib/common_test/src/ct_ftp.erl
index 8effb06e7e..93d1f88041 100644
--- a/lib/common_test/src/ct_ftp.erl
+++ b/lib/common_test/src/ct_ftp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,12 +18,6 @@
%% %CopyrightEnd%
%%
-%%% @doc FTP client module (based on the FTP support of the INETS application).
-%%%
-%%% @type connection() = handle() | ct:target_name()
-%%% @type handle() = ct_gen_conn:handle(). Handle for a specific
-%%% ftp connection.
-
-module(ct_ftp).
%% API
@@ -42,76 +36,14 @@
%%%=================================================================
%%% API
-%%%-----------------------------------------------------------------
-%%% @spec put(KeyOrName,LocalFile,RemoteFile) -> ok | {error,Reason}
-%%% KeyOrName = Key | Name
-%%% Key = atom()
-%%% Name = ct:target_name()
-%%% LocalFile = string()
-%%% RemoteFile = string()
-%%%
-%%% @doc Open a ftp connection and send a file to the remote host.
-%%%
-%%% <p><code>LocalFile</code> and <code>RemoteFile</code> must be
-%%% absolute paths.</p>
-%%%
-%%% <p>If the target host is a "special" node, the ftp address must be
-%%% specified in the config file like this:</p>
-%%% <pre>
-%%% {node,[{ftp,IpAddr}]}.</pre>
-%%%
-%%% <p>If the target host is something else, e.g. a unix host, the
-%%% config file must also include the username and password (both
-%%% strings):</p>
-%%% <pre>
-%%% {unix,[{ftp,IpAddr},
-%%% {username,Username},
-%%% {password,Password}]}.</pre>
-%%% @see ct:require/2
put(KeyOrName,LocalFile,RemoteFile) ->
Fun = fun(Ftp) -> send(Ftp,LocalFile,RemoteFile) end,
open_and_do(KeyOrName,Fun).
-%%%-----------------------------------------------------------------
-%%% @spec get(KeyOrName,RemoteFile,LocalFile) -> ok | {error,Reason}
-%%% KeyOrName = Key | Name
-%%% Key = atom()
-%%% Name = ct:target_name()
-%%% RemoteFile = string()
-%%% LocalFile = string()
-%%%
-%%% @doc Open a ftp connection and fetch a file from the remote host.
-%%%
-%%% <p><code>RemoteFile</code> and <code>LocalFile</code> must be
-%%% absolute paths.</p>
-%%%
-%%% <p>The config file must be as for put/3.</p>
-%%% @see put/3
-%%% @see ct:require/2
get(KeyOrName,RemoteFile,LocalFile) ->
Fun = fun(Ftp) -> recv(Ftp,RemoteFile,LocalFile) end,
open_and_do(KeyOrName,Fun).
-
-%%%-----------------------------------------------------------------
-%%% @spec open(KeyOrName) -> {ok,Handle} | {error,Reason}
-%%% KeyOrName = Key | Name
-%%% Key = atom()
-%%% Name = ct:target_name()
-%%% Handle = handle()
-%%%
-%%% @doc Open an FTP connection to the specified node.
-%%% <p>You can open one connection for a particular <code>Name</code> and
-%%% use the same name as reference for all subsequent operations. If you
-%%% want the connection to be associated with <code>Handle</code> instead
-%%% (in case you need to open multiple connections to a host for example),
-%%% simply use <code>Key</code>, the configuration variable name, to
-%%% specify the target. Note that a connection that has no associated target
-%%% name can only be closed with the handle value.</p>
-%%%
-%%% <p>See <c>ct:require/2</c> for how to create a new <c>Name</c></p>
-%%%
-%%% @see ct:require/2
open(KeyOrName) ->
case ct_util:get_key_from_name(KeyOrName) of
{ok,node} ->
@@ -152,25 +84,9 @@ open(KeyOrName,Username,Password) ->
ct_gen_conn:start(KeyOrName,full_addr(Addr),{Username,Password},?MODULE)
end.
-
-%%%-----------------------------------------------------------------
-%%% @spec send(Connection,LocalFile) -> ok | {error,Reason}
-%%%
-%%% @doc Send a file over FTP.
-%%% <p>The file will get the same name on the remote host.</p>
-%%% @see send/3
send(Connection,LocalFile) ->
send(Connection,LocalFile,filename:basename(LocalFile)).
-%%%-----------------------------------------------------------------
-%%% @spec send(Connection,LocalFile,RemoteFile) -> ok | {error,Reason}
-%%% Connection = connection()
-%%% LocalFile = string()
-%%% RemoteFile = string()
-%%%
-%%% @doc Send a file over FTP.
-%%%
-%%% <p>The file will be named <code>RemoteFile</code> on the remote host.</p>
send(Connection,LocalFile,RemoteFile) ->
case get_handle(Connection) of
{ok,Pid} ->
@@ -179,24 +95,9 @@ send(Connection,LocalFile,RemoteFile) ->
Error
end.
-%%%-----------------------------------------------------------------
-%%% @spec recv(Connection,RemoteFile) -> ok | {error,Reason}
-%%%
-%%% @doc Fetch a file over FTP.
-%%% <p>The file will get the same name on the local host.</p>
-%%% @see recv/3
recv(Connection,RemoteFile) ->
recv(Connection,RemoteFile,filename:basename(RemoteFile)).
-%%%-----------------------------------------------------------------
-%%% @spec recv(Connection,RemoteFile,LocalFile) -> ok | {error,Reason}
-%%% Connection = connection()
-%%% RemoteFile = string()
-%%% LocalFile = string()
-%%%
-%%% @doc Fetch a file over FTP.
-%%%
-%%% <p>The file will be named <code>LocalFile</code> on the local host.</p>
recv(Connection,RemoteFile,LocalFile) ->
case get_handle(Connection) of
{ok,Pid} ->
@@ -205,12 +106,6 @@ recv(Connection,RemoteFile,LocalFile) ->
Error
end.
-%%%-----------------------------------------------------------------
-%%% @spec cd(Connection,Dir) -> ok | {error,Reason}
-%%% Connection = connection()
-%%% Dir = string()
-%%%
-%%% @doc Change directory on remote host.
cd(Connection,Dir) ->
case get_handle(Connection) of
{ok,Pid} ->
@@ -219,13 +114,6 @@ cd(Connection,Dir) ->
Error
end.
-%%%-----------------------------------------------------------------
-%%% @spec ls(Connection,Dir) -> {ok,Listing} | {error,Reason}
-%%% Connection = connection()
-%%% Dir = string()
-%%% Listing = string()
-%%%
-%%% @doc List the directory Dir.
ls(Connection,Dir) ->
case get_handle(Connection) of
{ok,Pid} ->
@@ -234,12 +122,6 @@ ls(Connection,Dir) ->
Error
end.
-%%%-----------------------------------------------------------------
-%%% @spec type(Connection,Type) -> ok | {error,Reason}
-%%% Connection = connection()
-%%% Type = ascii | binary
-%%%
-%%% @doc Change file transfer type
type(Connection,Type) ->
case get_handle(Connection) of
{ok,Pid} ->
@@ -248,12 +130,6 @@ type(Connection,Type) ->
Error
end.
-%%%-----------------------------------------------------------------
-%%% @spec delete(Connection,File) -> ok | {error,Reason}
-%%% Connection = connection()
-%%% File = string()
-%%%
-%%% @doc Delete a file on remote host
delete(Connection,File) ->
case get_handle(Connection) of
{ok,Pid} ->
@@ -262,11 +138,6 @@ delete(Connection,File) ->
Error
end.
-%%%-----------------------------------------------------------------
-%%% @spec close(Connection) -> ok | {error,Reason}
-%%% Connection = connection()
-%%%
-%%% @doc Close the FTP connection.
close(Connection) ->
case get_handle(Connection) of
{ok,Pid} ->
@@ -279,21 +150,20 @@ close(Connection) ->
%%%=================================================================
%%% Callback functions
-%% @hidden
init(KeyOrName,{IP,Port},{Username,Password}) ->
case ftp_connect(IP,Port,Username,Password) of
{ok,FtpPid} ->
log(heading(init,KeyOrName),
"Opened ftp connection:\nIP: ~tp\nUsername: ~tp\nPassword: ~p\n",
- [IP,Username,lists:duplicate(length(Password),$*)]),
+ [IP,Username,lists:duplicate(string:length(Password),$*)]),
{ok,FtpPid,#state{ftp_pid=FtpPid,target_name=KeyOrName}};
Error ->
Error
end.
ftp_connect(IP,Port,Username,Password) ->
- _ = inets:start(),
- case inets:start(ftpc,[{host,IP},{port,Port}]) of
+ _ = ftp:start(),
+ case ftp:start_service([{host,IP},{port,Port}]) of
{ok,FtpPid} ->
case ftp:user(FtpPid,Username,Password) of
ok ->
@@ -305,7 +175,6 @@ ftp_connect(IP,Port,Username,Password) ->
{error,{open,Reason}}
end.
-%% @hidden
handle_msg({send,LocalFile,RemoteFile},State) ->
log(heading(send,State#state.target_name),
"LocalFile: ~tp\nRemoteFile: ~tp\n",[LocalFile,RemoteFile]),
@@ -333,15 +202,13 @@ handle_msg({delete,File},State) ->
Result = ftp:delete(State#state.ftp_pid,File),
{Result,State}.
-%% @hidden
reconnect(_Addr,_State) ->
{error,no_reconnection_of_ftp}.
-%% @hidden
terminate(FtpPid,State) ->
log(heading(terminate,State#state.target_name),
"Closing FTP connection.\nHandle: ~p\n",[FtpPid]),
- inets:stop(ftpc,FtpPid).
+ ftp:stop_service(FtpPid).
%%%=================================================================
diff --git a/lib/common_test/src/ct_gen_conn.erl b/lib/common_test/src/ct_gen_conn.erl
index 456bfd8bd1..1ab9946d96 100644
--- a/lib/common_test/src/ct_gen_conn.erl
+++ b/lib/common_test/src/ct_gen_conn.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,9 +18,9 @@
%% %CopyrightEnd%
%%
-%%% @doc Generic connection owner process.
+%%% Generic connection owner process.
%%%
-%%% @type handle() = pid(). A handle for using a connection implemented
+%%% -type handle() = pid(). A handle for using a connection implemented
%%% with ct_gen_conn.erl.
-module(ct_gen_conn).
@@ -48,7 +48,7 @@
ct_util_server}).
%%%-----------------------------------------------------------------
-%%% @spec start(Address,InitData,CallbackMod,Opts) ->
+%%% -spec start(Address,InitData,CallbackMod,Opts) ->
%%% {ok,Handle} | {error,Reason}
%%% Name = term()
%%% CallbackMod = atom()
@@ -58,57 +58,52 @@
%%% Opt = {name,Name} | {use_existing_connection,boolean()} |
%%% {reconnect,boolean()} | {forward_messages,boolean()}
%%%
-%%% @doc Open a connection and start the generic connection owner process.
+%%% Open a connection and start the generic connection owner process.
%%%
-%%% <p>The <code>CallbackMod</code> is a specific callback module for
+%%% The CallbackMod is a specific callback module for
%%% each type of connection (e.g. telnet, ftp,...). It must export the
-%%% function <code>init/3</code> which takes the arguments
-%%% <code>Name</code>, <code>Addresse</code>) and
-%%% <code>InitData</code> and returna
-%%% <code>{ok,ConnectionPid,State}</code> or
-%%% <code>{error,Reason}</code>.</p>
+%%% function init/3 which takes the arguments
+%%% Name, Addresse) and
+%%% InitData and returna
+%%% {ok,ConnectionPid,State} or
+%%% {error,Reason}.
%%%
-%%% If no name is given, the <code>Name</code> argument in init/3 will
-%%% have the value <code>undefined</code>.
+%%% If no name is given, the Name argument in init/3 will
+%%% have the value undefined.
%%%
%%% The callback modules must also export
-%%% ```
+%%%
%%% handle_msg(Msg,From,State) -> {reply,Reply,State} |
%%% {noreply,State} |
%%% {stop,Reply,State}
%%% terminate(ConnectionPid,State) -> term()
%%% close(Handle) -> term()
-%%% '''
%%%
-%%% The <code>close/1</code> callback function is actually a callback
+%%% The close/1 callback function is actually a callback
%%% for ct_util, for closing registered connections when
-%%% ct_util_server is terminated. <code>Handle</code> is the Pid of
+%%% ct_util_server is terminated. Handle is the Pid of
%%% the ct_gen_conn process.
%%%
-%%% If option <code>reconnect</code> is <code>true</code>, then the
+%%% If option reconnect is true, then the
%%% callback must also export
-%%% ```
+%%%
%%% reconnect(Address,State) -> {ok,ConnectionPid,State}
-%%% '''
%%%
-%%% If option <code>forward_messages</code> is <ocde>true</code>, then
+%%% If option forward_messages is <ocde>true, then
%%% the callback must also export
-%%% ```
+%%%
%%% handle_msg(Msg,State) -> {noreply,State} | {stop,State}
-%%% '''
%%%
%%% An old interface still exists. This is used by ct_telnet, ct_ftp
%%% and ct_ssh. The start function then has an explicit
-%%% <code>Name</code> argument, and no <code>Opts</code> argument. The
+%%% Name argument, and no Opts argument. The
%%% callback must export:
%%%
-%%% ```
%%% init(Name,Address,InitData) -> {ok,ConnectionPid,State}
%%% handle_msg(Msg,State) -> {Reply,State}
%%% reconnect(Address,State) -> {ok,ConnectionPid,State}
%%% terminate(ConnectionPid,State) -> term()
%%% close(Handle) -> term()
-%%% '''
%%%
start(Address,InitData,CallbackMod,Opts) when is_list(Opts) ->
do_start(Address,InitData,CallbackMod,Opts);
@@ -116,73 +111,73 @@ start(Name,Address,InitData,CallbackMod) ->
do_start(Address,InitData,CallbackMod,[{name,Name},{old,true}]).
%%%-----------------------------------------------------------------
-%%% @spec stop(Handle) -> ok
+%%% -spec stop(Handle) -> ok
%%% Handle = handle()
%%%
-%%% @doc Close the connection and stop the process managing it.
+%%% Close the connection and stop the process managing it.
stop(Handle) ->
call(Handle,stop,5000).
%%%-----------------------------------------------------------------
-%%% @spec get_conn_pid(Handle) -> ok
+%%% -spec get_conn_pid(Handle) -> ok
%%% Handle = handle()
%%%
-%%% @doc Return the connection pid associated with Handle
+%%% Return the connection pid associated with Handle
get_conn_pid(Handle) ->
call(Handle,get_conn_pid).
%%%-----------------------------------------------------------------
-%%% @spec log(Heading,Format,Args) -> ok
+%%% -spec log(Heading,Format,Args) -> ok
%%%
-%%% @doc Log activities on the current connection (tool-internal use only).
-%%% @see ct_logs:log/3
+%%% Log activities on the current connection (tool-internal use only).
+%%% See ct_logs:log/3
log(Heading,Format,Args) ->
log(log,[Heading,Format,Args]).
%%%-----------------------------------------------------------------
-%%% @spec start_log(Heading) -> ok
+%%% -spec start_log(Heading) -> ok
%%%
-%%% @doc Log activities on the current connection (tool-internal use only).
-%%% @see ct_logs:start_log/1
+%%% Log activities on the current connection (tool-internal use only).
+%%% See ct_logs:start_log/1
start_log(Heading) ->
log(start_log,[Heading]).
%%%-----------------------------------------------------------------
-%%% @spec cont_log(Format,Args) -> ok
+%%% -spec cont_log(Format,Args) -> ok
%%%
-%%% @doc Log activities on the current connection (tool-internal use only).
-%%% @see ct_logs:cont_log/2
+%%% Log activities on the current connection (tool-internal use only).
+%%% See ct_logs:cont_log/2
cont_log(Format,Args) ->
log(cont_log,[Format,Args]).
%%%-----------------------------------------------------------------
-%%% @spec cont_log_no_timestamp(Format,Args) -> ok
+%%% -spec cont_log_no_timestamp(Format,Args) -> ok
%%%
-%%% @doc Log activities on the current connection (tool-internal use only).
-%%% @see ct_logs:cont_log/2
+%%% Log activities on the current connection (tool-internal use only).
+%%% See ct_logs:cont_log/2
cont_log_no_timestamp(Format,Args) ->
log(cont_log_no_timestamp,[Format,Args]).
%%%-----------------------------------------------------------------
-%%% @spec end_log() -> ok
+%%% -spec end_log() -> ok
%%%
-%%% @doc Log activities on the current connection (tool-internal use only).
-%%% @see ct_logs:end_log/0
+%%% Log activities on the current connection (tool-internal use only).
+%%% See ct_logs:end_log/0
end_log() ->
log(end_log,[]).
%%%-----------------------------------------------------------------
-%%% @spec do_within_time(Fun,Timeout) -> FunResult | {error,Reason}
+%%% -spec do_within_time(Fun,Timeout) -> FunResult | {error,Reason}
%%% Fun = function()
%%% Timeout = integer()
%%%
-%%% @doc Execute a function within a limited time (tool-internal use only).
+%%% Execute a function within a limited time (tool-internal use only).
%%%
-%%% <p>Execute the given <code>Fun</code>, but interrupt if it takes
-%%% more than <code>Timeout</code> milliseconds.</p>
+%%% Execute the given Fun, but interrupt if it takes
+%%% more than Timeout milliseconds.
%%%
-%%% <p>The execution is also interrupted if the connection is
-%%% closed.</p>
+%%% The execution is also interrupted if the connection is
+%%% closed.
do_within_time(Fun,Timeout) ->
Self = self(),
Silent = get(silent),
diff --git a/lib/common_test/src/ct_groups.erl b/lib/common_test/src/ct_groups.erl
index 2235365a0e..f4b12c41c0 100644
--- a/lib/common_test/src/ct_groups.erl
+++ b/lib/common_test/src/ct_groups.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,11 +18,9 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Framework callback module.
-%%%
-%%% <p>This module contains CT internal help functions for searching
-%%% through groups specification trees and producing resulting
-%%% tests.</p>
+%%% This module contains CT internal help functions for searching
+%%% through groups specification trees and producing resulting
+%%% tests.
-module(ct_groups).
@@ -103,23 +101,34 @@ find(Mod, [], TCs, Tests, _Known, _Defs, false) ->
[{Mod,TC}];
({group,_}) ->
[];
+ ({testcase,TC,[Prop]}) when is_atom(TC), TC ==all ->
+ [{repeat,{Mod,TC},Prop}];
({_,_}=TC) when TCs == all ->
[TC];
- (TC) ->
- if is_atom(TC) ->
- Tuple = {Mod,TC},
- case lists:member(Tuple, TCs) of
- true ->
- [Tuple];
- false ->
- case lists:member(TC, TCs) of
- true -> [{Mod,TC}];
- false -> []
- end
- end;
- true ->
- []
- end
+ (TC) when is_atom(TC) ->
+ Tuple = {Mod,TC},
+ case lists:member(Tuple, TCs) of
+ true ->
+ [Tuple];
+ false ->
+ case lists:member(TC, TCs) of
+ true -> [Tuple];
+ false -> []
+ end
+ end;
+ ({testcase,TC,[Prop]}) when is_atom(TC) ->
+ Tuple = {Mod,TC},
+ case lists:member(Tuple, TCs) of
+ true ->
+ [{repeat,Tuple,Prop}];
+ false ->
+ case lists:member(TC, TCs) of
+ true -> [{repeat,Tuple,Prop}];
+ false -> []
+ end
+ end;
+ (_) ->
+ []
end, Tests),
if Cases == [] -> ['NOMATCH'];
true -> Cases
@@ -174,12 +183,19 @@ find(Mod, GrNames, all, [{M,TC} | Gs], Known,
Defs, FindAll) when is_atom(M), M /= group, is_atom(TC) ->
[{M,TC} | find(Mod, GrNames, all, Gs, Known, Defs, FindAll)];
+%% Save test case
+find(Mod, GrNames, all, [{testcase,TC,[Prop]} | Gs], Known,
+ Defs, FindAll) when is_atom(TC) ->
+ [{repeat,{Mod,TC},Prop} | find(Mod, GrNames, all, Gs, Known, Defs, FindAll)];
+
%% Check if test case should be saved
-find(Mod, GrNames, TCs, [TC | Gs], Known,
- Defs, FindAll) when is_atom(TC) orelse
- ((size(TC) == 2) and (element(1,TC) /= group)) ->
+find(Mod, GrNames, TCs, [TC | Gs], Known, Defs, FindAll)
+ when is_atom(TC) orelse
+ ((size(TC) == 3) andalso (element(1,TC) == testcase)) orelse
+ ((size(TC) == 2) and (element(1,TC) /= group)) ->
Case =
- if is_atom(TC) ->
+ case TC of
+ _ when is_atom(TC) ->
Tuple = {Mod,TC},
case lists:member(Tuple, TCs) of
true ->
@@ -190,7 +206,18 @@ find(Mod, GrNames, TCs, [TC | Gs], Known,
false -> []
end
end;
- true ->
+ {testcase,TC0,[Prop]} when is_atom(TC0) ->
+ Tuple = {Mod,TC0},
+ case lists:member(Tuple, TCs) of
+ true ->
+ {repeat,Tuple,Prop};
+ false ->
+ case lists:member(TC0, TCs) of
+ true -> {repeat,{Mod,TC0},Prop};
+ false -> []
+ end
+ end;
+ _ ->
case lists:member(TC, TCs) of
true -> {Mod,TC};
false -> []
@@ -291,12 +318,22 @@ modify_tc_list(GrSpecTs, TSCs, []) ->
modify_tc_list1(GrSpecTs, TSCs);
modify_tc_list(GrSpecTs, _TSCs, _) ->
- [Test || Test <- GrSpecTs, not is_atom(Test)].
+ [Test || Test <- GrSpecTs, not is_atom(Test), element(1,Test)=/=testcase].
modify_tc_list1(GrSpecTs, TSCs) ->
%% remove all cases in group tc list that should not be executed
GrSpecTs1 =
- lists:flatmap(fun(Test) when is_tuple(Test),
+ lists:flatmap(fun(Test={testcase,TC,_}) ->
+ case lists:keysearch(TC, 2, TSCs) of
+ {value,_} ->
+ [Test];
+ _ ->
+ case lists:member(TC, TSCs) of
+ true -> [Test];
+ false -> []
+ end
+ end;
+ (Test) when is_tuple(Test),
(size(Test) > 2) ->
[Test];
(Test={group,_}) ->
diff --git a/lib/common_test/src/ct_hooks.erl b/lib/common_test/src/ct_hooks.erl
index f0592a40be..97c349578f 100644
--- a/lib/common_test/src/ct_hooks.erl
+++ b/lib/common_test/src/ct_hooks.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,14 +18,12 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Framework test execution control module.
-%%%
-%%% <p>This module is a proxy for calling and handling common test hooks.</p>
-
-module(ct_hooks).
%% API Exports
-export([init/1]).
+-export([groups/2]).
+-export([all/2]).
-export([init_tc/3]).
-export([end_tc/5]).
-export([terminate/1]).
@@ -41,20 +39,61 @@
opts = [],
prio = ctfirst }]).
--record(ct_hook_config, {id, module, prio, scope, opts = [], state = []}).
+-record(ct_hook_config, {id, module, prio, scope, opts = [],
+ state = [], groups = []}).
%% -------------------------------------------------------------------------
%% API Functions
%% -------------------------------------------------------------------------
-%% @doc Called before any suites are started
-spec init(State :: term()) -> ok |
{fail, Reason :: term()}.
init(Opts) ->
call(get_builtin_hooks(Opts) ++ get_new_hooks(Opts, undefined),
ok, init, []).
-%% @doc Called after all suites are done.
+%% Call the post_groups/2 hook callback
+groups(Mod, Groups) ->
+ Info = try proplists:get_value(ct_hooks, Mod:suite(), []) of
+ CTHooks when is_list(CTHooks) ->
+ [{?config_name,CTHooks}];
+ CTHook when is_atom(CTHook) ->
+ [{?config_name,[CTHook]}]
+ catch _:_ ->
+ %% since this might be the first time Mod:suite()
+ %% is called, and it might just fail or return
+ %% something bad, we allow any failure here - it
+ %% will be catched later if there is something
+ %% really wrong.
+ [{?config_name,[]}]
+ end,
+ case call(fun call_generic/3, Info ++ [{'$ct_groups',Groups}], [post_groups, Mod]) of
+ [{'$ct_groups',NewGroups}] ->
+ NewGroups;
+ Other ->
+ Other
+ end.
+
+%% Call the post_all/3 hook callback
+all(Mod, Tests) ->
+ Info = try proplists:get_value(ct_hooks, Mod:suite(), []) of
+ CTHooks when is_list(CTHooks) ->
+ [{?config_name,CTHooks}];
+ CTHook when is_atom(CTHook) ->
+ [{?config_name,[CTHook]}]
+ catch _:_ ->
+ %% just allow any failure here - it will be catched
+ %% later if there is something really wrong.
+ [{?config_name,[]}]
+ end,
+ case call(fun call_generic/3, Info ++ [{'$ct_all',Tests}], [post_all, Mod]) of
+ [{'$ct_all',NewTests}] ->
+ NewTests;
+ Other ->
+ Other
+ end.
+
+%% Called after all suites are done.
-spec terminate(Hooks :: term()) ->
ok.
terminate(Hooks) ->
@@ -63,8 +102,6 @@ terminate(Hooks) ->
ct_hooks_terminate_dummy, terminate, Hooks),
ok.
-%% @doc Called as each test case is started. This includes all configuration
-%% tests.
-spec init_tc(Mod :: atom(),
FuncSpec :: atom() |
{ConfigFunc :: init_per_testcase | end_per_testcase,
@@ -88,6 +125,7 @@ init_tc(Mod, init_per_suite, Config) ->
[{?config_name,[]}]
end,
call(fun call_generic/3, Config ++ Info, [pre_init_per_suite, Mod]);
+
init_tc(Mod, end_per_suite, Config) ->
call(fun call_generic/3, Config, [pre_end_per_suite, Mod]);
init_tc(Mod, {init_per_group, GroupName, Properties}, Config) ->
@@ -104,8 +142,6 @@ init_tc(Mod, {end_per_testcase,TC}, Config) ->
init_tc(Mod, TC = error_in_suite, Config) ->
call(fun call_generic_fallback/3, Config, [pre_init_per_testcase, Mod, TC]).
-%% @doc Called as each test case is completed. This includes all configuration
-%% tests.
-spec end_tc(Mod :: atom(),
FuncSpec :: atom() |
{ConfigFunc :: init_per_testcase | end_per_testcase,
@@ -163,7 +199,7 @@ call_id(#ct_hook_config{ module = Mod, opts = Opts} = Hook, Config, Scope) ->
{Config, Hook#ct_hook_config{ id = Id, scope = scope(Scope)}}.
call_init(#ct_hook_config{ module = Mod, opts = Opts, id = Id, prio = P} = Hook,
- Config,_Meta) ->
+ Config, _Meta) ->
case Mod:init(Id, Opts) of
{ok, NewState} when P =:= undefined ->
{Config, Hook#ct_hook_config{ state = NewState, prio = 0 } };
@@ -194,6 +230,18 @@ call_generic(Hook, Value, Meta) ->
call_generic_fallback(Hook, Value, Meta) ->
do_call_generic(Hook, Value, Meta, true).
+do_call_generic(#ct_hook_config{ module = Mod} = Hook,
+ [{'$ct_groups',Groups}], [post_groups | Args], Fallback) ->
+ NewGroups = catch_apply(Mod, post_groups, Args ++ [Groups],
+ Groups, Fallback),
+ {[{'$ct_groups',NewGroups}], Hook#ct_hook_config{ groups = NewGroups } };
+
+do_call_generic(#ct_hook_config{ module = Mod, groups = Groups} = Hook,
+ [{'$ct_all',Tests}], [post_all | Args], Fallback) ->
+ NewTests = catch_apply(Mod, post_all, Args ++ [Tests, Groups],
+ Tests, Fallback),
+ {[{'$ct_all',NewTests}], Hook};
+
do_call_generic(#ct_hook_config{ module = Mod, state = State} = Hook,
Value, [Function | Args], Fallback) ->
{NewValue, NewState} = catch_apply(Mod, Function, Args ++ [Value, State],
@@ -228,17 +276,22 @@ call([{Hook, call_id, NextFun} | Rest], Config, Meta, Hooks) ->
Rest ++ [{NewId, call_init}]};
ExistingHook when is_tuple(ExistingHook) ->
{Hooks, Rest};
+ _ when hd(Meta)=:=post_groups; hd(Meta)=:=post_all ->
+ %% If CTH is started because of a call from
+ %% groups/2 or all/2, CTH:init/1 must not be
+ %% called (the suite scope should be used).
+ {Hooks ++ [NewHook],
+ Rest ++ [{NewId,NextFun}]};
_ ->
{Hooks ++ [NewHook],
Rest ++ [{NewId, call_init}, {NewId,NextFun}]}
end,
call(resort(NewRest,NewHooks,Meta), Config, Meta, NewHooks)
- catch Error:Reason ->
- Trace = erlang:get_stacktrace(),
+ catch Error:Reason:Trace ->
ct_logs:log("Suite Hook","Failed to start a CTH: ~tp:~tp",
[Error,{Reason,Trace}]),
- call([], {fail,"Failed to start CTH"
- ", see the CT Log for details"}, Meta, Hooks)
+ call([], {fail,"Failed to start CTH, "
+ "see the CT Log for details"}, Meta, Hooks)
end;
call([{HookId, call_init} | Rest], Config, Meta, Hooks) ->
call([{HookId, fun call_init/3} | Rest], Config, Meta, Hooks);
@@ -278,6 +331,10 @@ scope([pre_init_per_suite, SuiteName|_]) ->
[post_end_per_suite, SuiteName];
scope([post_init_per_suite, SuiteName|_]) ->
[post_end_per_suite, SuiteName];
+scope([post_groups, SuiteName|_]) ->
+ [post_groups, SuiteName];
+scope([post_all, SuiteName|_]) ->
+ [post_all, SuiteName];
scope(init) ->
none.
@@ -364,6 +421,7 @@ resort(Calls,Hooks,[F|_R]) when F == pre_end_per_testcase;
F == pre_end_per_suite;
F == post_end_per_suite ->
lists:reverse(resort(Calls,Hooks));
+
resort(Calls,Hooks,_Meta) ->
resort(Calls,Hooks).
@@ -422,8 +480,7 @@ catch_apply(M,F,A, Default, Fallback) ->
catch_apply(M,F,A) ->
try
erlang:apply(M,F,A)
- catch _:Reason ->
- Trace = erlang:get_stacktrace(),
+ catch _:Reason:Trace ->
ct_logs:log("Suite Hook","Call to CTH failed: ~w:~tp",
[error,{Reason,Trace}]),
throw({error_in_cth_call,
diff --git a/lib/common_test/src/ct_hooks_lock.erl b/lib/common_test/src/ct_hooks_lock.erl
index a82be288e1..be50a33e01 100644
--- a/lib/common_test/src/ct_hooks_lock.erl
+++ b/lib/common_test/src/ct_hooks_lock.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,11 +18,6 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Framework test execution control module.
-%%%
-%%% <p>This module is a proxy for calling and handling locks in
-%%% common test hooks.</p>
-
-module(ct_hooks_lock).
-behaviour(gen_server).
@@ -42,7 +37,6 @@
%%% API
%%%===================================================================
-%% @doc Starts the server
start(Id) ->
case gen_server:start({local, ?SERVER}, ?MODULE, Id, []) of
{error,{already_started, Pid}} ->
@@ -76,12 +70,10 @@ release() ->
%%% gen_server callbacks
%%%===================================================================
-%% @doc Initiates the server
init(Id) ->
ct_util:mark_process(),
{ok, #state{ id = Id }}.
-%% @doc Handling call messages
handle_call({stop,Id}, _From, #state{ id = Id, requests = Reqs } = State) ->
_ = [gen_server:reply(Req, locker_stopped) || {Req,_ReqId} <- Reqs],
{stop, normal, stopped, State};
@@ -108,11 +100,9 @@ handle_call({release, Pid}, _From,
handle_call({release, _Pid}, _From, State) ->
{reply, not_locked, State}.
-%% @doc Handling cast messages
handle_cast(_Msg, State) ->
{noreply, State}.
-%% @doc Handling all non call/cast messages
handle_info({'DOWN',Ref,process,Pid,_},
#state{ locked = {true, Pid, Ref},
requests = [{NextFrom,NextPid}|Rest] } = State) ->
@@ -121,11 +111,9 @@ handle_info({'DOWN',Ref,process,Pid,_},
{noreply,State#state{ locked = {true, NextPid, NextRef},
requests = Rest } }.
-%% @doc This function is called by a gen_server when it is about to terminate.
terminate(_Reason, _State) ->
ok.
-%% @doc Convert process state when code is changed
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl
index fb6a095b57..ca262b350f 100644
--- a/lib/common_test/src/ct_logs.erl
+++ b/lib/common_test/src/ct_logs.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,14 +18,12 @@
%% %CopyrightEnd%
%%
-%%% @doc Logging functionality for Common Test Framework.
+%%% Logging functionality for Common Test Framework.
%%%
-%%% <p>This module implements
-%%% <ul>
-%%% <li>Internal logging of activities in Common Test Framework</li>
-%%% <li>Compilation of test results into index pages on several levels</li>
-%%% </ul>
-%%% </p>
+%%% This module implements:
+%%%
+%%% Internal logging of activities in Common Test Framework, and
+%%% Compilation of test results into index pages on several levels
-module(ct_logs).
@@ -84,17 +82,17 @@
tests = []}).
%%%-----------------------------------------------------------------
-%%% @spec init(Mode, Verbosity) -> Result
+%%% -spec init(Mode, Verbosity) -> Result
%%% Mode = normal | interactive
%%% Result = {StartTime,LogDir}
%%% StartTime = term()
%%% LogDir = string()
%%%
-%%% @doc Initiate the logging mechanism (tool-internal use only).
+%%% Initiate the logging mechanism (tool-internal use only).
%%%
-%%% <p>This function is called by ct_util.erl when testing is
-%%% started. A new directory named ct_run.&lt;timestamp&gt; is created
-%%% and all logs are stored under this directory.</p>
+%%% This function is called by ct_util.erl when testing is
+%%% started. A new directory named ct_run.<timestamp> is created
+%%% and all logs are stored under this directory.
%%%
init(Mode, Verbosity) ->
Self = self(),
@@ -129,9 +127,9 @@ datestr_from_dirname([]) ->
"".
%%%-----------------------------------------------------------------
-%%% @spec close(Info, StartDir) -> ok
+%%% -spec close(Info, StartDir) -> ok
%%%
-%%% @doc Create index pages with test results and close the CT Log
+%%% Create index pages with test results and close the CT Log
%%% (tool-internal use only).
close(Info, StartDir) ->
%% close executes on the ct_util process, not on the logger process
@@ -151,7 +149,7 @@ close(Info, StartDir) ->
ok;
CacheBin ->
%% save final version of the log cache to file
- _ = file:write_file(?log_cache_name,CacheBin),
+ write_log_cache(CacheBin),
put(ct_log_cache,undefined)
end
end,
@@ -204,22 +202,22 @@ close(Info, StartDir) ->
ok.
%%%-----------------------------------------------------------------
-%%% @spec set_stylesheet(TC,SSFile) -> ok
+%%% -spec set_stylesheet(TC,SSFile) -> ok
set_stylesheet(TC, SSFile) ->
cast({set_stylesheet,TC,SSFile}).
%%%-----------------------------------------------------------------
-%%% @spec clear_stylesheet(TC) -> ok
+%%% -spec clear_stylesheet(TC) -> ok
clear_stylesheet(TC) ->
cast({clear_stylesheet,TC}).
%%%-----------------------------------------------------------------
-%%% @spec get_log_dir() -> {ok,Dir} | {error,Reason}
+%%% -spec get_log_dir() -> {ok,Dir} | {error,Reason}
get_log_dir() ->
get_log_dir(false).
%%%-----------------------------------------------------------------
-%%% @spec get_log_dir(ReturnAbsName) -> {ok,Dir} | {error,Reason}
+%%% -spec get_log_dir(ReturnAbsName) -> {ok,Dir} | {error,Reason}
get_log_dir(ReturnAbsName) ->
case call({get_log_dir,ReturnAbsName}) of
{error,does_not_exist} when ReturnAbsName == true ->
@@ -278,58 +276,58 @@ get_format_args(Content) ->
end, Content).
%%%-----------------------------------------------------------------
-%%% @spec init_tc(RefreshLog) -> ok
+%%% -spec init_tc(RefreshLog) -> ok
%%%
-%%% @doc Test case initiation (tool-internal use only).
+%%% Test case initiation (tool-internal use only).
%%%
-%%% <p>This function is called by ct_framework:init_tc/3</p>
+%%% This function is called by ct_framework:init_tc/3
init_tc(RefreshLog) ->
call({init_tc,self(),group_leader(),RefreshLog}),
tc_io_format(group_leader(), xhtml("", "<br />"), []),
ok.
%%%-----------------------------------------------------------------
-%%% @spec end_tc(TCPid) -> ok
+%%% -spec end_tc(TCPid) -> ok
%%%
-%%% @doc Test case clean up (tool-internal use only).
+%%% Test case clean up (tool-internal use only).
%%%
-%%% <p>This function is called by ct_framework:end_tc/3</p>
+%%% This function is called by ct_framework:end_tc/3
end_tc(TCPid) ->
%% use call here so that the TC process will wait and receive
%% possible exit signals from ct_logs before end_tc returns ok
call({end_tc,TCPid}).
%%%-----------------------------------------------------------------
-%%% @spec register_groupleader(Pid,GroupLeader) -> ok
+%%% -spec register_groupleader(Pid,GroupLeader) -> ok
%%%
-%%% @doc To enable logging to a group leader (tool-internal use only).
+%%% To enable logging to a group leader (tool-internal use only).
%%%
-%%% <p>This function is called by ct_framework:report/2</p>
+%%% This function is called by ct_framework:report/2
register_groupleader(Pid,GroupLeader) ->
call({register_groupleader,Pid,GroupLeader}),
ok.
%%%-----------------------------------------------------------------
-%%% @spec unregister_groupleader(Pid) -> ok
+%%% -spec unregister_groupleader(Pid) -> ok
%%%
-%%% @doc To disable logging to a group leader (tool-internal use only).
+%%% To disable logging to a group leader (tool-internal use only).
%%%
-%%% <p>This function is called by ct_framework:report/2</p>
+%%% This function is called by ct_framework:report/2
unregister_groupleader(Pid) ->
call({unregister_groupleader,Pid}),
ok.
%%%-----------------------------------------------------------------
-%%% @spec log(Heading,Format,Args) -> ok
+%%% -spec log(Heading,Format,Args) -> ok
%%%
-%%% @doc Log internal activity (tool-internal use only).
+%%% Log internal activity (tool-internal use only).
%%%
-%%% <p>This function writes an entry to the currently active log,
-%%% i.e. either the CT log or a test case log.</p>
+%%% This function writes an entry to the currently active log,
+%%% i.e. either the CT log or a test case log.
%%%
-%%% <p><code>Heading</code> is a short string indicating what type of
-%%% activity it is. <code>Format</code> and <code>Args</code> is the
-%%% data to log (as in <code>io:format(Format,Args)</code>).</p>
+%%% Heading is a short string indicating what type of
+%%% activity it is. Format and Args is the
+%%% data to log (as in io:format(Format,Args)).
log(Heading,Format,Args) ->
cast({log,sync,self(),group_leader(),ct_internal,?MAX_IMPORTANCE,
[{hd,int_header(),[log_timestamp(?now),Heading]},
@@ -339,32 +337,29 @@ log(Heading,Format,Args) ->
ok.
%%%-----------------------------------------------------------------
-%%% @spec start_log(Heading) -> ok
+%%% -spec start_log(Heading) -> ok
%%%
-%%% @doc Starts the logging of an activity (tool-internal use only).
+%%% Starts the logging of an activity (tool-internal use only).
%%%
-%%% <p>This function must be used in combination with
-%%% <code>cont_log/2</code> and <code>end_log/0</code>. The intention
-%%% is to call <code>start_log</code> once, then <code>cont_log</code>
-%%% any number of times and finally <code>end_log</code> once.</p>
+%%% This function must be used in combination with
+%%% cont_log/2 and end_log/0. The intention
+%%% is to call start_log once, then cont_log
+%%% any number of times and finally end_log once.
%%%
-%%% <p>For information about the parameters, see <code>log/3</code>.</p>
+%%% For information about the parameters, see log/3.
%%%
-%%% @see log/3
-%%% @see cont_log/2
-%%% @see end_log/0
+%%% See log/3, cont_log/2, and end_log/0.
start_log(Heading) ->
cast({log,sync,self(),group_leader(),ct_internal,?MAX_IMPORTANCE,
[{hd,int_header(),[log_timestamp(?now),Heading]}],false}),
ok.
%%%-----------------------------------------------------------------
-%%% @spec cont_log(Format,Args) -> ok
+%%% -spec cont_log(Format,Args) -> ok
%%%
-%%% @doc Adds information about an activity (tool-internal use only).
+%%% Adds information about an activity (tool-internal use only).
%%%
-%%% @see start_log/1
-%%% @see end_log/0
+%%% See start_log/1 and end_log/0.
cont_log([],[]) ->
ok;
cont_log(Format,Args) ->
@@ -374,12 +369,11 @@ cont_log(Format,Args) ->
ok.
%%%-----------------------------------------------------------------
-%%% @spec cont_log_no_timestamp(Format,Args) -> ok
+%%% -spec cont_log_no_timestamp(Format,Args) -> ok
%%%
-%%% @doc Adds information about an activity (tool-internal use only).
+%%% Adds information about an activity (tool-internal use only).
%%%
-%%% @see start_log/1
-%%% @see end_log/0
+%%% See start_log/1 and end_log/0.
cont_log_no_timestamp([],[]) ->
ok;
cont_log_no_timestamp(Format,Args) ->
@@ -388,12 +382,11 @@ cont_log_no_timestamp(Format,Args) ->
ok.
%%%-----------------------------------------------------------------
-%%% @spec end_log() -> ok
+%%% -spec end_log() -> ok
%%%
-%%% @doc Ends the logging of an activity (tool-internal use only).
+%%% Ends the logging of an activity (tool-internal use only).
%%%
-%%% @see start_log/1
-%%% @see cont_log/2
+%%% See start_log/1 and cont_log/2.
end_log() ->
cast({log,sync,self(),group_leader(),ct_internal,?MAX_IMPORTANCE,
[{ft,int_footer(), []}],false}),
@@ -401,15 +394,15 @@ end_log() ->
%%%-----------------------------------------------------------------
-%%% @spec add_external_logs(Logs) -> ok
+%%% -spec add_external_logs(Logs) -> ok
%%% Logs = [Log]
%%% Log = string()
%%%
-%%% @doc Print a link to each given <code>Log</code> in the test case
+%%% Print a link to each given Log in the test case
%%% log.
%%%
-%%% <p>The given <code>Logs</code> must exist in the priv dir of the
-%%% calling test suite.</p>
+%%% The given Logs must exist in the priv dir of the
+%%% calling test suite.
add_external_logs(Logs) ->
start_log("External Logs"),
[cont_log("<a href=\"~ts\">~ts</a>\n",
@@ -417,12 +410,12 @@ add_external_logs(Logs) ->
end_log().
%%%-----------------------------------------------------------------
-%%% @spec add_link(Heading,File,Type) -> ok
+%%% -spec add_link(Heading,File,Type) -> ok
%%% Heading = string()
%%% File = string()
%%% Type = string()
%%%
-%%% @doc Print a link to a given file stored in the priv_dir of the
+%%% Print a link to a given file stored in the priv_dir of the
%%% calling test suite.
add_link(Heading,File,Type) ->
log(Heading,"<a href=\"~ts\" type=~tp>~ts</a>\n",
@@ -430,25 +423,25 @@ add_link(Heading,File,Type) ->
%%%-----------------------------------------------------------------
-%%% @spec tc_log(Category,Format,Args) -> ok
-%%% @equiv tc_log(Category,?STD_IMPORTANCE,Format,Args)
+%%% -spec tc_log(Category,Format,Args) -> ok
+%%% Equivalent to tc_log(Category,?STD_IMPORTANCE,Format,Args)
tc_log(Category,Format,Args) ->
tc_log(Category,?STD_IMPORTANCE,"User",Format,Args,[]).
%%%-----------------------------------------------------------------
-%%% @spec tc_log(Category,Importance,Format,Args) -> ok
-%%% @equiv tc_log(Category,Importance,"User",Format,Args)
+%%% -spec tc_log(Category,Importance,Format,Args) -> ok
+%%% Equivalent to tc_log(Category,Importance,"User",Format,Args)
tc_log(Category,Importance,Format,Args) ->
tc_log(Category,Importance,"User",Format,Args,[]).
%%%-----------------------------------------------------------------
-%%% @spec tc_log(Category,Importance,Format,Args) -> ok
-%%% @equiv tc_log(Category,Importance,"User",Format,Args)
+%%% -spec tc_log(Category,Importance,Format,Args) -> ok
+%%% Equivalent to tc_log(Category,Importance,"User",Format,Args)
tc_log(Category,Importance,Format,Args,Opts) ->
tc_log(Category,Importance,"User",Format,Args,Opts).
%%%-----------------------------------------------------------------
-%%% @spec tc_log(Category,Importance,Heading,Format,Args,Opts) -> ok
+%%% -spec tc_log(Category,Importance,Heading,Format,Args,Opts) -> ok
%%% Category = atom()
%%% Importance = integer()
%%% Heading = string()
@@ -456,11 +449,11 @@ tc_log(Category,Importance,Format,Args,Opts) ->
%%% Args = list()
%%% Opts = list()
%%%
-%%% @doc Printout from a testcase.
+%%% Printout from a testcase.
%%%
-%%% <p>This function is called by <code>ct</code> when logging
+%%% This function is called by ct when logging
%%% stuff directly from a testcase (i.e. not from within the CT
-%%% framework).</p>
+%%% framework).
tc_log(Category,Importance,Heading,Format,Args,Opts) ->
Data =
case lists:member(no_css, Opts) of
@@ -481,26 +474,26 @@ tc_log(Category,Importance,Heading,Format,Args,Opts) ->
ok.
%%%-----------------------------------------------------------------
-%%% @spec tc_log_async(Category,Format,Args) -> ok
-%%% @equiv tc_log_async(Category,?STD_IMPORTANCE,"User",Format,Args)
+%%% -spec tc_log_async(Category,Format,Args) -> ok
+%%% Equivalent to tc_log_async(Category,?STD_IMPORTANCE,"User",Format,Args)
tc_log_async(Category,Format,Args) ->
tc_log_async(Category,?STD_IMPORTANCE,"User",Format,Args).
%%%-----------------------------------------------------------------
-%%% @spec tc_log_async(Category,Importance,Format,Args) -> ok
+%%% -spec tc_log_async(Category,Importance,Format,Args) -> ok
%%% Category = atom()
%%% Importance = integer()
%%% Heading = string()
%%% Format = string()
%%% Args = list()
%%%
-%%% @doc Internal use only.
+%%% Internal use only.
%%%
-%%% <p>This function is used to perform asynchronous printouts
+%%% This function is used to perform asynchronous printouts
%%% towards the test server IO handler. This is necessary in order
%%% to avoid deadlocks when e.g. the hook that handles SASL printouts
%%% prints to the test case log file at the same time test server
-%%% asks ct_logs for an html wrapper.</p>
+%%% asks ct_logs for an html wrapper.
tc_log_async(Category,Importance,Heading,Format,Args) ->
cast({log,async,self(),group_leader(),Category,Importance,
[{hd,div_header(Category,Heading),[]},
@@ -509,29 +502,29 @@ tc_log_async(Category,Importance,Heading,Format,Args) ->
true}),
ok.
%%%-----------------------------------------------------------------
-%%% @spec tc_print(Category,Format,Args)
-%%% @equiv tc_print(Category,?STD_IMPORTANCE,Format,Args,[])
+%%% -spec tc_print(Category,Format,Args)
+%%% Equivalent to tc_print(Category,?STD_IMPORTANCE,Format,Args,[])
tc_print(Category,Format,Args) ->
tc_print(Category,?STD_IMPORTANCE,Format,Args,[]).
%%%-----------------------------------------------------------------
-%%% @spec tc_print(Category,Importance,Format,Args)
-%%% @equiv tc_print(Category,Importance,Format,Args,[])
+%%% -spec tc_print(Category,Importance,Format,Args)
+%%% Equivalent to tc_print(Category,Importance,Format,Args,[])
tc_print(Category,Importance,Format,Args) ->
tc_print(Category,Importance,Format,Args,[]).
%%%-----------------------------------------------------------------
-%%% @spec tc_print(Category,Importance,Format,Args,Opts) -> ok
+%%% -spec tc_print(Category,Importance,Format,Args,Opts) -> ok
%%% Category = atom()
%%% Importance = integer()
%%% Format = string()
%%% Args = list()
%%% Opts = list()
%%%
-%%% @doc Console printout from a testcase.
+%%% Console printout from a testcase.
%%%
-%%% <p>This function is called by <code>ct</code> when printing
-%%% stuff from a testcase on the user console.</p>
+%%% This function is called by ct when printing
+%%% stuff from a testcase on the user console.
tc_print(Category,Importance,Format,Args,Opts) ->
VLvl = case ct_util:get_verbosity(Category) of
undefined ->
@@ -549,7 +542,7 @@ tc_print(Category,Importance,Format,Args,Opts) ->
undefined -> atom_to_list(Category);
Hd -> Hd
end,
- Str = lists:concat([get_header(Heading),Format,"\n\n"]),
+ Str = lists:flatten([get_header(Heading),Format,"\n\n"]),
try
io:format(?def_gl, Str, Args)
catch
@@ -572,44 +565,44 @@ get_header(Heading) ->
%%%-----------------------------------------------------------------
-%%% @spec tc_pal(Category,Format,Args) -> ok
-%%% @equiv tc_pal(Category,?STD_IMPORTANCE,Format,Args,[]) -> ok
+%%% -spec tc_pal(Category,Format,Args) -> ok
+%%% Equivalent to tc_pal(Category,?STD_IMPORTANCE,Format,Args,[]) -> ok
tc_pal(Category,Format,Args) ->
tc_pal(Category,?STD_IMPORTANCE,Format,Args,[]).
%%%-----------------------------------------------------------------
-%%% @spec tc_pal(Category,Importance,Format,Args) -> ok
-%%% @equiv tc_pal(Category,Importance,Format,Args,[]) -> ok
+%%% -spec tc_pal(Category,Importance,Format,Args) -> ok
+%%% Equivalent to tc_pal(Category,Importance,Format,Args,[]) -> ok
tc_pal(Category,Importance,Format,Args) ->
tc_pal(Category,Importance,Format,Args,[]).
%%%-----------------------------------------------------------------
-%%% @spec tc_pal(Category,Importance,Format,Args,Opts) -> ok
+%%% -spec tc_pal(Category,Importance,Format,Args,Opts) -> ok
%%% Category = atom()
%%% Importance = integer()
%%% Format = string()
%%% Args = list()
%%% Opts = list()
%%%
-%%% @doc Print and log from a testcase.
+%%% Print and log from a testcase.
%%%
-%%% <p>This function is called by <code>ct</code> when logging
+%%% This function is called by ct when logging
%%% stuff directly from a testcase. The info is written both in the
-%%% log and on the console.</p>
+%%% log and on the console.
tc_pal(Category,Importance,Format,Args,Opts) ->
tc_print(Category,Importance,Format,Args,Opts),
tc_log(Category,Importance,"User",Format,Args,[esc_chars|Opts]).
%%%-----------------------------------------------------------------
-%%% @spec ct_log(Category,Format,Args) -> ok
+%%% -spec ct_log(Category,Format,Args) -> ok
%%% Category = atom()
%%% Format = string()
%%% Args = list()
%%%
-%%% @doc Print to the ct framework log
+%%% Print to the ct framework log
%%%
-%%% <p>This function is called by internal ct functions to
-%%% force logging to the ct framework log</p>
+%%% This function is called by internal ct functions to
+%%% force logging to the ct framework log
ct_log(Category,Format,Args) ->
cast({ct_log,[{hd,div_header(Category),[]},
{Format,Args},
@@ -942,7 +935,7 @@ create_io_fun(FromPid, CtLogFd, EscChars) ->
{_HdOrFt,S,A} -> {false,S,A};
{S,A} -> {true,S,A}
end,
- try io_lib:format(Str, Args) of
+ try io_lib:format(lists:flatten(Str), Args) of
IoStr when Escapable, EscChars, IoList == [] ->
escape_chars(IoStr);
IoStr when Escapable, EscChars ->
@@ -1145,10 +1138,10 @@ set_evmgr_gl(GL) ->
open_ctlog(MiscIoName) ->
{ok,Fd} = file:open(?ct_log_name,[write,{encoding,utf8}]),
- io:format(Fd, header("Common Test Framework Log", {[],[1,2],[]}), []),
+ io:format(Fd, "~ts", [header("Common Test Framework Log", {[],[1,2],[]})]),
case file:consult(ct_run:variables_file_name("../")) of
{ok,Vars} ->
- io:format(Fd, config_table(Vars), []);
+ io:format(Fd, "~ts", [config_table(Vars)]);
{error,Reason} ->
{ok,Cwd} = file:get_cwd(),
Dir = filename:dirname(Cwd),
@@ -1191,26 +1184,23 @@ print_style(Fd, IoFormat, StyleSheet) ->
case file:read_file(StyleSheet) of
{ok,Bin} ->
Str = b2s(Bin,encoding(StyleSheet)),
- Pos0 = case string:str(Str,"<style>") of
- 0 -> string:str(Str,"<STYLE>");
- N0 -> N0
- end,
- Pos1 = case string:str(Str,"</style>") of
- 0 -> string:str(Str,"</STYLE>");
- N1 -> N1
- end,
- if (Pos0 == 0) and (Pos1 /= 0) ->
- print_style_error(Fd, IoFormat,
- StyleSheet, missing_style_start_tag);
- (Pos0 /= 0) and (Pos1 == 0) ->
- print_style_error(Fd, IoFormat,
- StyleSheet,missing_style_end_tag);
- Pos0 /= 0 ->
- Style = string:sub_string(Str,Pos0,Pos1+7),
- IoFormat(Fd,"~ts\n",[Style]);
- Pos0 == 0 ->
- IoFormat(Fd,"<style>\n~ts</style>\n",[Str])
- end;
+ case re:run(Str,"<style>.*</style>",
+ [dotall,caseless,{capture,all,list}]) of
+ nomatch ->
+ case re:run(Str,"</?style>",[caseless,{capture,all,list}]) of
+ nomatch ->
+ IoFormat(Fd,"<style>\n~ts</style>\n",[Str]);
+ {match,["</"++_]} ->
+ print_style_error(Fd, IoFormat,
+ StyleSheet,
+ missing_style_start_tag);
+ {match,[_]} ->
+ print_style_error(Fd, IoFormat,
+ StyleSheet,missing_style_end_tag)
+ end;
+ {match,[Style]} ->
+ IoFormat(Fd,"~ts\n",[Style])
+ end;
{error,Reason} ->
print_style_error(Fd,IoFormat,StyleSheet,Reason)
end.
@@ -1223,7 +1213,7 @@ print_style_error(Fd, IoFormat, StyleSheet, Reason) ->
close_ctlog(Fd) ->
io:format(Fd, "\n</pre>\n", []),
- io:format(Fd, [xhtml("<br><br>\n", "<br /><br />\n") | footer()], []),
+ io:format(Fd, "~ts", [[xhtml("<br><br>\n", "<br /><br />\n") | footer()]]),
ok = file:close(Fd).
%%%-----------------------------------------------------------------
@@ -1417,9 +1407,9 @@ make_one_index_entry1(SuiteName, Link, Label, Success, Fail, UserSkip, AutoSkip,
{Lbl,Timestamp,Node,AllInfo} =
case All of
{true,OldRuns} ->
- [_Prefix,NodeOrDate|_] = string:tokens(Link,"."),
- Node1 = case string:chr(NodeOrDate,$@) of
- 0 -> "-";
+ [_Prefix,NodeOrDate|_] = string:lexemes(Link,"."),
+ Node1 = case string:find(NodeOrDate,[$@]) of
+ nomatch -> "-";
_ -> NodeOrDate
end,
@@ -1526,7 +1516,7 @@ not_built(BaseName,_LogDir,_All,Missing) ->
%% Top.ObjDir | Top.ObjDir.suites | Top.ObjDir.Suite |
%% Top.ObjDir.Suite.cases | Top.ObjDir.Suite.Case
Failed =
- case string:tokens(BaseName,".") of
+ case string:lexemes(BaseName,".") of
[T,O] when is_list(T) -> % all under Top.ObjDir
locate_info({T,O},all,Missing);
[T,O,"suites"] ->
@@ -2032,7 +2022,7 @@ update_all_runs_in_cache(AllRunsData) ->
%% read from file as long as this logger process is alive
put(ct_log_cache,term_to_binary(LogCache));
_ ->
- file:write_file(?log_cache_name,term_to_binary(LogCache))
+ write_log_cache(term_to_binary(LogCache))
end;
SavedLogCache ->
update_all_runs_in_cache(AllRunsData,binary_to_term(SavedLogCache))
@@ -2046,7 +2036,7 @@ update_all_runs_in_cache(AllRunsData, LogCache) ->
%% read from file as long as this logger process is alive
put(ct_log_cache,term_to_binary(LogCache1));
_ ->
- file:write_file(?log_cache_name,term_to_binary(LogCache1))
+ write_log_cache(term_to_binary(LogCache1))
end.
sort_all_runs(Dirs) ->
@@ -2054,9 +2044,9 @@ sort_all_runs(Dirs) ->
%% "YYYY-MM-DD_HH.MM.SS"
lists:sort(fun(Dir1,Dir2) ->
[SS1,MM1,HH1,Date1|_] =
- lists:reverse(string:tokens(Dir1,[$.,$_])),
+ lists:reverse(string:lexemes(Dir1,[$.,$_])),
[SS2,MM2,HH2,Date2|_] =
- lists:reverse(string:tokens(Dir2,[$.,$_])),
+ lists:reverse(string:lexemes(Dir2,[$.,$_])),
{Date1,HH1,MM1,SS1} > {Date2,HH2,MM2,SS2}
end, Dirs).
@@ -2066,9 +2056,9 @@ sort_ct_runs(Dirs) ->
lists:sort(
fun(Dir1,Dir2) ->
[SS1,MM1,DateHH1 | _] =
- lists:reverse(string:tokens(filename:dirname(Dir1),[$.])),
+ lists:reverse(string:lexemes(filename:dirname(Dir1),[$.])),
[SS2,MM2,DateHH2 | _] =
- lists:reverse(string:tokens(filename:dirname(Dir2),[$.])),
+ lists:reverse(string:lexemes(filename:dirname(Dir2),[$.])),
{DateHH1,MM1,SS1} =< {DateHH2,MM2,SS2}
end, Dirs).
@@ -2214,27 +2204,15 @@ runentry(Dir, Totals={Node,Label,Logs,
0 -> "-";
N -> integer_to_list(N)
end,
- StripExt =
- fun(File) ->
- string:sub_string(File,1,
- length(File)-
- length(?logdir_ext)) ++ ", "
- end,
- Polish = fun(S) -> case lists:reverse(S) of
- [32,$,|Rev] -> lists:reverse(Rev);
- [$,|Rev] -> lists:reverse(Rev);
- _ -> S
- end
- end,
- TestNames = Polish(lists:flatten(lists:map(StripExt,Logs))),
+
+ RootNames = lists:map(fun(F) -> filename:rootname(F,?logdir_ext) end, Logs),
+ TestNames = lists:flatten(lists:join(", ", RootNames)),
TestNamesTrunc =
- if TestNames=="" ->
- "";
- length(TestNames) < ?testname_width ->
+ if length(TestNames) < ?testname_width ->
TestNames;
true ->
- Trunc = Polish(string:substr(TestNames,1,
- ?testname_width-3)),
+ Trunc = string:trim(string:slice(TestNames,0,?testname_width-3),
+ trailing,",\s"),
lists:flatten(io_lib:format("~ts...",[Trunc]))
end,
TotMissingStr =
@@ -2377,7 +2355,7 @@ force_rename(From,To,Number) ->
timestamp(Dir) ->
- TsR = lists:reverse(string:tokens(Dir,".-_")),
+ TsR = lists:reverse(string:lexemes(Dir,".-_")),
[S,Min,H,D,M,Y] = [list_to_integer(N) || N <- lists:sublist(TsR,6)],
format_time({{Y,M,D},{H,Min,S}}).
@@ -2690,7 +2668,7 @@ update_tests_in_cache(TempData,LogCache=#log_cache{tests=Tests}) ->
{_Pid,_Pid} ->
put(ct_log_cache,CacheBin);
_ ->
- file:write_file(?log_cache_name,CacheBin)
+ write_log_cache(CacheBin)
end.
%%
@@ -2926,7 +2904,7 @@ cache_vsn() ->
VSNfile = filename:join([EbinDir,"..","vsn.mk"]),
case file:read_file(VSNfile) of
{ok,Bin} ->
- [_,VSN] = string:tokens(binary_to_list(Bin),[$=,$\n,$ ]),
+ [_,VSN] = string:lexemes(binary_to_list(Bin),[$=,$\n,$ ]),
VSN;
_ ->
undefined
@@ -3008,13 +2986,13 @@ rm_files([]) ->
ok.
%%%-----------------------------------------------------------------
-%%% @spec simulate() -> pid()
+%%% -spec simulate() -> pid()
%%%
-%%% @doc Simulate the logger process.
+%%% Simulate the logger process.
%%%
-%%% <p>Simulate the logger process - for use when testing code using
+%%% Simulate the logger process - for use when testing code using
%%% ct_logs logging mechanism without using the ct
-%%% environment. (E.g. when testing code with ts)</p>
+%%% environment. (E.g. when testing code with ts)
simulate() ->
cast(stop),
S = self(),
@@ -3042,9 +3020,7 @@ simulate_logger_loop() ->
end.
%%%-----------------------------------------------------------------
-%%% @spec notify_and_lock_file(Files) -> ok
-%%%
-%%% @doc
+%%% -spec notify_and_lock_file(Files) -> ok
%%%
notify_and_lock_file(File) ->
case ct_event:is_alive() of
@@ -3057,9 +3033,7 @@ notify_and_lock_file(File) ->
end.
%%%-----------------------------------------------------------------
-%%% @spec notify_and_unlock_file(Files) -> ok
-%%%
-%%% @doc
+%%% -spec notify_and_unlock_file(Files) -> ok
%%%
notify_and_unlock_file(File) ->
case ct_event:is_alive() of
@@ -3072,9 +3046,7 @@ notify_and_unlock_file(File) ->
end.
%%%-----------------------------------------------------------------
-%%% @spec get_run_dirs(Dir) -> [string()] | false
-%%%
-%%% @doc
+%%% -spec get_run_dirs(Dir) -> [string()] | false
%%%
get_run_dirs(Dir) ->
case filelib:wildcard(filename:join(Dir, "run.[1-2]*")) of
@@ -3085,9 +3057,7 @@ get_run_dirs(Dir) ->
end.
%%%-----------------------------------------------------------------
-%%% @spec xhtml(HTML, XHTML) -> HTML | XHTML
-%%%
-%%% @doc
+%%% -spec xhtml(HTML, XHTML) -> HTML | XHTML
%%%
xhtml(HTML, XHTML) when is_function(HTML),
is_function(XHTML) ->
@@ -3102,9 +3072,7 @@ xhtml(HTML, XHTML) ->
end.
%%%-----------------------------------------------------------------
-%%% @spec odd_or_even() -> "odd" | "even"
-%%%
-%%% @doc
+%%% -spec odd_or_even() -> "odd" | "even"
%%%
odd_or_even() ->
case get(odd_or_even) of
@@ -3117,9 +3085,7 @@ odd_or_even() ->
end.
%%%-----------------------------------------------------------------
-%%% @spec basic_html() -> true | false
-%%%
-%%% @doc
+%%% -spec basic_html() -> true | false
%%%
basic_html() ->
case application:get_env(common_test, basic_html) of
@@ -3130,9 +3096,7 @@ basic_html() ->
end.
%%%-----------------------------------------------------------------
-%%% @spec locate_priv_file(FileName) -> PrivFile
-%%%
-%%% @doc
+%%% -spec locate_priv_file(FileName) -> PrivFile
%%%
locate_priv_file(FileName) ->
{ok,CWD} = file:get_cwd(),
@@ -3162,13 +3126,13 @@ locate_priv_file(FileName) ->
end.
%%%-----------------------------------------------------------------
-%%% @spec make_relative(AbsDir, Cwd) -> RelDir
+%%% -spec make_relative(AbsDir, Cwd) -> RelDir
%%%
-%%% @doc Return directory path to File (last element of AbsDir), which
-%%% is the path relative to Cwd. Examples when Cwd == "/ldisk/test/logs":
-%%% make_relative("/ldisk/test/logs/run/trace.log") -> "run/trace.log"
-%%% make_relative("/ldisk/test/trace.log") -> "../trace.log"
-%%% make_relative("/ldisk/test/logs/trace.log") -> "trace.log"
+%%% Return directory path to File (last element of AbsDir), which
+%%% is the path relative to Cwd. Examples when Cwd == "/ldisk/test/logs":
+%%% make_relative("/ldisk/test/logs/run/trace.log") -> "run/trace.log"
+%%% make_relative("/ldisk/test/trace.log") -> "../trace.log"
+%%% make_relative("/ldisk/test/logs/trace.log") -> "trace.log"
make_relative(AbsDir) ->
{ok,Cwd} = file:get_cwd(),
make_relative(AbsDir, Cwd).
@@ -3192,11 +3156,9 @@ make_relative1(DirTs, CwdTs) ->
Ups ++ DirTs.
%%%-----------------------------------------------------------------
-%%% @spec get_ts_html_wrapper(TestName, PrintLabel, Cwd, TableCols, Encoding)
+%%% -spec get_ts_html_wrapper(TestName, PrintLabel, Cwd, TableCols, Encoding)
%%% -> {Mode,Header,Footer}
%%%
-%%% @doc
-%%%
get_ts_html_wrapper(TestName, PrintLabel, Cwd, TableCols, Encoding) ->
get_ts_html_wrapper(TestName, undefined, PrintLabel, Cwd, TableCols, Encoding).
@@ -3332,7 +3294,7 @@ insert_javascript({tablesorter,TableName,
end, [{"CTDateSorter",DateCols},
{"CTTextSorter",TextCols},
{"CTValSorter",ValCols}]))),
- Headers1 = string:substr(Headers, 1, length(Headers)-2),
+ Headers1 = string:trim(Headers, trailing, ",\n"),
["<script type=\"text/javascript\">\n",
"// Parser for date format, e.g: Wed Jul 4 2012 11:24:15\n",
@@ -3438,3 +3400,9 @@ unexpected_io(Pid, _Category, _Importance, Content, CtLogFd, EscChars) ->
Data = io_lib:format("~ts", [lists:foldl(IoFun, [], Content)]),
test_server_io:print_unexpected(Data),
ok.
+
+write_log_cache(LogCacheBin) when is_binary(LogCacheBin) ->
+ TmpFile = ?log_cache_name++".tmp",
+ _ = file:write_file(TmpFile,LogCacheBin),
+ _ = file:rename(TmpFile,?log_cache_name),
+ ok.
diff --git a/lib/common_test/src/ct_master.erl b/lib/common_test/src/ct_master.erl
index ef2aff69b7..9fc169789c 100644
--- a/lib/common_test/src/ct_master.erl
+++ b/lib/common_test/src/ct_master.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,9 +18,6 @@
%% %CopyrightEnd%
%%
-%%% @doc Distributed test execution control for Common Test.
-%%% <p>This module exports functions for running Common Test nodes
-%%% on multiple hosts in parallel.</p>
-module(ct_master).
-export([run/1,run/3,run/4]).
@@ -45,50 +42,14 @@
blocked=[]
}).
-%%%-----------------------------------------------------------------
-%%% @spec run_test(Node,Opts) -> ok
-%%% Node = atom()
-%%% Opts = [OptTuples]
-%%% OptTuples = {config,CfgFiles} | {dir,TestDirs} | {suite,Suites} |
-%%% {testcase,Cases} | {spec,TestSpecs} | {allow_user_terms,Bool} |
-%%% {logdir,LogDir} | {event_handler,EventHandlers} |
-%%% {silent_connections,Conns} | {cover,CoverSpecFile} |
-%%% {cover_stop,Bool} | {userconfig, UserCfgFiles}
-%%% CfgFiles = string() | [string()]
-%%% TestDirs = string() | [string()]
-%%% Suites = atom() | [atom()]
-%%% Cases = atom() | [atom()]
-%%% TestSpecs = string() | [string()]
-%%% LogDir = string()
-%%% EventHandlers = EH | [EH]
-%%% EH = atom() | {atom(),InitArgs} | {[atom()],InitArgs}
-%%% InitArgs = [term()]
-%%% Conns = all | [atom()]
-%%%
-%%% @doc Tests are spawned on <code>Node</code> using <code>ct:run_test/1</code>.
run_test(Node,Opts) ->
run_test([{Node,Opts}]).
-%%% @hidden
run_test({Node,Opts}) ->
run_test([{Node,Opts}]);
run_test(NodeOptsList) when is_list(NodeOptsList) ->
start_master(NodeOptsList).
-%%%-----------------------------------------------------------------
-%%% @spec run(TestSpecs,AllowUserTerms,InclNodes,ExclNodes) -> ok
-%%% TestSpecs = string() | [SeparateOrMerged]
-%%% SeparateOrMerged = string() | [string()]
-%%% AllowUserTerms = bool()
-%%% InclNodes = [atom()]
-%%% ExclNodes = [atom()]
-%%%
-%%% @doc Tests are spawned on the nodes as specified in <code>TestSpecs</code>.
-%%% Each specification in TestSpec will be handled separately. It is however
-%%% possible to also specify a list of specifications that should be merged
-%%% into one before the tests are executed. Any test without a particular node
-%%% specification will also be executed on the nodes in <code>InclNodes</code>.
-%%% Nodes in the <code>ExclNodes</code> list will be excluded from the test.
run([TS|TestSpecs],AllowUserTerms,InclNodes,ExclNodes) when is_list(TS),
is_list(InclNodes),
is_list(ExclNodes) ->
@@ -128,22 +89,9 @@ run(TS,AllowUserTerms,InclNodes,ExclNodes) when is_list(InclNodes),
is_list(ExclNodes) ->
run([TS],AllowUserTerms,InclNodes,ExclNodes).
-%%%-----------------------------------------------------------------
-%%% @spec run(TestSpecs,InclNodes,ExclNodes) -> ok
-%%% TestSpecs = string() | [SeparateOrMerged]
-%%% SeparateOrMerged = string() | [string()]
-%%% InclNodes = [atom()]
-%%% ExclNodes = [atom()]
-%%%
-%%% @equiv run(TestSpecs,false,InclNodes,ExclNodes)
run(TestSpecs,InclNodes,ExclNodes) ->
run(TestSpecs,false,InclNodes,ExclNodes).
-%%%-----------------------------------------------------------------
-%%% @spec run(TestSpecs) -> ok
-%%% TestSpecs = string() | [SeparateOrMerged]
-%%%
-%%% @equiv run(TestSpecs,false,[],[])
run(TestSpecs=[TS|_]) when is_list(TS) ->
run(TestSpecs,false,[],[]);
run(TS) ->
@@ -156,15 +104,6 @@ exclude_nodes([],RunSkipPerNode) ->
RunSkipPerNode.
-%%%-----------------------------------------------------------------
-%%% @spec run_on_node(TestSpecs,AllowUserTerms,Node) -> ok
-%%% TestSpecs = string() | [SeparateOrMerged]
-%%% SeparateOrMerged = string() | [string()]
-%%% AllowUserTerms = bool()
-%%% Node = atom()
-%%%
-%%% @doc Tests are spawned on <code>Node</code> according to
-%%% <code>TestSpecs</code>.
run_on_node([TS|TestSpecs],AllowUserTerms,Node) when is_list(TS),is_atom(Node) ->
case catch ct_testspec:collect_tests_from_file([TS],[Node],
AllowUserTerms) of
@@ -194,13 +133,6 @@ run_on_node([],_,_) ->
run_on_node(TS,AllowUserTerms,Node) when is_atom(Node) ->
run_on_node([TS],AllowUserTerms,Node).
-%%%-----------------------------------------------------------------
-%%% @spec run_on_node(TestSpecs,Node) -> ok
-%%% TestSpecs = string() | [SeparateOrMerged]
-%%% SeparateOrMerged = string() | [string()]
-%%% Node = atom()
-%%%
-%%% @equiv run_on_node(TestSpecs,false,Node)
run_on_node(TestSpecs,Node) ->
run_on_node(TestSpecs,false,Node).
@@ -264,64 +196,25 @@ run_all([],AllLogDirs,_,AllEvHs,_AllIncludes,
ok.
-%%%-----------------------------------------------------------------
-%%% @spec abort() -> ok
-%%%
-%%% @doc Stops all running tests.
abort() ->
call(abort).
-%%%-----------------------------------------------------------------
-%%% @spec abort(Nodes) -> ok
-%%% Nodes = atom() | [atom()]
-%%%
-%%% @doc Stops tests on specified nodes.
abort(Nodes) when is_list(Nodes) ->
call({abort,Nodes});
abort(Node) when is_atom(Node) ->
abort([Node]).
-%%%-----------------------------------------------------------------
-%%% @spec progress() -> [{Node,Status}]
-%%% Node = atom()
-%%% Status = finished_ok | ongoing | aborted | {error,Reason}
-%%% Reason = term()
-%%%
-%%% @doc Returns test progress. If <code>Status</code> is <code>ongoing</code>,
-%%% tests are running on the node and have not yet finished.
progress() ->
call(progress).
-%%%-----------------------------------------------------------------
-%%% @spec get_event_mgr_ref() -> MasterEvMgrRef
-%%% MasterEvMgrRef = atom()
-%%%
-%%% @doc <p>Call this function in order to get a reference to the
-%%% CT master event manager. The reference can be used to e.g.
-%%% add a user specific event handler while tests are running.
-%%% Example:
-%%% <c>gen_event:add_handler(ct_master:get_event_mgr_ref(), my_ev_h, [])</c></p>
get_event_mgr_ref() ->
?CT_MEVMGR_REF.
-%%%-----------------------------------------------------------------
-%%% @spec basic_html(Bool) -> ok
-%%% Bool = true | false
-%%%
-%%% @doc If set to true, the ct_master logs will be written on a
-%%% primitive html format, not using the Common Test CSS style
-%%% sheet.
basic_html(Bool) ->
application:set_env(common_test_master, basic_html, Bool),
ok.
-%%%-----------------------------------------------------------------
-%%% @spec esc_chars(Bool) -> ok
-%%% Bool = true | false
-%%%
-%%% @doc If set to false, the ct_master logs will be written without
-%%% special characters being escaped in the HTML logs.
esc_chars(Bool) ->
application:set_env(common_test_master, esc_chars, Bool),
ok.
@@ -340,7 +233,6 @@ start_master(NodeOptsList,EvHandlers,MasterLogDir,LogDirs,InitOptions,Specs) ->
{Master,Result} -> Result
end.
-%%% @hidden
init_master(Parent,NodeOptsList,EvHandlers,MasterLogDir,LogDirs,
InitOptions,Specs) ->
case whereis(ct_master) of
@@ -458,7 +350,7 @@ master_loop(#state{node_ctrl_pids=[],
io_lib:format("~-40.40.*ts~tp\n",
[$_,atom_to_list(Node),Result])
end,lists:reverse(Finished)),
- log(all,"TEST RESULTS",Str,[]),
+ log(all,"TEST RESULTS","~ts", [Str]),
log(all,"Info","Updating log files",[]),
refresh_logs(LogDirs,[]),
@@ -682,12 +574,11 @@ refresh_logs([],Refreshed) ->
io_lib:format("Refreshing logs in ~tp... ~tp",
[D,Result])
end,Refreshed),
- log(all,"Info",Str,[]).
+ log(all,"Info","~ts", [Str]).
%%%-----------------------------------------------------------------
%%% NODE CONTROLLER, runs and controls tests on a test node.
%%%-----------------------------------------------------------------
-%%% @hidden
init_node_ctrl(MasterPid,Cookie,Opts) ->
%% make sure tests proceed even if connection to master is lost
process_flag(trap_exit, true),
@@ -742,7 +633,6 @@ start_ct_event() ->
%%%-----------------------------------------------------------------
%%% Event handling
%%%-----------------------------------------------------------------
-%%% @hidden
status(MasterPid,Event=#event{name=start_make}) ->
call(MasterPid,Event);
status(MasterPid,Event=#event{name=finished_make}) ->
@@ -809,7 +699,7 @@ filter_accessible(InitOptions, Inaccessible)->
start_nodes(InitOptions)->
lists:foreach(fun({NodeName, Options})->
- [NodeS,HostS]=string:tokens(atom_to_list(NodeName), "@"),
+ [NodeS,HostS]=string:lexemes(atom_to_list(NodeName), "@"),
Node=list_to_atom(NodeS),
Host=list_to_atom(HostS),
HasNodeStart = lists:keymember(node_start, 1, Options),
diff --git a/lib/common_test/src/ct_master_event.erl b/lib/common_test/src/ct_master_event.erl
index bd4d1efc92..a6ec5a7a75 100644
--- a/lib/common_test/src/ct_master_event.erl
+++ b/lib/common_test/src/ct_master_event.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,13 +18,13 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Framework Event Handler
+%%% Common Test Framework Event Handler
%%%
-%%% <p>This module implements an event handler that the CT Master
+%%% This module implements an event handler that the CT Master
%%% uses to handle status and progress notifications sent to the
%%% master node during test runs. This module may be used as a
%%% template for other event handlers that can be plugged in to
-%%% handle logging and reporting on the master node.</p>
+%%% handle logging and reporting on the master node.
-module(ct_master_event).
-behaviour(gen_event).
diff --git a/lib/common_test/src/ct_master_logs.erl b/lib/common_test/src/ct_master_logs.erl
index c4bb2cc69f..ea6f93b565 100644
--- a/lib/common_test/src/ct_master_logs.erl
+++ b/lib/common_test/src/ct_master_logs.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,10 +18,10 @@
%% %CopyrightEnd%
%%
-%%% @doc Logging functionality for Common Test Master.
+%%% Logging functionality for Common Test Master.
%%%
-%%% <p>This module implements a logger for the master
-%%% node.</p>
+%%% This module implements a logger for the master
+%%% node.
-module(ct_master_logs).
-export([start/2, make_all_runs_index/0, log/3, nodedir/2,
@@ -298,7 +298,7 @@ sort_all_runs(Dirs) ->
%% "YYYY-MM-DD_HH.MM.SS"
KeyList =
lists:map(fun(Dir) ->
- case lists:reverse(string:tokens(Dir,[$.,$_])) of
+ case lists:reverse(string:lexemes(Dir,[$.,$_])) of
[SS,MM,HH,Date|_] ->
{{Date,HH,MM,SS},Dir};
_Other ->
@@ -313,18 +313,8 @@ runentry(Dir) ->
{MasterStr,NodesStr} =
case read_details_file(Dir) of
{Master,Nodes} when is_list(Nodes) ->
- [_,Host] = string:tokens(atom_to_list(Master),"@"),
- NodesList =
- lists:reverse(lists:map(fun(N) ->
- atom_to_list(N) ++ ", "
- end,Nodes)),
- case NodesList of
- [N|NListR] ->
- N1 = string:sub_string(N,1,length(N)-2),
- {Host,lists:flatten(lists:reverse([N1|NListR]))};
- [] ->
- {Host,""}
- end;
+ [_,Host] = string:lexemes(atom_to_list(Master),"@"),
+ {Host,lists:concat(lists:join(", ",Nodes))};
_Error ->
{"unknown",""}
end,
@@ -349,7 +339,7 @@ all_runs_header() ->
xhtml("", "</tr></thead>\n<tbody>\n")]].
timestamp(Dir) ->
- [S,Min,H,D,M,Y|_] = lists:reverse(string:tokens(Dir,".-_")),
+ [S,Min,H,D,M,Y|_] = lists:reverse(string:lexemes(Dir,".-_")),
[S1,Min1,H1,D1,M1,Y1] = [list_to_integer(N) || N <- [S,Min,H,D,M,Y]],
format_time({{Y1,M1,D1},{H1,Min1,S1}}).
diff --git a/lib/common_test/src/ct_master_status.erl b/lib/common_test/src/ct_master_status.erl
index b27fdd341e..cb01220121 100644
--- a/lib/common_test/src/ct_master_status.erl
+++ b/lib/common_test/src/ct_master_status.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,12 +18,12 @@
%% %CopyrightEnd%
%%
-%%% @doc Logging functionality for Common Test Master.
+%%% doc Logging functionality for Common Test Master.
%%%
-%%% <p>This module keeps a list of <code>{Node,Status}</code>
+%%% This module keeps a list of {Node,Status}
%%% tuples. It is possible to anytime during a test run get
%%% a snapshot of the test status. The module is an event
-%%% handler for the master event manager.</p>
+%%% handler for the master event manager.
-module(ct_master_status).
-behaviour(gen_event).
diff --git a/lib/common_test/src/ct_netconfc.erl b/lib/common_test/src/ct_netconfc.erl
index 2c4b97df20..6a758c4ea3 100644
--- a/lib/common_test/src/ct_netconfc.erl
+++ b/lib/common_test/src/ct_netconfc.erl
@@ -583,7 +583,7 @@ get_config(Client, Source, Filter, Timeout) ->
-spec edit_config(Client, Target, Config) -> Result when
Client :: client(),
Target :: netconf_db(),
- Config :: simple_xml(),
+ Config :: simple_xml() | [simple_xml()],
Result :: ok | {error,error_reason()}.
edit_config(Client, Target, Config) ->
edit_config(Client, Target, Config, ?DEFAULT_TIMEOUT).
@@ -591,7 +591,7 @@ edit_config(Client, Target, Config) ->
-spec edit_config(Client, Target, Config, OptParams) -> Result when
Client :: client(),
Target :: netconf_db(),
- Config :: simple_xml(),
+ Config :: simple_xml() | [simple_xml()],
OptParams :: [simple_xml()],
Result :: ok | {error,error_reason()};
(Client, Target, Config, Timeout) -> Result when
@@ -608,10 +608,12 @@ edit_config(Client, Target, Config, OptParams) when is_list(OptParams) ->
-spec edit_config(Client, Target, Config, OptParams, Timeout) -> Result when
Client :: client(),
Target :: netconf_db(),
- Config :: simple_xml(),
+ Config :: simple_xml() | [simple_xml()],
OptParams :: [simple_xml()],
Timeout :: timeout(),
Result :: ok | {error,error_reason()}.
+edit_config(Client, Target, Config, OptParams, Timeout) when not is_list(Config)->
+ edit_config(Client, Target, [Config], OptParams, Timeout);
edit_config(Client, Target, Config, OptParams, Timeout) ->
call(Client, {send_rpc_op, edit_config, [Target,Config,OptParams], Timeout}).
@@ -1113,7 +1115,7 @@ encode_rpc_operation(get,[Filter]) ->
encode_rpc_operation(get_config,[Source,Filter]) ->
{'get-config',[{source,[Source]}] ++ filter(Filter)};
encode_rpc_operation(edit_config,[Target,Config,OptParams]) ->
- {'edit-config',[{target,[Target]}] ++ OptParams ++ [{config,[Config]}]};
+ {'edit-config',[{target,[Target]}] ++ OptParams ++ [{config,Config}]};
encode_rpc_operation(delete_config,[Target]) ->
{'delete-config',[{target,[Target]}]};
encode_rpc_operation(copy_config,[Target,Source]) ->
@@ -1467,7 +1469,7 @@ decode_data(Other) ->
{error,{unexpected_rpc_reply,Other}}.
get_qualified_name(Tag) ->
- case string:tokens(atom_to_list(Tag),":") of
+ case string:lexemes(atom_to_list(Tag),":") of
[TagStr] -> {[],TagStr};
[PrefixStr,TagStr] -> {PrefixStr,TagStr}
end.
diff --git a/lib/common_test/src/ct_netconfc.hrl b/lib/common_test/src/ct_netconfc.hrl
index 5eeeafa318..1d81c762ba 100644
--- a/lib/common_test/src/ct_netconfc.hrl
+++ b/lib/common_test/src/ct_netconfc.hrl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,9 +24,7 @@
%% This file defines constant values and records used by the
%% netconf client ct_netconfc.
%%
-%% @author Support
-%% @doc Netconf Client Interface.
-%% @end
+%% Netconf Client Interface.
%%----------------------------------------------------------------------
%%----------------------------------------------------------------------
diff --git a/lib/common_test/src/ct_property_test.erl b/lib/common_test/src/ct_property_test.erl
index 94ccb59af9..f51f454d08 100644
--- a/lib/common_test/src/ct_property_test.erl
+++ b/lib/common_test/src/ct_property_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -28,46 +28,6 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%% @doc EXPERIMENTAL support in common-test for calling property based tests.
-%%%
-%%% <p>This module is a first step towards running Property Based testing in the
-%%% Common Test framework. A property testing tool like QuickCheck or PropEr is
-%%% assumed to be installed.</p>
-%%%
-%%% <p>The idea is to have a common_test testsuite calling a property testing
-%%% tool with special property test suites as defined by that tool. In this manual
-%%% we assume the usual Erlang Application directory structure. The tests are
-%%% collected in the application's <c>test</c> directory. The test directory
-%%% has a sub-directory called <c>property_test</c> where everything needed for
-%%% the property tests are collected.</p>
-%%%
-%%% <p>A typical ct test suite using <c>ct_property_test</c> is organized as follows:
-%%% </p>
-%%% ```
-%%% -include_lib("common_test/include/ct.hrl").
-%%%
-%%% all() -> [prop_ftp_case].
-%%%
-%%% init_per_suite(Config) ->
-%%% ct_property_test:init_per_suite(Config).
-%%%
-%%% %%%---- test case
-%%% prop_ftp_case(Config) ->
-%%% ct_property_test:quickcheck(
-%%% ftp_simple_client_server:prop_ftp(Config),
-%%% Config
-%%% ).
-%%% '''
-%%%
-%%% <warning>
-%%% <p>
-%%% This is experimental code which may be changed or removed
-%%% anytime without any warning.
-%%% </p>
-%%% </warning>
-%%%
-%%% @end
-
-module(ct_property_test).
%% API
@@ -76,19 +36,6 @@
-include_lib("common_test/include/ct.hrl").
-%%%-----------------------------------------------------------------
-%%% @spec init_per_suite(Config) -> Config | {skip,Reason}
-%%%
-%%% @doc Initializes Config for property testing.
-%%%
-%%% <p>The function investigates if support is available for either Quickcheck, PropEr,
-%%% or Triq.
-%%% The options <c>{property_dir,AbsPath}</c> and
-%%% <c>{property_test_tool,Tool}</c> is set in the Config returned.</p>
-%%% <p>The function is intended to be called in the init_per_suite in the test suite.</p>
-%%% <p>The property tests are assumed to be in the subdirectory <c>property_test</c>.</p>
-%%% @end
-
init_per_suite(Config) ->
case which_module_exists([eqc,proper,triq]) of
{ok,ToolModule} ->
@@ -108,14 +55,6 @@ init_per_suite(Config) ->
{skip, "No property testing tool found"}
end.
-%%%-----------------------------------------------------------------
-%%% @spec quickcheck(Property, Config) -> true | {fail,Reason}
-%%%
-%%% @doc Call quickcheck and return the result in a form suitable for common_test.
-%%%
-%%% <p>The function is intended to be called in the test cases in the test suite.</p>
-%%% @end
-
quickcheck(Property, Config) ->
Tool = proplists:get_value(property_test_tool,Config),
F = function_name(quickcheck, Tool),
diff --git a/lib/common_test/src/ct_release_test.erl b/lib/common_test/src/ct_release_test.erl
index 551a7e06d7..ac3dcab7c9 100644
--- a/lib/common_test/src/ct_release_test.erl
+++ b/lib/common_test/src/ct_release_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2014-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2014-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,7 +18,7 @@
%% %CopyrightEnd%
%%
%%-----------------------------------------------------------------
-%% @doc EXPERIMENTAL support for testing of upgrade.
+%% EXPERIMENTAL support for testing of upgrade.
%%
%% This is a library module containing support for test of release
%% related activities in one or more applications. Currenty it
@@ -27,7 +27,7 @@
%% == Configuration ==
%%
%% In order to find version numbers of applications to upgrade from,
-%% `{@module}' needs to access and start old OTP
+%% ct_release_test needs to access and start old OTP
%% releases. A `common_test' configuration file can be used for
%% specifying the location of such releases, for example:
%%
@@ -39,48 +39,45 @@
%% The configuration file should preferably point out the latest patch
%% level on each major release.
%%
-%% If no such configuration file is given, {@link init/1} will return
-%% `{skip,Reason}' and any attempt at running {@link upgrade/4}
+%% If no such configuration file is given, init/1 will return
+%% {skip,Reason} and any attempt at running upgrade/4
%% will fail.
%%
%% == Callback functions ==
%%
-%% The following functions should be exported from a {@module}
+%% The following functions should be exported from a ct_release_test
%% callback module.
%%
%% All callback functions are called on the node where the upgrade is
%% executed.
%%
-%% <dl>
-%% <dt>Module:upgrade_init(CtData,State) -> NewState</dt>
-%% <dd>Types:
+%% Module:upgrade_init(CtData,State) -> NewState
+%% Types:
%%
-%% <b><code>CtData = {@link ct_data()}</code></b><br/>
-%% <b><code>State = NewState = cb_state()</code></b>
+%% CtData = ct_data()
+%% State = NewState = cb_state()
%%
%% Initialyze system before upgrade test starts.
%%
%% This function is called before the upgrade is started. All
-%% applications given in {@link upgrade/4} are already started by
+%% applications given in upgrade/4 are already started by
%% the boot script, so this callback is intended for additional
%% initialization, if necessary.
%%
-%% <code>CtData</code> is an opaque data structure which shall be used
-%% in any call to <code>ct_release_test</code> inside the callback.
+%% CtData is an opaque data structure which shall be used
+%% in any call to ct_release_test inside the callback.
%%
%% Example:
%%
-%% ```
%% upgrade_init(CtData,State) ->
%% {ok,{FromVsn,ToVsn}} = ct_release_test:get_app_vsns(CtData,myapp),
-%% open_connection(State).'''
-%% </dd>
+%% open_connection(State).
%%
-%% <dt>Module:upgrade_upgraded(CtData,State) -> NewState</dt>
-%% <dd>Types:
+%% Module:upgrade_upgraded(CtData,State) -> NewState
+%% Types:
%%
-%% <b><code>CtData = {@link ct_data()}</code></b><br/>
-%% <b><code>State = NewState = cb_state()</code></b>
+%% CtData = ct_data()
+%% State = NewState = cb_state()
%%
%% Check that upgrade was successful.
%%
@@ -89,21 +86,19 @@
%% been made permanent. It allows application specific checks to
%% ensure that the upgrade was successful.
%%
-%% <code>CtData</code> is an opaque data structure which shall be used
-%% in any call to <code>ct_release_test</code> inside the callback.
+%% CtData is an opaque data structure which shall be used
+%% in any call to ct_release_test inside the callback.
%%
%% Example:
%%
-%% ```
%% upgrade_upgraded(CtData,State) ->
-%% check_connection_still_open(State).'''
-%% </dd>
+%% check_connection_still_open(State).
%%
-%% <dt>Module:upgrade_downgraded(CtData,State) -> NewState</dt>
-%% <dd>Types:
+%% Module:upgrade_downgraded(CtData,State) -> NewState
+%% Types:
%%
-%% <b><code>CtData = {@link ct_data()}</code></b><br/>
-%% <b><code>State = NewState = cb_state()</code></b>
+%% CtData = ct_data()
+%% State = NewState = cb_state()
%%
%% Check that downgrade was successful.
%%
@@ -112,17 +107,13 @@
%% made permanent. It allows application specific checks to ensure
%% that the downgrade was successful.
%%
-%% <code>CtData</code> is an opaque data structure which shall be used
-%% in any call to <code>ct_release_test</code> inside the callback.
+%% CtData is an opaque data structure which shall be used
+%% in any call to ct_release_test inside the callback.
%%
%% Example:
%%
-%% ```
%% upgrade_downgraded(CtData,State) ->
-%% check_connection_closed(State).'''
-%% </dd>
-%% </dl>
-%% @end
+%% check_connection_closed(State).
%%-----------------------------------------------------------------
-module(ct_release_test).
@@ -152,7 +143,7 @@
Config :: config(),
Result :: config() | SkipOrFail,
SkipOrFail :: {skip,Reason} | {fail,Reason}.
-%% @doc Initialize `{@module}'.
+%% Initialize ct_release_test.
%%
%% This function can be called from any of the
%% `init_per_*' functions in the test suite. It updates
@@ -161,16 +152,15 @@
%% returned configuration must therefore also be returned from
%% the calling `init_per_*'.
%%
-%% If the initialization fails, e.g. if a required release can
-%% not be found, the function returns `{skip,Reason}'. In
+%% If the initialization fails, e.g. if a required release
+%% cannot be found, the function returns `{skip,Reason}'. In
%% this case the other test support functions in this mudule
-%% can not be used.
+%% cannot be used.
%%
%% Example:
%%
-%% ```
%% init_per_suite(Config) ->
-%% ct_release_test:init(Config).'''
+%% ct_release_test:init(Config).
%%
init(Config) ->
try init_upgrade_test() of
@@ -194,47 +184,42 @@ init(Config) ->
Callback :: {module(),InitState},
InitState :: cb_state(),
Config :: config().
-%% @doc Test upgrade of the given application(s).
+%% Test upgrade of the given application(s).
%%
%% This function can be called from a test case. It requires that
-%% `Config' has been initialized by calling {@link
-%% init/1} prior to this, for example from `init_per_suite/1'.
+%% `Config' has been initialized by calling
+%% init/1 prior to this, for example from `init_per_suite/1'.
%%
%% Upgrade tests are performed as follows:
%%
-%% <ol>
-%% <li>Figure out which OTP release to test upgrade
+%% Figure out which OTP release to test upgrade
%% from. Start a node running that release and find the
%% application versions on that node. Terminate the
-%% node.</li>
-%% <li>Figure out all dependencies for the applications under
-%% test.</li>
-%% <li>Create a release containing the core
+%% node.
+%% Figure out all dependencies for the applications under
+%% test.
+%% Create a release containing the core
%% applications `kernel', `stdlib' and `sasl'
%% in addition to the application(s) under test and all
%% dependencies of these. The versions of the applications
%% under test will be the ones found on the OTP release to
%% upgrade from. The versions of all other applications will
%% be those found on the current node, i.e. the common_test
-%% node. This is the "From"-release.</li>
-%% <li>Create another release containing the same
+%% node. This is the "From"-release.
+%% Create another release containing the same
%% applications as in the previous step, but with all
%% application versions taken from the current node. This is
-%% the "To"-release.</li>
-%% <li>Install the "From"-release and start a new node
-%% running this release.</li>
-%% <li>Perform the upgrade test and allow customized
+%% the "To"-release.
+%% Install the "From"-release and start a new node
+%% running this release.
+%% Perform the upgrade test and allow customized
%% control by using callbacks:
-%% <ol>
-%% <li>Callback: `upgrade_init/2'</li>
-%% <li>Unpack the new release</li>
-%% <li>Install the new release</li>
-%% <li>Callback: `upgrade_upgraded/2'</li>
-%% <li>Install the original release</li>
-%% <li>Callback: `upgrade_downgraded/2'</li>
-%% </ol>
-%% </li>
-%% </ol>
+%% Callback: `upgrade_init/2'
+%% Unpack the new release
+%% Install the new release
+%% Callback: `upgrade_upgraded/2'
+%% Install the original release
+%% Callback: `upgrade_downgraded/2'
%%
%% `App' or `Apps'
%% specifies the applications under test, i.e. the applications
@@ -244,27 +229,25 @@ init(Config) ->
%%
%% `Level' specifies which OTP release to
%% pick the "From" versions from.
-%% <dl>
-%% <dt>major</dt>
-%% <dd>From verions are picked from the previous major
+%% major
+%% From verions are picked from the previous major
%% release. For example, if the test is run on an OTP-17
-%% node, `{@module}' will pick the application
+%% node, ct_release_test will pick the application
%% "From" versions from an OTP installation running OTP
-%% R16B.</dd>
+%% R16B.
%%
-%% <dt>minor</dt>
-%% <dd>From verions are picked from the current major
+%% minor
+%% From verions are picked from the current major
%% release. For example, if the test is run on an OTP-17
-%% node, `{@module}' will pick the application
+%% node, ct_release_test will pick the application
%% "From" versions from an OTP installation running an
-%% earlier patch level of OTP-17.</dd>
-%% </dl>
+%% earlier patch level of OTP-17.
%%
%% The application "To" versions are allways picked from the
%% current node, i.e. the common_test node.
%%
%% `Callback' specifies the module (normally the
-%% test suite) which implements the {@section Callback functions}, and
+%% test suite) which implements the Callback functions, and
%% the initial value of the `State' variable used in these
%% functions.
%%
@@ -273,10 +256,8 @@ init(Config) ->
%%
%% Example:
%%
-%% ```
%% minor_upgrade(Config) ->
%% ct_release_test:upgrade(ssl,minor,{?MODULE,[]},Config).
-%% '''
%%
upgrade(App,Level,Callback,Config) when is_atom(App) ->
upgrade([App],Level,Callback,Config);
@@ -318,10 +299,10 @@ upgrade(Apps,Level,Callback,Config) ->
-spec cleanup(Config) -> Result when
Config :: config(),
Result :: config().
-%% @doc Clean up after tests.
+%% Clean up after tests.
%%
%% This function shall be called from the `end_per_*' function
-%% complementing the `init_per_*' function where {@link init/1}
+%% complementing the `init_per_*' function where init/1
%% is called.
%%
%% It cleans up after the test, for example kills hanging
@@ -329,9 +310,8 @@ upgrade(Apps,Level,Callback,Config) ->
%%
%% Example:
%%
-%% ```
%% end_per_suite(Config) ->
-%% ct_release_test:cleanup(Config).'''
+%% ct_release_test:cleanup(Config).
%%
cleanup(Config) ->
AllNodes = [node_name(?testnode)|nodes()],
@@ -352,15 +332,15 @@ cleanup(Config) ->
From :: string(),
To :: string(),
Reason :: {app_not_found,App}.
-%% @doc Get versions involved in this upgrade for the given application.
+%% Get versions involved in this upgrade for the given application.
%%
%% This function can be called from inside any of the callback
%% functions. It returns the old (From) and new (To) versions involved
%% in the upgrade/downgrade test for the given application.
%%
-%% <code>CtData</code> must be the first argument received in the
+%% CtData must be the first argument received in the
%% calling callback function - an opaque data structure set by
-%% <code>ct_release_tests</code>.
+%% ct_release_tests.
get_app_vsns(#ct_data{from=FromApps,to=ToApps},App) ->
case {lists:keyfind(App,1,FromApps),lists:keyfind(App,1,ToApps)} of
{{App,FromVsn,_},{App,ToVsn,_}} ->
@@ -380,16 +360,16 @@ get_app_vsns(#ct_data{from=FromApps,to=ToApps},App) ->
Down :: [Instr],
Instr :: term(),
Reason :: {app_not_found,App} | {vsn_not_found,{App,From}}.
-%% @doc Get appup instructions for the given application.
+%% Get appup instructions for the given application.
%%
%% This function can be called from inside any of the callback
%% functions. It reads the appup file for the given application and
%% returns the instructions for upgrade and downgrade for the versions
%% in the test.
%%
-%% <code>CtData</code> must be the first argument received in the
+%% CtData must be the first argument received in the
%% calling callback function - an opaque data structure set by
-%% <code>ct_release_tests</code>.
+%% ct_release_tests.
%%
%% See reference manual for appup files for types definitions for the
%% instructions.
@@ -446,7 +426,7 @@ init_upgrade_test(Level) ->
case OldRel of
false ->
ct:log("Release ~tp is not available."
- " Upgrade on '~p' level can not be tested.",
+ " Upgrade on '~p' level cannot be tested.",
[FromVsn,Level]),
undefined;
_ ->
@@ -548,7 +528,7 @@ target_system(Apps,CreateDir,InstallDir,{FromVsn,_,AllAppsVsns,Path}) ->
{path,Path}]]),
%% Unpack the tar to complete the installation
- erl_tar:extract(RelName ++ ".tar.gz", [{cwd, InstallDir}, compressed]),
+ ok = erl_tar:extract(RelName ++ ".tar.gz", [{cwd, InstallDir}, compressed]),
%% Add bin and log dirs
BinDir = filename:join([InstallDir, "bin"]),
@@ -574,11 +554,11 @@ target_system(Apps,CreateDir,InstallDir,{FromVsn,_,AllAppsVsns,Path}) ->
%% create start_erl.data, sys.config and start.src
StartErlData = filename:join([InstallDir, "releases", "start_erl.data"]),
- write_file(StartErlData, io_lib:fwrite("~s ~s~n", [ErtsVsn, FromVsn])),
+ ok = write_file(StartErlData, io_lib:fwrite("~s ~s~n", [ErtsVsn, FromVsn])),
SysConfig = filename:join([InstallDir, "releases", FromVsn, "sys.config"]),
- write_file(SysConfig, "[]."),
+ ok = write_file(SysConfig, "[]."),
StartSrc = filename:join(ErtsBinDir,"start.src"),
- write_file(StartSrc,start_script()),
+ ok = write_file(StartSrc,start_script()),
ok = file:change_mode(StartSrc,8#0755),
%% Make start_erl executable
@@ -640,7 +620,7 @@ upgrade_system(Apps, FromRel, CreateDir, InstallDir, {_,ToVsn,_,_}) ->
[{path,[FromPath]},
{outdir,CreateDir}]]),
SysConfig = filename:join([CreateDir, "sys.config"]),
- write_file(SysConfig, "[]."),
+ ok = write_file(SysConfig, "[]."),
ok = systools(make_tar,[RelName,[{erts,code:root_dir()}]]),
@@ -817,7 +797,7 @@ get_runtime_deps([App|Apps],StartApps,Acc,Visited) ->
RuntimeDeps =
lists:flatmap(
fun(Str) ->
- [RuntimeAppStr,_] = string:tokens(Str,"-"),
+ [RuntimeAppStr,_] = string:lexemes(Str,"-"),
RuntimeApp = list_to_atom(RuntimeAppStr),
case {lists:keymember(RuntimeApp,1,Acc),
lists:member(RuntimeApp,StartApps)} of
@@ -878,7 +858,7 @@ subst_file(Src, Dest, Vars, Opts) ->
{ok, Bin} = file:read_file(Src),
Conts = unicode:characters_to_list(Bin),
NConts = subst(Conts, Vars),
- write_file(Dest, NConts),
+ ok = write_file(Dest, NConts),
case lists:member(preserve, Opts) of
true ->
{ok, FileInfo} = file:read_file_info(Src),
diff --git a/lib/common_test/src/ct_repeat.erl b/lib/common_test/src/ct_repeat.erl
index 177ef37d1f..b97c6e59e7 100644
--- a/lib/common_test/src/ct_repeat.erl
+++ b/lib/common_test/src/ct_repeat.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,14 +18,14 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Framework module that handles repeated test runs
+%%% doc Common Test Framework module that handles repeated test runs
%%%
-%%% <p>This module exports functions for repeating tests. The following
+%%% This module exports functions for repeating tests. The following
%%% start flags (or equivalent ct:run_test/1 options) are supported:
%%% -until <StopTime>, StopTime = YYMoMoDDHHMMSS | HHMMSS
%%% -duration <DurTime>, DurTime = HHMMSS
%%% -force_stop [skip_rest]
-%%% -repeat <N>, N = integer()</p>
+%%% -repeat <N>, N = integer()
-module(ct_repeat).
@@ -278,7 +278,7 @@ log_loop_info(Args) ->
ForceStop ->
io_lib:format("force_stop is set to: ~w",[ForceStop])
end,
- ct_logs:log("Test loop info",LogStr1++LogStr2++LogStr3++LogStr4,[])
+ ct_logs:log("Test loop info","~ts", [LogStr1++LogStr2++LogStr3++LogStr4])
end.
ts(Secs) ->
diff --git a/lib/common_test/src/ct_rpc.erl b/lib/common_test/src/ct_rpc.erl
index b4a0bc9d74..cef5ad14e5 100644
--- a/lib/common_test/src/ct_rpc.erl
+++ b/lib/common_test/src/ct_rpc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,8 +18,6 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test specific layer on Erlang/OTP rpc.
-
-module(ct_rpc).
%%% API
@@ -29,49 +27,12 @@
%%%=========================================================================
%%% API
%%%=========================================================================
-%%% @spec app_node(App, Candidates) -> NodeName
-%%%
-%%% App = atom()
-%%% Candidates = [NodeName]
-%%% NodeName = atom()
-%%%
-%%% @doc From a set of candidate nodes determines which of them is
-%%% running the application App. If none of the candidate nodes
-%%% is running the application the function will make the test case
-%%% calling this function fail. This function is the same as calling
-%%% <code>app_node(App, Candidates, true)</code>.
-%%%
app_node(App, Candidates) ->
app_node(App, Candidates, true, []).
-%%% @spec app_node(App, Candidates, FailOnBadRPC) -> NodeName
-%%%
-%%% App = atom()
-%%% Candidates = [NodeName]
-%%% NodeName = atom()
-%%% FailOnBadRPC = true | false
-%%%
-%%% @doc Same as <code>app_node/2</code> only the <code>FailOnBadRPC</code>
-%%% argument will determine if the search for a candidate node should
-%%% stop or not if <code>badrpc</code> is received at some point.
-%%%
app_node(App, Candidates, FailOnBadRPC) ->
app_node(App, Candidates, FailOnBadRPC, []).
-%%% @spec app_node(App, Candidates, FailOnBadRPC, Cookie) -> NodeName
-%%%
-%%% App = atom()
-%%% Candidates = [NodeName]
-%%% NodeName = atom()
-%%% FailOnBadRPC = true | false
-%%% Cookie = atom()
-%%%
-%%% @doc Same as <code>app_node/2</code> only the <code>FailOnBadRPC</code>
-%%% argument will determine if the search for a candidate node should
-%%% stop or not if <code>badrpc</code> is received at some point.
-%%% The cookie on the client node will be set to <code>Cookie</code>
-%%% for this rpc operation (use to match the server node cookie).
-%%%
app_node(App, [], _, _) ->
ct:fail({application_not_running, App});
@@ -96,49 +57,12 @@ app_node(App, _Candidates = [CandidateNode | Nodes], FailOnBadRPC, Cookie) ->
end
end.
-%%% @spec call(Node, Module, Function, Args) -> term() | {badrpc, Reason}
-%%%
-%%% @doc Same as call(Node, Module, Function, Args, infinity)
-%%%
call(Node, Module, Function, Args) ->
call(Node, Module, Function, Args, infinity, []).
-%%% @spec call(Node, Module, Function, Args, TimeOut) ->
-%%% term() | {badrpc, Reason}
-%%% Node = NodeName | {Fun, FunArgs}
-%%% Fun = fun()
-%%% FunArgs = term()
-%%% NodeName = atom()
-%%% Module = atom()
-%%% Function = atom()
-%%% Args = [term()]
-%%% Reason = timeout | term()
-%%%
-%%% @doc Evaluates apply(Module, Function, Args) on the node Node.
-%%% Returns whatever Function returns or {badrpc, Reason} if the
-%%% remote procedure call fails. If Node is {Fun, FunArgs} applying
-%%% Fun to FunArgs should return a node name.
call(Node, Module, Function, Args, TimeOut) ->
call(Node, Module, Function, Args, TimeOut, []).
-%%% @spec call(Node, Module, Function, Args, TimeOut, Cookie) ->
-%%% term() | {badrpc, Reason}
-%%% Node = NodeName | {Fun, FunArgs}
-%%% Fun = fun()
-%%% FunArgs = term()
-%%% NodeName = atom()
-%%% Module = atom()
-%%% Function = atom()
-%%% Args = [term()]
-%%% Reason = timeout | term()
-%%% Cookie = atom()
-%%%
-%%% @doc Evaluates apply(Module, Function, Args) on the node Node.
-%%% Returns whatever Function returns or {badrpc, Reason} if the
-%%% remote procedure call fails. If Node is {Fun, FunArgs} applying
-%%% Fun to FunArgs should return a node name.
-%%% The cookie on the client node will be set to <code>Cookie</code>
-%%% for this rpc operation (use to match the server node cookie).
call({Fun, FunArgs}, Module, Function, Args, TimeOut, Cookie) ->
Node = Fun(FunArgs),
call(Node, Module, Function, Args, TimeOut, Cookie);
@@ -148,42 +72,9 @@ call(Node, Module, Function, Args, TimeOut, Cookie) when is_atom(Node) ->
_ = set_the_cookie(Cookie0),
Result.
-%%% @spec cast(Node, Module, Function, Args) -> ok
-%%% Node = NodeName | {Fun, FunArgs}
-%%% Fun = fun()
-%%% FunArgs = term()
-%%% NodeName = atom()
-%%% Module = atom()
-%%% Function = atom()
-%%% Args = [term()]
-%%% Reason = timeout | term()
-%%%
-%%% @doc Evaluates apply(Module, Function, Args) on the node Node.
-%%% No response is delivered and the process which makes the call is
-%%% not suspended until the evaluation is compleated as in the case of
-%%% call/[3,4]. If Node is {Fun, FunArgs} applying
-%%% Fun to FunArgs should return a node name.
cast(Node, Module, Function, Args) ->
cast(Node, Module, Function, Args, []).
-%%% @spec cast(Node, Module, Function, Args, Cookie) -> ok
-%%% Node = NodeName | {Fun, FunArgs}
-%%% Fun = fun()
-%%% FunArgs = term()
-%%% NodeName = atom()
-%%% Module = atom()
-%%% Function = atom()
-%%% Args = [term()]
-%%% Reason = timeout | term()
-%%% Cookie = atom()
-%%%
-%%% @doc Evaluates apply(Module, Function, Args) on the node Node.
-%%% No response is delivered and the process which makes the call is
-%%% not suspended until the evaluation is compleated as in the case of
-%%% call/[3,4]. If Node is {Fun, FunArgs} applying
-%%% Fun to FunArgs should return a node name.
-%%% The cookie on the client node will be set to <code>Cookie</code>
-%%% for this rpc operation (use to match the server node cookie).
cast({Fun, FunArgs}, Module, Function, Args, Cookie) ->
Node = Fun(FunArgs),
cast(Node, Module, Function, Args, Cookie);
@@ -196,7 +87,6 @@ cast(Node, Module, Function, Args, Cookie) when is_atom(Node) ->
%%%---------- Internal -----------
-%%% @hidden
set_the_cookie([]) ->
[];
set_the_cookie(Cookie) ->
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index 05b1e70098..960252a6fe 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,11 +18,6 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Framework test execution control module.
-%%%
-%%% <p>This module exports functions for installing and running tests
-%%% withing the Common Test Framework.</p>
-
-module(ct_run).
%% Script interface
@@ -84,17 +79,6 @@
tests,
starter}).
-%%%-----------------------------------------------------------------
-%%% @spec script_start() -> term()
-%%%
-%%% @doc Start tests via the ct_run program or script.
-%%%
-%%% <p>Example:<br/><code>./ct_run -config config.ctc -dir
-%%% $TEST_DIR</code></p>
-%%%
-%%% <p>Example:<br/><code>./ct_run -config config.ctc -suite
-%%% $SUITE_PATH/$SUITE_NAME [-case $CASE_NAME]</code></p>
-%%%
script_start() ->
process_flag(trap_exit, true),
Init = init:get_arguments(),
@@ -147,7 +131,7 @@ script_start(Args) ->
CTVsn =
case filename:basename(code:lib_dir(common_test)) of
CTBase when is_list(CTBase) ->
- case string:tokens(CTBase, "-") of
+ case string:lexemes(CTBase, "-") of
["common_test",Vsn] -> " v"++Vsn;
_ -> ""
end
@@ -317,7 +301,7 @@ script_start1(Parent, Args) ->
{undefined,InclDirs};
CtInclPath ->
AllInclDirs =
- string:tokens(CtInclPath,[$:,$ ,$,]) ++ InclDirs,
+ string:lexemes(CtInclPath,[$:,$ ,$,]) ++ InclDirs,
application:set_env(common_test, include, AllInclDirs),
{undefined,AllInclDirs}
end;
@@ -442,11 +426,9 @@ script_start2(Opts = #opts{vts = undefined,
TestSpecData ->
execute_all_specs(TestSpecData, Opts, Args, [])
catch
- throw:{error,Reason} ->
- StackTrace = erlang:get_stacktrace(),
+ throw:{error,Reason}:StackTrace ->
{error,{invalid_testspec,{Reason,StackTrace}}};
- _:Reason ->
- StackTrace = erlang:get_stacktrace(),
+ _:Reason:StackTrace ->
{error,{invalid_testspec,{Reason,StackTrace}}}
end;
[] ->
@@ -801,9 +783,6 @@ script_start4(#opts{shell = true, cover = Cover}, _) ->
script_start4(Opts = #opts{tests = Tests}, Args) ->
do_run(Tests, [], Opts, Args).
-%%%-----------------------------------------------------------------
-%%% @spec script_usage() -> ok
-%%% @doc Print usage information for <code>ct_run</code>.
script_usage() ->
io:format("\nUsage:\n\n"),
io:format("Run tests from command line:\n\n"
@@ -887,9 +866,6 @@ script_usage() ->
"\n\t [-basic_html]"
"\n\t [-no_esc_chars]\n\n").
-%%%-----------------------------------------------------------------
-%%% @hidden
-%%% @equiv ct:install/1
install(Opts) ->
install(Opts, ".").
@@ -933,15 +909,6 @@ install(Opts, LogDir) ->
variables_file_name(Dir) ->
filename:join(Dir, "variables-"++atom_to_list(node())).
-%%%-----------------------------------------------------------------
-%%% @spec run_test(Opts) -> Result
-%%% Opts = [tuple()]
-%%% Result = [TestResult] | {error,Reason}
-%%%
-%%% @doc Start tests from the erlang shell or from an erlang program.
-%%% @equiv ct:run_test/1
-%%%-----------------------------------------------------------------
-
run_test(StartOpt) when is_tuple(StartOpt) ->
run_test([StartOpt]);
@@ -1101,7 +1068,7 @@ run_test2(StartOpts) ->
application:set_env(common_test, include, InclDirs),
{undefined,InclDirs};
CtInclPath ->
- InclDirs1 = string:tokens(CtInclPath, [$:,$ ,$,]),
+ InclDirs1 = string:lexemes(CtInclPath, [$:,$ ,$,]),
AllInclDirs = InclDirs1++InclDirs,
application:set_env(common_test, include, AllInclDirs),
{undefined,AllInclDirs}
@@ -1211,11 +1178,9 @@ run_spec_file(Relaxed,
TestSpecData ->
run_all_specs(TestSpecData, Opts, StartOpts, [])
catch
- throw:{error,CTReason} ->
- StackTrace = erlang:get_stacktrace(),
+ throw:{error,CTReason}:StackTrace ->
exit({error,{invalid_testspec,{CTReason,StackTrace}}});
- _:CTReason ->
- StackTrace = erlang:get_stacktrace(),
+ _:CTReason:StackTrace ->
exit({error,{invalid_testspec,{CTReason,StackTrace}}})
end.
@@ -1431,14 +1396,6 @@ run_dir(Opts = #opts{logdir = LogDir,
exit({error,{incorrect_start_options,{Dir,Suite,GsAndCs}}})
end.
-%%%-----------------------------------------------------------------
-%%% @spec run_testspec(TestSpec) -> Result
-%%% TestSpec = [term()]
-%%%
-%%% @doc Run test specified by <code>TestSpec</code>. The terms are
-%%% the same as those used in test specification files.
-%%% @equiv ct:run_testspec/1
-%%%-----------------------------------------------------------------
run_testspec(TestSpec) ->
CTPid = spawn(run_testspec1_fun(TestSpec)),
Ref = monitor(process, CTPid),
@@ -1490,7 +1447,7 @@ run_testspec2(TestSpec) ->
false ->
Opts#opts.include;
CtInclPath ->
- EnvInclude = string:tokens(CtInclPath, [$:,$ ,$,]),
+ EnvInclude = string:lexemes(CtInclPath, [$:,$ ,$,]),
EnvInclude++Opts#opts.include
end,
application:set_env(common_test, include, AllInclude),
@@ -1638,9 +1595,6 @@ delistify([E]) -> E;
delistify(E) -> E.
-%%%-----------------------------------------------------------------
-%%% @hidden
-%%% @equiv ct:run/3
run(TestDir, Suite, Cases) ->
case install([]) of
ok ->
@@ -1649,9 +1603,6 @@ run(TestDir, Suite, Cases) ->
Error
end.
-%%%-----------------------------------------------------------------
-%%% @hidden
-%%% @equiv ct:run/2
run(TestDir, Suite) when is_list(TestDir), is_integer(hd(TestDir)) ->
case install([]) of
ok ->
@@ -1660,9 +1611,6 @@ run(TestDir, Suite) when is_list(TestDir), is_integer(hd(TestDir)) ->
Error
end.
-%%%-----------------------------------------------------------------
-%%% @hidden
-%%% @equiv ct:run/1
run(TestDirs) ->
case install([]) of
ok ->
@@ -1961,7 +1909,8 @@ auto_compile(TestSuites) ->
SuiteMakeErrors =
lists:flatmap(fun({TestDir,Suite} = TS) ->
case run_make(suites, TestDir,
- Suite, UserInclude) of
+ Suite, UserInclude,
+ [nowarn_export_all]) of
{error,{make_failed,Bad}} ->
[{TS,Bad}];
{error,_} ->
@@ -1979,7 +1928,7 @@ auto_compile(TestSuites) ->
case lists:member(Dir, Done) of
false ->
Failed1 =
- case run_make(helpmods, Dir, Suite, UserInclude) of
+ case run_make(helpmods, Dir, Suite, UserInclude, []) of
{error,{make_failed,BadMods}} ->
[{{Dir,all},BadMods}|Failed];
{error,_} ->
@@ -2072,16 +2021,9 @@ get_bad_suites([], BadSuites) ->
BadSuites.
-
-%%%-----------------------------------------------------------------
-%%% @hidden
-%%% @equiv ct:step/3
step(TestDir, Suite, Case) ->
step(TestDir, Suite, Case, []).
-%%%-----------------------------------------------------------------
-%%% @hidden
-%%% @equiv ct:step/4
step(TestDir, Suite, Case, Opts) when is_list(TestDir),
is_atom(Suite), is_atom(Case),
Suite =/= all, Case =/= all ->
@@ -2403,18 +2345,24 @@ start_cover(Opts=#opts{coverspec=CovData,cover_stop=CovStop},LogDir) ->
CovImport,
_CovExport,
#cover{app = CovApp,
+ local_only = LocalOnly,
level = CovLevel,
excl_mods = CovExcl,
incl_mods = CovIncl,
cross = CovCross,
src = _CovSrc}} = CovData,
+ case LocalOnly of
+ true -> cover:local_only();
+ false -> ok
+ end,
ct_logs:log("COVER INFO",
"Using cover specification file: ~ts~n"
"App: ~w~n"
+ "Local only: ~w~n"
"Cross cover: ~w~n"
"Including ~w modules~n"
"Excluding ~w modules",
- [CovFile,CovApp,CovCross,
+ [CovFile,CovApp,LocalOnly,CovCross,
length(CovIncl),length(CovExcl)]),
%% Tell test_server to print a link in its coverlog
@@ -2728,12 +2676,12 @@ get_name(Dir) ->
run_make(TestDir, Mod, UserInclude) ->
- run_make(suites, TestDir, Mod, UserInclude).
+ run_make(suites, TestDir, Mod, UserInclude, [nowarn_export_all]).
-run_make(Targets, TestDir0, Mod, UserInclude) when is_list(Mod) ->
- run_make(Targets, TestDir0, list_to_atom(Mod), UserInclude);
+run_make(Targets, TestDir0, Mod, UserInclude, COpts) when is_list(Mod) ->
+ run_make(Targets, TestDir0, list_to_atom(Mod), UserInclude, COpts);
-run_make(Targets, TestDir0, Mod, UserInclude) ->
+run_make(Targets, TestDir0, Mod, UserInclude, COpts) ->
case locate_test_dir(TestDir0, Mod) of
{ok,TestDir} ->
%% send a start_make notification which may suspend
@@ -2748,7 +2696,7 @@ run_make(Targets, TestDir0, Mod, UserInclude) ->
XmerlInclude = get_dir(xmerl, "include"),
ErlFlags = UserInclude ++ [{i,CtInclude},
{i,XmerlInclude},
- debug_info],
+ debug_info] ++ COpts,
Result =
if Mod == all ; Targets == helpmods ->
case (catch ct_make:all([noexec|ErlFlags])) of
diff --git a/lib/common_test/src/ct_slave.erl b/lib/common_test/src/ct_slave.erl
index b39195483b..dde33440be 100644
--- a/lib/common_test/src/ct_slave.erl
+++ b/lib/common_test/src/ct_slave.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -17,13 +17,6 @@
%%
%% %CopyrightEnd%
-%%% @doc Common Test Framework functions for starting and stopping nodes for
-%%% Large Scale Testing.
-%%%
-%%% <p>This module exports functions which are used by the Common Test Master
-%%% to start and stop "slave" nodes. It is the default callback module for the
-%%% <code>{init, node_start}</code> term of the Test Specification.</p>
-
%%----------------------------------------------------------------------
%% File : ct_slave.erl
%% Description : CT module for starting nodes for large-scale testing.
@@ -38,44 +31,12 @@
-record(options, {username, password, boot_timeout, init_timeout,
startup_timeout, startup_functions, monitor_master,
- kill_if_fail, erl_flags, env, ssh_port, ssh_opts}).
-
-%%%-----------------------------------------------------------------
-%%% @spec start(Node) -> Result
-%%% Node = atom()
-%%% Result = {ok, NodeName} |
-%%% {error, Reason, NodeName}
-%%% Reason = already_started |
-%%% started_not_connected |
-%%% boot_timeout |
-%%% init_timeout |
-%%% startup_timeout |
-%%% not_alive
-%%% NodeName = atom()
-%%% @doc Starts an Erlang node with name <code>Node</code> on the local host.
-%%% @see start/3
+ kill_if_fail, erl_flags, env, ssh_port, ssh_opts,
+ stop_timeout}).
+
start(Node) ->
start(gethostname(), Node).
-%%%-----------------------------------------------------------------
-%%% @spec start(HostOrNode, NodeOrOpts) -> Result
-%%% HostOrNode = atom()
-%%% NodeOrOpts = atom() | list()
-%%% Result = {ok, NodeName} |
-%%% {error, Reason, NodeName}
-%%% Reason = already_started |
-%%% started_not_connected |
-%%% boot_timeout |
-%%% init_timeout |
-%%% startup_timeout |
-%%% not_alive
-%%% NodeName = atom()
-%%% @doc Starts an Erlang node with default options on a specified
-%%% host, or on the local host with specified options. That is,
-%%% the call is interpreted as <code>start(Host, Node)</code> when the
-%%% second argument is atom-valued and <code>start(Node, Opts)</code>
-%%% when it's list-valued.
-%%% @see start/3
start(_HostOrNode = Node, _NodeOrOpts = Opts) %% match to satiate edoc
when is_list(Opts) ->
start(gethostname(), Node, Opts);
@@ -83,104 +44,6 @@ start(_HostOrNode = Node, _NodeOrOpts = Opts) %% match to satiate edoc
start(Host, Node) ->
start(Host, Node, []).
-%%%-----------------------------------------------------------------
-%%% @spec start(Host, Node, Opts) -> Result
-%%% Node = atom()
-%%% Host = atom()
-%%% Opts = [OptTuples]
-%%% OptTuples = {username, Username} |
-%%% {password, Password} |
-%%% {boot_timeout, BootTimeout} | {init_timeout, InitTimeout} |
-%%% {startup_timeout, StartupTimeout} |
-%%% {startup_functions, StartupFunctions} |
-%%% {monitor_master, Monitor} |
-%%% {kill_if_fail, KillIfFail} |
-%%% {erl_flags, ErlangFlags} |
-%%% {env, [{EnvVar,Value}]}
-%%% Username = string()
-%%% Password = string()
-%%% BootTimeout = integer()
-%%% InitTimeout = integer()
-%%% StartupTimeout = integer()
-%%% StartupFunctions = [StartupFunctionSpec]
-%%% StartupFunctionSpec = {Module, Function, Arguments}
-%%% Module = atom()
-%%% Function = atom()
-%%% Arguments = [term]
-%%% Monitor = bool()
-%%% KillIfFail = bool()
-%%% ErlangFlags = string()
-%%% EnvVar = string()
-%%% Value = string()
-%%% Result = {ok, NodeName} |
-%%% {error, Reason, NodeName}
-%%% Reason = already_started |
-%%% started_not_connected |
-%%% boot_timeout |
-%%% init_timeout |
-%%% startup_timeout |
-%%% not_alive
-%%% NodeName = atom()
-%%% @doc Starts an Erlang node with name <code>Node</code> on host
-%%% <code>Host</code> as specified by the combination of options in
-%%% <code>Opts</code>.
-%%%
-%%% <p>Options <code>Username</code> and <code>Password</code> will be used
-%%% to log in onto the remote host <code>Host</code>.
-%%% Username, if omitted, defaults to the current user name,
-%%% and password is empty by default.</p>
-%%%
-%%% <p>A list of functions specified in the <code>Startup</code> option will be
-%%% executed after startup of the node. Note that all used modules should be
-%%% present in the code path on the <code>Host</code>.</p>
-%%%
-%%% <p>The timeouts are applied as follows:</p>
-%%% <list>
-%%% <item>
-%%% <code>BootTimeout</code> - time to start the Erlang node, in seconds.
-%%% Defaults to 3 seconds. If node does not become pingable within this time,
-%%% the result <code>{error, boot_timeout, NodeName}</code> is returned;
-%%% </item>
-%%% <item>
-%%% <code>InitTimeout</code> - time to wait for the node until it calls the
-%%% internal callback function informing master about successfull startup.
-%%% Defaults to one second.
-%%% In case of timed out message the result
-%%% <code>{error, init_timeout, NodeName}</code> is returned;
-%%% </item>
-%%% <item>
-%%% <code>StartupTimeout</code> - time to wait intil the node finishes to run
-%%% the <code>StartupFunctions</code>. Defaults to one second.
-%%% If this timeout occurs, the result
-%%% <code>{error, startup_timeout, NodeName}</code> is returned.
-%%% </item>
-%%% </list>
-%%%
-%%% <p>Option <code>monitor_master</code> specifies, if the slave node should be
-%%% stopped in case of master node stop. Defaults to false.</p>
-%%%
-%%% <p>Option <code>kill_if_fail</code> specifies, if the slave node should be
-%%% killed in case of a timeout during initialization or startup.
-%%% Defaults to true. Note that node also may be still alive it the boot
-%%% timeout occurred, but it will not be killed in this case.</p>
-%%%
-%%% <p>Option <code>erlang_flags</code> specifies, which flags will be added
-%%% to the parameters of the <code>erl</code> executable.</p>
-%%%
-%%% <p>Option <code>env</code> specifies a list of environment variables
-%%% that will extended the environment.</p>
-%%%
-%%% <p>Special return values are:</p>
-%%% <list>
-%%% <item><code>{error, already_started, NodeName}</code> - if the node with
-%%% the given name is already started on a given host;</item>
-%%% <item><code>{error, started_not_connected, NodeName}</code> - if node is
-%%% started, but not connected to the master node.</item>
-%%% <item><code>{error, not_alive, NodeName}</code> - if node on which the
-%%% <code>ct_slave:start/3</code> is called, is not alive. Note that
-%%% <code>NodeName</code> is the name of current node in this case.</item>
-%%% </list>
-%%%
start(Host, Node, Opts) ->
ENode = enodename(Host, Node),
case erlang:is_alive() of
@@ -198,36 +61,22 @@ start(Host, Node, Opts) ->
end
end.
-%%% @spec stop(Node) -> Result
-%%% Node = atom()
-%%% Result = {ok, NodeName} |
-%%% {error, Reason, NodeName}
-%%% Reason = not_started |
-%%% not_connected |
-%%% stop_timeout
-
-%%% NodeName = atom()
-%%% @doc Stops the running Erlang node with name <code>Node</code> on
-%%% the localhost.
stop(Node) ->
stop(gethostname(), Node).
-%%% @spec stop(Host, Node) -> Result
-%%% Host = atom()
-%%% Node = atom()
-%%% Result = {ok, NodeName} |
-%%% {error, Reason, NodeName}
-%%% Reason = not_started |
-%%% not_connected |
-%%% stop_timeout
-%%% NodeName = atom()
-%%% @doc Stops the running Erlang node with name <code>Node</code> on
-%%% host <code>Host</code>.
+stop(_HostOrNode = Node, _NodeOrOpts = Opts) %% match to satiate edoc
+ when is_list(Opts) ->
+ stop(gethostname(), Node, Opts);
+
stop(Host, Node) ->
+ stop(Host, Node, []).
+
+stop(Host, Node, Opts) ->
ENode = enodename(Host, Node),
case is_started(ENode) of
{true, connected}->
- do_stop(ENode);
+ OptionsRec = fetch_options(Opts),
+ do_stop(ENode, OptionsRec);
{true, not_connected}->
{error, not_connected, ENode};
false->
@@ -257,26 +106,25 @@ fetch_options(Options) ->
EnvVars = get_option_value(env, Options, []),
SSHPort = get_option_value(ssh_port, Options, []),
SSHOpts = get_option_value(ssh_opts, Options, []),
+ StopTimeout = get_option_value(stop_timeout, Options, 5),
#options{username=UserName, password=Password,
boot_timeout=BootTimeout, init_timeout=InitTimeout,
startup_timeout=StartupTimeout, startup_functions=StartupFunctions,
monitor_master=Monitor, kill_if_fail=KillIfFail,
- erl_flags=ErlFlags, env=EnvVars, ssh_port=SSHPort, ssh_opts=SSHOpts}.
+ erl_flags=ErlFlags, env=EnvVars, ssh_port=SSHPort, ssh_opts=SSHOpts,
+ stop_timeout=StopTimeout}.
% send a message when slave node is started
-% @hidden
slave_started(ENode, MasterPid) ->
MasterPid ! {node_started, ENode},
ok.
% send a message when slave node has finished startup
-% @hidden
slave_ready(ENode, MasterPid) ->
MasterPid ! {node_ready, ENode},
ok.
% start monitoring of the master node
-% @hidden
monitor_master(MasterNode) ->
spawn(fun() -> monitor_master_int(MasterNode) end).
@@ -462,6 +310,8 @@ wait_for_node_alive(Node, N) ->
% call init:stop on a remote node
do_stop(ENode) ->
+ do_stop(ENode, fetch_options([])).
+do_stop(ENode, Options) ->
{Cover,MainCoverNode} =
case test_server:is_cover() of
true ->
@@ -472,7 +322,8 @@ do_stop(ENode) ->
{false,undefined}
end,
spawn(ENode, init, stop, []),
- case wait_for_node_dead(ENode, 5) of
+ StopTimeout = Options#options.stop_timeout,
+ case wait_for_node_dead(ENode, StopTimeout) of
{ok,ENode} ->
if Cover ->
%% To avoid that cover is started again if a node
diff --git a/lib/common_test/src/ct_snmp.erl b/lib/common_test/src/ct_snmp.erl
index 5844909d17..27b74dd04e 100644
--- a/lib/common_test/src/ct_snmp.erl
+++ b/lib/common_test/src/ct_snmp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,139 +18,8 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test user interface module for the OTP snmp application
-%%%
-%%% <p>The purpose of this module is to make snmp configuration easier for
-%%% the test case writer. Many test cases can use default values for common
-%%% operations and then no snmp configuration files need to be supplied. When
-%%% it is necessary to change particular configuration parameters, a subset
-%%% of the relevant snmp configuration files may be passed to <code>ct_snmp</code>
-%%% by means of Common Test configuration files.
-%%% For more specialized configuration parameters, it is possible to place a
-%%% "simple snmp configuration file" in the test suite data directory.
-%%% To simplify the test suite, Common Test keeps track
-%%% of some of the snmp manager information. This way the test suite doesn't
-%%% have to handle as many input parameters as it would if it had to interface the
-%%% OTP snmp manager directly.</p>
-%%%
-%%% <p> The following snmp manager and agent parameters are configurable: </p>
-%%%
-%%% <pre>
-%%% {snmp,
-%%% %%% Manager config
-%%% [{start_manager, boolean()} % Optional - default is true
-%%% {users, [{user_name(), [call_back_module(), user_data()]}]}, %% Optional
-%%% {usm_users, [{usm_user_name(), [usm_config()]}]},%% Optional - snmp v3 only
-%%% % managed_agents is optional
-%%% {managed_agents,[{agent_name(), [user_name(), agent_ip(), agent_port(), [agent_config()]]}]},
-%%% {max_msg_size, integer()}, % Optional - default is 484
-%%% {mgr_port, integer()}, % Optional - default is 5000
-%%% {engine _id, string()}, % Optional - default is "mgrEngine"
-%%%
-%%% %%% Agent config
-%%% {start_agent, boolean()}, % Optional - default is false
-%%% {agent_sysname, string()}, % Optional - default is "ct_test"
-%%% {agent_manager_ip, manager_ip()}, % Optional - default is localhost
-%%% {agent_vsns, list()}, % Optional - default is [v2]
-%%% {agent_trap_udp, integer()}, % Optional - default is 5000
-%%% {agent_udp, integer()}, % Optional - default is 4000
-%%% {agent_notify_type, atom()}, % Optional - default is trap
-%%% {agent_sec_type, sec_type()}, % Optional - default is none
-%%% {agent_passwd, string()}, % Optional - default is ""
-%%% {agent_engine_id, string()}, % Optional - default is "agentEngine"
-%%% {agent_max_msg_size, string()},% Optional - default is 484
-%%%
-%%% %% The following parameters represents the snmp configuration files
-%%% %% context.conf, standard.conf, community.conf, vacm.conf,
-%%% %% usm.conf, notify.conf, target_addr.conf and target_params.conf.
-%%% %% Note all values in agent.conf can be altered by the parametes
-%%% %% above. All these configuration files have default values set
-%%% %% up by the snmp application. These values can be overridden by
-%%% %% suppling a list of valid configuration values or a file located
-%%% %% in the test suites data dir that can produce a list
-%%% %% of valid configuration values if you apply file:consult/1 to the
-%%% %% file.
-%%% {agent_contexts, [term()] | {data_dir_file, rel_path()}}, % Optional
-%%% {agent_community, [term()] | {data_dir_file, rel_path()}},% Optional
-%%% {agent_sysinfo, [term()] | {data_dir_file, rel_path()}}, % Optional
-%%% {agent_vacm, [term()] | {data_dir_file, rel_path()}}, % Optional
-%%% {agent_usm, [term()] | {data_dir_file, rel_path()}}, % Optional
-%%% {agent_notify_def, [term()] | {data_dir_file, rel_path()}},% Optional
-%%% {agent_target_address_def, [term()] | {data_dir_file, rel_path()}},% Optional
-%%% {agent_target_param_def, [term()] | {data_dir_file, rel_path()}},% Optional
-%%% ]}.
-%%% </pre>
-%%%
-%%% <p>The <code>MgrAgentConfName</code> parameter in the functions
-%%% should be a name you allocate in your test suite using a
-%%% <code>require</code> statement.
-%%% Example (where <code>MgrAgentConfName = snmp_mgr_agent</code>):</p>
-%%% <pre> suite() -> [{require, snmp_mgr_agent, snmp}].</pre>
-%%% <p>or</p>
-%%% <pre> ct:require(snmp_mgr_agent, snmp).</pre>
-%%%
-%%% <p> Note that Usm users are needed for snmp v3 configuration and are
-%%% not to be confused with users.</p>
-%%%
-%%% <p> Snmp traps, inform and report messages are handled by the
-%%% user callback module. For more information about this see
-%%% the snmp application. </p>
-%%% <p> Note: It is recommended to use the .hrl-files created by the
-%%% Erlang/OTP mib-compiler to define the oids.
-%%% Example for the getting the erlang node name from the erlNodeTable
-%%% in the OTP-MIB:</p>
-%%% <pre>Oid = ?erlNodeEntry ++ [?erlNodeName, 1] </pre>
-%%%
-%%% <p>It is also possible to set values for snmp application configuration
-%%% parameters, such as <code>config</code>, <code>server</code>,
-%%% <code>net_if</code>, etc (see the "Configuring the application" chapter in
-%%% the OTP snmp User's Guide for a list of valid parameters and types). This is
-%%% done by defining a configuration data variable on the following form:</p>
-%%% <pre>
-%%% {snmp_app, [{manager, [snmp_app_manager_params()]},
-%%% {agent, [snmp_app_agent_params()]}]}.</pre>
-%%%
-%%% <p>A name for the data needs to be allocated in the suite using
-%%% <code>require</code> (see example above), and this name passed as
-%%% the <code>SnmpAppConfName</code> argument to <code>start/3</code>.
-%%% <code>ct_snmp</code> specifies default values for some snmp application
-%%% configuration parameters (such as <code>{verbosity,trace}</code> for the
-%%% <code>config</code> parameter). This set of defaults will be
-%%% merged with the parameters specified by the user, and user values
-%%% override <code>ct_snmp</code> defaults.</p>
-
-module(ct_snmp).
-%%% Common Types
-%%% @type agent_ip() = ip()
-%%% @type manager_ip() = ip()
-%%% @type agent_name() = atom()
-%%% @type ip() = string() | {integer(), integer(),
-%%% integer(), integer()}
-%%% @type agent_port() = integer()
-%%% @type agent_config() = {Item, Value}
-%%% @type user_name() = atom()
-%%% @type usm_user_name() = string()
-%%% @type usm_config() = {Item, Value}
-%%% @type call_back_module() = atom()
-%%% @type user_data() = term()
-%%% @type oids() = [oid()]
-%%% @type oid() = [byte()]
-%%% @type snmpreply() = {error_status(), error_index(), varbinds()}
-%%% @type error_status() = noError | atom()
-%%% @type error_index() = integer()
-%%% @type varbinds() = [varbind()]
-%%% @type varbind() = term()
-%%% @type value_type() = o ('OBJECT IDENTIFIER') | i ('INTEGER') |
-%%% u ('Unsigned32') | g ('Unsigned32') | s ('OCTET STRING')
-%%% @type varsandvals() = [var_and_val()]
-%%% @type var_and_val() = {oid(), value_type(), value()}
-%%% @type sec_type() = none | minimum | semi
-%%% @type rel_path() = string()
-%%% @type snmp_app_manager_params() = term()
-%%% @type snmp_app_agent_params() = term()
-
-
-include("snmp_types.hrl").
-include("inet.hrl").
-include("ct.hrl").
@@ -181,31 +50,9 @@
%%% API
%%%=========================================================================
-%%%-----------------------------------------------------------------
-%%% @spec start(Config, MgrAgentConfName) -> ok
-%%% @equiv start(Config, MgrAgentConfName, undefined)
start(Config, MgrAgentConfName) ->
start(Config, MgrAgentConfName, undefined).
-%%% @spec start(Config, MgrAgentConfName, SnmpAppConfName) -> ok
-%%% Config = [{Key, Value}]
-%%% Key = atom()
-%%% Value = term()
-%%% MgrAgentConfName = atom()
-%%% SnmpConfName = atom()
-%%%
-%%% @doc Starts an snmp manager and/or agent. In the manager case,
-%%% registrations of users and agents as specified by the configuration
-%%% <code>MgrAgentConfName</code> will be performed. When using snmp
-%%% v3 also so called usm users will be registered. Note that users,
-%%% usm_users and managed agents may also be registered at a later time
-%%% using ct_snmp:register_users/2, ct_snmp:register_agents/2, and
-%%% ct_snmp:register_usm_users/2. The agent started will be
-%%% called <code>snmp_master_agent</code>. Use ct_snmp:load_mibs/1 to load
-%%% mibs into the agent. With <code>SnmpAppConfName</code> it's possible
-%%% to configure the snmp application with parameters such as <code>config</code>,
-%%% <code>mibs</code>, <code>net_if</code>, etc. The values will be merged
-%%% with (and possibly override) default values set by <code>ct_snmp</code>.
start(Config, MgrAgentConfName, SnmpAppConfName) ->
StartManager= ct:get_config({MgrAgentConfName, start_manager}, true),
StartAgent = ct:get_config({MgrAgentConfName, start_agent}, false),
@@ -233,12 +80,6 @@ start_application(App) ->
Else
end.
-%%% @spec stop(Config) -> ok
-%%% Config = [{Key, Value}]
-%%% Key = atom()
-%%% Value = term()
-%%%
-%%% @doc Stops the snmp manager and/or agent removes all files created.
stop(Config) ->
PrivDir = ?config(priv_dir, Config),
ok = application:stop(snmp),
@@ -251,41 +92,16 @@ stop(Config) ->
catch del_dir(DbDir).
-%%% @spec get_values(Agent, Oids, MgrAgentConfName) -> SnmpReply
-%%%
-%%% Agent = agent_name()
-%%% Oids = oids()
-%%% MgrAgentConfName = atom()
-%%% SnmpReply = snmpreply()
-%%%
-%%% @doc Issues a synchronous snmp get request.
get_values(Agent, Oids, MgrAgentConfName) ->
[Uid | _] = agent_conf(Agent, MgrAgentConfName),
{ok, SnmpReply, _} = snmpm:sync_get2(Uid, target_name(Agent), Oids),
SnmpReply.
-%%% @spec get_next_values(Agent, Oids, MgrAgentConfName) -> SnmpReply
-%%%
-%%% Agent = agent_name()
-%%% Oids = oids()
-%%% MgrAgentConfName = atom()
-%%% SnmpReply = snmpreply()
-%%%
-%%% @doc Issues a synchronous snmp get next request.
get_next_values(Agent, Oids, MgrAgentConfName) ->
[Uid | _] = agent_conf(Agent, MgrAgentConfName),
{ok, SnmpReply, _} = snmpm:sync_get_next2(Uid, target_name(Agent), Oids),
SnmpReply.
-%%% @spec set_values(Agent, VarsAndVals, MgrAgentConfName, Config) -> SnmpReply
-%%%
-%%% Agent = agent_name()
-%%% Oids = oids()
-%%% MgrAgentConfName = atom()
-%%% Config = [{Key, Value}]
-%%% SnmpReply = snmpreply()
-%%%
-%%% @doc Issues a synchronous snmp set request.
set_values(Agent, VarsAndVals, MgrAgentConfName, Config) ->
PrivDir = ?config(priv_dir, Config),
[Uid | _] = agent_conf(Agent, MgrAgentConfName),
@@ -301,19 +117,6 @@ set_values(Agent, VarsAndVals, MgrAgentConfName, Config) ->
end,
SnmpSetReply.
-%%% @spec set_info(Config) -> [{Agent, OldVarsAndVals, NewVarsAndVals}]
-%%%
-%%% Config = [{Key, Value}]
-%%% Agent = agent_name()
-%%% OldVarsAndVals = varsandvals()
-%%% NewVarsAndVals = varsandvals()
-%%%
-%%% @doc Returns a list of all successful set requests performed in
-%%% the test case in reverse order. The list contains the involved
-%%% user and agent, the value prior to the set and the new value. This
-%%% is intended to facilitate the clean up in the end_per_testcase
-%%% function i.e. the undoing of the set requests and its possible
-%%% side-effects.
set_info(Config) ->
PrivDir = ?config(priv_dir, Config),
SetLogFile = filename:join(PrivDir, ?CT_SNMP_LOG_FILE),
@@ -325,18 +128,6 @@ set_info(Config) ->
[]
end.
-%%% @spec register_users(MgrAgentConfName, Users) -> ok | {error, Reason}
-%%%
-%%% MgrAgentConfName = atom()
-%%% Users = [user()]
-%%% Reason = term()
-%%%
-%%% @doc Register the manager entity (=user) responsible for specific agent(s).
-%%% Corresponds to making an entry in users.conf.
-%%%
-%%% <p>This function will try to register the given users, without
-%%% checking if any of them already exist. In order to change an
-%%% already registered user, the user must first be unregistered.</p>
register_users(MgrAgentConfName, Users) ->
case setup_users(Users) of
ok ->
@@ -350,19 +141,6 @@ register_users(MgrAgentConfName, Users) ->
Error
end.
-%%% @spec register_agents(MgrAgentConfName, ManagedAgents) -> ok | {error, Reason}
-%%%
-%%% MgrAgentConfName = atom()
-%%% ManagedAgents = [agent()]
-%%% Reason = term()
-%%%
-%%% @doc Explicitly instruct the manager to handle this agent.
-%%% Corresponds to making an entry in agents.conf
-%%%
-%%% <p>This function will try to register the given managed agents,
-%%% without checking if any of them already exist. In order to change
-%%% an already registered managed agent, the agent must first be
-%%% unregistered.</p>
register_agents(MgrAgentConfName, ManagedAgents) ->
case setup_managed_agents(MgrAgentConfName,ManagedAgents) of
ok ->
@@ -377,18 +155,6 @@ register_agents(MgrAgentConfName, ManagedAgents) ->
Error
end.
-%%% @spec register_usm_users(MgrAgentConfName, UsmUsers) -> ok | {error, Reason}
-%%%
-%%% MgrAgentConfName = atom()
-%%% UsmUsers = [usm_user()]
-%%% Reason = term()
-%%%
-%%% @doc Explicitly instruct the manager to handle this USM user.
-%%% Corresponds to making an entry in usm.conf
-%%%
-%%% <p>This function will try to register the given users, without
-%%% checking if any of them already exist. In order to change an
-%%% already registered user, the user must first be unregistered.</p>
register_usm_users(MgrAgentConfName, UsmUsers) ->
EngineID = ct:get_config({MgrAgentConfName, engine_id}, ?ENGINE_ID),
case setup_usm_users(UsmUsers, EngineID) of
@@ -403,23 +169,10 @@ register_usm_users(MgrAgentConfName, UsmUsers) ->
Error
end.
-%%% @spec unregister_users(MgrAgentConfName) -> ok
-%%%
-%%% MgrAgentConfName = atom()
-%%% Reason = term()
-%%%
-%%% @doc Unregister all users.
unregister_users(MgrAgentConfName) ->
Users = [Id || {Id,_} <- ct:get_config({MgrAgentConfName, users},[])],
unregister_users(MgrAgentConfName,Users).
-%%% @spec unregister_users(MgrAgentConfName,Users) -> ok
-%%%
-%%% MgrAgentConfName = atom()
-%%% Users = [user_name()]
-%%% Reason = term()
-%%%
-%%% @doc Unregister the given users.
unregister_users(MgrAgentConfName,Users) ->
takedown_users(Users),
SnmpVals = ct:get_config(MgrAgentConfName),
@@ -432,25 +185,12 @@ unregister_users(MgrAgentConfName,Users) ->
ct_config:update_config(MgrAgentConfName, NewSnmpVals),
ok.
-%%% @spec unregister_agents(MgrAgentConfName) -> ok
-%%%
-%%% MgrAgentConfName = atom()
-%%% Reason = term()
-%%%
-%%% @doc Unregister all managed agents.
unregister_agents(MgrAgentConfName) ->
ManagedAgents = [AgentName ||
{AgentName, _} <-
ct:get_config({MgrAgentConfName,managed_agents},[])],
unregister_agents(MgrAgentConfName,ManagedAgents).
-%%% @spec unregister_agents(MgrAgentConfName,ManagedAgents) -> ok
-%%%
-%%% MgrAgentConfName = atom()
-%%% ManagedAgents = [agent_name()]
-%%% Reason = term()
-%%%
-%%% @doc Unregister the given managed agents.
unregister_agents(MgrAgentConfName,ManagedAgents) ->
takedown_managed_agents(MgrAgentConfName, ManagedAgents),
SnmpVals = ct:get_config(MgrAgentConfName),
@@ -464,23 +204,10 @@ unregister_agents(MgrAgentConfName,ManagedAgents) ->
ct_config:update_config(MgrAgentConfName, NewSnmpVals),
ok.
-%%% @spec unregister_usm_users(MgrAgentConfName) -> ok
-%%%
-%%% MgrAgentConfName = atom()
-%%% Reason = term()
-%%%
-%%% @doc Unregister all usm users.
unregister_usm_users(MgrAgentConfName) ->
UsmUsers = [Id || {Id,_} <- ct:get_config({MgrAgentConfName, usm_users},[])],
unregister_usm_users(MgrAgentConfName,UsmUsers).
-%%% @spec unregister_usm_users(MgrAgentConfName,UsmUsers) -> ok
-%%%
-%%% MgrAgentConfName = atom()
-%%% UsmUsers = [usm_user_name()]
-%%% Reason = term()
-%%%
-%%% @doc Unregister the given usm users.
unregister_usm_users(MgrAgentConfName,UsmUsers) ->
EngineID = ct:get_config({MgrAgentConfName, engine_id}, ?ENGINE_ID),
takedown_usm_users(UsmUsers,EngineID),
@@ -495,23 +222,9 @@ unregister_usm_users(MgrAgentConfName,UsmUsers) ->
ct_config:update_config(MgrAgentConfName, NewSnmpVals),
ok.
-%%% @spec load_mibs(Mibs) -> ok | {error, Reason}
-%%%
-%%% Mibs = [MibName]
-%%% MibName = string()
-%%% Reason = term()
-%%%
-%%% @doc Load the mibs into the agent 'snmp_master_agent'.
load_mibs(Mibs) ->
snmpa:load_mibs(snmp_master_agent, Mibs).
-%%% @spec unload_mibs(Mibs) -> ok | {error, Reason}
-%%%
-%%% Mibs = [MibName]
-%%% MibName = string()
-%%% Reason = term()
-%%%
-%%% @doc Unload the mibs from the agent 'snmp_master_agent'.
unload_mibs(Mibs) ->
snmpa:unload_mibs(snmp_master_agent, Mibs).
diff --git a/lib/common_test/src/ct_ssh.erl b/lib/common_test/src/ct_ssh.erl
index ca62357e1c..79ab122452 100644
--- a/lib/common_test/src/ct_ssh.erl
+++ b/lib/common_test/src/ct_ssh.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,44 +18,6 @@
%% %CopyrightEnd%
%%
-%%% @doc SSH/SFTP client module.
-%%%
-%%% <p>ct_ssh uses the OTP ssh application and more detailed information
-%%% about e.g. functions, types and options can be found in the
-%%% documentation for this application.</p>
-%%%
-%%% <p>The <code>Server</code> argument in the SFTP functions should
-%%% only be used for SFTP sessions that have been started on existing
-%%% SSH connections (i.e. when the original connection type is
-%%% <code>ssh</code>). Whenever the connection type is
-%%% <code>sftp</code>, use the SSH connection reference only.</p>
-%%%
-%%% <p>The following options are valid for specifying an SSH/SFTP
-%%% connection (i.e. may be used as config elements):</p>
-%%%
-%%% <pre>
-%%%
-%%% [{ConnType, Addr},
-%%% {port, Port},
-%%% {user, UserName}
-%%% {password, Pwd}
-%%% {user_dir, String}
-%%% {public_key_alg, PubKeyAlg}
-%%% {connect_timeout, Timeout}
-%%% {key_cb, KeyCallbackMod}]
-%%% </pre>
-%%%
-%%% <p><code>ConnType = ssh | sftp</code>.</p>
-%%% <p>Please see ssh(3) for other types.</p>
-%%%
-%%% <p>All timeout parameters in ct_ssh functions are values in
-%%% milliseconds.</p>
-%%%
-%%% @type connection() = handle() | ct:target_name()
-%%% @type handle() = ct_gen_conn:handle(). Handle for a specific
-%%% SSH/SFTP connection.
-%%% @type ssh_sftp_return() = term(). A return value from an ssh_sftp function.
-
-module(ct_ssh).
%% SSH Functions
@@ -100,64 +62,15 @@
%%%-----------------------------------------------------------------
%%%------------------------ SSH COMMANDS ---------------------------
-%%%-----------------------------------------------------------------
-%%% @spec connect(KeyOrName) -> {ok,Handle} | {error,Reason}
-%%% @equiv connect(KeyOrName,host,[])
connect(KeyOrName) ->
connect(KeyOrName, host).
-%%%-----------------------------------------------------------------
-%%% @spec connect(KeyOrName,ConnType) -> {ok,Handle} | {error,Reason}
-%%% @equiv connect(KeyOrName,ConnType,[])
connect(KeyOrName, ConnType) when is_atom(ConnType) ->
connect(KeyOrName, ConnType, []);
-%%%-----------------------------------------------------------------
-%%% @spec connect(KeyOrName,ExtraOpts) -> {ok,Handle} | {error,Reason}
-%%% @equiv connect(KeyOrName,host,ExtraOpts)
connect(KeyOrName, ExtraOpts) when is_list(ExtraOpts) ->
connect(KeyOrName, host, ExtraOpts).
-%%%-----------------------------------------------------------------
-%%% @spec connect(KeyOrName,ConnType,ExtraOpts) ->
-%%% {ok,Handle} | {error,Reason}
-%%% KeyOrName = Key | Name
-%%% Key = atom()
-%%% Name = ct:target_name()
-%%% ConnType = ssh | sftp | host
-%%% ExtraOpts = ssh_connect_options()
-%%% Handle = handle()
-%%% Reason = term()
-%%%
-%%% @doc Open an SSH or SFTP connection using the information
-%%% associated with <code>KeyOrName</code>.
-%%%
-%%% <p>If <code>Name</code> (an alias name for <code>Key</code>),
-%%% is used to identify the connection, this name may
-%%% be used as connection reference for subsequent calls.
-%%% It's only possible to have one open connection at a time
-%%% associated with <code>Name</code>. If <code>Key</code> is
-%%% used, the returned handle must be used for subsequent calls
-%%% (multiple connections may be opened using the config
-%%% data specified by <code>Key</code>). See <c>ct:require/2</c>
-%%% for how to create a new <c>Name</c></p>
-%%%
-%%% <p><code>ConnType</code> will always override the type
-%%% specified in the address tuple in the configuration data (and
-%%% in <code>ExtraOpts</code>). So it is possible to for example
-%%% open an sftp connection directly using data originally
-%%% specifying an ssh connection. The value <code>host</code>
-%%% means the connection type specified by the host option
-%%% (either in the configuration data or in <code>ExtraOpts</code>)
-%%% will be used.</p>
-%%%
-%%% <p><code>ExtraOpts</code> (optional) are extra SSH options
-%%% to be added to the config data for <code>KeyOrName</code>.
-%%% The extra options will override any existing options with the
-%%% same key in the config data. For details on valid SSH
-%%% options, see the documentation for the OTP ssh application.</p>
-%%%
-%%% @see ct:require/2
connect(KeyOrName, ConnType, ExtraOpts) ->
case ct:get_config(KeyOrName) of
undefined ->
@@ -232,12 +145,6 @@ connect(KeyOrName, ConnType, ExtraOpts) ->
end
end.
-%%%-----------------------------------------------------------------
-%%% @spec disconnect(SSH) -> ok | {error,Reason}
-%%% SSH = connection()
-%%% Reason = term()
-%%%
-%%% @doc Close an SSH/SFTP connection.
disconnect(SSH) ->
case get_handle(SSH) of
{ok,Pid} ->
@@ -252,242 +159,78 @@ disconnect(SSH) ->
Error
end.
-%%%-----------------------------------------------------------------
-%%% @spec session_open(SSH) -> {ok,ChannelId} | {error, Reason}
-%%% @equiv session_open(SSH,DefaultTimeout)
session_open(SSH) ->
call(SSH, {session_open,?DEFAULT_TIMEOUT}).
-%%%-----------------------------------------------------------------
-%%% @spec session_open(SSH,Timeout) -> {ok,ChannelId} | {error, Reason}
-%%% SSH = connection()
-%%% Timeout = integer()
-%%% ChannelId = integer()
-%%% Reason = term()
-%%%
-%%% @doc Opens a channel for an SSH session.
session_open(SSH, Timeout) ->
call(SSH, {session_open,Timeout}).
-%%%-----------------------------------------------------------------
-%%% @spec session_close(SSH,ChannelId) -> ok | {error, Reason}
-%%% SSH = connection()
-%%% ChannelId = integer()
-%%% Reason = term()
-%%%
-%%% @doc Closes an SSH session channel.
session_close(SSH, ChannelId) ->
call(SSH, {session_close,ChannelId}).
-%%%-----------------------------------------------------------------
-%%% @spec exec(SSH,Command) -> {ok,Data} | {error,Reason}
-%%% @equiv exec(SSH,Command,DefaultTimeout)
exec(SSH, Command) ->
exec(SSH, undefined, Command, ?DEFAULT_TIMEOUT).
-%%%-----------------------------------------------------------------
-%%% @spec exec(SSH,Command,Timeout) -> {ok,Data} | {error,Reason}
-%%% SSH = connection()
-%%% Command = string()
-%%% Timeout = integer()
-%%% Data = list()
-%%% Reason = term()
-%%%
-%%% @doc Requests server to perform <code>Command</code>. A session
-%%% channel is opened automatically for the request.
-%%% <code>Data</code> is received from the server as a result
-%%% of the command.
exec(SSH, Command, Timeout) when is_list(Command) ->
exec(SSH, undefined, Command, Timeout);
-%%%-----------------------------------------------------------------
-%%% @spec exec(SSH,ChannelId,Command) -> {ok,Data} | {error,Reason}
-%%% @equiv exec(SSH,ChannelId,Command,DefaultTimeout)
exec(SSH, ChannelId, Command) when is_integer(ChannelId) ->
exec(SSH, ChannelId, Command, ?DEFAULT_TIMEOUT).
-%%%-----------------------------------------------------------------
-%%% @spec exec(SSH,ChannelId,Command,Timeout) -> {ok,Data} | {error,Reason}
-%%% SSH = connection()
-%%% ChannelId = integer()
-%%% Command = string()
-%%% Timeout = integer()
-%%% Data = list()
-%%% Reason = term()
-%%%
-%%% @doc Requests server to perform <code>Command</code>. A previously
-%%% opened session channel is used for the request.
-%%% <code>Data</code> is received from the server as a result
-%%% of the command.
exec(SSH, ChannelId, Command, Timeout) ->
call(SSH, {exec,ChannelId,Command,Timeout}).
-%%%-----------------------------------------------------------------
-%%% @spec receive_response(SSH,ChannelId) -> {ok,Data} | {error,Reason}
-%%% @equiv receive_response(SSH,ChannelId,close)
receive_response(SSH, ChannelId) ->
receive_response(SSH, ChannelId, close, ?DEFAULT_TIMEOUT).
-%%%-----------------------------------------------------------------
-%%% @spec receive_response(SSH,ChannelId,End) -> {ok,Data} | {error,Reason}
-%%% @equiv receive_response(SSH,ChannelId,End,DefaultTimeout)
receive_response(SSH, ChannelId, End) when is_function(End) ->
receive_response(SSH, ChannelId, End, ?DEFAULT_TIMEOUT);
-%%%-----------------------------------------------------------------
-%%% @spec receive_response(SSH,ChannelId,Timeout) -> {ok,Data} | {error,Reason}
-%%% @equiv receive_response(SSH,ChannelId,close,Timeout)
receive_response(SSH, ChannelId, Timeout) when is_integer(Timeout) ->
receive_response(SSH, ChannelId, close, Timeout).
-%%%-----------------------------------------------------------------
-%%% @spec receive_response(SSH,ChannelId,End,Timeout) ->
-%%% {ok,Data} | {timeout,Data} | {error,Reason}
-%%% SSH = connection()
-%%% ChannelId = integer()
-%%% End = Fun | close | timeout
-%%% Timeout = integer()
-%%% Data = list()
-%%% Reason = term()
-%%%
-%%% @doc Receives expected data from server on the specified
-%%% session channel.
-%%%
-%%% <p>If <code>End == close</code>, data is returned
-%%% to the caller when the channel is closed by the
-%%% server. If a timeout occurs before this happens,
-%%% the function returns <code>{timeout,Data}</code>
-%%% (where <code>Data</code> is the data received so far).
-%%% If <code>End == timeout</code>, a timeout is expected
-%%% and <code>{ok,Data}</code> is returned both in the case
-%%% of a timeout and when the channel is closed. If
-%%% <code>End</code> is a fun, this fun will be
-%%% called with one argument - the data value in a received
-%%% <code>ssh_cm</code> message (see ssh_connection(3)). The
-%%% fun should return <code>true</code> to end the receiving
-%%% operation (and have the so far collected data returned), or
-%%% <code>false</code> to wait for more data from the server.
-%%% (Note that even if a fun is supplied, the function returns
-%%% immediately if the server closes the channel).</p>
receive_response(SSH, ChannelId, End, Timeout) ->
call(SSH, {receive_response,ChannelId,End,Timeout}).
-%%%-----------------------------------------------------------------
-%%% @spec send(SSH,ChannelId,Data) -> ok | {error,Reason}
-%%% @equiv send(SSH,ChannelId,0,Data,DefaultTimeout)
send(SSH, ChannelId, Data) ->
send(SSH, ChannelId, 0, Data, ?DEFAULT_TIMEOUT).
-%%%-----------------------------------------------------------------
-%%% @spec send(SSH,ChannelId,Data,Timeout) -> ok | {error,Reason}
-%%% @equiv send(SSH,ChannelId,0,Data,Timeout)
send(SSH, ChannelId, Data, Timeout) when is_integer(Timeout) ->
send(SSH, ChannelId, 0, Data, Timeout);
-%%%-----------------------------------------------------------------
-%%% @spec send(SSH,ChannelId,Type,Data) -> ok | {error,Reason}
-%%% @equiv send(SSH,ChannelId,Type,Data,DefaultTimeout)
send(SSH, ChannelId, Type, Data) when is_integer(Type) ->
send(SSH, ChannelId, Type, Data, ?DEFAULT_TIMEOUT).
-%%%-----------------------------------------------------------------
-%%% @spec send(SSH,ChannelId,Type,Data,Timeout) -> ok | {error,Reason}
-%%% SSH = connection()
-%%% ChannelId = integer()
-%%% Type = integer()
-%%% Data = list()
-%%% Timeout = integer()
-%%% Reason = term()
-%%%
-%%% @doc Send data to server on specified session channel.
send(SSH, ChannelId, Type, Data, Timeout) ->
call(SSH, {send,ChannelId,Type,Data,Timeout}).
-%%%-----------------------------------------------------------------
-%%% @spec send_and_receive(SSH,ChannelId,Data) ->
-%%% {ok,Data} | {error,Reason}
-%%% @equiv send_and_receive(SSH,ChannelId,Data,close)
send_and_receive(SSH, ChannelId, Data) ->
send_and_receive(SSH, ChannelId, 0, Data, close, ?DEFAULT_TIMEOUT).
-%%%-----------------------------------------------------------------
-%%% @spec send_and_receive(SSH,ChannelId,Data,End) ->
-%%% {ok,Data} | {error,Reason}
-%%% @equiv send_and_receive(SSH,ChannelId,0,Data,End,DefaultTimeout)
send_and_receive(SSH, ChannelId, Data, End) when is_function(End) ->
send_and_receive(SSH, ChannelId, 0, Data, End, ?DEFAULT_TIMEOUT);
-%%%-----------------------------------------------------------------
-%%% @spec send_and_receive(SSH,ChannelId,Data,Timeout) ->
-%%% {ok,Data} | {error,Reason}
-%%% @equiv send_and_receive(SSH,ChannelId,0,Data,close,Timeout)
send_and_receive(SSH, ChannelId, Data, Timeout) when is_integer(Timeout) ->
send_and_receive(SSH, ChannelId, 0, Data, close, Timeout);
-%%%-----------------------------------------------------------------
-%%% @spec send_and_receive(SSH,ChannelId,Type,Data) ->
-%%% {ok,Data} | {error,Reason}
-%%% @equiv send_and_receive(SSH,ChannelId,Type,Data,close,DefaultTimeout)
send_and_receive(SSH, ChannelId, Type, Data) when is_integer(Type) ->
send_and_receive(SSH, ChannelId, Type, Data, close, ?DEFAULT_TIMEOUT).
-%%%-----------------------------------------------------------------
-%%% @spec send_and_receive(SSH,ChannelId,Data,End,Timeout) ->
-%%% {ok,Data} | {error,Reason}
-%%% @equiv send_and_receive(SSH,ChannelId,0,Data,End,Timeout)
send_and_receive(SSH, ChannelId, Data, End, Timeout) when is_integer(Timeout) ->
send_and_receive(SSH, ChannelId, 0, Data, End, Timeout);
-%%%-----------------------------------------------------------------
-%%% @spec send_and_receive(SSH,ChannelId,Type,Data,Timeout) ->
-%%% {ok,Data} | {error,Reason}
-%%% @equiv send_and_receive(SSH,ChannelId,Type,Data,close,Timeout)
send_and_receive(SSH, ChannelId, Type, Data, Timeout) when is_integer(Type) ->
send_and_receive(SSH, ChannelId, Type, Data, close, Timeout);
-%%%-----------------------------------------------------------------
-%%% @spec send_and_receive(SSH,ChannelId,Type,Data,End) ->
-%%% {ok,Data} | {error,Reason}
-%%% @equiv send_and_receive(SSH,ChannelId,Type,Data,End,DefaultTimeout)
send_and_receive(SSH, ChannelId, Type, Data, End) when is_function(End) ->
send_and_receive(SSH, ChannelId, Type, Data, End, ?DEFAULT_TIMEOUT).
-%%%-----------------------------------------------------------------
-%%% @spec send_and_receive(SSH,ChannelId,Type,Data,End,Timeout) ->
-%%% {ok,Data} | {error,Reason}
-%%% SSH = connection()
-%%% ChannelId = integer()
-%%% Type = integer()
-%%% Data = list()
-%%% End = Fun | close | timeout
-%%% Timeout = integer()
-%%% Reason = term()
-%%%
-%%% @doc Send data to server on specified session channel and wait
-%%% to receive the server response.
-%%%
-%%% <p>See <code>receive_response/4</code> for details on the
-%%% <code>End</code> argument.</p>
send_and_receive(SSH, ChannelId, Type, Data, End, Timeout) ->
call(SSH, {send_and_receive,ChannelId,Type,Data,End,Timeout}).
-%%%-----------------------------------------------------------------
-%%% @spec subsystem(SSH,ChannelId,Subsystem) -> Status | {error,Reason}
-%%% @equiv subsystem(SSH,ChannelId,Subsystem,DefaultTimeout)
subsystem(SSH, ChannelId, Subsystem) ->
subsystem(SSH, ChannelId, Subsystem, ?DEFAULT_TIMEOUT).
-%%%-----------------------------------------------------------------
-%%% @spec subsystem(SSH,ChannelId,Subsystem,Timeout) ->
-%%% Status | {error,Reason}
-%%% SSH = connection()
-%%% ChannelId = integer()
-%%% Subsystem = string()
-%%% Timeout = integer()
-%%% Status = success | failure
-%%% Reason = term()
-%%%
-%%% @doc Sends a request to execute a predefined subsystem.
subsystem(SSH, ChannelId, Subsystem, Timeout) ->
call(SSH, {subsystem,ChannelId,Subsystem,Timeout}).
@@ -511,439 +254,157 @@ shell(SSH, ChannelId, Timeout) ->
%%%-----------------------------------------------------------------
%%%------------------------ SFTP COMMANDS --------------------------
-%%%-----------------------------------------------------------------
-%%% @spec sftp_connect(SSH) -> {ok,Server} | {error,Reason}
-%%% SSH = connection()
-%%% Server = pid()
-%%% Reason = term()
-%%% @doc Starts an SFTP session on an already existing SSH connection.
-%%% <code>Server</code> identifies the new session and must be
-%%% specified whenever SFTP requests are to be sent.
sftp_connect(SSH) ->
call(SSH, sftp_connect).
-%%%-----------------------------------------------------------------
-%%% @spec read_file(SSH, File) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
read_file(SSH, File) ->
call(SSH, {read_file,sftp,File}).
-%%%-----------------------------------------------------------------
-%%% @spec read_file(SSH, Server, File) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
read_file(SSH, Server, File) ->
call(SSH, {read_file,Server,File}).
-%%%-----------------------------------------------------------------
-%%% @spec write_file(SSH, File, Iolist) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
write_file(SSH, File, Iolist) ->
call(SSH, {write_file,sftp,File,Iolist}).
-%%%-----------------------------------------------------------------
-%%% @spec write_file(SSH, Server, File, Iolist) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
write_file(SSH, Server, File, Iolist) ->
call(SSH, {write_file,Server,File,Iolist}).
-%%%-----------------------------------------------------------------
-%%% @spec list_dir(SSH, Path) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
list_dir(SSH, Path) ->
call(SSH, {list_dir,sftp,Path}).
-%%%-----------------------------------------------------------------
-%%% @spec list_dir(SSH, Server, Path) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
list_dir(SSH, Server, Path) ->
call(SSH, {list_dir,Server,Path}).
-%%%-----------------------------------------------------------------
-%%% @spec open(SSH, File, Mode) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
open(SSH, File, Mode) ->
call(SSH, {open,sftp,File,Mode}).
-%%%-----------------------------------------------------------------
-%%% @spec open(SSH, Server, File, Mode) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
open(SSH, Server, File, Mode) ->
call(SSH, {open,Server,File,Mode}).
-%%%-----------------------------------------------------------------
-%%% @spec opendir(SSH, Path) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
opendir(SSH, Path) ->
call(SSH, {opendir,sftp,Path}).
-%%%-----------------------------------------------------------------
-%%% @spec opendir(SSH, Server, Path) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
opendir(SSH, Server, Path) ->
call(SSH, {opendir,Server,Path}).
-%%%-----------------------------------------------------------------
-%%% @spec close(SSH, Handle) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
close(SSH, Handle) ->
call(SSH, {close,sftp,Handle}).
-%%%-----------------------------------------------------------------
-%%% @spec close(SSH, Server, Handle) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
close(SSH, Server, Handle) ->
call(SSH, {close,Server,Handle}).
-%%%-----------------------------------------------------------------
-%%% @spec read(SSH, Handle, Len) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
read(SSH, Handle, Len) ->
call(SSH, {read,sftp,Handle,Len}).
-%%%-----------------------------------------------------------------
-%%% @spec read(SSH, Server, Handle, Len) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
read(SSH, Server, Handle, Len) ->
call(SSH, {read,Server,Handle,Len}).
-%%%-----------------------------------------------------------------
-%%% @spec pread(SSH, Handle, Position, Length) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
pread(SSH, Handle, Position, Length) ->
call(SSH, {pread,sftp,Handle,Position,Length}).
-%%%-----------------------------------------------------------------
-%%% @spec pread(SSH, Server, Handle, Position, Length) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
pread(SSH, Server, Handle, Position, Length) ->
call(SSH, {pread,Server,Handle,Position,Length}).
-%%%-----------------------------------------------------------------
-%%% @spec aread(SSH, Handle, Len) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
aread(SSH, Handle, Len) ->
call(SSH, {aread,sftp,Handle,Len}).
-%%%-----------------------------------------------------------------
-%%% @spec aread(SSH, Server, Handle, Len) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
aread(SSH, Server, Handle, Len) ->
call(SSH, {aread,Server,Handle,Len}).
-%%%-----------------------------------------------------------------
-%%% @spec apread(SSH, Handle, Position, Length) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
apread(SSH, Handle, Position, Length) ->
call(SSH, {apread,sftp,Handle,Position,Length}).
-%%%-----------------------------------------------------------------
-%%% @spec apread(SSH, Server, Handle, Position, Length) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
apread(SSH, Server, Handle, Position, Length) ->
call(SSH, {apread,Server,Handle,Position,Length}).
-%%%-----------------------------------------------------------------
-%%% @spec write(SSH, Handle, Data) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
write(SSH, Handle, Data) ->
call(SSH, {write,sftp,Handle,Data}).
-%%%-----------------------------------------------------------------
-%%% @spec write(SSH, Server, Handle, Data) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
write(SSH, Server, Handle, Data) ->
call(SSH, {write,Server,Handle,Data}).
-%%%-----------------------------------------------------------------
-%%% @spec pwrite(SSH, Handle, Position, Data) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
pwrite(SSH, Handle, Position, Data) ->
call(SSH, {pwrite,sftp,Handle,Position,Data}).
-%%%-----------------------------------------------------------------
-%%% @spec pwrite(SSH, Server, Handle, Position, Data) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
pwrite(SSH, Server, Handle, Position, Data) ->
call(SSH, {pwrite,Server,Handle,Position,Data}).
-%%%-----------------------------------------------------------------
-%%% @spec awrite(SSH, Handle, Data) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
awrite(SSH, Handle, Data) ->
call(SSH, {awrite,sftp,Handle, Data}).
-%%%-----------------------------------------------------------------
-%%% @spec awrite(SSH, Server, Handle, Data) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
awrite(SSH, Server, Handle, Data) ->
call(SSH, {awrite,Server,Handle, Data}).
-%%%-----------------------------------------------------------------
-%%% @spec apwrite(SSH, Handle, Position, Data) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
apwrite(SSH, Handle, Position, Data) ->
call(SSH, {apwrite,sftp,Handle,Position,Data}).
-%%%-----------------------------------------------------------------
-%%% @spec apwrite(SSH, Server, Handle, Position, Data) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
apwrite(SSH, Server, Handle, Position, Data) ->
call(SSH, {apwrite,Server,Handle,Position,Data}).
-%%%-----------------------------------------------------------------
-%%% @spec position(SSH, Handle, Location) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
position(SSH, Handle, Location) ->
call(SSH, {position,sftp,Handle,Location}).
-%%%-----------------------------------------------------------------
-%%% @spec position(SSH, Server, Handle, Location) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
position(SSH, Server, Handle, Location) ->
call(SSH, {position,Server,Handle,Location}).
-%%%-----------------------------------------------------------------
-%%% @spec read_file_info(SSH, Name) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
read_file_info(SSH, Name) ->
call(SSH, {read_file_info,sftp,Name}).
-%%%-----------------------------------------------------------------
-%%% @spec read_file_info(SSH, Server, Name) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
read_file_info(SSH, Server, Name) ->
call(SSH, {read_file_info,Server,Name}).
-%%%-----------------------------------------------------------------
-%%% @spec get_file_info(SSH, Handle) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
get_file_info(SSH, Handle) ->
call(SSH, {get_file_info,sftp,Handle}).
-%%%-----------------------------------------------------------------
-%%% @spec get_file_info(SSH, Server, Handle) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
get_file_info(SSH, Server, Handle) ->
call(SSH, {get_file_info,Server,Handle}).
-%%%-----------------------------------------------------------------
-%%% @spec read_link_info(SSH, Name) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
read_link_info(SSH, Name) ->
call(SSH, {read_link_info,sftp,Name}).
-%%%-----------------------------------------------------------------
-%%% @spec read_link_info(SSH, Server, Name) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
read_link_info(SSH, Server, Name) ->
call(SSH, {read_link_info,Server,Name}).
-%%%-----------------------------------------------------------------
-%%% @spec write_file_info(SSH, Name, Info) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
write_file_info(SSH, Name, Info) ->
call(SSH, {write_file_info,sftp,Name,Info}).
-%%%-----------------------------------------------------------------
-%%% @spec write_file_info(SSH, Server, Name, Info) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
write_file_info(SSH, Server, Name, Info) ->
call(SSH, {write_file_info,Server,Name,Info}).
-%%%-----------------------------------------------------------------
-%%% @spec read_link(SSH, Name) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
read_link(SSH, Name) ->
call(SSH, {read_link,sftp,Name}).
-%%%-----------------------------------------------------------------
-%%% @spec read_link(SSH, Server, Name) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
read_link(SSH, Server, Name) ->
call(SSH, {read_link,Server,Name}).
-%%%-----------------------------------------------------------------
-%%% @spec make_symlink(SSH, Name, Target) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
make_symlink(SSH, Name, Target) ->
call(SSH, {make_symlink,sftp,Name,Target}).
-%%%-----------------------------------------------------------------
-%%% @spec make_symlink(SSH, Server, Name, Target) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
make_symlink(SSH, Server, Name, Target) ->
call(SSH, {make_symlink,Server,Name,Target}).
-%%%-----------------------------------------------------------------
-%%% @spec rename(SSH, OldName, NewName) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
rename(SSH, OldName, NewName) ->
call(SSH, {rename,sftp,OldName,NewName}).
-%%%-----------------------------------------------------------------
-%%% @spec rename(SSH, Server, OldName, NewName) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
rename(SSH, Server, OldName, NewName) ->
call(SSH, {rename,Server,OldName,NewName}).
-%%%-----------------------------------------------------------------
-%%% @spec delete(SSH, Name) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
delete(SSH, Name) ->
call(SSH, {delete,sftp,Name}).
-%%%-----------------------------------------------------------------
-%%% @spec delete(SSH, Server, Name) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
delete(SSH, Server, Name) ->
call(SSH, {delete,Server,Name}).
-%%%-----------------------------------------------------------------
-%%% @spec make_dir(SSH, Name) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
make_dir(SSH, Name) ->
call(SSH, {make_dir,sftp,Name}).
-%%%-----------------------------------------------------------------
-%%% @spec make_dir(SSH, Server, Name) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
make_dir(SSH, Server, Name) ->
call(SSH, {make_dir,Server,Name}).
-%%%-----------------------------------------------------------------
-%%% @spec del_dir(SSH, Name) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
del_dir(SSH, Name) ->
call(SSH, {del_dir,sftp,Name}).
-%%%-----------------------------------------------------------------
-%%% @spec del_dir(SSH, Server, Name) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
del_dir(SSH, Server, Name) ->
call(SSH, {del_dir,Server,Name}).
@@ -952,7 +413,6 @@ del_dir(SSH, Server, Name) ->
%%% Callback functions
%%%=================================================================
-%% @hidden
init(KeyOrName, {ConnType,Addr,Port}, AllOpts) ->
User = proplists:get_value(user, AllOpts),
Password = case proplists:get_value(password, AllOpts) of
@@ -996,12 +456,12 @@ init(KeyOrName, {ConnType,Addr,Port}, AllOpts) ->
try_log(heading(init,KeyOrName),
"Opened ~w connection:\n"
"Host: ~tp (~p)\nUser: ~tp\nPassword: ~p\n",
- [ConnType,Addr,Port,User,lists:duplicate(length(Password),$*)]),
+ [ConnType,Addr,Port,User,
+ lists:duplicate(string:length(Password),$*)]),
{ok,SSHRef,#state{ssh_ref=SSHRef, conn_type=ConnType,
target=KeyOrName}}
end.
-%% @hidden
handle_msg(sftp_connect, State) ->
#state{ssh_ref=SSHRef, target=Target} = State,
try_log(heading(sftp_connect,Target), "SSH Ref: ~p", [SSHRef]),
@@ -1245,15 +705,12 @@ handle_msg({del_dir,Srv,Name}=Cmd, S=#state{ssh_ref=SSHRef}) ->
[SSHRef,ref(Srv,SSHRef),mod(Cmd)]),
{ssh_sftp:del_dir(ref(Srv,SSHRef), Name),S}.
-%% @hidden
reconnect(_Addr,_State) ->
{error,no_reconnection_of_ssh}.
-%% @hidden
close(SSHRef) ->
disconnect(SSHRef).
-%% @hidden
terminate(SSHRef, State) ->
case State#state.conn_type of
ssh ->
@@ -1270,8 +727,6 @@ terminate(SSHRef, State) ->
%%%=================================================================
%%% Internal functions
-%%%-----------------------------------------------------------------
-%%%
do_recv_response(SSH, Chn, Data, End, Timeout) ->
receive
{ssh_cm, SSH, {open,Chn,RemoteChn,{session}}} ->
@@ -1350,8 +805,6 @@ do_recv_response(SSH, Chn, Data, End, Timeout) ->
end
end.
-%%%-----------------------------------------------------------------
-%%%
get_handle(SSH) when is_pid(SSH) ->
{ok,SSH};
get_handle(SSH) ->
@@ -1364,8 +817,6 @@ get_handle(SSH) ->
Error
end.
-%%%-----------------------------------------------------------------
-%%%
call(SSH, Msg) ->
call(SSH, Msg, infinity).
@@ -1377,29 +828,19 @@ call(SSH, Msg, Timeout) ->
Error
end.
-%%%-----------------------------------------------------------------
-%%%
ref(sftp, SSHRef) -> SSHRef;
ref(Server, _) -> Server.
-%%%-----------------------------------------------------------------
-%%%
mod(Cmd) ->
[Op,_Server|Args] = tuple_to_list(Cmd),
list_to_tuple([Op|Args]).
-%%%-----------------------------------------------------------------
-%%%
heading(Function, Ref) ->
io_lib:format("ct_ssh:~tw ~tp",[Function,Ref]).
-%%%-----------------------------------------------------------------
-%%%
log(Heading, Str, Args) ->
ct_gen_conn:log(Heading, Str, Args).
-%%%-----------------------------------------------------------------
-%%%
try_log(Heading, Str, Args) ->
try_log(Heading, Str, Args, infinity).
@@ -1413,8 +854,6 @@ try_log(Heading, Str, Args, Timeout) ->
ok
end.
-%%%-----------------------------------------------------------------
-%%%
debug(Str) ->
debug(Str, []).
diff --git a/lib/common_test/src/ct_telnet.erl b/lib/common_test/src/ct_telnet.erl
index b50cddd492..219f58dcf5 100644
--- a/lib/common_test/src/ct_telnet.erl
+++ b/lib/common_test/src/ct_telnet.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,131 +18,6 @@
%% %CopyrightEnd%
%%
-%% @doc Common Test specific layer on top of telnet client `ct_telnet_client.erl'
-%%
-%% <p>Use this module to set up telnet connections, send commands and
-%% perform string matching on the result.
-%% See the `unix_telnet' manual page for information about how to use
-%% `ct_telnet', and configure connections, specifically for unix hosts.</p>
-%% <p>The following default values are defined in `ct_telnet':</p>
-%% <pre>
-%% Connection timeout = 10 sec (time to wait for connection)
-%% Command timeout = 10 sec (time to wait for a command to return)
-%% Max no of reconnection attempts = 3
-%% Reconnection interval = 5 sek (time to wait in between reconnection attempts)
-%% Keep alive = true (will send NOP to the server every 8 sec if connection is idle)
-%% Polling limit = 0 (max number of times to poll to get a remaining string terminated)
-%% Polling interval = 1 sec (sleep time between polls)</pre>
-%% <p>These parameters can be altered by the user with the following
-%% configuration term:</p>
-%% <pre>
-%% {telnet_settings, [{connect_timeout,Millisec},
-%% {command_timeout,Millisec},
-%% {reconnection_attempts,N},
-%% {reconnection_interval,Millisec},
-%% {keep_alive,Bool},
-%% {poll_limit,N},
-%% {poll_interval,Millisec},
-%% {tcp_nodelay,Bool}]}.</pre>
-%% <p><code>Millisec = integer(), N = integer()</code></p>
-%% <p>Enter the <code>telnet_settings</code> term in a configuration
-%% file included in the test and ct_telnet will retrieve the information
-%% automatically. Note that `keep_alive' may be specified per connection if
-%% required. See `unix_telnet' for details.</p>
-%%
-%% == Logging ==
-%%
-%% The default logging behaviour of `ct_telnet' is to print information
-%% to the test case HTML log about performed operations and commands
-%% and their corresponding results. What won't be printed to the HTML log
-%% are text strings sent from the telnet server that are not explicitly
-%% received by means of a `ct_telnet' function such as `expect/3'.
-%% `ct_telnet' may however be configured to use a special purpose event handler,
-%% implemented in `ct_conn_log_h', for logging <b>all</b> telnet traffic.
-%% To use this handler, you need to install a Common Test hook named
-%% `cth_conn_log'. Example (using the test suite info function):
-%%
-%% ```
-%% suite() ->
-%% [{ct_hooks, [{cth_conn_log, [{conn_mod(),hook_options()}]}]}].
-%% '''
-%%
-%% `conn_mod()' is the name of the common_test module implementing
-%% the connection protocol, i.e. `ct_telnet'.
-%%
-%% The `cth_conn_log' hook performs unformatted logging of telnet data to
-%% a separate text file. All telnet communication is captured and printed,
-%% including arbitrary data sent from the server. The link to this text file
-%% can be found on the top of the test case HTML log.
-%%
-%% By default, data for all telnet connections is logged in one common
-%% file (named `default'), which might get messy e.g. if multiple telnet
-%% sessions are running in parallel. It is therefore possible to create a
-%% separate log file for each connection. To configure this, use the hook
-%% option `hosts' and list the names of the servers/connections that will be
-%% used in the suite. Note that the connections must be named for this to work
-%% (see the `open' function below).
-%%
-%% The hook option named `log_type' may be used to change the `cth_conn_log'
-%% behaviour. The default value of this option is `raw', which results in the
-%% behaviour described above. If the value is set to `html', all telnet
-%% communication is printed to the test case HTML log instead.
-%%
-%% All `cth_conn_log' hook options described above can also be specified in
-%% a configuration file with the configuration variable `ct_conn_log'. Example:
-%%
-%% ```
-%% {ct_conn_log, [{ct_telnet,[{log_type,raw},
-%% {hosts,[key_or_name()]}]}]}
-%% '''
-%%
-%% <b>Note</b> that hook options specified in a configuration file
-%% will overwrite any hardcoded hook options in the test suite!
-%%
-%% === Logging example ===
-%%
-%% The following `ct_hooks' statement will cause printing of telnet traffic
-%% to separate logs for the connections named `server1' and `server2'.
-%% Traffic for any other connections will be logged in the default telnet log.
-%%
-%% ```
-%% suite() ->
-%% [{ct_hooks,
-%% [{cth_conn_log, [{ct_telnet,[{hosts,[server1,server2]}]}]}]}].
-%%'''
-%%
-%% As previously explained, the above specification could also be provided
-%% by means of an entry like this in a configuration file:
-%%
-%% ```
-%% {ct_conn_log, [{ct_telnet,[{hosts,[server1,server2]}]}]}.
-%% '''
-%%
-%% in which case the `ct_hooks' statement in the test suite may simply look
-%% like this:
-%%
-%% ```
-%% suite() ->
-%% [{ct_hooks, [{cth_conn_log, []}]}].
-%% '''
-%%
-%% @end
-
-%% @type connection_type() = telnet | ts1 | ts2
-
-%% @type connection() = handle() |
-%% {ct:target_name(),connection_type()} | ct:target_name()
-
-%% @type handle() = ct_gen_conn:handle(). Handle for a
-%% specific telnet connection.
-
-%% @type prompt_regexp() = string(). A regular expression which
-%% matches all possible prompts for a specific type of target. The
-%% regexp must not have any groups i.e. when matching, re:run/3 shall
-%% return a list with one single element.
-%%
-%% @see unix_telnet
-
-module(ct_telnet).
-export([open/1, open/2, open/3, open/4, close/1]).
@@ -186,20 +61,9 @@
reconn_int=?RECONN_TIMEOUT,
tcp_nodelay=false}).
-%%%-----------------------------------------------------------------
-%%% @spec open(Name) -> {ok,Handle} | {error,Reason}
-%%% @equiv open(Name,telnet)
open(Name) ->
open(Name,telnet).
-%%%-----------------------------------------------------------------
-%%% @spec open(Name,ConnType) -> {ok,Handle} | {error,Reason}
-%%% Name = target_name()
-%%% ConnType = ct_telnet:connection_type()
-%%% Handle = ct_telnet:handle()
-%%% Reason = term()
-%%%
-%%% @doc Open a telnet connection to the specified target host.
open(Name,ConnType) ->
case ct_util:get_key_from_name(Name) of
{ok, unix} -> % unix host
@@ -210,44 +74,9 @@ open(Name,ConnType) ->
Error
end.
-%%%-----------------------------------------------------------------
-%%% @spec open(KeyOrName,ConnType,TargetMod) ->
-%%% {ok,Handle} | {error,Reason}
-%%% @equiv open(KeyOrName,ConnType,TargetMod,[])
open(KeyOrName,ConnType,TargetMod) ->
open(KeyOrName,ConnType,TargetMod,KeyOrName).
-%%%-----------------------------------------------------------------
-%%% @spec open(KeyOrName,ConnType,TargetMod,Extra) ->
-%%% {ok,Handle} | {error,Reason}
-%%% KeyOrName = Key | Name
-%%% Key = atom()
-%%% Name = ct:target_name()
-%%% ConnType = connection_type()
-%%% TargetMod = atom()
-%%% Extra = term()
-%%% Handle = handle()
-%%% Reason = term()
-%%%
-%%% @doc Open a telnet connection to the specified target host.
-%%%
-%%% <p>The target data must exist in a configuration file. The connection
-%%% may be associated with either <code>Name</code> and/or the returned
-%%% <code>Handle</code>. To allocate a name for the target,
-%%% use <code>ct:require/2</code> in a test case, or use a
-%%% <code>require</code> statement in the suite info function
-%%% (<code>suite/0</code>), or in a test case info function.
-%%% If you want the connection to be associated with <code>Handle</code> only
-%%% (in case you need to open multiple connections to a host for example),
-%%% simply use <code>Key</code>, the configuration variable name, to
-%%% specify the target. Note that a connection that has no associated target
-%%% name can only be closed with the handle value.</p>
-%%%
-%%% <p><code>TargetMod</code> is a module which exports the functions
-%%% <code>connect(Ip,Port,KeepAlive,Extra)</code> and <code>get_prompt_regexp()</code>
-%%% for the given <code>TargetType</code> (e.g. <code>unix_telnet</code>).</p>
-%%%
-%%% @see ct:require/2
open(KeyOrName,ConnType,TargetMod,Extra) ->
case ct:get_config({KeyOrName,ConnType}) of
undefined ->
@@ -287,17 +116,6 @@ open(KeyOrName,ConnType,TargetMod,Extra) ->
{old,true}])
end.
-%%%-----------------------------------------------------------------
-%%% @spec close(Connection) -> ok | {error,Reason}
-%%% Connection = ct_telnet:connection()
-%%% Reason = term()
-%%%
-%%% @doc Close the telnet connection and stop the process managing it.
-%%%
-%%% <p>A connection may be associated with a target name and/or a handle.
-%%% If <code>Connection</code> has no associated target name, it may only
-%%% be closed with the handle value (see the <code>open/4</code>
-%%% function).</p>
close(Connection) ->
case get_handle(Connection) of
{ok,Pid} ->
@@ -315,30 +133,10 @@ close(Connection) ->
%%%=================================================================
%%% Test suite interface
%%%-----------------------------------------------------------------
-%%% @spec cmd(Connection,Cmd) -> {ok,Data} | {error,Reason}
-%%% @equiv cmd(Connection,Cmd,[])
+
cmd(Connection,Cmd) ->
cmd(Connection,Cmd,[]).
-%%%-----------------------------------------------------------------
-%%% @spec cmd(Connection,Cmd,Opts) -> {ok,Data} | {error,Reason}
-%%% Connection = ct_telnet:connection()
-%%% Cmd = string()
-%%% Opts = [Opt]
-%%% Opt = {timeout,timeout()} | {newline,boolean()}
-%%% Data = [string()]
-%%% Reason = term()
-%%% @doc Send a command via telnet and wait for prompt.
-%%%
-%%% <p>This function will by default add a newline to the end of the
-%%% given command. If this is not desired, the option
-%%% `{newline,false}' can be used. This is necessary, for example,
-%%% when sending telnet command sequences (prefixed with the
-%%% Interprete As Command, IAC, character).</p>
-%%%
-%%% <p>The option `timeout' specifies how long the client shall wait for
-%%% prompt. If the time expires, the function returns
-%%% `{error,timeout}'. See the module description for information
-%%% about the default value for the command timeout.</p>
+
cmd(Connection,Cmd,Opts) when is_list(Opts) ->
case check_cmd_opts(Opts) of
ok ->
@@ -363,42 +161,13 @@ check_cmd_opts([]) ->
check_cmd_opts(Opts) ->
check_send_opts(Opts).
-%%%-----------------------------------------------------------------
-%%% @spec cmdf(Connection,CmdFormat,Args) -> {ok,Data} | {error,Reason}
-%%% @equiv cmdf(Connection,CmdFormat,Args,[])
cmdf(Connection,CmdFormat,Args) ->
cmdf(Connection,CmdFormat,Args,[]).
-%%%-----------------------------------------------------------------
-%%% @spec cmdf(Connection,CmdFormat,Args,Opts) -> {ok,Data} | {error,Reason}
-%%% Connection = ct_telnet:connection()
-%%% CmdFormat = string()
-%%% Args = list()
-%%% Opts = [Opt]
-%%% Opt = {timeout,timeout()} | {newline,boolean()}
-%%% Data = [string()]
-%%% Reason = term()
-%%% @doc Send a telnet command and wait for prompt
-%%% (uses a format string and list of arguments to build the command).
-%%%
-%%% <p>See {@link cmd/3} further description.</p>
+
cmdf(Connection,CmdFormat,Args,Opts) when is_list(Args) ->
Cmd = lists:flatten(io_lib:format(CmdFormat,Args)),
cmd(Connection,Cmd,Opts).
-%%%-----------------------------------------------------------------
-%%% @spec get_data(Connection) -> {ok,Data} | {error,Reason}
-%%% Connection = ct_telnet:connection()
-%%% Data = [string()]
-%%% Reason = term()
-%%% @doc Get all data that has been received by the telnet client
-%%% since the last command was sent. Note that only newline terminated
-%%% strings are returned. If the last string received has not yet
-%%% been terminated, the connection may be polled automatically until
-%%% the string is complete. The polling feature is controlled
-%%% by the `poll_limit' and `poll_interval' config values and is
-%%% by default disabled (meaning the function will immediately
-%%% return all complete strings received and save a remaining
-%%% non-terminated string for a later `get_data' call).
get_data(Connection) ->
case get_handle(Connection) of
{ok,Pid} ->
@@ -407,29 +176,9 @@ get_data(Connection) ->
Error
end.
-%%%-----------------------------------------------------------------
-%%% @spec send(Connection,Cmd) -> ok | {error,Reason}
-%%% @equiv send(Connection,Cmd,[])
send(Connection,Cmd) ->
send(Connection,Cmd,[]).
-%%%-----------------------------------------------------------------
-%%% @spec send(Connection,Cmd,Opts) -> ok | {error,Reason}
-%%% Connection = ct_telnet:connection()
-%%% Cmd = string()
-%%% Opts = [Opt]
-%%% Opt = {newline,boolean()}
-%%% Reason = term()
-%%% @doc Send a telnet command and return immediately.
-%%%
-%%% This function will by default add a newline to the end of the
-%%% given command. If this is not desired, the option
-%%% `{newline,false}' can be used. This is necessary, for example,
-%%% when sending telnet command sequences (prefixed with the
-%%% Interprete As Command, IAC, character).
-%%%
-%%% <p>The resulting output from the command can be read with
-%%% <code>get_data/1</code> or <code>expect/2/3</code>.</p>
send(Connection,Cmd,Opts) ->
case check_send_opts(Opts) of
ok ->
@@ -445,158 +194,47 @@ send(Connection,Cmd,Opts) ->
check_send_opts([{newline,Bool}|Opts]) when is_boolean(Bool) ->
check_send_opts(Opts);
+check_send_opts([{newline,String}|Opts]) when is_list(String) ->
+ case lists:all(fun(I) when is_integer(I), I>=0, I=<127 -> true;
+ (_) -> false
+ end, String) of
+ true ->
+ check_send_opts(Opts);
+ false ->
+ {error,{invalid_option,{newline,String}}}
+ end;
check_send_opts([Invalid|_]) ->
{error,{invalid_option,Invalid}};
check_send_opts([]) ->
ok.
-
-%%%-----------------------------------------------------------------
-%%% @spec sendf(Connection,CmdFormat,Args) -> ok | {error,Reason}
-%%% @equiv sendf(Connection,CmdFormat,Args,[])
sendf(Connection,CmdFormat,Args) when is_list(Args) ->
sendf(Connection,CmdFormat,Args,[]).
-%%%-----------------------------------------------------------------
-%%% @spec sendf(Connection,CmdFormat,Args,Opts) -> ok | {error,Reason}
-%%% Connection = ct_telnet:connection()
-%%% CmdFormat = string()
-%%% Args = list()
-%%% Opts = [Opt]
-%%% Opt = {newline,boolean()}
-%%% Reason = term()
-%%% @doc Send a telnet command and return immediately (uses a format
-%%% string and a list of arguments to build the command).
sendf(Connection,CmdFormat,Args,Opts) when is_list(Args) ->
Cmd = lists:flatten(io_lib:format(CmdFormat,Args)),
send(Connection,Cmd,Opts).
-%%%-----------------------------------------------------------------
-%%% @spec expect(Connection,Patterns) -> term()
-%%% @equiv expect(Connections,Patterns,[])
expect(Connection,Patterns) ->
expect(Connection,Patterns,[]).
-%%%-----------------------------------------------------------------
-%%% @spec expect(Connection,Patterns,Opts) -> {ok,Match} |
-%%% {ok,MatchList,HaltReason} |
-%%% {error,Reason}
-%%% Connection = ct_telnet:connection()
-%%% Patterns = Pattern | [Pattern]
-%%% Pattern = string() | {Tag,string()} | prompt | {prompt,Prompt}
-%%% Prompt = string()
-%%% Tag = term()
-%%% Opts = [Opt]
-%%% Opt = {idle_timeout,IdleTimeout} | {total_timeout,TotalTimeout} |
-%%% repeat | {repeat,N} | sequence | {halt,HaltPatterns} |
-%%% ignore_prompt | no_prompt_check | wait_for_prompt |
-%%% {wait_for_prompt,Prompt}
-%%% IdleTimeout = infinity | integer()
-%%% TotalTimeout = infinity | integer()
-%%% N = integer()
-%%% HaltPatterns = Patterns
-%%% MatchList = [Match]
-%%% Match = RxMatch | {Tag,RxMatch} | {prompt,Prompt}
-%%% RxMatch = [string()]
-%%% HaltReason = done | Match
-%%% Reason = timeout | {prompt,Prompt}
-%%%
-%%% @doc Get data from telnet and wait for the expected pattern.
-%%%
-%%% <p><code>Pattern</code> can be a POSIX regular expression. The function
-%%% returns as soon as a pattern has been successfully matched (at least one,
-%%% in the case of multiple patterns).</p>
-%%%
-%%% <p><code>RxMatch</code> is a list of matched strings. It looks
-%%% like this: <code>[FullMatch, SubMatch1, SubMatch2, ...]</code>
-%%% where <code>FullMatch</code> is the string matched by the whole
-%%% regular expression and <code>SubMatchN</code> is the string that
-%%% matched subexpression no <code>N</code>. Subexpressions are
-%%% denoted with '(' ')' in the regular expression</p>
-%%%
-%%% <p>If a <code>Tag</code> is given, the returned <code>Match</code>
-%%% will also include the matched <code>Tag</code>. Else, only
-%%% <code>RxMatch</code> is returned.</p>
-%%%
-%%% <p>The <code>idle_timeout</code> option indicates that the function
-%%% shall return if the telnet client is idle (i.e. if no data is
-%%% received) for more than <code>IdleTimeout</code> milliseconds. Default
-%%% timeout is 10 seconds.</p>
-%%%
-%%% <p>The <code>total_timeout</code> option sets a time limit for
-%%% the complete expect operation. After <code>TotalTimeout</code>
-%%% milliseconds, <code>{error,timeout}</code> is returned. The default
-%%% value is <code>infinity</code> (i.e. no time limit).</p>
-%%%
-%%% <p>The function will return when a prompt is received, even if no
-%%% pattern has yet been matched. In this event,
-%%% <code>{error,{prompt,Prompt}}</code> is returned.
-%%% However, this behaviour may be modified with the
-%%% <code>ignore_prompt</code> or <code>no_prompt_check</code> option, which
-%%% tells <code>expect</code> to return only when a match is found or after a
-%%% timeout.</p>
-%%%
-%%% <p>If the <code>ignore_prompt</code> option is used,
-%%% <code>ct_telnet</code> will ignore any prompt found. This option
-%%% is useful if data sent by the server could include a pattern that
-%%% would match the prompt regexp (as returned by
-%%% <code>TargedMod:get_prompt_regexp/0</code>), but which should not
-%%% cause the function to return.</p>
-%%%
-%%% <p>If the <code>no_prompt_check</code> option is used,
-%%% <code>ct_telnet</code> will not search for a prompt at all. This
-%%% is useful if, for instance, the <code>Pattern</code> itself
-%%% matches the prompt.</p>
-%%%
-%%% <p>The <code>wait_for_prompt</code> option forces <code>ct_telnet</code>
-%%% to wait until the prompt string has been received before returning
-%%% (even if a pattern has already been matched). This is equal to calling:
-%%% <code>expect(Conn, Patterns++[{prompt,Prompt}], [sequence|Opts])</code>.
-%%% Note that <code>idle_timeout</code> and <code>total_timeout</code>
-%%% may abort the operation of waiting for prompt.</p>
-%%%
-%%% <p>The <code>repeat</code> option indicates that the pattern(s)
-%%% shall be matched multiple times. If <code>N</code> is given, the
-%%% pattern(s) will be matched <code>N</code> times, and the function
-%%% will return with <code>HaltReason = done</code>.</p>
-%%%
-%%% <p>The <code>sequence</code> option indicates that all patterns
-%%% shall be matched in a sequence. A match will not be concluded
-%%% untill all patterns are matched.</p>
-%%%
-%%% <p>Both <code>repeat</code> and <code>sequence</code> can be
-%%% interrupted by one or more <code>HaltPatterns</code>. When
-%%% <code>sequence</code> or <code>repeat</code> is used, there will
-%%% always be a <code>MatchList</code> returned, i.e. a list of
-%%% <code>Match</code> instead of only one <code>Match</code>. There
-%%% will also be a <code>HaltReason</code> returned.</p>
-%%%
-%%% <p><underline>Examples:</underline><br/>
-%%% <code>expect(Connection,[{abc,"ABC"},{xyz,"XYZ"}],</code>
-%%% <code>[sequence,{halt,[{nnn,"NNN"}]}]).</code><br/> will try to match
-%%% "ABC" first and then "XYZ", but if "NNN" appears the function will
-%%% return <code>{error,{nnn,["NNN"]}}</code>. If both "ABC" and "XYZ"
-%%% are matched, the function will return
-%%% <code>{ok,[AbcMatch,XyzMatch]}</code>.</p>
-%%%
-%%% <p><code>expect(Connection,[{abc,"ABC"},{xyz,"XYZ"}],</code>
-%%% <code>[{repeat,2},{halt,[{nnn,"NNN"}]}]).</code><br/> will try to match
-%%% "ABC" or "XYZ" twice. If "NNN" appears the function will return
-%%% with <code>HaltReason = {nnn,["NNN"]}</code>.</p>
-%%%
-%%% <p>The <code>repeat</code> and <code>sequence</code> options can be
-%%% combined in order to match a sequence multiple times.</p>
expect(Connection,Patterns,Opts) ->
case get_handle(Connection) of
- {ok,Pid} ->
- call(Pid,{expect,Patterns,Opts});
- Error ->
- Error
+ {ok,Pid} ->
+ case call(Pid,{expect,Patterns,Opts}) of
+ {error,Reason} when element(1,Reason)==bad_pattern ->
+ %% Faulty user input - should fail the test case
+ exit({Reason,{?MODULE,?FUNCTION_NAME,3}});
+ Other ->
+ Other
+ end;
+ Error ->
+ Error
end.
%%%=================================================================
%%% Callback functions
-%% @hidden
+
init(Name,{Ip,Port,Type},{TargetMod,KeepAlive,Extra}) ->
S0 = case ct:get_config(telnet_settings) of
undefined ->
@@ -677,7 +315,6 @@ set_telnet_defaults([Unknown|Ss],S) ->
set_telnet_defaults([],S) ->
S.
-%% @hidden
handle_msg({cmd,Cmd,Opts},State) ->
start_gen_log(heading(cmd,State#state.name)),
log(State,cmd,"Cmd: ~tp",[Cmd]),
@@ -803,7 +440,6 @@ handle_msg({expect,Pattern,Opts},State) ->
{Return1,State#state{buffer=NewBuffer,prompt=Prompt}}.
-%% @hidden
reconnect({Ip,Port,_Type},State) ->
reconnect(Ip,Port,State#state.reconns,State).
reconnect(Ip,Port,N,State=#state{name=Name,
@@ -834,7 +470,6 @@ reconnect(Ip,Port,N,State=#state{name=Name,
end.
-%% @hidden
terminate(TelnPid,State) ->
Result = ct_telnet_client:close(TelnPid),
log(State,close,"Telnet connection for ~w closed.",[TelnPid]),
@@ -902,7 +537,6 @@ force_log(State,Action,String,Args) ->
log(State,Action,String,Args,true).
%%%-----------------------------------------------------------------
-%%% @hidden
log(State,Action,String,Args) when is_record(State, state) ->
log(State,Action,String,Args,false);
log(Name,Action,String,Args) when is_atom(Name) ->
@@ -911,7 +545,6 @@ log(TelnPid,Action,String,Args) when is_pid(TelnPid) ->
log(#state{teln_pid=TelnPid},Action,String,Args,false).
%%%-----------------------------------------------------------------
-%%% @hidden
log(undefined,String,Args) ->
log(#state{},undefined,String,Args,false);
log(Name,String,Args) when is_atom(Name) ->
@@ -920,7 +553,6 @@ log(TelnPid,String,Args) when is_pid(TelnPid) ->
log(#state{teln_pid=TelnPid},undefined,String,Args).
%%%-----------------------------------------------------------------
-%%% @hidden
log(#state{name=Name,teln_pid=TelnPid,host=Host,port=Port},
Action,String,Args,ForcePrint) ->
Name1 = if Name == undefined -> get({ct_telnet_pid2name,TelnPid});
@@ -971,7 +603,6 @@ log(#state{name=Name,teln_pid=TelnPid,host=Host,port=Port},
end.
%%%-----------------------------------------------------------------
-%%% @hidden
start_gen_log(Heading) ->
%% check if output is suppressed
case ct_util:is_silenced(telnet) of
@@ -980,7 +611,6 @@ start_gen_log(Heading) ->
end.
%%%-----------------------------------------------------------------
-%%% @hidden
end_gen_log() ->
%% check if output is suppressed
case ct_util:is_silenced(telnet) of
@@ -988,7 +618,6 @@ end_gen_log() ->
false -> ct_gen_conn:end_log()
end.
-%%% @hidden
%% Debug printouts.
debug_cont_gen_log(Str,Args) ->
Old = put(silent,true),
@@ -1038,8 +667,7 @@ teln_get_all_data(State=#state{teln_pid=Pid,prx=Prx},Data,Acc,LastLine,Polls) ->
found_prompt=false,
prompt_check=true}).
-%% @hidden
-%% @doc Externally the silent_teln_expect function shall only be used
+%% Externally the silent_teln_expect function shall only be used
%% by the TargetModule, i.e. the target specific module which
%% implements connect/2 and get_prompt_regexp/0.
silent_teln_expect(Name,Pid,Data,Pattern,Prx,Opts) ->
@@ -1057,64 +685,72 @@ silent_teln_expect(Name,Pid,Data,Pattern,Prx,Opts) ->
%% 2) Sequence: Several patterns are given, and they are matched in
%% the order they appear in the pattern list.
%% 3a) Repeat (single): 1) is repeated either N times or until a halt
-%% condition is fullfilled.
+%% condition is fulfilled.
%% 3b) Repeat (sequence): 2) is repeated either N times or until a
-%% halt condition is fullfilled.
+%% halt condition is fulfilled.
teln_expect(Name,Pid,Data,Pattern0,Prx,Opts) ->
- HaltPatterns =
+ HaltPatterns0 =
case get_ignore_prompt(Opts) of
true ->
get_haltpatterns(Opts);
false ->
[prompt | get_haltpatterns(Opts)]
end,
-
- PromptCheck = get_prompt_check(Opts),
-
- {WaitForPrompt,Pattern1,Opts1} = wait_for_prompt(Pattern0,Opts),
-
- Seq = get_seq(Opts1),
- Pattern2 = convert_pattern(Pattern1,Seq),
- {IdleTimeout,TotalTimeout} = get_timeouts(Opts1),
-
- EO = #eo{teln_pid=Pid,
- prx=Prx,
- idle_timeout=IdleTimeout,
- total_timeout=TotalTimeout,
- seq=Seq,
- haltpatterns=HaltPatterns,
- prompt_check=PromptCheck},
+ case convert_pattern(HaltPatterns0,false) of
+ {ok,HaltPatterns} ->
+ {WaitForPrompt,Pattern1,Opts1} = wait_for_prompt(Pattern0,Opts),
+ Seq = get_seq(Opts1),
+ case convert_pattern(Pattern1,Seq) of
+ {ok,Pattern2} ->
+ {IdleTimeout,TotalTimeout} = get_timeouts(Opts1),
+ PromptCheck = get_prompt_check(Opts1),
+
+ EO = #eo{teln_pid=Pid,
+ prx=Prx,
+ idle_timeout=IdleTimeout,
+ total_timeout=TotalTimeout,
+ seq=Seq,
+ haltpatterns=HaltPatterns,
+ prompt_check=PromptCheck},
- case get_repeat(Opts1) of
- false ->
- case teln_expect1(Name,Pid,Data,Pattern2,[],EO) of
- {ok,Matched,Rest} when WaitForPrompt ->
- case lists:reverse(Matched) of
- [{prompt,_},Matched1] ->
- {ok,Matched1,Rest};
- [{prompt,_}|Matched1] ->
- {ok,lists:reverse(Matched1),Rest}
- end;
- {ok,Matched,Rest} ->
- {ok,Matched,Rest};
- {halt,Why,Rest} ->
- {error,Why,Rest};
- {error,Reason} ->
- {error,Reason}
- end;
- N ->
- EO1 = EO#eo{repeat=N},
- repeat_expect(Name,Pid,Data,Pattern2,[],EO1)
+ case get_repeat(Opts1) of
+ false ->
+ case teln_expect1(Name,Pid,Data,Pattern2,[],EO) of
+ {ok,Matched,Rest} when WaitForPrompt ->
+ case lists:reverse(Matched) of
+ [{prompt,_},Matched1] ->
+ {ok,Matched1,Rest};
+ [{prompt,_}|Matched1] ->
+ {ok,lists:reverse(Matched1),Rest}
+ end;
+ {ok,Matched,Rest} ->
+ {ok,Matched,Rest};
+ {halt,Why,Rest} ->
+ {error,Why,Rest};
+ {error,Reason} ->
+ {error,Reason}
+ end;
+ N ->
+ EO1 = EO#eo{repeat=N},
+ repeat_expect(Name,Pid,Data,Pattern2,[],EO1)
+ end;
+ Error ->
+ Error
+ end;
+ Error ->
+ Error
end.
-convert_pattern(Pattern,Seq)
- when is_list(Pattern) and not is_integer(hd(Pattern)) ->
- case Seq of
- true -> Pattern;
- false -> rm_dupl(Pattern,[])
- end;
+convert_pattern(Pattern0,Seq)
+ when Pattern0==[] orelse (is_list(Pattern0) and not is_integer(hd(Pattern0))) ->
+ Pattern =
+ case Seq of
+ true -> Pattern0;
+ false -> rm_dupl(Pattern0,[])
+ end,
+ compile_pattern(Pattern,[]);
convert_pattern(Pattern,_Seq) ->
- [Pattern].
+ compile_pattern([Pattern],[]).
rm_dupl([P|Ps],Acc) ->
case lists:member(P,Acc) of
@@ -1126,6 +762,25 @@ rm_dupl([P|Ps],Acc) ->
rm_dupl([],Acc) ->
lists:reverse(Acc).
+compile_pattern([prompt|Patterns],Acc) ->
+ compile_pattern(Patterns,[prompt|Acc]);
+compile_pattern([{prompt,_}=P|Patterns],Acc) ->
+ compile_pattern(Patterns,[P|Acc]);
+compile_pattern([{Tag,Pattern}|Patterns],Acc) ->
+ try re:compile(Pattern,[unicode]) of
+ {ok,MP} -> compile_pattern(Patterns,[{Tag,MP}|Acc]);
+ {error,Error} -> {error,{bad_pattern,{Tag,Pattern},Error}}
+ catch error:badarg -> {error,{bad_pattern,{Tag,Pattern}}}
+ end;
+compile_pattern([Pattern|Patterns],Acc) ->
+ try re:compile(Pattern,[unicode]) of
+ {ok,MP} -> compile_pattern(Patterns,[MP|Acc]);
+ {error,Error} -> {error,{bad_pattern,Pattern,Error}}
+ catch error:badarg -> {error,{bad_pattern,Pattern}}
+ end;
+compile_pattern([],Acc) ->
+ {ok,lists:reverse(Acc)}.
+
get_timeouts(Opts) ->
{case lists:keysearch(idle_timeout,1,Opts) of
{value,{_,T}} ->
@@ -1159,7 +814,7 @@ get_seq(Opts) ->
get_haltpatterns(Opts) ->
case lists:keysearch(halt,1,Opts) of
{value,{halt,HaltPatterns}} ->
- convert_pattern(HaltPatterns,false);
+ HaltPatterns;
false ->
[]
end.
@@ -1203,7 +858,7 @@ wait_for_prompt2(Prompt, Pattern, Opts) ->
{true,Pattern1,Opts1}.
%% Repeat either single or sequence. All match results are accumulated
-%% and returned when a halt condition is fulllfilled.
+%% and returned when a halt condition is fulfilled.
repeat_expect(_Name,_Pid,Rest,_Pattern,Acc,#eo{repeat=0}) ->
{ok,lists:reverse(Acc),done,Rest};
repeat_expect(Name,Pid,Data,Pattern,Acc,EO) ->
@@ -1342,7 +997,7 @@ one_expect1(Name,Pid,Data,Pattern,Rest,EO) ->
%% 2) Sequence.
%% First the whole data chunk is searched for a prompt (to avoid doing
%% a regexp match for the prompt at each line).
-%% If we are searching for anyting else, the datachunk is split into
+%% If we are searching for anything else, the datachunk is split into
%% lines and each line is matched against the first pattern in the list.
%% When a match is found, the match result is accumulated, and we keep
%% searching for the next pattern in the list.
@@ -1455,7 +1110,7 @@ match_line(Name,Pid,Line,[{prompt,PromptType}|Patterns],FoundPrompt,Term,
when PromptType=/=FoundPrompt ->
match_line(Name,Pid,Line,Patterns,FoundPrompt,Term,EO,RetTag);
match_line(Name,Pid,Line,[{Tag,Pattern}|Patterns],FoundPrompt,Term,EO,RetTag) ->
- case re:run(Line,Pattern,[{capture,all,list},unicode]) of
+ case re:run(Line,Pattern,[{capture,all,list}]) of
nomatch ->
match_line(Name,Pid,Line,Patterns,FoundPrompt,Term,EO,RetTag);
{match,Match} ->
@@ -1463,7 +1118,7 @@ match_line(Name,Pid,Line,[{Tag,Pattern}|Patterns],FoundPrompt,Term,EO,RetTag) ->
{RetTag,{Tag,Match}}
end;
match_line(Name,Pid,Line,[Pattern|Patterns],FoundPrompt,Term,EO,RetTag) ->
- case re:run(Line,Pattern,[{capture,all,list},unicode]) of
+ case re:run(Line,Pattern,[{capture,all,list}]) of
nomatch ->
match_line(Name,Pid,Line,Patterns,FoundPrompt,Term,EO,RetTag);
{match,Match} ->
@@ -1472,7 +1127,7 @@ match_line(Name,Pid,Line,[Pattern|Patterns],FoundPrompt,Term,EO,RetTag) ->
end;
match_line(Name,Pid,Line,[],FoundPrompt,Term,EO,match) ->
match_line(Name,Pid,Line,EO#eo.haltpatterns,FoundPrompt,Term,EO,halt);
-%% print any terminated line that can not be matched
+%% print any terminated line that cannot be matched
match_line(Name,Pid,Line,[],_FoundPrompt,true,_EO,halt) ->
log(name_or_pid(Name,Pid)," ~ts",[Line]),
nomatch;
@@ -1530,8 +1185,6 @@ add_tabs([],[$\n|Acc],LastLine) ->
add_tabs([],[],LastLine) ->
{[],lists:reverse(LastLine)}.
-
-%%% @hidden
teln_receive_until_prompt(Pid,Prx,Timeout) ->
Fun = fun() -> teln_receive_until_prompt(Pid,Prx,[],[]) end,
ct_gen_conn:do_within_time(Fun, Timeout).
diff --git a/lib/common_test/src/ct_telnet_client.erl b/lib/common_test/src/ct_telnet_client.erl
index 76e4b9ea70..007477c855 100644
--- a/lib/common_test/src/ct_telnet_client.erl
+++ b/lib/common_test/src/ct_telnet_client.erl
@@ -101,9 +101,11 @@ close(Pid) ->
end.
send_data(Pid, Data) ->
- send_data(Pid, Data, true).
+ send_data(Pid, Data, "\n").
send_data(Pid, Data, true) ->
- send_data(Pid, Data++"\n", false);
+ send_data(Pid, Data, "\n");
+send_data(Pid, Data, Newline) when is_list(Newline) ->
+ send_data(Pid, Data++Newline, false);
send_data(Pid, Data, false) ->
Pid ! {send_data, Data},
ok.
diff --git a/lib/common_test/src/ct_testspec.erl b/lib/common_test/src/ct_testspec.erl
index bd3755722f..2c18caf18f 100644
--- a/lib/common_test/src/ct_testspec.erl
+++ b/lib/common_test/src/ct_testspec.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,10 +18,6 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Framework functions handling test specifications.
-%%%
-%%% <p>This module exports functions that are used within CT to
-%%% scan and parse test specifikations.</p>
-module(ct_testspec).
-export([prepare_tests/1, prepare_tests/2,
diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl
index 468edc4bee..9f489e9bfb 100644
--- a/lib/common_test/src/ct_util.erl
+++ b/lib/common_test/src/ct_util.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,11 +18,11 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Framework Utilities.
+%%% Common Test Framework Utilities.
%%%
-%%% <p>This is a support module for the Common Test Framework. It
+%%% This is a support module for the Common Test Framework. It
%%% implements the process ct_util_server which acts like a data
-%%% holder for suite, configuration and connection data.</p>
+%%% holder for suite, configuration and connection data.
%%%
-module(ct_util).
@@ -83,20 +83,20 @@
%%%-----------------------------------------------------------------
start() ->
start(normal, ".", ?default_verbosity).
-%%% @spec start(Mode) -> Pid | exit(Error)
+%%% -spec start(Mode) -> Pid | exit(Error)
%%% Mode = normal | interactive
%%% Pid = pid()
%%%
-%%% @doc Start start the ct_util_server process
+%%% Start start the ct_util_server process
%%% (tool-internal use only).
%%%
-%%% <p>This function is called from ct_run.erl. It starts and initiates
-%%% the <code>ct_util_server</code></p>
+%%% This function is called from ct_run.erl. It starts and initiates
+%%% the ct_util_server
%%%
-%%% <p>Returns the process identity of the
-%%% <code>ct_util_server</code>.</p>
+%%% Returns the process identity of the
+%%% ct_util_server.
%%%
-%%% @see ct
+%%% See ct.
start(LogDir) when is_list(LogDir) ->
start(normal, LogDir, ?default_verbosity);
start(Mode) ->
@@ -192,7 +192,10 @@ do_start(Parent, Mode, LogDir, Verbosity) ->
ok
end,
- ct_default_gl:start_link(group_leader()),
+ case ct_default_gl:start_link(group_leader()) of
+ {ok, _} -> ok;
+ ignore -> ok
+ end,
{StartTime,TestLogDir} = ct_logs:init(Mode, Verbosity),
@@ -209,11 +212,10 @@ do_start(Parent, Mode, LogDir, Verbosity) ->
self() ! {{stop,{self(),{user_error,CTHReason}}},
{Parent,make_ref()}}
catch
- _:CTHReason ->
+ _:CTHReason:StackTrace ->
ErrorInfo = if is_atom(CTHReason) ->
io_lib:format("{~tp,~tp}",
- [CTHReason,
- erlang:get_stacktrace()]);
+ [CTHReason, StackTrace]);
true ->
CTHReason
end,
@@ -521,19 +523,19 @@ get_key_from_name(Name)->
ct_config:get_key_from_name(Name).
%%%-----------------------------------------------------------------
-%%% @spec register_connection(TargetName,Address,Callback,Handle) ->
+%%% -spec register_connection(TargetName,Address,Callback,Handle) ->
%%% ok | {error,Reason}
%%% TargetName = ct:target_name()
%%% Address = term()
%%% Callback = atom()
%%% Handle = term
%%%
-%%% @doc Register a new connection (tool-internal use only).
+%%% Register a new connection (tool-internal use only).
%%%
-%%% <p>This function can be called when a new connection is
+%%% This function can be called when a new connection is
%%% established. The connection data is stored in the connection
%%% table, and ct_util will close all registered connections when the
-%%% test is finished by calling <code>Callback:close/1</code>.</p>
+%%% test is finished by calling Callback:close/1.
register_connection(TargetName,Address,Callback,Handle) ->
%% If TargetName is a registered alias for a config
%% variable, use it as reference for the connection,
@@ -554,28 +556,28 @@ register_connection(TargetName,Address,Callback,Handle) ->
ok.
%%%-----------------------------------------------------------------
-%%% @spec unregister_connection(Handle) -> ok
+%%% -spec unregister_connection(Handle) -> ok
%%% Handle = term
%%%
-%%% @doc Unregister a connection (tool-internal use only).
+%%% Unregister a connection (tool-internal use only).
%%%
-%%% <p>This function should be called when a registered connection is
+%%% This function should be called when a registered connection is
%%% closed. It removes the connection data from the connection
-%%% table.</p>
+%%% table.
unregister_connection(Handle) ->
ets:delete(?conn_table,Handle),
ok.
%%%-----------------------------------------------------------------
-%%% @spec does_connection_exist(TargetName,Address,Callback) ->
+%%% -spec does_connection_exist(TargetName,Address,Callback) ->
%%% {ok,Handle} | false
%%% TargetName = ct:target_name()
%%% Address = address
%%% Callback = atom()
%%% Handle = term()
%%%
-%%% @doc Check if a connection already exists.
+%%% Check if a connection already exists.
does_connection_exist(TargetName,Address,Callback) ->
case ct_config:get_key_from_name(TargetName) of
{ok,_Key} ->
@@ -595,7 +597,7 @@ does_connection_exist(TargetName,Address,Callback) ->
end.
%%%-----------------------------------------------------------------
-%%% @spec get_connection(TargetName,Callback) ->
+%%% -spec get_connection(TargetName,Callback) ->
%%% {ok,Connection} | {error,Reason}
%%% TargetName = ct:target_name()
%%% Callback = atom()
@@ -603,8 +605,8 @@ does_connection_exist(TargetName,Address,Callback) ->
%%% Handle = term()
%%% Address = term()
%%%
-%%% @doc Return the connection for <code>Callback</code> on the
-%%% given target (<code>TargetName</code>).
+%%% Return the connection for Callback on the
+%%% given target (TargetName).
get_connection(TargetName,Callback) ->
%% check that TargetName is a registered alias
case ct_config:get_key_from_name(TargetName) of
@@ -625,7 +627,7 @@ get_connection(TargetName,Callback) ->
end.
%%%-----------------------------------------------------------------
-%%% @spec get_connections(ConnPid) ->
+%%% -spec get_connections(ConnPid) ->
%%% {ok,Connections} | {error,Reason}
%%% Connections = [Connection]
%%% Connection = {TargetName,Handle,Callback,Address}
@@ -634,8 +636,8 @@ get_connection(TargetName,Callback) ->
%%% Callback = atom()
%%% Address = term()
%%%
-%%% @doc Get data for all connections associated with a particular
-%%% connection pid (see Callback:init/3).
+%%% Get data for all connections associated with a particular
+%%% connection pid (see Callback:init/3).
get_connections(ConnPid) ->
Conns = ets:tab2list(?conn_table),
lists:flatmap(fun(#conn{targetref=TargetName,
@@ -655,8 +657,7 @@ get_connections(ConnPid) ->
end, Conns).
%%%-----------------------------------------------------------------
-%%% @hidden
-%%% @equiv ct:get_target_name/1
+%%% Equivalent to ct:get_target_name/1
get_target_name(Handle) ->
case ets:select(?conn_table,[{#conn{handle=Handle,targetref='$1',_='_'},
[],
@@ -668,17 +669,14 @@ get_target_name(Handle) ->
end.
%%%-----------------------------------------------------------------
-%%% @spec close_connections() -> ok
+%%% -spec close_connections() -> ok
%%%
-%%% @doc Close all open connections.
+%%% Close all open connections.
close_connections() ->
close_connections(ets:tab2list(?conn_table)),
ok.
%%%-----------------------------------------------------------------
-%%% @spec
-%%%
-%%% @doc
override_silence_all_connections() ->
Protocols = [telnet,ftp,rpc,snmp,ssh],
override_silence_connections(Protocols),
@@ -739,12 +737,12 @@ reset_silent_connections() ->
%%%-----------------------------------------------------------------
-%%% @spec stop(Info) -> ok
+%%% -spec stop(Info) -> ok
%%%
-%%% @doc Stop the ct_util_server and close all existing connections
+%%% Stop the ct_util_server and close all existing connections
%%% (tool-internal use only).
%%%
-%%% @see ct
+%%% See ct.
stop(Info) ->
case whereis(ct_util_server) of
undefined ->
@@ -758,26 +756,25 @@ stop(Info) ->
end.
%%%-----------------------------------------------------------------
-%%% @spec update_last_run_index() -> ok
+%%% -spec update_last_run_index() -> ok
%%%
-%%% @doc Update <code>ct_run.&lt;timestamp&gt;/index.html</code>
+%%% Update ct_run.<timestamp>/index.html
%%% (tool-internal use only).
update_last_run_index() ->
call(update_last_run_index).
%%%-----------------------------------------------------------------
-%%% @spec get_mode() -> Mode
+%%% -spec get_mode() -> Mode
%%% Mode = normal | interactive
%%%
-%%% @doc Return the current mode of the ct_util_server
+%%% Return the current mode of the ct_util_server
%%% (tool-internal use only).
get_mode() ->
call(get_mode).
%%%-----------------------------------------------------------------
-%%% @hidden
-%%% @equiv ct:listenv/1
+%%% Equivalent to ct:listenv/1
listenv(Telnet) ->
case ct_telnet:send(Telnet,"listenv") of
ok ->
@@ -791,33 +788,32 @@ listenv(Telnet) ->
end.
%%%-----------------------------------------------------------------
-%%% @hidden
-%%% @equiv ct:parse_table/1
+%%% Equivalent to ct:parse_table/1
parse_table(Data) ->
{Heading, Rest} = get_headings(Data),
Lines = parse_row(Rest,[],size(Heading)),
{Heading,Lines}.
get_headings(["|" ++ Headings | Rest]) ->
- {remove_space(string:tokens(Headings, "|"),[]), Rest};
+ {remove_space(string:lexemes(Headings, "|"),[]), Rest};
get_headings([_ | Rest]) ->
get_headings(Rest);
get_headings([]) ->
{{},[]}.
parse_row(["|" ++ _ = Row | T], Rows, NumCols) when NumCols > 1 ->
- case string:tokens(Row, "|") of
+ case string:lexemes(Row, "|") of
Values when length(Values) =:= NumCols ->
parse_row(T,[remove_space(Values,[])|Rows], NumCols);
Values when length(Values) < NumCols ->
parse_row([Row ++"\n"++ hd(T) | tl(T)], Rows, NumCols)
end;
-parse_row(["|" ++ _ = Row | T], Rows, 1 = NumCols) ->
- case string:rchr(Row, $|) of
- 1 ->
+parse_row(["|" ++ X = Row | T], Rows, 1 = NumCols) ->
+ case string:find(X, [$|]) of
+ nomatch ->
parse_row([Row ++"\n"++hd(T) | tl(T)], Rows, NumCols);
_Else ->
- parse_row(T, [remove_space(string:tokens(Row,"|"),[])|Rows],
+ parse_row(T, [remove_space(string:lexemes(Row,"|"),[])|Rows],
NumCols)
end;
parse_row([_Skip | T], Rows, NumCols) ->
@@ -826,22 +822,16 @@ parse_row([], Rows, _NumCols) ->
lists:reverse(Rows).
remove_space([Str|Rest],Acc) ->
- remove_space(Rest,[string:strip(string:strip(Str),both,$')|Acc]);
+ remove_space(Rest,[string:trim(string:trim(Str,both,[$\s]),both,[$'])|Acc]);
remove_space([],Acc) ->
list_to_tuple(lists:reverse(Acc)).
%%%-----------------------------------------------------------------
-%%% @spec
-%%%
-%%% @doc
is_test_dir(Dir) ->
- lists:last(string:tokens(filename:basename(Dir), "_")) == "test".
+ lists:last(string:lexemes(filename:basename(Dir), "_")) == "test".
%%%-----------------------------------------------------------------
-%%% @spec
-%%%
-%%% @doc
get_testdir(Dir, all) ->
Abs = abs_name(Dir),
case is_test_dir(Abs) of
@@ -885,9 +875,6 @@ get_testdir(Dir, _) ->
get_testdir(Dir, all).
%%%-----------------------------------------------------------------
-%%% @spec
-%%%
-%%% @doc
get_attached(TCPid) ->
case dbg_iserver:safe_call({get_attpid,TCPid}) of
{ok,AttPid} when is_pid(AttPid) ->
@@ -897,9 +884,6 @@ get_attached(TCPid) ->
end.
%%%-----------------------------------------------------------------
-%%% @spec
-%%%
-%%% @doc
kill_attached(undefined,_AttPid) ->
ok;
kill_attached(_TCPid,undefined) ->
@@ -914,9 +898,6 @@ kill_attached(TCPid,AttPid) ->
%%%-----------------------------------------------------------------
-%%% @spec
-%%%
-%%% @doc
warn_duplicates(Suites) ->
Warn =
fun(Mod) ->
@@ -935,9 +916,6 @@ warn_duplicates(Suites) ->
ok.
%%%-----------------------------------------------------------------
-%%% @spec
-%%%
-%%% @doc
mark_process() ->
mark_process(system).
@@ -999,9 +977,6 @@ remaining_test_procs() ->
{TestProcs, SharedGL, OtherGLs}.
%%%-----------------------------------------------------------------
-%%% @spec
-%%%
-%%% @doc
get_profile_data() ->
get_profile_data(all).
@@ -1145,7 +1120,7 @@ open_url(iexplore, Args, URL) ->
_ = case win32reg:values(R) of
{ok, Paths} ->
Path = proplists:get_value(default, Paths),
- [Cmd | _] = string:tokens(Path, "%"),
+ [Cmd | _] = string:lexemes(Path, "%"),
Cmd1 = Cmd ++ " " ++ Args ++ " " ++ URL,
io:format(?def_gl, "~nOpening ~ts with command:~n ~ts~n", [URL,Cmd1]),
open_port({spawn,Cmd1}, []);
diff --git a/lib/common_test/src/ct_util.hrl b/lib/common_test/src/ct_util.hrl
index 039c8168ec..d5c93d05ba 100644
--- a/lib/common_test/src/ct_util.hrl
+++ b/lib/common_test/src/ct_util.hrl
@@ -62,6 +62,7 @@
merge_tests=true}).
-record(cover, {app=none,
+ local_only=false,
level=details,
excl_mods=[],
incl_mods=[],
diff --git a/lib/common_test/src/ct_webtool.erl b/lib/common_test/src/ct_webtool.erl
index 82aa78fc4b..32d4255217 100644
--- a/lib/common_test/src/ct_webtool.erl
+++ b/lib/common_test/src/ct_webtool.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -771,7 +771,7 @@ fill_out(Nr)->
%Controls whether the user selected a tool to start
%----------------------------------------------------------------------
get_tools(Input)->
- case httpd:parse_query(Input) of
+ case uri_string:dissect_query(Input) of
[]->
no_tools;
Tools->
diff --git a/lib/common_test/src/ct_webtool_sup.erl b/lib/common_test/src/ct_webtool_sup.erl
index 6c6dbde0a6..04fbbf8745 100644
--- a/lib/common_test/src/ct_webtool_sup.erl
+++ b/lib/common_test/src/ct_webtool_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/src/cth_log_redirect.erl b/lib/common_test/src/cth_log_redirect.erl
index 77f90c0df6..fe869a4373 100644
--- a/lib/common_test/src/cth_log_redirect.erl
+++ b/lib/common_test/src/cth_log_redirect.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -19,11 +19,9 @@
%%
-module(cth_log_redirect).
-%%% @doc Common Test Framework functions handling test specifications.
+%%% Common Test Framework functions handling test specifications.
%%%
-%%% <p>This module redirects sasl and error logger info to common test log.</p>
-%%% @end
-
+%%% This module redirects sasl and error logger info to common test log.
%% CTH Callbacks
-export([id/1, init/2,
@@ -33,17 +31,19 @@
pre_init_per_testcase/4, post_init_per_testcase/5,
pre_end_per_testcase/4, post_end_per_testcase/5]).
-%% Event handler Callbacks
--export([init/1,
- handle_event/2, handle_call/2, handle_info/2,
- terminate/1, terminate/2, code_change/3]).
+%% Logger handler and gen_server callbacks
+-export([log/2,
+ init/1,
+ handle_cast/2, handle_call/3,
+ terminate/1, terminate/2]).
%% Other
-export([handle_remote_events/1]).
-include("ct.hrl").
+-include("../../kernel/src/logger_internal.hrl").
--behaviour(gen_event).
+-behaviour(gen_server).
-record(eh_state, {log_func,
curr_suite,
@@ -57,7 +57,7 @@ id(_Opts) ->
init(?MODULE, _Opts) ->
ct_util:mark_process(),
- error_logger:add_report_handler(?MODULE),
+ ok = start_log_handler(),
tc_log_async.
pre_init_per_suite(Suite, Config, State) ->
@@ -100,7 +100,7 @@ pre_end_per_testcase(_Suite, _TC, Config, State) ->
post_end_per_testcase(_Suite, _TC, _Config, Result, State) ->
%% Make sure that the event queue is flushed
%% before ending this test case.
- gen_event:call(error_logger, ?MODULE, flush, 300000),
+ gen_server:call(?MODULE, flush, 300000),
{Result, State}.
pre_end_per_group(_Suite, Group, Config, {tc_log, Group}) ->
@@ -114,164 +114,181 @@ post_end_per_group(_Suite, _Group, Config, Return, State) ->
set_curr_func({group,undefined}, Config),
{Return, State}.
-%% Copied and modified from sasl_report_tty_h.erl
-init(_Type) ->
- {ok, #eh_state{log_func = tc_log_async}}.
-
-handle_event({_Type,GL,_Msg}, #eh_state{handle_remote_events = false} = State)
- when node(GL) /= node() ->
- {ok, State};
-handle_event(Event, #eh_state{log_func = LogFunc} = State) ->
- case lists:keyfind(sasl, 1, application:which_applications()) of
- false ->
- sasl_not_started;
- _Else ->
- {ok, ErrLogType} = application:get_env(sasl, errlog_type),
- SReport = sasl_report:format_report(group_leader(), ErrLogType,
- tag_event(Event, local)),
- if is_list(SReport) ->
- SaslHeader = format_header(State),
- case LogFunc of
- tc_log ->
- ct_logs:tc_log(sasl, ?STD_IMPORTANCE,
- SaslHeader, SReport, [], []);
- tc_log_async ->
- ct_logs:tc_log_async(sasl, ?STD_IMPORTANCE,
- SaslHeader, SReport, [])
- end;
- true -> %% Report is an atom if no logging is to be done
- ignore
- end
- end,
- %% note that error_logger (unlike sasl) expects UTC time
- EReport = error_logger_tty_h:write_event(
- tag_event(Event, utc), io_lib),
- if is_list(EReport) ->
- ErrHeader = format_header(State),
- case LogFunc of
- tc_log ->
- ct_logs:tc_log(error_logger, ?STD_IMPORTANCE,
- ErrHeader, EReport, [], []);
- tc_log_async ->
- ct_logs:tc_log_async(error_logger, ?STD_IMPORTANCE,
- ErrHeader, EReport, [])
- end;
- true -> %% Report is an atom if no logging is to be done
- ignore
+start_log_handler() ->
+ case whereis(?MODULE) of
+ undefined ->
+ ChildSpec =
+ #{id=>?MODULE,
+ start=>{gen_server,start_link,[{local,?MODULE},?MODULE,[],[]]},
+ restart=>transient,
+ shutdown=>2000,
+ type=>worker,
+ modules=>[?MODULE]},
+ {ok,_} = supervisor:start_child(logger_sup,ChildSpec),
+ ok;
+ _Pid ->
+ ok
end,
- {ok, State}.
+ ok = logger:add_handler(?MODULE,?MODULE,
+ #{level=>info,
+ formatter=>{?DEFAULT_FORMATTER,
+ ?DEFAULT_FORMAT_CONFIG}}).
+
+init([]) ->
+ {ok, #eh_state{log_func = tc_log_async}}.
-handle_info({'EXIT',User,killed}, State) ->
- case whereis(user) of
- %% init:stop/1/2 has been called, let's finish!
+log(#{msg:={report,Msg},meta:=#{domain:=[otp,sasl]}}=Log,Config) ->
+ case whereis(sasl_sup) of
undefined ->
- remove_handler;
- User ->
- remove_handler;
- _ ->
- {ok,State}
+ ok; % sasl application is not started
+ _Else ->
+ Level =
+ case application:get_env(sasl, errlog_type) of
+ {ok,error} ->
+ error;
+ {ok,_} ->
+ info;
+ undefined ->
+ info
+ end,
+ case Level of
+ error ->
+ case Msg of
+ #{label:={_,progress}} ->
+ ok;
+ _ ->
+ do_log(add_log_category(Log,sasl),Config)
+ end;
+ _ ->
+ do_log(add_log_category(Log,sasl),Config)
+ end
end;
+log(#{meta:=#{domain:=[otp]}}=Log,Config) ->
+ do_log(add_log_category(Log,error_logger),Config);
+log(#{meta:=#{domain:=_}},_) ->
+ ok;
+log(Log,Config) ->
+ do_log(add_log_category(Log,error_logger),Config).
+
+add_log_category(#{meta:=Meta}=Log,Category) ->
+ Log#{meta=>Meta#{?MODULE=>#{category=>Category}}}.
+
+do_log(Log,Config) ->
+ gen_server:call(?MODULE,{log,Log,Config}).
-handle_info(_, State) ->
- {ok,State}.
+handle_cast(_, State) ->
+ {noreply,State}.
-handle_call(flush,State) ->
- {ok, ok, State};
+handle_call({log,#{meta:=#{gl:=GL}},_}, _From,
+ #eh_state{handle_remote_events=false}=State)
+ when node(GL) /= node() ->
+ {reply, ok, State};
+
+handle_call({log,
+ #{meta:=#{?MODULE:=#{category:=Category}}}=Log,
+ #{formatter:={Formatter,FConfig}}},
+ _From,
+ #eh_state{log_func=LogFunc}=State) ->
+ Header = format_header(State),
+ String = Formatter:format(Log,FConfig),
+ case LogFunc of
+ tc_log ->
+ ct_logs:tc_log(Category, ?STD_IMPORTANCE,
+ Header, "~ts", [String], []);
+ tc_log_async ->
+ ct_logs:tc_log_async(sasl, ?STD_IMPORTANCE,
+ Header, "~ts", [String])
+ end,
+ {reply,ok,State};
-handle_call({set_curr_func,{group,Group,Conf},Config},
- State) when is_list(Config) ->
+handle_call(flush,_From,State) ->
+ {reply, ok, State};
+
+handle_call({set_curr_func,{group,Group,Conf},Config},_From,State)
+ when is_list(Config) ->
Parallel = case proplists:get_value(tc_group_properties, Config) of
undefined -> false;
Props -> lists:member(parallel, Props)
end,
- {ok, ok, State#eh_state{curr_group = Group,
- curr_func = Conf,
- parallel_tcs = Parallel}};
-handle_call({set_curr_func,{group,Group,Conf},_SkipOrFail}, State) ->
- {ok, ok, State#eh_state{curr_group = Group,
- curr_func = Conf,
- parallel_tcs = false}};
-handle_call({set_curr_func,{group,undefined},_Config}, State) ->
- {ok, ok, State#eh_state{curr_group = undefined,
- curr_func = undefined,
- parallel_tcs = false}};
-handle_call({set_curr_func,{Suite,Conf},_Config}, State) ->
- {ok, ok, State#eh_state{curr_suite = Suite,
- curr_func = Conf,
- parallel_tcs = false}};
-handle_call({set_curr_func,undefined,_Config}, State) ->
- {ok, ok, State#eh_state{curr_suite = undefined,
- curr_func = undefined,
- parallel_tcs = false}};
-handle_call({set_curr_func,TC,_Config}, State) ->
- {ok, ok, State#eh_state{curr_func = TC}};
-
-handle_call({set_logfunc,NewLogFunc}, State) ->
- {ok, NewLogFunc, State#eh_state{log_func = NewLogFunc}};
-
-handle_call({handle_remote_events,Bool}, State) ->
- {ok, ok, State#eh_state{handle_remote_events = Bool}};
-
-handle_call(_Query, _State) ->
- {error, bad_query}.
+ {reply, ok, State#eh_state{curr_group = Group,
+ curr_func = Conf,
+ parallel_tcs = Parallel}};
+handle_call({set_curr_func,{group,Group,Conf},_SkipOrFail}, _From, State) ->
+ {reply, ok, State#eh_state{curr_group = Group,
+ curr_func = Conf,
+ parallel_tcs = false}};
+handle_call({set_curr_func,{group,undefined},_Config}, _From, State) ->
+ {reply, ok, State#eh_state{curr_group = undefined,
+ curr_func = undefined,
+ parallel_tcs = false}};
+handle_call({set_curr_func,{Suite,Conf},_Config}, _From, State) ->
+ {reply, ok, State#eh_state{curr_suite = Suite,
+ curr_func = Conf,
+ parallel_tcs = false}};
+handle_call({set_curr_func,undefined,_Config}, _From, State) ->
+ {reply, ok, State#eh_state{curr_suite = undefined,
+ curr_func = undefined,
+ parallel_tcs = false}};
+handle_call({set_curr_func,TC,_Config}, _From, State) ->
+ {reply, ok, State#eh_state{curr_func = TC}};
+
+handle_call({set_logfunc,NewLogFunc}, _From, State) ->
+ {reply, NewLogFunc, State#eh_state{log_func = NewLogFunc}};
+
+handle_call({handle_remote_events,Bool}, _From, State) ->
+ {reply, ok, State#eh_state{handle_remote_events = Bool}}.
terminate(_) ->
- error_logger:delete_report_handler(?MODULE),
- [].
+ _ = logger:remove_handler(?MODULE),
+ _ = supervisor:terminate_child(logger_sup,?MODULE),
+ _ = supervisor:delete_child(logger_sup,?MODULE),
+ ok.
terminate(_Arg, _State) ->
ok.
-tag_event(Event, utc) ->
- {calendar:universal_time(), Event};
-tag_event(Event, _) ->
- {calendar:local_time(), Event}.
-
set_curr_func(CurrFunc, Config) ->
- gen_event:call(error_logger, ?MODULE, {set_curr_func, CurrFunc, Config}).
+ gen_server:call(?MODULE, {set_curr_func, CurrFunc, Config}).
set_log_func(Func) ->
- gen_event:call(error_logger, ?MODULE, {set_logfunc, Func}).
+ gen_server:call(?MODULE, {set_logfunc, Func}).
handle_remote_events(Bool) ->
- gen_event:call(error_logger, ?MODULE, {handle_remote_events, Bool}).
+ gen_server:call(?MODULE, {handle_remote_events, Bool}).
%%%-----------------------------------------------------------------
format_header(#eh_state{curr_suite = undefined,
curr_group = undefined,
curr_func = undefined}) ->
- io_lib:format("System report", []);
+ lists:flatten(io_lib:format("System report", []));
format_header(#eh_state{curr_suite = Suite,
curr_group = undefined,
curr_func = undefined}) ->
- io_lib:format("System report during ~w", [Suite]);
+ lists:flatten(io_lib:format("System report during ~w", [Suite]));
format_header(#eh_state{curr_suite = Suite,
curr_group = undefined,
curr_func = TcOrConf}) ->
- io_lib:format("System report during ~w:~tw/1",
- [Suite,TcOrConf]);
+ lists:flatten(io_lib:format("System report during ~w:~tw/1",
+ [Suite,TcOrConf]));
format_header(#eh_state{curr_suite = Suite,
curr_group = Group,
curr_func = Conf}) when Conf == init_per_group;
Conf == end_per_group ->
- io_lib:format("System report during ~w:~w/2 for ~tw",
- [Suite,Conf,Group]);
+ lists:flatten(io_lib:format("System report during ~w:~w/2 for ~tw",
+ [Suite,Conf,Group]));
format_header(#eh_state{curr_suite = Suite,
curr_group = Group,
parallel_tcs = true}) ->
- io_lib:format("System report during ~tw in ~w",
- [Group,Suite]);
+ lists:flatten(io_lib:format("System report during ~tw in ~w",
+ [Group,Suite]));
format_header(#eh_state{curr_suite = Suite,
curr_group = Group,
curr_func = TC}) ->
- io_lib:format("System report during ~w:~tw/1 in ~tw",
- [Suite,TC,Group]).
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
+ lists:flatten(io_lib:format("System report during ~w:~tw/1 in ~tw",
+ [Suite,TC,Group])).
diff --git a/lib/common_test/src/cth_surefire.erl b/lib/common_test/src/cth_surefire.erl
index da68bd105e..c9b4cb10c6 100644
--- a/lib/common_test/src/cth_surefire.erl
+++ b/lib/common_test/src/cth_surefire.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,10 +18,10 @@
%% %CopyrightEnd%
%%--------------------------------------------------------------------
-%%% @doc Common Test Framework functions handling test specifications.
+%%% Common Test Framework functions handling test specifications.
%%%
-%%% <p>This module creates a junit report of the test run if plugged in
-%%% as a suite_callback.</p>
+%%% This module creates a junit report of the test run if plugged in
+%%% as a suite_callback.
-module(cth_surefire).
@@ -184,15 +184,14 @@ end_tc(Name, _Config, _Res, State = #state{ curr_suite = Suite,
Log =
case Log0 of
"" ->
- LowerSuiteName = string:to_lower(atom_to_list(Suite)),
+ LowerSuiteName = string:lowercase(atom_to_list(Suite)),
filename:join(CurrLogDir,LowerSuiteName++"."++Name++".html");
_ ->
Log0
end,
Url = make_url(UrlBase,Log),
ClassName = atom_to_list(Suite),
- PGroup = string:join([ atom_to_list(Group)||
- Group <- lists:reverse(Groups)],"."),
+ PGroup = lists:concat(lists:join(".",lists:reverse(Groups))),
TimeTakes = io_lib:format("~f",[timer:now_diff(?now,TS) / 1000000]),
State#state{ test_cases = [#testcase{ log = Log,
url = Url,
@@ -236,7 +235,7 @@ close_suite(#state{ test_cases = TCs, url_base = UrlBase } = State) ->
terminate(State = #state{ test_cases = [] }) ->
{ok,D} = file:open(State#state.filepath,[write,{encoding,utf8}]),
io:format(D, "<?xml version=\"1.0\" encoding= \"UTF-8\" ?>", []),
- io:format(D, to_xml(State), []),
+ io:format(D, "~ts", [to_xml(State)]),
catch file:sync(D),
catch file:close(D);
terminate(State) ->
@@ -317,9 +316,9 @@ make_url(undefined,_) ->
make_url(_,[]) ->
undefined;
make_url(UrlBase0,Log) ->
- UrlBase = string:strip(UrlBase0,right,$/),
+ UrlBase = string:trim(UrlBase0,trailing,[$/]),
RelativeLog = get_relative_log_url(Log),
- string:join([UrlBase,RelativeLog],"/").
+ lists:flatten(lists:join($/,[UrlBase,RelativeLog])).
get_test_root(Log) ->
LogParts = filename:split(Log),
@@ -329,7 +328,7 @@ get_relative_log_url(Log) ->
LogParts = filename:split(Log),
Start = length(LogParts)-?log_depth,
Length = ?log_depth+1,
- string:join(lists:sublist(LogParts,Start,Length),"/").
+ lists:flatten(lists:join($/,lists:sublist(LogParts,Start,Length))).
count_tcs([#testcase{name=ConfCase}|TCs],Ok,F,S)
when ConfCase=="init_per_suite";
diff --git a/lib/common_test/src/test_server.erl b/lib/common_test/src/test_server.erl
index e56106408f..756cd4d692 100644
--- a/lib/common_test/src/test_server.erl
+++ b/lib/common_test/src/test_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -384,8 +384,8 @@ run_test_case_apply({CaseNum,Mod,Func,Args,Name,RunInit,TimetrapData}) ->
{Result,DetFail,ProcBef,ProcAft}.
-type tc_status() :: 'starting' | 'running' | 'init_per_testcase' |
- 'end_per_testcase' | {'framework',atom(),atom()} |
- 'tc'.
+ 'end_per_testcase' | {'framework',{atom(),atom(),list}} |
+ 'tc'.
-record(st,
{
ref :: reference(),
@@ -463,11 +463,12 @@ run_test_case_msgloop(#st{ref=Ref,pid=Pid,end_conf_pid=EndConfPid0}=St0) ->
%% it as a comment, potentially replacing user data
Error = lists:flatten(io_lib:format("Aborted: ~tp",
[Reason])),
- Error1 = lists:flatten([string:strip(S,left) ||
- S <- string:tokens(Error,
- [$\n])]),
- Comment = if length(Error1) > 63 ->
- string:substr(Error1,1,60) ++ "...";
+ Error1 = lists:flatten([string:trim(S,leading,"\s") ||
+ S <- string:lexemes(Error,
+ [$\n])]),
+ ErrorLength = string:length(Error1),
+ Comment = if ErrorLength > 63 ->
+ string:slice(Error1,0,60) ++ "...";
true ->
Error1
end,
@@ -652,8 +653,8 @@ handle_tc_exit({testcase_aborted,{user_timetrap_error,_}=Msg,_}, St) ->
#st{config=Config,mf={Mod,Func},pid=Pid} = St,
spawn_fw_call(Mod, Func, Config, Pid, Msg, unknown, self()),
St;
-handle_tc_exit(Reason, #st{status={framework,FwMod,FwFunc},
- config=Config,pid=Pid}=St) ->
+handle_tc_exit(Reason, #st{status={framework,{FwMod,FwFunc,_}=FwMFA},
+ config=Config,mf={Mod,Func},pid=Pid}=St) ->
R = case Reason of
{timetrap_timeout,TVal,_} ->
{timetrap,TVal};
@@ -665,7 +666,7 @@ handle_tc_exit(Reason, #st{status={framework,FwMod,FwFunc},
Other
end,
Error = {framework_error,R},
- spawn_fw_call(FwMod, FwFunc, Config, Pid, Error, unknown, self()),
+ spawn_fw_call(Mod, Func, Config, Pid, {Error,FwMFA}, unknown, self()),
St;
handle_tc_exit(Reason, #st{status=tc,config=Config0,mf={Mod,Func},pid=Pid}=St)
when is_list(Config0) ->
@@ -849,36 +850,68 @@ spawn_fw_call(Mod,EPTC={end_per_testcase,Func},EndConf,Pid,
"WARNING: end_per_testcase failed!</font>",
{died,W}
end,
- try do_end_tc_call(Mod,EPTC,{Pid,Report,[EndConf]}, Why) of
- _ -> ok
- catch
- _:FwEndTCErr ->
- exit({fw_notify_done,end_tc,FwEndTCErr})
- end,
- FailLoc = proplists:get_value(tc_fail_loc, EndConf),
+ FailLoc0 = proplists:get_value(tc_fail_loc, EndConf),
+ {RetVal1,FailLoc} =
+ try do_end_tc_call(Mod,EPTC,{Pid,Report,[EndConf]}, Why) of
+ Why ->
+ {RetVal,FailLoc0};
+ {failed,_} = R ->
+ {R,[{Mod,Func}]};
+ R ->
+ {R,FailLoc0}
+ catch
+ _:FwEndTCErr ->
+ exit({fw_notify_done,end_tc,FwEndTCErr})
+ end,
%% finished, report back (if end_per_testcase fails, a warning
%% should be printed as part of the comment)
SendTo ! {self(),fw_notify_done,
- {Time,RetVal,FailLoc,[],Warn}}
+ {Time,RetVal1,FailLoc,[],Warn}}
end,
spawn_link(FwCall);
-spawn_fw_call(FwMod,FwFunc,_,_Pid,{framework_error,FwError},_,SendTo) ->
+spawn_fw_call(Mod,Func,Conf,Pid,{{framework_error,FwError},
+ {FwMod,FwFunc,[A1,A2|_]}=FwMFA},_,SendTo) ->
FwCall =
fun() ->
ct_util:mark_process(),
- test_server_sup:framework_call(report, [framework_error,
- {{FwMod,FwFunc},
- FwError}]),
+ Time =
+ case FwError of
+ {timetrap,TVal} ->
+ TVal/1000;
+ _ ->
+ died
+ end,
+ {Ret,Loc,WarnOrError} =
+ cleanup_after_fw_error(Mod,Func,Conf,Pid,FwError,FwMFA),
Comment =
- lists:flatten(
- io_lib:format("<font color=\"red\">"
- "WARNING! ~w:~tw failed!</font>",
- [FwMod,FwFunc])),
+ case WarnOrError of
+ warn ->
+ group_leader() !
+ {printout,12,
+ "WARNING! ~w:~tw(~w,~tw,...) failed!\n"
+ " Reason: ~tp\n",
+ [FwMod,FwFunc,A1,A2,FwError]},
+ lists:flatten(
+ io_lib:format("<font color=\"red\">"
+ "WARNING! ~w:~tw(~w,~tw,...) "
+ "failed!</font>",
+ [FwMod,FwFunc,A1,A2]));
+ error ->
+ group_leader() !
+ {printout,12,
+ "Error! ~w:~tw(~w,~tw,...) failed!\n"
+ " Reason: ~tp\n",
+ [FwMod,FwFunc,A1,A2,FwError]},
+ lists:flatten(
+ io_lib:format("<font color=\"red\">"
+ "ERROR! ~w:~tw(~w,~tw,...) "
+ "failed!</font>",
+ [FwMod,FwFunc,A1,A2]))
+ end,
%% finished, report back
SendTo ! {self(),fw_notify_done,
- {died,{error,{FwMod,FwFunc,FwError}},
- {FwMod,FwFunc},[],Comment}}
+ {Time,Ret,Loc,[],Comment}}
end,
spawn_link(FwCall);
@@ -901,17 +934,185 @@ spawn_fw_call(Mod,Func,CurrConf,Pid,Error,Loc,SendTo) ->
FwErrorNotifyErr})
end,
Conf = [{tc_status,{failed,Error}}|CurrConf],
- try do_end_tc_call(Mod,EndTCFunc,{Pid,Error,[Conf]},Error) of
- _ -> ok
- catch
- _:FwEndTCErr ->
- exit({fw_notify_done,end_tc,FwEndTCErr})
- end,
+ {Time,RetVal,Loc1} =
+ try do_end_tc_call(Mod,EndTCFunc,{Pid,Error,[Conf]},Error) of
+ Error ->
+ {died, Error, Loc};
+ {failed,Reason} = NewReturn ->
+ fw_error_notify(Mod,Func1,Conf,Reason),
+ {died, NewReturn, [{Mod,Func}]};
+ NewReturn ->
+ T = case Error of
+ {timetrap_timeout,TT} -> TT;
+ _ -> 0
+ end,
+ {T, NewReturn, Loc}
+ catch
+ _:FwEndTCErr ->
+ exit({fw_notify_done,end_tc,FwEndTCErr})
+ end,
%% finished, report back
- SendTo ! {self(),fw_notify_done,{died,Error,Loc,[],undefined}}
+ SendTo ! {self(),fw_notify_done,{Time,RetVal,Loc1,[],undefined}}
end,
spawn_link(FwCall).
+cleanup_after_fw_error(_Mod,_Func,Conf,Pid,FwError,
+ {FwMod,FwFunc=init_tc,
+ [Mod,{init_per_testcase,Func}=IPTC|_]}) ->
+ %% Failed during pre_init_per_testcase, the test must be skipped
+ Skip = {auto_skip,{failed,{FwMod,FwFunc,FwError}}},
+ try begin do_end_tc_call(Mod,IPTC, {Pid,Skip,[Conf]}, FwError),
+ do_init_tc_call(Mod,{end_per_testcase_not_run,Func},
+ [Conf],{ok,[Conf]}),
+ do_end_tc_call(Mod,{end_per_testcase_not_run,Func},
+ {Pid,Skip,[Conf]}, FwError) end of
+ _ -> ok
+ catch
+ _:FwEndTCErr ->
+ exit({fw_notify_done,end_tc,FwEndTCErr})
+ end,
+ {Skip,{FwMod,FwFunc},error};
+cleanup_after_fw_error(_Mod,_Func,Conf,Pid,FwError,
+ {FwMod,FwFunc=end_tc,[Mod,{init_per_testcase,Func}|_]}) ->
+ %% Failed during post_init_per_testcase, the test must be skipped
+ Skip = {auto_skip,{failed,{FwMod,FwFunc,FwError}}},
+ try begin do_init_tc_call(Mod,{end_per_testcase_not_run,Func},
+ [Conf],{ok,[Conf]}),
+ do_end_tc_call(Mod,{end_per_testcase_not_run,Func},
+ {Pid,Skip,[Conf]}, FwError) end of
+ _ -> ok
+ catch
+ _:FwEndTCErr ->
+ exit({fw_notify_done,end_tc,FwEndTCErr})
+ end,
+ {Skip,{FwMod,FwFunc},error};
+cleanup_after_fw_error(_Mod,_Func,Conf,Pid,FwError,
+ {FwMod,FwFunc=init_tc,[Mod,{end_per_testcase,Func}|_]}) ->
+ %% Failed during pre_end_per_testcase. Warn about it.
+ {RetVal,Loc} =
+ case {proplists:get_value(tc_status, Conf),
+ proplists:get_value(tc_fail_loc, Conf, unknown)} of
+ {undefined,_} ->
+ {{failed,{FwMod,FwFunc,FwError}},{FwMod,FwFunc}};
+ {E = {failed,_Reason},unknown} ->
+ {E,[{Mod,Func}]};
+ {Result,FailLoc} ->
+ {Result,FailLoc}
+ end,
+ try begin do_end_tc_call(Mod,{end_per_testcase_not_run,Func},
+ {Pid,RetVal,[Conf]}, FwError) end of
+ _ -> ok
+ catch
+ _:FwEndTCErr ->
+ exit({fw_notify_done,end_tc,FwEndTCErr})
+ end,
+ {RetVal,Loc,warn};
+cleanup_after_fw_error(Mod,Func,Conf,Pid,FwError,
+ {FwMod,FwFunc=end_tc,[Mod,{end_per_testcase,Func}|_]}) ->
+ %% Failed during post_end_per_testcase. Warn about it.
+ {RetVal,Report,Loc} =
+ case {proplists:get_value(tc_status, Conf),
+ proplists:get_value(tc_fail_loc, Conf, unknown)} of
+ {undefined,_} ->
+ {{failed,{FwMod,FwFunc,FwError}},
+ {{FwMod,FwError},FwError},
+ {FwMod,FwFunc}};
+ {E = {failed,_Reason},unknown} ->
+ {E,{Mod,Func,E},[{Mod,Func}]};
+ {Result,FailLoc} ->
+ {Result,{Mod,Func,Result},FailLoc}
+ end,
+ try begin do_end_tc_call(Mod,{cleanup,{end_per_testcase_not_run,Func}},
+ {Pid,RetVal,[Conf]}, FwError) end of
+ _ -> ok
+ catch
+ _:FwEndTCErr ->
+ exit({fw_notify_done,end_tc,FwEndTCErr})
+ end,
+ test_server_sup:framework_call(report,[framework_error,Report]),
+ {RetVal,Loc,warn};
+cleanup_after_fw_error(Mod,Func,Conf,Pid,FwError,{FwMod,FwFunc=init_tc,_})
+ when Func =:= init_per_suite; Func =:=init_per_group ->
+ %% Failed during pre_init_per_suite or pre_init_per_group
+ RetVal = {failed,{FwMod,FwFunc,FwError}},
+ try do_end_tc_call(Mod,Func,{Pid,RetVal,[Conf]},FwError) of
+ _ -> ok
+ catch
+ _:FwEndTCErr ->
+ exit({fw_notify_done,end_tc,FwEndTCErr})
+ end,
+ {RetVal,{FwMod,FwFunc},error};
+cleanup_after_fw_error(Mod,Func,Conf,Pid,FwError,{FwMod,FwFunc=end_tc,_})
+ when Func =:= init_per_suite; Func =:=init_per_group ->
+ %% Failed during post_init_per_suite or post_init_per_group
+ RetVal = {failed,{FwMod,FwFunc,FwError}},
+ try do_end_tc_call(Mod,{cleanup,Func},{Pid,RetVal,[Conf]},FwError) of
+ _ -> ok
+ catch
+ _:FwEndTCErr ->
+ exit({fw_notify_done,end_tc,FwEndTCErr})
+ end,
+ ReportFunc =
+ case Func of
+ init_per_group ->
+ case proplists:get_value(tc_group_properties,Conf) of
+ undefined ->
+ {Func,unknown,[]};
+ GProps ->
+ Name = proplists:get_value(name,GProps),
+ {Func,Name,proplists:delete(name,GProps)}
+ end;
+ _ ->
+ Func
+ end,
+ test_server_sup:framework_call(report,[framework_error,
+ {Mod,ReportFunc,RetVal}]),
+ {RetVal,{FwMod,FwFunc},error};
+cleanup_after_fw_error(Mod,Func,Conf,Pid,FwError,{FwMod,FwFunc=init_tc,_})
+ when Func =:= end_per_suite; Func =:=end_per_group ->
+ %% Failed during pre_end_per_suite or pre_end_per_group
+ RetVal = {failed,{FwMod,FwFunc,FwError}},
+ try do_end_tc_call(Mod,Func,{Pid,RetVal,[Conf]},FwError) of
+ _ -> ok
+ catch
+ _:FwEndTCErr ->
+ exit({fw_notify_done,end_tc,FwEndTCErr})
+ end,
+ {RetVal,{FwMod,FwFunc},error};
+cleanup_after_fw_error(Mod,Func,Conf,Pid,FwError,{FwMod,FwFunc=end_tc,_})
+ when Func =:= end_per_suite; Func =:=end_per_group ->
+ %% Failed during post_end_per_suite or post_end_per_group
+ RetVal = {failed,{FwMod,FwFunc,FwError}},
+ try do_end_tc_call(Mod,{cleanup,Func},{Pid,RetVal,[Conf]},FwError) of
+ _ -> ok
+ catch
+ _:FwEndTCErr ->
+ exit({fw_notify_done,end_tc,FwEndTCErr})
+ end,
+ ReportFunc =
+ case Func of
+ end_per_group ->
+ case proplists:get_value(tc_group_properties,Conf) of
+ undefined ->
+ {Func,unknown,[]};
+ GProps ->
+ Name = proplists:get_value(name,GProps),
+ {Func,Name,proplists:delete(name,GProps)}
+ end;
+ _ ->
+ Func
+ end,
+ test_server_sup:framework_call(report,[framework_error,
+ {Mod,ReportFunc,RetVal}]),
+ {RetVal,{FwMod,FwFunc},error};
+cleanup_after_fw_error(_Mod,_Func,_Conf,_Pid,FwError,{FwMod,FwFunc,_}) ->
+ %% This is unexpected
+ test_server_sup:framework_call(report,
+ [framework_error,
+ {{FwMod,FwFunc},
+ FwError}]),
+ {FwError,{FwMod,FwFunc},error}.
+
%% The job proxy process forwards messages between the test case
%% process on a shielded node (and its descendants) and the job process.
%%
@@ -1087,6 +1288,9 @@ run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback) ->
EndConf1 =
user_callback(TCCallback, Mod, Func, 'end', EndConf),
+ %% save updated config in controller loop
+ set_tc_state(tc, EndConf1),
+
%% We can't handle fails or skips here
EndConf2 =
case do_init_tc_call(Mod,{end_per_testcase,Func},
@@ -1339,13 +1543,12 @@ do_init_per_testcase(Mod, Args) ->
{skip,Reason};
exit:{Skip,Reason} when Skip =:= skip; Skip =:= skipped ->
{skip,Reason};
- throw:Other ->
- set_loc(erlang:get_stacktrace()),
+ throw:Other:Stk ->
+ set_loc(Stk),
Line = get_loc(),
print_init_conf_result(Line,"thrown",Other),
{skip,{failed,{Mod,init_per_testcase,Other}}};
- _:Reason0 ->
- Stk = erlang:get_stacktrace(),
+ _:Reason0:Stk ->
Reason = {Reason0,Stk},
set_loc(Stk),
Line = get_loc(),
@@ -1394,20 +1597,19 @@ do_end_per_testcase(Mod,EndFunc,Func,Conf) ->
_ ->
ok
catch
- throw:Other ->
+ throw:Other:Stk ->
Comment0 = case read_comment() of
"" -> "";
Cmt -> Cmt ++ test_server_ctrl:xhtml("<br>",
"<br />")
end,
- set_loc(erlang:get_stacktrace()),
+ set_loc(Stk),
comment(io_lib:format("~ts<font color=\"red\">"
"WARNING: ~w thrown!"
"</font>\n",[Comment0,EndFunc])),
print_end_tc_warning(EndFunc,Other,"thrown",get_loc()),
{failed,{Mod,end_per_testcase,Other}};
- Class:Reason ->
- Stk = erlang:get_stacktrace(),
+ Class:Reason:Stk ->
set_loc(Stk),
Why = case Class of
exit -> {'EXIT',Reason};
@@ -1549,8 +1751,7 @@ ts_tc(M, F, A) ->
throw:{skipped, Reason} -> {skip, Reason};
exit:{skip, Reason} -> {skip, Reason};
exit:{skipped, Reason} -> {skip, Reason};
- Type:Reason ->
- Stk = erlang:get_stacktrace(),
+ Type:Reason:Stk ->
set_loc(Stk),
case Type of
throw ->
@@ -1739,8 +1940,8 @@ fail(Reason) ->
try
exit({suite_failed,Reason})
catch
- Class:R ->
- case erlang:get_stacktrace() of
+ Class:R:Stacktrace ->
+ case Stacktrace of
[{?MODULE,fail,1,_}|Stk] -> ok;
Stk -> ok
end,
@@ -1762,8 +1963,8 @@ fail() ->
try
exit(suite_failed)
catch
- Class:R ->
- case erlang:get_stacktrace() of
+ Class:R:Stacktrace ->
+ case Stacktrace of
[{?MODULE,fail,0,_}|Stk] -> ok;
Stk -> ok
end,
@@ -2042,15 +2243,15 @@ call_user_timetrap(Func, Sup) when is_function(Func) ->
try Func() of
Result ->
Sup ! {self(),Result}
- catch _:Error ->
- exit({Error,erlang:get_stacktrace()})
+ catch _:Error:Stk ->
+ exit({Error,Stk})
end;
call_user_timetrap({M,F,A}, Sup) ->
try apply(M,F,A) of
Result ->
Sup ! {self(),Result}
- catch _:Error ->
- exit({Error,erlang:get_stacktrace()})
+ catch _:Error:Stk ->
+ exit({Error,Stk})
end.
save_user_timetrap(TCPid, UserTTSup, StartTime) ->
@@ -2707,9 +2908,9 @@ is_cover() ->
is_debug() ->
case catch erlang:system_info(debug_compiled) of
{'EXIT', _} ->
- case string:str(erlang:system_info(system_version), "debug") of
- Int when is_integer(Int), Int > 0 -> true;
- _ -> false
+ case string:find(erlang:system_info(system_version), "debug") of
+ nomatch -> false;
+ _ -> true
end;
Res ->
Res
@@ -2745,9 +2946,9 @@ has_superfluous_schedulers() ->
%% We might want to do more tests on a commercial platform, for instance
%% ensuring that all applications have documentation).
is_commercial() ->
- case string:str(erlang:system_info(system_version), "source") of
- Int when is_integer(Int), Int > 0 -> false;
- _ -> true
+ case string:find(erlang:system_info(system_version), "source") of
+ nomatch -> true;
+ _ -> false
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/common_test/src/test_server_ctrl.erl b/lib/common_test/src/test_server_ctrl.erl
index 8ef28b3343..003d08d70d 100644
--- a/lib/common_test/src/test_server_ctrl.erl
+++ b/lib/common_test/src/test_server_ctrl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1393,7 +1393,7 @@ temp_nodename([Chr|Base], Acc) ->
%%
%% Counts the test cases that are about to run and returns that number.
%% If there's a conf group in TestSpec with a repeat property, the total number
-%% of cases can not be calculated and NoOfCases = unknown.
+%% of cases cannot be calculated and NoOfCases = unknown.
count_test_cases(TopCases, SkipCases) when is_list(TopCases) ->
case collect_all_cases(TopCases, SkipCases) of
{error,_Why} = Error ->
@@ -1443,6 +1443,8 @@ remove_conf([C={Mod,error_in_suite,_}|Cases], NoConf, Repeats) ->
true ->
remove_conf(Cases, [C|NoConf], Repeats)
end;
+remove_conf([C={repeat,_,_}|Cases], NoConf, _Repeats) ->
+ remove_conf(Cases, [C|NoConf], true);
remove_conf([C|Cases], NoConf, Repeats) ->
remove_conf(Cases, [C|NoConf], Repeats);
remove_conf([], NoConf, true) ->
@@ -1472,13 +1474,14 @@ get_suites([], Mods) ->
lists:reverse(Mods).
add_mod(Mod, Mods) ->
- case string:rstr(atom_to_list(Mod), "_SUITE") of
- 0 -> false;
- _ -> % test suite
+ case lists:reverse(atom_to_list(Mod)) of
+ "ETIUS_" ++ _ -> % test suite
case lists:member(Mod, Mods) of
true -> false;
false -> true
- end
+ end;
+ _ ->
+ false
end.
@@ -1557,7 +1560,7 @@ do_test_cases(TopCases, SkipCases,
Html1}
end,
- print(html, Header),
+ print(html, "~ts", [Header]),
print(html, xhtml("<p>", "<h4>")),
print_timestamp(html, "Test started at "),
@@ -1604,10 +1607,10 @@ do_test_cases(TopCases, SkipCases,
[?suitelog_name,CoverLog,?unexpected_io_log]),
print(html,
"<p>~ts</p>\n" ++
- xhtml(["<table bgcolor=\"white\" border=\"3\" cellpadding=\"5\">\n",
- "<thead>\n"],
- ["<table id=\"",?sortable_table_name,"\">\n",
- "<thead>\n"]) ++
+ xhtml("<table bgcolor=\"white\" border=\"3\" cellpadding=\"5\">\n" ++
+ "<thead>\n",
+ "<table id=\"" ++ ?sortable_table_name ++ "\">\n" ++
+ "<thead>\n") ++
"<tr><th>Num</th><th>Module</th><th>Group</th>" ++
"<th>Case</th><th>Log</th><th>Time</th><th>Result</th>" ++
"<th>Comment</th></tr>\n</thead>\n<tbody>\n",
@@ -2060,6 +2063,14 @@ add_init_and_end_per_suite([SkipCase|Cases], LastMod, LastRef, FwMod)
[SkipCase|add_init_and_end_per_suite(Cases, LastMod, LastRef, FwMod)];
add_init_and_end_per_suite([{conf,_,_,_}=Case|Cases], LastMod, LastRef, FwMod) ->
[Case|add_init_and_end_per_suite(Cases, LastMod, LastRef, FwMod)];
+add_init_and_end_per_suite([{repeat,{Mod,_},_}=Case|Cases], LastMod, LastRef, FwMod)
+ when Mod =/= LastMod, Mod =/= FwMod ->
+ {PreCases, NextMod, NextRef} =
+ do_add_init_and_end_per_suite(LastMod, LastRef, Mod, FwMod),
+ PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod,
+ NextRef, FwMod)];
+add_init_and_end_per_suite([{repeat,_,_}=Case|Cases], LastMod, LastRef, FwMod) ->
+ [Case|add_init_and_end_per_suite(Cases, LastMod, LastRef, FwMod)];
add_init_and_end_per_suite([{Mod,_}=Case|Cases], LastMod, LastRef, FwMod)
when Mod =/= LastMod, Mod =/= FwMod ->
{PreCases, NextMod, NextRef} =
@@ -2137,7 +2148,7 @@ do_add_init_and_end_per_suite(LastMod, LastRef, Mod, FwMod) ->
%% let's call a "fake" end_per_suite if it exists
case erlang:function_exported(FwMod, end_per_suite, 1) of
true ->
- [{conf,LastRef,[{suite,Mod}],
+ [{conf,LastRef,[{suite,LastMod}],
{FwMod,end_per_suite}}|Init];
false ->
[{conf,LastRef,[],{LastMod,end_per_suite}}|Init]
@@ -2300,7 +2311,7 @@ run_test_cases(TestSpec, Config, TimetrapData) ->
%% test_server_io:print_buffered/1 to print the data. To help with this,
%% two variables in the process dictionary are used:
%% 'test_server_common_io_handler' and 'test_server_queued_io'. The values
-%% are set to as follwing:
+%% are set to as following:
%%
%% Value Meaning
%% ----- -------
@@ -2632,7 +2643,7 @@ run_test_cases_loop([{conf,Ref,Props,{Mod,Func}}|_Cases]=Cs0,
NumStr ->
%% Ex: "123 456 789" or "123,456,789" -> {123,456,789}
list_to_tuple([list_to_integer(NS) ||
- NS <- string:tokens(NumStr, [$ ,$:,$,])])
+ NS <- string:lexemes(NumStr, [$ ,$:,$,])])
end,
{shuffle_cases(Ref, Cs0, UseSeed),{shuffle,UseSeed}}
end;
@@ -2925,6 +2936,29 @@ run_test_cases_loop([{conf,_Ref,_Props,_X}=Conf|_Cases0],
Config, _TimetrapData, _Mode, _Status) ->
erlang:error(badarg, [Conf,Config]);
+run_test_cases_loop([{repeat,Case,{RepeatType,N}}|Cases0], Config,
+ TimeTrapData, Mode, Status) ->
+ Ref = make_ref(),
+ Parallel = check_prop(parallel, Mode) =/= false,
+ Sequence = check_prop(sequence, Mode) =/= false,
+ RepeatStop = RepeatType=:=repeat_until_fail
+ orelse RepeatType=:=repeat_until_ok,
+
+ if Parallel andalso RepeatStop ->
+ %% Cannot check results of test case during parallal
+ %% execution, so only RepeatType=:=repeat is allowed in
+ %% combination with parallel groups.
+ erlang:error({illegal_combination,{parallel,RepeatType}});
+ Sequence andalso RepeatStop ->
+ %% Sequence is stop on fail + skip rest, so only
+ %% RepeatType=:=repeat makes sense inside a sequence.
+ erlang:error({illegal_combination,{sequence,RepeatType}});
+ true ->
+ Mode1 = [{Ref,[{repeat,{RepeatType,1,N}}],?now}|Mode],
+ run_test_cases_loop([Case | Cases0], Config, TimeTrapData,
+ Mode1, Status)
+ end;
+
run_test_cases_loop([{Mod,Case}|Cases], Config, TimetrapData, Mode, Status) ->
ActualCfg =
case get(test_server_create_priv_dir) of
@@ -2937,7 +2971,7 @@ run_test_cases_loop([{Mod,Case}|Cases], Config, TimetrapData, Mode, Status) ->
run_test_cases_loop([{Mod,Case,[ActualCfg]}|Cases], Config,
TimetrapData, Mode, Status);
-run_test_cases_loop([{Mod,Func,Args}|Cases], Config, TimetrapData, Mode, Status) ->
+run_test_cases_loop([{Mod,Func,Args}=Case|Cases], Config, TimetrapData, Mode0, Status) ->
{Num,RunInit} =
case FwMod = get_fw_mod(?MODULE) of
Mod when Func == error_in_suite ->
@@ -2947,6 +2981,14 @@ run_test_cases_loop([{Mod,Func,Args}|Cases], Config, TimetrapData, Mode, Status)
run_init}
end,
+ Mode =
+ case Mode0 of
+ [{_,[{repeat,{_,_,_}}],_}|RestMode] ->
+ RestMode;
+ _ ->
+ Mode0
+ end,
+
%% check the current execution mode and save info about the case if
%% detected that printouts to common log files is handled later
@@ -2974,36 +3016,42 @@ run_test_cases_loop([{Mod,Func,Args}|Cases], Config, TimetrapData, Mode, Status)
if is_tuple(RetVal) -> element(1,RetVal);
true -> undefined
end,
- {Failed,Status1} =
+ {Result,Failed,Status1} =
case RetTag of
Skip when Skip==skip; Skip==skipped ->
- {false,update_status(skipped, Mod, Func, Status)};
+ {skipped,false,update_status(skipped, Mod, Func, Status)};
Fail when Fail=='EXIT'; Fail==failed ->
- {true,update_status(failed, Mod, Func, Status)};
+ {failed,true,update_status(failed, Mod, Func, Status)};
_ when Time==died, RetVal=/=ok ->
- {true,update_status(failed, Mod, Func, Status)};
+ {failed,true,update_status(failed, Mod, Func, Status)};
_ ->
- {false,update_status(ok, Mod, Func, Status)}
+ {ok,false,update_status(ok, Mod, Func, Status)}
end,
case check_prop(sequence, Mode) of
false ->
+ {Cases1,Mode1} =
+ check_repeat_testcase(Case,Result,Cases,Mode0),
stop_minor_log_file(),
- run_test_cases_loop(Cases, Config, TimetrapData, Mode, Status1);
+ run_test_cases_loop(Cases1, Config, TimetrapData, Mode1, Status1);
Ref ->
%% the case is in a sequence; we must check the result and
%% determine if the following cases should run or be skipped
if not Failed -> % proceed with next case
+ {Cases1,Mode1} =
+ check_repeat_testcase(Case,Result,Cases,Mode0),
stop_minor_log_file(),
- run_test_cases_loop(Cases, Config, TimetrapData, Mode, Status1);
+ run_test_cases_loop(Cases1, Config, TimetrapData, Mode1, Status1);
true -> % skip rest of cases in sequence
print(minor, "~n*** ~tw failed.~n"
" Skipping all other cases in sequence.",
[Func]),
+ {Cases1,Mode1} =
+ check_repeat_testcase(Case,Result,Cases,Mode0),
Reason = {failed,{Mod,Func}},
- Cases2 = skip_cases_upto(Ref, Cases, Reason, tc,
+ Cases2 = skip_cases_upto(Ref, Cases1, Reason, tc,
Mode, auto_skip_case),
stop_minor_log_file(),
- run_test_cases_loop(Cases2, Config, TimetrapData, Mode, Status1)
+ run_test_cases_loop(Cases2, Config, TimetrapData, Mode1, Status1)
end
end;
%% the test case is being executed in parallel with the main process (and
@@ -3012,7 +3060,8 @@ run_test_cases_loop([{Mod,Func,Args}|Cases], Config, TimetrapData, Mode, Status)
%% io from Pid will be buffered by the test_server_io process and
%% handled later, so we have to save info about the case
queue_test_case_io(undefined, Pid, Num+1, Mod, Func),
- run_test_cases_loop(Cases, Config, TimetrapData, Mode, Status)
+ {Cases1,Mode1} = check_repeat_testcase(Case,ok,Cases,Mode0),
+ run_test_cases_loop(Cases1, Config, TimetrapData, Mode1, Status)
end;
%% TestSpec processing finished
@@ -3305,7 +3354,8 @@ skip_case1(Type, CaseNum, Mod, Func, Comment, Mode) ->
true ->
print(2,"*** Skipping test case #~w ~tw ***", [CaseNum,{Mod,Func}])
end,
- TR = xhtml("<tr valign=\"top\">", ["<tr class=\"",odd_or_even(),"\">"]),
+ TR = xhtml("<tr valign=\"top\">",
+ "<tr class=\"" ++ odd_or_even() ++ "\">"),
GroupName = case get_name(Mode) of
undefined -> "";
Name -> cast_to_list(Name)
@@ -3450,9 +3500,19 @@ modify_cases_upto1(Ref, {skip,Reason,FType,Mode,SkipType},
T, Orig, Alt)
end;
-%% next is some other case, ignore or copy
-modify_cases_upto1(Ref, {skip,_,_,_,_}=Op, [_Other|T], Orig, Alt) ->
+%% next is a repeated test case
+modify_cases_upto1(Ref, {skip,Reason,_,Mode,SkipType}=Op,
+ [{repeat,{_M,_F}=MF,_Repeat}|T], Orig, Alt) ->
+ modify_cases_upto1(Ref, Op, T, Orig, [{SkipType,{MF,Reason},Mode}|Alt]);
+
+%% next is an already skipped case, ignore or copy
+modify_cases_upto1(Ref, {skip,_,_,_,_}=Op, [{SkipType,_,_}|T], Orig, Alt)
+ when SkipType=:=skip_case; SkipType=:=auto_skip_case ->
modify_cases_upto1(Ref, Op, T, Orig, Alt);
+
+%% next is some other case, mark as skipped or copy
+modify_cases_upto1(Ref, {skip,Reason,_,Mode,SkipType}=Op, [Other|T], Orig, Alt) ->
+ modify_cases_upto1(Ref, Op, T, Orig, [{SkipType,{Other,Reason},Mode}|Alt]);
modify_cases_upto1(Ref, CopyOp, [C|T], Orig, Alt) ->
modify_cases_upto1(Ref, CopyOp, T, [C|Orig], [C|Alt]).
@@ -3795,8 +3855,8 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit,
end,
print(minor,
- escape_chars(io_lib:format("Config value:\n\n ~tp\n", [Args2Print])),
- []),
+ "~ts",
+ [escape_chars(io_lib:format("Config value:\n\n ~tp\n", [Args2Print]))]),
print(minor, "Current directory is ~tp\n", [Cwd]),
GrNameStr = case GrName of
@@ -3805,7 +3865,7 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit,
end,
print(major, "=started ~s", [lists:flatten(timestamp_get(""))]),
{{Col0,Col1},Style} = get_font_style((RunInit==run_init), Mode),
- TR = xhtml("<tr valign=\"top\">", ["<tr class=\"",odd_or_even(),"\">"]),
+ TR = xhtml("<tr valign=\"top\">", "<tr class=\"" ++ odd_or_even() ++ "\">"),
EncMinorBase = uri_encode(MinorBase),
print(html, TR ++ "<td>" ++ Col0 ++ "~ts" ++ Col1 ++ "</td>"
"<td>" ++ Col0 ++ "~w" ++ Col1 ++ "</td>"
@@ -3830,7 +3890,7 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit,
print(minor, "<a name=\"end\"></a>", [], internal_raw),
print(minor, "\n", [], internal_raw),
print_timestamp(minor, "Ended at "),
- print(major, "=ended ~s", [lists:flatten(timestamp_get(""))]),
+ print(major, "=ended ~s", [timestamp_get("")]),
do_unless_parallel(Main, fun() -> file:set_cwd(filename:dirname(TSDir)) end),
@@ -3840,6 +3900,10 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit,
{died,{timetrap_timeout,TimetrapTimeout}} ->
progress(failed, Num, Mod, Func, GrName, Loc,
timetrap_timeout, TimetrapTimeout, Comment, Style);
+ {died,Reason={auto_skip,_Why}} ->
+ %% died in init_per_testcase or in a hook in this context
+ progress(skip, Num, Mod, Func, GrName, Loc, Reason,
+ Time, Comment, Style);
{died,{Skip,Reason}} when Skip==skip; Skip==skipped ->
%% died in init_per_testcase
progress(skip, Num, Mod, Func, GrName, Loc, Reason,
@@ -4001,11 +4065,12 @@ progress(skip, CaseNum, Mod, Func, GrName, Loc, Reason, Time,
true -> "~w"
end, [Time]),
ReasonStr = escape_chars(reason_to_string(Reason1)),
- ReasonStr1 = lists:flatten([string:strip(S,left) ||
- S <- string:tokens(ReasonStr,[$\n])]),
+ ReasonStr1 = lists:flatten([string:trim(S,leading,"\s") ||
+ S <- string:lexemes(ReasonStr,[$\n])]),
+ ReasonLength = string:length(ReasonStr1),
ReasonStr2 =
- if length(ReasonStr1) > 80 ->
- string:substr(ReasonStr1, 1, 77) ++ "...";
+ if ReasonLength > 80 ->
+ string:slice(ReasonStr1, 0, 77) ++ "...";
true ->
ReasonStr1
end,
@@ -4073,9 +4138,9 @@ progress(failed, CaseNum, Mod, Func, GrName, Loc, {testcase_aborted,Reason}, _T,
FormatLoc = test_server_sup:format_loc(Loc),
print(minor, "=== Location: ~ts", [FormatLoc]),
print(minor,
- escape_chars(io_lib:format("=== Reason: {testcase_aborted,~tp}",
- [Reason])),
- []),
+ "~ts",
+ [escape_chars(io_lib:format("=== Reason: {testcase_aborted,~tp}",
+ [Reason]))]),
failed;
progress(failed, CaseNum, Mod, Func, GrName, unknown, Reason, Time,
@@ -4089,11 +4154,12 @@ progress(failed, CaseNum, Mod, Func, GrName, unknown, Reason, Time,
true -> "~w"
end, [Time]),
ErrorReason = escape_chars(lists:flatten(io_lib:format("~tp", [Reason]))),
- ErrorReason1 = lists:flatten([string:strip(S,left) ||
- S <- string:tokens(ErrorReason,[$\n])]),
+ ErrorReason1 = lists:flatten([string:trim(S,leading,"\s") ||
+ S <- string:lexemes(ErrorReason,[$\n])]),
+ ErrorReasonLength = string:length(ErrorReason1),
ErrorReason2 =
- if length(ErrorReason1) > 63 ->
- string:substr(ErrorReason1, 1, 60) ++ "...";
+ if ErrorReasonLength > 63 ->
+ string:slice(ErrorReason1, 0, 60) ++ "...";
true ->
ErrorReason1
end,
@@ -4112,8 +4178,8 @@ progress(failed, CaseNum, Mod, Func, GrName, unknown, Reason, Time,
print(minor, "=== Location: ~w", [unknown]),
{FStr,FormattedReason} = format_exception(Reason),
print(minor,
- escape_chars(io_lib:format("=== Reason: " ++ FStr, [FormattedReason])),
- []),
+ "~ts",
+ [escape_chars(io_lib:format("=== Reason: " ++ FStr, [FormattedReason]))]),
failed;
progress(failed, CaseNum, Mod, Func, GrName, Loc, Reason, Time,
@@ -4147,8 +4213,9 @@ progress(failed, CaseNum, Mod, Func, GrName, Loc, Reason, Time,
FormatLoc = test_server_sup:format_loc(LocMin),
print(minor, "=== Location: ~ts", [FormatLoc]),
{FStr,FormattedReason} = format_exception(Reason),
- print(minor, "=== Reason: " ++
- escape_chars(io_lib:format(FStr, [FormattedReason])), []),
+ print(minor, "~ts",
+ ["=== Reason: " ++
+ escape_chars(io_lib:format(FStr, [FormattedReason]))]),
failed;
progress(ok, _CaseNum, Mod, Func, GrName, _Loc, RetVal, Time,
@@ -4181,8 +4248,8 @@ progress(ok, _CaseNum, Mod, Func, GrName, _Loc, RetVal, Time,
"~ts</tr>\n",
[TimeStr,Comment]),
print(minor,
- escape_chars(io_lib:format("=== Returned value: ~tp", [RetVal])),
- []),
+ "~ts",
+ [escape_chars(io_lib:format("=== Returned value: ~tp", [RetVal]))]),
ok.
%%--------------------------------------------------------------------
@@ -4379,7 +4446,7 @@ do_format_exception(Reason={Error,Stack}) ->
PF = fun(Term, I) ->
io_lib:format("~." ++ integer_to_list(I) ++ "tp", [Term])
end,
- case catch lib:format_exception(1, error, Error, Stack, StackFun, PF, utf8) of
+ case catch erl_error:format_exception(1, error, Error, Stack, StackFun, PF, utf8) of
{'EXIT',_R} ->
{"~tp",Reason};
Formatted ->
@@ -4539,7 +4606,7 @@ timestamp_get(Leader) ->
timestamp_get_internal(Leader, Format) ->
{YY,MM,DD,H,M,S} = time_get(),
- io_lib:format(Format, [Leader,YY,MM,DD,H,M,S]).
+ lists:flatten(io_lib:format(Format, [Leader,YY,MM,DD,H,M,S])).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% time_get() -> {YY,MM,DD,H,M,S}
@@ -4795,6 +4862,14 @@ collect_cases({make,InitMFA,CaseList,FinMFA}, St0, Mode) ->
{error,_Reason} = Error -> Error
end;
+collect_cases({repeat,{Module, Case}, Repeat}, St, Mode) ->
+ case catch collect_case([Case], St#cc{mod=Module}, [], Mode) of
+ {ok, [{Module,Case}], _} ->
+ {ok, [{repeat,{Module, Case}, Repeat}], St};
+ Other ->
+ {error,Other}
+ end;
+
collect_cases({Module, Cases}, St, Mode) when is_list(Cases) ->
case (catch collect_case(Cases, St#cc{mod=Module}, [], Mode)) of
Result = {ok,_,_} ->
@@ -4903,7 +4978,7 @@ collect_files(Dir, Pattern, St, Mode) ->
fullname_to_mod(Path) when is_list(Path) ->
%% If this is called with a binary, then we are probably in +fnu
%% mode and have found a beam file with name encoded as latin1. We
- %% will let this crash since it can not work to load such a module
+ %% will let this crash since it cannot work to load such a module
%% anyway. It should be removed or renamed!
list_to_atom(filename:rootname(filename:basename(Path))).
@@ -5164,7 +5239,7 @@ display_info([Pid|T], R, M) ->
Other
end,
Reds = fetch(reductions, Info),
- LM = length(fetch(messages, Info)),
+ LM = fetch(message_queue_len, Info),
pformat(io_lib:format("~w", [Pid]),
io_lib:format("~tw", [Call]),
io_lib:format("~tw", [Curr]), Reds, LM),
@@ -5736,7 +5811,7 @@ uri_encode_comp([Char|Chars],Encoding) ->
Reserved = sets:is_element(Char, reserved()),
case (Char>127 andalso Encoding==latin1) orelse Reserved of
true ->
- [ $% | http_util:integer_to_hexlist(Char)] ++
+ [ $% | integer_to_list(Char, 16)] ++
uri_encode_comp(Chars,Encoding);
false ->
[Char | uri_encode_comp(Chars,Encoding)]
@@ -5758,3 +5833,42 @@ encoding(File) ->
E ->
E
end.
+
+check_repeat_testcase(Case,Result,Cases,
+ [{Ref,[{repeat,RepeatData0}],StartTime}|Mode0]) ->
+ case do_update_repeat_data(Result,RepeatData0) of
+ false ->
+ {Cases,Mode0};
+ RepeatData ->
+ {[Case|Cases],[{Ref,[{repeat,RepeatData}],StartTime}|Mode0]}
+ end;
+check_repeat_testcase(_,_,Cases,Mode) ->
+ {Cases,Mode}.
+
+do_update_repeat_data(_,{RT,N,N}) when is_integer(N) ->
+ report_repeat_testcase(N,N),
+ report_stop_repeat_testcase(done,{RT,N}),
+ false;
+do_update_repeat_data(ok,{repeat_until_ok=RT,M,N}) ->
+ report_repeat_testcase(M,N),
+ report_stop_repeat_testcase(RT,{RT,N}),
+ false;
+do_update_repeat_data(failed,{repeat_until_fail=RT,M,N}) ->
+ report_repeat_testcase(M,N),
+ report_stop_repeat_testcase(RT,{RT,N}),
+ false;
+do_update_repeat_data(_,{RT,M,N}) when is_integer(M) ->
+ report_repeat_testcase(M,N),
+ {RT,M+1,N};
+do_update_repeat_data(_,{_,M,N}=RepeatData) ->
+ report_repeat_testcase(M,N),
+ RepeatData.
+
+report_stop_repeat_testcase(Reason,RepVal) ->
+ print(minor, "~n*** Stopping test case repeat operation: ~w", [Reason]),
+ print(1, "Stopping test case repeat operation: ~w", [RepVal]).
+
+report_repeat_testcase(M,forever) ->
+ print(minor, "~n=== Repeated test case: ~w of infinity", [M]);
+report_repeat_testcase(M,N) ->
+ print(minor, "~n=== Repeated test case: ~w of ~w", [M,N]).
diff --git a/lib/common_test/src/test_server_node.erl b/lib/common_test/src/test_server_node.erl
index b3b6ae3d92..f77d5a4966 100644
--- a/lib/common_test/src/test_server_node.erl
+++ b/lib/common_test/src/test_server_node.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,7 +18,7 @@
%% %CopyrightEnd%
%%
-module(test_server_node).
--compile(r16).
+-compile(r20).
%%%
%%% The same compiled code for this module must be possible to load
@@ -315,9 +315,11 @@ start_node_peer(SlaveName, OptList, From, TI) ->
Prog0 = start_node_get_option_value(erl, OptList, default),
Prog = quote_progname(pick_erl_program(Prog0)),
Args =
- case string:str(SuppliedArgs,"-setcookie") of
- 0 -> "-setcookie " ++ TI#target_info.cookie ++ " " ++ SuppliedArgs;
- _ -> SuppliedArgs
+ case string:find(SuppliedArgs,"-setcookie") of
+ nomatch ->
+ "-setcookie " ++ TI#target_info.cookie ++ " " ++ SuppliedArgs;
+ _ ->
+ SuppliedArgs
end,
Cmd = lists:concat([Prog,
" -detached ",
@@ -589,18 +591,27 @@ cast_to_list(X) -> lists:flatten(io_lib:format("~tw", [X])).
%%% this
%%%
pick_erl_program(default) ->
- cast_to_list(lib:progname());
+ ct:get_progname();
pick_erl_program(L) ->
P = random_element(L),
case P of
{prog, S} ->
S;
{release, S} ->
+ clear_erl_aflags(),
find_release(S);
this ->
- cast_to_list(lib:progname())
+ ct:get_progname()
end.
+clear_erl_aflags() ->
+ %% When starting a node with a previous release, options in
+ %% ERL_AFLAGS could prevent the node from starting. For example,
+ %% if ERL_AFLAGS is set to "-emu_type lcnt", the node will only
+ %% start if the previous release happens to also have a lock
+ %% counter emulator installed (unlikely).
+ os:unsetenv("ERL_AFLAGS").
+
%% This is an attempt to distinguish between spaces in the program
%% path and spaces that separate arguments. The program is quoted to
%% allow spaces in the path.
@@ -609,10 +620,10 @@ pick_erl_program(L) ->
%% ({prog,String}) or if the -program switch to beam is used and
%% includes arguments (typically done by cerl in OTP test environment
%% in order to ensure that slave/peer nodes are started with the same
-%% emulator and flags as the test node. The return from lib:progname()
-%% could then typically be '/<full_path_to>/cerl -gcov').
+%% emulator and flags as the test node. The return from ct:get_progname()
+%% could then typically be "/<full_path_to>/cerl -gcov").
quote_progname(Progname) ->
- do_quote_progname(string:tokens(Progname," ")).
+ do_quote_progname(string:lexemes(Progname," ")).
do_quote_progname([Prog]) ->
"\""++Prog++"\"";
@@ -654,9 +665,19 @@ find_release({unix,linux}, Rel) ->
find_release(_, _) -> none.
find_rel_linux(Rel) ->
- case suse_release() of
- none -> [];
- SuseRel -> find_rel_suse(Rel, SuseRel)
+ try
+ case ubuntu_release() of
+ none -> none;
+ [UbuntuRel |_] -> throw(find_rel_ubuntu(Rel, UbuntuRel))
+ end,
+ case suse_release() of
+ none -> none;
+ SuseRel -> throw(find_rel_suse(Rel, SuseRel))
+ end,
+ []
+ catch
+ throw:Result ->
+ Result
end.
find_rel_suse(Rel, SuseRel) ->
@@ -733,6 +754,93 @@ suse_release(Fd) ->
end
end.
+find_rel_ubuntu(_Rel, UbuntuRel) when is_integer(UbuntuRel), UbuntuRel < 16 ->
+ [];
+find_rel_ubuntu(Rel, UbuntuRel) when is_integer(UbuntuRel) ->
+ Root = "/usr/local/otp/releases/ubuntu",
+ lists:foldl(fun (ChkUbuntuRel, Acc) ->
+ find_rel_ubuntu_aux1(Rel, Root++integer_to_list(ChkUbuntuRel))
+ ++ Acc
+ end,
+ [],
+ lists:seq(16, UbuntuRel)).
+
+find_rel_ubuntu_aux1(Rel, RootWc) ->
+ case erlang:system_info(wordsize) of
+ 4 ->
+ find_rel_ubuntu_aux2(Rel, RootWc++"_32");
+ 8 ->
+ find_rel_ubuntu_aux2(Rel, RootWc++"_64") ++
+ find_rel_ubuntu_aux2(Rel, RootWc++"_32")
+ end.
+
+find_rel_ubuntu_aux2(Rel, RootWc) ->
+ RelDir = filename:dirname(RootWc),
+ Pat = filename:basename(RootWc ++ "_" ++ Rel) ++ ".*",
+ case file:list_dir(RelDir) of
+ {ok,Dirs} ->
+ case lists:filter(fun(Dir) ->
+ case re:run(Dir, Pat, [unicode]) of
+ nomatch -> false;
+ _ -> true
+ end
+ end, Dirs) of
+ [] ->
+ [];
+ [R|_] ->
+ [filename:join([RelDir,R,"bin","erl"])]
+ end;
+ _ ->
+ []
+ end.
+
+ubuntu_release() ->
+ case file:open("/etc/lsb-release", [read]) of
+ {ok,Fd} ->
+ try
+ ubuntu_release(Fd, undefined, undefined)
+ after
+ file:close(Fd)
+ end;
+ {error,_} -> none
+ end.
+
+ubuntu_release(_Fd, DistrId, Rel) when DistrId /= undefined,
+ Rel /= undefined ->
+ Ubuntu = case DistrId of
+ "Ubuntu" -> true;
+ "ubuntu" -> true;
+ _ -> false
+ end,
+ case Ubuntu of
+ false -> none;
+ true -> Rel
+ end;
+ubuntu_release(Fd, DistroId, Rel) ->
+ case io:get_line(Fd, '') of
+ eof ->
+ none;
+ Line when is_list(Line) ->
+ case re:run(Line, "^DISTRIB_ID=(\\w+)$",
+ [{capture,all_but_first,list}]) of
+ {match,[NewDistroId]} ->
+ ubuntu_release(Fd, NewDistroId, Rel);
+ nomatch ->
+ case re:run(Line, "^DISTRIB_RELEASE=(\\d+(?:\\.\\d+)*)$",
+ [{capture,all_but_first,list}]) of
+ {match,[RelList]} ->
+ NewRel = lists:map(fun (N) ->
+ list_to_integer(N)
+ end,
+ string:lexemes(RelList, ".")),
+ ubuntu_release(Fd, DistroId, NewRel);
+ nomatch ->
+ ubuntu_release(Fd, DistroId, Rel)
+ end
+ end
+ end.
+
+
unpack(Bin) ->
{One,Term} = split_binary(Bin, 1),
case binary_to_list(One) of
diff --git a/lib/common_test/src/test_server_sup.erl b/lib/common_test/src/test_server_sup.erl
index 6ddbf1ad27..ab8066a88d 100644
--- a/lib/common_test/src/test_server_sup.erl
+++ b/lib/common_test/src/test_server_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -770,7 +770,7 @@ framework_call(Callback,Func,Args,DefaultReturn) ->
end,
case SetTcState of
true ->
- test_server:set_tc_state({framework,Mod,Func});
+ test_server:set_tc_state({framework,{Mod,Func,Args}});
false ->
ok
end,
@@ -781,8 +781,8 @@ framework_call(Callback,Func,Args,DefaultReturn) ->
catch
exit:Why ->
EH(Why);
- error:Why ->
- EH({Why,erlang:get_stacktrace()});
+ error:Why:Stacktrace ->
+ EH({Why,Stacktrace});
throw:Why ->
EH(Why)
end;
diff --git a/lib/common_test/src/unix_telnet.erl b/lib/common_test/src/unix_telnet.erl
index 8ac467014c..7a210237a8 100644
--- a/lib/common_test/src/unix_telnet.erl
+++ b/lib/common_test/src/unix_telnet.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,39 +18,6 @@
%% %CopyrightEnd%
%%
-%%% @doc Callback module for ct_telnet, for connecting to a telnet
-%%% server on a unix host.
-%%%
-%%% <p>It requires the following entry in the config file:</p>
-%%% <pre>
-%%% {unix,[{telnet,HostNameOrIpAddress},
-%%% {port,PortNum}, % optional
-%%% {username,UserName},
-%%% {password,Password},
-%%% {keep_alive,Bool}, % optional
-%%% {tcp_nodely,Bool}]} % optional</pre>
-%%%
-%%% <p>To communicate via telnet to the host specified by
-%%% <code>HostNameOrIpAddress</code>, use the interface functions in
-%%% <code>ct_telnet</code>, e.g. <code>open(Name), cmd(Name,Cmd), ...</code>.</p>
-%%%
-%%% <p><code>Name</code> is the name you allocated to the unix host in
-%%% your <code>require</code> statement. E.g.</p>
-%%% <pre> suite() -> [{require,Name,{unix,[telnet]}}].</pre>
-%%% <p>or</p>
-%%% <pre> ct:require(Name,{unix,[telnet]}).</pre>
-%%%
-%%% <p>The "keep alive" activity (i.e. that Common Test sends NOP to the server
-%%% every 10 seconds if the connection is idle) may be enabled or disabled for one
-%%% particular connection as described here. It may be disabled for all connections
-%%% using <c>telnet_settings</c> (see <c>ct_telnet</c>).</p>
-%%%
-%%% <p>Note that the <code>{port,PortNum}</code> tuple is optional and if
-%%% omitted, default telnet port 23 will be used. Also the <c>keep_alive</c> tuple
-%%% is optional, and the value defauls to true (enabled).</p>
-%%%
-%%% @see ct
-%%% @see ct_telnet
-module(unix_telnet).
%% Callbacks for ct_telnet.erl
@@ -61,36 +28,9 @@
-define(password,"Password: ").
-define(prx,"login: |Password: |\\\$ |> ").
-%%%-----------------------------------------------------------------
-%%% @spec get_prompt_regexp() -> PromptRegexp
-%%% PromptRegexp = ct_telnet:prompt_regexp()
-%%%
-%%% @doc Callback for ct_telnet.erl.
-%%%
-%%% <p>Return a suitable regexp string that will match common
-%%% prompts for users on unix hosts.</p>
get_prompt_regexp() ->
?prx.
-
-%%%-----------------------------------------------------------------
-%%% @spec connect(ConnName,Ip,Port,Timeout,KeepAlive,Extra) ->
-%%% {ok,Handle} | {error,Reason}
-%%% ConnName = ct:target_name()
-%%% Ip = string() | {integer(),integer(),integer(),integer()}
-%%% Port = integer()
-%%% Timeout = integer()
-%%% KeepAlive = bool()
-%%% TCPNoDelay = bool()
-%%% Extra = ct:target_name() | {Username,Password}
-%%% Username = string()
-%%% Password = string()
-%%% Handle = ct_telnet:handle()
-%%% Reason = term()
-%%%
-%%% @doc Callback for ct_telnet.erl.
-%%%
-%%% <p>Setup telnet connection to a unix host.</p>
connect(ConnName,Ip,Port,Timeout,KeepAlive,TCPNoDelay,Extra) ->
case Extra of
{Username,Password} ->
@@ -121,7 +61,8 @@ connect1(Name,Ip,Port,Timeout,KeepAlive,TCPNoDelay,Username,Password) ->
prompt,?prx,[]) of
{ok,{prompt,?password},_} ->
ok = ct_telnet_client:send_data(Pid,Password),
- Stars = lists:duplicate(length(Password),$*),
+ Stars =
+ lists:duplicate(string:length(Password),$*),
log(Name,send,"Password: ~s",[Stars]),
% ok = ct_telnet_client:send_data(Pid,""),
case ct_telnet:silent_teln_expect(Name,Pid,[],
diff --git a/lib/common_test/src/vts.erl b/lib/common_test/src/vts.erl
index 83fcde2f48..38e549d2d6 100644
--- a/lib/common_test/src/vts.erl
+++ b/lib/common_test/src/vts.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -919,7 +919,7 @@ get_input_data(Input,Key)->
end.
parse(Input) ->
- httpd:parse_query(Input).
+ uri_string:dissect_query(Input).
vts_integer_to_list(X) when is_atom(X) ->
atom_to_list(X);
diff --git a/lib/common_test/test/Makefile b/lib/common_test/test/Makefile
index ecd1f727a2..e510b74d6a 100644
--- a/lib/common_test/test/Makefile
+++ b/lib/common_test/test/Makefile
@@ -74,7 +74,9 @@ MODULES= \
ct_SUITE \
ct_keep_logs_SUITE \
ct_unicode_SUITE \
- ct_auto_clean_SUITE
+ ct_auto_clean_SUITE \
+ ct_util_SUITE \
+ ct_tc_repeat_SUITE
ERL_FILES= $(MODULES:%=%.erl)
HRL_FILES= test_server_test_lib.hrl
diff --git a/lib/common_test/test/ct_auto_clean_SUITE.erl b/lib/common_test/test/ct_auto_clean_SUITE.erl
index fd81430d0d..a89c90eb79 100644
--- a/lib/common_test/test/ct_auto_clean_SUITE.erl
+++ b/lib/common_test/test/ct_auto_clean_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/test/ct_auto_clean_SUITE_data/ac_SUITE.erl b/lib/common_test/test/ct_auto_clean_SUITE_data/ac_SUITE.erl
index dae7c1e22c..e779f70693 100644
--- a/lib/common_test/test/ct_auto_clean_SUITE_data/ac_SUITE.erl
+++ b/lib/common_test/test/ct_auto_clean_SUITE_data/ac_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/test/ct_auto_clean_SUITE_data/cth_auto_clean.erl b/lib/common_test/test/ct_auto_clean_SUITE_data/cth_auto_clean.erl
index 137c81969d..3f8d3957cc 100644
--- a/lib/common_test/test/ct_auto_clean_SUITE_data/cth_auto_clean.erl
+++ b/lib/common_test/test/ct_auto_clean_SUITE_data/cth_auto_clean.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/test/ct_auto_compile_SUITE.erl b/lib/common_test/test/ct_auto_compile_SUITE.erl
index dface99b8f..f88f13c889 100644
--- a/lib/common_test/test/ct_auto_compile_SUITE.erl
+++ b/lib/common_test/test/ct_auto_compile_SUITE.erl
@@ -169,7 +169,7 @@ test_events(ac_flag) ->
{?eh,start_info,{1,1,3}},
{?eh,tc_start,{ct_framework,error_in_suite}},
{?eh,tc_done,{ct_framework,error_in_suite,
- {failed,{error,'bad_SUITE can not be compiled or loaded'}}}},
+ {failed,{error,'bad_SUITE cannot be compiled or loaded'}}}},
{?eh,tc_start,{dummy_SUITE,init_per_suite}},
{?eh,tc_done,{dummy_SUITE,init_per_suite,ok}},
{?eh,test_stats,{1,1,{1,0}}},
@@ -186,7 +186,7 @@ test_events(ac_spec) ->
{?eh,start_info,{1,1,3}},
{?eh,tc_start,{ct_framework,error_in_suite}},
{?eh,tc_done,{ct_framework,error_in_suite,
- {failed,{error,'bad_SUITE can not be compiled or loaded'}}}},
+ {failed,{error,'bad_SUITE cannot be compiled or loaded'}}}},
{?eh,tc_start,{dummy_SUITE,init_per_suite}},
{?eh,tc_done,{dummy_SUITE,init_per_suite,ok}},
{?eh,test_stats,{1,1,{1,0}}},
diff --git a/lib/common_test/test/ct_config_SUITE.erl b/lib/common_test/test/ct_config_SUITE.erl
index 250700741c..ec5278b96d 100644
--- a/lib/common_test/test/ct_config_SUITE.erl
+++ b/lib/common_test/test/ct_config_SUITE.erl
@@ -211,18 +211,12 @@ reformat_events(Events, EH) ->
%%% Test related to 'localtime' will often fail if the test host is
%%% time warping, so let's just skip the 'dynamic' tests then.
skip_dynamic() ->
- case os:getenv("TS_EXTRA_PLATFORM_LABEL") of
- TSExtraPlatformLabel when is_list(TSExtraPlatformLabel) ->
- case string:str(TSExtraPlatformLabel,"TimeWarpingOS") of
- 0 -> false;
- _ -> true
- end;
- _ ->
- false
+ case string:find(os:getenv("TS_EXTRA_PLATFORM_LABEL", ""), "TimeWarpingOS") of
+ nomatch -> false;
+ _ -> true
end.
-
%%%-----------------------------------------------------------------
%%% TEST EVENTS
%%%-----------------------------------------------------------------
diff --git a/lib/common_test/test/ct_cover_SUITE_data/cover_SUITE.erl b/lib/common_test/test/ct_cover_SUITE_data/cover_SUITE.erl
index 4e013b8056..e9e8b2a54d 100644
--- a/lib/common_test/test/ct_cover_SUITE_data/cover_SUITE.erl
+++ b/lib/common_test/test/ct_cover_SUITE_data/cover_SUITE.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,9 +23,7 @@
%% Description:
%% This file contains the test cases for the code coverage support
%%
-%% @author Support
-%% @doc Test of code coverage support in common_test
-%% @end
+%% Test of code coverage support in common_test
%%----------------------------------------------------------------------
%%----------------------------------------------------------------------
-module(cover_SUITE).
diff --git a/lib/common_test/test/ct_error_SUITE.erl b/lib/common_test/test/ct_error_SUITE.erl
index 7468ebe9d9..d31bd26273 100644
--- a/lib/common_test/test/ct_error_SUITE.erl
+++ b/lib/common_test/test/ct_error_SUITE.erl
@@ -648,33 +648,35 @@ test_events(cfg_error) ->
{?eh,tc_start,{cfg_error_11_SUITE,end_per_suite}},
{?eh,tc_done,{cfg_error_11_SUITE,end_per_suite,ok}},
{?eh,tc_start,{cfg_error_12_SUITE,tc1}},
- {?eh,tc_done,{ct_framework,init_tc,{framework_error,{timetrap,500}}}},
- {?eh,test_stats,{13,8,{0,19}}},
+ {?eh,tc_done,{cfg_error_12_SUITE,tc1,
+ {auto_skipped,
+ {failed,{ct_framework,init_tc,{timetrap,500}}}}}},
+ {?eh,test_stats,{13,7,{0,20}}},
{?eh,tc_start,{cfg_error_12_SUITE,tc2}},
{?eh,tc_done,{cfg_error_12_SUITE,tc2,{failed,
{cfg_error_12_SUITE,end_per_testcase,
{timetrap_timeout,500}}}}},
- {?eh,test_stats,{14,8,{0,19}}},
+ {?eh,test_stats,{14,7,{0,20}}},
{?eh,tc_start,{cfg_error_12_SUITE,tc3}},
{?eh,tc_done,{cfg_error_12_SUITE,tc3,ok}},
- {?eh,test_stats,{15,8,{0,19}}},
+ {?eh,test_stats,{15,7,{0,20}}},
{?eh,tc_start,{cfg_error_12_SUITE,tc4}},
{?eh,tc_done,{cfg_error_12_SUITE,tc4,{failed,
{cfg_error_12_SUITE,end_per_testcase,
{timetrap_timeout,500}}}}},
- {?eh,test_stats,{16,8,{0,19}}},
+ {?eh,test_stats,{16,7,{0,20}}},
{?eh,tc_start,{cfg_error_13_SUITE,init_per_suite}},
{?eh,tc_done,{cfg_error_13_SUITE,init_per_suite,ok}},
{?eh,tc_start,{cfg_error_13_SUITE,tc1}},
{?eh,tc_done,{cfg_error_13_SUITE,tc1,ok}},
- {?eh,test_stats,{17,8,{0,19}}},
+ {?eh,test_stats,{17,7,{0,20}}},
{?eh,tc_start,{cfg_error_13_SUITE,end_per_suite}},
{?eh,tc_done,{cfg_error_13_SUITE,end_per_suite,ok}},
{?eh,tc_start,{cfg_error_14_SUITE,init_per_suite}},
{?eh,tc_done,{cfg_error_14_SUITE,init_per_suite,ok}},
{?eh,tc_start,{cfg_error_14_SUITE,tc1}},
{?eh,tc_done,{cfg_error_14_SUITE,tc1,ok}},
- {?eh,test_stats,{18,8,{0,19}}},
+ {?eh,test_stats,{18,7,{0,20}}},
{?eh,tc_start,{cfg_error_14_SUITE,end_per_suite}},
{?eh,tc_done,{cfg_error_14_SUITE,end_per_suite,
{comment,
@@ -728,25 +730,30 @@ test_events(lib_error) ->
{lib_error_1_SUITE,no_lines_throw,{failed,{error,{thrown,catch_me_if_u_can}}}}},
{?eh,test_stats,{0,8,{0,0}}},
{?eh,tc_start,{lib_error_1_SUITE,init_tc_error}},
- {?eh,tc_done,{ct_framework,init_tc,
- {framework_error,{{badmatch,[1,2]},'_'}}}},
- {?eh,test_stats,{0,9,{0,0}}},
+ {?eh,tc_done,{lib_error_1_SUITE,init_tc_error,
+ {auto_skipped,
+ {failed,
+ {ct_framework,init_tc,
+ {{badmatch,[1,2]},'_'}}}}}},
+ {?eh,test_stats,{0,8,{0,1}}},
{?eh,tc_start,{lib_error_1_SUITE,init_tc_exit}},
- {?eh,tc_done,{ct_framework,init_tc,{framework_error,byebye}}},
- {?eh,test_stats,{0,10,{0,0}}},
+ {?eh,tc_done,{lib_error_1_SUITE,init_tc_exit,
+ {auto_skipped,{failed,{ct_framework,init_tc,byebye}}}}},
+ {?eh,test_stats,{0,8,{0,2}}},
{?eh,tc_start,{lib_error_1_SUITE,init_tc_throw}},
- {?eh,tc_done,{ct_framework,init_tc,{framework_error,catch_me_if_u_can}}},
- {?eh,test_stats,{0,11,{0,0}}},
+ {?eh,tc_done,{lib_error_1_SUITE,init_tc_throw,
+ {auto_skipped,{failed,{ct_framework,init_tc,
+ catch_me_if_u_can}}}}},
+ {?eh,test_stats,{0,8,{0,3}}},
{?eh,tc_start,{lib_error_1_SUITE,end_tc_error}},
- {?eh,tc_done,{ct_framework,end_tc,
- {framework_error,{{badmatch,[1,2]},'_'}}}},
- {?eh,test_stats,{0,12,{0,0}}},
+ {?eh,tc_done,{lib_error_1_SUITE,end_tc_error,ok}}, % warning in comment
+ {?eh,test_stats,{1,8,{0,3}}},
{?eh,tc_start,{lib_error_1_SUITE,end_tc_exit}},
- {?eh,tc_done,{ct_framework,end_tc,{framework_error,byebye}}},
- {?eh,test_stats,{0,13,{0,0}}},
+ {?eh,tc_done,{lib_error_1_SUITE,end_tc_exit,ok}}, % warning in comment
+ {?eh,test_stats,{2,8,{0,3}}},
{?eh,tc_start,{lib_error_1_SUITE,end_tc_throw}},
- {?eh,tc_done,{ct_framework,end_tc,{framework_error,catch_me_if_u_can}}},
- {?eh,test_stats,{0,14,{0,0}}},
+ {?eh,tc_done,{lib_error_1_SUITE,end_tc_throw,ok}}, % warning in comment
+ {?eh,test_stats,{3,8,{0,3}}},
{?eh,tc_start,{lib_error_1_SUITE,end_per_suite}},
{?eh,tc_done,{lib_error_1_SUITE,end_per_suite,ok}},
{?eh,test_done,{'DEF','STOP_TIME'}},
diff --git a/lib/common_test/test/ct_error_SUITE_data/error/test/verify_config.erl b/lib/common_test/test/ct_error_SUITE_data/error/test/verify_config.erl
index 530ee09654..ef8c05cb2e 100644
--- a/lib/common_test/test/ct_error_SUITE_data/error/test/verify_config.erl
+++ b/lib/common_test/test/ct_error_SUITE_data/error/test/verify_config.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,9 +18,9 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Example Suite Callback module.
+%%% Common Test Example Suite Callback module.
%%%
-%%% <p>This module gives an example of a common test CTH (Common Test Hook).
+%%% This module gives an example of a common test CTH (Common Test Hook).
%%% There are many ways to add a CTH to a test run, you can do it either in
%%% the command line using -ct_hook, in a test spec using
%%% {ct_hook,M} or in the suite it self by returning ct_hook
@@ -31,7 +31,7 @@
%%% it will be stopped after end_per_suite and so on. See terminate
%%% documentation for a table describing the scoping machanics.
%%%
-%%% All of callbacks except init/1 in a CTH are optional.</p>
+%%% All of callbacks except init/1 in a CTH are optional.
-module(verify_config).
@@ -69,14 +69,14 @@
-record(state, { id = ?MODULE :: term()}).
-%% @doc Always called before any other callback function. Use this to initiate
+%% Always called before any other callback function. Use this to initiate
%% any common state. It should return an state for this CTH.
-spec init(Id :: term(), Opts :: proplists:proplist()) ->
{ok, State :: #state{}}.
init(Id, Opts) ->
{ok,Opts}.
-%% @doc The ID is used to uniquly identify an CTH instance, if two CTH's
+%% The ID is used to uniquly identify an CTH instance, if two CTH's
%% return the same ID the seconds CTH is ignored. This function should NOT
%% have any side effects as it might be called multiple times by common test.
-spec id(Opts :: proplists:proplist()) ->
@@ -84,7 +84,7 @@ init(Id, Opts) ->
id(Opts) ->
os:timestamp().
-%% @doc Called before init_per_suite is called. Note that this callback is
+%% Called before init_per_suite is called. Note that this callback is
%% only called if the CTH is added before init_per_suite is run (eg. in a test
%% specification, suite/0 function etc).
%% You can change the config in the this function.
@@ -95,7 +95,7 @@ id(Opts) ->
pre_init_per_suite(Suite,Config,State) ->
{Config, State}.
-%% @doc Called after init_per_suite.
+%% Called after init_per_suite.
%% you can change the return value in this function.
-spec post_init_per_suite(Suite :: atom(),
Config :: config(),
@@ -105,7 +105,7 @@ pre_init_per_suite(Suite,Config,State) ->
post_init_per_suite(Suite,Config,Return,State) ->
{Return, State}.
-%% @doc Called before end_per_suite. The config/state can be changed here,
+%% Called before end_per_suite. The config/state can be changed here,
%% though it will only affect the *end_per_suite function.
-spec pre_end_per_suite(Suite :: atom(),
Config :: config() | skip_or_fail(),
@@ -114,7 +114,7 @@ post_init_per_suite(Suite,Config,Return,State) ->
pre_end_per_suite(Suite,Config,State) ->
{Config, State}.
-%% @doc Called after end_per_suite. Note that the config cannot be
+%% Called after end_per_suite. Note that the config cannot be
%% changed here, only the status of the suite.
-spec post_end_per_suite(Suite :: atom(),
Config :: config(),
@@ -124,7 +124,7 @@ pre_end_per_suite(Suite,Config,State) ->
post_end_per_suite(Suite,Config,Return,State) ->
{Return, State}.
-%% @doc Called before each init_per_group.
+%% Called before each init_per_group.
%% You can change the config in this function.
-spec pre_init_per_group(Group :: atom(),
Config :: config(),
@@ -133,7 +133,7 @@ post_end_per_suite(Suite,Config,Return,State) ->
pre_init_per_group(Group,Config,State) ->
{Config, State}.
-%% @doc Called after each init_per_group.
+%% Called after each init_per_group.
%% You can change the return value in this function.
-spec post_init_per_group(Group :: atom(),
Config :: config(),
@@ -143,7 +143,7 @@ pre_init_per_group(Group,Config,State) ->
post_init_per_group(Group,Config,Return,State) ->
{Return, State}.
-%% @doc Called after each end_per_group. The config/state can be changed here,
+%% Called after each end_per_group. The config/state can be changed here,
%% though it will only affect the *end_per_group functions.
-spec pre_end_per_group(Group :: atom(),
Config :: config() | skip_or_fail(),
@@ -152,7 +152,7 @@ post_init_per_group(Group,Config,Return,State) ->
pre_end_per_group(Group,Config,State) ->
{Config, State}.
-%% @doc Called after each end_per_group. Note that the config cannot be
+%% Called after each end_per_group. Note that the config cannot be
%% changed here, only the status of the group.
-spec post_end_per_group(Group :: atom(),
Config :: config(),
@@ -162,7 +162,7 @@ pre_end_per_group(Group,Config,State) ->
post_end_per_group(Group,Config,Return,State) ->
{Return, State}.
-%% @doc Called before each test case.
+%% Called before each test case.
%% You can change the config in this function.
-spec pre_init_per_testcase(TC :: atom(),
Config :: config(),
@@ -171,7 +171,7 @@ post_end_per_group(Group,Config,Return,State) ->
pre_init_per_testcase(TC,Config,State) ->
{Config, State}.
-%% @doc Called after each test case. Note that the config cannot be
+%% Called after each test case. Note that the config cannot be
%% changed here, only the status of the test case.
-spec post_end_per_testcase(TC :: atom(),
Config :: config(),
@@ -198,7 +198,7 @@ post_end_per_testcase(TC,Config,Return,State) ->
end,
{Return, State}.
-%% @doc Called after post_init_per_suite, post_end_per_suite, post_init_per_group,
+%% Called after post_init_per_suite, post_end_per_suite, post_init_per_group,
%% post_end_per_group and post_end_per_tc if the suite, group or test case failed.
%% This function should be used for extra cleanup which might be needed.
%% It is not possible to modify the config or the status of the test run.
@@ -209,7 +209,7 @@ post_end_per_testcase(TC,Config,Return,State) ->
on_tc_fail(TC, Reason, State) ->
State.
-%% @doc Called when a test case is skipped by either user action
+%% Called when a test case is skipped by either user action
%% or due to an init function failing. Test case can be
%% end_per_suite, init_per_group, end_per_group and the actual test cases.
-spec on_tc_skip(TC :: end_per_suite |
@@ -221,7 +221,7 @@ on_tc_fail(TC, Reason, State) ->
on_tc_skip(TC, Reason, State) ->
State.
-%% @doc Called when the scope of the CTH is done, this depends on
+%% Called when the scope of the CTH is done, this depends on
%% when the CTH was specified. This translation table describes when this
%% function is called.
%%
diff --git a/lib/common_test/test/ct_event_handler_SUITE_data/eh_A.erl b/lib/common_test/test/ct_event_handler_SUITE_data/eh_A.erl
index 07b21b4178..e4c7be3cac 100644
--- a/lib/common_test/test/ct_event_handler_SUITE_data/eh_A.erl
+++ b/lib/common_test/test/ct_event_handler_SUITE_data/eh_A.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,10 +18,10 @@
%% %CopyrightEnd%
%%
-%%% @doc Event handler module
+%%% Event handler module
%%%
-%%% <p>This is an event handler module used for testing that
-%%% Common Test generates events as expected.</p>
+%%% This is an event handler module used for testing that
+%%% Common Test generates events as expected.
%%%
-module(eh_A).
diff --git a/lib/common_test/test/ct_hooks_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE.erl
index 8ba14e63bc..340b8f3d52 100644
--- a/lib/common_test/test/ct_hooks_SUITE.erl
+++ b/lib/common_test/test/ct_hooks_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -73,18 +73,22 @@ all() ->
all(suite) ->
lists:reverse(
[
+ crash_groups, crash_all, bad_return_groups, bad_return_all,
+ illegal_values_groups, illegal_values_all, alter_groups, alter_all,
+ alter_all_to_skip, alter_all_from_skip,
one_cth, two_cth, faulty_cth_no_init, faulty_cth_id_no_init,
faulty_cth_exit_in_init, faulty_cth_exit_in_id,
faulty_cth_exit_in_init_scope_suite, minimal_cth,
minimal_and_maximal_cth, faulty_cth_undef,
scope_per_suite_cth, scope_per_group_cth, scope_suite_cth,
+ scope_suite_group_only_cth,
scope_per_suite_state_cth, scope_per_group_state_cth,
scope_suite_state_cth,
fail_pre_suite_cth, double_fail_pre_suite_cth,
fail_post_suite_cth, skip_pre_suite_cth, skip_pre_end_cth,
skip_pre_init_tc_cth,
skip_post_suite_cth, recover_post_suite_cth, update_config_cth,
- state_update_cth, options_cth, same_id_cth,
+ state_update_cth, update_result_cth, options_cth, same_id_cth,
fail_n_skip_with_minimal_cth, prio_cth, no_config,
no_init_suite_config, no_init_config, no_end_config,
failed_sequence, repeat_force_stop, config_clash,
@@ -152,6 +156,11 @@ scope_suite_cth(Config) when is_list(Config) ->
do_test(scope_suite_cth, "ct_scope_suite_cth_SUITE.erl",
[],Config).
+scope_suite_group_only_cth(Config) when is_list(Config) ->
+ do_test(scope_suite_group_only_cth,
+ "ct_scope_suite_group_only_cth_SUITE.erl",
+ [],Config,ok,2,[{group,g1}]).
+
scope_per_group_cth(Config) when is_list(Config) ->
do_test(scope_per_group_cth, "ct_scope_per_group_cth_SUITE.erl",
[],Config).
@@ -209,6 +218,10 @@ state_update_cth(Config) when is_list(Config) ->
do_test(state_update_cth, "ct_cth_fail_one_skip_one_SUITE.erl",
[state_update_cth,state_update_cth],Config).
+update_result_cth(Config) ->
+ do_test(update_result_cth, "ct_cth_update_result_post_end_tc_SUITE.erl",
+ [update_result_post_end_tc_cth],Config).
+
options_cth(Config) when is_list(Config) ->
do_test(options_cth, "ct_cth_empty_SUITE.erl",
[{empty_cth,[test]}],Config).
@@ -257,16 +270,21 @@ cth_log(Config) when is_list(Config) ->
lists:foreach(
fun(UnexpIoLog) ->
{ok,Bin} = file:read_file(UnexpIoLog),
- Ts = string:tokens(binary_to_list(Bin),[$\n]),
- Matches = lists:foldl(fun([$=,$E,$R,$R,$O,$R|_], N) ->
- N+1;
- ([$L,$o,$g,$g,$e,$r|_], N) ->
- N+1;
+ Ts = string:lexemes(binary_to_list(Bin),[$\n]),
+ Matches = lists:foldl(fun([$=,$E,$R,$R,$O,$R|_], {E,I,L}) ->
+ {E+1,I,L};
+ ([$=,$I,$N,$F,$O|_], {E,I,L}) ->
+ {E,I+1,L};
+ ([$L,$o,$g,$g,$e,$r|_], {E,I,L}) ->
+ {E,I,L+1};
(_, N) -> N
- end, 0, Ts),
- ct:pal("~p matches in ~tp", [Matches,UnexpIoLog]),
- if Matches > 10 -> ok;
- true -> exit({no_unexpected_io_found,UnexpIoLog})
+ end, {0,0,0}, Ts),
+ ct:pal("~p ({Error,Info,Log}) matches in ~tp",
+ [Matches,UnexpIoLog]),
+ MatchList = tuple_to_list(Matches),
+ case [N || N <- MatchList, N<3] of
+ [] -> ok;
+ _ -> exit({missing_unexpected_io,UnexpIoLog})
end
end, UnexpIoLogs),
ok.
@@ -295,10 +313,74 @@ repeat_force_stop(Config) ->
[{force_stop,skip_rest},{duration,"000009"}]).
%% Test that expected callbacks, and only those, are called when a test
-%% are fails due to clash in config alias names
+%% fails due to clash in config alias names
config_clash(Config) ->
do_test(config_clash, "config_clash_SUITE.erl", [skip_cth], Config).
+%% Test post_groups and post_all hook callbacks, introduced by OTP-14746
+alter_groups(Config) ->
+ CfgFile = gen_config(?FUNCTION_NAME,
+ [{post_groups_return,[{new_group,[tc1,tc2]}]},
+ {post_all_return,[{group,new_group}]}],Config),
+ do_test(?FUNCTION_NAME, "all_and_groups_SUITE.erl", [all_and_groups_cth],
+ Config, ok, 2, [{config,CfgFile}]).
+
+alter_all(Config) ->
+ CfgFile = gen_config(?FUNCTION_NAME,[{post_all_return,[tc2]}],Config),
+ do_test(?FUNCTION_NAME, "all_and_groups_SUITE.erl", [all_and_groups_cth],
+ Config, ok, 2, [{config,CfgFile}]).
+
+alter_all_from_skip(Config) ->
+ CfgFile = gen_config(?FUNCTION_NAME,[{all_return,{skip,"skipped by all/0"}},
+ {post_all_return,[tc2]}],Config),
+ do_test(?FUNCTION_NAME, "all_and_groups_SUITE.erl", [all_and_groups_cth],
+ Config, ok, 2, [{config,CfgFile}]).
+
+alter_all_to_skip(Config) ->
+ CfgFile = gen_config(?FUNCTION_NAME,
+ [{post_all_return,{skip,"skipped by post_all/3"}}],
+ Config),
+ do_test(?FUNCTION_NAME, "all_and_groups_SUITE.erl", [all_and_groups_cth],
+ Config, ok, 2, [{config,CfgFile}]).
+
+bad_return_groups(Config) ->
+ CfgFile = gen_config(?FUNCTION_NAME,[{post_groups_return,not_a_list}],
+ Config),
+ do_test(?FUNCTION_NAME, "all_and_groups_SUITE.erl", [all_and_groups_cth],
+ Config, ok, 2, [{config,CfgFile}]).
+
+bad_return_all(Config) ->
+ CfgFile = gen_config(?FUNCTION_NAME,[{post_all_return,not_a_list}],
+ Config),
+ do_test(?FUNCTION_NAME, "all_and_groups_SUITE.erl", [all_and_groups_cth],
+ Config, ok, 2, [{config,CfgFile}]).
+
+illegal_values_groups(Config) ->
+ CfgFile = gen_config(?FUNCTION_NAME,
+ [{post_groups_return,[{new_group,[this_test_does_not_exist]},
+ this_is_not_a_group_def]}],
+ Config),
+ do_test(?FUNCTION_NAME, "all_and_groups_SUITE.erl", [all_and_groups_cth],
+ Config, ok, 2, [{config,CfgFile}]).
+
+illegal_values_all(Config) ->
+ CfgFile = gen_config(?FUNCTION_NAME,
+ [{post_all_return,[{group,this_group_does_not_exist},
+ {this_is_not_a_valid_term}]}],
+ Config),
+ do_test(?FUNCTION_NAME, "all_and_groups_SUITE.erl", [all_and_groups_cth],
+ Config, ok, 2, [{config,CfgFile}]).
+
+crash_groups(Config) ->
+ CfgFile = gen_config(?FUNCTION_NAME,[{post_groups_return,crash}],Config),
+ do_test(?FUNCTION_NAME, "all_and_groups_SUITE.erl", [all_and_groups_cth],
+ Config, ok, 2, [{config,CfgFile}]).
+
+crash_all(Config) ->
+ CfgFile = gen_config(?FUNCTION_NAME,[{post_all_return,crash}],Config),
+ do_test(?FUNCTION_NAME, "all_and_groups_SUITE.erl", [all_and_groups_cth],
+ Config, ok, 2, [{config,CfgFile}]).
+
%%%-----------------------------------------------------------------
%%% HELP FUNCTIONS
%%%-----------------------------------------------------------------
@@ -318,6 +400,7 @@ do_test(Tag, {WhatTag,Wildcard}, CTHs, Config, Res, EC, ExtraOpts) ->
filename:join([DataDir,"cth/tests",Wildcard])),
{Opts,ERPid} =
setup([{WhatTag,Files},{ct_hooks,CTHs},{label,Tag}|ExtraOpts], Config),
+
Res = ct_test_support:run(Opts, Config),
Events = ct_test_support:get_events(ERPid, Config),
@@ -343,6 +426,13 @@ reformat(Events, EH) ->
%reformat(Events, _EH) ->
% Events.
+gen_config(Name,KeyVals,Config) ->
+ PrivDir = ?config(priv_dir,Config),
+ File = filename:join(PrivDir,atom_to_list(Name)++".cfg"),
+ ok = file:write_file(File,[io_lib:format("~p.~n",[{Key,Value}])
+ || {Key,Value} <- KeyVals]),
+ File.
+
%%%-----------------------------------------------------------------
%%% TEST EVENTS
%%%-----------------------------------------------------------------
@@ -361,13 +451,16 @@ test_events(one_empty_cth) ->
{?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
{?eh,cth,{empty_cth,id,[[]]}},
{?eh,cth,{empty_cth,init,[{'_','_','_'},[]]}},
+ %% check that post_groups and post_all comes after init when hook
+ %% is installed with start flag/option.
+ {?eh,cth,{empty_cth,post_groups,[ct_cth_empty_SUITE,[]]}},
+ {?eh,cth,{empty_cth,post_all,[ct_cth_empty_SUITE,[test_case],[]]}},
{?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}},
{?eh,cth,{empty_cth,pre_init_per_suite,
[ct_cth_empty_SUITE,'$proplist',[]]}},
{?eh,cth,{empty_cth,post_init_per_suite,
[ct_cth_empty_SUITE,'$proplist','$proplist',[]]}},
{?eh,tc_done,{ct_cth_empty_SUITE,init_per_suite,ok}},
-
{?eh,tc_start,{ct_cth_empty_SUITE,test_case}},
{?eh,cth,{empty_cth,pre_init_per_testcase,[ct_cth_empty_SUITE,test_case,'$proplist',[]]}},
{?eh,cth,{empty_cth,post_init_per_testcase,[ct_cth_empty_SUITE,test_case,'$proplist','_',[]]}},
@@ -576,6 +669,10 @@ test_events(scope_suite_cth) ->
[
{?eh,start_logging,{'DEF','RUNDIR'}},
{?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ %% check that post_groups and post_all comes before init when hook
+ %% is installed in suite/0
+ {?eh,cth,{'_',post_groups,['_',[]]}},
+ {?eh,cth,{'_',post_all,['_','_',[]]}},
{?eh,tc_start,{ct_scope_suite_cth_SUITE,init_per_suite}},
{?eh,cth,{'_',id,[[]]}},
{?eh,cth,{'_',init,['_',[]]}},
@@ -597,6 +694,34 @@ test_events(scope_suite_cth) ->
{?eh,stop_logging,[]}
];
+test_events(scope_suite_group_only_cth) ->
+ Suite = ct_scope_suite_group_only_cth_SUITE,
+ CTH = empty_cth,
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{1,1,1}},
+ %% check that post_groups and post_all comes before init when hook
+ %% is installed in suite/0
+ {?eh,cth,{CTH,post_groups,['_',['_']]}},
+ {negative,
+ {?eh,cth,{CTH,post_all,['_','_','_']}},
+ {?eh,tc_start,{Suite,init_per_suite}}},
+ {?eh,cth,{CTH,id,[[]]}},
+ {?eh,cth,{CTH,init,['_',[]]}},
+ {?eh,cth,{CTH,pre_init_per_suite,[Suite,'$proplist',mystate]}},
+ {?eh,cth,{CTH,post_init_per_suite,[Suite,'$proplist','$proplist',mystate]}},
+ {?eh,tc_done,{Suite,init_per_suite,ok}},
+
+ {?eh,tc_start,{Suite,end_per_suite}},
+ {?eh,cth,{CTH,pre_end_per_suite,[Suite,'$proplist',mystate]}},
+ {?eh,cth,{CTH,post_end_per_suite,[Suite,'$proplist','_',mystate]}},
+ {?eh,cth,{CTH,terminate,[mystate]}},
+ {?eh,tc_done,{Suite,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}
+ ];
+
test_events(scope_per_group_cth) ->
[
{?eh,start_logging,{'DEF','RUNDIR'}},
@@ -656,6 +781,8 @@ test_events(scope_suite_state_cth) ->
[
{?eh,start_logging,{'DEF','RUNDIR'}},
{?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,cth,{'_',post_groups,['_',[]]}},
+ {?eh,cth,{'_',post_all,['_','_',[]]}},
{?eh,tc_start,{ct_scope_suite_state_cth_SUITE,init_per_suite}},
{?eh,cth,{'_',id,[[test]]}},
{?eh,cth,{'_',init,['_',[test]]}},
@@ -1094,6 +1221,106 @@ test_events(state_update_cth) ->
{?eh,stop_logging,[]}
];
+test_events(update_result_cth) ->
+ Suite = ct_cth_update_result_post_end_tc_SUITE,
+ [
+ {?eh,start_logging,'_'},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,cth,{'_',init,['_',[]]}},
+ {?eh,tc_start,{Suite,init_per_suite}},
+ {?eh,tc_done,{Suite,init_per_suite,ok}},
+
+ {?eh,tc_start,{Suite,tc_ok_to_fail}},
+ {?eh,cth,{'_',post_end_per_testcase,[Suite,tc_ok_to_fail,'_',ok,[]]}},
+ {?eh,tc_done,{Suite,tc_ok_to_fail,{failed,{error,"Test failure"}}}},
+ {?eh,cth,{'_',on_tc_fail,'_'}},
+ {?eh,test_stats,{0,1,{0,0}}},
+
+ {?eh,tc_start,{Suite,tc_ok_to_skip}},
+ {?eh,cth,{'_',post_end_per_testcase,[Suite,tc_ok_to_skip,'_',ok,[]]}},
+ {?eh,tc_done,{Suite,tc_ok_to_skip,{skipped,"Test skipped"}}},
+ {?eh,cth,{'_',on_tc_skip,'_'}},
+ {?eh,test_stats,{0,1,{1,0}}},
+
+ {?eh,tc_start,{Suite,tc_fail_to_ok}},
+ {?eh,cth,{'_',post_end_per_testcase,
+ [Suite,tc_fail_to_ok,'_',
+ {error,{test_case_failed,"should be changed to ok"}},[]]}},
+ {?eh,tc_done,{Suite,tc_fail_to_ok,ok}},
+ {?eh,test_stats,{1,1,{1,0}}},
+
+ {?eh,tc_start,{Suite,tc_fail_to_skip}},
+ {?eh,cth,{'_',post_end_per_testcase,
+ [Suite,tc_fail_to_skip,'_',
+ {error,{test_case_failed,"should be changed to skip"}},[]]}},
+ {?eh,tc_done,{Suite,tc_fail_to_skip,{skipped,"Test skipped"}}},
+ {?eh,cth,{'_',on_tc_skip,'_'}},
+ {?eh,test_stats,{1,1,{2,0}}},
+
+ {?eh,tc_start,{Suite,tc_timetrap_to_ok}},
+ {?eh,cth,{'_',post_end_per_testcase,
+ [Suite,tc_timetrap_to_ok,'_',{timetrap_timeout,3000},[]]}},
+ {?eh,tc_done,{Suite,tc_timetrap_to_ok,ok}},
+ {?eh,test_stats,{2,1,{2,0}}},
+
+ {?eh,tc_start,{Suite,tc_timetrap_to_skip}},
+ {?eh,cth,{'_',post_end_per_testcase,
+ [Suite,tc_timetrap_to_skip,'_',{timetrap_timeout,3000},[]]}},
+ {?eh,tc_done,{Suite,tc_timetrap_to_skip,{skipped,"Test skipped"}}},
+ {?eh,cth,{'_',on_tc_skip,'_'}},
+ {?eh,test_stats,{2,1,{3,0}}},
+
+ {?eh,tc_start,{Suite,tc_skip_to_fail}},
+ {?eh,cth,{'_',post_end_per_testcase,
+ [Suite,tc_skip_to_fail,'_',
+ {skip,"should be changed to fail"},[]]}},
+ {?eh,tc_done,{Suite,tc_skip_to_fail,{failed,{error,"Test failure"}}}},
+ {?eh,cth,{'_',on_tc_fail,'_'}},
+ {?eh,test_stats,{2,2,{3,0}}},
+
+ {?eh,tc_start,{Suite,end_fail_to_fail}},
+ {?eh,cth,{'_',post_end_per_testcase,
+ [Suite,end_fail_to_fail,'_',
+ {failed,
+ {Suite,end_per_testcase,
+ {'EXIT',{test_case_failed,"change result when end fails"}}}},[]]}},
+ {?eh,tc_done,{Suite,end_fail_to_fail,{failed,{error,"Test failure"}}}},
+ {?eh,cth,{'_',on_tc_fail,'_'}},
+ {?eh,test_stats,{2,3,{3,0}}},
+
+ {?eh,tc_start,{Suite,end_fail_to_skip}},
+ {?eh,cth,{'_',post_end_per_testcase,
+ [Suite,end_fail_to_skip,'_',
+ {failed,
+ {Suite,end_per_testcase,
+ {'EXIT',{test_case_failed,"change result when end fails"}}}},[]]}},
+ {?eh,tc_done,{Suite,end_fail_to_skip,{skipped,"Test skipped"}}},
+ {?eh,cth,{'_',on_tc_skip,'_'}},
+ {?eh,test_stats,{2,3,{4,0}}},
+
+ {?eh,tc_start,{Suite,end_timetrap_to_fail}},
+ {?eh,cth,{'_',post_end_per_testcase,
+ [Suite,end_timetrap_to_fail,'_',
+ {failed,{Suite,end_per_testcase,{timetrap_timeout,3000}}},[]]}},
+ {?eh,tc_done,{Suite,end_timetrap_to_fail,{failed,{error,"Test failure"}}}},
+ {?eh,cth,{'_',on_tc_fail,'_'}},
+ {?eh,test_stats,{2,4,{4,0}}},
+
+ {?eh,tc_start,{Suite,end_timetrap_to_skip}},
+ {?eh,cth,{'_',post_end_per_testcase,
+ [Suite,end_timetrap_to_skip,'_',
+ {failed,{Suite,end_per_testcase,{timetrap_timeout,3000}}},[]]}},
+ {?eh,tc_done,{Suite,end_timetrap_to_skip,{skipped,"Test skipped"}}},
+ {?eh,cth,{'_',on_tc_skip,'_'}},
+ {?eh,test_stats,{2,4,{5,0}}},
+
+ {?eh,tc_start,{Suite,end_per_suite}},
+ {?eh,tc_done,{Suite,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,cth,{'_',terminate,[[]]}},
+ {?eh,stop_logging,[]}
+ ];
+
test_events(options_cth) ->
[
{?eh,start_logging,{'DEF','RUNDIR'}},
@@ -2204,6 +2431,229 @@ test_events(config_clash) ->
%% Make sure no 'cth_error' events are received!
[{negative,{?eh,cth_error,'_'},E} || E <- Events];
+test_events(alter_groups) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,cth,{empty_cth,id,[[]]}},
+ {?eh,cth,{empty_cth,init,[{'_','_','_'},[]]}},
+ {?eh,cth,{empty_cth,post_groups,[all_and_groups_SUITE,
+ [{new_group,[tc1,tc2]}]]}},
+ {?eh,cth,{empty_cth,post_all,[all_and_groups_SUITE,[{group,new_group}],
+ [{new_group,[tc1,tc2]}]]}},
+ {?eh,start_info,{1,1,2}},
+ {?eh,cth,{empty_cth,post_groups,[all_and_groups_SUITE,
+ [{new_group,[tc1,tc2]}]]}},
+ {?eh,cth,{empty_cth,post_all,[all_and_groups_SUITE,[{group,new_group}],
+ [{new_group,[tc1,tc2]}]]}},
+ {?eh,tc_start,{all_and_groups_SUITE,{init_per_group,new_group,[]}}},
+ {?eh,tc_done,{all_and_groups_SUITE,
+ {init_per_group,new_group,'$proplist'},ok}},
+ {?eh,tc_start,{all_and_groups_SUITE,tc1}},
+ {?eh,tc_done,{all_and_groups_SUITE,tc1,ok}},
+ {?eh,tc_start,{all_and_groups_SUITE,tc2}},
+ {?eh,tc_done,{all_and_groups_SUITE,tc2,ok}},
+ {?eh,tc_start,{all_and_groups_SUITE,{end_per_group,new_group,[]}}},
+ {?eh,tc_done,{all_and_groups_SUITE,
+ {end_per_group,new_group,'$proplist'},ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,cth,{empty_cth,terminate,[[]]}},
+ {?eh,stop_logging,[]}
+ ];
+
+test_events(alter_all) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,cth,{empty_cth,id,[[]]}},
+ {?eh,cth,{empty_cth,init,[{'_','_','_'},[]]}},
+ {?eh,cth,{empty_cth,post_groups,[all_and_groups_SUITE,
+ [{test_group,[tc1]}]]}},
+ {?eh,cth,{empty_cth,post_all,[all_and_groups_SUITE,[tc2],
+ [{test_group,[tc1]}]]}},
+ {?eh,start_info,{1,1,1}},
+ {?eh,cth,{empty_cth,post_groups,[all_and_groups_SUITE,'_']}},
+ {?eh,cth,{empty_cth,post_all,[all_and_groups_SUITE,[tc2],'_']}},
+ {?eh,tc_start,{all_and_groups_SUITE,tc2}},
+ {?eh,tc_done,{all_and_groups_SUITE,tc2,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,cth,{empty_cth,terminate,[[]]}},
+ {?eh,stop_logging,[]}
+ ];
+
+test_events(alter_all_from_skip) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,cth,{empty_cth,id,[[]]}},
+ {?eh,cth,{empty_cth,init,[{'_','_','_'},[]]}},
+ {?eh,cth,{empty_cth,post_groups,[all_and_groups_SUITE,
+ [{test_group,[tc1]}]]}},
+ {?eh,cth,{empty_cth,post_all,[all_and_groups_SUITE,[tc2],
+ [{test_group,[tc1]}]]}},
+ {?eh,start_info,{1,1,1}},
+ {?eh,cth,{empty_cth,post_groups,[all_and_groups_SUITE,'_']}},
+ {?eh,cth,{empty_cth,post_all,[all_and_groups_SUITE,[tc2],'_']}},
+ {?eh,tc_start,{all_and_groups_SUITE,tc2}},
+ {?eh,tc_done,{all_and_groups_SUITE,tc2,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,cth,{empty_cth,terminate,[[]]}},
+ {?eh,stop_logging,[]}
+ ];
+
+test_events(alter_all_to_skip) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,cth,{empty_cth,id,[[]]}},
+ {?eh,cth,{empty_cth,init,[{'_','_','_'},[]]}},
+ {?eh,cth,{empty_cth,post_groups,[all_and_groups_SUITE,
+ [{test_group,[tc1]}]]}},
+ {?eh,cth,{empty_cth,post_all,[all_and_groups_SUITE,
+ {skip,"skipped by post_all/3"},
+ [{test_group,[tc1]}]]}},
+ {?eh,start_info,{1,1,0}},
+ {?eh,cth,{empty_cth,post_groups,[all_and_groups_SUITE,'_']}},
+ {?eh,cth,{empty_cth,post_all,[all_and_groups_SUITE,
+ {skip,"skipped by post_all/3"},
+ '_']}},
+ {?eh,tc_user_skip,{all_and_groups_SUITE,all,"skipped by post_all/3"}},
+ {?eh,cth,{'_',on_tc_skip,[all_and_groups_SUITE,all,
+ {tc_user_skip,"skipped by post_all/3"},
+ []]}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,cth,{empty_cth,terminate,[[]]}},
+ {?eh,stop_logging,[]}
+ ];
+
+test_events(illegal_values_groups) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,cth,{empty_cth,id,[[]]}},
+ {?eh,cth,{empty_cth,init,[{'_','_','_'},[]]}},
+ {?eh,cth,{empty_cth,post_groups,
+ [all_and_groups_SUITE,
+ [{new_group,[this_test_does_not_exist]},
+ this_is_not_a_group_def]]}},
+ {?eh,start_info,{1,0,0}},
+ {?eh,cth,{empty_cth,post_groups,
+ [all_and_groups_SUITE,
+ [{new_group,[this_test_does_not_exist]},
+ this_is_not_a_group_def]]}},
+ {?eh,tc_start,{ct_framework,error_in_suite}},
+ {?eh,tc_done,{ct_framework,error_in_suite,{failed,{error,'_'}}}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,cth,{empty_cth,terminate,[[]]}},
+ {?eh,stop_logging,[]}
+ ];
+
+test_events(illegal_values_all) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,cth,{empty_cth,id,[[]]}},
+ {?eh,cth,{empty_cth,init,[{'_','_','_'},[]]}},
+ {?eh,cth,{empty_cth,post_groups,[all_and_groups_SUITE,'_']}},
+ {?eh,cth,{empty_cth,post_all,
+ [all_and_groups_SUITE,
+ [{group,this_group_does_not_exist},
+ {this_is_not_a_valid_term}],'_']}},
+ {?eh,start_info,{1,0,0}},
+ {?eh,cth,{empty_cth,post_groups,[all_and_groups_SUITE,'_']}},
+ {?eh,cth,{empty_cth,post_all,
+ [all_and_groups_SUITE,
+ [{group,this_group_does_not_exist},
+ {this_is_not_a_valid_term}],'_']}},
+ {?eh,tc_start,{ct_framework,error_in_suite}},
+ {?eh,tc_done,
+ {ct_framework,error_in_suite,
+ {failed,
+ {error,'Invalid reference to group this_group_does_not_exist in all_and_groups_SUITE:all/0'}}}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,cth,{empty_cth,terminate,[[]]}},
+ {?eh,stop_logging,[]}
+ ];
+
+test_events(bad_return_groups) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,cth,{empty_cth,id,[[]]}},
+ {?eh,cth,{empty_cth,init,[{'_','_','_'},[]]}},
+ {?eh,cth,{empty_cth,post_groups,[all_and_groups_SUITE,not_a_list]}},
+ {?eh,start_info,{1,0,0}},
+ {?eh,cth,{empty_cth,post_groups,[all_and_groups_SUITE,not_a_list]}},
+ {?eh,tc_start,{ct_framework,error_in_suite}},
+ {?eh,tc_done,
+ {ct_framework,error_in_suite,
+ {failed,
+ {error,
+ {'Bad return value from post_groups/2 hook function',not_a_list}}}}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,cth,{empty_cth,terminate,[[]]}},
+ {?eh,stop_logging,[]}
+ ];
+
+test_events(bad_return_all) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,cth,{empty_cth,id,[[]]}},
+ {?eh,cth,{empty_cth,init,[{'_','_','_'},[]]}},
+ {?eh,cth,{empty_cth,post_groups,[all_and_groups_SUITE,'_']}},
+ {?eh,cth,{empty_cth,post_all,[all_and_groups_SUITE,not_a_list,'_']}},
+ {?eh,start_info,{1,0,0}},
+ {?eh,cth,{empty_cth,post_groups,[all_and_groups_SUITE,'_']}},
+ {?eh,cth,{empty_cth,post_all,[all_and_groups_SUITE,not_a_list,'_']}},
+ {?eh,tc_start,{ct_framework,error_in_suite}},
+ {?eh,tc_done,
+ {ct_framework,error_in_suite,
+ {failed,
+ {error,{'Bad return value from post_all/3 hook function',not_a_list}}}}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,cth,{empty_cth,terminate,[[]]}},
+ {?eh,stop_logging,[]}
+ ];
+
+test_events(crash_groups) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,cth,{empty_cth,id,[[]]}},
+ {?eh,cth,{empty_cth,init,[{'_','_','_'},[]]}},
+ {?eh,cth,{empty_cth,post_groups,[all_and_groups_SUITE,crash]}},
+ {?eh,start_info,{1,0,0}},
+ {?eh,cth,{empty_cth,post_groups,[all_and_groups_SUITE,crash]}},
+ {?eh,tc_start,{ct_framework,error_in_suite}},
+ {?eh,tc_done,{ct_framework,error_in_suite,
+ {failed,
+ {error,"all_and_groups_cth:post_groups/2 CTH call failed"}}}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,cth,{empty_cth,terminate,[[]]}},
+ {?eh,stop_logging,[]}
+ ];
+
+test_events(crash_all) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,cth,{empty_cth,id,[[]]}},
+ {?eh,cth,{empty_cth,init,[{'_','_','_'},[]]}},
+ {?eh,cth,{empty_cth,post_groups,[all_and_groups_SUITE,'_']}},
+ {?eh,cth,{empty_cth,post_all,[all_and_groups_SUITE,crash,'_']}},
+ {?eh,start_info,{1,0,0}},
+ {?eh,cth,{empty_cth,post_groups,[all_and_groups_SUITE,'_']}},
+ {?eh,cth,{empty_cth,post_all,[all_and_groups_SUITE,crash,'_']}},
+ {?eh,tc_start,{ct_framework,error_in_suite}},
+ {?eh,tc_done,{ct_framework,error_in_suite,
+ {failed,
+ {error,"all_and_groups_cth:post_all/3 CTH call failed"}}}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,cth,{empty_cth,terminate,[[]]}},
+ {?eh,stop_logging,[]}
+ ];
+
test_events(ok) ->
ok.
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/all_and_groups_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/all_and_groups_SUITE.erl
new file mode 100644
index 0000000000..adc86005f9
--- /dev/null
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/all_and_groups_SUITE.erl
@@ -0,0 +1,47 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(all_and_groups_SUITE).
+
+-suite_defaults([{timetrap, {minutes, 10}}]).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include("ct.hrl").
+
+init_per_group(_Group,Config) ->
+ Config.
+
+end_per_group(_Group,Config) ->
+ ok.
+
+all() ->
+ ct:get_config(all_return,[{group,test_group}]).
+
+groups() ->
+ [{test_group,[tc1]}].
+
+%% Test cases starts here.
+tc1(Config) ->
+ ok.
+
+tc2(Config) ->
+ ok.
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/all_and_groups_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/all_and_groups_cth.erl
new file mode 100644
index 0000000000..9ebc00e9de
--- /dev/null
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/all_and_groups_cth.erl
@@ -0,0 +1,100 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+
+-module(all_and_groups_cth).
+
+
+-include_lib("common_test/src/ct_util.hrl").
+-include_lib("common_test/include/ct_event.hrl").
+
+%% Send a cth_error event if a callback is called with unexpected arguments
+-define(fail(Info),
+ gen_event:notify(
+ ?CT_EVMGR_REF,
+ #event{ name = cth_error,
+ node = node(),
+ data = {illegal_hook_callback,{?MODULE,?FUNCTION_NAME,Info}}})).
+
+%% CT Hooks
+-compile(export_all).
+
+id(Opts) ->
+ empty_cth:id(Opts).
+
+post_groups(Suite,Groups) ->
+ case empty_cth:post_groups(Suite,ct:get_config(post_groups_return,Groups)) of
+ crash -> error(crash_in_post_groups);
+ R -> R
+ end.
+
+post_all(Suite,Tests,Groups) ->
+ case empty_cth:post_all(Suite,ct:get_config(post_all_return,Tests),Groups) of
+ crash -> error(crash_in_post_all);
+ R -> R
+ end.
+
+init(Id, Opts) ->
+ empty_cth:init(Id, Opts).
+
+pre_init_per_suite(Suite, Config, State) ->
+ empty_cth:pre_init_per_suite(Suite,Config,State).
+
+post_init_per_suite(Suite,Config,Return,State) ->
+ empty_cth:post_init_per_suite(Suite,Config,Return,State).
+
+pre_end_per_suite(Suite,Config,State) ->
+ empty_cth:pre_end_per_suite(Suite,Config,State).
+
+post_end_per_suite(Suite,Config,Return,State) ->
+ empty_cth:post_end_per_suite(Suite,Config,Return,State).
+
+pre_init_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_init_per_group(Suite,Group,Config,State).
+
+post_init_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_init_per_group(Suite,Group,Config,Return,State).
+
+pre_end_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_end_per_group(Suite,Group,Config,State).
+
+post_end_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_end_per_group(Suite,Group,Config,Return,State).
+
+pre_init_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_init_per_testcase(Suite,TC,Config,State).
+
+post_init_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_init_per_testcase(Suite,TC,Config,Return,State).
+
+pre_end_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_end_per_testcase(Suite,TC,Config,State).
+
+post_end_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_end_per_testcase(Suite,TC,Config,Return,State).
+
+on_tc_fail(Suite,TC,Reason,State) ->
+ empty_cth:on_tc_fail(Suite,TC,Reason,State).
+
+on_tc_skip(Suite,TC,Reason,State) ->
+ empty_cth:on_tc_skip(Suite,TC,Reason,State).
+
+terminate(State) ->
+ empty_cth:terminate(State).
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_cth_update_result_post_end_tc_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_cth_update_result_post_end_tc_SUITE.erl
new file mode 100644
index 0000000000..a16138ce6f
--- /dev/null
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_cth_update_result_post_end_tc_SUITE.erl
@@ -0,0 +1,101 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(ct_cth_update_result_post_end_tc_SUITE).
+
+-compile(export_all).
+
+-include("ct.hrl").
+
+suite() ->
+ [{timetrap,{seconds,3}}].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(Config) ->
+ ok.
+
+init_per_group(_,Config) ->
+ Config.
+
+end_per_group(_,_) ->
+ ok.
+
+init_per_testcase(_,Config) ->
+ Config.
+
+end_per_testcase(EndTimetrap,_) when EndTimetrap==end_timetrap_to_fail;
+ EndTimetrap==end_timetrap_to_skip->
+ timer:sleep(10000);
+end_per_testcase(EndFail,_) when EndFail==end_fail_to_fail;
+ EndFail==end_fail_to_skip->
+ ct:fail("change result when end fails");
+end_per_testcase(_,_) ->
+ ok.
+
+all() ->
+ [tc_ok_to_fail,
+ tc_ok_to_skip,
+ tc_fail_to_ok,
+ tc_fail_to_skip,
+ tc_timetrap_to_ok,
+ tc_timetrap_to_skip,
+ tc_skip_to_fail,
+ end_fail_to_fail,
+ end_fail_to_skip,
+ end_timetrap_to_fail,
+ end_timetrap_to_skip].
+
+%% Test cases starts here.
+tc_ok_to_fail(_Config) ->
+ ok.
+
+tc_ok_to_skip(_Config) ->
+ ok.
+
+tc_fail_to_ok(_Config) ->
+ ct:fail("should be changed to ok").
+
+tc_fail_to_skip(_Config) ->
+ ct:fail("should be changed to skip").
+
+tc_timetrap_to_ok(_Config) ->
+ timer:sleep(10000), % will time out after 3 sek
+ ok.
+
+tc_timetrap_to_skip(_Config) ->
+ timer:sleep(10000), % will time out after 3 sek
+ ok.
+
+tc_skip_to_fail(_Config) ->
+ {skip,"should be changed to fail"}.
+
+end_fail_to_fail(_Config) ->
+ ok.
+
+end_fail_to_skip(_Config) ->
+ ok.
+
+end_timetrap_to_fail(_Config) ->
+ ok.
+
+end_timetrap_to_skip(_Config) ->
+ ok.
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_match_state_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_match_state_cth.erl
new file mode 100644
index 0000000000..38c9da903d
--- /dev/null
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_match_state_cth.erl
@@ -0,0 +1,58 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+
+-module(ct_match_state_cth).
+
+
+-include_lib("common_test/src/ct_util.hrl").
+-include_lib("common_test/include/ct_event.hrl").
+
+-compile(export_all).
+
+id(Opts) ->
+ empty_cth:id(Opts).
+
+post_groups(Suite, Groups) ->
+ empty_cth:post_groups(Suite, Groups).
+
+post_all(Suite, Tests, Groups) ->
+ empty_cth:post_all(Suite, Tests, Groups).
+
+init(Id, Opts) ->
+ empty_cth:init(Id, Opts),
+ {ok,mystate}.
+
+%% In the following, always match against the state value, to ensure
+%% that init has indeed been called before the rest of the hooks.
+pre_init_per_suite(Suite,Config,mystate) ->
+ empty_cth:pre_init_per_suite(Suite,Config,mystate).
+
+post_init_per_suite(Suite,Config,Return,mystate) ->
+ empty_cth:post_init_per_suite(Suite,Config,Return,mystate).
+
+pre_end_per_suite(Suite,Config,mystate) ->
+ empty_cth:pre_end_per_suite(Suite,Config,mystate).
+
+post_end_per_suite(Suite,Config,Return,mystate) ->
+ empty_cth:post_end_per_suite(Suite,Config,Return,mystate).
+
+terminate(mystate) ->
+ empty_cth:terminate(mystate).
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_scope_per_tc_cth_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_scope_per_tc_cth_SUITE.erl
index d400348354..404fb33476 100644
--- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_scope_per_tc_cth_SUITE.erl
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_scope_per_tc_cth_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,7 +29,6 @@
%% Test server callback functions
%%--------------------------------------------------------------------
-%% @doc
%% Config - [tuple()]
%% A list of key/value pairs, holding the test case configuration.
%%
@@ -38,27 +37,23 @@
%% Note: This function is free to add any key/value pairs to the Config
%% variable, but should NOT alter/remove any existing entries.
%%
-%% @spec init_per_suite(Config) -> Config
-%% @end
+%% -spec init_per_suite(Config) -> Config
%%--------------------------------------------------------------------
init_per_suite(Config) ->
Config.
%%--------------------------------------------------------------------
-%% @doc
%% Config - [tuple()]
%% A list of key/value pairs, holding the test case configuration.
%%
%% Cleanup after the whole suite
%%
-%% @spec end_per_suite(Config) -> _
-%% @end
+%% -spec end_per_suite(Config) -> _
%%--------------------------------------------------------------------
end_per_suite(_Config) ->
ok.
%%--------------------------------------------------------------------
-%% @doc
%% Case - atom()
%% Name of the test case that is about to be run.
%% Config - [tuple()]
@@ -70,14 +65,12 @@ end_per_suite(_Config) ->
%% variable, but should NOT alter/remove any existing entries.
%% Initiation before each test case
%%
-%% @spec init_per_testcase(TestCase, Config) -> Config
-%% @end
+%% -spec init_per_testcase(TestCase, Config) -> Config
%%--------------------------------------------------------------------
init_per_testcase(_TestCase, Config) ->
[{ct_hooks,[empty_cth]}|Config].
%%--------------------------------------------------------------------
-%% @doc
%% Case - atom()
%% Name of the test case that is about to be run.
%% Config - [tuple()]
@@ -85,22 +78,19 @@ init_per_testcase(_TestCase, Config) ->
%%
%% Cleanup after each test case
%%
-%% @spec end_per_testcase(TestCase, Config) -> _
-%% @end
+%% -spec end_per_testcase(TestCase, Config) -> _
%%--------------------------------------------------------------------
end_per_testcase(_TestCase, _Config) ->
ok.
%%--------------------------------------------------------------------
-%% @doc
%% TestCases - [Case]
%% Case - atom()
%% Name of a test case.
%%
%% Returns a list of all test cases in this test suite
%%
-%% @spec all() -> TestCases
-%% @end
+%% -spec all() -> TestCases
%%--------------------------------------------------------------------
all() ->
[test_case].
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_scope_suite_group_only_cth_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_scope_suite_group_only_cth_SUITE.erl
new file mode 100644
index 0000000000..537c97d3f0
--- /dev/null
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_scope_suite_group_only_cth_SUITE.erl
@@ -0,0 +1,54 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(ct_scope_suite_group_only_cth_SUITE).
+
+-suite_defaults([{timetrap, {minutes, 10}}]).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include("ct.hrl").
+
+%% Test server callback functions
+suite() ->
+ [{ct_hooks,[ct_match_state_cth]}].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+end_per_testcase(_TestCase, _Config) ->
+ ok.
+
+all() ->
+ [test_case].
+
+groups() ->
+ [{g1,[test_case]}].
+
+%% Test cases starts here.
+test_case(Config) when is_list(Config) ->
+ ok.
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/cth_log_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/cth_log_SUITE.erl
index bd1ac54781..eda190b682 100644
--- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/cth_log_SUITE.erl
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/cth_log_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -124,6 +124,6 @@ gen() ->
gen_loop(N) ->
ct:log("Logger iteration: ~p", [N]),
error_logger:error_report(N),
- error_logger:info_report(progress, N),
+ error_logger:info_report(N),
ct:sleep(150),
gen_loop(N+1).
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl
index 961ea68d2d..60488e84c6 100644
--- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,9 +18,9 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Example Suite Callback module.
+%%% Common Test Example Suite Callback module.
%%%
-%%% <p>This module gives an example of a common test CTH (Common Test Hook).
+%%% This module gives an example of a common test CTH (Common Test Hook).
%%% There are many ways to add a CTH to a test run, you can do it either in
%%% the command line using -ct_hook, in a test spec using
%%% {ct_hook,M} or in the suite it self by returning ct_hook
@@ -31,7 +31,7 @@
%%% it will be stopped after end_per_suite and so on. See terminate
%%% documentation for a table describing the scoping machanics.
%%%
-%%% All of callbacks except init/1 in a CTH are optional.</p>
+%%% All of callbacks except init/1 in a CTH are optional.
-module(empty_cth).
@@ -39,6 +39,9 @@
-export([id/1]).
-export([init/2]).
+-export([post_all/3]).
+-export([post_groups/2]).
+
-export([pre_init_per_suite/3]).
-export([post_init_per_suite/4]).
-export([pre_end_per_suite/3]).
@@ -71,7 +74,32 @@
-record(state, { id = ?MODULE :: term()}).
-%% @doc Always called before any other callback function. Use this to initiate
+%% Called after groups/0.
+%% You can change the return value in this function.
+-spec post_groups(Suite :: atom(), Groups :: list()) -> list().
+post_groups(Suite,Groups) ->
+ gen_event:notify(
+ ?CT_EVMGR_REF, #event{ name = cth, node = node(),
+ data = {?MODULE, post_groups,
+ [Suite,Groups]}}),
+ ct:log("~w:post_groups(~w) called", [?MODULE,Suite]),
+ Groups.
+
+%% Called after all/0.
+%% You can change the return value in this function.
+-spec post_all(Suite :: atom(),
+ Tests :: list(),
+ Groups :: term()) ->
+ list().
+post_all(Suite,Tests,Groups) ->
+ gen_event:notify(
+ ?CT_EVMGR_REF, #event{ name = cth, node = node(),
+ data = {?MODULE, post_all,
+ [Suite,Tests,Groups]}}),
+ ct:log("~w:post_all(~w) called", [?MODULE,Suite]),
+ Tests.
+
+%% Always called before any other callback function. Use this to initiate
%% any common state. It should return an state for this CTH.
-spec init(Id :: term(), Opts :: proplists:proplist()) ->
{ok, State :: #state{}}.
@@ -81,7 +109,7 @@ init(Id, Opts) ->
ct:log("~w:init called", [?MODULE]),
{ok,Opts}.
-%% @doc The ID is used to uniquly identify an CTH instance, if two CTH's
+%% The ID is used to uniquly identify an CTH instance, if two CTH's
%% return the same ID the seconds CTH is ignored. This function should NOT
%% have any side effects as it might be called multiple times by common test.
-spec id(Opts :: proplists:proplist()) ->
@@ -92,7 +120,7 @@ id(Opts) ->
ct:log("~w:id called", [?MODULE]),
ct_test_support:unique_timestamp().
-%% @doc Called before init_per_suite is called. Note that this callback is
+%% Called before init_per_suite is called. Note that this callback is
%% only called if the CTH is added before init_per_suite is run (eg. in a test
%% specification, suite/0 function etc).
%% You can change the config in the this function.
@@ -108,7 +136,7 @@ pre_init_per_suite(Suite,Config,State) ->
ct:log("~w:pre_init_per_suite(~w) called", [?MODULE,Suite]),
{Config, State}.
-%% @doc Called after init_per_suite.
+%% Called after init_per_suite.
%% you can change the return value in this function.
-spec post_init_per_suite(Suite :: atom(),
Config :: config(),
@@ -123,7 +151,7 @@ post_init_per_suite(Suite,Config,Return,State) ->
ct:log("~w:post_init_per_suite(~w) called", [?MODULE,Suite]),
{Return, State}.
-%% @doc Called before end_per_suite. The config/state can be changed here,
+%% Called before end_per_suite. The config/state can be changed here,
%% though it will only affect the *end_per_suite function.
-spec pre_end_per_suite(Suite :: atom(),
Config :: config() | skip_or_fail(),
@@ -137,7 +165,7 @@ pre_end_per_suite(Suite,Config,State) ->
ct:log("~w:pre_end_per_suite(~w) called", [?MODULE,Suite]),
{Config, State}.
-%% @doc Called after end_per_suite. Note that the config cannot be
+%% Called after end_per_suite. Note that the config cannot be
%% changed here, only the status of the suite.
-spec post_end_per_suite(Suite :: atom(),
Config :: config(),
@@ -152,7 +180,7 @@ post_end_per_suite(Suite,Config,Return,State) ->
ct:log("~w:post_end_per_suite(~w) called", [?MODULE,Suite]),
{Return, State}.
-%% @doc Called before each init_per_group.
+%% Called before each init_per_group.
%% You can change the config in this function.
-spec pre_init_per_group(Suite :: atom(),
Group :: atom(),
@@ -167,7 +195,7 @@ pre_init_per_group(Suite,Group,Config,State) ->
ct:log("~w:pre_init_per_group(~w,~w) called", [?MODULE,Suite,Group]),
{Config, State}.
-%% @doc Called after each init_per_group.
+%% Called after each init_per_group.
%% You can change the return value in this function.
-spec post_init_per_group(Suite :: atom(),
Group :: atom(),
@@ -183,7 +211,7 @@ post_init_per_group(Suite,Group,Config,Return,State) ->
ct:log("~w:post_init_per_group(~w,~w) called", [?MODULE,Suite,Group]),
{Return, State}.
-%% @doc Called after each end_per_group. The config/state can be changed here,
+%% Called after each end_per_group. The config/state can be changed here,
%% though it will only affect the *end_per_group functions.
-spec pre_end_per_group(Suite :: atom(),
Group :: atom(),
@@ -198,7 +226,7 @@ pre_end_per_group(Suite,Group,Config,State) ->
ct:log("~w:pre_end_per_group(~w~w) called", [?MODULE,Suite,Group]),
{Config, State}.
-%% @doc Called after each end_per_group. Note that the config cannot be
+%% Called after each end_per_group. Note that the config cannot be
%% changed here, only the status of the group.
-spec post_end_per_group(Suite :: atom(),
Group :: atom(),
@@ -214,7 +242,7 @@ post_end_per_group(Suite,Group,Config,Return,State) ->
ct:log("~w:post_end_per_group(~w,~w) called", [?MODULE,Suite,Group]),
{Return, State}.
-%% @doc Called before init_per_testcase/2 for each test case.
+%% Called before init_per_testcase/2 for each test case.
%% You can change the config in this function.
-spec pre_init_per_testcase(Suite :: atom(),
TC :: atom(),
@@ -229,7 +257,7 @@ pre_init_per_testcase(Suite,TC,Config,State) ->
ct:log("~w:pre_init_per_testcase(~w,~w) called", [?MODULE,Suite,TC]),
{Config, State}.
-%% @doc Called after init_per_testcase/2, and before the test case.
+%% Called after init_per_testcase/2, and before the test case.
-spec post_init_per_testcase(Suite :: atom(),
TC :: atom(),
Config :: config(),
@@ -244,7 +272,7 @@ post_init_per_testcase(Suite,TC,Config,Return,State) ->
ct:log("~w:post_init_per_testcase(~w,~w) called", [?MODULE,Suite,TC]),
{Return, State}.
-%% @doc Called before end_per_testacse/2. No skip or fail allowed here,
+%% Called before end_per_testacse/2. No skip or fail allowed here,
%% only config additions.
-spec pre_end_per_testcase(Suite :: atom(),
TC :: atom(),
@@ -259,7 +287,7 @@ pre_end_per_testcase(Suite,TC,Config,State) ->
ct:log("~w:pre_end_per_testcase(~w,~w) called", [?MODULE,Suite,TC]),
{Config, State}.
-%% @doc Called after end_per_testcase/2 for each test case. Note that
+%% Called after end_per_testcase/2 for each test case. Note that
%% the config cannot be changed here, only the status of the test case.
-spec post_end_per_testcase(Suite :: atom(),
TC :: atom(),
@@ -275,7 +303,7 @@ post_end_per_testcase(Suite,TC,Config,Return,State) ->
ct:log("~w:post_end_per_testcase(~w,~w) called", [?MODULE,Suite,TC]),
{Return, State}.
-%% @doc Called after post_init_per_suite, post_end_per_suite, post_init_per_group,
+%% Called after post_init_per_suite, post_end_per_suite, post_init_per_group,
%% post_end_per_group and post_end_per_tc if the suite, group or test case failed.
%% This function should be used for extra cleanup which might be needed.
%% It is not possible to modify the config or the status of the test run.
@@ -292,7 +320,7 @@ on_tc_fail(Suite, TC, Reason, State) ->
ct:log("~w:on_tc_fail(~w,~w) called", [?MODULE,Suite,TC]),
State.
-%% @doc Called when a test case is skipped by either user action
+%% Called when a test case is skipped by either user action
%% or due to an init function failing. Test case can be
%% end_per_suite, init_per_group, end_per_group and the actual test cases.
-spec on_tc_skip(Suite :: atom(),
@@ -310,7 +338,7 @@ on_tc_skip(Suite, TC, Reason, State) ->
ct:log("~w:on_tc_skip(~w,~w) called", [?MODULE,Suite,TC]),
State.
-%% @doc Called when the scope of the CTH is done, this depends on
+%% Called when the scope of the CTH is done, this depends on
%% when the CTH was specified. This translation table describes when this
%% function is called.
%%
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/update_result_post_end_tc_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/update_result_post_end_tc_cth.erl
new file mode 100644
index 0000000000..7afb3d8781
--- /dev/null
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/update_result_post_end_tc_cth.erl
@@ -0,0 +1,98 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+
+-module(update_result_post_end_tc_cth).
+
+
+-include_lib("common_test/src/ct_util.hrl").
+-include_lib("common_test/include/ct_event.hrl").
+
+
+%% CT Hooks
+-compile(export_all).
+
+init(Id, Opts) ->
+ empty_cth:init(Id, Opts).
+
+pre_init_per_suite(Suite, Config, State) ->
+ empty_cth:pre_init_per_suite(Suite,Config,State).
+
+post_init_per_suite(Suite,Config,Return,State) ->
+ empty_cth:post_init_per_suite(Suite,Config,Return,State).
+
+pre_end_per_suite(Suite,Config,State) ->
+ empty_cth:pre_end_per_suite(Suite,Config,State).
+
+post_end_per_suite(Suite,Config,Return,State) ->
+ empty_cth:post_end_per_suite(Suite,Config,Return,State).
+
+pre_init_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_init_per_group(Suite,Group,Config,State).
+
+post_init_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_init_per_group(Suite,Group,Config,Return,State).
+
+pre_end_per_group(Suite,Group,Config,State) ->
+ empty_cth:pre_end_per_group(Suite,Group,Config,State).
+
+post_end_per_group(Suite,Group,Config,Return,State) ->
+ empty_cth:post_end_per_group(Suite,Group,Config,Return,State).
+
+pre_init_per_testcase(Suite,TC,Config,State) ->
+ empty_cth:pre_init_per_testcase(Suite,TC,Config,State).
+
+post_end_per_testcase(Suite,TC,Config,Return,State) ->
+ empty_cth:post_end_per_testcase(Suite,TC,Config,Return,State),
+ change_result(TC,Config,State).
+
+on_tc_fail(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_fail(Suite,TC,Reason,State).
+
+on_tc_skip(Suite,TC, Reason, State) ->
+ empty_cth:on_tc_skip(Suite,TC,Reason,State).
+
+terminate(State) ->
+ empty_cth:terminate(State).
+
+%%%-----------------------------------------------------------------
+%%%
+change_result(tc_ok_to_fail,_Config,State) ->
+ {{fail, "Test failure"}, State};
+change_result(tc_ok_to_skip,_Config,State) ->
+ {{skip, "Test skipped"}, State};
+change_result(tc_fail_to_ok,Config,State) ->
+ {lists:keydelete(tc_status,1,Config),State};
+change_result(tc_fail_to_skip,Config,State) ->
+ {{skip,"Test skipped"},State};
+change_result(tc_timetrap_to_ok,Config,State) ->
+ {lists:keydelete(tc_status,1,Config),State};
+change_result(tc_timetrap_to_skip,Config,State) ->
+ {{skip,"Test skipped"},State};
+change_result(tc_skip_to_fail,_Config,State) ->
+ {{fail, "Test failure"}, State};
+change_result(end_fail_to_fail,_Config,State) ->
+ {{fail, "Test failure"}, State};
+change_result(end_fail_to_skip,_Config,State) ->
+ {{skip, "Test skipped"}, State};
+change_result(end_timetrap_to_fail,_Config,State) ->
+ {{fail, "Test failure"}, State};
+change_result(end_timetrap_to_skip,_Config,State) ->
+ {{skip, "Test skipped"}, State}.
diff --git a/lib/common_test/test/ct_log_SUITE.erl b/lib/common_test/test/ct_log_SUITE.erl
index 93affda398..214eb17e1a 100644
--- a/lib/common_test/test/ct_log_SUITE.erl
+++ b/lib/common_test/test/ct_log_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -174,7 +174,7 @@ verify(Config) ->
TcLogFile = proplists:get_value(the_logfile, SavedCfg),
Pid = proplists:get_value(the_pid, SavedCfg),
StrPid = lists:flatten(io_lib:format("~p",[Pid])),
- EscPid = "&lt;" ++ string:substr(StrPid, 2, length(StrPid)-2) ++ "&gt;",
+ EscPid = "&lt;" ++ string:slice(StrPid, 1, length(StrPid)-2) ++ "&gt;",
String = proplists:get_value(the_string, SavedCfg),
ct:log("Read from prev testcase: ~p & ~p", [TcLogFile,Pid]),
{ok,Dev} = file:open(TcLogFile, [read]),
diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
index 586589ad40..69a7de1431 100644
--- a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
+++ b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,9 +23,7 @@
%% Description:
%% This file contains the test cases for the ct_netconfc API.
%%
-%% @author Support
-%% @doc Netconf Client Interface.
-%% @end
+%% Netconf Client Interface.
%%----------------------------------------------------------------------
%%----------------------------------------------------------------------
-module(netconfc1_SUITE).
@@ -207,7 +205,7 @@ hello_required_exists(Config) ->
SshDir = ?config(ssh_dir,Config),
{ok,_Client1} = open_configured_success(my_named_connection,SshDir),
- %% Check that same name can not be used twice
+ %% Check that same name cannot be used twice
{error,{connection_exists,_Client1}} =
ct_netconfc:open(my_named_connection,[{user_dir,SshDir}]),
@@ -273,7 +271,7 @@ no_client_hello(Config) ->
%% Tell server to receive a get request and then die without
%% replying since no hello has been received. (is this correct
- %% behavoiur??)
+ %% behaviour??)
?NS:expect_do(get,close),
{error,closed} = ct_netconfc:get(Client,whatever),
ok.
@@ -387,7 +385,7 @@ timeout_get(Config) ->
%% received, the timeout message might already be sent when the timer
%% is cancelled. This test checks that the timeout message is flushed
%% from the message queue. If it isn't, the client crashes and the
-%% session can not be closed afterwards.
+%% session cannot be closed afterwards.
%% Note that we can only hope that the test case triggers the problem
%% every now and then, as it is very timing dependent...
flush_timeout_get(Config) ->
@@ -442,6 +440,12 @@ edit_config(Config) ->
?ok = ct_netconfc:edit_config(Client,running,
{server,[{xmlns,"myns"}],
[{name,["myserver"]}]}),
+ ?NS:expect_reply('edit-config',ok),
+ ?ok = ct_netconfc:edit_config(Client,running,
+ [{server,[{xmlns,"myns"}],
+ [{name,["server1"]}]},
+ {server,[{xmlns,"myns"}],
+ [{name,["server2"]}]}]),
?NS:expect_do_reply('close-session',close,ok),
?ok = ct_netconfc:close_session(Client),
ok.
diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl b/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl
index 63bf9be134..656fdb4a40 100644
--- a/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl
+++ b/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -231,8 +231,7 @@ data_for_channel(CM, Ch, Data, State) ->
{ok, NewState}
end
catch
- Class:Reason ->
- Stacktrace = erlang:get_stacktrace(),
+ Class:Reason:Stacktrace ->
error_logger:error_report([{?MODULE, data_for_channel},
{request, Data},
{buffer, State#session.buffer},
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 7ffe6f045b..bca2d5f3de 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
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -164,7 +164,7 @@ pre_post_io(Config) ->
fun(PrePostIoFile) ->
ct:log("Reading Pre/Post Test IO Log file: ~ts", [PrePostIoFile]),
{ok,Bin} = file:read_file(PrePostIoFile),
- Ts = string:tokens(binary_to_list(Bin),[$\n]),
+ Ts = string:lexemes(binary_to_list(Bin),[$\n]),
PrePostIOEntries =
lists:foldl(fun([$L,$o,$g,$g,$e,$r|_],
{pre,PreLogN,PreErrN,0,0}) ->
@@ -203,7 +203,7 @@ pre_post_io(Config) ->
fun(UnexpIoFile) ->
ct:log("Reading Unexpected IO Log file: ~ts", [UnexpIoFile]),
{ok,Bin} = file:read_file(UnexpIoFile),
- Ts = string:tokens(binary_to_list(Bin),[$\n]),
+ Ts = string:lexemes(binary_to_list(Bin),[$\n]),
UnexpIOEntries =
lists:foldl(fun([$L,$o,$g,$g,$e,$r|_], [LogN,ErrN]) ->
[LogN+1,ErrN];
@@ -241,7 +241,7 @@ try_loop(_Fun, 0) ->
gave_up;
try_loop(Fun, N) ->
try Fun() of
- {error,_} ->
+ {Error,_} when Error==error; Error==badrpc ->
timer:sleep(10),
try_loop(Fun, N-1);
Result ->
@@ -257,7 +257,7 @@ try_loop(M, F, _A, 0) ->
gave_up;
try_loop(M, F, A, N) ->
try apply(M, F, A) of
- {error,_} ->
+ {Error,_Reason} when Error==error; Error==badrpc ->
timer:sleep(10),
try_loop(M, F, A, N-1);
Result ->
diff --git a/lib/common_test/test/ct_priv_dir_SUITE_data/priv_dir_SUITE.erl b/lib/common_test/test/ct_priv_dir_SUITE_data/priv_dir_SUITE.erl
index 1b171801a3..0e10ec187d 100644
--- a/lib/common_test/test/ct_priv_dir_SUITE_data/priv_dir_SUITE.erl
+++ b/lib/common_test/test/ct_priv_dir_SUITE_data/priv_dir_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -126,12 +126,12 @@ default(Config) ->
auto_per_tc(Config) ->
PrivDir = proplists:get_value(priv_dir, Config),
- ["log_private",_] = string:tokens(filename:basename(PrivDir), "."),
+ ["log_private",_] = string:lexemes(filename:basename(PrivDir), "."),
{ok,_} = file:list_dir(PrivDir).
manual_per_tc(Config) ->
PrivDir = proplists:get_value(priv_dir, Config),
- ["log_private",_] = string:tokens(filename:basename(PrivDir), "."),
+ ["log_private",_] = string:lexemes(filename:basename(PrivDir), "."),
{error,_} = file:list_dir(PrivDir),
ok = ct:make_priv_dir(),
{ok,_} = file:list_dir(PrivDir).
diff --git a/lib/common_test/test/ct_repeat_testrun_SUITE_data/a_test/r1_SUITE.erl b/lib/common_test/test/ct_repeat_testrun_SUITE_data/a_test/r1_SUITE.erl
index 4ce375b4ee..1a305b1516 100644
--- a/lib/common_test/test/ct_repeat_testrun_SUITE_data/a_test/r1_SUITE.erl
+++ b/lib/common_test/test/ct_repeat_testrun_SUITE_data/a_test/r1_SUITE.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -19,14 +19,6 @@
%%
%%----------------------------------------------------------------------
%% File: r1_SUITE.erl
-%%
-%% Description:
-%%
-%%
-%% @author Support
-%% @doc
-%% @end
-%%----------------------------------------------------------------------
%%----------------------------------------------------------------------
-module(r1_SUITE).
-include_lib("common_test/include/ct.hrl").
diff --git a/lib/common_test/test/ct_repeat_testrun_SUITE_data/b_test/r2_SUITE.erl b/lib/common_test/test/ct_repeat_testrun_SUITE_data/b_test/r2_SUITE.erl
index 77bb544080..393cbcc780 100644
--- a/lib/common_test/test/ct_repeat_testrun_SUITE_data/b_test/r2_SUITE.erl
+++ b/lib/common_test/test/ct_repeat_testrun_SUITE_data/b_test/r2_SUITE.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -19,14 +19,6 @@
%%
%%----------------------------------------------------------------------
%% File: r2_SUITE.erl
-%%
-%% Description:
-%%
-%%
-%% @author Support
-%% @doc
-%% @end
-%%----------------------------------------------------------------------
%%----------------------------------------------------------------------
-module(r2_SUITE).
-include_lib("common_test/include/ct.hrl").
diff --git a/lib/common_test/test/ct_snmp_SUITE_data/snmp_SUITE.erl b/lib/common_test/test/ct_snmp_SUITE_data/snmp_SUITE.erl
index a6533641d8..1c81bbe95d 100644
--- a/lib/common_test/test/ct_snmp_SUITE_data/snmp_SUITE.erl
+++ b/lib/common_test/test/ct_snmp_SUITE_data/snmp_SUITE.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,9 +23,7 @@
%% Description:
%% This file contains the test cases for the ct_snmp API.
%%
-%% @author Support
-%% @doc Test of SNMP support in common_test
-%% @end
+%% Test of SNMP support in common_test
%%----------------------------------------------------------------------
%%----------------------------------------------------------------------
-module(snmp_SUITE).
diff --git a/lib/common_test/test/ct_surefire_SUITE_data/surefire_SUITE.erl b/lib/common_test/test/ct_surefire_SUITE_data/surefire_SUITE.erl
index ed10356cdd..7a73e45b43 100644
--- a/lib/common_test/test/ct_surefire_SUITE_data/surefire_SUITE.erl
+++ b/lib/common_test/test/ct_surefire_SUITE_data/surefire_SUITE.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,9 +23,7 @@
%% Description:
%% This file contains the test cases for cth_surefire.
%%
-%% @author Support
-%% @doc Test of surefire support in common_test
-%% @end
+%% Test of surefire support in common_test
%%----------------------------------------------------------------------
%%----------------------------------------------------------------------
-module(surefire_SUITE).
diff --git a/lib/common_test/test/ct_tc_repeat_SUITE.erl b/lib/common_test/test/ct_tc_repeat_SUITE.erl
new file mode 100644
index 0000000000..433b5456fe
--- /dev/null
+++ b/lib/common_test/test/ct_tc_repeat_SUITE.erl
@@ -0,0 +1,438 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2009-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(ct_tc_repeat_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("common_test/include/ct_event.hrl").
+
+-define(eh, ct_test_support_eh).
+
+%%--------------------------------------------------------------------
+%% TEST SERVER CALLBACK FUNCTIONS
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% Description: Since Common Test starts another Test Server
+%% instance, the tests need to be performed on a separate node (or
+%% there will be clashes with logging processes etc).
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ DataDir = ?config(data_dir, Config),
+ ct_test_support:init_per_suite([{path_dirs,[DataDir]} | Config]).
+
+end_per_suite(Config) ->
+ ct_test_support:end_per_suite(Config).
+
+init_per_testcase(TestCase, Config) ->
+ ct_test_support:init_per_testcase(TestCase, Config).
+
+end_per_testcase(TestCase, Config) ->
+ ct_test_support:end_per_testcase(TestCase, Config).
+
+
+suite() ->
+ [{timetrap,{minutes,1}}].
+
+all() ->
+ all(suite).
+
+all(suite) ->
+ [
+ repeat,
+ repeat_parallel_until_ok,
+ repeat_parallel_until_fail,
+ repeat_sequence_until_ok,
+ repeat_sequence_until_fail,
+ pick_one_test_from_group,
+ pick_one_test_from_subgroup
+ ].
+
+
+%%--------------------------------------------------------------------
+%% TEST CASES
+%%--------------------------------------------------------------------
+
+%%%-----------------------------------------------------------------
+%%%
+%% Test post_groups and post_all hook callbacks, introduced by OTP-14746
+repeat(Config) ->
+ ok = do_test(?FUNCTION_NAME, "tc_repeat_SUITE", [], [], Config).
+
+repeat_parallel_until_ok(Config) ->
+ {error,{{illegal_combination,{parallel,repeat_until_ok}},_}} =
+ do_test(?FUNCTION_NAME, "tc_repeat_SUITE", [{group,g_parallel_until_ok}],
+ [], Config, 1, []).
+
+repeat_parallel_until_fail(Config) ->
+ {error,{{illegal_combination,{parallel,repeat_until_fail}},_}} =
+ do_test(?FUNCTION_NAME, "tc_repeat_SUITE", [{group,g_parallel_until_fail}],
+ [], Config, 1, []).
+
+repeat_sequence_until_ok(Config) ->
+ {error,{{illegal_combination,{sequence,repeat_until_ok}},_}} =
+ do_test(?FUNCTION_NAME, "tc_repeat_SUITE", [{group,g_sequence_until_ok}],
+ [], Config, 1, []).
+
+repeat_sequence_until_fail(Config) ->
+ {error,{{illegal_combination,{sequence,repeat_until_fail}},_}} =
+ do_test(?FUNCTION_NAME, "tc_repeat_SUITE", [{group,g_sequence_until_fail}],
+ [], Config, 1, []).
+
+pick_one_test_from_group(Config) ->
+ do_test(?FUNCTION_NAME, "tc_repeat_SUITE", [{group,g_mixed},{testcase,tc2}],
+ [], Config, 1, []).
+
+pick_one_test_from_subgroup(Config) ->
+ do_test(?FUNCTION_NAME, "tc_repeat_SUITE",
+ [{group,[[g_mixed,subgroup]]},{testcase,tc2}],
+ [], Config, 1, []).
+
+
+%%%-----------------------------------------------------------------
+%%% HELP FUNCTIONS
+%%%-----------------------------------------------------------------
+
+do_test(Tag, Suite, WTT, CTHs, Config) ->
+ do_test(Tag, Suite, WTT, CTHs, Config, 2, []).
+
+do_test(Tag, Suite0, WTT, CTHs, Config, EC, ExtraOpts) ->
+ DataDir = ?config(data_dir, Config),
+ Suite = filename:join([DataDir,Suite0]),
+ {Opts,ERPid} =
+ setup([{suite,Suite}|WTT]++[{ct_hooks,CTHs},{label,Tag}|ExtraOpts],
+ Config),
+ Res = ct_test_support:run(Opts, Config),
+ Events = ct_test_support:get_events(ERPid, Config),
+ %% io:format("~p~n",[Events]),
+
+ ct_test_support:log_events(Tag,
+ reformat(Events, ?eh),
+ ?config(priv_dir, Config),
+ Opts),
+
+ TestEvents = events_to_check(Tag, EC),
+ ok = ct_test_support:verify_events(TestEvents, Events, Config),
+ Res.
+
+setup(Test, Config) ->
+ Opts0 = ct_test_support:get_opts(Config),
+ Level = ?config(trace_level, Config),
+ EvHArgs = [{cbm,ct_test_support},{trace_level,Level}],
+ Opts = Opts0 ++ [{event_handler,{?eh,EvHArgs}}|Test],
+ ERPid = ct_test_support:start_event_receiver(Config),
+ {Opts,ERPid}.
+
+reformat(Events, EH) ->
+ ct_test_support:reformat(Events, EH).
+
+gen_config(Name,KeyVals,Config) ->
+ PrivDir = ?config(priv_dir,Config),
+ File = filename:join(PrivDir,atom_to_list(Name)++".cfg"),
+ ok = file:write_file(File,[io_lib:format("~p.~n",[{Key,Value}])
+ || {Key,Value} <- KeyVals]),
+ File.
+
+%%%-----------------------------------------------------------------
+%%% TEST EVENTS
+%%%-----------------------------------------------------------------
+events_to_check(Test) ->
+ %% 2 tests (ct:run_test + script_start) is default
+ events_to_check(Test, 2).
+
+events_to_check(_, 0) ->
+ [];
+events_to_check(Test, N) ->
+ test_events(Test) ++ events_to_check(Test, N-1).
+
+test_events(repeat) ->
+ S = tc_repeat_SUITE,
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{1,1,unknown}},
+
+ %% tc1, {repeat,2}
+ {?eh,tc_start,{S,tc1}},
+ {?eh,tc_done,{S,tc1,ok}},
+ {?eh,test_stats,{1,0,{0,0}}},
+ {?eh,tc_start,{S,tc1}},
+ {?eh,tc_done,{S,tc1,ok}},
+ {?eh,test_stats,{2,0,{0,0}}},
+ %% tc2, {repeat_until_ok,3}
+ {?eh,tc_start,{S,tc2}},
+ {?eh,tc_done,{S,tc2,ok}},
+ {?eh,test_stats,{3,0,{0,0}}},
+ %% tc3, {repeat_until_ok,3}
+ {?eh,tc_start,{S,tc3}},
+ {?eh,tc_done,{tc_repeat_SUITE,tc3,
+ {failed,{error,{test_case_failed,always_fail}}}}},
+ {?eh,test_stats,{3,1,{0,0}}},
+ {?eh,tc_start,{S,tc3}},
+ {?eh,tc_done,{S,tc3,{failed,{error,{test_case_failed,always_fail}}}}},
+ {?eh,test_stats,{3,2,{0,0}}},
+ {?eh,tc_start,{S,tc3}},
+ {?eh,tc_done,{S,tc3,{failed,{error,{test_case_failed,always_fail}}}}},
+ {?eh,test_stats,{3,3,{0,0}}},
+ %% tc4, {repeat_until_fail,3}
+ {?eh,tc_start,{S,tc4}},
+ {?eh,tc_done,{S,tc4,ok}},
+ {?eh,test_stats,{4,3,{0,0}}},
+ {?eh,tc_start,{S,tc4}},
+ {?eh,tc_done,{S,tc4,{failed,{error,{test_case_failed,second_time_fail}}}}},
+ {?eh,test_stats,{4,4,{0,0}}},
+ %% g, tc1, {repeat,2}
+ {?eh,tc_start,{S,{init_per_group,g,[]}}},
+ {?eh,tc_done,{S,{init_per_group,g,[]},ok}},
+ {?eh,tc_start,{S,tc1}},
+ {?eh,tc_done,{S,tc1,ok}},
+ {?eh,test_stats,{5,4,{0,0}}},
+ {?eh,tc_start,{S,tc1}},
+ {?eh,tc_done,{S,tc1,ok}},
+ {?eh,test_stats,{6,4,{0,0}}},
+ {?eh,tc_start,{S,{end_per_group,g,[]}}},
+ {?eh,tc_done,{S,{end_per_group,g,[]},ok}},
+ %% g_until_ok, tc2, {repeat_until_ok,3}
+ {?eh,tc_start,{S,{init_per_group,g_until_ok,[]}}},
+ {?eh,tc_done,{S,{init_per_group,g_until_ok,[]},ok}},
+ {?eh,tc_start,{S,tc2}},
+ {?eh,tc_done,{S,tc2,ok}},
+ {?eh,test_stats,{7,4,{0,0}}},
+ {?eh,tc_start,{S,{end_per_group,g_until_ok,[]}}},
+ {?eh,tc_done,{S,{end_per_group,g_until_ok,[]},ok}},
+ %% g_until_fail, tc4, {repeat_until_fail,3}
+ {?eh,tc_start,{S,{init_per_group,g_until_fail,[]}}},
+ {?eh,tc_done,{S,{init_per_group,g_until_fail,[]},ok}},
+ {?eh,tc_start,{S,tc4}},
+ {?eh,tc_done,{S,tc4,ok}},
+ {?eh,test_stats,{8,4,{0,0}}},
+ {?eh,tc_start,{S,tc4}},
+ {?eh,tc_done,{S,tc4,{failed,{error,{test_case_failed,second_time_fail}}}}},
+ {?eh,test_stats,{8,5,{0,0}}},
+ {?eh,tc_start,{S,{end_per_group,g_until_fail,[]}}},
+ {?eh,tc_done,{S,{end_per_group,g_until_fail,[]},ok}},
+ %% g, parallel, tc1, {repeat,2}
+ {parallel,
+ [{?eh,tc_start,{S,{init_per_group,g,[parallel]}}},
+ {?eh,tc_done,{S,{init_per_group,g,[parallel]},ok}},
+ {?eh,tc_start,{S,tc1}},
+ {?eh,tc_done,{S,tc1,ok}},
+ {?eh,test_stats,{9,5,{0,0}}},
+ {?eh,tc_start,{S,tc1}},
+ {?eh,tc_done,{S,tc1,ok}},
+ {?eh,test_stats,{10,5,{0,0}}},
+ {?eh,tc_start,{S,{end_per_group,g,[parallel]}}},
+ {?eh,tc_done,{S,{end_per_group,g,[parallel]},ok}}]},
+ %% g, sequence, tc1, {repeat,2}
+ {?eh,tc_start,{S,{init_per_group,g,[sequence]}}},
+ {?eh,tc_done,{S,{init_per_group,g,[sequence]},ok}},
+ {?eh,tc_start,{S,tc1}},
+ {?eh,tc_done,{S,tc1,ok}},
+ {?eh,test_stats,{11,5,{0,0}}},
+ {?eh,tc_start,{S,tc1}},
+ {?eh,tc_done,{S,tc1,ok}},
+ {?eh,test_stats,{12,5,{0,0}}},
+ {?eh,tc_start,{S,{end_per_group,g,[sequence]}}},
+ {?eh,tc_done,{S,{end_per_group,g,[sequence]},ok}},
+ %% g_sequence_skip_rest,
+ {?eh,tc_start,{S,{init_per_group,g_mixed,[sequence]}}},
+ {?eh,tc_done,{S,{init_per_group,g_mixed,[sequence]},ok}},
+ {?eh,tc_start,{S,tc1}},
+ {?eh,tc_done,{S,tc1,ok}},
+ {?eh,test_stats,{13,5,{0,0}}},
+ {?eh,tc_start,{S,tc1}},
+ {?eh,tc_done,{S,tc1,ok}},
+ {?eh,test_stats,{14,5,{0,0}}},
+ {?eh,tc_start,{S,tc4}},
+ {?eh,tc_done,{S,tc4,ok}},
+ {?eh,test_stats,{15,5,{0,0}}},
+ {?eh,tc_start,{S,tc4}},
+ {?eh,tc_done,{S,tc4,{failed,{error,{test_case_failed,second_time_fail}}}}},
+ {?eh,test_stats,{15,6,{0,0}}},
+ %% ----> fail in sequence, so skip rest
+ {?eh,tc_auto_skip,{S,{tc4,g_mixed}, % last of current repeat tc4
+ {failed,{tc_repeat_SUITE,tc4}}}},
+ {?eh,test_stats,{15,6,{0,1}}},
+ {?eh,tc_auto_skip,{S,{tc1,g_mixed}, % single tc1
+ {failed,{tc_repeat_SUITE,tc4}}}},
+ {?eh,test_stats,{15,6,{0,2}}},
+ {?eh,tc_auto_skip,{S,{tc1,g}, % group g, tc1, {repeat,2}
+ {failed,{tc_repeat_SUITE,tc4}}}},
+ {?eh,test_stats,{15,6,{0,3}}},
+ {?eh,tc_auto_skip,{S,{tc1,subgroup}, % subgroup, single tc1
+ {failed,{tc_repeat_SUITE,tc4}}}},
+ {?eh,test_stats,{15,6,{0,4}}},
+ {?eh,tc_auto_skip,{S,{tc2,subgroup}, % subgroup, tc2, {repeat,2}
+ {failed,{tc_repeat_SUITE,tc4}}}},
+ {?eh,test_stats,{15,6,{0,5}}},
+ {?eh,tc_auto_skip,{S,{tc2,g_mixed}, % tc2, {repeat,2}
+ {failed,{tc_repeat_SUITE,tc4}}}},
+ {?eh,test_stats,{15,6,{0,6}}},
+ {?eh,tc_auto_skip,{S,{tc2,g_mixed}, % single tc2
+ {failed,{tc_repeat_SUITE,tc4}}}},
+ {?eh,test_stats,{15,6,{0,7}}},
+ {?eh,tc_auto_skip,{S,{tc1,g_mixed}, % tc1, {repeat,2}
+ {failed,{tc_repeat_SUITE,tc4}}}},
+ {?eh,test_stats,{15,6,{0,8}}},
+ {?eh,tc_auto_skip,{S,{tc1,g_mixed}, % single tc1
+ {failed,{tc_repeat_SUITE,tc4}}}},
+ {?eh,test_stats,{15,6,{0,9}}},
+ {?eh,tc_start,{S,{end_per_group,g_mixed,'_'}}},
+ {?eh,tc_done,{S,{end_per_group,g_mixed,'_'},ok}},
+ %% done
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}
+ ];
+
+test_events(repeat_parallel_until_ok) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,tc_start,{'_',{init_per_group,g_parallel_until_ok,[parallel]}}},
+ {?eh,tc_done,{'_',{init_per_group,g_parallel_until_ok,[parallel]},ok}},
+ {?eh,severe_error,{{illegal_combination,{parallel,repeat_until_ok}},'_'}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}
+ ];
+
+test_events(repeat_parallel_until_fail) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,tc_start,{'_',{init_per_group,g_parallel_until_fail,[parallel]}}},
+ {?eh,tc_done,{'_',{init_per_group,g_parallel_until_fail,[parallel]},ok}},
+ {?eh,severe_error,{{illegal_combination,{parallel,repeat_until_fail}},'_'}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}
+ ];
+
+test_events(repeat_sequence_until_ok) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,tc_start,{'_',{init_per_group,g_sequence_until_ok,[sequence]}}},
+ {?eh,tc_done,{'_',{init_per_group,g_sequence_until_ok,[sequence]},ok}},
+ {?eh,severe_error,{{illegal_combination,{sequence,repeat_until_ok}},'_'}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}
+ ];
+
+test_events(repeat_sequence_until_fail) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,tc_start,{'_',{init_per_group,g_sequence_until_fail,[sequence]}}},
+ {?eh,tc_done,{'_',{init_per_group,g_sequence_until_fail,[sequence]},ok}},
+ {?eh,severe_error,{{illegal_combination,{sequence,repeat_until_fail}},'_'}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}
+ ];
+
+test_events(pick_one_test_from_group) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,tc_start,{'_',{init_per_group,g_mixed,[]}}},
+ {?eh,tc_done,{'_',{init_per_group,g_mixed,[]},ok}},
+ {negative,
+ {?eh,tc_start,{'_',tc1}},
+ {?eh,tc_start,{'_',tc2}}}, % single tc2
+ {?eh,tc_done,{'_',tc2,ok}},
+ {?eh,tc_start,{'_',tc2}}, % tc2, {repeat,2}
+ {?eh,tc_done,{'_',tc2,ok}},
+ {?eh,tc_start,{'_',tc2}},
+ {?eh,tc_done,{'_',tc2,ok}},
+ {negative,
+ {?eh,tc_start,{'_',tc1}},
+ {?eh,tc_start,{'_',{end_per_group,g_mixed,[]}}}},
+ {?eh,tc_done,{'_',{end_per_group,g_mixed,[]},ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}
+ ];
+
+test_events(pick_one_test_from_subgroup) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,tc_start,{'_',{init_per_group,g_mixed,[]}}},
+ {?eh,tc_done,{'_',{init_per_group,g_mixed,[]},ok}},
+ {negative,
+ {?eh,tc_start,{'_',tc2}},
+ {?eh,tc_start,{'_',{init_per_group,subgroup,[]}}}},
+ {?eh,tc_done,{'_',{init_per_group,subgroup,[]},ok}},
+ {negative,
+ {?eh,tc_start,{'_',tc1}},
+ {?eh,tc_start,{'_',tc2}}}, % tc2, {repeat,2}
+ {?eh,tc_done,{'_',tc2,ok}},
+ {?eh,tc_start,{'_',tc2}},
+ {?eh,tc_done,{'_',tc2,ok}},
+ {negative,
+ {?eh,tc_start,{'_',tc1}},
+ {?eh,tc_start,{'_',{end_per_group,subgroup,[]}}}},
+ {?eh,tc_done,{'_',{end_per_group,subgroup,[]},ok}},
+ {negative,
+ {?eh,tc_start,{'_',tc2}},
+ {?eh,tc_start,{'_',{end_per_group,g_mixed,[]}}}},
+ {?eh,tc_done,{'_',{end_per_group,g_mixed,[]},ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}
+ ];
+
+test_events(ok) ->
+ ok.
+
+%% test events help functions
+contains(List) ->
+ fun(Proplist) when is_list(Proplist) ->
+ contains(List,Proplist)
+ end.
+
+contains([{not_in_order,List}|T],Rest) ->
+ contains_parallel(List,Rest),
+ contains(T,Rest);
+contains([{Ele,Pos}|T] = L,[H|T2]) ->
+ case element(Pos,H) of
+ Ele ->
+ contains(T,T2);
+ _ ->
+ contains(L,T2)
+ end;
+contains([Ele|T],[{Ele,_}|T2])->
+ contains(T,T2);
+contains([Ele|T],[Ele|T2])->
+ contains(T,T2);
+contains(List,[_|T]) ->
+ contains(List,T);
+contains([],_) ->
+ match.
+
+contains_parallel([Key | T], Elems) ->
+ contains([Key],Elems),
+ contains_parallel(T,Elems);
+contains_parallel([],_Elems) ->
+ match.
+
+not_contains(List) ->
+ fun(Proplist) when is_list(Proplist) ->
+ [] = [Ele || {Ele,_} <- Proplist,
+ Test <- List,
+ Test =:= Ele]
+ end.
diff --git a/lib/common_test/test/ct_tc_repeat_SUITE_data/tc_repeat_SUITE.erl b/lib/common_test/test/ct_tc_repeat_SUITE_data/tc_repeat_SUITE.erl
new file mode 100644
index 0000000000..f5d960d12f
--- /dev/null
+++ b/lib/common_test/test/ct_tc_repeat_SUITE_data/tc_repeat_SUITE.erl
@@ -0,0 +1,85 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(tc_repeat_SUITE).
+
+-suite_defaults([{timetrap, {minutes, 10}}]).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include("ct.hrl").
+
+init_per_group(_Group,Config) ->
+ Config.
+
+end_per_group(_Group,Config) ->
+ ok.
+
+all() ->
+ [{testcase,tc1,[{repeat,2}]},
+ {testcase,tc2,[{repeat_until_ok,3}]},
+ {testcase,tc3,[{repeat_until_ok,3}]},
+ {testcase,tc4,[{repeat_until_fail,3}]},
+ {group,g},
+ {group,g_until_ok},
+ {group,g_until_fail},
+ {group,g,[parallel]},
+ {group,g,[sequence]},
+ {group,g_mixed,[sequence]}].
+
+groups() ->
+ [{g,[{testcase,tc1,[{repeat,2}]}]},
+ {g_until_ok,[{testcase,tc2,[{repeat_until_ok,3}]}]},
+ {g_until_fail,[{testcase,tc4,[{repeat_until_fail,3}]}]},
+ {g_parallel_until_ok,[parallel],[{testcase,tc2,[{repeat_until_ok,3}]}]},
+ {g_parallel_until_fail,[parallel],[{testcase,tc1,[{repeat_until_fail,2}]}]},
+ {g_sequence_until_ok,[sequence],[{testcase,tc2,[{repeat_until_ok,3}]}]},
+ {g_sequence_until_fail,[sequence],[{testcase,tc1,[{repeat_until_fail,2}]}]},
+ {g_mixed,[{testcase,tc1,[{repeat,2}]},
+ {testcase,tc4,[{repeat,3}]},
+ tc1,
+ {group,g},
+ {subgroup,[tc1,{testcase,tc2,[{repeat,2}]}]},
+ {testcase,tc2,[{repeat,2}]},
+ tc2,
+ {testcase,tc1,[{repeat,2}]},
+ tc1]}].
+
+%% Test cases starts here.
+tc1(_Config) ->
+ ok.
+
+tc2(_Config) ->
+ ok.
+
+tc3(_Config) ->
+ ct:fail(always_fail).
+
+tc4(Config) ->
+ case ?config(saved_config,Config) of
+ {tc4,_} ->
+ ct:fail(second_time_fail);
+ undefined ->
+ {save_config,Config}
+ end.
+
+tc5(_Config) ->
+ {skip,"just skip this"}.
diff --git a/lib/common_test/test/ct_telnet_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE.erl
index a0089c9bc9..f71b7c370f 100644
--- a/lib/common_test/test/ct_telnet_SUITE.erl
+++ b/lib/common_test/test/ct_telnet_SUITE.erl
@@ -50,10 +50,10 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
groups() ->
- [{legacy, [], [unix_telnet,own_server,timetrap]},
- {raw, [], [unix_telnet,own_server,timetrap]},
- {html, [], [unix_telnet,own_server]},
- {silent, [], [unix_telnet,own_server]}].
+ [{legacy, [], [unix_telnet,own_server,faulty_regexp,timetrap]},
+ {raw, [], [unix_telnet,own_server,faulty_regexp,timetrap]},
+ {html, [], [unix_telnet,own_server,faulty_regexp]},
+ {silent, [], [unix_telnet,own_server,faulty_regexp]}].
all() ->
[
@@ -119,6 +119,12 @@ own_server(Config) ->
all_tests_in_suite(own_server,"ct_telnet_own_server_SUITE",
CfgFile,Config).
+faulty_regexp(Config) ->
+ CfgFile = "telnet.faulty_regexp." ++
+ atom_to_list(groupname(Config)) ++ ".cfg",
+ all_tests_in_suite(faulty_regexp,"ct_telnet_faulty_regexp_SUITE",
+ CfgFile,Config).
+
timetrap(Config) ->
CfgFile = "telnet.timetrap." ++
atom_to_list(groupname(Config)) ++ ".cfg",
@@ -225,6 +231,31 @@ events_to_check(unix_telnet,Config) ->
all_cases(ct_telnet_basic_SUITE,Config);
events_to_check(own_server,Config) ->
all_cases(ct_telnet_own_server_SUITE,Config);
+events_to_check(faulty_regexp,_Config) ->
+ [{?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,tc_done,
+ {ct_telnet_faulty_regexp_SUITE,expect_pattern,
+ {failed,
+ {error,{{bad_pattern,"invalid(pattern",{"missing )",15}},
+ {ct_telnet,expect,3}}}}}},
+ {?eh,tc_done,
+ {ct_telnet_faulty_regexp_SUITE,expect_pattern_no_string,
+ {failed,
+ {error,{{bad_pattern,invalid_pattern},
+ {ct_telnet,expect,3}}}}}},
+ {?eh,tc_done,
+ {ct_telnet_faulty_regexp_SUITE,expect_tag_pattern,
+ {failed,
+ {error,{{bad_pattern,{tag,"invalid(pattern"},{"missing )",15}},
+ {ct_telnet,expect,3}}}}}},
+ {?eh,tc_done,
+ {ct_telnet_faulty_regexp_SUITE,expect_tag_pattern_no_string,
+ {failed,
+ {error,{{bad_pattern,{tag,invalid_pattern}},
+ {ct_telnet,expect,3}}}}}},
+ {?eh,tc_done,{ct_telnet_faulty_regexp_SUITE,expect_pattern_unicode,ok}},
+ {?eh,tc_done,{ct_telnet_faulty_regexp_SUITE,expect_tag_pattern_unicode,ok}},
+ {?eh,stop_logging,[]}];
events_to_check(timetrap,_Config) ->
[{?eh,start_logging,{'DEF','RUNDIR'}},
{?eh,tc_done,{ct_telnet_timetrap_SUITE,expect_timetrap,
diff --git a/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_faulty_regexp_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_faulty_regexp_SUITE.erl
new file mode 100644
index 0000000000..a5c9451a9c
--- /dev/null
+++ b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_faulty_regexp_SUITE.erl
@@ -0,0 +1,79 @@
+-module(ct_telnet_faulty_regexp_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+-define(name, telnet_server_conn1).
+
+%%--------------------------------------------------------------------
+%% TEST SERVER CALLBACK FUNCTIONS
+%%--------------------------------------------------------------------
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+suite() -> [{require,?name,{unix,[telnet]}},
+ {require,ct_conn_log},
+ {ct_hooks, [{cth_conn_log,[]}]}].
+
+all() ->
+ [expect_pattern,
+ expect_pattern_no_string,
+ expect_tag_pattern,
+ expect_tag_pattern_no_string,
+ expect_pattern_unicode,
+ expect_tag_pattern_unicode].
+
+groups() ->
+ [].
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+init_per_testcase(_,Config) ->
+ ct:log("init_per_testcase: opening telnet connection...",[]),
+ {ok,_} = ct_telnet:open(?name),
+ ct:log("...done",[]),
+ Config.
+
+end_per_testcase(_,_Config) ->
+ ct:log("end_per_testcase: closing telnet connection...",[]),
+ _ = ct_telnet:close(?name),
+ ct:log("...done",[]),
+ ok.
+
+expect_pattern(_) ->
+ ok = ct_telnet:send(?name, "echo ayt"),
+ ok = ct_telnet:expect(?name, "invalid(pattern").
+
+expect_pattern_no_string(_) ->
+ ok = ct_telnet:send(?name, "echo ayt"),
+ ok = ct_telnet:expect(?name, invalid_pattern).
+
+expect_tag_pattern(_) ->
+ ok = ct_telnet:send(?name, "echo ayt"),
+ ok = ct_telnet:expect(?name, {tag,"invalid(pattern"}).
+
+expect_tag_pattern_no_string(_) ->
+ ok = ct_telnet:send(?name, "echo ayt"),
+ ok = ct_telnet:expect(?name, {tag,invalid_pattern}).
+
+%% Test that a unicode pattern can be given without the testcase
+%% failing. Do however notice that there is no real unicode support
+%% in ct_telnet yet, that is, the telnet binary mode is not supported.
+expect_pattern_unicode(_) ->
+ ok = ct_telnet:send(?name, "echo ayt"),
+ {error,{prompt,_}} = ct_telnet:expect(?name, "pattern_with_unicode_αβ"),
+ ok.
+
+expect_tag_pattern_unicode(_) ->
+ ok = ct_telnet:send(?name, "echo ayt"),
+ {error,{prompt,_}} = ct_telnet:expect(?name, "pattern_with_unicode_αβ"),
+ ok.
diff --git a/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl
index 985fa40ad2..34df57027e 100644
--- a/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl
+++ b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl
@@ -58,7 +58,8 @@ all() ->
server_speaks,
server_disconnects,
newline_ayt,
- newline_break
+ newline_break,
+ newline_string
].
groups() ->
@@ -393,3 +394,11 @@ newline_break(_) ->
"> " = lists:flatten(R),
ok = ct_telnet:close(Handle),
ok.
+
+%% Test option {newline,String} to specify an own newline, e.g. "\r\n"
+newline_string(_) ->
+ {ok, Handle} = ct_telnet:open(telnet_server_conn1),
+ ok = ct_telnet:send(Handle, "echo hello-", [{newline,"own_nl\n"}]),
+ {ok,["hello-own_nl"]} = ct_telnet:expect(Handle, ["hello-own_nl"]),
+ ok = ct_telnet:close(Handle),
+ ok.
diff --git a/lib/common_test/test/ct_test_support.erl b/lib/common_test/test/ct_test_support.erl
index 44c27e54c2..388d5d46c6 100644
--- a/lib/common_test/test/ct_test_support.erl
+++ b/lib/common_test/test/ct_test_support.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,9 +18,9 @@
%% %CopyrightEnd%
%%
-%%% @doc Test support functions
+%%% Test support functions
%%%
-%%% <p>This is a support module for testing the Common Test Framework.</p>
+%%% This is a support module for testing the Common Test Framework.
%%%
-module(ct_test_support).
@@ -88,7 +88,7 @@ start_slave(Config, Level) ->
start_slave(ct, Config, Level).
start_slave(NodeName, Config, Level) ->
- [_,Host] = string:tokens(atom_to_list(node()), "@"),
+ [_,Host] = string:lexemes(atom_to_list(node()), "@"),
test_server:format(0, "Trying to start ~s~n",
[atom_to_list(NodeName)++"@"++Host]),
PR = proplists:get_value(printable_range,Config,io:printable_range()),
@@ -1088,8 +1088,8 @@ locate({TEH,Name,{'DEF','RUNDIR'}}, Node, [Ev|Evs], Config) ->
{TEH,#event{name=Name, node=Node, data=EvData}} ->
{_,{_,LogDir}} = lists:keysearch(logdir, 1, get_opts(Config)),
D = filename:join(LogDir, "ct_run." ++ atom_to_list(Node)),
- case string:str(EvData, D) of
- 0 -> exit({badmatch,EvData});
+ case string:find(EvData, D) of
+ nomatch -> exit({badmatch,EvData});
_ -> ok
end,
{Config,Evs};
@@ -1104,8 +1104,8 @@ locate({TEH,Name,{'DEF',{'START_TIME','LOGDIR'}}}, Node, [Ev|Evs], Config) ->
{DT={{_,_,_},{_,_,_}},Dir} when is_list(Dir) ->
{_,{_,LogDir}} = lists:keysearch(logdir, 1, get_opts(Config)),
D = filename:join(LogDir, "ct_run." ++ atom_to_list(Node)),
- case string:str(Dir, D) of
- 0 -> exit({badmatch,Dir});
+ case string:find(Dir, D) of
+ nomatch -> exit({badmatch,Dir});
_ -> ok
end,
{[{start_time,DT}|Config],Evs};
@@ -1373,7 +1373,7 @@ delete_dirs(LogDir) ->
Dirs2Del =
lists:foldl(fun(Dir, Del) ->
[S,Mi,H,D,Mo,Y|_] =
- lists:reverse(string:tokens(Dir, [$.,$-,$_])),
+ lists:reverse(string:lexemes(Dir, [$.,$-,$_])),
S2I = fun(Str) -> list_to_integer(Str) end,
DT = {{S2I(Y),S2I(Mo),S2I(D)}, {S2I(H),S2I(Mi),S2I(S)}},
Then = calendar:datetime_to_gregorian_seconds(DT),
diff --git a/lib/common_test/test/ct_test_support_eh.erl b/lib/common_test/test/ct_test_support_eh.erl
index e8db52dcd3..120692dc7c 100644
--- a/lib/common_test/test/ct_test_support_eh.erl
+++ b/lib/common_test/test/ct_test_support_eh.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,10 +18,10 @@
%% %CopyrightEnd%
%%
-%%% @doc Event handler module
+%%% Event handler module
%%%
-%%% <p>This is an event handler module used for testing that
-%%% Common Test generates events as expected.</p>
+%%% This is an event handler module used for testing that
+%%% Common Test generates events as expected.
%%%
-module(ct_test_support_eh).
diff --git a/lib/common_test/test/ct_unicode_SUITE.erl b/lib/common_test/test/ct_unicode_SUITE.erl
index 355503a5dc..6f6ec97ceb 100644
--- a/lib/common_test/test/ct_unicode_SUITE.erl
+++ b/lib/common_test/test/ct_unicode_SUITE.erl
@@ -191,7 +191,7 @@ check_logs(Dirs) ->
[] ->
ok;
Match ->
- MatchStr = string:join(Match,"\n"),
+ MatchStr = lists:join("\n",Match),
ct:log("ERROR: Escaped unicode characters found in:~n~ts",[MatchStr]),
ct:fail(escaped_unicode_characters_found)
end.
diff --git a/lib/common_test/test/ct_unicode_SUITE_data/unicode_atoms_SUITE.erl b/lib/common_test/test/ct_unicode_SUITE_data/unicode_atoms_SUITE.erl
index 993452500e..4f9dd20e3e 100644
--- a/lib/common_test/test/ct_unicode_SUITE_data/unicode_atoms_SUITE.erl
+++ b/lib/common_test/test/ct_unicode_SUITE_data/unicode_atoms_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -77,7 +77,7 @@ all() ->
'fail_αβ_4'(_Config) ->
ct:log("This is test case ~tw",[?FUNCTION_NAME]),
- S = try throw(ok) catch throw:ok -> erlang:get_stacktrace() end,
+ S = try throw(ok) catch throw:ok:Stacktrace -> Stacktrace end,
erlang:raise(error,{error,testcase,?FUNCTION_NAME},S),
ok.
diff --git a/lib/common_test/test/ct_userconfig_callback.erl b/lib/common_test/test/ct_userconfig_callback.erl
index c723f4ca1c..e48d338dd5 100644
--- a/lib/common_test/test/ct_userconfig_callback.erl
+++ b/lib/common_test/test/ct_userconfig_callback.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,7 +21,7 @@
-export([check_parameter/1, read_config/1]).
read_config(Str) ->
- KeyVals = string:tokens(Str, " "),
+ KeyVals = string:lexemes(Str, " "),
{ok,read_config1(KeyVals)}.
read_config1([Key,Val | KeyVals]) ->
diff --git a/lib/common_test/test/ct_util_SUITE.erl b/lib/common_test/test/ct_util_SUITE.erl
new file mode 100644
index 0000000000..1d773855da
--- /dev/null
+++ b/lib/common_test/test/ct_util_SUITE.erl
@@ -0,0 +1,490 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2009-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(ct_util_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("common_test/include/ct_event.hrl").
+
+-define(eh, ct_test_support_eh).
+
+%%--------------------------------------------------------------------
+%% TEST SERVER CALLBACK FUNCTIONS
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% Description: Since Common Test starts another Test Server
+%% instance, the tests need to be performed on a separate node (or
+%% there will be clashes with logging processes etc).
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ DataDir = ?config(data_dir, Config),
+ CTHs = filelib:wildcard(filename:join(DataDir,"*_cth.erl")),
+ io:format("CTHs: ~p",[CTHs]),
+ [io:format("Compiling ~p: ~p",
+ [FileName,compile:file(FileName,[{outdir,DataDir},debug_info])]) ||
+ FileName <- CTHs],
+ ct_test_support:init_per_suite([{path_dirs,[DataDir]} | Config]).
+
+end_per_suite(Config) ->
+ ct_test_support:end_per_suite(Config).
+
+init_per_testcase(TestCase, Config) ->
+ ct_test_support:init_per_testcase(TestCase, Config).
+
+end_per_testcase(TestCase, Config) ->
+ ct_test_support:end_per_testcase(TestCase, Config).
+
+
+suite() ->
+ [{timetrap,{minutes,1}}].
+
+all() ->
+ all(suite).
+
+all(suite) ->
+ [
+ pre_init_per_suite,
+ post_init_per_suite,
+ pre_end_per_suite,
+ post_end_per_suite,
+ pre_init_per_group,
+ post_init_per_group,
+ pre_end_per_group,
+ post_end_per_group,
+ pre_init_per_testcase,
+ post_init_per_testcase,
+ pre_end_per_testcase,
+ post_end_per_testcase
+ ].
+
+
+%%--------------------------------------------------------------------
+%% TEST CASES
+%%--------------------------------------------------------------------
+
+%%%-----------------------------------------------------------------
+%%%
+pre_init_per_suite(Config) ->
+ CfgFile = gen_config(?FUNCTION_NAME,
+ [{pre_init_per_suite,
+ {curr_tc_SUITE,kill}}],
+ Config),
+ ok = do_test(?FUNCTION_NAME,
+ "curr_tc_SUITE.erl",
+ [{ct_hooks,[ct_util_cth]},{config,CfgFile}],
+ Config).
+
+post_init_per_suite(Config) ->
+ CfgFile = gen_config(?FUNCTION_NAME,
+ [{post_init_per_suite,
+ {curr_tc_SUITE,kill}}],
+ Config),
+ ok = do_test(?FUNCTION_NAME,
+ "curr_tc_SUITE.erl",
+ [{ct_hooks,[ct_util_cth]},{config,CfgFile}],
+ Config).
+
+pre_end_per_suite(Config) ->
+ CfgFile = gen_config(?FUNCTION_NAME,
+ [{pre_end_per_suite,
+ {curr_tc_SUITE,kill}}],
+ Config),
+ ok = do_test(?FUNCTION_NAME,
+ "curr_tc_SUITE.erl",
+ [{ct_hooks,[ct_util_cth]},{config,CfgFile}],
+ Config).
+
+post_end_per_suite(Config) ->
+ CfgFile = gen_config(?FUNCTION_NAME,
+ [{post_end_per_suite,
+ {curr_tc_SUITE,kill}}],
+ Config),
+ ok = do_test(?FUNCTION_NAME,
+ "curr_tc_SUITE.erl",
+ [{ct_hooks,[ct_util_cth]},{config,CfgFile}],
+ Config).
+
+
+pre_init_per_group(Config) ->
+ CfgFile = gen_config(?FUNCTION_NAME,
+ [{pre_init_per_group,
+ {curr_tc_SUITE,g,kill}}],
+ Config),
+ ok = do_test(?FUNCTION_NAME,
+ "curr_tc_SUITE.erl",
+ [{ct_hooks,[ct_util_cth]},{config,CfgFile}],
+ Config).
+
+post_init_per_group(Config) ->
+ CfgFile = gen_config(?FUNCTION_NAME,
+ [{post_init_per_group,
+ {curr_tc_SUITE,g,kill}}],
+ Config),
+ ok = do_test(?FUNCTION_NAME,
+ "curr_tc_SUITE.erl",
+ [{ct_hooks,[ct_util_cth]},{config,CfgFile}],
+ Config).
+
+pre_end_per_group(Config) ->
+ CfgFile = gen_config(?FUNCTION_NAME,
+ [{pre_end_per_group,
+ {curr_tc_SUITE,g,kill}}],
+ Config),
+ ok = do_test(?FUNCTION_NAME,
+ "curr_tc_SUITE.erl",
+ [{ct_hooks,[ct_util_cth]},{config,CfgFile}],
+ Config).
+
+post_end_per_group(Config) ->
+ CfgFile = gen_config(?FUNCTION_NAME,
+ [{post_end_per_group,
+ {curr_tc_SUITE,g,kill}}],
+ Config),
+ ok = do_test(?FUNCTION_NAME,
+ "curr_tc_SUITE.erl",
+ [{ct_hooks,[ct_util_cth]},{config,CfgFile}],
+ Config).
+
+pre_init_per_testcase(Config) ->
+ CfgFile = gen_config(?FUNCTION_NAME,
+ [{pre_init_per_testcase,
+ {curr_tc_SUITE,tc1,kill}}],
+ Config),
+ ok = do_test(?FUNCTION_NAME,
+ "curr_tc_SUITE.erl",
+ [{ct_hooks,[ct_util_cth]},{config,CfgFile}],
+ Config).
+
+post_init_per_testcase(Config) ->
+ CfgFile = gen_config(?FUNCTION_NAME,
+ [{post_init_per_testcase,
+ {curr_tc_SUITE,tc1,{timeout,5000}}}],
+ Config),
+ ok = do_test(?FUNCTION_NAME,
+ "curr_tc_SUITE.erl",
+ [{ct_hooks,[ct_util_cth]},{config,CfgFile}],
+ Config).
+
+pre_end_per_testcase(Config) ->
+ CfgFile = gen_config(?FUNCTION_NAME,
+ [{pre_end_per_testcase,
+ {curr_tc_SUITE,tc1,{timeout,5000}}}],
+ Config),
+ ok = do_test(?FUNCTION_NAME,
+ "curr_tc_SUITE.erl",
+ [{ct_hooks,[ct_util_cth]},{config,CfgFile}],
+ Config).
+
+post_end_per_testcase(Config) ->
+ CfgFile = gen_config(?FUNCTION_NAME,
+ [{post_end_per_testcase,
+ {curr_tc_SUITE,tc1,kill}}],
+ Config),
+ ok = do_test(?FUNCTION_NAME,
+ "curr_tc_SUITE.erl",
+ [{ct_hooks,[ct_util_cth]},{config,CfgFile}],
+ Config).
+
+%%%-----------------------------------------------------------------
+%%% HELP FUNCTIONS
+%%%-----------------------------------------------------------------
+
+do_test(Tag, Suite, RunTestArgs, Config) ->
+ do_test(Tag, Suite, RunTestArgs, Config, 2).
+
+do_test(Tag, Suite0, RunTestArgs, Config, EC) ->
+ DataDir = ?config(data_dir, Config),
+ Suite = filename:join([DataDir,Suite0]),
+ {Opts,ERPid} = setup([{suite,Suite}]++[{label,Tag}|RunTestArgs],Config),
+ Res = ct_test_support:run(Opts, Config),
+ Events = ct_test_support:get_events(ERPid, Config),
+ %% io:format("~p~n",[Events]),
+
+ ct_test_support:log_events(Tag,
+ reformat(Events, ?eh),
+ ?config(priv_dir, Config),
+ Opts),
+
+ TestEvents = events_to_check(Tag, EC),
+ ok = ct_test_support:verify_events(TestEvents, Events, Config),
+ Res.
+
+setup(Test, Config) ->
+ Opts0 = ct_test_support:get_opts(Config),
+ Level = ?config(trace_level, Config),
+ EvHArgs = [{cbm,ct_test_support},{trace_level,Level}],
+ Opts = Opts0 ++ [{event_handler,{?eh,EvHArgs}}|Test],
+ ERPid = ct_test_support:start_event_receiver(Config),
+ {Opts,ERPid}.
+
+reformat(Events, EH) ->
+ ct_test_support:reformat(Events, EH).
+
+gen_config(Name,KeyVals,Config) ->
+ PrivDir = ?config(priv_dir,Config),
+ File = filename:join(PrivDir,atom_to_list(Name)++".cfg"),
+ ok = file:write_file(File,[io_lib:format("~p.~n",[{Key,Value}])
+ || {Key,Value} <- KeyVals]),
+ File.
+
+%%%-----------------------------------------------------------------
+%%% TEST EVENTS
+%%%-----------------------------------------------------------------
+events_to_check(Test) ->
+ %% 2 tests (ct:run_test + script_start) is default
+ events_to_check(Test, 2).
+
+events_to_check(_, 0) ->
+ [];
+events_to_check(Test, N) ->
+ test_events(Test) ++ events_to_check(Test, N-1).
+
+test_events(IPS) when IPS=:=pre_init_per_suite; IPS=:=post_init_per_suite ->
+ S = curr_tc_SUITE,
+ FwFunc =
+ case IPS of
+ pre_init_per_suite -> init_tc;
+ post_init_per_suite -> end_tc
+ end,
+ E = {failed,{ct_framework,FwFunc,{test_case_failed,hahahahahah}}},
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{1,1,4}},
+ {?eh,tc_start,{S,init_per_suite}},
+ {?eh,tc_done,{S,init_per_suite,E}},
+ {?eh,tc_auto_skip,{S,tc1,{failed,{S,init_per_suite,E}}}},
+ {?eh,tc_auto_skip,{S,tc2,{failed,{S,init_per_suite,E}}}},
+ {?eh,tc_auto_skip,{S,{tc1,g},{failed,{S,init_per_suite,E}}}},
+ {?eh,tc_auto_skip,{S,{tc2,g},{failed,{S,init_per_suite,E}}}},
+ {?eh,test_stats,{0,0,{0,4}}},
+ {?eh,tc_auto_skip,{S,end_per_suite,{failed,{S,init_per_suite,E}}}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}
+ ];
+
+test_events(EPS) when EPS=:=pre_end_per_suite; EPS=:=post_end_per_suite ->
+ S = curr_tc_SUITE,
+ FwFunc =
+ case EPS of
+ pre_end_per_suite -> init_tc;
+ post_end_per_suite -> end_tc
+ end,
+ E = {failed,{ct_framework,FwFunc,{test_case_failed,hahahahahah}}},
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{1,1,4}},
+ {?eh,tc_start,{S,init_per_suite}},
+ {?eh,tc_done,{S,init_per_suite,ok}},
+ {?eh,tc_start,{S,tc1}},
+ {?eh,tc_done,{S,tc1,ok}},
+ {?eh,test_stats,{1,0,{0,0}}},
+ {?eh,tc_start,{S,tc2}},
+ {?eh,tc_done,{S,tc2,ok}},
+ {?eh,test_stats,{2,0,{0,0}}},
+ [{?eh,tc_start,{S,{init_per_group,g,[]}}},
+ {?eh,tc_done,{S,{init_per_group,g,[]},ok}},
+ {?eh,tc_start,{S,tc1}},
+ {?eh,tc_done,{S,tc1,ok}},
+ {?eh,test_stats,{3,0,{0,0}}},
+ {?eh,tc_start,{S,tc2}},
+ {?eh,tc_done,{S,tc2,ok}},
+ {?eh,test_stats,{4,0,{0,0}}},
+ {?eh,tc_start,{S,{end_per_group,g,[]}}},
+ {?eh,tc_done,{S,{end_per_group,g,[]},ok}}],
+ {?eh,tc_start,{S,end_per_suite}},
+ {?eh,tc_done,{S,end_per_suite,E}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}
+ ];
+
+test_events(IPG) when IPG=:=pre_init_per_group; IPG=:=post_init_per_group ->
+ S = curr_tc_SUITE,
+ FwFunc =
+ case IPG of
+ pre_init_per_group -> init_tc;
+ post_init_per_group -> end_tc
+ end,
+ E = {failed,{ct_framework,FwFunc,{test_case_failed,hahahahahah}}},
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{1,1,4}},
+ {?eh,tc_start,{S,init_per_suite}},
+ {?eh,tc_done,{S,init_per_suite,ok}},
+ {?eh,tc_start,{S,tc1}},
+ {?eh,tc_done,{S,tc1,ok}},
+ {?eh,test_stats,{1,0,{0,0}}},
+ {?eh,tc_start,{S,tc2}},
+ {?eh,tc_done,{S,tc2,ok}},
+ {?eh,test_stats,{2,0,{0,0}}},
+ [{?eh,tc_start,{S,{init_per_group,g,[]}}},
+ {?eh,tc_done,{S,{init_per_group,g,[]},E}},
+ {?eh,tc_auto_skip,{S,{tc1,g},{failed,{S,init_per_group,E}}}},
+ {?eh,tc_auto_skip,{S,{tc2,g},{failed,{S,init_per_group,E}}}},
+ {?eh,test_stats,{2,0,{0,2}}},
+ {?eh,tc_auto_skip,{S,{end_per_group,g},{failed,{S,init_per_group,E}}}}],
+ {?eh,tc_start,{S,end_per_suite}},
+ {?eh,tc_done,{S,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}
+ ];
+
+test_events(EPG) when EPG=:=pre_end_per_group; EPG=:=post_end_per_group ->
+ S = curr_tc_SUITE,
+ FwFunc =
+ case EPG of
+ pre_end_per_group -> init_tc;
+ post_end_per_group -> end_tc
+ end,
+ E = {failed,{ct_framework,FwFunc,{test_case_failed,hahahahahah}}},
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{1,1,4}},
+ {?eh,tc_start,{S,init_per_suite}},
+ {?eh,tc_done,{S,init_per_suite,ok}},
+ {?eh,tc_start,{S,tc1}},
+ {?eh,tc_done,{S,tc1,ok}},
+ {?eh,test_stats,{1,0,{0,0}}},
+ {?eh,tc_start,{S,tc2}},
+ {?eh,tc_done,{S,tc2,ok}},
+ {?eh,test_stats,{2,0,{0,0}}},
+ [{?eh,tc_start,{S,{init_per_group,g,[]}}},
+ {?eh,tc_done,{S,{init_per_group,g,[]},ok}},
+ {?eh,tc_start,{S,tc1}},
+ {?eh,tc_done,{S,tc1,ok}},
+ {?eh,test_stats,{3,0,{0,0}}},
+ {?eh,tc_start,{S,tc2}},
+ {?eh,tc_done,{S,tc2,ok}},
+ {?eh,test_stats,{4,0,{0,0}}},
+ {?eh,tc_start,{S,{end_per_group,g,[]}}},
+ {?eh,tc_done,{S,{end_per_group,g,[]},E}}],
+ {?eh,tc_start,{S,end_per_suite}},
+ {?eh,tc_done,{S,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}
+ ];
+
+test_events(IPTC) when IPTC=:=pre_init_per_testcase;
+ IPTC=:=post_init_per_testcase ->
+ S = curr_tc_SUITE,
+ E = case IPTC of
+ pre_init_per_testcase ->
+ {failed,{ct_framework,init_tc,{test_case_failed,hahahahahah}}};
+ post_init_per_testcase ->
+ {failed,{ct_framework,end_tc,{timetrap,3000}}}
+ end,
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{1,1,4}},
+ {?eh,tc_start,{S,init_per_suite}},
+ {?eh,tc_done,{S,init_per_suite,ok}},
+ {?eh,tc_start,{S,tc1}},
+ {?eh,tc_done,{S,tc1,{auto_skipped,E}}},
+ {?eh,test_stats,{0,0,{0,1}}},
+ {?eh,tc_start,{S,tc2}},
+ {?eh,tc_done,{S,tc2,ok}},
+ {?eh,test_stats,{1,0,{0,1}}},
+ [{?eh,tc_start,{S,{init_per_group,g,[]}}},
+ {?eh,tc_done,{S,{init_per_group,g,[]},ok}},
+ {?eh,tc_start,{S,tc1}},
+ {?eh,tc_done,{S,tc1,{auto_skipped,E}}},
+ {?eh,test_stats,{1,0,{0,2}}},
+ {?eh,tc_start,{S,tc2}},
+ {?eh,tc_done,{S,tc2,ok}},
+ {?eh,test_stats,{2,0,{0,2}}},
+ {?eh,tc_start,{S,{end_per_group,g,[]}}},
+ {?eh,tc_done,{S,{end_per_group,g,[]},ok}}],
+ {?eh,tc_start,{S,end_per_suite}},
+ {?eh,tc_done,{S,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}
+ ];
+
+test_events(EPTC) when EPTC=:=pre_end_per_testcase; EPTC=:=post_end_per_testcase->
+ S = curr_tc_SUITE,
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{1,1,4}},
+ {?eh,tc_start,{S,tc1}},
+ {?eh,tc_done,{S,tc1,ok}},
+ {?eh,test_stats,{1,0,{0,0}}},
+ {?eh,tc_start,{S,tc2}},
+ {?eh,tc_done,{S,tc2,ok}},
+ {?eh,test_stats,{2,0,{0,0}}},
+ [{?eh,tc_start,{S,{init_per_group,g,[]}}},
+ {?eh,tc_done,{S,{init_per_group,g,[]},ok}},
+ {?eh,tc_start,{S,tc1}},
+ {?eh,tc_done,{S,tc1,ok}},
+ {?eh,test_stats,{3,0,{0,0}}},
+ {?eh,tc_start,{S,tc2}},
+ {?eh,tc_done,{S,tc2,ok}},
+ {?eh,test_stats,{4,0,{0,0}}},
+ {?eh,tc_start,{S,{end_per_group,g,[]}}},
+ {?eh,tc_done,{S,{end_per_group,g,[]},ok}}],
+ {?eh,tc_start,{S,end_per_suite}},
+ {?eh,tc_done,{S,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}
+ ].
+
+%% test events help functions
+contains(List) ->
+ fun(Proplist) when is_list(Proplist) ->
+ contains(List,Proplist)
+ end.
+
+contains([{not_in_order,List}|T],Rest) ->
+ contains_parallel(List,Rest),
+ contains(T,Rest);
+contains([{Ele,Pos}|T] = L,[H|T2]) ->
+ case element(Pos,H) of
+ Ele ->
+ contains(T,T2);
+ _ ->
+ contains(L,T2)
+ end;
+contains([Ele|T],[{Ele,_}|T2])->
+ contains(T,T2);
+contains([Ele|T],[Ele|T2])->
+ contains(T,T2);
+contains(List,[_|T]) ->
+ contains(List,T);
+contains([],_) ->
+ match.
+
+contains_parallel([Key | T], Elems) ->
+ contains([Key],Elems),
+ contains_parallel(T,Elems);
+contains_parallel([],_Elems) ->
+ match.
+
+not_contains(List) ->
+ fun(Proplist) when is_list(Proplist) ->
+ [] = [Ele || {Ele,_} <- Proplist,
+ Test <- List,
+ Test =:= Ele]
+ end.
diff --git a/lib/common_test/test/ct_util_SUITE_data/ct_util_cth.erl b/lib/common_test/test/ct_util_SUITE_data/ct_util_cth.erl
new file mode 100644
index 0000000000..34c1568a87
--- /dev/null
+++ b/lib/common_test/test/ct_util_SUITE_data/ct_util_cth.erl
@@ -0,0 +1,105 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+
+-module(ct_util_cth).
+
+
+-include_lib("common_test/src/ct_util.hrl").
+-include_lib("common_test/include/ct_event.hrl").
+
+%% Send a cth_error event if a callback is called with unexpected arguments
+
+%% CT Hooks
+-compile(export_all).
+
+id(Opts) ->
+ erlang:system_time(second).
+
+init(Id, Opts) ->
+ {ok,ok}.
+
+pre_init_per_suite(Suite,Config,State) ->
+ maybe_sleep(?FUNCTION_NAME,Suite),
+ {Config, State}.
+
+post_init_per_suite(Suite,Config,Return,State) ->
+ maybe_sleep(?FUNCTION_NAME,Suite),
+ {Return, State}.
+
+pre_end_per_suite(Suite,Config,State) ->
+ maybe_sleep(?FUNCTION_NAME,Suite),
+ {Config, State}.
+
+post_end_per_suite(Suite,Config,Return,State) ->
+ maybe_sleep(?FUNCTION_NAME,Suite),
+ {Return, State}.
+
+pre_init_per_group(Suite, Group, Config, State) ->
+ maybe_sleep(?FUNCTION_NAME,Suite,Group),
+ {Config,State}.
+
+post_init_per_group(Suite, Group, Config,Return,State) ->
+ maybe_sleep(?FUNCTION_NAME,Suite,Group),
+ {Return,State}.
+
+pre_end_per_group(Suite, Group, Config, State) ->
+ maybe_sleep(?FUNCTION_NAME,Suite,Group),
+ {Config,State}.
+
+post_end_per_group(Suite, Group, Config,Return,State) ->
+ maybe_sleep(?FUNCTION_NAME,Suite,Group),
+ {Return,State}.
+
+pre_init_per_testcase(Suite, TC, Config, State) ->
+ maybe_sleep(?FUNCTION_NAME,Suite,TC),
+ {Config,State}.
+
+post_init_per_testcase(Suite, TC, Config,Return,State) ->
+ maybe_sleep(?FUNCTION_NAME,Suite,TC),
+ {Return,State}.
+
+pre_end_per_testcase(Suite, TC, Config, State) ->
+ maybe_sleep(?FUNCTION_NAME,Suite,TC),
+ {Config,State}.
+
+post_end_per_testcase(Suite, TC, Config,Return,State) ->
+ maybe_sleep(?FUNCTION_NAME,Suite,TC),
+ {Return,State}.
+
+%%%-----------------------------------------------------------------
+maybe_sleep(FuncName,Suite) ->
+ maybe_sleep(FuncName,Suite,undefined).
+maybe_sleep(FuncName,Suite,GroupOrTC) ->
+ case ct:get_config(FuncName) of
+ {Suite,GroupOrTC,Fail} ->
+ fail(Fail);
+ {Suite,Fail} when GroupOrTC=:=undefined ->
+ fail(Fail);
+ _ ->
+ ok
+ end.
+
+fail({timeout,T}) ->
+ timer:sleep(T);
+fail(kill) ->
+ spawn_link(fun() -> ct:fail(hahahahahah) end),
+ timer:sleep(10000).
+
diff --git a/lib/common_test/test/ct_util_SUITE_data/curr_tc_SUITE.erl b/lib/common_test/test/ct_util_SUITE_data/curr_tc_SUITE.erl
new file mode 100644
index 0000000000..b48ba4d24e
--- /dev/null
+++ b/lib/common_test/test/ct_util_SUITE_data/curr_tc_SUITE.erl
@@ -0,0 +1,59 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(curr_tc_SUITE).
+
+-suite_defaults([{timetrap, {seconds, 3}}]).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include("ct.hrl").
+
+init_per_suite(Config) ->
+ [{?MODULE,?FUNCTION_NAME}] = ct_util:get_testdata(curr_tc),
+ Config.
+
+end_per_suite(Config) ->
+ [{?MODULE,?FUNCTION_NAME}] = ct_util:get_testdata(curr_tc),
+ ok.
+
+init_per_group(_Group,Config) ->
+ [{?MODULE,?FUNCTION_NAME}] = ct_util:get_testdata(curr_tc),
+ Config.
+
+end_per_group(_Group,Config) ->
+ [{?MODULE,?FUNCTION_NAME}] = ct_util:get_testdata(curr_tc),
+ ok.
+
+all() ->
+ [tc1,tc2,{group,g}].
+
+groups() ->
+ [{g,[tc1,tc2]}].
+
+%% Test cases starts here.
+tc1(_Config) ->
+ [{?MODULE,?FUNCTION_NAME}] = ct_util:get_testdata(curr_tc),
+ ok.
+
+tc2(_Config) ->
+ [{?MODULE,?FUNCTION_NAME}] = ct_util:get_testdata(curr_tc),
+ ok.
diff --git a/lib/common_test/test/ct_verbosity_SUITE_data/simple_evh.erl b/lib/common_test/test/ct_verbosity_SUITE_data/simple_evh.erl
index 03a0832e53..d1c293b4af 100644
--- a/lib/common_test/test/ct_verbosity_SUITE_data/simple_evh.erl
+++ b/lib/common_test/test/ct_verbosity_SUITE_data/simple_evh.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,14 +18,14 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Framework Event Handler
+%%% Common Test Framework Event Handler
%%%
-%%% <p>This module implements an event handler that CT uses to
+%%% This module implements an event handler that CT uses to
%%% handle status and progress notifications during test runs.
%%% The notifications are handled locally (per node) and passed
%%% on to ct_master when CT runs in distributed mode. This
%%% module may be used as a template for other event handlers
-%%% that can be plugged in to handle local logging and reporting.</p>
+%%% that can be plugged in to handle local logging and reporting.
-module(simple_evh).
-behaviour(gen_event).
diff --git a/lib/common_test/test/erl2html2_SUITE.erl b/lib/common_test/test/erl2html2_SUITE.erl
index 53a63578b2..b2336ff0bc 100644
--- a/lib/common_test/test/erl2html2_SUITE.erl
+++ b/lib/common_test/test/erl2html2_SUITE.erl
@@ -214,10 +214,10 @@ check_line_number(Last,Line,OrigLine) ->
[$>|Rest] = lists:dropwhile(fun($>) -> false; (_) -> true end,Line),
check_line_number(Last,Rest,OrigLine);
_ ->
- [N |_] = string:tokens(Line,":"),
+ [N |_] = string:lexemes(Line,":"),
% erlang:display(N),
Num =
- try list_to_integer(string:strip(N))
+ try list_to_integer(string:trim(N,both,"\s"))
catch _:_ -> ct:fail({no_line_number_after,Last,OrigLine})
end,
if Num == Last+1 ->
diff --git a/lib/common_test/test/telnet_server.erl b/lib/common_test/test/telnet_server.erl
index 65300b0bdf..cef7784333 100644
--- a/lib/common_test/test/telnet_server.erl
+++ b/lib/common_test/test/telnet_server.erl
@@ -249,7 +249,7 @@ do_handle_data("echo " ++ Data,State) ->
send(Data++"\r\n> ",State),
{ok,State};
do_handle_data("echo_sep " ++ Data,State) ->
- Msgs = string:tokens(Data," "),
+ Msgs = string:lexemes(Data," "),
lists:foreach(fun(Msg) ->
send(Msg,State),
timer:sleep(10)
@@ -260,28 +260,28 @@ do_handle_data("echo_no_prompt " ++ Data,State) ->
send(Data,State),
{ok,State};
do_handle_data("echo_ml " ++ Data,State) ->
- Lines = string:tokens(Data," "),
- ReturnData = string:join(Lines,"\n"),
+ Lines = string:lexemes(Data," "),
+ ReturnData = lists:flatten(lists:join("\n",Lines)),
send(ReturnData++"\r\n> ",State),
{ok,State};
do_handle_data("echo_ml_no_prompt " ++ Data,State) ->
- Lines = string:tokens(Data," "),
- ReturnData = string:join(Lines,"\n"),
+ Lines = string:lexemes(Data," "),
+ ReturnData = lists:flatten(lists:join("\n",Lines)),
send(ReturnData,State),
{ok,State};
do_handle_data("echo_loop " ++ Data,State) ->
- [TStr|Lines] = string:tokens(Data," "),
- ReturnData = string:join(Lines,"\n"),
+ [TStr|Lines] = string:lexemes(Data," "),
+ ReturnData = lists:flatten(lists:join("\n",Lines)),
send_loop(list_to_integer(TStr),ReturnData,State),
{ok,State};
do_handle_data("echo_delayed_prompt "++Data,State) ->
- [MsStr|EchoData] = string:tokens(Data, " "),
- send(string:join(EchoData,"\n"),State),
+ [MsStr|EchoData] = string:lexemes(Data, " "),
+ send(lists:flatten(lists:join("\n",EchoData)),State),
timer:sleep(list_to_integer(MsStr)),
send("\r\n> ",State),
{ok,State};
do_handle_data("disconnect_after " ++WaitStr,State) ->
- Wait = list_to_integer(string:strip(WaitStr,right,$\n)),
+ Wait = list_to_integer(string:trim(WaitStr,trailing,"\n")),
dbg("Server will close connection in ~w ms...", [Wait]),
erlang:send_after(Wait,self(),disconnect),
{ok,State};
diff --git a/lib/common_test/test/test_server_SUITE.erl b/lib/common_test/test/test_server_SUITE.erl
index 50d8bdd1ac..6e52f24025 100644
--- a/lib/common_test/test/test_server_SUITE.erl
+++ b/lib/common_test/test/test_server_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,12 +18,7 @@
%% %CopyrightEnd%
%%
%%%-------------------------------------------------------------------
-%%% @author Lukas Larsson <[email protected]>
-%%% @copyright (C) 2011, Erlang Solutions Ltd.
-%%% @doc
-%%%
-%%% @end
-%%% Created : 15 Feb 2011 by Lukas Larsson <[email protected]>
+%%% Author: Lukas Larsson <[email protected]>
%%%-------------------------------------------------------------------
-module(test_server_SUITE).
@@ -71,7 +66,7 @@ init_per_testcase(_TestCase, Config) ->
%% @spec end_per_testcase(TestCase, Config0) ->
%% void() | {save_config,Config1} | {fail,Reason}
end_per_testcase(test_server_unicode, _Config) ->
- [_,Host] = string:tokens(atom_to_list(node()), "@"),
+ [_,Host] = string:lexemes(atom_to_list(node()), "@"),
N1 = list_to_atom("test_server_tester_latin1" ++ "@" ++ Host),
N2 = list_to_atom("test_server_tester_utf8" ++ "@" ++ Host),
test_server:stop_node(N1),
@@ -265,7 +260,7 @@ translate_filename(Filename,EncodingOnTestNode) ->
end.
get_latest_run_dir(Dir) ->
- %% For the time being, filelib:wildcard can not take a binary
+ %% For the time being, filelib:wildcard cannot take a binary
%% argument, so we avoid using this here.
case file:list_dir(Dir) of
{ok,Files} ->
@@ -320,7 +315,7 @@ generate_and_run_unicode_test(Config0,Encoding) ->
DataDir = ?config(data_dir,Config0),
Suite = create_unicode_test_suite(DataDir,Encoding),
- %% We can not run this test on default node since it must be
+ %% We cannot run this test on default node since it must be
%% started with correct file name mode (+fnu/+fnl).
%% OBS: the node are stopped by end_per_testcase/2
Config1 = lists:keydelete(node,1,Config0),
@@ -347,7 +342,7 @@ generate_and_run_unicode_test(Config0,Encoding) ->
RunDir = get_latest_run_dir(LogDir),
true = filelib:is_dir(RunDir),
- LowerModStr = string:to_lower(ModStr),
+ LowerModStr = string:lowercase(ModStr),
SuiteHtml = translate_filename(LowerModStr++".src.html",Encoding),
true = filelib:is_regular(filename:join(RunDir,SuiteHtml)),
@@ -362,7 +357,7 @@ generate_and_run_unicode_test(Config0,Encoding) ->
%% remote file system on master - i.e. they will use same file name
%% mode as the master.
start_node(Config,Name,Args) ->
- [_,Host] = string:tokens(atom_to_list(node()), "@"),
+ [_,Host] = string:lexemes(atom_to_list(node()), "@"),
ct:log("Trying to start ~w@~s~n",[Name,Host]),
case test_server:start_node(Name, peer, [{args,Args}]) of
{error,Reason} ->
diff --git a/lib/common_test/test/test_server_test_lib.erl b/lib/common_test/test/test_server_test_lib.erl
index c18b89b178..58b3aaee9b 100644
--- a/lib/common_test/test/test_server_test_lib.erl
+++ b/lib/common_test/test/test_server_test_lib.erl
@@ -22,7 +22,7 @@
-export([parse_suite/1]).
-export([init/2, pre_init_per_testcase/3, post_end_per_testcase/4]).
-%% for test_server_SUITE when node can not be started as slave
+%% for test_server_SUITE when node cannot be started as slave
-export([prepare_tester_node/2]).
-include("test_server_test_lib.hrl").
@@ -43,7 +43,7 @@ pre_init_per_testcase(_TC,Config,State) ->
{start_slave(Config, 50),State}.
start_slave(Config,_Level) ->
- [_,Host] = string:tokens(atom_to_list(node()), "@"),
+ [_,Host] = string:lexemes(atom_to_list(node()), "@"),
ct:log("Trying to start ~s~n",
["test_server_tester@"++Host]),
@@ -121,7 +121,7 @@ parse_suite(FileName) ->
end.
fline(Fd) ->
- case prim_file:read_line(Fd) of
+ case file:read_line(Fd) of
eof -> eof;
{ok, Line} -> Line
end.
diff --git a/lib/common_test/test_server/configure.in b/lib/common_test/test_server/configure.in
index 0511d126b4..a32d050081 100644
--- a/lib/common_test/test_server/configure.in
+++ b/lib/common_test/test_server/configure.in
@@ -171,7 +171,7 @@ case $system in
fi
SHLIB_EXTRACT_ALL=""
;;
- *-openbsd*)
+ *-openbsd*|*-netbsd*|*-freebsd*|*-dragonfly*)
# Not available on all versions: check for include file.
AC_CHECK_HEADER(dlfcn.h, [
SHLIB_CFLAGS="-fpic"
@@ -194,29 +194,6 @@ case $system in
])
SHLIB_EXTRACT_ALL=""
;;
- *-netbsd*|*-freebsd*|*-dragonfly*)
- # Not available on all versions: check for include file.
- AC_CHECK_HEADER(dlfcn.h, [
- SHLIB_CFLAGS="-fpic"
- SHLIB_LD="ld"
- SHLIB_LDFLAGS="$LDFLAGS -Bshareable -x"
- SHLIB_SUFFIX=".so"
- if test X${enable_m64_build} = Xyes; then
- AC_MSG_ERROR(don't know how to link 64-bit dynamic drivers)
- fi
- if test X${enable_m32_build} = Xyes; then
- AC_MSG_ERROR(don't know how to link 32-bit dynamic drivers)
- fi
- ], [
- # No dynamic loading.
- SHLIB_CFLAGS=""
- SHLIB_LD="ld"
- SHLIB_LDFLAGS=""
- SHLIB_SUFFIX=""
- AC_MSG_ERROR(don't know how to compile and link dynamic drivers)
- ])
- SHLIB_EXTRACT_ALL=""
- ;;
*-solaris2*|*-sysv4*)
SHLIB_CFLAGS="-KPIC"
SHLIB_LD="/usr/ccs/bin/ld"
@@ -459,11 +436,11 @@ dnl Freely inspired by AC_TRY_LINK. (Maybe better to create a
dnl AC_LANG_JAVA instead...)
AC_DEFUN(ERL_TRY_LINK_JAVA,
[java_link='$JAVAC conftest.java 1>&AC_FD_CC'
-changequote(�, �)dnl
+changequote(, )dnl
cat > conftest.java <<EOF
-�$1�
+$1
class conftest { public static void main(String[] args) {
- �$2�
+ $2
; return; }}
EOF
changequote([, ])dnl
diff --git a/lib/common_test/test_server/ts.erl b/lib/common_test/test_server/ts.erl
index 5bfea9f4de..179380a562 100644
--- a/lib/common_test/test_server/ts.erl
+++ b/lib/common_test/test_server/ts.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -583,7 +583,7 @@ is_list_of_suites(List) ->
S = if is_atom(Suite) -> atom_to_list(Suite);
true -> Suite
end,
- try lists:last(string:tokens(S,"_")) of
+ try lists:last(string:lexemes(S,"_")) of
"SUITE" -> true;
"suite" -> true;
_ -> false
diff --git a/lib/common_test/test_server/ts_autoconf_win32.erl b/lib/common_test/test_server/ts_autoconf_win32.erl
index 52e5ac8e69..1179dfe0e5 100644
--- a/lib/common_test/test_server/ts_autoconf_win32.erl
+++ b/lib/common_test/test_server/ts_autoconf_win32.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -228,7 +228,7 @@ make(Vars) ->
end.
find_make(MakeCmd, Vars) ->
- [Make|_] = string:tokens(MakeCmd, " \t"),
+ [Make|_] = string:lexemes(MakeCmd, " \t"),
case os:find_executable(Make) of
false ->
{no, Vars};
@@ -248,9 +248,9 @@ javac(Vars) ->
end.
is_debug_build() ->
- case catch string:str(erlang:system_info(system_version), "debug") of
- Int when is_integer(Int), Int > 0 ->
- true;
- _ ->
- false
+ case catch string:find(erlang:system_info(system_version), "debug") of
+ nomatch ->
+ false;
+ _Else ->
+ true
end.
diff --git a/lib/common_test/test_server/ts_benchmark.erl b/lib/common_test/test_server/ts_benchmark.erl
index e4e06b54c2..a9486262b3 100644
--- a/lib/common_test/test_server/ts_benchmark.erl
+++ b/lib/common_test/test_server/ts_benchmark.erl
@@ -45,7 +45,7 @@ run(Specs, Opts, Vars) ->
|| Spec <- Specs],
file:delete(filename:join(Cwd,"latest_benchmark")),
{ok,D} = file:open(filename:join(Cwd,"latest_benchmark"),[write]),
- io:format(D,BDir,[]),
+ io:format(D,"~ts", [BDir]),
file:close(D).
diff --git a/lib/common_test/test_server/ts_erl_config.erl b/lib/common_test/test_server/ts_erl_config.erl
index 032593bdda..f3972bea4e 100644
--- a/lib/common_test/test_server/ts_erl_config.erl
+++ b/lib/common_test/test_server/ts_erl_config.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -208,7 +208,11 @@ erl_interface(Vars,OsType) ->
{filename:join(Dir, "lib"),
filename:join([Dir, "src", "eidefs.mk"])};
{srctree, _Root, Target} ->
- {filename:join([Dir, "obj", Target]),
+ Obj = case is_debug_build() of
+ true -> "obj.debug";
+ false -> "obj"
+ end,
+ {filename:join([Dir, Obj, Target]),
filename:join([Dir, "src", Target, "eidefs.mk"])}
end}
end,
@@ -311,7 +315,7 @@ lib_dir(Vars, Lib) ->
end,
CLibDir = filename:join(CLibDirList),
Cmd = "ls -d " ++ CLibDir ++ "*",
- XLibDir = lists:last(string:tokens(os:cmd(Cmd),"\n")),
+ XLibDir = lists:last(string:lexemes(os:cmd(Cmd),"\n")),
case file:list_dir(XLibDir) of
{error, enoent} ->
[];
@@ -358,18 +362,22 @@ link_library(_LibName,_Other) ->
%% Returns emulator specific variables.
emu_vars(Vars) ->
[{is_source_build, is_source_build()},
- {erl_name, atom_to_list(lib:progname())}|Vars].
+ {erl_name, get_progname()}|Vars].
+
+get_progname() ->
+ case init:get_argument(progname) of
+ {ok, [[Prog]]} ->
+ Prog;
+ _Other ->
+ "no_prog_name"
+ end.
is_source_build() ->
- string:str(erlang:system_info(system_version), "[source]") > 0.
+ string:find(erlang:system_info(system_version), "source") =/= nomatch.
is_debug_build() ->
- case catch string:str(erlang:system_info(system_version), "debug") of
- Int when is_integer(Int), Int > 0 ->
- true;
- _ ->
- false
- end.
+ string:find(erlang:system_info(system_version), "debug") =/= nomatch.
+
%%
%% ssl_libdir
%%
diff --git a/lib/common_test/test_server/ts_install.erl b/lib/common_test/test_server/ts_install.erl
index c4e0223ac7..86f16fa072 100644
--- a/lib/common_test/test_server/ts_install.erl
+++ b/lib/common_test/test_server/ts_install.erl
@@ -112,12 +112,6 @@ get_vars([], name, [], Result) ->
get_vars(_, _, _, _) ->
{error, fatal_bad_conf_vars}.
-config_flags() ->
- case os:getenv("CONFIG_FLAGS") of
- false -> [];
- CF -> string:tokens(CF, " \t\n")
- end.
-
unix_autoconf(XConf) ->
Configure = filename:absname("configure"),
Flags = proplists:get_value(crossflags,XConf,[]),
@@ -127,8 +121,8 @@ unix_autoconf(XConf) ->
Threads = [" --enable-shlib-thread-safety" ||
erlang:system_info(threads) /= false],
Debug = [" --enable-debug-mode" ||
- string:str(erlang:system_info(system_version),"debug") > 0],
- MXX_Build = [Y || Y <- config_flags(),
+ string:find(erlang:system_info(system_version),"debug") =/= nomatch],
+ MXX_Build = [Y || Y <- string:lexemes(os:getenv("CONFIG_FLAGS", ""), " \t\n"),
Y == "--enable-m64-build"
orelse Y == "--enable-m32-build"],
Args = Host ++ Build ++ Threads ++ Debug ++ " " ++ MXX_Build,
@@ -159,14 +153,12 @@ assign_vars([]) ->
assign_vars([{VAR,FlagsStr} | VARs]) ->
[{VAR,assign_vars(FlagsStr)} | assign_vars(VARs)];
assign_vars(FlagsStr) ->
- Flags = [assign_all_vars(Str,[]) || Str <- string:tokens(FlagsStr, [$ ])],
- string:strip(lists:flatten(lists:map(fun(Flag) ->
- Flag ++ " "
- end, Flags)), right).
+ Flags = [assign_all_vars(Str,[]) || Str <- string:lexemes(FlagsStr, [$\s])],
+ lists:flatten(lists:join(" ", Flags)).
assign_all_vars([$$ | Rest], FlagSoFar) ->
{VarName,Rest1} = get_var_name(Rest, []),
- assign_all_vars(Rest1, FlagSoFar ++ assign_var(VarName));
+ assign_all_vars(Rest1, FlagSoFar ++ os:getenv(VarName, ""));
assign_all_vars([Char | Rest], FlagSoFar) ->
assign_all_vars(Rest, FlagSoFar ++ [Char]);
assign_all_vars([], Flag) ->
@@ -179,12 +171,6 @@ get_var_name([Ch | Rest] = Str, VarR) ->
end;
get_var_name([], VarR) ->
{lists:reverse(VarR),[]}.
-
-assign_var(VarName) ->
- case os:getenv(VarName) of
- false -> "";
- Val -> Val
- end.
valid_char(Ch) when Ch >= $a, Ch =< $z -> true;
valid_char(Ch) when Ch >= $A, Ch =< $Z -> true;
@@ -282,7 +268,7 @@ add_vars(Vars0, Opts0) ->
{Opts, [{longnames, LongNames},
{platform_id, PlatformId},
{platform_filename, PlatformFilename},
- {rsh_name, get_rsh_name()},
+ {rsh_name, os:getenv("ERL_RSH", "ssh")},
{platform_label, PlatformLabel},
{ts_net_dir, Mounted},
{erl_flags, []},
@@ -292,7 +278,7 @@ add_vars(Vars0, Opts0) ->
get_testcase_callback() ->
case os:getenv("TS_TESTCASE_CALLBACK") of
ModFunc when is_list(ModFunc), ModFunc /= "" ->
- case string:tokens(ModFunc, " ") of
+ case string:lexemes(ModFunc, " ") of
[_Mod,_Func] -> ModFunc;
_ -> ""
end;
@@ -303,16 +289,10 @@ get_testcase_callback() ->
end
end.
-get_rsh_name() ->
- case os:getenv("ERL_RSH") of
- false -> "rsh";
- Str -> Str
- end.
-
platform_id(Vars) ->
{Id,_,_,_} = platform(Vars),
Id.
-
+
platform(Vars) ->
Hostname = hostname(),
@@ -408,17 +388,13 @@ off_heap_msgq() ->
end.
schedulers() ->
- case catch erlang:system_info(smp_support) of
- true ->
- case {erlang:system_info(schedulers),
- erlang:system_info(schedulers_online)} of
- {S,S} ->
- "/S"++integer_to_list(S);
- {S,O} ->
- "/S"++integer_to_list(S) ++ ":" ++
- integer_to_list(O)
- end;
- _ -> ""
+ case {erlang:system_info(schedulers),
+ erlang:system_info(schedulers_online)} of
+ {S,S} ->
+ "/S"++integer_to_list(S);
+ {S,O} ->
+ "/S"++integer_to_list(S) ++ ":" ++
+ integer_to_list(O)
end.
bind_type() ->
@@ -434,8 +410,8 @@ bind_type() ->
debug() ->
- case string:str(erlang:system_info(system_version), "debug") of
- 0 -> "";
+ case string:find(erlang:system_info(system_version), "debug") of
+ nomatch -> "";
_ -> "/Debug"
end.
diff --git a/lib/common_test/test_server/ts_install_cth.erl b/lib/common_test/test_server/ts_install_cth.erl
index 5d325b1115..b6503fb864 100644
--- a/lib/common_test/test_server/ts_install_cth.erl
+++ b/lib/common_test/test_server/ts_install_cth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,7 +18,7 @@
%% %CopyrightEnd%
%%
-%%% @doc TS Installed SCB
+%%% TS Installed SCB
%%%
%%% This module does what the make parts of the ts:run/x command did,
%%% but not the Makefile.first parts! So they have to be done by ts or
@@ -60,13 +60,13 @@
-record(state, { ts_conf_dir, target_system, install_opts, nodenames, nodes }).
-%% @doc The id of this SCB
+%% The id of this SCB
-spec id(Opts :: term()) ->
Id :: term().
id(_Opts) ->
?MODULE.
-%% @doc Always called before any other callback function.
+%% Always called before any other callback function.
-spec init(Id :: term(), Opts :: proplists:proplist()) ->
{ok, State :: #state{}}.
init(_Id, Opts) ->
@@ -81,7 +81,7 @@ init(_Id, Opts) ->
target_system = TargetSystem,
install_opts = InstallOpts } }.
-%% @doc Called before init_per_suite is called.
+%% Called before init_per_suite is called.
-spec pre_init_per_suite(Suite :: atom(),
Config :: config(),
State :: #state{}) ->
@@ -108,13 +108,12 @@ pre_init_per_suite(_Suite,Config,State) ->
{add_node_name(Config, State), State}
catch error:{badmatch,{error,enoent}} ->
{add_node_name(Config, State), State};
- Error:Reason ->
- Stack = erlang:get_stacktrace(),
+ Error:Reason:Stack ->
ct:pal("~p failed! ~p:{~p,~p}",[?MODULE,Error,Reason,Stack]),
{{fail,{?MODULE,{Error,Reason, Stack}}},State}
end.
-%% @doc Called after init_per_suite.
+%% Called after init_per_suite.
-spec post_init_per_suite(Suite :: atom(),
Config :: config(),
Return :: config() | skip_or_fail(),
@@ -124,7 +123,7 @@ post_init_per_suite(_Suite,_Config,Return,State) ->
test_server_ctrl:kill_slavenodes(),
{Return, State}.
-%% @doc Called before end_per_suite.
+%% Called before end_per_suite.
-spec pre_end_per_suite(Suite :: atom(),
Config :: config() | skip_or_fail(),
State :: #state{}) ->
@@ -132,7 +131,7 @@ post_init_per_suite(_Suite,_Config,Return,State) ->
pre_end_per_suite(_Suite,Config,State) ->
{Config, State}.
-%% @doc Called after end_per_suite.
+%% Called after end_per_suite.
-spec post_end_per_suite(Suite :: atom(),
Config :: config(),
Return :: term(),
@@ -141,7 +140,7 @@ pre_end_per_suite(_Suite,Config,State) ->
post_end_per_suite(_Suite,_Config,Return,State) ->
{Return, State}.
-%% @doc Called before each init_per_group.
+%% Called before each init_per_group.
-spec pre_init_per_group(Group :: atom(),
Config :: config(),
State :: #state{}) ->
@@ -149,7 +148,7 @@ post_end_per_suite(_Suite,_Config,Return,State) ->
pre_init_per_group(_Group,Config,State) ->
{add_node_name(Config, State), State}.
-%% @doc Called after each init_per_group.
+%% Called after each init_per_group.
-spec post_init_per_group(Group :: atom(),
Config :: config(),
Return :: config() | skip_or_fail(),
@@ -158,7 +157,7 @@ pre_init_per_group(_Group,Config,State) ->
post_init_per_group(_Group,_Config,Return,State) ->
{Return, State}.
-%% @doc Called after each end_per_group.
+%% Called after each end_per_group.
-spec pre_end_per_group(Group :: atom(),
Config :: config() | skip_or_fail(),
State :: #state{}) ->
@@ -166,7 +165,7 @@ post_init_per_group(_Group,_Config,Return,State) ->
pre_end_per_group(_Group,Config,State) ->
{Config, State}.
-%% @doc Called after each end_per_group.
+%% Called after each end_per_group.
-spec post_end_per_group(Group :: atom(),
Config :: config(),
Return :: term(),
@@ -175,7 +174,7 @@ pre_end_per_group(_Group,Config,State) ->
post_end_per_group(_Group,_Config,Return,State) ->
{Return, State}.
-%% @doc Called before each test case.
+%% Called before each test case.
-spec pre_init_per_testcase(TC :: atom(),
Config :: config(),
State :: #state{}) ->
@@ -191,7 +190,7 @@ pre_init_per_testcase(_TC,Config,State) ->
post_init_per_testcase(_TC,_Config,Return,State) ->
{Return, State}.
-%% @doc Called after each test case.
+%% Called after each test case.
-spec pre_end_per_testcase(TC :: atom(),
Config :: config(),
State :: #state{}) ->
@@ -207,7 +206,7 @@ pre_end_per_testcase(_TC,Config,State) ->
post_end_per_testcase(_TC,_Config,Return,State) ->
{Return, State}.
-%% @doc Called after a test case failed.
+%% Called after a test case failed.
-spec on_tc_fail(TC :: init_per_suite | end_per_suite |
init_per_group | end_per_group | atom(),
Reason :: term(), State :: #state{}) ->
@@ -215,7 +214,7 @@ post_end_per_testcase(_TC,_Config,Return,State) ->
on_tc_fail(_TC, _Reason, State) ->
State.
-%% @doc Called when a test case is skipped.
+%% Called when a test case is skipped.
-spec on_tc_skip(TC :: end_per_suite | init_per_group | end_per_group | atom(),
{tc_auto_skip, {failed, {Mod :: atom(), Function :: atom(),
Reason :: term()}}} |
@@ -225,7 +224,7 @@ on_tc_fail(_TC, _Reason, State) ->
on_tc_skip(_TC, _Reason, State) ->
State.
-%% @doc Called when the scope of the SCB is done.
+%% Called when the scope of the SCB is done.
-spec terminate(State :: #state{}) ->
term().
terminate(_State) ->
diff --git a/lib/common_test/test_server/ts_lib.erl b/lib/common_test/test_server/ts_lib.erl
index ea039a2c2b..7c1c14f467 100644
--- a/lib/common_test/test_server/ts_lib.erl
+++ b/lib/common_test/test_server/ts_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -99,7 +99,7 @@ specialized_specs(Dir,PostFix) ->
sort_tests([begin
DirPart = filename:dirname(Name),
AppTest = hd(lists:reverse(filename:split(DirPart))),
- list_to_atom(string:substr(AppTest, 1, length(AppTest)-5))
+ list_to_atom(string:slice(AppTest, 0, string:length(AppTest)-5))
end || Name <- Specs]).
specs(Dir) ->
@@ -111,9 +111,9 @@ specs(Dir) ->
[Spec,TestDir|_] =
lists:reverse(filename:split(FullName)),
[_TestSuffix|TDParts] =
- lists:reverse(string:tokens(TestDir,[$_,$.])),
+ lists:reverse(string:lexemes(TestDir,[$_,$.])),
[_SpecSuffix|SParts] =
- lists:reverse(string:tokens(Spec,[$_,$.])),
+ lists:reverse(string:lexemes(Spec,[$_,$.])),
if TDParts == SParts ->
[filename_to_atom(FullName)];
true ->
@@ -273,7 +273,7 @@ do_test(Rest, Vars, Test) ->
get_arg([$(|Rest], Vars, Stop, _) ->
get_arg(Rest, Vars, Stop, []);
get_arg([Stop|Rest], Vars, Stop, Acc) ->
- Arg = string:strip(lists:reverse(Acc)),
+ Arg = string:trim(lists:reverse(Acc),both,[$\s]),
Subst = subst(Arg, Vars),
{Subst,Rest};
get_arg([C|Rest], Vars, Stop, Acc) ->
diff --git a/lib/common_test/test_server/ts_run.erl b/lib/common_test/test_server/ts_run.erl
index e22fa8d196..7e12b9652c 100644
--- a/lib/common_test/test_server/ts_run.erl
+++ b/lib/common_test/test_server/ts_run.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -199,7 +199,7 @@ make_command(Vars, Spec, State) ->
TestPath = filename:nativename(TestDir),
Erl = case os:getenv("TS_RUN_VALGRIND") of
false ->
- atom_to_list(lib:progname());
+ ct:get_progname();
_ ->
case State#state.file of
Dir when is_list(Dir) ->
@@ -207,11 +207,7 @@ make_command(Vars, Spec, State) ->
_ ->
ok
end,
- "cerl -valgrind" ++
- case erlang:system_info(smp_support) of
- true -> " -smp";
- false -> ""
- end
+ "cerl -valgrind"
end,
Naming =
case ts_lib:var(longnames, Vars) of
@@ -415,9 +411,9 @@ make_common_test_args(Args0, Options0, _Vars) ->
end,
ConfigFiles = [{config,[filename:join(ConfigPath,File)
|| File <- get_config_files()]}],
- io_lib:format("~100000p",[[{abort_if_missing_suites,true} |
- Args0++Trace++Cover++Logdir++
- ConfigFiles++Options++TimeTrap]]).
+ io_lib:format("~0p",[[{abort_if_missing_suites,true} |
+ Args0++Trace++Cover++Logdir++
+ ConfigFiles++Options++TimeTrap]]).
to_list(X) when is_atom(X) ->
atom_to_list(X);
@@ -468,4 +464,4 @@ split_one(Path) ->
filename:split(Path).
split_path(Path) ->
- string:tokens(Path,";").
+ string:lexemes(Path,";").
diff --git a/lib/common_test/vsn.mk b/lib/common_test/vsn.mk
index ea3e9871cb..8dcb69c1c6 100644
--- a/lib/common_test/vsn.mk
+++ b/lib/common_test/vsn.mk
@@ -1 +1 @@
-COMMON_TEST_VSN = 1.15.4
+COMMON_TEST_VSN = 1.17.3
diff --git a/lib/compiler/doc/src/Makefile b/lib/compiler/doc/src/Makefile
index 13210de040..2fb163b9e7 100644
--- a/lib/compiler/doc/src/Makefile
+++ b/lib/compiler/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2017. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@ APPLICATION=compiler
# Release directory specification
# ----------------------------------------------------
RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
+COMPILER_DIR = $(ERL_TOP)/lib/compiler/src
# ----------------------------------------------------
# Target Specs
@@ -38,7 +39,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
XML_APPLICATION_FILES = ref_man.xml
XML_REF3_FILES = compile.xml
-XML_PART_FILES =
+XML_PART_FILES = internal.xml
XML_CHAPTER_FILES = notes.xml
BOOK_FILES = book.xml
@@ -49,6 +50,9 @@ XML_FILES = \
$(BOOK_FILES) $(XML_CHAPTER_FILES) \
$(XML_PART_FILES) $(XML_REF3_FILES) $(XML_APPLICATION_FILES)
+XML_INTERNAL_FILES = \
+ cerl.xml cerl_trees.xml cerl_clauses.xml
+
# ----------------------------------------------------
HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \
@@ -62,6 +66,8 @@ HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
+XML_GEN_FILES = $(XML_INTERNAL_FILES:%=$(XMLDIR)/%)
+
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
@@ -85,10 +91,14 @@ man: $(MAN3_FILES)
gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
+$(XML_INTERNAL_FILES:%=$(XMLDIR)/%): $(COMPILER_DIR)/$(@:$(XMLDIR)/%.xml=%.erl)
+ $(gen_verbose)escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(COMPILER_VSN) -dir $(XMLDIR) $(COMPILER_DIR)/$(@:$(XMLDIR)/%.xml=%.erl)
+
debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/lib/compiler/doc/src/book.xml b/lib/compiler/doc/src/book.xml
index af6b4cf47a..d101d40cb4 100644
--- a/lib/compiler/doc/src/book.xml
+++ b/lib/compiler/doc/src/book.xml
@@ -38,6 +38,9 @@
<applications>
<xi:include href="ref_man.xml"/>
</applications>
+ <internals>
+ <xi:include href="internal.xml"/>
+ </internals>
<releasenotes>
<xi:include href="notes.xml"/>
</releasenotes>
diff --git a/lib/compiler/doc/src/compile.xml b/lib/compiler/doc/src/compile.xml
index 10164890f2..549b1049d8 100644
--- a/lib/compiler/doc/src/compile.xml
+++ b/lib/compiler/doc/src/compile.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -29,7 +29,7 @@
<rev>A</rev>
<file>compile.sgml</file>
</header>
- <module>compile</module>
+ <module since="">compile</module>
<modulesummary>Erlang Compiler</modulesummary>
<description>
<p>This module provides an interface to the standard Erlang
@@ -40,7 +40,7 @@
<funcs>
<func>
- <name>env_compiler_options()</name>
+ <name since="OTP 19.0">env_compiler_options()</name>
<fsummary>
Compiler options defined via the environment variable
<c>ERL_COMPILER_OPTIONS</c>
@@ -53,7 +53,7 @@
</desc>
</func>
<func>
- <name>file(File)</name>
+ <name since="">file(File)</name>
<fsummary>Compiles a file.</fsummary>
<desc>
<p>Is the same as
@@ -63,7 +63,7 @@
</func>
<func>
- <name>file(File, Options) -> CompRet</name>
+ <name since="">file(File, Options) -> CompRet</name>
<fsummary>Compiles a file.</fsummary>
<type>
<v>CompRet = ModRet | BinRet | ErrRet</v>
@@ -123,6 +123,17 @@
in the Efficiency Guide.</p>
</item>
+ <tag><c>{compile_info, [{atom(), term()}]}</c></tag>
+ <item>
+ <p>Allows compilers built on top of <c>compile</c> to attach
+ extra compilation metadata to the <c>compile_info</c> chunk
+ in the generated beam file.</p>
+
+ <p>It is advised for compilers to remove all non-deterministic
+ information if the <c>deterministic</c> option is supported and
+ it was supplied by the user.</p>
+ </item>
+
<tag><c>compressed</c></tag>
<item>
<p>The compiler will compress the generated object code,
@@ -192,7 +203,8 @@
<tag><c>deterministic</c></tag>
<item>
<p>Omit the <c>options</c> and <c>source</c> tuples in
- the list returned by <c>Module:module_info(compile)</c>.
+ the list returned by <c>Module:module_info(compile)</c>, and
+ reduce the paths in stack traces to the module name alone.
This option will make it easier to achieve reproducible builds.
</p>
</item>
@@ -222,6 +234,15 @@ module.beam: module.erl \
header.hrl</code>
</item>
+ <tag><c>makedep_side_effect</c></tag>
+ <item>
+ <p>The dependecies are created as a side effect to the
+ normal compilation process. This means that the object
+ file will also be produced. This option override the
+ <c>makedep</c> option.
+ </p>
+ </item>
+
<tag><c>{makedep_output, Output}</c></tag>
<item>
<p>Writes generated rules to <c>Output</c> instead of the
@@ -327,8 +348,8 @@ module.beam: module.erl \
<tag><c>{source,FileName}</c></tag>
<item>
- <p>Sets the value of the source, as returned by
- <c>module_info(compile)</c>.</p>
+ <p>Overrides the source file name as presented in
+ <c>module_info(compile)</c> and stack traces.</p>
</item>
<tag><c>{outdir,Dir}</c></tag>
@@ -395,6 +416,17 @@ module.beam: module.erl \
is not documented, and can change between releases.</p>
</item>
+ <tag><c>no_spawn_compiler_process</c></tag>
+ <item>
+ <p>By default, all code is compiled in a separate process
+ which is terminated at the end of compilation. However,
+ some tools, like Dialyzer or compilers for other BEAM languages,
+ may already manage their own worker processes and spawning
+ an extra process may slow the compilation down.
+ In such scenarios, you can pass this option to stop the
+ compiler from spawning an additional process.</p>
+ </item>
+
<tag><c>no_strict_record_tests</c></tag>
<item>
<p>This option is not recommended.</p>
@@ -600,6 +632,22 @@ module.beam: module.erl \
to be deprecated.</p>
</item>
+ <tag><c>nowarn_removed</c></tag>
+ <item>
+ <p>Turns off warnings for calls to functions that have
+ been removed. Default is to emit warnings for every call
+ to a function known by the compiler to have been recently
+ removed from Erlang/OTP.</p>
+ </item>
+
+ <tag><c>{nowarn_removed, ModulesOrMFAs}</c></tag>
+ <item>
+ <p>Turns off warnings for calls to modules or functions
+ that have been removed. Default is to emit warnings for
+ every call to a function known by the compiler to have
+ been recently removed from Erlang/OTP.</p>
+ </item>
+
<tag><c>nowarn_obsolete_guard</c></tag>
<item>
<p>Turns off warnings for calls to old type testing BIFs,
@@ -629,14 +677,6 @@ module.beam: module.erl \
<p>Turns off warnings for unused record types. Default is to
emit warnings for unused locally defined record types.</p>
</item>
-
- <tag><c>nowarn_get_stacktrace</c></tag>
- <item>
- <p>Turns off warnings for using <c>get_stacktrace/0</c> in a context
- where it will probably not work in a future release. For example,
- by default there will be a warning if <c>get_stacktrace/0</c> is
- used following a <c>catch</c> expression.</p>
- </item>
</taglist>
<p>Another class of warnings is generated by the compiler
@@ -671,12 +711,13 @@ module.beam: module.erl \
</note>
<note>
- <p>The options <c>{nowarn_unused_function, FAs}</c>,
- <c>{nowarn_bif_clash, FAs}</c>, and
- <c>{nowarn_deprecated_function, MFAs}</c> are only
- recognized when given in files. They are not affected by
- options <c>warn_unused_function</c>, <c>warn_bif_clash</c>, or
- <c>warn_deprecated_function</c>.</p>
+ <p>Before OTP 22, the option <c>{nowarn_deprecated_function,
+ MFAs}</c> was only recognized when given in the file with
+ attribute <c>-compile()</c>. (The option
+ <c>{nowarn_unused_function,FAs}</c> was incorrectly documented
+ to only work in a file, but it also worked when given in the
+ option list.) Starting from OTP 22, all options that can be
+ given in the file can also be given in the option list.</p>
</note>
<p>For debugging of the compiler, or for pure curiosity,
@@ -705,7 +746,7 @@ module.beam: module.erl \
</func>
<func>
- <name>forms(Forms)</name>
+ <name since="">forms(Forms)</name>
<fsummary>Compiles a list of forms.</fsummary>
<desc>
<p>Is the same as
@@ -715,7 +756,7 @@ module.beam: module.erl \
</func>
<func>
- <name>forms(Forms, Options) -> CompRet</name>
+ <name since="">forms(Forms, Options) -> CompRet</name>
<fsummary>Compiles a list of forms.</fsummary>
<type>
<v>Forms = [Form]</v>
@@ -736,7 +777,7 @@ module.beam: module.erl \
</func>
<func>
- <name>format_error(ErrorDescriptor) -> chars()</name>
+ <name since="">format_error(ErrorDescriptor) -> chars()</name>
<fsummary>Formats an error descriptor.</fsummary>
<type>
<v>ErrorDescriptor = errordesc()</v>
@@ -751,7 +792,7 @@ module.beam: module.erl \
</func>
<func>
- <name>output_generated(Options) -> true | false</name>
+ <name since="">output_generated(Options) -> true | false</name>
<fsummary>Determines whether the compiler generates an output file.</fsummary>
<type>
<v>Options = [term()]</v>
@@ -766,7 +807,7 @@ module.beam: module.erl \
</func>
<func>
- <name>noenv_file(File, Options) -> CompRet</name>
+ <name since="">noenv_file(File, Options) -> CompRet</name>
<fsummary>Compiles a file (ignoring <c>ERL_COMPILER_OPTIONS)</c>.</fsummary>
<desc>
<p>Works like <seealso marker="#file/2">file/2</seealso>,
@@ -776,7 +817,7 @@ module.beam: module.erl \
</func>
<func>
- <name>noenv_forms(Forms, Options) -> CompRet</name>
+ <name since="">noenv_forms(Forms, Options) -> CompRet</name>
<fsummary>Compiles a list of forms (ignoring <c>ERL_COMPILER_OPTIONS)</c>.</fsummary>
<desc>
<p>Works like <seealso marker="#forms/2">forms/2</seealso>,
@@ -786,7 +827,7 @@ module.beam: module.erl \
</func>
<func>
- <name>noenv_output_generated(Options) -> true | false</name>
+ <name since="">noenv_output_generated(Options) -> true | false</name>
<fsummary>Determines whether the compiler generates an output file
(ignoring <c>ERL_COMPILER_OPTIONS)</c>.</fsummary>
<type>
diff --git a/lib/compiler/doc/src/internal.xml b/lib/compiler/doc/src/internal.xml
new file mode 100644
index 0000000000..f24b363c1c
--- /dev/null
+++ b/lib/compiler/doc/src/internal.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE part SYSTEM "part.dtd">
+
+<internal xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header>
+ <copyright>
+ <year>2018</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>Compiler Internal Documentation</title>
+ <prepared>Lukas Larsson</prepared>
+ <docno></docno>
+ <date>2018-07-07</date>
+ <rev>1.0.0</rev>
+ <file>internal.xml</file>
+ </header>
+ <description>
+ </description>
+ <xi:include href="cerl.xml"/>
+ <xi:include href="cerl_trees.xml"/>
+ <xi:include href="cerl_clauses.xml"/>
+</internal>
+
diff --git a/lib/compiler/doc/src/notes.xml b/lib/compiler/doc/src/notes.xml
index bc1f68337b..275c6268fa 100644
--- a/lib/compiler/doc/src/notes.xml
+++ b/lib/compiler/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,6 +32,621 @@
<p>This document describes the changes made to the Compiler
application.</p>
+<section><title>Compiler 7.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p><c>record_info/2</c> is a pseudo-function that
+ requires literal arguments known at compile time.
+ Therefore, the following usage is illegal: <c>fun
+ record/info/2</c>. The compiler would crash when during
+ compilation of that kind of code. Corrected to issue a
+ compilation error.</p>
+ <p>
+ Own Id: OTP-15760 Aux Id: ERL-907 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The compiler has been rewritten to internally use an
+ intermediate representation based on Static Single
+ Assignment (SSA). The new intermediate representation
+ makes more optimizations possible.</p>
+ <p>
+ Most noticeable is that the binary matching optimizations
+ are now applicable in many more circumstances than
+ before.</p>
+ <p>
+ Another noticeable change is that type optimizations are
+ now applied across local function calls, and will remove
+ a lot more redundant type tests than before.</p>
+ <p>
+ Own Id: OTP-14894 Aux Id: ERL-714 </p>
+ </item>
+ <item>
+ <p>Funs are no longer created when they are only used
+ locally, greatly improving the performance of named funs
+ and "fun-wrapped" macros.</p>
+ <p>
+ Own Id: OTP-15273 Aux Id: ERL-639 </p>
+ </item>
+ <item>
+ <p>All compiler options that can be given in the source
+ file can now also be given in the option list or from the
+ command line for <c>erlc</c>.</p>
+ <p>Specifically, the option
+ <c>{nowarn_deprecated_function,MFAs}</c> was only
+ recognized when given in the file with the attribute
+ <c>-compile()</c>. The option
+ <c>{nowarn_unused_function,FAs}</c> was incorrectly
+ documented to only work in a file, but it also worked
+ when given in the option list.</p>
+ <p>
+ Own Id: OTP-15456</p>
+ </item>
+ <item>
+ <p> Do not allow function specifications for functions
+ residing in other modules. </p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15563 Aux Id: ERL-845, OTP-15562 </p>
+ </item>
+ <item>
+ <p>Internal documentation has now been added to the
+ <em>Erts</em> and <em>Compiler</em> applications.</p>
+ <p>The internal documents for <em>Erts</em> describe
+ miscellaneous interesting implementation details. Those
+ details can change at any time.</p>
+ <p>The internal documentation for <em>Compiler</em>
+ documents the API for the Core Erlang modules. While we
+ will not change those APIs without good reason, we don't
+ give the same guarantees about backward compatibility as
+ for the rest of the APIs in OTP.</p>
+ <p>
+ Own Id: OTP-15715</p>
+ </item>
+ <item>
+ <p> There are new compiler options <c>nowarn_removed</c>
+ and <c>{nowarn_removed,Items}</c> to suppress warnings
+ for functions and modules that have been removed from
+ OTP.</p>
+ <p>
+ Own Id: OTP-15749 Aux Id: ERL-904 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.3.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>An expression such as <c>(A / B) band 16#ff</c> would
+ crash the compiler.</p>
+ <p>
+ Own Id: OTP-15518 Aux Id: ERL-829 </p>
+ </item>
+ <item>
+ <p>There could be an incorrect warning when the
+ <c>tuple_calls</c> option was given. The generated code
+ would be correct. Here is an example of code that would
+ trigger the warning:</p>
+ <p><c>(list_to_atom("prefix_" ++
+ atom_to_list(suffix))):doit(X)</c>.</p>
+ <p>
+ Own Id: OTP-15552 Aux Id: ERL-838 </p>
+ </item>
+ <item>
+ <p>Optimize (again) Dialyzer's handling of
+ left-associative use of <c>andalso</c> and <c>orelse</c>
+ in guards.</p>
+ <p>
+ Own Id: OTP-15577 Aux Id: ERL-851, PR-2141, PR-1944 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>An optimization that avoided allocation of a stack
+ frame for some <c>case</c> expressions was introduced in
+ OTP 21. (ERL-504/OTP-14808) It turns out that in rare
+ circumstances, this optimization is not safe. Therefore,
+ this optimization has been disabled.</p>
+ <p>A similar optimization will be included in OTP 22 in a
+ safe way.</p>
+ <p>
+ Own Id: OTP-15501 Aux Id: ERL-807, ERL-514, OTP-14808 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a rare internal consistency failure caused by a
+ bug in the <c>beam_jump</c> pass. (Thanks to Simon
+ Cornish for reporting this bug.)</p>
+ <p>
+ Own Id: OTP-15400 Aux Id: ERL-759 </p>
+ </item>
+ <item>
+ <p>The compiler could fail with an internal consistency
+ check failure when compiling code that used the
+ <c>is_function/2</c> BIF.</p>
+ <p>
+ Own Id: OTP-15435 Aux Id: ERL-778 </p>
+ </item>
+ <item>
+ <p>When an external fun was used, warnings for unused
+ variables could be suppressed.</p>
+ <p>
+ Own Id: OTP-15437 Aux Id: ERL-762 </p>
+ </item>
+ <item>
+ <p>The compiler would crash when compiling an
+ <c>after</c> block that called <c>erlang:raise/3</c> like
+ this: <c>erlang:raise(Class, Stacktrace,
+ Stacktrace)</c></p>
+ <p>
+ Own Id: OTP-15481</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>When specified, the <c>+{source,Name}</c> option will
+ now override the actual file name in stack traces,
+ instead of only affecting the return value of
+ <c>Mod:module_info()</c>.</p>
+ <p>The <c>+deterministic</c> flag will also affect stack
+ traces now, omitting all path information except the file
+ name, fixing a long-standing issue where deterministic
+ builds required deterministic paths.</p>
+ <p>
+ Own Id: OTP-15245 Aux Id: ERL-706 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.2.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a bug where incorrect code was generated
+ following a binary match guard.</p>
+ <p>
+ Own Id: OTP-15353 Aux Id: ERL-753 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.2.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>In rare circumstances, the matched out tail of a
+ binary could be the entire original binary. (There was
+ partial correction to this problem in version 7.2.5 of
+ the compiler application.)</p>
+ <p>
+ Own Id: OTP-15335 Aux Id: ERL-689, OTP-15219 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.2.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a bug that prevented certain variable-sized
+ binary comprehensions from compiling.</p>
+ <p>
+ Own Id: OTP-15186 Aux Id: ERL-665 </p>
+ </item>
+ <item>
+ <p>When compiling from Core Erlang, funs created in
+ certain expressions that were only used for their
+ side-effects were subtly broken.</p>
+ <p>
+ Own Id: OTP-15188 Aux Id: ERL-658 </p>
+ </item>
+ <item>
+ <p>There could be an internal consistency failure when a
+ <c>receive</c> was nested in a
+ <c>try</c>/<c>catch</c>.</p>
+ <p>
+ Own Id: OTP-15218 Aux Id: ERL-684 </p>
+ </item>
+ <item>
+ <p>In rare circumstances, the matched out tail of a
+ binary could be the entire original binary.</p>
+ <p>
+ Own Id: OTP-15219 Aux Id: ERL-689 </p>
+ </item>
+ <item>
+ <p>When <c>is_map_key/2</c> was used in a guard together
+ with the <c>not/1</c> or <c>or/2</c> operators, the error
+ behavior could be wrong when <c>is_map_key/2</c> was
+ passed a non-map as the second argument. </p>
+ <p>In rare circumstances, compiling code that uses
+ <c>is_map_key/2</c> could cause an internal consistency
+ check failure.</p>
+ <p>
+ Own Id: OTP-15227 Aux Id: ERL-699 </p>
+ </item>
+ <item>
+ <p>The compiler could crash when compiling a function
+ with multiple receives in multiple clauses.</p>
+ <p>
+ Own Id: OTP-15235 Aux Id: ERL-703 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.2.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fix a regression in OTP-15204 that removed
+ <c>.beam</c> file metadata that some external build tools
+ relied on.</p>
+ <p>
+ Own Id: OTP-15292</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.2.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed an issue where files compiled with the
+ <c>+deterministic</c> option differed if they were
+ compiled in a different directory but were otherwise
+ identical.</p>
+ <p>
+ Own Id: OTP-15204 Aux Id: ERL-679 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.2.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>In rare cases involving matching of binary literal
+ strings, the compiler could optimize away code that
+ should be executed.</p>
+ <p>
+ Own Id: OTP-15156 Aux Id: ERL-655 </p>
+ </item>
+ <item>
+ <p>There could be an internal consistency check failure
+ when compiling code that called <c>map_get(Key, Map)</c>
+ and then updated the same map.</p>
+ <p>
+ Own Id: OTP-15157</p>
+ </item>
+ <item>
+ <p>In rare circumstances, the compiler could crash in
+ <c>beam_jump</c> when compiling a floating point
+ operation.</p>
+ <p>
+ Own Id: OTP-15166 Aux Id: ERL-660 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.2.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>The could could crash when compiling a complicated
+ function that used the binary syntax.</p>
+ <p>
+ Own Id: OTP-15150 Aux Id: ERL-650 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed an error in an optimization pass that caused
+ impossible tuple matching.</p>
+ <p>
+ Own Id: OTP-14855 Aux Id: ERL-549 </p>
+ </item>
+ <item>
+ <p>The exception thrown when a list comprehension was
+ given a non-list term was not always correct.</p>
+ <p>
+ Own Id: OTP-14992 Aux Id: ERL-572 </p>
+ </item>
+ <item>
+ <p>The compiler could produce incorrect code in rare
+ circumstances when the <c>[{inline,F/A}]</c> option was
+ used.</p>
+ <p>
+ Own Id: OTP-15115 Aux Id: PR-1831 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>Changed the default behaviour of <c>.erlang</c>
+ loading: <c>.erlang</c> is no longer loaded from the
+ current directory. <c>c:erlangrc(PathList)</c> can be
+ used to search and load an <c>.erlang</c> file from user
+ specified directories.</p> <p><c>escript</c>,
+ <c>erlc</c>, <c>dialyzer</c> and <c>typer</c> no longer
+ load an <c>.erlang</c> at all.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14439</p>
+ </item>
+ <item>
+ <p>Support for "tuple calls" have been removed from the
+ run-time system. Tuple calls was an undocumented and
+ unsupported feature which allowed the module argument for
+ an apply operation to be a tuple: <c>Var = dict:new(),
+ Var:size()</c>. This "feature" frequently caused
+ confusion, especially when such call failed. The
+ stacktrace would point out functions that don't exist in
+ the source code.</p>
+ <p>For legacy code that need to use parameterized modules
+ or tuple calls for some other reason, there is a new
+ compiler option called <c>tuple_calls</c>. When this
+ option is given, the compiler will generate extra code
+ that emulates the old behavior for calls where the module
+ is a variable.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14497</p>
+ </item>
+ <item>
+ <p>In code such as <c>example({ok, Val}) -&gt; {ok,
+ Val}.</c> a tuple would be built. The compiler will now
+ automatically rewrite the code to
+ <c>example({ok,Val}=Tuple) -&gt; Tuple.</c> which will
+ reduce code size, execution time, and remove GC
+ pressure.</p>
+ <p>
+ Own Id: OTP-14505</p>
+ </item>
+ <item>
+ <p>The optimization of <c>case</c> expression where only
+ one of the case arms can execute successfully has been
+ improved.</p>
+ <p>
+ Own Id: OTP-14525</p>
+ </item>
+ <item>
+ <p>Some uses of binary matching has been slightly
+ improved, eliminating unnecessary register shuffling.</p>
+ <p>
+ Own Id: OTP-14594 Aux Id: ERL-444 </p>
+ </item>
+ <item>
+ <p>There is a new <c>{compile_info,Info}</c> option for
+ the compiler that allows BEAM-based languages such as
+ Elixir and LFE to add their own compiler versions.</p>
+ <p>
+ Own Id: OTP-14615 Aux Id: PR-1558 </p>
+ </item>
+ <item>
+ <p>Loaded BEAM code in a 64-bit system requires less
+ memory because of better packing of operands for
+ instructions.</p>
+ <p>These memory savings were achieved by major
+ improvements to the <c>beam_makeops</c> scripts used when
+ building the run time system and BEAM compiler. There is
+ also new for documentation for <c>beam_makeops</c> that
+ describes how new BEAM instructions and loader
+ transformations can be implemented. The documentation is
+ found in here in a source directory or git repository:
+ erts/emulator/internal_doc/beam_makeops.md. An online
+ version can be found here:
+ https://github.com/erlang/otp/blob/master/erts/emulator/internal_doc/beam_makeops.md</p>
+ <p>
+ Own Id: OTP-14626</p>
+ </item>
+ <item>
+ <p>Size calculations for binary constructions has been
+ somewhat optimized, producing smaller code.</p>
+ <p>
+ Own Id: OTP-14654</p>
+ </item>
+ <item>
+ <p>When the value returned from a '<c>catch</c>'
+ expression is ignored, no stacktrace will be built if an
+ exception is caught. That will save time and produce less
+ garbage. There are also some minor optimizations of
+ '<c>try</c>/<c>catch</c>' both in the compiler and
+ run-time system.</p>
+ <p>
+ Own Id: OTP-14683</p>
+ </item>
+ <item>
+ <p>There is a new syntax in '<c>try/catch</c>' for
+ retrieving the stacktrace without calling
+ '<c>erlang:get_stacktrace/0</c>'. See the reference
+ manual for a description of the new syntax. The
+ '<c>erlang:get_stacktrace/0</c>' BIF is now
+ deprecated.</p>
+ <p>
+ Own Id: OTP-14692</p>
+ </item>
+ <item>
+ <p>The following is an internal change in the compiler,
+ that is not noticeable for normal use of the compiler:
+ The module <c>v3_life</c> has been removed. Its
+ functionality has been simplified and integrated into
+ <c>v3_codegen</c>.</p>
+ <p>
+ Own Id: OTP-14712</p>
+ </item>
+ <item>
+ <p>The optimization of binary matching that delays
+ creation of sub binaries (see the Efficiency Guide) could
+ be thwarted by the argument order and could be necessary
+ to change the argument order. The compiler has now become
+ smarter and can handle any argument order.</p>
+ <p>
+ Own Id: OTP-14774</p>
+ </item>
+ <item>
+ <p>When the compiler was faced with complex case
+ expressions it would unnecessarily allocate stack
+ elements and shuffle data between x and y registers.
+ Improved code generation to only allocate a stack frame
+ when strictly necessary.</p>
+ <p>
+ Own Id: OTP-14808 Aux Id: ERL-514 </p>
+ </item>
+ <item>
+ <p>There is a new option '<c>makedep_side_effect</c>' for
+ the compiler and <c>-MMD</c> for '<c>erlc</c>' that
+ generates dependencies and continues to compile as
+ normal.</p>
+ <p>
+ Own Id: OTP-14830</p>
+ </item>
+ <item>
+ <p>When compiling modules with huge functions, the
+ compiler would generate a lot of atoms for its internal,
+ sometimes so many that the atom table would overflow. The
+ compiler has been rewritten to generate far less internal
+ atoms to avoid filling the atom table.</p>
+ <p>
+ Own Id: OTP-14968 Aux Id: ERL-563 </p>
+ </item>
+ <item>
+ <p>External funs with literal values for module, name,
+ and arity (e.g. <c>erlang:abs/1</c>) are now treated as
+ literals. That means more efficient code that produces
+ less garbage on the heap.</p>
+ <p>
+ Own Id: OTP-15003</p>
+ </item>
+ <item>
+ <p>Two new guards BIFs operating on maps have been added:
+ <c>map_get/2</c> and <c>is_map_key/2</c>. They do the
+ same as <c>maps:get/2</c> and <c>maps:is_key/2</c>,
+ respectively, except that they are allowed to be used in
+ guards.</p>
+ <p>
+ Own Id: OTP-15037 Aux Id: PR-1784, PR-1802 </p>
+ </item>
+ <item>
+ <p>A call or apply of a literal external fun will be
+ replaced with a direct call.</p>
+ <p>
+ Own Id: OTP-15044 Aux Id: ERL-614 </p>
+ </item>
+ <item>
+ <p>Part of EEP-44 has been implemented.</p>
+ <p>There is a new predefined macro called
+ <c>OTP_RELEASE</c> which is an integer indicating the OTP
+ release number (its value is <c>21</c> in this
+ release).</p>
+ <p>There are new preprocessor directives
+ <c>-if(Condition).</c> and <c>-elif(Condition).</c>. The
+ <c>if/elif</c> supports the builtin function
+ <c>defined(Symbol)</c>.</p>
+ <p>
+ Own Id: OTP-15087 Aux Id: PR-1810 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.1.5.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fix a regression in OTP-15204 that removed
+ <c>.beam</c> file metadata that some external build tools
+ relied on.</p>
+ <p>
+ Own Id: OTP-15292</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.1.5.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed an issue where files compiled with the
+ <c>+deterministic</c> option differed if they were
+ compiled in a different directory but were otherwise
+ identical.</p>
+ <p>
+ Own Id: OTP-15204 Aux Id: ERL-679 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Compiler 7.1.5</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/compiler/internal_doc/cerl-notes.md b/lib/compiler/internal_doc/cerl-notes.md
new file mode 100644
index 0000000000..705fe8f42d
--- /dev/null
+++ b/lib/compiler/internal_doc/cerl-notes.md
@@ -0,0 +1,75 @@
+Some notes on the cerl modules
+==============================
+
+Maps in cerl_clauses:match/3
+----------------------------
+
+Not much optimization is done for maps in `cerl_clauses:match/3`.
+
+The reason is that the inliner (`cerl_inline`) was not designed for
+data types that depend on variables bound in the enclosing environment
+(for example, the keys for maps). If we attempt to extend the
+optimizations for maps similar to the optimizations for the other data
+types, the inliner will crash for certain code. Here is an example of
+code that would crash the inliner:
+
+ t() ->
+ f(key).
+
+ f(K) ->
+ case #{K => value} of
+ #{key := V} -> V
+ end.
+
+The reason for the crash is that the inliner works in several
+passes and calls `cerl_clauses:match/3` twice. The inliner will
+assume that the same result will be returned both times, but
+for this example different bindings will be returned.
+
+Here is the rough outline of what happens:
+
+* The first time `cerl_clauses:match/3` will be asked to match the
+pattern `#{K := V}` against `#{key => value}`. It cannot say more
+than that the pattern *may* match.
+
+* Now the inliner will add the bindings to body of the clause (which
+is simply `V`). In this case, the bindings are still empty, so
+nothing is added.
+
+* The inliner will now do some substitutions and renaming. The
+variable `K` will be replaced with `key`.
+
+* The next time `cerl_clauses:match/3` is called, it will be asked to
+match the pattern `#{key := V}` against `#{key => value#}`. In this
+case, there will be a match and the bindings can be extended with
+`{V,value}`.
+
+* The inliner will see that the entire case can be removed. Only
+the body for the clause needs to be kept.
+
+Thus, after inlining the function `t/0` will look like this:
+
+ t() ->
+ V.
+
+The problem here is that the inliner assumed that the bindings from
+the first and second call to `cer_clauses:match/3` would be the same.
+It used the empty bindings from the first call for the body.
+
+The correct way would be to add the bindings from the second call:
+
+ t() ->
+ let V = value in V.
+
+### How to fix this ###
+
+The inliner will need to call `cerl_clauses:match/3` after doing
+all substitutions and renaming. It is not clear to me how difficult
+that would be. I assume that the inliner is written the way it is
+for a good reason. That means that switching the order things are
+done would lead to correctness and/or performance problems.
+
+### What must also be done to fix this ###
+
+`cerl_inline:make_template/3` must be extended to create a template
+for maps. That is relatively straightforward.
diff --git a/lib/compiler/scripts/.gitignore b/lib/compiler/scripts/.gitignore
new file mode 100644
index 0000000000..4e4eba766d
--- /dev/null
+++ b/lib/compiler/scripts/.gitignore
@@ -0,0 +1 @@
+/smoke-build
diff --git a/lib/compiler/scripts/smoke b/lib/compiler/scripts/smoke
new file mode 100755
index 0000000000..ae31c923b8
--- /dev/null
+++ b/lib/compiler/scripts/smoke
@@ -0,0 +1,123 @@
+#!/usr/bin/env escript
+%% -*- erlang -*-
+-mode(compile).
+
+main(_Args) ->
+ setup(),
+ clone_elixir(),
+ build_elixir(),
+ test_elixir(),
+ setup_mix(),
+ smoke(main),
+ smoke(rabbitmq),
+ halt(0).
+
+setup() ->
+ ScriptsDir = scripts_dir(),
+ SmokeBuildDir = filename:join(ScriptsDir, "smoke-build"),
+ _ = file:make_dir(SmokeBuildDir),
+ ok = file:set_cwd(SmokeBuildDir),
+ ok.
+
+clone_elixir() ->
+ {ok,SmokeDir} = file:get_cwd(),
+ DotGitDir = filename:join([SmokeDir,"elixir",".git"]),
+ ElixirRepo = "[email protected]:elixir-lang/elixir.git",
+ case filelib:is_dir(DotGitDir) of
+ false ->
+ cmd("git clone " ++ ElixirRepo);
+ true ->
+ GetHeadSHA1 = "cd elixir && git rev-parse --verify HEAD",
+ Before = os:cmd(GetHeadSHA1),
+ cmd("cd elixir && git pull --ff-only origin master"),
+ case os:cmd(GetHeadSHA1) of
+ Before ->
+ ok;
+ _After ->
+ %% There were some changes. Clean to force a re-build.
+ cmd("cd elixir && make clean")
+ end
+ end.
+
+build_elixir() ->
+ cmd("cd elixir && make compile").
+
+test_elixir() ->
+ cmd("cd elixir && make test_stdlib").
+
+setup_mix() ->
+ MixExsFile = filename:join(scripts_dir(), "smoke-mix.exs"),
+ {ok,MixExs} = file:read_file(MixExsFile),
+ ok = file:write_file("mix.exs", MixExs),
+
+ {ok,SmokeDir} = file:get_cwd(),
+ ElixirBin = filename:join([SmokeDir,"elixir","bin"]),
+ PATH = ElixirBin ++ ":" ++ os:getenv("PATH"),
+ os:putenv("PATH", PATH),
+ mix("local.hex --force"),
+ mix("local.rebar --force"),
+ ok.
+
+smoke(Set) ->
+ os:putenv("SMOKE_DEPS_SET", atom_to_list(Set)),
+ _ = file:delete("mix.lock"),
+ cmd("touch mix.exs"),
+ mix("deps.clean --all"),
+ mix("deps.get"),
+ mix("deps.compile"),
+ ok.
+
+scripts_dir() ->
+ Root = code:lib_dir(compiler),
+ filename:join(Root, "scripts").
+
+mix(Cmd) ->
+ cmd("mix " ++ Cmd).
+
+cmd(Cmd) ->
+ run("sh", ["-c",Cmd]).
+
+run(Program0, Args) ->
+ Program = case os:find_executable(Program0) of
+ Path when is_list(Path) ->
+ Path;
+ false ->
+ abort("Unable to find program: ~s\n", [Program0])
+ end,
+ Cmd = case {Program0,Args} of
+ {"sh",["-c"|ShCmd]} ->
+ ShCmd;
+ {_,_} ->
+ lists:join(" ", [Program0|Args])
+ end,
+ io:format("\n# ~s\n", [Cmd]),
+ Options = [{args,Args},binary,exit_status,stderr_to_stdout],
+ try open_port({spawn_executable,Program}, Options) of
+ Port ->
+ case run_loop(Port, <<>>) of
+ 0 ->
+ ok;
+ ExitCode ->
+ abort("*** Failed with exit code: ~p\n",
+ [ExitCode])
+ end
+ catch
+ error:_ ->
+ abort("Failed to execute ~s\n", [Program0])
+ end.
+
+run_loop(Port, Output) ->
+ receive
+ {Port,{exit_status,Status}} ->
+ Status;
+ {Port,{data,Bin}} ->
+ io:put_chars(Bin),
+ run_loop(Port, <<Output/binary,Bin/binary>>);
+ Msg ->
+ io:format("L: ~p~n", [Msg]),
+ run_loop(Port, Output)
+ end.
+
+abort(Format, Args) ->
+ io:format(Format, Args),
+ halt(1).
diff --git a/lib/compiler/scripts/smoke-mix.exs b/lib/compiler/scripts/smoke-mix.exs
new file mode 100644
index 0000000000..ba0815e465
--- /dev/null
+++ b/lib/compiler/scripts/smoke-mix.exs
@@ -0,0 +1,103 @@
+defmodule Smoke.MixProject do
+ use Mix.Project
+
+ def project do
+ [
+ app: :smoke,
+ version: "0.1.0",
+ elixir: "~> 1.8",
+ start_permanent: Mix.env() == :prod,
+ deps: deps()
+ ]
+ end
+
+ # Run "mix help compile.app" to learn about applications.
+ def application do
+ [
+ extra_applications: [:logger]
+ ]
+ end
+
+ # Run "mix help deps" to learn about dependencies.
+ defp deps do
+ case :os.getenv('SMOKE_DEPS_SET') do
+ 'main' ->
+ [
+ {:bear, "~> 0.8.7"},
+ {:cloudi_core, "~> 1.7"},
+ {:cloudi_service_monitoring, "~> 1.7"},
+ {:cloudi_service_tcp, "~> 1.7"},
+ {:cloudi_service_queue, "~> 1.7"},
+ {:cloudi_service_udp, "~> 1.7"},
+ {:cloudi_service_map_reduce, "~> 1.7"},
+ {:cloudi_service_api_requests, "~> 1.7"},
+ {:cloudi_service_router, "~> 1.7"},
+ {:cloudi_service_request_rate, "~> 1.7"},
+ {:concuerror, "~> 0.20.0"},
+ {:cowboy, "~> 2.6.1"},
+ {:ecto, "~> 3.0.6"},
+ {:ex_doc, "~> 0.19.3"},
+ {:distillery, "~> 2.0.12"},
+ {:erlydtl, "~> 0.12.1"},
+ {:gen_smtp, "~> 0.13.0"},
+ {:getopt, "~> 1.0.1"},
+ {:gettext, "~> 0.16.1"},
+ {:gpb, "~> 4.6"},
+ {:gproc, "~> 0.8.0"},
+ {:graphql, "~> 0.15.0", hex: :graphql_erl},
+ {:hackney, "~> 1.15.0"},
+ {:ibrowse, "~> 4.4.1"},
+ {:jose, "~> 1.9.0"},
+ {:lager, "~> 3.6"},
+ {:locus, "~> 1.6"},
+ {:nimble_parsec, "~> 0.5.0"},
+ {:phoenix, "~> 1.4.0"},
+ {:riak_pb, "~> 2.3"},
+ {:scalaris, git: "https://github.com/scalaris-team/scalaris",
+ compile: build_scalaris()},
+ {:tdiff, "~> 0.1.2"},
+ {:webmachine, "~> 1.11"},
+ {:wings, git: "https://github.com/dgud/wings.git",
+ compile: build_wings()},
+ {:zotonic_stdlib, "~> 1.0"},
+ ]
+ 'rabbitmq' ->
+ [{:rabbit_common, "~> 3.7"}]
+ _ ->
+ []
+ end
+ end
+
+ defp build_scalaris do
+ # Only compile the Erlang code.
+
+ """
+ echo '-include("rt_simple.hrl").' >include/rt.hrl
+ (cd src && erlc -W0 -I ../include -I ../contrib/log4erl/include -I ../contrib/yaws/include *.erl)
+ (cd src/comm_layer && erlc -W0 -I ../../include -I *.erl)
+ (cd src/cp && erlc -W0 -I ../../include -I *.erl)
+ (cd src/crdt && erlc -W0 -I ../../include -I *.erl)
+ (cd src/json && erlc -W0 -I ../../include -I *.erl)
+ (cd src/paxos && erlc -W0 -I ../../include -I *.erl)
+ (cd src/rbr && erlc -W0 -I ../../include -I *.erl)
+ (cd src/rrepair && erlc -W0 -I ../../include -I *.erl)
+ (cd src/time && erlc -W0 -I ../../include -I *.erl)
+ (cd src/transactions && erlc -W0 -I ../../include -I *.erl)
+ (cd src/tx && erlc -W0 -I ../../include -I *.erl)
+ """
+ end
+
+ defp build_wings do
+ # If the Erlang system is not installed, the build will
+ # crash in plugins_src/accel when attempting to build
+ # the accel driver. Since there is very little Erlang code in
+ # the directory, skip the entire directory.
+
+ """
+ echo "all:\n\t" >plugins_src/accel/Makefile
+ git commit -a -m'Disable for smoke testing'
+ git tag -a -m'Smoke test' vsmoke_test
+ make
+ """
+ end
+end
diff --git a/lib/compiler/src/Makefile b/lib/compiler/src/Makefile
index ef6db66ff6..87b0d345f2 100644
--- a/lib/compiler/src/Makefile
+++ b/lib/compiler/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2017. All Rights Reserved.
+# Copyright Ericsson AB 1996-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -49,10 +49,7 @@ MODULES = \
beam_a \
beam_asm \
beam_block \
- beam_bs \
- beam_bsm \
beam_clean \
- beam_dead \
beam_dict \
beam_disasm \
beam_except \
@@ -61,12 +58,20 @@ MODULES = \
beam_listing \
beam_opcodes \
beam_peep \
- beam_receive \
- beam_reorder \
- beam_record \
- beam_split \
+ beam_ssa \
+ beam_ssa_bsm \
+ beam_ssa_codegen \
+ beam_ssa_dead \
+ beam_ssa_funs \
+ beam_ssa_lint \
+ beam_ssa_opt \
+ beam_ssa_pp \
+ beam_ssa_pre_codegen \
+ beam_ssa_recv \
+ beam_ssa_share \
+ beam_ssa_type \
+ beam_kernel_to_ssa \
beam_trim \
- beam_type \
beam_utils \
beam_validator \
beam_z \
@@ -83,25 +88,24 @@ MODULES = \
core_scan \
erl_bifs \
rec_env \
+ sys_core_alias \
sys_core_bsm \
- sys_core_dsetel \
sys_core_fold \
sys_core_fold_lists \
sys_core_inline \
sys_pre_attributes \
- v3_codegen \
v3_core \
v3_kernel \
- v3_kernel_pp \
- v3_life
+ v3_kernel_pp
BEAM_H = $(wildcard ../priv/beam_h/*.h)
HRL_FILES= \
beam_disasm.hrl \
+ beam_ssa_opt.hrl \
+ beam_ssa.hrl \
core_parse.hrl \
- v3_kernel.hrl \
- v3_life.hrl
+ v3_kernel.hrl
YRL_FILE = core_parse.yrl
@@ -125,9 +129,10 @@ APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
ifeq ($(NATIVE_LIBS_ENABLED),yes)
ERL_COMPILE_FLAGS += +native
+else
+ERL_COMPILE_FLAGS += -Werror
endif
ERL_COMPILE_FLAGS += +inline +warn_unused_import \
- -Werror \
-I../../stdlib/include -I$(EGEN) -W +warn_missing_spec
# ----------------------------------------------------
@@ -186,20 +191,30 @@ release_docs_spec:
# ----------------------------------------------------
$(EBIN)/beam_disasm.beam: $(EGEN)/beam_opcodes.hrl beam_disasm.hrl
-$(EBIN)/beam_listing.beam: v3_life.hrl
-$(EBIN)/beam_validator.beam: beam_disasm.hrl
+$(EBIN)/beam_listing.beam: core_parse.hrl v3_kernel.hrl beam_ssa.hrl
+$(EBIN)/beam_kernel_to_ssa.beam: v3_kernel.hrl beam_ssa.hrl
+$(EBIN)/beam_ssa.beam: beam_ssa.hrl
+$(EBIN)/beam_ssa_bsm.beam: beam_ssa.hrl
+$(EBIN)/beam_ssa_codegen.beam: beam_ssa.hrl
+$(EBIN)/beam_ssa_dead.beam: beam_ssa.hrl
+$(EBIN)/beam_ssa_funs.beam: beam_ssa.hrl
+$(EBIN)/beam_ssa_lint.beam: beam_ssa.hrl
+$(EBIN)/beam_ssa_opt.beam: beam_ssa.hrl
+$(EBIN)/beam_ssa_pp.beam: beam_ssa.hrl
+$(EBIN)/beam_ssa_pre_codegen.beam: beam_ssa.hrl
+$(EBIN)/beam_ssa_recv.beam: beam_ssa.hrl
+$(EBIN)/beam_ssa_share.beam: beam_ssa.hrl
+$(EBIN)/beam_ssa_type.beam: beam_ssa.hrl
$(EBIN)/cerl.beam: core_parse.hrl
$(EBIN)/compile.beam: core_parse.hrl ../../stdlib/include/erl_compile.hrl
$(EBIN)/core_lib.beam: core_parse.hrl
$(EBIN)/core_lint.beam: core_parse.hrl
$(EBIN)/core_parse.beam: core_parse.hrl $(EGEN)/core_parse.erl
$(EBIN)/core_pp.beam: core_parse.hrl
-$(EBIN)/sys_core_dsetel.beam: core_parse.hrl
+$(EBIN)/sys_core_alias.beam: core_parse.hrl
$(EBIN)/sys_core_fold.beam: core_parse.hrl
$(EBIN)/sys_core_fold_lists.beam: core_parse.hrl
$(EBIN)/sys_core_inline.beam: core_parse.hrl
-$(EBIN)/v3_codegen.beam: v3_life.hrl
$(EBIN)/v3_core.beam: core_parse.hrl
$(EBIN)/v3_kernel.beam: core_parse.hrl v3_kernel.hrl
$(EBIN)/v3_kernel_pp.beam: v3_kernel.hrl
-$(EBIN)/v3_life.beam: v3_kernel.hrl v3_life.hrl
diff --git a/lib/compiler/src/beam_a.erl b/lib/compiler/src/beam_a.erl
index cdb32d5d55..0bccad1ecd 100644
--- a/lib/compiler/src/beam_a.erl
+++ b/lib/compiler/src/beam_a.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -39,15 +39,29 @@ function({function,Name,Arity,CLabel,Is0}) ->
%% Remove unusued labels for cleanliness and to help
%% optimization passes and HiPE.
- Is = beam_jump:remove_unused_labels(Is1),
- {function,Name,Arity,CLabel,Is}
+ Is2 = beam_jump:remove_unused_labels(Is1),
+
+ %% Some optimization passes can't handle consecutive labels.
+ %% Coalesce multiple consecutive labels.
+ Is = coalesce_consecutive_labels(Is2, [], []),
+
+ {function,Name,Arity,CLabel,Is}
catch
- Class:Error ->
- Stack = erlang:get_stacktrace(),
+ Class:Error:Stack ->
io:fwrite("Function: ~w/~w\n", [Name,Arity]),
erlang:raise(Class, Error, Stack)
end.
+rename_instrs([{test,is_eq_exact,_,[Dst,Src]}=Test,
+ {move,Src,Dst}|Is]) ->
+ %% The move instruction is not needed.
+ rename_instrs([Test|Is]);
+rename_instrs([{test,is_eq_exact,_,[Same,Same]}|Is]) ->
+ %% Same literal or same register. Will always succeed.
+ rename_instrs(Is);
+rename_instrs([{loop_rec,{f,Fail},{x,0}},{loop_rec_end,_},{label,Fail}|Is]) ->
+ %% This instruction sequence does nothing.
+ rename_instrs(Is);
rename_instrs([{apply_last,A,N}|Is]) ->
[{apply,A},{deallocate,N},return|rename_instrs(Is)];
rename_instrs([{call_last,A,F,N}|Is]) ->
@@ -59,8 +73,17 @@ rename_instrs([{call_only,A,F}|Is]) ->
rename_instrs([{call_ext_only,A,F}|Is]) ->
[{call_ext,A,F},return|rename_instrs(Is)];
rename_instrs([{'%live',_}|Is]) ->
- %% When compiling from old .S files.
+ %% Ignore old type of live annotation. Only happens when compiling
+ %% from very old .S files.
rename_instrs(Is);
+rename_instrs([{get_list,S,D1,D2}|Is]) ->
+ %% Only happens when compiling from old .S files.
+ if
+ D1 =:= S ->
+ [{get_tl,S,D2},{get_hd,S,D1}|rename_instrs(Is)];
+ true ->
+ [{get_hd,S,D1},{get_tl,S,D2}|rename_instrs(Is)]
+ end;
rename_instrs([I|Is]) ->
[rename_instr(I)|rename_instrs(Is)];
rename_instrs([]) -> [].
@@ -77,8 +100,12 @@ rename_instr({bs_put_utf16=I,F,Fl,Src}) ->
{bs_put,F,{I,Fl},[Src]};
rename_instr({bs_put_utf32=I,F,Fl,Src}) ->
{bs_put,F,{I,Fl},[Src]};
-rename_instr({bs_put_string,_,_}=I) ->
- {bs_put,{f,0},I,[]};
+rename_instr({bs_put_string,_,{string,String}}) ->
+ %% Only happens when compiling from .S files. In old
+ %% .S files, String is a list. In .S in OTP 22 and later,
+ %% String is a binary.
+ {bs_put,{f,0},{bs_put_binary,8,{field_flags,[unsigned,big]}},
+ [{atom,all},{literal,iolist_to_binary([String])}]};
rename_instr({bs_add=I,F,[Src1,Src2,U],Dst}) when is_integer(U) ->
{bif,I,F,[Src1,Src2,{integer,U}],Dst};
rename_instr({bs_utf8_size=I,F,Src,Dst}) ->
@@ -95,16 +122,14 @@ rename_instr({bs_private_append=I,F,Sz,U,Src,Flags,Dst}) ->
{bs_init,F,{I,U,Flags},none,[Sz,Src],Dst};
rename_instr(bs_init_writable=I) ->
{bs_init,{f,0},I,1,[{x,0}],{x,0}};
-rename_instr({test,Op,F,[Ctx,Bits,{string,Str}]}) ->
- %% When compiling from a .S file.
- <<Bs:Bits/bits,_/bits>> = list_to_binary(Str),
- {test,Op,F,[Ctx,Bs]};
rename_instr({put_map_assoc,Fail,S,D,R,L}) ->
{put_map,Fail,assoc,S,D,R,L};
rename_instr({put_map_exact,Fail,S,D,R,L}) ->
{put_map,Fail,exact,S,D,R,L};
rename_instr({test,has_map_fields,Fail,Src,{list,List}}) ->
{test,has_map_fields,Fail,[Src|List]};
+rename_instr({test,is_nil,Fail,[Src]}) ->
+ {test,is_eq_exact,Fail,[Src,nil]};
rename_instr({select_val=I,Reg,Fail,{list,List}}) ->
{select,I,Reg,Fail,List};
rename_instr({select_tuple_arity=I,Reg,Fail,{list,List}}) ->
@@ -112,3 +137,11 @@ rename_instr({select_tuple_arity=I,Reg,Fail,{list,List}}) ->
rename_instr(send) ->
{call_ext,2,send};
rename_instr(I) -> I.
+
+coalesce_consecutive_labels([{label,L}=Lbl,{label,Alias}|Is], Replace, Acc) ->
+ coalesce_consecutive_labels([Lbl|Is], [{Alias,L}|Replace], Acc);
+coalesce_consecutive_labels([I|Is], Replace, Acc) ->
+ coalesce_consecutive_labels(Is, Replace, [I|Acc]);
+coalesce_consecutive_labels([], Replace, Acc) ->
+ D = maps:from_list(Replace),
+ beam_utils:replace_labels(Acc, [], D, fun(L) -> L end).
diff --git a/lib/compiler/src/beam_asm.erl b/lib/compiler/src/beam_asm.erl
index f7c838e392..df09dcb06c 100644
--- a/lib/compiler/src/beam_asm.erl
+++ b/lib/compiler/src/beam_asm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,10 +21,10 @@
-module(beam_asm).
--export([module/5]).
+-export([module/4]).
-export([encode/2]).
--export_type([fail/0,label/0,reg/0,src/0,module_code/0,function_name/0]).
+-export_type([fail/0,label/0,reg/0,reg_num/0,src/0,module_code/0,function_name/0]).
-import(lists, [map/2,member/2,keymember/3,duplicate/2,splitwith/2]).
-include("beam_opcodes.hrl").
@@ -55,20 +55,20 @@
-type module_code() ::
{module(),[_],[_],[asm_function()],pos_integer()}.
--spec module(module_code(), [{binary(), binary()}], [_], [compile:option()], [compile:option()]) ->
+-spec module(module_code(), [{binary(), binary()}], [{atom(),term()}], [compile:option()]) ->
{'ok',binary()}.
-module(Code, ExtraChunks, SourceFile, Opts, CompilerOpts) ->
- {ok,assemble(Code, ExtraChunks, SourceFile, Opts, CompilerOpts)}.
+module(Code, ExtraChunks, CompileInfo, CompilerOpts) ->
+ {ok,assemble(Code, ExtraChunks, CompileInfo, CompilerOpts)}.
-assemble({Mod,Exp0,Attr0,Asm0,NumLabels}, ExtraChunks, SourceFile, Opts, CompilerOpts) ->
+assemble({Mod,Exp0,Attr0,Asm0,NumLabels}, ExtraChunks, CompileInfo, CompilerOpts) ->
{1,Dict0} = beam_dict:atom(Mod, beam_dict:new()),
{0,Dict1} = beam_dict:fname(atom_to_list(Mod) ++ ".erl", Dict0),
NumFuncs = length(Asm0),
{Asm,Attr} = on_load(Asm0, Attr0),
Exp = cerl_sets:from_list(Exp0),
{Code,Dict2} = assemble_1(Asm, Exp, Dict1, []),
- build_file(Code, Attr, Dict2, NumLabels, NumFuncs, ExtraChunks, SourceFile, Opts, CompilerOpts).
+ build_file(Code, Attr, Dict2, NumLabels, NumFuncs, ExtraChunks, CompileInfo, CompilerOpts).
on_load(Fs0, Attr0) ->
case proplists:get_value(on_load, Attr0) of
@@ -111,7 +111,7 @@ assemble_function([H|T], Acc, Dict0) ->
assemble_function([], Code, Dict) ->
{Code, Dict}.
-build_file(Code, Attr, Dict, NumLabels, NumFuncs, ExtraChunks, SourceFile, Opts, CompilerOpts) ->
+build_file(Code, Attr, Dict, NumLabels, NumFuncs, ExtraChunks, CompileInfo, CompilerOpts) ->
%% Create the code chunk.
CodeChunk = chunk(<<"Code">>,
@@ -182,8 +182,7 @@ build_file(Code, Attr, Dict, NumLabels, NumFuncs, ExtraChunks, SourceFile, Opts,
Essentials1 = [iolist_to_binary(C) || C <- Essentials0],
MD5 = module_md5(Essentials1),
Essentials = finalize_fun_table(Essentials1, MD5),
- {Attributes,Compile} = build_attributes(Opts, CompilerOpts, SourceFile,
- Attr, MD5),
+ {Attributes,Compile} = build_attributes(Attr, CompileInfo, MD5),
AttrChunk = chunk(<<"Attr">>, Attributes),
CompileChunk = chunk(<<"CInf">>, Compile),
@@ -193,7 +192,7 @@ build_file(Code, Attr, Dict, NumLabels, NumFuncs, ExtraChunks, SourceFile, Opts,
%% Create IFF chunk.
- Chunks = case member(slim, Opts) of
+ Chunks = case member(slim, CompilerOpts) of
true ->
[Essentials,AttrChunk];
false ->
@@ -241,9 +240,7 @@ build_form(Id, Chunks0) when byte_size(Id) =:= 4, is_list(Chunks0) ->
chunk(Id, Contents) when byte_size(Id) =:= 4, is_binary(Contents) ->
Size = byte_size(Contents),
- [<<Id/binary,Size:32>>,Contents|pad(Size)];
-chunk(Id, Contents) when is_list(Contents) ->
- chunk(Id, list_to_binary(Contents)).
+ [<<Id/binary,Size:32>>,Contents|pad(Size)].
%% Build a correctly padded chunk (with a sub-header).
@@ -265,22 +262,10 @@ flatten_exports(Exps) ->
flatten_imports(Imps) ->
list_to_binary(map(fun({M,F,A}) -> <<M:32,F:32,A:32>> end, Imps)).
-build_attributes(Opts, CompilerOpts, SourceFile, Attr, MD5) ->
- Misc0 = case SourceFile of
- [] -> [];
- [_|_] -> [{source,SourceFile}]
- end,
- Misc = case member(slim, CompilerOpts) of
- false -> Misc0;
- true -> []
- end,
- Compile = case member(deterministic, CompilerOpts) of
- false ->
- [{options,Opts},{version,?COMPILER_VSN}|Misc];
- true ->
- [{version,?COMPILER_VSN}]
- end,
- {term_to_binary(set_vsn_attribute(Attr, MD5)),term_to_binary(Compile)}.
+build_attributes(Attr, Compile, MD5) ->
+ AttrBinary = term_to_binary(set_vsn_attribute(Attr, MD5)),
+ CompileBinary = term_to_binary([{version,?COMPILER_VSN}|Compile]),
+ {AttrBinary,CompileBinary}.
build_line_table(Dict) ->
{NumLineInstrs,NumFnames0,Fnames0,NumLines,Lines0} =
@@ -422,15 +407,25 @@ encode_arg({atom, Atom}, Dict0) when is_atom(Atom) ->
{Index, Dict} = beam_dict:atom(Atom, Dict0),
{encode(?tag_a, Index), Dict};
encode_arg({integer, N}, Dict) ->
- {encode(?tag_i, N), Dict};
+ %% Conservatively assume that all integers whose absolute
+ %% value is greater than 1 bsl 128 will be bignums in
+ %% the runtime system.
+ if
+ N >= 1 bsl 128 ->
+ encode_literal(N, Dict);
+ N =< -(1 bsl 128) ->
+ encode_literal(N, Dict);
+ true ->
+ {encode(?tag_i, N), Dict}
+ end;
encode_arg(nil, Dict) ->
{encode(?tag_a, 0), Dict};
encode_arg({f, W}, Dict) ->
{encode(?tag_f, W), Dict};
%% encode_arg({'char', C}, Dict) ->
%% {encode(?tag_h, C), Dict};
-encode_arg({string, String}, Dict0) ->
- {Offset, Dict} = beam_dict:string(String, Dict0),
+encode_arg({string, BinString}, Dict0) when is_binary(BinString) ->
+ {Offset, Dict} = beam_dict:string(BinString, Dict0),
{encode(?tag_u, Offset), Dict};
encode_arg({extfunc, M, F, A}, Dict0) ->
{Index, Dict} = beam_dict:import(M, F, A, Dict0),
@@ -439,7 +434,7 @@ encode_arg({list, List}, Dict0) ->
{L, Dict} = encode_list(List, Dict0, []),
{[encode(?tag_z, 1), encode(?tag_u, length(List))|L], Dict};
encode_arg({float, Float}, Dict) when is_float(Float) ->
- encode_arg({literal,Float}, Dict);
+ encode_literal(Float, Dict);
encode_arg({fr,Fr}, Dict) ->
{[encode(?tag_z, 2),encode(?tag_u, Fr)], Dict};
encode_arg({field_flags,Flags0}, Dict) ->
@@ -447,12 +442,24 @@ encode_arg({field_flags,Flags0}, Dict) ->
{encode(?tag_u, Flags), Dict};
encode_arg({alloc,List}, Dict) ->
encode_alloc_list(List, Dict);
-encode_arg({literal,Lit}, Dict0) ->
- {Index,Dict} = beam_dict:literal(Lit, Dict0),
- {[encode(?tag_z, 4),encode(?tag_u, Index)],Dict};
+encode_arg({literal,Lit}, Dict) ->
+ if
+ Lit =:= [] ->
+ encode_arg(nil, Dict);
+ is_atom(Lit) ->
+ encode_arg({atom,Lit}, Dict);
+ is_integer(Lit) ->
+ encode_arg({integer,Lit}, Dict);
+ true ->
+ encode_literal(Lit, Dict)
+ end;
encode_arg(Int, Dict) when is_integer(Int) ->
{encode(?tag_u, Int),Dict}.
+encode_literal(Literal, Dict0) ->
+ {Index,Dict} = beam_dict:literal(Literal, Dict0),
+ {[encode(?tag_z, 4),encode(?tag_u, Index)],Dict}.
+
%%flag_to_bit(aligned) -> 16#01; %% No longer useful.
flag_to_bit(little) -> 16#02;
flag_to_bit(big) -> 16#00;
@@ -480,7 +487,7 @@ encode_alloc_list_1([{floats,Floats}|T], Dict, Acc0) ->
encode_alloc_list_1([], Dict, Acc) ->
{iolist_to_binary(Acc),Dict}.
--spec encode(non_neg_integer(), pos_integer()) -> iodata().
+-spec encode(non_neg_integer(), integer()) -> iolist() | integer().
encode(Tag, N) when N < 0 ->
encode1(Tag, negative_to_bytes(N));
diff --git a/lib/compiler/src/beam_block.erl b/lib/compiler/src/beam_block.erl
index 6543e05e20..707974b2c1 100644
--- a/lib/compiler/src/beam_block.erl
+++ b/lib/compiler/src/beam_block.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -17,36 +17,27 @@
%%
%% %CopyrightEnd%
%%
-%% Purpose : Partitions assembly instructions into basic blocks and
-%% optimizes them.
+%% Purpose: Partition BEAM instructions into basic blocks.
-module(beam_block).
-export([module/2]).
--import(lists, [reverse/1,reverse/2,foldl/3,member/2]).
+-import(lists, [keysort/2,reverse/1,splitwith/2]).
-spec module(beam_utils:module_code(), [compile:option()]) ->
{'ok',beam_utils:module_code()}.
-module({Mod,Exp,Attr,Fs0,Lc}, _Opt) ->
+module({Mod,Exp,Attr,Fs0,Lc}, _Opts) ->
Fs = [function(F) || F <- Fs0],
{ok,{Mod,Exp,Attr,Fs,Lc}}.
function({function,Name,Arity,CLabel,Is0}) ->
try
- %% Collect basic blocks and optimize them.
- Is1 = blockify(Is0),
- Is2 = embed_lines(Is1),
- Is3 = move_allocates(Is2),
- Is4 = beam_utils:live_opt(Is3),
- Is5 = opt_blocks(Is4),
- Is6 = beam_utils:delete_live_annos(Is5),
-
- %% Done.
- {function,Name,Arity,CLabel,Is6}
+ Is1 = blockify(Is0),
+ Is = embed_lines(Is1),
+ {function,Name,Arity,CLabel,Is}
catch
- Class:Error ->
- Stack = erlang:get_stacktrace(),
+ Class:Error:Stack ->
io:fwrite("Function: ~w/~w\n", [Name,Arity]),
erlang:raise(Class, Error, Stack)
end.
@@ -58,14 +49,12 @@ function({function,Name,Arity,CLabel,Is0}) ->
blockify(Is) ->
blockify(Is, []).
-blockify([{loop_rec,{f,Fail},{x,0}},{loop_rec_end,_Lbl},{label,Fail}|Is], Acc) ->
- %% Useless instruction sequence.
- blockify(Is, Acc);
blockify([I|Is0]=IsAll, Acc) ->
case collect(I) of
error -> blockify(Is0, [I|Acc]);
Instr when is_tuple(Instr) ->
- {Block,Is} = collect_block(IsAll),
+ {Block0,Is} = collect_block(IsAll),
+ Block = sort_moves(Block0),
blockify(Is, [{block,Block}|Acc])
end;
blockify([], Acc) -> reverse(Acc).
@@ -74,12 +63,10 @@ collect_block(Is) ->
collect_block(Is, []).
collect_block([{allocate,N,R}|Is0], Acc) ->
- {Inits,Is} = lists:splitwith(fun ({init,{y,_}}) -> true;
- (_) -> false
- end, Is0),
+ {Inits,Is} = splitwith(fun ({init,{y,_}}) -> true;
+ (_) -> false
+ end, Is0),
collect_block(Is, [{set,[],[],{alloc,R,{nozero,N,0,Inits}}}|Acc]);
-collect_block([{allocate_zero,Ns,R},{test_heap,Nh,R}|Is], Acc) ->
- collect_block(Is, [{set,[],[],{alloc,R,{zero,Ns,Nh,[]}}}|Acc]);
collect_block([I|Is]=Is0, Acc) ->
case collect(I) of
error -> {reverse(Acc),Is0};
@@ -94,22 +81,20 @@ collect({allocate_heap,Ns,Nh,R}) -> {set,[],[],{alloc,R,{nozero,Ns,Nh,[]}}};
collect({allocate_heap_zero,Ns,Nh,R}) -> {set,[],[],{alloc,R,{zero,Ns,Nh,[]}}};
collect({init,D}) -> {set,[D],[],init};
collect({test_heap,N,R}) -> {set,[],[],{alloc,R,{nozero,nostack,N,[]}}};
-collect({bif,N,F,As,D}) -> {set,[D],As,{bif,N,F}};
-collect({gc_bif,N,F,R,As,D}) -> {set,[D],As,{alloc,R,{gc_bif,N,F}}};
+collect({bif,N,{f,0},As,D}) -> {set,[D],As,{bif,N,{f,0}}};
+collect({gc_bif,N,{f,0},R,As,D}) -> {set,[D],As,{alloc,R,{gc_bif,N,{f,0}}}};
collect({move,S,D}) -> {set,[D],[S],move};
collect({put_list,S1,S2,D}) -> {set,[D],[S1,S2],put_list};
collect({put_tuple,A,D}) -> {set,[D],[],{put_tuple,A}};
collect({put,S}) -> {set,[],[S],put};
+collect({put_tuple2,D,{list,Els}}) -> {set,[D],Els,put_tuple2};
collect({get_tuple_element,S,I,D}) -> {set,[D],[S],{get_tuple_element,I}};
collect({set_tuple_element,S,D,I}) -> {set,[],[S,D],{set_tuple_element,I}};
-collect({get_list,S,D1,D2}) -> {set,[D1,D2],[S],get_list};
+collect({get_hd,S,D}) -> {set,[D],[S],get_hd};
+collect({get_tl,S,D}) -> {set,[D],[S],get_tl};
collect(remove_message) -> {set,[],[],remove_message};
-collect({put_map,F,Op,S,D,R,{list,Puts}}) ->
- {set,[D],[S|Puts],{alloc,R,{put_map,Op,F}}};
-collect({'catch'=Op,R,L}) ->
- {set,[R],[],{try_catch,Op,L}};
-collect({'try'=Op,R,L}) ->
- {set,[R],[],{try_catch,Op,L}};
+collect({put_map,{f,0},Op,S,D,R,{list,Puts}}) ->
+ {set,[D],[S|Puts],{alloc,R,{put_map,Op,{f,0}}}};
collect(fclearerror) -> {set,[],[],fclearerror};
collect({fcheckerror,{f,0}}) -> {set,[],[],fcheckerror};
collect({fmove,S,D}) -> {set,[D],[S],fmove};
@@ -134,350 +119,35 @@ embed_lines([I|Is], Acc) ->
embed_lines(Is, [I|Acc]);
embed_lines([], Acc) -> Acc.
-opt_blocks([{block,Bl0}|Is]) ->
- %% The live annotation at the beginning is not useful.
- [{'%live',_,_}|Bl] = Bl0,
- [{block,opt_block(Bl)}|opt_blocks(Is)];
-opt_blocks([I|Is]) ->
- [I|opt_blocks(Is)];
-opt_blocks([]) -> [].
-
-opt_block(Is0) ->
- Is = find_fixpoint(fun(Is) ->
- opt_tuple_element(opt(Is))
- end, Is0),
- opt_alloc(Is).
-
-find_fixpoint(OptFun, Is0) ->
- case OptFun(Is0) of
- Is0 -> Is0;
- Is1 -> find_fixpoint(OptFun, Is1)
- end.
-
-%% move_allocates(Is0) -> Is
-%% Move allocate instructions upwards in the instruction stream
-%% (within the same block), in the hope of getting more possibilities
-%% for optimizing away moves later.
-%%
-%% For example, we can transform the following instructions:
-%%
-%% get_tuple_element x(1) Element => x(2)
-%% allocate_zero StackSize 3 %% x(0), x(1), x(2) are live
-%%
-%% to the following instructions:
-%%
-%% allocate_zero StackSize 2 %% x(0) and x(1) are live
-%% get_tuple_element x(1) Element => x(2)
-%%
-%% NOTE: Since the beam_reorder pass has been run, it is no longer
-%% safe to assume that if x(N) is initialized, then all lower-numbered
-%% x registers are also initialized.
-%%
-%% For example, in general it is not safe to transform the following
-%% instructions:
-%%
-%% get_tuple_element x(0) Element => x(1)
-%% allocate_zero StackSize 3 %x(0), x(1), x(2) are live
-%%
-%% to the following instructions:
-%%
-%% allocate_zero StackSize 3
-%% get_tuple_element x(0) Element => x(1)
-%%
-%% The transformation is safe if and only if x(1) has been
-%% initialized previously. Unfortunately, beam_reorder may have moved
-%% a get_tuple_element instruction so that x(1) is not always
-%% initialized when this code is reached. To find whether or not x(1)
-%% is initialized, we would need to analyze all code preceding these
-%% two instructions (across branches). Since we currently don't have
-%% any practical mechanism for doing that, we will have to
-%% conservatively assume that the transformation is unsafe.
-
-move_allocates([{block,Bl0}|Is]) ->
- Bl = move_allocates_1(reverse(Bl0), []),
- [{block,Bl}|move_allocates(Is)];
-move_allocates([I|Is]) ->
- [I|move_allocates(Is)];
-move_allocates([]) -> [].
-
-move_allocates_1([I|Is], [{set,[],[],{alloc,Live0,Info}}|Acc]=Acc0) ->
- case {alloc_may_pass(I),alloc_live_regs(I, Live0)} of
- {false,_} ->
- move_allocates_1(Is, [I|Acc0]);
- {true,not_possible} ->
- move_allocates_1(Is, [I|Acc0]);
- {true,Live} when is_integer(Live) ->
- A = {set,[],[],{alloc,Live,Info}},
- move_allocates_1(Is, [A,I|Acc])
- end;
-move_allocates_1([I|Is], Acc) ->
- move_allocates_1(Is, [I|Acc]);
-move_allocates_1([], Acc) -> Acc.
-
-alloc_may_pass({set,_,_,{alloc,_,_}}) -> false;
-alloc_may_pass({set,_,_,{set_tuple_element,_}}) -> false;
-alloc_may_pass({set,_,_,put_list}) -> false;
-alloc_may_pass({set,_,_,put}) -> false;
-alloc_may_pass({set,_,_,_}) -> true.
-
-%% opt([Instruction]) -> [Instruction]
-%% Optimize the instruction stream inside a basic block.
-
-opt([{set,[X],[X],move}|Is]) -> opt(Is);
-opt([{set,_,_,{line,_}}=Line1,
- {set,[D1],[{integer,Idx1},Reg],{bif,element,{f,0}}}=I1,
- {set,_,_,{line,_}}=Line2,
- {set,[D2],[{integer,Idx2},Reg],{bif,element,{f,0}}}=I2|Is])
- when Idx1 < Idx2, D1 =/= D2, D1 =/= Reg, D2 =/= Reg ->
- opt([Line2,I2,Line1,I1|Is]);
-opt([{set,Ds0,Ss,Op}|Is0]) ->
- {Ds,Is} = opt_moves(Ds0, Is0),
- [{set,Ds,Ss,Op}|opt(Is)];
-opt([{'%live',_,_}=I|Is]) ->
- [I|opt(Is)];
-opt([]) -> [].
-
-%% opt_moves([Dest], [Instruction]) -> {[Dest],[Instruction]}
-%% For each Dest, does the optimization described in opt_move/2.
-
-opt_moves([], Is0) -> {[],Is0};
-opt_moves([D0]=Ds, Is0) ->
- case opt_move(D0, Is0) of
- not_possible -> {Ds,Is0};
- {D1,Is} -> {[D1],Is}
- end;
-opt_moves([X0,Y0], Is0) ->
- {X,Is2} = case opt_move(X0, Is0) of
- not_possible -> {X0,Is0};
- {Y0,_} -> {X0,Is0};
- {_X1,_Is1} = XIs1 -> XIs1
- end,
- case opt_move(Y0, Is2) of
- not_possible -> {[X,Y0],Is2};
- {X,_} -> {[X,Y0],Is2};
- {Y,Is} -> {[X,Y],Is}
- end.
-
-%% opt_move(Dest, [Instruction]) -> {UpdatedDest,[Instruction]} | not_possible
-%% If there is a {move,Dest,FinalDest} instruction
-%% in the instruction stream, remove the move instruction
-%% and let FinalDest be the destination.
-
-opt_move(Dest, Is) ->
- opt_move_1(Dest, Is, []).
-
-opt_move_1(R, [{set,[D],[R],move}|Is0], Acc) ->
- %% Provided that the source register is killed by instructions
- %% that follow, the optimization is safe.
- case eliminate_use_of_from_reg(Is0, R, D, []) of
- {yes,Is} -> opt_move_rev(D, Acc, Is);
- no -> not_possible
- end;
-opt_move_1(_R, [{set,_,_,{alloc,_,_}}|_], _) ->
- %% The optimization is either not possible or not safe.
- %%
- %% If R is an X register killed by allocation, the optimization is
- %% not safe. On the other hand, if the X register is killed, there
- %% will not follow a 'move' instruction with this X register as
- %% the source.
- %%
- %% If R is a Y register, the optimization is still not safe
- %% because the new target register is an X register that cannot
- %% safely pass the alloc instruction.
- not_possible;
-opt_move_1(R, [{set,_,_,_}=I|Is], Acc) ->
- %% If the source register is either killed or used by this
- %% instruction, the optimimization is not possible.
- case is_killed_or_used(R, I) of
- true -> not_possible;
- false -> opt_move_1(R, Is, [I|Acc])
- end;
-opt_move_1(_, _, _) ->
- not_possible.
-
-%% opt_tuple_element([Instruction]) -> [Instruction]
-%% If possible, move get_tuple_element instructions forward
-%% in the instruction stream to a move instruction, eliminating
-%% the move instruction. Example:
-%%
-%% get_tuple_element Tuple Pos Dst1
-%% ...
-%% move Dst1 Dst2
-%%
-%% This code may be possible to rewrite to:
-%%
-%% %%(Moved get_tuple_element instruction)
-%% ...
-%% get_tuple_element Tuple Pos Dst2
-%%
-
-opt_tuple_element([{set,[D],[S],{get_tuple_element,_}}=I|Is0]) ->
- case opt_tuple_element_1(Is0, I, {S,D}, []) of
- no ->
- [I|opt_tuple_element(Is0)];
- {yes,Is} ->
- opt_tuple_element(Is)
- end;
-opt_tuple_element([I|Is]) ->
- [I|opt_tuple_element(Is)];
-opt_tuple_element([]) -> [].
-
-opt_tuple_element_1([{set,_,_,{alloc,_,_}}|_], _, _, _) ->
- no;
-opt_tuple_element_1([{set,_,_,{try_catch,_,_}}|_], _, _, _) ->
- no;
-opt_tuple_element_1([{set,[D],[S],move}|Is0], I0, {_,S}, Acc) ->
- case eliminate_use_of_from_reg(Is0, S, D, []) of
- no ->
- no;
- {yes,Is} ->
- {set,[S],Ss,Op} = I0,
- I = {set,[D],Ss,Op},
- {yes,reverse(Acc, [I|Is])}
- end;
-opt_tuple_element_1([{set,Ds,Ss,_}=I|Is], MovedI, {S,D}=Regs, Acc) ->
- case member(S, Ds) orelse member(D, Ss) of
- true ->
- no;
- false ->
- opt_tuple_element_1(Is, MovedI, Regs, [I|Acc])
- end;
-opt_tuple_element_1(_, _, _, _) -> no.
-
-%% Reverse the instructions, while checking that there are no
-%% instructions that would interfere with using the new destination
-%% register (D).
-
-opt_move_rev(D, [I|Is], Acc) ->
- case is_killed_or_used(D, I) of
- true -> not_possible;
- false -> opt_move_rev(D, Is, [I|Acc])
- end;
-opt_move_rev(D, [], Acc) -> {D,Acc}.
-
-%% is_killed_or_used(Register, {set,_,_,_}) -> bool()
-%% Test whether the register is used by the instruction.
-
-is_killed_or_used(R, {set,Ss,Ds,_}) ->
- member(R, Ds) orelse member(R, Ss).
-
-%% eliminate_use_of_from_reg([Instruction], FromRegister, ToRegister, Acc) ->
-%% {yes,Is} | no
-%% Eliminate any use of FromRegister in the instruction sequence
-%% by replacing uses of FromRegister with ToRegister. If FromRegister
-%% is referenced by an allocation instruction, return 'no' to indicate
-%% that FromRegister is still used and that the optimization is not
-%% possible.
-
-eliminate_use_of_from_reg([{set,_,_,{alloc,Live,_}}|_]=Is0, {x,X}, _, Acc) ->
- if
- X < Live ->
- no;
- true ->
- {yes,reverse(Acc, Is0)}
- end;
-eliminate_use_of_from_reg([{set,Ds,Ss0,Op}=I0|Is], From, To, Acc) ->
- I = case member(From, Ss0) of
- true ->
- Ss = [case S of
- From -> To;
- _ -> S
- end || S <- Ss0],
- {set,Ds,Ss,Op};
- false ->
- I0
- end,
- case member(From, Ds) of
- true ->
- {yes,reverse(Acc, [I|Is])};
- false ->
- eliminate_use_of_from_reg(Is, From, To, [I|Acc])
- end;
-eliminate_use_of_from_reg([I]=Is, From, _To, Acc) ->
- case beam_utils:is_killed_block(From, [I]) of
- true ->
- {yes,reverse(Acc, Is)};
- false ->
- no
- end.
-
-%% opt_alloc(Instructions) -> Instructions'
-%% Optimises all allocate instructions.
-
-opt_alloc([{set,[],[],{alloc,Live0,Info0}},
- {set,[],[],{alloc,Live,Info}}|Is]) ->
- Live = Live0, %Assertion.
- Alloc = combine_alloc(Info0, Info),
- I = {set,[],[],{alloc,Live,Alloc}},
- opt_alloc([I|Is]);
-opt_alloc([{set,[],[],{alloc,R,{_,Ns,Nh,[]}}}|Is]) ->
- [{set,[],[],opt_alloc(Is, Ns, Nh, R)}|Is];
-opt_alloc([I|Is]) -> [I|opt_alloc(Is)];
-opt_alloc([]) -> [].
-
-combine_alloc({_,Ns,Nh1,Init}, {_,nostack,Nh2,[]}) ->
- {zero,Ns,beam_utils:combine_heap_needs(Nh1, Nh2),Init}.
-
-%% opt_alloc(Instructions, FrameSize, HeapNeed, LivingRegs) -> [Instr]
-%% Generates the optimal sequence of instructions for
-%% allocating and initalizing the stack frame and needed heap.
-
-opt_alloc(_Is, nostack, Nh, LivingRegs) ->
- {alloc,LivingRegs,{nozero,nostack,Nh,[]}};
-opt_alloc(Is, Ns, Nh, LivingRegs) ->
- InitRegs = init_yreg(Is, 0),
- case count_ones(InitRegs) of
- N when N*2 > Ns ->
- {alloc,LivingRegs,{nozero,Ns,Nh,gen_init(Ns, InitRegs)}};
- _ ->
- {alloc,LivingRegs,{zero,Ns,Nh,[]}}
+%% sort_moves([Instruction]) -> [Instruction].
+%% Sort move instructions on the Y register to give the loader
+%% more opportunities for combining instructions.
+
+sort_moves([{set,[{x,_}],[{y,_}],move}=I|Is0]) ->
+ {Moves,Is} = sort_moves_1(Is0, x, y, [I]),
+ Moves ++ sort_moves(Is);
+sort_moves([{set,[{y,_}],[{x,_}],move}=I|Is0]) ->
+ {Moves,Is} = sort_moves_1(Is0, y, x, [I]),
+ Moves ++ sort_moves(Is);
+sort_moves([I|Is]) ->
+ [I|sort_moves(Is)];
+sort_moves([]) -> [].
+
+sort_moves_1([{set,[{x,0}],[_],move}=I|Is], _DTag, _STag, Acc) ->
+ %% The loader sometimes combines a move to x0 with the
+ %% instruction that follows, producing, for example, a move_call
+ %% instruction. Therefore, we don't want include this move
+ %% instruction in the sorting.
+ {sort_on_yreg(Acc)++[I],Is};
+sort_moves_1([{set,[{DTag,_}],[{STag,_}],move}=I|Is], DTag, STag, Acc) ->
+ sort_moves_1(Is, DTag, STag, [I|Acc]);
+sort_moves_1(Is, _DTag, _STag, Acc) ->
+ {sort_on_yreg(Acc),Is}.
+
+sort_on_yreg([{set,[Dst],[Src],move}|_]=Moves) ->
+ case {Dst,Src} of
+ {{y,_},{x,_}} ->
+ keysort(2, Moves);
+ {{x,_},{y,_}} ->
+ keysort(3, Moves)
end.
-
-gen_init(Fs, Regs) -> gen_init(Fs, Regs, 0, []).
-
-gen_init(SameFs, _Regs, SameFs, Acc) -> reverse(Acc);
-gen_init(Fs, Regs, Y, Acc) when Regs band 1 =:= 0 ->
- gen_init(Fs, Regs bsr 1, Y+1, [{init,{y,Y}}|Acc]);
-gen_init(Fs, Regs, Y, Acc) ->
- gen_init(Fs, Regs bsr 1, Y+1, Acc).
-
-%% init_yreg(Instructions, RegSet) -> RegSetInitialized
-%% Calculate the set of initialized y registers.
-
-init_yreg([{set,_,_,{bif,_,_}}|_], Reg) -> Reg;
-init_yreg([{set,_,_,{alloc,_,{gc_bif,_,_}}}|_], Reg) -> Reg;
-init_yreg([{set,_,_,{alloc,_,{put_map,_,_}}}|_], Reg) -> Reg;
-init_yreg([{set,Ds,_,_}|Is], Reg) -> init_yreg(Is, add_yregs(Ds, Reg));
-init_yreg(_Is, Reg) -> Reg.
-
-add_yregs(Ys, Reg) -> foldl(fun(Y, R0) -> add_yreg(Y, R0) end, Reg, Ys).
-
-add_yreg({y,Y}, Reg) -> Reg bor (1 bsl Y);
-add_yreg(_, Reg) -> Reg.
-
-count_ones(Bits) -> count_ones(Bits, 0).
-count_ones(0, Acc) -> Acc;
-count_ones(Bits, Acc) ->
- count_ones(Bits bsr 1, Acc + (Bits band 1)).
-
-%% Calculate the new number of live registers when we move an allocate
-%% instruction upwards, passing a 'set' instruction.
-
-alloc_live_regs({set,Ds,Ss,_}, Regs0) ->
- Rset = x_live(Ss, x_dead(Ds, (1 bsl Regs0)-1)),
- live_regs(0, Rset).
-
-live_regs(N, 0) ->
- N;
-live_regs(N, Regs) when Regs band 1 =:= 1 ->
- live_regs(N+1, Regs bsr 1);
-live_regs(_, _) ->
- not_possible.
-
-x_dead([{x,N}|Rs], Regs) -> x_dead(Rs, Regs band (bnot (1 bsl N)));
-x_dead([_|Rs], Regs) -> x_dead(Rs, Regs);
-x_dead([], Regs) -> Regs.
-
-x_live([{x,N}|Rs], Regs) -> x_live(Rs, Regs bor (1 bsl N));
-x_live([_|Rs], Regs) -> x_live(Rs, Regs);
-x_live([], Regs) -> Regs.
diff --git a/lib/compiler/src/beam_bs.erl b/lib/compiler/src/beam_bs.erl
deleted file mode 100644
index beb055b23d..0000000000
--- a/lib/compiler/src/beam_bs.erl
+++ /dev/null
@@ -1,281 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%% Purpose : Partitions assembly instructions into basic blocks and
-%% optimizes them.
-
--module(beam_bs).
-
--export([module/2]).
--import(lists, [mapfoldl/3,reverse/1]).
-
--spec module(beam_utils:module_code(), [compile:option()]) ->
- {'ok',beam_utils:module_code()}.
-
-module({Mod,Exp,Attr,Fs0,Lc0}, _Opt) ->
- {Fs,Lc} = mapfoldl(fun function/2, Lc0, Fs0),
- {ok,{Mod,Exp,Attr,Fs,Lc}}.
-
-function({function,Name,Arity,CLabel,Is0}, Lc0) ->
- try
- Is1 = bs_put_opt(Is0),
- {Is,Lc} = bsm_opt(Is1, Lc0),
- {{function,Name,Arity,CLabel,Is},Lc}
- catch
- Class:Error ->
- Stack = erlang:get_stacktrace(),
- io:fwrite("Function: ~w/~w\n", [Name,Arity]),
- erlang:raise(Class, Error, Stack)
- end.
-
-%%%
-%%% Evaluation of constant bit fields.
-%%%
-
-bs_put_opt([{bs_put,_,_,_}=I|Is0]) ->
- {BsPuts0,Is} = collect_bs_puts(Is0, [I]),
- BsPuts = opt_bs_puts(BsPuts0),
- BsPuts ++ bs_put_opt(Is);
-bs_put_opt([I|Is]) ->
- [I|bs_put_opt(Is)];
-bs_put_opt([]) -> [].
-
-collect_bs_puts([{bs_put,_,_,_}=I|Is], Acc) ->
- collect_bs_puts(Is, [I|Acc]);
-collect_bs_puts([_|_]=Is, Acc) ->
- {reverse(Acc),Is}.
-
-opt_bs_puts(Is) ->
- opt_bs_1(Is, []).
-
-opt_bs_1([{bs_put,Fail,
- {bs_put_float,1,Flags0},[{integer,Sz},Src]}=I0|Is], Acc) ->
- try eval_put_float(Src, Sz, Flags0) of
- <<Int:Sz>> ->
- Flags = force_big(Flags0),
- I = {bs_put,Fail,{bs_put_integer,1,Flags},
- [{integer,Sz},{integer,Int}]},
- opt_bs_1([I|Is], Acc)
- catch
- error:_ ->
- opt_bs_1(Is, [I0|Acc])
- end;
-opt_bs_1([{bs_put,_,{bs_put_integer,1,_},[{integer,8},{integer,_}]}|_]=IsAll,
- Acc0) ->
- {Is,Acc} = bs_collect_string(IsAll, Acc0),
- opt_bs_1(Is, Acc);
-opt_bs_1([{bs_put,Fail,{bs_put_integer,1,F},[{integer,Sz},{integer,N}]}=I|Is0],
- Acc) when Sz > 8 ->
- case field_endian(F) of
- big ->
- %% We can do this optimization for any field size without
- %% risk for code explosion.
- case bs_split_int(N, Sz, Fail, Is0) of
- no_split -> opt_bs_1(Is0, [I|Acc]);
- Is -> opt_bs_1(Is, Acc)
- end;
- little when Sz < 128 ->
- %% We only try to optimize relatively small fields, to
- %% avoid an explosion in code size.
- <<Int:Sz>> = <<N:Sz/little>>,
- Flags = force_big(F),
- Is = [{bs_put,Fail,{bs_put_integer,1,Flags},
- [{integer,Sz},{integer,Int}]}|Is0],
- opt_bs_1(Is, Acc);
- _ -> %native or too wide little field
- opt_bs_1(Is0, [I|Acc])
- end;
-opt_bs_1([{bs_put,Fail,{Op,U,F},[{integer,Sz},Src]}|Is], Acc) when U > 1 ->
- opt_bs_1([{bs_put,Fail,{Op,1,F},[{integer,U*Sz},Src]}|Is], Acc);
-opt_bs_1([I|Is], Acc) ->
- opt_bs_1(Is, [I|Acc]);
-opt_bs_1([], Acc) -> reverse(Acc).
-
-eval_put_float(Src, Sz, Flags) when Sz =< 256 ->
- %%Only evaluate if Sz is reasonable.
- Val = value(Src),
- case field_endian(Flags) of
- little -> <<Val:Sz/little-float-unit:1>>;
- big -> <<Val:Sz/big-float-unit:1>>
- %% native intentionally not handled here - we can't optimize
- %% it.
- end.
-
-value({integer,I}) -> I;
-value({float,F}) -> F.
-
-bs_collect_string(Is, [{bs_put,_,{bs_put_string,Len,{string,Str}},[]}|Acc]) ->
- bs_coll_str_1(Is, Len, reverse(Str), Acc);
-bs_collect_string(Is, Acc) ->
- bs_coll_str_1(Is, 0, [], Acc).
-
-bs_coll_str_1([{bs_put,_,{bs_put_integer,U,_},[{integer,Sz},{integer,V}]}|Is],
- Len, StrAcc, IsAcc) when U*Sz =:= 8 ->
- Byte = V band 16#FF,
- bs_coll_str_1(Is, Len+1, [Byte|StrAcc], IsAcc);
-bs_coll_str_1(Is, Len, StrAcc, IsAcc) ->
- {Is,[{bs_put,{f,0},{bs_put_string,Len,{string,reverse(StrAcc)}},[]}|IsAcc]}.
-
-field_endian({field_flags,F}) -> field_endian_1(F).
-
-field_endian_1([big=E|_]) -> E;
-field_endian_1([little=E|_]) -> E;
-field_endian_1([native=E|_]) -> E;
-field_endian_1([_|Fs]) -> field_endian_1(Fs).
-
-force_big({field_flags,F}) ->
- {field_flags,force_big_1(F)}.
-
-force_big_1([big|_]=Fs) -> Fs;
-force_big_1([little|Fs]) -> [big|Fs];
-force_big_1([F|Fs]) -> [F|force_big_1(Fs)].
-
-bs_split_int(0, Sz, _, _) when Sz > 64 ->
- %% We don't want to split in this case because the
- %% string will consist of only zeroes.
- no_split;
-bs_split_int(-1, Sz, _, _) when Sz > 64 ->
- %% We don't want to split in this case because the
- %% string will consist of only 255 bytes.
- no_split;
-bs_split_int(N, Sz, Fail, Acc) ->
- FirstByteSz = case Sz rem 8 of
- 0 -> 8;
- Rem -> Rem
- end,
- bs_split_int_1(N, FirstByteSz, Sz, Fail, Acc).
-
-bs_split_int_1(-1, _, Sz, Fail, Acc) when Sz > 64 ->
- I = {bs_put,Fail,{bs_put_integer,1,{field_flags,[big]}},
- [{integer,Sz},{integer,-1}]},
- [I|Acc];
-bs_split_int_1(0, _, Sz, Fail, Acc) when Sz > 64 ->
- I = {bs_put,Fail,{bs_put_integer,1,{field_flags,[big]}},
- [{integer,Sz},{integer,0}]},
- [I|Acc];
-bs_split_int_1(N, ByteSz, Sz, Fail, Acc) when Sz > 0 ->
- Mask = (1 bsl ByteSz) - 1,
- I = {bs_put,Fail,{bs_put_integer,1,{field_flags,[big]}},
- [{integer,ByteSz},{integer,N band Mask}]},
- bs_split_int_1(N bsr ByteSz, 8, Sz-ByteSz, Fail, [I|Acc]);
-bs_split_int_1(_, _, _, _, Acc) -> Acc.
-
-%%%
-%%% Optimization of bit syntax matching: get rid
-%%% of redundant bs_restore2/2 instructions across select_val
-%%% instructions, as well as a few other simple peep-hole
-%%% optimizations.
-%%%
-
-bsm_opt(Is0, Lc0) ->
- {Is1,D0,Lc} = bsm_scan(Is0, [], Lc0, []),
- Is2 = case D0 of
- [] ->
- %% No bit syntax matching in this function.
- Is1;
- [_|_] ->
- %% Optimize the bit syntax matching.
- D = gb_trees:from_orddict(orddict:from_list(D0)),
- bsm_reroute(Is1, D, none, [])
- end,
- Is = beam_clean:bs_clean_saves(Is2),
- {bsm_opt_2(Is, []),Lc}.
-
-bsm_scan([{label,L}=Lbl,{bs_restore2,_,Save}=R|Is], D0, Lc, Acc0) ->
- D = [{{L,Save},Lc}|D0],
- Acc = [{label,Lc},R,Lbl|Acc0],
- bsm_scan(Is, D, Lc+1, Acc);
-bsm_scan([I|Is], D, Lc, Acc) ->
- bsm_scan(Is, D, Lc, [I|Acc]);
-bsm_scan([], D, Lc, Acc) ->
- {reverse(Acc),D,Lc}.
-
-bsm_reroute([{bs_save2,Reg,Save}=I|Is], D, _, Acc) ->
- bsm_reroute(Is, D, {Reg,Save}, [I|Acc]);
-bsm_reroute([{bs_restore2,Reg,Save}=I|Is], D, _, Acc) ->
- bsm_reroute(Is, D, {Reg,Save}, [I|Acc]);
-bsm_reroute([{label,_}=I|Is], D, S, Acc) ->
- bsm_reroute(Is, D, S, [I|Acc]);
-bsm_reroute([{select,select_val,Reg,F0,Lbls0}|Is], D, {_,Save}=S, Acc0) ->
- [F|Lbls] = bsm_subst_labels([F0|Lbls0], Save, D),
- Acc = [{select,select_val,Reg,F,Lbls}|Acc0],
- bsm_reroute(Is, D, S, Acc);
-bsm_reroute([{test,TestOp,F0,TestArgs}=I|Is], D, {_,Save}=S, Acc0) ->
- F = bsm_subst_label(F0, Save, D),
- Acc = [{test,TestOp,F,TestArgs}|Acc0],
- case bsm_not_bs_test(I) of
- true ->
- %% The test instruction will not update the bit offset for
- %% the binary being matched. Therefore the save position
- %% can be kept.
- bsm_reroute(Is, D, S, Acc);
- false ->
- %% The test instruction might update the bit offset. Kill
- %% our remembered Save position.
- bsm_reroute(Is, D, none, Acc)
- end;
-bsm_reroute([{test,TestOp,F0,Live,TestArgs,Dst}|Is], D, {_,Save}, Acc0) ->
- F = bsm_subst_label(F0, Save, D),
- Acc = [{test,TestOp,F,Live,TestArgs,Dst}|Acc0],
- %% The test instruction will update the bit offset. Kill our
- %% remembered Save position.
- bsm_reroute(Is, D, none, Acc);
-bsm_reroute([{block,[{set,[],[],{alloc,_,_}}]}=Bl,
- {bs_context_to_binary,_}=I|Is], D, S, Acc) ->
- %% To help further bit syntax optimizations.
- bsm_reroute([I,Bl|Is], D, S, Acc);
-bsm_reroute([I|Is], D, _, Acc) ->
- bsm_reroute(Is, D, none, [I|Acc]);
-bsm_reroute([], _, _, Acc) -> reverse(Acc).
-
-bsm_opt_2([{test,bs_test_tail2,F,[Ctx,Bits]}|Is],
- [{test,bs_skip_bits2,F,[Ctx,{integer,I},Unit,_Flags]}|Acc]) ->
- bsm_opt_2(Is, [{test,bs_test_tail2,F,[Ctx,Bits+I*Unit]}|Acc]);
-bsm_opt_2([{test,bs_skip_bits2,F,[Ctx,{integer,I1},Unit1,_]}|Is],
- [{test,bs_skip_bits2,F,[Ctx,{integer,I2},Unit2,Flags]}|Acc]) ->
- bsm_opt_2(Is, [{test,bs_skip_bits2,F,
- [Ctx,{integer,I1*Unit1+I2*Unit2},1,Flags]}|Acc]);
-bsm_opt_2([I|Is], Acc) ->
- bsm_opt_2(Is, [I|Acc]);
-bsm_opt_2([], Acc) -> reverse(Acc).
-
-%% bsm_not_bs_test({test,Name,_,Operands}) -> true|false.
-%% Test whether is the test is a "safe", i.e. does not move the
-%% bit offset for a binary.
-%%
-%% 'true' means that the test is safe, 'false' that we don't know or
-%% that the test moves the offset (e.g. bs_get_integer2).
-
-bsm_not_bs_test({test,bs_test_tail2,_,[_,_]}) -> true;
-bsm_not_bs_test(Test) -> beam_utils:is_pure_test(Test).
-
-bsm_subst_labels(Fs, Save, D) ->
- bsm_subst_labels_1(Fs, Save, D, []).
-
-bsm_subst_labels_1([F|Fs], Save, D, Acc) ->
- bsm_subst_labels_1(Fs, Save, D, [bsm_subst_label(F, Save, D)|Acc]);
-bsm_subst_labels_1([], _, _, Acc) ->
- reverse(Acc).
-
-bsm_subst_label({f,Lbl0}=F, Save, D) ->
- case gb_trees:lookup({Lbl0,Save}, D) of
- {value,Lbl} -> {f,Lbl};
- none -> F
- end;
-bsm_subst_label(Other, _, _) -> Other.
diff --git a/lib/compiler/src/beam_bsm.erl b/lib/compiler/src/beam_bsm.erl
deleted file mode 100644
index 9a4e7fb133..0000000000
--- a/lib/compiler/src/beam_bsm.erl
+++ /dev/null
@@ -1,702 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
--module(beam_bsm).
--export([module/2,format_error/1]).
-
--import(lists, [member/2,foldl/3,reverse/1,sort/1,all/2]).
-
-%%%
-%%% We optimize bit syntax matching where the tail end of a binary is
-%%% matched out and immediately passed on to a bs_start_match2 instruction,
-%%% such as in this code sequence:
-%%%
-%%% func_info ...
-%%% L1 test bs_start_match2 {f,...} {x,0} Live SavePositions {x,0}
-%%% . . .
-%%% test bs_get_binary2 {f,...} {x,0} all 1 Flags {x,0}
-%%% . . .
-%%% call_only 2 L1
-%%%
-%%% The sequence can be optimized simply by removing the bs_get_binary2
-%%% instruction. Another example:
-%%%
-%%% func_info ...
-%%% L1 test bs_start_match2 {f,...} {x,0} Live SavePositions {x,0}
-%%% . . .
-%%% test bs_get_binary2 {f,...} {x,0} all 8 Flags {x,1}
-%%% . . .
-%%% move {x,1} {x,0}
-%%% call_only 2 L1
-%%%
-%%% In this case, the bs_get_binary2 instruction must be replaced by
-%%%
-%%% test bs_unit {x,1} 8
-%%%
-%%% to ensure that the match fail if the length of the binary in bits
-%%% is not evenly divisible by 8.
-%%%
-%%% Note that the bs_start_match2 instruction doesn't need to be in the same
-%%% function as the caller. It can be in the beginning of any function, or
-%%% follow the bs_get_binary2 instruction in the same function. The important
-%%% thing is that the match context register is not copied or built into
-%%% data structures or passed to BIFs.
-%%%
-
--type label() :: beam_asm:label().
--type func_info() :: {beam_asm:reg(),boolean()}.
-
--record(btb,
- {f :: gb_trees:tree(label(), func_info()),
- index :: beam_utils:code_index(), %{Label,Code} index (for liveness).
- ok_br=gb_sets:empty() :: gb_sets:set(label()), %Labels that are OK.
- must_not_save=false :: boolean(), %Must not save position when
- % optimizing (reaches
- % bs_context_to_binary).
- must_save=false :: boolean() %Must save position when optimizing.
- }).
-
-
--spec module(beam_utils:module_code(), [compile:option()]) ->
- {'ok',beam_utils:module_code()}.
-
-module({Mod,Exp,Attr,Fs0,Lc}, Opts) ->
- FIndex = btb_index(Fs0),
- Fs = [function(F, FIndex) || F <- Fs0],
- Code = {Mod,Exp,Attr,Fs,Lc},
- case proplists:get_bool(bin_opt_info, Opts) of
- true ->
- {ok,Code,collect_warnings(Fs)};
- false ->
- {ok,Code}
- end.
-
--spec format_error('bin_opt' | {'no_bin_opt', term()}) -> nonempty_string().
-
-format_error(bin_opt) ->
- "OPTIMIZED: creation of sub binary delayed";
-format_error({no_bin_opt,Reason}) ->
- lists:flatten(["NOT OPTIMIZED: "|format_error_1(Reason)]).
-
-%%%
-%%% Local functions.
-%%%
-
-function({function,Name,Arity,Entry,Is}, FIndex) ->
- try
- Index = beam_utils:index_labels(Is),
- D = #btb{f=FIndex,index=Index},
- {function,Name,Arity,Entry,btb_opt_1(Is, D, [])}
- catch
- Class:Error ->
- Stack = erlang:get_stacktrace(),
- io:fwrite("Function: ~w/~w\n", [Name,Arity]),
- erlang:raise(Class, Error, Stack)
- end.
-
-btb_opt_1([{test,bs_get_binary2,F,_,[Reg,{atom,all},U,Fs],Reg}=I0|Is], D, Acc0) ->
- case btb_reaches_match(Is, [Reg], D) of
- {error,Reason} ->
- Comment = btb_comment_no_opt(Reason, Fs),
- btb_opt_1(Is, D, [Comment,I0|Acc0]);
- {ok,MustSave} ->
- Comment = btb_comment_opt(Fs),
- Acc1 = btb_gen_save(MustSave, Reg, [Comment|Acc0]),
- Acc = case U of
- 1 -> Acc1;
- _ -> [{test,bs_test_unit,F,[Reg,U]}|Acc1]
- end,
- btb_opt_1(Is, D, Acc)
- end;
-btb_opt_1([{test,bs_get_binary2,F,_,[Ctx,{atom,all},U,Fs],Dst}=I0|Is], D, Acc0) ->
- case btb_reaches_match(Is, [Ctx,Dst], D) of
- {error,Reason} ->
- Comment = btb_comment_no_opt(Reason, Fs),
- btb_opt_1(Is, D, [Comment,I0|Acc0]);
- {ok,MustSave} when U =:= 1 ->
- Comment = btb_comment_opt(Fs),
- Acc1 = btb_gen_save(MustSave, Ctx, [Comment|Acc0]),
- Acc = [{move,Ctx,Dst}|Acc1],
- btb_opt_1(Is, D, Acc);
- {ok,MustSave} ->
- Comment = btb_comment_opt(Fs),
- Acc1 = btb_gen_save(MustSave, Ctx, [Comment|Acc0]),
- Acc = [{move,Ctx,Dst},{test,bs_test_unit,F,[Ctx,U]}|Acc1],
- btb_opt_1(Is, D, Acc)
- end;
-btb_opt_1([I|Is], D, Acc) ->
- %%io:format("~p\n", [I]),
- btb_opt_1(Is, D, [I|Acc]);
-btb_opt_1([], _, Acc) ->
- reverse(Acc).
-
-btb_gen_save(true, Reg, Acc) ->
- [{bs_save2,Reg,{atom,start}}|Acc];
-btb_gen_save(false, _, Acc) -> Acc.
-
-%% btb_reaches_match([Instruction], [Register], D) ->
-%% {ok,MustSave}|{error,Reason}
-%%
-%% The list of Registers should be a list of registers referencing a
-%% match context. The Register may contain one element if the
-%% bs_get_binary2 instruction looks like
-%%
-%% test bs_get_binary2 {f,...} Ctx all _ _ Ctx
-%%
-%% or two elements if the instruction looks like
-%%
-%% test bs_get_binary2 {f,...} Ctx all _ _ Dst
-%%
-%% This function determines whether the bs_get_binary2 instruction
-%% can be omitted (retaining the match context instead of creating
-%% a sub binary).
-%%
-%% The rule is that the match context ultimately must end up at a
-%% bs_start_match2 instruction and nowhere else. That it, it must not
-%% be passed to BIFs, or copied or put into data structures. There
-%% must only be one copy alive when the match context reaches the
-%% bs_start_match2 instruction.
-%%
-%% At a branch, we must follow all branches and make sure that the above
-%% rule is followed (or that the branch kills the match context).
-%%
-%% The MustSave return value will be true if control may end up at
-%% bs_context_to_binary instruction. Since that instruction uses the
-%% saved start position, we must use "bs_save2 Ctx start" to
-%% update the saved start position. An additional complication is that
-%% "bs_save2 Ctx start" must not be used if Dst and Ctx are
-%% different registers and both registers may be passed to
-%% a bs_context_to_binary instruction.
-%%
-
-btb_reaches_match(Is, RegList, D) ->
- try
- Regs = btb_regs_from_list(RegList),
- #btb{must_not_save=MustNotSave,must_save=MustSave} =
- btb_reaches_match_1(Is, Regs, D),
- case MustNotSave andalso MustSave of
- true -> btb_error(must_and_must_not_save);
- false -> {ok,MustSave}
- end
- catch
- throw:{error,_}=Error -> Error
- end.
-
-btb_reaches_match_1(Is, Regs, D) ->
- case btb_are_registers_empty(Regs) of
- false ->
- btb_reaches_match_2(Is, Regs, D);
- true ->
- %% The context was killed, which is OK.
- D
- end.
-
-btb_reaches_match_2([{block,Bl}|Is], Regs0, D) ->
- Regs = btb_reaches_match_block(Bl, Regs0),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{call,Arity,{f,Lbl}}|Is], Regs0, D) ->
- case is_tail_call(Is) of
- true ->
- Regs1 = btb_kill_not_live(Arity, Regs0),
- Regs = btb_kill_yregs(Regs1),
- btb_tail_call(Lbl, Regs, D);
- false ->
- btb_call(Arity, Lbl, Regs0, Is, D)
- end;
-btb_reaches_match_2([{apply,Arity}|Is], Regs, D) ->
- btb_call(Arity+2, apply, Regs, Is, D);
-btb_reaches_match_2([{call_fun,Live}=I|Is], Regs, D) ->
- btb_ensure_not_used([{x,Live}], I, Regs),
- btb_call(Live, I, Regs, Is, D);
-btb_reaches_match_2([{make_fun2,_,_,_,Live}|Is], Regs, D) ->
- btb_call(Live, make_fun2, Regs, Is, D);
-btb_reaches_match_2([{call_ext,Arity,Func}=I|Is], Regs0, D) ->
- %% Allow us scanning beyond the call in case the match
- %% context is saved on the stack.
- case beam_jump:is_exit_instruction(I) of
- false ->
- btb_call(Arity, Func, Regs0, Is, D);
- true ->
- Regs = btb_kill_not_live(Arity, Regs0),
- btb_tail_call(Func, Regs, D)
- end;
-btb_reaches_match_2([{kill,Y}|Is], Regs, D) ->
- btb_reaches_match_1(Is, btb_kill([Y], Regs), D);
-btb_reaches_match_2([{deallocate,_}|Is], Regs0, D) ->
- Regs = btb_kill_yregs(Regs0),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([return=I|_], Regs0, D) ->
- btb_ensure_not_used([{x,0}], I, Regs0),
- D;
-btb_reaches_match_2([{gc_bif,_,{f,F},Live,Ss,Dst}=I|Is], Regs0, D0) ->
- btb_ensure_not_used(Ss, I, Regs0),
- Regs1 = btb_kill_not_live(Live, Regs0),
- Regs = btb_kill([Dst], Regs1),
- D = btb_follow_branch(F, Regs, D0),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{bif,_,{f,F},Ss,Dst}=I|Is], Regs0, D0) ->
- btb_ensure_not_used(Ss, I, Regs0),
- Regs = btb_kill([Dst], Regs0),
- D = btb_follow_branch(F, Regs, D0),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{get_map_elements,{f,F},Src,{list,Ls}}=I|Is], Regs0, D0) ->
- {Ss,Ds} = beam_utils:split_even(Ls),
- btb_ensure_not_used([Src|Ss], I, Regs0),
- Regs = btb_kill(Ds, Regs0),
- D = btb_follow_branch(F, Regs, D0),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{test,bs_start_match2,{f,F},Live,[Ctx,_],Ctx}=I|Is],
- Regs0, D0) ->
- CtxRegs = btb_context_regs(Regs0),
- case member(Ctx, CtxRegs) of
- false ->
- %% This bs_start_match2 instruction does not use "our"
- %% match state. Therefore we can continue the search
- %% for another bs_start_match2 instruction.
- D = btb_follow_branch(F, Regs0, D0),
- Regs = btb_kill_not_live(Live, Regs0),
- btb_reaches_match_2(Is, Regs, D);
- true ->
- %% OK. This instruction will use "our" match state,
- %% but we must make sure that all other copies of the
- %% match state are killed in the code that follows
- %% the instruction. (We know that the fail branch cannot
- %% be taken in this case.)
- OtherCtxRegs = CtxRegs -- [Ctx],
- case btb_are_all_unused(OtherCtxRegs, Is, D0) of
- false -> btb_error({OtherCtxRegs,not_all_unused_after,I});
- true -> D0
- end
- end;
-btb_reaches_match_2([{test,bs_start_match2,{f,F},Live,[Bin,_],Ctx}|Is],
- Regs0, D0) ->
- CtxRegs = btb_context_regs(Regs0),
- case member(Bin, CtxRegs) orelse member(Ctx, CtxRegs) of
- false ->
- %% This bs_start_match2 does not reference any copy of the
- %% match state. Therefore it can safely be passed on the
- %% way to another (perhaps more suitable) bs_start_match2
- %% instruction.
- D = btb_follow_branch(F, Regs0, D0),
- Regs = btb_kill_not_live(Live, Regs0),
- btb_reaches_match_2(Is, Regs, D);
- true ->
- %% This variant of the bs_start_match2 instruction does
- %% not accept a match state as source.
- btb_error(unsuitable_bs_start_match)
- end;
-btb_reaches_match_2([{test,_,{f,F},Ss}=I|Is], Regs, D0) ->
- btb_ensure_not_used(Ss, I, Regs),
- D = btb_follow_branch(F, Regs, D0),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{test,_,{f,F},_,Ss,_}=I|Is], Regs, D0) ->
- btb_ensure_not_used(Ss, I, Regs),
- D = btb_follow_branch(F, Regs, D0),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{select,_,Src,{f,F},Conds}=I|Is], Regs, D0) ->
- btb_ensure_not_used([Src], I, Regs),
- D1 = btb_follow_branch(F, Regs, D0),
- D = btb_follow_branches(Conds, Regs, D1),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{jump,{f,Lbl}}|_], Regs, #btb{index=Li}=D) ->
- Is = fetch_code_at(Lbl, Li),
- btb_reaches_match_2(Is, Regs, D);
-btb_reaches_match_2([{label,_}|Is], Regs, D) ->
- btb_reaches_match_2(Is, Regs, D);
-btb_reaches_match_2([{bs_init,{f,0},_,_,Ss,Dst}=I|Is], Regs, D) ->
- btb_ensure_not_used(Ss, I, Regs),
- btb_reaches_match_1(Is, btb_kill([Dst], Regs), D);
-btb_reaches_match_2([{bs_put,{f,0},_,Ss}=I|Is], Regs, D) ->
- btb_ensure_not_used(Ss, I, Regs),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{bs_restore2,Src,_}=I|Is], Regs0, D) ->
- case btb_contains_context(Src, Regs0) of
- false ->
- btb_reaches_match_1(Is, Regs0, D);
- true ->
- %% Check that all other copies of the context registers
- %% are unused by the following instructions.
- Regs = btb_kill([Src], Regs0),
- CtxRegs = btb_context_regs(Regs),
- case btb_are_all_unused(CtxRegs, Is, D) of
- false -> btb_error({CtxRegs,not_all_unused_after,I});
- true -> D#btb{must_not_save=true}
- end
- end;
-btb_reaches_match_2([{bs_context_to_binary,Src}=I|Is], Regs0, D) ->
- case btb_contains_context(Src, Regs0) of
- false ->
- btb_reaches_match_1(Is, Regs0, D);
- true ->
- %% Check that all other copies of the context registers
- %% are unused by the following instructions.
- Regs = btb_kill([Src], Regs0),
- CtxRegs = btb_context_regs(Regs),
- case btb_are_all_unused(CtxRegs, Is, D) of
- false -> btb_error({CtxRegs,not_all_unused_after,I});
- true -> D#btb{must_not_save=true}
- end
- end;
-btb_reaches_match_2([{badmatch,Src}=I|_], Regs, D) ->
- btb_ensure_not_used([Src], I, Regs),
- D;
-btb_reaches_match_2([{case_end,Src}=I|_], Regs, D) ->
- btb_ensure_not_used([Src], I, Regs),
- D;
-btb_reaches_match_2([if_end|_], _Regs, D) ->
- D;
-btb_reaches_match_2([{func_info,_,_,Arity}=I|_], Regs0, D) ->
- Regs = btb_kill_yregs(btb_kill_not_live(Arity, Regs0)),
- case btb_context_regs(Regs) of
- [] -> D;
- _ -> {binary_used_in,I}
- end;
-btb_reaches_match_2([{line,_}|Is], Regs, D) ->
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([I|_], Regs, _) ->
- btb_error({btb_context_regs(Regs),I,not_handled}).
-
-is_tail_call([{deallocate,_}|_]) -> true;
-is_tail_call([return|_]) -> true;
-is_tail_call(_) -> false.
-
-btb_call(Arity, Lbl, Regs0, Is, D0) ->
- Regs = btb_kill_not_live(Arity, Regs0),
- case btb_are_x_registers_empty(Regs) of
- false ->
- %% There is a match context in one of the x registers.
- %% First handle the call as if it were a tail call.
- D = btb_tail_call(Lbl, Regs, D0),
-
- %% No problem so far (the called function can handle a
- %% match context). Now we must make sure that we don't
- %% have any copies of the match context tucked away in an
- %% y register.
- RegList = btb_context_regs(Regs),
- case [R || {y,_}=R <- RegList] of
- [] ->
- D;
- [_|_] ->
- btb_error({multiple_uses,RegList})
- end;
- true ->
- %% No match context in any x register. It could have been
- %% saved to an y register, so continue to scan the code following
- %% the call.
- btb_reaches_match_1(Is, Regs, D0)
- end.
-
-btb_tail_call(Lbl, Regs, #btb{f=Ftree,must_save=MustSave0}=D) ->
- %% Ignore any y registers here.
- case [R || {x,_}=R <- btb_context_regs(Regs)] of
- [] ->
- D;
- [{x,_}=Reg] ->
- case gb_trees:lookup(Lbl, Ftree) of
- {value,{Reg,MustSave}} ->
- D#btb{must_save=MustSave0 or MustSave};
- _ when is_integer(Lbl) ->
- btb_error({{label,Lbl},no_suitable_bs_start_match});
- _ ->
- btb_error({binary_used_in,Lbl})
- end;
- [_|_] when not is_integer(Lbl) ->
- btb_error({binary_used_in,Lbl});
- [_|_]=RegList ->
- btb_error({multiple_uses,RegList})
- end.
-
-%% btb_follow_branches([Cond], Regs, D) -> D'
-%% Recursively follow all the branches.
-
-btb_follow_branches([{f,Lbl}|T], Regs, D0) ->
- D = btb_follow_branch(Lbl, Regs, D0),
- btb_follow_branches(T, Regs, D);
-btb_follow_branches([_|T], Regs, D) ->
- btb_follow_branches(T, Regs, D);
-btb_follow_branches([], _, D) -> D.
-
-%% btb_follow_branch(Lbl, Regs, D) -> D'
-%% Recursively follow the branch.
-
-btb_follow_branch(0, _Regs, D) -> D;
-btb_follow_branch(Lbl, Regs, #btb{ok_br=Br0,index=Li}=D) ->
- Key = {Lbl,Regs},
- case gb_sets:is_member(Key, Br0) of
- true ->
- %% We have already followed this branch and it was OK.
- D;
- false ->
- %% New branch. Try it.
- Is = fetch_code_at(Lbl, Li),
- #btb{ok_br=Br,must_not_save=MustNotSave,must_save=MustSave} =
- btb_reaches_match_1(Is, Regs, D),
-
- %% Since we got back, this branch is OK.
- D#btb{ok_br=gb_sets:insert(Key, Br),must_not_save=MustNotSave,
- must_save=MustSave}
- end.
-
-btb_reaches_match_block([{set,Ds,Ss,{alloc,Live,_}}=I|Is], Regs0) ->
- %% An allocation instruction or a GC bif. We'll kill all registers
- %% if any copy of the context is used as the source to the BIF.
- btb_ensure_not_used(Ss, I, Regs0),
- Regs1 = btb_kill_not_live(Live, Regs0),
- Regs = btb_kill(Ds, Regs1),
- btb_reaches_match_block(Is, Regs);
-btb_reaches_match_block([{set,[Dst]=Ds,[Src],move}|Is], Regs0) ->
- Regs1 = btb_kill(Ds, Regs0),
- Regs = case btb_contains_context(Src, Regs1) of
- false -> Regs1;
- true -> btb_set_context(Dst, Regs1)
- end,
- btb_reaches_match_block(Is, Regs);
-btb_reaches_match_block([{set,Ds,Ss,_}=I|Is], Regs0) ->
- btb_ensure_not_used(Ss, I, Regs0),
- Regs = btb_kill(Ds, Regs0),
- btb_reaches_match_block(Is, Regs);
-btb_reaches_match_block([], Regs) ->
- Regs.
-
-%% btb_are_all_killed([Register], [Instruction], D) -> true|false
-%% Test whether all of the register are unused in the instruction stream.
-
-btb_are_all_unused(RegList, Is, #btb{index=Li}) ->
- all(fun(R) ->
- beam_utils:is_not_used(R, Is, Li)
- end, RegList).
-
-%% btp_regs_from_list([Register]) -> RegisterSet.
-%% Create a register set from a list of registers.
-
-btb_regs_from_list(L) ->
- foldl(fun(R, Regs) ->
- btb_set_context(R, Regs)
- end, {0,0}, L).
-
-%% btb_set_context(Register, RegisterSet) -> RegisterSet'
-%% Update RegisterSet to indicate that Register contains the matching context.
-
-btb_set_context({x,N}, {Xregs,Yregs}) ->
- {Xregs bor (1 bsl N),Yregs};
-btb_set_context({y,N}, {Xregs,Yregs}) ->
- {Xregs,Yregs bor (1 bsl N)}.
-
-%% btb_ensure_not_used([Register], Instruction, RegisterSet) -> ok
-%% If any register in RegisterSet (the register(s) known to contain
-%% the match context) is used in the list of registers, generate an error.
-
-btb_ensure_not_used(Rs, I, Regs) ->
- case lists:any(fun(R) -> btb_contains_context(R, Regs) end, Rs) of
- true -> btb_error({binary_used_in,I});
- false -> ok
- end.
-
-%% btb_kill([Register], RegisterSet) -> RegisterSet'
-%% Kill all registers mentioned in the list of registers.
-
-btb_kill([{x,N}|Rs], {Xregs,Yregs}) ->
- btb_kill(Rs, {Xregs band (bnot (1 bsl N)),Yregs});
-btb_kill([{y,N}|Rs], {Xregs,Yregs}) ->
- btb_kill(Rs, {Xregs,Yregs band (bnot (1 bsl N))});
-btb_kill([{fr,_}|Rs], Regs) ->
- btb_kill(Rs, Regs);
-btb_kill([], Regs) -> Regs.
-
-%% btb_kill_not_live(Live, RegisterSet) -> RegisterSet'
-%% Kill all registers indicated not live by Live.
-
-btb_kill_not_live(Live, {Xregs,Yregs}) ->
- {Xregs band ((1 bsl Live)-1),Yregs}.
-
-%% btb_kill(Regs0) -> Regs
-%% Kill all y registers.
-
-btb_kill_yregs({Xregs,_}) -> {Xregs,0}.
-
-%% btb_are_registers_empty(RegisterSet) -> true|false
-%% Test whether the register set is empty.
-
-btb_are_registers_empty({0,0}) -> true;
-btb_are_registers_empty({_,_}) -> false.
-
-%% btb_are_x_registers_empty(Regs) -> true|false
-%% Test whether the x registers are empty.
-
-btb_are_x_registers_empty({0,_}) -> true;
-btb_are_x_registers_empty({_,_}) -> false.
-
-%% btb_contains_context(Register, RegisterSet) -> true|false
-%% Test whether Register contains the context.
-
-btb_contains_context({x,N}, {Regs,_}) -> Regs band (1 bsl N) =/= 0;
-btb_contains_context({y,N}, {_,Regs}) -> Regs band (1 bsl N) =/= 0;
-btb_contains_context(_, _) -> false.
-
-%% btb_context_regs(RegisterSet) -> [Register]
-%% Convert the register set to an explicit list of registers.
-btb_context_regs({Xregs,Yregs}) ->
- btb_context_regs_1(Xregs, 0, x, btb_context_regs_1(Yregs, 0, y, [])).
-
-btb_context_regs_1(0, _, _, Acc) ->
- Acc;
-btb_context_regs_1(Regs, N, Tag, Acc) when (Regs band 1) =:= 1 ->
- btb_context_regs_1(Regs bsr 1, N+1, Tag, [{Tag,N}|Acc]);
-btb_context_regs_1(Regs, N, Tag, Acc) ->
- btb_context_regs_1(Regs bsr 1, N+1, Tag, Acc).
-
-%% btb_index([Function]) -> GbTree({EntryLabel,{Register,MustSave}})
-%% Build an index of functions that accept a match context instead of
-%% a binary. MustSave is true if the function may pass the match
-%% context to the bs_context_to_binary instruction (in which case
-%% the current position in the binary must have saved into the
-%% start position using "bs_save_2 Ctx start").
-
-btb_index(Fs) ->
- btb_index_1(Fs, []).
-
-btb_index_1([{function,_,_,Entry,Is0}|Fs], Acc0) ->
- Is = drop_to_label(Is0, Entry),
- Acc = btb_index_2(Is, Entry, false, Acc0),
- btb_index_1(Fs, Acc);
-btb_index_1([], Acc) -> gb_trees:from_orddict(sort(Acc)).
-
-btb_index_2([{test,bs_start_match2,{f,_},_,[Reg,_],Reg}|_],
- Entry, MustSave, Acc) ->
- [{Entry,{Reg,MustSave}}|Acc];
-btb_index_2(Is0, Entry, _, Acc) ->
- try btb_index_find_start_match(Is0) of
- Is -> btb_index_2(Is, Entry, true, Acc)
- catch
- throw:none -> Acc
- end.
-
-drop_to_label([{label,L}|Is], L) -> Is;
-drop_to_label([_|Is], L) -> drop_to_label(Is, L).
-
-btb_index_find_start_match([{test,_,{f,F},_},{bs_context_to_binary,_}|Is]) ->
- btb_index_find_label(Is, F);
-btb_index_find_start_match(_) ->
- throw(none).
-
-btb_index_find_label([{label,L}|Is], L) -> Is;
-btb_index_find_label([_|Is], L) -> btb_index_find_label(Is, L).
-
-btb_error(Error) ->
- throw({error,Error}).
-
-fetch_code_at(Lbl, Li) ->
- case beam_utils:code_at(Lbl, Li) of
- Is when is_list(Is) -> Is
- end.
-
-%%%
-%%% Compilation information warnings.
-%%%
-
-btb_comment_opt({field_flags,[{anno,A}|_]}) ->
- {'%',{bin_opt,A}};
-btb_comment_opt(_) ->
- {'%',{bin_opt,[]}}.
-
-btb_comment_no_opt(Reason, {field_flags,[{anno,A}|_]}) ->
- {'%',{no_bin_opt,Reason,A}};
-btb_comment_no_opt(Reason, _) ->
- {'%',{no_bin_opt,Reason,[]}}.
-
-collect_warnings(Fs) ->
- D = warning_index_functions(Fs),
- foldl(fun(F, A) -> collect_warnings_fun(F, D, A) end, [], Fs).
-
-collect_warnings_fun({function,_,_,_,Is}, D, A) ->
- collect_warnings_instr(Is, D, A).
-
-collect_warnings_instr([{'%',{bin_opt,Where}}|Is], D, Acc0) ->
- Acc = add_warning(bin_opt, Where, Acc0),
- collect_warnings_instr(Is, D, Acc);
-collect_warnings_instr([{'%',{no_bin_opt,Reason0,Where}}|Is], D, Acc0) ->
- Reason = warning_translate_label(Reason0, D),
- Acc = add_warning({no_bin_opt,Reason}, Where, Acc0),
- collect_warnings_instr(Is, D, Acc);
-collect_warnings_instr([_|Is], D, Acc) ->
- collect_warnings_instr(Is, D, Acc);
-collect_warnings_instr([], _, Acc) -> Acc.
-
-add_warning(Term, Anno, Ws) ->
- Line = get_line(Anno),
- File = get_file(Anno),
- [{File,[{Line,?MODULE,Term}]}|Ws].
-
-warning_translate_label(Term, D) when is_tuple(Term) ->
- case element(1, Term) of
- {label,F} ->
- FA = gb_trees:get(F, D),
- setelement(1, Term, FA);
- _ -> Term
- end;
-warning_translate_label(Term, _) -> Term.
-
-get_line([Line|_]) when is_integer(Line) -> Line;
-get_line([_|T]) -> get_line(T);
-get_line([]) -> none.
-
-get_file([{file,File}|_]) -> File;
-get_file([_|T]) -> get_file(T);
-get_file([]) -> "no_file". % should not happen
-
-warning_index_functions(Fs) ->
- D = [{Entry,{F,A}} || {function,F,A,Entry,_} <- Fs],
- gb_trees:from_orddict(sort(D)).
-
-format_error_1({binary_used_in,{extfunc,M,F,A}}) ->
- [io_lib:format("sub binary used by ~p:~p/~p", [M,F,A])|
- case {M,F,A} of
- {erlang,split_binary,2} ->
- "; SUGGEST using binary matching instead of split_binary/2";
- _ ->
- ""
- end];
-format_error_1({binary_used_in,_}) ->
- "sub binary is used or returned";
-format_error_1({multiple_uses,_}) ->
- "sub binary is matched or used in more than one place";
-format_error_1(unsuitable_bs_start_match) ->
- "the binary matching instruction that follows in the same function "
- "have problems that prevent delayed sub binary optimization "
- "(probably indicated by INFO warnings)";
-format_error_1({{F,A},no_suitable_bs_start_match}) ->
- io_lib:format("called function ~p/~p does not begin with a suitable "
- "binary matching instruction", [F,A]);
-format_error_1(must_and_must_not_save) ->
- "different control paths use different positions in the binary";
-format_error_1({_,I,not_handled}) ->
- case I of
- {'catch',_,_} ->
- "the compiler currently does not attempt the delayed sub binary "
- "optimization when catch is used";
- {'try',_,_} ->
- "the compiler currently does not attempt the delayed sub binary "
- "optimization when try/catch is used";
- _ ->
- io_lib:format("compiler limitation: instruction ~p prevents "
- "delayed sub binary optimization", [I])
- end;
-format_error_1(Term) ->
- io_lib:format("~w", [Term]).
diff --git a/lib/compiler/src/beam_clean.erl b/lib/compiler/src/beam_clean.erl
index b736d39f9c..7299654476 100644
--- a/lib/compiler/src/beam_clean.erl
+++ b/lib/compiler/src/beam_clean.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -22,34 +22,21 @@
-module(beam_clean).
-export([module/2]).
--export([bs_clean_saves/1]).
-export([clean_labels/1]).
--import(lists, [map/2,foldl/3,reverse/1,filter/2]).
-spec module(beam_utils:module_code(), [compile:option()]) ->
{'ok',beam_utils:module_code()}.
module({Mod,Exp,Attr,Fs0,_}, Opts) ->
Order = [Lbl || {function,_,_,Lbl,_} <- Fs0],
- All = foldl(fun({function,_,_,Lbl,_}=Func,D) -> dict:store(Lbl, Func, D) end,
- dict:new(), Fs0),
+ All = maps:from_list([{Lbl,Func} || {function,_,_,Lbl,_}=Func <- Fs0]),
WorkList = rootset(Fs0, Exp, Attr),
- Used = find_all_used(WorkList, All, sets:from_list(WorkList)),
+ Used = find_all_used(WorkList, All, cerl_sets:from_list(WorkList)),
Fs1 = remove_unused(Order, Used, All),
{Fs2,Lc} = clean_labels(Fs1),
- Fs3 = bs_fix(Fs2),
- Fs = maybe_remove_lines(Fs3, Opts),
+ Fs = maybe_remove_lines(Fs2, Opts),
{ok,{Mod,Exp,Attr,Fs,Lc}}.
-%% Remove all bs_save2/2 instructions not referenced by a bs_restore2/2.
-
--spec bs_clean_saves([beam_utils:instruction()]) ->
- [beam_utils:instruction()].
-
-bs_clean_saves(Is) ->
- Needed = bs_restores(Is, []),
- bs_clean_saves_1(Is, gb_sets:from_list(Needed), []).
-
%% Determine the rootset, i.e. exported functions and
%% the on_load function (if any).
@@ -66,16 +53,16 @@ rootset(Fs, Root0, Attr) ->
%% Remove the unused functions.
remove_unused([F|Fs], Used, All) ->
- case sets:is_element(F, Used) of
+ case cerl_sets:is_element(F, Used) of
false -> remove_unused(Fs, Used, All);
- true -> [dict:fetch(F, All)|remove_unused(Fs, Used, All)]
+ true -> [map_get(F, All)|remove_unused(Fs, Used, All)]
end;
remove_unused([], _, _) -> [].
-
+
%% Find all used functions.
find_all_used([F|Fs0], All, Used0) ->
- {function,_,_,_,Code} = dict:fetch(F, All),
+ {function,_,_,_,Code} = map_get(F, All),
{Fs,Used} = update_work_list(Code, {Fs0,Used0}),
find_all_used(Fs, All, Used);
find_all_used([], _All, Used) -> Used.
@@ -89,20 +76,16 @@ update_work_list([_|Is], Sets) ->
update_work_list([], Sets) -> Sets.
add_to_work_list(F, {Fs,Used}=Sets) ->
- case sets:is_element(F, Used) of
+ case cerl_sets:is_element(F, Used) of
true -> Sets;
- false -> {[F|Fs],sets:add_element(F, Used)}
+ false -> {[F|Fs],cerl_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.
-%%%
-%%% We also expand is_record/3 to a sequence of instructions. It is done
-%%% here merely because this module will always be called even if optimization
-%%% is turned off. We don't want to do the expansion in beam_asm because we
-%%% want to see the expanded code in a .S file.
+%%% This cleanup will slightly reduce file size and slightly speed up
+%%% loading.
%%%
-type label() :: beam_asm:label().
@@ -118,7 +101,7 @@ add_to_work_list(F, {Fs,Used}=Sets) ->
clean_labels(Fs0) ->
St0 = #st{lmap=[],entry=1,lc=1},
{Fs1,#st{lmap=Lmap0,lc=Lc}} = function_renumber(Fs0, St0, []),
- Lmap = gb_trees:from_orddict(ordsets:from_list(Lmap0)),
+ Lmap = maps:from_list(Lmap0),
Fs = function_replace(Fs1, Lmap, []),
{Fs,Lc}.
@@ -127,45 +110,6 @@ function_renumber([{function,Name,Arity,_Entry,Asm0}|Fs], St0, Acc) ->
function_renumber(Fs, St, [{function,Name,Arity,St#st.entry,Asm}|Acc]);
function_renumber([], St, Acc) -> {Acc,St}.
-renumber_labels([{bif,is_record,{f,_},
- [Term,{atom,Tag}=TagAtom,{integer,Arity}],Dst}|Is0], Acc, St) ->
- ContLabel = 900000000+2*St#st.lc,
- FailLabel = ContLabel+1,
- Fail = {f,FailLabel},
- Tmp = Dst,
- Is = case is_record_tuple(Term, Tag, Arity) of
- yes ->
- [{move,{atom,true},Dst}|Is0];
- no ->
- [{move,{atom,false},Dst}|Is0];
- maybe ->
- [{test,is_tuple,Fail,[Term]},
- {test,test_arity,Fail,[Term,Arity]},
- {get_tuple_element,Term,0,Tmp},
- {test,is_eq_exact,Fail,[Tmp,TagAtom]},
- {move,{atom,true},Dst},
- {jump,{f,ContLabel}},
- {label,FailLabel},
- {move,{atom,false},Dst},
- {jump,{f,ContLabel}}, %Improves optimization by beam_dead.
- {label,ContLabel}|Is0]
- end,
- renumber_labels(Is, Acc, St);
-renumber_labels([{test,is_record,{f,_}=Fail,
- [Term,{atom,Tag}=TagAtom,{integer,Arity}]}|Is0], Acc, St) ->
- Tmp = {x,1022},
- Is = case is_record_tuple(Term, Tag, Arity) of
- yes ->
- Is0;
- no ->
- [{jump,Fail}|Is0];
- maybe ->
- [{test,is_tuple,Fail,[Term]},
- {test,test_arity,Fail,[Term,Arity]},
- {get_tuple_element,Term,0,Tmp},
- {test,is_eq_exact,Fail,[Tmp,TagAtom]}|Is0]
- end,
- renumber_labels(Is, Acc, St);
renumber_labels([{label,Old}|Is], [{label,New}|_]=Acc, #st{lmap=D0}=St) ->
D = [{Old,New}|D0],
renumber_labels(Is, Acc, St#st{lmap=D});
@@ -179,15 +123,10 @@ renumber_labels([I|Is], Acc, St0) ->
renumber_labels(Is, [I|Acc], St0);
renumber_labels([], Acc, St) -> {Acc,St}.
-is_record_tuple({x,_}, _, _) -> maybe;
-is_record_tuple({y,_}, _, _) -> maybe;
-is_record_tuple({literal,Tuple}, Tag, Arity)
- when element(1, Tuple) =:= Tag, tuple_size(Tuple) =:= Arity -> yes;
-is_record_tuple(_, _, _) -> no.
-
function_replace([{function,Name,Arity,Entry,Asm0}|Fs], Dict, Acc) ->
Asm = try
- replace(Asm0, [], Dict)
+ Fb = fun(Old) -> throw({error,{undefined_label,Old}}) end,
+ beam_utils:replace_labels(Asm0, [], Dict, Fb)
catch
throw:{error,{undefined_label,Lbl}=Reason} ->
io:format("Function ~s/~w refers to undefined label ~w\n",
@@ -197,151 +136,6 @@ function_replace([{function,Name,Arity,Entry,Asm0}|Fs], Dict, Acc) ->
function_replace(Fs, Dict, [{function,Name,Arity,Entry,Asm}|Acc]);
function_replace([], _, Acc) -> Acc.
-replace([{test,Test,{f,Lbl},Ops}|Is], Acc, D) ->
- replace(Is, [{test,Test,{f,label(Lbl, D)},Ops}|Acc], D);
-replace([{test,Test,{f,Lbl},Live,Ops,Dst}|Is], Acc, D) ->
- replace(Is, [{test,Test,{f,label(Lbl, D)},Live,Ops,Dst}|Acc], D);
-replace([{select,I,R,{f,Fail0},Vls0}|Is], Acc, D) ->
- Vls = map(fun ({f,L}) -> {f,label(L, D)};
- (Other) -> Other
- end, Vls0),
- Fail = label(Fail0, D),
- replace(Is, [{select,I,R,{f,Fail},Vls}|Acc], D);
-replace([{'try',R,{f,Lbl}}|Is], Acc, D) ->
- replace(Is, [{'try',R,{f,label(Lbl, D)}}|Acc], D);
-replace([{'catch',R,{f,Lbl}}|Is], Acc, D) ->
- replace(Is, [{'catch',R,{f,label(Lbl, D)}}|Acc], D);
-replace([{jump,{f,Lbl}}|Is], Acc, D) ->
- replace(Is, [{jump,{f,label(Lbl, D)}}|Acc], D);
-replace([{loop_rec,{f,Lbl},R}|Is], Acc, D) ->
- replace(Is, [{loop_rec,{f,label(Lbl, D)},R}|Acc], D);
-replace([{loop_rec_end,{f,Lbl}}|Is], Acc, D) ->
- replace(Is, [{loop_rec_end,{f,label(Lbl, D)}}|Acc], D);
-replace([{wait,{f,Lbl}}|Is], Acc, D) ->
- replace(Is, [{wait,{f,label(Lbl, D)}}|Acc], D);
-replace([{wait_timeout,{f,Lbl},To}|Is], Acc, D) ->
- replace(Is, [{wait_timeout,{f,label(Lbl, D)},To}|Acc], D);
-replace([{bif,Name,{f,Lbl},As,R}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{bif,Name,{f,label(Lbl, D)},As,R}|Acc], D);
-replace([{gc_bif,Name,{f,Lbl},Live,As,R}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{gc_bif,Name,{f,label(Lbl, D)},Live,As,R}|Acc], D);
-replace([{call,Ar,{f,Lbl}}|Is], Acc, D) ->
- replace(Is, [{call,Ar,{f,label(Lbl,D)}}|Acc], D);
-replace([{make_fun2,{f,Lbl},U1,U2,U3}|Is], Acc, D) ->
- replace(Is, [{make_fun2,{f,label(Lbl, D)},U1,U2,U3}|Acc], D);
-replace([{bs_init,{f,Lbl},Info,Live,Ss,Dst}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{bs_init,{f,label(Lbl, D)},Info,Live,Ss,Dst}|Acc], D);
-replace([{bs_put,{f,Lbl},Info,Ss}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{bs_put,{f,label(Lbl, D)},Info,Ss}|Acc], D);
-replace([{put_map=I,{f,Lbl},Op,Src,Dst,Live,List}|Is], Acc, D)
- when Lbl =/= 0 ->
- replace(Is, [{I,{f,label(Lbl, D)},Op,Src,Dst,Live,List}|Acc], D);
-replace([{get_map_elements=I,{f,Lbl},Src,List}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{I,{f,label(Lbl, D)},Src,List}|Acc], D);
-replace([I|Is], Acc, D) ->
- replace(Is, [I|Acc], D);
-replace([], Acc, _) -> Acc.
-
-label(Old, D) ->
- case gb_trees:lookup(Old, D) of
- {value,Val} -> Val;
- none -> throw({error,{undefined_label,Old}})
- end.
-
-%%%
-%%% Final fixup of bs_start_match2/5,bs_save2/bs_restore2 instructions for
-%%% new bit syntax matching (introduced in R11B).
-%%%
-%%% Pass 1: Scan the code, looking for bs_restore2/2 instructions.
-%%%
-%%% Pass 2: Update bs_save2/2 and bs_restore/2 instructions. Remove
-%%% any bs_save2/2 instruction whose save position are never referenced
-%%% by any bs_restore2/2 instruction.
-%%%
-%%% Note this module can be invoked several times, so we must be careful
-%%% not to touch instructions that have already been fixed up.
-%%%
-
-bs_fix(Fs) ->
- bs_fix(Fs, []).
-
-bs_fix([{function,Name,Arity,Entry,Asm0}|Fs], Acc) ->
- Asm = bs_function(Asm0),
- bs_fix(Fs, [{function,Name,Arity,Entry,Asm}|Acc]);
-bs_fix([], Acc) -> reverse(Acc).
-
-bs_function(Is) ->
- Dict0 = bs_restores(Is, []),
- S0 = sofs:relation(Dict0, [{context,save_point}]),
- S1 = sofs:relation_to_family(S0),
- S = sofs:to_external(S1),
- Dict = make_save_point_dict(S, []),
- bs_replace(Is, Dict, []).
-
-make_save_point_dict([{Ctx,Pts}|T], Acc0) ->
- Acc = make_save_point_dict_1(Pts, Ctx, 0, Acc0),
- make_save_point_dict(T, Acc);
-make_save_point_dict([], Acc) ->
- gb_trees:from_orddict(ordsets:from_list(Acc)).
-
-make_save_point_dict_1([H|T], Ctx, I, Acc) ->
- make_save_point_dict_1(T, Ctx, I+1, [{{Ctx,H},I}|Acc]);
-make_save_point_dict_1([], Ctx, I, Acc) ->
- [{Ctx,I}|Acc].
-
-%% Pass 1.
-bs_restores([{bs_restore2,_,{Same,Same}}|Is], Dict) ->
- %% This save point is special. No explicit save is needed.
- bs_restores(Is, Dict);
-bs_restores([{bs_restore2,_,{atom,start}}|Is], Dict) ->
- %% This instruction can occur if "compilation"
- %% started from a .S file.
- bs_restores(Is, Dict);
-bs_restores([{bs_restore2,_,{_,_}=SavePoint}|Is], Dict) ->
- bs_restores(Is, [SavePoint|Dict]);
-bs_restores([_|Is], Dict) ->
- bs_restores(Is, Dict);
-bs_restores([], Dict) -> Dict.
-
-%% Pass 2.
-bs_replace([{test,bs_start_match2,F,Live,[Src,Ctx],CtxR}|T], Dict, Acc) when is_atom(Ctx) ->
- Slots = case gb_trees:lookup(Ctx, Dict) of
- {value,Slots0} -> Slots0;
- none -> 0
- end,
- I = {test,bs_start_match2,F,Live,[Src,Slots],CtxR},
- bs_replace(T, Dict, [I|Acc]);
-bs_replace([{bs_save2,CtxR,{_,_}=SavePoint}|T], Dict, Acc) ->
- case gb_trees:lookup(SavePoint, Dict) of
- {value,N} ->
- bs_replace(T, Dict, [{bs_save2,CtxR,N}|Acc]);
- none ->
- bs_replace(T, Dict, Acc)
- end;
-bs_replace([{bs_restore2,_,{atom,start}}=I|T], Dict, Acc) ->
- %% This instruction can occur if "compilation"
- %% started from a .S file.
- bs_replace(T, Dict, [I|Acc]);
-bs_replace([{bs_restore2,CtxR,{Same,Same}}|T], Dict, Acc) ->
- %% This save point refers to the point in the binary where the match
- %% started. It has a special name.
- bs_replace(T, Dict, [{bs_restore2,CtxR,{atom,start}}|Acc]);
-bs_replace([{bs_restore2,CtxR,{_,_}=SavePoint}|T], Dict, Acc) ->
- N = gb_trees:get(SavePoint, Dict),
- bs_replace(T, Dict, [{bs_restore2,CtxR,N}|Acc]);
-bs_replace([I|Is], Dict, Acc) ->
- bs_replace(Is, Dict, [I|Acc]);
-bs_replace([], _, Acc) -> reverse(Acc).
-
-bs_clean_saves_1([{bs_save2,_,{_,_}=SavePoint}=I|Is], Needed, Acc) ->
- case gb_sets:is_member(SavePoint, Needed) of
- false -> bs_clean_saves_1(Is, Needed, Acc);
- true -> bs_clean_saves_1(Is, Needed, [I|Acc])
- end;
-bs_clean_saves_1([I|Is], Needed, Acc) ->
- bs_clean_saves_1(Is, Needed, [I|Acc]);
-bs_clean_saves_1([], _, Acc) -> reverse(Acc).
-
%%%
%%% Remove line instructions if requested.
%%%
@@ -353,8 +147,21 @@ maybe_remove_lines(Fs, Opts) ->
end.
remove_lines([{function,N,A,Lbl,Is0}|T]) ->
- Is = filter(fun({line,_}) -> false;
- (_) -> true
- end, Is0),
+ Is = remove_lines_fun(Is0),
[{function,N,A,Lbl,Is}|remove_lines(T)];
remove_lines([]) -> [].
+
+remove_lines_fun([{line,_}|Is]) ->
+ remove_lines_fun(Is);
+remove_lines_fun([{block,Bl0}|Is]) ->
+ Bl = remove_lines_block(Bl0),
+ [{block,Bl}|remove_lines_fun(Is)];
+remove_lines_fun([I|Is]) ->
+ [I|remove_lines_fun(Is)];
+remove_lines_fun([]) -> [].
+
+remove_lines_block([{set,_,_,{line,_}}|Is]) ->
+ remove_lines_block(Is);
+remove_lines_block([I|Is]) ->
+ [I|remove_lines_block(Is)];
+remove_lines_block([]) -> [].
diff --git a/lib/compiler/src/beam_dead.erl b/lib/compiler/src/beam_dead.erl
deleted file mode 100644
index d379fdc4eb..0000000000
--- a/lib/compiler/src/beam_dead.erl
+++ /dev/null
@@ -1,927 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
--module(beam_dead).
-
--export([module/2]).
-
-%%% Dead code is code that is executed but has no effect. This
-%%% optimization pass either removes dead code or jumps around it,
-%%% potentially making it unreachable and a target for the
-%%% the beam_jump pass.
-
--import(lists, [mapfoldl/3,reverse/1]).
-
-
--spec module(beam_utils:module_code(), [compile:option()]) ->
- {'ok',beam_utils:module_code()}.
-
-module({Mod,Exp,Attr,Fs0,_}, _Opts) ->
- {Fs1,Lc1} = beam_clean:clean_labels(Fs0),
- {Fs,Lc} = mapfoldl(fun function/2, Lc1, Fs1),
- %%{Fs,Lc} = {Fs1,Lc1},
- {ok,{Mod,Exp,Attr,Fs,Lc}}.
-
-function({function,Name,Arity,CLabel,Is0}, Lc0) ->
- try
- Is1 = beam_jump:remove_unused_labels(Is0),
-
- %% Initialize label information with the code
- %% for the func_info label. Without it, a register
- %% may seem to be live when it is not.
- [{label,L}|FiIs] = Is1,
- D0 = beam_utils:empty_label_index(),
- D = beam_utils:index_label(L, FiIs, D0),
-
- %% Optimize away dead code.
- {Is2,Lc} = forward(Is1, Lc0),
- Is3 = backward(Is2, D),
- Is = move_move_into_block(Is3, []),
- {{function,Name,Arity,CLabel,Is},Lc}
- catch
- Class:Error ->
- Stack = erlang:get_stacktrace(),
- io:fwrite("Function: ~w/~w\n", [Name,Arity]),
- erlang:raise(Class, Error, Stack)
- end.
-
-%% 'move' instructions outside of blocks may thwart the jump optimizer.
-%% Move them back into the block.
-
-move_move_into_block([{block,Bl0},{move,S,D}|Is], Acc) ->
- Bl = Bl0 ++ [{set,[D],[S],move}],
- move_move_into_block([{block,Bl}|Is], Acc);
-move_move_into_block([{move,S,D}|Is], Acc) ->
- Bl = [{set,[D],[S],move}],
- move_move_into_block([{block,Bl}|Is], Acc);
-move_move_into_block([I|Is], Acc) ->
- move_move_into_block(Is, [I|Acc]);
-move_move_into_block([], Acc) -> reverse(Acc).
-
-%%%
-%%% Scan instructions in execution order and remove redundant 'move'
-%%% instructions. 'move' instructions are redundant if we know that
-%%% the register already contains the value being assigned, as in the
-%%% following code:
-%%%
-%%% test is_eq_exact SomeLabel Src Dst
-%%% move Src Dst
-%%%
-%%% or in:
-%%%
-%%% test is_nil SomeLabel Dst
-%%% move nil Dst
-%%%
-%%% or in:
-%%%
-%%% select_val Register FailLabel [... Literal => L1...]
-%%% .
-%%% .
-%%% .
-%%% L1: move Literal Register
-%%%
-%%% Also add extra labels to help the second backward pass.
-%%%
-
-forward(Is, Lc) ->
- forward(Is, #{}, Lc, []).
-
-forward([{move,_,_}=Move|[{label,L}|_]=Is], D, Lc, Acc) ->
- %% move/2 followed by jump/1 is optimized by backward/3.
- forward([Move,{jump,{f,L}}|Is], D, Lc, Acc);
-forward([{bif,_,_,_,_}=Bif|[{label,L}|_]=Is], D, Lc, Acc) ->
- %% bif/4 followed by jump/1 is optimized by backward/3.
- forward([Bif,{jump,{f,L}}|Is], D, Lc, Acc);
-forward([{block,[]}|Is], D, Lc, Acc) ->
- %% Empty blocks can prevent optimizations.
- forward(Is, D, Lc, Acc);
-forward([{select,select_val,Reg,_,List}=I|Is], D0, Lc, Acc) ->
- D = update_value_dict(List, Reg, D0),
- forward(Is, D, Lc, [I|Acc]);
-forward([{label,Lbl}=LblI,{block,[{set,[Dst],[Lit],move}|BlkIs]}=Blk|Is], D, Lc, Acc) ->
- %% Assumption: The target labels in a select_val/3 instruction
- %% cannot be reached in any other way than through the select_val/3
- %% instruction (i.e. there can be no fallthrough to such label and
- %% it cannot be referenced by, for example, a jump/1 instruction).
- Key = {Lbl,Dst},
- Block = case D of
- #{Key := Lit} -> {block,BlkIs}; %Safe to remove move instruction.
- _ -> Blk %Must keep move instruction.
- end,
- forward([Block|Is], D, Lc, [LblI|Acc]);
-forward([{label,Lbl}=LblI|[{move,Lit,Dst}|Is1]=Is0], D, Lc, Acc) ->
- %% Assumption: The target labels in a select_val/3 instruction
- %% cannot be reached in any other way than through the select_val/3
- %% instruction (i.e. there can be no fallthrough to such label and
- %% it cannot be referenced by, for example, a jump/1 instruction).
- Is = case maps:find({Lbl,Dst}, D) of
- {ok,Lit} -> Is1; %Safe to remove move instruction.
- _ -> Is0 %Keep move instruction.
- end,
- forward(Is, D, Lc, [LblI|Acc]);
-forward([{test,is_eq_exact,_,[Same,Same]}|Is], D, Lc, Acc) ->
- forward(Is, D, Lc, Acc);
-forward([{test,is_eq_exact,_,[Dst,Src]}=I,
- {block,[{set,[Dst],[Src],move}|Bl]}|Is], D, Lc, Acc) ->
- forward([I,{block,Bl}|Is], D, Lc, Acc);
-forward([{test,is_nil,_,[Dst]}=I,
- {block,[{set,[Dst],[nil],move}|Bl]}|Is], D, Lc, Acc) ->
- forward([I,{block,Bl}|Is], D, Lc, Acc);
-forward([{test,is_eq_exact,_,[Dst,Src]}=I,{move,Src,Dst}|Is], D, Lc, Acc) ->
- forward([I|Is], D, Lc, Acc);
-forward([{test,is_nil,_,[Dst]}=I,{move,nil,Dst}|Is], D, Lc, Acc) ->
- forward([I|Is], D, Lc, Acc);
-forward([{test,_,_,_}=I|Is]=Is0, D, Lc, Acc) ->
- %% Help the second, backward pass to by inserting labels after
- %% relational operators so that they can be skipped if they are
- %% known to be true.
- case useful_to_insert_label(Is0) of
- false -> forward(Is, D, Lc, [I|Acc]);
- true -> forward(Is, D, Lc+1, [{label,Lc},I|Acc])
- end;
-forward([I|Is], D, Lc, Acc) ->
- forward(Is, D, Lc, [I|Acc]);
-forward([], _, Lc, Acc) -> {Acc,Lc}.
-
-update_value_dict([Lit,{f,Lbl}|T], Reg, D0) ->
- Key = {Lbl,Reg},
- D = case D0 of
- #{Key := inconsistent} -> D0;
- #{Key := _} -> D0#{Key := inconsistent};
- _ -> D0#{Key => Lit}
- end,
- update_value_dict(T, Reg, D);
-update_value_dict([], _, D) -> D.
-
-useful_to_insert_label([_,{label,_}|_]) ->
- false;
-useful_to_insert_label([{test,Op,_,_}|_]) ->
- case Op of
- is_lt -> true;
- is_ge -> true;
- is_eq_exact -> true;
- is_ne_exact -> true;
- _ -> false
- end.
-
-%%%
-%%% Scan instructions in reverse execution order and try to
-%%% shortcut branch instructions.
-%%%
-%%% For example, in this code:
-%%%
-%%% move Literal Register
-%%% jump L1
-%%% .
-%%% .
-%%% .
-%%% L1: test is_{integer,atom} FailLabel Register
-%%% select_val {x,0} FailLabel [... Literal => L2...]
-%%% .
-%%% .
-%%% .
-%%% L2: ...
-%%%
-%%% the 'selectval' instruction will always transfer control to L2,
-%%% so we can just as well jump to L2 directly by rewriting the
-%%% first part of the sequence like this:
-%%%
-%%% move Literal Register
-%%% jump L2
-%%%
-%%% If register Register is killed at label L2, we can remove the
-%%% 'move' instruction, leaving just the 'jump' instruction:
-%%%
-%%% jump L2
-%%%
-%%% These transformations may leave parts of the code unreachable.
-%%% The beam_jump pass will remove the unreachable code.
-
-backward(Is, D) ->
- backward(Is, D, []).
-
-backward([{test,is_eq_exact,Fail,[Dst,{integer,Arity}]}=I|
- [{bif,tuple_size,Fail,[Reg],Dst}|Is]=Is0], D, Acc) ->
- %% Provided that Dst is killed following this sequence,
- %% we can rewrite the instructions like this:
- %%
- %% bif tuple_size Fail Reg Dst ==> is_tuple Fail Reg
- %% is_eq_exact Fail Dst Integer test_arity Fail Reg Integer
- %%
- %% (still two instructions, but they they will be combined to
- %% one by the loader).
- case beam_utils:is_killed(Dst, Acc, D) andalso (Arity bsr 32) =:= 0 of
- false ->
- %% Not safe because the register Dst is not killed
- %% (probably cannot not happen in practice) or the arity
- %% does not fit in 32 bits (the loader will fail to load
- %% the module). We must move the first instruction to the
- %% accumulator to avoid an infinite loop.
- backward(Is0, D, [I|Acc]);
- true ->
- %% Safe.
- backward([{test,test_arity,Fail,[Reg,Arity]},
- {test,is_tuple,Fail,[Reg]}|Is], D, Acc)
- end;
-backward([{label,Lbl}=L|Is], D, Acc) ->
- backward(Is, beam_utils:index_label(Lbl, Acc, D), [L|Acc]);
-backward([{select,select_val,Reg,{f,Fail0},List0}|Is], D, Acc) ->
- List1 = shortcut_select_list(List0, Reg, D, []),
- Fail1 = shortcut_label(Fail0, D),
- Fail = shortcut_bs_test(Fail1, Is, D),
- List = prune_redundant(List1, Fail),
- case List of
- [] ->
- Jump = {jump,{f,Fail}},
- backward([Jump|Is], D, Acc);
- [V,F] ->
- Test = {test,is_eq_exact,{f,Fail},[Reg,V]},
- Jump = {jump,F},
- backward([Jump,Test|Is], D, Acc);
- [{atom,B1},F,{atom,B2},F] when B1 =:= not B2 ->
- Test = {test,is_boolean,{f,Fail},[Reg]},
- Jump = {jump,F},
- backward([Jump,Test|Is], D, Acc);
- [_|_] ->
- Sel = {select,select_val,Reg,{f,Fail},List},
- backward(Is, D, [Sel|Acc])
- end;
-backward([{jump,{f,To0}},{move,Src,Reg}=Move|Is], D, Acc) ->
- To = shortcut_select_label(To0, Reg, Src, D),
- Jump = {jump,{f,To}},
- case is_killed_at(Reg, To, D) of
- false -> backward([Move|Is], D, [Jump|Acc]);
- true -> backward([Jump|Is], D, Acc)
- end;
-backward([{jump,{f,To}}=J|[{bif,Op,{f,BifFail},Ops,Reg}|Is]=Is0], D, Acc) ->
- try replace_comp_op(To, Reg, Op, Ops, D) of
- I -> backward(Is, D, I++Acc)
- catch
- throw:not_possible ->
- case To =:= BifFail of
- true ->
- %% The bif instruction is redundant. See the comment
- %% in the next clause for why there is no need to
- %% test for liveness of Reg at label To.
- backward([J|Is], D, Acc);
- false ->
- backward(Is0, D, [J|Acc])
- end
- end;
-backward([{jump,{f,To}}=J|[{gc_bif,_,{f,To},_,_,_Dst}|Is]], D, Acc) ->
- %% The gc_bif instruction is redundant, since either the gc_bif
- %% instruction itself or the jump instruction will transfer control
- %% to label To. Note that a gc_bif instruction does not assign its
- %% destination register if the failure branch is taken; therefore,
- %% the code at label To is not allowed to assume that the destination
- %% register is initialized, and it is therefore no need to test
- %% for liveness of the destination register at label To.
- backward([J|Is], D, Acc);
-backward([{test,bs_start_match2,F,Live,[R,_]=Args,Ctxt}|Is], D,
- [{test,bs_match_string,F,[Ctxt,Bs]},
- {test,bs_test_tail2,F,[Ctxt,0]}|Acc0]=Acc) ->
- {f,To0} = F,
- case beam_utils:is_killed(Ctxt, Acc0, D) of
- true ->
- To = shortcut_bs_context_to_binary(To0, R, D),
- Eq = {test,is_eq_exact,{f,To},[R,{literal,Bs}]},
- backward(Is, D, [Eq|Acc0]);
- false ->
- To = shortcut_bs_start_match(To0, R, D),
- I = {test,bs_start_match2,{f,To},Live,Args,Ctxt},
- backward(Is, D, [I|Acc])
- end;
-backward([{test,bs_start_match2,{f,To0},Live,[Src|_]=Info,Dst}|Is], D, Acc) ->
- To = shortcut_bs_start_match(To0, Src, D),
- I = {test,bs_start_match2,{f,To},Live,Info,Dst},
- backward(Is, D, [I|Acc]);
-backward([{test,Op,{f,To0},Ops0}|Is], D, Acc) ->
- To1 = shortcut_bs_test(To0, Is, D),
- To2 = shortcut_label(To1, D),
- To3 = shortcut_rel_op(To2, Op, Ops0, D),
-
- %% Try to shortcut a repeated test:
- %%
- %% test Op {f,Fail1} Operands test Op {f,Fail2} Operands
- %% . . . ==> ...
- %% Fail1: test Op {f,Fail2} Operands Fail1: test Op {f,Fail2} Operands
- %%
- To = case beam_utils:code_at(To3, D) of
- [{test,Op,{f,To4},Ops}|_] ->
- case equal_ops(Ops0, Ops) of
- true -> To4;
- false -> To3
- end;
- _Code ->
- To3
- end,
- I = case Op of
- is_eq_exact -> combine_eqs(To, Ops0, D, Acc);
- _ -> {test,Op,{f,To},Ops0}
- end,
- case {I,Acc} of
- {{test,is_atom,Fail,Ops0},[{test,is_boolean,Fail,Ops0}|_]} ->
- %% An is_atom test before an is_boolean test (with the
- %% same failure label) is redundant.
- backward(Is, D, Acc);
- {{test,is_atom,Fail,[R]},
- [{test,is_eq_exact,Fail,[R,{atom,_}]}|_]} ->
- %% An is_atom test before a comparison with an atom (with
- %% the same failure label) is redundant.
- backward(Is, D, Acc);
- {{test,is_integer,Fail,[R]},
- [{test,is_eq_exact,Fail,[R,{integer,_}]}|_]} ->
- %% An is_integer test before a comparison with an integer
- %% (with the same failure label) is redundant.
- backward(Is, D, Acc);
- {{test,_,_,_},_} ->
- %% Still a test instruction. Done.
- backward(Is, D, [I|Acc]);
- {_,_} ->
- %% Rewritten to a select_val. Rescan.
- backward([I|Is], D, Acc)
- end;
-backward([{test,Op,{f,To0},Live,Ops0,Dst}|Is], D, Acc) ->
- To1 = shortcut_bs_test(To0, Is, D),
- To2 = shortcut_label(To1, D),
- %% Try to shortcut a repeated test:
- %%
- %% test Op {f,Fail1} _ Ops _ test Op {f,Fail2} _ Ops _
- %% . . . ==> ...
- %% Fail1: test Op {f,Fail2} _ Ops _ Fail1: test Op {f,Fail2} _ Ops _
- %%
- To = case beam_utils:code_at(To2, D) of
- [{test,Op,{f,To3},_,Ops,_}|_] ->
- case equal_ops(Ops0, Ops) of
- true -> To3;
- false -> To2
- end;
- _Code ->
- To2
- end,
- I = {test,Op,{f,To},Live,Ops0,Dst},
- backward(Is, D, [I|Acc]);
-backward([{kill,_}=I|Is], D, [{line,_},Exit|_]=Acc) ->
- case beam_jump:is_exit_instruction(Exit) of
- false -> backward(Is, D, [I|Acc]);
- true -> backward(Is, D, Acc)
- end;
-backward([{bif,'or',{f,To0},[Dst,{atom,false}],Dst}=I|Is], D,
- [{test,is_eq_exact,{f,To},[Dst,{atom,true}]}|_]=Acc) ->
- case shortcut_label(To0, D) of
- To ->
- backward(Is, D, Acc);
- _ ->
- backward(Is, D, [I|Acc])
- end;
-backward([I|Is], D, Acc) ->
- backward(Is, D, [I|Acc]);
-backward([], _D, Acc) -> Acc.
-
-equal_ops([{field_flags,FlA0}|T0], [{field_flags,FlB0}|T1]) ->
- FlA = lists:keydelete(anno, 1, FlA0),
- FlB = lists:keydelete(anno, 1, FlB0),
- FlA =:= FlB andalso equal_ops(T0, T1);
-equal_ops([Op|T0], [Op|T1]) ->
- equal_ops(T0, T1);
-equal_ops([], []) -> true;
-equal_ops(_, _) -> false.
-
-shortcut_select_list([Lit,{f,To0}|T], Reg, D, Acc) ->
- To = shortcut_select_label(To0, Reg, Lit, D),
- shortcut_select_list(T, Reg, D, [{f,To},Lit|Acc]);
-shortcut_select_list([], _, _, Acc) -> reverse(Acc).
-
-shortcut_label(0, _) ->
- 0;
-shortcut_label(To0, D) ->
- case beam_utils:code_at(To0, D) of
- [{jump,{f,To}}|_] -> shortcut_label(To, D);
- _ -> To0
- end.
-
-shortcut_select_label(To, Reg, Lit, D) ->
- shortcut_rel_op(To, is_ne_exact, [Reg,Lit], D).
-
-prune_redundant([_,{f,Fail}|T], Fail) ->
- prune_redundant(T, Fail);
-prune_redundant([V,F|T], Fail) ->
- [V,F|prune_redundant(T, Fail)];
-prune_redundant([], _) -> [].
-
-%% Replace a comparison operator with a test instruction and a jump.
-%% For example, if we have this code:
-%%
-%% bif '=:=' Fail Src1 Src2 {x,0}
-%% jump L1
-%% .
-%% .
-%% .
-%% L1: select_val {x,0} FailLabel [... true => L2..., ...false => L3...]
-%%
-%% the first two instructions can be replaced with
-%%
-%% test is_eq_exact L3 Src1 Src2
-%% jump L2
-%%
-%% provided that {x,0} is killed at both L2 and L3.
-
-replace_comp_op(To, Reg, Op, Ops, D) ->
- False = comp_op_find_shortcut(To, Reg, {atom,false}, D),
- True = comp_op_find_shortcut(To, Reg, {atom,true}, D),
- [bif_to_test(Op, Ops, False),{jump,{f,True}}].
-
-comp_op_find_shortcut(To0, Reg, Val, D) ->
- case shortcut_select_label(To0, Reg, Val, D) of
- To0 ->
- not_possible();
- To ->
- case is_killed_at(Reg, To, D) of
- false -> not_possible();
- true -> To
- end
- end.
-
-bif_to_test(Name, Args, Fail) ->
- try
- beam_utils:bif_to_test(Name, Args, {f,Fail})
- catch
- error:_ -> not_possible()
- end.
-
-not_possible() -> throw(not_possible).
-
-%% combine_eqs(To, Operands, Acc) -> Instruction.
-%% Combine two is_eq_exact instructions or (an is_eq_exact
-%% instruction and a select_val instruction) to a select_val
-%% instruction if possible.
-%%
-%% Example:
-%%
-%% is_eq_exact F1 Reg Lit1 select_val Reg F2 [ Lit1 L1
-%% L1: . Lit2 L2 ]
-%% .
-%% . ==>
-%% .
-%% F1: is_eq_exact F2 Reg Lit2 F1: is_eq_exact F2 Reg Lit2
-%% L2: .... L2:
-%%
-combine_eqs(To, [Reg,{Type,_}=Lit1]=Ops, D, [{label,L1}|_])
- when Type =:= atom; Type =:= integer ->
- case beam_utils:code_at(To, D) of
- [{test,is_eq_exact,{f,F2},[Reg,{Type,_}=Lit2]},
- {label,L2}|_] when Lit1 =/= Lit2 ->
- {select,select_val,Reg,{f,F2},[Lit1,{f,L1},Lit2,{f,L2}]};
- [{select,select_val,Reg,{f,F2},[{Type,_}|_]=List0}|_] ->
- List = remove_from_list(Lit1, List0),
- {select,select_val,Reg,{f,F2},[Lit1,{f,L1}|List]};
- _Is ->
- {test,is_eq_exact,{f,To},Ops}
- end;
-combine_eqs(To, Ops, _D, _Acc) ->
- {test,is_eq_exact,{f,To},Ops}.
-
-remove_from_list(Lit, [Lit,{f,_}|T]) ->
- T;
-remove_from_list(Lit, [Val,{f,_}=Fail|T]) ->
- [Val,Fail|remove_from_list(Lit, T)];
-remove_from_list(_, []) -> [].
-
-%% shortcut_bs_test(TargetLabel, ReversedInstructions, D) -> TargetLabel'
-%% Try to shortcut the failure label for bit syntax matching.
-
-shortcut_bs_test(To, Is, D) ->
- shortcut_bs_test_1(beam_utils:code_at(To, D), Is, To, D).
-
-shortcut_bs_test_1([{bs_restore2,Reg,SavePoint},
- {label,_},
- {test,bs_test_tail2,{f,To},[_,TailBits]}|_],
- PrevIs, To0, D) ->
- case count_bits_matched(PrevIs, {Reg,SavePoint}, 0) of
- Bits when Bits > TailBits ->
- %% This instruction will fail. We know because a restore has been
- %% done from the previous point SavePoint in the binary, and we
- %% also know that the binary contains at least Bits bits from
- %% SavePoint.
- %%
- %% Since we will skip a bs_restore2 if we shortcut to label To,
- %% we must now make sure that code at To does not depend on
- %% the position in the context in any way.
- case shortcut_bs_pos_used(To, Reg, D) of
- false -> To;
- true -> To0
- end;
- _Bits ->
- To0
- end;
-shortcut_bs_test_1([_|_], _, To, _) -> To.
-
-%% counts_bits_matched(ReversedInstructions, SavePoint, Bits) -> Bits'
-%% Given a reversed instruction stream, determine the minimum number
-%% of bits that will be matched by bit syntax instructions up to the
-%% given save point.
-
-count_bits_matched([{test,bs_get_utf8,{f,_},_,_,_}|Is], SavePoint, Bits) ->
- count_bits_matched(Is, SavePoint, Bits+8);
-count_bits_matched([{test,bs_get_utf16,{f,_},_,_,_}|Is], SavePoint, Bits) ->
- count_bits_matched(Is, SavePoint, Bits+16);
-count_bits_matched([{test,bs_get_utf32,{f,_},_,_,_}|Is], SavePoint, Bits) ->
- count_bits_matched(Is, SavePoint, Bits+32);
-count_bits_matched([{test,_,_,_,[_,Sz,U,{field_flags,_}],_}|Is], SavePoint, Bits) ->
- case Sz of
- {integer,N} -> count_bits_matched(Is, SavePoint, Bits+N*U);
- _ -> count_bits_matched(Is, SavePoint, Bits)
- end;
-count_bits_matched([{test,bs_match_string,_,[_,Bs]}|Is], SavePoint, Bits) ->
- count_bits_matched(Is, SavePoint, Bits+bit_size(Bs));
-count_bits_matched([{test,_,_,_}|Is], SavePoint, Bits) ->
- count_bits_matched(Is, SavePoint, Bits);
-count_bits_matched([{bs_save2,Reg,SavePoint}|_], {Reg,SavePoint}, Bits) ->
- %% The save point we are looking for - we are done.
- Bits;
-count_bits_matched([_|_], _, Bits) -> Bits.
-
-shortcut_bs_pos_used(To, Reg, D) ->
- shortcut_bs_pos_used_1(beam_utils:code_at(To, D), Reg, D).
-
-shortcut_bs_pos_used_1([{bs_context_to_binary,Reg}|_], Reg, _) ->
- false;
-shortcut_bs_pos_used_1(Is, Reg, D) ->
- not beam_utils:is_killed(Reg, Is, D).
-
-%% shortcut_bs_start_match(TargetLabel, Reg) -> TargetLabel
-%% A failing bs_start_match2 instruction means that the source (Reg)
-%% cannot be a binary. That means that it is safe to skip
-%% bs_context_to_binary instructions operating on Reg, and
-%% bs_start_match2 instructions operating on Reg.
-
-shortcut_bs_start_match(To, Reg, D) ->
- shortcut_bs_start_match_1(beam_utils:code_at(To, D), Reg, To, D).
-
-shortcut_bs_start_match_1([{bs_context_to_binary,Reg}|Is], Reg, To, D) ->
- shortcut_bs_start_match_1(Is, Reg, To, D);
-shortcut_bs_start_match_1([{jump,{f,To}}|_], Reg, _, D) ->
- Code = beam_utils:code_at(To, D),
- shortcut_bs_start_match_1(Code, Reg, To, D);
-shortcut_bs_start_match_1([{test,bs_start_match2,{f,To},_,[Reg|_],_}|_],
- Reg, _, D) ->
- Code = beam_utils:code_at(To, D),
- shortcut_bs_start_match_1(Code, Reg, To, D);
-shortcut_bs_start_match_1(_, _, To, _) ->
- To.
-
-%% shortcut_bs_context_to_binary(TargetLabel, Reg) -> TargetLabel
-%% If a bs_start_match2 instruction has been eliminated, the
-%% bs_context_to_binary instruction can be eliminated too.
-
-shortcut_bs_context_to_binary(To, Reg, D) ->
- shortcut_bs_ctb_1(beam_utils:code_at(To, D), Reg, To, D).
-
-shortcut_bs_ctb_1([{bs_context_to_binary,Reg}|Is], Reg, To, D) ->
- shortcut_bs_ctb_1(Is, Reg, To, D);
-shortcut_bs_ctb_1([{jump,{f,To}}|_], Reg, _, D) ->
- Code = beam_utils:code_at(To, D),
- shortcut_bs_ctb_1(Code, Reg, To, D);
-shortcut_bs_ctb_1(_, _, To, _) ->
- To.
-
-%% shortcut_rel_op(FailLabel, Operator, [Operand], D) -> FailLabel'
-%% Try to shortcut the given test instruction. Example:
-%%
-%% is_ge L1 {x,0} 48
-%% .
-%% .
-%% .
-%% L1: is_ge L2 {x,0} 65
-%%
-%% The first test instruction can be rewritten to "is_ge L2 {x,0} 48"
-%% since the instruction at L1 will also fail.
-%%
-%% If there are instructions between L1 and the other test instruction
-%% it may still be possible to do the shortcut. For example:
-%%
-%% L1: is_eq_exact L3 {x,0} 92
-%% is_ge L2 {x,0} 65
-%%
-%% Since the first test instruction failed, we know that {x,0} must
-%% be less than 48; therefore, we know that {x,0} cannot be equal to
-%% 92 and the jump to L3 cannot happen.
-
-shortcut_rel_op(To, Op, Ops, D) ->
- case normalize_op({test,Op,{f,To},Ops}) of
- {{NormOp,A,B},_} ->
- Normalized = {negate_op(NormOp),A,B},
- shortcut_rel_op_fp(To, Normalized, D);
- {_,_} ->
- To;
- error ->
- To
- end.
-
-shortcut_rel_op_fp(To0, Normalized, D) ->
- Code = beam_utils:code_at(To0, D),
- case shortcut_any_label(Code, Normalized) of
- error ->
- To0;
- To ->
- shortcut_rel_op_fp(To, Normalized, D)
- end.
-
-%% shortcut_any_label([Instruction], PrevCondition) -> FailLabel | error
-%% Using PrevCondition (a previous condition known to be true),
-%% try to shortcut to another failure label.
-
-shortcut_any_label([{jump,{f,Lbl}}|_], _Prev) ->
- Lbl;
-shortcut_any_label([{label,Lbl}|_], _Prev) ->
- Lbl;
-shortcut_any_label([{select,select_val,R,{f,Fail},L}|_], Prev) ->
- shortcut_selectval(L, R, Fail, Prev);
-shortcut_any_label([I|Is], Prev) ->
- case normalize_op(I) of
- error ->
- error;
- {Normalized,Fail} ->
- %% We have a relational operator.
- case will_succeed(Prev, Normalized) of
- no ->
- %% This test instruction will always branch
- %% to Fail.
- Fail;
- yes ->
- %% This test instruction will never branch,
- %% so we will look at the next instruction.
- shortcut_any_label(Is, Prev);
- maybe ->
- %% May or may not branch. From now on, we can only
- %% shortcut to the this specific failure label
- %% Fail.
- shortcut_specific_label(Is, Fail, Prev)
- end
- end.
-
-%% shortcut_specific_label([Instruction], FailLabel, PrevCondition) ->
-%% FailLabel | error
-%% We have previously encountered a test instruction that may or
-%% may not branch to FailLabel. Therefore we are only allowed
-%% to do the shortcut to the same fail label (FailLabel).
-
-shortcut_specific_label([{label,_}|Is], Fail, Prev) ->
- shortcut_specific_label(Is, Fail, Prev);
-shortcut_specific_label([{select,select_val,R,{f,F},L}|_], Fail, Prev) ->
- case shortcut_selectval(L, R, F, Prev) of
- Fail -> Fail;
- _ -> error
- end;
-shortcut_specific_label([I|Is], Fail, Prev) ->
- case normalize_op(I) of
- error ->
- error;
- {Normalized,Fail} ->
- case will_succeed(Prev, Normalized) of
- no ->
- %% Will branch to FailLabel.
- Fail;
- yes ->
- %% Will definitely never branch.
- shortcut_specific_label(Is, Fail, Prev);
- maybe ->
- %% May branch, but still OK since it will branch
- %% to FailLabel.
- shortcut_specific_label(Is, Fail, Prev)
- end;
- {Normalized,_} ->
- %% This test instruction will branch to a different
- %% fail label, if it branches at all.
- case will_succeed(Prev, Normalized) of
- yes ->
- %% Still OK, since the branch will never be
- %% taken.
- shortcut_specific_label(Is, Fail, Prev);
- no ->
- %% Give up. The branch will definitely be taken
- %% to a different fail label.
- error;
- maybe ->
- %% Give up. If the branch is taken, it will be
- %% to a different fail label.
- error
- end
- end.
-
-
-%% shortcut_selectval(List, Reg, Fail, PrevCond) -> FailLabel | error
-%% Try to shortcut a selectval instruction. A selectval instruction
-%% is equivalent to the following instruction sequence:
-%%
-%% is_ne_exact L1 Reg Value1
-%% .
-%% .
-%% .
-%% is_ne_exact LN Reg ValueN
-%% jump DefaultFailLabel
-%%
-shortcut_selectval([Val,{f,Lbl}|T], R, Fail, Prev) ->
- case will_succeed(Prev, {'=/=',R,get_literal(Val)}) of
- yes -> shortcut_selectval(T, R, Fail, Prev);
- no -> Lbl;
- maybe -> error
- end;
-shortcut_selectval([], _, Fail, _) -> Fail.
-
-%% will_succeed(PrevCondition, Condition) -> yes | no | maybe
-%% PrevCondition is a condition known to be true. This function
-%% will tell whether Condition will succeed.
-
-will_succeed({Op1,Reg,A}, {Op2,Reg,B}) ->
- will_succeed_1(Op1, A, Op2, B);
-will_succeed({'=:=',Reg,{literal,A}}, {TypeTest,Reg}) ->
- case erlang:TypeTest(A) of
- false -> no;
- true -> yes
- end;
-will_succeed({_,_,_}, maybe) ->
- maybe;
-will_succeed({_,_,_}, Test) when is_tuple(Test) ->
- maybe.
-
-will_succeed_1('=:=', A, '<', B) ->
- if
- B =< A -> no;
- true -> yes
- end;
-will_succeed_1('=:=', A, '=<', B) ->
- if
- B < A -> no;
- true -> yes
- end;
-will_succeed_1('=:=', A, '=:=', B) ->
- if
- A =:= B -> yes;
- true -> no
- end;
-will_succeed_1('=:=', A, '=/=', B) ->
- if
- A =:= B -> no;
- true -> yes
- end;
-will_succeed_1('=:=', A, '>=', B) ->
- if
- B > A -> no;
- true -> yes
- end;
-will_succeed_1('=:=', A, '>', B) ->
- if
- B >= A -> no;
- true -> yes
- end;
-
-will_succeed_1('=/=', A, '=/=', B) when A =:= B -> yes;
-will_succeed_1('=/=', A, '=:=', B) when A =:= B -> no;
-
-will_succeed_1('<', A, '=:=', B) when B >= A -> no;
-will_succeed_1('<', A, '=/=', B) when B >= A -> yes;
-will_succeed_1('<', A, '<', B) when B >= A -> yes;
-will_succeed_1('<', A, '=<', B) when B > A -> yes;
-will_succeed_1('<', A, '>=', B) when B > A -> no;
-will_succeed_1('<', A, '>', B) when B >= A -> no;
-
-will_succeed_1('=<', A, '=:=', B) when B > A -> no;
-will_succeed_1('=<', A, '=/=', B) when B > A -> yes;
-will_succeed_1('=<', A, '<', B) when B > A -> yes;
-will_succeed_1('=<', A, '=<', B) when B >= A -> yes;
-will_succeed_1('=<', A, '>=', B) when B > A -> no;
-will_succeed_1('=<', A, '>', B) when B >= A -> no;
-
-will_succeed_1('>=', A, '=:=', B) when B < A -> no;
-will_succeed_1('>=', A, '=/=', B) when B < A -> yes;
-will_succeed_1('>=', A, '<', B) when B =< A -> no;
-will_succeed_1('>=', A, '=<', B) when B < A -> no;
-will_succeed_1('>=', A, '>=', B) when B =< A -> yes;
-will_succeed_1('>=', A, '>', B) when B < A -> yes;
-
-will_succeed_1('>', A, '=:=', B) when B =< A -> no;
-will_succeed_1('>', A, '=/=', B) when B =< A -> yes;
-will_succeed_1('>', A, '<', B) when B =< A -> no;
-will_succeed_1('>', A, '=<', B) when B < A -> no;
-will_succeed_1('>', A, '>=', B) when B =< A -> yes;
-will_succeed_1('>', A, '>', B) when B < A -> yes;
-
-will_succeed_1(_, _, _, _) -> maybe.
-
-%% normalize_op(Instruction) -> {Normalized,FailLabel} | error
-%% Normalized = {Operator,Register,Literal} |
-%% {TypeTest,Register} |
-%% maybe
-%% Operation = '<' | '=<' | '=:=' | '=/=' | '>=' | '>'
-%% TypeTest = is_atom | is_integer ...
-%% Literal = {literal,Term}
-%%
-%% Normalize a relational operator to facilitate further
-%% comparisons between operators. Always make the register
-%% operand the first operand. Thus the following instruction:
-%%
-%% {test,is_ge,{f,99},{integer,13},{x,0}}
-%%
-%% will be normalized to:
-%%
-%% {'=<',{x,0},{literal,13}}
-%%
-%% NOTE: Bit syntax test instructions are scary. They may change the
-%% state of match contexts and update registers, so we don't dare
-%% mess with them.
-
-normalize_op({test,is_ge,{f,Fail},Ops}) ->
- normalize_op_1('>=', Ops, Fail);
-normalize_op({test,is_lt,{f,Fail},Ops}) ->
- normalize_op_1('<', Ops, Fail);
-normalize_op({test,is_eq_exact,{f,Fail},Ops}) ->
- normalize_op_1('=:=', Ops, Fail);
-normalize_op({test,is_ne_exact,{f,Fail},Ops}) ->
- normalize_op_1('=/=', Ops, Fail);
-normalize_op({test,is_nil,{f,Fail},[R]}) ->
- normalize_op_1('=:=', [R,nil], Fail);
-normalize_op({test,Op,{f,Fail},[R]}) ->
- case erl_internal:new_type_test(Op, 1) of
- true -> {{Op,R},Fail};
- false -> {maybe,Fail}
- end;
-normalize_op({test,_,{f,Fail},_}=I) ->
- case beam_utils:is_pure_test(I) of
- true -> {maybe,Fail};
- false -> error
- end;
-normalize_op(_) ->
- error.
-
-normalize_op_1(Op, [Op1,Op2], Fail) ->
- case {get_literal(Op1),get_literal(Op2)} of
- {error,error} ->
- %% Both operands are registers.
- {maybe,Fail};
- {error,Lit} ->
- {{Op,Op1,Lit},Fail};
- {Lit,error} ->
- {{turn_op(Op),Op2,Lit},Fail};
- {_,_} ->
- %% Both operands are literals. Can probably only
- %% happen if the Core Erlang optimizations passes were
- %% turned off, so don't bother trying to do something
- %% smart here.
- {maybe,Fail}
- end.
-
-turn_op('<') -> '>';
-turn_op('>=') -> '=<';
-turn_op('=:='=Op) -> Op;
-turn_op('=/='=Op) -> Op.
-
-negate_op('>=') -> '<';
-negate_op('<') -> '>=';
-negate_op('=<') -> '>';
-negate_op('>') -> '=<';
-negate_op('=:=') -> '=/=';
-negate_op('=/=') -> '=:='.
-
-get_literal({atom,Val}) ->
- {literal,Val};
-get_literal({integer,Val}) ->
- {literal,Val};
-get_literal({float,Val}) ->
- {literal,Val};
-get_literal(nil) ->
- {literal,[]};
-get_literal({literal,_}=Lit) ->
- Lit;
-get_literal({_,_}) -> error.
-
-
-%%%
-%%% Removing stores to Y registers is not always safe
-%%% if there is an instruction that causes an exception
-%%% within a catch. In practice, there are few or no
-%%% opportunities for removing stores to Y registers anyway
-%%% if sys_core_fold has been run.
-%%%
-
-is_killed_at({x,_}=Reg, Lbl, D) ->
- beam_utils:is_killed_at(Reg, Lbl, D);
-is_killed_at({y,_}, _, _) ->
- false.
diff --git a/lib/compiler/src/beam_dict.erl b/lib/compiler/src/beam_dict.erl
index 990e86062a..b2056332e6 100644
--- a/lib/compiler/src/beam_dict.erl
+++ b/lib/compiler/src/beam_dict.erl
@@ -126,18 +126,17 @@ import(Mod0, Name0, Arity, #asm{imports=Imp0,next_import=NextIndex}=D0)
{NextIndex,D2#asm{imports=Imp,next_import=NextIndex+1}}
end.
-%% Returns the index for a string in the string table (adding the string to the
-%% table if necessary).
+%% Returns the index for a binary string in the string table (adding
+%% the string to the table if necessary).
%% string(String, Dict) -> {Offset, Dict'}
--spec string(string(), bdict()) -> {non_neg_integer(), bdict()}.
+-spec string(binary(), bdict()) -> {non_neg_integer(), bdict()}.
-string(Str, Dict) when is_list(Str) ->
+string(BinString, Dict) when is_binary(BinString) ->
#asm{strings=Strings,string_offset=NextOffset} = Dict,
- StrBin = list_to_binary(Str),
- case old_string(StrBin, Strings) of
+ case old_string(BinString, Strings) of
none ->
- NewDict = Dict#asm{strings = <<Strings/binary,StrBin/binary>>,
- string_offset=NextOffset+byte_size(StrBin)},
+ NewDict = Dict#asm{strings = <<Strings/binary,BinString/binary>>,
+ string_offset=NextOffset+byte_size(BinString)},
{NextOffset,NewDict};
Offset when is_integer(Offset) ->
{NextOffset-Offset,Dict}
diff --git a/lib/compiler/src/beam_disasm.erl b/lib/compiler/src/beam_disasm.erl
index 8fd0b36d05..7d048716e4 100644
--- a/lib/compiler/src/beam_disasm.erl
+++ b/lib/compiler/src/beam_disasm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -163,8 +163,8 @@ pp_instr(I) ->
file(File) ->
try process_chunks(File)
- catch error:Reason ->
- {error,?MODULE,{internal,{Reason,erlang:get_stacktrace()}}}
+ catch error:Reason:Stack ->
+ {error,?MODULE,{internal,{Reason,Stack}}}
end.
%%-----------------------------------------------------------------------
@@ -373,6 +373,8 @@ disasm_instr(B, Bs, Atoms, Literals) ->
disasm_map_inst(get_map_elements, Arity, Bs, Atoms, Literals);
has_map_fields ->
disasm_map_inst(has_map_fields, Arity, Bs, Atoms, Literals);
+ put_tuple2 ->
+ disasm_put_tuple2(Bs, Atoms, Literals);
_ ->
try decode_n_args(Arity, Bs, Atoms, Literals) of
{Args, RestBs} ->
@@ -413,6 +415,14 @@ disasm_map_inst(Inst, Arity, Bs0, Atoms, Literals) ->
{List, RestBs} = decode_n_args(Len, Bs2, Atoms, Literals),
{{Inst, Args ++ [{Z,U,List}]}, RestBs}.
+disasm_put_tuple2(Bs, Atoms, Literals) ->
+ {X, Bs1} = decode_arg(Bs, Atoms, Literals),
+ {Z, Bs2} = decode_arg(Bs1, Atoms, Literals),
+ {U, Bs3} = decode_arg(Bs2, Atoms, Literals),
+ {u, Len} = U,
+ {List, RestBs} = decode_n_args(Len, Bs3, Atoms, Literals),
+ {{put_tuple2, [X,{Z,U,List}]}, RestBs}.
+
%%-----------------------------------------------------------------------
%% decode_arg([Byte]) -> {Arg, [Byte]}
%%
@@ -719,42 +729,6 @@ resolve_inst({wait,[Lbl]},_,_,_) ->
{wait,Lbl};
resolve_inst({wait_timeout,[Lbl,Int]},_,_,_) ->
{wait_timeout,Lbl,resolve_arg(Int)};
-resolve_inst({m_plus,Args},_,_,_) ->
- [W,SrcR1,SrcR2,DstR] = resolve_args(Args),
- {arithbif,'+',W,[SrcR1,SrcR2],DstR};
-resolve_inst({m_minus,Args},_,_,_) ->
- [W,SrcR1,SrcR2,DstR] = resolve_args(Args),
- {arithbif,'-',W,[SrcR1,SrcR2],DstR};
-resolve_inst({m_times,Args},_,_,_) ->
- [W,SrcR1,SrcR2,DstR] = resolve_args(Args),
- {arithbif,'*',W,[SrcR1,SrcR2],DstR};
-resolve_inst({m_div,Args},_,_,_) ->
- [W,SrcR1,SrcR2,DstR] = resolve_args(Args),
- {arithbif,'/',W,[SrcR1,SrcR2],DstR};
-resolve_inst({int_div,Args},_,_,_) ->
- [W,SrcR1,SrcR2,DstR] = resolve_args(Args),
- {arithbif,'div',W,[SrcR1,SrcR2],DstR};
-resolve_inst({int_rem,Args},_,_,_) ->
- [W,SrcR1,SrcR2,DstR] = resolve_args(Args),
- {arithbif,'rem',W,[SrcR1,SrcR2],DstR};
-resolve_inst({int_band,Args},_,_,_) ->
- [W,SrcR1,SrcR2,DstR] = resolve_args(Args),
- {arithbif,'band',W,[SrcR1,SrcR2],DstR};
-resolve_inst({int_bor,Args},_,_,_) ->
- [W,SrcR1,SrcR2,DstR] = resolve_args(Args),
- {arithbif,'bor',W,[SrcR1,SrcR2],DstR};
-resolve_inst({int_bxor,Args},_,_,_) ->
- [W,SrcR1,SrcR2,DstR] = resolve_args(Args),
- {arithbif,'bxor',W,[SrcR1,SrcR2],DstR};
-resolve_inst({int_bsl,Args},_,_,_) ->
- [W,SrcR1,SrcR2,DstR] = resolve_args(Args),
- {arithbif,'bsl',W,[SrcR1,SrcR2],DstR};
-resolve_inst({int_bsr,Args},_,_,_) ->
- [W,SrcR1,SrcR2,DstR] = resolve_args(Args),
- {arithbif,'bsr',W,[SrcR1,SrcR2],DstR};
-resolve_inst({int_bnot,Args},_,_,_) ->
- [W,SrcR,DstR] = resolve_args(Args),
- {arithbif,'bnot',W,[SrcR],DstR};
resolve_inst({is_lt=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
{test,I,L,Args};
@@ -800,9 +774,6 @@ resolve_inst({is_nil=I,Args0},_,_,_) ->
resolve_inst({is_binary=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
{test,I,L,Args};
-resolve_inst({is_constant=I,Args0},_,_,_) ->
- [L|Args] = resolve_args(Args0),
- {test,I,L,Args};
resolve_inst({is_list=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
{test,I,L,Args};
@@ -840,11 +811,6 @@ resolve_inst({get_tuple_element,[Src,{u,Off},Dst]},_,_,_) ->
{get_tuple_element,resolve_arg(Src),Off,resolve_arg(Dst)};
resolve_inst({set_tuple_element,[Src,Dst,{u,Off}]},_,_,_) ->
{set_tuple_element,resolve_arg(Src),resolve_arg(Dst),Off};
-resolve_inst({put_string,[{u,Len},{u,Off},Dst]},_,Strings,_) ->
- String = if Len > 0 -> binary_to_list(Strings, Off+1, Off+Len);
- true -> ""
- end,
- {put_string,Len,{string,String},Dst};
resolve_inst({put_list,[Src1,Src2,Dst]},_,_,_) ->
{put_list,resolve_arg(Src1),resolve_arg(Src2),Dst};
resolve_inst({put_tuple,[{u,Arity},Dst]},_,_,_) ->
@@ -859,9 +825,6 @@ resolve_inst({case_end,[X]},_,_,_) ->
{case_end,resolve_arg(X)};
resolve_inst({call_fun,[{u,N}]},_,_,_) ->
{call_fun,N};
-resolve_inst({make_fun,Args},_,_,Lbls) ->
- [{f,L},Magic,FreeVars] = resolve_args(Args),
- {make_fun,lookup(L,Lbls),Magic,FreeVars};
resolve_inst({is_function=I,Args0},_,_,_) ->
[L|Args] = resolve_args(Args0),
{test,I,L,Args};
@@ -870,30 +833,6 @@ resolve_inst({call_ext_only,[{u,N},{u,MFAix}]},Imports,_,_) ->
%%
%% Instructions for handling binaries added in R7A & R7B
%%
-resolve_inst({bs_start_match,[F,Reg]},_,_,_) ->
- {bs_start_match,F,Reg};
-resolve_inst({bs_get_integer=I,[Lbl,Arg2,{u,N},{u,U},Arg5]},_,_,_) ->
- [A2,A5] = resolve_args([Arg2,Arg5]),
- {test,I,Lbl,[A2,N,decode_field_flags(U),A5]};
-resolve_inst({bs_get_float=I,[Lbl,Arg2,{u,N},{u,U},Arg5]},_,_,_) ->
- [A2,A5] = resolve_args([Arg2,Arg5]),
- {test,I,Lbl,[A2,N,decode_field_flags(U),A5]};
-resolve_inst({bs_get_binary=I,[Lbl,Arg2,{u,N},{u,U},Arg5]},_,_,_) ->
- [A2,A5] = resolve_args([Arg2,Arg5]),
- {test,I,Lbl,[A2,N,decode_field_flags(U),A5]};
-resolve_inst({bs_skip_bits,[Lbl,Arg2,{u,N},{u,U}]},_,_,_) ->
- A2 = resolve_arg(Arg2),
- {test,bs_skip_bits,Lbl,[A2,N,decode_field_flags(U)]};
-resolve_inst({bs_test_tail,[F,{u,N}]},_,_,_) ->
- {test,bs_test_tail,F,[N]};
-resolve_inst({bs_save,[{u,N}]},_,_,_) ->
- {bs_save,N};
-resolve_inst({bs_restore,[{u,N}]},_,_,_) ->
- {bs_restore,N};
-resolve_inst({bs_init,[{u,N},{u,U}]},_,_,_) ->
- {bs_init,N,decode_field_flags(U)};
-resolve_inst({bs_final,[F,X]},_,_,_) ->
- {bs_final,F,X};
resolve_inst({bs_put_integer,[Lbl,Arg2,{u,N},{u,U},Arg5]},_,_,_) ->
[A2,A5] = resolve_args([Arg2,Arg5]),
{bs_put_integer,Lbl,A2,N,decode_field_flags(U),A5};
@@ -908,8 +847,6 @@ resolve_inst({bs_put_string,[{u,Len},{u,Off}]},_,Strings,_) ->
true -> ""
end,
{bs_put_string,Len,{string,String}};
-resolve_inst({bs_need_buf,[{u,N}]},_,_,_) ->
- {bs_need_buf,N};
%%
%% Instructions for handling floating point numbers added in June 2001 (R8).
@@ -961,9 +898,6 @@ resolve_inst({raise,[_Reg1,_Reg2]=Regs},_,_,_) ->
resolve_inst({bs_init2,[Lbl,Arg2,{u,W},{u,R},{u,F},Arg6]},_,_,_) ->
[A2,A6] = resolve_args([Arg2,Arg6]),
{bs_init2,Lbl,A2,W,R,decode_field_flags(F),A6};
-resolve_inst({bs_bits_to_bytes,[Lbl,Arg2,Arg3]},_,_,_) ->
- [A2,A3] = resolve_args([Arg2,Arg3]),
- {bs_bits_to_bytes,Lbl,A2,A3};
resolve_inst({bs_add=I,[Lbl,Arg2,Arg3,Arg4,Arg5]},_,_,_) ->
[A2,A3,A4,A5] = resolve_args([Arg2,Arg3,Arg4,Arg5]),
{I,Lbl,[A2,A3,A4],A5};
@@ -1041,12 +975,6 @@ resolve_inst({gc_bif3,Args},Imports,_,_) ->
{gc_bif,BifName,F,Live,[A1,A2,A3],Reg};
%%
-%% New instructions for creating non-byte aligned binaries.
-%%
-resolve_inst({bs_final2,[X,Y]},_,_,_) ->
- {bs_final2,X,Y};
-
-%%
%% R11B-5.
%%
resolve_inst({is_bitstr=I,Args0},_,_,_) ->
@@ -1165,6 +1093,36 @@ resolve_inst({get_map_elements,Args0},_,_,_) ->
{get_map_elements,FLbl,Src,{list,List}};
%%
+%% OTP 21.
+%%
+
+resolve_inst({build_stacktrace,[]},_,_,_) ->
+ build_stacktrace;
+resolve_inst({raw_raise,[]},_,_,_) ->
+ raw_raise;
+resolve_inst({get_hd,[Src,Dst]},_,_,_) ->
+ {get_hd,Src,Dst};
+resolve_inst({get_tl,[Src,Dst]},_,_,_) ->
+ {get_tl,Src,Dst};
+
+%% OTP 22
+resolve_inst({bs_start_match3,[Fail,Bin,Live,Dst]},_,_,_) ->
+ {bs_start_match3,Fail,Bin,Live,Dst};
+resolve_inst({bs_get_tail,[Src,Dst,Live]},_,_,_) ->
+ {bs_get_tail,Src,Dst,Live};
+resolve_inst({bs_get_position,[Src,Dst,Live]},_,_,_) ->
+ {bs_get_position,Src,Dst,Live};
+resolve_inst({bs_set_position,[Src,Dst]},_,_,_) ->
+ {bs_set_position,Src,Dst};
+
+%%
+%% OTP 22.
+%%
+resolve_inst({put_tuple2,[Dst,{{z,1},{u,_},List0}]},_,_,_) ->
+ List = resolve_args(List0),
+ {put_tuple2,Dst,{list,List}};
+
+%%
%% Catches instructions that are not yet handled.
%%
resolve_inst(X,_,_,_) -> ?exit({resolve_inst,X}).
diff --git a/lib/compiler/src/beam_disasm.hrl b/lib/compiler/src/beam_disasm.hrl
index d968cd9587..e8ebfc4cfc 100644
--- a/lib/compiler/src/beam_disasm.hrl
+++ b/lib/compiler/src/beam_disasm.hrl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,7 +26,8 @@
%% IT SHOULD BE MOVED TO A FILE THAT DEFINES (AND EXPORTS)
%% PROPER TYPES FOR THE SET OF BEAM INSTRUCTIONS.
%%
--type beam_instr() :: 'bs_init_writable' | 'fclearerror' | 'if_end'
+-type beam_instr() :: 'bs_init_writable' | 'build_stacktrace'
+ | 'fclearerror' | 'if_end' | 'raw_raise'
| 'remove_message' | 'return' | 'send' | 'timeout'
| tuple(). %% XXX: Very underspecified - FIX THIS
diff --git a/lib/compiler/src/beam_except.erl b/lib/compiler/src/beam_except.erl
index 9801c68ee2..28c89782c9 100644
--- a/lib/compiler/src/beam_except.erl
+++ b/lib/compiler/src/beam_except.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -31,7 +31,7 @@
%%% erlang:error(function_clause, Args) => jump FuncInfoLabel
%%%
--import(lists, [reverse/1]).
+-import(lists, [reverse/1,reverse/2,seq/2,splitwith/2]).
-spec module(beam_utils:module_code(), [compile:option()]) ->
{'ok',beam_utils:module_code()}.
@@ -45,8 +45,7 @@ function({function,Name,Arity,CLabel,Is0}) ->
Is = function_1(Is0),
{function,Name,Arity,CLabel,Is}
catch
- Class:Error ->
- Stack = erlang:get_stacktrace(),
+ Class:Error:Stack ->
io:fwrite("Function: ~w/~w\n", [Name,Arity]),
erlang:raise(Class, Error, Stack)
end.
@@ -54,7 +53,7 @@ function({function,Name,Arity,CLabel,Is0}) ->
-record(st,
{lbl :: beam_asm:label(), %func_info label
loc :: [_], %location for func_info
- arity :: arity() %arity for function
+ arity :: arity() %arity for function
}).
function_1(Is0) ->
@@ -75,27 +74,33 @@ translate([I|Is], St, Acc) ->
translate([], _, Acc) ->
reverse(Acc).
-translate_1(Ar, I, Is, St, [{line,_}=Line|Acc1]=Acc0) ->
- case dig_out(Ar, Acc1) of
+translate_1(Ar, I, Is, #st{arity=Arity}=St, [{line,_}=Line|Acc1]=Acc0) ->
+ case dig_out(Ar, Arity, Acc1) of
no ->
translate(Is, St, [I|Acc0]);
- {yes,{function_clause,Arity},Acc2} ->
- case {Line,St} of
- {{line,Loc},#st{lbl=Fi,loc=Loc,arity=Arity}} ->
+ {yes,function_clause,Acc2} ->
+ case {Is,Line,St} of
+ {[return|_],{line,Loc},#st{lbl=Fi,loc=Loc}} ->
Instr = {jump,{f,Fi}},
translate(Is, St, [Instr|Acc2]);
- {_,_} ->
- %% This must be "error(function_clause, Args)" in
- %% the Erlang source code or a fun. Don't translate.
+ {_,_,_} ->
+ %% Not a call_only instruction, or not the same
+ %% location information as in in the line instruction
+ %% before the func_info instruction. Not safe
+ %% to translate to a jump.
translate(Is, St, [I|Acc0])
end;
{yes,Instr,Acc2} ->
translate(Is, St, [Instr,Line|Acc2])
end.
-dig_out(Ar, [{kill,_}|Is]) ->
- dig_out(Ar, Is);
-dig_out(1, [{block,Bl0}|Is]) ->
+dig_out(1, _Arity, Is) ->
+ dig_out(Is);
+dig_out(2, Arity, Is) ->
+ dig_out_fc(Arity, Is);
+dig_out(_, _, _) -> no.
+
+dig_out([{block,Bl0}|Is]) ->
case dig_out_block(reverse(Bl0)) of
no -> no;
{yes,What,[]} ->
@@ -103,25 +108,13 @@ dig_out(1, [{block,Bl0}|Is]) ->
{yes,What,Bl} ->
{yes,What,[{block,Bl}|Is]}
end;
-dig_out(2, [{block,Bl}|Is]) ->
- case dig_out_block_fc(Bl) of
- no -> no;
- {yes,What} -> {yes,What,Is}
- end;
-dig_out(_, _) -> no.
+dig_out(_) -> no.
dig_out_block([{set,[{x,0}],[{atom,if_clause}],move}]) ->
{yes,if_end,[]};
dig_out_block([{set,[{x,0}],[{literal,{Exc,Value}}],move}|Is]) ->
translate_exception(Exc, {literal,Value}, Is, 0);
-dig_out_block([{set,[{x,0}],[Tuple],move},
- {set,[],[Value],put},
- {set,[],[{atom,Exc}],put},
- {set,[Tuple],[],{put_tuple,2}}|Is]) ->
- translate_exception(Exc, Value, Is, 3);
-dig_out_block([{set,[],[Value],put},
- {set,[],[{atom,Exc}],put},
- {set,[{x,0}],[],{put_tuple,2}}|Is]) ->
+dig_out_block([{set,[{x,0}],[{atom,Exc},Value],put_tuple2}|Is]) ->
translate_exception(Exc, Value, Is, 3);
dig_out_block(_) -> no.
@@ -139,23 +132,113 @@ fix_block(Is, Words) ->
reverse(fix_block_1(Is, Words)).
fix_block_1([{set,[],[],{alloc,Live,{F1,F2,Needed0,F3}}}|Is], Words) ->
- Needed = Needed0 - Words,
- true = Needed >= 0, %Assertion.
- [{set,[],[],{alloc,Live,{F1,F2,Needed,F3}}}|Is];
+ case Needed0 - Words of
+ 0 ->
+ Is;
+ Needed ->
+ true = Needed >= 0, %Assertion.
+ [{set,[],[],{alloc,Live,{F1,F2,Needed,F3}}}|Is]
+ end;
fix_block_1([I|Is], Words) ->
[I|fix_block_1(Is, Words)].
-dig_out_block_fc([{set,[],[],{alloc,Live,_}}|Bl]) ->
- case dig_out_fc(Bl, Live-1, nil) of
- no ->
- no;
- yes ->
- {yes,{function_clause,Live}}
+
+dig_out_fc(Arity, Is0) ->
+ Regs0 = maps:from_list([{{x,X},{arg,X}} || X <- seq(0, Arity-1)]),
+ {Is,Acc0} = splitwith(fun({label,_}) -> false;
+ ({test,_,_,_}) -> false;
+ (_) -> true
+ end, Is0),
+ {Regs,Acc} = dig_out_fc_1(reverse(Is), Regs0, Acc0),
+ case Regs of
+ #{{x,0}:={atom,function_clause},{x,1}:=Args} ->
+ case moves_from_stack(Args, 0, []) of
+ {Moves,Arity} ->
+ {yes,function_clause,reverse(Moves, Acc)};
+ {_,_} ->
+ no
+ end;
+ #{} ->
+ no
+ end.
+
+dig_out_fc_1([{block,Bl}|Is], Regs0, Acc) ->
+ Regs = dig_out_fc_block(Bl, Regs0),
+ dig_out_fc_1(Is, Regs, Acc);
+dig_out_fc_1([{bs_set_position,_,_}=I|Is], Regs, Acc) ->
+ dig_out_fc_1(Is, Regs, [I|Acc]);
+dig_out_fc_1([{bs_get_tail,Src,Dst,Live0}|Is], Regs0, Acc) ->
+ Regs = prune_xregs(Live0, Regs0),
+ Live = dig_out_stack_live(Regs, Live0),
+ I = {bs_get_tail,Src,Dst,Live},
+ dig_out_fc_1(Is, Regs, [I|Acc]);
+dig_out_fc_1([_|_], _Regs, _Acc) ->
+ {#{},[]};
+dig_out_fc_1([], Regs, Acc) ->
+ {Regs,Acc}.
+
+dig_out_fc_block([{set,[],[],{alloc,Live,_}}|Is], Regs0) ->
+ Regs = prune_xregs(Live, Regs0),
+ dig_out_fc_block(Is, Regs);
+dig_out_fc_block([{set,[Dst],[Hd,Tl],put_list}|Is], Regs0) ->
+ Regs = Regs0#{Dst=>{cons,get_reg(Hd, Regs0),get_reg(Tl, Regs0)}},
+ dig_out_fc_block(Is, Regs);
+dig_out_fc_block([{set,[Dst],[Src],move}|Is], Regs0) ->
+ Regs = Regs0#{Dst=>get_reg(Src, Regs0)},
+ dig_out_fc_block(Is, Regs);
+dig_out_fc_block([{set,_,_,_}|_], _Regs) ->
+ %% Unknown instruction. Fail.
+ #{};
+dig_out_fc_block([], Regs) -> Regs.
+
+dig_out_stack_live(Regs, Default) ->
+ Reg = {x,2},
+ case Regs of
+ #{Reg:=List} ->
+ dig_out_stack_live_1(List, Default);
+ #{} ->
+ Default
+ end.
+
+dig_out_stack_live_1({cons,{arg,N},T}, Live) ->
+ dig_out_stack_live_1(T, max(N + 1, Live));
+dig_out_stack_live_1({cons,_,T}, Live) ->
+ dig_out_stack_live_1(T, Live);
+dig_out_stack_live_1(nil, Live) ->
+ Live;
+dig_out_stack_live_1(_, Live) -> Live.
+
+prune_xregs(Live, Regs) ->
+ maps:filter(fun({x,X}, _) -> X < Live end, Regs).
+
+moves_from_stack({cons,{arg,N},_}, I, _Acc) when N =/= I ->
+ %% Wrong argument. Give up.
+ {[],-1};
+moves_from_stack({cons,H,T}, I, Acc) ->
+ case H of
+ {arg,I} ->
+ moves_from_stack(T, I+1, Acc);
+ _ ->
+ moves_from_stack(T, I+1, [{move,H,{x,I}}|Acc])
end;
-dig_out_block_fc(_) -> no.
+moves_from_stack(nil, I, Acc) ->
+ {reverse(Acc),I};
+moves_from_stack({literal,[H|T]}, I, Acc) ->
+ Cons = {cons,tag_literal(H),tag_literal(T)},
+ moves_from_stack(Cons, I, Acc);
+moves_from_stack(_, _, _) ->
+ %% Not understood. Give up.
+ {[],-1}.
+
+
+get_reg(R, Regs) ->
+ case Regs of
+ #{R:=Val} -> Val;
+ #{} -> R
+ end.
-dig_out_fc([{set,[Dst],[{x,Reg},Dst0],put_list}|Is], Reg, Dst0) ->
- dig_out_fc(Is, Reg-1, Dst);
-dig_out_fc([{set,[{x,0}],[{atom,function_clause}],move}], -1, {x,1}) ->
- yes;
-dig_out_fc(_, _, _) -> no.
+tag_literal([]) -> nil;
+tag_literal(T) when is_atom(T) -> {atom,T};
+tag_literal(T) when is_float(T) -> {float,T};
+tag_literal(T) when is_integer(T) -> {integer,T};
+tag_literal(T) -> {literal,T}.
diff --git a/lib/compiler/src/beam_flatten.erl b/lib/compiler/src/beam_flatten.erl
index a4d45a4ca6..3e6bc1b1ed 100644
--- a/lib/compiler/src/beam_flatten.erl
+++ b/lib/compiler/src/beam_flatten.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,8 +32,7 @@ module({Mod,Exp,Attr,Fs,Lc}, _Opt) ->
{ok,{Mod,Exp,Attr,[function(F) || F <- Fs],Lc}}.
function({function,Name,Arity,CLabel,Is0}) ->
- Is1 = block(Is0),
- Is = opt(Is1),
+ Is = block(Is0),
{function,Name,Arity,CLabel,Is}.
block(Is) ->
@@ -44,15 +43,11 @@ block([I|Is], Acc) -> block(Is, [I|Acc]);
block([], Acc) -> reverse(Acc).
norm_block([{set,[],[],{alloc,R,Alloc}}|Is], Acc0) ->
- case insert_alloc_in_bs_init(Acc0, Alloc) of
- impossible ->
- norm_block(Is, reverse(norm_allocate(Alloc, R), Acc0));
- Acc ->
- norm_block(Is, Acc)
- end;
-norm_block([I|Is], Acc) -> norm_block(Is, [norm(I)|Acc]);
+ norm_block(Is, reverse(norm_allocate(Alloc, R), Acc0));
+norm_block([I|Is], Acc) ->
+ norm_block(Is, [norm(I)|Acc]);
norm_block([], Acc) -> Acc.
-
+
norm({set,[D],As,{bif,N,F}}) -> {bif,N,F,As,D};
norm({set,[D],As,{alloc,R,{gc_bif,N,F}}}) -> {gc_bif,N,F,R,As,D};
norm({set,[D],[],init}) -> {init,D};
@@ -60,16 +55,19 @@ norm({set,[D],[S],move}) -> {move,S,D};
norm({set,[D],[S],fmove}) -> {fmove,S,D};
norm({set,[D],[S],fconv}) -> {fconv,S,D};
norm({set,[D],[S1,S2],put_list}) -> {put_list,S1,S2,D};
+norm({set,[D],Els,put_tuple2}) -> {put_tuple2,D,{list,Els}};
norm({set,[D],[],{put_tuple,A}}) -> {put_tuple,A,D};
norm({set,[],[S],put}) -> {put,S};
norm({set,[D],[S],{get_tuple_element,I}}) -> {get_tuple_element,S,I,D};
norm({set,[],[S,D],{set_tuple_element,I}}) -> {set_tuple_element,S,D,I};
-norm({set,[D1,D2],[S],get_list}) -> {get_list,S,D1,D2};
+norm({set,[D],[S],get_hd}) -> {get_hd,S,D};
+norm({set,[D],[S],get_tl}) -> {get_tl,S,D};
norm({set,[D],[S|Puts],{alloc,R,{put_map,Op,F}}}) ->
{put_map,F,Op,S,D,R,{list,Puts}};
norm({set,[],[],remove_message}) -> remove_message;
norm({set,[],[],fclearerror}) -> fclearerror;
-norm({set,[],[],fcheckerror}) -> {fcheckerror,{f,0}}.
+norm({set,[],[],fcheckerror}) -> {fcheckerror,{f,0}};
+norm({set,[],[],{line,_}=Line}) -> Line.
norm_allocate({_Zero,nostack,Nh,[]}, Regs) ->
[{test_heap,Nh,Regs}];
@@ -83,57 +81,3 @@ norm_allocate({nozero,Ns,0,Inits}, Regs) ->
[{allocate,Ns,Regs}|Inits];
norm_allocate({nozero,Ns,Nh,Inits}, Regs) ->
[{allocate_heap,Ns,Nh,Regs}|Inits].
-
-%% insert_alloc_in_bs_init(ReverseInstructionStream, AllocationInfo) ->
-%% impossible | ReverseInstructionStream'
-%% A bs_init/6 instruction should not be followed by a test heap instruction.
-%% Given the AllocationInfo from a test heap instruction, merge the
-%% allocation amounts into the previous bs_init/6 instruction (if any).
-%%
-insert_alloc_in_bs_init([{bs_put,_,_,_}=I|Is], Alloc) ->
- %% The instruction sequence ends with an bs_put/4 instruction.
- %% We'll need to search backwards for the bs_init/6 instruction.
- insert_alloc_1(Is, Alloc, [I]);
-insert_alloc_in_bs_init(_, _) -> impossible.
-
-insert_alloc_1([{bs_init=Op,Fail,Info0,Live,Ss,Dst}|Is],
- {_,nostack,Ws2,[]}, Acc) when is_integer(Live) ->
- %% The number of extra heap words is always in the second position
- %% in the Info tuple.
- Ws1 = element(2, Info0),
- Al = beam_utils:combine_heap_needs(Ws1, Ws2),
- Info = setelement(2, Info0, Al),
- I = {Op,Fail,Info,Live,Ss,Dst},
- reverse(Acc, [I|Is]);
-insert_alloc_1([{bs_put,_,_,_}=I|Is], Alloc, Acc) ->
- insert_alloc_1(Is, Alloc, [I|Acc]).
-
-%% opt(Is0) -> Is
-%% Simple peep-hole optimization to move a {move,Any,{x,0}} past
-%% any kill up to the next call instruction. (To give the loader
-%% an opportunity to combine the 'move' and the 'call' instructions.)
-%%
-opt(Is) ->
- opt_1(Is, []).
-
-opt_1([{move,_,{x,0}}=I|Is0], Acc0) ->
- case move_past_kill(Is0, I, Acc0) of
- impossible -> opt_1(Is0, [I|Acc0]);
- {Is,Acc} -> opt_1(Is, Acc)
- end;
-opt_1([I|Is], Acc) ->
- opt_1(Is, [I|Acc]);
-opt_1([], Acc) -> reverse(Acc).
-
-move_past_kill([{kill,Src}|_], {move,Src,_}, _) ->
- impossible;
-move_past_kill([{kill,_}=I|Is], Move, Acc) ->
- move_past_kill(Is, Move, [I|Acc]);
-move_past_kill([{trim,N,_}=I|Is], {move,Src,Dst}=Move, Acc) ->
- case Src of
- {y,Y} when Y < N-> impossible;
- {y,Y} -> {Is,[{move,{y,Y-N},Dst},I|Acc]};
- _ -> {Is,[Move,I|Acc]}
- end;
-move_past_kill(Is, Move, Acc) ->
- {Is,[Move|Acc]}.
diff --git a/lib/compiler/src/beam_jump.erl b/lib/compiler/src/beam_jump.erl
index 4365451356..74f80ca70e 100644
--- a/lib/compiler/src/beam_jump.erl
+++ b/lib/compiler/src/beam_jump.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@
-module(beam_jump).
-export([module/2,
- is_unreachable_after/1,is_exit_instruction/1,
+ is_exit_instruction/1,
remove_unused_labels/1]).
%%% The following optimisations are done:
@@ -71,9 +71,9 @@
%%%
%%% jump L2
%%% . . .
-%%% L1:
%%% L2: ...
%%%
+%%% and all preceding uses of L1 renamed to L2.
%%% If the jump is unreachable, it will be removed according to (1).
%%%
%%% (5) In
@@ -101,6 +101,10 @@
%%% always keep the label. (beam_clean will remove any unused
%%% labels.)
%%%
+%%% (7) Replace a jump to a return instruction with a return instruction.
+%%% Similarly, replace a jump to deallocate + return with those
+%%% instructions.
+%%%
%%% Note: This modules depends on (almost) all branches and jumps only
%%% going forward, so that we can remove instructions (including definition
%%% of labels) after any label that has not been referenced by the code
@@ -128,27 +132,136 @@
%%% on the program state.
%%%
--import(lists, [reverse/1,reverse/2,foldl/3]).
+-import(lists, [foldl/3,mapfoldl/3,reverse/1,reverse/2]).
-type instruction() :: beam_utils:instruction().
-spec module(beam_utils:module_code(), [compile:option()]) ->
{'ok',beam_utils:module_code()}.
-module({Mod,Exp,Attr,Fs0,Lc}, _Opt) ->
- Fs = [function(F) || F <- Fs0],
+module({Mod,Exp,Attr,Fs0,Lc0}, _Opt) ->
+ {Fs,Lc} = mapfoldl(fun function/2, Lc0, Fs0),
{ok,{Mod,Exp,Attr,Fs,Lc}}.
%% function(Function) -> Function'
%% Optimize jumps and branches.
%%
%% NOTE: This function assumes that there are no labels inside blocks.
-function({function,Name,Arity,CLabel,Asm0}) ->
- Asm1 = share(Asm0),
- Asm2 = move(Asm1),
- Asm3 = opt(Asm2, CLabel),
- Asm = remove_unused_labels(Asm3),
- {function,Name,Arity,CLabel,Asm}.
+function({function,Name,Arity,CLabel,Asm0}, Lc0) ->
+ try
+ Asm1 = eliminate_moves(Asm0),
+ {Asm2,Lc} = insert_labels(Asm1, Lc0, []),
+ Asm3 = share(Asm2),
+ Asm4 = move(Asm3),
+ Asm5 = opt(Asm4, CLabel),
+ Asm6 = unshare(Asm5),
+ Asm = remove_unused_labels(Asm6),
+ {{function,Name,Arity,CLabel,Asm},Lc}
+ catch
+ Class:Error:Stack ->
+ io:fwrite("Function: ~w/~w\n", [Name,Arity]),
+ erlang:raise(Class, Error, Stack)
+ end.
+
+%%%
+%%% Scan instructions in execution order and remove redundant 'move'
+%%% instructions. 'move' instructions are redundant if we know that
+%%% the register already contains the value being assigned, as in the
+%%% following code:
+%%%
+%%% select_val Register FailLabel [... Literal => L1...]
+%%% .
+%%% .
+%%% .
+%%% L1: move Literal Register
+%%%
+
+eliminate_moves(Is) ->
+ eliminate_moves(Is, #{}, []).
+
+eliminate_moves([{select,select_val,Reg,{f,Fail},List}=I|Is], D0, Acc) ->
+ D1 = add_unsafe_label(Fail, D0),
+ D = update_value_dict(List, Reg, D1),
+ eliminate_moves(Is, D, [I|Acc]);
+eliminate_moves([{test,is_eq_exact,_,[Reg,Val]}=I,
+ {block,BlkIs0}|Is], D0, Acc) ->
+ D = update_unsafe_labels(I, D0),
+ RegVal = {Reg,Val},
+ BlkIs = eliminate_moves_blk(BlkIs0, RegVal),
+ eliminate_moves([{block,BlkIs}|Is], D, [I|Acc]);
+eliminate_moves([{label,Lbl},{block,BlkIs0}=Blk|Is], D, Acc0) ->
+ Acc = [{label,Lbl}|Acc0],
+ case {no_fallthrough(Acc0),D} of
+ {true,#{Lbl:={_,_}=RegVal}} ->
+ BlkIs = eliminate_moves_blk(BlkIs0, RegVal),
+ eliminate_moves([{block,BlkIs}|Is], D, Acc);
+ {_,_} ->
+ eliminate_moves([Blk|Is], D, Acc)
+ end;
+eliminate_moves([{block,[]}|Is], D, Acc) ->
+ %% Empty blocks can prevent further jump optimizations.
+ eliminate_moves(Is, D, Acc);
+eliminate_moves([I|Is], D0, Acc) ->
+ D = update_unsafe_labels(I, D0),
+ eliminate_moves(Is, D, [I|Acc]);
+eliminate_moves([], _, Acc) -> reverse(Acc).
+
+eliminate_moves_blk([{set,[Dst],[_],move}|_]=Is, {_,Dst}) ->
+ Is;
+eliminate_moves_blk([{set,[Dst],[Lit],move}|Is], {Dst,Lit}) ->
+ %% Remove redundant 'move' instruction.
+ Is;
+eliminate_moves_blk([{set,[Dst],[_],move}|_]=Is, {Dst,_}) ->
+ Is;
+eliminate_moves_blk([{set,[_],[_],move}=I|Is], {_,_}=RegVal) ->
+ [I|eliminate_moves_blk(Is, RegVal)];
+eliminate_moves_blk(Is, _) -> Is.
+
+no_fallthrough([I|_]) ->
+ is_unreachable_after(I).
+
+update_value_dict([Lit,{f,Lbl}|T], Reg, D0) ->
+ D = case D0 of
+ #{Lbl:=unsafe} -> D0;
+ #{Lbl:={Reg,Lit}} -> D0;
+ #{Lbl:=_} -> D0#{Lbl:=unsafe};
+ #{} -> D0#{Lbl=>{Reg,Lit}}
+ end,
+ update_value_dict(T, Reg, D);
+update_value_dict([], _, D) -> D.
+
+add_unsafe_label(L, D) ->
+ D#{L=>unsafe}.
+
+update_unsafe_labels(I, D) ->
+ Ls = instr_labels(I),
+ update_unsafe_labels_1(Ls, D).
+
+update_unsafe_labels_1([L|Ls], D) ->
+ update_unsafe_labels_1(Ls, D#{L=>unsafe});
+update_unsafe_labels_1([], D) -> D.
+
+%%%
+%%% It seems to be useful to insert extra labels after certain
+%%% test instructions. This used to be done by beam_dead.
+%%%
+
+insert_labels([{test,Op,_,_}=I|Is], Lc, Acc) ->
+ Useful = case Op of
+ is_lt -> true;
+ is_ge -> true;
+ is_eq_exact -> true;
+ is_ne_exact -> true;
+ _ -> false
+ end,
+ case Useful of
+ false -> insert_labels(Is, Lc, [I|Acc]);
+ true -> insert_labels(Is, Lc+1, [{label,Lc},I|Acc])
+ end;
+insert_labels([I|Is], Lc, Acc) ->
+ insert_labels(Is, Lc, [I|Acc]);
+insert_labels([], Lc, Acc) ->
+ {reverse(Acc),Lc}.
%%%
%%% (1) We try to share the code for identical code segments by replacing all
@@ -156,41 +269,51 @@ function({function,Name,Arity,CLabel,Asm0}) ->
%%%
share(Is0) ->
- %% We will get more sharing if we never fall through to a label.
- Is = eliminate_fallthroughs(Is0, []),
- share_1(Is, #{}, [], []).
+ Is1 = eliminate_fallthroughs(Is0, []),
+ Is2 = find_fixpoint(fun(Is) ->
+ share_1(Is, #{}, #{}, [], [])
+ end, Is1),
+ reverse(Is2).
-share_1([{label,L}=Lbl|Is], Dict0, [_|_]=Seq, Acc) ->
+share_1([{label,L}=Lbl|Is], Dict0, Lbls0, [_|_]=Seq, Acc) ->
case maps:find(Seq, Dict0) of
- error ->
- Dict = maps:put(Seq, L, Dict0),
- share_1(Is, Dict, [], [Lbl|Seq ++ Acc]);
- {ok,Label} ->
- share_1(Is, Dict0, [], [Lbl,{jump,{f,Label}}|Acc])
+ error ->
+ Dict = maps:put(Seq, L, Dict0),
+ share_1(Is, Dict, Lbls0, [], [[Lbl|Seq]|Acc]);
+ {ok,Label} ->
+ Lbls = maps:put(L, Label, Lbls0),
+ share_1(Is, Dict0, Lbls, [], [[Lbl,{jump,{f,Label}}]|Acc])
end;
-share_1([{func_info,_,_,_}=I|Is], _, [], Acc) ->
- reverse(Is, [I|Acc]);
-share_1([{'catch',_,_}=I|Is], Dict0, Seq, Acc) ->
- Dict = clean_non_sharable(Dict0),
- share_1(Is, Dict, [I|Seq], Acc);
-share_1([{'try',_,_}=I|Is], Dict0, Seq, Acc) ->
- Dict = clean_non_sharable(Dict0),
- share_1(Is, Dict, [I|Seq], Acc);
-share_1([{try_case,_}=I|Is], Dict0, Seq, Acc) ->
- Dict = clean_non_sharable(Dict0),
- share_1(Is, Dict, [I|Seq], Acc);
-share_1([{catch_end,_}=I|Is], Dict0, Seq, Acc) ->
- Dict = clean_non_sharable(Dict0),
- share_1(Is, Dict, [I|Seq], Acc);
-share_1([I|Is], Dict, Seq, Acc) ->
+share_1([{func_info,_,_,_}|_]=Is0, _, Lbls, [], Acc0) when Lbls =/= #{} ->
+ lists:foldl(fun(Is, Acc) ->
+ beam_utils:replace_labels(Is, Acc, Lbls, fun(Old) -> Old end)
+ end, Is0, Acc0);
+share_1([{func_info,_,_,_}|_]=Is, _, Lbls, [], Acc) when Lbls =:= #{} ->
+ lists:foldl(fun lists:reverse/2, Is, Acc);
+share_1([{'catch',_,_}=I|Is], Dict0, Lbls0, Seq, Acc) ->
+ {Dict,Lbls} = clean_non_sharable(Dict0, Lbls0),
+ share_1(Is, Dict, Lbls, [I|Seq], Acc);
+share_1([{'try',_,_}=I|Is], Dict0, Lbls0, Seq, Acc) ->
+ {Dict,Lbls} = clean_non_sharable(Dict0, Lbls0),
+ share_1(Is, Dict, Lbls, [I|Seq], Acc);
+share_1([{try_case,_}=I|Is], Dict0, Lbls0, Seq, Acc) ->
+ {Dict,Lbls} = clean_non_sharable(Dict0, Lbls0),
+ share_1(Is, Dict, Lbls, [I|Seq], Acc);
+share_1([{catch_end,_}=I|Is], Dict0, Lbls0, Seq, Acc) ->
+ {Dict,Lbls} = clean_non_sharable(Dict0, Lbls0),
+ share_1(Is, Dict, Lbls, [I|Seq], Acc);
+share_1([{jump,{f,To}}=I,{label,L}=Lbl|Is], Dict0, Lbls0, _Seq, Acc) ->
+ Lbls = maps:put(L, To, Lbls0),
+ share_1(Is, Dict0, Lbls, [], [[Lbl,I]|Acc]);
+share_1([I|Is], Dict, Lbls, Seq, Acc) ->
case is_unreachable_after(I) of
false ->
- share_1(Is, Dict, [I|Seq], Acc);
+ share_1(Is, Dict, Lbls, [I|Seq], Acc);
true ->
- share_1(Is, Dict, [I], Acc)
+ share_1(Is, Dict, Lbls, [I], Acc)
end.
-clean_non_sharable(Dict) ->
+clean_non_sharable(Dict0, Lbls0) ->
%% We are passing in or out of a 'catch' or 'try' block. Remove
%% sequences that should not be shared over the boundaries of the
%% block. Since the end of the sequence must match, the only
@@ -198,7 +321,17 @@ clean_non_sharable(Dict) ->
%% the 'catch'/'try' block is a sequence that ends with an
%% instruction that causes an exception. Any sequence that causes
%% an exception must contain a line/1 instruction.
- maps:filter(fun(K, _V) -> sharable_with_try(K) end, Dict).
+ Dict1 = maps:to_list(Dict0),
+ Lbls1 = maps:to_list(Lbls0),
+ {Dict2,Lbls2} = foldl(fun({K, V}, {Dict,Lbls}) ->
+ case sharable_with_try(K) of
+ true ->
+ {[{K,V}|Dict],lists:keydelete(V, 2, Lbls)};
+ false ->
+ {Dict,Lbls}
+ end
+ end, {[],Lbls1}, Dict1),
+ {maps:from_list(Dict2),maps:from_list(Lbls2)}.
sharable_with_try([{line,_}|_]) ->
%% This sequence may cause an exception and may potentially
@@ -251,8 +384,6 @@ extract_seq([{line,_}=Line|Is], Acc) ->
extract_seq(Is, [Line|Acc]);
extract_seq([{block,_}=Bl|Is], Acc) ->
extract_seq_1(Is, [Bl|Acc]);
-extract_seq([{bs_context_to_binary,_}=I|Is], Acc) ->
- extract_seq_1(Is, [I|Acc]);
extract_seq([{label,_}|_]=Is, Acc) ->
extract_seq_1(Is, Acc);
extract_seq(_, _) -> no.
@@ -275,14 +406,14 @@ extract_seq_1(_, _) -> no.
-record(st,
{
entry :: beam_asm:label(), %Entry label (must not be moved).
- mlbl :: #{beam_asm:label() := [beam_asm:label()]}, %Moved labels.
+ replace :: #{beam_asm:label() := beam_asm:label()}, %Labels to replace.
labels :: cerl_sets:set() %Set of referenced labels.
}).
opt(Is0, CLabel) ->
find_fixpoint(fun(Is) ->
Lbls = initial_labels(Is),
- St = #st{entry=CLabel,mlbl=#{},labels=Lbls},
+ St = #st{entry=CLabel,replace=#{},labels=Lbls},
opt(Is, [], St)
end, Is0).
@@ -326,30 +457,16 @@ opt([{test,_,{f,_}=Lbl,_,_,_}=I|Is], Acc, St) ->
opt(Is, [I|Acc], label_used(Lbl, St));
opt([{select,_,_R,Fail,Vls}=I|Is], Acc, St) ->
skip_unreachable(Is, [I|Acc], label_used([Fail|Vls], St));
-opt([{label,Lbl}=I|Is], Acc, #st{mlbl=Mlbl}=St0) ->
- case maps:find(Lbl, Mlbl) of
- {ok,Lbls} ->
- %% Essential to remove the list of labels from the dictionary,
- %% since we will rescan the inserted labels. We MUST rescan.
- St = St0#st{mlbl=maps:remove(Lbl, Mlbl)},
- insert_labels([Lbl|Lbls], Is, Acc, St);
- error ->
- opt(Is, [I|Acc], St0)
- end;
+opt([{label,From}=I,{label,To}|Is], Acc, #st{replace=Replace}=St) ->
+ opt([I|Is], Acc, St#st{replace=Replace#{To => From}});
opt([{jump,{f,_}=X}|[{label,_},{jump,X}|_]=Is], Acc, St) ->
opt(Is, Acc, St);
opt([{jump,{f,Lbl}}|[{label,Lbl}|_]=Is], Acc, St) ->
opt(Is, Acc, St);
-opt([{jump,{f,L}=Lbl}=I|Is], Acc0, #st{mlbl=Mlbl0}=St0) ->
- %% All labels before this jump instruction should now be
- %% moved to the location of the jump's target.
- {Lbls,Acc} = collect_labels(Acc0, St0),
- St = case Lbls of
- [] -> St0;
- [_|_] ->
- Mlbl = maps_append_list(L, Lbls, Mlbl0),
- St0#st{mlbl=Mlbl}
- end,
+opt([{jump,{f,L}=Lbl}=I|Is], Acc0, St0) ->
+ %% Replace all labels before this jump instruction into the
+ %% location of the jump's target.
+ {Acc,St} = collect_labels(Acc0, L, St0),
skip_unreachable(Is, [I|Acc], label_used(Lbl, St));
%% Optimization: quickly handle some common instructions that don't
%% have any failure labels and where is_unreachable_after(I) =:= false.
@@ -369,36 +486,32 @@ opt([I|Is], Acc, #st{labels=Used0}=St0) ->
true -> skip_unreachable(Is, [I|Acc], St);
false -> opt(Is, [I|Acc], St)
end;
-opt([], Acc, #st{mlbl=Mlbl}) ->
- Code = reverse(Acc),
- insert_fc_labels(Code, Mlbl).
-
-insert_fc_labels([{label,L}=I|Is0], Mlbl) ->
- case maps:find(L, Mlbl) of
- error ->
- [I|insert_fc_labels(Is0, Mlbl)];
- {ok,Lbls} ->
- Is = [{label,Lb} || Lb <- Lbls] ++ Is0,
- [I|insert_fc_labels(Is, maps:remove(L, Mlbl))]
+opt([], Acc, #st{replace=Replace0}) when Replace0 =/= #{} ->
+ Replace = normalize_replace(maps:to_list(Replace0), Replace0, []),
+ beam_utils:replace_labels(Acc, [], Replace, fun(Old) -> Old end);
+opt([], Acc, #st{replace=Replace}) when Replace =:= #{} ->
+ reverse(Acc).
+
+normalize_replace([{From,To0}|Rest], Replace, Acc) ->
+ case Replace of
+ #{To0 := To} ->
+ normalize_replace([{From,To}|Rest], Replace, Acc);
+ _ ->
+ normalize_replace(Rest, Replace, [{From,To0}|Acc])
end;
-insert_fc_labels([_|_]=Is, _) -> Is.
-
-maps_append_list(K,Vs,M) ->
- case M of
- #{K:=Vs0} -> M#{K:=Vs0++Vs}; % same order as dict
- _ -> M#{K => Vs}
- end.
+normalize_replace([], _Replace, Acc) ->
+ maps:from_list(Acc).
-collect_labels(Is, #st{entry=Entry}) ->
- collect_labels_1(Is, Entry, []).
+collect_labels(Is, Label, #st{entry=Entry,replace=Replace} = St) ->
+ collect_labels_1(Is, Label, Entry, Replace, St).
-collect_labels_1([{label,Entry}|_]=Is, Entry, Acc) ->
+collect_labels_1([{label,Entry}|_]=Is, _Label, Entry, Acc, St) ->
%% Never move the entry label.
- {Acc,Is};
-collect_labels_1([{label,L}|Is], Entry, Acc) ->
- collect_labels_1(Is, Entry, [L|Acc]);
-collect_labels_1(Is, _Entry, Acc) ->
- {Acc,Is}.
+ {Is,St#st{replace=Acc}};
+collect_labels_1([{label,L}|Is], Label, Entry, Acc, St) ->
+ collect_labels_1(Is, Label, Entry, Acc#{L => Label}, St);
+collect_labels_1(Is, _Label, _Entry, Acc, St) ->
+ {Is,St#st{replace=Acc}}.
%% label_defined(Is, Label) -> true | false.
%% Test whether the label Label is defined at the start of the instruction
@@ -418,13 +531,6 @@ invert_test(is_eq_exact) -> is_ne_exact;
invert_test(is_ne_exact) -> is_eq_exact;
invert_test(_) -> not_possible.
-insert_labels([L|Ls], Is, [{jump,{f,L}}|Acc], St) ->
- insert_labels(Ls, [{label,L}|Is], Acc, St);
-insert_labels([L|Ls], Is, Acc, St) ->
- insert_labels(Ls, [{label,L}|Is], Acc, St);
-insert_labels([], Is, Acc, St) ->
- opt(Is, Acc, St).
-
%% skip_unreachable([Instruction], St).
%% Remove all instructions (including definitions of labels
%% that have not been referenced yet) up to the next
@@ -522,52 +628,109 @@ drop_upto_label([{label,_}|_]=Is) -> Is;
drop_upto_label([_|Is]) -> drop_upto_label(Is);
drop_upto_label([]) -> [].
-%% ulbl(Instruction, UsedGbSet) -> UsedGbSet'
-%% Update the gb_set UsedGbSet with any function-local labels
+%% unshare([Instruction]) -> [Instruction].
+%% Replace a jump to a return sequence (a `return` instruction
+%% optionally preced by a `deallocate` instruction) with the return
+%% sequence. This always saves execution time and may also save code
+%% space (depending on the architecture). Eliminating `jump`
+%% instructions also gives beam_trim more opportunities to trim the
+%% stack.
+
+unshare(Is) ->
+ Short = unshare_collect_short(Is, #{}),
+ unshare_short(Is, Short).
+
+unshare_collect_short([{label,L},return|Is], Map) ->
+ unshare_collect_short(Is, Map#{L=>[return]});
+unshare_collect_short([{label,L},{deallocate,_}=D,return|Is], Map) ->
+ %% `deallocate` and `return` are combined into one instruction by
+ %% the loader.
+ unshare_collect_short(Is, Map#{L=>[D,return]});
+unshare_collect_short([_|Is], Map) ->
+ unshare_collect_short(Is, Map);
+unshare_collect_short([], Map) -> Map.
+
+unshare_short([{jump,{f,F}}=I|Is], Map) ->
+ case Map of
+ #{F:=Seq} ->
+ Seq ++ unshare_short(Is, Map);
+ #{} ->
+ [I|unshare_short(Is, Map)]
+ end;
+unshare_short([I|Is], Map) ->
+ [I|unshare_short(Is, Map)];
+unshare_short([], _Map) -> [].
+
+%% ulbl(Instruction, UsedCerlSet) -> UsedCerlSet'
+%% Update the cerl_set UsedCerlSet with any function-local labels
%% (i.e. not with labels in call instructions) referenced by
%% the instruction Instruction.
%%
%% NOTE: This function does NOT look for labels inside blocks.
-ulbl({test,_,Fail,_}, Used) ->
- mark_used(Fail, Used);
-ulbl({test,_,Fail,_,_,_}, Used) ->
- mark_used(Fail, Used);
-ulbl({select,_,_,Fail,Vls}, Used) ->
- mark_used_list(Vls, mark_used(Fail, Used));
-ulbl({'try',_,Lbl}, Used) ->
- mark_used(Lbl, Used);
-ulbl({'catch',_,Lbl}, Used) ->
- mark_used(Lbl, Used);
-ulbl({jump,Lbl}, Used) ->
- mark_used(Lbl, Used);
-ulbl({loop_rec,Lbl,_}, Used) ->
- mark_used(Lbl, Used);
-ulbl({loop_rec_end,Lbl}, Used) ->
- mark_used(Lbl, Used);
-ulbl({wait,Lbl}, Used) ->
- mark_used(Lbl, Used);
-ulbl({wait_timeout,Lbl,_To}, Used) ->
- mark_used(Lbl, Used);
-ulbl({bif,_Name,Lbl,_As,_R}, Used) ->
- mark_used(Lbl, Used);
-ulbl({gc_bif,_Name,Lbl,_Live,_As,_R}, Used) ->
- mark_used(Lbl, Used);
-ulbl({bs_init,Lbl,_,_,_,_}, Used) ->
- mark_used(Lbl, Used);
-ulbl({bs_put,Lbl,_,_}, Used) ->
- mark_used(Lbl, Used);
-ulbl({put_map,Lbl,_Op,_Src,_Dst,_Live,_List}, Used) ->
- mark_used(Lbl, Used);
-ulbl({get_map_elements,Lbl,_Src,_List}, Used) ->
- mark_used(Lbl, Used);
-ulbl(_, Used) -> Used.
-
-mark_used({f,0}, Used) -> Used;
-mark_used({f,L}, Used) -> cerl_sets:add_element(L, Used).
-
-mark_used_list([{f,L}|T], Used) ->
- mark_used_list(T, cerl_sets:add_element(L, Used));
-mark_used_list([_|T], Used) ->
- mark_used_list(T, Used);
-mark_used_list([], Used) -> Used.
+ulbl(I, Used) ->
+ case instr_labels(I) of
+ [] ->
+ Used;
+ [Lbl] ->
+ cerl_sets:add_element(Lbl, Used);
+ [_|_]=L ->
+ ulbl_list(L, Used)
+ end.
+
+ulbl_list([L|Ls], Used) ->
+ ulbl_list(Ls, cerl_sets:add_element(L, Used));
+ulbl_list([], Used) -> Used.
+
+-spec instr_labels(Instruction) -> Labels when
+ Instruction :: instruction(),
+ Labels :: [beam_asm:label()].
+
+instr_labels({test,_,Fail,_}) ->
+ do_instr_labels(Fail);
+instr_labels({test,_,Fail,_,_,_}) ->
+ do_instr_labels(Fail);
+instr_labels({select,_,_,Fail,Vls}) ->
+ do_instr_labels_list(Vls, do_instr_labels(Fail));
+instr_labels({'try',_,Lbl}) ->
+ do_instr_labels(Lbl);
+instr_labels({'catch',_,Lbl}) ->
+ do_instr_labels(Lbl);
+instr_labels({jump,Lbl}) ->
+ do_instr_labels(Lbl);
+instr_labels({loop_rec,Lbl,_}) ->
+ do_instr_labels(Lbl);
+instr_labels({loop_rec_end,Lbl}) ->
+ do_instr_labels(Lbl);
+instr_labels({wait,Lbl}) ->
+ do_instr_labels(Lbl);
+instr_labels({wait_timeout,Lbl,_To}) ->
+ do_instr_labels(Lbl);
+instr_labels({bif,_Name,Lbl,_As,_R}) ->
+ do_instr_labels(Lbl);
+instr_labels({gc_bif,_Name,Lbl,_Live,_As,_R}) ->
+ do_instr_labels(Lbl);
+instr_labels({bs_init,Lbl,_,_,_,_}) ->
+ do_instr_labels(Lbl);
+instr_labels({bs_put,Lbl,_,_}) ->
+ do_instr_labels(Lbl);
+instr_labels({put_map,Lbl,_Op,_Src,_Dst,_Live,_List}) ->
+ do_instr_labels(Lbl);
+instr_labels({get_map_elements,Lbl,_Src,_List}) ->
+ do_instr_labels(Lbl);
+instr_labels({recv_mark,Lbl}) ->
+ do_instr_labels(Lbl);
+instr_labels({recv_set,Lbl}) ->
+ do_instr_labels(Lbl);
+instr_labels({fcheckerror,Lbl}) ->
+ do_instr_labels(Lbl);
+instr_labels(_) -> [].
+
+do_instr_labels({f,0}) -> [];
+do_instr_labels({f,F}) -> [F].
+
+do_instr_labels_list([{f,F}|T], Acc) ->
+ do_instr_labels_list(T, [F|Acc]);
+do_instr_labels_list([_|T], Acc) ->
+ do_instr_labels_list(T, Acc);
+do_instr_labels_list([], Acc) -> Acc.
diff --git a/lib/compiler/src/beam_kernel_to_ssa.erl b/lib/compiler/src/beam_kernel_to_ssa.erl
new file mode 100644
index 0000000000..df95749fb3
--- /dev/null
+++ b/lib/compiler/src/beam_kernel_to_ssa.erl
@@ -0,0 +1,1312 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% Purpose: Convert the Kernel Erlang format to the SSA format.
+
+-module(beam_kernel_to_ssa).
+
+%% The main interface.
+-export([module/2]).
+
+-import(lists, [append/1,duplicate/2,flatmap/2,foldl/3,
+ keysort/2,mapfoldl/3,map/2,member/2,
+ reverse/1,reverse/2,sort/1]).
+
+-include("v3_kernel.hrl").
+-include("beam_ssa.hrl").
+
+-type label() :: beam_ssa:label().
+
+%% Main codegen structure.
+-record(cg, {lcount=1 :: label(), %Label counter
+ bfail=1 :: label(),
+ catch_label=none :: 'none' | label(),
+ vars=#{} :: map(), %Defined variables.
+ break=0 :: label(), %Break label
+ recv=0 :: label(), %Receive label
+ ultimate_failure=0 :: label() %Label for ultimate match failure.
+ }).
+
+%% Internal records.
+-record(cg_break, {args :: [beam_ssa:value()],
+ phi :: label()
+ }).
+-record(cg_phi, {vars :: [beam_ssa:b_var()]
+ }).
+-record(cg_unreachable, {}).
+
+-spec module(#k_mdef{}, [compile:option()]) -> {'ok',#b_module{}}.
+
+module(#k_mdef{name=Mod,exports=Es,attributes=Attr,body=Forms}, _Opts) ->
+ Body = functions(Forms, Mod),
+ Module = #b_module{name=Mod,exports=Es,attributes=Attr,body=Body},
+ {ok,Module}.
+
+functions(Forms, Mod) ->
+ [function(F, Mod) || F <- Forms].
+
+function(#k_fdef{anno=Anno0,func=Name,arity=Arity,
+ vars=As0,body=Kb}, Mod) ->
+ try
+ #k_match{} = Kb, %Assertion.
+
+ %% Generate the SSA form immediate format.
+ St0 = #cg{},
+ {As,St1} = new_ssa_vars(As0, St0),
+ {Asm,St} = cg_fun(Kb, St1),
+ Anno1 = line_anno(Anno0),
+ Anno = Anno1#{func_info=>{Mod,Name,Arity}},
+ #b_function{anno=Anno,args=As,bs=Asm,cnt=St#cg.lcount}
+ catch
+ Class:Error:Stack ->
+ io:fwrite("Function: ~w/~w\n", [Name,Arity]),
+ erlang:raise(Class, Error, Stack)
+ end.
+
+%% cg_fun([Lkexpr], [HeadVar], State) -> {[Ainstr],State}
+
+cg_fun(Ke, St0) ->
+ {UltimateFail,FailIs,St1} = make_failure(badarg, St0),
+ St2 = St1#cg{bfail=UltimateFail,ultimate_failure=UltimateFail},
+ {B,St} = cg(Ke, St2),
+ Asm = [{label,0}|B++FailIs],
+ finalize(Asm, St).
+
+make_failure(Reason, St0) ->
+ {Lbl,St1} = new_label(St0),
+ {Dst,St} = new_ssa_var('@ssa_ret', St1),
+ Is = [{label,Lbl},
+ #b_set{op=call,dst=Dst,
+ args=[#b_remote{mod=#b_literal{val=erlang},
+ name=#b_literal{val=error},
+ arity=1},
+ #b_literal{val=Reason}]},
+ #b_ret{arg=Dst}],
+ {Lbl,Is,St}.
+
+%% cg(Lkexpr, State) -> {[Ainstr],State}.
+%% Generate code for a kexpr.
+
+cg(#k_match{body=M,ret=Rs}, St) ->
+ do_match_cg(M, Rs, St);
+cg(#k_guard_match{body=M,ret=Rs}, St) ->
+ do_match_cg(M, Rs, St);
+cg(#k_seq{arg=Arg,body=Body}, St0) ->
+ {ArgIs,St1} = cg(Arg, St0),
+ {BodyIs,St} = cg(Body, St1),
+ {ArgIs++BodyIs,St};
+cg(#k_call{anno=Le,op=Func,args=As,ret=Rs}, St) ->
+ call_cg(Func, As, Rs, Le, St);
+cg(#k_enter{anno=Le,op=Func,args=As}, St) ->
+ enter_cg(Func, As, Le, St);
+cg(#k_bif{anno=Le}=Bif, St) ->
+ bif_cg(Bif, Le, St);
+cg(#k_try{arg=Ta,vars=Vs,body=Tb,evars=Evs,handler=Th,ret=Rs}, St) ->
+ try_cg(Ta, Vs, Tb, Evs, Th, Rs, St);
+cg(#k_try_enter{arg=Ta,vars=Vs,body=Tb,evars=Evs,handler=Th}, St) ->
+ try_enter_cg(Ta, Vs, Tb, Evs, Th, St);
+cg(#k_catch{body=Cb,ret=[R]}, St) ->
+ do_catch_cg(Cb, R, St);
+cg(#k_receive{anno=Le,timeout=Te,var=Rvar,body=Rm,action=Tes,ret=Rs}, St) ->
+ recv_loop_cg(Te, Rvar, Rm, Tes, Rs, Le, St);
+cg(#k_receive_next{}, #cg{recv=Recv}=St) ->
+ Is = [#b_set{op=recv_next},make_uncond_branch(Recv)],
+ {Is,St};
+cg(#k_receive_accept{}, St) ->
+ Remove = #b_set{op=remove_message},
+ {[Remove],St};
+cg(#k_put{anno=Le,arg=Con,ret=Var}, St) ->
+ put_cg(Var, Con, Le, St);
+cg(#k_return{args=[Ret0]}, St) ->
+ Ret = ssa_arg(Ret0, St),
+ {[#b_ret{arg=Ret}],St};
+cg(#k_break{args=Bs}, #cg{break=Br}=St) ->
+ Args = ssa_args(Bs, St),
+ {[#cg_break{args=Args,phi=Br}],St};
+cg(#k_guard_break{args=Bs}, St) ->
+ cg(#k_break{args=Bs}, St).
+
+%% match_cg(Matc, [Ret], State) -> {[Ainstr],State}.
+%% Generate code for a match.
+
+do_match_cg(M, Rs, St0) ->
+ {B,St1} = new_label(St0),
+ {Mis,St2} = match_cg(M, St1#cg.bfail, St1#cg{break=B}),
+ {BreakVars,St} = new_ssa_vars(Rs, St2),
+ {Mis ++ [{label,B},#cg_phi{vars=BreakVars}],
+ St#cg{bfail=St0#cg.bfail,break=St1#cg.break}}.
+
+%% match_cg(Match, Fail, State) -> {[Ainstr],State}.
+%% Generate code for a match tree.
+
+match_cg(#k_alt{first=F,then=S}, Fail, St0) ->
+ {Tf,St1} = new_label(St0),
+ {Fis,St2} = match_cg(F, Tf, St1),
+ {Sis,St3} = match_cg(S, Fail, St2),
+ {Fis ++ [{label,Tf}] ++ Sis,St3};
+match_cg(#k_select{var=#k_var{}=V,types=Scs}, Fail, St) ->
+ match_fmf(fun (S, F, Sta) ->
+ select_cg(S, V, F, Fail, Sta)
+ end, Fail, St, Scs);
+match_cg(#k_guard{clauses=Gcs}, Fail, St) ->
+ match_fmf(fun (G, F, Sta) ->
+ guard_clause_cg(G, F, Sta)
+ end, Fail, St, Gcs);
+match_cg(Ke, _Fail, St0) ->
+ cg(Ke, St0).
+
+%% select_cg(Sclause, V, TypeFail, ValueFail, State) -> {Is,State}.
+%% Selecting type and value needs two failure labels, TypeFail is the
+%% label to jump to of the next type test when this type fails, and
+%% ValueFail is the label when this type is correct but the value is
+%% wrong. These are different as in the second case there is no need
+%% to try the next type, it will always fail.
+
+select_cg(#k_type_clause{type=k_binary,values=[S]}, Var, Tf, Vf, St) ->
+ select_binary(S, Var, Tf, Vf, St);
+select_cg(#k_type_clause{type=k_bin_seg,values=Vs}, Var, Tf, _Vf, St) ->
+ select_bin_segs(Vs, Var, Tf, St);
+select_cg(#k_type_clause{type=k_bin_int,values=Vs}, Var, Tf, _Vf, St) ->
+ select_bin_segs(Vs, Var, Tf, St);
+select_cg(#k_type_clause{type=k_bin_end,values=[S]}, Var, Tf, _Vf, St) ->
+ select_bin_end(S, Var, Tf, St);
+select_cg(#k_type_clause{type=k_map,values=Vs}, Var, Tf, Vf, St) ->
+ select_map(Vs, Var, Tf, Vf, St);
+select_cg(#k_type_clause{type=k_cons,values=[S]}, Var, Tf, Vf, St) ->
+ select_cons(S, Var, Tf, Vf, St);
+select_cg(#k_type_clause{type=k_nil,values=[S]}, Var, Tf, Vf, St) ->
+ select_nil(S, Var, Tf, Vf, St);
+select_cg(#k_type_clause{type=k_literal,values=Vs}, Var, Tf, Vf, St) ->
+ select_literal(Vs, Var, Tf, Vf, St);
+select_cg(#k_type_clause{type=Type,values=Scs}, Var, Tf, Vf, St0) ->
+ {Vis,St1} =
+ mapfoldl(fun (S, Sta) ->
+ {Val,Is,Stb} = select_val(S, Var, Vf, Sta),
+ {{Is,[Val]},Stb}
+ end, St0, Scs),
+ OptVls = combine(lists:sort(combine(Vis))),
+ {Vls,Sis,St2} = select_labels(OptVls, St1, [], []),
+ Arg = ssa_arg(Var, St2),
+ {Is,St} = select_val_cg(Type, Arg, Vls, Tf, Vf, Sis, St2),
+ {Is,St}.
+
+select_val_cg(k_tuple, Tuple, Vls, Tf, Vf, Sis, St0) ->
+ {Is0,St1} = make_cond_branch({bif,is_tuple}, [Tuple], Tf, St0),
+ {Arity,St2} = new_ssa_var('@ssa_arity', St1),
+ GetArity = #b_set{op={bif,tuple_size},dst=Arity,args=[Tuple]},
+ {Is,St} = select_val_cg(k_int, Arity, Vls, Vf, Vf, Sis, St2),
+ {Is0++[GetArity]++Is,St};
+select_val_cg(Type, R, Vls, Tf, Vf, Sis, St0) ->
+ {TypeIs,St1} = if
+ Tf =:= Vf ->
+ %% The type and value failure labels are the same;
+ %% we don't need a type test.
+ {[],St0};
+ true ->
+ %% Different labels for type failure and
+ %% label failure; we need a type test.
+ Test = select_type_test(Type),
+ make_cond_branch(Test, [R], Tf, St0)
+ end,
+ case Vls of
+ [{Val,Succ}] ->
+ {Is,St} = make_cond({bif,'=:='}, [R,Val], Vf, Succ, St1),
+ {TypeIs++Is++Sis,St};
+ [_|_] ->
+ {TypeIs++[#b_switch{arg=R,fail=Vf,list=Vls}|Sis],St1}
+ end.
+
+select_type_test(k_int) -> {bif,is_integer};
+select_type_test(k_atom) -> {bif,is_atom};
+select_type_test(k_float) -> {bif,is_float}.
+
+combine([{Is,Vs1},{Is,Vs2}|Vis]) -> combine([{Is,Vs1 ++ Vs2}|Vis]);
+combine([V|Vis]) -> [V|combine(Vis)];
+combine([]) -> [].
+
+select_labels([{Is,Vs}|Vis], St0, Vls, Sis) ->
+ {Lbl,St1} = new_label(St0),
+ select_labels(Vis, St1, add_vls(Vs, Lbl, Vls), [[{label,Lbl}|Is]|Sis]);
+select_labels([], St, Vls, Sis) ->
+ {Vls,append(Sis),St}.
+
+add_vls([V|Vs], Lbl, Acc) ->
+ add_vls(Vs, Lbl, [{#b_literal{val=V},Lbl}|Acc]);
+add_vls([], _, Acc) -> Acc.
+
+select_literal(S, V, Tf, Vf, St) ->
+ Src = ssa_arg(V, St),
+ F = fun(ValClause, Fail, St0) ->
+ {Val,ValIs,St1} = select_val(ValClause, V, Vf, St0),
+ Args = [Src,#b_literal{val=Val}],
+ {Is,St2} = make_cond_branch({bif,'=:='}, Args, Fail, St1),
+ {Is++ValIs,St2}
+ end,
+ match_fmf(F, Tf, St, S).
+
+select_cons(#k_val_clause{val=#k_cons{hd=Hd,tl=Tl},body=B},
+ V, Tf, Vf, St0) ->
+ Es = [Hd,Tl],
+ {Eis,St1} = select_extract_cons(V, Es, St0),
+ {Bis,St2} = match_cg(B, Vf, St1),
+ Src = ssa_arg(V, St2),
+ {Is,St} = make_cond_branch(is_nonempty_list, [Src], Tf, St2),
+ {Is ++ Eis ++ Bis,St}.
+
+select_nil(#k_val_clause{val=#k_nil{},body=B}, V, Tf, Vf, St0) ->
+ {Bis,St1} = match_cg(B, Vf, St0),
+ Src = ssa_arg(V, St1),
+ {Is,St} = make_cond_branch({bif,'=:='}, [Src,#b_literal{val=[]}], Tf, St1),
+ {Is ++ Bis,St}.
+
+select_binary(#k_val_clause{val=#k_binary{segs=#k_var{name=Ctx0}},body=B},
+ #k_var{}=Src, Tf, Vf, St0) ->
+ {Ctx,St1} = new_ssa_var(Ctx0, St0),
+ {Bis0,St2} = match_cg(B, Vf, St1),
+ {TestIs,St} = make_cond_branch(succeeded, [Ctx], Tf, St2),
+ Bis1 = [#b_set{op=bs_start_match,dst=Ctx,
+ args=[ssa_arg(Src, St)]}] ++ TestIs ++ Bis0,
+ Bis = finish_bs_matching(Bis1),
+ {Bis,St}.
+
+finish_bs_matching([#b_set{op=bs_match,
+ args=[#b_literal{val=string},Ctx,#b_literal{val=BinList}]}=Set|Is])
+ when is_list(BinList) ->
+ I = Set#b_set{args=[#b_literal{val=string},Ctx,
+ #b_literal{val=list_to_bitstring(BinList)}]},
+ finish_bs_matching([I|Is]);
+finish_bs_matching([I|Is]) ->
+ [I|finish_bs_matching(Is)];
+finish_bs_matching([]) -> [].
+
+make_cond(Cond, Args, Fail, Succ, St0) ->
+ {Bool,St} = new_ssa_var('@ssa_bool', St0),
+ Bif = #b_set{op=Cond,dst=Bool,args=Args},
+ Br = #b_br{bool=Bool,succ=Succ,fail=Fail},
+ {[Bif,Br],St}.
+
+make_cond_branch(Cond, Args, Fail, St0) ->
+ {Bool,St1} = new_ssa_var('@ssa_bool', St0),
+ {Succ,St} = new_label(St1),
+ Bif = #b_set{op=Cond,dst=Bool,args=Args},
+ Br = #b_br{bool=Bool,succ=Succ,fail=Fail},
+ {[Bif,Br,{label,Succ}],St}.
+
+make_uncond_branch(Fail) ->
+ #b_br{bool=#b_literal{val=true},succ=Fail,fail=Fail}.
+
+%% Instructions for selection of binary segments.
+
+select_bin_segs(Scs, Ivar, Tf, St) ->
+ match_fmf(fun(S, Fail, Sta) ->
+ select_bin_seg(S, Ivar, Fail, Sta)
+ end, Tf, St, Scs).
+
+select_bin_seg(#k_val_clause{val=#k_bin_seg{size=Size,unit=U,type=T,
+ seg=Seg,flags=Fs,next=Next},
+ body=B,anno=Anno},
+ #k_var{}=Src, Fail, St0) ->
+ LineAnno = line_anno(Anno),
+ Ctx = get_context(Src, St0),
+ {Mis,St1} = select_extract_bin(Next, Size, U, T, Fs, Fail,
+ Ctx, LineAnno, St0),
+ {Extracted,St2} = new_ssa_var(Seg#k_var.name, St1),
+ {Bis,St} = match_cg(B, Fail, St2),
+ BsGet = #b_set{op=bs_extract,dst=Extracted,args=[ssa_arg(Next, St)]},
+ Is = Mis ++ [BsGet] ++ Bis,
+ {Is,St};
+select_bin_seg(#k_val_clause{val=#k_bin_int{size=Sz,unit=U,flags=Fs,
+ val=Val,next=Next},
+ body=B},
+ #k_var{}=Src, Fail, St0) ->
+ Ctx = get_context(Src, St0),
+ {Mis,St1} = select_extract_int(Next, Val, Sz, U, Fs, Fail,
+ Ctx, St0),
+ {Bis,St} = match_cg(B, Fail, St1),
+ Is = case Mis ++ Bis of
+ [#b_set{op=bs_match,args=[#b_literal{val=string},OtherCtx1,Bin1]},
+ #b_set{op=succeeded,dst=Bool1},
+ #b_br{bool=Bool1,succ=Succ,fail=Fail},
+ {label,Succ},
+ #b_set{op=bs_match,dst=Dst,args=[#b_literal{val=string},_OtherCtx2,Bin2]}|
+ [#b_set{op=succeeded,dst=Bool2},
+ #b_br{bool=Bool2,fail=Fail}|_]=Is0] ->
+ %% We used to do this optimization later, but it
+ %% turns out that in huge functions with many
+ %% string matching instructions, it's a huge win
+ %% to do the combination now. To avoid copying the
+ %% binary data again and again, we'll combine bitstrings
+ %% in a list and convert all of it to a bitstring later.
+ {#b_literal{val=B1},#b_literal{val=B2}} = {Bin1,Bin2},
+ Bin = #b_literal{val=[B1,B2]},
+ Set = #b_set{op=bs_match,dst=Dst,args=[#b_literal{val=string},OtherCtx1,Bin]},
+ [Set|Is0];
+ Is0 ->
+ Is0
+ end,
+ {Is,St}.
+
+get_context(#k_var{}=Var, St) ->
+ ssa_arg(Var, St).
+
+select_bin_end(#k_val_clause{val=#k_bin_end{},body=B}, Src, Tf, St0) ->
+ Ctx = get_context(Src, St0),
+ {Bis,St1} = match_cg(B, Tf, St0),
+ {TestIs,St} = make_cond_branch(bs_test_tail, [Ctx,#b_literal{val=0}], Tf, St1),
+ Is = TestIs++Bis,
+ {Is,St}.
+
+select_extract_bin(#k_var{name=Hd}, Size0, Unit, Type, Flags, Vf,
+ Ctx, Anno, St0) ->
+ {Dst,St1} = new_ssa_var(Hd, St0),
+ Size = ssa_arg(Size0, St0),
+ build_bs_instr(Anno, Type, Vf, Ctx, Size, Unit, Flags, Dst, St1).
+
+select_extract_int(#k_var{name=Tl}, 0, #k_int{val=0}, _U, _Fs, _Vf,
+ Ctx, St0) ->
+ St = set_ssa_var(Tl, Ctx, St0),
+ {[],St};
+select_extract_int(#k_var{name=Tl}, Val, #k_int{val=Sz}, U, Fs, Vf,
+ Ctx, St0) ->
+ {Dst,St1} = new_ssa_var(Tl, St0),
+ Bits = U*Sz,
+ Bin = case member(big, Fs) of
+ true ->
+ <<Val:Bits>>;
+ false ->
+ true = member(little, Fs), %Assertion.
+ <<Val:Bits/little>>
+ end,
+ Bits = bit_size(Bin), %Assertion.
+ {TestIs,St} = make_cond_branch(succeeded, [Dst], Vf, St1),
+ Set = #b_set{op=bs_match,dst=Dst,
+ args=[#b_literal{val=string},Ctx,#b_literal{val=Bin}]},
+ {[Set|TestIs],St}.
+
+build_bs_instr(Anno, Type, Fail, Ctx, Size, Unit0, Flags0, Dst, St0) ->
+ Unit = #b_literal{val=Unit0},
+ Flags = #b_literal{val=Flags0},
+ NeedSize = bs_need_size(Type),
+ TypeArg = #b_literal{val=Type},
+ Get = case NeedSize of
+ true ->
+ #b_set{anno=Anno,op=bs_match,dst=Dst,
+ args=[TypeArg,Ctx,Flags,Size,Unit]};
+ false ->
+ #b_set{anno=Anno,op=bs_match,dst=Dst,
+ args=[TypeArg,Ctx,Flags]}
+ end,
+ {Is,St} = make_cond_branch(succeeded, [Dst], Fail, St0),
+ {[Get|Is],St}.
+
+select_val(#k_val_clause{val=#k_tuple{es=Es},body=B}, V, Vf, St0) ->
+ #k{us=Used} = k_get_anno(B),
+ {Eis,St1} = select_extract_tuple(V, Es, Used, St0),
+ {Bis,St2} = match_cg(B, Vf, St1),
+ {length(Es),Eis ++ Bis,St2};
+select_val(#k_val_clause{val=Val0,body=B}, _V, Vf, St0) ->
+ Val = case Val0 of
+ #k_atom{val=Lit} -> Lit;
+ #k_float{val=Lit} -> Lit;
+ #k_int{val=Lit} -> Lit;
+ #k_literal{val=Lit} -> Lit
+ end,
+ {Bis,St1} = match_cg(B, Vf, St0),
+ {Val,Bis,St1}.
+
+%% select_extract_tuple(Src, [V], State) -> {[E],State}.
+%% Extract tuple elements, but only if they are actually used.
+%%
+%% Not extracting tuple elements that are not used is an
+%% optimization for compile time and memory use during compilation.
+%% It is probably worthwhile because it is common to extract only a
+%% few elements from a huge record.
+
+select_extract_tuple(Src, Vs, Used, St0) ->
+ Tuple = ssa_arg(Src, St0),
+ F = fun (#k_var{name=V}, {Elem,S0}) ->
+ case member(V, Used) of
+ true ->
+ Args = [Tuple,#b_literal{val=Elem}],
+ {Dst,S} = new_ssa_var(V, S0),
+ Get = #b_set{op=get_tuple_element,dst=Dst,args=Args},
+ {[Get],{Elem+1,S}};
+ false ->
+ {[],{Elem+1,S0}}
+ end
+ end,
+ {Es,{_,St}} = flatmapfoldl(F, {0,St0}, Vs),
+ {Es,St}.
+
+select_map(Scs, V, Tf, Vf, St0) ->
+ MapSrc = ssa_arg(V, St0),
+ {Is,St1} =
+ match_fmf(fun(#k_val_clause{val=#k_map{op=exact,es=Es},
+ body=B}, Fail, St1) ->
+ select_map_val(V, Es, B, Fail, St1)
+ end, Vf, St0, Scs),
+ {TestIs,St} = make_cond_branch({bif,is_map}, [MapSrc], Tf, St1),
+ {TestIs++Is,St}.
+
+select_map_val(V, Es, B, Fail, St0) ->
+ {Eis,St1} = select_extract_map(Es, V, Fail, St0),
+ {Bis,St2} = match_cg(B, Fail, St1),
+ {Eis++Bis,St2}.
+
+select_extract_map([P|Ps], Src, Fail, St0) ->
+ MapSrc = ssa_arg(Src, St0),
+ #k_map_pair{key=Key0,val=#k_var{name=Dst0}} = P,
+ Key = ssa_arg(Key0, St0),
+ {Dst,St1} = new_ssa_var(Dst0, St0),
+ Set = #b_set{op=get_map_element,dst=Dst,args=[MapSrc,Key]},
+ {TestIs,St2} = make_cond_branch(succeeded, [Dst], Fail, St1),
+ {Is,St} = select_extract_map(Ps, Src, Fail, St2),
+ {[Set|TestIs]++Is,St};
+select_extract_map([], _, _, St) ->
+ {[],St}.
+
+select_extract_cons(Src0, [#k_var{name=Hd},#k_var{name=Tl}], St0) ->
+ Src = ssa_arg(Src0, St0),
+ {HdDst,St1} = new_ssa_var(Hd, St0),
+ {TlDst,St2} = new_ssa_var(Tl, St1),
+ GetHd = #b_set{op=get_hd,dst=HdDst,args=[Src]},
+ GetTl = #b_set{op=get_tl,dst=TlDst,args=[Src]},
+ {[GetHd,GetTl],St2}.
+
+guard_clause_cg(#k_guard_clause{guard=G,body=B}, Fail, St0) ->
+ {Gis,St1} = guard_cg(G, Fail, St0),
+ {Bis,St} = match_cg(B, Fail, St1),
+ {Gis ++ Bis,St}.
+
+%% guard_cg(Guard, Fail, State) -> {[Ainstr],State}.
+%% A guard is a boolean expression of tests. Tests return true or
+%% false. A fault in a test causes the test to return false. Tests
+%% never return the boolean, instead we generate jump code to go to
+%% the correct exit point. Primops and tests all go to the next
+%% instruction on success or jump to a failure label.
+
+guard_cg(#k_protected{arg=Ts,ret=Rs,inner=Inner}, Fail, St) ->
+ protected_cg(Ts, Rs, Inner, Fail, St);
+guard_cg(#k_test{op=Test0,args=As,inverted=Inverted}, Fail, St0) ->
+ #k_remote{mod=#k_atom{val=erlang},name=#k_atom{val=Test}} = Test0,
+ test_cg(Test, Inverted, As, Fail, St0);
+guard_cg(#k_seq{arg=Arg,body=Body}, Fail, St0) ->
+ {ArgIs,St1} = guard_cg(Arg, Fail, St0),
+ {BodyIs,St} = guard_cg(Body, Fail, St1),
+ {ArgIs++BodyIs,St};
+guard_cg(G, _Fail, St) ->
+ cg(G, St).
+
+test_cg('=/=', Inverted, As, Fail, St) ->
+ test_cg('=:=', not Inverted, As, Fail, St);
+test_cg('/=', Inverted, As, Fail, St) ->
+ test_cg('==', not Inverted, As, Fail, St);
+test_cg(Test, Inverted, As0, Fail, St0) ->
+ As = ssa_args(As0, St0),
+ case {Test,ssa_args(As0, St0)} of
+ {is_record,[Tuple,#b_literal{val=Atom}=Tag,#b_literal{val=Int}=Arity]}
+ when is_atom(Atom), is_integer(Int) ->
+ test_is_record_cg(Inverted, Fail, Tuple, Tag, Arity, St0);
+ {_,As} ->
+ {Bool,St1} = new_ssa_var('@ssa_bool', St0),
+ {Succ,St} = new_label(St1),
+ Bif = #b_set{op={bif,Test},dst=Bool,args=As},
+ Br = case Inverted of
+ false -> #b_br{bool=Bool,succ=Succ,fail=Fail};
+ true -> #b_br{bool=Bool,succ=Fail,fail=Succ}
+ end,
+ {[Bif,Br,{label,Succ}],St}
+ end.
+
+test_is_record_cg(false, Fail, Tuple, TagVal, ArityVal, St0) ->
+ {Arity,St1} = new_ssa_var('@ssa_arity', St0),
+ {Tag,St2} = new_ssa_var('@ssa_tag', St1),
+ {Is0,St3} = make_cond_branch({bif,is_tuple}, [Tuple], Fail, St2),
+ GetArity = #b_set{op={bif,tuple_size},dst=Arity,args=[Tuple]},
+ {Is1,St4} = make_cond_branch({bif,'=:='}, [Arity,ArityVal], Fail, St3),
+ GetTag = #b_set{op=get_tuple_element,dst=Tag,
+ args=[Tuple,#b_literal{val=0}]},
+ {Is2,St} = make_cond_branch({bif,'=:='}, [Tag,TagVal], Fail, St4),
+ Is = Is0 ++ [GetArity] ++ Is1 ++ [GetTag] ++ Is2,
+ {Is,St};
+test_is_record_cg(true, Fail, Tuple, TagVal, ArityVal, St0) ->
+ {Succ,St1} = new_label(St0),
+ {Arity,St2} = new_ssa_var('@ssa_arity', St1),
+ {Tag,St3} = new_ssa_var('@ssa_tag', St2),
+ {Is0,St4} = make_cond_branch({bif,is_tuple}, [Tuple], Succ, St3),
+ GetArity = #b_set{op={bif,tuple_size},dst=Arity,args=[Tuple]},
+ {Is1,St5} = make_cond_branch({bif,'=:='}, [Arity,ArityVal], Succ, St4),
+ GetTag = #b_set{op=get_tuple_element,dst=Tag,
+ args=[Tuple,#b_literal{val=0}]},
+ {Is2,St} = make_cond_branch({bif,'=:='}, [Tag,TagVal], Succ, St5),
+ Is3 = [make_uncond_branch(Fail),{label,Succ}],
+ Is = Is0 ++ [GetArity] ++ Is1 ++ [GetTag] ++ Is2 ++ Is3,
+ {Is,St}.
+
+%% protected_cg([Kexpr], [Ret], Fail, St) -> {[Ainstr],St}.
+%% Do a protected. Protecteds without return values are just done
+%% for effect, the return value is not checked, success passes on to
+%% the next instruction and failure jumps to Fail. If there are
+%% return values then these must be set to 'false' on failure,
+%% control always passes to the next instruction.
+
+protected_cg(Ts, [], _, Fail, St0) ->
+ %% Protect these calls, revert when done.
+ {Tis,St1} = guard_cg(Ts, Fail, St0#cg{bfail=Fail}),
+ {Tis,St1#cg{bfail=St0#cg.bfail}};
+protected_cg(Ts, Rs, Inner0, _Fail, St0) ->
+ {Pfail,St1} = new_label(St0),
+ {Br,St2} = new_label(St1),
+ Prot = duplicate(length(Rs), #b_literal{val=false}),
+ {Tis,St3} = guard_cg(Ts, Pfail, St2#cg{break=Pfail,bfail=Pfail}),
+ Inner = ssa_args(Inner0, St3),
+ {BreakVars,St} = new_ssa_vars(Rs, St3),
+ Is = Tis ++ [#cg_break{args=Inner,phi=Br},
+ {label,Pfail},#cg_break{args=Prot,phi=Br},
+ {label,Br},#cg_phi{vars=BreakVars}],
+ {Is,St#cg{break=St0#cg.break,bfail=St0#cg.bfail}}.
+
+%% match_fmf(Fun, LastFail, State, [Clause]) -> {Is,State}.
+%% This is a special flatmapfoldl for match code gen where we
+%% generate a "failure" label for each clause. The last clause uses
+%% an externally generated failure label, LastFail. N.B. We do not
+%% know or care how the failure labels are used.
+
+match_fmf(F, LastFail, St, [H]) ->
+ F(H, LastFail, St);
+match_fmf(F, LastFail, St0, [H|T]) ->
+ {Fail,St1} = new_label(St0),
+ {R,St2} = F(H, Fail, St1),
+ {Rs,St3} = match_fmf(F, LastFail, St2, T),
+ {R ++ [{label,Fail}] ++ Rs,St3}.
+
+%% fail_label(State) -> {Where,FailureLabel}.
+%% Where = guard | no_catch | in_catch
+%% Return an indication of which part of a function code is
+%% being generated for and the appropriate failure label to
+%% use.
+%%
+%% Where has the following meaning:
+%%
+%% guard - Inside a guard.
+%% no_catch - In a function body, not in the scope of
+%% a try/catch or catch.
+%% in_catch - In the scope of a try/catch or catch.
+
+fail_label(#cg{catch_label=Catch,bfail=Fail,ultimate_failure=Ult}) ->
+ if
+ Fail =/= Ult ->
+ {guard,Fail};
+ Catch =:= none ->
+ {no_catch,Fail};
+ is_integer(Catch) ->
+ {in_catch,Catch}
+ end.
+
+%% bif_fail_label(State) -> FailureLabel.
+%% Return the appropriate failure label for a guard BIF call or
+%% primop that fails.
+
+bif_fail_label(St) ->
+ {_,Fail} = fail_label(St),
+ Fail.
+
+%% call_cg(Func, [Arg], [Ret], Le, State) ->
+%% {[Ainstr],State}.
+%% enter_cg(Func, [Arg], Le, St) -> {[Ainstr],St}.
+%% Generate code for call and enter.
+
+call_cg(Func, As, [], Le, St) ->
+ call_cg(Func, As, [#k_var{name='@ssa_ignored'}], Le, St);
+call_cg(Func0, As, [#k_var{name=R}|MoreRs]=Rs, Le, St0) ->
+ case fail_label(St0) of
+ {guard,Fail} ->
+ %% Inside a guard. The only allowed function call is to
+ %% erlang:error/1,2. We will generate a branch to the
+ %% failure branch.
+ #k_remote{mod=#k_atom{val=erlang},
+ name=#k_atom{val=error}} = Func0, %Assertion.
+ [#k_var{name=DestVar}] = Rs,
+ St = set_ssa_var(DestVar, #b_literal{val=unused}, St0),
+ {[make_uncond_branch(Fail),#cg_unreachable{}],St};
+ {Catch,Fail} ->
+ %% Ordinary function call in a function body.
+ Args = ssa_args(As, St0),
+ {Ret,St1} = new_ssa_var(R, St0),
+ Func = call_target(Func0, Args, St0),
+ Call = #b_set{anno=line_anno(Le),op=call,dst=Ret,args=[Func|Args]},
+
+ %% If this is a call to erlang:error(), MoreRs could be a
+ %% nonempty list of variables that each need a value.
+ St2 = foldl(fun(#k_var{name=Dummy}, S) ->
+ set_ssa_var(Dummy, #b_literal{val=unused}, S)
+ end, St1, MoreRs),
+ case Catch of
+ no_catch ->
+ {[Call],St2};
+ in_catch ->
+ {TestIs,St} = make_cond_branch(succeeded, [Ret], Fail, St2),
+ {[Call|TestIs],St}
+ end
+ end.
+
+enter_cg(Func0, As0, Le, St0) ->
+ Anno = line_anno(Le),
+ Func = call_target(Func0, As0, St0),
+ As = ssa_args(As0, St0),
+ {Ret,St} = new_ssa_var('@ssa_ret', St0),
+ Call = #b_set{anno=Anno,op=call,dst=Ret,args=[Func|As]},
+ {[Call,#b_ret{arg=Ret}],St}.
+
+call_target(Func, As, St) ->
+ Arity = length(As),
+ case Func of
+ #k_remote{mod=Mod0,name=Name0} ->
+ Mod = ssa_arg(Mod0, St),
+ Name = ssa_arg(Name0, St),
+ #b_remote{mod=Mod,name=Name,arity=Arity};
+ #k_local{name=Name} when is_atom(Name) ->
+ #b_local{name=#b_literal{val=Name},arity=Arity};
+ #k_var{}=Var ->
+ ssa_arg(Var, St)
+ end.
+
+%% bif_cg(#k_bif{}, Le,State) -> {[Ainstr],State}.
+%% Generate code for a guard BIF or primop.
+
+bif_cg(#k_bif{op=#k_internal{name=Name},args=As,ret=Rs}, Le, St) ->
+ internal_cg(Name, As, Rs, Le, St);
+bif_cg(#k_bif{op=#k_remote{mod=#k_atom{val=erlang},name=#k_atom{val=Name}},
+ args=As,ret=Rs}, Le, St) ->
+ bif_cg(Name, As, Rs, Le, St).
+
+%% internal_cg(Bif, [Arg], [Ret], Le, State) ->
+%% {[Ainstr],State}.
+
+internal_cg(make_fun, [Name0,Arity0|As], Rs, _Le, St0) ->
+ #k_atom{val=Name} = Name0,
+ #k_int{val=Arity} = Arity0,
+ [#k_var{name=Dst0}] = Rs,
+ {Dst,St} = new_ssa_var(Dst0, St0),
+ Args = ssa_args(As, St),
+ Local = #b_local{name=#b_literal{val=Name},arity=Arity},
+ MakeFun = #b_set{op=make_fun,dst=Dst,args=[Local|Args]},
+ {[MakeFun],St};
+internal_cg(bs_init_writable=I, As, [#k_var{name=Dst0}], _Le, St0) ->
+ %% This behaves like a function call.
+ {Dst,St} = new_ssa_var(Dst0, St0),
+ Args = ssa_args(As, St),
+ Set = #b_set{op=I,dst=Dst,args=Args},
+ {[Set],St};
+internal_cg(build_stacktrace=I, As, [#k_var{name=Dst0}], _Le, St0) ->
+ {Dst,St} = new_ssa_var(Dst0, St0),
+ Args = ssa_args(As, St),
+ Set = #b_set{op=I,dst=Dst,args=Args},
+ {[Set],St};
+internal_cg(raise, As, [#k_var{name=Dst0}], _Le, St0) ->
+ Args = ssa_args(As, St0),
+ {Dst,St} = new_ssa_var(Dst0, St0),
+ Resume = #b_set{op=resume,dst=Dst,args=Args},
+ case St of
+ #cg{catch_label=none} ->
+ {[Resume],St};
+ #cg{catch_label=Catch} when is_integer(Catch) ->
+ Is = [Resume,make_uncond_branch(Catch),#cg_unreachable{}],
+ {Is,St}
+ end;
+internal_cg(raw_raise=I, As, [#k_var{name=Dst0}], _Le, St0) ->
+ %% This behaves like a function call.
+ {Dst,St} = new_ssa_var(Dst0, St0),
+ Args = ssa_args(As, St),
+ Set = #b_set{op=I,dst=Dst,args=Args},
+ {[Set],St}.
+
+bif_cg(Bif, As0, [#k_var{name=Dst0}], Le, St0) ->
+ {Dst,St1} = new_ssa_var(Dst0, St0),
+ case {Bif,ssa_args(As0, St0)} of
+ {is_record,[Tuple,#b_literal{val=Atom}=Tag,
+ #b_literal{val=Int}=Arity]}
+ when is_atom(Atom), is_integer(Int) ->
+ bif_is_record_cg(Dst, Tuple, Tag, Arity, St1);
+ {_,As} ->
+ I = #b_set{anno=line_anno(Le),op={bif,Bif},dst=Dst,args=As},
+ case erl_bifs:is_safe(erlang, Bif, length(As)) of
+ false ->
+ Fail = bif_fail_label(St1),
+ {Is,St} = make_cond_branch(succeeded, [Dst], Fail, St1),
+ {[I|Is],St};
+ true->
+ {[I],St1}
+ end
+ end.
+
+bif_is_record_cg(Dst, Tuple, TagVal, ArityVal, St0) ->
+ {Arity,St1} = new_ssa_var('@ssa_arity', St0),
+ {Tag,St2} = new_ssa_var('@ssa_tag', St1),
+ {Phi,St3} = new_label(St2),
+ {False,St4} = new_label(St3),
+ {Is0,St5} = make_cond_branch({bif,is_tuple}, [Tuple], False, St4),
+ GetArity = #b_set{op={bif,tuple_size},dst=Arity,args=[Tuple]},
+ {Is1,St6} = make_cond_branch({bif,'=:='}, [Arity,ArityVal], False, St5),
+ GetTag = #b_set{op=get_tuple_element,dst=Tag,
+ args=[Tuple,#b_literal{val=0}]},
+ {Is2,St} = make_cond_branch({bif,'=:='}, [Tag,TagVal], False, St6),
+ Is3 = [#cg_break{args=[#b_literal{val=true}],phi=Phi},
+ {label,False},
+ #cg_break{args=[#b_literal{val=false}],phi=Phi},
+ {label,Phi},
+ #cg_phi{vars=[Dst]}],
+ Is = Is0 ++ [GetArity] ++ Is1 ++ [GetTag] ++ Is2 ++ Is3,
+ {Is,St}.
+
+%% recv_loop_cg(TimeOut, ReceiveVar, ReceiveMatch, TimeOutExprs,
+%% [Ret], Le, St) -> {[Ainstr],St}.
+
+recv_loop_cg(Te, Rvar, Rm, Tes, Rs, Le, St0) ->
+ %% Get labels.
+ {Rl,St1} = new_label(St0),
+ {Tl,St2} = new_label(St1),
+ {Bl,St3} = new_label(St2),
+ St4 = St3#cg{break=Bl,recv=Rl},
+ {Ris,St5} = cg_recv_mesg(Rvar, Rm, Tl, Le, St4),
+ {Wis,St6} = cg_recv_wait(Te, Tes, St5),
+ {BreakVars,St} = new_ssa_vars(Rs, St6),
+ {Ris ++ [{label,Tl}] ++ Wis ++
+ [{label,Bl},#cg_phi{vars=BreakVars}],
+ St#cg{break=St0#cg.break,recv=St0#cg.recv}}.
+
+%% cg_recv_mesg( ) -> {[Ainstr],St}.
+
+cg_recv_mesg(#k_var{name=R}, Rm, Tl, Le, St0) ->
+ {Dst,St1} = new_ssa_var(R, St0),
+ {Mis,St2} = match_cg(Rm, none, St1),
+ RecvLbl = St1#cg.recv,
+ {TestIs,St} = make_cond_branch(succeeded, [Dst], Tl, St2),
+ Is = [#b_br{anno=line_anno(Le),bool=#b_literal{val=true},
+ succ=RecvLbl,fail=RecvLbl},
+ {label,RecvLbl},
+ #b_set{op=peek_message,dst=Dst}|TestIs],
+ {Is++Mis,St}.
+
+%% cg_recv_wait(Te, Tes, St) -> {[Ainstr],St}.
+
+cg_recv_wait(#k_int{val=0}, Es, St0) ->
+ {Tis,St} = cg(Es, St0),
+ {[#b_set{op=timeout}|Tis],St};
+cg_recv_wait(Te, Es, St0) ->
+ {Tis,St1} = cg(Es, St0),
+ Args = [ssa_arg(Te, St1)],
+ {WaitDst,St2} = new_ssa_var('@ssa_wait', St1),
+ {WaitIs,St} = make_cond_branch(succeeded, [WaitDst], St1#cg.recv, St2),
+ %% Infinite timeout will be optimized later.
+ Is = [#b_set{op=wait_timeout,dst=WaitDst,args=Args}] ++ WaitIs ++
+ [#b_set{op=timeout}] ++ Tis,
+ {Is,St}.
+
+%% try_cg(TryBlock, [BodyVar], TryBody, [ExcpVar], TryHandler, [Ret], St) ->
+%% {[Ainstr],St}.
+
+try_cg(Ta, Vs, Tb, Evs, Th, Rs, St0) ->
+ {B,St1} = new_label(St0), %Body label
+ {H,St2} = new_label(St1), %Handler label
+ {E,St3} = new_label(St2), %End label
+ {Next,St4} = new_label(St3),
+ {TryTag,St5} = new_ssa_var('@ssa_catch_tag', St4),
+ {SsaVs,St6} = new_ssa_vars(Vs, St5),
+ {SsaEvs,St7} = new_ssa_vars(Evs, St6),
+ {Ais,St8} = cg(Ta, St7#cg{break=B,catch_label=H}),
+ St9 = St8#cg{break=E,catch_label=St7#cg.catch_label},
+ {Bis,St10} = cg(Tb, St9),
+ {His,St11} = cg(Th, St10),
+ {BreakVars,St12} = new_ssa_vars(Rs, St11),
+ {CatchedAgg,St} = new_ssa_var('@ssa_agg', St12),
+ ExtractVs = extract_vars(SsaEvs, CatchedAgg, 0),
+ KillTryTag = #b_set{op=kill_try_tag,args=[TryTag]},
+ Args = [#b_literal{val='try'},TryTag],
+ Handler = [{label,H},
+ #b_set{op=landingpad,dst=CatchedAgg,args=Args}] ++
+ ExtractVs ++ [KillTryTag],
+ {[#b_set{op=new_try_tag,dst=TryTag,args=[#b_literal{val='try'}]},
+ #b_br{bool=TryTag,succ=Next,fail=H},
+ {label,Next}] ++ Ais ++
+ [{label,B},#cg_phi{vars=SsaVs},KillTryTag] ++ Bis ++
+ Handler ++ His ++
+ [{label,E},#cg_phi{vars=BreakVars}],
+ St#cg{break=St0#cg.break}}.
+
+try_enter_cg(Ta, Vs, Tb, Evs, Th, St0) ->
+ {B,St1} = new_label(St0), %Body label
+ {H,St2} = new_label(St1), %Handler label
+ {Next,St3} = new_label(St2),
+ {TryTag,St4} = new_ssa_var('@ssa_catch_tag', St3),
+ {SsaVs,St5} = new_ssa_vars(Vs, St4),
+ {SsaEvs,St6} = new_ssa_vars(Evs, St5),
+ {Ais,St7} = cg(Ta, St6#cg{break=B,catch_label=H}),
+ St8 = St7#cg{catch_label=St6#cg.catch_label},
+ {Bis,St9} = cg(Tb, St8),
+ {His,St10} = cg(Th, St9),
+ {CatchedAgg,St} = new_ssa_var('@ssa_agg', St10),
+ ExtractVs = extract_vars(SsaEvs, CatchedAgg, 0),
+ KillTryTag = #b_set{op=kill_try_tag,args=[TryTag]},
+ Args = [#b_literal{val='try'},TryTag],
+ Handler = [{label,H},
+ #b_set{op=landingpad,dst=CatchedAgg,args=Args}] ++
+ ExtractVs ++ [KillTryTag],
+ {[#b_set{op=new_try_tag,dst=TryTag,args=[#b_literal{val='try'}]},
+ #b_br{bool=TryTag,succ=Next,fail=H},
+ {label,Next}] ++ Ais ++
+ [{label,B},#cg_phi{vars=SsaVs},KillTryTag] ++ Bis ++
+ Handler ++ His,
+ St#cg{break=St0#cg.break}}.
+
+extract_vars([V|Vs], Agg, N) ->
+ I = #b_set{op=extract,dst=V,args=[Agg,#b_literal{val=N}]},
+ [I|extract_vars(Vs, Agg, N+1)];
+extract_vars([], _, _) -> [].
+
+%% do_catch_cg(CatchBlock, Ret, St) -> {[Ainstr],St}.
+
+do_catch_cg(Block, #k_var{name=R}, St0) ->
+ {B,St1} = new_label(St0),
+ {Next,St2} = new_label(St1),
+ {H,St3} = new_label(St2),
+ {CatchReg,St4} = new_ssa_var('@ssa_catch_tag', St3),
+ {Dst,St5} = new_ssa_var(R, St4),
+ {Succ,St6} = new_label(St5),
+ {Cis,St7} = cg(Block, St6#cg{break=Succ,catch_label=H}),
+ {CatchedVal,St8} = new_ssa_var('@catched_val', St7),
+ {SuccVal,St9} = new_ssa_var('@success_val', St8),
+ {CatchedAgg,St10} = new_ssa_var('@ssa_agg', St9),
+ {CatchEndVal,St} = new_ssa_var('@catch_end_val', St10),
+ Args = [#b_literal{val='catch'},CatchReg],
+ {[#b_set{op=new_try_tag,dst=CatchReg,args=[#b_literal{val='catch'}]},
+ #b_br{bool=CatchReg,succ=Next,fail=H},
+ {label,Next}] ++ Cis ++
+ [{label,H},
+ #b_set{op=landingpad,dst=CatchedAgg,args=Args},
+ #b_set{op=extract,dst=CatchedVal,
+ args=[CatchedAgg,#b_literal{val=0}]},
+ #cg_break{args=[CatchedVal],phi=B},
+ {label,Succ},
+ #cg_phi{vars=[SuccVal]},
+ #cg_break{args=[SuccVal],phi=B},
+ {label,B},#cg_phi{vars=[CatchEndVal]},
+ #b_set{op=catch_end,dst=Dst,args=[CatchReg,CatchEndVal]}],
+ St#cg{break=St1#cg.break,catch_label=St1#cg.catch_label}}.
+
+%% put_cg([Var], Constr, Le, Vdb, Bef, St) -> {[Ainstr],St}.
+%% Generate code for constructing terms.
+
+put_cg([#k_var{name=R}], #k_cons{hd=Hd,tl=Tl}, _Le, St0) ->
+ Args = ssa_args([Hd,Tl], St0),
+ {Dst,St} = new_ssa_var(R, St0),
+ PutList = #b_set{op=put_list,dst=Dst,args=Args},
+ {[PutList],St};
+put_cg([#k_var{name=R}], #k_tuple{es=Es}, _Le, St0) ->
+ {Ret,St} = new_ssa_var(R, St0),
+ Args = ssa_args(Es, St),
+ PutTuple = #b_set{op=put_tuple,dst=Ret,args=Args},
+ {[PutTuple],St};
+put_cg([#k_var{name=R}], #k_binary{segs=Segs}, Le, St0) ->
+ Fail = bif_fail_label(St0),
+ {Dst,St1} = new_ssa_var(R, St0),
+ cg_binary(Dst, Segs, Fail, Le, St1);
+put_cg([#k_var{name=R}], #k_map{op=Op,var=Map,
+ es=[#k_map_pair{key=#k_var{}=K,val=V}]},
+ Le, St0) ->
+ %% Map: single variable key.
+ SrcMap = ssa_arg(Map, St0),
+ LineAnno = line_anno(Le),
+ List = [ssa_arg(K, St0),ssa_arg(V, St0)],
+ {Dst,St1} = new_ssa_var(R, St0),
+ {Is,St} = put_cg_map(LineAnno, Op, SrcMap, Dst, List, St1),
+ {Is,St};
+put_cg([#k_var{name=R}], #k_map{op=Op,var=Map,es=Es}, Le, St0) ->
+ %% Map: one or more literal keys.
+ [] = [Var || #k_map_pair{key=#k_var{}=Var} <- Es], %Assertion
+ SrcMap = ssa_arg(Map, St0),
+ LineAnno = line_anno(Le),
+ List = flatmap(fun(#k_map_pair{key=K,val=V}) ->
+ [ssa_arg(K, St0),ssa_arg(V, St0)]
+ end, Es),
+ {Dst,St1} = new_ssa_var(R, St0),
+ {Is,St} = put_cg_map(LineAnno, Op, SrcMap, Dst, List, St1),
+ {Is,St};
+put_cg([#k_var{name=R}], Con0, _Le, St0) ->
+ %% Create an alias for a variable or literal.
+ Con = ssa_arg(Con0, St0),
+ St = set_ssa_var(R, Con, St0),
+ {[],St}.
+
+put_cg_map(LineAnno, Op, SrcMap, Dst, List, St0) ->
+ Fail = bif_fail_label(St0),
+ Args = [#b_literal{val=Op},SrcMap|List],
+ PutMap = #b_set{anno=LineAnno,op=put_map,dst=Dst,args=Args},
+ if
+ Op =:= assoc ->
+ {[PutMap],St0};
+ true ->
+ {Is,St} = make_cond_branch(succeeded, [Dst], Fail, St0),
+ {[PutMap|Is],St}
+ end.
+
+%%%
+%%% Code generation for constructing binaries.
+%%%
+
+cg_binary(Dst, Segs0, Fail, Le, St0) ->
+ {PutCode0,SzCalc0,St1} = cg_bin_put(Segs0, Fail, St0),
+ LineAnno = line_anno(Le),
+ Anno = Le#k.a,
+ case PutCode0 of
+ [#b_set{op=bs_put,dst=Bool,args=[_,_,Src,#b_literal{val=all}|_]},
+ #b_br{bool=Bool},
+ {label,_}|_] ->
+ #k_bin_seg{unit=Unit0,next=Segs} = Segs0,
+ Unit = #b_literal{val=Unit0},
+ {PutCode,SzCalc1,St2} = cg_bin_put(Segs, Fail, St1),
+ {_,SzVar,SzCode0,St3} = cg_size_calc(1, SzCalc1, Fail, St2),
+ SzCode = cg_bin_anno(SzCode0, LineAnno),
+ Args = case member(single_use, Anno) of
+ true ->
+ [#b_literal{val=private_append},Src,SzVar,Unit];
+ false ->
+ [#b_literal{val=append},Src,SzVar,Unit]
+ end,
+ BsInit = #b_set{anno=LineAnno,op=bs_init,dst=Dst,args=Args},
+ {TestIs,St} = make_cond_branch(succeeded, [Dst], Fail, St3),
+ {SzCode ++ [BsInit] ++ TestIs ++ PutCode,St};
+ [#b_set{op=bs_put}|_] ->
+ {Unit,SzVar,SzCode0,St2} = cg_size_calc(8, SzCalc0, Fail, St1),
+ SzCode = cg_bin_anno(SzCode0, LineAnno),
+ Args = [#b_literal{val=new},SzVar,Unit],
+ BsInit = #b_set{anno=LineAnno,op=bs_init,dst=Dst,args=Args},
+ {TestIs,St} = make_cond_branch(succeeded, [Dst], Fail, St2),
+ {SzCode ++ [BsInit] ++ TestIs ++ PutCode0,St}
+ end.
+
+cg_bin_anno([Set|Sets], Anno) ->
+ [Set#b_set{anno=Anno}|Sets];
+cg_bin_anno([], _) -> [].
+
+%% cg_size_calc(PreferredUnit, SzCalc, Fail, St0) ->
+%% {ActualUnit,SizeVariable,SizeCode,St}.
+%% Generate size calculation code.
+
+cg_size_calc(Unit, error, _Fail, St) ->
+ {#b_literal{val=Unit},#b_literal{val=badarg},[],St};
+cg_size_calc(8, [{1,_}|_]=SzCalc, Fail, St) ->
+ cg_size_calc(1, SzCalc, Fail, St);
+cg_size_calc(8, SzCalc, Fail, St0) ->
+ {Var,Pre,St} = cg_size_calc_1(SzCalc, Fail, St0),
+ {#b_literal{val=8},Var,Pre,St};
+cg_size_calc(1, SzCalc0, Fail, St0) ->
+ SzCalc = map(fun({8,#b_literal{val=Size}}) ->
+ {1,#b_literal{val=8*Size}};
+ ({8,{{bif,byte_size},Src}}) ->
+ {1,{{bif,bit_size},Src}};
+ ({8,{_,_}=UtfCalc}) ->
+ {1,{'*',#b_literal{val=8},UtfCalc}};
+ ({_,_}=Pair) ->
+ Pair
+ end, SzCalc0),
+ {Var,Pre,St} = cg_size_calc_1(SzCalc, Fail, St0),
+ {#b_literal{val=1},Var,Pre,St}.
+
+cg_size_calc_1(SzCalc, Fail, St0) ->
+ cg_size_calc_2(SzCalc, #b_literal{val=0}, Fail, St0).
+
+cg_size_calc_2([{_,{'*',Unit,{_,_}=Bif}}|T], Sum0, Fail, St0) ->
+ {Sum1,Pre0,St1} = cg_size_calc_2(T, Sum0, Fail, St0),
+ {BifDst,Pre1,St2} = cg_size_bif(Bif, Fail, St1),
+ {Sum,Pre2,St} = cg_size_add(Sum1, BifDst, Unit, Fail, St2),
+ {Sum,Pre0++Pre1++Pre2,St};
+cg_size_calc_2([{_,#b_literal{}=Sz}|T], Sum0, Fail, St0) ->
+ {Sum1,Pre0,St1} = cg_size_calc_2(T, Sum0, Fail, St0),
+ {Sum,Pre,St} = cg_size_add(Sum1, Sz, #b_literal{val=1}, Fail, St1),
+ {Sum,Pre0++Pre,St};
+cg_size_calc_2([{_,#b_var{}=Sz}|T], Sum0, Fail, St0) ->
+ {Sum1,Pre0,St1} = cg_size_calc_2(T, Sum0, Fail, St0),
+ {Sum,Pre,St} = cg_size_add(Sum1, Sz, #b_literal{val=1}, Fail, St1),
+ {Sum,Pre0++Pre,St};
+cg_size_calc_2([{_,{_,_}=Bif}|T], Sum0, Fail, St0) ->
+ {Sum1,Pre0,St1} = cg_size_calc_2(T, Sum0, Fail, St0),
+ {BifDst,Pre1,St2} = cg_size_bif(Bif, Fail, St1),
+ {Sum,Pre2,St} = cg_size_add(Sum1, BifDst, #b_literal{val=1}, Fail, St2),
+ {Sum,Pre0++Pre1++Pre2,St};
+cg_size_calc_2([], Sum, _Fail, St) ->
+ {Sum,[],St}.
+
+cg_size_bif(#b_var{}=Var, _Fail, St) ->
+ {Var,[],St};
+cg_size_bif({Name,Src}, Fail, St0) ->
+ {Dst,St1} = new_ssa_var('@ssa_bif', St0),
+ Bif = #b_set{op=Name,dst=Dst,args=[Src]},
+ {TestIs,St} = make_cond_branch(succeeded, [Dst], Fail, St1),
+ {Dst,[Bif|TestIs],St}.
+
+cg_size_add(#b_literal{val=0}, Val, #b_literal{val=1}, _Fail, St) ->
+ {Val,[],St};
+cg_size_add(A, B, Unit, Fail, St0) ->
+ {Dst,St1} = new_ssa_var('@ssa_sum', St0),
+ {TestIs,St} = make_cond_branch(succeeded, [Dst], Fail, St1),
+ BsAdd = #b_set{op=bs_add,dst=Dst,args=[A,B,Unit]},
+ {Dst,[BsAdd|TestIs],St}.
+
+cg_bin_put(Seg, Fail, St) ->
+ cg_bin_put_1(Seg, Fail, [], [], St).
+
+cg_bin_put_1(#k_bin_seg{size=Size0,unit=U,type=T,flags=Fs,seg=Src0,next=Next},
+ Fail, Acc, SzCalcAcc, St0) ->
+ [Src,Size] = ssa_args([Src0,Size0], St0),
+ NeedSize = bs_need_size(T),
+ TypeArg = #b_literal{val=T},
+ Flags = #b_literal{val=Fs},
+ Unit = #b_literal{val=U},
+ Args = case NeedSize of
+ true -> [TypeArg,Flags,Src,Size,Unit];
+ false -> [TypeArg,Flags,Src]
+ end,
+ {Is,St} = make_cond_branch(bs_put, Args, Fail, St0),
+ SzCalc = bin_size_calc(T, Src, Size, U),
+ cg_bin_put_1(Next, Fail, reverse(Is, Acc), [SzCalc|SzCalcAcc], St);
+cg_bin_put_1(#k_bin_end{}, _, Acc, SzCalcAcc, St) ->
+ SzCalc = fold_size_calc(SzCalcAcc, 0, []),
+ {reverse(Acc),SzCalc,St}.
+
+bs_need_size(utf8) -> false;
+bs_need_size(utf16) -> false;
+bs_need_size(utf32) -> false;
+bs_need_size(_) -> true.
+
+bin_size_calc(utf8, Src, _Size, _Unit) ->
+ {8,{bs_utf8_size,Src}};
+bin_size_calc(utf16, Src, _Size, _Unit) ->
+ {8,{bs_utf16_size,Src}};
+bin_size_calc(utf32, _Src, _Size, _Unit) ->
+ {8,#b_literal{val=4}};
+bin_size_calc(binary, Src, #b_literal{val=all}, Unit) ->
+ case Unit rem 8 of
+ 0 -> {8,{{bif,byte_size},Src}};
+ _ -> {1,{{bif,bit_size},Src}}
+ end;
+bin_size_calc(_Type, _Src, Size, Unit) ->
+ {Unit,Size}.
+
+fold_size_calc([{Unit,#b_literal{val=Size}}|T], Bits, Acc) ->
+ if
+ is_integer(Size) ->
+ fold_size_calc(T, Bits + Unit*Size, Acc);
+ true ->
+ error
+ end;
+fold_size_calc([{U,#b_var{}}=H|T], Bits, Acc) when U =:= 1; U =:= 8 ->
+ fold_size_calc(T, Bits, [H|Acc]);
+fold_size_calc([{U,#b_var{}=Var}|T], Bits, Acc) ->
+ fold_size_calc(T, Bits, [{1,{'*',#b_literal{val=U},Var}}|Acc]);
+fold_size_calc([{_,_}=H|T], Bits, Acc) ->
+ fold_size_calc(T, Bits, [H|Acc]);
+fold_size_calc([], Bits, Acc) ->
+ Bytes = Bits div 8,
+ RemBits = Bits rem 8,
+ Sizes = sort([{1,#b_literal{val=RemBits}},{8,#b_literal{val=Bytes}}|Acc]),
+ [Pair || {_,Sz}=Pair <- Sizes, Sz =/= #b_literal{val=0}].
+
+%%%
+%%% Utilities for creating the SSA types.
+%%%
+
+ssa_args(As, St) ->
+ [ssa_arg(A, St) || A <- As].
+
+ssa_arg(#k_var{name=V}, #cg{vars=Vars}) -> maps:get(V, Vars);
+ssa_arg(#k_literal{val=V}, _) -> #b_literal{val=V};
+ssa_arg(#k_atom{val=V}, _) -> #b_literal{val=V};
+ssa_arg(#k_float{val=V}, _) -> #b_literal{val=V};
+ssa_arg(#k_int{val=V}, _) -> #b_literal{val=V};
+ssa_arg(#k_nil{}, _) -> #b_literal{val=[]}.
+
+new_ssa_vars(Vs, St) ->
+ mapfoldl(fun(#k_var{name=V}, S) ->
+ new_ssa_var(V, S)
+ end, St, Vs).
+
+new_ssa_var(VarBase, #cg{lcount=Uniq,vars=Vars}=St0)
+ when is_atom(VarBase); is_integer(VarBase) ->
+ case Vars of
+ #{VarBase:=_} ->
+ Var = #b_var{name={VarBase,Uniq}},
+ St = St0#cg{lcount=Uniq+1,vars=Vars#{VarBase=>Var}},
+ {Var,St};
+ #{} ->
+ Var = #b_var{name=VarBase},
+ St = St0#cg{vars=Vars#{VarBase=>Var}},
+ {Var,St}
+ end.
+
+set_ssa_var(VarBase, Val, #cg{vars=Vars}=St)
+ when is_atom(VarBase); is_integer(VarBase) ->
+ St#cg{vars=Vars#{VarBase=>Val}}.
+
+%% new_label(St) -> {L,St}.
+
+new_label(#cg{lcount=Next}=St) ->
+ {Next,St#cg{lcount=Next+1}}.
+
+%% line_anno(Le) -> #{} | #{location:={File,Line}}.
+%% Create a location annotation, containing information about the
+%% current filename and line number. The annotation should be
+%% included in any operation that could cause an exception.
+
+line_anno(#k{a=Anno}) ->
+ line_anno_1(Anno).
+
+line_anno_1([Line,{file,Name}]) when is_integer(Line) ->
+ line_anno_2(Name, Line);
+line_anno_1([_|_]=A) ->
+ {Name,Line} = find_loc(A, no_file, 0),
+ line_anno_2(Name, Line);
+line_anno_1([]) ->
+ #{}.
+
+line_anno_2(no_file, _) ->
+ #{};
+line_anno_2(_, 0) ->
+ %% Missing line number or line number 0.
+ #{};
+line_anno_2(Name, Line) ->
+ #{location=>{Name,Line}}.
+
+find_loc([Line|T], File, _) when is_integer(Line) ->
+ find_loc(T, File, Line);
+find_loc([{file,File}|T], _, Line) ->
+ find_loc(T, File, Line);
+find_loc([_|T], File, Line) ->
+ find_loc(T, File, Line);
+find_loc([], File, Line) -> {File,Line}.
+
+flatmapfoldl(F, Accu0, [Hd|Tail]) ->
+ {R,Accu1} = F(Hd, Accu0),
+ {Rs,Accu2} = flatmapfoldl(F, Accu1, Tail),
+ {R++Rs,Accu2};
+flatmapfoldl(_, Accu, []) -> {[],Accu}.
+
+%%%
+%%% Finalize the code.
+%%%
+
+finalize(Asm0, St0) ->
+ Asm1 = fix_phis(Asm0),
+ {Asm,St} = fix_sets(Asm1, [], St0),
+ {build_map(Asm),St}.
+
+fix_phis(Is) ->
+ fix_phis_1(Is, none, #{}).
+
+fix_phis_1([{label,L},#cg_phi{vars=[]}=Phi|Is0], _Lbl, Map0) ->
+ case maps:is_key(L, Map0) of
+ false ->
+ %% No #cg_break{} references this label. Nothing else can
+ %% reference it, so it can be safely be removed.
+ {Is,Map} = drop_upto_label(Is0, Map0),
+ fix_phis_1(Is, none, Map);
+ true ->
+ %% There is a break referencing this label; probably caused
+ %% by a try/catch whose return value is ignored.
+ [{label,L}|fix_phis_1([Phi|Is0], L, Map0)]
+ end;
+fix_phis_1([{label,L}=I|Is], _Lbl, Map) ->
+ [I|fix_phis_1(Is, L, Map)];
+fix_phis_1([#cg_unreachable{}|Is0], _Lbl, Map0) ->
+ {Is,Map} = drop_upto_label(Is0, Map0),
+ fix_phis_1(Is, none, Map);
+fix_phis_1([#cg_break{args=Args,phi=Target}|Is], Lbl, Map) when is_integer(Lbl) ->
+ Pairs1 = case Map of
+ #{Target:=Pairs0} -> Pairs0;
+ #{} -> []
+ end,
+ Pairs = [[{Arg,Lbl} || Arg <- Args]|Pairs1],
+ I = make_uncond_branch(Target),
+ [I|fix_phis_1(Is, none, Map#{Target=>Pairs})];
+fix_phis_1([#cg_phi{vars=Vars}|Is0], Lbl, Map0) ->
+ Pairs = maps:get(Lbl, Map0),
+ Map1 = maps:remove(Lbl, Map0),
+ case gen_phis(Vars, Pairs) of
+ [#b_set{op=phi,args=[]}] ->
+ {Is,Map} = drop_upto_label(Is0, Map1),
+ Ret = #b_ret{arg=#b_literal{val=unreachable}},
+ [Ret|fix_phis_1(Is, none, Map)];
+ Phis ->
+ Phis ++ fix_phis_1(Is0, Lbl, Map1)
+ end;
+fix_phis_1([I|Is], Lbl, Map) ->
+ [I|fix_phis_1(Is, Lbl, Map)];
+fix_phis_1([], _, Map) ->
+ [] = maps:to_list(Map), %Assertion.
+ [].
+
+gen_phis([V|Vs], Preds0) ->
+ {Pairs,Preds} = collect_preds(Preds0, [], []),
+ [#b_set{op=phi,dst=V,args=Pairs}|gen_phis(Vs, Preds)];
+gen_phis([], _) -> [].
+
+collect_preds([[First|Rest]|T], ColAcc, RestAcc) ->
+ collect_preds(T, [First|ColAcc], [Rest|RestAcc]);
+collect_preds([], ColAcc, RestAcc) ->
+ {keysort(2, ColAcc),RestAcc}.
+
+fix_sets([#b_set{dst=none}=Set|Is], Acc, St0) ->
+ {Dst,St} = new_ssa_var('@ssa_ignored', St0),
+ I = Set#b_set{dst=Dst},
+ fix_sets(Is, [I|Acc], St);
+fix_sets([I|Is], Acc, St) ->
+ fix_sets(Is, [I|Acc], St);
+fix_sets([], Acc, St) ->
+ {reverse(Acc),St}.
+
+build_map(Is) ->
+ Blocks = build_graph_1(Is, [], []),
+ maps:from_list(Blocks).
+
+build_graph_1([{label,L}|Is], Lbls, []) ->
+ build_graph_1(Is, [L|Lbls], []);
+build_graph_1([{label,L}|Is], Lbls, [_|_]=BlockAcc) ->
+ make_blocks(Lbls, BlockAcc) ++ build_graph_1(Is, [L], []);
+build_graph_1([I|Is], Lbls, BlockAcc) ->
+ build_graph_1(Is, Lbls, [I|BlockAcc]);
+build_graph_1([], Lbls, BlockAcc) ->
+ make_blocks(Lbls, BlockAcc).
+
+make_blocks(Lbls, [Last|Is0]) ->
+ Is = reverse(Is0),
+ Block = #b_blk{is=Is,last=Last},
+ [{L,Block} || L <- Lbls].
+
+drop_upto_label([{label,_}|_]=Is, Map) ->
+ {Is,Map};
+drop_upto_label([#cg_break{phi=Target}|Is], Map) ->
+ Pairs = case Map of
+ #{Target:=Pairs0} -> Pairs0;
+ #{} -> []
+ end,
+ drop_upto_label(Is, Map#{Target=>Pairs});
+drop_upto_label([_|Is], Map) ->
+ drop_upto_label(Is, Map).
+
+k_get_anno(Thing) -> element(2, Thing).
diff --git a/lib/compiler/src/beam_listing.erl b/lib/compiler/src/beam_listing.erl
index 836378727b..6121593b11 100644
--- a/lib/compiler/src/beam_listing.erl
+++ b/lib/compiler/src/beam_listing.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@
-include("core_parse.hrl").
-include("v3_kernel.hrl").
--include("v3_life.hrl").
+-include("beam_ssa.hrl").
-include("beam_disasm.hrl").
-import(lists, [foreach/2]).
@@ -31,7 +31,6 @@
-type code() :: cerl:c_module()
| beam_utils:module_code()
| #k_mdef{}
- | {module(),_,_,_} %v3_life
| [_]. %form-based format
-spec module(file:io_device(), code()) -> 'ok'.
@@ -43,13 +42,15 @@ module(File, #k_mdef{}=Kern) ->
%% This is a kernel module.
io:put_chars(File, v3_kernel_pp:format(Kern));
%%io:put_chars(File, io_lib:format("~p~n", [Kern]));
-module(File, {Mod,Exp,Attr,Kern}) ->
- %% This is output from beam_life (v3).
- io:fwrite(File, "~w.~n~p.~n~p.~n", [Mod,Exp,Attr]),
- foreach(fun (F) -> function(File, F) end, Kern);
+module(File, #b_module{name=Mod,exports=Exp,attributes=Attr,body=Fs}) ->
+ io:format(File, "module ~p.\n", [Mod]),
+ io:format(File, "exports ~p.\n", [Exp]),
+ io:format(File, "attributes ~p.\n\n", [Attr]),
+ PP = [beam_ssa_pp:format_function(F) || F <- Fs],
+ io:put_chars(File, lists:join($\n, PP));
module(Stream, {Mod,Exp,Attr,Code,NumLabels}) ->
- %% This is output from beam_codegen.
- io:format(Stream, "{module, ~p}. %% version = ~w\n",
+ %% This is output from v3_codegen.
+ io:format(Stream, "{module, ~p}. %% version = ~w\n",
[Mod, beam_opcodes:format_number()]),
io:format(Stream, "\n{exports, ~p}.\n", [Exp]),
io:format(Stream, "\n{attributes, ~p}.\n", [Attr]),
@@ -60,82 +61,12 @@ module(Stream, {Mod,Exp,Attr,Code,NumLabels}) ->
[Name, Arity, Entry]),
io:put_chars(Stream, format_asm(Asm))
end, Code);
-module(Stream, Code) when is_binary(Code) ->
- #beam_file{ module = Module, compile_info = CInfo } = beam_disasm:file(Code),
- Loaded = code:is_loaded(Module),
- Sticky = code:is_sticky(Module),
- [code:unstick_mod(Module) || Sticky],
-
- {module, Module} = code:load_binary(Module, proplists:get_value(source, CInfo), Code),
- ok = erts_debug:df(Stream, Module),
-
- %% Restore loaded module
- _ = [{module, Module} = code:load_file(Module) || Loaded =/= false],
- [code:stick_mod(Module) || Sticky],
- ok;
module(Stream, [_|_]=Fs) ->
%% Form-based abstract format.
foreach(fun (F) -> io:format(Stream, "~p.\n", [F]) end, Fs).
format_asm([{label,L}|Is]) ->
- [" {label,",integer_to_list(L),"}.\n"|format_asm(Is)];
+ [io_lib:format(" {label,~p}.\n", [L])|format_asm(Is)];
format_asm([I|Is]) ->
[io_lib:format(" ~p", [I]),".\n"|format_asm(Is)];
format_asm([]) -> [].
-
-function(File, {function,Name,Arity,Args,Body,Vdb,_Anno}) ->
- io:nl(File),
- io:format(File, "function ~p/~p.\n", [Name,Arity]),
- io:format(File, " ~p.\n", [Args]),
- print_vdb(File, Vdb),
- put(beam_listing_nl, false),
- nl(File),
- foreach(fun(F) -> format(File, F, []) end, Body),
- nl(File),
- erase(beam_listing_nl).
-
-format(File, #l{ke=Ke,i=I,vdb=Vdb}, Ind) ->
- nl(File),
- ind_format(File, Ind, "~p ", [I]),
- print_vdb(File, Vdb),
- nl(File),
- format(File, Ke, Ind);
-format(File, Tuple, Ind) when is_tuple(Tuple) ->
- ind_format(File, Ind, "{", []),
- format_list(File, tuple_to_list(Tuple), [$\s|Ind]),
- ind_format(File, Ind, "}", []);
-format(File, List, Ind) when is_list(List) ->
- ind_format(File, Ind, "[", []),
- format_list(File, List, [$\s|Ind]),
- ind_format(File, Ind, "]", []);
-format(File, F, Ind) ->
- ind_format(File, Ind, "~p", [F]).
-
-format_list(File, [F], Ind) ->
- format(File, F, Ind);
-format_list(File, [F|Fs], Ind) ->
- format(File, F, Ind),
- ind_format(File, Ind, ",", []),
- format_list(File, Fs, Ind);
-format_list(_, [], _) -> ok.
-
-
-print_vdb(File, [{Var,F,E}|Vs]) ->
- io:format(File, "~p:~p..~p ", [Var,F,E]),
- print_vdb(File, Vs);
-print_vdb(_, []) -> ok.
-
-ind_format(File, Ind, Format, Args) ->
- case get(beam_listing_nl) of
- true ->
- put(beam_listing_nl, false),
- io:put_chars(File, Ind);
- false -> ok
- end,
- io:format(File, Format, Args).
-
-nl(File) ->
- case put(beam_listing_nl, true) of
- true -> ok;
- false -> io:nl(File)
- end.
diff --git a/lib/compiler/src/beam_peep.erl b/lib/compiler/src/beam_peep.erl
index 6df5c02334..5730e9704e 100644
--- a/lib/compiler/src/beam_peep.erl
+++ b/lib/compiler/src/beam_peep.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -41,8 +41,7 @@ function({function,Name,Arity,CLabel,Is0}) ->
Is = beam_jump:remove_unused_labels(Is1),
{function,Name,Arity,CLabel,Is}
catch
- Class:Error ->
- Stack = erlang:get_stacktrace(),
+ Class:Error:Stack ->
io:fwrite("Function: ~w/~w\n", [Name,Arity]),
erlang:raise(Class, Error, Stack)
end.
@@ -78,6 +77,12 @@ peep([{bif,tuple_size,_,[_]=Ops,Dst}=I|Is], SeenTests0, Acc) ->
%% Kill all remembered tests that depend on the destination register.
SeenTests = kill_seen(Dst, SeenTests1),
peep(Is, SeenTests, [I|Acc]);
+peep([{bif,map_get,_,[Key,Map],Dst}=I|Is], SeenTests0, Acc) ->
+ %% Pretend that we have seen {test,has_map_fields,_,[Map,Key]}
+ SeenTests1 = gb_sets:add({has_map_fields,[Map,Key]}, SeenTests0),
+ %% Kill all remembered tests that depend on the destination register.
+ SeenTests = kill_seen(Dst, SeenTests1),
+ peep(Is, SeenTests, [I|Acc]);
peep([{bif,_,_,_,Dst}=I|Is], SeenTests0, Acc) ->
%% Kill all remembered tests that depend on the destination register.
SeenTests = kill_seen(Dst, SeenTests0),
@@ -89,15 +94,42 @@ peep([{gc_bif,_,_,_,_,Dst}=I|Is], SeenTests0, Acc) ->
peep([{jump,{f,L}},{label,L}=I|Is], _, Acc) ->
%% Sometimes beam_jump has missed this optimization.
peep(Is, gb_sets:empty(), [I|Acc]);
-peep([{select,Op,R,F,Vls0}|Is], _, Acc) ->
+peep([{select,select_val,R,F,Vls0}|Is], SeenTests0, Acc0) ->
case prune_redundant_values(Vls0, F) of
[] ->
%% No values left. Must convert to plain jump.
I = {jump,F},
- peep(Is, gb_sets:empty(), [I|Acc]);
+ peep([I|Is], gb_sets:empty(), Acc0);
+ [{atom,_}=Value,Lbl] ->
+ %% Single value left. Convert to regular test.
+ Is1 = [{test,is_eq_exact,F,[R,Value]},{jump,Lbl}|Is],
+ peep(Is1, SeenTests0, Acc0);
+ [{integer,_}=Value,Lbl] ->
+ %% Single value left. Convert to regular test.
+ Is1 = [{test,is_eq_exact,F,[R,Value]},{jump,Lbl}|Is],
+ peep(Is1, SeenTests0, Acc0);
+ [{atom,B1},Lbl,{atom,B2},Lbl] when B1 =:= not B2 ->
+ %% Replace with is_boolean test.
+ Is1 = [{test,is_boolean,F,[R]},{jump,Lbl}|Is],
+ peep(Is1, SeenTests0, Acc0);
[_|_]=Vls ->
- I = {select,Op,R,F,Vls},
- peep(Is, gb_sets:empty(), [I|Acc])
+ I = {select,select_val,R,F,Vls},
+ peep(Is, gb_sets:empty(), [I|Acc0])
+ end;
+peep([{get_map_elements,Fail,Src,List}=I|Is], _SeenTests, Acc0) ->
+ SeenTests = gb_sets:empty(),
+ case simplify_get_map_elements(Fail, Src, List, Acc0) of
+ {ok,Acc} ->
+ peep(Is, SeenTests, Acc);
+ error ->
+ peep(Is, SeenTests, [I|Acc0])
+ end;
+peep([{test,has_map_fields,Fail,Ops}=I|Is], SeenTests, Acc0) ->
+ case simplify_has_map_fields(Fail, Ops, Acc0) of
+ {ok,Acc} ->
+ peep(Is, SeenTests, Acc);
+ error ->
+ peep(Is, SeenTests, [I|Acc0])
end;
peep([{test,Op,_,Ops}=I|Is], SeenTests0, Acc) ->
case beam_utils:is_pure_test(I) of
@@ -149,3 +181,39 @@ prune_redundant_values([_Val,F|Vls], F) ->
prune_redundant_values([Val,Lbl|Vls], F) ->
[Val,Lbl|prune_redundant_values(Vls, F)];
prune_redundant_values([], _) -> [].
+
+simplify_get_map_elements(Fail, Src, {list,[Key,Dst]},
+ [{get_map_elements,Fail,Src,{list,List1}}|Acc]) ->
+ case are_keys_literals([Key]) andalso are_keys_literals(List1) of
+ true ->
+ case member(Key, List1) of
+ true ->
+ %% The key is already in the other list. That is
+ %% very unusual, because there are optimizations to get
+ %% rid of duplicate keys. Therefore, don't try to
+ %% do anything smart here; just keep the
+ %% get_map_elements instructions separate.
+ error;
+ false ->
+ List = [Key,Dst|List1],
+ {ok,[{get_map_elements,Fail,Src,{list,List}}|Acc]}
+ end;
+ false ->
+ error
+ end;
+simplify_get_map_elements(_, _, _, _) -> error.
+
+simplify_has_map_fields(Fail, [Src|Keys0],
+ [{test,has_map_fields,Fail,[Src|Keys1]}|Acc]) ->
+ case are_keys_literals(Keys0) andalso are_keys_literals(Keys1) of
+ true ->
+ Keys = Keys0 ++ Keys1,
+ {ok,[{test,has_map_fields,Fail,[Src|Keys]}|Acc]};
+ false ->
+ error
+ end;
+simplify_has_map_fields(_, _, _) -> error.
+
+are_keys_literals([{x,_}|_]) -> false;
+are_keys_literals([{y,_}|_]) -> false;
+are_keys_literals([_|_]) -> true.
diff --git a/lib/compiler/src/beam_receive.erl b/lib/compiler/src/beam_receive.erl
deleted file mode 100644
index 1403e1e05e..0000000000
--- a/lib/compiler/src/beam_receive.erl
+++ /dev/null
@@ -1,415 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
--module(beam_receive).
--export([module/2]).
--import(lists, [foldl/3,reverse/1,reverse/2]).
-
-%%%
-%%% In code such as:
-%%%
-%%% Ref = make_ref(), %Or erlang:monitor(process, Pid)
-%%% .
-%%% .
-%%% .
-%%% receive
-%%% {Ref,Reply} -> Reply
-%%% end.
-%%%
-%%% we know that none of the messages that exist in the message queue
-%%% before the call to make_ref/0 can be matched out in the receive
-%%% statement. Therefore we can avoid going through the entire message
-%%% queue if we introduce two new instructions (here written as
-%%% BIFs in pseudo-Erlang):
-%%%
-%%% recv_mark(SomeUniqInteger),
-%%% Ref = make_ref(),
-%%% .
-%%% .
-%%% .
-%%% recv_set(SomeUniqInteger),
-%%% receive
-%%% {Ref,Reply} -> Reply
-%%% end.
-%%%
-%%% The recv_mark/1 instruction will save the current position and
-%%% SomeUniqInteger in the process context. The recv_set
-%%% instruction will verify that SomeUniqInteger is still stored
-%%% in the process context. If it is, it will set the current pointer
-%%% for the message queue (the next message to be read out) to the
-%%% position that was saved by recv_mark/1.
-%%%
-%%% The remove_message instruction must be modified to invalidate
-%%% the information stored by the previous recv_mark/1, in case there
-%%% is another receive executed between the calls to recv_mark/1 and
-%%% recv_set/1.
-%%%
-%%% We use a reference to a label (i.e. a position in the loaded code)
-%%% as the SomeUniqInteger.
-%%%
-
--spec module(beam_utils:module_code(), [compile:option()]) ->
- {'ok',beam_utils:module_code()}.
-
-module({Mod,Exp,Attr,Fs0,Lc}, _Opts) ->
- Fs = [function(F) || F <- Fs0],
- Code = {Mod,Exp,Attr,Fs,Lc},
- {ok,Code}.
-
-%%%
-%%% Local functions.
-%%%
-
-function({function,Name,Arity,Entry,Is}) ->
- try
- D = beam_utils:index_labels(Is),
- {function,Name,Arity,Entry,opt(Is, D, [])}
- catch
- Class:Error ->
- Stack = erlang:get_stacktrace(),
- io:fwrite("Function: ~w/~w\n", [Name,Arity]),
- erlang:raise(Class, Error, Stack)
- end.
-
-opt([{call_ext,A,{extfunc,erlang,spawn_monitor,A}}=I0|Is0], D, Acc)
- when A =:= 1; A =:= 3 ->
- case ref_in_tuple(Is0) of
- no ->
- opt(Is0, D, [I0|Acc]);
- {yes,Regs,Is1,MatchReversed} ->
- %% The call creates a brand new reference. Now
- %% search for a receive statement in the same
- %% function that will match against the reference.
- case opt_recv(Is1, Regs, D) of
- no ->
- opt(Is0, D, [I0|Acc]);
- {yes,Is,Lbl} ->
- opt(Is, D, MatchReversed++[I0,{recv_mark,{f,Lbl}}|Acc])
- end
- end;
-opt([{call_ext,Arity,{extfunc,erlang,Name,Arity}}=I|Is0], D, Acc) ->
- case creates_new_ref(Name, Arity) of
- true ->
- %% The call creates a brand new reference. Now
- %% search for a receive statement in the same
- %% function that will match against the reference.
- case opt_recv(Is0, regs_init_x0(), D) of
- no ->
- opt(Is0, D, [I|Acc]);
- {yes,Is,Lbl} ->
- opt(Is, D, [I,{recv_mark,{f,Lbl}}|Acc])
- end;
- false ->
- opt(Is0, D, [I|Acc])
- end;
-opt([I|Is], D, Acc) ->
- opt(Is, D, [I|Acc]);
-opt([], _, Acc) ->
- reverse(Acc).
-
-ref_in_tuple([{test,is_tuple,_,[{x,0}]}=I1,
- {test,test_arity,_,[{x,0},2]}=I2,
- {block,[{set,[_],[{x,0}],{get_tuple_element,0}},
- {set,[Dst],[{x,0}],{get_tuple_element,1}}|Bl]}=I3|Is]) ->
- ref_in_tuple_1(Bl, Dst, Is, [I3,I2,I1]);
-ref_in_tuple([{test,is_tuple,_,[{x,0}]}=I1,
- {test,test_arity,_,[{x,0},2]}=I2,
- {block,[{set,[Dst],[{x,0}],{get_tuple_element,1}}|Bl]}=I3|Is]) ->
- ref_in_tuple_1(Bl, Dst, Is, [I3,I2,I1]);
-ref_in_tuple(_) -> no.
-
-ref_in_tuple_1(Bl, Dst, Is, MatchReversed) ->
- Regs0 = regs_init_singleton(Dst),
- Regs = opt_update_regs_bl(Bl, Regs0),
- {yes,Regs,Is,MatchReversed}.
-
-%% creates_new_ref(Name, Arity) -> true|false.
-%% Return 'true' if the BIF Name/Arity will create a new reference.
-creates_new_ref(monitor, 2) -> true;
-creates_new_ref(make_ref, 0) -> true;
-creates_new_ref(_, _) -> false.
-
-%% opt_recv([Instruction], Regs, LabelIndex) -> no|{yes,[Instruction]}
-%% Search for a receive statement that will only retrieve messages
-%% that contain the newly created reference (which is currently in {x,0}).
-opt_recv(Is, Regs, D) ->
- L = gb_sets:empty(),
- opt_recv(Is, D, Regs, L, []).
-
-opt_recv([{label,L}=Lbl,{loop_rec,{f,Fail},_}=Loop|Is], D, R0, _, Acc) ->
- R = regs_kill_not_live(0, R0),
- case regs_empty(R) of
- false ->
- %% We now have the new reference in Y registers
- %% and the current instruction is the beginning of a
- %% receive statement. We must now verify that only messages
- %% that contain the reference will be matched.
- case opt_ref_used(Is, R, Fail, D) of
- false ->
- no;
- true ->
- RecvSet = {recv_set,{f,L}},
- {yes,reverse(Acc, [RecvSet,Lbl,Loop|Is]),L}
- end;
- true ->
- no
- end;
-opt_recv([I|Is], D, R0, L0, Acc) ->
- {R,L} = opt_update_regs(I, R0, L0),
- case regs_empty(R) of
- true ->
- %% The reference is no longer alive. There is no
- %% point in continuing the search.
- no;
- false ->
- opt_recv(Is, D, R, L, [I|Acc])
- end;
-opt_recv([], _, _, _, _) -> no.
-
-opt_update_regs({block,Bl}, R, L) ->
- {opt_update_regs_bl(Bl, R),L};
-opt_update_regs({call,_,_}, R, L) ->
- {regs_kill_not_live(0, R),L};
-opt_update_regs({call_ext,_,_}, R, L) ->
- {regs_kill_not_live(0, R),L};
-opt_update_regs({call_fun,_}, R, L) ->
- {regs_kill_not_live(0, R),L};
-opt_update_regs({kill,Y}, R, L) ->
- {regs_kill([Y], R),L};
-opt_update_regs({'catch',_,{f,Lbl}}, R, L) ->
- {R,gb_sets:add(Lbl, L)};
-opt_update_regs({catch_end,_}, R, L) ->
- {R,L};
-opt_update_regs({label,Lbl}, R, L) ->
- case gb_sets:is_member(Lbl, L) of
- false ->
- %% We can't allow arbitrary labels (since the receive
- %% could be entered without first creating the reference).
- {regs_init(),L};
- true ->
- %% A catch label for a previously seen catch instruction is OK.
- {R,L}
- end;
-opt_update_regs({try_end,_}, R, L) ->
- {R,L};
-opt_update_regs({line,_}, R, L) ->
- {R,L};
-opt_update_regs(_I, _R, L) ->
- %% Unrecognized instruction. Abort the search.
- {regs_init(),L}.
-
-opt_update_regs_bl([{set,Ds,_,{alloc,Live,_}}|Is], Regs0) ->
- Regs1 = regs_kill_not_live(Live, Regs0),
- Regs = regs_kill(Ds, Regs1),
- opt_update_regs_bl(Is, Regs);
-opt_update_regs_bl([{set,[Dst]=Ds,[Src],move}|Is], Regs0) ->
- Regs1 = regs_kill(Ds, Regs0),
- Regs = case regs_is_member(Src, Regs1) of
- false -> Regs1;
- true -> regs_add(Dst, Regs1)
- end,
- opt_update_regs_bl(Is, Regs);
-opt_update_regs_bl([{set,Ds,_,_}|Is], Regs0) ->
- Regs = regs_kill(Ds, Regs0),
- opt_update_regs_bl(Is, Regs);
-opt_update_regs_bl([], Regs) -> Regs.
-
-%% opt_ref_used([Instruction], RefRegs, FailLabel, LabelIndex) -> true|false
-%% Return 'true' if it is certain that only messages that contain the same
-%% reference as in RefRegs can be matched out. Otherwise return 'false'.
-%%
-%% Basically, we follow all possible paths through the receive statement.
-%% If all paths are safe, we return 'true'.
-%%
-%% A branch to FailLabel is safe, because it exits the receive statement
-%% and no further message may be matched out.
-%%
-%% If a path hits an comparision between RefRegs and part of the message,
-%% that path is safe (any messages that may be matched further down the
-%% path is guaranteed to contain the reference).
-%%
-%% Otherwise, if we hit a 'remove_message' instruction, we give up
-%% and return 'false' (the optimization is definitely unsafe). If
-%% we hit an unrecognized instruction, we also give up and return
-%% 'false' (the optimization may be unsafe).
-
-opt_ref_used(Is, RefRegs, Fail, D) ->
- Done = gb_sets:singleton(Fail),
- Regs = regs_init_x0(),
- try
- _ = opt_ref_used_1(Is, RefRegs, D, Done, Regs),
- true
- catch
- throw:not_used ->
- false
- end.
-
-%% This functions only returns if all paths through the receive
-%% statement are safe, and throws an 'not_used' term otherwise.
-opt_ref_used_1([{block,Bl}|Is], RefRegs, D, Done, Regs0) ->
- Regs = opt_ref_used_bl(Bl, Regs0),
- opt_ref_used_1(Is, RefRegs, D, Done, Regs);
-opt_ref_used_1([{test,is_eq_exact,{f,Fail},Args}|Is],
- RefRegs, D, Done0, Regs) ->
- Done = opt_ref_used_at(Fail, RefRegs, D, Done0, Regs),
- case is_ref_msg_comparison(Args, RefRegs, Regs) of
- false ->
- opt_ref_used_1(Is, RefRegs, D, Done, Regs);
- true ->
- %% The instructions that follow (Is) can only be executed
- %% if the message contains the same reference as in RefRegs.
- Done
- end;
-opt_ref_used_1([{test,is_ne_exact,{f,Fail},Args}|Is],
- RefRegs, D, Done0, Regs) ->
- Done = opt_ref_used_1(Is, RefRegs, D, Done0, Regs),
- case is_ref_msg_comparison(Args, RefRegs, Regs) of
- false ->
- opt_ref_used_at(Fail, RefRegs, D, Done, Regs);
- true ->
- Done
- end;
-opt_ref_used_1([{test,_,{f,Fail},_}|Is], RefRegs, D, Done0, Regs) ->
- Done = opt_ref_used_at(Fail, RefRegs, D, Done0, Regs),
- opt_ref_used_1(Is, RefRegs, D, Done, Regs);
-opt_ref_used_1([{select,_,_,{f,Fail},List}|_], RefRegs, D, Done, Regs) ->
- Lbls = [F || {f,F} <- List] ++ [Fail],
- opt_ref_used_in_all(Lbls, RefRegs, D, Done, Regs);
-opt_ref_used_1([{label,Lbl}|Is], RefRegs, D, Done, Regs) ->
- case gb_sets:is_member(Lbl, Done) of
- true -> Done;
- false -> opt_ref_used_1(Is, RefRegs, D, Done, Regs)
- end;
-opt_ref_used_1([{loop_rec_end,_}|_], _, _, Done, _) ->
- Done;
-opt_ref_used_1([_I|_], _RefReg, _D, _Done, _Regs) ->
- %% The optimization may be unsafe.
- throw(not_used).
-
-%% is_ref_msg_comparison(Args, RefRegs, RegisterSet) -> true|false.
-%% Return 'true' if Args denotes a comparison between the
-%% reference and message or part of the message.
-is_ref_msg_comparison([R1,R2], RefRegs, Regs) ->
- (regs_is_member(R2, RefRegs) andalso regs_is_member(R1, Regs)) orelse
- (regs_is_member(R1, RefRegs) andalso regs_is_member(R2, Regs)).
-
-opt_ref_used_in_all([L|Ls], RefRegs, D, Done0, Regs) ->
- Done = opt_ref_used_at(L, RefRegs, D, Done0, Regs),
- opt_ref_used_in_all(Ls, RefRegs, D, Done, Regs);
-opt_ref_used_in_all([], _, _, Done, _) -> Done.
-
-opt_ref_used_at(Fail, RefRegs, D, Done0, Regs) ->
- case gb_sets:is_member(Fail, Done0) of
- true ->
- Done0;
- false ->
- Is = beam_utils:code_at(Fail, D),
- Done = opt_ref_used_1(Is, RefRegs, D, Done0, Regs),
- gb_sets:add(Fail, Done)
- end.
-
-opt_ref_used_bl([{set,[],[],remove_message}|_], _) ->
- %% We have proved that a message that does not depend on the
- %% reference can be matched out.
- throw(not_used);
-opt_ref_used_bl([{set,Ds,Ss,_}|Is], Regs0) ->
- case regs_all_members(Ss, Regs0) of
- false ->
- %% The destination registers may be assigned values that
- %% are not dependent on the message being matched.
- Regs = regs_kill(Ds, Regs0),
- opt_ref_used_bl(Is, Regs);
- true ->
- %% All the sources depend on the message directly or
- %% indirectly.
- Regs = regs_add_list(Ds, Regs0),
- opt_ref_used_bl(Is, Regs)
- end;
-opt_ref_used_bl([], Regs) -> Regs.
-
-%%%
-%%% Functions for keeping track of a set of registers.
-%%%
-
-%% regs_init() -> RegisterSet
-%% Return an empty set of registers.
-
-regs_init() ->
- {0,0}.
-
-%% regs_init_singleton(Register) -> RegisterSet
-%% Return a set that only contains one register.
-
-regs_init_singleton(Reg) ->
- regs_add(Reg, regs_init()).
-
-%% regs_init_x0() -> RegisterSet
-%% Return a set that only contains the {x,0} register.
-
-regs_init_x0() ->
- {1 bsl 0,0}.
-
-%% regs_empty(Register) -> true|false
-%% Test whether the register set is empty.
-
-regs_empty(R) ->
- R =:= {0,0}.
-
-%% regs_kill_not_live(Live, RegisterSet) -> RegisterSet'
-%% Kill all registers indicated not live by Live.
-
-regs_kill_not_live(Live, {Xregs,Yregs}) ->
- {Xregs band ((1 bsl Live)-1),Yregs}.
-
-%% regs_kill([Register], RegisterSet) -> RegisterSet'
-%% Kill all registers mentioned in the list of registers.
-
-regs_kill([{x,N}|Rs], {Xregs,Yregs}) ->
- regs_kill(Rs, {Xregs band (bnot (1 bsl N)),Yregs});
-regs_kill([{y,N}|Rs], {Xregs,Yregs}) ->
- regs_kill(Rs, {Xregs,Yregs band (bnot (1 bsl N))});
-regs_kill([{fr,_}|Rs], Regs) ->
- regs_kill(Rs, Regs);
-regs_kill([], Regs) -> Regs.
-
-regs_add_list(List, Regs) ->
- foldl(fun(R, A) -> regs_add(R, A) end, Regs, List).
-
-%% regs_add(Register, RegisterSet) -> RegisterSet'
-%% Add a new register to the set of registers.
-
-regs_add({x,N}, {Xregs,Yregs}) ->
- {Xregs bor (1 bsl N),Yregs};
-regs_add({y,N}, {Xregs,Yregs}) ->
- {Xregs,Yregs bor (1 bsl N)}.
-
-%% regs_all_members([Register], RegisterSet) -> true|false
-%% Test whether all of the registers are part of the register set.
-
-regs_all_members([R|Rs], Regs) ->
- regs_is_member(R, Regs) andalso regs_all_members(Rs, Regs);
-regs_all_members([], _) -> true.
-
-%% regs_is_member(Register, RegisterSet) -> true|false
-%% Test whether Register is part of the register set.
-
-regs_is_member({x,N}, {Regs,_}) -> Regs band (1 bsl N) =/= 0;
-regs_is_member({y,N}, {_,Regs}) -> Regs band (1 bsl N) =/= 0;
-regs_is_member(_, _) -> false.
diff --git a/lib/compiler/src/beam_record.erl b/lib/compiler/src/beam_record.erl
deleted file mode 100644
index 419089b1bc..0000000000
--- a/lib/compiler/src/beam_record.erl
+++ /dev/null
@@ -1,106 +0,0 @@
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2014-2017. 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: beam_record.erl
-%% Author: Björn-Egil Dahlberg
-%% Created: 2014-09-03
-%%
-
--module(beam_record).
--export([module/2]).
-
-%% Rewrite the instruction stream on tagged tuple tests.
-%% Tagged tuples means a tuple of any arity with an atom as its first element.
-%% Typically records, ok-tuples and error-tuples.
-%%
-%% from:
-%% ...
-%% {test,is_tuple,Fail,[Src]}.
-%% {test,test_arity,Fail,[Src,Sz]}.
-%% ...
-%% {get_tuple_element,Src,0,Dst}.
-%% ...
-%% {test,is_eq_exact,Fail,[Dst,Atom]}.
-%% ...
-%% to:
-%% ...
-%% {test,is_tagged_tuple,Fail,[Src,Sz,Atom]}.
-%% ...
-
-
--import(lists, [reverse/1]).
-
--spec module(beam_utils:module_code(), [compile:option()]) ->
- {'ok',beam_utils:module_code()}.
-
-module({Mod,Exp,Attr,Fs0,Lc}, _Opt) ->
- Fs = [function(F) || F <- Fs0],
- {ok,{Mod,Exp,Attr,Fs,Lc}}.
-
-function({function,Name,Arity,CLabel,Is}) ->
- try
- Idx = beam_utils:index_labels(Is),
- {function,Name,Arity,CLabel,rewrite(Is,Idx)}
- catch
- Class:Error ->
- Stack = erlang:get_stacktrace(),
- io:fwrite("Function: ~w/~w\n", [Name,Arity]),
- erlang:raise(Class, Error, Stack)
- end.
-
-rewrite(Is,Idx) ->
- rewrite(Is,Idx,[]).
-
-rewrite([{test,is_tuple,Fail,[Src]}=I1,
- {test,test_arity,Fail,[Src,N]}=I2|Is],Idx,Acc) ->
- case is_tagged_tuple(Is,Fail,Src,Idx) of
- no ->
- rewrite(Is,Idx,[I2,I1|Acc]);
- {Atom,[{block,[]}|Is1]} ->
- rewrite(Is1,Idx,[{test,is_tagged_tuple,Fail,[Src,N,Atom]}|Acc]);
- {Atom,Is1} ->
- rewrite(Is1,Idx,[{test,is_tagged_tuple,Fail,[Src,N,Atom]}|Acc])
- end;
-rewrite([I|Is],Idx,Acc) ->
- rewrite(Is,Idx,[I|Acc]);
-rewrite([],_,Acc) -> reverse(Acc).
-
-is_tagged_tuple([{block,[{set,[Dst],[Src],{get_tuple_element,0}}=B|Bs]},
- {test,is_eq_exact,Fail,[Dst,{atom,_}=Atom]}|Is],Fail,Src,Idx) ->
-
- %% if Dst is killed in the instruction stream and at fail label,
- %% we can safely remove get_tuple_element.
- %%
- %% if Dst is not killed in the stream, we cannot remove get_tuple_element
- %% since it is referenced.
-
- case is_killed(Dst,Is,Fail,Idx) of
- true -> {Atom,[{block,Bs}|Is]};
- false -> {Atom,[{block,[B|Bs]}|Is]}
- end;
-is_tagged_tuple([{block,[{set,_,_,_}=B|Bs]},
- {test,is_eq_exact,_,_}=I|Is],Fail,Src,Idx) ->
- case is_tagged_tuple([{block,Bs},I|Is],Fail,Src,Idx) of
- {Atom,[{block,Bsr}|Isr]} -> {Atom,[{block,[B|Bsr]}|Isr]};
- no -> no
- end;
-is_tagged_tuple(_Is,_Fail,_Src,_Idx) ->
- no.
-
-is_killed(Dst,Is,{_,Lbl},Idx) ->
- beam_utils:is_killed(Dst,Is,Idx) andalso
- beam_utils:is_killed_at(Dst,Lbl,Idx).
diff --git a/lib/compiler/src/beam_reorder.erl b/lib/compiler/src/beam_reorder.erl
deleted file mode 100644
index 910b7f6b0a..0000000000
--- a/lib/compiler/src/beam_reorder.erl
+++ /dev/null
@@ -1,151 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
--module(beam_reorder).
-
--export([module/2]).
--import(lists, [member/2,reverse/1]).
-
--spec module(beam_utils:module_code(), [compile:option()]) ->
- {'ok',beam_utils:module_code()}.
-
-module({Mod,Exp,Attr,Fs0,Lc}, _Opt) ->
- Fs = [function(F) || F <- Fs0],
- {ok,{Mod,Exp,Attr,Fs,Lc}}.
-
-function({function,Name,Arity,CLabel,Is0}) ->
- try
- Is = reorder(Is0),
- {function,Name,Arity,CLabel,Is}
- catch
- Class:Error ->
- Stack = erlang:get_stacktrace(),
- io:fwrite("Function: ~w/~w\n", [Name,Arity]),
- erlang:raise(Class, Error, Stack)
- end.
-
-%% reorder(Instructions0) -> Instructions
-%% Reorder instructions before the beam_block pass, because reordering
-%% will be more cumbersome when the blocks are in place.
-%%
-%% Execution of get_tuple_element instructions can be delayed until
-%% they are actually needed. Consider the sequence:
-%%
-%% get_tuple_element Tuple Pos Dst
-%% test Test Fail Operands
-%%
-%% If Dst is killed at label Fail (and not referenced in Operands),
-%% we can can swap the instructions:
-%%
-%% test Test Fail Operands
-%% get_tuple_element Tuple Pos Dst
-%%
-%% That can be beneficial in two ways: Firstly, if the branch is taken
-%% we have avoided execution of the get_tuple_element instruction.
-%% Secondly, even if the branch is not taken, subsequent optimization
-%% (opt_blocks/1) may be able to change Dst to the final destination
-%% register and eliminate a 'move' instruction.
-
-reorder(Is) ->
- D = beam_utils:index_labels(Is),
- reorder_1(Is, D, []).
-
-reorder_1([{Op,_,_}=TryCatch|[I|Is]=Is0], D, Acc)
- when Op =:= 'catch'; Op =:= 'try' ->
- %% Don't allow 'try' or 'catch' instructions to split blocks if
- %% it can be avoided.
- case is_safe(I) of
- false ->
- reorder_1(Is0, D, [TryCatch|Acc]);
- true ->
- reorder_1([TryCatch|Is], D, [I|Acc])
- end;
-reorder_1([{label,L}=I|_], D, Acc) ->
- Is = beam_utils:code_at(L, D),
- reorder_1(Is, D, [I|Acc]);
-reorder_1([{test,is_nonempty_list,_,_}=I|Is], D, Acc) ->
- %% The run-time system may combine the is_nonempty_list test with
- %% the following get_list instruction.
- reorder_1(Is, D, [I|Acc]);
-reorder_1([{test,_,_,_}=I,
- {select,_,_,_,_}=S|Is], D, Acc) ->
- %% There is nothing to gain by inserting a get_tuple_element
- %% instruction between the test instruction and the select
- %% instruction.
- reorder_1(Is, D, [S,I|Acc]);
-reorder_1([{test,_,{f,_},[Src|_]}=I|Is], D,
- [{get_tuple_element,Src,_,_}|_]=Acc) ->
- %% We want to avoid code that can confuse beam_validator such as:
- %% is_tuple Fail Src
- %% test_arity Fail Src Arity
- %% is_map Fail Src
- %% get_tuple_element Src Pos Dst
- %% Therefore, don't reorder the instructions in such cases.
- reorder_1(Is, D, [I|Acc]);
-reorder_1([{test,_,{f,L},Ss}=I|Is0], D0,
- [{get_tuple_element,_,_,El}=G|Acc0]=Acc) ->
- case member(El, Ss) of
- true ->
- reorder_1(Is0, D0, [I|Acc]);
- false ->
- case beam_utils:is_killed_at(El, L, D0) of
- true ->
- Is = [I,G|Is0],
- reorder_1(Is, D0, Acc0);
- false ->
- case beam_utils:is_killed(El, Is0, D0) of
- true ->
- Code0 = beam_utils:code_at(L, D0),
- Code = [G|Code0],
- D = beam_utils:index_label(L, Code, D0),
- Is = [I|Is0],
- reorder_1(Is, D, Acc0);
- false ->
- reorder_1(Is0, D0, [I|Acc])
- end
- end
- end;
-reorder_1([{allocate_zero,N,Live}=I0|Is], D,
- [{get_tuple_element,{x,Tup},_,{x,Dst}}=G|Acc]=Acc0) ->
- case Tup < Dst andalso Dst+1 =:= Live of
- true ->
- %% Move allocation instruction upwards past
- %% get_tuple_element instructions to create more
- %% opportunities for moving get_tuple_element
- %% instructions.
- I = {allocate_zero,N,Dst},
- reorder_1([I,G|Is], D, Acc);
- false ->
- reorder_1(Is, D, [I0|Acc0])
- end;
-reorder_1([I|Is], D, Acc) ->
- reorder_1(Is, D, [I|Acc]);
-reorder_1([], _, Acc) -> reverse(Acc).
-
-%% is_safe(Instruction) -> true|false
-%% Test whether an instruction is safe (cannot cause an exception).
-
-is_safe({kill,_}) -> true;
-is_safe({move,_,_}) -> true;
-is_safe({put,_}) -> true;
-is_safe({put_list,_,_,_}) -> true;
-is_safe({put_tuple,_,_}) -> true;
-is_safe({test_heap,_,_}) -> true;
-is_safe(_) -> false.
diff --git a/lib/compiler/src/beam_split.erl b/lib/compiler/src/beam_split.erl
deleted file mode 100644
index d041f18806..0000000000
--- a/lib/compiler/src/beam_split.erl
+++ /dev/null
@@ -1,95 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
--module(beam_split).
--export([module/2]).
-
--import(lists, [reverse/1]).
-
--spec module(beam_utils:module_code(), [compile:option()]) ->
- {'ok',beam_utils:module_code()}.
-
-module({Mod,Exp,Attr,Fs0,Lc}, _Opts) ->
- Fs = [split_blocks(F) || F <- Fs0],
- {ok,{Mod,Exp,Attr,Fs,Lc}}.
-
-%% We must split the basic block when we encounter instructions with labels,
-%% such as catches and BIFs. All labels must be visible outside the blocks.
-
-split_blocks({function,Name,Arity,CLabel,Is0}) ->
- Is = split_blocks(Is0, []),
- {function,Name,Arity,CLabel,Is}.
-
-split_blocks([{block,Bl}|Is], Acc0) ->
- Acc = split_block(Bl, [], Acc0),
- split_blocks(Is, Acc);
-split_blocks([I|Is], Acc) ->
- split_blocks(Is, [I|Acc]);
-split_blocks([], Acc) -> reverse(Acc).
-
-split_block([{set,[R],[_,_,_]=As,{bif,is_record,{f,Lbl}}}|Is], Bl, Acc) ->
- %% is_record/3 must be translated by beam_clean; therefore,
- %% it must be outside of any block.
- split_block(Is, [], [{bif,is_record,{f,Lbl},As,R}|make_block(Bl, Acc)]);
-split_block([{set,[R],As,{bif,N,{f,Lbl}=Fail}}|Is], Bl, Acc) when Lbl =/= 0 ->
- split_block(Is, [], [{bif,N,Fail,As,R}|make_block(Bl, Acc)]);
-split_block([{set,[R],As,{bif,raise,{f,_}=Fail}}|Is], Bl, Acc) ->
- split_block(Is, [], [{bif,raise,Fail,As,R}|make_block(Bl, Acc)]);
-split_block([{set,[R],As,{alloc,Live,{gc_bif,N,{f,Lbl}=Fail}}}|Is], Bl, Acc)
- when Lbl =/= 0 ->
- split_block(Is, [], [{gc_bif,N,Fail,Live,As,R}|make_block(Bl, Acc)]);
-split_block([{set,[D],[S|Puts],{alloc,R,{put_map,Op,{f,Lbl}=Fail}}}|Is],
- Bl, Acc) when Lbl =/= 0 ->
- split_block(Is, [], [{put_map,Fail,Op,S,D,R,{list,Puts}}|
- make_block(Bl, Acc)]);
-split_block([{set,[R],[],{try_catch,Op,L}}|Is], Bl, Acc) ->
- split_block(Is, [], [{Op,R,L}|make_block(Bl, Acc)]);
-split_block([{set,[],[],{line,_}=Line}|Is], Bl, Acc) ->
- split_block(Is, [], [Line|make_block(Bl, Acc)]);
-split_block([I|Is], Bl, Acc) ->
- split_block(Is, [I|Bl], Acc);
-split_block([], Bl, Acc) -> make_block(Bl, Acc).
-
-make_block([], Acc) -> Acc;
-make_block([{set,[D],Ss,{bif,Op,Fail}}|Bl]=Bl0, Acc) ->
- %% If the last instruction in the block is a comparison or boolean operator
- %% (such as '=:='), move it out of the block to facilitate further
- %% optimizations.
- Arity = length(Ss),
- case erl_internal:comp_op(Op, Arity) orelse
- erl_internal:new_type_test(Op, Arity) orelse
- erl_internal:bool_op(Op, Arity) of
- false ->
- [{block,reverse(Bl0)}|Acc];
- true ->
- I = {bif,Op,Fail,Ss,D},
- case Bl =:= [] of
- true -> [I|Acc];
- false -> [I,{block,reverse(Bl)}|Acc]
- end
- end;
-make_block([{set,[Dst],[Src],move}|Bl], Acc) ->
- %% Make optimization of {move,Src,Dst}, {jump,...} possible.
- I = {move,Src,Dst},
- case Bl =:= [] of
- true -> [I|Acc];
- false -> [I,{block,reverse(Bl)}|Acc]
- end;
-make_block(Bl, Acc) -> [{block,reverse(Bl)}|Acc].
diff --git a/lib/compiler/src/beam_ssa.erl b/lib/compiler/src/beam_ssa.erl
new file mode 100644
index 0000000000..a9977b0b1d
--- /dev/null
+++ b/lib/compiler/src/beam_ssa.erl
@@ -0,0 +1,890 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% Purpose: Type definitions and utilities for the SSA format.
+
+-module(beam_ssa).
+-export([add_anno/3,get_anno/2,get_anno/3,
+ clobbers_xregs/1,def/2,def_used/2,
+ definitions/1,
+ dominators/1,common_dominators/3,
+ flatmapfold_instrs_rpo/4,
+ fold_po/3,fold_po/4,fold_rpo/3,fold_rpo/4,
+ fold_instrs_rpo/4,
+ linearize/1,
+ mapfold_blocks_rpo/4,
+ mapfold_instrs_rpo/4,
+ normalize/1,
+ no_side_effect/1,
+ predecessors/1,
+ rename_vars/3,
+ rpo/1,rpo/2,
+ split_blocks/3,
+ successors/1,successors/2,
+ trim_unreachable/1,
+ update_phi_labels/4,used/1,
+ uses/1,uses/2]).
+
+-export_type([b_module/0,b_function/0,b_blk/0,b_set/0,
+ b_ret/0,b_br/0,b_switch/0,terminator/0,
+ b_var/0,b_literal/0,b_remote/0,b_local/0,
+ value/0,argument/0,label/0,
+ var_name/0,var_base/0,literal_value/0,
+ op/0,anno/0,block_map/0,dominator_map/0,
+ rename_map/0,rename_proplist/0,usage_map/0,
+ definition_map/0]).
+
+-include("beam_ssa.hrl").
+
+-type b_module() :: #b_module{}.
+-type b_function() :: #b_function{}.
+-type b_blk() :: #b_blk{}.
+-type b_set() :: #b_set{}.
+
+-type b_br() :: #b_br{}.
+-type b_ret() :: #b_ret{}.
+-type b_switch() :: #b_switch{}.
+-type terminator() :: b_br() | b_ret() | b_switch().
+
+-type construct() :: b_module() | b_function() | b_blk() | b_set() |
+ terminator().
+
+-type b_var() :: #b_var{}.
+-type b_literal() :: #b_literal{}.
+-type b_remote() :: #b_remote{}.
+-type b_local() :: #b_local{}.
+
+-type value() :: b_var() | b_literal().
+-type phi_value() :: {value(),label()}.
+-type argument() :: value() | b_remote() | b_local() | phi_value().
+-type label() :: non_neg_integer().
+
+-type var_name() :: var_base() | {var_base(),non_neg_integer()}.
+-type var_base() :: atom() | non_neg_integer().
+
+-type literal_value() :: atom() | integer() | float() | list() |
+ nil() | tuple() | map() | binary().
+
+-type op() :: {'bif',atom()} | {'float',float_op()} | prim_op() | cg_prim_op().
+-type anno() :: #{atom() := any()}.
+
+-type block_map() :: #{label():=b_blk()}.
+-type dominator_map() :: #{label():=[label()]}.
+-type numbering_map() :: #{label():=non_neg_integer()}.
+-type usage_map() :: #{b_var():=[{label(),b_set() | terminator()}]}.
+-type definition_map() :: #{b_var():=b_set()}.
+-type rename_map() :: #{b_var():=value()}.
+-type rename_proplist() :: [{b_var(),value()}].
+
+%% Note: By default, dialyzer will collapse this type to atom().
+%% To avoid the collapsing, change the value of SET_LIMIT to 50 in the
+%% file erl_types.erl in the hipe application.
+
+-type prim_op() :: 'bs_add' | 'bs_extract' | 'bs_init' | 'bs_init_writable' |
+ 'bs_match' | 'bs_put' | 'bs_start_match' | 'bs_test_tail' |
+ 'bs_utf16_size' | 'bs_utf8_size' | 'build_stacktrace' |
+ 'call' | 'catch_end' |
+ 'extract' |
+ 'get_hd' | 'get_map_element' | 'get_tl' | 'get_tuple_element' |
+ 'has_map_field' |
+ 'is_nonempty_list' | 'is_tagged_tuple' |
+ 'kill_try_tag' |
+ 'landingpad' |
+ 'make_fun' | 'new_try_tag' |
+ 'peek_message' | 'phi' | 'put_list' | 'put_map' | 'put_tuple' |
+ 'raw_raise' | 'recv_next' | 'remove_message' | 'resume' |
+ 'succeeded' |
+ 'timeout' |
+ 'wait' | 'wait_timeout'.
+
+-type float_op() :: 'checkerror' | 'clearerror' | 'convert' | 'get' | 'put' |
+ '+' | '-' | '*' | '/'.
+
+%% Primops only used internally during code generation.
+-type cg_prim_op() :: 'bs_get' | 'bs_match_string' | 'bs_restore' | 'bs_skip' |
+ 'copy' | 'put_tuple_arity' | 'put_tuple_element' |
+ 'set_tuple_element'.
+
+-import(lists, [foldl/3,keyfind/3,mapfoldl/3,member/2,reverse/1]).
+
+-spec add_anno(Key, Value, Construct) -> Construct when
+ Key :: atom(),
+ Value :: any(),
+ Construct :: construct().
+
+add_anno(Key, Val, #b_function{anno=Anno}=Bl) ->
+ Bl#b_function{anno=Anno#{Key=>Val}};
+add_anno(Key, Val, #b_blk{anno=Anno}=Bl) ->
+ Bl#b_blk{anno=Anno#{Key=>Val}};
+add_anno(Key, Val, #b_set{anno=Anno}=Bl) ->
+ Bl#b_set{anno=Anno#{Key=>Val}};
+add_anno(Key, Val, #b_br{anno=Anno}=Bl) ->
+ Bl#b_br{anno=Anno#{Key=>Val}};
+add_anno(Key, Val, #b_ret{anno=Anno}=Bl) ->
+ Bl#b_ret{anno=Anno#{Key=>Val}};
+add_anno(Key, Val, #b_switch{anno=Anno}=Bl) ->
+ Bl#b_switch{anno=Anno#{Key=>Val}}.
+
+-spec get_anno(atom(), construct()) -> any().
+
+get_anno(Key, Construct) ->
+ map_get(Key, get_anno(Construct)).
+
+-spec get_anno(atom(), construct(),any()) -> any().
+
+get_anno(Key, Construct, Default) ->
+ maps:get(Key, get_anno(Construct), Default).
+
+get_anno(#b_function{anno=Anno}) -> Anno;
+get_anno(#b_blk{anno=Anno}) -> Anno;
+get_anno(#b_set{anno=Anno}) -> Anno;
+get_anno(#b_br{anno=Anno}) -> Anno;
+get_anno(#b_ret{anno=Anno}) -> Anno;
+get_anno(#b_switch{anno=Anno}) -> Anno.
+
+%% clobbers_xregs(#b_set{}) -> true|false.
+%% Test whether the instruction invalidates all X registers.
+
+-spec clobbers_xregs(b_set()) -> boolean().
+
+clobbers_xregs(#b_set{op=Op}) ->
+ case Op of
+ bs_init_writable -> true;
+ build_stacktrace -> true;
+ call -> true;
+ landingpad -> true;
+ make_fun -> true;
+ peek_message -> true;
+ raw_raise -> true;
+ _ -> false
+ end.
+
+%% no_side_effect(#b_set{}) -> true|false.
+%% Test whether this instruction has no side effect and thus is safe
+%% not to execute if its value is not used. Note that even if `true`
+%% is returned, the instruction could still be impure (e.g. bif:get).
+
+-spec no_side_effect(b_set()) -> boolean().
+
+no_side_effect(#b_set{op=Op}) ->
+ case Op of
+ {bif,_} -> true;
+ {float,get} -> true;
+ bs_init -> true;
+ bs_extract -> true;
+ bs_match -> true;
+ bs_start_match -> true;
+ bs_test_tail -> true;
+ bs_get_tail -> true;
+ bs_put -> true;
+ extract -> true;
+ get_hd -> true;
+ get_tl -> true;
+ get_map_element -> true;
+ get_tuple_element -> true;
+ has_map_field -> true;
+ is_nonempty_list -> true;
+ is_tagged_tuple -> true;
+ make_fun -> true;
+ put_map -> true;
+ put_list -> true;
+ put_tuple -> true;
+ succeeded -> true;
+ _ -> false
+ end.
+
+-spec predecessors(Blocks) -> #{BlockNumber:=[Predecessor]} when
+ Blocks :: block_map(),
+ BlockNumber :: label(),
+ Predecessor :: label().
+
+predecessors(Blocks) ->
+ P0 = [{S,L} || {L,Blk} <- maps:to_list(Blocks),
+ S <- successors(Blk)],
+ P1 = sofs:relation(P0),
+ P2 = sofs:rel2fam(P1),
+ P3 = sofs:to_external(P2),
+ P = [{0,[]}|P3],
+ maps:from_list(P).
+
+-spec successors(b_blk()) -> [label()].
+
+successors(#b_blk{last=Terminator}) ->
+ case Terminator of
+ #b_br{bool=#b_literal{val=true},succ=Succ} ->
+ [Succ];
+ #b_br{bool=#b_literal{val=false},fail=Fail} ->
+ [Fail];
+ #b_br{succ=Succ,fail=Fail} ->
+ [Fail,Succ];
+ #b_switch{fail=Fail,list=List} ->
+ [Fail|[L || {_,L} <- List]];
+ #b_ret{} ->
+ []
+ end.
+
+%% normalize(Instr0) -> Instr.
+%% Normalize instructions to help optimizations.
+%%
+%% For commutative operators (such as '+' and 'or'), always
+%% place a variable operand before a literal operand.
+%%
+%% Normalize #b_br{} to one of the following forms:
+%%
+%% #b_br{b_literal{val=true},succ=Label,fail=Label}
+%% #b_br{b_var{},succ=Label1,fail=Label2} where Label1 =/= Label2
+%%
+%% Simplify a #b_switch{} with a literal argument to a #b_br{}.
+%%
+%% Simplify a #b_switch{} with a variable argument and an empty
+%% switch list to a #b_br{}.
+
+-spec normalize(b_set() | terminator()) ->
+ b_set() | terminator().
+
+normalize(#b_set{op={bif,Bif},args=Args}=Set) ->
+ case {is_commutative(Bif),Args} of
+ {false,_} ->
+ Set;
+ {true,[#b_literal{}=Lit,#b_var{}=Var]} ->
+ Set#b_set{args=[Var,Lit]};
+ {true,_} ->
+ Set
+ end;
+normalize(#b_set{}=Set) ->
+ Set;
+normalize(#b_br{}=Br) ->
+ case Br of
+ #b_br{bool=Bool,succ=Same,fail=Same} ->
+ case Bool of
+ #b_literal{val=true} ->
+ Br;
+ _ ->
+ Br#b_br{bool=#b_literal{val=true}}
+ end;
+ #b_br{bool=#b_literal{val=true},succ=Succ} ->
+ Br#b_br{fail=Succ};
+ #b_br{bool=#b_literal{val=false},fail=Fail} ->
+ Br#b_br{bool=#b_literal{val=true},succ=Fail};
+ #b_br{} ->
+ Br
+ end;
+normalize(#b_switch{arg=Arg,fail=Fail,list=List}=Sw) ->
+ case Arg of
+ #b_literal{} ->
+ case keyfind(Arg, 1, List) of
+ false ->
+ #b_br{bool=#b_literal{val=true},succ=Fail,fail=Fail};
+ {Arg,L} ->
+ #b_br{bool=#b_literal{val=true},succ=L,fail=L}
+ end;
+ #b_var{} when List =:= [] ->
+ #b_br{bool=#b_literal{val=true},succ=Fail,fail=Fail};
+ #b_var{} ->
+ Sw
+ end;
+normalize(#b_ret{}=Ret) ->
+ Ret.
+
+-spec successors(label(), block_map()) -> [label()].
+
+successors(L, Blocks) ->
+ successors(map_get(L, Blocks)).
+
+-spec def(Ls, Blocks) -> Def when
+ Ls :: [label()],
+ Blocks :: block_map(),
+ Def :: ordsets:ordset(var_name()).
+
+def(Ls, Blocks) ->
+ Top = rpo(Ls, Blocks),
+ Blks = [map_get(L, Blocks) || L <- Top],
+ def_1(Blks, []).
+
+-spec def_used(Ls, Blocks) -> {Def,Used} when
+ Ls :: [label()],
+ Blocks :: block_map(),
+ Def :: ordsets:ordset(var_name()),
+ Used :: ordsets:ordset(var_name()).
+
+def_used(Ls, Blocks) ->
+ Top = rpo(Ls, Blocks),
+ Blks = [map_get(L, Blocks) || L <- Top],
+ Preds = cerl_sets:from_list(Top),
+ def_used_1(Blks, Preds, [], []).
+
+%% dominators(BlockMap) -> {Dominators,Numbering}.
+%% Calculate the dominator tree, returning a map where each entry
+%% in the map is a list that gives the path from that block to
+%% the top of the dominator tree. (Note that the suffixes of the
+%% paths are shared with each other, which make the representation
+%% of the dominator tree highly memory-efficient.)
+%%
+%% The implementation is based on:
+%%
+%% http://www.hipersoft.rice.edu/grads/publications/dom14.pdf
+%% Cooper, Keith D.; Harvey, Timothy J; Kennedy, Ken (2001).
+%% A Simple, Fast Dominance Algorithm.
+
+-spec dominators(Blocks) -> Result when
+ Blocks :: block_map(),
+ Result :: {dominator_map(), numbering_map()}.
+dominators(Blocks) ->
+ Preds = predecessors(Blocks),
+ Top0 = rpo(Blocks),
+ Df = maps:from_list(number(Top0, 0)),
+ [{0,[]}|Top] = [{L,map_get(L, Preds)} || L <- Top0],
+
+ %% The flow graph for an Erlang function is reducible, and
+ %% therefore one traversal in reverse postorder is sufficient.
+ Acc = #{0=>[0]},
+ {dominators_1(Top, Df, Acc),Df}.
+
+%% common_dominators([Label], Dominators, Numbering) -> [Label].
+%% Calculate the common dominators for the given list of blocks
+%% and Dominators and Numbering as returned from dominators/1.
+
+-spec common_dominators([label()], dominator_map(), numbering_map()) -> [label()].
+common_dominators(Ls, Dom, Numbering) ->
+ Doms = [map_get(L, Dom) || L <- Ls],
+ dom_intersection(Doms, Numbering).
+
+-spec fold_instrs_rpo(Fun, From, Acc0, Blocks) -> any() when
+ Fun :: fun((b_blk()|terminator(), any()) -> any()),
+ From :: [label()],
+ Acc0 :: any(),
+ Blocks :: block_map().
+
+fold_instrs_rpo(Fun, From, Acc0, Blocks) ->
+ Top = rpo(From, Blocks),
+ fold_instrs_rpo_1(Top, Fun, Blocks, Acc0).
+
+%% Like mapfold_instrs_rpo but at the block level to support lookahead and
+%% scope-dependent transformations.
+-spec mapfold_blocks_rpo(Fun, From, Acc, Blocks) -> Result when
+ Fun :: fun((label(), b_blk(), any()) -> {b_blk(), any()}),
+ From :: [label()],
+ Acc :: any(),
+ Blocks :: block_map(),
+ Result :: {block_map(), any()}.
+mapfold_blocks_rpo(Fun, From, Acc, Blocks) ->
+ Successors = rpo(From, Blocks),
+ foldl(fun(Lbl, A) ->
+ mapfold_blocks_rpo_1(Fun, Lbl, A)
+ end, {Blocks, Acc}, Successors).
+
+mapfold_blocks_rpo_1(Fun, Lbl, {Blocks0, Acc0}) ->
+ Block0 = map_get(Lbl, Blocks0),
+ {Block, Acc} = Fun(Lbl, Block0, Acc0),
+ Blocks = Blocks0#{Lbl:=Block},
+ {Blocks, Acc}.
+
+-spec mapfold_instrs_rpo(Fun, From, Acc0, Blocks0) -> {Blocks,Acc} when
+ Fun :: fun((b_blk()|terminator(), any()) -> any()),
+ From :: [label()],
+ Acc0 :: any(),
+ Acc :: any(),
+ Blocks0 :: block_map(),
+ Blocks :: block_map().
+
+mapfold_instrs_rpo(Fun, From, Acc0, Blocks) ->
+ Top = rpo(From, Blocks),
+ mapfold_instrs_rpo_1(Top, Fun, Blocks, Acc0).
+
+-spec flatmapfold_instrs_rpo(Fun, From, Acc0, Blocks0) -> {Blocks,Acc} when
+ Fun :: fun((b_blk()|terminator(), any()) -> any()),
+ From :: [label()],
+ Acc0 :: any(),
+ Acc :: any(),
+ Blocks0 :: block_map(),
+ Blocks :: block_map().
+
+flatmapfold_instrs_rpo(Fun, From, Acc0, Blocks) ->
+ Top = rpo(From, Blocks),
+ flatmapfold_instrs_rpo_1(Top, Fun, Blocks, Acc0).
+
+-type fold_fun() :: fun((label(), b_blk(), any()) -> any()).
+
+%% fold_rpo(Fun, [Label], Acc0, Blocks) -> Acc.
+%% Fold over all blocks a reverse postorder traversal of the block
+%% graph; that is, first visit a block, then visit its successors.
+
+-spec fold_rpo(Fun, Acc0, Blocks) -> any() when
+ Fun :: fold_fun(),
+ Acc0 :: any(),
+ Blocks :: #{label():=b_blk()}.
+
+fold_rpo(Fun, Acc0, Blocks) ->
+ fold_rpo(Fun, [0], Acc0, Blocks).
+
+%% fold_rpo(Fun, [Label], Acc0, Blocks) -> Acc. Fold over all blocks
+%% reachable from a given set of labels in a reverse postorder
+%% traversal of the block graph; that is, first visit a block, then
+%% visit its successors.
+
+-spec fold_rpo(Fun, Labels, Acc0, Blocks) -> any() when
+ Fun :: fold_fun(),
+ Labels :: [label()],
+ Acc0 :: any(),
+ Blocks :: #{label():=b_blk()}.
+
+fold_rpo(Fun, From, Acc0, Blocks) ->
+ Top = rpo(From, Blocks),
+ fold_rpo_1(Top, Fun, Blocks, Acc0).
+
+%% fold_po(Fun, Acc0, Blocks) -> Acc.
+%% Fold over all blocks in a postorder traversal of the block graph;
+%% that is, first visit all successors of block, then the block
+%% itself.
+
+-spec fold_po(Fun, Acc0, Blocks) -> any() when
+ Fun :: fold_fun(),
+ Acc0 :: any(),
+ Blocks :: #{label():=b_blk()}.
+
+%% fold_po(Fun, From, Acc0, Blocks) -> Acc.
+%% Fold over the blocks reachable from the block numbers given
+%% by From in a postorder traversal of the block graph.
+
+fold_po(Fun, Acc0, Blocks) ->
+ fold_po(Fun, [0], Acc0, Blocks).
+
+-spec fold_po(Fun, Labels, Acc0, Blocks) -> any() when
+ Fun :: fold_fun(),
+ Labels :: [label()],
+ Acc0 :: any(),
+ Blocks :: block_map().
+
+fold_po(Fun, From, Acc0, Blocks) ->
+ Top = reverse(rpo(From, Blocks)),
+ fold_rpo_1(Top, Fun, Blocks, Acc0).
+
+%% linearize(Blocks) -> [{BlockLabel,#b_blk{}}].
+%% Linearize the intermediate representation of the code.
+%% Unreachable blocks will be discarded, and phi nodes will
+%% be adjusted so that they no longer refers to discarded
+%% blocks or to blocks that no longer are predecessors of
+%% the phi node block.
+
+-spec linearize(Blocks) -> Linear when
+ Blocks :: block_map(),
+ Linear :: [{label(),b_blk()}].
+
+linearize(Blocks) ->
+ Seen = cerl_sets:new(),
+ {Linear0,_} = linearize_1([0], Blocks, Seen, []),
+ Linear = fix_phis(Linear0, #{}),
+ Linear.
+
+-spec rpo(Blocks) -> [Label] when
+ Blocks :: block_map(),
+ Label :: label().
+
+rpo(Blocks) ->
+ rpo([0], Blocks).
+
+-spec rpo(From, Blocks) -> Labels when
+ From :: [label()],
+ Blocks :: block_map(),
+ Labels :: [label()].
+
+rpo(From, Blocks) ->
+ Seen = cerl_sets:new(),
+ {Ls,_} = rpo_1(From, Blocks, Seen, []),
+ Ls.
+
+-spec rename_vars(Rename, [label()], block_map()) -> block_map() when
+ Rename :: rename_map() | rename_proplist().
+
+rename_vars(Rename, From, Blocks) when is_list(Rename) ->
+ rename_vars(maps:from_list(Rename), From, Blocks);
+rename_vars(Rename, From, Blocks) when is_map(Rename)->
+ Top = rpo(From, Blocks),
+ Preds = cerl_sets:from_list(Top),
+ F = fun(#b_set{op=phi,args=Args0}=Set) ->
+ Args = rename_phi_vars(Args0, Preds, Rename),
+ Set#b_set{args=Args};
+ (#b_set{args=Args0}=Set) ->
+ Args = [rename_var(A, Rename) || A <- Args0],
+ Set#b_set{args=Args};
+ (#b_switch{arg=Bool}=Sw) ->
+ Sw#b_switch{arg=rename_var(Bool, Rename)};
+ (#b_br{bool=Bool}=Br) ->
+ Br#b_br{bool=rename_var(Bool, Rename)};
+ (#b_ret{arg=Arg}=Ret) ->
+ Ret#b_ret{arg=rename_var(Arg, Rename)}
+ end,
+ map_instrs_1(Top, F, Blocks).
+
+%% split_blocks(Predicate, Blocks0, Count0) -> {Blocks,Count}.
+%% Call Predicate(Instruction) for each instruction in all
+%% blocks. If Predicate/1 returns true, split the block
+%% before this instruction.
+
+-spec split_blocks(Pred, Blocks0, Count0) -> {Blocks,Count} when
+ Pred :: fun((b_set()) -> boolean()),
+ Blocks :: block_map(),
+ Count0 :: beam_ssa:label(),
+ Blocks0 :: block_map(),
+ Blocks :: block_map(),
+ Count :: beam_ssa:label().
+
+split_blocks(P, Blocks, Count) ->
+ Ls = beam_ssa:rpo(Blocks),
+ split_blocks_1(Ls, P, Blocks, Count).
+
+-spec trim_unreachable(Blocks0) -> Blocks when
+ Blocks0 :: block_map(),
+ Blocks :: block_map().
+
+%% trim_unreachable(Blocks0) -> Blocks.
+%% Remove all unreachable blocks. Adjust all phi nodes so
+%% they don't refer to blocks that has been removed or no
+%% no longer branch to the phi node in question.
+
+trim_unreachable(Blocks) ->
+ %% Could perhaps be optimized if there is any need.
+ maps:from_list(linearize(Blocks)).
+
+%% update_phi_labels([BlockLabel], Old, New, Blocks0) -> Blocks.
+%% In the given blocks, replace label Old in with New in all
+%% phi nodes. This is useful after merging or splitting
+%% blocks.
+
+-spec update_phi_labels(From, Old, New, Blocks0) -> Blocks when
+ From :: [label()],
+ Old :: label(),
+ New :: label(),
+ Blocks0 :: block_map(),
+ Blocks :: block_map().
+
+update_phi_labels([L|Ls], Old, New, Blocks0) ->
+ case Blocks0 of
+ #{L:=#b_blk{is=[#b_set{op=phi}|_]=Is0}=Blk0} ->
+ Is = update_phi_labels_is(Is0, Old, New),
+ Blk = Blk0#b_blk{is=Is},
+ Blocks = Blocks0#{L:=Blk},
+ update_phi_labels(Ls, Old, New, Blocks);
+ #{L:=#b_blk{}} ->
+ %% No phi nodes in this block.
+ update_phi_labels(Ls, Old, New, Blocks0)
+ end;
+update_phi_labels([], _, _, Blocks) -> Blocks.
+
+-spec used(b_blk() | b_set() | terminator()) -> [var_name()].
+
+used(#b_blk{is=Is,last=Last}) ->
+ used_1([Last|Is], ordsets:new());
+used(#b_br{bool=#b_var{}=V}) ->
+ [V];
+used(#b_ret{arg=#b_var{}=V}) ->
+ [V];
+used(#b_set{op=phi,args=Args}) ->
+ ordsets:from_list([V || {#b_var{}=V,_} <- Args]);
+used(#b_set{args=Args}) ->
+ ordsets:from_list(used_args(Args));
+used(#b_switch{arg=#b_var{}=V}) ->
+ [V];
+used(_) -> [].
+
+-spec definitions(Blocks :: block_map()) -> definition_map().
+definitions(Blocks) ->
+ fold_instrs_rpo(fun(#b_set{ dst = Var }=I, Acc) ->
+ Acc#{Var => I};
+ (_Terminator, Acc) ->
+ Acc
+ end, [0], #{}, Blocks).
+
+-spec uses(Blocks :: block_map()) -> usage_map().
+uses(Blocks) ->
+ uses([0], Blocks).
+
+-spec uses(From, Blocks) -> usage_map() when
+ From :: [label()],
+ Blocks :: block_map().
+uses(From, Blocks) ->
+ fold_rpo(fun fold_uses_block/3, From, #{}, Blocks).
+
+fold_uses_block(Lbl, #b_blk{is=Is,last=Last}, UseMap0) ->
+ F = fun(I, UseMap) ->
+ foldl(fun(Var, Acc) ->
+ Uses0 = maps:get(Var, Acc, []),
+ Uses = [{Lbl, I} | Uses0],
+ maps:put(Var, Uses, Acc)
+ end, UseMap, used(I))
+ end,
+ F(Last, foldl(F, UseMap0, Is)).
+
+%%%
+%%% Internal functions.
+%%%
+
+is_commutative('and') -> true;
+is_commutative('or') -> true;
+is_commutative('xor') -> true;
+is_commutative('band') -> true;
+is_commutative('bor') -> true;
+is_commutative('bxor') -> true;
+is_commutative('+') -> true;
+is_commutative('*') -> true;
+is_commutative('=:=') -> true;
+is_commutative('==') -> true;
+is_commutative('=/=') -> true;
+is_commutative('/=') -> true;
+is_commutative(_) -> false.
+
+def_used_1([#b_blk{is=Is,last=Last}|Bs], Preds, Def0, Used0) ->
+ {Def,Used1} = def_used_is(Is, Preds, Def0, Used0),
+ Used = ordsets:union(used(Last), Used1),
+ def_used_1(Bs, Preds, Def, Used);
+def_used_1([], _Preds, Def, Used) ->
+ {ordsets:from_list(Def),Used}.
+
+def_used_is([#b_set{op=phi,dst=Dst,args=Args}|Is],
+ Preds, Def0, Used0) ->
+ Def = [Dst|Def0],
+ %% We must be careful to only include variables that will
+ %% be used when arriving from one of the predecessor blocks
+ %% in Preds.
+ Used1 = [V || {#b_var{}=V,L} <- Args, cerl_sets:is_element(L, Preds)],
+ Used = ordsets:union(ordsets:from_list(Used1), Used0),
+ def_used_is(Is, Preds, Def, Used);
+def_used_is([#b_set{dst=Dst}=I|Is], Preds, Def0, Used0) ->
+ Def = [Dst|Def0],
+ Used = ordsets:union(used(I), Used0),
+ def_used_is(Is, Preds, Def, Used);
+def_used_is([], _Preds, Def, Used) ->
+ {Def,Used}.
+
+def_1([#b_blk{is=Is}|Bs], Def0) ->
+ Def = def_is(Is, Def0),
+ def_1(Bs, Def);
+def_1([], Def) ->
+ ordsets:from_list(Def).
+
+def_is([#b_set{dst=Dst}|Is], Def) ->
+ def_is(Is, [Dst|Def]);
+def_is([], Def) -> Def.
+
+dominators_1([{L,Preds}|Ls], Df, Doms) ->
+ DomPreds = [map_get(P, Doms) || P <- Preds, is_map_key(P, Doms)],
+ Dom = [L|dom_intersection(DomPreds, Df)],
+ dominators_1(Ls, Df, Doms#{L=>Dom});
+dominators_1([], _Df, Doms) -> Doms.
+
+dom_intersection([S], _Df) ->
+ S;
+dom_intersection([S|Ss], Df) ->
+ dom_intersection(S, Ss, Df).
+
+dom_intersection(S1, [S2|Ss], Df) ->
+ dom_intersection(dom_intersection_1(S1, S2, Df), Ss, Df);
+dom_intersection(S, [], _Df) -> S.
+
+dom_intersection_1([E1|Es1]=Set1, [E2|Es2]=Set2, Df) ->
+ %% Blocks are numbered in the order they are found in
+ %% reverse postorder.
+ #{E1:=Df1,E2:=Df2} = Df,
+ if Df1 > Df2 ->
+ dom_intersection_1(Es1, Set2, Df);
+ Df2 > Df1 ->
+ dom_intersection_1(Es2, Set1, Df); %switch arguments!
+ true -> %Set1 == Set2
+ %% The common suffix of the sets is the intersection.
+ Set1
+ end.
+
+number([L|Ls], N) ->
+ [{L,N}|number(Ls, N+1)];
+number([], _) -> [].
+
+fold_rpo_1([L|Ls], Fun, Blocks, Acc0) ->
+ Block = map_get(L, Blocks),
+ Acc = Fun(L, Block, Acc0),
+ fold_rpo_1(Ls, Fun, Blocks, Acc);
+fold_rpo_1([], _, _, Acc) -> Acc.
+
+fold_instrs_rpo_1([L|Ls], Fun, Blocks, Acc0) ->
+ #b_blk{is=Is,last=Last} = map_get(L, Blocks),
+ Acc1 = foldl(Fun, Acc0, Is),
+ Acc = Fun(Last, Acc1),
+ fold_instrs_rpo_1(Ls, Fun, Blocks, Acc);
+fold_instrs_rpo_1([], _, _, Acc) -> Acc.
+
+mapfold_instrs_rpo_1([L|Ls], Fun, Blocks0, Acc0) ->
+ #b_blk{is=Is0,last=Last0} = Block0 = map_get(L, Blocks0),
+ {Is,Acc1} = mapfoldl(Fun, Acc0, Is0),
+ {Last,Acc} = Fun(Last0, Acc1),
+ Block = Block0#b_blk{is=Is,last=Last},
+ Blocks = Blocks0#{L:=Block},
+ mapfold_instrs_rpo_1(Ls, Fun, Blocks, Acc);
+mapfold_instrs_rpo_1([], _, Blocks, Acc) ->
+ {Blocks,Acc}.
+
+flatmapfold_instrs_rpo_1([L|Ls], Fun, Blocks0, Acc0) ->
+ #b_blk{is=Is0,last=Last0} = Block0 = map_get(L, Blocks0),
+ {Is,Acc1} = flatmapfoldl(Fun, Acc0, Is0),
+ {[Last],Acc} = Fun(Last0, Acc1),
+ Block = Block0#b_blk{is=Is,last=Last},
+ Blocks = Blocks0#{L:=Block},
+ flatmapfold_instrs_rpo_1(Ls, Fun, Blocks, Acc);
+flatmapfold_instrs_rpo_1([], _, Blocks, Acc) ->
+ {Blocks,Acc}.
+
+linearize_1([L|Ls], Blocks, Seen0, Acc0) ->
+ case cerl_sets:is_element(L, Seen0) of
+ true ->
+ linearize_1(Ls, Blocks, Seen0, Acc0);
+ false ->
+ Seen1 = cerl_sets:add_element(L, Seen0),
+ Block = map_get(L, Blocks),
+ Successors = successors(Block),
+ {Acc,Seen} = linearize_1(Successors, Blocks, Seen1, Acc0),
+ linearize_1(Ls, Blocks, Seen, [{L,Block}|Acc])
+ end;
+linearize_1([], _, Seen, Acc) ->
+ {Acc,Seen}.
+
+fix_phis([{L,Blk0}|Bs], S) ->
+ Blk = case Blk0 of
+ #b_blk{is=[#b_set{op=phi}|_]=Is0} ->
+ Is = fix_phis_1(Is0, L, S),
+ Blk0#b_blk{is=Is};
+ #b_blk{} ->
+ Blk0
+ end,
+ Successors = successors(Blk),
+ [{L,Blk}|fix_phis(Bs, S#{L=>Successors})];
+fix_phis([], _) -> [].
+
+fix_phis_1([#b_set{op=phi,args=Args0}=I|Is], L, S) ->
+ Args = [{Val,Pred} || {Val,Pred} <- Args0,
+ is_successor(L, Pred, S)],
+ [I#b_set{args=Args}|fix_phis_1(Is, L, S)];
+fix_phis_1(Is, _, _) -> Is.
+
+is_successor(L, Pred, S) ->
+ case S of
+ #{Pred:=Successors} ->
+ member(L, Successors);
+ #{} ->
+ %% This block has been removed.
+ false
+ end.
+
+rpo_1([L|Ls], Blocks, Seen0, Acc0) ->
+ case cerl_sets:is_element(L, Seen0) of
+ true ->
+ rpo_1(Ls, Blocks, Seen0, Acc0);
+ false ->
+ Block = map_get(L, Blocks),
+ Seen1 = cerl_sets:add_element(L, Seen0),
+ Successors = successors(Block),
+ {Acc,Seen} = rpo_1(Successors, Blocks, Seen1, Acc0),
+ rpo_1(Ls, Blocks, Seen, [L|Acc])
+ end;
+rpo_1([], _, Seen, Acc) ->
+ {Acc,Seen}.
+
+rename_var(#b_var{}=Old, Rename) ->
+ case Rename of
+ #{Old:=New} -> New;
+ #{} -> Old
+ end;
+rename_var(#b_remote{mod=Mod0,name=Name0}=Remote, Rename) ->
+ Mod = rename_var(Mod0, Rename),
+ Name = rename_var(Name0, Rename),
+ Remote#b_remote{mod=Mod,name=Name};
+rename_var(Old, _) -> Old.
+
+rename_phi_vars([{Var,L}|As], Preds, Ren) ->
+ case cerl_sets:is_element(L, Preds) of
+ true ->
+ [{rename_var(Var, Ren),L}|rename_phi_vars(As, Preds, Ren)];
+ false ->
+ [{Var,L}|rename_phi_vars(As, Preds, Ren)]
+ end;
+rename_phi_vars([], _, _) -> [].
+
+map_instrs_1([L|Ls], Fun, Blocks0) ->
+ #b_blk{is=Is0,last=Last0} = Blk0 = map_get(L, Blocks0),
+ Is = [Fun(I) || I <- Is0],
+ Last = Fun(Last0),
+ Blk = Blk0#b_blk{is=Is,last=Last},
+ Blocks = Blocks0#{L:=Blk},
+ map_instrs_1(Ls, Fun, Blocks);
+map_instrs_1([], _, Blocks) -> Blocks.
+
+flatmapfoldl(F, Accu0, [Hd|Tail]) ->
+ {R,Accu1} = F(Hd, Accu0),
+ {Rs,Accu2} = flatmapfoldl(F, Accu1, Tail),
+ {R++Rs,Accu2};
+flatmapfoldl(_, Accu, []) -> {[],Accu}.
+
+split_blocks_1([L|Ls], P, Blocks0, Count0) ->
+ #b_blk{is=Is0} = Blk = map_get(L, Blocks0),
+ case split_blocks_is(Is0, P, []) of
+ {yes,Bef,Aft} ->
+ NewLbl = Count0,
+ Count = Count0 + 1,
+ Br = #b_br{bool=#b_literal{val=true},succ=NewLbl,fail=NewLbl},
+ BefBlk = Blk#b_blk{is=Bef,last=Br},
+ NewBlk = Blk#b_blk{is=Aft},
+ Blocks1 = Blocks0#{L:=BefBlk,NewLbl=>NewBlk},
+ Successors = successors(NewBlk),
+ Blocks = update_phi_labels(Successors, L, NewLbl, Blocks1),
+ split_blocks_1([NewLbl|Ls], P, Blocks, Count);
+ no ->
+ split_blocks_1(Ls, P, Blocks0, Count0)
+ end;
+split_blocks_1([], _, Blocks, Count) ->
+ {Blocks,Count}.
+
+split_blocks_is([I|Is], P, []) ->
+ split_blocks_is(Is, P, [I]);
+split_blocks_is([I|Is], P, Acc) ->
+ case P(I) of
+ true ->
+ {yes,reverse(Acc),[I|Is]};
+ false ->
+ split_blocks_is(Is, P, [I|Acc])
+ end;
+split_blocks_is([], _, _) -> no.
+
+update_phi_labels_is([#b_set{op=phi,args=Args0}=I0|Is], Old, New) ->
+ Args = [{Arg,rename_label(Lbl, Old, New)} || {Arg,Lbl} <- Args0],
+ I = I0#b_set{args=Args},
+ [I|update_phi_labels_is(Is, Old, New)];
+update_phi_labels_is(Is, _, _) -> Is.
+
+rename_label(Old, Old, New) -> New;
+rename_label(Lbl, _Old, _New) -> Lbl.
+
+used_args([#b_var{}=V|As]) ->
+ [V|used_args(As)];
+used_args([#b_remote{mod=Mod,name=Name}|As]) ->
+ used_args([Mod,Name|As]);
+used_args([_|As]) ->
+ used_args(As);
+used_args([]) -> [].
+
+used_1([H|T], Used0) ->
+ Used = ordsets:union(used(H), Used0),
+ used_1(T, Used);
+used_1([], Used) -> Used.
diff --git a/lib/compiler/src/beam_ssa.hrl b/lib/compiler/src/beam_ssa.hrl
new file mode 100644
index 0000000000..fa76b08453
--- /dev/null
+++ b/lib/compiler/src/beam_ssa.hrl
@@ -0,0 +1,66 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-record(b_module, {anno=#{} :: beam_ssa:anno(),
+ name :: module(),
+ exports :: [{atom(),arity()}],
+ attributes :: list(),
+ body :: [beam_ssa:b_function()]}).
+-record(b_function, {anno=#{} :: beam_ssa:anno(),
+ args :: [beam_ssa:b_var()],
+ bs :: #{beam_ssa:label():=beam_ssa:b_blk()},
+ cnt :: beam_ssa:label()}).
+
+-record(b_blk, {anno=#{} :: beam_ssa:anno(),
+ is :: [beam_ssa:b_set()],
+ last :: beam_ssa:terminator()}).
+-record(b_set, {anno=#{} :: beam_ssa:anno(),
+ dst=none :: 'none'|beam_ssa:b_var(),
+ op :: beam_ssa:op(),
+ args=[] :: [beam_ssa:argument()]}).
+
+%% Terminators.
+-record(b_ret, {anno=#{} :: beam_ssa:anno(),
+ arg :: beam_ssa:value()}).
+
+-record(b_br, {anno=#{},
+ bool :: beam_ssa:value(),
+ succ :: beam_ssa:label(),
+ fail :: beam_ssa:label()}).
+
+-record(b_switch, {anno=#{} :: beam_ssa:anno(),
+ arg :: beam_ssa:value(),
+ fail :: beam_ssa:label(),
+ list :: [{beam_ssa:b_literal(),beam_ssa:label()}]}).
+
+%% Values.
+-record(b_var, {name :: beam_ssa:var_name()}).
+
+-record(b_literal, {val :: beam_ssa:literal_value()}).
+
+-record(b_remote, {mod :: beam_ssa:value(),
+ name :: beam_ssa:value(),
+ arity :: non_neg_integer()}).
+
+-record(b_local, {name :: beam_ssa:b_literal(),
+ arity :: non_neg_integer()}).
+
+%% If this block exists, it calls erlang:error(badarg).
+-define(BADARG_BLOCK, 1).
diff --git a/lib/compiler/src/beam_ssa_bsm.erl b/lib/compiler/src/beam_ssa_bsm.erl
new file mode 100644
index 0000000000..382e6f635e
--- /dev/null
+++ b/lib/compiler/src/beam_ssa_bsm.erl
@@ -0,0 +1,1046 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%%
+%%% This pass optimizes bit syntax matching, and is centered around the concept
+%%% of "match context reuse" which is best explained through example. To put it
+%%% shortly we attempt to turn this:
+%%%
+%%% <<0,B/bits>> = A,
+%%% <<1,C/bits>> = B,
+%%% <<D,_/bits>> = C,
+%%% D.
+%%%
+%%% ... Into this:
+%%%
+%%% <<0,1,D,_/bits>>=A,
+%%% D.
+%%%
+%%% Which is much faster as it avoids the creation of intermediate terms. This
+%%% is especially noticeable in loops where such garbage is generated on each
+%%% iteration.
+%%%
+%%% The optimization itself is very simple and can be applied whenever there's
+%%% matching on the tail end of a binary; instead of creating a new binary and
+%%% starting a new match context on it, we reuse the match context used to
+%%% extract the tail and avoid the creation of both objects.
+%%%
+%%% The catch is that a match context isn't a proper type and nothing outside
+%%% of bit syntax match operations can handle them. We therefore need to make
+%%% sure that they never "leak" into other instructions, and most of the pass
+%%% revolves around getting around that limitation.
+%%%
+%%% Unlike most other passes we look at the whole module so we can combine
+%%% matches across function boundaries, greatly increasing the performance of
+%%% complex matches and loops.
+%%%
+
+-module(beam_ssa_bsm).
+
+-export([module/2, format_error/1]).
+
+-include("beam_ssa.hrl").
+
+-import(lists, [member/2, reverse/1, splitwith/2, map/2, foldl/3, mapfoldl/3,
+ nth/2, max/1, unzip/1]).
+
+-spec format_error(term()) -> nonempty_string().
+
+format_error(OptInfo) ->
+ format_opt_info(OptInfo).
+
+-spec module(Module, Options) -> Result when
+ Module :: beam_ssa:b_module(),
+ Options :: [compile:option()],
+ Result :: {ok, beam_ssa:b_module(), list()}.
+
+-define(PASS(N), {N,fun N/1}).
+
+module(#b_module{body=Fs0}=Module, Opts) ->
+ ModInfo = analyze_module(Module),
+
+ %% combine_matches is repeated after accept_context_args as the control
+ %% flow changes can enable further optimizations, as in the example below:
+ %%
+ %% a(<<0,X/binary>>) -> a(X);
+ %% a(A) when bit_size(A) =:= 52 -> bar;
+ %% a(<<1,X/binary>>) -> X. %% Match context will be reused here when
+ %% %% when repeated.
+
+ {Fs, _} = compile:run_sub_passes(
+ [?PASS(combine_matches),
+ ?PASS(accept_context_args),
+ ?PASS(combine_matches),
+ ?PASS(allow_context_passthrough),
+ ?PASS(skip_outgoing_tail_extraction),
+ ?PASS(annotate_context_parameters)],
+ {Fs0, ModInfo}),
+
+ Ws = case proplists:get_bool(bin_opt_info, Opts) of
+ true -> collect_opt_info(Fs);
+ false -> []
+ end,
+
+ {ok, Module#b_module{body=Fs}, Ws}.
+
+-type module_info() :: #{ func_id() => func_info() }.
+
+-type func_id() :: {Name :: atom(), Arity :: non_neg_integer()}.
+
+-type func_info() :: #{ has_bsm_ops => boolean(),
+ parameters => [#b_var{}],
+ parameter_info => #{ #b_var{} => param_info() } }.
+
+-type param_info() :: suitable_for_reuse |
+ {Problem :: atom(), Where :: term()}.
+
+-spec analyze_module(#b_module{}) -> module_info().
+
+analyze_module(#b_module{body=Fs}) ->
+ foldl(fun(#b_function{args=Parameters}=F, I) ->
+ FuncInfo = #{ has_bsm_ops => has_bsm_ops(F),
+ parameters => Parameters,
+ parameter_info => #{} },
+ FuncId = get_fa(F),
+ I#{ FuncId => FuncInfo }
+ end, #{}, Fs).
+
+has_bsm_ops(#b_function{bs=Blocks}) ->
+ hbo_blocks(maps:to_list(Blocks)).
+
+hbo_blocks([{_,#b_blk{is=Is}} | Blocks]) ->
+ case hbo_is(Is) of
+ false -> hbo_blocks(Blocks);
+ true -> true
+ end;
+hbo_blocks([]) ->
+ false.
+
+hbo_is([#b_set{op=bs_start_match} | _]) -> true;
+hbo_is([_I | Is]) -> hbo_is(Is);
+hbo_is([]) -> false.
+
+%% Checks whether it's legal to make a call with the given argument as a match
+%% context, returning the param_info() of the relevant parameter.
+-spec check_context_call(#b_set{}, Arg, CtxChain, ModInfo) -> param_info() when
+ Arg :: #b_var{},
+ CtxChain :: [#b_var{}],
+ ModInfo :: module_info().
+check_context_call(#b_set{args=Args}, Arg, CtxChain, ModInfo) ->
+ Aliases = [Arg | CtxChain],
+ ccc_1(Args, Arg, Aliases, ModInfo).
+
+ccc_1([#b_local{}=Call | Args], Ctx, Aliases, ModInfo) ->
+ %% Matching operations assume that their context isn't aliased (as in
+ %% pointer aliasing), so we must reject calls whose arguments contain more
+ %% than one reference to the context.
+ %%
+ %% TODO: Try to fall back to passing binaries in these cases. Partial reuse
+ %% is better than nothing.
+ UseCount = foldl(fun(Arg, C) ->
+ case member(Arg, Aliases) of
+ true -> C + 1;
+ false -> C
+ end
+ end, 0, Args),
+ if
+ UseCount =:= 1 ->
+ #b_local{name=#b_literal{val=Name},arity=Arity} = Call,
+ Callee = {Name, Arity},
+
+ ParamInfo = funcinfo_get(Callee, parameter_info, ModInfo),
+ Parameters = funcinfo_get(Callee, parameters, ModInfo),
+ Parameter = nth(1 + arg_index(Ctx, Args), Parameters),
+
+ case maps:find(Parameter, ParamInfo) of
+ {ok, suitable_for_reuse} ->
+ suitable_for_reuse;
+ {ok, Other} ->
+ {unsuitable_call, {Call, Other}};
+ error ->
+ {no_match_on_entry, Call}
+ end;
+ UseCount > 1 ->
+ {multiple_uses_in_call, Call}
+ end;
+ccc_1([#b_remote{}=Call | _Args], _Ctx, _CtxChain, _ModInfo) ->
+ {remote_call, Call};
+ccc_1([Fun | _Args], _Ctx, _CtxChain, _ModInfo) ->
+ %% TODO: It may be possible to support this in the future for locally
+ %% defined funs, including ones with free variables.
+ {fun_call, Fun}.
+
+%% Returns the index of Var in Args.
+arg_index(Var, Args) -> arg_index_1(Var, Args, 0).
+
+arg_index_1(Var, [Var | _Args], Index) -> Index;
+arg_index_1(Var, [_Arg | Args], Index) -> arg_index_1(Var, Args, Index + 1).
+
+is_tail_binary(#b_set{op=bs_match,args=[#b_literal{val=binary} | Rest]}) ->
+ member(#b_literal{val=all}, Rest);
+is_tail_binary(#b_set{op=bs_get_tail}) ->
+ true;
+is_tail_binary(_) ->
+ false.
+
+is_tail_binary(#b_var{}=Var, Defs) ->
+ case find_match_definition(Var, Defs) of
+ {ok, Def} -> is_tail_binary(Def);
+ _ -> false
+ end;
+is_tail_binary(_Literal, _Defs) ->
+ false.
+
+assert_match_context(#b_var{}=Var, Defs) ->
+ case maps:find(Var, Defs) of
+ {ok, #b_set{op=bs_match,args=[_,#b_var{}=Ctx|_]}} ->
+ assert_match_context(Ctx, Defs);
+ {ok, #b_set{op=bs_start_match}} ->
+ ok
+ end.
+
+find_match_definition(#b_var{}=Var, Defs) ->
+ case maps:find(Var, Defs) of
+ {ok, #b_set{op=bs_extract,args=[Ctx]}} -> maps:find(Ctx, Defs);
+ {ok, #b_set{op=bs_get_tail}=Def} -> {ok, Def};
+ _ -> error
+ end.
+
+%% Returns a list of all contexts that were used to extract Var.
+context_chain_of(#b_var{}=Var, Defs) ->
+ case maps:find(Var, Defs) of
+ {ok, #b_set{op=bs_match,args=[_,#b_var{}=Ctx|_]}} ->
+ [Ctx | context_chain_of(Ctx, Defs)];
+ {ok, #b_set{op=bs_get_tail,args=[Ctx]}} ->
+ [Ctx | context_chain_of(Ctx, Defs)];
+ {ok, #b_set{op=bs_extract,args=[Ctx]}} ->
+ [Ctx | context_chain_of(Ctx, Defs)];
+ _ ->
+ []
+ end.
+
+%% Grabs the match context used to produce the given variable.
+match_context_of(#b_var{}=Var, Defs) ->
+ Ctx = match_context_of_1(Var, Defs),
+ assert_match_context(Ctx, Defs),
+ Ctx.
+
+match_context_of_1(Var, Defs) ->
+ case maps:get(Var, Defs) of
+ #b_set{op=bs_extract,args=[#b_var{}=Ctx0]} ->
+ #b_set{op=bs_match,
+ args=[_,#b_var{}=Ctx|_]} = maps:get(Ctx0, Defs),
+ Ctx;
+ #b_set{op=bs_get_tail,args=[#b_var{}=Ctx]} ->
+ Ctx
+ end.
+
+funcinfo_get(#b_function{}=F, Attribute, ModInfo) ->
+ funcinfo_get(get_fa(F), Attribute, ModInfo);
+funcinfo_get({_,_}=Key, Attribute, ModInfo) ->
+ FuncInfo = maps:get(Key, ModInfo),
+ maps:get(Attribute, FuncInfo).
+
+funcinfo_set(#b_function{}=F, Attribute, Value, ModInfo) ->
+ funcinfo_set(get_fa(F), Attribute, Value, ModInfo);
+funcinfo_set(Key, Attribute, Value, ModInfo) ->
+ FuncInfo = maps:put(Attribute, Value, maps:get(Key, ModInfo, #{})),
+ maps:put(Key, FuncInfo, ModInfo).
+
+get_fa(#b_function{ anno = Anno }) ->
+ {_,Name,Arity} = maps:get(func_info, Anno),
+ {Name,Arity}.
+
+%% Replaces matched-out binaries with aliases that are lazily converted to
+%% binary form when used, allowing us to keep the "match path" free of binary
+%% creation.
+
+-spec alias_matched_binaries(Blocks, Counter, AliasMap) -> Result when
+ Blocks :: beam_ssa:block_map(),
+ Counter :: non_neg_integer(),
+ AliasMap :: match_alias_map(),
+ Result :: {Blocks, Counter}.
+
+-type match_alias_map() ::
+ #{ Binary :: #b_var{} =>
+ { %% Replace all uses of Binary with an alias after this
+ %% label.
+ AliasAfter :: beam_ssa:label(),
+ %% The match context whose tail is equal to Binary.
+ Context :: #b_var{} } }.
+
+%% Keeps track of the promotions we need to insert. They're partially keyed by
+%% location because they may not be valid on all execution paths and we may
+%% need to add redundant promotions in some cases.
+-type promotion_map() ::
+ #{ { PromoteAt :: beam_ssa:label(),
+ Variable :: #b_var{} } =>
+ Instruction :: #b_set{} }.
+
+-record(amb, { dominators :: beam_ssa:dominator_map(),
+ match_aliases :: match_alias_map(),
+ cnt :: non_neg_integer(),
+ promotions = #{} :: promotion_map() }).
+
+alias_matched_binaries(Blocks0, Counter, AliasMap) when AliasMap =/= #{} ->
+ {Dominators, _} = beam_ssa:dominators(Blocks0),
+ State0 = #amb{ dominators = Dominators,
+ match_aliases = AliasMap,
+ cnt = Counter },
+ {Blocks, State} = beam_ssa:mapfold_blocks_rpo(fun amb_1/3, [0], State0,
+ Blocks0),
+ {amb_insert_promotions(Blocks, State), State#amb.cnt};
+alias_matched_binaries(Blocks, Counter, _AliasMap) ->
+ {Blocks, Counter}.
+
+amb_1(Lbl, #b_blk{is=Is0,last=Last0}=Block, State0) ->
+ {Is, State1} = mapfoldl(fun(I, State) ->
+ amb_assign_set(I, Lbl, State)
+ end, State0, Is0),
+ {Last, State} = amb_assign_last(Last0, Lbl, State1),
+ {Block#b_blk{is=Is,last=Last}, State}.
+
+amb_assign_set(#b_set{op=phi,args=Args0}=I, _Lbl, State0) ->
+ %% Phi node aliases are relative to their source block, not their
+ %% containing block.
+ {Args, State} =
+ mapfoldl(fun({Arg0, Lbl}, Acc) ->
+ {Arg, State} = amb_get_alias(Arg0, Lbl, Acc),
+ {{Arg, Lbl}, State}
+ end, State0, Args0),
+ {I#b_set{args=Args}, State};
+amb_assign_set(#b_set{args=Args0}=I, Lbl, State0) ->
+ {Args, State} = mapfoldl(fun(Arg0, Acc) ->
+ amb_get_alias(Arg0, Lbl, Acc)
+ end, State0, Args0),
+ {I#b_set{args=Args}, State}.
+
+amb_assign_last(#b_ret{arg=Arg0}=T, Lbl, State0) ->
+ {Arg, State} = amb_get_alias(Arg0, Lbl, State0),
+ {T#b_ret{arg=Arg}, State};
+amb_assign_last(#b_switch{arg=Arg0}=T, Lbl, State0) ->
+ {Arg, State} = amb_get_alias(Arg0, Lbl, State0),
+ {T#b_switch{arg=Arg}, State};
+amb_assign_last(#b_br{bool=Arg0}=T, Lbl, State0) ->
+ {Arg, State} = amb_get_alias(Arg0, Lbl, State0),
+ {T#b_br{bool=Arg}, State}.
+
+amb_get_alias(#b_var{}=Arg, Lbl, State) ->
+ case maps:find(Arg, State#amb.match_aliases) of
+ {ok, {AliasAfter, Context}} ->
+ %% Our context may not have been created yet, so we skip assigning
+ %% an alias unless the given block is among our dominators.
+ Dominators = maps:get(Lbl, State#amb.dominators),
+ case member(AliasAfter, Dominators) of
+ true -> amb_create_alias(Arg, Context, Lbl, State);
+ false -> {Arg, State}
+ end;
+ error ->
+ {Arg, State}
+ end;
+amb_get_alias(#b_remote{mod=Mod0,name=Name0}=Arg0, Lbl, State0) ->
+ {Mod, State1} = amb_get_alias(Mod0, Lbl, State0),
+ {Name, State} = amb_get_alias(Name0, Lbl, State1),
+ Arg = Arg0#b_remote{mod=Mod,name=Name},
+ {Arg, State};
+amb_get_alias(Arg, _Lbl, State) ->
+ {Arg, State}.
+
+amb_create_alias(#b_var{}=Arg0, Context, Lbl, State0) ->
+ Dominators = maps:get(Lbl, State0#amb.dominators),
+ Promotions0 = State0#amb.promotions,
+
+ PrevPromotions =
+ [maps:get({Dom, Arg0}, Promotions0)
+ || Dom <- Dominators, is_map_key({Dom, Arg0}, Promotions0)],
+
+ case PrevPromotions of
+ [_|_] ->
+ %% We've already created an alias prior to this block, so we'll
+ %% grab the most recent one to minimize stack use.
+
+ #b_set{dst=Alias} = max(PrevPromotions),
+ {Alias, State0};
+ [] ->
+ %% If we haven't created an alias we need to do so now. The
+ %% promotion will be inserted later by amb_insert_promotions/2.
+
+ Counter = State0#amb.cnt,
+ Alias = #b_var{name={'@ssa_bsm_alias', Counter}},
+ Promotion = #b_set{op=bs_get_tail,dst=Alias,args=[Context]},
+
+ Promotions = maps:put({Lbl, Arg0}, Promotion, Promotions0),
+ State = State0#amb{ promotions=Promotions, cnt=Counter+1 },
+
+ {Alias, State}
+ end.
+
+amb_insert_promotions(Blocks0, State) ->
+ F = fun({Lbl, #b_var{}}, Promotion, Blocks) ->
+ Block = maps:get(Lbl, Blocks),
+
+ Alias = Promotion#b_set.dst,
+ {Before, After} = splitwith(
+ fun(#b_set{args=Args}) ->
+ not is_var_in_args(Alias, Args)
+ end, Block#b_blk.is),
+ Is = Before ++ [Promotion | After],
+
+ maps:put(Lbl, Block#b_blk{is=Is}, Blocks)
+ end,
+ maps:fold(F, Blocks0, State#amb.promotions).
+
+is_var_in_args(Var, [Var | _]) -> true;
+is_var_in_args(Var, [#b_remote{name=Var} | _]) -> true;
+is_var_in_args(Var, [#b_remote{mod=Var} | _]) -> true;
+is_var_in_args(Var, [_ | Args]) -> is_var_in_args(Var, Args);
+is_var_in_args(_Var, []) -> false.
+
+%%%
+%%% Subpasses
+%%%
+
+%% Removes superflous chained bs_start_match instructions in the same
+%% function. When matching on an extracted tail binary, or on a binary we've
+%% already matched on, we reuse the original match context.
+%%
+%% This pass runs first since it makes subsequent optimizations more effective
+%% by removing spots where promotion would be required.
+
+-type prior_match_map() ::
+ #{ Binary :: #b_var{} =>
+ [{ %% The context and success label of a previous
+ %% bs_start_match made on this binary.
+ ValidAfter :: beam_ssa:label(),
+ Context :: #b_var{} }] }.
+
+-record(cm, { definitions :: beam_ssa:definition_map(),
+ dominators :: beam_ssa:dominator_map(),
+ blocks :: beam_ssa:block_map(),
+ match_aliases = #{} :: match_alias_map(),
+ prior_matches = #{} :: prior_match_map(),
+ renames = #{} :: beam_ssa:rename_map() }).
+
+combine_matches({Fs0, ModInfo}) ->
+ Fs = map(fun(F) -> combine_matches(F, ModInfo) end, Fs0),
+ {Fs, ModInfo}.
+
+combine_matches(#b_function{bs=Blocks0,cnt=Counter0}=F, ModInfo) ->
+ case funcinfo_get(F, has_bsm_ops, ModInfo) of
+ true ->
+ {Dominators, _} = beam_ssa:dominators(Blocks0),
+ {Blocks1, State} =
+ beam_ssa:mapfold_blocks_rpo(
+ fun(Lbl, #b_blk{is=Is0}=Block0, State0) ->
+ {Is, State} = cm_1(Is0, [], Lbl, State0),
+ {Block0#b_blk{is=Is}, State}
+ end, [0],
+ #cm{ definitions = beam_ssa:definitions(Blocks0),
+ dominators = Dominators,
+ blocks = Blocks0 },
+ Blocks0),
+
+ Blocks2 = beam_ssa:rename_vars(State#cm.renames, [0], Blocks1),
+
+ {Blocks, Counter} = alias_matched_binaries(Blocks2, Counter0,
+ State#cm.match_aliases),
+
+ F#b_function{ bs=Blocks, cnt=Counter };
+ false ->
+ F
+ end.
+
+cm_1([#b_set{ op=bs_start_match,
+ dst=Ctx,
+ args=[Src] },
+ #b_set{ op=succeeded,
+ dst=Bool,
+ args=[Ctx] }]=MatchSeq, Acc0, Lbl, State0) ->
+ Acc = reverse(Acc0),
+ case is_tail_binary(Src, State0#cm.definitions) of
+ true -> cm_combine_tail(Src, Ctx, Bool, Acc, State0);
+ false -> cm_handle_priors(Src, Ctx, Bool, Acc, MatchSeq, Lbl, State0)
+ end;
+cm_1([I | Is], Acc, Lbl, State) ->
+ cm_1(Is, [I | Acc], Lbl, State);
+cm_1([], Acc, _Lbl, State) ->
+ {reverse(Acc), State}.
+
+%% If we're dominated by at least one match on the same source, we can reuse
+%% the context created by that match.
+cm_handle_priors(Src, DstCtx, Bool, Acc, MatchSeq, Lbl, State0) ->
+ PriorCtxs = case maps:find(Src, State0#cm.prior_matches) of
+ {ok, Priors} ->
+ %% We've seen other match contexts on this source, but
+ %% we can only consider the ones whose success path
+ %% dominate us.
+ Dominators = maps:get(Lbl, State0#cm.dominators, []),
+ [Ctx || {ValidAfter, Ctx} <- Priors,
+ member(ValidAfter, Dominators)];
+ error ->
+ []
+ end,
+ case PriorCtxs of
+ [Ctx|_] ->
+ Renames0 = State0#cm.renames,
+ Renames = Renames0#{ Bool => #b_literal{val=true}, DstCtx => Ctx },
+ {Acc, State0#cm{ renames = Renames }};
+ [] ->
+ %% Since we lack a prior match, we need to register this one in
+ %% case we dominate another.
+ State = cm_register_prior(Src, DstCtx, Lbl, State0),
+ {Acc ++ MatchSeq, State}
+ end.
+
+cm_register_prior(Src, DstCtx, Lbl, State) ->
+ Block = maps:get(Lbl, State#cm.blocks),
+ #b_br{succ=ValidAfter} = Block#b_blk.last,
+
+ Priors0 = maps:get(Src, State#cm.prior_matches, []),
+ Priors = [{ValidAfter, DstCtx} | Priors0],
+
+ PriorMatches = maps:put(Src, Priors, State#cm.prior_matches),
+ State#cm{ prior_matches = PriorMatches }.
+
+cm_combine_tail(Src, DstCtx, Bool, Acc, State0) ->
+ SrcCtx = match_context_of(Src, State0#cm.definitions),
+
+ %% We replace the source with a context alias as it normally won't be used
+ %% on the happy path after being matched, and the added cost of conversion
+ %% is negligible if it is.
+ Aliases = maps:put(Src, {0, SrcCtx}, State0#cm.match_aliases),
+
+ Renames0 = State0#cm.renames,
+ Renames = Renames0#{ Bool => #b_literal{val=true}, DstCtx => SrcCtx },
+
+ State = State0#cm{ match_aliases = Aliases, renames = Renames },
+
+ {Acc, State}.
+
+%% Lets functions accept match contexts as arguments. The parameter must be
+%% unused before the bs_start_match instruction, and it must be matched in the
+%% first block.
+
+-record(aca, { unused_parameters :: ordsets:ordset(#b_var{}),
+ counter :: non_neg_integer(),
+ parameter_info = #{} :: #{ #b_var{} => param_info() },
+ match_aliases = #{} :: match_alias_map() }).
+
+accept_context_args({Fs, ModInfo}) ->
+ mapfoldl(fun accept_context_args/2, ModInfo, Fs).
+
+accept_context_args(#b_function{bs=Blocks0}=F, ModInfo0) ->
+ case funcinfo_get(F, has_bsm_ops, ModInfo0) of
+ true ->
+ Parameters = ordsets:from_list(funcinfo_get(F, parameters, ModInfo0)),
+ State0 = #aca{ unused_parameters = Parameters,
+ counter = F#b_function.cnt },
+
+ {Blocks1, State} = aca_1(Blocks0, State0),
+ {Blocks, Counter} = alias_matched_binaries(Blocks1,
+ State#aca.counter,
+ State#aca.match_aliases),
+
+ ModInfo = funcinfo_set(F, parameter_info, State#aca.parameter_info,
+ ModInfo0),
+
+ {F#b_function{bs=Blocks,cnt=Counter}, ModInfo};
+ false ->
+ {F, ModInfo0}
+ end.
+
+aca_1(Blocks, State) ->
+ %% We only handle block 0 as we don't yet support starting a match after a
+ %% test. This is generally good enough as the sys_core_bsm pass makes the
+ %% match instruction come first if possible, and it's rare for a function
+ %% to binary-match several parameters at once.
+ EntryBlock = maps:get(0, Blocks),
+ aca_enable_reuse(EntryBlock#b_blk.is, EntryBlock, Blocks, [], State).
+
+aca_enable_reuse([#b_set{op=bs_start_match,args=[Src]}=I0 | Rest],
+ EntryBlock, Blocks0, Acc, State0) ->
+ case aca_is_reuse_safe(Src, State0) of
+ true ->
+ {I, Last, Blocks1, State} =
+ aca_reuse_context(I0, EntryBlock, Blocks0, State0),
+
+ Is = reverse([I|Acc]) ++ Rest,
+ Blocks = maps:put(0, EntryBlock#b_blk{is=Is,last=Last}, Blocks1),
+
+ {Blocks, State};
+ false ->
+ {Blocks0, State0}
+ end;
+aca_enable_reuse([I | Is], EntryBlock, Blocks, Acc, State0) ->
+ UnusedParams0 = State0#aca.unused_parameters,
+ case ordsets:intersection(UnusedParams0, beam_ssa:used(I)) of
+ [] ->
+ aca_enable_reuse(Is, EntryBlock, Blocks, [I | Acc], State0);
+ PrematureUses ->
+ UnusedParams = ordsets:subtract(UnusedParams0, PrematureUses),
+
+ %% Mark the offending parameters as unsuitable for context reuse.
+ ParamInfo = foldl(fun(A, Ps) ->
+ maps:put(A, {used_before_match, I}, Ps)
+ end, State0#aca.parameter_info, PrematureUses),
+
+ State = State0#aca{ unused_parameters = UnusedParams,
+ parameter_info = ParamInfo },
+ aca_enable_reuse(Is, EntryBlock, Blocks, [I | Acc], State)
+ end;
+aca_enable_reuse([], _EntryBlock, Blocks, _Acc, State) ->
+ {Blocks, State}.
+
+aca_is_reuse_safe(Src, State) ->
+ %% Context reuse is unsafe unless all uses are dominated by the start_match
+ %% instruction. Since we only process block 0 it's enough to check if
+ %% they're unused so far.
+ ordsets:is_element(Src, State#aca.unused_parameters).
+
+aca_reuse_context(#b_set{dst=Dst, args=[Src]}=I0, Block, Blocks0, State0) ->
+ %% When matching fails on a reused context it needs to be converted back
+ %% to a binary. We only need to do this on the success path since it can't
+ %% be a context on the type failure path, but it's very common for these
+ %% to converge which requires special handling.
+ {State1, Last, Blocks} =
+ aca_handle_convergence(Src, State0, Block#b_blk.last, Blocks0),
+
+ Aliases = maps:put(Src, {Last#b_br.succ, Dst}, State1#aca.match_aliases),
+ ParamInfo = maps:put(Src, suitable_for_reuse, State1#aca.parameter_info),
+
+ State = State1#aca{ match_aliases = Aliases,
+ parameter_info = ParamInfo },
+
+ I = beam_ssa:add_anno(accepts_match_contexts, true, I0),
+
+ {I, Last, Blocks, State}.
+
+aca_handle_convergence(Src, State0, Last0, Blocks0) ->
+ #b_br{fail=Fail0,succ=Succ0} = Last0,
+
+ SuccPath = beam_ssa:rpo([Succ0], Blocks0),
+ FailPath = beam_ssa:rpo([Fail0], Blocks0),
+
+ %% The promotion logic in alias_matched_binaries breaks down if the source
+ %% is used after the fail/success paths converge, as we have no way to tell
+ %% whether the source is a match context or something else past that point.
+ %%
+ %% We could handle this through clever insertion of phi nodes but it's
+ %% far simpler to copy either branch in its entirety. It doesn't matter
+ %% which one as long as they become disjoint.
+ ConvergedPaths = ordsets:intersection(
+ ordsets:from_list(SuccPath),
+ ordsets:from_list(FailPath)),
+
+ case maps:is_key(Src, beam_ssa:uses(ConvergedPaths, Blocks0)) of
+ true ->
+ case shortest(SuccPath, FailPath) of
+ left ->
+ {Succ, Blocks, Counter} =
+ aca_copy_successors(Succ0, Blocks0, State0#aca.counter),
+ State = State0#aca{ counter = Counter },
+ {State, Last0#b_br{succ=Succ}, Blocks};
+ right ->
+ {Fail, Blocks, Counter} =
+ aca_copy_successors(Fail0, Blocks0, State0#aca.counter),
+ State = State0#aca{ counter = Counter },
+ {State, Last0#b_br{fail=Fail}, Blocks}
+ end;
+ false ->
+ {State0, Last0, Blocks0}
+ end.
+
+shortest([_|As], [_|Bs]) -> shortest(As, Bs);
+shortest([], _) -> left;
+shortest(_, []) -> right.
+
+%% Copies all successor blocks of Lbl, returning the label to the entry block
+%% of this copy. Since the copied blocks aren't referenced anywhere else, they
+%% are all guaranteed to be dominated by Lbl.
+aca_copy_successors(Lbl0, Blocks0, Counter0) ->
+ %% Building the block rename map up front greatly simplifies phi node
+ %% handling.
+ Path = beam_ssa:rpo([Lbl0], Blocks0),
+ {BRs, Counter1} = aca_cs_build_brs(Path, Counter0, #{}),
+ {Blocks, Counter} = aca_cs_1(Path, Blocks0, Counter1, #{}, BRs, #{}),
+ Lbl = maps:get(Lbl0, BRs),
+ {Lbl, Blocks, Counter}.
+
+aca_cs_build_brs([Lbl | Path], Counter0, Acc) ->
+ aca_cs_build_brs(Path, Counter0 + 1, maps:put(Lbl, Counter0, Acc));
+aca_cs_build_brs([], Counter, Acc) ->
+ {Acc, Counter}.
+
+aca_cs_1([Lbl0 | Path], Blocks, Counter0, VRs0, BRs, Acc0) ->
+ Block0 = maps:get(Lbl0, Blocks),
+ Lbl = maps:get(Lbl0, BRs),
+ {VRs, Block, Counter} = aca_cs_block(Block0, Counter0, VRs0, BRs),
+ Acc = maps:put(Lbl, Block, Acc0),
+ aca_cs_1(Path, Blocks, Counter, VRs, BRs, Acc);
+aca_cs_1([], Blocks, Counter, _VRs, _BRs, Acc) ->
+ {maps:merge(Blocks, Acc), Counter}.
+
+aca_cs_block(#b_blk{is=Is0,last=Last0}=Block0, Counter0, VRs0, BRs) ->
+ {VRs, Is, Counter} = aca_cs_is(Is0, Counter0, VRs0, BRs, []),
+ Last = aca_cs_last(Last0, VRs, BRs),
+ Block = Block0#b_blk{is=Is,last=Last},
+ {VRs, Block, Counter}.
+
+aca_cs_is([#b_set{op=Op,
+ dst=Dst0,
+ args=Args0}=I0 | Is],
+ Counter0, VRs0, BRs, Acc) ->
+ Args = case Op of
+ phi -> aca_cs_args_phi(Args0, VRs0, BRs);
+ _ -> aca_cs_args(Args0, VRs0)
+ end,
+ Counter = Counter0 + 1,
+ Dst = #b_var{name={'@ssa_bsm_aca',Counter}},
+ I = I0#b_set{dst=Dst,args=Args},
+ VRs = maps:put(Dst0, Dst, VRs0),
+ aca_cs_is(Is, Counter, VRs, BRs, [I | Acc]);
+aca_cs_is([], Counter, VRs, _BRs, Acc) ->
+ {VRs, reverse(Acc), Counter}.
+
+aca_cs_last(#b_switch{arg=Arg0,list=Switch0,fail=Fail0}=Sw, VRs, BRs) ->
+ Switch = [{Literal, maps:get(Lbl, BRs)} || {Literal, Lbl} <- Switch0],
+ Sw#b_switch{arg=aca_cs_arg(Arg0, VRs),
+ fail=maps:get(Fail0, BRs),
+ list=Switch};
+aca_cs_last(#b_br{bool=Arg0,succ=Succ0,fail=Fail0}=Br, VRs, BRs) ->
+ Br#b_br{bool=aca_cs_arg(Arg0, VRs),
+ succ=maps:get(Succ0, BRs),
+ fail=maps:get(Fail0, BRs)};
+aca_cs_last(#b_ret{arg=Arg0}=Ret, VRs, _BRs) ->
+ Ret#b_ret{arg=aca_cs_arg(Arg0, VRs)}.
+
+aca_cs_args_phi([{Arg, Lbl} | Args], VRs, BRs) ->
+ case BRs of
+ #{ Lbl := New } ->
+ [{aca_cs_arg(Arg, VRs), New} | aca_cs_args_phi(Args, VRs, BRs)];
+ #{} ->
+ aca_cs_args_phi(Args, VRs, BRs)
+ end;
+aca_cs_args_phi([], _VRs, _BRs) ->
+ [].
+
+aca_cs_args([Arg | Args], VRs) ->
+ [aca_cs_arg(Arg, VRs) | aca_cs_args(Args, VRs)];
+aca_cs_args([], _VRs) ->
+ [].
+
+aca_cs_arg(#b_remote{mod=Mod0,name=Name0}=Rem, VRs) ->
+ Mod = aca_cs_arg(Mod0, VRs),
+ Name = aca_cs_arg(Name0, VRs),
+ Rem#b_remote{mod=Mod,name=Name};
+aca_cs_arg(Arg, VRs) ->
+ case VRs of
+ #{ Arg := New } -> New;
+ #{} -> Arg
+ end.
+
+%% Allows contexts to pass through "wrapper functions" where the context is
+%% passed directly to a function that accepts match contexts (including other
+%% wrappers).
+%%
+%% This does not alter the function in any way, it only changes parameter info
+%% so that skip_outgoing_tail_extraction is aware that it's safe to pass
+%% contexts to us.
+
+allow_context_passthrough({Fs, ModInfo0}) ->
+ ModInfo =
+ acp_forward_params([{F, beam_ssa:uses(F#b_function.bs)} || F <- Fs],
+ ModInfo0),
+ {Fs, ModInfo}.
+
+acp_forward_params(FsUses, ModInfo0) ->
+ F = fun({#b_function{args=Parameters}=Func, UseMap}, ModInfo) ->
+ ParamInfo =
+ foldl(fun(Param, ParamInfo) ->
+ Uses = maps:get(Param, UseMap, []),
+ acp_1(Param, Uses, ModInfo, ParamInfo)
+ end,
+ funcinfo_get(Func, parameter_info, ModInfo),
+ Parameters),
+ funcinfo_set(Func, parameter_info, ParamInfo, ModInfo)
+ end,
+ %% Allowing context passthrough on one function may make it possible to
+ %% enable it on another, so it needs to be repeated for maximum effect.
+ case foldl(F, ModInfo0, FsUses) of
+ ModInfo0 -> ModInfo0;
+ Changed -> acp_forward_params(FsUses, Changed)
+ end.
+
+%% We have no way to know if an argument is a context, so it's only safe to
+%% forward them if they're passed exactly once in the first block. Any other
+%% uses are unsafe, including function_clause errors.
+acp_1(Param, [{0, #b_set{op=call}=I}], ModInfo, ParamInfo) ->
+ %% We don't need to provide a context chain as our callers make sure that
+ %% multiple arguments never reference the same context.
+ case check_context_call(I, Param, [], ModInfo) of
+ {no_match_on_entry, _} -> ParamInfo;
+ Other -> maps:put(Param, Other, ParamInfo)
+ end;
+acp_1(_Param, _Uses, _ModInfo, ParamInfo) ->
+ ParamInfo.
+
+%% This is conceptually similar to combine_matches but operates across
+%% functions. Whenever a tail binary is passed to a parameter that accepts
+%% match contexts we'll pass the context instead, improving performance by
+%% avoiding the creation of a new match context in the callee.
+%%
+%% We also create an alias to delay extraction until it's needed as an actual
+%% binary, which is often rare on the happy path. The cost of being wrong is
+%% negligible (`bs_test_unit + bs_get_tail` vs `bs_get_binary`) so we're
+%% applying it unconditionally to keep things simple.
+
+-record(sote, { definitions :: beam_ssa:definition_map(),
+ mod_info :: module_info(),
+ match_aliases = #{} :: match_alias_map() }).
+
+skip_outgoing_tail_extraction({Fs0, ModInfo}) ->
+ Fs = map(fun(F) -> skip_outgoing_tail_extraction(F, ModInfo) end, Fs0),
+ {Fs, ModInfo}.
+
+skip_outgoing_tail_extraction(#b_function{bs=Blocks0}=F, ModInfo) ->
+ case funcinfo_get(F, has_bsm_ops, ModInfo) of
+ true ->
+ State0 = #sote{ definitions = beam_ssa:definitions(Blocks0),
+ mod_info = ModInfo },
+
+ {Blocks1, State} = beam_ssa:mapfold_instrs_rpo(
+ fun sote_rewrite_calls/2, [0], State0, Blocks0),
+
+ {Blocks, Counter} = alias_matched_binaries(Blocks1,
+ F#b_function.cnt,
+ State#sote.match_aliases),
+
+ F#b_function{bs=Blocks,cnt=Counter};
+ false ->
+ F
+ end.
+
+sote_rewrite_calls(#b_set{op=call,args=Args}=Call, State) ->
+ sote_rewrite_call(Call, Args, [], State);
+sote_rewrite_calls(I, State) ->
+ {I, State}.
+
+sote_rewrite_call(Call, [], ArgsOut, State) ->
+ {Call#b_set{args=reverse(ArgsOut)}, State};
+sote_rewrite_call(Call0, [Arg | ArgsIn], ArgsOut, State0) ->
+ case is_tail_binary(Arg, State0#sote.definitions) of
+ true ->
+ CtxChain = context_chain_of(Arg, State0#sote.definitions),
+ case check_context_call(Call0, Arg, CtxChain, State0#sote.mod_info) of
+ suitable_for_reuse ->
+ Ctx = match_context_of(Arg, State0#sote.definitions),
+
+ MatchAliases0 = State0#sote.match_aliases,
+ MatchAliases = maps:put(Arg, {0, Ctx}, MatchAliases0),
+ State = State0#sote{ match_aliases = MatchAliases },
+
+ Call = beam_ssa:add_anno(bsm_info, context_reused, Call0),
+ sote_rewrite_call(Call, ArgsIn, [Ctx | ArgsOut], State);
+ Other ->
+ Call = beam_ssa:add_anno(bsm_info, Other, Call0),
+ sote_rewrite_call(Call, ArgsIn, [Arg | ArgsOut], State0)
+ end;
+ false ->
+ sote_rewrite_call(Call0, ArgsIn, [Arg | ArgsOut], State0)
+ end.
+
+%% Adds parameter_type_info annotations to help the validator determine whether
+%% our optimizations were safe.
+
+annotate_context_parameters({Fs, ModInfo}) ->
+ mapfoldl(fun annotate_context_parameters/2, ModInfo, Fs).
+
+annotate_context_parameters(F, ModInfo) ->
+ ParamInfo = funcinfo_get(F, parameter_info, ModInfo),
+ TypeAnno0 = beam_ssa:get_anno(parameter_type_info, F, #{}),
+ TypeAnno = maps:fold(fun(K, _V, Acc) when is_map_key(K, Acc) ->
+ %% Assertion.
+ error(conflicting_parameter_types);
+ (K, suitable_for_reuse, Acc) ->
+ T = beam_validator:type_anno(match_context),
+ Acc#{ K => T };
+ (_K, _V, Acc) ->
+ Acc
+ end, TypeAnno0, ParamInfo),
+ {beam_ssa:add_anno(parameter_type_info, TypeAnno, F), ModInfo}.
+
+%%%
+%%% +bin_opt_info
+%%%
+
+collect_opt_info(Fs) ->
+ foldl(fun(#b_function{bs=Blocks}=F, Acc0) ->
+ UseMap = beam_ssa:uses(Blocks),
+ Where = beam_ssa:get_anno(location, F, []),
+ beam_ssa:fold_instrs_rpo(
+ fun(I, Acc) ->
+ collect_opt_info_1(I, Where, UseMap, Acc)
+ end, [0], Acc0, Blocks)
+ end, [], Fs).
+
+collect_opt_info_1(#b_set{op=Op,anno=Anno,dst=Dst}=I, Where, UseMap, Acc0) ->
+ case is_tail_binary(I) of
+ true when Op =:= bs_match ->
+ %% The uses include when the context is passed raw, so we discard
+ %% everything but the bs_extract instruction to limit warnings to
+ %% unoptimized uses.
+ Uses0 = maps:get(Dst, UseMap, []),
+ case [E || {_, #b_set{op=bs_extract}=E} <- Uses0] of
+ [Use] -> add_unopt_binary_info(Use, false, Where, UseMap, Acc0);
+ [] -> Acc0
+ end;
+ true ->
+ %% Add a warning for each use. Note that we don't do anything
+ %% special if unused as a later pass will remove this instruction
+ %% anyway.
+ Uses = maps:get(Dst, UseMap, []),
+ foldl(fun({_Lbl, Use}, Acc) ->
+ add_unopt_binary_info(Use, false, Where, UseMap, Acc)
+ end, Acc0, Uses);
+ false ->
+ add_opt_info(Anno, Where, Acc0)
+ end;
+collect_opt_info_1(#b_ret{anno=Anno}, Where, _UseMap, Acc) ->
+ add_opt_info(Anno, Where, Acc);
+collect_opt_info_1(_I, _Where, _Uses, Acc) ->
+ Acc.
+
+add_opt_info(Anno, Where, Acc) ->
+ case maps:find(bsm_info, Anno) of
+ {ok, Term} -> [make_warning(Term, Anno, Where) | Acc];
+ error -> Acc
+ end.
+
+%% When an alias is promoted we need to figure out where it goes to ignore
+%% warnings for compiler-generated things, and provide more useful warnings in
+%% general.
+%%
+%% We track whether the binary has been used to build another term because it
+%% can be helpful when there's no line information.
+
+add_unopt_binary_info(#b_set{op=Follow,dst=Dst}, _Nested, Where, UseMap, Acc0)
+ when Follow =:= put_tuple;
+ Follow =:= put_list;
+ Follow =:= put_map ->
+ %% Term-building instructions.
+ {_, Uses} = unzip(maps:get(Dst, UseMap, [])),
+ foldl(fun(Use, Acc) ->
+ add_unopt_binary_info(Use, true, Where, UseMap, Acc)
+ end, Acc0, Uses);
+add_unopt_binary_info(#b_set{op=Follow,dst=Dst}, Nested, Where, UseMap, Acc0)
+ when Follow =:= bs_extract;
+ Follow =:= phi ->
+ %% Non-building instructions that need to be followed.
+ {_, Uses} = unzip(maps:get(Dst, UseMap, [])),
+ foldl(fun(Use, Acc) ->
+ add_unopt_binary_info(Use, Nested, Where, UseMap, Acc)
+ end, Acc0, Uses);
+add_unopt_binary_info(#b_set{op=call,
+ args=[#b_remote{mod=#b_literal{val=erlang},
+ name=#b_literal{val=error}} |
+ _Ignored]},
+ _Nested, _Where, _UseMap, Acc) ->
+ %% There's no nice way to tell compiler-generated exceptions apart from
+ %% user ones so we ignore them all. I doubt anyone cares.
+ Acc;
+add_unopt_binary_info(#b_switch{anno=Anno}=I, Nested, Where, _UseMap, Acc) ->
+ [make_promotion_warning(I, Nested, Anno, Where) | Acc];
+add_unopt_binary_info(#b_set{anno=Anno}=I, Nested, Where, _UseMap, Acc) ->
+ [make_promotion_warning(I, Nested, Anno, Where) | Acc];
+add_unopt_binary_info(#b_ret{anno=Anno}=I, Nested, Where, _UseMap, Acc) ->
+ [make_promotion_warning(I, Nested, Anno, Where) | Acc];
+add_unopt_binary_info(#b_br{anno=Anno}=I, Nested, Where, _UseMap, Acc) ->
+ [make_promotion_warning(I, Nested, Anno, Where) | Acc].
+
+make_promotion_warning(I, Nested, Anno, Where) ->
+ make_warning({binary_created, I, Nested}, Anno, Where).
+
+make_warning(Term, Anno, Where) ->
+ {File, Line} = maps:get(location, Anno, Where),
+ {File,[{Line,?MODULE,Term}]}.
+
+format_opt_info(context_reused) ->
+ "OPTIMIZED: match context reused";
+format_opt_info({binary_created, _, _}=Promotion) ->
+ io_lib:format("BINARY CREATED: ~s", [format_opt_info_1(Promotion)]);
+format_opt_info(Other) ->
+ io_lib:format("NOT OPTIMIZED: ~s", [format_opt_info_1(Other)]).
+
+format_opt_info_1({binary_created, #b_set{op=call,args=[Call|_]}, false}) ->
+ io_lib:format("binary is used in call to ~s which doesn't support "
+ "context reuse", [format_call(Call)]);
+format_opt_info_1({binary_created, #b_set{op=call,args=[Call|_]}, true}) ->
+ io_lib:format("binary is used in term passed to ~s",
+ [format_call(Call)]);
+format_opt_info_1({binary_created, #b_set{op={bif, BIF},args=Args}, false}) ->
+ io_lib:format("binary is used in ~p/~p which doesn't support context "
+ "reuse", [BIF, length(Args)]);
+format_opt_info_1({binary_created, #b_set{op={bif, BIF},args=Args}, true}) ->
+ io_lib:format("binary is used in term passed to ~p/~p",
+ [BIF, length(Args)]);
+format_opt_info_1({binary_created, #b_set{op=Op}, false}) ->
+ io_lib:format("binary is used in '~p' which doesn't support context "
+ "reuse", [Op]);
+format_opt_info_1({binary_created, #b_set{op=Op}, true}) ->
+ io_lib:format("binary is used in term passed to '~p'", [Op]);
+format_opt_info_1({binary_created, #b_ret{}, false}) ->
+ io_lib:format("binary is returned from the function", []);
+format_opt_info_1({binary_created, #b_ret{}, true}) ->
+ io_lib:format("binary is used in a term that is returned from the "
+ "function", []);
+format_opt_info_1({unsuitable_call, {Call, Inner}}) ->
+ io_lib:format("binary used in call to ~s, where ~s",
+ [format_call(Call), format_opt_info_1(Inner)]);
+format_opt_info_1({remote_call, Call}) ->
+ io_lib:format("binary is used in remote call to ~s", [format_call(Call)]);
+format_opt_info_1({fun_call, Call}) ->
+ io_lib:format("binary is used in fun call (~s)",
+ [format_call(Call)]);
+format_opt_info_1({multiple_uses_in_call, Call}) ->
+ io_lib:format("binary is passed as multiple arguments to ~s",
+ [format_call(Call)]);
+format_opt_info_1({no_match_on_entry, Call}) ->
+ io_lib:format("binary is used in call to ~s which does not begin with a "
+ "suitable binary match", [format_call(Call)]);
+format_opt_info_1({used_before_match, #b_set{op=call,args=[Call|_]}}) ->
+ io_lib:format("binary is used in call to ~s before being matched",
+ [format_call(Call)]);
+format_opt_info_1({used_before_match, #b_set{op={bif, BIF},args=Args}}) ->
+ io_lib:format("binary is used in ~p/~p before being matched",
+ [BIF, length(Args)]);
+format_opt_info_1({used_before_match, #b_set{op=phi}}) ->
+ io_lib:format("binary is returned from an expression before being "
+ "matched", []);
+format_opt_info_1({used_before_match, #b_set{op=Op}}) ->
+ io_lib:format("binary is used in '~p' before being matched",[Op]);
+format_opt_info_1(Term) ->
+ io_lib:format("~w", [Term]).
+
+format_call(#b_local{name=#b_literal{val=F},arity=A}) ->
+ io_lib:format("~p/~p", [F, A]);
+format_call(#b_remote{mod=#b_literal{val=M},name=#b_literal{val=F},arity=A}) ->
+ io_lib:format("~p:~p/~p", [M, F, A]);
+format_call(Fun) ->
+ io_lib:format("~p", [Fun]).
diff --git a/lib/compiler/src/beam_ssa_codegen.erl b/lib/compiler/src/beam_ssa_codegen.erl
new file mode 100644
index 0000000000..c2d5035b19
--- /dev/null
+++ b/lib/compiler/src/beam_ssa_codegen.erl
@@ -0,0 +1,2077 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% Purpose: Generate BEAM assembly code from the SSA format.
+
+-module(beam_ssa_codegen).
+
+-export([module/2]).
+-export([classify_heap_need/2]). %Called from beam_ssa_pre_codegen.
+
+-export_type([ssa_register/0]).
+
+-include("beam_ssa.hrl").
+
+-import(lists, [foldl/3,keymember/3,keysort/2,last/1,map/2,mapfoldl/3,
+ reverse/1,reverse/2,sort/1,splitwith/2,takewhile/2]).
+
+-record(cg, {lcount=1 :: beam_label(), %Label counter
+ functable=#{} :: #{fa()=>beam_label()},
+ labels=#{} :: #{ssa_label()=>0|beam_label()},
+ used_labels=gb_sets:empty() :: gb_sets:set(ssa_label()),
+ regs=#{} :: #{beam_ssa:var_name()=>ssa_register()},
+ ultimate_fail=1 :: beam_label(),
+ catches=gb_sets:empty() :: gb_sets:set(ssa_label())
+ }).
+
+-spec module(beam_ssa:b_module(), [compile:option()]) ->
+ {'ok',beam_asm:module_code()}.
+
+module(#b_module{name=Mod,exports=Es,attributes=Attrs,body=Fs}, _Opts) ->
+ {Asm,St} = functions(Fs, {atom,Mod}),
+ {ok,{Mod,Es,Attrs,Asm,St#cg.lcount}}.
+
+-record(need, {h=0 :: non_neg_integer(),
+ f=0 :: non_neg_integer()}).
+
+-record(cg_blk, {anno=#{} :: anno(),
+ is=[] :: [instruction()],
+ last :: terminator()}).
+
+-record(cg_set, {anno=#{} :: anno(),
+ dst :: b_var(),
+ op :: beam_ssa:op(),
+ args :: [beam_ssa:argument() | xreg()]}).
+
+-record(cg_alloc, {anno=#{} :: anno(),
+ stack=none :: 'none' | pos_integer(),
+ words=#need{} :: #need{},
+ live :: 'undefined' | pos_integer(),
+ def_yregs=[] :: [yreg()]
+ }).
+
+-record(cg_br, {bool :: beam_ssa:value(),
+ succ :: ssa_label(),
+ fail :: ssa_label()
+ }).
+-record(cg_ret, {arg :: cg_value(),
+ dealloc=none :: 'none' | pos_integer()
+ }).
+-record(cg_switch, {arg :: cg_value(),
+ fail :: ssa_label(),
+ list :: [sw_list_item()]
+ }).
+
+-type fa() :: {beam_asm:function_name(),arity()}.
+-type ssa_label() :: beam_ssa:label().
+-type beam_label() :: beam_asm:label().
+
+-type anno() :: beam_ssa:anno().
+
+-type b_var() :: beam_ssa:b_var().
+-type b_literal() :: beam_ssa:b_literal().
+
+-type cg_value() :: beam_ssa:value() | xreg().
+
+-type cg_set() :: #cg_set{}.
+-type cg_alloc() :: #cg_alloc{}.
+
+-type instruction() :: cg_set() | cg_alloc().
+
+-type cg_br() :: #cg_br{}.
+-type cg_ret() :: #cg_ret{}.
+-type cg_switch() :: #cg_switch{}.
+-type terminator() :: cg_br() | cg_ret() | cg_switch().
+
+-type sw_list_item() :: {b_literal(),ssa_label()}.
+
+-type reg_num() :: beam_asm:reg_num().
+-type xreg() :: {'x',reg_num()}.
+-type yreg() :: {'y',reg_num()}.
+
+-type ssa_register() :: xreg() | yreg() | {'fr',reg_num()} | {'z',reg_num()}.
+
+functions(Forms, AtomMod) ->
+ mapfoldl(fun (F, St) -> function(F, AtomMod, St) end,
+ #cg{lcount=1}, Forms).
+
+function(#b_function{anno=Anno,bs=Blocks}, AtomMod, St0) ->
+ #{func_info:={_,Name,Arity}} = Anno,
+ try
+ assert_badarg_block(Blocks), %Assertion.
+ Regs = maps:get(registers, Anno),
+ St1 = St0#cg{labels=#{},used_labels=gb_sets:empty(),
+ regs=Regs},
+ {Fi,St2} = new_label(St1), %FuncInfo label
+ {Entry,St3} = local_func_label(Name, Arity, St2),
+ {Ult,St4} = new_label(St3), %Ultimate failure
+ Labels = (St4#cg.labels)#{0=>Entry,?BADARG_BLOCK=>0},
+ St5 = St4#cg{labels=Labels,used_labels=gb_sets:singleton(Entry),
+ ultimate_fail=Ult},
+ {Body,St} = cg_fun(Blocks, St5),
+ Asm = [{label,Fi},line(Anno),
+ {func_info,AtomMod,{atom,Name},Arity}] ++
+ add_parameter_annos(Body, Anno) ++
+ [{label,Ult},if_end],
+ Func = {function,Name,Arity,Entry,Asm},
+ {Func,St}
+ catch
+ Class:Error:Stack ->
+ io:fwrite("Function: ~w/~w\n", [Name,Arity]),
+ erlang:raise(Class, Error, Stack)
+ end.
+
+assert_badarg_block(Blocks) ->
+ %% Assertion: ?BADARG_BLOCK must be the call erlang:error(badarg).
+ case Blocks of
+ #{?BADARG_BLOCK:=Blk} ->
+ #b_blk{is=[#b_set{op=call,dst=Ret,
+ args=[#b_remote{mod=#b_literal{val=erlang},
+ name=#b_literal{val=error}},
+ #b_literal{val=badarg}]}],
+ last=#b_ret{arg=Ret}} = Blk,
+ ok;
+ #{} ->
+ %% ?BADARG_BLOCK has been removed because it was never used.
+ ok
+ end.
+
+add_parameter_annos([{label, _}=Entry | Body], Anno) ->
+ ParamInfo = maps:get(parameter_type_info, Anno, #{}),
+ Annos = maps:fold(
+ fun(K, V, Acc) when is_map_key(K, ParamInfo) ->
+ TypeInfo = maps:get(K, ParamInfo),
+ [{'%', {type_info, V, TypeInfo}} | Acc];
+ (_K, _V, Acc) ->
+ Acc
+ end, [], maps:get(registers, Anno)),
+ [Entry | sort(Annos)] ++ Body.
+
+cg_fun(Blocks, St0) ->
+ Linear0 = linearize(Blocks),
+ St = collect_catch_labels(Linear0, St0),
+ Linear1 = need_heap(Linear0),
+ Linear2 = prefer_xregs(Linear1, St),
+ Linear3 = liveness(Linear2, St),
+ Linear4 = defined(Linear3, St),
+ Linear = opt_allocate(Linear4, St),
+ cg_linear(Linear, St).
+
+%% collect_catch_labels(Linear, St) -> St.
+%% Collect all catch labels (labels for blocks that begin
+%% with 'landingpad' instructions) for later use.
+
+collect_catch_labels(Linear, St) ->
+ Labels = collect_catch_labels_1(Linear),
+ St#cg{catches=gb_sets:from_list(Labels)}.
+
+collect_catch_labels_1([{L,#cg_blk{is=[#cg_set{op=landingpad}|_]}}|Bs]) ->
+ [L|collect_catch_labels_1(Bs)];
+collect_catch_labels_1([_|Bs]) ->
+ collect_catch_labels_1(Bs);
+collect_catch_labels_1([]) -> [].
+
+%% need_heap([{BlockLabel,Block]) -> [{BlockLabel,Block}].
+%% Insert need_heap instructions in the instruction list. Try to be smart and
+%% collect them together as much as possible.
+
+need_heap(Bs0) ->
+ Bs1 = need_heap_allocs(Bs0, #{}),
+ {Bs,#need{h=0,f=0}} = need_heap_blks(reverse(Bs1), #need{}, []),
+ Bs.
+
+need_heap_allocs([{L,#cg_blk{is=Is0,last=Terminator}=Blk0}|Bs], Counts0) ->
+ Next = next_block(Bs),
+ Successors = successors(Terminator),
+ Counts = foldl(fun(S, Cnts) ->
+ case Cnts of
+ #{S:=C} -> Cnts#{S:=C+1};
+ #{} when S =:= Next -> Cnts#{S=>1};
+ #{} -> Cnts#{S=>42}
+ end
+ end, Counts0, Successors),
+ case Counts of
+ #{L:=1} ->
+ [{L,Blk0}|need_heap_allocs(Bs, Counts)];
+ #{L:=_} ->
+ %% This block has multiple predecessors. Force an allocation
+ %% in this block so that the predecessors don't need to do
+ %% an allocation on behalf of this block.
+ Is = case need_heap_never(Is0) of
+ true -> Is0;
+ false -> [#cg_alloc{}|Is0]
+ end,
+ Blk = Blk0#cg_blk{is=Is},
+ [{L,Blk}|need_heap_allocs(Bs, Counts)];
+ #{} ->
+ [{L,Blk0}|need_heap_allocs(Bs, Counts)]
+ end;
+need_heap_allocs([], _) -> [].
+
+need_heap_never([#cg_alloc{}|_]) -> true;
+need_heap_never([#cg_set{op=recv_next}|_]) -> true;
+need_heap_never([#cg_set{op=wait}|_]) -> true;
+need_heap_never(_) -> false.
+
+need_heap_blks([{L,#cg_blk{is=Is0}=Blk0}|Bs], H0, Acc) ->
+ {Is1,H1} = need_heap_is(reverse(Is0), H0, []),
+ {Ns,H} = need_heap_terminator(Bs, L, H1),
+ Is = Ns ++ Is1,
+ Blk = Blk0#cg_blk{is=Is},
+ need_heap_blks(Bs, H, [{L,Blk}|Acc]);
+need_heap_blks([], H, Acc) ->
+ {Acc,H}.
+
+need_heap_is([#cg_alloc{words=Words}=Alloc0|Is], N, Acc) ->
+ Alloc = Alloc0#cg_alloc{words=add_heap_words(N, Words)},
+ need_heap_is(Is, #need{}, [Alloc|Acc]);
+need_heap_is([#cg_set{anno=Anno,op=bs_init}=I0|Is], N, Acc) ->
+ Alloc = case need_heap_need(N) of
+ [#cg_alloc{words=Need}] -> alloc(Need);
+ [] -> 0
+ end,
+ I = I0#cg_set{anno=Anno#{alloc=>Alloc}},
+ need_heap_is(Is, #need{}, [I|Acc]);
+need_heap_is([#cg_set{op=Op,args=Args}=I|Is], N, Acc) ->
+ case classify_heap_need(Op, Args) of
+ {put,Words} ->
+ %% Pass through adding to needed heap.
+ need_heap_is(Is, add_heap_words(N, Words), [I|Acc]);
+ put_float ->
+ need_heap_is(Is, add_heap_float(N), [I|Acc]);
+ neutral ->
+ need_heap_is(Is, N, [I|Acc]);
+ gc ->
+ need_heap_is(Is, #need{}, [I]++need_heap_need(N)++Acc)
+ end;
+need_heap_is([], N, Acc) ->
+ {Acc,N}.
+
+need_heap_terminator([{_,#cg_blk{last=#cg_br{succ=L,fail=L}}}|_], L, N) ->
+ %% Fallthrough.
+ {[],N};
+need_heap_terminator([{_,#cg_blk{is=Is,last=#cg_br{succ=L}}}|_], L, N) ->
+ case need_heap_need(N) of
+ [] ->
+ {[],#need{}};
+ [_|_]=Alloc ->
+ %% If the preceding instructions are a binary construction,
+ %% hoist the allocation and incorporate into the bs_init
+ %% instruction.
+ case reverse(Is) of
+ [#cg_set{op=succeeded},#cg_set{op=bs_init}|_] ->
+ {[],N};
+ [#cg_set{op=bs_put}|_] ->
+ {[],N};
+ _ ->
+ %% Not binary construction. Must emit an allocation
+ %% instruction in this block.
+ {Alloc,#need{}}
+ end
+ end;
+need_heap_terminator([{_,#cg_blk{}}|_], _, N) ->
+ {need_heap_need(N),#need{}};
+need_heap_terminator([], _, H) ->
+ {need_heap_need(H),#need{}}.
+
+need_heap_need(#need{h=0,f=0}) -> [];
+need_heap_need(#need{}=N) -> [#cg_alloc{words=N}].
+
+add_heap_words(#need{h=H1,f=F1}, #need{h=H2,f=F2}) ->
+ #need{h=H1+H2,f=F1+F2};
+add_heap_words(#need{h=Heap}=N, Words) when is_integer(Words) ->
+ N#need{h=Heap+Words}.
+
+add_heap_float(#need{f=F}=N) ->
+ N#need{f=F+1}.
+
+%% classify_heap_need(Operation, Arguments) ->
+%% gc | neutral | {put,Words} | put_float.
+%% Classify the heap need for this instruction. The return
+%% values have the following meaning.
+%%
+%% {put,Words} means that the instruction will use Words words to build
+%% something on the heap.
+%%
+%% 'put_float' means that the instruction will build one floating point
+%% number on the heap.
+%%
+%% 'gc' means that that the instruction can potentially do a GC or throw an
+%% exception. That means that an allocation instruction for any building
+%% must be placed after this instruction.
+%%
+%% 'neutral' means that the instruction does nothing to disturb the heap.
+
+-spec classify_heap_need(beam_ssa:op(), [beam_ssa:value()]) ->
+ 'gc' | 'neutral' |
+ {'put',non_neg_integer()} | 'put_float'.
+
+classify_heap_need(put_list, _) ->
+ {put,2};
+classify_heap_need(put_tuple_arity, [#b_literal{val=Words}]) ->
+ {put,Words+1};
+classify_heap_need(put_tuple, Elements) ->
+ {put,length(Elements)+1};
+classify_heap_need({bif,Name}, Args) ->
+ case is_gc_bif(Name, Args) of
+ false -> neutral;
+ true -> gc
+ end;
+classify_heap_need({float,Op}, _Args) ->
+ case Op of
+ get -> put_float;
+ _ -> neutral
+ end;
+classify_heap_need(Name, _Args) ->
+ classify_heap_need(Name).
+
+%% classify_heap_need(Operation) -> gc | neutral.
+%% Return either 'gc' or 'neutral'.
+%%
+%% 'gc' means that that the instruction can potentially do a GC or throw an
+%% exception. That means that an allocation instruction for any building
+%% must be placed after this instruction.
+%%
+%% 'neutral' means that the instruction does nothing to disturb the heap.
+%%
+%% Note: Only handle operations in this function that are not handled
+%% by classify_heap_need/2.
+
+classify_heap_need(bs_add) -> gc;
+classify_heap_need(bs_get) -> gc;
+classify_heap_need(bs_get_tail) -> gc;
+classify_heap_need(bs_init) -> gc;
+classify_heap_need(bs_init_writable) -> gc;
+classify_heap_need(bs_match_string) -> gc;
+classify_heap_need(bs_put) -> neutral;
+classify_heap_need(bs_restore) -> neutral;
+classify_heap_need(bs_save) -> neutral;
+classify_heap_need(bs_get_position) -> gc;
+classify_heap_need(bs_set_position) -> neutral;
+classify_heap_need(bs_skip) -> gc;
+classify_heap_need(bs_start_match) -> neutral;
+classify_heap_need(bs_test_tail) -> neutral;
+classify_heap_need(bs_utf16_size) -> neutral;
+classify_heap_need(bs_utf8_size) -> neutral;
+classify_heap_need(build_stacktrace) -> gc;
+classify_heap_need(call) -> gc;
+classify_heap_need(catch_end) -> gc;
+classify_heap_need(copy) -> neutral;
+classify_heap_need(extract) -> gc;
+classify_heap_need(get_hd) -> neutral;
+classify_heap_need(get_map_element) -> neutral;
+classify_heap_need(get_tl) -> neutral;
+classify_heap_need(get_tuple_element) -> neutral;
+classify_heap_need(has_map_field) -> neutral;
+classify_heap_need(is_nonempty_list) -> neutral;
+classify_heap_need(is_tagged_tuple) -> neutral;
+classify_heap_need(kill_try_tag) -> gc;
+classify_heap_need(landingpad) -> gc;
+classify_heap_need(make_fun) -> gc;
+classify_heap_need(new_try_tag) -> gc;
+classify_heap_need(peek_message) -> gc;
+classify_heap_need(put_map) -> gc;
+classify_heap_need(put_tuple_elements) -> neutral;
+classify_heap_need(raw_raise) -> gc;
+classify_heap_need(recv_next) -> gc;
+classify_heap_need(remove_message) -> neutral;
+classify_heap_need(resume) -> gc;
+classify_heap_need(set_tuple_element) -> gc;
+classify_heap_need(succeeded) -> neutral;
+classify_heap_need(timeout) -> gc;
+classify_heap_need(wait) -> gc;
+classify_heap_need(wait_timeout) -> gc.
+
+%%%
+%%% Because beam_ssa_pre_codegen has inserted 'copy' instructions to copy
+%%% variables that must be saved on the stack, a value can for some time
+%%% be in both an X register and a Y register.
+%%%
+%%% Here we will keep track of variables that have the same value and
+%%% rewrite instructions to use the variable that refers to the X
+%%% register instead of the Y register. That could improve performance,
+%%% since the BEAM interpreter have more optimized instructions
+%%% operating on X registers than on Y registers.
+%%%
+%%% 'call' and 'make_fun' are handled somewhat specially. If a value
+%%% already is in the correct X register, the X register will always
+%%% be used instead of the Y register. However, if there are one or more
+%%% values in the wrong X registers, the X registers variables will be
+%%% used only if that does not cause more 'move' instructions to be
+%%% be emitted than if the Y register variables were used.
+%%%
+%%% Here are some examples. The first example shows how a 'move' from
+%%% an Y register is eliminated:
+%%%
+%%% move x0 y1
+%%% move y1 x0 %%Will be eliminated.
+%%%
+%%% call f/1
+%%%
+%%% Here is an example when x0 and x1 must be swapped to load the argument
+%%% registers. Here the 'call' instruction will use the Y registers to
+%%% avoid introducing an extra 'move' insruction:
+%%%
+%%% move x0 y0
+%%% move x1 y1
+%%%
+%%% move y0 x1
+%%% move y1 x0
+%%%
+%%% call f/2
+%%%
+%%% Using the X register to load the argument registers would need
+%%% an extra 'move' instruction like this:
+%%%
+%%% move x0 y0
+%%% move x1 y1
+%%%
+%%% move x1 x2
+%%% move x0 x1
+%%% move x2 x0
+%%%
+%%% call f/2
+%%%
+
+prefer_xregs(Linear, St) ->
+ prefer_xregs(Linear, St, #{0=>#{}}).
+
+prefer_xregs([{L,#cg_blk{is=Is0,last=Last0}=Blk0}|Bs], St, Map0) ->
+ Copies0 = maps:get(L, Map0),
+ {Is,Copies} = prefer_xregs_is(Is0, St, Copies0, []),
+ Last = prefer_xregs_terminator(Last0, Copies, St),
+ Blk = Blk0#cg_blk{is=Is,last=Last},
+ Successors = successors(Last),
+ Map = prefer_xregs_successors(Successors, Copies, Map0),
+ [{L,Blk}|prefer_xregs(Bs, St, Map)];
+prefer_xregs([], _St, _Map) -> [].
+
+prefer_xregs_successors([L|Ls], Copies0, Map0) ->
+ case Map0 of
+ #{L:=Copies1} ->
+ Copies = merge_copies(Copies0, Copies1),
+ Map = Map0#{L:=Copies},
+ prefer_xregs_successors(Ls, Copies0, Map);
+ #{} ->
+ Map = Map0#{L=>Copies0},
+ prefer_xregs_successors(Ls, Copies0, Map)
+ end;
+prefer_xregs_successors([], _, Map) -> Map.
+
+prefer_xregs_is([#cg_alloc{}=I|Is], St, Copies0, Acc) ->
+ Copies = case I of
+ #cg_alloc{stack=none,words=#need{h=0,f=0}} ->
+ Copies0;
+ #cg_alloc{} ->
+ #{}
+ end,
+ prefer_xregs_is(Is, St, Copies, [I|Acc]);
+prefer_xregs_is([#cg_set{op=copy,dst=Dst,args=[Src]}=I|Is], St, Copies0, Acc) ->
+ Copies1 = prefer_xregs_prune(I, Copies0, St),
+ Copies = case beam_args([Src,Dst], St) of
+ [Same,Same] -> Copies1;
+ [_,_] -> Copies1#{Dst=>Src}
+ end,
+ prefer_xregs_is(Is, St, Copies, [I|Acc]);
+prefer_xregs_is([#cg_set{op=call,dst=Dst}=I0|Is], St, Copies, Acc) ->
+ I = prefer_xregs_call(I0, Copies, St),
+ prefer_xregs_is(Is, St, #{Dst=>{x,0}}, [I|Acc]);
+prefer_xregs_is([#cg_set{op=make_fun,dst=Dst}=I0|Is], St, Copies, Acc) ->
+ I = prefer_xregs_call(I0, Copies, St),
+ prefer_xregs_is(Is, St, #{Dst=>{x,0}}, [I|Acc]);
+prefer_xregs_is([#cg_set{op=set_tuple_element}=I|Is], St, Copies, Acc) ->
+ %% FIXME: HiPE translates the following code segment incorrectly:
+ %% {call_ext,3,{extfunc,erlang,setelement,3}}.
+ %% {move,{x,0},{y,3}}.
+ %% {set_tuple_element,{y,1},{y,3},1}.
+ %% Therefore, skip the translation of the arguments for set_tuple_element.
+ prefer_xregs_is(Is, St, Copies, [I|Acc]);
+prefer_xregs_is([#cg_set{args=Args0}=I0|Is], St, Copies0, Acc) ->
+ Args = [do_prefer_xreg(A, Copies0, St) || A <- Args0],
+ I = I0#cg_set{args=Args},
+ Copies = prefer_xregs_prune(I, Copies0, St),
+ prefer_xregs_is(Is, St, Copies, [I|Acc]);
+prefer_xregs_is([], _St, Copies, Acc) ->
+ {reverse(Acc),Copies}.
+
+prefer_xregs_terminator(#cg_br{bool=Arg0}=I, Copies, St) ->
+ Arg = do_prefer_xreg(Arg0, Copies, St),
+ I#cg_br{bool=Arg};
+prefer_xregs_terminator(#cg_ret{arg=Arg0}=I, Copies, St) ->
+ Arg = do_prefer_xreg(Arg0, Copies, St),
+ I#cg_ret{arg=Arg};
+prefer_xregs_terminator(#cg_switch{arg=Arg0}=I, Copies, St) ->
+ Arg = do_prefer_xreg(Arg0, Copies, St),
+ I#cg_switch{arg=Arg}.
+
+prefer_xregs_prune(#cg_set{anno=#{clobbers:=true}}, _, _) ->
+ #{};
+prefer_xregs_prune(#cg_set{dst=Dst}, Copies, St) ->
+ DstReg = beam_arg(Dst, St),
+ F = fun(_, Alias) ->
+ beam_arg(Alias, St) =/= DstReg
+ end,
+ maps:filter(F, Copies).
+
+%% prefer_xregs_call(Instruction, Copies, St) -> Instruction.
+%% Given a 'call' or 'make_fun' instruction, minimize the number
+%% of 'move' instructions to set up the argument registers.
+%% Prefer using X registers over Y registers, unless that will
+%% result in more 'move' instructions.
+
+prefer_xregs_call(#cg_set{args=[_]}=I, _Copies, _St) ->
+ I;
+prefer_xregs_call(#cg_set{args=[F|Args0]}=I, Copies, St) ->
+ case Args0 of
+ [A0] ->
+ %% Only one argument. Always prefer the X register
+ %% if available.
+ A = do_prefer_xreg(A0, Copies, St),
+ I#cg_set{args=[F,A]};
+ [_|_] ->
+ %% Two or more arguments. Try rewriting arguments in
+ %% two ways and see which way produces the least
+ %% number of 'move' instructions.
+ Args1 = prefer_xregs_call_1(Args0, Copies, 0, St),
+ Args2 = [do_prefer_xreg(A, Copies, St) || A <- Args0],
+ case {count_moves(Args1, St),count_moves(Args2, St)} of
+ {N1,N2} when N1 < N2 ->
+ %% There will be fewer 'move' instructions if
+ %% we keep using Y registers.
+ I#cg_set{args=[F|Args1]};
+ {_,_} ->
+ %% Always use the values in X registers.
+ I#cg_set{args=[F|Args2]}
+ end
+ end.
+
+count_moves(Args, St) ->
+ length(setup_args(beam_args(Args, St))).
+
+prefer_xregs_call_1([#b_var{}=A|As], Copies, X, St) ->
+ case {beam_arg(A, St),Copies} of
+ {{y,_},#{A:=Other}} ->
+ case beam_arg(Other, St) of
+ {x,X} ->
+ %% This value is already in the correct X register.
+ %% It is always benefical to use the X register variable.
+ [Other|prefer_xregs_call_1(As, Copies, X+1, St)];
+ _ ->
+ %% This value is another X register. Keep using
+ %% the Y register variable.
+ [A|prefer_xregs_call_1(As, Copies, X+1, St)]
+ end;
+ {_,_} ->
+ %% The value is not available in an X register.
+ [A|prefer_xregs_call_1(As, Copies, X+1, St)]
+ end;
+prefer_xregs_call_1([A|As], Copies, X, St) ->
+ [A|prefer_xregs_call_1(As, Copies, X+1, St)];
+prefer_xregs_call_1([], _, _, _) -> [].
+
+do_prefer_xreg(#b_var{}=A, Copies, St) ->
+ case {beam_arg(A, St),Copies} of
+ {{y,_},#{A:=Copy}} ->
+ Copy;
+ {_,_} ->
+ A
+ end;
+do_prefer_xreg(A, _, _) -> A.
+
+merge_copies(Copies0, Copies1) when map_size(Copies0) =< map_size(Copies1) ->
+ maps:filter(fun(K, V) ->
+ case Copies1 of
+ #{K:=V} -> true;
+ #{} -> false
+ end
+ end, Copies0);
+merge_copies(Copies0, Copies1) ->
+ merge_copies(Copies1, Copies0).
+
+
+%%%
+%%% Add annotations for the number of live registers.
+%%%
+
+liveness(Linear, #cg{regs=Regs}) ->
+ liveness(reverse(Linear), #{}, Regs, []).
+
+liveness([{L,#cg_blk{is=Is0,last=Last0}=Blk0}|Bs], LiveMap0, Regs, Acc) ->
+ Successors = liveness_successors(Last0),
+ Live0 = ordsets:union([liveness_get(S, LiveMap0) || S <- Successors]),
+ Live1 = liveness_terminator(Last0, Live0),
+ {Is,Live} = liveness_is(reverse(Is0), Regs, Live1, []),
+ LiveMap = LiveMap0#{L=>Live},
+ Blk = Blk0#cg_blk{is=Is},
+ liveness(Bs, LiveMap, Regs, [{L,Blk}|Acc]);
+liveness([], _LiveMap, _Regs, Acc) -> Acc.
+
+liveness_get(S, LiveMap) ->
+ case LiveMap of
+ #{S:=Live} -> Live;
+ #{} -> []
+ end.
+
+liveness_successors(Terminator) ->
+ successors(Terminator) -- [?BADARG_BLOCK].
+
+liveness_is([#cg_alloc{}=I0|Is], Regs, Live, Acc) ->
+ I = I0#cg_alloc{live=num_live(Live, Regs)},
+ liveness_is(Is, Regs, Live, [I|Acc]);
+liveness_is([#cg_set{dst=Dst,args=Args}=I0|Is], Regs, Live0, Acc) ->
+ Live1 = liveness_clobber(I0, Live0, Regs),
+ I1 = liveness_yregs_anno(I0, Live1, Regs),
+ Live2 = liveness_args(Args, Live1),
+ Live = ordsets:del_element(Dst, Live2),
+ I = liveness_anno(I1, Live, Regs),
+ liveness_is(Is, Regs, Live, [I|Acc]);
+liveness_is([], _, Live, Acc) ->
+ {Acc,Live}.
+
+liveness_terminator(#cg_br{bool=Arg}, Live) ->
+ liveness_terminator_1(Arg, Live);
+liveness_terminator(#cg_switch{arg=Arg}, Live) ->
+ liveness_terminator_1(Arg, Live);
+liveness_terminator(#cg_ret{arg=Arg}, Live) ->
+ liveness_terminator_1(Arg, Live).
+
+liveness_terminator_1(#b_var{}=V, Live) ->
+ ordsets:add_element(V, Live);
+liveness_terminator_1(#b_literal{}, Live) ->
+ Live;
+liveness_terminator_1(Reg, Live) ->
+ _ = verify_beam_register(Reg),
+ ordsets:add_element(Reg, Live).
+
+liveness_args([#b_var{}=V|As], Live) ->
+ liveness_args(As, ordsets:add_element(V, Live));
+liveness_args([#b_remote{mod=Mod,name=Name}|As], Live) ->
+ liveness_args([Mod,Name|As], Live);
+liveness_args([A|As], Live) ->
+ case is_beam_register(A) of
+ true ->
+ liveness_args(As, ordsets:add_element(A, Live));
+ false ->
+ liveness_args(As, Live)
+ end;
+liveness_args([], Live) -> Live.
+
+liveness_anno(#cg_set{op=Op}=I, Live, Regs) ->
+ case need_live_anno(Op) of
+ true ->
+ NumLive = num_live(Live, Regs),
+ Anno = (I#cg_set.anno)#{live=>NumLive},
+ I#cg_set{anno=Anno};
+ false ->
+ I
+ end.
+
+liveness_yregs_anno(#cg_set{op=Op,dst=Dst}=I, Live0, Regs) ->
+ case need_live_anno(Op) of
+ true ->
+ Live = ordsets:del_element(Dst, Live0),
+ LiveYregs = [V || V <- Live, is_yreg(V, Regs)],
+ Anno = (I#cg_set.anno)#{live_yregs=>LiveYregs},
+ I#cg_set{anno=Anno};
+ false ->
+ I
+ end.
+
+liveness_clobber(#cg_set{anno=Anno}, Live, Regs) ->
+ case Anno of
+ #{clobbers:=true} ->
+ [R || R <- Live, is_yreg(R, Regs)];
+ _ ->
+ Live
+ end.
+
+is_yreg(R, Regs) ->
+ case Regs of
+ #{R:={y,_}} -> true;
+ #{} -> false
+ end.
+
+num_live(Live, Regs) ->
+ Rs = ordsets:from_list([get_register(V, Regs) || V <- Live]),
+ num_live_1(Rs, 0).
+
+num_live_1([{x,X}|T], X) ->
+ num_live_1(T, X+1);
+num_live_1([{x,_}|_]=T, X) ->
+ %% error({hole,{x,X},expected,Next});
+ num_live_1(T, X+1);
+num_live_1([{y,_}|_], X) ->
+ X;
+num_live_1([{z,_}|_], X) ->
+ X;
+num_live_1([{fr,_}|T], X) ->
+ num_live_1(T, X);
+num_live_1([], X) ->
+ X.
+
+get_live(#cg_set{anno=#{live:=Live}}) ->
+ Live.
+
+%% need_live_anno(Operation) -> true|false.
+%% Return 'true' if the instruction needs a 'live' annotation with
+%% the number live X registers, or 'false' otherwise.
+
+need_live_anno(Op) ->
+ case Op of
+ {bif,_} -> true;
+ bs_get -> true;
+ bs_init -> true;
+ bs_get_position -> true;
+ bs_get_tail -> true;
+ bs_start_match -> true;
+ bs_skip -> true;
+ call -> true;
+ put_map -> true;
+ _ -> false
+ end.
+
+%%%
+%%% Add the following annotations for Y registers:
+%%%
+%%% def_yregs An ordset with variables that refer to live Y registers.
+%%% That is, Y registers that that have been killed
+%%% are not included. This annotation is added to all
+%%% instructions that require Y registers to be initialized.
+%%%
+%%% kill_yregs This annotation is added to call instructions. It is
+%%% an ordset containing variables referring to Y registers
+%%% that will no longer be used after the call instruction.
+%%%
+
+defined(Linear, #cg{regs=Regs}) ->
+ def(Linear, #{}, Regs).
+
+def([{L,#cg_blk{is=Is0,last=Last}=Blk0}|Bs], DefMap0, Regs) ->
+ Def0 = def_get(L, DefMap0),
+ {Is,Def} = def_is(Is0, Regs, Def0, []),
+ Successors = successors(Last),
+ DefMap = def_successors(Successors, Def, DefMap0),
+ Blk = Blk0#cg_blk{is=Is},
+ [{L,Blk}|def(Bs, DefMap, Regs)];
+def([], _, _) -> [].
+
+def_get(L, DefMap) ->
+ case DefMap of
+ #{L:=Def} -> Def;
+ #{} -> []
+ end.
+
+def_is([#cg_alloc{anno=Anno0}=I0|Is], Regs, Def, Acc) ->
+ I = I0#cg_alloc{anno=Anno0#{def_yregs=>Def}},
+ def_is(Is, Regs, Def, [I|Acc]);
+def_is([#cg_set{op=kill_try_tag,args=[#b_var{}=Tag]}=I|Is], Regs, Def0, Acc) ->
+ Def = ordsets:del_element(Tag, Def0),
+ def_is(Is, Regs, Def, [I|Acc]);
+def_is([#cg_set{op=catch_end,args=[#b_var{}=Tag|_]}=I|Is], Regs, Def0, Acc) ->
+ Def = ordsets:del_element(Tag, Def0),
+ def_is(Is, Regs, Def, [I|Acc]);
+def_is([#cg_set{anno=Anno0,op=call,dst=Dst}=I0|Is],
+ Regs, Def0, Acc) ->
+ #{live_yregs:=LiveYregVars} = Anno0,
+ LiveRegs = gb_sets:from_list([maps:get(V, Regs) || V <- LiveYregVars]),
+ Kill0 = ordsets:subtract(Def0, LiveYregVars),
+
+ %% Kill0 is the set of variables that have just died. However, the registers
+ %% used for killed variables may have been reused, so we must check that the
+ %% registers to be killed are not used by other variables.
+ Kill = [K || K <- Kill0, not gb_sets:is_element(maps:get(K, Regs), LiveRegs)],
+ Anno = Anno0#{def_yregs=>Def0,kill_yregs=>Kill},
+ I = I0#cg_set{anno=Anno},
+ Def1 = ordsets:subtract(Def0, Kill),
+ Def = def_add_yreg(Dst, Def1, Regs),
+ def_is(Is, Regs, Def, [I|Acc]);
+def_is([#cg_set{anno=Anno0,op={bif,Bif},dst=Dst,args=Args}=I0|Is],
+ Regs, Def0, Acc) ->
+ Arity = length(Args),
+ I = case is_gc_bif(Bif, Args) orelse not erl_bifs:is_safe(erlang, Bif, Arity) of
+ true ->
+ I0#cg_set{anno=Anno0#{def_yregs=>Def0}};
+ false ->
+ I0
+ end,
+ Def = def_add_yreg(Dst, Def0, Regs),
+ def_is(Is, Regs, Def, [I|Acc]);
+def_is([#cg_set{anno=Anno0,dst=Dst}=I0|Is], Regs, Def0, Acc) ->
+ I = case need_y_init(I0) of
+ true ->
+ I0#cg_set{anno=Anno0#{def_yregs=>Def0}};
+ false ->
+ I0
+ end,
+ Def = def_add_yreg(Dst, Def0, Regs),
+ def_is(Is, Regs, Def, [I|Acc]);
+def_is([], _, Def, Acc) ->
+ {reverse(Acc),Def}.
+
+def_add_yreg(Dst, Def, Regs) ->
+ case is_yreg(Dst, Regs) of
+ true -> ordsets:add_element(Dst, Def);
+ false -> Def
+ end.
+
+def_successors([S|Ss], Def0, DefMap) ->
+ case DefMap of
+ #{S:=Def1} ->
+ Def = ordsets:intersection(Def0, Def1),
+ def_successors(Ss, Def0, DefMap#{S:=Def});
+ #{} ->
+ def_successors(Ss, Def0, DefMap#{S=>Def0})
+ end;
+def_successors([], _, DefMap) -> DefMap.
+
+%% need_y_init(#cg_set{}) -> true|false.
+%% Return true if this instructions needs initialized Y registers
+%% (because the instruction may do a GC or cause an exception
+%% so that the stack will be scanned), or false otherwise.
+
+need_y_init(#cg_set{anno=#{clobbers:=Clobbers}}) -> Clobbers;
+need_y_init(#cg_set{op=bs_get}) -> true;
+need_y_init(#cg_set{op=bs_get_position}) -> true;
+need_y_init(#cg_set{op=bs_get_tail}) -> true;
+need_y_init(#cg_set{op=bs_init}) -> true;
+need_y_init(#cg_set{op=bs_skip,args=[#b_literal{val=Type}|_]}) ->
+ case Type of
+ utf8 -> true;
+ utf16 -> true;
+ utf32 -> true;
+ _ -> false
+ end;
+need_y_init(#cg_set{op=bs_start_match}) -> true;
+need_y_init(#cg_set{op=put_map}) -> true;
+need_y_init(#cg_set{}) -> false.
+
+%% opt_allocate([{BlockLabel,Block}], #st{}) -> [BeamInstruction].
+%% Update the def_yregs field of each #cg_alloc{} that allocates
+%% a stack frame. #cg_alloc.def_yregs will list all Y registers
+%% that will be initialized by the subsequent code (thus, the
+%% listed Y registers don't require init/1 instructions).
+
+opt_allocate(Linear, #cg{regs=Regs}) ->
+ opt_allocate_1(Linear, Regs).
+
+opt_allocate_1([{L,#cg_blk{is=[#cg_alloc{stack=Stk}=I0|Is]}=Blk0}|Bs]=Bs0, Regs)
+ when is_integer(Stk) ->
+ %% Collect the variables that are initialized by copy
+ %% instruction in this block.
+ case ordsets:from_list(opt_allocate_defs(Is, Regs)) of
+ Yregs when length(Yregs) =:= Stk ->
+ %% Those copy instructions are sufficient to fully
+ %% initialize the stack frame.
+ I = I0#cg_alloc{def_yregs=Yregs},
+ [{L,Blk0#cg_blk{is=[I|Is]}}|opt_allocate_1(Bs, Regs)];
+ Yregs0 ->
+ %% Determine a conservative approximation of the Y
+ %% registers that are guaranteed to be initialized by all
+ %% successors of this block, and to it add the variables
+ %% initialized by copy instructions in this block.
+ Yregs1 = opt_alloc_def(Bs0, gb_sets:singleton(L), []),
+ Yregs = ordsets:union(Yregs0, Yregs1),
+ I = I0#cg_alloc{def_yregs=Yregs},
+ [{L,Blk0#cg_blk{is=[I|Is]}}|opt_allocate_1(Bs, Regs)]
+ end;
+opt_allocate_1([B|Bs], Regs) ->
+ [B|opt_allocate_1(Bs, Regs)];
+opt_allocate_1([], _) -> [].
+
+opt_allocate_defs([#cg_set{op=copy,dst=Dst}|Is], Regs) ->
+ case is_yreg(Dst, Regs) of
+ true -> [Dst|opt_allocate_defs(Is, Regs)];
+ false -> []
+ end;
+opt_allocate_defs(_, _Regs) -> [].
+
+opt_alloc_def([{L,#cg_blk{is=Is,last=Last}}|Bs], Ws0, Def0) ->
+ case gb_sets:is_member(L, Ws0) of
+ false ->
+ opt_alloc_def(Bs, Ws0, Def0);
+ true ->
+ case opt_allocate_is(Is) of
+ none ->
+ Succ = successors(Last),
+ Ws = gb_sets:union(Ws0, gb_sets:from_list(Succ)),
+ opt_alloc_def(Bs, Ws, Def0);
+ Def1 when is_list(Def1) ->
+ Def = [Def1|Def0],
+ opt_alloc_def(Bs, Ws0, Def)
+ end
+ end;
+opt_alloc_def([], _, Def) ->
+ ordsets:intersection(Def).
+
+opt_allocate_is([#cg_set{anno=Anno}|Is]) ->
+ case Anno of
+ #{def_yregs:=Yregs} ->
+ Yregs;
+ #{} ->
+ opt_allocate_is(Is)
+ end;
+opt_allocate_is([#cg_alloc{anno=#{def_yregs:=Yregs},stack=none}|_]) ->
+ Yregs;
+opt_allocate_is([#cg_alloc{}|Is]) ->
+ opt_allocate_is(Is);
+opt_allocate_is([]) -> none.
+
+%%%
+%%% Here follows the main code generation functions.
+%%%
+
+%% cg_linear([{BlockLabel,Block}]) -> [BeamInstruction].
+%% Generate BEAM instructions.
+
+cg_linear([{L,#cg_blk{anno=#{recv_set:=L}=Anno0}=B0}|Bs], St0) ->
+ Anno = maps:remove(recv_set, Anno0),
+ B = B0#cg_blk{anno=Anno},
+ {Is,St1} = cg_linear([{L,B}|Bs], St0),
+ {Fail,St} = use_block_label(L, St1),
+ {[{recv_set,Fail}|Is],St};
+cg_linear([{L,#cg_blk{is=Is0,last=Last}}|Bs], St0) ->
+ Next = next_block(Bs),
+ St1 = new_block_label(L, St0),
+ {Is1,St2} = cg_block(Is0, Last, Next, St1),
+ {Is2,St} = cg_linear(Bs, St2),
+ {def_block_label(L, St)++Is1++Is2,St};
+cg_linear([], St) -> {[],St}.
+
+cg_block([#cg_set{op=recv_next}], #cg_br{succ=Lr0}, _Next, St0) ->
+ {Lr,St} = use_block_label(Lr0, St0),
+ {[{loop_rec_end,Lr}],St};
+cg_block([#cg_set{op=wait}], #cg_br{succ=Lr0}, _Next, St0) ->
+ {Lr,St} = use_block_label(Lr0, St0),
+ {[{wait,Lr}],St};
+cg_block(Is0, Last, Next, St0) ->
+ case Last of
+ #cg_br{succ=Next,fail=Next} ->
+ cg_block(Is0, none, St0);
+ #cg_br{succ=Same,fail=Same} ->
+ {Fail,St1} = use_block_label(Same, St0),
+ {Is,St} = cg_block(Is0, none, St1),
+ {Is++[jump(Fail)],St};
+ #cg_br{bool=Bool,succ=Next,fail=Fail0} ->
+ {Fail,St1} = use_block_label(Fail0, St0),
+ {Is,St} = cg_block(Is0, {Bool,Fail}, St1),
+ {Is,St};
+ #cg_br{bool=Bool,succ=Succ0,fail=Fail0} ->
+ {[Succ,Fail],St1} = use_block_labels([Succ0,Fail0], St0),
+ {Is,St} = cg_block(Is0, {Bool,Fail}, St1),
+ {Is++[jump(Succ)],St};
+ #cg_ret{arg=Src0,dealloc=N} ->
+ Src = beam_arg(Src0, St0),
+ cg_block(Is0, {return,Src,N}, St0);
+ #cg_switch{} ->
+ cg_switch(Is0, Last, St0)
+ end.
+
+cg_switch(Is0, Last, St0) ->
+ #cg_switch{arg=Src0,fail=Fail0,list=List0} = Last,
+ Src = beam_arg(Src0, St0),
+ {Fail1,St1} = use_block_label(Fail0, St0),
+ Fail = ensure_label(Fail1, St1),
+ {List1,St2} =
+ flatmapfoldl(fun({V,L}, S0) ->
+ {Lbl,S} = use_block_label(L, S0),
+ {[beam_arg(V, S),Lbl],S}
+ end, St1, List0),
+ {Is1,St} = cg_block(Is0, none, St2),
+ case reverse(Is1) of
+ [{bif,tuple_size,_,[Tuple],{z,_}=Src}|More] ->
+ List = map(fun({integer,Arity}) -> Arity;
+ ({f,_}=F) -> F
+ end, List1),
+ Is = reverse(More, [{select_tuple_arity,Tuple,Fail,{list,List}}]),
+ {Is,St};
+ _ ->
+ SelectVal = {select_val,Src,Fail,{list,List1}},
+ {Is1 ++ [SelectVal],St}
+ end.
+
+jump({f,_}=Fail) ->
+ {jump,Fail};
+jump({catch_tag,Fail}) ->
+ {jump,Fail}.
+
+bif_fail({f,_}=Fail) -> Fail;
+bif_fail({catch_tag,_}) -> {f,0}.
+
+next_block([]) -> none;
+next_block([{Next,_}|_]) -> Next.
+
+ensure_label(Fail0, #cg{ultimate_fail=Lbl}) ->
+ case bif_fail(Fail0) of
+ {f,0} -> {f,Lbl};
+ {f,_}=Fail -> Fail
+ end.
+
+cg_block([#cg_set{anno=#{recv_mark:=L}=Anno0}=I0|T], Context, St0) ->
+ Anno = maps:remove(recv_mark, Anno0),
+ I = I0#cg_set{anno=Anno},
+ {Is,St1} = cg_block([I|T], Context, St0),
+ {Fail,St} = use_block_label(L, St1),
+ {[{recv_mark,Fail}|Is],St};
+cg_block([#cg_set{op=new_try_tag,dst=Tag,args=Args}], {Tag,Fail0}, St) ->
+ {catch_tag,Fail} = Fail0,
+ [Reg,{atom,Kind}] = beam_args([Tag|Args], St),
+ {[{Kind,Reg,Fail}],St};
+cg_block([#cg_set{anno=Anno,op={bif,Name},dst=Dst0,args=Args0}=I,
+ #cg_set{op=succeeded,dst=Bool}], {Bool,Fail0}, St) ->
+ [Dst|Args] = beam_args([Dst0|Args0], St),
+ Line0 = call_line(body, {extfunc,erlang,Name,length(Args)}, Anno),
+ Fail = bif_fail(Fail0),
+ Line = case Fail of
+ {f,0} -> Line0;
+ {f,_} -> []
+ end,
+ case is_gc_bif(Name, Args) of
+ true ->
+ Live = get_live(I),
+ Kill = kill_yregs(Anno, St),
+ {Kill++Line++[{gc_bif,Name,Fail,Live,Args,Dst}],St};
+ false ->
+ {Line++[{bif,Name,Fail,Args,Dst}],St}
+ end;
+cg_block([#cg_set{op={bif,tuple_size},dst=Arity0,args=[Tuple0]},
+ #cg_set{op={bif,'=:='},dst=Bool,args=[Arity0,#b_literal{val=Ar}]}=Eq],
+ {Bool,Fail}=Context, St0) ->
+ Tuple = beam_arg(Tuple0, St0),
+ case beam_arg(Arity0, St0) of
+ {z,_} ->
+ %% The size will only be used once. Combine to a test_arity instruction.
+ Test = {test,test_arity,ensure_label(Fail, St0),[Tuple,Ar]},
+ {[Test],St0};
+ Arity ->
+ %% The size will be used more than once. Must do an explicit
+ %% BIF call followed by the '==' test.
+ TupleSize = {bif,tuple_size,{f,0},[Tuple],Arity},
+ {Is,St} = cg_block([Eq], Context, St0),
+ {[TupleSize|Is],St}
+ end;
+cg_block([#cg_set{op={bif,Name},dst=Dst0,args=Args0}]=Is0, {Dst0,Fail}, St0) ->
+ [Dst|Args] = beam_args([Dst0|Args0], St0),
+ case Dst of
+ {z,_} ->
+ %% The result of the BIF call will only be used once. Convert to
+ %% a test instruction.
+ {Test,St1} = bif_to_test(Name, Args, ensure_label(Fail, St0), St0),
+ {Test,St1};
+ _ ->
+ %% Must explicitly call the BIF since the result will be used
+ %% more than once.
+ {Is1,St1} = cg_block(Is0, none, St0),
+ {Is2,St} = cg_block([], {Dst0,Fail}, St1),
+ {Is1++Is2,St}
+ end;
+cg_block([#cg_set{anno=Anno,op={bif,Name},dst=Dst0,args=Args0}=I|T],
+ Context, St0) ->
+ [Dst|Args] = beam_args([Dst0|Args0], St0),
+ {Is0,St} = cg_block(T, Context, St0),
+ case is_gc_bif(Name, Args) of
+ true ->
+ Line = call_line(body, {extfunc,erlang,Name,length(Args)}, Anno),
+ Live = get_live(I),
+ Kill = kill_yregs(Anno, St),
+ Is = Kill++Line++[{gc_bif,Name,{f,0},Live,Args,Dst}|Is0],
+ {Is,St};
+ false ->
+ Is = [{bif,Name,{f,0},Args,Dst}|Is0],
+ {Is,St}
+ end;
+cg_block([#cg_set{op=bs_init,dst=Dst0,args=Args0,anno=Anno}=I,
+ #cg_set{op=succeeded,dst=Bool}], {Bool,Fail0}, St) ->
+ Fail = bif_fail(Fail0),
+ Line = line(Anno),
+ Alloc = map_get(alloc, Anno),
+ [#b_literal{val=Kind}|Args1] = Args0,
+ case Kind of
+ new ->
+ [Dst,Size,{integer,Unit}] = beam_args([Dst0|Args1], St),
+ Live = get_live(I),
+ {[Line|cg_bs_init(Dst, Size, Alloc, Unit, Live, Fail)],St};
+ private_append ->
+ [Dst,Src,Bits,{integer,Unit}] = beam_args([Dst0|Args1], St),
+ Flags = {field_flags,[]},
+ Is = [Line,{bs_private_append,Fail,Bits,Unit,Src,Flags,Dst}],
+ {Is,St};
+ append ->
+ [Dst,Src,Bits,{integer,Unit}] = beam_args([Dst0|Args1], St),
+ Flags = {field_flags,[]},
+ Live = get_live(I),
+ Is = [Line,{bs_append,Fail,Bits,Alloc,Live,Unit,Src,Flags,Dst}],
+ {Is,St}
+ end;
+cg_block([#cg_set{anno=Anno,op=bs_start_match,dst=Ctx0,args=[Bin0]}=I,
+ #cg_set{op=succeeded,dst=Bool}], {Bool,Fail}, St) ->
+ [Dst,Bin1] = beam_args([Ctx0,Bin0], St),
+ {Bin,Pre} = force_reg(Bin1, Dst),
+ Live = get_live(I),
+ %% num_slots is only set when using the old instructions.
+ case maps:find(num_slots, Anno) of
+ {ok, Slots} ->
+ Is = Pre ++ [{test,bs_start_match2,Fail,Live,[Bin,Slots],Dst}],
+ {Is,St};
+ error ->
+ Is = Pre ++ [{test,bs_start_match3,Fail,Live,[Bin],Dst}],
+ {Is,St}
+ end;
+cg_block([#cg_set{op=bs_get}=Set,
+ #cg_set{op=succeeded,dst=Bool}], {Bool,Fail}, St) ->
+ {cg_bs_get(Fail, Set, St),St};
+cg_block([#cg_set{op=bs_match_string,args=[CtxVar,#b_literal{val=String}]},
+ #cg_set{op=succeeded,dst=Bool}], {Bool,Fail}, St) ->
+ CtxReg = beam_arg(CtxVar, St),
+ Is = [{test,bs_match_string,Fail,[CtxReg,String]}],
+ {Is,St};
+cg_block([#cg_set{dst=Dst0,op=landingpad,args=Args0}|T], Context, St0) ->
+ [Dst,{atom,Kind},Tag] = beam_args([Dst0|Args0], St0),
+ case Kind of
+ 'catch' ->
+ cg_catch(Dst, T, Context, St0);
+ 'try' ->
+ cg_try(Dst, Tag, T, Context, St0)
+ end;
+cg_block([#cg_set{op=kill_try_tag,args=Args0}|Is], Context, St0) ->
+ [Reg] = beam_args(Args0, St0),
+ {Is0,St} = cg_block(Is, Context, St0),
+ {[{try_end,Reg}|Is0],St};
+cg_block([#cg_set{op=catch_end,dst=Dst0,args=Args0}|Is], Context, St0) ->
+ [Dst,Reg,{x,0}] = beam_args([Dst0|Args0], St0),
+ {Is0,St} = cg_block(Is, Context, St0),
+ {[{catch_end,Reg}|copy({x,0}, Dst)++Is0],St};
+cg_block([#cg_set{op=call}=I,
+ #cg_set{op=succeeded,dst=Bool}], {Bool,_Fail}, St) ->
+ %% A call in try/catch block.
+ cg_block([I], none, St);
+cg_block([#cg_set{op=Op,dst=Dst0,args=Args0}=I,
+ #cg_set{op=succeeded,dst=Bool}], {Bool,Fail}, St) ->
+ [Dst|Args] = beam_args([Dst0|Args0], St),
+ {cg_test(Op, bif_fail(Fail), Args, Dst, I),St};
+cg_block([#cg_set{op=bs_put,dst=Bool,args=Args0}], {Bool,Fail}, St) ->
+ Args = beam_args(Args0, St),
+ {cg_bs_put(bif_fail(Fail), Args),St};
+cg_block([#cg_set{op=bs_test_tail,dst=Bool,args=Args0}], {Bool,Fail}, St) ->
+ [Ctx,{integer,Bits}] = beam_args(Args0, St),
+ {[{test,bs_test_tail2,bif_fail(Fail),[Ctx,Bits]}],St};
+cg_block([#cg_set{op={float,checkerror},dst=Bool}], {Bool,Fail}, St) ->
+ {[{fcheckerror,bif_fail(Fail)}],St};
+cg_block([#cg_set{op=is_tagged_tuple,dst=Bool,args=Args0}], {Bool,Fail}, St) ->
+ [Src,{integer,Arity},Tag] = beam_args(Args0, St),
+ {[{test,is_tagged_tuple,ensure_label(Fail, St),[Src,Arity,Tag]}],St};
+cg_block([#cg_set{op=is_nonempty_list,dst=Bool,args=Args0}], {Bool,Fail}, St) ->
+ Args = beam_args(Args0, St),
+ {[{test,is_nonempty_list,ensure_label(Fail, St),Args}],St};
+cg_block([#cg_set{op=has_map_field,dst=Bool,args=Args0}], {Bool,Fail}, St) ->
+ [Src,Key] = beam_args(Args0, St),
+ {[{test,has_map_fields,Fail,Src,{list,[Key]}}],St};
+cg_block([#cg_set{op=call}=Call], {_Bool,_Fail}=Context, St0) ->
+ {Is0,St1} = cg_call(Call, body, none, St0),
+ {Is1,St} = cg_block([], Context, St1),
+ {Is0++Is1,St};
+cg_block([#cg_set{op=call,dst=Dst0}=Call], Context, St) ->
+ Dst = beam_arg(Dst0, St),
+ case Context of
+ {return,Dst,_} ->
+ cg_call(Call, tail, Context, St);
+ _ ->
+ cg_call(Call, body, Context, St)
+ end;
+cg_block([#cg_set{op=call}=Call|T], Context, St0) ->
+ {Is0,St1} = cg_call(Call, body, none, St0),
+ {Is1,St} = cg_block(T, Context, St1),
+ {Is0++Is1,St};
+cg_block([#cg_set{op=make_fun,dst=Dst0,args=[Local|Args0]}|T],
+ Context, St0) ->
+ #b_local{name=#b_literal{val=Func},arity=Arity} = Local,
+ [Dst|Args] = beam_args([Dst0|Args0], St0),
+ {FuncLbl,St1} = local_func_label(Func, Arity, St0),
+ Is0 = setup_args(Args) ++
+ [{make_fun2,{f,FuncLbl},0,0,length(Args)}|copy({x,0}, Dst)],
+ {Is1,St} = cg_block(T, Context, St1),
+ {Is0++Is1,St};
+cg_block([#cg_set{op=copy}|_]=T0, Context, St0) ->
+ {Is0,T} = cg_copy(T0, St0),
+ {Is1,St} = cg_block(T, Context, St0),
+ Is = Is0 ++ Is1,
+ case is_call(T) of
+ {yes,Arity} ->
+ {opt_call_moves(Is, Arity),St};
+ no ->
+ {Is,St}
+ end;
+cg_block([#cg_set{op=Op,dst=Dst0,args=Args0}=Set], none, St) ->
+ [Dst|Args] = beam_args([Dst0|Args0], St),
+ Is = cg_instr(Op, Args, Dst, Set),
+ {Is,St};
+cg_block([#cg_set{op=Op,dst=Dst0,args=Args0}=Set|T], Context, St0) ->
+ [Dst|Args] = beam_args([Dst0|Args0], St0),
+ Is0 = cg_instr(Op, Args, Dst, Set),
+ {Is1,St} = cg_block(T, Context, St0),
+ {Is0++Is1,St};
+cg_block([#cg_alloc{}=Alloc|T], Context, St0) ->
+ Is0 = cg_alloc(Alloc, St0),
+ {Is1,St} = cg_block(T, Context, St0),
+ {Is0++Is1,St};
+cg_block([], {return,Arg,none}, St) ->
+ Is = copy(Arg, {x,0}) ++ [return],
+ {Is,St};
+cg_block([], {return,Arg,N}, St) ->
+ Is = copy(Arg, {x,0}) ++ [{deallocate,N},return],
+ {Is,St};
+cg_block([], none, St) ->
+ {[],St};
+cg_block([], {Bool0,Fail}, St) ->
+ [Bool] = beam_args([Bool0], St),
+ {[{test,is_eq_exact,Fail,[Bool,{atom,true}]}],St}.
+
+cg_copy(T0, St) ->
+ {Copies,T} = splitwith(fun(#cg_set{op=copy}) -> true;
+ (_) -> false
+ end, T0),
+ Moves0 = cg_copy_1(Copies, St),
+ Moves1 = [Move || {move,Src,Dst}=Move <- Moves0, Src =/= Dst],
+ Scratch = {x,1022},
+ Moves = order_moves(Moves1, Scratch),
+ {Moves,T}.
+
+cg_copy_1([#cg_set{dst=Dst0,args=Args}|T], St) ->
+ [Dst,Src] = beam_args([Dst0|Args], St),
+ Copies = cg_copy_1(T, St),
+ case keymember(Dst, 3, Copies) of
+ true ->
+ %% Will be overwritten. Don't generate a move instruction.
+ Copies;
+ false ->
+ [{move,Src,Dst}|Copies]
+ end;
+cg_copy_1([], _St) -> [].
+
+-define(IS_LITERAL(Val), (Val =:= nil orelse
+ element(1, Val) =:= integer orelse
+ element(1, Val) =:= float orelse
+ element(1, Val) =:= atom orelse
+ element(1, Val) =:= literal)).
+
+bif_to_test('or', [V1,V2], {f,Lbl}=Fail, St0) when Lbl =/= 0 ->
+ {SuccLabel,St} = new_label(St0),
+ {[{test,is_eq_exact,{f,SuccLabel},[V1,{atom,false}]},
+ {test,is_eq_exact,Fail,[V2,{atom,true}]},
+ {label,SuccLabel}],St};
+bif_to_test(Op, Args, Fail, St) ->
+ {bif_to_test(Op, Args, Fail),St}.
+
+bif_to_test('and', [V1,V2], Fail) ->
+ [{test,is_eq_exact,Fail,[V1,{atom,true}]},
+ {test,is_eq_exact,Fail,[V2,{atom,true}]}];
+bif_to_test('not', [Var], Fail) ->
+ [{test,is_eq_exact,Fail,[Var,{atom,false}]}];
+bif_to_test(Name, Args, Fail) ->
+ [bif_to_test_1(Name, Args, Fail)].
+
+bif_to_test_1(is_atom, [_]=Ops, Fail) ->
+ {test,is_atom,Fail,Ops};
+bif_to_test_1(is_boolean, [_]=Ops, Fail) ->
+ {test,is_boolean,Fail,Ops};
+bif_to_test_1(is_binary, [_]=Ops, Fail) ->
+ {test,is_binary,Fail,Ops};
+bif_to_test_1(is_bitstring,[_]=Ops, Fail) ->
+ {test,is_bitstr,Fail,Ops};
+bif_to_test_1(is_float, [_]=Ops, Fail) ->
+ {test,is_float,Fail,Ops};
+bif_to_test_1(is_function, [_]=Ops, Fail) ->
+ {test,is_function,Fail,Ops};
+bif_to_test_1(is_function, [_,_]=Ops, Fail) ->
+ {test,is_function2,Fail,Ops};
+bif_to_test_1(is_integer, [_]=Ops, Fail) ->
+ {test,is_integer,Fail,Ops};
+bif_to_test_1(is_list, [_]=Ops, Fail) ->
+ {test,is_list,Fail,Ops};
+bif_to_test_1(is_map, [_]=Ops, Fail) ->
+ {test,is_map,Fail,Ops};
+bif_to_test_1(is_number, [_]=Ops, Fail) ->
+ {test,is_number,Fail,Ops};
+bif_to_test_1(is_pid, [_]=Ops, Fail) ->
+ {test,is_pid,Fail,Ops};
+bif_to_test_1(is_port, [_]=Ops, Fail) ->
+ {test,is_port,Fail,Ops};
+bif_to_test_1(is_reference, [_]=Ops, Fail) ->
+ {test,is_reference,Fail,Ops};
+bif_to_test_1(is_tuple, [_]=Ops, Fail) ->
+ {test,is_tuple,Fail,Ops};
+bif_to_test_1('=<', [A,B], Fail) ->
+ {test,is_ge,Fail,[B,A]};
+bif_to_test_1('>', [A,B], Fail) ->
+ {test,is_lt,Fail,[B,A]};
+bif_to_test_1('<', [_,_]=Ops, Fail) ->
+ {test,is_lt,Fail,Ops};
+bif_to_test_1('>=', [_,_]=Ops, Fail) ->
+ {test,is_ge,Fail,Ops};
+bif_to_test_1('==', [C,A], Fail) when ?IS_LITERAL(C) ->
+ {test,is_eq,Fail,[A,C]};
+bif_to_test_1('==', [_,_]=Ops, Fail) ->
+ {test,is_eq,Fail,Ops};
+bif_to_test_1('/=', [C,A], Fail) when ?IS_LITERAL(C) ->
+ {test,is_ne,Fail,[A,C]};
+bif_to_test_1('/=', [_,_]=Ops, Fail) ->
+ {test,is_ne,Fail,Ops};
+bif_to_test_1('=:=', [C,A], Fail) when ?IS_LITERAL(C) ->
+ {test,is_eq_exact,Fail,[A,C]};
+bif_to_test_1('=:=', [_,_]=Ops, Fail) ->
+ {test,is_eq_exact,Fail,Ops};
+bif_to_test_1('=/=', [C,A], Fail) when ?IS_LITERAL(C) ->
+ {test,is_ne_exact,Fail,[A,C]};
+bif_to_test_1('=/=', [_,_]=Ops, Fail) ->
+ {test,is_ne_exact,Fail,Ops}.
+
+opt_call_moves(Is0, Arity) ->
+ {Moves0,Is} = splitwith(fun({move,_,_}) -> true;
+ ({kill,_}) -> true;
+ (_) -> false
+ end, Is0),
+ Moves = opt_call_moves_1(Moves0, Arity),
+ Moves ++ Is.
+
+opt_call_moves_1([{move,Src,{x,_}=Tmp}=M1|[{kill,_}|_]=Is], Arity) ->
+ %% There could be a {move,Tmp,{x,0}} instruction after the
+ %% kill/1 instructions (moved to there by opt_move_to_x0/1).
+ case splitwith(fun({kill,_}) -> true;
+ (_) -> false
+ end, Is) of
+ {Kills,[{move,{x,_}=Tmp,{x,0}}=M2]} ->
+ %% The two move/2 instructions (M1 and M2) can be combined
+ %% to one. The question is, though, is it safe to place
+ %% them after the kill/1 instructions?
+ case is_killed(Src, Kills, Arity) of
+ true ->
+ %% Src (a Y register) is killed by one of the
+ %% kill/1 instructions. Thus M1 and M2
+ %% must be placed before the kill/1 instructions
+ %% (essentially undoing what opt_move_to_x0/1
+ %% did, which turned out to be a pessimization
+ %% in this case).
+ opt_call_moves_1([M1,M2|Kills], Arity);
+ false ->
+ %% Src is not killed by any of the kill/1
+ %% instructions. Thus it is safe to place
+ %% M1 and M2 after the kill/1 instructions.
+ opt_call_moves_1(Kills++[M1,M2], Arity)
+ end;
+ {_,_} ->
+ [M1|Is]
+ end;
+opt_call_moves_1([{move,Src,{x,_}=Tmp}=M1,{move,Tmp,Dst}=M2|Is], Arity) ->
+ case is_killed(Tmp, Is, Arity) of
+ true ->
+ %% The X register Tmp is never used again. We can collapse
+ %% the two move instruction into one.
+ [{move,Src,Dst}|opt_call_moves_1(Is, Arity)];
+ false ->
+ [M1|opt_call_moves_1([M2|Is], Arity)]
+ end;
+opt_call_moves_1([M|Ms], Arity) ->
+ [M|opt_call_moves_1(Ms, Arity)];
+opt_call_moves_1([], _Arity) -> [].
+
+is_killed(Y, [{kill,Y}|_], _) ->
+ true;
+is_killed(R, [{kill,_}|Is], Arity) ->
+ is_killed(R, Is, Arity);
+is_killed(R, [{move,R,_}|_], _) ->
+ false;
+is_killed(R, [{move,_,R}|_], _) ->
+ true;
+is_killed(R, [{move,_,_}|Is], Arity) ->
+ is_killed(R, Is, Arity);
+is_killed({x,X}, [], Arity) ->
+ X >= Arity;
+is_killed({y,_}, [], _) ->
+ false.
+
+cg_alloc(#cg_alloc{stack=none,words=#need{h=0,f=0}}, _St) ->
+ [];
+cg_alloc(#cg_alloc{stack=none,words=Need,live=Live}, _St) ->
+ [{test_heap,alloc(Need),Live}];
+cg_alloc(#cg_alloc{stack=Stk,words=Need,live=Live,def_yregs=DefYregs},
+ #cg{regs=Regs}) when is_integer(Stk) ->
+ Alloc = alloc(Need),
+ All = [{y,Y} || Y <- lists:seq(0, Stk-1)],
+ Def = ordsets:from_list([maps:get(V, Regs) || V <- DefYregs]),
+ NeedInit = ordsets:subtract(All, Def),
+ NoZero = length(Def)*2 > Stk,
+ I = case {NoZero,Alloc} of
+ {true,0} -> {allocate,Stk,Live};
+ {true,_} -> {allocate_heap,Stk,Alloc,Live};
+ {false,0} -> {allocate_zero,Stk,Live};
+ {false,_} -> {allocate_heap_zero,Stk,Alloc,Live}
+ end,
+ [I|case NoZero of
+ true -> [{init,Y} || Y <- NeedInit];
+ false -> []
+ end].
+
+alloc(#need{h=Words,f=0}) ->
+ Words;
+alloc(#need{h=Words,f=Floats}) ->
+ {alloc,[{words,Words},{floats,Floats}]}.
+
+is_call([#cg_set{op=call,args=[#b_var{}|Args]}|_]) ->
+ {yes,1+length(Args)};
+is_call([#cg_set{op=call,args=[_|Args]}|_]) ->
+ {yes,length(Args)};
+is_call([#cg_set{op=make_fun,args=[_|Args]}|_]) ->
+ {yes,length(Args)};
+is_call(_) ->
+ no.
+
+cg_call(#cg_set{anno=Anno,op=call,dst=Dst0,args=[#b_local{}=Func0|Args0]},
+ Where, Context, St0) ->
+ [Dst|Args] = beam_args([Dst0|Args0], St0),
+ #b_local{name=Name0,arity=Arity} = Func0,
+ {atom,Name} = beam_arg(Name0, St0),
+ {FuncLbl,St} = local_func_label(Name, Arity, St0),
+ Line = call_line(Where, local, Anno),
+ Call = build_call(call, Arity, {f,FuncLbl}, Context, Dst),
+ Is = setup_args(Args, Anno, Context, St) ++ Line ++ Call,
+ case Anno of
+ #{ result_type := Info } ->
+ {Is ++ [{'%', {type_info, Dst, Info}}], St};
+ #{} ->
+ {Is, St}
+ end;
+cg_call(#cg_set{anno=Anno0,op=call,dst=Dst0,args=[#b_remote{}=Func0|Args0]},
+ Where, Context, St) ->
+ [Dst|Args] = beam_args([Dst0|Args0], St),
+ #b_remote{mod=Mod0,name=Name0,arity=Arity} = Func0,
+ case {beam_arg(Mod0, St),beam_arg(Name0, St)} of
+ {{atom,Mod},{atom,Name}} ->
+ Func = {extfunc,Mod,Name,Arity},
+ Line = call_line(Where, Func, Anno0),
+ Call = build_call(call_ext, Arity, Func, Context, Dst),
+ Anno = case erl_bifs:is_exit_bif(Mod, Name, Arity) of
+ true ->
+ %% There is no need to kill Y registers
+ %% before calling an exit BIF.
+ maps:remove(kill_yregs, Anno0);
+ false ->
+ Anno0
+ end,
+ Is = setup_args(Args, Anno, Context, St) ++ Line ++ Call,
+ {Is,St};
+ {Mod,Name} ->
+ Apply = build_apply(Arity, Context, Dst),
+ Is = setup_args(Args++[Mod,Name], Anno0, Context, St) ++
+ [line(Anno0)] ++ Apply,
+ {Is,St}
+ end;
+cg_call(#cg_set{anno=Anno,op=call,dst=Dst0,args=Args0},
+ Where, Context, St) ->
+ [Dst,Func|Args] = beam_args([Dst0|Args0], St),
+ Line = call_line(Where, Func, Anno),
+ Arity = length(Args),
+ Call = build_call(call_fun, Arity, Func, Context, Dst),
+ Is = setup_args(Args++[Func], Anno, Context, St) ++ Line ++ Call,
+ {Is,St}.
+
+build_call(call_fun, Arity, _Func, none, Dst) ->
+ [{call_fun,Arity}|copy({x,0}, Dst)];
+build_call(call_fun, Arity, _Func, {return,Dst,N}, Dst) when is_integer(N) ->
+ [{call_fun,Arity},{deallocate,N},return];
+build_call(call_fun, Arity, _Func, {return,Val,N}, _Dst) when is_integer(N) ->
+ [{call_fun,Arity},{move,Val,{x,0}},{deallocate,N},return];
+build_call(call_ext, 2, {extfunc,erlang,'!',2}, none, Dst) ->
+ [send|copy({x,0}, Dst)];
+build_call(call_ext, 2, {extfunc,erlang,'!',2}, {return,Dst,N}, Dst)
+ when is_integer(N) ->
+ [send,{deallocate,N},return];
+build_call(Prefix, Arity, Func, {return,Dst,none}, Dst) ->
+ I = case Prefix of
+ call -> call_only;
+ call_ext -> call_ext_only
+ end,
+ [{I,Arity,Func}];
+build_call(call_ext, Arity, {extfunc,Mod,Name,Arity}=Func, {return,_,none}, _Dst) ->
+ true = erl_bifs:is_exit_bif(Mod, Name, Arity), %Assertion.
+ [{call_ext_only,Arity,Func}];
+build_call(Prefix, Arity, Func, {return,Dst,N}, Dst) when is_integer(N) ->
+ I = case Prefix of
+ call -> call_last;
+ call_ext -> call_ext_last
+ end,
+ [{I,Arity,Func,N}];
+build_call(I, Arity, Func, {return,Val,N}, _Dst) when is_integer(N) ->
+ [{I,Arity,Func}|copy(Val, {x,0})++[{deallocate,N},return]];
+build_call(I, Arity, Func, none, Dst) ->
+ [{I,Arity,Func}|copy({x,0}, Dst)].
+
+build_apply(Arity, {return,Dst,N}, Dst) when is_integer(N) ->
+ [{apply_last,Arity,N}];
+build_apply(Arity, {return,Val,N}, _Dst) when is_integer(N) ->
+ [{apply,Arity}|copy(Val, {x,0})++[{deallocate,N},return]];
+build_apply(Arity, none, Dst) ->
+ [{apply,Arity}|copy({x,0}, Dst)].
+
+cg_instr(put_map, [{atom,assoc},SrcMap|Ss], Dst, Set) ->
+ Live = get_live(Set),
+ [{put_map_assoc,{f,0},SrcMap,Dst,Live,{list,Ss}}];
+cg_instr(bs_get_tail, [Src], Dst, Set) ->
+ Live = get_live(Set),
+ [{bs_get_tail,Src,Dst,Live}];
+cg_instr(bs_get_position, [Ctx], Dst, Set) ->
+ Live = get_live(Set),
+ [{bs_get_position,Ctx,Dst,Live}];
+cg_instr(Op, Args, Dst, _Set) ->
+ cg_instr(Op, Args, Dst).
+
+cg_instr(bs_init_writable, Args, Dst) ->
+ setup_args(Args) ++ [bs_init_writable|copy({x,0}, Dst)];
+cg_instr(bs_restore, [Ctx,Slot], _Dst) ->
+ case Slot of
+ {integer,N} ->
+ [{bs_restore2,Ctx,N}];
+ {atom,start} ->
+ [{bs_restore2,Ctx,Slot}]
+ end;
+cg_instr(bs_save, [Ctx,Slot], _Dst) ->
+ {integer,N} = Slot,
+ [{bs_save2,Ctx,N}];
+cg_instr(bs_set_position, [Ctx,Pos], _Dst) ->
+ [{bs_set_position,Ctx,Pos}];
+cg_instr(build_stacktrace, Args, Dst) ->
+ setup_args(Args) ++ [build_stacktrace|copy({x,0}, Dst)];
+cg_instr(set_tuple_element=Op, [New,Tuple,{integer,Index}], _Dst) ->
+ [{Op,New,Tuple,Index}];
+cg_instr({float,clearerror}, [], _Dst) ->
+ [fclearerror];
+cg_instr({float,get}, [Src], Dst) ->
+ [{fmove,Src,Dst}];
+cg_instr({float,put}, [Src], Dst) ->
+ [{fmove,Src,Dst}];
+cg_instr(get_hd=Op, [Src], Dst) ->
+ [{Op,Src,Dst}];
+cg_instr(get_tl=Op, [Src], Dst) ->
+ [{Op,Src,Dst}];
+cg_instr(get_tuple_element=Op, [Src,{integer,N}], Dst) ->
+ [{Op,Src,N,Dst}];
+cg_instr(put_list=Op, [Hd,Tl], Dst) ->
+ [{Op,Hd,Tl,Dst}];
+cg_instr(put_tuple, Elements, Dst) ->
+ [{put_tuple2,Dst,{list,Elements}}];
+cg_instr(put_tuple_arity, [{integer,Arity}], Dst) ->
+ [{put_tuple,Arity,Dst}];
+cg_instr(put_tuple_elements, Elements, _Dst) ->
+ [{put,E} || E <- Elements];
+cg_instr(raw_raise, Args, Dst) ->
+ setup_args(Args) ++ [raw_raise|copy({x,0}, Dst)];
+cg_instr(remove_message, [], _Dst) ->
+ [remove_message];
+cg_instr(resume, [A,B], _Dst) ->
+ [{bif,raise,{f,0},[A,B],{x,0}}];
+cg_instr(timeout, [], _Dst) ->
+ [timeout].
+
+cg_test(bs_add=Op, Fail, [Src1,Src2,{integer,Unit}], Dst, _I) ->
+ [{Op,Fail,[Src1,Src2,Unit],Dst}];
+cg_test(bs_skip, Fail, Args, _Dst, I) ->
+ cg_bs_skip(Fail, Args, I);
+cg_test(bs_utf8_size=Op, Fail, [Src], Dst, _I) ->
+ [{Op,Fail,Src,Dst}];
+cg_test(bs_utf16_size=Op, Fail, [Src], Dst, _I) ->
+ [{Op,Fail,Src,Dst}];
+cg_test({float,convert}, Fail, [Src], Dst, _I) ->
+ {f,0} = Fail, %Assertion.
+ [{fconv,Src,Dst}];
+cg_test({float,Op0}, Fail, Args, Dst, #cg_set{anno=Anno}) ->
+ Op = case Op0 of
+ '+' -> fadd;
+ '-' when length(Args) =:= 2 -> fsub;
+ '-' -> fnegate;
+ '*' -> fmul;
+ '/' -> fdiv
+ end,
+ [line(Anno),{bif,Op,Fail,Args,Dst}];
+cg_test(get_map_element, Fail, [Map,Key], Dst, _I) ->
+ [{get_map_elements,Fail,Map,{list,[Key,Dst]}}];
+cg_test(peek_message, Fail, [], Dst, _I) ->
+ [{loop_rec,Fail,{x,0}}|copy({x,0}, Dst)];
+cg_test(put_map, Fail, [{atom,exact},SrcMap|Ss], Dst, Set) ->
+ Live = get_live(Set),
+ [{put_map_exact,Fail,SrcMap,Dst,Live,{list,Ss}}];
+cg_test(wait_timeout, Fail, [Timeout], _Dst, _) ->
+ case Timeout of
+ {atom,infinity} ->
+ [{wait,Fail}];
+ _ ->
+ [{wait_timeout,Fail,Timeout}]
+ end.
+
+cg_bs_get(Fail, #cg_set{dst=Dst0,args=[#b_literal{val=Type}|Ss0]}=Set, St) ->
+ Op = case Type of
+ integer -> bs_get_integer2;
+ float -> bs_get_float2;
+ binary -> bs_get_binary2;
+ utf8 -> bs_get_utf8;
+ utf16 -> bs_get_utf16;
+ utf32 -> bs_get_utf32
+ end,
+ [Dst|Ss1] = beam_args([Dst0|Ss0], St),
+ Ss = case Ss1 of
+ [Ctx,{literal,Flags},Size,{integer,Unit}] ->
+ %% Plain integer/float/binary.
+ [Ctx,Size,Unit,field_flags(Flags, Set)];
+ [Ctx,{literal,Flags}] ->
+ %% Utf8/16/32.
+ [Ctx,field_flags(Flags, Set)]
+ end,
+ Live = get_live(Set),
+ [{test,Op,Fail,Live,Ss,Dst}].
+
+cg_bs_skip(Fail, [{atom,Type}|Ss0], Set) ->
+ Op = case Type of
+ utf8 -> bs_skip_utf8;
+ utf16 -> bs_skip_utf16;
+ utf32 -> bs_skip_utf32;
+ _ -> bs_skip_bits2
+ end,
+ Live = get_live(Set),
+ Ss = case Ss0 of
+ [Ctx,{literal,Flags},Size,{integer,Unit}] ->
+ %% Plain integer/float/binary.
+ [Ctx,Size,Unit,field_flags(Flags, Set)];
+ [Ctx,{literal,Flags}] ->
+ %% Utf8/16/32.
+ [Ctx,Live,field_flags(Flags, Set)]
+ end,
+ case {Type,Ss} of
+ {binary,[_,{atom,all},1,_]} ->
+ [];
+ {binary,[R,{atom,all},U,_]} ->
+ [{test,bs_test_unit,Fail,[R,U]}];
+ {_,_} ->
+ [{test,Op,Fail,Ss}]
+ end.
+
+field_flags(Flags, #cg_set{anno=#{location:={File,Line}}}) ->
+ {field_flags,[{anno,[Line,{file,File}]}|Flags]};
+field_flags(Flags, _) ->
+ {field_flags,Flags}.
+
+cg_bs_put(Fail, [{atom,Type},{literal,Flags}|Args]) ->
+ Op = case Type of
+ integer -> bs_put_integer;
+ float -> bs_put_float;
+ binary -> bs_put_binary;
+ utf8 -> bs_put_utf8;
+ utf16 -> bs_put_utf16;
+ utf32 -> bs_put_utf32
+ end,
+ case Args of
+ [Src,Size,{integer,Unit}] ->
+ [{Op,Fail,Size,Unit,{field_flags,Flags},Src}];
+ [Src] ->
+ [{Op,Fail,{field_flags,Flags},Src}]
+ end.
+
+cg_bs_init(Dst, Size0, Alloc, Unit, Live, Fail) ->
+ Op = case Unit of
+ 1 -> bs_init_bits;
+ 8 -> bs_init2
+ end,
+ Size = cg_bs_init_size(Size0),
+ [{Op,Fail,Size,Alloc,Live,{field_flags,[]},Dst}].
+
+cg_bs_init_size({x,_}=R) -> R;
+cg_bs_init_size({y,_}=R) -> R;
+cg_bs_init_size({integer,Int}) -> Int.
+
+cg_catch(Agg, T0, Context, St0) ->
+ {Moves,T1} = cg_extract(T0, Agg, St0),
+ {T,St} = cg_block(T1, Context, St0),
+ {Moves++T,St}.
+
+cg_try(Agg, Tag, T0, Context, St0) ->
+ {Moves0,T1} = cg_extract(T0, Agg, St0),
+ Moves = order_moves(Moves0, {x,3}),
+ [#cg_set{op=kill_try_tag}|T2] = T1,
+ {T,St} = cg_block(T2, Context, St0),
+ {[{try_case,Tag}|Moves++T],St}.
+
+cg_extract([#cg_set{op=extract,dst=Dst0,args=Args0}|Is0], Agg, St) ->
+ [Dst,Agg,{integer,X}] = beam_args([Dst0|Args0], St),
+ {Ds,Is} = cg_extract(Is0, Agg, St),
+ case keymember(Dst, 3, Ds) of
+ true ->
+ %% This destination will be overwritten.
+ {Ds,Is};
+ false ->
+ {copy({x,X}, Dst)++Ds,Is}
+ end;
+cg_extract(Is, _, _) ->
+ {[],Is}.
+
+copy(Src, Src) -> [];
+copy(Src, Dst) -> [{move,Src,Dst}].
+
+force_reg({literal,_}=Lit, Reg) ->
+ {Reg,[{move,Lit,Reg}]};
+force_reg({integer,_}=Lit, Reg) ->
+ {Reg,[{move,Lit,Reg}]};
+force_reg({atom,_}=Lit, Reg) ->
+ {Reg,[{move,Lit,Reg}]};
+force_reg({float,_}=Lit, Reg) ->
+ {Reg,[{move,Lit,Reg}]};
+force_reg(nil=Lit, Reg) ->
+ {Reg,[{move,Lit,Reg}]};
+force_reg({Kind,_}=R, _) when Kind =:= x; Kind =:= y ->
+ {R,[]}.
+
+%% successors(Terminator) -> [Successor].
+%% Return an ordset of all successors for the given terminator.
+
+successors(#cg_br{succ=Succ,fail=Fail}) ->
+ ordsets:from_list([Succ,Fail]);
+successors(#cg_switch{fail=Fail,list=List}) ->
+ ordsets:from_list([Fail|[Lbl || {_,Lbl} <- List]]);
+successors(#cg_ret{}) -> [].
+
+%% linearize(Blocks) -> [{BlockLabel,#cg_blk{}}].
+%% Linearize the intermediate representation of the code. Also
+%% translate blocks from the SSA records to internal record types
+%% used only in this module.
+
+linearize(Blocks) ->
+ Linear = beam_ssa:linearize(Blocks),
+ linearize_1(Linear, Blocks).
+
+linearize_1([{?BADARG_BLOCK,_}|Ls], Blocks) ->
+ linearize_1(Ls, Blocks);
+linearize_1([{L,Block0}|Ls], Blocks) ->
+ Block = translate_block(L, Block0, Blocks),
+ [{L,Block}|linearize_1(Ls, Blocks)];
+linearize_1([], _Blocks) -> [].
+
+%% translate_block(BlockLabel, #b_blk{}, Blocks) -> #cg_blk{}.
+%% Translate a block to the internal records used in this module.
+%% Also eliminate phi nodes, replacing them with 'copy' instructions
+%% in the predecessor blocks.
+
+translate_block(L, #b_blk{anno=Anno,is=Is0,last=Last0}, Blocks) ->
+ Last = translate_terminator(Last0),
+ PhiCopies = translate_phis(L, Last, Blocks),
+ Is1 = translate_is(Is0, PhiCopies),
+ Is = case Anno of
+ #{frame_size:=Size} ->
+ Alloc = #cg_alloc{stack=Size},
+ [Alloc|Is1];
+ #{} -> Is1
+ end,
+ #cg_blk{anno=Anno,is=Is,last=Last}.
+
+translate_is([#b_set{op=phi}|Is], Tail) ->
+ translate_is(Is, Tail);
+translate_is([#b_set{anno=Anno0,op=Op,dst=Dst,args=Args}=I|Is], Tail) ->
+ Anno = case beam_ssa:clobbers_xregs(I) of
+ true -> Anno0#{clobbers=>true};
+ false -> Anno0
+ end,
+ [#cg_set{anno=Anno,op=Op,dst=Dst,args=Args}|translate_is(Is, Tail)];
+translate_is([], Tail) -> Tail.
+
+translate_terminator(#b_ret{anno=Anno,arg=Arg}) ->
+ Dealloc = case Anno of
+ #{deallocate:=N} -> N;
+ #{} -> none
+ end,
+ #cg_ret{arg=Arg,dealloc=Dealloc};
+translate_terminator(#b_br{bool=#b_literal{val=true},succ=Succ}) ->
+ #cg_br{bool=#b_literal{val=true},succ=Succ,fail=Succ};
+translate_terminator(#b_br{bool=#b_literal{val=false},fail=Fail}) ->
+ #cg_br{bool=#b_literal{val=true},succ=Fail,fail=Fail};
+translate_terminator(#b_br{bool=Bool,succ=Succ,fail=Fail}) ->
+ #cg_br{bool=Bool,succ=Succ,fail=Fail};
+translate_terminator(#b_switch{arg=Bool,fail=Fail,list=List}) ->
+ #cg_switch{arg=Bool,fail=Fail,list=List}.
+
+translate_phis(L, #cg_br{succ=Target,fail=Target}, Blocks) ->
+ #b_blk{is=Is} = maps:get(Target, Blocks),
+ Phis = takewhile(fun(#b_set{op=phi}) -> true;
+ (#b_set{}) -> false
+ end, Is),
+ phi_copies(Phis, L);
+translate_phis(_, _, _) -> [].
+
+phi_copies([#b_set{dst=Dst,args=PhiArgs}|Sets], L) ->
+ CopyArgs = [V || {V,Target} <- PhiArgs, Target =:= L],
+ [#cg_set{op=copy,dst=Dst,args=CopyArgs}|phi_copies(Sets, L)];
+phi_copies([], _) -> [].
+
+%% opt_move_to_x0([Instruction]) -> [Instruction].
+%% Simple peep-hole optimization to move a {move,Any,{x,0}} past
+%% any kill up to the next call instruction. (To give the loader
+%% an opportunity to combine the 'move' and the 'call' instructions.)
+
+opt_move_to_x0(Moves) ->
+ opt_move_to_x0(Moves, []).
+
+opt_move_to_x0([{move,_,{x,0}}=I|Is0], Acc0) ->
+ case move_past_kill(Is0, I, Acc0) of
+ impossible -> opt_move_to_x0(Is0, [I|Acc0]);
+ {Is,Acc} -> opt_move_to_x0(Is, Acc)
+ end;
+opt_move_to_x0([I|Is], Acc) ->
+ opt_move_to_x0(Is, [I|Acc]);
+opt_move_to_x0([], Acc) -> reverse(Acc).
+
+move_past_kill([{kill,Src}|_], {move,Src,_}, _) ->
+ impossible;
+move_past_kill([{kill,_}=I|Is], Move, Acc) ->
+ move_past_kill(Is, Move, [I|Acc]);
+move_past_kill(Is, Move, Acc) ->
+ {Is,[Move|Acc]}.
+
+%% setup_args(Args, Anno, Context) -> [Instruction].
+%% setup_args(Args) -> [Instruction].
+%% Set up X registers for a call.
+
+setup_args(Args, Anno, none, St) ->
+ case {setup_args(Args),kill_yregs(Anno, St)} of
+ {Moves,[]} ->
+ Moves;
+ {Moves,Kills} ->
+ opt_move_to_x0(Moves ++ Kills)
+ end;
+setup_args(Args, _, _, _) ->
+ setup_args(Args).
+
+setup_args([]) ->
+ [];
+setup_args([_|_]=Args) ->
+ Moves = gen_moves(Args, 0, []),
+ Scratch = {x,1+last(sort([length(Args)-1|[X || {x,X} <- Args]]))},
+ order_moves(Moves, Scratch).
+
+%% kill_yregs(Anno, #cg{}) -> [{kill,{y,Y}}].
+%% Kill Y registers that will not be used again.
+
+kill_yregs(#{kill_yregs:=Kill}, #cg{regs=Regs}) ->
+ ordsets:from_list([{kill,maps:get(V, Regs)} || V <- Kill]);
+kill_yregs(#{}, #cg{}) -> [].
+
+%% gen_moves(As, I, Acc)
+%% Generate the basic move instruction to move the arguments
+%% to their proper registers. The list will be sorted on
+%% destinations. (I.e. the move to {x,0} will be first --
+%% see the comment to order_moves/2.)
+
+gen_moves([A|As], I, Acc) ->
+ gen_moves(As, I+1, copy(A, {x,I}) ++ Acc);
+gen_moves([], _, Acc) ->
+ keysort(3, Acc).
+
+%% order_moves([Move], ScratchReg) -> [Move]
+%% Orders move instruction so that source registers are not
+%% destroyed before they are used. If there are cycles
+%% (such as {move,{x,0},{x,1}}, {move,{x,1},{x,1}}),
+%% the scratch register is used to break up the cycle.
+%% If possible, the first move of the input list is placed
+%% last in the result list (to make the move to {x,0} occur
+%% just before the call to allow the Beam loader to coalesce
+%% the instructions).
+
+order_moves(Ms, Scr) -> order_moves(Ms, Scr, []).
+
+order_moves([{move,_,_}=M|Ms0], ScrReg, Acc0) ->
+ {Chain,Ms} = collect_chain(Ms0, [M], ScrReg),
+ Acc = reverse(Chain, Acc0),
+ order_moves(Ms, ScrReg, Acc);
+order_moves([], _, Acc) -> Acc.
+
+collect_chain(Ms, Path, ScrReg) ->
+ collect_chain(Ms, Path, [], ScrReg).
+
+collect_chain([{move,Src,Same}=M|Ms0], [{move,Same,_}|_]=Path, Others, ScrReg) ->
+ case keymember(Src, 3, Path) of
+ false ->
+ collect_chain(reverse(Others, Ms0), [M|Path], [], ScrReg);
+ true ->
+ %% There is a cycle, which we must break up.
+ {break_up_cycle(M, Path, ScrReg),reverse(Others, Ms0)}
+ end;
+collect_chain([M|Ms], Path, Others, ScrReg) ->
+ collect_chain(Ms, Path, [M|Others], ScrReg);
+collect_chain([], Path, Others, _) ->
+ {Path,Others}.
+
+break_up_cycle({move,Src,_}=M, Path, ScrReg) ->
+ [{move,ScrReg,Src},M|break_up_cycle1(Src, Path, ScrReg)].
+
+break_up_cycle1(Dst, [{move,Src,Dst}|Path], ScrReg) ->
+ [{move,Src,ScrReg}|Path];
+break_up_cycle1(Dst, [M|Path], LastMove) ->
+ [M|break_up_cycle1(Dst, Path, LastMove)].
+
+%%%
+%%% General utility functions.
+%%%
+
+verify_beam_register({x,_}=Reg) -> Reg.
+
+is_beam_register({x,_}) -> true;
+is_beam_register(_) -> false.
+
+get_register(V, Regs) ->
+ case is_beam_register(V) of
+ true -> V;
+ false -> maps:get(V, Regs)
+ end.
+
+beam_args(As, St) ->
+ [beam_arg(A, St) || A <- As].
+
+beam_arg(#b_var{}=Name, #cg{regs=Regs}) ->
+ maps:get(Name, Regs);
+beam_arg(#b_literal{val=Val}, _) ->
+ if
+ is_atom(Val) -> {atom,Val};
+ is_float(Val) -> {float,Val};
+ is_integer(Val) -> {integer,Val};
+ Val =:= [] -> nil;
+ true -> {literal,Val}
+ end;
+beam_arg(Reg, _) ->
+ verify_beam_register(Reg).
+
+new_block_label(L, St0) ->
+ {_Lbl,St} = label_for_block(L, St0),
+ St.
+
+def_block_label(L, #cg{labels=Labels,used_labels=Used}) ->
+ Lbl = maps:get(L, Labels),
+ case gb_sets:is_member(Lbl, Used) of
+ false -> [];
+ true -> [{label,Lbl}]
+ end.
+
+use_block_labels(Ls, St) ->
+ mapfoldl(fun use_block_label/2, St, Ls).
+
+use_block_label(L, #cg{used_labels=Used,catches=Catches}=St0) ->
+ {Lbl,St} = label_for_block(L, St0),
+ case gb_sets:is_member(L, Catches) of
+ true ->
+ {{catch_tag,{f,Lbl}},
+ St#cg{used_labels=gb_sets:add(Lbl, Used)}};
+ false ->
+ {{f,Lbl},St#cg{used_labels=gb_sets:add(Lbl, Used)}}
+ end.
+
+label_for_block(L, #cg{labels=Labels0}=St0) ->
+ case Labels0 of
+ #{L:=Lbl} ->
+ {Lbl,St0};
+ #{} ->
+ {Lbl,St} = new_label(St0),
+ Labels = Labels0#{L=>Lbl},
+ {Lbl,St#cg{labels=Labels}}
+ end.
+
+%% local_func_label(Name, Arity, State) -> {Label,State'}
+%% local_func_label({Name,Arity}, State) -> {Label,State'}
+%% Get the function entry label for a local function.
+
+local_func_label(Name, Arity, St) ->
+ local_func_label({Name,Arity}, St).
+
+local_func_label(Key, #cg{functable=Map}=St0) ->
+ case Map of
+ #{Key := Label} ->
+ {Label,St0};
+ _ ->
+ {Label,St} = new_label(St0),
+ {Label,St#cg{functable=Map#{Key => Label}}}
+ end.
+
+%% is_gc_bif(Name, Args) -> true|false.
+%% Determines whether the BIF Name/Arity might do a GC.
+
+-spec is_gc_bif(atom(), [beam_ssa:value()]) -> boolean().
+
+is_gc_bif(hd, [_]) -> false;
+is_gc_bif(tl, [_]) -> false;
+is_gc_bif(self, []) -> false;
+is_gc_bif(node, []) -> false;
+is_gc_bif(node, [_]) -> false;
+is_gc_bif(element, [_,_]) -> false;
+is_gc_bif(get, [_]) -> false;
+is_gc_bif(is_map_key, [_,_]) -> false;
+is_gc_bif(map_get, [_,_]) -> false;
+is_gc_bif(tuple_size, [_]) -> false;
+is_gc_bif(Bif, Args) ->
+ Arity = length(Args),
+ not (erl_internal:bool_op(Bif, Arity) orelse
+ erl_internal:new_type_test(Bif, Arity) orelse
+ erl_internal:comp_op(Bif, Arity)).
+
+%% new_label(St) -> {L,St}.
+
+new_label(#cg{lcount=Next}=St) ->
+ {Next,St#cg{lcount=Next+1}}.
+
+%% call_line(tail|body, Func, Anno) -> [] | [{line,...}].
+%% Produce a line instruction if it will be needed by the
+%% call to Func.
+
+call_line(_Context, {extfunc,Mod,Name,Arity}, Anno) ->
+ case erl_bifs:is_safe(Mod, Name, Arity) of
+ false ->
+ %% The call could be to a BIF.
+ %% We'll need a line instruction in case the
+ %% BIF call fails.
+ [line(Anno)];
+ true ->
+ %% Call to a safe BIF. Since it cannot fail,
+ %% we don't need any line instruction here.
+ []
+ end;
+call_line(body, _, Anno) ->
+ [line(Anno)];
+call_line(tail, local, _) ->
+ %% Tail-recursive call to a local function. A line
+ %% instruction will not be useful.
+ [];
+call_line(tail, _, Anno) ->
+ %% Call to a fun.
+ [line(Anno)].
+
+%% line(Le) -> {line,[] | {location,File,Line}}
+%% Create a line instruction, containing information about
+%% the current filename and line number. A line information
+%% instruction should be placed before any operation that could
+%% cause an exception.
+
+line(#{location:={File,Line}}) ->
+ {line,[{location,File,Line}]};
+line(#{}) ->
+ {line,[]}.
+
+flatmapfoldl(F, Accu0, [Hd|Tail]) ->
+ {R,Accu1} = F(Hd, Accu0),
+ {Rs,Accu2} = flatmapfoldl(F, Accu1, Tail),
+ {R++Rs,Accu2};
+flatmapfoldl(_, Accu, []) -> {[],Accu}.
diff --git a/lib/compiler/src/beam_ssa_dead.erl b/lib/compiler/src/beam_ssa_dead.erl
new file mode 100644
index 0000000000..bb43a550ae
--- /dev/null
+++ b/lib/compiler/src/beam_ssa_dead.erl
@@ -0,0 +1,1076 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% Dead code is code that is executed but has no effect. This
+%% optimization pass either removes dead code or jumps around it,
+%% potentially making it unreachable so that it can be dropped
+%% the next time beam_ssa:linearize/1 is called.
+%%
+
+-module(beam_ssa_dead).
+-export([opt/1]).
+
+-include("beam_ssa.hrl").
+-import(lists, [append/1,keymember/3,last/1,member/2,
+ takewhile/2,reverse/1]).
+
+-type used_vars() :: #{beam_ssa:label():=ordsets:ordset(beam_ssa:var_name())}.
+
+-type basic_type_test() :: atom() | {'is_tagged_tuple',pos_integer(),atom()}.
+-type type_test() :: basic_type_test() | {'not',basic_type_test()}.
+-type op_name() :: atom().
+-type basic_rel_op() :: {op_name(),beam_ssa:b_var(),beam_ssa:value()} |
+ {basic_type_test(),beam_ssa:value()}.
+-type rel_op() :: {op_name(),beam_ssa:b_var(),beam_ssa:value()} |
+ {type_test(),beam_ssa:value()}.
+
+-record(st,
+ {bs :: beam_ssa:block_map(),
+ us :: used_vars(),
+ skippable :: #{beam_ssa:label():='true'},
+ rel_op=none :: 'none' | rel_op(),
+ target=any :: 'any' | 'one_way' | beam_ssa:label()
+ }).
+
+-spec opt([{Label0,Block0}]) -> [{Label,Block}] when
+ Label0 :: beam_ssa:label(),
+ Block0 :: beam_ssa:b_blk(),
+ Label :: beam_ssa:label(),
+ Block :: beam_ssa:b_blk().
+
+opt(Linear) ->
+ {Used,Skippable} = used_vars(Linear),
+ Blocks0 = maps:from_list(Linear),
+ St0 = #st{bs=Blocks0,us=Used,skippable=Skippable},
+ St = shortcut_opt(St0),
+ #st{bs=Blocks} = combine_eqs(St#st{us=#{}}),
+ beam_ssa:linearize(Blocks).
+
+%%%
+%%% Shortcut br/switch targets.
+%%%
+%%% A br/switch may branch to another br/switch that in turn always
+%%% branches to another target. Rewrite br/switch to refer to the
+%%% ultimate targets directly. That will save execution time, but
+%%% could also reduce the size of the code if some of the original
+%%% targets become unreachable and be deleted.
+%%%
+%%% When rewriting branches, we must be careful not to skip instructions
+%%% that have side effects or that bind variables that will be used
+%%% at the new target.
+%%%
+%%% We must also avoid branching to phi nodes. The reason is
+%%% twofold. First, we might create a critical edge which is strictly
+%%% forbidden. Second, there will be a branch from a block that is not
+%%% listed in the list of predecessors in the phi node. Those
+%%% limitations could probably be overcome, but it is not clear how
+%%% much that would improve the code.
+%%%
+
+shortcut_opt(#st{bs=Blocks}=St) ->
+ %% Processing the blocks in reverse post order seems to give more
+ %% opportunities for optimizations compared to post order. (Based on
+ %% running scripts/diffable with both PO and RPO and looking at
+ %% the diff.)
+ %%
+ %% Unfortunately, processing the blocks in reverse post order
+ %% potentially makes the time complexity quadratic or even cubic if
+ %% the ordset of unset variables grows large, instead of
+ %% linear for post order processing. We try to still get reasonable
+ %% compilation times by optimizations that will keep the constant
+ %% factor as low as possible, and we try to avoid the cubic time
+ %% complexity by trying to keep the set of unset variables as small
+ %% as possible.
+
+ Ls = beam_ssa:rpo(Blocks),
+ shortcut_opt(Ls, #{}, St).
+
+shortcut_opt([L|Ls], Bs, #st{bs=Blocks0}=St) ->
+ #b_blk{is=Is,last=Last0} = Blk0 = get_block(L, St),
+ case shortcut_terminator(Last0, Is, L, Bs, St) of
+ Last0 ->
+ %% No change. No need to update the block.
+ shortcut_opt(Ls, Bs, St);
+ Last ->
+ %% The terminator was simplified in some way.
+ %% Update the block.
+ Blk = Blk0#b_blk{last=Last},
+ Blocks = Blocks0#{L=>Blk},
+ shortcut_opt(Ls, Bs, St#st{bs=Blocks})
+ end;
+shortcut_opt([], _, St) -> St.
+
+shortcut_terminator(#b_br{bool=#b_literal{val=true},succ=Succ0},
+ _Is, From, Bs, St0) ->
+ St = St0#st{rel_op=none},
+ shortcut(Succ0, From, Bs, St);
+shortcut_terminator(#b_br{bool=#b_var{}=Bool,succ=Succ0,fail=Fail0}=Br,
+ Is, From, Bs, St0) ->
+ St = St0#st{target=one_way},
+ RelOp = get_rel_op(Bool, Is),
+ SuccBs = bind_var(Bool, #b_literal{val=true}, Bs),
+ BrSucc = shortcut(Succ0, From, SuccBs, St#st{rel_op=RelOp}),
+ FailBs = bind_var(Bool, #b_literal{val=false}, Bs),
+ BrFail = shortcut(Fail0, From, FailBs, St#st{rel_op=invert_op(RelOp)}),
+ case {BrSucc,BrFail} of
+ {#b_br{bool=#b_literal{val=true},succ=Succ},
+ #b_br{bool=#b_literal{val=true},succ=Fail}}
+ when Succ =/= Succ0; Fail =/= Fail0 ->
+ %% One or both of the targets were cut short.
+ beam_ssa:normalize(Br#b_br{succ=Succ,fail=Fail});
+ {_,_} ->
+ %% No change.
+ Br
+ end;
+shortcut_terminator(#b_switch{arg=Bool,list=List0}=Sw, _Is, From, Bs, St) ->
+ List = shortcut_switch(List0, Bool, From, Bs, St),
+ beam_ssa:normalize(Sw#b_switch{list=List});
+shortcut_terminator(Last, _Is, _Bs, _From, _St) ->
+ Last.
+
+shortcut_switch([{Lit,L0}|T], Bool, From, Bs, St0) ->
+ RelOp = {'=:=',Bool,Lit},
+ St = St0#st{rel_op=RelOp},
+ #b_br{bool=#b_literal{val=true},succ=L} =
+ shortcut(L0, From, bind_var(Bool, Lit, Bs), St#st{target=one_way}),
+ [{Lit,L}|shortcut_switch(T, Bool, From, Bs, St0)];
+shortcut_switch([], _, _, _, _) -> [].
+
+shortcut(L, From, Bs, St) ->
+ shortcut_1(L, From, Bs, ordsets:new(), St).
+
+shortcut_1(L, From, Bs0, UnsetVars0, St) ->
+ case shortcut_2(L, From, Bs0, UnsetVars0, St) of
+ none ->
+ %% No more shortcuts found. Package up the previous
+ %% label in an unconditional branch.
+ #b_br{bool=#b_literal{val=true},succ=L,fail=L};
+ {#b_br{bool=#b_var{}}=Br,_,_} ->
+ %% This is a two-way branch. We can't do any better.
+ Br;
+ {#b_br{bool=#b_literal{val=true},succ=Succ},Bs,UnsetVars} ->
+ %% This is a safe `br`, but try to find a better one.
+ shortcut_1(Succ, L, Bs, UnsetVars, St)
+ end.
+
+%% Try to shortcut this block, branching to a successor.
+shortcut_2(L, From, Bs0, UnsetVars0, St) ->
+ #b_blk{is=Is,last=Last} = get_block(L, St),
+ case eval_is(Is, From, Bs0, St) of
+ none ->
+ %% It is not safe to avoid this block because it
+ %% has instructions with potential side effects.
+ none;
+ Bs ->
+ %% The instructions in the block (if any) don't
+ %% have any side effects and can be skipped.
+ %% Evaluate the terminator.
+ case eval_terminator(Last, Bs, St) of
+ none ->
+ %% The terminator is not suitable (could be
+ %% because it is a switch that can't be simplified
+ %% or it is a ret instruction).
+ none;
+ #b_br{}=Br ->
+ %% We have a potentially suitable br.
+ %% Now update the set of variables that will never
+ %% be set if this block will be skipped.
+ case update_unset_vars(L, Is, Br, UnsetVars0, St) of
+ unsafe ->
+ %% It is unsafe to use this br,
+ %% because it refers to a variable defined
+ %% in this block.
+ shortcut_unsafe_br(Br, L, Bs, UnsetVars0, St);
+ UnsetVars ->
+ %% Continue checking whether this br is
+ %% suitable.
+ shortcut_test_br(Br, L, Bs, UnsetVars, St)
+ end
+ end
+ end.
+
+shortcut_test_br(Br, From, Bs, UnsetVars, St) ->
+ case is_br_safe(UnsetVars, Br, St) of
+ false ->
+ shortcut_unsafe_br(Br, From, Bs, UnsetVars, St);
+ true ->
+ shortcut_safe_br(Br, From, Bs, UnsetVars, St)
+ end.
+
+shortcut_unsafe_br(Br, From, Bs, UnsetVars, #st{target=Target}=St) ->
+ %% Branching using this `br` is unsafe, either because it
+ %% is an unconditional branch to a phi node, or because
+ %% one or more of the variables that are not set will be
+ %% used. Try to follow branches of this `br`, to find a
+ %% safe `br`.
+ case Br of
+ #b_br{bool=#b_literal{val=true},succ=L} ->
+ case Target of
+ L ->
+ %% We have reached the forced target, and it
+ %% is unsafe. Give up.
+ none;
+ _ ->
+ %% Try following this branch to see whether it
+ %% leads to a safe `br`.
+ shortcut_2(L, From, Bs, UnsetVars, St)
+ end;
+ #b_br{bool=#b_var{},succ=Succ,fail=Fail} ->
+ case {Succ,Fail} of
+ {L,Target} ->
+ %% The failure label is the forced target.
+ %% Try following the success label to see
+ %% whether it also ultimately ends up at the
+ %% forced target.
+ shortcut_2(L, From, Bs, UnsetVars, St);
+ {Target,L} ->
+ %% The success label is the forced target.
+ %% Try following the failure label to see
+ %% whether it also ultimately ends up at the
+ %% forced target.
+ shortcut_2(L, From, Bs, UnsetVars, St);
+ {_,_} ->
+ case Target of
+ any ->
+ %% This two-way branch is unsafe. Try
+ %% reducing it to a one-way branch.
+ shortcut_two_way(Br, From, Bs, UnsetVars, St);
+ one_way ->
+ %% This two-way branch is unsafe. Try
+ %% reducing it to a one-way branch.
+ shortcut_two_way(Br, From, Bs, UnsetVars, St);
+ _ when is_integer(Target) ->
+ %% This two-way branch is unsafe, and
+ %% there already is a forced target.
+ %% Give up.
+ none
+ end
+ end
+ end.
+
+shortcut_safe_br(Br, From, Bs, UnsetVars, #st{target=Target}=St) ->
+ %% This `br` instruction is safe. It does not branch to a phi
+ %% node, and all variables that will be used are guaranteed to be
+ %% defined.
+ case Br of
+ #b_br{bool=#b_literal{val=true},succ=L} ->
+ %% This is a one-way branch.
+ case Target of
+ any ->
+ %% No forced target. Success!
+ {Br,Bs,UnsetVars};
+ one_way ->
+ %% The target must be a one-way branch, which this
+ %% `br` is. Success!
+ {Br,Bs,UnsetVars};
+ L when is_integer(Target) ->
+ %% The forced target is L. Success!
+ {Br,Bs,UnsetVars};
+ _ when is_integer(Target) ->
+ %% Wrong forced target. Try following this branch
+ %% to see if it ultimately ends up at the forced
+ %% target.
+ shortcut_2(L, From, Bs, UnsetVars, St)
+ end;
+ #b_br{bool=#b_var{}} ->
+ %% This is a two-way branch.
+ if
+ Target =:= any; Target =:= one_way ->
+ %% No specific forced target. Try to reduce the
+ %% two-way branch to an one-way branch.
+ case shortcut_two_way(Br, From, Bs, UnsetVars, St) of
+ none when Target =:= any ->
+ %% This `br` can't be reduced to a one-way
+ %% branch. Return the `br` as-is.
+ {Br,Bs,UnsetVars};
+ none when Target =:= one_way ->
+ %% This `br` can't be reduced to a one-way
+ %% branch. The caller wants a one-way
+ %% branch. Give up.
+ none;
+ {_,_,_}=Res ->
+ %% This `br` was successfully reduced to a
+ %% one-way branch.
+ Res
+ end;
+ is_integer(Target) ->
+ %% There is a forced target, which can't
+ %% be reached because this `br` is a two-way
+ %% branch. Give up.
+ none
+ end
+ end.
+
+update_unset_vars(L, Is, Br, UnsetVars, #st{skippable=Skippable}) ->
+ case is_map_key(L, Skippable) of
+ true ->
+ %% None of the variables used in this block are used in
+ %% the successors. Thus, there is no need to add the
+ %% variables to the set of unset variables.
+ case Br of
+ #b_br{bool=#b_var{}=Bool} ->
+ case keymember(Bool, #b_set.dst, Is) of
+ true ->
+ %% Bool is a variable defined in this
+ %% block. Using the br instruction from
+ %% this block (and skipping the body of
+ %% the block) is unsafe.
+ unsafe;
+ false ->
+ %% Bool is either a variable not defined
+ %% in this block or a literal. Adding it
+ %% to the UnsetVars set would not change
+ %% the outcome of the tests in
+ %% is_br_safe/2.
+ UnsetVars
+ end;
+ #b_br{} ->
+ UnsetVars
+ end;
+ false ->
+ %% Some variables defined in this block are used by
+ %% successors. We must update the set of unset variables.
+ SetInThisBlock = [V || #b_set{dst=V} <- Is],
+ ordsets:union(UnsetVars, ordsets:from_list(SetInThisBlock))
+ end.
+
+shortcut_two_way(#b_br{succ=Succ,fail=Fail}, From, Bs0, UnsetVars0, St0) ->
+ case shortcut_2(Succ, From, Bs0, UnsetVars0, St0#st{target=Fail}) of
+ {#b_br{bool=#b_literal{},succ=Fail},_,_}=Res ->
+ Res;
+ none ->
+ St = St0#st{target=Succ},
+ case shortcut_2(Fail, From, Bs0, UnsetVars0, St) of
+ {#b_br{bool=#b_literal{},succ=Succ},_,_}=Res ->
+ Res;
+ none ->
+ none
+ end
+ end.
+
+get_block(L, St) ->
+ #st{bs=#{L:=Blk}} = St,
+ Blk.
+
+is_br_safe(UnsetVars, Br, #st{us=Us}=St) ->
+ %% Check that none of the unset variables will be used.
+ case Br of
+ #b_br{bool=#b_var{}=V,succ=Succ,fail=Fail} ->
+ #{Succ:=Used0,Fail:=Used1} = Us,
+
+ %% A two-way branch never branches to a phi node, so there
+ %% is no need to check for phi nodes here.
+ not member(V, UnsetVars) andalso
+ ordsets:is_disjoint(Used0, UnsetVars) andalso
+ ordsets:is_disjoint(Used1, UnsetVars);
+ #b_br{succ=Same,fail=Same} ->
+ %% An unconditional branch must not jump to
+ %% a phi node.
+ not is_forbidden(Same, St) andalso
+ ordsets:is_disjoint(map_get(Same, Us), UnsetVars)
+ end.
+
+is_forbidden(L, St) ->
+ case get_block(L, St) of
+ #b_blk{is=[#b_set{op=phi}|_]} -> true;
+ #b_blk{is=[#b_set{op=peek_message}|_]} -> true;
+ #b_blk{} -> false
+ end.
+
+
+%% Evaluate the instructions in the block.
+%% Return the updated bindings, or 'none' if there is
+%% any instruction with potential side effects.
+
+eval_is([#b_set{op=phi,dst=Dst,args=Args}|Is], From, Bs0, St) ->
+ Val = get_phi_arg(Args, From),
+ Bs = bind_var(Dst, Val, Bs0),
+ eval_is(Is, From, Bs, St);
+eval_is([#b_set{op={bif,_},dst=Dst}=I0|Is], From, Bs, St) ->
+ I = sub(I0, Bs),
+ case eval_bif(I, St) of
+ #b_literal{}=Val ->
+ eval_is(Is, From, bind_var(Dst, Val, Bs), St);
+ none ->
+ eval_is(Is, From, Bs, St)
+ end;
+eval_is([#b_set{op=Op,dst=Dst}=I|Is], From, Bs, St)
+ when Op =:= is_tagged_tuple; Op =:= is_nonempty_list ->
+ #b_set{args=Args} = sub(I, Bs),
+ case eval_rel_op(Op, Args, St) of
+ #b_literal{}=Val ->
+ eval_is(Is, From, bind_var(Dst, Val, Bs), St);
+ none ->
+ eval_is(Is, From, Bs, St)
+ end;
+eval_is([#b_set{}=I|Is], From, Bs, St) ->
+ case beam_ssa:no_side_effect(I) of
+ true ->
+ %% This instruction has no side effects. It can
+ %% safely be omitted.
+ eval_is(Is, From, Bs, St);
+ false ->
+ %% This instruction may have some side effect.
+ %% It is not safe to avoid this instruction.
+ none
+ end;
+eval_is([], _From, Bs, _St) -> Bs.
+
+get_phi_arg([{Val,From}|_], From) -> Val;
+get_phi_arg([_|As], From) -> get_phi_arg(As, From).
+
+eval_terminator(#b_br{bool=#b_var{}=Bool}=Br, Bs, _St) ->
+ Val = get_value(Bool, Bs),
+ beam_ssa:normalize(Br#b_br{bool=Val});
+eval_terminator(#b_br{bool=#b_literal{}}=Br, _Bs, _St) ->
+ beam_ssa:normalize(Br);
+eval_terminator(#b_switch{arg=Arg,fail=Fail,list=List}=Sw, Bs, St) ->
+ case get_value(Arg, Bs) of
+ #b_literal{}=Val ->
+ %% Literal argument. Simplify to a `br`.
+ beam_ssa:normalize(Sw#b_switch{arg=Val});
+ #b_var{} ->
+ %% Try optimizing the switch.
+ case eval_switch(List, Arg, St, Fail) of
+ none ->
+ none;
+ To when is_integer(To) ->
+ %% Either one of the values in the switch
+ %% matched a previous value in a '=:=' test, or
+ %% none of the values matched a previous test.
+ #b_br{bool=#b_literal{val=true},succ=To,fail=To}
+ end
+ end;
+eval_terminator(#b_ret{}, _Bs, _St) ->
+ none.
+
+eval_switch(List, Arg, #st{rel_op={_,Arg,_}=PrevOp}, Fail) ->
+ %% There is a previous relational operator testing the same variable.
+ %% Optimization may be possible.
+ eval_switch_1(List, Arg, PrevOp, Fail);
+eval_switch(_, _, _, _) ->
+ %% There is either no previous relational operator, or it tests
+ %% a different variable. Nothing to optimize.
+ none.
+
+eval_switch_1([{Lit,Lbl}|T], Arg, PrevOp, Fail) ->
+ RelOp = {'=:=',Arg,Lit},
+ case will_succeed(PrevOp, RelOp) of
+ yes ->
+ %% Success. This branch will always be taken.
+ Lbl;
+ no ->
+ %% This branch will never be taken.
+ eval_switch_1(T, Arg, PrevOp, Fail);
+ maybe ->
+ %% This label could be reached.
+ eval_switch_1(T, Arg, PrevOp, none)
+ end;
+eval_switch_1([], _Arg, _PrevOp, Fail) ->
+ %% Fail is now either the failure label or 'none'.
+ Fail.
+
+bind_var(Var, Val0, Bs) ->
+ Val = get_value(Val0, Bs),
+ Bs#{Var=>Val}.
+
+get_value(#b_var{}=Var, Bs) ->
+ case Bs of
+ #{Var:=Val} -> get_value(Val, Bs);
+ #{} -> Var
+ end;
+get_value(#b_literal{}=Lit, _Bs) -> Lit.
+
+eval_bif(#b_set{op={bif,Bif},args=Args}, St) ->
+ Arity = length(Args),
+ case erl_bifs:is_pure(erlang, Bif, Arity) of
+ false ->
+ none;
+ true ->
+ case get_lit_args(Args) of
+ none ->
+ %% Not literal arguments. Try to evaluate
+ %% it based on a previous relational operator.
+ eval_rel_op({bif,Bif}, Args, St);
+ LitArgs ->
+ try apply(erlang, Bif, LitArgs) of
+ Val -> #b_literal{val=Val}
+ catch
+ error:_ -> none
+ end
+ end
+ end.
+
+get_lit_args([#b_literal{val=Lit1}]) ->
+ [Lit1];
+get_lit_args([#b_literal{val=Lit1},
+ #b_literal{val=Lit2}]) ->
+ [Lit1,Lit2];
+get_lit_args([#b_literal{val=Lit1},
+ #b_literal{val=Lit2},
+ #b_literal{val=Lit3}]) ->
+ [Lit1,Lit2,Lit3];
+get_lit_args(_) -> none.
+
+%%%
+%%% Handling of relational operators.
+%%%
+
+get_rel_op(Bool, [_|_]=Is) ->
+ case last(Is) of
+ #b_set{op=Op,dst=Bool,args=Args} ->
+ normalize_op(Op, Args);
+ #b_set{} ->
+ none
+ end;
+get_rel_op(_, []) -> none.
+
+%% normalize_op(Instruction) -> {Normalized,FailLabel} | error
+%% Normalized = {Operator,Variable,Variable|Literal} |
+%% {TypeTest,Variable}
+%% Operation = '<' | '=<' | '=:=' | '=/=' | '>=' | '>'
+%% TypeTest = is_atom | is_integer ...
+%% Variable = #b_var{}
+%% Literal = #b_literal{}
+%%
+%% Normalize a relational operator to facilitate further
+%% comparisons between operators. Always make the register
+%% operand the first operand. If there are two registers,
+%% order the registers in lexical order.
+%%
+%% For example, this instruction:
+%%
+%% #b_set{op={bif,=<},args=[#b_literal{}, #b_var{}}
+%%
+%% will be normalized to:
+%%
+%% {'=<',#b_var{},#b_literal{}}
+
+-spec normalize_op(Op, Args) -> NormalizedOp | 'none' when
+ Op :: beam_ssa:op(),
+ Args :: [beam_ssa:value()],
+ NormalizedOp :: basic_rel_op().
+
+normalize_op(is_tagged_tuple, [Arg,#b_literal{val=Size},#b_literal{val=Tag}])
+ when is_integer(Size), is_atom(Tag) ->
+ {{is_tagged_tuple,Size,Tag},Arg};
+normalize_op(is_nonempty_list, [Arg]) ->
+ {is_nonempty_list,Arg};
+normalize_op({bif,Bif}, [Arg]) ->
+ case erl_internal:new_type_test(Bif, 1) of
+ true -> {Bif,Arg};
+ false -> none
+ end;
+normalize_op({bif,Bif}, [_,_]=Args) ->
+ case erl_internal:comp_op(Bif, 2) of
+ true ->
+ normalize_op_1(Bif, Args);
+ false ->
+ none
+ end;
+normalize_op(_, _) -> none.
+
+normalize_op_1(Bif, Args) ->
+ case Args of
+ [#b_literal{}=Arg1,#b_var{}=Arg2] ->
+ {turn_op(Bif),Arg2,Arg1};
+ [#b_var{}=Arg1,#b_literal{}=Arg2] ->
+ {Bif,Arg1,Arg2};
+ [#b_var{}=A,#b_var{}=B] ->
+ if A < B -> {Bif,A,B};
+ true -> {turn_op(Bif),B,A}
+ end;
+ [#b_literal{},#b_literal{}] ->
+ none
+ end.
+
+-spec invert_op(basic_rel_op() | 'none') -> rel_op() | 'none'.
+
+invert_op({Op,Arg1,Arg2}) ->
+ {invert_op_1(Op),Arg1,Arg2};
+invert_op({TypeTest,Arg}) ->
+ {{'not',TypeTest},Arg};
+invert_op(none) -> none.
+
+invert_op_1('>=') -> '<';
+invert_op_1('<') -> '>=';
+invert_op_1('=<') -> '>';
+invert_op_1('>') -> '=<';
+invert_op_1('=:=') -> '=/=';
+invert_op_1('=/=') -> '=:=';
+invert_op_1('==') -> '/=';
+invert_op_1('/=') -> '=='.
+
+turn_op('<') -> '>';
+turn_op('=<') -> '>=';
+turn_op('>') -> '<';
+turn_op('>=') -> '=<';
+turn_op('=:='=Op) -> Op;
+turn_op('=/='=Op) -> Op;
+turn_op('=='=Op) -> Op;
+turn_op('/='=Op) -> Op.
+
+eval_rel_op(_Bif, _Args, #st{rel_op=none}) ->
+ none;
+eval_rel_op(Bif, Args, #st{rel_op=Prev}) ->
+ case normalize_op(Bif, Args) of
+ none ->
+ none;
+ RelOp ->
+ case will_succeed(Prev, RelOp) of
+ yes -> #b_literal{val=true};
+ no -> #b_literal{val=false};
+ maybe -> none
+ end
+ end.
+
+%% will_succeed(PrevCondition, Condition) -> yes | no | maybe
+%% PrevCondition is a condition known to be true. This function
+%% will tell whether Condition will succeed.
+
+will_succeed({_Op,_Var,_Value}=Same, {_Op,_Var,_Value}=Same) ->
+ %% Repeated test.
+ yes;
+will_succeed({Op1,Var,#b_literal{val=A}}, {Op2,Var,#b_literal{val=B}}) ->
+ will_succeed_1(Op1, A, Op2, B);
+will_succeed({Op1,Var,#b_var{}=A}, {Op2,Var,#b_var{}=B}) ->
+ will_succeed_vars(Op1, A, Op2, B);
+will_succeed({'=:=',Var,#b_literal{val=A}}, {TypeTest,Var}) ->
+ eval_type_test(TypeTest, A);
+will_succeed({_,_}=Same, {_,_}=Same) ->
+ %% Repeated type test.
+ yes;
+will_succeed({Test1,Var}, {Test2,Var}) ->
+ will_succeed_test(Test1, Test2);
+will_succeed({_,_}, {_,_}) ->
+ maybe;
+will_succeed({_,_}, {_,_,_}) ->
+ maybe;
+will_succeed({_,_,_}, {_,_}) ->
+ maybe;
+will_succeed({_,_,_}, {_,_,_}) ->
+ maybe.
+
+will_succeed_test({'not',Test1}, Test2) ->
+ case Test1 =:= Test2 of
+ true -> no;
+ false -> maybe
+ end;
+will_succeed_test(is_tuple, {is_tagged_tuple,_,_}) ->
+ maybe;
+will_succeed_test({is_tagged_tuple,_,_}, is_tuple) ->
+ yes;
+will_succeed_test(is_list, is_nonempty_list) ->
+ maybe;
+will_succeed_test(is_nonempty_list, is_list) ->
+ yes;
+will_succeed_test(T1, T2) ->
+ case is_numeric_test(T1) andalso is_numeric_test(T2) of
+ true -> maybe;
+ false -> no
+ end.
+
+will_succeed_1('=:=', A, '<', B) ->
+ if
+ B =< A -> no;
+ true -> yes
+ end;
+will_succeed_1('=:=', A, '=<', B) ->
+ if
+ B < A -> no;
+ true -> yes
+ end;
+will_succeed_1('=:=', A, '=:=', B) when A =/= B ->
+ no;
+will_succeed_1('=:=', A, '=/=', B) ->
+ if
+ A =:= B -> no;
+ true -> yes
+ end;
+will_succeed_1('=:=', A, '>=', B) ->
+ if
+ B > A -> no;
+ true -> yes
+ end;
+will_succeed_1('=:=', A, '>', B) ->
+ if
+ B >= A -> no;
+ true -> yes
+ end;
+
+will_succeed_1('=/=', A, '=:=', B) when A =:= B -> no;
+
+will_succeed_1('<', A, '=:=', B) when B >= A -> no;
+will_succeed_1('<', A, '=/=', B) when B >= A -> yes;
+will_succeed_1('<', A, '<', B) when B >= A -> yes;
+will_succeed_1('<', A, '=<', B) when B > A -> yes;
+will_succeed_1('<', A, '>=', B) when B > A -> no;
+will_succeed_1('<', A, '>', B) when B >= A -> no;
+
+will_succeed_1('=<', A, '=:=', B) when B > A -> no;
+will_succeed_1('=<', A, '=/=', B) when B > A -> yes;
+will_succeed_1('=<', A, '<', B) when B > A -> yes;
+will_succeed_1('=<', A, '=<', B) when B >= A -> yes;
+will_succeed_1('=<', A, '>=', B) when B > A -> no;
+will_succeed_1('=<', A, '>', B) when B >= A -> no;
+
+will_succeed_1('>=', A, '=:=', B) when B < A -> no;
+will_succeed_1('>=', A, '=/=', B) when B < A -> yes;
+will_succeed_1('>=', A, '<', B) when B =< A -> no;
+will_succeed_1('>=', A, '=<', B) when B < A -> no;
+will_succeed_1('>=', A, '>=', B) when B =< A -> yes;
+will_succeed_1('>=', A, '>', B) when B < A -> yes;
+
+will_succeed_1('>', A, '=:=', B) when B =< A -> no;
+will_succeed_1('>', A, '=/=', B) when B =< A -> yes;
+will_succeed_1('>', A, '<', B) when B =< A -> no;
+will_succeed_1('>', A, '=<', B) when B < A -> no;
+will_succeed_1('>', A, '>=', B) when B =< A -> yes;
+will_succeed_1('>', A, '>', B) when B < A -> yes;
+
+will_succeed_1('==', A, '==', B) ->
+ if
+ A == B -> yes;
+ true -> no
+ end;
+will_succeed_1('==', A, '/=', B) ->
+ if
+ A == B -> no;
+ true -> yes
+ end;
+will_succeed_1('/=', A, '/=', B) when A == B -> yes;
+will_succeed_1('/=', A, '==', B) when A == B -> no;
+
+will_succeed_1(_, _, _, _) -> maybe.
+
+will_succeed_vars('=/=', Val, '=:=', Val) -> no;
+will_succeed_vars('=:=', Val, '=/=', Val) -> no;
+will_succeed_vars('=:=', Val, '>=', Val) -> yes;
+will_succeed_vars('=:=', Val, '=<', Val) -> yes;
+
+will_succeed_vars('/=', Val1, '==', Val2) when Val1 == Val2 -> no;
+will_succeed_vars('==', Val1, '/=', Val2) when Val1 == Val2 -> no;
+
+will_succeed_vars(_, _, _, _) -> maybe.
+
+is_numeric_test(is_float) -> true;
+is_numeric_test(is_integer) -> true;
+is_numeric_test(is_number) -> true;
+is_numeric_test(_) -> false.
+
+eval_type_test(Test, Arg) ->
+ case eval_type_test_1(Test, Arg) of
+ true -> yes;
+ false -> no
+ end.
+
+eval_type_test_1(is_nonempty_list, Arg) ->
+ case Arg of
+ [_|_] -> true;
+ _ -> false
+ end;
+eval_type_test_1({is_tagged_tuple,Sz,Tag}, Arg) ->
+ if
+ tuple_size(Arg) =:= Sz, element(1, Arg) =:= Tag ->
+ true;
+ true ->
+ false
+ end;
+eval_type_test_1(Test, Arg) ->
+ erlang:Test(Arg).
+
+%%%
+%%% Combine bif:'=:=' and switch instructions
+%%% to switch instructions.
+%%%
+%%% Consider this code:
+%%%
+%%% 0:
+%%% @ssa_bool = bif:'=:=' Var, literal 1
+%%% br @ssa_bool, label 2, label 3
+%%%
+%%% 2:
+%%% ret literal a
+%%%
+%%% 3:
+%%% @ssa_bool:7 = bif:'=:=' Var, literal 2
+%%% br @ssa_bool:7, label 4, label 999
+%%%
+%%% 4:
+%%% ret literal b
+%%%
+%%% 999:
+%%% .
+%%% .
+%%% .
+%%%
+%%% The two bif:'=:=' instructions can be combined
+%%% to a switch:
+%%%
+%%% 0:
+%%% switch Var, label 999, [ { literal 1, label 2 },
+%%% { literal 2, label 3 } ]
+%%%
+%%% 2:
+%%% ret literal a
+%%%
+%%% 4:
+%%% ret literal b
+%%%
+%%% 999:
+%%% .
+%%% .
+%%% .
+%%%
+
+combine_eqs(#st{bs=Blocks}=St) ->
+ Ls = reverse(beam_ssa:rpo(Blocks)),
+ combine_eqs_1(Ls, St).
+
+combine_eqs_1([L|Ls], #st{bs=Blocks0}=St0) ->
+ case comb_get_sw(L, St0) of
+ none ->
+ combine_eqs_1(Ls, St0);
+ {_,Arg,_,Fail0,List0} ->
+ case comb_get_sw(Fail0, St0) of
+ {true,Arg,Fail1,Fail,List1} ->
+ %% Another switch/br with the same arguments was
+ %% found. Try combining them.
+ case combine_lists(Fail1, List0, List1, Blocks0) of
+ none ->
+ %% Different types of literals in the lists,
+ %% or the success cases in the first switch
+ %% could branch to the second switch
+ %% (increasing code size and repeating tests).
+ combine_eqs_1(Ls, St0);
+ List ->
+ %% Everything OK! Combine the lists.
+ Sw0 = #b_switch{arg=Arg,fail=Fail,list=List},
+ Sw = beam_ssa:normalize(Sw0),
+ Blk0 = map_get(L, Blocks0),
+ Blk = Blk0#b_blk{last=Sw},
+ Blocks = Blocks0#{L:=Blk},
+ St = St0#st{bs=Blocks},
+ combine_eqs_1(Ls, St)
+ end;
+ {true,_OtherArg,_,_,_} ->
+ %% The other switch/br uses a different Arg.
+ combine_eqs_1(Ls, St0);
+ {false,_,_,_,_} ->
+ %% Not safe: Bindings of variables that will be used
+ %% or execution of instructions with potential
+ %% side effects will be skipped.
+ combine_eqs_1(Ls, St0);
+ none ->
+ %% No switch/br at this label.
+ combine_eqs_1(Ls, St0)
+ end
+ end;
+combine_eqs_1([], St) -> St.
+
+comb_get_sw(L, Blocks) ->
+ comb_get_sw(L, true, Blocks).
+
+comb_get_sw(L, Safe0, #st{bs=Blocks,skippable=Skippable}) ->
+ #b_blk{is=Is,last=Last} = map_get(L, Blocks),
+ Safe1 = Safe0 andalso is_map_key(L, Skippable),
+ case Last of
+ #b_ret{} ->
+ none;
+ #b_br{bool=#b_var{}=Bool,succ=Succ,fail=Fail} ->
+ case comb_is(Is, Bool, Safe1) of
+ {none,_} ->
+ none;
+ {#b_set{op={bif,'=:='},args=[#b_var{}=Arg,#b_literal{}=Lit]},Safe} ->
+ {Safe,Arg,L,Fail,[{Lit,Succ}]};
+ {#b_set{},_} ->
+ none
+ end;
+ #b_br{} ->
+ none;
+ #b_switch{arg=#b_var{}=Arg,fail=Fail,list=List} ->
+ {none,Safe} = comb_is(Is, none, Safe1),
+ {Safe,Arg,L,Fail,List}
+ end.
+
+comb_is([#b_set{dst=#b_var{}=Bool}=I], Bool, Safe) ->
+ {I,Safe};
+comb_is([#b_set{}=I|Is], Bool, Safe0) ->
+ Safe = Safe0 andalso beam_ssa:no_side_effect(I),
+ comb_is(Is, Bool, Safe);
+comb_is([], _Bool, Safe) ->
+ {none,Safe}.
+
+%% combine_list(Fail, List1, List2, Blocks) -> List|none.
+%% Try to combine two switch lists, returning the combined
+%% list or 'none' if not possible.
+%%
+%% The values in the two lists must be all of the same type.
+%%
+%% The code reached from the labels in the first list must
+%% not reach the failure label (if they do, tests could
+%% be repeated).
+%%
+
+combine_lists(Fail, L1, L2, Blocks) ->
+ Ls = beam_ssa:rpo([Lbl || {_,Lbl} <- L1], Blocks),
+ case member(Fail, Ls) of
+ true ->
+ %% One or more of labels in the first list
+ %% could reach the failure label. That
+ %% means that the second switch/br instruction
+ %% will be retained, increasing code size and
+ %% potentially also execution time.
+ none;
+ false ->
+ %% The combined switch will replace both original
+ %% br/switch instructions, leading to a reduction in code
+ %% size and potentially also in execution time.
+ combine_lists_1(L1, L2)
+ end.
+
+combine_lists_1(List0, List1) ->
+ case are_lists_compatible(List0, List1) of
+ true ->
+ First = maps:from_list(List0),
+ List0 ++ [{Val,Lbl} || {Val,Lbl} <- List1,
+ not is_map_key(Val, First)];
+ false ->
+ none
+ end.
+
+are_lists_compatible([{#b_literal{val=Val1},_}|_],
+ [{#b_literal{val=Val2},_}|_]) ->
+ case lit_type(Val1) of
+ none -> false;
+ Type -> Type =:= lit_type(Val2)
+ end.
+
+lit_type(Val) ->
+ if
+ is_atom(Val) -> atom;
+ is_float(Val) -> float;
+ is_integer(Val) -> integer;
+ true -> none
+ end.
+
+%%%
+%%% Calculate used variables for each block.
+%%%
+
+used_vars(Linear) ->
+ used_vars(reverse(Linear), #{}, #{}).
+
+used_vars([{L,#b_blk{is=Is}=Blk}|Bs], UsedVars0, Skip0) ->
+ %% Calculate the variables used by each block and its
+ %% successors. This information is used by
+ %% shortcut_opt/1.
+
+ Successors = beam_ssa:successors(Blk),
+ Used0 = used_vars_succ(Successors, L, UsedVars0, []),
+ Used = used_vars_blk(Blk, Used0),
+ UsedVars = used_vars_phis(Is, L, Used, UsedVars0),
+
+ %% combine_eqs/1 needs different variable usage information than
+ %% shortcut_opt/1. The Skip map will have an entry for each block
+ %% that can be skipped (does not bind any variable used in
+ %% successor). This information is also useful for speeding up
+ %% shortcut_opt/1.
+
+ Defined0 = [Def || #b_set{dst=Def} <- Is],
+ Defined = ordsets:from_list(Defined0),
+ MaySkip = ordsets:is_disjoint(Defined, Used0),
+ case MaySkip of
+ true ->
+ Skip = Skip0#{L=>true},
+ used_vars(Bs, UsedVars, Skip);
+ false ->
+ used_vars(Bs, UsedVars, Skip0)
+ end;
+used_vars([], UsedVars, Skip) ->
+ {UsedVars,Skip}.
+
+used_vars_succ([S|Ss], L, LiveMap, Live0) ->
+ Key = {S,L},
+ case LiveMap of
+ #{Key:=Live} ->
+ %% The successor has a phi node, and the value for
+ %% this block in the phi node is a variable.
+ used_vars_succ(Ss, L, LiveMap, ordsets:union(Live, Live0));
+ #{S:=Live} ->
+ %% No phi node in the successor, or the value for
+ %% this block in the phi node is a literal.
+ used_vars_succ(Ss, L, LiveMap, ordsets:union(Live, Live0));
+ #{} ->
+ %% A peek_message block which has not been processed yet.
+ used_vars_succ(Ss, L, LiveMap, Live0)
+ end;
+used_vars_succ([], _, _, Acc) -> Acc.
+
+used_vars_phis(Is, L, Live0, UsedVars0) ->
+ UsedVars = UsedVars0#{L=>Live0},
+ Phis = takewhile(fun(#b_set{op=Op}) -> Op =:= phi end, Is),
+ case Phis of
+ [] ->
+ UsedVars;
+ [_|_] ->
+ PhiArgs = append([Args || #b_set{args=Args} <- Phis]),
+ case [{P,V} || {#b_var{}=V,P} <- PhiArgs] of
+ [_|_]=PhiVars ->
+ PhiLive0 = rel2fam(PhiVars),
+ PhiLive = [{{L,P},ordsets:union(ordsets:from_list(Vs), Live0)} ||
+ {P,Vs} <- PhiLive0],
+ maps:merge(UsedVars, maps:from_list(PhiLive));
+ [] ->
+ %% There were only literals in the phi node(s).
+ UsedVars
+ end
+ end.
+
+used_vars_blk(#b_blk{is=Is,last=Last}, Used0) ->
+ Used = ordsets:union(Used0, beam_ssa:used(Last)),
+ used_vars_is(reverse(Is), Used).
+
+used_vars_is([#b_set{op=phi}|Is], Used) ->
+ used_vars_is(Is, Used);
+used_vars_is([#b_set{dst=Dst}=I|Is], Used0) ->
+ Used1 = ordsets:union(Used0, beam_ssa:used(I)),
+ Used = ordsets:del_element(Dst, Used1),
+ used_vars_is(Is, Used);
+used_vars_is([], Used) ->
+ Used.
+
+%%%
+%%% Common utilities.
+%%%
+
+sub(#b_set{args=Args}=I, Sub) ->
+ I#b_set{args=[sub_arg(A, Sub) || A <- Args]}.
+
+sub_arg(#b_var{}=Old, Sub) ->
+ case Sub of
+ #{Old:=New} -> New;
+ #{} -> Old
+ end;
+sub_arg(Old, _Sub) -> Old.
+
+rel2fam(S0) ->
+ S1 = sofs:relation(S0),
+ S = sofs:rel2fam(S1),
+ sofs:to_external(S).
diff --git a/lib/compiler/src/beam_ssa_funs.erl b/lib/compiler/src/beam_ssa_funs.erl
new file mode 100644
index 0000000000..e77c00fa89
--- /dev/null
+++ b/lib/compiler/src/beam_ssa_funs.erl
@@ -0,0 +1,149 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%%
+%%% If a fun is defined locally and only used for calls, it can be replaced
+%%% with direct calls to the relevant function. This greatly speeds up "named
+%%% functions" (which rely on make_fun to recreate themselves) and macros that
+%%% wrap their body in a fun.
+%%%
+
+-module(beam_ssa_funs).
+
+-export([module/2]).
+
+-include("beam_ssa.hrl").
+
+-import(lists, [foldl/3]).
+
+-spec module(Module, Options) -> Result when
+ Module :: beam_ssa:b_module(),
+ Options :: [compile:option()],
+ Result :: {ok, beam_ssa:b_module()}.
+
+module(#b_module{body=Fs0}=Module, _Opts) ->
+ Trampolines = foldl(fun find_trampolines/2, #{}, Fs0),
+ Fs = [lfo(F, Trampolines) || F <- Fs0],
+ {ok, Module#b_module{body=Fs}}.
+
+%% If a function does absolutely nothing beyond calling another function with
+%% the same arguments in the same order, we can shave off a call by short-
+%% circuiting it.
+find_trampolines(#b_function{args=Args,bs=Blocks}=F, Trampolines) ->
+ case map_get(0, Blocks) of
+ #b_blk{is=[#b_set{op=call,
+ args=[#b_local{}=Actual | Args],
+ dst=Dst}],
+ last=#b_ret{arg=Dst}} ->
+ {_, Name, Arity} = beam_ssa:get_anno(func_info, F),
+ Trampoline = #b_local{name=#b_literal{val=Name},arity=Arity},
+ Trampolines#{Trampoline => Actual};
+ _ ->
+ Trampolines
+ end.
+
+lfo(#b_function{bs=Blocks0}=F, Trampolines) ->
+ Linear0 = beam_ssa:linearize(Blocks0),
+ Linear = lfo_optimize(Linear0, lfo_analyze(Linear0, #{}), Trampolines),
+ F#b_function{bs=maps:from_list(Linear)}.
+
+%% Gather a map of the locally defined funs that are only used for calls.
+lfo_analyze([{_L,#b_blk{is=Is,last=Last}}|Bs], LFuns0) ->
+ LFuns = lfo_analyze_last(Last, lfo_analyze_is(Is, LFuns0)),
+ lfo_analyze(Bs, LFuns);
+lfo_analyze([], LFuns) ->
+ LFuns.
+
+lfo_analyze_is([#b_set{op=make_fun,
+ dst=Dst,
+ args=[#b_local{} | FreeVars]}=Def | Is],
+ LFuns0) ->
+ LFuns = maps:put(Dst, Def, maps:without(FreeVars, LFuns0)),
+ lfo_analyze_is(Is, LFuns);
+lfo_analyze_is([#b_set{op=call,
+ args=[Fun | CallArgs]} | Is],
+ LFuns) when is_map_key(Fun, LFuns) ->
+ #b_set{args=[#b_local{arity=Arity} | FreeVars]} = map_get(Fun, LFuns),
+ case length(CallArgs) + length(FreeVars) of
+ Arity ->
+ lfo_analyze_is(Is, maps:without(CallArgs, LFuns));
+ _ ->
+ %% This will `badarity` at runtime, and it's easier to disable the
+ %% optimization than to simulate it.
+ lfo_analyze_is(Is, maps:without([Fun | CallArgs], LFuns))
+ end;
+lfo_analyze_is([#b_set{args=Args} | Is], LFuns) when map_size(LFuns) =/= 0 ->
+ %% We disqualify funs that are used outside calls because this forces them
+ %% to be created anyway, and the slight performance gain from direct calls
+ %% is not enough to offset the potential increase in stack frame size (the
+ %% free variables need to be kept alive until the call).
+ %%
+ %% This is also a kludge to make HiPE work, as the latter will generate
+ %% code with the assumption that the functions referenced in a make_fun
+ %% will only be used by funs, which will not be the case if we mix it with
+ %% direct calls. See cerl_cconv.erl for details.
+ %%
+ %% Future optimizations like delaying fun creation until use may require us
+ %% to copy affected functions so that HiPE gets its own to play with (until
+ %% HiPE is fixed anyway).
+ lfo_analyze_is(Is, maps:without(Args, LFuns));
+lfo_analyze_is([_ | Is], LFuns) ->
+ lfo_analyze_is(Is, LFuns);
+lfo_analyze_is([], LFuns) ->
+ LFuns.
+
+lfo_analyze_last(#b_switch{arg=Arg}, LFuns) ->
+ maps:remove(Arg, LFuns);
+lfo_analyze_last(#b_ret{arg=Arg}, LFuns) ->
+ maps:remove(Arg, LFuns);
+lfo_analyze_last(_, LFuns) ->
+ LFuns.
+
+%% Replace all calls of suitable funs with a direct call to their
+%% implementation. Liveness optimization will get rid of the make_fun
+%% instruction.
+lfo_optimize(Linear, LFuns, _Trampolines) when map_size(LFuns) =:= 0 ->
+ Linear;
+lfo_optimize(Linear, LFuns, Trampolines) ->
+ lfo_optimize_1(Linear, LFuns, Trampolines).
+
+lfo_optimize_1([{L,#b_blk{is=Is0}=Blk}|Bs], LFuns, Trampolines) ->
+ Is = lfo_optimize_is(Is0, LFuns, Trampolines),
+ [{L,Blk#b_blk{is=Is}} | lfo_optimize_1(Bs, LFuns, Trampolines)];
+lfo_optimize_1([], _LFuns, _Trampolines) ->
+ [].
+
+lfo_optimize_is([#b_set{op=call,
+ args=[Fun | CallArgs]}=Call0 | Is],
+ LFuns, Trampolines) when is_map_key(Fun, LFuns) ->
+ #b_set{args=[Local | FreeVars]} = map_get(Fun, LFuns),
+ Args = [lfo_short_circuit(Local, Trampolines) | CallArgs ++ FreeVars],
+ Call = beam_ssa:add_anno(local_fun_opt, Fun, Call0#b_set{args=Args}),
+ [Call | lfo_optimize_is(Is, LFuns, Trampolines)];
+lfo_optimize_is([I | Is], LFuns, Trampolines) ->
+ [I | lfo_optimize_is(Is, LFuns, Trampolines)];
+lfo_optimize_is([], _LFuns, _Trampolines) ->
+ [].
+
+lfo_short_circuit(Call, Trampolines) ->
+ case maps:find(Call, Trampolines) of
+ {ok, Other} -> lfo_short_circuit(Other, Trampolines);
+ error -> Call
+ end.
diff --git a/lib/compiler/src/beam_ssa_lint.erl b/lib/compiler/src/beam_ssa_lint.erl
new file mode 100644
index 0000000000..a003607dab
--- /dev/null
+++ b/lib/compiler/src/beam_ssa_lint.erl
@@ -0,0 +1,349 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% Purpose: Internal consistency checks for the beam_ssa format.
+
+-module(beam_ssa_lint).
+
+-export([module/2, format_error/1]).
+
+-import(lists, [append/1, foldl/3, foreach/2]).
+
+-include("beam_ssa.hrl").
+
+-spec module(#b_module{}, [compile:option()]) ->
+ {'ok',#b_module{}} | {'error',list()}.
+module(#b_module{body=Fs,name=Name}=Mod0, _Options) ->
+ Es0 = append([validate_function(F) || F <- Fs]),
+ case [{?MODULE,E} || E <- Es0] of
+ [] ->
+ {ok, Mod0};
+ [_|_]=Es ->
+ {error,[{atom_to_list(Name), Es}]}
+ end.
+
+-spec format_error(term()) -> iolist().
+format_error({{_M,F,A},{redefined_variable, Name, Old, I}}) ->
+ io_lib:format("~p/~p: Variable ~ts (~ts) redefined by ~ts",
+ [F, A, format_var(Name), format_instr(Old), format_instr(I)]);
+format_error({{_M,F,A},{missing_phi_paths, Paths, I}}) ->
+ io_lib:format("~p/~p: Phi node ~ts doesn't define a value for these "
+ "branches: ~w",
+ [F, A, format_instr(I), Paths]);
+format_error({{_M,F,A},{garbage_phi_paths, Paths, I}}) ->
+ io_lib:format("~p/~p: Phi node ~ts defines a value for these unreachable "
+ "or non-existent branches: ~w",
+ [F, A, format_instr(I), Paths]);
+format_error({{_M,F,A},{unknown_phi_variable, Name, {From, _To}, I}}) ->
+ io_lib:format("~p/~p: Variable ~ts used in phi node ~ts is undefined on "
+ "branch ~w",
+ [F, A, format_var(Name), format_instr(I), From]);
+format_error({{_M,F,A},{unknown_block, Label, I}}) ->
+ io_lib:format("~p/~p: Unknown block ~p referenced in ~ts",
+ [F, A, Label, I]);
+format_error({{_M,F,A},{unknown_variable, Name, I}}) ->
+ io_lib:format("~p/~p: Unbound variable ~ts used in ~ts",
+ [F, A, format_var(Name), format_instr(I)]);
+format_error({{_M,F,A},{phi_inside_block, Name, Id}}) ->
+ io_lib:format("~p/~p: Phi node defining ~ts is not at start of block ~p",
+ [F, A, format_var(Name), Id]);
+format_error({{_M,F,A},{undefined_label_in_phi, Label, I}}) ->
+ io_lib:format("~p/~p: Unknown block label ~p in phi node ~ts",
+ [F, A, Label, format_instr(I)]).
+
+format_instr(I) ->
+ [$',beam_ssa_pp:format_instr(I),$'].
+
+format_var(V) ->
+ beam_ssa_pp:format_var(#b_var{name=V}).
+
+validate_function(F) ->
+ try
+ validate_variables(F),
+ []
+ catch
+ throw:Reason ->
+ #{func_info:=MFA} = F#b_function.anno,
+ [{MFA,Reason}];
+ Class:Error:Stack ->
+ io:fwrite("Function: ~p\n", [F#b_function.anno]),
+ erlang:raise(Class, Error, Stack)
+ end.
+
+-type defined_vars() :: gb_sets:set(beam_ssa:var_name()).
+
+-record(vvars,
+ {blocks :: #{ beam_ssa:label() => beam_ssa:b_blk() },
+ branch_def_vars :: #{
+ %% Describes the variable state at the time of this exact branch (phi
+ %% node validation).
+ {From :: beam_ssa:label(), To :: beam_ssa:label()} => defined_vars(),
+ %% Describes the variable state common to all branches leading to this
+ %% label (un/redefined variable validation).
+ beam_ssa:label() => defined_vars() },
+ defined_vars :: defined_vars()}).
+
+-spec validate_variables(beam_ssa:b_function()) -> ok.
+validate_variables(#b_function{ args = Args, bs = Blocks }) ->
+ %% Prefill the mapping with function arguments.
+ ArgNames = vvars_get_varnames(Args),
+ DefVars = gb_sets:from_list(ArgNames),
+ Entry = 0,
+
+ State = #vvars{blocks = Blocks,
+ branch_def_vars = #{ Entry => DefVars },
+ defined_vars = DefVars},
+ ok = vvars_assert_unique(Blocks, ArgNames),
+ vvars_phi_nodes(vvars_block(Entry, State)).
+
+%% Checks the uniqueness of all variables across all blocks.
+-spec vvars_assert_unique(Blocks, [beam_ssa:var_name()]) -> ok when
+ Blocks :: #{ beam_ssa:label() => beam_ssa:b_blk() }.
+vvars_assert_unique(Blocks, Args) ->
+ BlockIs = [Is || #b_blk{is=Is} <- maps:values(Blocks)],
+ Defined0 = maps:from_list([{V,argument} || V <- Args]),
+ _ = foldl(fun(Is, Defined) ->
+ vvars_assert_unique_1(Is, Defined)
+ end, Defined0, BlockIs),
+ ok.
+
+-spec vvars_assert_unique_1(Is, Defined) -> ok when
+ Is :: list(beam_ssa:b_set()),
+ Defined :: #{ beam_ssa:var_name() => beam_ssa:b_set() }.
+vvars_assert_unique_1([#b_set{dst=#b_var{name=DstName}}=I|Is], Defined) ->
+ case Defined of
+ #{DstName:=Old} -> throw({redefined_variable, DstName, Old, I});
+ _ -> vvars_assert_unique_1(Is, Defined#{DstName=>I})
+ end;
+vvars_assert_unique_1([], Defined) ->
+ Defined.
+
+-spec vvars_phi_nodes(State :: #vvars{}) -> ok.
+vvars_phi_nodes(#vvars{ blocks = Blocks }=State) ->
+ _ = [vvars_phi_nodes_1(Is, Id, State) ||
+ {Id, #b_blk{ is = Is }} <- maps:to_list(Blocks)],
+ ok.
+
+-spec vvars_phi_nodes_1(Is, Id, State) -> ok when
+ Is :: list(beam_ssa:b_set()),
+ Id :: beam_ssa:label(),
+ State :: #vvars{}.
+vvars_phi_nodes_1([#b_set{ op = phi, args = Phis }=I | Is], Id, State) ->
+ ok = vvars_assert_phi_paths(Phis, I, Id, State),
+ ok = vvars_assert_phi_vars(Phis, I, Id, State),
+ vvars_phi_nodes_1(Is, Id, State);
+vvars_phi_nodes_1([_ | Is], Id, _State) ->
+ case [Dst || #b_set{op=phi,dst=#b_var{name=Dst}} <- Is] of
+ [Name|_] ->
+ throw({phi_inside_block, Name, Id});
+ [] ->
+ ok
+ end;
+vvars_phi_nodes_1([], _Id, _State) ->
+ ok.
+
+%% Checks whether all paths leading to this phi node are represented, and that
+%% it doesn't reference any non-existent paths.
+-spec vvars_assert_phi_paths(Phis, I, Id, State) -> ok when
+ Phis :: list({beam_ssa:argument(), beam_ssa:label()}),
+ Id :: beam_ssa:label(),
+ I :: beam_ssa:b_set(),
+ State :: #vvars{}.
+vvars_assert_phi_paths(Phis, I, Id, State) ->
+ BranchKeys = maps:keys(State#vvars.branch_def_vars),
+ RequiredPaths = ordsets:from_list([From || {From, To} <- BranchKeys, To =:= Id]),
+ ProvidedPaths = ordsets:from_list([From || {_Value, From} <- Phis]),
+ case ordsets:subtract(RequiredPaths, ProvidedPaths) of
+ [_|_]=MissingPaths -> throw({missing_phi_paths, MissingPaths, I});
+ [] -> ok
+ end.
+ %% %% The following test is sometimes useful to find missing optimizations.
+ %% %% It is commented out, though, because it can be triggered by
+ %% %% by weird but legal code.
+ %% case ordsets:subtract(ProvidedPaths, RequiredPaths) of
+ %% [_|_]=GarbagePaths -> throw({garbage_phi_paths, GarbagePaths, I});
+ %% [] -> ok
+ %% end.
+
+%% Checks whether all variables used in this phi node are defined in the branch
+%% they arrived on.
+-spec vvars_assert_phi_vars(Phis, I, Id, State) -> ok when
+ Phis :: list({beam_ssa:argument(), beam_ssa:label()}),
+ Id :: beam_ssa:label(),
+ I :: beam_ssa:b_set(),
+ State :: #vvars{}.
+vvars_assert_phi_vars(Phis, I, Id, #vvars{blocks=Blocks,
+ branch_def_vars=BranchDefVars}) ->
+ Vars = [{Var, From} || {#b_var{}=Var, From} <- Phis],
+ foreach(fun({#b_var{name=VarName}, From}) ->
+ BranchKey = {From, Id},
+ case BranchDefVars of
+ #{BranchKey:=DefVars} ->
+ case gb_sets:is_member(VarName, DefVars) of
+ true -> ok;
+ false -> throw({unknown_variable, VarName, I})
+ end;
+ #{} ->
+ throw({unknown_phi_variable, VarName, BranchKey, I})
+ end
+ end, Vars),
+ Labels = [From || {#b_literal{},From} <- Phis],
+ foreach(fun(Label) ->
+ case Blocks of
+ #{Label:=_} ->
+ ok;
+ #{} ->
+ throw({undefined_label_in_phi, Label, I})
+ end
+ end, Labels).
+
+-spec vvars_block(Id, State) -> #vvars{} when
+ Id :: beam_ssa:label(),
+ State :: #vvars{}.
+vvars_block(Id, State0) ->
+ #{ Id := #b_blk{ is = Is, last = Terminator} } = State0#vvars.blocks,
+ #{ Id := DefVars } = State0#vvars.branch_def_vars,
+ State = State0#vvars{ defined_vars = DefVars },
+ vvars_terminator(Terminator, Id, vvars_block_1(Is, State)).
+
+-spec vvars_block_1(Blocks, State) -> #vvars{} when
+ Blocks :: list(beam_ssa:b_blk()),
+ State :: #vvars{}.
+vvars_block_1([], State) ->
+ State;
+vvars_block_1([#b_set{ dst = #b_var{ name = DstName }, op = phi } | Is], State0) ->
+ %% We don't check phi node arguments at this point since we may not have
+ %% visited their definition yet. They'll be handled later on in
+ %% vvars_phi_nodes/1 after all blocks are processed.
+ vvars_block_1(Is, vvars_save_var(DstName, State0));
+vvars_block_1([#b_set{ dst = #b_var{ name = DstName }, args = Args }=I | Is], State0) ->
+ ok = vvars_assert_args(Args, I, State0),
+ vvars_block_1(Is, vvars_save_var(DstName, State0)).
+
+-spec vvars_terminator(Terminator, From, State) -> #vvars{} when
+ Terminator :: beam_ssa:terminator(),
+ From :: beam_ssa:label(),
+ State :: #vvars{}.
+vvars_terminator(#b_ret{ arg = Arg }=I, _From, State) ->
+ ok = vvars_assert_args([Arg], I, State),
+ State;
+vvars_terminator(#b_switch{arg=Arg,fail=Fail,list=Switch}=I, From, State) ->
+ ok = vvars_assert_args([Arg], I, State),
+ ok = vvars_assert_args([A || {A,_Lbl} <- Switch], I, State),
+ Labels = [Fail | [Lbl || {_Arg, Lbl} <- Switch]],
+ ok = vvars_assert_labels(Labels, I, State),
+ vvars_terminator_1(Labels, From, State);
+vvars_terminator(#b_br{bool=#b_literal{val=true},succ=Succ}=I, From, State) ->
+ Labels = [Succ],
+ ok = vvars_assert_labels(Labels, I, State),
+ vvars_terminator_1(Labels, From, State);
+vvars_terminator(#b_br{bool=#b_literal{val=false},fail=Fail}=I, From, State) ->
+ Labels = [Fail],
+ ok = vvars_assert_labels(Labels, I, State),
+ vvars_terminator_1(Labels, From, State);
+vvars_terminator(#b_br{ bool = Arg, succ = Succ, fail = Fail }=I, From, State) ->
+ ok = vvars_assert_args([Arg], I, State),
+ Labels = [Fail, Succ],
+ ok = vvars_assert_labels(Labels, I, State),
+ vvars_terminator_1(Labels, From, State).
+
+-spec vvars_terminator_1(Labels, From, State) -> #vvars{} when
+ Labels :: list(beam_ssa:label()),
+ From :: beam_ssa:label(),
+ State :: #vvars{}.
+vvars_terminator_1(Labels0, From, State0) ->
+ %% Filter out all branches that have already been taken. This should result
+ %% in either all of Labels0 or an empty list.
+ Labels = [To || To <- Labels0,
+ not maps:is_key({From, To}, State0#vvars.branch_def_vars)],
+ true = Labels =:= Labels0 orelse Labels =:= [], %Assertion
+ State1 = foldl(fun(To, State) ->
+ vvars_save_branch(From, To, State)
+ end, State0, Labels),
+ foldl(fun(To, State) ->
+ vvars_block(To, State)
+ end, State1, Labels).
+
+%% Gets all variable names in args, ignoring literals etc
+-spec vvars_get_varnames(Args) -> list(beam_ssa:var_name()) when
+ Args :: list(beam_ssa:argument()).
+vvars_get_varnames(Args) ->
+ [Name || #b_var{ name = Name } <- Args].
+
+%% Checks that all variables in Args are defined in all paths leading to the
+%% current State.
+-spec vvars_assert_args(Args, I, State) -> ok when
+ Args :: list(beam_ssa:argument()),
+ I :: beam_ssa:terminator() | beam_ssa:b_set(),
+ State :: #vvars{}.
+vvars_assert_args(Args, I, #vvars{defined_vars=DefVars}=State) ->
+ foreach(fun(#b_remote{mod=Mod,name=Name}) ->
+ vvars_assert_args([Mod,Name], I, State);
+ (#b_var{name=Name}) ->
+ case gb_sets:is_member(Name, DefVars) of
+ true -> ok;
+ false -> throw({unknown_variable,Name,I})
+ end;
+ (_) -> ok
+ end, Args).
+
+%% Checks that all given labels are defined in State.
+-spec vvars_assert_labels(Labels, I, State) -> ok when
+ Labels :: list(beam_ssa:label()),
+ I :: beam_ssa:terminator(),
+ State :: #vvars{}.
+vvars_assert_labels(Labels, I, #vvars{blocks=Blocks}) ->
+ foreach(fun(Label) ->
+ case maps:is_key(Label, Blocks) of
+ false -> throw({unknown_block, Label, I});
+ true -> ok
+ end
+ end, Labels).
+
+-spec vvars_save_branch(From, To, State) -> #vvars{} when
+ From :: beam_ssa:label(),
+ To :: beam_ssa:label(),
+ State :: #vvars{}.
+vvars_save_branch(From, To, State) ->
+ DefVars = State#vvars.defined_vars,
+ Branches0 = State#vvars.branch_def_vars,
+ case Branches0 of
+ #{ To := LblDefVars } ->
+ MergedVars = vvars_merge_branches(DefVars, LblDefVars),
+
+ Branches = Branches0#{ To => MergedVars, {From, To} => DefVars },
+ State#vvars { branch_def_vars = Branches };
+ _ ->
+ Branches = Branches0#{ To => DefVars, {From, To} => DefVars },
+ State#vvars { branch_def_vars = Branches }
+ end.
+
+-spec vvars_merge_branches(New, Existing) -> defined_vars() when
+ New :: defined_vars(),
+ Existing :: defined_vars().
+vvars_merge_branches(New, Existing) ->
+ gb_sets:intersection(New, Existing).
+
+-spec vvars_save_var(VarName, State) -> #vvars{} when
+ VarName :: beam_ssa:var_name(),
+ State :: #vvars{}.
+vvars_save_var(VarName, State0) ->
+ %% vvars_assert_unique guarantees that variables are never set twice.
+ DefVars = gb_sets:insert(VarName, State0#vvars.defined_vars),
+ State0#vvars{ defined_vars = DefVars }.
diff --git a/lib/compiler/src/beam_ssa_opt.erl b/lib/compiler/src/beam_ssa_opt.erl
new file mode 100644
index 0000000000..90c0d3cf16
--- /dev/null
+++ b/lib/compiler/src/beam_ssa_opt.erl
@@ -0,0 +1,2279 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%%
+%%% This is a collection of various optimizations that don't need a separate
+%%% pass by themselves and/or are mutually beneficial to other passes.
+%%%
+%%% The optimizations are applied in "phases," each with a list of sub-passes
+%%% to run. These sub-passes are applied on all functions in a module before
+%%% moving on to the next phase, which lets us gather module-level information
+%%% in one phase and then apply it in the next without having to risk working
+%%% with incomplete information.
+%%%
+%%% Each sub-pass operates on a #st{} record and a func_info_db(), where the
+%%% former is just a #b_function{} whose blocks can be represented either in
+%%% linear or map form, and the latter is a map with information about all
+%%% functions in the module (see beam_ssa_opt.hrl for more details).
+%%%
+
+-module(beam_ssa_opt).
+-export([module/2]).
+
+-include("beam_ssa_opt.hrl").
+
+-import(lists, [all/2,append/1,duplicate/2,foldl/3,keyfind/3,member/2,
+ reverse/1,reverse/2,
+ splitwith/2,sort/1,takewhile/2,unzip/1]).
+
+-define(DEFAULT_REPETITIONS, 2).
+
+-spec module(beam_ssa:b_module(), [compile:option()]) ->
+ {'ok',beam_ssa:b_module()}.
+
+-record(st, {ssa :: [{beam_ssa:label(),beam_ssa:b_blk()}] |
+ beam_ssa:block_map(),
+ args :: [beam_ssa:b_var()],
+ cnt :: beam_ssa:label(),
+ anno :: beam_ssa:anno()}).
+-type st_map() :: #{ func_id() => #st{} }.
+
+module(Module, Opts) ->
+ FuncDb0 = case proplists:get_value(no_module_opt, Opts, false) of
+ false -> build_func_db(Module);
+ true -> #{}
+ end,
+
+ %% Passes that perform module-level optimizations are often aided by
+ %% optimizing callers before callees and vice versa, so we optimize all
+ %% functions in call order, flipping it as required.
+ StMap0 = build_st_map(Module),
+ Order = get_call_order_po(StMap0, FuncDb0),
+
+ Phases =
+ [{Order, prologue_passes(Opts)}] ++
+ repeat(Opts, repeated_passes(Opts), Order) ++
+ [{Order, epilogue_passes(Opts)}],
+
+ {StMap, _FuncDb} = foldl(fun({FuncIds, Ps}, {StMap, FuncDb}) ->
+ phase(FuncIds, Ps, StMap, FuncDb)
+ end, {StMap0, FuncDb0}, Phases),
+
+ {ok, finish(Module, StMap)}.
+
+phase([FuncId | Ids], Ps, StMap, FuncDb0) ->
+ try compile:run_sub_passes(Ps, {map_get(FuncId, StMap), FuncDb0}) of
+ {St, FuncDb} ->
+ phase(Ids, Ps, StMap#{ FuncId => St }, FuncDb)
+ catch
+ Class:Error:Stack ->
+ #b_local{name=#b_literal{val=Name},arity=Arity} = FuncId,
+ io:fwrite("Function: ~w/~w\n", [Name,Arity]),
+ erlang:raise(Class, Error, Stack)
+ end;
+phase([], _Ps, StMap, FuncDb) ->
+ {StMap, FuncDb}.
+
+%% Repeats the given passes, alternating the order between runs to make the
+%% type pass more efficient.
+repeat(Opts, Ps, OrderA) ->
+ Repeat = proplists:get_value(ssa_opt_repeat, Opts, ?DEFAULT_REPETITIONS),
+ OrderB = reverse(OrderA),
+ repeat_1(Repeat, Ps, OrderA, OrderB).
+
+repeat_1(0, _Opts, _OrderA, _OrderB) ->
+ [];
+repeat_1(N, Ps, OrderA, OrderB) when N > 0, N rem 2 =:= 0 ->
+ [{OrderA, Ps} | repeat_1(N - 1, Ps, OrderA, OrderB)];
+repeat_1(N, Ps, OrderA, OrderB) when N > 0, N rem 2 =:= 1 ->
+ [{OrderB, Ps} | repeat_1(N - 1, Ps, OrderA, OrderB)].
+
+%%
+
+get_func_id(F) ->
+ {_Mod, Name, Arity} = beam_ssa:get_anno(func_info, F),
+ #b_local{name=#b_literal{val=Name}, arity=Arity}.
+
+-spec build_st_map(#b_module{}) -> st_map().
+build_st_map(#b_module{body=Fs}) ->
+ build_st_map_1(Fs, #{}).
+
+build_st_map_1([F | Fs], Map) ->
+ #b_function{anno=Anno,args=Args,cnt=Counter,bs=Bs} = F,
+ St = #st{anno=Anno,args=Args,cnt=Counter,ssa=Bs},
+ build_st_map_1(Fs, Map#{ get_func_id(F) => St });
+build_st_map_1([], Map) ->
+ Map.
+
+-spec finish(#b_module{}, st_map()) -> #b_module{}.
+finish(#b_module{body=Fs0}=Module, StMap) ->
+ Module#b_module{body=finish_1(Fs0, StMap)}.
+
+finish_1([F0 | Fs], StMap) ->
+ #st{anno=Anno,cnt=Counter,ssa=Blocks} = map_get(get_func_id(F0), StMap),
+ F = F0#b_function{anno=Anno,bs=Blocks,cnt=Counter},
+ [F | finish_1(Fs, StMap)];
+finish_1([], _StMap) ->
+ [].
+
+%%
+
+-define(PASS(N), {N,fun N/1}).
+
+prologue_passes(Opts) ->
+ Ps = [?PASS(ssa_opt_split_blocks),
+ ?PASS(ssa_opt_coalesce_phis),
+ ?PASS(ssa_opt_tail_phis),
+ ?PASS(ssa_opt_element),
+ ?PASS(ssa_opt_linearize),
+ ?PASS(ssa_opt_tuple_size),
+ ?PASS(ssa_opt_record),
+ ?PASS(ssa_opt_cse), %Helps the first type pass.
+ ?PASS(ssa_opt_type_start)],
+ passes_1(Ps, Opts).
+
+%% These passes all benefit from each other (in roughly this order), so they
+%% are repeated as required.
+repeated_passes(Opts) ->
+ Ps = [?PASS(ssa_opt_live),
+ ?PASS(ssa_opt_bs_puts),
+ ?PASS(ssa_opt_dead),
+ ?PASS(ssa_opt_cse),
+ ?PASS(ssa_opt_tail_phis),
+ ?PASS(ssa_opt_type_continue)], %Must run after ssa_opt_dead to
+ %clean up phi nodes.
+ passes_1(Ps, Opts).
+
+epilogue_passes(Opts) ->
+ Ps = [?PASS(ssa_opt_type_finish),
+ ?PASS(ssa_opt_float),
+ ?PASS(ssa_opt_sw),
+
+ %% Run live one more time to clean up after the float and sw
+ %% passes.
+ ?PASS(ssa_opt_live),
+ ?PASS(ssa_opt_bsm),
+ ?PASS(ssa_opt_bsm_units),
+ ?PASS(ssa_opt_bsm_shortcut),
+ ?PASS(ssa_opt_blockify),
+ ?PASS(ssa_opt_sink),
+ ?PASS(ssa_opt_merge_blocks),
+ ?PASS(ssa_opt_get_tuple_element),
+ ?PASS(ssa_opt_trim_unreachable)],
+ passes_1(Ps, Opts).
+
+passes_1(Ps, Opts0) ->
+ Negations = [{list_to_atom("no_"++atom_to_list(N)),N} ||
+ {N,_} <- Ps],
+ Opts = proplists:substitute_negations(Negations, Opts0),
+ [case proplists:get_value(Name, Opts, true) of
+ true ->
+ P;
+ false ->
+ {NoName,Name} = keyfind(Name, 2, Negations),
+ {NoName,fun(S) -> S end}
+ end || {Name,_}=P <- Ps].
+
+%% Builds a function information map with basic information about incoming and
+%% outgoing local calls, as well as whether the function is exported.
+-spec build_func_db(#b_module{}) -> func_info_db().
+build_func_db(#b_module{body=Fs,exports=Exports}) ->
+ try
+ fdb_1(Fs, gb_sets:from_list(Exports), #{})
+ catch
+ %% All module-level optimizations are invalid when a NIF can override a
+ %% function, so we have to bail out.
+ throw:load_nif -> #{}
+ end.
+
+fdb_1([#b_function{ args=Args,bs=Bs }=F | Fs], Exports, FuncDb0) ->
+ Id = get_func_id(F),
+
+ #b_local{name=#b_literal{val=Name}, arity=Arity} = Id,
+ Exported = gb_sets:is_element({Name, Arity}, Exports),
+ ArgTypes = duplicate(length(Args), #{}),
+
+ FuncDb1 = case FuncDb0 of
+ %% We may have an entry already if someone's called us.
+ #{ Id := Info } ->
+ FuncDb0#{ Id := Info#func_info{ exported=Exported,
+ arg_types=ArgTypes }};
+ #{} ->
+ FuncDb0#{ Id => #func_info{ exported=Exported,
+ arg_types=ArgTypes }}
+ end,
+
+ FuncDb = beam_ssa:fold_rpo(fun(_L, #b_blk{is=Is}, FuncDb) ->
+ fdb_is(Is, Id, FuncDb)
+ end, FuncDb1, Bs),
+
+ fdb_1(Fs, Exports, FuncDb);
+fdb_1([], _Exports, FuncDb) ->
+ FuncDb.
+
+fdb_is([#b_set{op=call,
+ args=[#b_local{}=Callee | _]} | Is],
+ Caller, FuncDb) ->
+ fdb_is(Is, Caller, fdb_update(Caller, Callee, FuncDb));
+fdb_is([#b_set{op=call,
+ args=[#b_remote{mod=#b_literal{val=erlang},
+ name=#b_literal{val=load_nif}},
+ _Path, _LoadInfo]} | _Is], _Caller, _FuncDb) ->
+ throw(load_nif);
+fdb_is([_ | Is], Caller, FuncDb) ->
+ fdb_is(Is, Caller, FuncDb);
+fdb_is([], _Caller, FuncDb) ->
+ FuncDb.
+
+fdb_update(Caller, Callee, FuncDb) ->
+ CallerVertex = maps:get(Caller, FuncDb, #func_info{}),
+ CalleeVertex = maps:get(Callee, FuncDb, #func_info{}),
+
+ Calls = ordsets:add_element(Callee, CallerVertex#func_info.out),
+ CalledBy = ordsets:add_element(Caller, CalleeVertex#func_info.in),
+
+ FuncDb#{ Caller => CallerVertex#func_info{out=Calls},
+ Callee => CalleeVertex#func_info{in=CalledBy} }.
+
+%% Returns the post-order of all local calls in this module. That is,
+%% called functions will be ordered before the functions calling them.
+%%
+%% Functions where module-level optimization is disabled are added last in
+%% arbitrary order.
+
+get_call_order_po(StMap, FuncDb) ->
+ Order = gco_po(FuncDb),
+ Order ++ maps:fold(fun(K, _V, Acc) ->
+ case is_map_key(K, FuncDb) of
+ false -> [K | Acc];
+ true -> Acc
+ end
+ end, [], StMap).
+
+gco_po(FuncDb) ->
+ All = sort(maps:keys(FuncDb)),
+ {RPO,_} = gco_rpo(All, FuncDb, cerl_sets:new(), []),
+ reverse(RPO).
+
+gco_rpo([Id|Ids], FuncDb, Seen0, Acc0) ->
+ case cerl_sets:is_element(Id, Seen0) of
+ true ->
+ gco_rpo(Ids, FuncDb, Seen0, Acc0);
+ false ->
+ #func_info{out=Successors} = map_get(Id, FuncDb),
+ Seen1 = cerl_sets:add_element(Id, Seen0),
+ {Acc,Seen} = gco_rpo(Successors, FuncDb, Seen1, Acc0),
+ gco_rpo(Ids, FuncDb, Seen, [Id|Acc])
+ end;
+gco_rpo([], _, Seen, Acc) ->
+ {Acc,Seen}.
+
+%%%
+%%% Trivial sub passes.
+%%%
+
+ssa_opt_dead({#st{ssa=Linear}=St, FuncDb}) ->
+ {St#st{ssa=beam_ssa_dead:opt(Linear)}, FuncDb}.
+
+ssa_opt_linearize({#st{ssa=Blocks}=St, FuncDb}) ->
+ {St#st{ssa=beam_ssa:linearize(Blocks)}, FuncDb}.
+
+ssa_opt_type_start({#st{ssa=Linear0,args=Args,anno=Anno}=St0, FuncDb0}) ->
+ {Linear, FuncDb} = beam_ssa_type:opt_start(Linear0, Args, Anno, FuncDb0),
+ {St0#st{ssa=Linear}, FuncDb}.
+
+ssa_opt_type_continue({#st{ssa=Linear0,args=Args,anno=Anno}=St0, FuncDb0}) ->
+ {Linear, FuncDb} = beam_ssa_type:opt_continue(Linear0, Args, Anno, FuncDb0),
+ {St0#st{ssa=Linear}, FuncDb}.
+
+ssa_opt_type_finish({#st{args=Args,anno=Anno0}=St0, FuncDb0}) ->
+ {Anno, FuncDb} = beam_ssa_type:opt_finish(Args, Anno0, FuncDb0),
+ {St0#st{anno=Anno}, FuncDb}.
+
+ssa_opt_blockify({#st{ssa=Linear}=St, FuncDb}) ->
+ {St#st{ssa=maps:from_list(Linear)}, FuncDb}.
+
+ssa_opt_trim_unreachable({#st{ssa=Blocks}=St, FuncDb}) ->
+ {St#st{ssa=beam_ssa:trim_unreachable(Blocks)}, FuncDb}.
+
+%%%
+%%% Split blocks before certain instructions to enable more optimizations.
+%%%
+%%% Splitting before element/2 enables the optimization that swaps
+%%% element/2 instructions.
+%%%
+%%% Splitting before call and make_fun instructions gives more opportunities
+%%% for sinking get_tuple_element instructions.
+%%%
+
+ssa_opt_split_blocks({#st{ssa=Blocks0,cnt=Count0}=St, FuncDb}) ->
+ P = fun(#b_set{op={bif,element}}) -> true;
+ (#b_set{op=call}) -> true;
+ (#b_set{op=make_fun}) -> true;
+ (_) -> false
+ end,
+ {Blocks,Count} = beam_ssa:split_blocks(P, Blocks0, Count0),
+ {St#st{ssa=Blocks,cnt=Count}, FuncDb}.
+
+%%%
+%%% Coalesce phi nodes.
+%%%
+%%% Nested cases can led to code such as this:
+%%%
+%%% 10:
+%%% _1 = phi {literal value1, label 8}, {Var, label 9}
+%%% br 11
+%%%
+%%% 11:
+%%% _2 = phi {_1, label 10}, {literal false, label 3}
+%%%
+%%% The phi nodes can be coalesced like this:
+%%%
+%%% 11:
+%%% _2 = phi {literal value1, label 8}, {Var, label 9}, {literal false, label 3}
+%%%
+%%% Coalescing can help other optimizations, and can in some cases reduce register
+%%% shuffling (if the phi variables for two phi nodes happens to be allocated to
+%%% different registers).
+%%%
+
+ssa_opt_coalesce_phis({#st{ssa=Blocks0}=St, FuncDb}) ->
+ Ls = beam_ssa:rpo(Blocks0),
+ Blocks = c_phis_1(Ls, Blocks0),
+ {St#st{ssa=Blocks}, FuncDb}.
+
+c_phis_1([L|Ls], Blocks0) ->
+ case map_get(L, Blocks0) of
+ #b_blk{is=[#b_set{op=phi}|_]}=Blk ->
+ Blocks = c_phis_2(L, Blk, Blocks0),
+ c_phis_1(Ls, Blocks);
+ #b_blk{} ->
+ c_phis_1(Ls, Blocks0)
+ end;
+c_phis_1([], Blocks) -> Blocks.
+
+c_phis_2(L, #b_blk{is=Is0}=Blk0, Blocks0) ->
+ case c_phis_args(Is0, Blocks0) of
+ none ->
+ Blocks0;
+ {_,_,Preds}=Info ->
+ Is = c_rewrite_phis(Is0, Info),
+ Blk = Blk0#b_blk{is=Is},
+ Blocks = Blocks0#{L:=Blk},
+ c_fix_branches(Preds, L, Blocks)
+ end.
+
+c_phis_args([#b_set{op=phi,args=Args0}|Is], Blocks) ->
+ case c_phis_args_1(Args0, Blocks) of
+ none ->
+ c_phis_args(Is, Blocks);
+ Res ->
+ Res
+ end;
+c_phis_args(_, _Blocks) -> none.
+
+c_phis_args_1([{Var,Pred}|As], Blocks) ->
+ case c_get_pred_vars(Var, Pred, Blocks) of
+ none ->
+ c_phis_args_1(As, Blocks);
+ Result ->
+ Result
+ end;
+c_phis_args_1([], _Blocks) -> none.
+
+c_get_pred_vars(Var, Pred, Blocks) ->
+ case map_get(Pred, Blocks) of
+ #b_blk{is=[#b_set{op=phi,dst=Var,args=Args}]} ->
+ {Var,Pred,Args};
+ #b_blk{} ->
+ none
+ end.
+
+c_rewrite_phis([#b_set{op=phi,args=Args0}=I|Is], Info) ->
+ Args = c_rewrite_phi(Args0, Info),
+ [I#b_set{args=Args}|c_rewrite_phis(Is, Info)];
+c_rewrite_phis(Is, _Info) -> Is.
+
+c_rewrite_phi([{Var,Pred}|As], {Var,Pred,Values}) ->
+ Values ++ As;
+c_rewrite_phi([{Value,Pred}|As], {_,Pred,Values}) ->
+ [{Value,P} || {_,P} <- Values] ++ As;
+c_rewrite_phi([A|As], Info) ->
+ [A|c_rewrite_phi(As, Info)];
+c_rewrite_phi([], _Info) -> [].
+
+c_fix_branches([{_,Pred}|As], L, Blocks0) ->
+ #b_blk{last=Last0} = Blk0 = map_get(Pred, Blocks0),
+ #b_br{bool=#b_literal{val=true}} = Last0, %Assertion.
+ Last = Last0#b_br{bool=#b_literal{val=true},succ=L,fail=L},
+ Blk = Blk0#b_blk{last=Last},
+ Blocks = Blocks0#{Pred:=Blk},
+ c_fix_branches(As, L, Blocks);
+c_fix_branches([], _, Blocks) -> Blocks.
+
+%%%
+%%% Eliminate phi nodes in the tail of a function.
+%%%
+%%% Try to eliminate short blocks that starts with a phi node
+%%% and end in a return. For example:
+%%%
+%%% Result = phi { Res1, 4 }, { literal true, 5 }
+%%% Ret = put_tuple literal ok, Result
+%%% ret Ret
+%%%
+%%% The code in this block can be inserted at the end blocks 4 and
+%%% 5. Thus, the following code can be inserted into block 4:
+%%%
+%%% Ret:1 = put_tuple literal ok, Res1
+%%% ret Ret:1
+%%%
+%%% And the following code into block 5:
+%%%
+%%% Ret:2 = put_tuple literal ok, literal true
+%%% ret Ret:2
+%%%
+%%% Which can be further simplified to:
+%%%
+%%% ret literal {ok, true}
+%%%
+%%% This transformation may lead to more code improvements:
+%%%
+%%% - Stack trimming
+%%% - Fewer test_heap instructions
+%%% - Smaller stack frames
+%%%
+
+ssa_opt_tail_phis({#st{ssa=SSA0,cnt=Count0}=St, FuncDb}) ->
+ {SSA,Count} = opt_tail_phis(SSA0, Count0),
+ {St#st{ssa=SSA,cnt=Count}, FuncDb}.
+
+opt_tail_phis(Blocks, Count) when is_map(Blocks) ->
+ opt_tail_phis(maps:values(Blocks), Blocks, Count);
+opt_tail_phis(Linear0, Count0) when is_list(Linear0) ->
+ Blocks0 = maps:from_list(Linear0),
+ {Blocks,Count} = opt_tail_phis(Blocks0, Count0),
+ {beam_ssa:linearize(Blocks),Count}.
+
+opt_tail_phis([#b_blk{is=Is0,last=Last}|Bs], Blocks0, Count0) ->
+ case {Is0,Last} of
+ {[#b_set{op=phi,args=[_,_|_]}|_],#b_ret{arg=#b_var{}}=Ret} ->
+ {Phis,Is} = splitwith(fun(#b_set{op=Op}) -> Op =:= phi end, Is0),
+ case suitable_tail_ops(Is) of
+ true ->
+ {Blocks,Count} = opt_tail_phi(Phis, Is, Ret,
+ Blocks0, Count0),
+ opt_tail_phis(Bs, Blocks, Count);
+ false ->
+ opt_tail_phis(Bs, Blocks0, Count0)
+ end;
+ {_,_} ->
+ opt_tail_phis(Bs, Blocks0, Count0)
+ end;
+opt_tail_phis([], Blocks, Count) ->
+ {Blocks,Count}.
+
+opt_tail_phi(Phis0, Is, Ret, Blocks0, Count0) ->
+ Phis = rel2fam(reduce_phis(Phis0)),
+ {Blocks,Count,Cost} =
+ foldl(fun(PhiArg, Acc) ->
+ opt_tail_phi_arg(PhiArg, Is, Ret, Acc)
+ end, {Blocks0,Count0,0}, Phis),
+ MaxCost = length(Phis) * 3 + 2,
+ if
+ Cost =< MaxCost ->
+ %% The transformation would cause at most a slight
+ %% increase in code size if no more optimizations
+ %% can be applied.
+ {Blocks,Count};
+ true ->
+ %% The code size would be increased too much.
+ {Blocks0,Count0}
+ end.
+
+reduce_phis([#b_set{dst=PhiDst,args=PhiArgs}|Is]) ->
+ [{L,{PhiDst,Val}} || {Val,L} <- PhiArgs] ++ reduce_phis(Is);
+reduce_phis([]) -> [].
+
+opt_tail_phi_arg({PredL,Sub0}, Is0, Ret0, {Blocks0,Count0,Cost0}) ->
+ Blk0 = map_get(PredL, Blocks0),
+ #b_blk{is=IsPrefix,last=#b_br{succ=Next,fail=Next}} = Blk0,
+ case is_exit_bif(IsPrefix) of
+ false ->
+ Sub1 = maps:from_list(Sub0),
+ {Is1,Count,Sub} = new_names(Is0, Sub1, Count0, []),
+ Is2 = [sub(I, Sub) || I <- Is1],
+ Cost = build_cost(Is2, Cost0),
+ Is = IsPrefix ++ Is2,
+ Ret = sub(Ret0, Sub),
+ Blk = Blk0#b_blk{is=Is,last=Ret},
+ Blocks = Blocks0#{PredL:=Blk},
+ {Blocks,Count,Cost};
+ true ->
+ %% The block ends in a call to a function that
+ %% will cause an exception.
+ {Blocks0,Count0,Cost0+3}
+ end.
+
+is_exit_bif([#b_set{op=call,
+ args=[#b_remote{mod=#b_literal{val=Mod},
+ name=#b_literal{val=Name}}|Args]}]) ->
+ erl_bifs:is_exit_bif(Mod, Name, length(Args));
+is_exit_bif(_) -> false.
+
+new_names([#b_set{dst=Dst}=I|Is], Sub0, Count0, Acc) ->
+ {NewDst,Count} = new_var(Dst, Count0),
+ Sub = Sub0#{Dst=>NewDst},
+ new_names(Is, Sub, Count, [I#b_set{dst=NewDst}|Acc]);
+new_names([], Sub, Count, Acc) ->
+ {reverse(Acc),Count,Sub}.
+
+suitable_tail_ops(Is) ->
+ all(fun(#b_set{op=Op}) ->
+ is_suitable_tail_op(Op)
+ end, Is).
+
+is_suitable_tail_op({bif,_}) -> true;
+is_suitable_tail_op(put_list) -> true;
+is_suitable_tail_op(put_tuple) -> true;
+is_suitable_tail_op(_) -> false.
+
+build_cost([#b_set{op=put_list,args=Args}|Is], Cost) ->
+ case are_all_literals(Args) of
+ true ->
+ build_cost(Is, Cost);
+ false ->
+ build_cost(Is, Cost + 1)
+ end;
+build_cost([#b_set{op=put_tuple,args=Args}|Is], Cost) ->
+ case are_all_literals(Args) of
+ true ->
+ build_cost(Is, Cost);
+ false ->
+ build_cost(Is, Cost + length(Args) + 1)
+ end;
+build_cost([#b_set{op={bif,_},args=Args}|Is], Cost) ->
+ case are_all_literals(Args) of
+ true ->
+ build_cost(Is, Cost);
+ false ->
+ build_cost(Is, Cost + 1)
+ end;
+build_cost([], Cost) -> Cost.
+
+are_all_literals(Args) ->
+ all(fun(#b_literal{}) -> true;
+ (_) -> false
+ end, Args).
+
+%%%
+%%% Order element/2 calls.
+%%%
+%%% Order an unbroken chain of element/2 calls for the same tuple
+%%% with the same failure label so that the highest element is
+%%% retrieved first. That will allow the other element/2 calls to
+%%% be replaced with get_tuple_element/3 instructions.
+%%%
+
+ssa_opt_element({#st{ssa=Blocks}=St, FuncDb}) ->
+ %% Collect the information about element instructions in this
+ %% function.
+ GetEls = collect_element_calls(beam_ssa:linearize(Blocks)),
+
+ %% Collect the element instructions into chains. The
+ %% element calls in each chain are ordered in reverse
+ %% execution order.
+ Chains = collect_chains(GetEls, []),
+
+ %% For each chain, swap the first element call with the
+ %% element call with the highest index.
+ {St#st{ssa=swap_element_calls(Chains, Blocks)}, FuncDb}.
+
+collect_element_calls([{L,#b_blk{is=Is0,last=Last}}|Bs]) ->
+ case {Is0,Last} of
+ {[#b_set{op={bif,element},dst=Element,
+ args=[#b_literal{val=N},#b_var{}=Tuple]},
+ #b_set{op=succeeded,dst=Bool,args=[Element]}],
+ #b_br{bool=Bool,succ=Succ,fail=Fail}} ->
+ Info = {L,Succ,{Tuple,Fail},N},
+ [Info|collect_element_calls(Bs)];
+ {_,_} ->
+ collect_element_calls(Bs)
+ end;
+collect_element_calls([]) -> [].
+
+collect_chains([{This,_,V,_}=El|Els], [{_,This,V,_}|_]=Chain) ->
+ %% Add to the previous chain.
+ collect_chains(Els, [El|Chain]);
+collect_chains([El|Els], [_,_|_]=Chain) ->
+ %% Save the previous chain and start a new chain.
+ [Chain|collect_chains(Els, [El])];
+collect_chains([El|Els], _Chain) ->
+ %% The previous chain is too short; discard it and start a new.
+ collect_chains(Els, [El]);
+collect_chains([], [_,_|_]=Chain) ->
+ %% Save the last chain.
+ [Chain];
+collect_chains([], _) -> [].
+
+swap_element_calls([[{L,_,_,N}|_]=Chain|Chains], Blocks0) ->
+ Blocks = swap_element_calls_1(Chain, {N,L}, Blocks0),
+ swap_element_calls(Chains, Blocks);
+swap_element_calls([], Blocks) -> Blocks.
+
+swap_element_calls_1([{L1,_,_,N1}], {N2,L2}, Blocks) when N2 > N1 ->
+ %% We have reached the end of the chain, and the first
+ %% element instrution to be executed. Its index is lower
+ %% than the maximum index found while traversing the chain,
+ %% so we will need to swap the instructions.
+ #{L1:=Blk1,L2:=Blk2} = Blocks,
+ [#b_set{dst=Dst1}=GetEl1,Succ1] = Blk1#b_blk.is,
+ [#b_set{dst=Dst2}=GetEl2,Succ2] = Blk2#b_blk.is,
+ Is1 = [GetEl2,Succ1#b_set{args=[Dst2]}],
+ Is2 = [GetEl1,Succ2#b_set{args=[Dst1]}],
+ Blocks#{L1:=Blk1#b_blk{is=Is1},L2:=Blk2#b_blk{is=Is2}};
+swap_element_calls_1([{L,_,_,N1}|Els], {N2,_}, Blocks) when N1 > N2 ->
+ swap_element_calls_1(Els, {N2,L}, Blocks);
+swap_element_calls_1([_|Els], Highest, Blocks) ->
+ swap_element_calls_1(Els, Highest, Blocks);
+swap_element_calls_1([], _, Blocks) ->
+ %% Nothing to do. The element call with highest index
+ %% is already the first one to be executed.
+ Blocks.
+
+%%%
+%%% Record optimization.
+%%%
+%%% Replace tuple matching with an is_tagged_tuple instruction
+%%% when applicable.
+%%%
+
+ssa_opt_record({#st{ssa=Linear}=St, FuncDb}) ->
+ Blocks = maps:from_list(Linear),
+ {St#st{ssa=record_opt(Linear, Blocks)}, FuncDb}.
+
+record_opt([{L,#b_blk{is=Is0,last=Last}=Blk0}|Bs], Blocks) ->
+ Is = record_opt_is(Is0, Last, Blocks),
+ Blk = Blk0#b_blk{is=Is},
+ [{L,Blk}|record_opt(Bs, Blocks)];
+record_opt([], _Blocks) -> [].
+
+record_opt_is([#b_set{op={bif,is_tuple},dst=Bool,args=[Tuple]}=Set],
+ Last, Blocks) ->
+ case is_tagged_tuple(Tuple, Bool, Last, Blocks) of
+ {yes,Size,Tag} ->
+ Args = [Tuple,Size,Tag],
+ [Set#b_set{op=is_tagged_tuple,args=Args}];
+ no ->
+ [Set]
+ end;
+record_opt_is([I|Is]=Is0, #b_br{bool=Bool}=Last, Blocks) ->
+ case is_tagged_tuple_1(Is0, Last, Blocks) of
+ {yes,_Fail,Tuple,Arity,Tag} ->
+ Args = [Tuple,Arity,Tag],
+ [I#b_set{op=is_tagged_tuple,dst=Bool,args=Args}];
+ no ->
+ [I|record_opt_is(Is, Last, Blocks)]
+ end;
+record_opt_is([I|Is], Last, Blocks) ->
+ [I|record_opt_is(Is, Last, Blocks)];
+record_opt_is([], _Last, _Blocks) -> [].
+
+is_tagged_tuple(#b_var{}=Tuple, Bool,
+ #b_br{bool=Bool,succ=Succ,fail=Fail},
+ Blocks) ->
+ #b_blk{is=Is,last=Last} = map_get(Succ, Blocks),
+ case is_tagged_tuple_1(Is, Last, Blocks) of
+ {yes,Fail,Tuple,Arity,Tag} ->
+ {yes,Arity,Tag};
+ _ ->
+ no
+ end;
+is_tagged_tuple(_, _, _, _) -> no.
+
+is_tagged_tuple_1(Is, Last, Blocks) ->
+ case {Is,Last} of
+ {[#b_set{op={bif,tuple_size},dst=ArityVar,
+ args=[#b_var{}=Tuple]},
+ #b_set{op={bif,'=:='},
+ dst=Bool,
+ args=[ArityVar, #b_literal{val=ArityVal}=Arity]}],
+ #b_br{bool=Bool,succ=Succ,fail=Fail}}
+ when is_integer(ArityVal) ->
+ SuccBlk = map_get(Succ, Blocks),
+ case is_tagged_tuple_2(SuccBlk, Tuple, Fail) of
+ no ->
+ no;
+ {yes,Tag} ->
+ {yes,Fail,Tuple,Arity,Tag}
+ end;
+ _ ->
+ no
+ end.
+
+is_tagged_tuple_2(#b_blk{is=Is,
+ last=#b_br{bool=#b_var{}=Bool,fail=Fail}},
+ Tuple, Fail) ->
+ is_tagged_tuple_3(Is, Bool, Tuple);
+is_tagged_tuple_2(#b_blk{}, _, _) -> no.
+
+is_tagged_tuple_3([#b_set{op=get_tuple_element,
+ dst=TagVar,
+ args=[#b_var{}=Tuple,#b_literal{val=0}]}|Is],
+ Bool, Tuple) ->
+ is_tagged_tuple_4(Is, Bool, TagVar);
+is_tagged_tuple_3([_|Is], Bool, Tuple) ->
+ is_tagged_tuple_3(Is, Bool, Tuple);
+is_tagged_tuple_3([], _, _) -> no.
+
+is_tagged_tuple_4([#b_set{op={bif,'=:='},dst=Bool,
+ args=[#b_var{}=TagVar,
+ #b_literal{val=TagVal}=Tag]}],
+ Bool, TagVar) when is_atom(TagVal) ->
+ {yes,Tag};
+is_tagged_tuple_4([_|Is], Bool, TagVar) ->
+ is_tagged_tuple_4(Is, Bool, TagVar);
+is_tagged_tuple_4([], _, _) -> no.
+
+%%%
+%%% Common subexpression elimination (CSE).
+%%%
+%%% Eliminate repeated evaluation of identical expressions. To avoid
+%%% increasing the size of the stack frame, we don't eliminate
+%%% subexpressions across instructions that clobber the X registers.
+%%%
+
+ssa_opt_cse({#st{ssa=Linear}=St, FuncDb}) ->
+ M = #{0=>#{}},
+ {St#st{ssa=cse(Linear, #{}, M)}, FuncDb}.
+
+cse([{L,#b_blk{is=Is0,last=Last0}=Blk}|Bs], Sub0, M0) ->
+ Es0 = map_get(L, M0),
+ {Is1,Es,Sub} = cse_is(Is0, Es0, Sub0, []),
+ Last = sub(Last0, Sub),
+ M = cse_successors(Is1, Blk, Es, M0),
+ Is = reverse(Is1),
+ [{L,Blk#b_blk{is=Is,last=Last}}|cse(Bs, Sub, M)];
+cse([], _, _) -> [].
+
+cse_successors([#b_set{op=succeeded,args=[Src]},Bif|_], Blk, EsSucc, M0) ->
+ case cse_suitable(Bif) of
+ true ->
+ %% The previous instruction only has a valid value at the success branch.
+ %% We must remove the substitution for Src from the failure branch.
+ #b_blk{last=#b_br{succ=Succ,fail=Fail}} = Blk,
+ M = cse_successors_1([Succ], EsSucc, M0),
+ EsFail = maps:filter(fun(_, Val) -> Val =/= Src end, EsSucc),
+ cse_successors_1([Fail], EsFail, M);
+ false ->
+ %% There can't be any replacement for Src in EsSucc. No need for
+ %% any special handling.
+ cse_successors_1(beam_ssa:successors(Blk), EsSucc, M0)
+ end;
+cse_successors(_Is, Blk, Es, M) ->
+ cse_successors_1(beam_ssa:successors(Blk), Es, M).
+
+cse_successors_1([L|Ls], Es0, M) ->
+ case M of
+ #{L:=Es1} when map_size(Es1) =:= 0 ->
+ %% The map is already empty. No need to do anything
+ %% since the intersection will be empty.
+ cse_successors_1(Ls, Es0, M);
+ #{L:=Es1} ->
+ %% Calculate the intersection of the two maps.
+ %% Both keys and values must match.
+ Es = maps:filter(fun(Key, Value) ->
+ case Es1 of
+ #{Key:=Value} -> true;
+ #{} -> false
+ end
+ end, Es0),
+ cse_successors_1(Ls, Es0, M#{L:=Es});
+ #{} ->
+ cse_successors_1(Ls, Es0, M#{L=>Es0})
+ end;
+cse_successors_1([], _, M) -> M.
+
+cse_is([#b_set{op=succeeded,dst=Bool,args=[Src]}=I0|Is], Es, Sub0, Acc) ->
+ I = sub(I0, Sub0),
+ case I of
+ #b_set{args=[Src]} ->
+ cse_is(Is, Es, Sub0, [I|Acc]);
+ #b_set{} ->
+ %% The previous instruction has been eliminated. Eliminate the
+ %% 'succeeded' instruction too.
+ Sub = Sub0#{Bool=>#b_literal{val=true}},
+ cse_is(Is, Es, Sub, Acc)
+ end;
+cse_is([#b_set{dst=Dst}=I0|Is], Es0, Sub0, Acc) ->
+ I = sub(I0, Sub0),
+ case beam_ssa:clobbers_xregs(I) of
+ true ->
+ %% Retaining the expressions map across calls and other
+ %% clobbering instructions would work, but it would cause
+ %% the common subexpressions to be saved to Y registers,
+ %% which would probably increase the size of the stack
+ %% frame.
+ cse_is(Is, #{}, Sub0, [I|Acc]);
+ false ->
+ case cse_expr(I) of
+ none ->
+ %% Not suitable for CSE.
+ cse_is(Is, Es0, Sub0, [I|Acc]);
+ {ok,ExprKey} ->
+ case Es0 of
+ #{ExprKey:=Src} ->
+ Sub = Sub0#{Dst=>Src},
+ cse_is(Is, Es0, Sub, Acc);
+ #{} ->
+ Es = Es0#{ExprKey=>Dst},
+ cse_is(Is, Es, Sub0, [I|Acc])
+ end
+ end
+ end;
+cse_is([], Es, Sub, Acc) ->
+ {Acc,Es,Sub}.
+
+cse_expr(#b_set{op=Op,args=Args}=I) ->
+ case cse_suitable(I) of
+ true -> {ok,{Op,Args}};
+ false -> none
+ end.
+
+cse_suitable(#b_set{op=get_hd}) -> true;
+cse_suitable(#b_set{op=get_tl}) -> true;
+cse_suitable(#b_set{op=put_list}) -> true;
+cse_suitable(#b_set{op=get_tuple_element}) -> true;
+cse_suitable(#b_set{op=put_tuple}) -> true;
+cse_suitable(#b_set{op={bif,tuple_size}}) ->
+ %% Doing CSE for tuple_size/1 can prevent the
+ %% creation of test_arity and select_tuple_arity
+ %% instructions. That could decrease performance
+ %% and beam_validator could fail to understand
+ %% that tuple operations that follow are safe.
+ false;
+cse_suitable(#b_set{anno=Anno,op={bif,Name},args=Args}) ->
+ %% Doing CSE for floating point operators is unsafe.
+ %% Doing CSE for comparison operators would prevent
+ %% creation of 'test' instructions.
+ Arity = length(Args),
+ not (is_map_key(float_op, Anno) orelse
+ erl_internal:new_type_test(Name, Arity) orelse
+ erl_internal:comp_op(Name, Arity) orelse
+ erl_internal:bool_op(Name, Arity));
+cse_suitable(#b_set{}) -> false.
+
+%%%
+%%% Using floating point instructions.
+%%%
+%%% Use the special floating points version of arithmetic
+%%% instructions, if the operands are known to be floats or the result
+%%% of the operation will be a float.
+%%%
+%%% The float instructions were never used in guards before, so we
+%%% will take special care to keep not using them in guards. Using
+%%% them in guards would require a new version of the 'fconv'
+%%% instruction that would take a failure label. Since it is unlikely
+%%% that using float instructions in guards would be benefical, why
+%%% bother implementing a new instruction? Also, implementing float
+%%% instructions in guards in HiPE could turn out to be a lot of work.
+%%%
+
+-record(fs,
+ {s=undefined :: 'undefined' | 'cleared',
+ regs=#{} :: #{beam_ssa:b_var():=beam_ssa:b_var()},
+ fail=none :: 'none' | beam_ssa:label(),
+ non_guards :: gb_sets:set(beam_ssa:label()),
+ bs :: beam_ssa:block_map()
+ }).
+
+ssa_opt_float({#st{ssa=Linear0,cnt=Count0}=St, FuncDb}) ->
+ NonGuards0 = float_non_guards(Linear0),
+ NonGuards = gb_sets:from_list(NonGuards0),
+ Blocks = maps:from_list(Linear0),
+ Fs = #fs{non_guards=NonGuards,bs=Blocks},
+ {Linear,Count} = float_opt(Linear0, Count0, Fs),
+ {St#st{ssa=Linear,cnt=Count}, FuncDb}.
+
+float_blk_is_in_guard(#b_blk{last=#b_br{fail=F}}, #fs{non_guards=NonGuards}) ->
+ not gb_sets:is_member(F, NonGuards);
+float_blk_is_in_guard(#b_blk{}, #fs{}) ->
+ false.
+
+float_non_guards([{L,#b_blk{is=Is}}|Bs]) ->
+ case Is of
+ [#b_set{op=landingpad}|_] ->
+ [L|float_non_guards(Bs)];
+ _ ->
+ float_non_guards(Bs)
+ end;
+float_non_guards([]) -> [?BADARG_BLOCK].
+
+float_opt([{L,Blk}|Bs0], Count0, Fs) ->
+ case float_blk_is_in_guard(Blk, Fs) of
+ true ->
+ %% This block is inside a guard. Don't do
+ %% any floating point optimizations.
+ {Bs,Count} = float_opt(Bs0, Count0, Fs),
+ {[{L,Blk}|Bs],Count};
+ false ->
+ %% This block is not inside a guard.
+ %% We can do the optimization.
+ float_opt_1(L, Blk, Bs0, Count0, Fs)
+ end;
+float_opt([], Count, _Fs) ->
+ {[],Count}.
+
+float_opt_1(L, #b_blk{is=Is0}=Blk0, Bs0, Count0, Fs0) ->
+ case float_opt_is(Is0, Fs0, Count0, []) of
+ {Is1,Fs1,Count1} ->
+ Fs2 = float_fail_label(Blk0, Fs1),
+ Fail = Fs2#fs.fail,
+ {Flush,Blk,Fs,Count2} = float_maybe_flush(Blk0, Fs2, Count1),
+ Split = float_split_conv(Is1, Blk),
+ {Blks0,Count3} = float_number(Split, L, Count2),
+ {Blks,Count4} = float_conv(Blks0, Fail, Count3),
+ {Bs,Count} = float_opt(Bs0, Count4, Fs),
+ {Blks++Flush++Bs,Count};
+ none ->
+ {Bs,Count} = float_opt(Bs0, Count0, Fs0),
+ {[{L,Blk0}|Bs],Count}
+ end.
+
+%% Split {float,convert} instructions into individual blocks.
+float_split_conv(Is0, Blk) ->
+ Br = #b_br{bool=#b_literal{val=true},succ=0,fail=0},
+ case splitwith(fun(#b_set{op=Op}) ->
+ Op =/= {float,convert}
+ end, Is0) of
+ {Is,[]} ->
+ [Blk#b_blk{is=Is}];
+ {[_|_]=Is1,[#b_set{op={float,convert}}=Conv|Is2]} ->
+ [#b_blk{is=Is1,last=Br},
+ #b_blk{is=[Conv],last=Br}|float_split_conv(Is2, Blk)];
+ {[],[#b_set{op={float,convert}}=Conv|Is1]} ->
+ [#b_blk{is=[Conv],last=Br}|float_split_conv(Is1, Blk)]
+ end.
+
+%% Number the blocks that were split.
+float_number([B|Bs0], FirstL, Count0) ->
+ {Bs,Count} = float_number(Bs0, Count0),
+ {[{FirstL,B}|Bs],Count}.
+
+float_number([B|Bs0], Count0) ->
+ {Bs,Count} = float_number(Bs0, Count0+1),
+ {[{Count0,B}|Bs],Count};
+float_number([], Count) ->
+ {[],Count}.
+
+%% Insert 'succeeded' instructions after each {float,convert}
+%% instruction.
+float_conv([{L,#b_blk{is=Is0}=Blk0}|Bs0], Fail, Count0) ->
+ case Is0 of
+ [#b_set{op={float,convert}}=Conv] ->
+ {Bool0,Count1} = new_reg('@ssa_bool', Count0),
+ Bool = #b_var{name=Bool0},
+ Succeeded = #b_set{op=succeeded,dst=Bool,
+ args=[Conv#b_set.dst]},
+ Is = [Conv,Succeeded],
+ [{NextL,_}|_] = Bs0,
+ Br = #b_br{bool=Bool,succ=NextL,fail=Fail},
+ Blk = Blk0#b_blk{is=Is,last=Br},
+ {Bs,Count} = float_conv(Bs0, Fail, Count1),
+ {[{L,Blk}|Bs],Count};
+ [_|_] ->
+ case Bs0 of
+ [{NextL,_}|_] ->
+ Br = #b_br{bool=#b_literal{val=true},
+ succ=NextL,fail=NextL},
+ Blk = Blk0#b_blk{last=Br},
+ {Bs,Count} = float_conv(Bs0, Fail, Count0),
+ {[{L,Blk}|Bs],Count};
+ [] ->
+ {[{L,Blk0}],Count0}
+ end
+ end.
+
+float_maybe_flush(Blk0, #fs{s=cleared,fail=Fail,bs=Blocks}=Fs0, Count0) ->
+ #b_blk{last=#b_br{bool=#b_var{},succ=Succ}=Br} = Blk0,
+
+ %% If the success block starts with a floating point operation, we can
+ %% defer flushing to that block as long as it isn't a guard.
+ #b_blk{is=Is} = SuccBlk = map_get(Succ, Blocks),
+ SuccIsGuard = float_blk_is_in_guard(SuccBlk, Fs0),
+
+ case Is of
+ [#b_set{anno=#{float_op:=_}}|_] when not SuccIsGuard ->
+ %% No flush needed.
+ {[],Blk0,Fs0,Count0};
+ _ ->
+ %% Flush needed.
+ {Bool0,Count1} = new_reg('@ssa_bool', Count0),
+ Bool = #b_var{name=Bool0},
+
+ %% Allocate block numbers.
+ CheckL = Count1, %For checkerror.
+ FlushL = Count1 + 1, %For flushing of float regs.
+ Count = Count1 + 2,
+ Blk = Blk0#b_blk{last=Br#b_br{succ=CheckL}},
+
+ %% Build the block with the checkerror instruction.
+ CheckIs = [#b_set{op={float,checkerror},dst=Bool}],
+ CheckBr = #b_br{bool=Bool,succ=FlushL,fail=Fail},
+ CheckBlk = #b_blk{is=CheckIs,last=CheckBr},
+
+ %% Build the block that flushes all registers.
+ FlushIs = float_flush_regs(Fs0),
+ FlushBr = #b_br{bool=#b_literal{val=true},succ=Succ,fail=Succ},
+ FlushBlk = #b_blk{is=FlushIs,last=FlushBr},
+
+ %% Update state and blocks.
+ Fs = Fs0#fs{s=undefined,regs=#{},fail=none},
+ FlushBs = [{CheckL,CheckBlk},{FlushL,FlushBlk}],
+ {FlushBs,Blk,Fs,Count}
+ end;
+float_maybe_flush(Blk, Fs, Count) ->
+ {[],Blk,Fs,Count}.
+
+float_opt_is([#b_set{op=succeeded,args=[Src]}=I0],
+ #fs{regs=Rs}=Fs, Count, Acc) ->
+ case Rs of
+ #{Src:=Fr} ->
+ I = I0#b_set{args=[Fr]},
+ {reverse(Acc, [I]),Fs,Count};
+ #{} ->
+ {reverse(Acc, [I0]),Fs,Count}
+ end;
+float_opt_is([#b_set{anno=Anno0}=I0|Is0], Fs0, Count0, Acc) ->
+ case Anno0 of
+ #{float_op:=FTypes} ->
+ Anno = maps:remove(float_op, Anno0),
+ I1 = I0#b_set{anno=Anno},
+ {Is,Fs,Count} = float_make_op(I1, FTypes, Fs0, Count0),
+ float_opt_is(Is0, Fs, Count, reverse(Is, Acc));
+ #{} ->
+ float_opt_is(Is0, Fs0#fs{regs=#{}}, Count0, [I0|Acc])
+ end;
+float_opt_is([], Fs, _Count, _Acc) ->
+ #fs{s=undefined} = Fs, %Assertion.
+ none.
+
+float_make_op(#b_set{op={bif,Op},dst=Dst,args=As0}=I0,
+ Ts, #fs{s=S,regs=Rs0}=Fs, Count0) ->
+ {As1,Rs1,Count1} = float_load(As0, Ts, Rs0, Count0, []),
+ {As,Is0} = unzip(As1),
+ {Fr,Count2} = new_reg('@fr', Count1),
+ FrDst = #b_var{name=Fr},
+ I = I0#b_set{op={float,Op},dst=FrDst,args=As},
+ Rs = Rs1#{Dst=>FrDst},
+ Is = append(Is0) ++ [I],
+ case S of
+ undefined ->
+ {Ignore,Count} = new_reg('@ssa_ignore', Count2),
+ C = #b_set{op={float,clearerror},dst=#b_var{name=Ignore}},
+ {[C|Is],Fs#fs{s=cleared,regs=Rs},Count};
+ cleared ->
+ {Is,Fs#fs{regs=Rs},Count2}
+ end.
+
+float_load([A|As], [T|Ts], Rs0, Count0, Acc) ->
+ {Load,Rs,Count} = float_reg_arg(A, T, Rs0, Count0),
+ float_load(As, Ts, Rs, Count, [Load|Acc]);
+float_load([], [], Rs, Count, Acc) ->
+ {reverse(Acc),Rs,Count}.
+
+float_reg_arg(A, T, Rs, Count0) ->
+ case Rs of
+ #{A:=Fr} ->
+ {{Fr,[]},Rs,Count0};
+ #{} ->
+ {Fr,Count} = new_float_copy_reg(Count0),
+ Dst = #b_var{name=Fr},
+ I = float_load_reg(T, A, Dst),
+ {{Dst,[I]},Rs#{A=>Dst},Count}
+ end.
+
+float_load_reg(convert, #b_var{}=Src, Dst) ->
+ #b_set{op={float,convert},dst=Dst,args=[Src]};
+float_load_reg(convert, #b_literal{val=Val}=Src, Dst) ->
+ try float(Val) of
+ F ->
+ #b_set{op={float,put},dst=Dst,args=[#b_literal{val=F}]}
+ catch
+ error:_ ->
+ %% Let the exception happen at runtime.
+ #b_set{op={float,convert},dst=Dst,args=[Src]}
+ end;
+float_load_reg(float, Src, Dst) ->
+ #b_set{op={float,put},dst=Dst,args=[Src]}.
+
+new_float_copy_reg(Count) ->
+ new_reg('@fr_copy', Count).
+
+new_reg(Base, Count) ->
+ Fr = {Base,Count},
+ {Fr,Count+1}.
+
+float_fail_label(#b_blk{last=Last}, Fs) ->
+ case Last of
+ #b_br{bool=#b_var{},fail=Fail} ->
+ Fs#fs{fail=Fail};
+ _ ->
+ Fs
+ end.
+
+float_flush_regs(#fs{regs=Rs}) ->
+ maps:fold(fun(_, #b_var{name={'@fr_copy',_}}, Acc) ->
+ Acc;
+ (Dst, Fr, Acc) ->
+ [#b_set{op={float,get},dst=Dst,args=[Fr]}|Acc]
+ end, [], Rs).
+
+%%%
+%%% Live optimization.
+%%%
+%%% Optimize instructions whose values are not used. They could be
+%%% removed if they have no side effects, or in a few cases replaced
+%%% with a cheaper instructions
+%%%
+
+ssa_opt_live({#st{ssa=Linear0}=St, FuncDb}) ->
+ RevLinear = reverse(Linear0),
+ Blocks0 = maps:from_list(RevLinear),
+ Blocks = live_opt(RevLinear, #{}, Blocks0),
+ Linear = beam_ssa:linearize(Blocks),
+ {St#st{ssa=Linear}, FuncDb}.
+
+live_opt([{L,Blk0}|Bs], LiveMap0, Blocks) ->
+ Blk1 = beam_ssa_share:block(Blk0, Blocks),
+ Successors = beam_ssa:successors(Blk1),
+ Live0 = live_opt_succ(Successors, L, LiveMap0, gb_sets:empty()),
+ {Blk,Live} = live_opt_blk(Blk1, Live0),
+ LiveMap = live_opt_phis(Blk#b_blk.is, L, Live, LiveMap0),
+ live_opt(Bs, LiveMap, Blocks#{L:=Blk});
+live_opt([], _, Acc) -> Acc.
+
+live_opt_succ([S|Ss], L, LiveMap, Live0) ->
+ Key = {S,L},
+ case LiveMap of
+ #{Key:=Live} ->
+ %% The successor has a phi node, and the value for
+ %% this block in the phi node is a variable.
+ live_opt_succ(Ss, L, LiveMap, gb_sets:union(Live, Live0));
+ #{S:=Live} ->
+ %% No phi node in the successor, or the value for
+ %% this block in the phi node is a literal.
+ live_opt_succ(Ss, L, LiveMap, gb_sets:union(Live, Live0));
+ #{} ->
+ %% A peek_message block which has not been processed yet.
+ live_opt_succ(Ss, L, LiveMap, Live0)
+ end;
+live_opt_succ([], _, _, Acc) -> Acc.
+
+live_opt_phis(Is, L, Live0, LiveMap0) ->
+ LiveMap = LiveMap0#{L=>Live0},
+ Phis = takewhile(fun(#b_set{op=Op}) -> Op =:= phi end, Is),
+ case Phis of
+ [] ->
+ LiveMap;
+ [_|_] ->
+ PhiArgs = append([Args || #b_set{args=Args} <- Phis]),
+ case [{P,V} || {#b_var{}=V,P} <- PhiArgs] of
+ [_|_]=PhiVars ->
+ PhiLive0 = rel2fam(PhiVars),
+ PhiLive = [{{L,P},gb_sets:union(gb_sets:from_list(Vs), Live0)} ||
+ {P,Vs} <- PhiLive0],
+ maps:merge(LiveMap, maps:from_list(PhiLive));
+ [] ->
+ %% There were only literals in the phi node(s).
+ LiveMap
+ end
+ end.
+
+live_opt_blk(#b_blk{is=Is0,last=Last}=Blk, Live0) ->
+ Live1 = gb_sets:union(Live0, gb_sets:from_ordset(beam_ssa:used(Last))),
+ {Is,Live} = live_opt_is(reverse(Is0), Live1, []),
+ {Blk#b_blk{is=Is},Live}.
+
+live_opt_is([#b_set{op=phi,dst=Dst}=I|Is], Live, Acc) ->
+ case gb_sets:is_member(Dst, Live) of
+ true ->
+ live_opt_is(Is, Live, [I|Acc]);
+ false ->
+ live_opt_is(Is, Live, Acc)
+ end;
+live_opt_is([#b_set{op=succeeded,dst=SuccDst=SuccDstVar,
+ args=[Dst]}=SuccI,
+ #b_set{dst=Dst}=I|Is], Live0, Acc) ->
+ case gb_sets:is_member(Dst, Live0) of
+ true ->
+ Live1 = gb_sets:add(Dst, Live0),
+ Live = gb_sets:delete_any(SuccDst, Live1),
+ live_opt_is([I|Is], Live, [SuccI|Acc]);
+ false ->
+ case live_opt_unused(I) of
+ {replace,NewI0} ->
+ NewI = NewI0#b_set{dst=SuccDstVar},
+ live_opt_is([NewI|Is], Live0, Acc);
+ keep ->
+ case gb_sets:is_member(SuccDst, Live0) of
+ true ->
+ Live1 = gb_sets:add(Dst, Live0),
+ Live = gb_sets:delete(SuccDst, Live1),
+ live_opt_is([I|Is], Live, [SuccI|Acc]);
+ false ->
+ live_opt_is([I|Is], Live0, Acc)
+ end
+ end
+ end;
+live_opt_is([#b_set{dst=Dst}=I|Is], Live0, Acc) ->
+ case gb_sets:is_member(Dst, Live0) of
+ true ->
+ Live1 = gb_sets:union(Live0, gb_sets:from_ordset(beam_ssa:used(I))),
+ Live = gb_sets:delete(Dst, Live1),
+ live_opt_is(Is, Live, [I|Acc]);
+ false ->
+ case beam_ssa:no_side_effect(I) of
+ true ->
+ live_opt_is(Is, Live0, Acc);
+ false ->
+ Live = gb_sets:union(Live0, gb_sets:from_ordset(beam_ssa:used(I))),
+ live_opt_is(Is, Live, [I|Acc])
+ end
+ end;
+live_opt_is([], Live, Acc) ->
+ {Acc,Live}.
+
+live_opt_unused(#b_set{op=get_map_element}=Set) ->
+ {replace,Set#b_set{op=has_map_field}};
+live_opt_unused(_) -> keep.
+
+%%%
+%%% Optimize binary matching.
+%%%
+%%% * If the value of segment is never extracted, rewrite
+%%% to a bs_skip instruction.
+%%%
+%%% * Coalesce adjacent bs_skip instructions and skip instructions
+%%% with bs_test_tail.
+%%%
+
+ssa_opt_bsm({#st{ssa=Linear}=St, FuncDb}) ->
+ Extracted0 = bsm_extracted(Linear),
+ Extracted = cerl_sets:from_list(Extracted0),
+ {St#st{ssa=bsm_skip(Linear, Extracted)}, FuncDb}.
+
+bsm_skip([{L,#b_blk{is=Is0}=Blk}|Bs0], Extracted) ->
+ Bs = bsm_skip(Bs0, Extracted),
+ Is = bsm_skip_is(Is0, Extracted),
+ coalesce_skips({L,Blk#b_blk{is=Is}}, Bs);
+bsm_skip([], _) -> [].
+
+bsm_skip_is([I0|Is], Extracted) ->
+ case I0 of
+ #b_set{op=bs_match,
+ dst=Ctx,
+ args=[#b_literal{val=T}=Type,PrevCtx|Args0]}
+ when T =/= string, T =/= skip ->
+ I = case cerl_sets:is_element(Ctx, Extracted) of
+ true ->
+ I0;
+ false ->
+ %% The value is never extracted.
+ Args = [#b_literal{val=skip},PrevCtx,Type|Args0],
+ I0#b_set{args=Args}
+ end,
+ [I|Is];
+ #b_set{} ->
+ [I0|bsm_skip_is(Is, Extracted)]
+ end;
+bsm_skip_is([], _) -> [].
+
+bsm_extracted([{_,#b_blk{is=Is}}|Bs]) ->
+ case Is of
+ [#b_set{op=bs_extract,args=[Ctx]}|_] ->
+ [Ctx|bsm_extracted(Bs)];
+ _ ->
+ bsm_extracted(Bs)
+ end;
+bsm_extracted([]) -> [].
+
+coalesce_skips({L,#b_blk{is=[#b_set{op=bs_extract}=Extract|Is0],
+ last=Last0}=Blk0}, Bs0) ->
+ case coalesce_skips_is(Is0, Last0, Bs0) of
+ not_possible ->
+ [{L,Blk0}|Bs0];
+ {Is,Last,Bs} ->
+ Blk = Blk0#b_blk{is=[Extract|Is],last=Last},
+ [{L,Blk}|Bs]
+ end;
+coalesce_skips({L,#b_blk{is=Is0,last=Last0}=Blk0}, Bs0) ->
+ case coalesce_skips_is(Is0, Last0, Bs0) of
+ not_possible ->
+ [{L,Blk0}|Bs0];
+ {Is,Last,Bs} ->
+ Blk = Blk0#b_blk{is=Is,last=Last},
+ [{L,Blk}|Bs]
+ end.
+
+coalesce_skips_is([#b_set{op=bs_match,
+ args=[#b_literal{val=skip},
+ Ctx0,Type,Flags,
+ #b_literal{val=Size0},
+ #b_literal{val=Unit0}]}=Skip0,
+ #b_set{op=succeeded}],
+ #b_br{succ=L2,fail=Fail}=Br0,
+ Bs0) when is_integer(Size0) ->
+ case Bs0 of
+ [{L2,#b_blk{is=[#b_set{op=bs_match,
+ dst=SkipDst,
+ args=[#b_literal{val=skip},_,_,_,
+ #b_literal{val=Size1},
+ #b_literal{val=Unit1}]},
+ #b_set{op=succeeded}=Succeeded],
+ last=#b_br{fail=Fail}=Br}}|Bs] when is_integer(Size1) ->
+ SkipBits = Size0 * Unit0 + Size1 * Unit1,
+ Skip = Skip0#b_set{dst=SkipDst,
+ args=[#b_literal{val=skip},Ctx0,
+ Type,Flags,
+ #b_literal{val=SkipBits},
+ #b_literal{val=1}]},
+ Is = [Skip,Succeeded],
+ {Is,Br,Bs};
+ [{L2,#b_blk{is=[#b_set{op=bs_test_tail,
+ args=[_Ctx,#b_literal{val=TailSkip}]}],
+ last=#b_br{succ=NextSucc,fail=Fail}}}|Bs] ->
+ SkipBits = Size0 * Unit0,
+ TestTail = Skip0#b_set{op=bs_test_tail,
+ args=[Ctx0,#b_literal{val=SkipBits+TailSkip}]},
+ Br = Br0#b_br{bool=TestTail#b_set.dst,succ=NextSucc},
+ Is = [TestTail],
+ {Is,Br,Bs};
+ _ ->
+ not_possible
+ end;
+coalesce_skips_is(_, _, _) ->
+ not_possible.
+
+%%%
+%%% Short-cutting binary matching instructions.
+%%%
+
+ssa_opt_bsm_shortcut({#st{ssa=Linear}=St, FuncDb}) ->
+ Positions = bsm_positions(Linear, #{}),
+ case map_size(Positions) of
+ 0 ->
+ %% No binary matching instructions.
+ {St, FuncDb};
+ _ ->
+ {St#st{ssa=bsm_shortcut(Linear, Positions)}, FuncDb}
+ end.
+
+bsm_positions([{L,#b_blk{is=Is,last=Last}}|Bs], PosMap0) ->
+ PosMap = bsm_positions_is(Is, PosMap0),
+ case {Is,Last} of
+ {[#b_set{op=bs_test_tail,dst=Bool,args=[Ctx,#b_literal{val=Bits0}]}],
+ #b_br{bool=Bool,fail=Fail}} ->
+ Bits = Bits0 + map_get(Ctx, PosMap0),
+ bsm_positions(Bs, PosMap#{L=>{Bits,Fail}});
+ {_,_} ->
+ bsm_positions(Bs, PosMap)
+ end;
+bsm_positions([], PosMap) -> PosMap.
+
+bsm_positions_is([#b_set{op=bs_start_match,dst=New}|Is], PosMap0) ->
+ PosMap = PosMap0#{New=>0},
+ bsm_positions_is(Is, PosMap);
+bsm_positions_is([#b_set{op=bs_match,dst=New,args=Args}|Is], PosMap0) ->
+ [_,Old|_] = Args,
+ #{Old:=Bits0} = PosMap0,
+ Bits = bsm_update_bits(Args, Bits0),
+ PosMap = PosMap0#{New=>Bits},
+ bsm_positions_is(Is, PosMap);
+bsm_positions_is([_|Is], PosMap) ->
+ bsm_positions_is(Is, PosMap);
+bsm_positions_is([], PosMap) -> PosMap.
+
+bsm_update_bits([#b_literal{val=string},_,#b_literal{val=String}], Bits) ->
+ Bits + bit_size(String);
+bsm_update_bits([#b_literal{val=utf8}|_], Bits) ->
+ Bits + 8;
+bsm_update_bits([#b_literal{val=utf16}|_], Bits) ->
+ Bits + 16;
+bsm_update_bits([#b_literal{val=utf32}|_], Bits) ->
+ Bits + 32;
+bsm_update_bits([_,_,_,#b_literal{val=Sz},#b_literal{val=U}], Bits)
+ when is_integer(Sz) ->
+ Bits + Sz*U;
+bsm_update_bits(_, Bits) -> Bits.
+
+bsm_shortcut([{L,#b_blk{is=Is,last=Last0}=Blk}|Bs], PosMap) ->
+ case {Is,Last0} of
+ {[#b_set{op=bs_match,dst=New,args=[_,Old|_]},
+ #b_set{op=succeeded,dst=Bool,args=[New]}],
+ #b_br{bool=Bool,fail=Fail}} ->
+ case PosMap of
+ #{Old:=Bits,Fail:={TailBits,NextFail}} when Bits > TailBits ->
+ Last = Last0#b_br{fail=NextFail},
+ [{L,Blk#b_blk{last=Last}}|bsm_shortcut(Bs, PosMap)];
+ #{} ->
+ [{L,Blk}|bsm_shortcut(Bs, PosMap)]
+ end;
+ {_,_} ->
+ [{L,Blk}|bsm_shortcut(Bs, PosMap)]
+ end;
+bsm_shortcut([], _PosMap) -> [].
+
+%%%
+%%% Eliminate redundant bs_test_unit2 instructions.
+%%%
+
+ssa_opt_bsm_units({#st{ssa=Linear}=St, FuncDb}) ->
+ {St#st{ssa=bsm_units(Linear, #{})}, FuncDb}.
+
+bsm_units([{L,#b_blk{last=#b_br{succ=Succ,fail=Fail}}=Block0} | Bs], UnitMaps0) ->
+ UnitsIn = maps:get(L, UnitMaps0, #{}),
+ {Block, UnitsOut} = bsm_units_skip(Block0, UnitsIn),
+ UnitMaps1 = bsm_units_join(Succ, UnitsOut, UnitMaps0),
+ UnitMaps = bsm_units_join(Fail, UnitsIn, UnitMaps1),
+ [{L, Block} | bsm_units(Bs, UnitMaps)];
+bsm_units([{L,#b_blk{last=#b_switch{fail=Fail,list=Switch}}=Block} | Bs], UnitMaps0) ->
+ UnitsIn = maps:get(L, UnitMaps0, #{}),
+ Labels = [Fail | [Lbl || {_Arg, Lbl} <- Switch]],
+ UnitMaps = foldl(fun(Lbl, UnitMaps) ->
+ bsm_units_join(Lbl, UnitsIn, UnitMaps)
+ end, UnitMaps0, Labels),
+ [{L, Block} | bsm_units(Bs, UnitMaps)];
+bsm_units([{L, Block} | Bs], UnitMaps) ->
+ [{L, Block} | bsm_units(Bs, UnitMaps)];
+bsm_units([], _UnitMaps) ->
+ [].
+
+bsm_units_skip(Block, Units) ->
+ bsm_units_skip_1(Block#b_blk.is, Block, Units).
+
+bsm_units_skip_1([#b_set{op=bs_start_match,dst=New}|_], Block, Units) ->
+ %% We bail early since there can't be more than one match per block.
+ {Block, Units#{ New => 1 }};
+bsm_units_skip_1([#b_set{op=bs_match,
+ dst=New,
+ args=[#b_literal{val=skip},
+ Ctx,
+ #b_literal{val=binary},
+ _Flags,
+ #b_literal{val=all},
+ #b_literal{val=OpUnit}]}=Skip | Test],
+ Block0, Units) ->
+ [#b_set{op=succeeded,dst=Bool,args=[New]}] = Test, %Assertion.
+ #b_br{bool=Bool} = Last0 = Block0#b_blk.last, %Assertion.
+ CtxUnit = map_get(Ctx, Units),
+ if
+ CtxUnit rem OpUnit =:= 0 ->
+ Is = takewhile(fun(I) -> I =/= Skip end, Block0#b_blk.is),
+ Last = Last0#b_br{bool=#b_literal{val=true}},
+ Block = Block0#b_blk{is=Is,last=Last},
+ {Block, Units#{ New => CtxUnit }};
+ CtxUnit rem OpUnit =/= 0 ->
+ {Block0, Units#{ New => OpUnit, Ctx => OpUnit }}
+ end;
+bsm_units_skip_1([#b_set{op=bs_match,dst=New,args=Args}|_], Block, Units) ->
+ [_,Ctx|_] = Args,
+ CtxUnit = map_get(Ctx, Units),
+ OpUnit = bsm_op_unit(Args),
+ {Block, Units#{ New => gcd(OpUnit, CtxUnit) }};
+bsm_units_skip_1([_I | Is], Block, Units) ->
+ bsm_units_skip_1(Is, Block, Units);
+bsm_units_skip_1([], Block, Units) ->
+ {Block, Units}.
+
+bsm_op_unit([_,_,_,Size,#b_literal{val=U}]) ->
+ case Size of
+ #b_literal{val=Sz} when is_integer(Sz) -> Sz*U;
+ _ -> U
+ end;
+bsm_op_unit([#b_literal{val=string},_,#b_literal{val=String}]) ->
+ bit_size(String);
+bsm_op_unit([#b_literal{val=utf8}|_]) ->
+ 8;
+bsm_op_unit([#b_literal{val=utf16}|_]) ->
+ 16;
+bsm_op_unit([#b_literal{val=utf32}|_]) ->
+ 32;
+bsm_op_unit(_) ->
+ 1.
+
+%% Several paths can lead to the same match instruction and the inferred units
+%% may differ between them, so we can only keep the information that is common
+%% to all paths.
+bsm_units_join(Lbl, MapA, UnitMaps0) when is_map_key(Lbl, UnitMaps0) ->
+ MapB = map_get(Lbl, UnitMaps0),
+ Merged = if
+ map_size(MapB) =< map_size(MapA) ->
+ bsm_units_join_1(maps:keys(MapB), MapA, MapB);
+ map_size(MapB) > map_size(MapA) ->
+ bsm_units_join_1(maps:keys(MapA), MapB, MapA)
+ end,
+ UnitMaps0#{Lbl := Merged};
+bsm_units_join(Lbl, MapA, UnitMaps0) when MapA =/= #{} ->
+ UnitMaps0#{Lbl => MapA};
+bsm_units_join(_Lbl, _MapA, UnitMaps0) ->
+ UnitMaps0.
+
+bsm_units_join_1([Key | Keys], Left, Right) when is_map_key(Key, Left) ->
+ UnitA = map_get(Key, Left),
+ UnitB = map_get(Key, Right),
+ bsm_units_join_1(Keys, Left, Right#{Key := gcd(UnitA, UnitB)});
+bsm_units_join_1([Key | Keys], Left, Right) ->
+ bsm_units_join_1(Keys, Left, maps:remove(Key, Right));
+bsm_units_join_1([], _MapA, Right) ->
+ Right.
+
+%%%
+%%% Optimize binary construction.
+%%%
+%%% If an integer segment or a float segment has a literal size and
+%%% a literal value, convert to a binary segment. Coalesce adjacent
+%%% literal binary segments. Literal binary segments will be converted
+%%% to bs_put_string instructions in later pass.
+%%%
+
+ssa_opt_bs_puts({#st{ssa=Linear0,cnt=Count0}=St, FuncDb}) ->
+ {Linear,Count} = opt_bs_puts(Linear0, Count0, []),
+ {St#st{ssa=Linear,cnt=Count}, FuncDb}.
+
+opt_bs_puts([{L,#b_blk{is=Is}=Blk0}|Bs], Count0, Acc0) ->
+ case Is of
+ [#b_set{op=bs_put}=I0] ->
+ case opt_bs_put(L, I0, Blk0, Count0, Acc0) of
+ not_possible ->
+ opt_bs_puts(Bs, Count0, [{L,Blk0}|Acc0]);
+ {Count,Acc1} ->
+ Acc = opt_bs_puts_merge(Acc1),
+ opt_bs_puts(Bs, Count, Acc)
+ end;
+ _ ->
+ opt_bs_puts(Bs, Count0, [{L,Blk0}|Acc0])
+ end;
+opt_bs_puts([], Count, Acc) ->
+ {reverse(Acc),Count}.
+
+opt_bs_puts_merge([{L1,#b_blk{is=Is}=Blk0},{L2,#b_blk{is=AccIs}}=BAcc|Acc]) ->
+ case {AccIs,Is} of
+ {[#b_set{op=bs_put,
+ args=[#b_literal{val=binary},
+ #b_literal{},
+ #b_literal{val=Bin0},
+ #b_literal{val=all},
+ #b_literal{val=1}]}],
+ [#b_set{op=bs_put,
+ args=[#b_literal{val=binary},
+ #b_literal{},
+ #b_literal{val=Bin1},
+ #b_literal{val=all},
+ #b_literal{val=1}]}=I0]} ->
+ %% Coalesce the two segments to one.
+ Bin = <<Bin0/bitstring,Bin1/bitstring>>,
+ I = I0#b_set{args=bs_put_args(binary, Bin, all)},
+ Blk = Blk0#b_blk{is=[I]},
+ [{L2,Blk}|Acc];
+ {_,_} ->
+ [{L1,Blk0},BAcc|Acc]
+ end.
+
+opt_bs_put(L, I0, #b_blk{last=Br0}=Blk0, Count0, Acc) ->
+ case opt_bs_put(I0) of
+ [Bin] when is_bitstring(Bin) ->
+ Args = bs_put_args(binary, Bin, all),
+ I = I0#b_set{args=Args},
+ Blk = Blk0#b_blk{is=[I]},
+ {Count0,[{L,Blk}|Acc]};
+ [{int,Int,Size},Bin] when is_bitstring(Bin) ->
+ %% Construct a bs_put_integer instruction following
+ %% by a bs_put_binary instruction.
+ IntArgs = bs_put_args(integer, Int, Size),
+ BinArgs = bs_put_args(binary, Bin, all),
+ {BinL,BinVarNum} = {Count0,Count0+1},
+ Count = Count0 + 2,
+ BinVar = #b_var{name={'@ssa_bool',BinVarNum}},
+ BinI = I0#b_set{dst=BinVar,args=BinArgs},
+ BinBlk = Blk0#b_blk{is=[BinI],last=Br0#b_br{bool=BinVar}},
+ IntI = I0#b_set{args=IntArgs},
+ IntBlk = Blk0#b_blk{is=[IntI],last=Br0#b_br{succ=BinL}},
+ {Count,[{BinL,BinBlk},{L,IntBlk}|Acc]};
+ not_possible ->
+ not_possible
+ end.
+
+opt_bs_put(#b_set{args=[#b_literal{val=binary},_,#b_literal{val=Val},
+ #b_literal{val=all},#b_literal{val=Unit}]})
+ when is_bitstring(Val) ->
+ if
+ bit_size(Val) rem Unit =:= 0 ->
+ [Val];
+ true ->
+ not_possible
+ end;
+opt_bs_put(#b_set{args=[#b_literal{val=Type},#b_literal{val=Flags},
+ #b_literal{val=Val},#b_literal{val=Size},
+ #b_literal{val=Unit}]}=I0) when is_integer(Size) ->
+ EffectiveSize = Size * Unit,
+ if
+ EffectiveSize > 0 ->
+ case {Type,opt_bs_put_endian(Flags)} of
+ {integer,big} when is_integer(Val) ->
+ if
+ EffectiveSize < 64 ->
+ [<<Val:EffectiveSize>>];
+ true ->
+ opt_bs_put_split_int(Val, EffectiveSize)
+ end;
+ {integer,little} when is_integer(Val), EffectiveSize < 128 ->
+ %% To avoid an explosion in code size, we only try
+ %% to optimize relatively small fields.
+ <<Int:EffectiveSize>> = <<Val:EffectiveSize/little>>,
+ Args = bs_put_args(Type, Int, EffectiveSize),
+ I = I0#b_set{args=Args},
+ opt_bs_put(I);
+ {binary,_} when is_bitstring(Val) ->
+ <<Bitstring:EffectiveSize/bits,_/bits>> = Val,
+ [Bitstring];
+ {float,Endian} ->
+ try
+ [opt_bs_put_float(Val, EffectiveSize, Endian)]
+ catch error:_ ->
+ not_possible
+ end;
+ {_,_} ->
+ not_possible
+ end;
+ true ->
+ not_possible
+ end;
+opt_bs_put(#b_set{}) -> not_possible.
+
+opt_bs_put_float(N, Sz, Endian) ->
+ case Endian of
+ big -> <<N:Sz/big-float-unit:1>>;
+ little -> <<N:Sz/little-float-unit:1>>
+ end.
+
+bs_put_args(Type, Val, Size) ->
+ [#b_literal{val=Type},
+ #b_literal{val=[unsigned,big]},
+ #b_literal{val=Val},
+ #b_literal{val=Size},
+ #b_literal{val=1}].
+
+opt_bs_put_endian([big=E|_]) -> E;
+opt_bs_put_endian([little=E|_]) -> E;
+opt_bs_put_endian([native=E|_]) -> E;
+opt_bs_put_endian([_|Fs]) -> opt_bs_put_endian(Fs).
+
+opt_bs_put_split_int(Int, Size) ->
+ Pos = opt_bs_put_split_int_1(Int, 0, Size - 1),
+ UpperSize = Size - Pos,
+ if
+ Pos =:= 0 ->
+ %% Value is 0 or -1 -- keep the original instruction.
+ not_possible;
+ UpperSize < 64 ->
+ %% No or few leading zeroes or ones.
+ [<<Int:Size>>];
+ true ->
+ %% There are 64 or more leading ones or zeroes in
+ %% the resulting binary. Split into two separate
+ %% segments to avoid an explosion in code size.
+ [{int,Int bsr Pos,UpperSize},<<Int:Pos>>]
+ end.
+
+opt_bs_put_split_int_1(_Int, L, R) when L > R ->
+ 8 * ((L + 7) div 8);
+opt_bs_put_split_int_1(Int, L, R) ->
+ Mid = (L + R) div 2,
+ case Int bsr Mid of
+ Upper when Upper =:= 0; Upper =:= -1 ->
+ opt_bs_put_split_int_1(Int, L, Mid - 1);
+ _ ->
+ opt_bs_put_split_int_1(Int, Mid + 1, R)
+ end.
+
+%%%
+%%% Optimize expressions such as "tuple_size(Var) =:= 2".
+%%%
+%%% Consider this code:
+%%%
+%%% 0:
+%%% .
+%%% .
+%%% .
+%%% Size = bif:tuple_size Var
+%%% BoolVar1 = succeeded Size
+%%% br BoolVar1, label 4, label 3
+%%%
+%%% 4:
+%%% BoolVar2 = bif:'=:=' Size, literal 2
+%%% br BoolVar2, label 6, label 3
+%%%
+%%% 6: ... %% OK
+%%%
+%%% 3: ... %% Not a tuple of size 2
+%%%
+%%% The BEAM code will look this:
+%%%
+%%% {bif,tuple_size,{f,3},[{x,0}],{x,0}}.
+%%% {test,is_eq_exact,{f,3},[{x,0},{integer,2}]}.
+%%%
+%%% Better BEAM code will be produced if we transform the
+%%% code like this:
+%%%
+%%% 0:
+%%% .
+%%% .
+%%% .
+%%% br label 10
+%%%
+%%% 10:
+%%% NewBoolVar = bif:is_tuple Var
+%%% br NewBoolVar, label 11, label 3
+%%%
+%%% 11:
+%%% Size = bif:tuple_size Var
+%%% br label 4
+%%%
+%%% 4:
+%%% BoolVar2 = bif:'=:=' Size, literal 2
+%%% br BoolVar2, label 6, label 3
+%%%
+%%% (The key part of the transformation is the removal of
+%%% the 'succeeded' instruction to signal to the code generator
+%%% that the call to tuple_size/1 can't fail.)
+%%%
+%%% The BEAM code will look like:
+%%%
+%%% {test,is_tuple,{f,3},[{x,0}]}.
+%%% {test_arity,{f,3},[{x,0},2]}.
+%%%
+%%% Those two instructions will be combined into a single
+%%% is_tuple_of_arity instruction by the loader.
+%%%
+
+ssa_opt_tuple_size({#st{ssa=Linear0,cnt=Count0}=St, FuncDb}) ->
+ {Linear,Count} = opt_tup_size(Linear0, Count0, []),
+ {St#st{ssa=Linear,cnt=Count}, FuncDb}.
+
+opt_tup_size([{L,#b_blk{is=Is,last=Last}=Blk}|Bs], Count0, Acc0) ->
+ case {Is,Last} of
+ {[#b_set{op={bif,'=:='},dst=Bool,args=[#b_var{}=Tup,#b_literal{val=Arity}]}],
+ #b_br{bool=Bool}} when is_integer(Arity), Arity >= 0 ->
+ {Acc,Count} = opt_tup_size_1(Tup, L, Count0, Acc0),
+ opt_tup_size(Bs, Count, [{L,Blk}|Acc]);
+ {_,_} ->
+ opt_tup_size(Bs, Count0, [{L,Blk}|Acc0])
+ end;
+opt_tup_size([], Count, Acc) ->
+ {reverse(Acc),Count}.
+
+opt_tup_size_1(Size, EqL, Count0, [{L,Blk0}|Acc]) ->
+ case Blk0 of
+ #b_blk{is=Is0,last=#b_br{bool=Bool,succ=EqL,fail=Fail}} ->
+ case opt_tup_size_is(Is0, Bool, Size, []) of
+ none ->
+ {[{L,Blk0}|Acc],Count0};
+ {PreIs,TupleSizeIs,Tuple} ->
+ opt_tup_size_2(PreIs, TupleSizeIs, L, EqL,
+ Tuple, Fail, Count0, Acc)
+ end;
+ #b_blk{} ->
+ {[{L,Blk0}|Acc],Count0}
+ end;
+opt_tup_size_1(_, _, Count, Acc) ->
+ {Acc,Count}.
+
+opt_tup_size_2(PreIs, TupleSizeIs, PreL, EqL, Tuple, Fail, Count0, Acc) ->
+ IsTupleL = Count0,
+ TupleSizeL = Count0 + 1,
+ Bool = #b_var{name={'@ssa_bool',Count0+2}},
+ Count = Count0 + 3,
+
+ True = #b_literal{val=true},
+ PreBr = #b_br{bool=True,succ=IsTupleL,fail=IsTupleL},
+ PreBlk = #b_blk{is=PreIs,last=PreBr},
+
+ IsTupleIs = [#b_set{op={bif,is_tuple},dst=Bool,args=[Tuple]}],
+ IsTupleBr = #b_br{bool=Bool,succ=TupleSizeL,fail=Fail},
+ IsTupleBlk = #b_blk{is=IsTupleIs,last=IsTupleBr},
+
+ TupleSizeBr = #b_br{bool=True,succ=EqL,fail=EqL},
+ TupleSizeBlk = #b_blk{is=TupleSizeIs,last=TupleSizeBr},
+ {[{TupleSizeL,TupleSizeBlk},
+ {IsTupleL,IsTupleBlk},
+ {PreL,PreBlk}|Acc],Count}.
+
+opt_tup_size_is([#b_set{op={bif,tuple_size},dst=Size,args=[Tuple]}=I,
+ #b_set{op=succeeded,dst=Bool,args=[Size]}],
+ Bool, Size, Acc) ->
+ {reverse(Acc),[I],Tuple};
+opt_tup_size_is([I|Is], Bool, Size, Acc) ->
+ opt_tup_size_is(Is, Bool, Size, [I|Acc]);
+opt_tup_size_is([], _, _, _Acc) -> none.
+
+%%%
+%%% Optimize #b_switch{} instructions.
+%%%
+%%% If the argument for a #b_switch{} comes from a phi node with all
+%%% literals, any values in the switch list which are not in the phi
+%%% node can be removed.
+%%%
+%%% If the values in the phi node and switch list are the same,
+%%% the failure label can't be reached and be eliminated.
+%%%
+%%% A #b_switch{} with only one value can be rewritten to
+%%% a #b_br{}. A switch that only verifies that the argument
+%%% is 'true' or 'false' can be rewritten to a is_boolean test.
+%%%
+
+ssa_opt_sw({#st{ssa=Linear0,cnt=Count0}=St, FuncDb}) ->
+ {Linear,Count} = opt_sw(Linear0, Count0, []),
+ {St#st{ssa=Linear,cnt=Count}, FuncDb}.
+
+opt_sw([{L,#b_blk{is=Is,last=#b_switch{}=Sw0}=Blk0}|Bs], Count0, Acc) ->
+ %% Ensure that no label in the switch list is the same
+ %% as the failure label.
+ #b_switch{fail=Fail,list=List0} = Sw0,
+ List = [{Val,Lbl} || {Val,Lbl} <- List0, Lbl =/= Fail],
+ Sw1 = beam_ssa:normalize(Sw0#b_switch{list=List}),
+ case Sw1 of
+ #b_switch{arg=Arg,fail=Fail,list=[{Lit,Lbl}]} ->
+ %% Rewrite a single value switch to a br.
+ Bool = #b_var{name={'@ssa_bool',Count0}},
+ Count = Count0 + 1,
+ IsEq = #b_set{op={bif,'=:='},dst=Bool,args=[Arg,Lit]},
+ Br = #b_br{bool=Bool,succ=Lbl,fail=Fail},
+ Blk = Blk0#b_blk{is=Is++[IsEq],last=Br},
+ opt_sw(Bs, Count, [{L,Blk}|Acc]);
+ #b_switch{arg=Arg,fail=Fail,
+ list=[{#b_literal{val=B1},Lbl},{#b_literal{val=B2},Lbl}]}
+ when B1 =:= not B2 ->
+ %% Replace with is_boolean test.
+ Bool = #b_var{name={'@ssa_bool',Count0}},
+ Count = Count0 + 1,
+ IsBool = #b_set{op={bif,is_boolean},dst=Bool,args=[Arg]},
+ Br = #b_br{bool=Bool,succ=Lbl,fail=Fail},
+ Blk = Blk0#b_blk{is=Is++[IsBool],last=Br},
+ opt_sw(Bs, Count, [{L,Blk}|Acc]);
+ Sw0 ->
+ opt_sw(Bs, Count0, [{L,Blk0}|Acc]);
+ Sw ->
+ Blk = Blk0#b_blk{last=Sw},
+ opt_sw(Bs, Count0, [{L,Blk}|Acc])
+ end;
+opt_sw([{L,#b_blk{}=Blk}|Bs], Count, Acc) ->
+ opt_sw(Bs, Count, [{L,Blk}|Acc]);
+opt_sw([], Count, Acc) ->
+ {reverse(Acc),Count}.
+
+%%%
+%%% Merge blocks.
+%%%
+
+ssa_opt_merge_blocks({#st{ssa=Blocks}=St, FuncDb}) ->
+ Preds = beam_ssa:predecessors(Blocks),
+ Merged = merge_blocks_1(beam_ssa:rpo(Blocks), Preds, Blocks),
+ {St#st{ssa=Merged}, FuncDb}.
+
+merge_blocks_1([L|Ls], Preds0, Blocks0) ->
+ case Preds0 of
+ #{L:=[P]} ->
+ #{P:=Blk0,L:=Blk1} = Blocks0,
+ case is_merge_allowed(L, Blk0, Blk1) of
+ true ->
+ #b_blk{is=Is0} = Blk0,
+ #b_blk{is=Is1} = Blk1,
+ verify_merge_is(Is1),
+ Is = Is0 ++ Is1,
+ Blk = Blk1#b_blk{is=Is},
+ Blocks1 = maps:remove(L, Blocks0),
+ Blocks2 = Blocks1#{P:=Blk},
+ Successors = beam_ssa:successors(Blk),
+ Blocks = beam_ssa:update_phi_labels(Successors, L, P, Blocks2),
+ Preds = merge_update_preds(Successors, L, P, Preds0),
+ merge_blocks_1(Ls, Preds, Blocks);
+ false ->
+ merge_blocks_1(Ls, Preds0, Blocks0)
+ end;
+ #{} ->
+ merge_blocks_1(Ls, Preds0, Blocks0)
+ end;
+merge_blocks_1([], _Preds, Blocks) -> Blocks.
+
+merge_update_preds([L|Ls], From, To, Preds0) ->
+ Ps = [rename_label(P, From, To) || P <- map_get(L, Preds0)],
+ Preds = Preds0#{L:=Ps},
+ merge_update_preds(Ls, From, To, Preds);
+merge_update_preds([], _, _, Preds) -> Preds.
+
+rename_label(From, From, To) -> To;
+rename_label(Lbl, _, _) -> Lbl.
+
+verify_merge_is([#b_set{op=Op}|_]) ->
+ %% The merged block has only one predecessor, so it should not have any phi
+ %% nodes.
+ true = Op =/= phi; %Assertion.
+verify_merge_is(_) ->
+ ok.
+
+is_merge_allowed(_, #b_blk{}, #b_blk{is=[#b_set{op=peek_message}|_]}) ->
+ false;
+is_merge_allowed(L, #b_blk{last=#b_br{}}=Blk, #b_blk{}) ->
+ %% The predecessor block must have exactly one successor (L) for
+ %% the merge to be safe.
+ case beam_ssa:successors(Blk) of
+ [L] -> true;
+ [_|_] -> false
+ end;
+is_merge_allowed(_, #b_blk{last=#b_switch{}}, #b_blk{}) ->
+ false.
+
+%%%
+%%% When a tuple is matched, the pattern matching compiler generates a
+%%% get_tuple_element instruction for every tuple element that will
+%%% ever be used in the rest of the function. That often forces the
+%%% extracted tuple elements to be stored in Y registers until it's
+%%% time to use them. It could also mean that there could be execution
+%%% paths that will never use the extracted elements.
+%%%
+%%% This optimization will sink get_tuple_element instructions, that
+%%% is, move them forward in the execution stream to the last possible
+%%% block there they will still dominate all uses. That may reduce the
+%%% size of stack frames, reduce register shuffling, and avoid
+%%% extracting tuple elements on execution paths that never use the
+%%% extracted values.
+%%%
+
+ssa_opt_sink({#st{ssa=Blocks0}=St, FuncDb}) ->
+ Linear = beam_ssa:linearize(Blocks0),
+
+ %% Create a map with all variables that define get_tuple_element
+ %% instructions. The variable name map to the block it is defined in.
+ case def_blocks(Linear) of
+ [] ->
+ %% No get_tuple_element instructions, so there is nothing to do.
+ {St, FuncDb};
+ [_|_]=Defs0 ->
+ Defs = maps:from_list(Defs0),
+ {do_ssa_opt_sink(Linear, Defs, St), FuncDb}
+ end.
+
+do_ssa_opt_sink(Linear, Defs, #st{ssa=Blocks0}=St) ->
+ %% Now find all the blocks that use variables defined by get_tuple_element
+ %% instructions.
+ Used = used_blocks(Linear, Defs, []),
+
+ %% Calculate dominators.
+ {Dom,Numbering} = beam_ssa:dominators(Blocks0),
+
+ %% It is not safe to move get_tuple_element instructions to blocks
+ %% that begin with certain instructions. It is also unsafe to move
+ %% the instructions into any part of a receive. To avoid such
+ %% unsafe moves, pretend that the unsuitable blocks are not
+ %% dominators.
+ Unsuitable = unsuitable(Linear, Blocks0),
+
+ %% Calculate new positions for get_tuple_element instructions. The new
+ %% position is a block that dominates all uses of the variable.
+ DefLoc = new_def_locations(Used, Defs, Dom, Numbering, Unsuitable),
+
+ %% Now move all suitable get_tuple_element instructions to their
+ %% new blocks.
+ Blocks = foldl(fun({V,To}, A) ->
+ From = map_get(V, Defs),
+ move_defs(V, From, To, A)
+ end, Blocks0, DefLoc),
+ St#st{ssa=Blocks}.
+
+def_blocks([{L,#b_blk{is=Is}}|Bs]) ->
+ def_blocks_is(Is, L, def_blocks(Bs));
+def_blocks([]) -> [].
+
+def_blocks_is([#b_set{op=get_tuple_element,dst=Dst}|Is], L, Acc) ->
+ def_blocks_is(Is, L, [{Dst,L}|Acc]);
+def_blocks_is([_|Is], L, Acc) ->
+ def_blocks_is(Is, L, Acc);
+def_blocks_is([], _, Acc) -> Acc.
+
+used_blocks([{L,Blk}|Bs], Def, Acc0) ->
+ Used = beam_ssa:used(Blk),
+ Acc = [{V,L} || V <- Used, maps:is_key(V, Def)] ++ Acc0,
+ used_blocks(Bs, Def, Acc);
+used_blocks([], _Def, Acc) ->
+ rel2fam(Acc).
+
+%% unsuitable(Linear, Blocks) -> Unsuitable.
+%% Return an ordset of block labels for the blocks that are not
+%% suitable for sinking of get_tuple_element instructions.
+
+unsuitable(Linear, Blocks) ->
+ Predecessors = beam_ssa:predecessors(Blocks),
+ Unsuitable0 = unsuitable_1(Linear),
+ Unsuitable1 = unsuitable_recv(Linear, Blocks, Predecessors),
+ gb_sets:from_list(Unsuitable0 ++ Unsuitable1).
+
+unsuitable_1([{L,#b_blk{is=[#b_set{op=Op}|_]}}|Bs]) ->
+ Unsuitable = case Op of
+ bs_extract -> true;
+ bs_put -> true;
+ {float,_} -> true;
+ landingpad -> true;
+ peek_message -> true;
+ wait_timeout -> true;
+ _ -> false
+ end,
+ case Unsuitable of
+ true ->
+ [L|unsuitable_1(Bs)];
+ false ->
+ unsuitable_1(Bs)
+ end;
+unsuitable_1([{_,#b_blk{}}|Bs]) ->
+ unsuitable_1(Bs);
+unsuitable_1([]) -> [].
+
+unsuitable_recv([{L,#b_blk{is=[#b_set{op=Op}|_]}}|Bs], Blocks, Predecessors) ->
+ Ls = case Op of
+ remove_message ->
+ unsuitable_loop(L, Blocks, Predecessors);
+ recv_next ->
+ unsuitable_loop(L, Blocks, Predecessors);
+ _ ->
+ []
+ end,
+ Ls ++ unsuitable_recv(Bs, Blocks, Predecessors);
+unsuitable_recv([_|Bs], Blocks, Predecessors) ->
+ unsuitable_recv(Bs, Blocks, Predecessors);
+unsuitable_recv([], _, _) -> [].
+
+unsuitable_loop(L, Blocks, Predecessors) ->
+ unsuitable_loop(L, Blocks, Predecessors, []).
+
+unsuitable_loop(L, Blocks, Predecessors, Acc) ->
+ Ps = map_get(L, Predecessors),
+ unsuitable_loop_1(Ps, Blocks, Predecessors, Acc).
+
+unsuitable_loop_1([P|Ps], Blocks, Predecessors, Acc0) ->
+ case map_get(P, Blocks) of
+ #b_blk{is=[#b_set{op=peek_message}|_]} ->
+ unsuitable_loop_1(Ps, Blocks, Predecessors, Acc0);
+ #b_blk{} ->
+ case ordsets:is_element(P, Acc0) of
+ false ->
+ Acc1 = ordsets:add_element(P, Acc0),
+ Acc = unsuitable_loop(P, Blocks, Predecessors, Acc1),
+ unsuitable_loop_1(Ps, Blocks, Predecessors, Acc);
+ true ->
+ unsuitable_loop_1(Ps, Blocks, Predecessors, Acc0)
+ end
+ end;
+unsuitable_loop_1([], _, _, Acc) -> Acc.
+
+%% new_def_locations([{Variable,[UsedInBlock]}|Vs], Defs,
+%% Dominators, Numbering, Unsuitable) ->
+%% [{Variable,NewDefinitionBlock}]
+%%
+%% Calculate new locations for get_tuple_element instructions. For
+%% each variable, the new location is a block that dominates all uses
+%% of the variable and as near to the uses of as possible.
+
+new_def_locations([{V,UsedIn}|Vs], Defs, Dom, Numbering, Unsuitable) ->
+ DefIn = map_get(V, Defs),
+ Common = common_dominator(UsedIn, Dom, Numbering, Unsuitable),
+ case member(Common, map_get(DefIn, Dom)) of
+ true ->
+ %% The common dominator is either DefIn or an
+ %% ancestor of DefIn.
+ new_def_locations(Vs, Defs, Dom, Numbering, Unsuitable);
+ false ->
+ %% We have found a suitable descendant of DefIn,
+ %% to which the get_tuple_element instruction can
+ %% be sunk.
+ [{V,Common}|new_def_locations(Vs, Defs, Dom, Numbering, Unsuitable)]
+ end;
+new_def_locations([], _, _, _, _) -> [].
+
+common_dominator(Ls0, Dom, Numbering, Unsuitable) ->
+ [Common|_] = beam_ssa:common_dominators(Ls0, Dom, Numbering),
+ case gb_sets:is_member(Common, Unsuitable) of
+ true ->
+ %% It is not allowed to place the instruction here. Try
+ %% to find another suitable dominating block by going up
+ %% one step in the dominator tree.
+ [Common,OneUp|_] = map_get(Common, Dom),
+ common_dominator([OneUp], Dom, Numbering, Unsuitable);
+ false ->
+ Common
+ end.
+
+%% Move get_tuple_element instructions to their new locations.
+
+move_defs(V, From, To, Blocks) ->
+ #{From:=FromBlk0,To:=ToBlk0} = Blocks,
+ {Def,FromBlk} = remove_def(V, FromBlk0),
+ try insert_def(V, Def, ToBlk0) of
+ ToBlk ->
+ %%io:format("~p: ~p => ~p\n", [V,From,To]),
+ Blocks#{From:=FromBlk,To:=ToBlk}
+ catch
+ throw:not_possible ->
+ Blocks
+ end.
+
+remove_def(V, #b_blk{is=Is0}=Blk) ->
+ {Def,Is} = remove_def_is(Is0, V, []),
+ {Def,Blk#b_blk{is=Is}}.
+
+remove_def_is([#b_set{dst=Dst}=Def|Is], Dst, Acc) ->
+ {Def,reverse(Acc, Is)};
+remove_def_is([I|Is], Dst, Acc) ->
+ remove_def_is(Is, Dst, [I|Acc]).
+
+insert_def(V, Def, #b_blk{is=Is0}=Blk) ->
+ Is = insert_def_is(Is0, V, Def),
+ Blk#b_blk{is=Is}.
+
+insert_def_is([#b_set{op=phi}=I|Is], V, Def) ->
+ case member(V, beam_ssa:used(I)) of
+ true ->
+ throw(not_possible);
+ false ->
+ [I|insert_def_is(Is, V, Def)]
+ end;
+insert_def_is([#b_set{op=Op}=I|Is]=Is0, V, Def) ->
+ Action0 = case Op of
+ call -> beyond;
+ 'catch_end' -> beyond;
+ timeout -> beyond;
+ _ -> here
+ end,
+ Action = case Is of
+ [#b_set{op=succeeded}|_] -> here;
+ _ -> Action0
+ end,
+ case Action of
+ beyond ->
+ case member(V, beam_ssa:used(I)) of
+ true ->
+ %% The variable is used by this instruction. We must
+ %% place the definition before this instruction.
+ [Def|Is0];
+ false ->
+ %% Place it beyond the current instruction.
+ [I|insert_def_is(Is, V, Def)]
+ end;
+ here ->
+ [Def|Is0]
+ end;
+insert_def_is([], _V, Def) ->
+ [Def].
+
+%%%
+%%% Order consecutive get_tuple_element instructions in ascending
+%%% position order. This will give the loader more opportunities
+%%% for combining get_tuple_element instructions.
+%%%
+
+ssa_opt_get_tuple_element({#st{ssa=Blocks0}=St, FuncDb}) ->
+ Blocks = opt_get_tuple_element(maps:to_list(Blocks0), Blocks0),
+ {St#st{ssa=Blocks}, FuncDb}.
+
+opt_get_tuple_element([{L,#b_blk{is=Is0}=Blk0}|Bs], Blocks) ->
+ case opt_get_tuple_element_is(Is0, false, []) of
+ {yes,Is} ->
+ Blk = Blk0#b_blk{is=Is},
+ opt_get_tuple_element(Bs, Blocks#{L:=Blk});
+ no ->
+ opt_get_tuple_element(Bs, Blocks)
+ end;
+opt_get_tuple_element([], Blocks) -> Blocks.
+
+opt_get_tuple_element_is([#b_set{op=get_tuple_element,
+ args=[#b_var{}=Src,_]}=I0|Is0],
+ _AnyChange, Acc) ->
+ {GetIs0,Is} = collect_get_tuple_element(Is0, Src, [I0]),
+ GetIs1 = sort([{Pos,I} || #b_set{args=[_,Pos]}=I <- GetIs0]),
+ GetIs = [I || {_,I} <- GetIs1],
+ opt_get_tuple_element_is(Is, true, reverse(GetIs, Acc));
+opt_get_tuple_element_is([I|Is], AnyChange, Acc) ->
+ opt_get_tuple_element_is(Is, AnyChange, [I|Acc]);
+opt_get_tuple_element_is([], AnyChange, Acc) ->
+ case AnyChange of
+ true -> {yes,reverse(Acc)};
+ false -> no
+ end.
+
+collect_get_tuple_element([#b_set{op=get_tuple_element,
+ args=[Src,_]}=I|Is], Src, Acc) ->
+ collect_get_tuple_element(Is, Src, [I|Acc]);
+collect_get_tuple_element(Is, _Src, Acc) ->
+ {Acc,Is}.
+
+%%%
+%%% Common utilities.
+%%%
+
+gcd(A, B) ->
+ case A rem B of
+ 0 -> B;
+ X -> gcd(B, X)
+ end.
+
+rel2fam(S0) ->
+ S1 = sofs:relation(S0),
+ S = sofs:rel2fam(S1),
+ sofs:to_external(S).
+
+sub(I, Sub) ->
+ beam_ssa:normalize(sub_1(I, Sub)).
+
+sub_1(#b_set{op=phi,args=Args}=I, Sub) ->
+ I#b_set{args=[{sub_arg(A, Sub),P} || {A,P} <- Args]};
+sub_1(#b_set{args=Args}=I, Sub) ->
+ I#b_set{args=[sub_arg(A, Sub) || A <- Args]};
+sub_1(#b_br{bool=#b_var{}=Old}=Br, Sub) ->
+ New = sub_arg(Old, Sub),
+ Br#b_br{bool=New};
+sub_1(#b_switch{arg=#b_var{}=Old}=Sw, Sub) ->
+ New = sub_arg(Old, Sub),
+ Sw#b_switch{arg=New};
+sub_1(#b_ret{arg=#b_var{}=Old}=Ret, Sub) ->
+ New = sub_arg(Old, Sub),
+ Ret#b_ret{arg=New};
+sub_1(Last, _) -> Last.
+
+sub_arg(#b_remote{mod=Mod,name=Name}=Rem, Sub) ->
+ Rem#b_remote{mod=sub_arg(Mod, Sub),name=sub_arg(Name, Sub)};
+sub_arg(Old, Sub) ->
+ case Sub of
+ #{Old:=New} -> New;
+ #{} -> Old
+ end.
+
+new_var(#b_var{name={Base,N}}, Count) ->
+ true = is_integer(N), %Assertion.
+ {#b_var{name={Base,Count}},Count+1};
+new_var(#b_var{name=Base}, Count) ->
+ {#b_var{name={Base,Count}},Count+1}.
diff --git a/lib/compiler/src/beam_ssa_opt.hrl b/lib/compiler/src/beam_ssa_opt.hrl
new file mode 100644
index 0000000000..37711a6f48
--- /dev/null
+++ b/lib/compiler/src/beam_ssa_opt.hrl
@@ -0,0 +1,53 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-include("beam_ssa.hrl").
+
+-record(func_info,
+ {%% Local calls going in/out of this function.
+ in = ordsets:new() :: ordsets:ordset(func_id()),
+ out = ordsets:new() :: ordsets:ordset(func_id()),
+
+ %% Whether the function is exported or not; some optimizations may
+ %% need to be suppressed if it is.
+ exported = true :: boolean(),
+
+ %% The inferred types of each argument (as opposed to parameter),
+ %% indexed by call site.
+ %%
+ %% This is more effective than the naive approach of joining into a
+ %% "parameter_type" as we go as it lets us narrow parameter types
+ %% without having to visit all callers on each pass, which helps a lot
+ %% when dealing with co-recursive functions.
+ arg_types = [] :: list(arg_type_map()),
+
+ %% The inferred return type of this function, this is either [type()]
+ %% or [] to note absence.
+ ret_type = [] :: list()}).
+
+-type arg_key() :: {CallerId :: func_id(),
+ CallDst :: beam_ssa:b_var()}.
+-type arg_type_map() :: #{ arg_key() => term() }.
+
+%% Per-function metadata used by various optimization passes to perform
+%% module-level optimization. If a function is absent it means that
+%% module-level optimization has been turned off for said function.
+-type func_id() :: beam_ssa:b_local().
+-type func_info_db() :: #{ func_id() => #func_info{} }.
diff --git a/lib/compiler/src/beam_ssa_pp.erl b/lib/compiler/src/beam_ssa_pp.erl
new file mode 100644
index 0000000000..34ac08b32e
--- /dev/null
+++ b/lib/compiler/src/beam_ssa_pp.erl
@@ -0,0 +1,238 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(beam_ssa_pp).
+
+-export([format_function/1,format_instr/1,format_var/1]).
+
+-include("beam_ssa.hrl").
+
+-spec format_function(beam_ssa:b_function()) -> iolist().
+
+format_function(#b_function{anno=Anno0,args=Args,
+ bs=Blocks,cnt=Counter}) ->
+ #{func_info:={M,F,_}} = Anno0,
+ Anno = maps:without([func_info,location,live_intervals,registers], Anno0),
+ FuncAnno = case Anno0 of
+ #{live_intervals:=Intervals} ->
+ Anno0#{live_intervals:=maps:from_list(Intervals)};
+ #{} ->
+ Anno0
+ end,
+ ReachableBlocks = beam_ssa:rpo(Blocks),
+ All = maps:keys(Blocks),
+ Unreachable = ordsets:subtract(ordsets:from_list(All),
+ ordsets:from_list(ReachableBlocks)),
+ [case Anno0 of
+ #{location:={Filename,Line}} ->
+ io_lib:format("%% ~ts:~p\n", [Filename,Line]);
+ #{} ->
+ []
+ end,
+ io_lib:format("%% Counter = ~p\n", [Counter]),
+ [format_anno(Key, Value) ||
+ {Key,Value} <- lists:sort(maps:to_list(Anno))],
+ io_lib:format("function ~p:~p(~ts) {\n", [M,F,format_args(Args, FuncAnno)]),
+ [format_live_interval(Var, FuncAnno) || Var <- Args],
+ format_blocks(ReachableBlocks, Blocks, FuncAnno),
+ case Unreachable of
+ [] ->
+ [];
+ [_|_] ->
+ ["\n%% Unreachable blocks\n\n",
+ format_blocks(Unreachable, Blocks, FuncAnno)]
+ end,
+
+ "}\n"].
+
+
+-spec format_instr(beam_ssa:b_set()) -> iolist().
+
+format_instr(#b_set{}=I) ->
+ Cs = lists:flatten(format_instr(I#b_set{anno=#{}}, #{}, true)),
+ string:trim(Cs, leading);
+format_instr(I0) ->
+ I = setelement(2, I0, #{}),
+ Cs = lists:flatten(format_terminator(I, #{})),
+ string:trim(Cs, both).
+
+-spec format_var(beam_ssa:b_var()) -> iolist().
+
+format_var(V) ->
+ Cs = lists:flatten(format_var(V, #{})),
+ string:trim(Cs, leading).
+
+%%%
+%%% Local functions.
+%%%
+
+format_anno(Key, Map) when is_map(Map) ->
+ Sorted = lists:sort(maps:to_list(Map)),
+ [io_lib:format("%% ~s:\n", [Key]),
+ [io_lib:format("%% ~w => ~w\n", [K,V]) || {K,V} <- Sorted]];
+format_anno(Key, Value) ->
+ io_lib:format("%% ~s: ~p\n", [Key,Value]).
+
+format_blocks(Ls, Blocks, Anno) ->
+ PP = [format_block(L, Blocks, Anno) || L <- Ls],
+ lists:join($\n, PP).
+
+format_block(L, Blocks, FuncAnno) ->
+ #b_blk{anno=Anno,is=Is,last=Last} = maps:get(L, Blocks),
+ [case map_size(Anno) of
+ 0 -> [];
+ _ -> io_lib:format("%% ~p\n", [Anno])
+ end,
+ io_lib:format("~p:", [L]),
+ format_instrs(Is, FuncAnno, true),
+ $\n,
+ format_terminator(Last, FuncAnno)].
+
+format_instrs([I|Is], FuncAnno, First) ->
+ [$\n,
+ format_instr(I, FuncAnno, First),
+ format_instrs(Is, FuncAnno, false)];
+format_instrs([], _FuncAnno, _First) ->
+ [].
+
+format_instr(#b_set{anno=Anno,op=Op,dst=Dst,args=Args},
+ FuncAnno, First) ->
+ AnnoStr = format_anno(Anno),
+ LiveIntervalStr = format_live_interval(Dst, FuncAnno),
+ [if
+ First ->
+ [];
+ AnnoStr =/= []; LiveIntervalStr =/= [] ->
+ $\n;
+ true ->
+ []
+ end,
+ AnnoStr,
+ LiveIntervalStr,
+ io_lib:format(" ~s~ts = ~ts", [format_i_number(Anno),
+ format_var(Dst, FuncAnno),
+ format_op(Op)]),
+ case Args of
+ [] ->
+ [];
+ [_|_] ->
+ io_lib:format(" ~ts", [format_args(Args, FuncAnno)])
+ end].
+
+format_i_number(#{n:=N}) ->
+ io_lib:format("[~p] ", [N]);
+format_i_number(#{}) -> [].
+
+format_terminator(#b_br{anno=A,bool=#b_literal{val=true},succ=Lbl}, _) ->
+ io_lib:format(" ~sbr label ~p\n", [format_i_number(A),Lbl]);
+format_terminator(#b_br{anno=A,bool=#b_literal{val=false},fail=Lbl}, _) ->
+ io_lib:format(" ~sbr label ~p\n", [format_i_number(A),Lbl]);
+format_terminator(#b_br{anno=A,bool=Bool,succ=Succ,fail=Fail}, FuncAnno) ->
+ io_lib:format(" ~sbr ~ts, label ~p, label ~p\n",
+ [format_i_number(A),format_arg(Bool, FuncAnno),Succ,Fail]);
+format_terminator(#b_switch{anno=A,arg=Arg,fail=Fail,list=List}, FuncAnno) ->
+ io_lib:format(" ~sswitch ~ts, label ~p, ~ts\n",
+ [format_i_number(A),format_arg(Arg, FuncAnno),Fail,
+ format_list(List,FuncAnno)]);
+format_terminator(#b_ret{anno=A,arg=Arg}, FuncAnno) ->
+ io_lib:format(" ~sret ~ts\n", [format_i_number(A),format_arg(Arg, FuncAnno)]).
+
+format_op({Prefix,Name}) ->
+ io_lib:format("~p:~p", [Prefix,Name]);
+format_op(Name) ->
+ io_lib:format("~p", [Name]).
+
+format_register(#b_var{}=V, #{registers:=Regs}) ->
+ {Tag,N} = maps:get(V, Regs),
+ io_lib:format("~p~p", [Tag,N]);
+format_register(_, #{}) -> "".
+
+format_var(Var, FuncAnno) ->
+ VarString = format_var_1(Var),
+ case format_register(Var, FuncAnno) of
+ [] -> VarString;
+ [_|_]=Reg -> [Reg,$/,VarString]
+ end.
+
+format_var_1(#b_var{name={Name,Uniq}}) ->
+ if
+ is_atom(Name) ->
+ io_lib:format("~ts:~p", [Name,Uniq]);
+ is_integer(Name) ->
+ io_lib:format("_~p:~p", [Name,Uniq])
+ end;
+format_var_1(#b_var{name=Name}) when is_atom(Name) ->
+ atom_to_list(Name);
+format_var_1(#b_var{name=Name}) when is_integer(Name) ->
+ "_"++integer_to_list(Name).
+
+format_args(Args, FuncAnno) ->
+ Ss = [format_arg(Arg, FuncAnno) || Arg <- Args],
+ lists:join(", ", Ss).
+
+format_arg(#b_var{}=Arg, FuncAnno) ->
+ format_var(Arg, FuncAnno);
+format_arg(#b_literal{val=Val}, _FuncAnno) ->
+ io_lib:format("literal ~p", [Val]);
+format_arg(#b_remote{mod=Mod,name=Name,arity=Arity}, FuncAnno) ->
+ io_lib:format("remote (~ts):(~ts)/~p",
+ [format_arg(Mod, FuncAnno),format_arg(Name, FuncAnno),Arity]);
+format_arg(#b_local{name=Name,arity=Arity}, FuncAnno) ->
+ io_lib:format("local ~ts/~p", [format_arg(Name, FuncAnno),Arity]);
+format_arg({Value,Label}, FuncAnno) when is_integer(Label) ->
+ io_lib:format("{ ~ts, ~p }", [format_arg(Value, FuncAnno),Label]);
+format_arg(Other, _) ->
+ io_lib:format("*** ~p ***", [Other]).
+
+format_list(List, FuncAnno) ->
+ Ss = [io_lib:format("{ ~ts, ~ts }", [format_arg(Val, FuncAnno),format_label(L)]) ||
+ {Val,L} <- List],
+ io_lib:format("[ ~ts ]", [lists:join(", ", Ss)]).
+
+format_label(L) ->
+ ["label ",integer_to_list(L)].
+
+format_anno(#{n:=_}=Anno) ->
+ format_anno(maps:remove(n, Anno));
+format_anno(#{location:={File,Line}}=Anno0) ->
+ Anno = maps:remove(location, Anno0),
+ [io_lib:format(" %% ~ts:~p\n", [File,Line])|format_anno_1(Anno)];
+format_anno(Anno) ->
+ format_anno_1(Anno).
+
+format_anno_1(Anno) ->
+ case map_size(Anno) of
+ 0 ->
+ [];
+ _ ->
+ [io_lib:format(" %% Anno: ~p\n", [Anno])]
+ end.
+
+format_live_interval(#b_var{}=Dst, #{live_intervals:=Intervals}) ->
+ case Intervals of
+ #{Dst:=Rs0} ->
+ Rs1 = [io_lib:format("~p..~p", [Start,End]) ||
+ {Start,End} <- Rs0],
+ Rs = lists:join(" ", Rs1),
+ io_lib:format(" %% ~ts: ~s\n", [format_var_1(Dst),Rs]);
+ #{} ->
+ []
+ end;
+format_live_interval(_, _) -> [].
+
diff --git a/lib/compiler/src/beam_ssa_pre_codegen.erl b/lib/compiler/src/beam_ssa_pre_codegen.erl
new file mode 100644
index 0000000000..bf99e8fc26
--- /dev/null
+++ b/lib/compiler/src/beam_ssa_pre_codegen.erl
@@ -0,0 +1,2850 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% Purpose: Prepare for code generation, including register allocation.
+%%
+%% The output of this compiler pass is still in the SSA format, but
+%% it has been annotated and transformed to help the code generator.
+%%
+%% * Some instructions are translated to other instructions closer to
+%% the BEAM instructions. For example, the binary matching
+%% instructions are transformed from the optimization-friendly
+%% internal format to instruction more similar to the actual BEAM
+%% instructions.
+%%
+%% * Blocks that will need an instruction for allocating a stack frame
+%% are annotated with a {frame_size,Size} annotation.
+%%
+%% * 'copy' instructions are added for all variables that need
+%% to be saved to the stack frame. Additional 'copy' instructions
+%% can be added as an optimization to reuse y registers (see
+%% the copy_retval sub pass).
+%%
+%% * Each function is annotated with a {register,RegisterMap}
+%% annotation that maps each variable to a BEAM register. The linear
+%% scan algorithm is used to allocate registers.
+%%
+%% There are four kind of registers. x, y, fr (floating point register),
+%% and z. A variable will be allocated to a z register if it is only
+%% used by the instruction following the instruction that defines the
+%% the variable. The code generator will typically combine those
+%% instructions to a test instruction. z registers are also used for
+%% some instructions that don't have a return value.
+%%
+%% References:
+%%
+%% [1] H. Mössenböck and M. Pfeiffer. Linear scan register allocation
+%% in the context of SSA form and register constraints. In Proceedings
+%% of the International Conference on Compiler Construction, pages
+%% 229–246. LNCS 2304, Springer-Verlag, 2002.
+%%
+%% [2] C. Wimmer and H. Mössenböck. Optimized interval splitting in a
+%% linear scan register allocator. In Proceedings of the ACM/USENIX
+%% International Conference on Virtual Execution Environments, pages
+%% 132–141. ACM Press, 2005.
+%%
+%% [3] C. Wimmer and M. Franz. Linear Scan Register Allocation on SSA
+%% Form. In Proceedings of the International Symposium on Code
+%% Generation and Optimization, pages 170-179. ACM Press, 2010.
+%%
+
+-module(beam_ssa_pre_codegen).
+
+-export([module/2]).
+
+-include("beam_ssa.hrl").
+
+-import(lists, [all/2,any/2,append/1,duplicate/2,
+ foldl/3,last/1,map/2,member/2,partition/2,
+ reverse/1,reverse/2,sort/1,splitwith/2,zip/2]).
+
+-spec module(beam_ssa:b_module(), [compile:option()]) ->
+ {'ok',beam_ssa:b_module()}.
+
+module(#b_module{body=Fs0}=Module, Opts) ->
+ UseBSM3 = not proplists:get_bool(no_bsm3, Opts),
+ Ps = passes(Opts),
+ Fs = functions(Fs0, Ps, UseBSM3),
+ {ok,Module#b_module{body=Fs}}.
+
+functions([F|Fs], Ps, UseBSM3) ->
+ [function(F, Ps, UseBSM3)|functions(Fs, Ps, UseBSM3)];
+functions([], _Ps, _UseBSM3) -> [].
+
+-type b_var() :: beam_ssa:b_var().
+-type var_name() :: beam_ssa:var_name().
+-type instr_number() :: pos_integer().
+-type range() :: {instr_number(),instr_number()}.
+-type reg_num() :: beam_asm:reg_num().
+-type xreg() :: {'x',reg_num()}.
+-type yreg() :: {'y',reg_num()}.
+-type ypool() :: {'y',beam_ssa:label()}.
+-type reservation() :: 'fr' | {'prefer',xreg()} | 'x' | {'x',xreg()} |
+ ypool() | {yreg(),ypool()} | 'z'.
+-type ssa_register() :: beam_ssa_codegen:ssa_register().
+
+-define(TC(Body), tc(fun() -> Body end, ?FILE, ?LINE)).
+-record(st, {ssa :: beam_ssa:block_map(),
+ args :: [b_var()],
+ cnt :: beam_ssa:label(),
+ use_bsm3 :: boolean(),
+ frames=[] :: [beam_ssa:label()],
+ intervals=[] :: [{b_var(),[range()]}],
+ res=[] :: [{b_var(),reservation()}] | #{b_var():=reservation()},
+ regs=#{} :: #{b_var():=ssa_register()},
+ extra_annos=[] :: [{atom(),term()}]
+ }).
+-define(PASS(N), {N,fun N/1}).
+
+passes(Opts) ->
+ AddPrecgAnnos = proplists:get_bool(dprecg, Opts),
+ FixTuples = proplists:get_bool(no_put_tuple2, Opts),
+ Ps = [?PASS(assert_no_critical_edges),
+
+ %% Preliminaries.
+ ?PASS(fix_bs),
+ ?PASS(sanitize),
+ case FixTuples of
+ false -> ignore;
+ true -> ?PASS(fix_tuples)
+ end,
+ ?PASS(use_set_tuple_element),
+ ?PASS(place_frames),
+ ?PASS(fix_receives),
+
+ %% Find and reserve Y registers.
+ ?PASS(find_yregs),
+ ?PASS(reserve_yregs),
+
+ %% Handle legacy binary match instruction that don't
+ %% accept a Y register as destination.
+ ?PASS(legacy_bs),
+
+ %% Improve reuse of Y registers to potentially
+ %% reduce the size of the stack frame.
+ ?PASS(copy_retval),
+ ?PASS(opt_get_list),
+
+ %% Calculate live intervals.
+ ?PASS(number_instructions),
+ ?PASS(live_intervals),
+ ?PASS(reserve_regs),
+
+ %% If needed for a .precg file, save the live intervals
+ %% so they can be included in an annotation.
+ case AddPrecgAnnos of
+ false -> ignore;
+ true -> ?PASS(save_live_intervals)
+ end,
+
+ %% Allocate registers.
+ ?PASS(linear_scan),
+ ?PASS(frame_size),
+ ?PASS(turn_yregs)],
+ [P || P <- Ps, P =/= ignore].
+
+function(#b_function{anno=Anno,args=Args,bs=Blocks0,cnt=Count0}=F0,
+ Ps, UseBSM3) ->
+ try
+ St0 = #st{ssa=Blocks0,args=Args,use_bsm3=UseBSM3,cnt=Count0},
+ St = compile:run_sub_passes(Ps, St0),
+ #st{ssa=Blocks,cnt=Count,regs=Regs,extra_annos=ExtraAnnos} = St,
+ F1 = add_extra_annos(F0, ExtraAnnos),
+ F = beam_ssa:add_anno(registers, Regs, F1),
+ F#b_function{bs=Blocks,cnt=Count}
+ catch
+ Class:Error:Stack ->
+ #{func_info:={_,Name,Arity}} = Anno,
+ io:fwrite("Function: ~w/~w\n", [Name,Arity]),
+ erlang:raise(Class, Error, Stack)
+ end.
+
+save_live_intervals(#st{intervals=Intervals}=St) ->
+ St#st{extra_annos=[{live_intervals,Intervals}]}.
+
+%% Add extra annotations when a .precg listing file is being produced.
+add_extra_annos(F, Annos) ->
+ foldl(fun({Name,Value}, Acc) ->
+ beam_ssa:add_anno(Name, Value, Acc)
+ end, F, Annos).
+
+%% assert_no_critical_edges(St0) -> St.
+%% The code generator will not work if there are critial edges.
+%% Abort if any critical edges are found.
+
+assert_no_critical_edges(#st{ssa=Blocks}=St) ->
+ F = fun assert_no_ces/3,
+ beam_ssa:fold_rpo(F, Blocks, Blocks),
+ St.
+
+assert_no_ces(_, #b_blk{is=[#b_set{op=phi,args=[_,_]=Phis}|_]}, Blocks) ->
+ %% This block has multiple predecessors. Make sure that none
+ %% of the precessors have more than one successor.
+ true = all(fun({_,P}) ->
+ length(beam_ssa:successors(P, Blocks)) =:= 1
+ end, Phis), %Assertion.
+ Blocks;
+assert_no_ces(_, _, Blocks) -> Blocks.
+
+%% fix_bs(St0) -> St.
+%% Fix up the binary matching instructions:
+%%
+%% * Insert bs_save and bs_restore instructions where needed.
+%%
+%% * Combine bs_match and bs_extract instructions to bs_get
+%% instructions.
+
+fix_bs(#st{ssa=Blocks,cnt=Count0,use_bsm3=UseBSM3}=St) ->
+ F = fun(#b_set{op=bs_start_match,dst=Dst}, A) ->
+ %% Mark the root of the match context list.
+ [{Dst,{context,Dst}}|A];
+ (#b_set{op=bs_match,dst=Dst,args=[_,ParentCtx|_]}, A) ->
+ %% Link this match context the previous match context.
+ [{Dst,ParentCtx}|A];
+ (_, A) ->
+ A
+ end,
+ case beam_ssa:fold_instrs_rpo(F, [0], [],Blocks) of
+ [] ->
+ %% No binary matching in this function.
+ St;
+ [_|_]=M ->
+ CtxChain = maps:from_list(M),
+ Linear0 = beam_ssa:linearize(Blocks),
+
+ %% Insert position instructions where needed.
+ {Linear1,Count} = case UseBSM3 of
+ true ->
+ bs_pos_bsm3(Linear0, CtxChain, Count0);
+ false ->
+ bs_pos_bsm2(Linear0, CtxChain, Count0)
+ end,
+
+ %% Rename instructions.
+ Linear = bs_instrs(Linear1, CtxChain, []),
+
+ St#st{ssa=maps:from_list(Linear),cnt=Count}
+ end.
+
+%% Insert bs_get_position and bs_set_position instructions as needed.
+bs_pos_bsm3(Linear0, CtxChain, Count0) ->
+ Rs0 = bs_restores(Linear0, CtxChain, #{}, #{}),
+ Rs = maps:values(Rs0),
+ S0 = sofs:relation(Rs, [{context,save_point}]),
+ S1 = sofs:relation_to_family(S0),
+ S = sofs:to_external(S1),
+
+ {SavePoints,Count1} = make_bs_pos_dict(S, Count0, []),
+ {Gets,Count2} = make_bs_setpos_map(Rs, SavePoints, Count1, []),
+ {Sets,Count} = make_bs_getpos_map(maps:to_list(Rs0), SavePoints, Count2, []),
+
+ %% Now insert all saves and restores.
+ {bs_insert_bsm3(Linear0, Gets, Sets, SavePoints),Count}.
+
+make_bs_setpos_map([{Ctx,Save}=Ps|T], SavePoints, Count, Acc) ->
+ SavePoint = get_savepoint(Ps, SavePoints),
+ I = #b_set{op=bs_get_position,dst=SavePoint,args=[Ctx]},
+ make_bs_setpos_map(T, SavePoints, Count+1, [{Save,I}|Acc]);
+make_bs_setpos_map([], _, Count, Acc) ->
+ {maps:from_list(Acc),Count}.
+
+make_bs_getpos_map([{Bef,{Ctx,_}=Ps}|T], SavePoints, Count, Acc) ->
+ Ignored = #b_var{name={'@ssa_ignored',Count}},
+ Args = [Ctx, get_savepoint(Ps, SavePoints)],
+ I = #b_set{op=bs_set_position,dst=Ignored,args=Args},
+ make_bs_getpos_map(T, SavePoints, Count+1, [{Bef,I}|Acc]);
+make_bs_getpos_map([], _, Count, Acc) ->
+ {maps:from_list(Acc),Count}.
+
+get_savepoint({_,_}=Ps, SavePoints) ->
+ Name = {'@ssa_bs_position', map_get(Ps, SavePoints)},
+ #b_var{name=Name}.
+
+make_bs_pos_dict([{Ctx,Pts}|T], Count0, Acc0) ->
+ {Acc, Count} = make_bs_pos_dict_1(Pts, Ctx, Count0, Acc0),
+ make_bs_pos_dict(T, Count, Acc);
+make_bs_pos_dict([], Count, Acc) ->
+ {maps:from_list(Acc), Count}.
+
+make_bs_pos_dict_1([H|T], Ctx, I, Acc) ->
+ make_bs_pos_dict_1(T, Ctx, I+1, [{{Ctx,H},I}|Acc]);
+make_bs_pos_dict_1([], Ctx, I, Acc) ->
+ {[{Ctx,I}|Acc], I}.
+
+%% As bs_position but without OTP-22 instructions. This is only used when
+%% cross-compiling to older versions.
+bs_pos_bsm2(Linear0, CtxChain, Count0) ->
+ Rs0 = bs_restores(Linear0, CtxChain, #{}, #{}),
+ Rs = maps:values(Rs0),
+ S0 = sofs:relation(Rs, [{context,save_point}]),
+ S1 = sofs:relation_to_family(S0),
+ S = sofs:to_external(S1),
+ Slots = make_save_point_dict(S, []),
+ {Saves,Count1} = make_save_map(Rs, Slots, Count0, []),
+ {Restores,Count} = make_restore_map(maps:to_list(Rs0), Slots, Count1, []),
+
+ %% Now insert all saves and restores.
+ {bs_insert_bsm2(Linear0, Saves, Restores, Slots),Count}.
+
+make_save_map([{Ctx,Save}=Ps|T], Slots, Count, Acc) ->
+ Ignored = #b_var{name={'@ssa_ignored',Count}},
+ case make_slot(Ps, Slots) of
+ #b_literal{val=start} ->
+ make_save_map(T, Slots, Count, Acc);
+ Slot ->
+ I = #b_set{op=bs_save,dst=Ignored,args=[Ctx,Slot]},
+ make_save_map(T, Slots, Count+1, [{Save,I}|Acc])
+ end;
+make_save_map([], _, Count, Acc) ->
+ {maps:from_list(Acc),Count}.
+
+make_restore_map([{Bef,{Ctx,_}=Ps}|T], Slots, Count, Acc) ->
+ Ignored = #b_var{name={'@ssa_ignored',Count}},
+ I = #b_set{op=bs_restore,dst=Ignored,args=[Ctx,make_slot(Ps, Slots)]},
+ make_restore_map(T, Slots, Count+1, [{Bef,I}|Acc]);
+make_restore_map([], _, Count, Acc) ->
+ {maps:from_list(Acc),Count}.
+
+make_slot({Same,Same}, _Slots) ->
+ #b_literal{val=start};
+make_slot({_,_}=Ps, Slots) ->
+ #b_literal{val=map_get(Ps, Slots)}.
+
+make_save_point_dict([{Ctx,Pts}|T], Acc0) ->
+ Acc = make_save_point_dict_1(Pts, Ctx, 0, Acc0),
+ make_save_point_dict(T, Acc);
+make_save_point_dict([], Acc) ->
+ maps:from_list(Acc).
+
+make_save_point_dict_1([Ctx|T], Ctx, I, Acc) ->
+ %% Special {atom,start} save point. Does not need a
+ %% bs_save instruction.
+ make_save_point_dict_1(T, Ctx, I, Acc);
+make_save_point_dict_1([H|T], Ctx, I, Acc) ->
+ make_save_point_dict_1(T, Ctx, I+1, [{{Ctx,H},I}|Acc]);
+make_save_point_dict_1([], Ctx, I, Acc) ->
+ [{Ctx,I}|Acc].
+
+bs_restores([{L,#b_blk{is=Is,last=Last}}|Bs], CtxChain, D0, Rs0) ->
+ InPos = maps:get(L, D0, #{}),
+ {SuccPos, FailPos, Rs} = bs_restores_is(Is, CtxChain, InPos, InPos, Rs0),
+
+ D = bs_update_successors(Last, SuccPos, FailPos, D0),
+ bs_restores(Bs, CtxChain, D, Rs);
+bs_restores([], _, _, Rs) -> Rs.
+
+bs_update_successors(#b_br{succ=Succ,fail=Fail}, SPos, FPos, D) ->
+ join_positions([{Succ,SPos},{Fail,FPos}], D);
+bs_update_successors(#b_switch{fail=Fail,list=List}, SPos, FPos, D) ->
+ SPos = FPos, %Assertion.
+ Update = [{L,SPos} || {_,L} <- List] ++ [{Fail,SPos}],
+ join_positions(Update, D);
+bs_update_successors(#b_ret{}, SPos, FPos, D) ->
+ SPos = FPos, %Assertion.
+ D.
+
+join_positions([{L,MapPos0}|T], D) ->
+ case D of
+ #{L:=MapPos0} ->
+ %% Same map.
+ join_positions(T, D);
+ #{L:=MapPos1} ->
+ %% Different maps.
+ MapPos = join_positions_1(MapPos0, MapPos1),
+ join_positions(T, D#{L:=MapPos});
+ #{} ->
+ join_positions(T, D#{L=>MapPos0})
+ end;
+join_positions([], D) -> D.
+
+join_positions_1(MapPos0, MapPos1) ->
+ MapPos2 = maps:map(fun(Start, Pos) ->
+ case MapPos0 of
+ #{Start:=Pos} -> Pos;
+ #{Start:=_} -> unknown;
+ #{} -> Pos
+ end
+ end, MapPos1),
+ maps:merge(MapPos0, MapPos2).
+
+%%
+%% Updates the restore and position maps according to the given instructions.
+%%
+%% Note that positions may be updated even when a match fails; if a match
+%% requires a restore, the position at the fail block will be the position
+%% we've *restored to* and not the one we entered the current block with.
+%%
+
+bs_restores_is([#b_set{op=bs_start_match,dst=Start}|Is],
+ CtxChain, SPos0, FPos, Rs) ->
+ %% We only allow one match per block.
+ SPos0 = FPos, %Assertion.
+ SPos = SPos0#{Start=>Start},
+ bs_restores_is(Is, CtxChain, SPos, FPos, Rs);
+bs_restores_is([#b_set{op=bs_match,dst=NewPos,args=Args}=I|Is],
+ CtxChain, SPos0, FPos0, Rs0) ->
+ SPos0 = FPos0, %Assertion.
+ Start = bs_subst_ctx(NewPos, CtxChain),
+ [_,FromPos|_] = Args,
+ case SPos0 of
+ #{Start:=FromPos} ->
+ %% Same position, no restore needed.
+ SPos = case bs_match_type(I) of
+ plain ->
+ %% Update position to new position.
+ SPos0#{Start:=NewPos};
+ _ ->
+ %% Position will not change (test_unit
+ %% instruction or no instruction at
+ %% all).
+ SPos0#{Start:=FromPos}
+ end,
+ bs_restores_is(Is, CtxChain, SPos, FPos0, Rs0);
+ #{Start:=_} ->
+ %% Different positions, might need a restore instruction.
+ case bs_match_type(I) of
+ none ->
+ %% This is a tail test that will be optimized away.
+ %% There's no need to do a restore, and all
+ %% positions are unchanged.
+ bs_restores_is(Is, CtxChain, SPos0, FPos0, Rs0);
+ test_unit ->
+ %% This match instruction will be replaced by
+ %% a test_unit instruction. We will need a
+ %% restore. The new position will be the position
+ %% restored to (NOT NewPos).
+ SPos = SPos0#{Start:=FromPos},
+ FPos = FPos0#{Start:=FromPos},
+ Rs = Rs0#{NewPos=>{Start,FromPos}},
+ bs_restores_is(Is, CtxChain, SPos, FPos, Rs);
+ plain ->
+ %% Match or skip. Position will be changed.
+ SPos = SPos0#{Start:=NewPos},
+ FPos = FPos0#{Start:=FromPos},
+ Rs = Rs0#{NewPos=>{Start,FromPos}},
+ bs_restores_is(Is, CtxChain, SPos, FPos, Rs)
+ end
+ end;
+bs_restores_is([#b_set{op=bs_extract,args=[FromPos|_]}|Is],
+ CtxChain, SPos, FPos, Rs) ->
+ Start = bs_subst_ctx(FromPos, CtxChain),
+ #{Start:=FromPos} = SPos, %Assertion.
+ #{Start:=FromPos} = FPos, %Assertion.
+ bs_restores_is(Is, CtxChain, SPos, FPos, Rs);
+bs_restores_is([#b_set{op=call,dst=Dst,args=Args}|Is],
+ CtxChain, SPos0, FPos0, Rs0) ->
+ {Rs, SPos1, FPos1} = bs_restore_args(Args, SPos0, FPos0, CtxChain, Dst, Rs0),
+ {SPos, FPos} = bs_invalidate_pos(Args, SPos1, FPos1, CtxChain),
+ bs_restores_is(Is, CtxChain, SPos, FPos, Rs);
+bs_restores_is([#b_set{op=landingpad}|Is], CtxChain, SPos0, FPos0, Rs) ->
+ %% We can land here from any point, so all positions are invalid.
+ Invalidate = fun(_Start,_Pos) -> unknown end,
+ SPos = maps:map(Invalidate, SPos0),
+ FPos = maps:map(Invalidate, FPos0),
+ bs_restores_is(Is, CtxChain, SPos, FPos, Rs);
+bs_restores_is([#b_set{op=Op,dst=Dst,args=Args}|Is],
+ CtxChain, SPos0, FPos0, Rs0)
+ when Op =:= bs_test_tail;
+ Op =:= bs_get_tail ->
+ {Rs, SPos, FPos} = bs_restore_args(Args, SPos0, FPos0, CtxChain, Dst, Rs0),
+ bs_restores_is(Is, CtxChain, SPos, FPos, Rs);
+bs_restores_is([_|Is], CtxChain, SPos, FPos, Rs) ->
+ bs_restores_is(Is, CtxChain, SPos, FPos, Rs);
+bs_restores_is([], _CtxChain, SPos, FPos, Rs) ->
+ {SPos, FPos, Rs}.
+
+bs_match_type(#b_set{args=[#b_literal{val=skip},_Ctx,
+ #b_literal{val=binary},_Flags,
+ #b_literal{val=all},#b_literal{val=U}]}) ->
+ case U of
+ 1 -> none;
+ _ -> test_unit
+ end;
+bs_match_type(_) ->
+ plain.
+
+%% Call instructions leave the match position in an undefined state,
+%% requiring us to invalidate each affected argument.
+bs_invalidate_pos([#b_var{}=Arg|Args], SPos0, FPos0, CtxChain) ->
+ Start = bs_subst_ctx(Arg, CtxChain),
+ case SPos0 of
+ #{Start:=_} ->
+ SPos = SPos0#{Start:=unknown},
+ FPos = FPos0#{Start:=unknown},
+ bs_invalidate_pos(Args, SPos, FPos, CtxChain);
+ #{} ->
+ %% Not a match context.
+ bs_invalidate_pos(Args, SPos0, FPos0, CtxChain)
+ end;
+bs_invalidate_pos([_|Args], SPos, FPos, CtxChain) ->
+ bs_invalidate_pos(Args, SPos, FPos, CtxChain);
+bs_invalidate_pos([], SPos, FPos, _CtxChain) ->
+ {SPos, FPos}.
+
+bs_restore_args([#b_var{}=Arg|Args], SPos0, FPos0, CtxChain, Dst, Rs0) ->
+ Start = bs_subst_ctx(Arg, CtxChain),
+ case SPos0 of
+ #{Start:=Arg} ->
+ %% Same position, no restore needed.
+ bs_restore_args(Args, SPos0, FPos0, CtxChain, Dst, Rs0);
+ #{Start:=_} ->
+ %% Different positions, need a restore instruction.
+ SPos = SPos0#{Start:=Arg},
+ FPos = FPos0#{Start:=Arg},
+ Rs = Rs0#{Dst=>{Start,Arg}},
+ bs_restore_args(Args, SPos, FPos, CtxChain, Dst, Rs);
+ #{} ->
+ %% Not a match context.
+ bs_restore_args(Args, SPos0, FPos0, CtxChain, Dst, Rs0)
+ end;
+bs_restore_args([_|Args], SPos, FPos, CtxChain, Dst, Rs) ->
+ bs_restore_args(Args, SPos, FPos, CtxChain, Dst, Rs);
+bs_restore_args([], SPos, FPos, _CtxChain, _Dst, Rs) ->
+ {Rs,SPos,FPos}.
+
+%% Insert all bs_save and bs_restore instructions.
+
+bs_insert_bsm3(Blocks, Saves, Restores, SavePoints) ->
+ bs_insert_1(Blocks, Saves, Restores, SavePoints, fun(I) -> I end).
+
+bs_insert_bsm2(Blocks, Saves, Restores, SavePoints) ->
+ %% The old instructions require bs_start_match to be annotated with the
+ %% number of position slots it needs.
+ bs_insert_1(Blocks, Saves, Restores, SavePoints,
+ fun(#b_set{op=bs_start_match,dst=Dst}=I0) ->
+ NumSlots = case SavePoints of
+ #{Dst:=NumSlots0} -> NumSlots0;
+ #{} -> 0
+ end,
+ beam_ssa:add_anno(num_slots, NumSlots, I0);
+ (I) ->
+ I
+ end).
+
+bs_insert_1([{L,#b_blk{is=Is0}=Blk}|Bs0], Saves, Restores, Slots, XFrm) ->
+ Is = bs_insert_is_1(Is0, Restores, Slots, XFrm),
+ Bs = bs_insert_saves(Is, Bs0, Saves),
+ [{L,Blk#b_blk{is=Is}}|bs_insert_1(Bs, Saves, Restores, Slots, XFrm)];
+bs_insert_1([], _, _, _, _) -> [].
+
+bs_insert_is_1([#b_set{op=Op,dst=Dst}=I0|Is], Restores, SavePoints, XFrm) ->
+ I = XFrm(I0),
+ if
+ Op =:= bs_test_tail;
+ Op =:= bs_get_tail;
+ Op =:= bs_match;
+ Op =:= call ->
+ Rs = case Restores of
+ #{Dst:=R} -> [R];
+ #{} -> []
+ end,
+ Rs ++ [I|bs_insert_is_1(Is, Restores, SavePoints, XFrm)];
+ true ->
+ [I|bs_insert_is_1(Is, Restores, SavePoints, XFrm)]
+ end;
+bs_insert_is_1([], _, _, _) -> [].
+
+bs_insert_saves([#b_set{dst=Dst}|Is], Bs, Saves) ->
+ case Saves of
+ #{Dst:=S} ->
+ bs_insert_save(S, Bs);
+ #{} ->
+ bs_insert_saves(Is, Bs, Saves)
+ end;
+bs_insert_saves([], Bs, _) -> Bs.
+
+bs_insert_save(Save, [{L,#b_blk{is=Is0}=Blk}|Bs]) ->
+ Is = case Is0 of
+ [#b_set{op=bs_extract}=Ex|Is1] ->
+ [Ex,Save|Is1];
+ _ ->
+ [Save|Is0]
+ end,
+ [{L,Blk#b_blk{is=Is}}|Bs].
+
+%% Translate bs_match instructions to bs_get, bs_match_string,
+%% or bs_skip. Also rename match context variables to use the
+%% variable assigned to by the start_match instruction.
+
+bs_instrs([{L,#b_blk{is=Is0}=Blk}|Bs], CtxChain, Acc0) ->
+ case bs_instrs_is(Is0, CtxChain, []) of
+ [#b_set{op=bs_extract,dst=Dst,args=[Ctx]}|Is] ->
+ %% Drop this instruction. Rewrite the corresponding
+ %% bs_match instruction in the previous block to
+ %% a bs_get instruction.
+ Acc = bs_combine(Dst, Ctx, Acc0),
+ bs_instrs(Bs, CtxChain, [{L,Blk#b_blk{is=Is}}|Acc]);
+ Is ->
+ bs_instrs(Bs, CtxChain, [{L,Blk#b_blk{is=Is}}|Acc0])
+ end;
+bs_instrs([], _, Acc) ->
+ reverse(Acc).
+
+bs_instrs_is([#b_set{op=Op,args=Args0}=I0|Is], CtxChain, Acc) ->
+ Args = [bs_subst_ctx(A, CtxChain) || A <- Args0],
+ I1 = I0#b_set{args=Args},
+ I = case {Op,Args} of
+ {bs_match,[#b_literal{val=skip},Ctx,Type|As]} ->
+ I1#b_set{op=bs_skip,args=[Type,Ctx|As]};
+ {bs_match,[#b_literal{val=string},Ctx|As]} ->
+ I1#b_set{op=bs_match_string,args=[Ctx|As]};
+ {bs_get_tail,[Ctx|As]} ->
+ I1#b_set{op=bs_get_tail,args=[Ctx|As]};
+ {_,_} ->
+ I1
+ end,
+ bs_instrs_is(Is, CtxChain, [I|Acc]);
+bs_instrs_is([], _, Acc) ->
+ reverse(Acc).
+
+%% Combine a bs_match instruction with the destination register
+%% taken from a bs_extract instruction.
+
+bs_combine(Dst, Ctx, [{L,#b_blk{is=Is0}=Blk}|Acc]) ->
+ [#b_set{}=Succeeded,
+ #b_set{op=bs_match,args=[Type,_|As]}=BsMatch|Is1] = reverse(Is0),
+ Is = reverse(Is1, [BsMatch#b_set{op=bs_get,dst=Dst,args=[Type,Ctx|As]},
+ Succeeded#b_set{args=[Dst]}]),
+ [{L,Blk#b_blk{is=Is}}|Acc].
+
+bs_subst_ctx(#b_var{}=Var, CtxChain) ->
+ case CtxChain of
+ #{Var:={context,Ctx}} ->
+ Ctx;
+ #{Var:=ParentCtx} ->
+ bs_subst_ctx(ParentCtx, CtxChain);
+ #{} ->
+ %% Not a match context variable.
+ Var
+ end;
+bs_subst_ctx(Other, _CtxChain) ->
+ Other.
+
+%% legacy_bs(St0) -> St.
+%% Binary matching instructions in OTP 21 and earlier don't support
+%% a Y register as destination. If St#st.use_bsm3 is false,
+%% we will need to rewrite those instructions so that the result
+%% is first put in an X register and then moved to a Y register
+%% if the operation succeeded.
+
+legacy_bs(#st{use_bsm3=false,ssa=Blocks0,cnt=Count0,res=Res}=St) ->
+ IsYreg = maps:from_list([{V,true} || {V,{y,_}} <- Res]),
+ Linear0 = beam_ssa:linearize(Blocks0),
+ {Linear,Count} = legacy_bs(Linear0, IsYreg, Count0, #{}, []),
+ Blocks = maps:from_list(Linear),
+ St#st{ssa=Blocks,cnt=Count};
+legacy_bs(#st{use_bsm3=true}=St) -> St.
+
+legacy_bs([{L,Blk}|Bs], IsYreg, Count0, Copies0, Acc) ->
+ #b_blk{is=Is0,last=Last} = Blk,
+ Is1 = case Copies0 of
+ #{L:=Copy} -> [Copy|Is0];
+ #{} -> Is0
+ end,
+ {Is,Count,Copies} = legacy_bs_is(Is1, Last, IsYreg, Count0, Copies0, []),
+ legacy_bs(Bs, IsYreg, Count, Copies, [{L,Blk#b_blk{is=Is}}|Acc]);
+legacy_bs([], _IsYreg, Count, _Copies, Acc) ->
+ {Acc,Count}.
+
+legacy_bs_is([#b_set{op=Op,dst=Dst}=I0,
+ #b_set{op=succeeded,dst=SuccDst,args=[Dst]}=SuccI0],
+ Last, IsYreg, Count0, Copies0, Acc) ->
+ NeedsFix = is_map_key(Dst, IsYreg) andalso
+ case Op of
+ bs_get -> true;
+ bs_init -> true;
+ _ -> false
+ end,
+ case NeedsFix of
+ true ->
+ TempDst = #b_var{name={'@bs_temp_dst',Count0}},
+ Count = Count0 + 1,
+ I = I0#b_set{dst=TempDst},
+ SuccI = SuccI0#b_set{args=[TempDst]},
+ Copy = #b_set{op=copy,dst=Dst,args=[TempDst]},
+ #b_br{bool=SuccDst,succ=SuccL} = Last,
+ Copies = Copies0#{SuccL=>Copy},
+ legacy_bs_is([], Last, IsYreg, Count, Copies, [SuccI,I|Acc]);
+ false ->
+ legacy_bs_is([], Last, IsYreg, Count0, Copies0, [SuccI0,I0|Acc])
+ end;
+legacy_bs_is([I|Is], Last, IsYreg, Count, Copies, Acc) ->
+ legacy_bs_is(Is, Last, IsYreg, Count, Copies, [I|Acc]);
+legacy_bs_is([], _Last, _IsYreg, Count, Copies, Acc) ->
+ {reverse(Acc),Count,Copies}.
+
+%% sanitize(St0) -> St.
+%% Remove constructs that can cause problems later:
+%%
+%% * Unreachable blocks may cause problems for determination of
+%% dominators.
+%%
+%% * Some instructions (such as get_hd) don't accept literal
+%% arguments. Evaluate the instructions and remove them.
+
+sanitize(#st{ssa=Blocks0,cnt=Count0}=St) ->
+ Ls = beam_ssa:rpo(Blocks0),
+ {Blocks,Count} = sanitize(Ls, Count0, Blocks0, #{}),
+ St#st{ssa=Blocks,cnt=Count}.
+
+sanitize([L|Ls], Count0, Blocks0, Values0) ->
+ #b_blk{is=Is0} = Blk0 = map_get(L, Blocks0),
+ case sanitize_is(Is0, Count0, Values0, false, []) of
+ no_change ->
+ sanitize(Ls, Count0, Blocks0, Values0);
+ {Is,Count,Values} ->
+ Blk = Blk0#b_blk{is=Is},
+ Blocks = Blocks0#{L:=Blk},
+ sanitize(Ls, Count, Blocks, Values)
+ end;
+sanitize([], Count, Blocks0, Values) ->
+ Blocks = if
+ map_size(Values) =:= 0 ->
+ Blocks0;
+ true ->
+ beam_ssa:rename_vars(Values, [0], Blocks0)
+ end,
+
+ %% Unreachable blocks can cause problems for the dominator calculations.
+ Ls = beam_ssa:rpo(Blocks),
+ Reachable = gb_sets:from_list(Ls),
+ {case map_size(Blocks) =:= gb_sets:size(Reachable) of
+ true -> Blocks;
+ false -> remove_unreachable(Ls, Blocks, Reachable, [])
+ end,Count}.
+
+sanitize_is([#b_set{op=get_map_element,args=Args0}=I0|Is],
+ Count0, Values, Changed, Acc) ->
+ case sanitize_args(Args0, Values) of
+ [#b_literal{}=Map,Key] ->
+ %% Bind the literal map to a variable.
+ {MapVar,Count} = new_var('@ssa_map', Count0),
+ I = I0#b_set{args=[MapVar,Key]},
+ Copy = #b_set{op=copy,dst=MapVar,args=[Map]},
+ sanitize_is(Is, Count, Values, true, [I,Copy|Acc]);
+ [_,_]=Args0 ->
+ sanitize_is(Is, Count0, Values, Changed, [I0|Acc]);
+ [_,_]=Args ->
+ I = I0#b_set{args=Args},
+ sanitize_is(Is, Count0, Values, Changed, [I|Acc])
+ end;
+sanitize_is([#b_set{op=Op,dst=Dst,args=Args0}=I0|Is0],
+ Count, Values, Changed0, Acc) ->
+ Args = sanitize_args(Args0, Values),
+ case sanitize_instr(Op, Args, I0) of
+ {value,Value0} ->
+ Value = #b_literal{val=Value0},
+ sanitize_is(Is0, Count, Values#{Dst=>Value}, true, Acc);
+ {ok,I} ->
+ sanitize_is(Is0, Count, Values, true, [I|Acc]);
+ ok ->
+ I = I0#b_set{args=Args},
+ Changed = Changed0 orelse Args =/= Args0,
+ sanitize_is(Is0, Count, Values, Changed, [I|Acc])
+ end;
+sanitize_is([], Count, Values, Changed, Acc) ->
+ case Changed of
+ true ->
+ {reverse(Acc),Count,Values};
+ false ->
+ no_change
+ end.
+
+sanitize_args(Args, Values) ->
+ map(fun(Var) ->
+ case Values of
+ #{Var:=New} -> New;
+ #{} -> Var
+ end
+ end, Args).
+
+sanitize_instr({bif,Bif}, [#b_literal{val=Lit}], _I) ->
+ case erl_bifs:is_pure(erlang, Bif, 1) of
+ false ->
+ ok;
+ true ->
+ try
+ {value,erlang:Bif(Lit)}
+ catch
+ error:_ ->
+ ok
+ end
+ end;
+sanitize_instr({bif,Bif}, [#b_literal{val=Lit1},#b_literal{val=Lit2}], _I) ->
+ true = erl_bifs:is_pure(erlang, Bif, 2), %Assertion.
+ try
+ {value,erlang:Bif(Lit1, Lit2)}
+ catch
+ error:_ ->
+ ok
+ end;
+sanitize_instr(get_hd, [#b_literal{val=[Hd|_]}], _I) ->
+ {value,Hd};
+sanitize_instr(get_tl, [#b_literal{val=[_|Tl]}], _I) ->
+ {value,Tl};
+sanitize_instr(get_tuple_element, [#b_literal{val=T},
+ #b_literal{val=I}], _I)
+ when I < tuple_size(T) ->
+ {value,element(I+1, T)};
+sanitize_instr(is_nonempty_list, [#b_literal{val=Lit}], _I) ->
+ {value,case Lit of
+ [_|_] -> true;
+ _ -> false
+ end};
+sanitize_instr(is_tagged_tuple, [#b_literal{val=Tuple},
+ #b_literal{val=Arity},
+ #b_literal{val=Tag}], _I)
+ when is_integer(Arity), is_atom(Tag) ->
+ if
+ tuple_size(Tuple) =:= Arity, element(1, Tuple) =:= Tag ->
+ {value,true};
+ true ->
+ {value,false}
+ end;
+sanitize_instr(bs_init, [#b_literal{val=new},#b_literal{val=Sz}|_], I0) ->
+ if
+ is_integer(Sz), Sz >= 0 -> ok;
+ true -> {ok,sanitize_badarg(I0)}
+ end;
+sanitize_instr(bs_init, [#b_literal{val=append},_,#b_literal{val=Sz}|_], I0) ->
+ if
+ is_integer(Sz), Sz >= 0 -> ok;
+ true -> {ok,sanitize_badarg(I0)}
+ end;
+sanitize_instr(succeeded, [#b_literal{}], _I) ->
+ {value,true};
+sanitize_instr(_, _, _) -> ok.
+
+sanitize_badarg(I) ->
+ Func = #b_remote{mod=#b_literal{val=erlang},
+ name=#b_literal{val=error},arity=1},
+ I#b_set{op=call,args=[Func,#b_literal{val=badarg}]}.
+
+remove_unreachable([L|Ls], Blocks, Reachable, Acc) ->
+ #b_blk{is=Is0} = Blk0 = map_get(L, Blocks),
+ case split_phis(Is0) of
+ {[_|_]=Phis,Rest} ->
+ Is = [prune_phi(Phi, Reachable) || Phi <- Phis] ++ Rest,
+ Blk = Blk0#b_blk{is=Is},
+ remove_unreachable(Ls, Blocks, Reachable, [{L,Blk}|Acc]);
+ {[],_} ->
+ remove_unreachable(Ls, Blocks, Reachable, [{L,Blk0}|Acc])
+ end;
+remove_unreachable([], _Blocks, _, Acc) ->
+ maps:from_list(Acc).
+
+prune_phi(#b_set{args=Args0}=Phi, Reachable) ->
+ Args = [A || {_,Pred}=A <- Args0,
+ gb_sets:is_element(Pred, Reachable)],
+ Phi#b_set{args=Args}.
+
+%%%
+%%% Fix tuples.
+%%%
+
+%% fix_tuples(St0) -> St.
+%% If compatibility with a previous version of Erlang has been
+%% requested, tuple creation must be split into two instruction to
+%% mirror the the way tuples are created in BEAM prior to OTP 22.
+%% Each put_tuple instruction is split into put_tuple_arity followed
+%% by put_tuple_elements.
+
+fix_tuples(#st{ssa=Blocks0,cnt=Count0}=St) ->
+ F = fun (#b_set{op=put_tuple,args=Args}=Put, C0) ->
+ Arity = #b_literal{val=length(Args)},
+ {Ignore,C} = new_var('@ssa_ignore', C0),
+ {[Put#b_set{op=put_tuple_arity,args=[Arity]},
+ #b_set{dst=Ignore,op=put_tuple_elements,args=Args}],C};
+ (I, C) -> {[I],C}
+ end,
+ {Blocks,Count} = beam_ssa:flatmapfold_instrs_rpo(F, [0], Count0, Blocks0),
+ St#st{ssa=Blocks,cnt=Count}.
+
+%%%
+%%% Introduce the set_tuple_element instructions to make
+%%% multiple-field record updates faster.
+%%%
+%%% The expansion of record field updates, when more than one field is
+%%% updated, but not a majority of the fields, will create a sequence of
+%%% calls to `erlang:setelement(Index, Value, Tuple)` where Tuple in the
+%%% first call is the original record tuple, and in the subsequent calls
+%%% Tuple is the result of the previous call. Furthermore, all Index
+%%% values are constant positive integers, and the first call to
+%%% `setelement` will have the greatest index. Thus all the following
+%%% calls do not actually need to test at run-time whether Tuple has type
+%%% tuple, nor that the index is within the tuple bounds.
+%%%
+%%% Since this optimization introduces destructive updates, it used to
+%%% be done as the very last Core Erlang pass before going to
+%%% lower-level code. However, it turns out that this kind of destructive
+%%% updates are awkward also in SSA code and can prevent or complicate
+%%% type analysis and aggressive optimizations.
+%%%
+%%% NOTE: Because there no write barriers in the system, this kind of
+%%% optimization can only be done when we are sure that garbage
+%%% collection will not be triggered between the creation of the tuple
+%%% and the destructive updates - otherwise we might insert pointers
+%%% from an older generation to a newer.
+%%%
+
+use_set_tuple_element(#st{ssa=Blocks0}=St) ->
+ Uses = count_uses(Blocks0),
+ RPO = reverse(beam_ssa:rpo(Blocks0)),
+ Blocks = use_ste_1(RPO, Uses, Blocks0),
+ St#st{ssa=Blocks}.
+
+use_ste_1([L|Ls], Uses, Blocks0) ->
+ {Blk0,Blocks} = use_ste_across(L, Uses, Blocks0),
+ #b_blk{is=Is0} = Blk0,
+ case use_ste_is(Is0, Uses) of
+ Is0 ->
+ use_ste_1(Ls, Uses, Blocks);
+ Is ->
+ Blk = Blk0#b_blk{is=Is},
+ use_ste_1(Ls, Uses, Blocks#{L:=Blk})
+ end;
+use_ste_1([], _, Blocks) -> Blocks.
+
+%%% Optimize within a single block.
+
+use_ste_is([#b_set{}=I|Is0], Uses) ->
+ Is = use_ste_is(Is0, Uses),
+ case extract_ste(I) of
+ none ->
+ [I|Is];
+ Extracted ->
+ use_ste_call(Extracted, I, Is, Uses)
+ end;
+use_ste_is([], _Uses) -> [].
+
+use_ste_call({Dst0,Pos0,_Var0,_Val0}, Call1, Is0, Uses) ->
+ case get_ste_call(Is0, []) of
+ {Prefix,{Dst1,Pos1,Dst0,Val1},Call2,Is}
+ when Pos1 > 0, Pos0 > Pos1 ->
+ case is_single_use(Dst0, Uses) of
+ true ->
+ Call = Call1#b_set{dst=Dst1},
+ Args = [Val1,Dst1,#b_literal{val=Pos1-1}],
+ Dsetel = Call2#b_set{op=set_tuple_element,
+ dst=Dst0,
+ args=Args},
+ [Call|Prefix] ++ [Dsetel|Is];
+ false ->
+ [Call1|Is0]
+ end;
+ _ ->
+ [Call1|Is0]
+ end.
+
+get_ste_call([#b_set{op=get_tuple_element}=I|Is], Acc) ->
+ get_ste_call(Is, [I|Acc]);
+get_ste_call([#b_set{op=call}=I|Is], Acc) ->
+ case extract_ste(I) of
+ none ->
+ none;
+ Extracted ->
+ {reverse(Acc),Extracted,I,Is}
+ end;
+get_ste_call(_, _) -> none.
+
+extract_ste(#b_set{op=call,dst=Dst,
+ args=[#b_remote{mod=#b_literal{val=M},
+ name=#b_literal{val=F}}|Args]}) ->
+ case {M,F,Args} of
+ {erlang,setelement,[#b_literal{val=Pos},Tuple,Val]} ->
+ {Dst,Pos,Tuple,Val};
+ {_,_,_} ->
+ none
+ end;
+extract_ste(#b_set{}) -> none.
+
+%%% Optimize accross blocks within a try/catch block.
+
+use_ste_across(L, Uses, Blocks) ->
+ case map_get(L, Blocks) of
+ #b_blk{last=#b_br{bool=#b_var{}}}=Blk ->
+ try
+ use_ste_across_1(L, Blk, Uses, Blocks)
+ catch
+ throw:not_possible ->
+ {Blk,Blocks}
+ end;
+ #b_blk{}=Blk ->
+ {Blk,Blocks}
+ end.
+
+use_ste_across_1(L, Blk0, Uses, Blocks0) ->
+ #b_blk{is=IsThis,last=#b_br{bool=Bool,succ=Next}} = Blk0,
+ case reverse(IsThis) of
+ [#b_set{op=succeeded,dst=Bool,args=[Result]}=Succ0,
+ #b_set{op=call,args=[#b_remote{}|_],dst=Result}=Call1|Prefix] ->
+ case is_single_use(Bool, Uses) andalso
+ is_n_uses(2, Result, Uses) of
+ true -> ok;
+ false -> throw(not_possible)
+ end,
+ Call2 = use_ste_across_next(Next, Uses, Blocks0),
+ Is = [Call1,Call2],
+ case use_ste_is(Is, decrement_uses(Result, Uses)) of
+ [#b_set{}=Call,#b_set{op=set_tuple_element}=Ste] ->
+ Blocks1 = use_ste_fix_next(Ste, Next, Blocks0),
+ Succ = Succ0#b_set{args=[Call#b_set.dst]},
+ Blk = Blk0#b_blk{is=reverse(Prefix, [Call,Succ])},
+ Blocks = Blocks1#{L:=Blk},
+ {Blk,Blocks};
+ _ ->
+ throw(not_possible)
+ end;
+ _ ->
+ throw(not_possible)
+ end.
+
+use_ste_across_next(Next, Uses, Blocks) ->
+ case map_get(Next, Blocks) of
+ #b_blk{is=[#b_set{op=call,dst=Result,args=[#b_remote{}|_]}=Call,
+ #b_set{op=succeeded,dst=Bool,args=[Result]}],
+ last=#b_br{bool=Bool}} ->
+ case is_single_use(Bool, Uses) andalso
+ is_n_uses(2, Result, Uses) of
+ true -> ok;
+ false -> throw(not_possible)
+ end,
+ Call;
+ #b_blk{} ->
+ throw(not_possible)
+ end.
+
+use_ste_fix_next(Ste, Next, Blocks) ->
+ Blk0 = map_get(Next, Blocks),
+ #b_blk{is=[#b_set{op=call},#b_set{op=succeeded}],last=Br0} = Blk0,
+ Br = beam_ssa:normalize(Br0#b_br{bool=#b_literal{val=true}}),
+ Blk = Blk0#b_blk{is=[Ste],last=Br},
+ Blocks#{Next:=Blk}.
+
+%% Count how many times each variable is used.
+
+count_uses(Blocks) ->
+ count_uses_blk(maps:values(Blocks), #{}).
+
+count_uses_blk([#b_blk{is=Is,last=Last}|Bs], CountMap0) ->
+ F = fun(I, CountMap) ->
+ foldl(fun(Var, Acc) ->
+ case Acc of
+ #{Var:=3} -> Acc;
+ #{Var:=C} -> Acc#{Var:=C+1};
+ #{} -> Acc#{Var=>1}
+ end
+ end, CountMap, beam_ssa:used(I))
+ end,
+ CountMap = F(Last, foldl(F, CountMap0, Is)),
+ count_uses_blk(Bs, CountMap);
+count_uses_blk([], CountMap) -> CountMap.
+
+decrement_uses(V, Uses) ->
+ #{V:=C} = Uses,
+ Uses#{V:=C-1}.
+
+is_n_uses(N, V, Uses) ->
+ case Uses of
+ #{V:=N} -> true;
+ #{} -> false
+ end.
+
+is_single_use(V, Uses) ->
+ case Uses of
+ #{V:=1} -> true;
+ #{} -> false
+ end.
+
+%%%
+%%% Find out where frames should be placed.
+%%%
+
+%% place_frames(St0) -> St.
+%% Return a list of the labels for the blocks that need stack frame
+%% allocation instructions.
+%%
+%% This function attempts to place stack frames as tight as possible
+%% around the code, to avoid building stack frames for code paths
+%% that don't need one.
+%%
+%% Stack frames are placed in blocks that dominate all of their
+%% descendants. That guarantees that the deallocation instructions
+%% cannot be reached from other execution paths that didn't set up
+%% a stack frame or set up a stack frame with a different size.
+
+place_frames(#st{ssa=Blocks}=St) ->
+ {Doms,_} = beam_ssa:dominators(Blocks),
+ Ls = beam_ssa:rpo(Blocks),
+ Tried = gb_sets:empty(),
+ Frames0 = [],
+ {Frames,_} = place_frames_1(Ls, Blocks, Doms, Tried, Frames0),
+ St#st{frames=Frames}.
+
+place_frames_1([L|Ls], Blocks, Doms, Tried0, Frames0) ->
+ Blk = map_get(L, Blocks),
+ case need_frame(Blk) of
+ true ->
+ %% This block needs a frame. Try to place it here.
+ {Frames,Tried} = do_place_frame(L, Blocks, Doms, Tried0, Frames0),
+
+ %% Successfully placed. Try to place more frames in descendants
+ %% that are not dominated by this block.
+ place_frames_1(Ls, Blocks, Doms, Tried, Frames);
+ false ->
+ try
+ place_frames_1(Ls, Blocks, Doms, Tried0, Frames0)
+ catch
+ throw:{need_frame,For,Tried1}=Reason ->
+ %% An descendant block needs a stack frame. Try to
+ %% place it here.
+ case is_dominated_by(For, L, Doms) of
+ true ->
+ %% Try to place a frame here.
+ {Frames,Tried} = do_place_frame(L, Blocks, Doms,
+ Tried1, Frames0),
+ place_frames_1(Ls, Blocks, Doms, Tried, Frames);
+ false ->
+ %% Wrong place. This block does not dominate
+ %% the block that needs the frame. Pass it on
+ %% to our ancestors.
+ throw(Reason)
+ end
+ end
+ end;
+place_frames_1([], _, _, Tried, Frames) ->
+ {Frames,Tried}.
+
+%% do_place_frame(Label, Blocks, Dominators, Tried0, Frames0) -> {Frames,Tried}.
+%% Try to place a frame in this block. This function returns
+%% successfully if it either succeds at placing a frame in this
+%% block, if an ancestor that dominates this block has already placed
+%% a frame, or if we have already tried to put a frame in this block.
+%%
+%% An {need_frame,Label,Tried} exception will be thrown if this block
+%% block is not suitable for having a stack frame (i.e. it does not dominate
+%% all of its descendants). The exception means that an ancestor will have to
+%% place the frame needed by this block.
+
+do_place_frame(L, Blocks, Doms, Tried0, Frames) ->
+ case gb_sets:is_element(L, Tried0) of
+ true ->
+ %% We have already tried to put a frame in this block.
+ {Frames,Tried0};
+ false ->
+ %% Try to place a frame in this block.
+ Tried = gb_sets:insert(L, Tried0),
+ case place_frame_here(L, Blocks, Doms, Frames) of
+ yes ->
+ %% We need a frame and it is safe to place it here.
+ {[L|Frames],Tried};
+ no ->
+ %% An ancestor has a frame. Not needed.
+ {Frames,Tried};
+ ancestor ->
+ %% This block does not dominate all of its
+ %% descendants. We must place the frame in
+ %% an ancestor.
+ throw({need_frame,L,Tried})
+ end
+ end.
+
+%% place_frame_here(Label, Blocks, Doms, Frames) -> no|yes|ancestor.
+%% Determine whether a frame should be placed in block Label.
+
+place_frame_here(L, Blocks, Doms, Frames) ->
+ B0 = any(fun(DomBy) ->
+ is_dominated_by(L, DomBy, Doms)
+ end, Frames),
+ case B0 of
+ true ->
+ %% This block is dominated by an ancestor block that
+ %% defines a frame. Not needed/allowed to put a frame
+ %% here.
+ no;
+ false ->
+ %% No frame in any ancestor. We need a frame.
+ %% Now check whether the frame can be placed here.
+ %% If this block dominates all of its descendants
+ %% and the predecessors of any phi nodes it can be
+ %% placed here.
+ Descendants = beam_ssa:rpo([L], Blocks),
+ PhiPredecessors = phi_predecessors(L, Blocks),
+ MustDominate = ordsets:from_list(PhiPredecessors ++ Descendants),
+ Dominates = all(fun(?BADARG_BLOCK) ->
+ %% This block defines no variables and calls
+ %% erlang:error(badarg). It does not matter
+ %% whether L dominates ?BADARG_BLOCK or not;
+ %% it is still safe to put the frame in L.
+ true;
+ (Bl) ->
+ is_dominated_by(Bl, L, Doms)
+ end, MustDominate),
+
+ %% Also, this block must not be a loop header.
+ IsLoopHeader = is_loop_header(L, Blocks),
+ case Dominates andalso not IsLoopHeader of
+ true -> yes;
+ false -> ancestor
+ end
+ end.
+
+%% phi_predecessors(Label, Blocks) ->
+%% Return all predecessors referenced in phi nodes.
+
+phi_predecessors(L, Blocks) ->
+ #b_blk{is=Is} = map_get(L, Blocks),
+ [P || #b_set{op=phi,args=Args} <- Is, {_,P} <- Args].
+
+%% is_dominated_by(Label, DominatedBy, Dominators) -> true|false.
+%% Test whether block Label is dominated by block DominatedBy.
+
+is_dominated_by(L, DomBy, Doms) ->
+ DominatedBy = map_get(L, Doms),
+ member(DomBy, DominatedBy).
+
+%% need_frame(#b_blk{}) -> true|false.
+%% Test whether any of the instructions in the block requires a stack frame.
+
+need_frame(#b_blk{is=Is,last=#b_ret{arg=Ret}}) ->
+ need_frame_1(Is, {return,Ret});
+need_frame(#b_blk{is=Is}) ->
+ need_frame_1(Is, body).
+
+need_frame_1([#b_set{op=make_fun,dst=Fun}|Is], {return,_}=Context) ->
+ %% Since make_fun clobbers X registers, a stack frame is needed if
+ %% any of the following instructions use any other variable than
+ %% the one holding the reference to the created fun.
+ need_frame_1(Is, Context) orelse
+ case beam_ssa:used(#b_blk{is=Is,last=#b_ret{arg=Fun}}) of
+ [Fun] -> false;
+ [_|_] -> true
+ end;
+need_frame_1([#b_set{op=new_try_tag}|_], _) ->
+ true;
+need_frame_1([#b_set{op=call,dst=Val}]=Is, {return,Ret}) ->
+ if
+ Val =:= Ret -> need_frame_1(Is, tail);
+ true -> need_frame_1(Is, body)
+ end;
+need_frame_1([#b_set{op=call,args=[Func|_]}|Is], Context) ->
+ case Func of
+ #b_remote{mod=#b_literal{val=Mod},
+ name=#b_literal{val=Name},
+ arity=Arity} when is_atom(Mod), is_atom(Name) ->
+ case erl_bifs:is_exit_bif(Mod, Name, Arity) of
+ true ->
+ false;
+ false ->
+ Context =:= body orelse
+ Is =/= [] orelse
+ is_trap_bif(Mod, Name, Arity)
+ end;
+ #b_remote{} ->
+ %% This is an apply(), which always needs a frame.
+ true;
+ #b_local{} ->
+ Context =:= body orelse Is =/= [];
+ _ ->
+ %% A fun call always needs a frame.
+ true
+ end;
+need_frame_1([I|Is], Context) ->
+ beam_ssa:clobbers_xregs(I) orelse need_frame_1(Is, Context);
+need_frame_1([], _) -> false.
+
+%% is_trap_bif(Mod, Name, Arity) -> true|false.
+%% Test whether we need a stack frame for this BIF.
+
+is_trap_bif(erlang, '!', 2) -> true;
+is_trap_bif(erlang, link, 1) -> true;
+is_trap_bif(erlang, unlink, 1) -> true;
+is_trap_bif(erlang, monitor_node, 2) -> true;
+is_trap_bif(erlang, group_leader, 2) -> true;
+is_trap_bif(erlang, exit, 2) -> true;
+is_trap_bif(_, _, _) -> false.
+
+%%%
+%%% Fix variables used in matching in receive.
+%%%
+%%% The loop_rec/2 instruction may return a reference to a
+%%% message outside of any heap or heap fragment. If the message
+%%% does not match, it is not allowed to store any reference to
+%%% the message (or part of the message) on the stack. If we do,
+%%% the message will be corrupted if there happens to be a GC.
+%%%
+%%% Here we make sure to introduce copies of variables that are
+%%% matched out and subsequently used after the remove_message/0
+%%% instructions. That will make sure that only X registers are
+%%% used during matching.
+%%%
+%%% Depending on where variables are defined and used, they must
+%%% be handled in two different ways.
+%%%
+%%% Variables that are always defined in the receive (before branching
+%%% out into the different clauses of the receive) and used after the
+%%% receive must be handled in the following way: Before each
+%%% remove_message instruction, each such variable must be copied, and
+%%% all variables must be consolidated using a phi node in the
+%%% common exit block for the receive.
+%%%
+%%% Variables that are matched out and used in the same clause
+%%% need copy instructions before the remove_message instruction
+%%% in that clause.
+%%%
+
+fix_receives(#st{ssa=Blocks0,cnt=Count0}=St) ->
+ {Blocks,Count} = fix_receives_1(maps:to_list(Blocks0),
+ Blocks0, Count0),
+ St#st{ssa=Blocks,cnt=Count}.
+
+fix_receives_1([{L,Blk}|Ls], Blocks0, Count0) ->
+ case Blk of
+ #b_blk{is=[#b_set{op=peek_message}|_]} ->
+ Rm = find_rm_blocks(L, Blocks0),
+ LoopExit = find_loop_exit(Rm, Blocks0),
+ Defs0 = beam_ssa:def([L], Blocks0),
+ CommonUsed = recv_common(Defs0, LoopExit, Blocks0),
+ {Blocks1,Count1} = recv_fix_common(CommonUsed, LoopExit, Rm,
+ Blocks0, Count0),
+ Defs = ordsets:subtract(Defs0, CommonUsed),
+ {Blocks,Count} = fix_receive(Rm, Defs, Blocks1, Count1),
+ fix_receives_1(Ls, Blocks, Count);
+ #b_blk{} ->
+ fix_receives_1(Ls, Blocks0, Count0)
+ end;
+fix_receives_1([], Blocks, Count) ->
+ {Blocks,Count}.
+
+recv_common(_Defs, none, _Blocks) ->
+ %% There is no common exit block because receive is used
+ %% in the tail position of a function.
+ [];
+recv_common(Defs, Exit, Blocks) ->
+ {ExitDefs,ExitUsed} = beam_ssa:def_used([Exit], Blocks),
+ Def = ordsets:subtract(Defs, ExitDefs),
+ ordsets:intersection(Def, ExitUsed).
+
+%% recv_fix_common([CommonVar], LoopExit, [RemoveMessageLabel],
+%% Blocks0, Count0) -> {Blocks,Count}.
+%% Handle variables alwys defined in a receive and used
+%% in the exit block following the receive.
+
+recv_fix_common([Msg0|T], Exit, Rm, Blocks0, Count0) ->
+ {Msg,Count1} = new_var('@recv', Count0),
+ Blocks1 = beam_ssa:rename_vars(#{Msg0=>Msg}, [Exit], Blocks0),
+ N = length(Rm),
+ {MsgVars,Count} = new_vars(duplicate(N, '@recv'), Count1),
+ PhiArgs = fix_exit_phi_args(MsgVars, Rm, Exit, Blocks1),
+ Phi = #b_set{op=phi,dst=Msg,args=PhiArgs},
+ ExitBlk0 = map_get(Exit, Blocks1),
+ ExitBlk = ExitBlk0#b_blk{is=[Phi|ExitBlk0#b_blk.is]},
+ Blocks2 = Blocks1#{Exit:=ExitBlk},
+ Blocks = recv_fix_common_1(MsgVars, Rm, Msg0, Blocks2),
+ recv_fix_common(T, Exit, Rm, Blocks, Count);
+recv_fix_common([], _, _, Blocks, Count) ->
+ {Blocks,Count}.
+
+recv_fix_common_1([V|Vs], [Rm|Rms], Msg, Blocks0) ->
+ Ren = #{Msg=>V},
+ Blocks1 = beam_ssa:rename_vars(Ren, [Rm], Blocks0),
+ #b_blk{is=Is0} = Blk0 = map_get(Rm, Blocks1),
+ Copy = #b_set{op=copy,dst=V,args=[Msg]},
+ Is = insert_after_phis(Is0, [Copy]),
+ Blk = Blk0#b_blk{is=Is},
+ Blocks = Blocks1#{Rm:=Blk},
+ recv_fix_common_1(Vs, Rms, Msg, Blocks);
+recv_fix_common_1([], [], _Msg, Blocks) -> Blocks.
+
+fix_exit_phi_args([V|Vs], [Rm|Rms], Exit, Blocks) ->
+ Path = beam_ssa:rpo([Rm], Blocks),
+ Preds = exit_predecessors(Path, Exit, Blocks),
+ [{V,Pred} || Pred <- Preds] ++ fix_exit_phi_args(Vs, Rms, Exit, Blocks);
+fix_exit_phi_args([], [], _, _) -> [].
+
+exit_predecessors([L|Ls], Exit, Blocks) ->
+ Blk = map_get(L, Blocks),
+ case member(Exit, beam_ssa:successors(Blk)) of
+ true ->
+ [L|exit_predecessors(Ls, Exit, Blocks)];
+ false ->
+ exit_predecessors(Ls, Exit, Blocks)
+ end;
+exit_predecessors([], _Exit, _Blocks) -> [].
+
+%% fix_receive([Label], Defs, Blocks0, Count0) -> {Blocks,Count}.
+%% Add a copy instruction for all variables that are matched out and
+%% later used within a clause of the receive.
+
+fix_receive([L|Ls], Defs, Blocks0, Count0) ->
+ {RmDefs,Used0} = beam_ssa:def_used([L], Blocks0),
+ Def = ordsets:subtract(Defs, RmDefs),
+ Used = ordsets:intersection(Def, Used0),
+ {NewVars,Count} = new_vars([Base || #b_var{name=Base} <- Used], Count0),
+ Ren = zip(Used, NewVars),
+ Blocks1 = beam_ssa:rename_vars(Ren, [L], Blocks0),
+ #b_blk{is=Is0} = Blk1 = map_get(L, Blocks1),
+ CopyIs = [#b_set{op=copy,dst=New,args=[Old]} || {Old,New} <- Ren],
+ Is = insert_after_phis(Is0, CopyIs),
+ Blk = Blk1#b_blk{is=Is},
+ Blocks = Blocks1#{L:=Blk},
+ fix_receive(Ls, Defs, Blocks, Count);
+fix_receive([], _Defs, Blocks, Count) ->
+ {Blocks,Count}.
+
+%% find_loop_exit([Label], Blocks) -> Label | none.
+%% Find the block to which control is transferred when the
+%% the receive loop is exited.
+
+find_loop_exit([L1,L2|_Ls], Blocks) ->
+ Path1 = beam_ssa:rpo([L1], Blocks),
+ Path2 = beam_ssa:rpo([L2], Blocks),
+ find_loop_exit_1(reverse(Path1), reverse(Path2), none);
+find_loop_exit(_, _) -> none.
+
+find_loop_exit_1([H|T1], [H|T2], _) ->
+ find_loop_exit_1(T1, T2, H);
+find_loop_exit_1(_, _, Exit) -> Exit.
+
+%% find_rm_blocks(StartLabel, Blocks) -> [Label].
+%% Find all blocks that start with remove_message within the receive
+%% loop whose peek_message label is StartLabel.
+
+find_rm_blocks(L, Blocks) ->
+ Seen = gb_sets:singleton(L),
+ Blk = map_get(L, Blocks),
+ Succ = beam_ssa:successors(Blk),
+ find_rm_blocks_1(Succ, Seen, Blocks).
+
+find_rm_blocks_1([L|Ls], Seen0, Blocks) ->
+ case gb_sets:is_member(L, Seen0) of
+ true ->
+ find_rm_blocks_1(Ls, Seen0, Blocks);
+ false ->
+ Seen = gb_sets:insert(L, Seen0),
+ Blk = map_get(L, Blocks),
+ case find_rm_act(Blk#b_blk.is) of
+ prune ->
+ %% Looping back. Don't look at any successors.
+ find_rm_blocks_1(Ls, Seen, Blocks);
+ continue ->
+ %% Neutral block. Do nothing here, but look at
+ %% all successors.
+ Succ = beam_ssa:successors(Blk),
+ find_rm_blocks_1(Succ++Ls, Seen, Blocks);
+ found ->
+ %% Found remove_message instruction.
+ [L|find_rm_blocks_1(Ls, Seen, Blocks)]
+ end
+ end;
+find_rm_blocks_1([], _, _) -> [].
+
+find_rm_act([#b_set{op=Op}|Is]) ->
+ case Op of
+ remove_message -> found;
+ peek_message -> prune;
+ recv_next -> prune;
+ wait_timeout -> prune;
+ wait -> prune;
+ _ -> find_rm_act(Is)
+ end;
+find_rm_act([]) ->
+ continue.
+
+%%%
+%%% Find out which variables need to be stored in Y registers.
+%%%
+
+-record(dk, {d :: ordsets:ordset(var_name()),
+ k :: ordsets:ordset(var_name())
+ }).
+
+%% find_yregs(St0) -> St.
+%% Find all variables that must be stored in Y registers. Annotate
+%% the blocks that allocate frames with the set of Y registers
+%% used within that stack frame.
+%%
+%% Basically, we following all execution paths starting from a block
+%% that allocates a frame, keeping track of of all defined registers
+%% and all registers killed by an instruction that clobbers X
+%% registers. For every use of a variable, we check if if it is in
+%% the set of killed variables; if it is, it must be stored in an Y
+%% register.
+
+find_yregs(#st{frames=[]}=St) ->
+ St;
+find_yregs(#st{frames=[_|_]=Frames,args=Args,ssa=Blocks0}=St) ->
+ FrameDefs = find_defs(Frames, Blocks0, [V || #b_var{}=V <- Args]),
+ Blocks = find_yregs_1(FrameDefs, Blocks0),
+ St#st{ssa=Blocks}.
+
+find_yregs_1([{F,Defs}|Fs], Blocks0) ->
+ DK = #dk{d=Defs,k=[]},
+ D0 = #{F=>DK},
+ Ls = beam_ssa:rpo([F], Blocks0),
+ Yregs0 = [],
+ Yregs = find_yregs_2(Ls, Blocks0, D0, Yregs0),
+ Blk0 = map_get(F, Blocks0),
+ Blk = beam_ssa:add_anno(yregs, Yregs, Blk0),
+ Blocks = Blocks0#{F:=Blk},
+ find_yregs_1(Fs, Blocks);
+find_yregs_1([], Blocks) -> Blocks.
+
+find_yregs_2([L|Ls], Blocks0, D0, Yregs0) ->
+ Blk0 = map_get(L, Blocks0),
+ #b_blk{is=Is,last=Last} = Blk0,
+ Ys0 = map_get(L, D0),
+ {Yregs1,Ys} = find_yregs_is(Is, Ys0, Yregs0),
+ Yregs = find_yregs_terminator(Last, Ys, Yregs1),
+ Successors = beam_ssa:successors(Blk0),
+ D = find_update_succ(Successors, Ys, D0),
+ find_yregs_2(Ls, Blocks0, D, Yregs);
+find_yregs_2([], _Blocks, _D, Yregs) -> Yregs.
+
+find_defs(Frames, Blocks, Defs) ->
+ Seen = gb_sets:empty(),
+ FramesSet = gb_sets:from_list(Frames),
+ {FrameDefs,_} = find_defs_1([0], Blocks, FramesSet, Seen, Defs, []),
+ FrameDefs.
+
+find_defs_1([L|Ls], Blocks, Frames, Seen0, Defs0, Acc0) ->
+ case gb_sets:is_member(L, Frames) of
+ true ->
+ OrderedDefs = ordsets:from_list(Defs0),
+ find_defs_1(Ls, Blocks, Frames, Seen0, Defs0,
+ [{L,OrderedDefs}|Acc0]);
+ false ->
+ case gb_sets:is_member(L, Seen0) of
+ true ->
+ find_defs_1(Ls, Blocks, Frames, Seen0, Defs0, Acc0);
+ false ->
+ Seen1 = gb_sets:insert(L, Seen0),
+ {Acc,Seen} = find_defs_1(Ls, Blocks, Frames, Seen1, Defs0, Acc0),
+ #b_blk{is=Is} = Blk = map_get(L, Blocks),
+ Defs = find_defs_is(Is, Defs0),
+ Successors = beam_ssa:successors(Blk),
+ find_defs_1(Successors, Blocks, Frames, Seen, Defs, Acc)
+ end
+ end;
+find_defs_1([], _, _, Seen, _, Acc) ->
+ {Acc,Seen}.
+
+find_defs_is([#b_set{dst=Dst}|Is], Acc) ->
+ find_defs_is(Is, [Dst|Acc]);
+find_defs_is([], Acc) -> Acc.
+
+find_update_succ([S|Ss], #dk{d=Defs0,k=Killed0}=DK0, D0) ->
+ case D0 of
+ #{S:=#dk{d=Defs1,k=Killed1}} ->
+ Defs = ordsets:intersection(Defs0, Defs1),
+ Killed = ordsets:union(Killed0, Killed1),
+ DK = #dk{d=Defs,k=Killed},
+ D = D0#{S:=DK},
+ find_update_succ(Ss, DK0, D);
+ #{} ->
+ D = D0#{S=>DK0},
+ find_update_succ(Ss, DK0, D)
+ end;
+find_update_succ([], _, D) -> D.
+
+find_yregs_is([#b_set{dst=Dst}=I|Is], #dk{d=Defs0,k=Killed0}=Ys, Yregs0) ->
+ Used = beam_ssa:used(I),
+ Yregs1 = ordsets:intersection(Used, Killed0),
+ Yregs = ordsets:union(Yregs0, Yregs1),
+ case beam_ssa:clobbers_xregs(I) of
+ false ->
+ Defs = ordsets:add_element(Dst, Defs0),
+ find_yregs_is(Is, Ys#dk{d=Defs}, Yregs);
+ true ->
+ Killed = ordsets:union(Defs0, Killed0),
+ Defs = [Dst],
+ find_yregs_is(Is, Ys#dk{d=Defs,k=Killed}, Yregs)
+ end;
+find_yregs_is([], Ys, Yregs) -> {Yregs,Ys}.
+
+find_yregs_terminator(Terminator, #dk{k=Killed}, Yregs0) ->
+ Used = beam_ssa:used(Terminator),
+ Yregs = ordsets:intersection(Used, Killed),
+ ordsets:union(Yregs0, Yregs).
+
+%%%
+%%% Try to reduce the size of the stack frame, by adding an explicit
+%%% 'copy' instructions for return values from 'call' and 'make_fun' that
+%%% need to be saved in Y registers. Here is an example to show
+%%% how that's useful. First, here is the Erlang code:
+%%%
+%%% f(Pid) ->
+%%% Res = foo(42),
+%%% _ = node(Pid),
+%%% bar(),
+%%% Res.
+%%%
+%%% Compiled to SSA format, the main part of the code looks like this:
+%%%
+%%% 0:
+%%% Res = call local literal foo/1, literal 42
+%%% _1 = bif:node Pid
+%%% @ssa_bool = succeeded _1
+%%% br @ssa_bool, label 3, label 1
+%%% 3:
+%%% @ssa_ignored = call local literal bar/0
+%%% ret Res
+%%%
+%%% It can be seen that the variables Pid and Res must be saved in Y
+%%% registers in order to survive the function calls. A previous sub
+%%% pass has inserted a 'copy' instruction to save the value of the
+%%% variable Pid:
+%%%
+%%% 0:
+%%% Pid:4 = copy Pid
+%%% Res = call local literal foo/1, literal 42
+%%% _1 = bif:node Pid:4
+%%% @ssa_bool = succeeded _1
+%%% br @ssa_bool, label 3, label 1
+%%%
+%%% 3:
+%%% @ssa_ignored = call local literal bar/0
+%%% ret Res
+%%%
+%%% The Res and Pid:4 variables must be assigned to different Y registers
+%%% because they are live at the same time. copy_retval() inserts a
+%%% 'copy' instruction to copy Res to a new variable:
+%%%
+%%% 0:
+%%% Pid:4 = copy Pid
+%%% Res:6 = call local literal foo/1, literal 42
+%%% _1 = bif:node Pid:4
+%%% @ssa_bool = succeeded _1
+%%% br @ssa_bool, label 3, label 1
+%%%
+%%% 3:
+%%% Res = copy Res:6
+%%% @ssa_ignored = call local literal bar/0
+%%% ret Res
+%%%
+%%% The new variable Res:6 is used to capture the return value from the call.
+%%% The variables Pid:4 and Res are no longer live at the same time, so they
+%%% can be assigned to the same Y register.
+%%%
+
+copy_retval(#st{frames=Frames,ssa=Blocks0,cnt=Count0}=St) ->
+ {Blocks,Count} = copy_retval_1(Frames, Blocks0, Count0),
+ St#st{ssa=Blocks,cnt=Count}.
+
+copy_retval_1([F|Fs], Blocks0, Count0) ->
+ #b_blk{anno=#{yregs:=Yregs0},is=Is} = map_get(F, Blocks0),
+ Yregs1 = gb_sets:from_list(Yregs0),
+ Yregs = collect_yregs(Is, Yregs1),
+ Ls = beam_ssa:rpo([F], Blocks0),
+ {Blocks,Count} = copy_retval_2(Ls, Yregs, none, Blocks0, Count0),
+ copy_retval_1(Fs, Blocks, Count);
+copy_retval_1([], Blocks, Count) ->
+ {Blocks,Count}.
+
+collect_yregs([#b_set{op=copy,dst=Y,args=[#b_var{}=X]}|Is],
+ Yregs0) ->
+ true = gb_sets:is_member(X, Yregs0), %Assertion.
+ Yregs = gb_sets:insert(Y, gb_sets:delete(X, Yregs0)),
+ collect_yregs(Is, Yregs);
+collect_yregs([#b_set{}|Is], Yregs) ->
+ collect_yregs(Is, Yregs);
+collect_yregs([], Yregs) -> Yregs.
+
+copy_retval_2([L|Ls], Yregs, Copy0, Blocks0, Count0) ->
+ #b_blk{is=Is0,last=Last} = Blk = map_get(L, Blocks0),
+ RC = case {Last,Ls} of
+ {#b_br{succ=Succ,fail=?BADARG_BLOCK},[Succ|_]} ->
+ true;
+ {_,_} ->
+ false
+ end,
+ case copy_retval_is(Is0, RC, Yregs, Copy0, Count0, []) of
+ {Is,Count} ->
+ case Copy0 =:= none andalso Count0 =:= Count of
+ true ->
+ copy_retval_2(Ls, Yregs, none, Blocks0, Count0);
+ false ->
+ Blocks = Blocks0#{L=>Blk#b_blk{is=Is}},
+ copy_retval_2(Ls, Yregs, none, Blocks, Count)
+ end;
+ {Is,Count,Copy} ->
+ Blocks = Blocks0#{L=>Blk#b_blk{is=Is}},
+ copy_retval_2(Ls, Yregs, Copy, Blocks, Count)
+ end;
+copy_retval_2([], _Yregs, none, Blocks, Count) ->
+ {Blocks,Count}.
+
+copy_retval_is([#b_set{op=put_tuple_elements,args=Args0}=I0], false, _Yregs,
+ Copy, Count, Acc) ->
+ I = I0#b_set{args=copy_sub_args(Args0, Copy)},
+ {reverse(Acc, [I|acc_copy([], Copy)]),Count};
+copy_retval_is([#b_set{op=Op}=I0], false, Yregs, Copy, Count0, Acc0)
+ when Op =:= call; Op =:= make_fun ->
+ {I,Count,Acc} = place_retval_copy(I0, Yregs, Copy, Count0, Acc0),
+ {reverse(Acc, [I]),Count};
+copy_retval_is([#b_set{}]=Is, false, _Yregs, Copy, Count, Acc) ->
+ {reverse(Acc, acc_copy(Is, Copy)),Count};
+copy_retval_is([#b_set{},#b_set{op=succeeded}]=Is, false, _Yregs, Copy, Count, Acc) ->
+ {reverse(Acc, acc_copy(Is, Copy)),Count};
+copy_retval_is([#b_set{op=Op,dst=#b_var{name=RetName}=Dst}=I0|Is], RC, Yregs,
+ Copy0, Count0, Acc0) when Op =:= call; Op =:= make_fun ->
+ {I1,Count1,Acc} = place_retval_copy(I0, Yregs, Copy0, Count0, Acc0),
+ case gb_sets:is_member(Dst, Yregs) of
+ true ->
+ {NewVar,Count} = new_var(RetName, Count1),
+ Copy = #b_set{op=copy,dst=Dst,args=[NewVar]},
+ I = I1#b_set{dst=NewVar},
+ copy_retval_is(Is, RC, Yregs, Copy, Count, [I|Acc]);
+ false ->
+ copy_retval_is(Is, RC, Yregs, none, Count1, [I1|Acc])
+ end;
+copy_retval_is([#b_set{args=Args0}=I0|Is], RC, Yregs, Copy, Count, Acc) ->
+ I = I0#b_set{args=copy_sub_args(Args0, Copy)},
+ case beam_ssa:clobbers_xregs(I) of
+ true ->
+ copy_retval_is(Is, RC, Yregs, none, Count, [I|acc_copy(Acc, Copy)]);
+ false ->
+ copy_retval_is(Is, RC, Yregs, Copy, Count, [I|Acc])
+ end;
+copy_retval_is([], RC, _, Copy, Count, Acc) ->
+ case {Copy,RC} of
+ {none,_} ->
+ {reverse(Acc),Count};
+ {#b_set{},true} ->
+ {reverse(Acc),Count,Copy};
+ {#b_set{},false} ->
+ {reverse(Acc, [Copy]),Count}
+ end.
+
+%%
+%% Consider this code:
+%%
+%% Var = ...
+%% ...
+%% A1 = call foo/0
+%% A = copy A1
+%% B = call bar/1, Var
+%%
+%% If the Var variable is no longer used after this code, its Y register
+%% can't be reused for A. To allow the Y register to be reused
+%% we will need to insert 'copy' instructions for arguments that are
+%% in Y registers:
+%%
+%% Var = ...
+%% ...
+%% A1 = call foo/0
+%% Var1 = copy Var
+%% A = copy A1
+%% B = call bar/1, Var1
+%%
+
+place_retval_copy(I, _Yregs, none, Count, Acc) ->
+ {I,Count,Acc};
+place_retval_copy(#b_set{args=[F|Args0]}=I, Yregs, Copy, Count0, Acc0) ->
+ #b_set{dst=Avoid} = Copy,
+ {Args,Acc1,Count} = copy_func_args(Args0, Yregs, Avoid, Acc0, [], Count0),
+ Acc = [Copy|Acc1],
+ {I#b_set{args=[F|Args]},Count,Acc}.
+
+copy_func_args([#b_var{name=AName}=A|As], Yregs, Avoid, CopyAcc, Acc, Count0) ->
+ case gb_sets:is_member(A, Yregs) of
+ true when A =/= Avoid ->
+ {NewVar,Count} = new_var(AName, Count0),
+ Copy = #b_set{op=copy,dst=NewVar,args=[A]},
+ copy_func_args(As, Yregs, Avoid, [Copy|CopyAcc], [NewVar|Acc], Count);
+ _ ->
+ copy_func_args(As, Yregs, Avoid, CopyAcc, [A|Acc], Count0)
+ end;
+copy_func_args([A|As], Yregs, Avoid, CopyAcc, Acc, Count) ->
+ copy_func_args(As, Yregs, Avoid, CopyAcc, [A|Acc], Count);
+copy_func_args([], _Yregs, _Avoid, CopyAcc, Acc, Count) ->
+ {reverse(Acc),CopyAcc,Count}.
+
+acc_copy(Acc, none) -> Acc;
+acc_copy(Acc, #b_set{}=Copy) -> [Copy|Acc].
+
+copy_sub_args(Args, none) ->
+ Args;
+copy_sub_args(Args, #b_set{dst=Dst,args=[Src]}) ->
+ [sub_arg(A, Dst, Src) || A <- Args].
+
+sub_arg(Old, Old, New) -> New;
+sub_arg(Old, _, _) -> Old.
+
+%%%
+%%% Consider:
+%%%
+%%% x1/Hd = get_hd x0/Cons
+%%% y0/Tl = get_tl x0/Cons
+%%%
+%%% Register x0 can't be reused for Hd. If Hd needs to be in x0,
+%%% a 'move' instruction must be inserted.
+%%%
+%%% If we swap get_hd and get_tl when Tl is in a Y register,
+%%% x0 can be used for Hd if Cons is not used again:
+%%%
+%%% y0/Tl = get_tl x0/Cons
+%%% x0/Hd = get_hd x0/Cons
+%%%
+
+opt_get_list(#st{ssa=Blocks,res=Res}=St) ->
+ ResMap = maps:from_list(Res),
+ Ls = beam_ssa:rpo(Blocks),
+ St#st{ssa=opt_get_list_1(Ls, ResMap, Blocks)}.
+
+opt_get_list_1([L|Ls], Res, Blocks0) ->
+ #b_blk{is=Is0} = Blk = map_get(L, Blocks0),
+ case opt_get_list_is(Is0, Res, [], false) of
+ no ->
+ opt_get_list_1(Ls, Res, Blocks0);
+ {yes,Is} ->
+ Blocks = Blocks0#{L:=Blk#b_blk{is=Is}},
+ opt_get_list_1(Ls, Res, Blocks)
+ end;
+opt_get_list_1([], _, Blocks) -> Blocks.
+
+opt_get_list_is([#b_set{op=get_hd,dst=Hd,
+ args=[Cons]}=GetHd,
+ #b_set{op=get_tl,dst=Tl,
+ args=[Cons]}=GetTl|Is],
+ Res, Acc, Changed) ->
+ %% Note that when this pass is run, only Y registers have
+ %% reservations. The absence of an entry for a variable therefore
+ %% means that the variable will be in an X register.
+ case Res of
+ #{Hd:={y,_}} ->
+ %% Hd will be in a Y register. Don't swap.
+ opt_get_list_is([GetTl|Is], Res, [GetHd|Acc], Changed);
+ #{Tl:={y,_}} ->
+ %% Tl will be in a Y register. Swap.
+ opt_get_list_is([GetHd|Is], Res, [GetTl|Acc], true);
+ #{} ->
+ %% Both are in X registers. Nothing to do.
+ opt_get_list_is([GetTl|Is], Res, [GetHd|Acc], Changed)
+ end;
+opt_get_list_is([I|Is], Res, Acc, Changed) ->
+ opt_get_list_is(Is, Res, [I|Acc], Changed);
+opt_get_list_is([], _Res, Acc, Changed) ->
+ case Changed of
+ true ->
+ {yes,reverse(Acc)};
+ false ->
+ no
+ end.
+
+%%%
+%%% Number instructions in the order they are executed.
+%%%
+
+%% number_instructions(St0) -> St.
+%% Number instructions in the order they are executed. Use a step
+%% size of 2. Don't number phi instructions. All phi variables in
+%% a block will be live one unit before the first non-phi instruction
+%% in the block.
+
+number_instructions(#st{ssa=Blocks0}=St) ->
+ Ls = beam_ssa:rpo(Blocks0),
+ St#st{ssa=number_is_1(Ls, 1, Blocks0)}.
+
+number_is_1([L|Ls], N0, Blocks0) ->
+ #b_blk{is=Is0,last=Last0} = Bl0 = map_get(L, Blocks0),
+ {Is,N1} = number_is_2(Is0, N0, []),
+ Last = beam_ssa:add_anno(n, N1, Last0),
+ N = N1 + 2,
+ Bl = Bl0#b_blk{is=Is,last=Last},
+ Blocks = Blocks0#{L:=Bl},
+ number_is_1(Ls, N, Blocks);
+number_is_1([], _, Blocks) -> Blocks.
+
+number_is_2([#b_set{op=phi}=I|Is], N, Acc) ->
+ number_is_2(Is, N, [I|Acc]);
+number_is_2([I0|Is], N, Acc) ->
+ I = beam_ssa:add_anno(n, N, I0),
+ number_is_2(Is, N+2, [I|Acc]);
+number_is_2([], N, Acc) ->
+ {reverse(Acc),N}.
+
+%%%
+%%% Calculate live intervals.
+%%%
+
+live_intervals(#st{args=Args,ssa=Blocks}=St) ->
+ Vars0 = [{V,{0,1}} || #b_var{}=V <- Args],
+ F = fun(L, _, A) -> live_interval_blk(L, Blocks, A) end,
+ LiveMap0 = #{},
+ Acc0 = {[],LiveMap0},
+ {Vars,_} = beam_ssa:fold_po(F, Acc0, Blocks),
+ Intervals = merge_ranges(rel2fam(Vars0++Vars)),
+ St#st{intervals=Intervals}.
+
+merge_ranges([{V,Rs}|T]) ->
+ [{V,merge_ranges_1(Rs)}|merge_ranges(T)];
+merge_ranges([]) -> [].
+
+merge_ranges_1([{A,N},{N,Z}|Rs]) ->
+ merge_ranges_1([{A,Z}|Rs]);
+merge_ranges_1([R|Rs]) ->
+ [R|merge_ranges_1(Rs)];
+merge_ranges_1([]) -> [].
+
+live_interval_blk(L, Blocks, {Vars0,LiveMap0}) ->
+ Live0 = [],
+ Successors = beam_ssa:successors(L, Blocks),
+ Live1 = update_successors(Successors, L, Blocks, LiveMap0, Live0),
+
+ %% Add ranges for all variables that are live in the successors.
+ #b_blk{is=Is,last=Last} = map_get(L, Blocks),
+ End = beam_ssa:get_anno(n, Last),
+ Use = [{V,{use,End+1}} || V <- Live1],
+
+ %% Determine used and defined variables in this block.
+ FirstNumber = first_number(Is, Last),
+ UseDef0 = live_interval_blk_1([Last|reverse(Is)], FirstNumber, Use),
+ UseDef = rel2fam(UseDef0),
+
+ %% Update what is live at the beginning of this block and
+ %% store it.
+ Used = [V || {V,[{use,_}|_]} <- UseDef],
+ Live2 = ordsets:union(Live1, Used),
+ Killed = [V || {V,[{def,_}|_]} <- UseDef],
+ Live = ordsets:subtract(Live2, Killed),
+ LiveMap = LiveMap0#{L=>Live},
+
+ %% Construct the ranges for this block.
+ Vars = make_block_ranges(UseDef, FirstNumber, Vars0),
+ {Vars,LiveMap}.
+
+make_block_ranges([{V,[{def,Def}]}|Vs], First, Acc) ->
+ make_block_ranges(Vs, First, [{V,{Def,Def}}|Acc]);
+make_block_ranges([{V,[{def,Def}|Uses]}|Vs], First, Acc) ->
+ {use,Last} = last(Uses),
+ make_block_ranges(Vs, First, [{V,{Def,Last}}|Acc]);
+make_block_ranges([{V,[{use,_}|_]=Uses}|Vs], First, Acc) ->
+ {use,Last} = last(Uses),
+ make_block_ranges(Vs, First, [{V,{First,Last}}|Acc]);
+make_block_ranges([], _, Acc) -> Acc.
+
+live_interval_blk_1([#b_set{op=phi,dst=Dst}|Is], FirstNumber, Acc0) ->
+ Acc = [{Dst,{def,FirstNumber}}|Acc0],
+ live_interval_blk_1(Is, FirstNumber, Acc);
+live_interval_blk_1([#b_set{op=bs_start_match}=I|Is],
+ FirstNumber, Acc0) ->
+ N = beam_ssa:get_anno(n, I),
+ #b_set{dst=Dst} = I,
+ Acc1 = [{Dst,{def,N}}|Acc0],
+ Acc = [{V,{use,N}} || V <- beam_ssa:used(I)] ++ Acc1,
+ live_interval_blk_1(Is, FirstNumber, Acc);
+live_interval_blk_1([I|Is], FirstNumber, Acc0) ->
+ N = beam_ssa:get_anno(n, I),
+ Acc1 = case I of
+ #b_set{dst=Dst} ->
+ [{Dst,{def,N}}|Acc0];
+ _ ->
+ Acc0
+ end,
+ Used = beam_ssa:used(I),
+ Acc = [{V,{use,N}} || V <- Used] ++ Acc1,
+ live_interval_blk_1(Is, FirstNumber, Acc);
+live_interval_blk_1([], _FirstNumber, Acc) ->
+ Acc.
+
+%% first_number([#b_set{}]) -> InstructionNumber.
+%% Return the number for the first instruction for the block.
+%% Note that this number is one less than the first
+%% non-phi instruction in the block.
+
+first_number([#b_set{op=phi}|Is], Last) ->
+ first_number(Is, Last);
+first_number([I|_], _) ->
+ beam_ssa:get_anno(n, I) - 1;
+first_number([], Last) ->
+ beam_ssa:get_anno(n, Last) - 1.
+
+update_successors([L|Ls], Pred, Blocks, LiveMap, Live0) ->
+ Live1 = ordsets:union(Live0, get_live(L, LiveMap)),
+ #b_blk{is=Is} = map_get(L, Blocks),
+ Live = update_live_phis(Is, Pred, Live1),
+ update_successors(Ls, Pred, Blocks, LiveMap, Live);
+update_successors([], _, _, _, Live) -> Live.
+
+get_live(L, LiveMap) ->
+ case LiveMap of
+ #{L:=Live} -> Live;
+ #{} -> []
+ end.
+
+update_live_phis([#b_set{op=phi,dst=Killed,args=Args}|Is],
+ Pred, Live0) ->
+ Used = [V || {#b_var{}=V,L} <- Args, L =:= Pred],
+ Live1 = ordsets:union(ordsets:from_list(Used), Live0),
+ Live = ordsets:del_element(Killed, Live1),
+ update_live_phis(Is, Pred, Live);
+update_live_phis(_, _, Live) -> Live.
+
+%%%
+%%% Reserve Y registers.
+%%%
+
+%% reserve_yregs(St0) -> St.
+%% In each block that allocates a stack frame, insert instructions
+%% that copy variables that must be in Y registers (given by
+%% the `yregs` annotation) to new variables.
+%%
+%% Also allocate specific Y registers for try and catch tags.
+%% The outermost try/catch tag is placed in y0, any directly
+%% nested tag in y1, and so on. Note that this is the reversed
+%% order as required by BEAM; it will be corrected later by
+%% turn_yregs().
+
+reserve_yregs(#st{frames=Frames}=St0) ->
+ foldl(fun reserve_yregs_1/2, St0, Frames).
+
+reserve_yregs_1(L, #st{ssa=Blocks0,cnt=Count0,res=Res0}=St) ->
+ Blk = map_get(L, Blocks0),
+ Yregs = beam_ssa:get_anno(yregs, Blk),
+ {Def,Used} = beam_ssa:def_used([L], Blocks0),
+ UsedYregs = ordsets:intersection(Yregs, Used),
+ DefBefore = ordsets:subtract(UsedYregs, Def),
+ {BeforeVars,Blocks,Count} = rename_vars(DefBefore, L, Blocks0, Count0),
+ InsideVars = ordsets:subtract(UsedYregs, DefBefore),
+ ResTryTags0 = reserve_try_tags(L, Blocks),
+ ResTryTags = [{V,{Reg,Count}} || {V,Reg} <- ResTryTags0],
+ Vars = BeforeVars ++ InsideVars,
+ Res = [{V,{y,Count}} || V <- Vars] ++ ResTryTags ++ Res0,
+ St#st{res=Res,ssa=Blocks,cnt=Count+1}.
+
+reserve_try_tags(L, Blocks) ->
+ Seen = gb_sets:empty(),
+ {Res0,_} = reserve_try_tags_1([L], Blocks, Seen, #{}),
+ Res1 = [maps:to_list(M) || {_,M} <- maps:to_list(Res0)],
+ Res = [{V,{y,Y}} || {V,Y} <- append(Res1)],
+ ordsets:from_list(Res).
+
+reserve_try_tags_1([L|Ls], Blocks, Seen0, ActMap0) ->
+ case gb_sets:is_element(L, Seen0) of
+ true ->
+ reserve_try_tags_1(Ls, Blocks, Seen0, ActMap0);
+ false ->
+ Seen1 = gb_sets:insert(L, Seen0),
+ #b_blk{is=Is} = Blk = map_get(L, Blocks),
+ Active0 = get_active(L, ActMap0),
+ Active = reserve_try_tags_is(Is, Active0),
+ Successors = beam_ssa:successors(Blk),
+ ActMap1 = update_act_map(Successors, Active, ActMap0),
+ {ActMap,Seen} = reserve_try_tags_1(Ls, Blocks, Seen1, ActMap1),
+ reserve_try_tags_1(Successors, Blocks, Seen,ActMap)
+ end;
+reserve_try_tags_1([], _Blocks, Seen, ActMap) ->
+ {ActMap,Seen}.
+
+get_active(L, ActMap) ->
+ case ActMap of
+ #{L:=Active} -> Active;
+ #{} -> #{}
+ end.
+
+reserve_try_tags_is([#b_set{op=new_try_tag,dst=V}|Is], Active) ->
+ N = map_size(Active),
+ reserve_try_tags_is(Is, Active#{V=>N});
+reserve_try_tags_is([#b_set{op=kill_try_tag,args=[Tag]}|Is], Active) ->
+ reserve_try_tags_is(Is, maps:remove(Tag, Active));
+reserve_try_tags_is([_|Is], Active) ->
+ reserve_try_tags_is(Is, Active);
+reserve_try_tags_is([], Active) -> Active.
+
+update_act_map([L|Ls], Active0, ActMap0) ->
+ case ActMap0 of
+ #{L:=Active1} ->
+ ActMap = ActMap0#{L=>maps:merge(Active0, Active1)},
+ update_act_map(Ls, Active0, ActMap);
+ #{} ->
+ ActMap = ActMap0#{L=>Active0},
+ update_act_map(Ls, Active0, ActMap)
+ end;
+update_act_map([], _, ActMap) -> ActMap.
+
+rename_vars([], _, Blocks, Count) ->
+ {[],Blocks,Count};
+rename_vars(Vs, L, Blocks0, Count0) ->
+ {NewVars,Count} = new_vars([Base || #b_var{name=Base} <- Vs], Count0),
+ Ren = zip(Vs, NewVars),
+ Blocks1 = beam_ssa:rename_vars(Ren, [L], Blocks0),
+ #b_blk{is=Is0} = Blk0 = map_get(L, Blocks1),
+ CopyIs = [#b_set{op=copy,dst=New,args=[Old]} || {Old,New} <- Ren],
+ Is = insert_after_phis(Is0, CopyIs),
+ Blk = Blk0#b_blk{is=Is},
+ Blocks = Blocks1#{L:=Blk},
+ {NewVars,Blocks,Count}.
+
+insert_after_phis([#b_set{op=phi}=I|Is], InsertIs) ->
+ [I|insert_after_phis(Is, InsertIs)];
+insert_after_phis(Is, InsertIs) ->
+ InsertIs ++ Is.
+
+%% frame_size(St0) -> St.
+%% Calculate the frame size for each block that allocates a frame.
+%% Annotate the block with the frame size. Also annotate all
+%% return instructions with {deallocate,FrameSize} to simplify
+%% code generation.
+
+frame_size(#st{frames=Frames,regs=Regs,ssa=Blocks0}=St) ->
+ Blocks = foldl(fun(L, Blks) ->
+ frame_size_1(L, Regs, Blks)
+ end, Blocks0, Frames),
+ St#st{ssa=Blocks}.
+
+frame_size_1(L, Regs, Blocks0) ->
+ Def = beam_ssa:def([L], Blocks0),
+ Yregs0 = [map_get(V, Regs) || V <- Def, is_yreg(map_get(V, Regs))],
+ Yregs = ordsets:from_list(Yregs0),
+ FrameSize = length(ordsets:from_list(Yregs)),
+ if
+ FrameSize =/= 0 ->
+ [{y,0}|_] = Yregs, %Assertion.
+ {y,Last} = last(Yregs),
+ Last = FrameSize - 1, %Assertion.
+ ok;
+ true ->
+ ok
+ end,
+ Blk0 = map_get(L, Blocks0),
+ Blk = beam_ssa:add_anno(frame_size, FrameSize, Blk0),
+
+ %% Insert an annotation for frame deallocation on
+ %% each #b_ret{}.
+ Blocks = Blocks0#{L:=Blk},
+ Reachable = beam_ssa:rpo([L], Blocks),
+ frame_deallocate(Reachable, FrameSize, Blocks).
+
+frame_deallocate([L|Ls], Size, Blocks0) ->
+ Blk0 = map_get(L, Blocks0),
+ Blk = case Blk0 of
+ #b_blk{last=#b_ret{}=Ret0} ->
+ Ret = beam_ssa:add_anno(deallocate, Size, Ret0),
+ Blk0#b_blk{last=Ret};
+ #b_blk{} ->
+ Blk0
+ end,
+ Blocks = Blocks0#{L:=Blk},
+ frame_deallocate(Ls, Size, Blocks);
+frame_deallocate([], _, Blocks) -> Blocks.
+
+
+%% turn_yregs(St0) -> St.
+%% Renumber y registers so that {y,0} becomes {y,FrameSize-1},
+%% {y,FrameSize-1} becomes {y,0} and so on. This is to make nested
+%% catches work. The register allocator (linear_scan()) has given
+%% a lower number to the outermost catch.
+
+turn_yregs(#st{frames=Frames,regs=Regs0,ssa=Blocks}=St) ->
+ Regs1 = foldl(fun(L, A) ->
+ Blk = map_get(L, Blocks),
+ FrameSize = beam_ssa:get_anno(frame_size, Blk),
+ Def = beam_ssa:def([L], Blocks),
+ [turn_yregs_1(Def, FrameSize, Regs0)|A]
+ end, [], Frames),
+ Regs = maps:merge(Regs0, maps:from_list(append(Regs1))),
+ St#st{regs=Regs}.
+
+turn_yregs_1(Def, FrameSize, Regs) ->
+ Yregs0 = [{map_get(V, Regs),V} || V <- Def, is_yreg(map_get(V, Regs))],
+ Yregs1 = rel2fam(Yregs0),
+ FrameSize = length(Yregs1),
+ Yregs2 = [{{y,FrameSize-Y-1},Vs} || {{y,Y},Vs} <- Yregs1],
+ R0 = sofs:family(Yregs2),
+ R1 = sofs:family_to_relation(R0),
+ R = sofs:converse(R1),
+ sofs:to_external(R).
+
+%%%
+%%% Reserving registers before register allocation.
+%%%
+
+%% reserve_regs(St0) -> St.
+%% Reserve registers prior to register allocation. Y registers
+%% have already been reserved. This function will reserve z,
+%% fr, and specific x registers.
+
+reserve_regs(#st{args=Args,ssa=Blocks,intervals=Intervals,res=Res0}=St) ->
+ %% Reserve x0, x1, and so on for the function arguments.
+ Res1 = reserve_arg_regs(Args, 0, Res0),
+
+ %% Reserve Z registers (dummy registers) for instructions with no
+ %% return values (e.g. remove_message) or pseudo-return values
+ %% (e.g. landingpad).
+ Res2 = reserve_zregs(Blocks, Intervals, Res1),
+
+ %% Reserve float registers.
+ Res3 = reserve_fregs(Blocks, Res2),
+
+ %% Reserve all remaining unreserved variables as X registers.
+ Res = maps:from_list(Res3),
+ St#st{res=reserve_xregs(Blocks, Res)}.
+
+reserve_arg_regs([#b_var{}=Arg|Is], N, Acc) ->
+ reserve_arg_regs(Is, N+1, [{Arg,{x,N}}|Acc]);
+reserve_arg_regs([], _, Acc) -> Acc.
+
+reserve_zregs(Blocks, Intervals, Res) ->
+ ShortLived0 = [V || {V,[{Start,End}]} <- Intervals, Start+2 =:= End],
+ ShortLived = cerl_sets:from_list(ShortLived0),
+ F = fun(_, #b_blk{is=Is,last=Last}, A) ->
+ reserve_zreg(Is, Last, ShortLived, A)
+ end,
+ beam_ssa:fold_rpo(F, [0], Res, Blocks).
+
+reserve_zreg([#b_set{op=Op,dst=Dst}],
+ #b_br{bool=Dst}, _ShortLived, A) when Op =:= call;
+ Op =:= get_tuple_element ->
+ %% If type optimization has determined that the result of these
+ %% instructions can be used directly in a branch, we must avoid reserving a
+ %% z register or code generation will fail.
+ A;
+reserve_zreg([#b_set{op={bif,tuple_size},dst=Dst},
+ #b_set{op={bif,'=:='},args=[Dst,Val]}], Last, ShortLived, A0) ->
+ case {Val,Last} of
+ {#b_literal{val=Arity},#b_br{bool=#b_var{}}} when Arity bsr 32 =:= 0 ->
+ %% These two instructions can be combined to a test_arity
+ %% instruction provided that the arity variable is short-lived.
+ reserve_zreg_1(Dst, ShortLived, A0);
+ {_,_} ->
+ %% Either the arity is too big, or the boolean value is not
+ %% used in a conditional branch.
+ A0
+ end;
+reserve_zreg([#b_set{op={bif,tuple_size},dst=Dst}],
+ #b_switch{}, ShortLived, A) ->
+ reserve_zreg_1(Dst, ShortLived, A);
+reserve_zreg([#b_set{op={bif,'xor'}}], _Last, _ShortLived, A) ->
+ %% There is no short, easy way to rewrite 'xor' to a series of
+ %% test instructions.
+ A;
+reserve_zreg([#b_set{op={bif,is_record}}], _Last, _ShortLived, A) ->
+ %% There is no short, easy way to rewrite is_record/2 to a series of
+ %% test instructions.
+ A;
+reserve_zreg([#b_set{op=Op,dst=Dst}|Is], Last, ShortLived, A0) ->
+ IsZReg = case Op of
+ bs_match_string -> true;
+ bs_save -> true;
+ bs_restore -> true;
+ bs_set_position -> true;
+ {float,clearerror} -> true;
+ kill_try_tag -> true;
+ landingpad -> true;
+ put_tuple_elements -> true;
+ remove_message -> true;
+ set_tuple_element -> true;
+ succeeded -> true;
+ timeout -> true;
+ wait_timeout -> true;
+ _ -> false
+ end,
+ A = case IsZReg of
+ true -> [{Dst,z}|A0];
+ false -> A0
+ end,
+ reserve_zreg(Is, Last, ShortLived, A);
+reserve_zreg([], #b_br{bool=Bool}, ShortLived, A) ->
+ reserve_zreg_1(Bool, ShortLived, A);
+reserve_zreg([], _, _, A) -> A.
+
+reserve_zreg_1(#b_var{}=V, ShortLived, A) ->
+ case cerl_sets:is_element(V, ShortLived) of
+ true -> [{V,z}|A];
+ false -> A
+ end;
+reserve_zreg_1(#b_literal{}, _, A) -> A.
+
+reserve_fregs(Blocks, Res) ->
+ F = fun(_, #b_blk{is=Is}, A) ->
+ reserve_freg(Is, A)
+ end,
+ beam_ssa:fold_rpo(F, [0], Res, Blocks).
+
+reserve_freg([#b_set{op={float,Op},dst=V}|Is], Res) ->
+ case Op of
+ get ->
+ reserve_freg(Is, Res);
+ _ ->
+ reserve_freg(Is, [{V,fr}|Res])
+ end;
+reserve_freg([_|Is], Res) ->
+ reserve_freg(Is, Res);
+reserve_freg([], Res) -> Res.
+
+%% reserve_xregs(St0) -> St.
+%% Reserve all remaining variables as X registers.
+%%
+%% If a variable will need to be in a specific X register for a
+%% 'call' or 'make_fun' (and there is nothing that will kill it
+%% between the definition and use), reserve the register using a
+%% {prefer,{x,X} annotation. That annotation means that the linear
+%% scan algorithm will place the variable in the preferred register,
+%% unless that register is already occupied.
+%%
+%% All remaining variables are reserved as X registers. Linear scan
+%% will allocate the lowest free X register for the variable.
+
+reserve_xregs(Blocks, Res) ->
+ Ls = reverse(beam_ssa:rpo(Blocks)),
+ reserve_xregs(Ls, Blocks, #{}, Res).
+
+reserve_xregs([L|Ls], Blocks, XsMap0, Res0) ->
+ #b_blk{anno=Anno,is=Is0,last=Last} = map_get(L, Blocks),
+
+ %% Calculate mapping from variable name to the preferred
+ %% register.
+ Xs0 = reserve_terminator(L, Is0, Last, Blocks, XsMap0, Res0),
+
+ %% We need to figure out where the code generator will
+ %% place instructions that will do a garbage collection.
+ %% Insert 'gc' markers as pseudo-instructions in the
+ %% instruction sequence.
+ Is1 = reverse(Is0),
+ Is2 = res_place_gc_instrs(Is1, []),
+ Is = res_place_allocate(Anno, Is2),
+
+ %% Add register hints for variables that are defined
+ %% in the (reversed) instruction sequence.
+ {Res,Xs} = reserve_xregs_is(Is, Res0, Xs0, []),
+
+ XsMap = XsMap0#{L=>Xs},
+ reserve_xregs(Ls, Blocks, XsMap, Res);
+reserve_xregs([], _, _, Res) -> Res.
+
+%% Insert explicit 'gc' markers points where there will
+%% be a garbage collection. (Note that the instruction
+%% sequence passed to this function is reversed.)
+
+res_place_gc_instrs([#b_set{op=phi}=I|Is], Acc) ->
+ res_place_gc_instrs(Is, [I|Acc]);
+res_place_gc_instrs([#b_set{op=Op}=I|Is], Acc)
+ when Op =:= call; Op =:= make_fun ->
+ case Acc of
+ [] ->
+ res_place_gc_instrs(Is, [I|Acc]);
+ [GC|_] when GC =:= gc; GC =:= test_heap ->
+ res_place_gc_instrs(Is, [I,gc|Acc]);
+ [_|_] ->
+ res_place_gc_instrs(Is, [I,gc|Acc])
+ end;
+res_place_gc_instrs([#b_set{op=Op,args=Args}=I|Is], Acc0) ->
+ case beam_ssa_codegen:classify_heap_need(Op, Args) of
+ neutral ->
+ case Acc0 of
+ [test_heap|Acc] ->
+ res_place_gc_instrs(Is, [test_heap,I|Acc]);
+ Acc ->
+ res_place_gc_instrs(Is, [I|Acc])
+ end;
+ {put,_} ->
+ case Acc0 of
+ [test_heap|Acc] ->
+ res_place_gc_instrs(Is, [test_heap,I|Acc]);
+ Acc ->
+ res_place_gc_instrs(Is, [test_heap,I|Acc])
+ end;
+ _ ->
+ res_place_gc_instrs(Is, [gc,I|Acc0])
+ end;
+res_place_gc_instrs([], Acc) ->
+ %% Reverse and replace 'test_heap' markers with 'gc'.
+ %% (The distinction is no longer useful.)
+ res_place_gc_instrs_rev(Acc, []).
+
+res_place_gc_instrs_rev([test_heap|Is], [gc|_]=Acc) ->
+ res_place_gc_instrs_rev(Is, Acc);
+res_place_gc_instrs_rev([test_heap|Is], Acc) ->
+ res_place_gc_instrs_rev(Is, [gc|Acc]);
+res_place_gc_instrs_rev([gc|Is], [gc|_]=Acc) ->
+ res_place_gc_instrs_rev(Is, Acc);
+res_place_gc_instrs_rev([I|Is], Acc) ->
+ res_place_gc_instrs_rev(Is, [I|Acc]);
+res_place_gc_instrs_rev([], Acc) -> Acc.
+
+res_place_allocate(#{yregs:=_}, Is) ->
+ %% There will be an 'allocate' instruction inserted here.
+ Is ++ [gc];
+res_place_allocate(#{}, Is) -> Is.
+
+reserve_xregs_is([gc|Is], Res, Xs0, Used) ->
+ %% At this point, the code generator will place an instruction
+ %% that does a garbage collection. We must prune the remembered
+ %% registers.
+ Xs = res_xregs_prune(Xs0, Used, Res),
+ reserve_xregs_is(Is, Res, Xs, Used);
+reserve_xregs_is([#b_set{op=Op,dst=Dst,args=Args}=I|Is], Res0, Xs0, Used0) ->
+ Res = reserve_xreg(Dst, Xs0, Res0),
+ Used1 = ordsets:union(Used0, beam_ssa:used(I)),
+ Used = ordsets:del_element(Dst, Used1),
+ case Op of
+ call ->
+ Xs = reserve_call_args(tl(Args)),
+ reserve_xregs_is(Is, Res, Xs, Used);
+ make_fun ->
+ Xs = reserve_call_args(tl(Args)),
+ reserve_xregs_is(Is, Res, Xs, Used);
+ _ ->
+ reserve_xregs_is(Is, Res, Xs0, Used)
+ end;
+reserve_xregs_is([], Res, Xs, _Used) ->
+ {Res,Xs}.
+
+%% Pick up register hints from the successors of this blocks.
+reserve_terminator(_L, _Is, #b_br{bool=#b_var{},succ=Succ,fail=?BADARG_BLOCK},
+ _Blocks, XsMap, _Res) ->
+ %% We know that no variables are used at ?BADARG_BLOCK, so
+ %% any register hints from the success blocks are safe to use.
+ map_get(Succ, XsMap);
+reserve_terminator(L, Is, #b_br{bool=#b_var{},succ=Succ,fail=Fail},
+ Blocks, XsMap, Res) when Succ =/= Fail ->
+ #{Succ:=SuccBlk,Fail:=FailBlk} = Blocks,
+ case {SuccBlk,FailBlk} of
+ {#b_blk{is=[],last=#b_br{succ=PhiL,fail=PhiL}},
+ #b_blk{is=[],last=#b_br{succ=PhiL,fail=PhiL}}} ->
+ %% Both branches ultimately transfer to the same
+ %% block (via two blocks with no instructions).
+ %% Pick up register hints from the phi nodes
+ %% in the common block.
+ #{PhiL:=#b_blk{is=PhiIs}} = Blocks,
+ Xs = res_xregs_from_phi(PhiIs, Succ, Res, #{}),
+ res_xregs_from_phi(PhiIs, Fail, Res, Xs);
+ {_,_} when Is =/= [] ->
+ case last(Is) of
+ #b_set{op=succeeded,args=[Arg]} ->
+ %% We know that Arg will not be used at the failure
+ %% label, so we can pick up register hints from the
+ %% success label.
+ Br = #b_br{bool=#b_literal{val=true},succ=Succ,fail=Succ},
+ case reserve_terminator(L, [], Br, Blocks, XsMap, Res) of
+ #{Arg:=Reg} -> #{Arg=>Reg};
+ #{} -> #{}
+ end;
+ _ ->
+ %% Register hints from the success block may not
+ %% be safe at the failure block, and vice versa.
+ #{}
+ end;
+ {_,_} ->
+ %% Register hints from the success block may not
+ %% be safe at the failure block, and vice versa.
+ #{}
+ end;
+reserve_terminator(L, Is, #b_br{bool=#b_literal{val=true},succ=Succ},
+ Blocks, XsMap, Res) ->
+ case map_get(Succ, Blocks) of
+ #b_blk{is=[],last=Last} ->
+ reserve_terminator(Succ, Is, Last, Blocks, XsMap, Res);
+ #b_blk{is=[_|_]=PhiIs} ->
+ res_xregs_from_phi(PhiIs, L, Res, #{})
+ end;
+reserve_terminator(_, _, _, _, _, _) -> #{}.
+
+%% Pick up a reservation from a phi node.
+res_xregs_from_phi([#b_set{op=phi,dst=Dst,args=Args}|Is],
+ Pred, Res, Acc) ->
+ case [V || {#b_var{}=V,L} <- Args, L =:= Pred] of
+ [] ->
+ %% The value of the phi node for this predecessor
+ %% is a literal. Nothing to do here.
+ res_xregs_from_phi(Is, Pred, Res, Acc);
+ [V] ->
+ case Res of
+ #{Dst:={prefer,Reg}} ->
+ %% Try placing V in the same register as for
+ %% the phi node.
+ res_xregs_from_phi(Is, Pred, Res, Acc#{V=>Reg});
+ #{Dst:=_} ->
+ res_xregs_from_phi(Is, Pred, Res, Acc)
+ end
+ end;
+res_xregs_from_phi(_, _, _, Acc) -> Acc.
+
+reserve_call_args(Args) ->
+ reserve_call_args(Args, 0, #{}).
+
+reserve_call_args([#b_var{}=Var|As], X, Xs) ->
+ reserve_call_args(As, X+1, Xs#{Var=>{x,X}});
+reserve_call_args([#b_literal{}|As], X, Xs) ->
+ reserve_call_args(As, X+1, Xs);
+reserve_call_args([], _, Xs) -> Xs.
+
+reserve_xreg(V, Xs, Res) ->
+ case Res of
+ #{V:=_} ->
+ %% Already reserved (but not as an X register).
+ Res;
+ #{} ->
+ case Xs of
+ #{V:=X} ->
+ %% Add a hint that this specific X register is
+ %% preferred, unless it is already in use.
+ Res#{V=>{prefer,X}};
+ #{} ->
+ %% Reserve as an X register in general.
+ Res#{V=>x}
+ end
+ end.
+
+%% res_xregs_prune(PreferredRegs, Used, Res) -> PreferredRegs.
+%% Prune the list of preferred registers, to make sure that
+%% there are no "holes" (uninitialized X registers) when
+%% invoking the garbage collector.
+
+res_xregs_prune(Xs, Used, Res) when map_size(Xs) =/= 0 ->
+ %% The number of safe registers is the number of the X registers
+ %% used after this point. The actual number of safe registers may
+ %% be higher than this number, but this is a conservative safe
+ %% estimate.
+ NumSafe = foldl(fun(V, N) ->
+ case Res of
+ #{V:={x,_}} -> N + 1;
+ #{V:=_} -> N;
+ #{} -> N + 1
+ end
+ end, 0, Used),
+
+ %% Remove unsafe registers from the list of potential
+ %% preferred registers.
+ maps:filter(fun(_, {x,X}) -> X < NumSafe end, Xs);
+res_xregs_prune(Xs, _Used, _Res) -> Xs.
+
+%%%
+%%% Register allocation using linear scan.
+%%%
+
+-record(i,
+ {sort=1 :: instr_number(),
+ reg=none :: i_reg(),
+ pool=x :: pool_id(),
+ var=#b_var{} :: b_var(),
+ rs=[] :: [range()]
+ }).
+
+-record(l,
+ {cur=#i{} :: interval(),
+ unhandled_res=[] :: [interval()],
+ unhandled_any=[] :: [interval()],
+ active=[] :: [interval()],
+ inactive=[] :: [interval()],
+ free=#{} :: #{var_name()=>pool(),
+ {'next',pool_id()}:=reg_num()},
+ regs=[] :: [{b_var(),ssa_register()}]
+ }).
+
+-type interval() :: #i{}.
+-type i_reg() :: ssa_register() | {'prefer',xreg()} | 'none'.
+-type pool_id() :: 'fr' | 'x' | 'z' | instr_number().
+-type pool() :: ordsets:ordset(ssa_register()).
+
+linear_scan(#st{intervals=Intervals0,res=Res}=St0) ->
+ St = St0#st{intervals=[],res=[]},
+ Free = init_free(maps:to_list(Res)),
+ Intervals1 = [init_interval(Int, Res) || Int <- Intervals0],
+ Intervals = sort(Intervals1),
+ IsReserved = fun(#i{reg=Reg}) ->
+ case Reg of
+ none -> false;
+ {prefer,{_,_}} -> false;
+ {_,_} -> true
+ end
+ end,
+ {UnhandledRes,Unhandled} = partition(IsReserved, Intervals),
+ L = #l{unhandled_res=UnhandledRes,
+ unhandled_any=Unhandled,free=Free},
+ #l{regs=Regs} = do_linear(L),
+ St#st{regs=maps:from_list(Regs)}.
+
+init_interval({V,[{Start,_}|_]=Rs}, Res) ->
+ Info = map_get(V, Res),
+ Pool = case Info of
+ {prefer,{x,_}} -> x;
+ x -> x;
+ {x,_} -> x;
+ {y,Uniq} -> Uniq;
+ {{y,_},Uniq} -> Uniq;
+ z -> z;
+ fr -> fr
+ end,
+ Reg = case Info of
+ {prefer,{x,_}} -> Info;
+ {x,_} -> Info;
+ {{y,_}=Y,_} -> Y;
+ _ -> none
+ end,
+ #i{sort=Start,var=V,reg=Reg,pool=Pool,rs=Rs}.
+
+init_free(Res) ->
+ Free0 = rel2fam([{x,{x,0}}|init_free_1(Res)]),
+ #{x:=Xs0} = Free1 = maps:from_list(Free0),
+ Xs = init_xregs(Xs0),
+ Free = Free1#{x:=Xs},
+ Next = maps:fold(fun(K, V, A) -> [{{next,K},length(V)}|A] end, [], Free),
+ maps:merge(Free, maps:from_list(Next)).
+
+init_free_1([{_,{prefer,{x,_}=Reg}}|Res]) ->
+ [{x,Reg}|init_free_1(Res)];
+init_free_1([{_,{x,_}=Reg}|Res]) ->
+ [{x,Reg}|init_free_1(Res)];
+init_free_1([{_,{y,Uniq}}|Res]) ->
+ [{Uniq,{y,0}}|init_free_1(Res)];
+init_free_1([{_,{{y,_}=Reg,Uniq}}|Res]) ->
+ [{Uniq,Reg}|init_free_1(Res)];
+init_free_1([{_,z}|Res]) ->
+ [{z,{z,0}}|init_free_1(Res)];
+init_free_1([{_,fr}|Res]) ->
+ [{fr,{fr,0}}|init_free_1(Res)];
+init_free_1([{_,x}|Res]) ->
+ init_free_1(Res);
+init_free_1([]) -> [].
+
+%% Make sure that the pool of xregs is contiguous.
+init_xregs([{x,N},{x,M}|Is]) when N+1 =:= M ->
+ [{x,N}|init_xregs([{x,M}|Is])];
+init_xregs([{x,N}|[{x,_}|_]=Is]) ->
+ [{x,N}|init_xregs([{x,N+1}|Is])];
+init_xregs([{x,_}]=Is) -> Is.
+
+do_linear(L0) ->
+ case set_next_current(L0) of
+ done ->
+ L0;
+ L1 ->
+ L2 = expire_active(L1),
+ L3 = check_inactive(L2),
+ Available = collect_available(L3),
+ L4 = select_register(Available, L3),
+ L = make_cur_active(L4),
+ do_linear(L)
+ end.
+
+set_next_current(#l{unhandled_res=[Cur1|T1],
+ unhandled_any=[Cur2|T2]}=L) ->
+ case {Cur1,Cur2} of
+ {#i{sort=N1},#i{sort=N2}} when N1 < N2 ->
+ L#l{cur=Cur1,unhandled_res=T1};
+ {_,_} ->
+ L#l{cur=Cur2,unhandled_any=T2}
+ end;
+set_next_current(#l{unhandled_res=[],
+ unhandled_any=[Cur|T]}=L) ->
+ L#l{cur=Cur,unhandled_any=T};
+set_next_current(#l{unhandled_res=[Cur|T],
+ unhandled_any=[]}=L) ->
+ L#l{cur=Cur,unhandled_res=T};
+set_next_current(#l{unhandled_res=[],unhandled_any=[]}) ->
+ done.
+
+expire_active(#l{cur=#i{sort=CurBegin},active=Act0}=L0) ->
+ {Act,L} = expire_active(Act0, CurBegin, L0, []),
+ L#l{active=Act}.
+
+expire_active([#i{reg=Reg,rs=Rs0}=I|Is], CurBegin, L0, Acc) ->
+ {_,_} = Reg, %Assertion.
+ case overlap_status(Rs0, CurBegin) of
+ ends_before_cur ->
+ L = free_reg(I, L0),
+ expire_active(Is, CurBegin, L, Acc);
+ overlapping ->
+ expire_active(Is, CurBegin, L0, [I|Acc]);
+ not_overlapping ->
+ Rs = strip_before_current(Rs0, CurBegin),
+ L1 = free_reg(I, L0),
+ L = L1#l{inactive=[I#i{rs=Rs}|L1#l.inactive]},
+ expire_active(Is, CurBegin, L, Acc)
+ end;
+expire_active([], _CurBegin, L, Acc) ->
+ {Acc,L}.
+
+check_inactive(#l{cur=#i{sort=CurBegin},inactive=InAct0}=L0) ->
+ {InAct,L} = check_inactive(InAct0, CurBegin, L0, []),
+ L#l{inactive=InAct}.
+
+check_inactive([#i{rs=Rs0}=I|Is], CurBegin, L0, Acc) ->
+ case overlap_status(Rs0, CurBegin) of
+ ends_before_cur ->
+ check_inactive(Is, CurBegin, L0, Acc);
+ not_overlapping ->
+ check_inactive(Is, CurBegin, L0, [I|Acc]);
+ overlapping ->
+ Rs = strip_before_current(Rs0, CurBegin),
+ L1 = L0#l{active=[I#i{rs=Rs}|L0#l.active]},
+ L = reserve_reg(I, L1),
+ check_inactive(Is, CurBegin, L, Acc)
+ end;
+check_inactive([], _CurBegin, L, Acc) ->
+ {Acc,L}.
+
+strip_before_current([{_,E}|Rs], CurBegin) when E =< CurBegin ->
+ strip_before_current(Rs, CurBegin);
+strip_before_current(Rs, _CurBegin) -> Rs.
+
+collect_available(#l{cur=#i{reg={prefer,{_,_}=Prefer}}=I}=L) ->
+ %% Use the preferred register if it is available.
+ Avail = collect_available(L#l{cur=I#i{reg=none}}),
+ case member(Prefer, Avail) of
+ true -> [Prefer];
+ false -> Avail
+ end;
+collect_available(#l{cur=#i{reg={_,_}=ReservedReg}}) ->
+ %% Return the already reserved register.
+ [ReservedReg];
+collect_available(#l{unhandled_res=Unhandled,cur=Cur}=L) ->
+ Free = get_pool(Cur, L),
+
+ %% Note that since the live intervals are constructed from
+ %% SSA form, there cannot be any overlap of the current interval
+ %% with any inactive interval. See [3], page 175. Therefore we
+ %% only have check the unhandled intervals for overlap with
+ %% the current interval. As a further optimization, we only need
+ %% to check the intervals that have reserved registers.
+ collect_available(Unhandled, Cur, Free).
+
+collect_available([#i{pool=Pool1}|Is], #i{pool=Pool2}=Cur, Free)
+ when Pool1 =/= Pool2 ->
+ %% Wrong pool. Ignore this interval.
+ collect_available(Is, Cur, Free);
+collect_available([#i{reg={_,_}=Reg}=I|Is], Cur, Free0) ->
+ case overlaps(I, Cur) of
+ true ->
+ Free = ordsets:del_element(Reg, Free0),
+ collect_available(Is, Cur, Free);
+ false ->
+ collect_available(Is, Cur, Free0)
+ end;
+collect_available([], _, Free) -> Free.
+
+select_register([{_,_}=Reg|_], #l{cur=Cur0,regs=Regs}=L) ->
+ Cur = Cur0#i{reg=Reg},
+ reserve_reg(Cur, L#l{cur=Cur,regs=[{Cur#i.var,Reg}|Regs]});
+select_register([], #l{cur=Cur0,regs=Regs}=L0) ->
+ %% Allocate a new register in the pool.
+ {Reg,L1} = get_next_free(Cur0, L0),
+ Cur = Cur0#i{reg=Reg},
+ L = L1#l{cur=Cur,regs=[{Cur#i.var,Reg}|Regs]},
+ reserve_reg(Cur, L).
+
+make_cur_active(#l{cur=Cur,active=Act}=L) ->
+ L#l{active=[Cur|Act]}.
+
+overlaps(#i{rs=Rs1}, #i{rs=Rs2}) ->
+ are_overlapping(Rs1, Rs2).
+
+overlap_status([{S,E}], CurBegin) ->
+ if
+ E =< CurBegin -> ends_before_cur;
+ CurBegin < S -> not_overlapping;
+ true -> overlapping
+ end;
+overlap_status([{S,E}|Rs], CurBegin) ->
+ if
+ E =< CurBegin ->
+ overlap_status(Rs, CurBegin);
+ S =< CurBegin ->
+ overlapping;
+ true ->
+ not_overlapping
+ end.
+
+reserve_reg(#i{reg={_,_}=Reg}=I, L) ->
+ FreeRegs0 = get_pool(I, L),
+ FreeRegs = ordsets:del_element(Reg, FreeRegs0),
+ update_pool(I, FreeRegs, L).
+
+free_reg(#i{reg={_,_}=Reg}=I, L) ->
+ FreeRegs0 = get_pool(I, L),
+ FreeRegs = ordsets:add_element(Reg, FreeRegs0),
+ update_pool(I, FreeRegs, L).
+
+get_pool(#i{pool=Pool}, #l{free=Free}) ->
+ map_get(Pool, Free).
+
+update_pool(#i{pool=Pool}, New, #l{free=Free0}=L) ->
+ Free = Free0#{Pool:=New},
+ L#l{free=Free}.
+
+get_next_free(#i{pool=Pool}, #l{free=Free0}=L0) ->
+ K = {next,Pool},
+ N = map_get(K, Free0),
+ Free = Free0#{K:=N+1},
+ L = L0#l{free=Free},
+ if
+ is_integer(Pool) -> {{y,N},L};
+ is_atom(Pool) -> {{Pool,N},L}
+ end.
+
+%%%
+%%% Interval utilities.
+%%%
+
+are_overlapping([R|Rs1], Rs2) ->
+ case are_overlapping_1(R, Rs2) of
+ true ->
+ true;
+ false ->
+ are_overlapping(Rs1, Rs2)
+ end;
+are_overlapping([], _) -> false.
+
+are_overlapping_1({_S1,E1}, [{S2,_E2}|_]) when E1 < S2 ->
+ false;
+are_overlapping_1({S1,E1}=R, [{S2,E2}|Rs]) ->
+ (S2 < E1 andalso E2 > S1) orelse are_overlapping_1(R, Rs);
+are_overlapping_1({_,_}, []) -> false.
+
+%%%
+%%% Utilities.
+%%%
+
+%% is_loop_header(L, Blocks) -> false|true.
+%% Check whether the block is a loop header.
+
+is_loop_header(L, Blocks) ->
+ %% We KNOW that a loop header must start with a peek_message
+ %% instruction.
+ case map_get(L, Blocks) of
+ #b_blk{is=[#b_set{op=peek_message}|_]} -> true;
+ _ -> false
+ end.
+
+rel2fam(S0) ->
+ S1 = sofs:relation(S0),
+ S = sofs:rel2fam(S1),
+ sofs:to_external(S).
+
+split_phis(Is) ->
+ splitwith(fun(#b_set{op=Op}) -> Op =:= phi end, Is).
+
+is_yreg({y,_}) -> true;
+is_yreg({x,_}) -> false;
+is_yreg({z,_}) -> false;
+is_yreg({fr,_}) -> false.
+
+new_vars([Base|Vs0], Count0) ->
+ {V,Count1} = new_var(Base, Count0),
+ {Vs,Count} = new_vars(Vs0, Count1),
+ {[V|Vs],Count};
+new_vars([], Count) -> {[],Count}.
+
+new_var({Base,Int}, Count) ->
+ true = is_integer(Int), %Assertion.
+ {#b_var{name={Base,Count}},Count+1};
+new_var(Base, Count) ->
+ {#b_var{name={Base,Count}},Count+1}.
diff --git a/lib/compiler/src/beam_ssa_recv.erl b/lib/compiler/src/beam_ssa_recv.erl
new file mode 100644
index 0000000000..1e0e1ecac2
--- /dev/null
+++ b/lib/compiler/src/beam_ssa_recv.erl
@@ -0,0 +1,278 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(beam_ssa_recv).
+-export([module/2]).
+
+%%%
+%%% In code such as:
+%%%
+%%% Ref = make_ref(), %Or erlang:monitor(process, Pid)
+%%% .
+%%% .
+%%% .
+%%% receive
+%%% {Ref,Reply} -> Reply
+%%% end.
+%%%
+%%% we know that none of the messages that exist in the message queue
+%%% before the call to make_ref/0 can be matched out in the receive
+%%% statement. Therefore we can avoid going through the entire message
+%%% queue if we introduce two new instructions (here written as
+%%% BIFs in pseudo-Erlang):
+%%%
+%%% recv_mark(SomeUniqInteger),
+%%% Ref = make_ref(),
+%%% .
+%%% .
+%%% .
+%%% recv_set(SomeUniqInteger),
+%%% receive
+%%% {Ref,Reply} -> Reply
+%%% end.
+%%%
+%%% The recv_mark/1 instruction will save the current position and
+%%% SomeUniqInteger in the process context. The recv_set
+%%% instruction will verify that SomeUniqInteger is still stored
+%%% in the process context. If it is, it will set the current pointer
+%%% for the message queue (the next message to be read out) to the
+%%% position that was saved by recv_mark/1.
+%%%
+%%% The remove_message instruction must be modified to invalidate
+%%% the information stored by the previous recv_mark/1, in case there
+%%% is another receive executed between the calls to recv_mark/1 and
+%%% recv_set/1.
+%%%
+%%% We use a reference to a label (i.e. a position in the loaded code)
+%%% as the SomeUniqInteger.
+%%%
+
+-include("beam_ssa.hrl").
+-import(lists, [all/2,reverse/2]).
+
+-spec module(beam_ssa:b_module(), [compile:option()]) ->
+ {'ok',beam_ssa:b_module()}.
+
+module(#b_module{body=Fs0}=Module, _Opts) ->
+ Fs = [function(F) || F <- Fs0],
+ {ok,Module#b_module{body=Fs}}.
+
+%%%
+%%% Local functions.
+%%%
+
+function(#b_function{anno=Anno,bs=Blocks0}=F) ->
+ try
+ Blocks = opt(Blocks0),
+ F#b_function{bs=Blocks}
+ catch
+ Class:Error:Stack ->
+ #{func_info:={_,Name,Arity}} = Anno,
+ io:fwrite("Function: ~w/~w\n", [Name,Arity]),
+ erlang:raise(Class, Error, Stack)
+ end.
+
+opt(Blocks) ->
+ Linear = beam_ssa:linearize(Blocks),
+ opt(Linear, Blocks, []).
+
+opt([{L,#b_blk{is=[#b_set{op=peek_message}|_]}=Blk0}|Bs], Blocks0, Preds) ->
+ %% Search for a suitable reference creating call in one of the predecessor
+ %% blocks. Whether we find such a call or not, we always clear the
+ %% the list of predecessors to ensure that any nested receive can't
+ %% search above the current receive.
+ case recv_opt(Preds, L, Blocks0) of
+ {yes,Blocks1} ->
+ Blk = beam_ssa:add_anno(recv_set, L, Blk0),
+ Blocks = Blocks1#{L:=Blk},
+ opt(Bs, Blocks, []);
+ no ->
+ opt(Bs, Blocks0, [])
+ end;
+opt([{L,_}|Bs], Blocks, Preds) ->
+ opt(Bs, Blocks, [L|Preds]);
+opt([], Blocks, _) -> Blocks.
+
+recv_opt([L|Ls], RecvLbl, Blocks) ->
+ #b_blk{is=Is0} = Blk0 = map_get(L, Blocks),
+ case recv_opt_is(Is0, RecvLbl, Blocks, []) of
+ {yes,Is} ->
+ Blk = Blk0#b_blk{is=Is},
+ {yes,Blocks#{L:=Blk}};
+ no ->
+ recv_opt(Ls, RecvLbl, Blocks)
+ end;
+recv_opt([], _, _Blocks) -> no.
+
+recv_opt_is([#b_set{op=call}=I0|Is], RecvLbl, Blocks0, Acc) ->
+ case makes_ref(I0, Blocks0) of
+ no ->
+ recv_opt_is(Is, RecvLbl, Blocks0, [I0|Acc]);
+ {yes,Ref} ->
+ case opt_ref_used(RecvLbl, Ref, Blocks0) of
+ false ->
+ recv_opt_is(Is, RecvLbl, Blocks0, [I0|Acc]);
+ true ->
+ I = beam_ssa:add_anno(recv_mark, RecvLbl, I0),
+ {yes,reverse(Acc, [I|Is])}
+ end
+ end;
+recv_opt_is([I|Is], RecvLbl, Blocks, Acc) ->
+ recv_opt_is(Is, RecvLbl, Blocks, [I|Acc]);
+recv_opt_is([], _, _, _) -> no.
+
+makes_ref(#b_set{dst=Dst,args=[Func0|_]}, Blocks) ->
+ Func = case Func0 of
+ #b_remote{mod=#b_literal{val=erlang},
+ name=#b_literal{val=Name},arity=A0} ->
+ {Name,A0};
+ _ ->
+ none
+ end,
+ case Func of
+ {make_ref,0} ->
+ {yes,Dst};
+ {monitor,2} ->
+ {yes,Dst};
+ {spawn_monitor,A} when A =:= 1; A =:= 3 ->
+ ref_in_tuple(Dst, Blocks);
+ _ ->
+ no
+ end.
+
+ref_in_tuple(Tuple, Blocks) ->
+ F = fun(#b_set{op=get_tuple_element,dst=Ref,
+ args=[#b_var{}=Tup,#b_literal{val=1}]}, no)
+ when Tup =:= Tuple -> {yes,Ref};
+ (_, A) -> A
+ end,
+ beam_ssa:fold_instrs_rpo(F, [0], no, Blocks).
+
+opt_ref_used(RecvLbl, Ref, Blocks) ->
+ Vs = #{Ref=>ref,ref=>Ref,ref_matched=>false},
+ case opt_ref_used_1(RecvLbl, Vs, Blocks) of
+ used -> true;
+ not_used -> false;
+ done -> false
+ end.
+
+opt_ref_used_1(L, Vs0, Blocks) ->
+ #b_blk{is=Is} = Blk = map_get(L, Blocks),
+ case opt_ref_used_is(Is, Vs0) of
+ #{}=Vs ->
+ opt_ref_used_last(Blk, Vs, Blocks);
+ Result ->
+ Result
+ end.
+
+opt_ref_used_is([#b_set{op=peek_message,dst=Msg}|Is], Vs0) ->
+ Vs = Vs0#{Msg=>message},
+ opt_ref_used_is(Is, Vs);
+opt_ref_used_is([#b_set{op={bif,Bif},args=Args,dst=Dst}=I|Is],
+ Vs0) ->
+ S = case Bif of
+ '=:=' -> true;
+ '==' -> true;
+ _ -> none
+ end,
+ case S of
+ none ->
+ Vs = update_vars(I, Vs0),
+ opt_ref_used_is(Is, Vs);
+ Bool when is_boolean(Bool) ->
+ case is_ref_msg_comparison(Args, Vs0) of
+ true ->
+ Vs = Vs0#{Dst=>{is_ref,Bool}},
+ opt_ref_used_is(Is, Vs);
+ false ->
+ opt_ref_used_is(Is, Vs0)
+ end
+ end;
+opt_ref_used_is([#b_set{op=remove_message}|_], Vs) ->
+ case Vs of
+ #{ref_matched:=true} ->
+ used;
+ #{ref_matched:=false} ->
+ not_used
+ end;
+opt_ref_used_is([#b_set{op=recv_next}|_], _Vs) ->
+ done;
+opt_ref_used_is([#b_set{op=wait_timeout}|_], _Vs) ->
+ done;
+opt_ref_used_is([#b_set{op=wait}|_], _Vs) ->
+ done;
+opt_ref_used_is([#b_set{}=I|Is], Vs0) ->
+ Vs = update_vars(I, Vs0),
+ opt_ref_used_is(Is, Vs);
+opt_ref_used_is([], Vs) -> Vs.
+
+opt_ref_used_last(#b_blk{last=Last}=Blk, Vs, Blocks) ->
+ case Last of
+ #b_br{bool=#b_var{}=Bool,succ=Succ,fail=Fail} ->
+ case Vs of
+ #{Bool:={is_ref,Matched}} ->
+ ref_used_in([{Succ,Vs#{ref_matched:=Matched}},
+ {Fail,Vs#{ref_matched:=not Matched}}],
+ Blocks);
+ #{} ->
+ ref_used_in([{Succ,Vs},{Fail,Vs}], Blocks)
+ end;
+ _ ->
+ SuccVs = [{Succ,Vs} || Succ <- beam_ssa:successors(Blk)],
+ ref_used_in(SuccVs, Blocks)
+ end.
+
+ref_used_in([{L,Vs0}|Ls], Blocks) ->
+ case opt_ref_used_1(L, Vs0, Blocks) of
+ not_used ->
+ not_used;
+ used ->
+ case ref_used_in(Ls, Blocks) of
+ done -> used;
+ Result -> Result
+ end;
+ done -> ref_used_in(Ls, Blocks)
+ end;
+ref_used_in([], _) -> done.
+
+update_vars(#b_set{args=Args,dst=Dst}, Vs) ->
+ Vars = [V || #b_var{}=V <- Args],
+ All = all(fun(Var) ->
+ case Vs of
+ #{Var:=message} -> true;
+ #{} -> false
+ end
+ end, Vars),
+ case All of
+ true -> Vs#{Dst=>message};
+ false -> Vs
+ end.
+
+%% is_ref_msg_comparison(Args, Variables) -> true|false.
+%% Return 'true' if Args denotes a comparison between the
+%% reference and message or part of the message.
+
+is_ref_msg_comparison([#b_var{}=V1,#b_var{}=V2], Vs) ->
+ case Vs of
+ #{V1:=ref,V2:=message} -> true;
+ #{V1:=message,V2:=ref} -> true;
+ #{} -> false
+ end;
+is_ref_msg_comparison(_, _) -> false.
diff --git a/lib/compiler/src/beam_ssa_share.erl b/lib/compiler/src/beam_ssa_share.erl
new file mode 100644
index 0000000000..426efa2cc9
--- /dev/null
+++ b/lib/compiler/src/beam_ssa_share.erl
@@ -0,0 +1,370 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%% Share code for semantically equivalent blocks referred to
+%% to by `br` and `switch` instructions.
+%%
+%% A similar optimization is done in beam_jump, but doing it here as
+%% well is beneficial as it may enable other optimizations. If there
+%% are many semantically equivalent clauses, this optimization can
+%% substanstially decrease compilation times.
+%%
+%% block/2 is called from the liveness optimization pass in
+%% beam_ssa_opt, as code sharing helps the liveness pass and vice
+%% versa.
+%%
+
+-module(beam_ssa_share).
+-export([module/2,block/2]).
+
+-include("beam_ssa.hrl").
+
+-import(lists, [keyfind/3,reverse/1,sort/1]).
+
+-spec module(beam_ssa:b_module(), [compile:option()]) ->
+ {'ok',beam_ssa:b_module()}.
+
+module(#b_module{body=Fs0}=Module, _Opts) ->
+ Fs = [function(F) || F <- Fs0],
+ {ok,Module#b_module{body=Fs}}.
+
+-spec block(Blk0, Blocks0) -> Blk when
+ Blk0 :: beam_ssa:b_blk(),
+ Blocks0 :: beam_ssa:block_map(),
+ Blk :: beam_ssa:b_blk().
+
+block(#b_blk{last=Last0}=Blk, Blocks) ->
+ case share_terminator(Last0, Blocks) of
+ none -> Blk;
+ Last -> Blk#b_blk{last=beam_ssa:normalize(Last)}
+ end.
+
+%%%
+%%% Local functions.
+%%%
+
+function(#b_function{anno=Anno,bs=Blocks0}=F) ->
+ try
+ PO = reverse(beam_ssa:rpo(Blocks0)),
+ {Blocks1,Changed} = blocks(PO, Blocks0, false),
+ Blocks = case Changed of
+ true ->
+ beam_ssa:trim_unreachable(Blocks1);
+ false ->
+ Blocks0
+ end,
+ F#b_function{bs=Blocks}
+ catch
+ Class:Error:Stack ->
+ #{func_info:={_,Name,Arity}} = Anno,
+ io:fwrite("Function: ~w/~w\n", [Name,Arity]),
+ erlang:raise(Class, Error, Stack)
+ end.
+
+blocks([L|Ls], Blocks, Changed) ->
+ #b_blk{last=Last0} = Blk0 = map_get(L, Blocks),
+ case block(Blk0, Blocks) of
+ #b_blk{last=Last0} ->
+ blocks(Ls, Blocks, Changed);
+ #b_blk{}=Blk ->
+ blocks(Ls, Blocks#{L:=Blk}, true)
+ end;
+blocks([], Blocks, Changed) ->
+ {Blocks,Changed}.
+
+share_terminator(#b_br{bool=#b_var{},succ=Succ0,fail=Fail0}=Br, Blocks) ->
+ {Succ,SuccBlk} = shortcut_nonempty_block(Succ0, Blocks),
+ {Fail,FailBlk} = shortcut_nonempty_block(Fail0, Blocks),
+ case are_equivalent(Succ, SuccBlk, Fail, FailBlk, Blocks) of
+ true ->
+ %% The blocks are semantically equivalent.
+ Br#b_br{succ=Succ,fail=Succ};
+ false ->
+ if
+ Succ =:= Succ0, Fail =:= Fail0 ->
+ %% None of blocks were cut short.
+ none;
+ true ->
+ %% One or both labels were cut short
+ %% to avoid jumping to an empty block.
+ Br#b_br{succ=Succ,fail=Fail}
+ end
+ end;
+share_terminator(#b_switch{}=Sw, Blocks) ->
+ share_switch(Sw, Blocks);
+share_terminator(_Last, _Blocks) -> none.
+
+%% Test whether the two blocks are semantically equivalent. This
+%% function is specially optimized to return `false` as fast as
+%% possible if the blocks are not equivalent, as that is the common
+%% case.
+
+are_equivalent(_Succ, _, ?BADARG_BLOCK, _, _Blocks) ->
+ %% ?BADARG_BLOCK is special. Sharing could be incorrect.
+ false;
+are_equivalent(_Succ, #b_blk{is=Is1,last=#b_ret{arg=RetVal1}=Ret1},
+ _Fail, #b_blk{is=Is2,last=#b_ret{arg=RetVal2}=Ret2}, _Blocks) ->
+ case {RetVal1,RetVal2} of
+ {#b_literal{},#b_literal{}} ->
+ case RetVal1 =:= RetVal2 of
+ true ->
+ %% The return values are identical literals. We
+ %% only need to compare the canonicalized bodies.
+ Can1 = canonical_is(Is1),
+ Can2 = canonical_is(Is2),
+ Can1 =:= Can2;
+ false ->
+ %% Non-equal literals.
+ false
+ end;
+ {#b_var{},#b_var{}} ->
+ %% The return values are varibles. We must canonicalize
+ %% the blocks (including returns) and compare them.
+ Can1 = canonical_is(Is1 ++ [Ret1]),
+ Can2 = canonical_is(Is2 ++ [Ret2]),
+ Can1 =:= Can2;
+ {_,_} ->
+ %% One literal and one variable.
+ false
+ end;
+are_equivalent(Succ,
+ #b_blk{is=Is1,
+ last=#b_br{bool=#b_literal{val=true},
+ succ=Target}},
+ Fail,
+ #b_blk{is=Is2,
+ last=#b_br{bool=#b_literal{val=true},
+ succ=Target}},
+ Blocks) ->
+ %% Both blocks end with an unconditional branch to the
+ %% same target block. If the target block has phi nodes,
+ %% we must pick up the values from the phi nodes and
+ %% compare them.
+ #b_blk{is=Is} = map_get(Target, Blocks),
+ Phis1 = canonical_terminator_phis(Is, Succ),
+ Phis2 = canonical_terminator_phis(Is, Fail),
+ case {Phis1,Phis2} of
+ {[#b_set{args=[#b_literal{}]}|_],_} when Phis1 =/= Phis2 ->
+ %% Different values are used in the phi nodes.
+ false;
+ {_,[#b_set{args=[#b_literal{}]}|_]} when Phis1 =/= Phis2 ->
+ %% Different values are used in the phi nodes.
+ false;
+ {_,_} ->
+ %% The values in the phi nodes are variables or identical
+ %% literals. We must canonicalize the blocks and compare
+ %% them.
+ Can1 = canonical_is(Is1 ++ Phis1),
+ Can2 = canonical_is(Is2 ++ Phis2),
+ Can1 =:= Can2
+ end;
+are_equivalent(Succ0, #b_blk{is=Is1,last=#b_br{bool=#b_var{},fail=Same}},
+ Fail0, #b_blk{is=Is2,last=#b_br{bool=#b_var{},fail=Same}},
+ Blocks) ->
+ %% Two-way branches with identical failure labels. First compare the
+ %% canonicalized bodies of the blocks.
+ case canonical_is(Is1) =:= canonical_is(Is2) of
+ false ->
+ %% Different bodies.
+ false;
+ true ->
+ %% Bodies were equal. That is fairly uncommon, so to keep
+ %% the code simple we will rewrite the `br` to a `switch`
+ %% and let share_switch/2 do the work of following the
+ %% branches.
+ Sw = #b_switch{arg=#b_var{name=not_used},fail=Fail0,
+ list=[{#b_literal{},Succ0}]},
+ #b_switch{fail=Fail,list=[{_,Succ}]} = share_switch(Sw, Blocks),
+ Fail =:= Succ
+ end;
+are_equivalent(_, _, _, _, _) -> false.
+
+share_switch(#b_switch{fail=Fail0,list=List0}=Sw, Blocks) ->
+ Prep = share_prepare_sw([{value,Fail0}|List0], Blocks, 0, []),
+ Res = do_share_switch(Prep, Blocks, []),
+ [{_,Fail}|List] = [VL || {_,VL} <- sort(Res)],
+ Sw#b_switch{fail=Fail,list=List}.
+
+share_prepare_sw([{V,L0}|T], Blocks, N, Acc) ->
+ {L,_Blk} = shortcut_nonempty_block(L0, Blocks),
+ share_prepare_sw(T, Blocks, N+1, [{{L,#{}},{N,{V,L}}}|Acc]);
+share_prepare_sw([], _, _, Acc) -> Acc.
+
+do_share_switch(Prep, Blocks, Acc) ->
+ Map = share_switch_1(Prep, Blocks, #{}),
+ share_switch_2(maps:values(Map), Blocks, Acc).
+
+share_switch_1([{Next0,Res}|T], Blocks, Map) ->
+ {Can,Next} = canonical_block(Next0, Blocks),
+ case Map of
+ #{Can:=Ls} ->
+ share_switch_1(T, Blocks, Map#{Can:=[{Next,Res}|Ls]});
+ #{} ->
+ share_switch_1(T, Blocks, Map#{Can=>[{Next,Res}]})
+ end;
+share_switch_1([], _Blocks, Map) -> Map.
+
+share_switch_2([[{_,{N,Res}}]|T], Blocks, Acc) ->
+ %% This block is not equivalent to any other block.
+ share_switch_2(T, Blocks, [{N,Res}|Acc]);
+share_switch_2([[{done,{_,{_,Common}}}|_]=Eqs|T], Blocks, Acc0) ->
+ %% Two or more blocks are semantically equivalent, and all blocks
+ %% are either terminated with a `ret` or a `br` to the same target
+ %% block. Replace the labels in the `switch` for all of those
+ %% blocks with the label for the first of the blocks.
+ Acc = [{N,{V,Common}} || {done,{N,{V,_}}} <- Eqs] ++ Acc0,
+ share_switch_2(T, Blocks, Acc);
+share_switch_2([[{_,_}|_]=Prep|T], Blocks, Acc0) ->
+ %% Two or more blocks are semantically equivalent, but they have
+ %% different successful successor blocks. Now we must check
+ %% recursively whether the successor blocks are equivalent too.
+ Acc = do_share_switch(Prep, Blocks, Acc0),
+ share_switch_2(T, Blocks, Acc);
+share_switch_2([], _, Acc) -> Acc.
+
+canonical_block({L,VarMap0}, Blocks) ->
+ #b_blk{is=Is,last=Last0} = map_get(L, Blocks),
+ case canonical_terminator(L, Last0, Blocks) of
+ none ->
+ %% The block has a terminator that we don't handle.
+ {{none,L},done};
+ {Last,done} ->
+ %% The block ends with a `ret` or an unconditional `br` to
+ %% another block.
+ {Can,_VarMap} = canonical_is(Is ++ Last, VarMap0, []),
+ {Can,done};
+ {Last,Next} ->
+ %% The block ends with a conditional branch.
+ {Can,VarMap} = canonical_is(Is ++ Last, VarMap0, []),
+ {Can,{Next,VarMap}}
+ end.
+
+%% Translate a sequence of instructions to a canonical representation. If the
+%% canonical representation of two blocks compare equal, the blocks are
+%% semantically equivalent. The following translations are done:
+%%
+%% * Variables defined in the instruction sequence are replaced with
+%% {var,0}, {var,1}, and so on. Free variables are not changed.
+%%
+%% * `location` annotations that would produce a `line` instruction are
+%% kept. All other annotations are cleared.
+%%
+%% * Instructions are repackaged into tuples instead of into the
+%% usual records. The main reason is to avoid violating the types for
+%% the SSA records. We can simplify things a little by linking the
+%% instructions directly instead of putting them into a list.
+
+canonical_is(Is) ->
+ {Can,_} = canonical_is(Is, #{}, []),
+ Can.
+
+canonical_is([#b_set{op=Op,dst=Dst,args=Args0}=I|Is], VarMap0, Acc) ->
+ Args = [canonical_arg(Arg, VarMap0) || Arg <-Args0],
+ Var = {var,map_size(VarMap0)},
+ VarMap = VarMap0#{Dst=>Var},
+ LineAnno = case Op of
+ bs_match ->
+ %% The location annotation for a bs_match instruction
+ %% is only used in warnings, never to emit a `line`
+ %% instruction. Therefore, it should not be included.
+ [];
+ _ ->
+ %% The location annotation will be used in a `line`
+ %% instruction. It must be included.
+ beam_ssa:get_anno(location, I, none)
+ end,
+ canonical_is(Is, VarMap, {Op,LineAnno,Var,Args,Acc});
+canonical_is([#b_ret{arg=Arg}], VarMap, Acc0) ->
+ Acc1 = case Acc0 of
+ {call,_Anno,Var,[#b_local{}|_]=Args,PrevAcc} ->
+ %% This is a tail-recursive call to a local function.
+ %% There will be no line instruction generated;
+ %% thus, the annotation is not significant.
+ {call,[],Var,Args,PrevAcc};
+ _ ->
+ Acc0
+ end,
+ {{ret,canonical_arg(Arg, VarMap),Acc1},VarMap};
+canonical_is([#b_br{bool=#b_var{},fail=Fail}], VarMap, Acc) ->
+ {{br,succ,Fail,Acc},VarMap};
+canonical_is([#b_br{succ=Succ}], VarMap, Acc) ->
+ {{br,Succ,Acc},VarMap};
+canonical_is([], VarMap, Acc) ->
+ {Acc,VarMap}.
+
+canonical_terminator(_L, #b_ret{}=Ret, _Blocks) ->
+ {[Ret],done};
+canonical_terminator(L, #b_br{bool=#b_literal{val=true},succ=Succ}=Br, Blocks) ->
+ #b_blk{is=Is} = map_get(Succ, Blocks),
+ case canonical_terminator_phis(Is, L) of
+ [] ->
+ {[],Succ};
+ [_|_]=Phis ->
+ {Phis ++ [Br],done}
+ end;
+canonical_terminator(_L, #b_br{bool=#b_var{},succ=Succ}=Br, _Blocks) ->
+ {[Br],Succ};
+canonical_terminator(_, _, _) -> none.
+
+canonical_terminator_phis([#b_set{op=phi,args=PhiArgs}=Phi|Is], L) ->
+ {Value,L} = keyfind(L, 2, PhiArgs),
+ [Phi#b_set{op=copy,args=[Value]}|canonical_terminator_phis(Is, L)];
+canonical_terminator_phis([#b_set{op=peek_message}=I|_], L) ->
+ %% We could get stuck into an infinite loop if we allowed the
+ %% comparisons to continue into this block. Force an unequal
+ %% compare with all other predecessors of this block.
+ [I#b_set{op=copy,args=[#b_literal{val=L}]}];
+canonical_terminator_phis(_, _) -> [].
+
+canonical_arg(#b_var{}=Var, VarMap) ->
+ case VarMap of
+ #{Var:=CanonicalVar} ->
+ CanonicalVar;
+ #{} ->
+ Var
+ end;
+canonical_arg(#b_remote{mod=Mod,name=Name}, VarMap) ->
+ {remote,canonical_arg(Mod, VarMap),
+ canonical_arg(Name, VarMap)};
+canonical_arg(Other, _VarMap) -> Other.
+
+%% Shortcut branches to empty blocks if safe.
+
+shortcut_nonempty_block(L, Blocks) ->
+ case map_get(L, Blocks) of
+ #b_blk{is=[],last=#b_br{bool=#b_literal{val=true},succ=Succ}}=Blk ->
+ %% This block is empty.
+ case is_forbidden(Succ, Blocks) of
+ false ->
+ shortcut_nonempty_block(Succ, Blocks);
+ true ->
+ {L,Blk}
+ end;
+ #b_blk{}=Blk ->
+ {L,Blk}
+ end.
+
+is_forbidden(L, Blocks) ->
+ case map_get(L, Blocks) of
+ #b_blk{is=[#b_set{op=phi}|_]} -> true;
+ #b_blk{is=[#b_set{op=peek_message}|_]} -> true;
+ #b_blk{} -> false
+ end.
diff --git a/lib/compiler/src/beam_ssa_type.erl b/lib/compiler/src/beam_ssa_type.erl
new file mode 100644
index 0000000000..06b42f1928
--- /dev/null
+++ b/lib/compiler/src/beam_ssa_type.erl
@@ -0,0 +1,1956 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(beam_ssa_type).
+-export([opt_start/4, opt_continue/4, opt_finish/3]).
+
+-include("beam_ssa_opt.hrl").
+-import(lists, [all/2,any/2,droplast/1,foldl/3,last/1,member/2,
+ keyfind/3,partition/2,reverse/1,reverse/2,
+ seq/2,sort/1,split/2]).
+
+-define(UNICODE_INT, #t_integer{elements={0,16#10FFFF}}).
+
+-record(d,
+ {ds :: #{beam_ssa:b_var():=beam_ssa:b_set()},
+ ls :: #{beam_ssa:label():=type_db()},
+ once :: cerl_sets:set(beam_ssa:b_var()),
+ func_id :: func_id(),
+ func_db :: func_info_db(),
+ sub = #{} :: #{beam_ssa:b_var():=beam_ssa:value()},
+ ret_type = [] :: [type()]}).
+
+-define(ATOM_SET_SIZE, 5).
+
+%% Records that represent type information.
+-record(t_atom, {elements=any :: 'any' | [atom()]}).
+-record(t_integer, {elements=any :: 'any' | {integer(),integer()}}).
+-record(t_bs_match, {type :: type()}).
+-record(t_tuple, {size=0 :: integer(),
+ exact=false :: boolean(),
+ %% Known element types (1-based index), unknown elements are
+ %% are assumed to be 'any'.
+ elements=#{} :: #{ non_neg_integer() => type() }}).
+
+-type type() :: 'any' | 'none' |
+ #t_atom{} | #t_integer{} | #t_bs_match{} | #t_tuple{} |
+ {'binary',pos_integer()} | 'cons' | 'float' | 'list' | 'map' | 'nil' | 'number'.
+-type type_db() :: #{beam_ssa:var_name():=type()}.
+
+-spec opt_start(Linear, Args, Anno, FuncDb) -> {Linear, FuncDb} when
+ Linear :: [{non_neg_integer(), beam_ssa:b_blk()}],
+ Args :: [beam_ssa:b_var()],
+ Anno :: beam_ssa:anno(),
+ FuncDb :: func_info_db().
+opt_start(Linear, Args, Anno, FuncDb) ->
+ %% This is the first run through the module, so our arg_types can be
+ %% incomplete as we may not have visited all call sites at least once.
+ Ts = maps:from_list([{V,any} || #b_var{}=V <- Args]),
+ opt_continue_1(Linear, Args, get_func_id(Anno), Ts, FuncDb).
+
+-spec opt_continue(Linear, Args, Anno, FuncDb) -> {Linear, FuncDb} when
+ Linear :: [{non_neg_integer(), beam_ssa:b_blk()}],
+ Args :: [beam_ssa:b_var()],
+ Anno :: beam_ssa:anno(),
+ FuncDb :: func_info_db().
+opt_continue(Linear, Args, Anno, FuncDb) ->
+ Id = get_func_id(Anno),
+ case FuncDb of
+ #{ Id := #func_info{exported=false,arg_types=ArgTypes} } ->
+ %% This is a local function and we're guaranteed to have visited
+ %% every call site at least once, so we know that the parameter
+ %% types are at least as narrow as the join of all argument types.
+ Ts = join_arg_types(Args, ArgTypes, Anno),
+ opt_continue_1(Linear, Args, Id, Ts, FuncDb);
+ #{} ->
+ %% We can't infer the parameter types of exported functions, nor
+ %% the ones where module-level optimization is disabled, but
+ %% running the pass again could still help other functions.
+ Ts = maps:from_list([{V,any} || #b_var{}=V <- Args]),
+ opt_continue_1(Linear, Args, Id, Ts, FuncDb)
+ end.
+
+join_arg_types(Args, ArgTypes, Anno) ->
+ %% We suppress type optimization for parameters that have already been
+ %% optimized by another pass, as they may have done things we have no idea
+ %% how to interpret and running them over could generate incorrect code.
+ ParamTypes = maps:get(parameter_type_info, Anno, #{}),
+ Ts0 = join_arg_types_1(Args, ArgTypes, #{}),
+ maps:fold(fun(Arg, _V, Ts) ->
+ maps:put(Arg, any, Ts)
+ end, Ts0, ParamTypes).
+
+join_arg_types_1([Arg | Args], [TM | TMs], Ts) when map_size(TM) =/= 0 ->
+ join_arg_types_1(Args, TMs, Ts#{ Arg => join(maps:values(TM))});
+join_arg_types_1([Arg | Args], [_TM | TMs], Ts) ->
+ join_arg_types_1(Args, TMs, Ts#{ Arg => any });
+join_arg_types_1([], [], Ts) ->
+ Ts.
+
+-spec opt_continue_1(Linear, Args, Id, Ts, FuncDb) -> Result when
+ Linear :: [{non_neg_integer(), beam_ssa:b_blk()}],
+ Args :: [beam_ssa:b_var()],
+ Id :: func_id(),
+ Ts :: type_db(),
+ FuncDb :: func_info_db(),
+ Result :: {Linear, FuncDb}.
+opt_continue_1(Linear0, Args, Id, Ts, FuncDb0) ->
+ UsedOnce = used_once(Linear0, Args),
+ FakeCall = #b_set{op=call,args=[#b_remote{mod=#b_literal{val=unknown},
+ name=#b_literal{val=unknown},
+ arity=0}]},
+ Defs = maps:from_list([{Var,FakeCall#b_set{dst=Var}} ||
+ #b_var{}=Var <- Args]),
+
+ D = #d{ func_db=FuncDb0,
+ func_id=Id,
+ ds=Defs,
+ ls=#{0=>Ts,?BADARG_BLOCK=>#{}},
+ once=UsedOnce },
+
+ {Linear, FuncDb, NewRet} = opt(Linear0, D, []),
+
+ case FuncDb of
+ #{ Id := Entry0 } ->
+ Entry = Entry0#func_info{ret_type=NewRet},
+ {Linear, FuncDb#{ Id := Entry }};
+ #{} ->
+ %% Module-level optimizations have been turned off for this
+ %% function.
+ {Linear, FuncDb}
+ end.
+
+-spec opt_finish(Args, Anno, FuncDb) -> {Anno, FuncDb} when
+ Args :: [beam_ssa:b_var()],
+ Anno :: beam_ssa:anno(),
+ FuncDb :: func_info_db().
+opt_finish(Args, Anno, FuncDb) ->
+ Id = get_func_id(Anno),
+ case FuncDb of
+ #{ Id := #func_info{exported=false,arg_types=ArgTypes} } ->
+ ParamInfo0 = maps:get(parameter_type_info, Anno, #{}),
+ ParamInfo = opt_finish_1(Args, ArgTypes, ParamInfo0),
+ {Anno#{ parameter_type_info => ParamInfo }, FuncDb};
+ #{} ->
+ {Anno, FuncDb}
+ end.
+
+opt_finish_1([Arg | Args], [TypeMap | TypeMaps], ParamInfo)
+ when is_map_key(Arg, ParamInfo); %% See join_arg_types/3
+ map_size(TypeMap) =:= 0 ->
+ opt_finish_1(Args, TypeMaps, ParamInfo);
+opt_finish_1([Arg | Args], [TypeMap | TypeMaps], ParamInfo0) ->
+ case join(maps:values(TypeMap)) of
+ any ->
+ opt_finish_1(Args, TypeMaps, ParamInfo0);
+ JoinedType ->
+ JoinedType = verified_type(JoinedType),
+ ParamInfo = ParamInfo0#{ Arg => validator_anno(JoinedType) },
+ opt_finish_1(Args, TypeMaps, ParamInfo)
+ end;
+opt_finish_1([], [], ParamInfo) ->
+ ParamInfo.
+
+validator_anno(#t_tuple{size=Size,exact=Exact,elements=Elements0}) ->
+ Elements = maps:fold(fun(Index, Type, Acc) ->
+ Key = beam_validator:type_anno(integer, Index),
+ Acc#{ Key => validator_anno(Type) }
+ end, #{}, Elements0),
+ beam_validator:type_anno(tuple, Size, Exact, Elements);
+validator_anno(#t_integer{elements={Same,Same}}) ->
+ beam_validator:type_anno(integer, Same);
+validator_anno(#t_integer{}) ->
+ beam_validator:type_anno(integer);
+validator_anno(float) ->
+ beam_validator:type_anno(float);
+validator_anno(#t_atom{elements=[Val]}) ->
+ beam_validator:type_anno(atom, Val);
+validator_anno(#t_atom{}=A) ->
+ case t_is_boolean(A) of
+ true -> beam_validator:type_anno(bool);
+ false -> beam_validator:type_anno(atom)
+ end;
+validator_anno(T) ->
+ beam_validator:type_anno(T).
+
+get_func_id(Anno) ->
+ #{func_info:={_Mod, Name, Arity}} = Anno,
+ #b_local{name=#b_literal{val=Name}, arity=Arity}.
+
+opt([{L,Blk}|Bs], #d{ls=Ls}=D, Acc) ->
+ case Ls of
+ #{L:=Ts} ->
+ opt_1(L, Blk, Bs, Ts, D, Acc);
+ #{} ->
+ %% This block is never reached. Discard it.
+ opt(Bs, D, Acc)
+ end;
+opt([], D, Acc) ->
+ #d{func_db=FuncDb,ret_type=NewRet} = D,
+ {reverse(Acc), FuncDb, NewRet}.
+
+opt_1(L, #b_blk{is=Is0,last=Last0}=Blk0, Bs, Ts0,
+ #d{ds=Ds0,sub=Sub0,func_db=Fdb0}=D0, Acc) ->
+ case opt_is(Is0, Ts0, Ds0, Fdb0, D0, Sub0, []) of
+ {Is,Ts,Ds,Fdb,Sub} ->
+ D1 = D0#d{ds=Ds,sub=Sub,func_db=Fdb},
+ Last1 = simplify_terminator(Last0, Sub, Ts, Ds),
+ Last = opt_terminator(Last1, Ts, Ds),
+ D = update_successors(Last, Ts, D1),
+ Blk = Blk0#b_blk{is=Is,last=Last},
+ opt(Bs, D, [{L,Blk}|Acc]);
+ {no_return,Ret,Is,Ds,Fdb,Sub} ->
+ %% This call will never reach the successor block.
+ %% Rewrite the terminator to a 'ret', and remove
+ %% all type information for this label. That can
+ %% potentially narrow the type of the phi node
+ %% in the former successor.
+ Ls = maps:remove(L, D0#d.ls),
+ RetType = join([none|D0#d.ret_type]),
+ D = D0#d{ds=Ds,ls=Ls,sub=Sub,
+ func_db=Fdb,ret_type=[RetType]},
+ Blk = Blk0#b_blk{is=Is,last=Ret},
+ opt(Bs, D, [{L,Blk}|Acc])
+ end.
+
+simplify_terminator(#b_br{bool=Bool}=Br, Sub, Ts, _Ds) ->
+ Br#b_br{bool=simplify_arg(Bool, Sub, Ts)};
+simplify_terminator(#b_switch{arg=Arg}=Sw, Sub, Ts, _Ds) ->
+ Sw#b_switch{arg=simplify_arg(Arg, Sub, Ts)};
+simplify_terminator(#b_ret{arg=Arg}=Ret, Sub, Ts, Ds) ->
+ %% Reducing the result of a call to a literal (fairly common for 'ok')
+ %% breaks tail call optimization.
+ case Ds of
+ #{ Arg := #b_set{op=call}} -> Ret;
+ #{} -> Ret#b_ret{arg=simplify_arg(Arg, Sub, Ts)}
+ end.
+
+opt_is([#b_set{op=phi,dst=Dst,args=Args0}=I0|Is],
+ Ts0, Ds0, Fdb, #d{ls=Ls}=D, Sub0, Acc) ->
+ %% Simplify the phi node by removing all predecessor blocks that no
+ %% longer exists or no longer branches to this block.
+ Args = [{simplify_arg(Arg, Sub0, Ts0),From} ||
+ {Arg,From} <- Args0, maps:is_key(From, Ls)],
+ case all_same(Args) of
+ true ->
+ %% Eliminate the phi node if there is just one source
+ %% value or if the values are identical.
+ [{Val,_}|_] = Args,
+ Sub = Sub0#{Dst=>Val},
+ opt_is(Is, Ts0, Ds0, Fdb, D, Sub, Acc);
+ false ->
+ I = I0#b_set{args=Args},
+ Ts = update_types(I, Ts0, Ds0),
+ Ds = Ds0#{Dst=>I},
+ opt_is(Is, Ts, Ds, Fdb, D, Sub0, [I|Acc])
+ end;
+opt_is([#b_set{op=call,args=Args0,dst=Dst}=I0|Is],
+ Ts0, Ds0, Fdb0, D, Sub0, Acc) ->
+ Args = simplify_args(Args0, Sub0, Ts0),
+ I1 = beam_ssa:normalize(I0#b_set{args=Args}),
+ {Ts1,Ds,Fdb,I2} = opt_call(I1, D, Ts0, Ds0, Fdb0),
+ case {map_get(Dst, Ts1),Is} of
+ {Type,[#b_set{op=succeeded}]} when Type =/= none ->
+ %% This call instruction is inside a try/catch
+ %% block. Don't attempt to simplify it.
+ opt_is(Is, Ts1, Ds, Fdb, D, Sub0, [I2|Acc]);
+ {none,[#b_set{op=succeeded}]} ->
+ %% This call instruction is inside a try/catch
+ %% block, but we know it will never return and
+ %% later optimizations may try to exploit that.
+ %%
+ %% For example, if we have an expression that
+ %% either returns this call or a tuple, we know
+ %% that the expression always returns a tuple
+ %% and can turn a later element/3 into
+ %% get_tuple_element.
+ %%
+ %% This is sound but difficult to validate in a
+ %% meaningful way as try/catch currently forces
+ %% us to maintain the illusion that the success
+ %% block is reachable even when its not, so we
+ %% disable the optimization to keep things
+ %% simple.
+ Ts = Ts1#{ Dst := any },
+ opt_is(Is, Ts, Ds, Fdb, D, Sub0, [I2|Acc]);
+ {none,_} ->
+ %% This call never returns. The rest of the
+ %% instructions will not be executed.
+ Ret = #b_ret{arg=Dst},
+ {no_return,Ret,reverse(Acc, [I2]),Ds,Fdb,Sub0};
+ {_,_} ->
+ case simplify_call(I2) of
+ #b_set{}=I ->
+ opt_is(Is, Ts1, Ds, Fdb, D, Sub0, [I|Acc]);
+ #b_literal{}=Lit ->
+ Sub = Sub0#{Dst=>Lit},
+ Ts = maps:remove(Dst, Ts1),
+ opt_is(Is, Ts, Ds0, Fdb, D, Sub, Acc);
+ #b_var{}=Var ->
+ Ts = maps:remove(Dst, Ts1),
+ Sub = Sub0#{Dst=>Var},
+ opt_is(Is, Ts, Ds0, Fdb, D, Sub, Acc)
+ end
+ end;
+opt_is([#b_set{op=succeeded,args=[Arg],dst=Dst}=I],
+ Ts0, Ds0, Fdb, D, Sub0, Acc) ->
+ case Ds0 of
+ #{ Arg := #b_set{op=call} } ->
+ %% The success check of a call is part of exception handling and
+ %% must not be optimized away. We still have to update its type
+ %% though.
+ Ts = update_types(I, Ts0, Ds0),
+ Ds = Ds0#{Dst=>I},
+
+ opt_is([], Ts, Ds, Fdb, D, Sub0, [I|Acc]);
+ #{} ->
+ Args = simplify_args([Arg], Sub0, Ts0),
+ Type = type(succeeded, Args, Ts0, Ds0),
+ case get_literal_from_type(Type) of
+ #b_literal{}=Lit ->
+ Sub = Sub0#{Dst=>Lit},
+ opt_is([], Ts0, Ds0, Fdb, D, Sub, Acc);
+ none ->
+ Ts = Ts0#{Dst=>Type},
+ Ds = Ds0#{Dst=>I},
+ opt_is([], Ts, Ds, Fdb, D, Sub0, [I|Acc])
+ end
+ end;
+opt_is([#b_set{args=Args0,dst=Dst}=I0|Is],
+ Ts0, Ds0, Fdb, D, Sub0, Acc) ->
+ Args = simplify_args(Args0, Sub0, Ts0),
+ I1 = beam_ssa:normalize(I0#b_set{args=Args}),
+ case simplify(I1, Ts0) of
+ #b_set{}=I2 ->
+ I = beam_ssa:normalize(I2),
+ Ts = update_types(I, Ts0, Ds0),
+ Ds = Ds0#{Dst=>I},
+ opt_is(Is, Ts, Ds, Fdb, D, Sub0, [I|Acc]);
+ #b_literal{}=Lit ->
+ Sub = Sub0#{Dst=>Lit},
+ opt_is(Is, Ts0, Ds0, Fdb, D, Sub, Acc);
+ #b_var{}=Var ->
+ case Is of
+ [#b_set{op=succeeded,dst=SuccDst,args=[Dst]}] ->
+ %% We must remove this 'succeeded' instruction.
+ Sub = Sub0#{Dst=>Var,SuccDst=>#b_literal{val=true}},
+ opt_is([], Ts0, Ds0, Fdb, D, Sub, Acc);
+ _ ->
+ Sub = Sub0#{Dst=>Var},
+ opt_is(Is, Ts0, Ds0, Fdb, D, Sub, Acc)
+ end
+ end;
+opt_is([], Ts, Ds, Fdb, _D, Sub, Acc) ->
+ {reverse(Acc), Ts, Ds, Fdb, Sub}.
+
+simplify_call(#b_set{op=call,args=[#b_remote{}=Rem|Args]}=I) ->
+ case Rem of
+ #b_remote{mod=#b_literal{val=Mod},
+ name=#b_literal{val=Name}} ->
+ case erl_bifs:is_pure(Mod, Name, length(Args)) of
+ true ->
+ simplify_remote_call(Mod, Name, Args, I);
+ false ->
+ I
+ end;
+ #b_remote{} ->
+ I
+ end;
+simplify_call(I) -> I.
+
+%% Simplify a remote call to a pure BIF.
+simplify_remote_call(erlang, '++', [#b_literal{val=[]},Tl], _I) ->
+ Tl;
+simplify_remote_call(erlang, setelement,
+ [#b_literal{val=Pos},
+ #b_literal{val=Tuple},
+ #b_var{}=Value], I)
+ when is_integer(Pos), 1 =< Pos, Pos =< tuple_size(Tuple) ->
+ %% Position is a literal integer and the shape of the
+ %% tuple is known.
+ Els0 = [#b_literal{val=El} || El <- tuple_to_list(Tuple)],
+ {Bef,[_|Aft]} = split(Pos - 1, Els0),
+ Els = Bef ++ [Value|Aft],
+ I#b_set{op=put_tuple,args=Els};
+simplify_remote_call(Mod, Name, Args0, I) ->
+ case make_literal_list(Args0) of
+ none ->
+ I;
+ Args ->
+ %% The arguments are literals. Try to evaluate the BIF.
+ try apply(Mod, Name, Args) of
+ Val ->
+ case cerl:is_literal_term(Val) of
+ true ->
+ #b_literal{val=Val};
+ false ->
+ %% The value can't be expressed as a literal
+ %% (e.g. a pid).
+ I
+ end
+ catch
+ _:_ ->
+ %% Failed. Don't bother trying to optimize
+ %% the call.
+ I
+ end
+ end.
+
+opt_call(#b_set{dst=Dst,args=[#b_local{}=Callee|Args]}=I0, D, Ts0, Ds0, Fdb0) ->
+ {Ts, Ds, I} = opt_local_call(I0, Ts0, Ds0, Fdb0),
+ case Fdb0 of
+ #{ Callee := #func_info{exported=false,arg_types=ArgTypes0}=Info } ->
+ %% Update the argument types of *this exact call*, the types
+ %% will be joined later when the callee is optimized.
+ CallId = {D#d.func_id, Dst},
+ ArgTypes = update_arg_types(Args, ArgTypes0, CallId, Ts0),
+
+ Fdb = Fdb0#{ Callee => Info#func_info{arg_types=ArgTypes} },
+ {Ts, Ds, Fdb, I};
+ #{} ->
+ %% We can't narrow the argument types of exported functions as they
+ %% can receive anything as part of an external call.
+ {Ts, Ds, Fdb0, I}
+ end;
+opt_call(#b_set{dst=Dst}=I, _D, Ts0, Ds0, Fdb) ->
+ Ts = update_types(I, Ts0, Ds0),
+ Ds = Ds0#{ Dst => I },
+ {Ts, Ds, Fdb, I}.
+
+opt_local_call(#b_set{dst=Dst,args=[Id|_]}=I0, Ts0, Ds0, Fdb) ->
+ Type = case Fdb of
+ #{ Id := #func_info{ret_type=[T]} } -> T;
+ #{} -> any
+ end,
+ I = case Type of
+ any -> I0;
+ none -> I0;
+ _ -> beam_ssa:add_anno(result_type, validator_anno(Type), I0)
+ end,
+ Ts = Ts0#{ Dst => Type },
+ Ds = Ds0#{ Dst => I },
+ {Ts, Ds, I}.
+
+update_arg_types([Arg | Args], [TypeMap0 | TypeMaps], CallId, Ts) ->
+ %% Match contexts are treated as bitstrings when optimizing arguments, as
+ %% we don't yet support removing the "bs_start_match3" instruction.
+ NewType = case get_type(Arg, Ts) of
+ #t_bs_match{} -> {binary, 1};
+ Type -> Type
+ end,
+ TypeMap = TypeMap0#{ CallId => NewType },
+ [TypeMap | update_arg_types(Args, TypeMaps, CallId, Ts)];
+update_arg_types([], [], _CallId, _Ts) ->
+ [].
+
+simplify(#b_set{op={bif,'and'},args=Args}=I, Ts) ->
+ case is_safe_bool_op(Args, Ts) of
+ true ->
+ case Args of
+ [_,#b_literal{val=false}=Res] -> Res;
+ [Res,#b_literal{val=true}] -> Res;
+ _ -> eval_bif(I, Ts)
+ end;
+ false ->
+ I
+ end;
+simplify(#b_set{op={bif,'or'},args=Args}=I, Ts) ->
+ case is_safe_bool_op(Args, Ts) of
+ true ->
+ case Args of
+ [Res,#b_literal{val=false}] -> Res;
+ [_,#b_literal{val=true}=Res] -> Res;
+ _ -> eval_bif(I, Ts)
+ end;
+ false ->
+ I
+ end;
+simplify(#b_set{op={bif,element},args=[#b_literal{val=Index},Tuple]}=I0, Ts) ->
+ case t_tuple_size(get_type(Tuple, Ts)) of
+ {_,Size} when is_integer(Index), 1 =< Index, Index =< Size ->
+ I = I0#b_set{op=get_tuple_element,
+ args=[Tuple,#b_literal{val=Index-1}]},
+ simplify(I, Ts);
+ _ ->
+ eval_bif(I0, Ts)
+ end;
+simplify(#b_set{op={bif,hd},args=[List]}=I, Ts) ->
+ case get_type(List, Ts) of
+ cons ->
+ I#b_set{op=get_hd};
+ _ ->
+ eval_bif(I, Ts)
+ end;
+simplify(#b_set{op={bif,tl},args=[List]}=I, Ts) ->
+ case get_type(List, Ts) of
+ cons ->
+ I#b_set{op=get_tl};
+ _ ->
+ eval_bif(I, Ts)
+ end;
+simplify(#b_set{op={bif,size},args=[Term]}=I, Ts) ->
+ case get_type(Term, Ts) of
+ #t_tuple{} ->
+ simplify(I#b_set{op={bif,tuple_size}}, Ts);
+ _ ->
+ eval_bif(I, Ts)
+ end;
+simplify(#b_set{op={bif,tuple_size},args=[Term]}=I, Ts) ->
+ case get_type(Term, Ts) of
+ #t_tuple{size=Size,exact=true} ->
+ #b_literal{val=Size};
+ _ ->
+ I
+ end;
+simplify(#b_set{op={bif,'=='},args=Args}=I, Ts) ->
+ Types = get_types(Args, Ts),
+ EqEq = case {meet(Types),join(Types)} of
+ {none,any} -> true;
+ {#t_integer{},#t_integer{}} -> true;
+ {float,float} -> true;
+ {{binary,_},_} -> true;
+ {#t_atom{},_} -> true;
+ {_,_} -> false
+ end,
+ case EqEq of
+ true ->
+ simplify(I#b_set{op={bif,'=:='}}, Ts);
+ false ->
+ eval_bif(I, Ts)
+ end;
+simplify(#b_set{op={bif,'=:='},args=[Same,Same]}, _Ts) ->
+ #b_literal{val=true};
+simplify(#b_set{op={bif,'=:='},args=[A1,_A2]=Args}=I, Ts) ->
+ [T1,T2] = get_types(Args, Ts),
+ case meet(T1, T2) of
+ none ->
+ #b_literal{val=false};
+ _ ->
+ case {t_is_boolean(T1),T2} of
+ {true,#t_atom{elements=[true]}} ->
+ %% Bool =:= true ==> Bool
+ A1;
+ {_,_} ->
+ eval_bif(I, Ts)
+ end
+ end;
+simplify(#b_set{op={bif,Op},args=Args}=I, Ts) ->
+ Types = get_types(Args, Ts),
+ case is_float_op(Op, Types) of
+ false ->
+ eval_bif(I, Ts);
+ true ->
+ AnnoArgs = [anno_float_arg(A) || A <- Types],
+ eval_bif(beam_ssa:add_anno(float_op, AnnoArgs, I), Ts)
+ end;
+simplify(#b_set{op=get_tuple_element,args=[Tuple,#b_literal{val=N}]}=I, Ts) ->
+ case get_type(Tuple, Ts) of
+ #t_tuple{size=Size,elements=Es} when Size > N ->
+ ElemType = get_element_type(N + 1, Es),
+ case get_literal_from_type(ElemType) of
+ #b_literal{}=Lit -> Lit;
+ none -> I
+ end;
+ none ->
+ %% Will never be executed because of type conflict.
+ %% #b_literal{val=ignored};
+ I
+ end;
+simplify(#b_set{op=is_nonempty_list,args=[Src]}=I, Ts) ->
+ case get_type(Src, Ts) of
+ any -> I;
+ list -> I;
+ cons -> #b_literal{val=true};
+ _ -> #b_literal{val=false}
+ end;
+simplify(#b_set{op=is_tagged_tuple,
+ args=[Src,#b_literal{val=Size},#b_literal{}=Tag]}=I, Ts) ->
+ simplify_is_record(I, get_type(Src, Ts), Size, Tag, Ts);
+simplify(#b_set{op=put_list,args=[#b_literal{val=H},
+ #b_literal{val=T}]}, _Ts) ->
+ #b_literal{val=[H|T]};
+simplify(#b_set{op=put_tuple,args=Args}=I, _Ts) ->
+ case make_literal_list(Args) of
+ none -> I;
+ List -> #b_literal{val=list_to_tuple(List)}
+ end;
+simplify(#b_set{op=wait_timeout,args=[#b_literal{val=0}]}, _Ts) ->
+ #b_literal{val=true};
+simplify(#b_set{op=wait_timeout,args=[#b_literal{val=infinity}]}=I, _Ts) ->
+ I#b_set{op=wait,args=[]};
+simplify(I, _Ts) -> I.
+
+make_literal_list(Args) ->
+ make_literal_list(Args, []).
+
+make_literal_list([#b_literal{val=H}|T], Acc) ->
+ make_literal_list(T, [H|Acc]);
+make_literal_list([_|_], _) ->
+ none;
+make_literal_list([], Acc) ->
+ reverse(Acc).
+
+is_safe_bool_op(Args, Ts) ->
+ [T1,T2] = get_types(Args, Ts),
+ t_is_boolean(T1) andalso t_is_boolean(T2).
+
+all_same([{H,_}|T]) ->
+ all(fun({E,_}) -> E =:= H end, T).
+
+eval_bif(#b_set{op={bif,Bif},args=Args}=I, Ts) ->
+ Arity = length(Args),
+ case erl_bifs:is_pure(erlang, Bif, Arity) of
+ false ->
+ I;
+ true ->
+ case make_literal_list(Args) of
+ none ->
+ case get_types(Args, Ts) of
+ [any] ->
+ I;
+ [Type] ->
+ case will_succeed(Bif, Type) of
+ yes ->
+ #b_literal{val=true};
+ no ->
+ #b_literal{val=false};
+ maybe ->
+ I
+ end;
+ _ ->
+ I
+ end;
+ LitArgs ->
+ try apply(erlang, Bif, LitArgs) of
+ Val -> #b_literal{val=Val}
+ catch
+ error:_ -> I
+ end
+
+ end
+ end.
+
+simplify_args(Args, Sub, Ts) ->
+ [simplify_arg(Arg, Sub, Ts) || Arg <- Args].
+
+simplify_arg(#b_var{}=Arg0, Sub, Ts) ->
+ case sub_arg(Arg0, Sub) of
+ #b_literal{}=LitArg ->
+ LitArg;
+ #b_var{}=Arg ->
+ Type = get_type(Arg, Ts),
+ case get_literal_from_type(Type) of
+ none -> Arg;
+ #b_literal{}=Lit -> Lit
+ end
+ end;
+simplify_arg(#b_remote{mod=Mod,name=Name}=Rem, Sub, Ts) ->
+ Rem#b_remote{mod=simplify_arg(Mod, Sub, Ts),
+ name=simplify_arg(Name, Sub, Ts)};
+simplify_arg(Arg, _Sub, _Ts) -> Arg.
+
+sub_arg(#b_var{}=Old, Sub) ->
+ case Sub of
+ #{Old:=New} -> New;
+ #{} -> Old
+ end.
+
+is_float_op('-', [float]) ->
+ true;
+is_float_op('/', [_,_]) ->
+ true;
+is_float_op(Op, [float,_Other]) ->
+ is_float_op_1(Op);
+is_float_op(Op, [_Other,float]) ->
+ is_float_op_1(Op);
+is_float_op(_, _) -> false.
+
+is_float_op_1('+') -> true;
+is_float_op_1('-') -> true;
+is_float_op_1('*') -> true;
+is_float_op_1(_) -> false.
+
+anno_float_arg(float) -> float;
+anno_float_arg(_) -> convert.
+
+opt_terminator(#b_br{bool=#b_literal{}}=Br, _Ts, _Ds) ->
+ beam_ssa:normalize(Br);
+opt_terminator(#b_br{bool=#b_var{}}=Br, Ts, Ds) ->
+ simplify_not(Br, Ts, Ds);
+opt_terminator(#b_switch{arg=#b_literal{}}=Sw, _Ts, _Ds) ->
+ beam_ssa:normalize(Sw);
+opt_terminator(#b_switch{arg=#b_var{}=V}=Sw, Ts, Ds) ->
+ case get_type(V, Ts) of
+ any ->
+ beam_ssa:normalize(Sw);
+ Type ->
+ beam_ssa:normalize(opt_switch(Sw, Type, Ts, Ds))
+ end;
+opt_terminator(#b_ret{}=Ret, _Ts, _Ds) -> Ret.
+
+
+opt_switch(#b_switch{fail=Fail,list=List0}=Sw0, Type, Ts, Ds) ->
+ List = prune_switch_list(List0, Fail, Type, Ts),
+ Sw1 = Sw0#b_switch{list=List},
+ case Type of
+ #t_integer{elements={_,_}=Range} ->
+ simplify_switch_int(Sw1, Range);
+ #t_atom{elements=[_|_]} ->
+ case t_is_boolean(Type) of
+ true ->
+ #b_br{} = Br = simplify_switch_bool(Sw1, Ts, Ds),
+ opt_terminator(Br, Ts, Ds);
+ false ->
+ simplify_switch_atom(Type, Sw1)
+ end;
+ _ ->
+ Sw1
+ end.
+
+prune_switch_list([{_,Fail}|T], Fail, Type, Ts) ->
+ prune_switch_list(T, Fail, Type, Ts);
+prune_switch_list([{Arg,_}=Pair|T], Fail, Type, Ts) ->
+ case meet(get_type(Arg, Ts), Type) of
+ none ->
+ %% Different types. This value can never match.
+ prune_switch_list(T, Fail, Type, Ts);
+ _ ->
+ [Pair|prune_switch_list(T, Fail, Type, Ts)]
+ end;
+prune_switch_list([], _, _, _) -> [].
+
+update_successors(#b_br{bool=#b_literal{val=true},succ=S}, Ts, D) ->
+ update_successor(S, Ts, D);
+update_successors(#b_br{bool=#b_var{}=Bool,succ=Succ,fail=Fail}, Ts0, D0) ->
+ case cerl_sets:is_element(Bool, D0#d.once) of
+ true ->
+ %% This variable is defined in this block and is only
+ %% referenced by this br terminator. Therefore, there is
+ %% no need to include it in the type database passed on to
+ %% the successors of this block.
+ Ts = maps:remove(Bool, Ts0),
+ {SuccTs,FailTs} = infer_types_br(Bool, Ts, D0),
+ D = update_successor(Fail, FailTs, D0),
+ update_successor(Succ, SuccTs, D);
+ false ->
+ {SuccTs,FailTs} = infer_types_br(Bool, Ts0, D0),
+ D = update_successor_bool(Bool, false, Fail, FailTs, D0),
+ update_successor_bool(Bool, true, Succ, SuccTs, D)
+ end;
+update_successors(#b_switch{arg=#b_var{}=V,fail=Fail,list=List}, Ts, D0) ->
+ case cerl_sets:is_element(V, D0#d.once) of
+ true ->
+ %% This variable is defined in this block and is only
+ %% referenced by this switch terminator. Therefore, there is
+ %% no need to include it in the type database passed on to
+ %% the successors of this block.
+ D = update_successor(Fail, Ts, D0),
+ F = fun({Val,S}, A) ->
+ SuccTs0 = infer_types_switch(V, Val, Ts, D),
+ SuccTs = maps:remove(V, SuccTs0),
+ update_successor(S, SuccTs, A)
+ end,
+ foldl(F, D, List);
+ false ->
+ %% V can not be equal to any of the values in List at the fail
+ %% block.
+ FailTs = subtract_sw_list(V, List, Ts),
+ D = update_successor(Fail, FailTs, D0),
+ F = fun({Val,S}, A) ->
+ SuccTs = infer_types_switch(V, Val, Ts, D),
+ update_successor(S, SuccTs, A)
+ end,
+ foldl(F, D, List)
+ end;
+update_successors(#b_ret{arg=Arg}, Ts, D) ->
+ FuncId = D#d.func_id,
+ case D#d.ds of
+ #{ Arg := #b_set{op=call,args=[FuncId | _]} } ->
+ %% Returning a call to ourselves doesn't affect our own return
+ %% type.
+ D;
+ #{} ->
+ RetType = join([get_type(Arg, Ts) | D#d.ret_type]),
+ D#d{ret_type=[RetType]}
+ end.
+
+subtract_sw_list(V, List, Ts) ->
+ Ts#{ V := sub_sw_list_1(get_type(V, Ts), List, Ts) }.
+
+sub_sw_list_1(Type, [{Val,_}|T], Ts) ->
+ ValType = get_type(Val, Ts),
+ sub_sw_list_1(subtract(Type, ValType), T, Ts);
+sub_sw_list_1(Type, [], _Ts) ->
+ Type.
+
+update_successor_bool(#b_var{}=Var, BoolValue, S, Ts, D) ->
+ case t_is_boolean(get_type(Var, Ts)) of
+ true ->
+ update_successor(S, Ts#{Var:=t_atom(BoolValue)}, D);
+ false ->
+ %% The `br` terminator is preceeded by an instruction that
+ %% does not produce a boolean value, such a `new_try_tag`.
+ update_successor(S, Ts, D)
+ end.
+
+update_successor(?BADARG_BLOCK, _Ts, #d{}=D) ->
+ %% We KNOW that no variables are used in the ?BADARG_BLOCK,
+ %% so there is no need to update the type information. That
+ %% can be a huge timesaver for huge functions.
+ D;
+update_successor(S, Ts0, #d{ls=Ls}=D) ->
+ case Ls of
+ #{S:=Ts1} ->
+ Ts = join_types(Ts0, Ts1),
+ D#d{ls=Ls#{S:=Ts}};
+ #{} ->
+ D#d{ls=Ls#{S=>Ts0}}
+ end.
+
+update_types(#b_set{op=Op,dst=Dst,args=Args}, Ts, Ds) ->
+ T = type(Op, Args, Ts, Ds),
+ Ts#{Dst=>T}.
+
+type(phi, Args, Ts, _Ds) ->
+ Types = [get_type(A, Ts) || {A,_} <- Args],
+ join(Types);
+type({bif,'band'}, Args, Ts, _Ds) ->
+ band_type(Args, Ts);
+type({bif,Bif}, Args, Ts, _Ds) ->
+ case bif_type(Bif, Args) of
+ number ->
+ arith_op_type(Args, Ts);
+ Type ->
+ Type
+ end;
+type(bs_init, [#b_literal{val=Type}|Args], _Ts, _Ds) ->
+ case {Type,Args} of
+ {new,[_,#b_literal{val=Unit}]} ->
+ {binary,Unit};
+ {append,[_,_,#b_literal{val=Unit}]} ->
+ {binary,Unit};
+ {private_append,[_,_,#b_literal{val=Unit}]} ->
+ {binary,Unit}
+ end;
+type(bs_extract, [Ctx], Ts, _Ds) ->
+ #t_bs_match{type=Type} = get_type(Ctx, Ts),
+ Type;
+type(bs_match, Args, _Ts, _Ds) ->
+ #t_bs_match{type=bs_match_type(Args)};
+type(bs_get_tail, _Args, _Ts, _Ds) ->
+ {binary, 1};
+type(call, [#b_remote{mod=#b_literal{val=Mod},
+ name=#b_literal{val=Name}}|Args], Ts, _Ds) ->
+ case {Mod,Name,Args} of
+ {erlang,setelement,[Pos,Tuple,Arg]} ->
+ case {get_type(Pos, Ts),get_type(Tuple, Ts)} of
+ {#t_integer{elements={Index,Index}},
+ #t_tuple{elements=Es0,size=Size}=T} ->
+ %% This is an exact index, update the type of said element
+ %% or return 'none' if it's known to be out of bounds.
+ Es = set_element_type(Index, get_type(Arg, Ts), Es0),
+ case T#t_tuple.exact of
+ false ->
+ T#t_tuple{size=max(Index, Size),elements=Es};
+ true when Index =< Size ->
+ T#t_tuple{elements=Es};
+ true ->
+ none
+ end;
+ {#t_integer{elements={Min,Max}},
+ #t_tuple{elements=Es0,size=Size}=T} ->
+ %% We know this will land between Min and Max, so kill the
+ %% types for those indexes.
+ Es = maps:without(seq(Min, Max), Es0),
+ case T#t_tuple.exact of
+ false ->
+ T#t_tuple{elements=Es,size=max(Min, Size)};
+ true when Min =< Size ->
+ T#t_tuple{elements=Es,size=Size};
+ true ->
+ none
+ end;
+ {_,#t_tuple{}=T} ->
+ %% Position unknown, so we have to discard all element
+ %% information.
+ T#t_tuple{elements=#{}};
+ {#t_integer{elements={Min,_Max}},_} ->
+ #t_tuple{size=Min};
+ {_,_} ->
+ #t_tuple{}
+ end;
+ {erlang,'++',[List1,List2]} ->
+ case get_type(List1, Ts) =:= cons orelse
+ get_type(List2, Ts) =:= cons of
+ true -> cons;
+ false -> list
+ end;
+ {erlang,'--',[_,_]} ->
+ list;
+ {lists,F,Args} ->
+ Types = get_types(Args, Ts),
+ lists_function_type(F, Types);
+ {math,_,_} ->
+ case is_math_bif(Name, length(Args)) of
+ false -> any;
+ true -> float
+ end;
+ {_,_,_} ->
+ case erl_bifs:is_exit_bif(Mod, Name, length(Args)) of
+ true -> none;
+ false -> any
+ end
+ end;
+type(get_tuple_element, [Tuple, Offset], Ts, _Ds) ->
+ #t_tuple{size=Size,elements=Es} = get_type(Tuple, Ts),
+ #b_literal{val=N} = Offset,
+ true = Size > N, %Assertion.
+ get_element_type(N + 1, Es);
+type(is_nonempty_list, [_], _Ts, _Ds) ->
+ t_boolean();
+type(is_tagged_tuple, [_,#b_literal{},#b_literal{}], _Ts, _Ds) ->
+ t_boolean();
+type(put_map, _Args, _Ts, _Ds) ->
+ map;
+type(put_list, _Args, _Ts, _Ds) ->
+ cons;
+type(put_tuple, Args, Ts, _Ds) ->
+ {Es, _} = foldl(fun(Arg, {Es0, Index}) ->
+ Type = get_type(Arg, Ts),
+ Es = set_element_type(Index, Type, Es0),
+ {Es, Index + 1}
+ end, {#{}, 1}, Args),
+ #t_tuple{exact=true,size=length(Args),elements=Es};
+type(succeeded, [#b_var{}=Src], Ts, Ds) ->
+ case maps:get(Src, Ds) of
+ #b_set{op={bif,Bif},args=BifArgs} ->
+ Types = get_types(BifArgs, Ts),
+ case {Bif,Types} of
+ {BoolOp,[T1,T2]} when BoolOp =:= 'and'; BoolOp =:= 'or' ->
+ case t_is_boolean(T1) andalso t_is_boolean(T2) of
+ true -> t_atom(true);
+ false -> t_boolean()
+ end;
+ {byte_size,[{binary,_}]} ->
+ t_atom(true);
+ {bit_size,[{binary,_}]} ->
+ t_atom(true);
+ {map_size,[map]} ->
+ t_atom(true);
+ {'not',[Type]} ->
+ case t_is_boolean(Type) of
+ true -> t_atom(true);
+ false -> t_boolean()
+ end;
+ {size,[{binary,_}]} ->
+ t_atom(true);
+ {tuple_size,[#t_tuple{}]} ->
+ t_atom(true);
+ {_,_} ->
+ t_boolean()
+ end;
+ #b_set{op=get_hd} ->
+ t_atom(true);
+ #b_set{op=get_tl} ->
+ t_atom(true);
+ #b_set{op=get_tuple_element} ->
+ t_atom(true);
+ #b_set{op=wait} ->
+ t_atom(false);
+ #b_set{} ->
+ t_boolean()
+ end;
+type(succeeded, [#b_literal{}], _Ts, _Ds) ->
+ t_atom(true);
+type(_, _, _, _) -> any.
+
+arith_op_type(Args, Ts) ->
+ Types = get_types(Args, Ts),
+ foldl(fun(#t_integer{}, unknown) -> t_integer();
+ (#t_integer{}, number) -> number;
+ (#t_integer{}, float) -> float;
+ (#t_integer{}, #t_integer{}) -> t_integer();
+ (float, unknown) -> float;
+ (float, #t_integer{}) -> float;
+ (float, number) -> float;
+ (number, unknown) -> number;
+ (number, #t_integer{}) -> number;
+ (number, float) -> float;
+ (any, _) -> number;
+ (Same, Same) -> Same;
+ (_, _) -> none
+ end, unknown, Types).
+
+lists_function_type(F, Types) ->
+ case {F,Types} of
+ %% Functions that return booleans.
+ {all,[_,_]} ->
+ t_boolean();
+ {any,[_,_]} ->
+ t_boolean();
+ {keymember,[_,_,_]} ->
+ t_boolean();
+ {member,[_,_]} ->
+ t_boolean();
+ {prefix,[_,_]} ->
+ t_boolean();
+ {suffix,[_,_]} ->
+ t_boolean();
+
+ %% Functions that return lists.
+ {dropwhile,[_,_]} ->
+ list;
+ {duplicate,[_,_]} ->
+ list;
+ {filter,[_,_]} ->
+ list;
+ {flatten,[_]} ->
+ list;
+ {map,[_Fun,List]} ->
+ same_length_type(List);
+ {MapFold,[_Fun,_Acc,List]} when MapFold =:= mapfoldl;
+ MapFold =:= mapfoldr ->
+ #t_tuple{size=2,exact=true,
+ elements=#{1=>same_length_type(List)}};
+ {partition,[_,_]} ->
+ t_two_tuple(list, list);
+ {reverse,[List]} ->
+ same_length_type(List);
+ {sort,[List]} ->
+ same_length_type(List);
+ {splitwith,[_,_]} ->
+ t_two_tuple(list, list);
+ {takewhile,[_,_]} ->
+ list;
+ {unzip,[List]} ->
+ ListType = same_length_type(List),
+ t_two_tuple(ListType, ListType);
+ {usort,[List]} ->
+ same_length_type(List);
+ {zip,[_,_]} ->
+ list;
+ {zipwith,[_,_,_]} ->
+ list;
+ {_,_} ->
+ any
+ end.
+
+%% For a lists function that return a list of the same
+%% length as the input list, return the type of the list.
+same_length_type(cons) -> cons;
+same_length_type(nil) -> nil;
+same_length_type(_) -> list.
+
+t_two_tuple(Type1, Type2) ->
+ #t_tuple{size=2,exact=true,
+ elements=#{1=>Type1,2=>Type2}}.
+
+%% will_succeed(TestOperation, Type) -> yes|no|maybe.
+%% Test whether TestOperation applied to an argument of type Type
+%% will succeed. Return yes, no, or maybe.
+%%
+%% Type is a type as described in the comment for verified_type/1 at
+%% the very end of this file, but it will *never* be 'any'.
+
+will_succeed(is_atom, Type) ->
+ case Type of
+ #t_atom{} -> yes;
+ _ -> no
+ end;
+will_succeed(is_binary, Type) ->
+ case Type of
+ {binary,U} when U rem 8 =:= 0 -> yes;
+ {binary,_} -> maybe;
+ _ -> no
+ end;
+will_succeed(is_bitstring, Type) ->
+ case Type of
+ {binary,_} -> yes;
+ _ -> no
+ end;
+will_succeed(is_boolean, Type) ->
+ case Type of
+ #t_atom{elements=any} ->
+ maybe;
+ #t_atom{elements=Es} ->
+ case t_is_boolean(Type) of
+ true ->
+ yes;
+ false ->
+ case any(fun is_boolean/1, Es) of
+ true -> maybe;
+ false -> no
+ end
+ end;
+ _ ->
+ no
+ end;
+will_succeed(is_float, Type) ->
+ case Type of
+ float -> yes;
+ number -> maybe;
+ _ -> no
+ end;
+will_succeed(is_integer, Type) ->
+ case Type of
+ #t_integer{} -> yes;
+ number -> maybe;
+ _ -> no
+ end;
+will_succeed(is_list, Type) ->
+ case Type of
+ list -> yes;
+ cons -> yes;
+ _ -> no
+ end;
+will_succeed(is_map, Type) ->
+ case Type of
+ map -> yes;
+ _ -> no
+ end;
+will_succeed(is_number, Type) ->
+ case Type of
+ float -> yes;
+ #t_integer{} -> yes;
+ number -> yes;
+ _ -> no
+ end;
+will_succeed(is_tuple, Type) ->
+ case Type of
+ #t_tuple{} -> yes;
+ _ -> no
+ end;
+will_succeed(_, _) -> maybe.
+
+
+band_type([Other,#b_literal{val=Int}], Ts) when is_integer(Int) ->
+ band_type_1(Int, Other, Ts);
+band_type([_,_], _) -> t_integer().
+
+band_type_1(Int, OtherSrc, Ts) ->
+ Type = band_type_2(Int, 0),
+ OtherType = get_type(OtherSrc, Ts),
+ meet(Type, OtherType).
+
+band_type_2(N, Bits) when Bits < 64 ->
+ case 1 bsl Bits of
+ P when P =:= N + 1 ->
+ t_integer(0, N);
+ P when P > N + 1 ->
+ t_integer();
+ _ ->
+ band_type_2(N, Bits+1)
+ end;
+band_type_2(_, _) ->
+ %% Negative or large positive number. Give up.
+ t_integer().
+
+bs_match_type([#b_literal{val=Type}|Args]) ->
+ bs_match_type(Type, Args).
+
+bs_match_type(binary, Args) ->
+ [_,_,_,#b_literal{val=U}] = Args,
+ {binary,U};
+bs_match_type(float, _) ->
+ float;
+bs_match_type(integer, Args) ->
+ case Args of
+ [_,
+ #b_literal{val=Flags},
+ #b_literal{val=Size},
+ #b_literal{val=Unit}] when Size * Unit < 64 ->
+ NumBits = Size * Unit,
+ case member(unsigned, Flags) of
+ true ->
+ t_integer(0, (1 bsl NumBits)-1);
+ false ->
+ %% Signed integer. Don't bother.
+ t_integer()
+ end;
+ [_|_] ->
+ t_integer()
+ end;
+bs_match_type(skip, _) ->
+ any;
+bs_match_type(string, _) ->
+ any;
+bs_match_type(utf8, _) ->
+ ?UNICODE_INT;
+bs_match_type(utf16, _) ->
+ ?UNICODE_INT;
+bs_match_type(utf32, _) ->
+ ?UNICODE_INT.
+
+simplify_switch_atom(#t_atom{elements=Atoms}, #b_switch{list=List0}=Sw) ->
+ case sort([A || {#b_literal{val=A},_} <- List0]) of
+ Atoms ->
+ %% All possible atoms are included in the list. The
+ %% failure label will never be used.
+ [{_,Fail}|List] = List0,
+ Sw#b_switch{fail=Fail,list=List};
+ _ ->
+ Sw
+ end.
+
+simplify_switch_int(#b_switch{list=List0}=Sw, {Min,Max}) ->
+ List1 = sort(List0),
+ Vs = [V || {#b_literal{val=V},_} <- List1],
+ case eq_ranges(Vs, Min, Max) of
+ true ->
+ {_,LastL} = last(List1),
+ List = droplast(List1),
+ Sw#b_switch{fail=LastL,list=List};
+ false ->
+ Sw
+ end.
+
+eq_ranges([H], H, H) -> true;
+eq_ranges([H|T], H, Max) -> eq_ranges(T, H+1, Max);
+eq_ranges(_, _, _) -> false.
+
+simplify_is_record(I, #t_tuple{exact=Exact,
+ size=Size,
+ elements=Es},
+ RecSize, RecTag, Ts) ->
+ TagType = maps:get(1, Es, any),
+ TagMatch = case get_literal_from_type(TagType) of
+ #b_literal{}=RecTag -> yes;
+ #b_literal{} -> no;
+ none ->
+ %% Is it at all possible for the tag to match?
+ case meet(get_type(RecTag, Ts), TagType) of
+ none -> no;
+ _ -> maybe
+ end
+ end,
+ if
+ Size =/= RecSize, Exact; Size > RecSize; TagMatch =:= no ->
+ #b_literal{val=false};
+ Size =:= RecSize, Exact, TagMatch =:= yes ->
+ #b_literal{val=true};
+ true ->
+ I
+ end;
+simplify_is_record(I, any, _Size, _Tag, _Ts) ->
+ I;
+simplify_is_record(_I, _Type, _Size, _Tag, _Ts) ->
+ #b_literal{val=false}.
+
+simplify_switch_bool(#b_switch{arg=B,fail=Fail,list=List0}, Ts, Ds) ->
+ FalseVal = #b_literal{val=false},
+ TrueVal = #b_literal{val=true},
+ List1 = List0 ++ [{FalseVal,Fail},{TrueVal,Fail}],
+ {_,FalseLbl} = keyfind(FalseVal, 1, List1),
+ {_,TrueLbl} = keyfind(TrueVal, 1, List1),
+ Br = beam_ssa:normalize(#b_br{bool=B,succ=TrueLbl,fail=FalseLbl}),
+ simplify_not(Br, Ts, Ds).
+
+simplify_not(#b_br{bool=#b_var{}=V,succ=Succ,fail=Fail}=Br0, Ts, Ds) ->
+ case Ds of
+ #{V:=#b_set{op={bif,'not'},args=[Bool]}} ->
+ case t_is_boolean(get_type(Bool, Ts)) of
+ true ->
+ Br = Br0#b_br{bool=Bool,succ=Fail,fail=Succ},
+ beam_ssa:normalize(Br);
+ false ->
+ Br0
+ end;
+ #{} ->
+ Br0
+ end;
+simplify_not(#b_br{bool=#b_literal{}}=Br, _Ts, _Ds) -> Br.
+
+%%%
+%%% Calculate the set of variables that are only used once in the
+%%% terminator of the block that defines them. That will allow us to
+%%% discard type information for variables that will never be
+%%% referenced by the successor blocks, potentially improving
+%%% compilation times.
+%%%
+
+used_once(Linear, Args) ->
+ Map0 = used_once_1(reverse(Linear), #{}),
+ Map = maps:without(Args, Map0),
+ cerl_sets:from_list(maps:keys(Map)).
+
+used_once_1([{L,#b_blk{is=Is,last=Last}}|Bs], Uses0) ->
+ Uses1 = used_once_last_uses(beam_ssa:used(Last), L, Uses0),
+ Uses = used_once_2(reverse(Is), L, Uses1),
+ used_once_1(Bs, Uses);
+used_once_1([], Uses) -> Uses.
+
+used_once_2([#b_set{dst=Dst}=I|Is], L, Uses0) ->
+ Uses = used_once_uses(beam_ssa:used(I), L, Uses0),
+ case Uses of
+ #{Dst:=[L]} ->
+ used_once_2(Is, L, Uses);
+ #{} ->
+ %% Used more than once or used once in
+ %% in another block.
+ used_once_2(Is, L, maps:remove(Dst, Uses))
+ end;
+used_once_2([], _, Uses) -> Uses.
+
+used_once_uses([V|Vs], L, Uses) ->
+ case Uses of
+ #{V:=more_than_once} ->
+ used_once_uses(Vs, L, Uses);
+ #{} ->
+ %% Already used or first use is not in
+ %% a terminator.
+ used_once_uses(Vs, L, Uses#{V=>more_than_once})
+ end;
+used_once_uses([], _, Uses) -> Uses.
+
+used_once_last_uses([V|Vs], L, Uses) ->
+ case Uses of
+ #{V:=[_]} ->
+ %% Second time this variable is used.
+ used_once_last_uses(Vs, L, Uses#{V:=more_than_once});
+ #{V:=more_than_once} ->
+ %% Used at least twice before.
+ used_once_last_uses(Vs, L, Uses);
+ #{} ->
+ %% First time this variable is used.
+ used_once_last_uses(Vs, L, Uses#{V=>[L]})
+ end;
+used_once_last_uses([], _, Uses) -> Uses.
+
+
+get_types(Values, Ts) ->
+ [get_type(Val, Ts) || Val <- Values].
+-spec get_type(beam_ssa:value(), type_db()) -> type().
+
+get_type(#b_var{}=V, Ts) ->
+ #{V:=T} = Ts,
+ T;
+get_type(#b_literal{val=Val}, _Ts) ->
+ if
+ is_atom(Val) ->
+ t_atom(Val);
+ is_float(Val) ->
+ float;
+ is_integer(Val) ->
+ t_integer(Val);
+ is_list(Val), Val =/= [] ->
+ cons;
+ is_map(Val) ->
+ map;
+ Val =:= {} ->
+ #t_tuple{exact=true};
+ is_tuple(Val) ->
+ {Es, _} = foldl(fun(E, {Es0, Index}) ->
+ Type = get_type(#b_literal{val=E}, #{}),
+ Es = set_element_type(Index, Type, Es0),
+ {Es, Index + 1}
+ end, {#{}, 1}, tuple_to_list(Val)),
+ #t_tuple{exact=true,size=tuple_size(Val),elements=Es};
+ Val =:= [] ->
+ nil;
+ true ->
+ any
+ end.
+
+%% infer_types(Var, Types, #d{}) -> {SuccTypes,FailTypes}
+%% Looking at the expression that defines the variable Var, infer
+%% the types for the variables in the arguments. Return the updated
+%% type database for the case that the expression evaluates to
+%% true, and and for the case that it evaluates to false.
+%%
+%% Here is an example. The variable being asked about is
+%% the variable Bool, which is defined like this:
+%%
+%% Bool = is_nonempty_list L
+%%
+%% If 'is_nonempty_list L' evaluates to 'true', L must
+%% must be cons. The meet of the previously known type of L and 'cons'
+%% will be added to SuccTypes.
+%%
+%% On the other hand, if 'is_nonempty_list L' evaluates to false, L
+%% is not cons and cons can be subtracted from the previously known
+%% type for L. For example, if L was known to be 'list', subtracting
+%% 'cons' would give 'nil' as the only possible type. The result of the
+%% subtraction for L will be added to FailTypes.
+%%
+%% Here is another example, asking about the variable Bool:
+%%
+%% Head = bif:hd L
+%% Bool = succeeded Head
+%%
+%% 'succeeded Head' will evaluate to 'true' if the instrution that
+%% defined Head succeeded. In this case, it is the 'bif:hd L'
+%% instruction, which will succeed if L is 'cons'. Thus, the meet of
+%% the previous type for L and 'cons' will be added to SuccTypes.
+%%
+%% If 'succeeded Head' evaluates to 'false', it means that 'bif:hd L'
+%% failed and that L is not 'cons'. 'cons' can be subtracted from the
+%% previously known type for L and the result put in FailTypes.
+
+infer_types_br(#b_var{}=V, Ts, #d{ds=Ds}) ->
+ #{V:=#b_set{op=Op,args=Args}} = Ds,
+ Types0 = infer_type(Op, Args, Ds),
+
+ %% We must be careful with types inferred from '=:='.
+ %%
+ %% If we have seen L =:= [a], we know that L is 'cons' if the
+ %% comparison succeeds. However, if the comparison fails, L could
+ %% still be 'cons'. Therefore, we must not subtract 'cons' from the
+ %% previous type of L.
+ %%
+ %% However, it is safe to subtract a type inferred from '=:=' if
+ %% it is single-valued, e.g. if it is [] or the atom 'true'.
+ EqTypes0 = infer_eq_type(Op, Args, Ts, Ds),
+ {Types1,EqTypes} = partition(fun({_,T}) ->
+ is_singleton_type(T)
+ end, EqTypes0),
+
+ Types = Types1 ++ Types0,
+ {meet_types(EqTypes++Types, Ts),subtract_types(Types, Ts)}.
+
+infer_types_switch(V, Lit, Ts, #d{ds=Ds}) ->
+ Types = infer_eq_type({bif,'=:='}, [V, Lit], Ts, Ds),
+ meet_types(Types, Ts).
+
+infer_eq_type({bif,'=:='}, [#b_var{}=Src,#b_literal{}=Lit], Ts, Ds) ->
+ Def = maps:get(Src, Ds),
+ Type = get_type(Lit, Ts),
+ [{Src,Type} | infer_eq_lit(Def, Lit)];
+infer_eq_type({bif,'=:='}, [#b_var{}=Arg0,#b_var{}=Arg1], Ts, _Ds) ->
+ %% As an example, assume that L1 is known to be 'list', and L2 is
+ %% known to be 'cons'. Then if 'L1 =:= L2' evaluates to 'true', it can
+ %% be inferred that L1 is 'cons' (the meet of 'cons' and 'list').
+ Type0 = get_type(Arg0, Ts),
+ Type1 = get_type(Arg1, Ts),
+ Type = meet(Type0, Type1),
+ [{V,MeetType} ||
+ {V,OrigType,MeetType} <-
+ [{Arg0,Type0,Type},{Arg1,Type1,Type}],
+ OrigType =/= MeetType];
+infer_eq_type(_Op, _Args, _Ts, _Ds) ->
+ [].
+
+infer_eq_lit(#b_set{op={bif,tuple_size},args=[#b_var{}=Tuple]},
+ #b_literal{val=Size}) when is_integer(Size) ->
+ [{Tuple,#t_tuple{exact=true,size=Size}}];
+infer_eq_lit(#b_set{op=get_tuple_element,
+ args=[#b_var{}=Tuple,#b_literal{val=N}]},
+ #b_literal{}=Lit) ->
+ Index = N + 1,
+ Es = set_element_type(Index, get_type(Lit, #{}), #{}),
+ [{Tuple,#t_tuple{size=Index,elements=Es}}];
+infer_eq_lit(_, _) -> [].
+
+infer_type({bif,element}, [#b_literal{val=Pos},#b_var{}=Tuple], _Ds) ->
+ if
+ is_integer(Pos), 1 =< Pos ->
+ [{Tuple,#t_tuple{size=Pos}}];
+ true ->
+ []
+ end;
+infer_type({bif,element}, [#b_var{}=Position,#b_var{}=Tuple], _Ds) ->
+ [{Position,t_integer()},{Tuple,#t_tuple{}}];
+infer_type({bif,Bif}, [#b_var{}=Src]=Args, _Ds) ->
+ case inferred_bif_type(Bif, Args) of
+ any -> [];
+ T -> [{Src,T}]
+ end;
+infer_type({bif,binary_part}, [#b_var{}=Src,_], _Ds) ->
+ [{Src,{binary,8}}];
+infer_type({bif,is_map_key}, [_,#b_var{}=Src], _Ds) ->
+ [{Src,map}];
+infer_type({bif,map_get}, [_,#b_var{}=Src], _Ds) ->
+ [{Src,map}];
+infer_type({bif,Bif}, [_,_]=Args, _Ds) ->
+ case inferred_bif_type(Bif, Args) of
+ any -> [];
+ T -> [{A,T} || #b_var{}=A <- Args]
+ end;
+infer_type({bif,binary_part}, [#b_var{}=Src,Pos,Len], _Ds) ->
+ [{Src,{binary,8}}|
+ [{V,t_integer()} || #b_var{}=V <- [Pos,Len]]];
+infer_type(bs_start_match, [#b_var{}=Bin], _Ds) ->
+ [{Bin,{binary,1}}];
+infer_type(is_nonempty_list, [#b_var{}=Src], _Ds) ->
+ [{Src,cons}];
+infer_type(is_tagged_tuple, [#b_var{}=Src,#b_literal{val=Size},
+ #b_literal{}=Tag], _Ds) ->
+ Es = set_element_type(1, get_type(Tag, #{}), #{}),
+ [{Src,#t_tuple{exact=true,size=Size,elements=Es}}];
+infer_type(succeeded, [#b_var{}=Src], Ds) ->
+ #b_set{op=Op,args=Args} = maps:get(Src, Ds),
+ infer_type(Op, Args, Ds);
+infer_type(_Op, _Args, _Ds) ->
+ [].
+
+%% bif_type(Name, Args) -> Type
+%% Return the return type for the guard BIF or operator Name with
+%% arguments Args.
+%%
+%% Note that that the following BIFs are handle elsewhere:
+%%
+%% band/2
+
+bif_type(abs, [_]) -> number;
+bif_type(bit_size, [_]) -> t_integer();
+bif_type(byte_size, [_]) -> t_integer();
+bif_type(ceil, [_]) -> t_integer();
+bif_type(float, [_]) -> float;
+bif_type(floor, [_]) -> t_integer();
+bif_type(is_map_key, [_,_]) -> t_boolean();
+bif_type(length, [_]) -> t_integer();
+bif_type(map_size, [_]) -> t_integer();
+bif_type(node, []) -> #t_atom{};
+bif_type(node, [_]) -> #t_atom{};
+bif_type(round, [_]) -> t_integer();
+bif_type(size, [_]) -> t_integer();
+bif_type(trunc, [_]) -> t_integer();
+bif_type(tuple_size, [_]) -> t_integer();
+bif_type('bnot', [_]) -> t_integer();
+bif_type('bor', [_,_]) -> t_integer();
+bif_type('bsl', [_,_]) -> t_integer();
+bif_type('bsr', [_,_]) -> t_integer();
+bif_type('bxor', [_,_]) -> t_integer();
+bif_type('div', [_,_]) -> t_integer();
+bif_type('rem', [_,_]) -> t_integer();
+bif_type('/', [_,_]) -> float;
+bif_type(Name, Args) ->
+ Arity = length(Args),
+ case erl_internal:new_type_test(Name, Arity) orelse
+ erl_internal:bool_op(Name, Arity) orelse
+ erl_internal:comp_op(Name, Arity) of
+ true ->
+ t_boolean();
+ false ->
+ case erl_internal:arith_op(Name, Arity) of
+ true -> number;
+ false -> any
+ end
+ end.
+
+inferred_bif_type(is_atom, [_]) -> t_atom();
+inferred_bif_type(is_binary, [_]) -> {binary,8};
+inferred_bif_type(is_bitstring, [_]) -> {binary,1};
+inferred_bif_type(is_boolean, [_]) -> t_boolean();
+inferred_bif_type(is_float, [_]) -> float;
+inferred_bif_type(is_integer, [_]) -> t_integer();
+inferred_bif_type(is_list, [_]) -> list;
+inferred_bif_type(is_map, [_]) -> map;
+inferred_bif_type(is_number, [_]) -> number;
+inferred_bif_type(is_tuple, [_]) -> #t_tuple{};
+inferred_bif_type(abs, [_]) -> number;
+inferred_bif_type(bit_size, [_]) -> {binary,1};
+inferred_bif_type('bnot', [_]) -> t_integer();
+inferred_bif_type(byte_size, [_]) -> {binary,1};
+inferred_bif_type(ceil, [_]) -> number;
+inferred_bif_type(float, [_]) -> number;
+inferred_bif_type(floor, [_]) -> number;
+inferred_bif_type(hd, [_]) -> cons;
+inferred_bif_type(length, [_]) -> list;
+inferred_bif_type(map_size, [_]) -> map;
+inferred_bif_type('not', [_]) -> t_boolean();
+inferred_bif_type(round, [_]) -> number;
+inferred_bif_type(trunc, [_]) -> number;
+inferred_bif_type(tl, [_]) -> cons;
+inferred_bif_type(tuple_size, [_]) -> #t_tuple{};
+inferred_bif_type('and', [_,_]) -> t_boolean();
+inferred_bif_type('or', [_,_]) -> t_boolean();
+inferred_bif_type('xor', [_,_]) -> t_boolean();
+inferred_bif_type('band', [_,_]) -> t_integer();
+inferred_bif_type('bor', [_,_]) -> t_integer();
+inferred_bif_type('bsl', [_,_]) -> t_integer();
+inferred_bif_type('bsr', [_,_]) -> t_integer();
+inferred_bif_type('bxor', [_,_]) -> t_integer();
+inferred_bif_type('div', [_,_]) -> t_integer();
+inferred_bif_type('rem', [_,_]) -> t_integer();
+inferred_bif_type('+', [_,_]) -> number;
+inferred_bif_type('-', [_,_]) -> number;
+inferred_bif_type('*', [_,_]) -> number;
+inferred_bif_type('/', [_,_]) -> number;
+inferred_bif_type(_, _) -> any.
+
+is_math_bif(cos, 1) -> true;
+is_math_bif(cosh, 1) -> true;
+is_math_bif(sin, 1) -> true;
+is_math_bif(sinh, 1) -> true;
+is_math_bif(tan, 1) -> true;
+is_math_bif(tanh, 1) -> true;
+is_math_bif(acos, 1) -> true;
+is_math_bif(acosh, 1) -> true;
+is_math_bif(asin, 1) -> true;
+is_math_bif(asinh, 1) -> true;
+is_math_bif(atan, 1) -> true;
+is_math_bif(atanh, 1) -> true;
+is_math_bif(erf, 1) -> true;
+is_math_bif(erfc, 1) -> true;
+is_math_bif(exp, 1) -> true;
+is_math_bif(log, 1) -> true;
+is_math_bif(log2, 1) -> true;
+is_math_bif(log10, 1) -> true;
+is_math_bif(sqrt, 1) -> true;
+is_math_bif(atan2, 2) -> true;
+is_math_bif(pow, 2) -> true;
+is_math_bif(ceil, 1) -> true;
+is_math_bif(floor, 1) -> true;
+is_math_bif(fmod, 2) -> true;
+is_math_bif(pi, 0) -> true;
+is_math_bif(_, _) -> false.
+
+join_types(Ts0, Ts1) ->
+ if
+ map_size(Ts0) < map_size(Ts1) ->
+ join_types_1(maps:keys(Ts0), Ts1, Ts0);
+ true ->
+ join_types_1(maps:keys(Ts1), Ts0, Ts1)
+ end.
+
+join_types_1([V|Vs], Ts0, Ts1) ->
+ case {Ts0,Ts1} of
+ {#{V:=Same},#{V:=Same}} ->
+ join_types_1(Vs, Ts0, Ts1);
+ {#{V:=T0},#{V:=T1}} ->
+ case join(T0, T1) of
+ T1 ->
+ join_types_1(Vs, Ts0, Ts1);
+ T ->
+ join_types_1(Vs, Ts0, Ts1#{V:=T})
+ end;
+ {#{},#{V:=_}} ->
+ join_types_1(Vs, Ts0, Ts1)
+ end;
+join_types_1([], Ts0, Ts1) ->
+ maps:merge(Ts0, Ts1).
+
+join([T1,T2|Ts]) ->
+ join([join(T1, T2)|Ts]);
+join([T]) -> T.
+
+get_literal_from_type(#t_atom{elements=[Atom]}) ->
+ #b_literal{val=Atom};
+get_literal_from_type(#t_integer{elements={Int,Int}}) ->
+ #b_literal{val=Int};
+get_literal_from_type(nil) ->
+ #b_literal{val=[]};
+get_literal_from_type(_) -> none.
+
+t_atom() ->
+ #t_atom{elements=any}.
+
+t_atom(Atom) when is_atom(Atom) ->
+ #t_atom{elements=[Atom]}.
+
+t_boolean() ->
+ #t_atom{elements=[false,true]}.
+
+t_integer() ->
+ #t_integer{elements=any}.
+
+t_integer(Int) when is_integer(Int) ->
+ #t_integer{elements={Int,Int}}.
+
+t_integer(Min, Max) when is_integer(Min), is_integer(Max) ->
+ #t_integer{elements={Min,Max}}.
+
+t_is_boolean(#t_atom{elements=[F,T]}) ->
+ F =:= false andalso T =:= true;
+t_is_boolean(#t_atom{elements=[B]}) ->
+ is_boolean(B);
+t_is_boolean(_) -> false.
+
+t_tuple_size(#t_tuple{size=Size,exact=false}) ->
+ {at_least,Size};
+t_tuple_size(#t_tuple{size=Size,exact=true}) ->
+ {exact,Size};
+t_tuple_size(_) ->
+ none.
+
+is_singleton_type(Type) ->
+ get_literal_from_type(Type) =/= none.
+
+get_element_type(Index, Es) ->
+ case Es of
+ #{ Index := T } -> T;
+ #{} -> any
+ end.
+
+set_element_type(_Key, none, Es) ->
+ Es;
+set_element_type(Key, any, Es) ->
+ maps:remove(Key, Es);
+set_element_type(Key, Type, Es) ->
+ Es#{ Key => Type }.
+
+%% join(Type1, Type2) -> Type
+%% Return the "join" of Type1 and Type2. The join is a more general
+%% type than Type1 and Type2. For example:
+%%
+%% join(#t_integer{elements=any}, #t_integer=elements={0,3}}) ->
+%% #t_integer{}
+%%
+%% The join for two different types result in 'any', which is
+%% the top element for our type lattice:
+%%
+%% join(#t_integer{}, map) -> any
+
+-spec join(type(), type()) -> type().
+
+join(T, T) ->
+ verified_type(T);
+join(none, T) ->
+ verified_type(T);
+join(T, none) ->
+ verified_type(T);
+join(any, _) -> any;
+join(_, any) -> any;
+join(#t_atom{elements=[_|_]=Set1}, #t_atom{elements=[_|_]=Set2}) ->
+ Set = ordsets:union(Set1, Set2),
+ case ordsets:size(Set) of
+ Size when Size =< ?ATOM_SET_SIZE ->
+ #t_atom{elements=Set};
+ _Size ->
+ #t_atom{elements=any}
+ end;
+join(#t_atom{elements=any}=T, #t_atom{elements=[_|_]}) -> T;
+join(#t_atom{elements=[_|_]}, #t_atom{elements=any}=T) -> T;
+join({binary,U1}, {binary,U2}) ->
+ {binary,gcd(U1, U2)};
+join(#t_integer{}, #t_integer{}) -> t_integer();
+join(list, cons) -> list;
+join(cons, list) -> list;
+join(nil, cons) -> list;
+join(cons, nil) -> list;
+join(nil, list) -> list;
+join(list, nil) -> list;
+join(#t_integer{}, float) -> number;
+join(float, #t_integer{}) -> number;
+join(#t_integer{}, number) -> number;
+join(number, #t_integer{}) -> number;
+join(float, number) -> number;
+join(number, float) -> number;
+join(#t_tuple{size=Sz,exact=ExactA,elements=EsA},
+ #t_tuple{size=Sz,exact=ExactB,elements=EsB}) ->
+ Exact = ExactA and ExactB,
+ Es = join_tuple_elements(Sz, EsA, EsB),
+ #t_tuple{size=Sz,exact=Exact,elements=Es};
+join(#t_tuple{size=SzA,elements=EsA}, #t_tuple{size=SzB,elements=EsB}) ->
+ Sz = min(SzA, SzB),
+ Es = join_tuple_elements(Sz, EsA, EsB),
+ #t_tuple{size=Sz,elements=Es};
+join(_T1, _T2) ->
+ %%io:format("~p ~p\n", [_T1,_T2]),
+ any.
+
+join_tuple_elements(MinSize, EsA, EsB) ->
+ Es0 = join_elements(EsA, EsB),
+ maps:filter(fun(Index, _Type) -> Index =< MinSize end, Es0).
+
+join_elements(Es1, Es2) ->
+ Keys = if
+ map_size(Es1) =< map_size(Es2) -> maps:keys(Es1);
+ map_size(Es1) > map_size(Es2) -> maps:keys(Es2)
+ end,
+ join_elements_1(Keys, Es1, Es2, #{}).
+
+join_elements_1([Key | Keys], Es1, Es2, Acc0) ->
+ case {Es1, Es2} of
+ {#{ Key := Type1 }, #{ Key := Type2 }} ->
+ Acc = set_element_type(Key, join(Type1, Type2), Acc0),
+ join_elements_1(Keys, Es1, Es2, Acc);
+ {#{}, #{}} ->
+ join_elements_1(Keys, Es1, Es2, Acc0)
+ end;
+join_elements_1([], _Es1, _Es2, Acc) ->
+ Acc.
+
+gcd(A, B) ->
+ case A rem B of
+ 0 -> B;
+ X -> gcd(B, X)
+ end.
+
+meet_types([{V,T0}|Vs], Ts) ->
+ #{V:=T1} = Ts,
+ case meet(T0, T1) of
+ T1 -> meet_types(Vs, Ts);
+ T -> meet_types(Vs, Ts#{V:=T})
+ end;
+meet_types([], Ts) -> Ts.
+
+meet([T1,T2|Ts]) ->
+ meet([meet(T1, T2)|Ts]);
+meet([T]) -> T.
+
+subtract_types([{V,T0}|Vs], Ts) ->
+ #{V:=T1} = Ts,
+ case subtract(T1, T0) of
+ T1 -> subtract_types(Vs, Ts);
+ T -> subtract_types(Vs, Ts#{V:=T})
+ end;
+subtract_types([], Ts) -> Ts.
+
+%% subtract(Type1, Type2) -> Type.
+%% Subtract Type2 from Type1. Example:
+%%
+%% subtract(list, cons) -> nil
+
+subtract(#t_atom{elements=[_|_]=Set0}, #t_atom{elements=[_|_]=Set1}) ->
+ case ordsets:subtract(Set0, Set1) of
+ [] -> none;
+ [_|_]=Set -> #t_atom{elements=Set}
+ end;
+subtract(number, float) -> #t_integer{};
+subtract(number, #t_integer{elements=any}) -> float;
+subtract(list, cons) -> nil;
+subtract(list, nil) -> cons;
+subtract(T, _) -> T.
+
+%% meet(Type1, Type2) -> Type
+%% Return the "meet" of Type1 and Type2. The meet is a narrower
+%% type than Type1 and Type2. For example:
+%%
+%% meet(#t_integer{elements=any}, #t_integer{elements={0,3}}) ->
+%% #t_integer{elements={0,3}}
+%%
+%% The meet for two different types result in 'none', which is
+%% the bottom element for our type lattice:
+%%
+%% meet(#t_integer{}, map) -> none
+
+-spec meet(type(), type()) -> type().
+
+meet(T, T) ->
+ verified_type(T);
+meet(#t_atom{elements=[_|_]=Set1}, #t_atom{elements=[_|_]=Set2}) ->
+ case ordsets:intersection(Set1, Set2) of
+ [] ->
+ none;
+ [_|_]=Set ->
+ #t_atom{elements=Set}
+ end;
+meet(#t_atom{elements=[_|_]}=T, #t_atom{elements=any}) ->
+ T;
+meet(#t_atom{elements=any}, #t_atom{elements=[_|_]}=T) ->
+ T;
+meet(#t_integer{elements={_,_}}=T, #t_integer{elements=any}) ->
+ T;
+meet(#t_integer{elements=any}, #t_integer{elements={_,_}}=T) ->
+ T;
+meet(#t_integer{elements={Min1,Max1}},
+ #t_integer{elements={Min2,Max2}}) ->
+ #t_integer{elements={max(Min1, Min2),min(Max1, Max2)}};
+meet(#t_integer{}=T, number) -> T;
+meet(float=T, number) -> T;
+meet(number, #t_integer{}=T) -> T;
+meet(number, float=T) -> T;
+meet(list, cons) -> cons;
+meet(list, nil) -> nil;
+meet(cons, list) -> cons;
+meet(nil, list) -> nil;
+meet(#t_tuple{}=T1, #t_tuple{}=T2) ->
+ meet_tuples(T1, T2);
+meet({binary,U1}, {binary,U2}) ->
+ {binary,max(U1, U2)};
+meet(any, T) ->
+ verified_type(T);
+meet(T, any) ->
+ verified_type(T);
+meet(_, _) ->
+ %% Inconsistent types. There will be an exception at runtime.
+ none.
+
+meet_tuples(#t_tuple{size=Sz1,exact=true},
+ #t_tuple{size=Sz2,exact=true}) when Sz1 =/= Sz2 ->
+ none;
+meet_tuples(#t_tuple{size=Sz1,exact=Ex1,elements=Es1},
+ #t_tuple{size=Sz2,exact=Ex2,elements=Es2}) ->
+ Size = max(Sz1, Sz2),
+ Exact = Ex1 or Ex2,
+ case meet_elements(Es1, Es2) of
+ none ->
+ none;
+ Es ->
+ #t_tuple{size=Size,exact=Exact,elements=Es}
+ end.
+
+meet_elements(Es1, Es2) ->
+ Keys = maps:keys(Es1) ++ maps:keys(Es2),
+ meet_elements_1(Keys, Es1, Es2, #{}).
+
+meet_elements_1([Key | Keys], Es1, Es2, Acc) ->
+ case {Es1, Es2} of
+ {#{ Key := Type1 }, #{ Key := Type2 }} ->
+ case meet(Type1, Type2) of
+ none -> none;
+ Type -> meet_elements_1(Keys, Es1, Es2, Acc#{ Key => Type })
+ end;
+ {#{ Key := Type1 }, _} ->
+ meet_elements_1(Keys, Es1, Es2, Acc#{ Key => Type1 });
+ {_, #{ Key := Type2 }} ->
+ meet_elements_1(Keys, Es1, Es2, Acc#{ Key => Type2 })
+ end;
+meet_elements_1([], _Es1, _Es2, Acc) ->
+ Acc.
+
+%% verified_type(Type) -> Type
+%% Returns the passed in type if it is one of the defined types.
+%% Crashes if there is anything wrong with the type.
+%%
+%% Here are all possible types:
+%%
+%% any Any Erlang term (top element for the type lattice).
+%%
+%% #t_atom{} Any atom or some specific atoms.
+%% {binary,Unit} Binary/bitstring aligned to unit Unit.
+%% float Floating point number.
+%% #t_integer{} Integer
+%% list Empty or nonempty list.
+%% map Map.
+%% nil Empty list.
+%% cons Cons (nonempty list).
+%% number A number (float or integer).
+%% #t_tuple{} Tuple.
+%%
+%% none No type (bottom element for the type lattice).
+
+-spec verified_type(T) -> T when
+ T :: type().
+
+verified_type(any=T) -> T;
+verified_type(none=T) -> T;
+verified_type(#t_atom{elements=any}=T) -> T;
+verified_type(#t_atom{elements=[_|_]}=T) -> T;
+verified_type({binary,U}=T) when is_integer(U) -> T;
+verified_type(#t_integer{elements=any}=T) -> T;
+verified_type(#t_integer{elements={Min,Max}}=T)
+ when is_integer(Min), is_integer(Max) -> T;
+verified_type(list=T) -> T;
+verified_type(map=T) -> T;
+verified_type(nil=T) -> T;
+verified_type(cons=T) -> T;
+verified_type(number=T) -> T;
+verified_type(#t_tuple{size=Size,elements=Es}=T) ->
+ %% All known elements must have a valid index and type. 'any' is prohibited
+ %% since it's implicit and should never be present in the map.
+ maps:fold(fun(Index, Element, _) when is_integer(Index),
+ 1 =< Index, Index =< Size,
+ Element =/= any, Element =/= none ->
+ verified_type(Element)
+ end, [], Es),
+ T;
+verified_type(float=T) -> T.
diff --git a/lib/compiler/src/beam_trim.erl b/lib/compiler/src/beam_trim.erl
index 4da0985085..acf3838da4 100644
--- a/lib/compiler/src/beam_trim.erl
+++ b/lib/compiler/src/beam_trim.erl
@@ -21,12 +21,11 @@
-module(beam_trim).
-export([module/2]).
--import(lists, [reverse/1,reverse/2,splitwith/2,sort/1]).
+-import(lists, [any/2,member/2,reverse/1,reverse/2,splitwith/2,sort/1]).
-record(st,
- {safe :: gb_sets:set(beam_asm:label()), %Safe labels.
- lbl :: beam_utils:code_index() %Code at each label.
- }).
+ {safe :: cerl_sets:set(beam_asm:label()) %Safe labels.
+ }).
-spec module(beam_utils:module_code(), [compile:option()]) ->
{'ok',beam_utils:module_code()}.
@@ -36,10 +35,15 @@ module({Mod,Exp,Attr,Fs0,Lc}, _Opts) ->
{ok,{Mod,Exp,Attr,Fs,Lc}}.
function({function,Name,Arity,CLabel,Is0}) ->
- %%ok = io:fwrite("~w: ~p\n", [?LINE,{Name,Arity}]),
- St = #st{safe=safe_labels(Is0, []),lbl=beam_utils:index_labels(Is0)},
- Is = trim(Is0, St, []),
- {function,Name,Arity,CLabel,Is}.
+ try
+ St = #st{safe=safe_labels(Is0, [])},
+ Is = trim(Is0, St, []),
+ {function,Name,Arity,CLabel,Is}
+ catch
+ Class:Error:Stack ->
+ io:fwrite("Function: ~w/~w\n", [Name,Arity]),
+ erlang:raise(Class, Error, Stack)
+ end.
trim([{kill,_}|_]=Is0, St, Acc) ->
{Kills0,Is1} = splitwith(fun({kill,_}) -> true;
@@ -47,14 +51,33 @@ trim([{kill,_}|_]=Is0, St, Acc) ->
end, Is0),
Kills = sort(Kills0),
try
- {FrameSize,Layout} = frame_layout(Is1, Kills, St),
- Configs = trim_instructions(Layout),
- try_remap(Configs, Is1, FrameSize)
- of
+ %% Find out the size and layout of the stack frame.
+ %% Example of a layout:
+ %%
+ %% [{kill,{y,0}},{dead,{y,1},{live,{y,2}},{kill,{y,3}}]
+ %%
+ %% That means that y0 and y3 are to be killed, that y1
+ %% has been killed previously, and that y2 is live.
+ {FrameSize,Layout} = frame_layout(Is1, Kills, St),
+
+ %% Calculate all recipes that are not worse in terms
+ %% of estimated execution time. The recipes are ordered
+ %% in descending order from how much they trim.
+ Recipes = trim_recipes(Layout),
+
+ %% Try the recipes in order. A recipe may not work out because
+ %% a register that was previously killed may be
+ %% resurrected. If that happens, the next recipe, which trims
+ %% less, will be tried.
+ try_remap(Recipes, Is1, FrameSize)
+ of
{Is,TrimInstr} ->
+ %% One of the recipes was applied.
trim(Is, St, reverse(TrimInstr)++Acc)
catch
not_possible ->
+ %% No recipe worked out. Use the original kill
+ %% instructions.
trim(Is1, St, reverse(Kills, Acc))
end;
trim([I|Is], St, Acc) ->
@@ -62,34 +85,42 @@ trim([I|Is], St, Acc) ->
trim([], _, Acc) ->
reverse(Acc).
-%% trim_instructions([{kill,R}|{live,R}|{dead,R}]) -> {[Instruction],MapFun}
-%% Figure out the sequence of moves and trim to use.
+%% trim_recipes([{kill,R}|{live,R}|{dead,R}]) -> [Recipe].
+%% Recipe = {Kills,NumberToTrim,Moves}
+%% Kills = [{kill,Y}]
+%% Moves = [{move,SrcY,DstY}]
+%%
+%% Calculate how to best trim the stack and kill the correct
+%% Y registers. Return a list of possible recipes. The best
+%% recipe (the one that trims the most) is first in the list.
+%% All of the recipes are no worse in estimated execution time
+%% than the original sequences of kill instructions.
-trim_instructions(Layout) ->
+trim_recipes(Layout) ->
Cost = length([I || {kill,_}=I <- Layout]),
- trim_instructions_1(Layout, 0, [], {Cost,[]}).
+ trim_recipes_1(Layout, 0, [], {Cost,[]}).
-trim_instructions_1([{kill,{y,Trim0}}|Ks], Trim0, Moves, Config0) ->
+trim_recipes_1([{kill,{y,Trim0}}|Ks], Trim0, Moves, Recipes0) ->
Trim = Trim0 + 1,
- Config = save_config(Ks, Trim, Moves, Config0),
- trim_instructions_1(Ks, Trim, Moves, Config);
-trim_instructions_1([{dead,{y,Trim0}}|Ks], Trim0, Moves, Config0) ->
+ Recipes = save_recipe(Ks, Trim, Moves, Recipes0),
+ trim_recipes_1(Ks, Trim, Moves, Recipes);
+trim_recipes_1([{dead,{y,Trim0}}|Ks], Trim0, Moves, Recipes0) ->
Trim = Trim0 + 1,
- Config = save_config(Ks, Trim, Moves, Config0),
- trim_instructions_1(Ks, Trim, Moves, Config);
-trim_instructions_1([{live,{y,Trim0}=Src}|Ks0], Trim0, Moves0, Config0) ->
+ Recipes = save_recipe(Ks, Trim, Moves, Recipes0),
+ trim_recipes_1(Ks, Trim, Moves, Recipes);
+trim_recipes_1([{live,{y,Trim0}=Src}|Ks0], Trim0, Moves0, Recipes0) ->
case take_last_dead(Ks0) of
none ->
- {_,ConfigList} = Config0,
- ConfigList;
+ {_,RecipesList} = Recipes0,
+ RecipesList;
{Dst,Ks} ->
Trim = Trim0 + 1,
Moves = [{move,Src,Dst}|Moves0],
- Config = save_config(Ks, Trim, Moves, Config0),
- trim_instructions_1(Ks, Trim, Moves, Config)
+ Recipes = save_recipe(Ks, Trim, Moves, Recipes0),
+ trim_recipes_1(Ks, Trim, Moves, Recipes)
end;
-trim_instructions_1([], _, _, {_,ConfigList}) ->
- ConfigList.
+trim_recipes_1([], _, _, {_,RecipesList}) ->
+ RecipesList.
take_last_dead(L) ->
take_last_dead_1(reverse(L)).
@@ -100,28 +131,48 @@ take_last_dead_1([{dead,Reg}|Is]) ->
{Reg,reverse(Is)};
take_last_dead_1(_) -> none.
-save_config(Ks, Trim, Moves, {MaxCost,Acc}=Config) ->
- case config_cost(Ks, Moves) of
- Cost when Cost =< MaxCost ->
- {MaxCost,[{Ks,Trim,Moves}|Acc]};
+save_recipe(Ks, Trim, Moves, {MaxCost,Acc}=Recipes) ->
+ case recipe_cost(Ks, Moves) of
+ Cost when Cost =< MaxCost ->
+ %% The price is right.
+ {MaxCost,[{Ks,Trim,Moves}|Acc]};
_Cost ->
- Config
+ %% Too expensive.
+ Recipes
end.
-config_cost(Ks, Moves) ->
+recipe_cost(Ks, Moves) ->
%% We estimate that a {move,{y,_},{y,_}} instruction is roughly twice as
%% expensive as a {kill,{y,_}} instruction. A {trim,_} instruction is
%% roughly as expensive as a {kill,{y,_}} instruction.
- config_cost_1(Ks, 1+2*length(Moves)).
+ recipe_cost_1(Ks, 1+2*length(Moves)).
-config_cost_1([{kill,_}|Ks], Cost) ->
- config_cost_1(Ks, Cost+1);
-config_cost_1([_|Ks], Cost) ->
- config_cost_1(Ks, Cost);
-config_cost_1([], Cost) -> Cost.
+recipe_cost_1([{kill,_}|Ks], Cost) ->
+ recipe_cost_1(Ks, Cost+1);
+recipe_cost_1([_|Ks], Cost) ->
+ recipe_cost_1(Ks, Cost);
+recipe_cost_1([], Cost) -> Cost.
-expand_config({Layout,Trim,Moves}, FrameSize) ->
+%% try_remap([Recipe], [Instruction], FrameSize) ->
+%% {[Instruction],[TrimInstruction]}.
+%% Try to renumber Y registers in the instruction stream. The
+%% first rececipe that works will be used.
+%%
+%% This function will issue a `not_possible` exception if none
+%% of the recipes were possible to apply.
+
+try_remap([R|Rs], Is, FrameSize) ->
+ {TrimInstr,Map} = expand_recipe(R, FrameSize),
+ try
+ {remap(Is, Map, []),TrimInstr}
+ catch
+ throw:not_possible ->
+ try_remap(Rs, Is, FrameSize)
+ end;
+try_remap([], _, _) -> throw(not_possible).
+
+expand_recipe({Layout,Trim,Moves}, FrameSize) ->
Kills = [Kill || {kill,_}=Kill <- Layout],
{Kills++reverse(Moves, [{trim,Trim,FrameSize-Trim}]),create_map(Trim, Moves)}.
@@ -132,16 +183,16 @@ create_map(Trim, []) ->
(Any) -> Any
end;
create_map(Trim, Moves) ->
- GbTree0 = [{Src,Dst-Trim} || {move,{y,Src},{y,Dst}} <- Moves],
- GbTree = gb_trees:from_orddict(sort(GbTree0)),
- IllegalTargets = gb_sets:from_list([Dst || {move,_,{y,Dst}} <- Moves]),
+ Map0 = [{Src,Dst-Trim} || {move,{y,Src},{y,Dst}} <- Moves],
+ Map = maps:from_list(Map0),
+ IllegalTargets = cerl_sets:from_list([Dst || {move,_,{y,Dst}} <- Moves]),
fun({y,Y0}) when Y0 < Trim ->
- case gb_trees:lookup(Y0, GbTree) of
- {value,Y} -> {y,Y};
- none -> throw(not_possible)
- end;
+ case Map of
+ #{Y0:=Y} -> {y,Y};
+ #{} -> throw(not_possible)
+ end;
({y,Y}) ->
- case gb_sets:is_element(Y, IllegalTargets) of
+ case cerl_sets:is_element(Y, IllegalTargets) of
true -> throw(not_possible);
false -> {y,Y-Trim}
end;
@@ -149,19 +200,17 @@ create_map(Trim, Moves) ->
(Any) -> Any
end.
-try_remap([C|Cs], Is, FrameSize) ->
- {TrimInstr,Map} = expand_config(C, FrameSize),
- try
- {remap(Is, Map, []),TrimInstr}
- catch
- throw:not_possible ->
- try_remap(Cs, Is, FrameSize)
- end;
-try_remap([], _, _) -> throw(not_possible).
-
+remap([{'%',_}=I|Is], Map, Acc) ->
+ remap(Is, Map, [I|Acc]);
remap([{block,Bl0}|Is], Map, Acc) ->
Bl = remap_block(Bl0, Map, []),
remap(Is, Map, [{block,Bl}|Acc]);
+remap([{bs_get_tail,Src,Dst,Live}|Is], Map, Acc) ->
+ I = {bs_get_tail,Map(Src),Map(Dst),Live},
+ remap(Is, Map, [I|Acc]);
+remap([{bs_set_position,Src1,Src2}|Is], Map, Acc) ->
+ I = {bs_set_position,Map(Src1),Map(Src2)},
+ remap(Is, Map, [I|Acc]);
remap([{call_fun,_}=I|Is], Map, Acc) ->
remap(Is, Map, [I|Acc]);
remap([{call,_,_}=I|Is], Map, Acc) ->
@@ -205,35 +254,68 @@ remap([return|_]=Is, _, Acc) ->
reverse(Acc, Is);
remap([{line,_}=I|Is], Map, Acc) ->
remap(Is, Map, [I|Acc]).
-
+
remap_block([{set,Ds0,Ss0,Info}|Is], Map, Acc) ->
Ds = [Map(D) || D <- Ds0],
Ss = [Map(S) || S <- Ss0],
remap_block(Is, Map, [{set,Ds,Ss,Info}|Acc]);
remap_block([], _, Acc) -> reverse(Acc).
-
-safe_labels([{label,L},{line,_},{badmatch,{Tag,_}}|Is], Acc) when Tag =/= y ->
- safe_labels(Is, [L|Acc]);
-safe_labels([{label,L},{line,_},{case_end,{Tag,_}}|Is], Acc) when Tag =/= y ->
- safe_labels(Is, [L|Acc]);
-safe_labels([{label,L},{line,_},if_end|Is], Acc) ->
- safe_labels(Is, [L|Acc]);
-safe_labels([{label,L},
- {block,[{set,[{x,0}],[{Tag,_}],move}]},
- {line,_},
- {call_ext,1,{extfunc,erlang,error,1}}|Is], Acc) when Tag =/= y ->
- safe_labels(Is, [L|Acc]);
+
+%% safe_labels([Instruction], Accumulator) -> gb_set()
+%% Build a gb_set of safe labels. The code at a safe
+%% label does not depend on the values in a specific
+%% Y register, only that all Y registers are initialized
+%% so that it safe to scan the stack when an exception
+%% is generated.
+%%
+%% In other words, code at a safe label will continue
+%% to work if Y registers have been renumbered and
+%% the size of the stack frame has changed.
+
+safe_labels([{label,L}|Is], Acc) ->
+ case is_safe_label(Is) of
+ true -> safe_labels(Is, [L|Acc]);
+ false -> safe_labels(Is, Acc)
+ end;
safe_labels([_|Is], Acc) ->
safe_labels(Is, Acc);
-safe_labels([], Acc) -> gb_sets:from_list(Acc).
+safe_labels([], Acc) -> cerl_sets:from_list(Acc).
+
+is_safe_label([{'%',_}|Is]) ->
+ is_safe_label(Is);
+is_safe_label([{line,_}|Is]) ->
+ is_safe_label(Is);
+is_safe_label([{badmatch,{Tag,_}}|_]) ->
+ Tag =/= y;
+is_safe_label([{case_end,{Tag,_}}|_]) ->
+ Tag =/= y;
+is_safe_label([{try_case_end,{Tag,_}}|_]) ->
+ Tag =/= y;
+is_safe_label([if_end|_]) ->
+ true;
+is_safe_label([{block,Bl}|Is]) ->
+ is_safe_label_block(Bl) andalso is_safe_label(Is);
+is_safe_label([{call_ext,_,{extfunc,M,F,A}}|_]) ->
+ erl_bifs:is_exit_bif(M, F, A);
+is_safe_label(_) -> false.
+
+is_safe_label_block([{set,Ds,Ss,_}|Is]) ->
+ IsYreg = fun({y,_}) -> true;
+ (_) -> false
+ end,
+ %% This instruction is safe if the instruction
+ %% neither reads or writes Y registers.
+ not (any(IsYreg, Ss) orelse any(IsYreg, Ds)) andalso
+ is_safe_label_block(Is);
+is_safe_label_block([]) -> true.
%% frame_layout([Instruction], [{kill,_}], St) ->
%% [{kill,Reg} | {live,Reg} | {dead,Reg}]
%% Figure out the layout of the stack frame.
-frame_layout(Is, Kills, #st{safe=Safe,lbl=D}) ->
+frame_layout(Is, Kills, #st{safe=Safe}) ->
N = frame_size(Is, Safe),
- IsKilled = fun(R) -> beam_utils:is_not_used(R, Is, D) end,
+ IsKilled = fun(R) -> is_not_used(R, Is) end,
{N,frame_layout_1(Kills, 0, N, IsKilled, [])}.
frame_layout_1([{kill,{y,Y}}=I|Ks], Y, N, IsKilled, Acc) ->
@@ -253,7 +335,14 @@ frame_layout_2(Is) -> reverse(Is).
%% frame_size([Instruction], SafeLabels) -> FrameSize
%% Find out the frame size by looking at the code that follows.
+%%
+%% Implicitly, also check that the instructions are a straight
+%% sequence of code that ends in a return. Any branches are
+%% to safe labels (i.e., the code at those labels don't depend
+%% on the contents of any Y register).
+frame_size([{'%',_}|Is], Safe) ->
+ frame_size(Is, Safe);
frame_size([{block,_}|Is], Safe) ->
frame_size(Is, Safe);
frame_size([{call_fun,_}|Is], Safe) ->
@@ -285,15 +374,94 @@ frame_size([{make_fun2,_,_,_,_}|Is], Safe) ->
frame_size(Is, Safe);
frame_size([{get_map_elements,{f,L},_,_}|Is], Safe) ->
frame_size_branch(L, Is, Safe);
-frame_size([{deallocate,N}|_], _) -> N;
+frame_size([{deallocate,N}|_], _) ->
+ N;
frame_size([{line,_}|Is], Safe) ->
frame_size(Is, Safe);
-frame_size([_|_], _) -> throw(not_possible).
+frame_size([{bs_set_position,_,_}|Is], Safe) ->
+ frame_size(Is, Safe);
+frame_size([{bs_get_tail,_,_,_}|Is], Safe) ->
+ frame_size(Is, Safe);
+frame_size(_, _) -> throw(not_possible).
frame_size_branch(0, Is, Safe) ->
frame_size(Is, Safe);
frame_size_branch(L, Is, Safe) ->
- case gb_sets:is_member(L, Safe) of
+ case cerl_sets:is_element(L, Safe) of
false -> throw(not_possible);
true -> frame_size(Is, Safe)
end.
+
+%% is_not_used(Y, [Instruction]) -> true|false.
+%% Test whether the value of Y is unused in the instruction sequence.
+%% Return true if the value of Y is not used, and false if it is used.
+%%
+%% This function handles the same instructions as frame_size/2. It
+%% assumes that any labels in the instructions are safe labels.
+
+is_not_used(Y, [{'%',_}|Is]) ->
+ is_not_used(Y, Is);
+is_not_used(Y, [{apply,_}|Is]) ->
+ is_not_used(Y, Is);
+is_not_used(Y, [{bif,_,{f,_},Ss,Dst}|Is]) ->
+ is_not_used_ss_dst(Y, Ss, Dst, Is);
+is_not_used(Y, [{block,Bl}|Is]) ->
+ case is_not_used_block(Y, Bl) of
+ used -> false;
+ killed -> true;
+ transparent -> is_not_used(Y, Is)
+ end;
+is_not_used(Y, [{bs_get_tail,Src,Dst,_}|Is]) ->
+ is_not_used_ss_dst(Y, [Src], Dst, Is);
+is_not_used(Y, [{bs_init,_,_,_,Ss,Dst}|Is]) ->
+ is_not_used_ss_dst(Y, Ss, Dst, Is);
+is_not_used(Y, [{bs_put,{f,_},_,Ss}|Is]) ->
+ not member(Y, Ss) andalso is_not_used(Y, Is);
+is_not_used(Y, [{bs_set_position,Src1,Src2}|Is]) ->
+ Y =/= Src1 andalso Y =/= Src2 andalso
+ is_not_used(Y, Is);
+is_not_used(Y, [{call,_,_}|Is]) ->
+ is_not_used(Y, Is);
+is_not_used(Y, [{call_ext,_,_}=I|Is]) ->
+ beam_jump:is_exit_instruction(I) orelse is_not_used(Y, Is);
+is_not_used(Y, [{call_fun,_}|Is]) ->
+ is_not_used(Y, Is);
+is_not_used(_Y, [{deallocate,_}|_]) ->
+ true;
+is_not_used(Y, [{gc_bif,_,{f,_},_Live,Ss,Dst}|Is]) ->
+ is_not_used_ss_dst(Y, Ss, Dst, Is);
+is_not_used(Y, [{get_map_elements,{f,_},S,{list,List}}|Is]) ->
+ {Ss,Ds} = beam_utils:split_even(List),
+ case member(Y, [S|Ss]) of
+ true ->
+ false;
+ false ->
+ member(Y, Ds) orelse is_not_used(Y, Is)
+ end;
+is_not_used(Y, [{kill,Yreg}|Is]) ->
+ Y =:= Yreg orelse is_not_used(Y, Is);
+is_not_used(Y, [{line,_}|Is]) ->
+ is_not_used(Y, Is);
+is_not_used(Y, [{make_fun2,_,_,_,_}|Is]) ->
+ is_not_used(Y, Is);
+is_not_used(Y, [{test,_,_,Ss}|Is]) ->
+ not member(Y, Ss) andalso is_not_used(Y, Is);
+is_not_used(Y, [{test,_Op,{f,_},_Live,Ss,Dst}|Is]) ->
+ is_not_used_ss_dst(Y, Ss, Dst, Is).
+
+is_not_used_block(Y, [{set,Ds,Ss,_}|Is]) ->
+ case member(Y, Ss) of
+ true ->
+ used;
+ false ->
+ case member(Y, Ds) of
+ true ->
+ killed;
+ false ->
+ is_not_used_block(Y, Is)
+ end
+ end;
+is_not_used_block(_Y, []) -> transparent.
+
+is_not_used_ss_dst(Y, Ss, Dst, Is) ->
+ not member(Y, Ss) andalso (Y =:= Dst orelse is_not_used(Y, Is)).
diff --git a/lib/compiler/src/beam_type.erl b/lib/compiler/src/beam_type.erl
deleted file mode 100644
index fc2c7a991b..0000000000
--- a/lib/compiler/src/beam_type.erl
+++ /dev/null
@@ -1,937 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%% Purpose : Type-based optimisations.
-
--module(beam_type).
-
--export([module/2]).
-
--import(lists, [filter/2,foldl/3,keyfind/3,member/2,
- reverse/1,reverse/2,sort/1]).
-
--define(UNICODE_INT, {integer,{0,16#10FFFF}}).
-
--spec module(beam_utils:module_code(), [compile:option()]) ->
- {'ok',beam_utils:module_code()}.
-
-module({Mod,Exp,Attr,Fs0,Lc}, _Opts) ->
- Fs = [function(F) || F <- Fs0],
- {ok,{Mod,Exp,Attr,Fs,Lc}}.
-
-function({function,Name,Arity,CLabel,Asm0}) ->
- try
- Asm1 = beam_utils:live_opt(Asm0),
- Asm2 = opt(Asm1, [], tdb_new()),
- Asm3 = beam_utils:live_opt(Asm2),
- Asm = beam_utils:delete_live_annos(Asm3),
- {function,Name,Arity,CLabel,Asm}
- catch
- Class:Error ->
- Stack = erlang:get_stacktrace(),
- io:fwrite("Function: ~w/~w\n", [Name,Arity]),
- erlang:raise(Class, Error, Stack)
- end.
-
-%% opt([Instruction], Accumulator, TypeDb) -> {[Instruction'],TypeDb'}
-%% Keep track of type information; try to simplify.
-
-opt([{block,Body1}|Is], [{block,Body0}|Acc], Ts0) ->
- {Body2,Ts} = simplify(Body1, Ts0),
- Body = merge_blocks(Body0, Body2),
- opt(Is, [{block,Body}|Acc], Ts);
-opt([{block,Body0}|Is], Acc, Ts0) ->
- {Body,Ts} = simplify(Body0, Ts0),
- opt(Is, [{block,Body}|Acc], Ts);
-opt([I0|Is], Acc, Ts0) ->
- case simplify_basic([I0], Ts0) of
- {[],Ts} -> opt(Is, Acc, Ts);
- {[I],Ts} -> opt(Is, [I|Acc], Ts)
- end;
-opt([], Acc, _) -> reverse(Acc).
-
-%% simplify(Instruction, TypeDb) -> NewInstruction
-%% Simplify an instruction using type information (this is
-%% technically a "strength reduction").
-
-simplify(Is0, TypeDb0) ->
- {Is,_} = BasicRes = simplify_basic(Is0, TypeDb0),
- case simplify_float(Is, TypeDb0) of
- not_possible -> BasicRes;
- {_,_}=Res -> Res
- end.
-
-%% simplify_basic([Instruction], TypeDatabase) -> {[Instruction],TypeDatabase'}
-%% Basic simplification, mostly tuples, no floating point optimizations.
-
-simplify_basic(Is, Ts) ->
- simplify_basic_1(Is, Ts, []).
-
-simplify_basic_1([{set,[D],[{integer,Index},Reg],{bif,element,_}}=I0|Is], Ts0, Acc) ->
- I = case max_tuple_size(Reg, Ts0) of
- Sz when 0 < Index, Index =< Sz ->
- {set,[D],[Reg],{get_tuple_element,Index-1}};
- _Other -> I0
- end,
- Ts = update(I, Ts0),
- simplify_basic_1(Is, Ts, [I|Acc]);
-simplify_basic_1([{set,[D],[TupleReg],{get_tuple_element,0}}=I|Is0], Ts0, Acc) ->
- case tdb_find(TupleReg, Ts0) of
- {tuple,_,[Contents]} ->
- simplify_basic_1([{set,[D],[Contents],move}|Is0], Ts0, Acc);
- _ ->
- Ts = update(I, Ts0),
- simplify_basic_1(Is0, Ts, [I|Acc])
- end;
-simplify_basic_1([{set,_,_,{try_catch,_,_}}=I|Is], _Ts, Acc) ->
- simplify_basic_1(Is, tdb_new(), [I|Acc]);
-simplify_basic_1([{test,is_atom,_,[R]}=I|Is], Ts, Acc) ->
- case tdb_find(R, Ts) of
- boolean -> simplify_basic_1(Is, Ts, Acc);
- _ -> simplify_basic_1(Is, Ts, [I|Acc])
- end;
-simplify_basic_1([{test,is_integer,_,[R]}=I|Is], Ts, Acc) ->
- case tdb_find(R, Ts) of
- integer -> simplify_basic_1(Is, Ts, Acc);
- {integer,_} -> simplify_basic_1(Is, Ts, Acc);
- _ -> simplify_basic_1(Is, Ts, [I|Acc])
- end;
-simplify_basic_1([{test,is_tuple,_,[R]}=I|Is], Ts, Acc) ->
- case tdb_find(R, Ts) of
- {tuple,_,_} -> simplify_basic_1(Is, Ts, Acc);
- _ -> simplify_basic_1(Is, Ts, [I|Acc])
- end;
-simplify_basic_1([{test,is_map,_,[R]}=I|Is], Ts0, Acc) ->
- case tdb_find(R, Ts0) of
- map -> simplify_basic_1(Is, Ts0, Acc);
- _Other ->
- Ts = update(I, Ts0),
- simplify_basic_1(Is, Ts, [I|Acc])
- end;
-simplify_basic_1([{test,is_nonempty_list,_,[R]}=I|Is], Ts0, Acc) ->
- case tdb_find(R, Ts0) of
- nonempty_list -> simplify_basic_1(Is, Ts0, Acc);
- _Other ->
- Ts = update(I, Ts0),
- simplify_basic_1(Is, Ts, [I|Acc])
- end;
-simplify_basic_1([{test,is_eq_exact,Fail,[R,{atom,_}=Atom]}=I|Is0], Ts0, Acc0) ->
- Acc = case tdb_find(R, Ts0) of
- {atom,_}=Atom -> Acc0;
- {atom,_} -> [{jump,Fail}|Acc0];
- _ -> [I|Acc0]
- end,
- Ts = update(I, Ts0),
- simplify_basic_1(Is0, Ts, Acc);
-simplify_basic_1([{select,select_val,Reg,_,_}=I0|Is], Ts, Acc) ->
- I = case tdb_find(Reg, Ts) of
- {integer,Range} ->
- simplify_select_val_int(I0, Range);
- boolean ->
- simplify_select_val_bool(I0);
- _ ->
- I0
- end,
- simplify_basic_1(Is, tdb_new(), [I|Acc]);
-simplify_basic_1([I|Is], Ts0, Acc) ->
- Ts = update(I, Ts0),
- simplify_basic_1(Is, Ts, [I|Acc]);
-simplify_basic_1([], Ts, Acc) ->
- Is = reverse(Acc),
- {Is,Ts}.
-
-simplify_select_val_int({select,select_val,R,_,L0}=I, {Min,Max}) ->
- Vs = sort([V || {integer,V} <- L0]),
- case eq_ranges(Vs, Min, Max) of
- false -> I;
- true -> simplify_select_val_1(L0, {integer,Max}, R, [])
- end.
-
-simplify_select_val_bool({select,select_val,R,_,L}=I) ->
- Vs = sort([V || {atom,V} <- L]),
- case Vs of
- [false,true] ->
- simplify_select_val_1(L, {atom,false}, R, []);
- _ ->
- I
- end.
-
-simplify_select_val_1([Val,F|T], Val, R, Acc) ->
- L = reverse(Acc, T),
- {select,select_val,R,F,L};
-simplify_select_val_1([V,F|T], Val, R, Acc) ->
- simplify_select_val_1(T, Val, R, [F,V|Acc]).
-
-eq_ranges([H], H, H) -> true;
-eq_ranges([H|T], H, Max) -> eq_ranges(T, H+1, Max);
-eq_ranges(_, _, _) -> false.
-
-%% simplify_float([Instruction], TypeDatabase) ->
-%% {[Instruction],TypeDatabase'} | not_possible
-%% Simplify floating point operations in blocks.
-%%
-simplify_float(Is0, Ts0) ->
- {Is1,Ts} = simplify_float_1(Is0, Ts0, [], []),
- Is2 = opt_fmoves(Is1, []),
- Is3 = flt_need_heap(Is2),
- try
- {flt_liveness(Is3),Ts}
- catch
- throw:not_possible -> not_possible
- end.
-
-simplify_float_1([{set,[],[],fclearerror}|Is], Ts, Rs, Acc) ->
- simplify_float_1(Is, Ts, Rs, clearerror(Acc));
-simplify_float_1([{set,[],[],fcheckerror}|Is], Ts, Rs, Acc) ->
- simplify_float_1(Is, Ts, Rs, checkerror(Acc));
-simplify_float_1([{set,[{fr,_}],_,_}=I|Is], Ts, Rs, Acc) ->
- simplify_float_1(Is, Ts, Rs, [I|Acc]);
-simplify_float_1([{set,[D0],[A0],{alloc,_,{gc_bif,'-',{f,0}}}}=I|Is]=Is0,
- Ts0, Rs0, Acc0) ->
- case tdb_find(A0, Ts0) of
- float ->
- A = coerce_to_float(A0),
- {Rs1,Acc1} = load_reg(A, Ts0, Rs0, Acc0),
- {D,Rs} = find_dest(D0, Rs1),
- Areg = fetch_reg(A, Rs),
- Acc = [{set,[D],[Areg],{bif,fnegate,{f,0}}}|clearerror(Acc1)],
- Ts = tdb_update([{D0,float}], Ts0),
- simplify_float_1(Is, Ts, Rs, Acc);
- _Other ->
- Ts = update(I, Ts0),
- {Rs,Acc} = flush(Rs0, Is0, Acc0),
- simplify_float_1(Is, Ts, Rs, [I|checkerror(Acc)])
- end;
-simplify_float_1([{set,[D0],[A0,B0],{alloc,_,{gc_bif,Op0,{f,0}}}}=I|Is]=Is0,
- Ts0, Rs0, Acc0) ->
- case float_op(Op0, A0, B0, Ts0) of
- no ->
- Ts = update(I, Ts0),
- {Rs,Acc} = flush(Rs0, Is0, Acc0),
- simplify_float_1(Is, Ts, Rs, [I|checkerror(Acc)]);
- {yes,Op} ->
- A = coerce_to_float(A0),
- B = coerce_to_float(B0),
- {Rs1,Acc1} = load_reg(A, Ts0, Rs0, Acc0),
- {Rs2,Acc2} = load_reg(B, Ts0, Rs1, Acc1),
- {D,Rs} = find_dest(D0, Rs2),
- Areg = fetch_reg(A, Rs),
- Breg = fetch_reg(B, Rs),
- Acc = [{set,[D],[Areg,Breg],{bif,Op,{f,0}}}|clearerror(Acc2)],
- Ts = tdb_update([{D0,float}], Ts0),
- simplify_float_1(Is, Ts, Rs, Acc)
- end;
-simplify_float_1([{set,_,_,{try_catch,_,_}}=I|Is]=Is0, _Ts, Rs0, Acc0) ->
- Acc = flush_all(Rs0, Is0, Acc0),
- simplify_float_1(Is, tdb_new(), Rs0, [I|Acc]);
-simplify_float_1([{set,_,_,{line,_}}=I|Is], Ts, Rs, Acc) ->
- simplify_float_1(Is, Ts, Rs, [I|Acc]);
-simplify_float_1([I|Is], Ts0, [], Acc) ->
- Ts = update(I, Ts0),
- simplify_float_1(Is, Ts, [], [I|Acc]);
-simplify_float_1([I|Is]=Is0, Ts0, Rs0, Acc0) ->
- Ts = update(I, Ts0),
- {Rs,Acc} = flush(Rs0, Is0, Acc0),
- simplify_float_1(Is, Ts, Rs, [I|checkerror(Acc)]);
-simplify_float_1([], Ts, [], Acc) ->
- Is = reverse(Acc),
- {Is,Ts}.
-
-coerce_to_float({integer,I}=Int) ->
- try float(I) of
- F ->
- {float,F}
- catch _:_ ->
- %% Let the overflow happen at run-time.
- Int
- end;
-coerce_to_float(Other) -> Other.
-
-opt_fmoves([{set,[{x,_}=R],[{fr,_}]=Src,fmove}=I1,
- {set,[_]=Dst,[{x,_}=R],move}=I2|Is], Acc) ->
- case beam_utils:is_killed_block(R, Is) of
- false -> opt_fmoves(Is, [I2,I1|Acc]);
- true -> opt_fmoves(Is, [{set,Dst,Src,fmove}|Acc])
- end;
-opt_fmoves([I|Is], Acc) ->
- opt_fmoves(Is, [I|Acc]);
-opt_fmoves([], Acc) -> reverse(Acc).
-
-clearerror(Is) ->
- clearerror(Is, Is).
-
-clearerror([{set,[],[],fclearerror}|_], OrigIs) -> OrigIs;
-clearerror([{set,[],[],fcheckerror}|_], OrigIs) -> [{set,[],[],fclearerror}|OrigIs];
-clearerror([_|Is], OrigIs) -> clearerror(Is, OrigIs);
-clearerror([], OrigIs) -> [{set,[],[],fclearerror}|OrigIs].
-
-%% merge_blocks(Block1, Block2) -> Block.
-%% Combine two blocks and eliminate any move instructions that assign
-%% to registers that are killed later in the block.
-%%
-merge_blocks(B1, [{'%live',_,_}|B2]) ->
- merge_blocks_1(B1++[{set,[],[],stop_here}|B2]).
-
-merge_blocks_1([{set,[],_,stop_here}|Is]) -> Is;
-merge_blocks_1([{set,[D],_,move}=I|Is]) ->
- case beam_utils:is_killed_block(D, Is) of
- true -> merge_blocks_1(Is);
- false -> [I|merge_blocks_1(Is)]
- end;
-merge_blocks_1([I|Is]) -> [I|merge_blocks_1(Is)].
-
-%% flt_need_heap([Instruction]) -> [Instruction]
-%% Insert need heap allocation instructions in the instruction stream
-%% to properly account for both inserted floating point operations and
-%% normal term build operations (such as put_list/3).
-%%
-%% Ignore old heap allocation instructions (except if they allocate a stack
-%% frame too), as they may be in the wrong place (because gc_bif instructions
-%% could have been converted to floating point operations).
-
-flt_need_heap(Is) ->
- flt_need_heap_1(reverse(Is), 0, 0, []).
-
-flt_need_heap_1([{set,[],[],{alloc,_,Alloc}}|Is], H, Fl, Acc) ->
- case Alloc of
- {_,nostack,_,_} ->
- %% Remove any existing test_heap/2 instruction.
- flt_need_heap_1(Is, H, Fl, Acc);
- {Z,Stk,_,Inits} when is_integer(Stk) ->
- %% Keep any allocate*/2 instruction and recalculate heap need.
- I = {set,[],[],{alloc,regs,{Z,Stk,build_alloc(H, Fl),Inits}}},
- flt_need_heap_1(Is, 0, 0, [I|Acc])
- end;
-flt_need_heap_1([I|Is], H0, Fl0, Acc) ->
- {Ns,H1,Fl1} = flt_need_heap_2(I, H0, Fl0),
- flt_need_heap_1(Is, H1, Fl1, [I|Ns]++Acc);
-flt_need_heap_1([], H, Fl, Acc) ->
- flt_alloc(H, Fl) ++ Acc.
-
-%% First come all instructions that build. We pass through, while we
-%% add to the need for heap words and floats on the heap.
-flt_need_heap_2({set,[_],[{fr,_}],fmove}, H, Fl) ->
- {[],H,Fl+1};
-flt_need_heap_2({set,_,_,put_list}, H, Fl) ->
- {[],H+2,Fl};
-flt_need_heap_2({set,_,_,{put_tuple,_}}, H, Fl) ->
- {[],H+1,Fl};
-flt_need_heap_2({set,_,_,put}, H, Fl) ->
- {[],H+1,Fl};
-%% Then the "neutral" instructions. We just pass them.
-flt_need_heap_2({set,[{fr,_}],_,_}, H, Fl) ->
- {[],H,Fl};
-flt_need_heap_2({set,[],[],fclearerror}, H, Fl) ->
- {[],H,Fl};
-flt_need_heap_2({set,[],[],fcheckerror}, H, Fl) ->
- {[],H,Fl};
-flt_need_heap_2({set,_,_,{bif,_,_}}, H, Fl) ->
- {[],H,Fl};
-flt_need_heap_2({set,_,_,move}, H, Fl) ->
- {[],H,Fl};
-flt_need_heap_2({set,_,_,{get_tuple_element,_}}, H, Fl) ->
- {[],H,Fl};
-flt_need_heap_2({set,_,_,get_list}, H, Fl) ->
- {[],H,Fl};
-flt_need_heap_2({set,_,_,{try_catch,_,_}}, H, Fl) ->
- {[],H,Fl};
-flt_need_heap_2({set,_,_,init}, H, Fl) ->
- {[],H,Fl};
-%% All other instructions should cause the insertion of an allocation
-%% instruction if needed.
-flt_need_heap_2(_, H, Fl) ->
- {flt_alloc(H, Fl),0,0}.
-
-flt_alloc(0, 0) ->
- [];
-flt_alloc(H, 0) ->
- [{set,[],[],{alloc,regs,{nozero,nostack,H,[]}}}];
-flt_alloc(H, F) ->
- [{set,[],[],{alloc,regs,{nozero,nostack,
- build_alloc(H, F),[]}}}].
-
-build_alloc(Words, 0) -> Words;
-build_alloc(Words, Floats) -> {alloc,[{words,Words},{floats,Floats}]}.
-
-
-%% flt_liveness([Instruction]) -> [Instruction]
-%% (Re)calculate the number of live registers for each heap allocation
-%% function. We base liveness of the number of register map at the
-%% beginning of the instruction sequence.
-%%
-%% A 'not_possible' term will be thrown if the set of live registers
-%% is not continous at an allocation function (e.g. if {x,0} and {x,2}
-%% are live, but not {x,1}).
-
-flt_liveness([{'%live',_Live,Regs}=LiveInstr|Is]) ->
- flt_liveness_1(Is, Regs, [LiveInstr]).
-
-flt_liveness_1([{set,Ds,Ss,{alloc,Live0,Alloc}}|Is], Regs0, Acc) ->
- Live = min(Live0, live_regs(Regs0)),
- I = {set,Ds,Ss,{alloc,Live,Alloc}},
- Regs1 = init_regs(Live),
- Regs = x_live(Ds, Regs1),
- flt_liveness_1(Is, Regs, [I|Acc]);
-flt_liveness_1([{set,Ds,_,_}=I|Is], Regs0, Acc) ->
- Regs = x_live(Ds, Regs0),
- flt_liveness_1(Is, Regs, [I|Acc]);
-flt_liveness_1([{'%live',_,_}], _Regs, Acc) ->
- reverse(Acc).
-
-init_regs(Live) ->
- (1 bsl Live) - 1.
-
-live_regs(Regs) ->
- live_regs_1(Regs, 0).
-
-live_regs_1(0, N) -> N;
-live_regs_1(R, N) ->
- case R band 1 of
- 0 -> throw(not_possible);
- 1 -> live_regs_1(R bsr 1, N+1)
- end.
-
-x_live([{x,N}|Rs], Regs) -> x_live(Rs, Regs bor (1 bsl N));
-x_live([_|Rs], Regs) -> x_live(Rs, Regs);
-x_live([], Regs) -> Regs.
-
-%% update(Instruction, TypeDb) -> NewTypeDb
-%% Update the type database to account for executing an instruction.
-%%
-%% First the cases for instructions inside basic blocks.
-update({'%live',_,_}, Ts) -> Ts;
-update({set,[D],[S],move}, Ts) ->
- tdb_copy(S, D, Ts);
-update({set,[D],[{integer,I},Reg],{bif,element,_}}, Ts0) ->
- tdb_update([{Reg,{tuple,I,[]}},{D,kill}], Ts0);
-update({set,[D],[_Index,Reg],{bif,element,_}}, Ts0) ->
- tdb_update([{Reg,{tuple,0,[]}},{D,kill}], Ts0);
-update({set,[D],Args,{bif,N,_}}, Ts0) ->
- Ar = length(Args),
- BoolOp = erl_internal:new_type_test(N, Ar) orelse
- erl_internal:comp_op(N, Ar) orelse
- erl_internal:bool_op(N, Ar),
- case BoolOp of
- true ->
- tdb_update([{D,boolean}], Ts0);
- false ->
- tdb_update([{D,kill}], Ts0)
- end;
-update({set,[D],[S],{get_tuple_element,0}}, Ts) ->
- tdb_update([{D,{tuple_element,S,0}}], Ts);
-update({set,[D],[S],{alloc,_,{gc_bif,float,{f,0}}}}, Ts0) ->
- %% Make sure we reject non-numeric literal argument.
- case possibly_numeric(S) of
- true -> tdb_update([{D,float}], Ts0);
- false -> Ts0
- end;
-update({set,[D],[S1,S2],{alloc,_,{gc_bif,'band',{f,0}}}}, Ts) ->
- case keyfind(integer, 1, [S1,S2]) of
- {integer,N} ->
- update_band(N, D, Ts);
- false ->
- tdb_update([{D,integer}], Ts)
- end;
-update({set,[D],[S1,S2],{alloc,_,{gc_bif,'/',{f,0}}}}, Ts0) ->
- %% Make sure we reject non-numeric literals.
- case possibly_numeric(S1) andalso possibly_numeric(S2) of
- true -> tdb_update([{D,float}], Ts0);
- false -> Ts0
- end;
-update({set,[D],[S1,S2],{alloc,_,{gc_bif,Op,{f,0}}}}, Ts0) ->
- case op_type(Op) of
- integer ->
- tdb_update([{D,integer}], Ts0);
- {float,_} ->
- case {tdb_find(S1, Ts0),tdb_find(S2, Ts0)} of
- {float,_} -> tdb_update([{D,float}], Ts0);
- {_,float} -> tdb_update([{D,float}], Ts0);
- {_,_} -> tdb_update([{D,kill}], Ts0)
- end;
- unknown ->
- tdb_update([{D,kill}], Ts0)
- end;
-update({set,[],_Src,_Op}, Ts0) -> Ts0;
-update({set,[D],_Src,_Op}, Ts0) ->
- tdb_update([{D,kill}], Ts0);
-update({set,[D1,D2],_Src,_Op}, Ts0) ->
- tdb_update([{D1,kill},{D2,kill}], Ts0);
-update({kill,D}, Ts) ->
- tdb_update([{D,kill}], Ts);
-
-%% Instructions outside of blocks.
-update({test,is_float,_Fail,[Src]}, Ts0) ->
- tdb_update([{Src,float}], Ts0);
-update({test,test_arity,_Fail,[Src,Arity]}, Ts0) ->
- tdb_update([{Src,{tuple,Arity,[]}}], Ts0);
-update({test,is_map,_Fail,[Src]}, Ts0) ->
- tdb_update([{Src,map}], Ts0);
-update({get_map_elements,_,Src,{list,Elems0}}, Ts0) ->
- {_Ss,Ds} = beam_utils:split_even(Elems0),
- Elems = [{Dst,kill} || Dst <- Ds],
- tdb_update([{Src,map}|Elems], Ts0);
-update({test,is_nonempty_list,_Fail,[Src]}, Ts0) ->
- tdb_update([{Src,nonempty_list}], Ts0);
-update({test,is_eq_exact,_,[Reg,{atom,_}=Atom]}, Ts) ->
- case tdb_find(Reg, Ts) of
- error ->
- Ts;
- {tuple_element,TupleReg,0} ->
- tdb_update([{TupleReg,{tuple,1,[Atom]}}], Ts);
- _ ->
- Ts
- end;
-update({test,is_record,_Fail,[Src,Tag,{integer,Arity}]}, Ts) ->
- tdb_update([{Src,{tuple,Arity,[Tag]}}], Ts);
-
-%% Binary matching
-
-update({test,bs_get_integer2,_,_,Args,Dst}, Ts) ->
- tdb_update([{Dst,get_bs_integer_type(Args)}], Ts);
-update({test,bs_get_utf8,_,_,_,Dst}, Ts) ->
- tdb_update([{Dst,?UNICODE_INT}], Ts);
-update({test,bs_get_utf16,_,_,_,Dst}, Ts) ->
- tdb_update([{Dst,?UNICODE_INT}], Ts);
-update({test,bs_get_utf32,_,_,_,Dst}, Ts) ->
- tdb_update([{Dst,?UNICODE_INT}], Ts);
-update({bs_init,_,_,_,_,Dst}, Ts) ->
- tdb_update([{Dst,kill}], Ts);
-update({bs_put,_,_,_}, Ts) ->
- Ts;
-update({bs_save2,_,_}, Ts) ->
- Ts;
-update({bs_restore2,_,_}, Ts) ->
- Ts;
-update({bs_context_to_binary,Dst}, Ts) ->
- tdb_update([{Dst,kill}], Ts);
-update({test,bs_start_match2,_,_,_,Dst}, Ts) ->
- tdb_update([{Dst,kill}], Ts);
-update({test,bs_get_binary2,_,_,_,Dst}, Ts) ->
- tdb_update([{Dst,kill}], Ts);
-update({test,bs_get_float2,_,_,_,Dst}, Ts) ->
- tdb_update([{Dst,float}], Ts);
-
-update({test,_Test,_Fail,_Other}, Ts) ->
- Ts;
-
-%% Calls
-
-update({call_ext,Ar,{extfunc,math,Math,Ar}}, Ts) ->
- case is_math_bif(Math, Ar) of
- true -> tdb_update([{{x,0},float}], Ts);
- false -> tdb_kill_xregs(Ts)
- end;
-update({call_ext,3,{extfunc,erlang,setelement,3}}, Ts0) ->
- Ts = tdb_kill_xregs(Ts0),
- case tdb_find({x,1}, Ts0) of
- {tuple,Sz,_}=T0 ->
- T = case tdb_find({x,0}, Ts0) of
- {integer,{I,I}} when I > 1 ->
- %% First element is not changed. The result
- %% will have the same type.
- T0;
- _ ->
- %% Position is 1 or unknown. May change the
- %% first element of the tuple.
- {tuple,Sz,[]}
- end,
- tdb_update([{{x,0},T}], Ts);
- _ ->
- Ts
- end;
-update({call,_Arity,_Func}, Ts) -> tdb_kill_xregs(Ts);
-update({call_ext,_Arity,_Func}, Ts) -> tdb_kill_xregs(Ts);
-update({make_fun2,_,_,_,_}, Ts) -> tdb_kill_xregs(Ts);
-update({call_fun, _}, Ts) -> tdb_kill_xregs(Ts);
-update({apply, _}, Ts) -> tdb_kill_xregs(Ts);
-
-update({line,_}, Ts) -> Ts;
-
-%% The instruction is unknown. Kill all information.
-update(_I, _Ts) -> tdb_new().
-
-update_band(N, Reg, Ts) ->
- Type = update_band_1(N, 0),
- tdb_update([{Reg,Type}], Ts).
-
-update_band_1(N, Bits) when Bits < 64 ->
- case 1 bsl Bits of
- P when P =:= N + 1 ->
- {integer,{0,N}};
- P when P > N + 1 ->
- integer;
- _ ->
- update_band_1(N, Bits+1)
- end;
-update_band_1(_, _) ->
- %% Negative or large positive number. Give up.
- integer.
-
-get_bs_integer_type([_,{integer,N},U,{field_flags,Fl}])
- when N*U < 64 ->
- NumBits = N*U,
- case member(unsigned, Fl) of
- true ->
- {integer,{0,(1 bsl NumBits)-1}};
- false ->
- %% Signed integer. Don't bother.
- integer
- end;
-get_bs_integer_type(_) ->
- %% Avoid creating ranges with a huge upper limit.
- integer.
-
-is_math_bif(cos, 1) -> true;
-is_math_bif(cosh, 1) -> true;
-is_math_bif(sin, 1) -> true;
-is_math_bif(sinh, 1) -> true;
-is_math_bif(tan, 1) -> true;
-is_math_bif(tanh, 1) -> true;
-is_math_bif(acos, 1) -> true;
-is_math_bif(acosh, 1) -> true;
-is_math_bif(asin, 1) -> true;
-is_math_bif(asinh, 1) -> true;
-is_math_bif(atan, 1) -> true;
-is_math_bif(atanh, 1) -> true;
-is_math_bif(erf, 1) -> true;
-is_math_bif(erfc, 1) -> true;
-is_math_bif(exp, 1) -> true;
-is_math_bif(log, 1) -> true;
-is_math_bif(log2, 1) -> true;
-is_math_bif(log10, 1) -> true;
-is_math_bif(sqrt, 1) -> true;
-is_math_bif(atan2, 2) -> true;
-is_math_bif(pow, 2) -> true;
-is_math_bif(ceil, 1) -> true;
-is_math_bif(floor, 1) -> true;
-is_math_bif(fmod, 2) -> true;
-is_math_bif(pi, 0) -> true;
-is_math_bif(_, _) -> false.
-
-%% Reject non-numeric literals.
-possibly_numeric({x,_}) -> true;
-possibly_numeric({y,_}) -> true;
-possibly_numeric({integer,_}) -> true;
-possibly_numeric({float,_}) -> true;
-possibly_numeric(_) -> false.
-
-max_tuple_size(Reg, Ts) ->
- case tdb_find(Reg, Ts) of
- {tuple,Sz,_} -> Sz;
- _Other -> 0
- end.
-
-float_op('/', A, B, _) ->
- case possibly_numeric(A) andalso possibly_numeric(B) of
- true -> {yes,fdiv};
- false -> no
- end;
-float_op(Op, {float,_}, B, _) ->
- case possibly_numeric(B) of
- true -> arith_op(Op);
- false -> no
- end;
-float_op(Op, A, {float,_}, _) ->
- case possibly_numeric(A) of
- true -> arith_op(Op);
- false -> no
- end;
-float_op(Op, A, B, Ts) ->
- case {tdb_find(A, Ts),tdb_find(B, Ts)} of
- {float,_} -> arith_op(Op);
- {_,float} -> arith_op(Op);
- {_,_} -> no
- end.
-
-find_dest(V, Rs0) ->
- case find_reg(V, Rs0) of
- {ok,FR} ->
- {FR,mark(V, Rs0, dirty)};
- error ->
- Rs = put_reg(V, Rs0, dirty),
- {ok,FR} = find_reg(V, Rs),
- {FR,Rs}
- end.
-
-load_reg({float,_}=F, _, Rs0, Is0) ->
- Rs = put_reg(F, Rs0, clean),
- {ok,FR} = find_reg(F, Rs),
- Is = [{set,[FR],[F],fmove}|Is0],
- {Rs,Is};
-load_reg(V, Ts, Rs0, Is0) ->
- case find_reg(V, Rs0) of
- {ok,_FR} -> {Rs0,Is0};
- error ->
- Rs = put_reg(V, Rs0, clean),
- {ok,FR} = find_reg(V, Rs),
- Op = case tdb_find(V, Ts) of
- float -> fmove;
- _ -> fconv
- end,
- Is = [{set,[FR],[V],Op}|Is0],
- {Rs,Is}
- end.
-
-arith_op(Op) ->
- case op_type(Op) of
- {float,Instr} -> {yes,Instr};
- _ -> no
- end.
-
-op_type('+') -> {float,fadd};
-op_type('-') -> {float,fsub};
-op_type('*') -> {float,fmul};
-%% '/' and 'band' are specially handled.
-op_type('bor') -> integer;
-op_type('bxor') -> integer;
-op_type('bsl') -> integer;
-op_type('bsr') -> integer;
-op_type('div') -> integer;
-op_type(_) -> unknown.
-
-flush(Rs, [{set,[_],[_,_,_],{bif,is_record,_}}|_]=Is0, Acc0) ->
- Acc = flush_all(Rs, Is0, Acc0),
- {[],Acc};
-flush(Rs, [{set,[_],[],{put_tuple,_}}|_]=Is0, Acc0) ->
- Acc = flush_all(Rs, Is0, Acc0),
- {[],Acc};
-flush(Rs0, [{set,Ds,Ss,_Op}|_], Acc0) ->
- Save = cerl_sets:from_list(Ss),
- Acc = save_regs(Rs0, Save, Acc0),
- Rs1 = foldl(fun(S, A) -> mark(S, A, clean) end, Rs0, Ss),
- Kill = cerl_sets:from_list(Ds),
- Rs = kill_regs(Rs1, Kill),
- {Rs,Acc};
-flush(Rs0, Is, Acc0) ->
- Acc = flush_all(Rs0, Is, Acc0),
- {[],Acc}.
-
-flush_all([{_,{float,_},_}|Rs], Is, Acc) ->
- flush_all(Rs, Is, Acc);
-flush_all([{I,V,dirty}|Rs], Is, Acc0) ->
- Acc = checkerror(Acc0),
- case beam_utils:is_killed_block(V, Is) of
- true -> flush_all(Rs, Is, Acc);
- false -> flush_all(Rs, Is, [{set,[V],[{fr,I}],fmove}|Acc])
- end;
-flush_all([{_,_,clean}|Rs], Is, Acc) -> flush_all(Rs, Is, Acc);
-flush_all([free|Rs], Is, Acc) -> flush_all(Rs, Is, Acc);
-flush_all([], _, Acc) -> Acc.
-
-save_regs(Rs, Save, Acc) ->
- foldl(fun(R, A) -> save_reg(R, Save, A) end, Acc, Rs).
-
-save_reg({I,V,dirty}, Save, Acc) ->
- case cerl_sets:is_element(V, Save) of
- true -> [{set,[V],[{fr,I}],fmove}|checkerror(Acc)];
- false -> Acc
- end;
-save_reg(_, _, Acc) -> Acc.
-
-kill_regs(Rs, Kill) ->
- [kill_reg(R, Kill) || R <- Rs].
-
-kill_reg({_,V,_}=R, Kill) ->
- case cerl_sets:is_element(V, Kill) of
- true -> free;
- false -> R
- end;
-kill_reg(R, _) -> R.
-
-mark(V, [{I,V,_}|Rs], Mark) -> [{I,V,Mark}|Rs];
-mark(V, [R|Rs], Mark) -> [R|mark(V, Rs, Mark)];
-mark(_, [], _) -> [].
-
-fetch_reg(V, [{I,V,_}|_]) -> {fr,I};
-fetch_reg(V, [_|SRs]) -> fetch_reg(V, SRs).
-
-find_reg(V, [{I,V,_}|_]) -> {ok,{fr,I}};
-find_reg(V, [_|SRs]) -> find_reg(V, SRs);
-find_reg(_, []) -> error.
-
-put_reg(V, Rs, Dirty) -> put_reg_1(V, Rs, Dirty, 0).
-
-put_reg_1(V, [free|Rs], Dirty, I) -> [{I,V,Dirty}|Rs];
-put_reg_1(V, [R|Rs], Dirty, I) -> [R|put_reg_1(V, Rs, Dirty, I+1)];
-put_reg_1(V, [], Dirty, I) -> [{I,V,Dirty}].
-
-checkerror(Is) ->
- checkerror_1(Is, Is).
-
-checkerror_1([{set,[],[],fcheckerror}|_], OrigIs) -> OrigIs;
-checkerror_1([{set,_,_,{bif,fadd,_}}|_], OrigIs) -> checkerror_2(OrigIs);
-checkerror_1([{set,_,_,{bif,fsub,_}}|_], OrigIs) -> checkerror_2(OrigIs);
-checkerror_1([{set,_,_,{bif,fmul,_}}|_], OrigIs) -> checkerror_2(OrigIs);
-checkerror_1([{set,_,_,{bif,fdiv,_}}|_], OrigIs) -> checkerror_2(OrigIs);
-checkerror_1([{set,_,_,{bif,fnegate,_}}|_], OrigIs) -> checkerror_2(OrigIs);
-checkerror_1([_|Is], OrigIs) -> checkerror_1(Is, OrigIs);
-checkerror_1([], OrigIs) -> OrigIs.
-
-checkerror_2(OrigIs) -> [{set,[],[],fcheckerror}|OrigIs].
-
-
-%%% Routines for maintaining a type database. The type database
-%%% associates type information with registers.
-%%%
-%%% {tuple,Size,First} means that the corresponding register contains a
-%%% tuple with *at least* Size elements. An tuple with unknown
-%%% size is represented as {tuple,0,[]}. First is either [] (meaning that
-%%% the tuple's first element is unknown) or [FirstElement] (the contents
-%%% of the first element).
-%%%
-%%% 'float' means that the register contains a float.
-%%%
-%%% 'integer' or {integer,{Min,Max}} that the register contains an
-%%% integer.
-
-%% tdb_new() -> EmptyDataBase
-%% Creates a new, empty type database.
-
-tdb_new() -> [].
-
-%% tdb_find(Register, Db) -> Information|error
-%% Returns type information or the atom error if there is no type
-%% information available for Register.
-
-tdb_find({x,_}=K, Ts) -> tdb_find_1(K, Ts);
-tdb_find({y,_}=K, Ts) -> tdb_find_1(K, Ts);
-tdb_find(_, _) -> error.
-
-tdb_find_1(K, Ts) ->
- case orddict:find(K, Ts) of
- {ok,Val} -> Val;
- error -> error
- end.
-
-%% tdb_copy(Source, Dest, Db) -> Db'
-%% Update the type information for Dest to have the same type
-%% as the Source.
-
-tdb_copy({Tag,_}=S, D, Ts) when Tag =:= x; Tag =:= y ->
- case tdb_find(S, Ts) of
- error -> orddict:erase(D, Ts);
- Type -> orddict:store(D, Type, Ts)
- end;
-tdb_copy(Literal, D, Ts) ->
- Type = case Literal of
- {atom,_} -> Literal;
- {float,_} -> float;
- {integer,Int} -> {integer,{Int,Int}};
- {literal,[_|_]} -> nonempty_list;
- {literal,#{}} -> map;
- {literal,Tuple} when tuple_size(Tuple) >= 1 ->
- Lit = tag_literal(element(1, Tuple)),
- {tuple,tuple_size(Tuple),[Lit]};
- _ -> term
- end,
- if
- Type =:= term ->
- orddict:erase(D, Ts);
- true ->
- verify_type(Type),
- orddict:store(D, Type, Ts)
- end.
-
-tag_literal(A) when is_atom(A) -> {atom,A};
-tag_literal(F) when is_float(F) -> {float,F};
-tag_literal(I) when is_integer(I) -> {integer,I};
-tag_literal([]) -> nil;
-tag_literal(Lit) -> {literal,Lit}.
-
-%% tdb_update([UpdateOp], Db) -> NewDb
-%% UpdateOp = {Register,kill}|{Register,NewInfo}
-%% Updates a type database. If a 'kill' operation is given, the type
-%% information for that register will be removed from the database.
-%% A kill operation takes precedence over other operations for the same
-%% register (i.e. [{{x,0},kill},{{x,0},{tuple,5,[]}}] means that the
-%% the existing type information, if any, will be discarded, and the
-%% the '{tuple,5,[]}' information ignored.
-%%
-%% If NewInfo information is given and there exists information about
-%% the register, the old and new type information will be merged.
-%% For instance, {tuple,5,_} and {tuple,10,_} will be merged to produce
-%% {tuple,10,_}.
-
-tdb_update(Uis0, Ts0) ->
- Uis1 = filter(fun ({{x,_},_Op}) -> true;
- ({{y,_},_Op}) -> true;
- (_) -> false
- end, Uis0),
- tdb_update1(lists:sort(Uis1), Ts0).
-
-tdb_update1([{Key,kill}|Ops], [{K,_Old}|_]=Db) when Key < K ->
- tdb_update1(remove_key(Key, Ops), Db);
-tdb_update1([{Key,Type}=New|Ops], [{K,_Old}|_]=Db) when Key < K ->
- verify_type(Type),
- [New|tdb_update1(Ops, Db)];
-tdb_update1([{Key,kill}|Ops], [{Key,_}|Db]) ->
- tdb_update1(remove_key(Key, Ops), Db);
-tdb_update1([{Key,NewInfo}|Ops], [{Key,OldInfo}|Db]) ->
- [{Key,merge_type_info(NewInfo, OldInfo)}|tdb_update1(Ops, Db)];
-tdb_update1([{_,_}|_]=Ops, [Old|Db]) ->
- [Old|tdb_update1(Ops, Db)];
-tdb_update1([{Key,kill}|Ops], []) ->
- tdb_update1(remove_key(Key, Ops), []);
-tdb_update1([{_,Type}=New|Ops], []) ->
- verify_type(Type),
- [New|tdb_update1(Ops, [])];
-tdb_update1([], Db) -> Db.
-
-%% tdb_kill_xregs(Db) -> NewDb
-%% Kill all information about x registers. Also kill all tuple_element
-%% dependencies from y registers to x registers.
-
-tdb_kill_xregs([{{x,_},_Type}|Db]) -> tdb_kill_xregs(Db);
-tdb_kill_xregs([{{y,_},{tuple_element,{x,_},_}}|Db]) -> tdb_kill_xregs(Db);
-tdb_kill_xregs([Any|Db]) -> [Any|tdb_kill_xregs(Db)];
-tdb_kill_xregs([]) -> [].
-
-remove_key(Key, [{Key,_Op}|Ops]) -> remove_key(Key, Ops);
-remove_key(_, Ops) -> Ops.
-
-merge_type_info(I, I) -> I;
-merge_type_info({tuple,Sz1,Same}, {tuple,Sz2,Same}=Max) when Sz1 < Sz2 ->
- Max;
-merge_type_info({tuple,Sz1,Same}=Max, {tuple,Sz2,Same}) when Sz1 > Sz2 ->
- Max;
-merge_type_info({tuple,Sz1,[]}, {tuple,_Sz2,First}=Tuple2) ->
- merge_type_info({tuple,Sz1,First}, Tuple2);
-merge_type_info({tuple,_Sz1,First}=Tuple1, {tuple,Sz2,_}) ->
- merge_type_info(Tuple1, {tuple,Sz2,First});
-merge_type_info(integer, {integer,_}) ->
- integer;
-merge_type_info({integer,_}, integer) ->
- integer;
-merge_type_info({integer,{Min1,Max1}}, {integer,{Min2,Max2}}) ->
- {integer,{max(Min1, Min2),min(Max1, Max2)}};
-merge_type_info(NewType, _) ->
- verify_type(NewType),
- NewType.
-
-verify_type({atom,_}) -> ok;
-verify_type(boolean) -> ok;
-verify_type(integer) -> ok;
-verify_type({integer,{Min,Max}})
- when is_integer(Min), is_integer(Max) -> ok;
-verify_type(map) -> ok;
-verify_type(nonempty_list) -> ok;
-verify_type({tuple,Sz,[]}) when is_integer(Sz) -> ok;
-verify_type({tuple,Sz,[_]}) when is_integer(Sz) -> ok;
-verify_type({tuple_element,_,_}) -> ok;
-verify_type(float) -> ok.
diff --git a/lib/compiler/src/beam_utils.erl b/lib/compiler/src/beam_utils.erl
index e39fbdc3b7..6e6574c0b3 100644
--- a/lib/compiler/src/beam_utils.erl
+++ b/lib/compiler/src/beam_utils.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,21 +18,16 @@
%% %CopyrightEnd%
%%
%% Purpose : Common utilities used by several optimization passes.
-%%
+%%
-module(beam_utils).
--export([is_killed_block/2,is_killed/3,is_killed_at/3,
- is_not_used/3,
- empty_label_index/0,index_label/3,index_labels/1,
- code_at/2,bif_to_test/3,is_pure_test/1,
- live_opt/1,delete_live_annos/1,combine_heap_needs/2,
- split_even/1]).
+-export([replace_labels/4,is_pure_test/1,split_even/1]).
-export_type([code_index/0,module_code/0,instruction/0]).
--import(lists, [member/2,sort/1,reverse/1,splitwith/2]).
+-import(lists, [map/2,reverse/1]).
-%% instruction() describes all instructions that are used during optimzation
+%% instruction() describes all instructions that are used during optimization
%% (from beam_a to beam_z).
-type instruction() :: atom() | tuple().
@@ -48,150 +43,18 @@
-type fail() :: beam_asm:fail() | 'fail'.
-type test() :: {'test',atom(),fail(),[beam_asm:src()]} |
{'test',atom(),fail(),integer(),list(),beam_asm:reg()}.
--type result_cache() :: gb_trees:tree(beam_asm:label(), 'killed' | 'used').
-
--record(live,
- {lbl :: code_index(), %Label to code index.
- res :: result_cache()}). %Result cache for each label.
-
-
-%% is_killed_block(Register, [Instruction]) -> true|false
-%% Determine whether a register is killed by the instruction sequence inside
-%% a block.
-%%
-%% If true is returned, it means that the register will not be
-%% referenced in ANY way (not even indirectly by an allocate instruction);
-%% i.e. it is OK to enter the instruction sequence with Register
-%% containing garbage.
-
--spec is_killed_block(beam_asm:reg(), [instruction()]) -> boolean().
-
-is_killed_block({x,X}, [{set,_,_,{alloc,Live,_}}|_]) ->
- X >= Live;
-is_killed_block(R, [{set,Ds,Ss,_Op}|Is]) ->
- not member(R, Ss) andalso (member(R, Ds) orelse is_killed_block(R, Is));
-is_killed_block(R, [{'%live',_,Regs}|Is]) ->
- case R of
- {x,X} when (Regs bsr X) band 1 =:= 0 -> true;
- _ -> is_killed_block(R, Is)
- end;
-is_killed_block(_, []) -> false.
-
-%% is_killed(Register, [Instruction], State) -> true|false
-%% Determine whether a register is killed by the instruction sequence.
-%% If true is returned, it means that the register will not be
-%% referenced in ANY way (not even indirectly by an allocate instruction);
-%% i.e. it is OK to enter the instruction sequence with Register
-%% containing garbage.
-%%
-%% The state (constructed by index_instructions/1) is used to allow us
-%% to determine the kill state across branches.
-
--spec is_killed(beam_asm:reg(), [instruction()], code_index()) -> boolean().
-
-is_killed(R, Is, D) ->
- St = #live{lbl=D,res=gb_trees:empty()},
- case check_liveness(R, Is, St) of
- {killed,_} -> true;
- {_,_} -> false
- end.
-
-%% is_killed_at(Reg, Lbl, State) -> true|false
-%% Determine whether Reg is killed at label Lbl.
-
--spec is_killed_at(beam_asm:reg(), beam_asm:label(), code_index()) -> boolean().
-
-is_killed_at(R, Lbl, D) when is_integer(Lbl) ->
- St0 = #live{lbl=D,res=gb_trees:empty()},
- case check_liveness_at(R, Lbl, St0) of
- {killed,_} -> true;
- {_,_} -> false
- end.
-
-%% is_not_used(Register, [Instruction], State) -> true|false
-%% Determine whether a register is never used in the instruction sequence
-%% (it could still be referenced by an allocate instruction, meaning that
-%% it MUST be initialized, but that its value does not matter).
-%% The state is used to allow us to determine the usage state
-%% across branches.
-
--spec is_not_used(beam_asm:reg(), [instruction()], code_index()) -> boolean().
-
-is_not_used(R, Is, D) ->
- St = #live{lbl=D,res=gb_trees:empty()},
- case check_liveness(R, Is, St) of
- {used,_} -> false;
- {_,_} -> true
- end.
-
-%% index_labels(FunctionIs) -> State
-%% Index the instruction sequence so that we can quickly
-%% look up the instruction following a specific label.
--spec index_labels([instruction()]) -> code_index().
-
-index_labels(Is) ->
- index_labels_1(Is, []).
-
-%% empty_label_index() -> State
-%% Create an empty label index.
-
--spec empty_label_index() -> code_index().
-
-empty_label_index() ->
- gb_trees:empty().
-
-%% index_label(Label, [Instruction], State) -> State
-%% Add an index for a label.
-
--spec index_label(beam_asm:label(), [instruction()], code_index()) ->
- code_index().
-
-index_label(Lbl, Is0, Acc) ->
- Is = drop_labels(Is0),
- gb_trees:enter(Lbl, Is, Acc).
-
-
-%% code_at(Label, State) -> [I].
-%% Retrieve the code at the given label.
-
--spec code_at(beam_asm:label(), code_index()) -> [instruction()].
-
-code_at(L, Ll) ->
- gb_trees:get(L, Ll).
-
-%% bif_to_test(Bif, [Op], Fail) -> {test,Test,Fail,[Op]}
-%% Convert a BIF to a test. Fail if not possible.
-
--spec bif_to_test(atom(), list(), fail()) -> test().
-
-bif_to_test(is_atom, [_]=Ops, Fail) -> {test,is_atom,Fail,Ops};
-bif_to_test(is_boolean, [_]=Ops, Fail) -> {test,is_boolean,Fail,Ops};
-bif_to_test(is_binary, [_]=Ops, Fail) -> {test,is_binary,Fail,Ops};
-bif_to_test(is_bitstring,[_]=Ops, Fail) -> {test,is_bitstr,Fail,Ops};
-bif_to_test(is_float, [_]=Ops, Fail) -> {test,is_float,Fail,Ops};
-bif_to_test(is_function, [_]=Ops, Fail) -> {test,is_function,Fail,Ops};
-bif_to_test(is_function, [_,_]=Ops, Fail) -> {test,is_function2,Fail,Ops};
-bif_to_test(is_integer, [_]=Ops, Fail) -> {test,is_integer,Fail,Ops};
-bif_to_test(is_list, [_]=Ops, Fail) -> {test,is_list,Fail,Ops};
-bif_to_test(is_map, [_]=Ops, Fail) -> {test,is_map,Fail,Ops};
-bif_to_test(is_number, [_]=Ops, Fail) -> {test,is_number,Fail,Ops};
-bif_to_test(is_pid, [_]=Ops, Fail) -> {test,is_pid,Fail,Ops};
-bif_to_test(is_port, [_]=Ops, Fail) -> {test,is_port,Fail,Ops};
-bif_to_test(is_reference, [_]=Ops, Fail) -> {test,is_reference,Fail,Ops};
-bif_to_test(is_tuple, [_]=Ops, Fail) -> {test,is_tuple,Fail,Ops};
-bif_to_test('=<', [A,B], Fail) -> {test,is_ge,Fail,[B,A]};
-bif_to_test('>', [A,B], Fail) -> {test,is_lt,Fail,[B,A]};
-bif_to_test('<', [_,_]=Ops, Fail) -> {test,is_lt,Fail,Ops};
-bif_to_test('>=', [_,_]=Ops, Fail) -> {test,is_ge,Fail,Ops};
-bif_to_test('==', [A,nil], Fail) -> {test,is_nil,Fail,[A]};
-bif_to_test('==', [_,_]=Ops, Fail) -> {test,is_eq,Fail,Ops};
-bif_to_test('/=', [_,_]=Ops, Fail) -> {test,is_ne,Fail,Ops};
-bif_to_test('=:=', [A,nil], Fail) -> {test,is_nil,Fail,[A]};
-bif_to_test('=:=', [_,_]=Ops, Fail) -> {test,is_eq_exact,Fail,Ops};
-bif_to_test('=/=', [_,_]=Ops, Fail) -> {test,is_ne_exact,Fail,Ops};
-bif_to_test(is_record, [_,_,_]=Ops, Fail) -> {test,is_record,Fail,Ops}.
+%% replace_labels(FunctionIs, Tail, ReplaceDb, Fallback) -> FunctionIs.
+%% Replace all labels in instructions according to the ReplaceDb.
+%% If label is not found the Fallback is called with the label to
+%% produce a new one.
+-spec replace_labels([instruction()],
+ [instruction()],
+ #{beam_asm:label() => beam_asm:label()},
+ fun((beam_asm:label()) -> term())) -> [instruction()].
+replace_labels(Is, Acc, D, Fb) ->
+ replace_labels_1(Is, Acc, D, Fb).
%% is_pure_test({test,Op,Fail,Ops}) -> true|false.
%% Return 'true' if the test instruction does not modify any
@@ -206,65 +69,15 @@ is_pure_test({test,is_eq_exact,_,[_,_]}) -> true;
is_pure_test({test,is_ne_exact,_,[_,_]}) -> true;
is_pure_test({test,is_ge,_,[_,_]}) -> true;
is_pure_test({test,is_lt,_,[_,_]}) -> true;
-is_pure_test({test,is_nil,_,[_]}) -> true;
is_pure_test({test,is_nonempty_list,_,[_]}) -> true;
+is_pure_test({test,is_tagged_tuple,_,[_,_,_]}) -> true;
is_pure_test({test,test_arity,_,[_,_]}) -> true;
is_pure_test({test,has_map_fields,_,[_|_]}) -> true;
is_pure_test({test,is_bitstr,_,[_]}) -> true;
is_pure_test({test,is_function2,_,[_,_]}) -> true;
-is_pure_test({test,Op,_,Ops}) ->
+is_pure_test({test,Op,_,Ops}) ->
erl_internal:new_type_test(Op, length(Ops)).
-
-%% live_opt([Instruction]) -> [Instruction].
-%% Go through the instruction sequence in reverse execution
-%% order, keep track of liveness and remove 'move' instructions
-%% whose destination is a register that will not be used.
-%% Also insert {'%live',Live,Regs} annotations at the beginning
-%% and end of each block.
-
--spec live_opt([instruction()]) -> [instruction()].
-
-live_opt(Is0) ->
- {[{label,Fail}|_]=Bef,[Fi|Is]} =
- splitwith(fun({func_info,_,_,_}) -> false;
- (_) -> true
- end, Is0),
- {func_info,_,_,Live} = Fi,
- D = gb_trees:insert(Fail, live_call(Live), gb_trees:empty()),
- Bef ++ [Fi|live_opt(reverse(Is), 0, D, [])].
-
-
-%% delete_live_annos([Instruction]) -> [Instruction].
-%% Delete all live annotations.
-
--spec delete_live_annos([instruction()]) -> [instruction()].
-
-delete_live_annos([{block,Bl0}|Is]) ->
- case delete_live_annos(Bl0) of
- [] -> delete_live_annos(Is);
- [_|_]=Bl -> [{block,Bl}|delete_live_annos(Is)]
- end;
-delete_live_annos([{'%live',_,_}|Is]) ->
- delete_live_annos(Is);
-delete_live_annos([I|Is]) ->
- [I|delete_live_annos(Is)];
-delete_live_annos([]) -> [].
-
-%% combine_heap_needs(HeapNeed1, HeapNeed2) -> HeapNeed
-%% Combine the heap need for two allocation instructions.
-
--spec combine_heap_needs(term(), term()) -> term().
-
-combine_heap_needs({alloc,Alloc1}, {alloc,Alloc2}) ->
- {alloc,combine_alloc_lists(Alloc1, Alloc2)};
-combine_heap_needs({alloc,Alloc}, Words) when is_integer(Words) ->
- {alloc,combine_alloc_lists(Alloc, [{words,Words}])};
-combine_heap_needs(Words, {alloc,Alloc}) when is_integer(Words) ->
- {alloc,combine_alloc_lists(Alloc, [{words,Words}])};
-combine_heap_needs(H1, H2) when is_integer(H1), is_integer(H2) ->
- H1+H2.
-
%% split_even/1
%% [1,2,3,4,5,6] -> {[1,3,5],[2,4,6]}
@@ -272,595 +85,65 @@ combine_heap_needs(H1, H2) when is_integer(H1), is_integer(H2) ->
split_even(Rs) -> split_even(Rs, [], []).
-
%%%
%%% Local functions.
%%%
-
-%% check_liveness(Reg, [Instruction], #live{}) ->
-%% {killed | not_used | used, #live{}}
-%% Find out whether Reg is used or killed in instruction sequence.
-%%
-%% killed - Reg is assigned or killed by an allocation instruction.
-%% not_used - the value of Reg is not used, but Reg must not be garbage
-%% used - Reg is used
-
-check_liveness(R, [{block,Blk}|Is], St0) ->
- case check_liveness_block(R, Blk, St0) of
- {transparent,St1} ->
- check_liveness(R, Is, St1);
- {Other,_}=Res when is_atom(Other) ->
- Res
- end;
-check_liveness(R, [{label,_}|Is], St) ->
- check_liveness(R, Is, St);
-check_liveness(R, [{test,_,{f,Fail},As}|Is], St0) ->
- case member(R, As) of
- true ->
- {used,St0};
- false ->
- case check_liveness_at(R, Fail, St0) of
- {killed,St1} ->
- check_liveness(R, Is, St1);
- {not_used,St1} ->
- not_used(check_liveness(R, Is, St1));
- {used,_}=Used ->
- Used
- end
- end;
-check_liveness(R, [{test,Op,Fail,Live,Ss,Dst}|Is], St) ->
- %% Check this instruction as a block to get a less conservative
- %% result if the caller is is_not_used/3.
- Block = [{set,[Dst],Ss,{alloc,Live,{bif,Op,Fail}}}],
- check_liveness(R, [{block,Block}|Is], St);
-check_liveness(R, [{select,_,R,_,_}|_], St) ->
- {used,St};
-check_liveness(R, [{select,_,_,Fail,Branches}|_], St) ->
- check_liveness_everywhere(R, [Fail|Branches], St);
-check_liveness(R, [{jump,{f,F}}|_], St) ->
- check_liveness_at(R, F, St);
-check_liveness(R, [{case_end,Used}|_], St) ->
- check_liveness_ret(R, Used, St);
-check_liveness(R, [{badmatch,Used}|_], St) ->
- check_liveness_ret(R, Used, St);
-check_liveness(_, [if_end|_], St) ->
- {killed,St};
-check_liveness(R, [{func_info,_,_,Ar}|_], St) ->
- case R of
- {x,X} when X < Ar -> {used,St};
- _ -> {killed,St}
- end;
-check_liveness(R, [{kill,R}|_], St) ->
- {killed,St};
-check_liveness(R, [{kill,_}|Is], St) ->
- check_liveness(R, Is, St);
-check_liveness(R, [{bs_init,_,_,none,Ss,Dst}|Is], St) ->
- case member(R, Ss) of
- true ->
- {used,St};
- false ->
- if
- R =:= Dst -> {killed,St};
- true -> check_liveness(R, Is, St)
- end
- end;
-check_liveness(R, [{bs_init,_,_,Live,Ss,Dst}|Is], St) ->
- case R of
- {x,X} ->
- case X < Live orelse member(R, Ss) of
- true -> {used,St};
- false -> {killed,St}
- end;
- {y,_} ->
- case member(R, Ss) of
- true -> {used,St};
- false ->
- if
- R =:= Dst -> {killed,St};
- true -> check_liveness(R, Is, St)
- end
- end
- end;
-check_liveness(R, [{deallocate,_}|Is], St) ->
- case R of
- {y,_} -> {killed,St};
- _ -> check_liveness(R, Is, St)
- end;
-check_liveness({x,_}=R, [return|_], St) ->
- case R of
- {x,0} -> {used,St};
- {x,_} -> {killed,St}
- end;
-check_liveness(R, [{call,Live,_}|Is], St) ->
- case R of
- {x,X} when X < Live -> {used,St};
- {x,_} -> {killed,St};
- {y,_} -> not_used(check_liveness(R, Is, St))
- end;
-check_liveness(R, [{call_ext,Live,_}=I|Is], St) ->
- case R of
- {x,X} when X < Live ->
- {used,St};
- {x,_} ->
- {killed,St};
- {y,_} ->
- case beam_jump:is_exit_instruction(I) of
- false ->
- not_used(check_liveness(R, Is, St));
- true ->
- %% We must make sure we don't check beyond this
- %% instruction or we will fall through into random
- %% unrelated code and get stuck in a loop.
- {killed,St}
- end
- end;
-check_liveness(R, [{call_fun,Live}|Is], St) ->
- case R of
- {x,X} when X =< Live -> {used,St};
- {x,_} -> {killed,St};
- {y,_} -> not_used(check_liveness(R, Is, St))
- end;
-check_liveness(R, [{apply,Args}|Is], St) ->
- case R of
- {x,X} when X < Args+2 -> {used,St};
- {x,_} -> {killed,St};
- {y,_} -> not_used(check_liveness(R, Is, St))
- end;
-check_liveness(R, [{bif,Op,Fail,Ss,D}|Is], St) ->
- Set = {set,[D],Ss,{bif,Op,Fail}},
- check_liveness(R, [{block,[Set]}|Is], St);
-check_liveness(R, [{gc_bif,Op,{f,Fail},Live,Ss,D}|Is], St) ->
- Set = {set,[D],Ss,{alloc,Live,{gc_bif,Op,Fail}}},
- check_liveness(R, [{block,[Set]}|Is], St);
-check_liveness(R, [{bs_put,{f,0},_,Ss}|Is], St) ->
- case member(R, Ss) of
- true -> {used,St};
- false -> check_liveness(R, Is, St)
- end;
-check_liveness(R, [{bs_restore2,S,_}|Is], St) ->
- case R of
- S -> {used,St};
- _ -> check_liveness(R, Is, St)
- end;
-check_liveness(R, [{bs_save2,S,_}|Is], St) ->
- case R of
- S -> {used,St};
- _ -> check_liveness(R, Is, St)
- end;
-check_liveness(R, [{move,S,D}|Is], St) ->
- case R of
- S -> {used,St};
- D -> {killed,St};
- _ -> check_liveness(R, Is, St)
- end;
-check_liveness(R, [{make_fun2,_,_,_,NumFree}|Is], St) ->
- case R of
- {x,X} when X < NumFree -> {used,St};
- {x,_} -> {killed,St};
- {y,_} -> not_used(check_liveness(R, Is, St))
- end;
-check_liveness({x,_}=R, [{'catch',_,_}|Is], St) ->
- %% All x registers will be killed if an exception occurs.
- %% Therefore we only need to check the liveness for the
- %% instructions following the catch instruction.
- check_liveness(R, Is, St);
-check_liveness({x,_}=R, [{'try',_,_}|Is], St) ->
- %% All x registers will be killed if an exception occurs.
- %% Therefore we only need to check the liveness for the
- %% instructions inside the 'try' block.
- check_liveness(R, Is, St);
-check_liveness(R, [{try_end,Y}|Is], St) ->
- case R of
- Y ->
- {killed,St};
- {y,_} ->
- %% y registers will be used if an exception occurs and
- %% control transfers to the label given in the previous
- %% try/2 instruction.
- {used,St};
- _ ->
- check_liveness(R, Is, St)
- end;
-check_liveness(R, [{catch_end,Y}|Is], St) ->
- case R of
- Y -> {killed,St};
- _ -> check_liveness(R, Is, St)
- end;
-check_liveness(R, [{get_tuple_element,S,_,D}|Is], St) ->
- case R of
- S -> {used,St};
- D -> {killed,St};
- _ -> check_liveness(R, Is, St)
- end;
-check_liveness(R, [{bs_context_to_binary,S}|Is], St) ->
- case R of
- S -> {used,St};
- _ -> check_liveness(R, Is, St)
- end;
-check_liveness(R, [{loop_rec,{f,_},{x,0}}|_], St) ->
- case R of
- {x,_} ->
- {killed,St};
- _ ->
- %% y register. Rarely happens. Be very conversative and
- %% assume it's used.
- {used,St}
- end;
-check_liveness(R, [{loop_rec_end,{f,Fail}}|_], St) ->
- check_liveness_at(R, Fail, St);
-check_liveness(R, [{line,_}|Is], St) ->
- check_liveness(R, Is, St);
-check_liveness(R, [{get_map_elements,{f,Fail},S,{list,L}}|Is], St0) ->
- {Ss,Ds} = split_even(L),
- case member(R, [S|Ss]) of
- true ->
- {used,St0};
- false ->
- case check_liveness_at(R, Fail, St0) of
- {killed,St}=Killed ->
- case member(R, Ds) of
- true -> Killed;
- false -> check_liveness(R, Is, St)
- end;
- Other ->
- Other
- end
- end;
-check_liveness(R, [{put_map,F,Op,S,D,Live,{list,Puts}}|Is], St) ->
- Set = {set,[D],[S|Puts],{alloc,Live,{put_map,Op,F}}},
- check_liveness(R, [{block,[Set]}||Is], St);
-check_liveness(R, [{test_heap,N,Live}|Is], St) ->
- I = {block,[{set,[],[],{alloc,Live,{nozero,nostack,N,[]}}}]},
- check_liveness(R, [I|Is], St);
-check_liveness(R, [{allocate_zero,N,Live}|Is], St) ->
- I = {block,[{set,[],[],{alloc,Live,{zero,N,0,[]}}}]},
- check_liveness(R, [I|Is], St);
-check_liveness(R, [{get_list,S,D1,D2}|Is], St) ->
- I = {block,[{set,[D1,D2],[S],get_list}]},
- check_liveness(R, [I|Is], St);
-check_liveness(_R, Is, St) when is_list(Is) ->
- %% Not implemented. Conservatively assume that the register is used.
- {used,St}.
-
-check_liveness_everywhere(R, Lbls, St0) ->
- check_liveness_everywhere_1(R, Lbls, killed, St0).
-
-check_liveness_everywhere_1(R, [{f,Lbl}|T], Res0, St0) ->
- {Res1,St} = check_liveness_at(R, Lbl, St0),
- Res = case Res1 of
- killed -> Res0;
- _ -> Res1
- end,
- case Res of
- used -> {used,St};
- _ -> check_liveness_everywhere_1(R, T, Res, St)
- end;
-check_liveness_everywhere_1(R, [_|T], Res, St) ->
- check_liveness_everywhere_1(R, T, Res, St);
-check_liveness_everywhere_1(_, [], Res, St) ->
- {Res,St}.
-
-check_liveness_at(R, Lbl, #live{lbl=Ll,res=ResMemorized}=St0) ->
- case gb_trees:lookup(Lbl, ResMemorized) of
- {value,Res} ->
- {Res,St0};
- none ->
- {Res,St} = case gb_trees:lookup(Lbl, Ll) of
- {value,Is} -> check_liveness(R, Is, St0);
- none -> {used,St0}
- end,
- {Res,St#live{res=gb_trees:insert(Lbl, Res, St#live.res)}}
+replace_labels_1([{test,Test,{f,Lbl},Ops}|Is], Acc, D, Fb) ->
+ replace_labels_1(Is, [{test,Test,{f,label(Lbl, D, Fb)},Ops}|Acc], D, Fb);
+replace_labels_1([{test,Test,{f,Lbl},Live,Ops,Dst}|Is], Acc, D, Fb) ->
+ replace_labels_1(Is, [{test,Test,{f,label(Lbl, D, Fb)},Live,Ops,Dst}|Acc], D, Fb);
+replace_labels_1([{select,I,R,{f,Fail0},Vls0}|Is], Acc, D, Fb) ->
+ Vls = map(fun ({f,L}) -> {f,label(L, D, Fb)};
+ (Other) -> Other
+ end, Vls0),
+ Fail = label(Fail0, D, Fb),
+ replace_labels_1(Is, [{select,I,R,{f,Fail},Vls}|Acc], D, Fb);
+replace_labels_1([{'try',R,{f,Lbl}}|Is], Acc, D, Fb) ->
+ replace_labels_1(Is, [{'try',R,{f,label(Lbl, D, Fb)}}|Acc], D, Fb);
+replace_labels_1([{'catch',R,{f,Lbl}}|Is], Acc, D, Fb) ->
+ replace_labels_1(Is, [{'catch',R,{f,label(Lbl, D, Fb)}}|Acc], D, Fb);
+replace_labels_1([{jump,{f,Lbl}}|Is], Acc, D, Fb) ->
+ replace_labels_1(Is, [{jump,{f,label(Lbl, D, Fb)}}|Acc], D, Fb);
+replace_labels_1([{loop_rec,{f,Lbl},R}|Is], Acc, D, Fb) ->
+ replace_labels_1(Is, [{loop_rec,{f,label(Lbl, D, Fb)},R}|Acc], D, Fb);
+replace_labels_1([{loop_rec_end,{f,Lbl}}|Is], Acc, D, Fb) ->
+ replace_labels_1(Is, [{loop_rec_end,{f,label(Lbl, D, Fb)}}|Acc], D, Fb);
+replace_labels_1([{wait,{f,Lbl}}|Is], Acc, D, Fb) ->
+ replace_labels_1(Is, [{wait,{f,label(Lbl, D, Fb)}}|Acc], D, Fb);
+replace_labels_1([{wait_timeout,{f,Lbl},To}|Is], Acc, D, Fb) ->
+ replace_labels_1(Is, [{wait_timeout,{f,label(Lbl, D, Fb)},To}|Acc], D, Fb);
+replace_labels_1([{recv_mark=Op,{f,Lbl}}|Is], Acc, D, Fb) ->
+ replace_labels_1(Is, [{Op,{f,label(Lbl, D, Fb)}}|Acc], D, Fb);
+replace_labels_1([{recv_set=Op,{f,Lbl}}|Is], Acc, D, Fb) ->
+ replace_labels_1(Is, [{Op,{f,label(Lbl, D, Fb)}}|Acc], D, Fb);
+replace_labels_1([{bif,Name,{f,Lbl},As,R}|Is], Acc, D, Fb) when Lbl =/= 0 ->
+ replace_labels_1(Is, [{bif,Name,{f,label(Lbl, D, Fb)},As,R}|Acc], D, Fb);
+replace_labels_1([{gc_bif,Name,{f,Lbl},Live,As,R}|Is], Acc, D, Fb) when Lbl =/= 0 ->
+ replace_labels_1(Is, [{gc_bif,Name,{f,label(Lbl, D, Fb)},Live,As,R}|Acc], D, Fb);
+replace_labels_1([{call,Ar,{f,Lbl}}|Is], Acc, D, Fb) ->
+ replace_labels_1(Is, [{call,Ar,{f,label(Lbl, D, Fb)}}|Acc], D, Fb);
+replace_labels_1([{make_fun2,{f,Lbl},U1,U2,U3}|Is], Acc, D, Fb) ->
+ replace_labels_1(Is, [{make_fun2,{f,label(Lbl, D, Fb)},U1,U2,U3}|Acc], D, Fb);
+replace_labels_1([{bs_init,{f,Lbl},Info,Live,Ss,Dst}|Is], Acc, D, Fb) when Lbl =/= 0 ->
+ replace_labels_1(Is, [{bs_init,{f,label(Lbl, D, Fb)},Info,Live,Ss,Dst}|Acc], D, Fb);
+replace_labels_1([{bs_put,{f,Lbl},Info,Ss}|Is], Acc, D, Fb) when Lbl =/= 0 ->
+ replace_labels_1(Is, [{bs_put,{f,label(Lbl, D, Fb)},Info,Ss}|Acc], D, Fb);
+replace_labels_1([{put_map=I,{f,Lbl},Op,Src,Dst,Live,List}|Is], Acc, D, Fb)
+ when Lbl =/= 0 ->
+ replace_labels_1(Is, [{I,{f,label(Lbl, D, Fb)},Op,Src,Dst,Live,List}|Acc], D, Fb);
+replace_labels_1([{get_map_elements=I,{f,Lbl},Src,List}|Is], Acc, D, Fb) when Lbl =/= 0 ->
+ replace_labels_1(Is, [{I,{f,label(Lbl, D, Fb)},Src,List}|Acc], D, Fb);
+replace_labels_1([I|Is], Acc, D, Fb) ->
+ replace_labels_1(Is, [I|Acc], D, Fb);
+replace_labels_1([], Acc, _, _) -> Acc.
+
+label(Old, D, Fb) ->
+ case D of
+ #{Old := New} -> New;
+ _ -> Fb(Old)
end.
-not_used({killed,St}) -> {not_used,St};
-not_used({_,_}=Res) -> Res.
-
-check_liveness_ret(R, R, St) -> {used,St};
-check_liveness_ret(_, _, St) -> {killed,St}.
-
-%% check_liveness_block(Reg, [Instruction], State) ->
-%% {killed | not_used | used | transparent,State'}
-%% Finds out how Reg is used in the instruction sequence inside a block.
-%% Returns one of:
-%% killed - Reg is assigned a new value or killed by an
-%% allocation instruction
-%% not_used - The value is not used, but the register is referenced
-%% e.g. by an allocation instruction
-%% transparent - Reg is neither used nor killed
-%% used - Reg is explicitly used by an instruction
-%%
-%% '%live' annotations are not allowed.
-%%
-%% (Unknown instructions will cause an exception.)
-
-check_liveness_block({x,X}=R, [{set,Ds,Ss,{alloc,Live,Op}}|Is], St0) ->
- if
- X >= Live ->
- {killed,St0};
- true ->
- case check_liveness_block_1(R, Ss, Ds, Op, Is, St0) of
- {killed,St} -> {not_used,St};
- {transparent,St} -> {not_used,St};
- {_,_}=Res -> Res
- end
- end;
-check_liveness_block({y,_}=R, [{set,Ds,Ss,{alloc,_Live,Op}}|Is], St) ->
- check_liveness_block_1(R, Ss, Ds, Op, Is, St);
-check_liveness_block(R, [{set,Ds,Ss,Op}|Is], St) ->
- check_liveness_block_1(R, Ss, Ds, Op, Is, St);
-check_liveness_block(_, [], St) -> {transparent,St}.
-
-check_liveness_block_1(R, Ss, Ds, Op, Is, St0) ->
- case member(R, Ss) of
- true ->
- {used,St0};
- false ->
- case check_liveness_block_2(R, Op, Ss, St0) of
- {killed,St} ->
- case member(R, Ds) of
- true -> {killed,St};
- false -> check_liveness_block(R, Is, St)
- end;
- {not_used,St} ->
- not_used(case member(R, Ds) of
- true -> {killed,St};
- false -> check_liveness_block(R, Is, St)
- end);
- {used,St} ->
- {used,St}
- end
- end.
-
-check_liveness_block_2(R, {gc_bif,_Op,{f,Lbl}}, _Ss, St) ->
- check_liveness_block_3(R, Lbl, St);
-check_liveness_block_2(R, {bif,Op,{f,Lbl}}, Ss, St) ->
- Arity = length(Ss),
- case erl_internal:comp_op(Op, Arity) orelse
- erl_internal:new_type_test(Op, Arity) of
- true ->
- {killed,St};
- false ->
- check_liveness_block_3(R, Lbl, St)
- end;
-check_liveness_block_2(R, {put_map,_Op,{f,Lbl}}, _Ss, St) ->
- check_liveness_block_3(R, Lbl, St);
-check_liveness_block_2(_, _, _, St) ->
- {killed,St}.
-
-check_liveness_block_3(_, 0, St) ->
- {killed,St};
-check_liveness_block_3(R, Lbl, St0) ->
- check_liveness_at(R, Lbl, St0).
-
-index_labels_1([{label,Lbl}|Is0], Acc) ->
- Is = drop_labels(Is0),
- index_labels_1(Is0, [{Lbl,Is}|Acc]);
-index_labels_1([_|Is], Acc) ->
- index_labels_1(Is, Acc);
-index_labels_1([], Acc) -> gb_trees:from_orddict(sort(Acc)).
-
-drop_labels([{label,_}|Is]) -> drop_labels(Is);
-drop_labels(Is) -> Is.
-
-%% Help functions for combine_heap_needs.
-
-combine_alloc_lists(Al1, Al2) ->
- combine_alloc_lists_1(sort(Al1++Al2)).
-
-combine_alloc_lists_1([{words,W1},{words,W2}|T])
- when is_integer(W1), is_integer(W2) ->
- [{words,W1+W2}|combine_alloc_lists_1(T)];
-combine_alloc_lists_1([{floats,F1},{floats,F2}|T])
- when is_integer(F1), is_integer(F2) ->
- [{floats,F1+F2}|combine_alloc_lists_1(T)];
-combine_alloc_lists_1([{words,_}=W|T]) ->
- [W|combine_alloc_lists_1(T)];
-combine_alloc_lists_1([{floats,_}=F|T]) ->
- [F|combine_alloc_lists_1(T)];
-combine_alloc_lists_1([]) -> [].
-
-%% live_opt/4.
-
-%% Bit syntax instructions.
-live_opt([{bs_context_to_binary,Src}=I|Is], Regs0, D, Acc) ->
- Regs = x_live([Src], Regs0),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_init,Fail,_,none,Ss,Dst}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live(Ss, x_dead([Dst], Regs0)),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_init,Fail,Info,Live0,Ss,Dst}|Is], Regs0, D, Acc) ->
- Regs1 = x_dead([Dst], Regs0),
- Live = live_regs(Regs1),
- true = Live =< Live0, %Assertion.
- Regs2 = live_call(Live),
- Regs3 = x_live(Ss, Regs2),
- Regs = live_join_label(Fail, D, Regs3),
- I = {bs_init,Fail,Info,Live,Ss,Dst},
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_put,Fail,_,Ss}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live(Ss, Regs0),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_restore2,Src,_}=I|Is], Regs0, D, Acc) ->
- Regs = x_live([Src], Regs0),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_save2,Src,_}=I|Is], Regs0, D, Acc) ->
- Regs = x_live([Src], Regs0),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{test,bs_start_match2,Fail,Live,[Src,_],_}=I|Is], _, D, Acc) ->
- Regs0 = live_call(Live),
- Regs1 = x_live([Src], Regs0),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-
-%% Other instructions.
-live_opt([{block,Bl0}|Is], Regs0, D, Acc) ->
- Live0 = {'%live',live_regs(Regs0),Regs0},
- {Bl,Regs} = live_opt_block(reverse(Bl0), Regs0, D, [Live0]),
- Live = {'%live',live_regs(Regs),Regs},
- live_opt(Is, Regs, D, [{block,[Live|Bl]}|Acc]);
-live_opt([{label,L}=I|Is], Regs, D0, Acc) ->
- D = gb_trees:insert(L, Regs, D0),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{jump,{f,L}}=I|Is], _, D, Acc) ->
- Regs = gb_trees:get(L, D),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([return=I|Is], _, D, Acc) ->
- live_opt(Is, 1, D, [I|Acc]);
-live_opt([{catch_end,_}=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(1), D, [I|Acc]);
-live_opt([{badmatch,Src}=I|Is], _, D, Acc) ->
- Regs = x_live([Src], 0),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{case_end,Src}=I|Is], _, D, Acc) ->
- Regs = x_live([Src], 0),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{try_case_end,Src}=I|Is], _, D, Acc) ->
- Regs = x_live([Src], 0),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([if_end=I|Is], _, D, Acc) ->
- Regs = 0,
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{call,Arity,_}=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(Arity), D, [I|Acc]);
-live_opt([{call_ext,Arity,_}=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(Arity), D, [I|Acc]);
-live_opt([{call_fun,Arity}=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(Arity+1), D, [I|Acc]);
-live_opt([{apply,Arity}=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(Arity+2), D, [I|Acc]);
-live_opt([{make_fun2,_,_,_,Arity}=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(Arity), D, [I|Acc]);
-live_opt([{test,_,Fail,Ss}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live(Ss, Regs0),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{test,_,Fail,Live,Ss,_}=I|Is], _, D, Acc) ->
- Regs0 = live_call(Live),
- Regs1 = x_live(Ss, Regs0),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{select,_,Src,Fail,List}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live([Src], Regs0),
- Regs = live_join_labels([Fail|List], D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{try_case,_}=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(1), D, [I|Acc]);
-live_opt([{loop_rec,_Fail,_Dst}=I|Is], _, D, Acc) ->
- live_opt(Is, 0, D, [I|Acc]);
-live_opt([timeout=I|Is], _, D, Acc) ->
- live_opt(Is, 0, D, [I|Acc]);
-live_opt([{wait,_}=I|Is], _, D, Acc) ->
- live_opt(Is, 0, D, [I|Acc]);
-live_opt([{get_map_elements,Fail,Src,{list,List}}=I|Is], Regs0, D, Acc) ->
- {Ss,Ds} = split_even(List),
- Regs1 = x_live([Src|Ss], x_dead(Ds, Regs0)),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-
-%% Transparent instructions - they neither use nor modify x registers.
-live_opt([{deallocate,_}=I|Is], Regs, D, Acc) ->
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{kill,_}=I|Is], Regs, D, Acc) ->
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{try_end,_}=I|Is], Regs, D, Acc) ->
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{loop_rec_end,_}=I|Is], Regs, D, Acc) ->
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{wait_timeout,_,nil}=I|Is], Regs, D, Acc) ->
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{wait_timeout,_,{Tag,_}}=I|Is], Regs, D, Acc) when Tag =/= x ->
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{line,_}=I|Is], Regs, D, Acc) ->
- live_opt(Is, Regs, D, [I|Acc]);
-
-%% The following instructions can occur if the "compilation" has been
-%% started from a .S file using the 'from_asm' option.
-live_opt([{trim,_,_}=I|Is], Regs, D, Acc) ->
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{'%',_}=I|Is], Regs, D, Acc) ->
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{recv_set,_}=I|Is], Regs, D, Acc) ->
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{recv_mark,_}=I|Is], Regs, D, Acc) ->
- live_opt(Is, Regs, D, [I|Acc]);
-
-live_opt([], _, _, Acc) -> Acc.
-
-live_opt_block([{set,Ds,Ss,Op0}|Is], Regs0, D, Acc) ->
- Regs1 = x_live(Ss, x_dead(Ds, Regs0)),
- {Op, Regs} = live_opt_block_op(Op0, Regs1, D),
- I = {set, Ds, Ss, Op},
-
- case Ds of
- [{x,X}] ->
- case (not is_live(X, Regs0)) andalso Op =:= move of
- true ->
- live_opt_block(Is, Regs0, D, Acc);
- false ->
- live_opt_block(Is, Regs, D, [I|Acc])
- end;
- _ ->
- live_opt_block(Is, Regs, D, [I|Acc])
- end;
-live_opt_block([{'%live',_,_}|Is], Regs, D, Acc) ->
- live_opt_block(Is, Regs, D, Acc);
-live_opt_block([], Regs, _, Acc) -> {Acc,Regs}.
-
-live_opt_block_op({alloc,Live0,AllocOp}, Regs0, D) ->
- Regs =
- case AllocOp of
- {Kind, _N, Fail} when Kind =:= gc_bif; Kind =:= put_map ->
- live_join_label(Fail, D, Regs0);
- _ ->
- Regs0
- end,
-
- %% The life-time analysis used by the code generator is sometimes too
- %% conservative, so it may be possible to lower the number of live
- %% registers based on the exact liveness information. The main benefit is
- %% that more optimizations that depend on liveness information (such as the
- %% beam_bool and beam_dead passes) may be applied.
- Live = live_regs(Regs),
- true = Live =< Live0,
- {{alloc,Live,AllocOp}, live_call(Live)};
-live_opt_block_op({bif,_N,Fail} = Op, Regs, D) ->
- {Op, live_join_label(Fail, D, Regs)};
-live_opt_block_op(Op, Regs, _D) ->
- {Op, Regs}.
-
-live_join_labels([{f,L}|T], D, Regs0) when L =/= 0 ->
- Regs = gb_trees:get(L, D) bor Regs0,
- live_join_labels(T, D, Regs);
-live_join_labels([_|T], D, Regs) ->
- live_join_labels(T, D, Regs);
-live_join_labels([], _, Regs) -> Regs.
-
-live_join_label({f,0}, _, Regs) ->
- Regs;
-live_join_label({f,L}, D, Regs) ->
- gb_trees:get(L, D) bor Regs.
-
-live_call(Live) -> (1 bsl Live) - 1.
-
-live_regs(Regs) ->
- live_regs_1(0, Regs).
-
-live_regs_1(N, 0) -> N;
-live_regs_1(N, Regs) -> live_regs_1(N+1, Regs bsr 1).
-
-x_dead([{x,N}|Rs], Regs) -> x_dead(Rs, Regs band (bnot (1 bsl N)));
-x_dead([_|Rs], Regs) -> x_dead(Rs, Regs);
-x_dead([], Regs) -> Regs.
-
-x_live([{x,N}|Rs], Regs) -> x_live(Rs, Regs bor (1 bsl N));
-x_live([_|Rs], Regs) -> x_live(Rs, Regs);
-x_live([], Regs) -> Regs.
-
-is_live(X, Regs) -> ((Regs bsr X) band 1) =:= 1.
-
split_even([], Ss, Ds) ->
{reverse(Ss),reverse(Ds)};
split_even([S,D|Rs], Ss, Ds) ->
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl
index ea38969814..09a5a6c104 100644
--- a/lib/compiler/src/beam_validator.erl
+++ b/lib/compiler/src/beam_validator.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,10 +26,9 @@
%% Interface for compiler.
-export([module/2, format_error/1]).
+-export([type_anno/1, type_anno/2, type_anno/4]).
--include("beam_disasm.hrl").
-
--import(lists, [reverse/1,foldl/3,foreach/2,dropwhile/2]).
+-import(lists, [dropwhile/2,foldl/3,member/2,reverse/1,sort/1,zip/2]).
%% To be called by the compiler.
@@ -46,6 +45,34 @@ module({Mod,Exp,Attr,Fs,Lc}=Code, _Opts)
{error,[{atom_to_list(Mod),Es}]}
end.
+%% Provides a stable interface for type annotations, used by certain passes to
+%% indicate that we can safely assume that a register has a given type.
+-spec type_anno(term()) -> term().
+type_anno(atom) -> {atom,[]};
+type_anno(bool) -> bool;
+type_anno({binary,_}) -> binary;
+type_anno(cons) -> cons;
+type_anno(float) -> {float,[]};
+type_anno(integer) -> {integer,[]};
+type_anno(list) -> list;
+type_anno(map) -> map;
+type_anno(match_context) -> match_context;
+type_anno(number) -> number;
+type_anno(nil) -> nil.
+
+-spec type_anno(term(), term()) -> term().
+type_anno(atom, Value) when is_atom(Value) -> {atom, Value};
+type_anno(float, Value) when is_float(Value) -> {float, Value};
+type_anno(integer, Value) when is_integer(Value) -> {integer, Value}.
+
+-spec type_anno(term(), term(), term(), term()) -> term().
+type_anno(tuple, Size, Exact, Elements) when is_integer(Size), Size >= 0,
+ is_map(Elements) ->
+ case Exact of
+ true -> {tuple, Size, Elements};
+ false -> {tuple, [Size], Elements}
+ end.
+
-spec format_error(term()) -> iolist().
format_error({{_M,F,A},{I,Off,limit}}) ->
@@ -85,8 +112,6 @@ format_error(Error) ->
%%% Things currently not checked. XXX
%%%
%%% - Heap allocation for binaries.
-%%% - That put_tuple is followed by the correct number of
-%%% put instructions.
%%%
%% validate(Module, [Function]) -> [] | [Error]
@@ -94,34 +119,9 @@ format_error(Error) ->
%% format as used in the compiler and in .S files.
validate(Module, Fs) ->
- Ft = index_bs_start_match(Fs, []),
+ Ft = index_parameter_types(Fs, []),
validate_0(Module, Fs, Ft).
-index_bs_start_match([{function,_,_,Entry,Code0}|Fs], Acc0) ->
- Code = dropwhile(fun({label,L}) when L =:= Entry -> false;
- (_) -> true
- end, Code0),
- case Code of
- [{label,Entry}|Is] ->
- Acc = index_bs_start_match_1(Is, Entry, Acc0),
- index_bs_start_match(Fs, Acc);
- _ ->
- %% Something serious is wrong. Ignore it for now.
- %% It will be detected and diagnosed later.
- index_bs_start_match(Fs, Acc0)
- end;
-index_bs_start_match([], Acc) ->
- gb_trees:from_orddict(lists:sort(Acc)).
-
-index_bs_start_match_1([{test,bs_start_match2,_,_,_,_}=I|_], Entry, Acc) ->
- [{Entry,[I]}|Acc];
-index_bs_start_match_1([{test,_,{f,F},_},{bs_context_to_binary,_}|Is0], Entry, Acc) ->
- [{label,F}|Is] = dropwhile(fun({label,L}) when L =:= F -> false;
- (_) -> true
- end, Is0),
- index_bs_start_match_1(Is, Entry, Acc);
-index_bs_start_match_1(_, _, Acc) -> Acc.
-
validate_0(_Module, [], _) -> [];
validate_0(Module, [{function,Name,Ar,Entry,Code}|Fs], Ft) ->
try validate_1(Code, Name, Ar, Entry, Ft) of
@@ -130,47 +130,132 @@ validate_0(Module, [{function,Name,Ar,Entry,Code}|Fs], Ft) ->
throw:Error ->
%% Controlled error.
[Error|validate_0(Module, Fs, Ft)];
- Class:Error ->
+ Class:Error:Stack ->
%% Crash.
- Stack = erlang:get_stacktrace(),
io:fwrite("Function: ~w/~w\n", [Name,Ar]),
erlang:raise(Class, Error, Stack)
end.
+-record(value_ref, {id :: index()}).
+-record(value, {op :: term(), args :: [argument()], type :: type()}).
+
+-type argument() :: #value_ref{} | literal().
+
-type index() :: non_neg_integer().
--type reg_tab() :: gb_trees:tree(index(), 'none' | {'value', _}).
-
--record(st, %Emulation state
- {x=init_regs(0, term) :: reg_tab(),%x register info.
- y=init_regs(0, initialized) :: reg_tab(),%y register info.
- f=init_fregs(), %
- numy=none, %Number of y registers.
- h=0, %Available heap size.
- hf=0, %Available heap size for floats.
- fls=undefined, %Floating point state.
- ct=[], %List of hot catch/try labels
- setelem=false %Previous instruction was setelement/3.
- }).
+
+-type literal() :: {atom, [] | atom()} |
+ {float, [] | float()} |
+ {integer, [] | integer()} |
+ {literal, term()} |
+ nil.
+
+-type tuple_sz() :: [non_neg_integer()] | %% Inexact
+ non_neg_integer(). %% Exact.
+
+%% Match context type.
+-record(ms,
+ {id=make_ref() :: reference(), %Unique ID.
+ valid=0 :: non_neg_integer(), %Valid slots
+ slots=0 :: non_neg_integer() %Number of slots
+ }).
+
+-type type() :: binary |
+ cons |
+ list |
+ map |
+ nil |
+ #ms{} |
+ ms_position |
+ none |
+ number |
+ term |
+ tuple_in_progress |
+ {tuple, tuple_sz(), #{ literal() => type() }} |
+ literal().
+
+-type tag() :: initialized |
+ uninitialized |
+ {catchtag, [label()]} |
+ {trytag, [label()]}.
+
+-type x_regs() :: #{ {x, index()} => #value_ref{} }.
+-type y_regs() :: #{ {y, index()} => tag() | #value_ref{} }.
+
+%% Emulation state
+-record(st,
+ {%% All known values.
+ vs=#{} :: #{ #value_ref{} => #value{} },
+ %% Register states.
+ xs=#{} :: x_regs(),
+ ys=#{} :: y_regs(),
+ f=init_fregs(),
+ %% A set of all registers containing "fragile" terms. That is, terms
+ %% that don't exist on our process heap and would be destroyed by a
+ %% GC.
+ fragile=cerl_sets:new() :: cerl_sets:set(),
+ %% Number of Y registers.
+ %%
+ %% Note that this may be 0 if there's a frame without saved values,
+ %% such as on a body-recursive call.
+ numy=none :: none | undecided | index(),
+ %% Available heap size.
+ h=0,
+ %Available heap size for floats.
+ hf=0,
+ %% Floating point state.
+ fls=undefined,
+ %% List of hot catch/try labels
+ ct=[],
+ %% Previous instruction was setelement/3.
+ setelem=false,
+ %% put/1 instructions left.
+ puts_left=none
+ }).
-type label() :: integer().
-type label_set() :: gb_sets:set(label()).
-type branched_tab() :: gb_trees:tree(label(), #st{}).
-type ft_tab() :: gb_trees:tree().
--record(vst, %Validator state
- {current=none :: #st{} | 'none', %Current state
- branched=gb_trees:empty() :: branched_tab(), %States at jumps
- labels=gb_sets:empty() :: label_set(), %All defined labels
- ft=gb_trees:empty() :: ft_tab() %Some other functions
- % in the module (those that start with bs_start_match2).
- }).
-
-%% Match context type.
--record(ms,
- {id=make_ref() :: reference(), %Unique ID.
- valid=0 :: non_neg_integer(), %Valid slots
- slots=0 :: non_neg_integer() %Number of slots
- }).
+%% Validator state
+-record(vst,
+ {%% Current state
+ current=none :: #st{} | 'none',
+ %% States at labels
+ branched=gb_trees:empty() :: branched_tab(),
+ %% All defined labels
+ labels=gb_sets:empty() :: label_set(),
+ %% Argument information of other functions in the module
+ ft=gb_trees:empty() :: ft_tab(),
+ %% Counter for #value_ref{} creation
+ ref_ctr=0 :: index()
+ }).
+
+index_parameter_types([{function,_,_,Entry,Code0}|Fs], Acc0) ->
+ Code = dropwhile(fun({label,L}) when L =:= Entry -> false;
+ (_) -> true
+ end, Code0),
+ case Code of
+ [{label,Entry}|Is] ->
+ Acc = index_parameter_types_1(Is, Entry, Acc0),
+ index_parameter_types(Fs, Acc);
+ _ ->
+ %% Something serious is wrong. Ignore it for now.
+ %% It will be detected and diagnosed later.
+ index_parameter_types(Fs, Acc0)
+ end;
+index_parameter_types([], Acc) ->
+ gb_trees:from_orddict(sort(Acc)).
+
+index_parameter_types_1([{'%', {type_info, Reg, Type0}} | Is], Entry, Acc) ->
+ Type = case Type0 of
+ match_context -> #ms{};
+ _ -> Type0
+ end,
+ Key = {Entry, Reg},
+ index_parameter_types_1(Is, Entry, [{Key, Type} | Acc]);
+index_parameter_types_1(_, _, Acc) ->
+ Acc.
validate_1(Is, Name, Arity, Entry, Ft) ->
validate_2(labels(Is), Name, Arity, Entry, Ft).
@@ -183,14 +268,10 @@ validate_2({Ls1,Is}, Name, Arity, _Entry, _Ft) ->
validate_3({Ls2,Is}, Name, Arity, Entry, Mod, Ls1, Ft) ->
Offset = 1 + length(Ls1) + 1 + length(Ls2),
- EntryOK = lists:member(Entry, Ls2),
+ EntryOK = member(Entry, Ls2),
if
EntryOK ->
- St = init_state(Arity),
- Vst0 = #vst{current=St,
- branched=gb_trees_from_list([{L,St} || L <- Ls1]),
- labels=gb_sets:from_list(Ls1++Ls2),
- ft=Ft},
+ Vst0 = init_vst(Arity, Ls1, Ls2, Ft),
MFA = {Mod,Name,Arity},
Vst = valfun(Is, MFA, Offset, Vst0),
validate_fun_info_branches(Ls1, MFA, Vst);
@@ -207,7 +288,13 @@ validate_fun_info_branches([], _, _) -> ok.
validate_fun_info_branches_1(Arity, {_,_,Arity}, _) -> ok;
validate_fun_info_branches_1(X, {Mod,Name,Arity}=MFA, Vst) ->
try
- get_term_type({x,X}, Vst)
+ case Vst of
+ #vst{current=#st{numy=none}} ->
+ ok;
+ #vst{current=#st{numy=Size}} ->
+ error({unexpected_stack_frame,Size})
+ end,
+ assert_term({x,X}, Vst)
catch Error ->
I = {func_info,{atom,Mod},{atom,Name},Arity},
Offset = 2,
@@ -228,19 +315,22 @@ labels_1([{line,_}|Is], R) ->
labels_1(Is, R) ->
{reverse(R),Is}.
-init_state(Arity) ->
- Xs = init_regs(Arity, term),
- Ys = init_regs(0, initialized),
- kill_heap_allocation(#st{x=Xs,y=Ys,numy=none,ct=[]}).
+init_vst(Arity, Ls1, Ls2, Ft) ->
+ Vst0 = init_function_args(Arity - 1, #vst{current=#st{}}),
+ Branches = gb_trees_from_list([{L,Vst0#vst.current} || L <- Ls1]),
+ Labels = gb_sets:from_list(Ls1++Ls2),
+ Vst0#vst{branched=Branches,
+ labels=Labels,
+ ft=Ft}.
+
+init_function_args(-1, Vst) ->
+ Vst;
+init_function_args(X, Vst) ->
+ init_function_args(X - 1, create_term(term, argument, [], {x,X}, Vst)).
kill_heap_allocation(St) ->
St#st{h=0,hf=0}.
-init_regs(0, _) ->
- gb_trees:empty();
-init_regs(N, Type) ->
- gb_trees_from_list([{R,Type} || R <- lists:seq(0, N-1)]).
-
valfun([], MFA, _Offset, #vst{branched=Targets0,labels=Labels0}=Vst) ->
Targets = gb_trees:keys(Targets0),
Labels = gb_sets:to_list(Labels0),
@@ -261,50 +351,47 @@ valfun([I|Is], MFA, Offset, Vst0) ->
%% Instructions that are allowed in dead code or when failing,
%% that is while the state is undecided in some way.
-valfun_1({label,Lbl}, #vst{current=St0,branched=B,labels=Lbls}=Vst) ->
- St = merge_states(Lbl, St0, B),
- Vst#vst{current=St,branched=gb_trees:enter(Lbl, St, B),
- labels=gb_sets:add(Lbl, Lbls)};
+valfun_1({label,Lbl}, #vst{current=St0,
+ ref_ctr=Counter0,
+ branched=B,
+ labels=Lbls}=Vst) ->
+ {St, Counter} = merge_states(Lbl, St0, B, Counter0),
+ Vst#vst{current=St,
+ ref_ctr=Counter,
+ branched=gb_trees:enter(Lbl, St, B),
+ labels=gb_sets:add(Lbl, Lbls)};
valfun_1(_I, #vst{current=none}=Vst) ->
%% Ignore instructions after erlang:error/1,2, which
%% the original R10B compiler thought would return.
Vst;
valfun_1({badmatch,Src}, Vst) ->
- assert_term(Src, Vst),
+ assert_durable_term(Src, Vst),
+ verify_y_init(Vst),
kill_state(Vst);
valfun_1({case_end,Src}, Vst) ->
- assert_term(Src, Vst),
+ assert_durable_term(Src, Vst),
+ verify_y_init(Vst),
kill_state(Vst);
valfun_1(if_end, Vst) ->
+ verify_y_init(Vst),
kill_state(Vst);
valfun_1({try_case_end,Src}, Vst) ->
- assert_term(Src, Vst),
+ verify_y_init(Vst),
+ assert_durable_term(Src, Vst),
kill_state(Vst);
-%% Instructions that can not cause exceptions
-valfun_1({bs_context_to_binary,Ctx}, #vst{current=#st{x=Xs}}=Vst) ->
- case Ctx of
- {Tag,X} when Tag =:= x; Tag =:= y ->
- Type = case gb_trees:lookup(X, Xs) of
- {value,#ms{}} -> term;
- _ -> get_term_type(Ctx, Vst)
- end,
- set_type_reg(Type, Ctx, Vst);
- _ ->
- error({bad_source,Ctx})
- end;
+%% Instructions that cannot cause exceptions
+valfun_1({bs_get_tail,Ctx,Dst,Live}, Vst0) ->
+ bsm_validate_context(Ctx, Vst0),
+ verify_live(Live, Vst0),
+ verify_y_init(Vst0),
+ Vst = prune_x_regs(Live, Vst0),
+ extract_term(binary, bs_get_tail, [Ctx], Dst, Vst, Vst0);
valfun_1(bs_init_writable=I, Vst) ->
call(I, 1, Vst);
-valfun_1({move,{y,_}=Src,{y,_}=Dst}, Vst) ->
- %% The stack trimming optimization may generate a move from an initialized
- %% but unassigned Y register to another Y register.
- case get_term_type_1(Src, Vst) of
- {catchtag,_} -> error({catchtag,Src});
- {trytag,_} -> error({trytag,Src});
- Type -> set_type_reg(Type, Dst, Vst)
- end;
+valfun_1(build_stacktrace=I, Vst) ->
+ call(I, 1, Vst);
valfun_1({move,Src,Dst}, Vst) ->
- Type = get_move_term_type(Src, Vst),
- set_type_reg(Type, Dst, Vst);
+ assign(Src, Dst, Vst);
valfun_1({fmove,Src,{fr,_}=Dst}, Vst) ->
assert_type(float, Src, Vst),
set_freg(Dst, Vst);
@@ -312,15 +399,15 @@ valfun_1({fmove,{fr,_}=Src,Dst}, Vst0) ->
assert_freg_set(Src, Vst0),
assert_fls(checked, Vst0),
Vst = eat_heap_float(Vst0),
- set_type_reg({float,[]}, Dst, Vst);
-valfun_1({kill,{y,_}=Reg}, Vst) ->
- set_type_y(initialized, Reg, Vst);
-valfun_1({init,{y,_}=Reg}, Vst) ->
- set_type_y(initialized, Reg, Vst);
+ create_term({float,[]}, fmove, [], Dst, Vst);
+valfun_1({kill,Reg}, Vst) ->
+ create_tag(initialized, kill, [], Reg, Vst);
+valfun_1({init,Reg}, Vst) ->
+ create_tag(initialized, init, [], Reg, Vst);
valfun_1({test_heap,Heap,Live}, Vst) ->
test_heap(Heap, Live, Vst);
-valfun_1({bif,Op,{f,_},Src,Dst}=I, Vst) ->
- case is_bif_safe(Op, length(Src)) of
+valfun_1({bif,Op,{f,_},Ss,Dst}=I, Vst) ->
+ case is_bif_safe(Op, length(Ss)) of
false ->
%% Since the BIF can fail, make sure that any catch state
%% is updated.
@@ -328,22 +415,50 @@ valfun_1({bif,Op,{f,_},Src,Dst}=I, Vst) ->
true ->
%% It can't fail, so we finish handling it here (not updating
%% catch state).
- validate_src(Src, Vst),
- Type = bif_type(Op, Src, Vst),
- set_type_reg(Type, Dst, Vst)
+ validate_src(Ss, Vst),
+ Type = bif_return_type(Op, Ss, Vst),
+ extract_term(Type, {bif,Op}, Ss, Dst, Vst)
end;
%% Put instructions.
valfun_1({put_list,A,B,Dst}, Vst0) ->
assert_term(A, Vst0),
assert_term(B, Vst0),
Vst = eat_heap(2, Vst0),
- set_type_reg(cons, Dst, Vst);
+ create_term(cons, put_list, [A, B], Dst, Vst);
+valfun_1({put_tuple2,Dst,{list,Elements}}, Vst0) ->
+ _ = [assert_term(El, Vst0) || El <- Elements],
+ Size = length(Elements),
+ Vst = eat_heap(Size+1, Vst0),
+ {Es,_} = foldl(fun(Val, {Es0, Index}) ->
+ Type = get_term_type(Val, Vst0),
+ Es = set_element_type({integer,Index}, Type, Es0),
+ {Es, Index + 1}
+ end, {#{}, 1}, Elements),
+ Type = {tuple,Size,Es},
+ create_term(Type, put_tuple2, [], Dst, Vst);
valfun_1({put_tuple,Sz,Dst}, Vst0) when is_integer(Sz) ->
+ Vst1 = eat_heap(1, Vst0),
+ Vst = create_term(tuple_in_progress, put_tuple, [], Dst, Vst1),
+ #vst{current=St0} = Vst,
+ St = St0#st{puts_left={Sz,{Dst,Sz,#{}}}},
+ Vst#vst{current=St};
+valfun_1({put,Src}, Vst0) ->
+ assert_term(Src, Vst0),
Vst = eat_heap(1, Vst0),
- set_type_reg({tuple,Sz}, Dst, Vst);
-valfun_1({put,Src}, Vst) ->
- assert_term(Src, Vst),
- eat_heap(1, Vst);
+ #vst{current=St0} = Vst,
+ case St0 of
+ #st{puts_left=none} ->
+ error(not_building_a_tuple);
+ #st{puts_left={1,{Dst,Sz,Es0}}} ->
+ Es = Es0#{ {integer,Sz} => get_term_type(Src, Vst0) },
+ St = St0#st{puts_left=none},
+ create_term({tuple,Sz,Es}, put_tuple, [], Dst, Vst#vst{current=St});
+ #st{puts_left={PutsLeft,{Dst,Sz,Es0}}} when is_integer(PutsLeft) ->
+ Index = Sz - PutsLeft + 1,
+ Es = Es0#{ {integer,Index} => get_term_type(Src, Vst0) },
+ St = St0#st{puts_left={PutsLeft-1,{Dst,Sz,Es}}},
+ Vst#vst{current=St}
+ end;
%% Instructions for optimization of selective receives.
valfun_1({recv_mark,{f,Fail}}, Vst) when is_integer(Fail) ->
Vst;
@@ -351,16 +466,36 @@ valfun_1({recv_set,{f,Fail}}, Vst) when is_integer(Fail) ->
Vst;
%% Misc.
valfun_1(remove_message, Vst) ->
- Vst;
+ %% The message term is no longer fragile. It can be used
+ %% without restrictions.
+ remove_fragility(Vst);
+valfun_1({'%', {type_info, Reg, match_context}}, Vst) ->
+ update_type(fun meet/2, #ms{}, Reg, Vst);
+valfun_1({'%', {type_info, Reg, Type}}, Vst) ->
+ %% Explicit type information inserted by optimization passes to indicate
+ %% that Reg has a certain type, so that we can accept cross-function type
+ %% optimizations.
+ update_type(fun meet/2, Type, Reg, Vst);
+valfun_1({'%', {remove_fragility, Reg}}, Vst) ->
+ %% This is a hack to make prim_eval:'receive'/2 work.
+ %%
+ %% Normally it's illegal to pass fragile terms as a function argument as we
+ %% have no way of knowing what the callee will do with it, but we know that
+ %% prim_eval:'receive'/2 won't leak the term, nor cause a GC since it's
+ %% disabled while matching messages.
+ remove_fragility(Reg, Vst);
valfun_1({'%',_}, Vst) ->
Vst;
valfun_1({line,_}, Vst) ->
Vst;
%% Exception generating calls
valfun_1({call_ext,Live,Func}=I, Vst) ->
- case return_type(Func, Vst) of
+ case call_return_type(Func, Vst) of
exception ->
verify_live(Live, Vst),
+ %% The stack will be scanned, so Y registers
+ %% must be initialized.
+ verify_y_init(Vst),
kill_state(Vst);
_ ->
valfun_2(I, Vst)
@@ -370,75 +505,122 @@ valfun_1(_I, #vst{current=#st{ct=undecided}}) ->
%%
%% Allocate and deallocate, et.al
valfun_1({allocate,Stk,Live}, Vst) ->
- allocate(false, Stk, 0, Live, Vst);
+ allocate(uninitialized, Stk, 0, Live, Vst);
valfun_1({allocate_heap,Stk,Heap,Live}, Vst) ->
- allocate(false, Stk, Heap, Live, Vst);
+ allocate(uninitialized, Stk, Heap, Live, Vst);
valfun_1({allocate_zero,Stk,Live}, Vst) ->
- allocate(true, Stk, 0, Live, Vst);
+ allocate(initialized, Stk, 0, Live, Vst);
valfun_1({allocate_heap_zero,Stk,Heap,Live}, Vst) ->
- allocate(true, Stk, Heap, Live, Vst);
+ allocate(initialized, Stk, Heap, Live, Vst);
valfun_1({deallocate,StkSize}, #vst{current=#st{numy=StkSize}}=Vst) ->
verify_no_ct(Vst),
deallocate(Vst);
valfun_1({deallocate,_}, #vst{current=#st{numy=NumY}}) ->
error({allocated,NumY});
-valfun_1({trim,N,Remaining}, #vst{current=#st{y=Yregs0,numy=NumY}=St}=Vst) ->
+valfun_1({trim,N,Remaining}, #vst{current=St0}=Vst) ->
+ #st{numy=NumY} = St0,
if
- N =< NumY, N+Remaining =:= NumY ->
- Yregs1 = [{Y-N,Type} || {Y,Type} <- gb_trees:to_list(Yregs0), Y >= N],
- Yregs = gb_trees_from_list(Yregs1),
- Vst#vst{current=St#st{y=Yregs,numy=NumY-N}};
- true ->
- error({trim,N,Remaining,allocated,NumY})
+ N =< NumY, N+Remaining =:= NumY ->
+ Vst#vst{current=trim_stack(N, 0, NumY, St0)};
+ N > NumY; N+Remaining =/= NumY ->
+ error({trim,N,Remaining,allocated,NumY})
end;
%% Catch & try.
-valfun_1({'catch',Dst,{f,Fail}}, Vst0) when Fail /= none ->
- Vst = #vst{current=#st{ct=Fails}=St} =
- set_type_y({catchtag,[Fail]}, Dst, Vst0),
- Vst#vst{current=St#st{ct=[[Fail]|Fails]}};
-valfun_1({'try',Dst,{f,Fail}}, Vst0) ->
- Vst = #vst{current=#st{ct=Fails}=St} =
- set_type_y({trytag,[Fail]}, Dst, Vst0),
- Vst#vst{current=St#st{ct=[[Fail]|Fails]}};
-valfun_1({catch_end,Reg}, #vst{current=#st{ct=[Fail|Fails]}}=Vst0) ->
- case get_special_y_type(Reg, Vst0) of
- {catchtag,Fail} ->
- Vst = #vst{current=St} = set_catch_end(Reg, Vst0),
- Xs = gb_trees_from_list([{0,term}]),
- Vst#vst{current=St#st{x=Xs,ct=Fails,fls=undefined}};
- Type ->
- error({bad_type,Type})
+valfun_1({'catch',Dst,{f,Fail}}, Vst) when Fail =/= none ->
+ init_try_catch_branch(catchtag, Dst, Fail, Vst);
+valfun_1({'try',Dst,{f,Fail}}, Vst) when Fail =/= none ->
+ init_try_catch_branch(trytag, Dst, Fail, Vst);
+valfun_1({catch_end,Reg}, #vst{current=#st{ct=[Fail|_]}}=Vst0) ->
+ case get_tag_type(Reg, Vst0) of
+ {catchtag,Fail} ->
+ %% {x,0} contains the caught term, if any.
+ create_term(term, catch_end, [], {x,0}, kill_catch_tag(Reg, Vst0));
+ Type ->
+ error({wrong_tag_type,Type})
end;
-valfun_1({try_end,Reg}, #vst{current=#st{ct=[Fail|Fails]}=St0}=Vst0) ->
- case get_special_y_type(Reg, Vst0) of
- {trytag,Fail} ->
- Vst = case Fail of
- [FailLabel] -> branch_state(FailLabel, Vst0);
- _ -> Vst0
- end,
- St = St0#st{ct=Fails,fls=undefined},
- set_catch_end(Reg, Vst#vst{current=St});
- Type ->
- error({bad_type,Type})
+valfun_1({try_end,Reg}, #vst{current=#st{ct=[Fail|_]}}=Vst) ->
+ case get_tag_type(Reg, Vst) of
+ {trytag,Fail} ->
+ %% Kill the catch tag, note that x registers are unaffected.
+ kill_catch_tag(Reg, Vst);
+ Type ->
+ error({wrong_tag_type,Type})
end;
-valfun_1({try_case,Reg}, #vst{current=#st{ct=[Fail|Fails]}}=Vst0) ->
- case get_special_y_type(Reg, Vst0) of
- {trytag,Fail} ->
- Vst = #vst{current=St} = set_catch_end(Reg, Vst0),
- Xs = gb_trees_from_list([{0,{atom,[]}},{1,term},{2,term}]),
- Vst#vst{current=St#st{x=Xs,ct=Fails,fls=undefined}};
- Type ->
- error({bad_type,Type})
+valfun_1({try_case,Reg}, #vst{current=#st{ct=[Fail|_]}}=Vst0) ->
+ case get_tag_type(Reg, Vst0) of
+ {trytag,Fail} ->
+ %% Kill the catch tag and all x registers.
+ Vst1 = prune_x_regs(0, kill_catch_tag(Reg, Vst0)),
+
+ %% Class:Error:Stacktrace
+ Vst2 = create_term({atom,[]}, try_case, [], {x,0}, Vst1),
+ Vst = create_term(term, try_case, [], {x,1}, Vst2),
+ create_term(term, try_case, [], {x,2}, Vst);
+ Type ->
+ error({wrong_tag_type,Type})
end;
+valfun_1({get_list,Src,D1,D2}, Vst0) ->
+ assert_not_literal(Src),
+ assert_type(cons, Src, Vst0),
+ Vst = extract_term(term, get_hd, [Src], D1, Vst0),
+ extract_term(term, get_tl, [Src], D2, Vst);
+valfun_1({get_hd,Src,Dst}, Vst) ->
+ assert_not_literal(Src),
+ assert_type(cons, Src, Vst),
+ extract_term(term, get_hd, [Src], Dst, Vst);
+valfun_1({get_tl,Src,Dst}, Vst) ->
+ assert_not_literal(Src),
+ assert_type(cons, Src, Vst),
+ extract_term(term, get_tl, [Src], Dst, Vst);
+valfun_1({get_tuple_element,Src,N,Dst}, Vst) ->
+ assert_not_literal(Src),
+ assert_type({tuple_element,N+1}, Src, Vst),
+ Index = {integer,N+1},
+ Type = get_element_type(Index, Src, Vst),
+ extract_term(Type, {bif,element}, [Index, Src], Dst, Vst);
+valfun_1({jump,{f,Lbl}}, Vst) ->
+ branch(Lbl, Vst,
+ fun(SuccVst) ->
+ %% The next instruction is never executed.
+ kill_state(SuccVst)
+ end);
valfun_1(I, Vst) ->
valfun_2(I, Vst).
-%% Update branched state if necessary and try next set of instructions.
-valfun_2(I, #vst{current=#st{ct=[]}}=Vst) ->
- valfun_3(I, Vst);
+init_try_catch_branch(Tag, Dst, Fail, Vst0) ->
+ Vst1 = create_tag({Tag,[Fail]}, 'try_catch', [], Dst, Vst0),
+ #vst{current=#st{ct=Fails}=St0} = Vst1,
+ St = St0#st{ct=[[Fail]|Fails]},
+ Vst = Vst0#vst{current=St},
+
+ branch(Fail, Vst,
+ fun(CatchVst) ->
+ #vst{current=#st{ys=Ys}} = CatchVst,
+ maps:fold(fun init_catch_handler_1/3, CatchVst, Ys)
+ end,
+ fun(SuccVst) ->
+ %% All potentially-throwing instructions after this
+ %% one will implicitly branch to the fail label;
+ %% see valfun_2/2
+ SuccVst
+ end).
+
+%% Set the initial state at the try/catch label. Assume that Y registers
+%% contain terms or try/catch tags.
+init_catch_handler_1(Reg, initialized, Vst) ->
+ create_term(term, 'catch_handler', [], Reg, Vst);
+init_catch_handler_1(Reg, uninitialized, Vst) ->
+ create_term(term, 'catch_handler', [], Reg, Vst);
+init_catch_handler_1(_, _, Vst) ->
+ Vst.
+
valfun_2(I, #vst{current=#st{ct=[[Fail]|_]}}=Vst) when is_integer(Fail) ->
- %% Update branched state
+ %% We have an active try/catch tag and we can jump there from this
+ %% instruction, so we need to update the branched state of the try/catch
+ %% handler.
valfun_3(I, branch_state(Fail, Vst));
+valfun_2(I, #vst{current=#st{ct=[]}}=Vst) ->
+ valfun_3(I, Vst);
valfun_2(_, _) ->
error(ambiguous_catch_try_state).
@@ -446,17 +628,23 @@ valfun_2(_, _) ->
%% Floating point.
valfun_3({fconv,Src,{fr,_}=Dst}, Vst) ->
assert_term(Src, Vst),
- set_freg(Dst, Vst);
-valfun_3({bif,fadd,_,[_,_]=Src,Dst}, Vst) ->
- float_op(Src, Dst, Vst);
-valfun_3({bif,fdiv,_,[_,_]=Src,Dst}, Vst) ->
- float_op(Src, Dst, Vst);
-valfun_3({bif,fmul,_,[_,_]=Src,Dst}, Vst) ->
- float_op(Src, Dst, Vst);
-valfun_3({bif,fnegate,_,[_]=Src,Dst}, Vst) ->
- float_op(Src, Dst, Vst);
-valfun_3({bif,fsub,_,[_,_]=Src,Dst}, Vst) ->
- float_op(Src, Dst, Vst);
+
+ %% An exception is raised on error, hence branching to 0.
+ branch(0, Vst,
+ fun(SuccVst0) ->
+ SuccVst = update_type(fun meet/2, number, Src, SuccVst0),
+ set_freg(Dst, SuccVst)
+ end);
+valfun_3({bif,fadd,_,[_,_]=Ss,Dst}, Vst) ->
+ float_op(Ss, Dst, Vst);
+valfun_3({bif,fdiv,_,[_,_]=Ss,Dst}, Vst) ->
+ float_op(Ss, Dst, Vst);
+valfun_3({bif,fmul,_,[_,_]=Ss,Dst}, Vst) ->
+ float_op(Ss, Dst, Vst);
+valfun_3({bif,fnegate,_,[_]=Ss,Dst}, Vst) ->
+ float_op(Ss, Dst, Vst);
+valfun_3({bif,fsub,_,[_,_]=Ss,Dst}, Vst) ->
+ float_op(Ss, Dst, Vst);
valfun_3(fclearerror, Vst) ->
case get_fls(Vst) of
undefined -> ok;
@@ -507,183 +695,260 @@ valfun_4({call_ext_last,_,_,_}, #vst{current=#st{numy=NumY}}) ->
valfun_4({make_fun2,_,_,_,Live}, Vst) ->
call(make_fun, Live, Vst);
%% Other BIFs
-valfun_4({bif,tuple_size,{f,Fail},[Tuple],Dst}, Vst0) ->
- TupleType0 = get_term_type(Tuple, Vst0),
- Vst1 = branch_state(Fail, Vst0),
- TupleType = upgrade_tuple_type({tuple,[0]}, TupleType0),
- Vst = set_type(TupleType, Tuple, Vst1),
- set_type_reg({integer,[]}, Dst, Vst);
-valfun_4({bif,element,{f,Fail},[Pos,Tuple],Dst}, Vst0) ->
- TupleType0 = get_term_type(Tuple, Vst0),
- PosType = get_term_type(Pos, Vst0),
- Vst1 = branch_state(Fail, Vst0),
- TupleType = upgrade_tuple_type({tuple,[get_tuple_size(PosType)]}, TupleType0),
- Vst = set_type(TupleType, Tuple, Vst1),
- set_type_reg(term, Dst, Vst);
+valfun_4({bif,element,{f,Fail},[Pos,Src],Dst}, Vst) ->
+ branch(Fail, Vst,
+ fun(SuccVst0) ->
+ PosType = get_term_type(Pos, SuccVst0),
+ TupleType = {tuple,[get_tuple_size(PosType)],#{}},
+
+ SuccVst1 = update_type(fun meet/2, TupleType,
+ Src, SuccVst0),
+ SuccVst = update_type(fun meet/2, {integer,[]},
+ Pos, SuccVst1),
+
+ ElementType = get_element_type(PosType, Src, SuccVst),
+ extract_term(ElementType, {bif,element}, [Pos,Src],
+ Dst, SuccVst)
+ end);
valfun_4({bif,raise,{f,0},Src,_Dst}, Vst) ->
validate_src(Src, Vst),
kill_state(Vst);
-valfun_4({bif,Op,{f,Fail},Src,Dst}, Vst0) ->
- validate_src(Src, Vst0),
- Vst = branch_state(Fail, Vst0),
- Type = bif_type(Op, Src, Vst),
- set_type_reg(Type, Dst, Vst);
-valfun_4({gc_bif,Op,{f,Fail},Live,Src,Dst}, #vst{current=St0}=Vst0) ->
+valfun_4(raw_raise=I, Vst) ->
+ call(I, 3, Vst);
+valfun_4({bif,Op,{f,Fail},[Src]=Ss,Dst}, Vst) when Op =:= hd; Op =:= tl ->
+ assert_term(Src, Vst),
+ branch(Fail, Vst,
+ fun(FailVst) ->
+ update_type(fun subtract/2, cons, Src, FailVst)
+ end,
+ fun(SuccVst0) ->
+ SuccVst = update_type(fun meet/2, cons, Src, SuccVst0),
+ extract_term(term, {bif,Op}, Ss, Dst, SuccVst)
+ end);
+valfun_4({bif,Op,{f,Fail},Ss,Dst}, Vst) ->
+ validate_src(Ss, Vst),
+ branch(Fail, Vst,
+ fun(SuccVst0) ->
+ %% Infer argument types. Note that we can't subtract
+ %% types as the BIF could fail for reasons other than
+ %% bad argument types.
+ ArgTypes = bif_arg_types(Op, Ss),
+ SuccVst = foldl(fun({Arg, T}, V) ->
+ update_type(fun meet/2, T, Arg, V)
+ end, SuccVst0, zip(Ss, ArgTypes)),
+ Type = bif_return_type(Op, Ss, SuccVst),
+ extract_term(Type, {bif,Op}, Ss, Dst, SuccVst)
+ end);
+valfun_4({gc_bif,Op,{f,Fail},Live,Ss,Dst}, #vst{current=St0}=Vst0) ->
+ validate_src(Ss, Vst0),
verify_live(Live, Vst0),
verify_y_init(Vst0),
+
+ %% Heap allocations and X registers are killed regardless of whether we
+ %% fail or not, as we may fail after GC.
St = kill_heap_allocation(St0),
- Vst1 = Vst0#vst{current=St},
- Vst2 = branch_state(Fail, Vst1),
- Vst = prune_x_regs(Live, Vst2),
- validate_src(Src, Vst),
- Type = bif_type(Op, Src, Vst),
- set_type_reg(Type, Dst, Vst);
+ Vst = prune_x_regs(Live, Vst0#vst{current=St}),
+
+ branch(Fail, Vst,
+ fun(SuccVst0) ->
+ ArgTypes = bif_arg_types(Op, Ss),
+ SuccVst = foldl(fun({Arg, T}, V) ->
+ update_type(fun meet/2, T, Arg, V)
+ end, SuccVst0, zip(Ss, ArgTypes)),
+
+ Type = bif_return_type(Op, Ss, SuccVst),
+
+ %% We're passing Vst0 as the original because the
+ %% registers were pruned before the branch.
+ extract_term(Type, {gc_bif,Op}, Ss, Dst, SuccVst, Vst0)
+ end);
valfun_4(return, #vst{current=#st{numy=none}}=Vst) ->
- assert_term({x,0}, Vst),
+ assert_durable_term({x,0}, Vst),
kill_state(Vst);
valfun_4(return, #vst{current=#st{numy=NumY}}) ->
error({stack_frame,NumY});
-valfun_4({jump,{f,Lbl}}, Vst) ->
- kill_state(branch_state(Lbl, Vst));
-valfun_4({loop_rec,{f,Fail},Dst}, Vst0) ->
- Vst = branch_state(Fail, Vst0),
- set_type_reg(term, Dst, Vst);
+valfun_4({loop_rec,{f,Fail},Dst}, Vst) ->
+ %% This term may not be part of the root set until remove_message/0 is
+ %% executed. If control transfers to the loop_rec_end/1 instruction, no
+ %% part of this term must be stored in a Y register.
+ branch(Fail, Vst,
+ fun(SuccVst0) ->
+ {Ref, SuccVst} = new_value(term, loop_rec, [], SuccVst0),
+ mark_fragile(Dst, set_reg_vref(Ref, Dst, SuccVst))
+ end);
valfun_4({wait,_}, Vst) ->
+ verify_y_init(Vst),
kill_state(Vst);
valfun_4({wait_timeout,_,Src}, Vst) ->
assert_term(Src, Vst),
- Vst;
+ verify_y_init(Vst),
+ prune_x_regs(0, Vst);
valfun_4({loop_rec_end,_}, Vst) ->
+ verify_y_init(Vst),
kill_state(Vst);
-valfun_4(timeout, #vst{current=St}=Vst) ->
- Vst#vst{current=St#st{x=init_regs(0, term)}};
+valfun_4(timeout, Vst) ->
+ prune_x_regs(0, Vst);
valfun_4(send, Vst) ->
call(send, 2, Vst);
-valfun_4({set_tuple_element,Src,Tuple,I}, Vst) ->
+valfun_4({set_tuple_element,Src,Tuple,N}, Vst) ->
+ I = N + 1,
assert_term(Src, Vst),
- assert_type({tuple_element,I+1}, Tuple, Vst),
- Vst;
+ assert_type({tuple_element,I}, Tuple, Vst),
+ %% Manually update the tuple type; we can't rely on the ordinary update
+ %% helpers as we must support overwriting (rather than just widening or
+ %% narrowing) known elements, and we can't use extract_term either since
+ %% the source tuple may be aliased.
+ {tuple, Sz, Es0} = get_term_type(Tuple, Vst),
+ Es = set_element_type({integer,I}, get_term_type(Src, Vst), Es0),
+ override_type({tuple, Sz, Es}, Tuple, Vst);
%% Match instructions.
valfun_4({select_val,Src,{f,Fail},{list,Choices}}, Vst) ->
assert_term(Src, Vst),
- Lbls = [L || {f,L} <- Choices]++[Fail],
- kill_state(foldl(fun(L, S) -> branch_state(L, S) end, Vst, Lbls));
+ assert_choices(Choices),
+ validate_select_val(Fail, Choices, Src, Vst);
valfun_4({select_tuple_arity,Tuple,{f,Fail},{list,Choices}}, Vst) ->
assert_type(tuple, Tuple, Vst),
- kill_state(branch_arities(Choices, Tuple, branch_state(Fail, Vst)));
-valfun_4({get_list,Src,D1,D2}, Vst0) ->
- assert_type(cons, Src, Vst0),
- Vst = set_type_reg(term, D1, Vst0),
- set_type_reg(term, D2, Vst);
-valfun_4({get_tuple_element,Src,I,Dst}, Vst) ->
- assert_type({tuple_element,I+1}, Src, Vst),
- set_type_reg(term, Dst, Vst);
+ assert_arities(Choices),
+ validate_select_tuple_arity(Fail, Choices, Tuple, Vst);
%% New bit syntax matching instructions.
-valfun_4({test,bs_start_match2,{f,Fail},Live,[Ctx,NeedSlots],Ctx}, Vst0) ->
- %% If source and destination registers are the same, match state
- %% is OK as input.
- CtxType = get_move_term_type(Ctx, Vst0),
- verify_live(Live, Vst0),
- Vst1 = prune_x_regs(Live, Vst0),
- BranchVst = case CtxType of
- #ms{} ->
- %% The failure branch will never be taken when Ctx
- %% is a match context. Therefore, the type for Ctx
- %% at the failure label must not be match_context
- %% (or we could reject legal code).
- set_type_reg(term, Ctx, Vst1);
- _ ->
- Vst1
- end,
- Vst = branch_state(Fail, BranchVst),
- set_type_reg(bsm_match_state(NeedSlots), Ctx, Vst);
-valfun_4({test,bs_start_match2,{f,Fail},Live,[Src,Slots],Dst}, Vst0) ->
- assert_term(Src, Vst0),
- verify_live(Live, Vst0),
- Vst1 = prune_x_regs(Live, Vst0),
- Vst = branch_state(Fail, Vst1),
- set_type_reg(bsm_match_state(Slots), Dst, Vst);
+valfun_4({test,bs_start_match3,{f,Fail},Live,[Src],Dst}, Vst) ->
+ validate_bs_start_match(Fail, Live, bsm_match_state(), Src, Dst, Vst);
+valfun_4({test,bs_start_match2,{f,Fail},Live,[Src,Slots],Dst}, Vst) ->
+ validate_bs_start_match(Fail, Live, bsm_match_state(Slots), Src, Dst, Vst);
valfun_4({test,bs_match_string,{f,Fail},[Ctx,_,_]}, Vst) ->
bsm_validate_context(Ctx, Vst),
- branch_state(Fail, Vst);
+ branch(Fail, Vst, fun(V) -> V end);
valfun_4({test,bs_skip_bits2,{f,Fail},[Ctx,Src,_,_]}, Vst) ->
bsm_validate_context(Ctx, Vst),
assert_term(Src, Vst),
- branch_state(Fail, Vst);
+ branch(Fail, Vst, fun(V) -> V end);
valfun_4({test,bs_test_tail2,{f,Fail},[Ctx,_]}, Vst) ->
bsm_validate_context(Ctx, Vst),
- branch_state(Fail, Vst);
+ branch(Fail, Vst, fun(V) -> V end);
valfun_4({test,bs_test_unit,{f,Fail},[Ctx,_]}, Vst) ->
bsm_validate_context(Ctx, Vst),
- branch_state(Fail, Vst);
+ branch(Fail, Vst, fun(V) -> V end);
valfun_4({test,bs_skip_utf8,{f,Fail},[Ctx,Live,_]}, Vst) ->
validate_bs_skip_utf(Fail, Ctx, Live, Vst);
valfun_4({test,bs_skip_utf16,{f,Fail},[Ctx,Live,_]}, Vst) ->
validate_bs_skip_utf(Fail, Ctx, Live, Vst);
valfun_4({test,bs_skip_utf32,{f,Fail},[Ctx,Live,_]}, Vst) ->
validate_bs_skip_utf(Fail, Ctx, Live, Vst);
-valfun_4({test,bs_get_integer2,{f,Fail},Live,[Ctx,_,_,_],Dst}, Vst) ->
- validate_bs_get(Fail, Ctx, Live, {integer, []}, Dst, Vst);
-valfun_4({test,bs_get_float2,{f,Fail},Live,[Ctx,_,_,_],Dst}, Vst) ->
- validate_bs_get(Fail, Ctx, Live, {float, []}, Dst, Vst);
-valfun_4({test,bs_get_binary2,{f,Fail},Live,[Ctx,_,_,_],Dst}, Vst) ->
- validate_bs_get(Fail, Ctx, Live, term, Dst, Vst);
-valfun_4({test,bs_get_utf8,{f,Fail},Live,[Ctx,_],Dst}, Vst) ->
- validate_bs_get(Fail, Ctx, Live, {integer, []}, Dst, Vst);
-valfun_4({test,bs_get_utf16,{f,Fail},Live,[Ctx,_],Dst}, Vst) ->
- validate_bs_get(Fail, Ctx, Live, {integer, []}, Dst, Vst);
-valfun_4({test,bs_get_utf32,{f,Fail},Live,[Ctx,_],Dst}, Vst) ->
- validate_bs_get(Fail, Ctx, Live, {integer, []}, Dst, Vst);
+valfun_4({test,bs_get_integer2=Op,{f,Fail},Live,[Ctx,_,_,_],Dst}, Vst) ->
+ validate_bs_get(Op, Fail, Ctx, Live, {integer, []}, Dst, Vst);
+valfun_4({test,bs_get_float2=Op,{f,Fail},Live,[Ctx,_,_,_],Dst}, Vst) ->
+ validate_bs_get(Op, Fail, Ctx, Live, {float, []}, Dst, Vst);
+valfun_4({test,bs_get_binary2=Op,{f,Fail},Live,[Ctx,_,_,_],Dst}, Vst) ->
+ validate_bs_get(Op, Fail, Ctx, Live, binary, Dst, Vst);
+valfun_4({test,bs_get_utf8=Op,{f,Fail},Live,[Ctx,_],Dst}, Vst) ->
+ validate_bs_get(Op, Fail, Ctx, Live, {integer, []}, Dst, Vst);
+valfun_4({test,bs_get_utf16=Op,{f,Fail},Live,[Ctx,_],Dst}, Vst) ->
+ validate_bs_get(Op, Fail, Ctx, Live, {integer, []}, Dst, Vst);
+valfun_4({test,bs_get_utf32=Op,{f,Fail},Live,[Ctx,_],Dst}, Vst) ->
+ validate_bs_get(Op, Fail, Ctx, Live, {integer, []}, Dst, Vst);
valfun_4({bs_save2,Ctx,SavePoint}, Vst) ->
bsm_save(Ctx, SavePoint, Vst);
valfun_4({bs_restore2,Ctx,SavePoint}, Vst) ->
bsm_restore(Ctx, SavePoint, Vst);
+valfun_4({bs_get_position, Ctx, Dst, Live}, Vst0) ->
+ bsm_validate_context(Ctx, Vst0),
+ verify_live(Live, Vst0),
+ verify_y_init(Vst0),
+ Vst = prune_x_regs(Live, Vst0),
+ create_term(ms_position, bs_get_position, [Ctx], Dst, Vst, Vst0);
+valfun_4({bs_set_position, Ctx, Pos}, Vst) ->
+ bsm_validate_context(Ctx, Vst),
+ assert_type(ms_position, Pos, Vst),
+ Vst;
%% Other test instructions.
-valfun_4({test,is_float,{f,Lbl},[Float]}, Vst) ->
- assert_term(Float, Vst),
- set_type({float,[]}, Float, branch_state(Lbl, Vst));
-valfun_4({test,is_tuple,{f,Lbl},[Tuple]}, Vst) ->
- Type0 = get_term_type(Tuple, Vst),
- Type = upgrade_tuple_type({tuple,[0]}, Type0),
- set_type(Type, Tuple, branch_state(Lbl, Vst));
-valfun_4({test,is_nonempty_list,{f,Lbl},[Cons]}, Vst) ->
- assert_term(Cons, Vst),
- set_type(cons, Cons, branch_state(Lbl, Vst));
-valfun_4({test,test_arity,{f,Lbl},[Tuple,Sz]}, Vst) when is_integer(Sz) ->
- assert_type(tuple, Tuple, Vst),
- set_type_reg({tuple,Sz}, Tuple, branch_state(Lbl, Vst));
-valfun_4({test,is_tagged_tuple,{f,Lbl},[Src,Sz,_Atom]}, Vst) ->
- validate_src([Src], Vst),
- set_type_reg({tuple, Sz}, Src, branch_state(Lbl, Vst));
valfun_4({test,has_map_fields,{f,Lbl},Src,{list,List}}, Vst) ->
assert_type(map, Src, Vst),
assert_unique_map_keys(List),
- branch_state(Lbl, Vst);
-valfun_4({test,is_map,{f,Lbl},[Src]}, Vst0) ->
- Vst = branch_state(Lbl, Vst0),
- case Src of
- {Tag,_} when Tag =:= x; Tag =:= y ->
- set_type_reg(map, Src, Vst);
- {literal,Map} when is_map(Map) ->
- Vst;
- _ ->
- kill_state(Vst)
- end;
+ branch(Lbl, Vst, fun(V) -> V end);
+valfun_4({test,is_atom,{f,Lbl},[Src]}, Vst) ->
+ type_test(Lbl, {atom,[]}, Src, Vst);
+valfun_4({test,is_binary,{f,Lbl},[Src]}, Vst) ->
+ type_test(Lbl, binary, Src, Vst);
+valfun_4({test,is_bitstr,{f,Lbl},[Src]}, Vst) ->
+ type_test(Lbl, binary, Src, Vst);
+valfun_4({test,is_boolean,{f,Lbl},[Src]}, Vst) ->
+ type_test(Lbl, bool, Src, Vst);
+valfun_4({test,is_float,{f,Lbl},[Src]}, Vst) ->
+ type_test(Lbl, {float,[]}, Src, Vst);
+valfun_4({test,is_tuple,{f,Lbl},[Src]}, Vst) ->
+ type_test(Lbl, {tuple,[0],#{}}, Src, Vst);
+valfun_4({test,is_integer,{f,Lbl},[Src]}, Vst) ->
+ type_test(Lbl, {integer,[]}, Src, Vst);
+valfun_4({test,is_nonempty_list,{f,Lbl},[Src]}, Vst) ->
+ type_test(Lbl, cons, Src, Vst);
+valfun_4({test,is_number,{f,Lbl},[Src]}, Vst) ->
+ type_test(Lbl, number, Src, Vst);
+valfun_4({test,is_list,{f,Lbl},[Src]}, Vst) ->
+ type_test(Lbl, list, Src, Vst);
+valfun_4({test,is_map,{f,Lbl},[Src]}, Vst) ->
+ type_test(Lbl, map, Src, Vst);
+valfun_4({test,is_nil,{f,Lbl},[Src]}, Vst) ->
+ %% is_nil is an exact check against the 'nil' value, and should not be
+ %% treated as a simple type test.
+ assert_term(Src, Vst),
+ branch(Lbl, Vst,
+ fun(FailVst) ->
+ update_ne_types(Src, nil, FailVst)
+ end,
+ fun(SuccVst) ->
+ update_eq_types(Src, nil, SuccVst)
+ end);
+valfun_4({test,test_arity,{f,Lbl},[Tuple,Sz]}, Vst) when is_integer(Sz) ->
+ assert_type(tuple, Tuple, Vst),
+ Type = {tuple, Sz, #{}},
+ type_test(Lbl, Type, Tuple, Vst);
+valfun_4({test,is_tagged_tuple,{f,Lbl},[Src,Sz,Atom]}, Vst) ->
+ assert_term(Src, Vst),
+ Type = {tuple, Sz, #{ {integer,1} => Atom }},
+ type_test(Lbl, Type, Src, Vst);
+valfun_4({test,is_eq_exact,{f,Lbl},[Src,Val]=Ss}, Vst) ->
+ validate_src(Ss, Vst),
+ branch(Lbl, Vst,
+ fun(FailVst) ->
+ update_ne_types(Src, Val, FailVst)
+ end,
+ fun(SuccVst) ->
+ update_eq_types(Src, Val, SuccVst)
+ end);
+valfun_4({test,is_ne_exact,{f,Lbl},[Src,Val]=Ss}, Vst) ->
+ validate_src(Ss, Vst),
+ branch(Lbl, Vst,
+ fun(FailVst) ->
+ update_eq_types(Src, Val, FailVst)
+ end,
+ fun(SuccVst) ->
+ update_ne_types(Src, Val, SuccVst)
+ end);
valfun_4({test,_Op,{f,Lbl},Src}, Vst) ->
+ %% is_pid, is_reference, et cetera.
validate_src(Src, Vst),
- branch_state(Lbl, Vst);
+ branch(Lbl, Vst, fun(V) -> V end);
valfun_4({bs_add,{f,Fail},[A,B,_],Dst}, Vst) ->
assert_term(A, Vst),
assert_term(B, Vst),
- set_type_reg({integer,[]}, Dst, branch_state(Fail, Vst));
+ branch(Fail, Vst,
+ fun(SuccVst) ->
+ create_term({integer,[]}, bs_add, [A, B], Dst, SuccVst)
+ end);
valfun_4({bs_utf8_size,{f,Fail},A,Dst}, Vst) ->
assert_term(A, Vst),
- set_type_reg({integer,[]}, Dst, branch_state(Fail, Vst));
+ branch(Fail, Vst,
+ fun(SuccVst) ->
+ create_term({integer,[]}, bs_utf8_size, [A], Dst, SuccVst)
+ end);
valfun_4({bs_utf16_size,{f,Fail},A,Dst}, Vst) ->
assert_term(A, Vst),
- set_type_reg({integer,[]}, Dst, branch_state(Fail, Vst));
+ branch(Fail, Vst,
+ fun(SuccVst) ->
+ create_term({integer,[]}, bs_utf16_size, [A], Dst, SuccVst)
+ end);
valfun_4({bs_init2,{f,Fail},Sz,Heap,Live,_,Dst}, Vst0) ->
verify_live(Live, Vst0),
verify_y_init(Vst0),
@@ -693,10 +958,12 @@ valfun_4({bs_init2,{f,Fail},Sz,Heap,Live,_,Dst}, Vst0) ->
true ->
assert_term(Sz, Vst0)
end,
- Vst1 = heap_alloc(Heap, Vst0),
- Vst2 = branch_state(Fail, Vst1),
- Vst = prune_x_regs(Live, Vst2),
- set_type_reg(binary, Dst, Vst);
+ Vst = heap_alloc(Heap, Vst0),
+ branch(Fail, Vst,
+ fun(SuccVst0) ->
+ SuccVst = prune_x_regs(Live, SuccVst0),
+ create_term(binary, bs_init2, [], Dst, SuccVst, SuccVst0)
+ end);
valfun_4({bs_init_bits,{f,Fail},Sz,Heap,Live,_,Dst}, Vst0) ->
verify_live(Live, Vst0),
verify_y_init(Vst0),
@@ -706,113 +973,203 @@ valfun_4({bs_init_bits,{f,Fail},Sz,Heap,Live,_,Dst}, Vst0) ->
true ->
assert_term(Sz, Vst0)
end,
- Vst1 = heap_alloc(Heap, Vst0),
- Vst2 = branch_state(Fail, Vst1),
- Vst = prune_x_regs(Live, Vst2),
- set_type_reg(binary, Dst, Vst);
+ Vst = heap_alloc(Heap, Vst0),
+ branch(Fail, Vst,
+ fun(SuccVst0) ->
+ SuccVst = prune_x_regs(Live, SuccVst0),
+ create_term(binary, bs_init_bits, [], Dst, SuccVst)
+ end);
valfun_4({bs_append,{f,Fail},Bits,Heap,Live,_Unit,Bin,_Flags,Dst}, Vst0) ->
verify_live(Live, Vst0),
verify_y_init(Vst0),
assert_term(Bits, Vst0),
assert_term(Bin, Vst0),
- Vst1 = heap_alloc(Heap, Vst0),
- Vst2 = branch_state(Fail, Vst1),
- Vst = prune_x_regs(Live, Vst2),
- set_type_reg(binary, Dst, Vst);
-valfun_4({bs_private_append,{f,Fail},Bits,_Unit,Bin,_Flags,Dst}, Vst0) ->
- assert_term(Bits, Vst0),
- assert_term(Bin, Vst0),
- Vst = branch_state(Fail, Vst0),
- set_type_reg(binary, Dst, Vst);
+ Vst = heap_alloc(Heap, Vst0),
+ branch(Fail, Vst,
+ fun(SuccVst0) ->
+ SuccVst = prune_x_regs(Live, SuccVst0),
+ create_term(binary, bs_append, [Bin], Dst, SuccVst, SuccVst0)
+ end);
+valfun_4({bs_private_append,{f,Fail},Bits,_Unit,Bin,_Flags,Dst}, Vst) ->
+ assert_term(Bits, Vst),
+ assert_term(Bin, Vst),
+ branch(Fail, Vst,
+ fun(SuccVst) ->
+ create_term(binary, bs_private_append, [Bin], Dst, SuccVst)
+ end);
valfun_4({bs_put_string,Sz,_}, Vst) when is_integer(Sz) ->
Vst;
valfun_4({bs_put_binary,{f,Fail},Sz,_,_,Src}, Vst) ->
assert_term(Sz, Vst),
assert_term(Src, Vst),
- branch_state(Fail, Vst);
+ branch(Fail, Vst,
+ fun(SuccVst) ->
+ update_type(fun meet/2, binary, Src, SuccVst)
+ end);
valfun_4({bs_put_float,{f,Fail},Sz,_,_,Src}, Vst) ->
assert_term(Sz, Vst),
assert_term(Src, Vst),
- branch_state(Fail, Vst);
+ branch(Fail, Vst,
+ fun(SuccVst) ->
+ update_type(fun meet/2, {float,[]}, Src, SuccVst)
+ end);
valfun_4({bs_put_integer,{f,Fail},Sz,_,_,Src}, Vst) ->
assert_term(Sz, Vst),
assert_term(Src, Vst),
- branch_state(Fail, Vst);
+ branch(Fail, Vst,
+ fun(SuccVst) ->
+ update_type(fun meet/2, {integer,[]}, Src, SuccVst)
+ end);
valfun_4({bs_put_utf8,{f,Fail},_,Src}, Vst) ->
assert_term(Src, Vst),
- branch_state(Fail, Vst);
+ branch(Fail, Vst,
+ fun(SuccVst) ->
+ update_type(fun meet/2, {integer,[]}, Src, SuccVst)
+ end);
valfun_4({bs_put_utf16,{f,Fail},_,Src}, Vst) ->
assert_term(Src, Vst),
- branch_state(Fail, Vst);
+ branch(Fail, Vst,
+ fun(SuccVst) ->
+ update_type(fun meet/2, {integer,[]}, Src, SuccVst)
+ end);
valfun_4({bs_put_utf32,{f,Fail},_,Src}, Vst) ->
assert_term(Src, Vst),
- branch_state(Fail, Vst);
+ branch(Fail, Vst,
+ fun(SuccVst) ->
+ update_type(fun meet/2, {integer,[]}, Src, SuccVst)
+ end);
%% Map instructions.
-valfun_4({put_map_assoc,{f,Fail},Src,Dst,Live,{list,List}}, Vst) ->
- verify_put_map(Fail, Src, Dst, Live, List, Vst);
-valfun_4({put_map_exact,{f,Fail},Src,Dst,Live,{list,List}}, Vst) ->
- verify_put_map(Fail, Src, Dst, Live, List, Vst);
+valfun_4({put_map_assoc=Op,{f,Fail},Src,Dst,Live,{list,List}}, Vst) ->
+ verify_put_map(Op, Fail, Src, Dst, Live, List, Vst);
+valfun_4({put_map_exact=Op,{f,Fail},Src,Dst,Live,{list,List}}, Vst) ->
+ verify_put_map(Op, Fail, Src, Dst, Live, List, Vst);
valfun_4({get_map_elements,{f,Fail},Src,{list,List}}, Vst) ->
verify_get_map(Fail, Src, List, Vst);
valfun_4(_, _) ->
error(unknown_instruction).
verify_get_map(Fail, Src, List, Vst0) ->
+ assert_not_literal(Src), %OTP 22.
assert_type(map, Src, Vst0),
- Vst1 = foldl(fun(D, Vsti) ->
- case is_reg_defined(D,Vsti) of
- true -> set_type_reg(term,D,Vsti);
- false -> Vsti
- end
- end, Vst0, extract_map_vals(List)),
- Vst2 = branch_state(Fail, Vst1),
- Keys = extract_map_keys(List),
- assert_unique_map_keys(Keys),
- verify_get_map_pair(List,Vst0,Vst2).
-
-extract_map_vals([_Key,Val|T]) ->
- [Val|extract_map_vals(T)];
-extract_map_vals([]) -> [].
+
+ branch(Fail, Vst0,
+ fun(FailVst) ->
+ clobber_map_vals(List, Src, FailVst)
+ end,
+ fun(SuccVst) ->
+ Keys = extract_map_keys(List),
+ assert_unique_map_keys(Keys),
+ extract_map_vals(List, Src, SuccVst, SuccVst)
+ end).
+
+%% get_map_elements may leave its destinations in an inconsistent state when
+%% the fail label is taken. Consider the following:
+%%
+%% {get_map_elements,{f,7},{x,1},{list,[{atom,a},{x,1},{atom,b},{x,2}]}}.
+%%
+%% If 'a' exists but not 'b', {x,1} is overwritten when we jump to {f,7}.
+clobber_map_vals([Key,Dst|T], Map, Vst0) ->
+ case is_reg_defined(Dst, Vst0) of
+ true ->
+ Vst = extract_term(term, {bif,map_get}, [Key, Map], Dst, Vst0),
+ clobber_map_vals(T, Map, Vst);
+ false ->
+ clobber_map_vals(T, Map, Vst0)
+ end;
+clobber_map_vals([], _Map, Vst) ->
+ Vst.
extract_map_keys([Key,_Val|T]) ->
[Key|extract_map_keys(T)];
extract_map_keys([]) -> [].
-verify_get_map_pair([],_,Vst) -> Vst;
-verify_get_map_pair([Src,Dst|Vs],Vst0,Vsti) ->
- assert_term(Src, Vst0),
- verify_get_map_pair(Vs,Vst0,set_type_reg(term,Dst,Vsti)).
+extract_map_vals([Key,Dst|Vs], Map, Vst0, Vsti0) ->
+ assert_term(Key, Vst0),
+ Vsti = extract_term(term, {bif,map_get}, [Key, Map], Dst, Vsti0),
+ extract_map_vals(Vs, Map, Vst0, Vsti);
+extract_map_vals([], _Map, _Vst0, Vst) ->
+ Vst.
-verify_put_map(Fail, Src, Dst, Live, List, Vst0) ->
+verify_put_map(Op, Fail, Src, Dst, Live, List, Vst0) ->
assert_type(map, Src, Vst0),
verify_live(Live, Vst0),
verify_y_init(Vst0),
- foreach(fun (Term) -> assert_term(Term, Vst0) end, List),
- Vst1 = heap_alloc(0, Vst0),
- Vst2 = branch_state(Fail, Vst1),
- Vst = prune_x_regs(Live, Vst2),
- Keys = extract_map_keys(List),
- assert_unique_map_keys(Keys),
- set_type_reg(map, Dst, Vst).
+ _ = [assert_term(Term, Vst0) || Term <- List],
+ Vst = heap_alloc(0, Vst0),
+
+ branch(Fail, Vst,
+ fun(SuccVst0) ->
+ SuccVst = prune_x_regs(Live, SuccVst0),
+ Keys = extract_map_keys(List),
+ assert_unique_map_keys(Keys),
+ create_term(map, Op, [Src], Dst, SuccVst, SuccVst0)
+ end).
+
+%%
+%% Common code for validating bs_start_match* instructions.
+%%
+
+validate_bs_start_match(Fail, Live, Type, Src, Dst, Vst) ->
+ verify_live(Live, Vst),
+ verify_y_init(Vst),
+
+ %% #ms{} can represent either a match context or a term, so we have to mark
+ %% the source as a term if it fails with a match context as an input. This
+ %% hack is only needed until we get proper union types.
+ branch(Fail, Vst,
+ fun(FailVst) ->
+ case get_movable_term_type(Src, FailVst) of
+ #ms{} -> override_type(term, Src, FailVst);
+ _ -> FailVst
+ end
+ end,
+ fun(SuccVst0) ->
+ SuccVst1 = update_type(fun meet/2, binary,
+ Src, SuccVst0),
+ SuccVst = prune_x_regs(Live, SuccVst1),
+ extract_term(Type, bs_start_match, [Src], Dst,
+ SuccVst, SuccVst0)
+ end).
%%
%% Common code for validating bs_get* instructions.
%%
-validate_bs_get(Fail, Ctx, Live, Type, Dst, Vst0) ->
- bsm_validate_context(Ctx, Vst0),
- verify_live(Live, Vst0),
- Vst1 = prune_x_regs(Live, Vst0),
- Vst = branch_state(Fail, Vst1),
- set_type_reg(Type, Dst, Vst).
+validate_bs_get(Op, Fail, Ctx, Live, Type, Dst, Vst) ->
+ bsm_validate_context(Ctx, Vst),
+ verify_live(Live, Vst),
+ verify_y_init(Vst),
+
+ branch(Fail, Vst,
+ fun(SuccVst0) ->
+ SuccVst = prune_x_regs(Live, SuccVst0),
+ extract_term(Type, Op, [Ctx], Dst, SuccVst, SuccVst0)
+ end).
%%
%% Common code for validating bs_skip_utf* instructions.
%%
-validate_bs_skip_utf(Fail, Ctx, Live, Vst0) ->
- bsm_validate_context(Ctx, Vst0),
- verify_live(Live, Vst0),
- Vst = prune_x_regs(Live, Vst0),
- branch_state(Fail, Vst).
+validate_bs_skip_utf(Fail, Ctx, Live, Vst) ->
+ bsm_validate_context(Ctx, Vst),
+ verify_y_init(Vst),
+ verify_live(Live, Vst),
+
+ branch(Fail, Vst,
+ fun(SuccVst) ->
+ prune_x_regs(Live, SuccVst)
+ end).
+
+%%
+%% Common code for is_$type instructions.
+%%
+type_test(Fail, Type, Reg, Vst) ->
+ assert_term(Reg, Vst),
+ branch(Fail, Vst,
+ fun(FailVst) ->
+ update_type(fun subtract/2, Type, Reg, FailVst)
+ end,
+ fun(SuccVst) ->
+ update_type(fun meet/2, Type, Reg, SuccVst)
+ end).
%%
%% Special state handling for setelement/3 and set_tuple_element/3 instructions.
@@ -829,34 +1186,29 @@ val_dsetel({set_tuple_element,_,_,_}, #vst{current=#st{setelem=false}}) ->
error(illegal_context_for_set_tuple_element);
val_dsetel({set_tuple_element,_,_,_}, #vst{current=#st{setelem=true}}=Vst) ->
Vst;
+val_dsetel({get_tuple_element,_,_,_}, Vst) ->
+ Vst;
val_dsetel({line,_}, Vst) ->
Vst;
val_dsetel(_, #vst{current=#st{setelem=true}=St}=Vst) ->
Vst#vst{current=St#st{setelem=false}};
val_dsetel(_, Vst) -> Vst.
-kill_state(#vst{current=#st{ct=[[Fail]|_]}}=Vst) when is_integer(Fail) ->
- %% There is an active catch. Make sure that we merge the state into
- %% the catch label before clearing it, so that that we can be sure
- %% that the label gets a state.
- kill_state_1(branch_state(Fail, Vst));
kill_state(Vst) ->
- kill_state_1(Vst).
-
-kill_state_1(Vst) ->
Vst#vst{current=none}.
%% A "plain" call.
%% The stackframe must be initialized.
%% The instruction will return to the instruction following the call.
-call(Name, Live, #vst{current=St}=Vst) ->
- verify_call_args(Name, Live, Vst),
- verify_y_init(Vst),
- case return_type(Name, Vst) of
- Type when Type =/= exception ->
- %% Type is never 'exception' because it has been handled earlier.
- Xs = gb_trees_from_list([{0,Type}]),
- Vst#vst{current=St#st{x=Xs,f=init_fregs()}}
+call(Name, Live, #vst{current=St0}=Vst0) ->
+ verify_call_args(Name, Live, Vst0),
+ verify_y_init(Vst0),
+ case call_return_type(Name, Vst0) of
+ Type when Type =/= exception ->
+ %% Type is never 'exception' because it has been handled earlier.
+ St = St0#st{f=init_fregs()},
+ Vst = prune_x_regs(0, Vst0#vst{current=St}),
+ create_term(Type, call, [], {x,0}, Vst)
end.
%% Tail call.
@@ -872,79 +1224,131 @@ tail_call(Name, Live, Vst0) ->
verify_call_args(_, 0, #vst{}) ->
ok;
verify_call_args({f,Lbl}, Live, Vst) when is_integer(Live)->
- verify_local_call(Lbl, Live, Vst);
+ verify_local_args(Live - 1, Lbl, #{}, Vst);
verify_call_args(_, Live, Vst) when is_integer(Live)->
- verify_call_args_1(Live, Vst);
+ verify_remote_args_1(Live - 1, Vst);
verify_call_args(_, Live, _) ->
error({bad_number_of_live_regs,Live}).
-verify_call_args_1(0, _) -> ok;
-verify_call_args_1(N, Vst) ->
- X = N - 1,
- get_term_type({x,X}, Vst),
- verify_call_args_1(X, Vst).
-
-verify_local_call(Lbl, Live, Vst) ->
- case all_ms_in_x_regs(Live, Vst) of
- [{R,Ctx}] ->
- %% Verify that there is a suitable bs_start_match2 instruction.
- verify_call_match_context(Lbl, R, Vst),
-
- %% Since the callee has consumed the match context,
- %% there must be no additional copies in Y registers.
- #ms{id=Id} = Ctx,
- case ms_in_y_regs(Id, Vst) of
- [] ->
- ok;
- [_|_]=Ys ->
- error({multiple_match_contexts,[R|Ys]})
- end;
- [_,_|_]=Xs0 ->
- Xs = [R || {R,_} <- Xs0],
- error({multiple_match_contexts,Xs});
- [] ->
- ok
+verify_remote_args_1(-1, _) ->
+ ok;
+verify_remote_args_1(X, Vst) ->
+ assert_durable_term({x, X}, Vst),
+ verify_remote_args_1(X - 1, Vst).
+
+verify_local_args(-1, _Lbl, _CtxIds, _Vst) ->
+ ok;
+verify_local_args(X, Lbl, CtxIds, Vst) ->
+ Reg = {x, X},
+ assert_not_fragile(Reg, Vst),
+ case get_movable_term_type(Reg, Vst) of
+ #ms{id=Id}=Type ->
+ case CtxIds of
+ #{ Id := Other } ->
+ error({multiple_match_contexts, [Reg, Other]});
+ #{} ->
+ verify_arg_type(Lbl, Reg, Type, Vst),
+ verify_local_args(X - 1, Lbl, CtxIds#{ Id => Reg }, Vst)
+ end;
+ Type ->
+ verify_arg_type(Lbl, Reg, Type, Vst),
+ verify_local_args(X - 1, Lbl, CtxIds, Vst)
end.
-all_ms_in_x_regs(0, _Vst) ->
- [];
-all_ms_in_x_regs(Live0, Vst) ->
- Live = Live0 - 1,
- R = {x,Live},
- case get_move_term_type(R, Vst) of
- #ms{}=M ->
- [{R,M}|all_ms_in_x_regs(Live, Vst)];
- _ ->
- all_ms_in_x_regs(Live, Vst)
+%% Verifies that the given argument narrows to what the function expects.
+verify_arg_type(Lbl, Reg, #ms{}, #vst{ft=Ft}) ->
+ %% Match contexts require explicit support, and may not be passed to a
+ %% function that accepts arbitrary terms.
+ case gb_trees:lookup({Lbl, Reg}, Ft) of
+ {value, #ms{}} -> ok;
+ _ -> error(no_bs_start_match2)
+ end;
+verify_arg_type(Lbl, Reg, GivenType, #vst{ft=Ft}) ->
+ case gb_trees:lookup({Lbl, Reg}, Ft) of
+ {value, #ms{}} ->
+ %% Functions that accept match contexts also accept all other
+ %% terms. This will change once we support union types.
+ ok;
+ {value, RequiredType} ->
+ case vat_1(GivenType, RequiredType) of
+ true -> ok;
+ false -> error({bad_arg_type, Reg, GivenType, RequiredType})
+ end;
+ none ->
+ ok
end.
-ms_in_y_regs(Id, #vst{current=#st{y=Ys0}}) ->
- Ys = gb_trees:to_list(Ys0),
- [{y,Y} || {Y,#ms{id=OtherId}} <- Ys, OtherId =:= Id].
+%% Checks whether the Given argument is compatible with the Required one. This
+%% is essentially a relaxed version of 'meet(Given, Req) =:= Given', where we
+%% accept that the Given value has the right type but not necessarily the exact
+%% same value; if {atom,gurka} is required, we'll consider {atom,[]} valid.
+%%
+%% This will catch all problems that could crash the emulator, like passing a
+%% 1-tuple when the callee expects a 3-tuple, but some value errors might slip
+%% through.
+vat_1(Same, Same) -> true;
+vat_1({atom,A}, {atom,B}) -> A =:= B orelse is_list(A) orelse is_list(B);
+vat_1({atom,A}, bool) -> is_boolean(A) orelse is_list(A);
+vat_1(bool, {atom,B}) -> is_boolean(B) orelse is_list(B);
+vat_1(cons, list) -> true;
+vat_1({float,A}, {float,B}) -> A =:= B orelse is_list(A) orelse is_list(B);
+vat_1({float,_}, number) -> true;
+vat_1({integer,A}, {integer,B}) -> A =:= B orelse is_list(A) orelse is_list(B);
+vat_1({integer,_}, number) -> true;
+vat_1(_, {literal,_}) -> false;
+vat_1({literal,_}=Lit, Required) -> vat_1(get_literal_type(Lit), Required);
+vat_1(nil, list) -> true;
+vat_1({tuple,SzA,EsA}, {tuple,SzB,EsB}) ->
+ if
+ is_list(SzB) ->
+ tuple_sz(SzA) >= tuple_sz(SzB) andalso vat_elements(EsA, EsB);
+ SzA =:= SzB ->
+ vat_elements(EsA, EsB);
+ SzA =/= SzB ->
+ false
+ end;
+vat_1(_, _) -> false.
-verify_call_match_context(Lbl, Ctx, #vst{ft=Ft}) ->
- case gb_trees:lookup(Lbl, Ft) of
- none ->
- error(no_bs_start_match2);
- {value,[{test,bs_start_match2,_,_,[Ctx,_],Ctx}|_]} ->
- ok;
- {value,[{test,bs_start_match2,_,_,_,_}=I|_]} ->
- error({unsuitable_bs_start_match2,I})
- end.
+vat_elements(EsA, EsB) ->
+ maps:fold(fun(Key, Req, Acc) ->
+ case EsA of
+ #{ Key := Given } -> Acc andalso vat_1(Given, Req);
+ #{} -> false
+ end
+ end, true, EsB).
-allocate(Zero, Stk, Heap, Live, #vst{current=#st{numy=none}}=Vst0) ->
+allocate(Tag, Stk, Heap, Live, #vst{current=#st{numy=none}=St}=Vst0) ->
verify_live(Live, Vst0),
- Vst = #vst{current=St} = prune_x_regs(Live, Vst0),
- Ys = init_regs(Stk, case Zero of
- true -> initialized;
- false -> uninitialized
- end),
- heap_alloc(Heap, Vst#vst{current=St#st{y=Ys,numy=Stk}});
+ Vst1 = Vst0#vst{current=St#st{numy=Stk}},
+ Vst2 = prune_x_regs(Live, Vst1),
+ Vst = init_stack(Tag, Stk - 1, Vst2),
+ heap_alloc(Heap, Vst);
allocate(_, _, _, _, #vst{current=#st{numy=Numy}}) ->
error({existing_stack_frame,{size,Numy}}).
deallocate(#vst{current=St}=Vst) ->
- Vst#vst{current=St#st{y=init_regs(0, initialized),numy=none}}.
+ Vst#vst{current=St#st{ys=#{},numy=none}}.
+
+init_stack(_Tag, -1, Vst) ->
+ Vst;
+init_stack(Tag, Y, Vst) ->
+ init_stack(Tag, Y - 1, create_tag(Tag, allocate, [], {y,Y}, Vst)).
+
+trim_stack(From, To, Top, #st{ys=Ys0}=St) when From =:= Top ->
+ Ys = maps:filter(fun({y,Y}, _) -> Y < To end, Ys0),
+ St#st{numy=To,ys=Ys};
+trim_stack(From, To, Top, St0) ->
+ Src = {y, From},
+ Dst = {y, To},
+
+ #st{ys=Ys0} = St0,
+ Ys = case Ys0 of
+ #{ Src := Ref } -> Ys0#{ Dst => Ref };
+ #{} -> error({invalid_shift,Src,Dst})
+ end,
+ St = St0#st{ys=Ys},
+
+ trim_stack(From + 1, To + 1, Top, St).
test_heap(Heap, Live, Vst0) ->
verify_live(Live, Vst0),
@@ -969,13 +1373,43 @@ heap_alloc_2([{floats,Floats}|T], St0) ->
St = St0#st{hf=Floats},
heap_alloc_2(T, St);
heap_alloc_2([], St) -> St.
-
-prune_x_regs(Live, #vst{current=#st{x=Xs0}=St0}=Vst) when is_integer(Live) ->
- Xs1 = gb_trees:to_list(Xs0),
- Xs = [P || {R,_}=P <- Xs1, R < Live],
- St = St0#st{x=gb_trees:from_orddict(Xs)},
+
+prune_x_regs(Live, #vst{current=St0}=Vst) when is_integer(Live) ->
+ #st{fragile=Fragile0,xs=Xs0} = St0,
+ Fragile = cerl_sets:filter(fun({x,X}) ->
+ X < Live;
+ ({y,_}) ->
+ true
+ end, Fragile0),
+ Xs = maps:filter(fun({x,X}, _) ->
+ X < Live
+ end, Xs0),
+ St = St0#st{fragile=Fragile,xs=Xs},
Vst#vst{current=St}.
+%% All choices in a select_val list must be integers, floats, or atoms.
+%% All must be of the same type.
+assert_choices([{Tag,_},{f,_}|T]) ->
+ if
+ Tag =:= atom; Tag =:= float; Tag =:= integer ->
+ assert_choices_1(T, Tag);
+ true ->
+ error(bad_select_list)
+ end;
+assert_choices([]) -> ok.
+
+assert_choices_1([{Tag,_},{f,_}|T], Tag) ->
+ assert_choices_1(T, Tag);
+assert_choices_1([_,{f,_}|_], _Tag) ->
+ error(bad_select_list);
+assert_choices_1([], _Tag) -> ok.
+
+assert_arities([Arity,{f,_}|T]) when is_integer(Arity) ->
+ assert_arities(T);
+assert_arities([]) -> ok;
+assert_arities(_) -> error(bad_tuple_arity_list).
+
+
%%%
%%% Floating point checking.
%%%
@@ -995,8 +1429,8 @@ prune_x_regs(Live, #vst{current=#st{x=Xs0}=St0}=Vst) when is_integer(Live) ->
%%% fmove Src {fr,_} %% Move INTO floating point register.
%%%
-float_op(Src, Dst, Vst0) ->
- foreach (fun(S) -> assert_freg_set(S, Vst0) end, Src),
+float_op(Ss, Dst, Vst0) ->
+ _ = [assert_freg_set(S, Vst0) || S <- Ss],
assert_fls(cleared, Vst0),
Vst = set_fls(cleared, Vst0),
set_freg(Dst, Vst).
@@ -1014,8 +1448,7 @@ get_fls(#vst{current=#st{fls=Fls}}) when is_atom(Fls) -> Fls.
init_fregs() -> 0.
-set_freg({fr,Fr}=Freg, #vst{current=#st{f=Fregs0}=St}=Vst)
- when is_integer(Fr), 0 =< Fr ->
+set_freg({fr,Fr}=Freg, #vst{current=#st{f=Fregs0}=St}=Vst) ->
check_limit(Freg),
Bit = 1 bsl Fr,
if
@@ -1051,7 +1484,10 @@ assert_unique_map_keys([]) ->
assert_unique_map_keys([_]) ->
ok;
assert_unique_map_keys([_,_|_]=Ls) ->
- Vs = [get_literal(L) || L <- Ls],
+ Vs = [begin
+ assert_literal(L),
+ L
+ end || L <- Ls],
case length(Vs) =:= sets:size(sets:from_list(Vs)) of
true -> ok;
false -> error(keys_not_unique)
@@ -1061,6 +1497,8 @@ assert_unique_map_keys([_,_|_]=Ls) ->
%%% New binary matching instructions.
%%%
+bsm_match_state() ->
+ #ms{}.
bsm_match_state(Slots) ->
#ms{slots=Slots}.
@@ -1068,13 +1506,14 @@ bsm_validate_context(Reg, Vst) ->
_ = bsm_get_context(Reg, Vst),
ok.
-bsm_get_context({x,X}=Reg, #vst{current=#st{x=Xs}}=_Vst) when is_integer(X) ->
- case gb_trees:lookup(X, Xs) of
- {value,#ms{}=Ctx} -> Ctx;
- _ -> error({no_bsm_context,Reg})
+bsm_get_context({Kind,_}=Reg, Vst) when Kind =:= x; Kind =:= y->
+ case get_movable_term_type(Reg, Vst) of
+ #ms{}=Ctx -> Ctx;
+ _ -> error({no_bsm_context,Reg})
end;
-bsm_get_context(Reg, _) -> error({bad_source,Reg}).
-
+bsm_get_context(Reg, _) ->
+ error({bad_source,Reg}).
+
bsm_save(Reg, {atom,start}, Vst) ->
%% Save point refering to where the match started.
%% It is always valid. But don't forget to validate the context register.
@@ -1084,7 +1523,7 @@ bsm_save(Reg, SavePoint, Vst) ->
case bsm_get_context(Reg, Vst) of
#ms{valid=Bits,slots=Slots}=Ctxt0 when SavePoint < Slots ->
Ctx = Ctxt0#ms{valid=Bits bor (1 bsl SavePoint),slots=Slots},
- set_type_reg(Ctx, Reg, Vst);
+ override_type(Ctx, Reg, Vst);
_ -> error({illegal_save,SavePoint})
end.
@@ -1103,56 +1542,380 @@ bsm_restore(Reg, SavePoint, Vst) ->
_ -> error({illegal_restore,SavePoint,range})
end.
+validate_select_val(_Fail, _Choices, _Src, #vst{current=none}=Vst) ->
+ %% We've already branched on all of Src's possible values, so we know we
+ %% can't reach the fail label or any of the remaining choices.
+ Vst;
+validate_select_val(Fail, [Val,{f,L}|T], Src, Vst0) ->
+ Vst = branch(L, Vst0,
+ fun(BranchVst) ->
+ update_eq_types(Src, Val, BranchVst)
+ end,
+ fun(FailVst) ->
+ update_ne_types(Src, Val, FailVst)
+ end),
+ validate_select_val(Fail, T, Src, Vst);
+validate_select_val(Fail, [], _, Vst) ->
+ branch(Fail, Vst,
+ fun(SuccVst) ->
+ %% The next instruction is never executed.
+ kill_state(SuccVst)
+ end).
+
+validate_select_tuple_arity(_Fail, _Choices, _Src, #vst{current=none}=Vst) ->
+ %% We've already branched on all of Src's possible values, so we know we
+ %% can't reach the fail label or any of the remaining choices.
+ Vst;
+validate_select_tuple_arity(Fail, [Arity,{f,L}|T], Tuple, Vst0) ->
+ Type = {tuple, Arity, #{}},
+ Vst = branch(L, Vst0,
+ fun(BranchVst) ->
+ update_type(fun meet/2, Type, Tuple, BranchVst)
+ end,
+ fun(FailVst) ->
+ update_type(fun subtract/2, Type, Tuple, FailVst)
+ end),
+ validate_select_tuple_arity(Fail, T, Tuple, Vst);
+validate_select_tuple_arity(Fail, [], _, #vst{}=Vst) ->
+ branch(Fail, Vst,
+ fun(SuccVst) ->
+ %% The next instruction is never executed.
+ kill_state(SuccVst)
+ end).
+
+infer_types({Kind,_}=Reg, Vst) when Kind =:= x; Kind =:= y ->
+ infer_types(get_reg_vref(Reg, Vst), Vst);
+infer_types(#value_ref{}=Ref, #vst{current=#st{vs=Vs}}) ->
+ case Vs of
+ #{ Ref := Entry } -> infer_types_1(Entry);
+ #{} -> fun(_, S) -> S end
+ end;
+infer_types(_, #vst{}) ->
+ fun(_, S) -> S end.
+
+infer_types_1(#value{op={bif,'=:='},args=[LHS,RHS]}) ->
+ fun({atom,true}, S) ->
+ %% Either side might contain something worth inferring, so we need
+ %% to check them both.
+ Infer_L = infer_types(RHS, S),
+ Infer_R = infer_types(LHS, S),
+ Infer_R(RHS, Infer_L(LHS, S));
+ (_, S) -> S
+ end;
+infer_types_1(#value{op={bif,element},args=[{integer,Index}=Key,Tuple]}) ->
+ fun(Val, S) ->
+ case is_value_alive(Tuple, S) of
+ true ->
+ Type = {tuple,[Index], #{ Key => get_term_type(Val, S) }},
+ update_type(fun meet/2, Type, Tuple, S);
+ false ->
+ S
+ end
+ end;
+infer_types_1(#value{op={bif,is_atom},args=[Src]}) ->
+ infer_type_test_bif({atom,[]}, Src);
+infer_types_1(#value{op={bif,is_boolean},args=[Src]}) ->
+ infer_type_test_bif(bool, Src);
+infer_types_1(#value{op={bif,is_binary},args=[Src]}) ->
+ infer_type_test_bif(binary, Src);
+infer_types_1(#value{op={bif,is_bitstring},args=[Src]}) ->
+ infer_type_test_bif(binary, Src);
+infer_types_1(#value{op={bif,is_float},args=[Src]}) ->
+ infer_type_test_bif(float, Src);
+infer_types_1(#value{op={bif,is_integer},args=[Src]}) ->
+ infer_type_test_bif({integer,{}}, Src);
+infer_types_1(#value{op={bif,is_list},args=[Src]}) ->
+ infer_type_test_bif(list, Src);
+infer_types_1(#value{op={bif,is_map},args=[Src]}) ->
+ infer_type_test_bif(map, Src);
+infer_types_1(#value{op={bif,is_number},args=[Src]}) ->
+ infer_type_test_bif(number, Src);
+infer_types_1(#value{op={bif,is_tuple},args=[Src]}) ->
+ infer_type_test_bif({tuple,[0],#{}}, Src);
+infer_types_1(#value{op={bif,tuple_size}, args=[Tuple]}) ->
+ fun({integer,Arity}, S) ->
+ case is_value_alive(Tuple, S) of
+ true -> update_type(fun meet/2, {tuple,Arity,#{}}, Tuple, S);
+ false -> S
+ end;
+ (_, S) -> S
+ end;
+infer_types_1(_) ->
+ fun(_, S) -> S end.
+
+infer_type_test_bif(Type, Src) ->
+ fun({atom,true}, S) ->
+ case is_value_alive(Src, S) of
+ true -> update_type(fun meet/2, Type, Src, S);
+ false -> S
+ end;
+ (_, S) ->
+ S
+ end.
+
%%%
%%% Keeping track of types.
%%%
-set_type(Type, {x,_}=Reg, Vst) -> set_type_reg(Type, Reg, Vst);
-set_type(Type, {y,_}=Reg, Vst) -> set_type_y(Type, Reg, Vst);
-set_type(_, _, #vst{}=Vst) -> Vst.
-
-set_type_reg(Type, {x,X}=Reg, #vst{current=#st{x=Xs}=St}=Vst)
- when is_integer(X), 0 =< X ->
- check_limit(Reg),
- Vst#vst{current=St#st{x=gb_trees:enter(X, Type, Xs)}};
-set_type_reg(Type, Reg, Vst) ->
- set_type_y(Type, Reg, Vst).
-
-set_type_y(Type, {y,Y}=Reg, #vst{current=#st{y=Ys0}=St}=Vst)
- when is_integer(Y), 0 =< Y ->
- check_limit(Reg),
- Ys = case gb_trees:lookup(Y, Ys0) of
- none ->
- error({invalid_store,Reg,Type});
- {value,{catchtag,_}=Tag} ->
- error(Tag);
- {value,{trytag,_}=Tag} ->
- error(Tag);
- {value,_} ->
- gb_trees:update(Y, Type, Ys0)
- end,
- Vst#vst{current=St#st{y=Ys}};
-set_type_y(Type, Reg, #vst{}) -> error({invalid_store,Reg,Type}).
-
-set_catch_end({y,Y}, #vst{current=#st{y=Ys0}=St}=Vst) ->
- Ys = gb_trees:update(Y, initialized, Ys0),
- Vst#vst{current=St#st{y=Ys}}.
-
-
-is_reg_defined({x,_}=Reg, Vst) -> is_type_defined_x(Reg, Vst);
-is_reg_defined({y,_}=Reg, Vst) -> is_type_defined_y(Reg, Vst);
-is_reg_defined(V, #vst{}) -> error({not_a_register, V}).
+%% Assigns Src to Dst and marks them as aliasing each other.
+assign({y,_}=Src, {y,_}=Dst, Vst) ->
+ %% The stack trimming optimization may generate a move from an initialized
+ %% but unassigned Y register to another Y register.
+ case get_raw_type(Src, Vst) of
+ initialized -> create_tag(initialized, init, [], Dst, Vst);
+ _ -> assign_1(Src, Dst, Vst)
+ end;
+assign({Kind,_}=Src, Dst, Vst) when Kind =:= x; Kind =:= y ->
+ assign_1(Src, Dst, Vst);
+assign(Literal, Dst, Vst) ->
+ Type = get_literal_type(Literal),
+ create_term(Type, move, [Literal], Dst, Vst).
+
+%% Creates a special tag value that isn't a regular term, such as 'initialized'
+%% or 'catchtag'
+create_tag(Tag, _Op, _Ss, {y,_}=Dst, #vst{current=#st{ys=Ys0}=St0}=Vst) ->
+ case maps:get(Dst, Ys0, uninitialized) of
+ {catchtag,_}=Prev ->
+ error(Prev);
+ {trytag,_}=Prev ->
+ error(Prev);
+ _ ->
+ check_try_catch_tags(Tag, Dst, Vst),
+ Ys = Ys0#{ Dst => Tag },
+ St = St0#st{ys=Ys},
+ remove_fragility(Dst, Vst#vst{current=St})
+ end;
+create_tag(_Tag, _Op, _Ss, Dst, _Vst) ->
+ error({invalid_tag_register, Dst}).
+
+%% Wipes a special tag, leaving the register initialized but empty.
+kill_tag({y,_}=Reg, #vst{current=#st{ys=Ys0}=St0}=Vst) ->
+ _ = get_tag_type(Reg, Vst), %Assertion.
+ Ys = Ys0#{ Reg => initialized },
+ Vst#vst{current=St0#st{ys=Ys}}.
+
+%% Creates a completely new term with the given type.
+create_term(Type, Op, Ss0, Dst, Vst0) ->
+ create_term(Type, Op, Ss0, Dst, Vst0, Vst0).
+
+%% As create_term/4, but uses the incoming Vst for argument resolution in
+%% case x-regs have been pruned and the sources can no longer be found.
+create_term(Type, Op, Ss0, Dst, Vst0, OrigVst) ->
+ {Ref, Vst1} = new_value(Type, Op, resolve_args(Ss0, OrigVst), Vst0),
+ Vst = remove_fragility(Dst, Vst1),
+ set_reg_vref(Ref, Dst, Vst).
+
+%% Extracts a term from Ss, propagating fragility.
+extract_term(Type, Op, Ss0, Dst, Vst0) ->
+ extract_term(Type, Op, Ss0, Dst, Vst0, Vst0).
+
+%% As extract_term/4, but uses the incoming Vst for argument resolution in
+%% case x-regs have been pruned and the sources can no longer be found.
+extract_term(Type, Op, Ss0, Dst, Vst0, OrigVst) ->
+ {Ref, Vst1} = new_value(Type, Op, resolve_args(Ss0, OrigVst), Vst0),
+ Vst = propagate_fragility(Dst, Ss0, Vst1),
+ set_reg_vref(Ref, Dst, Vst).
+
+%% Translates instruction arguments into the argument() type, decoupling them
+%% from their registers, allowing us to infer their types after they've been
+%% clobbered or moved.
+resolve_args([{Kind,_}=Src | Args], Vst) when Kind =:= x; Kind =:= y ->
+ [get_reg_vref(Src, Vst) | resolve_args(Args, Vst)];
+resolve_args([Lit | Args], Vst) ->
+ assert_literal(Lit),
+ [Lit | resolve_args(Args, Vst)];
+resolve_args([], _Vst) ->
+ [].
+
+%% Overrides the type of Reg. This is ugly but a necessity for certain
+%% destructive operations.
+override_type(Type, Reg, Vst) ->
+ update_type(fun(_, T) -> T end, Type, Reg, Vst).
+
+%% This is used when linear code finds out more and more information about a
+%% type, so that the type gets more specialized.
+update_type(Merge, With, #value_ref{}=Ref, Vst) ->
+ %% If the old type can't be merged with the new one, the type information
+ %% is inconsistent and we know that some instructions will never be
+ %% executed at run-time. For example:
+ %%
+ %% {test,is_list,Fail,[Reg]}.
+ %% {test,is_tuple,Fail,[Reg]}.
+ %% {test,test_arity,Fail,[Reg,5]}.
+ %%
+ %% Note that the test_arity instruction can never be reached, so we need to
+ %% kill the state to avoid raising an error when we encounter it.
+ %%
+ %% Simply returning `kill_state(Vst)` is unsafe however as we might be in
+ %% the middle of an instruction, and altering the rest of the validator
+ %% (eg. prune_x_regs/2) to no-op on dead states is prone to error.
+ %%
+ %% We therefore throw a 'type_conflict' error instead, which causes
+ %% validation to fail unless we're in a context where such errors can be
+ %% handled, such as in a branch handler.
+ Current = get_raw_type(Ref, Vst),
+ case Merge(Current, With) of
+ none -> throw({type_conflict, Current, With});
+ Type -> set_type(Type, Ref, Vst)
+ end;
+update_type(Merge, With, {Kind,_}=Reg, Vst) when Kind =:= x; Kind =:= y ->
+ update_type(Merge, With, get_reg_vref(Reg, Vst), Vst);
+update_type(Merge, With, Literal, Vst) ->
+ assert_literal(Literal),
+ %% Literals always retain their type, but we still need to bail on type
+ %% conflicts.
+ case Merge(Literal, With) of
+ none -> throw({type_conflict, Literal, With});
+ _Type -> Vst
+ end.
+
+update_ne_types(LHS, RHS, Vst) ->
+ %% While updating types on equality is fairly straightforward, inequality
+ %% is a bit trickier since all we know is that the *value* of LHS differs
+ %% from RHS, so we can't blindly subtract their types.
+ %%
+ %% Consider `number =/= {integer,[]}`; all we know is that LHS isn't equal
+ %% to some *specific integer* of unknown value, and if we were to subtract
+ %% {integer,[]} we would erroneously infer that the new type is {float,[]}.
+ %%
+ %% Therefore, we only subtract when we know that RHS has a specific value.
+ RType = get_term_type(RHS, Vst),
+ case is_literal(RType) of
+ true -> update_type(fun subtract/2, RType, LHS, Vst);
+ false -> Vst
+ end.
-is_type_defined_x({x,X}, #vst{current=#st{x=Xs}}) ->
- gb_trees:is_defined(X,Xs).
+update_eq_types(LHS, RHS, Vst0) ->
+ %% Either side might contain something worth inferring, so we need
+ %% to check them both.
+ Infer_L = infer_types(RHS, Vst0),
+ Infer_R = infer_types(LHS, Vst0),
+ Vst1 = Infer_R(RHS, Infer_L(LHS, Vst0)),
+
+ T1 = get_term_type(LHS, Vst1),
+ T2 = get_term_type(RHS, Vst1),
+
+ Vst = update_type(fun meet/2, T2, LHS, Vst1),
+ update_type(fun meet/2, T1, RHS, Vst).
+
+%% Helper functions for the above.
+
+assign_1(Src, Dst, Vst0) ->
+ assert_movable(Src, Vst0),
+ Vst = propagate_fragility(Dst, [Src], Vst0),
+ set_reg_vref(get_reg_vref(Src, Vst), Dst, Vst).
+
+set_reg_vref(Ref, {x,_}=Dst, Vst) ->
+ check_limit(Dst),
+ #vst{current=#st{xs=Xs0}=St0} = Vst,
+ St = St0#st{xs=Xs0#{ Dst => Ref }},
+ Vst#vst{current=St};
+set_reg_vref(Ref, {y,_}=Dst, #vst{current=#st{ys=Ys0}=St0} = Vst) ->
+ check_limit(Dst),
+ case Ys0 of
+ #{ Dst := {catchtag,_}=Tag } ->
+ error(Tag);
+ #{ Dst := {trytag,_}=Tag } ->
+ error(Tag);
+ #{ Dst := _ } ->
+ St = St0#st{ys=Ys0#{ Dst => Ref }},
+ Vst#vst{current=St};
+ #{} ->
+ %% Storing into a non-existent Y register means that we haven't set
+ %% up a (sufficiently large) stack.
+ error({invalid_store, Dst})
+ end.
-is_type_defined_y({y,Y}, #vst{current=#st{y=Ys}}) ->
- gb_trees:is_defined(Y,Ys).
+get_reg_vref({x,_}=Src, #vst{current=#st{xs=Xs}}) ->
+ check_limit(Src),
+ case Xs of
+ #{ Src := #value_ref{}=Ref } ->
+ Ref;
+ #{} ->
+ error({uninitialized_reg, Src})
+ end;
+get_reg_vref({y,_}=Src, #vst{current=#st{ys=Ys}}) ->
+ check_limit(Src),
+ case Ys of
+ #{ Src := #value_ref{}=Ref } ->
+ Ref;
+ #{ Src := initialized } ->
+ error({unassigned, Src});
+ #{ Src := Tag } when Tag =/= uninitialized ->
+ error(Tag);
+ #{} ->
+ error({uninitialized_reg, Src})
+ end.
+
+set_type(Type, #value_ref{}=Ref, #vst{current=#st{vs=Vs0}=St}=Vst) ->
+ case Vs0 of
+ #{ Ref := #value{}=Entry } ->
+ Vs = Vs0#{ Ref => Entry#value{type=Type} },
+ Vst#vst{current=St#st{vs=Vs}};
+ #{} ->
+ %% Dead references may happen during type inference and are not an
+ %% error in and of themselves. If a problem were to arise from this
+ %% it'll explode elsewhere.
+ Vst
+ end.
+
+new_value(Type, Op, Ss, #vst{current=#st{vs=Vs0}=St,ref_ctr=Counter}=Vst) ->
+ Ref = #value_ref{id=Counter},
+ Vs = Vs0#{ Ref => #value{op=Op,args=Ss,type=Type} },
+
+ {Ref, Vst#vst{current=St#st{vs=Vs},ref_ctr=Counter+1}}.
+
+kill_catch_tag(Reg, #vst{current=#st{ct=[Fail|Fails]}=St}=Vst0) ->
+ Vst = Vst0#vst{current=St#st{ct=Fails,fls=undefined}},
+ {_, Fail} = get_tag_type(Reg, Vst), %Assertion.
+ kill_tag(Reg, Vst).
+
+check_try_catch_tags(Type, {y,N}=Reg, Vst) ->
+ %% Every catch or try/catch must use a lower Y register number than any
+ %% enclosing catch or try/catch. That will ensure that when the stack is
+ %% scanned when an exception occurs, the innermost try/catch tag is found
+ %% first.
+ case is_try_catch_tag(Type) of
+ true ->
+ case collect_try_catch_tags(N - 1, Vst, []) of
+ [_|_]=Bad -> error({bad_try_catch_nesting, Reg, Bad});
+ [] -> ok
+ end;
+ false ->
+ ok
+ end.
+
+is_reg_defined({x,_}=Reg, #vst{current=#st{xs=Xs}}) -> is_map_key(Reg, Xs);
+is_reg_defined({y,_}=Reg, #vst{current=#st{ys=Ys}}) -> is_map_key(Reg, Ys);
+is_reg_defined(V, #vst{}) -> error({not_a_register, V}).
assert_term(Src, Vst) ->
- get_term_type(Src, Vst),
+ _ = get_term_type(Src, Vst),
+ ok.
+
+assert_movable(Src, Vst) ->
+ _ = get_movable_term_type(Src, Vst),
ok.
+assert_literal(Src) ->
+ case is_literal(Src) of
+ true -> ok;
+ false -> error({literal_required,Src})
+ end.
+
+assert_not_literal(Src) ->
+ case is_literal(Src) of
+ true -> error({literal_not_allowed,Src});
+ false -> ok
+ end.
+
+is_literal(nil) -> true;
+is_literal({atom,A}) when is_atom(A) -> true;
+is_literal({float,F}) when is_float(F) -> true;
+is_literal({integer,I}) when is_integer(I) -> true;
+is_literal({literal,_L}) -> true;
+is_literal(_) -> false.
+
%% The possible types.
%%
%% First non-term types:
@@ -1171,10 +1934,10 @@ assert_term(Src, Vst) ->
%% used by the catch instructions; NOT safe to use in other
%% instructions.
%%
-%% exception Can only be used as a type returned by return_type/2
-%% (which gives the type of the value returned by a BIF).
-%% Thus 'exception' is never stored as type descriptor
-%% for a register.
+%% exception Can only be used as a type returned by
+%% call_return_type/2 (which gives the type of the value
+%% returned by a call). Thus 'exception' is never stored
+%% as type descriptor for a register.
%%
%% #ms{} A match context for bit syntax matching. We do allow
%% it to moved/to from stack, but otherwise it must only
@@ -1185,17 +1948,22 @@ assert_term(Src, Vst) ->
%%
%% term Any valid Erlang (but not of the special types above).
%%
+%% binary Binary or bitstring.
+%%
%% bool The atom 'true' or the atom 'false'.
%%
%% cons Cons cell: [_|_]
%%
%% nil Empty list: []
%%
-%% {tuple,[Sz]} Tuple. An element has been accessed using
-%% element/2 or setelement/3 so that it is known that
-%% the type is a tuple of size at least Sz.
+%% list List: [] or [_|_]
+%%
+%% {tuple,[Sz],Es} Tuple. An element has been accessed using
+%% element/2 or setelement/3 so that it is known that
+%% the type is a tuple of size at least Sz. Es is a map
+%% containing known types by tuple index.
%%
-%% {tuple,Sz} Tuple. A test_arity instruction has been seen
+%% {tuple,Sz,Es} Tuple. A test_arity instruction has been seen
%% so that it is known that the size is exactly Sz.
%%
%% {atom,[]} Atom.
@@ -1211,18 +1979,214 @@ assert_term(Src, Vst) ->
%%
%% map Map.
%%
+%% none A conflict in types. There will be an exception at runtime.
+%%
+
+%% join(Type1, Type2) -> Type
+%% Return the most specific type possible.
+join(Same, Same) ->
+ Same;
+join(none, Other) ->
+ Other;
+join(Other, none) ->
+ Other;
+join({literal,_}=T1, T2) ->
+ join_literal(T1, T2);
+join(T1, {literal,_}=T2) ->
+ join_literal(T2, T1);
+join({tuple,Size,EsA}, {tuple,Size,EsB}) ->
+ Es = join_tuple_elements(tuple_sz(Size), EsA, EsB),
+ {tuple, Size, Es};
+join({tuple,A,EsA}, {tuple,B,EsB}) ->
+ Size = min(tuple_sz(A), tuple_sz(B)),
+ Es = join_tuple_elements(Size, EsA, EsB),
+ {tuple, [Size], Es};
+join({Type,A}, {Type,B})
+ when Type =:= atom; Type =:= integer; Type =:= float ->
+ if A =:= B -> {Type,A};
+ true -> {Type,[]}
+ end;
+join({Type,_}, number)
+ when Type =:= integer; Type =:= float ->
+ number;
+join(number, {Type,_})
+ when Type =:= integer; Type =:= float ->
+ number;
+join({integer,_}, {float,_}) ->
+ number;
+join({float,_}, {integer,_}) ->
+ number;
+join(bool, {atom,A}) ->
+ join_bool(A);
+join({atom,A}, bool) ->
+ join_bool(A);
+join({atom,A}, {atom,B}) when is_boolean(A), is_boolean(B) ->
+ bool;
+join({atom,_}, {atom,_}) ->
+ {atom,[]};
+join(#ms{id=Id1,valid=B1,slots=Slots1},
+ #ms{id=Id2,valid=B2,slots=Slots2}) ->
+ Id = if
+ Id1 =:= Id2 -> Id1;
+ true -> make_ref()
+ end,
+ #ms{id=Id,valid=B1 band B2,slots=min(Slots1, Slots2)};
+join(T1, T2) when T1 =/= T2 ->
+ %% We've exhaused all other options, so the type must either be a list or
+ %% a 'term'.
+ join_list(T1, T2).
+
+join_tuple_elements(Limit, EsA, EsB) ->
+ Es0 = join_elements(EsA, EsB),
+ maps:filter(fun({integer,Index}, _Type) -> Index =< Limit end, Es0).
+
+join_elements(Es1, Es2) ->
+ Keys = if
+ map_size(Es1) =< map_size(Es2) -> maps:keys(Es1);
+ map_size(Es1) > map_size(Es2) -> maps:keys(Es2)
+ end,
+ join_elements_1(Keys, Es1, Es2, #{}).
+
+join_elements_1([Key | Keys], Es1, Es2, Acc0) ->
+ Type = case {Es1, Es2} of
+ {#{ Key := Same }, #{ Key := Same }} -> Same;
+ {#{ Key := Type1 }, #{ Key := Type2 }} -> join(Type1, Type2);
+ {#{}, #{}} -> term
+ end,
+ Acc = set_element_type(Key, Type, Acc0),
+ join_elements_1(Keys, Es1, Es2, Acc);
+join_elements_1([], _Es1, _Es2, Acc) ->
+ Acc.
+
+%% Joins types of literals; note that the left argument must either be a
+%% literal or exactly equal to the second argument.
+join_literal(Same, Same) ->
+ Same;
+join_literal({literal,_}=Lit, T) ->
+ join_literal(T, get_literal_type(Lit));
+join_literal(T1, T2) ->
+ %% We're done extracting the types, try merging them again.
+ join(T1, T2).
+
+join_list(nil, cons) -> list;
+join_list(nil, list) -> list;
+join_list(cons, list) -> list;
+join_list(T, nil) -> join_list(nil, T);
+join_list(T, cons) -> join_list(cons, T);
+join_list(_, _) ->
+ %% Not a list, so it must be a term.
+ term.
+
+join_bool([]) -> {atom,[]};
+join_bool(true) -> bool;
+join_bool(false) -> bool;
+join_bool(_) -> {atom,[]}.
+
+%% meet(Type1, Type2) -> Type
+%% Return the meet of two types. The meet is a more specific type.
+%% It will be 'none' if the types are in conflict.
+
+meet(Same, Same) ->
+ Same;
+meet(term, Other) ->
+ Other;
+meet(Other, term) ->
+ Other;
+meet(#ms{}, binary) ->
+ #ms{};
+meet(binary, #ms{}) ->
+ #ms{};
+meet({literal,_}, {literal,_}) ->
+ none;
+meet(T1, {literal,_}=T2) ->
+ meet(T2, T1);
+meet({literal,_}=T1, T2) ->
+ case meet(get_literal_type(T1), T2) of
+ none -> none;
+ _ -> T1
+ end;
+meet(T1, T2) ->
+ case {erlang:min(T1, T2),erlang:max(T1, T2)} of
+ {{atom,_}=A,{atom,[]}} -> A;
+ {bool,{atom,B}=Atom} when is_boolean(B) -> Atom;
+ {bool,{atom,[]}} -> bool;
+ {cons,list} -> cons;
+ {{float,_}=T,{float,[]}} -> T;
+ {{integer,_}=T,{integer,[]}} -> T;
+ {list,nil} -> nil;
+ {number,{integer,_}=T} -> T;
+ {number,{float,_}=T} -> T;
+ {{tuple,Size1,Es1},{tuple,Size2,Es2}} ->
+ Es = meet_elements(Es1, Es2),
+ case {Size1,Size2,Es} of
+ {_, _, none} ->
+ none;
+ {[Sz1],[Sz2],_} ->
+ Sz = erlang:max(Sz1, Sz2),
+ assert_tuple_elements(Sz, Es),
+ {tuple,[Sz],Es};
+ {Sz1,[Sz2],_} when Sz2 =< Sz1 ->
+ assert_tuple_elements(Sz1, Es),
+ {tuple,Sz1,Es};
+ {Sz,Sz,_} ->
+ assert_tuple_elements(Sz, Es),
+ {tuple,Sz,Es};
+ {_,_,_} ->
+ none
+ end;
+ {_,_} -> none
+ end.
+
+meet_elements(Es1, Es2) ->
+ Keys = maps:keys(Es1) ++ maps:keys(Es2),
+ meet_elements_1(Keys, Es1, Es2, #{}).
+
+meet_elements_1([Key | Keys], Es1, Es2, Acc) ->
+ case {Es1, Es2} of
+ {#{ Key := Type1 }, #{ Key := Type2 }} ->
+ case meet(Type1, Type2) of
+ none -> none;
+ Type -> meet_elements_1(Keys, Es1, Es2, Acc#{ Key => Type })
+ end;
+ {#{ Key := Type1 }, _} ->
+ meet_elements_1(Keys, Es1, Es2, Acc#{ Key => Type1 });
+ {_, #{ Key := Type2 }} ->
+ meet_elements_1(Keys, Es1, Es2, Acc#{ Key => Type2 })
+ end;
+meet_elements_1([], _Es1, _Es2, Acc) ->
+ Acc.
+
+%% No tuple elements may have an index above the known size.
+assert_tuple_elements(Limit, Es) ->
+ true = maps:fold(fun({integer,Index}, _T, true) ->
+ Index =< Limit
+ end, true, Es). %Assertion.
+
+%% subtract(Type1, Type2) -> Type
+%% Subtract Type2 from Type2. Example:
+%% subtract(list, nil) -> cons
+
+subtract(Same, Same) -> none;
+subtract(list, nil) -> cons;
+subtract(list, cons) -> nil;
+subtract(number, {integer,[]}) -> {float,[]};
+subtract(number, {float,[]}) -> {integer,[]};
+subtract(bool, {atom,false}) -> {atom, true};
+subtract(bool, {atom,true}) -> {atom, false};
+subtract(Type, _) -> Type.
assert_type(WantedType, Term, Vst) ->
- assert_type(WantedType, get_term_type(Term, Vst)).
+ Type = get_term_type(Term, Vst),
+ assert_type(WantedType, Type).
assert_type(Correct, Correct) -> ok;
assert_type(float, {float,_}) -> ok;
-assert_type(tuple, {tuple,_}) -> ok;
+assert_type(tuple, {tuple,_,_}) -> ok;
assert_type(tuple, {literal,Tuple}) when is_tuple(Tuple) -> ok;
-assert_type({tuple_element,I}, {tuple,[Sz]})
+assert_type({tuple_element,I}, {tuple,[Sz],_})
when 1 =< I, I =< Sz ->
ok;
-assert_type({tuple_element,I}, {tuple,Sz})
+assert_type({tuple_element,I}, {tuple,Sz,_})
when is_integer(Sz), 1 =< I, I =< Sz ->
ok;
assert_type({tuple_element,I}, {literal,Lit}) when I =< tuple_size(Lit) ->
@@ -1232,138 +2196,300 @@ assert_type(cons, {literal,[_|_]}) ->
assert_type(Needed, Actual) ->
error({bad_type,{needed,Needed},{actual,Actual}}).
-%% upgrade_tuple_type(NewTupleType, OldType) -> TupleType.
-%% upgrade_tuple_type/2 is used when linear code finds out more and
-%% more information about a tuple type, so that the type gets more
-%% specialized. If OldType is not a tuple type, the type information
-%% is inconsistent, and we know that some instructions will never
-%% be executed at run-time.
-
-upgrade_tuple_type({tuple,[Sz]}, {tuple,[OldSz]}=T) when Sz < OldSz ->
- %% The old type has a higher value for the least tuple size.
- T;
-upgrade_tuple_type({tuple,[Sz]}, {tuple,OldSz}=T)
- when is_integer(Sz), is_integer(OldSz), Sz =< OldSz ->
- %% The old size is exact, and the new size is smaller than the old size.
- T;
-upgrade_tuple_type({tuple,_}=T, _) ->
- %% The new type information is exact or has a higher value for
- %% the least tuple size.
- %% Note that inconsistencies are also handled in this
- %% clause, e.g. if the old type was an integer or a tuple accessed
- %% outside its size; inconsistences will generally cause an exception
- %% at run-time but are safe from our point of view.
- T.
+get_element_type(Key, Src, Vst) ->
+ get_element_type_1(Key, get_term_type(Src, Vst)).
+
+get_element_type_1({integer,_}=Key, {tuple,_Sz,Es}) ->
+ case Es of
+ #{ Key := Type } -> Type;
+ #{} -> term
+ end;
+get_element_type_1(_Index, _Type) ->
+ term.
+
+set_element_type(_Key, none, Es) ->
+ Es;
+set_element_type(Key, term, Es) ->
+ maps:remove(Key, Es);
+set_element_type(Key, Type, Es) ->
+ Es#{ Key => Type }.
get_tuple_size({integer,[]}) -> 0;
get_tuple_size({integer,Sz}) -> Sz;
get_tuple_size(_) -> 0.
validate_src(Ss, Vst) when is_list(Ss) ->
- foreach(fun(S) -> get_term_type(S, Vst) end, Ss).
+ _ = [assert_term(S, Vst) || S <- Ss],
+ ok.
-%% get_move_term_type(Src, ValidatorState) -> Type
+%% get_term_type(Src, ValidatorState) -> Type
%% Get the type of the source Src. The returned type Type will be
-%% a standard Erlang type (no catch/try tags). Match contexts are OK.
+%% a standard Erlang type (no catch/try tags or match contexts).
-get_move_term_type(Src, Vst) ->
- case get_term_type_1(Src, Vst) of
- initialized -> error({unassigned,Src});
- {catchtag,_} -> error({catchtag,Src});
- {trytag,_} -> error({trytag,Src});
- Type -> Type
+get_term_type(Src, Vst) ->
+ case get_movable_term_type(Src, Vst) of
+ #ms{} -> error({match_context,Src});
+ Type -> Type
end.
-%% get_term_type(Src, ValidatorState) -> Type
+%% get_movable_term_type(Src, ValidatorState) -> Type
%% Get the type of the source Src. The returned type Type will be
-%% a standard Erlang type (no catch/try tags or match contexts).
+%% a standard Erlang type (no catch/try tags). Match contexts are OK.
-get_term_type(Src, Vst) ->
- case get_term_type_1(Src, Vst) of
- initialized -> error({unassigned,Src});
- {catchtag,_} -> error({catchtag,Src});
- {trytag,_} -> error({trytag,Src});
- #ms{} -> error({match_context,Src});
- Type -> Type
+get_movable_term_type(Src, Vst) ->
+ case get_raw_type(Src, Vst) of
+ initialized -> error({unassigned,Src});
+ uninitialized -> error({uninitialized_reg,Src});
+ {catchtag,_} -> error({catchtag,Src});
+ {trytag,_} -> error({trytag,Src});
+ tuple_in_progress -> error({tuple_in_progress,Src});
+ {literal,_}=Lit -> get_literal_type(Lit);
+ Type -> Type
end.
-%% get_special_y_type(Src, ValidatorState) -> Type
-%% Return the type for the Y register without doing any validity checks.
-
-get_special_y_type({y,_}=Reg, Vst) -> get_term_type_1(Reg, Vst);
-get_special_y_type(Src, _) -> error({source_not_y_reg,Src}).
-
-get_term_type_1(nil=T, _) -> T;
-get_term_type_1({atom,A}=T, _) when is_atom(A) -> T;
-get_term_type_1({float,F}=T, _) when is_float(F) -> T;
-get_term_type_1({integer,I}=T, _) when is_integer(I) -> T;
-get_term_type_1({literal,Map}, _) when is_map(Map) -> map;
-get_term_type_1({literal,_}=T, _) -> T;
-get_term_type_1({x,X}=Reg, #vst{current=#st{x=Xs}}) when is_integer(X) ->
- case gb_trees:lookup(X, Xs) of
- {value,Type} -> Type;
- none -> error({uninitialized_reg,Reg})
+%% get_tag_type(Src, ValidatorState) -> Type
+%% Return the tag type of a Y register, erroring out if it contains a term.
+
+get_tag_type({y,_}=Src, Vst) ->
+ case get_raw_type(Src, Vst) of
+ {catchtag, _}=Tag -> Tag;
+ {trytag, _}=Tag -> Tag;
+ uninitialized=Tag -> Tag;
+ initialized=Tag -> Tag;
+ Other -> error({invalid_tag,Src,Other})
end;
-get_term_type_1({y,Y}=Reg, #vst{current=#st{y=Ys}}) when is_integer(Y) ->
- case gb_trees:lookup(Y, Ys) of
- none -> error({uninitialized_reg,Reg});
- {value,uninitialized} -> error({uninitialized_reg,Reg});
- {value,Type} -> Type
+get_tag_type(Src, _) ->
+ error({invalid_tag_register,Src}).
+
+%% get_raw_type(Src, ValidatorState) -> Type
+%% Return the type of a register without doing any validity checks or
+%% conversions.
+get_raw_type({x,X}=Src, #vst{current=#st{xs=Xs}}=Vst) when is_integer(X) ->
+ check_limit(Src),
+ case Xs of
+ #{ Src := #value_ref{}=Ref } -> get_raw_type(Ref, Vst);
+ #{} -> uninitialized
end;
-get_term_type_1(Src, _) -> error({bad_source,Src}).
-
+get_raw_type({y,Y}=Src, #vst{current=#st{ys=Ys}}=Vst) when is_integer(Y) ->
+ check_limit(Src),
+ case Ys of
+ #{ Src := #value_ref{}=Ref } -> get_raw_type(Ref, Vst);
+ #{ Src := Tag } -> Tag;
+ #{} -> uninitialized
+ end;
+get_raw_type(#value_ref{}=Ref, #vst{current=#st{vs=Vs}}) ->
+ case Vs of
+ #{ Ref := #value{type=Type} } -> Type;
+ #{} -> none
+ end;
+get_raw_type(Src, #vst{}) ->
+ get_literal_type(Src).
+
+is_value_alive(#value_ref{}=Ref, #vst{current=#st{vs=Vs}}) ->
+ is_map_key(Ref, Vs).
+
+get_literal_type(nil=T) -> T;
+get_literal_type({atom,A}=T) when is_atom(A) -> T;
+get_literal_type({float,F}=T) when is_float(F) -> T;
+get_literal_type({integer,I}=T) when is_integer(I) -> T;
+get_literal_type({literal,[_|_]}) -> cons;
+get_literal_type({literal,Bitstring}) when is_bitstring(Bitstring) -> binary;
+get_literal_type({literal,Map}) when is_map(Map) -> map;
+get_literal_type({literal,Tuple}) when is_tuple(Tuple) -> glt_1(Tuple);
+get_literal_type({literal,_}) -> term;
+get_literal_type(T) -> error({not_literal,T}).
+
+glt_1([]) -> nil;
+glt_1(A) when is_atom(A) -> {atom, A};
+glt_1(F) when is_float(F) -> {float, F};
+glt_1(I) when is_integer(I) -> {integer, I};
+glt_1(T) when is_tuple(T) ->
+ {Es,_} = foldl(fun(Val, {Es0, Index}) ->
+ Type = glt_1(Val),
+ Es = set_element_type({integer,Index}, Type, Es0),
+ {Es, Index + 1}
+ end, {#{}, 1}, tuple_to_list(T)),
+ {tuple, tuple_size(T), Es};
+glt_1(L) ->
+ {literal, L}.
-%% get_literal(Src) -> literal_value().
-get_literal(nil) -> [];
-get_literal({atom,A}) when is_atom(A) -> A;
-get_literal({float,F}) when is_float(F) -> F;
-get_literal({integer,I}) when is_integer(I) -> I;
-get_literal({literal,L}) -> L;
-get_literal(T) -> error({not_literal,T}).
+%%%
+%%% Branch tracking
+%%%
+%% Forks the execution flow, with the provided funs returning the new state of
+%% their respective branch; the "fail" fun returns the state where the branch
+%% is taken, and the "success" fun returns the state where it's not.
+%%
+%% If either path is known not to be taken at runtime (eg. due to a type
+%% conflict), it will simply be discarded.
+-spec branch(Lbl :: label(),
+ Original :: #vst{},
+ FailFun :: BranchFun,
+ SuccFun :: BranchFun) -> #vst{} when
+ BranchFun :: fun((#vst{}) -> #vst{}).
+branch(Lbl, Vst0, FailFun, SuccFun) ->
+ #vst{current=St0} = Vst0,
+ try FailFun(Vst0) of
+ Vst1 ->
+ Vst2 = branch_state(Lbl, Vst1),
+ Vst = Vst2#vst{current=St0},
+ try SuccFun(Vst) of
+ V -> V
+ catch
+ {type_conflict, _, _} ->
+ %% The instruction is guaranteed to fail; kill the state.
+ kill_state(Vst)
+ end
+ catch
+ {type_conflict, _, _} ->
+ %% This instruction is guaranteed not to fail, so we run the
+ %% success branch *without* catching type conflicts to avoid hiding
+ %% errors in the validator itself; one of the branches must
+ %% succeed.
+ SuccFun(Vst0)
+ end.
-branch_arities([], _, #vst{}=Vst) -> Vst;
-branch_arities([Sz,{f,L}|T], Tuple, #vst{current=St}=Vst0)
- when is_integer(Sz) ->
- Vst1 = set_type_reg({tuple,Sz}, Tuple, Vst0),
- Vst = branch_state(L, Vst1),
- branch_arities(T, Tuple, Vst#vst{current=St}).
+%% A shorthand version of branch/4 for when the state is only altered on
+%% success.
+branch(Fail, Vst, SuccFun) ->
+ branch(Fail, Vst, fun(V) -> V end, SuccFun).
+%% Directly branches off the state. This is an "internal" operation that should
+%% be used sparingly.
branch_state(0, #vst{}=Vst) ->
- %% If the instruction fails, the stack may be scanned
- %% looking for a catch tag. Therefore the Y registers
- %% must be initialized at this point.
+ %% If the instruction fails, the stack may be scanned looking for a catch
+ %% tag. Therefore the Y registers must be initialized at this point.
verify_y_init(Vst),
Vst;
-branch_state(L, #vst{current=St,branched=B}=Vst) ->
- Vst#vst{
- branched=case gb_trees:is_defined(L, B) of
- false ->
- gb_trees:insert(L, St, B);
- true ->
- MergedSt = merge_states(L, St, B),
- gb_trees:update(L, MergedSt, B)
- end}.
-
-%% merge_states/3 is used when there are more than one way to arrive
-%% at this point, and the type states for the different paths has
-%% to be merged. The type states are downgraded to the least common
-%% subset for the subsequent code.
-
-merge_states(L, St, Branched) when L =/= 0 ->
+branch_state(L, #vst{current=St,branched=B,ref_ctr=Counter0}=Vst) ->
+ case gb_trees:is_defined(L, B) of
+ true ->
+ {MergedSt, Counter} = merge_states(L, St, B, Counter0),
+ Branched = gb_trees:update(L, MergedSt, B),
+ Vst#vst{branched=Branched,ref_ctr=Counter};
+ false ->
+ Vst#vst{branched=gb_trees:insert(L, St, B)}
+ end.
+
+%% merge_states/3 is used when there's more than one way to arrive at a
+%% certain point, requiring the states to be merged down to the least
+%% common subset for the subsequent code.
+
+merge_states(L, St, Branched, Counter) when L =/= 0 ->
case gb_trees:lookup(L, Branched) of
- none -> St;
- {value,OtherSt} when St =:= none -> OtherSt;
- {value,OtherSt} -> merge_states_1(St, OtherSt)
+ none ->
+ {St, Counter};
+ {value,OtherSt} when St =:= none ->
+ {OtherSt, Counter};
+ {value,OtherSt} ->
+ merge_states_1(St, OtherSt, Counter)
+ end.
+
+merge_states_1(#st{xs=XsA,ys=YsA,vs=VsA,fragile=FragA,numy=NumYA,h=HA,ct=CtA},
+ #st{xs=XsB,ys=YsB,vs=VsB,fragile=FragB,numy=NumYB,h=HB,ct=CtB},
+ Counter0) ->
+ %% When merging registers we drop all registers that aren't defined in both
+ %% states, and resolve conflicts by creating new values (similar to phi
+ %% nodes in SSA).
+ %%
+ %% While doing this we build a "merge map" detailing which values need to
+ %% be kept and which new values need to be created to resolve conflicts.
+ %% This map is then used to create a new value database where the types of
+ %% all values have been joined.
+ {Xs, Merge0, Counter1} = merge_regs(XsA, XsB, #{}, Counter0),
+ {Ys, Merge, Counter} = merge_regs(YsA, YsB, Merge0, Counter1),
+ Vs = merge_values(Merge, VsA, VsB),
+
+ Fragile = merge_fragility(FragA, FragB),
+ NumY = merge_stk(NumYA, NumYB),
+ Ct = merge_ct(CtA, CtB),
+
+ St = #st{xs=Xs,ys=Ys,vs=Vs,fragile=Fragile,numy=NumY,h=min(HA, HB),ct=Ct},
+ {St, Counter}.
+
+%% Merges the contents of two register maps, returning the updated "merge map"
+%% and the new registers.
+merge_regs(RsA, RsB, Merge, Counter) ->
+ Keys = if
+ map_size(RsA) =< map_size(RsB) -> maps:keys(RsA);
+ map_size(RsA) > map_size(RsB) -> maps:keys(RsB)
+ end,
+ merge_regs_1(Keys, RsA, RsB, #{}, Merge, Counter).
+
+merge_regs_1([Reg | Keys], RsA, RsB, Regs, Merge0, Counter0) ->
+ case {RsA, RsB} of
+ {#{ Reg := #value_ref{}=RefA }, #{ Reg := #value_ref{}=RefB }} ->
+ {Ref, Merge, Counter} = merge_vrefs(RefA, RefB, Merge0, Counter0),
+ merge_regs_1(Keys, RsA, RsB, Regs#{ Reg => Ref }, Merge, Counter);
+ {#{ Reg := TagA }, #{ Reg := TagB }} ->
+ %% Tags describe the state of the register rather than the value it
+ %% contains, so if a register contains a tag in one state we have
+ %% to merge it as a tag regardless of whether the other state says
+ %% it's a value.
+ {y, _} = Reg, %Assertion.
+ merge_regs_1(Keys, RsA, RsB, Regs#{ Reg => merge_tags(TagA,TagB) },
+ Merge0, Counter0);
+ {#{}, #{}} ->
+ merge_regs_1(Keys, RsA, RsB, Regs, Merge0, Counter0)
+ end;
+merge_regs_1([], _, _, Regs, Merge, Counter) ->
+ {Regs, Merge, Counter}.
+
+merge_tags(Same, Same) ->
+ Same;
+merge_tags(uninitialized, _) ->
+ uninitialized;
+merge_tags(_, uninitialized) ->
+ uninitialized;
+merge_tags({catchtag,T0}, {catchtag,T1}) ->
+ {catchtag, ordsets:from_list(T0 ++ T1)};
+merge_tags({trytag,T0}, {trytag,T1}) ->
+ {trytag, ordsets:from_list(T0 ++ T1)};
+merge_tags(_A, _B) ->
+ %% All other combinations leave the register initialized. Errors arising
+ %% from this will be caught later on.
+ initialized.
+
+merge_vrefs(Ref, Ref, Merge, Counter) ->
+ %% We have two (potentially) different versions of the same value, so we
+ %% should join their types into the same value.
+ {Ref, Merge#{ Ref => Ref }, Counter};
+merge_vrefs(RefA, RefB, Merge, Counter) ->
+ %% We have two different values, so we need to create a new value from
+ %% their joined type if we haven't already done so.
+ Key = {RefA, RefB},
+ case Merge of
+ #{ Key := Ref } ->
+ {Ref, Merge, Counter};
+ #{} ->
+ Ref = #value_ref{id=Counter},
+ {Ref, Merge#{ Key => Ref }, Counter + 1}
end.
-merge_states_1(#st{x=Xs0,y=Ys0,numy=NumY0,h=H0,ct=Ct0},
- #st{x=Xs1,y=Ys1,numy=NumY1,h=H1,ct=Ct1}) ->
- NumY = merge_stk(NumY0, NumY1),
- Xs = merge_regs(Xs0, Xs1),
- Ys = merge_y_regs(Ys0, Ys1),
- Ct = merge_ct(Ct0, Ct1),
- #st{x=Xs,y=Ys,numy=NumY,h=min(H0, H1),ct=Ct}.
+merge_values(Merge, VsA, VsB) ->
+ maps:fold(fun(Spec, New, Acc) ->
+ merge_values_1(Spec, New, VsA, VsB, Acc)
+ end, #{}, Merge).
+
+merge_values_1(Same, Same, VsA, VsB, Acc) ->
+ %% We're merging different versions of the same value, so it's safe to
+ %% reuse old entries if the type's unchanged.
+ #value{type=TypeA}=EntryA = map_get(Same, VsA),
+ #value{type=TypeB}=EntryB = map_get(Same, VsB),
+ Entry = case join(TypeA, TypeB) of
+ TypeA -> EntryA;
+ TypeB -> EntryB;
+ JoinedType -> EntryA#value{type=JoinedType}
+ end,
+ Acc#{ Same => Entry };
+merge_values_1({RefA, RefB}, New, VsA, VsB, Acc) ->
+ #value{type=TypeA} = map_get(RefA, VsA),
+ #value{type=TypeB} = map_get(RefB, VsB),
+ Acc#{ New => #value{op=join,args=[],type=join(TypeA, TypeB)} }.
+
+merge_fragility(FragileA, FragileB) ->
+ cerl_sets:union(FragileA, FragileB).
merge_stk(S, S) -> S;
merge_stk(_, _) -> undecided.
@@ -1376,123 +2502,70 @@ merge_ct_1([C0|Ct0], [C1|Ct1]) ->
merge_ct_1([], []) -> [];
merge_ct_1(_, _) -> undecided.
-merge_regs(Rs0, Rs1) ->
- Rs = merge_regs_1(gb_trees:to_list(Rs0), gb_trees:to_list(Rs1)),
- gb_trees_from_list(Rs).
-
-merge_regs_1([Same|Rs1], [Same|Rs2]) ->
- [Same|merge_regs_1(Rs1, Rs2)];
-merge_regs_1([{R1,_}|Rs1], [{R2,_}|_]=Rs2) when R1 < R2 ->
- merge_regs_1(Rs1, Rs2);
-merge_regs_1([{R1,_}|_]=Rs1, [{R2,_}|Rs2]) when R1 > R2 ->
- merge_regs_1(Rs1, Rs2);
-merge_regs_1([{R,Type1}|Rs1], [{R,Type2}|Rs2]) ->
- [{R,merge_types(Type1, Type2)}|merge_regs_1(Rs1, Rs2)];
-merge_regs_1([], []) -> [];
-merge_regs_1([], [_|_]) -> [];
-merge_regs_1([_|_], []) -> [].
-
-merge_y_regs(Rs0, Rs1) ->
- case {gb_trees:size(Rs0),gb_trees:size(Rs1)} of
- {Sz0,Sz1} when Sz0 < Sz1 ->
- merge_y_regs_1(Sz0-1, Rs1, Rs0);
- {_,Sz1} ->
- merge_y_regs_1(Sz1-1, Rs0, Rs1)
- end.
+tuple_sz([Sz]) -> Sz;
+tuple_sz(Sz) -> Sz.
-merge_y_regs_1(Y, S, Regs0) when Y >= 0 ->
- Type0 = gb_trees:get(Y, Regs0),
- case gb_trees:get(Y, S) of
- Type0 ->
- merge_y_regs_1(Y-1, S, Regs0);
- Type1 ->
- Type = merge_types(Type0, Type1),
- Regs = gb_trees:update(Y, Type, Regs0),
- merge_y_regs_1(Y-1, S, Regs)
- end;
-merge_y_regs_1(_, _, Regs) -> Regs.
+verify_y_init(#vst{current=#st{numy=NumY,ys=Ys}}=Vst) when is_integer(NumY) ->
+ HighestY = maps:fold(fun({y,Y}, _, Acc) -> max(Y, Acc) end, -1, Ys),
+ true = NumY > HighestY, %Assertion.
+ verify_y_init_1(NumY - 1, Vst),
+ ok;
+verify_y_init(#vst{current=#st{numy=undecided,ys=Ys}}=Vst) ->
+ HighestY = maps:fold(fun({y,Y}, _, Acc) -> max(Y, Acc) end, -1, Ys),
+ verify_y_init_1(HighestY, Vst);
+verify_y_init(#vst{}) ->
+ ok.
-%% merge_types(Type1, Type2) -> Type
-%% Return the most specific type possible.
-%% Note: Type1 must NOT be the same as Type2.
-merge_types(uninitialized=I, _) -> I;
-merge_types(_, uninitialized=I) -> I;
-merge_types(initialized=I, _) -> I;
-merge_types(_, initialized=I) -> I;
-merge_types({catchtag,T0},{catchtag,T1}) ->
- {catchtag,ordsets:from_list(T0++T1)};
-merge_types({trytag,T0},{trytag,T1}) ->
- {trytag,ordsets:from_list(T0++T1)};
-merge_types({tuple,A}, {tuple,B}) ->
- {tuple,[min(tuple_sz(A), tuple_sz(B))]};
-merge_types({Type,A}, {Type,B})
- when Type =:= atom; Type =:= integer; Type =:= float ->
- if A =:= B -> {Type,A};
- true -> {Type,[]}
- end;
-merge_types({Type,_}, number)
- when Type =:= integer; Type =:= float ->
- number;
-merge_types(number, {Type,_})
- when Type =:= integer; Type =:= float ->
- number;
-merge_types(bool, {atom,A}) ->
- merge_bool(A);
-merge_types({atom,A}, bool) ->
- merge_bool(A);
-merge_types(#ms{id=Id1,valid=B1,slots=Slots1},
- #ms{id=Id2,valid=B2,slots=Slots2}) ->
- Id = if
- Id1 =:= Id2 -> Id1;
- true -> make_ref()
- end,
- #ms{id=Id,valid=B1 band B2,slots=min(Slots1, Slots2)};
-merge_types(T1, T2) when T1 =/= T2 ->
- %% Too different. All we know is that the type is a 'term'.
- term.
+verify_y_init_1(-1, _Vst) ->
+ ok;
+verify_y_init_1(Y, Vst) ->
+ Reg = {y, Y},
+ assert_not_fragile(Reg, Vst),
+ case get_raw_type(Reg, Vst) of
+ uninitialized -> error({uninitialized_reg,Reg});
+ _ -> verify_y_init_1(Y - 1, Vst)
+ end.
-tuple_sz([Sz]) -> Sz;
-tuple_sz(Sz) -> Sz.
+verify_live(0, _Vst) ->
+ ok;
+verify_live(Live, Vst) when is_integer(Live), 0 < Live, Live =< 1023 ->
+ verify_live_1(Live - 1, Vst);
+verify_live(Live, _Vst) ->
+ error({bad_number_of_live_regs,Live}).
-merge_bool([]) -> {atom,[]};
-merge_bool(true) -> bool;
-merge_bool(false) -> bool;
-merge_bool(_) -> {atom,[]}.
-
-verify_y_init(#vst{current=#st{y=Ys}}) ->
- verify_y_init_1(gb_trees:to_list(Ys)).
-
-verify_y_init_1([]) -> ok;
-verify_y_init_1([{Y,uninitialized}|_]) ->
- error({uninitialized_reg,{y,Y}});
-verify_y_init_1([{_,_}|Ys]) ->
- verify_y_init_1(Ys).
-
-verify_live(0, #vst{}) -> ok;
-verify_live(N, #vst{current=#st{x=Xs}}) ->
- verify_live_1(N, Xs).
-
-verify_live_1(0, _) -> ok;
-verify_live_1(N, Xs) when is_integer(N) ->
- X = N-1,
- case gb_trees:is_defined(X, Xs) of
- false -> error({{x,X},not_live});
- true -> verify_live_1(X, Xs)
- end;
-verify_live_1(N, _) -> error({bad_number_of_live_regs,N}).
+verify_live_1(-1, _) ->
+ ok;
+verify_live_1(X, Vst) when is_integer(X) ->
+ Reg = {x, X},
+ case get_raw_type(Reg, Vst) of
+ uninitialized -> error({Reg, not_live});
+ _ -> verify_live_1(X - 1, Vst)
+ end.
-verify_no_ct(#vst{current=#st{numy=none}}) -> ok;
+verify_no_ct(#vst{current=#st{numy=none}}) ->
+ ok;
verify_no_ct(#vst{current=#st{numy=undecided}}) ->
error(unknown_size_of_stackframe);
-verify_no_ct(#vst{current=#st{y=Ys}}) ->
- case [Y || Y <- gb_trees:to_list(Ys), verify_no_ct_1(Y)] of
- [] -> ok;
- CT -> error({unfinished_catch_try,CT})
+verify_no_ct(#vst{current=St}=Vst) ->
+ case collect_try_catch_tags(St#st.numy - 1, Vst, []) of
+ [_|_]=Bad -> error({unfinished_catch_try,Bad});
+ [] -> ok
end.
-verify_no_ct_1({_, {catchtag, _}}) -> true;
-verify_no_ct_1({_, {trytag, _}}) -> true;
-verify_no_ct_1({_, _}) -> false.
+%% Collects all try/catch tags, walking down from the Nth stack position.
+collect_try_catch_tags(-1, _Vst, Acc) ->
+ Acc;
+collect_try_catch_tags(Y, Vst, Acc0) ->
+ Tag = get_raw_type({y, Y}, Vst),
+ Acc = case is_try_catch_tag(Tag) of
+ true -> [{{y, Y}, Tag} | Acc0];
+ false -> Acc0
+ end,
+ collect_try_catch_tags(Y - 1, Vst, Acc).
+
+is_try_catch_tag({catchtag,_}) -> true;
+is_try_catch_tag({trytag,_}) -> true;
+is_try_catch_tag(_) -> false.
eat_heap(N, #vst{current=#st{h=Heap0}=St}=Vst) ->
case Heap0-N of
@@ -1510,68 +2583,190 @@ eat_heap_float(#vst{current=#st{hf=HeapFloats0}=St}=Vst) ->
Vst#vst{current=St#st{hf=HeapFloats}}
end.
-bif_type('-', Src, Vst) ->
- arith_type(Src, Vst);
-bif_type('+', Src, Vst) ->
- arith_type(Src, Vst);
-bif_type('*', Src, Vst) ->
- arith_type(Src, Vst);
-bif_type(abs, [Num], Vst) ->
+%%% FRAGILITY
+%%%
+%%% The loop_rec/2 instruction may return a reference to a term that is not
+%%% part of the root set. That term or any part of it must not be included in a
+%%% garbage collection. Therefore, the term (or any part of it) must not be
+%%% passed to another function, placed in another term, or live in a Y register
+%%% over an instruction that may GC.
+%%%
+%%% Fragility is marked on a per-register (rather than per-value) basis.
+
+%% Marks Reg as fragile.
+mark_fragile(Reg, Vst) ->
+ #vst{current=#st{fragile=Fragile0}=St0} = Vst,
+ Fragile = cerl_sets:add_element(Reg, Fragile0),
+ St = St0#st{fragile=Fragile},
+ Vst#vst{current=St}.
+
+propagate_fragility(Reg, Args, #vst{current=St0}=Vst) ->
+ #st{fragile=Fragile0} = St0,
+
+ Sources = cerl_sets:from_list(Args),
+ Fragile = case cerl_sets:is_disjoint(Sources, Fragile0) of
+ true -> cerl_sets:del_element(Reg, Fragile0);
+ false -> cerl_sets:add_element(Reg, Fragile0)
+ end,
+
+ St = St0#st{fragile=Fragile},
+ Vst#vst{current=St}.
+
+%% Marks Reg as durable, must be used when assigning a newly created value to
+%% a register.
+remove_fragility(Reg, Vst) ->
+ #vst{current=#st{fragile=Fragile0}=St0} = Vst,
+ case cerl_sets:is_element(Reg, Fragile0) of
+ true ->
+ Fragile = cerl_sets:del_element(Reg, Fragile0),
+ St = St0#st{fragile=Fragile},
+ Vst#vst{current=St};
+ false ->
+ Vst
+ end.
+
+%% Marks all registers as durable.
+remove_fragility(#vst{current=St0}=Vst) ->
+ St = St0#st{fragile=cerl_sets:new()},
+ Vst#vst{current=St}.
+
+assert_durable_term(Src, Vst) ->
+ assert_term(Src, Vst),
+ assert_not_fragile(Src, Vst).
+
+assert_not_fragile({Kind,_}=Src, Vst) when Kind =:= x; Kind =:= y ->
+ check_limit(Src),
+ #vst{current=#st{fragile=Fragile}} = Vst,
+ case cerl_sets:is_element(Src, Fragile) of
+ true -> error({fragile_message_reference, Src});
+ false -> ok
+ end;
+assert_not_fragile(Lit, #vst{}) ->
+ assert_literal(Lit),
+ ok.
+
+%%%
+%%% Return/argument types of BIFs
+%%%
+
+bif_return_type('-', Src, Vst) ->
+ arith_return_type(Src, Vst);
+bif_return_type('+', Src, Vst) ->
+ arith_return_type(Src, Vst);
+bif_return_type('*', Src, Vst) ->
+ arith_return_type(Src, Vst);
+bif_return_type(abs, [Num], Vst) ->
case get_term_type(Num, Vst) of
- {float,_}=T -> T;
- {integer,_}=T -> T;
- _ -> number
+ {float,_}=T -> T;
+ {integer,_}=T -> T;
+ _ -> number
end;
-bif_type(float, _, _) -> {float,[]};
-bif_type('/', _, _) -> {float,[]};
+bif_return_type(float, _, _) -> {float,[]};
+bif_return_type('/', _, _) -> {float,[]};
+%% Binary operations
+bif_return_type('binary_part', [_,_], _) -> binary;
+bif_return_type('binary_part', [_,_,_], _) -> binary;
+bif_return_type('bit_size', [_], _) -> {integer,[]};
+bif_return_type('byte_size', [_], _) -> {integer,[]};
%% Integer operations.
-bif_type(ceil, [_], _) -> {integer,[]};
-bif_type('div', [_,_], _) -> {integer,[]};
-bif_type(floor, [_], _) -> {integer,[]};
-bif_type('rem', [_,_], _) -> {integer,[]};
-bif_type(length, [_], _) -> {integer,[]};
-bif_type(size, [_], _) -> {integer,[]};
-bif_type(trunc, [_], _) -> {integer,[]};
-bif_type(round, [_], _) -> {integer,[]};
-bif_type('band', [_,_], _) -> {integer,[]};
-bif_type('bor', [_,_], _) -> {integer,[]};
-bif_type('bxor', [_,_], _) -> {integer,[]};
-bif_type('bnot', [_], _) -> {integer,[]};
-bif_type('bsl', [_,_], _) -> {integer,[]};
-bif_type('bsr', [_,_], _) -> {integer,[]};
+bif_return_type(ceil, [_], _) -> {integer,[]};
+bif_return_type('div', [_,_], _) -> {integer,[]};
+bif_return_type(floor, [_], _) -> {integer,[]};
+bif_return_type('rem', [_,_], _) -> {integer,[]};
+bif_return_type(length, [_], _) -> {integer,[]};
+bif_return_type(size, [_], _) -> {integer,[]};
+bif_return_type(trunc, [_], _) -> {integer,[]};
+bif_return_type(round, [_], _) -> {integer,[]};
+bif_return_type('band', [_,_], _) -> {integer,[]};
+bif_return_type('bor', [_,_], _) -> {integer,[]};
+bif_return_type('bxor', [_,_], _) -> {integer,[]};
+bif_return_type('bnot', [_], _) -> {integer,[]};
+bif_return_type('bsl', [_,_], _) -> {integer,[]};
+bif_return_type('bsr', [_,_], _) -> {integer,[]};
%% Booleans.
-bif_type('==', [_,_], _) -> bool;
-bif_type('/=', [_,_], _) -> bool;
-bif_type('=<', [_,_], _) -> bool;
-bif_type('<', [_,_], _) -> bool;
-bif_type('>=', [_,_], _) -> bool;
-bif_type('>', [_,_], _) -> bool;
-bif_type('=:=', [_,_], _) -> bool;
-bif_type('=/=', [_,_], _) -> bool;
-bif_type('not', [_], _) -> bool;
-bif_type('and', [_,_], _) -> bool;
-bif_type('or', [_,_], _) -> bool;
-bif_type('xor', [_,_], _) -> bool;
-bif_type(is_atom, [_], _) -> bool;
-bif_type(is_boolean, [_], _) -> bool;
-bif_type(is_binary, [_], _) -> bool;
-bif_type(is_float, [_], _) -> bool;
-bif_type(is_function, [_], _) -> bool;
-bif_type(is_integer, [_], _) -> bool;
-bif_type(is_list, [_], _) -> bool;
-bif_type(is_map, [_], _) -> bool;
-bif_type(is_number, [_], _) -> bool;
-bif_type(is_pid, [_], _) -> bool;
-bif_type(is_port, [_], _) -> bool;
-bif_type(is_reference, [_], _) -> bool;
-bif_type(is_tuple, [_], _) -> bool;
+bif_return_type('==', [_,_], _) -> bool;
+bif_return_type('/=', [_,_], _) -> bool;
+bif_return_type('=<', [_,_], _) -> bool;
+bif_return_type('<', [_,_], _) -> bool;
+bif_return_type('>=', [_,_], _) -> bool;
+bif_return_type('>', [_,_], _) -> bool;
+bif_return_type('=:=', [_,_], _) -> bool;
+bif_return_type('=/=', [_,_], _) -> bool;
+bif_return_type('not', [_], _) -> bool;
+bif_return_type('and', [_,_], _) -> bool;
+bif_return_type('or', [_,_], _) -> bool;
+bif_return_type('xor', [_,_], _) -> bool;
+bif_return_type(is_atom, [_], _) -> bool;
+bif_return_type(is_boolean, [_], _) -> bool;
+bif_return_type(is_binary, [_], _) -> bool;
+bif_return_type(is_float, [_], _) -> bool;
+bif_return_type(is_function, [_], _) -> bool;
+bif_return_type(is_function, [_,_], _) -> bool;
+bif_return_type(is_integer, [_], _) -> bool;
+bif_return_type(is_list, [_], _) -> bool;
+bif_return_type(is_map, [_], _) -> bool;
+bif_return_type(is_number, [_], _) -> bool;
+bif_return_type(is_pid, [_], _) -> bool;
+bif_return_type(is_port, [_], _) -> bool;
+bif_return_type(is_reference, [_], _) -> bool;
+bif_return_type(is_tuple, [_], _) -> bool;
%% Misc.
-bif_type(node, [], _) -> {atom,[]};
-bif_type(node, [_], _) -> {atom,[]};
-bif_type(hd, [_], _) -> term;
-bif_type(tl, [_], _) -> term;
-bif_type(get, [_], _) -> term;
-bif_type(Bif, _, _) when is_atom(Bif) -> term.
+bif_return_type(tuple_size, [_], _) -> {integer,[]};
+bif_return_type(map_size, [_], _) -> {integer,[]};
+bif_return_type(node, [], _) -> {atom,[]};
+bif_return_type(node, [_], _) -> {atom,[]};
+bif_return_type(hd, [_], _) -> term;
+bif_return_type(tl, [_], _) -> term;
+bif_return_type(get, [_], _) -> term;
+bif_return_type(Bif, _, _) when is_atom(Bif) -> term.
+
+%% Generic
+bif_arg_types(tuple_size, [_]) -> [{tuple,[0],#{}}];
+bif_arg_types(map_size, [_]) -> [map];
+bif_arg_types(is_map_key, [_,_]) -> [term, map];
+bif_arg_types(map_get, [_,_]) -> [term, map];
+bif_arg_types(length, [_]) -> [list];
+bif_arg_types(hd, [_]) -> [cons];
+bif_arg_types(tl, [_]) -> [cons];
+%% Boolean
+bif_arg_types('not', [_]) -> [bool];
+bif_arg_types('and', [_,_]) -> [bool, bool];
+bif_arg_types('or', [_,_]) -> [bool, bool];
+bif_arg_types('xor', [_,_]) -> [bool, bool];
+%% Binary
+bif_arg_types('binary_part', [_,_]) ->
+ PosLen = {tuple, 2, #{ {integer,1} => {integer,[]},
+ {integer,2} => {integer,[]} }},
+ [binary, PosLen];
+bif_arg_types('binary_part', [_,_,_]) ->
+ [binary, {integer,[]}, {integer,[]}];
+bif_arg_types('bit_size', [_]) -> [binary];
+bif_arg_types('byte_size', [_]) -> [binary];
+%% Numerical
+bif_arg_types('-', [_]) -> [number];
+bif_arg_types('-', [_,_]) -> [number,number];
+bif_arg_types('+', [_]) -> [number];
+bif_arg_types('+', [_,_]) -> [number,number];
+bif_arg_types('*', [_,_]) -> [number, number];
+bif_arg_types('/', [_,_]) -> [number, number];
+bif_arg_types(abs, [_]) -> [number];
+bif_arg_types(ceil, [_]) -> [number];
+bif_arg_types(float, [_]) -> [number];
+bif_arg_types(floor, [_]) -> [number];
+bif_arg_types(trunc, [_]) -> [number];
+bif_arg_types(round, [_]) -> [number];
+%% Integer-specific
+bif_arg_types('div', [_,_]) -> [{integer,[]}, {integer,[]}];
+bif_arg_types('rem', [_,_]) -> [{integer,[]}, {integer,[]}];
+bif_arg_types('band', [_,_]) -> [{integer,[]}, {integer,[]}];
+bif_arg_types('bor', [_,_]) -> [{integer,[]}, {integer,[]}];
+bif_arg_types('bxor', [_,_]) -> [{integer,[]}, {integer,[]}];
+bif_arg_types('bnot', [_]) -> [{integer,[]}];
+bif_arg_types('bsl', [_,_]) -> [{integer,[]}, {integer,[]}];
+bif_arg_types('bsr', [_,_]) -> [{integer,[]}, {integer,[]}];
+%% Unsafe type tests that may fail if an argument doesn't have the right type.
+bif_arg_types(is_function, [_,_]) -> [term, {integer,[]}];
+bif_arg_types(_, Args) -> [term || _Arg <- Args].
is_bif_safe('/=', 2) -> true;
is_bif_safe('<', 2) -> true;
@@ -1600,86 +2795,190 @@ is_bif_safe(self, 0) -> true;
is_bif_safe(node, 0) -> true;
is_bif_safe(_, _) -> false.
-arith_type([A,B], Vst) ->
- case {get_term_type(A, Vst),get_term_type(B, Vst)} of
+arith_return_type([A], Vst) ->
+ %% Unary '+' or '-'.
+ case get_term_type(A, Vst) of
+ {integer,_} -> {integer,[]};
+ {float,_} -> {float,[]};
+ _ -> number
+ end;
+arith_return_type([A,B], Vst) ->
+ TypeA = get_term_type(A, Vst),
+ TypeB = get_term_type(B, Vst),
+ case {TypeA, TypeB} of
+ {{integer,_},{integer,_}} -> {integer,[]};
{{float,_},_} -> {float,[]};
{_,{float,_}} -> {float,[]};
{_,_} -> number
end;
-arith_type(_, _) -> number.
+arith_return_type(_, _) -> number.
-return_type({extfunc,M,F,A}, Vst) -> return_type_1(M, F, A, Vst);
-return_type(_, _) -> term.
+%%%
+%%% Return/argument types of calls
+%%%
-return_type_1(erlang, setelement, 3, Vst) ->
- Tuple = {x,1},
+call_return_type({extfunc,M,F,A}, Vst) -> call_return_type_1(M, F, A, Vst);
+call_return_type(_, _) -> term.
+
+call_return_type_1(erlang, setelement, 3, Vst) ->
+ IndexType = get_term_type({x,0}, Vst),
TupleType =
- case get_term_type(Tuple, Vst) of
- {tuple,_}=TT ->
- TT;
- {literal,Lit} when is_tuple(Lit) ->
- {tuple,tuple_size(Lit)};
- _ ->
- {tuple,[0]}
- end,
- case get_term_type({x,0}, Vst) of
- {integer,[]} -> TupleType;
- {integer,I} -> upgrade_tuple_type({tuple,[I]}, TupleType);
- _ -> TupleType
+ case get_term_type({x,1}, Vst) of
+ {literal,Tuple}=Lit when is_tuple(Tuple) -> get_literal_type(Lit);
+ {tuple,_,_}=TT -> TT;
+ _ -> {tuple,[0],#{}}
+ end,
+ case IndexType of
+ {integer,I} when is_integer(I) ->
+ case meet({tuple,[I],#{}}, TupleType) of
+ {tuple, Sz, Es0} ->
+ ValueType = get_term_type({x,2}, Vst),
+ Es = set_element_type({integer,I}, ValueType, Es0),
+ {tuple, Sz, Es};
+ none ->
+ TupleType
+ end;
+ _ ->
+ %% The index could point anywhere, so we must discard all element
+ %% information.
+ setelement(3, TupleType, #{})
+ end;
+call_return_type_1(erlang, '++', 2, Vst) ->
+ case get_term_type({x,0}, Vst) =:= cons orelse
+ get_term_type({x,1}, Vst) =:= cons of
+ true -> cons;
+ false -> list
end;
-return_type_1(erlang, F, A, _) ->
- return_type_erl(F, A);
-return_type_1(math, F, A, _) ->
- return_type_math(F, A);
-return_type_1(M, F, A, _) when is_atom(M), is_atom(F), is_integer(A), A >= 0 ->
+call_return_type_1(erlang, '--', 2, _Vst) ->
+ list;
+call_return_type_1(erlang, F, A, _) ->
+ erlang_mod_return_type(F, A);
+call_return_type_1(lists, F, A, Vst) ->
+ lists_mod_return_type(F, A, Vst);
+call_return_type_1(math, F, A, _) ->
+ math_mod_return_type(F, A);
+call_return_type_1(M, F, A, _) when is_atom(M), is_atom(F), is_integer(A), A >= 0 ->
term.
-return_type_erl(exit, 1) -> exception;
-return_type_erl(throw, 1) -> exception;
-return_type_erl(error, 1) -> exception;
-return_type_erl(error, 2) -> exception;
-return_type_erl(F, A) when is_atom(F), is_integer(A), A >= 0 -> term.
-
-return_type_math(cos, 1) -> {float,[]};
-return_type_math(cosh, 1) -> {float,[]};
-return_type_math(sin, 1) -> {float,[]};
-return_type_math(sinh, 1) -> {float,[]};
-return_type_math(tan, 1) -> {float,[]};
-return_type_math(tanh, 1) -> {float,[]};
-return_type_math(acos, 1) -> {float,[]};
-return_type_math(acosh, 1) -> {float,[]};
-return_type_math(asin, 1) -> {float,[]};
-return_type_math(asinh, 1) -> {float,[]};
-return_type_math(atan, 1) -> {float,[]};
-return_type_math(atanh, 1) -> {float,[]};
-return_type_math(erf, 1) -> {float,[]};
-return_type_math(erfc, 1) -> {float,[]};
-return_type_math(exp, 1) -> {float,[]};
-return_type_math(log, 1) -> {float,[]};
-return_type_math(log2, 1) -> {float,[]};
-return_type_math(log10, 1) -> {float,[]};
-return_type_math(sqrt, 1) -> {float,[]};
-return_type_math(atan2, 2) -> {float,[]};
-return_type_math(pow, 2) -> {float,[]};
-return_type_math(ceil, 1) -> {float,[]};
-return_type_math(floor, 1) -> {float,[]};
-return_type_math(fmod, 2) -> {float,[]};
-return_type_math(pi, 0) -> {float,[]};
-return_type_math(F, A) when is_atom(F), is_integer(A), A >= 0 -> term.
-
-check_limit({x,X}) when is_integer(X), X < 1023 ->
- %% Note: x(1023) is reserved for use by the BEAM loader.
- ok;
-check_limit({y,Y}) when is_integer(Y), Y < 1024 ->
- ok;
-check_limit({fr,Fr}) when is_integer(Fr), Fr < 1024 ->
- ok;
-check_limit(_) ->
- error(limit).
+erlang_mod_return_type(exit, 1) -> exception;
+erlang_mod_return_type(throw, 1) -> exception;
+erlang_mod_return_type(error, 1) -> exception;
+erlang_mod_return_type(error, 2) -> exception;
+erlang_mod_return_type(F, A) when is_atom(F), is_integer(A), A >= 0 -> term.
+
+math_mod_return_type(cos, 1) -> {float,[]};
+math_mod_return_type(cosh, 1) -> {float,[]};
+math_mod_return_type(sin, 1) -> {float,[]};
+math_mod_return_type(sinh, 1) -> {float,[]};
+math_mod_return_type(tan, 1) -> {float,[]};
+math_mod_return_type(tanh, 1) -> {float,[]};
+math_mod_return_type(acos, 1) -> {float,[]};
+math_mod_return_type(acosh, 1) -> {float,[]};
+math_mod_return_type(asin, 1) -> {float,[]};
+math_mod_return_type(asinh, 1) -> {float,[]};
+math_mod_return_type(atan, 1) -> {float,[]};
+math_mod_return_type(atanh, 1) -> {float,[]};
+math_mod_return_type(erf, 1) -> {float,[]};
+math_mod_return_type(erfc, 1) -> {float,[]};
+math_mod_return_type(exp, 1) -> {float,[]};
+math_mod_return_type(log, 1) -> {float,[]};
+math_mod_return_type(log2, 1) -> {float,[]};
+math_mod_return_type(log10, 1) -> {float,[]};
+math_mod_return_type(sqrt, 1) -> {float,[]};
+math_mod_return_type(atan2, 2) -> {float,[]};
+math_mod_return_type(pow, 2) -> {float,[]};
+math_mod_return_type(ceil, 1) -> {float,[]};
+math_mod_return_type(floor, 1) -> {float,[]};
+math_mod_return_type(fmod, 2) -> {float,[]};
+math_mod_return_type(pi, 0) -> {float,[]};
+math_mod_return_type(F, A) when is_atom(F), is_integer(A), A >= 0 -> term.
+
+lists_mod_return_type(all, 2, _Vst) ->
+ bool;
+lists_mod_return_type(any, 2, _Vst) ->
+ bool;
+lists_mod_return_type(keymember, 3, _Vst) ->
+ bool;
+lists_mod_return_type(member, 2, _Vst) ->
+ bool;
+lists_mod_return_type(prefix, 2, _Vst) ->
+ bool;
+lists_mod_return_type(suffix, 2, _Vst) ->
+ bool;
+lists_mod_return_type(dropwhile, 2, _Vst) ->
+ list;
+lists_mod_return_type(duplicate, 2, _Vst) ->
+ list;
+lists_mod_return_type(filter, 2, _Vst) ->
+ list;
+lists_mod_return_type(flatten, 1, _Vst) ->
+ list;
+lists_mod_return_type(map, 2, Vst) ->
+ same_length_type({x,1}, Vst);
+lists_mod_return_type(MF, 3, Vst) when MF =:= mapfoldl; MF =:= mapfoldr ->
+ ListType = same_length_type({x,2}, Vst),
+ {tuple,2,#{ {integer,1} => ListType} };
+lists_mod_return_type(partition, 2, _Vst) ->
+ two_tuple(list, list);
+lists_mod_return_type(reverse, 1, Vst) ->
+ same_length_type({x,0}, Vst);
+lists_mod_return_type(seq, 2, _Vst) ->
+ list;
+lists_mod_return_type(sort, 1, Vst) ->
+ same_length_type({x,0}, Vst);
+lists_mod_return_type(sort, 2, Vst) ->
+ same_length_type({x,1}, Vst);
+lists_mod_return_type(splitwith, 2, _Vst) ->
+ two_tuple(list, list);
+lists_mod_return_type(takewhile, 2, _Vst) ->
+ list;
+lists_mod_return_type(unzip, 1, Vst) ->
+ ListType = same_length_type({x,0}, Vst),
+ two_tuple(ListType, ListType);
+lists_mod_return_type(usort, 1, Vst) ->
+ same_length_type({x,0}, Vst);
+lists_mod_return_type(zip, 2, _Vst) ->
+ list;
+lists_mod_return_type(zipwith, 3, _Vst) ->
+ list;
+lists_mod_return_type(_, _, _) ->
+ term.
+
+two_tuple(Type1, Type2) ->
+ {tuple,2,#{ {integer,1} => Type1,
+ {integer,2} => Type2 }}.
+
+same_length_type(Reg, Vst) ->
+ case get_term_type(Reg, Vst) of
+ {literal,[_|_]} -> cons;
+ cons -> cons;
+ nil -> nil;
+ _ -> list
+ end.
+
+check_limit({x,X}=Src) when is_integer(X) ->
+ if
+ %% Note: x(1023) is reserved for use by the BEAM loader.
+ 0 =< X, X < 1023 -> ok;
+ 1023 =< X -> error(limit);
+ X < 0 -> error({bad_register, Src})
+ end;
+check_limit({y,Y}=Src) when is_integer(Y) ->
+ if
+ 0 =< Y, Y < 1024 -> ok;
+ 1024 =< Y -> error(limit);
+ Y < 0 -> error({bad_register, Src})
+ end;
+check_limit({fr,Fr}=Src) when is_integer(Fr) ->
+ if
+ 0 =< Fr, Fr < 1023 -> ok;
+ 1023 =< Fr -> error(limit);
+ Fr < 0 -> error({bad_register, Src})
+ end.
min(A, B) when is_integer(A), is_integer(B), A < B -> A;
min(A, B) when is_integer(A), is_integer(B) -> B.
-gb_trees_from_list(L) -> gb_trees:from_orddict(lists:sort(L)).
+gb_trees_from_list(L) -> gb_trees:from_orddict(sort(L)).
error(Error) -> throw(Error).
diff --git a/lib/compiler/src/beam_z.erl b/lib/compiler/src/beam_z.erl
index 787e33c142..415b579240 100644
--- a/lib/compiler/src/beam_z.erl
+++ b/lib/compiler/src/beam_z.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,22 +24,23 @@
-export([module/2]).
--import(lists, [dropwhile/2]).
+-import(lists, [dropwhile/2,map/2]).
-spec module(beam_utils:module_code(), [compile:option()]) ->
{'ok',beam_asm:module_code()}.
-module({Mod,Exp,Attr,Fs0,Lc}, _Opt) ->
- Fs = [function(F) || F <- Fs0],
+module({Mod,Exp,Attr,Fs0,Lc}, Opts) ->
+ NoGetHdTl = proplists:get_bool(no_get_hd_tl, Opts),
+ Fs = [function(F, NoGetHdTl) || F <- Fs0],
{ok,{Mod,Exp,Attr,Fs,Lc}}.
-function({function,Name,Arity,CLabel,Is0}) ->
+function({function,Name,Arity,CLabel,Is0}, NoGetHdTl) ->
try
- Is = undo_renames(Is0),
+ Is1 = undo_renames(Is0),
+ Is = maybe_eliminate_get_hd_tl(Is1, NoGetHdTl),
{function,Name,Arity,CLabel,Is}
catch
- Class:Error ->
- Stack = erlang:get_stacktrace(),
+ Class:Error:Stack ->
io:fwrite("Function: ~w/~w\n", [Name,Arity]),
erlang:raise(Class, Error, Stack)
end.
@@ -66,6 +67,35 @@ undo_renames([{bif,raise,_,_,_}=I|Is0]) ->
(_) -> true
end, Is0),
[I|undo_renames(Is)];
+undo_renames([{get_hd,Src,Dst1},{get_tl,Src,Dst2}|Is]) ->
+ [{get_list,Src,Dst1,Dst2}|undo_renames(Is)];
+undo_renames([{get_tl,Src,Dst2},{get_hd,Src,Dst1}|Is]) ->
+ [{get_list,Src,Dst1,Dst2}|undo_renames(Is)];
+undo_renames([{bs_put,_,{bs_put_binary,1,_},
+ [{atom,all},{literal,<<>>}]}|Is]) ->
+ undo_renames(Is);
+undo_renames([{bs_put,Fail,{bs_put_binary,1,_Flags},
+ [{atom,all},{literal,BinString}]}|Is0]) ->
+ Bits = bit_size(BinString),
+ Bytes = Bits div 8,
+ case Bits rem 8 of
+ 0 ->
+ I = {bs_put_string,byte_size(BinString),
+ {string,BinString}},
+ [undo_rename(I)|undo_renames(Is0)];
+ Rem ->
+ <<Binary:Bytes/bytes,Int:Rem>> = BinString,
+ PutInt = {bs_put_integer,Fail,{integer,Rem},1,
+ {field_flags,[unsigned,big]},{integer,Int}},
+ Is = [PutInt|undo_renames(Is0)],
+ case Binary of
+ <<>> ->
+ Is;
+ _ ->
+ [{bs_put_string,byte_size(Binary),
+ {string,Binary}}|Is]
+ end
+ end;
undo_renames([I|Is]) ->
[undo_rename(I)|undo_renames(Is)];
undo_renames([]) -> [].
@@ -74,8 +104,6 @@ undo_rename({bs_put,F,{I,U,Fl},[Sz,Src]}) ->
{I,F,Sz,U,Fl,Src};
undo_rename({bs_put,F,{I,Fl},[Src]}) ->
{I,F,Fl,Src};
-undo_rename({bs_put,{f,0},{bs_put_string,_,_}=I,[]}) ->
- I;
undo_rename({bif,bs_add=I,F,[Src1,Src2,{integer,U}],Dst}) ->
{I,F,[Src1,Src2,U],Dst};
undo_rename({bif,bs_utf8_size=I,F,[Src],Dst}) ->
@@ -96,7 +124,7 @@ undo_rename({test,bs_match_string=Op,F,[Ctx,Bin0]}) ->
0 -> Bin0;
Rem -> <<Bin0/bitstring,0:(8-Rem)>>
end,
- {test,Op,F,[Ctx,Bits,{string,binary_to_list(Bin)}]};
+ {test,Op,F,[Ctx,Bits,{string,Bin}]};
undo_rename({put_map,Fail,assoc,S,D,R,L}) ->
{put_map_assoc,Fail,S,D,R,L};
undo_rename({put_map,Fail,exact,S,D,R,L}) ->
@@ -105,6 +133,22 @@ undo_rename({test,has_map_fields,Fail,[Src|List]}) ->
{test,has_map_fields,Fail,Src,{list,List}};
undo_rename({get_map_elements,Fail,Src,{list,List}}) ->
{get_map_elements,Fail,Src,{list,List}};
+undo_rename({test,is_eq_exact,Fail,[Src,nil]}) ->
+ {test,is_nil,Fail,[Src]};
undo_rename({select,I,Reg,Fail,List}) ->
{I,Reg,Fail,{list,List}};
undo_rename(I) -> I.
+
+%%%
+%%% Eliminate get_hd/get_tl instructions if requested by
+%%% the no_get_hd_tl option.
+%%%
+
+maybe_eliminate_get_hd_tl(Is, true) ->
+ map(fun({get_hd,Cons,Hd}) ->
+ {get_list,Cons,Hd,{x,1022}};
+ ({get_tl,Cons,Tl}) ->
+ {get_list,Cons,{x,1022},Tl};
+ (I) -> I
+ end, Is);
+maybe_eliminate_get_hd_tl(Is, false) -> Is.
diff --git a/lib/compiler/src/cerl.erl b/lib/compiler/src/cerl.erl
index 6b936a7687..62cd5b5120 100644
--- a/lib/compiler/src/cerl.erl
+++ b/lib/compiler/src/cerl.erl
@@ -433,6 +433,8 @@ is_literal_term(T) when is_tuple(T) ->
is_literal_term(B) when is_bitstring(B) -> true;
is_literal_term(M) when is_map(M) ->
is_literal_term_list(maps:to_list(M));
+is_literal_term(F) when is_function(F) ->
+ erlang:fun_info(F, type) =:= {type,external};
is_literal_term(_) ->
false.
@@ -2155,12 +2157,16 @@ values_arity(Node) ->
%% @spec c_binary(Segments::[cerl()]) -> cerl()
%%
-%% @doc Creates an abstract binary-template. A binary object is a
-%% sequence of 8-bit bytes. It is specified by zero or more bit-string
-%% template <em>segments</em> of arbitrary lengths (in number of bits),
-%% such that the sum of the lengths is evenly divisible by 8. If
-%% <code>Segments</code> is <code>[S1, ..., Sn]</code>, the result
-%% represents "<code>#{<em>S1</em>, ..., <em>Sn</em>}#</code>". All the
+
+%% @doc Creates an abstract binary-template. A binary object is in
+%% this context a sequence of an arbitrary number of bits. (The number
+%% of bits used to be evenly divisible by 8, but after the
+%% introduction of bit strings in the Erlang language, the choice was
+%% made to use the binary template for all bit strings.) It is
+%% specified by zero or more bit-string template <em>segments</em> of
+%% arbitrary lengths (in number of bits). If <code>Segments</code> is
+%% <code>[S1, ..., Sn]</code>, the result represents
+%% "<code>#{<em>S1</em>, ..., <em>Sn</em>}#</code>". All the
%% <code>Si</code> must have type <code>bitstr</code>.
%%
%% @see ann_c_binary/2
diff --git a/lib/compiler/src/cerl_clauses.erl b/lib/compiler/src/cerl_clauses.erl
index 7d6518c3c6..3fd7ddd181 100644
--- a/lib/compiler/src/cerl_clauses.erl
+++ b/lib/compiler/src/cerl_clauses.erl
@@ -14,8 +14,8 @@
%% @author Richard Carlsson <[email protected]>
%% @doc Utility functions for Core Erlang case/receive clauses.
%%
-%% <p>Syntax trees are defined in the module <a
-%% href=""><code>cerl</code></a>.</p>
+%% <p>Syntax trees are defined in the module
+%% <a href="cerl"><code>cerl</code></a>.</p>
%%
%% @type cerl() = cerl:cerl()
@@ -353,6 +353,8 @@ match(P, E, Bs) ->
map ->
%% The most we can do is to say "definitely no match" if a
%% map pattern is matched against non-map data.
+ %% (Note: See the document internal_doc/cerl-notes.md for
+ %% information why we don't try to do more here.)
case E of
any ->
{false, Bs};
diff --git a/lib/compiler/src/cerl_inline.erl b/lib/compiler/src/cerl_inline.erl
index f5afa75b16..caff47dbcb 100644
--- a/lib/compiler/src/cerl_inline.erl
+++ b/lib/compiler/src/cerl_inline.erl
@@ -1822,6 +1822,14 @@ new_var(Env) ->
Name = env__new_vname(Env),
c_var(Name).
+%% The way a template variable is used makes it necessary
+%% to make sure that it is unique in the entire function.
+%% Therefore, template variables are atoms with the prefix "@i".
+
+new_template_var(Env) ->
+ Name = env__new_tname(Env),
+ c_var(Name).
+
residualize_var(R, S) ->
S1 = count_size(weight(var), S),
{ref_to_var(R), st__set_var_referenced(R#ref.loc, S1)}.
@@ -2183,7 +2191,7 @@ make_template(E, Vs0, Env0) ->
T = make_data_skel(data_type(E), Ts),
E1 = update_data(E, data_type(E),
[hd(get_ann(T)) || T <- Ts]),
- V = new_var(Env1),
+ V = new_template_var(Env1),
Env2 = env__bind(var_name(V), E1, Env1),
{set_ann(T, [V]), [V | Vs1], Env2};
false ->
@@ -2198,7 +2206,7 @@ make_template(E, Vs0, Env0) ->
Env2 = env__bind(V, E1, Env1),
{T, Vs1, Env2};
_ ->
- V = new_var(Env0),
+ V = new_template_var(Env0),
Env1 = env__bind(var_name(V), E, Env0),
{set_ann(V, [V]), [V | Vs0], Env1}
end
@@ -2564,6 +2572,11 @@ env__is_defined(Key, Env) ->
env__new_vname(Env) ->
rec_env:new_key(Env).
+env__new_tname(Env) ->
+ rec_env:new_key(fun(I) ->
+ list_to_atom("@i"++integer_to_list(I))
+ end, Env).
+
env__new_fname(A, N, Env) ->
rec_env:new_key(fun (X) ->
S = integer_to_list(X),
diff --git a/lib/compiler/src/cerl_sets.erl b/lib/compiler/src/cerl_sets.erl
index 0361186713..f489baf238 100644
--- a/lib/compiler/src/cerl_sets.erl
+++ b/lib/compiler/src/cerl_sets.erl
@@ -204,4 +204,4 @@ fold(F, Init, D) ->
Set2 :: set(Element).
filter(F, D) ->
- maps:from_list(lists:filter(fun({K,_}) -> F(K) end, maps:to_list(D))).
+ maps:filter(fun(K,_) -> F(K) end, D).
diff --git a/lib/compiler/src/cerl_trees.erl b/lib/compiler/src/cerl_trees.erl
index f30a0b33ac..533c984221 100644
--- a/lib/compiler/src/cerl_trees.erl
+++ b/lib/compiler/src/cerl_trees.erl
@@ -22,7 +22,8 @@
-module(cerl_trees).
-export([depth/1, fold/3, free_variables/1, get_label/1, label/1, label/2,
- map/2, mapfold/3, mapfold/4, size/1, variables/1]).
+ map/2, mapfold/3, mapfold/4, next_free_variable_name/1,
+ size/1, variables/1]).
-import(cerl, [alias_pat/1, alias_var/1, ann_c_alias/3, ann_c_apply/3,
ann_c_binary/2, ann_c_bitstr/6, ann_c_call/4,
@@ -350,10 +351,9 @@ mapfold(F, S0, T) ->
mapfold(fun(T0, A) -> {T0, A} end, F, S0, T).
-%% @spec mapfold(Pre, Post, Initial::term(), Tree::cerl()) ->
-%% {cerl(), term()}
-%%
-%% Pre = Post = (cerl(), term()) -> {cerl(), term()}
+%% @spec mapfold(Pre, Post, Initial::term(), Tree::cerl()) -> {cerl(), term()}
+%% Pre = (cerl(), term()) -> {cerl(), term()}
+%% Post = (cerl(), term()) -> {cerl(), term()}
%%
%% @doc Does a combined map/fold operation on the nodes of the
%% tree. It begins by calling <code>Pre</code> on the tree, using the
@@ -507,6 +507,7 @@ mapfold_pairs(_, _, S, []) ->
%% well-formed Core Erlang syntax tree.
%%
%% @see free_variables/1
+%% @see next_free_variable_name/1
-spec variables(cerl:cerl()) -> [cerl:var_name()].
@@ -519,6 +520,7 @@ variables(T) ->
%% @doc Like <code>variables/1</code>, but only includes variables
%% that are free in the tree.
%%
+%% @see next_free_variable_name/1
%% @see variables/1
-spec free_variables(cerl:cerl()) -> [cerl:var_name()].
@@ -678,6 +680,110 @@ var_list_names([V | Vs], A) ->
var_list_names([], A) ->
A.
+%% ---------------------------------------------------------------------
+
+%% @spec next_free_variable_name(Tree::cerl()) -> var_name()
+%%
+%% var_name() = integer()
+%%
+%% @doc Returns a integer variable name higher than any other integer
+%% variable name in the syntax tree. An exception is thrown if
+%% <code>Tree</code> does not represent a well-formed Core Erlang
+%% syntax tree.
+%%
+%% @see variables/1
+%% @see free_variables/1
+
+-spec next_free_variable_name(cerl:cerl()) -> integer().
+
+next_free_variable_name(T) ->
+ 1 + next_free(T, -1).
+
+next_free(T, Max) ->
+ case type(T) of
+ literal ->
+ Max;
+ var ->
+ case var_name(T) of
+ Int when is_integer(Int) ->
+ max(Int, Max);
+ _ ->
+ Max
+ end;
+ values ->
+ next_free_in_list(values_es(T), Max);
+ cons ->
+ next_free(cons_hd(T), next_free(cons_tl(T), Max));
+ tuple ->
+ next_free_in_list(tuple_es(T), Max);
+ map ->
+ next_free_in_list([map_arg(T)|map_es(T)], Max);
+ map_pair ->
+ next_free_in_list([map_pair_op(T),map_pair_key(T),
+ map_pair_val(T)], Max);
+ 'let' ->
+ Max1 = next_free(let_body(T), Max),
+ Max2 = next_free_in_list(let_vars(T), Max1),
+ next_free(let_arg(T), Max2);
+ seq ->
+ next_free(seq_arg(T),
+ next_free(seq_body(T), Max));
+ apply ->
+ next_free(apply_op(T),
+ next_free_in_list(apply_args(T), Max));
+ call ->
+ next_free(call_module(T),
+ next_free(call_name(T),
+ next_free_in_list(
+ call_args(T), Max)));
+ primop ->
+ next_free_in_list(primop_args(T), Max);
+ 'case' ->
+ next_free(case_arg(T),
+ next_free_in_list(case_clauses(T), Max));
+ clause ->
+ Max1 = next_free(clause_guard(T),
+ next_free(clause_body(T), Max)),
+ next_free_in_list(clause_pats(T), Max1);
+ alias ->
+ next_free(alias_var(T),
+ next_free(alias_pat(T), Max));
+ 'fun' ->
+ next_free(fun_body(T),
+ next_free_in_list(fun_vars(T), Max));
+ 'receive' ->
+ Max1 = next_free_in_list(receive_clauses(T),
+ next_free(receive_timeout(T), Max)),
+ next_free(receive_action(T), Max1);
+ 'try' ->
+ Max1 = next_free(try_body(T), Max),
+ Max2 = next_free_in_list(try_vars(T), Max1),
+ Max3 = next_free(try_handler(T), Max2),
+ Max4 = next_free_in_list(try_evars(T), Max3),
+ next_free(try_arg(T), Max4);
+ 'catch' ->
+ next_free(catch_body(T), Max);
+ binary ->
+ next_free_in_list(binary_segments(T), Max);
+ bitstr ->
+ next_free(bitstr_val(T), next_free(bitstr_size(T), Max));
+ letrec ->
+ Max1 = next_free_in_defs(letrec_defs(T), Max),
+ Max2 = next_free(letrec_body(T), Max1),
+ next_free_in_list(letrec_vars(T), Max2);
+ module ->
+ next_free_in_defs(module_defs(T), Max)
+ end.
+
+next_free_in_list([H | T], Max) ->
+ next_free_in_list(T, next_free(H, Max));
+next_free_in_list([], Max) ->
+ Max.
+
+next_free_in_defs([{_, Post} | Ds], Max) ->
+ next_free_in_defs(Ds, next_free(Post, Max));
+next_free_in_defs([], Max) ->
+ Max.
%% ---------------------------------------------------------------------
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index 50b0ba76f8..28db8986ff 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -31,6 +31,9 @@
%% Erlc interface.
-export([compile/3,compile_beam/3,compile_asm/3,compile_core/3]).
+%% Utility functions for compiler passes.
+-export([run_sub_passes/2]).
+
-export_type([option/0]).
-include("erl_compile.hrl").
@@ -39,6 +42,8 @@
-import(lists, [member/2,reverse/1,reverse/2,keyfind/3,last/1,
map/2,flatmap/2,foreach/2,foldr/3,any/2]).
+-define(SUB_PASS_TIMES, compile__sub_pass_times).
+
%%----------------------------------------------------------------------
-type abstract_code() :: [erl_parse:abstract_form()].
@@ -64,6 +69,7 @@
-type err_ret() :: 'error' | {'error', errors(), warnings()}.
-type comp_ret() :: mod_ret() | bin_ret() | err_ret().
+
%%----------------------------------------------------------------------
%%
@@ -143,6 +149,30 @@ noenv_output_generated(Opts) ->
env_compiler_options() -> env_default_opts().
+
+%%%
+%%% Run sub passes from a compiler pass.
+%%%
+
+-spec run_sub_passes([term()], term()) -> term().
+
+run_sub_passes(Ps, St) ->
+ case get(?SUB_PASS_TIMES) of
+ undefined ->
+ Runner = fun(_Name, Run, S) -> Run(S) end,
+ run_sub_passes_1(Ps, Runner, St);
+ Times when is_list(Times) ->
+ Runner = fun(Name, Run, S0) ->
+ T1 = erlang:monotonic_time(),
+ S = Run(S0),
+ T2 = erlang:monotonic_time(),
+ put(?SUB_PASS_TIMES,
+ [{Name,T2-T1}|get(?SUB_PASS_TIMES)]),
+ S
+ end,
+ run_sub_passes_1(Ps, Runner, St)
+ end.
+
%%
%% Local functions
%%
@@ -180,8 +210,11 @@ do_compile(Input, Opts0) ->
{error,Reason}
end
end,
- %% Dialyzer has already spawned workers.
- case lists:member(dialyzer, Opts) of
+ %% Some tools, like Dialyzer, has already spawned workers
+ %% and spawning extra workers actually slow the compilation
+ %% down instead of speeding it up, so we provide a mechanism
+ %% to bypass the compiler process.
+ case lists:member(no_spawn_compiler_process, Opts) of
true ->
IntFun();
false ->
@@ -203,7 +236,12 @@ expand_opts(Opts0) ->
{_,_,undefined} -> [debug_info|Opts0];
{_,_,_} -> Opts0
end,
- foldr(fun expand_opt/2, [], Opts).
+ %% iff,unless processing is to complex...
+ Opts1 = case proplists:is_defined(makedep_side_effect,Opts) of
+ true -> proplists:delete(makedep,Opts);
+ false -> Opts
+ end,
+ foldr(fun expand_opt/2, [], Opts1).
expand_opt(basic_validation, Os) ->
[no_code_generation,to_pp,binary|Os];
@@ -213,21 +251,33 @@ expand_opt(report, Os) ->
[report_errors,report_warnings|Os];
expand_opt(return, Os) ->
[return_errors,return_warnings|Os];
+expand_opt(no_bsm3, Os) ->
+ %% The new bsm pass requires bsm3 instructions.
+ [no_bsm3,no_bsm_opt|Os];
expand_opt(r16, Os) ->
- [no_record_opt,no_utf8_atoms|Os];
+ expand_opt_before_21(Os);
expand_opt(r17, Os) ->
- [no_record_opt,no_utf8_atoms|Os];
+ expand_opt_before_21(Os);
expand_opt(r18, Os) ->
- [no_record_opt,no_utf8_atoms|Os];
+ expand_opt_before_21(Os);
expand_opt(r19, Os) ->
- [no_record_opt,no_utf8_atoms|Os];
+ expand_opt_before_21(Os);
+expand_opt(r20, Os) ->
+ expand_opt_before_21(Os);
+expand_opt(r21, Os) ->
+ [no_put_tuple2 | expand_opt(no_bsm3, Os)];
expand_opt({debug_info_key,_}=O, Os) ->
[encrypt_debug_info,O|Os];
-expand_opt(no_float_opt, Os) ->
- %%Turn off the entire type optimization pass.
- [no_topt|Os];
+expand_opt(no_type_opt, Os) ->
+ [no_ssa_opt_type_start,
+ no_ssa_opt_type_continue,
+ no_ssa_opt_type_finish | Os];
expand_opt(O, Os) -> [O|Os].
+expand_opt_before_21(Os) ->
+ [no_put_tuple2, no_get_hd_tl, no_ssa_opt_record,
+ no_utf8_atoms | expand_opt(no_bsm3, Os)].
+
%% format_error(ErrorDescriptor) -> string()
-spec format_error(term()) -> iolist().
@@ -240,6 +290,10 @@ format_error(bad_crypto_key) ->
"invalid crypto key.";
format_error(no_crypto_key) ->
"no crypto key supplied.";
+format_error({unimplemented_instruction,Instruction}) ->
+ io_lib:fwrite("native-code compilation failed because of an "
+ "unimplemented instruction (~s).",
+ [Instruction]);
format_error({native, E}) ->
io_lib:fwrite("native-code compilation failed with reason: ~tP.",
[E, 25]);
@@ -288,7 +342,7 @@ format_error_reason({Reason, Stack}) when is_list(Stack) ->
end,
FormatFun = fun (Term, _) -> io_lib:format("~tp", [Term]) end,
[io_lib:format("~tp", [Reason]),"\n\n",
- lib:format_stacktrace(1, Stack, StackFun, FormatFun)];
+ erl_error:format_stacktrace(1, Stack, StackFun, FormatFun)];
format_error_reason(Reason) ->
io_lib:format("~tp", [Reason]).
@@ -380,17 +434,57 @@ fold_comp([{Name,Pass}|Ps], Run, Code0, St0) ->
end;
fold_comp([], _Run, Code, St) -> {ok,Code,St}.
+run_sub_passes_1([{Name,Run}|Ps], Runner, St0)
+ when is_atom(Name), is_function(Run, 1) ->
+ try Runner(Name, Run, St0) of
+ St ->
+ run_sub_passes_1(Ps, Runner, St)
+ catch
+ C:E:Stk ->
+ io:format("Sub pass ~s\n", [Name]),
+ erlang:raise(C, E, Stk)
+ end;
+run_sub_passes_1([], _, St) -> St.
+
run_tc({Name,Fun}, Code, St) ->
+ put(?SUB_PASS_TIMES, []),
T1 = erlang:monotonic_time(),
Val = (catch Fun(Code, St)),
T2 = erlang:monotonic_time(),
- Elapsed = erlang:convert_time_unit(T2 - T1, native, millisecond),
+ Times = erase(?SUB_PASS_TIMES),
+ Elapsed = erlang:convert_time_unit(T2 - T1, native, microsecond),
Mem0 = erts_debug:flat_size(Val)*erlang:system_info(wordsize),
Mem = lists:flatten(io_lib:format("~.1f kB", [Mem0/1024])),
io:format(" ~-30s: ~10.3f s ~12s\n",
- [Name,Elapsed/1000,Mem]),
+ [Name,Elapsed/1000000,Mem]),
+ print_times(Times, Name),
Val.
+print_times(Times0, Name) ->
+ Fam0 = sofs:relation(Times0),
+ Fam1 = sofs:rel2fam(Fam0),
+ Fam2 = sofs:to_external(Fam1),
+ Fam3 = [{W,lists:sum(Times)} || {W,Times} <- Fam2],
+ Fam = reverse(lists:keysort(2, Fam3)),
+ Total = case lists:sum([T || {_,T} <- Fam]) of
+ 0 -> 1;
+ Total0 -> Total0
+ end,
+ case Fam of
+ [] ->
+ ok;
+ [_|_] ->
+ io:format(" %% Sub passes of ~s from slowest to fastest:\n", [Name]),
+ print_times_1(Fam, Total)
+ end.
+
+print_times_1([{Name,T}|Ts], Total) ->
+ Elapsed = erlang:convert_time_unit(T, native, microsecond),
+ io:format(" ~-27s: ~10.3f s ~3w %\n",
+ [Name,Elapsed/1000000,round(100*T/Total)]),
+ print_times_1(Ts, Total);
+print_times_1([], _Total) -> ok.
+
run_eprof({Name,Fun}, Code, Name, St) ->
io:format("~p: Running eprof\n", [Name]),
c:appcall(tools, eprof, start_profiling, [[self()]]),
@@ -674,6 +768,7 @@ select_list_passes_1([], _, Acc) ->
standard_passes() ->
[?pass(transform_module),
+ {iff,makedep_side_effect,?pass(makedep_and_output)},
{iff,makedep,[
?pass(makedep),
{unless,binary,?pass(makedep_output)}
@@ -706,14 +801,16 @@ core_passes() ->
[{unless,no_copt,
[{core_old_inliner,fun test_old_inliner/1,fun core_old_inliner/2},
{iff,doldinline,{listing,"oldinline"}},
- {pass,sys_core_fold},
+ {unless,no_fold,{pass,sys_core_fold}},
{iff,dcorefold,{listing,"corefold"}},
{core_inline_module,fun test_core_inliner/1,fun core_inline_module/2},
{iff,dinline,{listing,"inline"}},
{core_fold_after_inlining,fun test_any_inliner/1,
fun core_fold_module_after_inlining/2},
+ {iff,dcopt,{listing,"copt"}},
+ {unless,no_alias,{pass,sys_core_alias}},
+ {iff,dalias,{listing,"core_alias"}},
?pass(core_transforms)]},
- {iff,dcopt,{listing,"copt"}},
{iff,'to_core',{done,"core"}}]}
| kernel_passes()].
@@ -721,8 +818,6 @@ kernel_passes() ->
%% Optimizations that must be done after all other optimizations.
[{pass,sys_core_bsm},
{iff,dcbsm,{listing,"core_bsm"}},
- {pass,sys_core_dsetel},
- {iff,dsetel,{listing,"dsetel"}},
{iff,clint,?pass(core_lint_module)},
{iff,core,?pass(save_core_code)},
@@ -731,10 +826,30 @@ kernel_passes() ->
?pass(v3_kernel),
{iff,dkern,{listing,"kernel"}},
{iff,'to_kernel',{done,"kernel"}},
- {pass,v3_life},
- {iff,dlife,{listing,"life"}},
- {pass,v3_codegen},
- {iff,dcg,{listing,"codegen"}}
+ {pass,beam_kernel_to_ssa},
+ {iff,dssa,{listing,"ssa"}},
+ {iff,ssalint,{pass,beam_ssa_lint}},
+ {delay,
+ [{unless,no_share_opt,{pass,beam_ssa_share}},
+ {iff,dssashare,{listing,"ssashare"}},
+ {iff,ssalint,{pass,beam_ssa_lint}},
+ {unless,no_bsm_opt,{pass,beam_ssa_bsm}},
+ {iff,dssabsm,{listing,"ssabsm"}},
+ {iff,ssalint,{pass,beam_ssa_lint}},
+ {unless,no_fun_opt,{pass,beam_ssa_funs}},
+ {iff,dssafuns,{listing,"ssafuns"}},
+ {iff,ssalint,{pass,beam_ssa_lint}},
+ {unless,no_ssa_opt,{pass,beam_ssa_opt}},
+ {iff,dssaopt,{listing,"ssaopt"}},
+ {iff,ssalint,{pass,beam_ssa_lint}},
+ {unless,no_recv_opt,{pass,beam_ssa_recv}},
+ {iff,drecv,{listing,"recv"}}]},
+ {pass,beam_ssa_pre_codegen},
+ {iff,dprecg,{listing,"precodegen"}},
+ {iff,ssalint,{pass,beam_ssa_lint}},
+ {pass,beam_ssa_codegen},
+ {iff,dcg,{listing,"codegen"}},
+ {iff,doldcg,{listing,"codegen"}}
| asm_passes()].
asm_passes() ->
@@ -743,32 +858,16 @@ asm_passes() ->
[{pass,beam_a},
{iff,da,{listing,"a"}},
{unless,no_postopt,
- [{unless,no_reorder,{pass,beam_reorder}},
- {iff,dre,{listing,"reorder"}},
- {pass,beam_block},
+ [{pass,beam_block},
{iff,dblk,{listing,"block"}},
{unless,no_except,{pass,beam_except}},
{iff,dexcept,{listing,"except"}},
- {unless,no_bs_opt,{pass,beam_bs}},
- {iff,dbs,{listing,"bs"}},
- {unless,no_topt,{pass,beam_type}},
- {iff,dtype,{listing,"type"}},
- {pass,beam_split},
- {iff,dsplit,{listing,"split"}},
- {unless,no_dead,{pass,beam_dead}},
- {iff,ddead,{listing,"dead"}},
{unless,no_jopt,{pass,beam_jump}},
{iff,djmp,{listing,"jump"}},
{unless,no_peep_opt,{pass,beam_peep}},
{iff,dpeep,{listing,"peep"}},
{pass,beam_clean},
{iff,dclean,{listing,"clean"}},
- {unless,no_bsm_opt,{pass,beam_bsm}},
- {iff,dbsm,{listing,"bsm"}},
- {unless,no_recv_opt,{pass,beam_receive}},
- {iff,drecv,{listing,"recv"}},
- {unless,no_record_opt,{pass,beam_record}},
- {iff,drecord,{listing,"record"}},
{unless,no_stack_trimming,{pass,beam_trim}},
{iff,dtrim,{listing,"trim"}},
{pass,beam_flatten}]},
@@ -777,7 +876,9 @@ asm_passes() ->
%% need to do a few clean-ups to code.
{iff,no_postopt,[{pass,beam_clean}]},
+ {iff,diffable,?pass(diffable)},
{pass,beam_z},
+ {iff,diffable,{listing,"S"}},
{iff,dz,{listing,"z"}},
{iff,dopt,{listing,"optimize"}},
{iff,'S',{listing,"S"}},
@@ -787,7 +888,7 @@ asm_passes() ->
| binary_passes()].
binary_passes() ->
- [{iff,'to_dis',{listing,"dis"}},
+ [{iff,'to_dis',?pass(to_dis)},
{native_compile,fun test_native/1,fun native_compile/2},
{unless,binary,?pass(save_binary,not_werror)}
].
@@ -921,11 +1022,17 @@ parse_module(_Code, St0) ->
end.
do_parse_module(DefEncoding, #compile{ifile=File,options=Opts,dir=Dir}=St) ->
+ SourceName0 = proplists:get_value(source, Opts, File),
+ SourceName = case member(deterministic, Opts) of
+ true -> filename:basename(SourceName0);
+ false -> SourceName0
+ end,
R = epp:parse_file(File,
- [{includes,[".",Dir|inc_paths(Opts)]},
- {macros,pre_defs(Opts)},
- {default_encoding,DefEncoding},
- extra]),
+ [{includes,[".",Dir|inc_paths(Opts)]},
+ {source_name, SourceName},
+ {macros,pre_defs(Opts)},
+ {default_encoding,DefEncoding},
+ extra]),
case R of
{ok,Forms,Extra} ->
Encoding = proplists:get_value(encoding, Extra),
@@ -1128,6 +1235,16 @@ core_lint_module(Code, St) ->
errors=St#compile.errors ++ Es}}
end.
+%% makedep + output and continue
+makedep_and_output(Code0, St) ->
+ {ok,DepCode,St1} = makedep(Code0,St),
+ case makedep_output(DepCode, St1) of
+ {ok,_IgnoreCode,St2} ->
+ {ok,Code0,St2};
+ {error,St2} ->
+ {error,St2}
+ end.
+
makedep(Code0, #compile{ifile=Ifile,ofile=Ofile,options=Opts}=St) ->
%% Get the target of the Makefile rule.
@@ -1408,16 +1525,30 @@ encrypt_debug_info(DebugInfo, Key, Opts) ->
end.
cleanup_compile_options(Opts) ->
- lists:filter(fun keep_compile_option/1, Opts).
-
+ IsDeterministic = lists:member(deterministic, Opts),
+ lists:filter(fun(Opt) ->
+ keep_compile_option(Opt, IsDeterministic)
+ end, Opts).
+
+%% Include paths and current directory don't affect compilation, but they might
+%% be helpful so we include them unless we're doing a deterministic build.
+keep_compile_option({i, _}, Deterministic) ->
+ not Deterministic;
+keep_compile_option({cwd, _}, Deterministic) ->
+ not Deterministic;
%% We are storing abstract, not asm or core.
-keep_compile_option(from_asm) -> false;
-keep_compile_option(from_core) -> false;
+keep_compile_option(from_asm, _Deterministic) ->
+ false;
+keep_compile_option(from_core, _Deterministic) ->
+ false;
%% Parse transform and macros have already been applied.
-keep_compile_option({parse_transform, _}) -> false;
-keep_compile_option({d, _, _}) -> false;
+keep_compile_option({parse_transform, _}, _Deterministic) ->
+ false;
+keep_compile_option({d, _, _}, _Deterministic) ->
+ false;
%% Do not affect compilation result on future calls.
-keep_compile_option(Option) -> effects_code_generation(Option).
+keep_compile_option(Option, _Deterministic) ->
+ effects_code_generation(Option).
start_crypto() ->
try crypto:start() of
@@ -1448,15 +1579,33 @@ save_core_code(Code, St) ->
beam_asm(Code0, #compile{ifile=File,extra_chunks=ExtraChunks,options=CompilerOpts}=St) ->
case debug_info(St) of
{ok,DebugInfo,Opts0} ->
- Source = paranoid_absname(File),
Opts1 = [O || O <- Opts0, effects_code_generation(O)],
Chunks = [{<<"Dbgi">>, DebugInfo} | ExtraChunks],
- {ok,Code} = beam_asm:module(Code0, Chunks, Source, Opts1, CompilerOpts),
+ CompileInfo = compile_info(File, CompilerOpts, Opts1),
+ {ok,Code} = beam_asm:module(Code0, Chunks, CompileInfo, CompilerOpts),
{ok,Code,St#compile{abstract_code=[]}};
{error,Es} ->
{error,St#compile{errors=St#compile.errors ++ [{File,Es}]}}
end.
+compile_info(File, CompilerOpts, Opts) ->
+ IsSlim = member(slim, CompilerOpts),
+ IsDeterministic = member(deterministic, CompilerOpts),
+ Info0 = proplists:get_value(compile_info, Opts, []),
+ Info1 =
+ case paranoid_absname(File) of
+ [_|_] = Source when not IsSlim, not IsDeterministic ->
+ [{source,Source} | Info0];
+ _ ->
+ Info0
+ end,
+ Info2 =
+ case IsDeterministic of
+ false -> [{options,proplists:delete(compile_info, Opts)} | Info1];
+ true -> Info1
+ end,
+ Info2.
+
paranoid_absname(""=File) ->
File;
paranoid_absname(File) ->
@@ -1506,21 +1655,24 @@ native_compile_1(Code, St) ->
case IgnoreErrors of
true ->
Ws = [{St#compile.ifile,[{none,?MODULE,{native,R}}]}],
- {ok,St#compile{warnings=St#compile.warnings ++ Ws}};
+ {ok,Code,St#compile{warnings=St#compile.warnings ++ Ws}};
false ->
Es = [{St#compile.ifile,[{none,?MODULE,{native,R}}]}],
{error,St#compile{errors=St#compile.errors ++ Es}}
end
catch
- Class:R ->
- Stk = erlang:get_stacktrace(),
+ exit:{unimplemented_instruction,_}=Unimplemented ->
+ Ws = [{St#compile.ifile,
+ [{none,?MODULE,Unimplemented}]}],
+ {ok,Code,St#compile{warnings=St#compile.warnings ++ Ws}};
+ Class:R:Stack ->
case IgnoreErrors of
true ->
Ws = [{St#compile.ifile,
- [{none,?MODULE,{native_crash,R,Stk}}]}],
- {ok,St#compile{warnings=St#compile.warnings ++ Ws}};
+ [{none,?MODULE,{native_crash,R,Stack}}]}],
+ {ok,Code,St#compile{warnings=St#compile.warnings ++ Ws}};
false ->
- erlang:raise(Class, R, Stk)
+ erlang:raise(Class, R, Stack)
end
end.
@@ -1748,6 +1900,21 @@ listing(LFun, Ext, Code, St) ->
{error,St#compile{errors=St#compile.errors ++ Es}}
end.
+to_dis(Code, #compile{module=Module,ofile=Outfile}=St) ->
+ Loaded = code:is_loaded(Module),
+ Sticky = code:is_sticky(Module),
+ _ = [code:unstick_mod(Module) || Sticky],
+
+ {module,Module} = code:load_binary(Module, "", Code),
+ DestDir = filename:dirname(Outfile),
+ DisFile = filename:join(DestDir, atom_to_list(Module) ++ ".dis"),
+ ok = erts_debug:dis_to_file(Module, DisFile),
+
+ %% Restore loaded module
+ _ = [{module, Module} = code:load_file(Module) || Loaded =/= false],
+ [code:stick_mod(Module) || Sticky],
+ {ok,Code,St}.
+
output_encoding(F, #compile{encoding = none}) ->
ok = io:setopts(F, [{encoding, epp:default_encoding()}]);
output_encoding(F, #compile{encoding = Encoding}) ->
@@ -1773,6 +1940,39 @@ restore_expand_module([F|Fs]) ->
[F|restore_expand_module(Fs)];
restore_expand_module([]) -> [].
+%%%
+%%% Transform the BEAM code to make it more friendly for
+%%% diffing: using function names instead of labels for
+%%% local calls and number labels relative to each function.
+%%%
+
+diffable(Code0, St) ->
+ {Mod,Exp,Attr,Fs0,NumLabels} = Code0,
+ EntryLabels0 = [{Entry,{Name,Arity}} ||
+ {function,Name,Arity,Entry,_} <- Fs0],
+ EntryLabels = maps:from_list(EntryLabels0),
+ Fs = [diffable_fix_function(F, EntryLabels) || F <- Fs0],
+ Code = {Mod,Exp,Attr,Fs,NumLabels},
+ {ok,Code,St}.
+
+diffable_fix_function({function,Name,Arity,Entry0,Is0}, LabelMap0) ->
+ Entry = maps:get(Entry0, LabelMap0),
+ {Is1,LabelMap} = diffable_label_map(Is0, 1, LabelMap0, []),
+ Fb = fun(Old) -> error({no_fb,Old}) end,
+ Is = beam_utils:replace_labels(Is1, [], LabelMap, Fb),
+ {function,Name,Arity,Entry,Is}.
+
+diffable_label_map([{label,Old}|Is], New, Map, Acc) ->
+ case Map of
+ #{Old:=NewLabel} ->
+ diffable_label_map(Is, New, Map, [{label,NewLabel}|Acc]);
+ #{} ->
+ diffable_label_map(Is, New+1, Map#{Old=>New}, [{label,New}|Acc])
+ end;
+diffable_label_map([I|Is], New, Map, Acc) ->
+ diffable_label_map(Is, New, Map, [I|Acc]);
+diffable_label_map([], _New, Map, Acc) ->
+ {Acc,Map}.
-spec options() -> 'ok'.
@@ -1893,22 +2093,25 @@ pre_load() ->
L = [beam_a,
beam_asm,
beam_block,
- beam_bs,
- beam_bsm,
beam_clean,
- beam_dead,
beam_dict,
beam_except,
beam_flatten,
beam_jump,
+ beam_kernel_to_ssa,
beam_opcodes,
beam_peep,
- beam_receive,
- beam_record,
- beam_reorder,
- beam_split,
+ beam_ssa,
+ beam_ssa_bsm,
+ beam_ssa_codegen,
+ beam_ssa_dead,
+ beam_ssa_funs,
+ beam_ssa_opt,
+ beam_ssa_pre_codegen,
+ beam_ssa_recv,
+ beam_ssa_share,
+ beam_ssa_type,
beam_trim,
- beam_type,
beam_utils,
beam_validator,
beam_z,
@@ -1923,12 +2126,10 @@ pre_load() ->
erl_lint,
erl_parse,
erl_scan,
+ sys_core_alias,
sys_core_bsm,
- sys_core_dsetel,
sys_core_fold,
- v3_codegen,
v3_core,
- v3_kernel,
- v3_life],
+ v3_kernel],
_ = code:ensure_modules_loaded(L),
ok.
diff --git a/lib/compiler/src/compiler.app.src b/lib/compiler/src/compiler.app.src
index 3139d68902..a086a3a8d3 100644
--- a/lib/compiler/src/compiler.app.src
+++ b/lib/compiler/src/compiler.app.src
@@ -24,24 +24,29 @@
beam_a,
beam_asm,
beam_block,
- beam_bs,
- beam_bsm,
beam_clean,
- beam_dead,
beam_dict,
beam_disasm,
beam_except,
beam_flatten,
beam_jump,
+ beam_kernel_to_ssa,
beam_listing,
beam_opcodes,
beam_peep,
- beam_receive,
- beam_reorder,
- beam_record,
- beam_split,
+ beam_ssa,
+ beam_ssa_bsm,
+ beam_ssa_codegen,
+ beam_ssa_dead,
+ beam_ssa_funs,
+ beam_ssa_lint,
+ beam_ssa_opt,
+ beam_ssa_pp,
+ beam_ssa_pre_codegen,
+ beam_ssa_recv,
+ beam_ssa_share,
+ beam_ssa_type,
beam_trim,
- beam_type,
beam_utils,
beam_validator,
beam_z,
@@ -58,17 +63,15 @@
core_lib,
erl_bifs,
rec_env,
+ sys_core_alias,
sys_core_bsm,
- sys_core_dsetel,
sys_core_fold,
sys_core_fold_lists,
sys_core_inline,
sys_pre_attributes,
- v3_codegen,
v3_core,
v3_kernel,
- v3_kernel_pp,
- v3_life
+ v3_kernel_pp
]},
{registered, []},
{applications, [kernel, stdlib]},
diff --git a/lib/compiler/src/core_lint.erl b/lib/compiler/src/core_lint.erl
index 7d3513c0ba..3f69cb03a9 100644
--- a/lib/compiler/src/core_lint.erl
+++ b/lib/compiler/src/core_lint.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -353,12 +353,6 @@ expr(#c_case{arg=Arg,clauses=Cs}, Def, Rt, St0) ->
Pc = case_patcount(Cs),
St1 = body(Arg, Def, Pc, St0),
clauses(Cs, Def, Pc, Rt, St1);
-expr(#c_receive{clauses=Cs,timeout=#c_literal{val=infinity},
- action=#c_literal{}},
- Def, Rt, St) ->
- %% If the timeout is 'infinity', the after code can never
- %% be reached. We don't care if the return count is wrong.
- clauses(Cs, Def, 1, Rt, St);
expr(#c_receive{clauses=Cs,timeout=T,action=A}, Def, Rt, St0) ->
St1 = expr(T, Def, 1, St0),
St2 = body(A, Def, Rt, St1),
@@ -497,8 +491,10 @@ pattern(#c_tuple{es=Es}, Def, Ps, St) ->
pattern_list(Es, Def, Ps, St);
pattern(#c_map{es=Es}, Def, Ps, St) ->
pattern_list(Es, Def, Ps, St);
-pattern(#c_map_pair{op=#c_literal{val=exact},key=K,val=V},Def,Ps,St) ->
- pattern_list([K,V],Def,Ps,St);
+pattern(#c_map_pair{op=#c_literal{val=exact},key=K,val=V}, Def, Ps, St) ->
+ %% The key is an input.
+ pat_map_expr(K, Def, St),
+ pattern_list([V],Def,Ps,St);
pattern(#c_binary{segments=Ss}, Def, Ps, St0) ->
St = pat_bin_tail_check(Ss, St0),
pat_bin(Ss, Def, Ps, St);
@@ -561,6 +557,10 @@ pat_bit_expr(#c_binary{}, _, _Def, St) ->
pat_bit_expr(_, _, _, St) ->
add_error({illegal_expr,St#lint.func}, St).
+pat_map_expr(#c_var{name=N}, Def, St) -> expr_var(N, Def, St);
+pat_map_expr(#c_literal{}, _Def, St) -> St;
+pat_map_expr(_, _, St) -> add_error({illegal_expr,St#lint.func}, St).
+
%% pattern_list([Var], Defined, State) -> {[PatVar],State}.
%% pattern_list([Var], Defined, [PatVar], State) -> {[PatVar],State}.
diff --git a/lib/compiler/src/core_parse.hrl b/lib/compiler/src/core_parse.hrl
index 83a6f0179c..90c796d3d9 100644
--- a/lib/compiler/src/core_parse.hrl
+++ b/lib/compiler/src/core_parse.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,81 +29,82 @@
%% The record definitions appear alphabetically
--record(c_alias, {anno=[], var, % var :: Tree,
- pat}). % pat :: Tree
+-record(c_alias, {anno=[] :: list(), var :: cerl:cerl(),
+ pat :: cerl:cerl()}).
--record(c_apply, {anno=[], op, % op :: Tree,
- args}). % args :: [Tree]
+-record(c_apply, {anno=[] :: list(), op :: cerl:cerl(),
+ args :: [cerl:cerl()]}).
--record(c_binary, {anno=[], segments :: [cerl:c_bitstr()]}).
+-record(c_binary, {anno=[] :: list(), segments :: [cerl:c_bitstr()]}).
--record(c_bitstr, {anno=[], val, % val :: Tree,
- size, % size :: Tree,
- unit, % unit :: Tree,
- type, % type :: Tree,
- flags}). % flags :: Tree
+-record(c_bitstr, {anno=[] :: list(), val :: cerl:cerl(),
+ size :: cerl:cerl(),
+ unit :: cerl:cerl(),
+ type :: cerl:cerl(),
+ flags :: cerl:cerl()}).
--record(c_call, {anno=[], module, % module :: Tree,
- name, % name :: Tree,
- args}). % args :: [Tree]
+-record(c_call, {anno=[] :: list(), module :: cerl:cerl(),
+ name :: cerl:cerl(),
+ args :: [cerl:cerl()]}).
--record(c_case, {anno=[], arg, % arg :: Tree,
- clauses}). % clauses :: [Tree]
+-record(c_case, {anno=[] :: list(), arg :: cerl:cerl(),
+ clauses :: [cerl:cerl()]}).
--record(c_catch, {anno=[], body}). % body :: Tree
+-record(c_catch, {anno=[] :: list(), body :: cerl:cerl()}).
--record(c_clause, {anno=[], pats, % pats :: [Tree],
- guard, % guard :: Tree,
- body}). % body :: Tree
+-record(c_clause, {anno=[] :: list(), pats :: [cerl:cerl()],
+ guard :: cerl:cerl(),
+ body :: cerl:cerl() | any()}). % TODO
--record(c_cons, {anno=[], hd, % hd :: Tree,
- tl}). % tl :: Tree
+-record(c_cons, {anno=[] :: list(), hd :: cerl:cerl(),
+ tl :: cerl:cerl()}).
--record(c_fun, {anno=[], vars, % vars :: [Tree],
- body}). % body :: Tree
+-record(c_fun, {anno=[] :: list(), vars :: [cerl:cerl()],
+ body :: cerl:cerl()}).
--record(c_let, {anno=[], vars, % vars :: [Tree],
- arg, % arg :: Tree,
- body}). % body :: Tree
+-record(c_let, {anno=[] :: list(), vars :: [cerl:cerl()],
+ arg :: cerl:cerl(),
+ body :: cerl:cerl()}).
--record(c_letrec, {anno=[], defs, % defs :: [#c_def{}],
- body}). % body :: Tree
+-record(c_letrec, {anno=[] :: list(),
+ defs :: [{cerl:cerl(), cerl:cerl()}],
+ body :: cerl:cerl()}).
--record(c_literal, {anno=[], val}). % val :: literal()
+-record(c_literal, {anno=[] :: list(), val :: any()}).
--record(c_map, {anno=[],
+-record(c_map, {anno=[] :: list(),
arg=#c_literal{val=#{}} :: cerl:c_var() | cerl:c_literal(),
es :: [cerl:c_map_pair()],
is_pat=false :: boolean()}).
--record(c_map_pair, {anno=[],
+-record(c_map_pair, {anno=[] :: list(),
op :: #c_literal{val::'assoc'} | #c_literal{val::'exact'},
- key,
- val}).
+ key :: any(), % TODO
+ val :: any()}). % TODO
--record(c_module, {anno=[], name, % name :: Tree,
- exports, % exports :: [Tree],
- attrs, % attrs :: [#c_def{}],
- defs}). % defs :: [#c_def{}]
+-record(c_module, {anno=[] :: list(), name :: cerl:cerl(),
+ exports :: [cerl:cerl()],
+ attrs :: [{cerl:cerl(), cerl:cerl()}],
+ defs :: [{cerl:cerl(), cerl:cerl()}]}).
--record(c_primop, {anno=[], name, % name :: Tree,
- args}). % args :: [Tree]
+-record(c_primop, {anno=[] :: list(), name :: cerl:cerl(),
+ args :: [cerl:cerl()]}).
--record(c_receive, {anno=[], clauses, % clauses :: [Tree],
- timeout, % timeout :: Tree,
- action}). % action :: Tree
+-record(c_receive, {anno=[] :: list(), clauses :: [cerl:cerl()],
+ timeout :: cerl:cerl(),
+ action :: cerl:cerl()}).
--record(c_seq, {anno=[], arg, % arg :: Tree,
- body}). % body :: Tree
+-record(c_seq, {anno=[] :: list(), arg :: cerl:cerl() | any(), % TODO
+ body :: cerl:cerl()}).
--record(c_try, {anno=[], arg, % arg :: Tree,
- vars, % vars :: [Tree],
- body, % body :: Tree
- evars, % evars :: [Tree],
- handler}). % handler :: Tree
+-record(c_try, {anno=[] :: list(), arg :: cerl:cerl(),
+ vars :: [cerl:cerl()],
+ body :: cerl:cerl(),
+ evars :: [cerl:cerl()],
+ handler :: cerl:cerl()}).
--record(c_tuple, {anno=[], es}). % es :: [Tree]
+-record(c_tuple, {anno=[] :: list(), es :: [cerl:cerl()]}).
--record(c_values, {anno=[], es}). % es :: [Tree]
+-record(c_values, {anno=[] :: list(), es :: [cerl:cerl()]}).
--record(c_var, {anno=[], name :: cerl:var_name()}).
+-record(c_var, {anno=[] :: list(), name :: cerl:var_name()}).
diff --git a/lib/compiler/src/core_parse.yrl b/lib/compiler/src/core_parse.yrl
index 79a7cccd98..10d8c44dd3 100644
--- a/lib/compiler/src/core_parse.yrl
+++ b/lib/compiler/src/core_parse.yrl
@@ -1,7 +1,7 @@
%% -*-Erlang-*-
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -36,7 +36,7 @@ other_pattern atomic_pattern tuple_pattern cons_pattern tail_pattern
binary_pattern segment_patterns segment_pattern
expression single_expression
-literal literals atomic_literal tuple_literal cons_literal tail_literal
+literal literals atomic_literal tuple_literal cons_literal tail_literal fun_literal
nil tuple cons tail
binary segments segment
@@ -267,6 +267,7 @@ single_expression -> cons : '$1'.
single_expression -> binary : '$1'.
single_expression -> variable : '$1'.
single_expression -> function_name : '$1'.
+single_expression -> fun_literal : '$1'.
single_expression -> fun_expr : '$1'.
single_expression -> let_expr : '$1'.
single_expression -> letrec_expr : '$1'.
@@ -303,6 +304,9 @@ tail_literal -> ']' : #c_literal{val=[]}.
tail_literal -> '|' literal ']' : '$2'.
tail_literal -> ',' literal tail_literal : c_cons('$2', '$3').
+fun_literal -> 'fun' atom ':' atom '/' integer :
+ #c_literal{val = erlang:make_fun(tok_val('$2'), tok_val('$4'), tok_val('$6'))}.
+
tuple -> '{' '}' : c_tuple([]).
tuple -> '{' anno_expressions '}' : c_tuple('$2').
@@ -496,7 +500,7 @@ make_lit_bin(Acc, [#c_bitstr{val=I0,size=Sz0,unit=U0,type=Type0,flags=F0}|T]) ->
throw(impossible)
end,
if
- Sz =< 8, T =:= [] ->
+ 0 =< Sz, Sz =< 8, T =:= [] ->
<<Acc/binary,I:Sz>>;
Sz =:= 8 ->
make_lit_bin(<<Acc/binary,I:8>>, T);
diff --git a/lib/compiler/src/core_pp.erl b/lib/compiler/src/core_pp.erl
index cff6c7098b..cb3f24fd08 100644
--- a/lib/compiler/src/core_pp.erl
+++ b/lib/compiler/src/core_pp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -136,6 +136,11 @@ format_1(#c_literal{anno=A,val=M},Ctxt) when is_map(M) ->
key=#c_literal{val=K},
val=#c_literal{val=V}} || {K,V} <- Pairs],
format_1(#c_map{anno=A,arg=#c_literal{val=#{}},es=Cpairs},Ctxt);
+format_1(#c_literal{val=F},_Ctxt) when is_function(F) ->
+ {module,M} = erlang:fun_info(F, module),
+ {name,N} = erlang:fun_info(F, name),
+ {arity,A} = erlang:fun_info(F, arity),
+ ["fun ",core_atom(M),$:,core_atom(N),$/,integer_to_list(A)];
format_1(#c_var{name={I,A}}, _) ->
[core_atom(I),$/,integer_to_list(A)];
format_1(#c_var{name=V}, _) ->
@@ -464,7 +469,7 @@ indent(#ctxt{indent=N}) ->
N =< 0 ->
"";
true ->
- string:chars($\t, N div ?TAB_WIDTH, spaces(N rem ?TAB_WIDTH))
+ lists:duplicate(N div ?TAB_WIDTH, $\t) ++ spaces(N rem ?TAB_WIDTH)
end.
nl_indent(Ctxt) -> [$\n|indent(Ctxt)].
@@ -541,4 +546,3 @@ segs_from_bitstring(Bitstring) ->
unit=#c_literal{val=1},
type=#c_literal{val=integer},
flags=#c_literal{val=[unsigned,big]}}].
-
diff --git a/lib/compiler/src/core_scan.erl b/lib/compiler/src/core_scan.erl
index 9f0676538f..a50a2ffa8d 100644
--- a/lib/compiler/src/core_scan.erl
+++ b/lib/compiler/src/core_scan.erl
@@ -200,8 +200,8 @@ pre_string(eof, Q, _, Sp, SoFar, Pos) ->
pre_string_error(Q, Sp, SoFar, Pos).
pre_string_error(Q, Sp, SoFar, Pos) ->
- S = reverse(string:substr(SoFar, 1, string:chr(SoFar, Q)-1)),
- pre_error({string,Q,string:substr(S, 1, 16)}, Sp, Pos).
+ [S,_] = string:split(SoFar, [Q]),
+ pre_error({string,Q,string:slice(string:reverse(S), 0, 16)}, Sp, Pos).
pre_char([C|Cs], SoFar) -> pre_char(C, Cs, SoFar);
pre_char([], _) -> more;
diff --git a/lib/compiler/src/erl_bifs.erl b/lib/compiler/src/erl_bifs.erl
index bafa9d75b7..94a5dfe012 100644
--- a/lib/compiler/src/erl_bifs.erl
+++ b/lib/compiler/src/erl_bifs.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,6 +32,22 @@
%% Returns `true' if the function `Module:Name/Arity' does not
%% affect the state, nor depend on the state, although its
%% evaluation is not guaranteed to complete normally for all input.
+%%
+%% NOTE: There is no need to include every new pure BIF
+%% here. Including it here means that the value of the function
+%% will be evaluated at compile-time if the arguments are
+%% constant. If that optimization is not useful/desired, there is
+%% no need to include the new BIF here.
+%%
+%% Functions whose return value could conceivably change in a
+%% future version of the runtime system must NOT be included here.
+%%
+%% Here are some example of functions that should not be
+%% included: `term_to_binary/1', hashing functions, non-trivial
+%% encode/decode functions.
+%%
+%% When unsure whether a new BIF should be included here, the
+%% conservative safe choice is NOT to include it.
-spec is_pure(atom(), atom(), arity()) -> boolean().
@@ -91,9 +107,11 @@ is_pure(erlang, is_bitstring, 1) -> true;
%% erlang:is_builtin/3 depends on the state (i.e. the version of the emulator).
is_pure(erlang, is_float, 1) -> true;
is_pure(erlang, is_function, 1) -> true;
+is_pure(erlang, is_function, 2) -> true;
is_pure(erlang, is_integer, 1) -> true;
is_pure(erlang, is_list, 1) -> true;
is_pure(erlang, is_map, 1) -> true;
+is_pure(erlang, is_map_key, 2) -> true;
is_pure(erlang, is_number, 1) -> true;
is_pure(erlang, is_pid, 1) -> true;
is_pure(erlang, is_port, 1) -> true;
@@ -106,9 +124,12 @@ is_pure(erlang, list_to_atom, 1) -> true;
is_pure(erlang, list_to_binary, 1) -> true;
is_pure(erlang, list_to_float, 1) -> true;
is_pure(erlang, list_to_integer, 1) -> true;
+is_pure(erlang, list_to_integer, 2) -> true;
is_pure(erlang, list_to_pid, 1) -> true;
is_pure(erlang, list_to_tuple, 1) -> true;
is_pure(erlang, max, 2) -> true;
+is_pure(erlang, make_fun, 3) -> true;
+is_pure(erlang, map_get, 2) -> true;
is_pure(erlang, min, 2) -> true;
is_pure(erlang, phash, 2) -> false;
is_pure(erlang, pid_to_list, 1) -> true;
@@ -190,12 +211,14 @@ is_safe(erlang, is_float, 1) -> true;
is_safe(erlang, is_function, 1) -> true;
is_safe(erlang, is_integer, 1) -> true;
is_safe(erlang, is_list, 1) -> true;
+is_safe(erlang, is_map, 1) -> true;
is_safe(erlang, is_number, 1) -> true;
is_safe(erlang, is_pid, 1) -> true;
is_safe(erlang, is_port, 1) -> true;
is_safe(erlang, is_reference, 1) -> true;
is_safe(erlang, is_tuple, 1) -> true;
is_safe(erlang, make_ref, 0) -> true;
+is_safe(erlang, make_fun, 3) -> true;
is_safe(erlang, max, 2) -> true;
is_safe(erlang, min, 2) -> true;
is_safe(erlang, node, 0) -> true;
diff --git a/lib/compiler/src/genop.tab b/lib/compiler/src/genop.tab
index b5688de339..86590fad87 100755
--- a/lib/compiler/src/genop.tab
+++ b/lib/compiler/src/genop.tab
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1998-2017. All Rights Reserved.
+# Copyright Ericsson AB 1998-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -142,8 +142,7 @@ BEAM_FORMAT_NUMBER=0
20: send/0
## @spec remove_message
-## @doc Unlink the current message from the message queue and store a
-## pointer to the message in x(0). Remove any timeout.
+## @doc Unlink the current message from the message queue. Remove any timeout.
21: remove_message/0
## @spec timeout
@@ -545,3 +544,55 @@ BEAM_FORMAT_NUMBER=0
## Test the arity of Reg and jumps to Lbl if it is not N.
## Test the first element of the tuple and jumps to Lbl if it is not Atom.
159: is_tagged_tuple/4
+
+# OTP 21
+
+## @spec build_stacktrace
+## @doc Given the raw stacktrace in x(0), build a cooked stacktrace suitable
+## for human consumption. Store it in x(0). Destroys all other registers.
+## Do a garbage collection if necessary to allocate space on the heap
+## for the result.
+160: build_stacktrace/0
+
+## @spec raw_raise
+## @doc This instruction works like the erlang:raise/3 BIF, except that the
+## stacktrace in x(2) must be a raw stacktrace.
+## x(0) is the class of the exception (error, exit, or throw),
+## x(1) is the exception term, and x(2) is the raw stackframe.
+## If x(0) is not a valid class, the instruction will not throw an
+## exception, but store the atom 'badarg' in x(0) and execute the
+## next instruction.
+161: raw_raise/0
+
+## @spec get_hd Source Head
+## @doc Get the head (or car) part of a list (a cons cell) from Source and
+## put it into the register Head.
+162: get_hd/2
+
+## @spec get_tl Source Tail
+## @doc Get the tail (or cdr) part of a list (a cons cell) from Source and
+## put it into the register Tail.
+163: get_tl/2
+
+# OTP 22
+
+## @spec put_tuple2 Destination Elements
+## @doc Build a tuple with the elements in the list Elements and put it
+## put into register Destination.
+164: put_tuple2/2
+
+## @spec bs_get_tail Ctx Dst Live
+## @doc Sets Dst to the tail of Ctx at the current position
+165: bs_get_tail/3
+
+## @spec bs_start_match3 Fail Bin Live Dst
+## @doc Starts a binary match sequence
+166: bs_start_match3/4
+
+## @spec bs_get_position Ctx Dst Live
+## @doc Sets Dst to the current position of Ctx
+167: bs_get_position/3
+
+## @spec bs_set_positon Ctx Pos
+## @doc Sets the current position of Ctx to Pos
+168: bs_set_position/2
diff --git a/lib/compiler/src/sys_core_alias.erl b/lib/compiler/src/sys_core_alias.erl
new file mode 100644
index 0000000000..3326c6a2a8
--- /dev/null
+++ b/lib/compiler/src/sys_core_alias.erl
@@ -0,0 +1,307 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% Purpose : Replace values by aliases from patterns optimisation for Core
+
+%% Replace expressions by aliases from patterns. For example:
+%%
+%% example({ok, Val}) ->
+%% {ok, Val}.
+%%
+%% will become:
+%%
+%% example({ok, Val} = Tuple) ->
+%% Tuple.
+%%
+%% Currently this pass aliases tuple and cons nodes made of literals,
+%% variables and other cons. The tuple/cons may appear anywhere in the
+%% pattern and it will be aliased if used later on.
+%%
+%% Notice a tuple/cons made only of literals is not aliased as it may
+%% be part of the literal pool.
+
+-module(sys_core_alias).
+
+-export([module/2]).
+
+-include("core_parse.hrl").
+
+-define(NOTSET, 0).
+
+-record(sub, {p=#{} :: #{term() => ?NOTSET | atom()}, %% Found pattern substitutions
+ v=cerl_sets:new() :: cerl_sets:set(cerl:var_name()), %% Variables used by patterns
+ t=undefined :: term()}). %% Temporary information from pre to post
+
+-type sub() :: #sub{}.
+
+-spec module(cerl:c_module(), [compile:option()]) ->
+ {'ok',cerl:c_module(),[]}.
+
+module(#c_module{defs=Ds0}=Mod, _Opts) ->
+ Ds1 = [def(D) || D <- Ds0],
+ {ok,Mod#c_module{defs=Ds1},[]}.
+
+def({#c_var{name={F,Arity}}=Name,B0}) ->
+ try
+ put(new_var_num, 0),
+ {B1,_} = cerl_trees:mapfold(fun pre/2, fun post/2, sub_new(undefined), B0),
+ erase(new_var_num),
+ {Name,B1}
+ catch
+ Class:Error:Stack ->
+ io:fwrite("Function: ~w/~w\n", [F,Arity]),
+ erlang:raise(Class, Error, Stack)
+ end.
+
+pre(#c_let{vars=Vars}=Node, Sub) ->
+ {Node,sub_fold(get_variables(Vars), Sub)};
+
+pre(#c_fun{vars=Vars}=Node, Sub) ->
+ {Node,sub_fold(get_variables(Vars), Sub)};
+
+pre(#c_clause{pats=Pats}=Node, Sub0) ->
+ VarNames = get_variables(Pats),
+ Sub1 = sub_fold(VarNames, Sub0),
+ Keys = get_pattern_keys(Pats),
+ Sub2 = sub_add_keys(Keys, Sub1),
+
+ #sub{v=SubNames,t=Temp} = Sub2,
+ Sub3 = Sub2#sub{v=merge_variables(VarNames, SubNames),
+ t={clause,Pats,Keys,SubNames,Temp}},
+
+ {Node#c_clause{pats=[]},Sub3};
+
+pre(Node, Sub0) ->
+ %% We cache only tuples and cons.
+ case cerl:is_data(Node) andalso not cerl:is_literal(Node) of
+ false ->
+ {Node,Sub0};
+ true ->
+ Kind = cerl:data_type(Node),
+ Es = cerl:data_es(Node),
+ case sub_cache_nodes(Kind, Es, Sub0) of
+ {Name,Sub1} ->
+ {cerl:ann_c_var(cerl:get_ann(Node), Name),Sub1};
+ error ->
+ {Node,Sub0}
+ end
+ end.
+
+post(#c_let{}=Node, Sub) ->
+ {Node,sub_unfold(Sub)};
+
+post(#c_fun{}=Node, Sub) ->
+ {Node,sub_unfold(Sub)};
+
+post(#c_clause{}=Node, #sub{t={clause,Pats0,Keys,V,T}}=Sub0) ->
+ {Sub1,PostKeys} = sub_take_keys(Keys, Sub0),
+ Pats1 = put_pattern_keys(Pats0, PostKeys),
+ Sub2 = sub_unfold(Sub1#sub{v=V,t=T}),
+ {Node#c_clause{pats=Pats1},Sub2};
+
+post(Node, Sub) ->
+ {Node,Sub}.
+
+%% sub_new/1
+%% sub_add_keys/2
+%% sub_take_keys/3
+%% sub_cache_nodes/3
+%%
+%% Manages the substitutions record.
+
+%% Builds a new sub.
+-spec sub_new(term()) -> sub().
+sub_new(Temp) ->
+ #sub{t=Temp}.
+
+%% Folds the sub into a new one if the variables in nodes are not disjoint
+sub_fold(VarNames, #sub{v=SubNames}=Sub) ->
+ case is_disjoint_variables(VarNames, SubNames) of
+ true -> Sub#sub{t={temp,Sub#sub.t}};
+ false -> sub_new({sub,Sub})
+ end.
+
+%% Unfolds the sub in case one was folded in the previous step
+sub_unfold(#sub{t={temp,Temp}}=Sub) ->
+ Sub#sub{t=Temp};
+sub_unfold(#sub{t={sub,Sub}}) ->
+ Sub.
+
+%% Adds the keys extracted from patterns to the state.
+-spec sub_add_keys([term()], sub()) -> sub().
+sub_add_keys(Keys, #sub{p=Pat0}=Sub) ->
+ Pat1 =
+ lists:foldl(fun(Key, Acc) ->
+ false = maps:is_key(Key, Acc), %Assertion.
+ maps:put(Key, ?NOTSET, Acc)
+ end, Pat0, Keys),
+ Sub#sub{p=Pat1}.
+
+%% Take the keys from the map taking into account the keys
+%% that have changed as those must become aliases in the pattern.
+-spec sub_take_keys([term()], sub()) -> {sub(), [{term(), atom()}]}.
+sub_take_keys(Keys, #sub{p=Pat0}=Sub) ->
+ {Pat1,Acc} = sub_take_keys(Keys, Pat0, []),
+ {Sub#sub{p=Pat1},Acc}.
+
+sub_take_keys([K|T], Sub0, Acc) ->
+ case maps:take(K, Sub0) of
+ {?NOTSET,Sub1} ->
+ sub_take_keys(T, Sub1, Acc);
+ {Name,Sub1} ->
+ sub_take_keys(T, Sub1, [{K,Name}|Acc])
+ end;
+sub_take_keys([], Sub, Acc) ->
+ {Sub,Acc}.
+
+%% Check if the node can be cached based on the state information.
+%% If it can be cached and it does not have an alias for it, we
+%% build one.
+-spec sub_cache_nodes(atom(), [cerl:cerl()], sub()) -> {atom(), sub()} | error.
+sub_cache_nodes(Kind, Nodes, #sub{p=Pat}=Sub) ->
+ case nodes_to_key(Kind, Nodes) of
+ {ok, Key} ->
+ case Pat of
+ #{Key := ?NOTSET} ->
+ new_var_name(Key, Sub);
+ #{Key := Name} ->
+ {Name,Sub};
+ #{} ->
+ error
+ end;
+ error ->
+ error
+ end.
+
+new_var_name(Key, #sub{p=Pat}=Sub) ->
+ Counter = get(new_var_num),
+ Name = list_to_atom("@r" ++ integer_to_list(Counter)),
+ put(new_var_num, Counter + 1),
+ {Name,Sub#sub{p=maps:put(Key, Name, Pat)}}.
+
+%% get_variables/1
+%% is_disjoint_variables/2
+%% merge_variables/2
+
+get_variables(NodesList) ->
+ cerl_sets:from_list([Var || Node <- NodesList, Var <- cerl_trees:variables(Node)]).
+
+is_disjoint_variables(Vars1, Vars2) ->
+ cerl_sets:is_disjoint(Vars1, Vars2).
+
+merge_variables(Vars1, Vars2) ->
+ cerl_sets:union(Vars1, Vars2).
+
+%% get_pattern_keys/2
+%% put_pattern_keys/2
+%%
+%% Gets keys from patterns or add them as aliases.
+
+get_pattern_keys(Patterns) ->
+ lists:foldl(fun get_pattern_keys/2, [], Patterns).
+
+get_pattern_keys(#c_tuple{es=Es}, Acc0) ->
+ Acc1 = accumulate_pattern_keys(tuple, Es, Acc0),
+ lists:foldl(fun get_pattern_keys/2, Acc1, Es);
+get_pattern_keys(#c_cons{hd=Hd,tl=Tl}, Acc0) ->
+ Acc1 = accumulate_pattern_keys(cons, [Hd, Tl], Acc0),
+ get_pattern_keys(Tl, get_pattern_keys(Hd, Acc1));
+get_pattern_keys(#c_alias{pat=Pat}, Acc0) ->
+ get_pattern_keys(Pat, Acc0);
+get_pattern_keys(#c_map{es=Es}, Acc0) ->
+ lists:foldl(fun get_pattern_keys/2, Acc0, Es);
+get_pattern_keys(#c_map_pair{val=Val}, Acc0) ->
+ get_pattern_keys(Val, Acc0);
+get_pattern_keys(_, Acc) ->
+ Acc.
+
+accumulate_pattern_keys(Kind, Nodes, Acc) ->
+ case nodes_to_key(Kind, Nodes) of
+ {ok,Key} -> [Key|Acc];
+ error -> Acc
+ end.
+
+put_pattern_keys(Patterns, []) ->
+ Patterns;
+put_pattern_keys(Patterns, Keys) ->
+ {NewPatterns,Map} =
+ lists:mapfoldl(fun alias_pattern_keys/2, maps:from_list(Keys), Patterns),
+ %% Check all aliases have been consumed from the map.
+ 0 = map_size(Map),
+ NewPatterns.
+
+alias_pattern_keys(#c_tuple{anno=Anno,es=Es0}=Node, Acc0) ->
+ {Es1,Acc1} = lists:mapfoldl(fun alias_pattern_keys/2, Acc0, Es0),
+ nodes_to_alias(tuple, Es0, Anno, Node#c_tuple{es=Es1}, Acc1);
+alias_pattern_keys(#c_cons{anno=Anno,hd=Hd0,tl=Tl0}=Node, Acc0) ->
+ {Hd1,Acc1} = alias_pattern_keys(Hd0, Acc0),
+ {Tl1,Acc2} = alias_pattern_keys(Tl0, Acc1),
+ nodes_to_alias(cons, [Hd0, Tl0], Anno, Node#c_cons{hd=Hd1,tl=Tl1}, Acc2);
+alias_pattern_keys(#c_alias{pat=Pat0}=Node, Acc0) ->
+ {Pat1,Acc1} = alias_pattern_keys(Pat0, Acc0),
+ {Node#c_alias{pat=Pat1}, Acc1};
+alias_pattern_keys(#c_map{es=Es0}=Node, Acc0) ->
+ {Es1,Acc1} = lists:mapfoldl(fun alias_pattern_keys/2, Acc0, Es0),
+ {Node#c_map{es=Es1}, Acc1};
+alias_pattern_keys(#c_map_pair{val=Val0}=Node, Acc0) ->
+ {Val1,Acc1} = alias_pattern_keys(Val0, Acc0),
+ {Node#c_map_pair{val=Val1}, Acc1};
+alias_pattern_keys(Pattern, Acc) ->
+ {Pattern,Acc}.
+
+%% Check if a node must become an alias because
+%% its pattern was used later on as an expression.
+nodes_to_alias(Kind, Inner, Anno, Node, Keys0) ->
+ case nodes_to_key(Kind, Inner) of
+ {ok,Key} ->
+ case maps:take(Key, Keys0) of
+ {Name,Keys1} ->
+ Var = cerl:ann_c_var(Anno, Name),
+ {cerl:ann_c_alias(Anno, Var, Node), Keys1};
+ error ->
+ {Node,Keys0}
+ end;
+ error ->
+ {Node,Keys0}
+ end.
+
+%% Builds the key used to check if a value can be
+%% replaced by an alias. It considers literals,
+%% aliases, variables, tuples and cons recursively.
+nodes_to_key(Kind, Nodes) ->
+ nodes_to_key(Nodes, [], Kind).
+
+nodes_to_key([#c_alias{var=Var}|T], Acc, Kind) ->
+ nodes_to_key([Var|T], Acc, Kind);
+nodes_to_key([#c_var{name=Name}|T], Acc, Kind) ->
+ nodes_to_key(T, [[var,Name]|Acc], Kind);
+nodes_to_key([Node|T], Acc0, Kind) ->
+ case cerl:is_data(Node) of
+ false ->
+ error;
+ true ->
+ case nodes_to_key(cerl:data_es(Node), [], cerl:data_type(Node)) of
+ {ok,Key} ->
+ nodes_to_key(T, [Key|Acc0], Kind);
+ error ->
+ error
+ end
+ end;
+nodes_to_key([], Acc, Kind) ->
+ {ok,[Kind|Acc]}.
diff --git a/lib/compiler/src/sys_core_bsm.erl b/lib/compiler/src/sys_core_bsm.erl
index 3e04cc33df..685e807e65 100644
--- a/lib/compiler/src/sys_core_bsm.erl
+++ b/lib/compiler/src/sys_core_bsm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2017. All Rights Reserved.
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,332 +24,70 @@
-export([module/2,format_error/1]).
-include("core_parse.hrl").
--import(lists, [member/2,nth/2,reverse/1,usort/1]).
-spec module(cerl:c_module(), [compile:option()]) -> {'ok', cerl:c_module()}.
-module(#c_module{defs=Ds0}=Mod, Opts) ->
- {Ds,Ws0} = function(Ds0, [], []),
- case member(bin_opt_info, Opts) of
- false ->
- {ok,Mod#c_module{defs=Ds}};
- true ->
- Ws1 = [make_warning(Where, What) || {Where,What} <- Ws0],
- Ws = usort(Ws1),
- {ok,Mod#c_module{defs=Ds},Ws}
- end.
+module(#c_module{defs=Ds}=Mod, _Opts) ->
+ {ok,Mod#c_module{defs=function(Ds)}}.
-function([{#c_var{name={F,Arity}}=Name,B0}|Fs], FsAcc, Ws0) ->
- try cerl_trees:mapfold(fun bsm_an/2, Ws0, B0) of
- {B,Ws} ->
- function(Fs, [{Name,B}|FsAcc], Ws)
+function([{#c_var{name={F,Arity}}=Name,B0}|Fs]) ->
+ try cerl_trees:map(fun bsm_reorder/1, B0) of
+ B -> [{Name,B} | function(Fs)]
catch
- Class:Error ->
- Stack = erlang:get_stacktrace(),
- io:fwrite("Function: ~w/~w\n", [F,Arity]),
- erlang:raise(Class, Error, Stack)
+ Class:Error:Stack ->
+ io:fwrite("Function: ~w/~w\n", [F,Arity]),
+ erlang:raise(Class, Error, Stack)
end;
-function([], Fs, Ws) ->
- {reverse(Fs),Ws}.
+function([]) ->
+ [].
-type error() :: atom().
-spec format_error(error()) -> nonempty_string().
-format_error(bin_opt_alias) ->
- "INFO: the '=' operator will prevent delayed sub binary optimization";
-format_error(bin_partition) ->
- "INFO: matching non-variables after a previous clause matching a variable "
- "will prevent delayed sub binary optimization";
-format_error(bin_left_var_used_in_guard) ->
- "INFO: a variable to the left of the binary pattern is used in a guard; "
- "will prevent delayed sub binary optimization";
-format_error(bin_argument_order) ->
- "INFO: matching anything else but a plain variable to the left of "
- "binary pattern will prevent delayed sub binary optimization; "
- "SUGGEST changing argument order";
-format_error(bin_var_used) ->
- "INFO: using a matched out sub binary will prevent "
- "delayed sub binary optimization";
-format_error(orig_bin_var_used_in_guard) ->
- "INFO: using the original binary variable in a guard will prevent "
- "delayed sub binary optimization";
-format_error(bin_var_used_in_guard) ->
- "INFO: using a matched out sub binary in a guard will prevent "
- "delayed sub binary optimization".
-
-
-%%%
-%%% Annotate bit syntax matching to faciliate optimization in further passes.
-%%%
-
-bsm_an(Core0, Ws0) ->
- case bsm_an(Core0) of
- {ok,Core} ->
- {Core,Ws0};
- {ok,Core,W} ->
- {Core,[W|Ws0]}
+format_error(_) -> error(badarg).
+
+%%% Reorder bit syntax matching to faciliate optimization in further passes.
+
+bsm_reorder(#c_case{arg=#c_var{}=V}=Case) ->
+ bsm_reorder_1([V], Case);
+bsm_reorder(#c_case{arg=#c_values{es=Es}}=Case) ->
+ bsm_reorder_1(Es, Case);
+bsm_reorder(Core) ->
+ Core.
+
+bsm_reorder_1(Vs0, #c_case{clauses=Cs0}=Case) ->
+ case bsm_leftmost(Cs0) of
+ Pos when Pos > 0, Pos =/= none ->
+ Vs = core_lib:make_values(move_from_col(Pos, Vs0)),
+ Cs = [C#c_clause{pats=move_from_col(Pos, Ps)}
+ || #c_clause{pats=Ps}=C <- Cs0],
+ Case#c_case{arg=Vs,clauses=Cs};
+ _ ->
+ Case
end.
-bsm_an(#c_case{arg=#c_var{}=V}=Case) ->
- bsm_an_1([V], Case);
-bsm_an(#c_case{arg=#c_values{es=Es}}=Case) ->
- bsm_an_1(Es, Case);
-bsm_an(Other) ->
- {ok,Other}.
-
-bsm_an_1(Vs, #c_case{clauses=Cs}=Case) ->
- case bsm_leftmost(Cs) of
- none -> {ok,Case};
- Pos -> bsm_an_2(Vs, Cs, Case, Pos)
- end.
-
-bsm_an_2(Vs, Cs, Case, Pos) ->
- case bsm_nonempty(Cs, Pos) of
- true -> bsm_an_3(Vs, Cs, Case, Pos);
- false -> {ok,Case}
- end.
-
-bsm_an_3(Vs, Cs, Case, Pos) ->
- try
- bsm_ensure_no_partition(Cs, Pos),
- {ok,bsm_do_an(Vs, Pos, Cs, Case)}
- catch
- throw:{problem,Where,What} ->
- {ok,Case,{Where,What}}
- end.
-
-bsm_do_an(Vs0, Pos, Cs0, Case) ->
- case nth(Pos, Vs0) of
- #c_var{name=Vname}=V0 ->
- Cs = bsm_do_an_var(Vname, Pos, Cs0, []),
- V = bsm_annotate_for_reuse(V0),
- Bef = lists:sublist(Vs0, Pos-1),
- Aft = lists:nthtail(Pos, Vs0),
- case Bef ++ [V|Aft] of
- [_] ->
- Case#c_case{arg=V,clauses=Cs};
- Vs ->
- Case#c_case{arg=#c_values{es=Vs},clauses=Cs}
- end;
- _ ->
- Case
- end.
-
-bsm_do_an_var(V, S, [#c_clause{pats=Ps,guard=G,body=B0}=C0|Cs], Acc) ->
- case nth(S, Ps) of
- #c_var{name=VarName} ->
- case core_lib:is_var_used(V, G) of
- true -> bsm_problem(C0, orig_bin_var_used_in_guard);
- false -> ok
- end,
- case core_lib:is_var_used(VarName, G) of
- true -> bsm_problem(C0, bin_var_used_in_guard);
- false -> ok
- end,
- B1 = bsm_maybe_ctx_to_binary(VarName, B0),
- B = bsm_maybe_ctx_to_binary(V, B1),
- C = C0#c_clause{body=B},
- bsm_do_an_var(V, S, Cs, [C|Acc]);
- #c_alias{}=P ->
- case bsm_could_match_binary(P) of
- false ->
- bsm_do_an_var(V, S, Cs, [C0|Acc]);
- true ->
- bsm_problem(C0, bin_opt_alias)
- end;
- P ->
- case bsm_could_match_binary(P) andalso bsm_is_var_used(V, G, B0) of
- false ->
- bsm_do_an_var(V, S, Cs, [C0|Acc]);
- true ->
- bsm_problem(C0, bin_var_used)
- end
- end;
-bsm_do_an_var(_, _, [], Acc) -> reverse(Acc).
-
-bsm_annotate_for_reuse(#c_var{anno=Anno}=Var) ->
- Var#c_var{anno=[reuse_for_context|Anno]}.
-
-bsm_is_var_used(V, G, B) ->
- core_lib:is_var_used(V, G) orelse core_lib:is_var_used(V, B).
-
-bsm_maybe_ctx_to_binary(V, B) ->
- case core_lib:is_var_used(V, B) andalso not previous_ctx_to_binary(V, B) of
- false ->
- B;
- true ->
- #c_seq{arg=#c_primop{name=#c_literal{val=bs_context_to_binary},
- args=[#c_var{name=V}]},
- body=B}
- end.
-
-previous_ctx_to_binary(V, Core) ->
- case Core of
- #c_seq{arg=#c_primop{name=#c_literal{val=bs_context_to_binary},
- args=[#c_var{name=V}]}} ->
- true;
- _ ->
- false
- end.
+move_from_col(Pos, L) ->
+ {First,[Col|Rest]} = lists:split(Pos - 1, L),
+ [Col|First] ++ Rest.
%% bsm_leftmost(Cs) -> none | ArgumentNumber
-%% Find the leftmost argument that does binary matching. Return
-%% the number of the argument (1-N).
+%% Find the leftmost argument that matches a nonempty binary.
+%% Return either 'none' or the argument number (1-N).
bsm_leftmost(Cs) ->
bsm_leftmost_1(Cs, none).
+bsm_leftmost_1([_|_], 1) ->
+ 1;
bsm_leftmost_1([#c_clause{pats=Ps}|Cs], Pos) ->
bsm_leftmost_2(Ps, Cs, 1, Pos);
bsm_leftmost_1([], Pos) -> Pos.
bsm_leftmost_2(_, Cs, Pos, Pos) ->
bsm_leftmost_1(Cs, Pos);
-bsm_leftmost_2([#c_binary{}|_], Cs, N, _) ->
+bsm_leftmost_2([#c_binary{segments=[_|_]}|_], Cs, N, _) ->
bsm_leftmost_1(Cs, N);
bsm_leftmost_2([_|Ps], Cs, N, Pos) ->
bsm_leftmost_2(Ps, Cs, N+1, Pos);
bsm_leftmost_2([], Cs, _, Pos) ->
bsm_leftmost_1(Cs, Pos).
-
-%% bsm_nonempty(Cs, Pos) -> true|false
-%% Check if at least one of the clauses matches a non-empty
-%% binary in the given argument position.
-%%
-bsm_nonempty([#c_clause{pats=Ps}|Cs], Pos) ->
- case nth(Pos, Ps) of
- #c_binary{segments=[_|_]} ->
- true;
- _ ->
- bsm_nonempty(Cs, Pos)
- end;
-bsm_nonempty([], _ ) -> false.
-
-%% bsm_ensure_no_partition(Cs, Pos) -> ok (exception if problem)
-%% We must make sure that matching is not partitioned between
-%% variables like this:
-%% foo(<<...>>) -> ...
-%% foo(<Variable>) when ... -> ...
-%% foo(<Any non-variable pattern>) ->
-%% If there is such partition, we are not allowed to reuse the binary variable
-%% for the match context.
-%%
-%% Also, arguments to the left of the argument that is matched
-%% against a binary, are only allowed to be simple variables, not
-%% used in guards. The reason is that we must know that the binary is
-%% only matched in one place (i.e. there must be only one bs_start_match2
-%% instruction emitted).
-
-bsm_ensure_no_partition(Cs, Pos) ->
- bsm_ensure_no_partition_1(Cs, Pos, before).
-
-%% Loop through each clause.
-bsm_ensure_no_partition_1([#c_clause{pats=Ps,guard=G}|Cs], Pos, State0) ->
- State = bsm_ensure_no_partition_2(Ps, Pos, G, simple_vars, State0),
- case State of
- 'after' ->
- bsm_ensure_no_partition_after(Cs, Pos);
- _ ->
- ok
- end,
- bsm_ensure_no_partition_1(Cs, Pos, State);
-bsm_ensure_no_partition_1([], _, _) -> ok.
-
-%% Loop through each pattern for this clause.
-bsm_ensure_no_partition_2([#c_binary{}=Where|_], 1, _, Vstate, State) ->
- case State of
- before when Vstate =:= simple_vars -> within;
- before -> bsm_problem(Where, Vstate);
- within when Vstate =:= simple_vars -> within;
- within -> bsm_problem(Where, Vstate)
- end;
-bsm_ensure_no_partition_2([#c_alias{}=Alias|_], 1, N, Vstate, State) ->
- %% Retrieve the real pattern that the alias refers to and check that.
- P = bsm_real_pattern(Alias),
- bsm_ensure_no_partition_2([P], 1, N, Vstate, State);
-bsm_ensure_no_partition_2([_|_], 1, _, _Vstate, before=State) ->
- %% No binary matching yet - therefore no partition.
- State;
-bsm_ensure_no_partition_2([P|_], 1, _, Vstate, State) ->
- case bsm_could_match_binary(P) of
- false ->
- %% If clauses can be freely arranged (Vstate =:= simple_vars),
- %% a clause that cannot match a binary will not partition the clause.
- %% Example:
- %%
- %% a(Var, <<>>) -> ...
- %% a(Var, []) -> ...
- %% a(Var, <<B>>) -> ...
- %%
- %% But if the clauses can't be freely rearranged, as in
- %%
- %% b(Var, <<X>>) -> ...
- %% b(1, 2) -> ...
- %%
- %% we do have a problem.
- %%
- case Vstate of
- simple_vars -> State;
- _ -> bsm_problem(P, Vstate)
- end;
- true ->
- %% The pattern P *may* match a binary, so we must update the state.
- %% (P must be a variable.)
- case State of
- within -> 'after';
- 'after' -> 'after'
- end
- end;
-bsm_ensure_no_partition_2([#c_var{name=V}|Ps], N, G, Vstate, S) ->
- case core_lib:is_var_used(V, G) of
- false ->
- bsm_ensure_no_partition_2(Ps, N-1, G, Vstate, S);
- true ->
- bsm_ensure_no_partition_2(Ps, N-1, G, bin_left_var_used_in_guard, S)
- end;
-bsm_ensure_no_partition_2([_|Ps], N, G, _, S) ->
- bsm_ensure_no_partition_2(Ps, N-1, G, bin_argument_order, S).
-
-bsm_ensure_no_partition_after([#c_clause{pats=Ps}=C|Cs], Pos) ->
- case nth(Pos, Ps) of
- #c_var{} ->
- bsm_ensure_no_partition_after(Cs, Pos);
- _ ->
- bsm_problem(C, bin_partition)
- end;
-bsm_ensure_no_partition_after([], _) -> ok.
-
-bsm_could_match_binary(#c_alias{pat=P}) -> bsm_could_match_binary(P);
-bsm_could_match_binary(#c_cons{}) -> false;
-bsm_could_match_binary(#c_tuple{}) -> false;
-bsm_could_match_binary(#c_literal{val=Lit}) -> is_bitstring(Lit);
-bsm_could_match_binary(_) -> true.
-
-bsm_real_pattern(#c_alias{pat=P}) -> bsm_real_pattern(P);
-bsm_real_pattern(P) -> P.
-
-bsm_problem(Where, What) ->
- throw({problem,Where,What}).
-
-make_warning(Core, Term) ->
- case should_suppress_warning(Core) of
- true ->
- ok;
- false ->
- Anno = cerl:get_ann(Core),
- Line = get_line(Anno),
- File = get_file(Anno),
- {File,[{Line,?MODULE,Term}]}
- end.
-
-should_suppress_warning(Core) ->
- Ann = cerl:get_ann(Core),
- member(compiler_generated, Ann).
-
-get_line([Line|_]) when is_integer(Line) -> Line;
-get_line([_|T]) -> get_line(T);
-get_line([]) -> none.
-
-get_file([{file,File}|_]) -> File;
-get_file([_|T]) -> get_file(T);
-get_file([]) -> "no_file". % should not happen
diff --git a/lib/compiler/src/sys_core_dsetel.erl b/lib/compiler/src/sys_core_dsetel.erl
deleted file mode 100644
index bd3eeae238..0000000000
--- a/lib/compiler/src/sys_core_dsetel.erl
+++ /dev/null
@@ -1,361 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%% Purpose : Using dsetelement to make multiple-field record updates
-%% faster.
-
-%% The expansion of record field updates, when more than one field is
-%% updated, but not a majority of the fields, will create a sequence of
-%% calls to 'erlang:setelement(Index, Value, Tuple)' where Tuple in the
-%% first call is the original record tuple, and in the subsequent calls
-%% Tuple is the result of the previous call. Furthermore, all Index
-%% values are constant positive integers, and the first call to
-%% 'setelement' will have the greatest index. Thus all the following
-%% calls do not actually need to test at run-time whether Tuple has type
-%% tuple, nor that the index is within the tuple bounds.
-%%
-%% Since this introduces destructive updates in the Core Erlang code, it
-%% must be done as a last stage before going to lower-level code.
-%%
-%% NOTE: Because there are currently no write barriers in the system,
-%% this kind of optimization can only be done when we are sure that
-%% garbage collection will not be triggered between the creation of the
-%% tuple and the destructive updates - otherwise we might insert
-%% pointers from an older generation to a newer.
-%%
-%% The rewriting is done as follows:
-%%
-%% let X1 = call 'erlang':'setelement(5, Tuple, Value1)
-%% in call 'erlang':'setelement(3, X1, Value2)
-%% =>
-%% let X1 = call 'erlang':'setelement(5, Tuple, Value1)
-%% in do primop dsetelement(3, X1, Value2)
-%% X1
-%% and
-%% let X1 = call 'erlang':'setelement(5, Tuple, Value1)
-%% in let X2 = call 'erlang':'setelement(3, X1, Value2)
-%% in ...
-%% =>
-%% let X2 = call 'erlang':'setelement(5, Tuple, Value1)
-%% in do primop 'dsetelement(3, X2, Value2)
-%% ...
-%% if X1 is used exactly once.
-%% Thus, we need to track variable usage.
-%%
-
--module(sys_core_dsetel).
-
--export([module/2]).
-
--include("core_parse.hrl").
-
--spec module(cerl:c_module(), [compile:option()]) -> {'ok', cerl:c_module()}.
-
-module(M0, _Options) ->
- M = visit_module(M0),
- {ok,M}.
-
-visit_module(#c_module{defs=Ds0}=R) ->
- Env = #{},
- Ds = visit_module_1(Ds0, Env, []),
- R#c_module{defs=Ds}.
-
-visit_module_1([{Name,F0}|Fs], Env, Acc) ->
- try visit(Env, F0) of
- {F,_} ->
- visit_module_1(Fs, Env, [{Name,F}|Acc])
- catch
- Class:Error ->
- Stack = erlang:get_stacktrace(),
- #c_var{name={Func,Arity}} = Name,
- io:fwrite("Function: ~w/~w\n", [Func,Arity]),
- erlang:raise(Class, Error, Stack)
- end;
-visit_module_1([], _, Acc) ->
- lists:reverse(Acc).
-
-visit(Env, #c_var{name={_,_}}=R) ->
- %% Ignore local function name.
- {R, Env};
-visit(Env0, #c_var{name=X}=R) ->
- %% There should not be any free variables. If there are,
- %% the case will fail with an exception.
- case Env0 of
- #{X:=N} ->
- {R, Env0#{X:=N+1}}
- end;
-visit(Env, #c_literal{}=R) ->
- {R, Env};
-visit(Env0, #c_tuple{es=Es0}=R) ->
- {Es1,Env1} = visit_list(Env0, Es0),
- {R#c_tuple{es=Es1}, Env1};
-visit(Env0, #c_map{es=Es0}=R) ->
- {Es1,Env1} = visit_list(Env0, Es0),
- {R#c_map{es=Es1}, Env1};
-visit(Env0, #c_map_pair{key=K0,val=V0}=R) ->
- {K,Env1} = visit(Env0, K0),
- {V,Env2} = visit(Env1, V0),
- {R#c_map_pair{key=K,val=V}, Env2};
-visit(Env0, #c_cons{hd=H0,tl=T0}=R) ->
- {H1,Env1} = visit(Env0, H0),
- {T1,Env2} = visit(Env1, T0),
- {R#c_cons{hd=H1,tl=T1}, Env2};
-visit(Env0, #c_binary{segments=Segs}=R) ->
- Env = visit_bin_segs(Env0, Segs),
- {R, Env};
-visit(Env0, #c_values{es=Es0}=R) ->
- {Es1,Env1} = visit_list(Env0, Es0),
- {R#c_values{es=Es1}, Env1};
-visit(Env0, #c_fun{vars=Vs, body=B0}=R) ->
- {Xs, Env1} = bind_vars(Vs, Env0),
- {B1,Env2} = visit(Env1, B0),
- {R#c_fun{body=B1}, restore_vars(Xs, Env0, Env2)};
-visit(Env0, #c_let{vars=Vs, arg=A0, body=B0}=R) ->
- {A1,Env1} = visit(Env0, A0),
- {Xs,Env2} = bind_vars(Vs, Env1),
- {B1,Env3} = visit(Env2, B0),
- rewrite(R#c_let{arg=A1,body=B1}, Env3, restore_vars(Xs, Env1, Env3));
-visit(Env0, #c_seq{arg=A0, body=B0}=R) ->
- {A1,Env1} = visit(Env0, A0),
- {B1,Env2} = visit(Env1, B0),
- {R#c_seq{arg=A1,body=B1}, Env2};
-visit(Env0, #c_case{arg=A0,clauses=Cs0}=R) ->
- {A1,Env1} = visit(Env0, A0),
- {Cs1,Env2} = visit_list(Env1, Cs0),
- {R#c_case{arg=A1,clauses=Cs1}, Env2};
-visit(Env0, #c_clause{pats=Ps,guard=G0,body=B0}=R) ->
- {Vs, Env1} = visit_pats(Ps, Env0),
- {G1,Env2} = visit(Env1, G0),
- {B1,Env3} = visit(Env2, B0),
- {R#c_clause{guard=G1,body=B1}, restore_vars(Vs, Env0, Env3)};
-visit(Env0, #c_receive{clauses=Cs0,timeout=T0,action=A0}=R) ->
- {T1,Env1} = visit(Env0, T0),
- {Cs1,Env2} = visit_list(Env1, Cs0),
- {A1,Env3} = visit(Env2, A0),
- {R#c_receive{clauses=Cs1,timeout=T1,action=A1}, Env3};
-visit(Env0, #c_apply{op=Op0, args=As0}=R) ->
- {Op1,Env1} = visit(Env0, Op0),
- {As1,Env2} = visit_list(Env1, As0),
- {R#c_apply{op=Op1,args=As1}, Env2};
-visit(Env0, #c_call{module=M0,name=N0,args=As0}=R) ->
- {M1,Env1} = visit(Env0, M0),
- {N1,Env2} = visit(Env1, N0),
- {As1,Env3} = visit_list(Env2, As0),
- {R#c_call{module=M1,name=N1,args=As1}, Env3};
-visit(Env0, #c_primop{name=N0, args=As0}=R) ->
- {N1,Env1} = visit(Env0, N0),
- {As1,Env2} = visit_list(Env1, As0),
- {R#c_primop{name=N1,args=As1}, Env2};
-visit(Env0, #c_try{arg=E0, vars=Vs, body=B0, evars=Evs, handler=H0}=R) ->
- {E1,Env1} = visit(Env0, E0),
- {Xs, Env2} = bind_vars(Vs, Env1),
- {B1,Env3} = visit(Env2, B0),
- Env4 = restore_vars(Xs, Env1, Env3),
- {Ys, Env5} = bind_vars(Evs, Env4),
- {H1,Env6} = visit(Env5, H0),
- {R#c_try{arg=E1,body=B1,handler=H1}, restore_vars(Ys, Env4, Env6)};
-visit(Env0, #c_catch{body=B0}=R) ->
- {B1,Env1} = visit(Env0, B0),
- {R#c_catch{body=B1}, Env1};
-visit(Env0, #c_letrec{defs=Ds0,body=B0}=R) ->
- {Xs, Env1} = bind_vars([V || {V,_} <- Ds0], Env0),
- {Ds1,Env2} = visit_def_list(Env1, Ds0),
- {B1,Env3} = visit(Env2, B0),
- {R#c_letrec{defs=Ds1,body=B1}, restore_vars(Xs, Env0, Env3)}.
-%% The following general code for handling modules is slow if a module
-%% contains very many functions. There is special code in visit_module/1
-%% which is much faster.
-%% visit(Env0, #c_module{defs=D0}=R) ->
-%% {R1,Env1} = visit(Env0, #c_letrec{defs=D0,body=#c_nil{}}),
-%% {R#c_module{defs=R1#c_letrec.defs}, Env1};
-
-visit_list(Env, L) ->
- lists:mapfoldl(fun (E, A) -> visit(A, E) end, Env, L).
-
-visit_def_list(Env, L) ->
- lists:mapfoldl(fun ({Name,V0}, E0) ->
- {V1,E1} = visit(E0, V0),
- {{Name,V1}, E1}
- end, Env, L).
-
-visit_bin_segs(Env, Segs) ->
- lists:foldl(fun (#c_bitstr{val=Val,size=Sz}, E0) ->
- {_, E1} = visit(E0, Val),
- {_, E2} = visit(E1, Sz),
- E2
- end, Env, Segs).
-
-bind_vars(Vs, Env) ->
- bind_vars(Vs, Env, []).
-
-bind_vars([#c_var{name=X}|Vs], Env0, Xs)->
- bind_vars(Vs, Env0#{X=>0}, [X|Xs]);
-bind_vars([], Env,Xs) ->
- {Xs, Env}.
-
-visit_pats(Ps, Env) ->
- visit_pats(Ps, Env, []).
-
-visit_pats([P|Ps], Env0, Vs0) ->
- {Vs1, Env1} = visit_pat(Env0, P, Vs0),
- visit_pats(Ps, Env1, Vs1);
-visit_pats([], Env, Vs) ->
- {Vs, Env}.
-
-visit_pat(Env0, #c_var{name=V}, Vs) ->
- {[V|Vs], Env0#{V=>0}};
-visit_pat(Env0, #c_tuple{es=Es}, Vs) ->
- visit_pats(Es, Env0, Vs);
-visit_pat(Env0, #c_map{es=Es}, Vs) ->
- visit_pats(Es, Env0, Vs);
-visit_pat(Env0, #c_map_pair{op=#c_literal{val=exact},key=V,val=K}, Vs0) ->
- {Vs1, Env1} = visit_pat(Env0, V, Vs0),
- visit_pat(Env1, K, Vs1);
-visit_pat(Env0, #c_cons{hd=H,tl=T}, Vs0) ->
- {Vs1, Env1} = visit_pat(Env0, H, Vs0),
- visit_pat(Env1, T, Vs1);
-visit_pat(Env0, #c_binary{segments=Segs}, Vs) ->
- visit_pats(Segs, Env0, Vs);
-visit_pat(Env0, #c_bitstr{val=Val,size=Sz}, Vs0) ->
- {Vs1, Env1} =
- case Sz of
- #c_var{name=V} ->
- %% We don't tolerate free variables.
- case Env0 of
- #{V:=N} ->
- {Vs0, Env0#{V:=N+1}}
- end;
- _ ->
- visit_pat(Env0, Sz, Vs0)
- end,
- visit_pat(Env1, Val, Vs1);
-visit_pat(Env0, #c_alias{pat=P,var=#c_var{name=V}}, Vs) ->
- visit_pat(Env0#{V=>0}, P, [V|Vs]);
-visit_pat(Env, #c_literal{}, Vs) ->
- {Vs, Env}.
-
-restore_vars([V|Vs], Env0, Env1) ->
- case Env0 of
- #{V:=N} ->
- restore_vars(Vs, Env0, Env1#{V=>N});
- _ ->
- restore_vars(Vs, Env0, maps:remove(V, Env1))
- end;
-restore_vars([], _, Env1) ->
- Env1.
-
-
-%% let X1 = call 'erlang':'setelement(5, Tuple, Value1)
-%% in call 'erlang':'setelement(3, X1, Value2)
-%% =>
-%% let X1 = call 'erlang':'setelement(5, Tuple, Value1)
-%% in do primop dsetelement(3, X1, Value2)
-%% X1
-
-rewrite(#c_let{vars=[#c_var{name=X}=V]=Vs,
- arg=#c_call{module=#c_literal{val='erlang'},
- name=#c_literal{val='setelement'},
- args=[#c_literal{val=Index1}, _Tuple, _Val1]
- }=A,
- body=#c_call{anno=Banno,module=#c_literal{val='erlang'},
- name=#c_literal{val='setelement'},
- args=[#c_literal{val=Index2},
- #c_var{name=X},
- Val2]
- }
- }=R,
- _BodyEnv, FinalEnv)
- when is_integer(Index1), is_integer(Index2), Index2 > 0, Index1 > Index2 ->
- case is_safe(Val2) of
- true ->
- {R#c_let{vars=Vs,
- arg=A,
- body=#c_seq{arg=#c_primop{
- anno=Banno,
- name=#c_literal{val='dsetelement'},
- args=[#c_literal{val=Index2},
- V,
- Val2]},
- body=V}
- },
- FinalEnv};
- false ->
- {R, FinalEnv}
- end;
-
-%% let X1 = call 'erlang':'setelement(5, Tuple, Value1)
-%% in let X2 = 'erlang':'setelement(3, X1, Value2)
-%% in ...
-%% =>
-%% let X2 = call 'erlang':'setelement(5, Tuple, Value1)
-%% in do primop dsetelement(3, X2, Value2)
-%% ...
-%% if X1 is used exactly once.
-
-rewrite(#c_let{vars=[#c_var{name=X1}],
- arg=#c_call{module=#c_literal{val='erlang'},
- name=#c_literal{val='setelement'},
- args=[#c_literal{val=Index1}, _Tuple, _Val1]
- }=A,
- body=#c_let{vars=[#c_var{}=V]=Vs,
- arg=#c_call{anno=Banno,
- module=#c_literal{val='erlang'},
- name=#c_literal{val='setelement'},
- args=[#c_literal{val=Index2},
- #c_var{name=X1},
- Val2]},
- body=B}
- }=R,
- BodyEnv, FinalEnv)
- when is_integer(Index1), is_integer(Index2), Index2 > 0, Index1 > Index2 ->
- case is_single_use(X1, BodyEnv) andalso is_safe(Val2) of
- true ->
- {R#c_let{vars=Vs,
- arg=A,
- body=#c_seq{arg=#c_primop{
- anno=Banno,
- name=#c_literal{val='dsetelement'},
- args=[#c_literal{val=Index2},
- V,
- Val2]},
- body=B}
- },
- FinalEnv};
- false ->
- {R, FinalEnv}
- end;
-
-rewrite(R, _, FinalEnv) ->
- {R, FinalEnv}.
-
-%% is_safe(CoreExpr) -> true|false
-%% Determines whether the Core expression can cause a GC collection at run-time.
-%% Note: Assumes that the constant pool is turned on.
-
-is_safe(#c_var{}) -> true;
-is_safe(#c_literal{}) -> true;
-is_safe(_) -> false.
-
-is_single_use(V, Env) ->
- case Env of
- #{V:=1} ->
- true;
- _ ->
- false
- end.
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index d73060fb7e..4939a94a92 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -99,7 +99,7 @@
t=#{} :: map(), %Types
in_guard=false}). %In guard or not.
--type type_info() :: cerl:cerl() | 'bool' | 'integer'.
+-type type_info() :: cerl:cerl() | 'bool' | 'integer' | {'fun', pos_integer()}.
-type yes_no_maybe() :: 'yes' | 'no' | 'maybe'.
-type sub() :: #sub{}.
@@ -108,25 +108,29 @@
module(#c_module{defs=Ds0}=Mod, Opts) ->
put(no_inline_list_funcs, not member(inline_list_funcs, Opts)),
- case get(new_var_num) of
- undefined -> put(new_var_num, 0);
- _ -> ok
- end,
init_warnings(),
Ds1 = [function_1(D) || D <- Ds0],
+ erase(new_var_num),
erase(no_inline_list_funcs),
{ok,Mod#c_module{defs=Ds1},get_warnings()}.
function_1({#c_var{name={F,Arity}}=Name,B0}) ->
try
+ %% Find a suitable starting value for the variable
+ %% counter. Note that this pass assumes that new_var_name/1
+ %% returns a variable name distinct from any variable used in
+ %% the entire body of the function. We use integers as
+ %% variable names to avoid filling up the atom table when
+ %% compiling huge functions.
+ Count = cerl_trees:next_free_variable_name(B0),
+ put(new_var_num, Count),
B = find_fixpoint(fun(Core) ->
%% This must be a fun!
expr(Core, value, sub_new())
end, B0, 20),
{Name,B}
catch
- Class:Error ->
- Stack = erlang:get_stacktrace(),
+ Class:Error:Stack ->
io:fwrite("Function: ~w/~w\n", [F,Arity]),
erlang:raise(Class, Error, Stack)
end.
@@ -146,14 +150,9 @@ find_fixpoint(OptFun, Core0, Max) ->
body(Body, Sub) ->
body(Body, value, Sub).
-body(#c_values{anno=A,es=Es0}, Ctxt, Sub) ->
- Es1 = expr_list(Es0, Ctxt, Sub),
- case Ctxt of
- value ->
- #c_values{anno=A,es=Es1};
- effect ->
- make_effect_seq(Es1, Sub)
- end;
+body(#c_values{anno=A,es=Es0}, value, Sub) ->
+ Es1 = expr_list(Es0, value, Sub),
+ #c_values{anno=A,es=Es1};
body(E, Ctxt, Sub) ->
?ASSERT(verify_scope(E, Sub)),
expr(E, Ctxt, Sub).
@@ -208,6 +207,8 @@ opt_guard_try(#c_case{clauses=Cs}=Term) ->
Term#c_case{clauses=opt_guard_try_list(Cs)};
opt_guard_try(#c_clause{body=B0}=Term) ->
Term#c_clause{body=opt_guard_try(B0)};
+opt_guard_try(#c_let{vars=[],arg=#c_values{es=[]},body=B}) ->
+ B;
opt_guard_try(#c_let{arg=Arg,body=B0}=Term) ->
case opt_guard_try(B0) of
#c_literal{}=B ->
@@ -314,9 +315,15 @@ expr(#c_seq{arg=Arg0,body=B0}=Seq0, Ctxt, Sub) ->
false ->
%% Arg cannot be "values" here - only a single value
%% make sense here.
- case is_safe_simple(Arg, Sub) of
- true -> B1;
- false -> Seq0#c_seq{arg=Arg,body=B1}
+ case {Ctxt,is_safe_simple(Arg, Sub)} of
+ {effect,true} -> B1;
+ {effect,false} ->
+ case is_safe_simple(B1, Sub) of
+ true -> Arg;
+ false -> Seq0#c_seq{arg=Arg,body=B1}
+ end;
+ {value,true} -> B1;
+ {value,false} -> Seq0#c_seq{arg=Arg,body=B1}
end
end;
expr(#c_let{}=Let0, Ctxt, Sub) ->
@@ -338,7 +345,12 @@ expr(#c_letrec{body=#c_var{}}=Letrec, effect, _Sub) ->
void();
expr(#c_letrec{defs=Fs0,body=B0}=Letrec, Ctxt, Sub) ->
Fs1 = map(fun ({Name,Fb}) ->
- {Name,expr(Fb, {letrec,Ctxt}, Sub)}
+ case Ctxt =:= effect andalso is_fun_effect_safe(Name, B0) of
+ true ->
+ {Name,expr(Fb, {letrec, effect}, Sub)};
+ false ->
+ {Name,expr(Fb, {letrec, value}, Sub)}
+ end
end, Fs0),
B1 = body(B0, Ctxt, Sub),
Letrec#c_letrec{defs=Fs1,body=B1};
@@ -380,10 +392,7 @@ expr(#c_case{}=Case0, Ctxt, Sub) ->
Case = Case1#c_case{arg=Arg2,clauses=Cs2},
warn_no_clause_match(Case1, Case),
Expr = eval_case(Case, Sub),
- case move_case_into_arg(Case, Sub) of
- impossible -> Expr;
- Other -> Other
- end;
+ move_case_into_arg(Expr, Sub);
Other ->
expr(Other, Ctxt, Sub)
end;
@@ -392,14 +401,15 @@ expr(#c_receive{clauses=Cs0,timeout=T0,action=A0}=Recv, Ctxt, Sub) ->
T1 = expr(T0, value, Sub),
A1 = body(A0, Ctxt, Sub),
Recv#c_receive{clauses=Cs1,timeout=T1,action=A1};
-expr(#c_apply{anno=Anno,op=Op0,args=As0}=App, _, Sub) ->
+expr(#c_apply{anno=Anno,op=Op0,args=As0}=Apply0, _, Sub) ->
Op1 = expr(Op0, value, Sub),
As1 = expr_list(As0, value, Sub),
- case cerl:is_data(Op1) of
+ case cerl:is_data(Op1) andalso not is_literal_fun(Op1) of
false ->
- App#c_apply{op=Op1,args=As1};
+ Apply = Apply0#c_apply{op=Op1,args=As1},
+ fold_apply(Apply, Op1, As1);
true ->
- add_warning(App, invalid_call),
+ add_warning(Apply0, invalid_call),
Err = #c_call{anno=Anno,
module=#c_literal{val=erlang},
name=#c_literal{val=error},
@@ -415,9 +425,20 @@ expr(#c_call{module=M0,name=N0}=Call0, Ctxt, Sub) ->
no -> call(Call, M1, N1, Sub);
{yes,Seq} -> expr(Seq, Ctxt, Sub)
end;
+expr(#c_primop{name=#c_literal{val=build_stacktrace}}, effect, _Sub) ->
+ void();
expr(#c_primop{args=As0}=Prim, _, Sub) ->
As1 = expr_list(As0, value, Sub),
Prim#c_primop{args=As1};
+expr(#c_catch{anno=Anno,body=B}, effect, Sub) ->
+ %% When the return value of the 'catch' is ignored, we can replace it
+ %% with a try/catch to avoid building a stack trace when an exception
+ %% occurs.
+ Var = #c_var{name='catch_value'},
+ Evs = [#c_var{name='Class'},#c_var{name='Reason'},#c_var{name='Stk'}],
+ Try = #c_try{anno=Anno,arg=B,vars=[Var],body=Var,
+ evars=Evs,handler=void()},
+ expr(Try, effect, Sub);
expr(#c_catch{body=B0}=Catch, _, Sub) ->
%% We can remove catch if the value is simple
B1 = body(B0, value, Sub),
@@ -457,9 +478,101 @@ expr(#c_try{anno=A,arg=E0,vars=Vs0,body=B0,evars=Evs0,handler=H0}=Try, _, Sub0)
false ->
{Evs1,Sub2} = var_list(Evs0, Sub0),
H1 = body(H0, value, Sub2),
- Try#c_try{arg=E1,vars=Vs1,body=B1,evars=Evs1,handler=H1}
+ H2 = opt_try_handler(H1, lists:last(Evs1)),
+ Try#c_try{arg=E1,vars=Vs1,body=B1,evars=Evs1,handler=H2}
end.
+%% Attempts to convert old erlang:get_stacktrace/0 calls into the new
+%% three-argument catch, with possibility of further optimisations.
+opt_try_handler(#c_call{anno=A,module=#c_literal{val=erlang},name=#c_literal{val=get_stacktrace},args=[]}, Var) ->
+ #c_primop{anno=A,name=#c_literal{val=build_stacktrace},args=[Var]};
+opt_try_handler(#c_case{clauses=Cs0} = Case, Var) ->
+ Cs = [C#c_clause{body=opt_try_handler(B, Var)} || #c_clause{body=B} = C <- Cs0],
+ Case#c_case{clauses=Cs};
+opt_try_handler(#c_let{arg=Arg} = Let, Var) ->
+ Let#c_let{arg=opt_try_handler(Arg, Var)};
+opt_try_handler(X, _) -> X.
+
+%% If a fun or its application is used as an argument, then it's unsafe to
+%% handle it in effect context as the side-effects may rely on its return
+%% value. The following is a minimal example of where it can go wrong:
+%%
+%% do letrec 'f'/0 = fun () -> ... whatever ...
+%% in call 'side':'effect'(apply 'f'/0())
+%% 'ok'
+%%
+%% This function returns 'true' if Body definitely does not rely on a
+%% value produced by FVar, or 'false' if Body depends on or might depend on
+%% a value produced by FVar.
+
+is_fun_effect_safe(#c_var{}=FVar, Body) ->
+ ifes_1(FVar, Body, true).
+
+ifes_1(FVar, #c_alias{pat=Pat}, _Safe) ->
+ ifes_1(FVar, Pat, false);
+ifes_1(FVar, #c_apply{op=Op,args=Args}, Safe) ->
+ %% FVar(...) is safe as long its return value is ignored, but it's never
+ %% okay to pass FVar as an argument.
+ ifes_list(FVar, Args, false) andalso ifes_1(FVar, Op, Safe);
+ifes_1(FVar, #c_binary{segments=Segments}, _Safe) ->
+ ifes_list(FVar, Segments, false);
+ifes_1(FVar, #c_bitstr{val=Val,size=Size,unit=Unit}, _Safe) ->
+ ifes_list(FVar, [Val, Size, Unit], false);
+ifes_1(FVar, #c_call{args=Args}, _Safe) ->
+ ifes_list(FVar, Args, false);
+ifes_1(FVar, #c_case{arg=Arg,clauses=Clauses}, Safe) ->
+ ifes_1(FVar, Arg, false) andalso ifes_list(FVar, Clauses, Safe);
+ifes_1(FVar, #c_catch{body=Body}, _Safe) ->
+ ifes_1(FVar, Body, false);
+ifes_1(FVar, #c_clause{pats=Pats,guard=Guard,body=Body}, Safe) ->
+ ifes_list(FVar, Pats, false) andalso
+ ifes_1(FVar, Guard, false) andalso
+ ifes_1(FVar, Body, Safe);
+ifes_1(FVar, #c_cons{hd=Hd,tl=Tl}, _Safe) ->
+ ifes_1(FVar, Hd, false) andalso ifes_1(FVar, Tl, false);
+ifes_1(FVar, #c_fun{body=Body}, _Safe) ->
+ ifes_1(FVar, Body, false);
+ifes_1(FVar, #c_let{arg=Arg,body=Body}, Safe) ->
+ ifes_1(FVar, Arg, false) andalso ifes_1(FVar, Body, Safe);
+ifes_1(FVar, #c_letrec{defs=Defs,body=Body}, Safe) ->
+ Funs = [Fun || {_,Fun} <- Defs],
+ ifes_list(FVar, Funs, false) andalso ifes_1(FVar, Body, Safe);
+ifes_1(_FVar, #c_literal{}, _Safe) ->
+ true;
+ifes_1(FVar, #c_map{arg=Arg,es=Elements}, _Safe) ->
+ ifes_1(FVar, Arg, false) andalso ifes_list(FVar, Elements, false);
+ifes_1(FVar, #c_map_pair{key=Key,val=Val}, _Safe) ->
+ ifes_1(FVar, Key, false) andalso ifes_1(FVar, Val, false);
+ifes_1(FVar, #c_primop{args=Args}, _Safe) ->
+ ifes_list(FVar, Args, false);
+ifes_1(FVar, #c_receive{timeout=Timeout,action=Action,clauses=Clauses}, Safe) ->
+ ifes_1(FVar, Timeout, false) andalso
+ ifes_1(FVar, Action, Safe) andalso
+ ifes_list(FVar, Clauses, Safe);
+ifes_1(FVar, #c_seq{arg=Arg,body=Body}, Safe) ->
+ %% Arg of a #c_seq{} has no effect so it's okay to use FVar there even if
+ %% Safe=false.
+ ifes_1(FVar, Arg, true) andalso ifes_1(FVar, Body, Safe);
+ifes_1(FVar, #c_try{arg=Arg,handler=Handler,body=Body}, Safe) ->
+ ifes_1(FVar, Arg, false) andalso
+ ifes_1(FVar, Handler, Safe) andalso
+ ifes_1(FVar, Body, Safe);
+ifes_1(FVar, #c_tuple{es=Elements}, _Safe) ->
+ ifes_list(FVar, Elements, false);
+ifes_1(FVar, #c_values{es=Elements}, _Safe) ->
+ ifes_list(FVar, Elements, false);
+ifes_1(#c_var{name=Name}, #c_var{name=Name}, Safe) ->
+ %% It's safe to return FVar if it's unused.
+ Safe;
+ifes_1(_FVar, #c_var{}, _Safe) ->
+ true.
+
+ifes_list(FVar, [E|Es], Safe) ->
+ ifes_1(FVar, E, Safe) andalso ifes_list(FVar, Es, Safe);
+ifes_list(_FVar, [], _Safe) ->
+ true.
+
+
expr_list(Es, Ctxt, Sub) ->
[expr(E, Ctxt, Sub) || E <- Es].
@@ -479,6 +592,9 @@ bitstr_list(Es, Sub) ->
bitstr(#c_bitstr{val=Val,size=Size}=BinSeg, Sub) ->
BinSeg#c_bitstr{val=expr(Val, Sub),size=expr(Size, value, Sub)}.
+is_literal_fun(#c_literal{val=F}) -> is_function(F);
+is_literal_fun(_) -> false.
+
%% is_safe_simple(Expr, Sub) -> true | false.
%% A safe simple cannot fail with badarg and is safe to use
%% in a guard.
@@ -743,6 +859,25 @@ make_effect_seq([H|T], Sub) ->
end;
make_effect_seq([], _) -> void().
+%% fold_apply(Apply, LiteraFun, Args) -> Apply.
+%% Replace an apply of a literal external fun with a call.
+
+fold_apply(Apply, #c_literal{val=Fun}, Args) when is_function(Fun) ->
+ {module,Mod} = erlang:fun_info(Fun, module),
+ {name,Name} = erlang:fun_info(Fun, name),
+ {arity,Arity} = erlang:fun_info(Fun, arity),
+ if
+ Arity =:= length(Args) ->
+ #c_call{anno=Apply#c_apply.anno,
+ module=#c_literal{val=Mod},
+ name=#c_literal{val=Name},
+ args=Args};
+ true ->
+ Apply
+ end;
+fold_apply(Apply, _, _) -> Apply.
+
+
%% Handling remote calls. The module/name fields have been processed.
call(#c_call{args=As}=Call, #c_literal{val=M}=M0, #c_literal{val=N}=N0, Sub) ->
@@ -780,6 +915,8 @@ fold_call(Call, #c_literal{val=M}, #c_literal{val=F}, Args, Sub) ->
fold_call_1(Call, M, F, Args, Sub);
fold_call(Call, _M, _N, _Args, _Sub) -> Call.
+fold_call_1(Call, erlang, apply, [Fun,Args], _) ->
+ simplify_fun_apply(Call, Fun, Args);
fold_call_1(Call, erlang, apply, [Mod,Func,Args], _) ->
simplify_apply(Call, Mod, Func, Args);
fold_call_1(Call, Mod, Name, Args, Sub) ->
@@ -824,18 +961,16 @@ fold_lit_args(Call, Module, Name, Args0) ->
%%
fold_non_lit_args(Call, erlang, is_boolean, [Arg], Sub) ->
eval_is_boolean(Call, Arg, Sub);
-fold_non_lit_args(Call, erlang, element, [Arg1,Arg2], Sub) ->
- eval_element(Call, Arg1, Arg2, Sub);
fold_non_lit_args(Call, erlang, length, [Arg], _) ->
eval_length(Call, Arg);
fold_non_lit_args(Call, erlang, '++', [Arg1,Arg2], _) ->
eval_append(Call, Arg1, Arg2);
fold_non_lit_args(Call, lists, append, [Arg1,Arg2], _) ->
eval_append(Call, Arg1, Arg2);
-fold_non_lit_args(Call, erlang, setelement, [Arg1,Arg2,Arg3], _) ->
- eval_setelement(Call, Arg1, Arg2, Arg3);
-fold_non_lit_args(Call, erlang, is_record, [Arg1,Arg2,Arg3], Sub) ->
- eval_is_record(Call, Arg1, Arg2, Arg3, Sub);
+fold_non_lit_args(Call, erlang, is_function, [Arg1], Sub) ->
+ eval_is_function_1(Call, Arg1, Sub);
+fold_non_lit_args(Call, erlang, is_function, [Arg1,Arg2], Sub) ->
+ eval_is_function_2(Call, Arg1, Arg2, Sub);
fold_non_lit_args(Call, erlang, N, Args, Sub) ->
NumArgs = length(Args),
case erl_internal:comp_op(N, NumArgs) of
@@ -851,6 +986,22 @@ fold_non_lit_args(Call, erlang, N, Args, Sub) ->
end;
fold_non_lit_args(Call, _, _, _, _) -> Call.
+eval_is_function_1(Call, Arg1, Sub) ->
+ case get_type(Arg1, Sub) of
+ none -> Call;
+ {'fun',_} -> #c_literal{anno=cerl:get_ann(Call),val=true};
+ _ -> #c_literal{anno=cerl:get_ann(Call),val=false}
+ end.
+
+eval_is_function_2(Call, Arg1, #c_literal{val=Arity}, Sub)
+ when is_integer(Arity), Arity > 0 ->
+ case get_type(Arg1, Sub) of
+ none -> Call;
+ {'fun',Arity} -> #c_literal{anno=cerl:get_ann(Call),val=true};
+ _ -> #c_literal{anno=cerl:get_ann(Call),val=false}
+ end;
+eval_is_function_2(Call, _Arg1, _Arg2, _Sub) -> Call.
+
%% Evaluate a relational operation using type information.
eval_rel_op(Call, Op, [#c_var{name=V},#c_var{name=V}], _) ->
Bool = erlang:Op(same, same),
@@ -984,96 +1135,6 @@ eval_append(Call, #c_cons{anno=Anno,hd=H,tl=T}, List) ->
eval_append(Call, X, Y) ->
Call#c_call{args=[X,Y]}. %Rebuild call arguments.
-%% eval_element(Call, Pos, Tuple, Types) -> Val.
-%% Evaluates element/2 if the position Pos is a literal and
-%% the shape of the tuple Tuple is known.
-%%
-eval_element(Call, #c_literal{val=Pos}, Tuple, Types)
- when is_integer(Pos) ->
- case get_type(Tuple, Types) of
- none ->
- Call;
- Type ->
- Es = case cerl:is_c_tuple(Type) of
- false -> [];
- true -> cerl:tuple_es(Type)
- end,
- if
- 1 =< Pos, Pos =< length(Es) ->
- El = lists:nth(Pos, Es),
- try
- cerl:set_ann(pat_to_expr(El), [compiler_generated])
- catch
- throw:impossible ->
- Call
- end;
- true ->
- %% Index outside tuple or not a tuple.
- eval_failure(Call, badarg)
- end
- end;
-eval_element(Call, Pos, Tuple, Sub) ->
- case is_int_type(Pos, Sub) =:= no orelse
- is_tuple_type(Tuple, Sub) =:= no of
- true ->
- eval_failure(Call, badarg);
- false ->
- Call
- end.
-
-%% eval_is_record(Call, Var, Tag, Size, Types) -> Val.
-%% Evaluates is_record/3 using type information.
-%%
-eval_is_record(Call, Term, #c_literal{val=NeededTag},
- #c_literal{val=Size}, Types) ->
- case get_type(Term, Types) of
- none ->
- Call;
- Type ->
- Es = case cerl:is_c_tuple(Type) of
- false -> [];
- true -> cerl:tuple_es(Type)
- end,
- case Es of
- [#c_literal{val=Tag}|_] ->
- Bool = Tag =:= NeededTag andalso
- length(Es) =:= Size,
- #c_literal{val=Bool};
- _ ->
- #c_literal{val=false}
- end
- end;
-eval_is_record(Call, _, _, _, _) -> Call.
-
-%% eval_setelement(Call, Pos, Tuple, NewVal) -> Core.
-%% Evaluates setelement/3 if position Pos is an integer
-%% and the shape of the tuple Tuple is known.
-%%
-eval_setelement(Call, #c_literal{val=Pos}, Tuple, NewVal)
- when is_integer(Pos) ->
- case cerl:is_data(Tuple) of
- false ->
- Call;
- true ->
- Es0 = case cerl:is_c_tuple(Tuple) of
- false -> [];
- true -> cerl:tuple_es(Tuple)
- end,
- if
- 1 =< Pos, Pos =< length(Es0) ->
- Es = eval_setelement_1(Pos, Es0, NewVal),
- cerl:update_c_tuple(Tuple, Es);
- true ->
- eval_failure(Call, badarg)
- end
- end;
-eval_setelement(Call, _, _, _) -> Call.
-
-eval_setelement_1(1, [_|T], NewVal) ->
- [NewVal|T];
-eval_setelement_1(Pos, [H|T], NewVal) when Pos > 1 ->
- [H|eval_setelement_1(Pos-1, T, NewVal)].
-
%% eval_failure(Call, Reason) -> Core.
%% Warn for a call that will fail and replace the call with
%% a call to erlang:error(Reason).
@@ -1088,24 +1149,38 @@ eval_failure(Call, Reason) ->
%% Simplify an apply/3 to a call if the number of arguments
%% are known at compile time.
-simplify_apply(Call, Mod, Func, Args) ->
+simplify_apply(Call, Mod, Func, Args0) ->
case is_atom_or_var(Mod) andalso is_atom_or_var(Func) of
- true -> simplify_apply_1(Args, Call, Mod, Func, []);
- false -> Call
+ true ->
+ case get_fixed_args(Args0, []) of
+ error ->
+ Call;
+ {ok,Args} ->
+ Call#c_call{module=Mod,name=Func,args=Args}
+ end;
+ false ->
+ Call
end.
-
-simplify_apply_1(#c_literal{val=MoreArgs0}, Call, Mod, Func, Args)
- when length(MoreArgs0) >= 0 ->
- MoreArgs = [#c_literal{val=Arg} || Arg <- MoreArgs0],
- Call#c_call{module=Mod,name=Func,args=reverse(Args, MoreArgs)};
-simplify_apply_1(#c_cons{hd=Arg,tl=T}, Call, Mod, Func, Args) ->
- simplify_apply_1(T, Call, Mod, Func, [Arg|Args]);
-simplify_apply_1(_, Call, _, _, _) -> Call.
-
is_atom_or_var(#c_literal{val=Atom}) when is_atom(Atom) -> true;
is_atom_or_var(#c_var{}) -> true;
is_atom_or_var(_) -> false.
+simplify_fun_apply(#c_call{anno=Anno}=Call, Fun, Args0) ->
+ case get_fixed_args(Args0, []) of
+ error ->
+ Call;
+ {ok,Args} ->
+ #c_apply{anno=Anno,op=Fun,args=Args}
+ end.
+
+get_fixed_args(#c_literal{val=MoreArgs0}, Args)
+ when length(MoreArgs0) >= 0 ->
+ MoreArgs = [#c_literal{val=Arg} || Arg <- MoreArgs0],
+ {ok,reverse(Args, MoreArgs)};
+get_fixed_args(#c_cons{hd=Arg,tl=T}, Args) ->
+ get_fixed_args(T, [Arg|Args]);
+get_fixed_args(_, _) -> error.
+
%% clause(Clause, Cepxr, Context, Sub) -> Clause.
clause(#c_clause{pats=Ps0}=Cl, Cexpr, Ctxt, Sub0) ->
@@ -1119,16 +1194,15 @@ clause(#c_clause{pats=Ps0}=Cl, Cexpr, Ctxt, Sub0) ->
end.
clause_1(#c_clause{guard=G0,body=B0}=Cl, Ps1, Cexpr, Ctxt, Sub1) ->
- Sub2 = update_types(Cexpr, Ps1, Sub1),
GSub = case {Cexpr,Ps1,G0} of
{_,_,#c_literal{}} ->
%% No need for substitution tricks when the guard
%% does not contain any variables.
- Sub2;
+ Sub1;
{#c_var{name='_'},_,_} ->
%% In a 'receive', Cexpr is the variable '_', which represents the
%% message being matched. We must NOT do any extra substiutions.
- Sub2;
+ Sub1;
{#c_var{},[#c_var{}=Var],_} ->
%% The idea here is to optimize expressions such as
%%
@@ -1150,16 +1224,16 @@ clause_1(#c_clause{guard=G0,body=B0}=Cl, Ps1, Cexpr, Ctxt, Sub1) ->
%%
case cerl:is_c_fname(Cexpr) of
false ->
- sub_set_var(Var, Cexpr, Sub2);
+ sub_set_var(Var, Cexpr, Sub1);
true ->
%% We must not copy funs, and especially not into guards.
- Sub2
+ Sub1
end;
_ ->
- Sub2
+ Sub1
end,
G1 = guard(G0, GSub),
- B1 = body(B0, Ctxt, Sub2),
+ B1 = body(B0, Ctxt, Sub1),
Cl#c_clause{pats=Ps1,guard=G1,body=B1}.
%% let_substs(LetVars, LetArg, Sub) -> {[Var],[Val],Sub}.
@@ -1214,13 +1288,18 @@ let_subst_list([], [], _) -> {[],[],[]}.
%%pattern(Pat, Sub) -> pattern(Pat, Sub, Sub).
pattern(#c_var{}=Pat, Isub, Osub) ->
- case sub_is_val(Pat, Isub) of
+ case sub_is_in_scope(Pat, Isub) of
true ->
+ %% This variable either has a substitution or is used in
+ %% the variable list of an enclosing `let`. In either
+ %% case, it must be renamed to an unused name to avoid
+ %% name capture problems.
V1 = make_var_name(),
Pat1 = #c_var{name=V1},
{Pat1,sub_set_var(Pat, Pat1, sub_add_scope([V1], Osub))};
false ->
- {Pat,sub_del_var(Pat, Osub)}
+ %% This variable has never been used. Add it to the scope.
+ {Pat,sub_add_scope([Pat#c_var.name], Osub)}
end;
pattern(#c_literal{}=Pat, _, Osub) -> {Pat,Osub};
pattern(#c_cons{anno=Anno,hd=H0,tl=T0}, Isub, Osub0) ->
@@ -1238,8 +1317,7 @@ pattern(#c_binary{segments=V0}=Pat, Isub, Osub0) ->
{Pat#c_binary{segments=V1},Osub1};
pattern(#c_alias{var=V0,pat=P0}=Pat, Isub, Osub0) ->
{V1,Osub1} = pattern(V0, Isub, Osub0),
- {P1,Osub2} = pattern(P0, Isub, Osub1),
- Osub = update_types(V1, [P1], Osub2),
+ {P1,Osub} = pattern(P0, Isub, Osub1),
{Pat#c_alias{var=V1,pat=P1},Osub}.
map_pair_pattern_list(Ps0, Isub, Osub0) ->
@@ -1399,8 +1477,8 @@ is_subst(_) -> false.
%% sub_set_name(Name, Value, #sub{}) -> #sub{}.
%% sub_del_var(Var, #sub{}) -> #sub{}.
%% sub_subst_var(Var, Value, #sub{}) -> [{Name,Value}].
-%% sub_is_val(Var, #sub{}) -> boolean().
-%% sub_add_scope(#sub{}) -> #sub{}
+%% sub_is_in_scope(Var, #sub{}) -> boolean().
+%% sub_add_scope([Var], #sub{}) -> #sub{}
%% sub_subst_scope(#sub{}) -> #sub{}
%%
%% We use the variable name as key so as not have problems with
@@ -1435,18 +1513,6 @@ sub_set_name(V, Val, #sub{v=S,s=Scope,t=Tdb0}=Sub) ->
Tdb = copy_type(V, Val, Tdb1),
Sub#sub{v=orddict:store(V, Val, S),s=cerl_sets:add_element(V, Scope),t=Tdb}.
-sub_del_var(#c_var{name=V}, #sub{v=S,s=Scope,t=Tdb}=Sub) ->
- %% Profiling shows that for programs with many record operations,
- %% sub_del_var/2 is a bottleneck. Since the scope contains all
- %% variables that are live, we know that V cannot be present in S
- %% if it is not in the scope.
- case cerl_sets:is_element(V, Scope) of
- false ->
- Sub#sub{s=cerl_sets:add_element(V, Scope)};
- true ->
- Sub#sub{v=orddict:erase(V, S),t=kill_types(V, Tdb)}
- end.
-
sub_subst_var(#c_var{name=V}, Val, #sub{v=S0}) ->
%% Fold chained substitutions.
[{V,Val}] ++ [ {K,Val} || {K,#c_var{name=V1}} <- S0, V1 =:= V].
@@ -1472,16 +1538,8 @@ sub_subst_scope_1([H|T], Key, Acc) ->
sub_subst_scope_1(T, Key-1, [{Key,#c_var{name=H}}|Acc]);
sub_subst_scope_1([], _, Acc) -> Acc.
-sub_is_val(#c_var{name=V}, #sub{v=S,s=Scope}) ->
- %% When the bottleneck in sub_del_var/2 was eliminated, this
- %% became the new bottleneck. Since the scope contains all
- %% live variables, a variable V can only be the target for
- %% a substitution if it is in the scope.
- cerl_sets:is_element(V, Scope) andalso v_is_value(V, S).
-
-v_is_value(Var, [{_,#c_var{name=Var}}|_]) -> true;
-v_is_value(Var, [_|T]) -> v_is_value(Var, T);
-v_is_value(_, []) -> false.
+sub_is_in_scope(#c_var{name=V}, #sub{s=Scope}) ->
+ cerl_sets:is_element(V, Scope).
%% warn_no_clause_match(CaseOrig, CaseOpt) -> ok
%% Generate a warning if none of the user-specified clauses
@@ -1939,58 +1997,22 @@ case_opt_compiler_generated(Core) ->
%% case_expand_var(Expr0, Sub) -> Expr
-%% If Expr0 is a variable that has been previously matched and
-%% is known to be a tuple, return the tuple instead. Otherwise
+%% If Expr0 is a variable that is known to be bound to a
+%% constructed tuple, return the tuple instead. Otherwise
%% return Expr0 unchanged.
-%%
+
case_expand_var(E, #sub{t=Tdb}) ->
Key = cerl:var_name(E),
case Tdb of
- #{Key:=T0} ->
- case cerl:is_c_tuple(T0) of
- false ->
- E;
- true ->
- %% The pattern was a tuple. Now we must make sure
- %% that the elements of the tuple are suitable. In
- %% particular, we don't want binary or map
- %% construction here, since that means that the
- %% binary or map will be constructed in the 'case'
- %% argument. That is wasteful for binaries. Even
- %% worse is that any map pattern that use the ':='
- %% operator will fail when used in map
- %% construction (only the '=>' operator is allowed
- %% when constructing a map from scratch).
- try
- cerl_trees:map(fun coerce_to_data/1, T0)
- catch
- throw:impossible ->
- %% Something unsuitable was found (map or
- %% or binary). Keep the variable.
- E
- end
+ #{Key:=T} ->
+ case cerl:is_c_tuple(T) of
+ false -> E;
+ true -> T
end;
_ ->
E
end.
-%% coerce_to_data(Core) -> Core'
-%% Coerce an element originally from a pattern to an data item or or
-%% variable. Throw an 'impossible' exception if non-data Core Erlang
-%% terms such as binary construction or map construction are
-%% encountered.
-
-coerce_to_data(C) ->
- case cerl:is_c_alias(C) of
- false ->
- case cerl:is_data(C) orelse cerl:is_c_var(C) of
- true -> C;
- false -> throw(impossible)
- end;
- true ->
- coerce_to_data(cerl:alias_pat(C))
- end.
-
%% case_opt_nomatch(E, Clauses, LitExpr) -> Clauses'
%% Remove all clauses that cannot possibly match.
@@ -2146,7 +2168,7 @@ make_var(A) ->
make_var_name() ->
N = get(new_var_num),
put(new_var_num, N+1),
- list_to_atom("@f"++integer_to_list(N)).
+ N.
letify(Bs, Body) ->
Ann = cerl:get_ann(Body),
@@ -2422,16 +2444,10 @@ move_let_into_expr(#c_let{vars=InnerVs0,body=InnerBody0}=Inner,
Outer#c_let{vars=OuterVs,arg=Arg,
body=Inner#c_let{vars=InnerVs,arg=OuterBody,body=InnerBody}};
move_let_into_expr(#c_let{vars=Lvs0,body=Lbody0}=Let,
- #c_case{arg=Cexpr0,clauses=[Ca0,Cb0|Cs]}=Case, Sub0) ->
- %% Test if there are no more clauses than Ca0 and Cb0, or if
- %% Cb0 is guaranteed to match.
- TwoClauses = Cs =:= [] orelse
- case Cb0 of
- #c_clause{pats=[#c_var{}],guard=#c_literal{val=true}} -> true;
- _ -> false
- end,
- case {TwoClauses,is_failing_clause(Ca0),is_failing_clause(Cb0)} of
- {true,false,true} ->
+ #c_case{arg=Cexpr0,clauses=[Ca0|Cs0]}=Case, Sub0) ->
+ case not is_failing_clause(Ca0) andalso
+ are_all_failing_clauses(Cs0) of
+ true ->
%% let <Lvars> = case <Case-expr> of
%% <Cpats> -> <Clause-body>;
%% <OtherCpats> -> erlang:error(...)
@@ -2467,8 +2483,8 @@ move_let_into_expr(#c_let{vars=Lvs0,body=Lbody0}=Let,
body=Lbody},
Ca = Ca0#c_clause{pats=CaPats,guard=G,body=B},
- Cb = clause(Cb0, Cexpr, value, Sub0),
- Case#c_case{arg=Cexpr,clauses=[Ca,Cb]}
+ Cs = [clause(C, Cexpr, value, Sub0) || C <- Cs0],
+ Case#c_case{arg=Cexpr,clauses=[Ca|Cs]}
catch
nomatch ->
%% This is not a defeat. The code will eventually
@@ -2476,7 +2492,7 @@ move_let_into_expr(#c_let{vars=Lvs0,body=Lbody0}=Let,
%% optimizations done in this module.
impossible
end;
- {_,_,_} -> impossible
+ false -> impossible
end;
move_let_into_expr(#c_let{vars=Lvs0,body=Lbody0}=Let,
#c_seq{arg=Sarg0,body=Sbody0}=Seq, Sub0) ->
@@ -2499,9 +2515,86 @@ move_let_into_expr(#c_let{vars=Lvs0,body=Lbody0}=Let,
body=Lbody}};
move_let_into_expr(_Let, _Expr, _Sub) -> impossible.
+are_all_failing_clauses(Cs) ->
+ all(fun is_failing_clause/1, Cs).
+
is_failing_clause(#c_clause{body=B}) ->
will_fail(B).
+%% opt_build_stacktrace(Let) -> Core.
+%% If the stacktrace is *only* used in a call to erlang:raise/3,
+%% there is no need to build a cooked stackframe using build_stacktrace/1.
+
+opt_build_stacktrace(#c_let{vars=[#c_var{name=Cooked}],
+ arg=#c_primop{name=#c_literal{val=build_stacktrace},
+ args=[RawStk]},
+ body=Body}=Let) ->
+ case Body of
+ #c_call{module=#c_literal{val=erlang},
+ name=#c_literal{val=raise},
+ args=[Class,Exp,#c_var{name=Cooked}]} ->
+ case core_lib:is_var_used(Cooked, #c_cons{hd=Class,tl=Exp}) of
+ true ->
+ %% Not safe. The stacktrace is used in the class or
+ %% reason.
+ Let;
+ false ->
+ %% The stacktrace is only used in the last
+ %% argument for erlang:raise/3. There is no need
+ %% to build the stacktrace. Replace the call to
+ %% erlang:raise/3 with the the raw_raise/3
+ %% instruction, which will use a raw stacktrace.
+ #c_primop{name=#c_literal{val=raw_raise},
+ args=[Class,Exp,RawStk]}
+ end;
+ #c_let{vars=[#c_var{name=V}],arg=Arg,body=B0} when V =/= Cooked ->
+ case core_lib:is_var_used(Cooked, Arg) of
+ false ->
+ %% The built stacktrace is not used in the argument,
+ %% so we can sink the building of the stacktrace into
+ %% the body of the let.
+ B = opt_build_stacktrace(Let#c_let{body=B0}),
+ Body#c_let{body=B};
+ true ->
+ Let
+ end;
+ #c_seq{arg=Arg,body=B0} ->
+ case core_lib:is_var_used(Cooked, Arg) of
+ false ->
+ %% The built stacktrace is not used in the argument,
+ %% so we can sink the building of the stacktrace into
+ %% the body of the sequence.
+ B = opt_build_stacktrace(Let#c_let{body=B0}),
+ Body#c_seq{body=B};
+ true ->
+ Let
+ end;
+ #c_case{arg=Arg,clauses=Cs0} ->
+ case core_lib:is_var_used(Cooked, Arg) orelse
+ is_used_in_any_guard(Cooked, Cs0) of
+ false ->
+ %% The built stacktrace is not used in the argument,
+ %% so we can sink the building of the stacktrace into
+ %% each arm of the case.
+ Cs = [begin
+ B = opt_build_stacktrace(Let#c_let{body=B0}),
+ C#c_clause{body=B}
+ end || #c_clause{body=B0}=C <- Cs0],
+ Body#c_case{clauses=Cs};
+ true ->
+ Let
+ end;
+ _ ->
+ Let
+ end;
+opt_build_stacktrace(Expr) ->
+ Expr.
+
+is_used_in_any_guard(V, Cs) ->
+ any(fun(#c_clause{guard=G}) ->
+ core_lib:is_var_used(V, G)
+ end, Cs).
+
%% opt_case_in_let(Let) -> Let'
%% Try to avoid building tuples that are immediately matched.
%% A common pattern is:
@@ -2616,9 +2709,13 @@ delay_build_expr_1(#c_receive{clauses=Cs0,
timeout=Timeout,
action=A0}=Rec, TypeSig) ->
Cs = delay_build_cs(Cs0, TypeSig),
- A = case Timeout of
- #c_literal{val=infinity} -> A0;
- _ -> delay_build_expr(A0, TypeSig)
+ A = case {Timeout,A0} of
+ {#c_literal{val=infinity},#c_literal{}} ->
+ {_Type,Arity} = TypeSig,
+ Es = lists:duplicate(Arity, A0),
+ core_lib:make_values(Es);
+ _ ->
+ delay_build_expr(A0, TypeSig)
end,
Rec#c_receive{clauses=Cs,action=A};
delay_build_expr_1(#c_seq{body=B0}=Seq, TypeSig) ->
@@ -2653,53 +2750,94 @@ opt_simple_let_1(#c_let{vars=Vs0,body=B0}=Let, Arg0, Ctxt, Sub0) ->
%% Optimise let and add new substitutions.
{Vs,Args,Sub1} = let_substs(Vs0, Arg0, Sub0),
BodySub = update_let_types(Vs, Args, Sub1),
+ Sub = Sub1#sub{v=[],s=cerl_sets:new()},
B = body(B0, Ctxt, BodySub),
Arg = core_lib:make_values(Args),
- opt_simple_let_2(Let, Vs, Arg, B, B0, Ctxt, Sub1).
+ opt_simple_let_2(Let, Vs, Arg, B, B0, Sub).
-opt_simple_let_2(Let0, Vs0, Arg0, Body, PrevBody, Ctxt, Sub) ->
+
+%% opt_simple_let_2(Let0, Vs0, Arg0, Body, PrevBody, Ctxt, Sub) -> Core.
+%% Do final simplifications of the let.
+%%
+%% Note that the substitutions and scope in Sub have been cleared
+%% and should not be used.
+
+opt_simple_let_2(Let0, Vs0, Arg0, Body, PrevBody, Sub) ->
case {Vs0,Arg0,Body} of
- {[#c_var{name=N1}],Arg1,#c_var{name=N2}} ->
- case N1 =:= N2 of
- true ->
- %% let <Var> = Arg in <Var> ==> Arg
- Arg1;
- false ->
- %% let <Var> = Arg in <OtherVar> ==> seq Arg OtherVar
- Arg = maybe_suppress_warnings(Arg1, Vs0, PrevBody),
- #c_seq{arg=Arg,body=Body}
- end;
+ {[#c_var{name=V}],Arg1,#c_var{name=V}} ->
+ %% let <Var> = Arg in <Var> ==> Arg
+ Arg1;
{[],#c_values{es=[]},_} ->
%% No variables left.
Body;
- {Vs,Arg1,#c_literal{}} ->
- Arg = maybe_suppress_warnings(Arg1, Vs, PrevBody),
- case Ctxt of
- effect ->
- %% Throw away the literal body.
- Arg;
- value ->
- %% Since the variable is not used in the body, we
- %% can rewrite the let to a sequence.
- %% let <Var> = Arg in Literal ==> seq Arg Literal
- #c_seq{arg=Arg,body=Body}
- end;
- {Vs,Arg1,Body} ->
- %% If none of the variables are used in the body, we can
- %% rewrite the let to a sequence:
- %% let <Var> = Arg in BodyWithoutVar ==>
- %% seq Arg BodyWithoutVar
- case is_any_var_used(Vs, Body) of
- false ->
- Arg = maybe_suppress_warnings(Arg1, Vs, PrevBody),
- #c_seq{arg=Arg,body=Body};
- true ->
- Let1 = Let0#c_let{vars=Vs,arg=Arg1,body=Body},
- opt_bool_case_in_let(Let1, Sub)
+ {[#c_var{name=V}=Var|Vars]=Vars0,Arg1,Body} ->
+ case core_lib:is_var_used(V, Body) of
+ false when Vars =:= [] ->
+ %% If the variable is not used in the body, we can
+ %% rewrite the let to a sequence:
+ %% let <Var> = Arg in BodyWithoutVar ==>
+ %% seq Arg BodyWithoutVar
+ Arg = maybe_suppress_warnings(Arg1, Var, PrevBody),
+ #c_seq{arg=Arg,body=Body};
+ false ->
+ %% There are multiple values returned by the argument
+ %% and the first value is not used (this is a 'case'
+ %% with exported variables, but the return value is
+ %% ignored). We can remove the first variable and the
+ %% the first value returned from the 'let' argument.
+ Arg2 = remove_first_value(Arg1, Sub),
+ Let1 = Let0#c_let{vars=Vars,arg=Arg2,body=Body},
+ post_opt_let(Let1, Sub);
+ true ->
+ Let1 = Let0#c_let{vars=Vars0,arg=Arg1,body=Body},
+ post_opt_let(Let1, Sub)
end
end.
-%% maybe_suppress_warnings(Arg, [#c_var{}], PreviousBody) -> Arg'
+%% post_opt_let(Let, Sub)
+%% Final optimizations of the let.
+%%
+%% Note that the substitutions and scope in Sub have been cleared
+%% and should not be used.
+
+post_opt_let(Let0, Sub) ->
+ Let1 = opt_bool_case_in_let(Let0, Sub),
+ opt_build_stacktrace(Let1).
+
+
+%% remove_first_value(Core0, Sub) -> Core.
+%% Core0 is an expression that returns at least two values.
+%% Remove the first value returned from Core0.
+
+remove_first_value(#c_values{es=[V|Vs]}, Sub) ->
+ Values = core_lib:make_values(Vs),
+ case is_safe_simple(V, Sub) of
+ false ->
+ #c_seq{arg=V,body=Values};
+ true ->
+ Values
+ end;
+remove_first_value(#c_case{clauses=Cs0}=Core, Sub) ->
+ Cs = remove_first_value_cs(Cs0, Sub),
+ Core#c_case{clauses=Cs};
+remove_first_value(#c_receive{clauses=Cs0,action=Act0}=Core, Sub) ->
+ Cs = remove_first_value_cs(Cs0, Sub),
+ Act = remove_first_value(Act0, Sub),
+ Core#c_receive{clauses=Cs,action=Act};
+remove_first_value(#c_let{body=B}=Core, Sub) ->
+ Core#c_let{body=remove_first_value(B, Sub)};
+remove_first_value(#c_seq{body=B}=Core, Sub) ->
+ Core#c_seq{body=remove_first_value(B, Sub)};
+remove_first_value(#c_primop{}=Core, _Sub) ->
+ Core;
+remove_first_value(#c_call{}=Core, _Sub) ->
+ Core.
+
+remove_first_value_cs(Cs, Sub) ->
+ [C#c_clause{body=remove_first_value(B, Sub)} ||
+ #c_clause{body=B}=C <- Cs].
+
+%% maybe_suppress_warnings(Arg, #c_var{}, PreviousBody) -> Arg'
%% Try to suppress false warnings when a variable is not used.
%% For instance, we don't expect a warning for useless building in:
%%
@@ -2710,12 +2848,12 @@ opt_simple_let_2(Let0, Vs0, Arg0, Body, PrevBody, Ctxt, Sub) ->
%% referenced in the original unoptimized code. If they were, we will
%% consider the warning false and suppress it.
-maybe_suppress_warnings(Arg, Vs, PrevBody) ->
+maybe_suppress_warnings(Arg, #c_var{name=V}, PrevBody) ->
case should_suppress_warning(Arg) of
true ->
Arg; %Already suppressed.
false ->
- case is_any_var_used(Vs, PrevBody) of
+ case core_lib:is_var_used(V, PrevBody) of
true ->
suppress_warning([Arg]);
false ->
@@ -2804,7 +2942,7 @@ move_case_into_arg(#c_case{arg=#c_case{arg=OuterArg,
Outer#c_case{arg=OuterArg,
clauses=[OuterCa,OuterCb]};
false ->
- impossible
+ Inner0
end;
move_case_into_arg(#c_case{arg=#c_seq{arg=OuterArg,body=InnerArg}=Outer,
clauses=InnerClauses}=Inner, _Sub) ->
@@ -2820,15 +2958,8 @@ move_case_into_arg(#c_case{arg=#c_seq{arg=OuterArg,body=InnerArg}=Outer,
%%
Outer#c_seq{arg=OuterArg,
body=Inner#c_case{arg=InnerArg,clauses=InnerClauses}};
-move_case_into_arg(_, _) ->
- impossible.
-
-is_any_var_used([#c_var{name=V}|Vs], Expr) ->
- case core_lib:is_var_used(V, Expr) of
- false -> is_any_var_used(Vs, Expr);
- true -> true
- end;
-is_any_var_used([], _) -> false.
+move_case_into_arg(Expr, _) ->
+ Expr.
%%%
%%% Retrieving information about types.
@@ -2875,14 +3006,6 @@ is_int_type(Var, Sub) ->
C -> yes_no(cerl:is_c_int(C))
end.
--spec is_tuple_type(cerl:cerl(), sub()) -> yes_no_maybe().
-
-is_tuple_type(Var, Sub) ->
- case get_type(Var, Sub) of
- none -> maybe;
- C -> yes_no(cerl:is_c_tuple(C))
- end.
-
yes_no(true) -> yes;
yes_no(false) -> no.
@@ -2944,23 +3067,23 @@ returns_integer(_, _) -> false.
%% update_types(Expr, Pattern, Sub) -> Sub'
%% Update the type database.
--spec update_types(cerl:cerl(), [type_info()], sub()) -> sub().
+-spec update_types(cerl:c_var(), [type_info()], sub()) -> sub().
-update_types(Expr, Pat, #sub{t=Tdb0}=Sub) ->
- Tdb = update_types_1(Expr, Pat, Tdb0),
+update_types(#c_var{name=V}, Pat, #sub{t=Tdb0}=Sub) ->
+ Tdb = update_types_1(V, Pat, Tdb0),
Sub#sub{t=Tdb}.
-update_types_1(#c_var{name=V}, Pat, Types) ->
- update_types_2(V, Pat, Types);
-update_types_1(_, _, Types) -> Types.
-
-update_types_2(V, [#c_tuple{}=P], Types) ->
+update_types_1(V, [#c_tuple{}=P], Types) ->
Types#{V=>P};
-update_types_2(V, [#c_literal{val=Bool}], Types) when is_boolean(Bool) ->
+update_types_1(V, [#c_literal{val=Bool}], Types) when is_boolean(Bool) ->
Types#{V=>bool};
-update_types_2(V, [Type], Types) when is_atom(Type) ->
+update_types_1(V, [#c_fun{vars=Vars}], Types) ->
+ Types#{V=>{'fun',length(Vars)}};
+update_types_1(V, [#c_var{name={_,Arity}}], Types) ->
+ Types#{V=>{'fun',Arity}};
+update_types_1(V, [Type], Types) when is_atom(Type) ->
Types#{V=>Type};
-update_types_2(_, _, Types) -> Types.
+update_types_1(_, _, Types) -> Types.
%% kill_types(V, Tdb) -> Tdb'
%% Kill any entries that references the variable,
@@ -2976,6 +3099,8 @@ kill_types2(V, [{_,#c_tuple{}=Tuple}=Entry|Tdb]) ->
false -> [Entry|kill_types2(V, Tdb)];
true -> kill_types2(V, Tdb)
end;
+kill_types2(V, [{_, {'fun',_}}=Entry|Tdb]) ->
+ [Entry|kill_types2(V, Tdb)];
kill_types2(V, [{_,Atom}=Entry|Tdb]) when is_atom(Atom) ->
[Entry|kill_types2(V, Tdb)];
kill_types2(_, []) -> [].
diff --git a/lib/compiler/src/sys_core_fold_lists.erl b/lib/compiler/src/sys_core_fold_lists.erl
index 9867fab46a..e93b435011 100644
--- a/lib/compiler/src/sys_core_fold_lists.erl
+++ b/lib/compiler/src/sys_core_fold_lists.erl
@@ -37,22 +37,27 @@ call(#c_call{anno=Anno}, lists, all, [Arg1,Arg2]) ->
Xs = #c_var{name='Xs'},
X = #c_var{name='X'},
Err1 = #c_tuple{es=[#c_literal{val='case_clause'}, X]},
- CC1 = #c_clause{pats=[#c_literal{val=true}], guard=#c_literal{val=true},
+ CC1 = #c_clause{anno=Anno,
+ pats=[#c_literal{val=true}], guard=#c_literal{val=true},
body=#c_apply{anno=Anno, op=Loop, args=[Xs]}},
- CC2 = #c_clause{pats=[#c_literal{val=false}], guard=#c_literal{val=true},
+ CC2 = #c_clause{anno=Anno,
+ pats=[#c_literal{val=false}], guard=#c_literal{val=true},
body=#c_literal{val=false}},
- CC3 = #c_clause{pats=[X], guard=#c_literal{val=true},
+ CC3 = #c_clause{anno=Anno,
+ pats=[X], guard=#c_literal{val=true},
body=match_fail(Anno, Err1)},
- C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
+ C1 = #c_clause{anno=Anno,
+ pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
body=#c_case{arg=#c_apply{anno=Anno, op=F, args=[X]},
clauses = [CC1, CC2, CC3]}},
- C2 = #c_clause{pats=[#c_literal{val=[]}],
+ C2 = #c_clause{anno=Anno,
+ pats=[#c_literal{val=[]}],
guard=#c_call{module=#c_literal{val=erlang},
name=#c_literal{val=is_function},
args=[F, #c_literal{val=1}]},
body=#c_literal{val=true}},
Err2 = #c_tuple{es=[#c_literal{val='function_clause'}, F, Xs]},
- C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
+ C3 = #c_clause{anno=Anno, pats=[Xs], guard=#c_literal{val=true},
body=match_fail([{function_name,{'lists^all',1}}|Anno], Err2)},
Fun = #c_fun{vars=[Xs],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
@@ -66,16 +71,21 @@ call(#c_call{anno=Anno}, lists, any, [Arg1,Arg2]) ->
Xs = #c_var{name='Xs'},
X = #c_var{name='X'},
Err1 = #c_tuple{es=[#c_literal{val='case_clause'}, X]},
- CC1 = #c_clause{pats=[#c_literal{val=true}], guard=#c_literal{val=true},
+ CC1 = #c_clause{anno=Anno,
+ pats=[#c_literal{val=true}], guard=#c_literal{val=true},
body=#c_literal{val=true}},
- CC2 = #c_clause{pats=[#c_literal{val=false}], guard=#c_literal{val=true},
+ CC2 = #c_clause{anno=Anno,
+ pats=[#c_literal{val=false}], guard=#c_literal{val=true},
body=#c_apply{anno=Anno, op=Loop, args=[Xs]}},
- CC3 = #c_clause{pats=[X], guard=#c_literal{val=true},
+ CC3 = #c_clause{anno=Anno,
+ pats=[X], guard=#c_literal{val=true},
body=match_fail(Anno, Err1)},
- C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
+ C1 = #c_clause{anno=Anno,
+ pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
body=#c_case{arg=#c_apply{anno=Anno, op=F, args=[X]},
clauses = [CC1, CC2, CC3]}},
- C2 = #c_clause{pats=[#c_literal{val=[]}],
+ C2 = #c_clause{anno=Anno,
+ pats=[#c_literal{val=[]}],
guard=#c_call{module=#c_literal{val=erlang},
name=#c_literal{val=is_function},
args=[F, #c_literal{val=1}]},
@@ -94,16 +104,17 @@ call(#c_call{anno=Anno}, lists, foreach, [Arg1,Arg2]) ->
F = #c_var{name='F'},
Xs = #c_var{name='Xs'},
X = #c_var{name='X'},
- C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
+ C1 = #c_clause{anno=Anno,
+ pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
body=#c_seq{arg=#c_apply{anno=Anno, op=F, args=[X]},
body=#c_apply{anno=Anno, op=Loop, args=[Xs]}}},
- C2 = #c_clause{pats=[#c_literal{val=[]}],
+ C2 = #c_clause{anno=Anno, pats=[#c_literal{val=[]}],
guard=#c_call{module=#c_literal{val=erlang},
name=#c_literal{val=is_function},
args=[F, #c_literal{val=1}]},
body=#c_literal{val=ok}},
Err = #c_tuple{es=[#c_literal{val='function_clause'}, F, Xs]},
- C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
+ C3 = #c_clause{anno=Anno, pats=[Xs], guard=#c_literal{val=true},
body=match_fail([{function_name,{'lists^foreach',1}}|Anno], Err)},
Fun = #c_fun{vars=[Xs],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
@@ -117,7 +128,8 @@ call(#c_call{anno=Anno}, lists, map, [Arg1,Arg2]) ->
Xs = #c_var{name='Xs'},
X = #c_var{name='X'},
H = #c_var{name='H'},
- C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
+ C1 = #c_clause{anno=Anno,
+ pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
body=#c_let{vars=[H], arg=#c_apply{anno=Anno,
op=F,
args=[X]},
@@ -126,7 +138,7 @@ call(#c_call{anno=Anno}, lists, map, [Arg1,Arg2]) ->
tl=#c_apply{anno=Anno,
op=Loop,
args=[Xs]}}}},
- C2 = #c_clause{pats=[#c_literal{val=[]}],
+ C2 = #c_clause{anno=Anno, pats=[#c_literal{val=[]}],
guard=#c_call{module=#c_literal{val=erlang},
name=#c_literal{val=is_function},
args=[F, #c_literal{val=1}]},
@@ -146,7 +158,8 @@ call(#c_call{anno=Anno}, lists, flatmap, [Arg1,Arg2]) ->
Xs = #c_var{name='Xs'},
X = #c_var{name='X'},
H = #c_var{name='H'},
- C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
+ C1 = #c_clause{anno=Anno,
+ pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
body=#c_let{vars=[H],
arg=#c_apply{anno=Anno, op=F, args=[X]},
body=#c_call{anno=[compiler_generated|Anno],
@@ -156,13 +169,13 @@ call(#c_call{anno=Anno}, lists, flatmap, [Arg1,Arg2]) ->
#c_apply{anno=Anno,
op=Loop,
args=[Xs]}]}}},
- C2 = #c_clause{pats=[#c_literal{val=[]}],
+ C2 = #c_clause{anno=Anno, pats=[#c_literal{val=[]}],
guard=#c_call{module=#c_literal{val=erlang},
name=#c_literal{val=is_function},
args=[F, #c_literal{val=1}]},
body=#c_literal{val=[]}},
Err = #c_tuple{es=[#c_literal{val='function_clause'}, F, Xs]},
- C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
+ C3 = #c_clause{anno=Anno, pats=[Xs], guard=#c_literal{val=true},
body=match_fail([{function_name,{'lists^flatmap',1}}|Anno], Err)},
Fun = #c_fun{vars=[Xs],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
@@ -177,11 +190,13 @@ call(#c_call{anno=Anno}, lists, filter, [Arg1,Arg2]) ->
X = #c_var{name='X'},
B = #c_var{name='B'},
Err1 = #c_tuple{es=[#c_literal{val='case_clause'}, X]},
- CC1 = #c_clause{pats=[#c_literal{val=true}], guard=#c_literal{val=true},
+ CC1 = #c_clause{anno=Anno,
+ pats=[#c_literal{val=true}], guard=#c_literal{val=true},
body=#c_cons{anno=[compiler_generated], hd=X, tl=Xs}},
- CC2 = #c_clause{pats=[#c_literal{val=false}], guard=#c_literal{val=true},
+ CC2 = #c_clause{anno=Anno,
+ pats=[#c_literal{val=false}], guard=#c_literal{val=true},
body=Xs},
- CC3 = #c_clause{pats=[X], guard=#c_literal{val=true},
+ CC3 = #c_clause{anno=Anno, pats=[X], guard=#c_literal{val=true},
body=match_fail(Anno, Err1)},
Case = #c_case{arg=B, clauses = [CC1, CC2, CC3]},
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
@@ -192,13 +207,15 @@ call(#c_call{anno=Anno}, lists, filter, [Arg1,Arg2]) ->
op=Loop,
args=[Xs]},
body=Case}}},
- C2 = #c_clause{pats=[#c_literal{val=[]}],
+ C2 = #c_clause{anno=Anno,
+ pats=[#c_literal{val=[]}],
guard=#c_call{module=#c_literal{val=erlang},
name=#c_literal{val=is_function},
args=[F, #c_literal{val=1}]},
body=#c_literal{val=[]}},
Err2 = #c_tuple{es=[#c_literal{val='function_clause'}, F, Xs]},
- C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
+ C3 = #c_clause{anno=Anno,
+ pats=[Xs], guard=#c_literal{val=true},
body=match_fail([{function_name,{'lists^filter',1}}|Anno], Err2)},
Fun = #c_fun{vars=[Xs],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
@@ -212,19 +229,20 @@ call(#c_call{anno=Anno}, lists, foldl, [Arg1,Arg2,Arg3]) ->
Xs = #c_var{name='Xs'},
X = #c_var{name='X'},
A = #c_var{name='A'},
- C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
+ C1 = #c_clause{anno=Anno,
+ pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
body=#c_apply{anno=Anno,
op=Loop,
args=[Xs, #c_apply{anno=Anno,
op=F,
args=[X, A]}]}},
- C2 = #c_clause{pats=[#c_literal{val=[]}],
+ C2 = #c_clause{anno=Anno, pats=[#c_literal{val=[]}],
guard=#c_call{module=#c_literal{val=erlang},
name=#c_literal{val=is_function},
args=[F, #c_literal{val=2}]},
body=A},
Err = #c_tuple{es=[#c_literal{val='function_clause'}, F, A, Xs]},
- C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
+ C3 = #c_clause{anno=Anno, pats=[Xs], guard=#c_literal{val=true},
body=match_fail([{function_name,{'lists^foldl',2}}|Anno], Err)},
Fun = #c_fun{vars=[Xs, A],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
@@ -238,19 +256,20 @@ call(#c_call{anno=Anno}, lists, foldr, [Arg1,Arg2,Arg3]) ->
Xs = #c_var{name='Xs'},
X = #c_var{name='X'},
A = #c_var{name='A'},
- C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
+ C1 = #c_clause{anno=Anno,
+ pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
body=#c_apply{anno=Anno,
op=F,
args=[X, #c_apply{anno=Anno,
op=Loop,
args=[Xs, A]}]}},
- C2 = #c_clause{pats=[#c_literal{val=[]}],
+ C2 = #c_clause{anno=Anno, pats=[#c_literal{val=[]}],
guard=#c_call{module=#c_literal{val=erlang},
name=#c_literal{val=is_function},
args=[F, #c_literal{val=2}]},
body=A},
Err = #c_tuple{es=[#c_literal{val='function_clause'}, F, A, Xs]},
- C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
+ C3 = #c_clause{anno=Anno, pats=[Xs], guard=#c_literal{val=true},
body=match_fail([{function_name,{'lists^foldr',2}}|Anno], Err)},
Fun = #c_fun{vars=[Xs, A],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
@@ -266,13 +285,14 @@ call(#c_call{anno=Anno}, lists, mapfoldl, [Arg1,Arg2,Arg3]) ->
Avar = #c_var{name='A'},
Match =
fun (A, P, E) ->
- C1 = #c_clause{pats=[P], guard=#c_literal{val=true}, body=E},
+ C1 = #c_clause{anno=Anno, pats=[P], guard=#c_literal{val=true}, body=E},
Err = #c_tuple{es=[#c_literal{val='badmatch'}, X]},
- C2 = #c_clause{pats=[X], guard=#c_literal{val=true},
+ C2 = #c_clause{anno=Anno, pats=[X], guard=#c_literal{val=true},
body=match_fail(Anno, Err)},
#c_case{arg=A, clauses=[C1, C2]}
end,
- C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
+ C1 = #c_clause{anno=Anno,
+ pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
body=Match(#c_apply{anno=Anno, op=F, args=[X, Avar]},
#c_tuple{es=[X, Avar]},
%%% Tuple passing version
@@ -292,7 +312,7 @@ call(#c_call{anno=Anno}, lists, mapfoldl, [Arg1,Arg2,Arg3]) ->
%%% body=#c_values{es=[#c_cons{hd=X, tl=Xs},
%%% A]}}
)},
- C2 = #c_clause{pats=[#c_literal{val=[]}],
+ C2 = #c_clause{anno=Anno, pats=[#c_literal{val=[]}],
guard=#c_call{module=#c_literal{val=erlang},
name=#c_literal{val=is_function},
args=[F, #c_literal{val=2}]},
@@ -302,7 +322,7 @@ call(#c_call{anno=Anno}, lists, mapfoldl, [Arg1,Arg2,Arg3]) ->
%%% Multiple-value version
%%% body=#c_values{es=[#c_literal{val=[]}, A]}},
Err = #c_tuple{es=[#c_literal{val='function_clause'}, F, Avar, Xs]},
- C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
+ C3 = #c_clause{anno=Anno, pats=[Xs], guard=#c_literal{val=true},
body=match_fail([{function_name,{'lists^mapfoldl',2}}|Anno], Err)},
Fun = #c_fun{vars=[Xs, Avar],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
@@ -326,13 +346,13 @@ call(#c_call{anno=Anno}, lists, mapfoldr, [Arg1,Arg2,Arg3]) ->
Avar = #c_var{name='A'},
Match =
fun (A, P, E) ->
- C1 = #c_clause{pats=[P], guard=#c_literal{val=true}, body=E},
+ C1 = #c_clause{anno=Anno, pats=[P], guard=#c_literal{val=true}, body=E},
Err = #c_tuple{es=[#c_literal{val='badmatch'}, X]},
- C2 = #c_clause{pats=[X], guard=#c_literal{val=true},
+ C2 = #c_clause{anno=Anno, pats=[X], guard=#c_literal{val=true},
body=match_fail(Anno, Err)},
#c_case{arg=A, clauses=[C1, C2]}
end,
- C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
+ C1 = #c_clause{anno=Anno, pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
%%% Tuple passing version
body=Match(#c_apply{anno=Anno,
op=Loop,
@@ -352,7 +372,8 @@ call(#c_call{anno=Anno}, lists, mapfoldr, [Arg1,Arg2,Arg3]) ->
%%% #c_values{es=[#c_cons{hd=X, tl=Xs},
%%% A]})}
},
- C2 = #c_clause{pats=[#c_literal{val=[]}],
+ C2 = #c_clause{anno=Anno,
+ pats=[#c_literal{val=[]}],
guard=#c_call{module=#c_literal{val=erlang},
name=#c_literal{val=is_function},
args=[F, #c_literal{val=2}]},
@@ -362,7 +383,7 @@ call(#c_call{anno=Anno}, lists, mapfoldr, [Arg1,Arg2,Arg3]) ->
%%% Multiple-value version
%%% body=#c_values{es=[#c_literal{val=[]}, A]}},
Err = #c_tuple{es=[#c_literal{val='function_clause'}, F, Avar, Xs]},
- C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
+ C3 = #c_clause{anno=Anno, pats=[Xs], guard=#c_literal{val=true},
body=match_fail([{function_name,{'lists^mapfoldr',2}}|Anno], Err)},
Fun = #c_fun{vars=[Xs, Avar],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
diff --git a/lib/compiler/src/sys_core_inline.erl b/lib/compiler/src/sys_core_inline.erl
index 8c1f69d5de..3380e3f1bd 100644
--- a/lib/compiler/src/sys_core_inline.erl
+++ b/lib/compiler/src/sys_core_inline.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -143,7 +143,7 @@ inline_inline(#ifun{body=B,weight=Iw}=If, Is) ->
case find_inl(F, A, Is) of
#ifun{vars=Vs,body=B2,weight=W} when W < Iw ->
#c_let{vars=Vs,
- arg=core_lib:make_values(As),
+ arg=kill_id_anns(core_lib:make_values(As)),
body=kill_id_anns(B2)};
_Other -> Call
end;
@@ -160,7 +160,7 @@ inline_func(#fstat{def={Name,F0}}=Fstat, Is) ->
case find_inl(F, A, Is) of
#ifun{vars=Vs,body=B} ->
{#c_let{vars=Vs,
- arg=core_lib:make_values(As),
+ arg=kill_id_anns(core_lib:make_values(As)),
body=kill_id_anns(B)},
true}; %Have modified
_Other -> {Call,Mod}
@@ -195,6 +195,9 @@ kill_id_anns(Body) ->
cerl_trees:map(fun(#c_fun{anno=A0}=CFun) ->
A = kill_id_anns_1(A0),
CFun#c_fun{anno=A};
+ (#c_var{anno=A0}=Var) ->
+ A = kill_id_anns_1(A0),
+ Var#c_var{anno=A};
(Expr) ->
%% Mark everything as compiler generated to
%% suppress bogus warnings.
diff --git a/lib/compiler/src/v3_codegen.erl b/lib/compiler/src/v3_codegen.erl
deleted file mode 100644
index 47c1567f10..0000000000
--- a/lib/compiler/src/v3_codegen.erl
+++ /dev/null
@@ -1,2298 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%% Purpose : Code generator for Beam.
-
-%% The following assumptions have been made:
-%%
-%% 1. Matches, i.e. things with {match,M,Ret} wrappers, only return
-%% values; no variables are exported. If the match would have returned
-%% extra variables then these have been transformed to multiple return
-%% values.
-%%
-%% 2. All BIF's called in guards are gc-safe so there is no need to
-%% put thing on the stack in the guard. While this would in principle
-%% work it would be difficult to keep track of the stack depth when
-%% trimming.
-%%
-%% The code generation uses variable lifetime information added by
-%% the v3_life module to save variables, allocate registers and
-%% move registers to the stack when necessary.
-%%
-%% We try to use a consistent variable name scheme throughout. The
-%% StackReg record is always called Bef,Int<n>,Aft.
-
--module(v3_codegen).
-
-%% The main interface.
--export([module/2]).
-
--import(lists, [member/2,keymember/3,keysort/2,keydelete/3,
- append/1,flatmap/2,filter/2,foldl/3,foldr/3,mapfoldl/3,
- sort/1,reverse/1,reverse/2]).
--import(v3_life, [vdb_find/2]).
-
-%%-compile([export_all]).
-
--include("v3_life.hrl").
-
-%% Main codegen structure.
--record(cg, {lcount=1, %Label counter
- bfail, %Fail label for BIFs
- break, %Break label
- recv, %Receive label
- is_top_block, %Boolean: top block or not
- functable=#{}, %Map of local functions: {Name,Arity}=>Label
- in_catch=false, %Inside a catch or not.
- need_frame, %Need a stack frame.
- ultimate_failure %Label for ultimate match failure.
- }).
-
-%% Stack/register state record.
--record(sr, {reg=[], %Register table
- stk=[], %Stack table
- res=[]}). %Reserved regs: [{reserved,I,V}]
-
--type life_module() :: {module(),_,_,[_]}.
-
--spec module(life_module(), [compile:option()]) -> {'ok',beam_asm:module_code()}.
-
-module({Mod,Exp,Attr,Forms}, _Options) ->
- {Fs,St} = functions(Forms, {atom,Mod}),
- {ok,{Mod,Exp,Attr,Fs,St#cg.lcount}}.
-
-functions(Forms, AtomMod) ->
- mapfoldl(fun (F, St) -> function(F, AtomMod, St) end, #cg{lcount=1}, Forms).
-
-function({function,Name,Arity,Asm0,Vb,Vdb,Anno}, AtomMod, St0) ->
- try
- {Asm,EntryLabel,St} = cg_fun(Vb, Asm0, Vdb, AtomMod,
- {Name,Arity}, Anno, St0),
- Func = {function,Name,Arity,EntryLabel,Asm},
- {Func,St}
- catch
- Class:Error ->
- Stack = erlang:get_stacktrace(),
- io:fwrite("Function: ~w/~w\n", [Name,Arity]),
- erlang:raise(Class, Error, Stack)
- end.
-
-%% cg_fun([Lkexpr], [HeadVar], Vdb, State) -> {[Ainstr],State}
-
-cg_fun(Les, Hvs, Vdb, AtomMod, NameArity, Anno, St0) ->
- {Fi,St1} = new_label(St0), %FuncInfo label
- {Fl,St2} = local_func_label(NameArity, St1),
-
- %%
- %% The pattern matching compiler (in v3_kernel) no longer
- %% provides its own catch-all clause, because the
- %% call to erlang:exit/1 caused problem when cases were
- %% used in guards. Therefore, there may be tests that
- %% cannot fail (providing that there is not a bug in a
- %% previous optimzation pass), but still need to provide
- %% a label (there are instructions, such as is_tuple/2,
- %% that do not allow {f,0}).
- %%
- %% We will generate an ultimate failure label and put it
- %% at the end of function, followed by an 'if_end' instruction.
- %% Note that and 'if_end' instruction does not need any
- %% live x registers, so it will always be safe to jump to
- %% it. (We never ever expect the jump to be taken, and in
- %% must functions there will never be any references to
- %% the label in the first place.)
- %%
-
- {UltimateMatchFail,St3} = new_label(St2),
-
- %% Create initial stack/register state, clear unused arguments.
- Bef = clear_dead(#sr{reg=foldl(fun ({var,V}, Reg) ->
- put_reg(V, Reg)
- end, [], Hvs),
- stk=[]}, 0, Vdb),
- {B,_Aft,St} = cg_list(Les, 0, Vdb, Bef,
- St3#cg{bfail=0,
- ultimate_failure=UltimateMatchFail,
- is_top_block=true}),
- {Name,Arity} = NameArity,
- Asm = [{label,Fi},line(Anno),{func_info,AtomMod,{atom,Name},Arity},
- {label,Fl}|B++[{label,UltimateMatchFail},if_end]],
- {Asm,Fl,St}.
-
-%% cg(Lkexpr, Vdb, StackReg, State) -> {[Ainstr],StackReg,State}.
-%% Generate code for a kexpr.
-%% Split function into two steps for clarity, not efficiency.
-
-cg(Le, Vdb, Bef, St) ->
- cg(Le#l.ke, Le, Vdb, Bef, St).
-
-cg({block,Es}, Le, Vdb, Bef, St) ->
- block_cg(Es, Le, Vdb, Bef, St);
-cg({match,M,Rs}, Le, Vdb, Bef, St) ->
- match_cg(M, Rs, Le, Vdb, Bef, St);
-cg({guard_match,M,Rs}, Le, Vdb, Bef, St) ->
- guard_match_cg(M, Rs, Le, Vdb, Bef, St);
-cg({call,Func,As,Rs}, Le, Vdb, Bef, St) ->
- call_cg(Func, As, Rs, Le, Vdb, Bef, St);
-cg({enter,Func,As}, Le, Vdb, Bef, St) ->
- enter_cg(Func, As, Le, Vdb, Bef, St);
-cg({bif,Bif,As,Rs}, Le, Vdb, Bef, St) ->
- bif_cg(Bif, As, Rs, Le, Vdb, Bef, St);
-cg({gc_bif,Bif,As,Rs}, Le, Vdb, Bef, St) ->
- gc_bif_cg(Bif, As, Rs, Le, Vdb, Bef, St);
-cg({internal,Bif,As,Rs}, Le, Vdb, Bef, St) ->
- internal_cg(Bif, As, Rs, Le, Vdb, Bef, St);
-cg({receive_loop,Te,Rvar,Rm,Tes,Rs}, Le, Vdb, Bef, St) ->
- recv_loop_cg(Te, Rvar, Rm, Tes, Rs, Le, Vdb, Bef, St);
-cg(receive_next, Le, Vdb, Bef, St) ->
- recv_next_cg(Le, Vdb, Bef, St);
-cg(receive_accept, _Le, _Vdb, Bef, St) -> {[remove_message],Bef,St};
-cg({'try',Ta,Vs,Tb,Evs,Th,Rs}, Le, Vdb, Bef, St) ->
- try_cg(Ta, Vs, Tb, Evs, Th, Rs, Le, Vdb, Bef, St);
-cg({try_enter,Ta,Vs,Tb,Evs,Th}, Le, Vdb, Bef, St) ->
- try_enter_cg(Ta, Vs, Tb, Evs, Th, Le, Vdb, Bef, St);
-cg({'catch',Cb,R}, Le, Vdb, Bef, St) ->
- catch_cg(Cb, R, Le, Vdb, Bef, St);
-cg({set,Var,Con}, Le, Vdb, Bef, St) ->
- set_cg(Var, Con, Le, Vdb, Bef, St);
-cg({return,Rs}, Le, Vdb, Bef, St) -> return_cg(Rs, Le, Vdb, Bef, St);
-cg({break,Bs}, Le, Vdb, Bef, St) -> break_cg(Bs, Le, Vdb, Bef, St);
-cg({guard_break,Bs,N}, Le, Vdb, Bef, St) ->
- guard_break_cg(Bs, N, Le, Vdb, Bef, St);
-cg({need_heap,H}, _Le, _Vdb, Bef, St) ->
- {[{test_heap,H,max_reg(Bef#sr.reg)}],Bef,St}.
-
-%% cg_list([Kexpr], FirstI, Vdb, StackReg, St) -> {[Ainstr],StackReg,St}.
-
-cg_list(Kes, I, Vdb, Bef, St0) ->
- {Keis,{Aft,St1}} =
- flatmapfoldl(fun (Ke, {Inta,Sta}) ->
- {Keis,Intb,Stb} = cg(Ke, Vdb, Inta, Sta),
- {Keis,{Intb,Stb}}
- end, {Bef,St0}, need_heap(Kes, I)),
- {Keis,Aft,St1}.
-
-%% need_heap([Lkexpr], I, St) -> [Lkexpr].
-%% Insert need_heap instructions in Kexpr list. Try to be smart and
-%% collect them together as much as possible.
-
-need_heap(Kes0, I) ->
- {Kes,H} = need_heap_0(reverse(Kes0), 0, []),
-
- %% Prepend need_heap if necessary.
- need_heap_need(I, H) ++ Kes.
-
-need_heap_0([Ke|Kes], H0, Acc) ->
- {Ns,H} = need_heap_1(Ke, H0),
- need_heap_0(Kes, H, [Ke|Ns]++Acc);
-need_heap_0([], H, Acc) ->
- {Acc,H}.
-
-need_heap_1(#l{ke={set,_,{binary,_}},i=I}, H) ->
- {need_heap_need(I, H),0};
-need_heap_1(#l{ke={set,_,{map,_,_,_}},i=I}, H) ->
- {need_heap_need(I, H),0};
-need_heap_1(#l{ke={set,_,Val}}, H) ->
- %% Just pass through adding to needed heap.
- {[],H + case Val of
- {cons,_} -> 2;
- {tuple,Es} -> 1 + length(Es);
- _Other -> 0
- end};
-need_heap_1(#l{ke={bif,_Bif,_As,_Rs}}, H) ->
- {[],H};
-need_heap_1(#l{i=I}, H) ->
- %% Call or call-like instruction such as set_tuple_element/3.
- {need_heap_need(I, H),0}.
-
-need_heap_need(_I, 0) -> [];
-need_heap_need(I, H) -> [#l{ke={need_heap,H},i=I}].
-
-%% match_cg(Match, [Ret], Le, Vdb, StackReg, State) ->
-%% {[Ainstr],StackReg,State}.
-%% Generate code for a match. First save all variables on the stack
-%% that are to survive after the match. We leave saved variables in
-%% their registers as they might actually be in the right place.
-
-match_cg(M, Rs, Le, Vdb, Bef, St0) ->
- I = Le#l.i,
- {Sis,Int0} = adjust_stack(Bef, I, I+1, Vdb),
- {B,St1} = new_label(St0),
- {Mis,Int1,St2} = match_cg(M, St1#cg.ultimate_failure,
- Int0, St1#cg{break=B}),
- %% Put return values in registers.
- Reg = load_vars(Rs, Int1#sr.reg),
- {Sis ++ Mis ++ [{label,B}],
- clear_dead(Int1#sr{reg=Reg}, I, Vdb),
- St2#cg{break=St1#cg.break}}.
-
-guard_match_cg(M, Rs, Le, Vdb, Bef, St0) ->
- I = Le#l.i,
- {B,St1} = new_label(St0),
- #cg{bfail=Fail} = St1,
- {Mis,Aft,St2} = match_cg(M, Fail, Bef, St1#cg{break=B}),
- %% Update the register descriptors for the return registers.
- Reg = guard_match_regs(Aft#sr.reg, Rs),
- {Mis ++ [{label,B}],
- clear_dead(Aft#sr{reg=Reg}, I, Vdb),
- St2#cg{break=St1#cg.break}}.
-
-guard_match_regs([{I,gbreakvar}|Rs], [{var,V}|Vs]) ->
- [{I,V}|guard_match_regs(Rs, Vs)];
-guard_match_regs([R|Rs], Vs) ->
- [R|guard_match_regs(Rs, Vs)];
-guard_match_regs([], []) -> [].
-
-
-%% match_cg(Match, Fail, StackReg, State) -> {[Ainstr],StackReg,State}.
-%% Generate code for a match tree. N.B. there is no need pass Vdb
-%% down as each level which uses this takes its own internal Vdb not
-%% the outer one.
-
-match_cg(Le, Fail, Bef, St) ->
- match_cg(Le#l.ke, Le, Fail, Bef, St).
-
-match_cg({alt,F,S}, _Le, Fail, Bef, St0) ->
- {Tf,St1} = new_label(St0),
- {Fis,Faft,St2} = match_cg(F, Tf, Bef, St1),
- {Sis,Saft,St3} = match_cg(S, Fail, Bef, St2),
- Aft = sr_merge(Faft, Saft),
- {Fis ++ [{label,Tf}] ++ Sis,Aft,St3};
-match_cg({select,{var,Vname}=V,Scs0}, #l{a=Anno}, Fail, Bef, St) ->
- ReuseForContext = member(reuse_for_context, Anno) andalso
- find_reg(Vname, Bef#sr.reg) =/= error,
- Scs = case ReuseForContext of
- false -> Scs0;
- true -> bsm_rename_ctx(Scs0, Vname)
- end,
- match_fmf(fun (S, F, Sta) ->
- select_cg(S, V, F, Fail, Bef, Sta) end,
- Fail, St, Scs);
-match_cg({guard,Gcs}, _Le, Fail, Bef, St) ->
- match_fmf(fun (G, F, Sta) -> guard_clause_cg(G, F, Bef, Sta) end,
- Fail, St, Gcs);
-match_cg({block,Es}, Le, _Fail, Bef, St) ->
- %% Must clear registers and stack of dead variables.
- Int = clear_dead(Bef, Le#l.i, Le#l.vdb),
- block_cg(Es, Le, Int, St).
-
-%% bsm_rename_ctx([Clause], Var) -> [Clause]
-%% We know from an annotation that the register for a binary can
-%% be reused for the match context because the two are not truly
-%% alive at the same time (even though the conservative life time
-%% information calculated by v3_life says so).
-%%
-%% The easiest way to have those variables share the same register is
-%% to rename the variable with the shortest life-span (the match
-%% context) to the variable for the binary (which can have a very
-%% long life-time because it is locked during matching). We KNOW that
-%% the match state variable will only be alive during the matching.
-%%
-%% We must also remove all information about the match context
-%% variable from all life-time information databases (Vdb).
-
-bsm_rename_ctx([#l{ke={type_clause,binary,
- [#l{ke={val_clause,{binary,{var,Old}},Ke0}}=L2]}}=L1|Cs], New) ->
- Ke = bsm_rename_ctx(Ke0, Old, New, false),
- [L1#l{ke={type_clause,binary,
- [L2#l{ke={val_clause,{binary,{var,New}},Ke}}]}}|bsm_rename_ctx(Cs, New)];
-bsm_rename_ctx([C|Cs], New) ->
- [C|bsm_rename_ctx(Cs, New)];
-bsm_rename_ctx([], _) -> [].
-
-%% bsm_rename_ctx(Ke, OldName, NewName, InProt) -> Ke'
-%% Rename and clear OldName from life-time information. We must
-%% recurse into any block contained in a protected, but it would
-%% only complicatate things to recurse into blocks not in a protected
-%% (the match context variable is not live inside them).
-
-bsm_rename_ctx(#l{ke={select,{var,V},Cs0}}=L, Old, New, InProt) ->
- Cs = bsm_rename_ctx_list(Cs0, Old, New, InProt),
- L#l{ke={select,{var,bsm_rename_var(V, Old, New)},Cs}};
-bsm_rename_ctx(#l{ke={type_clause,Type,Cs0}}=L, Old, New, InProt) ->
- Cs = bsm_rename_ctx_list(Cs0, Old, New, InProt),
- L#l{ke={type_clause,Type,Cs}};
-bsm_rename_ctx(#l{ke={val_clause,{bin_end,V},Ke0}}=L, Old, New, InProt) ->
- Ke = bsm_rename_ctx(Ke0, Old, New, InProt),
- L#l{ke={val_clause,{bin_end,bsm_rename_var(V, Old, New)},Ke}};
-bsm_rename_ctx(#l{ke={val_clause,{bin_seg,V,Sz,U,Type,Fl,Vs},Ke0}}=L,
- Old, New, InProt) ->
- Ke = bsm_rename_ctx(Ke0, Old, New, InProt),
- L#l{ke={val_clause,{bin_seg,bsm_rename_var(V, Old, New),Sz,U,Type,Fl,Vs},Ke}};
-bsm_rename_ctx(#l{ke={val_clause,{bin_int,V,Sz,U,Fl,Val,Vs},Ke0}}=L,
- Old, New, InProt) ->
- Ke = bsm_rename_ctx(Ke0, Old, New, InProt),
- L#l{ke={val_clause,{bin_int,bsm_rename_var(V, Old, New),Sz,U,Fl,Val,Vs},Ke}};
-bsm_rename_ctx(#l{ke={val_clause,Val,Ke0}}=L, Old, New, InProt) ->
- Ke = bsm_rename_ctx(Ke0, Old, New, InProt),
- L#l{ke={val_clause,Val,Ke}};
-bsm_rename_ctx(#l{ke={alt,F0,S0}}=L, Old, New, InProt) ->
- F = bsm_rename_ctx(F0, Old, New, InProt),
- S = bsm_rename_ctx(S0, Old, New, InProt),
- L#l{ke={alt,F,S}};
-bsm_rename_ctx(#l{ke={guard,Gcs0}}=L, Old, New, InProt) ->
- Gcs = bsm_rename_ctx_list(Gcs0, Old, New, InProt),
- L#l{ke={guard,Gcs}};
-bsm_rename_ctx(#l{ke={guard_clause,G0,B0}}=L, Old, New, InProt) ->
- G = bsm_rename_ctx(G0, Old, New, InProt),
- B = bsm_rename_ctx(B0, Old, New, InProt),
- %% A guard clause may cause unsaved variables to be saved on the stack.
- %% Since the match state variable Old is an alias for New (uses the
- %% same register), it is neither in the stack nor register descriptor
- %% lists and we would crash when we didn't find it unless we remove
- %% it from the database.
- bsm_forget_var(L#l{ke={guard_clause,G,B}}, Old);
-bsm_rename_ctx(#l{ke={protected,Ts0,Rs}}=L, Old, New, _InProt) ->
- InProt = true,
- Ts = bsm_rename_ctx_list(Ts0, Old, New, InProt),
- bsm_forget_var(L#l{ke={protected,Ts,Rs}}, Old);
-bsm_rename_ctx(#l{ke={match,Ms0,Rs}}=L, Old, New, InProt) ->
- Ms = bsm_rename_ctx(Ms0, Old, New, InProt),
- L#l{ke={match,Ms,Rs}};
-bsm_rename_ctx(#l{ke={guard_match,Ms0,Rs}}=L, Old, New, InProt) ->
- Ms = bsm_rename_ctx(Ms0, Old, New, InProt),
- L#l{ke={guard_match,Ms,Rs}};
-bsm_rename_ctx(#l{ke={test,_,_,_}}=L, _, _, _) -> L;
-bsm_rename_ctx(#l{ke={bif,_,_,_}}=L, _, _, _) -> L;
-bsm_rename_ctx(#l{ke={gc_bif,_,_,_}}=L, _, _, _) -> L;
-bsm_rename_ctx(#l{ke={set,_,_}}=L, _, _, _) -> L;
-bsm_rename_ctx(#l{ke={call,_,_,_}}=L, _, _, _) -> L;
-bsm_rename_ctx(#l{ke={block,_}}=L, Old, _, false) ->
- %% This block is not inside a protected. The match context variable cannot
- %% possibly be live inside the block.
- bsm_forget_var(L, Old);
-bsm_rename_ctx(#l{ke={block,Bl0}}=L, Old, New, true) ->
- %% A block in a protected. We must recursively rename the variable
- %% inside the block.
- Bl = bsm_rename_ctx_list(Bl0, Old, New, true),
- bsm_forget_var(L#l{ke={block,Bl}}, Old);
-bsm_rename_ctx(#l{ke={guard_break,Bs,Locked0}}=L0, Old, _New, _InProt) ->
- Locked = Locked0 -- [Old],
- L = L0#l{ke={guard_break,Bs,Locked}},
- bsm_forget_var(L, Old).
-
-bsm_rename_ctx_list([C|Cs], Old, New, InProt) ->
- [bsm_rename_ctx(C, Old, New, InProt)|
- bsm_rename_ctx_list(Cs, Old, New, InProt)];
-bsm_rename_ctx_list([], _, _, _) -> [].
-
-bsm_rename_var(Old, Old, New) -> New;
-bsm_rename_var(V, _, _) -> V.
-
-%% bsm_forget_var(#l{}, Variable) -> #l{}
-%% Remove a variable from the variable life-time database.
-
-bsm_forget_var(#l{vdb=Vdb}=L, V) ->
- L#l{vdb=keydelete(V, 1, Vdb)}.
-
-%% block_cg([Kexpr], Le, Vdb, StackReg, St) -> {[Ainstr],StackReg,St}.
-%% block_cg([Kexpr], Le, StackReg, St) -> {[Ainstr],StackReg,St}.
-
-block_cg(Es, Le, _Vdb, Bef, St) ->
- block_cg(Es, Le, Bef, St).
-
-block_cg(Es, Le, Bef, #cg{is_top_block=false}=St) ->
- cg_block(Es, Le#l.i, Le#l.vdb, Bef, St);
-block_cg(Es, Le, Bef, St0) ->
- {Is0,Aft,St} = cg_block(Es, Le#l.i, Le#l.vdb, Bef,
- St0#cg{is_top_block=false,need_frame=false}),
- Is = top_level_block(Is0, Aft, max_reg(Bef#sr.reg), St),
- {Is,Aft,St#cg{is_top_block=true}}.
-
-cg_block([], _I, _Vdb, Bef, St0) ->
- {[],Bef,St0};
-cg_block(Kes0, I, Vdb, Bef, St0) ->
- {Kes2,Int1,St1} =
- case basic_block(Kes0) of
- {Kes1,LastI,Args,Rest} ->
- Ke = hd(Kes1),
- Fb = Ke#l.i,
- cg_basic_block(Kes1, Fb, LastI, Args, Vdb, Bef, St0);
- {Kes1,Rest} ->
- cg_list(Kes1, I, Vdb, Bef, St0)
- end,
- {Kes3,Int2,St2} = cg_block(Rest, I, Vdb, Int1, St1),
- {Kes2 ++ Kes3,Int2,St2}.
-
-basic_block(Kes) -> basic_block(Kes, []).
-
-basic_block([Le|Les], Acc) ->
- case collect_block(Le#l.ke) of
- include -> basic_block(Les, [Le|Acc]);
- {block_end,As} ->
- case Acc of
- [] ->
- %% If the basic block does not contain any set instructions,
- %% it serves no useful purpose to do basic block optimizations.
- {[Le],Les};
- _ ->
- {reverse(Acc, [Le]),Le#l.i,As,Les}
- end;
- no_block -> {reverse(Acc, [Le]),Les}
- end.
-
-%% sets that may garbage collect are not allowed in basic blocks.
-
-collect_block({set,_,{binary,_}}) -> no_block;
-collect_block({set,_,{map,_,_,_}}) -> no_block;
-collect_block({set,_,_}) -> include;
-collect_block({call,{var,_}=Var,As,_Rs}) -> {block_end,As++[Var]};
-collect_block({call,Func,As,_Rs}) -> {block_end,As++func_vars(Func)};
-collect_block({enter,{var,_}=Var,As})-> {block_end,As++[Var]};
-collect_block({enter,Func,As}) -> {block_end,As++func_vars(Func)};
-collect_block({return,Rs}) -> {block_end,Rs};
-collect_block({break,Bs}) -> {block_end,Bs};
-collect_block(_) -> no_block.
-
-func_vars({remote,M,F}) when element(1, M) =:= var;
- element(1, F) =:= var ->
- [M,F];
-func_vars(_) -> [].
-
-%% cg_basic_block([Kexpr], FirstI, LastI, As, Vdb, StackReg, State) ->
-%% {[Ainstr],StackReg,State}.
-
-cg_basic_block(Kes, Fb, Lf, As, Vdb, Bef, St0) ->
- Res = make_reservation(As, 0),
- Regs0 = reserve(Res, Bef#sr.reg, Bef#sr.stk),
- Stk = extend_stack(Bef, Lf, Lf+1, Vdb),
- Int0 = Bef#sr{reg=Regs0,stk=Stk,res=Res},
- X0_v0 = x0_vars(As, Fb, Lf, Vdb),
- {Keis,{Aft,_,St1}} =
- flatmapfoldl(fun(Ke, St) -> cg_basic_block(Ke, St, Lf, Vdb) end,
- {Int0,X0_v0,St0}, need_heap(Kes, Fb)),
- {Keis,Aft,St1}.
-
-cg_basic_block(#l{ke={need_heap,_}}=Ke, {Inta,X0v,Sta}, _Lf, Vdb) ->
- {Keis,Intb,Stb} = cg(Ke, Vdb, Inta, Sta),
- {Keis, {Intb,X0v,Stb}};
-cg_basic_block(Ke, {Inta,X0_v1,Sta}, Lf, Vdb) ->
- {Sis,Intb} = save_carefully(Inta, Ke#l.i, Lf+1, Vdb),
- {X0_v2,Intc} = allocate_x0(X0_v1, Ke#l.i, Intb),
- Intd = reserve(Intc),
- {Keis,Inte,Stb} = cg(Ke, Vdb, Intd, Sta),
- {Sis ++ Keis, {Inte,X0_v2,Stb}}.
-
-make_reservation([], _) -> [];
-make_reservation([{var,V}|As], I) -> [{I,V}|make_reservation(As, I+1)];
-make_reservation([A|As], I) -> [{I,A}|make_reservation(As, I+1)].
-
-reserve(Sr) -> Sr#sr{reg=reserve(Sr#sr.res, Sr#sr.reg, Sr#sr.stk)}.
-
-reserve([{I,V}|Rs], [free|Regs], Stk) -> [{reserved,I,V}|reserve(Rs, Regs, Stk)];
-reserve([{I,V}|Rs], [{I,V}|Regs], Stk) -> [{I,V}|reserve(Rs, Regs, Stk)];
-reserve([{I,V}|Rs], [{I,Var}|Regs], Stk) ->
- case on_stack(Var, Stk) of
- true -> [{reserved,I,V}|reserve(Rs, Regs, Stk)];
- false -> [{I,Var}|reserve(Rs, Regs, Stk)]
- end;
-reserve([{I,V}|Rs], [{reserved,I,_}|Regs], Stk) ->
- [{reserved,I,V}|reserve(Rs, Regs, Stk)];
-%reserve([{I,V}|Rs], [Other|Regs], Stk) -> [Other|reserve(Rs, Regs, Stk)];
-reserve([{I,V}|Rs], [], Stk) -> [{reserved,I,V}|reserve(Rs, [], Stk)];
-reserve([], Regs, _) -> Regs.
-
-extend_stack(Bef, Fb, Lf, Vdb) ->
- Stk0 = clear_dead_stk(Bef#sr.stk, Fb, Vdb),
- Saves = [V || {V,F,L} <- Vdb,
- F < Fb,
- L >= Lf,
- not on_stack(V, Stk0)],
- Stk1 = foldl(fun (V, Stk) -> put_stack(V, Stk) end, Stk0, Saves),
- Bef#sr.stk ++ lists:duplicate(length(Stk1) - length(Bef#sr.stk), free).
-
-save_carefully(Bef, Fb, Lf, Vdb) ->
- Stk = Bef#sr.stk,
- %% New variables that are in use but not on stack.
- New = [VFL || {V,F,L} = VFL <- Vdb,
- F < Fb,
- L >= Lf,
- not on_stack(V, Stk)],
- Saves = [V || {V,_,_} <- keysort(2, New)],
- save_carefully(Saves, Bef, []).
-
-save_carefully([], Bef, Acc) -> {reverse(Acc),Bef};
-save_carefully([V|Vs], Bef, Acc) ->
- case put_stack_carefully(V, Bef#sr.stk) of
- error -> {reverse(Acc),Bef};
- Stk1 ->
- SrcReg = fetch_reg(V, Bef#sr.reg),
- Move = {move,SrcReg,fetch_stack(V, Stk1)},
- {x,_} = SrcReg, %Assertion - must be X register.
- save_carefully(Vs, Bef#sr{stk=Stk1}, [Move|Acc])
- end.
-
-x0_vars([], _Fb, _Lf, _Vdb) -> [];
-x0_vars([{var,V}|_], Fb, _Lf, Vdb) ->
- {V,F,_L} = VFL = vdb_find(V, Vdb),
- x0_vars1([VFL], Fb, F, Vdb);
-x0_vars([X0|_], Fb, Lf, Vdb) ->
- x0_vars1([{X0,Lf,Lf}], Fb, Lf, Vdb).
-
-x0_vars1(X0, Fb, Xf, Vdb) ->
- Vs0 = [VFL || {_V,F,L}=VFL <- Vdb,
- F >= Fb,
- L < Xf],
- Vs1 = keysort(3, Vs0),
- keysort(2, X0++Vs1).
-
-allocate_x0([], _, Bef) -> {[],Bef#sr{res=[]}};
-allocate_x0([{_,_,L}|Vs], I, Bef) when L =< I ->
- allocate_x0(Vs, I, Bef);
-allocate_x0([{V,_F,_L}=VFL|Vs], _, Bef) ->
- {[VFL|Vs],Bef#sr{res=reserve_x0(V, Bef#sr.res)}}.
-
-reserve_x0(V, [_|Res]) -> [{0,V}|Res];
-reserve_x0(V, []) -> [{0,V}].
-
-top_level_block(Keis, #sr{stk=[]}, _MaxRegs, #cg{need_frame=false}) ->
- Keis;
-top_level_block(Keis, Bef, MaxRegs, _St) ->
- %% This top block needs an allocate instruction before it, and a
- %% deallocate instruction before each return.
- FrameSz = length(Bef#sr.stk),
- MaxY = FrameSz-1,
- Keis1 = flatmap(fun ({call_only,Arity,Func}) ->
- [{call_last,Arity,Func,FrameSz}];
- ({call_ext_only,Arity,Func}) ->
- [{call_ext_last,Arity,Func,FrameSz}];
- ({apply_only,Arity}) ->
- [{apply_last,Arity,FrameSz}];
- (return) ->
- [{deallocate,FrameSz},return];
- (Tuple) when is_tuple(Tuple) ->
- [turn_yregs(Tuple, MaxY)];
- (Other) ->
- [Other]
- end, Keis),
- [{allocate_zero,FrameSz,MaxRegs}|Keis1].
-
-%% turn_yregs(Size, Tuple, MaxY) -> Tuple'
-%% Renumber y register so that {y,0} becomes {y,FrameSize-1},
-%% {y,FrameSize-1} becomes {y,0} and so on. This is to make nested
-%% catches work. The code generation algorithm gives a lower register
-%% number to the outer catch, which is wrong.
-
-turn_yregs({call,_,_}=I, _MaxY) -> I;
-turn_yregs({call_ext,_,_}=I, _MaxY) -> I;
-turn_yregs({jump,_}=I, _MaxY) -> I;
-turn_yregs({label,_}=I, _MaxY) -> I;
-turn_yregs({line,_}=I, _MaxY) -> I;
-turn_yregs({test_heap,_,_}=I, _MaxY) -> I;
-turn_yregs({bif,Op,F,A,B}, MaxY) ->
- {bif,Op,F,turn_yreg(A, MaxY),turn_yreg(B, MaxY)};
-turn_yregs({gc_bif,Op,F,Live,A,B}, MaxY) when is_integer(Live) ->
- {gc_bif,Op,F,Live,turn_yreg(A, MaxY),turn_yreg(B, MaxY)};
-turn_yregs({get_tuple_element,S,N,D}, MaxY) ->
- {get_tuple_element,turn_yreg(S, MaxY),N,turn_yreg(D, MaxY)};
-turn_yregs({put_tuple,Arity,D}, MaxY) ->
- {put_tuple,Arity,turn_yreg(D, MaxY)};
-turn_yregs({select_val,R,F,L}, MaxY) ->
- {select_val,turn_yreg(R, MaxY),F,L};
-turn_yregs({test,Op,F,L}, MaxY) ->
- {test,Op,F,turn_yreg(L, MaxY)};
-turn_yregs({test,Op,F,Live,A,B}, MaxY) when is_integer(Live) ->
- {test,Op,F,Live,turn_yreg(A, MaxY),turn_yreg(B, MaxY)};
-turn_yregs({Op,A}, MaxY) ->
- {Op,turn_yreg(A, MaxY)};
-turn_yregs({Op,A,B}, MaxY) ->
- {Op,turn_yreg(A, MaxY),turn_yreg(B, MaxY)};
-turn_yregs({Op,A,B,C}, MaxY) ->
- {Op,turn_yreg(A, MaxY),turn_yreg(B, MaxY),turn_yreg(C, MaxY)};
-turn_yregs(Tuple, MaxY) ->
- turn_yregs(tuple_size(Tuple), Tuple, MaxY).
-
-turn_yregs(1, Tp, _) ->
- Tp;
-turn_yregs(N, Tp, MaxY) ->
- E = turn_yreg(element(N, Tp), MaxY),
- turn_yregs(N-1, setelement(N, Tp, E), MaxY).
-
-turn_yreg({yy,YY}, MaxY) ->
- {y,MaxY-YY};
-turn_yreg({list,Ls},MaxY) ->
- {list,turn_yreg(Ls, MaxY)};
-turn_yreg([_|_]=Ts, MaxY) ->
- [turn_yreg(T, MaxY) || T <- Ts];
-turn_yreg(Other, _MaxY) ->
- Other.
-
-%% select_cg(Sclause, V, TypeFail, ValueFail, StackReg, State) ->
-%% {Is,StackReg,State}.
-%% Selecting type and value needs two failure labels, TypeFail is the
-%% label to jump to of the next type test when this type fails, and
-%% ValueFail is the label when this type is correct but the value is
-%% wrong. These are different as in the second case there is no need
-%% to try the next type, it will always fail.
-
-select_cg(#l{ke={type_clause,cons,[S]}}, {var,V}, Tf, Vf, Bef, St) ->
- select_cons(S, V, Tf, Vf, Bef, St);
-select_cg(#l{ke={type_clause,nil,[S]}}, {var,V}, Tf, Vf, Bef, St) ->
- select_nil(S, V, Tf, Vf, Bef, St);
-select_cg(#l{ke={type_clause,binary,[S]}}, {var,V}, Tf, Vf, Bef, St) ->
- select_binary(S, V, Tf, Vf, Bef, St);
-select_cg(#l{ke={type_clause,bin_seg,S}}, {var,V}, Tf, _Vf, Bef, St) ->
- select_bin_segs(S, V, Tf, Bef, St);
-select_cg(#l{ke={type_clause,bin_int,S}}, {var,V}, Tf, _Vf, Bef, St) ->
- select_bin_segs(S, V, Tf, Bef, St);
-select_cg(#l{ke={type_clause,bin_end,[S]}}, {var,V}, Tf, _Vf, Bef, St) ->
- select_bin_end(S, V, Tf, Bef, St);
-select_cg(#l{ke={type_clause,map,S}}, {var,V}, Tf, Vf, Bef, St) ->
- select_map(S, V, Tf, Vf, Bef, St);
-select_cg(#l{ke={type_clause,Type,Scs}}, {var,V}, Tf, Vf, Bef, St0) ->
- {Vis,{Aft,St1}} =
- mapfoldl(fun (S, {Int,Sta}) ->
- {Val,Is,Inta,Stb} = select_val(S, V, Vf, Bef, Sta),
- {{Is,[Val]},{sr_merge(Int, Inta),Stb}}
- end, {void,St0}, Scs),
- OptVls = combine(lists:sort(combine(Vis))),
- {Vls,Sis,St2} = select_labels(OptVls, St1, [], []),
- {select_val_cg(Type, fetch_var(V, Bef), Vls, Tf, Vf, Sis), Aft, St2}.
-
-select_val_cg(tuple, R, [Arity,{f,Lbl}], Tf, Vf, [{label,Lbl}|Sis]) ->
- [{test,is_tuple,{f,Tf},[R]},{test,test_arity,{f,Vf},[R,Arity]}|Sis];
-select_val_cg(tuple, R, Vls, Tf, Vf, Sis) ->
- [{test,is_tuple,{f,Tf},[R]},{select_tuple_arity,R,{f,Vf},{list,Vls}}|Sis];
-select_val_cg(Type, R, [Val, {f,Lbl}], Fail, Fail, [{label,Lbl}|Sis]) ->
- [{test,is_eq_exact,{f,Fail},[R,{Type,Val}]}|Sis];
-select_val_cg(Type, R, [Val, {f,Lbl}], Tf, Vf, [{label,Lbl}|Sis]) ->
- [{test,select_type_test(Type),{f,Tf},[R]},
- {test,is_eq_exact,{f,Vf},[R,{Type,Val}]}|Sis];
-select_val_cg(Type, R, Vls0, Tf, Vf, Sis) ->
- Vls1 = [case Value of {f,_Lbl} -> Value; _ -> {Type,Value} end || Value <- Vls0],
- [{test,select_type_test(Type),{f,Tf},[R]}, {select_val,R,{f,Vf},{list,Vls1}}|Sis].
-
-select_type_test(integer) -> is_integer;
-select_type_test(atom) -> is_atom;
-select_type_test(float) -> is_float.
-
-combine([{Is,Vs1}, {Is,Vs2}|Vis]) -> combine([{Is,Vs1 ++ Vs2}|Vis]);
-combine([V|Vis]) -> [V|combine(Vis)];
-combine([]) -> [].
-
-select_labels([{Is,Vs}|Vis], St0, Vls, Sis) ->
- {Lbl,St1} = new_label(St0),
- select_labels(Vis, St1, add_vls(Vs, Lbl, Vls), [[{label,Lbl}|Is]|Sis]);
-select_labels([], St, Vls, Sis) ->
- {Vls,append(Sis),St}.
-
-add_vls([V|Vs], Lbl, Acc) ->
- add_vls(Vs, Lbl, [V, {f,Lbl}|Acc]);
-add_vls([], _, Acc) -> Acc.
-
-select_cons(#l{ke={val_clause,{cons,Es},B},i=I,vdb=Vdb}, V, Tf, Vf, Bef, St0) ->
- {Eis,Int,St1} = select_extract_cons(V, Es, I, Vdb, Bef, St0),
- {Bis,Aft,St2} = match_cg(B, Vf, Int, St1),
- {[{test,is_nonempty_list,{f,Tf},[fetch_var(V, Bef)]}] ++ Eis ++ Bis,Aft,St2}.
-
-select_nil(#l{ke={val_clause,nil,B}}, V, Tf, Vf, Bef, St0) ->
- {Bis,Aft,St1} = match_cg(B, Vf, Bef, St0),
- {[{test,is_nil,{f,Tf},[fetch_var(V, Bef)]}] ++ Bis,Aft,St1}.
-
-select_binary(#l{ke={val_clause,{binary,{var,V}},B},i=I,vdb=Vdb},
- V, Tf, Vf, Bef, St0) ->
- Int0 = clear_dead(Bef#sr{reg=Bef#sr.reg}, I, Vdb),
- {Bis0,Aft,St1} = match_cg(B, Vf, Int0, St0),
- CtxReg = fetch_var(V, Int0),
- Live = max_reg(Bef#sr.reg),
- Bis1 = [{test,bs_start_match2,{f,Tf},Live,[CtxReg,V],CtxReg},
- {bs_save2,CtxReg,{V,V}}|Bis0],
- Bis = finish_select_binary(Bis1),
- {Bis,Aft,St1};
-select_binary(#l{ke={val_clause,{binary,{var,Ivar}},B},i=I,vdb=Vdb},
- V, Tf, Vf, Bef, St0) ->
- Regs = put_reg(Ivar, Bef#sr.reg),
- Int0 = clear_dead(Bef#sr{reg=Regs}, I, Vdb),
- {Bis0,Aft,St1} = match_cg(B, Vf, Int0, St0),
- CtxReg = fetch_var(Ivar, Int0),
- Live = max_reg(Bef#sr.reg),
- Bis1 = [{test,bs_start_match2,{f,Tf},Live,[fetch_var(V, Bef),Ivar],CtxReg},
- {bs_save2,CtxReg,{Ivar,Ivar}}|Bis0],
- Bis = finish_select_binary(Bis1),
- {Bis,Aft,St1}.
-
-finish_select_binary([{bs_save2,R,Point}=I,{bs_restore2,R,Point}|Is]) ->
- [I|finish_select_binary(Is)];
-finish_select_binary([{bs_save2,R,Point}=I,{test,is_eq_exact,_,_}=Test,
- {bs_restore2,R,Point}|Is]) ->
- [I,Test|finish_select_binary(Is)];
-finish_select_binary([{test,bs_match_string,F,[Ctx,BinList]}|Is])
- when is_list(BinList) ->
- I = {test,bs_match_string,F,[Ctx,list_to_bitstring(BinList)]},
- [I|finish_select_binary(Is)];
-finish_select_binary([I|Is]) ->
- [I|finish_select_binary(Is)];
-finish_select_binary([]) -> [].
-
-%% New instructions for selection of binary segments.
-
-select_bin_segs(Scs, Ivar, Tf, Bef, St) ->
- match_fmf(fun(S, Fail, Sta) ->
- select_bin_seg(S, Ivar, Fail, Bef, Sta) end,
- Tf, St, Scs).
-
-select_bin_seg(#l{ke={val_clause,{bin_seg,Ctx,Size,U,T,Fs0,Es},B},i=I,vdb=Vdb,a=A},
- Ivar, Fail, Bef, St0) ->
- Fs = [{anno,A}|Fs0],
- {Mis,Int,St1} = select_extract_bin(Es, Size, U, T, Fs, Fail,
- I, Vdb, Bef, Ctx, B, St0),
- {Bis,Aft,St2} = match_cg(B, Fail, Int, St1),
- CtxReg = fetch_var(Ctx, Bef),
- Is = if
- Mis =:= [] ->
- %% No bs_restore2 instruction needed if no match instructions.
- Bis;
- true ->
- [{bs_restore2,CtxReg,{Ctx,Ivar}}|Mis++Bis]
- end,
- {Is,Aft,St2};
-select_bin_seg(#l{ke={val_clause,{bin_int,Ctx,Sz,U,Fs,Val,Es},B},i=I,vdb=Vdb},
- Ivar, Fail, Bef, St0) ->
- {Mis,Int,St1} = select_extract_int(Es, Val, Sz, U, Fs, Fail,
- I, Vdb, Bef, Ctx, St0),
- {Bis,Aft,St2} = match_cg(B, Fail, Int, St1),
- CtxReg = fetch_var(Ctx, Bef),
- Is = case Mis ++ Bis of
- [{test,bs_match_string,F,[OtherCtx,Bin1]},
- {bs_save2,OtherCtx,_},
- {bs_restore2,OtherCtx,_},
- {test,bs_match_string,F,[OtherCtx,Bin2]}|Is0] ->
- %% We used to do this optimization later, but it
- %% turns out that in huge functions with many
- %% bs_match_string instructions, it's a big win
- %% to do the combination now. To avoid copying the
- %% binary data again and again, we'll combine bitstrings
- %% in a list and convert all of it to a bitstring later.
- [{test,bs_match_string,F,[OtherCtx,[Bin1,Bin2]]}|Is0];
- Is0 ->
- Is0
- end,
- {[{bs_restore2,CtxReg,{Ctx,Ivar}}|Is],Aft,St2}.
-
-select_extract_int([{var,Tl}], Val, {integer,Sz}, U, Fs, Vf,
- I, Vdb, Bef, Ctx, St) ->
- Bits = U*Sz,
- Bin = case member(big, Fs) of
- true ->
- <<Val:Bits>>;
- false ->
- true = member(little, Fs), %Assertion.
- <<Val:Bits/little>>
- end,
- Bits = bit_size(Bin), %Assertion.
- CtxReg = fetch_var(Ctx, Bef),
- Is = if
- Bits =:= 0 ->
- [{bs_save2,CtxReg,{Ctx,Tl}}];
- true ->
- [{test,bs_match_string,{f,Vf},[CtxReg,Bin]},
- {bs_save2,CtxReg,{Ctx,Tl}}]
- end,
- {Is,clear_dead(Bef, I, Vdb),St}.
-
-select_extract_bin([{var,Hd},{var,Tl}], Size0, Unit, Type, Flags, Vf,
- I, Vdb, Bef, Ctx, _Body, St) ->
- SizeReg = get_bin_size_reg(Size0, Bef),
- {Es,Aft} =
- case vdb_find(Hd, Vdb) of
- {_,_,Lhd} when Lhd =< I ->
- %% The extracted value will not be used.
- CtxReg = fetch_var(Ctx, Bef),
- Live = max_reg(Bef#sr.reg),
- Skip = build_skip_instr(Type, Vf, CtxReg, Live,
- SizeReg, Unit, Flags),
- {[Skip,{bs_save2,CtxReg,{Ctx,Tl}}],Bef};
- {_,_,_} ->
- Reg = put_reg(Hd, Bef#sr.reg),
- Int1 = Bef#sr{reg=Reg},
- Rhd = fetch_reg(Hd, Reg),
- CtxReg = fetch_reg(Ctx, Reg),
- Live = max_reg(Bef#sr.reg),
- {[build_bs_instr(Type, Vf, CtxReg, Live, SizeReg,
- Unit, Flags, Rhd),
- {bs_save2,CtxReg,{Ctx,Tl}}],Int1}
- end,
- {Es,clear_dead(Aft, I, Vdb),St};
-select_extract_bin([{var,Hd}], Size, Unit, binary, Flags, Vf,
- I, Vdb, Bef, Ctx, Body, St) ->
- %% Match the last segment of a binary. We KNOW that the size
- %% must be 'all'.
- Size = {atom,all}, %Assertion.
- {Es,Aft} =
- case vdb_find(Hd, Vdb) of
- {_,_,Lhd} when Lhd =< I ->
- %% The result will not be used. Furthermore, since we
- %% we are at the end of the binary, the position will
- %% not be used again; thus, it is safe to do a cheaper
- %% test of the unit.
- CtxReg = fetch_var(Ctx, Bef),
- {case Unit of
- 1 ->
- [];
- _ ->
- [{test,bs_test_unit,{f,Vf},[CtxReg,Unit]}]
- end,Bef};
- {_,_,_} ->
- case is_context_unused(Body) of
- false ->
- Reg = put_reg(Hd, Bef#sr.reg),
- Int1 = Bef#sr{reg=Reg},
- Rhd = fetch_reg(Hd, Reg),
- CtxReg = fetch_reg(Ctx, Reg),
- Name = bs_get_binary2,
- Live = max_reg(Bef#sr.reg),
- {[{test,Name,{f,Vf},Live,
- [CtxReg,Size,Unit,{field_flags,Flags}],Rhd}],
- Int1};
- true ->
- %% Since the matching context will not be used again,
- %% we can reuse its register. Reusing the register
- %% opens some interesting optimizations in the
- %% run-time system.
-
- Reg0 = Bef#sr.reg,
- CtxReg = fetch_reg(Ctx, Reg0),
- Reg = replace_reg_contents(Ctx, Hd, Reg0),
- Int1 = Bef#sr{reg=Reg},
- Name = bs_get_binary2,
- Live = max_reg(Int1#sr.reg),
- {[{test,Name,{f,Vf},Live,
- [CtxReg,Size,Unit,{field_flags,Flags}],CtxReg}],
- Int1}
- end
- end,
- {Es,clear_dead(Aft, I, Vdb),St}.
-
-%% is_context_unused(Ke) -> true | false
-%% Simple heurististic to determine whether the code that follows will
-%% use the current matching context again. (The information of liveness
-%% calculcated by v3_life is too conservative to be useful for this purpose.)
-%% 'true' means that the code that follows will definitely not use the context
-%% again (because it is a block, not guard or matching code); 'false' that we
-%% are not sure (there is either a guard, or more matching, either which may
-%% reference the context again).
-
-is_context_unused(#l{ke=Ke}) -> is_context_unused(Ke);
-is_context_unused({block,_}) -> true;
-is_context_unused(_) -> false.
-
-select_bin_end(#l{ke={val_clause,{bin_end,Ctx},B}},
- Ivar, Tf, Bef, St0) ->
- {Bis,Aft,St2} = match_cg(B, Tf, Bef, St0),
- CtxReg = fetch_var(Ctx, Bef),
- {[{bs_restore2,CtxReg,{Ctx,Ivar}},
- {test,bs_test_tail2,{f,Tf},[CtxReg,0]}|Bis],Aft,St2}.
-
-get_bin_size_reg({var,V}, Bef) ->
- fetch_var(V, Bef);
-get_bin_size_reg(Literal, _Bef) ->
- Literal.
-
-build_bs_instr(Type, Vf, CtxReg, Live, SizeReg, Unit, Flags, Rhd) ->
- {Format,Name} = case Type of
- integer -> {plain,bs_get_integer2};
- float -> {plain,bs_get_float2};
- binary -> {plain,bs_get_binary2};
- utf8 -> {utf,bs_get_utf8};
- utf16 -> {utf,bs_get_utf16};
- utf32 -> {utf,bs_get_utf32}
- end,
- case Format of
- plain ->
- {test,Name,{f,Vf},Live,
- [CtxReg,SizeReg,Unit,{field_flags,Flags}],Rhd};
- utf ->
- {test,Name,{f,Vf},Live,
- [CtxReg,{field_flags,Flags}],Rhd}
- end.
-
-build_skip_instr(Type, Vf, CtxReg, Live, SizeReg, Unit, Flags) ->
- {Format,Name} = case Type of
- utf8 -> {utf,bs_skip_utf8};
- utf16 -> {utf,bs_skip_utf16};
- utf32 -> {utf,bs_skip_utf32};
- _ -> {plain,bs_skip_bits2}
- end,
- case Format of
- plain ->
- {test,Name,{f,Vf},[CtxReg,SizeReg,Unit,{field_flags,Flags}]};
- utf ->
- {test,Name,{f,Vf},[CtxReg,Live,{field_flags,Flags}]}
- end.
-
-select_val(#l{ke={val_clause,{tuple,Es},B},i=I,vdb=Vdb}, V, Vf, Bef, St0) ->
- {Eis,Int,St1} = select_extract_tuple(V, Es, I, Vdb, Bef, St0),
- {Bis,Aft,St2} = match_cg(B, Vf, Int, St1),
- {length(Es),Eis ++ Bis,Aft,St2};
-select_val(#l{ke={val_clause,{_,Val},B}}, _V, Vf, Bef, St0) ->
- {Bis,Aft,St1} = match_cg(B, Vf, Bef, St0),
- {Val,Bis,Aft,St1}.
-
-%% select_extract_tuple(Src, [V], I, Vdb, StackReg, State) ->
-%% {[E],StackReg,State}.
-%% Extract tuple elements, but only if they do not immediately die.
-
-select_extract_tuple(Src, Vs, I, Vdb, Bef, St) ->
- F = fun ({var,V}, {Int0,Elem}) ->
- case vdb_find(V, Vdb) of
- {V,_,L} when L =< I -> {[], {Int0,Elem+1}};
- _Other ->
- Reg1 = put_reg(V, Int0#sr.reg),
- Int1 = Int0#sr{reg=Reg1},
- Rsrc = fetch_var(Src, Int1),
- {[{get_tuple_element,Rsrc,Elem,fetch_reg(V, Reg1)}],
- {Int1,Elem+1}}
- end
- end,
- {Es,{Aft,_}} = flatmapfoldl(F, {Bef,0}, Vs),
- {Es,Aft,St}.
-
-select_map(Scs, V, Tf, Vf, Bef, St0) ->
- Reg = fetch_var(V, Bef),
- {Is,Aft,St1} =
- match_fmf(fun(#l{ke={val_clause,{map,exact,_,Es},B},i=I,vdb=Vdb}, Fail, St1) ->
- select_map_val(V, Es, B, Fail, I, Vdb, Bef, St1)
- end, Vf, St0, Scs),
- {[{test,is_map,{f,Tf},[Reg]}|Is],Aft,St1}.
-
-select_map_val(V, Es, B, Fail, I, Vdb, Bef, St0) ->
- {Eis,Int,St1} = select_extract_map(V, Es, Fail, I, Vdb, Bef, St0),
- {Bis,Aft,St2} = match_cg(B, Fail, Int, St1),
- {Eis++Bis,Aft,St2}.
-
-select_extract_map(_, [], _, _, _, Bef, St) -> {[],Bef,St};
-select_extract_map(Src, Vs, Fail, I, Vdb, Bef, St) ->
- %% First split the instruction flow
- %% We want one set of each
- %% 1) has_map_fields (no target registers)
- %% 2) get_map_elements (with target registers)
- %% Assume keys are term-sorted
- Rsrc = fetch_var(Src, Bef),
-
- {{HasKs,GetVs,HasVarKs,GetVarVs},Aft} = lists:foldr(fun
- ({map_pair,{var,K},{var,V}},{{HasKsi,GetVsi,HasVarVsi,GetVarVsi},Int0}) ->
- case vdb_find(V, Vdb) of
- {V,_,L} when L =< I ->
- RK = fetch_var(K,Int0),
- {{HasKsi,GetVsi,[RK|HasVarVsi],GetVarVsi},Int0};
- _Other ->
- Reg1 = put_reg(V, Int0#sr.reg),
- Int1 = Int0#sr{reg=Reg1},
- RK = fetch_var(K,Int0),
- RV = fetch_reg(V,Reg1),
- {{HasKsi,GetVsi,HasVarVsi,[[RK,RV]|GetVarVsi]},Int1}
- end;
- ({map_pair,Key,{var,V}},{{HasKsi,GetVsi,HasVarVsi,GetVarVsi},Int0}) ->
- case vdb_find(V, Vdb) of
- {V,_,L} when L =< I ->
- {{[Key|HasKsi],GetVsi,HasVarVsi,GetVarVsi},Int0};
- _Other ->
- Reg1 = put_reg(V, Int0#sr.reg),
- Int1 = Int0#sr{reg=Reg1},
- {{HasKsi,[Key,fetch_reg(V, Reg1)|GetVsi],HasVarVsi,GetVarVsi},Int1}
- end
- end, {{[],[],[],[]},Bef}, Vs),
-
- Code = [{test,has_map_fields,{f,Fail},Rsrc,{list,HasKs}} || HasKs =/= []] ++
- [{test,has_map_fields,{f,Fail},Rsrc,{list,[K]}} || K <- HasVarKs] ++
- [{get_map_elements, {f,Fail},Rsrc,{list,GetVs}} || GetVs =/= []] ++
- [{get_map_elements, {f,Fail},Rsrc,{list,[K,V]}} || [K,V] <- GetVarVs],
- {Code, Aft, St}.
-
-
-select_extract_cons(Src, [{var,Hd}, {var,Tl}], I, Vdb, Bef, St) ->
- {Es,Aft} = case {vdb_find(Hd, Vdb), vdb_find(Tl, Vdb)} of
- {{_,_,Lhd}, {_,_,Ltl}} when Lhd =< I, Ltl =< I ->
- %% Both head and tail are dead. No need to generate
- %% any instruction.
- {[], Bef};
- _ ->
- %% At least one of head and tail will be used,
- %% but we must always fetch both. We will call
- %% clear_dead/2 to allow reuse of the register
- %% in case only of them is used.
-
- Reg0 = put_reg(Tl, put_reg(Hd, Bef#sr.reg)),
- Int0 = Bef#sr{reg=Reg0},
- Rsrc = fetch_var(Src, Int0),
- Rhd = fetch_reg(Hd, Reg0),
- Rtl = fetch_reg(Tl, Reg0),
- Int1 = clear_dead(Int0, I, Vdb),
- {[{get_list,Rsrc,Rhd,Rtl}], Int1}
- end,
- {Es,Aft,St}.
-
-
-guard_clause_cg(#l{ke={guard_clause,G,B},vdb=Vdb}, Fail, Bef, St0) ->
- {Gis,Int,St1} = guard_cg(G, Fail, Vdb, Bef, St0),
- {Bis,Aft,St} = match_cg(B, Fail, Int, St1),
- {Gis ++ Bis,Aft,St}.
-
-%% guard_cg(Guard, Fail, Vdb, StackReg, State) ->
-%% {[Ainstr],StackReg,State}.
-%% A guard is a boolean expression of tests. Tests return true or
-%% false. A fault in a test causes the test to return false. Tests
-%% never return the boolean, instead we generate jump code to go to
-%% the correct exit point. Primops and tests all go to the next
-%% instruction on success or jump to a failure label.
-
-guard_cg(#l{ke={protected,Ts,Rs},i=I,vdb=Pdb}, Fail, _Vdb, Bef, St) ->
- protected_cg(Ts, Rs, Fail, I, Pdb, Bef, St);
-guard_cg(#l{ke={block,Ts},i=I,vdb=Bdb}, Fail, _Vdb, Bef, St) ->
- guard_cg_list(Ts, Fail, I, Bdb, Bef, St);
-guard_cg(#l{ke={test,Test,As,Inverted},i=I,vdb=_Tdb}, Fail, Vdb, Bef, St0) ->
- case Inverted of
- false ->
- test_cg(Test, As, Fail, I, Vdb, Bef, St0);
- true ->
- {Psucc,St1} = new_label(St0),
- {Is,Aft,St2} = test_cg(Test, As, Psucc, I, Vdb, Bef, St1),
- {Is++[{jump,{f,Fail}},{label,Psucc}],Aft,St2}
- end;
-guard_cg(G, _Fail, Vdb, Bef, St) ->
- %%ok = io:fwrite("cg ~w: ~p~n", [?LINE,{G,Fail,Vdb,Bef}]),
- {Gis,Aft,St1} = cg(G, Vdb, Bef, St),
- %%ok = io:fwrite("cg ~w: ~p~n", [?LINE,{Aft}]),
- {Gis,Aft,St1}.
-
-%% protected_cg([Kexpr], [Ret], Fail, I, Vdb, Bef, St) -> {[Ainstr],Aft,St}.
-%% Do a protected. Protecteds without return values are just done
-%% for effect, the return value is not checked, success passes on to
-%% the next instruction and failure jumps to Fail. If there are
-%% return values then these must be set to 'false' on failure,
-%% control always passes to the next instruction.
-
-protected_cg(Ts, [], Fail, I, Vdb, Bef, St0) ->
- %% Protect these calls, revert when done.
- {Tis,Aft,St1} = guard_cg_list(Ts, Fail, I, Vdb, Bef,
- St0#cg{bfail=Fail}),
- {Tis,Aft,St1#cg{bfail=St0#cg.bfail}};
-protected_cg(Ts, Rs, _Fail, I, Vdb, Bef, St0) ->
- {Pfail,St1} = new_label(St0),
- {Psucc,St2} = new_label(St1),
- {Tis,Aft,St3} = guard_cg_list(Ts, Pfail, I, Vdb, Bef,
- St2#cg{bfail=Pfail}),
- %%ok = io:fwrite("cg ~w: ~p~n", [?LINE,{Rs,I,Vdb,Aft}]),
- %% Set return values to false.
- Mis = [{move,{atom,false},fetch_var(V,Aft)}||{var,V} <- Rs],
- {Tis ++ [{jump,{f,Psucc}},
- {label,Pfail}] ++ Mis ++ [{label,Psucc}],
- Aft,St3#cg{bfail=St0#cg.bfail}}.
-
-%% test_cg(TestName, Args, Fail, I, Vdb, Bef, St) -> {[Ainstr],Aft,St}.
-%% Generate test instruction. Use explicit fail label here.
-
-test_cg(is_map, [A], Fail, I, Vdb, Bef, St) ->
- %% We must avoid creating code like this:
- %%
- %% move x(0) y(0)
- %% is_map Fail [x(0)]
- %% make_fun => x(0) %% Overwrite x(0)
- %% put_map_assoc y(0) ...
- %%
- %% The code is safe, but beam_validator does not understand that.
- %% Extending beam_validator to handle such (rare) code as the
- %% above would make it slower for all programs. Instead, change
- %% the code generator to always prefer the Y register for is_map()
- %% and put_map_assoc() instructions, ensuring that they use the
- %% same register.
- Arg = cg_reg_arg_prefer_y(A, Bef),
- Aft = clear_dead(Bef, I, Vdb),
- {[{test,is_map,{f,Fail},[Arg]}],Aft,St};
-test_cg(is_boolean, [{atom,Val}], Fail, I, Vdb, Bef, St) ->
- Aft = clear_dead(Bef, I, Vdb),
- Is = case is_boolean(Val) of
- true -> [];
- false -> [{jump,{f,Fail}}]
- end,
- {Is,Aft,St};
-test_cg(Test, As, Fail, I, Vdb, Bef, St) ->
- Args = cg_reg_args(As, Bef),
- Aft = clear_dead(Bef, I, Vdb),
- {[beam_utils:bif_to_test(Test, Args, {f,Fail})],Aft,St}.
-
-%% guard_cg_list([Kexpr], Fail, I, Vdb, StackReg, St) ->
-%% {[Ainstr],StackReg,St}.
-
-guard_cg_list(Kes, Fail, I, Vdb, Bef, St0) ->
- {Keis,{Aft,St1}} =
- flatmapfoldl(fun (Ke, {Inta,Sta}) ->
- {Keis,Intb,Stb} =
- guard_cg(Ke, Fail, Vdb, Inta, Sta),
- {Keis,{Intb,Stb}}
- end, {Bef,St0}, need_heap(Kes, I)),
- {Keis,Aft,St1}.
-
-%% match_fmf(Fun, LastFail, State, [Clause]) -> {Is,Aft,State}.
-%% This is a special flatmapfoldl for match code gen where we
-%% generate a "failure" label for each clause. The last clause uses
-%% an externally generated failure label, LastFail. N.B. We do not
-%% know or care how the failure labels are used.
-
-match_fmf(F, LastFail, St, [H]) ->
- F(H, LastFail, St);
-match_fmf(F, LastFail, St0, [H|T]) ->
- {Fail,St1} = new_label(St0),
- {R,Aft1,St2} = F(H, Fail, St1),
- {Rs,Aft2,St3} = match_fmf(F, LastFail, St2, T),
- {R ++ [{label,Fail}] ++ Rs,sr_merge(Aft1, Aft2),St3}.
-
-%% call_cg(Func, [Arg], [Ret], Le, Vdb, StackReg, State) ->
-%% {[Ainstr],StackReg,State}.
-%% enter_cg(Func, [Arg], Le, Vdb, Bef, St) -> {[Ainstr],Aft,St}.
-%% Call and enter first put the arguments into registers and save any
-%% other registers, then clean up and compress the stack and set the
-%% frame size. Finally the actual call is made. Call then needs the
-%% return values filled in.
-
-call_cg({var,_V} = Var, As, Rs, Le, Vdb, Bef, St0) ->
- {Sis,Int} = cg_setup_call(As++[Var], Bef, Le#l.i, Vdb),
- %% Put return values in registers.
- Reg = load_vars(Rs, clear_regs(Int#sr.reg)),
- %% Build complete code and final stack/register state.
- Arity = length(As),
- {Frees,Aft} = free_dead(clear_dead(Int#sr{reg=Reg}, Le#l.i, Vdb)),
- {Sis ++ Frees ++ [line(Le),{call_fun,Arity}],Aft,
- need_stack_frame(St0)};
-call_cg({remote,Mod,Name}, As, Rs, Le, Vdb, Bef, St0)
- when element(1, Mod) =:= var;
- element(1, Name) =:= var ->
- {Sis,Int} = cg_setup_call(As++[Mod,Name], Bef, Le#l.i, Vdb),
- %% Put return values in registers.
- Reg = load_vars(Rs, clear_regs(Int#sr.reg)),
- %% Build complete code and final stack/register state.
- Arity = length(As),
- St = need_stack_frame(St0),
- %%{Call,St1} = build_call(Func, Arity, St0),
- {Frees,Aft} = free_dead(clear_dead(Int#sr{reg=Reg}, Le#l.i, Vdb)),
- {Sis ++ Frees ++ [line(Le),{apply,Arity}],Aft,St};
-call_cg(Func, As, Rs, Le, Vdb, Bef, St0) ->
- case St0 of
- #cg{bfail=Fail} when Fail =/= 0 ->
- %% Inside a guard. The only allowed function call is to
- %% erlang:error/1,2. We will generate the following code:
- %%
- %% move {atom,ok} DestReg
- %% jump FailureLabel
- {remote,{atom,erlang},{atom,error}} = Func, %Assertion.
- [{var,DestVar}] = Rs,
- Int0 = clear_dead(Bef, Le#l.i, Vdb),
- Reg = put_reg(DestVar, Int0#sr.reg),
- Int = Int0#sr{reg=Reg},
- Dst = fetch_reg(DestVar, Reg),
- {[{move,{atom,ok},Dst},{jump,{f,Fail}}],
- clear_dead(Int, Le#l.i, Vdb),St0};
- #cg{} ->
- %% Ordinary function call in a function body.
- {Sis,Int} = cg_setup_call(As, Bef, Le#l.i, Vdb),
- %% Put return values in registers.
- Reg = load_vars(Rs, clear_regs(Int#sr.reg)),
- %% Build complete code and final stack/register state.
- Arity = length(As),
- {Call,St1} = build_call(Func, Arity, St0),
- {Frees,Aft} = free_dead(clear_dead(Int#sr{reg=Reg}, Le#l.i, Vdb)),
- {Sis ++ Frees ++ [line(Le)|Call],Aft,St1}
- end.
-
-build_call({remote,{atom,erlang},{atom,'!'}}, 2, St0) ->
- {[send],need_stack_frame(St0)};
-build_call({remote,{atom,Mod},{atom,Name}}, Arity, St0) ->
- {[{call_ext,Arity,{extfunc,Mod,Name,Arity}}],need_stack_frame(St0)};
-build_call(Name, Arity, St0) when is_atom(Name) ->
- {Lbl,St1} = local_func_label(Name, Arity, need_stack_frame(St0)),
- {[{call,Arity,{f,Lbl}}],St1}.
-
-free_dead(#sr{stk=Stk0}=Aft) ->
- {Instr,Stk} = free_dead(Stk0, 0, [], []),
- {Instr,Aft#sr{stk=Stk}}.
-
-free_dead([dead|Stk], Y, Instr, StkAcc) ->
- %% Note: kill/1 is equivalent to init/1 (translated by beam_asm).
- %% We use kill/1 to help further optimisation passes.
- free_dead(Stk, Y+1, [{kill,{yy,Y}}|Instr], [free|StkAcc]);
-free_dead([Any|Stk], Y, Instr, StkAcc) ->
- free_dead(Stk, Y+1, Instr, [Any|StkAcc]);
-free_dead([], _, Instr, StkAcc) -> {Instr,reverse(StkAcc)}.
-
-enter_cg({var,_V} = Var, As, Le, Vdb, Bef, St0) ->
- {Sis,Int} = cg_setup_call(As++[Var], Bef, Le#l.i, Vdb),
- %% Build complete code and final stack/register state.
- Arity = length(As),
- {Sis ++ [line(Le),{call_fun,Arity},return],
- clear_dead(Int#sr{reg=clear_regs(Int#sr.reg)}, Le#l.i, Vdb),
- need_stack_frame(St0)};
-enter_cg({remote,Mod,Name}, As, Le, Vdb, Bef, St0)
- when element(1, Mod) =:= var;
- element(1, Name) =:= var ->
- {Sis,Int} = cg_setup_call(As++[Mod,Name], Bef, Le#l.i, Vdb),
- %% Build complete code and final stack/register state.
- Arity = length(As),
- St = need_stack_frame(St0),
- {Sis ++ [line(Le),{apply_only,Arity}],
- clear_dead(Int#sr{reg=clear_regs(Int#sr.reg)}, Le#l.i, Vdb),
- St};
-enter_cg(Func, As, Le, Vdb, Bef, St0) ->
- {Sis,Int} = cg_setup_call(As, Bef, Le#l.i, Vdb),
- %% Build complete code and final stack/register state.
- Arity = length(As),
- {Call,St1} = build_enter(Func, Arity, St0),
- Line = enter_line(Func, Arity, Le),
- {Sis ++ Line ++ Call,
- clear_dead(Int#sr{reg=clear_regs(Int#sr.reg)}, Le#l.i, Vdb),
- St1}.
-
-build_enter({remote,{atom,erlang},{atom,'!'}}, 2, St0) ->
- {[send,return],need_stack_frame(St0)};
-build_enter({remote,{atom,Mod},{atom,Name}}, Arity, St0) ->
- St1 = case trap_bif(Mod, Name, Arity) of
- true -> need_stack_frame(St0);
- false -> St0
- end,
- {[{call_ext_only,Arity,{extfunc,Mod,Name,Arity}}],St1};
-build_enter(Name, Arity, St0) when is_atom(Name) ->
- {Lbl,St1} = local_func_label(Name, Arity, St0),
- {[{call_only,Arity,{f,Lbl}}],St1}.
-
-enter_line({remote,{atom,Mod},{atom,Name}}, Arity, Le) ->
- case erl_bifs:is_safe(Mod, Name, Arity) of
- false ->
- %% Tail-recursive call, possibly to a BIF.
- %% We'll need a line instruction in case the
- %% BIF call fails.
- [line(Le)];
- true ->
- %% Call to a safe BIF. Since it cannot fail,
- %% we don't need any line instruction here.
- []
- end;
-enter_line(_, _, _) ->
- %% Tail-recursive call to a local function. A line
- %% instruction will not be useful.
- [].
-
-%% local_func_label(Name, Arity, State) -> {Label,State'}
-%% local_func_label({Name,Arity}, State) -> {Label,State'}
-%% Get the function entry label for a local function.
-
-local_func_label(Name, Arity, St) ->
- local_func_label({Name,Arity}, St).
-
-local_func_label(Key, #cg{functable=Map}=St0) ->
- case Map of
- #{Key := Label} -> {Label,St0};
- _ ->
- {Label,St} = new_label(St0),
- {Label,St#cg{functable=Map#{Key => Label}}}
- end.
-
-%% need_stack_frame(State) -> State'
-%% Make a note in the state that this function will need a stack frame.
-
-need_stack_frame(#cg{need_frame=true}=St) -> St;
-need_stack_frame(St) -> St#cg{need_frame=true}.
-
-%% trap_bif(Mod, Name, Arity) -> true|false
-%% Trap bifs that need a stack frame.
-
-trap_bif(erlang, link, 1) -> true;
-trap_bif(erlang, unlink, 1) -> true;
-trap_bif(erlang, monitor_node, 2) -> true;
-trap_bif(erlang, group_leader, 2) -> true;
-trap_bif(erlang, exit, 2) -> true;
-trap_bif(_, _, _) -> false.
-
-%% internal_cg(Bif, [Arg], [Ret], Le, Vdb, StackReg, State) ->
-%% {[Ainstr],StackReg,State}.
-
-internal_cg(bs_context_to_binary=Instr, [Src0], [], Le, Vdb, Bef, St0) ->
- [Src] = cg_reg_args([Src0], Bef),
- case is_register(Src) of
- false ->
- {[],clear_dead(Bef, Le#l.i, Vdb), St0};
- true ->
- {[{Instr,Src}],clear_dead(Bef, Le#l.i, Vdb), St0}
- end;
-internal_cg(dsetelement, [Index0,Tuple0,New0], _Rs, Le, Vdb, Bef, St0) ->
- [New,Tuple,{integer,Index1}] = cg_reg_args([New0,Tuple0,Index0], Bef),
- Index = Index1-1,
- {[{set_tuple_element,New,Tuple,Index}],
- clear_dead(Bef, Le#l.i, Vdb), St0};
-internal_cg(make_fun, [Func0,Arity0|As], Rs, Le, Vdb, Bef, St0) ->
- %% This behaves more like a function call.
- {atom,Func} = Func0,
- {integer,Arity} = Arity0,
- {Sis,Int} = cg_setup_call(As, Bef, Le#l.i, Vdb),
- Reg = load_vars(Rs, clear_regs(Int#sr.reg)),
- {FuncLbl,St1} = local_func_label(Func, Arity, St0),
- MakeFun = {make_fun2,{f,FuncLbl},0,0,length(As)},
- {Sis ++ [MakeFun],
- clear_dead(Int#sr{reg=Reg}, Le#l.i, Vdb),
- St1};
-internal_cg(bs_init_writable=I, As, Rs, Le, Vdb, Bef, St) ->
- %% This behaves like a function call.
- {Sis,Int} = cg_setup_call(As, Bef, Le#l.i, Vdb),
- Reg = load_vars(Rs, clear_regs(Int#sr.reg)),
- {Sis++[I],clear_dead(Int#sr{reg=Reg}, Le#l.i, Vdb),St};
-internal_cg(raise, As, Rs, Le, Vdb, Bef, St) ->
- %% raise can be treated like a guard BIF.
- bif_cg(raise, As, Rs, Le, Vdb, Bef, St).
-
-%% bif_cg(Bif, [Arg], [Ret], Le, Vdb, StackReg, State) ->
-%% {[Ainstr],StackReg,State}.
-
-bif_cg(Bif, As, [{var,V}], Le, Vdb, Bef, St0) ->
- Ars = cg_reg_args(As, Bef),
-
- %% If we are inside a catch and in a body (not in guard) and the
- %% BIF may fail, we must save everything that will be alive after
- %% the catch (because the code after the code assumes that all
- %% variables that are live are stored on the stack).
- %%
- %% Currently, we are somewhat pessimistic in
- %% that we save any variable that will be live after this BIF call.
-
- MayFail = not erl_bifs:is_safe(erlang, Bif, length(As)),
- {Sis,Int0} =
- case MayFail of
- true ->
- maybe_adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb, St0);
- false ->
- {[],Bef}
- end,
- Int1 = clear_dead(Int0, Le#l.i, Vdb),
- Reg = put_reg(V, Int1#sr.reg),
- Int = Int1#sr{reg=Reg},
- Dst = fetch_reg(V, Reg),
- BifFail = {f,St0#cg.bfail},
- %% We need a line instructions for BIFs that may fail in a body.
- Line = case BifFail of
- {f,0} when MayFail ->
- [line(Le)];
- _ ->
- []
- end,
- {Sis++Line++[{bif,Bif,BifFail,Ars,Dst}],
- clear_dead(Int, Le#l.i, Vdb), St0}.
-
-
-%% gc_bif_cg(Bif, [Arg], [Ret], Le, Vdb, StackReg, State) ->
-%% {[Ainstr],StackReg,State}.
-
-gc_bif_cg(Bif, As, [{var,V}], Le, Vdb, Bef, St0) ->
- Ars = cg_reg_args(As, Bef),
-
- %% If we are inside a catch and in a body (not in guard) and the
- %% BIF may fail, we must save everything that will be alive after
- %% the catch (because the code after the code assumes that all
- %% variables that are live are stored on the stack).
- %%
- %% Currently, we are somewhat pessimistic in
- %% that we save any variable that will be live after this BIF call.
-
- {Sis,Int0} = maybe_adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb, St0),
-
- Int1 = clear_dead(Int0, Le#l.i, Vdb),
- Reg = put_reg(V, Int1#sr.reg),
- Int = Int1#sr{reg=Reg},
- Dst = fetch_reg(V, Reg),
- BifFail = {f,St0#cg.bfail},
- Line = case BifFail of
- {f,0} -> [line(Le)];
- {f,_} -> []
- end,
- {Sis++Line++[{gc_bif,Bif,BifFail,max_reg(Bef#sr.reg),Ars,Dst}],
- clear_dead(Int, Le#l.i, Vdb), St0}.
-
-%% recv_loop_cg(TimeOut, ReceiveVar, ReceiveMatch, TimeOutExprs,
-%% [Ret], Le, Vdb, Bef, St) -> {[Ainstr],Aft,St}.
-
-recv_loop_cg(Te, Rvar, Rm, Tes, Rs, Le, Vdb, Bef, St0) ->
- {Sis,Int0} = adjust_stack(Bef, Le#l.i, Le#l.i, Vdb),
- Int1 = Int0#sr{reg=clear_regs(Int0#sr.reg)},
- %% Get labels.
- {Rl,St1} = new_label(St0),
- {Tl,St2} = new_label(St1),
- {Bl,St3} = new_label(St2),
- St4 = St3#cg{break=Bl,recv=Rl}, %Set correct receive labels
- {Ris,Raft,St5} = cg_recv_mesg(Rvar, Rm, Tl, Int1, St4),
- {Wis,Taft,St6} = cg_recv_wait(Te, Tes, Le#l.i, Int1, St5),
- Int2 = sr_merge(Raft, Taft), %Merge stack/registers
- Reg = load_vars(Rs, Int2#sr.reg),
- {Sis ++ [line(Le)] ++ Ris ++ [{label,Tl}] ++ Wis ++ [{label,Bl}],
- clear_dead(Int2#sr{reg=Reg}, Le#l.i, Vdb),
- St6#cg{break=St0#cg.break,recv=St0#cg.recv}}.
-
-%% cg_recv_mesg( ) -> {[Ainstr],Aft,St}.
-
-cg_recv_mesg({var,R}, Rm, Tl, Bef, St0) ->
- Int0 = Bef#sr{reg=put_reg(R, Bef#sr.reg)},
- Ret = fetch_reg(R, Int0#sr.reg),
- %% Int1 = clear_dead(Int0, I, Rm#l.vdb),
- Int1 = Int0,
- {Mis,Int2,St1} = match_cg(Rm, none, Int1, St0),
- {[{label,St1#cg.recv},{loop_rec,{f,Tl},Ret}|Mis],Int2,St1}.
-
-%% cg_recv_wait(Te, Tes, I, Vdb, Int2, St3) -> {[Ainstr],Aft,St}.
-
-cg_recv_wait({atom,infinity}, Tes, I, Bef, St0) ->
- %% We know that the 'after' body will never be executed.
- %% But to keep the stack and register information up to date,
- %% we will generate the code for the 'after' body, and then discard it.
- Int1 = clear_dead(Bef, I, Tes#l.vdb),
- {_,Int2,St1} = cg_block(Tes#l.ke, Tes#l.i, Tes#l.vdb,
- Int1#sr{reg=clear_regs(Int1#sr.reg)}, St0),
- {[{wait,{f,St1#cg.recv}}],Int2,St1};
-cg_recv_wait({integer,0}, Tes, _I, Bef, St0) ->
- {Tis,Int,St1} = cg_block(Tes#l.ke, Tes#l.i, Tes#l.vdb, Bef, St0),
- {[timeout|Tis],Int,St1};
-cg_recv_wait(Te, Tes, I, Bef, St0) ->
- Reg = cg_reg_arg(Te, Bef),
- %% Must have empty registers here! Bug if anything in registers.
- Int0 = clear_dead(Bef, I, Tes#l.vdb),
- {Tis,Int,St1} = cg_block(Tes#l.ke, Tes#l.i, Tes#l.vdb,
- Int0#sr{reg=clear_regs(Int0#sr.reg)}, St0),
- {[{wait_timeout,{f,St1#cg.recv},Reg},timeout] ++ Tis,Int,St1}.
-
-%% recv_next_cg(Le, Vdb, StackReg, St) -> {[Ainstr],StackReg,St}.
-%% Use adjust stack to clear stack, but only need it for Aft.
-
-recv_next_cg(Le, Vdb, Bef, St) ->
- {Sis,Aft} = adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb),
- {[{loop_rec_end,{f,St#cg.recv}}] ++ Sis,Aft,St}. %Joke
-
-%% try_cg(TryBlock, [BodyVar], TryBody, [ExcpVar], TryHandler, [Ret],
-%% Le, Vdb, StackReg, St) -> {[Ainstr],StackReg,St}.
-
-try_cg(Ta, Vs, Tb, Evs, Th, Rs, Le, Vdb, Bef, St0) ->
- {B,St1} = new_label(St0), %Body label
- {H,St2} = new_label(St1), %Handler label
- {E,St3} = new_label(St2), %End label
- TryTag = Ta#l.i,
- Int1 = Bef#sr{stk=put_catch(TryTag, Bef#sr.stk)},
- TryReg = fetch_stack({catch_tag,TryTag}, Int1#sr.stk),
- {Ais,Int2,St4} = cg(Ta, Vdb, Int1, St3#cg{break=B,in_catch=true}),
- Int3 = Int2#sr{stk=drop_catch(TryTag, Int2#sr.stk)},
- St5 = St4#cg{break=E,in_catch=St3#cg.in_catch},
- {Bis,Baft,St6} = cg(Tb, Vdb, Int3#sr{reg=load_vars(Vs, Int3#sr.reg)}, St5),
- {His,Haft,St7} = cg(Th, Vdb, Int3#sr{reg=load_vars(Evs, Int3#sr.reg)}, St6),
- Int4 = sr_merge(Baft, Haft), %Merge stack/registers
- Aft = Int4#sr{reg=load_vars(Rs, Int4#sr.reg)},
- {[{'try',TryReg,{f,H}}] ++ Ais ++
- [{label,B},{try_end,TryReg}] ++ Bis ++
- [{label,H},{try_case,TryReg}] ++ His ++
- [{label,E}],
- clear_dead(Aft, Le#l.i, Vdb),
- St7#cg{break=St0#cg.break}}.
-
-try_enter_cg(Ta, Vs, Tb, Evs, Th, Le, Vdb, Bef, St0) ->
- {B,St1} = new_label(St0), %Body label
- {H,St2} = new_label(St1), %Handler label
- TryTag = Ta#l.i,
- Int1 = Bef#sr{stk=put_catch(TryTag, Bef#sr.stk)},
- TryReg = fetch_stack({catch_tag,TryTag}, Int1#sr.stk),
- {Ais,Int2,St3} = cg(Ta, Vdb, Int1, St2#cg{break=B,in_catch=true}),
- Int3 = Int2#sr{stk=drop_catch(TryTag, Int2#sr.stk)},
- St4 = St3#cg{in_catch=St2#cg.in_catch},
- {Bis,Baft,St5} = cg(Tb, Vdb, Int3#sr{reg=load_vars(Vs, Int3#sr.reg)}, St4),
- {His,Haft,St6} = cg(Th, Vdb, Int3#sr{reg=load_vars(Evs, Int3#sr.reg)}, St5),
- Int4 = sr_merge(Baft, Haft), %Merge stack/registers
- Aft = Int4,
- {[{'try',TryReg,{f,H}}] ++ Ais ++
- [{label,B},{try_end,TryReg}] ++ Bis ++
- [{label,H},{try_case,TryReg}] ++ His,
- clear_dead(Aft, Le#l.i, Vdb),
- St6#cg{break=St0#cg.break}}.
-
-%% catch_cg(CatchBlock, Ret, Le, Vdb, Bef, St) -> {[Ainstr],Aft,St}.
-
-catch_cg(C, {var,R}, Le, Vdb, Bef, St0) ->
- {B,St1} = new_label(St0),
- CatchTag = Le#l.i,
- Int1 = Bef#sr{stk=put_catch(CatchTag, Bef#sr.stk)},
- CatchReg = fetch_stack({catch_tag,CatchTag}, Int1#sr.stk),
- {Cis,Int2,St2} = cg_block(C, Le#l.i, Le#l.vdb, Int1,
- St1#cg{break=B,in_catch=true}),
- [] = Int2#sr.reg, %Assertion.
- Aft = Int2#sr{reg=[{0,R}],stk=drop_catch(CatchTag, Int2#sr.stk)},
- {[{'catch',CatchReg,{f,B}}] ++ Cis ++
- [{label,B},{catch_end,CatchReg}],
- clear_dead(Aft, Le#l.i, Vdb),
- St2#cg{break=St1#cg.break,in_catch=St1#cg.in_catch}}.
-
-%% set_cg([Var], Constr, Le, Vdb, Bef, St) -> {[Ainstr],Aft,St}.
-%% We have to be careful how a 'set' works. First the structure is
-%% built, then it is filled and finally things can be cleared. The
-%% annotation must reflect this and make sure that the return
-%% variable is allocated first.
-%%
-%% put_list and put_map are atomic instructions, both of
-%% which can safely resuse one of the source registers as target.
-
-set_cg([{var,R}], {cons,Es}, Le, Vdb, Bef, St) ->
- [S1,S2] = cg_reg_args(Es, Bef),
- Int0 = clear_dead(Bef, Le#l.i, Vdb),
- Int1 = Int0#sr{reg=put_reg(R, Int0#sr.reg)},
- Ret = fetch_reg(R, Int1#sr.reg),
- {[{put_list,S1,S2,Ret}], Int1, St};
-set_cg([{var,R}], {binary,Segs}, Le, Vdb, Bef, #cg{bfail=Bfail}=St) ->
- %% At run-time, binaries are constructed in three stages:
- %% 1) First the size of the binary is calculated.
- %% 2) Then the binary is allocated.
- %% 3) Then each field in the binary is constructed.
- %% For simplicity, we use the target register to also hold the
- %% size of the binary. Therefore the target register must *not*
- %% be one of the source registers.
-
- %% First allocate the target register.
- Int0 = Bef#sr{reg=put_reg(R, Bef#sr.reg)},
- Target = fetch_reg(R, Int0#sr.reg),
-
- %% Also allocate a scratch register for size calculations.
- Temp = find_scratch_reg(Int0#sr.reg),
-
- %% First generate the code that constructs each field.
- Fail = {f,Bfail},
- PutCode = cg_bin_put(Segs, Fail, Bef),
- {Sis,Int1} = maybe_adjust_stack(Int0, Le#l.i, Le#l.i+1, Vdb, St),
- MaxRegs = max_reg(Bef#sr.reg),
- Aft = clear_dead(Int1, Le#l.i, Vdb),
-
- %% Now generate the complete code for constructing the binary.
- Code = cg_binary(PutCode, Target, Temp, Fail, MaxRegs, Le#l.a),
- {Sis++Code,Aft,St};
-
-%% Map: single variable key.
-set_cg([{var,R}], {map,Op,Map,[{map_pair,{var,_}=K,V}]}, Le, Vdb, Bef, St0) ->
- {Sis,Int0} = maybe_adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb, St0),
-
- SrcReg = cg_reg_arg_prefer_y(Map, Int0),
- Line = line(Le#l.a),
-
- List = [cg_reg_arg(K,Int0),cg_reg_arg(V,Int0)],
-
- Live = max_reg(Bef#sr.reg),
-
- %% The target register can reuse one of the source registers.
- Aft0 = clear_dead(Int0, Le#l.i, Vdb),
- Aft = Aft0#sr{reg=put_reg(R, Aft0#sr.reg)},
- Target = fetch_reg(R, Aft#sr.reg),
-
- {Is,St1} = set_cg_map(Line, Op, SrcReg, Target, Live, List, St0),
- {Sis++Is,Aft,St1};
-
-%% Map: (possibly) multiple literal keys.
-set_cg([{var,R}], {map,Op,Map,Es}, Le, Vdb, Bef, St0) ->
-
- %% assert key literals
- [] = [Var||{map_pair,{var,_}=Var,_} <- Es],
-
- {Sis,Int0} = maybe_adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb, St0),
- SrcReg = cg_reg_arg_prefer_y(Map, Int0),
- Line = line(Le#l.a),
-
- %% fetch registers for values to be put into the map
- Pairs = [{K,V} || {_,K,V} <- Es],
- List = flatmap(fun({K,V}) -> [K,cg_reg_arg(V,Int0)] end, Pairs),
-
- Live = max_reg(Bef#sr.reg),
-
- %% The target register can reuse one of the source registers.
- Aft0 = clear_dead(Int0, Le#l.i, Vdb),
- Aft = Aft0#sr{reg=put_reg(R, Aft0#sr.reg)},
- Target = fetch_reg(R, Aft#sr.reg),
-
- {Is,St1} = set_cg_map(Line, Op, SrcReg, Target, Live, List, St0),
- {Sis++Is,Aft,St1};
-
-%% Everything else.
-set_cg([{var,R}], Con, Le, Vdb, Bef, St) ->
- %% Find a place for the return register first.
- Int = Bef#sr{reg=put_reg(R, Bef#sr.reg)},
- Ret = fetch_reg(R, Int#sr.reg),
- Ais = case Con of
- {tuple,Es} ->
- [{put_tuple,length(Es),Ret}] ++ cg_build_args(Es, Bef);
- Other ->
- [{move,cg_reg_arg(Other, Int),Ret}]
- end,
- {Ais,clear_dead(Int, Le#l.i, Vdb),St}.
-
-
-set_cg_map(Line, Op0, SrcReg, Target, Live, List, St0) ->
- Bfail = St0#cg.bfail,
- Fail = {f,St0#cg.bfail},
- Op = case Op0 of
- assoc -> put_map_assoc;
- exact -> put_map_exact
- end,
- {OkLbl,St1} = new_label(St0),
- {BadLbl,St2} = new_label(St1),
- Is = if
- Bfail =:= 0 orelse Op =:= put_map_assoc ->
- [Line,{Op,{f,0},SrcReg,Target,Live,{list,List}}];
- true ->
- %% Ensure that Target is always set, even if
- %% the map update operation fails. That is necessary
- %% because Target may be included in a test_heap
- %% instruction.
- [Line,
- {Op,{f,BadLbl},SrcReg,Target,Live,{list,List}},
- {jump,{f,OkLbl}},
- {label,BadLbl},
- {move,{atom,ok},Target},
- {jump,Fail},
- {label,OkLbl}]
- end,
- {Is,St2}.
-
-%%%
-%%% Code generation for constructing binaries.
-%%%
-
-cg_binary([{bs_put_binary,Fail,{atom,all},U,_Flags,Src}|PutCode],
- Target, Temp, Fail, MaxRegs, Anno) ->
- Line = line(Anno),
- Live = cg_live(Target, MaxRegs),
- SzCode = cg_bitstr_size(PutCode, Target, Temp, Fail, Live),
- BinFlags = {field_flags,[]},
- Code = [Line|SzCode] ++
- [case member(single_use, Anno) of
- true ->
- {bs_private_append,Fail,Target,U,Src,BinFlags,Target};
- false ->
- {bs_append,Fail,Target,0,MaxRegs,U,Src,BinFlags,Target}
- end] ++ PutCode,
- cg_bin_opt(Code);
-cg_binary(PutCode, Target, Temp, Fail, MaxRegs, Anno) ->
- Line = line(Anno),
- Live = cg_live(Target, MaxRegs),
- {InitOp,SzCode} = cg_binary_size(PutCode, Target, Temp, Fail, Live),
-
- Code = [Line|SzCode] ++ [{InitOp,Fail,Target,0,MaxRegs,
- {field_flags,[]},Target}|PutCode],
- cg_bin_opt(Code).
-
-cg_live({x,X}, MaxRegs) when X =:= MaxRegs -> MaxRegs+1;
-cg_live({x,X}, MaxRegs) when X < MaxRegs -> MaxRegs.
-
-%% Generate code that calculate the size of the bitstr to be
-%% built in BITS.
-
-cg_bitstr_size(PutCode, Target, Temp, Fail, Live) ->
- {Bits,Es} = cg_bitstr_size_1(PutCode, 0, []),
- reverse(cg_gen_binsize(Es, Target, Temp, Fail, Live,
- [{move,{integer,Bits},Target}])).
-
-cg_bitstr_size_1([{bs_put_utf8,_,_,Src}|Next], Bits, Acc) ->
- cg_bitstr_size_1(Next, Bits, [{'*',{bs_utf8_size,Src},8}|Acc]);
-cg_bitstr_size_1([{bs_put_utf16,_,_,Src}|Next], Bits, Acc) ->
- cg_bitstr_size_1(Next, Bits, [{'*',{bs_utf16_size,Src},8}|Acc]);
-cg_bitstr_size_1([{bs_put_utf32,_,_,_}|Next], Bits, Acc) ->
- cg_bitstr_size_1(Next, Bits+32, Acc);
-cg_bitstr_size_1([{_,_,S,U,_,Src}|Next], Bits, Acc) ->
- case S of
- {integer,N} -> cg_bitstr_size_1(Next, Bits+N*U, Acc);
- {atom,all} -> cg_bitstr_size_1(Next, Bits, [{bit_size,Src}|Acc]);
- _ when U =:= 1 -> cg_bitstr_size_1(Next, Bits, [S|Acc]);
- _ -> cg_bitstr_size_1(Next, Bits, [{'*',S,U}|Acc])
- end;
-cg_bitstr_size_1([], Bits, Acc) -> {Bits,Acc}.
-
-%% Generate code that calculate the size of the bitstr to be
-%% built in BYTES or BITS (depending on what is easiest).
-
-cg_binary_size(PutCode, Target, Temp, Fail, Live) ->
- {InitInstruction,Szs} = cg_binary_size_1(PutCode, 0, []),
- SizeExpr = reverse(cg_gen_binsize(Szs, Target, Temp, Fail, Live, [{move,{integer,0},Target}])),
- {InitInstruction,SizeExpr}.
-
-cg_binary_size_1([{bs_put_utf8,_Fail,_Flags,Src}|T], Bits, Acc) ->
- cg_binary_size_1(T, Bits, [{8,{bs_utf8_size,Src}}|Acc]);
-cg_binary_size_1([{bs_put_utf16,_Fail,_Flags,Src}|T], Bits, Acc) ->
- cg_binary_size_1(T, Bits, [{8,{bs_utf16_size,Src}}|Acc]);
-cg_binary_size_1([{bs_put_utf32,_Fail,_Flags,_Src}|T], Bits, Acc) ->
- cg_binary_size_1(T, Bits+32, Acc);
-cg_binary_size_1([{_Put,_Fail,S,U,_Flags,Src}|T], Bits, Acc) ->
- cg_binary_size_2(S, U, Src, T, Bits, Acc);
-cg_binary_size_1([], Bits, Acc) ->
- Bytes = Bits div 8,
- RemBits = Bits rem 8,
- Sizes0 = sort([{1,{integer,RemBits}},{8,{integer,Bytes}}|Acc]),
- Sizes = filter(fun({_,{integer,0}}) -> false;
- (_) -> true end, Sizes0),
- case Sizes of
- [{1,_}|_] ->
- {bs_init_bits,cg_binary_bytes_to_bits(Sizes, [])};
- [{8,_}|_] ->
- {bs_init2,[E || {8,E} <- Sizes]};
- [] ->
- {bs_init_bits,[]}
- end.
-
-cg_binary_size_2({integer,N}, U, _, Next, Bits, Acc) ->
- cg_binary_size_1(Next, Bits+N*U, Acc);
-cg_binary_size_2({atom,all}, U, E, Next, Bits, Acc) ->
- if
- U rem 8 =:= 0 ->
- cg_binary_size_1(Next, Bits, [{8,{byte_size,E}}|Acc]);
- true ->
- cg_binary_size_1(Next, Bits, [{1,{bit_size,E}}|Acc])
- end;
-cg_binary_size_2(Reg, 1, _, Next, Bits, Acc) ->
- cg_binary_size_1(Next, Bits, [{1,Reg}|Acc]);
-cg_binary_size_2(Reg, 8, _, Next, Bits, Acc) ->
- cg_binary_size_1(Next, Bits, [{8,Reg}|Acc]);
-cg_binary_size_2(Reg, U, _, Next, Bits, Acc) ->
- cg_binary_size_1(Next, Bits, [{1,{'*',Reg,U}}|Acc]).
-
-cg_binary_bytes_to_bits([{8,{integer,N}}|T], Acc) ->
- cg_binary_bytes_to_bits(T, [{integer,8*N}|Acc]);
-cg_binary_bytes_to_bits([{8,{byte_size,Reg}}|T], Acc) ->
- cg_binary_bytes_to_bits(T, [{bit_size,Reg}|Acc]);
-cg_binary_bytes_to_bits([{8,Reg}|T], Acc) ->
- cg_binary_bytes_to_bits(T, [{'*',Reg,8}|Acc]);
-cg_binary_bytes_to_bits([{1,Sz}|T], Acc) ->
- cg_binary_bytes_to_bits(T, [Sz|Acc]);
-cg_binary_bytes_to_bits([], Acc) ->
- cg_binary_bytes_to_bits_1(sort(Acc)).
-
-cg_binary_bytes_to_bits_1([{integer,I},{integer,J}|T]) ->
- cg_binary_bytes_to_bits_1([{integer,I+J}|T]);
-cg_binary_bytes_to_bits_1([H|T]) ->
- [H|cg_binary_bytes_to_bits_1(T)];
-cg_binary_bytes_to_bits_1([]) -> [].
-
-cg_gen_binsize([{'*',{bs_utf8_size,Src},B}|T], Target, Temp, Fail, Live, Acc) ->
- Size = {bs_utf8_size,Fail,Src,Temp},
- Add = {bs_add,Fail,[Target,Temp,B],Target},
- cg_gen_binsize(T, Target, Temp, Fail, Live,
- [Add,Size|Acc]);
-cg_gen_binsize([{'*',{bs_utf16_size,Src},B}|T], Target, Temp, Fail, Live, Acc) ->
- Size = {bs_utf16_size,Fail,Src,Temp},
- Add = {bs_add,Fail,[Target,Temp,B],Target},
- cg_gen_binsize(T, Target, Temp, Fail, Live,
- [Add,Size|Acc]);
-cg_gen_binsize([{'*',A,B}|T], Target, Temp, Fail, Live, Acc) ->
- cg_gen_binsize(T, Target, Temp, Fail, Live,
- [{bs_add,Fail,[Target,A,B],Target}|Acc]);
-cg_gen_binsize([{bit_size,B}|T], Target, Temp, Fail, Live, Acc) ->
- cg_gen_binsize([Temp|T], Target, Temp, Fail, Live,
- [{gc_bif,bit_size,Fail,Live,[B],Temp}|Acc]);
-cg_gen_binsize([{byte_size,B}|T], Target, Temp, Fail, Live, Acc) ->
- cg_gen_binsize([Temp|T], Target, Temp, Fail, Live,
- [{gc_bif,byte_size,Fail,Live,[B],Temp}|Acc]);
-cg_gen_binsize([{bs_utf8_size,B}|T], Target, Temp, Fail, Live, Acc) ->
- cg_gen_binsize([Temp|T], Target, Temp, Fail, Live,
- [{bs_utf8_size,Fail,B,Temp}|Acc]);
-cg_gen_binsize([{bs_utf16_size,B}|T], Target, Temp, Fail, Live, Acc) ->
- cg_gen_binsize([Temp|T], Target, Temp, Fail, Live,
- [{bs_utf16_size,Fail,B,Temp}|Acc]);
-cg_gen_binsize([E0|T], Target, Temp, Fail, Live, Acc) ->
- cg_gen_binsize(T, Target, Temp, Fail, Live,
- [{bs_add,Fail,[Target,E0,1],Target}|Acc]);
-cg_gen_binsize([], _, _, _, _, Acc) -> Acc.
-
-
-%% cg_bin_opt(Code0) -> Code
-%% Optimize the size calculations for binary construction.
-
-cg_bin_opt([{move,Size,D},{bs_append,Fail,D,Extra,Regs,U,Bin,Flags,D}|Is]) ->
- cg_bin_opt([{bs_append,Fail,Size,Extra,Regs,U,Bin,Flags,D}|Is]);
-cg_bin_opt([{move,Size,D},{bs_private_append,Fail,D,U,Bin,Flags,D}|Is]) ->
- cg_bin_opt([{bs_private_append,Fail,Size,U,Bin,Flags,D}|Is]);
-cg_bin_opt([{move,{integer,0},D},{bs_add,_,[D,{integer,_}=S,1],Dst}|Is]) ->
- cg_bin_opt([{move,S,Dst}|Is]);
-cg_bin_opt([{move,{integer,0},D},{bs_add,Fail,[D,S,U],Dst}|Is]) ->
- cg_bin_opt([{bs_add,Fail,[{integer,0},S,U],Dst}|Is]);
-cg_bin_opt([{move,{integer,Bytes},D},{Op,Fail,D,Extra,Regs,Flags,D}|Is])
- when Op =:= bs_init2; Op =:= bs_init_bits ->
- cg_bin_opt([{Op,Fail,Bytes,Extra,Regs,Flags,D}|Is]);
-cg_bin_opt([{move,Src1,Dst},{bs_add,Fail,[Dst,Src2,U],Dst}|Is]) ->
- cg_bin_opt([{bs_add,Fail,[Src1,Src2,U],Dst}|Is]);
-cg_bin_opt([I|Is]) ->
- [I|cg_bin_opt(Is)];
-cg_bin_opt([]) -> [].
-
-cg_bin_put({bin_seg,[],S0,U,T,Fs,[E0,Next]}, Fail, Bef) ->
- S1 = cg_reg_arg(S0, Bef),
- E1 = cg_reg_arg(E0, Bef),
- {Format,Op} = case T of
- integer -> {plain,bs_put_integer};
- utf8 -> {utf,bs_put_utf8};
- utf16 -> {utf,bs_put_utf16};
- utf32 -> {utf,bs_put_utf32};
- binary -> {plain,bs_put_binary};
- float -> {plain,bs_put_float}
- end,
- case Format of
- plain ->
- [{Op,Fail,S1,U,{field_flags,Fs},E1}|cg_bin_put(Next, Fail, Bef)];
- utf ->
- [{Op,Fail,{field_flags,Fs},E1}|cg_bin_put(Next, Fail, Bef)]
- end;
-cg_bin_put({bin_end,[]}, _, _) -> [].
-
-cg_build_args(As, Bef) ->
- [{put,cg_reg_arg(A, Bef)} || A <- As].
-
-%% return_cg([Val], Le, Vdb, Bef, St) -> {[Ainstr],Aft,St}.
-%% break_cg([Val], Le, Vdb, Bef, St) -> {[Ainstr],Aft,St}.
-%% These are very simple, just put return/break values in registers
-%% from 0, then return/break. Use the call setup to clean up stack,
-%% but must clear registers to ensure sr_merge works correctly.
-
-return_cg(Rs, Le, Vdb, Bef, St) ->
- {Ms,Int} = cg_setup_call(Rs, Bef, Le#l.i, Vdb),
- {Ms ++ [return],Int#sr{reg=clear_regs(Int#sr.reg)},St}.
-
-break_cg(Bs, Le, Vdb, Bef, St) ->
- {Ms,Int} = cg_setup_call(Bs, Bef, Le#l.i, Vdb),
- {Ms ++ [{jump,{f,St#cg.break}}],
- Int#sr{reg=clear_regs(Int#sr.reg)},St}.
-
-guard_break_cg(Bs, Locked, #l{i=I}, Vdb, #sr{reg=Reg0}=Bef, St) ->
- RegLocked = get_locked_regs(Reg0, Locked),
- #sr{reg=Reg1} = Int = clear_dead(Bef#sr{reg=RegLocked}, I, Vdb),
- Reg2 = trim_free(Reg1),
- NumLocked = length(Reg2),
- Moves0 = gen_moves(Bs, Bef, NumLocked, []),
- Moves = order_moves(Moves0, find_scratch_reg(RegLocked)),
- {BreakVars,_} = mapfoldl(fun(_, RegNum) ->
- {{RegNum,gbreakvar},RegNum+1}
- end, length(Reg2), Bs),
- Reg = Reg2 ++ BreakVars,
- Aft = Int#sr{reg=Reg},
- {Moves ++ [{jump,{f,St#cg.break}}],Aft,St}.
-
-get_locked_regs([R|Rs0], Preserve) ->
- case {get_locked_regs(Rs0, Preserve),R} of
- {[],{_,V}} ->
- case lists:member(V, Preserve) of
- true -> [R];
- false -> []
- end;
- {[],_} ->
- [];
- {Rs,_} ->
- [R|Rs]
- end;
-get_locked_regs([], _) -> [].
-
-%% cg_reg_arg(Arg0, Info) -> Arg
-%% cg_reg_args([Arg0], Info) -> [Arg]
-%% Convert argument[s] into registers. Literal values are returned unchanged.
-
-cg_reg_args(As, Bef) -> [cg_reg_arg(A, Bef) || A <- As].
-
-cg_reg_arg({var,V}, Bef) -> fetch_var(V, Bef);
-cg_reg_arg(Literal, _) -> Literal.
-
-cg_reg_arg_prefer_y({var,V}, Bef) -> fetch_var_prefer_y(V, Bef);
-cg_reg_arg_prefer_y(Literal, _) -> Literal.
-
-%% cg_setup_call([Arg], Bef, Cur, Vdb) -> {[Instr],Aft}.
-%% Do the complete setup for a call/enter.
-
-cg_setup_call(As, Bef, I, Vdb) ->
- {Ms,Int0} = cg_call_args(As, Bef, I, Vdb),
- %% Have set up arguments, can now clean up, compress and save to stack.
- Int1 = Int0#sr{stk=clear_dead_stk(Int0#sr.stk, I, Vdb),res=[]},
- {Sis,Int2} = adjust_stack(Int1, I, I+1, Vdb),
- {Ms ++ Sis,Int2}.
-
-%% cg_call_args([Arg], SrState) -> {[Instr],SrState}.
-%% Setup the arguments to a call/enter/bif. Put the arguments into
-%% consecutive registers starting at {x,0} moving any data which
-%% needs to be saved. Return a modified SrState structure with the
-%% new register contents. N.B. the resultant register info will
-%% contain non-variable values when there are non-variable values.
-%%
-%% This routine is complicated by unsaved values in x registers.
-%% We'll move away any unsaved values that are in the registers
-%% to be overwritten by the arguments.
-
-cg_call_args(As, Bef, I, Vdb) ->
- Regs0 = load_arg_regs(Bef#sr.reg, As),
- Unsaved = unsaved_registers(Regs0, Bef#sr.stk, I, I+1, Vdb),
- {UnsavedMoves,Regs} = move_unsaved(Unsaved, Bef#sr.reg, Regs0),
- Moves0 = gen_moves(As, Bef),
- Moves = order_moves(Moves0, find_scratch_reg(Regs)),
- {UnsavedMoves ++ Moves,Bef#sr{reg=Regs}}.
-
-%% load_arg_regs([Reg], Arguments) -> [Reg]
-%% Update the register descriptor to include the arguments (from {x,0}
-%% and upwards). Values in argument register are overwritten.
-%% Values in x registers above the arguments are preserved.
-
-load_arg_regs(Regs, As) -> load_arg_regs(Regs, As, 0).
-
-load_arg_regs([_|Rs], [{var,V}|As], I) -> [{I,V}|load_arg_regs(Rs, As, I+1)];
-load_arg_regs([_|Rs], [A|As], I) -> [{I,A}|load_arg_regs(Rs, As, I+1)];
-load_arg_regs([], [{var,V}|As], I) -> [{I,V}|load_arg_regs([], As, I+1)];
-load_arg_regs([], [A|As], I) -> [{I,A}|load_arg_regs([], As, I+1)];
-load_arg_regs(Rs, [], _) -> Rs.
-
-%% Returns the variables must be saved and are currently in the
-%% x registers that are about to be overwritten by the arguments.
-
-unsaved_registers(Regs, Stk, Fb, Lf, Vdb) ->
- [V || {V,F,L} <- Vdb,
- F < Fb,
- L >= Lf,
- not on_stack(V, Stk),
- not in_reg(V, Regs)].
-
-in_reg(V, Regs) -> keymember(V, 2, Regs).
-
-%% Move away unsaved variables from the registers that are to be
-%% overwritten by the arguments.
-move_unsaved(Vs, OrigRegs, NewRegs) ->
- move_unsaved(Vs, OrigRegs, NewRegs, []).
-
-move_unsaved([V|Vs], OrigRegs, NewRegs0, Acc) ->
- NewRegs = put_reg(V, NewRegs0),
- Src = fetch_reg(V, OrigRegs),
- Dst = fetch_reg(V, NewRegs),
- move_unsaved(Vs, OrigRegs, NewRegs, [{move,Src,Dst}|Acc]);
-move_unsaved([], _, Regs, Acc) -> {Acc,Regs}.
-
-%% gen_moves(As, Sr)
-%% Generate the basic move instruction to move the arguments
-%% to their proper registers. The list will be sorted on
-%% destinations. (I.e. the move to {x,0} will be first --
-%% see the comment to order_moves/2.)
-
-gen_moves(As, Sr) -> gen_moves(As, Sr, 0, []).
-
-gen_moves([{var,V}|As], Sr, I, Acc) ->
- case fetch_var(V, Sr) of
- {x,I} -> gen_moves(As, Sr, I+1, Acc);
- Reg -> gen_moves(As, Sr, I+1, [{move,Reg,{x,I}}|Acc])
- end;
-gen_moves([A|As], Sr, I, Acc) ->
- gen_moves(As, Sr, I+1, [{move,A,{x,I}}|Acc]);
-gen_moves([], _, _, Acc) -> lists:keysort(3, Acc).
-
-%% order_moves([Move], ScratchReg) -> [Move]
-%% Orders move instruction so that source registers are not
-%% destroyed before they are used. If there are cycles
-%% (such as {move,{x,0},{x,1}}, {move,{x,1},{x,1}}),
-%% the scratch register is used to break up the cycle.
-%% If possible, the first move of the input list is placed
-%% last in the result list (to make the move to {x,0} occur
-%% just before the call to allow the Beam loader to coalesce
-%% the instructions).
-
-order_moves(Ms, Scr) -> order_moves(Ms, Scr, []).
-
-order_moves([{move,_,_}=M|Ms0], ScrReg, Acc0) ->
- {Chain,Ms} = collect_chain(Ms0, [M], ScrReg),
- Acc = reverse(Chain, Acc0),
- order_moves(Ms, ScrReg, Acc);
-order_moves([], _, Acc) -> Acc.
-
-collect_chain(Ms, Path, ScrReg) ->
- collect_chain(Ms, Path, [], ScrReg).
-
-collect_chain([{move,Src,Same}=M|Ms0], [{move,Same,_}|_]=Path, Others, ScrReg) ->
- case lists:keyfind(Src, 3, Path) of
- false ->
- collect_chain(reverse(Others, Ms0), [M|Path], [], ScrReg);
- _ -> % We have a cycle.
- {break_up_cycle(M, Path, ScrReg),reverse(Others, Ms0)}
- end;
-collect_chain([M|Ms], Path, Others, ScrReg) ->
- collect_chain(Ms, Path, [M|Others], ScrReg);
-collect_chain([], Path, Others, _) ->
- {Path,Others}.
-
-break_up_cycle({move,Src,_}=M, Path, ScrReg) ->
- [{move,ScrReg,Src},M|break_up_cycle1(Src, Path, ScrReg)].
-
-break_up_cycle1(Dst, [{move,Src,Dst}|Path], ScrReg) ->
- [{move,Src,ScrReg}|Path];
-break_up_cycle1(Dst, [M|Path], LastMove) ->
- [M|break_up_cycle1(Dst, Path, LastMove)].
-
-%% clear_dead(Sr, Until, Vdb) -> Aft.
-%% Remove all variables in Sr which have died AT ALL so far.
-
-clear_dead(Sr, Until, Vdb) ->
- Sr#sr{reg=clear_dead_reg(Sr, Until, Vdb),
- stk=clear_dead_stk(Sr#sr.stk, Until, Vdb)}.
-
-clear_dead_reg(Sr, Until, Vdb) ->
- Reg = [case R of
- {_I,V} = IV ->
- case vdb_find(V, Vdb) of
- {V,_,L} when L > Until -> IV;
- _ -> free %Remove anything else
- end;
- {reserved,_I,_V} = Reserved -> Reserved;
- free -> free
- end || R <- Sr#sr.reg],
- reserve(Sr#sr.res, Reg, Sr#sr.stk).
-
-clear_dead_stk(Stk, Until, Vdb) ->
- [case S of
- {V} = T ->
- case vdb_find(V, Vdb) of
- {V,_,L} when L > Until -> T;
- _ -> dead %Remove anything else
- end;
- free -> free;
- dead -> dead
- end || S <- Stk].
-
-
-%% sr_merge(Sr1, Sr2) -> Sr.
-%% Merge two stack/register states keeping the longest of both stack
-%% and register. Perform consistency check on both, elements must be
-%% the same. Allow frame size 'void' to make easy creation of
-%% "empty" frame.
-
-sr_merge(#sr{reg=R1,stk=S1,res=[]}, #sr{reg=R2,stk=S2,res=[]}) ->
- #sr{reg=longest(R1, R2),stk=longest(S1, S2),res=[]};
-sr_merge(void, S2) -> S2#sr{res=[]}.
-
-longest([H|T1], [H|T2]) -> [H|longest(T1, T2)];
-longest([dead|T1], [free|T2]) -> [dead|longest(T1, T2)];
-longest([free|T1], [dead|T2]) -> [dead|longest(T1, T2)];
-longest([dead|_] = L, []) -> L;
-longest([], [dead|_] = L) -> L;
-longest([free|_] = L, []) -> L;
-longest([], [free|_] = L) -> L;
-longest([], []) -> [].
-
-trim_free([R|Rs0]) ->
- case {trim_free(Rs0),R} of
- {[],free} -> [];
- {Rs,R} -> [R|Rs]
- end;
-trim_free([]) -> [].
-
-%% maybe_adjust_stack(Bef, FirstBefore, LastFrom, Vdb, St) -> {[Ainstr],Aft}.
-%% Adjust the stack, but only if the code is inside a catch and not
-%% inside a guard. Use this funtion before instructions that may
-%% cause an exception.
-
-maybe_adjust_stack(Bef, Fb, Lf, Vdb, St) ->
- case St of
- #cg{in_catch=true,bfail=0} ->
- adjust_stack(Bef, Fb, Lf, Vdb);
- #cg{} ->
- {[],Bef}
- end.
-
-%% adjust_stack(Bef, FirstBefore, LastFrom, Vdb) -> {[Ainstr],Aft}.
-%% Do complete stack adjustment by compressing stack and adding
-%% variables to be saved. Try to optimise ordering on stack by
-%% having reverse order to their lifetimes.
-%%
-%% In Beam, there is a fixed stack frame and no need to do stack compression.
-
-adjust_stack(Bef, Fb, Lf, Vdb) ->
- Stk0 = Bef#sr.stk,
- {Stk1,Saves} = save_stack(Stk0, Fb, Lf, Vdb),
- {saves(Saves, Bef#sr.reg, Stk1),
- Bef#sr{stk=Stk1}}.
-
-%% save_stack(Stack, FirstBefore, LastFrom, Vdb) -> {[SaveVar],NewStack}.
-%% Save variables which are used past current point and which are not
-%% already on the stack.
-
-save_stack(Stk0, Fb, Lf, Vdb) ->
- %% New variables that are in use but not on stack.
- New = [VFL || {V,F,L} = VFL <- Vdb,
- F < Fb,
- L >= Lf,
- not on_stack(V, Stk0)],
- %% Add new variables that are not just dropped immediately.
- %% N.B. foldr works backwards from the end!!
- Saves = [V || {V,_,_} <- keysort(3, New)],
- Stk1 = foldr(fun (V, Stk) -> put_stack(V, Stk) end, Stk0, Saves),
- {Stk1,Saves}.
-
-%% saves([SaveVar], Reg, Stk) -> [{move,Reg,Stk}].
-%% Generate move instructions to save variables onto stack. The
-%% stack/reg info used is that after the new stack has been made.
-
-saves(Ss, Reg, Stk) ->
- [{move,fetch_reg(V, Reg),fetch_stack(V, Stk)} || V <- Ss].
-
-%% fetch_var(VarName, StkReg) -> r{R} | sp{Sp}.
-%% find_var(VarName, StkReg) -> ok{r{R} | sp{Sp}} | error.
-%% Fetch/find a variable in either the registers or on the
-%% stack. Fetch KNOWS it's there.
-
-fetch_var(V, Sr) ->
- case find_reg(V, Sr#sr.reg) of
- {ok,R} -> R;
- error -> fetch_stack(V, Sr#sr.stk)
- end.
-
-fetch_var_prefer_y(V, #sr{reg=Reg,stk=Stk}) ->
- case find_stack(V, Stk) of
- {ok,R} -> R;
- error -> fetch_reg(V, Reg)
- end.
-
-load_vars(Vs, Regs) ->
- foldl(fun ({var,V}, Rs) -> put_reg(V, Rs) end, Regs, Vs).
-
-%% put_reg(Val, Regs) -> Regs.
-%% find_reg(Val, Regs) -> {ok,r{R}} | error.
-%% fetch_reg(Val, Regs) -> r{R}.
-%% Functions to interface the registers.
-
-% put_regs(Vs, Rs) -> foldl(fun put_reg/2, Rs, Vs).
-
-put_reg(V, Rs) -> put_reg_1(V, Rs, 0).
-
-put_reg_1(V, [free|Rs], I) -> [{I,V}|Rs];
-put_reg_1(V, [{reserved,I,V}|Rs], I) -> [{I,V}|Rs];
-put_reg_1(V, [R|Rs], I) -> [R|put_reg_1(V, Rs, I+1)];
-put_reg_1(V, [], I) -> [{I,V}].
-
-fetch_reg(V, [{I,V}|_]) -> {x,I};
-fetch_reg(V, [_|SRs]) -> fetch_reg(V, SRs).
-
-find_reg(V, [{I,V}|_]) -> {ok,{x,I}};
-find_reg(V, [_|SRs]) -> find_reg(V, SRs);
-find_reg(_, []) -> error.
-
-%% For the bit syntax, we need a scratch register if we are constructing
-%% a binary that will not be used.
-
-find_scratch_reg(Rs) -> find_scratch_reg(Rs, 0).
-
-find_scratch_reg([free|_], I) -> {x,I};
-find_scratch_reg([_|Rs], I) -> find_scratch_reg(Rs, I+1);
-find_scratch_reg([], I) -> {x,I}.
-
-replace_reg_contents(Old, New, [{I,Old}|Rs]) -> [{I,New}|Rs];
-replace_reg_contents(Old, New, [R|Rs]) -> [R|replace_reg_contents(Old, New, Rs)].
-
-%%clear_regs(Regs) -> map(fun (R) -> free end, Regs).
-clear_regs(_) -> [].
-
-max_reg(Regs) ->
- foldl(fun ({I,_}, _) -> I;
- (_, Max) -> Max end,
- -1, Regs) + 1.
-
-%% put_stack(Val, [{Val}]) -> [{Val}].
-%% fetch_stack(Var, Stk) -> sp{S}.
-%% find_stack(Var, Stk) -> ok{sp{S}} | error.
-%% Functions to interface the stack.
-
-put_stack(Val, []) -> [{Val}];
-put_stack(Val, [dead|Stk]) -> [{Val}|Stk];
-put_stack(Val, [free|Stk]) -> [{Val}|Stk];
-put_stack(Val, [NotFree|Stk]) -> [NotFree|put_stack(Val, Stk)].
-
-put_stack_carefully(Val, Stk0) ->
- try
- put_stack_carefully1(Val, Stk0)
- catch
- throw:error ->
- error
- end.
-
-put_stack_carefully1(_, []) -> throw(error);
-put_stack_carefully1(Val, [dead|Stk]) -> [{Val}|Stk];
-put_stack_carefully1(Val, [free|Stk]) -> [{Val}|Stk];
-put_stack_carefully1(Val, [NotFree|Stk]) ->
- [NotFree|put_stack_carefully1(Val, Stk)].
-
-fetch_stack(Var, Stk) -> fetch_stack(Var, Stk, 0).
-
-fetch_stack(V, [{V}|_], I) -> {yy,I};
-fetch_stack(V, [_|Stk], I) -> fetch_stack(V, Stk, I+1).
-
-find_stack(Var, Stk) -> find_stack(Var, Stk, 0).
-
-find_stack(V, [{V}|_], I) -> {ok,{yy,I}};
-find_stack(V, [_|Stk], I) -> find_stack(V, Stk, I+1);
-find_stack(_, [], _) -> error.
-
-on_stack(V, Stk) -> keymember(V, 1, Stk).
-
-is_register({x,_}) -> true;
-is_register({yy,_}) -> true;
-is_register(_) -> false.
-
-%% put_catch(CatchTag, Stack) -> Stack'
-%% drop_catch(CatchTag, Stack) -> Stack'
-%% Special interface for putting and removing catch tags, to ensure that
-%% catches nest properly. Also used for try tags.
-
-put_catch(Tag, Stk0) -> put_catch(Tag, reverse(Stk0), []).
-
-put_catch(Tag, [], Stk) ->
- put_stack({catch_tag,Tag}, Stk);
-put_catch(Tag, [{{catch_tag,_}}|_]=RevStk, Stk) ->
- reverse(RevStk, put_stack({catch_tag,Tag}, Stk));
-put_catch(Tag, [Other|Stk], Acc) ->
- put_catch(Tag, Stk, [Other|Acc]).
-
-drop_catch(Tag, [{{catch_tag,Tag}}|Stk]) -> [free|Stk];
-drop_catch(Tag, [Other|Stk]) -> [Other|drop_catch(Tag, Stk)].
-
-%% new_label(St) -> {L,St}.
-
-new_label(#cg{lcount=Next}=St) ->
- {Next,St#cg{lcount=Next+1}}.
-
-%% line(Le) -> {line,[] | {location,File,Line}}
-%% Create a line instruction, containing information about
-%% the current filename and line number. A line information
-%% instruction should be placed before any operation that could
-%% cause an exception.
-
-line(#l{a=Anno}) ->
- line(Anno);
-line([Line,{file,Name}]) when is_integer(Line) ->
- line_1(Name, Line);
-line([_|_]=A) ->
- {Name,Line} = find_loc(A, no_file, 0),
- line_1(Name, Line);
-line([]) ->
- {line,[]}.
-
-line_1(no_file, _) ->
- {line,[]};
-line_1(_, 0) ->
- %% Missing line number or line number 0.
- {line,[]};
-line_1(Name, Line) ->
- {line,[{location,Name,Line}]}.
-
-find_loc([Line|T], File, _) when is_integer(Line) ->
- find_loc(T, File, Line);
-find_loc([{file,File}|T], _, Line) ->
- find_loc(T, File, Line);
-find_loc([_|T], File, Line) ->
- find_loc(T, File, Line);
-find_loc([], File, Line) -> {File,Line}.
-
-flatmapfoldl(F, Accu0, [Hd|Tail]) ->
- {R,Accu1} = F(Hd, Accu0),
- {Rs,Accu2} = flatmapfoldl(F, Accu1, Tail),
- {R++Rs,Accu2};
-flatmapfoldl(_, Accu, []) -> {[],Accu}.
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index ae650546e5..3699c9d22e 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -228,7 +228,8 @@ function({function,_,Name,Arity,Cs0}, Ws0, File, Opts) ->
body(Cs0, Name, Arity, St0) ->
Anno = lineno_anno(element(2, hd(Cs0)), St0),
- {Args,St1} = new_vars(Anno, Arity, St0),
+ {Args0,St1} = new_vars(Anno, Arity, St0),
+ Args = reverse(Args0), %Nicer order
case clauses(Cs0, St1) of
{Cs1,[],St2} ->
{Ps,St3} = new_vars(Arity, St2), %Need new variables here
@@ -328,14 +329,16 @@ gexpr({protect,Line,Arg}, Bools0, St0) ->
Anno = lineno_anno(Line, St),
{#iprotect{anno=#a{anno=Anno},body=Eps++[E]},[],Bools0,St}
end;
-gexpr({op,L,'andalso',E1,E2}, Bools, St0) ->
+gexpr({op,_,'andalso',_,_}=E0, Bools, St0) ->
+ {op,L,'andalso',E1,E2} = right_assoc(E0, 'andalso'),
Anno = lineno_anno(L, St0),
{#c_var{name=V0},St} = new_var(Anno, St0),
V = {var,L,V0},
False = {atom,L,false},
E = make_bool_switch_guard(L, E1, V, E2, False),
gexpr(E, Bools, St);
-gexpr({op,L,'orelse',E1,E2}, Bools, St0) ->
+gexpr({op,_,'orelse',_,_}=E0, Bools, St0) ->
+ {op,L,'orelse',E1,E2} = right_assoc(E0, 'orelse'),
Anno = lineno_anno(L, St0),
{#c_var{name=V0},St} = new_var(Anno, St0),
V = {var,L,V0},
@@ -764,14 +767,16 @@ expr({op,_,'++',{lc,Llc,E,Qs0},More}, St0) ->
{Qs,St2} = preprocess_quals(Llc, Qs0, St1),
{Y,Yps,St} = lc_tq(Llc, E, Qs, Mc, St2),
{Y,Mps++Yps,St};
-expr({op,L,'andalso',E1,E2}, St0) ->
+expr({op,_,'andalso',_,_}=E0, St0) ->
+ {op,L,'andalso',E1,E2} = right_assoc(E0, 'andalso'),
Anno = lineno_anno(L, St0),
{#c_var{name=V0},St} = new_var(Anno, St0),
V = {var,L,V0},
False = {atom,L,false},
E = make_bool_switch(L, E1, V, E2, False, St0),
expr(E, St);
-expr({op,L,'orelse',E1,E2}, St0) ->
+expr({op,_,'orelse',_,_}=E0, St0) ->
+ {op,L,'orelse',E1,E2} = right_assoc(E0, 'orelse'),
Anno = lineno_anno(L, St0),
{#c_var{name=V0},St} = new_var(Anno, St0),
V = {var,L,V0},
@@ -920,8 +925,9 @@ try_exception(Ecs0, St0) ->
%% Note that Tag is not needed for rethrow - it is already in Info.
{Evs,St1} = new_vars(3, St0), % Tag, Value, Info
{Ecs1,Ceps,St2} = clauses(Ecs0, St1),
+ Ecs2 = try_build_stacktrace(Ecs1, hd(Evs)),
[_,Value,Info] = Evs,
- LA = case Ecs1 of
+ LA = case Ecs2 of
[] -> [];
[C|_] -> get_lineno_anno(C)
end,
@@ -930,7 +936,7 @@ try_exception(Ecs0, St0) ->
body=[#iprimop{anno=#a{}, %Must have an #a{}
name=#c_literal{val=raise},
args=[Info,Value]}]},
- Hs = [#icase{anno=#a{anno=LA},args=[c_tuple(Evs)],clauses=Ecs1,fc=Ec}],
+ Hs = [#icase{anno=#a{anno=LA},args=[c_tuple(Evs)],clauses=Ecs2,fc=Ec}],
{Evs,Ceps++Hs,St2}.
try_after(As, St0) ->
@@ -946,6 +952,25 @@ try_after(As, St0) ->
Hs = [#icase{anno=#a{},args=[c_tuple(Evs)],clauses=[],fc=Ec}],
{Evs,Hs,St1}.
+try_build_stacktrace([#iclause{pats=Ps0,body=B0}=C0|Cs], RawStk) ->
+ [#c_tuple{es=[Class,Exc,Stk]}=Tup] = Ps0,
+ case Stk of
+ #c_var{name='_'} ->
+ %% Stacktrace variable is not used. Nothing to do.
+ [C0|try_build_stacktrace(Cs, RawStk)];
+ _ ->
+ %% Add code to build the stacktrace.
+ Ps = [Tup#c_tuple{es=[Class,Exc,RawStk]}],
+ Call = #iprimop{anno=#a{},
+ name=#c_literal{val=build_stacktrace},
+ args=[RawStk]},
+ Iset = #iset{var=Stk,arg=Call},
+ B = [Iset|B0],
+ C = C0#iclause{pats=Ps,body=B},
+ [C|try_build_stacktrace(Cs, RawStk)]
+ end;
+try_build_stacktrace([], _) -> [].
+
%% expr_bin([ArgExpr], St) -> {[Arg],[PreExpr],St}.
%% Flatten the arguments of a bin. Do this straight left to right!
%% Note that ibinary needs to have its annotation wrapped in a #a{}
@@ -1132,7 +1157,7 @@ fun_tq(Cs0, L, St0, NameInfo) ->
%% lc_tq(Line, Exp, [Qualifier], Mc, State) -> {LetRec,[PreExp],State}.
%% This TQ from Simon PJ pp 127-138.
-lc_tq(Line, E, [#igen{anno=GAnno,ceps=Ceps,
+lc_tq(Line, E, [#igen{anno=#a{anno=GA}=GAnno,ceps=Ceps,
acc_pat=AccPat,acc_guard=AccGuard,
skip_pat=SkipPat,tail=Tail,tail_pat=TailPat,
arg={Pre,Arg}}|Qs], Mc, St0) ->
@@ -1142,7 +1167,7 @@ lc_tq(Line, E, [#igen{anno=GAnno,ceps=Ceps,
F = #c_var{anno=LA,name={Name,1}},
Nc = #iapply{anno=GAnno,op=F,args=[Tail]},
{Var,St2} = new_var(St1),
- Fc = function_clause([Var], LA, {Name,1}),
+ Fc = function_clause([Var], GA, {Name,1}),
TailClause = #iclause{anno=LAnno,pats=[TailPat],guard=[],body=[Mc]},
Cs0 = case {AccPat,AccGuard} of
{SkipPat,[]} ->
@@ -1165,9 +1190,9 @@ lc_tq(Line, E, [#igen{anno=GAnno,ceps=Ceps,
body=Lps ++ [Lc]}|Cs0],
St3}
end,
- Fun = #ifun{anno=LAnno,id=[],vars=[Var],clauses=Cs,fc=Fc},
- {#iletrec{anno=LAnno#a{anno=[list_comprehension|LA]},defs=[{{Name,1},Fun}],
- body=Pre ++ [#iapply{anno=LAnno,op=F,args=[Arg]}]},
+ Fun = #ifun{anno=GAnno,id=[],vars=[Var],clauses=Cs,fc=Fc},
+ {#iletrec{anno=GAnno#a{anno=[list_comprehension|GA]},defs=[{{Name,1},Fun}],
+ body=Pre ++ [#iapply{anno=GAnno,op=F,args=[Arg]}]},
Ceps,St4};
lc_tq(Line, E, [#ifilter{}=Filter|Qs], Mc, St) ->
filter_tq(Line, E, Filter, Mc, St, Qs, fun lc_tq/5);
@@ -1481,7 +1506,7 @@ bc_initial_size(E0, Q, St0) ->
end.
bc_elem_size({bin,_,El}, St0) ->
- case bc_elem_size_1(El, 0, []) of
+ case bc_elem_size_1(El, ordsets:new(), 0, []) of
{Bits,[]} ->
{#c_literal{val=Bits},[],[],St0};
{Bits,Vars0} ->
@@ -1495,19 +1520,33 @@ bc_elem_size(_, _) ->
throw(impossible).
bc_elem_size_1([{bin_element,_,{string,_,String},{integer,_,N},_}=El|Es],
- Bits, Vars) ->
+ DefVars, Bits, SizeVars) ->
U = get_unit(El),
- bc_elem_size_1(Es, Bits+U*N*length(String), Vars);
-bc_elem_size_1([{bin_element,_,_,{integer,_,N},_}=El|Es], Bits, Vars) ->
+ bc_elem_size_1(Es, DefVars, Bits+U*N*length(String), SizeVars);
+bc_elem_size_1([{bin_element,_,Expr,{integer,_,N},_}=El|Es],
+ DefVars0, Bits, SizeVars) ->
U = get_unit(El),
- bc_elem_size_1(Es, Bits+U*N, Vars);
-bc_elem_size_1([{bin_element,_,_,{var,_,Var},_}=El|Es], Bits, Vars) ->
- U = get_unit(El),
- bc_elem_size_1(Es, Bits, [{U,#c_var{name=Var}}|Vars]);
-bc_elem_size_1([_|_], _, _) ->
+ DefVars = bc_elem_size_def_var(Expr, DefVars0),
+ bc_elem_size_1(Es, DefVars, Bits+U*N, SizeVars);
+bc_elem_size_1([{bin_element,_,Expr,{var,_,Src},_}=El|Es],
+ DefVars0, Bits, SizeVars) ->
+ case ordsets:is_element(Src, DefVars0) of
+ false ->
+ U = get_unit(El),
+ DefVars = bc_elem_size_def_var(Expr, DefVars0),
+ bc_elem_size_1(Es, DefVars, Bits, [{U,#c_var{name=Src}}|SizeVars]);
+ true ->
+ throw(impossible)
+ end;
+bc_elem_size_1([_|_], _, _, _) ->
throw(impossible);
-bc_elem_size_1([], Bits, Vars) ->
- {Bits,Vars}.
+bc_elem_size_1([], _DefVars, Bits, SizeVars) ->
+ {Bits,SizeVars}.
+
+bc_elem_size_def_var({var,_,Var}, DefVars) ->
+ ordsets:add_element(Var, DefVars);
+bc_elem_size_def_var(_Expr, DefVars) ->
+ DefVars.
bc_elem_size_combine([{U,V}|T], U, UVars, Acc) ->
bc_elem_size_combine(T, U, [V|UVars], Acc);
@@ -1985,7 +2024,7 @@ new_fun_name(Type, #core{fcount=C}=St) ->
%% new_var_name(State) -> {VarName,State}.
new_var_name(#core{vcount=C}=St) ->
- {list_to_atom("@c" ++ integer_to_list(C)),St#core{vcount=C + 1}}.
+ {C,St#core{vcount=C + 1}}.
%% new_var(State) -> {{var,Name},State}.
%% new_var(LineAnno, State) -> {{var,Name},State}.
@@ -2020,6 +2059,11 @@ fail_clause(Pats, Anno, Arg) ->
body=[#iprimop{anno=#a{anno=Anno},name=#c_literal{val=match_fail},
args=[Arg]}]}.
+%% Optimization for Dialyzer.
+right_assoc({op,L1,Op,{op,L2,Op,E1,E2},E3}, Op) ->
+ right_assoc({op,L2,Op,E1,{op,L1,Op,E2,E3}}, Op);
+right_assoc(E, _Op) -> E.
+
annotate_tuple(A, Es, St) ->
case member(dialyzer, St#core.opts) of
true ->
@@ -2462,9 +2506,11 @@ cexpr(#icase{anno=A,args=Largs,clauses=Lcs,fc=Lfc}, As, St0) ->
cexpr(#ireceive1{anno=A,clauses=Lcs}, As, St0) ->
Exp = intersection(A#a.ns, As), %Exports
{Ccs,St1} = cclauses(Lcs, Exp, St0),
+ True = #c_literal{val=true},
+ Action = core_lib:make_values(lists:duplicate(1+length(Exp), True)),
{#c_receive{anno=A#a.anno,
clauses=Ccs,
- timeout=#c_literal{val=infinity},action=#c_literal{val=true}},
+ timeout=#c_literal{val=infinity},action=Action},
Exp,A#a.us,St1};
cexpr(#ireceive2{anno=A,clauses=Lcs,timeout=Lto,action=Les}, As, St0) ->
Exp = intersection(A#a.ns, As), %Exports
@@ -2505,8 +2551,46 @@ cexpr(#ifun{anno=#a{us=Us0}=A0,name={named,Name},fc=#iclause{pats=Ps}}=Fun0,
end;
cexpr(#iapply{anno=A,op=Op,args=Args}, _As, St) ->
{#c_apply{anno=A#a.anno,op=Op,args=Args},[],A#a.us,St};
-cexpr(#icall{anno=A,module=Mod,name=Name,args=Args}, _As, St) ->
- {#c_call{anno=A#a.anno,module=Mod,name=Name,args=Args},[],A#a.us,St};
+cexpr(#icall{anno=A,module=Mod,name=Name,args=Args}, _As, St0) ->
+ Anno = A#a.anno,
+ case (not cerl:is_c_atom(Mod)) andalso member(tuple_calls, St0#core.opts) of
+ true ->
+ GenAnno = [compiler_generated|Anno],
+
+ %% Generate the clause that matches on the tuple
+ {TupleVar,St1} = new_var(GenAnno, St0),
+ {TupleSizeVar, St2} = new_var(GenAnno, St1),
+ {TupleModVar, St3} = new_var(GenAnno, St2),
+ {TupleArgsVar, St4} = new_var(GenAnno, St3),
+ TryVar = cerl:c_var('Try'),
+
+ TupleGuardExpr =
+ cerl:c_let([TupleSizeVar],
+ c_call_erl(tuple_size, [TupleVar]),
+ c_call_erl('>', [TupleSizeVar, cerl:c_int(0)])),
+
+ TupleGuard =
+ cerl:c_try(TupleGuardExpr, [TryVar], TryVar,
+ [cerl:c_var('T'),cerl:c_var('R')], cerl:c_atom(false)),
+
+ TupleApply =
+ cerl:c_let([TupleModVar],
+ c_call_erl(element, [cerl:c_int(1),TupleVar]),
+ cerl:c_let([TupleArgsVar],
+ cerl:make_list(Args ++ [TupleVar]),
+ c_call_erl(apply, [TupleModVar,Name,TupleArgsVar]))),
+
+ TupleClause = cerl:ann_c_clause(GenAnno, [TupleVar], TupleGuard, TupleApply),
+
+ %% Generate the fallback clause
+ {OtherVar,St5} = new_var(GenAnno, St4),
+ OtherApply = cerl:ann_c_call(GenAnno, OtherVar, Name, Args),
+ OtherClause = cerl:ann_c_clause(GenAnno, [OtherVar], OtherApply),
+
+ {cerl:ann_c_case(GenAnno, Mod, [TupleClause,OtherClause]),[],A#a.us,St5};
+ false ->
+ {#c_call{anno=Anno,module=Mod,name=Name,args=Args},[],A#a.us,St0}
+ end;
cexpr(#iprimop{anno=A,name=Name,args=Args}, _As, St) ->
{#c_primop{anno=A#a.anno,name=Name,args=Args},[],A#a.us,St};
cexpr(#iprotect{anno=A,body=Es}, _As, St0) ->
@@ -2536,6 +2620,10 @@ cfun(#ifun{anno=A,id=Id,vars=Args,clauses=Lcs,fc=Lfc}, _As, St0) ->
clauses=Ccs ++ [Cfc]}},
[],A#a.us,St2}.
+c_call_erl(Fun, Args) ->
+ As = [compiler_generated],
+ cerl:ann_c_call(As, cerl:c_atom(erlang), cerl:c_atom(Fun), Args).
+
%% lit_vars(Literal) -> [Var].
lit_vars(Lit) -> lit_vars(Lit, []).
diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl
index 1fc05109c5..e2b8787224 100644
--- a/lib/compiler/src/v3_kernel.erl
+++ b/lib/compiler/src/v3_kernel.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -82,7 +82,7 @@
-export([module/2,format_error/1]).
-import(lists, [map/2,foldl/3,foldr/3,mapfoldl/3,splitwith/2,member/2,
- keymember/3,keyfind/3,partition/2,droplast/1,last/1,sort/1]).
+ keyfind/3,partition/2,droplast/1,last/1,sort/1,reverse/1]).
-import(ordsets, [add_element/2,del_element/2,union/2,union/1,subtract/2]).
-import(cerl, [c_tuple/1]).
@@ -107,6 +107,7 @@ copy_anno(Kdst, Ksrc) ->
-record(iclause, {anno=[],isub,osub,pats,guard,body}).
-record(ireceive_accept, {anno=[],arg}).
-record(ireceive_next, {anno=[],arg}).
+-record(ignored, {anno=[]}).
-type warning() :: term(). % XXX: REFINE
@@ -155,20 +156,23 @@ include_attribute(_) -> true.
function({#c_var{name={F,Arity}=FA},Body}, St0) ->
%%io:format("~w/~w~n", [F,Arity]),
try
- St1 = St0#kern{func=FA,ff=undefined,vcount=0,fcount=0,ds=cerl_sets:new()},
+ %% Find a suitable starting value for the variable counter. Note
+ %% that this pass assumes that new_var_name/1 returns a variable
+ %% name distinct from any variable used in the entire body of
+ %% the function. We use integers as variable names to avoid
+ %% filling up the atom table when compiling huge functions.
+ Count = cerl_trees:next_free_variable_name(Body),
+ St1 = St0#kern{func=FA,ff=undefined,vcount=Count,fcount=0,ds=cerl_sets:new()},
{#ifun{anno=Ab,vars=Kvs,body=B0},[],St2} = expr(Body, new_sub(), St1),
{B1,_,St3} = ubody(B0, return, St2),
%%B1 = B0, St3 = St2, %Null second pass
- {#k_fdef{anno=#k{us=[],ns=[],a=Ab},
- func=F,arity=Arity,vars=Kvs,body=B1},St3}
+ {make_fdef(#k{us=[],ns=[],a=Ab}, F, Arity, Kvs, B1),St3}
catch
- Class:Error ->
- Stack = erlang:get_stacktrace(),
+ Class:Error:Stack ->
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.
@@ -489,7 +493,7 @@ make_alt(First0, Then0) ->
Then1 = pre_seq(droplast(Then0), last(Then0)),
First2 = make_protected(First1),
Then2 = make_protected(Then1),
- Body = #k_atom{val=ignored},
+ Body = #ignored{},
First3 = #k_guard_clause{guard=First2,body=Body},
Then3 = #k_guard_clause{guard=Then2,body=Body},
First = #k_guard{clauses=[First3]},
@@ -1356,7 +1360,7 @@ new_fun_name(Type, #kern{func={F,Arity},fcount=C}=St) ->
%% new_var_name(State) -> {VarName,State}.
new_var_name(#kern{vcount=C}=St) ->
- {list_to_atom("@k" ++ integer_to_list(C)),St#kern{vcount=C+1}}.
+ {C,St#kern{vcount=C+1}}.
%% new_var(State) -> {#k_var{},State}.
@@ -1410,8 +1414,6 @@ is_remote_bif(_, _, _) -> false.
%% return multiple values. Only used in bodies where a BIF may be
%% called for effect only.
-bif_vals(dsetelement, 3) -> 0;
-bif_vals(bs_context_to_binary, 1) -> 0;
bif_vals(_, _) -> 1.
bif_vals(_, _, _) -> 1.
@@ -1588,24 +1590,12 @@ match_var([U|Us], Cs0, Def, St) ->
%% constructor/constant as first argument. Group the constructors
%% according to type, the order is really irrelevant but tries to be
%% smart.
-
-match_con(Us, [C], Def, St) ->
- %% There is only one clause. We can keep literal tuples and
- %% lists, but we must convert []/integer/float/atom literals
- %% to the proper record (#k_nil{} and so on).
- Cs = [expand_pat_lit_clause(C, false)],
- match_con_1(Us, Cs, Def, St);
-match_con(Us, Cs0, Def, St) ->
- %% More than one clause. Remove literals at the top level.
- Cs = [expand_pat_lit_clause(C, true) || C <- Cs0],
- match_con_1(Us, Cs, Def, St).
-
-match_con_1([U|_Us] = L, Cs, Def, St0) ->
+match_con([U|_Us] = L, Cs, Def, St0) ->
%% Extract clauses for different constructors (types).
%%ok = io:format("match_con ~p~n", [Cs]),
- Ttcs = select_types([k_binary], Cs) ++ select_bin_con(Cs) ++
- select_types([k_cons,k_tuple,k_map,k_atom,k_float,k_int,
- k_nil,k_literal], Cs),
+ Ttcs0 = select_types(Cs, [], [], [], [], [], [], [], [], []),
+ Ttcs1 = [{T, Types} || {T, [_ | _] = Types} <- Ttcs0],
+ Ttcs = opt_single_valued(Ttcs1),
%%ok = io:format("ttcs = ~p~n", [Ttcs]),
{Scs,St1} =
mapfoldl(fun ({T,Tcs}, St) ->
@@ -1616,30 +1606,49 @@ match_con_1([U|_Us] = L, Cs, Def, St0) ->
St0, Ttcs),
{build_alt_1st_no_fail(build_select(U, Scs), Def),St1}.
-select_types(Types, Cs) ->
- [{T,Tcs} || T <- Types, begin Tcs = select(T, Cs), Tcs =/= [] end].
-
-expand_pat_lit_clause(#iclause{pats=[#ialias{pat=#k_literal{anno=A,val=Val}}=Alias|Ps]}=C, B) ->
- P = case B of
- true -> expand_pat_lit(Val, A);
- false -> literal(Val, A)
- end,
+select_types([NoExpC | Cs], Bin, BinCon, Cons, Tuple, Map, Atom, Float, Int, Nil) ->
+ C = expand_pat_lit_clause(NoExpC),
+ case clause_con(C) of
+ k_binary ->
+ select_types(Cs, [C |Bin], BinCon, Cons, Tuple, Map, Atom, Float, Int, Nil);
+ k_bin_seg ->
+ select_types(Cs, Bin, [C | BinCon], Cons, Tuple, Map, Atom, Float, Int, Nil);
+ k_bin_end ->
+ select_types(Cs, Bin, [C | BinCon], Cons, Tuple, Map, Atom, Float, Int, Nil);
+ k_cons ->
+ select_types(Cs, Bin, BinCon, [C | Cons], Tuple, Map, Atom, Float, Int, Nil);
+ k_tuple ->
+ select_types(Cs, Bin, BinCon, Cons, [C | Tuple], Map, Atom, Float, Int, Nil);
+ k_map ->
+ select_types(Cs, Bin, BinCon, Cons, Tuple, [C | Map], Atom, Float, Int, Nil);
+ k_atom ->
+ select_types(Cs, Bin, BinCon, Cons, Tuple, Map, [C | Atom], Float, Int, Nil);
+ k_float ->
+ select_types(Cs, Bin, BinCon, Cons, Tuple, Map, Atom, [C | Float], Int, Nil);
+ k_int ->
+ select_types(Cs, Bin, BinCon, Cons, Tuple, Map, Atom, Float, [C | Int], Nil);
+ k_nil ->
+ select_types(Cs, Bin, BinCon, Cons, Tuple, Map, Atom, Float, Int, [C | Nil])
+ end;
+select_types([], Bin, BinCon, Cons, Tuple, Map, Atom, Float, Int, Nil) ->
+ [{k_binary, reverse(Bin)}] ++ handle_bin_con(reverse(BinCon)) ++
+ [
+ {k_cons, reverse(Cons)},
+ {k_tuple, reverse(Tuple)},
+ {k_map, reverse(Map)},
+ {k_atom, reverse(Atom)},
+ {k_float, reverse(Float)},
+ {k_int, reverse(Int)},
+ {k_nil, reverse(Nil)}
+ ].
+
+expand_pat_lit_clause(#iclause{pats=[#ialias{pat=#k_literal{anno=A,val=Val}}=Alias|Ps]}=C) ->
+ P = expand_pat_lit(Val, A),
C#iclause{pats=[Alias#ialias{pat=P}|Ps]};
-expand_pat_lit_clause(#iclause{pats=[#k_literal{anno=A,val=Val}|Ps]}=C, B) ->
- P = case B of
- true -> expand_pat_lit(Val, A);
- false -> literal(Val, A)
- end,
+expand_pat_lit_clause(#iclause{pats=[#k_literal{anno=A,val=Val}|Ps]}=C) ->
+ P = expand_pat_lit(Val, A),
C#iclause{pats=[P|Ps]};
-expand_pat_lit_clause(#iclause{pats=[#k_binary{anno=A,segs=#k_bin_end{}}|Ps]}=C, B) ->
- case B of
- true ->
- C;
- false ->
- P = #k_literal{anno=A,val = <<>>},
- C#iclause{pats=[P|Ps]}
- end;
-expand_pat_lit_clause(C, _) -> C.
+expand_pat_lit_clause(C) -> C.
expand_pat_lit([H|T], A) ->
#k_cons{anno=A,hd=literal(H, A),tl=literal(T, A)};
@@ -1659,20 +1668,113 @@ literal(Val, A) when is_atom(Val) ->
literal(Val, A) when is_list(Val); is_tuple(Val) ->
#k_literal{anno=A,val=Val}.
-%% select_bin_con([Clause]) -> [{Type,[Clause]}].
-%% Extract clauses for the k_bin_seg constructor. As k_bin_seg
-%% matching can overlap, the k_bin_seg constructors cannot be
-%% reordered, only grouped.
+%% opt_singled_valued([{Type,Clauses}]) -> [{Type,Clauses}].
+%% If a type only has one clause and if the pattern is literal,
+%% the matching can be done more efficiently by directly comparing
+%% with the literal (that is especially true for binaries).
-select_bin_con(Cs0) ->
- Cs1 = lists:filter(fun (C) ->
- Con = clause_con(C),
- (Con =:= k_bin_seg) or (Con =:= k_bin_end)
- end, Cs0),
- select_bin_con_1(Cs1).
+opt_single_valued(Ttcs) ->
+ opt_single_valued(Ttcs, [], []).
+opt_single_valued([{_,[#iclause{pats=[P0|Ps]}=Tc]}=Ttc|Ttcs], TtcAcc, LitAcc) ->
+ try combine_lit_pat(P0) of
+ P ->
+ LitTtc = Tc#iclause{pats=[P|Ps]},
+ opt_single_valued(Ttcs, TtcAcc, [LitTtc|LitAcc])
+ catch
+ not_possible ->
+ opt_single_valued(Ttcs, [Ttc|TtcAcc], LitAcc)
+ end;
+opt_single_valued([Ttc|Ttcs], TtcAcc, LitAcc) ->
+ opt_single_valued(Ttcs, [Ttc|TtcAcc], LitAcc);
+opt_single_valued([], TtcAcc, []) ->
+ reverse(TtcAcc);
+opt_single_valued([], TtcAcc, LitAcc) ->
+ Literals = {k_literal,reverse(LitAcc)},
+ %% Test the literals as early as possible.
+ case reverse(TtcAcc) of
+ [{k_binary,_}=Bin|Ttcs] ->
+ %% The delayed creation of sub binaries requires
+ %% bs_start_match2 to be the first instruction in the
+ %% function.
+ [Bin,Literals|Ttcs];
+ Ttcs ->
+ [Literals|Ttcs]
+ end.
+
+combine_lit_pat(#ialias{pat=Pat0}=Alias) ->
+ Pat = combine_lit_pat(Pat0),
+ Alias#ialias{pat=Pat};
+combine_lit_pat(Pat) ->
+ case do_combine_lit_pat(Pat) of
+ #k_literal{val=Val} when is_atom(Val) ->
+ throw(not_possible);
+ #k_literal{val=Val} when is_number(Val) ->
+ throw(not_possible);
+ #k_literal{val=[]} ->
+ throw(not_possible);
+ #k_literal{}=Lit ->
+ Lit
+ end.
+
+do_combine_lit_pat(#k_atom{anno=A,val=Val}) ->
+ #k_literal{anno=A,val=Val};
+do_combine_lit_pat(#k_float{anno=A,val=Val}) ->
+ #k_literal{anno=A,val=Val};
+do_combine_lit_pat(#k_int{anno=A,val=Val}) ->
+ #k_literal{anno=A,val=Val};
+do_combine_lit_pat(#k_nil{anno=A}) ->
+ #k_literal{anno=A,val=[]};
+do_combine_lit_pat(#k_binary{anno=A,segs=Segs}) ->
+ Bin = combine_bin_segs(Segs),
+ #k_literal{anno=A,val=Bin};
+do_combine_lit_pat(#k_cons{anno=A,hd=Hd0,tl=Tl0}) ->
+ #k_literal{val=Hd} = do_combine_lit_pat(Hd0),
+ #k_literal{val=Tl} = do_combine_lit_pat(Tl0),
+ #k_literal{anno=A,val=[Hd|Tl]};
+do_combine_lit_pat(#k_literal{}=Lit) ->
+ Lit;
+do_combine_lit_pat(#k_tuple{anno=A,es=Es0}) ->
+ Es = [begin
+ #k_literal{val=Lit} = do_combine_lit_pat(El),
+ Lit
+ end || El <- Es0],
+ #k_literal{anno=A,val=list_to_tuple(Es)};
+do_combine_lit_pat(_) ->
+ throw(not_possible).
-select_bin_con_1(Cs) ->
+combine_bin_segs(#k_bin_seg{size=Size0,unit=Unit,type=integer,
+ flags=[unsigned,big],seg=Seg,next=Next}) ->
+ #k_literal{val=Size1} = do_combine_lit_pat(Size0),
+ #k_literal{val=Int} = do_combine_lit_pat(Seg),
+ Size = Size1 * Unit,
+ if
+ 0 < Size, Size < 64 ->
+ Bin = <<Int:Size>>,
+ case Bin of
+ <<Int:Size>> ->
+ NextBin = combine_bin_segs(Next),
+ <<Bin/bits,NextBin/bits>>;
+ _ ->
+ %% The integer Int does not fit in the segment,
+ %% thus it will not match.
+ throw(not_possible)
+ end;
+ true ->
+ %% Avoid creating huge binary literals.
+ throw(not_possible)
+ end;
+combine_bin_segs(#k_bin_end{}) ->
+ <<>>;
+combine_bin_segs(_) ->
+ throw(not_possible).
+
+%% handle_bin_con([Clause]) -> [{Type,[Clause]}].
+%% Handle clauses for the k_bin_seg constructor. As k_bin_seg
+%% matching can overlap, the k_bin_seg constructors cannot be
+%% reordered, only grouped.
+
+handle_bin_con(Cs) ->
try
%% The usual way to match literals is to first extract the
%% value to a register, and then compare the register to the
@@ -1711,14 +1813,14 @@ select_bin_con_1(Cs) ->
end
catch
throw:not_possible ->
- select_bin_con_2(Cs)
+ handle_bin_con_not_possible(Cs)
end.
-select_bin_con_2([C1|Cs]) ->
+handle_bin_con_not_possible([C1|Cs]) ->
Con = clause_con(C1),
{More,Rest} = splitwith(fun (C) -> clause_con(C) =:= Con end, Cs),
- [{Con,[C1|More]}|select_bin_con_2(Rest)];
-select_bin_con_2([]) -> [].
+ [{Con,[C1|More]}|handle_bin_con_not_possible(Rest)];
+handle_bin_con_not_possible([]) -> [].
%% select_bin_int([Clause]) -> {k_bin_int,[Clause]}
%% If the first pattern in each clause selects the same integer,
@@ -1818,10 +1920,6 @@ select_utf8(Val0) ->
throw(not_possible)
end.
-%% select(Con, [Clause]) -> [Clause].
-
-select(T, Cs) -> [ C || C <- Cs, clause_con(C) =:= T ].
-
%% match_value([Var], Con, [Clause], Default, State) -> {SelectExpr,State}.
%% At this point all the clauses have the same constructor, we must
%% now separate them according to value.
@@ -1957,8 +2055,9 @@ get_match(#k_binary{}, St0) ->
{[V]=Mes,St1} = new_vars(1, St0),
{#k_binary{segs=V},Mes,St1};
get_match(#k_bin_seg{size=#k_atom{val=all},next={k_bin_end,[]}}=Seg, St0) ->
- {[S]=Vars,St1} = new_vars(1, St0),
- {Seg#k_bin_seg{seg=S,next=[]},Vars,St1};
+ {[S,N0],St1} = new_vars(2, St0),
+ N = set_kanno(N0, [no_usage]),
+ {Seg#k_bin_seg{seg=S,next=N},[S],St1};
get_match(#k_bin_seg{}=Seg, St0) ->
{[S,N0],St1} = new_vars(2, St0),
N = set_kanno(N0, [no_usage]),
@@ -2143,7 +2242,9 @@ ubody(E, return, St0) ->
{Ea,Pa,St1} = force_atomic(E, St0),
ubody(pre_seq(Pa, #ivalues{args=[Ea]}), return, St1)
end;
-ubody(E, {break,_Rs} = Break, St0) ->
+ubody(#ignored{}, {break,_} = Break, St) ->
+ ubody(#ivalues{args=[]}, Break, St);
+ubody(E, {break,[_]} = Break, St0) ->
%%ok = io:fwrite("ubody ~w:~p~n", [?LINE,{E,Br}]),
%% Exiting expressions need no trailing break.
case is_exit_expr(E) of
@@ -2151,6 +2252,16 @@ ubody(E, {break,_Rs} = Break, St0) ->
false ->
{Ea,Pa,St1} = force_atomic(E, St0),
ubody(pre_seq(Pa, #ivalues{args=[Ea]}), Break, St1)
+ end;
+ubody(E, {break,Rs}=Break, St0) ->
+ case is_exit_expr(E) of
+ true ->
+ uexpr(E, return, St0);
+ false ->
+ {Vs,St1} = new_vars(length(Rs), St0),
+ Iset = #iset{vars=Vs,arg=E},
+ PreSeq = pre_seq([Iset], #ivalues{args=Vs}),
+ ubody(PreSeq, Break, St1)
end.
iletrec_funs(#iletrec{defs=Fs}, St0) ->
@@ -2179,9 +2290,8 @@ iletrec_funs_gen(Fs, FreeVs, St) ->
Arity0 = length(Vs),
{Fb1,_,Lst1} = ubody(Fb0, return, Lst0#kern{ff={N,Arity0}}),
Arity = Arity0 + length(FreeVs),
- Fun = #k_fdef{anno=#k{us=[],ns=[],a=Fa},
- func=N,arity=Arity,
- vars=Vs ++ FreeVs,body=Fb1},
+ Fun = make_fdef(#k{us=[],ns=[],a=Fa}, N, Arity,
+ Vs++FreeVs, Fb1),
Lst1#kern{funs=[Fun|Lst1#kern.funs]}
end, St, Fs).
@@ -2245,8 +2355,7 @@ uexpr(#k_bif{anno=A,op=Op,args=As}=Bif, {break,Rs}, St0) ->
{Brs,St1} = bif_returns(Op, Rs, St0),
{Bif#k_bif{anno=#k{us=Used,ns=lit_list_vars(Brs),a=A},ret=Brs},
Used,St1};
-uexpr(#k_match{anno=A,vars=Vs0,body=B0}, Br, St0) ->
- Vs = handle_reuse_annos(Vs0, St0),
+uexpr(#k_match{anno=A,vars=Vs,body=B0}, Br, St0) ->
Rs = break_rets(Br),
{B1,Bu,St1} = umatch(B0, Br, St0),
case is_in_guard(St1) of
@@ -2276,20 +2385,20 @@ uexpr(#k_try{anno=A,arg=A0,vars=Vs,body=B0,evars=Evs,handler=H0},
true ->
{[#k_var{name=X}],#k_var{name=X}} = {Vs,B0}, %Assertion.
#k_atom{val=false} = H0, %Assertion.
- {A1,Bu,St1} = uexpr(A0, Br, St0),
+ {Avs,St1} = new_vars(length(Rs0), St0),
+ {A1,Bu,St} = uexpr(A0, {break,Avs}, St1),
{#k_protected{anno=#k{us=Bu,ns=lit_list_vars(Rs0),a=A},
- arg=A1,ret=Rs0},Bu,St1};
+ arg=A1,ret=Rs0,inner=Avs},Bu,St};
false ->
{Avs,St1} = new_vars(length(Vs), St0),
{A1,Au,St2} = ubody(A0, {break,Avs}, St1),
{B1,Bu,St3} = ubody(B0, Br, St2),
{H1,Hu,St4} = ubody(H0, Br, St3),
- {Rs1,St5} = ensure_return_vars(Rs0, St4),
Used = union([Au,subtract(Bu, lit_list_vars(Vs)),
subtract(Hu, lit_list_vars(Evs))]),
- {#k_try{anno=#k{us=Used,ns=lit_list_vars(Rs1),a=A},
- arg=A1,vars=Vs,body=B1,evars=Evs,handler=H1,ret=Rs1},
- Used,St5}
+ {#k_try{anno=#k{us=Used,ns=lit_list_vars(Rs0),a=A},
+ arg=A1,vars=Vs,body=B1,evars=Evs,handler=H1,ret=Rs0},
+ Used,St4}
end;
uexpr(#k_try{anno=A,arg=A0,vars=Vs,body=B0,evars=Evs,handler=H0},
return, St0) ->
@@ -2297,13 +2406,11 @@ uexpr(#k_try{anno=A,arg=A0,vars=Vs,body=B0,evars=Evs,handler=H0},
{A1,Au,St2} = ubody(A0, {break,Avs}, St1), %Must break to clean up here!
{B1,Bu,St3} = ubody(B0, return, St2),
{H1,Hu,St4} = ubody(H0, return, St3),
- NumNew = 1,
- {Ns,St5} = new_vars(NumNew, St4),
Used = union([Au,subtract(Bu, lit_list_vars(Vs)),
subtract(Hu, lit_list_vars(Evs))]),
- {#k_try_enter{anno=#k{us=Used,ns=Ns,a=A},
+ {#k_try_enter{anno=#k{us=Used,ns=[],a=A},
arg=A1,vars=Vs,body=B1,evars=Evs,handler=H1},
- Used,St5};
+ Used,St4};
uexpr(#k_catch{anno=A,body=B0}, {break,Rs0}, St0) ->
{Rb,St1} = new_var(St0),
{B1,Bu,St2} = ubody(B0, {break,[Rb]}, St1),
@@ -2325,8 +2432,7 @@ uexpr(#ifun{anno=A,vars=Vs,body=B0}, {break,Rs}, St0) ->
%% No id annotation. Must invent a fun name.
new_fun_name(St1)
end,
- Fun = #k_fdef{anno=#k{us=[],ns=[],a=A},func=Fname,arity=Arity,
- vars=Vs ++ Fvs,body=B1},
+ Fun = make_fdef(#k{us=[],ns=[],a=A}, Fname, Arity, Vs++Fvs, B1),
{#k_bif{anno=#k{us=Free,ns=lit_list_vars(Rs),a=A},
op=#k_internal{name=make_fun,arity=length(Free)+2},
args=[#k_atom{val=Fname},#k_int{val=Arity}|Fvs],
@@ -2343,31 +2449,14 @@ uexpr(Lit, {break,Rs0}, St0) ->
add_local_function(_, #kern{funs=ignore}=St) -> St;
add_local_function(F, #kern{funs=Funs}=St) -> St#kern{funs=[F|Funs]}.
-%% handle_reuse_annos([#k_var{}], State) -> State.
-%% In general, it is only safe to reuse a variable for a match context
-%% if the original value of the variable will no longer be needed.
-%%
-%% If a variable has been bound in an outer letrec and is therefore
-%% free in the current function, the variable may still be used.
-%% We don't bother to check whether the variable is actually used,
-%% but simply clears the 'reuse_for_context' annotation for any variable
-%% that is free.
-handle_reuse_annos(Vs, St) ->
- [handle_reuse_anno(V, St) || V <- Vs].
-
-handle_reuse_anno(#k_var{anno=A}=V, St) ->
- case member(reuse_for_context, A) of
- false -> V;
- true -> handle_reuse_anno_1(V, St)
- end.
-
-handle_reuse_anno_1(#k_var{anno=Anno,name=Vname}=V, #kern{ff={F,A}}=St) ->
- FreeVs = get_free(F, A, St),
- case keymember(Vname, #k_var.name, FreeVs) of
- true -> V#k_var{anno=Anno--[reuse_for_context]};
- false -> V
- end;
-handle_reuse_anno_1(V, _St) -> V.
+%% Make a #k_fdef{}, making sure that the body is always a #k_match{}.
+make_fdef(Anno, Name, Arity, Vs, #k_match{}=Body) ->
+ #k_fdef{anno=Anno,func=Name,arity=Arity,vars=Vs,body=Body};
+make_fdef(Anno, Name, Arity, Vs, Body) ->
+ Ka = get_kanno(Body),
+ Match = #k_match{anno=#k{us=Ka#k.us,ns=[],a=Ka#k.a},
+ vars=Vs,body=Body,ret=[]},
+ #k_fdef{anno=Anno,func=Name,arity=Arity,vars=Vs,body=Match}.
%% get_free(Name, Arity, State) -> [Free].
%% store_free(Name, Arity, [Free], State) -> State.
@@ -2412,8 +2501,7 @@ umatch(#k_alt{anno=A,first=F0,then=T0}, Br, St0) ->
Used = union(Fu, Tu),
{#k_alt{anno=#k{us=Used,ns=[],a=A},first=F1,then=T1},
Used,St2};
-umatch(#k_select{anno=A,var=V0,types=Ts0}, Br, St0) ->
- V = handle_reuse_anno(V0, St0),
+umatch(#k_select{anno=A,var=V,types=Ts0}, Br, St0) ->
{Ts1,Tus,St1} = umatch_list(Ts0, Br, St0),
Used = case member(no_usage, get_kanno(V)) of
true -> Tus;
diff --git a/lib/compiler/src/v3_kernel.hrl b/lib/compiler/src/v3_kernel.hrl
index 7cd30b25a8..e26360a6da 100644
--- a/lib/compiler/src/v3_kernel.hrl
+++ b/lib/compiler/src/v3_kernel.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -66,7 +66,7 @@
-record(k_receive_next, {anno=[]}).
-record(k_try, {anno=[],arg,vars,body,evars,handler,ret=[]}).
-record(k_try_enter, {anno=[],arg,vars,body,evars,handler}).
--record(k_protected, {anno=[],arg,ret=[]}).
+-record(k_protected, {anno=[],arg,ret=[],inner}).
-record(k_catch, {anno=[],body,ret=[]}).
-record(k_guard_match, {anno=[],vars,body,ret=[]}).
diff --git a/lib/compiler/src/v3_kernel_pp.erl b/lib/compiler/src/v3_kernel_pp.erl
index 53097d0d7d..c12c301ee2 100644
--- a/lib/compiler/src/v3_kernel_pp.erl
+++ b/lib/compiler/src/v3_kernel_pp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -248,7 +248,7 @@ format_1(#k_put{arg=A,ret=Rs}, Ctxt) ->
[format(A, Ctxt),
format_ret(Rs, ctxt_bump_indent(Ctxt, 1))
];
-format_1(#k_try{arg=A,vars=Vs,body=B,evars=Evs,handler=H}, Ctxt) ->
+format_1(#k_try{arg=A,vars=Vs,body=B,evars=Evs,handler=H,ret=Rs}, Ctxt) ->
Ctxt1 = ctxt_bump_indent(Ctxt, Ctxt#ctxt.body_indent),
["try",
nl_indent(Ctxt1),
@@ -264,7 +264,8 @@ format_1(#k_try{arg=A,vars=Vs,body=B,evars=Evs,handler=H}, Ctxt) ->
nl_indent(Ctxt1),
format(H, Ctxt1),
nl_indent(Ctxt),
- "end"
+ "end",
+ format_ret(Rs, Ctxt)
];
format_1(#k_try_enter{arg=A,vars=Vs,body=B,evars=Evs,handler=H}, Ctxt) ->
Ctxt1 = ctxt_bump_indent(Ctxt, Ctxt#ctxt.body_indent),
@@ -491,7 +492,7 @@ indent(Ctxt) -> indent(Ctxt#ctxt.indent, Ctxt).
indent(N, _Ctxt) when N =< 0 -> "";
indent(N, Ctxt) ->
T = Ctxt#ctxt.tab_width,
- string:chars($\t, N div T, string:chars($\s, N rem T)).
+ lists:duplicate(N div T, $\t) ++ lists:duplicate(N rem T, $\s).
nl_indent(Ctxt) -> [$\n|indent(Ctxt)].
@@ -508,7 +509,7 @@ unindent([$\t|T], N, Ctxt, C) ->
if N >= Tab ->
unindent(T, N - Tab, Ctxt, C);
true ->
- unindent([string:chars($\s, Tab - N)|T], 0, Ctxt, C)
+ unindent([lists:duplicate(Tab - N, $\s)|T], 0, Ctxt, C)
end;
unindent([L|T], N, Ctxt, C) when is_list(L) ->
unindent(L, N, Ctxt, [T|C]);
diff --git a/lib/compiler/src/v3_life.erl b/lib/compiler/src/v3_life.erl
deleted file mode 100644
index be3ade47ff..0000000000
--- a/lib/compiler/src/v3_life.erl
+++ /dev/null
@@ -1,468 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%% Purpose : Convert annotated kernel expressions to annotated beam format.
-
-%% This module creates beam format annotated with variable lifetime
-%% information. Each thing is given an index and for each variable we
-%% store the first and last index for its occurrence. The variable
-%% database, VDB, attached to each thing is only relevant internally
-%% for that thing.
-%%
-%% For nested things like matches the numbering continues locally and
-%% the VDB for that thing refers to the variable usage within that
-%% thing. Variables which live through a such a thing are internally
-%% given a very large last index. Internally the indexes continue
-%% after the index of that thing. This creates no problems as the
-%% internal variable info never escapes and externally we only see
-%% variable which are alive both before or after.
-%%
-%% This means that variables never "escape" from a thing and the only
-%% way to get values from a thing is to "return" them, with 'break' or
-%% 'return'. Externally these values become the return values of the
-%% thing. This is no real limitation as most nested things have
-%% multiple threads so working out a common best variable usage is
-%% difficult.
-
--module(v3_life).
-
--export([module/2]).
-
--export([vdb_find/2]).
-
--import(lists, [member/2,map/2,reverse/1,sort/1]).
--import(ordsets, [add_element/2,intersection/2,union/2]).
-
--include("v3_kernel.hrl").
--include("v3_life.hrl").
-
--type fa() :: {atom(),arity()}.
-
-%% These are not defined in v3_kernel.hrl.
-get_kanno(Kthing) -> element(2, Kthing).
-%%set_kanno(Kthing, Anno) -> setelement(2, Kthing, Anno).
-
--spec module(#k_mdef{}, [compile:option()]) ->
- {'ok',{module(),[fa()],[_],[_]}}.
-
-module(#k_mdef{name=M,exports=Es,attributes=As,body=Fs0}, _Opts) ->
- Fs1 = functions(Fs0, []),
- {ok,{M,Es,As,Fs1}}.
-
-functions([F|Fs], Acc) ->
- functions(Fs, [function(F)|Acc]);
-functions([], Acc) -> reverse(Acc).
-
-%% function(Kfunc) -> Func.
-
-function(#k_fdef{anno=#k{a=Anno},func=F,arity=Ar,vars=Vs,body=Kb}) ->
- try
- As = var_list(Vs),
- Vdb0 = init_vars(As),
- %% Force a top-level match!
- B0 = case Kb of
- #k_match{} -> Kb;
- _ ->
- Ka = get_kanno(Kb),
- #k_match{anno=#k{us=Ka#k.us,ns=[],a=Ka#k.a},
- vars=Vs,body=Kb,ret=[]}
- end,
- {B1,_,Vdb1} = body(B0, 1, Vdb0),
- {function,F,Ar,As,B1,Vdb1,Anno}
- catch
- Class:Error ->
- Stack = erlang:get_stacktrace(),
- io:fwrite("Function: ~w/~w\n", [F,Ar]),
- erlang:raise(Class, Error, Stack)
- end.
-
-%% body(Kbody, I, Vdb) -> {[Expr],MaxI,Vdb}.
-%% Handle a body.
-
-body(#k_seq{arg=Ke,body=Kb}, I, Vdb0) ->
- %%ok = io:fwrite("life ~w:~p~n", [?LINE,{Ke,I,Vdb0}]),
- A = get_kanno(Ke),
- Vdb1 = use_vars(union(A#k.us, A#k.ns), I, Vdb0),
- {Es,MaxI,Vdb2} = body(Kb, I+1, Vdb1),
- E = expr(Ke, I, Vdb2),
- {[E|Es],MaxI,Vdb2};
-body(Ke, I, Vdb0) ->
- %%ok = io:fwrite("life ~w:~p~n", [?LINE,{Ke,I,Vdb0}]),
- A = get_kanno(Ke),
- Vdb1 = use_vars(union(A#k.us, A#k.ns), I, Vdb0),
- E = expr(Ke, I, Vdb1),
- {[E],I,Vdb1}.
-
-%% protected(Kprotected, I, Vdb) -> Protected.
-%% Only used in guards.
-
-protected(#k_protected{anno=A,arg=Ts,ret=Rs}, I, Vdb) ->
- %% Lock variables that are alive before try and used afterwards.
- %% Don't lock variables that are only used inside the protected
- %% expression.
- Pdb0 = vdb_sub(I, I+1, Vdb),
- {T,MaxI,Pdb1} = body(Ts, I+1, Pdb0),
- Pdb2 = use_vars(A#k.ns, MaxI+1, Pdb1), %Save "return" values
- #l{ke={protected,T,var_list(Rs)},i=I,a=A#k.a,vdb=Pdb2}.
-
-%% expr(Kexpr, I, Vdb) -> Expr.
-
-expr(#k_test{anno=A,op=Op,args=As,inverted=Inverted}, I, _Vdb) ->
- #l{ke={test,test_op(Op),atomic_list(As),Inverted},i=I,a=A#k.a};
-expr(#k_call{anno=A,op=Op,args=As,ret=Rs}, I, _Vdb) ->
- #l{ke={call,call_op(Op),atomic_list(As),var_list(Rs)},i=I,a=A#k.a};
-expr(#k_enter{anno=A,op=Op,args=As}, I, _Vdb) ->
- #l{ke={enter,call_op(Op),atomic_list(As)},i=I,a=A#k.a};
-expr(#k_bif{anno=A,op=Op,args=As,ret=Rs}, I, _Vdb) ->
- Bif = k_bif(A, Op, As, Rs),
- #l{ke=Bif,i=I,a=A#k.a};
-expr(#k_match{anno=A,body=Kb,ret=Rs}, I, Vdb) ->
- %% Work out imported variables which need to be locked.
- Mdb = vdb_sub(I, I+1, Vdb),
- M = match(Kb, A#k.us, I+1, [], Mdb),
- #l{ke={match,M,var_list(Rs)},i=I,vdb=use_vars(A#k.us, I+1, Mdb),a=A#k.a};
-expr(#k_guard_match{anno=A,body=Kb,ret=Rs}, I, Vdb) ->
- %% Work out imported variables which need to be locked.
- Mdb = vdb_sub(I, I+1, Vdb),
- M = match(Kb, A#k.us, I+1, [], Mdb),
- #l{ke={guard_match,M,var_list(Rs)},i=I,vdb=use_vars(A#k.us, I+1, Mdb),a=A#k.a};
-expr(#k_try{}=Try, I, Vdb) ->
- body_try(Try, I, Vdb);
-expr(#k_protected{}=Protected, I, Vdb) ->
- protected(Protected, I, Vdb);
-expr(#k_try_enter{anno=A,arg=Ka,vars=Vs,body=Kb,evars=Evs,handler=Kh}, I, Vdb) ->
- %% Lock variables that are alive before the catch and used afterwards.
- %% Don't lock variables that are only used inside the try.
- Tdb0 = vdb_sub(I, I+1, Vdb),
- %% This is the tricky bit. Lock variables in Arg that are used in
- %% the body and handler. Add try tag 'variable'.
- Ab = get_kanno(Kb),
- Ah = get_kanno(Kh),
- Tdb1 = use_vars(union(Ab#k.us, Ah#k.us), I+3, Tdb0),
- Tdb2 = vdb_sub(I, I+2, Tdb1),
- Vnames = fun (Kvar) -> Kvar#k_var.name end, %Get the variable names
- {Aes,_,Adb} = body(Ka, I+2, add_var({catch_tag,I+1}, I+1, 1000000, Tdb2)),
- {Bes,_,Bdb} = body(Kb, I+4, new_vars(sort(map(Vnames, Vs)), I+3, Tdb2)),
- {Hes,_,Hdb} = body(Kh, I+4, new_vars(sort(map(Vnames, Evs)), I+3, Tdb2)),
- #l{ke={try_enter,#l{ke={block,Aes},i=I+1,vdb=Adb,a=[]},
- var_list(Vs),#l{ke={block,Bes},i=I+3,vdb=Bdb,a=[]},
- var_list(Evs),#l{ke={block,Hes},i=I+3,vdb=Hdb,a=[]}},
- i=I,vdb=Tdb1,a=A#k.a};
-expr(#k_catch{anno=A,body=Kb,ret=[R]}, I, Vdb) ->
- %% Lock variables that are alive before the catch and used afterwards.
- %% Don't lock variables that are only used inside the catch.
- %% Add catch tag 'variable'.
- Cdb0 = vdb_sub(I, I+1, Vdb),
- {Es,_,Cdb1} = body(Kb, I+1, add_var({catch_tag,I}, I, locked, Cdb0)),
- #l{ke={'catch',Es,variable(R)},i=I,vdb=Cdb1,a=A#k.a};
-expr(#k_receive{anno=A,var=V,body=Kb,timeout=T,action=Ka,ret=Rs}, I, Vdb) ->
- %% Work out imported variables which need to be locked.
- Rdb = vdb_sub(I, I+1, Vdb),
- M = match(Kb, add_element(V#k_var.name, A#k.us), I+1, [],
- new_vars([V#k_var.name], I, Rdb)),
- {Tes,_,Adb} = body(Ka, I+1, Rdb),
- #l{ke={receive_loop,atomic(T),variable(V),M,
- #l{ke=Tes,i=I+1,vdb=Adb,a=[]},var_list(Rs)},
- i=I,vdb=use_vars(A#k.us, I+1, Vdb),a=A#k.a};
-expr(#k_receive_accept{anno=A}, I, _Vdb) ->
- #l{ke=receive_accept,i=I,a=A#k.a};
-expr(#k_receive_next{anno=A}, I, _Vdb) ->
- #l{ke=receive_next,i=I,a=A#k.a};
-expr(#k_put{anno=A,arg=Arg,ret=Rs}, I, _Vdb) ->
- #l{ke={set,var_list(Rs),literal(Arg, [])},i=I,a=A#k.a};
-expr(#k_break{anno=A,args=As}, I, _Vdb) ->
- #l{ke={break,atomic_list(As)},i=I,a=A#k.a};
-expr(#k_guard_break{anno=A,args=As}, I, Vdb) ->
- Locked = [V || {V,_,_} <- Vdb],
- #l{ke={guard_break,atomic_list(As),Locked},i=I,a=A#k.a};
-expr(#k_return{anno=A,args=As}, I, _Vdb) ->
- #l{ke={return,atomic_list(As)},i=I,a=A#k.a}.
-
-body_try(#k_try{anno=A,arg=Ka,vars=Vs,body=Kb,evars=Evs,handler=Kh,ret=Rs},
- I, Vdb) ->
- %% Lock variables that are alive before the catch and used afterwards.
- %% Don't lock variables that are only used inside the try.
- Tdb0 = vdb_sub(I, I+1, Vdb),
- %% This is the tricky bit. Lock variables in Arg that are used in
- %% the body and handler. Add try tag 'variable'.
- Ab = get_kanno(Kb),
- Ah = get_kanno(Kh),
- Tdb1 = use_vars(union(Ab#k.us, Ah#k.us), I+3, Tdb0),
- Tdb2 = vdb_sub(I, I+2, Tdb1),
- Vnames = fun (Kvar) -> Kvar#k_var.name end, %Get the variable names
- {Aes,_,Adb} = body(Ka, I+2, add_var({catch_tag,I+1}, I+1, locked, Tdb2)),
- {Bes,_,Bdb} = body(Kb, I+4, new_vars(sort(map(Vnames, Vs)), I+3, Tdb2)),
- {Hes,_,Hdb} = body(Kh, I+4, new_vars(sort(map(Vnames, Evs)), I+3, Tdb2)),
- #l{ke={'try',#l{ke={block,Aes},i=I+1,vdb=Adb,a=[]},
- var_list(Vs),#l{ke={block,Bes},i=I+3,vdb=Bdb,a=[]},
- var_list(Evs),#l{ke={block,Hes},i=I+3,vdb=Hdb,a=[]},
- var_list(Rs)},
- i=I,vdb=Tdb1,a=A#k.a}.
-
-%% call_op(Op) -> Op.
-%% test_op(Op) -> Op.
-%% Do any necessary name translations here to munge into beam format.
-
-call_op(#k_local{name=N}) -> N;
-call_op(#k_remote{mod=M,name=N}) -> {remote,atomic(M),atomic(N)};
-call_op(Other) -> variable(Other).
-
-test_op(#k_remote{mod=#k_atom{val=erlang},name=#k_atom{val=N}}) -> N.
-
-%% k_bif(Anno, Op, [Arg], [Ret], Vdb) -> Expr.
-%% Build bifs.
-
-k_bif(_A, #k_internal{name=Name}, As, Rs) ->
- {internal,Name,atomic_list(As),var_list(Rs)};
-k_bif(_A, #k_remote{mod=#k_atom{val=erlang},name=#k_atom{val=Name}}, As, Rs) ->
- Ar = length(As),
- case is_gc_bif(Name, Ar) of
- false ->
- {bif,Name,atomic_list(As),var_list(Rs)};
- true ->
- {gc_bif,Name,atomic_list(As),var_list(Rs)}
- end.
-
-%% match(Kexpr, [LockVar], I, Vdb) -> Expr.
-%% Convert match tree to old format.
-
-match(#k_alt{anno=A,first=Kf,then=Kt}, Ls, I, Ctxt, Vdb0) ->
- Vdb1 = use_vars(union(A#k.us, Ls), I, Vdb0),
- F = match(Kf, Ls, I+1, Ctxt, Vdb1),
- T = match(Kt, Ls, I+1, Ctxt, Vdb1),
- #l{ke={alt,F,T},i=I,vdb=Vdb1,a=A#k.a};
-match(#k_select{anno=A,var=V,types=Kts}, Ls0, I, Ctxt, Vdb0) ->
- Vanno = get_kanno(V),
- Ls1 = case member(no_usage, Vanno) of
- false -> add_element(V#k_var.name, Ls0);
- true -> Ls0
- end,
- Anno = case member(reuse_for_context, Vanno) of
- true -> [reuse_for_context|A#k.a];
- false -> A#k.a
- end,
- Vdb1 = use_vars(union(A#k.us, Ls1), I, Vdb0),
- Ts = [type_clause(Tc, Ls1, I+1, Ctxt, Vdb1) || Tc <- Kts],
- #l{ke={select,literal(V, Ctxt),Ts},i=I,vdb=Vdb1,a=Anno};
-match(#k_guard{anno=A,clauses=Kcs}, Ls, I, Ctxt, Vdb0) ->
- Vdb1 = use_vars(union(A#k.us, Ls), I, Vdb0),
- Cs = [guard_clause(G, Ls, I+1, Ctxt, Vdb1) || G <- Kcs],
- #l{ke={guard,Cs},i=I,vdb=Vdb1,a=A#k.a};
-match(Other, Ls, I, _Ctxt, Vdb0) ->
- Vdb1 = use_vars(Ls, I, Vdb0),
- {B,_,Vdb2} = body(Other, I+1, Vdb1),
- #l{ke={block,B},i=I,vdb=Vdb2,a=[]}.
-
-type_clause(#k_type_clause{anno=A,type=T,values=Kvs}, Ls, I, Ctxt, Vdb0) ->
- %%ok = io:format("life ~w: ~p~n", [?LINE,{T,Kvs}]),
- Vdb1 = use_vars(union(A#k.us, Ls), I+1, Vdb0),
- Vs = [val_clause(Vc, Ls, I+1, Ctxt, Vdb1) || Vc <- Kvs],
- #l{ke={type_clause,type(T),Vs},i=I,vdb=Vdb1,a=A#k.a}.
-
-val_clause(#k_val_clause{anno=A,val=V,body=Kb}, Ls0, I, Ctxt0, Vdb0) ->
- New = (get_kanno(V))#k.ns,
- Bus = (get_kanno(Kb))#k.us,
- %%ok = io:format("Ls0 = ~p, Used=~p\n New=~p, Bus=~p\n", [Ls0,Used,New,Bus]),
- Ls1 = union(intersection(New, Bus), Ls0), %Lock for safety
- Vdb1 = use_vars(union(A#k.us, Ls1), I+1, new_vars(New, I, Vdb0)),
- Ctxt = case V of
- #k_binary{segs=#k_var{name=C0}} -> C0;
- _ -> Ctxt0
- end,
- B = match(Kb, Ls1, I+1, Ctxt, Vdb1),
- #l{ke={val_clause,literal(V, Ctxt),B},i=I,vdb=use_vars(Bus, I+1, Vdb1),a=A#k.a}.
-
-guard_clause(#k_guard_clause{anno=A,guard=Kg,body=Kb}, Ls, I, Ctxt, Vdb0) ->
- Vdb1 = use_vars(union(A#k.us, Ls), I+2, Vdb0),
- Gdb = vdb_sub(I+1, I+2, Vdb1),
- G = protected(Kg, I+1, Gdb),
- B = match(Kb, Ls, I+2, Ctxt, Vdb1),
- #l{ke={guard_clause,G,B},
- i=I,vdb=use_vars((get_kanno(Kg))#k.us, I+2, Vdb1),
- a=A#k.a}.
-
-%% type(Ktype) -> Type.
-
-type(k_literal) -> literal;
-type(k_int) -> integer;
-%%type(k_char) -> integer; %Hhhmmm???
-type(k_float) -> float;
-type(k_atom) -> atom;
-type(k_nil) -> nil;
-type(k_cons) -> cons;
-type(k_tuple) -> tuple;
-type(k_binary) -> binary;
-type(k_bin_seg) -> bin_seg;
-type(k_bin_int) -> bin_int;
-type(k_bin_end) -> bin_end;
-type(k_map) -> map.
-
-%% variable(Klit) -> Lit.
-%% var_list([Klit]) -> [Lit].
-
-variable(#k_var{name=N}) -> {var,N}.
-
-var_list(Ks) -> [variable(K) || K <- Ks].
-
-%% atomic(Klit) -> Lit.
-%% atomic_list([Klit]) -> [Lit].
-
-atomic(#k_literal{val=V}) -> {literal,V};
-atomic(#k_var{name=N}) -> {var,N};
-atomic(#k_int{val=I}) -> {integer,I};
-atomic(#k_float{val=F}) -> {float,F};
-atomic(#k_atom{val=N}) -> {atom,N};
-%%atomic(#k_char{val=C}) -> {char,C};
-atomic(#k_nil{}) -> nil.
-
-atomic_list(Ks) -> [atomic(K) || K <- Ks].
-
-%% literal(Klit) -> Lit.
-%% literal_list([Klit]) -> [Lit].
-
-literal(#k_var{name=N}, _) -> {var,N};
-literal(#k_literal{val=I}, _) -> {literal,I};
-literal(#k_int{val=I}, _) -> {integer,I};
-literal(#k_float{val=F}, _) -> {float,F};
-literal(#k_atom{val=N}, _) -> {atom,N};
-%%literal(#k_char{val=C}, _) -> {char,C};
-literal(#k_nil{}, _) -> nil;
-literal(#k_cons{hd=H,tl=T}, Ctxt) ->
- {cons,[literal(H, Ctxt),literal(T, Ctxt)]};
-literal(#k_binary{segs=V}, Ctxt) ->
- {binary,literal(V, Ctxt)};
-literal(#k_bin_seg{size=S,unit=U,type=T,flags=Fs,seg=Seg,next=[]}, Ctxt) ->
- %% Only occurs in patterns.
- {bin_seg,Ctxt,literal(S, Ctxt),U,T,Fs,[literal(Seg, Ctxt)]};
-literal(#k_bin_seg{size=S,unit=U,type=T,flags=Fs,seg=Seg,next=N}, Ctxt) ->
- {bin_seg,Ctxt,literal(S, Ctxt),U,T,Fs,
- [literal(Seg, Ctxt),literal(N, Ctxt)]};
-literal(#k_bin_int{size=S,unit=U,flags=Fs,val=Int,next=N}, Ctxt) ->
- %% Only occurs in patterns.
- {bin_int,Ctxt,literal(S, Ctxt),U,Fs,Int,
- [literal(N, Ctxt)]};
-literal(#k_bin_end{}, Ctxt) ->
- {bin_end,Ctxt};
-literal(#k_tuple{es=Es}, Ctxt) ->
- {tuple,literal_list(Es, Ctxt)};
-literal(#k_map{op=Op,var=Var,es=Es0}, Ctxt) ->
- {map,Op,literal(Var, Ctxt),literal_list(Es0, Ctxt)};
-literal(#k_map_pair{key=K,val=V}, Ctxt) ->
- {map_pair,literal(K, Ctxt),literal(V, Ctxt)}.
-
-literal_list(Ks, Ctxt) ->
- [literal(K, Ctxt) || K <- Ks].
-
-
-%% is_gc_bif(Name, Arity) -> true|false
-%% Determines whether the BIF Name/Arity might do a GC.
-
-is_gc_bif(hd, 1) -> false;
-is_gc_bif(tl, 1) -> false;
-is_gc_bif(self, 0) -> false;
-is_gc_bif(node, 0) -> false;
-is_gc_bif(node, 1) -> false;
-is_gc_bif(element, 2) -> false;
-is_gc_bif(get, 1) -> false;
-is_gc_bif(tuple_size, 1) -> false;
-is_gc_bif(Bif, Arity) ->
- not (erl_internal:bool_op(Bif, Arity) orelse
- erl_internal:new_type_test(Bif, Arity) orelse
- erl_internal:comp_op(Bif, Arity)).
-
-%% Keep track of life time for variables.
-%%
-%% init_vars([{var,VarName}]) -> Vdb.
-%% new_vars([VarName], I, Vdb) -> Vdb.
-%% use_vars([VarName], I, Vdb) -> Vdb.
-%% add_var(VarName, F, L, Vdb) -> Vdb.
-%%
-%% The list of variable names for new_vars/3 and use_vars/3
-%% must be sorted.
-
-init_vars(Vs) ->
- vdb_new(Vs).
-
-new_vars([], _, Vdb) -> Vdb;
-new_vars([V], I, Vdb) -> vdb_store_new(V, {V,I,I}, Vdb);
-new_vars(Vs, I, Vdb) -> vdb_update_vars(Vs, Vdb, I).
-
-use_vars([], _, Vdb) ->
- Vdb;
-use_vars([V], I, Vdb) ->
- case vdb_find(V, Vdb) of
- {V,F,L} when I > L -> vdb_update(V, {V,F,I}, Vdb);
- {V,_,_} -> Vdb;
- error -> vdb_store_new(V, {V,I,I}, Vdb)
- end;
-use_vars(Vs, I, Vdb) -> vdb_update_vars(Vs, Vdb, I).
-
-add_var(V, F, L, Vdb) ->
- vdb_store_new(V, {V,F,L}, Vdb).
-
-%% vdb
-
-vdb_new(Vs) ->
- sort([{V,0,0} || {var,V} <- Vs]).
-
--type var() :: atom().
-
--spec vdb_find(var(), [vdb_entry()]) -> 'error' | vdb_entry().
-
-vdb_find(V, Vdb) ->
- case lists:keyfind(V, 1, Vdb) of
- false -> error;
- Vd -> Vd
- end.
-
-vdb_update(V, Update, [{V,_,_}|Vdb]) ->
- [Update|Vdb];
-vdb_update(V, Update, [Vd|Vdb]) ->
- [Vd|vdb_update(V, Update, Vdb)].
-
-vdb_store_new(V, New, [{V1,_,_}=Vd|Vdb]) when V > V1 ->
- [Vd|vdb_store_new(V, New, Vdb)];
-vdb_store_new(V, New, [{V1,_,_}|_]=Vdb) when V < V1 ->
- [New|Vdb];
-vdb_store_new(_, New, []) -> [New].
-
-vdb_update_vars([V|_]=Vs, [{V1,_,_}=Vd|Vdb], I) when V > V1 ->
- [Vd|vdb_update_vars(Vs, Vdb, I)];
-vdb_update_vars([V|Vs], [{V1,_,_}|_]=Vdb, I) when V < V1 ->
- %% New variable.
- [{V,I,I}|vdb_update_vars(Vs, Vdb, I)];
-vdb_update_vars([V|Vs], [{_,F,L}=Vd|Vdb], I) ->
- %% Existing variable.
- if
- I > L -> [{V,F,I}|vdb_update_vars(Vs, Vdb, I)];
- true -> [Vd|vdb_update_vars(Vs, Vdb, I)]
- end;
-vdb_update_vars([V|Vs], [], I) ->
- %% New variable.
- [{V,I,I}|vdb_update_vars(Vs, [], I)];
-vdb_update_vars([], Vdb, _) -> Vdb.
-
-%% vdb_sub(Min, Max, Vdb) -> Vdb.
-%% Extract variables which are used before and after Min. Lock
-%% variables alive after Max.
-
-vdb_sub(Min, Max, Vdb) ->
- [ if L >= Max -> {V,F,locked};
- true -> Vd
- end || {V,F,L}=Vd <- Vdb, F < Min, L >= Min ].
diff --git a/lib/compiler/src/v3_life.hrl b/lib/compiler/src/v3_life.hrl
deleted file mode 100644
index 5c76312067..0000000000
--- a/lib/compiler/src/v3_life.hrl
+++ /dev/null
@@ -1,29 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%% This record contains variable life-time annotation for a
-%% kernel expression. Added by v3_life, used by v3_codegen.
-
--type vdb_entry() :: {atom(),non_neg_integer(),non_neg_integer()}.
-
--record(l, {ke, %Kernel expression
- i=0 :: non_neg_integer(), %Op number
- vdb=[] :: [vdb_entry()], %Variable database
- a=[] :: [term()]}). %Core annotation
-
diff --git a/lib/compiler/test/Makefile b/lib/compiler/test/Makefile
index 63763f31b2..db8eb7e2e1 100644
--- a/lib/compiler/test/Makefile
+++ b/lib/compiler/test/Makefile
@@ -14,6 +14,7 @@ MODULES= \
beam_except_SUITE \
beam_jump_SUITE \
beam_reorder_SUITE \
+ beam_ssa_SUITE \
beam_type_SUITE \
beam_utils_SUITE \
bif_SUITE \
@@ -22,6 +23,7 @@ MODULES= \
bs_construct_SUITE \
bs_match_SUITE \
bs_utf_SUITE \
+ core_alias_SUITE \
core_fold_SUITE \
compile_SUITE \
compilation_SUITE \
@@ -51,6 +53,7 @@ NO_OPT= \
beam_except \
beam_jump \
beam_reorder \
+ beam_ssa \
beam_type \
beam_utils \
bif \
@@ -74,6 +77,7 @@ INLINE= \
andor \
apply \
beam_block \
+ beam_ssa \
beam_utils \
bif \
bs_bincomp \
@@ -93,16 +97,30 @@ INLINE= \
receive \
record
+R21= \
+ bs_construct \
+ bs_match
+
CORE_MODULES = \
lfe_andor_SUITE \
lfe_guard_SUITE
+NO_MOD_OPT = $(NO_OPT)
+
+NO_SSA_OPT = $(NO_OPT)
+
NO_OPT_MODULES= $(NO_OPT:%=%_no_opt_SUITE)
NO_OPT_ERL_FILES= $(NO_OPT_MODULES:%=%.erl)
POST_OPT_MODULES= $(NO_OPT:%=%_post_opt_SUITE)
POST_OPT_ERL_FILES= $(POST_OPT_MODULES:%=%.erl)
INLINE_MODULES= $(INLINE:%=%_inline_SUITE)
INLINE_ERL_FILES= $(INLINE_MODULES:%=%.erl)
+R21_MODULES= $(R21:%=%_r21_SUITE)
+R21_ERL_FILES= $(R21_MODULES:%=%.erl)
+NO_MOD_OPT_MODULES= $(NO_MOD_OPT:%=%_no_module_opt_SUITE)
+NO_MOD_OPT_ERL_FILES= $(NO_MOD_OPT_MODULES:%=%.erl)
+NO_SSA_OPT_MODULES= $(NO_SSA_OPT:%=%_no_ssa_opt_SUITE)
+NO_SSA_OPT_ERL_FILES= $(NO_SSA_OPT_MODULES:%=%.erl)
ERL_FILES= $(MODULES:%=%.erl)
CORE_FILES= $(CORE_MODULES:%=%.core)
@@ -123,7 +141,7 @@ RELSYSDIR = $(RELEASE_PATH)/compiler_test
# ----------------------------------------------------
ERL_MAKE_FLAGS +=
-ERL_COMPILE_FLAGS += +clint +clint0
+ERL_COMPILE_FLAGS += +clint +clint0 +ssalint
EBIN = .
@@ -131,15 +149,24 @@ EBIN = .
# Targets
# ----------------------------------------------------
-make_emakefile: $(NO_OPT_ERL_FILES) $(POST_OPT_ERL_FILES) $(INLINE_ERL_FILES)
+make_emakefile: $(NO_OPT_ERL_FILES) $(POST_OPT_ERL_FILES) $(NO_SSA_OPT_ERL_FILES) \
+ $(INLINE_ERL_FILES) $(R21_ERL_FILES) $(NO_MOD_OPT_ERL_FILES)
$(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES) \
> $(EMAKEFILE)
- $(ERL_TOP)/make/make_emakefile +no_copt +no_postopt $(ERL_COMPILE_FLAGS) \
+ $(ERL_TOP)/make/make_emakefile +no_copt +no_postopt \
+ +no_ssa_opt +no_recv_opt $(ERL_COMPILE_FLAGS) \
-o$(EBIN) $(NO_OPT_MODULES) >> $(EMAKEFILE)
+ $(ERL_TOP)/make/make_emakefile +no_share_opt +no_bsm_opt +no_fun_opt \
+ +no_ssa_opt +no_recv_opt $(ERL_COMPILE_FLAGS) \
+ -o$(EBIN) $(NO_SSA_OPT_MODULES) >> $(EMAKEFILE)
$(ERL_TOP)/make/make_emakefile +no_copt $(ERL_COMPILE_FLAGS) \
-o$(EBIN) $(POST_OPT_MODULES) >> $(EMAKEFILE)
$(ERL_TOP)/make/make_emakefile +inline $(ERL_COMPILE_FLAGS) \
-o$(EBIN) $(INLINE_MODULES) >> $(EMAKEFILE)
+ $(ERL_TOP)/make/make_emakefile +r21 $(ERL_COMPILE_FLAGS) \
+ -o$(EBIN) $(R21_MODULES) >> $(EMAKEFILE)
+ $(ERL_TOP)/make/make_emakefile +no_module_opt $(ERL_COMPILE_FLAGS) \
+ -o$(EBIN) $(NO_MOD_OPT_MODULES) >> $(EMAKEFILE)
$(ERL_TOP)/make/make_emakefile +from_core $(ERL_COMPILE_FLAGS) \
-o$(EBIN) $(CORE_MODULES) >> $(EMAKEFILE)
@@ -160,12 +187,21 @@ docs:
%_no_opt_SUITE.erl: %_SUITE.erl
sed -e 's;-module($(basename $<));-module($(basename $@));' $< > $@
+%_no_ssa_opt_SUITE.erl: %_SUITE.erl
+ sed -e 's;-module($(basename $<));-module($(basename $@));' $< > $@
+
%_post_opt_SUITE.erl: %_SUITE.erl
sed -e 's;-module($(basename $<));-module($(basename $@));' $< > $@
%_inline_SUITE.erl: %_SUITE.erl
sed -e 's;-module($(basename $<));-module($(basename $@));' $< > $@
+%_r21_SUITE.erl: %_SUITE.erl
+ sed -e 's;-module($(basename $<));-module($(basename $@));' $< > $@
+
+%_no_module_opt_SUITE.erl: %_SUITE.erl
+ sed -e 's;-module($(basename $<));-module($(basename $@));' $< > $@
+
# ----------------------------------------------------
# Release Target
# ----------------------------------------------------
@@ -178,7 +214,9 @@ release_tests_spec: make_emakefile
$(INSTALL_DATA) compiler.spec compiler.cover \
$(EMAKEFILE) $(ERL_FILES) "$(RELSYSDIR)"
$(INSTALL_DATA) $(NO_OPT_ERL_FILES) $(POST_OPT_ERL_FILES) \
- $(INLINE_ERL_FILES) "$(RELSYSDIR)"
+ $(INLINE_ERL_FILES) $(R21_ERL_FILES) \
+ $(NO_MOD_OPT_ERL_FILES) \
+ $(NO_SSA_OPT_ERL_FILES) "$(RELSYSDIR)"
$(INSTALL_DATA) $(CORE_FILES) "$(RELSYSDIR)"
for file in $(ERL_DUMMY_FILES); do \
module=`basename $$file .erl`; \
diff --git a/lib/compiler/test/andor_SUITE.erl b/lib/compiler/test/andor_SUITE.erl
index 05c087104d..5c463063c1 100644
--- a/lib/compiler/test/andor_SUITE.erl
+++ b/lib/compiler/test/andor_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,7 +29,6 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -38,6 +37,7 @@ groups() ->
combined,in_case,slow_compilation]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/apply_SUITE.erl b/lib/compiler/test/apply_SUITE.erl
index cca92e4713..2ee518b1a0 100644
--- a/lib/compiler/test/apply_SUITE.erl
+++ b/lib/compiler/test/apply_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,13 +29,13 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[mfa, fun_apply].
groups() ->
[].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -73,6 +73,7 @@ mfa(Config) when is_list(Config) ->
{'EXIT',_} = (catch ?APPLY2(Mod, (id(bazzzzzz)), a, b)),
{'EXIT',_} = (catch ?APPLY2({}, baz, a, b)),
{'EXIT',_} = (catch ?APPLY2(?MODULE, [], a, b)),
+ {'EXIT',_} = (catch bad_literal_call(1)),
ok = apply(Mod, foo, id([])),
{[a,b|c]} = apply(Mod, bar, id([[a,b|c]])),
@@ -92,6 +93,13 @@ mfa(Config) when is_list(Config) ->
apply(Mod, foo, []).
+%% The single call to this function with a literal argument caused type
+%% optimization to swap out the 'mod' field of a #b_remote{}, which was
+%% mishandled during code generation as it assumed that the module would always
+%% be an atom.
+bad_literal_call(I) ->
+ I:foo().
+
foo() ->
ok.
diff --git a/lib/compiler/test/beam_block_SUITE.erl b/lib/compiler/test/beam_block_SUITE.erl
index 55d5f2dbe8..40a30b65d7 100644
--- a/lib/compiler/test/beam_block_SUITE.erl
+++ b/lib/compiler/test/beam_block_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@
-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,
init_per_group/2,end_per_group/2,
get_map_elements/1,otp_7345/1,move_opt_across_gc_bif/1,
- erl_202/1,repro/1]).
+ erl_202/1,repro/1,local_cse/1,second_block_pass/1]).
%% The only test for the following functions is that
%% the code compiles and is accepted by beam_validator.
@@ -31,7 +31,6 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -40,10 +39,13 @@ groups() ->
otp_7345,
move_opt_across_gc_bif,
erl_202,
- repro
+ repro,
+ local_cse,
+ second_block_pass
]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -237,6 +239,72 @@ find_operands(Cfg,XsiGraph,ActiveList,Count) ->
[Count+1, length(NewActiveList), length(digraph:vertices(XsiGraph))],
find_operands(NewCfg,XsiGraph,NewActiveList,Count+1).
+%% Some tests of local common subexpression elimination (CSE).
+
+local_cse(_Config) ->
+ {Self,{ok,Self}} = local_cse_1(),
+
+ local_cse_2([]),
+ local_cse_2(lists:seq(1, 512)),
+ local_cse_2(?MODULE:module_info()),
+
+ {[b],[a,b]} = local_cse_3(a, b),
+
+ {2000,Self,{Self,write_cache}} = local_cse_4(),
+
+ ok.
+
+local_cse_1() ->
+ %% Cover handling of unsafe tuple construction in
+ %% eliminate_use_of_from_reg/4. It became necessary to handle
+ %% unsafe tuples when local CSE was introduced.
+
+ {self(),{ok,self()}}.
+
+local_cse_2(Term) ->
+ case cse_make_binary(Term) of
+ <<Size:8,BinTerm:Size/binary>> ->
+ Term = binary_to_term(BinTerm);
+ <<Size:8,SizeTerm:Size/binary,BinTerm/binary>> ->
+ {'$size',TermSize} = binary_to_term(SizeTerm),
+ TermSize = byte_size(BinTerm),
+ Term = binary_to_term(BinTerm)
+ end.
+
+%% Copy of observer_backend:ttb_make_binary/1. During development of
+%% the local CSE optimization this function was incorrectly optimized.
+
+cse_make_binary(Term) ->
+ B = term_to_binary(Term),
+ SizeB = byte_size(B),
+ if SizeB > 255 ->
+ SB = term_to_binary({'$size',SizeB}),
+ <<(byte_size(SB)):8, SB/binary, B/binary>>;
+ true ->
+ <<SizeB:8, B/binary>>
+ end.
+
+local_cse_3(X, Y) ->
+ %% The following expression was incorrectly transformed to {[X,Y],[X,Y]}
+ %% during development of the local CSE optimization.
+
+ {[Y],[X,Y]}.
+
+local_cse_4() ->
+ do_local_cse_4(2000, self(), {self(), write_cache}).
+
+do_local_cse_4(X, Y, Z) ->
+ {X,Y,Z}.
+
+%% Tests previously found bugs when running beam_block the second time.
+
+second_block_pass(_Config) ->
+ [#{dts:=5.0}] = second_1([#{dts => 10.0}], 2.0),
+ ok.
+
+second_1(Fs, TS) ->
+ [F#{dts=>DTS / TS} || #{dts:=DTS} = F <- Fs].
+
%%%
%%% Common functions.
%%%
diff --git a/lib/compiler/test/beam_except_SUITE.erl b/lib/compiler/test/beam_except_SUITE.erl
index 47367d6eab..8e3b373d29 100644
--- a/lib/compiler/test/beam_except_SUITE.erl
+++ b/lib/compiler/test/beam_except_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,20 +21,21 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
- multiple_allocs/1,coverage/1]).
+ multiple_allocs/1,bs_get_tail/1,coverage/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
[{p,[parallel],
[multiple_allocs,
+ bs_get_tail,
coverage]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -63,6 +64,17 @@ place(lee) ->
conditions() ->
(talking = going) = storage + [large = wanted].
+bs_get_tail(Config) ->
+ {<<"abc">>,0,0,Config} = bs_get_tail_1(id(<<0:32, "abc">>), 0, 0, Config),
+ {'EXIT',
+ {function_clause,
+ [{?MODULE,bs_get_tail_1,[<<>>,0,0,Config],_}|_]}} =
+ (catch bs_get_tail_1(id(<<>>), 0, 0, Config)),
+ ok.
+
+bs_get_tail_1(<<_:32, Rest/binary>>, Z1, Z2, F1) ->
+ {Rest,Z1,Z2,F1}.
+
coverage(_) ->
File = {file,"fake.erl"},
ok = fc(a),
@@ -72,9 +84,16 @@ coverage(_) ->
{'EXIT',{function_clause,
[{?MODULE,fc,[y],[File,{line,2}]}|_]}} =
(catch fc(y)),
- {'EXIT',{function_clause,
- [{?MODULE,fc,[[a,b,c]],[File,{line,6}]}|_]}} =
- (catch fc([a,b,c])),
+ case ?MODULE of
+ beam_except_no_opt_SUITE ->
+ %% There will be a different stack fram in
+ %% unoptimized code.
+ ok;
+ _ ->
+ {'EXIT',{function_clause,
+ [{?MODULE,fc,[[a,b,c]],[File,{line,6}]}|_]}} =
+ (catch fc([a,b,c]))
+ end,
{'EXIT',{undef,[{erlang,error,[a,b,c],_}|_]}} =
(catch erlang:error(a, b, c)),
@@ -83,8 +102,24 @@ coverage(_) ->
(catch bar(x)),
{'EXIT',{{case_clause,{1}},[{?MODULE,bar,1,[File,{line,9}]}|_]}} =
(catch bar(0)),
+
+ Self = self(),
+ {'EXIT',{{strange,Self},[{?MODULE,foo,[any],[File,{line,14}]}|_]}} =
+ (catch foo(any)),
+
+ {ok,succeed,1,2} = foobar(succeed, 1, 2),
+ {'EXIT',{function_clause,[{?MODULE,foobar,[[fail],1,2],
+ [{file,"fake.erl"},{line,16}]}|_]}} =
+ (catch foobar([fail], 1, 2)),
+ {'EXIT',{function_clause,[{?MODULE,fake_function_clause,[{a,b},42.0],_}|_]}} =
+ (catch fake_function_clause({a,b})),
+
ok.
+fake_function_clause(A) -> error(function_clause, [A,42.0]).
+
+id(I) -> I.
+
-file("fake.erl", 1).
fc(a) -> %Line 2
ok; %Line 3
@@ -96,3 +131,9 @@ bar(X) -> %Line 8
case {X+1} of %Line 9
1 -> ok %Line 10
end. %Line 11
+%% Cover collection code for function_clause exceptions.
+foo(A) -> %Line 13
+ error({strange,self()}, [A]). %Line 14
+%% Cover beam_except:tag_literal/1.
+foobar(A, B, C) when is_atom(A) -> %Line 16
+ {ok,A,B,C}. %Line 17
diff --git a/lib/compiler/test/beam_jump_SUITE.erl b/lib/compiler/test/beam_jump_SUITE.erl
index 088f63606c..a456f31d79 100644
--- a/lib/compiler/test/beam_jump_SUITE.erl
+++ b/lib/compiler/test/beam_jump_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2016. All Rights Reserved.
+%% Copyright Ericsson AB 2016-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,22 +21,27 @@
-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,
init_per_group/2,end_per_group/2,
- undefined_label/1,ambiguous_catch_try_state/1]).
+ undefined_label/1,ambiguous_catch_try_state/1,
+ unsafe_move_elimination/1,build_tuple/1,
+ coverage/1]).
suite() ->
[{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
[{p,[parallel],
[undefined_label,
- ambiguous_catch_try_state
+ ambiguous_catch_try_state,
+ unsafe_move_elimination,
+ build_tuple,
+ coverage
]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -72,3 +77,134 @@ river() -> song.
checks(Wanted) ->
%% Must be one line to cause the unsafe optimization.
{catch case river() of sheet -> begin +Wanted, if "da" -> Wanted end end end, catch case river() of sheet -> begin + Wanted, if "da" -> Wanted end end end}.
+
+unsafe_move_elimination(_Config) ->
+ {{left,right,false},false} = unsafe_move_elimination_1(left, right, false),
+ {{false,right,false},false} = unsafe_move_elimination_1(false, right, true),
+ {{true,right,right},right} = unsafe_move_elimination_1(true, right, true),
+ [ok = unsafe_move_elimination_2(I) || I <- lists:seq(0,16)],
+ ok.
+
+unsafe_move_elimination_1(Left, Right, Simple0) ->
+ id(1),
+
+ %% The move at label 29 would be removed by beam_jump, which is unsafe because
+ %% the two select_val instructions have different source registers.
+ %%
+ %% {select_val,{y,0},{f,25},{list,[{atom,true},{f,27},{atom,false},{f,29}]}}.
+ %% ^^^^^ ^^^^^^^^^^^^^^^^^^^
+ %% {label,27}.
+ %% {kill,{y,0}}.
+ %% {move,{y,2},{x,0}}.
+ %% {line,...}.
+ %% {call,1,{f,31}}.
+ %% {select_val,{x,0},{f,33},{list,[{atom,true},{f,35},{atom,false},{f,29}]}}.
+ %% ^^^^^ ^^^^^^^^^^^^^^^^^^^
+ %% {label,29}.
+ %% {move,{atom,false},{y,0}}. <=== REMOVED (unsafely).
+ %% {jump,{f,37}}.
+
+ Simple = case case Simple0 of
+ false -> false;
+ true -> id(Left)
+ end
+ of
+ false ->
+ false;
+ true ->
+ id(Right)
+ end,
+ {id({Left,Right,Simple}),Simple}.
+
+unsafe_move_elimination_2(Int) ->
+ %% The type optimization pass would recognize that TagInt can only be
+ %% [0 .. 7], so the first 'case' would select_val over [0 .. 6] and swap
+ %% out the fail label with the block for 7.
+ %%
+ %% A later optimization would merge this block with 'expects_h' in the
+ %% second case, as the latter is only reachable from the former.
+ %%
+ %% ... but this broke down when the move elimination optimization didn't
+ %% take the fail label of the first select_val into account. This caused it
+ %% to believe that the only way to reach 'expects_h' was through the second
+ %% case when 'Tag' =:= 'h', which made it remove the move instruction
+ %% added in the first case, passing garbage to expects_h/2.
+ TagInt = Int band 2#111,
+ Tag = case TagInt of
+ 0 -> a;
+ 1 -> b;
+ 2 -> c;
+ 3 -> d;
+ 4 -> e;
+ 5 -> f;
+ 6 -> g;
+ 7 -> h
+ end,
+ case Tag of
+ g -> expects_g(TagInt, Tag);
+ h -> expects_h(TagInt, Tag);
+ _ -> Tag = id(Tag), ok
+ end.
+
+expects_g(6, Atom) ->
+ Atom = id(g),
+ ok.
+
+expects_h(7, Atom) ->
+ Atom = id(h),
+ ok.
+
+-record(message2, {id, p1}).
+-record(message3, {id, p1, p2}).
+
+build_tuple(_Config) ->
+ {'EXIT',{{badrecord,message3},_}} = (catch do_build_tuple(#message2{})),
+ ok.
+
+do_build_tuple(Message) ->
+ if is_record(Message, message2) ->
+ Res = {res, rand:uniform(100)},
+ {Message#message3.id, Res}
+ end.
+
+coverage(_Config) ->
+ ok = coverage_1(ok),
+ {error,badarg} = coverage_1({error,badarg}),
+
+ gt = coverage_2(100, 42),
+ le = coverage_2(100, 999),
+ le = coverage_2([], []),
+ gt = coverage_2([], xxx),
+
+ ok.
+
+coverage_1(Var) ->
+ case id(Var) of
+ ok -> ok;
+ Error -> Error
+ end.
+
+%% Cover beam_jump:invert_test(is_ne_exact).
+coverage_2(Pre1, Pre2) ->
+ case
+ case Pre1 == [] of
+ false ->
+ false;
+ true ->
+ Pre2 /= []
+ end
+ of
+ true ->
+ gt;
+ false ->
+ case Pre1 > Pre2 of
+ true ->
+ gt;
+ false ->
+ le
+ end
+ end.
+
+
+id(I) ->
+ I.
diff --git a/lib/compiler/test/beam_reorder_SUITE.erl b/lib/compiler/test/beam_reorder_SUITE.erl
index 27ce51eec3..c8a4f9a75f 100644
--- a/lib/compiler/test/beam_reorder_SUITE.erl
+++ b/lib/compiler/test/beam_reorder_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,7 +26,6 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -36,6 +35,7 @@ groups() ->
]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/beam_ssa_SUITE.erl b/lib/compiler/test/beam_ssa_SUITE.erl
new file mode 100644
index 0000000000..15cf9bcbf3
--- /dev/null
+++ b/lib/compiler/test/beam_ssa_SUITE.erl
@@ -0,0 +1,497 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(beam_ssa_SUITE).
+
+-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,
+ init_per_group/2,end_per_group/2,
+ calls/1,tuple_matching/1,recv/1,maps/1,
+ cover_ssa_dead/1,combine_sw/1,share_opt/1]).
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [{group,p}].
+
+groups() ->
+ [{p,test_lib:parallel(),
+ [tuple_matching,
+ calls,
+ recv,
+ maps,
+ cover_ssa_dead,
+ combine_sw,
+ share_opt
+ ]}].
+
+init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+calls(Config) ->
+ Ret = {return,value,Config},
+ Ret = fun_call(fun(42) -> ok end, Ret),
+ Ret = apply_fun(fun(a, b) -> ok end, [a,b], Ret),
+ Ret = apply_mfa(test_lib, id, [anything], Ret),
+ {'EXIT',{badarg,_}} = (catch call_error()),
+ {'EXIT',{badarg,_}} = (catch call_error(42)),
+ 5 = start_it([erlang,length,1,2,3,4,5]),
+ ok.
+
+fun_call(Fun, X0) ->
+ X = id(X0),
+ Fun(42),
+ X.
+
+apply_fun(Fun, Args, X0) ->
+ X = id(X0),
+ apply(Fun, Args),
+ X.
+
+apply_mfa(Mod, Name, Args, X0) ->
+ X = id(X0),
+ apply(Mod, Name, Args),
+ X.
+
+call_error() ->
+ error(badarg),
+ ok.
+
+call_error(I) ->
+ <<I:(-8)>>,
+ ok.
+
+start_it([_|_]=MFA) ->
+ case MFA of
+ [M,F|Args] -> M:F(Args)
+ end.
+
+tuple_matching(_Config) ->
+ do_tuple_matching({tag,42}),
+
+ true = is_two_tuple({a,b}),
+ false = is_two_tuple({a,b,c}),
+ false = is_two_tuple(atom),
+
+ ok.
+
+do_tuple_matching(Arg) ->
+ Res = do_tuple_matching_1(Arg),
+ Res = do_tuple_matching_2(Arg),
+ Res = do_tuple_matching_3(Arg),
+ Res.
+
+do_tuple_matching_1({tag,V}) ->
+ {ok,V}.
+
+do_tuple_matching_2(Tuple) when is_tuple(Tuple) ->
+ Size = tuple_size(Tuple),
+ if
+ Size =:= 2 ->
+ {ok,element(2, Tuple)}
+ end.
+
+do_tuple_matching_3(Tuple) when is_tuple(Tuple) ->
+ Size = tuple_size(Tuple),
+ if
+ Size =:= 2 ->
+ 2 = id(Size),
+ {ok,element(2, Tuple)}
+ end.
+
+is_two_tuple(Arg) ->
+ case is_tuple(Arg) of
+ false -> false;
+ true -> tuple_size(Arg) == 2
+ end.
+
+-record(reporter_state, {res,run_config}).
+-record(run_config, {report_interval=0}).
+
+recv(_Config) ->
+ Parent = self(),
+
+ %% Test sync_wait_mon/2.
+ Succ = fun() -> Parent ! {ack,self(),{result,42}} end,
+ {result,42} = sync_wait_mon(spawn_monitor(Succ), infinity),
+
+ Down = fun() -> exit(down) end,
+ {error,down} = sync_wait_mon(spawn_monitor(Down), infinity),
+
+ Exit = fun() ->
+ Self = self(),
+ spawn(fun() -> exit(Self, kill_me) end),
+ receive _ -> ok end
+ end,
+ {error,kill_me} = sync_wait_mon(spawn_monitor(Exit), infinity),
+
+ Timeout = fun() -> receive _ -> ok end end,
+ {error,timeout} = sync_wait_mon(spawn_monitor(Timeout), 0),
+
+ %% Test reporter_loop/1.
+ {a,Parent} = reporter_loop(#reporter_state{res={a,Parent},
+ run_config=#run_config{}}),
+
+ %% Test bad_sink/0.
+ bad_sink(),
+
+ %% Test tricky_recv_1/0.
+ self() ! 1,
+ a = tricky_recv_1(),
+ self() ! 2,
+ b = tricky_recv_1(),
+
+ %% Test tricky_recv_2/0.
+ self() ! 1,
+ {1,yes} = tricky_recv_2(),
+ self() ! 2,
+ {2,maybe} = tricky_recv_2(),
+
+ %% Test 'receive after infinity' in try/catch.
+ Pid = spawn(fun recv_after_inf_in_try/0),
+ exit(Pid, done),
+
+ %% Test tricky_recv_3().
+ self() ! {{self(),r0},{1,42,"name"}},
+ {Parent,r0,[<<1:32,1:8,42:8>>,"name",0]} = tricky_recv_3(),
+ self() ! {{self(),r1},{2,99,<<"data">>}},
+ {Parent,r1,<<1:32,2:8,99:8,"data">>} = tricky_recv_3(),
+
+ %% Test tricky_recv_4().
+ self() ! {[self(),r0],{1,42,"name"}},
+ {Parent,r0,[<<1:32,1:8,42:8>>,"name",0]} = tricky_recv_4(),
+ self() ! {[self(),r1],{2,99,<<"data">>}},
+ {Parent,r1,<<1:32,2:8,99:8,"data">>} = tricky_recv_4(),
+
+ ok.
+
+sync_wait_mon({Pid, Ref}, Timeout) ->
+ receive
+ {ack,Pid,Return} ->
+ erlang:demonitor(Ref, [flush]),
+ Return;
+ {'DOWN',Ref,_Type,Pid,Reason} ->
+ {error,Reason};
+ {'EXIT',Pid,Reason} ->
+ erlang:demonitor(Ref, [flush]),
+ {error,Reason}
+ after Timeout ->
+ erlang:demonitor(Ref, [flush]),
+ exit(Pid, kill),
+ {error,timeout}
+ end.
+
+reporter_loop(State) ->
+ RC = State#reporter_state.run_config,
+ receive after RC#run_config.report_interval ->
+ State#reporter_state.res
+ end.
+
+bad_sink() ->
+ {ok,Pid} = my_spawn(self()),
+ %% The get_tuple_element instruction for the matching
+ %% above was sinked into the receive loop. That will
+ %% not work (and would be bad for performance if it
+ %% would work).
+ receive
+ {ok,Pid} ->
+ ok;
+ error ->
+ exit(failed)
+ end,
+ exit(Pid, kill).
+
+my_spawn(Parent) ->
+ Pid = spawn(fun() ->
+ Parent ! {ok,self()},
+ receive _ -> ok end
+ end),
+ {ok,Pid}.
+
+tricky_recv_1() ->
+ receive
+ X=1 ->
+ id(42),
+ a;
+ X=2 ->
+ b
+ end,
+ case X of
+ 1 -> a;
+ 2 -> b
+ end.
+
+tricky_recv_2() ->
+ receive
+ X=1 ->
+ Y = case id(X) of
+ 1 -> yes;
+ _ -> no
+ end,
+ a;
+ X=2 ->
+ Y = maybe,
+ b
+ end,
+ {X,Y}.
+
+recv_after_inf_in_try() ->
+ try
+ %% Used to crash beam_kernel_to_ssa.
+ receive after infinity -> ok end
+ catch
+ _A:_B ->
+ receive after infinity -> ok end
+ end.
+
+tricky_recv_3() ->
+ {Pid, R, Request} =
+ receive
+ {{Pid0,R0}, {1, Proto0, Name0}} ->
+ {Pid0, R0,
+ [<<1:32, 1:8, Proto0:8>>,Name0,0]};
+ {{Pid1,R1}, {2, Proto1, Data1}} ->
+ {Pid1, R1,
+ <<1:32, 2:8, Proto1:8, Data1/binary>>}
+ end,
+ id({Pid,R,Request}).
+
+tricky_recv_4() ->
+ {Pid, R, Request} =
+ receive
+ {[Pid0,R0], {1, Proto0, Name0}} ->
+ {Pid0, R0,
+ [<<1:32, 1:8, Proto0:8>>,Name0,0]};
+ {[Pid1,R1], {2, Proto1, Data1}} ->
+ {Pid1, R1,
+ <<1:32, 2:8, Proto1:8, Data1/binary>>}
+ end,
+ id({Pid,R,Request}).
+
+maps(_Config) ->
+ {'EXIT',{{badmatch,#{}},_}} = (catch maps_1(any)),
+ ok.
+
+maps_1(K) ->
+ _ = id(42),
+ #{K:=V} = #{},
+ V.
+
+-record(wx_ref, {type=any_type,ref=any_ref}).
+
+cover_ssa_dead(_Config) ->
+ str = format_str(str, escapable, [], true),
+ [iolist,str] = format_str(str, escapable, iolist, true),
+ bad = format_str(str, not_escapable, [], true),
+ bad = format_str(str, not_escapable, iolist, true),
+ bad = format_str(str, escapable, [], false),
+ bad = format_str(str, escapable, [], bad),
+
+ DefWxRef = #wx_ref{},
+ {DefWxRef,77,9999,[]} = contains(#wx_ref{}, 77, 9999),
+ {DefWxRef,77.0,9999,[]} = contains(#wx_ref{}, 77.0, 9999),
+ {DefWxRef,77,9999.0,[]} = contains(#wx_ref{}, 77, 9999.0),
+ {DefWxRef,77.0,9999.0,[]} = contains(#wx_ref{}, 77.0, 9999.0),
+ {any_type,any_ref,42,43,[option]} = contains(#wx_ref{}, {42,43}, [option]),
+ {any_type,any_ref,42,43,[]} = contains(#wx_ref{}, {42,43}, []),
+ {any_type,any_ref,42.0,43,[]} = contains(#wx_ref{}, {42.0,43}, []),
+ {any_type,any_ref,42,43.0,[]} = contains(#wx_ref{}, {42,43.0}, []),
+ {any_type,any_ref,42.0,43.0,[]} = contains(#wx_ref{}, {42.0,43.0}, []),
+
+ nope = conv_alub(false, '=:='),
+ ok = conv_alub(true, '=:='),
+ ok = conv_alub(true, none),
+ error = conv_alub(false, none),
+
+ {false,false} = eval_alu(false, false, false),
+ {true,false} = eval_alu(false, false, true),
+ {false,true} = eval_alu(false, true, false),
+ {false,false} = eval_alu(false, true, true),
+ {false,true} = eval_alu(true, false, false),
+ {false,false} = eval_alu(true, false, true),
+ {true,true} = eval_alu(true, true, false),
+ {false,true} = eval_alu(true, true, true),
+
+ 100.0 = percentage(1.0, 0.0),
+ 100.0 = percentage(1, 0),
+ 0.0 = percentage(0, 0),
+ 0.0 = percentage(0.0, 0.0),
+ 40.0 = percentage(4.0, 10.0),
+ 60.0 = percentage(6, 10),
+
+ %% Cover '=:=', followed by '=/='.
+ false = 'cover__=:=__=/='(41),
+ true = 'cover__=:=__=/='(42),
+ false = 'cover__=:=__=/='(43),
+
+ %% Cover '<', followed by '=/='.
+ true = 'cover__<__=/='(41),
+ false = 'cover__<__=/='(42),
+ false = 'cover__<__=/='(43),
+
+ %% Cover '=<', followed by '=/='.
+ true = 'cover__=<__=/='(41),
+ true = 'cover__=<__=/='(42),
+ false = 'cover__=<__=/='(43),
+
+ %% Cover '>=', followed by '=/='.
+ false = 'cover__>=__=/='(41),
+ true = 'cover__>=__=/='(42),
+ true = 'cover__>=__=/='(43),
+
+ %% Cover '>', followed by '=/='.
+ false = 'cover__>__=/='(41),
+ false = 'cover__>__=/='(42),
+ true = 'cover__>__=/='(43),
+
+ ok.
+
+'cover__=:=__=/='(X) when X =:= 42 -> X =/= 43;
+'cover__=:=__=/='(_) -> false.
+
+'cover__<__=/='(X) when X < 42 -> X =/= 42;
+'cover__<__=/='(_) -> false.
+
+'cover__=<__=/='(X) when X =< 42 -> X =/= 43;
+'cover__=<__=/='(_) -> false.
+
+'cover__>=__=/='(X) when X >= 42 -> X =/= 41;
+'cover__>=__=/='(_) -> false.
+
+'cover__>__=/='(X) when X > 42 -> X =/= 42;
+'cover__>__=/='(_) -> false.
+
+format_str(Str, FormatData, IoList, EscChars) ->
+ Escapable = FormatData =:= escapable,
+ case id(Str) of
+ IoStr when Escapable, EscChars, IoList == [] ->
+ id(IoStr);
+ IoStr when Escapable, EscChars ->
+ [IoList,id(IoStr)];
+ _ ->
+ bad
+ end.
+
+contains(This, X, Y) when is_record(This, wx_ref), is_number(X), is_number(Y) ->
+ {This,X,Y,[]};
+contains(#wx_ref{type=ThisT,ref=ThisRef}, {CX,CY}, Options)
+ when is_number(CX), is_number(CY), is_list(Options) ->
+ {ThisT,ThisRef,CX,CY,Options}.
+
+conv_alub(HasDst, CmpOp) ->
+ case (not HasDst) andalso CmpOp =/= none of
+ true -> nope;
+ false ->
+ case HasDst of
+ false -> error;
+ true -> ok
+ end
+ end.
+
+eval_alu(Sign1, Sign2, N) ->
+ V = (Sign1 andalso Sign2 andalso (not N))
+ or ((not Sign1) andalso (not Sign2) andalso N),
+ C = (Sign1 andalso Sign2)
+ or ((not N) andalso (Sign1 orelse Sign2)),
+ {V,C}.
+
+percentage(Divident, Divisor) ->
+ if Divisor == 0 andalso Divident /= 0 ->
+ 100.0;
+ Divisor == 0 ->
+ 0.0;
+ true ->
+ Divident / Divisor * 100
+ end.
+
+combine_sw(_Config) ->
+ [a] = do_comb_sw_1(a),
+ [b,b] = do_comb_sw_1(b),
+ [c] = do_comb_sw_1(c),
+ [c] = do_comb_sw_1(c),
+ [] = do_comb_sw_1(z),
+
+ [a] = do_comb_sw_2(a),
+ [b2,b1] = do_comb_sw_2(b),
+ [c] = do_comb_sw_2(c),
+ [c] = do_comb_sw_2(c),
+ [] = do_comb_sw_2(z),
+
+ ok.
+
+do_comb_sw_1(X) ->
+ put(?MODULE, []),
+ if
+ X == a; X == b ->
+ put(?MODULE, [X|get(?MODULE)]);
+ true ->
+ ok
+ end,
+ if
+ X == b; X == c ->
+ put(?MODULE, [X|get(?MODULE)]);
+ true ->
+ ok
+ end,
+ erase(?MODULE).
+
+do_comb_sw_2(X) ->
+ put(?MODULE, []),
+ case X of
+ a ->
+ put(?MODULE, [a|get(?MODULE)]);
+ b ->
+ put(?MODULE, [b1|get(?MODULE)]);
+ _ ->
+ ok
+ end,
+ case X of
+ b ->
+ put(?MODULE, [b2|get(?MODULE)]);
+ c ->
+ put(?MODULE, [c|get(?MODULE)]);
+ _ ->
+ ok
+ end,
+ erase(?MODULE).
+
+share_opt(_Config) ->
+ ok = do_share_opt(0).
+
+do_share_opt(A) ->
+ %% The compiler would be stuck in an infinite loop in beam_ssa_share.
+ case A of
+ 0 -> a;
+ 1 -> b;
+ 2 -> c
+ end,
+ receive after 1 -> ok end.
+
+
+%% The identity function.
+id(I) -> I.
diff --git a/lib/compiler/test/beam_type_SUITE.erl b/lib/compiler/test/beam_type_SUITE.erl
index d44fa60997..882e281a44 100644
--- a/lib/compiler/test/beam_type_SUITE.erl
+++ b/lib/compiler/test/beam_type_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,19 +21,20 @@
-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,
init_per_group/2,end_per_group/2,
- integers/1,coverage/1,booleans/1,setelement/1,cons/1,
- tuple/1,record_float/1,binary_float/1,float_compare/1,
- arity_checks/1]).
+ integers/1,numbers/1,coverage/1,booleans/1,setelement/1,
+ cons/1,tuple/1,record_float/1,binary_float/1,float_compare/1,
+ arity_checks/1,elixir_binaries/1,find_best/1,
+ test_size/1,cover_lists_functions/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
[{p,[parallel],
[integers,
+ numbers,
coverage,
booleans,
setelement,
@@ -42,10 +43,15 @@ groups() ->
record_float,
binary_float,
float_compare,
- arity_checks
+ arity_checks,
+ elixir_binaries,
+ find_best,
+ test_size,
+ cover_lists_functions
]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -111,8 +117,8 @@ do_integers_4(_, _, Res) ->
Res.
do_integers_5(X0, Y0) ->
- %% X and Y will use the same register.
- X = X0 band 1,
+ %% _X and Y will use the same register.
+ _X = X0 band 1,
Y = Y0 band 3,
case Y of
0 -> zero;
@@ -121,7 +127,60 @@ do_integers_5(X0, Y0) ->
3 -> three
end.
-coverage(_Config) ->
+numbers(_Config) ->
+ Int = id(42),
+ true = is_integer(Int),
+ true = is_number(Int),
+ false = is_float(Int),
+
+ Float = id(42.0),
+ true = is_float(Float),
+ true = is_number(Float),
+ false = is_integer(Float),
+
+ Number = id(1) + id(2),
+ true = is_number(Number),
+ true = is_integer(Number),
+ false = is_float(Number),
+
+ AnotherNumber = id(99.0) + id(1),
+ true = is_float(AnotherNumber),
+ true = is_number(AnotherNumber),
+ false = is_integer(AnotherNumber),
+
+ NotNumber = id(atom),
+ true = is_atom(NotNumber),
+ false = is_number(NotNumber),
+ false = is_integer(NotNumber),
+ false = is_float(NotNumber),
+
+ true = is_number(Int),
+ true = is_number(Float),
+ true = is_number(Number),
+ true = is_number(AnotherNumber),
+
+ %% Cover beam_ssa_type:join/2.
+
+ Join1 = case id(a) of
+ a -> 3 + id(7); %Number.
+ b -> id(5) / id(2) %Float.
+ end,
+ true = is_integer(Join1),
+
+ Join2 = case id(a) of
+ a -> id(5) / 2; %Float.
+ b -> 3 + id(7) %Number.
+ end,
+ true = is_float(Join2),
+
+ %% Cover beam_ssa_type:meet/2.
+
+ Meet1 = id(0) + -10.0, %Float.
+ 10.0 = abs(Meet1), %Number.
+
+ ok.
+
+coverage(Config) ->
{'EXIT',{badarith,_}} = (catch id(1) bsl 0.5),
{'EXIT',{badarith,_}} = (catch id(2.0) bsl 2),
{'EXIT',{badarith,_}} = (catch a + 0.5),
@@ -132,18 +191,82 @@ coverage(_Config) ->
id(id(42) band 387439739874298734983787934283479243879),
id(-1 band id(13)),
+ error = if
+ is_map(Config), is_integer(Config) -> ok;
+ true -> error
+ end,
+ error = if
+ is_map(Config), is_atom(Config) -> ok;
+ true -> error
+ end,
+ error = if
+ is_map(Config), is_tuple(Config) -> ok;
+ true -> error
+ end,
+ error = if
+ is_integer(Config), is_bitstring(Config) -> ok;
+ true -> error
+ end,
+
+ ok = case Config of
+ <<_>> when is_binary(Config) ->
+ impossible;
+ [_|_] ->
+ ok
+ end,
+
+ %% Cover beam_type:verified_type(none).
+ {'EXIT',{badarith,_}} = (catch (id(2) / id(1)) band 16#ff),
+
ok.
booleans(_Config) ->
- {'EXIT',{{case_clause,_},_}} = (catch do_booleans(42)),
+ {'EXIT',{{case_clause,_},_}} = (catch do_booleans_1(42)),
+
+ ok = do_booleans_2(42, 41),
+ error = do_booleans_2(42, 42),
+
+ AnyAtom = id(atom),
+ true = is_atom(AnyAtom),
+ false = is_boolean(AnyAtom),
+
+ MaybeBool = id(maybe),
+ case MaybeBool of
+ true -> ok;
+ maybe -> ok;
+ false -> ok
+ end,
+ false = is_boolean(MaybeBool),
+
+ NotBool = id(a),
+ case NotBool of
+ a -> ok;
+ b -> ok;
+ c -> ok
+ end,
+ false = is_boolean(NotBool),
+
ok.
-do_booleans(B) ->
+do_booleans_1(B) ->
case is_integer(B) of
yes -> yes;
no -> no
end.
+do_booleans_2(A, B) ->
+ Not = not do_booleans_cmp(A, B),
+ case Not of
+ true ->
+ case Not of
+ true -> error;
+ false -> ok
+ end;
+ false -> ok
+ end.
+
+do_booleans_cmp(A, B) -> A > B.
+
setelement(_Config) ->
T0 = id({a,42}),
{a,_} = T0,
@@ -152,13 +275,59 @@ setelement(_Config) ->
cons(_Config) ->
[did] = cons(assigned, did),
+
+ true = cons_is_empty_list([]),
+ false = cons_is_empty_list([a]),
+
+ false = cons_not(true),
+ true = cons_not(false),
+
+ {$a,"bc"} = cons_hdtl(true),
+ {$d,"ef"} = cons_hdtl(false),
ok.
cons(assigned, Instrument) ->
[Instrument] = [did].
+cons_is_empty_list(L) ->
+ Cons = case L of
+ [] -> "true";
+ _ -> "false"
+ end,
+ id(1),
+ case Cons of
+ "true" -> true;
+ "false" -> false
+ end.
+
+cons_not(B) ->
+ Cons = case B of
+ true -> "true";
+ false -> "false"
+ end,
+ id(1),
+ case Cons of
+ "true" -> false;
+ "false" -> true
+ end.
+
+cons_hdtl(B) ->
+ Cons = case B of
+ true -> "abc";
+ false -> "def"
+ end,
+ id(1),
+ {id(hd(Cons)),id(tl(Cons))}.
+
+-record(bird, {a=a,b=id(42)}).
+
tuple(_Config) ->
{'EXIT',{{badmatch,{necessary}},_}} = (catch do_tuple()),
+
+ [] = [X || X <- [], #bird{a = a} == {r,X,foo}],
+ [] = [X || X <- [], #bird{b = b} == {bird,X}],
+ [] = [X || X <- [], 3 == X#bird.a],
+
ok.
do_tuple() ->
@@ -232,5 +401,91 @@ do_tuple_arity_check(RGB) when is_tuple(RGB),
_ -> ok
end.
+elixir_binaries(_Config) ->
+ <<"foo blitzky baz">> = elixir_binary_1(<<"blitzky">>),
+ <<"foo * baz">> = elixir_binary_2($*),
+ <<7:4,755:10>> = elixir_bitstring_3(<<755:10>>),
+ ok.
+
+elixir_binary_1(Bar) when is_binary(Bar) ->
+ <<"foo ",
+ case Bar of
+ Rewrite when is_binary(Rewrite) ->
+ Rewrite;
+ Rewrite ->
+ list_to_binary(Rewrite)
+ end/binary,
+ " baz">>.
+
+elixir_binary_2(Arg) ->
+ Bin = <<Arg>>,
+ <<"foo ",
+ case Bin of
+ Rewrite when is_binary(Rewrite) ->
+ Rewrite;
+ Rewrite ->
+ list_to_binary:to_string(Rewrite)
+ end/binary,
+ " baz">>.
+
+elixir_bitstring_3(Bar) when is_bitstring(Bar) ->
+ <<7:4,
+ case Bar of
+ Rewrite when is_bitstring(Rewrite) ->
+ Rewrite;
+ Rewrite ->
+ list_to_bitstring(Rewrite)
+ end/bitstring>>.
+
+find_best(_Config) ->
+ ok = find_best([a], nil),
+ ok = find_best([<<"a">>], nil),
+ {error,_} = find_best([], nil),
+ ok.
+
+%% Failed because beam_type assumed that the operand
+%% for bs_context_binary must be a binary. Not true!
+find_best([a|Tail], Best) ->
+ find_best(Tail,
+ case Best of
+ X when X =:= nil orelse X =:= false -> a;
+ X -> X
+ end);
+find_best([<<"a">>|Tail], Best) ->
+ find_best(Tail,
+ case Best of
+ X when X =:= nil orelse X =:= false -> <<"a">>;
+ X -> X
+ end);
+find_best([], a) ->
+ ok;
+find_best([], <<"a">>) ->
+ ok;
+find_best([], nil) ->
+ {error,<<"should not get here">>}.
+
+test_size(_Config) ->
+ 2 = do_test_size({a,b}),
+ 4 = do_test_size(<<42:32>>),
+ ok.
+
+do_test_size(Term) when is_tuple(Term) ->
+ size(Term);
+do_test_size(Term) when is_binary(Term) ->
+ size(Term).
+
+cover_lists_functions(Config) ->
+ case lists:suffix([no|Config], Config) of
+ true ->
+ ct:fail(should_be_false);
+ false ->
+ ok
+ end,
+ Zipped = lists:zipwith(fun(A, B) -> {A,B} end,
+ lists:duplicate(length(Config), zip),
+ Config),
+ true = is_list(Zipped),
+ ok.
+
id(I) ->
I.
diff --git a/lib/compiler/test/beam_utils_SUITE.erl b/lib/compiler/test/beam_utils_SUITE.erl
index 710cb050d4..eb0af59f9d 100644
--- a/lib/compiler/test/beam_utils_SUITE.erl
+++ b/lib/compiler/test/beam_utils_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,13 +24,14 @@
apply_fun/1,apply_mf/1,bs_init/1,bs_save/1,
is_not_killed/1,is_not_used_at/1,
select/1,y_catch/1,otp_8949_b/1,liveopt/1,coverage/1,
- y_registers/1]).
+ y_registers/1,user_predef/1,scan_f/1,cafu/1,
+ receive_label/1,read_size_file_version/1,not_used/1,
+ is_used_fr/1,unsafe_is_function/1]).
-export([id/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -46,10 +47,18 @@ groups() ->
otp_8949_b,
liveopt,
coverage,
- y_registers
+ y_registers,
+ user_predef,
+ scan_f,
+ cafu,
+ read_size_file_version,
+ not_used,
+ is_used_fr,
+ unsafe_is_function
]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -117,6 +126,24 @@ bs_init(_Config) ->
{'EXIT',{badarg,_}} = (catch do_bs_init_2([0.5])),
{'EXIT',{badarg,_}} = (catch do_bs_init_2([-1])),
{'EXIT',{badarg,_}} = (catch do_bs_init_2([1 bsl 32])),
+
+ <<>> = do_bs_init_3({tag,0}, 0, 0),
+ <<0>> = do_bs_init_3({tag,0}, 2, 1),
+
+ <<"_build/shared">> = do_bs_init_4([], false),
+ <<"abc/shared">> = do_bs_init_4(<<"abc">>, false),
+ <<"foo/foo">> = do_bs_init_4(<<"foo">>, true),
+ error = do_bs_init_4([], not_boolean),
+
+ Id = 17575,
+ Domain = -8798798,
+ [<<10,1:16,Id:16/signed>>,<<8,2:16,Domain:32/signed>>] =
+ do_bs_init_5(#{tag=>value,id=>Id,domain=>Domain}),
+ {'EXIT',{{required,id},[_|_]}} =
+ (catch do_bs_init_5(#{tag=>value,id=>nil,domain=>Domain})),
+ {'EXIT',{{required,domain},[_|_]}} =
+ (catch do_bs_init_5(#{tag=>value,id=>Id,domain=>nil})),
+
ok.
do_bs_init_1([?MODULE], Sz) ->
@@ -134,6 +161,59 @@ do_bs_init_2(SigNos) ->
erlang:error(badarg)
>>.
+do_bs_init_3({tag,Pos}, Offset, Len) ->
+ N0 = Offset - Pos,
+ N = if N0 > Len -> Len;
+ true -> N0
+ end,
+ <<0:N/unit:8>>.
+
+do_bs_init_4(Arg1, Arg2) ->
+ Build =
+ case id(Arg1) of
+ X when X =:= [] orelse X =:= false -> <<"_build">>;
+ X -> X
+ end,
+ case id(Arg2) of
+ true ->
+ id(<<case Build of
+ Rewrite when is_binary(Rewrite) ->
+ Rewrite;
+ Rewrite ->
+ id(Rewrite)
+ end/binary,
+ "/",
+ case id(<<"foo">>) of
+ Rewrite when is_binary(Rewrite) ->
+ Rewrite;
+ Rewrite ->
+ id(Rewrite)
+ end/binary>>);
+ false ->
+ id(<<case Build of
+ Rewrite when is_binary(Rewrite) ->
+ Rewrite;
+ Rewrite ->
+ id(Rewrite)
+ end/binary,
+ "/shared">>);
+ _Other ->
+ error
+ end.
+
+do_bs_init_5(#{tag := value, id := Id, domain := Domain}) ->
+ [case Id of
+ nil ->
+ error(id({required, id}));
+ _ ->
+ <<10, 1:16/signed, Id:16/signed>>
+ end,
+ case Domain of
+ nil ->
+ error(id({required, domain}));
+ _ ->
+ <<8, 2:16/signed, Domain:32/signed>>
+ end].
bs_save(_Config) ->
{a,30,<<>>} = do_bs_save(<<1:1,30:5>>),
@@ -376,5 +456,139 @@ do(A, B) -> {A,B}.
appointment(#{"resolution" := Url}) ->
do(receive _ -> Url end, #{true => Url}).
+%% From epp.erl.
+user_predef(_Config) ->
+ #{key:="value"} = user_predef({key,"value"}, #{}),
+ #{key:="value"} = user_predef({key,"value"}, #{key=>defined}),
+ error = user_predef({key,"value"}, #{key=>[defined]}),
+ ok.
+
+user_predef({M,Val}, Ms) ->
+ case Ms of
+ #{M:=Defs} when is_list(Defs) ->
+ error;
+ _ ->
+ Ms#{M=>Val}
+ end.
+
+%% From disk_log_1.erl.
+scan_f(_Config) ->
+ {1,<<>>,[]} = scan_f(<<1:32>>, 1, []),
+ {1,<<>>,[<<156>>]} = scan_f(<<1:32,156,1:32>>, 1, []),
+ ok.
+
+scan_f(<<Size:32,Tail/binary>>, FSz, Acc) when Size =< FSz ->
+ case Tail of
+ <<BinTerm:Size/binary,Tail2/binary>> ->
+ scan_f(Tail2, FSz, [BinTerm | Acc]);
+ _ ->
+ {Size,Tail,Acc}
+ end.
+
+%% From file_io_server.erl.
+cafu(_Config) ->
+ error = cafu(<<42:32>>, -1, 0, {utf32,big}),
+ error = cafu(<<42:32>>, 10, 0, {utf32,big}),
+ error = cafu(<<42:32>>, -1, 0, {utf32,little}),
+ ok.
+
+cafu(<<_/big-utf32,Rest/binary>>, N, Count, {utf32,big}) when N < 0 ->
+ cafu(Rest, -1, Count+1, {utf32,big});
+cafu(<<_/big-utf32,Rest/binary>>, N, Count, {utf32,big}) ->
+ cafu(Rest, N-1, Count+1, {utf32,big});
+cafu(<<_/little-utf32,Rest/binary>>, N, Count, {utf32,little}) when N < 0 ->
+ cafu(Rest, -1, Count+1, {utf32,little});
+cafu(_, _, _, _) ->
+ error.
+
+-record(rec_label, {bool}).
+
+receive_label(_Config) ->
+ Pid = spawn_link(fun() -> do_receive_label(#rec_label{bool=true}) end),
+ Msg = {a,b,c},
+ Pid ! {self(),Msg},
+ receive
+ {ok,Msg} ->
+ unlink(Pid),
+ exit(Pid, die),
+ ok
+ end.
+
+do_receive_label(Rec) ->
+ receive
+ {From,Message} when Rec#rec_label.bool ->
+ From ! {ok,Message},
+ do_receive_label(Rec)
+ end.
+
+read_size_file_version(_Config) ->
+ ok = do_read_size_file_version({ok,<<42>>}),
+ {ok,7777} = do_read_size_file_version({ok,<<7777:32>>}),
+ ok.
+
+do_read_size_file_version(E) ->
+ case E of
+ {ok,<<Version>>} when Version =:= 42 ->
+ ok;
+ {ok,<<MaxFiles:32>>} ->
+ {ok,MaxFiles}
+ end.
+
+-record(s, { a, b }).
+-record(k, { v }).
+
+not_used(_Config) ->
+ [] = not_used_p(any, #s{b=true}, #k{}, ignored),
+ #k{v=42} = not_used_p(any, #s{b=false}, #k{v=42}, ignored),
+ #k{v=42} = not_used_p(any, #s{b=bad}, #k{v=42}, ignored),
+ ok.
+
+not_used_p(_C, S, K, L) when is_record(K, k) ->
+ if ((S#s.b) and
+ (S#s.b)) ->
+ [];
+ true ->
+ id(L),
+ id(K#k.v),
+ id(K)
+ end.
+
+is_used_fr(_Config) ->
+ 1 = is_used_fr(self(), self()),
+ 1 = is_used_fr(self(), other),
+ receive 1 -> ok end,
+ receive 1 -> ok end,
+ receive 1 -> ok end,
+ receive 1 -> ok end,
+ ok.
+
+is_used_fr(X, Y) ->
+ %% beam_utils:is_used({fr,R}, Code) would crash.
+ _ = 0 / (X ! 1),
+ _ = case Y of
+ X -> ok;
+ _ -> error
+ end,
+ X ! 1.
+
+%% ERL-778.
+unsafe_is_function(_Config) ->
+ {undefined,any} = unsafe_is_function(undefined, any),
+ {ok,any} = unsafe_is_function(fun() -> ok end, any),
+ {'EXIT',{{case_clause,_},_}} = (catch unsafe_is_function(fun(_) -> ok end, any)),
+ ok.
+
+unsafe_is_function(F, M) ->
+ %% There would be an internal consistency failure:
+ %% Instruction: {bif,is_function,{f,0},[{x,0},{integer,0}],{x,2}}
+ %% Error: {uninitialized_reg,{y,0}}:
+
+ NewValue = case is_function(F, 0) of
+ true -> F();
+ false when F =:= undefined -> undefined
+ end,
+ {NewValue,M}.
+
+
%% The identity function.
id(I) -> I.
diff --git a/lib/compiler/test/beam_validator_SUITE.erl b/lib/compiler/test/beam_validator_SUITE.erl
index c23514b36b..6b1438abdd 100644
--- a/lib/compiler/test/beam_validator_SUITE.erl
+++ b/lib/compiler/test/beam_validator_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -33,8 +33,10 @@
state_after_fault_in_catch/1,no_exception_in_catch/1,
undef_label/1,illegal_instruction/1,failing_gc_guard_bif/1,
map_field_lists/1,cover_bin_opt/1,
- val_dsetel/1]).
-
+ val_dsetel/1,bad_tuples/1,bad_try_catch_nesting/1,
+ receive_stacked/1,aliased_types/1,type_conflict/1,
+ infer_on_eq/1,infer_dead_value/1]).
+
-include_lib("common_test/include/ct.hrl").
init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
@@ -48,7 +50,6 @@ suite() ->
{timetrap,{minutes,10}}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -61,9 +62,13 @@ groups() ->
freg_state,bad_bin_match,bad_dsetel,
state_after_fault_in_catch,no_exception_in_catch,
undef_label,illegal_instruction,failing_gc_guard_bif,
- map_field_lists,cover_bin_opt,val_dsetel]}].
+ map_field_lists,cover_bin_opt,val_dsetel,
+ bad_tuples,bad_try_catch_nesting,
+ receive_stacked,aliased_types,type_conflict,
+ infer_on_eq,infer_dead_value]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -104,13 +109,12 @@ xrange(Config) when is_list(Config) ->
Errors = do_val(xrange, Config),
[{{t,sum_1,2},
{{bif,'+',{f,0},[{x,-1},{x,1}],{x,0}},4,
- {uninitialized_reg,{x,-1}}}},
+ {bad_register,{x,-1}}}},
{{t,sum_2,2},
- {{bif,'+',{f,0},[{x,0},{x,1023}],{x,0}},4,
- {uninitialized_reg,{x,1023}}}},
+ {{bif,'+',{f,0},[{x,0},{x,1023}],{x,0}},4,limit}},
{{t,sum_3,2},
{{bif,'+',{f,0},[{x,0},{x,1}],{x,-1}},4,
- {invalid_store,{x,-1},number}}},
+ {bad_register,{x,-1}}}},
{{t,sum_4,2},
{{bif,'+',{f,0},[{x,0},{x,1}],{x,1023}},4,limit}}] = Errors,
ok.
@@ -119,15 +123,15 @@ yrange(Config) when is_list(Config) ->
Errors = do_val(yrange, Config),
[{{t,sum_1,2},
{{move,{x,1},{y,-1}},5,
- {invalid_store,{y,-1},term}}},
+ {bad_register,{y,-1}}}},
{{t,sum_2,2},
{{bif,'+',{f,0},[{x,0},{y,1024}],{x,0}},7,
- {uninitialized_reg,{y,1024}}}},
+ limit}},
{{t,sum_3,2},
{{move,{x,1},{y,1024}},5,limit}},
{{t,sum_4,2},
{{move,{x,1},{y,-1}},5,
- {invalid_store,{y,-1},term}}}] = Errors,
+ {bad_register,{y,-1}}}}] = Errors,
ok.
stack(Config) when is_list(Config) ->
@@ -156,7 +160,7 @@ merge_undefined(Config) when is_list(Config) ->
[{{t,handle_call,2},
{{call_ext,2,{extfunc,debug,filter,2}},
22,
- {uninitialized_reg,{y,0}}}}] = Errors,
+ {uninitialized_reg,{y,_}}}}] = Errors,
ok.
uninit(Config) when is_list(Config) ->
@@ -175,7 +179,7 @@ unsafe_catch(Config) when is_list(Config) ->
Errors = do_val(unsafe_catch, Config),
[{{t,small,2},
{{bs_put_integer,{f,0},{integer,16},1,
- {field_flags,[unsigned,big]},{y,0}},
+ {field_flags,[unsigned,big]},{y,0}},
20,
{unassigned,{y,0}}}}] = Errors,
ok.
@@ -208,19 +212,19 @@ bad_catch_try(Config) when is_list(Config) ->
Errors = do_val(bad_catch_try, Config),
[{{bad_catch_try,bad_1,1},
{{'catch',{x,0},{f,3}},
- 5,{invalid_store,{x,0},{catchtag,[3]}}}},
+ 5,{invalid_tag_register,{x,0}}}},
{{bad_catch_try,bad_2,1},
{{catch_end,{x,9}},
- 8,{source_not_y_reg,{x,9}}}},
+ 8,{invalid_tag_register,{x,9}}}},
{{bad_catch_try,bad_3,1},
- {{catch_end,{y,1}},9,{bad_type,{atom,kalle}}}},
+ {{catch_end,{y,1}},9,{invalid_tag,{y,1},{atom,kalle}}}},
{{bad_catch_try,bad_4,1},
- {{'try',{x,0},{f,15}},5,{invalid_store,{x,0},{trytag,[15]}}}},
+ {{'try',{x,0},{f,15}},5,{invalid_tag_register,{x,0}}}},
{{bad_catch_try,bad_5,1},
- {{try_case,{y,1}},12,{bad_type,term}}},
+ {{try_case,{y,1}},12,{invalid_tag,{y,1},term}}},
{{bad_catch_try,bad_6,1},
{{move,{integer,1},{y,1}},7,
- {invalid_store,{y,1},{integer,1}}}}] = Errors,
+ {invalid_store,{y,1}}}}] = Errors,
ok.
cons_guard(Config) when is_list(Config) ->
@@ -244,7 +248,7 @@ freg_range(Config) when is_list(Config) ->
{{t,sum_3,2},
{{bif,fadd,{f,0},[{fr,0},{fr,1}],{fr,-1}},
7,
- {bad_target,{fr,-1}}}},
+ {bad_register,{fr,-1}}}},
{{t,sum_4,2},
{{bif,fadd,{f,0},[{fr,0},{fr,1}],{fr,1024}},
7,
@@ -421,9 +425,9 @@ try_bin_opt(Mod) ->
try
do_bin_opt(Mod)
catch
- Class:Error ->
+ Class:Error:Stk ->
io:format("~p: ~p ~p\n~p\n",
- [Mod,Class,Error,erlang:get_stacktrace()]),
+ [Mod,Class,Error,Stk]),
error
end.
@@ -509,6 +513,193 @@ destroy_reg({Tag,N}) ->
{y,N+1}
end.
+bad_tuples(Config) ->
+ Errors = do_val(bad_tuples, Config),
+ [{{bad_tuples,heap_overflow,1},
+ {{put,{x,0}},8,{heap_overflow,{left,0},{wanted,1}}}},
+ {{bad_tuples,long,2},
+ {{put,{atom,too_long}},8,not_building_a_tuple}},
+ {{bad_tuples,self_referential,1},
+ {{put,{x,1}},7,{tuple_in_progress,{x,1}}}},
+ {{bad_tuples,short,1},
+ {{move,{x,1},{x,0}},7,{tuple_in_progress,{x,1}}}}] = Errors,
+
+ ok.
+
+bad_try_catch_nesting(Config) ->
+ Errors = do_val(bad_try_catch_nesting, Config),
+ [{{bad_try_catch_nesting,main,2},
+ {{'try',{y,2},{f,3}},
+ 7,
+ {bad_try_catch_nesting,{y,2},[{{y,1},{trytag,[5]}}]}}}] = Errors,
+ ok.
+
+receive_stacked(Config) ->
+ Mod = ?FUNCTION_NAME,
+ Errors = do_val(Mod, Config),
+ [{{receive_stacked,f1,0},
+ {{loop_rec_end,{f,3}},
+ 17,
+ {fragile_message_reference,{y,_}}}},
+ {{receive_stacked,f2,0},
+ {{test_heap,3,0},10,{fragile_message_reference,{y,_}}}},
+ {{receive_stacked,f3,0},
+ {{test_heap,3,0},10,{fragile_message_reference,{y,_}}}},
+ {{receive_stacked,f4,0},
+ {{test_heap,3,0},10,{fragile_message_reference,{y,_}}}},
+ {{receive_stacked,f5,0},
+ {{loop_rec_end,{f,23}},
+ 23,
+ {fragile_message_reference,{y,_}}}},
+ {{receive_stacked,f6,0},
+ {{gc_bif,byte_size,{f,29},0,[{y,_}],{x,0}},
+ 12,
+ {fragile_message_reference,{y,_}}}},
+ {{receive_stacked,f7,0},
+ {{loop_rec_end,{f,33}},
+ 20,
+ {fragile_message_reference,{y,_}}}},
+ {{receive_stacked,f8,0},
+ {{loop_rec_end,{f,38}},
+ 20,
+ {fragile_message_reference,{y,_}}}},
+ {{receive_stacked,m1,0},
+ {{loop_rec_end,{f,43}},
+ 19,
+ {fragile_message_reference,{y,_}}}},
+ {{receive_stacked,m2,0},
+ {{loop_rec_end,{f,48}},
+ 33,
+ {fragile_message_reference,{y,_}}}}] = Errors,
+
+ %% Compile the original source code as a smoke test.
+ Data = proplists:get_value(data_dir, Config),
+ Base = atom_to_list(Mod),
+ File = filename:join(Data, Base),
+ {ok,Mod,_} = compile:file(File, [binary]),
+
+ ok.
+
+aliased_types(Config) ->
+ Seq = lists:seq(1, 5),
+ 1 = aliased_types_1(Seq, Config),
+
+ {1,1} = aliased_types_2(Seq),
+ {42,none} = aliased_types_2([]),
+
+ gurka = aliased_types_3([gurka]),
+ gaffel = aliased_types_3([gaffel]),
+
+ ok.
+
+%% ERL-735: validator failed to track types on aliased registers, rejecting
+%% legitimate optimizations.
+%%
+%% move x0 y0
+%% bif hd L1 x0
+%% get_hd y0 %% The validator failed to see that y0 was a list
+%%
+aliased_types_1(Bug, Config) ->
+ if
+ Config =/= [gurka, gaffel] -> %% Pointless branch.
+ _ = hd(Bug),
+ lists:seq(1, 5),
+ hd(Bug)
+ end.
+
+%% ERL-832: validator failed to realize that a Y register was a cons.
+aliased_types_2(Bug) ->
+ Res = case Bug of
+ [] -> id(42);
+ _ -> hd(Bug)
+ end,
+ {Res,case Bug of
+ [] -> none;
+ _ -> hd(Bug)
+ end}.
+
+%% ERL-832 part deux; validator failed to realize that an aliased register was
+%% a cons.
+aliased_types_3(Bug) ->
+ List = [Y || Y <- Bug],
+ case List of
+ [] -> Bug;
+ _ ->
+ if
+ hd(List) -> a:a();
+ true -> ok
+ end,
+ hd(List)
+ end.
+
+
+%% ERL-867; validation proceeded after a type conflict, causing incorrect types
+%% to be joined.
+
+-record(r, { e1 = e1, e2 = e2 }).
+
+type_conflict(Config) when is_list(Config) ->
+ {e1, e2} = type_conflict_1(#r{}),
+ ok.
+
+type_conflict_1(C) ->
+ Src = id(C#r.e2),
+ TRes = try id(Src) of
+ R -> R
+ catch
+ %% C:R can never match, yet it assumed that the type of 'C' was
+ %% an atom from here on.
+ C:R -> R
+ end,
+ {C#r.e1, TRes}.
+
+%% ERL-886; validation failed to infer types on both sides of '=:='
+
+infer_on_eq(Config) when is_list(Config) ->
+ {ok, gurka} = infer_on_eq_1(id({gurka})),
+ {ok, gaffel} = infer_on_eq_2(id({gaffel})),
+ {ok, elefant} = infer_on_eq_3(id({elefant})),
+ {ok, myra} = infer_on_eq_4(id({myra})),
+ ok.
+
+infer_on_eq_1(T) ->
+ 1 = erlang:tuple_size(T),
+ {ok, erlang:element(1, T)}.
+
+infer_on_eq_2(T) ->
+ Size = erlang:tuple_size(T),
+ Size = 1,
+ {ok, erlang:element(1, T)}.
+
+infer_on_eq_3(T) ->
+ true = 1 =:= erlang:tuple_size(T),
+ {ok, erlang:element(1, T)}.
+
+infer_on_eq_4(T) ->
+ true = erlang:tuple_size(T) =:= 1,
+ {ok, erlang:element(1, T)}.
+
+%% ERIERL-348; types were inferred for dead values, causing validation to fail.
+
+infer_dead_value(Config) when is_list(Config) ->
+ a = idv_1({a, b, c, d, e, f, g}, {0, 0, 0, 0, 0, 0, 0}),
+ b = idv_1({a, b, c, d, 0, 0, 0}, {a, b, c, d, 0, 0, 0}),
+ c = idv_1({0, 0, 0, 0, 0, f, g}, {0, 0, 0, 0, 0, f, g}),
+ error = idv_1(gurka, gaffel),
+ ok.
+
+idv_1({_A, _B, _C, _D, _E, _F, _G},
+ {0, 0, 0, 0, 0, 0, 0}) ->
+ a;
+idv_1({A, B, C, D,_E, _F, _G}=_Tuple1,
+ {A, B, C, D, 0, 0, 0}=_Tuple2) ->
+ b;
+idv_1({_A, _B, _C, _D, _E, F, G},
+ {0, 0, 0, 0, 0, F, G}) ->
+ c;
+idv_1(_A, _B) ->
+ error.
+
%%%-------------------------------------------------------------------------
transform_remove(Remove, Module) ->
@@ -567,3 +758,6 @@ night(Turned) ->
ok.
participating(_, _, _, _) -> ok.
+
+id(I) ->
+ I.
diff --git a/lib/compiler/test/beam_validator_SUITE_data/bad_bin_match.S b/lib/compiler/test/beam_validator_SUITE_data/bad_bin_match.S
index a60ca1e89a..c7610971f1 100644
--- a/lib/compiler/test/beam_validator_SUITE_data/bad_bin_match.S
+++ b/lib/compiler/test/beam_validator_SUITE_data/bad_bin_match.S
@@ -11,5 +11,5 @@
{label,1}.
{func_info,{atom,t},{atom,t},1}.
{label,2}.
- {test,bs_start_match2,{f,1},1,[{x,0},0],{x,0}}.
+ {test,bs_start_match3,{f,1},1,[{x,0}],{x,0}}.
return.
diff --git a/lib/compiler/test/beam_validator_SUITE_data/bad_try_catch_nesting.S b/lib/compiler/test/beam_validator_SUITE_data/bad_try_catch_nesting.S
new file mode 100644
index 0000000000..9f1b21a17b
--- /dev/null
+++ b/lib/compiler/test/beam_validator_SUITE_data/bad_try_catch_nesting.S
@@ -0,0 +1,64 @@
+{module, bad_try_catch_nesting}. %% version = 0
+
+{exports, [{main,2},{module_info,0},{module_info,1}]}.
+
+{attributes, []}.
+
+{labels, 11}.
+
+
+{function, main, 2, 2}.
+ {label,1}.
+ {line,[{location,"bad_try_catch_nesting.erl",4}]}.
+ {func_info,{atom,bad_try_catch_nesting},{atom,main},2}.
+ {label,2}.
+ {allocate_zero,3,2}.
+ {'try',{y,1},{f,5}}.
+ {move,{x,1},{y,0}}.
+ {'try',{y,2},{f,3}}.
+ {line,[{location,"bad_try_catch_nesting.erl",7}]}.
+ {call_fun,0}.
+ {try_end,{y,2}}.
+ {jump,{f,4}}.
+ {label,3}.
+ {try_case,{y,2}}.
+ {test,is_ne_exact,{f,4},[{x,0},{atom,error}]}.
+ {line,[]}.
+ {bif,raise,{f,0},[{x,2},{x,1}],{x,0}}.
+ {label,4}.
+ {move,{y,0},{x,0}}.
+ {kill,{y,0}}.
+ {line,[{location,"bad_try_catch_nesting.erl",12}]}.
+ {call_fun,0}.
+ {try_end,{y,1}}.
+ {deallocate,3}.
+ return.
+ {label,5}.
+ {try_case,{y,1}}.
+ {test,is_eq_exact,{f,6},[{x,0},{atom,throw}]}.
+ {deallocate,3}.
+ return.
+ {label,6}.
+ {line,[]}.
+ {bif,raise,{f,0},[{x,2},{x,1}],{x,0}}.
+
+
+{function, module_info, 0, 8}.
+ {label,7}.
+ {line,[]}.
+ {func_info,{atom,bad_try_catch_nesting},{atom,module_info},0}.
+ {label,8}.
+ {move,{atom,bad_try_catch_nesting},{x,0}}.
+ {line,[]}.
+ {call_ext_only,1,{extfunc,erlang,get_module_info,1}}.
+
+
+{function, module_info, 1, 10}.
+ {label,9}.
+ {line,[]}.
+ {func_info,{atom,bad_try_catch_nesting},{atom,module_info},1}.
+ {label,10}.
+ {move,{x,0},{x,1}}.
+ {move,{atom,bad_try_catch_nesting},{x,0}}.
+ {line,[]}.
+ {call_ext_only,2,{extfunc,erlang,get_module_info,2}}.
diff --git a/lib/compiler/test/beam_validator_SUITE_data/bad_tuples.S b/lib/compiler/test/beam_validator_SUITE_data/bad_tuples.S
new file mode 100644
index 0000000000..7980241c37
--- /dev/null
+++ b/lib/compiler/test/beam_validator_SUITE_data/bad_tuples.S
@@ -0,0 +1,88 @@
+{module, bad_tuples}. %% version = 0
+
+{exports, [{heap_overflow,1},
+ {long,2},
+ {module_info,0},
+ {module_info,1},
+ {self_referential,1},
+ {short,1}]}.
+
+{attributes, []}.
+
+{labels, 13}.
+
+
+{function, short, 1, 2}.
+ {label,1}.
+ {line,[{location,"bad_tuples.erl",4}]}.
+ {func_info,{atom,bad_tuples},{atom,short},1}.
+ {label,2}.
+ {test_heap,3,1}.
+ {put_tuple,2,{x,1}}.
+ {put,{atom,ok}}.
+ {move,{x,1},{x,0}}.
+ return.
+
+
+{function, long, 2, 4}.
+ {label,3}.
+ {line,[{location,"bad_tuples.erl",7}]}.
+ {func_info,{atom,bad_tuples},{atom,long},2}.
+ {label,4}.
+ {test_heap,6,2}.
+ {put_tuple,2,{x,2}}.
+ {put,{x,0}}.
+ {put,{x,1}}.
+ {put,{atom,too_long}}.
+ {put_tuple,2,{x,0}}.
+ {put,{atom,ok}}.
+ {put,{x,2}}.
+ return.
+
+
+{function, heap_overflow, 1, 6}.
+ {label,5}.
+ {line,[{location,"bad_tuples.erl",10}]}.
+ {func_info,{atom,bad_tuples},{atom,heap_overflow},1}.
+ {label,6}.
+ {test_heap,3,1}.
+ {put_tuple,2,{x,1}}.
+ {put,{atom,ok}}.
+ {put,{x,0}}.
+ {put,{x,0}}.
+ {move,{x,1},{x,0}}.
+ return.
+
+
+{function, self_referential, 1, 8}.
+ {label,7}.
+ {line,[{location,"bad_tuples.erl",13}]}.
+ {func_info,{atom,bad_tuples},{atom,self_referential},1}.
+ {label,8}.
+ {test_heap,3,1}.
+ {put_tuple,2,{x,1}}.
+ {put,{atom,ok}}.
+ {put,{x,1}}.
+ {move,{x,1},{x,0}}.
+ return.
+
+
+{function, module_info, 0, 10}.
+ {label,9}.
+ {line,[]}.
+ {func_info,{atom,bad_tuples},{atom,module_info},0}.
+ {label,10}.
+ {move,{atom,bad_tuples},{x,0}}.
+ {line,[]}.
+ {call_ext_only,1,{extfunc,erlang,get_module_info,1}}.
+
+
+{function, module_info, 1, 12}.
+ {label,11}.
+ {line,[]}.
+ {func_info,{atom,bad_tuples},{atom,module_info},1}.
+ {label,12}.
+ {move,{x,0},{x,1}}.
+ {move,{atom,bad_tuples},{x,0}}.
+ {line,[]}.
+ {call_ext_only,2,{extfunc,erlang,get_module_info,2}}.
diff --git a/lib/compiler/test/beam_validator_SUITE_data/merge_undefined.S b/lib/compiler/test/beam_validator_SUITE_data/merge_undefined.S
index 481d55045d..aa344807e4 100644
--- a/lib/compiler/test/beam_validator_SUITE_data/merge_undefined.S
+++ b/lib/compiler/test/beam_validator_SUITE_data/merge_undefined.S
@@ -15,8 +15,9 @@
{select_val,{x,0},{f,1},{list,[{atom,gurka},{f,3},{atom,delete},{f,4}]}}.
{label,3}.
{allocate_heap,2,6,2}.
- %% The Y registers are not initialized here.
{test,is_eq_exact,{f,5},[{x,0},{atom,ok}]}.
+ %% This is unreachable since {x,0} is known not to be 'ok'. We should not
+ %% fail with "uninitialized y registers" on erlang:exit/1
{move,{atom,nisse},{x,0}}.
{call_ext,1,{extfunc,erlang,exit,1}}.
{label,4}.
@@ -29,6 +30,7 @@
{call_ext,2,{extfunc,io,format,2}}.
{test,is_ne_exact,{f,6},[{x,0},{atom,ok}]}.
{label,5}.
+ %% The Y registers are not initialized here.
{move,{atom,logReader},{x,1}}.
{move,{atom,console},{x,0}}.
{call_ext,2,{extfunc,debug,filter,2}}.
diff --git a/lib/compiler/test/beam_validator_SUITE_data/receive_stacked.S b/lib/compiler/test/beam_validator_SUITE_data/receive_stacked.S
new file mode 100644
index 0000000000..a878204d16
--- /dev/null
+++ b/lib/compiler/test/beam_validator_SUITE_data/receive_stacked.S
@@ -0,0 +1,390 @@
+{module, receive_stacked}. %% version = 0
+
+{exports, [{f1,0},
+ {f2,0},
+ {f3,0},
+ {f4,0},
+ {f5,0},
+ {f6,0},
+ {f7,0},
+ {f8,0},
+ {id,1},
+ {m1,0},
+ {m2,0},
+ {module_info,0},
+ {module_info,1}]}.
+
+{attributes, []}.
+
+{labels, 57}.
+
+
+{function, f1, 0, 2}.
+ {label,1}.
+ {line,[{location,"receive_stacked.erl",15}]}.
+ {func_info,{atom,receive_stacked},{atom,f1},0}.
+ {label,2}.
+ {allocate_zero,1,0}.
+ {label,3}.
+ {loop_rec,{f,5},{x,0}}.
+ {move,{x,0},{y,0}}.
+ {test,is_integer,{f,4},[{y,0}]}.
+ remove_message.
+ {move,{integer,42},{x,0}}.
+ {line,[{location,"receive_stacked.erl",18}]}.
+ {call,1,{f,52}}.
+ {move,{y,0},{x,0}}.
+ {deallocate,1}.
+ return.
+ {label,4}.
+ {loop_rec_end,{f,3}}.
+ {label,5}.
+ {wait,{f,3}}.
+
+
+{function, f2, 0, 7}.
+ {label,6}.
+ {line,[{location,"receive_stacked.erl",22}]}.
+ {func_info,{atom,receive_stacked},{atom,f2},0}.
+ {label,7}.
+ {allocate_zero,2,0}.
+ {label,8}.
+ {loop_rec,{f,10},{x,0}}.
+ {test,is_nonempty_list,{f,9},[{x,0}]}.
+ {get_list,{x,0},{y,1},{x,0}}.
+ {test,is_nil,{f,9},[{x,0}]}.
+ {test_heap,3,0}.
+ remove_message.
+ {put_tuple,2,{y,0}}.
+ {put,{atom,ok}}.
+ {put,{y,1}}.
+ {move,{integer,42},{x,0}}.
+ {line,[{location,"receive_stacked.erl",26}]}.
+ {call,1,{f,52}}.
+ {test_heap,3,0}.
+ {put_tuple,2,{x,0}}.
+ {put,{y,0}}.
+ {put,{y,1}}.
+ {deallocate,2}.
+ return.
+ {label,9}.
+ {loop_rec_end,{f,8}}.
+ {label,10}.
+ {wait,{f,8}}.
+
+
+{function, f3, 0, 12}.
+ {label,11}.
+ {line,[{location,"receive_stacked.erl",30}]}.
+ {func_info,{atom,receive_stacked},{atom,f3},0}.
+ {label,12}.
+ {allocate_zero,2,0}.
+ {label,13}.
+ {loop_rec,{f,15},{x,0}}.
+ {test,is_nonempty_list,{f,14},[{x,0}]}.
+ {get_hd,{x,0},{y,1}}.
+ {test,is_integer,{f,14},[{y,1}]}.
+ {test_heap,3,0}.
+ remove_message.
+ {put_tuple,2,{y,0}}.
+ {put,{atom,ok}}.
+ {put,{y,1}}.
+ {move,{integer,42},{x,0}}.
+ {line,[{location,"receive_stacked.erl",34}]}.
+ {call,1,{f,52}}.
+ {test_heap,3,0}.
+ {put_tuple,2,{x,0}}.
+ {put,{y,0}}.
+ {put,{y,1}}.
+ {deallocate,2}.
+ return.
+ {label,14}.
+ {loop_rec_end,{f,13}}.
+ {label,15}.
+ {wait,{f,13}}.
+
+
+{function, f4, 0, 17}.
+ {label,16}.
+ {line,[{location,"receive_stacked.erl",38}]}.
+ {func_info,{atom,receive_stacked},{atom,f4},0}.
+ {label,17}.
+ {allocate_zero,2,0}.
+ {label,18}.
+ {loop_rec,{f,20},{x,0}}.
+ {test,is_nonempty_list,{f,19},[{x,0}]}.
+ {get_tl,{x,0},{y,1}}.
+ {test,is_list,{f,19},[{y,1}]}.
+ {test_heap,3,0}.
+ remove_message.
+ {put_tuple,2,{y,0}}.
+ {put,{atom,ok}}.
+ {put,{y,1}}.
+ {move,{integer,42},{x,0}}.
+ {line,[{location,"receive_stacked.erl",42}]}.
+ {call,1,{f,52}}.
+ {test_heap,3,0}.
+ {put_tuple,2,{x,0}}.
+ {put,{y,0}}.
+ {put,{y,1}}.
+ {deallocate,2}.
+ return.
+ {label,19}.
+ {loop_rec_end,{f,18}}.
+ {label,20}.
+ {wait,{f,18}}.
+
+
+{function, f5, 0, 22}.
+ {label,21}.
+ {line,[{location,"receive_stacked.erl",46}]}.
+ {func_info,{atom,receive_stacked},{atom,f5},0}.
+ {label,22}.
+ {allocate_zero,2,0}.
+ {label,23}.
+ {loop_rec,{f,25},{x,0}}.
+ {test,is_tuple,{f,24},[{x,0}]}.
+ {test,test_arity,{f,24},[{x,0},1]}.
+ {get_tuple_element,{x,0},0,{y,1}}.
+ {test,is_integer,{f,24},[{y,1}]}.
+ remove_message.
+ {put_map_assoc,{f,0},{literal,#{}},{y,0},0,{list,[{atom,key},{y,1}]}}.
+ {move,{integer,42},{x,0}}.
+ {line,[{location,"receive_stacked.erl",50}]}.
+ {call,1,{f,52}}.
+ {test_heap,3,0}.
+ {put_tuple,2,{x,0}}.
+ {put,{y,0}}.
+ {put,{y,1}}.
+ {deallocate,2}.
+ return.
+ {label,24}.
+ {loop_rec_end,{f,23}}.
+ {label,25}.
+ {wait,{f,23}}.
+
+
+{function, f6, 0, 27}.
+ {label,26}.
+ {line,[{location,"receive_stacked.erl",54}]}.
+ {func_info,{atom,receive_stacked},{atom,f6},0}.
+ {label,27}.
+ {allocate_zero,1,0}.
+ {label,28}.
+ {loop_rec,{f,30},{x,0}}.
+ {test,bs_start_match3,{f,29},1,[{x,0}],{x,0}}.
+ {test,bs_get_integer2,
+ {f,29},
+ 1,
+ [{x,0},
+ {integer,8},
+ 1,
+ {field_flags,[{anno,[56,{file,"receive_stacked.erl"}]},
+ unsigned,big]}],
+ {x,1}}.
+ {test,bs_get_binary2,
+ {f,29},
+ 1,
+ [{x,0},
+ {atom,all},
+ 8,
+ {field_flags,[{anno,[56,{file,"receive_stacked.erl"}]},
+ unsigned,big]}],
+ {y,0}}.
+ {'%',
+ {no_bin_opt,
+ {binary_used_in,{gc_bif,byte_size,{f,29},0,[{y,0}],{x,0}}},
+ [56,{file,"receive_stacked.erl"}]}}.
+ {line,[{location,"receive_stacked.erl",56}]}.
+ {gc_bif,byte_size,{f,29},0,[{y,0}],{x,0}}.
+ {test,is_lt,{f,29},[{integer,8},{x,0}]}.
+ remove_message.
+ {move,{integer,42},{x,0}}.
+ {line,[{location,"receive_stacked.erl",57}]}.
+ {call,1,{f,52}}.
+ {move,{y,0},{x,0}}.
+ {deallocate,1}.
+ return.
+ {label,29}.
+ {loop_rec_end,{f,28}}.
+ {label,30}.
+ {wait,{f,28}}.
+
+
+{function, f7, 0, 32}.
+ {label,31}.
+ {line,[{location,"receive_stacked.erl",61}]}.
+ {func_info,{atom,receive_stacked},{atom,f7},0}.
+ {label,32}.
+ {allocate_zero,1,0}.
+ {label,33}.
+ {loop_rec,{f,35},{x,0}}.
+ {test,bs_start_match3,{f,34},1,[{x,0}],{x,0}}.
+ {test,bs_get_integer2,
+ {f,34},
+ 1,
+ [{x,0},
+ {integer,8},
+ 1,
+ {field_flags,[{anno,[63,{file,"receive_stacked.erl"}]},
+ unsigned,big]}],
+ {x,1}}.
+ {test,bs_get_binary2,
+ {f,34},
+ 1,
+ [{x,0},
+ {atom,all},
+ 8,
+ {field_flags,[{anno,[63,{file,"receive_stacked.erl"}]},
+ unsigned,big]}],
+ {y,0}}.
+ {'%',{no_bin_opt,{binary_used_in,{test,is_binary,{f,34},[{y,0}]}},
+ [63,{file,"receive_stacked.erl"}]}}.
+ {test,is_eq_exact,{f,34},[{y,0},{literal,<<0,1,2,3>>}]}.
+ remove_message.
+ {move,{integer,42},{x,0}}.
+ {line,[{location,"receive_stacked.erl",64}]}.
+ {call,1,{f,52}}.
+ {move,{y,0},{x,0}}.
+ {deallocate,1}.
+ return.
+ {label,34}.
+ {loop_rec_end,{f,33}}.
+ {label,35}.
+ {wait,{f,33}}.
+
+
+{function, f8, 0, 37}.
+ {label,36}.
+ {line,[{location,"receive_stacked.erl",68}]}.
+ {func_info,{atom,receive_stacked},{atom,f8},0}.
+ {label,37}.
+ {allocate_zero,1,0}.
+ {label,38}.
+ {loop_rec,{f,40},{x,0}}.
+ {test,bs_start_match3,{f,39},1,[{x,0}],{x,1}}.
+ {test,bs_get_integer2,
+ {f,39},
+ 2,
+ [{x,1},
+ {integer,8},
+ 1,
+ {field_flags,[{anno,[70,{file,"receive_stacked.erl"}]},
+ unsigned,big]}],
+ {x,2}}.
+ {test,bs_get_binary2,
+ {f,39},
+ 2,
+ [{x,1},
+ {atom,all},
+ 8,
+ {field_flags,[{anno,[70,{file,"receive_stacked.erl"}]},
+ unsigned,big]}],
+ {y,0}}.
+ {'%',{no_bin_opt,{[{x,1},{y,0}],{loop_rec_end,{f,38}},not_handled},
+ [70,{file,"receive_stacked.erl"}]}}.
+ {test,is_eq_exact,{f,39},[{x,0},{literal,<<0,1,2,3>>}]}.
+ remove_message.
+ {move,{integer,42},{x,0}}.
+ {line,[{location,"receive_stacked.erl",71}]}.
+ {call,1,{f,52}}.
+ {move,{y,0},{x,0}}.
+ {deallocate,1}.
+ return.
+ {label,39}.
+ {loop_rec_end,{f,38}}.
+ {label,40}.
+ {wait,{f,38}}.
+
+
+{function, m1, 0, 42}.
+ {label,41}.
+ {line,[{location,"receive_stacked.erl",75}]}.
+ {func_info,{atom,receive_stacked},{atom,m1},0}.
+ {label,42}.
+ {allocate_zero,1,0}.
+ {label,43}.
+ {loop_rec,{f,45},{x,0}}.
+ {test,is_map,{f,44},[{x,0}]}.
+ {get_map_elements,{f,44},{x,0},{list,[{atom,key},{y,0}]}}.
+ {test,is_integer,{f,44},[{y,0}]}.
+ remove_message.
+ {move,{integer,42},{x,0}}.
+ {line,[{location,"receive_stacked.erl",78}]}.
+ {call,1,{f,52}}.
+ {test_heap,2,0}.
+ {put_list,{y,0},nil,{x,0}}.
+ {deallocate,1}.
+ return.
+ {label,44}.
+ {loop_rec_end,{f,43}}.
+ {label,45}.
+ {wait,{f,43}}.
+
+
+{function, m2, 0, 47}.
+ {label,46}.
+ {line,[{location,"receive_stacked.erl",82}]}.
+ {func_info,{atom,receive_stacked},{atom,m2},0}.
+ {label,47}.
+ {allocate_zero,4,0}.
+ {move,{atom,key1},{x,0}}.
+ {line,[{location,"receive_stacked.erl",83}]}.
+ {call,1,{f,52}}.
+ {move,{x,0},{y,3}}.
+ {move,{atom,key2},{x,0}}.
+ {line,[{location,"receive_stacked.erl",84}]}.
+ {call,1,{f,52}}.
+ {move,{x,0},{y,2}}.
+ {label,48}.
+ {loop_rec,{f,50},{x,0}}.
+ {test,is_map,{f,49},[{x,0}]}.
+ {get_map_elements,{f,49},{x,0},{list,[{y,3},{y,1}]}}.
+ {get_map_elements,{f,49},{x,0},{list,[{y,2},{y,0}]}}.
+ {test,is_integer,{f,49},[{y,1}]}.
+ {test,is_integer,{f,49},[{y,0}]}.
+ remove_message.
+ {kill,{y,2}}.
+ {kill,{y,3}}.
+ {move,{integer,42},{x,0}}.
+ {line,[{location,"receive_stacked.erl",87}]}.
+ {call,1,{f,52}}.
+ {test_heap,3,0}.
+ {put_tuple,2,{x,0}}.
+ {put,{y,1}}.
+ {put,{y,0}}.
+ {deallocate,4}.
+ return.
+ {label,49}.
+ {loop_rec_end,{f,48}}.
+ {label,50}.
+ {wait,{f,48}}.
+
+
+{function, id, 1, 52}.
+ {label,51}.
+ {line,[{location,"receive_stacked.erl",91}]}.
+ {func_info,{atom,receive_stacked},{atom,id},1}.
+ {label,52}.
+ return.
+
+
+{function, module_info, 0, 54}.
+ {label,53}.
+ {line,[]}.
+ {func_info,{atom,receive_stacked},{atom,module_info},0}.
+ {label,54}.
+ {move,{atom,receive_stacked},{x,0}}.
+ {line,[]}.
+ {call_ext_only,1,{extfunc,erlang,get_module_info,1}}.
+
+
+{function, module_info, 1, 56}.
+ {label,55}.
+ {line,[]}.
+ {func_info,{atom,receive_stacked},{atom,module_info},1}.
+ {label,56}.
+ {move,{x,0},{x,1}}.
+ {move,{atom,receive_stacked},{x,0}}.
+ {line,[]}.
+ {call_ext_only,2,{extfunc,erlang,get_module_info,2}}.
diff --git a/lib/compiler/test/beam_validator_SUITE_data/receive_stacked.erl b/lib/compiler/test/beam_validator_SUITE_data/receive_stacked.erl
new file mode 100644
index 0000000000..b95fa9ca62
--- /dev/null
+++ b/lib/compiler/test/beam_validator_SUITE_data/receive_stacked.erl
@@ -0,0 +1,92 @@
+-module(receive_stacked).
+-compile([export_all,nowarn_export_all]).
+
+%% Messages may be stored outside any process heap until they
+%% have been accepted by the 'remove_message' instruction.
+%% When matching of a message fails, it is not allowed to
+%% leave references to the message or any part of it in
+%% the Y registers. An experimental code generator could
+%% do that, causing an emulator crash if there happenened to
+%% be a garbage collection.
+%%
+%% The 'S' file corresponding to this file was compiled with
+%% that experimental code generator.
+
+f1() ->
+ receive
+ X when is_integer(X) ->
+ id(42),
+ X
+ end.
+
+f2() ->
+ receive
+ [X] ->
+ Res = {ok,X},
+ id(42),
+ {Res,X}
+ end.
+
+f3() ->
+ receive
+ [H|_] when is_integer(H) ->
+ Res = {ok,H},
+ id(42),
+ {Res,H}
+ end.
+
+f4() ->
+ receive
+ [_|T] when is_list(T) ->
+ Res = {ok,T},
+ id(42),
+ {Res,T}
+ end.
+
+f5() ->
+ receive
+ {X} when is_integer(X) ->
+ Res = #{key=>X},
+ id(42),
+ {Res,X}
+ end.
+
+f6() ->
+ receive
+ <<_:8,T/binary>> when byte_size(T) > 8 ->
+ id(42),
+ T
+ end.
+
+f7() ->
+ receive
+ <<_:8,T/binary>> when is_binary(T) ->
+ id(42),
+ T
+ end.
+
+f8() ->
+ receive
+ <<_:8,T/binary>> = Bin when is_binary(Bin) ->
+ id(42),
+ T
+ end.
+
+m1() ->
+ receive
+ #{key:=V} when is_integer(V) ->
+ id(42),
+ [V]
+ end.
+
+m2() ->
+ K1 = id(key1),
+ K2 = id(key2),
+ receive
+ #{K1:=V1,K2:=V2} when is_integer(V1), is_integer(V2) ->
+ id(42),
+ {V1,V2}
+ end.
+
+id(I) ->
+ I.
diff --git a/lib/compiler/test/bif_SUITE.erl b/lib/compiler/test/bif_SUITE.erl
index bba2058f2f..423a7666af 100644
--- a/lib/compiler/test/bif_SUITE.erl
+++ b/lib/compiler/test/bif_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2016. All Rights Reserved.
+%% Copyright Ericsson AB 2016-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,23 +23,23 @@
-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,
init_per_group/2,end_per_group/2,
- beam_validator/1,trunc_and_friends/1,cover_safe_bifs/1]).
+ beam_validator/1,trunc_and_friends/1,cover_safe_and_pure_bifs/1]).
suite() ->
[{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
[{p,[parallel],
[beam_validator,
trunc_and_friends,
- cover_safe_bifs
+ cover_safe_and_pure_bifs
]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -106,7 +106,7 @@ trunc_template(Func, Bif) ->
catch error:badarg -> ok end,
ok.").
-cover_safe_bifs(Config) ->
+cover_safe_and_pure_bifs(Config) ->
_ = get(),
_ = get_keys(a),
_ = group_leader(),
@@ -118,5 +118,6 @@ cover_safe_bifs(Config) ->
_ = processes(),
_ = registered(),
_ = term_to_binary(Config),
+ 42 = list_to_integer("2A", 16),
ok.
diff --git a/lib/compiler/test/bs_bincomp_SUITE.erl b/lib/compiler/test/bs_bincomp_SUITE.erl
index dd1d245f88..0419b16eea 100644
--- a/lib/compiler/test/bs_bincomp_SUITE.erl
+++ b/lib/compiler/test/bs_bincomp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,22 +26,22 @@
init_per_group/2,end_per_group/2,
byte_aligned/1,bit_aligned/1,extended_byte_aligned/1,
extended_bit_aligned/1,mixed/1,filters/1,trim_coverage/1,
- nomatch/1,sizes/1,general_expressions/1]).
+ nomatch/1,sizes/1,general_expressions/1,matched_out_size/1]).
-include_lib("common_test/include/ct.hrl").
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[byte_aligned, bit_aligned, extended_byte_aligned,
extended_bit_aligned, mixed, filters, trim_coverage,
- nomatch, sizes, general_expressions].
+ nomatch, sizes, general_expressions, matched_out_size].
groups() ->
[].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -338,6 +338,13 @@ general_expressions(_) ->
-undef(BAD).
+matched_out_size(Config) when is_list(Config) ->
+ <<1, 2>> = matched_out_size_1(<<4, 1:4, 4, 2:4>>),
+ ok.
+
+matched_out_size_1(Binary) ->
+ << <<X>> || <<S, X:S>> <= Binary>>.
+
cs_init() ->
erts_debug:set_internal_state(available_internal_state, true),
ok.
diff --git a/lib/compiler/test/bs_bit_binaries_SUITE.erl b/lib/compiler/test/bs_bit_binaries_SUITE.erl
index 208d8c5487..526769f3a6 100644
--- a/lib/compiler/test/bs_bit_binaries_SUITE.erl
+++ b/lib/compiler/test/bs_bit_binaries_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -34,7 +34,6 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -43,9 +42,10 @@ groups() ->
asymmetric_tests,big_asymmetric_tests,
binary_to_and_from_list,big_binary_to_and_from_list,
send_and_receive,send_and_receive_alot]}].
-
+
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/bs_construct_SUITE.erl b/lib/compiler/test/bs_construct_SUITE.erl
index da99aba346..bccd70d6cb 100644
--- a/lib/compiler/test/bs_construct_SUITE.erl
+++ b/lib/compiler/test/bs_construct_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
+ verify_highest_opcode/1,
two/1,test1/1,fail/1,float_bin/1,in_guard/1,in_catch/1,
nasty_literals/1,coerce_to_float/1,side_effect/1,
opt/1,otp_7556/1,float_arith/1,otp_8054/1,
@@ -38,18 +39,19 @@ suite() ->
[{ct_hooks,[ts_install_cth]},
{timetrap,{minutes,1}}].
-all() ->
- test_lib:recompile(?MODULE),
+all() ->
[{group,p}].
-groups() ->
+groups() ->
[{p,[parallel],
- [two,test1,fail,float_bin,in_guard,in_catch,
+ [verify_highest_opcode,
+ two,test1,fail,float_bin,in_guard,in_catch,
nasty_literals,side_effect,opt,otp_7556,float_arith,
otp_8054,cover]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -68,6 +70,20 @@ init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
end_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
ok.
+verify_highest_opcode(_Config) ->
+ case ?MODULE of
+ bs_construct_r21_SUITE ->
+ {ok,Beam} = file:read_file(code:which(?MODULE)),
+ case test_lib:highest_opcode(Beam) of
+ Highest when Highest =< 163 ->
+ ok;
+ TooHigh ->
+ ct:fail({too_high_opcode_for_21,TooHigh})
+ end;
+ _ ->
+ ok
+ end.
+
two(Config) when is_list(Config) ->
<<0,1,2,3,4,6,7,8,9>> = two_1([0], [<<1,2,3,4>>,<<6,7,8,9>>]),
ok.
@@ -153,6 +169,8 @@ l(I_13, I_big1, I_16, Bin) ->
[0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
16#77,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,
16#FF,16#FF,16#FF,16#FF,16#FF,16#FF]),
+ ?T(<< (<<"abc",7:3>>):3/binary >>,
+ [$a,$b,$c]),
%% Mix different units.
?T(<<37558955:(I_16-12)/unit:8,1:1>>,
@@ -303,7 +321,17 @@ fail(Config) when is_list(Config) ->
{'EXIT',{badarg,_}} = (catch <<42.0/integer>>),
{'EXIT',{badarg,_}} = (catch <<42/binary>>),
{'EXIT',{badarg,_}} = (catch <<an_atom/integer>>),
-
+
+ %% Bad literal sizes
+ Bin = i(<<>>),
+ {'EXIT',{badarg,_}} = (catch <<0:(-1)>>),
+ {'EXIT',{badarg,_}} = (catch <<Bin/binary,0:(-1)>>),
+ {'EXIT',{badarg,_}} = (catch <<0:(-(1 bsl 100))>>),
+ {'EXIT',{badarg,_}} = (catch <<Bin/binary,0:(-(1 bsl 100))>>),
+
+ %% Unaligned sizes with literal binaries.
+ {'EXIT',{badarg,_}} = (catch <<0,(<<7777:17>>)/binary>>),
+
ok.
float_bin(Config) when is_list(Config) ->
diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl
index 2fe8cd0cff..d97f49c56e 100644
--- a/lib/compiler/test/bs_match_SUITE.erl
+++ b/lib/compiler/test/bs_match_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
+ verify_highest_opcode/1,
size_shadow/1,int_float/1,otp_5269/1,null_fields/1,wiger/1,
bin_tail/1,save_restore/1,
partitioned_bs_match/1,function_clause/1,
@@ -39,7 +40,11 @@
match_string_opt/1,select_on_integer/1,
map_and_binary/1,unsafe_branch_caching/1,
bad_literals/1,good_literals/1,constant_propagation/1,
- parse_xml/1,get_payload/1,num_slots_different/1]).
+ parse_xml/1,get_payload/1,escape/1,num_slots_different/1,
+ beam_bsm/1,guard/1,is_ascii/1,non_opt_eq/1,
+ expression_before_match/1,erl_689/1,restore_on_call/1,
+ restore_after_catch/1,matches_on_parameter/1,big_positions/1,
+ matching_meets_apply/1,bs_start_match2_defs/1]).
-export([coverage_id/1,coverage_external_ignore/2]).
@@ -52,12 +57,12 @@ suite() ->
{timetrap,{minutes,1}}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
- [{p,[parallel],
- [size_shadow,int_float,otp_5269,null_fields,wiger,
+ [{p,[],
+ [verify_highest_opcode,
+ size_shadow,int_float,otp_5269,null_fields,wiger,
bin_tail,save_restore,
partitioned_bs_match,function_clause,unit,
shared_sub_bins,bin_and_float,dec_subidentifiers,
@@ -71,10 +76,15 @@ groups() ->
match_string_opt,select_on_integer,
map_and_binary,unsafe_branch_caching,
bad_literals,good_literals,constant_propagation,parse_xml,
- get_payload,num_slots_different]}].
+ get_payload,escape,num_slots_different,
+ beam_bsm,guard,is_ascii,non_opt_eq,
+ expression_before_match,erl_689,restore_on_call,
+ matches_on_parameter,big_positions,
+ matching_meets_apply,bs_start_match2_defs]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -93,6 +103,20 @@ init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
end_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
ok.
+verify_highest_opcode(_Config) ->
+ case ?MODULE of
+ bs_match_r21_SUITE ->
+ {ok,Beam} = file:read_file(code:which(?MODULE)),
+ case test_lib:highest_opcode(Beam) of
+ Highest when Highest =< 163 ->
+ ok;
+ TooHigh ->
+ ct:fail({too_high_opcode_for_21,TooHigh})
+ end;
+ _ ->
+ ok
+ end.
+
size_shadow(Config) when is_list(Config) ->
%% Originally OTP-5270.
7 = size_shadow_1(),
@@ -246,6 +270,12 @@ bin_tail(Config) when is_list(Config) ->
ok = bin_tail_e(<<2:2,1:1,1:5,42:64>>),
error = bin_tail_e(<<3:2,1:1,1:5,42:64>>),
error = bin_tail_e(<<>>),
+
+ MD5 = erlang:md5(<<42>>),
+ <<"abc">> = bin_tail_f(<<MD5/binary,"abc">>, MD5, 3),
+ error = bin_tail_f(<<MD5/binary,"abc">>, MD5, 999),
+ {'EXIT',{_,_}} = (catch bin_tail_f(<<0:16/unit:8>>, MD5, 0)),
+
ok.
bin_tail_c(Bin, Offset) ->
@@ -302,6 +332,14 @@ bin_tail_e_var(Bin) ->
<<2:2,_:1,1:5,Tail/binary>> -> Tail;
_ -> error
end.
+
+bin_tail_f(Bin, MD5, Size) ->
+ case Bin of
+ <<MD5:16/binary, Tail:Size/binary>> ->
+ Tail;
+ <<MD5:16/binary, _/binary>> ->
+ error
+ end.
save_restore(Config) when is_list(Config) ->
0 = save_restore_1(<<0:2,42:6>>),
@@ -328,6 +366,11 @@ save_restore(Config) when is_list(Config) ->
{"-",<<"x">>} = nnn(C),
{"-",<<"x">>} = ooo(C),
+ a = multiple_matches(<<777:16>>, <<777:16>>),
+ b = multiple_matches(<<777:16>>, <<999:16>>),
+ c = multiple_matches(<<777:16>>, <<57:8>>),
+ d = multiple_matches(<<17:8>>, <<1111:16>>),
+
Bin = <<-1:64>>,
case bad_float_unpack_match(Bin) of
-1 -> ok;
@@ -355,6 +398,11 @@ nnn(<<Char, Tail/binary>>) -> {[Char],Tail}. %% Buggy Tail!
ooo(<<" - ", Tail/binary>>) -> Tail;
ooo(<<Char, Tail/binary>>) -> {[Char],Tail}.
+multiple_matches(<<Y:16>>, <<Y:16>>) -> a;
+multiple_matches(<<_:16>>, <<_:16>>) -> b;
+multiple_matches(<<_:16>>, <<_:8>>) -> c;
+multiple_matches(<<_:8>>, <<_:16>>) -> d.
+
bad_float_unpack_match(<<F:64/float>>) -> F;
bad_float_unpack_match(<<I:64/integer-signed>>) -> I.
@@ -443,6 +491,15 @@ unit(Config) when is_list(Config) ->
127 = peek7(<<127:7>>),
100 = peek7(<<100:7,19:7>>),
fc(peek7, [<<1,2>>], catch peek7(<<1,2>>)),
+
+ 1 = unit_opt(1, -1),
+ 8 = unit_opt(8, -1),
+
+ <<1:32,"abc">> = unit_opt_2(<<1:32,"abc">>),
+ <<"def">> = unit_opt_2(<<2:32,"def">>),
+ {'EXIT',_} = (catch unit_opt_2(<<1:32,33:7>>)),
+ {'EXIT',_} = (catch unit_opt_2(<<2:32,55:7>>)),
+
ok.
peek1(<<B:8,_/bitstring>>) -> B.
@@ -453,6 +510,27 @@ peek8(<<B:8,_/binary>>) -> B.
peek16(<<B:16,_/binary-unit:16>>) -> B.
+unit_opt(U, X) ->
+ %% Cover type analysis in beam_ssa_type.
+ Bin = case U of
+ 1 -> <<X:7>>;
+ 8 -> <<X>>
+ end,
+ %% The type of Bin will be set to {binary,gcd(1, 8)}.
+ case Bin of
+ <<_/binary-unit:8>> -> 8;
+ <<_/binary-unit:1>> -> 1
+ end.
+
+unit_opt_2(<<St:32,KO/binary>> = Bin0) ->
+ Bin = if
+ St =:= 1 ->
+ Bin0;
+ St =:= 2 ->
+ <<KO/binary>>
+ end,
+ id(Bin).
+
shared_sub_bins(Config) when is_list(Config) ->
{15,[<<>>,<<5>>,<<4,5>>,<<3,4,5>>,<<2,3,4,5>>]} = sum(<<1,2,3,4,5>>, [], 0),
ok.
@@ -676,6 +754,24 @@ coverage(Config) when is_list(Config) ->
<<>> = coverage_per_key(<<4:32>>),
<<$a,$b,$c>> = coverage_per_key(<<7:32,"abc">>),
+ binary = coverage_bitstring(<<>>),
+ binary = coverage_bitstring(<<7>>),
+ bitstring = coverage_bitstring(<<7:4>>),
+ other = coverage_bitstring([a]),
+
+ %% Cover code in beam_trim.
+
+ {done,<<17,53>>,[253,155,200]} =
+ coverage_trim(<<253,155,200,17,53>>, e0, e1, e2, e3, []),
+
+ <<"(right|linux)">> = coverage_trim_1(<<"">>, <<"right">>, <<"linux">>),
+ <<"/(right|linux)">> = coverage_trim_1(<<"/">>, <<"right">>, <<"linux">>),
+ <<"(left|linux)/(right|linux)">> =
+ coverage_trim_1(<<"left">>, <<"right">>, <<"linux">>),
+
+ {10,<<"-">>,""} = coverage_trim_2(<<"-">>, 10, []),
+ {8,<<"-">>,"aa"} = coverage_trim_2(<<"aa-">>, 10, []),
+
ok.
coverage_fold(Fun, Acc, <<H,T/binary>>) ->
@@ -766,6 +862,41 @@ coverage_per_key(<<BinSize:32,Bin/binary>> = B) ->
true = (byte_size(B) =:= BinSize),
Bin.
+coverage_bitstring(Bin) when is_binary(Bin) -> binary;
+coverage_bitstring(<<_/bitstring>>) -> bitstring;
+coverage_bitstring(_) -> other.
+
+coverage_trim(<<C:8,T/binary>> = Bin, E0, E1, E2, E3, Acc) ->
+ case id(C > 128) of
+ true ->
+ coverage_trim(T, E0, E1, E2, E3, [C|Acc]);
+ false ->
+ {done,Bin,lists:reverse(Acc)}
+ end.
+
+coverage_trim_1(<<>>, Right, OsType) ->
+ do_coverage_trim_1(Right, OsType);
+coverage_trim_1(<<"/">>, Right, OsType) ->
+ <<"/",(do_coverage_trim_1(Right, OsType))/binary>>;
+coverage_trim_1(Left, Right, OsType) ->
+ <<(do_coverage_trim_1(Left, OsType))/binary,
+ "/",
+ (do_coverage_trim_1(Right, OsType))/binary>>.
+
+do_coverage_trim_1(A, OsType) ->
+ <<"(",A/binary,"|",OsType/binary,")">>.
+
+coverage_trim_2(<<C/utf8,R/binary>> = Bin, I, L) ->
+ case printable_char(C) of
+ true ->
+ coverage_trim_2(R, I - 1, [C | L]);
+ false ->
+ {I,Bin,lists:reverse(L)}
+ end.
+
+printable_char($a) -> true;
+printable_char(_) -> false.
+
multiple_uses(Config) when is_list(Config) ->
{344,62879,345,<<245,159,1,89>>} = multiple_uses_1(<<1,88,245,159,1,89>>),
true = multiple_uses_2(<<0,0,197,18>>),
@@ -799,7 +930,7 @@ multiple_uses_cmp(<<_:16>>, <<_:16>>) -> false.
first_after(Data, Offset) ->
case byte_size(Data) > Offset of
false ->
- {First, Rest} = {ok, ok},
+ {_First, _Rest} = {ok, ok},
ok;
true ->
<<_:Offset/binary, Rest/binary>> = Data,
@@ -1513,7 +1644,7 @@ is_next_char_whitespace(<<C/utf8,_/binary>>) ->
{this_hdr = 17,
ext_hdr_opts}).
-get_payload(Config) ->
+get_payload(_Config) ->
<<3445:48>> = do_get_payload(#ext_header{ext_hdr_opts = <<3445:48>>}),
{'EXIT',_} = (catch do_get_payload(#ext_header{})),
ok.
@@ -1524,6 +1655,21 @@ do_get_payload(ExtHdr) ->
<<_:13,_:35>> = ExtHdr#ext_header.ext_hdr_opts,
ExtHdrOptions.
+escape(_Config) ->
+ 0 = escape(<<>>, 0),
+ 1 = escape(<<128>>, 0),
+ 2 = escape(<<128,255>>, 0),
+ 42 = escape(<<42>>, 0),
+ 50 = escape(<<42,8>>, 0),
+ ok.
+
+escape(<<Byte, Rest/bits>>, Pos) when Byte >= 127 ->
+ escape(Rest, Pos + 1);
+escape(<<Byte, Rest/bits>>, Pos) ->
+ escape(Rest, Pos + Byte);
+escape(<<_Rest/bits>>, Pos) ->
+ Pos.
+
%% ERL-490
num_slots_different(_Config) ->
Ts = [{<<"de">>, <<"default">>, <<"Remove">>, <<"a">>},
@@ -1557,8 +1703,306 @@ lgettext(<<"de">>, <<"navigation">>, <<"Results">>) ->
lgettext(<<"de">>, <<"navigation">>, <<"Resources">>) ->
{ok, <<"Ressourcen">>}.
+%% Test more code in beam_bsm.
+beam_bsm(_Config) ->
+ true = check_bitstring_list(<<1:1,0:1,1:1,1:1>>, [1,0,1,1]),
+ false = check_bitstring_list(<<1:1,0:1,1:1,1:1>>, [0]),
+
+ true = bsm_validate_scheme(<<>>),
+ true = bsm_validate_scheme(<<5,10>>),
+ false = bsm_validate_scheme(<<5,10,11,12>>),
+ true = bsm_validate_scheme([]),
+ true = bsm_validate_scheme([5,10]),
+ false = bsm_validate_scheme([5,6,7]),
+
+ <<1,2,3>> = bsm_must_save_and_not_save(<<1,2,3>>, []),
+ D = fun(N) -> 2*N end,
+ [2,4|<<3>>] = bsm_must_save_and_not_save(<<1,2,3>>, [D,D]),
+
+ ok.
+
+check_bitstring_list(<<H:1,T1/bitstring>>, [H|T2]) ->
+ check_bitstring_list(T1, T2);
+check_bitstring_list(<<>>, []) ->
+ true;
+check_bitstring_list(_, _) ->
+ false.
+
+bsm_validate_scheme([]) -> true;
+bsm_validate_scheme([H|T]) ->
+ case bsm_is_scheme(H) of
+ true -> bsm_validate_scheme(T);
+ false -> false
+ end;
+bsm_validate_scheme(<<>>) -> true;
+bsm_validate_scheme(<<H, Rest/binary>>) ->
+ case bsm_is_scheme(H) of
+ true -> bsm_validate_scheme(Rest);
+ false -> false
+ end.
+
+bsm_is_scheme(Int) ->
+ Int rem 5 =:= 0.
+
+%% NOT OPTIMIZED: different control paths use different positions in the binary
+bsm_must_save_and_not_save(Bin, []) ->
+ Bin;
+bsm_must_save_and_not_save(<<H,T/binary>>, [F|Fs]) ->
+ [F(H)|bsm_must_save_and_not_save(T, Fs)];
+bsm_must_save_and_not_save(<<>>, []) ->
+ [].
+
+guard(_Config) ->
+ _Tuple = id({a,b}),
+ ok = guard_1(<<1,2,3>>, {1,2,3}),
+ ok = guard_2(<<42>>, #{}),
+ ok.
+
+%% Cover handling of #k_put{} in v3_codegen:bsm_rename_ctx/4.
+guard_1(<<A,B,C>>, Tuple) when Tuple =:= {A,B,C} ->
+ ok.
+
+%% Cover handling of #k_call{} in v3_codegen:bsm_rename_ctx/4.
+guard_2(<<_>>, Healing) when Healing#{[] => Healing} =:= #{[] => #{}} ->
+ ok.
+
+is_ascii(_Config) ->
+ true = do_is_ascii(<<>>),
+ true = do_is_ascii(<<"string">>),
+ false = do_is_ascii(<<1024/utf8>>),
+ {'EXIT',{function_clause,_}} = (catch do_is_ascii(<<$A,0:3>>)),
+ {'EXIT',{function_clause,_}} = (catch do_is_ascii(<<16#80,0:3>>)),
+ ok.
+
+do_is_ascii(<<>>) ->
+ true;
+do_is_ascii(<<C,_/binary>>) when C >= 16#80 ->
+ %% This clause must fail to match if the size of the argument in
+ %% bits is not divisible by 8. Beware of unsafe optimizations.
+ false;
+do_is_ascii(<<_, T/binary>>) ->
+ do_is_ascii(T).
+
+non_opt_eq(_Config) ->
+ true = non_opt_eq([], <<>>),
+ true = non_opt_eq([$a], <<$a>>),
+ false = non_opt_eq([$a], <<$b>>),
+ ok.
+
+%% An example from the Efficiency Guide. It used to be not optimized,
+%% but now it can be optimized.
+
+non_opt_eq([H|T1], <<H,T2/binary>>) ->
+ non_opt_eq(T1, T2);
+non_opt_eq([_|_], <<_,_/binary>>) ->
+ false;
+non_opt_eq([], <<>>) ->
+ true.
+
+%% ERL-689
+
+erl_689(_Config) ->
+ {{0, 0, 0}, <<>>} = do_erl_689_1(<<0>>, ?MODULE),
+ {{2018, 8, 7}, <<>>} = do_erl_689_1(<<4,2018:16/little,8,7>>, ?MODULE),
+ {{0, 0, 0}, <<>>} = do_erl_689_2(?MODULE, <<0>>),
+ {{2018, 8, 7}, <<>>} = do_erl_689_2(?MODULE, <<4,2018:16/little,8,7>>),
+ ok.
+
+do_erl_689_1(Arg1, Arg2) ->
+ Res = do_erl_689_1a(Arg1, Arg2),
+ Res = do_erl_689_1b(Arg1, Arg2).
+
+do_erl_689_2(Arg1, Arg2) ->
+ Res = do_erl_689_2a(Arg1, Arg2),
+ Res = do_erl_689_2b(Arg1, Arg2).
+
+do_erl_689_1a(<<Length, Data/binary>>, _) ->
+ case {Data, Length} of
+ {_, 0} ->
+ %% bs_context_to_binary would incorrectly set Data to the original
+ %% binary (before matching in the function head).
+ {{0, 0, 0}, Data};
+ {<<Y:16/little, M, D, Rest/binary>>, 4} ->
+ {{Y, M, D}, Rest}
+ end.
+
+do_erl_689_1b(<<Length, Data/binary>>, _) ->
+ case {Data, Length} of
+ {_, 0} ->
+ %% bs_context_to_binary would incorrectly set Data to the original
+ %% binary (before matching in the function head).
+ id(0),
+ {{0, 0, 0}, Data};
+ {<<Y:16/little, M, D, Rest/binary>>, 4} ->
+ id(1),
+ {{Y, M, D}, Rest}
+ end.
+
+do_erl_689_2a(_, <<Length, Data/binary>>) ->
+ case {Length, Data} of
+ {0, _} ->
+ %% bs_context_to_binary would incorrectly set Data to the original
+ %% binary (before matching in the function head).
+ {{0, 0, 0}, Data};
+ {4, <<Y:16/little, M, D, Rest/binary>>} ->
+ {{Y, M, D}, Rest}
+ end.
+
+do_erl_689_2b(_, <<Length, Data/binary>>) ->
+ case {Length, Data} of
+ {0, _} ->
+ %% bs_context_to_binary would incorrectly set Data to the original
+ %% binary (before matching in the function head).
+ id(0),
+ {{0, 0, 0}, Data};
+ {4, <<Y:16/little, M, D, Rest/binary>>} ->
+ id(1),
+ {{Y, M, D}, Rest}
+ end.
+
+%% ERL-753
+
+bs_start_match2_defs(_Config) ->
+ {<<"http://127.0.0.1:1234/vsaas/hello">>} = api_url(<<"hello">>),
+ {"https://127.0.0.1:4321/vsaas/hello"} = api_url({https, "hello"}).
+
+api_url(URL) ->
+ case URL of
+ <<_/binary>> -> {<<"http://127.0.0.1:1234/vsaas/",URL/binary>>};
+ {https, [_|_] = URL1} -> {"https://127.0.0.1:4321/vsaas/"++URL1}
+ end.
check(F, R) ->
R = F().
+%% Make sure that an expression that comes between function start and a match
+%% expression passes validation.
+expression_before_match(Config) when is_list(Config) ->
+ <<_,R/binary>> = id(<<0,1,2,3>>),
+ {1, <<2,3>>} = expression_before_match_1(R),
+ ok.
+
+expression_before_match_1(R) ->
+ A = id(1),
+ case R of
+ <<1,Bar/binary>> -> {A, Bar};
+ <<>> -> {A, baz}
+ end.
+
+%% Make sure that context positions are updated on calls.
+restore_on_call(Config) when is_list(Config) ->
+ ok = restore_on_call_plain(<<0, 1, 2>>),
+ <<"x">> = restore_on_call_match(<<0, "x">>),
+ ok.
+
+restore_on_call_plain(<<0, Rest/binary>>) ->
+ <<2>> = restore_on_call_plain_1(Rest),
+ %% {badmatch, <<>>} on missing restore.
+ <<2>> = restore_on_call_plain_1(Rest),
+ ok.
+
+restore_on_call_plain_1(<<1, Rest/binary>>) -> Rest;
+restore_on_call_plain_1(Other) -> Other.
+
+%% Calls a function that moves the match context passed to it, and then matches
+%% on its result to confuse the reposition algorithm's success/fail logic.
+restore_on_call_match(<<0, Bin/binary>>) ->
+ case skip_until_zero(Bin) of
+ {skipped, Rest} ->
+ Rest;
+ not_found ->
+ %% The match context did not get repositioned before the
+ %% bs_get_tail instruction here.
+ Bin
+ end.
+
+skip_until_zero(<<0,Rest/binary>>) ->
+ {skipped, Rest};
+skip_until_zero(<<_C,Rest/binary>>) ->
+ skip_until_zero(Rest);
+skip_until_zero(_) ->
+ not_found.
+
+%% 'catch' must invalidate positions.
+restore_after_catch(Config) when is_list(Config) ->
+ <<0, 1>> = restore_after_catch_1(<<0, 1>>),
+ ok.
+
+restore_after_catch_1(<<A/binary>>) ->
+ try throw_after_byte(A) of
+ _ -> impossible
+ catch
+ throw:_Any ->
+ %% Will equal <<1>> if the bug is present.
+ A
+ end.
+
+throw_after_byte(<<_,_/binary>>) ->
+ throw(away).
+
+matches_on_parameter(Config) when is_list(Config) ->
+ %% This improves coverage for matching on "naked" parameters.
+ {<<"urka">>, <<"a">>} = matches_on_parameter_1(<<"gurka">>),
+ ok = (catch matches_on_parameter_2(<<"10001110101">>, 0)).
+
+matches_on_parameter_1(Bin) ->
+ <<"g", A/binary>> = Bin,
+ <<_,_,"rk", B/binary>> = Bin,
+ {A, B}.
+
+matches_on_parameter_2(Bin, Offset) ->
+ <<_:Offset, Bit:1, Rest/bits>> = Bin,
+ case bit_size(Rest) of
+ 0 -> throw(ok);
+ _ -> [Bit | matches_on_parameter_2(Bin, Offset + 1)]
+ end.
+
+big_positions(Config) when is_list(Config) ->
+ %% This provides coverage for when match context positions no longer fit
+ %% into an immediate on 32-bit platforms.
+
+ A = <<0:((1 bsl 27) - 8), $A, 1:1, "gurka", $A>>,
+ B = <<0:((1 bsl 27) - 8), $B, "hello", $B>>,
+
+ {a,$A} = bp_start_match(A),
+ {b,$B} = bp_start_match(B),
+ {a,$A} = bp_getpos(A),
+ {b,$B} = bp_getpos(B),
+
+ ok.
+
+%% After the first iteration the context's position will no longer fit into an
+%% immediate. To improve performance the bs_start_match3 instruction will
+%% return a new context with an updated base position so that we won't have to
+%% resort to using bigints.
+bp_start_match(<<_:(1 bsl 27),T/bits>>) -> bp_start_match(T);
+bp_start_match(<<1:1,"gurka",A>>) -> {a,A};
+bp_start_match(<<"hello",B>>) -> {b,B}.
+
+%% This is a corner case where the above didn't work perfectly; if the position
+%% was _just_ small enough to fit into an immediate when bs_start_match3 was
+%% hit, but too large at bs_get_position, then it must be saved as a bigint.
+bp_getpos(<<_:((1 bsl 27) - 8),T/bits>>) -> bp_getpos(T);
+bp_getpos(<<A,1:1,"gurka",A>>) -> {a,A};
+bp_getpos(<<B,"hello",B>>) -> {b,B}.
+
+matching_meets_apply(_Config) ->
+ <<"abc">> = do_matching_meets_apply(<<"/abc">>, []),
+ 42 = do_matching_meets_apply(<<"">>, {erlang,-42}),
+ 100 = do_matching_meets_apply(no_binary, {erlang,-100}),
+ ok.
+
+do_matching_meets_apply(<<$/, Rest/binary>>, _Handler) ->
+ id(Rest);
+do_matching_meets_apply(<<_/binary>>=Name, never_matches_a) ->
+ %% Used to crash the compiler because variables in a remote
+ %% were not handled properly by beam_ssa_bsm.
+ Name:foo(gurka);
+do_matching_meets_apply(<<_/binary>>=Name, never_matches_b) ->
+ %% Another case of the above.
+ foo:Name(gurka);
+do_matching_meets_apply(_Bin, {Handler, State}) ->
+ %% Another case of the above.
+ Handler:abs(State).
+
id(I) -> I.
diff --git a/lib/compiler/test/bs_utf_SUITE.erl b/lib/compiler/test/bs_utf_SUITE.erl
index ef3fc54b37..8ea4a849ec 100644
--- a/lib/compiler/test/bs_utf_SUITE.erl
+++ b/lib/compiler/test/bs_utf_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -31,7 +31,6 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[utf8_roundtrip, unused_utf_char, utf16_roundtrip,
utf32_roundtrip, guard, extreme_tripping, literals,
coverage].
@@ -40,6 +39,7 @@ groups() ->
[].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/compilation_SUITE.erl b/lib/compiler/test/compilation_SUITE.erl
index a4de125d32..74f9dbd9b4 100644
--- a/lib/compiler/test/compilation_SUITE.erl
+++ b/lib/compiler/test/compilation_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -66,7 +66,6 @@ suite() ->
{timetrap,{minutes,10}}].
all() ->
- test_lib:recompile(?MODULE),
[self_compile_old_inliner,self_compile,
{group,p}].
@@ -88,6 +87,7 @@ groups() ->
string_table,otp_8949_a,split_cases]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -170,7 +170,7 @@ try_it(Module, Conf) ->
atom_to_list(Module)),
Out = proplists:get_value(priv_dir,Conf),
io:format("Compiling: ~s\n", [Src]),
- CompRc0 = compile:file(Src, [clint0,clint,{outdir,Out},report,
+ CompRc0 = compile:file(Src, [clint0,clint,ssalint,{outdir,Out},report,
bin_opt_info|OtherOpts]),
io:format("Result: ~p\n",[CompRc0]),
{ok,_Mod} = CompRc0,
@@ -189,7 +189,7 @@ try_it(Module, Conf) ->
ct:timetrap(Timetrap),
io:format("Compiling (with old inliner): ~s\n", [Src]),
- CompRc2 = compile:file(Src, [clint,
+ CompRc2 = compile:file(Src, [clint,ssalint,
{outdir,Out},report,bin_opt_info,
{inline,1000}|OtherOpts]),
io:format("Result: ~p\n",[CompRc2]),
@@ -355,7 +355,7 @@ compile_compiler(Files, OutDir, Version, InlineOpts) ->
io:format("~ts", [code:which(compile)]),
io:format("Compiling ~s into ~ts", [Version,OutDir]),
Opts = [report,
- clint0,clint,
+ clint0,clint,ssalint,
bin_opt_info,
{outdir,OutDir},
{d,'COMPILER_VSN',"\""++Version++"\""},
diff --git a/lib/compiler/test/compilation_SUITE_data/opt_crash.erl b/lib/compiler/test/compilation_SUITE_data/opt_crash.erl
index f1607cca68..4643ce61f6 100644
--- a/lib/compiler/test/compilation_SUITE_data/opt_crash.erl
+++ b/lib/compiler/test/compilation_SUITE_data/opt_crash.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -33,7 +33,7 @@ test() ->
{userinfo,nil},
fun() -> nil end},
nil},
- {'query',nil}}},
+ {query,nil}}},
{absoluteURI,
{scheme,_},
@@ -43,7 +43,7 @@ test() ->
{userinfo,nil},
HostportBefore},
nil},
- {'query',nil}}} = URI_Before,
+ {query,nil}}} = URI_Before,
%% ... some funky code ommitted, not relevant ...
@@ -55,7 +55,7 @@ test() ->
{userinfo,nil},
HostportAfter},
nil},
- {'query',nil}}} = URI_Before,
+ {query,nil}}} = URI_Before,
%% NOTE: I intended to write URI_After instead of URI_Before
%% but the accident revealed that when you add the line below,
%% it causes internal error in v3_codegen on compilation
diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl
index 96897d612d..53627b9d81 100644
--- a/lib/compiler/test/compile_SUITE.erl
+++ b/lib/compiler/test/compile_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -27,16 +27,16 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
app_test/1,appup_test/1,
- debug_info/4, custom_debug_info/1,
- file_1/1, forms_2/1, module_mismatch/1, big_file/1, outdir/1,
+ debug_info/4, custom_debug_info/1, custom_compile_info/1,
+ file_1/1, forms_2/1, module_mismatch/1, outdir/1,
binary/1, makedep/1, cond_and_ifdef/1, listings/1, listings_big/1,
other_output/1, kernel_listing/1, encrypted_abstr/1,
strict_record/1, utf8_atoms/1, utf8_functions/1, extra_chunks/1,
- cover/1, env/1, core_pp/1,
- core_roundtrip/1, asm/1, optimized_guards/1,
+ cover/1, env/1, core_pp/1, tuple_calls/1,
+ core_roundtrip/1, asm/1,
sys_pre_attributes/1, dialyzer/1,
warnings/1, pre_load_check/1, env_compiler_options/1,
- bc_options/1
+ bc_options/1, deterministic_include/1, deterministic_paths/1
]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -46,19 +46,20 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
-spec all() -> all_return_type().
all() ->
- test_lib:recompile(?MODULE),
- [app_test, appup_test, file_1, forms_2, module_mismatch, big_file, outdir,
+ [app_test, appup_test, file_1, forms_2, module_mismatch, outdir,
binary, makedep, cond_and_ifdef, listings, listings_big,
- other_output, kernel_listing, encrypted_abstr,
+ other_output, kernel_listing, encrypted_abstr, tuple_calls,
strict_record, utf8_atoms, utf8_functions, extra_chunks,
- cover, env, core_pp, core_roundtrip, asm, optimized_guards,
+ cover, env, core_pp, core_roundtrip, asm,
sys_pre_attributes, dialyzer, warnings, pre_load_check,
- env_compiler_options, custom_debug_info, bc_options].
+ env_compiler_options, custom_debug_info, bc_options,
+ custom_compile_info, deterministic_include, deterministic_paths].
groups() ->
[].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -103,6 +104,7 @@ file_1(Config) when is_list(Config) ->
compile_and_verify(Simple, Target, []),
compile_and_verify(Simple, Target, [native]),
compile_and_verify(Simple, Target, [debug_info]),
+ compile_and_verify(Simple, Target, [no_postopt]),
{ok,simple} = compile:file(Simple, [no_line_info]), %Coverage
{ok,simple} = compile:file(Simple, [{eprof,beam_z}]), %Coverage
@@ -230,17 +232,6 @@ module_mismatch(Config) when is_list(Config) ->
ok.
-big_file(Config) when is_list(Config) ->
- {Big,Target} = get_files(Config, big, "big_file"),
- ok = file:set_cwd(filename:dirname(Target)),
- compile_and_verify(Big, Target, []),
- compile_and_verify(Big, Target, [debug_info]),
- compile_and_verify(Big, Target, [no_postopt]),
-
- %% Cleanup.
- ok = file:delete(Target),
- ok.
-
%% Tests that the {outdir, Dir} option works.
outdir(Config) when is_list(Config) ->
@@ -369,42 +360,37 @@ do_file_listings(DataDir, PrivDir, [File|Files]) ->
TargetDir = filename:join(PrivDir, listings),
ok = file:make_dir(TargetDir),
- %% Test all dedicated listing options.
- do_listing(Simple, TargetDir, 'S'),
- do_listing(Simple, TargetDir, 'E'),
- do_listing(Simple, TargetDir, 'P'),
- do_listing(Simple, TargetDir, dpp, ".pp"),
- do_listing(Simple, TargetDir, dabstr, ".abstr"),
- do_listing(Simple, TargetDir, dexp, ".expand"),
- do_listing(Simple, TargetDir, dcore, ".core"),
- do_listing(Simple, TargetDir, doldinline, ".oldinline"),
- do_listing(Simple, TargetDir, dinline, ".inline"),
- do_listing(Simple, TargetDir, dcore, ".core"),
- do_listing(Simple, TargetDir, dcopt, ".copt"),
- do_listing(Simple, TargetDir, dcbsm, ".core_bsm"),
- do_listing(Simple, TargetDir, dsetel, ".dsetel"),
- do_listing(Simple, TargetDir, dkern, ".kernel"),
- do_listing(Simple, TargetDir, dlife, ".life"),
- do_listing(Simple, TargetDir, dcg, ".codegen"),
- do_listing(Simple, TargetDir, dblk, ".block"),
- do_listing(Simple, TargetDir, dexcept, ".except"),
- do_listing(Simple, TargetDir, dbs, ".bs"),
- do_listing(Simple, TargetDir, dtype, ".type"),
- do_listing(Simple, TargetDir, ddead, ".dead"),
- do_listing(Simple, TargetDir, djmp, ".jump"),
- do_listing(Simple, TargetDir, dclean, ".clean"),
- do_listing(Simple, TargetDir, dpeep, ".peep"),
- do_listing(Simple, TargetDir, dopt, ".optimize"),
-
- %% First clean up.
- Listings = filename:join(PrivDir, listings),
- lists:foreach(fun(F) -> ok = file:delete(F) end,
- filelib:wildcard(filename:join(Listings, "*"))),
+ List = [{'S',".S"},
+ {'E',".E"},
+ {'P',".P"},
+ {dpp, ".pp"},
+ {dabstr, ".abstr"},
+ {dexp, ".expand"},
+ {dcore, ".core"},
+ {doldinline, ".oldinline"},
+ {dinline, ".inline"},
+ {dcore, ".core"},
+ {dcopt, ".copt"},
+ {dcbsm, ".core_bsm"},
+ {dkern, ".kernel"},
+ {dssa, ".ssa"},
+ {dssaopt, ".ssaopt"},
+ {dprecg, ".precodegen"},
+ {dcg, ".codegen"},
+ {dblk, ".block"},
+ {dexcept, ".except"},
+ {djmp, ".jump"},
+ {dclean, ".clean"},
+ {dpeep, ".peep"},
+ {dopt, ".optimize"},
+ {diffable, ".S"}],
+ p_listings(List, Simple, TargetDir),
%% Test options that produce a listing file if 'binary' is not given.
do_listing(Simple, TargetDir, to_pp, ".P"),
do_listing(Simple, TargetDir, to_exp, ".E"),
do_listing(Simple, TargetDir, to_core0, ".core"),
+ Listings = filename:join(PrivDir, listings),
ok = file:delete(filename:join(Listings, File ++ ".core")),
do_listing(Simple, TargetDir, to_core, ".core"),
do_listing(Simple, TargetDir, to_kernel, ".kernel"),
@@ -420,21 +406,35 @@ do_file_listings(DataDir, PrivDir, [File|Files]) ->
listings_big(Config) when is_list(Config) ->
{Big,Target} = get_files(Config, big, listings_big),
TargetDir = filename:dirname(Target),
- do_listing(Big, TargetDir, 'S'),
- do_listing(Big, TargetDir, 'E'),
- do_listing(Big, TargetDir, 'P'),
- do_listing(Big, TargetDir, dkern, ".kernel"),
- do_listing(Big, TargetDir, to_dis, ".dis"),
-
- TargetNoext = filename:rootname(Target, code:objfile_extension()),
- {ok,big} = compile:file(TargetNoext, [from_asm,{outdir,TargetDir}]),
-
- %% Cleanup.
- ok = file:delete(Target),
- lists:foreach(fun(F) -> ok = file:delete(F) end,
- filelib:wildcard(filename:join(TargetDir, "*"))),
- ok = file:del_dir(TargetDir),
- ok.
+ List = [{'S',".S"},
+ {'E',".E"},
+ {'P',".P"},
+ {dkern, ".kernel"},
+ {dssa, ".ssa"},
+ {dssaopt, ".ssaopt"},
+ {dprecg, ".precodegen"},
+ {to_dis, ".dis"}],
+ p_listings(List, Big, TargetDir).
+
+p_listings(List, File, BaseDir) ->
+ Run = fun({Option,Extension}) ->
+ Uniq = erlang:unique_integer([positive]),
+ Dir = filename:join(BaseDir, integer_to_list(Uniq)),
+ ok = file:make_dir(Dir),
+ try
+ do_listing(File, Dir, Option, Extension),
+ ok
+ catch
+ Class:Error:Stk ->
+ io:format("~p:~p\n~p\n", [Class,Error,Stk]),
+ error
+ after
+ _ = [ok = file:delete(F) ||
+ F <- filelib:wildcard(filename:join(Dir, "*"))],
+ ok = file:del_dir(Dir)
+ end
+ end,
+ test_lib:p_run(Run, List).
other_output(Config) when is_list(Config) ->
{Simple,_Target} = get_files(Config, simple, "other_output"),
@@ -500,9 +500,8 @@ do_kernel_listing({M,A}) ->
io:format("*** compilation failure '~p' for module ~s\n",
[Error,M]),
error;
- Class:Error ->
- io:format("~p: ~p ~p\n~p\n",
- [M,Class,Error,erlang:get_stacktrace()]),
+ Class:Error:Stk ->
+ io:format("~p: ~p ~p\n~p\n", [M,Class,Error,Stk]),
error
end.
@@ -661,13 +660,27 @@ custom_debug_info(Config) when is_list(Config) ->
{ok,{simple,[{debug_info,{debug_info_v1,?MODULE,error}}]}} =
beam_lib:chunks(ErrorBin, [debug_info]).
+custom_compile_info(Config) when is_list(Config) ->
+ Anno = erl_anno:new(1),
+ Forms = [{attribute,Anno,module,custom_compile_info}],
+ Opts = [binary,{compile_info,[{another,version}]}],
+
+ {ok,custom_compile_info,Bin} = compile:forms(Forms, Opts),
+ {ok,{custom_compile_info,[{compile_info,CompileInfo}]}} =
+ beam_lib:chunks(Bin, [compile_info]),
+ version = proplists:get_value(another, CompileInfo),
+ CompileOpts = proplists:get_value(options, CompileInfo),
+ undefined = proplists:get_value(compile_info, CompileOpts),
+
+ {ok,custom_compile_info,DetBin} = compile:forms(Forms, [deterministic|Opts]),
+ {ok,{custom_compile_info,[{compile_info,DetInfo}]}} =
+ beam_lib:chunks(DetBin, [compile_info]),
+ version = proplists:get_value(another, DetInfo).
+
cover(Config) when is_list(Config) ->
io:format("~p\n", [compile:options()]),
ok.
-do_listing(Source, TargetDir, Type) ->
- do_listing(Source, TargetDir, Type, "." ++ atom_to_list(Type)).
-
do_listing(Source, TargetDir, Type, Ext) ->
io:format("Source: ~p TargetDir: ~p\n Type: ~p Ext: ~p\n",
[Source, TargetDir, Type, Ext]),
@@ -793,6 +806,37 @@ extra_chunks(Config) when is_list(Config) ->
{ok,{extra_chunks,[{"ExCh",<<"Contents">>}]}} =
beam_lib:chunks(ExtraChunksBinary, ["ExCh"]).
+tuple_calls(Config) when is_list(Config) ->
+ Anno = erl_anno:new(1),
+ Forms = [{attribute,Anno,export,[{size,1},{store,1}]},
+ {function,Anno,size,1,
+ [{clause,Anno,[{var,[],mod}],[],
+ [{call,[],{remote,[],{var,[],mod},{atom,[],size}},[]}]}]},
+ {function,Anno,store,1,
+ [{clause,Anno,[{var,[],mod}],[],
+ [{call,[],{remote,[],{var,[],mod},{atom,[],store}},[{atom,[],key},{atom,[],value}]}]}]}],
+
+ TupleCallsFalse = [{attribute,Anno,module,tuple_calls_false}|Forms],
+ {ok,_,TupleCallsFalseBinary} = compile:forms(TupleCallsFalse, [binary]),
+ code:load_binary(tuple_calls_false, "compile_SUITE.erl", TupleCallsFalseBinary),
+ {'EXIT',{badarg,_}} = (catch tuple_calls_false:store(dict())),
+ {'EXIT',{badarg,_}} = (catch tuple_calls_false:size(dict())),
+ {'EXIT',{badarg,_}} = (catch tuple_calls_false:size(empty_tuple())),
+
+ TupleCallsTrue = [{attribute,Anno,module,tuple_calls_true}|Forms],
+ {ok,_,TupleCallsTrueBinary} = compile:forms(TupleCallsTrue, [binary,tuple_calls]),
+ code:load_binary(tuple_calls_true, "compile_SUITE.erl", TupleCallsTrueBinary),
+ Dict = tuple_calls_true:store(dict()),
+ 1 = tuple_calls_true:size(Dict),
+ {'EXIT',{badarg,_}} = (catch tuple_calls_true:size(empty_tuple())),
+
+ ok.
+
+dict() ->
+ dict:new().
+empty_tuple() ->
+ {}.
+
env(Config) when is_list(Config) ->
{Simple,Target} = get_files(Config, simple, env),
{ok,Cwd} = file:get_cwd(),
@@ -854,9 +898,8 @@ do_core_pp({M,A}, Outdir) ->
io:format("*** compilation failure '~p' for module ~s\n",
[Error,M]),
error;
- Class:Error ->
- io:format("~p: ~p ~p\n~p\n",
- [M,Class,Error,erlang:get_stacktrace()]),
+ Class:Error:Stk ->
+ io:format("~p: ~p ~p\n~p\n", [M,Class,Error,Stk]),
error
end.
@@ -874,7 +917,7 @@ do_core_pp_1(M, A, Outdir) ->
ok = file:delete(CoreFile),
%% Compile as usual (including optimizations).
- compile_forms(M, Core, [clint,from_core,binary]),
+ compile_forms(M, Core, [clint,ssalint,from_core,binary]),
%% Don't optimize to test that we are not dependent
%% on the Core Erlang optmimization passes.
@@ -883,7 +926,7 @@ do_core_pp_1(M, A, Outdir) ->
%% records; if sys_core_fold was run it would fix
%% that; if sys_core_fold was not run v3_kernel would
%% crash.)
- compile_forms(M, Core, [clint,from_core,no_copt,binary]),
+ compile_forms(M, Core, [clint,ssalint,from_core,no_copt,binary]),
ok.
@@ -913,9 +956,8 @@ do_core_roundtrip(Beam, Outdir) ->
io:format("*** compilation failure '~p' for file ~s\n",
[Error,Beam]),
error;
- Class:Error ->
- io:format("~p: ~p ~p\n~p\n",
- [Beam,Class,Error,erlang:get_stacktrace()]),
+ Class:Error:Stk ->
+ io:format("~p: ~p ~p\n~p\n", [Beam,Class,Error,Stk]),
error
end.
@@ -1066,10 +1108,30 @@ remove_compiler_gen(M) ->
remove_compiler_gen_1(Pair) ->
Op0 = cerl:map_pair_op(Pair),
Op = cerl:set_ann(Op0, []),
- K = cerl:map_pair_key(Pair),
- V = cerl:map_pair_val(Pair),
+ K = map_var(cerl:map_pair_key(Pair)),
+ V = map_var(cerl:map_pair_val(Pair)),
cerl:update_c_map_pair(Pair, Op, K, V).
+map_var(Var) ->
+ case cerl:is_c_var(Var) of
+ true ->
+ case cerl:var_name(Var) of
+ Name when is_atom(Name) ->
+ L = atom_to_list(Name),
+ try list_to_integer(L) of
+ Int ->
+ cerl:update_c_var(Var, Int)
+ catch
+ error:_ ->
+ Var
+ end;
+ _ ->
+ Var
+ end;
+ false ->
+ Var
+ end.
+
%% Compile to Beam assembly language (.S) and then try to
%% run .S through the compiler again.
@@ -1100,102 +1162,11 @@ do_asm(Beam, Outdir) ->
[Other,AsmFile]),
error
end
- catch Class:Error ->
- io:format("~p: ~p ~p\n~p\n",
- [M,Class,Error,erlang:get_stacktrace()]),
+ catch Class:Error:Stk ->
+ io:format("~p: ~p ~p\n~p\n", [M,Class,Error,Stk]),
error
end.
-%% Make sure that guards are fully optimized. Guards should
-%% should use 'test' instructions, not 'bif' instructions.
-
-optimized_guards(_Config) ->
- TestBeams = get_unique_beam_files(),
- test_lib:p_run(fun(F) -> do_opt_guards(F) end, TestBeams).
-
-do_opt_guards(Beam) ->
- {ok,{M,[{abstract_code,{raw_abstract_v1,A}}]}} =
- beam_lib:chunks(Beam, [abstract_code]),
- try
- {ok,M,Asm} = compile:forms(A, ['S']),
- do_opt_guards_mod(Asm)
- catch Class:Error ->
- io:format("~p: ~p ~p\n~p\n",
- [M,Class,Error,erlang:get_stacktrace()]),
- error
- end.
-
-do_opt_guards_mod({Mod,_Exp,_Attr,Asm,_NumLabels}) ->
- case do_opt_guards_fs(Mod, Asm) of
- [] ->
- ok;
- [_|_]=Bifs ->
- io:format("ERRORS FOR ~p:\n~p\n", [Mod,Bifs]),
- error
- end.
-
-do_opt_guards_fs(Mod, [{function,Name,Arity,_,Is}|Fs]) ->
- Bifs0 = do_opt_guards_fun(Is),
-
- %% The compiler does not attempt to optimize 'xor'.
- %% Therefore, ignore all functions that use 'xor' in
- %% a guard.
- Bifs = case lists:any(fun({bif,'xor',_,_,_}) -> true;
- (_) -> false
- end, Bifs0) of
- true -> [];
- false -> Bifs0
- end,
-
- %% Filter out the allowed exceptions.
- FA = {Name,Arity},
- case {Bifs,is_exception(Mod, FA)} of
- {[_|_],true} ->
- io:format("~p:~p/~p IGNORED:\n~p\n",
- [Mod,Name,Arity,Bifs]),
- do_opt_guards_fs(Mod, Fs);
- {[_|_],false} ->
- [{FA,Bifs}|do_opt_guards_fs(Mod, Fs)];
- {[],false} ->
- do_opt_guards_fs(Mod, Fs);
- {[],true} ->
- io:format("Redundant exception for ~p:~p/~p\n",
- [Mod,Name,Arity]),
- error(redundant)
- end;
-do_opt_guards_fs(_, []) -> [].
-
-do_opt_guards_fun([{bif,Name,{f,F},As,_}=I|Is]) when F =/= 0 ->
- Arity = length(As),
- case erl_internal:comp_op(Name, Arity) orelse
- erl_internal:bool_op(Name, Arity) orelse
- erl_internal:new_type_test(Name, Arity) of
- true ->
- [I|do_opt_guards_fun(Is)];
- false ->
- do_opt_guards_fun(Is)
- end;
-do_opt_guards_fun([_|Is]) ->
- do_opt_guards_fun(Is);
-do_opt_guards_fun([]) -> [].
-
-is_exception(bs_match_SUITE, {matching_and_andalso_2,2}) -> true;
-is_exception(bs_match_SUITE, {matching_and_andalso_3,2}) -> true;
-is_exception(guard_SUITE, {'-complex_not/1-fun-4-',1}) -> true;
-is_exception(guard_SUITE, {'-complex_not/1-fun-5-',1}) -> true;
-is_exception(guard_SUITE, {basic_andalso_orelse,1}) -> true;
-is_exception(guard_SUITE, {bad_guards,1}) -> true;
-is_exception(guard_SUITE, {bad_guards_2,2}) -> true;
-is_exception(guard_SUITE, {bad_guards_3,2}) -> true;
-is_exception(guard_SUITE, {cqlc,4}) -> true;
-is_exception(guard_SUITE, {csemi7,3}) -> true;
-is_exception(guard_SUITE, {misc,1}) -> true;
-is_exception(guard_SUITE, {nested_not_2b,4}) -> true;
-is_exception(guard_SUITE, {tricky_1,2}) -> true;
-is_exception(map_SUITE, {map_guard_update,2}) -> true;
-is_exception(map_SUITE, {map_guard_update_variables,3}) -> true;
-is_exception(_, _) -> false.
-
sys_pre_attributes(Config) ->
DataDir = proplists:get_value(data_dir, Config),
File = filename:join(DataDir, "attributes.erl"),
@@ -1282,10 +1253,13 @@ do_warnings_2([], Next, F) ->
%% pre-loads the modules that are used by a typical compilation.
pre_load_check(Config) ->
- case test_server:is_cover() of
- true ->
+ case {test_server:is_cover(),code:module_info(native)} of
+ {true,_} ->
{skip,"Cover is running"};
- false ->
+ {false,true} ->
+ %% Tracing won't work.
+ {skip,"'code' is native-compiled"};
+ {false,false} ->
try
do_pre_load_check(Config)
after
@@ -1409,41 +1383,96 @@ env_compiler_options(_Config) ->
bc_options(Config) ->
DataDir = proplists:get_value(data_dir, Config),
- 101 = highest_opcode(DataDir, small_float, [no_line_info]),
+ L = [{101, small_float, [no_get_hd_tl,no_line_info]},
+ {103, big, [no_put_tuple2,no_get_hd_tl,no_ssa_opt_record,
+ no_line_info,no_stack_trimming]},
+ {125, small_float, [no_get_hd_tl,no_line_info,no_ssa_opt_float]},
+
+ {132, small, [no_put_tuple2,no_get_hd_tl,no_ssa_opt_record,
+ no_ssa_opt_float,no_line_info,no_bsm3]},
+
+ {153, small, [r20]},
+ {153, small, [r21]},
+
+ {136, big, [no_put_tuple2,no_get_hd_tl,
+ no_ssa_opt_record,no_line_info]},
+
+ {153, big, [no_put_tuple2,no_get_hd_tl, no_ssa_opt_record]},
+ {153, big, [r16]},
+ {153, big, [r17]},
+ {153, big, [r18]},
+ {153, big, [r19]},
+ {153, small_float, [r16]},
+ {153, small_float, []},
+
+ {158, small_maps, [r17]},
+ {158, small_maps, [r18]},
+ {158, small_maps, [r19]},
+ {158, small_maps, [r20]},
+ {158, small_maps, [r21]},
+
+ {164, small_maps, []},
+ {164, big, []}
+ ],
+
+ Test = fun({Expected,Mod,Options}) ->
+ case highest_opcode(DataDir, Mod, Options) of
+ Expected ->
+ ok;
+ Got ->
+ io:format("*** module ~p, options ~p => got ~p; expected ~p\n",
+ [Mod,Options,Got,Expected]),
+ error
+ end
+ end,
+ test_lib:p_run(Test, L),
+ ok.
- 103 = highest_opcode(DataDir, big,
- [no_record_opt,no_line_info,no_stack_trimming]),
+highest_opcode(DataDir, Mod, Opt) ->
+ Src = filename:join(DataDir, atom_to_list(Mod)++".erl"),
+ {ok,Mod,Beam} = compile:file(Src, [binary|Opt]),
+ test_lib:highest_opcode(Beam).
- 125 = highest_opcode(DataDir, small_float, [no_line_info,no_float_opt]),
+deterministic_include(Config) when is_list(Config) ->
+ DataDir = proplists:get_value(data_dir, Config),
+ Simple = filename:join(DataDir, "simple"),
+
+ %% Files without +deterministic should differ if their include paths do,
+ %% as their debug info will be different.
+ {ok,_,NonDetA} = compile:file(Simple, [binary, {i,"gurka"}]),
+ {ok,_,NonDetB} = compile:file(Simple, [binary, {i,"gaffel"}]),
+ true = NonDetA =/= NonDetB,
- 132 = highest_opcode(DataDir, small,
- [no_record_opt,no_float_opt,no_line_info]),
+ %% ... but files with +deterministic shouldn't.
+ {ok,_,DetC} = compile:file(Simple, [binary, deterministic, {i,"gurka"}]),
+ {ok,_,DetD} = compile:file(Simple, [binary, deterministic, {i,"gaffel"}]),
+ true = DetC =:= DetD,
- 136 = highest_opcode(DataDir, big, [no_record_opt,no_line_info]),
+ ok.
- 153 = highest_opcode(DataDir, big, [no_record_opt]),
- 153 = highest_opcode(DataDir, big, [r16]),
- 153 = highest_opcode(DataDir, big, [r17]),
- 153 = highest_opcode(DataDir, big, [r18]),
- 153 = highest_opcode(DataDir, big, [r19]),
- 153 = highest_opcode(DataDir, small_float, [r16]),
- 153 = highest_opcode(DataDir, small_float, []),
+deterministic_paths(Config) when is_list(Config) ->
+ DataDir = proplists:get_value(data_dir, Config),
- 158 = highest_opcode(DataDir, small_maps, [r17]),
- 158 = highest_opcode(DataDir, small_maps, [r18]),
- 158 = highest_opcode(DataDir, small_maps, [r19]),
- 158 = highest_opcode(DataDir, small_maps, []),
+ %% Files without +deterministic should differ if they were compiled from a
+ %% different directory.
+ true = deterministic_paths_1(DataDir, "simple", []),
- 159 = highest_opcode(DataDir, big, []),
+ %% ... but files with +deterministic shouldn't.
+ false = deterministic_paths_1(DataDir, "simple", [deterministic]),
ok.
-highest_opcode(DataDir, Mod, Opt) ->
- Src = filename:join(DataDir, atom_to_list(Mod)++".erl"),
- {ok,Mod,Beam} = compile:file(Src, [binary|Opt]),
- {ok,{Mod,[{"Code",Code}]}} = beam_lib:chunks(Beam, ["Code"]),
- <<16:32,0:32,HighestOpcode:32,_/binary>> = Code,
- HighestOpcode.
+deterministic_paths_1(DataDir, Name, Opts) ->
+ Simple = filename:join(DataDir, "simple"),
+ {ok, Cwd} = file:get_cwd(),
+ try
+ {ok,_,A} = compile:file(Simple, [binary | Opts]),
+ ok = file:set_cwd(DataDir),
+ {ok,_,B} = compile:file(Name, [binary | Opts]),
+ A =/= B
+ after
+ file:set_cwd(Cwd)
+ end.
%%%
%%% Utilities.
diff --git a/lib/compiler/test/compile_SUITE_data/big.erl b/lib/compiler/test/compile_SUITE_data/big.erl
index 2e54ee8660..765c71c07d 100644
--- a/lib/compiler/test/compile_SUITE_data/big.erl
+++ b/lib/compiler/test/compile_SUITE_data/big.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -741,3 +741,7 @@ snmp_access(suite) ->
debug_support(suite) ->
[ info, schema, schema, kill, lkill ].
+%% Cover translation of get_hd/2 to get_list/3 when option no_get_hd_tl
+%% is given.
+cover_get_hd([Hd|_]) ->
+ Hd.
diff --git a/lib/compiler/test/compiler.cover b/lib/compiler/test/compiler.cover
index 3fd7fc1937..fac0f9947c 100644
--- a/lib/compiler/test/compiler.cover
+++ b/lib/compiler/test/compiler.cover
@@ -1,5 +1,4 @@
-{incl_app,compiler,details}.
-
%% -*- erlang -*-
+{local_only,compiler,true}.
+{incl_app,compiler,details}.
{excl_mods,compiler,[core_scan,core_parse]}.
-
diff --git a/lib/compiler/test/core_SUITE.erl b/lib/compiler/test/core_SUITE.erl
index 0e07e8dd2e..e5611e99d1 100644
--- a/lib/compiler/test/core_SUITE.erl
+++ b/lib/compiler/test/core_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@
bs_shadowed_size_var/1,
cover_v3_kernel_1/1,cover_v3_kernel_2/1,cover_v3_kernel_3/1,
cover_v3_kernel_4/1,cover_v3_kernel_5/1,
- non_variable_apply/1]).
+ non_variable_apply/1,name_capture/1,fun_letrec_effect/1]).
-include_lib("common_test/include/ct.hrl").
@@ -47,7 +47,6 @@ suite() ->
{timetrap,{minutes,5}}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -58,11 +57,12 @@ groups() ->
bs_shadowed_size_var,
cover_v3_kernel_1,cover_v3_kernel_2,cover_v3_kernel_3,
cover_v3_kernel_4,cover_v3_kernel_5,
- non_variable_apply
+ non_variable_apply,name_capture,fun_letrec_effect
]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -93,6 +93,8 @@ end_per_group(_GroupName, Config) ->
?comp(cover_v3_kernel_4).
?comp(cover_v3_kernel_5).
?comp(non_variable_apply).
+?comp(name_capture).
+?comp(fun_letrec_effect).
try_it(Mod, Conf) ->
Src = filename:join(proplists:get_value(data_dir, Conf),
diff --git a/lib/compiler/test/core_SUITE_data/fun_letrec_effect.core b/lib/compiler/test/core_SUITE_data/fun_letrec_effect.core
new file mode 100644
index 0000000000..ab6f5b7940
--- /dev/null
+++ b/lib/compiler/test/core_SUITE_data/fun_letrec_effect.core
@@ -0,0 +1,25 @@
+module 'fun_letrec_effect' ['fun_letrec_effect'/0, 'ok'/0, 'wat'/0]
+attributes []
+
+'fun_letrec_effect'/0 =
+ fun () ->
+ do apply 'wat'/0()
+ receive
+ <'bar'> when 'true' -> 'ok'
+ <_0> when 'true' -> 'failed'
+ after 'infinity' ->
+ 'true'
+
+%% The return value (bar) of the fun was optimized away because the result of
+%% the `letrec ... in` was unused, despite the fun's return value being
+%% relevant for the side-effect of the expression.
+'wat'/0 =
+ fun () ->
+ let <Self> = call 'erlang':'self'() in
+ do letrec 'f'/0 = fun () ->
+ do call 'maps':'put'('foo', 'bar', ~{}~)
+ 'bar'
+ in call 'erlang':'send'(Self, apply 'f'/0())
+ 'undefined'
+
+end
diff --git a/lib/compiler/test/core_SUITE_data/name_capture.core b/lib/compiler/test/core_SUITE_data/name_capture.core
new file mode 100644
index 0000000000..0969f95b72
--- /dev/null
+++ b/lib/compiler/test/core_SUITE_data/name_capture.core
@@ -0,0 +1,110 @@
+module 'name_capture' ['module_info'/0,
+ 'module_info'/1,
+ 'name_capture'/0]
+ attributes ['compile' =
+ [{'inline',[{'badarg_exit',2}]}]]
+'name_capture'/0 =
+ fun () ->
+ case <> of
+ <> when 'true' ->
+ let <_0> =
+ catch
+ apply 'first'/1
+ ('badarg')
+ in case _0 of
+ <{'EXIT',{'badarg',_7}}> when 'true' ->
+ let <Seq> =
+ call 'lists':'seq'
+ (7, 17)
+ in case apply 'first'/1
+ ({'ok',Seq}) of
+ <_8>
+ when call 'erlang':'=:='
+ (_8,
+ Seq) ->
+ let <SomeOtherTerm> =
+ {'some','other','term'}
+ in let <_5> =
+ catch
+ apply 'first'/1
+ (SomeOtherTerm)
+ in case _5 of
+ <{'EXIT',_9}>
+ when call 'erlang':'=:='
+ (_9,
+ SomeOtherTerm) ->
+ 'ok'
+ <_6> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_6})
+ end
+ <_3> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_3})
+ end
+ <_1> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_1})
+ end
+ <> when 'true' ->
+ primop 'match_fail'
+ ({'function_clause'})
+ end
+'first'/1 =
+ fun (_0) ->
+ case _0 of
+ <Tab> when 'true' ->
+ let <_1> =
+ apply 'treq'/2
+ (Tab, 'first')
+ %% The _1 variable in the `let` must be renamed
+ %% to avoid a name capture problem.
+ in let <_0,_1> =
+ <_1,[Tab|[]]>
+ in case <_0,_1> of
+ <'badarg',A> when 'true' ->
+ call 'erlang':'error'
+ ('badarg', A)
+ <{'ok',Reply},_X_A> when 'true' ->
+ Reply
+ <Reply,_X_A> when 'true' ->
+ call 'erlang':'exit'
+ (Reply)
+ <_3,_2> when 'true' ->
+ primop 'match_fail'
+ ({'function_clause',_3,_2})
+ end
+ <_2> when 'true' ->
+ primop 'match_fail'
+ ({'function_clause',_2})
+ end
+'treq'/2 =
+ fun (_0,_1) ->
+ case <_0,_1> of
+ <Action,_4> when 'true' ->
+ Action
+ <_3,_2> when 'true' ->
+ primop 'match_fail'
+ ({'function_clause',_3,_2})
+ end
+'module_info'/0 =
+ fun () ->
+ case <> of
+ <> when 'true' ->
+ call 'erlang':'get_module_info'
+ ('name_capture')
+ <> when 'true' ->
+ primop 'match_fail'
+ ({'function_clause'})
+ end
+'module_info'/1 =
+ fun (_0) ->
+ case _0 of
+ <X> when 'true' ->
+ call 'erlang':'get_module_info'
+ ('name_capture', X)
+ <_1> when 'true' ->
+ primop 'match_fail'
+ ({'function_clause',_1})
+ end
+end
diff --git a/lib/compiler/test/core_alias_SUITE.erl b/lib/compiler/test/core_alias_SUITE.erl
new file mode 100644
index 0000000000..737b1567d4
--- /dev/null
+++ b/lib/compiler/test/core_alias_SUITE.erl
@@ -0,0 +1,195 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(core_alias_SUITE).
+
+-export([all/0, suite/0, groups/0,init_per_suite/1, end_per_suite/1,
+ init_per_group/2, end_per_group/2,
+ tuples/1, cons/1]).
+
+-include_lib("common_test/include/ct.hrl").
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [{group,p}].
+
+groups() ->
+ [{p,[parallel],
+ [tuples, cons]}].
+
+init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+
+id(X) -> X.
+
+tuples(Config) when is_list(Config) ->
+ Tuple = {ok,id(value)},
+
+ true = erts_debug:same(Tuple, simple_tuple(Tuple)),
+ true = erts_debug:same(Tuple, simple_tuple_in_map(#{hello => Tuple})),
+ true = erts_debug:same(Tuple, simple_tuple_case_repeated(Tuple, Tuple)),
+ true = erts_debug:same(Tuple, simple_tuple_fun_repeated(Tuple, Tuple)),
+ true = erts_debug:same(Tuple, simple_tuple_twice_head(Tuple, Tuple)),
+
+ {Tuple1, Tuple2} = simple_tuple_twice_body(Tuple),
+ true = erts_debug:same(Tuple, Tuple1),
+ true = erts_debug:same(Tuple, Tuple2),
+
+ Nested = {nested,Tuple},
+ true = erts_debug:same(Tuple, nested_tuple_part(Nested)),
+ true = erts_debug:same(Nested, nested_tuple_whole(Nested)),
+ true = erts_debug:same(Nested, nested_tuple_with_alias(Nested)),
+
+ true = erts_debug:same(Tuple, tuple_rebinding_after(Tuple)),
+
+ Tuple = unaliased_tuple_rebinding_before(Tuple),
+ false = erts_debug:same(Tuple, unaliased_tuple_rebinding_before(Tuple)),
+ Nested = unaliased_literal_tuple_head(Nested),
+ false = erts_debug:same(Nested, unaliased_literal_tuple_head(Nested)),
+ Nested = unaliased_literal_tuple_body(Nested),
+ false = erts_debug:same(Nested, unaliased_literal_tuple_body(Nested)),
+ Nested = unaliased_different_var_tuple(Nested, Tuple),
+ false = erts_debug:same(Nested, unaliased_different_var_tuple(Nested, Tuple)).
+
+simple_tuple({ok,X}) ->
+ {ok,X}.
+simple_tuple_twice_head({ok,X}, {ok,X}) ->
+ {ok,X}.
+simple_tuple_twice_body({ok,X}) ->
+ {{ok,X},{ok,X}}.
+simple_tuple_in_map(#{hello := {ok,X}}) ->
+ {ok,X}.
+simple_tuple_fun_repeated({ok,X}, Y) ->
+ io:format("~p~n", [X]),
+ (fun({ok,X}) -> {ok,X} end)(Y).
+simple_tuple_case_repeated({ok,X}, Y) ->
+ io:format("~p~n", [X]),
+ case Y of {ok,X} -> {ok,X} end.
+
+nested_tuple_part({nested,{ok,X}}) ->
+ {ok,X}.
+nested_tuple_whole({nested,{ok,X}}) ->
+ {nested,{ok,X}}.
+nested_tuple_with_alias({nested,{ok,_}=Y}) ->
+ {nested,Y}.
+
+tuple_rebinding_after(Y) ->
+ (fun(X) -> {ok,X} end)(Y),
+ case Y of {ok,X} -> {ok,X} end.
+unaliased_tuple_rebinding_before({ok,X}) ->
+ io:format("~p~n", [X]),
+ (fun(X) -> {ok,X} end)(value).
+unaliased_literal_tuple_head({nested,{ok,value}=X}) ->
+ io:format("~p~n", [X]),
+ {nested,{ok,value}}.
+unaliased_literal_tuple_body({nested,{ok,value}=X}) ->
+ Res = {nested,Y={ok,value}},
+ io:format("~p~n", [[X,Y]]),
+ Res.
+unaliased_different_var_tuple({nested,{ok,value}=X}, Y) ->
+ io:format("~p~n", [X]),
+ {nested,Y}.
+
+cons(Config) when is_list(Config) ->
+ Cons = [ok|id(value)],
+
+ true = erts_debug:same(Cons, simple_cons(Cons)),
+ true = erts_debug:same(Cons, simple_cons_in_map(#{hello => Cons})),
+ true = erts_debug:same(Cons, simple_cons_case_repeated(Cons, Cons)),
+ true = erts_debug:same(Cons, simple_cons_fun_repeated(Cons, Cons)),
+ true = erts_debug:same(Cons, simple_cons_twice_head(Cons, Cons)),
+
+ {Cons1,Cons2} = simple_cons_twice_body(Cons),
+ true = erts_debug:same(Cons, Cons1),
+ true = erts_debug:same(Cons, Cons2),
+
+ Nested = [nested,Cons],
+ true = erts_debug:same(Cons, nested_cons_part(Nested)),
+ true = erts_debug:same(Nested, nested_cons_whole(Nested)),
+ true = erts_debug:same(Nested, nested_cons_with_alias(Nested)),
+ true = erts_debug:same(Cons, cons_rebinding_after(Cons)),
+
+ Unstripped = id([a,b]),
+ Stripped = cons_with_binary([<<>>|Unstripped]),
+ true = erts_debug:same(Unstripped, Stripped),
+
+ Cons = unaliased_cons_rebinding_before(Cons),
+ false = erts_debug:same(Cons, unaliased_cons_rebinding_before(Cons)),
+ Nested = unaliased_literal_cons_head(Nested),
+ false = erts_debug:same(Nested, unaliased_literal_cons_head(Nested)),
+ Nested = unaliased_literal_cons_body(Nested),
+ false = erts_debug:same(Nested, unaliased_literal_cons_body(Nested)),
+ Nested = unaliased_different_var_cons(Nested, Cons),
+ false = erts_debug:same(Nested, unaliased_different_var_cons(Nested, Cons)).
+
+simple_cons([ok|X]) ->
+ [ok|X].
+simple_cons_twice_head([ok|X], [ok|X]) ->
+ [ok|X].
+simple_cons_twice_body([ok|X]) ->
+ {[ok|X],[ok|X]}.
+simple_cons_in_map(#{hello := [ok|X]}) ->
+ [ok|X].
+simple_cons_fun_repeated([ok|X], Y) ->
+ io:format("~p~n", [X]),
+ (fun([ok|X]) -> [ok|X] end)(Y).
+simple_cons_case_repeated([ok|X], Y) ->
+ io:format("~p~n", [X]),
+ case Y of [ok|X] -> [ok|X] end.
+
+nested_cons_part([nested,[ok|X]]) ->
+ [ok|X].
+nested_cons_whole([nested,[ok|X]]) ->
+ [nested,[ok|X]].
+nested_cons_with_alias([nested,[ok|_]=Y]) ->
+ [nested,Y].
+
+cons_with_binary([<<>>,X|Y]) ->
+ cons_with_binary([X|Y]);
+cons_with_binary(A) ->
+ A.
+
+cons_rebinding_after(Y) ->
+ (fun(X) -> [ok|X] end)(Y),
+ case Y of [ok|X] -> [ok|X] end.
+unaliased_cons_rebinding_before([ok|X]) ->
+ io:format("~p~n", [X]),
+ (fun(X) -> [ok|X] end)(value).
+unaliased_literal_cons_head([nested,[ok|value]=X]) ->
+ io:format("~p~n", [X]),
+ [nested,[ok|value]].
+unaliased_literal_cons_body([nested,[ok|value]=X]) ->
+ Res = [nested,Y=[ok|value]],
+ io:format("~p~n", [[X, Y]]),
+ Res.
+unaliased_different_var_cons([nested,[ok|value]=X], Y) ->
+ io:format("~p~n", [X]),
+ [nested,Y].
diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl
index 0097e28d4d..adfebd5158 100644
--- a/lib/compiler/test/core_fold_SUITE.erl
+++ b/lib/compiler/test/core_fold_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,7 +26,9 @@
unused_multiple_values_error/1,unused_multiple_values/1,
multiple_aliases/1,redundant_boolean_clauses/1,
mixed_matching_clauses/1,unnecessary_building/1,
- no_no_file/1,configuration/1,supplies/1]).
+ no_no_file/1,configuration/1,supplies/1,
+ redundant_stack_frame/1,export_from_case/1,
+ empty_values/1,cover_letrec_effect/1]).
-export([foo/0,foo/1,foo/2,foo/3]).
@@ -35,7 +37,6 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -45,10 +46,13 @@ groups() ->
unused_multiple_values_error,unused_multiple_values,
multiple_aliases,redundant_boolean_clauses,
mixed_matching_clauses,unnecessary_building,
- no_no_file,configuration,supplies]}].
+ no_no_file,configuration,supplies,
+ redundant_stack_frame,export_from_case,
+ empty_values,cover_letrec_effect]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -208,9 +212,14 @@ bifs(Config) when is_list(Config) ->
{ok,#{K:=V}} = id(list_to_tuple([ok,#{K=>V}])),
ok.
--define(CMP_SAME(A0, B), (fun(A) -> true = A == B, false = A /= B end)(id(A0))).
--define(CMP_DIFF(A0, B), (fun(A) -> false = A == B, true = A /= B end)(id(A0))).
-
+-define(CMP_SAME0(A0, B), (fun(A) -> true = A == B, false = A /= B end)(id(A0))).
+-define(CMP_SAME1(A0, B), (fun(A) -> false = A /= B, true = A == B end)(id(A0))).
+-define(CMP_SAME(A0, B), (true = ?CMP_SAME0(A0, B) =:= not ?CMP_SAME1(A0, B))).
+
+-define(CMP_DIFF0(A0, B), (fun(A) -> false = A == B, true = A /= B end)(id(A0))).
+-define(CMP_DIFF1(A0, B), (fun(A) -> true = A /= B, false = A == B end)(id(A0))).
+-define(CMP_DIFF(A0, B), (true = ?CMP_DIFF0(A0, B) =:= not ?CMP_DIFF1(A0, B))).
+
eq(Config) when is_list(Config) ->
?CMP_SAME([a,b,c], [a,b,c]),
?CMP_SAME([42.0], [42.0]),
@@ -274,6 +283,8 @@ coverage(Config) when is_list(Config) ->
a = cover_remove_non_vars_alias({a,b,c}),
error = cover_will_match_lit_list(),
{ok,[a]} = cover_is_safe_bool_expr(a),
+ false = cover_is_safe_bool_expr2(a),
+ ok = cover_eval_is_function(fun id/1),
ok = cover_opt_guard_try(#cover_opt_guard_try{list=[a]}),
error = cover_opt_guard_try(#cover_opt_guard_try{list=[]}),
@@ -337,6 +348,15 @@ cover_is_safe_bool_expr(X) ->
false
end.
+cover_is_safe_bool_expr2(X) ->
+ try
+ V = [X],
+ is_function(V, 1)
+ catch
+ _:_ ->
+ false
+ end.
+
cover_opt_guard_try(Msg) ->
if
length(Msg#cover_opt_guard_try.list) =/= 1 ->
@@ -345,6 +365,12 @@ cover_opt_guard_try(Msg) ->
ok
end.
+cover_eval_is_function(X) ->
+ case X of
+ {a,_} -> is_function(X);
+ _ -> ok
+ end.
+
bsm_an_inlined(<<_:8>>, _) -> ok;
bsm_an_inlined(_, _) -> error.
@@ -352,7 +378,7 @@ unused_multiple_values_error(Config) when is_list(Config) ->
PrivDir = proplists:get_value(priv_dir, Config),
Dir = test_lib:get_data_dir(Config),
Core = filename:join(Dir, "unused_multiple_values_error"),
- Opts = [no_copt,clint,return,from_core,{outdir,PrivDir}
+ Opts = [no_copt,clint,ssalint,return,from_core,{outdir,PrivDir}
|test_lib:opt_opts(?MODULE)],
{error,[{unused_multiple_values_error,
[{none,core_lint,{return_mismatch,{hello,1}}}]}],
@@ -476,7 +502,7 @@ source(true, Activities) ->
Activities
end.
-tim(#{reduction := Emergency}) ->
+tim(#{reduction := _Emergency}) ->
try
fun() -> surgery end
catch
@@ -527,4 +553,92 @@ supplies(_Config) ->
do_supplies(#{1 := Value}) when byte_size(Value), byte_size(kg) -> working.
+redundant_stack_frame(_Config) ->
+ {1,2} = do_redundant_stack_frame(#{x=>1,y=>2}),
+ {'EXIT',{{badkey,_,x},_}} = (catch do_redundant_stack_frame(#{y=>2})),
+ {'EXIT',{{badkey,_,y},_}} = (catch do_redundant_stack_frame(#{x=>1})),
+ ok.
+
+do_redundant_stack_frame(Map) ->
+ %% There should not be a stack frame for this function.
+ X = case Map of
+ #{x := X0} ->
+ X0;
+ #{} ->
+ erlang:error({badkey, Map, x})
+ end,
+ Y = case Map of
+ #{y := Y0} ->
+ Y0;
+ #{} ->
+ erlang:error({badkey, Map, y})
+ end,
+ {X, Y}.
+
+%% Cover some clauses in sys_core_fold:remove_first_value/2.
+
+-record(export_from_case, {val}).
+
+export_from_case(_Config) ->
+ a = export_from_case_1(true),
+ b = export_from_case_1(false),
+
+ R = #export_from_case{val=0},
+ {ok,R} = export_from_case_2(false, R),
+ {ok,#export_from_case{val=42}} = export_from_case_2(true, R),
+
+ ok.
+
+export_from_case_1(Bool) ->
+ case Bool of
+ true ->
+ id(42),
+ Result = a;
+ false ->
+ Result = b
+ end,
+ id(Result).
+
+export_from_case_2(Bool, Rec) ->
+ case Bool of
+ false ->
+ Result = Rec;
+ true ->
+ Result = Rec#export_from_case{val=42}
+ end,
+ {ok,Result}.
+
+empty_values(_Config) ->
+ case ?MODULE of
+ core_fold_inline_SUITE ->
+ {'EXIT',_} = (catch do_empty_values());
+ _ ->
+ {'EXIT',{function_clause,_}} = (catch do_empty_values())
+ end,
+ ok.
+
+do_empty_values() when (#{})#{} ->
+ c.
+
+cover_letrec_effect(_Config) ->
+ self() ! {tag,42},
+ _ = try
+ try
+ ignore
+ after
+ receive
+ {tag,Int}=Term ->
+ Res = #{k => {Term,<<Int:16>>}},
+ self() ! Res
+ end
+ end
+ after
+ ok
+ end,
+ receive
+ Any ->
+ #{k := {{tag,42},<<42:16>>}} = Any
+ end,
+ ok.
+
id(I) -> I.
diff --git a/lib/compiler/test/error_SUITE.erl b/lib/compiler/test/error_SUITE.erl
index 01c779b181..8b9dbe4aa0 100644
--- a/lib/compiler/test/error_SUITE.erl
+++ b/lib/compiler/test/error_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -31,7 +31,6 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -40,6 +39,7 @@ groups() ->
transforms,maps_warnings,bad_utf8]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/float_SUITE.erl b/lib/compiler/test/float_SUITE.erl
index 08c3dd8593..0fa8070dc8 100644
--- a/lib/compiler/test/float_SUITE.erl
+++ b/lib/compiler/test/float_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -20,21 +20,23 @@
-module(float_SUITE).
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
- pending/1,bif_calls/1,math_functions/1,mixed_float_and_int/1]).
+ pending/1,bif_calls/1,math_functions/1,mixed_float_and_int/1,
+ subtract_number_type/1,float_followed_by_guard/1]).
-include_lib("common_test/include/ct.hrl").
suite() -> [{ct_hooks,[ts_install_cth]}].
-all() ->
- test_lib:recompile(?MODULE),
+all() ->
[pending, bif_calls, math_functions,
- mixed_float_and_int].
+ mixed_float_and_int, subtract_number_type,
+ float_followed_by_guard].
groups() ->
[].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -176,5 +178,31 @@ mixed_float_and_int(Config) when is_list(Config) ->
pc(Cov, NotCov, X) ->
round(Cov/(Cov+NotCov)*100) + 42 + 2.0*X.
+subtract_number_type(Config) when is_list(Config) ->
+ 120 = fact(5).
+
+fact(N) ->
+ fact(N, 1).
+
+fact(0, P) -> P;
+fact(1, P) -> P;
+fact(N, P) -> fact(N-1, P*N).
+
+float_followed_by_guard(Config) when is_list(Config) ->
+ true = ffbg_1(5, 1),
+ false = ffbg_1(1, 5),
+ ok.
+
+ffbg_1(A, B0) ->
+ %% This is a non-guard block followed by a *guard block* that starts with a
+ %% floating point operation, and the compiler erroneously assumed that it
+ %% was safe to skip fcheckerror because the next block started with a float
+ %% op.
+ B = id(B0) / 1.0,
+ if
+ A - B > 0.0 -> true;
+ A - B =< 0.0 -> false
+ end.
+
id(I) -> I.
diff --git a/lib/compiler/test/fun_SUITE.erl b/lib/compiler/test/fun_SUITE.erl
index 16474adf5b..1df0a05275 100644
--- a/lib/compiler/test/fun_SUITE.erl
+++ b/lib/compiler/test/fun_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,7 +32,6 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -41,6 +40,7 @@ groups() ->
eep37_dup,badarity,badfun]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -194,6 +194,17 @@ external(Config) when is_list(Config) ->
?APPLY2(ListsMod, ListsMap, 2),
?APPLY2(ListsMod, ListsMap, ListsArity),
+ 42 = (fun erlang:abs/1)(-42),
+ 42 = (id(fun erlang:abs/1))(-42),
+ 42 = apply(fun erlang:abs/1, [-42]),
+ 42 = apply(id(fun erlang:abs/1), [-42]),
+ 6 = (fun lists:sum/1)([1,2,3]),
+ 6 = (id(fun lists:sum/1))([1,2,3]),
+
+ {'EXIT',{{badarity,_},_}} = (catch (fun lists:sum/1)(1, 2, 3)),
+ {'EXIT',{{badarity,_},_}} = (catch (id(fun lists:sum/1))(1, 2, 3)),
+ {'EXIT',{{badarity,_},_}} = (catch apply(fun lists:sum/1, [1,2,3])),
+
ok.
call_me(I) ->
@@ -238,6 +249,13 @@ badfun(_Config) ->
expect_badfun(X, catch X(put(?FUNCTION_NAME, of_course))),
of_course = erase(?FUNCTION_NAME),
+ %% A literal as a Fun used to crash the code generator. This only happened
+ %% when type optimization had reduced `Fun` to a literal, hence the match.
+ Literal = fun(literal = Fun) ->
+ Fun()
+ end,
+ expect_badfun(literal, catch Literal(literal)),
+
ok.
expect_badfun(Term, Exit) ->
diff --git a/lib/compiler/test/guard_SUITE.erl b/lib/compiler/test/guard_SUITE.erl
index ccb9b58225..ed0a56f064 100644
--- a/lib/compiler/test/guard_SUITE.erl
+++ b/lib/compiler/test/guard_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -35,12 +35,11 @@
basic_andalso_orelse/1,traverse_dcd/1,
check_qlc_hrl/1,andalso_semi/1,t_tuple_size/1,binary_part/1,
bad_constants/1,bad_guards/1,
- guard_in_catch/1,beam_bool_SUITE/1]).
+ guard_in_catch/1,beam_bool_SUITE/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -57,6 +56,7 @@ groups() ->
bad_constants,bad_guards,guard_in_catch,beam_bool_SUITE]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -1291,6 +1291,36 @@ rel_ops(Config) when is_list(Config) ->
true = any_atom /= id(42),
true = [] /= id(42),
+ %% Coverage of beam_utils:bif_to_test/3
+ Empty = id([]),
+ ?T(==, [], Empty),
+
+ %% Cover beam_ssa_dead:turn_op('/=').
+ ok = (fun(A, B) when is_atom(A) ->
+ X = id(A /= B),
+ if
+ X -> ok;
+ true -> error
+ end
+ end)(a, b),
+ ok = (fun(A, B) when is_atom(A) ->
+ X = id(B /= A),
+ if
+ X -> ok;
+ true -> error
+ end
+ end)(a, b),
+
+ %% Cover beam_ssa_dead.
+ Arrow = fun([T1,T2]) when T1 == $>, T2 == $>;
+ T1 == $<, T2 == $| -> true;
+ (_) -> false
+ end,
+ true = Arrow(">>"),
+ true = Arrow("<|"),
+ false = Arrow("><"),
+ false = Arrow(""),
+
ok.
-undef(TestOp).
@@ -1324,6 +1354,9 @@ rel_op_combinations_1(N, Digits) ->
Bool = is_digit_6(N),
Bool = is_digit_7(N),
Bool = is_digit_8(N),
+ Bool = is_digit_9(42, N),
+ Bool = is_digit_10(N, 0),
+ Bool = is_digit_11(N, 0),
rel_op_combinations_1(N-1, Digits).
is_digit_1(X) when 16#0660 =< X, X =< 16#0669 -> true;
@@ -1367,6 +1400,24 @@ is_digit_8(X) when X =< 16#0669, X > (16#0660-1) -> true;
is_digit_8(16#0670) -> false;
is_digit_8(_) -> false.
+is_digit_9(A, 0) when A =:= 42 -> false;
+is_digit_9(_, X) when X > 16#065F, X < 16#066A -> true;
+is_digit_9(_, X) when 16#0030 =< X, X =< 16#0039 -> true;
+is_digit_9(_, X) when 16#06F0 =< X, X =< 16#06F9 -> true;
+is_digit_9(_, _) -> false.
+
+is_digit_10(0, 0) -> false;
+is_digit_10(X, _) when X < 16#066A, 16#0660 =< X -> true;
+is_digit_10(X, _) when 16#0030 =< X, X =< 16#0039 -> true;
+is_digit_10(X, _) when 16#06F0 =< X, X =< 16#06F9 -> true;
+is_digit_10(_, _) -> false.
+
+is_digit_11(0, 0) -> false;
+is_digit_11(X, _) when X =< 16#0669, 16#0660 =< X -> true;
+is_digit_11(X, _) when 16#0030 =< X, X =< 16#0039 -> true;
+is_digit_11(X, _) when 16#06F0 =< X, X =< 16#06F9 -> true;
+is_digit_11(_, _) -> false.
+
rel_op_combinations_2(0, _) ->
ok;
rel_op_combinations_2(N, Range) ->
@@ -1467,6 +1518,7 @@ rel_op_combinations_3(N, Red) ->
Val = redundant_9(N),
Val = redundant_10(N),
Val = redundant_11(N),
+ Val = redundant_11(N),
rel_op_combinations_3(N-1, Red).
redundant_1(X) when X >= 51, X =< 80 -> 5*X;
@@ -1521,6 +1573,10 @@ redundant_11(X) when X =:= 10 -> 2*X;
redundant_11(X) when X >= 51, X =< 80 -> 5*X;
redundant_11(_) -> none.
+redundant_12(X) when X >= 50, X =< 80 -> 2*X;
+redundant_12(X) when X < 51 -> 5*X;
+redundant_12(_) -> none.
+
%% Test type tests on literal values. (From emulator test suites.)
literal_type_tests(Config) when is_list(Config) ->
case ?MODULE of
@@ -1615,7 +1671,9 @@ type_tests() ->
is_reference,
is_port,
is_binary,
- is_function].
+ is_bitstring,
+ is_function,
+ is_map].
basic_andalso_orelse(Config) when is_list(Config) ->
T = id({type,integers,23,42}),
@@ -1771,15 +1829,10 @@ t_tuple_size(Config) when is_list(Config) ->
error = ludicrous_tuple_size({a,b,c}),
error = ludicrous_tuple_size([a,b,c]),
- %% Test the "unsafe case" - the register assigned the tuple size is
- %% not killed.
- DataDir = test_lib:get_data_dir(Config),
- File = filename:join(DataDir, "guard_SUITE_tuple_size"),
- {ok,Mod,Code} = compile:file(File, [from_asm,binary]),
- code:load_binary(Mod, File, Code),
- 14 = Mod:t({1,2,3,4}),
- _ = code:delete(Mod),
- _ = code:purge(Mod),
+ good_ip({1,2,3,4}),
+ good_ip({1,2,3,4,5,6,7,8}),
+ error = validate_ip({42,11}),
+ error = validate_ip(atom),
ok.
@@ -1797,6 +1850,16 @@ ludicrous_tuple_size(T)
when tuple_size(T) =:= 16#FFFFFFFFFFFFFFFF -> ok;
ludicrous_tuple_size(_) -> error.
+good_ip(IP) ->
+ IP = validate_ip(IP).
+
+validate_ip(Value) when is_tuple(Value) andalso
+ ((size(Value) =:= 4) orelse (size(Value) =:= 8)) ->
+ %% size/1 (converted to tuple_size) used more than once.
+ Value;
+validate_ip(_) ->
+ error.
+
%%
%% The binary_part/2,3 guard BIFs
%%
@@ -2198,8 +2261,6 @@ maps() ->
evidence(#{0 := Charge}) when 0; #{[] => Charge} == #{[] => 42} ->
ok.
-
-
%% Call this function to turn off constant propagation.
id(I) -> I.
diff --git a/lib/compiler/test/guard_SUITE_data/guard_SUITE_tuple_size.S b/lib/compiler/test/guard_SUITE_data/guard_SUITE_tuple_size.S
deleted file mode 100644
index cffb792920..0000000000
--- a/lib/compiler/test/guard_SUITE_data/guard_SUITE_tuple_size.S
+++ /dev/null
@@ -1,30 +0,0 @@
-{module, guard_SUITE_tuple_size}. %% version = 0
-
-{exports, [{t,1}]}.
-
-{attributes, []}.
-
-{labels, 5}.
-
-
-{function, t, 1, 2}.
- {label,1}.
- {func_info,{atom,guard_SUITE_tuple_size},{atom,t},1}.
- {label,2}.
- {bif,tuple_size,{f,4},[{x,0}],{x,1}}.
- {test,is_eq_exact,{f,4},[{x,1},{integer,4}]}.
- {test,is_tuple,{f,3},[{x,0}]}.
- {test,test_arity,{f,3},[{x,0},4]}.
- {get_tuple_element,{x,0},0,{x,5}}.
- {get_tuple_element,{x,0},1,{x,2}}.
- {get_tuple_element,{x,0},2,{x,3}}.
- {get_tuple_element,{x,0},3,{x,4}}.
- {gc_bif,'+',{f,0},6,[{x,1},{x,2}],{x,0}}.
- {gc_bif,'+',{f,0},6,[{x,0},{x,3}],{x,0}}.
- {gc_bif,'+',{f,0},6,[{x,0},{x,4}],{x,0}}.
- {gc_bif,'+',{f,0},6,[{x,0},{x,5}],{x,0}}.
- return.
- {label,3}.
- {badmatch,{x,0}}.
- {label,4}.
- {jump,{f,1}}.
diff --git a/lib/compiler/test/inline_SUITE.erl b/lib/compiler/test/inline_SUITE.erl
index ae59cc8026..aff1a56c47 100644
--- a/lib/compiler/test/inline_SUITE.erl
+++ b/lib/compiler/test/inline_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,7 +32,6 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -42,13 +41,10 @@ groups() ->
coverage]}].
init_per_suite(Config) ->
- Pa = "-pa " ++ filename:dirname(code:which(?MODULE)),
- {ok,Node} = start_node(compiler, Pa),
- [{testing_node,Node}|Config].
+ test_lib:recompile(?MODULE),
+ Config.
-end_per_suite(Config) ->
- Node = proplists:get_value(testing_node, Config),
- test_server:stop_node(Node),
+end_per_suite(_Config) ->
ok.
init_per_group(_GroupName, Config) ->
@@ -89,26 +85,26 @@ attribute(Config) when is_list(Config) ->
?comp(maps_inline_test).
try_inline(Mod, Config) ->
- Node = proplists:get_value(testing_node, Config),
Src = filename:join(proplists:get_value(data_dir, Config),
atom_to_list(Mod)),
Out = proplists:get_value(priv_dir,Config),
%% Normal compilation.
io:format("Compiling: ~s\n", [Src]),
- {ok,Mod} = compile:file(Src, [{outdir,Out},report,bin_opt_info,clint]),
+ {ok,Mod} = compile:file(Src, [{outdir,Out},report,
+ bin_opt_info,clint,ssalint]),
ct:timetrap({minutes,10}),
- NormalResult = rpc:call(Node, ?MODULE, load_and_call, [Out,Mod]),
+ NormalResult = load_and_call(Out, Mod),
%% Inlining.
io:format("Compiling with old inliner: ~s\n", [Src]),
{ok,Mod} = compile:file(Src, [{outdir,Out},report,bin_opt_info,
- {inline,1000},clint]),
+ {inline,1000},clint,ssalint]),
%% Run inlined code.
ct:timetrap({minutes,10}),
- OldInlinedResult = rpc:call(Node, ?MODULE, load_and_call, [Out,Mod]),
+ OldInlinedResult = load_and_call(Out, Mod),
%% Compare results.
compare(NormalResult, OldInlinedResult),
@@ -117,11 +113,11 @@ try_inline(Mod, Config) ->
%% Inlining.
io:format("Compiling with new inliner: ~s\n", [Src]),
{ok,Mod} = compile:file(Src, [{outdir,Out},report,
- bin_opt_info,inline,clint]),
+ bin_opt_info,inline,clint,ssalint]),
%% Run inlined code.
ct:timetrap({minutes,10}),
- InlinedResult = rpc:call(Node, ?MODULE, load_and_call, [Out,Mod]),
+ InlinedResult = load_and_call(Out, Mod),
%% Compare results.
compare(NormalResult, InlinedResult),
@@ -130,6 +126,11 @@ try_inline(Mod, Config) ->
%% Delete Beam file.
ok = file:delete(filename:join(Out, atom_to_list(Mod)++code:objfile_extension())),
+ %% Delete loaded module.
+ _ = code:purge(Mod),
+ _ = code:delete(Mod),
+ _ = code:purge(Mod),
+
ok.
compare(Same, Same) -> ok;
@@ -143,12 +144,6 @@ compare([H1|_], [H2|_]) ->
ct:fail(different);
compare([], []) -> ok.
-start_node(Name, Args) ->
- case test_server:start_node(Name, slave, [{args,Args}]) of
- {ok,Node} -> {ok, Node};
- Error -> ct:fail(Error)
- end.
-
load_and_call(Out, Module) ->
io:format("Loading...\n",[]),
code:purge(Module),
@@ -349,9 +344,8 @@ otp_7223_2({a}) ->
1.
coverage(Config) when is_list(Config) ->
- Mod = bsdecode,
+ Mod = attribute,
Src = filename:join(proplists:get_value(data_dir, Config), Mod),
- {ok,Mod,_} = compile:file(Src, [binary,report,{inline,0},clint]),
- {ok,Mod,_} = compile:file(Src, [binary,report,{inline,20},
- verbose,clint]),
+ {ok,Mod,_} = compile:file(Src, [binary,report,{inline,0},
+ clint,ssalint]),
ok.
diff --git a/lib/compiler/test/inline_SUITE_data/barnes2.erl b/lib/compiler/test/inline_SUITE_data/barnes2.erl
index a986331060..49e9bdfb6b 100644
--- a/lib/compiler/test/inline_SUITE_data/barnes2.erl
+++ b/lib/compiler/test/inline_SUITE_data/barnes2.erl
@@ -6,7 +6,7 @@
?MODULE() ->
Stars = create_scenario(1000, 1.0),
R = hd(loop(10,1000.0,Stars,0)),
- Str = lists:flatten(io:lib_format("~s", [R])),
+ Str = lists:flatten(io_lib:format("~p", [R])),
{R,Str =:= {1.00000,-1.92269e+4,-1.92269e+4,2.86459e-2,2.86459e-2}}.
create_scenario(N, M) ->
diff --git a/lib/compiler/test/lc_SUITE.erl b/lib/compiler/test/lc_SUITE.erl
index 9ad417b09b..c80b7cc59e 100644
--- a/lib/compiler/test/lc_SUITE.erl
+++ b/lib/compiler/test/lc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -33,7 +33,6 @@ suite() ->
{timetrap,{minutes,1}}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -48,6 +47,7 @@ groups() ->
]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -107,6 +107,31 @@ basic(Config) when is_list(Config) ->
[] = [X || X <- L1, X+1 < 2],
{'EXIT',_} = (catch [X || X <- L1, odd(X)]),
fc([x], catch [E || E <- id(x)]),
+
+ %% Make sure that line numbers point out the generator.
+ case ?MODULE of
+ lc_inline_SUITE ->
+ ok;
+ _ ->
+ {'EXIT',{function_clause,
+ [{?MODULE,_,_,
+ [{file,"bad_lc.erl"},{line,4}]}|_]}} =
+ (catch bad_generator(a)),
+ {'EXIT',{function_clause,
+ [{?MODULE,_,_,
+ [{file,"bad_lc.erl"},{line,4}]}|_]}} =
+ (catch bad_generator([a|b])),
+ {'EXIT',{badarg,
+ [{erlang,length,_,_},
+ {?MODULE,bad_generator_bc,1,
+ [{file,"bad_lc.erl"},{line,7}]}|_]}} =
+ (catch bad_generator_bc(a)),
+ {'EXIT',{badarg,
+ [{erlang,length,_,_},
+ {?MODULE,bad_generator_bc,1,
+ [{file,"bad_lc.erl"},{line,7}]}|_]}} =
+ (catch bad_generator_bc([a|b]))
+ end,
ok.
tuple_list() ->
@@ -249,3 +274,11 @@ fc(Args, {'EXIT',{function_clause,[{?MODULE,_,Arity,_}|_]}})
fc(Args, {'EXIT',{{case_clause,ActualArgs},_}})
when ?MODULE =:= lc_inline_SUITE ->
Args = tuple_to_list(ActualArgs).
+
+-file("bad_lc.erl", 1).
+bad_generator(List) -> %Line 2
+ [I || %Line 3
+ I <- List]. %Line 4
+bad_generator_bc(List) -> %Line 5
+ << <<I:4>> || %Line 6
+ I <- List>>. %Line 7
diff --git a/lib/compiler/test/map_SUITE.erl b/lib/compiler/test/map_SUITE.erl
index 5e90b79aa2..440b632381 100644
--- a/lib/compiler/test/map_SUITE.erl
+++ b/lib/compiler/test/map_SUITE.erl
@@ -36,7 +36,7 @@
t_guard_fun/1,
t_list_comprehension/1,
t_map_sort_literals/1,
- t_map_size/1,
+ t_map_size/1, t_map_get/1,
t_build_and_match_aliasing/1,
t_is_map/1,
@@ -67,14 +67,18 @@
%% errors in 18
t_register_corruption/1,
- t_bad_update/1
+ t_bad_update/1,
+ %% new in OTP 21
+ t_reused_key_variable/1,
+
+ %% new in OTP 22
+ t_mixed_clause/1,cover_beam_trim/1
]).
suite() -> [].
all() ->
- test_lib:recompile(?MODULE),
[
%% literals
t_build_and_match_literals, t_build_and_match_literals_large,
@@ -89,7 +93,7 @@ all() ->
t_guard_receive, t_guard_receive_large,
t_guard_fun, t_list_comprehension,
t_map_sort_literals,
- t_map_size,
+ t_map_size, t_map_get,
t_build_and_match_aliasing,
t_is_map,
@@ -120,13 +124,23 @@ all() ->
%% errors in 18
t_register_corruption,
- t_bad_update
+ t_bad_update,
+
+ %% new in OTP 21
+ t_reused_key_variable,
+
+ %% new in OTP 22
+ t_mixed_clause,cover_beam_trim
].
groups() -> [].
-init_per_suite(Config) -> Config.
-end_per_suite(_Config) -> ok.
+init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
init_per_group(_GroupName, Config) -> Config.
end_per_group(_GroupName, Config) -> Config.
@@ -686,6 +700,32 @@ t_map_size(Config) when is_list(Config) ->
map_is_size(M,N) when map_size(M) =:= N -> true;
map_is_size(_,_) -> false.
+t_map_get(Config) when is_list(Config) ->
+ 1 = map_get(a, id(#{a=>1})),
+
+ {'EXIT',{{badkey,a},_}} = (catch map_get(a, #{})),
+ {'EXIT',{{badkey,a},_}} = (catch map_get(a, #{b=>1})),
+
+ M = #{"a"=>1, "b" => 2},
+ true = check_map_value(M, "a", 1),
+ false = check_map_value(M, "b", 1),
+ true = check_map_value(M#{"c"=>2}, "c", 2),
+ false = check_map_value(M#{"a"=>5}, "a", 1),
+
+ {'EXIT',{{badmap,[]},_}} = (catch map_get(a, [])),
+ {'EXIT',{{badmap,<<1,2,3>>},_}} = (catch map_get(a, <<1,2,3>>)),
+ {'EXIT',{{badmap,1},_}} = (catch map_get(a, 1)),
+
+ %% Test that beam_validator understands that NewMap is
+ %% a map after seeing map_get(a, NewMap).
+ NewMap = id(#{a=>b}),
+ b = map_get(a, NewMap),
+ #{a:=z} = NewMap#{a:=z},
+ ok.
+
+check_map_value(Map, Key, Value) when map_get(Key, Map) =:= Value -> true;
+check_map_value(_, _, _) -> false.
+
t_is_map(Config) when is_list(Config) ->
true = is_map(#{}),
true = is_map(#{a=>1}),
@@ -695,8 +735,28 @@ t_is_map(Config) when is_list(Config) ->
if is_map(#{b=>1}) -> ok end,
if not is_map([1,2,3]) -> ok end,
if not is_map(x) -> ok end,
+
+ ok = do_t_is_map(map, #{}),
+ error = do_t_is_map(map, {a,b,c}),
+ ok = do_t_is_map(number, 42),
+ ok = do_t_is_map(number, 42.0),
+ error = do_t_is_map(number, {a,b,c}),
ok.
+do_t_is_map(What, X) ->
+ B = case What of
+ map ->
+ %% Cover conversion of is_map/1 BIF to test instruction
+ %% in beam_utils:bif_to_test/3.
+ is_map(X);
+ number ->
+ is_number(X)
+ end,
+ case B of
+ true -> ok;
+ false -> error
+ end.
+
% test map updates without matching
t_update_literals(Config) when is_list(Config) ->
Map = #{x=>1,y=>2,z=>3,q=>4},
@@ -1158,12 +1218,84 @@ t_guard_bifs(Config) when is_list(Config) ->
true = map_guard_empty_2(),
true = map_guard_head(#{a=>1}),
false = map_guard_head([]),
+
+ true = map_get_head(#{a=>1}),
+ false = map_get_head(#{}),
+ false = map_get_head([]),
+
+ true = map_get_head_not(#{a=>false}),
+ false = map_get_head_not(#{a=>true}),
+ false = map_get_head(#{}),
+ false = map_get_head([]),
+
+ true = map_is_key_head(#{a=>1}),
+ false = map_is_key_head(#{}),
+ false = map_is_key_head(not_a_map),
+
+ false = map_is_key_head_not(#{a=>1}),
+ true = map_is_key_head_not(#{b=>1}),
+ true = map_is_key_head_not(#{}),
+ false = map_is_key_head_not(not_a_map),
+
true = map_guard_body(#{a=>1}),
false = map_guard_body({}),
true = map_guard_pattern(#{a=>1, <<"hi">> => "hi" }),
false = map_guard_pattern("list"),
true = map_guard_tautology(),
true = map_guard_ill_map_size(),
+ true = map_field_check_sequence(#{a=>1}),
+ false = map_field_check_sequence(#{}),
+
+ %% The guard BIFs used in a body.
+
+ v = map_get(a, id(#{a=>v})),
+ {'EXIT',{{badkey,a},_}} =
+ (catch map_get(a, id(#{}))),
+ {'EXIT',{{badmap,not_a_map},_}} =
+ (catch map_get(a, id(not_a_map))),
+
+ true = is_map_key(a, id(#{a=>1})),
+ false = is_map_key(b, id(#{a=>1})),
+ false = is_map_key(b, id(#{})),
+ {'EXIT',{{badmap,not_a_map},_}} =
+ (catch is_map_key(b, id(not_a_map))),
+
+ {true,v} = erl_699(#{k=>v}),
+ {'EXIT',{{badkey,k},_}} = (catch erl_699(#{})),
+ {'EXIT',{{badmap,not_a_map},_}} = (catch erl_699(not_a_map)),
+
+ %% Cover optimizations in beam_dead.
+
+ ok = beam_dead_1(#{a=>any,k=>true}),
+ error = beam_dead_1(#{a=>any,k=>false}),
+ error = beam_dead_1(#{a=>any}),
+ error = beam_dead_1(#{}),
+
+ ok = beam_dead_2(#{a=>any,k=>true}),
+ error = beam_dead_2(#{a=>any,k=>false}),
+ error = beam_dead_2(#{a=>any}),
+ error = beam_dead_2(#{}),
+
+ ok = beam_dead_3(#{k=>true}),
+ error = beam_dead_3(#{k=>false}),
+ error = beam_dead_3(#{}),
+
+ ok = beam_dead_4(#{k=>true}),
+ error = beam_dead_4(#{k=>false}),
+ error = beam_dead_4(#{}),
+ error = beam_dead_4(not_a_map),
+
+ ok = beam_dead_5(#{k=>true}),
+ error = beam_dead_5(#{k=>false}),
+ error = beam_dead_3(#{}),
+
+ %% Test is_map_key/2 followed by map update.
+
+ Used0 = map_usage(var, #{other=>value}),
+ Used0 = #{other=>value,var=>dead},
+ Used1 = map_usage(var, #{var=>live}),
+ Used1 = #{var=>live},
+
ok.
map_guard_empty() when is_map(#{}); false -> true.
@@ -1173,6 +1305,18 @@ map_guard_empty_2() when true; #{} andalso false -> true.
map_guard_head(M) when is_map(M) -> true;
map_guard_head(_) -> false.
+map_get_head(M) when map_get(a, M) =:= 1 -> true;
+map_get_head(_) -> false.
+
+map_get_head_not(M) when not map_get(a, M) -> true;
+map_get_head_not(_) -> false.
+
+map_is_key_head(M) when is_map_key(a, M) -> true;
+map_is_key_head(_) -> false.
+
+map_is_key_head_not(M) when not is_map_key(a, M) -> true;
+map_is_key_head_not(_) -> false.
+
map_guard_body(M) -> is_map(M).
map_guard_pattern(#{}) -> true;
@@ -1182,23 +1326,75 @@ map_guard_tautology() when #{} =:= #{}; true -> true.
map_guard_ill_map_size() when true; map_size(0) -> true.
+map_field_check_sequence(M)
+ when is_map(M) andalso is_map_key(a, M) andalso (map_get(a, M) == 1) ->
+ true;
+map_field_check_sequence(_) ->
+ false.
+
+erl_699(M) ->
+ %% Used to cause an internal consistency failure.
+ {is_map_key(k, M),maps:get(k, M)}.
+
+beam_dead_1(#{a:=_,k:=_}=M) when map_get(k, M) ->
+ ok;
+beam_dead_1(#{}) ->
+ error.
+
+beam_dead_2(M) ->
+ case M of
+ #{a:=_,k:=_} when map_get(k, M) ->
+ ok;
+ #{} ->
+ error
+ end.
+
+beam_dead_3(M) ->
+ case M of
+ #{k:=_} when map_get(k, M) ->
+ ok;
+ #{} ->
+ error
+ end.
+
+beam_dead_4(M) ->
+ case M of
+ #{} when map_get(k, M) ->
+ ok;
+ _ ->
+ error
+ end.
+
+beam_dead_5(#{}=M) when map_get(k, M) ->
+ ok;
+beam_dead_5(#{}) ->
+ error.
+
+%% Test is_map_key/2, followed by an update of the map.
+map_usage(Def, Used) ->
+ case is_map_key(Def, Used) of
+ true -> Used;
+ false -> Used#{Def=>dead}
+ end.
+
+
t_guard_sequence(Config) when is_list(Config) ->
- {1, "a"} = map_guard_sequence_1(#{seq=>1,val=>id("a")}),
- {2, "b"} = map_guard_sequence_1(#{seq=>2,val=>id("b")}),
- {3, "c"} = map_guard_sequence_1(#{seq=>3,val=>id("c")}),
- {4, "d"} = map_guard_sequence_1(#{seq=>4,val=>id("d")}),
- {5, "e"} = map_guard_sequence_1(#{seq=>5,val=>id("e")}),
-
- {1,M1} = map_guard_sequence_2(M1 = id(#{a=>3})),
- {2,M2} = map_guard_sequence_2(M2 = id(#{a=>4, b=>4})),
- {3,gg,M3} = map_guard_sequence_2(M3 = id(#{a=>gg, b=>4})),
- {4,sc,sc,M4} = map_guard_sequence_2(M4 = id(#{a=>sc, b=>3, c=>sc2})),
- {5,kk,kk,M5} = map_guard_sequence_2(M5 = id(#{a=>kk, b=>other, c=>sc2})),
-
- %% error case
- {'EXIT',{function_clause,_}} = (catch map_guard_sequence_1(#{seq=>6,val=>id("e")})),
- {'EXIT',{function_clause,_}} = (catch map_guard_sequence_2(#{b=>5})),
- ok.
+ {1, "a"} = map_guard_sequence_1(#{seq=>1,val=>id("a")}),
+ {2, "b"} = map_guard_sequence_1(#{seq=>2,val=>id("b")}),
+ {3, "c"} = map_guard_sequence_1(#{seq=>3,val=>id("c")}),
+ {4, "d"} = map_guard_sequence_1(#{seq=>4,val=>id("d")}),
+ {5, "e"} = map_guard_sequence_1(#{seq=>5,val=>id("e")}),
+
+ {1,M1} = map_guard_sequence_2(M1 = id(#{a=>3})),
+ {2,M2} = map_guard_sequence_2(M2 = id(#{a=>4, b=>4})),
+ {3,gg,M3} = map_guard_sequence_2(M3 = id(#{a=>gg, b=>4})),
+ {4,sc,sc,M4} = map_guard_sequence_2(M4 = id(#{a=>sc, b=>3, c=>sc2})),
+ {5,kk,kk,M5} = map_guard_sequence_2(M5 = id(#{a=>kk, b=>other, c=>sc2})),
+
+ %% error case
+ {'EXIT',{function_clause,_}} = (catch map_guard_sequence_1(#{seq=>6,val=>id("e")})),
+ {'EXIT',{function_clause,_}} = (catch map_guard_sequence_2(#{b=>5})),
+ ok.
t_guard_sequence_large(Config) when is_list(Config) ->
M0 = id(#{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00",03]}=>"10",
@@ -1253,21 +1449,21 @@ t_guard_sequence_large(Config) when is_list(Config) ->
18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 2" }),
- {1, "a"} = map_guard_sequence_1(M0#{seq=>1,val=>id("a")}),
- {2, "b"} = map_guard_sequence_1(M0#{seq=>2,val=>id("b")}),
- {3, "c"} = map_guard_sequence_1(M0#{seq=>3,val=>id("c")}),
- {4, "d"} = map_guard_sequence_1(M0#{seq=>4,val=>id("d")}),
- {5, "e"} = map_guard_sequence_1(M0#{seq=>5,val=>id("e")}),
+ {1, "a"} = map_guard_sequence_1(M0#{seq=>1,val=>id("a")}),
+ {2, "b"} = map_guard_sequence_1(M0#{seq=>2,val=>id("b")}),
+ {3, "c"} = map_guard_sequence_1(M0#{seq=>3,val=>id("c")}),
+ {4, "d"} = map_guard_sequence_1(M0#{seq=>4,val=>id("d")}),
+ {5, "e"} = map_guard_sequence_1(M0#{seq=>5,val=>id("e")}),
- {1,M1} = map_guard_sequence_2(M1 = id(M0#{a=>3})),
- {2,M2} = map_guard_sequence_2(M2 = id(M0#{a=>4, b=>4})),
- {3,gg,M3} = map_guard_sequence_2(M3 = id(M0#{a=>gg, b=>4})),
- {4,sc,sc,M4} = map_guard_sequence_2(M4 = id(M0#{a=>sc, b=>3, c=>sc2})),
- {5,kk,kk,M5} = map_guard_sequence_2(M5 = id(M0#{a=>kk, b=>other, c=>sc2})),
+ {1,M1} = map_guard_sequence_2(M1 = id(M0#{a=>3})),
+ {2,M2} = map_guard_sequence_2(M2 = id(M0#{a=>4, b=>4})),
+ {3,gg,M3} = map_guard_sequence_2(M3 = id(M0#{a=>gg, b=>4})),
+ {4,sc,sc,M4} = map_guard_sequence_2(M4 = id(M0#{a=>sc, b=>3, c=>sc2})),
+ {5,kk,kk,M5} = map_guard_sequence_2(M5 = id(M0#{a=>kk, b=>other, c=>sc2})),
- {'EXIT',{function_clause,_}} = (catch map_guard_sequence_1(M0#{seq=>6,val=>id("e")})),
- {'EXIT',{function_clause,_}} = (catch map_guard_sequence_2(M0#{b=>5})),
- ok.
+ {'EXIT',{function_clause,_}} = (catch map_guard_sequence_1(M0#{seq=>6,val=>id("e")})),
+ {'EXIT',{function_clause,_}} = (catch map_guard_sequence_2(M0#{b=>5})),
+ ok.
map_guard_sequence_1(#{seq:=1=Seq, val:=Val}) -> {Seq,Val};
map_guard_sequence_1(#{seq:=2=Seq, val:=Val}) -> {Seq,Val};
@@ -1889,7 +2085,7 @@ t_register_corruption(Config) when is_list(Config) ->
{3,wanted,<<"value">>} = register_corruption_foo(wanted,M),
ok.
-register_corruption_foo(A,#{a := V1, b := V2}) ->
+register_corruption_foo(_,#{a := V1, b := V2}) ->
register_corruption_dummy_call(1,V1,V2);
register_corruption_foo(A,#{b := V}) ->
register_corruption_dummy_call(2,A,V);
@@ -1960,6 +2156,41 @@ properly(Item) ->
increase(Allows) ->
catch fun() -> Allows end#{[] => +Allows, "warranty" => fun id/1}.
+t_reused_key_variable(Config) when is_list(Config) ->
+ Key = id(key),
+ Map1 = id(#{Key=>Config}),
+ Map2 = id(#{Key=>Config}),
+ case {Map1,Map2} of
+ %% core_lint treated Key as pattern variables, not input variables,
+ %% and complained about the variable being duplicated.
+ {#{Key:=Same},#{Key:=Same}} ->
+ ok
+ end.
+
+t_mixed_clause(_Config) ->
+ put(fool_inliner, x),
+ K = get(fool_inliner),
+ {42,100} = case #{K=>42,y=>100} of
+ #{x:=X,y:=Y} ->
+ {X,Y}
+ end,
+ nomatch = case #{K=>42,y=>100} of
+ #{x:=X,y:=0} ->
+ {X,Y};
+ #{} ->
+ nomatch
+ end,
+ ok.
+
+cover_beam_trim(_Config) ->
+ val = do_cover_beam_trim(id, max, max, id, #{id=>val}),
+ ok.
+
+do_cover_beam_trim(Id, OldMax, Max, Id, M) ->
+ OldMax = id(Max),
+ #{Id:=Val} = id(M),
+ Val.
+
%% aux
diff --git a/lib/compiler/test/match_SUITE.erl b/lib/compiler/test/match_SUITE.erl
index 52b2da05f7..94bfbb0efe 100644
--- a/lib/compiler/test/match_SUITE.erl
+++ b/lib/compiler/test/match_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,27 +23,29 @@
init_per_group/2,end_per_group/2,
pmatch/1,mixed/1,aliases/1,non_matching_aliases/1,
match_in_call/1,untuplify/1,shortcut_boolean/1,letify_guard/1,
- selectify/1,underscore/1,match_map/1,map_vars_used/1,
- coverage/1,grab_bag/1,literal_binary/1]).
+ selectify/1,deselectify/1,underscore/1,match_map/1,map_vars_used/1,
+ coverage/1,grab_bag/1,literal_binary/1,
+ unary_op/1,eq_types/1,match_after_return/1]).
-include_lib("common_test/include/ct.hrl").
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
[{p,[parallel],
[pmatch,mixed,aliases,non_matching_aliases,
match_in_call,untuplify,
- shortcut_boolean,letify_guard,selectify,
+ shortcut_boolean,letify_guard,selectify,deselectify,
underscore,match_map,map_vars_used,coverage,
- grab_bag,literal_binary]}].
+ grab_bag,literal_binary,unary_op,eq_types,
+ match_after_return]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -253,6 +255,8 @@ non_matching_aliases(_Config) ->
none = mixed_aliases([d]),
none = mixed_aliases({a,42}),
none = mixed_aliases(42),
+ none = mixed_aliases(<<6789:16>>),
+ none = mixed_aliases(#{key=>value}),
{'EXIT',{{badmatch,42},_}} = (catch nomatch_alias(42)),
{'EXIT',{{badmatch,job},_}} = (catch entirely()),
@@ -278,6 +282,16 @@ mixed_aliases(<<X:8>> = x) -> {a,X};
mixed_aliases([b] = <<X:8>>) -> {b,X};
mixed_aliases(<<X:8>> = {a,X}) -> {c,X};
mixed_aliases([X] = <<X:8>>) -> {d,X};
+mixed_aliases(<<X:16>> = X) -> {e,X};
+mixed_aliases(X = <<X:16>>) -> {f,X};
+mixed_aliases(<<X:16,_/binary>> = X) -> {g,X};
+mixed_aliases(X = <<X:16,_/binary>>) -> {h,X};
+mixed_aliases(X = #{key:=X}) -> {i,X};
+mixed_aliases(#{key:=X} = X) -> {j,X};
+mixed_aliases([X] = #{key:=X}) -> {k,X};
+mixed_aliases(#{key:=X} = [X]) -> {l,X};
+mixed_aliases({a,X} = #{key:=X}) -> {m,X};
+mixed_aliases(#{key:=X} = {a,X}) -> {n,X};
mixed_aliases(_) -> none.
nomatch_alias(I) ->
@@ -377,6 +391,13 @@ untuplify(Config) when is_list(Config) ->
%% We do this to cover sys_core_fold:unalias_pat/1.
{1,2,3,4,alias,{[1,2],{3,4},alias}} = untuplify_1([1,2], {3,4}, alias),
error = untuplify_1([1,2], {3,4}, 42),
+
+ %% Test that a previous bug in v3_codegen is gone. (The sinking of
+ %% stack frames into only the case arms that needed them was not always
+ %% safe.)
+ [33, -1, -33, 1] = untuplify_2(32, 65),
+ {33, 1, -33, -1} = untuplify_2(65, 32),
+
ok.
untuplify_1(A, B, C) ->
@@ -389,6 +410,21 @@ untuplify_1(A, B, C) ->
error
end.
+untuplify_2(V1, V2) ->
+ {D1,D2,D3,D4} =
+ if V1 > V2 ->
+ %% The 1 value was overwritten by the value of V2-V1.
+ {V1-V2, 1, V2-V1, -1};
+ true ->
+ {V2-V1, -1, V1-V2, 1}
+ end,
+ if
+ D2 > D4 ->
+ {D1, D2, D3, D4};
+ true ->
+ [D1, D2, D3, D4]
+ end.
+
%% Coverage of beam_dead:shortcut_boolean_label/4.
shortcut_boolean(Config) when is_list(Config) ->
false = shortcut_boolean_1([0]),
@@ -433,6 +469,7 @@ letify_guard(A, B) ->
selectify(Config) when is_list(Config) ->
integer = sel_different_types({r,42}),
atom = sel_different_types({r,forty_two}),
+ float = sel_different_types({r,100.0}),
none = sel_different_types({r,18}),
{'EXIT',_} = (catch sel_different_types([a,b,c])),
@@ -443,12 +480,15 @@ selectify(Config) when is_list(Config) ->
integer42 = sel_same_value2(42),
integer43 = sel_same_value2(43),
error = sel_same_value2(44),
+
ok.
sel_different_types({r,_}=T) when element(2, T) =:= forty_two ->
atom;
sel_different_types({r,_}=T) when element(2, T) =:= 42 ->
integer;
+sel_different_types({r,_}=T) when element(2, T) =:= 100.0 ->
+ float;
sel_different_types({r,_}) ->
none.
@@ -466,6 +506,122 @@ sel_same_value2(V) when V =:= 42; V =:= 43 ->
sel_same_value2(_) ->
error.
+%% Test deconstruction of select_val instructions to regular tests
+%% with zero or one values left.
+
+deselectify(Config) when is_list(Config) ->
+ one_or_other = desel_tuple_arity({1}),
+ two = desel_tuple_arity({1,1}),
+ one_or_other = desel_tuple_arity({1,1,1}),
+
+ one_or_other = dsel_integer(1),
+ two = dsel_integer(2),
+ one_or_other = dsel_integer(3),
+
+ one_or_other = dsel_integer_typecheck(1),
+ two = dsel_integer_typecheck(2),
+ one_or_other = dsel_integer_typecheck(3),
+
+ one_or_other = dsel_atom(one),
+ two = dsel_atom(two),
+ one_or_other = dsel_atom(three),
+
+ one_or_other = dsel_atom_typecheck(one),
+ two = dsel_atom_typecheck(two),
+ one_or_other = dsel_atom_typecheck(three),
+
+ %% Cover deconstruction of select_val instructions in
+ %% beam_peep.
+
+ stop = dsel_peek_0(stop),
+ ignore = dsel_peek_0(ignore),
+ Config = dsel_peek_0(Config),
+
+ stop = dsel_peek_1(stop, any),
+ Config = dsel_peek_1(ignore, Config),
+ other = dsel_peek_1(other, ignored),
+
+ 0 = dsel_peek_2(0, any),
+ Config = dsel_peek_2(1, Config),
+ 2 = dsel_peek_2(2, ignored),
+
+ true = dsel_peek_3(true),
+ false = dsel_peek_3(false),
+ {error,Config} = dsel_peek_3(Config),
+
+ ok.
+
+%% The following will be optimized by the sharing optimizations
+%% in beam_ssa_opt.
+
+desel_tuple_arity(Tuple) when is_tuple(Tuple) ->
+ case Tuple of
+ {_} -> one_or_other;
+ {_,_} -> two;
+ _ -> one_or_other
+ end.
+
+dsel_integer(Val) ->
+ case Val of
+ 1 -> one_or_other;
+ 2 -> two;
+ _ -> one_or_other
+ end.
+
+dsel_integer_typecheck(Val) when is_integer(Val) ->
+ case Val of
+ 1 -> one_or_other;
+ 2 -> two;
+ _ -> one_or_other
+ end.
+
+dsel_atom(Val) ->
+ case Val of
+ one -> one_or_other;
+ two -> two;
+ _ -> one_or_other
+ end.
+
+dsel_atom_typecheck(Val) when is_atom(Val) ->
+ case Val of
+ one -> one_or_other;
+ two -> two;
+ _ -> one_or_other
+ end.
+
+%% The following functions are carefully crafted so that the sharing
+%% optimizations in beam_ssa_opt can't be applied. After applying the
+%% beam_jump:eliminate_moves/1 optimization and beam_clean:clean_labels/1
+%% has unified labels, beam_peep is able to optimize these functions.
+
+dsel_peek_0(A0) ->
+ case id(A0) of
+ stop -> stop;
+ ignore -> ignore;
+ A -> A
+ end.
+
+dsel_peek_1(A0, B) ->
+ case id(A0) of
+ stop -> stop;
+ ignore -> B;
+ A -> A
+ end.
+
+dsel_peek_2(A0, B) ->
+ case id(A0) of
+ 0 -> 0;
+ 1 -> B;
+ A -> A
+ end.
+
+dsel_peek_3(A0) ->
+ case id(A0) of
+ true -> true;
+ false -> false;
+ Other -> {error,Other}
+ end.
+
underscore(Config) when is_list(Config) ->
case Config of
[] ->
@@ -508,13 +664,26 @@ do_map_vars_used(X, Y, Map) ->
Val
end.
+-record(coverage_id, {bool=false,id}).
coverage(Config) when is_list(Config) ->
%% Cover beam_dead.
ok = coverage_1(x, a),
ok = coverage_1(x, b),
%% Cover sys_pre_expand.
- ok = coverage_3("abc").
+ ok = coverage_3("abc"),
+
+ %% Cover beam_ssa_dead.
+ {expr,key} = coverage_4([literal,get], [[expr,key]]),
+ {expr,key} = coverage_4([expr,key], []),
+
+ a = coverage_5([8,8,8], #coverage_id{bool=true}),
+ b = coverage_5([], #coverage_id{bool=true}),
+
+ %% Cover beam_ssa_opt.
+ ok = coverage_6(),
+
+ ok.
coverage_1(B, Tag) ->
case Tag of
@@ -527,6 +696,37 @@ coverage_2(2, b, x) -> ok.
coverage_3([$a]++[]++"bc") -> ok.
+%% Cover beam_ssa_dead:eval_type_test_1(is_nonempty_list, Arg).
+coverage_4([literal,get], [Expr]) ->
+ coverage_4(Expr, []);
+coverage_4([Expr,Key], []) ->
+ {Expr,Key}.
+
+%% Cover beam_ssa_dead:eval_type_test_1(is_tagged_tuple, Arg).
+coverage_5(Config, TermId)
+ when TermId =:= #coverage_id{bool=true},
+ Config =:= [8,8,8] ->
+ a;
+coverage_5(_Config, #coverage_id{bool=true}) ->
+ b.
+
+coverage_6() ->
+ X = 17,
+ case
+ case id(1) > 0 of
+ true ->
+ 17;
+ false ->
+ 42
+ end
+ of
+ X ->
+ ok;
+ V ->
+ %% Cover beam_ssa_opt:make_literal/2.
+ error([error,X,V])
+ end.
+
grab_bag(_Config) ->
[_|T] = id([a,b,c]),
[b,c] = id(T),
@@ -557,6 +757,10 @@ grab_bag(_Config) ->
{bad,16#555555555555555555555555555555555555555555555555555}],
ok = grab_bag_remove_failure(L, unit, 0),
+ {42,<<43,44>>} = grab_bag_single_valued(<<42,43,44>>),
+ empty_list = grab_bag_single_valued([]),
+ empty_tuple = grab_bag_single_valued({}),
+
ok.
grab_bag_remove_failure([], _Unit, _MaxFailure) ->
@@ -574,6 +778,12 @@ grab_bag_remove_failure([{stretch,_,Mi}=Stretch | Specs], Unit, _MaxFailure) ->
ok
end.
+%% Cover a line v3_kernel that places binary matching first.
+grab_bag_single_valued(<<H,T/bytes>>) -> {H,T};
+grab_bag_single_valued([]) -> empty_list;
+grab_bag_single_valued({}) -> empty_tuple.
+
+
%% Regression in 19.0, reported by Alexei Sholik
literal_binary(_Config) ->
3 = literal_binary_match(bar, <<"y">>),
@@ -592,5 +802,104 @@ literal_binary_match(_, <<"x">>) -> 2;
literal_binary_match(_, <<"y">>) -> 3;
literal_binary_match(_, _) -> fail.
+unary_op(Config) ->
+ %% ERL-514. This test case only verifies that the code
+ %% calculates the correct result, not that the generated
+ %% code is optimial.
+
+ {non_associative,30} = unary_op_1('&'),
+ {non_associative,300} = unary_op_1('^'),
+ {non_associative,300} = unary_op_1('not'),
+ {non_associative,300} = unary_op_1('+'),
+ {non_associative,300} = unary_op_1('-'),
+ {non_associative,300} = unary_op_1('~~~'),
+ {non_associative,300} = unary_op_1('!'),
+ {non_associative,320} = unary_op_1('@'),
+
+ error = unary_op_1(Config),
+ error = unary_op_1(abc),
+ error = unary_op_1(42),
+
+ ok.
+
+unary_op_1(Vop@1) ->
+ %% If all optimizations are working as they should, there should
+ %% be no stack frame and all '=:=' tests should be coalesced into
+ %% a single select_val instruction.
+
+ case Vop@1 =:= '&' of
+ true ->
+ {non_associative,30};
+ false ->
+ case
+ case Vop@1 =:= '^' of
+ true ->
+ true;
+ false ->
+ case Vop@1 =:= 'not' of
+ true ->
+ true;
+ false ->
+ case Vop@1 =:= '+' of
+ true ->
+ true;
+ false ->
+ case Vop@1 =:= '-' of
+ true ->
+ true;
+ false ->
+ case Vop@1 =:= '~~~' of
+ true ->
+ true;
+ false ->
+ Vop@1 =:= '!'
+ end
+ end
+ end
+ end
+ end
+ of
+ true ->
+ {non_associative,300};
+ false ->
+ case Vop@1 =:= '@' of
+ true ->
+ {non_associative,320};
+ false ->
+ error
+ end
+ end
+ end.
+
+eq_types(_Config) ->
+ Ref = make_ref(),
+ Ref = eq_types(Ref, any),
+ ok.
+
+eq_types(A, B) ->
+ %% {put_tuple2,{y,0},{list,[{x,0},{x,1}]}}.
+ Term0 = {A, B},
+ Term = id(Term0),
+
+ %% {test,is_eq_exact,{f,3},[{y,0},{x,0}]}.
+ %% Here beam_validator must infer that {x,0} has the
+ %% same type as {y,0}.
+ Term = Term0,
+
+ %% {get_tuple_element,{x,0},0,{x,0}}.
+ {Ref22,_} = Term,
+
+ Ref22.
+
+match_after_return(Config) when is_list(Config) ->
+ %% The return type of the following call will never match the 'wont_happen'
+ %% clauses below, and the beam_ssa_type was clever enough to see that but
+ %% didn't remove the blocks, so it crashed when trying to extract A.
+ ok = case mar_test_tuple(erlang:unique_integer()) of
+ {gurka, never_matches, A} -> {wont_happen, A};
+ _ -> ok
+ end.
+
+mar_test_tuple(I) -> {gurka, I}.
id(I) -> I.
diff --git a/lib/compiler/test/misc_SUITE.erl b/lib/compiler/test/misc_SUITE.erl
index 4bd884d86b..a0b415ceaa 100644
--- a/lib/compiler/test/misc_SUITE.erl
+++ b/lib/compiler/test/misc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -61,7 +61,6 @@ suite() ->
-spec all() -> misc_SUITE_test_cases().
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -70,6 +69,7 @@ groups() ->
confused_literals,integer_encoding,override_bif]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -161,16 +161,16 @@ md5_1(Beam) ->
%% Cover some code that handles internal errors.
silly_coverage(Config) when is_list(Config) ->
- %% sys_core_fold, sys_core_bsm, sys_core_setel, v3_kernel
+ %% sys_core_fold, sys_core_alias, sys_core_bsm, v3_kernel
BadCoreErlang = {c_module,[],
name,[],[],
[{{c_var,[],{foo,2}},seriously_bad_body}]},
expect_error(fun() -> sys_core_fold:module(BadCoreErlang, []) end),
+ expect_error(fun() -> sys_core_alias:module(BadCoreErlang, []) end),
expect_error(fun() -> sys_core_bsm:module(BadCoreErlang, []) end),
- expect_error(fun() -> sys_core_dsetel:module(BadCoreErlang, []) end),
expect_error(fun() -> v3_kernel:module(BadCoreErlang, []) end),
- %% v3_life
+ %% beam_kernel_to_ssa
BadKernel = {k_mdef,[],?MODULE,
[{foo,0}],
[],
@@ -178,11 +178,38 @@ silly_coverage(Config) when is_list(Config) ->
{k,[],[],[]},
f,0,[],
seriously_bad_body}]},
- expect_error(fun() -> v3_life:module(BadKernel, []) end),
-
- %% v3_codegen
- CodegenInput = {?MODULE,[{foo,0}],[],[{function,foo,0,[a|b],a,b,[]}]},
- expect_error(fun() -> v3_codegen:module(CodegenInput, []) end),
+ expect_error(fun() -> beam_kernel_to_ssa:module(BadKernel, []) end),
+
+ %% beam_ssa_lint
+ %% beam_ssa_recv
+ %% beam_ssa_share
+ %% beam_ssa_pre_codegen
+ %% beam_ssa_codegen
+ BadSSA = {b_module,#{},a,b,c,
+ [{b_function,#{func_info=>{mod,foo,0}},args,bad_blocks,0}]},
+ expect_error(fun() -> beam_ssa_lint:module(BadSSA, []) end),
+ expect_error(fun() -> beam_ssa_recv:module(BadSSA, []) end),
+ expect_error(fun() -> beam_ssa_share:module(BadSSA, []) end),
+ expect_error(fun() -> beam_ssa_pre_codegen:module(BadSSA, []) end),
+ expect_error(fun() -> beam_ssa_codegen:module(BadSSA, []) end),
+
+ %% beam_ssa_opt
+ BadSSABlocks = #{0 => {b_blk,#{},[bad_code],{b_ret,#{},arg}}},
+ BadSSAOpt = {b_module,#{},a,[],c,
+ [{b_function,#{func_info=>{mod,foo,0}},[],
+ BadSSABlocks,0}]},
+ expect_error(fun() -> beam_ssa_opt:module(BadSSAOpt, []) end),
+
+ %% beam_ssa_lint, beam_ssa_pp
+ {error,[{_,Errors}]} = beam_ssa_lint:module(bad_ssa_lint_input(), []),
+ _ = [io:put_chars(Mod:format_error(Reason)) ||
+ {Mod,Reason} <- Errors],
+
+ %% Cover printing of annotations in beam_ssa_pp
+ PPAnno = #{func_info=>{mod,foo,0},other_anno=>value,map_anno=>#{k=>v}},
+ PPBlocks = #{0=>{b_blk,#{},[],{b_ret,#{},{b_literal,42}}}},
+ PP = {b_function,PPAnno,[],PPBlocks,0},
+ io:put_chars(beam_ssa_pp:format_function(PP)),
%% beam_a
BeamAInput = {?MODULE,[{foo,0}],[],
@@ -192,14 +219,6 @@ silly_coverage(Config) when is_list(Config) ->
{label,2}|non_proper_list]}],99},
expect_error(fun() -> beam_a:module(BeamAInput, []) end),
- %% beam_reorder
- BlockInput = {?MODULE,[{foo,0}],[],
- [{function,foo,0,2,
- [{label,1},
- {func_info,{atom,?MODULE},{atom,foo},0},
- {label,2}|non_proper_list]}],99},
- expect_error(fun() -> beam_reorder:module(BlockInput, []) end),
-
%% beam_block
BlockInput = {?MODULE,[{foo,0}],[],
[{function,foo,0,2,
@@ -208,19 +227,6 @@ silly_coverage(Config) when is_list(Config) ->
{label,2}|non_proper_list]}],99},
expect_error(fun() -> beam_block:module(BlockInput, []) end),
- %% beam_bs
- BsInput = BlockInput,
- expect_error(fun() -> beam_bs:module(BsInput, []) end),
-
- %% beam_type
- TypeInput = {?MODULE,[{foo,0}],[],
- [{function,foo,0,2,
- [{label,1},
- {line,loc},
- {func_info,{atom,?MODULE},{atom,foo},0},
- {label,2}|non_proper_list]}],99},
- expect_error(fun() -> beam_type:module(TypeInput, []) end),
-
%% beam_except
ExceptInput = {?MODULE,[{foo,0}],[],
[{function,foo,0,2,
@@ -230,15 +236,9 @@ silly_coverage(Config) when is_list(Config) ->
{label,2}|non_proper_list]}],99},
expect_error(fun() -> beam_except:module(ExceptInput, []) end),
- %% beam_dead. This is tricky. Our function must look OK to
- %% beam_utils:clean_labels/1, but must crash beam_dead.
- DeadInput = {?MODULE,[{foo,0}],[],
- [{function,foo,0,2,
- [{label,1},
- {func_info,{atom,?MODULE},{atom,foo},0},
- {label,2},
- {test,is_eq_exact,{f,1},[bad,operands]}]}],99},
- expect_error(fun() -> beam_dead:module(DeadInput, []) end),
+ %% beam_jump
+ JumpInput = BlockInput,
+ expect_error(fun() -> beam_jump:module(JumpInput, []) end),
%% beam_clean
CleanInput = {?MODULE,[{foo,0}],[],
@@ -249,6 +249,10 @@ silly_coverage(Config) when is_list(Config) ->
{jump,{f,42}}]}],99},
expect_error(fun() -> beam_clean:module(CleanInput, []) end),
+ %% beam_jump
+ TrimInput = BlockInput,
+ expect_error(fun() -> beam_trim:module(TrimInput, []) end),
+
%% beam_peep. This is tricky. Use a select instruction with
%% an odd number of elements in the list to crash
%% prune_redundant_values/2 but not beam_clean:clean_labels/1.
@@ -256,48 +260,10 @@ silly_coverage(Config) when is_list(Config) ->
[{function,foo,0,2,
[{label,1},
{func_info,{atom,?MODULE},{atom,foo},0},
- {label,2},{select,op,r,{f,2},[{f,2}]}]}],
+ {label,2},{select,select_val,r,{f,2},[{f,2}]}]}],
2},
expect_error(fun() -> beam_peep:module(PeepInput, []) end),
- %% beam_bsm. This is tricky. Our function must be sane enough to not crash
- %% btb_index/1, but must crash the main optimization pass.
- BsmInput = {?MODULE,[{foo,0}],[],
- [{function,foo,0,2,
- [{label,1},
- {func_info,{atom,?MODULE},{atom,foo},0},
- {label,2},
- {test,bs_get_binary2,{f,99},0,[{x,0},{atom,all},1,[]],{x,0}},
- {block,[a|b]}]}],0},
- expect_error(fun() -> beam_bsm:module(BsmInput, []) end),
-
- %% beam_receive.
- ReceiveInput = {?MODULE,[{foo,0}],[],
- [{function,foo,0,2,
- [{label,1},
- {func_info,{atom,?MODULE},{atom,foo},0},
- {label,2},
- {call_ext,0,{extfunc,erlang,make_ref,0}},
- {block,[a|b]}]}],0},
- expect_error(fun() -> beam_receive:module(ReceiveInput, []) end),
-
- %% beam_record.
- RecordInput = {?MODULE,[{foo,0}],[],
- [{function,foo,1,2,
- [{label,1},
- {func_info,{atom,?MODULE},{atom,foo},1},
- {label,2},
- {test,is_tuple,{f,1},[{x,0}]},
- {test,test_arity,{f,1},[{x,0},3]},
- {block,[{set,[{x,1}],[{x,0}],{get_tuple_element,0}}]},
- {test,is_eq_exact,{f,1},[{x,1},{atom,bar}]},
- {block,[{set,[{x,2}],[{x,0}],{get_tuple_element,1}}|a]},
- {test,is_eq_exact,{f,1},[{x,2},{integer,1}]},
- {block,[{set,[{x,0}],[{atom,ok}],move}]},
- return]}],0},
-
- expect_error(fun() -> beam_record:module(RecordInput, []) end),
-
BeamZInput = {?MODULE,[{foo,0}],[],
[{function,foo,0,2,
[{label,1},
@@ -315,14 +281,38 @@ silly_coverage(Config) when is_list(Config) ->
ok.
+bad_ssa_lint_input() ->
+ {b_module,#{},t,
+ [{foobar,1},{module_info,0},{module_info,1}],
+ [],
+ [{b_function,
+ #{func_info => {t,foobar,1},location => {"t.erl",4}},
+ [{b_var,0}],
+ #{0 => {b_blk,#{},[],{b_ret,#{},{b_var,'@undefined_var'}}}},
+ 3},
+ {b_function,
+ #{func_info => {t,module_info,0}},
+ [],
+ #{0 =>
+ {b_blk,#{},
+ [{b_set,#{},
+ {b_var,{'@ssa_ret',3}},
+ call,
+ [{b_remote,
+ {b_literal,erlang},
+ {b_literal,get_module_info},
+ 1},
+ {b_var,'@unknown_variable'}]}],
+ {b_ret,#{},{b_var,{'@ssa_ret',3}}}}},
+ 4}]}.
+
expect_error(Fun) ->
try Fun() of
Any ->
io:format("~p", [Any]),
ct:fail(call_was_supposed_to_fail)
catch
- Class:Reason ->
- Stk = erlang:get_stacktrace(),
+ Class:Reason:Stk ->
io:format("~p:~p\n~p\n", [Class,Reason,Stk]),
case {Class,Reason} of
{error,undef} ->
@@ -363,9 +353,7 @@ integer_encoding_1(Config) ->
io:put_chars(Src, "t(Last) ->[\n"),
io:put_chars(Data, "[\n"),
- do_integer_encoding(-(id(1) bsl 10000), Src, Data),
- do_integer_encoding(id(1) bsl 10000, Src, Data),
- do_integer_encoding(1024, 0, Src, Data),
+ do_integer_encoding(137, 0, Src, Data),
_ = [begin
B = 1 bsl I,
do_integer_encoding(-B-1, Src, Data),
@@ -374,7 +362,7 @@ integer_encoding_1(Config) ->
do_integer_encoding(B-1, Src, Data),
do_integer_encoding(B, Src, Data),
do_integer_encoding(B+1, Src, Data)
- end || I <- lists:seq(1, 128)],
+ end || I <- lists:seq(1, 130)],
io:put_chars(Src, "Last].\n\n"),
ok = file:close(Src),
io:put_chars(Data, "0].\n\n"),
@@ -388,8 +376,6 @@ integer_encoding_1(Config) ->
%% Compare lists.
List = Mod:t(0),
{ok,[List]} = file:consult(DataFile),
- OneBsl10000 = id(1) bsl 10000,
- [-(1 bsl 10000),OneBsl10000|_] = List,
%% Cleanup.
file:delete(SrcFile),
@@ -408,7 +394,3 @@ do_integer_encoding(I, Src, Data) ->
Str = integer_to_list(I),
io:put_chars(Src, [Str,",\n"]),
io:put_chars(Data, [Str,",\n"]).
-
-
-id(I) -> I.
-
diff --git a/lib/compiler/test/overridden_bif_SUITE.erl b/lib/compiler/test/overridden_bif_SUITE.erl
index ce18916515..6b8a9591c9 100644
--- a/lib/compiler/test/overridden_bif_SUITE.erl
+++ b/lib/compiler/test/overridden_bif_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -36,7 +36,6 @@ suite() ->
{timetrap,{minutes,1}}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -45,6 +44,7 @@ groups() ->
]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/receive_SUITE.erl b/lib/compiler/test/receive_SUITE.erl
index 8304672558..0038eb1a4b 100644
--- a/lib/compiler/test/receive_SUITE.erl
+++ b/lib/compiler/test/receive_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,7 +25,8 @@
init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
export/1,recv/1,coverage/1,otp_7980/1,ref_opt/1,
- wait/1]).
+ wait/1,recv_in_try/1,double_recv/1,receive_var_zero/1,
+ match_built_terms/1]).
-include_lib("common_test/include/ct.hrl").
@@ -40,15 +41,17 @@ suite() ->
{timetrap,{minutes,2}}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
[{p,test_lib:parallel(),
- [recv,coverage,otp_7980,ref_opt,export,wait]}].
+ [recv,coverage,otp_7980,ref_opt,export,wait,
+ recv_in_try,double_recv,receive_var_zero,
+ match_built_terms]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -222,9 +225,8 @@ do_ref_opt(Source, PrivDir) ->
collect_recv_opt_instrs(Code)
end,
ok
- catch Class:Error ->
- io:format("~s: ~p ~p\n~p\n",
- [Source,Class,Error,erlang:get_stacktrace()]),
+ catch Class:Error:Stk ->
+ io:format("~s: ~p ~p\n~p\n", [Source,Class,Error,Stk]),
error
end.
@@ -265,6 +267,10 @@ export(Config) when is_list(Config) ->
self() ! {result,Ref,42},
42 = export_1(Ref),
{error,timeout} = export_1(Ref),
+
+ self() ! {result,Ref},
+ {ok,Ref} = export_2(),
+
ok.
export_1(Reference) ->
@@ -281,6 +287,10 @@ export_1(Reference) ->
id({build,self()}),
Result.
+export_2() ->
+ receive {result,Result} -> ok end,
+ {ok,Result}.
+
wait(Config) when is_list(Config) ->
self() ! <<42>>,
<<42>> = wait_1(r, 1, 2),
@@ -298,4 +308,123 @@ wait_1(r, _, _) ->
wait_1(A, B, C) ->
{A,B,C}.
+recv_in_try(_Config) ->
+ self() ! {ok,fh}, {ok,fh} = recv_in_try(infinity, native),
+ self() ! {ok,ignored}, {ok,42} = recv_in_try(infinity, plain),
+ self() ! {error,ignored}, nok = recv_in_try(infinity, plain),
+ timeout = recv_in_try(1, plain),
+ ok.
+
+recv_in_try(Timeout, Format) ->
+ try
+ receive
+ {Status,History} ->
+ %% {test,is_tuple,{f,148},[{x,0}]}.
+ %% {test,test_arity,{f,148},[{x,0},2]}.
+ %% {get_tuple_element,{x,0},0,{y,1}}. %y1 is fragile.
+ %%
+ %% %% Here the fragility of y1 would be be progated to
+ %% %% the 'catch' below. Incorrect, since get_tuple_element
+ %% %% can't fail.
+ %% {get_tuple_element,{x,0},1,{x,2}}.
+ %%
+ %% remove_message. %y1 fragility cleared.
+ FH = case Format of
+ native ->
+ id(History);
+ plain ->
+ id(42)
+ end,
+ case Status of
+ ok ->
+ {ok,FH};
+ error ->
+ nok
+ end
+ after Timeout ->
+ timeout
+ end
+ catch
+ %% The fragility of y1 incorrectly propagated to here.
+ %% beam_validator would complain.
+ throw:{error,Reason} ->
+ {nok,Reason}
+ end.
+
+%% ERL-703. The compiler would crash because beam_utils:anno_defs/1
+%% failed to take into account that code after loop_rec_end is
+%% unreachable.
+
+double_recv(_Config) ->
+ self() ! {more,{a,term}},
+ ok = do_double_recv({more,{a,term}}, any),
+ self() ! message,
+ ok = do_double_recv(whatever, message),
+
+ error = do_double_recv({more,42}, whatever),
+ error = do_double_recv(whatever, whatever),
+ ok.
+
+do_double_recv({more, Rest}, _Msg) ->
+ receive
+ {more, Rest} ->
+ ok
+ after 0 ->
+ error
+ end;
+do_double_recv(_, Msg) ->
+ receive
+ Msg ->
+ ok
+ after 0 ->
+ error
+ end.
+
+%% Test 'after Z', when Z =:= 0 been propagated as an immediate by the type
+%% optimization pass.
+receive_var_zero(Config) when is_list(Config) ->
+ self() ! x,
+ self() ! y,
+ Z = zero(),
+ timeout = receive
+ z -> ok
+ after Z -> timeout
+ end,
+ timeout = receive
+ after Z -> timeout
+ end,
+ self() ! w,
+ receive
+ x -> ok;
+ Other ->
+ ct:fail({bad_message,Other})
+ end.
+
+zero() -> 0.
+
+%% ERL-862; the validator would explode when a term was constructed in a
+%% receive guard.
+
+-define(MATCH_BUILT_TERM(Ref, Expr),
+ (fun() ->
+ Ref = make_ref(),
+ A = id($a),
+ B = id($b),
+ Built = id(Expr),
+ self() ! {Ref, A, B},
+ receive
+ {Ref, A, B} when Expr =:= Built ->
+ ok
+ after 5000 ->
+ ct:fail("Failed to match message with term built in "
+ "receive guard.")
+ end
+ end)()).
+
+match_built_terms(Config) when is_list(Config) ->
+ ?MATCH_BUILT_TERM(Ref, [A, B]),
+ ?MATCH_BUILT_TERM(Ref, {A, B}),
+ ?MATCH_BUILT_TERM(Ref, <<A, B>>),
+ ?MATCH_BUILT_TERM(Ref, #{ 1 => A, 2 => B}).
+
id(I) -> I.
diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/no_5.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/no_5.erl
new file mode 100644
index 0000000000..4fbde3a83d
--- /dev/null
+++ b/lib/compiler/test/receive_SUITE_data/ref_opt/no_5.erl
@@ -0,0 +1,38 @@
+-module(no_5).
+-compile([export_all,nowarn_export_all]).
+
+?MODULE() ->
+ ok.
+
+%% Nested receives were not handled properly.
+
+confusing_recv_mark(Pid) ->
+ Ref = make_ref(),
+ %% There would be a recv_mark here.
+ MRef = erlang:monitor(process, Pid),
+ receive
+ Ref ->
+ %% And a recv_set here.
+ receive
+ MRef -> gurka
+ end;
+ MRef ->
+ gaffel
+ end.
+
+%% The optimization could potentially be improved to
+%% handle matching of multiple refs, like this:
+
+proper_recv_mark(Pid) ->
+ %% Place the recv_mark before the creation of both refs.
+ Ref = make_ref(),
+ MRef = erlang:monitor(process, Pid),
+ %% Place the recv_set here.
+ receive
+ Ref ->
+ receive
+ MRef -> gurka
+ end;
+ MRef ->
+ gaffel
+ end.
diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.S b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.S
deleted file mode 100644
index fd14228135..0000000000
--- a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.S
+++ /dev/null
@@ -1,71 +0,0 @@
-{module, yes_14}. %% version = 0
-
-{exports, [{f,2},{module_info,0},{module_info,1},{yes_14,0}]}.
-
-{attributes, []}.
-
-{labels, 12}.
-
-
-{function, yes_14, 0, 2}.
- {label,1}.
- {func_info,{atom,yes_14},{atom,yes_14},0}.
- {label,2}.
- {move,{atom,ok},{x,0}}.
- return.
-
-
-{function, f, 2, 4}.
- {label,3}.
- {func_info,{atom,yes_14},{atom,f},2}.
- {label,4}.
- {allocate_heap,2,3,2}.
- {move,{x,0},{y,1}}.
- {put_tuple,2,{y,0}}.
- {put,{atom,data}}.
- {put,{x,1}}.
- {call_ext,0,{extfunc,erlang,make_ref,0}}. % Ref in [x0]
- {test_heap,4,1}.
- {put_tuple,3,{x,1}}.
- {put,{atom,request}}.
- {put,{x,0}}.
- {put,{y,0}}.
- {move,{x,0},{y,0}}. % Ref in [x0,y0]
- {move,{y,1},{x,0}}. % Ref in [y0]
- {kill,{y,1}}.
- send.
- {move,{y,0},{x,0}}. % Ref in [x0,y0]
- {move,{x,0},{y,1}}. % Ref in [x0,y0,y1]
- {label,5}.
- {loop_rec,{f,7},{x,0}}. % Ref in [y0,y1]
- {test,is_tuple,{f,6},[{x,0}]}.
- {test,test_arity,{f,6},[{x,0},2]}.
- {get_tuple_element,{x,0},0,{x,1}}.
- {get_tuple_element,{x,0},1,{x,2}}.
- {test,is_eq_exact,{f,6},[{x,1},{atom,reply}]}.
- {test,is_eq_exact,{f,6},[{x,2},{y,1}]}.
- remove_message.
- {move,{atom,ok},{x,0}}.
- {deallocate,2}.
- return.
- {label,6}.
- {loop_rec_end,{f,5}}.
- {label,7}.
- {wait,{f,5}}.
-
-
-{function, module_info, 0, 9}.
- {label,8}.
- {func_info,{atom,yes_14},{atom,module_info},0}.
- {label,9}.
- {move,{atom,yes_14},{x,0}}.
- {call_ext_only,1,{extfunc,erlang,get_module_info,1}}.
-
-
-{function, module_info, 1, 11}.
- {label,10}.
- {func_info,{atom,yes_14},{atom,module_info},1}.
- {label,11}.
- {move,{x,0},{x,1}}.
- {move,{atom,yes_14},{x,0}}.
- {call_ext_only,2,{extfunc,erlang,get_module_info,2}}.
diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.erl
new file mode 100644
index 0000000000..aa47c02af9
--- /dev/null
+++ b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.erl
@@ -0,0 +1,27 @@
+-module(yes_14).
+-compile(export_all).
+
+?MODULE() ->
+ ok.
+
+do_call(Process, Request) ->
+ Mref = erlang:monitor(process, Process),
+ Process ! Request,
+ Local = case node(Process) of
+ Node when Node =:= node() -> true;
+ _Node -> false
+ end,
+ id(Local),
+ receive
+ {X,Y,Z} when Mref =/= X, Z =:= 42, Mref =:= Y ->
+ error;
+ {X,Y,_} when Mref =/= X, Mref =:= Y ->
+ error;
+ {Mref, Reply} ->
+ erlang:demonitor(Mref, [flush]),
+ {ok, Reply};
+ {'DOWN', Mref, _, _, _} ->
+ error
+ end.
+
+id(I) -> I.
diff --git a/lib/compiler/test/record_SUITE.erl b/lib/compiler/test/record_SUITE.erl
index 5546765f26..4ed7f39780 100644
--- a/lib/compiler/test/record_SUITE.erl
+++ b/lib/compiler/test/record_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -41,7 +41,6 @@ suite() ->
{timetrap,{minutes,2}}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -52,6 +51,7 @@ groups() ->
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/regressions_SUITE.erl b/lib/compiler/test/regressions_SUITE.erl
index 7a6fe08c73..39febf060f 100644
--- a/lib/compiler/test/regressions_SUITE.erl
+++ b/lib/compiler/test/regressions_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,13 +21,29 @@
-module(regressions_SUITE).
-include_lib("common_test/include/ct.hrl").
--export([all/0,groups/0,init_per_testcase/2,end_per_testcase/2,suite/0]).
+-export([all/0,groups/0,init_per_testcase/2,end_per_testcase/2,
+ init_per_group/2,end_per_group/2,
+ init_per_suite/1,end_per_suite/1,
+ suite/0]).
-export([maps/1]).
groups() ->
[{p,test_lib:parallel(),
[maps]}].
+init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
init_per_testcase(_Case, Config) ->
Config.
@@ -39,7 +55,6 @@ suite() ->
{timetrap,{minutes,2}}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
%%% test cases
diff --git a/lib/compiler/test/test_lib.erl b/lib/compiler/test/test_lib.erl
index 8954a9f5fb..3348c6e9ea 100644
--- a/lib/compiler/test/test_lib.erl
+++ b/lib/compiler/test/test_lib.erl
@@ -22,7 +22,8 @@
-include_lib("common_test/include/ct.hrl").
-compile({no_auto_import,[binary_part/2]}).
-export([id/1,recompile/1,parallel/0,uniq/0,opt_opts/1,get_data_dir/1,
- is_cloned_mod/1,smoke_disasm/1,p_run/2]).
+ is_cloned_mod/1,smoke_disasm/1,p_run/2,
+ highest_opcode/1]).
%% Used by test case that override BIFs.
-export([binary_part/2,binary/1]).
@@ -50,12 +51,8 @@ smoke_disasm(File) when is_list(File) ->
Res = beam_disasm:file(File),
{beam_file,_Mod} = {element(1, Res),element(2, Res)}.
-%% If we are running cover, we don't want to run test cases that
-%% invokes the compiler in parallel, as doing so would probably
-%% be slower than running them sequentially.
-
parallel() ->
- case test_server:is_cover() orelse erlang:system_info(schedulers) =:= 1 of
+ case erlang:system_info(schedulers) =:= 1 of
true -> [];
false -> [parallel]
end.
@@ -70,18 +67,24 @@ uniq() ->
opt_opts(Mod) ->
Comp = Mod:module_info(compile),
{options,Opts} = lists:keyfind(options, 1, Comp),
- lists:filter(fun(no_copt) -> true;
- (no_postopt) -> true;
- (no_float_opt) -> true;
- (no_new_funs) -> true;
- (no_new_binaries) -> true;
- (no_new_apply) -> true;
- (no_gc_bifs) -> true;
- (no_stack_trimming) -> true;
- (debug_info) -> true;
- (inline) -> true;
- (_) -> false
- end, Opts).
+ lists:filter(fun
+ (debug_info) -> true;
+ (inline) -> true;
+ (no_bsm3) -> true;
+ (no_bsm_opt) -> true;
+ (no_copt) -> true;
+ (no_fun_opt) -> true;
+ (no_module_opt) -> true;
+ (no_postopt) -> true;
+ (no_put_tuple2) -> true;
+ (no_recv_opt) -> true;
+ (no_share_opt) -> true;
+ (no_ssa_float) -> true;
+ (no_ssa_opt) -> true;
+ (no_stack_trimming) -> true;
+ (no_type_opt) -> true;
+ (_) -> false
+ end, Opts).
%% Some test suites gets cloned (e.g. to "record_SUITE" to
%% "record_no_opt_SUITE"), but the data directory is not cloned.
@@ -91,37 +94,40 @@ get_data_dir(Config) ->
Data0 = proplists:get_value(data_dir, Config),
Opts = [{return,list}],
Data1 = re:replace(Data0, "_no_opt_SUITE", "_SUITE", Opts),
- Data = re:replace(Data1, "_post_opt_SUITE", "_SUITE", Opts),
- re:replace(Data, "_inline_SUITE", "_SUITE", Opts).
+ Data2 = re:replace(Data1, "_post_opt_SUITE", "_SUITE", Opts),
+ Data3 = re:replace(Data2, "_inline_SUITE", "_SUITE", Opts),
+ Data4 = re:replace(Data3, "_r21_SUITE", "_SUITE", Opts),
+ Data = re:replace(Data4, "_no_module_opt_SUITE", "_SUITE", Opts),
+ re:replace(Data, "_no_ssa_opt_SUITE", "_SUITE", Opts).
is_cloned_mod(Mod) ->
is_cloned_mod_1(atom_to_list(Mod)).
%% Test whether Mod is a cloned module.
-is_cloned_mod_1("no_opt_SUITE") -> true;
-is_cloned_mod_1("post_opt_SUITE") -> true;
-is_cloned_mod_1("inline_SUITE") -> true;
+is_cloned_mod_1("_no_opt_SUITE") -> true;
+is_cloned_mod_1("_no_ssa_opt_SUITE") -> true;
+is_cloned_mod_1("_post_opt_SUITE") -> true;
+is_cloned_mod_1("_inline_SUITE") -> true;
+is_cloned_mod_1("_21_SUITE") -> true;
+is_cloned_mod_1("_no_module_opt_SUITE") -> true;
is_cloned_mod_1([_|T]) -> is_cloned_mod_1(T);
is_cloned_mod_1([]) -> false.
+%% Return the highest opcode use in the BEAM module.
+
+highest_opcode(Beam) ->
+ {ok,{_Mod,[{"Code",Code}]}} = beam_lib:chunks(Beam, ["Code"]),
+ FormatNumber = 0,
+ <<16:32,FormatNumber:32,HighestOpcode:32,_/binary>> = Code,
+ HighestOpcode.
+
%% p_run(fun(Data) -> ok|error, List) -> ok
%% Will fail the test case if there were any errors.
p_run(Test, List) ->
S = erlang:system_info(schedulers),
- N = case test_server:is_cover() of
- false ->
- S + 1;
- true ->
- %% Cover is running. Using too many processes
- %% could slow us down. Measurements on my computer
- %% showed that using 4 parallel processes was
- %% slightly faster than using 3. Using more than
- %% 4 would not buy us much and could actually be
- %% slower.
- min(S, 4)
- end,
+ N = S + 1,
io:format("p_run: ~p parallel processes\n", [N]),
p_run_loop(Test, List, N, [], 0, 0).
diff --git a/lib/compiler/test/trycatch_SUITE.erl b/lib/compiler/test/trycatch_SUITE.erl
index a591d6cc93..539f9d69fa 100644
--- a/lib/compiler/test/trycatch_SUITE.erl
+++ b/lib/compiler/test/trycatch_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,14 +26,15 @@
nested_of/1,nested_catch/1,nested_after/1,
nested_horrid/1,last_call_optimization/1,bool/1,
plain_catch_coverage/1,andalso_orelse/1,get_in_try/1,
- hockey/1,handle_info/1,catch_in_catch/1,grab_bag/1]).
+ hockey/1,handle_info/1,catch_in_catch/1,grab_bag/1,
+ stacktrace/1,nested_stacktrace/1,raise/1,
+ no_return_in_try_block/1]).
-include_lib("common_test/include/ct.hrl").
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -42,10 +43,13 @@ groups() ->
after_oops,eclectic,rethrow,nested_of,nested_catch,
nested_after,nested_horrid,last_call_optimization,
bool,plain_catch_coverage,andalso_orelse,get_in_try,
- hockey,handle_info,catch_in_catch,grab_bag]}].
+ hockey,handle_info,catch_in_catch,grab_bag,
+ stacktrace,nested_stacktrace,raise,
+ no_return_in_try_block]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -115,6 +119,16 @@ basic(Conf) when is_list(Conf) ->
catch nisse -> erro
end,
+ %% Unmatchable clauses.
+ try
+ throw(thrown)
+ catch
+ {a,b}={a,b,c} -> %Intentionally no match.
+ ok;
+ thrown ->
+ ok
+ end,
+
ok.
after_call() ->
@@ -324,11 +338,11 @@ eclectic(Conf) when is_list(Conf) ->
{{error,{exit,V},{'EXIT',V}},V} =
eclectic_1({foo,{error,{exit,V}}}, error, {value,V}),
{{value,{value,V},V},
- {'EXIT',{badarith,[{?MODULE,my_add,2,_}|_]}}} =
+ {'EXIT',{badarith,[{erlang,'+',[0,a],_},{?MODULE,my_add,2,_}|_]}}} =
eclectic_1({foo,{value,{value,V}}}, undefined, {'add',{0,a}}),
{{'EXIT',V},V} =
eclectic_1({catch_foo,{exit,V}}, undefined, {throw,V}),
- {{error,{'div',{1,0}},{'EXIT',{badarith,[{?MODULE,my_div,2,_}|_]}}},
+ {{error,{'div',{1,0}},{'EXIT',{badarith,[{erlang,'div',[1,0],_},{?MODULE,my_div,2,_}|_]}}},
{'EXIT',V}} =
eclectic_1({foo,{error,{'div',{1,0}}}}, error, {exit,V}),
{{{error,V},{'EXIT',{V,[{?MODULE,foo,1,_}|_]}}},
@@ -345,7 +359,7 @@ eclectic(Conf) when is_list(Conf) ->
eclectic_2({error,{value,V}}, throw, {error,V}),
{{caught,{'EXIT',{badarg,[{erlang,abs,[V],_}|_]}}},V} =
eclectic_2({value,{'abs',V}}, undefined, {value,V}),
- {{caught,{'EXIT',{badarith,[{?MODULE,my_add,2,_}|_]}}},V} =
+ {{caught,{'EXIT',{badarith,[{erlang,'+',[0,a],_},{?MODULE,my_add,2,_}|_]}}},V} =
eclectic_2({exit,{'add',{0,a}}}, exit, {value,V}),
{{caught,{'EXIT',V}},undefined} =
eclectic_2({value,{error,V}}, undefined, {exit,V}),
@@ -1039,5 +1053,262 @@ grab_bag(_Config) ->
ok.
+stacktrace(_Config) ->
+ V = [make_ref()|self()],
+ case ?MODULE:module_info(native) of
+ false ->
+ {value2,{caught1,badarg,[{erlang,abs,[V],_}|_]}} =
+ stacktrace_1({'abs',V}, error, {value,V}),
+ {caught2,{error,badarith},[{erlang,'+',[0,a],_},
+ {?MODULE,my_add,2,_}|_]} =
+ stacktrace_1({'div',{1,0}}, error, {'add',{0,a}});
+ true ->
+ {value2,{caught1,badarg,[{?MODULE,my_abs,1,_}|_]}} =
+ stacktrace_1({'abs',V}, error, {value,V}),
+ {caught2,{error,badarith},[{?MODULE,my_add,2,_}|_]} =
+ stacktrace_1({'div',{1,0}}, error, {'add',{0,a}})
+ end,
+ {caught2,{error,{try_clause,V}},[{?MODULE,stacktrace_1,3,_}|_]} =
+ stacktrace_1({value,V}, error, {value,V}),
+ {caught2,{throw,V},[{?MODULE,foo,1,_}|_]} =
+ stacktrace_1({value,V}, error, {throw,V}),
+
+ try
+ stacktrace_2()
+ catch
+ error:{badmatch,_}:Stk2 ->
+ [{?MODULE,stacktrace_2,0,_},
+ {?MODULE,stacktrace,1,_}|_] = Stk2,
+ Stk2 = erlang:get_stacktrace(),
+ ok
+ end,
+
+ try
+ stacktrace_3(a, b)
+ catch
+ error:function_clause:Stk3 ->
+ Stk3 = erlang:get_stacktrace(),
+ case lists:module_info(native) of
+ false ->
+ [{lists,prefix,[a,b],_}|_] = Stk3;
+ true ->
+ [{lists,prefix,2,_}|_] = Stk3
+ end
+ end,
+
+ try
+ throw(x)
+ catch
+ throw:x:IntentionallyUnused ->
+ ok
+ end.
+
+stacktrace_1(X, C1, Y) ->
+ try try foo(X) of
+ C1 -> value1
+ catch
+ C1:D1:Stk1 ->
+ Stk1 = erlang:get_stacktrace(),
+ {caught1,D1,Stk1}
+ after
+ foo(Y)
+ end of
+ V2 -> {value2,V2}
+ catch
+ C2:D2:Stk2 -> {caught2,{C2,D2},Stk2=erlang:get_stacktrace()}
+ end.
+
+stacktrace_2() ->
+ ok = erlang:process_info(self(), current_function),
+ ok.
+
+stacktrace_3(A, B) ->
+ {ok,lists:prefix(A, B)}.
+
+nested_stacktrace(_Config) ->
+ V = [{make_ref()}|[self()]],
+ value1 = nested_stacktrace_1({{value,{V,x1}},void,{V,x1}},
+ {void,void,void}),
+ case ?MODULE:module_info(native) of
+ false ->
+ {caught1,
+ [{erlang,'+',[V,x1],_},{?MODULE,my_add,2,_}|_],
+ value2} =
+ nested_stacktrace_1({{'add',{V,x1}},error,badarith},
+ {{value,{V,x2}},void,{V,x2}}),
+ {caught1,
+ [{erlang,'+',[V,x1],_},{?MODULE,my_add,2,_}|_],
+ {caught2,[{erlang,abs,[V],_}|_]}} =
+ nested_stacktrace_1({{'add',{V,x1}},error,badarith},
+ {{'abs',V},error,badarg});
+ true ->
+ {caught1,
+ [{?MODULE,my_add,2,_}|_],
+ value2} =
+ nested_stacktrace_1({{'add',{V,x1}},error,badarith},
+ {{value,{V,x2}},void,{V,x2}}),
+ {caught1,
+ [{?MODULE,my_add,2,_}|_],
+ {caught2,[{?MODULE,my_abs,1,_}|_]}} =
+ nested_stacktrace_1({{'add',{V,x1}},error,badarith},
+ {{'abs',V},error,badarg})
+ end,
+ ok.
+
+nested_stacktrace_1({X1,C1,V1}, {X2,C2,V2}) ->
+ try foo(X1) of
+ V1 -> value1
+ catch
+ C1:V1:S1 ->
+ S1 = erlang:get_stacktrace(),
+ T2 = try foo(X2) of
+ V2 -> value2
+ catch
+ C2:V2:S2 ->
+ S2 = erlang:get_stacktrace(),
+ {caught2,S2}
+ end,
+ {caught1,S1,T2}
+ end.
+
+raise(_Config) ->
+ test_raise(fun() -> exit({exit,tuple}) end),
+ test_raise(fun() -> abs(id(x)) end),
+ test_raise(fun() -> throw({was,thrown}) end),
+
+ badarg = bad_raise(fun() -> abs(id(x)) end),
+
+ ok.
+
+bad_raise(Expr) ->
+ try
+ Expr()
+ catch
+ _:E:Stk ->
+ erlang:raise(bad_class, E, Stk)
+ end.
+
+test_raise(Expr) ->
+ test_raise_1(Expr),
+ test_raise_2(Expr),
+ test_raise_3(Expr),
+ test_raise_4(Expr).
+
+test_raise_1(Expr) ->
+ erase(exception),
+ try
+ do_test_raise_1(Expr)
+ catch
+ C:E:Stk ->
+ {C,E,Stk} = erase(exception)
+ end.
+
+do_test_raise_1(Expr) ->
+ try
+ Expr()
+ catch
+ C:E:Stk ->
+ %% Here the stacktrace must be built.
+ put(exception, {C,E,Stk}),
+ erlang:raise(C, E, Stk)
+ end.
+
+test_raise_2(Expr) ->
+ erase(exception),
+ try
+ do_test_raise_2(Expr)
+ catch
+ C:E:Stk ->
+ {C,E} = erase(exception),
+ try
+ Expr()
+ catch
+ _:_:S ->
+ [StkTop|_] = S,
+ [StkTop|_] = Stk
+ end
+ end.
+
+do_test_raise_2(Expr) ->
+ try
+ Expr()
+ catch
+ C:E:Stk ->
+ %% Here it is possible to replace erlang:raise/3 with
+ %% the raw_raise/3 instruction since the stacktrace is
+ %% not actually used.
+ put(exception, {C,E}),
+ erlang:raise(C, E, Stk)
+ end.
+
+test_raise_3(Expr) ->
+ try
+ do_test_raise_3(Expr)
+ catch
+ exit:{exception,C,E}:Stk ->
+ try
+ Expr()
+ catch
+ C:E:S ->
+ [StkTop|_] = S,
+ [StkTop|_] = Stk
+ end
+ end.
+
+do_test_raise_3(Expr) ->
+ try
+ Expr()
+ catch
+ C:E:Stk ->
+ %% Here it is possible to replace erlang:raise/3 with
+ %% the raw_raise/3 instruction since the stacktrace is
+ %% not actually used.
+ erlang:raise(exit, {exception,C,E}, Stk)
+ end.
+
+test_raise_4(Expr) ->
+ try
+ do_test_raise_4(Expr)
+ catch
+ exit:{exception,C,E,Stk}:Stk ->
+ try
+ Expr()
+ catch
+ C:E:S ->
+ [StkTop|_] = S,
+ [StkTop|_] = Stk
+ end
+ end.
+
+do_test_raise_4(Expr) ->
+ try
+ Expr()
+ catch
+ C:E:Stk ->
+ %% Here the stacktrace must be built.
+ erlang:raise(exit, {exception,C,E,Stk}, Stk)
+ end.
+
+no_return_in_try_block(Config) when is_list(Config) ->
+ 1.0 = no_return_in_try_block_1(0),
+ 1.0 = no_return_in_try_block_1(0.0),
+
+ gurka = no_return_in_try_block_1(gurka),
+ [] = no_return_in_try_block_1([]),
+
+ ok.
+
+no_return_in_try_block_1(H) ->
+ try
+ Float = if
+ is_number(H) -> float(H);
+ true -> no_return()
+ end,
+ Float + 1
+ catch
+ throw:no_return -> H
+ end.
+
+no_return() -> throw(no_return).
id(I) -> I.
diff --git a/lib/compiler/test/warnings_SUITE.erl b/lib/compiler/test/warnings_SUITE.erl
index 857995b6a6..70b7100451 100644
--- a/lib/compiler/test/warnings_SUITE.erl
+++ b/lib/compiler/test/warnings_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -42,7 +42,7 @@
comprehensions/1,maps/1,maps_bin_opt_info/1,
redundant_boolean_clauses/1,
latin1_fallback/1,underscore/1,no_warnings/1,
- bit_syntax/1,inlining/1]).
+ bit_syntax/1,inlining/1,tuple_calls/1]).
init_per_testcase(_Case, Config) ->
Config.
@@ -55,7 +55,6 @@ suite() ->
{timetrap,{minutes,2}}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -65,9 +64,11 @@ groups() ->
bin_opt_info,bin_construction,comprehensions,maps,
maps_bin_opt_info,
redundant_boolean_clauses,latin1_fallback,
- underscore,no_warnings,bit_syntax,inlining]}].
+ underscore,no_warnings,bit_syntax,inlining,
+ tuple_calls]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -239,19 +240,7 @@ guard(Config) when is_list(Config) ->
{4,sys_core_fold,nomatch_guard},
{6,sys_core_fold,no_clause_match},
{6,sys_core_fold,nomatch_guard},
- {6,sys_core_fold,{eval_failure,badarg}},
- {8,sys_core_fold,no_clause_match},
- {8,sys_core_fold,nomatch_guard},
- {8,sys_core_fold,{eval_failure,badarg}},
- {9,sys_core_fold,no_clause_match},
- {9,sys_core_fold,nomatch_guard},
- {9,sys_core_fold,{eval_failure,badarg}},
- {10,sys_core_fold,no_clause_match},
- {10,sys_core_fold,nomatch_guard},
- {10,sys_core_fold,{eval_failure,badarg}},
- {11,sys_core_fold,no_clause_match},
- {11,sys_core_fold,nomatch_guard},
- {11,sys_core_fold,{eval_failure,badarg}}
+ {6,sys_core_fold,{eval_failure,badarg}}
]}}],
[] = run(Config, Ts),
@@ -522,25 +511,43 @@ bin_opt_info(Config) when is_list(Config) ->
<<>> -> ok
end.
+ %% We use a tail in a BIF instruction, remote call, function
+ %% return, and an optimizable tail call for better coverage.
+ t2(<<A,B,T/bytes>>) ->
+ if
+ A > B -> t2(T);
+ A =< B -> T
+ end;
+ t2(<<_,T/bytes>>) when byte_size(T) < 4 ->
+ foo;
t2(<<_,T/bytes>>) ->
- split_binary(T, 4).
+ split_binary(T, 4).
">>,
- Ts1 = [{bsm1,
- Code,
- [bin_opt_info],
- {warnings,
- [{4,sys_core_bsm,orig_bin_var_used_in_guard},
- {5,beam_bsm,{no_bin_opt,{{t1,1},no_suitable_bs_start_match}}},
- {9,beam_bsm,{no_bin_opt,
- {binary_used_in,{extfunc,erlang,split_binary,2}}}} ]}}],
- [] = run(Config, Ts1),
+
+ Ws = (catch run_test(Config, Code, [bin_opt_info])),
+
+ %% This is an inexact match since the pass reports exact instructions as
+ %% part of the warnings, which may include annotations that vary from run
+ %% to run.
+ {warnings,
+ [{5,beam_ssa_bsm,{unsuitable_call,
+ {{b_local,{b_literal,t1},1},
+ {used_before_match,
+ {b_set,_,_,{bif,byte_size},[_]}}}}},
+ {5,beam_ssa_bsm,{binary_created,_,_}},
+ {11,beam_ssa_bsm,{binary_created,_,_}}, %% A =< B -> T
+ {13,beam_ssa_bsm,context_reused}, %% A > B -> t2(T);
+ {16,beam_ssa_bsm,{binary_created,_,_}}, %% when byte_size(T) < 4 ->
+ {19,beam_ssa_bsm,{remote_call,
+ {b_remote,
+ {b_literal,erlang},
+ {b_literal,split_binary},2}}},
+ {19,beam_ssa_bsm,{binary_created,_,_}} %% split_binary(T, 4)
+ ]} = Ws,
%% For coverage: don't give the bin_opt_info option.
- Ts2 = [{bsm2,
- Code,
- [],
- []}],
- [] = run(Config, Ts2),
+ [] = (catch run_test(Config, Code, [])),
+
ok.
bin_construction(Config) when is_list(Config) ->
@@ -746,7 +753,7 @@ maps_bin_opt_info(Config) when is_list(Config) ->
M.
">>,
[bin_opt_info],
- {warnings,[{2,beam_bsm,bin_opt}]}}],
+ {warnings,[{3,beam_ssa_bsm,context_reused}]}}],
[] = run(Config, Ts),
ok.
@@ -952,6 +959,20 @@ inlining(Config) ->
run(Config, Ts),
ok.
+tuple_calls(Config) ->
+ %% Make sure that no spurious warnings are generated.
+ Ts = [{inlining_1,
+ <<"-compile(tuple_calls).
+ dispatch(X) ->
+ (list_to_atom(\"prefix_\" ++
+ atom_to_list(suffix))):doit(X).
+ ">>,
+ [],
+ []}
+ ],
+ run(Config, Ts),
+ ok.
+
%%%
%%% End of test cases.
%%%
@@ -969,7 +990,6 @@ run(Config, Tests) ->
end,
lists:foldl(F, [], Tests).
-
%% Compiles a test module and returns the list of errors and warnings.
run_test(Conf, Test0, Warnings) ->
diff --git a/lib/compiler/test/z_SUITE.erl b/lib/compiler/test/z_SUITE.erl
index d864184f4c..bfa8e279e8 100644
--- a/lib/compiler/test/z_SUITE.erl
+++ b/lib/compiler/test/z_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,13 +26,13 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[loaded].
groups() ->
[].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -54,8 +54,7 @@ do_loaded([{M,_}|Ms], E0) ->
_ = M:module_info(functions),
E0
catch
- C:Error ->
- Stk = erlang:get_stacktrace(),
+ C:Error:Stk ->
io:format("~p:~p\n~p\n", [C,Error,Stk]),
E0 + 1
end,
diff --git a/lib/compiler/vsn.mk b/lib/compiler/vsn.mk
index ee75ee27fd..494de072ff 100644
--- a/lib/compiler/vsn.mk
+++ b/lib/compiler/vsn.mk
@@ -1 +1 @@
-COMPILER_VSN = 7.1.5
+COMPILER_VSN = 7.4
diff --git a/lib/configure.in.src b/lib/configure.in.src
deleted file mode 100644
index d507a5c0dd..0000000000
--- a/lib/configure.in.src
+++ /dev/null
@@ -1,62 +0,0 @@
-dnl
-dnl %CopyrightBegin%
-dnl
-dnl Copyright Ericsson AB 1999-2016. All Rights Reserved.
-dnl
-dnl Licensed under the Apache License, Version 2.0 (the "License");
-dnl you may not use this file except in compliance with the License.
-dnl You may obtain a copy of the License at
-dnl
-dnl http://www.apache.org/licenses/LICENSE-2.0
-dnl
-dnl Unless required by applicable law or agreed to in writing, software
-dnl distributed under the License is distributed on an "AS IS" BASIS,
-dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-dnl See the License for the specific language governing permissions and
-dnl limitations under the License.
-dnl
-dnl %CopyrightEnd%
-dnl
-
-dnl Turn off caching
-define([AC_CACHE_LOAD], )dnl
-define([AC_CACHE_SAVE], )dnl
-
-dnl Process this file with autoconf to produce a configure script.
-AC_INIT
-
-dnl
-dnl This is just to run configure in all applications that need it.
-dnl
-
-if test -z "$ERL_TOP" || test ! -d $ERL_TOP ; then
- AC_MSG_ERROR(You need to set the environment variable ERL_TOP!)
-fi
-erl_top=${ERL_TOP}
-AC_CONFIG_AUX_DIRS($erl_top/erts/autoconf)
-
-AC_ARG_ENABLE(bootstrap-only,
-[ --enable-bootstrap-only enable bootstrap only configuration],
-[ if test "X$enableval" = "Xyes"; then
- bootstrap_only=yes
- else
- bootstrap_only=no
- fi
-],
-bootstrap_only=no)
-
-# Multiple versions of autoconf generates code that
-# don't work on all platforms (e.g. SunOS 5.8) if
-# sub directories are soft links. Internally at Ericsson
-# some OTP application directories are soft links.
-# An added "/." solves this problem.
-
-@BOOTSTRAP_CONFIGURE_APPS@
-
-if test $bootstrap_only = no; then
-
-@NON_BOOTSTRAP_CONFIGURE_APPS@
-
-fi
-
-AC_OUTPUT
diff --git a/lib/cosEvent/AUTHORS b/lib/cosEvent/AUTHORS
deleted file mode 100644
index 624d275f78..0000000000
--- a/lib/cosEvent/AUTHORS
+++ /dev/null
@@ -1,5 +0,0 @@
-Original Authors:
-Niclas Eklund
-
-Contributors:
-
diff --git a/lib/cosEvent/Makefile b/lib/cosEvent/Makefile
deleted file mode 100644
index 276b7bd865..0000000000
--- a/lib/cosEvent/Makefile
+++ /dev/null
@@ -1,42 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1999-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include vsn.mk
-VSN=$(COSEVENT_VSN)
-
-# ----------------------------------------------------
-# Common Macros
-# ----------------------------------------------------
-
-SUB_DIRECTORIES = src doc/src
-
-SPECIAL_TARGETS =
-
-# ----------------------------------------------------
-# Default Subdir Targets
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_subdir.mk
-
diff --git a/lib/cosEvent/doc/src/CosEventChannelAdmin.xml b/lib/cosEvent/doc/src/CosEventChannelAdmin.xml
deleted file mode 100644
index 29336c1878..0000000000
--- a/lib/cosEvent/doc/src/CosEventChannelAdmin.xml
+++ /dev/null
@@ -1,78 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1997</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>CosEventChannelAdmin</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>1997-11-13</date>
- <rev>PA1</rev>
- <file>CosEventChannelAdmin.xml</file>
- </header>
- <module>CosEventChannelAdmin</module>
- <modulesummary>The CosEventChannelAdmin defines a set if event service interfaces that enables decoupled asynchronous communication between objects and implements generic (untyped) version of the OMG COSS standard event service.</modulesummary>
- <description>
- <p>The event service defines two roles for objects: the supplier role and
- the consumer role. Suppliers supply event data to the event channel and
- consumers receive event data from the channel. Suppliers do not need to
- know the identity of the consumers, and vice versa. Consumers and
- suppliers are connected to the event channel via proxies, which are managed
- by ConsumerAdmin and SupplierAdmin objects.</p>
- <p>There are four general models of communication. These are: </p>
- <list type="bulleted">
- <item>The canonical push model. It allows the suppliers of events to initiate the
- transfer of event data to consumers. Event channels play the role of
- <c><![CDATA[Notifier]]></c>. Active suppliers use event channel to push data to
- passive consumers registered with the event channel.</item>
- <item>The canonical pull model. It allows consumers to request events from
- suppliers. Event channels play the role of <c><![CDATA[Procure]]></c> since they
- procure events on behalf of consumers. Active consumers can explicitly
- pull data from passive suppliers via the event channels.</item>
- <item>The hybrid push/pull model. It allows consumers request events queued at
- a channel by suppliers. Event channels play the role of <c><![CDATA[Queue]]></c>.
- Active consumers explicitly pull data deposited by active suppliers via
- the event channels.</item>
- <item>The hybrid pull/push model. It allows the channel to pull events from
- suppliers and push them to consumers. Event channels play the role of
- <c><![CDATA[Intelligent agent]]></c>. Active event channels can pull data from
- passive suppliers to push it to passive consumers.</item>
- </list>
- <p>To get access to all definitions, e.g., exceptions,
- include necessary <c><![CDATA[hrl]]></c> files by using:<br></br><c><![CDATA[-include_lib("cosEvent/include/*.hrl").]]></c></p>
- <p>There are seven different interfaces supported in the service:</p>
- <list type="bulleted">
- <item>ProxyPushConsumer</item>
- <item>ProxyPullSupplier</item>
- <item>ProxyPullConsumer</item>
- <item>ProxyPushSupplier</item>
- <item>ConsumerAdmin</item>
- <item>SupplierAdmin</item>
- <item>EventChannel</item>
- </list>
- </description>
-
-</erlref>
-
diff --git a/lib/cosEvent/doc/src/CosEventChannelAdmin_ConsumerAdmin.xml b/lib/cosEvent/doc/src/CosEventChannelAdmin_ConsumerAdmin.xml
deleted file mode 100644
index 80d36ba5c5..0000000000
--- a/lib/cosEvent/doc/src/CosEventChannelAdmin_ConsumerAdmin.xml
+++ /dev/null
@@ -1,73 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1997</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosEventChannelAdmin_ConsumerAdmin</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>1997-11-13</date>
- <rev>PA1</rev>
- <file>CosEventChannelAdmin_ConsumerAdmin.xml</file>
- </header>
- <module>CosEventChannelAdmin_ConsumerAdmin</module>
- <modulesummary>This module implements a ConsumerAdmin interface, which allows consumers to be connected to the event channel.</modulesummary>
- <description>
- <p>The ConsumerAdmin interface defines the first step for connecting consumers
- to the event channel. It acts as a factory for creating proxy suppliers.
- Both consumer administration and supplier administration are defined as separate
- objects so that the creator of the channel can control the addition of
- suppliers and consumers. </p>
- <p>To get access to all definitions include necessary <c><![CDATA[hrl]]></c> files by using:<br></br><c><![CDATA[-include_lib("cosEvent/include/*.hrl").]]></c></p>
- </description>
- <funcs>
- <func>
- <name>obtain_push_supplier(Object) -> Return</name>
- <fsummary>Create a ProxyPushSupplier object</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>Return = #objref</v>
- </type>
- <desc>
- <p>This operation returns a ProxyPushSupplier object reference.</p>
- </desc>
- </func>
- <func>
- <name>obtain_pull_supplier(Object) -> Return</name>
- <fsummary>Create a ProxyPullSupplier object</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>Return = #objref</v>
- </type>
- <desc>
- <p>This operation returns a ProxyPullSupplier object reference.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosEvent/doc/src/CosEventChannelAdmin_EventChannel.xml b/lib/cosEvent/doc/src/CosEventChannelAdmin_EventChannel.xml
deleted file mode 100644
index f32e742240..0000000000
--- a/lib/cosEvent/doc/src/CosEventChannelAdmin_EventChannel.xml
+++ /dev/null
@@ -1,95 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1997</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosEventChannelAdmin_EventChannel</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>1997-11-13</date>
- <rev>PA1</rev>
- <file>CosEventChannelAdmin_EventChannel.xml</file>
- </header>
- <module>CosEventChannelAdmin_EventChannel</module>
- <modulesummary>This module implements an Event Channel interface, which plays the role of a mediator between consumers and suppliers.</modulesummary>
- <description>
- <p>An event channel is an object that allows multiple suppliers to communicate
- with multiple consumers in a highly decoupled, asynchronous manner. The event
- channel is built up incrementally. When an event channel is
- created no suppliers or consumers are connected to it. Event Channel can
- implement group communication by serving as a replicator, broadcaster, or
- multicaster that forward events from one or more suppliers to multiple
- consumers.</p>
- <p>It is up to the user to decide when an event channel is created and how
- references to the event channel are obtained. By representing the event
- channel as an object, it has all of the properties that apply to objects.
- One way to manage an event channel is to register it in a naming context,
- or export it through an operation on an object.</p>
- <p>To get access to all definitions include necessary <c><![CDATA[hrl]]></c> files by using:<br></br><c><![CDATA[-include_lib("cosEvent/include/*.hrl").]]></c></p>
- <p>Any object that possesses an object reference that supports the ProxyPullConsumer
- interface can perform the following operations:</p>
- </description>
- <funcs>
- <func>
- <name>for_consumers(Object) -> Return</name>
- <fsummary>Return a ConsumerAdmin object</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>Return = #objref</v>
- </type>
- <desc>
- <p>This operation returns a ConsumerAdmin object reference. If ConsumerAdmin
- object does not exist already it creates one.</p>
- </desc>
- </func>
- <func>
- <name>for_suppliers(Object) -> Return</name>
- <fsummary>Return a SupplierAdmin object</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>Return = #objref</v>
- </type>
- <desc>
- <p>This operation returns a SupplierAdmin object reference. If SupplierAdmin
- object does not exist already it creates one.</p>
- </desc>
- </func>
- <func>
- <name>destroy(Object) -> Return</name>
- <fsummary>Destroy the event channel</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>Return = #objref</v>
- </type>
- <desc>
- <p></p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPullConsumer.xml b/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPullConsumer.xml
deleted file mode 100644
index 83bf8acbf2..0000000000
--- a/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPullConsumer.xml
+++ /dev/null
@@ -1,85 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1997</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosEventChannelAdmin_ProxyPullConsumer</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>1997-11-13</date>
- <rev>PA1</rev>
- <file>CosEventChannelAdmin_ProxyPullConsumer.xml</file>
- </header>
- <module>CosEventChannelAdmin_ProxyPullConsumer</module>
- <modulesummary>This module implements a ProxyPullConsumer interface which acts as a middleman between pull supplier and the event channel.</modulesummary>
- <description>
- <p>The ProxyPullConsumer interface defines the second step for connecting pull
- suppliers to the event channel. A proxy consumer is similar to a normal consumer,
- but includes an additional method for connecting a supplier to the proxy
- consumer.</p>
- <p>To get access to all definitions, e.g., exceptions,
- include necessary <c><![CDATA[hrl]]></c> files by using:<br></br><c><![CDATA[-include_lib("cosEvent/include/*.hrl").]]></c></p>
- <p>Any object that possesses an object reference that supports the ProxyPullConsumer
- interface can perform the following operations:</p>
- </description>
- <funcs>
- <func>
- <name>connect_pull_supplier(Object, PullSupplier) -> Return</name>
- <fsummary>Connect the pull supplier to the proxy pull consumer</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>PullSupplier = #objref of PullSupplier type</v>
- <v>Return = ok | {'EXCEPTION', E}</v>
- <v>E = #'CosEventChannelAdmin_AlreadyConnected'{} | #'CosEventChannelAdmin_TypeError'{}</v>
- </type>
- <desc>
- <p>This operation connects PullSupplier object to the ProxyPullConsumer object.
- If a nil object reference is passed CORBA standard <c><![CDATA[BAD_PARAM]]></c> exception
- is raised. If the ProxyPullConsumer is already connected to a PullSupplier,
- then the <c><![CDATA[CosEventChannelAdmin_AlreadyConnected]]></c> exception is raised.
- Implementations of ProxyPullConsumers may require additional interface
- functionality; if these requirements are not met the
- <c><![CDATA[CosEventChannelAdmin_TypeError]]></c> exception will be raised.</p>
- </desc>
- </func>
- <func>
- <name>disconnect_pull_consumer(Object) -> Return</name>
- <fsummary>Disconnect the ProxyPullConsumer object from the event channel.</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>Return = ok</v>
- </type>
- <desc>
- <p>This operation disconnects proxy pull consumer from the event channel and
- sends a notification about the loss of the connection to the pull supplier
- attached to it.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPullSupplier.xml b/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPullSupplier.xml
deleted file mode 100644
index 0060e71e2b..0000000000
--- a/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPullSupplier.xml
+++ /dev/null
@@ -1,112 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1997</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosEventChannelAdmin_ProxyPullSupplier</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved>Lars Thors</approved>
- <checked></checked>
- <date>1997-11-13</date>
- <rev>PA1</rev>
- <file>CosEventChannelAdmin_ProxyPullSupplier.xml</file>
- </header>
- <module>CosEventChannelAdmin_ProxyPullSupplier</module>
- <modulesummary>This module implements a ProxyPullSupplier interface which acts as a middleman between pull consumer and the event channel.</modulesummary>
- <description>
- <p>The ProxyPullSupplier interface defines the second step for connecting pull consumers to the event channel. A proxy supplier is similar to a normal supplier,
- but includes an additional method for connecting a consumer to the proxy
- supplier.</p>
- <p>To get access to all definitions, e.g., exceptions,
- include necessary <c><![CDATA[hrl]]></c> files by using:<br></br><c><![CDATA[-include_lib("cosEvent/include/*.hrl").]]></c></p>
- <p>Any object that possesses an object reference that supports the ProxyPullSupplier
- interface can perform the following operations:</p>
- </description>
- <funcs>
- <func>
- <name>connect_pull_consumer(Object, PullConsumer) -> Return</name>
- <fsummary>Connect the pull consumer to the proxy pull supplier</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>PullConsumer = #objref of PullConsumer type</v>
- <v>Return = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}}</v>
- </type>
- <desc>
- <p>This operation connects PullConsumer object to the ProxyPullSupplier object.
- A nil object reference can be passed to this operation. If so a channel
- cannot invoke the disconnect_pull_consumer operation on the consumer;
- the consumer may be disconnected from the channel without being
- informed. If the ProxyPullSupplier is already connected to a
- PullConsumer, then the <c><![CDATA[CosEventChannelAdmin_AlreadyConnected]]></c>
- exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>disconnect_pull_supplier(Object) -> Return</name>
- <fsummary>Disconnect the ProxyPullSupplier object from the event channel.</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>Return = ok</v>
- </type>
- <desc>
- <p>This operation disconnects proxy pull supplier from the event channel.
- It sends a notification about the loss of the connection to the pull consumer
- attached to it, unless nil object reference was passed at the connection
- time.</p>
- </desc>
- </func>
- <func>
- <name>pull(Object) -> Return</name>
- <fsummary>Transmit data from suppliers to consumers.</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>Return = any</v>
- </type>
- <desc>
- <p>This operation blocks until the event data is available or the
- <c><![CDATA[CosEventComm_Disconnected]]></c> exception is raised.
- It returns the event data to the consumer.</p>
- </desc>
- </func>
- <func>
- <name>try_pull(Object) -> Return</name>
- <fsummary>Transmit data from suppliers to consumers.</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>Return = {any, bool()}</v>
- </type>
- <desc>
- <p>This operation does not block: if the event data is available, it returns
- the event data and sets the data availability flag to true; otherwise
- it returns a long with an undefined value and sets the data availability to
- false. If the event communication has already been disconnected, the
- <c><![CDATA[CosEventComm_Disconnected]]></c> exception is raised.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPushConsumer.xml b/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPushConsumer.xml
deleted file mode 100644
index 9f19d001f9..0000000000
--- a/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPushConsumer.xml
+++ /dev/null
@@ -1,99 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1997</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosEventChannelAdmin_ProxyPushConsumer</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>1997-11-13</date>
- <rev>PA1</rev>
- <file>CosEventChannelAdmin_ProxyPushConsumer.xml</file>
- </header>
- <module>CosEventChannelAdmin_ProxyPushConsumer</module>
- <modulesummary>This module implements a ProxyPushConsumer interface which acts as a middleman between push supplier and the event channel.</modulesummary>
- <description>
- <p>The ProxyPushConsumer interface defines the second step for connecting push
- suppliers to the event channel. A proxy consumer is similar to a normal consumer,
- but includes an additional method for connecting a supplier to the proxy
- consumer.</p>
- <p>To get access to all definitions, e.g., exceptions,
- include necessary <c><![CDATA[hrl]]></c> files by using:<br></br><c><![CDATA[-include_lib("cosEvent/include/*.hrl").]]></c></p>
- <p>Any object that possesses an object reference that supports the ProxyPushConsumer
- interface can perform the following operations:</p>
- </description>
- <funcs>
- <func>
- <name>connect_push_supplier(Object, PushSupplier) -> Return</name>
- <fsummary>Connect the push supplier to the proxy push consumer</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>PushSupplier = #objref of PushSupplier type</v>
- <v>Return = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}}</v>
- </type>
- <desc>
- <p>This operation connects PushSupplier object to the ProxyPushConsumer object.
- A nil object reference can be passed to this operation. If so a channel
- cannot invoke the disconnect_push_supplier operation on the supplier;
- the supplier may be disconnected from the channel without being
- informed. If the ProxyPushConsumer is already connected to a
- PushSupplier, then the <c><![CDATA[CosEventChannelAdmin_AlreadyConnected]]></c>
- exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>disconnect_push_consumer(Object) -> Return</name>
- <fsummary>Disconnect the ProxyPushConsumer object from the event channel.</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>Return = ok</v>
- </type>
- <desc>
- <p>This operation disconnects proxy push consumer from the event channel.
- Sends a notification about the loss of the connection to the push supplier
- attached to it, unless nil object reference was passed at the connection
- time.</p>
- </desc>
- </func>
- <func>
- <name>push(Object, Data) -> Return</name>
- <fsummary>Communicate event data to the consumers.</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>Data = any</v>
- <v>Return = ok | {'EXCEPTION', #'CosEventComm_Disconnected'{}}</v>
- </type>
- <desc>
- <p>This operation sends event data to all connected consumers via the
- event channel. If the event communication has already been disconnected,
- the <c><![CDATA[CosEventComm_Disconnected]]></c> is raised.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPushSupplier.xml b/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPushSupplier.xml
deleted file mode 100644
index 2b1098b9a7..0000000000
--- a/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPushSupplier.xml
+++ /dev/null
@@ -1,85 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1997</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosEventChannelAdmin_ProxyPushSupplier</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>1997-11-13</date>
- <rev>PA1</rev>
- <file>CosEventChannelAdmin_ProxyPushSupplier.xml</file>
- </header>
- <module>CosEventChannelAdmin_ProxyPushSupplier</module>
- <modulesummary>This module implements a ProxyPushSupplier interface which acts as a middleman between push consumer and the event channel.</modulesummary>
- <description>
- <p>The ProxyPushSupplier interface defines the second step for connecting push
- consumers to the event channel. A proxy supplier is similar to a normal supplier,
- but includes an additional method for connecting a consumer to the proxy
- supplier.</p>
- <p>To get access to all definitions, e.g., exceptions,
- include necessary <c><![CDATA[hrl]]></c> files by using:<br></br><c><![CDATA[-include_lib("cosEvent/include/*.hrl").]]></c></p>
- <p>Any object that possesses an object reference that supports the ProxyPushSupplier
- interface can perform the following operations:</p>
- </description>
- <funcs>
- <func>
- <name>connect_push_consumer(Object, PushConsumer) -> Return</name>
- <fsummary>Connect the push consumer to the proxy push supplier</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>PushConsumer = #objref of PushConsumer type</v>
- <v>Return = ok | {'EXCEPTION', E}</v>
- <v>E = #'CosEventChannelAdmin_AlreadyConnected'{} | #'CosEventChannelAdmin_TypeError'{}</v>
- </type>
- <desc>
- <p>This operation connects PushConsumer object to the ProxyPushSupplier object.
- If a nil object reference is passed CORBA standard <c><![CDATA[BAD_PARAM]]></c> exception
- is raised. If the ProxyPushSupplier is already connected to a PushConsumer,
- then the <c><![CDATA[CosEventChannelAdmin_AlreadyConnected]]></c> exception is raised.
- Implementations of ProxyPushSuppliers may require additional interface
- functionality; if these requirements are not met the
- <c><![CDATA[CosEventChannelAdmin_TypeError]]></c> exception will be raised.</p>
- </desc>
- </func>
- <func>
- <name>disconnect_push_supplier(Object) -> Return</name>
- <fsummary>Disconnect the ProxyPushSupplier object from the event channel.</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>Return = ok</v>
- </type>
- <desc>
- <p>This operation disconnects proxy push supplier from the event channel and
- sends a notification about the loss of the connection to the push consumer
- attached to it.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosEvent/doc/src/CosEventChannelAdmin_SupplierAdmin.xml b/lib/cosEvent/doc/src/CosEventChannelAdmin_SupplierAdmin.xml
deleted file mode 100644
index 2a58c0a873..0000000000
--- a/lib/cosEvent/doc/src/CosEventChannelAdmin_SupplierAdmin.xml
+++ /dev/null
@@ -1,73 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1997</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosEventChannelAdmin_SupplierAdmin</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>1997-11-13</date>
- <rev>PA1</rev>
- <file>CosEventChannelAdmin_SupplierAdmin.xml</file>
- </header>
- <module>CosEventChannelAdmin_SupplierAdmin</module>
- <modulesummary>This module implements a SupplierAdmin interface, which allows suppliers to be connected to the event channel.</modulesummary>
- <description>
- <p>The SupplierAdmin interface defines the first step for connecting suppliers
- to the event channel. It acts as a factory for creating proxy consumers.
- Both consumer administration and supplier administration are defined as separate
- objects so that the creator of the channel can control the addition of
- suppliers and consumers.</p>
- <p>To get access to all definitions include necessary <c><![CDATA[hrl]]></c> files by using:<br></br><c><![CDATA[-include_lib("cosEvent/include/*.hrl").]]></c></p>
- </description>
- <funcs>
- <func>
- <name>obtain_push_consumer(Object) -> Return</name>
- <fsummary>Create a ProxyPushConsumer object</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>Return = #objref</v>
- </type>
- <desc>
- <p>This operation returns a ProxyPushConsumer object reference.</p>
- </desc>
- </func>
- <func>
- <name>obtain_pull_consumer(Object) -> Return</name>
- <fsummary>Create a ProxyPullConsumer object</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>Return = #objref</v>
- </type>
- <desc>
- <p>This operation returns a ProxyPullConsumer object reference.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosEvent/doc/src/Makefile b/lib/cosEvent/doc/src/Makefile
deleted file mode 100644
index 4fcb210e5a..0000000000
--- a/lib/cosEvent/doc/src/Makefile
+++ /dev/null
@@ -1,145 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1999-2017. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../../vsn.mk
-VSN=$(COSEVENT_VSN)
-APPLICATION=cosEvent
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-XML_APPLICATION_FILES = ref_man.xml
-XML_REF3_FILES = \
- CosEventChannelAdmin.xml \
- CosEventChannelAdmin_ConsumerAdmin.xml \
- CosEventChannelAdmin_SupplierAdmin.xml \
- CosEventChannelAdmin_EventChannel.xml \
- CosEventChannelAdmin_ProxyPullConsumer.xml \
- CosEventChannelAdmin_ProxyPullSupplier.xml \
- CosEventChannelAdmin_ProxyPushConsumer.xml \
- CosEventChannelAdmin_ProxyPushSupplier.xml \
- cosEventApp.xml
-
-XML_PART_FILES = \
- part.xml
-XML_CHAPTER_FILES = \
- ch_contents.xml \
- ch_introduction.xml \
- ch_event_service.xml \
- notes.xml
-
-BOOK_FILES = book.xml
-
-XML_FILES = $(BOOK_FILES) $(XML_APPLICATION_FILES) $(XML_REF3_FILES) \
- $(XML_PART_FILES) $(XML_CHAPTER_FILES)
-
-TECHNICAL_DESCR_FILES =
-
-GIF_FILES = \
- e_s_components.gif \
- e_s_models.gif
-
-
-PS_FILES =
-
-
-# ----------------------------------------------------
-
-INTERNAL_HTML_FILES = $(TECHNICAL_DESCR_FILES:%.xml=$(HTMLDIR)/%.html)
-
-HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \
- $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html)
-
-INFO_FILE = ../../info
-EXTRA_FILES = \
- $(DEFAULT_GIF_FILES) \
- $(DEFAULT_HTML_FILES) \
- $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html) \
- $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html)
-
-MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-
-HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
-
-TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-XML_FLAGS +=
-DVIPS_FLAGS +=
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-$(HTMLDIR)/%.gif: %.gif
- $(INSTALL_DATA) $< $@
-
-docs: pdf html man
-
-$(TOP_PDF_FILE): $(XML_FILES)
-
-pdf: $(TOP_PDF_FILE)
-
-html: gifs $(HTML_REF_MAN_FILE)
-
-clean clean_docs:
- rm -rf $(HTMLDIR)/*
- rm -f $(MAN3DIR)/*
- rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
- rm -f errs core *~
- rm -f $(JD_HTML) $(JD_PACK)
-
-man: $(MAN3_FILES)
-
-gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
-
-$(INDEX_TARGET): $(INDEX_SRC)
- sed -e 's;%VSN%;$(VSN);' $(INDEX_SRC) > $(INDEX_TARGET)
-
-debug opt:
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_docs_spec: docs
- $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
- $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
- $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
- $(INSTALL_DATA) $(HTMLDIR)/* \
- "$(RELSYSDIR)/doc/html"
- $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
- $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
- $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
-
-release_spec:
diff --git a/lib/cosEvent/doc/src/book.xml b/lib/cosEvent/doc/src/book.xml
deleted file mode 100644
index 5c0172b4cd..0000000000
--- a/lib/cosEvent/doc/src/book.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE book SYSTEM "book.dtd">
-
-<book xmlns:xi="http://www.w3.org/2001/XInclude">
- <header titlestyle="normal">
- <copyright>
- <year>1999</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosEvent</title>
- <prepared></prepared>
- <docno></docno>
- <date>1998-04-25</date>
- <rev>1.0</rev>
- <file>book.xml</file>
- </header>
- <insidecover>
- </insidecover>
- <pagetext>cosEvent</pagetext>
- <preamble>
- <contents level="2"></contents>
- </preamble>
- <parts lift="no">
- <xi:include href="part.xml"/>
- </parts>
- <applications>
- <xi:include href="ref_man.xml"/>
- </applications>
- <releasenotes>
- <xi:include href="notes.xml"/>
- </releasenotes>
- <listofterms></listofterms>
- <index></index>
-</book>
-
diff --git a/lib/cosEvent/doc/src/ch_contents.xml b/lib/cosEvent/doc/src/ch_contents.xml
deleted file mode 100644
index 07773877ea..0000000000
--- a/lib/cosEvent/doc/src/ch_contents.xml
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1999</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>The cosEvent Application</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>1999-09-17</date>
- <rev>B</rev>
- <file>ch_contents.xml</file>
- </header>
-
- <section>
- <title>Content Overview</title>
- <p>The cosEvent documentation is divided into three sections:
- </p>
- <list type="bulleted">
- <item>
- <p>PART ONE - The User's Guide
- <br></br>Description of the cosEvent Application including
- services and a small tutorial demonstrating
- the development of a simple service.</p>
- </item>
- <item>
- <p>PART TWO - Release Notes
- <br></br>A concise history of cosEvent.</p>
- </item>
- <item>
- <p>PART THREE - The Reference Manual
- <br></br> A quick reference guide, including a
- brief description, to all the functions available in cosEvent.</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Brief Description of the User's Guide</title>
- <p>The User's Guide contains the following parts:</p>
- <list type="bulleted">
- <item>
- <p>CosEvent overview</p>
- </item>
- <item>
- <p>CosEvent installation and examples</p>
- </item>
- </list>
- </section>
-</chapter>
-
diff --git a/lib/cosEvent/doc/src/ch_event_service.xml b/lib/cosEvent/doc/src/ch_event_service.xml
deleted file mode 100644
index 3a783234af..0000000000
--- a/lib/cosEvent/doc/src/ch_event_service.xml
+++ /dev/null
@@ -1,222 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1997</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Event Service</title>
- <prepared></prepared>
- <docno></docno>
- <date>97-11-19</date>
- <rev>A</rev>
- <file>ch_es_intro.xml</file>
- </header>
-
- <section>
- <title>Overview of the CosEvent Service</title>
- <p>The Event service allows programmers to subscribe to
- information channels. Suppliers can generate events without knowing the
- consumer identities and the consumer can receive events without knowing
- the supplier identity. Both push and pull event delivery are supported.
- The Event service will queue information and processes.
- </p>
- <p>The CORBA Event service provides a flexible model for
- asynchronous, decoupled communication between objects. This
- chapter outlines communication models and the roles and
- relationships of key components in the CosEvent service. It
- shows a simple example on use of this service.</p>
- </section>
-
- <section>
- <title>Event Service Components</title>
- <p>There are five components in the OMG CosEvent service architecture. These
- are described below:</p>
- <marker id="e_s_components"></marker>
- <image file="e_s_components.gif">
- <icaption>
-Figure 1: Event service Components</icaption>
- </image>
- <list type="bulleted">
- <item><em>Suppliers and consumers:</em> Consumers are the ultimate targets of
- events generated by suppliers. Consumers and suppliers can both play active
- and
- passive roles. There could be two types of consumers and suppliers: push
- or pull. A PushSupplier object can actively push an event to a passive
- PushConsumer object. Likewise, a PullSupplier object can passively
- wait for a PullConsumer object to actively pull an event from it.</item>
- <item><em>EventChannel:</em> The central abstraction in the CosEvent service is the
- EventChannel which plays the role of a mediator between consumers and
- suppliers. Consumers and suppliers register their interest with the
- EventChannel. It can provide many-to-many communication. The channel
- consumes events from one or more suppliers, and supplies events to one
- or more consumers. An EventChannel can support consumers and suppliers
- using different communication models.</item>
- <item><em>ProxySuppliers and ProxyConsumers:</em> ProxySuppliers act as middlemen
- between consumers and the EventChannel. A ProxySupplier is similar to
- a normal supplier, but includes an additional method for connecting a
- consumer to the ProxySupplier. Likewise, ProxyConsumers act as
- middlemen between suppliers and the EventChannel. A ProxyConsumer is
- similar to a normal consumer, but includes an additional method for
- connecting a supplier to the ProxyConsumer.</item>
- <item><em>Supplier and consumer administrations:</em> Consumer administration acts as
- a factory for creating ProxySuppliers. Supplier administration acts as
- a factory for creating ProxyConsumers.</item>
- </list>
- </section>
-
- <section>
- <title>Event Service Communication Models</title>
- <p>There are four general models of component collaboration in the OMG CosEvent service
- architecture. The following describes these models:
- (Please note that proxies are not shown in the diagrams for simplicity).</p>
- <marker id="e_s_models"></marker>
- <image file="e_s_models.gif">
- <icaption>
-Figure 2: Event service Communication Models</icaption>
- </image>
- <list type="bulleted">
- <item><em>The Canonical Push Model:</em> The Canonical push model shown in figure 2(A) allows
- the suppliers of events to initiate the transfer of event data to consumers.
- In this model, suppliers are active initiators and consumers are the passive
- targets of the requests. EventChannels play the role of <c><![CDATA[Notifier]]></c>.
- Thus, active suppliers use EventChannels to push data to passive consumers that
- have registered with the EventChannels.</item>
- <item><em>The Canonical Pull Model:</em>The Canonical pull model shown
- in figure 2(B)
- allows consumers to request events from suppliers. In this model,
- Consumers are
- active initiators and suppliers are the passive targets of the pull
- requests.
- EventChannel plays the role of <c><![CDATA[Procurer]]></c> since it procures
- events
- on behalf of consumers. Thus, active consumers can explicitly pull
- data
- from passive suppliers via the EventChannels.</item>
- <item><em>The Hybrid Push/Pull Model:</em> The push/pull model shown in figure 2(C) is a
- hybrid that allows consumers to request events queued at an EventChannel
- by suppliers. In this model, both suppliers and consumers are active
- initiators of the requests. EventChannels play the role of <c><![CDATA[Queue]]></c>.
- Thus, active consumers can explicitly pull data deposited by active
- suppliers via the EventChannels.</item>
- <item><em>The Hybrid Pull/Push Model:</em> The pull/push model shown in figure 2(D) is another
- hybrid that allows the channel to pull events from suppliers and push them
- to consumers. In this model, suppliers are passive targets of pull requests
- and consumers are passive targets of pushes. EventChannels play the role of
- <c><![CDATA[Intelligent Agent]]></c>. Thus, active EventChannels can pull data from
- passive suppliers and push that data to passive consumers.</item>
- </list>
- </section>
-
- <section>
- <title>A Tutorial on How to Create a Simple Service</title>
- <p>To be able to use the cosEvent application supplier and consumer objects
- must be implemented, which must inherit from the appropriate interface
- defined in the <em>CosEventComm.idl</em> specification.</p>
- <p>We start by creating an interface which inherits from the correct interface,
- e.g., CosEventComm::PushConsumer. Hence, we must also implement all
- operations defined in the PushConsumer interface. The IDL-file could look like:
- </p>
- <code type="c"><![CDATA[
-#ifndef _MYCLIENT_IDL
-#define _MYCLIENT_IDL
-#include <CosEventComm.idl>
-
-module myClientImpl {
-
- interface ownInterface:CosEventComm::PushConsumer {
-
- void ownFunctions(in any NeededArguments)
- raises(OwnExceptions);
-
- };
-};
-
-#endif
- ]]></code>
- <p>Run the IDL compiler on this file by calling the <c><![CDATA[ic:gen/1]]></c> function.
- This will produce the API named <c><![CDATA[myClientImpl_ownInterface.erl]]></c>.
- After generating the API stubs and the server skeletons it is time to
- implement the servers and if no special options are sent
- to the IDl compiler the file name is <c><![CDATA[myClientImpl_ownInterface_impl.erl]]></c>.</p>
- </section>
-
- <section>
- <title>How to Run Everything</title>
- <p>Below is a short transcript on how to run cosEvent. </p>
- <code type="none"><![CDATA[
-
-%% Start Mnesia and Orber
-mnesia:delete_schema([node()]),
-mnesia:create_schema([node()]),
-orber:install([node()]),
-mnesia:start(),
-orber:start(),
-
-%% Install cosEvent in the IFR.
-cosEventApp:install(),
-
-%% Register the application specific Client implementations
-%% in the IFR.
-'oe_myClientImpl':'oe_register'(),
-
-%% Start the cosEvent application.
-cosEventApp:start(),
-
-%% Start a channel using the default configuration
-Ch = cosEventApp:start_channel(),
-%% ... or use configuration parameters.
-Ch = cosEventApp:start_channel([{pull_interval, 10}, {maxEvents, 50}]),
-
-%% Retrieve a SupplierAdmin and a ConsumerAdmin.
-AdminSupplier = 'CosEventChannelAdmin_EventChannel':for_suppliers(Ch),
-AdminConsumer = 'CosEventChannelAdmin_EventChannel':for_consumers(Ch),
-
-%% Use the corresponding Admin object to get access to wanted Proxies
-
-%% Create a Push Consumer Proxy, which the Client Push Supplier will push
-%% events to.
-ProxyPushConsumer =
- 'CosEventChannelAdmin_SupplierAdmin':obtain_push_consumer(AdminSupplier),
-
-%% Create a Push Supplier Proxy, which will push events to the registered
-%% Push Consumer.
-ProxyPushSupplier =
- 'CosEventChannelAdmin_ConsumerAdmin':obtain_push_supplier(AdminConsumer),
-
-
-%% Create application Clients. We can, for example, start the Clients
-%% our selves or look them up in the naming service. This is application
-%% specific.
-Consumer = myClientImpl_ownInterface:oe_create(),
-Supplier = ...
-
-%% Connect each Client to the corresponding Proxy.
-'CosEventChannelAdmin_ProxyPushConsumer':
- connect_push_supplier(ProxyPushConsumer, Supplier),
-'CosEventChannelAdmin_ProxyPushSupplier':
- connect_push_consumer(ProxyPushSupplier, Consumer),
- ]]></code>
- <p>The example above, exemplifies a event system, i.e., the <em>Canonical Push Model</em>, where the Supplier client in some way generates event
- and pushes them to the proxy. The push supplier proxies will eventually
- push the events to each Consumer client.</p>
- </section>
-</chapter>
-
diff --git a/lib/cosEvent/doc/src/ch_introduction.xml b/lib/cosEvent/doc/src/ch_introduction.xml
deleted file mode 100644
index c88e96e40d..0000000000
--- a/lib/cosEvent/doc/src/ch_introduction.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1999</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>Introduction to cosEvent</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>1999-09-17</date>
- <rev></rev>
- <file>ch_introduction.xml</file>
- </header>
-
- <section>
- <title>Overview</title>
- <p>The cosEvent application is a Event Service compliant with the <url href="http://www.omg.org">OMG</url>
- Event Service CosEvent.
- </p>
-
- <section>
- <title>Purpose and Dependencies</title>
- <p>CosEvent is dependent on <em>Orber</em>, which provides CORBA functionality in an Erlang environment.</p>
- </section>
-
- <section>
- <title>Prerequisites</title>
- <p>To fully understand the concepts presented in the
- documentation, it is recommended that the user is familiar
- with distributed programming and CORBA.
- </p>
- <p>Recommended reading includes <em>CORBA, Fundamentals and Programming - Jon Siegel</em> and <em>Open Telecom Platform Documentation Set</em>. It is also helpful to have read
- <em>Concurrent Programming in Erlang</em>.</p>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosEvent/doc/src/cosEventApp.xml b/lib/cosEvent/doc/src/cosEventApp.xml
deleted file mode 100644
index d26512e0c3..0000000000
--- a/lib/cosEvent/doc/src/cosEventApp.xml
+++ /dev/null
@@ -1,169 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2001</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>cosEventApp</title>
- <prepared>Niclas Eklund</prepared>
- <responsible>Niclas Eklund</responsible>
- <docno></docno>
- <approved>Niclas Eklund</approved>
- <checked></checked>
- <date>2000-01-31</date>
- <rev>PA1</rev>
- <file>cosEventApp.xml</file>
- </header>
- <module>cosEventApp</module>
- <modulesummary>The main module of the cosEvent application.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use:<br></br><c><![CDATA[-include_lib("cosEvent/include/*.hrl").]]></c></p>
- <p>This module contains the functions for starting and stopping the application.</p>
- </description>
- <funcs>
- <func>
- <name>install() -> Return</name>
- <fsummary>Install the cosEvent application</fsummary>
- <type>
- <v>Return = ok | {'EXCEPTION', E} | {'EXIT', R}</v>
- </type>
- <desc>
- <p>This operation installs the cosEvent application.</p>
- </desc>
- </func>
- <func>
- <name>uninstall() -> Return</name>
- <fsummary>Uninstall the cosEvent application</fsummary>
- <type>
- <v>Return = ok | {'EXCEPTION', E} | {'EXIT', R}</v>
- </type>
- <desc>
- <p>This operation uninstalls the cosEvent application.</p>
- </desc>
- </func>
- <func>
- <name>start() -> Return</name>
- <fsummary>Start the cosEvent application</fsummary>
- <type>
- <v>Return = ok | {error, Reason}</v>
- </type>
- <desc>
- <p>This operation starts the cosEvent application.</p>
- </desc>
- </func>
- <func>
- <name>stop() -> Return</name>
- <fsummary>Stop the cosEvent application</fsummary>
- <type>
- <v>Return = ok | {error, Reason}</v>
- </type>
- <desc>
- <p>This operation stops the cosEvent application.</p>
- </desc>
- </func>
- <func>
- <name>start_channel() -> Channel</name>
- <fsummary>Start a channel with default settings</fsummary>
- <type>
- <v>Channel = #objref</v>
- </type>
- <desc>
- <p>This operation creates a new instance of a
- <seealso marker="CosEventChannelAdmin_EventChannel">Event Channel</seealso>
- using the default settings.</p>
- </desc>
- </func>
- <func>
- <name>start_channel(Options) -> Channel</name>
- <fsummary>Start a channel with settings defined by the given options</fsummary>
- <type>
- <v>Options = [Option]</v>
- <v>Option = {pull_interval, Seconds} | {typecheck, Boolean} | {maxEvents, Integer} | {blocking, Boolean}</v>
- <v>Channel = #objref</v>
- </type>
- <desc>
- <p>This operation creates a new instance of a
- <seealso marker="CosEventChannelAdmin_EventChannel">Event Channel</seealso></p>
- <p></p>
- <list type="bulleted">
- <item><c><![CDATA[{pull_interval, Seconds}]]></c> - determine how often Proxy Pull
- Consumers will check for new events with the client application. The
- default value is 20 seconds.</item>
- <item><c><![CDATA[{typecheck, Boolean}]]></c> - if this option is set to true the
- proxies will check if the supplied client object is of correct type.
- The default value is false.</item>
- <item><c><![CDATA[{maxEvents, Integer}]]></c> - this option determine how many events
- the <c><![CDATA[ProxyPullSuppliers]]></c> will store before discarding events.
- If the limit is reached events will be discarded in any order.
- The default value is 300.</item>
- <item><c><![CDATA[{blocking, Boolean}]]></c> - this option determine the behavior of
- the channel when handling events internally. If set to <c><![CDATA[true]]></c> the
- risk of a single event supplier floods the system is reduced, but
- the performance may also be reduced.
- The default value is <c><![CDATA[true]]></c>.</item>
- </list>
- </desc>
- </func>
- <func>
- <name>start_channel_link() -> Channel</name>
- <fsummary>Start a channel, which is linked to the invoking process, with default settings</fsummary>
- <type>
- <v>Channel = #objref</v>
- </type>
- <desc>
- <p>This operation creates a new instance of a
- <seealso marker="CosEventChannelAdmin_EventChannel">Event Channel</seealso>,
- which is linked to the invoking process, using the default settings.</p>
- </desc>
- </func>
- <func>
- <name>start_channel_link(Options) -> Channel</name>
- <fsummary>Start a channel, which is linked to the invoking process, with settings defined by the given options</fsummary>
- <type>
- <v>Options = [Option]</v>
- <v>Option = {pull_interval, Seconds} | {typecheck, Boolean} | {maxEvents, Integer} | {blocking, Boolean}</v>
- <v>Channel = #objref</v>
- </type>
- <desc>
- <p>This operation creates a new instance of a
- <seealso marker="CosEventChannelAdmin_EventChannel">Event Channel</seealso>,
- which is linked to the invoking process, with settings defined by the
- given options. Allowed options are the same as for
- <c><![CDATA[cosEventApp:start_channel/1]]></c>.</p>
- </desc>
- </func>
- <func>
- <name>stop_channel(Channel) -> Reply</name>
- <fsummary>Terminate the target object</fsummary>
- <type>
- <v>Channel = #objref</v>
- <v>Reply = ok | {'EXCEPTION', E}</v>
- </type>
- <desc>
- <p>This operation stop the target event channel.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosEvent/doc/src/e_s_components.gif b/lib/cosEvent/doc/src/e_s_components.gif
deleted file mode 100644
index a448c14ce0..0000000000
--- a/lib/cosEvent/doc/src/e_s_components.gif
+++ /dev/null
Binary files differ
diff --git a/lib/cosEvent/doc/src/e_s_models.gif b/lib/cosEvent/doc/src/e_s_models.gif
deleted file mode 100644
index 329b0858d1..0000000000
--- a/lib/cosEvent/doc/src/e_s_models.gif
+++ /dev/null
Binary files differ
diff --git a/lib/cosEvent/doc/src/notes.xml b/lib/cosEvent/doc/src/notes.xml
deleted file mode 100644
index ba0b0d88db..0000000000
--- a/lib/cosEvent/doc/src/notes.xml
+++ /dev/null
@@ -1,348 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1999</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosEvent Release Notes</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>99-02-12</date>
- <rev>A</rev>
- <file>notes.xml</file>
- </header>
-
- <section><title>cosEvent 2.2.2</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> Removed all old unused files in the documentation.
- </p>
- <p>
- Own Id: OTP-14475 Aux Id: ERL-409, PR-1493 </p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosEvent 2.2.1</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Internal changes</p>
- <p>
- Own Id: OTP-13551</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosEvent 2.2</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> Remove the usage of erlang:now() from all Corba
- applications and use the new rand module instead of
- random. </p>
- <p>
- Own Id: OTP-12687</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosEvent 2.1.15</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> The default encoding of Erlang files has been changed
- from ISO-8859-1 to UTF-8. </p> <p> The encoding of XML
- files has also been changed to UTF-8. </p>
- <p>
- Own Id: OTP-10907</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosEvent 2.1.14</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> Postscript files no longer needed for the generation
- of PDF files have been removed. </p>
- <p>
- Own Id: OTP-11016</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosEvent 2.1.13</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Misc build updates</p>
- <p>
- Own Id: OTP-10784</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosEvent 2.1.12</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>Erlang/OTP can now be built using parallel make if you
- limit the number of jobs, for instance using '<c>make
- -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not
- work at the moment because of some missing
- dependencies.</p>
- <p>
- Own Id: OTP-9451</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section>
- <title>cosEvent 2.1.11</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- Removed superfluous usage of shy in the documentation since it can cause problem if
- a buggy tool is used.</p>
- <p>
- Own Id: OTP-9319 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosEvent 2.1.10</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- Eliminated Dialyzer warnings when using exit or throw.</p>
- <p>
- Own Id: OTP-9050 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosEvent 2.1.9</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- Test suites published.</p>
- <p>
- Own Id: OTP-8543 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosEvent 2.1.8</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- Removed the usage of the codeinclude tag in the documentation.</p>
- <p>
- Own Id: OTP-8409 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosEvent 2.1.7</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- The documentation is now built with open source tools (xsltproc and fop)
- that exists on most platforms. One visible change is that the frames are removed.</p>
- <p>
- Own Id: OTP-8201 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosEvent 2.1.6</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Obsolete guards, e.g. record vs is_record, has been changed
- to avoid compiler warnings.</p>
- <p>Own id: OTP-7987</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosEvent 2.1.5</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Updated file headers.</p>
- <p>Own id: OTP-7837</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosEvent 2.1.4</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Documentation source included in open source releases.</p>
- <p>Own id: OTP-7595</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosEvent 2.1.3</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Updated file headers.</p>
- <p>Own id: OTP-7011</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosEvent 2.1.2</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>The documentation source has been converted from SGML to XML.</p>
- <p>Own id: OTP-6754</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosEvent 2.1.1</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Minor Makefile changes.</p>
- <p>Own id: OTP-6701</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosEvent 2.1</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>The stub/skeleton-files generated by IC have been improved,
- i.e., depending on the IDL-files, reduced the size of the
- erl- and beam-files and decreased dependencies off Orber's
- Interface Repository. It is necessary to re-compile all IDL-files
- and use COS-applications, including Orber, compiled with
- IC-4.2.</p>
- <p>Own id: OTP-4576</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosEvent 2.0</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>This version is a completely new version of the cosEvent
- application; older versions was <em>not</em> compliant with the OMG
- specification. The <c><![CDATA[look and feel]]></c> have been changed
- to be more uniform with the other COS-services.</p>
- </item>
- </list>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosEvent/doc/src/part.xml b/lib/cosEvent/doc/src/part.xml
deleted file mode 100644
index 5e32455ebb..0000000000
--- a/lib/cosEvent/doc/src/part.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE part SYSTEM "part.dtd">
-
-<part xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>1999</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosEvent User's Guide</title>
- <prepared></prepared>
- <docno></docno>
- <date>1998-04-26</date>
- <rev>1.0</rev>
- <file>part.xml</file>
- </header>
- <description>
- <p>The <em>cosEvent</em> application is an Erlang implementation of a
- CORBA Service CosEvent.</p>
- </description>
- <xi:include href="ch_contents.xml"/>
- <xi:include href="ch_introduction.xml"/>
- <xi:include href="ch_event_service.xml"/>
-</part>
-
diff --git a/lib/cosEvent/doc/src/ref_man.xml b/lib/cosEvent/doc/src/ref_man.xml
deleted file mode 100644
index 5db5626478..0000000000
--- a/lib/cosEvent/doc/src/ref_man.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE application SYSTEM "application.dtd">
-
-<application xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>1999</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosEvent Reference Manual</title>
- <prepared></prepared>
- <docno></docno>
- <date>1998-05-05</date>
- <rev>2.0</rev>
- <file>ref_man.xml</file>
- </header>
- <description>
- <p>The <em>cosEvent</em> application is an Erlang implementation of
- a CORBA Service CosEvent.</p>
- </description>
- <xi:include href="cosEventApp.xml"/>
- <xi:include href="CosEventChannelAdmin.xml"/>
- <xi:include href="CosEventChannelAdmin_ConsumerAdmin.xml"/>
- <xi:include href="CosEventChannelAdmin_SupplierAdmin.xml"/>
- <xi:include href="CosEventChannelAdmin_EventChannel.xml"/>
- <xi:include href="CosEventChannelAdmin_ProxyPullConsumer.xml"/>
- <xi:include href="CosEventChannelAdmin_ProxyPushConsumer.xml"/>
- <xi:include href="CosEventChannelAdmin_ProxyPullSupplier.xml"/>
- <xi:include href="CosEventChannelAdmin_ProxyPushSupplier.xml"/>
-</application>
-
diff --git a/lib/cosEvent/info b/lib/cosEvent/info
deleted file mode 100644
index dc9f7b7404..0000000000
--- a/lib/cosEvent/info
+++ /dev/null
@@ -1,2 +0,0 @@
-group: orb
-short: Orber OMG Event Service
diff --git a/lib/cosEvent/src/CosEventChannelAdmin.cfg b/lib/cosEvent/src/CosEventChannelAdmin.cfg
deleted file mode 100644
index 0de579bd6f..0000000000
--- a/lib/cosEvent/src/CosEventChannelAdmin.cfg
+++ /dev/null
@@ -1,6 +0,0 @@
-{this, "CosEventChannelAdmin::SupplierAdmin"}.
-{{handle_info, "CosEventChannelAdmin::SupplierAdmin"}, true}.
-{this, "CosEventChannelAdmin::ProxyPushConsumer"}.
-{{handle_info, "CosEventChannelAdmin::ProxyPushConsumer"}, true}.
-{this, "CosEventChannelAdmin::ProxyPullConsumer"}.
-{{handle_info, "CosEventChannelAdmin::ProxyPullConsumer"}, true}.
diff --git a/lib/cosEvent/src/CosEventChannelAdmin.idl b/lib/cosEvent/src/CosEventChannelAdmin.idl
deleted file mode 100644
index d5cb92c4e0..0000000000
--- a/lib/cosEvent/src/CosEventChannelAdmin.idl
+++ /dev/null
@@ -1,66 +0,0 @@
-#ifndef _COSEVENTCHANELADMIN_IDL
-#define _COSEVENTCHANELADMIN_IDL
-
-#include "CosEventComm.idl"
-
-#pragma prefix "omg.org"
-
-module CosEventChannelAdmin
-{
- exception AlreadyConnected{};
- exception TypeError{};
-
- interface ProxyPushConsumer: CosEventComm::PushConsumer
- {
- void connect_push_supplier(in CosEventComm::
- PushSupplier push_supplier)
- raises (AlreadyConnected);
- };
-
- interface ProxyPullSupplier: CosEventComm::PullSupplier
- {
- void connect_pull_consumer(in CosEventComm::
- PullConsumer pull_consumer)
- raises (AlreadyConnected);
- };
-
- interface ProxyPullConsumer: CosEventComm::PullConsumer
- {
- void connect_pull_supplier(in CosEventComm::
- PullSupplier pull_supplier)
- raises (AlreadyConnected, TypeError);
- };
-
- interface ProxyPushSupplier: CosEventComm::PushSupplier
- {
- void connect_push_consumer(in CosEventComm::
- PushConsumer push_consumer)
- raises (AlreadyConnected, TypeError);
- };
-
- interface ConsumerAdmin
- {
- ProxyPushSupplier obtain_push_supplier();
- ProxyPullSupplier obtain_pull_supplier();
- };
-
- interface SupplierAdmin
- {
- ProxyPushConsumer obtain_push_consumer();
- ProxyPullConsumer obtain_pull_consumer();
- };
-
- interface EventChannel
- {
- ConsumerAdmin for_consumers();
- SupplierAdmin for_suppliers();
- void destroy();
- };
-
-};
-
-#endif
-
-
-
-
diff --git a/lib/cosEvent/src/CosEventChannelAdmin_ProxyPullConsumer_impl.erl b/lib/cosEvent/src/CosEventChannelAdmin_ProxyPullConsumer_impl.erl
deleted file mode 100644
index cb9bb4f4a4..0000000000
--- a/lib/cosEvent/src/CosEventChannelAdmin_ProxyPullConsumer_impl.erl
+++ /dev/null
@@ -1,206 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : CosEventChannelAdmin_ProxyPullConsumer_impl.erl
-%% Description :
-%%
-%%----------------------------------------------------------------------
--module('CosEventChannelAdmin_ProxyPullConsumer_impl').
-
-%%----------------------------------------------------------------------
-%% Include files
-%%----------------------------------------------------------------------
--include("CosEventChannelAdmin.hrl").
--include("CosEventComm.hrl").
--include("cosEventApp.hrl").
-
-%%----------------------------------------------------------------------
-%% External exports
-%%----------------------------------------------------------------------
-%% Mandatory
--export([init/1,
- terminate/2,
- code_change/3,
- handle_info/2]).
-
-%% Interface functions
--export([connect_pull_supplier/3]).
-
-%% Exports from "CosEventComm::PullConsumer"
--export([disconnect_pull_consumer/2]).
-
-
-%%----------------------------------------------------------------------
-%% Internal exports
-%%----------------------------------------------------------------------
-
-%%----------------------------------------------------------------------
-%% Records
-%%----------------------------------------------------------------------
--record(state, {admin, admin_pid, channel, client,
- typecheck, pull_interval, timer_ref}).
-
-%%----------------------------------------------------------------------
-%% Macros
-%%----------------------------------------------------------------------
-
-%%======================================================================
-%% External functions
-%%======================================================================
-%%----------------------------------------------------------------------
-%% Function : init/1
-%% Returns : {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
-%% Description: Initiates the server
-%%----------------------------------------------------------------------
-init([Admin, AdminPid, Channel, TypeCheck, PullInterval]) ->
- process_flag(trap_exit, true),
- Secs = timer:seconds(PullInterval),
- timer:start(),
- {ok, #state{admin = Admin, admin_pid = AdminPid, channel = Channel,
- typecheck = TypeCheck, pull_interval = Secs}}.
-
-%%----------------------------------------------------------------------
-%% Function : terminate/2
-%% Returns : any (ignored by gen_server)
-%% Description: Shutdown the server
-%%----------------------------------------------------------------------
-terminate(_Reason, #state{client = undefined}) ->
- ?DBG("Terminating ~p; no client connected.~n", [_Reason]),
- ok;
-terminate(_Reason, #state{client = Client} = State) ->
- stop_timer(State),
- ?DBG("Terminating ~p~n", [_Reason]),
- cosEventApp:disconnect('CosEventComm_PullSupplier',
- disconnect_pull_supplier, Client),
- ok.
-
-%%----------------------------------------------------------------------
-%% Function : code_change/3
-%% Returns : {ok, NewState}
-%% Description: Convert process state when code is changed
-%%----------------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%---------------------------------------------------------------------%
-%% function : handle_info
-%% Arguments:
-%% Returns : {noreply, State} |
-%% {stop, Reason, State}
-%% Effect : If the Parent Admin or the Channel terminates so must this object.
-%%----------------------------------------------------------------------
-handle_info({'EXIT', Pid, Reason}, #state{admin_pid = Pid} = State) ->
- ?DBG("Parent Admin terminated ~p~n", [Reason]),
- orber:dbg("[~p] CosEventChannelAdmin_ProxyPullConsumer:handle_info(~p);~n"
- "My Admin terminated and so will I.", [?LINE, Reason], ?DEBUG_LEVEL),
- {stop, Reason, State};
-handle_info(try_pull_event, State) ->
- try_pull_event(State);
-handle_info(_Info, State) ->
- ?DBG("Unknown Info ~p~n", [_Info]),
- {noreply, State}.
-
-%%----------------------------------------------------------------------
-%% Function : connect_pull_supplier
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-connect_pull_supplier(_OE_This, #state{client = undefined,
- typecheck = TypeCheck} = State, NewClient) ->
- case corba_object:is_nil(NewClient) of
- true ->
- ?DBG("A NIL client supplied.~n", []),
- orber:dbg("[~p] CosEventChannelAdmin_ProxyPullConsumer:connect_pull_supplier(..);~n"
- "Supplied a NIL reference which is not allowed.",
- [?LINE], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status = ?COMPLETED_NO});
- false ->
- cosEventApp:type_check(NewClient, 'CosEventComm_PullSupplier', TypeCheck),
- NewState = start_timer(State),
- {reply, ok, NewState#state{client = NewClient}}
- end;
-connect_pull_supplier(_, _, _) ->
- corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}).
-
-
-%%----------------------------------------------------------------------
-%% Function : disconnect_pull_consumer
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-disconnect_pull_consumer(_OE_This, State) ->
- NewState = stop_timer(State),
- ?DBG("Disconnect invoked ~p~n", [NewState]),
- {stop, normal, ok, NewState#state{client = undefined}}.
-
-%%======================================================================
-%% Internal functions
-%%======================================================================
-%% Start timer which send a message each time we should pull for new events.
-start_timer(State) ->
- case catch timer:send_interval(State#state.pull_interval, try_pull_event) of
- {ok,PullTRef} ->
- ?DBG("Started timer: ~p~n", [State#state.pull_interval]),
- State#state{timer_ref = PullTRef};
- _ ->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-stop_timer(#state{timer_ref = undefined} = State) ->
- ?DBG("No timer to stop~n",[]),
- State;
-stop_timer(State) ->
- ?DBG("Stopped timer~n",[]),
- timer:cancel(State#state.timer_ref),
- State#state{timer_ref = undefined}.
-
-
-try_pull_event(State) ->
- case catch 'CosEventComm_PullSupplier':try_pull(State#state.client) of
- {_,false} ->
- ?DBG("Client did not supply event~n", []),
- {noreply, State};
- {Any, true} ->
- 'oe_CosEventComm_Channel':send_sync(State#state.channel, Any),
- ?DBG("Received Event ~p and forwarded it successfully.~n", [Any]),
- {noreply, State};
- {'EXCEPTION', #'CosEventComm_Disconnected'{}} ->
- ?DBG("Client claims we are disconnectedwhen trying to pull event.~n", []),
- orber:dbg("[~p] CosEventChannelAdmin_ProxyPullConsumer:try_pull_event();~n"
- "Client claims we are disconnected when trying to pull event so I terminate.",
- [?LINE], ?DEBUG_LEVEL),
- {stop, normal, State#state{client = undefined}};
- What ->
- orber:dbg("[~p] CosEventChannelAdmin_ProxyPullConsumer:try_pull_event(~p);~n"
- "My Client behaves badly so I terminate.",
- [?LINE, What], ?DEBUG_LEVEL),
- {stop, normal, State}
- end.
-
-
-%%======================================================================
-%% END OF MODULE
-%%======================================================================
diff --git a/lib/cosEvent/src/CosEventChannelAdmin_ProxyPushConsumer_impl.erl b/lib/cosEvent/src/CosEventChannelAdmin_ProxyPushConsumer_impl.erl
deleted file mode 100644
index 4c2b8629f2..0000000000
--- a/lib/cosEvent/src/CosEventChannelAdmin_ProxyPushConsumer_impl.erl
+++ /dev/null
@@ -1,170 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : CosEventChannelAdmin_ProxyPushConsumer_impl.erl
-%% Description :
-%%
-%%----------------------------------------------------------------------
--module('CosEventChannelAdmin_ProxyPushConsumer_impl').
-
-%%----------------------------------------------------------------------
-%% Include files
-%%----------------------------------------------------------------------
--include("CosEventChannelAdmin.hrl").
--include("CosEventComm.hrl").
--include("cosEventApp.hrl").
-
-%%----------------------------------------------------------------------
-%% External exports
-%%----------------------------------------------------------------------
-%% Mandatory
--export([init/1,
- terminate/2,
- code_change/3,
- handle_info/2]).
-
-%% Exports from "CosEventChannelAdmin::ProxyPushConsumer"
--export([connect_push_supplier/3]).
-
-%% Exports from "CosEventComm::PushConsumer"
--export([push/3,
- disconnect_push_consumer/2]).
-
-%%----------------------------------------------------------------------
-%% Internal exports
-%%----------------------------------------------------------------------
-
-%%----------------------------------------------------------------------
-%% Records
-%%----------------------------------------------------------------------
--record(state, {admin, admin_pid, channel, client, typecheck}).
-
-%%----------------------------------------------------------------------
-%% Macros
-%%----------------------------------------------------------------------
-
-%%======================================================================
-%% External functions
-%%======================================================================
-%%----------------------------------------------------------------------
-%% Function : init/1
-%% Returns : {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
-%% Description: Initiates the server
-%%----------------------------------------------------------------------
-init([Admin, AdminPid, Channel, TypeCheck]) ->
- process_flag(trap_exit, true),
- {ok, #state{admin = Admin, admin_pid = AdminPid, channel = Channel,
- typecheck = TypeCheck}}.
-
-%%----------------------------------------------------------------------
-%% Function : terminate/2
-%% Returns : any (ignored by gen_server)
-%% Description: Shutdown the server
-%%----------------------------------------------------------------------
-terminate(_Reason, #state{client = undefined}) ->
- ?DBG("Terminating ~p; no client connected.~n", [_Reason]),
- ok;
-terminate(_Reason, #state{client = Client} = _State) ->
- ?DBG("Terminating ~p~n", [_Reason]),
- cosEventApp:disconnect('CosEventComm_PushSupplier',
- disconnect_push_supplier, Client),
- ok.
-
-%%----------------------------------------------------------------------
-%% Function : code_change/3
-%% Returns : {ok, NewState}
-%% Description: Convert process state when code is changed
-%%----------------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%---------------------------------------------------------------------%
-%% function : handle_info
-%% Arguments:
-%% Returns : {noreply, State} |
-%% {stop, Reason, State}
-%% Effect : If the Parnet Admin or the Channel terminates so must this object.
-%%----------------------------------------------------------------------
-handle_info({'EXIT', Pid, Reason}, #state{admin_pid = Pid} = State) ->
- ?DBG("Parent Admin terminated ~p~n", [Reason]),
- orber:dbg("[~p] CosEventChannelAdmin_ProxyPushConsumer:handle_info(~p);~n"
- "My Admin terminated and so will I.",
- [?LINE, Reason], ?DEBUG_LEVEL),
- {stop, Reason, State};
-handle_info(_Info, State) ->
- ?DBG("Unknown Info ~p~n", [_Info]),
- {noreply, State}.
-
-%%----------------------------------------------------------------------
-%% Function : connect_push_supplier
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-connect_push_supplier(_OE_This, #state{client = undefined,
- typecheck = TypeCheck} = State, NewClient) ->
- case corba_object:is_nil(NewClient) of
- true ->
- ?DBG("A NIL client supplied.~n", []),
- {reply, ok, State};
- false ->
- cosEventApp:type_check(NewClient, 'CosEventComm_PushSupplier', TypeCheck),
- ?DBG("Connected to client.~n", []),
- {reply, ok, State#state{client = NewClient}}
- end;
-connect_push_supplier(_, _, _) ->
- corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}).
-
-
-%%----------------------------------------------------------------------
-%% Function : push
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-push(_OE_This, State, Any) ->
- %% We should not use corba:reply here since if we block incoming
- %% events this will prevent producers to flood the system.
- ?DBG("Received Event ~p and forwarded it successfully.~n", [Any]),
- 'oe_CosEventComm_Channel':send_sync(State#state.channel, Any),
- {reply, ok, State}.
-
-%%----------------------------------------------------------------------
-%% Function : disconnect_push_consumer
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-disconnect_push_consumer(_OE_This, State) ->
- ?DBG("Disconnect invoked ~p~n", [State]),
- {stop, normal, ok, State#state{client = undefined}}.
-
-%%======================================================================
-%% Internal functions
-%%======================================================================
-
-%%======================================================================
-%% END OF MODULE
-%%======================================================================
diff --git a/lib/cosEvent/src/CosEventChannelAdmin_SupplierAdmin_impl.erl b/lib/cosEvent/src/CosEventChannelAdmin_SupplierAdmin_impl.erl
deleted file mode 100644
index fb5304292b..0000000000
--- a/lib/cosEvent/src/CosEventChannelAdmin_SupplierAdmin_impl.erl
+++ /dev/null
@@ -1,160 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : CosEventChannelAdmin_SupplierAdmin_impl.erl
-%% Created : 21 Mar 2001
-%% Description :
-%%
-%%----------------------------------------------------------------------
--module('CosEventChannelAdmin_SupplierAdmin_impl').
-
-
-%%----------------------------------------------------------------------
-%% Include files
-%%----------------------------------------------------------------------
--include("cosEventApp.hrl").
-
-
-%%----------------------------------------------------------------------
-%% External exports
-%%----------------------------------------------------------------------
-%% Mandatory
--export([init/1,
- terminate/2,
- code_change/3,
- handle_info/2]).
-
-%% Exports from "CosEventChannelAdmin::SupplierAdmin"
--export([obtain_push_consumer/2,
- obtain_pull_consumer/2]).
-
-%%----------------------------------------------------------------------
-%% Internal exports
-%%----------------------------------------------------------------------
-
-%%----------------------------------------------------------------------
-%% Records
-%%----------------------------------------------------------------------
--record(state, {channel, channel_pid, typecheck, pull_interval, server_options}).
-
-%%----------------------------------------------------------------------
-%% Macros
-%%----------------------------------------------------------------------
-
-%%======================================================================
-%% External functions
-%%======================================================================
-%%----------------------------------------------------------------------
-%% Function : init/1
-%% Returns : {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
-%% Description: Initiates the server
-%%----------------------------------------------------------------------
-init([Channel, ChannelPid, TypeCheck, PullInterval, ServerOpts]) ->
- process_flag(trap_exit, true),
- {ok, #state{channel = Channel, channel_pid = ChannelPid, typecheck = TypeCheck,
- pull_interval = PullInterval, server_options = ServerOpts}}.
-
-%%----------------------------------------------------------------------
-%% Function : terminate/2
-%% Returns : any (ignored by gen_server)
-%% Description: Shutdown the server
-%%----------------------------------------------------------------------
-terminate(_Reason, _State) ->
- ?DBG("Terminating ~p~n", [_Reason]),
- ok.
-
-%%----------------------------------------------------------------------
-%% Function : code_change/3
-%% Returns : {ok, NewState}
-%% Description: Convert process state when code is changed
-%%----------------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%---------------------------------------------------------------------%
-%% function : handle_info
-%% Arguments:
-%% Returns : {noreply, State} |
-%% {stop, Reason, State}
-%% Effect : Functions demanded by the gen_server module.
-%%----------------------------------------------------------------------
-handle_info({'EXIT', Pid, Reason}, #state{channel_pid = Pid} = State) ->
- ?DBG("Parent Channel terminated ~p~n", [Reason]),
- orber:dbg("[~p] CosEventChannelAdmin_SupplierAdmin:handle_info(~p);~n"
- "My Channel terminated and so will I.",
- [?LINE, Reason], ?DEBUG_LEVEL),
- {stop, Reason, State};
-handle_info(_Info, State) ->
- ?DBG("Unknown Info ~p~n", [_Info]),
- {noreply, State}.
-
-
-%%----------------------------------------------------------------------
-%% Function : obtain_push_consumer
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-obtain_push_consumer(OE_This, #state{channel = Channel,
- channel_pid = _ChannelPid,
- typecheck = TypeCheck,
- server_options = ServerOpts} = State) ->
- ?DBG("Starting a new CosEventChannelAdmin_ProxyPushConsumer.~n", []),
- {reply,
- 'CosEventChannelAdmin_ProxyPushConsumer':oe_create_link([OE_This,
- self(),
- Channel,
- TypeCheck],
- ServerOpts),
- State}.
-
-%%----------------------------------------------------------------------
-%% Function : obtain_pull_consumer
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-obtain_pull_consumer(OE_This, #state{channel = Channel,
- channel_pid = _ChannelPid,
- typecheck = TypeCheck,
- pull_interval= PullInterval,
- server_options = ServerOpts} = State) ->
- ?DBG("Starting a new CosEventChannelAdmin_ProxyPullConsumer.~n", []),
- {reply,
- 'CosEventChannelAdmin_ProxyPullConsumer':oe_create_link([OE_This,
- self(),
- Channel,
- TypeCheck,
- PullInterval],
- ServerOpts),
- State}.
-
-%%======================================================================
-%% Internal functions
-%%======================================================================
-
-%%======================================================================
-%% END OF MODULE
-%%======================================================================
diff --git a/lib/cosEvent/src/CosEventComm.idl b/lib/cosEvent/src/CosEventComm.idl
deleted file mode 100644
index bb0c107394..0000000000
--- a/lib/cosEvent/src/CosEventComm.idl
+++ /dev/null
@@ -1,37 +0,0 @@
-
-#ifndef _COSEVENTCOMM_IDL
-#define _COSEVENTCOMM_IDL
-
-#pragma prefix "omg.org"
-
-module CosEventComm
-{
- exception Disconnected{};
-
- interface PushConsumer
- {
- void push(in any data) raises (Disconnected);
- void disconnect_push_consumer();
- };
-
-
- interface PushSupplier
- {
- void disconnect_push_supplier();
- };
-
- interface PullSupplier
- {
- any pull() raises(Disconnected);
- any try_pull(out boolean has_event) raises(Disconnected);
- void disconnect_pull_supplier();
- };
-
- interface PullConsumer
- {
- void disconnect_pull_consumer();
- };
-};
-
-#endif
-
diff --git a/lib/cosEvent/src/Makefile b/lib/cosEvent/src/Makefile
deleted file mode 100644
index 29d6223005..0000000000
--- a/lib/cosEvent/src/Makefile
+++ /dev/null
@@ -1,217 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-ifeq ($(TYPE),debug)
-ERL_COMPILE_FLAGS += -Ddebug -W
-endif
-EBIN=../ebin
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(COSEVENT_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/cosEvent-$(VSN)
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-
-MODULES = \
- CosEventChannelAdmin_ProxyPullConsumer_impl \
- CosEventChannelAdmin_ProxyPushConsumer_impl \
- CosEventChannelAdmin_SupplierAdmin_impl \
- oe_CosEventComm_CAdmin_impl \
- oe_CosEventComm_Channel_impl \
- oe_CosEventComm_PullerS_impl \
- oe_CosEventComm_PusherS_impl \
- cosEventApp
-
-
-
-ERL_FILES = $(MODULES:%=%.erl)
-HRL_FILES = cosEventApp.hrl
-
-
-GEN_ERL_FILES1 = \
- oe_CosEventChannelAdmin.erl \
- CosEventChannelAdmin_ConsumerAdmin.erl \
- CosEventChannelAdmin_EventChannel.erl \
- CosEventChannelAdmin_ProxyPullConsumer.erl \
- CosEventChannelAdmin_ProxyPullSupplier.erl \
- CosEventChannelAdmin_ProxyPushConsumer.erl \
- CosEventChannelAdmin_ProxyPushSupplier.erl \
- CosEventChannelAdmin_SupplierAdmin.erl \
- CosEventChannelAdmin_AlreadyConnected.erl \
- CosEventChannelAdmin_TypeError.erl
-
-GEN_ERL_FILES2 = \
- oe_CosEventComm_CAdmin.erl \
- oe_CosEventComm_Channel.erl \
- oe_CosEventComm_Event.erl \
- oe_CosEventComm_PullerS.erl \
- oe_CosEventComm_PusherS.erl \
- oe_cosEventApp.erl
-
-GEN_ERL_FILES3 = \
- oe_CosEventComm.erl \
- CosEventComm_Disconnected.erl \
- CosEventComm_PullConsumer.erl \
- CosEventComm_PullSupplier.erl \
- CosEventComm_PushConsumer.erl \
- CosEventComm_PushSupplier.erl
-
-GEN_ERL_FILES = \
- $(GEN_ERL_FILES1) $(GEN_ERL_FILES2) $(GEN_ERL_FILES3)
-
-EXTERNAL_INC_PATH = ../include
-
-GEN_HRL_FILES1 = \
- oe_CosEventChannelAdmin.hrl \
- CosEventChannelAdmin.hrl \
- CosEventChannelAdmin_ConsumerAdmin.hrl \
- CosEventChannelAdmin_EventChannel.hrl \
- CosEventChannelAdmin_ProxyPullConsumer.hrl \
- CosEventChannelAdmin_ProxyPullSupplier.hrl \
- CosEventChannelAdmin_ProxyPushConsumer.hrl \
- CosEventChannelAdmin_ProxyPushSupplier.hrl \
- CosEventChannelAdmin_SupplierAdmin.hrl
-
-EXTERNAL_GEN_HRL_FILES1 = $(GEN_HRL_FILES1:%=$(EXTERNAL_INC_PATH)/%)
-
-GEN_HRL_FILES2 = \
- oe_CosEventComm_PullerS.hrl \
- oe_CosEventComm_CAdmin.hrl \
- oe_CosEventComm_PusherS.hrl \
- oe_CosEventComm_Channel.hrl \
- oe_cosEventApp.hrl \
- oe_CosEventComm_Event.hrl
-
-GEN_HRL_FILES3 = \
- oe_CosEventComm.hrl \
- CosEventComm.hrl \
- CosEventComm_PullConsumer.hrl \
- CosEventComm_PullSupplier.hrl \
- CosEventComm_PushConsumer.hrl \
- CosEventComm_PushSupplier.hrl
-
-EXTERNAL_GEN_HRL_FILES3 = $(GEN_HRL_FILES3:%=$(EXTERNAL_INC_PATH)/%)
-
-GEN_HRL_FILES = \
- $(EXTERNAL_GEN_HRL_FILES1) $(GEN_HRL_FILES2) $(EXTERNAL_GEN_HRL_FILES3)
-
-TARGET_FILES = \
- $(GEN_ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR)) \
- $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-
-GEN_FILES = $(GEN_HRL_FILES) $(GEN_ERL_FILES)
-
-IDL_FILES = \
- CosEventChannelAdmin.idl \
- CosEventComm.idl \
- cosEventApp.idl
-
-APPUP_FILE = cosEvent.appup
-APPUP_SRC = $(APPUP_FILE).src
-APPUP_TARGET = $(EBIN)/$(APPUP_FILE)
-
-APP_FILE = cosEvent.app
-APP_SRC = $(APP_FILE).src
-APP_TARGET = $(EBIN)/$(APP_FILE)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_IDL_FLAGS += -pa $(ERL_TOP)/lib/cosEvent/ebin -pa $(ERL_TOP)/lib/ic/ebin
-# The -pa option is just used temporary until erlc can handle
-# includes from other directories than ../include .
-ERL_COMPILE_FLAGS += \
- $(ERL_IDL_FLAGS) \
- -I$(ERL_TOP)/lib/orber/include \
- -I$(ERL_TOP)/lib/cosEvent/include \
- +'{parse_transform,sys_pre_attributes}' \
- +'{attribute,insert,app_vsn,"cosEvent_$(COSEVENT_VSN)"}'
-
-YRL_FLAGS =
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
-
-debug:
- @${MAKE} TYPE=debug opt
-
-clean:
- rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET) IDL-GENERATED
- rm -f errs core *~
-
-$(APP_TARGET): $(APP_SRC)
- $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $(APP_SRC) > $(APP_TARGET)
-$(APPUP_TARGET): $(APPUP_SRC)
- $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $(APPUP_SRC) > $(APPUP_TARGET)
-
-docs:
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-IDL-GENERATED: CosEventChannelAdmin.idl cosEventApp.idl CosEventComm.idl
- $(gen_verbose)erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosEventChannelAdmin.cfg"}' CosEventChannelAdmin.idl
- $(V_at)mv $(GEN_HRL_FILES1) $(EXTERNAL_INC_PATH)
- $(V_at)erlc $(ERL_IDL_FLAGS) +'{cfgfile,"cosEventApp.cfg"}' cosEventApp.idl
- $(V_at)erlc $(ERL_IDL_FLAGS) CosEventComm.idl
- $(V_at)mv $(GEN_HRL_FILES3) $(EXTERNAL_INC_PATH)
- $(V_at)>IDL-GENERATED
-
-$(GEN_FILES): IDL-GENERATED
-
-$(TARGET_FILES): IDL-GENERATED
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)"
- $(INSTALL_DATA) ../info "$(RELSYSDIR)"
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
- $(INSTALL_DIR) "$(RELSYSDIR)/src"
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(GEN_ERL_FILES) $(IDL_FILES) "$(RELSYSDIR)/src"
- $(INSTALL_DIR) "$(RELSYSDIR)/include"
- $(INSTALL_DATA) $(GEN_HRL_FILES) "$(RELSYSDIR)/include"
-
-
-release_docs_spec:
-
-
-
-
-
-
diff --git a/lib/cosEvent/src/cosEvent.app.src b/lib/cosEvent/src/cosEvent.app.src
deleted file mode 100644
index 5ffd12bc6b..0000000000
--- a/lib/cosEvent/src/cosEvent.app.src
+++ /dev/null
@@ -1,46 +0,0 @@
-{application, cosEvent,
- [{description, "The Erlang CosEvent application"},
- {vsn, "%VSN%"},
- {modules,
- [
- 'CosEventChannelAdmin_ProxyPullConsumer_impl',
- 'CosEventChannelAdmin_ProxyPushConsumer_impl',
- 'CosEventChannelAdmin_SupplierAdmin_impl',
- 'oe_CosEventComm_CAdmin_impl',
- 'oe_CosEventComm_Channel_impl',
- 'oe_CosEventComm_PullerS_impl',
- 'oe_CosEventComm_PusherS_impl',
- 'cosEventApp',
- 'oe_CosEventChannelAdmin',
- 'CosEventChannelAdmin_AlreadyConnected',
- 'CosEventChannelAdmin_ConsumerAdmin',
- 'CosEventChannelAdmin_EventChannel',
- 'CosEventChannelAdmin_ProxyPullConsumer',
- 'CosEventChannelAdmin_ProxyPullSupplier',
- 'CosEventChannelAdmin_ProxyPushConsumer',
- 'CosEventChannelAdmin_ProxyPushSupplier',
- 'CosEventChannelAdmin_SupplierAdmin',
- 'CosEventChannelAdmin_TypeError',
- 'oe_CosEventComm_CAdmin',
- 'oe_CosEventComm_Channel',
- 'oe_CosEventComm_Event',
- 'oe_CosEventComm_PullerS',
- 'oe_CosEventComm_PusherS',
- 'oe_cosEventApp',
- 'oe_CosEventComm',
- 'CosEventComm_PushSupplier',
- 'CosEventComm_PushConsumer',
- 'CosEventComm_PullSupplier',
- 'CosEventComm_PullConsumer',
- 'CosEventComm_Disconnected'
- ]
- },
- {registered, []},
- {applications, [orber, stdlib, kernel]},
- {env, []},
- {mod, {cosEventApp, []}},
- {runtime_dependencies, ["stdlib-2.0","orber-3.6.27","kernel-3.0","erts-7.0"]}
-]}.
-
-
-
diff --git a/lib/cosEvent/src/cosEvent.appup.src b/lib/cosEvent/src/cosEvent.appup.src
deleted file mode 100644
index d69b2ef20c..0000000000
--- a/lib/cosEvent/src/cosEvent.appup.src
+++ /dev/null
@@ -1,6 +0,0 @@
-{"%VSN%",
- [
- ],
- [
- ]
-}
diff --git a/lib/cosEvent/src/cosEventApp.cfg b/lib/cosEvent/src/cosEventApp.cfg
deleted file mode 100644
index bbacd134f7..0000000000
--- a/lib/cosEvent/src/cosEventApp.cfg
+++ /dev/null
@@ -1,15 +0,0 @@
-{this, "oe_CosEventComm::Event"}.
-{from, "oe_CosEventComm::Event"}.
-{{handle_info, "oe_CosEventComm::Event"}, true}.
-{this, "oe_CosEventComm::Channel"}.
-{from, "oe_CosEventComm::Channel"}.
-{{handle_info, "oe_CosEventComm::Channel"}, true}.
-{this, "oe_CosEventComm::CAdmin"}.
-{from, "oe_CosEventComm::CAdmin"}.
-{{handle_info, "oe_CosEventComm::CAdmin"}, true}.
-{this, "oe_CosEventComm::PullerS"}.
-{from, "oe_CosEventComm::PullerS"}.
-{{handle_info, "oe_CosEventComm::PullerS"}, true}.
-{this, "oe_CosEventComm::PusherS"}.
-{from, "oe_CosEventComm::PusherS"}.
-{{handle_info, "oe_CosEventComm::PusherS"}, true}.
diff --git a/lib/cosEvent/src/cosEventApp.erl b/lib/cosEvent/src/cosEventApp.erl
deleted file mode 100644
index b3c38cef0e..0000000000
--- a/lib/cosEvent/src/cosEventApp.erl
+++ /dev/null
@@ -1,301 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : cosEventApp.erl
-%% Description :
-%%
-%%----------------------------------------------------------------------
--module(cosEventApp).
-
-%%--------------- INCLUDES -----------------------------------
--include_lib("orber/include/corba.hrl").
--include("cosEventApp.hrl").
-
-
-%%--------------- EXPORTS-------------------------------------
-%% cosEvent API external
--export([start/0, stop/0, install/0, uninstall/0, start_channel/0, start_channel/1,
- start_channel_link/0, start_channel_link/1, stop_channel/1]).
-
-%% cosEvent API internal
--export([create_link/3, get_option/2, type_check/3, disconnect/3, do_disconnect/3]).
-
-%% Application callbacks
--export([start/2, init/1, stop/1]).
-
-%%--------------- DEFINES ------------------------------------
--define(IDL_MODULES, ['oe_CosEventComm',
- 'oe_CosEventChannelAdmin',
- 'oe_cosEventApp']).
-
--define(SUPERVISOR_NAME, oe_cosEventSup).
--define(SUP_FLAG, {simple_one_for_one,50,10}).
-
--define(SUP_SPEC(Name, Args),
- ['CosEventChannel_EventChannel',Args,
- [{sup_child, true}, {regname, {global, Name}}]]).
--define(SUP_CHILD,
- {"oe_EventChild",
- {cosEventApp,create_link, []},
- transient,100000,worker,
- ['CosEventChannel_EventChannel']}).
-
-
-%%-----------------------------------------------------------%
-%% function : install
-%% Arguments: -
-%% Returns : ok | EXIT | EXCEPTION
-%% Effect : Install necessary data in the IFR DB
-%%------------------------------------------------------------
-install() ->
- case install_loop(?IDL_MODULES, []) of
- ok ->
- ok;
- {error, Reason} ->
- exit(Reason)
- end.
-
-install_loop([], _) ->
- ok;
-install_loop([H|T], Accum) ->
- case catch H:'oe_register'() of
- {'EXIT',{unregistered,App}} ->
- ?write_ErrorMsg("Unable to register '~p'; application ~p not registered.\n"
- "Trying to unregister ~p~n", [H,App,Accum]),
- uninstall_loop(Accum, {exit, register});
- {'EXCEPTION',_} ->
- ?write_ErrorMsg("Unable to register '~p'; propably already registered.\n"
- "You are adviced to confirm this.\n"
- "Trying to unregister ~p~n", [H,Accum]),
- uninstall_loop(Accum, {exit, register});
- ok ->
- install_loop(T, [H|Accum]);
- _ ->
- ?write_ErrorMsg("Unable to register '~p'; reason unknown.\n"
- "Trying to unregister ~p~n", [H,Accum]),
- uninstall_loop(Accum, {exit, register})
- end.
-
-%%-----------------------------------------------------------%
-%% function : uninstall
-%% Arguments: -
-%% Returns : ok | EXIT | EXCEPTION
-%% Effect : Remove data related to cosEvent from the IFR DB
-%%------------------------------------------------------------
-uninstall() ->
- case uninstall_loop(lists:reverse(?IDL_MODULES), ok) of
- ok ->
- ok;
- {error, Reason} ->
- exit(Reason)
- end.
-
-uninstall_loop([],ok) ->
- ok;
-uninstall_loop([],{exit, register}) ->
- {error, {?MODULE, "oe_register failed"}};
-uninstall_loop([],{exit, unregister}) ->
- {error, {?MODULE, "oe_unregister failed"}};
-uninstall_loop([],{exit, both}) ->
- {error, {?MODULE, "oe_register and, for some of those already registered, oe_unregister failed"}};
-uninstall_loop([H|T], Status) ->
- case catch H:'oe_unregister'() of
- ok ->
- uninstall_loop(T, Status);
- _ when Status == ok ->
- ?write_ErrorMsg("Unable to unregister '~p'; propably already unregistered.\n"
- "You are adviced to confirm this.\n",[H]),
- uninstall_loop(T, {exit, unregister});
- _ ->
- ?write_ErrorMsg("Unable to unregister '~p'; propably already unregistered.\n"
- "You are adviced to confirm this.\n",[H]),
- uninstall_loop(T, {exit, both})
- end.
-
-%%-----------------------------------------------------------%
-%% function : start/stop
-%% Arguments:
-%% Returns :
-%% Effect : Starts or stops the cosTime application.
-%%------------------------------------------------------------
-
-start() ->
- application:start(cosEvent).
-stop() ->
- application:stop(cosEvent).
-
-%%-----------------------------------------------------------%
-%% function : start
-%% Arguments: Type - see module application
-%% Arg - see module application
-%% Returns :
-%% Effect : Module callback for application
-%%------------------------------------------------------------
-
-start(_, _) ->
- supervisor:start_link({local, ?SUPERVISOR_NAME}, cosEventApp, app_init).
-
-
-%%-----------------------------------------------------------%
-%% function : stop
-%% Arguments: Arg - see module application
-%% Returns :
-%% Effect : Module callback for application
-%%------------------------------------------------------------
-
-stop(_) ->
- ok.
-
-%%-----------------------------------------------------------%
-%% function : start_channel
-%% Arguments: -
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-start_channel() ->
- start_channel(?DEFAULT_OPTIONS).
-
-start_channel(Options) when is_list(Options) ->
- ServerOpts = get_option(?SERVER, Options),
- 'oe_CosEventComm_Channel':oe_create([Options, ServerOpts], ServerOpts);
-start_channel(Options) ->
- orber:dbg("[~p] cosEventApp:start_channel(~p);~n"
- "Options not correct.", [?LINE, Options], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%-----------------------------------------------------------%
-%% function : start_channel
-%% Arguments: -
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-start_channel_link() ->
- start_channel_link(?DEFAULT_OPTIONS).
-
-start_channel_link(Options) when is_list(Options) ->
- ServerOpts = get_option(?SERVER, Options),
- 'oe_CosEventComm_Channel':oe_create_link([Options, ServerOpts], ServerOpts);
-start_channel_link(Options) ->
- orber:dbg("[~p] cosEventApp:start_channel_link(~p);~n"
- "Options not correct.", [?LINE, Options], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%-----------------------------------------------------------%
-%% function : stop_factory
-%% Arguments: ChannelObj
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-stop_channel(ChannelObj) ->
- corba:dispose(ChannelObj).
-
-%%-----------------------------------------------------------%
-%% function : init
-%% Arguments:
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-
-%% Starting using create_factory/X
-init(own_init) ->
- {ok,{?SUP_FLAG, [?SUP_CHILD]}};
-%% When starting as an application.
-init(app_init) ->
- {ok,{?SUP_FLAG, [?SUP_CHILD]}}.
-
-%%-----------------------------------------------------------%
-%% function : create_link
-%% Arguments: Module - which Module to call
-%% Env/ArgList - ordinary oe_create arguments.
-%% Returns :
-%% Exception:
-%% Effect : Necessary since we want the supervisor to be a
-%% 'simple_one_for_one'. Otherwise, using for example,
-%% 'one_for_one', we have to call supervisor:delete_child
-%% to remove the childs startspecification from the
-%% supervisors internal state.
-%%------------------------------------------------------------
-create_link(Module, Env, ArgList) ->
- Module:oe_create_link(Env, ArgList).
-
-
-%%-----------------------------------------------------------%
-%% function : get_option
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-get_option(Key, OptionList) ->
- case lists:keysearch(Key, 1, OptionList) of
- {value,{Key,Value}} ->
- Value;
- _ ->
- case lists:keysearch(Key, 1, ?DEFAULT_OPTIONS) of
- {value,{Key,Value}} ->
- Value;
- _->
- {error, "Invalid option"}
- end
- end.
-
-%%-----------------------------------------------------------%
-%% function : type_check
-%% Arguments: Obj - objectrefernce to test.
-%% Mod - Module which contains typeID/0.
-%% Returns : 'ok' or raises exception.
-%% Effect :
-%%------------------------------------------------------------
-type_check(_Obj, _Mod, false) ->
- ok;
-type_check(Obj, Mod, _) ->
- case catch corba_object:is_a(Obj, Mod:typeID()) of
- true ->
- ok;
- _ ->
- orber:dbg("[~p] cosEventApp:type_check(~p) failed; Should be ~p",
- [?LINE, Obj, Mod], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO})
- end.
-
-%%-----------------------------------------------------------%
-%% function : disconnect
-%% Arguments: Module - one of the interfaces defined in CosEventComm.
-%% Function - the appropriate disconnect function.
-%% Object - the client object reference.
-%% Returns : ok
-%% Exception:
-%% Effect : If the process would try to diconnect itself it could
-%% result in a deadlock. Hence, we spawn a new process to do it.
-%%------------------------------------------------------------
-disconnect(Module, Function, Object) ->
- spawn(cosEventApp, do_disconnect, [Module, Function, Object]),
- ok.
-
-do_disconnect(Module, Function, Object) ->
- catch Module:Function(Object),
- ?DBG("Disconnect ~p:~p(..).~n", [Module, Function]),
- ok.
-
-%%--------------- END OF MODULE ------------------------------
-
-
diff --git a/lib/cosEvent/src/cosEventApp.hrl b/lib/cosEvent/src/cosEventApp.hrl
deleted file mode 100644
index d801e83530..0000000000
--- a/lib/cosEvent/src/cosEventApp.hrl
+++ /dev/null
@@ -1,63 +0,0 @@
-%%----------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : cosEventApp.hrl
-%% Description :
-%%
-%%----------------------------------------------------------------------
-
-%%--------------- INCLUDES -----------------------------------
-%% External
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
-
--define(write_ErrorMsg(Txt, Arg),
-error_logger:error_msg("================ CosEvent =================~n"
- Txt
- "===========================================~n",
- Arg)).
-
-
--define(PULL_INTERVAL, pull_interval).
--define(TYPECHECK, typecheck).
--define(MAXEVENTS, maxEvents).
--define(BLOCKING, blocking).
--define(SERVER, server_options).
--define(DEFAULT_OPTIONS, [{?PULL_INTERVAL, 20},
- {?BLOCKING, true},
- {?TYPECHECK, false},
- {?MAXEVENTS, 300},
- {?SERVER, []}]).
-
--define(DEBUG_LEVEL, 3).
-
--ifdef(debug).
--define(DBG(F,A),
- io:format("[~p (~p)] "++F,[?MODULE, ?LINE]++A)).
--else.
--define(DBG(F,A), ok).
--endif.
-
-
-
-
-%%--------------- END OF MODULE ----------------------------------------
diff --git a/lib/cosEvent/src/cosEventApp.idl b/lib/cosEvent/src/cosEventApp.idl
deleted file mode 100644
index e5a134685f..0000000000
--- a/lib/cosEvent/src/cosEventApp.idl
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef _COS_EVENT_APP_IDL_
-#define _COS_EVENT_APP_IDL_
-
-#include<CosEventChannelAdmin.idl>
-
-
-module oe_CosEventComm {
-
-
- interface Event {
- oneway void send(in any event);
- void send_sync(in any event);
- };
-
- interface Channel : CosEventChannelAdmin::EventChannel, Event {};
-
- interface CAdmin : CosEventChannelAdmin::ConsumerAdmin, Event {};
-
- interface PullerS : CosEventChannelAdmin::ProxyPullSupplier, Event {};
-
- interface PusherS : CosEventChannelAdmin::ProxyPushSupplier, Event {};
-
-};
-
-
-#endif
diff --git a/lib/cosEvent/src/oe_CosEventComm_CAdmin_impl.erl b/lib/cosEvent/src/oe_CosEventComm_CAdmin_impl.erl
deleted file mode 100644
index 728c4cc5ab..0000000000
--- a/lib/cosEvent/src/oe_CosEventComm_CAdmin_impl.erl
+++ /dev/null
@@ -1,234 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : oe_CosEventComm_CAdmin_impl.erl
-%% Description :
-%%
-%%----------------------------------------------------------------------
--module(oe_CosEventComm_CAdmin_impl).
-
-%%----------------------------------------------------------------------
-%% Include files
-%%----------------------------------------------------------------------
--include_lib("orber/include/corba.hrl").
--include("cosEventApp.hrl").
-
-%%----------------------------------------------------------------------
-%% External exports
-%%----------------------------------------------------------------------
--export([init/1,
- terminate/2,
- code_change/3,
- handle_info/2]).
-
-%% Exports from "CosEventChannelAdmin::ConsumerAdmin"
--export([obtain_push_supplier/3,
- obtain_pull_supplier/3]).
-
-
-%%----------------------------------------------------------------------
-%% Internal exports
-%%----------------------------------------------------------------------
-%% Exports from "oe_CosEventComm::Event"
--export([send/3, send_sync/4]).
-
-%%----------------------------------------------------------------------
-%% Records
-%%----------------------------------------------------------------------
--record(state, {channel_pid, typecheck, maxevents, proxies = [],
- server_options}).
-
-%%----------------------------------------------------------------------
-%% Macros
-%%----------------------------------------------------------------------
-
-
-%%======================================================================
-%% External functions
-%%======================================================================
-%%----------------------------------------------------------------------
-%% Function : init/1
-%% Returns : {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
-%% Description: Initiates the server
-%%----------------------------------------------------------------------
-init([ChannelPid, TypeCheck, MaxEvents, ServerOpts]) ->
- process_flag(trap_exit, true),
- {ok, #state{channel_pid = ChannelPid, typecheck = TypeCheck,
- maxevents = MaxEvents, server_options = ServerOpts}}.
-
-%%----------------------------------------------------------------------
-%% Function : terminate/2
-%% Returns : any (ignored by gen_server)
-%% Description: Shutdown the server
-%%----------------------------------------------------------------------
-terminate(_Reason, _State) ->
- ?DBG("Terminating ~p~n", [_Reason]),
- ok.
-
-%%----------------------------------------------------------------------
-%% Function : code_change/3
-%% Returns : {ok, NewState}
-%% Description: Convert process state when code is changed
-%%----------------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%---------------------------------------------------------------------%
-%% function : handle_info
-%% Arguments:
-%% Returns : {noreply, State} |
-%% {stop, Reason, State}
-%% Effect : Functions demanded by the gen_server module.
-%%----------------------------------------------------------------------
-handle_info({'EXIT', Pid, Reason}, #state{channel_pid = Pid} = State) ->
- ?DBG("Parent Channel terminated ~p~n", [Reason]),
- orber:dbg("[~p] oe_CosEventComm_PullerS_impl:handle_info(~p);~n"
- "My Channel terminated and so will I which will cause"
- " my children to do the same thing.",
- [?LINE, Reason], ?DEBUG_LEVEL),
- {stop, Reason, State};
-handle_info({'EXIT', Pid, _Reason}, #state{proxies = Proxies} = State) ->
- %% A child terminated which is normal. Hence, no logging.
- ?DBG("Probably a child terminated ~p~n", [_Reason]),
- {noreply, State#state{proxies = lists:keydelete(Pid, 2, Proxies)}};
-handle_info(_Info, State) ->
- ?DBG("Unknown Info ~p~n", [_Info]),
- {noreply, State}.
-
-%%----------------------------------------------------------------------
-%% Function : obtain_push_supplier
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-obtain_push_supplier(_, _, #state{server_options = ServerOpts} = State) ->
- case catch 'oe_CosEventComm_PusherS':oe_create_link([self(),
- State#state.typecheck],
- [{sup_child, true}|ServerOpts]) of
- {ok, Pid, Proxy} ->
- ?DBG("Started a new oe_CosEventComm_PusherS.~n", []),
- {reply, Proxy, State#state{proxies = [{Proxy, Pid}|State#state.proxies]}};
- Other ->
- orber:dbg("[~p] oe_CosEventComm_CAdmin:obtain_push_supplier();~nError: ~p",
- [?LINE, Other], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-%%----------------------------------------------------------------------
-%% Function : obtain_pull_supplier
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-obtain_pull_supplier(_, _, #state{server_options = ServerOpts} = State) ->
- case catch 'oe_CosEventComm_PullerS':oe_create_link([self(),
- State#state.typecheck,
- State#state.maxevents],
- [{sup_child, true}|ServerOpts]) of
- {ok, Pid, Proxy} ->
- ?DBG("Started a new oe_CosEventComm_PullerS.~n", []),
- {reply, Proxy, State#state{proxies = [{Proxy, Pid}|State#state.proxies]}};
- Other ->
- orber:dbg("[~p] oe_CosEventComm_CAdmin:obtain_pull_supplier();~nError: ~p",
- [?LINE, Other], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-
-%%----------------------------------------------------------------------
-%% Function : send
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-send(_, #state{proxies = Proxies} = State, Any) ->
- ?DBG("Received Event ~p~n", [Any]),
- case send_helper(Proxies, Any, [], false) of
- ok ->
- ?DBG("Received Event and forwarded it successfully.~n", []),
- {noreply, State};
- {error, Dropped} ->
- ?DBG("Received Event but forward failed to: ~p~n", [Dropped]),
- RemainingProxies = delete_proxies(Dropped, Proxies),
- {noreply, State#state{proxies = RemainingProxies}}
- end.
-
-%%----------------------------------------------------------------------
-%% Function : send_sync
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-send_sync(_, OE_From, #state{proxies = Proxies} = State, Any) ->
- ?DBG("Received Event ~p~n", [Any]),
- corba:reply(OE_From, ok),
- case send_helper(Proxies, Any, [], true) of
- ok ->
- ?DBG("Received Event and forwarded (sync) it successfully.~n", []),
- {noreply, State};
- {error, Dropped} ->
- ?DBG("Received Event but forward (sync) failed to: ~p~n", [Dropped]),
- RemainingProxies = delete_proxies(Dropped, Proxies),
- {noreply, State#state{proxies = RemainingProxies}}
- end.
-
-
-%%======================================================================
-%% Internal functions
-%%======================================================================
-send_helper([], _, [], _) ->
- ok;
-send_helper([], _, Dropped, _) ->
- {error, Dropped};
-send_helper([{ObjRef, Pid}|T], Event, Dropped, false) ->
- case catch 'oe_CosEventComm_Event':send(ObjRef, Event) of
- ok ->
- send_helper(T, Event, Dropped, false);
- What ->
- orber:dbg("[~p] oe_CosEventComm_CAdmin:send_helper(~p, ~p);~n"
- "Bad return value ~p. Closing connection.",
- [?LINE, ObjRef, Event, What], ?DEBUG_LEVEL),
- send_helper(T, Event, [{ObjRef, Pid}|Dropped], false)
- end;
-send_helper([{ObjRef, Pid}|T], Event, Dropped, Sync) ->
- case catch 'oe_CosEventComm_Event':send_sync(ObjRef, Event) of
- ok ->
- send_helper(T, Event, Dropped, Sync);
- What ->
- orber:dbg("[~p] oe_CosEventComm_CAdmin:send_helper(~p, ~p);~n"
- "Bad return value ~p. Closing connection.",
- [?LINE, ObjRef, Event, What], ?DEBUG_LEVEL),
- send_helper(T, Event, [{ObjRef, Pid}|Dropped], Sync)
- end.
-
-delete_proxies([], RemainingProxies) ->
- RemainingProxies;
-delete_proxies([{_,Pid}|T], Proxies) ->
- Rest = lists:keydelete(Pid, 2, Proxies),
- delete_proxies(T, Rest).
-
-%%======================================================================
-%% END OF MODULE
-%%======================================================================
diff --git a/lib/cosEvent/src/oe_CosEventComm_Channel_impl.erl b/lib/cosEvent/src/oe_CosEventComm_Channel_impl.erl
deleted file mode 100644
index 4f53ca6164..0000000000
--- a/lib/cosEvent/src/oe_CosEventComm_Channel_impl.erl
+++ /dev/null
@@ -1,247 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : oe_CosEventComm_Channel_impl.erl
-%% Description :
-%%
-%%----------------------------------------------------------------------
--module(oe_CosEventComm_Channel_impl).
-
-%%----------------------------------------------------------------------
-%% Include files
-%%----------------------------------------------------------------------
--include_lib("orber/include/corba.hrl").
--include("cosEventApp.hrl").
-
-
-%%----------------------------------------------------------------------
-%% External exports
-%%----------------------------------------------------------------------
-%% Mandatory
--export([init/1,
- terminate/2,
- code_change/3,
- handle_info/2]).
-
-%% Exports from "CosEventChannelAdmin::EventChannel"
--export([for_consumers/3,
- for_suppliers/3,
- destroy/3]).
-
-
-%%----------------------------------------------------------------------
-%% Internal exports
-%%----------------------------------------------------------------------
-%% Exports from "oe_CosEventComm::Event"
--export([send/3, send_sync/4]).
-
-%%----------------------------------------------------------------------
-%% Records
-%%----------------------------------------------------------------------
--record(state, {typecheck, pull_interval, maxevents, blocking, cadmins = [],
- server_options}).
-
-%%----------------------------------------------------------------------
-%% Macros
-%%----------------------------------------------------------------------
-
-%%======================================================================
-%% External functions
-%%======================================================================
-%%----------------------------------------------------------------------
-%% Function : init/1
-%% Returns : {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
-%% Description: Initiates the server
-%%----------------------------------------------------------------------
-init([Options, ServerOpts]) ->
- process_flag(trap_exit, true),
- PullI = cosEventApp:get_option(?PULL_INTERVAL, Options),
- TC = cosEventApp:get_option(?TYPECHECK, Options),
- Max = cosEventApp:get_option(?MAXEVENTS, Options),
- Blocking = cosEventApp:get_option(?BLOCKING, Options),
- {ok, #state{typecheck = TC, pull_interval = PullI, maxevents = Max,
- blocking = Blocking, server_options = ServerOpts}}.
-
-%%----------------------------------------------------------------------
-%% Function : terminate/2
-%% Returns : any (ignored by gen_server)
-%% Description: Shutdown the server
-%%----------------------------------------------------------------------
-terminate(_Reason, _State) ->
- ?DBG("Terminating ~p~n", [_Reason]),
- ok.
-
-%%----------------------------------------------------------------------
-%% Function : code_change/3
-%% Returns : {ok, NewState}
-%% Description: Convert process state when code is changed
-%%----------------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%---------------------------------------------------------------------%
-%% function : handle_info
-%% Arguments:
-%% Returns : {noreply, State} |
-%% {stop, Reason, State}
-%% Effect : Functions demanded by the gen_server module.
-%%----------------------------------------------------------------------
-handle_info({'EXIT', Pid, _Reason}, #state{cadmins = CAdmins} = State) ->
- ?DBG("Probably a child terminated with Reason: ~p~n", [_Reason]),
- {noreply, State#state{cadmins = lists:keydelete(Pid, 2, CAdmins)}};
-handle_info(_Info, State) ->
- ?DBG("Unknown Info ~p~n", [_Info]),
- {noreply, State}.
-
-
-%%----------------------------------------------------------------------
-%% Function : for_consumers
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-for_consumers(_, _, #state{server_options = ServerOpts} = State) ->
- case catch 'oe_CosEventComm_CAdmin':oe_create_link([self(),
- State#state.typecheck,
- State#state.maxevents,
- ServerOpts],
- [{sup_child, true}|ServerOpts]) of
- {ok, Pid, AdminCo} ->
- ?DBG("Created a new oe_CosEventComm_CAdmin.~n", []),
- {reply, AdminCo,
- State#state{cadmins = [{AdminCo, Pid}|State#state.cadmins]}};
- Other ->
- orber:dbg("[~p] oe_CosEventComm_Channel:for_consumers(); Error: ~p",
- [?LINE, Other], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-%%----------------------------------------------------------------------
-%% Function : for_suppliers
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-for_suppliers(OE_This, _, #state{server_options = ServerOpts} = State) ->
- case catch 'CosEventChannelAdmin_SupplierAdmin':oe_create_link([OE_This, self(),
- State#state.typecheck,
- State#state.pull_interval,
- ServerOpts],
- [{sup_child, true}|ServerOpts]) of
- {ok, _Pid, AdminSu} ->
- ?DBG("Created a new CosEventChannelAdmin_SupplierAdmin.~n", []),
- {reply, AdminSu, State};
- Other ->
- orber:dbg("[~p] oe_CosEventComm_Channel:for_suppliers();~nError: ~p",
- [?LINE, Other], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-%%----------------------------------------------------------------------
-%% Function : destroy
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-destroy(_, _, State) ->
- ?DBG("Destroy invoked.", []),
- {stop, normal, ok, State}.
-
-%%----------------------------------------------------------------------
-%% Function : send
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-send(_OE_This, #state{cadmins = CAdmins} = State, Any) ->
- ?DBG("Received Event ~p~n", [Any]),
- case send_helper(CAdmins, Any, [], false) of
- ok ->
- ?DBG("Received Event and forwarded it successfully.~n", []),
- {noreply, State};
- {error, Dropped} ->
- ?DBG("Received Event but forward failed for: ~p~n", [Dropped]),
- RemainingAdmins = delete_cadmin(Dropped, CAdmins),
- {noreply, State#state{cadmins = RemainingAdmins}}
- end.
-
-%%----------------------------------------------------------------------
-%% Function : send_sync
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-send_sync(_OE_This, OE_From, #state{cadmins = CAdmins, blocking = BL} = State, Any) ->
- ?DBG("Received Event ~p~n", [Any]),
- corba:reply(OE_From, ok),
- case send_helper(CAdmins, Any, [], BL) of
- ok ->
- ?DBG("Received Event and forwarded (sync) it successfully.~n", []),
- {reply, ok, State};
- {error, Dropped} ->
- ?DBG("Received Event but forward (sync) failed for: ~p~n", [Dropped]),
- RemainingAdmins = delete_cadmin(Dropped, CAdmins),
- {reply, ok, State#state{cadmins = RemainingAdmins}}
- end.
-
-
-%%======================================================================
-%% Internal functions
-%%======================================================================
-send_helper([], _, [], _) ->
- ok;
-send_helper([], _, Dropped, _) ->
- {error, Dropped};
-send_helper([{ObjRef, Pid}|T], Event, Dropped, false) ->
- case catch 'oe_CosEventComm_CAdmin':send(ObjRef, Event) of
- ok ->
- send_helper(T, Event, Dropped, false);
- What ->
- orber:dbg("[~p] oe_CosEventComm_Channel:send_helper(~p, ~p);~n"
- "Bad return value ~p. Closing connection.",
- [?LINE, ObjRef, Event, What], ?DEBUG_LEVEL),
- send_helper(T, Event, [{ObjRef, Pid}|Dropped], false)
- end;
-send_helper([{ObjRef, Pid}|T], Event, Dropped, Sync) ->
- case catch 'oe_CosEventComm_CAdmin':send_sync(ObjRef, Event) of
- ok ->
- send_helper(T, Event, Dropped, Sync);
- What ->
- orber:dbg("[~p] oe_CosEventComm_Channel:send_helper(~p, ~p);~n"
- "Bad return value ~p. Closing connection.",
- [?LINE, ObjRef, Event, What], ?DEBUG_LEVEL),
- send_helper(T, Event, [{ObjRef, Pid}|Dropped], Sync)
- end.
-
-
-delete_cadmin([], RemainingAdmins) ->
- RemainingAdmins;
-delete_cadmin([{_,Pid}|T], CAdmins) ->
- Rest = lists:keydelete(Pid, 2, CAdmins),
- delete_cadmin(T, Rest).
-
-%%======================================================================
-%% END OF MODULE
-%%======================================================================
diff --git a/lib/cosEvent/src/oe_CosEventComm_PullerS_impl.erl b/lib/cosEvent/src/oe_CosEventComm_PullerS_impl.erl
deleted file mode 100644
index b431296624..0000000000
--- a/lib/cosEvent/src/oe_CosEventComm_PullerS_impl.erl
+++ /dev/null
@@ -1,282 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2015. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : oe_CosEventComm_PullerS_impl.erl
-%% Description :
-%%
-%%----------------------------------------------------------------------
--module(oe_CosEventComm_PullerS_impl).
-
-%%----------------------------------------------------------------------
-%% Include files
-%%----------------------------------------------------------------------
--include_lib("orber/include/corba.hrl").
--include("CosEventChannelAdmin.hrl").
--include("CosEventComm.hrl").
--include("cosEventApp.hrl").
-
-%%----------------------------------------------------------------------
-%% External exports
-%%----------------------------------------------------------------------
--export([init/1,
- terminate/2,
- code_change/3,
- handle_info/2]).
-%% Exports from "CosEventChannelAdmin::ProxyPullSupplier"
--export([connect_pull_consumer/4]).
-
-%% Exports from "CosEventComm::PullSupplier"
--export([pull/3,
- try_pull/3,
- disconnect_pull_supplier/3]).
-
-%%----------------------------------------------------------------------
-%% Internal exports
-%%----------------------------------------------------------------------
-%% Exports from "oe_CosEventComm::Event
--export([send/3, send_sync/4]).
-
-%%----------------------------------------------------------------------
-%% Records
-%%----------------------------------------------------------------------
--record(state, {admin_pid, client, db, respond_to, typecheck, maxevents}).
-
-%%----------------------------------------------------------------------
-%% Macros
-%%----------------------------------------------------------------------
-
-%%======================================================================
-%% External functions
-%%======================================================================
-%%---------------------------------------------------------------------%
-%% Function : init/1
-%% Returns : {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
-%% Description: Initiates the server
-%%----------------------------------------------------------------------
-init([AdminPid, TypeCheck, MaxEvents]) ->
- process_flag(trap_exit, true),
- {ok, #state{admin_pid = AdminPid,
- db = ets:new(oe_ets, [set, private, ordered_set]),
- typecheck = TypeCheck, maxevents = MaxEvents}}.
-
-%%---------------------------------------------------------------------%
-%% function : handle_info
-%% Arguments:
-%% Returns : {noreply, State} |
-%% {stop, Reason, State}
-%% Effect : Functions demanded by the gen_server module.
-%% The CosEvent specification states:
-%% "A nil object reference may be passed to the connect_pull_consumer operation;
-%% if so a channel cannot invoke a disconnect_pull_consumer operation on the
-%% consumer; the consumer may be disconnected from the channel without being
-%% informed."
-%% If we would invoke the disconnect_pull_consumer operation
-%% at the same time as the client tries to pull an event it
-%% would cause a dead-lock. We can solve this by spawning a process
-%% but as is the client will discover that the object no longer exists
-%% the next time it tries to pull an event.
-%%----------------------------------------------------------------------
-handle_info({'EXIT', Pid, Reason}, #state{admin_pid = Pid} = State) ->
- orber:dbg("[~p] oe_CosEventComm_PullerS_impl:handle_info(~p);~n"
- "My Admin terminated and so will I.",
- [?LINE, Reason], ?DEBUG_LEVEL),
- {stop, Reason, State};
-handle_info(_Info, State) ->
- ?DBG("Unknown Info ~p~n", [_Info]),
- {noreply, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : terminate/2
-%% Returns : any (ignored by gen_server)
-%% Description: Shutdown the server
-%%----------------------------------------------------------------------
-terminate(_Reason, #state{client = undefined, respond_to = undefined, db = DB}) ->
- ?DBG("Terminating ~p; no client connected and no pending pull's.~n", [_Reason]),
- ets:delete(DB),
- ok;
-terminate(_Reason, #state{client = undefined, respond_to = ReplyTo, db = DB}) ->
- ?DBG("Terminating ~p; no client connected but a pending pull.~n", [_Reason]),
- corba:reply(ReplyTo, {'EXCEPTION', #'CosEventComm_Disconnected'{}}),
- ets:delete(DB),
- ok;
-terminate(_Reason, #state{client = Client, respond_to = undefined, db = DB}) ->
- ?DBG("Terminating ~p; no pending pull~n", [_Reason]),
- cosEventApp:disconnect('CosEventComm_PullConsumer',
- disconnect_pull_consumer, Client),
- ets:delete(DB),
- ok;
-terminate(_Reason, #state{client = Client, respond_to = ReplyTo, db = DB}) ->
- ?DBG("Terminating ~p; pending pull~n", [_Reason]),
- corba:reply(ReplyTo, {'EXCEPTION', #'CosEventComm_Disconnected'{}}),
- cosEventApp:disconnect('CosEventComm_PullConsumer',
- disconnect_pull_consumer, Client),
- ets:delete(DB),
- ok.
-
-%%---------------------------------------------------------------------%
-%% Function : code_change/3
-%% Returns : {ok, NewState}
-%% Description: Convert process state when code is changed
-%%----------------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : connect_pull_consumer
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-connect_pull_consumer(_OE_This, _OE_From, #state{client = undefined,
- typecheck = TypeCheck} = State,
- NewClient) ->
- case corba_object:is_nil(NewClient) of
- true ->
- ?DBG("A NIL client supplied.~n", []),
- {reply, ok, State};
- false ->
- cosEventApp:type_check(NewClient, 'CosEventComm_PullConsumer', TypeCheck),
- ?DBG("Connected to client.~n", []),
- {reply, ok, State#state{client = NewClient}}
- end;
-connect_pull_consumer(_, _, _, _) ->
- corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}).
-
-
-%%---------------------------------------------------------------------%
-%% Function : pull
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-pull(_OE_This, OE_From, State) ->
- case get_event(State#state.db) of
- false ->
- ?DBG("pull invoked but no event stored; put the client on hold.~n", []),
- {noreply, State#state{respond_to = OE_From}};
- Event ->
- ?DBG("pull invoked and returned: ~p~n", [Event]),
- {reply, Event, State}
- end.
-
-%%---------------------------------------------------------------------%
-%% Function : try_pull
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-try_pull(_OE_This, _OE_From, State) ->
- case get_event(State#state.db) of
- false ->
- ?DBG("try_pull invoked but no event stored.~n", []),
- {reply, {any:create(orber_tc:long(), 0), false}, State};
- Event ->
- ?DBG("try_pull invoked and returned: ~p~n", [Event]),
- {reply, {Event, true}, State}
- end.
-
-%%---------------------------------------------------------------------%
-%% Function : disconnect_pull_supplier
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-disconnect_pull_supplier(_OE_This, _OE_From, State) ->
- ?DBG("Disconnect invoked ~p ~n", [State]),
- {stop, normal, ok, State#state{client = undefined}}.
-
-
-%%======================================================================
-%% Internal functions
-%%======================================================================
-%%---------------------------------------------------------------------%
-%% Function : send
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-send(_OE_This, #state{respond_to = undefined} = State, Any) ->
- ?DBG("Received event ~p and stored it.~n", [Any]),
- store_event(State#state.db, State#state.maxevents, Any),
- {noreply, State};
-send(_OE_This, State, Any) ->
- ?DBG("Received event ~p and sent it to pending client.~n", [Any]),
- corba:reply(State#state.respond_to, Any),
- {noreply, State#state{respond_to = undefined}}.
-
-%%---------------------------------------------------------------------%
-%% Function : send_sync
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-send_sync(_OE_This, _OE_From, #state{respond_to = undefined} = State, Any) ->
- ?DBG("Received event ~p and stored it (sync).~n", [Any]),
- store_event(State#state.db, State#state.maxevents, Any),
- {reply, ok, State};
-send_sync(_OE_This, _OE_From, State, Any) ->
- ?DBG("Received event ~p and sent it to pending client (sync).~n", [Any]),
- corba:reply(State#state.respond_to, Any),
- {reply, ok, State#state{respond_to = undefined}}.
-
-
-%%---------------------------------------------------------------------%
-%% Function : store_event
-%% Arguments : DB - ets reference
-%% Event - CORBA::Any
-%% Returns : true
-%% Description: Insert the event in FIFO order.
-%%----------------------------------------------------------------------
-store_event(DB, Max, Event) ->
- case ets:info(DB, size) of
- CurrentSize when CurrentSize < Max ->
- ets:insert(DB, {{erlang:system_time(), erlang:unique_integer([positive])},
- Event});
- _ ->
- orber:dbg("[~p] oe_CosEventComm_PullerS:store_event(~p); DB full drop event.",
- [?LINE, Event], ?DEBUG_LEVEL),
- true
- end.
-
-%%---------------------------------------------------------------------%
-%% Function : get_event
-%% Arguments : DB - ets reference
-%% Event - CORBA::Any
-%% Returns : false | Event (CORBA::Any)
-%% Description: Lookup event in FIFO order; return false if no event exists.
-%%----------------------------------------------------------------------
-get_event(DB) ->
- case ets:first(DB) of
- '$end_of_table' ->
- false;
- Key ->
- [{_, Event}] = ets:lookup(DB, Key),
- ets:delete(DB, Key),
- Event
- end.
-
-%%======================================================================
-%% END OF MODULE
-%%======================================================================
diff --git a/lib/cosEvent/src/oe_CosEventComm_PusherS_impl.erl b/lib/cosEvent/src/oe_CosEventComm_PusherS_impl.erl
deleted file mode 100644
index ac23412000..0000000000
--- a/lib/cosEvent/src/oe_CosEventComm_PusherS_impl.erl
+++ /dev/null
@@ -1,218 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : oe_CosEventComm_PusherS_impl.erl
-%% Description :
-%%
-%%----------------------------------------------------------------------
--module(oe_CosEventComm_PusherS_impl).
-
-%%----------------------------------------------------------------------
-%% Include files
-%%----------------------------------------------------------------------
--include_lib("orber/include/corba.hrl").
--include("CosEventChannelAdmin.hrl").
--include("CosEventComm.hrl").
--include("cosEventApp.hrl").
-
-
-%%----------------------------------------------------------------------
-%% External exports
-%%----------------------------------------------------------------------
--export([init/1,
- terminate/2,
- code_change/3,
- handle_info/2]).
-
-%% Exports from "CosEventChannelAdmin::ProxyPushSupplier"
--export([connect_push_consumer/4]).
-
-%% Exports from "CosEventComm::PushSupplier"
--export([disconnect_push_supplier/3]).
-
-
-%%----------------------------------------------------------------------
-%% Internal exports
-%%----------------------------------------------------------------------
-%% Exports from "oe_CosEventComm::Event"
--export([send/3, send_sync/4]).
-
-%%----------------------------------------------------------------------
-%% Records
-%%----------------------------------------------------------------------
--record(state, {admin_pid, client, typecheck}).
-
-%%----------------------------------------------------------------------
-%% Macros
-%%----------------------------------------------------------------------
-
-%%======================================================================
-%% External functions
-%%======================================================================
-%%----------------------------------------------------------------------
-%% Function : init/1
-%% Returns : {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
-%% Description: Initiates the server
-%%----------------------------------------------------------------------
-init([AdminPid, TypeCheck]) ->
- process_flag(trap_exit, true),
- {ok, #state{admin_pid = AdminPid, typecheck = TypeCheck}}.
-
-%%----------------------------------------------------------------------
-%% Function : terminate/2
-%% Returns : any (ignored by gen_server)
-%% Description: Shutdown the server
-%%----------------------------------------------------------------------
-terminate(_Reason, #state{client = undefined}) ->
- ?DBG("Terminating ~p; no client connected.~n", [_Reason]),
- ok;
-terminate(_Reason, #state{client = Client} = _State) ->
- ?DBG("Terminating ~p~n", [_Reason]),
- cosEventApp:disconnect('CosEventComm_PushConsumer',
- disconnect_push_consumer, Client),
- ok.
-
-%%----------------------------------------------------------------------
-%% Function : code_change/3
-%% Returns : {ok, NewState}
-%% Description: Convert process state when code is changed
-%%----------------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%---------------------------------------------------------------------%
-%% function : handle_info
-%% Arguments:
-%% Returns : {noreply, State} |
-%% {stop, Reason, State}
-%% Effect : Functions demanded by the gen_server module.
-%%----------------------------------------------------------------------
-handle_info({'EXIT', Pid, Reason}, #state{admin_pid = Pid} = State) ->
- ?DBG("Parent Admin terminated ~p~n", [Reason]),
- orber:dbg("[~p] oe_CosEventComm_PusherS_impl:handle_info(~p);~n"
- "My Admin terminated and so will I.",
- [?LINE, Reason], ?DEBUG_LEVEL),
- {stop, Reason, State};
-handle_info(_Info, State) ->
- ?DBG("Unknown Info ~p~n", [_Info]),
- {noreply, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : connect_push_consumer
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-connect_push_consumer(_OE_This, _, #state{client = undefined,
- typecheck = TypeCheck} = State, NewClient) ->
- case corba_object:is_nil(NewClient) of
- true ->
- orber:dbg("[~p] oe_CosEventComm_PusherS_impl:connect_push_consumer(..);~n"
- "Supplied a NIL reference which is not allowed.",
- [?LINE], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status = ?COMPLETED_NO});
- false ->
- cosEventApp:type_check(NewClient, 'CosEventComm_PushConsumer', TypeCheck),
- ?DBG("Connected to client.~n", []),
- {reply, ok, State#state{client = NewClient}}
- end;
-connect_push_consumer(_, _, _, _) ->
- corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}).
-
-
-%%---------------------------------------------------------------------%
-%% Function : disconnect_push_supplier
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-disconnect_push_supplier(_OE_This, _, State) ->
- ?DBG("Disconnect invoked ~p ~n", [State]),
- {stop, normal, ok, State#state{client = undefined}}.
-
-%%======================================================================
-%% Internal functions
-%%======================================================================
-%%----------------------------------------------------------------------
-%% Function : send
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-send(_OE_This, #state{client = undefined} = State, _Any) ->
- %% No consumer connected.
- ?DBG("Received event ~p but have no client.~n", [_Any]),
- {noreply, State};
-send(_OE_This, #state{client = Client} = State, Any) ->
- %% Push Data
- case catch 'CosEventComm_PushConsumer':push(Client, Any) of
- ok ->
- ?DBG("Received event ~p and delivered it client.~n", [Any]),
- {noreply, State};
- {'EXCEPTION', #'CosEventComm_Disconnected'{}} ->
- ?DBG("Received event ~p but failed to deliver it since the client claims we are disconnected.~n", [Any]),
- {stop, normal, State#state{client = undefined}};
- Other ->
- ?DBG("Received event ~p but failed to deliver it to client.~n", [Any]),
- orber:dbg("[~p] oe_CosEventComm_PusherS_impl:send(~p);~n"
- "My Client behaves badly, returned ~p, so I will terminate.",
- [?LINE, Any, Other], ?DEBUG_LEVEL),
- {stop, normal, State}
- end.
-
-
-%%----------------------------------------------------------------------
-%% Function : send_sync
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-send_sync(_OE_This, _OE_From, #state{client = undefined} = State, _Any) ->
- %% No consumer connected.
- ?DBG("Received event ~p but have no client.~n", [_Any]),
- {reply, ok, State};
-send_sync(_OE_This, OE_From, #state{client = Client} = State, Any) ->
- corba:reply(OE_From, ok),
- %% Push Data
- case catch 'CosEventComm_PushConsumer':push(Client, Any) of
- ok ->
- ?DBG("Received event ~p and delivered (sync) it client.~n", [Any]),
- {noreply, State};
- {'EXCEPTION', #'CosEventComm_Disconnected'{}} ->
- ?DBG("Received event ~p but failed to deliver (sync) it since the client claims we are disconnected.~n", [Any]),
- {stop, normal, State#state{client = undefined}};
- Other ->
- ?DBG("Received event ~p but failed to deliver (sync) it to client.~n", [Any]),
- orber:dbg("[~p] oe_CosEventComm_PusherS_impl:send_sync(~p);~n"
- "My Client behaves badly, returned ~p, so I will terminate.",
- [?LINE, Any, Other], ?DEBUG_LEVEL),
- {stop, normal, State}
- end.
-
-
-%%======================================================================
-%% END OF MODULE
-%%======================================================================
-
diff --git a/lib/cosEvent/test/Makefile b/lib/cosEvent/test/Makefile
deleted file mode 100644
index 878e1c8a4c..0000000000
--- a/lib/cosEvent/test/Makefile
+++ /dev/null
@@ -1,150 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1999-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(COSEVENT_VSN)
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/cosEvent_test
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-TEST_SPEC_FILE = cosEvent.spec
-COVER_FILE = cosEvent.cover
-
-
-IDL_FILES = \
- event_test_server.idl \
-
-IDLOUTDIR = idl_output
-
-MODULES = \
- event_test_PushC_impl \
- event_test_PullC_impl \
- event_test_PushS_impl \
- event_test_PullS_impl \
- event_channel_SUITE \
- generated_SUITE
-
-GEN_MOD_COS = \
- event_test_PullC \
- event_test_PushS \
- event_test_PullS \
- oe_event_test_server \
- event_test_PushC
-
-GEN_HRL_COS = \
- event_test.hrl \
- event_test_PushC.hrl \
- event_test_PullC.hrl \
- event_test_PushS.hrl \
- event_test_PullS.hrl \
- oe_event_test_server.hrl
-
-
-GEN_MODULES = $(GEN_MOD_COS)
-
-ERL_FILES = $(MODULES:%=%.erl)
-
-HRL_FILES =
-
-GEN_HRL_FILES = $(GEN_HRL_COS)
-
-GEN_FILES = \
- $(GEN_HRL_FILES:%=$(IDLOUTDIR)/%) \
- $(GEN_MODULES:%=$(IDLOUTDIR)/%.erl)
-
-GEN_TARGET_FILES = $(GEN_MODULES:%=$(IDLOUTDIR)/%.$(EMULATOR))
-
-SUITE_TARGET_FILES = $(MODULES:%=%.$(EMULATOR))
-
-TARGET_FILES = \
- $(GEN_TARGET_FILES) \
- $(SUITE_TARGET_FILES)
-
-# ----------------------------------------------------
-# PROGRAMS
-# ----------------------------------------------------
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_IDL_FLAGS += -pa $(ERL_TOP)/lib/orber/ebin -pa $(ERL_TOP)/lib/ic/ebin
-
-ERL_COMPILE_FLAGS += $(ERL_IDL_FLAGS) \
- -pa $(ERL_TOP)/lib/cosEvent/ebin \
- -pa $(ERL_TOP)/lib/cosEvent/test/idl_output \
- -I$(ERL_TOP)/lib/cosEvent \
- -I$(ERL_TOP)/lib/cosEvent/test/$(IDLOUTDIR)
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-tests debug opt: $(TARGET_FILES)
-
-clean:
- rm -f idl_output/*
- rm -rf java_initial_reference_idl java_cos_naming_idl
- rm -rf java_iiop_module_idl java_output/*
- rm -f $(TARGET_FILES)
- rm -f errs core *~
-
-
-docs:
-
-# ----------------------------------------------------
-# Special Targets
-# ----------------------------------------------------
-
-IDL-GENERATED: event_test_server.idl
- erlc $(ERL_IDL_FLAGS) -o$(IDLOUTDIR) event_test_server.idl
- >IDL-GENERATED
-
-$(GEN_FILES): IDL-GENERATED
-
-$(TARGET_FILES): IDL-GENERATED
-
-# ----------------------------------------------------
-# Release Targets
-# ----------------------------------------------------
-# We don't copy generated intermediate erlang and hrl files
-
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec:
-
-release_docs_spec:
-
-release_tests_spec: tests
- $(INSTALL_DIR) "$(RELSYSDIR)"
- $(INSTALL_DATA) $(IDL_FILES) $(TEST_SPEC_FILE) \
- $(COVER_FILE) $(ERL_FILES) "$(RELSYSDIR)"
- $(INSTALL_DATA) $(SUITE_TARGET_FILES) "$(RELSYSDIR)"
- $(INSTALL_DIR) "$(RELSYSDIR)/$(IDLOUTDIR)"
- $(INSTALL_DATA) $(GEN_TARGET_FILES) $(GEN_FILES) \
- "$(RELSYSDIR)/$(IDLOUTDIR)"
-
diff --git a/lib/cosEvent/test/cosEvent.cover b/lib/cosEvent/test/cosEvent.cover
deleted file mode 100644
index df12ea3ca9..0000000000
--- a/lib/cosEvent/test/cosEvent.cover
+++ /dev/null
@@ -1,2 +0,0 @@
-{incl_app,cosEvent,details}.
-
diff --git a/lib/cosEvent/test/cosEvent.spec b/lib/cosEvent/test/cosEvent.spec
deleted file mode 100644
index f793693779..0000000000
--- a/lib/cosEvent/test/cosEvent.spec
+++ /dev/null
@@ -1 +0,0 @@
-{suites,"../cosEvent_test",all}.
diff --git a/lib/cosEvent/test/event_channel_SUITE.erl b/lib/cosEvent/test/event_channel_SUITE.erl
deleted file mode 100644
index bbae8d782a..0000000000
--- a/lib/cosEvent/test/event_channel_SUITE.erl
+++ /dev/null
@@ -1,326 +0,0 @@
-%%-----------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-
--module(event_channel_SUITE).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/include/corba.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming.hrl").
--include_lib("orber/src/orber_iiop.hrl").
-
-%%-----------------------------------------------------------------
-%% Macros
-%%-----------------------------------------------------------------
-
--define(default_timeout, test_server:minutes(5)).
-
-
--define(match(ExpectedRes, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- io:format("------ CORRECT RESULT ------~n~p~n",
- [AcTuAlReS]),
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
- event_objects_api/1, events_api/1, events_sync_api/1,
- cases/0, init_per_suite/1, end_per_suite/1,
- init_per_testcase/2, end_per_testcase/2, app_test/1]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- cases().
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-cases() ->
- [events_api, events_sync_api, event_objects_api,
- app_test].
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-
-init_per_testcase(_Case, Config) ->
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-init_per_suite(Config) when is_list(Config) ->
- Path = code:which(?MODULE),
- code:add_pathz(filename:join(filename:dirname(Path), "idl_output")),
- mnesia:delete_schema([node()]),
- mnesia:create_schema([node()]),
- orber:install([node()]),
- application:start(mnesia),
- application:start(orber),
- cosEventApp:install(),
- cosEventApp:start(),
- oe_event_test_server:oe_register(),
- Config.
-
-end_per_suite(Config) when is_list(Config) ->
- oe_event_test_server:oe_unregister(),
- cosEventApp:stop(),
- cosEventApp:uninstall(),
- application:stop(orber),
- application:stop(mnesia),
- mnesia:delete_schema([node()]),
- Path = code:which(?MODULE),
- code:del_path(filename:join(filename:dirname(Path), "idl_output")),
- Config.
-
-%%-----------------------------------------------------------------
-%% Tests app file
-%%-----------------------------------------------------------------
-app_test(doc) -> [];
-app_test(suite) -> [];
-app_test(_Config) ->
- ok=test_server:app_test(cosEvent),
- ok.
-
-
-
-%% Testing the CosEvent API to setup a complete service
-event_objects_api(_Config) ->
-
- Ch = ?match({_,key,_,_,_,_}, cosEventApp:start_channel([{typecheck, true},
- {pull_interval, 300}])),
-
- AC=?match({_,key,_,_,_,_},
- 'CosEventChannelAdmin_EventChannel':for_consumers(Ch)),
- AS=?match({_,key,_,_,_,_},
- 'CosEventChannelAdmin_EventChannel':for_suppliers(Ch)),
-
- PPushS=?match({_,key,_,_,_,_},
- 'CosEventChannelAdmin_ConsumerAdmin':obtain_push_supplier(AC)),
- PPullS=?match({_,key,_,_,_,_},
- 'CosEventChannelAdmin_ConsumerAdmin':obtain_pull_supplier(AC)),
-
- PPushC=?match({_,key,_,_,_,_},
- 'CosEventChannelAdmin_SupplierAdmin':obtain_push_consumer(AS)),
- PPullC=?match({_,key,_,_,_,_},
- 'CosEventChannelAdmin_SupplierAdmin':obtain_pull_consumer(AS)),
-
- PushC=?match({_,key,_,_,_,_},
- 'event_test_PushC':oe_create([])),
- PullC=?match({_,key,_,_,_,_},
- 'event_test_PullC':oe_create(PPullC)),
-
- PushS=?match({_,key,_,_,_,_},
- 'event_test_PushS':oe_create(PPushC)),
-
- PullS=?match({_,key,_,_,_,_},
- 'event_test_PullS':oe_create([])),
-
- NIL = corba:create_nil_objref(),
-
- ?match({'EXCEPTION',{'BAD_PARAM',_,_,_}},
- 'CosEventChannelAdmin_ProxyPushSupplier':connect_push_consumer(PPushS, NIL)),
- ?match({'EXCEPTION',{'BAD_PARAM',_,_,_}},
- 'CosEventChannelAdmin_ProxyPushSupplier':connect_push_consumer(PPushS, PullS)),
- ?match(ok, 'CosEventChannelAdmin_ProxyPushSupplier':connect_push_consumer(PPushS, PushC)),
- ?match({'EXCEPTION',{'CosEventChannelAdmin_AlreadyConnected',_}},
- 'CosEventChannelAdmin_ProxyPushSupplier':connect_push_consumer(PPushS, PushC)),
-
- ?match(ok, 'CosEventChannelAdmin_ProxyPullSupplier':connect_pull_consumer(PPullS, NIL)),
- ?match({'EXCEPTION',{'BAD_PARAM',_,_,_}},
- 'CosEventChannelAdmin_ProxyPullSupplier':connect_pull_consumer(PPullS, PullS)),
- ?match(ok, 'CosEventChannelAdmin_ProxyPullSupplier':connect_pull_consumer(PPullS, PullC)),
- ?match({'EXCEPTION',{'CosEventChannelAdmin_AlreadyConnected',_}},
- 'CosEventChannelAdmin_ProxyPullSupplier':connect_pull_consumer(PPullS, PullC)),
-
- ?match(ok, 'CosEventChannelAdmin_ProxyPushConsumer':connect_push_supplier(PPushC, NIL)),
- ?match({'EXCEPTION',{'BAD_PARAM',_,_,_}},
- 'CosEventChannelAdmin_ProxyPushConsumer':connect_push_supplier(PPushC, PullS)),
- ?match(ok, 'CosEventChannelAdmin_ProxyPushConsumer':connect_push_supplier(PPushC, PushS)),
- ?match({'EXCEPTION',{'CosEventChannelAdmin_AlreadyConnected',_}},
- 'CosEventChannelAdmin_ProxyPushConsumer':connect_push_supplier(PPushC, PushS)),
-
- ?match({'EXCEPTION',{'BAD_PARAM',_,_,_}},
- 'CosEventChannelAdmin_ProxyPullConsumer':connect_pull_supplier(PPullC, NIL)),
- ?match({'EXCEPTION',{'BAD_PARAM',_,_,_}},
- 'CosEventChannelAdmin_ProxyPullConsumer':connect_pull_supplier(PPullC, PushS)),
- ?match(ok, 'CosEventChannelAdmin_ProxyPullConsumer':connect_pull_supplier(PPullC, PullS)),
- ?match({'EXCEPTION',{'CosEventChannelAdmin_AlreadyConnected',_}},
- 'CosEventChannelAdmin_ProxyPullConsumer':connect_pull_supplier(PPullC, PullS)),
-
-
- catch corba:dispose(AC),
- %% Wait a couple of seconds to be sure all data removed from DB.
- timer:sleep(2000),
-
- %% Since we terminated ConsumerAdmin only the Supplier Proxies should be terminated.
- ?match(true, corba_object:non_existent(AC)),
- ?match(true, corba_object:non_existent(PPushS)),
- ?match(true, corba_object:non_existent(PPullS)),
-
- ?match(false, corba_object:non_existent(Ch)),
- ?match(false, corba_object:non_existent(AS)),
- ?match(false, corba_object:non_existent(PPullC)),
- ?match(false, corba_object:non_existent(PPushC)),
-
- %% Terminate a proxy and check that its admin is unaffected.
- catch corba:dispose(PPullC),
- timer:sleep(2000),
- ?match(false, corba_object:non_existent(AS)),
- ?match(true, corba_object:non_existent(PPullC)),
-
- catch corba:dispose(Ch),
- timer:sleep(2000),
-
- ?match(true, corba_object:non_existent(Ch)),
- ?match(true, corba_object:non_existent(AS)),
- ?match(true, corba_object:non_existent(PPullC)),
- ?match(true, corba_object:non_existent(PPushC)),
-
- %% The client should be notified; wait for a couple of seconds and check it.
- timer:sleep(2000),
- ?match(true, corba_object:non_existent(PushC)),
- ?match(true, corba_object:non_existent(PullC)),
- ?match(true, corba_object:non_existent(PushS)),
- ?match(true, corba_object:non_existent(PullS)),
-
- ok.
-
-%% Testing the CosEvent API for sending events asynchronous
-events_api(_Config) ->
-
- Ch = ?match({_,key,_,_,_,_}, cosEventApp:start_channel([{typecheck, true},
- {pull_interval, 2},
- {blocking, false}])),
- event_sender(Ch).
-
-
-%% Testing the CosEvent API for sending events synchronous
-events_sync_api(_Config) ->
-
- Ch = ?match({_,key,_,_,_,_}, cosEventApp:start_channel([{typecheck, true},
- {pull_interval, 2},
- {blocking, true}])),
- event_sender(Ch).
-
-event_sender(Ch) ->
- Event1 = #any{typecode=tk_long, value = 1},
- Event2 = #any{typecode=tk_long, value = 2},
- Event3 = #any{typecode=tk_long, value = 3},
- Event4 = #any{typecode=tk_long, value = 4},
- Event5 = #any{typecode=tk_long, value = 5},
- Event6 = #any{typecode=tk_long, value = 6},
-
- AC=?match({_,key,_,_,_,_},
- 'CosEventChannelAdmin_EventChannel':for_consumers(Ch)),
- AS=?match({_,key,_,_,_,_},
- 'CosEventChannelAdmin_EventChannel':for_suppliers(Ch)),
-
- PPushS=?match({_,key,_,_,_,_},
- 'CosEventChannelAdmin_ConsumerAdmin':obtain_push_supplier(AC)),
- PPullS=?match({_,key,_,_,_,_},
- 'CosEventChannelAdmin_ConsumerAdmin':obtain_pull_supplier(AC)),
-
- PPushC=?match({_,key,_,_,_,_},
- 'CosEventChannelAdmin_SupplierAdmin':obtain_push_consumer(AS)),
- PPullC=?match({_,key,_,_,_,_},
- 'CosEventChannelAdmin_SupplierAdmin':obtain_pull_consumer(AS)),
-
- PushC=?match({_,key,_,_,_,_}, 'event_test_PushC':oe_create([])),
- PullC=?match({_,key,_,_,_,_}, 'event_test_PullC':oe_create(PPullS)),
-
- PushS=?match({_,key,_,_,_,_}, 'event_test_PushS':oe_create(PPushC)),
-
- PullS=?match({_,key,_,_,_,_}, 'event_test_PullS':oe_create([])),
-
- ?match(ok, 'CosEventChannelAdmin_ProxyPushSupplier':connect_push_consumer(PPushS, PushC)),
- ?match(ok, 'CosEventChannelAdmin_ProxyPullSupplier':connect_pull_consumer(PPullS, PullC)),
- ?match(ok, 'CosEventChannelAdmin_ProxyPushConsumer':connect_push_supplier(PPushC, PushS)),
- ?match(ok, 'CosEventChannelAdmin_ProxyPullConsumer':connect_pull_supplier(PPullC, PullS)),
-
- %% No events should be available at the consumer side at this point.
- ?match({_, false}, event_test_PullC:do_try_pull(PullC)),
- ?match([], event_test_PushC:get_data(PushC)),
-
- %% Push an event and wait to be sure it have reached the destination.
- ?match(ok, event_test_PushS:do_push(PushS, Event1)),
- ?match(ok, event_test_PushS:do_push(PushS, Event2)),
- ?match(ok, event_test_PushS:do_push(PushS, Event3)),
- timer:sleep(2000),
- ?match({Event1, true}, event_test_PullC:do_try_pull(PullC)),
- ?match({Event2, true}, event_test_PullC:do_try_pull(PullC)),
- ?match({Event3, true}, event_test_PullC:do_try_pull(PullC)),
- ?match({_, false}, event_test_PullC:do_try_pull(PullC)),
- ?match([Event1, Event2, Event3], event_test_PushC:get_data(PushC)),
-
- ?match(ok, event_test_PullS:add_event(PullS, Event4)),
- ?match(ok, event_test_PullS:add_event(PullS, Event5)),
- ?match(ok, event_test_PullS:add_event(PullS, Event6)),
-
- %% Since the pull operation is blocking we do not need to "sleep".
- %% The ProxyPullConsumer will pull for events according to the pull_interval
- %% parameter given when started the channel.
- ?match(Event4, event_test_PullC:do_pull(PullC)),
- ?match(Event5, event_test_PullC:do_pull(PullC)),
- ?match(Event6, event_test_PullC:do_pull(PullC)),
-
- timer:sleep(2000),
- ?match([Event4, Event5, Event6], event_test_PushC:get_data(PushC)),
-
-
- catch corba:dispose(Ch),
- %% The client should be notified; wait for a couple of seconds and check it.
- timer:sleep(2000),
- ?match(true, corba_object:non_existent(PushC)),
- ?match(true, corba_object:non_existent(PullC)),
- ?match(true, corba_object:non_existent(PushS)),
- ?match(true, corba_object:non_existent(PullS)),
-
- ok.
diff --git a/lib/cosEvent/test/event_test_PullC_impl.erl b/lib/cosEvent/test/event_test_PullC_impl.erl
deleted file mode 100644
index fb72d2e595..0000000000
--- a/lib/cosEvent/test/event_test_PullC_impl.erl
+++ /dev/null
@@ -1,44 +0,0 @@
-%%------------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%------------------------------------------------------------------------
-%% Description: a very simple implementation of PullConsumer interface
-%%------------------------------------------------------------------------
--module(event_test_PullC_impl).
-
--export([init/1, terminate/2, disconnect_pull_consumer/1, do_pull/1, do_try_pull/1]).
-
-init(Proxy) ->
- {ok, Proxy}.
-
-terminate(_From, _Reason) ->
- ok.
-
-disconnect_pull_consumer(Proxy) ->
- io:format("event_test_PullC terminates~n",[]),
- {stop, normal, ok, Proxy}.
-
-do_pull(Proxy) ->
- {reply, 'CosEventComm_PullSupplier':pull(Proxy), Proxy}.
-
-do_try_pull(Proxy) ->
- {reply, 'CosEventComm_PullSupplier':try_pull(Proxy), Proxy}.
-
diff --git a/lib/cosEvent/test/event_test_PullS_impl.erl b/lib/cosEvent/test/event_test_PullS_impl.erl
deleted file mode 100644
index de59b251da..0000000000
--- a/lib/cosEvent/test/event_test_PullS_impl.erl
+++ /dev/null
@@ -1,58 +0,0 @@
-%%------------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%------------------------------------------------------------------------
-%% Description: a very simple implementation of Pull Supplier interface
-%%------------------------------------------------------------------------
--module(event_test_PullS_impl).
-
--include_lib("orber/include/corba.hrl").
-
--export([init/1, terminate/2, pull/1, try_pull/1, disconnect_pull_supplier/1,
- add_event/2]).
-
-init(_) ->
- {ok, []}.
-
-terminate(_From, _Reason) ->
- ok.
-
-pull([]) ->
- corba:raise(#'INTERNAL'{completion_status = ?COMPLETED_NO});
-pull([Event|Events]) ->
- {reply, Event, Events}.
-
-try_pull([]) ->
- {reply, {#any{typecode=tk_null, value = null}, false}, []};
-try_pull([Event|Events]) ->
- {reply, {Event, true}, Events}.
-
-disconnect_pull_supplier(Events) ->
- io:format("event_test_PullS terminates ~p~n", [Events]),
- {stop, normal, ok, Events}.
-
-
-add_event(Events, Event) ->
- %% Store in FIFO order; don't really care if we use '++' since
- %% this operation is used in tests only.
- {reply, ok, Events ++ [Event]}.
-
-
diff --git a/lib/cosEvent/test/event_test_PushC_impl.erl b/lib/cosEvent/test/event_test_PushC_impl.erl
deleted file mode 100644
index 98e4d611fc..0000000000
--- a/lib/cosEvent/test/event_test_PushC_impl.erl
+++ /dev/null
@@ -1,47 +0,0 @@
-%%------------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%------------------------------------------------------------------------
-%% Description: a very simple implementation of Push Consumer interface
-%%------------------------------------------------------------------------
-
--module(event_test_PushC_impl).
-
--export([init/1, terminate/2, push/2, disconnect_push_consumer/1, get_data/1]).
-
-init(_) ->
- {ok, []}.
-
-terminate(_From, _Reason) ->
- ok.
-
-push(Events, Event) ->
- {reply, ok, [Event|Events]}.
-
-disconnect_push_consumer(Events) ->
- io:format("event_test_PushC terminates: ~p~n", [Events]),
- {stop, normal, ok, Events}.
-
-
-get_data(Events) ->
- %% Returns Events in FIFO order and reset state.
- {reply, lists:reverse(Events), []}.
-
diff --git a/lib/cosEvent/test/event_test_PushS_impl.erl b/lib/cosEvent/test/event_test_PushS_impl.erl
deleted file mode 100644
index 062ee8a311..0000000000
--- a/lib/cosEvent/test/event_test_PushS_impl.erl
+++ /dev/null
@@ -1,42 +0,0 @@
-%%------------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%------------------------------------------------------------------------
-%% Description: a very simple implementation of Push Supplier interface
-%%------------------------------------------------------------------------
-
--module(event_test_PushS_impl).
-
--export([init/1, terminate/2, disconnect_push_supplier/1, do_push/2]).
-
-init(Proxy) ->
- {ok, Proxy}.
-
-terminate(_From, _Reason) ->
- ok.
-
-disconnect_push_supplier(Proxy) ->
- io:format("event_test_PullC terminates~n",[]),
- {stop, normal, ok, Proxy}.
-
-do_push(Proxy, Event) ->
- {reply, 'CosEventComm_PushConsumer':push(Proxy, Event), Proxy}.
-
diff --git a/lib/cosEvent/test/event_test_server.idl b/lib/cosEvent/test/event_test_server.idl
deleted file mode 100644
index f76ac085e1..0000000000
--- a/lib/cosEvent/test/event_test_server.idl
+++ /dev/null
@@ -1,48 +0,0 @@
-//
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 2001-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-//
-
-#ifndef _EVENT_TEST_SERVER_IDL
-#define _EVENT_TEST_SERVER_IDL
-
-#include <../src/CosEventComm.idl>
-
-module event_test {
-
- interface PushC : CosEventComm::PushConsumer {
- typedef sequence<any> AnySeq;
- AnySeq get_data();
- };
- interface PullC : CosEventComm::PullConsumer {
- any do_pull();
- any do_try_pull(out boolean has_event);
- };
-
- interface PushS : CosEventComm::PushSupplier {
- void do_push(in any Event);
- };
- interface PullS : CosEventComm::PullSupplier {
- void add_event(in any Event);
- };
-
-};
-
-#endif
-
-
diff --git a/lib/cosEvent/test/generated_SUITE.erl b/lib/cosEvent/test/generated_SUITE.erl
deleted file mode 100644
index 86794023af..0000000000
--- a/lib/cosEvent/test/generated_SUITE.erl
+++ /dev/null
@@ -1,473 +0,0 @@
-%%-----------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File : generated_SUITE.erl
-%% Purpose :
-%%-----------------------------------------------------------------
-
--module(generated_SUITE).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/include/corba.hrl").
-
--define(default_timeout, test_server:minutes(3)).
-
--define(match(ExpectedRes, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
--define(nomatch(Not, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- Not ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS);
- _ ->
- AcTuAlReS
- end
- end()).
-
-
--define(checktc(_Op),
- fun(TC) ->
- case orber_tc:check_tc(TC) of
- false ->
- io:format("###### ERROR ERROR ######~n~p - ~p~n", [Op, TC]),
- exit(TC);
- true ->
- true
- end
- end).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--compile(export_all).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- ['CosEventChannelAdmin_AlreadyConnected',
- 'CosEventChannelAdmin_TypeError',
- 'CosEventComm_Disconnected',
- 'CosEventChannelAdmin_ConsumerAdmin',
- 'CosEventChannelAdmin_EventChannel',
- 'CosEventChannelAdmin_ProxyPullConsumer',
- 'CosEventChannelAdmin_ProxyPullSupplier',
- 'CosEventChannelAdmin_ProxyPushConsumer',
- 'CosEventChannelAdmin_ProxyPushSupplier',
- 'CosEventChannelAdmin_SupplierAdmin',
- oe_CosEventComm_CAdmin, oe_CosEventComm_Channel,
- oe_CosEventComm_Event, oe_CosEventComm_PullerS,
- oe_CosEventComm_PusherS, 'CosEventComm_PullConsumer',
- 'CosEventComm_PullSupplier',
- 'CosEventComm_PushConsumer',
- 'CosEventComm_PushSupplier'].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-init_per_testcase(_Case, Config) ->
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventChannelAdmin_AlreadyConnected'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventChannelAdmin_AlreadyConnected'(_) ->
- ?match(true, orber_tc:check_tc('CosEventChannelAdmin_AlreadyConnected':tc())),
- ?match("IDL:omg.org/CosEventChannelAdmin/AlreadyConnected:1.0",
- 'CosEventChannelAdmin_AlreadyConnected':id()),
- ?match("CosEventChannelAdmin_AlreadyConnected",
- 'CosEventChannelAdmin_AlreadyConnected':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventChannelAdmin_TypeError'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventChannelAdmin_TypeError'(_) ->
- ?match(true, orber_tc:check_tc('CosEventChannelAdmin_TypeError':tc())),
- ?match("IDL:omg.org/CosEventChannelAdmin/TypeError:1.0",
- 'CosEventChannelAdmin_TypeError':id()),
- ?match("CosEventChannelAdmin_TypeError",
- 'CosEventChannelAdmin_TypeError':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventComm_Disconnected'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventComm_Disconnected'(_) ->
- ?match(true, orber_tc:check_tc('CosEventComm_Disconnected':tc())),
- ?match("IDL:omg.org/CosEventComm/Disconnected:1.0",
- 'CosEventComm_Disconnected':id()),
- ?match("CosEventComm_Disconnected", 'CosEventComm_Disconnected':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventChannelAdmin_ConsumerAdmin'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventChannelAdmin_ConsumerAdmin'(_) ->
- ?nomatch(undefined, 'CosEventChannelAdmin_ConsumerAdmin':oe_tc(obtain_push_supplier)),
- ?nomatch(undefined, 'CosEventChannelAdmin_ConsumerAdmin':oe_tc(obtain_pull_supplier)),
- ?match(undefined, 'CosEventChannelAdmin_ConsumerAdmin':oe_tc(undefined)),
- ?match([_|_], 'CosEventChannelAdmin_ConsumerAdmin':oe_get_interface()),
- ?match("IDL:omg.org/CosEventChannelAdmin/ConsumerAdmin:1.0",
- 'CosEventChannelAdmin_ConsumerAdmin':typeID()),
- check_tc('CosEventChannelAdmin_ConsumerAdmin':oe_get_interface()),
- ?match(true, 'CosEventChannelAdmin_ConsumerAdmin':oe_is_a('CosEventChannelAdmin_ConsumerAdmin':typeID())),
- ?match(false, 'CosEventChannelAdmin_ConsumerAdmin':oe_is_a("wrong")),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventChannelAdmin_EventChannel'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventChannelAdmin_EventChannel'(_) ->
- ?nomatch(undefined, 'CosEventChannelAdmin_EventChannel':oe_tc(for_consumers)),
- ?nomatch(undefined, 'CosEventChannelAdmin_EventChannel':oe_tc(for_suppliers)),
- ?nomatch(undefined, 'CosEventChannelAdmin_EventChannel':oe_tc(destroy)),
- ?match(undefined, 'CosEventChannelAdmin_EventChannel':oe_tc(undefined)),
- ?match([_|_], 'CosEventChannelAdmin_EventChannel':oe_get_interface()),
- ?match("IDL:omg.org/CosEventChannelAdmin/EventChannel:1.0",
- 'CosEventChannelAdmin_EventChannel':typeID()),
- check_tc('CosEventChannelAdmin_EventChannel':oe_get_interface()),
- ?match(true, 'CosEventChannelAdmin_EventChannel':oe_is_a('CosEventChannelAdmin_EventChannel':typeID())),
- ?match(false, 'CosEventChannelAdmin_EventChannel':oe_is_a("wrong")),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventChannelAdmin_ProxyPullConsumer'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventChannelAdmin_ProxyPullConsumer'(_) ->
- ?nomatch(undefined, 'CosEventChannelAdmin_ProxyPullConsumer':oe_tc(connect_pull_supplier)),
- ?nomatch(undefined, 'CosEventChannelAdmin_ProxyPullConsumer':oe_tc(disconnect_pull_consumer)),
- ?match(undefined, 'CosEventChannelAdmin_ProxyPullConsumer':oe_tc(undefined)),
- ?match([_|_], 'CosEventChannelAdmin_ProxyPullConsumer':oe_get_interface()),
- ?match("IDL:omg.org/CosEventChannelAdmin/ProxyPullConsumer:1.0",
- 'CosEventChannelAdmin_ProxyPullConsumer':typeID()),
- check_tc('CosEventChannelAdmin_ProxyPullConsumer':oe_get_interface()),
- ?match(true, 'CosEventChannelAdmin_ProxyPullConsumer':oe_is_a('CosEventChannelAdmin_ProxyPullConsumer':typeID())),
- ?match(true, 'CosEventChannelAdmin_ProxyPullConsumer':oe_is_a('CosEventComm_PullConsumer':typeID())),
- ?match(false, 'CosEventChannelAdmin_ProxyPullConsumer':oe_is_a("wrong")),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventChannelAdmin_ProxyPullSupplier'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventChannelAdmin_ProxyPullSupplier'(_) ->
- ?nomatch(undefined, 'CosEventChannelAdmin_ProxyPullSupplier':oe_tc(connect_pull_consumer)),
- ?nomatch(undefined, 'CosEventChannelAdmin_ProxyPullSupplier':oe_tc(pull)),
- ?nomatch(undefined, 'CosEventChannelAdmin_ProxyPullSupplier':oe_tc(try_pull)),
- ?nomatch(undefined, 'CosEventChannelAdmin_ProxyPullSupplier':oe_tc(disconnect_pull_supplier)),
- ?match(undefined, 'CosEventChannelAdmin_ProxyPullSupplier':oe_tc(undefined)),
- ?match([_|_], 'CosEventChannelAdmin_ProxyPullSupplier':oe_get_interface()),
- ?match("IDL:omg.org/CosEventChannelAdmin/ProxyPullSupplier:1.0",
- 'CosEventChannelAdmin_ProxyPullSupplier':typeID()),
- check_tc('CosEventChannelAdmin_ProxyPullSupplier':oe_get_interface()),
- ?match(true, 'CosEventChannelAdmin_ProxyPullSupplier':oe_is_a('CosEventChannelAdmin_ProxyPullSupplier':typeID())),
- ?match(true, 'CosEventChannelAdmin_ProxyPullSupplier':oe_is_a('CosEventComm_PullSupplier':typeID())),
- ?match(false, 'CosEventChannelAdmin_ProxyPullSupplier':oe_is_a("wrong")),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventChannelAdmin_ProxyPushConsumer'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventChannelAdmin_ProxyPushConsumer'(_) ->
- ?nomatch(undefined, 'CosEventChannelAdmin_ProxyPushConsumer':oe_tc(connect_push_supplier)),
- ?nomatch(undefined, 'CosEventChannelAdmin_ProxyPushConsumer':oe_tc(push)),
- ?nomatch(undefined, 'CosEventChannelAdmin_ProxyPushConsumer':oe_tc(disconnect_push_consumer)),
- ?match(undefined, 'CosEventChannelAdmin_ProxyPushConsumer':oe_tc(undefined)),
- ?match([_|_], 'CosEventChannelAdmin_ProxyPushConsumer':oe_get_interface()),
- ?match("IDL:omg.org/CosEventChannelAdmin/ProxyPushConsumer:1.0",
- 'CosEventChannelAdmin_ProxyPushConsumer':typeID()),
- check_tc('CosEventChannelAdmin_ProxyPushConsumer':oe_get_interface()),
- ?match(true, 'CosEventChannelAdmin_ProxyPushConsumer':oe_is_a('CosEventChannelAdmin_ProxyPushConsumer':typeID())),
- ?match(true, 'CosEventChannelAdmin_ProxyPushConsumer':oe_is_a('CosEventComm_PushConsumer':typeID())),
- ?match(false, 'CosEventChannelAdmin_ProxyPushConsumer':oe_is_a("wrong")),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventChannelAdmin_ProxyPushSupplier'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventChannelAdmin_ProxyPushSupplier'(_) ->
- ?nomatch(undefined, 'CosEventChannelAdmin_ProxyPushSupplier':oe_tc(connect_push_consumer)),
- ?nomatch(undefined, 'CosEventChannelAdmin_ProxyPushSupplier':oe_tc(disconnect_push_supplier)),
- ?match(undefined, 'CosEventChannelAdmin_ProxyPushSupplier':oe_tc(undefined)),
- ?match([_|_], 'CosEventChannelAdmin_ProxyPushSupplier':oe_get_interface()),
- ?match("IDL:omg.org/CosEventChannelAdmin/ProxyPushSupplier:1.0",
- 'CosEventChannelAdmin_ProxyPushSupplier':typeID()),
- check_tc('CosEventChannelAdmin_ProxyPushSupplier':oe_get_interface()),
- ?match(true, 'CosEventChannelAdmin_ProxyPushSupplier':oe_is_a('CosEventChannelAdmin_ProxyPushSupplier':typeID())),
- ?match(true, 'CosEventChannelAdmin_ProxyPushSupplier':oe_is_a('CosEventComm_PushSupplier':typeID())),
- ?match(false, 'CosEventChannelAdmin_ProxyPushSupplier':oe_is_a("wrong")),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventChannelAdmin_SupplierAdmin'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventChannelAdmin_SupplierAdmin'(_) ->
- ?nomatch(undefined, 'CosEventChannelAdmin_SupplierAdmin':oe_tc(obtain_push_consumer)),
- ?nomatch(undefined, 'CosEventChannelAdmin_SupplierAdmin':oe_tc(obtain_pull_consumer)),
- ?match(undefined, 'CosEventChannelAdmin_SupplierAdmin':oe_tc(undefined)),
- ?match([_|_], 'CosEventChannelAdmin_SupplierAdmin':oe_get_interface()),
- ?match("IDL:omg.org/CosEventChannelAdmin/SupplierAdmin:1.0",
- 'CosEventChannelAdmin_SupplierAdmin':typeID()),
- check_tc('CosEventChannelAdmin_SupplierAdmin':oe_get_interface()),
- ?match(true, 'CosEventChannelAdmin_SupplierAdmin':oe_is_a('CosEventChannelAdmin_SupplierAdmin':typeID())),
- ?match(false, 'CosEventChannelAdmin_SupplierAdmin':oe_is_a("wrong")),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'oe_CosEventComm_CAdmin'
-%% Description:
-%%-----------------------------------------------------------------
-'oe_CosEventComm_CAdmin'(_) ->
- ?nomatch(undefined, 'oe_CosEventComm_CAdmin':oe_tc(obtain_push_supplier)),
- ?nomatch(undefined, 'oe_CosEventComm_CAdmin':oe_tc(obtain_pull_supplier)),
- ?nomatch(undefined, 'oe_CosEventComm_CAdmin':oe_tc(send)),
- ?nomatch(undefined, 'oe_CosEventComm_CAdmin':oe_tc(send_sync)),
- ?match(undefined, 'oe_CosEventComm_CAdmin':oe_tc(undefined)),
- ?match([_|_], 'oe_CosEventComm_CAdmin':oe_get_interface()),
- ?match("IDL:oe_CosEventComm/CAdmin:1.0",
- 'oe_CosEventComm_CAdmin':typeID()),
- check_tc('oe_CosEventComm_CAdmin':oe_get_interface()),
- ?match(true, 'oe_CosEventComm_CAdmin':oe_is_a('oe_CosEventComm_CAdmin':typeID())),
- ?match(true, 'oe_CosEventComm_CAdmin':oe_is_a('CosEventChannelAdmin_ConsumerAdmin':typeID())),
- ?match(true, 'oe_CosEventComm_CAdmin':oe_is_a('oe_CosEventComm_Event':typeID())),
- ?match(false, 'oe_CosEventComm_CAdmin':oe_is_a("wrong")),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'oe_CosEventComm_Channel'
-%% Description:
-%%-----------------------------------------------------------------
-'oe_CosEventComm_Channel'(_) ->
- ?nomatch(undefined, 'oe_CosEventComm_Channel':oe_tc(for_consumers)),
- ?nomatch(undefined, 'oe_CosEventComm_Channel':oe_tc(for_suppliers)),
- ?nomatch(undefined, 'oe_CosEventComm_Channel':oe_tc(destroy)),
- ?nomatch(undefined, 'oe_CosEventComm_Channel':oe_tc(send)),
- ?nomatch(undefined, 'oe_CosEventComm_Channel':oe_tc(send_sync)),
- ?match(undefined, 'oe_CosEventComm_Channel':oe_tc(undefined)),
- ?match([_|_], 'oe_CosEventComm_Channel':oe_get_interface()),
- ?match("IDL:oe_CosEventComm/Channel:1.0",
- 'oe_CosEventComm_Channel':typeID()),
- check_tc('oe_CosEventComm_Channel':oe_get_interface()),
- ?match(true, 'oe_CosEventComm_Channel':oe_is_a('oe_CosEventComm_Channel':typeID())),
- ?match(true, 'oe_CosEventComm_Channel':oe_is_a('CosEventChannelAdmin_EventChannel':typeID())),
- ?match(true, 'oe_CosEventComm_Channel':oe_is_a('oe_CosEventComm_Event':typeID())),
- ?match(false, 'oe_CosEventComm_Channel':oe_is_a("wrong")),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'oe_CosEventComm_Event'
-%% Description:
-%%-----------------------------------------------------------------
-'oe_CosEventComm_Event'(_) ->
- ?nomatch(undefined, 'oe_CosEventComm_Event':oe_tc(send)),
- ?nomatch(undefined, 'oe_CosEventComm_Event':oe_tc(send_sync)),
- ?match(undefined, 'oe_CosEventComm_Event':oe_tc(undefined)),
- ?match([_|_], 'oe_CosEventComm_Event':oe_get_interface()),
- ?match("IDL:oe_CosEventComm/Event:1.0",
- 'oe_CosEventComm_Event':typeID()),
- check_tc('oe_CosEventComm_Event':oe_get_interface()),
- ?match(true, 'oe_CosEventComm_Event':oe_is_a('oe_CosEventComm_Event':typeID())),
- ?match(false, 'oe_CosEventComm_Event':oe_is_a("wrong")),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'oe_CosEventComm_PullerS'
-%% Description:
-%%-----------------------------------------------------------------
-'oe_CosEventComm_PullerS'(_) ->
- ?nomatch(undefined, 'oe_CosEventComm_PullerS':oe_tc(connect_pull_consumer)),
- ?nomatch(undefined, 'oe_CosEventComm_PullerS':oe_tc(pull)),
- ?nomatch(undefined, 'oe_CosEventComm_PullerS':oe_tc(try_pull)),
- ?nomatch(undefined, 'oe_CosEventComm_PullerS':oe_tc(disconnect_pull_supplier)),
- ?nomatch(undefined, 'oe_CosEventComm_PullerS':oe_tc(send)),
- ?nomatch(undefined, 'oe_CosEventComm_PullerS':oe_tc(send_sync)),
- ?match(undefined, 'oe_CosEventComm_PullerS':oe_tc(undefined)),
- ?match([_|_], 'oe_CosEventComm_PullerS':oe_get_interface()),
- ?match("IDL:oe_CosEventComm/PullerS:1.0",
- 'oe_CosEventComm_PullerS':typeID()),
- check_tc('oe_CosEventComm_PullerS':oe_get_interface()),
- ?match(true, 'oe_CosEventComm_PullerS':oe_is_a('oe_CosEventComm_PullerS':typeID())),
- ?match(true, 'oe_CosEventComm_PullerS':oe_is_a('CosEventChannelAdmin_ProxyPullSupplier':typeID())),
- ?match(true, 'oe_CosEventComm_PullerS':oe_is_a('CosEventComm_PullSupplier':typeID())),
- ?match(true, 'oe_CosEventComm_PullerS':oe_is_a('oe_CosEventComm_Event':typeID())),
- ?match(false, 'oe_CosEventComm_PullerS':oe_is_a("wrong")),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'oe_CosEventComm_PusherS'
-%% Description:
-%%-----------------------------------------------------------------
-'oe_CosEventComm_PusherS'(_) ->
- ?nomatch(undefined, 'oe_CosEventComm_PusherS':oe_tc(connect_push_consumer)),
- ?nomatch(undefined, 'oe_CosEventComm_PusherS':oe_tc(disconnect_push_supplier)),
- ?nomatch(undefined, 'oe_CosEventComm_PusherS':oe_tc(send)),
- ?nomatch(undefined, 'oe_CosEventComm_PusherS':oe_tc(send_sync)),
- ?match(undefined, 'oe_CosEventComm_PusherS':oe_tc(undefined)),
- ?match([_|_], 'oe_CosEventComm_PusherS':oe_get_interface()),
- ?match("IDL:oe_CosEventComm/PusherS:1.0",
- 'oe_CosEventComm_PusherS':typeID()),
- check_tc('oe_CosEventComm_PusherS':oe_get_interface()),
- ?match(true, 'oe_CosEventComm_PusherS':oe_is_a('oe_CosEventComm_PusherS':typeID())),
- ?match(true, 'oe_CosEventComm_PusherS':oe_is_a('CosEventChannelAdmin_ProxyPushSupplier':typeID())),
- ?match(true, 'oe_CosEventComm_PusherS':oe_is_a('CosEventComm_PushSupplier':typeID())),
- ?match(true, 'oe_CosEventComm_PusherS':oe_is_a('oe_CosEventComm_Event':typeID())),
- ?match(false, 'oe_CosEventComm_PusherS':oe_is_a("wrong")),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventComm_PullConsumer'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventComm_PullConsumer'(_) ->
- ?nomatch(undefined, 'CosEventComm_PullConsumer':oe_tc(disconnect_pull_consumer)),
- ?match(undefined, 'CosEventComm_PullConsumer':oe_tc(undefined)),
- ?match([_|_], 'CosEventComm_PullConsumer':oe_get_interface()),
- ?match("IDL:omg.org/CosEventComm/PullConsumer:1.0",
- 'CosEventComm_PullConsumer':typeID()),
- check_tc('CosEventComm_PullConsumer':oe_get_interface()),
- ?match(true, 'CosEventComm_PullConsumer':oe_is_a('CosEventComm_PullConsumer':typeID())),
- ?match(false, 'CosEventComm_PullConsumer':oe_is_a("wrong")),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventComm_PullSupplier'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventComm_PullSupplier'(_) ->
- ?nomatch(undefined, 'CosEventComm_PullSupplier':oe_tc(pull)),
- ?nomatch(undefined, 'CosEventComm_PullSupplier':oe_tc(try_pull)),
- ?nomatch(undefined, 'CosEventComm_PullSupplier':oe_tc(disconnect_pull_supplier)),
- ?match(undefined, 'CosEventComm_PullSupplier':oe_tc(undefined)),
- ?match([_|_], 'CosEventComm_PullSupplier':oe_get_interface()),
- ?match("IDL:omg.org/CosEventComm/PullSupplier:1.0",
- 'CosEventComm_PullSupplier':typeID()),
- check_tc('CosEventComm_PullSupplier':oe_get_interface()),
- ?match(true, 'CosEventComm_PullSupplier':oe_is_a('CosEventComm_PullSupplier':typeID())),
- ?match(false, 'CosEventComm_PullSupplier':oe_is_a("wrong")),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventComm_PushConsumer'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventComm_PushConsumer'(_) ->
- ?nomatch(undefined, 'CosEventComm_PushConsumer':oe_tc(push)),
- ?nomatch(undefined, 'CosEventComm_PushConsumer':oe_tc(disconnect_push_consumer)),
- ?match(undefined, 'CosEventComm_PushConsumer':oe_tc(undefined)),
- ?match([_|_], 'CosEventComm_PushConsumer':oe_get_interface()),
- ?match("IDL:omg.org/CosEventComm/PushConsumer:1.0",
- 'CosEventComm_PushConsumer':typeID()),
- check_tc('CosEventComm_PushConsumer':oe_get_interface()),
- ?match(true, 'CosEventComm_PushConsumer':oe_is_a('CosEventComm_PushConsumer':typeID())),
- ?match(false, 'CosEventComm_PushConsumer':oe_is_a("wrong")),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventComm_PushSupplier'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventComm_PushSupplier'(_) ->
- ?nomatch(undefined, 'CosEventComm_PushSupplier':oe_tc(disconnect_push_supplier)),
- ?match(undefined, 'CosEventComm_PushSupplier':oe_tc(undefined)),
- ?match([_|_], 'CosEventComm_PushSupplier':oe_get_interface()),
- ?match("IDL:omg.org/CosEventComm/PushSupplier:1.0",
- 'CosEventComm_PushSupplier':typeID()),
- check_tc('CosEventComm_PushSupplier':oe_get_interface()),
- ?match(true, 'CosEventComm_PushSupplier':oe_is_a('CosEventComm_PushSupplier':typeID())),
- ?match(false, 'CosEventComm_PushSupplier':oe_is_a("wrong")),
- ok.
-
-
-
-%%-----------------------------------------------------------------
-%% MISC functions
-%%-----------------------------------------------------------------
-check_tc([]) ->
- ok;
-check_tc([{Op, {RetType, InParameters, OutParameters}}|T]) ->
- io:format("checked - ~s~n", [Op]),
- lists:all(?checktc(Op), [RetType|InParameters]),
- lists:all(?checktc(Op), OutParameters),
- check_tc(T).
-
-
diff --git a/lib/cosEvent/vsn.mk b/lib/cosEvent/vsn.mk
deleted file mode 100644
index 578950294a..0000000000
--- a/lib/cosEvent/vsn.mk
+++ /dev/null
@@ -1,2 +0,0 @@
-COSEVENT_VSN = 2.2.2
-
diff --git a/lib/cosEventDomain/AUTHORS b/lib/cosEventDomain/AUTHORS
deleted file mode 100644
index 6d03df4c5a..0000000000
--- a/lib/cosEventDomain/AUTHORS
+++ /dev/null
@@ -1,4 +0,0 @@
-Original Authors:
-Niclas Eklund
-
-Contributors:
diff --git a/lib/cosEventDomain/Makefile b/lib/cosEventDomain/Makefile
deleted file mode 100644
index 8e8ae7e4da..0000000000
--- a/lib/cosEventDomain/Makefile
+++ /dev/null
@@ -1,42 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2001-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include vsn.mk
-VSN=$(COSEVENTDOMAIN_VSN)
-
-# ----------------------------------------------------
-# Common Macros
-# ----------------------------------------------------
-
-SUB_DIRECTORIES = src doc/src
-
-SPECIAL_TARGETS =
-
-# ----------------------------------------------------
-# Default Subdir Targets
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_subdir.mk
-
diff --git a/lib/cosEventDomain/doc/pdf/.gitignore b/lib/cosEventDomain/doc/pdf/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosEventDomain/doc/pdf/.gitignore
+++ /dev/null
diff --git a/lib/cosEventDomain/doc/src/CosEventDomainAdmin.xml b/lib/cosEventDomain/doc/src/CosEventDomainAdmin.xml
deleted file mode 100644
index 6931059e67..0000000000
--- a/lib/cosEventDomain/doc/src/CosEventDomainAdmin.xml
+++ /dev/null
@@ -1,93 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2002</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosEventDomainAdmin</title>
- <prepared>Niclas Eklund</prepared>
- <responsible>Niclas Eklund</responsible>
- <docno></docno>
- <approved>Niclas Eklund</approved>
- <checked></checked>
- <date>2001-08-20</date>
- <rev>PA1</rev>
- </header>
- <module>CosEventDomainAdmin</module>
- <modulesummary>This module export functions which return QoS and Admin Properties constants.</modulesummary>
- <description>
- <p>To get access to all definitions include necessary <c><![CDATA[hrl]]></c> files by using:<br></br><c><![CDATA[-include_lib("cosEventDomain/include/*.hrl").]]></c></p>
- </description>
- <funcs>
- <func>
- <name>'CycleDetection'() -> string()</name>
- <fsummary>Return the CycleDetection identifier required when defining QoS Properties</fsummary>
- <desc>
- <p>This function returns the CycleDetection identifier; required when
- defining QoS Properties.</p>
- </desc>
- </func>
- <func>
- <name>'AuthorizeCycles'() -> short()</name>
- <fsummary>Return the AuthorizeCycles value; required when defining QoS Properties</fsummary>
- <desc>
- <p>This function returns the AuthorizeCycles value; required when
- defining QoS Properties.</p>
- </desc>
- </func>
- <func>
- <name>'ForbidCycles'() -> short()</name>
- <fsummary>Return the ForbidCycles value; required when defining QoS Properties</fsummary>
- <desc>
- <p>This function returns the ForbidCycles value; required when
- defining QoS Properties.</p>
- </desc>
- </func>
- <func>
- <name>'DiamondDetection'() -> string()</name>
- <fsummary>Return the DiamondDetection identifier required when defining QoS Properties</fsummary>
- <desc>
- <p>This function returns the DiamondDetection identifier; required when
- defining QoS Properties.</p>
- </desc>
- </func>
- <func>
- <name>'AuthorizeDiamonds'() -> short()</name>
- <fsummary>Return the AuthorizeDiamonds value; required when defining QoS Properties</fsummary>
- <desc>
- <p>This function returns the AuthorizeDiamonds value; required when
- defining QoS Properties.</p>
- </desc>
- </func>
- <func>
- <name>'ForbidDiamonds'() -> short()</name>
- <fsummary>Return the ForbidDiamonds value; required when defining QoS Properties</fsummary>
- <desc>
- <p>This function returns the ForbidDiamonds value; required when
- defining QoS Properties.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosEventDomain/doc/src/CosEventDomainAdmin_EventDomain.xml b/lib/cosEventDomain/doc/src/CosEventDomainAdmin_EventDomain.xml
deleted file mode 100644
index e99c8d380b..0000000000
--- a/lib/cosEventDomain/doc/src/CosEventDomainAdmin_EventDomain.xml
+++ /dev/null
@@ -1,627 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2001</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>CosEventDomainAdmin_EventDomain</title>
- <prepared></prepared>
- <docno></docno>
- <approved>Niclas Eklund</approved>
- <checked></checked>
- <date>2001-08-20</date>
- <rev>PA1</rev>
- </header>
- <module>CosEventDomainAdmin_EventDomain</module>
- <modulesummary>This module implements the Event Domain interface.</modulesummary>
- <description>
- <p>To get access to all definitions include necessary <c><![CDATA[hrl]]></c> files by using:<br></br><c><![CDATA[-include_lib("cosEventDomain/include/*.hrl").]]></c></p>
- <p>This module also exports the functions described in:</p>
- <list type="bulleted">
- <item><em>CosNotification_QoSAdmin</em></item>
- <item><em>CosNotification_AdminPropertiesAdmin</em></item>
- </list>
- </description>
- <funcs>
- <func>
- <name>add_channel(EventDomain, Channel) -> MemberID</name>
- <fsummary>Add a new channel to the EventDomain</fsummary>
- <type>
- <v>EventDomain = Channel = #objref</v>
- <v>MemberID = long()</v>
- </type>
- <desc>
- <p>Adds the given channel to the target domain. The channel
- must be a <c><![CDATA[CosNotifyChannelAdmin::EventChannel]]></c>.</p>
- </desc>
- </func>
- <func>
- <name>get_all_channels(EventDomain) -> MemberIDSeq</name>
- <fsummary>Return all channel id's associated with target object</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>MemberIDSeq = [long()]</v>
- </type>
- <desc>
- <p>Returns a a sequence of all channels associated with
- the target object.</p>
- </desc>
- </func>
- <func>
- <name>get_channel(EventDomain, MemberID) -> Reply</name>
- <fsummary>Return the channel associated with the given id</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>MemberID = long()</v>
- <v>Reply = Channel | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- <v>Channel = #objref</v>
- </type>
- <desc>
- <p>If the target domain have a <c><![CDATA[CosNotifyChannelAdmin::EventChannel]]></c>
- represented by the given id this channel is returned. Otherwise,
- an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>remove_channel(EventDomain, MemberID) -> Reply</name>
- <fsummary>Remove the channel associated with the given id and remove all connections of that channel</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>MemberID = long()</v>
- <v>Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- </type>
- <desc>
- <p>If a <c><![CDATA[CosNotifyChannelAdmin::EventChannel]]></c> with the
- <c><![CDATA[MemberID]]></c> exists it will removed and all its <c><![CDATA[Connections]]></c>
- terminated. Otherwise an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>add_connection(EventDomain, Connection) -> Reply</name>
- <fsummary>If possible, setup a connection described by the <c><![CDATA[#'CosEventDomainAdmin_Connection'{}]]></c>struct</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>Connection = 'CosEventDomainAdmin_Connection'{supplier_id=MemberID, consumer_id=MemberID, ctype=Type, notification_style=Style}</v>
- <v>MemberID = long()</v>
- <v>Type = 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT'</v>
- <v>Style = 'Pull' | 'Push'</v>
- <v>Reply = ConnectionID | {'EXCEPTION', Exc}</v>
- <v>ConnectionID = long()</v>
- <v>Exc = #'CosNotifyChannelAdmin_ChannelNotFound'{} | #'CosNotifyChannelAdmin_TypeError'{} | #'CosEventDomainAdmin_AlreadyExists'{} | #'CosEventDomainAdmin_DiamondCreationForbidden'{diam=RouteSeq} | #'CosEventDomainAdmin_CycleCreationForbidden'{cyc=MemberIDSeq}</v>
- <v>RouteSeq = [MemberIDSeq]</v>
- <v>MemberIDSeq = [long()]</v>
- </type>
- <desc>
- <p>The Connection parameter must contain valid data to enable
- the target domain to setup a connection between two channels.
- The struct members <c><![CDATA[supplier_id]]></c> and <c><![CDATA[consumer_id]]></c>
- determines which channel should produce and consume events.
- which type of events and if the supplier should push or the
- consumer pull events is determined by <c><![CDATA[ctype]]></c> and
- <c><![CDATA[notification_style]]></c> respectively.</p>
- <p>If the target domain is not able to setup the connection
- the appropriate exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>get_all_connections(EventDomain) -> ConnectionIDSeq</name>
- <fsummary>Return a sequence of all connections within the target domain</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>ConnectionIDSeq = [long()]</v>
- </type>
- <desc>
- <p>This operation returns a sequence of all connections within
- the target domain.</p>
- </desc>
- </func>
- <func>
- <name>get_connection(EventDomain, ConnectionID) -> Reply</name>
- <fsummary>Return a <c><![CDATA[#'CosEventDomainAdmin_Connection'{}]]></c>struct describing the connection associated with the given id within the target domain</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>ConnectionID = long()</v>
- <v>Reply = Connection | {'EXCEPTION', #'CosEventDomainAdmin_ConnectionNotFound'{}}</v>
- <v>Connection = 'CosEventDomainAdmin_Connection'{supplier_id=MemberID, consumer_id=MemberID, ctype=Type, notification_style=Style}</v>
- <v>MemberID = long()</v>
- <v>Type = 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT'</v>
- <v>Style = 'Pull' | 'Push'</v>
- </type>
- <desc>
- <p>If a connection identified by the given id exists within the
- target domain, a <c><![CDATA[#'CosEventDomainAdmin_Connection'{}]]></c> which
- describe the connection is returned. Otherwise, an exception
- is raised.</p>
- </desc>
- </func>
- <func>
- <name>remove_connection(EventDomain, ConnectionID) -> Reply</name>
- <fsummary>Remove the connection identified by the given id from the target domain</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>ConnectionID = long()</v>
- <v>Reply = ok | {'EXCEPTION', #'CosEventDomainAdmin_ConnectionNotFound'{}}</v>
- </type>
- <desc>
- <p>If the supplied connection id exists, the connection the
- id represents is terminated. Otherwise, an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>get_offer_channels(EventDomain, MemberID) -> Reply</name>
- <fsummary>Return all id's of the channels which produce events received by the channel identified by the given id</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>MemberID = long()</v>
- <v>Reply = MemberIDSeq | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- </type>
- <desc>
- <p>This operation returns a sequence, containing the member id's
- of all channels within the target domain which will supply events
- to the channel identified by the given id. But, if no such
- id exists in this domain, an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>get_subscription_channels(EventDomain, MemberID) -> Reply</name>
- <fsummary>Return all id's of the channels which consume events supplied by the channel identified by the given id</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>Reply = MemberIDSeq | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- </type>
- <desc>
- <p>This operations behaves like <c><![CDATA[get_subscription_channels]]></c>;
- the difference is that the id's returned identifies channels
- which will consume events supplied by the channel associated
- with the given id.</p>
- </desc>
- </func>
- <func>
- <name>destroy(EventDomain) -> ok</name>
- <fsummary>Destroy the event domain and all connections within it</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- </type>
- <desc>
- <p>Calling this operation will terminate all connections
- within the target domain. The domain will terminate but
- all channels will not be affected.</p>
- </desc>
- </func>
- <func>
- <name>get_cycles(EventDomain) -> RouteSeq</name>
- <fsummary>Return a list of all cycles which exists within the target domain</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>RouteSeq = [MemberIDSeq]</v>
- <v>MemberIDSeq = [long()]</v>
- </type>
- <desc>
- <p>Returns a list of all cycles within the target domain.</p>
- </desc>
- </func>
- <func>
- <name>get_diamonds(EventDomain) -> DiamondSeq</name>
- <fsummary>Return a list of all diamonds which exists within the target domain</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>DiamondSeq = [RouteSeq]</v>
- <v>RouteSeq = [MemberIDSeq]</v>
- <v>MemberIDSeq = [long()]</v>
- </type>
- <desc>
- <p>Returns a list of all diamonds within the target domain</p>
- </desc>
- </func>
- <func>
- <name>set_default_consumer_channel(EventDomain, MemberID) -> Reply</name>
- <fsummary>Set the channel represented by the given id as default for supplier clients</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>Reply = MemberID | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- <v>MemberID = long()</v>
- </type>
- <desc>
- <p>If the given id represents a channel within the target domain,
- this channel will be used when connection a supplier client
- without specifying a certain channel. If no such channel exists
- an exceptions is raised.</p>
- </desc>
- </func>
- <func>
- <name>set_default_supplier_channel(EventDomain, MemberID) -> Reply</name>
- <fsummary>Set the channel represented by the given id as default for supplier clients</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>Reply = MemberID | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- <v>MemberID = long()</v>
- </type>
- <desc>
- <p>If the given id represents a channel within the target domain,
- this channel will be used when connection a consumer client
- without specifying a certain channel. If no such channel exists
- an exceptions is raised.</p>
- </desc>
- </func>
- <func>
- <name>connect_push_consumer(EventDomain, Consumer) -> Reply</name>
- <fsummary>Connect the PushConsumer to the default Channel</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>Consumer = CosEventComm::PushConsumer</v>
- <v>Reply = CosNotifyChannelAdmin::ProxyPushSupplier | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- </type>
- <desc>
- <p>If a default Channel have been set, this operation connects the given
- PushConsumer to it. Otherwise, the
- <c><![CDATA[#'CosNotifyChannelAdmin_ChannelNotFound'{}]]></c> exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>connect_pull_consumer(EventDomain, Consumer) -> Reply</name>
- <fsummary>Connect the PullConsumer to the default Channel</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>Consumer = CosEventComm::PullConsumer</v>
- <v>Reply = CosNotifyChannelAdmin::ProxyPullSupplier | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- </type>
- <desc>
- <p>If a default Channel have been set, this operation connects the given
- PullConsumer to it. Otherwise, the
- <c><![CDATA[#'CosNotifyChannelAdmin_ChannelNotFound'{}]]></c> exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>connect_push_supplier(EventDomain, Supplier) -> Reply</name>
- <fsummary>Connect the PushSupplier to the default Channel</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>Supplier = CosEventComm::PushSupplier</v>
- <v>Reply = CosNotifyChannelAdmin::ProxyPushConsumer | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- </type>
- <desc>
- <p>If a default Channel have been set, this operation connects the given
- PushSupplier to it. Otherwise, the
- <c><![CDATA[#'CosNotifyChannelAdmin_ChannelNotFound'{}]]></c> exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>connect_pull_supplier(EventDomain, Supplier) -> Reply</name>
- <fsummary>Connect the PullSupplier to the default Channel</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>Supplier = CosEventComm::PullSupplier</v>
- <v>Reply = CosNotifyChannelAdmin::ProxyPushConsumer | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- </type>
- <desc>
- <p>If a default Channel have been set, this operation connects the given
- PullSupplier to it. Otherwise, the
- <c><![CDATA[#'CosNotifyChannelAdmin_ChannelNotFound'{}]]></c> exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>connect_structured_push_consumer(EventDomain, Consumer) -> Reply</name>
- <fsummary>Connect the StructuredPushConsumer to the default Channel</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>Consumer = CosNotifyComm::StructuredPushConsumer</v>
- <v>Reply = CosNotifyChannelAdmin::StructuredProxyPushSupplier | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- </type>
- <desc>
- <p>If a default Channel have been set, this operation connects the given
- StructuredPushConsumer to it. Otherwise, the
- <c><![CDATA[#'CosNotifyChannelAdmin_ChannelNotFound'{}]]></c> exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>connect_structured_pull_consumer(EventDomain, Consumer) -> Reply</name>
- <fsummary>Connect the StructuredPullConsumer to the default Channel</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>Consumer = CosNotifyComm::StructuredPullConsumer</v>
- <v>Reply = CosNotifyChannelAdmin::StructuredProxyPullSupplier | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- </type>
- <desc>
- <p>If a default Channel have been set, this operation connects the given
- StructuredPullConsumer to it. Otherwise, the
- <c><![CDATA[#'CosNotifyChannelAdmin_ChannelNotFound'{}]]></c> exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>connect_structured_push_supplier(EventDomain, Supplier) -> Reply</name>
- <fsummary>Connect the StructuredPushSupplier to the default Channel</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>Supplier = CosNotifyComm::StructuredPushSupplier</v>
- <v>Reply = CosNotifyChannelAdmin::StructuredProxyPushConsumer | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- </type>
- <desc>
- <p>If a default Channel have been set, this operation connects the given
- StructuredPushSupplier to it. Otherwise, the
- <c><![CDATA[#'CosNotifyChannelAdmin_ChannelNotFound'{}]]></c> exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>connect_structured_pull_supplier(EventDomain, Supplier) -> Reply</name>
- <fsummary>Connect the StructuredPullSupplier to the default Channel</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>Supplier = CosNotifyComm::StructuredPullSupplier</v>
- <v>Reply = CosNotifyChannelAdmin::StructuredProxyPullConsume | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- </type>
- <desc>
- <p>If a default Channel have been set, this operation connects the given
- StructuredPullSupplier to it. Otherwise, the
- <c><![CDATA[#'CosNotifyChannelAdmin_ChannelNotFound'{}]]></c> exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>connect_sequence_push_consumer(EventDomain, Consumer) -> Reply</name>
- <fsummary>Connect the SequencePushConsumer to the default Channel</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>Consumer = CosNotifyComm::SequencePushConsumer</v>
- <v>Reply = CosNotifyChannelAdmin::SequenceProxyPushSupplier | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- </type>
- <desc>
- <p>If a default Channel have been set, this operation connects the given
- SequencePushConsumer to it. Otherwise, the
- <c><![CDATA[#'CosNotifyChannelAdmin_ChannelNotFound'{}]]></c> exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>connect_sequence_pull_consumer(EventDomain, Consumer) -> Reply</name>
- <fsummary>Connect the SequencePullConsumer to the default Channel</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>Consumer = CosNotifyComm::SequencePullConsumer</v>
- <v>Reply = CosNotifyChannelAdmin::SequenceProxyPullSupplier | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- </type>
- <desc>
- <p>If a default Channel have been set, this operation connects the given
- SequencePullConsumer to it. Otherwise, the
- <c><![CDATA[#'CosNotifyChannelAdmin_ChannelNotFound'{}]]></c> exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>connect_sequence_push_supplier(EventDomain, Supplier) -> Reply</name>
- <fsummary>Connect the SequencePushSupplier to the default Channel</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>Supplier = CosNotifyComm::SequencePushSupplier</v>
- <v>Reply = CosNotifyChannelAdmin::SequenceProxyPushConsumer | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- </type>
- <desc>
- <p>If a default Channel have been set, this operation connects the given
- SequencePushSupplier to it. Otherwise, the
- <c><![CDATA[#'CosNotifyChannelAdmin_ChannelNotFound'{}]]></c> exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>connect_sequence_pull_supplier(EventDomain, Supplier) -> Reply</name>
- <fsummary>Connect the SequencePullSupplier to the default Channel</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>Supplier = CosNotifyComm::SequencePullSupplier</v>
- <v>Reply = CosNotifyChannelAdmin::SequenceProxyPullConsumer | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- </type>
- <desc>
- <p>If a default Channel have been set, this operation connects the given
- SequencePullSupplier to it. Otherwise, the
- <c><![CDATA[#'CosNotifyChannelAdmin_ChannelNotFound'{}]]></c> exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>connect_push_consumer_with_id(EventDomain, Consumer, MemberID) -> Reply</name>
- <fsummary>Connect the PushConsumer to the Channel with the given MemberID</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>Consumer = CosEventComm::PushConsumer</v>
- <v>MemberID = long()</v>
- <v>Reply = CosNotifyChannelAdmin::ProxyPushSupplier | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- </type>
- <desc>
- <p>If a Channel associated with the given MemberID exists within the
- target Domain, this operation connects the given PushConsumer
- to it. Otherwise, the <c><![CDATA[#'CosNotifyChannelAdmin_ChannelNotFound'{}]]></c>
- exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>connect_pull_consumer_with_id(EventDomain, Consumer, MemberID) -> Reply</name>
- <fsummary>Connect the PullConsumer to the Channel with the given MemberID</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>Consumer = CosEventComm::PullConsumer</v>
- <v>MemberID = long()</v>
- <v>Reply = CosNotifyChannelAdmin::ProxyPullSupplier | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- </type>
- <desc>
- <p>If a Channel associated with the given MemberID exists within the
- target Domain, this operation connects the given PullConsumer
- to it. Otherwise, the <c><![CDATA[#'CosNotifyChannelAdmin_ChannelNotFound'{}]]></c>
- exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>connect_push_supplier_with_id(EventDomain, Supplier, MemberID) -> Reply</name>
- <fsummary>Connect the PushSupplier to the Channel with the given MemberID</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>Supplier = CosEventComm::PushSupplier</v>
- <v>MemberID = long()</v>
- <v>Reply = CosNotifyChannelAdmin::ProxyPushConsumer | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- </type>
- <desc>
- <p>If a Channel associated with the given MemberID exists within the
- target Domain, this operation connects the given PushSupplier
- to it. Otherwise, the <c><![CDATA[#'CosNotifyChannelAdmin_ChannelNotFound'{}]]></c>
- exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>connect_pull_supplier_with_id(EventDomain, Supplier, MemberID) -> Reply</name>
- <fsummary>Connect the PullSupplier to the Channel with the given MemberID</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>Supplier = CosEventComm::PullSupplier</v>
- <v>MemberID = long()</v>
- <v>Reply = CosNotifyChannelAdmin::ProxyPushConsumer | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- </type>
- <desc>
- <p>If a Channel associated with the given MemberID exists within the
- target Domain, this operation connects the given PullSupplier
- to it. Otherwise, the <c><![CDATA[#'CosNotifyChannelAdmin_ChannelNotFound'{}]]></c>
- exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>connect_structured_push_consumer_with_id(EventDomain, Consumer, MemberID) -> Reply</name>
- <fsummary>Connect the StructuredPushConsumer to the Channel with the given MemberID</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>Consumer = CosNotifyComm::StructuredPushConsumer</v>
- <v>MemberID = long()</v>
- <v>Reply = CosNotifyChannelAdmin::StructuredProxyPushSupplier | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- </type>
- <desc>
- <p>If a Channel associated with the given MemberID exists within the
- target Domain, this operation connects the given StructuredPushConsumer
- to it. Otherwise, the <c><![CDATA[#'CosNotifyChannelAdmin_ChannelNotFound'{}]]></c>
- exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>connect_structured_pull_consumer_with_id(EventDomain, Consumer, MemberID) -> Reply</name>
- <fsummary>Connect the StructuredPullConsumer to the Channel with the given MemberID</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>Consumer = CosNotifyComm::StructuredPullConsumer</v>
- <v>MemberID = long()</v>
- <v>Reply = CosNotifyChannelAdmin::StructuredProxyPullSupplier | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- </type>
- <desc>
- <p>If a Channel associated with the given MemberID exists within the
- target Domain, this operation connects the given StructuredPullConsumer
- to it. Otherwise, the <c><![CDATA[#'CosNotifyChannelAdmin_ChannelNotFound'{}]]></c>
- exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>connect_structured_push_supplier_with_id(EventDomain, Supplier, MemberID) -> Reply</name>
- <fsummary>Connect the StructuredPushSupplier to the Channel with the given MemberID</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>Supplier = CosNotifyComm::StructuredPushSupplier</v>
- <v>MemberID = long()</v>
- <v>Reply = CosNotifyChannelAdmin::StructuredProxyPushConsumer | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- </type>
- <desc>
- <p>If a Channel associated with the given MemberID exists within the
- target Domain, this operation connects the given StructuredPushSupplier
- to it. Otherwise, the <c><![CDATA[#'CosNotifyChannelAdmin_ChannelNotFound'{}]]></c>
- exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>connect_structured_pull_supplier_with_id(EventDomain, Supplier, MemberID) -> Reply</name>
- <fsummary>Connect the StructuredPullSupplier to the Channel with the given MemberID</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>Supplier = CosNotifyComm::StructuredPullSupplier</v>
- <v>MemberID = long()</v>
- <v>Reply = CosNotifyChannelAdmin::StructuredProxyPullConsumer | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- </type>
- <desc>
- <p>If a Channel associated with the given MemberID exists within the
- target Domain, this operation connects the given StructuredPullSupplier
- to it. Otherwise, the <c><![CDATA[#'CosNotifyChannelAdmin_ChannelNotFound'{}]]></c>
- exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>connect_sequence_push_consumer_with_id(EventDomain, Consumer, MemberID) -> Reply</name>
- <fsummary>Connect the SequencePushConsumer to the Channel with the given MemberID</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>Consumer = CosNotifyComm::SequencePushConsumer</v>
- <v>MemberID = long()</v>
- <v>Reply = CosNotifyChannelAdmin::SequenceProxyPushSupplier | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- </type>
- <desc>
- <p>If a Channel associated with the given MemberID exists within the
- target Domain, this operation connects the given SequencePushConsumer
- to it. Otherwise, the <c><![CDATA[#'CosNotifyChannelAdmin_ChannelNotFound'{}]]></c>
- exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>connect_sequence_pull_consumer_with_id(EventDomain, Consumer, MemberID) -> Reply</name>
- <fsummary>Connect the SequencePullConsumer to the Channel with the given MemberID</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>Consumer = CosNotifyComm::SequencePullConsumer</v>
- <v>MemberID = long()</v>
- <v>Reply = CosNotifyChannelAdmin::SequenceProxyPullSupplier | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- </type>
- <desc>
- <p>If a Channel associated with the given MemberID exists within the
- target Domain, this operation connects the given SequencePullConsumer
- to it. Otherwise, the <c><![CDATA[#'CosNotifyChannelAdmin_ChannelNotFound'{}]]></c>
- exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>connect_sequence_push_supplier_with_id(EventDomain, Supplier, MemberID) -> Reply</name>
- <fsummary>Connect the SequencePushSupplier to the Channel with the given MemberID</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>Supplier = CosNotifyComm::SequencePushSupplier</v>
- <v>MemberID = long()</v>
- <v>Reply = CosNotifyChannelAdmin::SequenceProxyPushConsumer | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- </type>
- <desc>
- <p>If a Channel associated with the given MemberID exists within the
- target Domain, this operation connects the given SequencePushSupplier
- to it. Otherwise, the <c><![CDATA[#'CosNotifyChannelAdmin_ChannelNotFound'{}]]></c>
- exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>connect_sequence_pull_supplier_with_id(EventDomain, Supplier, MemberID) -> Reply</name>
- <fsummary>Connect the SequencePullSupplier to the Channel with the given MemberID</fsummary>
- <type>
- <v>EventDomain = #objref</v>
- <v>Supplier = CosNotifyComm::SequencePullSupplier</v>
- <v>MemberID = long()</v>
- <v>Reply = CosNotifyChannelAdmin::SequenceProxyPullConsumer | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- </type>
- <desc>
- <p>If a Channel associated with the given MemberID exists within the
- target Domain, this operation connects the given SequencePullSupplier
- to it. Otherwise, the <c><![CDATA[#'CosNotifyChannelAdmin_ChannelNotFound'{}]]></c>
- exception is raised.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosEventDomain/doc/src/CosEventDomainAdmin_EventDomainFactory.xml b/lib/cosEventDomain/doc/src/CosEventDomainAdmin_EventDomainFactory.xml
deleted file mode 100644
index 602e0e5fb0..0000000000
--- a/lib/cosEventDomain/doc/src/CosEventDomainAdmin_EventDomainFactory.xml
+++ /dev/null
@@ -1,88 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2001</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosEventDomainAdmin_EventDomainFactory</title>
- <prepared>Niclas Eklund</prepared>
- <responsible>Niclas Eklund</responsible>
- <docno></docno>
- <approved>Niclas Eklund</approved>
- <checked></checked>
- <date>2001-08-20</date>
- <rev>PA1</rev>
- </header>
- <module>CosEventDomainAdmin_EventDomainFactory</module>
- <modulesummary>This module implements an Event Domain Factory interface, which is used to create new Event Domain instances.</modulesummary>
- <description>
- <p>To get access to all definitions include necessary <c><![CDATA[hrl]]></c> files by using:<br></br><c><![CDATA[-include_lib("cosEventDomain/include/*.hrl").]]></c></p>
- </description>
- <funcs>
- <func>
- <name>create_event_domain(Factory, QoS, Admin) -> Reply</name>
- <fsummary>Create a new ConsumerAdmin object</fsummary>
- <type>
- <v>Factory = #objref</v>
- <v>QoS = CosNotification::QoSProperties</v>
- <v>Admin = CosNotification::AdminProperties</v>
- <v>Reply = {EventDomain, DomainID} | {'EXCEPTION', #'CosNotification_UnsupportedQoS'{}} | {'EXCEPTION', #'CosNotification_UnsupportedAdmin'{}}</v>
- <v>EventDomain = #objref</v>
- </type>
- <desc>
- <p>To create a new EventDomain this operation is used. If it is not
- possible to support the given <c><![CDATA[QoSProperties]]></c> or <c><![CDATA[AdminProperties]]></c>
- an exception is raised, which list the properties not supported. For more
- information see the <c><![CDATA[cosNotification]]></c> user's guide.</p>
- </desc>
- </func>
- <func>
- <name>get_all_domains(Factory) -> DomainIDSeq</name>
- <fsummary>Return a DomainID sequence of all domains associated with the target object</fsummary>
- <type>
- <v>Factory = #objref</v>
- <v>DomainIDSeq = [long()]</v>
- </type>
- <desc>
- <p>This function returns a DomainID sequence of all domains associated with the
- target object.</p>
- </desc>
- </func>
- <func>
- <name>get_event_domain(Factory, DomainID) -> Reply</name>
- <fsummary>Return the domain associated with the given id</fsummary>
- <type>
- <v>Factory = #objref</v>
- <v>DomainID = long()</v>
- <v>Reply = EventDomain | {'EXCEPTION', #'CosEventDomainAdmin_DomainNotFound'{}}</v>
- <v>EventDomain = #objref</v>
- </type>
- <desc>
- <p>This operation returns the EventDomain object associated with the
- given DomainID. If no such binding exists an exception is raised.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosEventDomain/doc/src/Makefile b/lib/cosEventDomain/doc/src/Makefile
deleted file mode 100644
index 9faf65394d..0000000000
--- a/lib/cosEventDomain/doc/src/Makefile
+++ /dev/null
@@ -1,137 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2001-2017. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../../vsn.mk
-VSN=$(COSEVENTDOMAIN_VSN)
-APPLICATION=cosEventDomain
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-XML_APPLICATION_FILES = ref_man.xml
-XML_REF3_FILES = \
- CosEventDomainAdmin_EventDomainFactory.xml \
- CosEventDomainAdmin_EventDomain.xml \
- CosEventDomainAdmin.xml \
- cosEventDomainApp.xml
-
-XML_PART_FILES = \
- part.xml
-XML_CHAPTER_FILES = \
- ch_contents.xml \
- ch_introduction.xml \
- ch_QoS.xml \
- ch_event_domain_service.xml \
- notes.xml
-
-BOOK_FILES = book.xml
-
-XML_FILES = $(BOOK_FILES) $(XML_APPLICATION_FILES) $(XML_REF3_FILES) \
- $(XML_PART_FILES) $(XML_CHAPTER_FILES)
-
-TECHNICAL_DESCR_FILES =
-
-GIF_FILES =
-
-PS_FILES =
-
-# ----------------------------------------------------
-
-INTERNAL_HTML_FILES = $(TECHNICAL_DESCR_FILES:%.xml=$(HTMLDIR)/%.html)
-
-HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \
- $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html)
-
-INFO_FILE = ../../info
-EXTRA_FILES = \
- $(DEFAULT_GIF_FILES) \
- $(DEFAULT_HTML_FILES) \
- $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html) \
- $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html)
-
-MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-
-HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
-
-TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-XML_FLAGS +=
-DVIPS_FLAGS +=
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-$(HTMLDIR)/%.gif: %.gif
- $(INSTALL_DATA) $< $@
-
-docs: pdf html man
-
-$(TOP_PDF_FILE): $(XML_FILES)
-
-pdf: $(TOP_PDF_FILE)
-
-html: gifs $(HTML_REF_MAN_FILE)
-
-clean clean_docs:
- rm -rf $(HTMLDIR)/*
- rm -f $(MAN3DIR)/*
- rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
- rm -f errs core *~
- rm -f $(JD_HTML) $(JD_PACK)
-
-man: $(MAN3_FILES)
-
-gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
-
-$(INDEX_TARGET): $(INDEX_SRC)
- sed -e 's;%VSN%;$(VSN);' $(INDEX_SRC) > $(INDEX_TARGET)
-
-debug opt:
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_docs_spec: docs
- $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
- $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
- $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
- $(INSTALL_DATA) $(HTMLDIR)/* \
- "$(RELSYSDIR)/doc/html"
- $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
- $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
- $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
-
-release_spec:
diff --git a/lib/cosEventDomain/doc/src/book.xml b/lib/cosEventDomain/doc/src/book.xml
deleted file mode 100644
index b073e5edc0..0000000000
--- a/lib/cosEventDomain/doc/src/book.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE book SYSTEM "book.dtd">
-
-<book xmlns:xi="http://www.w3.org/2001/XInclude">
- <header titlestyle="normal">
- <copyright>
- <year>2001</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosEventDomain</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2001-08-20</date>
- <rev>1.0</rev>
- </header>
- <insidecover>
- </insidecover>
- <pagetext>cosEventDomain</pagetext>
- <preamble>
- <contents level="2"></contents>
- </preamble>
- <parts lift="no">
- <xi:include href="part.xml"/>
- </parts>
- <applications>
- <xi:include href="ref_man.xml"/>
- </applications>
- <releasenotes>
- <xi:include href="notes.xml"/>
- </releasenotes>
- <listofterms></listofterms>
- <index></index>
-</book>
-
diff --git a/lib/cosEventDomain/doc/src/ch_QoS.xml b/lib/cosEventDomain/doc/src/ch_QoS.xml
deleted file mode 100644
index c356e38752..0000000000
--- a/lib/cosEventDomain/doc/src/ch_QoS.xml
+++ /dev/null
@@ -1,118 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2002</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Quality Of Service and Admin Properties</title>
- <prepared></prepared>
- <docno></docno>
- <date>2000-05-29</date>
- <rev></rev>
- <file>ch_QoS.xml</file>
- </header>
-
- <section>
- <title>Quality Of Service and Admin Properties</title>
- <p>This chapter explains the allowed properties it is possible to set for this
- application. </p>
-
- <section>
- <title>Quality Of Service</title>
- <p>The cosEventDomain application supports the following QoS settings:</p>
- <table>
- <row>
- <cell align="center" valign="middle"><em>QoS</em></cell>
- <cell align="center" valign="middle"><em>Range</em></cell>
- <cell align="center" valign="middle"><em>Default</em></cell>
- </row>
- <row>
- <cell align="left" valign="middle">CycleDetection</cell>
- <cell align="left" valign="middle">AuthorizeCycles/ForbidCycles</cell>
- <cell align="left" valign="middle">ForbidCycles</cell>
- </row>
- <row>
- <cell align="left" valign="middle">DiamondDetection</cell>
- <cell align="left" valign="middle">AuthorizeDiamonds/ForbidDiamonds</cell>
- <cell align="left" valign="middle">ForbidDiamonds</cell>
- </row>
- <tcaption>Supported QoS settings</tcaption>
- </table>
-<br></br><br></br><br></br><br></br> <p><em>Comments on the table 'Supported QoS Settings':</em></p>
- <taglist>
- <tag><em>CycleDetection</em></tag>
- <item>If a cycle is created, the user <em>must</em> be aware of the fact
- that unless they set timeout on events, events that are not filtered
- will loop endlessly through the topology.</item>
- <tag><em>DiamondDetection</em></tag>
- <item>A Diamond in this context, means that the same
- event may reach a point in the graph by more than one route
- (i.e. transitive). Hence, it is possible that multiple copies
- are delivered.</item>
- </taglist>
- </section>
-
- <section>
- <title>Setting Quality Of Service</title>
- <p>Assume we have a Consumer Admin object which we want to change
- the current Quality of Service. Typical usage:</p>
- <code type="none"><![CDATA[
-QoS =
- [#'CosNotification_Property'
- {name='CosEventDomainAdmin':'DiamondDetection'(),
- value=any:create(orber_tc:short(),
- 'CosEventDomainAdmin':'AuthorizeDiamonds'())},
- #'CosNotification_Property'
- {name='CosEventDomainAdmin':'CycleDetection'(),
- value=any:create(orber_tc:short(),
- 'CosEventDomainAdmin':'ForbidCycles'())}],
-'CosEventDomainAdmin_EventDomain':set_qos(ED, QoS),
- ]]></code>
- <p>If it is not possible to set the requested QoS the <c><![CDATA[UnsupportedQoS]]></c>
- exception is raised, which includes a sequence of <c><![CDATA[PropertyError]]></c>'s
- describing which QoS, possible range and why is not allowed. The error
- codes are:</p>
- <list type="bulleted">
- <item>UNSUPPORTED_PROPERTY - QoS not supported for this type of target object.</item>
- <item>UNAVAILABLE_PROPERTY - due to current QoS settings the given property
- is not allowed.</item>
- <item>UNSUPPORTED_VALUE - property value out of range; valid range is returned.</item>
- <item>UNAVAILABLE_VALUE - due to current QoS settings the given value is
- not allowed; valid range is returned.</item>
- <item>BAD_PROPERTY - unrecognized property.</item>
- <item>BAD_TYPE - type of supplied property is incorrect.</item>
- <item>BAD_VALUE - illegal value.</item>
- </list>
- <p>The CosEventDomainAdmin_EventDomain interface also supports an operation
- called <c><![CDATA[validate_qos/2]]></c>. The purpose of this operations is to check
- if a QoS setting is supported by the target object and if so, the operation
- returns additional properties which could be optionally added as well.</p>
- </section>
-
- <section>
- <title>Admin Properties</title>
- <p>The OMG specification do not contain any definitions of Admin Properties.
- Hence, the cosEventDomain application currently does not support any Admin
- Properties.</p>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosEventDomain/doc/src/ch_contents.xml b/lib/cosEventDomain/doc/src/ch_contents.xml
deleted file mode 100644
index b8fefecf44..0000000000
--- a/lib/cosEventDomain/doc/src/ch_contents.xml
+++ /dev/null
@@ -1,69 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2001</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>The cosEventDomain Application</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2001-08-20</date>
- <rev>B</rev>
- <file>ch_contents.xml</file>
- </header>
-
- <section>
- <title>Content Overview</title>
- <p>The cosEventDomain documentation is divided into three sections:
- </p>
- <list type="bulleted">
- <item>
- <p>PART ONE - The User's Guide
- <br></br>Description of the cosEventDomain Application including
- services and a small tutorial demonstrating
- the development of a simple service.</p>
- </item>
- <item>
- <p>PART TWO - Release Notes
- <br></br>A concise history of cosEventDomain.</p>
- </item>
- <item>
- <p>PART THREE - The Reference Manual
- <br></br> A quick reference guide, including a
- brief description, to all the functions available in cosEventDomain.</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Brief Description of the User's Guide</title>
- <p>The User's Guide contains the following parts:</p>
- <list type="bulleted">
- <item>
- <p>CosEventDomain overview</p>
- </item>
- <item>
- <p>CosEventDomain installation and examples</p>
- </item>
- </list>
- </section>
-</chapter>
-
diff --git a/lib/cosEventDomain/doc/src/ch_event_domain_service.xml b/lib/cosEventDomain/doc/src/ch_event_domain_service.xml
deleted file mode 100644
index a0ecf20415..0000000000
--- a/lib/cosEventDomain/doc/src/ch_event_domain_service.xml
+++ /dev/null
@@ -1,111 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2001</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Event Domain Service</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2001-08-20</date>
- <rev>A</rev>
- <file>ch_event_domain_service.xml</file>
- </header>
-
- <section>
- <title>Overview of the CosEventDomain Service</title>
- <p>The Event Domain service allows programmers to manage a cluster
- of information channels.</p>
-
- <section>
- <title>Event Domain Service Components</title>
- <p>There are two components in the OMG CosEventDomainAdmin service architecture:</p>
- <list type="bulleted">
- <item><em>EventDomainFactory:</em> a factory for creating EventDomains.</item>
- <item><em>EventDomain:</em> supplies a tool, which makes it easy to create
- topologies of interconnected channels (i.e. a directed graph).</item>
- </list>
- </section>
-
- <section>
- <title>A Tutorial on How to Create a Simple Service</title>
- <p>To be able to use the cosEventDomain application, the cosNotification
- and, possibly, the cosTime application must be installed.</p>
- </section>
-
- <section>
- <title>How to Run Everything</title>
- <p>Below is a short transcript on how to run cosEventDomain. </p>
- <code type="none"><![CDATA[
-
-%% Start Mnesia and Orber
-mnesia:delete_schema([node()]),
-mnesia:create_schema([node()]),
-orber:install([node()]),
-mnesia:start(),
-orber:start(),
-
-%% Install and start cosNotification.
-cosNotificationApp:install(),
-cosNotificationApp:start(),
-
-%% Install and start cosEventDomain.
-cosEventDomainApp:install(),
-cosEventDomainApp:start(),
-
-%% Start a CosEventDomainAdmin factory.
-AdminFac = cosEventDomainApp:start_factory(),
-
-%% Define the desired QoS settings:
-QoS =
- [#'CosNotification_Property'
- {name='CosEventDomainAdmin':'DiamondDetection'(),
- value=any:create(orber_tc:short(),
- 'CosEventDomainAdmin':'AuthorizeDiamonds'())},
- #'CosNotification_Property'
- {name='CosEventDomainAdmin':'CycleDetection'(),
- value=any:create(orber_tc:short(),
- 'CosEventDomainAdmin':'ForbidCycles'())}],
-
-%% Create a new EventDomain:
-{ED, EDId} = 'CosEventDomainAdmin_EventDomainFactory':
- create_event_domain(Fac, QoS, []),
-
-%% Now we can add Notification Channels to the Domain. How this
-%% is done, see the cosNotification documentation. Let us assume
-%% that we have gained access to two Channel Objects; add them to the
-%% domain:
-ID1 = 'CosEventDomainAdmin_EventDomain':add_channel(ED, Ch1),
-ID2 = 'CosEventDomainAdmin_EventDomain':add_channel(ED, Ch2),
-
-%% To connect them, we must first define a connection struct:
-C1 = #'CosEventDomainAdmin_Connection'{supplier_id=ID1,
- consumer_id=ID2,
- ctype='STRUCTURED_EVENT',
- notification_style='Pull'},
-
-%% Connect them:
-'CosEventDomainAdmin_EventDomain':add_connection(ED, C1),
- ]]></code>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosEventDomain/doc/src/ch_introduction.xml b/lib/cosEventDomain/doc/src/ch_introduction.xml
deleted file mode 100644
index f7a3426673..0000000000
--- a/lib/cosEventDomain/doc/src/ch_introduction.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2001</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Introduction to cosEventDomain</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2001-08-20</date>
- <rev></rev>
- <file>ch_introduction.xml</file>
- </header>
-
- <section>
- <title>Overview</title>
- <p>The cosEventDomain application is a Event Domain Service compliant with the <url href="http://www.omg.org">OMG</url>
- Service CosEventDomainAdmin.
- </p>
-
- <section>
- <title>Purpose and Dependencies</title>
- <p>CosEventDomain is dependent on <em>Orber</em>, which provides CORBA functionality in an Erlang environment.</p>
- </section>
-
- <section>
- <title>Prerequisites</title>
- <p>To fully understand the concepts presented in the
- documentation, it is recommended that the user is familiar
- with distributed programming and CORBA.
- </p>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosEventDomain/doc/src/cosEventDomainApp.xml b/lib/cosEventDomain/doc/src/cosEventDomainApp.xml
deleted file mode 100644
index c75ee05512..0000000000
--- a/lib/cosEventDomain/doc/src/cosEventDomainApp.xml
+++ /dev/null
@@ -1,150 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2001</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>cosEventDomainApp</title>
- <prepared>Niclas Eklund</prepared>
- <responsible>Niclas Eklund</responsible>
- <docno></docno>
- <approved>Niclas Eklund</approved>
- <checked></checked>
- <date>2001-08-20</date>
- <rev>PA1</rev>
- </header>
- <module>cosEventDomainApp</module>
- <modulesummary>The main module of the cosEventDomain application.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use:<br></br><c><![CDATA[-include_lib("cosEventDomain/include/*.hrl").]]></c></p>
- <p>This module contains the functions for starting and stopping the application.</p>
- </description>
- <funcs>
- <func>
- <name>install() -> Return</name>
- <fsummary>Install the cosEventDomain application</fsummary>
- <type>
- <v>Return = ok | {'EXCEPTION', E} | {'EXIT', R}</v>
- </type>
- <desc>
- <p>This operation installs the cosEventDomain application.</p>
- </desc>
- </func>
- <func>
- <name>uninstall() -> Return</name>
- <fsummary>Uninstall the cosEventDomain application</fsummary>
- <type>
- <v>Return = ok | {'EXCEPTION', E} | {'EXIT', R}</v>
- </type>
- <desc>
- <p>This operation uninstalls the cosEventDomain application.</p>
- </desc>
- </func>
- <func>
- <name>start() -> Return</name>
- <fsummary>Start the cosEventDomain application</fsummary>
- <type>
- <v>Return = ok | {error, Reason}</v>
- </type>
- <desc>
- <p>This operation starts the cosEventDomain application.</p>
- </desc>
- </func>
- <func>
- <name>stop() -> Return</name>
- <fsummary>Stop the cosEventDomain application</fsummary>
- <type>
- <v>Return = ok | {error, Reason}</v>
- </type>
- <desc>
- <p>This operation stops the cosEventDomain application.</p>
- </desc>
- </func>
- <func>
- <name>start_factory() -> Factory</name>
- <fsummary>Start a factory with default settings</fsummary>
- <type>
- <v>Factory = #objref</v>
- </type>
- <desc>
- <p>This operation creates a new instance of a
- <seealso marker="CosEventDomainAdmin_EventDomainFactory">Event Domain Factory</seealso>
- using the default settings.</p>
- </desc>
- </func>
- <func>
- <name>start_factory(Options) -> Factory</name>
- <fsummary>Start a factory with settings defined by the given options</fsummary>
- <type>
- <v>Options = [Option]</v>
- <v>Option = currently no options defined.</v>
- <v>Factory = #objref</v>
- </type>
- <desc>
- <p>This operation creates a new instance of a
- <seealso marker="CosEventDomainAdmin_EventDomainFactory">Event Domain Factory</seealso></p>
- </desc>
- </func>
- <func>
- <name>start_factory_link() -> Factory</name>
- <fsummary>Start a factory, which is linked to the invoking process, with default settings</fsummary>
- <type>
- <v>Factory = #objref</v>
- </type>
- <desc>
- <p>This operation creates a new instance of a
- <seealso marker="CosEventDomainAdmin_EventDomainFactory">Event Domain Factory</seealso>,
- which is linked to the invoking process, using the default settings.</p>
- </desc>
- </func>
- <func>
- <name>start_factory_link(Options) -> Factory</name>
- <fsummary>Start a factory, which is linked to the invoking process, with settings defined by the given options</fsummary>
- <type>
- <v>Options = [Option]</v>
- <v>Option = currently no options defined.</v>
- <v>Factory = #objref</v>
- </type>
- <desc>
- <p>This operation creates a new instance of a
- <seealso marker="CosEventDomainAdmin_EventDomainFactory">Event Domain Factory</seealso>,
- which is linked to the invoking process, with settings defined by the
- given options. Allowed options are the same as for
- <c><![CDATA[cosEventDomainApp:start_factory/1]]></c>.</p>
- </desc>
- </func>
- <func>
- <name>stop_factory(Factory) -> Reply</name>
- <fsummary>Terminate the target object</fsummary>
- <type>
- <v>Factory = #objref</v>
- <v>Reply = ok | {'EXCEPTION', E}</v>
- </type>
- <desc>
- <p>This operation stop the target factory.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosEventDomain/doc/src/notes.xml b/lib/cosEventDomain/doc/src/notes.xml
deleted file mode 100644
index bd0a119ad2..0000000000
--- a/lib/cosEventDomain/doc/src/notes.xml
+++ /dev/null
@@ -1,331 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2001</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosEventDomain Release Notes</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>2001-08-20</date>
- <rev>A</rev>
- <file>notes.xml</file>
- </header>
-
- <section><title>cosEventDomain 1.2.2</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> Removed all old unused files in the documentation.
- </p>
- <p>
- Own Id: OTP-14475 Aux Id: ERL-409, PR-1493 </p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosEventDomain 1.2.1</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Internal changes</p>
- <p>
- Own Id: OTP-13551</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosEventDomain 1.2</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> Remove the usage of erlang:now() from all Corba
- applications and use the new rand module instead of
- random. </p>
- <p>
- Own Id: OTP-12687</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosEventDomain 1.1.14</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> The default encoding of Erlang files has been changed
- from ISO-8859-1 to UTF-8. </p> <p> The encoding of XML
- files has also been changed to UTF-8. </p>
- <p>
- Own Id: OTP-10907</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosEventDomain 1.1.13</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Misc build updates</p>
- <p>
- Own Id: OTP-10784</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosEventDomain 1.1.12</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>Erlang/OTP can now be built using parallel make if you
- limit the number of jobs, for instance using '<c>make
- -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not
- work at the moment because of some missing
- dependencies.</p>
- <p>
- Own Id: OTP-9451</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section>
- <title>cosEventDomain 1.1.11</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- Removed superfluous usage of shy in the documentation since it can cause problem if
- a buggy tool is used.</p>
- <p>
- Own Id: OTP-9319 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosEventDomain 1.1.10</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- Eliminated Dialyzer warnings when using exit or throw.</p>
- <p>
- Own Id: OTP-9050 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosEventDomain 1.1.9</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- Test suites published.</p>
- <p>
- Own Id: OTP-8543 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosEventDomain 1.1.8</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>Removed superfluous VT in the documentation.</p>
- <p>Own id: OTP-8353 Aux Id:</p>
- </item>
- <item>
- <p>The documentation EIX file was not generated.</p>
- <p>Own id: OTP-8355 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosEventDomain 1.1.7</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- The documentation is now built with open source tools (xsltproc and fop)
- that exists on most platforms. One visible change is that the frames are removed.</p>
- <p>
- Own Id: OTP-8201 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosEventDomain 1.1.6</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Obsolete guards, e.g. record vs is_record, has been changed
- to avoid compiler warnings.</p>
- <p>Own id: OTP-7987</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosEventDomain 1.1.5</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Updated file headers.</p>
- <p>Own id: OTP-7837</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosEventDomain 1.1.4</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Documentation source included in open source releases.</p>
- <p>Own id: OTP-7595</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosEventDomain 1.1.3</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Updated file headers.</p>
- <p>Own id: OTP-7011</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosEventDomain 1.1.2</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>The documentation source has been converted from SGML to XML.</p>
- <p>Own id: OTP-6754</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosEventDomain 1.1.1</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Minor Makefile changes.</p>
- <p>Own id: OTP-6701</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosEventDomain 1.1</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>The stub/skeleton-files generated by IC have been improved,
- i.e., depending on the IDL-files, reduced the size of the
- erl- and beam-files and decreased dependencies off Orber's
- Interface Repository. It is necessary to re-compile all IDL-files
- and use COS-applications, including Orber, compiled with
- IC-4.2.</p>
- <p>Own id: OTP-4576</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosEventDomain 1.0</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>First release of the cosEventDomain application.</p>
- </item>
- </list>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosEventDomain/doc/src/part.xml b/lib/cosEventDomain/doc/src/part.xml
deleted file mode 100644
index 328fdfc20f..0000000000
--- a/lib/cosEventDomain/doc/src/part.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE part SYSTEM "part.dtd">
-
-<part xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>2001</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosEventDomain User's Guide</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2001-08-20</date>
- <rev>1.0</rev>
- </header>
- <description>
- <p>The <em>cosEventDomain</em> application is an Erlang implementation of a
- CORBA Service CosEventDomainAdmin.</p>
- </description>
- <xi:include href="ch_contents.xml"/>
- <xi:include href="ch_introduction.xml"/>
- <xi:include href="ch_QoS.xml"/>
- <xi:include href="ch_event_domain_service.xml"/>
-</part>
-
diff --git a/lib/cosEventDomain/doc/src/ref_man.xml b/lib/cosEventDomain/doc/src/ref_man.xml
deleted file mode 100644
index 14b826e4f9..0000000000
--- a/lib/cosEventDomain/doc/src/ref_man.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE application SYSTEM "application.dtd">
-
-<application xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>2001</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosEventDomain Reference Manual</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2001-08-20</date>
- <rev>1.0</rev>
- </header>
- <description>
- <p>The <em>cosEventDomain</em> application is an Erlang implementation of
- a CORBA Service CosEventDomainAdmin.</p>
- </description>
- <xi:include href="cosEventDomainApp.xml"/>
- <xi:include href="CosEventDomainAdmin.xml"/>
- <xi:include href="CosEventDomainAdmin_EventDomainFactory.xml"/>
- <xi:include href="CosEventDomainAdmin_EventDomain.xml"/>
-</application>
-
diff --git a/lib/cosEventDomain/ebin/.gitignore b/lib/cosEventDomain/ebin/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosEventDomain/ebin/.gitignore
+++ /dev/null
diff --git a/lib/cosEventDomain/example/.gitignore b/lib/cosEventDomain/example/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosEventDomain/example/.gitignore
+++ /dev/null
diff --git a/lib/cosEventDomain/include/.gitignore b/lib/cosEventDomain/include/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosEventDomain/include/.gitignore
+++ /dev/null
diff --git a/lib/cosEventDomain/info b/lib/cosEventDomain/info
deleted file mode 100644
index 46ecf9504d..0000000000
--- a/lib/cosEventDomain/info
+++ /dev/null
@@ -1,2 +0,0 @@
-group: orb
-short: Orber OMG Event Domain Service
diff --git a/lib/cosEventDomain/src/CosEventDomainAdmin.cfg b/lib/cosEventDomain/src/CosEventDomainAdmin.cfg
deleted file mode 100644
index 75a2720088..0000000000
--- a/lib/cosEventDomain/src/CosEventDomainAdmin.cfg
+++ /dev/null
@@ -1,4 +0,0 @@
-{this, "CosEventDomainAdmin::EventDomain"}.
-{{handle_info, "CosEventDomainAdmin::EventDomain"}, true}.
-{this, "CosEventDomainAdmin::EventDomainFactory"}.
-{{handle_info, "CosEventDomainAdmin::EventDomainFactory"}, true}.
diff --git a/lib/cosEventDomain/src/CosEventDomainAdmin.idl b/lib/cosEventDomain/src/CosEventDomainAdmin.idl
deleted file mode 100644
index 2ecd935c67..0000000000
--- a/lib/cosEventDomain/src/CosEventDomainAdmin.idl
+++ /dev/null
@@ -1,280 +0,0 @@
-#ifndef _COS_EVENT_DOMAIN_ADMIN_IDL_
-#define _COS_EVENT_DOMAIN_ADMIN_IDL_
-
-#pragma prefix "omg.org"
-
-// Event Domain Interface
-#include "CosNotification.idl"
-#include "CosEventComm.idl"
-#include "CosNotifyComm.idl"
-#include "CosNotifyChannelAdmin.idl"
-
-
-module CosEventDomainAdmin {
-
- // The following constant declarations define the Event Domain
- // QoS property names and the associated values each property can
- // take on. The name/value pairs for each Event Domain property
- // are grouped, beginning with a string constant defined for the
- // property name, followed by the values the property can take on.
-
- const string CycleDetection = "CycleDetection";
- const short AuthorizeCycles = 0; // Default value
- const short ForbidCycles = 1;
-
- const string DiamondDetection = "DiamondDetection";
- const short AuthorizeDiamonds = 0; // Default value
- const short ForbidDiamonds = 1;
-
-
- // The following enum declaration defines the types that a channel
- // can be of. It is used to specify channel types while externalizing
- // and instantiating topologies.
- enum ChannelType
- {
- CHANNEL,
- TYPED_CHANNEL,
- LOG_CHANNEL,
- TYPED_LOG_CHANNEL
- };
-
- enum NotificationStyle {
- Push,
- Pull
- };
-
- typedef long MemberID;
- typedef sequence <MemberID> MemberIDSeq;
- typedef long ConnectionID;
- typedef sequence <ConnectionID> ConnectionIDSeq;
-
- struct Connection {
- MemberID supplier_id;
- MemberID consumer_id;
- CosNotifyChannelAdmin::ClientType ctype;
- NotificationStyle notification_style;
- };
-
-
- typedef MemberIDSeq Route;
- typedef sequence<Route> RouteSeq;
-
- typedef Route Cycle;
- typedef sequence<Cycle> CycleSeq;
-
- typedef RouteSeq Diamond;
- typedef sequence<Diamond> DiamondSeq;
-
- exception CycleCreationForbidden
- {
- Cycle cyc;
- };
-
- exception DiamondCreationForbidden
- {
- Diamond diam;
- };
-
- // Forward declarations
- interface ConsumerAdmin;
- interface SupplierAdmin;
-
-
- typedef long DomainID;
- typedef sequence <DomainID> DomainIDSeq;
- typedef long ItemID;
-
-
- // EventDomain administrates EventChannels that reside in the same
- // administrative domain
- exception ConnectionNotFound {};
- exception AlreadyExists {};
-
-
- interface EventDomain :
- CosNotification::QoSAdmin ,
- CosNotification::AdminPropertiesAdmin {
-
- MemberID add_channel ( in CosNotifyChannelAdmin::EventChannel channel );
-
- MemberIDSeq get_all_channels ();
-
- CosNotifyChannelAdmin::EventChannel get_channel ( in MemberID channel )
- raises ( CosNotifyChannelAdmin::ChannelNotFound );
-
- void remove_channel ( in MemberID channel)
- raises (CosNotifyChannelAdmin::ChannelNotFound);
-
- ConnectionID add_connection ( in Connection connection)
- raises (CosNotifyChannelAdmin::ChannelNotFound,
- CosEventChannelAdmin::TypeError,
- AlreadyExists,
- CycleCreationForbidden,
- DiamondCreationForbidden);
-
- ConnectionIDSeq get_all_connections ();
-
- Connection get_connection ( in ConnectionID connection )
- raises ( ConnectionNotFound );
-
- void remove_connection ( in ConnectionID connection )
- raises ( ConnectionNotFound );
-
- CosNotifyChannelAdmin::ChannelIDSeq get_offer_channels ( in MemberID channel )
- raises ( CosNotifyChannelAdmin::ChannelNotFound );
-
- CosNotifyChannelAdmin::ChannelIDSeq get_subscription_channels ( in MemberID channel )
- raises ( CosNotifyChannelAdmin::ChannelNotFound );
-
- void destroy();
-
- // Cycle and diamond configurations listing
- CycleSeq get_cycles();
-
- DiamondSeq get_diamonds();
-
-
- // Connection of clients to the domain
- // - using no specific information
- // - for any clients
- void set_default_consumer_channel(in MemberID channel)
- raises (CosNotifyChannelAdmin::ChannelNotFound);
-
- void set_default_supplier_channel(in MemberID channel)
- raises (CosNotifyChannelAdmin::ChannelNotFound);
-
- CosNotifyChannelAdmin::ProxyPushSupplier
- connect_push_consumer(in CosEventComm::PushConsumer client)
- raises (CosNotifyChannelAdmin::ChannelNotFound);
-
- CosNotifyChannelAdmin::ProxyPullSupplier
- connect_pull_consumer(in CosEventComm::PullConsumer client)
- raises (CosNotifyChannelAdmin::ChannelNotFound);
-
- CosNotifyChannelAdmin::ProxyPushConsumer
- connect_push_supplier(in CosEventComm::PushSupplier client)
- raises (CosNotifyChannelAdmin::ChannelNotFound);
-
- CosNotifyChannelAdmin::ProxyPullConsumer
- connect_pull_supplier(in CosEventComm::PullSupplier client)
- raises (CosNotifyChannelAdmin::ChannelNotFound);
-
- // - for structured clients
- CosNotifyChannelAdmin::StructuredProxyPushSupplier
- connect_structured_push_consumer(in CosNotifyComm::StructuredPushConsumer client)
- raises (CosNotifyChannelAdmin::ChannelNotFound);
-
- CosNotifyChannelAdmin::StructuredProxyPullSupplier
- connect_structured_pull_consumer(in CosNotifyComm::StructuredPullConsumer client)
- raises (CosNotifyChannelAdmin::ChannelNotFound);
-
- CosNotifyChannelAdmin::StructuredProxyPushConsumer
- connect_structured_push_supplier(in CosNotifyComm::StructuredPushSupplier client)
- raises (CosNotifyChannelAdmin::ChannelNotFound);
-
- CosNotifyChannelAdmin::StructuredProxyPullConsumer
- connect_structured_pull_supplier(in CosNotifyComm::StructuredPullSupplier client)
- raises (CosNotifyChannelAdmin::ChannelNotFound);
-
- // - for sequence clients
- CosNotifyChannelAdmin::SequenceProxyPushSupplier
- connect_sequence_push_consumer(in CosNotifyComm::SequencePushConsumer client)
- raises (CosNotifyChannelAdmin::ChannelNotFound);
-
- CosNotifyChannelAdmin::SequenceProxyPullSupplier
- connect_sequence_pull_consumer(in CosNotifyComm::SequencePullConsumer client)
- raises (CosNotifyChannelAdmin::ChannelNotFound);
-
- CosNotifyChannelAdmin::SequenceProxyPushConsumer
- connect_sequence_push_supplier(in CosNotifyComm::SequencePushSupplier client)
- raises (CosNotifyChannelAdmin::ChannelNotFound);
-
- CosNotifyChannelAdmin::SequenceProxyPullConsumer
- connect_sequence_pull_supplier(in CosNotifyComm::SequencePullSupplier client)
- raises (CosNotifyChannelAdmin::ChannelNotFound);
-
- // - using a channel id
- // - for any clients
- CosNotifyChannelAdmin::ProxyPushSupplier
- connect_push_consumer_with_id(in CosEventComm::PushConsumer client,
- in MemberID channel)
- raises (CosNotifyChannelAdmin::ChannelNotFound);
-
- CosNotifyChannelAdmin::ProxyPullSupplier
- connect_pull_consumer_with_id(in CosEventComm::PullConsumer client,
- in MemberID channel)
- raises (CosNotifyChannelAdmin::ChannelNotFound);
-
- CosNotifyChannelAdmin::ProxyPushConsumer
- connect_push_supplier_with_id(in CosEventComm::PushSupplier client,
- in MemberID channel)
- raises (CosNotifyChannelAdmin::ChannelNotFound);
-
- CosNotifyChannelAdmin::ProxyPullConsumer
- connect_pull_supplier_with_id(in CosEventComm::PullSupplier client,
- in MemberID channel)
- raises (CosNotifyChannelAdmin::ChannelNotFound);
-
- // - for structured clients
- CosNotifyChannelAdmin::StructuredProxyPushSupplier
- connect_structured_push_consumer_with_id(in CosNotifyComm::StructuredPushConsumer client,
- in MemberID channel)
- raises (CosNotifyChannelAdmin::ChannelNotFound);
-
- CosNotifyChannelAdmin::StructuredProxyPullSupplier
- connect_structured_pull_consumer_with_id(in CosNotifyComm::StructuredPullConsumer client,
- in MemberID channel)
- raises (CosNotifyChannelAdmin::ChannelNotFound);
-
- CosNotifyChannelAdmin::StructuredProxyPushConsumer
- connect_structured_push_supplier_with_id(in CosNotifyComm::StructuredPushSupplier client,
- in MemberID channel)
- raises (CosNotifyChannelAdmin::ChannelNotFound);
-
- CosNotifyChannelAdmin::StructuredProxyPullConsumer
- connect_structured_pull_supplier_with_id(in CosNotifyComm::StructuredPullSupplier client,
- in MemberID channel)
- raises (CosNotifyChannelAdmin::ChannelNotFound);
-
- // - for sequence clients
- CosNotifyChannelAdmin::SequenceProxyPushSupplier
- connect_sequence_push_consumer_with_id(in CosNotifyComm::SequencePushConsumer client,
- in MemberID channel)
- raises (CosNotifyChannelAdmin::ChannelNotFound);
-
- CosNotifyChannelAdmin::SequenceProxyPullSupplier
- connect_sequence_pull_consumer_with_id(in CosNotifyComm::SequencePullConsumer client,
- in MemberID channel)
- raises (CosNotifyChannelAdmin::ChannelNotFound);
-
- CosNotifyChannelAdmin::SequenceProxyPushConsumer
- connect_sequence_push_supplier_with_id(in CosNotifyComm::SequencePushSupplier client,
- in MemberID channel)
- raises (CosNotifyChannelAdmin::ChannelNotFound);
-
- CosNotifyChannelAdmin::SequenceProxyPullConsumer
- connect_sequence_pull_supplier_with_id(in CosNotifyComm::SequencePullSupplier client,
- in MemberID channel)
- raises (CosNotifyChannelAdmin::ChannelNotFound);
- };
-
- exception DomainNotFound {};
-
- interface EventDomainFactory {
-
- EventDomain create_event_domain( in CosNotification::QoSProperties initialQoS ,
- in CosNotification::AdminProperties initialAdmin,
- out DomainID id )
- raises ( CosNotification::UnsupportedQoS,
- CosNotification::UnsupportedAdmin );
-
- DomainIDSeq get_all_domains ();
-
- EventDomain get_event_domain (
- in DomainID id )
- raises ( DomainNotFound );
- };
-};
-
-#endif // _COS_EVENT_DOMAIN_ADMIN_IDL_
-
diff --git a/lib/cosEventDomain/src/CosEventDomainAdmin_EventDomainFactory_impl.erl b/lib/cosEventDomain/src/CosEventDomainAdmin_EventDomainFactory_impl.erl
deleted file mode 100644
index 75ff81196c..0000000000
--- a/lib/cosEventDomain/src/CosEventDomainAdmin_EventDomainFactory_impl.erl
+++ /dev/null
@@ -1,183 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : CosEventDomainAdmin_EventDomainFactory_impl.erl
-%% Description :
-%%
-%%----------------------------------------------------------------------
--module('CosEventDomainAdmin_EventDomainFactory_impl').
-
-%%----------------------------------------------------------------------
-%% Include files
-%%----------------------------------------------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
--include_lib("cosNotification/include/CosNotification.hrl").
-
--include("CosEventDomainAdmin.hrl").
--include("cosEventDomainApp.hrl").
-
-%%----------------------------------------------------------------------
-%% External exports
-%%----------------------------------------------------------------------
--export([init/1,
- terminate/2,
- code_change/3,
- handle_info/2]).
-
--export([create_event_domain/4,
- get_all_domains/2,
- get_event_domain/3]).
-
-%%----------------------------------------------------------------------
-%% Internal exports
-%%----------------------------------------------------------------------
--export([]).
-
-%%----------------------------------------------------------------------
-%% Records
-%%----------------------------------------------------------------------
--record(state, {current_id = -1, domains = []}).
-
-%%----------------------------------------------------------------------
-%% Macros
-%%----------------------------------------------------------------------
-
-%%======================================================================
-%% External functions
-%%======================================================================
-%%----------------------------------------------------------------------
-%% Function : init/1
-%% Returns : {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
-%% Description: Initiates the server
-%%----------------------------------------------------------------------
-init([]) ->
- process_flag(trap_exit, true),
- {ok, #state{}}.
-
-%%----------------------------------------------------------------------
-%% Function : terminate/2
-%% Returns : any (ignored by gen_server)
-%% Description: Shutdown the server
-%%----------------------------------------------------------------------
-terminate(_Reason, _State) ->
- ok.
-
-%%----------------------------------------------------------------------
-%% Function : code_change/3
-%% Returns : {ok, NewState}
-%% Description: Convert process state when code is changed
-%%----------------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%----------------------------------------------------------------------
-%% Function : handle_info/2
-%% Returns : {noreply, State} |
-%% {stop, Reason, State}
-%% Description: Handle, for example, exit signals.
-%%----------------------------------------------------------------------
-handle_info({'EXIT', Pid, _Reason}, State) ->
- {noreply, State#state{domains=delete_domain(State#state.domains, Pid, [])}};
-handle_info(_Info, State) ->
- {noreply, State}.
-
-
-%%----------------------------------------------------------------------
-%% Function : create_event_domain
-%% Arguments : InitialQoS - CosNotification::QoSProperties
-%% InitialAdmin - CosNotification::AdminProperties
-%% Returns : CosEventDomainAdmin::EventDomain |
-%% {'EXCEPTION', #'CosNotification_UnsupportedQoS'{}} |
-%% {'EXCEPTION', #'CosNotification_UnsupportedAdmin'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-create_event_domain(_OE_This, State, InitialQoS, InitialAdmin) ->
- Id = cosEventDomainApp:create_id(State#state.current_id),
- Admin = cosEventDomainApp:get_admin(InitialAdmin),
- QoS = cosEventDomainApp:get_qos(InitialQoS),
- case catch 'CosEventDomainAdmin_EventDomain':oe_create_link([self(), Id,
- QoS, Admin],
- [{sup_child, true}]) of
- {ok, Pid, ED} ->
- {reply, {ED, Id}, State#state{current_id = Id,
- domains = [{Id, ED, Pid}|State#state.domains]}};
- What ->
- orber:dbg("[~p] CosEventDomainAdmin_EventDomainFactory:"
- "create_event_domain();~n"
- "Failed creatin a new EventDomain due to: ~p",
- [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-%%----------------------------------------------------------------------
-%% Function : get_all_domains
-%% Arguments : -
-%% Returns : CosEventDomainAdmin::DomainIDSeq - [long()]
-%% Description:
-%%----------------------------------------------------------------------
-get_all_domains(_OE_This, State) ->
- {reply, get_all_domains_helper(State#state.domains, []), State}.
-
-get_all_domains_helper([], Acc) ->
- Acc;
-get_all_domains_helper([{Id, _, _}|T], Acc) ->
- get_all_domains_helper(T, [Id|Acc]).
-
-
-%%----------------------------------------------------------------------
-%% Function : get_event_domain
-%% Arguments : CosEventDomainAdmin::DomainID - long()
-%% Returns : CosEventDomainAdmin::EventDomain |
-%% {'EXCEPTION', #'CosEventDomainAdmin_DomainNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-get_event_domain(_OE_This, State, DomainID) ->
- {reply, get_event_domain_helper(State#state.domains, DomainID), State}.
-
-get_event_domain_helper([], _) ->
- corba:raise(#'CosEventDomainAdmin_DomainNotFound'{});
-get_event_domain_helper([{Id, ED, _}|_], Id) ->
- ED;
-get_event_domain_helper([_|T], Id) ->
- get_event_domain_helper(T, Id).
-
-%%======================================================================
-%% Internal functions
-%%======================================================================
-delete_domain([], _, Acc) ->
- %% The domain didn't exist.
- Acc;
-delete_domain([{_Id, _, Pid}], Pid, Acc) ->
- Acc;
-delete_domain([{_Id, _, Pid}|T], Pid, Acc) ->
- T++Acc;
-delete_domain([H|T], Pid, Acc) ->
- delete_domain(T, Pid, [H|Acc]).
-
-%%======================================================================
-%% END OF MODULE
-%%======================================================================
-
diff --git a/lib/cosEventDomain/src/CosEventDomainAdmin_EventDomain_impl.erl b/lib/cosEventDomain/src/CosEventDomainAdmin_EventDomain_impl.erl
deleted file mode 100644
index a31a70acc2..0000000000
--- a/lib/cosEventDomain/src/CosEventDomainAdmin_EventDomain_impl.erl
+++ /dev/null
@@ -1,1426 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : CosEventDomainAdmin_EventDomain_impl.erl
-%% Description :
-%%
-%%----------------------------------------------------------------------
--module('CosEventDomainAdmin_EventDomain_impl').
-
-%%----------------------------------------------------------------------
-%% Include files
-%%----------------------------------------------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
--include_lib("cosNotification/include/CosNotifyChannelAdmin.hrl").
--include_lib("cosNotification/include/CosNotification.hrl").
-
--include("cosEventDomainApp.hrl").
--include("CosEventDomainAdmin.hrl").
-
-%%----------------------------------------------------------------------
-%% External exports
-%%----------------------------------------------------------------------
--export([init/1,
- terminate/2,
- code_change/3,
- handle_info/2]).
-
-%%------------------ CosEventDomainAdmin::EventDomain ------------------
--export([add_channel/3,
- get_all_channels/2,
- get_channel/3,
- remove_channel/3,
- add_connection/3,
- get_all_connections/2,
- get_connection/3,
- remove_connection/3,
- get_offer_channels/3,
- get_subscription_channels/3,
- destroy/2,
- get_cycles/2,
- get_diamonds/2,
- set_default_consumer_channel/3,
- set_default_supplier_channel/3,
- connect_push_consumer/3,
- connect_pull_consumer/3,
- connect_push_supplier/3,
- connect_pull_supplier/3,
- connect_structured_push_consumer/3,
- connect_structured_pull_consumer/3,
- connect_structured_push_supplier/3,
- connect_structured_pull_supplier/3,
- connect_sequence_push_consumer/3,
- connect_sequence_pull_consumer/3,
- connect_sequence_push_supplier/3,
- connect_sequence_pull_supplier/3,
- connect_push_consumer_with_id/4,
- connect_pull_consumer_with_id/4,
- connect_push_supplier_with_id/4,
- connect_pull_supplier_with_id/4,
- connect_structured_push_consumer_with_id/4,
- connect_structured_pull_consumer_with_id/4,
- connect_structured_push_supplier_with_id/4,
- connect_structured_pull_supplier_with_id/4,
- connect_sequence_push_consumer_with_id/4,
- connect_sequence_pull_consumer_with_id/4,
- connect_sequence_push_supplier_with_id/4,
- connect_sequence_pull_supplier_with_id/4]).
-
-%%------------------ CosNotification::QoSAdmin -------------------------
--export([get_qos/2,
- set_qos/3,
- validate_qos/3]).
-
-%%------------------ CosNotification::AdminPropertiesAdmin -------------
--export([get_admin/2,
- set_admin/3]).
-
-
-
-%%----------------------------------------------------------------------
-%% Internal exports
-%%----------------------------------------------------------------------
--export([]).
-
-%%----------------------------------------------------------------------
-%% Records
-%%----------------------------------------------------------------------
--record(state, {parent_pid, id, graph, ch_counter=-1,
- co_counter=-1, def_supplier, def_consumer, diamonds, cyclic}).
-
--record(connection, {supplier, consumer, data}).
-
-%%----------------------------------------------------------------------
-%% Macros
-%%----------------------------------------------------------------------
-
-%%======================================================================
-%% External functions
-%%======================================================================
-%%----------------------------------------------------------------------
-%% Function : init/1
-%% Returns : {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
-%% Description: Initiates the server
-%%----------------------------------------------------------------------
-init([ParentPid, MyId, QoS, _Admin]) ->
- process_flag(trap_exit, true),
- Diamonds = case lists:keysearch(?DiamondDetection, 1, QoS) of
- false ->
- ?ForbidDiamonds;
- {value, {_, Value}} ->
- Value
- end,
- case lists:keysearch(?CycleDetection, 1, QoS) of
- {value, {_, ?AuthorizeCycles}} ->
- {ok, #state{parent_pid = ParentPid, id = MyId,
- graph = digraph:new([private]),
- diamonds = Diamonds, cyclic = ?AuthorizeCycles}};
- _ ->
- {ok, #state{parent_pid = ParentPid, id = MyId,
- graph = digraph:new([acyclic, private]),
- diamonds = Diamonds, cyclic = ?ForbidCycles}}
- end.
-
-%%----------------------------------------------------------------------
-%% Function : terminate/2
-%% Returns : any (ignored by gen_server)
-%% Description: Shutdown the server
-%%----------------------------------------------------------------------
-terminate(_Reason, #state{graph = DG} = _State) ->
- Connections = digraph:edges(DG),
- close_connections(DG, Connections),
- digraph:delete(DG),
- ok.
-
-%%----------------------------------------------------------------------
-%% Function : code_change/3
-%% Returns : {ok, NewState}
-%% Description: Convert process state when code is changed
-%%----------------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%----------------------------------------------------------------------
-%% Function : handle_info/2
-%% Returns : {noreply, State} |
-%% {stop, Reason, State}
-%% Description: Handle, for example, exit signals.
-%%----------------------------------------------------------------------
-handle_info({'EXIT', Pid, Reason}, #state{parent_pid = Pid} = State) ->
- {stop, Reason, State};
-handle_info(_Info, State) ->
- {noreply, State}.
-
-%%----------------------------------------------------------------------
-%%------------------ CosEventDomainAdmin::EventDomain ------------------
-%%---------------------------------------------------------------------%
-%% Function : add_channel
-%% Arguments : Channel - CosNotifyChannelAdmin::EventChannel
-%% Returns : MemberId - long()
-%% Description:
-%%----------------------------------------------------------------------
-add_channel(_OE_This, #state{ch_counter=C, graph = DG} = State, Channel) ->
- type_check(Channel, 'CosNotifyChannelAdmin_EventChannel'),
- Id = cosEventDomainApp:create_id(C),
- digraph:add_vertex(DG, Id, Channel),
- {reply, Id, State#state{ch_counter=Id}}.
-
-%%---------------------------------------------------------------------%
-%% Function : get_all_channels
-%% Arguments : -
-%% Returns : CosEventDomainAdmin::MemberIDSeq ([long()])
-%% Description:
-%%----------------------------------------------------------------------
-get_all_channels(_OE_This, #state{graph = DG} = State) ->
- {reply, digraph:vertices(DG), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : get_channel
-%% Arguments : Id - CosEventDomainAdmin::MemberID (long())
-%% Returns : CosNotifyChannelAdmin::EventChannel |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}
-%% Description:
-%%----------------------------------------------------------------------
-get_channel(_OE_This, #state{graph = DG} = State, Id) ->
- {reply, lookup_channel(DG, Id), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : remove_channel
-%% Arguments : Id - CosEventDomainAdmin::MemberID (long())
-%% Returns : ok |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}
-%% Description:
-%%----------------------------------------------------------------------
-remove_channel(_OE_This, #state{graph = DG} = State, Id) ->
- lookup_channel(DG, Id),
- close_connections(DG, digraph:edges(DG, Id)),
- digraph:del_vertex(DG, Id),
- {reply, ok, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : add_connection
-%% Arguments : Connection - CosEventDomainAdmin::Connection
-%% Returns : ConnectionID |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_TypeError'{}} |
-%% {'EXCEPTION', #'CosEventDomainAdmin_AlreadyExists'{}} |
-%% {'EXCEPTION', #'CosEventDomainAdmin_CycleCreationForbidden'{cyc}} |
-%% {'EXCEPTION', #'CosEventDomainAdmin_DiamondCreationForbidden'{diam}}
-%% Description:
-%%----------------------------------------------------------------------
-add_connection(_OE_This, #state{graph = DG, co_counter = C} = State,
- Connection) when is_record(Connection,
- 'CosEventDomainAdmin_Connection') ->
- SId = Connection#'CosEventDomainAdmin_Connection'.supplier_id,
- SChannel = lookup_channel(DG, SId),
- CId = Connection#'CosEventDomainAdmin_Connection'.consumer_id,
- CChannel = lookup_channel(DG, CId),
- case lists:member(CId, digraph:out_neighbours(DG, SId)) of
- false ->
- Id = cosEventDomainApp:create_id(C),
- %% Try to insert the new connection before we actually setup a connection.
- %% Note that #connection is NOT complete, hence, we must update it later.
- case digraph:add_edge(DG, Id, SId, CId, #connection{data=Connection}) of
- {error, {bad_edge, Path}} ->
- corba:raise(#'CosEventDomainAdmin_CycleCreationForbidden'{cyc=Path});
- Id when State#state.diamonds == ?AuthorizeDiamonds ->
- case catch setup_connection(Connection, SChannel, CChannel) of
- {ok, SProxy, CProxy} ->
- %% Now we can update the connection with complete data.
- digraph:add_edge(DG, Id, SId, CId, #connection{supplier=SProxy,
- consumer=CProxy,
- data=Connection}),
- {reply, Id, State#state{co_counter = Id}};
- {'EXCEPTION', E} ->
- digraph:del_edge(DG, Id),
- corba:raise(E);
- What ->
- digraph:del_edge(DG, Id),
- orber:dbg("[~p] CosEventDomainAdmin_EventDomain:"
- "add_connection(~p);~nFailed setting up"
- " connection due to: ~p",
- [?LINE, Connection, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_MAYBE})
- end;
- Id ->
- case get_diamonds_helper(State, false, SId) of
- [] ->
- case catch setup_connection(Connection, SChannel, CChannel) of
- {ok, SProxy, CProxy} ->
- %% Now we can update the connection with complete data.
- digraph:add_edge(DG, Id, SId, CId, #connection{supplier=SProxy,
- consumer=CProxy,
- data=Connection}),
- {reply, Id, State#state{co_counter = Id}};
- {'EXCEPTION', E} ->
- digraph:del_edge(DG, Id),
- corba:raise(E);
- What ->
- digraph:del_edge(DG, Id),
- orber:dbg("[~p] CosEventDomainAdmin_EventDomain:"
- "add_connection(~p);~nFailed setting"
- " up connection due to: ~p",
- [?LINE, Connection, What],
- ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_MAYBE})
- end;
- Diamond ->
- %% Since no diamonds should exist the returned list can
- %% only describe the diamond we just created.
- digraph:del_edge(DG, Id),
- corba:raise(#'CosEventDomainAdmin_DiamondCreationForbidden'
- {diam=Diamond})
- end
- end;
- true ->
- corba:raise(#'CosEventDomainAdmin_AlreadyExists'{})
- end.
-
-
-%%---------------------------------------------------------------------%
-%% Function : get_all_connections
-%% Arguments : -
-%% Returns : CosEventDomainAdmin::ConnectionIDSeq - [long()]
-%% Description:
-%%----------------------------------------------------------------------
-get_all_connections(_OE_This, #state{graph = DG} = State) ->
- {reply, digraph:edges(DG), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : get_connection
-%% Arguments : Id - CosEventDomainAdmin::ConnectionID (long())
-%% Returns : CosEventDomainAdmin::Connection |
-%% {'EXCEPTION', #'CosEventDomainAdmin_ConnectionNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-get_connection(_OE_This, #state{graph = DG} = State, Id) ->
- {reply, lookup_connection_data(DG, Id), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : remove_connection
-%% Arguments : Id - CosEventDomainAdmin::ConnectionID (long())
-%% Returns : ok |
-%% {'EXCEPTION', #'CosEventDomainAdmin_ConnectionNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-remove_connection(_OE_This, #state{graph = DG} = State, Id) ->
- #connection{supplier=S, consumer=C, data=Connection} =
- lookup_connection(DG, Id),
- close_connection(Connection, S, C),
- digraph:del_edge(DG, Id),
- {reply, ok, State}.
-
-
-%%---------------------------------------------------------------------%
-%% Function : get_offer_channels
-%% Arguments : Id - CosEventDomainAdmin::MemberID (long())
-%% Returns : CosNotifyChannelAdmin::ChannelIDSeq |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-get_offer_channels(_OE_This, #state{graph = DG, cyclic = Cyclic} = State, Id) ->
- lookup_channel(DG, Id),
- case digraph:vertex(DG, Id) of
- {Id, _Channel} when Cyclic == ?ForbidCycles ->
- {reply, digraph_utils:reaching_neighbours([Id], DG), State};
- {Id, _Channel} ->
- %% If cyclic graphs is allowed 'Id' will appear in the returned list.
- %% Hence, we must delete it.
- {reply,lists:delete(Id, digraph_utils:reaching_neighbours([Id], DG)),
- State};
- false ->
- corba:raise(#'CosNotifyChannelAdmin_ChannelNotFound'{})
- end.
-
-%%---------------------------------------------------------------------%
-%% Function : get_subscription_channels
-%% Arguments : Id - CosEventDomainAdmin::MemberID (long())
-%% Returns : CosNotifyChannelAdmin::ChannelIDSeq |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-get_subscription_channels(_OE_This, #state{graph = DG, cyclic = Cyclic} = State, Id) ->
- lookup_channel(DG, Id),
- case digraph:vertex(DG, Id) of
- {Id, _Channel} when Cyclic == ?ForbidCycles ->
- {reply, digraph_utils:reachable_neighbours([Id], DG), State};
- {Id, _Channel} ->
- %% If cyclic graphs is allowed 'Id' will appear in the returned list.
- %% Hence, we must delete it.
- {reply, lists:delete(Id, digraph_utils:reachable_neighbours([Id], DG)),
- State};
- false ->
- corba:raise(#'CosNotifyChannelAdmin_ChannelNotFound'{})
- end.
-
-%%---------------------------------------------------------------------%
-%% Function : destroy
-%% Arguments : -
-%% Returns : ok
-%% Description:
-%%----------------------------------------------------------------------
-destroy(_OE_This, #state{graph = _DG} = State) ->
- {stop, normal, ok, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : get_cycles
-%% Arguments : -
-%% Returns : CosEventDomainAdmin::CycleSeq
-%% Description:
-%%----------------------------------------------------------------------
-get_cycles(_OE_This, #state{cyclic = ?ForbidCycles} = State) ->
- {reply, [], State};
-get_cycles(_OE_This, #state{graph = DG} = State) ->
- {reply, digraph_utils:cyclic_strong_components(DG), State}.
-
-%%----------------------------------------------------------------------
-%% Function : get_diamonds
-%% Arguments : -
-%% Returns : CosEventDomainAdmin::DiamondSeq
-%% Description:
-%%----------------------------------------------------------------------
-get_diamonds(_OE_This, #state{diamonds = ?ForbidDiamonds} = State) ->
- {reply, [], State};
-get_diamonds(_OE_This, State) ->
- {reply, get_diamonds_helper(State, true), State}.
-
-get_diamonds_helper(#state{graph = DG} = _State, FindAll) ->
- case find_candidates(DG) of
- {[], _, _} ->
- [];
- {_, [], _} ->
- [];
- {COut, CIn, Max} ->
- %% In this case we cannot tell if a diamond exists. Got to
- %% check the paths between the candidates.
- evaluate_candidates(DG, COut, CIn, [], Max, FindAll)
- end.
-
-get_diamonds_helper(#state{graph = DG} = _State, FindAll, Vertex) ->
- case find_candidates(DG, Vertex) of
- {[], _, _} ->
- [];
- {_, [], _} ->
- [];
- {COut, CIn, Max} ->
- %% In this case we cannot tell if a diamond exists. Got to
- %% check the paths between the candidates.
- evaluate_candidates(DG, COut, CIn, [], Max, FindAll)
- end.
-
-%%---------------------------------------------------------------------%
-%% Function : set_default_consumer_channel
-%% Arguments : Id - CosEventDomainAdmin::MemberID (long())
-%% Returns : ok |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-set_default_consumer_channel(_OE_This, #state{graph = DG} = State, Id) ->
- lookup_channel(DG, Id),
- {reply, ok, State#state{def_consumer=Id}}.
-
-%%---------------------------------------------------------------------%
-%% Function : set_default_supplier_channel
-%% Arguments : Id - CosEventDomainAdmin::MemberID (long())
-%% Returns : ok |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-set_default_supplier_channel(_OE_This, #state{graph = DG} = State, Id) ->
- lookup_channel(DG, Id),
- {reply, ok, State#state{def_supplier=Id}}.
-
-%%---------------------------------------------------------------------%
-%% Function : connect_push_consumer
-%% Arguments : PC - CosEventComm::PushConsumer
-%% Returns : CosNotifyChannelAdmin::ProxyPushSupplier |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-connect_push_consumer(_OE_This, #state{def_supplier = Ch} = State, PC) ->
- type_check(PC, 'CosEventComm_PushConsumer'),
- Proxy = connect_a_push_consumer(Ch, PC, 'ANY_EVENT'),
- {reply, Proxy, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : connect_pull_consumer
-%% Arguments : PC - CosEventComm::PullConsumer
-%% Returns : CosNotifyChannelAdmin::ProxyPullSupplier |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-connect_pull_consumer(_OE_This, #state{def_consumer = Ch} = State, PC) ->
- Proxy = connect_a_pull_consumer(Ch, PC, 'ANY_EVENT'),
- {reply, Proxy, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : connect_push_supplier
-%% Arguments : PS - CosEventComm::PushSupplier
-%% Returns : CosNotifyChannelAdmin::ProxyPushConsumer |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-connect_push_supplier(_OE_This, #state{def_supplier = Ch} = State, PS) ->
- Proxy = connect_a_push_supplier(Ch, PS, 'ANY_EVENT'),
- {reply, Proxy, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : connect_pull_supplier
-%% Arguments : PS - CosEventComm::PullSupplier
-%% Returns : CosNotifyChannelAdmin::ProxyPullConsumer
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-connect_pull_supplier(_OE_This, #state{def_consumer = Ch} = State, PS) ->
- type_check(PS, 'CosEventComm_PullSupplier'),
- Proxy = connect_a_pull_supplier(Ch, PS, 'ANY_EVENT'),
- {reply, Proxy, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : connect_structured_push_consumer
-%% Arguments : PC - CosNotifyComm::StructuredPushConsumer
-%% Returns : CosNotifyChannelAdmin::StructuredProxyPushSupplier |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-connect_structured_push_consumer(_OE_This, #state{def_supplier = Ch} = State, PC) ->
- type_check(PC, 'CosNotifyComm_StructuredPushConsumer'),
- Proxy = connect_a_push_consumer(Ch, PC, 'STRUCTURED_EVENT'),
- {reply, Proxy, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : connect_structured_pull_consumer
-%% Arguments : PC - CosNotifyComm::StructuredPullConsumer
-%% Returns : CosNotifyChannelAdmin::StructuredProxyPullSupplier |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-connect_structured_pull_consumer(_OE_This, #state{def_supplier = Ch} = State, PC) ->
- Proxy = connect_a_pull_consumer(Ch, PC, 'STRUCTURED_EVENT'),
- {reply, Proxy, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : connect_structured_push_supplier
-%% Arguments : PS - CosNotifyComm::StructuredPushSupplier
-%% Returns : CosNotifyChannelAdmin::StructuredProxyPushConsumer |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-connect_structured_push_supplier(_OE_This, #state{def_consumer = Ch} = State, PS) ->
- Proxy = connect_a_push_supplier(Ch, PS, 'STRUCTURED_EVENT'),
- {reply, Proxy, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : connect_structured_pull_supplier
-%% Arguments : PS - CosNotifyComm::StructuredPullSupplier
-%% Returns : CosNotifyChannelAdmin::StructuredProxyPullConsumer |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-connect_structured_pull_supplier(_OE_This, #state{def_consumer = Ch} = State, PS) ->
- type_check(PS, 'CosNotifyComm_StructuredPullSupplier'),
- Proxy = connect_a_pull_supplier(Ch, PS, 'STRUCTURED_EVENT'),
- {reply, Proxy, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : connect_sequence_push_consumer
-%% Arguments : PC - CosNotifyComm::SequencePushConsumer
-%% Returns : CosNotifyChannelAdmin::SequenceProxyPushSupplier |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-connect_sequence_push_consumer(_OE_This, #state{def_supplier = Ch} = State, PC) ->
- type_check(PC, 'CosNotifyComm_SequencePushConsumer'),
- Proxy = connect_a_push_consumer(Ch, PC, 'SEQUENCE_EVENT'),
- {reply, Proxy, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : connect_sequence_pull_consumer
-%% Arguments : PC - CosNotifyComm::SequencePullConsumer
-%% Returns : CosNotifyChannelAdmin::SequenceProxyPullSupplier |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-connect_sequence_pull_consumer(_OE_This, #state{def_supplier = Ch} = State, PC) ->
- Proxy = connect_a_pull_consumer(Ch, PC, 'SEQUENCE_EVENT'),
- {reply, Proxy, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : connect_sequence_push_supplier
-%% Arguments : PS - CosNotifyComm::SequencePushSupplier
-%% Returns : CosNotifyChannelAdmin::SequenceProxyPushConsumer |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-connect_sequence_push_supplier(_OE_This, #state{def_consumer = Ch} = State, PS) ->
- Proxy = connect_a_push_supplier(Ch, PS, 'SEQUENCE_EVENT'),
- {reply, Proxy, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : connect_sequence_pull_supplier
-%% Arguments : PS - CosNotifyComm::SequencePullSupplier
-%% Returns : CosNotifyChannelAdmin::SequenceProxyPullConsumer |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-connect_sequence_pull_supplier(_OE_This, #state{def_consumer = Ch} = State, PS) ->
- type_check(PS, 'CosNotifyComm_SequencePullSupplier'),
- Proxy = connect_a_pull_supplier(Ch, PS, 'SEQUENCE_EVENT'),
- {reply, Proxy, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : connect_push_consumer_with_id
-%% Arguments : PC - CosEventComm::PushConsumer
-%% Id - CosEventDomainAdmin::MemberID (long())
-%% Returns : CosNotifyChannelAdmin::ProxyPushSupplier |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-connect_push_consumer_with_id(_OE_This, #state{graph = DG} = State, PC, Id) ->
- type_check(PC, 'CosEventComm_PushConsumer'),
- Channel = lookup_channel(DG, Id),
- Proxy = connect_a_push_consumer(Channel, PC, 'ANY_EVENT'),
- {reply, Proxy, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : connect_pull_consumer_with_id
-%% Arguments : PC - CosEventComm::PullConsumer
-%% Id - CosEventDomainAdmin::MemberID (long())
-%% Returns : CosNotifyChannelAdmin::ProxyPullSupplier |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-connect_pull_consumer_with_id(_OE_This, #state{graph = DG} = State, PC, Id) ->
- Channel = lookup_channel(DG, Id),
- Proxy = connect_a_pull_consumer(Channel, PC, 'ANY_EVENT'),
- {reply, Proxy, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : connect_push_supplier_with_id
-%% Arguments : PS - CosEventComm::PushSupplier
-%% Id - CosEventDomainAdmin::MemberID (long())
-%% Returns : CosNotifyChannelAdmin::ProxyPushConsumer |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-connect_push_supplier_with_id(_OE_This, #state{graph = DG} = State, PS, Id) ->
- Channel = lookup_channel(DG, Id),
- Proxy = connect_a_push_supplier(Channel, PS, 'ANY_EVENT'),
- {reply, Proxy, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : connect_pull_supplier_with_id
-%% Arguments : PS - CosEventComm::PullSupplier
-%% Id - CosEventDomainAdmin::MemberID (long())
-%% Returns : CosNotifyChannelAdmin::ProxyPullConsumer |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-connect_pull_supplier_with_id(_OE_This, #state{graph = DG} = State, PS, Id) ->
- type_check(PS, 'CosEventComm_PullSupplier'),
- Channel = lookup_channel(DG, Id),
- Proxy = connect_a_pull_supplier(Channel, PS, 'ANY_EVENT'),
- {reply, Proxy, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : connect_structured_push_consumer_with_id
-%% Arguments : PC - CosNotifyComm::StructuredPushConsumer
-%% Id - CosEventDomainAdmin::MemberID (long())
-%% Returns : CosNotifyChannelAdmin::StructuredProxyPushSupplier |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-connect_structured_push_consumer_with_id(_OE_This, #state{graph = DG} = State, PC, Id) ->
- type_check(PC, 'CosNotifyComm_StructuredPushConsumer'),
- Channel = lookup_channel(DG, Id),
- Proxy = connect_a_push_consumer(Channel, PC, 'STRUCTURED_EVENT'),
- {reply, Proxy, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : connect_structured_pull_consumer_with_id
-%% Arguments : PC - CosNotifyComm::StructuredPullConsumer
-%% Id - CosEventDomainAdmin::MemberID (long())
-%% Returns : CosNotifyChannelAdmin::StructuredProxyPullSupplier |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-connect_structured_pull_consumer_with_id(_OE_This, #state{graph = DG} = State, PC, Id) ->
- Channel = lookup_channel(DG, Id),
- Proxy = connect_a_pull_consumer(Channel, PC, 'STRUCTURED_EVENT'),
- {reply, Proxy, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : connect_structured_push_supplier_with_id
-%% Arguments : PS - CosNotifyComm::StructuredPushSupplier
-%% Id - CosEventDomainAdmin::MemberID (long())
-%% Returns : CosNotifyChannelAdmin::StructuredProxyPushConsumer |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-connect_structured_push_supplier_with_id(_OE_This, #state{graph = DG} = State, PS, Id) ->
- Channel = lookup_channel(DG, Id),
- Proxy = connect_a_push_supplier(Channel, PS, 'STRUCTURED_EVENT'),
- {reply, Proxy, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : connect_structured_pull_supplier_with_id
-%% Arguments : PS - CosNotifyComm::StructuredPullSupplier
-%% Id - CosEventDomainAdmin::MemberID (long())
-%% Returns : CosNotifyChannelAdmin::StructuredProxyPullConsumer |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-connect_structured_pull_supplier_with_id(_OE_This, #state{graph = DG} = State, PS, Id) ->
- type_check(PS, 'CosNotifyComm_StructuredPullSupplier'),
- Channel = lookup_channel(DG, Id),
- Proxy = connect_a_pull_supplier(Channel, PS, 'STRUCTURED_EVENT'),
- {reply, Proxy, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : connect_sequence_push_consumer_with_id
-%% Arguments : PC - CosNotifyComm::SequencePushConsumer
-%% Id - CosEventDomainAdmin::MemberID (long())
-%% Returns : CosNotifyChannelAdmin::SequenceProxyPushSupplier |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-connect_sequence_push_consumer_with_id(_OE_This, #state{graph = DG} = State, PC, Id) ->
- type_check(PC, 'CosNotifyComm_SequencePushConsumer'),
- Channel = lookup_channel(DG, Id),
- Proxy = connect_a_push_consumer(Channel, PC, 'SEQUENCE_EVENT'),
- {reply, Proxy, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : connect_sequence_pull_consumer_with_id
-%% Arguments : PC - CosNotifyComm::SequencePullConsumer
-%% Id - CosEventDomainAdmin::MemberID (long())
-%% Returns : CosNotifyChannelAdmin::SequenceProxyPullSupplier |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-connect_sequence_pull_consumer_with_id(_OE_This, #state{graph = DG} = State, PC, Id) ->
- Channel = lookup_channel(DG, Id),
- Proxy = connect_a_pull_consumer(Channel, PC, 'SEQUENCE_EVENT'),
- {reply, Proxy, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : connect_sequence_push_supplier_with_id
-%% Arguments : PS - CosNotifyComm::SequencePushSupplier
-%% Id - CosEventDomainAdmin::MemberID (long())
-%% Returns : CosNotifyChannelAdmin::SequenceProxyPushConsumer |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-connect_sequence_push_supplier_with_id(_OE_This, #state{graph = DG} = State, PS, Id) ->
- Channel = lookup_channel(DG, Id),
- Proxy = connect_a_push_supplier(Channel, PS, 'SEQUENCE_EVENT'),
- {reply, Proxy, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : connect_sequence_pull_supplier_with_id
-%% Arguments : PS - CosNotifyComm::SequencePullSupplier
-%% Id - CosEventDomainAdmin::MemberID (long())
-%% Returns : CosNotifyChannelAdmin::SequenceProxyPullConsumer |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} |
-%% Description:
-%%----------------------------------------------------------------------
-connect_sequence_pull_supplier_with_id(_OE_This, #state{graph = DG} = State, PS, Id) ->
- type_check(PS, 'CosNotifyComm_SequencePullSupplier'),
- Channel = lookup_channel(DG, Id),
- Proxy = connect_a_pull_supplier(Channel, PS, 'SEQUENCE_EVENT'),
- {reply, Proxy, State}.
-
-
-%%----------------------------------------------------------------------
-%%------------------ CosNotification::QoSAdmin -------------------------
-%%---------------------------------------------------------------------%
-%% Function : get_qos
-%% Arguments : -
-%% Returns : CosNotification::QoSProperties
-%% Description:
-%%----------------------------------------------------------------------
-get_qos(_OE_This, #state{cyclic = Cyclic, diamonds = Diamonds} = State) ->
- {reply, [#'CosNotification_Property'
- {name = ?DiamondDetection,
- value = any:create(orber_tc:short(), Diamonds)},
- #'CosNotification_Property'
- {name = ?CycleDetection,
- value = any:create(orber_tc:short(), Cyclic)}], State}.
-
-%%---------------------------------------------------------------------%
-%% Function : set_qos
-%% Arguments : NewQoS - CosNotification::QoSProperties
-%% Returns : ok |
-%% {'EXCEPTION', #'CosNotification_UnsupportedQoS{}}
-%% Description:
-%%----------------------------------------------------------------------
-set_qos(_OE_This, State, NewQoS) ->
- QoS = cosEventDomainApp:get_qos(NewQoS),
- case set_qos_helper(QoS, State, []) of
- {ok, NewState} ->
- {reply, ok, NewState};
- {error, Errors} ->
- corba:raise(#'CosNotification_UnsupportedQoS'{qos_err = Errors})
- end.
-
-set_qos_helper([], State, []) ->
- {ok, State}; %{reply, ok, State};
-set_qos_helper([], _, Errors) ->
- {error, Errors};
-set_qos_helper([{?DiamondDetection, Diamonds}|T], #state{diamonds = Diamonds} = State,
- Errors) ->
- set_qos_helper(T, State, Errors);
-set_qos_helper([{?CycleDetection, Cyclic}|T], #state{cyclic = Cyclic} = State,
- Errors) ->
- set_qos_helper(T, State, Errors);
-set_qos_helper([{?DiamondDetection, ?AuthorizeDiamonds}|T], State, Errors) ->
- %% Diamonds have not been allowed so far so it's safe to allow it.
- set_qos_helper(T, State#state{diamonds = ?AuthorizeDiamonds}, Errors);
-set_qos_helper([{?DiamondDetection, ?ForbidDiamonds}|T], State, Errors) ->
- %% If any diamonds already exists we cannot allow this. Hence, now we must check
- %% if we can update the QoS.
- case get_diamonds_helper(State, false) of
- [] ->
- set_qos_helper(T, State#state{diamonds = ?ForbidDiamonds}, Errors);
- _ ->
- set_qos_helper(T, State,
- [#'CosNotification_PropertyError'
- {code = 'UNAVAILABLE_VALUE',
- name = ?DiamondDetection,
- available_range = #'CosNotification_PropertyRange'
- {low_val=any:create(orber_tc:short(), ?AuthorizeDiamonds),
- high_val=any:create(orber_tc:short(), ?AuthorizeDiamonds)}}|Errors])
- end;
-set_qos_helper([{?CycleDetection, _}|T], #state{cyclic = Cyclic} = State, Errors) ->
- %% Currently we do not support changing the Cycle schema. If we want to,
- %% we must copy the graph to a new instance of the correct type.
- set_qos_helper(T, State,
- [#'CosNotification_PropertyError'
- {code = 'UNAVAILABLE_VALUE',
- name = ?CycleDetection,
- available_range = #'CosNotification_PropertyRange'
- {low_val=any:create(orber_tc:short(), Cyclic),
- high_val=any:create(orber_tc:short(), Cyclic)}}|Errors]).
-
-%%---------------------------------------------------------------------%
-%% Function : validate_qos
-%% Arguments : WantedQoS - CosNotification::QoSProperties
-%% Returns : {ok, CosNotification::NamedPropertyRangeSeq} |
-%% {'EXCEPTION', #'CosNotification_UnsupportedQoS{}}
-%% Description: NamedPropertyRangeSeq is of out-type
-%%----------------------------------------------------------------------
-validate_qos(_OE_This, State, WantedQoS) ->
- QoS = cosEventDomainApp:get_qos(WantedQoS),
- case validate_qos_helper(QoS, State, [], []) of
- {ok, Properties} ->
- {reply, {ok, Properties}, State};
- {error, Errors} ->
- corba:raise(#'CosNotification_UnsupportedQoS'{qos_err = Errors})
- end.
-
-validate_qos_helper([], _, Properties, []) ->
- {ok, Properties};
-validate_qos_helper([], _, _, Errors) ->
- {error, Errors};
-validate_qos_helper([{?DiamondDetection, ?ForbidDiamonds}|T], State, Properties,
- Errors) ->
- case get_diamonds_helper(State, false) of
- [] ->
- Property =
- #'CosNotification_NamedPropertyRange'
- {name = ?DiamondDetection,
- range = #'CosNotification_PropertyRange'
- {low_val=any:create(orber_tc:short(), ?AuthorizeDiamonds),
- high_val=any:create(orber_tc:short(), ?ForbidDiamonds)}},
- validate_qos_helper(T, State, [Property|Properties], Errors);
- _ ->
- Error =
- #'CosNotification_PropertyError'
- {code = 'UNAVAILABLE_VALUE',
- name = ?DiamondDetection,
- available_range = #'CosNotification_PropertyRange'
- {low_val=any:create(orber_tc:short(), ?AuthorizeDiamonds),
- high_val=any:create(orber_tc:short(), ?AuthorizeDiamonds)}},
- validate_qos_helper(T, State, Properties, [Error|Errors])
- end;
-validate_qos_helper([{?DiamondDetection, ?AuthorizeDiamonds}|T], State, Properties,
- Errors) ->
- Property =
- #'CosNotification_NamedPropertyRange'
- {name = ?DiamondDetection,
- range = #'CosNotification_PropertyRange'
- {low_val=any:create(orber_tc:short(), ?AuthorizeDiamonds),
- high_val=any:create(orber_tc:short(), ?ForbidDiamonds)}},
- validate_qos_helper(T, State, [Property|Properties], Errors);
-validate_qos_helper([{?CycleDetection, Cyclic}|T], #state{cyclic = Cyclic} = State,
- Properties, Errors) ->
- validate_qos_helper(T, State, Properties, Errors);
-validate_qos_helper([{?CycleDetection, _}|T], #state{cyclic = Cyclic} = State,
- Properties, Errors) ->
- Error =
- #'CosNotification_PropertyError'
- {code = 'UNAVAILABLE_VALUE',
- name = ?CycleDetection,
- available_range = #'CosNotification_PropertyRange'
- {low_val=any:create(orber_tc:short(), Cyclic),
- high_val=any:create(orber_tc:short(), Cyclic)}},
- validate_qos_helper(T, State, Properties, [Error|Errors]).
-
-
-%%----------------------------------------------------------------------
-%%------------------ CosNotification::AdminPropertiesAdmin -------------
-%%---------------------------------------------------------------------%
-%% Function : get_admin
-%% Arguments : -
-%% Returns : CosNotification::AdminProperties
-%% Description: No Admins currently supported
-%%----------------------------------------------------------------------
-get_admin(_OE_This, State) ->
- {reply, [], State}.
-
-%%---------------------------------------------------------------------%
-%% Function : set_admin
-%% Arguments : NewAdmins - CosNotification::AdminProperties
-%% Returns : ok |
-%% {'EXCEPTION', #'CosNotification_UnsupportedAdmin{}}
-%% Description: No Admins currently supported
-%%----------------------------------------------------------------------
-set_admin(_OE_This, State, NewAdmins) ->
- cosEventDomainApp:get_admin(NewAdmins),
- {reply, ok, State}.
-
-
-%%======================================================================
-%% Internal functions
-%%======================================================================
-%%---------------------------------------------------------------------%
-%% Function : find_candidates
-%% Arguments : Digraph reference
-%% (Vertex - if we're interested in a specific vertex.
-%% Returns : {[SourceVertices], [SinkVertices], Max}
-%% SourceVertices - {Vertice, [ReachableVertices]}
-%% SinkVertices - {Vertice, [ReachingVertices]}
-%% Max - number of edges in the graph.
-%% Description: To be a part of a diamond ("transitive" relation xRy, yRz => xRz;
-%% in comparison with discrete mathematics we do not require that the
-%% entire graph is transitive) a vertex must have more than one
-%% outgoing and/or incoming. Hence, a digraph must contain at least
-%% one vertex with more than one outgoing edges and at least
-%% one with more than one incoming edges for a diamond to exist.
-%% Hence, the purpose of this function is to find vertices that
-%% look like:
-%%
-%% Vout->V1 V6->Vin
-%% \ and ^
-%% +->V2 |
-%% V8--+
-%%----------------------------------------------------------------------
-find_candidates(DG) ->
- Edges = digraph:edges(DG),
- {COut, CIn, Max} = find_candidates_helper(Edges, [], [], DG, 0),
- {filter_candidates(COut), filter_candidates(CIn), Max}.
-
-
-find_candidates(DG, _Vertex) ->
- %% We should use the fact that we know one of the vertices.
- Edges = digraph:edges(DG),
- {COut, CIn, Max} = find_candidates_helper(Edges, [], [], DG, 0),
- {filter_candidates(COut), filter_candidates(CIn), Max}.
-
-find_candidates_helper([], AccOut, AccIn, _, Counter) ->
- {lists:sort(AccOut), lists:sort(AccIn), Counter};
-find_candidates_helper([H|T], AccOut, AccIn, DG, Counter) ->
- {H, V1, V2, _Label} = digraph:edge(DG, H),
- find_candidates_helper(T, [{V1, V2}|AccOut], [{V2,V1}|AccIn], DG, Counter+1).
-
-filter_candidates([]) ->
- [];
-filter_candidates([{V1, V2}|T]) ->
- filter_candidates([{V1, V2}|T], V1, [], []).
-filter_candidates([], _V, [_Acc1], Acc2) ->
- %% Only one in/out connection. Hence, cannot be start- or end-point
- %% of a diamond.
- lists:reverse(Acc2);
-filter_candidates([], V, Acc1, Acc2) ->
- lists:reverse([{V, lists:reverse(Acc1)}|Acc2]);
-filter_candidates([{V1, V2}|T], V1, Acc1, Acc2) ->
- filter_candidates(T, V1, [V2|Acc1], Acc2);
-filter_candidates([{V1, V2}|T], _V, [_Acc1], Acc2) ->
- %% Only one in/out connection. Hence, cannot be start- or end-point
- %% of a diamond.
- filter_candidates(T, V1, [V2], Acc2);
-filter_candidates([{V1, V2}|T], V, Acc1, Acc2) ->
- filter_candidates(T, V1, [V2], [{V, lists:reverse(Acc1)}|Acc2]).
-
-%%---------------------------------------------------------------------%
-%% Function : evaluate_candidates
-%% Arguments : -
-%% Returns : [Diamond]
-%% Description: There are several scenarios but they can be categorized as:
-%% (1) (2) (3) (4)
-%% 2 2 2-..-56
-%% / \ / \ / \
-%% 1---4 1---4 1---4 1 4
-%% \ / \ / \ /
-%% 3 3 3-..-11
-%%
-%% The purpose of this function is to find these in the cheapest
-%% way possible. For complex diamonds (may also include cycles)
-%% duplicates may be generated. For example, #2/#3 is a sub-set of #1
-%% but they are as well diamonds.
-%%----------------------------------------------------------------------
-evaluate_candidates(_DG, [], _, Acc, _Max, _) ->
- Acc;
-evaluate_candidates(DG, [{V, OutV}|T], CIn, Acc, Max, FindAll) ->
- case evaluate_candidates_helper(DG, V, OutV, CIn, [], FindAll) of
- [] ->
- evaluate_candidates(DG, T, CIn, Acc, Max, FindAll);
- Diamonds when FindAll == true ->
- %% May be more than one diamond.
- evaluate_candidates(DG, T, CIn, Diamonds ++ Acc, Max, FindAll);
- Diamond ->
- Diamond
- end.
-
-evaluate_candidates_helper(_, _, _, _, [Diamond], false) ->
- Diamond;
-evaluate_candidates_helper(_, _, _, [], Diamonds, _) ->
- Diamonds;
-evaluate_candidates_helper(DG, V1, OutV, [{V1, _InV}|T], Diamonds, FindAll) ->
- evaluate_candidates_helper(DG, V1, OutV, T, Diamonds, FindAll);
-evaluate_candidates_helper(DG, V1, OutV, [{V2, InV}|T], Diamonds, FindAll) ->
- case double_match(OutV, InV, [], V1, V2) of
- [] ->
- case is_member(InV, V1) of
- true ->
- %% At this point we know that we have:
- %% x -> y
- %% For this pair to be a part of a diamond we have two options:
- %% (1) x - y (2) x ---- y
- %% \ / or \ / or a additional path besides z1-zN,
- %% z z1-zN
- case double_match_exclude(OutV, InV, [], V1, V2) of
- [] ->
- %% Nope it's not #1.
- case digraph_match(OutV, V2, V1, DG, 1) of
- false ->
- evaluate_candidates_helper(DG, V1, OutV, T,
- Diamonds, FindAll);
- Diamond ->
- evaluate_candidates_helper(DG, V1, OutV, T,
- [[[V1, V2]|Diamond]|Diamonds],
- FindAll)
- end;
- Diamond ->
- %% We've found a diamond looking like:
- %% x - y xRy, yRz => xRz
- %% \ /
- %% z
- evaluate_candidates_helper(DG, V1, OutV, T,
- [[[V1, V2]|Diamond]|Diamonds],
- FindAll)
- end;
- false ->
- case digraph_match(OutV, V2, V1, DG) of
- false ->
- evaluate_candidates_helper(DG, V1, OutV, T,
- Diamonds, FindAll);
- Diamond ->
- evaluate_candidates_helper(DG, V1, OutV, T,
- [Diamond|Diamonds], FindAll)
- end
- end;
- Diamond ->
- %% We've found a diamond looking something like:
- %% 2
- %% / \
- %% 1-5-4 V1 eq. 1, V2 eq 4.
- %% \ /
- %% 3
- evaluate_candidates_helper(DG, V1, OutV, T, [Diamond|Diamonds],
- FindAll)
- end.
-
-is_member([], _) ->
- false;
-is_member([H|_], H) ->
- true;
-is_member([H|_], H2) when H > H2 ->
- %% Since it's a sorted list no need to look any further.
- false;
-is_member([_|T], H) ->
- is_member(T, H).
-
-double_match([], _, [_Matched], _, _) ->
- [];
-double_match([], _, Matched, _, _) ->
- Matched;
-double_match(_, [], [_Matched], _, _) ->
- [];
-double_match(_, [], Matched, _, _) ->
- Matched;
-double_match([H|T1], [H|T2], Matched, V1, V2) ->
- double_match(T1, T2, [[V1,H,V2] | Matched], V1, V2);
-double_match([H1|T1], [H2|T2], Matched, V1, V2) when H1 > H2 ->
- double_match([H1|T1], T2, Matched, V1, V2);
-double_match([_H1|T1], [H2|T2], Matched, V1, V2) ->
- double_match(T1, [H2|T2], Matched, V1, V2).
-
-double_match_exclude([], _, Matched, _, _) ->
- Matched;
-double_match_exclude(_, [], Matched, _, _) ->
- Matched;
-%% exclude it
-double_match_exclude([V2|T1], CIn, Matched, V1, V2) ->
- double_match_exclude(T1, CIn, Matched, V1, V2);
-%% exclude it
-double_match_exclude(COut, [V1|T2], Matched, V1, V2) ->
- double_match_exclude(COut, T2, Matched, V1, V2);
-%% Found match
-double_match_exclude([H|T1], [H|T2], Matched, V1, V2) ->
- double_match_exclude(T1, T2, [[V1,H,V2] | Matched], V1, V2);
-double_match_exclude([H1|T1], [H2|T2], Matched, V1, V2) when H1 > H2 ->
- double_match_exclude([H1|T1], T2, Matched, V1, V2);
-double_match_exclude([_H1|T1], [H2|T2], Matched, V1, V2) ->
- double_match_exclude(T1, [H2|T2], Matched, V1, V2).
-
-
-digraph_match(OutV, V2, V1, DG) ->
- digraph_match(OutV, V2, V1, DG, [], 0).
-
-digraph_match(OutV, V2, V1, DG, Counter) ->
- digraph_match(OutV, V2, V1, DG, [], Counter).
-
-digraph_match([], _, _, _, _, Counter) when Counter < 2 ->
- false;
-digraph_match([], _, _, _, Acc, _) ->
- Acc;
-digraph_match([Vin|T], Vin, Vout, DG, Acc, Counter) ->
- digraph_match(T, Vin, Vout, DG, Acc, Counter);
-digraph_match([H|T], Vin, Vout, DG, Acc, Counter) ->
- case get_path(DG, H, Vin, H, Vout) of
- false ->
- digraph_match(T, Vin, Vout, DG, Acc, Counter);
- Path ->
- %% Found one path; now me must se if there are one more.
- digraph_match(T, Vin, Vout, DG, [[Vout|lists:reverse(Path)] | Acc],
- Counter+1)
- end.
-
-get_path(G, V1, V2, E1, E2) ->
- one_path(digraph:out_neighbours(G, V1), V2, [], [V1], [V1], G, E1, E2).
-
-one_path([E1|_Vs], W, Cont, Xs, Ps, G, E1, E2) ->
- one_path([], W, Cont, Xs, Ps, G, E1, E2);
-one_path([E2|_Vs], W, Cont, Xs, Ps, G, E1, E2) ->
- one_path([], W, Cont, Xs, Ps, G, E1, E2);
-one_path([W|_Ws], W, _Cont, _Xs, Ps, _G, _E1, _E2) ->
- [W|Ps];
-one_path([V|Vs], W, Cont, Xs, Ps, G, E1, E2) ->
- case lists:member(V, Xs) of
- true -> one_path(Vs, W, Cont, Xs, Ps, G, E1, E2);
- false -> one_path(digraph:out_neighbours(G, V), W,
- [{Vs,Ps} | Cont], [V|Xs], [V|Ps], G, E1, E2)
- end;
-one_path([], W, [{Vs,Ps}|Cont], Xs, _, G, E1, E2) ->
- one_path(Vs, W, Cont, Xs, Ps, G, E1, E2);
-one_path([], _, [], _, _, _, _, _) -> false.
-
-%%---------------------------------------------------------------------%
-%% function : type_check
-%% Arguments: Obj - objectrefernce to test.
-%% Mod - Module which contains typeID/0.
-%% Returns : 'ok' or raises exception.
-%% Effect :
-%%----------------------------------------------------------------------
-type_check(Obj, Mod) ->
- case catch corba_object:is_a(Obj,Mod:typeID()) of
- true ->
- ok;
- What ->
- orber:dbg("[~p] CosEventDomainAdmin:type_check();~n"
- "Object of incorrect type supplied; should be: ~p~n"
- "Failed due to: ~p", [?LINE, Mod, What], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{minor=507, completion_status=?COMPLETED_NO})
- end.
-
-%%---------------------------------------------------------------------%
-%% function : lookup_channel
-%% Arguments: DG - digraph reference
-%% Id - CosEventDomainAdmin::MemberID (long())
-%% Returns : CosNotifyChannelAdmin::EventChannel |
-%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}
-%% Effect :
-%%----------------------------------------------------------------------
-lookup_channel(DG, Id) ->
- case digraph:vertex(DG, Id) of
- {Id, Channel} ->
- Channel;
- false ->
- corba:raise(#'CosNotifyChannelAdmin_ChannelNotFound'{})
- end.
-
-
-%%---------------------------------------------------------------------%
-%% function : lookup_connection
-%% Arguments: DG - digraph reference
-%% Id - CosEventDomainAdmin::ConnectionID (long())
-%% Returns : #connectio{} |
-%% {'EXCEPTION', #'CosEventDomainAdmin_ConnectionNotFound'{}}
-%% Effect :
-%%----------------------------------------------------------------------
-lookup_connection(DG, Id) ->
- case digraph:edge(DG, Id) of
- {Id, _SId, _CId, Connection} ->
- Connection;
- false ->
- corba:raise(#'CosEventDomainAdmin_ConnectionNotFound'{})
- end.
-
-%%---------------------------------------------------------------------%
-%% function : lookup_connection_data
-%% Arguments: DG - digraph reference
-%% Id - CosEventDomainAdmin::ConnectionID (long())
-%% Returns : CosEventDomainAdmin::Connection |
-%% {'EXCEPTION', #'CosEventDomainAdmin_ConnectionNotFound'{}}
-%% Effect :
-%%----------------------------------------------------------------------
-lookup_connection_data(DG, Id) ->
- case digraph:edge(DG, Id) of
- {Id, _SId, _CId, #connection{data = Connection}} ->
- Connection;
- false ->
- corba:raise(#'CosEventDomainAdmin_ConnectionNotFound'{})
- end.
-
-%%---------------------------------------------------------------------%
-%% function : close_connections
-%% Arguments: DG -digraph reference
-%% [CosEventDomainAdmin::ConnectionID] - [long()]
-%% Returns : ok
-%% Effect :
-%%----------------------------------------------------------------------
-close_connections(_DG, []) ->
- ok;
-close_connections(DG, [H|T]) ->
- #connection{supplier=S, consumer=C, data=Connection} =
- lookup_connection(DG, H),
- close_connection(Connection, S, C),
- digraph:del_edge(DG, H),
- close_connections(DG, T).
-
-%%---------------------------------------------------------------------%
-%% function : close_connection
-%% Arguments: CosEventDomainAdmin::Connection
-%% S - SupplierProxy
-%% C - ConsumerProxy
-%% Returns : ok
-%% Effect :
-%%----------------------------------------------------------------------
-close_connection(#'CosEventDomainAdmin_Connection'{ctype=Type,
- notification_style = Style},
- S, C) ->
- case {Type, Style} of
- {'ANY_EVENT', 'Push'} ->
- catch 'CosNotifyChannelAdmin_ProxyPushSupplier':disconnect_push_supplier(S),
- catch 'CosNotifyChannelAdmin_ProxyPushConsumer':disconnect_push_consumer(C);
- {'ANY_EVENT', 'Pull'} ->
- catch 'CosNotifyChannelAdmin_ProxyPullSupplier':disconnect_pull_supplier(S),
- catch 'CosNotifyChannelAdmin_ProxyPullConsumer':disconnect_pull_consumer(C);
- {'STRUCTURED_EVENT', 'Push'} ->
- catch 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':disconnect_structured_push_supplier(S),
- catch 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':disconnect_structured_push_consumer(C);
- {'STRUCTURED_EVENT', 'Pull'} ->
- catch 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':disconnect_structured_pull_supplier(S),
- catch 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':disconnect_structured_pull_consumer(C);
- {'SEQUENCE_EVENT', 'Push'} ->
- catch 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':disconnect_sequence_push_supplier(S),
- catch 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':disconnect_sequence_push_consumer(C);
- {'SEQUENCE_EVENT', 'Pull'}->
- catch 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':disconnect_sequence_pull_supplier(S),
- catch 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':disconnect_sequence_pull_consumer(C)
- end,
- ok.
-
-%%---------------------------------------------------------------------%
-%% function : setup_connection
-%% Arguments: CosEventDomainAdmin::Connection
-%% S - SupplierProxy
-%% C - ConsumerProxy
-%% Returns : {ok, SupplierProxy, ConsumerProxy};
-%% Effect :
-%%----------------------------------------------------------------------
-setup_connection(#'CosEventDomainAdmin_Connection'{ctype=Type,
- notification_style = Style},
- S, C) ->
- Admin =
- 'CosNotifyChannelAdmin_EventChannel':'_get_default_consumer_admin'(S),
- case Style of
- 'Push' ->
- {Proxy, _Id} =
- 'CosNotifyChannelAdmin_ConsumerAdmin':
- obtain_notification_push_supplier(Admin, Type),
- CProxy = connect_a_push_supplier(C, Proxy, Type),
- case Type of
- 'ANY_EVENT' ->
- 'CosNotifyChannelAdmin_ProxyPushSupplier':
- connect_any_push_consumer(Proxy, CProxy);
- 'STRUCTURED_EVENT' ->
- 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':
- connect_structured_push_consumer(Proxy, CProxy);
- 'SEQUENCE_EVENT' ->
- 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':
- connect_sequence_push_consumer(Proxy, CProxy)
- end,
- {ok, Proxy, CProxy};
- 'Pull' ->
- {Proxy, _Id} =
- 'CosNotifyChannelAdmin_ConsumerAdmin':
- obtain_notification_pull_supplier(Admin, Type),
- CProxy = connect_a_pull_supplier(C, Proxy, Type),
- case Type of
- 'ANY_EVENT' ->
- 'CosNotifyChannelAdmin_ProxyPullSupplier':
- connect_any_pull_consumer(Proxy, CProxy);
- 'STRUCTURED_EVENT' ->
- 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':
- connect_structured_pull_consumer(Proxy, CProxy);
- 'SEQUENCE_EVENT' ->
- 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':
- connect_sequence_pull_consumer(Proxy, CProxy)
- end,
- {ok, Proxy, CProxy}
- end.
-
-%%---------------------------------------------------------------------%
-%% function : connect_a_pull_consumer
-%% Arguments: Channel - CosNotifyChannelAdmin::EventChannel | undefined
-%% PC - a PullConsumer
-%% Type - 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT'
-%% Returns :
-%% Effect :
-%%----------------------------------------------------------------------
-connect_a_pull_consumer(undefined, _, _) ->
- corba:raise(#'CosNotifyChannelAdmin_ChannelNotFound'{});
-connect_a_pull_consumer(Channel, PC, Type) ->
- Admin =
- 'CosNotifyChannelAdmin_EventChannel':'_get_default_consumer_admin'(Channel),
- {Proxy, _Id} =
- 'CosNotifyChannelAdmin_ConsumerAdmin':obtain_notification_pull_supplier(Admin,
- Type),
- case Type of
- 'ANY_EVENT' ->
- 'CosNotifyChannelAdmin_ProxyPullSupplier':connect_any_pull_consumer(Proxy, PC);
- 'STRUCTURED_EVENT' ->
- 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':connect_structured_pull_consumer(Proxy, PC);
- 'SEQUENCE_EVENT' ->
- 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':connect_sequence_pull_consumer(Proxy, PC)
- end,
- Proxy.
-
-%%---------------------------------------------------------------------%
-%% function : connect_a_push_consumer
-%% Arguments: Channel - CosNotifyChannelAdmin::EventChannel | undefined
-%% PC - a PushConsumer
-%% Type - 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT'
-%% Returns :
-%% Effect :
-%%----------------------------------------------------------------------
-connect_a_push_consumer(undefined, _, _) ->
- corba:raise(#'CosNotifyChannelAdmin_ChannelNotFound'{});
-connect_a_push_consumer(Channel, PC, Type) ->
- Admin =
- 'CosNotifyChannelAdmin_EventChannel':'_get_default_consumer_admin'(Channel),
- {Proxy, _Id} =
- 'CosNotifyChannelAdmin_ConsumerAdmin':obtain_notification_push_supplier(Admin,
- Type),
- case Type of
- 'ANY_EVENT' ->
- 'CosNotifyChannelAdmin_ProxyPushSupplier':connect_any_push_consumer(Proxy, PC);
- 'STRUCTURED_EVENT' ->
- 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':connect_structured_push_consumer(Proxy, PC);
- 'SEQUENCE_EVENT' ->
- 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':connect_sequence_push_consumer(Proxy, PC)
- end,
- Proxy.
-
-%%---------------------------------------------------------------------%
-%% function : connect_a_pull_supplier
-%% Arguments: Channel - CosNotifyChannelAdmin::EventChannel | undefined
-%% PC - a PullSupplier
-%% Type - 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT'
-%% Returns :
-%% Effect :
-%%----------------------------------------------------------------------
-connect_a_pull_supplier(undefined, _, _) ->
- corba:raise(#'CosNotifyChannelAdmin_ChannelNotFound'{});
-connect_a_pull_supplier(Channel, PS, Type) ->
- Admin =
- 'CosNotifyChannelAdmin_EventChannel':'_get_default_supplier_admin'(Channel),
- {Proxy, _Id} =
- 'CosNotifyChannelAdmin_SupplierAdmin':obtain_notification_pull_consumer(Admin,
- Type),
- case Type of
- 'ANY_EVENT' ->
- 'CosNotifyChannelAdmin_ProxyPullConsumer':connect_any_pull_supplier(Proxy, PS);
- 'STRUCTURED_EVENT' ->
- 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':connect_structured_pull_supplier(Proxy, PS);
- 'SEQUENCE_EVENT' ->
- 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':connect_sequence_pull_supplier(Proxy, PS)
- end,
- Proxy.
-
-%%---------------------------------------------------------------------%
-%% function : connect_a_push_supplier
-%% Arguments: Channel - CosNotifyChannelAdmin::EventChannel | undefined
-%% PC - a PushSupplier
-%% Type - 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT'
-%% Returns :
-%% Effect :
-%%----------------------------------------------------------------------
-connect_a_push_supplier(undefined, _, _) ->
- corba:raise(#'CosNotifyChannelAdmin_ChannelNotFound'{});
-connect_a_push_supplier(Channel, PS, Type) ->
- Admin =
- 'CosNotifyChannelAdmin_EventChannel':'_get_default_supplier_admin'(Channel),
- {Proxy, _Id} =
- 'CosNotifyChannelAdmin_SupplierAdmin':obtain_notification_push_consumer(Admin,
- Type),
- case Type of
- 'ANY_EVENT' ->
- 'CosNotifyChannelAdmin_ProxyPushConsumer':connect_any_push_supplier(Proxy, PS);
- 'STRUCTURED_EVENT' ->
- 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':connect_structured_push_supplier(Proxy, PS);
- 'SEQUENCE_EVENT' ->
- 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':connect_sequence_push_supplier(Proxy, PS)
- end,
- Proxy.
-
-
-%%======================================================================
-%% END OF MODULE
-%%======================================================================
-
diff --git a/lib/cosEventDomain/src/Makefile b/lib/cosEventDomain/src/Makefile
deleted file mode 100644
index cdaf9e5f1f..0000000000
--- a/lib/cosEventDomain/src/Makefile
+++ /dev/null
@@ -1,185 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2001-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-ifeq ($(TYPE),debug)
-ERL_COMPILE_FLAGS += -Ddebug -W
-endif
-EBIN=../ebin
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(COSEVENTDOMAIN_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/cosEventDomain-$(VSN)
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-
-MODULES = \
- CosEventDomainAdmin_EventDomainFactory_impl \
- CosEventDomainAdmin_EventDomain_impl \
- cosEventDomainApp
-
-ERL_FILES = $(MODULES:%=%.erl)
-HRL_FILES = cosEventDomainApp.hrl
-
-EXTERNAL_INC_PATH = ../include
-
-GEN_ERL_FILES = \
- oe_CosEventDomainAdmin.erl \
- CosEventDomainAdmin.erl \
- CosEventDomainAdmin_DiamondSeq.erl \
- CosEventDomainAdmin_AlreadyExists.erl \
- CosEventDomainAdmin_DomainIDSeq.erl \
- CosEventDomainAdmin_Connection.erl \
- CosEventDomainAdmin_ConnectionIDSeq.erl \
- CosEventDomainAdmin_ConnectionNotFound.erl \
- CosEventDomainAdmin_CycleCreationForbidden.erl \
- CosEventDomainAdmin_CycleSeq.erl \
- CosEventDomainAdmin_DiamondCreationForbidden.erl \
- CosEventDomainAdmin_DomainNotFound.erl \
- CosEventDomainAdmin_EventDomain.erl \
- CosEventDomainAdmin_EventDomainFactory.erl \
- CosEventDomainAdmin_MemberIDSeq.erl \
- CosEventDomainAdmin_RouteSeq.erl
-
-
-
-GEN_HRL_FILES = \
- oe_CosEventDomainAdmin.hrl \
- CosEventDomainAdmin.hrl \
- CosEventDomainAdmin_EventDomainFactory.hrl \
- CosEventDomainAdmin_EventDomain.hrl
-
-EXTERNAL_GEN_HRL_FILES = \
- $(GEN_HRL_FILES:%=$(EXTERNAL_INC_PATH)/%)
-
-
-TARGET_FILES = \
- $(GEN_ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR)) \
- $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-
-GEN_FILES = $(GEN_HRL_FILES) $(GEN_ERL_FILES)
-
-IDL_FILES = \
- CosEventDomainAdmin.idl
-
-APPUP_FILE = cosEventDomain.appup
-APPUP_SRC = $(APPUP_FILE).src
-APPUP_TARGET = $(EBIN)/$(APPUP_FILE)
-
-APP_FILE = cosEventDomain.app
-APP_SRC = $(APP_FILE).src
-APP_TARGET = $(EBIN)/$(APP_FILE)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_IDL_FLAGS += \
- -pa $(ERL_TOP)/lib/cosEventDomain/ebin \
- -pa $(ERL_TOP)/lib/cosEventDomain/include \
- -pa $(ERL_TOP)/lib/cosNotification/include \
- -pa $(ERL_TOP)/lib/cosNotification/ebin \
- -pa $(ERL_TOP)/lib/ic/ebin \
- -I$(ERL_TOP)/lib/cosNotification/include \
- -I$(ERL_TOP)/lib/cosNotification/ebin \
- -I$(ERL_TOP)/lib/cosNotification/src \
- -I$(ERL_TOP)/lib/cosEvent/src \
- -I$(ERL_TOP)/lib/cosEventDomain/include
-# The -pa option is just used temporary until erlc can handle
-# includes from other directories than ../include .
-ERL_COMPILE_FLAGS += \
- $(ERL_IDL_FLAGS) \
- -pa $(ERL_TOP)/lib/cosEventDomain/include \
- -pa $(ERL_TOP)/lib/cosNotification/ebin \
- -pa $(ERL_TOP)/lib/cosNotification/include \
- -pa $(ERL_TOP)/lib/cosNotification/src \
- -I$(ERL_TOP)/lib/cosEventDomain/include \
- -I$(ERL_TOP)/lib/cosNotification/ebin \
- -I$(ERL_TOP)/lib/cosNotification/include \
- -I$(ERL_TOP)/lib/cosNotification/src \
- -I$(ERL_TOP)/lib/cosEvent/src \
- -I$(ERL_TOP)/lib/cosEvent/include \
- +'{parse_transform,sys_pre_attributes}' \
- +'{attribute,insert,app_vsn,"cosEventDomain_$(COSEVENTDOMAIN_VSN)"}'
-
-YRL_FLAGS =
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
-
-debug:
- @${MAKE} TYPE=debug opt
-
-clean:
- rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET) IDL-GENERATED
- rm -f errs core *~
-
-$(APP_TARGET): $(APP_SRC)
- $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $(APP_SRC) > $(APP_TARGET)
-$(APPUP_TARGET): $(APPUP_SRC)
- $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $(APPUP_SRC) > $(APPUP_TARGET)
-
-docs:
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-IDL-GENERATED: CosEventDomainAdmin.idl
- $(gen_verbose)erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosEventDomainAdmin.cfg"}' CosEventDomainAdmin.idl
- $(V_at)mv $(GEN_HRL_FILES) $(EXTERNAL_INC_PATH)
- $(V_at)>IDL-GENERATED
-
-$(GEN_FILES): IDL-GENERATED
-
-$(TARGET_FILES): IDL-GENERATED
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)"
- $(INSTALL_DATA) ../info "$(RELSYSDIR)"
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
- $(INSTALL_DIR) "$(RELSYSDIR)/src"
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(GEN_ERL_FILES) $(IDL_FILES) "$(RELSYSDIR)/src"
- $(INSTALL_DIR) "$(RELSYSDIR)/include"
- $(INSTALL_DATA) $(EXTERNAL_GEN_HRL_FILES) "$(RELSYSDIR)/include"
-
-
-release_docs_spec:
-
-
-
-
-
diff --git a/lib/cosEventDomain/src/cosEventDomain.app.src b/lib/cosEventDomain/src/cosEventDomain.app.src
deleted file mode 100644
index f218ac853e..0000000000
--- a/lib/cosEventDomain/src/cosEventDomain.app.src
+++ /dev/null
@@ -1,33 +0,0 @@
-{application, cosEventDomain,
- [{description, "The Erlang CosEventDomain application"},
- {vsn, "%VSN%"},
- {modules,
- [
- 'CosEventDomainAdmin_EventDomainFactory_impl',
- 'CosEventDomainAdmin_EventDomain_impl',
- 'cosEventDomainApp',
- 'oe_CosEventDomainAdmin',
- 'CosEventDomainAdmin',
- 'CosEventDomainAdmin_DiamondSeq',
- 'CosEventDomainAdmin_AlreadyExists',
- 'CosEventDomainAdmin_DomainIDSeq',
- 'CosEventDomainAdmin_Connection',
- 'CosEventDomainAdmin_ConnectionIDSeq',
- 'CosEventDomainAdmin_ConnectionNotFound',
- 'CosEventDomainAdmin_CycleCreationForbidden',
- 'CosEventDomainAdmin_CycleSeq',
- 'CosEventDomainAdmin_DiamondCreationForbidden',
- 'CosEventDomainAdmin_DomainNotFound',
- 'CosEventDomainAdmin_EventDomain',
- 'CosEventDomainAdmin_EventDomainFactory',
- 'CosEventDomainAdmin_MemberIDSeq',
- 'CosEventDomainAdmin_RouteSeq'
- ]
- },
- {registered, []},
- {applications, [orber, stdlib, kernel]},
- {env, []},
- {mod, {cosEventDomainApp, []}},
- {runtime_dependencies, ["stdlib-2.0","orber-3.6.27","kernel-3.0","erts-7.0",
- "cosNotification-1.1.21"]}
-]}.
diff --git a/lib/cosEventDomain/src/cosEventDomain.appup.src b/lib/cosEventDomain/src/cosEventDomain.appup.src
deleted file mode 100644
index d69b2ef20c..0000000000
--- a/lib/cosEventDomain/src/cosEventDomain.appup.src
+++ /dev/null
@@ -1,6 +0,0 @@
-{"%VSN%",
- [
- ],
- [
- ]
-}
diff --git a/lib/cosEventDomain/src/cosEventDomainApp.erl b/lib/cosEventDomain/src/cosEventDomainApp.erl
deleted file mode 100644
index be7c2f518a..0000000000
--- a/lib/cosEventDomain/src/cosEventDomainApp.erl
+++ /dev/null
@@ -1,341 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2015. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%--------------------------------------------------------------------
-%% File : cosEventDomainApp.erl
-%% Purpose :
-%%--------------------------------------------------------------------
-
--module(cosEventDomainApp).
-
-%%--------------- INCLUDES -----------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
--include_lib("cosNotification/include/CosNotification.hrl").
-%% Application files
--include("cosEventDomainApp.hrl").
--include("CosEventDomainAdmin.hrl").
-
-%%--------------- EXPORTS ------------------------------------
-%% External MISC
--export([get_option/3,
- create_id/1,
- is_debug_compiled/0,
- install/0,
- uninstall/0,
- start_factory/0,
- start_factory/1,
- start_factory_link/0,
- start_factory_link/1,
- stop_factory/1,
- start/0,
- stop/0,
- create_link/3,
- get_qos/1,
- get_admin/1]).
-
-%% Application callbacks
--export([start/2, init/1, stop/1]).
-
-%%--------------- DEFINES ------------------------------------
-
--define(SUPERVISOR_NAME, oe_cosEventDomainSup).
--define(SUP_FLAG, {simple_one_for_one,50,10}).
-
--define(SUP_SPEC(Name, Args),
- ['CosEventDomainAdmin_EventDomain',Args,
- [{sup_child, true}, {regname, {global, Name}}]]).
--define(SUP_CHILD,
- {"oe_EventDomainChild",
- {cosEventDomainApp,create_link, []},
- transient,100000,worker,
- ['CosEventDomainAdmin_EventDomain']}).
-
-
--define(DEFAULT_OPTIONS, []).
-
-%%--------------- DEFINITIONS OF CONSTANTS -------------------
-%%--------------- EXTERNAL MISC FUNCTIONS --------------------
-%%-----------------------------------------------------------%
-%% function : install
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-install() ->
- oe_CosEventDomainAdmin:oe_register().
-
-%%-----------------------------------------------------------%
-%% function : uninstall
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-uninstall() ->
- oe_CosEventDomainAdmin:oe_unregister().
-
-%%-----------------------------------------------------------%
-%% function : start/stop
-%% Arguments:
-%% Returns :
-%% Effect : Starts or stops the cosTime application.
-%%------------------------------------------------------------
-
-start() ->
- application:start(cosEventDomain).
-stop() ->
- application:stop(cosEventDomain).
-
-%%-----------------------------------------------------------%
-%% function : start
-%% Arguments: Type - see module application
-%% Arg - see module application
-%% Returns :
-%% Effect : Module callback for application
-%%------------------------------------------------------------
-
-start(_, _) ->
- supervisor:start_link({local, ?SUPERVISOR_NAME}, cosEventDomainApp, app_init).
-
-
-%%-----------------------------------------------------------%
-%% function : stop
-%% Arguments: Arg - see module application
-%% Returns :
-%% Effect : Module callback for application
-%%------------------------------------------------------------
-
-stop(_) ->
- ok.
-
-%%-----------------------------------------------------------%
-%% function : start_channel
-%% Arguments: -
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-start_factory() ->
- start_factory(?DEFAULT_OPTIONS).
-
-start_factory(Options) when is_list(Options) ->
- 'CosEventDomainAdmin_EventDomainFactory':oe_create(Options);
-start_factory(Options) ->
- orber:dbg("[~p] cosEventDomainApp:start_factory(~p);~n"
- "Options not correct.",
- [?LINE, Options], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%-----------------------------------------------------------%
-%% function : start_channel
-%% Arguments: -
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-start_factory_link() ->
- start_factory_link(?DEFAULT_OPTIONS).
-
-start_factory_link(Options) when is_list(Options) ->
- 'CosEventDomainAdmin_EventDomainFactory':oe_create_link(Options);
-start_factory_link(Options) ->
- orber:dbg("[~p] cosEventDomainApp:start_factory_link(~p);~n"
- "Options not correct.",
- [?LINE, Options], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%-----------------------------------------------------------%
-%% function : stop_factory
-%% Arguments: ChannelObj
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-stop_factory(ChannelObj) ->
- corba:dispose(ChannelObj).
-
-%%-----------------------------------------------------------%
-%% function : init
-%% Arguments:
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-
-%% Starting using create_factory/X
-init(own_init) ->
- {ok,{?SUP_FLAG, [?SUP_CHILD]}};
-%% When starting as an application.
-init(app_init) ->
- {ok,{?SUP_FLAG, [?SUP_CHILD]}}.
-
-
-%%------------------------------------------------------------
-%% function : create_link
-%% Arguments: Module - which Module to call
-%% Env/ArgList - ordinary oe_create arguments.
-%% Returns :
-%% Exception:
-%% Effect : Necessary since we want the supervisor to be a
-%% 'simple_one_for_one'. Otherwise, using for example,
-%% 'one_for_one', we have to call supervisor:delete_child
-%% to remove the childs startspecification from the
-%% supervisors internal state.
-%%------------------------------------------------------------
-create_link(Module, Env, ArgList) ->
- Module:oe_create_link(Env, ArgList).
-
-%%-----------------------------------------------------------%
-%% function : get_option
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-get_option(Key, OptionList, DefaultList) ->
- case lists:keysearch(Key, 1, OptionList) of
- {value,{Key,Value}} ->
- Value;
- _ ->
- case lists:keysearch(Key, 1, DefaultList) of
- {value,{Key,Value}} ->
- Value;
- _->
- {error, "Invalid option"}
- end
- end.
-
-%%------------------------------------------------------------
-%% function : create_id/1
-%% Arguments: CosEventDomainAdmin::DomainID (long)
-%% Returns : CosEventDomainAdmin::DomainID (long)
-%% Exception:
-%% Purpose :
-%%------------------------------------------------------------
-create_id(2147483647) ->
- -2147483648;
-create_id(OldID) ->
- OldID+1.
-
-%%------------------------------------------------------------
-%% function : get_qos
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-get_qos([]) ->
- [];
-get_qos(Properties) ->
- case get_qos(Properties, [], []) of
- {ok, Supported} ->
- Supported;
- {error, Unsupported} ->
- corba:raise(#'CosNotification_UnsupportedQoS'{qos_err = Unsupported})
- end.
-
-get_qos([], Supported, []) ->
- {ok, Supported};
-get_qos([], _, Unsupported) ->
- {error, Unsupported};
-get_qos([#'CosNotification_Property'{name = ?CycleDetection,
- value= #any{value = ?AuthorizeCycles}}|T],
- Supported, Unsupported) ->
- get_qos(T, [{?CycleDetection, ?AuthorizeCycles}|Supported], Unsupported);
-get_qos([#'CosNotification_Property'{name = ?CycleDetection,
- value= #any{value = ?ForbidCycles}}|T],
- Supported, Unsupported) ->
- get_qos(T, [{?CycleDetection, ?ForbidCycles}|Supported], Unsupported);
-get_qos([#'CosNotification_Property'{name = ?CycleDetection}|T],
- Supported, Unsupported) ->
- %% Illegal value supplied.
- get_qos(T, Supported,
- [#'CosNotification_PropertyError'
- {code = 'UNSUPPORTED_VALUE',
- name = ?CycleDetection,
- available_range = #'CosNotification_PropertyRange'
- {low_val=any:create(orber_tc:short(), ?AuthorizeCycles),
- high_val=any:create(orber_tc:short(), ?ForbidCycles)}}|Unsupported]);
-get_qos([#'CosNotification_Property'{name = ?DiamondDetection,
- value= #any{value = ?AuthorizeDiamonds}}|T],
- Supported, Unsupported) ->
- get_qos(T, [{?DiamondDetection, ?AuthorizeDiamonds}|Supported], Unsupported);
-get_qos([#'CosNotification_Property'{name = ?DiamondDetection,
- value= #any{value = ?ForbidDiamonds}}|T],
- Supported, Unsupported) ->
- get_qos(T, [{?DiamondDetection, ?ForbidDiamonds}|Supported], Unsupported);
-get_qos([#'CosNotification_Property'{name = ?DiamondDetection}|T],
- Supported, Unsupported) ->
- %% Illegal value supplied.
- get_qos(T, Supported,
- [#'CosNotification_PropertyError'
- {code = 'UNSUPPORTED_VALUE',
- name = ?DiamondDetection,
- available_range = #'CosNotification_PropertyRange'
- {low_val=any:create(orber_tc:short(), ?AuthorizeDiamonds),
- high_val=any:create(orber_tc:short(), ?ForbidDiamonds)
- }} | Unsupported]);
-get_qos([#'CosNotification_Property'{name = Name}|T], Supported, Unsupported) ->
- %% Unknown QoS supplied.
- get_qos(T, Supported,
- [#'CosNotification_PropertyError'
- {code = 'BAD_PROPERTY',
- name = Name,
- available_range = #'CosNotification_PropertyRange'
- {low_val=any:create(orber_tc:null(), null),
- high_val=any:create(orber_tc:null(), null)}} | Unsupported]).
-
-%%------------------------------------------------------------
-%% function : get_admin
-%% Arguments:
-%% Returns : {"EXCEPTION', #'CosNotification_PropertyError'{}}
-%% Exception:
-%% Effect : No Admin supported.
-%%------------------------------------------------------------
-get_admin([]) ->
- [];
-get_admin(Properties) ->
- get_admin(Properties, []).
-
-get_admin([], Unsupported) ->
- corba:raise(#'CosNotification_UnsupportedAdmin'{admin_err = Unsupported});
-get_admin([#'CosNotification_Property'{name = Name}|T], Unsupported) ->
- %% Unknown QoS supplied.
- get_admin(T, [#'CosNotification_PropertyError'
- {code = 'BAD_PROPERTY',
- name = Name,
- available_range = #'CosNotification_PropertyRange'
- {low_val=any:create(orber_tc:null(), null),
- high_val=any:create(orber_tc:null(), null)}} | Unsupported]).
-
-
-%%------------------------------------------------------------
-%% function : is_debug_compiled
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
--ifdef(debug).
- is_debug_compiled() -> true.
--else.
- is_debug_compiled() -> false.
--endif.
-
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/cosEventDomain/src/cosEventDomainApp.hrl b/lib/cosEventDomain/src/cosEventDomainApp.hrl
deleted file mode 100644
index 6df20692be..0000000000
--- a/lib/cosEventDomain/src/cosEventDomainApp.hrl
+++ /dev/null
@@ -1,70 +0,0 @@
-%%----------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : cosEventDomainApp.hrl
-%% Purpose :
-%%----------------------------------------------------------------------
-
-
-%%--------------- INCLUDES -----------------------------------
-%% External
-
-%% Local
-
--define(write_ErrorMsg(Txt, Arg),
-error_logger:error_msg("============== CosEventDomain =============~n"
- Txt
- "===========================================~n",
- Arg)).
-
--define(DEBUG_LEVEL, 3).
-
--ifdef(debug).
--define(DBG(F,A),
- io:format("[LINE: ~p MODULE: ~p] "++F,[?LINE, ?MODULE]++A)).
--else.
--define(DBG(F,A), ok).
--endif.
-
-%%%%%% WARNING! These definitions are defined in the CosEventDomainAdmin.idl
-%%%%%% file. If the specification is changed so must the definitions!!
-%%%%%% We use this approach to be able to use them as guards.
-
-%%%% Constant: 'CycleDetection'
--define(CycleDetection, "CycleDetection").
-
-%%%% Constant: 'AuthorizeCycles'
--define(AuthorizeCycles, 0).
-
-%%%% Constant: 'ForbidCycles'
--define(ForbidCycles, 1).
-
-%%%% Constant: 'DiamondDetection'
--define(DiamondDetection, "DiamondDetection").
-
-%%%% Constant: 'AuthorizeDiamonds'
--define(AuthorizeDiamonds, 0).
-
-%%%% Constant: 'ForbidDiamonds'
--define(ForbidDiamonds, 1).
-
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/cosEventDomain/test/Makefile b/lib/cosEventDomain/test/Makefile
deleted file mode 100644
index 1841676be7..0000000000
--- a/lib/cosEventDomain/test/Makefile
+++ /dev/null
@@ -1,104 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2001-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(COSEVENTDOMAIN_VSN)
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/cosEventDomain_test
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-TEST_SPEC_FILE = cosEventDomain.spec
-COVER_FILE = cosEventDomain.cover
-
-
-MODULES = \
- event_domain_SUITE \
- generated_SUITE
-
-ERL_FILES = $(MODULES:%=%.erl)
-
-HRL_FILES =
-
-SUITE_TARGET_FILES = $(MODULES:%=%.$(EMULATOR))
-
-TARGET_FILES = \
- $(SUITE_TARGET_FILES)
-
-# ----------------------------------------------------
-# PROGRAMS
-# ----------------------------------------------------
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_IDL_FLAGS += -pa $(ERL_TOP)/lib/orber/ebin -pa $(ERL_TOP)/lib/ic/ebin
-
-ERL_COMPILE_FLAGS += \
- $(ERL_IDL_FLAGS) \
- -pa $(ERL_TOP)/lib/cosEventDomain/ebin \
- -pa $(ERL_TOP)/lib/cosEventDomain/include \
- -pa $(ERL_TOP)/lib/cosNotification/ebin \
- -pa $(ERL_TOP)/lib/cosNotification/include \
- -I$(ERL_TOP)/lib/cosEventDomain/include \
- -I$(ERL_TOP)/lib/cosNotification/include \
- -I$(ERL_TOP)/lib/cosNotification/ebin
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-tests debug opt: $(TARGET_FILES)
-
-clean:
- rm -f $(TARGET_FILES)
- rm -f errs core *~
-
-
-docs:
-
-# ----------------------------------------------------
-# Special Targets
-# ----------------------------------------------------
-
-# ----------------------------------------------------
-# Release Targets
-# ----------------------------------------------------
-# We don't copy generated intermediate erlang and hrl files
-
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec:
-
-release_docs_spec:
-
-release_tests_spec: tests
- $(INSTALL_DIR) "$(RELSYSDIR)"
- $(INSTALL_DATA) $(TEST_SPEC_FILE) \
- $(COVER_FILE) $(ERL_FILES) "$(RELSYSDIR)"
- $(INSTALL_DATA) $(SUITE_TARGET_FILES) "$(RELSYSDIR)"
-
diff --git a/lib/cosEventDomain/test/cosEventDomain.cover b/lib/cosEventDomain/test/cosEventDomain.cover
deleted file mode 100644
index f87f6d97bf..0000000000
--- a/lib/cosEventDomain/test/cosEventDomain.cover
+++ /dev/null
@@ -1,2 +0,0 @@
-{incl_app,cosEventDomain,details}.
-
diff --git a/lib/cosEventDomain/test/cosEventDomain.spec b/lib/cosEventDomain/test/cosEventDomain.spec
deleted file mode 100644
index bcee74c5f1..0000000000
--- a/lib/cosEventDomain/test/cosEventDomain.spec
+++ /dev/null
@@ -1 +0,0 @@
-{suites,"../cosEventDomain_test",all}.
diff --git a/lib/cosEventDomain/test/event_domain_SUITE.erl b/lib/cosEventDomain/test/event_domain_SUITE.erl
deleted file mode 100644
index 031b7726c5..0000000000
--- a/lib/cosEventDomain/test/event_domain_SUITE.erl
+++ /dev/null
@@ -1,464 +0,0 @@
-%%-----------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-
--module(event_domain_SUITE).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/include/corba.hrl").
--include_lib("cosNotification/include/CosNotifyChannelAdmin.hrl").
--include_lib("cosNotification/include/CosNotification.hrl").
-
--include_lib("cosEventDomain/include/CosEventDomainAdmin.hrl").
--include_lib("cosEventDomain/src/cosEventDomainApp.hrl").
-
-%%-----------------------------------------------------------------
-%% Macros
-%%-----------------------------------------------------------------
-
--define(default_timeout, test_server:minutes(5)).
-
-
--define(match(ExpectedRes, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- io:format("------ CORRECT RESULT ------~n~p~n",
- [AcTuAlReS]),
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
- event_domain_api/1, event_domain_factory_api/1,
- cases/0, init_per_suite/1, end_per_suite/1,
- init_per_testcase/2, end_per_testcase/2, app_test/1]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- cases().
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-cases() ->
- [event_domain_api, event_domain_factory_api, app_test].
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-
-init_per_testcase(_Case, Config) ->
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-init_per_suite(Config) when is_list(Config) ->
- mnesia:delete_schema([node()]),
- mnesia:create_schema([node()]),
- ok = corba:orb_init([{flags, 16#02},
- {orber_debug_level, 10}]),
- orber:install([node()]),
- application:start(mnesia),
- application:start(orber),
- cosEventApp:install(),
- cosEventApp:start(),
- cosNotificationApp:install(),
- cosNotificationApp:start(),
- cosEventDomainApp:install(),
- cosEventDomainApp:start(),
- Config.
-
-end_per_suite(Config) when is_list(Config) ->
- cosEventDomainApp:stop(),
- cosEventDomainApp:uninstall(),
- cosNotificationApp:stop(),
- cosNotificationApp:uninstall(),
- cosEventApp:stop(),
- cosEventApp:uninstall(),
- application:stop(orber),
- application:stop(mnesia),
- mnesia:delete_schema([node()]),
- Config.
-
-%%-----------------------------------------------------------------
-%% Tests app file
-%%-----------------------------------------------------------------
-app_test(_Config) ->
- ok=test_server:app_test(cosEventDomain),
- ok.
-
-
-%% Testing the CosEventDomain Domain API
-event_domain_api(_Config) ->
-
- %% We will setup a cluster looking like:
- %% 7-8--->
- %% /
- %% 2 - 4 6->
- %% \ /
- %% 5---9-1-3
-
- %% 2-4
- %% 4-1
- %% 1-3
- %% 3-6
- %% 5-9
- %% 9-1
- %% 4-7
- %% 7-8
-
-
- ChFac = ?match({_,key,_,_,_,_},
- cosNotificationApp:start_global_factory([{pullInterval,1}])),
- {Ch0,_} = ?match({{_,key,_,_,_,_}, _},
- 'CosNotifyChannelAdmin_EventChannelFactory':create_channel(ChFac, [], [])),
- Fac = ?match({_,key,_,_,_,_},
- cosEventDomainApp:start_factory()),
- {ED, _} = ?match({{_,key,_,_,_,_}, _},
- 'CosEventDomainAdmin_EventDomainFactory':create_event_domain(Fac, [], [])),
- ID0 = 'CosEventDomainAdmin_EventDomain':add_channel(ED, Ch0),
- ?match(Ch0, 'CosEventDomainAdmin_EventDomain':get_channel(ED, ID0)),
- ?match([0], 'CosEventDomainAdmin_EventDomain':get_all_channels(ED)),
- ?match({'EXCEPTION',{'CosNotifyChannelAdmin_ChannelNotFound',_}},
- 'CosEventDomainAdmin_EventDomain':get_channel(ED, 100)),
- ?match({'EXCEPTION',{'CosNotifyChannelAdmin_ChannelNotFound',_}},
- 'CosEventDomainAdmin_EventDomain':remove_channel(ED, 100)),
- ?match(ok, 'CosEventDomainAdmin_EventDomain':remove_channel(ED, 0)),
- ?match([], 'CosEventDomainAdmin_EventDomain':get_all_channels(ED)),
- ?match({'EXCEPTION',{'CosNotifyChannelAdmin_ChannelNotFound',_}},
- 'CosEventDomainAdmin_EventDomain':remove_channel(ED, 0)),
-
- %% Create a new event channel.
- {Ch1,_} = ?match({{_,key,_,_,_,_}, _},
- 'CosNotifyChannelAdmin_EventChannelFactory':create_channel(ChFac, [], [])),
- {Ch2,_} = ?match({{_,key,_,_,_,_}, _},
- 'CosNotifyChannelAdmin_EventChannelFactory':create_channel(ChFac, [], [])),
- {Ch3,_} = ?match({{_,key,_,_,_,_}, _},
- 'CosNotifyChannelAdmin_EventChannelFactory':create_channel(ChFac, [], [])),
- {Ch4,_} = ?match({{_,key,_,_,_,_}, _},
- 'CosNotifyChannelAdmin_EventChannelFactory':create_channel(ChFac, [], [])),
- {Ch5,_} = ?match({{_,key,_,_,_,_}, _},
- 'CosNotifyChannelAdmin_EventChannelFactory':create_channel(ChFac, [], [])),
- {Ch6,_} = ?match({{_,key,_,_,_,_}, _},
- 'CosNotifyChannelAdmin_EventChannelFactory':create_channel(ChFac, [], [])),
- {Ch7,_} = ?match({{_,key,_,_,_,_}, _},
- 'CosNotifyChannelAdmin_EventChannelFactory':create_channel(ChFac, [], [])),
- {Ch8,_} = ?match({{_,key,_,_,_,_}, _},
- 'CosNotifyChannelAdmin_EventChannelFactory':create_channel(ChFac, [], [])),
- {Ch9,_} = ?match({{_,key,_,_,_,_}, _},
- 'CosNotifyChannelAdmin_EventChannelFactory':create_channel(ChFac, [], [])),
-
- ID1 = 'CosEventDomainAdmin_EventDomain':add_channel(ED, Ch1),
- ID2 = 'CosEventDomainAdmin_EventDomain':add_channel(ED, Ch2),
- ID3 = 'CosEventDomainAdmin_EventDomain':add_channel(ED, Ch3),
- ID4 = 'CosEventDomainAdmin_EventDomain':add_channel(ED, Ch4),
- ID5 = 'CosEventDomainAdmin_EventDomain':add_channel(ED, Ch5),
- ID6 = 'CosEventDomainAdmin_EventDomain':add_channel(ED, Ch6),
- ID7 = 'CosEventDomainAdmin_EventDomain':add_channel(ED, Ch7),
- ID8 = 'CosEventDomainAdmin_EventDomain':add_channel(ED, Ch8),
- ID9 = 'CosEventDomainAdmin_EventDomain':add_channel(ED, Ch9),
- ?match([_,_,_,_,_,_,_,_,_],
- 'CosEventDomainAdmin_EventDomain':get_all_channels(ED)),
-
- ?match([], 'CosEventDomainAdmin_EventDomain':get_all_connections(ED)),
- C1 = #'CosEventDomainAdmin_Connection'{supplier_id=ID2,
- consumer_id=ID4,
- ctype='STRUCTURED_EVENT',
- notification_style='Pull'},
- C2 = #'CosEventDomainAdmin_Connection'{supplier_id=ID4,
- consumer_id=ID1,
- ctype='ANY_EVENT',
- notification_style='Push'},
- C3 = #'CosEventDomainAdmin_Connection'{supplier_id=ID1,
- consumer_id=ID3,
- ctype='ANY_EVENT',
- notification_style='Pull'},
- C4 = #'CosEventDomainAdmin_Connection'{supplier_id=ID3,
- consumer_id=ID6,
- ctype='STRUCTURED_EVENT',
- notification_style='Push'},
- C5 = #'CosEventDomainAdmin_Connection'{supplier_id=ID5,
- consumer_id=ID9,
- ctype='ANY_EVENT',
- notification_style='Pull'},
- C6 = #'CosEventDomainAdmin_Connection'{supplier_id=ID9,
- consumer_id=ID1,
- ctype='ANY_EVENT',
- notification_style='Push'},
- C7 = #'CosEventDomainAdmin_Connection'{supplier_id=ID4,
- consumer_id=ID7,
- ctype='STRUCTURED_EVENT',
- notification_style='Pull'},
- C8 = #'CosEventDomainAdmin_Connection'{supplier_id=ID7,
- consumer_id=ID8,
- ctype='ANY_EVENT',
- notification_style='Push'},
- C9 = #'CosEventDomainAdmin_Connection'{supplier_id=ID8,
- consumer_id=ID4,
- ctype='ANY_EVENT',
- notification_style='Pull'},
- C10 = #'CosEventDomainAdmin_Connection'{supplier_id=ID5,
- consumer_id=ID4,
- ctype='ANY_EVENT',
- notification_style='Pull'},
- C11 = #'CosEventDomainAdmin_Connection'{supplier_id=ID4,
- consumer_id=ID6,
- ctype='ANY_EVENT',
- notification_style='Pull'},
- C12 = #'CosEventDomainAdmin_Connection'{supplier_id=ID8,
- consumer_id=ID6,
- ctype='ANY_EVENT',
- notification_style='Pull'},
-
- CID1 = 'CosEventDomainAdmin_EventDomain':add_connection(ED, C1),
- ?match([CID1], 'CosEventDomainAdmin_EventDomain':get_all_connections(ED)),
- _CID2 = 'CosEventDomainAdmin_EventDomain':add_connection(ED, C2),
- ?match([_,_],
- 'CosEventDomainAdmin_EventDomain':get_all_connections(ED)),
- _CID3 = 'CosEventDomainAdmin_EventDomain':add_connection(ED, C3),
- ?match([_,_,_],
- 'CosEventDomainAdmin_EventDomain':get_all_connections(ED)),
- _CID4 = 'CosEventDomainAdmin_EventDomain':add_connection(ED, C4),
- ?match([_,_,_,_],
- 'CosEventDomainAdmin_EventDomain':get_all_connections(ED)),
- _CID5 = 'CosEventDomainAdmin_EventDomain':add_connection(ED, C5),
- ?match([_,_,_,_,_],
- 'CosEventDomainAdmin_EventDomain':get_all_connections(ED)),
- _CID6 = 'CosEventDomainAdmin_EventDomain':add_connection(ED, C6),
- ?match([_,_,_,_,_,_],
- 'CosEventDomainAdmin_EventDomain':get_all_connections(ED)),
- CID7 = 'CosEventDomainAdmin_EventDomain':add_connection(ED, C7),
- ?match([_,_,_,_,_,_,_],
- 'CosEventDomainAdmin_EventDomain':get_all_connections(ED)),
- _CID8 = 'CosEventDomainAdmin_EventDomain':add_connection(ED, C8),
- ?match([_,_,_,_,_,_,_,_],
- 'CosEventDomainAdmin_EventDomain':get_all_connections(ED)),
-
- ?match({'EXCEPTION',{'CosEventDomainAdmin_AlreadyExists', _}},
- 'CosEventDomainAdmin_EventDomain':add_connection(ED, C8)),
- %% No cycles should exist.
- ?match([], 'CosEventDomainAdmin_EventDomain':get_cycles(ED)),
-
- ?match([_, _], 'CosEventDomainAdmin_EventDomain':get_qos(ED)),
- AllowCyclic = #'CosNotification_Property'{name=?CycleDetection,
- value=any:create(orber_tc:short(),
- ?AuthorizeCycles)},
- ?match({'EXCEPTION',{'CosNotification_UnsupportedQoS',_,_}},
- 'CosEventDomainAdmin_EventDomain':set_qos(ED, [AllowCyclic])),
- ForbidCyclic = #'CosNotification_Property'{name=?CycleDetection,
- value=any:create(orber_tc:short(),
- ?ForbidCycles)},
- %% The same as before; must work.
- ?match(ok, 'CosEventDomainAdmin_EventDomain':set_qos(ED, [ForbidCyclic])),
-
- AllowDiamonds = #'CosNotification_Property'{name=?DiamondDetection,
- value=any:create(orber_tc:short(),
- ?AuthorizeDiamonds)},
- %% Since no diamonds allowed before this is always ok.
- ?match(ok, 'CosEventDomainAdmin_EventDomain':set_qos(ED, [AllowDiamonds])),
-
- ?match([_, _], 'CosEventDomainAdmin_EventDomain':get_qos(ED)),
-
- ForbidDiamonds = #'CosNotification_Property'{name=?DiamondDetection,
- value=any:create(orber_tc:short(),
- ?ForbidDiamonds)},
- %% No diamonds created before. Hence, will work.
- ?match(ok, 'CosEventDomainAdmin_EventDomain':set_qos(ED, [ForbidDiamonds])),
-
- ?match([_, _], 'CosEventDomainAdmin_EventDomain':get_qos(ED)),
-
- ?match({ok, [_]}, 'CosEventDomainAdmin_EventDomain':validate_qos(ED,
- [ForbidDiamonds,
- ForbidCyclic])),
- %% No diamonds exists, hence, this is ok.
- ?match({ok, [_]}, 'CosEventDomainAdmin_EventDomain':validate_qos(ED,
- [AllowDiamonds,
- ForbidCyclic])),
- ?match({'EXCEPTION',{'CosNotification_UnsupportedQoS',_,_}},
- 'CosEventDomainAdmin_EventDomain':validate_qos(ED, [ForbidDiamonds,
- AllowCyclic])),
-
- %% Since the ED is started is asyclic we may not succeed with this invokation.
- ?match({'EXCEPTION',{'CosEventDomainAdmin_CycleCreationForbidden',_,_}},
- 'CosEventDomainAdmin_EventDomain':add_connection(ED, C9)),
- ?match([], 'CosEventDomainAdmin_EventDomain':get_offer_channels(ED, ID2)),
-
- ?match([2], 'CosEventDomainAdmin_EventDomain':get_offer_channels(ED, ID4)),
- ?match([_,_,_], 'CosEventDomainAdmin_EventDomain':get_offer_channels(ED, ID8)),
- ?match({'EXCEPTION',{'CosNotifyChannelAdmin_ChannelNotFound',_}},
- 'CosEventDomainAdmin_EventDomain':get_offer_channels(ED, 100)),
- ?match([], 'CosEventDomainAdmin_EventDomain':get_subscription_channels(ED, ID8)),
- ?match([_,_,_,_,_],
- 'CosEventDomainAdmin_EventDomain':get_subscription_channels(ED, ID4)),
- ?match([_,_,_,_,_,_],
- 'CosEventDomainAdmin_EventDomain':get_subscription_channels(ED, ID2)),
- ?match({'EXCEPTION',{'CosNotifyChannelAdmin_ChannelNotFound',_}},
- 'CosEventDomainAdmin_EventDomain':get_subscription_channels(ED, 100)),
- Nil = corba:create_nil_objref(),
-
- P2=?match({_,key,_,_,_,_},
- 'CosEventDomainAdmin_EventDomain':connect_push_supplier_with_id(ED, Nil, ID2)),
- P7=?match({_,key,_,_,_,_},
- 'CosEventDomainAdmin_EventDomain':connect_push_supplier_with_id(ED, Nil, ID7)),
- P8=?match({_,key,_,_,_,_},
- 'CosEventDomainAdmin_EventDomain':connect_pull_consumer_with_id(ED, Nil, ID8)),
- P6=?match({_,key,_,_,_,_},
- 'CosEventDomainAdmin_EventDomain':connect_pull_consumer_with_id(ED, Nil, ID6)),
- E1 = #any{typecode=tk_long, value=1},
- E2 = #any{typecode=tk_long, value=2},
-
- ?match(ok, 'CosNotifyChannelAdmin_ProxyPushConsumer':push(P2, E1)),
- ?match(E1, 'CosNotifyChannelAdmin_ProxyPullSupplier':pull(P8)),
- ?match(E1, 'CosNotifyChannelAdmin_ProxyPullSupplier':pull(P6)),
- ?match(ok, 'CosNotifyChannelAdmin_ProxyPushConsumer':push(P7, E2)),
- ?match(E2, 'CosNotifyChannelAdmin_ProxyPullSupplier':pull(P8)),
- timer:sleep(10000),
- ?match({_,false}, 'CosNotifyChannelAdmin_ProxyPullSupplier':try_pull(P6)),
-
- ?match(ok, 'CosEventDomainAdmin_EventDomain':remove_connection(ED, CID7)),
-
- ?match({'EXCEPTION',{'CosEventDomainAdmin_ConnectionNotFound',_}},
- 'CosEventDomainAdmin_EventDomain':remove_connection(ED, CID7)),
-
- ?match({'EXCEPTION',{'CosEventDomainAdmin_ConnectionNotFound',_}},
- 'CosEventDomainAdmin_EventDomain':remove_connection(ED, 100)),
-
- ?match([], 'CosEventDomainAdmin_EventDomain':get_offer_channels(ED, ID7)),
- ?match([2], 'CosEventDomainAdmin_EventDomain':get_offer_channels(ED, ID4)),
-
- ?match([8], 'CosEventDomainAdmin_EventDomain':get_subscription_channels(ED, ID7)),
- ?match([_,_,_], 'CosEventDomainAdmin_EventDomain':get_subscription_channels(ED, ID4)),
-
- CID10 = ?match(8, 'CosEventDomainAdmin_EventDomain':add_connection(ED, C7)),
-
- %% Now we'll check diamond management.
- %% Currently it should not be possible to create a diamond (due to QoS-setting).
- ?match({'EXCEPTION',{'CosEventDomainAdmin_DiamondCreationForbidden',_,_}},
- 'CosEventDomainAdmin_EventDomain':add_connection(ED, C11)),
- ?match({'EXCEPTION',{'CosEventDomainAdmin_DiamondCreationForbidden',_,_}},
- 'CosEventDomainAdmin_EventDomain':add_connection(ED, C10)),
- ?match({'EXCEPTION',{'CosEventDomainAdmin_DiamondCreationForbidden',_,_}},
- 'CosEventDomainAdmin_EventDomain':add_connection(ED, C12)),
- ?match(ok, 'CosEventDomainAdmin_EventDomain':set_qos(ED, [AllowDiamonds])),
-
- CID11 = ?match(9, 'CosEventDomainAdmin_EventDomain':add_connection(ED, C10)),
- ?match([_,_,_,_,_,_,_,_,_],
- 'CosEventDomainAdmin_EventDomain':get_all_connections(ED)),
- ?match([_], 'CosEventDomainAdmin_EventDomain':get_diamonds(ED)),
-
- CID12 = ?match(10, 'CosEventDomainAdmin_EventDomain':add_connection(ED, C11)),
- ?match([_, _, _], 'CosEventDomainAdmin_EventDomain':get_diamonds(ED)),
-
- CID13 = ?match(11, 'CosEventDomainAdmin_EventDomain':add_connection(ED, C12)),
-
- ?match([_, _, _], 'CosEventDomainAdmin_EventDomain':get_diamonds(ED)),
-
- ?match({'EXCEPTION',{'CosNotification_UnsupportedQoS',_,_}},
- 'CosEventDomainAdmin_EventDomain':set_qos(ED, [ForbidDiamonds])),
-
- ?match(ok, 'CosEventDomainAdmin_EventDomain':remove_connection(ED, CID10)),
- ?match(ok, 'CosEventDomainAdmin_EventDomain':remove_connection(ED, CID11)),
- ?match(ok, 'CosEventDomainAdmin_EventDomain':remove_connection(ED, CID12)),
- ?match(ok, 'CosEventDomainAdmin_EventDomain':remove_connection(ED, CID13)),
- ?match(ok, 'CosEventDomainAdmin_EventDomain':set_qos(ED, [ForbidDiamonds])),
- ?match([_, _], 'CosEventDomainAdmin_EventDomain':get_qos(ED)),
- ?match({'EXCEPTION',{'CosEventDomainAdmin_DiamondCreationForbidden',_,_}},
- 'CosEventDomainAdmin_EventDomain':add_connection(ED, C10)),
-
- ?match(ok, 'CosEventDomainAdmin_EventDomain':destroy(ED)),
-
- ok.
-
-%% Testing the CosEventDomain Factory API
-event_domain_factory_api(_Config) ->
-
- Cyclic = #'CosNotification_Property'{name=?CycleDetection,
- value=any:create(orber_tc:short(),
- ?ForbidCycles)},
-
- BadProp = #'CosNotification_Property'{name="Wrong",
- value=any:create(orber_tc:short(),
- ?ForbidCycles)},
-
- BadQoSVal = #'CosNotification_Property'{name=?CycleDetection,
- value=any:create(orber_tc:short(),
- 10)},
-
- Fac = ?match({_,key,_,_,_,_},
- cosEventDomainApp:start_factory()),
- ?match([], 'CosEventDomainAdmin_EventDomainFactory':get_all_domains(Fac)),
- ?match({'EXCEPTION',{'CosEventDomainAdmin_DomainNotFound',_}},
- 'CosEventDomainAdmin_EventDomainFactory':get_event_domain(Fac, 0)),
- {ED,_} = 'CosEventDomainAdmin_EventDomainFactory':create_event_domain(Fac, [Cyclic], []),
- ?match([0], 'CosEventDomainAdmin_EventDomainFactory':get_all_domains(Fac)),
- ED = 'CosEventDomainAdmin_EventDomainFactory':get_event_domain(Fac, 0),
- ?match({'EXCEPTION',{'CosEventDomainAdmin_DomainNotFound',_}},
- 'CosEventDomainAdmin_EventDomainFactory':get_event_domain(Fac, 1)),
- corba:dispose(ED),
- timer:sleep(3000),
- ?match([], 'CosEventDomainAdmin_EventDomainFactory':get_all_domains(Fac)),
- ?match({'EXCEPTION',{'CosEventDomainAdmin_DomainNotFound',_}},
- 'CosEventDomainAdmin_EventDomainFactory':get_event_domain(Fac, 0)),
- {ED2,_} = ?match({{_,key,_,_,_,_}, _},
- 'CosEventDomainAdmin_EventDomainFactory':create_event_domain(Fac, [], [])),
- ?match([1], 'CosEventDomainAdmin_EventDomainFactory':get_all_domains(Fac)),
- ?match(ED2, 'CosEventDomainAdmin_EventDomainFactory':get_event_domain(Fac, 1)),
- corba:dispose(ED2),
-
- ?match({'EXCEPTION', {'CosNotification_UnsupportedQoS',_,_}},
- 'CosEventDomainAdmin_EventDomainFactory':create_event_domain(Fac, [BadProp], [])),
- ?match({'EXCEPTION',{'CosNotification_UnsupportedAdmin',_,_}},
- 'CosEventDomainAdmin_EventDomainFactory':create_event_domain(Fac, [], [BadProp])),
- ?match({'EXCEPTION',{'CosNotification_UnsupportedQoS',_,_}},
- 'CosEventDomainAdmin_EventDomainFactory':create_event_domain(Fac, [BadQoSVal], [])),
- ?match({'EXCEPTION',{'CosNotification_UnsupportedAdmin',_,_}},
- 'CosEventDomainAdmin_EventDomainFactory':create_event_domain(Fac, [], [BadQoSVal])),
-
- corba:dispose(Fac),
- ok.
diff --git a/lib/cosEventDomain/test/generated_SUITE.erl b/lib/cosEventDomain/test/generated_SUITE.erl
deleted file mode 100644
index 172465da2f..0000000000
--- a/lib/cosEventDomain/test/generated_SUITE.erl
+++ /dev/null
@@ -1,384 +0,0 @@
-%%-----------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File : generated_SUITE.erl
-%% Purpose :
-%%-----------------------------------------------------------------
-
--module(generated_SUITE).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/include/corba.hrl").
-
--define(default_timeout, test_server:minutes(3)).
-
--define(match(ExpectedRes, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
--define(nomatch(Not, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- Not ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS);
- _ ->
- AcTuAlReS
- end
- end()).
-
-
--define(checktc(_Op),
- fun(TC) ->
- case orber_tc:check_tc(TC) of
- false ->
- io:format("###### ERROR ERROR ######~n~p - ~p~n", [Op, TC]),
- exit(TC);
- true ->
- true
- end
- end).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--compile(export_all).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- ['CosEventDomainAdmin',
- 'CosEventDomainAdmin_DiamondSeq',
- 'CosEventDomainAdmin_AlreadyExists',
- 'CosEventDomainAdmin_DomainIDSeq',
- 'CosEventDomainAdmin_Connection',
- 'CosEventDomainAdmin_ConnectionIDSeq',
- 'CosEventDomainAdmin_ConnectionNotFound',
- 'CosEventDomainAdmin_CycleCreationForbidden',
- 'CosEventDomainAdmin_CycleSeq',
- 'CosEventDomainAdmin_DiamondCreationForbidden',
- 'CosEventDomainAdmin_DomainNotFound',
- 'CosEventDomainAdmin_MemberIDSeq',
- 'CosEventDomainAdmin_RouteSeq',
- 'CosEventDomainAdmin_EventDomainFactory',
- 'CosEventDomainAdmin_EventDomain'].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-init_per_testcase(_Case, Config) ->
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventDomainAdmin'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventDomainAdmin'(_) ->
- ?match("CycleDetection", 'CosEventDomainAdmin':'CycleDetection'()),
- ?match(0, 'CosEventDomainAdmin':'AuthorizeCycles'()),
- ?match(1, 'CosEventDomainAdmin':'ForbidCycles'()),
- ?match("DiamondDetection", 'CosEventDomainAdmin':'DiamondDetection'()),
- ?match(0, 'CosEventDomainAdmin':'AuthorizeDiamonds'()),
- ?match(1, 'CosEventDomainAdmin':'ForbidDiamonds'()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventDomainAdmin_DiamondSeq'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventDomainAdmin_DiamondSeq'(_) ->
- ?match(true, orber_tc:check_tc('CosEventDomainAdmin_DiamondSeq':tc())),
- ?match("IDL:omg.org/CosEventDomainAdmin/DiamondSeq:1.0",
- 'CosEventDomainAdmin_DiamondSeq':id()),
- ?match("CosEventDomainAdmin_DiamondSeq",
- 'CosEventDomainAdmin_DiamondSeq':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventDomainAdmin_AlreadyExists'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventDomainAdmin_AlreadyExists'(_) ->
- ?match(true, orber_tc:check_tc('CosEventDomainAdmin_AlreadyExists':tc())),
- ?match("IDL:omg.org/CosEventDomainAdmin/AlreadyExists:1.0",
- 'CosEventDomainAdmin_AlreadyExists':id()),
- ?match("CosEventDomainAdmin_AlreadyExists",
- 'CosEventDomainAdmin_AlreadyExists':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventDomainAdmin_DomainIDSeq'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventDomainAdmin_DomainIDSeq'(_) ->
- ?match(true, orber_tc:check_tc('CosEventDomainAdmin_DomainIDSeq':tc())),
- ?match("IDL:omg.org/CosEventDomainAdmin/DomainIDSeq:1.0",
- 'CosEventDomainAdmin_DomainIDSeq':id()),
- ?match("CosEventDomainAdmin_DomainIDSeq",
- 'CosEventDomainAdmin_DomainIDSeq':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventDomainAdmin_Connection'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventDomainAdmin_Connection'(_) ->
- ?match(true, orber_tc:check_tc('CosEventDomainAdmin_Connection':tc())),
- ?match("IDL:omg.org/CosEventDomainAdmin/Connection:1.0",
- 'CosEventDomainAdmin_Connection':id()),
- ?match("CosEventDomainAdmin_Connection",
- 'CosEventDomainAdmin_Connection':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventDomainAdmin_ConnectionIDSeq'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventDomainAdmin_ConnectionIDSeq'(_) ->
- ?match(true, orber_tc:check_tc('CosEventDomainAdmin_ConnectionIDSeq':tc())),
- ?match("IDL:omg.org/CosEventDomainAdmin/ConnectionIDSeq:1.0",
- 'CosEventDomainAdmin_ConnectionIDSeq':id()),
- ?match("CosEventDomainAdmin_ConnectionIDSeq",
- 'CosEventDomainAdmin_ConnectionIDSeq':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventDomainAdmin_ConnectionNotFound'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventDomainAdmin_ConnectionNotFound'(_) ->
- ?match(true, orber_tc:check_tc('CosEventDomainAdmin_ConnectionNotFound':tc())),
- ?match("IDL:omg.org/CosEventDomainAdmin/ConnectionNotFound:1.0",
- 'CosEventDomainAdmin_ConnectionNotFound':id()),
- ?match("CosEventDomainAdmin_ConnectionNotFound",
- 'CosEventDomainAdmin_ConnectionNotFound':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventDomainAdmin_CycleCreationForbidden'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventDomainAdmin_CycleCreationForbidden'(_) ->
- ?match(true, orber_tc:check_tc('CosEventDomainAdmin_CycleCreationForbidden':tc())),
- ?match("IDL:omg.org/CosEventDomainAdmin/CycleCreationForbidden:1.0",
- 'CosEventDomainAdmin_CycleCreationForbidden':id()),
- ?match("CosEventDomainAdmin_CycleCreationForbidden",
- 'CosEventDomainAdmin_CycleCreationForbidden':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventDomainAdmin_CycleSeq'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventDomainAdmin_CycleSeq'(_) ->
- ?match(true, orber_tc:check_tc('CosEventDomainAdmin_CycleSeq':tc())),
- ?match("IDL:omg.org/CosEventDomainAdmin/CycleSeq:1.0",
- 'CosEventDomainAdmin_CycleSeq':id()),
- ?match("CosEventDomainAdmin_CycleSeq",
- 'CosEventDomainAdmin_CycleSeq':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventDomainAdmin_DiamondCreationForbidden'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventDomainAdmin_DiamondCreationForbidden'(_) ->
- ?match(true, orber_tc:check_tc('CosEventDomainAdmin_DiamondCreationForbidden':tc())),
- ?match("IDL:omg.org/CosEventDomainAdmin/DiamondCreationForbidden:1.0",
- 'CosEventDomainAdmin_DiamondCreationForbidden':id()),
- ?match("CosEventDomainAdmin_DiamondCreationForbidden",
- 'CosEventDomainAdmin_DiamondCreationForbidden':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventDomainAdmin_DomainNotFound'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventDomainAdmin_DomainNotFound'(_) ->
- ?match(true, orber_tc:check_tc('CosEventDomainAdmin_DomainNotFound':tc())),
- ?match("IDL:omg.org/CosEventDomainAdmin/DomainNotFound:1.0",
- 'CosEventDomainAdmin_DomainNotFound':id()),
- ?match("CosEventDomainAdmin_DomainNotFound",
- 'CosEventDomainAdmin_DomainNotFound':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventDomainAdmin_MemberIDSeq'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventDomainAdmin_MemberIDSeq'(_) ->
- ?match(true, orber_tc:check_tc('CosEventDomainAdmin_MemberIDSeq':tc())),
- ?match("IDL:omg.org/CosEventDomainAdmin/MemberIDSeq:1.0",
- 'CosEventDomainAdmin_MemberIDSeq':id()),
- ?match("CosEventDomainAdmin_MemberIDSeq",
- 'CosEventDomainAdmin_MemberIDSeq':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventDomainAdmin_RouteSeq'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventDomainAdmin_RouteSeq'(_) ->
- ?match(true, orber_tc:check_tc('CosEventDomainAdmin_RouteSeq':tc())),
- ?match("IDL:omg.org/CosEventDomainAdmin/RouteSeq:1.0",
- 'CosEventDomainAdmin_RouteSeq':id()),
- ?match("CosEventDomainAdmin_RouteSeq",
- 'CosEventDomainAdmin_RouteSeq':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventDomainAdmin_EventDomainFactory'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventDomainAdmin_EventDomainFactory'(_) ->
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomainFactory':oe_tc(create_event_domain)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomainFactory':oe_tc(get_all_domains)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomainFactory':oe_tc(get_event_domain)),
- ?match(undefined, 'CosEventDomainAdmin_EventDomainFactory':oe_tc(undefined)),
- ?match([_|_], 'CosEventDomainAdmin_EventDomainFactory':oe_get_interface()),
- ?match("IDL:omg.org/CosEventDomainAdmin/EventDomainFactory:1.0",
- 'CosEventDomainAdmin_EventDomainFactory':typeID()),
- check_tc('CosEventDomainAdmin_EventDomainFactory':oe_get_interface()),
- ?match(true, 'CosEventDomainAdmin_EventDomainFactory':oe_is_a('CosEventDomainAdmin_EventDomainFactory':typeID())),
- ?match(false, 'CosEventDomainAdmin_EventDomainFactory':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosEventDomainAdmin_EventDomain'
-%% Description:
-%%-----------------------------------------------------------------
-'CosEventDomainAdmin_EventDomain'(_) ->
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(add_channel)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(get_all_channels)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(get_channel)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(remove_channel)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(add_connection)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(get_all_connections)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(get_connection)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(remove_connection)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(get_offer_channels)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(get_subscription_channels)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(destroy)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(get_cycles)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(get_diamonds)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(set_default_consumer_channel)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(set_default_supplier_channel)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(connect_push_consumer)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(connect_pull_consumer)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(connect_push_supplier)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(connect_pull_supplier)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(connect_structured_push_consumer)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(connect_structured_pull_consumer)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(connect_structured_push_supplier)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(connect_structured_pull_supplier)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(connect_sequence_push_consumer)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(connect_sequence_pull_consumer)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(connect_sequence_push_supplier)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(connect_sequence_pull_supplier)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(connect_push_consumer_with_id)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(connect_pull_consumer_with_id)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(connect_push_supplier_with_id)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(connect_pull_supplier_with_id)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(connect_structured_push_consumer_with_id)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(connect_structured_pull_consumer_with_id)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(connect_structured_push_supplier_with_id)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(connect_structured_pull_supplier_with_id)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(connect_sequence_push_consumer_with_id)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(connect_sequence_pull_consumer_with_id)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(connect_sequence_push_supplier_with_id)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(connect_sequence_pull_supplier_with_id)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(get_qos)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(set_qos)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(validate_qos)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(get_admin)),
- ?nomatch(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(set_admin)),
- ?match(undefined, 'CosEventDomainAdmin_EventDomain':oe_tc(undefined)),
- ?match([_|_], 'CosEventDomainAdmin_EventDomain':oe_get_interface()),
- ?match("IDL:omg.org/CosEventDomainAdmin/EventDomain:1.0",
- 'CosEventDomainAdmin_EventDomain':typeID()),
- check_tc('CosEventDomainAdmin_EventDomain':oe_get_interface()),
- ?match(true, 'CosEventDomainAdmin_EventDomain':oe_is_a('CosEventDomainAdmin_EventDomain':typeID())),
- ?match(true, 'CosEventDomainAdmin_EventDomain':oe_is_a('CosNotification_QoSAdmin':typeID())),
- ?match(true, 'CosEventDomainAdmin_EventDomain':oe_is_a('CosNotification_AdminPropertiesAdmin':typeID())),
- ?match(false, 'CosEventDomainAdmin_EventDomain':oe_is_a("wrong")),
- ok.
-
-
-
-%%-----------------------------------------------------------------
-%% MISC functions
-%%-----------------------------------------------------------------
-check_tc([]) ->
- ok;
-check_tc([{Op, {RetType, InParameters, OutParameters}}|T]) ->
- io:format("checked - ~s~n", [Op]),
- lists:all(?checktc(Op), [RetType|InParameters]),
- lists:all(?checktc(Op), OutParameters),
- check_tc(T).
-
-
diff --git a/lib/cosEventDomain/vsn.mk b/lib/cosEventDomain/vsn.mk
deleted file mode 100644
index 0c063a00f9..0000000000
--- a/lib/cosEventDomain/vsn.mk
+++ /dev/null
@@ -1,2 +0,0 @@
-COSEVENTDOMAIN_VSN = 1.2.2
-
diff --git a/lib/cosFileTransfer/AUTHORS b/lib/cosFileTransfer/AUTHORS
deleted file mode 100644
index 55d8059989..0000000000
--- a/lib/cosFileTransfer/AUTHORS
+++ /dev/null
@@ -1,4 +0,0 @@
-Original Authors:
-Niclas Eklund
-
-Contributors:
diff --git a/lib/cosFileTransfer/Makefile b/lib/cosFileTransfer/Makefile
deleted file mode 100644
index c9c07dcdad..0000000000
--- a/lib/cosFileTransfer/Makefile
+++ /dev/null
@@ -1,42 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2000-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include vsn.mk
-VSN=$(COSFILETRANSFER_VSN)
-
-# ----------------------------------------------------
-# Common Macros
-# ----------------------------------------------------
-# SUB_DIRECTORIES = src test examples doc/src
-# At the moment we don't have any example programs.
-SUB_DIRECTORIES = src doc/src
-
-SPECIAL_TARGETS =
-
-# ----------------------------------------------------
-# Default Subdir Targets
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_subdir.mk
diff --git a/lib/cosFileTransfer/doc/html/.gitignore b/lib/cosFileTransfer/doc/html/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosFileTransfer/doc/html/.gitignore
+++ /dev/null
diff --git a/lib/cosFileTransfer/doc/man3/.gitignore b/lib/cosFileTransfer/doc/man3/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosFileTransfer/doc/man3/.gitignore
+++ /dev/null
diff --git a/lib/cosFileTransfer/doc/man6/.gitignore b/lib/cosFileTransfer/doc/man6/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosFileTransfer/doc/man6/.gitignore
+++ /dev/null
diff --git a/lib/cosFileTransfer/doc/pdf/.gitignore b/lib/cosFileTransfer/doc/pdf/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosFileTransfer/doc/pdf/.gitignore
+++ /dev/null
diff --git a/lib/cosFileTransfer/doc/src/CosFileTransfer.gif b/lib/cosFileTransfer/doc/src/CosFileTransfer.gif
deleted file mode 100644
index 16970ad5ad..0000000000
--- a/lib/cosFileTransfer/doc/src/CosFileTransfer.gif
+++ /dev/null
Binary files differ
diff --git a/lib/cosFileTransfer/doc/src/CosFileTransfer_Directory.xml b/lib/cosFileTransfer/doc/src/CosFileTransfer_Directory.xml
deleted file mode 100644
index da5810521a..0000000000
--- a/lib/cosFileTransfer/doc/src/CosFileTransfer_Directory.xml
+++ /dev/null
@@ -1,69 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosFileTransfer_Directory</title>
- <prepared></prepared>
- <docno></docno>
- <checked></checked>
- <date>2000-11-09</date>
- <rev>PA1</rev>
- </header>
- <module>CosFileTransfer_Directory</module>
- <modulesummary>This module implements the OMG CosFileTransfer::Directory interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosFileTransfer/include/*.hrl").</c></p>
- <p>This module also exports the functions described in:</p>
- <list type="bulleted">
- <item>
- <p><seealso marker="CosFileTransfer_File">CosFileTransfer_File</seealso></p>
- </item>
- <item>
- <p>CosPropertyService_PropertySetDef in the cosProperty application.</p>
- </item>
- </list>
- </description>
- <funcs>
- <func>
- <name>list(Directory, Max) -> Return</name>
- <fsummary>Return a list, of length <c>Max</c>or less, containing Object References representing files or directories contained within the target Directory and a <c>FileIterator</c>or a <c>NIL</c>object</fsummary>
- <type>
- <v>Directory = #objref</v>
- <v>Return = {ok, FileList, FileIterator}</v>
- <v>FileList = [File]</v>
- <v>File = FileIterator = #objref</v>
- </type>
- <desc>
- <p>This operation returns a list, of length <c>Max</c> or less, containing
- Object References representing files or directories contained within
- the target Directory. If the amount of objects found is less than <c>Max</c>
- the returned Iterator will be a <c>NIL</c> object.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosFileTransfer/doc/src/CosFileTransfer_File.xml b/lib/cosFileTransfer/doc/src/CosFileTransfer_File.xml
deleted file mode 100644
index 373c14d1f1..0000000000
--- a/lib/cosFileTransfer/doc/src/CosFileTransfer_File.xml
+++ /dev/null
@@ -1,94 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosFileTransfer_File</title>
- <prepared></prepared>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>2000-11-09</date>
- <rev>PA1</rev>
- </header>
- <module>CosFileTransfer_File</module>
- <modulesummary>This module implements the OMG CosFileTransfer::File interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosFileTransfer/include/*.hrl").</c></p>
- <p>This module also exports the functions described in:</p>
- <list type="bulleted">
- <item>
- <p>CosPropertyService_PropertySetDef in the cosProperty application.</p>
- </item>
- </list>
- </description>
- <funcs>
- <func>
- <name>'_get_name'(File) -> string()</name>
- <fsummary>Return the target object's associated name</fsummary>
- <type>
- <v>File = #objref</v>
- </type>
- <desc>
- <p>This read only attribute represents the target object's associated name.</p>
- </desc>
- </func>
- <func>
- <name>'_get_complete_file_name'(File) -> string()</name>
- <fsummary>Return the target object's associated absolute name.</fsummary>
- <type>
- <v>File = #objref</v>
- </type>
- <desc>
- <p>This read only attribute represents the target object's associated
- absolute name.</p>
- </desc>
- </func>
- <func>
- <name>'_get_parent'(File) -> Directory</name>
- <fsummary>Return the target object's container.</fsummary>
- <type>
- <v>File = Directory = #objref</v>
- </type>
- <desc>
- <p>This read only attribute represents the target object's container.
- In some cases a <c>NIL</c> object will be returned.</p>
- </desc>
- </func>
- <func>
- <name>'_get_associated_session'(File) -> FileTransferSession</name>
- <fsummary>Return the target object's associated <c>FileTransferSession</c></fsummary>
- <type>
- <v>File = FileTransferSession = #objref</v>
- </type>
- <desc>
- <p>This read only attribute represents the target object's associated
- <c>FileTransferSession</c>.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosFileTransfer/doc/src/CosFileTransfer_FileIterator.xml b/lib/cosFileTransfer/doc/src/CosFileTransfer_FileIterator.xml
deleted file mode 100644
index f5c219b9c1..0000000000
--- a/lib/cosFileTransfer/doc/src/CosFileTransfer_FileIterator.xml
+++ /dev/null
@@ -1,86 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>CosFileTransfer_FileIterator</title>
- <prepared></prepared>
- <docno></docno>
- <checked></checked>
- <date>2000-11-09</date>
- <rev>PA1</rev>
- </header>
- <module>CosFileTransfer_FileIterator</module>
- <modulesummary>This module implements the OMG CosFileTransfer::FileIterator interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosFileTransfer/include/*.hrl").</c></p>
- </description>
- <funcs>
- <func>
- <name>next_one(Iterator) -> Return</name>
- <fsummary>Return the next <c>FileWrapper</c>and a boolean which indicate whether the <c>FileWrapper</c>is valid or not.</fsummary>
- <type>
- <v>Iterator = #objref</v>
- <v>Return = {boolean(), #'CosFileTransfer_FileWrapper'{the_file = File file_type = Type}}</v>
- <v>File = #objref</v>
- <v>Type = nfile | ndirectory</v>
- </type>
- <desc>
- <p>This operation returns true if a <c>FileWrapper</c> exists at the
- current position and the out parameter contains a valid <c>File</c>
- reference. If false is returned the out parameter is a non-valid
- <c>FileWrapper</c>.</p>
- </desc>
- </func>
- <func>
- <name>next_n(Iterator, Max) -> Return</name>
- <fsummary>Return a list, of length <c>Max</c>or less, containing <c>FileWrappers</c>and a boolean which indicates if more <c>FileWrappers</c>exists</fsummary>
- <type>
- <v>Iterator = #objref</v>
- <v>Max = unsigned long()</v>
- <v>Return = {boolean(), FileList}</v>
- <v>FileList = [#'CosFileTransfer_FileWrapper'{the_file = File file_type = Type}]</v>
- <v>File = #objref</v>
- <v>Type = nfile | ndirectory</v>
- </type>
- <desc>
- <p>This operation returns true if the requested number of <c>FileWrappers</c>
- can be delivered and there are additional <c>FileWrappers</c>. If false is
- returned a list, of length <c>Max</c> or less, containing the last valid
- <c>FileWrappers</c> associated with the target object.</p>
- </desc>
- </func>
- <func>
- <name>destroy(Iterator) -> ok</name>
- <fsummary>Terminate the target object</fsummary>
- <type>
- <v>Iterator = #objref</v>
- </type>
- <desc>
- <p>This operation terminates the target object.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosFileTransfer/doc/src/CosFileTransfer_FileTransferSession.xml b/lib/cosFileTransfer/doc/src/CosFileTransfer_FileTransferSession.xml
deleted file mode 100644
index 312af3b8c2..0000000000
--- a/lib/cosFileTransfer/doc/src/CosFileTransfer_FileTransferSession.xml
+++ /dev/null
@@ -1,191 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>CosFileTransfer_FileTransferSession</title>
- <prepared></prepared>
- <docno></docno>
- <checked></checked>
- <date>2000-11-09</date>
- <rev>PA1</rev>
- </header>
- <module>CosFileTransfer_FileTransferSession</module>
- <modulesummary>This module implements the OMG CosFileTransfer::FileTransferSession interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosFileTransfer/include/*.hrl").</c></p>
- </description>
- <funcs>
- <func>
- <name>'_get_protocols_supported'(FTS) -> Return</name>
- <fsummary>Return the protocols supported by the target object</fsummary>
- <type>
- <v>FTS = #objref</v>
- <v>Return = [#'CosFileTransfer_ProtocolSupport'{protocol_name=Type, addresses=[Address]}]</v>
- <v>Type = Address = string()</v>
- </type>
- <desc>
- <p>This read only attribute returns the protocols supported by the
- target object.</p>
- </desc>
- </func>
- <func>
- <name>set_directory(FTS, Directory) -> Return</name>
- <fsummary>Change the current working directory of the target object's associated file system</fsummary>
- <type>
- <v>FTS = Directory = #objref</v>
- <v>Return = ok | {'EXCEPTION, E}</v>
- </type>
- <desc>
- <p>Invoking this operation will change the current working directory of
- the target object's associated file system. If fail to do so the
- appropriate exception is raised. </p>
- </desc>
- </func>
- <func>
- <name>create_file(FTS, FileNameList) -> Return</name>
- <fsummary>Create a <c>File</c>Object representing a file which may or may not exist</fsummary>
- <type>
- <v>FTS = #objref</v>
- <v>FileNameList = [string()]</v>
- <v>Return = File | {'EXCEPTION, E}</v>
- <v>File = #objref</v>
- </type>
- <desc>
- <p>This operation creates a <c>File</c> Object representing a file which
- may or may not exist.
- For this operation to be independent of the working directory the
- supplied <c>FileNameList</c> must represent the absolute name.</p>
- </desc>
- </func>
- <func>
- <name>create_directory(FTS, FileNameList) -> Return</name>
- <fsummary>Create a new directory in the target objects associated file systems domain</fsummary>
- <type>
- <v>FTS = #objref</v>
- <v>FileNameList = [string()]</v>
- <v>Return = Directory | {'EXCEPTION, E}</v>
- <v>Directory = #objref</v>
- </type>
- <desc>
- <p>This operation creates a new directory in the target objects associated
- file systems domain. If fail to do so an exception is raised but,
- if successful, a <c>Directory</c> object representing the new
- directory is returned.</p>
- </desc>
- </func>
- <func>
- <name>get_file(FTS, FileNameList) -> Return</name>
- <fsummary>Create a <c>FileWrapper</c>which represents a file or directory</fsummary>
- <type>
- <v>FTS = #objref</v>
- <v>FileNameList = [string()]</v>
- <v>Return = FileWrapper | {'EXCEPTION, E}</v>
- <v>FileWrapper = #'CosFileTransfer_FileWrapper'{the_file = File file_type = Type}</v>
- <v>File = #objref</v>
- <v>Type = nfile | ndirectory</v>
- </type>
- <desc>
- <p>This operation, creates a <c>FileWrapper</c> which represents a file or directory, and
- should be independent of the working Directory,
- i.e., a full path name must be supplied. Furthermore, the file or
- directory represented by the <c>FileNameList</c> must exist.</p>
- </desc>
- </func>
- <func>
- <name>delete(FTS, File) -> Return</name>
- <fsummary>Delete the file or directory, represented by the <c>File</c>object, from the target objects associated file system</fsummary>
- <type>
- <v>FTS = File = #objref</v>
- <v>Return = ok | {'EXCEPTION', E}</v>
- </type>
- <desc>
- <p>This operation removes the file or directory, represented by the <c>File</c>
- object, from the target objects associated file system. If it is a non-empty
- directory or non-existing file or directory an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>transfer(FTS, SourceFile, DestinationFile) -> Return</name>
- <fsummary>Copy the file represented by the <c>SourceFile</c>from the target object's file system to a file in the destination <c>FileTransferSession's</c>file system</fsummary>
- <type>
- <v>FTS = SourceFile = DestinationFile = #objref</v>
- <v>Return = ok | {'EXCEPTION', E}</v>
- </type>
- <desc>
- <p>If the target object's and the <c>DestinationFile's</c> associated
- <c>FileTransferSession's</c> support the same protocol(s) this operation
- will copy the file represented by the <c>SourceFile</c> from the target
- object's file system to a file in the destination
- <c>FileTransferSession's</c> file system. The file is represented by the
- <c>DestinationFile</c> object and may not exist.
- This operation must be invoked on the <c>FileTransferSession</c>
- associated with the <c>SourceFile</c> object.</p>
- </desc>
- </func>
- <func>
- <name>append(FTS, SourceFile, DestinationFile) -> Return</name>
- <fsummary>Append the file represented by the <c>SourceFile</c>from the target object's file system to a file in the destination <c>FileTransferSession's</c>file system</fsummary>
- <type>
- <v>FTS = SourceFile = DestinationFile = #objref</v>
- <v>Return = ok | {'EXCEPTION', E}</v>
- </type>
- <desc>
- <p>This operation behaves almost like the <c>transfer/3</c> operation. The
- difference is that the <c>DestinationFile</c> must exist since the
- <c>SourceFile</c> will be appended to the <c>DestinationFile</c>.</p>
- <p>Currently, it is not possible to use this operation when the target
- object represents FTP.</p>
- </desc>
- </func>
- <func>
- <name>insert(FTS, SourceFile, DestinationFile, Offset) -> Return</name>
- <fsummary>Insert the <c>SourceFile</c>into the <c>DestinationFile</c> <c>Offset</c>bytes from the start of the file</fsummary>
- <type>
- <v>FTS = SourceFile = DestinationFile = #objref</v>
- <v>Offset = long()</v>
- <v>Return = ok | {'EXCEPTION', E}</v>
- </type>
- <desc>
- <p>This operation behaves almost like the <c>append/3</c> operation. The
- difference is that the <c>SourceFile</c> will be inserted into the
- <c>DestinationFile</c> <c>Offset</c> bytes from the start of the file.</p>
- <p>Currently, it is not possible to use this operation when the target
- object represents FTP.</p>
- </desc>
- </func>
- <func>
- <name>logout(FTS) -> ok</name>
- <fsummary>Terminate the target object and close the connection to the file system it represents</fsummary>
- <type>
- <v>FTS = #objref</v>
- </type>
- <desc>
- <p>This operation terminates the target object and closes the connection
- to the file system it represents.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosFileTransfer/doc/src/CosFileTransfer_VirtualFileSystem.xml b/lib/cosFileTransfer/doc/src/CosFileTransfer_VirtualFileSystem.xml
deleted file mode 100644
index 701e56e660..0000000000
--- a/lib/cosFileTransfer/doc/src/CosFileTransfer_VirtualFileSystem.xml
+++ /dev/null
@@ -1,83 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosFileTransfer_VirtualFileSystem</title>
- <prepared></prepared>
- <docno></docno>
- <checked></checked>
- <date>2000-11-09</date>
- <rev>PA1</rev>
- </header>
- <module>CosFileTransfer_VirtualFileSystem</module>
- <modulesummary>This module implements the OMG CosFileTransfer::VirtualFileSystem interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosFileTransfer/include/*.hrl").</c></p>
- </description>
- <funcs>
- <func>
- <name>'_get_file_system_type'(VFS) -> Return</name>
- <fsummary>Return the target object's associated file system</fsummary>
- <type>
- <v>VFS = #objref</v>
- <v>Return = 'FTP' | 'NATIVE'</v>
- </type>
- <desc>
- <p>This read only attribute represents the target object's associated
- file system.</p>
- </desc>
- </func>
- <func>
- <name>'_get_supported_content_types'(VFS) -> Return</name>
- <fsummary>Return the target object's supported content types.</fsummary>
- <type>
- <v>VFS = #objref</v>
- <v>Return = </v>
- </type>
- <desc>
- <p>This read only attribute represents the target object's supported
- content types.</p>
- </desc>
- </func>
- <func>
- <name>login(VFS, User, Password, Account) -> Return</name>
- <fsummary>Create a new instance of a <c>FileTransferSession</c>and a <c>Directory</c></fsummary>
- <type>
- <v>VFS = #objref</v>
- <v>User = Password = Account = string()</v>
- <v>Return = {FileTransferSession, Directory} | {'EXCEPTION', E}</v>
- <v>FileTransferSession = Directory = #objref</v>
- </type>
- <desc>
- <p>This operation creates a new instance of a <c>FileTransferSession</c>
- and a <c>Directory</c>. The later represents the current working
- directory of the returned <c>FileTransferSession</c>.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosFileTransfer/doc/src/Makefile b/lib/cosFileTransfer/doc/src/Makefile
deleted file mode 100644
index fcaa88c1e2..0000000000
--- a/lib/cosFileTransfer/doc/src/Makefile
+++ /dev/null
@@ -1,142 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2000-2017. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../../vsn.mk
-VSN=$(COSFILETRANSFER_VSN)
-APPLICATION=cosFileTransfer
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-XML_APPLICATION_FILES = ref_man.xml
-XML_REF3_FILES = \
- cosFileTransferApp.xml \
- CosFileTransfer_Directory.xml \
- CosFileTransfer_File.xml \
- CosFileTransfer_VirtualFileSystem.xml \
- CosFileTransfer_FileTransferSession.xml \
- CosFileTransfer_FileIterator.xml
-
-XML_PART_FILES = \
- part.xml
-XML_CHAPTER_FILES = \
- ch_contents.xml \
- ch_introduction.xml \
- ch_install.xml \
- ch_system.xml \
- ch_example.xml \
- notes.xml
-
-BOOK_FILES = book.xml
-
-XML_FILES = $(BOOK_FILES) $(XML_APPLICATION_FILES) $(XML_REF3_FILES) \
- $(XML_PART_FILES) $(XML_CHAPTER_FILES)
-
-TECHNICAL_DESCR_FILES =
-
-GIF_FILES = \
- CosFileTransfer.gif
-
-PS_FILES =
-
-# ----------------------------------------------------
-
-INTERNAL_HTML_FILES = $(TECHNICAL_DESCR_FILES:%.xml=$(HTMLDIR)/%.html)
-
-HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \
- $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html) \
- $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html)
-
-
-INFO_FILE = ../../info
-
-EXTRA_FILES = \
- $(DEFAULT_GIF_FILES) \
- $(DEFAULT_HTML_FILES) \
- $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html)
-
-MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-
-HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
-
-TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-XML_FLAGS +=
-DVIPS_FLAGS +=
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-$(HTMLDIR)/%.gif: %.gif
- $(INSTALL_DATA) $< $@
-
-docs: pdf html man
-
-$(TOP_PDF_FILE): $(XML_FILES)
-
-pdf: $(TOP_PDF_FILE)
-
-html: gifs $(HTML_REF_MAN_FILE)
-
-clean clean_docs:
- rm -rf $(HTMLDIR)/*
- rm -f $(MAN3DIR)/*
- rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
- rm -f errs core *~
-
-man: $(MAN3_FILES)
-
-gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
-
-$(INDEX_TARGET): $(INDEX_SRC)
- sed -e 's;%VSN%;$(VSN);' $(INDEX_SRC) > $(INDEX_TARGET)
-
-debug opt:
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_docs_spec: docs
- $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
- $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
- $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
- $(INSTALL_DATA) $(HTMLDIR)/* \
- "$(RELSYSDIR)/doc/html"
- $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
- $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
- $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
-
-release_spec:
diff --git a/lib/cosFileTransfer/doc/src/book.xml b/lib/cosFileTransfer/doc/src/book.xml
deleted file mode 100644
index 9a9ec3d0a2..0000000000
--- a/lib/cosFileTransfer/doc/src/book.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE book SYSTEM "book.dtd">
-
-<book xmlns:xi="http://www.w3.org/2001/XInclude">
- <header titlestyle="normal">
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosFileTransfer</title>
- <prepared></prepared>
- <docno></docno>
- <date>2000-08-24</date>
- <rev>1.0</rev>
- </header>
- <insidecover>
- </insidecover>
- <pagetext>cosFileTransfer</pagetext>
- <preamble>
- <contents level="2"></contents>
- </preamble>
- <parts lift="no">
- <xi:include href="part.xml"/>
- </parts>
- <applications>
- <xi:include href="ref_man.xml"/>
- </applications>
- <releasenotes>
- <xi:include href="notes.xml"/>
- </releasenotes>
- <listofterms></listofterms>
- <index></index>
-</book>
-
diff --git a/lib/cosFileTransfer/doc/src/ch_contents.xml b/lib/cosFileTransfer/doc/src/ch_contents.xml
deleted file mode 100644
index bd4ed5116f..0000000000
--- a/lib/cosFileTransfer/doc/src/ch_contents.xml
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>The cosFileTransfer Application</title>
- <prepared></prepared>
- <docno></docno>
- <date>2000-08-24</date>
- <rev>1.0</rev>
- <file>ch_contents.xml</file>
- </header>
-
- <section>
- <title>Content Overview</title>
- <p>The cosFileTransfer documentation is divided into three sections:
- </p>
- <list type="bulleted">
- <item>
- <p>PART ONE - The User's Guide
- <br></br>
-Description of the cosFileTransfer Application including
- services and a small tutorial demonstrating
- the development of a simple service.</p>
- </item>
- <item>
- <p>PART TWO - Release Notes
- <br></br>
-A concise history of cosFileTransfer.</p>
- </item>
- <item>
- <p>PART THREE - The Reference Manual
- <br></br>
- A quick reference guide, including a
- brief description, to all the functions available in cosFileTransfer.</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Brief description of the User's Guide</title>
- <p>The User's Guide contains the following parts:</p>
- <list type="bulleted">
- <item>
- <p>cosFileTransfer overview</p>
- </item>
- <item>
- <p>cosFileTransfer installation</p>
- </item>
- <item>
- <p>A tutorial example</p>
- </item>
- </list>
- </section>
-</chapter>
-
diff --git a/lib/cosFileTransfer/doc/src/ch_example.xml b/lib/cosFileTransfer/doc/src/ch_example.xml
deleted file mode 100644
index 7e3c65eedd..0000000000
--- a/lib/cosFileTransfer/doc/src/ch_example.xml
+++ /dev/null
@@ -1,96 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosFileTransfer Examples</title>
- <prepared></prepared>
- <docno></docno>
- <date>2000-08-24</date>
- <rev>A</rev>
- <file>ch_example.xml</file>
- </header>
-
- <section>
- <title>A tutorial on how to create a simple service</title>
-
- <section>
- <title>Initiate the application</title>
- <p>To use the complete cosFileTransfer application cosProperty
- must be installed.</p>
- </section>
-
- <section>
- <title>How to run everything</title>
- <p>Below is a short transcript on how to run cosFileTransfer. </p>
- <code type="none">
-
-%% Start Mnesia and Orber
-mnesia:delete_schema([node()]),
-mnesia:create_schema([node()]),
-orber:install([node()]),
-mnesia:start(),
-orber:start(),
-
-%% The File Transfer Service depends on the cosProperty
-%% application. Hence, we must install cosProperty first.
-%% It's NOT necessary to invoke cosProperty:install_db().
-cosProperty:install(),
-
-%% Install File Transfer Service in the IFR.
-cosFileTransfer:install(),
-
-%% Now start the application and necessary services.
-cosFileTransfer:start(),
-
-%% Create two Virtual File Systems respectively representing an FTP-
-%% and the local NFS file system.
-VFSFTP = cosFileTransferApp:create_VFS('FTP', [], FTPHost, 21),
-VFSNATIVE = cosFileTransferApp:
- create_VFS({'NATIVE', 'cosFileTransferNATIVE_file'},
- [], MyLocalHost, 0),
-
-%% Login to each system.
-{FSFTP, DirFTP} = 'CosFileTransfer_VirtualFileSystem':
- login(VFSFTP, "myId", "myPwd", "myAccount"),
-{FSNATIVE, DirNATIVE} = 'CosFileTransfer_VirtualFileSystem':
- login(VFSNATIVE, "myId", "myPwd", "myAccount"),
-
-%% If we want to copy a file from the NFS to the FTP we must first
-%% create a File object which contains its attributes.
-Target = 'CosFileTransfer_FileTransferSession':create_file(FSFTP,
- ["/", "ftp", "incoming", "targetFile"])),
-
- #'CosFileTransfer_FileWrapper'{the_file = Dir} =
-%% Lookup the file we want to copy.
-FileWrapper = 'CosFileTransfer_FileTransferSession':get_file(FSNATIVE,
- ["/", "home", "myId", "sourceFile"]),
-Source = FileWrapper#'CosFileTransfer_FileWrapper'.the_file,
-
-%% Now we are ready to transfer the file. Please note that we most
-%% call the source Session object.
-'CosFileTransfer_FileTransferSession':transfer(FSNATIVE, Source, Target),
- </code>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosFileTransfer/doc/src/ch_install.xml b/lib/cosFileTransfer/doc/src/ch_install.xml
deleted file mode 100644
index 9681f98b45..0000000000
--- a/lib/cosFileTransfer/doc/src/ch_install.xml
+++ /dev/null
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Installing cosFileTransfer</title>
- <prepared></prepared>
- <docno></docno>
- <date>2000-08-24</date>
- <rev></rev>
- <file>ch_install.xml</file>
- </header>
-
- <section>
- <title>Installation Process </title>
- <p>This chapter describes how to install
- <seealso marker="cosFileTransferApp">cosFileTransferApp</seealso> in an Erlang Environment.
- </p>
-
- <section>
- <title>Preparation</title>
- <p>Before starting the installation process for cosFileTransfer,
- the application <c>Orber</c> must be running and <c>cosProperty</c> installed by
- using <c>cosProperty:install()</c>. Please note that it is <em>NOT</em> necessary
- to use <c>cosProperty:install_db()</c> for running the cosFileTransfer application.</p>
- </section>
-
- <section>
- <title>Configuration</title>
- <p>When starting the cosFileTransfer application the following configuration parameters
- can be used:</p>
- <list type="bulleted">
- <item><em>buffert_size</em> - default is 64000. This option determine
- how many bytes will be read at a time when transferring files.</item>
- </list>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosFileTransfer/doc/src/ch_introduction.xml b/lib/cosFileTransfer/doc/src/ch_introduction.xml
deleted file mode 100644
index 67616b0a39..0000000000
--- a/lib/cosFileTransfer/doc/src/ch_introduction.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Introduction to cosFileTransfer</title>
- <prepared></prepared>
- <docno></docno>
- <date>2000-08-24</date>
- <rev></rev>
- <file>ch_introduction.xml</file>
- </header>
-
- <section>
- <title>Overview</title>
- <p>The cosFileTransfer application is a FileTransfer Service compliant with the
- <url href="http://www.omg.org">OMG</url> Service CosFileTransfer.
- </p>
-
- <section>
- <title>Purpose and Dependencies</title>
- <p>If a Virtual File System is started as 'FTP', the inets-2.5.4 application,
- or later, must be installed.</p>
- <p><em>cosFileTransfer</em> is dependent on <em>Orber</em>, which provides CORBA functionality in an Erlang environment,
- and <em>cosProperty</em>.</p>
- </section>
-
- <section>
- <title>Prerequisites</title>
- <p>To fully understand the concepts presented in the
- documentation, it is recommended that the user is familiar
- with distributed programming, CORBA, the Orber and cosProperty applications.
- </p>
- <p>Recommended reading includes <em>CORBA, Fundamentals and Programming - Jon Siegel</em> and <em>Open Telecom Platform Documentation Set</em>. It is also helpful to have read <em>Concurrent Programming in Erlang</em>.</p>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosFileTransfer/doc/src/ch_system.xml b/lib/cosFileTransfer/doc/src/ch_system.xml
deleted file mode 100644
index 377ec1fa49..0000000000
--- a/lib/cosFileTransfer/doc/src/ch_system.xml
+++ /dev/null
@@ -1,138 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2001</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Using the File Transfer Service</title>
- <prepared></prepared>
- <docno></docno>
- <date>2001-08-07</date>
- <rev></rev>
- <file>ch_system.xml</file>
- </header>
-
- <section>
- <title>Overview</title>
- <p>This chapter describes how two File Transfer Service applications interact.</p>
-
- <section>
- <title>Components</title>
- <p>There are several ways the OMG File Transfer Service can be used.
- Below one scenario is visualized: </p>
- <marker id="CosFileTransfer"></marker>
- <image file="CosFileTransfer.gif">
- <icaption>Figure 1: The File Transfer Service Components.</icaption>
- </image>
- <list type="bulleted">
- <item><em>Source ORB:</em> this is the ORB we want to transfer a file from/via and it holds
- an object reference to a
- <seealso marker="CosFileTransfer_VirtualFileSystem">Virtual File System (VFS)</seealso> which,
- in this example, represents an FTP server.</item>
- <item><em>Target ORB:</em> the goal may be, for example, to transfer a new file or append to an
- existing file placed at the location that this ORB's <c>VFS</c> represents.
- In this scenario it is the local disk or the NFS.</item>
- <item><em>Transport Protocol:</em> initially the ORB's, i.e., target and source, communicate via
- normal <c>CORBA</c> requests to determine whether or not they can communicate. If the
- File Transfer Service's have one, or more, <c>Transport Protocol</c> in common the data
- will be streamed using this protocol. The cosFileTransfer application currently supports
- <c>TCP/IP</c> and <c>SSL</c>.</item>
- </list>
- <p>Which type of file system the <c>VFS</c> is supposed to represent is determined
- by the options given when creating it, which is also how one determine which
- <c>Transport Protocol</c> to use. Hence, the source and target <c>VFS</c> described above
- can be started by invoking, respectively, the following operations:</p>
- <code type="none">
-1> SVFS = cosFileTransferApp:create_VFS('FTP', [], Host, 21, [{protocol, tcp}]),
-2> TVFS = cosFileTransferApp:create_VFS({'NATIVE', 'cosFileTransferNATIVE_file'},
- [], OtherHost, 0, [{protocol, tcp}]),
- </code>
- <p>Naturally can any combination of <c>VFS</c>-types be used and it is also possible
- to use own drivers, i.e., <c>{'NATIVE', 'MyDriver'}</c>.</p>
- <p>After creating necessary <c>VFS's</c> we can login in and perform operations
- on files and directories residing on each file system.</p>
- </section>
-
- <section>
- <title>How To Use SSL</title>
- <p>To be able to use <c>SSL</c> as transport protocol a few configuration
- parameters must be set. The required parameters depend on if Orber is
- the target or/and the source ORB. However, the SSL_CERT_FILE variable
- must be defined in both cases.</p>
- <p>Setting of a CA certificate file with an option does not work due to
- weaknesses in the SSLeay package. A work-around in the ssl application is
- to set the OS environment variable SSL_CERT_FILE before SSL is started.
- However, then the CA certificate file will be global for all connections
- (both incoming and outgoing calls).</p>
-
- <section>
- <title>Configurations when cosFileTransfer is Used as Target</title>
- <p>The following three configuration variables can be used to configure
- cosFileTransfer's SSL target behavior.</p>
- <list type="bulleted">
- <item><em>ssl_server_certfile</em> which is a path to a file containing a
- chain of PEM encoded certificates for cosFileTransfer as target.</item>
- <item><em>ssl_server_verify</em> which specifies type of verification:
- 0 = do not verify peer; 1 = verify peer, verify client once, 2 =
- verify peer, verify client once, fail if no peer certificate.
- The default value is 0.</item>
- <item><em>ssl_server_depth</em> which specifies verification depth, i.e.
- how far in a chain of certificates the verification process shall
- proceed before the verification is considered successful. The
- default value is 1. </item>
- </list>
- <p>There also exist a number of API functions for accessing the values of
- these variables:</p>
- <list type="bulleted">
- <item>cosFileTransferApp:ssl_server_certfile/0</item>
- <item>cosFileTransferApp:ssl_server_verify/0</item>
- <item>cosFileTransferApp:ssl_server_depth/0</item>
- </list>
- </section>
-
- <section>
- <title>Configurations when cosFileTransfer is used as Source</title>
- <p>Below is the list of configuration variables used when cosFileTransfer
- act as the source application.</p>
- <list type="bulleted">
- <item><em>ssl_client_certfile</em> which is a path to a file containing a
- chain of PEM encoded certificates used in outgoing calls.</item>
- <item><em>ssl_client_verify</em> which specifies type of verification:
- 0 = do not verify peer; 1 = verify peer, verify client once, 2 =
- verify peer, verify client once, fail if no peer certificate.
- The default value is 0.</item>
- <item><em>ssl_client_depth</em> which specifies verification depth, i.e.
- how far in a chain of certificates the verification process shall
- proceed before the verification is considered successful. The
- default value is 1. </item>
- </list>
- <p>There also exist a number of API functions for accessing the values of
- these variables in the client processes:</p>
- <list type="bulleted">
- <item>cosFileTransferApp:ssl_client_certfile/0</item>
- <item>cosFileTransferApp:ssl_client_verify/0</item>
- <item>cosFileTransferApp:ssl_client_depth/0</item>
- </list>
- </section>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosFileTransfer/doc/src/cosFileTransferApp.xml b/lib/cosFileTransfer/doc/src/cosFileTransferApp.xml
deleted file mode 100644
index ae7b4f1ec5..0000000000
--- a/lib/cosFileTransfer/doc/src/cosFileTransferApp.xml
+++ /dev/null
@@ -1,173 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosFileTransferApp</title>
- <prepared></prepared>
- <docno></docno>
- <checked></checked>
- <date>2000-08-24</date>
- <rev>PA1</rev>
- </header>
- <module>cosFileTransferApp</module>
- <modulesummary>The main module of the cosFileTransfer application.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosFileTransfer/include/*.hrl").</c></p>
- <p>This module contains the functions for starting and stopping the application.</p>
- </description>
- <funcs>
- <func>
- <name>install() -> Return</name>
- <fsummary>Install the cosFileTransfer application</fsummary>
- <type>
- <v>Return = ok | {'EXIT', Reason}</v>
- </type>
- <desc>
- <p>This operation installs the cosFileTransfer application. Note, the
- <c>cosProperty</c> application must be installed prior to invoking this
- operation.</p>
- </desc>
- </func>
- <func>
- <name>uninstall() -> Return</name>
- <fsummary>Uninstall the cosFileTransfer application</fsummary>
- <type>
- <v>Return = ok | {'EXIT', Reason}</v>
- </type>
- <desc>
- <p>This operation uninstalls the cosFileTransfer application.</p>
- </desc>
- </func>
- <func>
- <name>start() -> Return</name>
- <fsummary>Start the cosFileTransfer application</fsummary>
- <type>
- <v>Return = ok | {error, Reason}</v>
- </type>
- <desc>
- <p>This operation starts the cosFileTransfer application.</p>
- </desc>
- </func>
- <func>
- <name>stop() -> Return</name>
- <fsummary>Stop the cosFileTransfer application</fsummary>
- <type>
- <v>Return = ok | {error, Reason}</v>
- </type>
- <desc>
- <p>This operation stops the cosFileTransfer application.</p>
- </desc>
- </func>
- <func>
- <name>create_VFS(Type, Content, Host, Port [,Options]) -> Return</name>
- <fsummary>Create a new instance of a Virtual File System</fsummary>
- <type>
- <v>Type = 'FTP' | {'NATIVE', 'cosFileTransferNATIVE_file'} | {'NATIVE', MyModule}</v>
- <v>Content = []</v>
- <v>Host = string(), e.g. "myHost@myServer" or "012.345.678.910"</v>
- <v>Port = integer()</v>
- <v>Options = [Option]</v>
- <v>Option = {protocol, Protocol} | {connect_timeout, Seconds}</v>
- <v>Protocol = tcp | ssl</v>
- <v>Return = VFS | {'EXCEPTION, E}</v>
- <v>VFS = #objref</v>
- </type>
- <desc>
- <p>This operation creates a new instance of a Virtual File System. The
- <c>Type</c> parameter determines which type we want the VFS to represent.
- 'FTP' maps to the <c>INETS</c> ftp implementation, while
- {'NATIVE', 'cosFileTransferNATIVE_file'} uses the <c>file</c> module.
- It is also possible to implement own mappings which are activated by
- supplying {'NATIVE', MyModule}. The MyModule module must export the same
- functions and behave in the same way as the INETS ftp module, and
- an operation named <c>open(Host, Port)</c>, which shall return
- <c>{ok, Pid}</c> or <c>{error, Reason}</c>.</p>
- <p>If no <c>Options</c> are supplied the default setting will be
- used, i.e., tcp and 60 seconds.</p>
- <p>The <c>Content</c> parameter is currently ignored by must be supplied
- as an empty list.</p>
- </desc>
- </func>
- <func>
- <name>ssl_server_certfile() -> string()</name>
- <fsummary>Display the path to the target certificate</fsummary>
- <desc>
- <p>This function returns a path to a file containing a chain of PEM encoded
- certificates for the cosFileTransfer as target.
- This is configured by setting the application variable
- <em>ssl_server_certfile</em>.</p>
- </desc>
- </func>
- <func>
- <name>ssl_client_certfile() -> string()</name>
- <fsummary>Display the path to the client certificate</fsummary>
- <desc>
- <p>This function returns a path to a file containing a chain of PEM encoded
- certificates used in outgoing calls.
- The default value is configured by setting the application variable
- <em>ssl_client_certfile</em>.</p>
- </desc>
- </func>
- <func>
- <name>ssl_server_verify() -> 0 | 1 | 2</name>
- <fsummary>Display the SSL verification type for incoming calls</fsummary>
- <desc>
- <p>This function returns the type of verification used by SSL during authentication of the other
- peer for incoming calls.
- It is configured by setting the application variable
- <em>ssl_server_verify</em>.</p>
- </desc>
- </func>
- <func>
- <name>ssl_client_verify() -> 0 | 1 | 2</name>
- <fsummary>Display the SSL verification type for outgoing calls</fsummary>
- <desc>
- <p>This function returns the type of verification used by SSL during authentication of the other
- peer for outgoing calls.
- The default value is configured by setting the application variable
- <em>ssl_client_verify</em>.</p>
- </desc>
- </func>
- <func>
- <name>ssl_server_depth() -> int()</name>
- <fsummary>Display the SSL verification depth for incoming calls</fsummary>
- <desc>
- <p>This function returns the SSL verification depth for incoming calls.
- It is configured by setting the application variable
- <em>ssl_server_depth</em>.</p>
- </desc>
- </func>
- <func>
- <name>ssl_client_depth() -> int()</name>
- <fsummary>Display the SSL verification depth for outgoing calls</fsummary>
- <desc>
- <p>This function returns the SSL verification depth for outgoing calls.
- The default value is configured by setting the application variable
- <em>ssl_client_depth</em>.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosFileTransfer/doc/src/notes.xml b/lib/cosFileTransfer/doc/src/notes.xml
deleted file mode 100644
index e0b4bdf64b..0000000000
--- a/lib/cosFileTransfer/doc/src/notes.xml
+++ /dev/null
@@ -1,379 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosFileTransfer Release Notes</title>
- <prepared></prepared>
- <docno></docno>
- <checked></checked>
- <date>2000-08-24</date>
- <rev>A</rev>
- <file>notes.xml</file>
- </header>
-
- <section><title>cosFileTransfer 1.2.2</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> Removed all old unused files in the documentation.
- </p>
- <p>
- Own Id: OTP-14475 Aux Id: ERL-409, PR-1493 </p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosFileTransfer 1.2.1</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Internal changes</p>
- <p>
- Own Id: OTP-13551</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosFileTransfer 1.2</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> Remove the usage of erlang:now() from all Corba
- applications and use the new rand module instead of
- random. </p>
- <p>
- Own Id: OTP-12687</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosFileTransfer 1.1.16</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> The default encoding of Erlang files has been changed
- from ISO-8859-1 to UTF-8. </p> <p> The encoding of XML
- files has also been changed to UTF-8. </p>
- <p>
- Own Id: OTP-10907</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosFileTransfer 1.1.15</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> Postscript files no longer needed for the generation
- of PDF files have been removed. </p>
- <p>
- Own Id: OTP-11016</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosFileTransfer 1.1.14</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Misc build updates</p>
- <p>
- Own Id: OTP-10784</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosFileTransfer 1.1.13</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>Erlang/OTP can now be built using parallel make if you
- limit the number of jobs, for instance using '<c>make
- -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not
- work at the moment because of some missing
- dependencies.</p>
- <p>
- Own Id: OTP-9451</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosFileTransfer 1.1.12</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> XML files have been corrected. </p>
- <p>
- Own Id: OTP-9550 Aux Id: OTP-9541 </p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section>
- <title>cosFileTransfer 1.1.11</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- Removed superfluous usage of shy in the documentation since it can cause problem if
- a buggy tool is used.</p>
- <p>
- Own Id: OTP-9319 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosFileTransfer 1.1.10</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- Removed obsolete SSL dependency.</p>
- <p>
- Own Id: OTP-8374 Aux Id:</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>The documentation EIX file was not generated.</p>
- <p>Own id: OTP-8355 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosFileTransfer 1.1.9</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- The documentation is now built with open source tools (xsltproc and fop)
- that exists on most platforms. One visible change is that the frames are removed.</p>
- <p>
- Own Id: OTP-8201 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosFileTransfer 1.1.8</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Obsolete guards, e.g. record vs is_record, has been changed
- to avoid compiler warnings.</p>
- <p>Own id: OTP-7987</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosFileTransfer 1.1.7</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Updated file headers.</p>
- <p>Own id: OTP-7837</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosFileTransfer 1.1.6</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Documentation source included in open source releases.</p>
- <p>Own id: OTP-7595</p>
- </item>
- </list>
- </section>
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>When using predefined native file copy the return values from
- file operation was not handled correctly.</p>
- <p>Own id: OTP-7599</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosFileTransfer 1.1.5</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>CosFileTransfer now uses the changed Inets API.</p>
- <p>Own id: OTP-7020</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosFileTransfer 1.1.4</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>The documentation source has been converted from SGML to XML.</p>
- <p>Own id: OTP-6754</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosFileTransfer 1.1.3</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Minor Makefile changes.</p>
- <p>Own id: OTP-6701</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosFileTransfer 1.1.2</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Due to changed behavior of the ftp client a few changes
- has been made.</p>
- <p>Own id: OTP-5135</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosFileTransfer 1.1.1</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>Depending on which ftp server is used, the operation
- CosFileTransfer::Directory::list could fail.</p>
- <p>Own id: OTP-4954</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosFileTransfer 1.1</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>The stub/skeleton-files generated by IC have been improved,
- i.e., depending on the IDL-files, reduced the size of the
- erl- and beam-files and decreased dependencies off Orber's
- Interface Repository. It is necessary to re-compile all IDL-files
- and use COS-applications, including Orber, compiled with
- IC-4.2.</p>
- <p>Own id: OTP-4576</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosFileTransfer 1.0.2</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>First release of the cosFileTransfer application. Please note that
- the OMG specification was not finalized when this version
- was released. Hence, the API may be changed in way which is not
- compatible with this version. Contact support if you are in doubt.</p>
- <p>Own Id: -</p>
- </item>
- </list>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosFileTransfer/doc/src/part.xml b/lib/cosFileTransfer/doc/src/part.xml
deleted file mode 100644
index b4e6f573dd..0000000000
--- a/lib/cosFileTransfer/doc/src/part.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE part SYSTEM "part.dtd">
-
-<part xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosFileTransfer User's Guide</title>
- <prepared></prepared>
- <docno></docno>
- <date>2000-08-24</date>
- <rev>1.0</rev>
- </header>
- <description>
- <p>The cosFileTransfer Application is an Erlang implementation of the OMG
- CORBA FileTransfer Service.</p>
- </description>
- <xi:include href="ch_contents.xml"/>
- <xi:include href="ch_introduction.xml"/>
- <xi:include href="ch_install.xml"/>
- <xi:include href="ch_system.xml"/>
- <xi:include href="ch_example.xml"/>
-</part>
-
diff --git a/lib/cosFileTransfer/doc/src/ref_man.xml b/lib/cosFileTransfer/doc/src/ref_man.xml
deleted file mode 100644
index ce050128e6..0000000000
--- a/lib/cosFileTransfer/doc/src/ref_man.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE application SYSTEM "application.dtd">
-
-<application xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosFileTransfer Reference Manual</title>
- <prepared></prepared>
- <docno></docno>
- <date>2000-08-24</date>
- <rev>1.0</rev>
- </header>
- <description>
- <p>The cosFileTransfer Application is an Erlang implementation of the OMG
- CORBA File Transfer Service.</p>
- </description>
- <xi:include href="cosFileTransferApp.xml"/>>
- <xi:include href="CosFileTransfer_File.xml"/>>
- <xi:include href="CosFileTransfer_Directory.xml"/>>
- <xi:include href="CosFileTransfer_FileIterator.xml"/>>
- <xi:include href="CosFileTransfer_VirtualFileSystem.xml"/>>
- <xi:include href="CosFileTransfer_FileTransferSession.xml"/>>
-</application>
-
diff --git a/lib/cosFileTransfer/ebin/.gitignore b/lib/cosFileTransfer/ebin/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosFileTransfer/ebin/.gitignore
+++ /dev/null
diff --git a/lib/cosFileTransfer/examples/.gitignore b/lib/cosFileTransfer/examples/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosFileTransfer/examples/.gitignore
+++ /dev/null
diff --git a/lib/cosFileTransfer/include/.gitignore b/lib/cosFileTransfer/include/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosFileTransfer/include/.gitignore
+++ /dev/null
diff --git a/lib/cosFileTransfer/info b/lib/cosFileTransfer/info
deleted file mode 100644
index e5ca860f1c..0000000000
--- a/lib/cosFileTransfer/info
+++ /dev/null
@@ -1,3 +0,0 @@
-group: orb
-short: Orber OMG File Transfer Service
-
diff --git a/lib/cosFileTransfer/priv/.gitignore b/lib/cosFileTransfer/priv/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosFileTransfer/priv/.gitignore
+++ /dev/null
diff --git a/lib/cosFileTransfer/src/CosFileTransfer.cfg b/lib/cosFileTransfer/src/CosFileTransfer.cfg
deleted file mode 100644
index a98f102e73..0000000000
--- a/lib/cosFileTransfer/src/CosFileTransfer.cfg
+++ /dev/null
@@ -1,10 +0,0 @@
-{this, "CosFileTransfer::Directory"}.
-{{handle_info, "CosFileTransfer::Directory"}, true}.
-{this, "CosFileTransfer::File"}.
-{{handle_info, "CosFileTransfer::File"}, true}.
-{this, "CosFileTransfer::VirtualFileSystem"}.
-{{handle_info, "CosFileTransfer::VirtualFileSystem"}, true}.
-{this, "CosFileTransfer::FileTransferSession"}.
-{{handle_info, "CosFileTransfer::FileTransferSession"}, true}.
-{this, "CosFileTransfer::FileIterator"}.
-{{handle_info, "CosFileTransfer::FileIterator"}, true}.
diff --git a/lib/cosFileTransfer/src/CosFileTransfer.idl b/lib/cosFileTransfer/src/CosFileTransfer.idl
deleted file mode 100644
index 2eb310478a..0000000000
--- a/lib/cosFileTransfer/src/CosFileTransfer.idl
+++ /dev/null
@@ -1,157 +0,0 @@
-//File: CosFileTransfer.idl
-#ifndef _COS_FILE_TRANSFER_IDL_
-#define _COS_FILE_TRANSFER_IDL_
-
-#include <CosProperty.idl>
-#pragma prefix "omg.org"
-
-module CosFileTransfer {
-
- typedef string Istring;
- typedef Istring ProtocolAddress;
- typedef long ContentType;
-
- const ContentType FTAM_1 = 1;
- const ContentType FTAM_2 = 2;
- const ContentType FTAM_3 = 3;
- const ContentType FTAM_4 = 4;
- const ContentType FTAM_5 = 5;
- const ContentType NBS_9 = 6;
- const ContentType INTAP_1 = 7;
-
- exception CommandNotImplementedException { Istring reason; };
- exception SessionException { Istring reason; };
- exception TransferException { Istring reason; };
- exception FileNotFoundException { Istring reason; };
- exception RequestFailureException { Istring reason; };
- exception IllegalOperationException { Istring reason; };
-
- interface VirtualFileSystem;
-
- struct AccessLevel {
- boolean read;
- boolean insert;
- boolean replace;
- boolean extend;
- boolean erase;
- boolean read_attr;
- boolean change_attr;
- boolean delete;
- };
-
- typedef sequence<ProtocolAddress> ProtocolAddressList;
-
- struct ProtocolSupport {
- Istring protocol_name;
- ProtocolAddressList addresses;
- };
-
- typedef sequence<ProtocolSupport> SupportedProtocolAddresses;
-
- interface Directory;
- interface FileTransferSession;
-
- typedef Istring FileName;
- typedef sequence<FileName> FileNameList;
-
- interface File:CosPropertyService::PropertySetDef {
-
- readonly attribute FileName name;
- readonly attribute FileNameList complete_file_name;
- readonly attribute Directory parent;
- readonly attribute FileTransferSession associated_session;
-
- };
-
- enum FileType {nfile, ndirectory};
-
- struct FileWrapper {
- File the_file;
- FileType file_type;
- };
-
- typedef sequence<FileWrapper> FileList;
-
- interface FileIterator;
- interface Directory : File {
-
- void list(in unsigned long how_many, out FileList fl, out FileIterator fi);
-
- };
-
- interface FileIterator {
-
- boolean next_one(out FileWrapper f);
- boolean next_n(in unsigned long how_many, out FileList fl);
-
- void destroy();
- };
-
- interface FileTransferSession {
-
- readonly attribute SupportedProtocolAddresses protocols_supported;
-
- void set_directory(in Directory new_directory)
- raises(SessionException, FileNotFoundException, RequestFailureException,
- IllegalOperationException);
-
- File create_file(in FileNameList name)
- raises(SessionException, FileNotFoundException, RequestFailureException,
- IllegalOperationException);
-
- Directory create_directory(in FileNameList name)
- raises(SessionException, FileNotFoundException, RequestFailureException,
- IllegalOperationException);
-
- FileWrapper get_file(in FileNameList complete_file_name)
- raises(SessionException, FileNotFoundException, RequestFailureException,
- IllegalOperationException);
-
- void delete(in File file)
- raises(SessionException, FileNotFoundException, RequestFailureException,
- IllegalOperationException);
-
- void transfer(in File src, in File dest)
- raises(SessionException, TransferException, FileNotFoundException,
- RequestFailureException, IllegalOperationException);
-
- void append(in File src, in File dest)
- raises(CommandNotImplementedException, SessionException, TransferException,
- FileNotFoundException, RequestFailureException,
- IllegalOperationException);
-
- void insert(in File src, in File dest, in long offset)
- raises(CommandNotImplementedException, SessionException, TransferException,
- FileNotFoundException, RequestFailureException,
- IllegalOperationException);
-
- void logout();
-
- // WARNING!!!
- // Theses are Orber specific operations and may only be used internally!!
- // Maybe removed, altered and changed in any way without warning!!
- Directory oe_orber_create_directory_current()
- raises(SessionException, FileNotFoundException, IllegalOperationException);
- FileList oe_orber_get_content(in FileNameList complete_file_name,
- in Directory parent);
- long oe_orber_count_children(in FileNameList complete_file_name);
-
- };
-
- interface VirtualFileSystem {
-
- enum NativeFileSystemType { FTAM, FTP, NATIVE };
-
- readonly attribute NativeFileSystemType file_system_type;
-
- typedef sequence<ContentType> ContentList;
-
- readonly attribute ContentList supported_content_types;
-
- FileTransferSession login(in Istring username, in Istring password,
- in Istring account, out Directory root)
- raises(SessionException, FileNotFoundException, IllegalOperationException);
- };
-};
-
-#endif //_COS_FILE_TRANSFER_IDL_
diff --git a/lib/cosFileTransfer/src/CosFileTransfer_Directory_impl.erl b/lib/cosFileTransfer/src/CosFileTransfer_Directory_impl.erl
deleted file mode 100644
index 8ce6cebf77..0000000000
--- a/lib/cosFileTransfer/src/CosFileTransfer_Directory_impl.erl
+++ /dev/null
@@ -1,453 +0,0 @@
-%%----------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : CosFileTransfer_Directory_impl
-%% Description :
-%%
-%% Created : 12 Sept 2000
-%%----------------------------------------------------------------------
--module('CosFileTransfer_Directory_impl').
-
-%%----------------------------------------------------------------------
-%% Include files
-%%----------------------------------------------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
-
--include_lib("cosProperty/include/CosPropertyService.hrl").
-
--include("cosFileTransferApp.hrl").
-
-%%----------------------------------------------------------------------
-%% External exports
-%%----------------------------------------------------------------------
--export([init/1,
- terminate/2]).
-
-%% Interface functions
--export([list/3]).
-
-%% Inherited CosFileTransfer::File
--export(['_get_name'/2,
- '_get_complete_file_name'/2,
- '_get_parent'/2,
- '_get_associated_session'/2]).
-
-%% Inherited CosPropertyService::PropertySetDef
--export([get_allowed_property_types/2,
- get_allowed_properties/2,
- define_property_with_mode/5,
- define_properties_with_modes/3,
- get_property_mode/3,
- get_property_modes/3,
- set_property_mode/4,
- set_property_modes/3]).
-
-%% Inherited CosPropertyService::PropertySet
--export([define_property/4,
- define_properties/3,
- get_number_of_properties/2,
- get_all_property_names/3,
- get_property_value/3,
- get_properties/3,
- get_all_properties/3,
- delete_property/3,
- delete_properties/3,
- delete_all_properties/2,
- is_property_defined/3]).
-
-%%----------------------------------------------------------------------
-%% Internal exports
-%%----------------------------------------------------------------------
-
-%%----------------------------------------------------------------------
-%% Records
-%%----------------------------------------------------------------------
--record(state, {property,
- name,
- completeName,
- parent,
- assocSession}).
-
-%%----------------------------------------------------------------------
-%% Macros
-%%----------------------------------------------------------------------
--define(create_InitState(Pr, N, C, Pa, A),
- #state{property = Pr,
- name = N,
- completeName = C,
- parent = Pa,
- assocSession = A}).
-
--define(get_PropertyRef(S), S#state.property).
--define(get_Name(S), S#state.name).
--define(get_CompleteName(S), S#state.completeName).
--define(get_Parent(S), S#state.parent).
--define(get_AssocSession(S), S#state.assocSession).
-
-%%======================================================================
-%% External functions
-%%======================================================================
-%%----------------------------------------------------------------------
-%% Function : init/1
-%% Returns : {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
-%% Description: Initiates the server
-%%----------------------------------------------------------------------
-init([Name, CompleteName, Parent, AssocSession]) ->
- PropTypes = [tk_long, tk_boolean],
- %% WARNING if the order of the properties is changed so must
- %% get_all_properties/3 in this module be as well!
- PropDefs = [#'CosPropertyService_PropertyDef'
- {property_name = "num_children",
- property_value = #any{typecode=tk_long, value=0},
- property_mode = fixed_readonly},
- #'CosPropertyService_PropertyDef'
- {property_name = "is_directory",
- property_value = #any{typecode=tk_boolean, value=true},
- property_mode = fixed_readonly}],
- Prop = cosProperty:create_static_SetDef(PropTypes, PropDefs),
- {ok, ?create_InitState(Prop, Name, CompleteName, Parent, AssocSession)}.
-
-%%----------------------------------------------------------------------
-%% Function : terminate/2
-%% Returns : any (ignored by gen_server)
-%% Description: Shutdown the server
-%%----------------------------------------------------------------------
-terminate(_Reason, _State) ->
- ok.
-
-%%======================================================================
-%% CosFileTransfer::Directory
-%%======================================================================
-%%----------------------------------------------------------------------
-%% Function : list
-%% Arguments : Max - ulong()
-%% Returns : {ok, FileList, FileIterator}
-%% Description:
-%%----------------------------------------------------------------------
-list(OE_This, State, Max) ->
- case 'CosFileTransfer_FileTransferSession':
- oe_orber_get_content(?get_AssocSession(State), ?get_CompleteName(State),
- OE_This) of
- [] ->
- {reply, {ok, [], corba:create_nil_objref()}, State};
- FileList when length(FileList) > Max ->
- {reply,
- {ok, lists:sublist(FileList, Max),
- 'CosFileTransfer_FileIterator':oe_create([lists:nthtail(Max,
- FileList)])},
- State};
- FileList ->
- {reply, {ok, FileList, corba:create_nil_objref()}, State}
- end.
-
-%%======================================================================
-%% CosFileTransfer::File
-%%======================================================================
-%%---------------------------------------------------------------------%
-%% Function : '_get_name'
-%% Arguments : -
-%% Returns : CosFileTransfer::FileName - string
-%% Description:
-%%----------------------------------------------------------------------
-'_get_name'(_OE_This, State) ->
- {reply, ?get_Name(State), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : '_get_complete_file_name'
-%% Arguments : -
-%% Returns : CosFileTransfer::FileNameList - a list of strings's
-%% Description:
-%%----------------------------------------------------------------------
-'_get_complete_file_name'(_OE_This, State) ->
- {reply, ?get_CompleteName(State), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : '_get_parent'
-%% Arguments : -
-%% Returns : CosFileTransfer::Directory
-%% Description:
-%%----------------------------------------------------------------------
-'_get_parent'(_OE_This, State) ->
- {reply, ?get_Parent(State), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : '_get_associated_session'
-%% Arguments : -
-%% Returns : CosFileTransfer::FileTransferSession
-%% Description:
-%%----------------------------------------------------------------------
-'_get_associated_session'(_OE_This, State) ->
- {reply, ?get_AssocSession(State), State}.
-
-%%======================================================================
-%% CosPropertyService::PropertySetDef
-%%======================================================================
-%%---------------------------------------------------------------------%
-%% Function : get_allowed_property_types
-%% Arguments : -
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-get_allowed_property_types(_OE_This, State) ->
- {reply, 'CosPropertyService_PropertySetDef':
- get_allowed_property_types(?get_PropertyRef(State)), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : get_allowed_properties
-%% Arguments : -
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-get_allowed_properties(_OE_This, State) ->
- {reply, 'CosPropertyService_PropertySetDef':
- get_allowed_properties(?get_PropertyRef(State)), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : define_property_with_mode
-%% Arguments : Name - string()
-%% Value - #any{}
-%% Mode - normal | read_only | fixed_normal | fixed_readonly
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-define_property_with_mode(_OE_This, State, Name, Value, Mode) ->
- {reply, 'CosPropertyService_PropertySetDef':
- define_property_with_mode(?get_PropertyRef(State), Name, Value, Mode), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : define_properties_with_modes
-%% Arguments : PropertyDefs - list of #'CosPropertyService_PropertyDef'{}
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-define_properties_with_modes(_OE_This, State, PropertyDefs) ->
- {reply, 'CosPropertyService_PropertySetDef':
- define_properties_with_modes(?get_PropertyRef(State), PropertyDefs), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : get_property_mode
-%% Arguments : Name - string()
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-get_property_mode(_OE_This, State, Name) ->
- {reply, 'CosPropertyService_PropertySetDef':
- get_property_mode(?get_PropertyRef(State), Name), State}.
-
-
-%%---------------------------------------------------------------------%
-%% Function : get_property_modes
-%% Arguments : Names - a list of Name (i.e. string()'s).
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-get_property_modes(_OE_This, State, Names) ->
- {reply, 'CosPropertyService_PropertySetDef':
- get_property_modes(?get_PropertyRef(State), Names), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : set_property_mode
-%% Arguments : Name - string()
-%% Mode - normal | read_only | fixed_normal | fixed_readonly
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-set_property_mode(_OE_This, State, Name, Mode) ->
- {reply, 'CosPropertyService_PropertySetDef':
- set_property_mode(?get_PropertyRef(State), Name, Mode), State}.
-
-
-%%---------------------------------------------------------------------%
-%% Function : set_property_modes
-%% Arguments : Modes - a list of #'CosPropertyService_PropertyModes'{}
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-set_property_modes(_OE_This, State, PropertyModes) ->
- {reply, 'CosPropertyService_PropertySetDef':
- set_property_modes(?get_PropertyRef(State), PropertyModes), State}.
-
-%%======================================================================
-%% CosPropertyService::PropertySet
-%%======================================================================
-%%---------------------------------------------------------------------%
-%% Function : define_property
-%% Arguments : Name - string()
-%% Value - #any{}
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-define_property(_OE_This, State, Name, Value) ->
- {reply, 'CosPropertyService_PropertySet':
- define_property(?get_PropertyRef(State), Name, Value), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : define_properties
-%% Arguments : Properties - a list of #'CosPropertyService_Property'{}
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-define_properties(_OE_This, State, Properties) ->
- {reply, 'CosPropertyService_PropertySet':
- define_properties(?get_PropertyRef(State), Properties), State}.
-
-
-%%---------------------------------------------------------------------%
-%% Function : get_number_of_properties
-%% Arguments : -
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-get_number_of_properties(_OE_This, State) ->
- {reply, 'CosPropertyService_PropertySet':
- get_number_of_properties(?get_PropertyRef(State)), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : get_all_property_names
-%% Arguments : Max - ulong()
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-get_all_property_names(_OE_This, State, Max) ->
- {reply, 'CosPropertyService_PropertySet':
- get_all_property_names(?get_PropertyRef(State), Max), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : get_property_value
-%% Arguments : Name - string()
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-get_property_value(_OE_This, State, "num_children") ->
- Count = 'CosFileTransfer_FileTransferSession':
- oe_orber_count_children(?get_AssocSession(State), ?get_CompleteName(State)),
- {reply, #any{typecode=tk_long, value=Count}, State};
-get_property_value(_OE_This, State, Name) ->
- {reply, 'CosPropertyService_PropertySet':
- get_property_value(?get_PropertyRef(State), Name), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : get_properties
-%% Arguments : Names - a list of Name (i.e. string()'s)
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-get_properties(_OE_This, State, Names) ->
- {Bool, Props} =
- 'CosPropertyService_PropertySet':get_properties(?get_PropertyRef(State),
- Names),
- NewProps = change_property(Props, [], State),
- {reply, {Bool, NewProps}, State}.
-
-change_property([], Acc, _State) ->
- Acc;
-change_property([H|T], Acc, State) ->
- NewAcc =
- case H of
- #'CosPropertyService_Property'{property_name = "num_children"} ->
- Count = 'CosFileTransfer_FileTransferSession':
- oe_orber_count_children(?get_AssocSession(State),
- ?get_CompleteName(State)),
- [H#'CosPropertyService_Property'
- {property_value = #any{typecode=tk_long, value=Count}}|Acc];
- _ ->
- [H|Acc]
- end,
- change_property(T, NewAcc, State).
-
-%%---------------------------------------------------------------------%
-%% Function : get_all_properties
-%% Arguments : Max - ulong()
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-get_all_properties(_OE_This, State, 0) ->
- %% WARNING if we start supporting more than 10 Properties the next line must
- %% be updated!
- {ok, Props, _Iterator} =
- 'CosPropertyService_PropertySet':get_all_properties(?get_PropertyRef(State),
- 10),
- NewProps = change_property(Props, [], State),
- %% WARNING if the cosProperty:start_PropertiesIterator/1 is updated
- %% it must be done hear as well.
- {reply, {ok, [], cosProperty:start_PropertiesIterator(NewProps)}, State};
-get_all_properties(_OE_This, State, Max) ->
- {ok, Props, Iterator} =
- 'CosPropertyService_PropertySet':get_all_properties(?get_PropertyRef(State),
- Max),
- NewProps = change_property(Props, [], State),
- {reply, {ok, NewProps, Iterator}, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : delete_property
-%% Arguments : Name - string()
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-delete_property(_OE_This, State, Name) ->
- {reply, 'CosPropertyService_PropertySet':
- delete_property(?get_PropertyRef(State), Name), State}.
-
-
-%%---------------------------------------------------------------------%
-%% Function : delete_properties
-%% Arguments : Names - a list of Name (i.e. string()'s)
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-delete_properties(_OE_This, State, Names) ->
- {reply, 'CosPropertyService_PropertySet':
- delete_properties(?get_PropertyRef(State), Names), State}.
-
-
-%%---------------------------------------------------------------------%
-%% Function : delete_all_properties
-%% Arguments : -
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-delete_all_properties(_OE_This, State) ->
- {reply, 'CosPropertyService_PropertySet':
- delete_all_properties(?get_PropertyRef(State)), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : is_property_defined
-%% Arguments : Name - string()
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-is_property_defined(_OE_This, State, Name) ->
- {reply, 'CosPropertyService_PropertySet':
- is_property_defined(?get_PropertyRef(State), Name), State}.
-
-%%======================================================================
-%% Internal functions
-%%======================================================================
-
-%%======================================================================
-%% END OF MODULE
-%%======================================================================
-
diff --git a/lib/cosFileTransfer/src/CosFileTransfer_FileIterator_impl.erl b/lib/cosFileTransfer/src/CosFileTransfer_FileIterator_impl.erl
deleted file mode 100644
index d824129147..0000000000
--- a/lib/cosFileTransfer/src/CosFileTransfer_FileIterator_impl.erl
+++ /dev/null
@@ -1,158 +0,0 @@
-%%----------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : CosFileTransfer_FileIterator_impl.erl
-%% Description :
-%%
-%% Created : 12 Sept 2000
-%%----------------------------------------------------------------------
--module('CosFileTransfer_FileIterator_impl').
-
-
-
-
-%%----------------------------------------------------------------------
-%% Include files
-%%----------------------------------------------------------------------
--include("cosFileTransferApp.hrl").
-
-%%----------------------------------------------------------------------
-%% External exports
-%%----------------------------------------------------------------------
--export([init/1,
- terminate/2,
- code_change/3,
- handle_info/2]).
-
-%% Interface functions
--export([next_one/2,
- next_n/3,
- destroy/2]).
-
-%%----------------------------------------------------------------------
-%% Internal exports
-%%----------------------------------------------------------------------
--export([]).
-
-%%----------------------------------------------------------------------
-%% Records
-%%----------------------------------------------------------------------
-
-%%----------------------------------------------------------------------
-%% Macros
-%%----------------------------------------------------------------------
-
-%%======================================================================
-%% External functions
-%%======================================================================
-%%----------------------------------------------------------------------
-%% Function : init/1
-%% Returns : {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
-%% Description: Initiates the server
-%%----------------------------------------------------------------------
-init([FileList]) ->
- {ok, FileList}.
-
-%%----------------------------------------------------------------------
-%% Function : terminate/2
-%% Returns : any (ignored by gen_server)
-%% Description: Shutdown the server
-%%----------------------------------------------------------------------
-terminate(_Reason, _State) ->
- ok.
-
-%%----------------------------------------------------------------------
-%% Function : code_change/3
-%% Returns : {ok, NewState}
-%% Description: Convert process state when code is changed
-%%----------------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%---------------------------------------------------------------------%
-%% function : handle_info/2
-%% Arguments:
-%% Returns :
-%% Effect :
-%%----------------------------------------------------------------------
-handle_info(Info, State) ->
- case Info of
- {'EXIT', _Pid, Reason} ->
- {stop, Reason, State};
- _Other ->
- {noreply, State}
- end.
-
-%%======================================================================
-%% CosFileTransfer::FileIterator
-%%======================================================================
-%%---------------------------------------------------------------------%
-%% Function : next_one
-%% Arguments :
-%% Returns : {boolean(), FileWrapper}
-%% Description:
-%%----------------------------------------------------------------------
-next_one(_OE_This, []) ->
- {reply, {false,
- #'CosFileTransfer_FileWrapper'{the_file = corba:create_nil_objref(),
- file_type = nfile}}, []};
-next_one(_OE_This, [FileWrapper]) ->
- {reply, {true, FileWrapper}, []};
-next_one(_OE_This, [FileWrapper|Rest]) ->
- {reply, {true, FileWrapper}, Rest}.
-
-%%---------------------------------------------------------------------%
-%% Function : next_n
-%% Arguments : HowMany - ulong()
-%% Returns : {boolean(), FileWrapperList}
-%% Description:
-%%----------------------------------------------------------------------
-next_n(_OE_This, [], _) ->
- {reply, {false, []}, []};
-next_n(_OE_This, FileWrapperList, HowMany) when HowMany > length(FileWrapperList) ->
- {reply, {true, FileWrapperList}, []};
-next_n(_OE_This, FileWrapperList, HowMany) ->
- {reply, {true, lists:sublist(FileWrapperList, HowMany)},
- lists:nthtail(HowMany, FileWrapperList)}.
-
-%%---------------------------------------------------------------------%
-%% Function : destroy
-%% Arguments : -
-%% Returns : -
-%% Description:
-%%----------------------------------------------------------------------
-destroy(_OE_This, State) ->
- {stop, normal, ok, State}.
-
-
-%%======================================================================
-%% Internal functions
-%%======================================================================
-
-
-
-%%======================================================================
-%% END OF MODULE
-%%======================================================================
diff --git a/lib/cosFileTransfer/src/CosFileTransfer_FileTransferSession_impl.erl b/lib/cosFileTransfer/src/CosFileTransfer_FileTransferSession_impl.erl
deleted file mode 100644
index 3a8285f092..0000000000
--- a/lib/cosFileTransfer/src/CosFileTransfer_FileTransferSession_impl.erl
+++ /dev/null
@@ -1,1061 +0,0 @@
-%%----------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : CosFileTransfer_FileTransferSession_impl.erl
-%% Description :
-%%
-%% Created : 12 Sept 2000
-%%----------------------------------------------------------------------
--module('CosFileTransfer_FileTransferSession_impl').
-
-
-%%----------------------------------------------------------------------
-%% Include files
-%%----------------------------------------------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
-
--include("cosFileTransferApp.hrl").
-
-%%----------------------------------------------------------------------
-%% External exports
-%%----------------------------------------------------------------------
--export([init/1,
- terminate/2,
- code_change/3,
- handle_info/2]).
-
-%% Interface functions
--export(['_get_protocols_supported'/2,
- set_directory/3,
- create_file/3,
- create_directory/3,
- get_file/3,
- delete/3,
- transfer/4,
- append/4,
- insert/5,
- logout/2]).
-
-%%----------------------------------------------------------------------
-%% Internal exports
-%%----------------------------------------------------------------------
--export([oe_orber_create_directory_current/2, oe_orber_get_content/4,
- oe_orber_count_children/3]).
--export([invoke_call/3]).
-
-%%----------------------------------------------------------------------
-%% Records
-%%----------------------------------------------------------------------
--record(state, {protocols, server, type, current, module, connection, mytype,
- connection_timeout}).
-
-%%----------------------------------------------------------------------
-%% Macros
-%%----------------------------------------------------------------------
--define(create_InitState(P, S, T, C, M, Co, Ty, CT),
- #state{protocols=P, server=S, type=T, current=C, module=M, connection=Co,
- mytype=Ty, connection_timeout=CT}).
-
--define(get_Protocols(S), S#state.protocols).
--define(get_Server(S), S#state.server).
--define(get_CurrentDir(S), S#state.current).
--define(get_Module(S), S#state.module).
--define(get_Connection(S), S#state.connection).
--define(get_MyType(S), S#state.mytype).
--define(get_ConnectionTimeout(S), S#state.connection_timeout).
--define(set_CurrentDir(S, C), S#state{current=C}).
-
--define(is_FTP(S), S#state.type=='FTP').
--define(is_FTAM(S), S#state.type=='FTAM').
--define(is_NATIVE(S), S#state.type=='NATIVE').
--define(is_ORBER_NATIVE(S), S#state.module==cosFileTransferNATIVE_file).
-
-
-%%======================================================================
-%% External functions
-%%======================================================================
-%%----------------------------------------------------------------------
-%% Function : init/1
-%% Returns : {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
-%% Description: Initiates the server
-%%----------------------------------------------------------------------
-init(['FTP', Host, Port, User, Password, _Account, Protocol, Timeout]) ->
- {ok, Pid} = inets:start(ftpc, [{host, Host}, {port, Port}], stand_alone),
- ok = ftp:user(Pid, User, Password),
- {ok, PWD} = ftp:pwd(Pid),
- {Connection, ProtocolSupport} = setup_local(Protocol),
- {ok, ?create_InitState(ProtocolSupport, Pid, 'FTP',
- PWD, ftp, Connection, Protocol, Timeout)};
-init([{'NATIVE', Mod}, Host, Port, User, Password, _Account, Protocol, Timeout]) ->
- {ok, Pid} = Mod:open(Host, Port),
- ok = Mod:user(Pid, User, Password),
- {ok, PWD} = Mod:pwd(Pid),
- {Connection, ProtocolSupport} = setup_local(Protocol),
- {ok, ?create_InitState(ProtocolSupport, Pid, 'NATIVE',
- PWD, Mod, Connection, Protocol, Timeout)}.
-
-
-%%----------------------------------------------------------------------
-%% Function : terminate/2
-%% Returns : any (ignored by gen_server)
-%% Description: Shutdown the server
-%%----------------------------------------------------------------------
-terminate(_Reason, #state{type = Type, server = Server, module = Mod} = State) ->
- case ?get_MyType(State) of
- ssl ->
- catch ssl:close(?get_Connection(State));
- _ ->
- catch gen_tcp:close(?get_Connection(State))
- end,
- case Type of
- 'FTP' ->
- inets:stop(ftpc, Server);
- 'NATIVE' ->
- Mod:close(Server);
- _ ->
- ok
- end,
- ok.
-
-%%----------------------------------------------------------------------
-%% Function : code_change/3
-%% Returns : {ok, NewState}
-%% Description: Convert process state when code is changed
-%%----------------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%---------------------------------------------------------------------%
-%% function : handle_info/2
-%% Arguments:
-%% Returns :
-%% Effect :
-%%----------------------------------------------------------------------
-handle_info(Info, State) ->
- case Info of
- {'EXIT', _Pid, Reason} ->
- {stop, Reason, State};
- _Other ->
- {noreply, State}
- end.
-
-%%======================================================================
-%% CosFileTransfer::FileTransferSession
-%%======================================================================
-%%---------------------------------------------------------------------%
-%% Function : _get_protocols_supported
-%% Arguments :
-%% Returns : A list of CosFileTransfer::ProtocolSupport, i.e.,
-%% struct ProtocolSupport {
-%% Istring protocol_name;
-%% ProtocolAddressList addresses; %% eq a list of strings.
-%% };
-%% Description:
-%%----------------------------------------------------------------------
-'_get_protocols_supported'(_OE_This, State) ->
- {reply, ?get_Protocols(State), State}.
-
-%%----------------------------------------------------------------------
-%% Function : set_directory
-%% Arguments : Directory - CosFileTransfer::Directory
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-set_directory(_OE_This, State, Directory) when ?is_FTP(State); ?is_NATIVE(State) ->
- Mod = ?get_Module(State),
- Path = filename:join('CosFileTransfer_Directory':
- '_get_complete_file_name'(Directory)),
- case catch Mod:cd(?get_Server(State), Path) of
- ok ->
- {reply, ok, ?set_CurrentDir(State, Path)};
- {error, epath} ->
- corba:raise(#'CosFileTransfer_FileNotFoundException'
- {reason="Directory not found."});
- {error, elogin} ->
- corba:raise(#'CosFileTransfer_SessionException'
- {reason="User not loggen in."});
- {error, econn} ->
- corba:raise(#'CosFileTransfer_RequestFailureException'
- {reason="Premature connection ending."});
- _ ->
- corba:raise(#'CosFileTransfer_RequestFailureException'
- {reason = "Unexpected error."})
- end.
-
-%%----------------------------------------------------------------------
-%% Function : create_file
-%% Arguments : FileNameList
-%% Returns : File
-%% Description: This operation creates a File Object representing a
-%% file which may or may not exist. Typically used as
-%% argument when invoking transfer/3. See also get_file/2.
-%%----------------------------------------------------------------------
-create_file(OE_This, State, FileNameList) ->
- {reply, cosFileTransferApp:create_file(OE_This, FileNameList), State}.
-
-%%----------------------------------------------------------------------
-%% Function : create_directory
-%% Arguments : FileNameList - full path name.
-%% Returns : Directory
-%% Description:
-%%----------------------------------------------------------------------
-create_directory(OE_This, State, FileNameList) when ?is_FTP(State);
- ?is_NATIVE(State) ->
- Mod = ?get_Module(State),
- case Mod:mkdir(?get_Server(State), filename:join(FileNameList)) of
- ok ->
- {reply, cosFileTransferApp:create_dir(OE_This, FileNameList), State};
- {error, epath} ->
- corba:raise(#'CosFileTransfer_FileNotFoundException'
- {reason="Directory not found."});
- {error, elogin} ->
- corba:raise(#'CosFileTransfer_SessionException'
- {reason="User not loggen in."});
- {error, econn} ->
- corba:raise(#'CosFileTransfer_RequestFailureException'
- {reason="Premature connection ending."});
- _ ->
- corba:raise(#'CosFileTransfer_RequestFailureException'
- {reason="Unknown error."})
- end.
-
-
-%%----------------------------------------------------------------------
-%% Function : get_file
-%% Arguments : FileNameList
-%% Returns : FileWrapper
-%% Description: This operation should be independent of the working Directory,
-%% i.e., a full path name must be supplied. The file or
-%% directory the returned object is supposed to represent
-%% MUST(!!!!) exist.
-%%----------------------------------------------------------------------
-get_file(OE_This, State, FileNameList) when ?is_FTP(State);
- ?is_NATIVE(State) ->
- case check_type(OE_This, State, filename:join(FileNameList)) of
- {ndirectory, _Listing} ->
- {reply,
- #'CosFileTransfer_FileWrapper'{the_file =
- cosFileTransferApp:
- create_dir(OE_This,
- FileNameList),
- file_type = ndirectory},
- State};
- nfile ->
- {reply,
- #'CosFileTransfer_FileWrapper'{the_file =
- cosFileTransferApp:
- create_file(OE_This,
- FileNameList),
- file_type = nfile},
- State};
- Other ->
- %% If we want to return {stop, ....}
- Other
- end.
-
-%%----------------------------------------------------------------------
-%% Function : delete
-%% Arguments : File
-%% Returns : -
-%% Description:
-%%----------------------------------------------------------------------
-delete(_OE_This, State, File) when ?is_FTP(State); ?is_NATIVE(State) ->
- Mod = ?get_Module(State),
- Result =
- case 'CosPropertyService_PropertySet':
- get_property_value(File, "is_directory") of
- #any{value=false} ->
- Mod:delete(?get_Server(State),
- filename:join('CosFileTransfer_File':
- '_get_complete_file_name'(File)));
- #any{value=true} ->
- Mod:rmdir(?get_Server(State),
- filename:join('CosFileTransfer_File':
- '_get_complete_file_name'(File)));
- Other ->
- Other
- end,
- case Result of
- ok ->
- {reply, ok, State};
- {error, epath} ->
- corba:raise(#'CosFileTransfer_FileNotFoundException'
- {reason="File or Directory not found."});
- {error, elogin} ->
- corba:raise(#'CosFileTransfer_SessionException'
- {reason="User not loggen in."});
- {error, econn} ->
- corba:raise(#'CosFileTransfer_RequestFailureException'
- {reason="Premature connection ending."});
- _ ->
- corba:raise(#'CosFileTransfer_RequestFailureException'
- {reason="Unknown error."})
- end.
-
-%%----------------------------------------------------------------------
-%% Function : transfer
-%% Arguments : SrcFile eq DestFile eq CosFileTransfer::File
-%% Returns : -
-%% Description: DestFile must be a newly created File object, using create_file()
-%% on the Target FileTransferSession, prior to calling transfer().
-%%----------------------------------------------------------------------
-transfer(OE_This, State, SrcFile, DestFile) when ?is_ORBER_NATIVE(State) ->
- case which_FTS_type(OE_This, SrcFile, DestFile) of
- {source, TargetFTS} ->
- %% The source FTS is supposed to be the active one, set up a connection.
- Protocols = 'CosFileTransfer_FileTransferSession':
- '_get_protocols_supported'(TargetFTS),
- SrcName = 'CosFileTransfer_File':'_get_complete_file_name'(SrcFile),
- Pid = spawn(?MODULE, invoke_call, [self(), transfer,
- [TargetFTS, SrcFile, DestFile]]),
- send_file(Protocols, ?get_MyType(State), ?get_ConnectionTimeout(State),
- filename:join(SrcName)),
- check_reply(Pid),
- {reply, ok, State};
- {target, _SourceFTS} ->
- DestName = 'CosFileTransfer_File':'_get_complete_file_name'(DestFile),
- receive_file(?get_MyType(State), ?get_Connection(State),
- ?get_ConnectionTimeout(State),
- filename:join(DestName), write),
- {reply, ok, State}
- end;
-transfer(OE_This, State, SrcFile, DestFile) when ?is_FTP(State); ?is_NATIVE(State) ->
- case which_FTS_type(OE_This, SrcFile, DestFile) of
- {source, TargetFTS} ->
- source_FTS_operation(State, SrcFile, DestFile, transfer, 0, TargetFTS);
- {target, _SourceFTS} ->
- target_FTS_operation(State, SrcFile, DestFile, send, 0)
- end.
-
-
-%%----------------------------------------------------------------------
-%% Function : append
-%% Arguments : SrcFile eq DestFile eq CosFileTransfer::File
-%% Returns : -
-%% Description:
-%%----------------------------------------------------------------------
-append(OE_This, State, SrcFile, DestFile) when ?is_ORBER_NATIVE(State) ->
- case which_FTS_type(OE_This, SrcFile, DestFile) of
- {source, TargetFTS} ->
- SrcName = filename:join('CosFileTransfer_File':
- '_get_complete_file_name'(SrcFile)),
- check_type(OE_This, State, SrcName),
- %% The source FTS is supposed to be the active one, set up a connection.
- Protocols = 'CosFileTransfer_FileTransferSession':
- '_get_protocols_supported'(TargetFTS),
- Pid = spawn(?MODULE, invoke_call, [self(), append,
- [TargetFTS, SrcFile, DestFile]]),
- send_file(Protocols, ?get_MyType(State), ?get_ConnectionTimeout(State),
- SrcName),
- check_reply(Pid),
- {reply, ok, State};
- {target, _SourceFTS} ->
- DestName = filename:join('CosFileTransfer_File':
- '_get_complete_file_name'(DestFile)),
- check_type(OE_This, State, DestName),
- receive_file(?get_MyType(State), ?get_Connection(State),
- ?get_ConnectionTimeout(State), DestName, append),
- {reply, ok, State}
- end;
-append(OE_This, State, SrcFile, DestFile) when ?is_NATIVE(State) ->
- case which_FTS_type(OE_This, SrcFile, DestFile) of
- {source, TargetFTS} ->
- source_FTS_operation(State, SrcFile, DestFile, append, 0, TargetFTS);
- {target, _SourceFTS} ->
- target_FTS_operation(State, SrcFile, DestFile, append, 0)
- end;
-append(_OE_This, _State, _SrcFile, _DestFile) ->
- corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO}).
-
-
-%%----------------------------------------------------------------------
-%% Function : insert
-%% Arguments : SrcFile eq DestFile eq CosFileTransfer::File
-%% Offset - long
-%% Returns : -
-%% Description:
-%%----------------------------------------------------------------------
-insert(OE_This, State, SrcFile, DestFile, Offset) when ?is_NATIVE(State) ->
- case which_FTS_type(OE_This, SrcFile, DestFile) of
- {source, TargetFTS} when ?is_ORBER_NATIVE(State) ->
- SrcName = 'CosFileTransfer_File':'_get_complete_file_name'(SrcFile),
- check_type(OE_This, State, filename:join(SrcName)),
- %% The source FTS is supposed to be the active one, set up a connection.
- Protocols = 'CosFileTransfer_FileTransferSession':
- '_get_protocols_supported'(TargetFTS),
- Pid = spawn(?MODULE, invoke_call, [self(), insert,
- [TargetFTS, SrcFile,
- DestFile, Offset]]),
- send_file(Protocols, ?get_MyType(State), ?get_ConnectionTimeout(State),
- filename:join(SrcName)),
- check_reply(Pid),
- {reply, ok, State};
- {source, TargetFTS} ->
- source_FTS_operation(State, SrcFile, DestFile, insert, Offset, TargetFTS);
- {target, _SourceFTS} ->
- target_FTS_operation(State, SrcFile, DestFile, insert, Offset)
- end;
-insert(_OE_This, _State, _SrcFile, _DestFile, _Offset) ->
- corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO}).
-
-
-%%----------------------------------------------------------------------
-%% Function : logout
-%% Arguments : -
-%% Returns : -
-%% Description:
-%%----------------------------------------------------------------------
-logout(_OE_This, State) when ?is_FTP(State); ?is_NATIVE(State) ->
- Mod = ?get_Module(State),
- catch Mod:close(?get_Server(State)),
- {stop, normal, ok, State}.
-
-%%======================================================================
-%% Internal functions
-%%======================================================================
-%%----------------------------------------------------------------------
-%% Function : oe_orber_create_directory_current
-%% Arguments : -
-%% Returns : Directory
-%% Description: Creates a Directory describing the working directory
-%% of the remote server, e.g., an FTP-server.
-%%----------------------------------------------------------------------
-oe_orber_create_directory_current(OE_This, State) when ?is_FTP(State);
- ?is_NATIVE(State) ->
- Mod = ?get_Module(State),
- FileNameList = filename:split(?get_CurrentDir(State)),
- case Mod:nlist(?get_Server(State), ?get_CurrentDir(State)) of
- {ok, _Listing} ->
- {reply, cosFileTransferApp:create_dir(OE_This, FileNameList),
- State};
- {error, epath} ->
- corba:raise(#'CosFileTransfer_FileNotFoundException'
- {reason="Directory not found."});
- {error, elogin} ->
- corba:raise(#'CosFileTransfer_SessionException'
- {reason="User not loggen in."});
- {error, econn} ->
- corba:raise(#'CosFileTransfer_RequestFailureException'
- {reason="Premature connection ending."});
- _ ->
- corba:raise(#'CosFileTransfer_RequestFailureException'
- {reason="Unknown error."})
- end.
-%%----------------------------------------------------------------------
-%% Function : oe_orber_get_content
-%% Arguments : -
-%% Returns : string
-%% Description:
-%%----------------------------------------------------------------------
-oe_orber_get_content(OE_This, State, FileNameList, Parent) when ?is_FTP(State);
- ?is_NATIVE(State) ->
- Mod = ?get_Module(State),
- case Mod:nlist(?get_Server(State), filename:join(FileNameList)) of
- {ok, Listing} ->
- create_content(Listing, OE_This, State, Parent, FileNameList);
- {error, epath} ->
- {reply, [], State};
- _ ->
- corba:raise(#'CosFileTransfer_FileNotFoundException'
- {reason="Directory not found."})
- end.
-
-%%----------------------------------------------------------------------
-%% Function : oe_orber_count_children
-%% Arguments : -
-%% Returns : string
-%% Description:
-%%----------------------------------------------------------------------
-oe_orber_count_children(OE_This, State, FileNameList) when ?is_FTP(State);
- ?is_NATIVE(State) ->
- case catch check_type(OE_This, State, filename:join(FileNameList)) of
- {ndirectory, Members} ->
- {reply, length(Members), State};
- {stop, normal, _, _} ->
- {stop, normal,
- {'EXCEPTION', #'INTERNAL'{completion_status=?COMPLETED_NO}},
- State};
- _->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-%%----------------------------------------------------------------------
-%% Function : delete_tmp_file
-%% Arguments : -
-%% Returns : ok | {'EXCEPTION', E}
-%% Description:
-%%----------------------------------------------------------------------
-delete_tmp_file(TmpFileName, ErrorMsg) ->
- case file:delete(TmpFileName) of
- ok ->
- ok;
- _ ->
- corba:raise(#'CosFileTransfer_RequestFailureException'{reason=ErrorMsg})
- end.
-
-
-%%----------------------------------------------------------------------
-%% Function : invoke_call
-%% Arguments : -
-%% Returns : ok | {'EXCEPTION', E}
-%% Description:
-%%----------------------------------------------------------------------
-invoke_call(Pid, Op, Args) ->
- Result = (catch apply('CosFileTransfer_FileTransferSession', Op, Args)),
- Pid ! {transfer_result, self(), Result},
- ok.
-
-%%----------------------------------------------------------------------
-%% Function : check_reply
-%% Arguments : Pid - the pid of the spawned process.
-%% Returns : ok | {'EXCEPTION', E}
-%% Description:
-%%----------------------------------------------------------------------
-check_reply(Pid) ->
- receive
- {transfer_result, Pid, ok} ->
- ok;
- {transfer_result, Pid, {'EXCEPTION', E}} ->
- orber:debug_level_print("[~p] CosFileTransfer_FileTransferSession:check_reply();
-Raised exception: ", [?LINE, E], ?DEBUG_LEVEL),
- corba:raise(E);
- {transfer_result, Pid, {'EXIT', Reason}} ->
- orber:debug_level_print("[~p] CosFileTransfer_FileTransferSession:check_reply();
-Got EXIT-signal with reason: ", [?LINE, Reason], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{minor=199,
- completion_status=?COMPLETED_NO})
- after infinity ->
- %% Should we add an exception here or do we reuse the iiop_timeout?
- %% For now keep as is.
- corba:raise(#'INTERNAL'{minor=199,
- completion_status=?COMPLETED_NO})
- end.
-
-
-%%----------------------------------------------------------------------
-%% Function : which_FTS_type
-%% Arguments : -
-%% Returns : {source, FTS} | {target, FTS} | {'EXCEPTION', #'BAD_PARAM'{}}
-%% Description: Used to determine if the target FTS is supposed to act
-%% as sender or receiver and also return the counter part FTS.
-%% An exception is raised if the user supplied incorrect parameters.
-%%----------------------------------------------------------------------
-which_FTS_type(OE_This, SrcFile, DestFile) ->
- TargetFTS = 'CosFileTransfer_File':'_get_associated_session'(DestFile),
- SourceFTS = 'CosFileTransfer_File':'_get_associated_session'(SrcFile),
- case corba_object:is_equivalent(OE_This, TargetFTS) of
- true ->
- {target, SourceFTS};
- false ->
- case corba_object:is_equivalent(OE_This, SourceFTS) of
- true ->
- {source, TargetFTS};
- false ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO})
- end
- end.
-
-
-%%----------------------------------------------------------------------
-%% Function : setup_connection
-%% Arguments : A list of #'CosFileTransfer_ProtocolSupport'{}
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-setup_connection([], Protocol, _) ->
- orber:debug_level_print("[~p] CosFileTransfer_FileTransferSession:setup_connection(~p);
-The Protocols listed are not supported.", [?LINE, Protocol], ?DEBUG_LEVEL),
- corba:raise(#'CosFileTransfer_TransferException'{reason="Unsupported protocol"});
-setup_connection([#'CosFileTransfer_ProtocolSupport'{protocol_name="TCP/IP",
- addresses=Addr}|_],
- tcp, Timeout) ->
- setup_connection_helper(Addr, gen_tcp, [], Timeout);
-setup_connection([#'CosFileTransfer_ProtocolSupport'{protocol_name="SSL",
- addresses=Addr}|_],
- ssl, Timeout) ->
- Options = [{certfile, cosFileTransferApp:ssl_client_certfile()},
- {verify, cosFileTransferApp:ssl_client_verify()},
- {depth, cosFileTransferApp:ssl_client_depth()}] ++
- ssl_client_cacertfile_option(),
- setup_connection_helper(Addr, ssl, Options, Timeout);
-setup_connection([_|T], Type, Timeout) ->
- setup_connection(T, Type, Timeout).
-
-setup_connection_helper([], _, _, _) ->
- corba:raise(#'CosFileTransfer_RequestFailureException'
- {reason="Unable to contact remote server."});
-setup_connection_helper([H|T], Driver, Options, Timeout) ->
- case string:tokens(H, ":") of
- [Host, Port] when Driver == gen_tcp ->
- case gen_tcp:connect(Host, list_to_integer(Port),
- [binary,
- {packet, raw},
- {reuseaddr, true},
- {nodelay, true}|Options], Timeout) of
- {ok, Sock} ->
- {gen_tcp, Sock};
- _->
- %% No response.
- setup_connection_helper(T, Driver, Options, Timeout)
- end;
- [Host, Port] when Driver == ssl ->
- case ssl:connect(Host, list_to_integer(Port),
- [binary,
- {packet, 0},
- {active, false}|Options], Timeout) of
- {ok, Sock} ->
- {ssl, Sock};
- _->
- %% No response.
- setup_connection_helper(T, Driver, Options, Timeout)
- end;
- _ ->
- %% Badly configured address.
- setup_connection_helper(T, Driver, Options, Timeout)
- end.
-
-ssl_client_cacertfile_option() ->
- case cosFileTransferApp:ssl_client_cacertfile() of
- [] ->
- [];
- X when is_list(X) ->
- {cacertfile, X};
- _ ->
- []
- end.
-
-%%----------------------------------------------------------------------
-%% Function : create_content
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-create_content(Listing, OE_This, State, Parent, PathList) ->
- create_content(string:tokens(Listing, ?SEPARATOR), OE_This,
- State, Parent, PathList, []).
-
-create_content([], _OE_This, State, _Parent, _PathList, Acc) ->
- {reply, Acc, State};
-create_content([H|T], OE_This, State, Parent, PathList, Acc) ->
- FullPathList = PathList ++[filename:basename(H)],
- case check_type(OE_This, State, filename:join(FullPathList)) of
- nfile ->
- create_content(T, OE_This, State, Parent, PathList,
- [#'CosFileTransfer_FileWrapper'
- {the_file = cosFileTransferApp:create_file(OE_This,
- FullPathList,
- Parent),
- file_type = nfile}|Acc]);
- {ndirectory, _Members} ->
- create_content(T, OE_This, State, Parent, PathList,
- [#'CosFileTransfer_FileWrapper'
- {the_file = cosFileTransferApp:create_dir(OE_This,
- FullPathList,
- Parent),
- file_type = ndirectory}|Acc]);
- Other ->
- Other
- end.
-
-
-%%----------------------------------------------------------------------
-%% Function : MISC functions
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-setup_local(tcp) ->
- {ok,Socket}=gen_tcp:listen(0, [binary,
- {packet, 0},
- {backlog,1},
- {active, false}]),
- {ok, Port} = inet:port(Socket),
- {Socket, [#'CosFileTransfer_ProtocolSupport'{protocol_name="TCP/IP",
- addresses = [local_address(Port)]}]};
-setup_local(ssl) ->
- Options = [{certfile, cosFileTransferApp:ssl_server_certfile()},
- {verify, cosFileTransferApp:ssl_server_verify()},
- {depth, cosFileTransferApp:ssl_server_depth()}] ++
- ssl_server_cacertfile_option(),
- {ok,Socket}=ssl:listen(0, [binary,
- {packet, 0},
- {backlog,1},
- {active, false}|Options]),
- {ok, {_Address, Port}} = ssl:sockname(Socket),
- {Socket, [#'CosFileTransfer_ProtocolSupport'{protocol_name="SSL",
- addresses = [local_address(Port)]}]}.
-
-local_address(Port) ->
- {ok, Hostname} = inet:gethostname(),
- {ok, {A1, A2, A3, A4}} = inet:getaddr(Hostname, inet),
- integer_to_list(A1) ++ "." ++ integer_to_list(A2) ++ "." ++ integer_to_list(A3)
- ++ "." ++ integer_to_list(A4)++":"++integer_to_list(Port).
-
-ssl_server_cacertfile_option() ->
- case cosFileTransferApp:ssl_server_cacertfile() of
- [] ->
- [];
- X when is_list(X) ->
- [{cacertfile, X}];
- _ ->
- []
- end.
-
-%%----------------------------------------------------------------------
-%% Function : source_file_operation
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-source_FTS_operation(State, SrcFile, DestFile, Op, Offset, FTS) ->
- Mod = ?get_Module(State),
- %% The source FTS is supposed to be the active one, set up a connection.
- Protocols = 'CosFileTransfer_FileTransferSession':'_get_protocols_supported'(FTS),
- SrcName = 'CosFileTransfer_File':'_get_complete_file_name'(SrcFile),
- TempName = cosFileTransferApp:create_name("TemporarySrcFile"),
- case Mod:recv(?get_Server(State), filename:join(SrcName), TempName) of
- ok when Op == insert ->
- %% Downloaded the File, we are now ready to transmit.
- Pid = spawn(?MODULE, invoke_call, [self(), insert,
- [FTS, SrcFile, DestFile, Offset]]),
- send_file(Protocols, ?get_MyType(State), ?get_ConnectionTimeout(State),
- TempName),
- %% Delete the temporary local copy.
- delete_tmp_file(TempName,
- "Transfer completed but failed to remove temporary local copy."),
- check_reply(Pid),
- {reply, ok, State};
- ok ->
- %% Downloaded the File, we are now ready to transmit.
- Pid = spawn(?MODULE, invoke_call, [self(), Op, [FTS, SrcFile, DestFile]]),
- send_file(Protocols, ?get_MyType(State), ?get_ConnectionTimeout(State),
- TempName),
- %% Delete the temporary local copy.
- delete_tmp_file(TempName,
- "Transfer completed but failed to remove temporary local copy."),
- check_reply(Pid),
- {reply, ok, State};
- {error, epath} ->
- corba:raise(#'CosFileTransfer_FileNotFoundException'
- {reason="File not found."});
- {error, elogin} ->
- corba:raise(#'CosFileTransfer_SessionException'
- {reason="User not loggen in."});
- {error, econn} ->
- corba:raise(#'CosFileTransfer_RequestFailureException'
- {reason="Premature connection ending."})
- end.
-
-%%----------------------------------------------------------------------
-%% Function : target_file_operation
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-target_FTS_operation(State, _SrcFile, DestFile, Op, Offset) ->
- Mod = ?get_Module(State),
- DestName = 'CosFileTransfer_File':'_get_complete_file_name'(DestFile),
- TempName = cosFileTransferApp:create_name("TemporaryDestFile"),
- receive_file(?get_MyType(State), ?get_Connection(State),
- ?get_ConnectionTimeout(State), TempName, write),
- Result =
- if
- Op == insert ->
- Mod:insert(?get_Server(State), TempName, filename:join(DestName), Offset);
- true ->
- Mod:Op(?get_Server(State), TempName, filename:join(DestName))
- end,
- case Result of
- ok ->
- %% Delete the temporary local copy.
- delete_tmp_file(TempName,
- "Transfer completed but failed to remove temporary local copy."),
- %% Completed the transfer successfully.
- {reply, ok, State};
- {error, epath} ->
- delete_tmp_file(TempName,
- "IllegalOperationException and not able to remove temporary local copy."),
- corba:raise(#'CosFileTransfer_IllegalOperationException'
- {reason="Not allowed by destination."});
- {error, elogin} ->
- delete_tmp_file(TempName,
- "SessionException and not able to remove temporary local copy."),
- corba:raise(#'CosFileTransfer_SessionException'
- {reason="User not logged in."});
- {error, econn} ->
- delete_tmp_file(TempName,
- "TransferException and not able to remove temporary local copy."),
- corba:raise(#'CosFileTransfer_TransferException'
- {reason="Premature connection ending."});
- {error, etnospc} ->
- delete_tmp_file(TempName,
- "RequestFailureException and not able to remove temporary local copy."),
- corba:raise(#'CosFileTransfer_RequestFailureException'
- {reason="Premature connection ending."});
- {error, efnamena} ->
- delete_tmp_file(TempName,
- "IllegalOperationException and not able to remove temporary local copy."),
- corba:raise(#'CosFileTransfer_IllegalOperationException'
- {reason="Not allowed by destination."})
- end.
-
-%%----------------------------------------------------------------------
-%% Function : receive_file
-%% Arguments : Driver - currently only gen_tcp supported.
-%% LSocket - which socket to use.
-%% FileName - an absolute file name representing the
-%% file we want to create or append to.
-%% Type - 'read', 'write', 'append'.
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-receive_file(tcp, LSock, Timeout, FileName, Type) ->
- %% The Type can be the ones allowed by the file-module, i.e.,
- %% 'read', 'write' or 'append'
- FD = file_open(FileName, Type),
- case gen_tcp:accept(LSock, Timeout) of
- {ok, Sock} ->
- receive_file_helper(gen_tcp, Sock, FD);
- {error, timeout} ->
- orber:dbg("[~p] CosFileTransfer_FileTransferSession:receive_file();~n"
- "gen_tcp:accept(~p) timed out", [?LINE, Timeout], ?DEBUG_LEVEL),
- corba:raise(#'CosFileTransfer_RequestFailureException'
- {reason="TCP accept timed out.."});
- {error, Why} ->
- orber:dbg("[~p] CosFileTransfer_FileTransferSession:receive_file();~n"
- "gen_tcp:accept(~p) failed: ~p", [?LINE, Timeout, Why], ?DEBUG_LEVEL),
- corba:raise(#'CosFileTransfer_RequestFailureException'
- {reason="TCP accept failed."})
- end;
-receive_file(ssl, LSock, Timeout, FileName, Type) ->
- %% The Type can be the ones allowed by the file-module, i.e.,
- %% 'read', 'write' or 'append'
- FD = file_open(FileName, Type),
- case ssl:transport_accept(LSock, Timeout) of
- {ok, Sock} ->
- case ssl:ssl_accept(Sock, Timeout) of
- ok ->
- receive_file_helper(ssl, Sock, FD);
- {error, Error} ->
- orber:dbg("[~p] CosFileTransfer_FileTransferSession:receive_file();~n"
- "ssl:ssl_accept(~p) failed: ~p",
- [?LINE, Timeout, Error], ?DEBUG_LEVEL),
- corba:raise(#'CosFileTransfer_RequestFailureException'
- {reason="TCP accept failed."})
- end;
- {error, timeout} ->
- orber:dbg("[~p] CosFileTransfer_FileTransferSession:receive_file();~n"
- "ssl:transport_accept(~p) timed out",
- [?LINE, Timeout], ?DEBUG_LEVEL),
- corba:raise(#'CosFileTransfer_RequestFailureException'
- {reason="TCP accept timed out.."});
- {error, Why} ->
- orber:dbg("[~p] CosFileTransfer_FileTransferSession:receive_file();~n"
- "ssl:transport_accept(~p) failed: ~p",
- [?LINE, Timeout, Why], ?DEBUG_LEVEL),
- corba:raise(#'CosFileTransfer_RequestFailureException'
- {reason="TCP accept failed."})
- end.
-
-receive_file_helper(Driver, Sock, FD) ->
- case Driver:recv(Sock, 0) of
- {ok, Bin} ->
- file:write(FD, Bin),
- receive_file_helper(Driver, Sock, FD);
- {error, closed} ->
- file:close(FD);
- What ->
- orber:debug_level_print("[~p] CosFileTransfer_FileTransferSession:receive_file(~p);
-Error occured when receiving data: ~p", [?LINE, Driver, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-%%----------------------------------------------------------------------
-%% Function : send_file
-%% Arguments : Driver - currently only gen_tcp supported.
-%% Sock - which socket to use.
-%% FileName - an absolute file name representing the
-%% file we want to send.
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-send_file(Protocols, Type, Timeout, FileName) ->
- {Driver, Sock} = setup_connection(Protocols, Type, Timeout),
- FD = file_open(FileName, read),
- BuffSize = cosFileTransferApp:get_buffert_size(),
- send_file_helper(Driver, Sock, FD, BuffSize).
-
-send_file_helper(Driver, Sock, FD, BuffSize) ->
- case file:read(FD, BuffSize) of
- eof ->
- file:close(FD),
- Driver:close(Sock);
- {ok, Bin} ->
- case Driver:send(Sock, Bin) of
- ok ->
- send_file_helper(Driver, Sock, FD, BuffSize);
- What ->
- orber:debug_level_print("[~p] CosFileTransfer_FileTransferSession:send_file_helper(~p);
-Error occured when sending data: ~p", [?LINE, Driver, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end
- end.
-
-
-file_open(File, Type) ->
- case file:open(File, [raw, binary, Type]) of
- {ok, FD} ->
- FD;
- {error, What} ->
- orber:debug_level_print("[~p] CosFileTransfer_FileTransferSession:file_open(~p);
-Failed to open the file due to: ~p", [?LINE, File, What], ?DEBUG_LEVEL),
- corba:raise(#'CosFileTransfer_RequestFailureException'
- {reason="Unable to open given file."})
- end.
-
-%%----------------------------------------------------------------------
-%% Function : check_type
-%% Arguments : FullName - an absolute file name representing the
-%% file or directory we want to evaluate.
-%% Returns :
-%% Description:
-%% When communcating with FTP-servers on different platforms a variety of
-%% answers can be returned. A few examples:
-%%
-%% ### ftp:nlist on an empty directory ###
-%% {ok, ""}, {error, epath}
-%%
-%% ### ftp:nlist on a non-existing directory or file ###
-%% {ok, "XXX: No such file or directory}, {error, epath}
-%%
-%% ### ftp:nlist on an existing directory with one contained item ###
-%% {ok, "Item"}
-%%
-%% Comparing the above we see that it's virtually impossible to tell apart
-%% {ok, "XXX: No such file or directory} and {ok, "Item"}.
-%% Hence, it's easier to test if it's possible to do ftp:cd instead.
-%% Ugly, but rather effective. If we look at the bright side, it's only
-%% necessary when we try to lookup:
-%% * non-existing item
-%% * A directory with one member only.
-%% * An empty directory.
-%%
-%% Furthermore, no need for traversing Listings etc.
-%%----------------------------------------------------------------------
-check_type(_OE_This, State, FullName) when ?is_FTP(State); ?is_NATIVE(State) ->
- Mod = ?get_Module(State),
- Result =
- case Mod:nlist(?get_Server(State), FullName) of
- {ok, Listing} when length(Listing) > 0->
- case string:tokens(Listing, ?SEPARATOR) of
- [FullName] ->
- nfile;
- Members when length(Members) > 1 ->
- %% Must test if more than one member since sometimes
- %% this operation returns for example:
- %% {ok, "XXX No such file or drectory"}
- {ndirectory, Members};
- Member ->
- case Mod:cd(?get_Server(State), FullName) of
- ok ->
- case Mod:cd(?get_Server(State),
- ?get_CurrentDir(State)) of
- ok ->
- {ndirectory, Member};
- _ ->
- %% Failed, we cannot continue since the
- %% FTS now pointso an incorrect Directory.
- %% Hence, we must terminate.
- {stop, normal,
- {'EXCEPTION',
- #'CosFileTransfer_RequestFailureException'
- {reason="Unknown error."}}, State}
- end;
- {error, E} ->
- {error, E};
- _ ->
- nfile
- end
- end;
- {error, epath} ->
- %% Might be a file.
- DirName = filename:dirname(FullName),
- case Mod:nlist(?get_Server(State), DirName) of
- {ok, Listing} when length(Listing) > 0->
- Members = string:tokens(Listing, ?SEPARATOR),
- case lists:member(FullName, Members) of
- true ->
- nfile;
- _ ->
- BName = filename:basename(FullName),
- case lists:member(BName, Members) of
- true ->
- nfile;
- _ ->
- {error, epath}
- end
- end;
- _ ->
- {error, epath}
- end;
- _ ->
- case Mod:cd(?get_Server(State), FullName) of
- ok ->
- case Mod:cd(?get_Server(State), ?get_CurrentDir(State)) of
- ok ->
- {ndirectory, []};
- _ ->
- %% Failed, we cannot continue since the
- %% FTS now pointso an incorrect Directory.
- %% Hence, we must terminate.
- {stop, normal,
- {'EXCEPTION',
- #'CosFileTransfer_RequestFailureException'
- {reason="Unknown error."}}, State}
- end;
- _ ->
- {error, epath}
- end
- end,
- case Result of
- {error, epath} ->
- corba:raise(#'CosFileTransfer_FileNotFoundException'
- {reason="File or Directory not found."});
- {error, elogin} ->
- corba:raise(#'CosFileTransfer_SessionException'
- {reason="User not logged in."});
- {error, econn} ->
- corba:raise(#'CosFileTransfer_RequestFailureException'
- {reason="Premature connection ending."});
- Other ->
- Other
- end.
-
-
-
-%%======================================================================
-%% END OF MODULE
-%%======================================================================
diff --git a/lib/cosFileTransfer/src/CosFileTransfer_File_impl.erl b/lib/cosFileTransfer/src/CosFileTransfer_File_impl.erl
deleted file mode 100644
index 263255413e..0000000000
--- a/lib/cosFileTransfer/src/CosFileTransfer_File_impl.erl
+++ /dev/null
@@ -1,385 +0,0 @@
-%%----------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : CosFileTransfer_File_impl.erl
-%% Description :
-%%
-%% Created : 5 Feb 2001
-%%----------------------------------------------------------------------
--module('CosFileTransfer_File_impl').
-
-%%----------------------------------------------------------------------
-%% Include files
-%%----------------------------------------------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
-
--include_lib("cosProperty/include/CosPropertyService.hrl").
-
--include("cosFileTransferApp.hrl").
-
-%%----------------------------------------------------------------------
-%% External exports
-%%----------------------------------------------------------------------
--export([init/1,
- terminate/2]).
-
-%% Interface functions
--export(['_get_name'/2,
- '_get_complete_file_name'/2,
- '_get_parent'/2,
- '_get_associated_session'/2]).
-
-%% Inherited CosPropertyService::PropertySetDef
--export([get_allowed_property_types/2,
- get_allowed_properties/2,
- define_property_with_mode/5,
- define_properties_with_modes/3,
- get_property_mode/3,
- get_property_modes/3,
- set_property_mode/4,
- set_property_modes/3]).
-
-%% Inherited CosPropertyService::PropertySet
--export([define_property/4,
- define_properties/3,
- get_number_of_properties/2,
- get_all_property_names/3,
- get_property_value/3,
- get_properties/3,
- get_all_properties/3,
- delete_property/3,
- delete_properties/3,
- delete_all_properties/2,
- is_property_defined/3]).
-
-%%----------------------------------------------------------------------
-%% Internal exports
-%%----------------------------------------------------------------------
-
-%%----------------------------------------------------------------------
-%% Records
-%%----------------------------------------------------------------------
--record(state, {property,
- name,
- completeName,
- parent,
- assocSession}).
-
-%%----------------------------------------------------------------------
-%% Macros
-%%----------------------------------------------------------------------
--define(create_InitState(Pr, N, C, Pa, A),
- #state{property = Pr,
- name = N,
- completeName = C,
- parent = Pa,
- assocSession = A}).
-
--define(get_PropertyRef(S), S#state.property).
--define(get_Name(S), S#state.name).
--define(get_CompleteName(S), S#state.completeName).
--define(get_Parent(S), S#state.parent).
--define(get_AssocSession(S), S#state.assocSession).
-
-%%======================================================================
-%% External functions
-%%======================================================================
-%%----------------------------------------------------------------------
-%% Function : init/1
-%% Returns : {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
-%% Description: Initiates the server
-%%----------------------------------------------------------------------
-init([Name, CompleteName, Parent, AssocSession]) ->
- PropTypes = [tk_boolean],
- PropDefs = [#'CosPropertyService_PropertyDef'
- {property_name = "is_directory",
- property_value = #any{typecode=tk_boolean, value=false},
- property_mode = fixed_readonly}],
- Prop = cosProperty:create_static_SetDef(PropTypes, PropDefs),
- {ok, ?create_InitState(Prop, Name, CompleteName, Parent, AssocSession)}.
-
-%%----------------------------------------------------------------------
-%% Function : terminate/2
-%% Returns : any (ignored by gen_server)
-%% Description: Shutdown the server
-%%----------------------------------------------------------------------
-terminate(_Reason, _State) ->
- ok.
-
-%%======================================================================
-%% CosFileTransfer::File
-%%======================================================================
-%%---------------------------------------------------------------------%
-%% Function : '_get_name'
-%% Arguments : -
-%% Returns : CosFileTransfer::FileName - string
-%% Description:
-%%----------------------------------------------------------------------
-'_get_name'(_OE_This, State) ->
- {reply, ?get_Name(State), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : '_get_complete_file_name'
-%% Arguments : -
-%% Returns : CosFileTransfer::FileNameList - a list of strings's
-%% Description:
-%%----------------------------------------------------------------------
-'_get_complete_file_name'(_OE_This, State) ->
- {reply, ?get_CompleteName(State), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : '_get_parent'
-%% Arguments : -
-%% Returns : CosFileTransfer::Directory
-%% Description:
-%%----------------------------------------------------------------------
-'_get_parent'(_OE_This, State) ->
- {reply, ?get_Parent(State), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : '_get_associated_session'
-%% Arguments : -
-%% Returns : CosFileTransfer::FileTransferSession
-%% Description:
-%%----------------------------------------------------------------------
-'_get_associated_session'(_OE_This, State) ->
- {reply, ?get_AssocSession(State), State}.
-
-%%======================================================================
-%% CosPropertyService::PropertySetDef
-%%======================================================================
-%%---------------------------------------------------------------------%
-%% Function : get_allowed_property_types
-%% Arguments : -
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-get_allowed_property_types(_OE_This, State) ->
- {reply, 'CosPropertyService_PropertySetDef':
- get_allowed_property_types(?get_PropertyRef(State)), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : get_allowed_properties
-%% Arguments : -
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-get_allowed_properties(_OE_This, State) ->
- {reply, 'CosPropertyService_PropertySetDef':
- get_allowed_properties(?get_PropertyRef(State)), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : define_property_with_mode
-%% Arguments : Name - string()
-%% Value - #any{}
-%% Mode - normal | read_only | fixed_normal | fixed_readonly
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-define_property_with_mode(_OE_This, State, Name, Value, Mode) ->
- {reply, 'CosPropertyService_PropertySetDef':
- define_property_with_mode(?get_PropertyRef(State), Name, Value, Mode), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : define_properties_with_modes
-%% Arguments : PropertyDefs - list of #'CosPropertyService_PropertyDef'{}
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-define_properties_with_modes(_OE_This, State, PropertyDefs) ->
- {reply, 'CosPropertyService_PropertySetDef':
- define_properties_with_modes(?get_PropertyRef(State), PropertyDefs), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : get_property_mode
-%% Arguments : Name - string()
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-get_property_mode(_OE_This, State, Name) ->
- {reply, 'CosPropertyService_PropertySetDef':
- get_property_mode(?get_PropertyRef(State), Name), State}.
-
-
-%%---------------------------------------------------------------------%
-%% Function : get_property_modes
-%% Arguments : Names - a list of Name (i.e. string()'s).
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-get_property_modes(_OE_This, State, Names) ->
- {reply, 'CosPropertyService_PropertySetDef':
- get_property_modes(?get_PropertyRef(State), Names), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : set_property_mode
-%% Arguments : Name - string()
-%% Mode - normal | read_only | fixed_normal | fixed_readonly
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-set_property_mode(_OE_This, State, Name, Mode) ->
- {reply, 'CosPropertyService_PropertySetDef':
- set_property_mode(?get_PropertyRef(State), Name, Mode), State}.
-
-
-%%---------------------------------------------------------------------%
-%% Function : set_property_modes
-%% Arguments : Modes - a list of #'CosPropertyService_PropertyModes'{}
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-set_property_modes(_OE_This, State, PropertyModes) ->
- {reply, 'CosPropertyService_PropertySetDef':
- set_property_modes(?get_PropertyRef(State), PropertyModes), State}.
-
-%%======================================================================
-%% CosPropertyService::PropertySet
-%%======================================================================
-%%---------------------------------------------------------------------%
-%% Function : define_property
-%% Arguments : Name - string()
-%% Value - #any{}
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-define_property(_OE_This, State, Name, Value) ->
- {reply, 'CosPropertyService_PropertySet':
- define_property(?get_PropertyRef(State), Name, Value), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : define_properties
-%% Arguments : Properties - a list of #'CosPropertyService_Property'{}
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-define_properties(_OE_This, State, Properties) ->
- {reply, 'CosPropertyService_PropertySet':
- define_properties(?get_PropertyRef(State), Properties), State}.
-
-
-%%---------------------------------------------------------------------%
-%% Function : get_number_of_properties
-%% Arguments : -
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-get_number_of_properties(_OE_This, State) ->
- {reply, 'CosPropertyService_PropertySet':
- get_number_of_properties(?get_PropertyRef(State)), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : get_all_property_names
-%% Arguments : Max - ulong()
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-get_all_property_names(_OE_This, State, Max) ->
- {reply, 'CosPropertyService_PropertySet':
- get_all_property_names(?get_PropertyRef(State), Max), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : get_property_value
-%% Arguments : Name - string()
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-get_property_value(_OE_This, State, Name) ->
- {reply, 'CosPropertyService_PropertySet':
- get_property_value(?get_PropertyRef(State), Name), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : get_properties
-%% Arguments : Names - a list of Name (i.e. string()'s)
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-get_properties(_OE_This, State, Names) ->
- {reply, 'CosPropertyService_PropertySet':
- get_properties(?get_PropertyRef(State), Names), State}.
-
-
-%%---------------------------------------------------------------------%
-%% Function : get_all_properties
-%% Arguments : Max - ulong()
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-get_all_properties(_OE_This, State, Max) ->
- {reply, 'CosPropertyService_PropertySet':
- get_all_properties(?get_PropertyRef(State), Max), State}.
-
-
-%%---------------------------------------------------------------------%
-%% Function : delete_property
-%% Arguments : Name - string()
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-delete_property(_OE_This, State, Name) ->
- {reply, 'CosPropertyService_PropertySet':
- delete_property(?get_PropertyRef(State), Name), State}.
-
-
-%%---------------------------------------------------------------------%
-%% Function : delete_properties
-%% Arguments : Names - a list of Name (i.e. string()'s)
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-delete_properties(_OE_This, State, Names) ->
- {reply, 'CosPropertyService_PropertySet':
- delete_properties(?get_PropertyRef(State), Names), State}.
-
-
-%%---------------------------------------------------------------------%
-%% Function : delete_all_properties
-%% Arguments : -
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-delete_all_properties(_OE_This, State) ->
- {reply, 'CosPropertyService_PropertySet':
- delete_all_properties(?get_PropertyRef(State)), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : is_property_defined
-%% Arguments : Name - string()
-%% Returns : See cosProperty application.
-%% Description:
-%%----------------------------------------------------------------------
-is_property_defined(_OE_This, State, Name) ->
- {reply, 'CosPropertyService_PropertySet':
- is_property_defined(?get_PropertyRef(State), Name), State}.
-
-%%======================================================================
-%% Internal functions
-%%======================================================================
-
-%%======================================================================
-%% END OF MODULE
-%%======================================================================
-
diff --git a/lib/cosFileTransfer/src/CosFileTransfer_VirtualFileSystem_impl.erl b/lib/cosFileTransfer/src/CosFileTransfer_VirtualFileSystem_impl.erl
deleted file mode 100644
index 7440498a23..0000000000
--- a/lib/cosFileTransfer/src/CosFileTransfer_VirtualFileSystem_impl.erl
+++ /dev/null
@@ -1,217 +0,0 @@
-%%----------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : CosFileTransfer_VirtualFileSystem_impl.erl
-%% Description :
-%%
-%% Created : 12 Sept 2000
-%%----------------------------------------------------------------------
--module('CosFileTransfer_VirtualFileSystem_impl').
-
-%%----------------------------------------------------------------------
-%% Include files
-%%----------------------------------------------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
-
--include_lib("cosFileTransfer/include/CosFileTransfer.hrl").
--include("cosFileTransferApp.hrl").
-
-
-%%----------------------------------------------------------------------
-%% External exports
-%%----------------------------------------------------------------------
--export([init/1,
- terminate/2,
- code_change/3,
- handle_info/2]).
-
-%% Interface functions
--export(['_get_file_system_type'/2,
- '_get_supported_content_types'/2,
- login/5]).
-
-%%----------------------------------------------------------------------
-%% Internal exports
-%%----------------------------------------------------------------------
--export([]).
-
-%%----------------------------------------------------------------------
-%% Records
-%%----------------------------------------------------------------------
--record(state, {type, content, host, port, protocol, timeout, module}).
-
-%%----------------------------------------------------------------------
-%% Macros
-%%----------------------------------------------------------------------
--define(create_InitState(T, C, H, P, Pr, TO),
- #state{type=T,
- content=C,
- host=H,
- port=P,
- protocol=Pr,
- timeout=TO}).
--define(create_NativeInitState(T, C, H, P, Pr, TO, M),
- #state{type=T,
- content=C,
- host=H,
- port=P,
- protocol=Pr,
- timeout=TO,
- module=M}).
-
--define(get_Type(S), S#state.type).
--define(get_Content(S), S#state.content).
--define(get_Host(S), S#state.host).
--define(get_Port(S), S#state.port).
--define(get_StartDir(S), S#state.startdir).
--define(get_Module(S), S#state.module).
--define(get_Protocol(S), S#state.protocol).
--define(get_Timeout(S), S#state.timeout).
-
--define(is_FTP(S), S#state.type == 'FTP').
--define(is_FTAM(S), S#state.type == 'FTAM').
--define(is_NATIVE(S), S#state.type == 'NATIVE').
-
-
-%%======================================================================
-%% External functions
-%%======================================================================
-%%----------------------------------------------------------------------
-%% Function : init/1
-%% Returns : {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
-%% Description: Initiates the server
-%%----------------------------------------------------------------------
-init([{Type, Mod}, Content, Host, Port, Options]) ->
- Prot = cosFileTransferApp:get_option(protocol, Options, ?DEFAULT_CONFIG),
- Time = timer:seconds(cosFileTransferApp:get_option(connect_timeout, Options,
- ?DEFAULT_CONFIG)),
- {ok, ?create_NativeInitState(Type, Content, Host, Port, Prot, Time, Mod)};
-init([Type, Content, Host, Port, Options]) ->
- Prot = cosFileTransferApp:get_option(protocol, Options, ?DEFAULT_CONFIG),
- Time = timer:seconds(cosFileTransferApp:get_option(connect_timeout, Options,
- ?DEFAULT_CONFIG)),
- {ok, ?create_InitState(Type, Content, Host, Port, Prot, Time)}.
-
-%%----------------------------------------------------------------------
-%% Function : terminate/2
-%% Returns : any (ignored by gen_server)
-%% Description: Shutdown the server
-%%----------------------------------------------------------------------
-terminate(_Reason, _State) ->
- ok.
-
-%%----------------------------------------------------------------------
-%% Function : code_change/3
-%% Returns : {ok, NewState}
-%% Description: Convert process state when code is changed
-%%----------------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%---------------------------------------------------------------------%
-%% function : handle_info/2
-%% Arguments:
-%% Returns :
-%% Effect :
-%%----------------------------------------------------------------------
-handle_info(_Info, State) ->
- {noreply, State}.
-
-%%======================================================================
-%% CosFileTransfer::VirtualFileSystem
-%%======================================================================
-%%---------------------------------------------------------------------%
-%% Function : '_get_file_system_type'
-%% Arguments : -
-%% Returns : CosFileTransfer::NativeFileSystemType, i.e., 'FTP', 'FTAM',
-%% or 'NATIVE'. Currently only 'FTP' is allowed.
-%% Description:
-%%----------------------------------------------------------------------
-'_get_file_system_type'(_OE_This, State) ->
- {reply, ?get_Type(State), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : '_get_supported_content_types'
-%% Arguments :
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-'_get_supported_content_types'(_OE_This, State) ->
- {reply, ?get_Content(State), State}.
-
-%%----------------------------------------------------------------------
-%% Function : login
-%% Arguments : User - string()
-%% Password - string()
-%% Account - string()
-%% Returns : FileTransferSession object and Directory object (out-type).
-%% Description:
-%%----------------------------------------------------------------------
-login(_OE_This, State, User, Password, Account) when ?is_FTP(State) ->
- case catch 'CosFileTransfer_FileTransferSession':
- oe_create(['FTP', ?get_Host(State), ?get_Port(State), User, Password, Account,
- ?get_Protocol(State), ?get_Timeout(State)],
- [{sup_child, true}]) of
- {ok, _Pid, FTS} ->
- Dir = 'CosFileTransfer_FileTransferSession':
- oe_orber_create_directory_current(FTS),
- {reply, {FTS, Dir}, State};
- What ->
- orber:debug_level_print("[~p] CosFileTransfer_VirtualFileSystem:login(~p ~p ~p ~p);
-Unable to create a FileTransferSession: ~p",
- [?LINE, ?get_Host(State), ?get_Port(State), User,
- ?get_Protocol(State), What],
- ?DEBUG_LEVEL),
- corba:raise(#'CosFileTransfer_SessionException'{reason="Failed creating a FTS"})
- end;
-login(_OE_This, State, User, Password, Account) when ?is_NATIVE(State) ->
- case catch 'CosFileTransfer_FileTransferSession':
- oe_create([{'NATIVE', ?get_Module(State)}, ?get_Host(State),
- ?get_Port(State), User, Password, Account,
- ?get_Protocol(State), ?get_Timeout(State)],
- [{sup_child, true}]) of
- {ok, _Pid, FTS} ->
- Dir = 'CosFileTransfer_FileTransferSession':
- oe_orber_create_directory_current(FTS),
- {reply, {FTS, Dir}, State};
- What ->
- orber:debug_level_print("[~p] CosFileTransfer_VirtualFileSystem:login(~p ~p ~p ~p);
-Unable to create a FileTransferSession: ~p",
- [?LINE, ?get_Host(State), ?get_Port(State), User,
- ?get_Protocol(State), What],
- ?DEBUG_LEVEL),
- corba:raise(#'CosFileTransfer_SessionException'{reason="Failed creating a FTS"})
- end.
-
-%%======================================================================
-%% Internal functions
-%%======================================================================
-
-
-
-%%======================================================================
-%% END OF MODULE
-%%======================================================================
diff --git a/lib/cosFileTransfer/src/Makefile b/lib/cosFileTransfer/src/Makefile
deleted file mode 100644
index b3967101e9..0000000000
--- a/lib/cosFileTransfer/src/Makefile
+++ /dev/null
@@ -1,188 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2000-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-
-ifeq ($(TYPE),debug)
-ERL_COMPILE_FLAGS += -Ddebug -W
-endif
-
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(COSFILETRANSFER_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/cosFileTransfer-$(VSN)
-
-EXTERNAL_INC_PATH = ../include
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-
-MODULES = \
- cosFileTransferApp \
- CosFileTransfer_Directory_impl \
- CosFileTransfer_File_impl \
- CosFileTransfer_VirtualFileSystem_impl \
- CosFileTransfer_FileTransferSession_impl \
- CosFileTransfer_FileIterator_impl \
- cosFileTransferNATIVE_file \
-
-ERL_FILES = $(MODULES:%=%.erl)
-HRL_FILES = \
- cosFileTransferApp.hrl \
-
-GEN_ERL_FILES = \
- oe_CosFileTransfer.erl \
- CosFileTransfer.erl \
- CosFileTransfer_AccessLevel.erl \
- CosFileTransfer_CommandNotImplementedException.erl \
- CosFileTransfer_Directory.erl \
- CosFileTransfer_File.erl \
- CosFileTransfer_FileIterator.erl \
- CosFileTransfer_FileList.erl \
- CosFileTransfer_FileNameList.erl \
- CosFileTransfer_FileNotFoundException.erl \
- CosFileTransfer_FileTransferSession.erl \
- CosFileTransfer_FileWrapper.erl \
- CosFileTransfer_IllegalOperationException.erl \
- CosFileTransfer_ProtocolAddressList.erl \
- CosFileTransfer_ProtocolSupport.erl \
- CosFileTransfer_RequestFailureException.erl \
- CosFileTransfer_SessionException.erl \
- CosFileTransfer_SupportedProtocolAddresses.erl \
- CosFileTransfer_TransferException.erl \
- CosFileTransfer_VirtualFileSystem.erl \
- CosFileTransfer_VirtualFileSystem_ContentList.erl \
-
-LOCAL_HRL_FILES = \
- oe_CosFileTransfer.hrl \
- CosFileTransfer.hrl \
- CosFileTransfer_Directory.hrl \
- CosFileTransfer_File.hrl \
- CosFileTransfer_FileIterator.hrl \
- CosFileTransfer_FileTransferSession.hrl \
- CosFileTransfer_VirtualFileSystem.hrl \
-
-GEN_HRL_FILES = $(LOCAL_HRL_FILES:%=$(EXTERNAL_INC_PATH)/%)
-
-GEN_FILES = \
- $(GEN_HRL_FILES) \
- $(GEN_ERL_FILES)
-
-TARGET_FILES = \
- $(GEN_ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR)) \
- $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-
-IDL_FILES = \
- CosFileTransfer.idl
-
-APPUP_FILE = cosFileTransfer.appup
-APPUP_SRC = $(APPUP_FILE).src
-APPUP_TARGET = $(EBIN)/$(APPUP_FILE)
-
-APP_FILE = cosFileTransfer.app
-APP_SRC = $(APP_FILE).src
-APP_TARGET = $(EBIN)/$(APP_FILE)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_IDL_FLAGS += -pa $(ERL_TOP)/lib/cosFileTransfer/ebin \
- -pa $(ERL_TOP)/lib/cosProperty/ebin \
- -pa $(ERL_TOP)/lib/cosProperty/src \
- -I$(ERL_TOP)/lib/cosProperty/src \
- -pa $(ERL_TOP)/lib/ic/ebin \
- -pa $(ERL_TOP)/lib/orber/ebin
-
-# The -pa option is just used temporary until erlc can handle
-# includes from other directories than ../include .
-ERL_COMPILE_FLAGS += \
- $(ERL_IDL_FLAGS) \
- -pa $(ERL_TOP)/lib/orber/include \
- -pa $(ERL_TOP)/lib/cosFileTransfer/include \
- -pa $(ERL_TOP)/lib/cosProperty/include \
- -pa $(ERL_TOP)/lib/cosProperty/src \
- -I$(ERL_TOP)/lib/orber/include \
- -I$(ERL_TOP)/lib/cosFileTransfer/include \
- -I$(ERL_TOP)/lib/cosProperty/include \
- -I$(ERL_TOP)/lib/cosProperty/src \
- +'{parse_transform,sys_pre_attributes}' \
- +'{attribute,insert,app_vsn,"cosFileTransfer_$(COSFILETRANSFER_VSN)"}'
-
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
-
-debug:
- @${MAKE} TYPE=debug opt
-
-cleanb:
- rm -f $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
- rm -f errs core *~
-
-clean:
- rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET) IDL-GENERATED
- rm -f errs core *~
-
-$(APP_TARGET): $(APP_SRC)
- $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
-
-$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
-
-docs:
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-IDL-GENERATED: CosFileTransfer.idl
- $(gen_verbose)erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosFileTransfer.cfg"}' CosFileTransfer.idl
- $(V_at)mv $(LOCAL_HRL_FILES) $(EXTERNAL_INC_PATH)
- $(V_at)>IDL-GENERATED
-
-$(GEN_FILES): IDL-GENERATED
-
-$(TARGET_FILES): IDL-GENERATED
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
- $(INSTALL_DIR) "$(RELSYSDIR)/src"
- $(INSTALL_DATA) $(GEN_FILES) $(IDL_FILES) "$(RELSYSDIR)/src"
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(GEN_ERL_FILES) $(IDL_FILES) "$(RELSYSDIR)/src"
- $(INSTALL_DIR) "$(RELSYSDIR)/include"
- $(INSTALL_DATA) $(GEN_HRL_FILES) "$(RELSYSDIR)/include"
-
-release_docs_spec:
diff --git a/lib/cosFileTransfer/src/cosFileTransfer.app.src b/lib/cosFileTransfer/src/cosFileTransfer.app.src
deleted file mode 100644
index 033eec9700..0000000000
--- a/lib/cosFileTransfer/src/cosFileTransfer.app.src
+++ /dev/null
@@ -1,43 +0,0 @@
-{application, cosFileTransfer,
- [{description, "The Erlang CosFileTransfer application"},
- {vsn, "%VSN%"},
- {modules,
- [
- 'cosFileTransferApp',
- 'CosFileTransfer_Directory_impl',
- 'CosFileTransfer_File_impl',
- 'CosFileTransfer_VirtualFileSystem_impl',
- 'CosFileTransfer_FileTransferSession_impl',
- 'CosFileTransfer_FileIterator_impl',
- 'cosFileTransferNATIVE_file',
- 'oe_CosFileTransfer',
- 'CosFileTransfer',
- 'CosFileTransfer_AccessLevel',
- 'CosFileTransfer_CommandNotImplementedException',
- 'CosFileTransfer_Directory',
- 'CosFileTransfer_File',
- 'CosFileTransfer_FileIterator',
- 'CosFileTransfer_FileList',
- 'CosFileTransfer_FileNameList',
- 'CosFileTransfer_FileNotFoundException',
- 'CosFileTransfer_FileTransferSession',
- 'CosFileTransfer_FileWrapper',
- 'CosFileTransfer_IllegalOperationException',
- 'CosFileTransfer_ProtocolAddressList',
- 'CosFileTransfer_ProtocolSupport',
- 'CosFileTransfer_RequestFailureException',
- 'CosFileTransfer_SessionException',
- 'CosFileTransfer_SupportedProtocolAddresses',
- 'CosFileTransfer_TransferException',
- 'CosFileTransfer_VirtualFileSystem',
- 'CosFileTransfer_VirtualFileSystem_ContentList'
- ]
- },
- {registered, []},
- {applications, [orber, stdlib, kernel]},
- {env, []},
- {mod, {cosFileTransferApp, []}},
- {runtime_dependencies, ["stdlib-2.0","ssl-5.3.4","orber-3.6.27","kernel-3.0",
- "inets-5.10","erts-7.0","cosProperty-1.1.17"]}
-]}.
-
diff --git a/lib/cosFileTransfer/src/cosFileTransfer.appup.src b/lib/cosFileTransfer/src/cosFileTransfer.appup.src
deleted file mode 100644
index 6c3b2833b7..0000000000
--- a/lib/cosFileTransfer/src/cosFileTransfer.appup.src
+++ /dev/null
@@ -1,7 +0,0 @@
-{"%VSN%",
- [
- ],
- [
- ]
-}.
-
diff --git a/lib/cosFileTransfer/src/cosFileTransferApp.erl b/lib/cosFileTransfer/src/cosFileTransferApp.erl
deleted file mode 100644
index 29a7237d70..0000000000
--- a/lib/cosFileTransfer/src/cosFileTransferApp.erl
+++ /dev/null
@@ -1,471 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2015. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : cosFileTransferApp.erl
-%% Purpose :
-%% Created : 25 Aug 2000
-%%----------------------------------------------------------------------
--module(cosFileTransferApp).
-
-
-%%--------------- INCLUDES -----------------------------------
--include("cosFileTransferApp.hrl").
-
-%%--------------- EXPORTS-------------------------------------
-%% cosFileTransferApp API external
--export([start/0, stop/0, install/0, uninstall/0, create_VFS/4, create_VFS/5,
- get_buffert_size/0]).
-
-%% cosFileTransferApp API internal
--export([create_link/3, get_option/3, type_check/2, configure/2]).
-
-%% Application callbacks
--export([start/2, init/1, stop/1]).
-
-%% INTERNAL EXPORTS!! DO NOT USE THESE!!
--export([create_dir/2, create_dir/3, create_file/2, create_file/3, split_paths/1,
- create_name/1]).
-
--export([ssl_server_certfile/0, ssl_client_certfile/0, ssl_port/0,
- ssl_server_verify/0,
- ssl_client_verify/0,
- ssl_server_depth/0, ssl_client_depth/0,
- ssl_server_cacertfile/0,
- ssl_client_cacertfile/0]).
-
-
-%%--------------- DEFINES ------------------------------------
--define(SUPERVISOR_NAME, oe_cosFileTransferSup).
--define(SUP_FLAG, {simple_one_for_one,50,10}).
--define(SUP_DIRECTORY_SPEC(Name, Args),
- ['CosFileTransfer_Directory',Args,
- [{sup_child, true}, {regname, {global, Name}}]]).
--define(SUP_CHILD,
- {"oe_FileTransferChild",
- {cosFileTransfer,create_link, []},
- transient,100000,worker,
- []}).
-
-%%------------------------------------------------------------
-%% function : install
-%% Arguments: -
-%% Returns : ok | EXIT | EXCEPTION
-%% Effect : Install necessary data in the IFR DB
-%%------------------------------------------------------------
-install() ->
- oe_CosFileTransfer:oe_register().
-
-%%------------------------------------------------------------
-%% function : uninstall
-%% Arguments: -
-%% Returns : ok | EXIT | EXCEPTION
-%% Effect : Remove data related to cosFileTransfer from the IFR DB
-%%------------------------------------------------------------
-uninstall() ->
- oe_CosFileTransfer:oe_unregister().
-
-
-%%------------------------------------------------------------
-%% function : start/stop
-%% Arguments:
-%% Returns :
-%% Effect : Starts or stops the cosFileTransfer application.
-%%------------------------------------------------------------
-start() ->
- application:start(cosFileTransfer).
-stop() ->
- application:stop(cosFileTransfer).
-
-%%------------------------------------------------------------
-%% function : start
-%% Arguments: Type - see module application
-%% Arg - see module application
-%% Returns :
-%% Effect : Module callback for application
-%%------------------------------------------------------------
-start(_, _) ->
- supervisor:start_link({local, ?SUPERVISOR_NAME}, cosFileTransferApp, app_init).
-
-
-%%------------------------------------------------------------
-%% function : stop
-%% Arguments: Arg - see module application
-%% Returns :
-%% Effect : Module callback for application
-%%------------------------------------------------------------
-stop(_) ->
- ok.
-
-%%-----------------------------------------------------------%
-%% function : init
-%% Arguments:
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-%% Starting using create_factory/X
-init(own_init) ->
- {ok,{?SUP_FLAG, [?SUP_CHILD]}};
-%% When starting as an application.
-init(app_init) ->
- {ok,{?SUP_FLAG, [?SUP_CHILD]}}.
-
-%%------------------------------------------------------------
-%% function : create_VFS
-%% Arguments:
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-create_VFS(Type, Content, Host, Port) ->
- create_VFS(Type, Content, Host, Port, []).
-
-create_VFS('FTP', Content, Host, Port, Options)
- when is_list(Host) andalso is_integer(Port) andalso is_list(Options) ->
- 'CosFileTransfer_VirtualFileSystem':oe_create(['FTP', Content, Host, Port,
- Options],
- [{pseudo, true}]);
-create_VFS({'NATIVE', Mod}, Content, Host, Port, Options)
- when is_list(Host) andalso is_integer(Port) andalso is_list(Options) ->
- 'CosFileTransfer_VirtualFileSystem':oe_create([{'NATIVE', Mod}, Content,
- Host, Port, Options],
- [{pseudo, true}]);
-create_VFS(_, _, _, _, _) ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%-----------------------------------------------------------%
-%% function : create_link
-%% Arguments: Module - which Module to call
-%% Env/ArgList - ordinary oe_create arguments.
-%% Returns :
-%% Exception:
-%% Effect : Necessary since we want the supervisor to be a
-%% 'simple_one_for_one'. Otherwise, using for example,
-%% 'one_for_one', we have to call supervisor:delete_child
-%% to remove the childs startspecification from the
-%% supervisors internal state.
-%%------------------------------------------------------------
-create_link(Module, Env, ArgList) ->
- Module:oe_create_link(Env, ArgList).
-
-%%-----------------------------------------------------------%
-%% function : get_option
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-get_option(Key, OptionList, DefaultList) ->
- case lists:keysearch(Key, 1, OptionList) of
- {value,{Key,Value}} ->
- Value;
- _ ->
- case lists:keysearch(Key, 1, DefaultList) of
- {value,{Key,Value}} ->
- Value;
- _->
- {error, "Invalid option"}
- end
- end.
-
-%%-----------------------------------------------------------%
-%% function : type_check
-%% Arguments: Obj - objectrefernce to test.
-%% Mod - Module which contains typeID/0.
-%% Returns : 'ok' or raises exception.
-%% Effect :
-%%------------------------------------------------------------
-type_check(Obj, Mod) ->
- case catch corba_object:is_a(Obj,Mod:typeID()) of
- true ->
- ok;
- _ ->
- corba:raise(#'BAD_PARAM'{minor=700, completion_status=?COMPLETED_NO})
- end.
-
-
-%%-----------------------------------------------------------%
-%% function : create_name/1
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-create_name(Type) ->
- Time = erlang:system_time(),
- Unique = erlang:unique_integer([positive]),
- lists:concat(['oe_',node(),'_',Type,'_',Time,'_',Unique]).
-
-
-%%-----------------------------------------------------------%
-%% function : get_buffert_size/0
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect : Lookup the configuration variable 'buffert_size'
-%%------------------------------------------------------------
-get_buffert_size() ->
- case application:get_env(cosFileTransfer, buffert_size) of
- {ok, Size} when is_integer(Size) ->
- Size;
- _ ->
- ?DEFAULT_BUFSIZE
- end.
-
-%%-----------------------------------------------------------%
-%% function : configure/1
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-configure(buffert_size, Value) when is_integer(Value) ->
- do_configure(buffert_size, Value);
-configure(ssl_port, Value) when is_integer(Value) ->
- do_safe_configure(ssl_port, Value);
-configure(ssl_server_certfile, Value) when is_list(Value) ->
- do_safe_configure(ssl_server_certfile, Value);
-configure(ssl_server_certfile, Value) when is_atom(Value) ->
- do_safe_configure(ssl_server_certfile, atom_to_list(Value));
-configure(ssl_client_certfile, Value) when is_list(Value) ->
- do_safe_configure(ssl_client_certfile, Value);
-configure(ssl_client_certfile, Value) when is_atom(Value) ->
- do_safe_configure(ssl_client_certfile, atom_to_list(Value));
-configure(ssl_server_verify, Value) when is_integer(Value) ->
- do_safe_configure(ssl_server_verify, Value);
-configure(ssl_client_verify, Value) when is_integer(Value) ->
- do_safe_configure(ssl_client_verify, Value);
-configure(ssl_server_depth, Value) when is_integer(Value) ->
- do_safe_configure(ssl_server_depth, Value);
-configure(ssl_client_depth, Value) when is_integer(Value) ->
- do_safe_configure(ssl_client_depth, Value);
-configure(ssl_server_cacertfile, Value) when is_list(Value) ->
- do_safe_configure(ssl_server_cacertfile, Value);
-configure(ssl_server_cacertfile, Value) when is_atom(Value) ->
- do_safe_configure(ssl_server_cacertfile, atom_to_list(Value));
-configure(ssl_client_cacertfile, Value) when is_list(Value) ->
- do_safe_configure(ssl_client_cacertfile, Value);
-configure(ssl_client_cacertfile, Value) when is_atom(Value) ->
- do_safe_configure(ssl_client_cacertfile, atom_to_list(Value));
-configure(_, _) ->
- exit({error, "Bad configure parameter(s)"}).
-
-%% This function may be used as long as it is safe to change a value at any time.
-do_configure(Key, Value) ->
- case is_loaded() of
- false ->
- application:load(cosFileTransfer),
- application_controller:set_env(cosFileTransfer, Key, Value);
- true ->
- application_controller:set_env(cosFileTransfer, Key, Value)
- end.
-
-
-%% This function MUST(!!) be used when we cannot change a value if cosFileTransfer
-%% is running.
-do_safe_configure(Key, Value) ->
- case is_loaded() of
- false ->
- application:load(cosFileTransfer),
- application_controller:set_env(cosFileTransfer, Key, Value);
- true ->
- case is_running() of
- false ->
- application_controller:set_env(cosFileTransfer, Key, Value);
- true ->
- exit("cosFileTransfer already running, the given key may not be updated!")
- end
- end.
-
-%%-----------------------------------------------------------%
-%% function : SSL parameter access functions
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-ssl_port() ->
- case application:get_env(cosFileTransfer, ssl_port) of
- {ok, Port} when is_integer(Port) ->
- Port;
- _ ->
- -1
- end.
-
-ssl_server_certfile() ->
- case application:get_env(cosFileTransfer, ssl_server_certfile) of
- {ok, V1} when is_list(V1) ->
- V1;
- {ok, V2} when is_atom(V2) ->
- atom_to_list(V2);
- _What ->
- {ok, Cwd} = file:get_cwd(),
- filename:join(Cwd,"ssl_server_cert.pem")
- end.
-
-
-ssl_client_certfile() ->
- case application:get_env(cosFileTransfer, ssl_client_certfile) of
- {ok, V1} when is_list(V1) ->
- V1;
- {ok, V2} when is_atom(V2) ->
- atom_to_list(V2);
- _ ->
- {ok, Cwd} = file:get_cwd(),
- filename:join(Cwd,"ssl_client_cert.pem")
- end.
-
-ssl_server_verify() ->
- Verify = case application:get_env(cosFileTransfer, ssl_server_verify) of
- {ok, V} when is_integer(V) ->
- V;
- _ ->
- 0
- end,
- if
- Verify =< 2, Verify >= 0 ->
- Verify;
- true ->
- 0
- end.
-
-ssl_client_verify() ->
- Verify = case application:get_env(cosFileTransfer, ssl_client_verify) of
- {ok, V1} when is_integer(V1) ->
- V1;
- _ ->
- 0
- end,
- if
- Verify =< 2, Verify >= 0 ->
- Verify;
- true ->
- 0
- end.
-
-ssl_server_depth() ->
- case application:get_env(cosFileTransfer, ssl_server_depth) of
- {ok, V1} when is_integer(V1) ->
- V1;
- _ ->
- 1
- end.
-
-ssl_client_depth() ->
- case application:get_env(cosFileTransfer, ssl_client_depth) of
- {ok, V1} when is_integer(V1) ->
- V1;
- _ ->
- 1
- end.
-
-
-ssl_server_cacertfile() ->
- case application:get_env(cosFileTransfer, ssl_server_cacertfile) of
- {ok, V1} when is_list(V1) ->
- V1;
- {ok, V2} when is_atom(V2) ->
- atom_to_list(V2);
- _ ->
- []
- end.
-
-ssl_client_cacertfile() ->
- case application:get_env(cosFileTransfer, ssl_client_cacertfile) of
- {ok, V1} when is_list(V1) ->
- V1;
- {ok, V2} when is_atom(V2) ->
- atom_to_list(V2);
- _ ->
- []
- end.
-
-
-%%============================================================
-%% Internal functions
-%%============================================================
-%%-----------------------------------------------------------%
-%% function : is_loaded/0
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect : Check if the application is loaded
-%%------------------------------------------------------------
-is_loaded() ->
- is_loaded(application:loaded_applications()).
-
-is_running() ->
- is_loaded(application:which_applications()).
-
-is_loaded([]) ->
- false;
-is_loaded([{cosFileTransfer, _, _} |_As]) ->
- true;
-is_loaded([_ |As]) ->
- is_loaded(As).
-
-
-
-
-%%-----------------------------------------------------------%
-%% function : create_dir/3/4
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-create_dir(Session, FileNameList) ->
- create_dir(Session, FileNameList, corba:create_nil_objref()).
-create_dir(Session, FileNameList, Parent) ->
- 'CosFileTransfer_Directory':oe_create([lists:last(FileNameList), FileNameList,
- Parent, Session],
- [{pseudo, true}]).
-
-%%-----------------------------------------------------------%
-%% function : create_file/2/3
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-create_file(Session, FileNameList) ->
- create_file(Session, FileNameList, corba:create_nil_objref()).
-create_file(Session, FileNameList, Parent) ->
- 'CosFileTransfer_File':oe_create([lists:last(FileNameList), FileNameList,
- Parent, Session], [{pseudo, true}]).
-
-%%-----------------------------------------------------------%
-%% function : split_paths
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-split_paths(Listing) ->
- split_paths(string:tokens(Listing, ?SEPARATOR), []).
-split_paths([], Acc) ->
- Acc;
-split_paths([H|T], Acc) ->
- split_paths(T, [filename:split(H)|Acc]).
-
-
-%%--------------- END OF MODULE ------------------------------
-
-
diff --git a/lib/cosFileTransfer/src/cosFileTransferApp.hrl b/lib/cosFileTransfer/src/cosFileTransferApp.hrl
deleted file mode 100644
index 037be7a4af..0000000000
--- a/lib/cosFileTransfer/src/cosFileTransferApp.hrl
+++ /dev/null
@@ -1,69 +0,0 @@
-%%----------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : cosFileTransferApp.hrl
-%% Purpose :
-%% Created : 10 Feb 2000
-%%----------------------------------------------------------------------
-
-
-%%--------------- INCLUDES -----------------------------------
-%% External
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
--include_lib("cosProperty/include/CosPropertyService.hrl").
-
-%% Local
--include_lib("cosFileTransfer/include/CosFileTransfer.hrl").
-
--define(write_ErrorMsg(Txt, Arg),
-error_logger:error_msg("============= CosFileTransfer =============~n"
- Txt
- "===========================================~n",
- Arg)).
-
--define(FTP_PORT_INT, 21).
--define(FTP_PORT_STR, "21").
--define(TCP_ID, "TCP").
--define(FTP_ID, "FTP").
--define(FTAM_ID, "FTAM").
--define(NATIVE_ID, "NATIVE").
--define(SUPPURTED_PROTOCOLS, ["TCP/IP", "SSL"]).
-
--define(DEFAULT_CONFIG, [{protocol, tcp}, {connect_timeout, 60}]).
-
--define(SEPARATOR, "\r\n").
-
--define(DEFAULT_BUFSIZE, 64000).
-
--define(DEBUG_LEVEL, 3).
-
--ifdef(debug).
--define(debug_print(F,A),
- io:format("[LINE: ~p MODULE: ~p] "++F,[?LINE, ?MODULE]++A)).
--define(ft_TypeCheck(O,M), 'cosFileTransferApp':type_check(O,M)).
--else.
--define(debug_print(F,A), ok).
--define(ft_TypeCheck(O,I), ok).
--endif.
-
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/cosFileTransfer/src/cosFileTransferNATIVE_file.erl b/lib/cosFileTransfer/src/cosFileTransferNATIVE_file.erl
deleted file mode 100644
index 2969e61a2b..0000000000
--- a/lib/cosFileTransfer/src/cosFileTransferNATIVE_file.erl
+++ /dev/null
@@ -1,359 +0,0 @@
-%%----------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : cosFileTransferNATIVE_file.erl
-%% Description :
-%%
-%% Created : 9 Nov 2000
-%%----------------------------------------------------------------------
--module('cosFileTransferNATIVE_file').
-
-
-%%----------------------------------------------------------------------
-%% Include files
-%%----------------------------------------------------------------------
--include("cosFileTransferApp.hrl").
--include_lib("kernel/include/file.hrl").
-
-%%----------------------------------------------------------------------
-%% External exports
-%%----------------------------------------------------------------------
--export([open/1,
- open/2,
- open/3,
- user/3,
- pwd/1,
- cd/2,
- mkdir/2,
- rmdir/2,
- nlist/1,
- nlist/2,
- delete/2,
- recv/2,
- recv/3,
- send/2,
- send/3,
- close/1,
- insert/4]).
-
-%%----------------------------------------------------------------------
-%% Internal exports
-%%----------------------------------------------------------------------
--export([]).
-
-%%----------------------------------------------------------------------
-%% Records
-%%----------------------------------------------------------------------
-
-%%----------------------------------------------------------------------
-%% Macros
-%%----------------------------------------------------------------------
-
-%%======================================================================
-%% External functions
-%%======================================================================
-%%----------------------------------------------------------------------
-%% function : open
-%% Arguments:
-%% Returns : {ok, Ref} | {error, ehost} for future use
-%% Effect :
-%%----------------------------------------------------------------------
-open(_Host) ->
- {ok, 'NATIVE'}.
-open(_Host, _Port) ->
- {ok, 'NATIVE'}.
-open(_Host, _Port, _Flags) ->
- {ok, 'NATIVE'}.
-
-%%----------------------------------------------------------------------
-%% function : user
-%% Arguments: Ref - what's returned by open/1/2
-%% User = Password = string()
-%% Returns : ok | {error, euser | econn} for future use
-%% Effect :
-%%----------------------------------------------------------------------
-user(_Ref, _User, _Password) ->
- ok.
-
-%%----------------------------------------------------------------------
-%% function : pwd
-%% Arguments: Ref - what's returned by open/1/2
-%% Returns : {ok, string()} | {error, elogin | econn}
-%% Effect :
-%%----------------------------------------------------------------------
-pwd(_Ref) ->
- case file:get_cwd() of
- {ok, Cwd} ->
- {ok, Cwd};
- _ ->
- {error, econn}
- end.
-
-%%----------------------------------------------------------------------
-%% function : cd
-%% Arguments: Ref - what's returned by open/1/2
-%% Dir - string()
-%% Returns : ok | {error, epath | elogin | econn}
-%% Effect :
-%%----------------------------------------------------------------------
-cd(_Ref, Dir) ->
- case file:set_cwd(Dir) of
- ok ->
- ok;
- {error, _} ->
- {error, epath}
- end.
-
-%%----------------------------------------------------------------------
-%% function : mkdir
-%% Arguments: Ref - what's returned by open/1/2
-%% Dir - string()
-%% Returns : ok | {error, epath}
-%% Effect :
-%%----------------------------------------------------------------------
-mkdir(_Ref, Dir) ->
- case file:make_dir(Dir) of
- ok ->
- ok;
- {error, _Reason} ->
- {error, epath}
- end.
-
-%%----------------------------------------------------------------------
-%% function : rmdir
-%% Arguments: Ref - what's returned by open/1/2
-%% Dir - string()
-%% Returns : ok | {error, epath}
-%% Effect :
-%%----------------------------------------------------------------------
-rmdir(_Ref, Dir) ->
- case file:del_dir(Dir) of
- ok ->
- ok;
- {error, _Reason} ->
- {error, epath}
- end.
-
-%%----------------------------------------------------------------------
-%% function : nlist
-%% Arguments: Ref - what's returned by open/1/2
-%% Dir - string()
-%% Returns : {ok, Listing} | {error, epath | elogin | econn}
-%% Effect :
-%%----------------------------------------------------------------------
-nlist(_Ref) ->
- case file:get_cwd() of
- {ok, Cwd} ->
- %% Here we can assume that it's a Directory is tested.
- convert_to_nlist(file:list_dir(Cwd));
- _ ->
- {error, epath}
- end.
-nlist(_Ref, Dir) ->
- case file:list_dir(Dir) of
- {error, _} ->
- %% Might be a File
- case file:read_file_info(Dir) of
- {ok, _} ->
- convert_to_nlist_helper([Dir], []);
- _ ->
- {error, epath}
- end;
- {ok, Content} ->
- convert_to_nlist_helper(Content, [])
- end.
-
-convert_to_nlist({error, _}) ->
- {error, epath};
-convert_to_nlist({ok, Content}) ->
- convert_to_nlist_helper(Content, []).
-
-convert_to_nlist_helper([], Acc) ->
- {ok, lists:concat(Acc)};
-convert_to_nlist_helper([H|T], Acc) ->
- convert_to_nlist_helper(T, [H, "\r\n"|Acc]).
-
-%%----------------------------------------------------------------------
-%% function : delete
-%% Arguments: Ref - what's returned by open/1/2
-%% File - string()
-%% Returns : ok | {error, epath}
-%% Effect :
-%%----------------------------------------------------------------------
-delete(_Ref, File) ->
- case file:delete(File) of
- ok ->
- ok;
- {error, _Reason} ->
- {error, epath}
- end.
-
-%%----------------------------------------------------------------------
-%% function : recv
-%% Arguments: Ref - what's returned by open/1/2
-%% Returns : ok | {error, epath | elogin | econn}
-%% Effect :
-%%----------------------------------------------------------------------
-recv(_Ref, _Remote) ->
- ok.
-recv(_Ref, Remote, Local) ->
- copy_file(Remote, Local).
-
-%%----------------------------------------------------------------------
-%% function : send
-%% Arguments: Ref - what's returned by open/1/2
-%% Returns : ok | {error, epath | elogin | econn | etnospc | epnospc | efnamena}
-%% Effect :
-%%----------------------------------------------------------------------
-send(_Ref, _Local) ->
- ok.
-send(_Ref, Local, Remote) ->
- copy_file(Local, Remote).
-
-%%----------------------------------------------------------------------
-%% function : close
-%% Arguments: Ref - what's returned by open/1/2
-%% Returns : ok
-%% Effect : Currently none.
-%%----------------------------------------------------------------------
-close(_) ->
- ok.
-
-
-%%----------------------------------------------------------------------
-%% function : insert
-%% Arguments: Ref - what's returned by open/1/2
-%% Local - absolute file name
-%% Remote - absolute file name
-%% Offset - long()
-%% Returns : ok
-%% Effect :
-%%----------------------------------------------------------------------
-insert(_Ref, Source, Target, Offset) ->
- case file:open(Source, [raw, binary, read]) of
- {ok, SourceDev} ->
- case file:open(Target, [raw, binary, read, write]) of
- {ok, TargetDev} ->
- {ok, #file_info{size=SSize}} =
- file:read_file_info(Source),
- {ok, #file_info{size=TSize}} =
- file:read_file_info(Target),
- insert_file_helper(SourceDev, TargetDev, SSize, TSize, Offset);
- Reason ->
- file:close(SourceDev),
- convert_error(Reason)
- end;
- Reason ->
- convert_error(Reason)
- end.
-
-
-insert_file_helper(SourceDev, TargetDev, SSize, TSize, Offset) ->
- BuffSize = cosFileTransferApp:get_buffert_size(),
- move_data(TargetDev, TSize, SSize+TSize, TSize-Offset, BuffSize),
- insert_data(SourceDev, TargetDev, 0, Offset, BuffSize),
- file:close(SourceDev),
- file:close(TargetDev).
-move_data(_F, _RLocation, _WLocation, Counter, _BuffSize) when Counter == 0 ->
- ok;
-move_data(F, RLocation, WLocation, Counter, BuffSize) when Counter =< BuffSize ->
- case file:pread(F, RLocation-Counter, Counter) of
- {ok, Bin} ->
- file:pwrite(F, WLocation-Counter, Bin);
- eof ->
- ok
- end;
-move_data(F, RLocation, WLocation, Counter, BuffSize) ->
- NewRLC = RLocation-BuffSize,
- NewWLC = WLocation-BuffSize,
- case file:pread(F, NewRLC, BuffSize) of
- {ok, Bin} ->
- file:pwrite(F, NewWLC, Bin),
- move_data(F, NewRLC, NewWLC, Counter-BuffSize, BuffSize);
- eof ->
- ok
- end.
-
-insert_data(FSRC, FTGT, RLocation, WLocation, BuffSize) ->
- case file:pread(FSRC, RLocation, BuffSize) of
- {ok, Bin} ->
- file:pwrite(FTGT, WLocation, Bin),
- insert_data(FSRC, FTGT, RLocation+BuffSize, WLocation+BuffSize, BuffSize);
- eof ->
- ok
- end.
-
-
-%%======================================================================
-%% Internal functions
-%%======================================================================
-copy_file(Source, Target) ->
- case file:open(Source, [raw, binary, read]) of
- {ok, SourceDev} ->
- case file:open(Target, [raw, binary, append]) of
- {ok, TargetDev} ->
- BuffSize = cosFileTransferApp:get_buffert_size(),
- copy_file_helper(SourceDev, TargetDev, BuffSize);
- Reason ->
- file:close(SourceDev),
- convert_error(Reason)
- end;
- Reason ->
- convert_error(Reason)
- end.
-
-copy_file_helper(SourceDev, TargetDev, BuffSize) ->
- case file:read(SourceDev, BuffSize) of
- eof ->
- file:close(SourceDev),
- file:close(TargetDev);
- {ok, Bin} ->
- case file:write(TargetDev, Bin) of
- ok ->
- copy_file_helper(SourceDev, TargetDev, BuffSize);
- Reason ->
- file:close(SourceDev),
- file:close(TargetDev),
- convert_error(Reason)
- end;
- {error, Reason} ->
- file:close(SourceDev),
- file:close(TargetDev),
- convert_error(Reason)
- end.
-
-convert_error({error, eacces}) ->
- {error, elogin};
-convert_error({error, enoent}) ->
- {error, epath};
-convert_error({error, enotdir}) ->
- {error, epath};
-convert_error({error, eidir}) ->
- {error, epath};
-convert_error({error, enospc}) ->
- {error, etnospc};
-convert_error(_) ->
- {error, epath}.
-
-%%======================================================================
-%% END OF MODULE
-%%======================================================================
diff --git a/lib/cosFileTransfer/test/Makefile b/lib/cosFileTransfer/test/Makefile
deleted file mode 100644
index 45c67a95dd..0000000000
--- a/lib/cosFileTransfer/test/Makefile
+++ /dev/null
@@ -1,132 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2000-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(COSFILETRANSFER_VSN)
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/cosFileTransfer_test
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-TEST_SPEC_FILE = cosFileTransfer.spec
-COVER_FILE = cosFileTransfer.cover
-
-
-IDL_FILES =
-
-IDLOUTDIR = idl_output
-
-MODULES = \
- fileTransfer_SUITE \
-
-GEN_MODULES = \
-
-GEN_HRL_FILES = \
-
-ERL_FILES = $(MODULES:%=%.erl)
-
-HRL_FILES =
-
-GEN_FILES = \
- $(GEN_HRL_FILES:%=$(IDLOUTDIR)/%) \
- $(GEN_MODULES:%=$(IDLOUTDIR)/%.erl)
-
-GEN_TARGET_FILES = $(GEN_MODULES:%=$(IDLOUTDIR)/%.$(EMULATOR))
-
-SUITE_TARGET_FILES = $(MODULES:%=%.$(EMULATOR))
-
-TARGET_FILES = \
- $(GEN_TARGET_FILES) \
- $(SUITE_TARGET_FILES)
-
-
-# ----------------------------------------------------
-# PROGRAMS
-# ----------------------------------------------------
-LOCAL_CLASSPATH = $(ERL_TOP)lib/cosFileTransfer/priv:$(ERL_TOP)lib/cosFileTransfer/test
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_IDL_FLAGS += -pa $(ERL_TOP)/lib/cosFileTransfer/ebin \
- -pa $(ERL_TOP)/lib/cosFileTransfer/src \
- -pa $(ERL_TOP)/lib/cosFileTransfer/include \
- -pa $(ERL_TOP)/lib/cosProperty/ebin \
- -pa $(ERL_TOP)/lib/cosProperty/include \
- -pa $(ERL_TOP)/lib/orber/ebin \
- -pa $(ERL_TOP)/lib/ic/ebin
-
-ERL_COMPILE_FLAGS += \
- $(ERL_IDL_FLAGS) \
- -pa $(ERL_TOP)/lib/orber/include \
- -pa $(ERL_TOP)/lib/cosProperty/include \
- -pa $(ERL_TOP)/lib/cosFileTransfer/ebin \
- -pa $(ERL_TOP)/lib/cosFileTransfer/include \
- -pa $(ERL_TOP)/lib/cosFileTransfer/test/idl_output \
- -I$(ERL_TOP)/lib/orber/include \
- -I$(ERL_TOP)/lib/cosProperty/include \
- -I$(ERL_TOP)/lib/cosFileTransfer/src \
- -I$(ERL_TOP)/lib/cosFileTransfer/include \
- -I$(ERL_TOP)/lib/cosFileTransfer \
- -I$(ERL_TOP)/lib/cosFileTransfer/test/$(IDLOUTDIR)
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-
-tests debug opt: $(TARGET_FILES)
-
-clean:
- rm -f idl_output/*
- rm -f $(TARGET_FILES)
- rm -f errs core *~
-
-docs:
-
-# ----------------------------------------------------
-# Special Targets
-# ----------------------------------------------------
-
-# ----------------------------------------------------
-# Release Targets
-# ----------------------------------------------------
-# We don't copy generated intermediate erlang and hrl files
-
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec:
-
-release_docs_spec:
-
-release_tests_spec: tests
- $(INSTALL_DIR) "$(RELSYSDIR)"
- $(INSTALL_DATA) $(IDL_FILES) $(TEST_SPEC_FILE) \
- $(COVER_FILE) $(ERL_FILES) "$(RELSYSDIR)"
- $(INSTALL_DATA) $(SUITE_TARGET_FILES) "$(RELSYSDIR)"
- chmod -R u+w "$(RELSYSDIR)"
diff --git a/lib/cosFileTransfer/test/cosFileTransfer.cover b/lib/cosFileTransfer/test/cosFileTransfer.cover
deleted file mode 100644
index 063dd66990..0000000000
--- a/lib/cosFileTransfer/test/cosFileTransfer.cover
+++ /dev/null
@@ -1,2 +0,0 @@
-{incl_app,cosFileTransfer,details}.
-
diff --git a/lib/cosFileTransfer/test/cosFileTransfer.spec b/lib/cosFileTransfer/test/cosFileTransfer.spec
deleted file mode 100644
index 290b27d048..0000000000
--- a/lib/cosFileTransfer/test/cosFileTransfer.spec
+++ /dev/null
@@ -1 +0,0 @@
-{suites,"../cosFileTransfer_test", all}.
diff --git a/lib/cosFileTransfer/test/fileTransfer_SUITE.erl b/lib/cosFileTransfer/test/fileTransfer_SUITE.erl
deleted file mode 100644
index 12aef2913a..0000000000
--- a/lib/cosFileTransfer/test/fileTransfer_SUITE.erl
+++ /dev/null
@@ -1,938 +0,0 @@
-%%-----------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : fileTransfer_SUITE.erl
-%% Purpose :
-%%----------------------------------------------------------------------
-
--module(fileTransfer_SUITE).
-
-%%--------------- INCLUDES -----------------------------------
--include_lib("cosFileTransfer/src/cosFileTransferApp.hrl").
-
--include_lib("common_test/include/ct.hrl").
-
-%%--------------- DEFINES ------------------------------------
--define(default_timeout, test_server:minutes(20)).
--define(match(ExpectedRes, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- io:format("------ CORRECT RESULT ------~n~p~n",
- [AcTuAlReS]),
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
--define(matchnopr(ExpectedRes, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- io:format("------ CORRECT RESULT (~p) ------~n", [?LINE]),
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
-
-
-
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0,suite/0,groups/0,
- init_per_group/2,end_per_group/2,
- cases/0,
- init_per_suite/1,
- end_per_suite/1,
- fileIterator_api/1,
- fts_ftp_file_api/1,
- fts_ftp_file_ssl_api/1,
- fts_ftp_dir_api/1,
- fts_native_file_api/1,
- fts_native_file_ssl_api/1,
- fts_native_dir_api/1,
- init_per_testcase/2,
- end_per_testcase/2,
- install_data/2,
- uninstall_data/1,
- slave_sup/0,
- app_test/1]).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() ->
- [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- cases().
-
-groups() ->
- [].
-
-
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-cases() ->
- [fts_ftp_dir_api, fts_ftp_file_api,
- fts_ftp_file_ssl_api, fts_native_dir_api,
- fts_native_file_api, fts_native_file_ssl_api,
- fileIterator_api, app_test].
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-
-init_per_testcase(_Case, Config) ->
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-init_per_suite(Config) ->
- case crypto_works() of
- false ->
- {skip,"Could not start crypto!"};
- true ->
- orber:jump_start(),
- cosProperty:install(),
- cosProperty:start(),
- Dir = filename:join([code:lib_dir(ssl), "examples", "certs", "etc"]),
- %% Client
- cosFileTransferApp:configure(ssl_client_certfile,
- filename:join([Dir, "client", "cert.pem"])),
- cosFileTransferApp:configure(ssl_client_cacertfile,
- filename:join([Dir, "client", "cacerts.pem"])),
- cosFileTransferApp:configure(ssl_client_verify, 1),
- cosFileTransferApp:configure(ssl_client_depth, 0),
- %% Server
- cosFileTransferApp:configure(ssl_server_certfile,
- filename:join([Dir, "server", "cert.pem"])),
- cosFileTransferApp:configure(ssl_server_cacertfile,
- filename:join([Dir, "server", "cacerts.pem"])),
- cosFileTransferApp:configure(ssl_server_verify, 1),
- cosFileTransferApp:configure(ssl_server_depth, 0),
- crypto:start(),
- ssl:start(),
- cosFileTransferApp:install(),
- cosFileTransferApp:start(),
- if
- is_list(Config) ->
- Config;
- true ->
- exit("Config not a list")
- end
- end.
-
-crypto_works() ->
- try crypto:start() of
- {error,{already_started,crypto}} -> true;
- ok -> true
- catch
- error:_ ->
- false
- end.
-
-end_per_suite(Config) ->
- ssl:stop(),
- crypto:stop(),
- cosFileTransferApp:stop(),
- cosProperty:stop(),
- cosProperty:uninstall(),
- cosFileTransferApp:uninstall(),
- orber:jump_stop(),
- Config.
-
-%%-----------------------------------------------------------------
-%% Local definitions
-%%-----------------------------------------------------------------
--define(FTP_USER, "anonymous").
--define(FTP_PASS, "fileTransfer_SUITE@localhost").
--define(TEST_DIR,["/", "incoming"]).
-
--define(FTP_PORT, 21).
--define(FTP_ACC, "anonymous").
-
--define(BAD_HOST, "badhostname").
--define(BAD_USER, "baduser").
--define(BAD_DIR, "baddirectory").
-
--define(TEST_FILE_DATA, "If this file exists after a completed test an error occurred.").
--define(TEST_FILE_DATA2, "1234567890123").
-
-%%-----------------------------------------------------------------
-%% aoo-file test
-%%-----------------------------------------------------------------
-app_test(_Config) ->
- ok=?t:app_test(cosFileTransfer),
- ok.
-
-%%-----------------------------------------------------------------
-%% FileIterator API tests
-%%-----------------------------------------------------------------
-fileIterator_api(Config) ->
- case ftp_host(Config) of
- {skipped, SkippedReason} ->
- {skipped, SkippedReason};
- Host ->
-
- {ok, Node} = create_node("fileIterator_api", 4008, normal),
- ?match(ok, remote_apply(Node, ?MODULE, install_data,
- [tcp, {{'NATIVE',
- 'cosFileTransferNATIVE_file'}, Host,
- "fileIterator_api"}])),
-
- %% Create a Virtual File System.
-%% VFS = ?match({_,_,_,_,_,_},
-%% cosFileTransferApp:create_VFS({'NATIVE',
-%% 'cosFileTransferNATIVE_file'},
-%% [], Host, ?FTP_PORT)),
- VFS = ?matchnopr({'IOP_IOR',"IDL:omg.org/CosFileTransfer/VirtualFileSystem:1.0",_},
- corba:string_to_object("corbaname::1.2@localhost:4008/NameService#fileIterator_api")),
-
- %% Start two File Transfer Sessions (Source and Target).
- {FS, Dir} = ?matchnopr({{_,_,_},{_,_,_}},
- 'CosFileTransfer_VirtualFileSystem':login(VFS,
- ?FTP_USER,
- ?FTP_PASS,
- ?FTP_ACC)),
-
- %% Do some basic test on one of the Directories attributes.
- ?match([_H|_], 'CosFileTransfer_Directory':'_get_name'(Dir)),
- ?match([_H|_], 'CosFileTransfer_Directory':'_get_complete_file_name'(Dir)),
- ?match({'IOP_IOR',[],[]}, 'CosFileTransfer_Directory':'_get_parent'(Dir)),
- ?matchnopr(FS, 'CosFileTransfer_Directory':'_get_associated_session'(Dir)),
- {ok,[],FileIter} = ?match({ok,[],_}, 'CosFileTransfer_Directory':list(Dir, 0)),
- %% Usually the working directory for the test is not empty so no need for
- %% creating files of our own?!
- #any{value=Children} = ?match({any, _, _},
- 'CosPropertyService_PropertySet':
- get_property_value(Dir, "num_children")),
-
- if
- Children > 5 ->
- ?matchnopr({true, _}, 'CosFileTransfer_FileIterator':next_one(FileIter)),
- ?matchnopr({true, _}, 'CosFileTransfer_FileIterator':next_n(FileIter, 3)),
- ?matchnopr({true, _}, 'CosFileTransfer_FileIterator':next_n(FileIter,
- Children)),
- ?matchnopr({false, _}, 'CosFileTransfer_FileIterator':next_one(FileIter)),
- ?match({false, []}, 'CosFileTransfer_FileIterator':next_n(FileIter, 1)),
- ok;
- true ->
- ok
- end,
- ?match(ok, 'CosFileTransfer_FileIterator':destroy(FileIter)),
- ?match(false, corba_object:non_existent(FS)),
- ?match(ok, 'CosFileTransfer_FileTransferSession':logout(FS)),
- %% To make sure Orber can remove it from mnesia.
- timer:sleep(1000),
- ?match(true, corba_object:non_existent(FS)),
- ?match(ok, remote_apply(Node, ?MODULE, uninstall_data, ["fileIterator_api"])),
- stop_orber_remote(Node, normal),
- ok
- end.
-
-
-%%-----------------------------------------------------------------
-%% FileTransferSession API tests
-%%-----------------------------------------------------------------
-fts_ftp_file_api(Config) ->
- {ok, Node} = create_node("ftp_file_api", 4004, normal),
- file_helper(Config, 'FTP', ?TEST_DIR, Node, 4004, "ftp_file_api", tcp).
-
-fts_ftp_file_ssl_api(Config) ->
- {ok, Node} = create_node("ftp_file_api_ssl", {4005, 1}, ssl),
- file_helper(Config, 'FTP', ?TEST_DIR, Node, 4005, "ftp_file_api_ssl", ssl).
-
-fts_native_file_api(Config) ->
- {ok, Node} = create_node("native_file_api", 4006, normal),
- {ok, Pwd} = file:get_cwd(),
- file_helper(Config,{'NATIVE', 'cosFileTransferNATIVE_file'},filename:split(Pwd),
- Node, 4006, "native_file_api", tcp).
-
-fts_native_file_ssl_api(Config) ->
- {ok, Node} = create_node("native_file_ssl_api", {4007, 1}, ssl),
- {ok, Pwd} = file:get_cwd(),
- file_helper(Config,{'NATIVE', 'cosFileTransferNATIVE_file'},filename:split(Pwd),
- Node, 4007, "native_file_ssl_api", ssl).
-
-
-file_helper(Config, WhichType, TEST_DIR, Node, Port, Name, Type) ->
- case ftp_host(Config) of
- {skipped, SkippedReason} ->
- {skipped, SkippedReason};
- Host ->
- TEST_SOURCE = TEST_DIR ++ [create_name(remove_me_source)],
- TEST_SOURCE2 = TEST_DIR ++ [create_name(remove_me_source)],
- TEST_TARGET = TEST_DIR ++ [create_name(remove_me_target)],
-
- io:format("<<<<<< CosFileTransfer Testing Configuration >>>>>>~n",[]),
- io:format("Source: ~p~nTarget: ~p~n", [TEST_SOURCE, TEST_TARGET]),
-
- ?match(ok, remote_apply(Node, ?MODULE, install_data,
- [Type, {WhichType, Host, Name}])),
-
- VFST = ?match({'IOP_IOR',"IDL:omg.org/CosFileTransfer/VirtualFileSystem:1.0",_},
- corba:string_to_object("corbaname::1.2@localhost:"++integer_to_list(Port)++"/NameService#"++Name)),
-
-
- %% Create a Virtual File System.
- VFS = ?match({_,_,_,_,_,_},
- cosFileTransferApp:create_VFS(WhichType, [], Host, ?FTP_PORT,
- [{protocol, Type}])),
- %% Start two File Transfer Sessions (Source and Target).
- {FST, _DirT} = ?match({{_,_,_},{_,_,_}},
- 'CosFileTransfer_VirtualFileSystem':login(VFST,
- ?FTP_USER,
- ?FTP_PASS,
- ?FTP_ACC)),
- {FSS, DirS} = ?match({{_,_,_,_,_,_},{_,_,_,_,_,_}},
- 'CosFileTransfer_VirtualFileSystem':login(VFS,
- ?FTP_USER,
- ?FTP_PASS,
- ?FTP_ACC)),
-
- %% Do some basic test on one of the Directories attributes.
- ?match([_H|_], 'CosFileTransfer_Directory':'_get_name'(DirS)),
- ?match([_H|_], 'CosFileTransfer_Directory':'_get_complete_file_name'(DirS)),
- ?match({'IOP_IOR',[],[]}, 'CosFileTransfer_Directory':'_get_parent'(DirS)),
- ?match(FSS, 'CosFileTransfer_Directory':'_get_associated_session'(DirS)),
-
- %% Get a FileList before we create any new Files
- #'CosFileTransfer_FileWrapper'{the_file = Dir} =
- ?match({'CosFileTransfer_FileWrapper', _, ndirectory},
- 'CosFileTransfer_FileTransferSession':get_file(FSS, TEST_DIR)),
- {ok,FileList, Iter1} = ?match({ok,_,_}, 'CosFileTransfer_Directory':list(Dir, 10)),
- loop_files(FileList),
-
- case Iter1 of
- {'IOP_IOR',[],[]} ->
- ok;
- _->
- ?match(ok, 'CosFileTransfer_FileIterator':destroy(Iter1))
- end,
-
- #any{value=Count1} = ?match({any, _, _}, 'CosPropertyService_PropertySet':
- get_property_value(Dir, "num_children")),
-
- %% Now we want to transfer a file from source to target. First, we'll create
- %% a a file to work with.
- create_file_on_source_node(WhichType, Config, Host,
- filename:join(TEST_SOURCE), TEST_DIR,
- ?TEST_FILE_DATA),
- create_file_on_source_node(WhichType, Config, Host,
- filename:join(TEST_SOURCE2), TEST_DIR,
- ?TEST_FILE_DATA2),
-
- #'CosFileTransfer_FileWrapper'{the_file = FileS} =
- ?matchnopr({'CosFileTransfer_FileWrapper', _, nfile},
- 'CosFileTransfer_FileTransferSession':get_file(FSS, TEST_SOURCE)),
- #'CosFileTransfer_FileWrapper'{the_file = FileS2} =
- ?matchnopr({'CosFileTransfer_FileWrapper', _, nfile},
- 'CosFileTransfer_FileTransferSession':get_file(FSS, TEST_SOURCE2)),
-
- #any{value=Count2} = ?match({any, _, _}, 'CosPropertyService_PropertySet':
- get_property_value(Dir, "num_children")),
- timer:sleep(2000),
- ?match(true, (Count1+2 == Count2)),
-
- %% Create a target File
- FileT = ?matchnopr({_,_,_},
- 'CosFileTransfer_FileTransferSession':create_file(FST, TEST_TARGET)),
- %% Try to delete the non-existing file.
- ?match({'EXCEPTION', _},
- 'CosFileTransfer_FileTransferSession':delete(FST, FileT)),
-
- ?match(ok, 'CosFileTransfer_FileTransferSession':transfer(FSS, FileS, FileT)),
-
- %% Remove this test when ftp supports append.
- case WhichType of
- {'NATIVE', 'cosFileTransferNATIVE_file'} ->
- ?match(ok, 'CosFileTransfer_FileTransferSession':append(FSS, FileS, FileT)),
- ?match(ok, 'CosFileTransfer_FileTransferSession':insert(FSS, FileS2, FileT, 7));
- _->
- ok
- end,
-
- %% Delete source and target files
- ?match(ok, 'CosFileTransfer_FileTransferSession':delete(FSS, FileS)),
- ?match(ok, 'CosFileTransfer_FileTransferSession':delete(FSS, FileS2)),
- ?match(ok, 'CosFileTransfer_FileTransferSession':delete(FST, FileT)),
-
- %% Should be back where we started.
- timer:sleep(2000),
- #any{value=Count3} = ?match({any, _, _}, 'CosPropertyService_PropertySet':
- get_property_value(Dir, "num_children")),
- ?match(true, (Count1 == Count3)),
-
-
- ?match(false, corba_object:non_existent(FSS)),
- ?match(false, corba_object:non_existent(FST)),
- ?match(ok, 'CosFileTransfer_FileTransferSession':logout(FSS)),
- ?match(ok, 'CosFileTransfer_FileTransferSession':logout(FST)),
- %% To make sure Orber can remove it from mnesia.
- timer:sleep(2000),
- ?match(true, corba_object:non_existent(FSS)),
- ?match(true, corba_object:non_existent(FST)),
- ?match(ok, remote_apply(Node, ?MODULE, uninstall_data, [Name])),
- stop_orber_remote(Node, normal),
- ok
- end.
-
-%%-----------------------------------------------------------------
-%% FileTransferSession API tests
-%%-----------------------------------------------------------------
-fts_ftp_dir_api(Config) ->
- {ok, Node} = create_node("ftp_dir_api", 4009, normal),
- dir_helper(Config, 'FTP', ?TEST_DIR, Node, 4009, "ftp_dir_api").
-
-fts_native_dir_api(Config) ->
- {ok, Node} = create_node("native_dir_api", 4010, normal),
- {ok, Pwd} = file:get_cwd(),
- dir_helper(Config, {'NATIVE', 'cosFileTransferNATIVE_file'},
- filename:split(Pwd), Node, 4010, "native_dir_api").
-
-dir_helper(Config, WhichType, TEST_DIR, Node, Port, Name) ->
- case ftp_host(Config) of
- {skipped, SkippedReason} ->
- {skipped, SkippedReason};
- Host ->
- TEST_DIR_LEVEL1 = TEST_DIR ++ [create_name(remove_me_dir1)],
- TEST_DIR_LEVEL2 = TEST_DIR_LEVEL1 ++ [create_name(remove_me_dir2)],
-
- io:format("<<<<<< CosFileTransfer Testing Configuration >>>>>>~n",[]),
- io:format("Top Dir: ~p~nLevel2 Dir: ~p~n", [TEST_DIR_LEVEL1, TEST_DIR_LEVEL2]),
-
- ?match(ok, remote_apply(Node, ?MODULE, install_data,
- [tcp, {WhichType, Host, Name}])),
-
- VFS = ?matchnopr({'IOP_IOR',"IDL:omg.org/CosFileTransfer/VirtualFileSystem:1.0",_},
- corba:string_to_object("corbaname::1.2@localhost:"++integer_to_list(Port)++"/NameService#"++Name)),
-
- %% Start two File Transfer Sessions (Source and Target).
- {FS, DirS} = ?matchnopr({{'IOP_IOR',_,_}, _},
- 'CosFileTransfer_VirtualFileSystem':login(VFS,
- ?FTP_USER,
- ?FTP_PASS,
- ?FTP_ACC)),
-
- %% Do some basic test on one of the Directories attributes.
- ?match([_H|_], 'CosFileTransfer_Directory':'_get_name'(DirS)),
- ?match([_H|_], 'CosFileTransfer_Directory':'_get_complete_file_name'(DirS)),
- ?match({'IOP_IOR',[],[]}, 'CosFileTransfer_Directory':'_get_parent'(DirS)),
- ?matchnopr(FS, 'CosFileTransfer_Directory':'_get_associated_session'(DirS)),
-
- %% Create a Root Directory. Currently we only need to create one but
- %% later on, when supporting other protocols than FTP it's not enough.
- Dir1 = 'CosFileTransfer_FileTransferSession':create_directory(FS,
- TEST_DIR_LEVEL1),
- io:format("<<<<<< CosFileTransfer Testing Properties >>>>>>~n",[]),
- ?match({ok, [tk_long, tk_boolean]},
- 'CosFileTransfer_Directory':get_allowed_property_types(Dir1)),
- ?match({ok, [_,_]},
- 'CosFileTransfer_Directory':get_allowed_properties(Dir1)),
- ?match({'EXCEPTION', _},
- 'CosFileTransfer_Directory':define_property_with_mode(Dir1,
- "num_children",
- #any{typecode=tk_long, value=0},
- fixed_readonly)),
- ?match({'EXCEPTION', _},
- 'CosFileTransfer_Directory':define_property_with_mode(Dir1,
- "wrong",
- #any{typecode=tk_long, value=0},
- fixed_readonly)),
- ?match({'EXCEPTION', _},
- 'CosFileTransfer_Directory':define_property_with_mode(Dir1,
- "num_children",
- #any{typecode=tk_short, value=0},
- fixed_readonly)),
- ?match({'EXCEPTION', _},
- 'CosFileTransfer_Directory':define_property_with_mode(Dir1,
- "num_children",
- #any{typecode=tk_long, value=0},
- fixed_normal)),
- ?match({'EXCEPTION', _},
- 'CosFileTransfer_Directory':define_properties_with_modes(Dir1,
- [#'CosPropertyService_PropertyDef'
- {property_name = "num_children",
- property_value = #any{typecode=tk_long, value=0},
- property_mode = fixed_readonly}])),
- ?match(fixed_readonly,
- 'CosFileTransfer_Directory':get_property_mode(Dir1, "num_children")),
- ?match({true,
- [#'CosPropertyService_PropertyMode'{property_name = "num_children",
- property_mode = fixed_readonly}]},
- 'CosFileTransfer_Directory':get_property_modes(Dir1, ["num_children"])),
- ?match({'EXCEPTION', _},
- 'CosFileTransfer_Directory':set_property_mode(Dir1, "num_children", fixed_readonly)),
-
- ?match({'EXCEPTION', _},
- 'CosFileTransfer_Directory':
- set_property_modes(Dir1,
- [#'CosPropertyService_PropertyMode'
- {property_name = "num_children",
- property_mode = fixed_readonly}])),
- ?match({'EXCEPTION', _},
- 'CosFileTransfer_Directory':
- set_property_modes(Dir1,
- [#'CosPropertyService_PropertyMode'
- {property_name = "wrong",
- property_mode = fixed_readonly}])),
- ?match({'EXCEPTION', _},
- 'CosFileTransfer_Directory':
- set_property_modes(Dir1,
- [#'CosPropertyService_PropertyMode'
- {property_name = "num_children",
- property_mode = fixed_normal}])),
- ?match({'EXCEPTION', _},
- 'CosFileTransfer_Directory':define_property(Dir1,
- "num_children",
- #any{typecode=tk_long, value=0})),
- ?match({'EXCEPTION', _},
- 'CosFileTransfer_Directory':define_property(Dir1,
- "wrong",
- #any{typecode=tk_long, value=0})),
- ?match({'EXCEPTION', _},
- 'CosFileTransfer_Directory':define_property(Dir1,
- "num_children",
- #any{typecode=tk_short, value=0})),
-
- ?match({'EXCEPTION', _},
- 'CosFileTransfer_Directory':define_property(Dir1,
- "num_children",
- #any{typecode=tk_long, value=0})),
-
- ?match({'EXCEPTION', _},
- 'CosFileTransfer_Directory':
- define_properties(Dir1,
- [#'CosPropertyService_Property'
- {property_name = "num_children",
- property_value = #any{typecode=tk_long,
- value=0}}])),
- ?match({'EXCEPTION', _},
- 'CosFileTransfer_Directory':
- define_properties(Dir1,
- [#'CosPropertyService_Property'
- {property_name = "wrong",
- property_value = #any{typecode=tk_long,
- value=0}}])),
- ?match({'EXCEPTION', _},
- 'CosFileTransfer_Directory':
- define_properties(Dir1,
- [#'CosPropertyService_Property'
- {property_name = "num_children",
- property_value = #any{typecode=tk_short,
- value=0}}])),
- ?match(2, 'CosFileTransfer_Directory':get_number_of_properties(Dir1)),
-
- ?match({ok, ["num_children", "is_directory"], {'IOP_IOR',[],[]}},
- 'CosFileTransfer_Directory':get_all_property_names(Dir1, 2)),
- ?match({ok, ["is_directory"], _},
- 'CosFileTransfer_Directory':get_all_property_names(Dir1, 1)),
-
- ?match(#any{},
- 'CosFileTransfer_Directory':get_property_value(Dir1, "num_children")),
- ?match(#any{},
- 'CosFileTransfer_Directory':get_property_value(Dir1, "is_directory")),
- ?match({'EXCEPTION', _},
- 'CosFileTransfer_Directory':get_property_value(Dir1, "wrong")),
-
- ?match({true,
- [#'CosPropertyService_Property'{property_name = "num_children"}]},
- 'CosFileTransfer_Directory':get_properties(Dir1, ["num_children"])),
- ?match({false,
- [#'CosPropertyService_Property'{property_name = "wrong"}]},
- 'CosFileTransfer_Directory':get_properties(Dir1, ["wrong"])),
-
- ?match({ok, [_],_},
- 'CosFileTransfer_Directory':get_all_properties(Dir1, 1)),
- ?match({ok, [_,_], {'IOP_IOR',[],[]}},
- 'CosFileTransfer_Directory':get_all_properties(Dir1, 2)),
-
- ?match({'EXCEPTION', _},
- 'CosFileTransfer_Directory':delete_property(Dir1, "num_children")),
- ?match({'EXCEPTION', _},
- 'CosFileTransfer_Directory':delete_property(Dir1, "wrong")),
-
-
- ?match({'EXCEPTION', _},
- 'CosFileTransfer_Directory':delete_properties(Dir1, ["num_children"])),
- ?match({'EXCEPTION', _},
- 'CosFileTransfer_Directory':delete_properties(Dir1, ["wrong"])),
- ?match(false, 'CosFileTransfer_Directory':delete_all_properties(Dir1)),
- ?match(true,
- 'CosFileTransfer_Directory':is_property_defined(Dir1, "num_children")),
- ?match(false,
- 'CosFileTransfer_Directory':is_property_defined(Dir1, "wrong")),
-
- %% The Top Dir should be empty and ...
- ?match({ok,[],_}, 'CosFileTransfer_Directory':list(Dir1, 1000)),
- ?match( #any{value=0},
- 'CosPropertyService_PropertySet':get_property_value(Dir1, "num_children")),
- %% Create a sub-directory.
- Dir2 = 'CosFileTransfer_FileTransferSession':create_directory(FS,
- TEST_DIR_LEVEL2),
- ?match( #any{value=1},
- 'CosPropertyService_PropertySet':get_property_value(Dir1, "num_children")),
-
- ?match({ok, [_,_], {'IOP_IOR',[],[]}},
- 'CosFileTransfer_Directory':get_all_properties(Dir1, 2)),
- {_,_,Iterator1} = ?match({ok, [_], _},
- 'CosFileTransfer_Directory':get_all_properties(Dir1, 1)),
- ?match({false, [_]},
- 'CosPropertyService_PropertiesIterator':next_n(Iterator1,4)),
-
- {_,_,Iterator0} = ?match({ok, [], _},
- 'CosFileTransfer_Directory':get_all_properties(Dir1, 0)),
-
- ?match({false, [_, {'CosPropertyService_Property',
- "num_children",{any,tk_long,1}}]},
- 'CosPropertyService_PropertiesIterator':next_n(Iterator0,4)),
-
- ?match({true,
- [#'CosPropertyService_Property'{property_name = "num_children"}]},
- 'CosFileTransfer_Directory':get_properties(Dir1, ["num_children"])),
-
- %% The Top Directory is not emtpy any more and ...
- {ok,[#'CosFileTransfer_FileWrapper'{the_file = DirRef}],_} =
- ?matchnopr({ok,[{'CosFileTransfer_FileWrapper', _, ndirectory}],_},
- 'CosFileTransfer_Directory':list(Dir1, 1000)),
- %% ... its name eq. to 'TEST_DIR_LEVEL2'
- ?match(TEST_DIR_LEVEL2,
- 'CosFileTransfer_Directory':'_get_complete_file_name'(DirRef)),
-
- #'CosFileTransfer_FileWrapper'{the_file = Dir3} =
- ?matchnopr({'CosFileTransfer_FileWrapper', _, ndirectory},
- 'CosFileTransfer_FileTransferSession':get_file(FS, TEST_DIR_LEVEL1)),
-
- %% Must get the same result for the 'get_file' operation.
- {ok,[#'CosFileTransfer_FileWrapper'{the_file = DirRef2}],_} =
- ?matchnopr({ok,[{'CosFileTransfer_FileWrapper', _, ndirectory}],_},
- 'CosFileTransfer_Directory':list(Dir3,1000)),
- ?match(TEST_DIR_LEVEL2,
- 'CosFileTransfer_Directory':'_get_complete_file_name'(DirRef2)),
-
- %% Since the top directory isn't empty deleting it must fail.
- ?match({'EXCEPTION', _},
- 'CosFileTransfer_FileTransferSession':delete(FS, Dir1)),
-
- %% Delete the sub-directory and ...
- ?match(ok, 'CosFileTransfer_FileTransferSession':delete(FS, Dir2)),
- %% ... see if the top directory realyy is empty.
- ?match({ok,[],_}, 'CosFileTransfer_Directory':list(Dir1, 1000)),
-
- ?match(ok, 'CosFileTransfer_FileTransferSession':delete(FS, Dir1)),
- %% Test if the top directory been removed as intended.
- ?match({'EXCEPTION', {'CosFileTransfer_FileNotFoundException', _, _}},
- 'CosFileTransfer_FileTransferSession':get_file(FS, TEST_DIR_LEVEL1)),
-
- ?match(false, corba_object:non_existent(FS)),
- ?match(ok, 'CosFileTransfer_FileTransferSession':logout(FS)),
- %% To make sure Orber can remove it from mnesia.
- timer:sleep(1000),
- ?match(true, corba_object:non_existent(FS)),
- ?match(ok, remote_apply(Node, ?MODULE, uninstall_data, [Name])),
- stop_orber_remote(Node, normal),
- ok
- end.
-
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-ftp_host(Config) ->
- case ?config(ftp_remote_host, Config) of
- undefined ->
- {skipped, "The configuration parameter 'ftp_remote_host' not defined."};
- Host ->
- Host
- end.
-
-loop_files([]) ->
- io:format("@@@ DONE @@@~n", []);
-loop_files([#'CosFileTransfer_FileWrapper'{the_file = H}|T]) ->
- FullName = 'CosFileTransfer_File':'_get_complete_file_name'(H),
- Name = 'CosFileTransfer_File':'_get_name'(H),
- io:format("FULL NAME: ~p SHORT NAME: ~p~n", [FullName, Name]),
- loop_files(T).
-
-
-create_file_on_source_node('FTP', _Config, Host, FileName, Path, Data) ->
- io:format("<<<<<< CosFileTransfer Testing File >>>>>>~n",[]),
- io:format("Host: ~p~nPath: ~p~nFile: ~p~n", [Host, Path, FileName]),
- {ok, Pid} = ?match({ok, _}, inets:start(ftpc, [{host, Host}], stand_alone)),
- ?match(ok, ftp:user(Pid, ?FTP_USER, ?FTP_PASS)),
- ?match(ok, ftp:cd(Pid, Path)),
- ?match(ok, ftp:send_bin(Pid, list_to_binary(Data), FileName)),
- ?match(ok, inets:stop(ftpc, Pid));
-create_file_on_source_node({'NATIVE', _}, _Config, Host, FileName, Path, Data) ->
- io:format("<<<<<< CosFileTransfer Testing File >>>>>>~n",[]),
- io:format("Host: ~p~nPath: ~p~nFile: ~p~n", [Host, Path, FileName]),
- ?match(ok, file:write_file(FileName, list_to_binary(Data))).
-
-create_name(Type) ->
- Time = erlang:system_time(),
- Unique = erlang:unique_integer([positive]),
- lists:concat([Type, '_', Time, '_', Unique]).
-
-
-
-
-%%------------------------------------------------------------
-%% function : create_node/4
-%% Arguments: Name - the name of the new node (atom())
-%% Port - which iiop_port (integer())
-%% Domain - which domain.
-%% Type - if /4 used the types defines the extra arguments
-%% to be used.
-%% Returns : {ok, Node} | {error, _}
-%% Effect : Starts a new slave-node with given (optinally)
-%% extra arguments. If fails it retries 'Retries' times.
-%%------------------------------------------------------------
-create_node(Name, Port, normal) ->
- Args = basic_args(Name),
- create_node(Name, Port, 10, normal, Args, []);
-create_node(Name, {Port, _Depth}, ssl) ->
- Dir = filename:join([code:lib_dir(ssl), "examples", "certs", "etc"]),
- Args = basic_args(Name),
- {ok, Node} = create_node(list_to_atom(Name), Port, 10, ssl, Args, []),
- %% Client
- rpc:call(Node, application, set_env, [cosFileTransfer, ssl_client_certfile,
- filename:join([Dir, "client", "cert.pem"])]),
- rpc:call(Node, application, set_env, [cosFileTransfer, ssl_client_cacertfile,
- filename:join([Dir, "client", "cacerts.pem"])]),
- rpc:call(Node, application, set_env, [cosFileTransfer, ssl_client_keyfile,
- filename:join([Dir, "client", "key.pem"])]),
- rpc:call(Node, application, set_env, [cosFileTransfer, ssl_client_verify, 1]),
- rpc:call(Node, application, set_env, [cosFileTransfer, ssl_client_depth, 0]),
-
- %% Server
- rpc:call(Node, application, set_env, [cosFileTransfer, ssl_server_certfile,
- filename:join([Dir, "server", "cert.pem"])]),
- rpc:call(Node, application, set_env, [cosFileTransfer, ssl_server_cacertfile,
- filename:join([Dir, "server", "cacerts.pem"])]),
- rpc:call(Node, application, set_env, [cosFileTransfer, ssl_server_keyfile,
- filename:join([Dir, "server", "key.pem"])]),
- rpc:call(Node, application, set_env, [cosFileTransfer, ssl_server_verify, 1]),
- rpc:call(Node, application, set_env, [cosFileTransfer, ssl_server_depth, 0]),
- {ok, Node}.
-
-%create_node(Name, {Port, Depth}, ssl) ->
-% TestLibs = filename:join(filename:dirname(code:which(?MODULE)), "ssl_data"),
-% Args = basic_args(Name),
-% SArgs = basic_ssl_args(TestLibs, Args),
-% LArgs = level_based_ssl(Depth, TestLibs, SArgs),
-% create_node(list_to_atom(Name), Port, 10, ssl, LArgs, [{sslpath, TestLibs}]).
-
-create_node(Name, Port, Retries, Type, Args, Options) ->
- [_, Host] = ?match([_,_],string:tokens(atom_to_list(node()), [$@])),
- case starter(Host, Name, Args) of
- {ok, NewNode} ->
- ?match(pong, net_adm:ping(NewNode)),
- {ok, Cwd} = file:get_cwd(),
- Path = code:get_path(),
- ?match(ok, rpc:call(NewNode, file, set_cwd, [Cwd])),
- true = rpc:call(NewNode, code, set_path, [Path]),
- ?match(ok, start_orber_remote(NewNode, Type, Options, Port)),
- spawn_link(NewNode, ?MODULE, slave_sup, []),
- rpc:multicall([node() | nodes()], global, sync, []),
- {ok, NewNode};
- {error, Reason} when Retries == 0->
- {error, Reason};
- {error, Reason} ->
- io:format("Could not start slavenode ~p ~p retrying~n",
- [{Host, Name, Args}, Reason]),
- timer:sleep(500),
- create_node(Name, Port, Retries - 1, Type, Args, Options)
- end.
-
-starter(Host, Name, Args) ->
- slave:start(Host, Name, Args).
-
-slave_sup() ->
- process_flag(trap_exit, true),
- receive
- {'EXIT', _, _} ->
- ignore
- end.
-
-
-%%------------------------------------------------------------
-%% function : destroy_node
-%% Arguments: Node - which node to destroy.
-%% Type - normal | ssl
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
--ifdef(false).
-destroy_node(Node, Type) ->
- stopper(Node, Type).
-
-stopper(Node, Type) ->
- catch stop_orber_remote(Node, Type),
- slave:stop(Node).
--endif.
-
-%%------------------------------------------------------------
-%% function : remote_apply
-%% Arguments: N - Node, M - Module,
-%% F - Function, A - Arguments (list)
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-remote_apply(N, M,F,A) ->
- case rpc:call(N, M, F, A) of
- {badrpc, Reason} ->
- exit(Reason);
- Other ->
- Other
- end.
-
-%%------------------------------------------------------------
-%% function : stop_orber_remote
-%% Arguments: Node - which node to stop orber on.
-%% Type - normal | ssl | light | .......
-%% Returns : ok
-%% Effect : Stops orber on given node and, if specified,
-%% other applications or programs.
-%%------------------------------------------------------------
-stop_orber_remote(Node, ssl) ->
- rpc:call(Node, ssl, stop, []),
- rpc:call(Node, crypto, stop, []),
- orb_rpc_blast(Node, ssl);
-stop_orber_remote(Node, Type) ->
- orb_rpc_blast(Node, Type).
-
-orb_rpc_blast(Node, _) ->
- rpc:call(Node, cosFileTransferApp, stop, []),
- rpc:call(Node, cosProperty, stop, []),
- rpc:call(Node, cosFileTransferApp, uninstall, []),
- rpc:call(Node, cosProperty, uninstall, []),
- rpc:call(Node, orber, jump_stop, []).
-
-%%------------------------------------------------------------
-%% function : start_orber_remote
-%% Arguments: Node - which node to start orber on.
-%% Type - normal | ssl | light | .......
-%% Returns : ok
-%% Effect : Starts orber on given node and, if specified,
-%% other applications or programs.
-%%------------------------------------------------------------
-start_orber_remote(Node, ssl, _Options, Port) ->
- rpc:call(Node, ssl, start, []),
- rpc:call(Node, crypto, start, []),
- rpc:call(Node, ssl, seed, ["testing"]),
- orb_rpc_setup(Node, ssl, Port);
-start_orber_remote(Node, Type, _, Port) ->
- orb_rpc_setup(Node, Type, Port).
-
-orb_rpc_setup(Node, _, Port) ->
- rpc:call(Node, orber, jump_start, [Port]),
- rpc:call(Node, cosProperty, install, []),
- rpc:call(Node, cosProperty, start, []),
- rpc:call(Node, cosFileTransferApp, install, []).
-
-%%--------------- MISC FUNCTIONS -----------------------------
-basic_args(_Name) ->
- TestLibs = filename:dirname(code:which(?MODULE)),
- " -orber orber_debug_level 10" ++
- " -pa " ++
- TestLibs ++
- " -pa " ++
- filename:join(TestLibs, "all_SUITE_data") ++
- " -pa " ++
- filename:dirname(code:which(cosFileTransferApp)).
-
--ifdef(false).
-basic_ssl_args(TestLibs, Args) ->
-% Args ++
-% " -cosFileTransfer ssl_client_certfile \\\"" ++
-% filename:join(TestLibs, "ssl_client_cert.pem") ++
-% "\\\" -cosFileTransfer ssl_server_certfile \\\""++
-% filename:join(TestLibs, "ssl_server_cert.pem")++"\\\"".
-
- io:format("<<<<<< SSL LIBS ~p >>>>>>~n",[TestLibs]),
- NewArgs = Args ++
- " -cosFileTransfer ssl_client_certfile \\\"" ++
- filename:join(TestLibs, "ssl_client_cert.pem") ++
- "\\\" -cosFileTransfer ssl_server_certfile \\\""++
- filename:join(TestLibs, "ssl_server_cert.pem")++"\\\"",
- io:format("<<<<<< SSL LIBS ARGS ~p >>>>>>~n",[NewArgs]),
- NewArgs.
-
-level_based_ssl(1, _TestLibs, Args) ->
- Args;
-level_based_ssl(2, _TestLibs, Args) ->
- Args.% ++
-% " -cosFileTransfer ssl_server_depth 2 " ++
-% " -cosFileTransfer ssl_client_depth 2 " ++
-% " -cosFileTransfer ssl_server_verify " ++
-% " -cosFileTransfer ssl_client_verify " ++
-% " -cosFileTransfer ssl_server_cacertfile " ++
-% " -cosFileTransfer ssl_client_cacertfile " ++
-
--endif.
-
-install_data(Protocol, {WhichType, Host, Name}) ->
- io:format("<<<<<< Starting ~p/~p VFS at ~p/~p>>>>>>~n",
- [Protocol, WhichType, Host, Name]),
- %% Create a Virtual File System.
- VFS = ?match({_,_,_,_,_,_},
- cosFileTransferApp:create_VFS(WhichType, [], Host, ?FTP_PORT,
- [{protocol, Protocol}])),
- NS = corba:resolve_initial_references("NameService"),
- NC1 = lname_component:set_id(lname_component:create(), Name),
- N = lname:insert_component(lname:create(), 1, NC1),
- 'CosNaming_NamingContext':rebind(NS, N, VFS).
-
-uninstall_data(Name) ->
- VFS = ?match({_,_,_,_,_,_},
- corba:string_to_object("corbaname:rir:/NameService#"++Name)),
- ?match(ok, corba:dispose(VFS)),
- ok.
-
-
-
-%%------------------- EOF MODULE-----------------------------------
diff --git a/lib/cosFileTransfer/vsn.mk b/lib/cosFileTransfer/vsn.mk
deleted file mode 100644
index 561f11fbb2..0000000000
--- a/lib/cosFileTransfer/vsn.mk
+++ /dev/null
@@ -1 +0,0 @@
-COSFILETRANSFER_VSN = 1.2.2
diff --git a/lib/cosNotification/AUTHORS b/lib/cosNotification/AUTHORS
deleted file mode 100644
index 55d8059989..0000000000
--- a/lib/cosNotification/AUTHORS
+++ /dev/null
@@ -1,4 +0,0 @@
-Original Authors:
-Niclas Eklund
-
-Contributors:
diff --git a/lib/cosNotification/Makefile b/lib/cosNotification/Makefile
deleted file mode 100644
index 0408417a3b..0000000000
--- a/lib/cosNotification/Makefile
+++ /dev/null
@@ -1,42 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1999-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include vsn.mk
-VSN=$(COSNOTIFICATION_VSN)
-
-# ----------------------------------------------------
-# Common Macros
-# ----------------------------------------------------
-# SUB_DIRECTORIES = src test examples doc/src
-# At the moment we don't have any example programs.
-SUB_DIRECTORIES = src doc/src
-
-SPECIAL_TARGETS =
-
-# ----------------------------------------------------
-# Default Subdir Targets
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_subdir.mk
diff --git a/lib/cosNotification/doc/html/.gitignore b/lib/cosNotification/doc/html/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosNotification/doc/html/.gitignore
+++ /dev/null
diff --git a/lib/cosNotification/doc/man3/.gitignore b/lib/cosNotification/doc/man3/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosNotification/doc/man3/.gitignore
+++ /dev/null
diff --git a/lib/cosNotification/doc/man6/.gitignore b/lib/cosNotification/doc/man6/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosNotification/doc/man6/.gitignore
+++ /dev/null
diff --git a/lib/cosNotification/doc/pdf/.gitignore b/lib/cosNotification/doc/pdf/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosNotification/doc/pdf/.gitignore
+++ /dev/null
diff --git a/lib/cosNotification/doc/src/CosNotification.xml b/lib/cosNotification/doc/src/CosNotification.xml
deleted file mode 100644
index 6aac312d5e..0000000000
--- a/lib/cosNotification/doc/src/CosNotification.xml
+++ /dev/null
@@ -1,235 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2002</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosNotification</title>
- <prepared>Niclas Eklund</prepared>
- <responsible>Niclas Eklund</responsible>
- <docno></docno>
- <approved>Niclas Eklund</approved>
- <checked></checked>
- <date>2002-02-05</date>
- <rev>PA1</rev>
- </header>
- <module>CosNotification</module>
- <modulesummary>This module export functions which return QoS and Admin Properties constants.</modulesummary>
- <description>
- <p>To get access to all definitions include necessary <c>hrl</c> files by using: <br></br>
-<c>-include_lib("cosNotification/include/*.hrl").</c></p>
- </description>
- <funcs>
- <func>
- <name>'EventReliability'() -> string()</name>
- <fsummary>Return the EventReliability QoS identifier</fsummary>
- <desc>
- <p>This function returns the EventReliability QoS identifier</p>
- </desc>
- </func>
- <func>
- <name>'BestEffort'() -> short()</name>
- <fsummary>Return the BestEffort QoS value</fsummary>
- <desc>
- <p>This function returns the BestEffort QoS value.</p>
- </desc>
- </func>
- <func>
- <name>'Persistent'() -> short()</name>
- <fsummary>Return the Persistent QoS value</fsummary>
- <desc>
- <p>This function returns the Persistent QoS value.</p>
- </desc>
- </func>
- <func>
- <name>'ConnectionReliability'() -> string()</name>
- <fsummary>Return the ConnectionReliability QoS identifier</fsummary>
- <desc>
- <p>This function returns the ConnectionReliability QoS identifier.</p>
- </desc>
- </func>
- <func>
- <name>'Priority'() -> string()</name>
- <fsummary>Return the Priority QoS identifier</fsummary>
- <desc>
- <p>This function returns the Priority QoS identifier.</p>
- </desc>
- </func>
- <func>
- <name>'LowestPriority'() -> short()</name>
- <fsummary>Return the LowestPriority QoS value</fsummary>
- <desc>
- <p>This function returns the LowestPriority QoS value.</p>
- </desc>
- </func>
- <func>
- <name>'HighestPriority'() -> short()</name>
- <fsummary>Return the HighestPriority QoS value</fsummary>
- <desc>
- <p>This function returns the HighestPriority QoS value.</p>
- </desc>
- </func>
- <func>
- <name>'DefaultPriority'() -> short()</name>
- <fsummary>Return the DefaultPriority QoS value</fsummary>
- <desc>
- <p>This function returns the DefaultPriority QoS value.</p>
- </desc>
- </func>
- <func>
- <name>'StartTime'() -> string()</name>
- <fsummary>Return the StartTime QoS identifier</fsummary>
- <desc>
- <p>This function returns the StartTime QoS identifier.</p>
- </desc>
- </func>
- <func>
- <name>'StopTime'() -> string()</name>
- <fsummary>Return the StopTime QoS identifier</fsummary>
- <desc>
- <p>This function returns the StopTime QoS identifier.</p>
- </desc>
- </func>
- <func>
- <name>'Timeout'() -> string()</name>
- <fsummary>Return the Timeout QoS identifier</fsummary>
- <desc>
- <p>This function returns the Timeout QoS identifier.</p>
- </desc>
- </func>
- <func>
- <name>'OrderPolicy'() -> string()</name>
- <fsummary>Return the OrderPolicy QoS identifier</fsummary>
- <desc>
- <p>This function returns the OrderPolicy QoS identifier.</p>
- </desc>
- </func>
- <func>
- <name>'AnyOrder'() -> short()</name>
- <fsummary>Return the AnyOrder QoS value</fsummary>
- <desc>
- <p>This function returns the AnyOrder QoS value.</p>
- </desc>
- </func>
- <func>
- <name>'FifoOrder'() -> short()</name>
- <fsummary>Return the FifoOrder QoS value</fsummary>
- <desc>
- <p>This function returns the FifoOrder QoS value.</p>
- </desc>
- </func>
- <func>
- <name>'PriorityOrder'() -> short()</name>
- <fsummary>Return the PriorityOrder QoS value</fsummary>
- <desc>
- <p>This function returns the PriorityOrder QoS value.</p>
- </desc>
- </func>
- <func>
- <name>'DeadlineOrder'() -> short()</name>
- <fsummary>Return the DeadlineOrder QoS value</fsummary>
- <desc>
- <p>This function returns the DeadlineOrder QoS value.</p>
- </desc>
- </func>
- <func>
- <name>'DiscardPolicy'() -> string()</name>
- <fsummary>Return the DiscardPolicy QoS identifier</fsummary>
- <desc>
- <p>This function returns the DiscardPolicy QoS identifier.</p>
- </desc>
- </func>
- <func>
- <name>'LifoOrder'() -> short()</name>
- <fsummary>Return the LifoOrder QoS value</fsummary>
- <desc>
- <p>This function returns the LifoOrder QoS value.</p>
- </desc>
- </func>
- <func>
- <name>'RejectNewEvents'() -> short()</name>
- <fsummary>Return the RejectNewEvents QoS value</fsummary>
- <desc>
- <p>This function returns the RejectNewEvents QoS value.</p>
- </desc>
- </func>
- <func>
- <name>'MaximumBatchSize'() -> string()</name>
- <fsummary>Return the MaximumBatchSize QoS identifier</fsummary>
- <desc>
- <p>This function returns the MaximumBatchSize QoS identifier.</p>
- </desc>
- </func>
- <func>
- <name>'PacingInterval'() -> string()</name>
- <fsummary>Return the PacingInterval QoS identifier</fsummary>
- <desc>
- <p>This function returns the PacingInterval QoS identifier.</p>
- </desc>
- </func>
- <func>
- <name>'StartTimeSupported'() -> string()</name>
- <fsummary>Return the StartTimeSupported QoS identifier</fsummary>
- <desc>
- <p>This function returns the StartTimeSupported QoS identifier.</p>
- </desc>
- </func>
- <func>
- <name>'StopTimeSupported'() -> string()</name>
- <fsummary>Return the StopTimeSupported QoS identifier</fsummary>
- <desc>
- <p>This function returns the StopTimeSupported QoS identifier.</p>
- </desc>
- </func>
- <func>
- <name>'MaxEventsPerConsumer'() -> string()</name>
- <fsummary>Return the MaxEventsPerConsumer QoS identifier</fsummary>
- <desc>
- <p>This function returns the MaxEventsPerConsumer QoS identifier.</p>
- </desc>
- </func>
- <func>
- <name>'MaxQueueLength'() -> string()</name>
- <fsummary>Return the MaxQueueLength Admin identifier</fsummary>
- <desc>
- <p>This function returns the MaxQueueLength Admin identifier.</p>
- </desc>
- </func>
- <func>
- <name>'MaxConsumers'() -> string()</name>
- <fsummary>Return the MaxConsumers Admin identifier</fsummary>
- <desc>
- <p>This function returns the MaxConsumers Admin identifier.</p>
- </desc>
- </func>
- <func>
- <name>'MaxSuppliers'() -> string()</name>
- <fsummary>Return the MaxSuppliers Admin identifier</fsummary>
- <desc>
- <p>This function returns the MaxSuppliers Admin identifier.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosNotification/doc/src/CosNotification_AdminPropertiesAdmin.xml b/lib/cosNotification/doc/src/CosNotification_AdminPropertiesAdmin.xml
deleted file mode 100644
index 6086402f1a..0000000000
--- a/lib/cosNotification/doc/src/CosNotification_AdminPropertiesAdmin.xml
+++ /dev/null
@@ -1,79 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosNotification_AdminPropertiesAdmin</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved>Niclas Eklund</approved>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosNotification_AdminPropertiesAdmin</module>
- <modulesummary>This module implements the OMG CosNotification::AdminPropertiesAdmin interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosNotification/include/*.hrl").</c></p>
- <p>All objects, which inherit this interface, export functions described in this module.</p>
- </description>
- <funcs>
- <func>
- <name>get_admin(Object) -> AdminProperties</name>
- <fsummary>Return a list of <c>AdminProperties</c>associated with the target object</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>AdminProperties = [AdminProperty]</v>
- <v>AdminProperty = #'CosNotification_Property'{name, value}</v>
- <v>name = string()</v>
- <v>value = #any</v>
- </type>
- <desc>
- <p>This operation returns sequence of name-value pairs which encapsulates the
- current administrative properties of the target object.</p>
- </desc>
- </func>
- <func>
- <name>set_admin(Object, AdminProperties) -> Reply</name>
- <fsummary>Update the <c>AdminProperties</c>for the target object</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>AdminProperties = [AdminProperty]</v>
- <v>AdminProperty = #'CosNotification_Property'{name, value}</v>
- <v>name = string()</v>
- <v>value = #any</v>
- <v>Reply = ok | {'EXCEPTION', CosNotification_UnsupportedAdmin}</v>
- </type>
- <desc>
- <p>As input, this operation accepts a sequence of name-value pairs encapsulating the
- desired administrative settings for the target object. If it is not possible to
- set the given properties the exception <c>UnsupportedAdmin</c> will be raised.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosNotification/doc/src/CosNotification_QoSAdmin.xml b/lib/cosNotification/doc/src/CosNotification_QoSAdmin.xml
deleted file mode 100644
index 7774652e60..0000000000
--- a/lib/cosNotification/doc/src/CosNotification_QoSAdmin.xml
+++ /dev/null
@@ -1,107 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>CosNotification_QoSAdmin</title>
- <prepared></prepared>
- <docno></docno>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosNotification_QoSAdmin</module>
- <modulesummary>This module implements the OMG CosNotification::QoSAdmin interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosNotification/include/*.hrl").</c></p>
- <p>All objects, which inherit this interface, export functions described in this module.</p>
- </description>
- <funcs>
- <func>
- <name>get_qos(Object) -> Reply</name>
- <fsummary>Return a list of name-value pairs which encapsulates the current QoS settings for the target object</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>Reply = [QoSProperty]</v>
- <v>QoSProperty = #'CosNotification_Property'{name, value}</v>
- <v>name = string()</v>
- <v>value = #any</v>
- </type>
- <desc>
- <p>This operation returns a list of name-value pairs which encapsulates the current QoS settings
- for the target object.</p>
- </desc>
- </func>
- <func>
- <name>set_qos(Object, QoS) -> Reply</name>
- <fsummary>Change the QoS settings for the target object</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>QoS = [QoSProperty]</v>
- <v>QoSProperty = #'CosNotification_Property'{name, value}</v>
- <v>name = string()</v>
- <v>value = #any</v>
- <v>Reply = ok | {'EXCEPTION', #'CosNotification_UnsupportedQoS'{qos_err}}</v>
- <v>qos_err = PropertyErrorSeq</v>
- <v>PropertyErrorSeq = [PropertyError]</v>
- <v>PropertyError = #'CosNotification_PropertyError'{code, name, available_range}</v>
- <v>code = 'UNSUPPORTED_PROPERTY' | 'UNAVAILABLE_PROPERTY' | 'UNSUPPORTED_VALUE' | 'UNAVAILABLE_VALUE' | 'BAD_PROPERTY' | 'BAD_TYPE' | 'BAD_VALUE'</v>
- <v>name = string()</v>
- <v>available_range = PropertyRange</v>
- <v>PropertyRange = #CosNotification_PropertyRange{low_val, high_val}</v>
- <v>low_val = high_val = #any</v>
- </type>
- <desc>
- <p>To alter the current QoS settings for the target object this function must be used.
- If it is not possible to set the requested QoS the <c>UnsupportedQoS</c>
- exception is raised, which includes a sequence of <c>PropertyError</c>'s
- describing which QoS, possible range and why is not allowed.</p>
- </desc>
- </func>
- <func>
- <name>validate_qos(Object, QoS) -> Reply</name>
- <fsummary>Validate if the supplied QoS properties is valid for the target object </fsummary>
- <type>
- <v>Object = #objref</v>
- <v>QoS = [QoSProperty]</v>
- <v>QoSProperty = #'Property'{name, value}</v>
- <v>name = string()</v>
- <v>value = #any</v>
- <v>Reply = {ok, NamedPropertyRangeSeq} | {'EXCEPTION', CosNotification_UnsupportedQoS{}}</v>
- <v>NamedPropertyRangeSeq = [NamedPropertyRange]</v>
- <v>NamedPropertyRange = #CosNotification_NamedPropertyRange{name, range}</v>
- <v>name = string()</v>
- <v>range = #CosNotification_PropertyRange{low_val, high_val}</v>
- <v>low_val = #any</v>
- <v>high_val = #any</v>
- </type>
- <desc>
- <p>The purpose of this operations is to check if a QoS setting is supported
- by the target object and if so, the operation returns additional properties
- which could be optionally added as well.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ConsumerAdmin.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ConsumerAdmin.xml
deleted file mode 100644
index cbe22ce7cd..0000000000
--- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ConsumerAdmin.xml
+++ /dev/null
@@ -1,242 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosNotifyChannelAdmin_ConsumerAdmin</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosNotifyChannelAdmin_ConsumerAdmin</module>
- <modulesummary>This module implements the OMG CosNotifyChannelAdmin::ConsumerAdmin interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosNotification/include/*.hrl").</c></p>
- <p>This module also exports the functions described in:</p>
- <list type="bulleted">
- <item>
- <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyComm_NotifySubscribe">CosNotifyComm_NotifySubscribe</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p>
- </item>
- </list>
- </description>
- <funcs>
- <func>
- <name>_get_MyID(ConsumerAdmin) -> AdminID</name>
- <fsummary>Return the target object's Id</fsummary>
- <type>
- <v>ConsumerAdmin = #objref</v>
- <v>AdminID = long()</v>
- </type>
- <desc>
- <p>The ID returned by the creating channel is equal to the value encapsulated by
- this readonly attribute.</p>
- </desc>
- </func>
- <func>
- <name>_get_MyChannel(ConsumerAdmin) -> Channel</name>
- <fsummary>Return the ancestor channel</fsummary>
- <type>
- <v>ConsumerAdmin = #objref</v>
- <v>Channel = #objref</v>
- </type>
- <desc>
- <p>The creating channel's reference is maintained by this readonly attribute.</p>
- </desc>
- </func>
- <func>
- <name>_get_MyOperator(ConsumerAdmin) -> OpType</name>
- <fsummary>Return the filtering schema used by the target object</fsummary>
- <type>
- <v>ConsumerAdmin = #objref</v>
- <v>OpType = 'AND_OP' | 'OR_OP'</v>
- </type>
- <desc>
- <p>When <c>ConsumerAdmin's</c> are created an operation type,
- i.e., <c>'AND_OP'</c> or <c>'OR_OP'</c>, is supplied, which determines
- the semantics used by the target object concerning evaluation against
- any associated <c>Filter</c> objects.</p>
- </desc>
- </func>
- <func>
- <name>_get_priority_filter(ConsumerAdmin) -> MappingFilter</name>
- <fsummary>Return the associated priority <c>MappingFilter</c></fsummary>
- <type>
- <v>ConsumerAdmin = MappingFilter = #objref</v>
- </type>
- <desc>
- <p>If set, this operation returns the associated priority <c>MappingFilter</c>, otherwise
- a <c>NIL</c> object reference is returned.</p>
- </desc>
- </func>
- <func>
- <name>_set_priority_filter(ConsumerAdmin, MappingFilter) -> ok</name>
- <fsummary>Set the priority <c>MappingFilter</c></fsummary>
- <type>
- <v>ConsumerAdmin = MappingFilter = #objref</v>
- </type>
- <desc>
- <p>To associate a priority <c>MappingFilter</c> with the target object this operation
- must be used.</p>
- </desc>
- </func>
- <func>
- <name>_get_lifetime_filter(ConsumerAdmin) -> MappingFilter</name>
- <fsummary>Return the associated lifetime <c>MappingFilter</c></fsummary>
- <type>
- <v>ConsumerAdmin = MappingFilter = #objref</v>
- </type>
- <desc>
- <p>Unless a lifetime <c>MappingFilter</c> have been associated with the target object
- a <c>NIL</c> object reference is returned by this operation.</p>
- </desc>
- </func>
- <func>
- <name>_set_lifetime_filter(ConsumerAdmin, MappingFilter) -> ok</name>
- <fsummary>Set the lifetime <c>MappingFilter</c></fsummary>
- <type>
- <v>ConsumerAdmin = MappingFilter = #objref</v>
- </type>
- <desc>
- <p>This operation associate a lifetime <c>MappingFilter</c> with the target object.</p>
- </desc>
- </func>
- <func>
- <name>_get_pull_suppliers(ConsumerAdmin) -> ProxyIDSeq</name>
- <fsummary>Return a list of all associated pull supplier Id:s</fsummary>
- <type>
- <v>ConsumerAdmin = #objref</v>
- <v>ProxyIDSeq = [ProxyID]</v>
- <v>ProxyID = long()</v>
- </type>
- <desc>
- <p>This readonly attribute maintains the Id's for all <c>PullProxies</c> created
- by the target object and still alive.</p>
- </desc>
- </func>
- <func>
- <name>_get_push_suppliers(ConsumerAdmin) -> ProxyIDSeq</name>
- <fsummary>Return a list of all associated push supplier Id:s</fsummary>
- <type>
- <v>ConsumerAdmin = #objref</v>
- <v>ProxyIDSeq = [ProxyID]</v>
- <v>ProxyID = long()</v>
- </type>
- <desc>
- <p>This attribute is similar to the <c>_get_pull_suppliers</c> attribute but maintains
- the Id's for all <c>PushProxies</c> created by the target object and still alive.</p>
- </desc>
- </func>
- <func>
- <name>get_proxy_supplier(ConsumerAdmin, ProxyID) -> Reply</name>
- <fsummary>Return the proxy supplier with matching Id</fsummary>
- <type>
- <v>ConsumerAdmin = #objref</v>
- <v>ProxyID = long()</v>
- <v>Reply = Proxy | {'EXCEPTION', #'CosNotifyChannelAdmin_ProxyNotFound'{}}</v>
- <v>Proxy = #objref</v>
- </type>
- <desc>
- <p>If a proxy with the given Id exists the reference to the object is returned, but if
- the object have terminated, or an incorrect Id is supplied, an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>obtain_notification_pull_supplier(ConsumerAdmin, ConsumerType) -> Reply</name>
- <fsummary>Create a supplier proxy</fsummary>
- <type>
- <v>ConsumerAdmin = #objref</v>
- <v>ConsumerType = 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT'</v>
- <v>Reply = {Proxy, ProxyID}</v>
- <v>Proxy = #objref</v>
- <v>ProxyID = long()</v>
- </type>
- <desc>
- <p>Determined by the parameter <c>ConsumerType</c>, a proxy which will
- accept events of the defined type is created. Along with the object reference an
- Id is returned. </p>
- </desc>
- </func>
- <func>
- <name>obtain_pull_supplier(ConsumerAdmin) -> Proxy</name>
- <fsummary>Create a supplier proxy</fsummary>
- <type>
- <v>ConsumerAdmin = #objref</v>
- <v>Proxy = #objref</v>
- </type>
- <desc>
- <p>This operation creates a new proxy which accepts <c>#any{}</c> events.</p>
- </desc>
- </func>
- <func>
- <name>obtain_notification_push_supplier(ConsumerAdmin, ConsumerType) -> Reply</name>
- <fsummary>Create a supplier proxy</fsummary>
- <type>
- <v>ConsumerAdmin = #objref</v>
- <v>ConsumerType = 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT'</v>
- <v>Reply = {Proxy, ProxyID}</v>
- <v>Proxy = #objref</v>
- <v>ProxyID = long()</v>
- </type>
- <desc>
- <p>A proxy which accepts events of the type described by the parameter <c>ConsumerType</c>
- is created by this operation. A unique Id is returned as an out parameter.</p>
- </desc>
- </func>
- <func>
- <name>obtain_push_supplier(ConsumerAdmin) -> Proxy</name>
- <fsummary>Create a supplier proxy</fsummary>
- <type>
- <v>ConsumerAdmin = #objref</v>
- <v>Proxy = #objref</v>
- </type>
- <desc>
- <p>The object created by this function is a proxy which accepts <c>#any{}</c> events.</p>
- </desc>
- </func>
- <func>
- <name>destroy(ConsumerAdmin) -> ok</name>
- <fsummary>Terminate the target object and all its children</fsummary>
- <type>
- <v>ConsumerAdmin = #objref</v>
- </type>
- <desc>
- <p>To terminate the target object this operation should be used. The associated
- <c>Channel</c> will be notified.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannel.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannel.xml
deleted file mode 100644
index 7696e6a26c..0000000000
--- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannel.xml
+++ /dev/null
@@ -1,226 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>CosNotifyChannelAdmin_EventChannel</title>
- <prepared></prepared>
- <docno></docno>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosNotifyChannelAdmin_EventChannel</module>
- <modulesummary>This module implements the OMG CosNotifyChannelAdmin::EventChannel interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosNotification/include/*.hrl").</c></p>
- <p>This module also exports the functions described in:</p>
- <list type="bulleted">
- <item>
- <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotification_AdminPropertiesAdmin">CosNotification_AdminPropertiesAdmin</seealso></p>
- </item>
- </list>
- </description>
- <funcs>
- <func>
- <name>_get_MyFactory(Channel) -> ChannelFactory</name>
- <fsummary>Return the factory object which created the target object</fsummary>
- <type>
- <v>Channel = #objref</v>
- <v>ChannelFactory = #objref</v>
- </type>
- <desc>
- <p>This readonly attribute maintains the reference of the event channel
- factory that created the target channel.</p>
- </desc>
- </func>
- <func>
- <name>_get_default_consumer_admin(Channel) -> ConsumerAdmin</name>
- <fsummary>Return the default consumer admin associated with the target object</fsummary>
- <type>
- <v>Channel = #objref</v>
- <v>ConsumerAdmin = #objref</v>
- </type>
- <desc>
- <p>This is a readonly attribute which maintains a reference to a default
- <c>ConsumerAdmin</c> object associated with the target object.</p>
- </desc>
- </func>
- <func>
- <name>_get_default_supplier_admin(Channel) -> SupplierAdmin</name>
- <fsummary>Return the default supplier admin associated with the target object</fsummary>
- <type>
- <v>Channel = #objref</v>
- <v>SupplierAdmin = #objref</v>
- </type>
- <desc>
- <p>This is a readonly attribute which maintains a reference to a default
- <c>SupplierAdmin</c> object associated with the target object.</p>
- </desc>
- </func>
- <func>
- <name>_get_default_filter_factory(Channel) -> FilterFactory</name>
- <fsummary>Return the default filter factory associated with the target object</fsummary>
- <type>
- <v>Channel = #objref</v>
- <v>FilterFactory = #objref</v>
- </type>
- <desc>
- <p>The default <c>FilterFactory</c> associated with the target channel
- is maintained by this readonly attribute.</p>
- </desc>
- </func>
- <func>
- <name>new_for_consumers(Channel, OpType) -> Return</name>
- <fsummary>Create a new <c>ConsumerAdmin</c>object</fsummary>
- <type>
- <v>Channel = #objref</v>
- <v>OpType = 'AND_OP' | 'OR_OP'</v>
- <v>Return = {ConsumerAdmin, AdminID}</v>
- <v>ConsumerAdmin = #objref</v>
- <v>AdminID = long()</v>
- </type>
- <desc>
- <p>This operation creates a new instance of a <c>ConsumerAdmin</c> and supplies
- an Id which may be used when invoking other operations exported by this module.
- The returned object will inherit the Quality of Service properties of the
- target channel.</p>
- </desc>
- </func>
- <func>
- <name>for_consumers(Channel) -> ConsumerAdmin</name>
- <fsummary>Create a new <c>ConsumerAdmin</c>object</fsummary>
- <type>
- <v>Channel = #objref</v>
- <v>ConsumerAdmin = #objref</v>
- </type>
- <desc>
- <p>A new new instance of a <c>ConsumerAdmin</c> object is created but no
- Id is returned. The returned object's operation type, i.e., <c>'AND_OP'</c> or <c>'OR_OP'</c>,
- will be set to the value of the configuration parameter <c>filterOp</c>.
- The target object's Quality of Service properties will be inherited by the
- returned <c>ConsumerAdmin</c>.</p>
- </desc>
- </func>
- <func>
- <name>new_for_suppliers(Channel, OpType) -> Return</name>
- <fsummary>Create a new <c>SupplierAdmin</c>object</fsummary>
- <type>
- <v>Channel = #objref</v>
- <v>OpType = 'AND_OP' | 'OR_OP'</v>
- <v>Return = {SupplierAdmin, AdminID}</v>
- <v>SupplierAdmin = #objref</v>
- <v>AdminID = long()</v>
- </type>
- <desc>
- <p>Enables us to create a new instance of a <c>SupplierAdmin</c>. An Id, which
- may be used when invoking other operations exported by this module, is also
- returned. The current Quality of Service settings associated with the target
- object will be inherited by the <c>SupplierAdmin</c>.</p>
- </desc>
- </func>
- <func>
- <name>for_suppliers(Channel) -> SupplierAdmin</name>
- <fsummary>Create a new <c>SupplierAdmin</c>object</fsummary>
- <type>
- <v>Channel = #objref</v>
- <v>SupplierAdmin = #objref</v>
- </type>
- <desc>
- <p>To create a new <c>SupplierAdmin</c> with the target object's current
- Quality of Service settings we can use this function. The returned object's
- operation type (<c>'AND_OP'</c> or <c>'OR_OP'</c>) will be determined by the
- configuration variable <c>filterOp</c>.</p>
- </desc>
- </func>
- <func>
- <name>get_consumeradmin(Channel, AdminID) -> ConsumerAdmin</name>
- <fsummary>Return the <c>ConsumerAdmin</c>matching AdminID</fsummary>
- <type>
- <v>Channel = #objref</v>
- <v>AdminID = long()</v>
- <v>ConsumerAdmin = #objref | {'EXCEPTION', #'CosNotifyChannelAdmin_AdminNotFound'{}}</v>
- </type>
- <desc>
- <p>If the given Id is associated with a <c>ConsumerAdmin</c> the object reference
- is returned. If such association never existed or the <c>ConsumerAdmin</c>
- have terminated an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>get_supplieradmin(Channel, AdminID) -> SupplierAdmin</name>
- <fsummary>Return the <c>SupplierAdmin</c>matching AdminID</fsummary>
- <type>
- <v>Channel = #objref</v>
- <v>AdminID = long()</v>
- <v>SupplierAdmin = #objref | {'EXCEPTION', #'CosNotifyChannelAdmin_AdminNotFound'{}}</v>
- </type>
- <desc>
- <p>Equal to the operation <c>get_consumeradmin/2</c> but a reference to
- a <c>SupplierAdmin</c> is returned.</p>
- </desc>
- </func>
- <func>
- <name>get_all_consumeradmins(Channel) -> Reply</name>
- <fsummary>Return a list of all <c>ConsumerAdmins</c>, currently active, Id:s</fsummary>
- <type>
- <v>Channel = #objref</v>
- <v>Reply = [AdminID]</v>
- <v>AdminID = long()</v>
- </type>
- <desc>
- <p>To get access to all <c>ConsumerAdmin</c> Id's created by the target object, and still
- alive, this operation could be invoked.</p>
- </desc>
- </func>
- <func>
- <name>get_all_supplieradmins(Channel) -> Reply</name>
- <fsummary>Return a list of all <c>SupplierAdmins</c>, currently active, Id:s</fsummary>
- <type>
- <v>Channel = #objref</v>
- <v>Reply = [AdminID]</v>
- <v>AdminID = long()</v>
- </type>
- <desc>
- <p>Equal to the operation <c>get_all_consumeradmins/1</c> but returns
- a list of all <c>SupplierAdmin</c> object ID's.</p>
- </desc>
- </func>
- <func>
- <name>destroy(Channel) -> ok</name>
- <fsummary>Terminate the channel and all its children</fsummary>
- <type>
- <v>Channel = #objref</v>
- </type>
- <desc>
- <p>The <c>destroy</c> operation will terminate the target channel and
- all associated Admin objects.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannelFactory.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannelFactory.xml
deleted file mode 100644
index 552ea182c0..0000000000
--- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannelFactory.xml
+++ /dev/null
@@ -1,89 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>CosNotifyChannelAdmin_EventChannelFactory</title>
- <prepared></prepared>
- <docno></docno>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosNotifyChannelAdmin_EventChannelFactory</module>
- <modulesummary>This module implements the OMG CosNotifyChannelAdmin::EventChannelFactory interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosNotification/include/*.hrl").</c></p>
- </description>
- <funcs>
- <func>
- <name>create_channel(ChannelFactory, InitialQoS, InitialAdmin) -> Return</name>
- <fsummary>Create a new channel</fsummary>
- <type>
- <v>ChannelFactory = #objref</v>
- <v>InitialQoS = CosNotification::QoSProperties</v>
- <v>InitialAdmin = CosNotification::AdminProperties</v>
- <v>Return = {EventChannel, ChannelID}</v>
- <v>EventChannel = #objref</v>
- <v>ChannelID = long()</v>
- </type>
- <desc>
- <p>This operation creates a new event channel. Along with the channel
- reference an id is returned which can be used when invoking other
- operations exported by this module. The Quality of Service argument
- supplied will be inherited by objects created by the channel. For more
- information about QoS settings see the <c>User's Guide</c>.</p>
- <p>If no QoS- and/or Admin-properties are supplied (i.e. empty list),
- the <em>default</em> settings will be used. For more information, see the
- User's Guide.</p>
- </desc>
- </func>
- <func>
- <name>get_all_channels(ChannelFactory) -> ChannelIDSeq</name>
- <fsummary>Return all Id:s for channels, currently alive, created by the target object</fsummary>
- <type>
- <v>ChannelFactory = #objref</v>
- <v>ChannelIDSeq = [long()]</v>
- </type>
- <desc>
- <p>This operation returns a id sequence of all channel's created by this ChannelFactory.</p>
- </desc>
- </func>
- <func>
- <name>get_event_channel(ChannelFactory, ChannelID) -> Return</name>
- <fsummary>Return the channel object associated with the given Id</fsummary>
- <type>
- <v>ChannelFactory = #objref</v>
- <v>ChannelID = long()</v>
- <v>Retrurn = EventChannel | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}</v>
- <v>EventChannel = #objref</v>
- </type>
- <desc>
- <p>This operation returns the EventChannel associated with the given id. If no channel is
- associated with the id, i.e., never existed or have been terminated, an exception is raised.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyConsumer.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyConsumer.xml
deleted file mode 100644
index 3d61893162..0000000000
--- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyConsumer.xml
+++ /dev/null
@@ -1,128 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosNotifyChannelAdmin_ProxyConsumer</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosNotifyChannelAdmin_ProxyConsumer</module>
- <modulesummary>This module implements the OMG CosNotifyChannelAdmin::ProxyConsumer interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosNotification/include/*.hrl").</c></p>
- <p>This module also exports the functions described in:</p>
- <list type="bulleted">
- <item>
- <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p>
- </item>
- </list>
- </description>
- <funcs>
- <func>
- <name>_get_MyType(ProxyConsumer) -> ProxyType</name>
- <fsummary>Return the proxy type</fsummary>
- <type>
- <v>ProxyConsumer = #objref</v>
- <v>ProxyType = 'PUSH_ANY' | 'PULL_ANY' | 'PUSH_STRUCTURED' | 'PULL_STRUCTURED' | 'PUSH_SEQUENCE' | 'PULL_SEQUENCE'</v>
- </type>
- <desc>
- <p>This readonly attribute maintains the enumerant describing the which type the target object
- is. </p>
- </desc>
- </func>
- <func>
- <name>_get_MyAdmin(ProxyConsumer) -> AdminObject</name>
- <fsummary>return the associated <c>Admin</c>object</fsummary>
- <type>
- <v>ProxyConsumer = AdminObject = #objref</v>
- </type>
- <desc>
- <p>This readonly attribute maintains the admin's reference which created the target object.</p>
- </desc>
- </func>
- <func>
- <name>obtain_subscription_types(ProxyConsumer, ObtainInfoMode) -> EventTypeSeq</name>
- <fsummary>Administer subscription types</fsummary>
- <type>
- <v>ProxyConsumer = #objref</v>
- <v>ObtainInfoMode = 'ALL_NOW_UPDATES_OFF' | 'ALL_NOW_UPDATES_ON' | 'NONE_NOW_UPDATES_OFF' | 'NONE_NOW_UPDATES_ON'</v>
- <v>EventTypeSeq = [EventType]</v>
- <v>EventType = #'CosNotification_EventType'{domain_name, type_name}</v>
- <v>domain_name = type_name = string()</v>
- </type>
- <desc>
- <p>Depending on the input parameter <c>ObtainInfoMode</c>, this operation may return a
- sequence of the <c>EventTypes</c> the target object is interested in receiving.
- If <c>'ALL_NOW_UPDATES_OFF'</c> or <c>'ALL_NOW_UPDATES_ON'</c> is given a sequence will
- be returned, otherwise not. If <c>'ALL_NOW_UPDATES_OFF'</c> or <c>'NONE_NOW_UPDATES_OFF'</c>
- are issued the target object will not inform the associated <c>NotifySubscribe</c> object
- when an update occurs. <c>'ALL_NOW_UPDATES_ON'</c> or <c>'NONE_NOW_UPDATES_ON'</c> will
- result in that update information will be sent.</p>
- </desc>
- </func>
- <func>
- <name>validate_event_qos(ProxyConsumer, QoSProperties) -> Reply</name>
- <fsummary>Check if certain Quality of Service properties can be added to events in the current context of the target object</fsummary>
- <type>
- <v>ProxyConsumer = #objref</v>
- <v>QoSProperties = [QoSProperty]</v>
- <v>QoSProperty = #'CosNotification_Property'{name, value}</v>
- <v>name = string()</v>
- <v>value = #any</v>
- <v>Reply = {ok, NamedPropertyRangeSeq} | {'EXCEPTION', CosNotification_UnsupportedQoS{qos_err}}</v>
- <v>NamedPropertyRangeSeq = [NamedPropertyRange]</v>
- <v>NamedPropertyRange = #CosNotification_NamedPropertyRange{name, range}</v>
- <v>name = string()</v>
- <v>range = #CosNotification_PropertyRange{low_val, high_val}</v>
- <v>low_val = #any</v>
- <v>high_val = #any</v>
- <v>qos_err = PropertyErrorSeq</v>
- <v>PropertyErrorSeq = [PropertyError]</v>
- <v>PropertyError = #'CosNotification_PropertyError'{code, name, available_range}</v>
- <v>code = 'UNSUPPORTED_PROPERTY' | 'UNAVAILABLE_PROPERTY' | 'UNSUPPORTED_VALUE' | 'UNAVAILABLE_VALUE' | 'BAD_PROPERTY' | 'BAD_TYPE' | 'BAD_VALUE'</v>
- <v>name = string()</v>
- <v>available_range = PropertyRange</v>
- <v>PropertyRange = #CosNotification_PropertyRange{low_val, high_val}</v>
- <v>low_val = high_val = #any</v>
- </type>
- <desc>
- <p>To check if certain Quality of Service properties can be added to events in
- the current context of the target object this operation should be used. If we
- cannot support the required settings an exception describing why will be raised.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullConsumer.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullConsumer.xml
deleted file mode 100644
index caf572dee8..0000000000
--- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullConsumer.xml
+++ /dev/null
@@ -1,113 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosNotifyChannelAdmin_ProxyPullConsumer</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosNotifyChannelAdmin_ProxyPullConsumer</module>
- <modulesummary>This module implements the OMG CosNotifyChannelAdmin::ProxyPullConsumer interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosNotification/include/*.hrl").</c></p>
- <p>This module also exports the functions described in:</p>
- <list type="bulleted">
- <item>
- <p><seealso marker="CosNotifyComm_NotifyPublish">CosNotifyComm_NotifyPublish</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyChannelAdmin_ProxyConsumer">CosNotifyChannelAdmin_ProxyConsumer</seealso></p>
- </item>
- </list>
- </description>
- <funcs>
- <func>
- <name>connect_any_pull_supplier(ProxyPullConsumer, PullSupplier) -> Reply</name>
- <fsummary>Connect a supplier to the proxy</fsummary>
- <type>
- <v>ProxyPullConsumer = #objref</v>
- <v>PullSupplier = #objref</v>
- <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}} | {'EXCEPTION', #'CosEventChannelAdmin_TypeError'{}}</v>
- </type>
- <desc>
- <p>This operation connects the given <c>PullSupplier</c> to the target object.
- If a client is already connected the <c>AlreadyConnected</c> exception
- will be raised. The client must support the operations <c>pull</c> and
- <c>try_pull</c>, otherwise the <c>TypeError</c> exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>suspend_connection(ProxyPullConsumer) -> Reply</name>
- <fsummary>Suspend the connection between the client and the proxy</fsummary>
- <type>
- <v>ProxyPullConsumer = #objref</v>
- <v>Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}}</v>
- </type>
- <desc>
- <p>If we want to temporarily suspend the connection with the target object this
- operation must be sued. If the connection already have been suspended or
- no client have been connected an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>resume_connection(ProxyPullConsumer) -> Reply</name>
- <fsummary>Resume a previously suspended connection with the proxy</fsummary>
- <type>
- <v>ProxyPullConsumer = #objref</v>
- <v>Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyActive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}}</v>
- </type>
- <desc>
- <p>If The connection have been suspended earlier we can invoke this operation to
- reinstate the connection. If the connection already is active or no client
- have been connected to the target object an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>disconnect_pull_consumer(ProxyPullConsumer) -> ok</name>
- <fsummary>Close the connection and terminate the proxy</fsummary>
- <type>
- <v>ProxyPullConsumer = #objref</v>
- </type>
- <desc>
- <p>Invoking this operation disconnects the client from the target object which
- then terminates and inform its administrative parent.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullSupplier.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullSupplier.xml
deleted file mode 100644
index 42aaaec319..0000000000
--- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullSupplier.xml
+++ /dev/null
@@ -1,112 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosNotifyChannelAdmin_ProxyPullSupplier</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosNotifyChannelAdmin_ProxyPullSupplier</module>
- <modulesummary>This module implements the OMG CosNotifyChannelAdmin::ProxyPullSupplier interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosNotification/include/*.hrl").</c></p>
- <p>This module also exports the functions described in:</p>
- <list type="bulleted">
- <item>
- <p><seealso marker="CosNotifyComm_NotifySubscribe">CosNotifyComm_NotifySubscribe</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyChannelAdmin_ProxySupplier">CosNotifyChannelAdmin_ProxySupplier</seealso></p>
- </item>
- </list>
- </description>
- <funcs>
- <func>
- <name>connect_any_pull_consumer(ProxyPullSupplier, PullConsumer) -> Reply</name>
- <fsummary>Connect a consumer to the proxy</fsummary>
- <type>
- <v>ProxyPullSupplier = #objref</v>
- <v>PullConsumer = #objref</v>
- <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}}</v>
- </type>
- <desc>
- <p>This operation connects the given <c>PullConsumer</c> to the target object.
- If a connection already exists the <c>AlreadyConnected</c> exception is
- raised.</p>
- </desc>
- </func>
- <func>
- <name>pull(ProxyPullSupplier) -> Reply</name>
- <fsummary>Pull an Any event from the proxy</fsummary>
- <type>
- <v>ProxyPullSupplier = #objref</v>
- <v>Reply = #any | {'EXCEPTION', #'CosEventChannelAdmin_Disconnected'{}}</v>
- </type>
- <desc>
- <p>This operation pulls next <c>#any{}</c> event, and blocks, if the target object
- have no events to forward, until an event can be delivered. If no client have
- been connected the <c>Disconnected</c> exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>try_pull(ProxyPullSupplier) -> Reply</name>
- <fsummary>Try and pull an Any event from the proxy</fsummary>
- <type>
- <v>ProxyPullSupplier = #objref</v>
- <v>Reply = {#any, HasEvent} | {'EXCEPTION', #'CosEventChannelAdmin_Disconnected'{}}</v>
- <v>HasEvent = boolean()</v>
- </type>
- <desc>
- <p>This operation pulls next event, but do not block if the target object
- have no event to forward. If no client have
- been connected the <c>Disconnected</c> exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>disconnect_pull_supplier(ProxyPullSupplier) -> ok</name>
- <fsummary>Close the connection and terminate the proxy</fsummary>
- <type>
- <v>ProxyPullSupplier = #objref</v>
- </type>
- <desc>
- <p>Invoking this operation will cause the target object to close the connection and terminate.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushConsumer.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushConsumer.xml
deleted file mode 100644
index 9808b460c7..0000000000
--- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushConsumer.xml
+++ /dev/null
@@ -1,98 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosNotifyChannelAdmin_ProxyPushConsumer</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved>Niclas Eklund</approved>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosNotifyChannelAdmin_ProxyPushConsumer</module>
- <modulesummary>This module implements the OMG CosNotifyChannelAdmin::ProxyPushConsumer interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosNotification/include/*.hrl").</c></p>
- <p>This module also exports the functions described in:</p>
- <list type="bulleted">
- <item>
- <p><seealso marker="CosNotifyComm_NotifyPublish">CosNotifyComm_NotifyPublish</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyChannelAdmin_ProxyConsumer">CosNotifyChannelAdmin_ProxyConsumer</seealso></p>
- </item>
- </list>
- </description>
- <funcs>
- <func>
- <name>connect_any_push_supplier(ProxyPushConsumer, PushSupplier) -> Reply</name>
- <fsummary>Connect a supplier to the proxy</fsummary>
- <type>
- <v>ProxyPushConsumer = #objref</v>
- <v>PushSupplier = #objref</v>
- <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}}</v>
- </type>
- <desc>
- <p>This operation connects a <c>PushSupplier</c> to the target object. If
- a connection already exists the <c>AlreadyConnected</c> exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>push(ProxyPushConsumer, Event) -> Reply</name>
- <fsummary>Push an Any event to the proxy</fsummary>
- <type>
- <v>ProxyPushConsumer = #objref</v>
- <v>Event = #any</v>
- <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_Disconnected'{}}</v>
- </type>
- <desc>
- <p>This operation pushes an <c>#any{}</c> event to the target object. If no client
- have been connected the <c>Disconnected</c> exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>disconnect_push_consumer(ProxyPushConsumer) -> ok</name>
- <fsummary>Close the connection and terminate the proxy</fsummary>
- <type>
- <v>ProxyPushConsumer = #objref</v>
- </type>
- <desc>
- <p>Invoking this operation will cause the target object to close the connection and
- terminate.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushSupplier.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushSupplier.xml
deleted file mode 100644
index 6f85de114a..0000000000
--- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushSupplier.xml
+++ /dev/null
@@ -1,110 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosNotifyChannelAdmin_ProxyPushSupplier</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosNotifyChannelAdmin_ProxyPushSupplier</module>
- <modulesummary>This module implements the OMG CosNotifyChannelAdmin::ProxyPushSupplier interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosNotification/include/*.hrl").</c></p>
- <p>This module also exports the functions described in:</p>
- <list type="bulleted">
- <item>
- <p><seealso marker="CosNotifyComm_NotifySubscribe">CosNotifyComm_NotifySubscribe</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmi</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyChannelAdmin_ProxySupplier">CosNotifyChannelAdmin_ProxySupplier</seealso></p>
- </item>
- </list>
- </description>
- <funcs>
- <func>
- <name>connect_any_push_consumer(ProxyPushSupplier, PushConsumer) -> Reply</name>
- <fsummary>Connect a consumer to the proxy</fsummary>
- <type>
- <v>ProxyPushSupplier = #objref</v>
- <v>PushConsumer = #objref</v>
- <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}} | {'EXCEPTION', #'CosEventChannelAdmin_TypeError'{}}</v>
- </type>
- <desc>
- <p>This operation connects a <c>PushConsumer</c> to the target object. If
- a connection already exists or the given client does not support
- the operation <c>push</c> an exception, <c>AlreadyConnected</c> and
- <c>TypeError</c> respectively, is raised.</p>
- </desc>
- </func>
- <func>
- <name>suspend_connection(ProxyPushSupplier) -> Reply</name>
- <fsummary>Suspend the connection between the proxy and the client</fsummary>
- <type>
- <v>ProxyPushSupplier = #objref</v>
- <v>Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}}</v>
- </type>
- <desc>
- <p>This operation suspends the connection with the client object. If the connection
- already is suspended or no client have been associated an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>resume_connection(ProxyPushSupplier) -> Reply</name>
- <fsummary>Resume a previously suspended connection with the proxy</fsummary>
- <type>
- <v>ProxyPullConsumer = #objref</v>
- <v>Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}}</v>
- </type>
- <desc>
- <p>If a connection have been suspended earlier, calling this operation will resume the connection.
- If the connection already is active or no client have been connected an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>disconnect_push_supplier(ProxyPushSupplier) -> ok</name>
- <fsummary>Close the connection and terminate the proxy</fsummary>
- <type>
- <v>ProxyPushSupplier = #objref</v>
- </type>
- <desc>
- <p>This operation cause the target object to close the connection and terminate.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxySupplier.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxySupplier.xml
deleted file mode 100644
index 69013fdb1e..0000000000
--- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxySupplier.xml
+++ /dev/null
@@ -1,175 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosNotifyChannelAdmin_ProxySupplier</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosNotifyChannelAdmin_ProxySupplier</module>
- <modulesummary>This module implements the OMG CosNotifyChannelAdmin::ProxySupplier interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosNotification/include/*.hrl").</c></p>
- <p>This module also exports the functions described in:</p>
- <list type="bulleted">
- <item>
- <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p>
- </item>
- </list>
- </description>
- <funcs>
- <func>
- <name>_get_MyType(ProxySupplier) -> ProxyType</name>
- <fsummary>Return the proxy type</fsummary>
- <type>
- <v>ProxySupplier = #objref</v>
- <v>ProxyType = 'PUSH_ANY' | 'PULL_ANY' | 'PUSH_STRUCTURED' | 'PULL_STRUCTURED' | 'PUSH_SEQUENCE' | 'PULL_SEQUENCE'</v>
- </type>
- <desc>
- <p>This readonly attribute maintains the enumerant describing the which type the target object
- is.</p>
- </desc>
- </func>
- <func>
- <name>_get_MyAdmin(ProxySupplier) -> AdminObject</name>
- <fsummary>Return the target object's associated <c>Admin</c>object</fsummary>
- <type>
- <v>ProxySupplier = #objref</v>
- <v>AdminObject = #objref</v>
- </type>
- <desc>
- <p>This readonly attribute maintains the admin's reference which created the target object.</p>
- </desc>
- </func>
- <func>
- <name>_get_priority_filter(ProxySupplier) -> MappingFilter</name>
- <fsummary>Return the target object's associated priority <c>MappingFilter</c></fsummary>
- <type>
- <v>ProxySupplier = #objref</v>
- <v>MappingFilter = #objref</v>
- </type>
- <desc>
- <p>This operation returns the associated priority MappingFilter.
- If no such object exist a <c>NIL</c> reference is returned.</p>
- </desc>
- </func>
- <func>
- <name>_set_priority_filter(ProxySupplier, MappingFilter) -> ok</name>
- <fsummary>Set the target object's associated priority <c>MappingFilter</c></fsummary>
- <type>
- <v>ProxySupplier = #objref</v>
- <v>MappingFilter = #objref</v>
- </type>
- <desc>
- <p>This operation associate a new priority MappingFilter with the target object.</p>
- </desc>
- </func>
- <func>
- <name>_get_lifetime_filter(ProxySupplier) -> MappingFilter</name>
- <fsummary>Return the target object's associated lifetime <c>MappingFilter</c></fsummary>
- <type>
- <v>ProxySupplier = #objref</v>
- <v>MappingFilter = #objref</v>
- </type>
- <desc>
- <p>This operation returns the associated lifetime MappingFilter.
- If no such object exist a <c>NIL</c> reference is returned.</p>
- </desc>
- </func>
- <func>
- <name>_set_lifetime_filter(ProxySupplier, MappingFilter) -> ok</name>
- <fsummary>Set the target object's associated lifetime <c>MappingFilter</c></fsummary>
- <type>
- <v>ProxySupplier = #objref</v>
- <v>MappingFilter = #objref</v>
- </type>
- <desc>
- <p>This operation associate a new lifetime MappingFilter with the target object.</p>
- </desc>
- </func>
- <func>
- <name>obtain_offered_types(ProxySupplier, ObtainInfoMode) -> EventTypeSeq</name>
- <fsummary>Administer the type of events the proxy supplies</fsummary>
- <type>
- <v>ProxySupplier = #objref</v>
- <v>ObtainInfoMode = 'ALL_NOW_UPDATES_OFF' | 'ALL_NOW_UPDATES_ON' | 'NONE_NOW_UPDATES_OFF' | 'NONE_NOW_UPDATES_ON'</v>
- <v>EventTypeSeq = [EventType]</v>
- <v>EventType = #'CosNotification_EventType'{domain_name, type_name}</v>
- <v>domain_name = type_name = string()</v>
- </type>
- <desc>
- <p>Depending on the input parameter <c>ObtainInfoMode</c>, this operation may return a
- sequence of the <c>EventTypes</c> the target object is interested in receiving.
- If <c>'ALL_NOW_UPDATES_OFF'</c> or <c>'ALL_NOW_UPDATES_ON'</c> is given a sequence will
- be returned, otherwise not. If <c>'ALL_NOW_UPDATES_OFF'</c> or <c>'NONE_NOW_UPDATES_OFF'</c>
- are issued the target object will not inform the associated <c>NotifySubscribe</c> object
- when an update occurs. <c>'ALL_NOW_UPDATES_ON'</c> or <c>'NONE_NOW_UPDATES_ON'</c> will
- result in that update information will be sent.</p>
- </desc>
- </func>
- <func>
- <name>validate_event_qos(ProxySupplier, QoSProperties) -> Reply</name>
- <fsummary>Check if the QoS properties can be set</fsummary>
- <type>
- <v>ProxySupplier = #objref</v>
- <v>QoSProperties = [QoSProperty]</v>
- <v>QoSProperty = #'CosNotification_Property'{name, value}</v>
- <v>name = string()</v>
- <v>value = #any</v>
- <v>Reply = {ok, NamedPropertyRangeSeq} | {'EXCEPTION', CosNotification_UnsupportedQoS{qos_err}}</v>
- <v>NamedPropertyRangeSeq = [NamedPropertyRange]</v>
- <v>NamedPropertyRange = #CosNotification_NamedPropertyRange{name, range}</v>
- <v>name = string()</v>
- <v>range = #CosNotification_PropertyRange{low_val, high_val}</v>
- <v>low_val = #any</v>
- <v>high_val = #any</v>
- <v>qos_err = PropertyErrorSeq</v>
- <v>PropertyErrorSeq = [PropertyError]</v>
- <v>PropertyError = #'CosNotification_PropertyError'{code, name, available_range}</v>
- <v>code = 'UNSUPPORTED_PROPERTY' | 'UNAVAILABLE_PROPERTY' | 'UNSUPPORTED_VALUE' | 'UNAVAILABLE_VALUE' | 'BAD_PROPERTY' | 'BAD_TYPE' | 'BAD_VALUE'</v>
- <v>name = string()</v>
- <v>available_range = PropertyRange</v>
- <v>PropertyRange = #CosNotification_PropertyRange{low_val, high_val}</v>
- <v>low_val = high_val = #any</v>
- </type>
- <desc>
- <p>To check if certain Quality of Service properties can be added to events in
- the current context of the target object this operation should be used. If we
- cannot support the required settings an exception describing why will be raised.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullConsumer.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullConsumer.xml
deleted file mode 100644
index 043472df55..0000000000
--- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullConsumer.xml
+++ /dev/null
@@ -1,112 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosNotifyChannelAdmin_SequenceProxyPullConsumer</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosNotifyChannelAdmin_SequenceProxyPullConsumer</module>
- <modulesummary>This module implements the OMG CosNotifyChannelAdmin::SequenceProxyPullConsumer interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosNotification/include/*.hrl").</c></p>
- <p>This module also exports the functions described in:</p>
- <list type="bulleted">
- <item>
- <p><seealso marker="CosNotifyComm_NotifyPublish">CosNotifyComm_NotifyPublish</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyChannelAdmin_ProxyConsumer">CosNotifyChannelAdmin_ProxyConsumer</seealso></p>
- </item>
- </list>
- </description>
- <funcs>
- <func>
- <name>connect_sequence_pull_supplier(SequenceProxyPullConsumer, PullSupplier) -> Reply</name>
- <fsummary>Connect a supplier to the proxy</fsummary>
- <type>
- <v>SequenceProxyPullConsumer = #objref</v>
- <v>PullSupplier = #objref</v>
- <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}} | {'EXCEPTION', #'CosEventChannelAdmin_TypeError'{}}</v>
- </type>
- <desc>
- <p>This operation connects a <c>PullSupplier</c> to the target object. If a
- connection already exists or the supplied client does not support the functions
- <c>pull_structured_events</c> and <c>try_pull_structured_events</c> an exception
- is raised.</p>
- </desc>
- </func>
- <func>
- <name>suspend_connection(SequenceProxyPullConsumer) -> Reply</name>
- <fsummary>Suspend the connection with the proxy</fsummary>
- <type>
- <v>SequenceProxyPullConsumer = #objref</v>
- <v>Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}}</v>
- </type>
- <desc>
- <p>If a connection exist, invoking this operation will suspend the connection
- until instructed otherwise. Otherwise, no client have been connected or this operation
- already have been invoked an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>resume_connection(SequenceProxyPullConsumer) -> Reply</name>
- <fsummary>Resume a previously suspended connection with the proxy</fsummary>
- <type>
- <v>SequenceProxyPullConsumer = #objref</v>
- <v>Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}}</v>
- </type>
- <desc>
- <p>If an connection have been suspended this operation must be used to resume the
- connection. If the connection already is active or no client have been connected an
- exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>disconnect_sequence_pull_consumer(SequenceProxyPullConsumer) -> ok</name>
- <fsummary>Close connection and terminate the proxy</fsummary>
- <type>
- <v>SequenceProxyPullConsumer = #objref</v>
- </type>
- <desc>
- <p>This operation close the connection to the client and terminates the target object.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullSupplier.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullSupplier.xml
deleted file mode 100644
index a0040a50d7..0000000000
--- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullSupplier.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosNotifyChannelAdmin_SequenceProxyPullSupplier</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosNotifyChannelAdmin_SequenceProxyPullSupplier</module>
- <modulesummary>This module implements the OMG CosNotifyChannelAdmin::SequenceProxyPullSupplier interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosNotification/include/*.hrl").</c></p>
- <p>This module also exports the functions described in:</p>
- <list type="bulleted">
- <item>
- <p><seealso marker="CosNotifyComm_NotifySubscribe">CosNotifyComm_NotifySubscribe</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyChannelAdmin_ProxySupplier">CosNotifyChannelAdmin_ProxySupplier</seealso></p>
- </item>
- </list>
- </description>
- <funcs>
- <func>
- <name>connect_sequence_pull_consumer(SequenceProxyPullSupplier, PullConsumer) -> Reply</name>
- <fsummary>Connect a consumer to the proxy</fsummary>
- <type>
- <v>SequenceProxyPullSupplier = #objref</v>
- <v>PullConsumer = #objref</v>
- <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}}</v>
- </type>
- <desc>
- <p>This operation connects a <c>PullConsumer</c> to the target object. If a connection
- already exists an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>pull_structured_events(SequenceProxyPullSupplier, MaxEvents) -> Reply</name>
- <fsummary>Pull structured events from the proxy</fsummary>
- <type>
- <v>SequenceProxyPullSupplier = #objref</v>
- <v>MaxEvents = long()</v>
- <v>Reply = EventBatch | {'EXCEPTION', #'CosEventChannelAdmin_Disconnected'{}}</v>
- <v>EventBatch = [StructuredEvent]</v>
- <v>StructuredEvent = #'CosNotification_StructuredEvent'{header, filterable_data, remainder_of_body}</v>
- <v>header = EventHeader</v>
- <v>filterable_data = [#'CosNotification_Property'{name, value}]</v>
- <v>name = string()</v>
- <v>value = #any</v>
- <v>remainder_of_body = #any</v>
- <v>EventHeader = #'CosNotification_EventHeader'{fixed_header, variable_header}</v>
- <v>fixed_header = FixedEventHeader</v>
- <v>variable_header = OptionalHeaderFields</v>
- <v>FixedEventHeader = #'CosNotification_FixedEventHeader'{event_type, event_name}</v>
- <v>event_type = EventType</v>
- <v>event_name = string()</v>
- <v>EventType = #'CosNotification_EventType'{domain_name, type_name}</v>
- <v>domain_name = type_name = string()</v>
- <v>OptionalHeaderFields = [#'CosNotification_Property'{name, value}]</v>
- </type>
- <desc>
- <p>A client use this operation to pull next event sequence of maximum length
- <c>MaxEvents</c>. This operation is blocking and will not reply until the
- requested amount of events can be delivered or the QoS property <c>PacingInterval</c>
- is reached. For more information see the <c>User's Guide</c>.</p>
- </desc>
- </func>
- <func>
- <name>try_pull_structured_events(SequenceProxyPullSupplier, MaxEvents) -> Reply</name>
- <fsummary>Try to pull structured events from the proxy</fsummary>
- <type>
- <v>SequenceProxyPullSupplier = #objref</v>
- <v>MaxEvents = long()</v>
- <v>Reply = {EventBatch, HasEvent} | {'EXCEPTION', #'CosEventChannelAdmin_Disconnected'{}}</v>
- <v>HasEvent = boolean()</v>
- <v>EventBatch = [StructuredEvent]</v>
- <v>StructuredEvent = #'CosNotification_StructuredEvent'{header, filterable_data, remainder_of_body}</v>
- <v>header = EventHeader</v>
- <v>filterable_data = [#'CosNotification_Property'{name, value}]</v>
- <v>name = string()</v>
- <v>value = #any</v>
- <v>remainder_of_body = #any</v>
- <v>EventHeader = #'CosNotification_EventHeader'{fixed_header, variable_header}</v>
- <v>fixed_header = FixedEventHeader</v>
- <v>variable_header = OptionalHeaderFields</v>
- <v>FixedEventHeader = #'CosNotification_FixedEventHeader'{event_type, event_name}</v>
- <v>event_type = EventType</v>
- <v>event_name = string()</v>
- <v>EventType = #'CosNotification_EventType'{domain_name, type_name}</v>
- <v>domain_name = type_name = string()</v>
- <v>OptionalHeaderFields = [#'CosNotification_Property'{name, value}]</v>
- </type>
- <desc>
- <p>This operation pulls an event sequence of the maximum length <c>MaxEvents</c>,
- but do not block if the target object have no events to forward. The outparameter,
- <c>HasEvent</c> is true if the sequence contain any events.</p>
- </desc>
- </func>
- <func>
- <name>disconnect_sequence_pull_supplier(SequenceProxyPullSupplier) -> ok</name>
- <fsummary>Close the connection and terminate the proxy</fsummary>
- <type>
- <v>SequenceProxyPullSupplier = #objref</v>
- </type>
- <desc>
- <p>This operation cause the target object to close the connection and terminate.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushConsumer.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushConsumer.xml
deleted file mode 100644
index efec1f99cc..0000000000
--- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushConsumer.xml
+++ /dev/null
@@ -1,109 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>CosNotifyChannelAdmin_SequenceProxyPushConsumer</title>
- <prepared></prepared>
- <docno></docno>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosNotifyChannelAdmin_SequenceProxyPushConsumer</module>
- <modulesummary>This module implements the OMG CosNotifyChannelAdmin::SequenceProxyPushConsumer interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosNotification/include/*.hrl").</c></p>
- <p>This module also exports the functions described in:</p>
- <list type="bulleted">
- <item>
- <p><seealso marker="CosNotifyComm_NotifyPublish">CosNotifyComm_NotifyPublish</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyChannelAdmin_ProxyConsumer">CosNotifyChannelAdmin_ProxyConsumer</seealso></p>
- </item>
- </list>
- </description>
- <funcs>
- <func>
- <name>connect_sequence_push_supplier(SequenceProxyPushConsumer, PushSupplier) -> Reply</name>
- <fsummary>Connect a supplier to the proxy</fsummary>
- <type>
- <v>SequenceProxyPushConsumer = #objref</v>
- <v>PushSupplier = #objref</v>
- <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}}</v>
- </type>
- <desc>
- <p>This operation connects a <c>PushSupplier</c> to the target object. If a
- connection already exists the <c>AlreadyConnected</c> exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>push_structured_events(SequenceProxyPushConsumer, EventBatch) -> Reply</name>
- <fsummary>Push a structured event to the proxy</fsummary>
- <type>
- <v>SequenceProxyPushConsumer = #objref</v>
- <v>EventBatch = [StructuredEvent]</v>
- <v>StructuredEvent = #'CosNotification_StructuredEvent'{header, filterable_data, remainder_of_body}</v>
- <v>header = EventHeader</v>
- <v>filterable_data = [#'CosNotification_Property'{name, value}]</v>
- <v>name = string()</v>
- <v>value = #any</v>
- <v>remainder_of_body = #any</v>
- <v>EventHeader = #'CosNotification_EventHeader'{fixed_header, variable_header}</v>
- <v>fixed_header = FixedEventHeader</v>
- <v>variable_header = OptionalHeaderFields</v>
- <v>FixedEventHeader = #'CosNotification_FixedEventHeader'{event_type, event_name}</v>
- <v>event_type = EventType</v>
- <v>event_name = string()</v>
- <v>EventType = #'CosNotification_EventType'{domain_name, type_name}</v>
- <v>domain_name = type_name = string()</v>
- <v>OptionalHeaderFields = [#'CosNotification_Property'{name, value}]</v>
- <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_Disconnected'{}}</v>
- </type>
- <desc>
- <p>A client must use this operation when it wishes to push a new sequence of events
- to the target object. If no connection exists the <c>Disconnected</c> exception
- is raised.</p>
- </desc>
- </func>
- <func>
- <name>disconnect_sequence_push_consumer(SequenceProxyPushConsumer) -> ok</name>
- <fsummary>Close connection and terminate the proxy</fsummary>
- <type>
- <v>SequenceProxyPushConsumer = #objref</v>
- </type>
- <desc>
- <p>This operation cause the target object to close the connection and terminate.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushSupplier.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushSupplier.xml
deleted file mode 100644
index 229d3667c5..0000000000
--- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushSupplier.xml
+++ /dev/null
@@ -1,111 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosNotifyChannelAdmin_SequenceProxyPushSupplier</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosNotifyChannelAdmin_SequenceProxyPushSupplier</module>
- <modulesummary>This module implements the OMG CosNotifyChannelAdmin::SequenceProxyPushSupplier interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosNotification/include/*.hrl").</c></p>
- <p>This module also exports the functions described in:</p>
- <list type="bulleted">
- <item>
- <p><seealso marker="CosNotifyComm_NotifySubscribe">CosNotifyComm_NotifySubscribe</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyChannelAdmin_ProxySupplier">CosNotifyChannelAdmin_ProxySupplier</seealso></p>
- </item>
- </list>
- </description>
- <funcs>
- <func>
- <name>connect_sequence_push_consumer(SequenceProxyPushSupplier, PushConsumer) -> Reply</name>
- <fsummary>Connect a consumer to the proxy</fsummary>
- <type>
- <v>SequenceProxyPushSupplier = #objref</v>
- <v>PushConsumer = #objref</v>
- <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}} | {'EXCEPTION', #'CosEventChannelAdmin_TypeError'{}}</v>
- </type>
- <desc>
- <p>This operation connects a <c>PushConsumer</c> to the target object. If a
- connection already exists or the function <c>psuh_structured_events</c>
- is not supported the exceptions <c>AlreadyConnected</c> or
- <c>TypeError</c> will be raised respectively.</p>
- </desc>
- </func>
- <func>
- <name>suspend_connection(SequenceProxyPushSupplier) -> Reply</name>
- <fsummary>Suspend the connection between the client and the target object</fsummary>
- <type>
- <v>SequenceProxyPushSupplier = #objref</v>
- <v>Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}}</v>
- </type>
- <desc>
- <p>This operation suspends the connection between the client and the target object.
- If no connection exists or the connection is already suspended an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>resume_connection(SequenceProxyPushSupplier) -> Reply</name>
- <fsummary>Resume a previously suspended connection with the proxy</fsummary>
- <type>
- <v>SequenceProxyPullConsumer = #objref</v>
- <v>Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}}</v>
- </type>
- <desc>
- <p>If the connection have previously been suspended this operation must used
- if we want to resume the connection. If no object have been connected or the connection
- already is active an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>disconnect_sequence_push_supplier(SequenceProxyPushSupplier) -> ok</name>
- <fsummary>Close the connection and terminate the proxy</fsummary>
- <type>
- <v>SequenceProxyPushSupplier = #objref</v>
- </type>
- <desc>
- <p>This operation cause the target object to close the connection and terminate.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullConsumer.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullConsumer.xml
deleted file mode 100644
index 5a86cb84da..0000000000
--- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullConsumer.xml
+++ /dev/null
@@ -1,110 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosNotifyChannelAdmin_StructuredProxyPullConsumer</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosNotifyChannelAdmin_StructuredProxyPullConsumer</module>
- <modulesummary>This module implements the OMG CosNotifyChannelAdmin::StructuredProxyPullConsumer interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosNotification/include/*.hrl").</c></p>
- <p>This module also exports the functions described in:</p>
- <list type="bulleted">
- <item>
- <p><seealso marker="CosNotifyComm_NotifyPublish">CosNotifyComm_NotifyPublish</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyChannelAdmin_ProxyConsumer">CosNotifyChannelAdmin_ProxyConsumer</seealso></p>
- </item>
- </list>
- </description>
- <funcs>
- <func>
- <name>connect_structured_pull_supplier(StructuredProxyPullConsumer, PullSupplier) -> Reply</name>
- <fsummary>Connect a supplier to the proxy</fsummary>
- <type>
- <v>StructuredProxyPullConsumer = #objref</v>
- <v>PullSupplier = #objref</v>
- <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}} | {'EXCEPTION', #'CosEventChannelAdmin_TypeError'{}}</v>
- </type>
- <desc>
- <p>This operation connects a <c>PullSupplier</c> to the target object. If a connection
- already exists or the given client object does not support the functions
- <c>pull_structured_event</c> and <c>try_pull_structured_event</c> an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>suspend_connection(StructuredProxyPullConsumer) -> Reply</name>
- <fsummary>Suspend the connection between the target object and its client</fsummary>
- <type>
- <v>StructuredProxyPullConsumer = #objref</v>
- <v>Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}}</v>
- </type>
- <desc>
- <p>This operation suspends the connection between the target object and its client.
- If no connection exists or already suspended an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>resume_connection(StructuredProxyPullConsumer) -> Reply</name>
- <fsummary>Resume a previously suspended connection with the proxy</fsummary>
- <type>
- <v>StructuredProxyPullConsumer = #objref</v>
- <v>Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}}</v>
- </type>
- <desc>
- <p>If the connection have been suspended this operation must be used if we want
- to resume the connection. If the connection already are active or no connection
- have been created an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>disconnect_structured_pull_consumer(StructuredProxyPullConsumer) -> ok</name>
- <fsummary>Close the connection and terminate the proxy</fsummary>
- <type>
- <v>StructuredProxyPullConsumer = #objref</v>
- </type>
- <desc>
- <p>This operation cause the target object to close the connection and terminate.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullSupplier.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullSupplier.xml
deleted file mode 100644
index 1ca7c2d7df..0000000000
--- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullSupplier.xml
+++ /dev/null
@@ -1,140 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosNotifyChannelAdmin_StructuredProxyPullSupplier</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosNotifyChannelAdmin_StructuredProxyPullSupplier</module>
- <modulesummary>This module implements the OMG CosNotifyChannelAdmin::StructuredProxyPullSupplier interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosNotification/include/*.hrl").</c></p>
- <p>This module also exports the functions described in:</p>
- <list type="bulleted">
- <item>
- <p><seealso marker="CosNotifyComm_NotifySubscribe">CosNotifyComm_NotifySubscribe</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyChannelAdmin_ProxySupplier">CosNotifyChannelAdmin_ProxySupplier</seealso></p>
- </item>
- </list>
- </description>
- <funcs>
- <func>
- <name>connect_structured_pull_consumer(StructuredProxyPullSupplier, PullConsumer) -> Reply</name>
- <fsummary>Connect a consumer to the proxy</fsummary>
- <type>
- <v>StructuredProxyPullSupplier = #objref</v>
- <v>PullConsumer = #objref</v>
- <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}}</v>
- </type>
- <desc>
- <p>This operation connects a <c>PullConsumer</c> to the target object. If a connection
- already exists the <c>AlreadyConnected</c> exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>pull_structured_event(StructuredProxyPullSupplier) -> Reply</name>
- <fsummary>Pull a structured event from the proxy</fsummary>
- <type>
- <v>StructuredProxyPullSupplier = #objref</v>
- <v>Reply = StructuredEvent | {'EXCEPTION', #'CosEventChannelAdmin_Disconnected'{}}</v>
- <v>StructuredEvent = #'CosNotification_StructuredEvent'{header, filterable_data, remainder_of_body}</v>
- <v>header = EventHeader</v>
- <v>filterable_data = [#'CosNotification_Property'{name, value}]</v>
- <v>name = string()</v>
- <v>value = #any</v>
- <v>remainder_of_body = #any</v>
- <v>EventHeader = #'CosNotification_EventHeader'{fixed_header, variable_header}</v>
- <v>fixed_header = FixedEventHeader</v>
- <v>variable_header = OptionalHeaderFields</v>
- <v>FixedEventHeader = #'CosNotification_FixedEventHeader'{event_type, event_name}</v>
- <v>event_type = EventType</v>
- <v>event_name = string()</v>
- <v>EventType = #'CosNotification_EventType'{domain_name, type_name}</v>
- <v>domain_name = type_name = string()</v>
- <v>OptionalHeaderFields = [#'CosNotification_Property'{name, value}]</v>
- </type>
- <desc>
- <p>This operation pulls next event from the target object; if an event cannot
- be delivered this function blocks until an event arrives.</p>
- </desc>
- </func>
- <func>
- <name>try_pull_structured_event(StructuredProxyPullSupplier) -> Reply</name>
- <fsummary>Try to pull a structured event from the proxy</fsummary>
- <type>
- <v>StructuredProxyPullSupplier = #objref</v>
- <v>Reply = {StructuredEvent, HasEvent} | {'EXCEPTION', #'CosEventChannelAdmin_Disconnected'{}}</v>
- <v>HasEvent = boolean()</v>
- <v>StructuredEvent = #'CosNotification_StructuredEvent'{header, filterable_data, remainder_of_body}</v>
- <v>header = EventHeader</v>
- <v>filterable_data = [#'CosNotification_Property'{name, value}]</v>
- <v>name = string()</v>
- <v>value = #any</v>
- <v>remainder_of_body = #any</v>
- <v>EventHeader = #'CosNotification_EventHeader'{fixed_header, variable_header}</v>
- <v>fixed_header = FixedEventHeader</v>
- <v>variable_header = OptionalHeaderFields</v>
- <v>FixedEventHeader = #'CosNotification_FixedEventHeader'{event_type, event_name}</v>
- <v>event_type = EventType</v>
- <v>event_name = string()</v>
- <v>EventType = #'CosNotification_EventType'{domain_name, type_name}</v>
- <v>domain_name = type_name = string()</v>
- <v>OptionalHeaderFields = [#'CosNotification_Property'{name, value}]</v>
- </type>
- <desc>
- <p>This operation try to pull next event from the target object. If no event have arrived
- an empty event is returned and the out parameter <c>HasEvent</c> is set to false. Otherwise,
- the boolean flag is set to true and an valid event is returned.</p>
- </desc>
- </func>
- <func>
- <name>disconnect_structured_pull_supplier(StructuredProxyPullSupplier) -> ok</name>
- <fsummary>Close connection and terminate the proxy</fsummary>
- <type>
- <v>StructuredProxyPullSupplier = #objref</v>
- </type>
- <desc>
- <p>This operation cause the target object to close the connection and terminate.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushConsumer.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushConsumer.xml
deleted file mode 100644
index 63bcdf120c..0000000000
--- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushConsumer.xml
+++ /dev/null
@@ -1,110 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosNotifyChannelAdmin_StructuredProxyPushConsumer</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosNotifyChannelAdmin_StructuredProxyPushConsumer</module>
- <modulesummary>This module implements the OMG CosNotifyChannelAdmin::StructuredProxyPushConsumer interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosNotification/include/*.hrl").</c></p>
- <p>This module also exports the functions described in:</p>
- <list type="bulleted">
- <item>
- <p><seealso marker="CosNotifyComm_NotifyPublish">CosNotifyComm_NotifyPublish</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyChannelAdmin_ProxyConsumer">CosNotifyChannelAdmin_ProxyConsumer</seealso></p>
- </item>
- </list>
- </description>
- <funcs>
- <func>
- <name>connect_structured_push_supplier(StructuredProxyPushConsumer, PushSupplier) -> Reply</name>
- <fsummary>Connect a supplier to the proxy</fsummary>
- <type>
- <v>StructuredProxyPushConsumer = #objref</v>
- <v>PushSupplier = #objref</v>
- <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}}</v>
- </type>
- <desc>
- <p>This operation connects a <c>PushSupplier</c> to the target object. If a connection
- already exists an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>push_structured_event(StructuredProxyPushConsumer, StructuredEvent) -> Reply</name>
- <fsummary>Push a structured event to the proxy</fsummary>
- <type>
- <v>StructuredProxyPushConsumer = #objref</v>
- <v>StructuredEvent = #'CosNotification_StructuredEvent'{header, filterable_data, remainder_of_body}</v>
- <v>header = EventHeader</v>
- <v>filterable_data = [#'CosNotification_Property'{name, value}]</v>
- <v>name = string()</v>
- <v>value = #any</v>
- <v>remainder_of_body = #any</v>
- <v>EventHeader = #'CosNotification_EventHeader'{fixed_header, variable_header}</v>
- <v>fixed_header = FixedEventHeader</v>
- <v>variable_header = OptionalHeaderFields</v>
- <v>FixedEventHeader = #'CosNotification_FixedEventHeader'{event_type, event_name}</v>
- <v>event_type = EventType</v>
- <v>event_name = string()</v>
- <v>EventType = #'CosNotification_EventType'{domain_name, type_name}</v>
- <v>domain_name = type_name = string()</v>
- <v>OptionalHeaderFields = [#'CosNotification_Property'{name, value}]</v>
- <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_Disconnected'{}}</v>
- </type>
- <desc>
- <p>When a client want to push a new event to the target object this operation must be used.</p>
- </desc>
- </func>
- <func>
- <name>disconnect_structured_push_consumer(StructuredProxyPushConsumer) -> ok</name>
- <fsummary>Close the connection and terminate the proxy</fsummary>
- <type>
- <v>StructuredProxyPushConsumer = #objref</v>
- </type>
- <desc>
- <p>This operation cause the target object to close the connection and terminate.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushSupplier.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushSupplier.xml
deleted file mode 100644
index 9ba5497fd8..0000000000
--- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushSupplier.xml
+++ /dev/null
@@ -1,110 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosNotifyChannelAdmin_StructuredProxyPushSupplier</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosNotifyChannelAdmin_StructuredProxyPushSupplier</module>
- <modulesummary>This module implements the OMG CosNotifyChannelAdmin::StructuredProxyPushSupplier interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosNotification/include/*.hrl").</c></p>
- <p>This module also exports the functions described in:</p>
- <list type="bulleted">
- <item>
- <p><seealso marker="CosNotifyComm_NotifySubscribe">CosNotifyComm_NotifySubscribe</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyChannelAdmin_ProxySupplier">CosNotifyChannelAdmin_ProxySupplier</seealso></p>
- </item>
- </list>
- </description>
- <funcs>
- <func>
- <name>connect_structured_push_consumer(StructuredProxyPushSupplier, PushConsumer) -> Reply</name>
- <fsummary>Connect a consumer to the proxy</fsummary>
- <type>
- <v>StructuredProxyPushSupplier = #objref</v>
- <v>PushConsumer = #objref</v>
- <v>Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}} | {'EXCEPTION', #'CosEventChannelAdmin_TypeError'{}}</v>
- </type>
- <desc>
- <p>This operation connects a <c>PushConsumer</c> to the target object. If
- a connection already exists or the function <c>push_structured_event</c>
- is not supported by the client object an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>suspend_connection(StructuredProxyPushSupplier) -> Reply</name>
- <fsummary>Suspend the connection with the target object</fsummary>
- <type>
- <v>StructuredProxyPushSupplier = #objref</v>
- <v>Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}}</v>
- </type>
- <desc>
- <p>This operation suspends the connection with the target object. If no connection
- exists or the connection already is suspended an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>resume_connection(StructuredProxyPushSupplier) -> Reply</name>
- <fsummary>Resume a previously suspended connection</fsummary>
- <type>
- <v>StructuredProxyPullConsumer = #objref</v>
- <v>Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}}</v>
- </type>
- <desc>
- <p>If the connection with the target object have been suspended this function
- must be used to resume the connection. If no client have been connected or
- the connection is active an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>disconnect_structured_push_supplier(StructuredProxyPushSupplier) -> ok</name>
- <fsummary>Close the connection and terminate the target object</fsummary>
- <type>
- <v>StructuredProxyPushSupplier = #objref</v>
- </type>
- <desc>
- <p>This operation cause the target object to close the connection and terminate.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SupplierAdmin.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SupplierAdmin.xml
deleted file mode 100644
index 540edaff3f..0000000000
--- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SupplierAdmin.xml
+++ /dev/null
@@ -1,195 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosNotifyChannelAdmin_SupplierAdmin</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved>Niclas Eklund</approved>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosNotifyChannelAdmin_SupplierAdmin</module>
- <modulesummary>This module implements the OMG CosNotifyChannelAdmin::SupplierAdmin interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosNotification/include/*.hrl").</c></p>
- <p>This module also exports the functions described in:</p>
- <list type="bulleted">
- <item>
- <p><seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyComm_NotifySubscribe">CosNotifyComm_NotifyPublish</seealso></p>
- </item>
- <item>
- <p><seealso marker="CosNotifyFilter_FilterAdmin">CosNotifyFilter_FilterAdmin</seealso></p>
- </item>
- </list>
- </description>
- <funcs>
- <func>
- <name>_get_MyID(SupplierAdmin) -> AdminID</name>
- <fsummary>Return the objects Id</fsummary>
- <type>
- <v>SupplierAdmin = #objref</v>
- <v>AdminID = long()</v>
- </type>
- <desc>
- <p>When a <c>SupplierAdmin</c> object is created it is given a unique Id
- by the creating channel. This readonly attribute maintains this Id.</p>
- </desc>
- </func>
- <func>
- <name>_get_MyChannel(SupplierAdmin) -> Channel</name>
- <fsummary>Return the objects associated channel</fsummary>
- <type>
- <v>SupplierAdmin = #objref</v>
- <v>Channel = #objref</v>
- </type>
- <desc>
- <p>The creating channel's reference is maintained by this readonly attribute.</p>
- </desc>
- </func>
- <func>
- <name>_get_MyOperator(SupplierAdmin) -> OpType</name>
- <fsummary>Return the filter scheme</fsummary>
- <type>
- <v>SupplierAdmin = #objref</v>
- <v>OpType = 'AND_OP' | 'OR_OP'</v>
- </type>
- <desc>
- <p>The Operation Type, which determines the semantics the target object will
- use for any associated <c>Filters</c>, is maintained by this readonly attribute.</p>
- </desc>
- </func>
- <func>
- <name>_get_pull_consumers(SupplierAdmin) -> ProxyIDSeq</name>
- <fsummary>Return all associated pull consumers Id:s</fsummary>
- <type>
- <v>SupplierAdmin = #objref</v>
- <v>ProxyIDSeq = [ProxyID]</v>
- <v>ProxyID = long()</v>
- </type>
- <desc>
- <p>A sequence of all associated <c>PullProxy</c> Id's is maintained by this
- readonly attribute.</p>
- </desc>
- </func>
- <func>
- <name>_get_push_consumers(SupplierAdmin) -> ProxyIDSeq</name>
- <fsummary>Return all associated push consumers Id:s</fsummary>
- <type>
- <v>SupplierAdmin = #objref</v>
- <v>ProxyIDSeq = [ProxyID]</v>
- <v>ProxyID = long()</v>
- </type>
- <desc>
- <p>This operation returns all <c>PushProxy</c> Id's created by the target
- object.</p>
- </desc>
- </func>
- <func>
- <name>get_proxy_consumer(SupplierAdmin, ProxyID) -> Reply</name>
- <fsummary>Return the Proxy which corresponds to the given Id</fsummary>
- <type>
- <v>SupplierAdmin = #objref</v>
- <v>ProxyID = long()</v>
- <v>Reply = Proxy | {'EXCEPTION', #'CosNotifyChannelAdmin_ProxyNotFound'{}}</v>
- <v>Proxy = #objref</v>
- </type>
- <desc>
- <p>The Proxy which corresponds to the given Id is returned by this operation.</p>
- </desc>
- </func>
- <func>
- <name>obtain_notification_pull_consumer(SupplierAdmin, SupplierType) -> Reply</name>
- <fsummary>Create a new proxy</fsummary>
- <type>
- <v>SupplierAdmin = #objref</v>
- <v>SupplierType = 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT'</v>
- <v>Reply = {Proxy, ProxyID}</v>
- <v>Proxy = #objref</v>
- <v>ProxyID = long()</v>
- </type>
- <desc>
- <p>This operation creates a new proxy and returns its object reference along with its ID.
- The <c>SupplierType</c> parameter determines the event type accepted by the proxy.</p>
- </desc>
- </func>
- <func>
- <name>obtain_pull_consumer(SupplierAdmin) -> Proxy</name>
- <fsummary>Create a new proxy</fsummary>
- <type>
- <v>SupplierAdmin = #objref</v>
- <v>Proxy = #objref</v>
- </type>
- <desc>
- <p>A proxy which accepts <c>#any{}</c> events is created by this operation.</p>
- </desc>
- </func>
- <func>
- <name>obtain_notification_push_consumer(SupplierAdmin, SupplierType) -> Reply</name>
- <fsummary>Create a new proxy</fsummary>
- <type>
- <v>SupplierAdmin = #objref</v>
- <v>SupplierType = 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT'</v>
- <v>Reply = {Proxy, ProxyID}</v>
- <v>Proxy = #objref</v>
- <v>ProxyID = long()</v>
- </type>
- <desc>
- <p>Determined by the <c>SupplierType</c> parameter a compliant proxy is created and
- its object reference along with its Id is returned by this operation.</p>
- </desc>
- </func>
- <func>
- <name>obtain_push_consumer(SupplierAdmin) -> Proxy</name>
- <fsummary>Create a new proxy</fsummary>
- <type>
- <v>SupplierAdmin = #objref</v>
- <v>Proxy = #objref</v>
- </type>
- <desc>
- <p>A proxy which accepts <c>#any{}</c> events is created by this operation.</p>
- </desc>
- </func>
- <func>
- <name>destroy(SupplierAdmin) -> ok</name>
- <fsummary>Terminate the target object</fsummary>
- <type>
- <v>SupplierAdmin = #objref</v>
- </type>
- <desc>
- <p>This operation terminates the SupplierAdmin object and notifies the creating channel
- that the target object no longer is active.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosNotification/doc/src/CosNotifyComm_NotifyPublish.xml b/lib/cosNotification/doc/src/CosNotifyComm_NotifyPublish.xml
deleted file mode 100644
index a41319cb5c..0000000000
--- a/lib/cosNotification/doc/src/CosNotifyComm_NotifyPublish.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosNotifyComm_NotifyPublish</title>
- <prepared>Niclas Eklund</prepared>
- <responsible>Niclas Eklund</responsible>
- <docno></docno>
- <approved>Niclas Eklund</approved>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosNotifyComm_NotifyPublish</module>
- <modulesummary>This module implements the OMG CosNotifyComm::NotifyPublish interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosNotification/include/*.hrl").</c></p>
- <p>All objects, which inherit this interface, export functions described in this module.</p>
- </description>
- <funcs>
- <func>
- <name>offer_change(Object, Added, Removed) -> Reply</name>
- <fsummary>Inform the target object which type of events the supplier will deliver</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>Added = Removed = EventTypeSeq</v>
- <v>EventTypeSeq = [type]</v>
- <v>Reply = ok | {'EXCEPTION', CosNotifyComm_InvalidEventType{type}}</v>
- <v>type = #'CosNotification_EventType'{domain_name, type_name}</v>
- <v>domain_name = type_name = string()</v>
- </type>
- <desc>
- <p>Objects supporting this interface can be informed by supplier objects about
- which type of events that will be delivered in the future. This operation
- accepts two parameters describing new and old event types respectively.
- If any of the supplied event type names is syntactically incorrect an exception
- is raised.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosNotification/doc/src/CosNotifyComm_NotifySubscribe.xml b/lib/cosNotification/doc/src/CosNotifyComm_NotifySubscribe.xml
deleted file mode 100644
index 277c666459..0000000000
--- a/lib/cosNotification/doc/src/CosNotifyComm_NotifySubscribe.xml
+++ /dev/null
@@ -1,64 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosNotifyComm_NotifySubscribe</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosNotifyComm_NotifySubscribe</module>
- <modulesummary>This module implements the OMG CosNotifyComm::NotifySubscribe interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosNotification/include/*.hrl").</c></p>
- <p>All objects, which inherit this interface, export functions described in this module.</p>
- </description>
- <funcs>
- <func>
- <name>subscription_change(Object, Added, Removed) -> Reply</name>
- <fsummary>Inform the target object which event types the client will and will not accept in the future</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>Added = Removed = EventTypeSeq</v>
- <v>EventTypeSeq = [type]</v>
- <v>Reply = ok | {'EXCEPTION', CosNotifyComm_InvalidEventType{type}}</v>
- <v>type = #'CosNotification_EventType'{domain_name, type_name}</v>
- <v>domain_name = type_name = string()</v>
- </type>
- <desc>
- <p>This operation takes as input two sequences of event type names
- specifying events the client will and will not accept in the future
- respectively.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosNotification/doc/src/CosNotifyFilter_Filter.xml b/lib/cosNotification/doc/src/CosNotifyFilter_Filter.xml
deleted file mode 100644
index a953540849..0000000000
--- a/lib/cosNotification/doc/src/CosNotifyFilter_Filter.xml
+++ /dev/null
@@ -1,223 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>CosNotifyFilter_Filter</title>
- <prepared></prepared>
- <docno></docno>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosNotifyFilter_Filter</module>
- <modulesummary>This module implements the OMG CosNotifyFilter::Filter interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosNotification/include/*.hrl").</c></p>
- </description>
- <funcs>
- <func>
- <name>_get_constraint_grammar(Filter) -> Grammar</name>
- <fsummary>Return which type of Grammar the Filter uses</fsummary>
- <type>
- <v>Filter = #objref</v>
- <v>Grammar = string()</v>
- </type>
- <desc>
- <p>This operation returns which type of Grammar the Filter uses. Currently, only <c>"EXTENDED_TCL"</c> is supported.</p>
- </desc>
- </func>
- <func>
- <name>add_constraints(Filter, ConstraintExpSeq) -> Reply</name>
- <fsummary>Add new constraints to the filter</fsummary>
- <type>
- <v>Filter = #objref</v>
- <v>ConstraintExpSeq = [Constraint]</v>
- <v>ConstraintExp = #'CosNotifyFilter_ConstraintExp'{event_types, constraint_expr}</v>
- <v>event_types = #'CosNotification_EventTypeSeq'{}</v>
- <v>constraint_expr = string()</v>
- <v>Reply = ConstraintInfoSeq | {'EXCEPTION', #'CosNotifyFilter_InvalidConstraint'{constr}}</v>
- <v>constr = ConstraintExp</v>
- <v>ConstraintInfoSeq = [ConstraintInfo]</v>
- <v>ConstraintInfo = #'CosNotifyFilter_ConstraintInfo'{constraint_expression, constraint_id}</v>
- <v>constraint_expression = ConstraintExp</v>
- <v>constraint_id = long()</v>
- </type>
- <desc>
- <p>Initially, Filters do not contain any constraints, hence, all events will be forwarded.
- The <c>add_constraints/2</c> operation allow us to add constraints to the target object.</p>
- </desc>
- </func>
- <func>
- <name>modify_constraints(Filter, ConstraintIDSeq, ConstraintInfoSeq) -> Reply</name>
- <fsummary>Modify existing constraints</fsummary>
- <type>
- <v>Filter = #objref</v>
- <v>ConstraintIDSeq = [ConstraintID]</v>
- <v>ConstraintID = long()</v>
- <v>ConstraintInfoSeq = [ConstraintInfo]</v>
- <v>ConstraintInfo = #'CosNotifyFilter_ConstraintInfo'{constraint_expression, constraint_id}</v>
- <v>constraint_expression = ConstraintExp</v>
- <v>constraint_id = long()</v>
- <v>Reply = ok | {'EXCEPTION', #'CosNotifyFilter_InvalidConstraint'{constr}} | {'EXCEPTION', #'CosNotifyFilter_ConstraintNotFound'{id}}</v>
- <v>constr = ConstraintExp</v>
- <v>id = long()</v>
- <v>ConstraintExp = #'CosNotifyFilter_ConstraintExp'{event_types, constraint_expr}</v>
- <v>event_types = #'CosNotification_EventTypeSeq'{}</v>
- <v>constraint_expr = string()</v>
- </type>
- <desc>
- <p>This operation is invoked by a client in order to modify the constraints associated
- with the target object. The constraints related to the Id's in the parameter sequence
- <c>ConstraintIDSeq</c> will, if all values are valid, be deleted. The <c>ConstraintInfoSeq</c>
- parameter contains of Id-Expression pairs and a constraint matching one of the unique
- Id's will, if all input values are correct, be updated. If the parameters contain incorrect
- data en exception will be raised.</p>
- </desc>
- </func>
- <func>
- <name>get_constraints(Filter, ConstraintIDSeq) -> Reply</name>
- <fsummary>Return all constraints which match the supplied Ids</fsummary>
- <type>
- <v>Filter = #objref</v>
- <v>ConstraintIDSeq = [ConstraintID]</v>
- <v>ConstraintID = long()</v>
- <v>Reply = ConstraintInfoSeq | {'EXCEPTION', #'CosNotifyFilter_ConstraintNotFound'{id}}</v>
- <v>ConstraintInfoSeq = [ConstraintInfo]</v>
- <v>ConstraintInfo = #'CosNotifyFilter_ConstraintInfo'{constraint_expression, constraint_id}</v>
- <v>constraint_expression = ConstraintExp</v>
- <v>constraint_id = id = long()</v>
- </type>
- <desc>
- <p>This operation return a sequence of ConstraintInfo's, related to the given ConstraintID's,
- associated with the target object.</p>
- </desc>
- </func>
- <func>
- <name>get_all_constraints(Filter) -> ConstraintInfoSeq</name>
- <fsummary>Return all constraints associated with the target object</fsummary>
- <type>
- <v>Filter = #objref</v>
- <v>ConstraintInfoSeq = [ConstraintInfo]</v>
- <v>ConstraintInfo = #'CosNotifyFilter_ConstraintInfo'{constraint_expression, constraint_id}</v>
- <v>constraint_expression = ConstraintExp</v>
- <v>constraint_id = long()</v>
- </type>
- <desc>
- <p>All constraints, and their unique Id, associated with the target object will be returned by this operation.</p>
- </desc>
- </func>
- <func>
- <name>remove_all_constraints(Filter) -> ok</name>
- <fsummary>Remove all constraints associated with the target object</fsummary>
- <type>
- <v>Filter = #objref</v>
- </type>
- <desc>
- <p>All constraints associated with the target object are removed by this operation and, since
- the the target object no longer contain any constraints, true will always be the result of
- any match operation.</p>
- </desc>
- </func>
- <func>
- <name>destroy(Filter) -> ok</name>
- <fsummary>Terminate the target object</fsummary>
- <type>
- <v>Filter = #objref</v>
- </type>
- <desc>
- <p>This operation terminates the target object.</p>
- </desc>
- </func>
- <func>
- <name>match(Filter, Event) -> Reply</name>
- <fsummary>Match the Any event if it satisfies at least one constraint</fsummary>
- <type>
- <v>Filter = #objref</v>
- <v>Event = #any</v>
- <v>Reply = boolean() | {'EXCEPTION', #'CosNotifyFilter_UnsupportedFilterableData'{}}</v>
- </type>
- <desc>
- <p>This operation accepts an <c>#any{}</c> event and returns <c>true</c> if it satisfies
- at least one constraint. If the event contains data of the wrong type, e.g., should be
- a string() but in fact i a short(), an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>match_structured(Filter, Event) -> Reply</name>
- <fsummary>Match the structured event if it satisfies at least one constraint</fsummary>
- <type>
- <v>Filter = #objref</v>
- <v>Event = #'CosNotification_StructuredEvent'{}</v>
- <v>Reply = boolean() | {'EXCEPTION', #'CosNotifyFilter_UnsupportedFilterableData'{}}</v>
- </type>
- <desc>
- <p>This operation is similar to the <c>match</c> operation but accepts structured
- events instead.</p>
- </desc>
- </func>
- <func>
- <name>attach_callback(Filter, NotifySubscribe) -> CallbackID</name>
- <fsummary>Connect NotifySubscribe object, which should be informed when the target object's constraints are updated</fsummary>
- <type>
- <v>Filter = #objref</v>
- <v>NotifySubscribe = #objref</v>
- <v>CallbackID = long()</v>
- </type>
- <desc>
- <p>This operation connects a NotifySubscribe object, which should be informed
- when the target object's constraints are updated. A unique Id is returned
- which must be stored if we ever want to detach the callback object in the future.</p>
- </desc>
- </func>
- <func>
- <name>detach_callback(Filter, CallbackID) -> Reply</name>
- <fsummary>Disconnect the NotifySubscribe object with the given Id</fsummary>
- <type>
- <v>Filter = #objref</v>
- <v>CallbackID = long()</v>
- <v>Reply = ok | {'EXCEPTION', #'CosNotifyFilter_CallbackNotFound'{}}</v>
- </type>
- <desc>
- <p>If the target object has an associated callback that matches the supplied
- Id it will be removed and longer informed of any updates. If no object
- with a matching Id is found an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>get_callbacks(Filter) -> CallbackIDSeq</name>
- <fsummary>Return all NotifySubscribe Id's associated with the target object</fsummary>
- <type>
- <v>Filter = #objref</v>
- <v>CallbackIDSeq = [CallbackID]</v>
- <v>CallbackID = long()</v>
- </type>
- <desc>
- <p>This operation returns a sequence of all connected NotifySubscribe object Id's.
- If no callbacks are associated with the target object the list will be empty.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosNotification/doc/src/CosNotifyFilter_FilterAdmin.xml b/lib/cosNotification/doc/src/CosNotifyFilter_FilterAdmin.xml
deleted file mode 100644
index 5cb56963f1..0000000000
--- a/lib/cosNotification/doc/src/CosNotifyFilter_FilterAdmin.xml
+++ /dev/null
@@ -1,112 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosNotifyFilter_FilterAdmin</title>
- <prepared>Niclas Eklund</prepared>
- <responsible>Niclas Eklund</responsible>
- <docno></docno>
- <approved>Niclas Eklund</approved>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosNotifyFilter_FilterAdmin</module>
- <modulesummary>This module implements the OMG CosNotifyFilter::FilterAdmin interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosNotification/include/*.hrl").</c></p>
- <p>All objects, which inherit this interface, export functions described in this module.</p>
- </description>
- <funcs>
- <func>
- <name>add_filter(Object, Filter) -> FilterID</name>
- <fsummary>Add a new filter to the target object</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>Filter = #objref</v>
- <v>FilterID = long()</v>
- </type>
- <desc>
- <p>This operation connects a new <c>Filter</c> to the target object. This <c>Filter</c> will, together
- with other associated <c>Filters</c>, be used to select events to forward. A unique Id is
- returned and should be used if we no longer want to consult the given <c>Filter</c>.</p>
- </desc>
- </func>
- <func>
- <name>remove_filter(Object, FilterID) -> ok</name>
- <fsummary>Remove a filter associated with the target object</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>FilterID = long()</v>
- </type>
- <desc>
- <p>If a certain <c>Filter</c> no longer should be associated with the target object
- this operation must be used. Events will no longer be tested against the <c>Filter</c>
- associated with the given Id.</p>
- </desc>
- </func>
- <func>
- <name>get_filter(Object, FilterID) -> Reply</name>
- <fsummary>Return the filter with the given Id</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>FilterID = long()</v>
- <v>Reply = Filter | {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}}</v>
- <v>Filter = #objref</v>
- </type>
- <desc>
- <p>If the target object is associated with a <c>Filter</c> matching the given Id the
- reference will be returned. If no such <c>Filter</c> is known by the target object
- an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>get_all_filters(Object) -> FilterIDSeq</name>
- <fsummary>Return a list of all filter Id:s associated with the target object</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>FilterIDSeq = [FilterID]</v>
- <v>FilterID = long()</v>
- </type>
- <desc>
- <p>Id's for all <c>Filter</c> objects associated with the target object is
- returned by this operation.</p>
- </desc>
- </func>
- <func>
- <name>remove_all_filters(Object) -> ok</name>
- <fsummary>Remove all filters from the target object</fsummary>
- <type>
- <v>Object = #objref</v>
- </type>
- <desc>
- <p>If we want to remove all <c>Filters</c> associated with the target object we can use this function.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosNotification/doc/src/CosNotifyFilter_FilterFactory.xml b/lib/cosNotification/doc/src/CosNotifyFilter_FilterFactory.xml
deleted file mode 100644
index adacbc3281..0000000000
--- a/lib/cosNotification/doc/src/CosNotifyFilter_FilterFactory.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosNotifyFilter_FilterFactory</title>
- <prepared>Niclas Eklund</prepared>
- <responsible>Niclas Eklund</responsible>
- <docno></docno>
- <approved>Niclas Eklund</approved>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosNotifyFilter_FilterFactory</module>
- <modulesummary>This module implements the OMG CosNotifyFilter::FilterFactory interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosNotification/include/*.hrl").</c></p>
- </description>
- <funcs>
- <func>
- <name>create_filter(FilterFactory, Grammar) -> Reply</name>
- <fsummary>Create a <c>Filter</c>object</fsummary>
- <type>
- <v>FilterFactory = #objref</v>
- <v>Grammar = string()</v>
- <v>Reply = Filter | {'EXCEPTION', #'CosNotifyFilter_InvalidGrammar'{}}</v>
- <v>Filter = #objref</v>
- </type>
- <desc>
- <p>This operation creates a new Filter object, under the condition
- that Grammar given is supported. Currently, only <c>"EXTENDED_TCL"</c> is supported.</p>
- </desc>
- </func>
- <func>
- <name>create_mapping_filter(FilterFactory, Grammar) -> Reply</name>
- <fsummary>Create a <c>MappingFilter</c>object</fsummary>
- <type>
- <v>FilterFactory = #objref</v>
- <v>Grammar = string()</v>
- <v>Reply = MappingFilter | {'EXCEPTION', #'CosNotifyFilter_InvalidGrammar'{}}</v>
- <v>Filter = #objref</v>
- </type>
- <desc>
- <p>This operation creates a new MappingFilter object, under the condition
- that Grammar given is supported. Currently, only <c>"EXTENDED_TCL"</c> is supported.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosNotification/doc/src/CosNotifyFilter_MappingFilter.xml b/lib/cosNotification/doc/src/CosNotifyFilter_MappingFilter.xml
deleted file mode 100644
index c0db8c1ae0..0000000000
--- a/lib/cosNotification/doc/src/CosNotifyFilter_MappingFilter.xml
+++ /dev/null
@@ -1,228 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>CosNotifyFilter_MappingFilter</title>
- <prepared></prepared>
- <docno></docno>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosNotifyFilter_MappingFilter</module>
- <modulesummary>This module implements the OMG CosNotifyFilter::MappingFilter interface.</modulesummary>
- <description>
- <p>The main purpose of this module is to match events against associated
- constraints and return the value for the first constraint that returns
- true for the given event. If all constraints return false the default value
- will be returned.</p>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosNotification/include/*.hrl").</c></p>
- </description>
- <funcs>
- <func>
- <name>_get_constraint_grammar(MappingFilter) -> Grammar</name>
- <fsummary>Return which type of Grammar the MappingFilter uses</fsummary>
- <type>
- <v>MappingFilter = #objref</v>
- <v>Grammar = string()</v>
- </type>
- <desc>
- <p>This operation returns which type of Grammar the MappingFilter uses.
- Currently, only <c>"EXTENDED_TCL"</c> is supported.</p>
- </desc>
- </func>
- <func>
- <name>_get_value_type(MappingFilter) -> CORBA::TypeCode</name>
- <fsummary>Return the <c>CORBA::TypeCode</c>of the default value associated with the target object</fsummary>
- <type>
- <v>MappingFilter = #objref</v>
- </type>
- <desc>
- <p>This readonly attribute maintains the <c>CORBA::TypeCode</c> of the default value
- associated with the target object.</p>
- </desc>
- </func>
- <func>
- <name>_get_default_value(MappingFilter) -> #any</name>
- <fsummary>Return the <c>#any{}</c> default value associated with the target object</fsummary>
- <type>
- <v>MappingFilter = #objref</v>
- </type>
- <desc>
- <p>This readonly attribute maintains the <c>#any{}</c> default value associated with
- the target object.</p>
- </desc>
- </func>
- <func>
- <name>add_mapping_constraints(MappingFilter, MappingConstraintPairSeq) -> Reply</name>
- <fsummary>Add new mapping constraints</fsummary>
- <type>
- <v>MappingFilter = #objref</v>
- <v>MappingConstraintPairSeq = [MappingConstraintPair]</v>
- <v>MappingConstraintPair = #'CosNotifyFilter_MappingConstraintPair'{constraint_expression, result_to_set}</v>
- <v>constraint_expression = #'CosNotifyFilter_ConstraintExp'{event_types, constraint_expr}</v>
- <v>event_types = #'CosNotification_EventTypeSeq'{}</v>
- <v>constraint_expr = string()</v>
- <v>result_to_set = #any</v>
- <v>Reply = MappingConstraintInfoSeq | {'EXCEPTION', #'CosNotifyFilter_InvalidConstraint'{constr}} | {'EXCEPTION', #'CosNotifyFilter_InvalidValue'{constr, value}}</v>
- <v>constr = ConstraintExp</v>
- <v>ConstraintExp = #'CosNotifyFilter_ConstraintExp'{event_types, constraint_expr}</v>
- <v>event_types = #'CosNotification_EventTypeSeq'{}</v>
- <v>constraint_expr = string()</v>
- <v>MappingConstraintInfoSeq = [MappingConstraintInfo]</v>
- <v>MappingConstraintInfo = #'CosNotifyFilter_MappingConstraintInfo'{constraint_expression, constraint_id, value}</v>
- <v>constraint_expression = ConstraintExp</v>
- <v>constraint_id = long()</v>
- <v>value = #any</v>
- </type>
- <desc>
- <p>This operation add new mapping constraints, which will be used when trying to override
- Quality of Service settings defined in the given event. If a constraint return true the
- associated value will be returned, otherwise the default value.</p>
- </desc>
- </func>
- <func>
- <name>modify_constraints(MappingFilter, ConstraintIDSeq, MappingConstraintInfoSeq) -> Reply</name>
- <fsummary>Modify the constraints associated with the target object</fsummary>
- <type>
- <v>MappingFilter = #objref</v>
- <v>ConstraintIDSeq = [ConstraintID]</v>
- <v>ConstraintID = long()</v>
- <v>MappingConstraintInfoSeq = [MappingConstraintInfo]</v>
- <v>MappingConstraintInfo = #'CosNotifyFilter_MappingConstraintInfo'{constraint_expression, constraint_id, value}</v>
- <v>constraint_expression = ConstraintExp</v>
- <v>constraint_id = long()</v>
- <v>value = #any</v>
- <v>ConstraintInfoSeq = [ConstraintInfo]</v>
- <v>ConstraintInfo = #'CosNotifyFilter_ConstraintInfo'{constraint_expression, constraint_id}</v>
- <v>constraint_expression = ConstraintExp</v>
- <v>constraint_id = long()</v>
- <v>Reply = ok | {'EXCEPTION', #'CosNotifyFilter_InvalidConstraint'{constr}} | {'EXCEPTION', #'CosNotifyFilter_ConstraintNotFound'{id}} | {'EXCEPTION', #'CosNotifyFilter_InvalidValue'{constr, value}}</v>
- <v>constr = ConstraintExp</v>
- <v>id = long()</v>
- <v>value = #any</v>
- <v>ConstraintExp = #'CosNotifyFilter_ConstraintExp'{event_types, constraint_expr}</v>
- <v>event_types = #'CosNotification_EventTypeSeq'{}</v>
- <v>constraint_expr = string()</v>
- </type>
- <desc>
- <p>The <c>ConstraintIDSeq</c> supplied should relate to constraints the caller wishes to
- remove. If any of the supplied Id's are not found an exception will be raised. This
- operation also accepts a sequence of <c>MappingConstraintInfo</c> which will be added.
- If the target object cannot modify the constraints as requested an exception is raised
- describing which constraint, and why, could not be updated.</p>
- </desc>
- </func>
- <func>
- <name>get_mapping_constraints(MappingFilter, ConstraintIDSeq) -> Reply</name>
- <fsummary>Return the target object's associated constraints with given ID:s</fsummary>
- <type>
- <v>MappingFilter = #objref</v>
- <v>ConstraintIDSeq = [ConstraintID]</v>
- <v>ConstraintID = long()</v>
- <v>Reply = MappingConstraintInfoSeq | {'EXCEPTION', #'CosNotifyFilter_ConstraintNotFound'{id}}</v>
- <v>MappingConstraintInfoSeq = [MappingConstraintInfo]</v>
- <v>MappingConstraintInfo = #'CosNotifyFilter_MappingConstraintInfo'{constraint_expression, constraint_id, value}</v>
- <v>constraint_expression = ConstraintExp</v>
- <v>ConstraintExp = #'CosNotifyFilter_ConstraintExp'{event_types, constraint_expr}</v>
- <v>event_types = #'CosNotification_EventTypeSeq'{}</v>
- <v>constraint_expr = string()</v>
- <v>constraint_id = id = long()</v>
- <v>value = #any</v>
- </type>
- <desc>
- <p>When adding a new constraint a unique Id is returned, which is accepted as input for this
- operation. The associated constraint is returned, but if no such Id exists an exception is raised. </p>
- </desc>
- </func>
- <func>
- <name>get_all_mapping_constraints(MappingFilter) -> MappingConstraintInfoSeq</name>
- <fsummary>Return the target object's all associated constraints</fsummary>
- <type>
- <v>MappingFilter = #objref</v>
- <v>MappingConstraintInfoSeq = [MappingConstraintInfo]</v>
- <v>MappingConstraintInfo = #'CosNotifyFilter_MappingConstraintInfo'{constraint_expression, constraint_id, value}</v>
- <v>constraint_expression = ConstraintExp</v>
- <v>ConstraintExp = #'CosNotifyFilter_ConstraintExp'{event_types, constraint_expr}</v>
- <v>event_types = #'CosNotification_EventTypeSeq'{}</v>
- <v>constraint_expr = string()</v>
- <v>constraint_id = long()</v>
- <v>value = #any</v>
- </type>
- <desc>
- <p>This operation returns a sequence of all unique Id's associated with the target object.
- If no constraint have been added the sequence will be empty.</p>
- </desc>
- </func>
- <func>
- <name>remove_all_mapping_constraints(MappingFilter) -> ok</name>
- <fsummary>Remove all constraints associated with the target object</fsummary>
- <type>
- <v>MappingFilter = #objref</v>
- </type>
- <desc>
- <p>This operation removes all constraints associated with the target object.</p>
- </desc>
- </func>
- <func>
- <name>destroy(MappingFilter) -> ok</name>
- <fsummary>Terminate the target object</fsummary>
- <type>
- <v>MappingFilter = #objref</v>
- </type>
- <desc>
- <p>This operation terminates the target object. Remember to remove
- this Filter from the objects it have been associated with.</p>
- </desc>
- </func>
- <func>
- <name>match(MappingFilter, Event) -> Reply</name>
- <fsummary>Evaluate the given Any event with the Filter's constraints</fsummary>
- <type>
- <v>MappingFilter = #objref</v>
- <v>Event = #any</v>
- <v>Reply = {boolean(), #any} | {'EXCEPTION', #'CosNotifyFilter_UnsupportedFilterableData'{}}</v>
- </type>
- <desc>
- <p>This operation evaluates <c>Any</c> events with the Filter's constraints,
- and returns the value to use. The value is the default value if all constraints
- returns false and the value associated with the first constraint returning true.</p>
- </desc>
- </func>
- <func>
- <name>match_structured(MappingFilter, Event) -> Reply</name>
- <fsummary>Evaluate the given structured event with the Filter's constraints</fsummary>
- <type>
- <v>MappingFilter = #objref</v>
- <v>Event = #'CosNotification_StructuredEvent'{}</v>
- <v>Reply = {boolean(), #any} | {'EXCEPTION', #'CosNotifyFilter_UnsupportedFilterableData'{}}</v>
- </type>
- <desc>
- <p>Similar to <c>match/2</c> but accepts a structured event as input.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosNotification/doc/src/Makefile b/lib/cosNotification/doc/src/Makefile
deleted file mode 100644
index 43ed8294c4..0000000000
--- a/lib/cosNotification/doc/src/Makefile
+++ /dev/null
@@ -1,167 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2000-2017. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../../vsn.mk
-VSN=$(COSNOTIFICATION_VSN)
-APPLICATION=cosNotification
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-XML_APPLICATION_FILES = ref_man.xml
-XML_REF3_FILES = \
- cosNotificationApp.xml \
- CosNotifyChannelAdmin_EventChannelFactory.xml \
- CosNotifyChannelAdmin_EventChannel.xml \
- CosNotification.xml \
- CosNotification_QoSAdmin.xml \
- CosNotification_AdminPropertiesAdmin.xml \
- CosNotifyChannelAdmin_ConsumerAdmin.xml \
- CosNotifyChannelAdmin_SupplierAdmin.xml \
- CosNotifyComm_NotifyPublish.xml \
- CosNotifyComm_NotifySubscribe.xml \
- CosNotifyFilter_FilterAdmin.xml \
- CosNotifyFilter_FilterFactory.xml \
- CosNotifyFilter_Filter.xml \
- CosNotifyFilter_MappingFilter.xml \
- CosNotifyChannelAdmin_ProxyConsumer.xml \
- CosNotifyChannelAdmin_ProxySupplier.xml \
- CosNotifyChannelAdmin_ProxyPullConsumer.xml \
- CosNotifyChannelAdmin_ProxyPullSupplier.xml \
- CosNotifyChannelAdmin_ProxyPushConsumer.xml \
- CosNotifyChannelAdmin_ProxyPushSupplier.xml \
- CosNotifyChannelAdmin_SequenceProxyPullConsumer.xml \
- CosNotifyChannelAdmin_SequenceProxyPullSupplier.xml \
- CosNotifyChannelAdmin_SequenceProxyPushConsumer.xml \
- CosNotifyChannelAdmin_SequenceProxyPushSupplier.xml \
- CosNotifyChannelAdmin_StructuredProxyPullConsumer.xml \
- CosNotifyChannelAdmin_StructuredProxyPullSupplier.xml \
- CosNotifyChannelAdmin_StructuredProxyPushConsumer.xml \
- CosNotifyChannelAdmin_StructuredProxyPushSupplier.xml \
-
-
-
-XML_PART_FILES = \
- part.xml
-XML_CHAPTER_FILES = \
- ch_contents.xml \
- ch_introduction.xml \
- ch_install.xml \
- ch_system.xml \
- ch_BNF.xml \
- ch_QoS.xml \
- ch_example.xml \
- notes.xml
-
-BOOK_FILES = book.xml
-
-XML_FILES = $(BOOK_FILES) $(XML_APPLICATION_FILES) $(XML_REF3_FILES) \
- $(XML_PART_FILES) $(XML_CHAPTER_FILES)
-
-TECHNICAL_DESCR_FILES =
-
-GIF_FILES = \
- eventstructure.gif \
- notificationFlow.gif
-
-PS_FILES =
-
-# ----------------------------------------------------
-
-INTERNAL_HTML_FILES = $(TECHNICAL_DESCR_FILES:%.xml=$(HTMLDIR)/%.html)
-
-HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \
- $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html)
-
-INFO_FILE = ../../info
-EXTRA_FILES = \
- $(DEFAULT_GIF_FILES) \
- $(DEFAULT_HTML_FILES) \
- $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html) \
- $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html)
-
-MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-
-HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
-
-TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-XML_FLAGS +=
-DVIPS_FLAGS +=
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-$(HTMLDIR)/%.gif: %.gif
- $(INSTALL_DATA) $< $@
-
-docs: pdf html man
-
-$(TOP_PDF_FILE): $(XML_FILES)
-
-pdf: $(TOP_PDF_FILE)
-
-html: gifs $(HTML_REF_MAN_FILE)
-
-clean clean_docs:
- rm -rf $(HTMLDIR)/*
- rm -f $(MAN3DIR)/*
- rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
- rm -f errs core *~
-
-man: $(MAN3_FILES)
-
-gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
-
-$(INDEX_TARGET): $(INDEX_SRC)
- sed -e 's;%VSN%;$(VSN);' $(INDEX_SRC) > $(INDEX_TARGET)
-
-debug opt:
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_docs_spec: docs
- $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
- $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
- $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
- $(INSTALL_DATA) $(HTMLDIR)/* \
- "$(RELSYSDIR)/doc/html"
- $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
- $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
- $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
-
-release_spec:
diff --git a/lib/cosNotification/doc/src/book.xml b/lib/cosNotification/doc/src/book.xml
deleted file mode 100644
index 3151abceaa..0000000000
--- a/lib/cosNotification/doc/src/book.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE book SYSTEM "book.dtd">
-
-<book xmlns:xi="http://www.w3.org/2001/XInclude">
- <header titlestyle="normal">
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosNotification</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2000-01-31</date>
- <rev>1.0</rev>
- </header>
- <insidecover>
- </insidecover>
- <pagetext>cosNotification</pagetext>
- <preamble>
- <contents level="2"></contents>
- </preamble>
- <parts lift="no">
- <xi:include href="part.xml"/>
- </parts>
- <applications>
- <xi:include href="ref_man.xml"/>
- </applications>
- <releasenotes>
- <xi:include href="notes.xml"/>
- </releasenotes>
- <listofterms></listofterms>
- <index></index>
-</book>
-
diff --git a/lib/cosNotification/doc/src/ch_BNF.xml b/lib/cosNotification/doc/src/ch_BNF.xml
deleted file mode 100644
index 9763c0c4ca..0000000000
--- a/lib/cosNotification/doc/src/ch_BNF.xml
+++ /dev/null
@@ -1,457 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Filters and the Constraint Language BNF</title>
- <prepared></prepared>
- <docno></docno>
- <date>2000-04-13</date>
- <rev></rev>
- <file>ch_BNF.xml</file>
- </header>
-
- <section>
- <title>Filters and the Constraint Language BNF</title>
- <p>This chapter describes, the grammar supported by
- <seealso marker="CosNotifyFilter_Filter">CosNotifyFilter_Filter</seealso> and
- <seealso marker="CosNotifyFilter_MappingFilter">CosNotifyFilter_MappingFilter</seealso>,
- and how to create and use filter objects.
- </p>
-
- <section>
- <title>How to create filter objects</title>
- <p>To be able to filter events we must create a filter and associate
- it with one, or more, of the administrative or proxy objects. In the example
- below, we choose to associate the filter with a ConsumerAdmin object.</p>
- <code type="none">
-FilterFactory = cosNotificationApp:start_filter_factory(),
-Filter = 'CosNotifyFilter_FilterFactory':
- create_filter(FilterFactory,"EXTENDED_TCL"),
-ConstraintInfoSeq = 'CosNotifyFilter_Filter':
- add_constraints(Filter, ConstraintExpSeq),
-FilterID = 'CosNotifyChannelAdmin_ConsumerAdmin':
- add_filter(AdminConsumer, Filter),
- </code>
- <p><c>"EXTENDED_TCL"</c> is the only grammar supported by Orber Notification
- Service.</p>
- <p>Depending on which operation type the Admin object uses, i.e.,
- <c>'AND_OP'</c> or <c>'OR_OP'</c>, events will be tested using the
- associated filter. The operation properties are:</p>
- <p></p>
- <list type="bulleted">
- <item>
- <p>'AND_OP' - must be approved by the proxy's <em>and</em> its parent admin's
- filters. If all filters associated with an object (Admin or Proxy)
- return false the event will be discarded. In this situation it is pointless
- to try and verify with the other object's associated filters since the outcome
- still would be the same.</p>
- </item>
- <item>
- <p>'OR_OP' - if one of the object's (Admin or Proxy) filters return true, the event
- will not be checked against any other filter associated with a proxy or its
- parent admin. If a object's associated filters all return false,
- the event will be forwarded to related proxies/admins, and
- tested against any associated filters.</p>
- </item>
- </list>
- <p>Initially, filters are empty and will always return true. Hence, we must
- add constraints by using <c>'CosNotifyFilter_Filter':add_constraints/2</c>.
- As input, the second argument must be a sequence of:</p>
- <code type="none">
-#'CosNotifyFilter_ConstraintExp'{
- event_types = [#'CosNotification_EventType'{
- domain_name = string(),
- type_name = string()}],
- constraint_expr = string()}
- </code>
- <p>The <c>event_types</c> describes which types of events that should be matched using
- the associated <c>constraint_expr</c>.</p>
- <p>If a constraint expression is supposed to apply for all events, then the <c>type_name</c> can
- be set to the special event type <c>%ALL</c> in a constraint's event type sequence. The
- <c>domain_name</c> should be <c>""</c> or <c>"*"</c>.</p>
- <p>In the following sections we will take a closer look on how to write
- constraint expressions.</p>
- </section>
-
- <section>
- <title>The CosNotification Constraint Language</title>
- <p>The constraint language supported by the Notification Service is:</p>
- <code type="none"><![CDATA[
-<constraint> := /* empty */
- | <bool>
-
-<bool> := <bool_or>
-
-<bool_or> := <bool_or> or <bool_and>
- | <bool_and>
-
-<bool_and> := <bool_and> and <bool_compare>
- | <bool_compare>
-
-<bool_compare> := <expr_in> == <expr_in>
- | <expr_in> != <expr_in>
- | <expr_in> < <expr_in>
- | <expr_in> <= <expr_in>
- | <expr_in> > <expr_in>
- | <expr_in> >= <expr_in>
- | <expr_in>
-
-<expr_in> := <expr_twiddle> in <Ident> /* sequence only */
- | <expr_twiddle>
- | <expr_twiddle> in $ <Component> /* sequence only */
-
-<expr_twiddle> := <expr> ~ <expr> /* string data types only */
- | <expr>
-
-<expr> := <expr> + <term>
- | <expr> - <term>
- | <term>
-
-<term> := <term> * <factor_not>
- | <term> / <factor_not>
- | <factor_not>
-
-<factor_not> := not <factor>
- | <factor>
-
-<factor> := ( <bool_or> )
- | exist <Ident>
- | <Ident>
- | <Number>
- | - <Number>
- | <String>
- | TRUE
- | FALSE
- | + <Number>
- | exist $ <Component>
- | $ <Component>
- | default $ <Component> /* discriminated unions only */
-
-<Component> := /* empty */
- | . <CompDot>
- | <CompArray>
- | <CompAssoc>
- | <Ident> <CompExt> /* run-time variable */
-
-<CompExt> := /* empty */
- | . <CompDot>
- | <CompArray>
- | <CompAssoc>
-
-<CompDot> := <Ident> <CompExt>
- | <CompPos>
- | <UnionPos>
- | _length /* only valid for arrays or sequences */
- | _d /* discriminated unions only */
- | _type_id /* only valid if possible to obtain */
- | _repos_id /* only valid if possible to obtain */
-
-<CompArray> := [ <Digits> ] <CompExt>
-
-<CompAssoc> := ( <Ident> ) <CompExt>
-
-<CompPos> := <Digits> <CompExt>
-
-<UnionPos> := ( <UnionVal> ) <CompExt>
-
-<UnionVal> := /* empty */
- | <Digits>
- | - <Digits>
- | + <Digits>
- | <String>
-
-/* Character set issues */
-<Ident> :=<Leader> <FollowSeq>
- | \ < Leader> <FollowSeq>
-
-<FollowSeq> := /* <empty> */
- | <FollowSeq> <Follow>
-
-<Number> := <Mantissa>
- | <Mantissa> <Exponent>
-
-<Mantissa> := <Digits>
- | <Digits> .
- | . <Digits>
- | <Digits> . <Digits>
-
-<Exponent> := <Exp> <Sign> <Digits>
-
-<Sign> := +
- | -
-
-<Exp> := E
- | e
-
-<Digits> := <Digits> <Digit>
- | <Digit>
-
-<String> := ' <TextChars> '
-
-<TextChars> := /* <empty> */
- | <TextChars> <TextChar>
-
-<TextChar> := <Alpha>
- | <Digit>
- | <Other>
- | <Special>
-
-<Special> := \\
- | \'
-
-<Leader> := <Alpha>
-
-<Follow> := <Alpha>
- | <Digit>
- | _
-
-<Alpha> is the set of alphabetic characters [A-Za-z]
-<Digit> is the set of digits [0-9]
-<Other> is the set of ASCII characters that are not <Alpha>, <Digit>, or <Special>
- ]]></code>
- <p>In the absence of parentheses, the following precedence relations hold :</p>
- <list type="ordered">
- <item><c>()</c>, <c>exist</c>, <c>default</c>, <c>unary-sign</c></item>
- <item><c>not</c></item>
- <item><c>*</c>, <c>/</c></item>
- <item><c>+</c>, <c>-</c></item>
- <item><c>~</c></item>
- <item><c>in</c></item>
- <item><c>==</c>, <c>!=</c>, <c><![CDATA[<]]></c>, <c><![CDATA[<=]]></c>, <c>></c>, <c>>=</c></item>
- <item><c>and</c></item>
- <item><c>or</c></item>
- </list>
- </section>
-
- <section>
- <title>The Constraint Language Data Types</title>
- <p>The Notification Service Constraint Language, defines how to write
- constraint expressions, which can be used to filter events. The
- representation does, however, differ slightly from ordinary Erlang terms.</p>
- <p>When creating a <c>ConstraintExp</c>, the field <c>constraint_expr</c> must be
- set to contain a string, e.g., <c><![CDATA["1 < 2"]]></c>. The Notification Service Constraint
- Language, is designed to be able to filter structured and unstructured events
- using the same constraint expression. The Constraint Language Types and Operations
- can be divided into two sub-groups:</p>
- <list type="bulleted">
- <item>
- <p>Basic - arithmetics, strings, constants, numbers etc.</p>
- </item>
- <item>
- <p>Complex - accessing members of complex data types, such as unions.</p>
- </item>
- </list>
- <p>Some of the basic types, e.g., integer, are self explanatory. Hence, they are not described further.</p>
- <table>
- <row>
- <cell align="center" valign="middle"><em>Type/Operation</em></cell>
- <cell align="center" valign="middle"><em>Examples</em></cell>
- <cell align="center" valign="middle"><em>Description</em></cell>
- </row>
- <row>
- <cell align="left" valign="middle"><c>string</c></cell>
- <cell align="left" valign="middle"><c>"'MyString'"</c></cell>
- <cell align="left" valign="middle">Strings are represented as a sequence of zero or more <c><![CDATA[<TextChar>]]></c>s enclosed in single quotes, e.g., <c>'string'</c>.</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><c>~</c></cell>
- <cell align="left" valign="middle"><c>"'Sring1' ~ 'String2'"</c></cell>
- <cell align="left" valign="middle">The operator <c>~</c>is called the substring operator and mean "String1 is contained within String2".</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><c>boolean</c></cell>
- <cell align="left" valign="middle"><c>"TRUE == (('lang' ~ 'Erlang' + 'fun' ~ 'functional') >= 2)"</c></cell>
- <cell align="left" valign="middle">Booleans may only be TRUE or FALSE, i.e., only capital letters. Expressions which evaluate to TRUE or FALSE can be summed up and matched, where TRUE equals 1 and FALSE 0.</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><c>sequence</c></cell>
- <cell align="left" valign="middle"><c>"myIntegerSequence[2]"</c></cell>
- <cell align="left" valign="middle">The BNF use C/C++ notation, i.e., the example will return the <em>third</em>element.</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><c>_length</c></cell>
- <cell align="left" valign="middle"><c>"myIntegerSequence._length"</c></cell>
- <cell align="left" valign="middle">Returns the length of an sequence or array.</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><c>in</c></cell>
- <cell align="left" valign="middle"><c>"'Erlang' in $.FunctionalLanguagesStringSeq"</c></cell>
- <cell align="left" valign="middle">Returns <c>TRUE</c>if a given element is found in the given sequence. The element must be of a simple type and the same as the sequence is defined to contain.</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><c>$</c></cell>
- <cell align="left" valign="middle"><c>"$ == 40"</c></cell>
- <cell align="left" valign="middle">Denote the current event as well as any run-time variables. If the event is unstructured and its contained value 40, the example will return <c>TRUE</c>.</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><c>.</c></cell>
- <cell align="left" valign="middle"><c>"$.MyStructMember == 40"</c></cell>
- <cell align="left" valign="middle">The structure member operator <c>.</c>may be used to reference its members when the data refers to a named structure, discriminated union, or CORBA::Any data structure.</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><c>_type_id</c></cell>
- <cell align="left" valign="middle"><c>"$._type_id == 'MyStruct'"</c></cell>
- <cell align="left" valign="middle">Returns the unscoped IDL type name of the component. This operation is only valid if said information can be obtained.</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><c>_repos_id</c></cell>
- <cell align="left" valign="middle"><c>"$._repos_id == 'IDL:MyModule/MyStruct:1.0'"</c></cell>
- <cell align="left" valign="middle">Returns the RepositoryId of the component. This operation is only valid if said information can be obtained.</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><c>_d</c></cell>
- <cell align="left" valign="middle"><c>"$.eventUnion._d"</c></cell>
- <cell align="left" valign="middle">May only be used when accessing discriminated unions and refers to the discriminator.</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><c>exist</c></cell>
- <cell align="left" valign="middle"><c>"exist $.eventUnion._d and $.eventUnion._d == 10"</c></cell>
- <cell align="left" valign="middle">To avoid that a filtering of an event fails due to that, for example, we try to compare a union discriminator which does not exist, we can use this operator.</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><c>default</c></cell>
- <cell align="left" valign="middle"><c>"default $.eventUnion._d"</c></cell>
- <cell align="left" valign="middle">If the <c>_d</c>operation is in conjunction with the <c>default</c>operation, TRUE will be returned if the union has a default member that is active.</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><c>union</c></cell>
- <cell align="left" valign="middle"><c>"$.(0) == 5"</c>eq. <c>"$.('zero') == 5"</c></cell>
- <cell align="left" valign="middle">When the component refers to a union, with one of the cases defined as <c>case 0: short zero;</c>, we use <c>0</c>or <c>'zero'</c>. The result of the example is <c>TRUE</c>if the union has a discriminator set to <c>0</c>and the value <c>5</c>. If more than one case is defined to be<c>'zero'</c>, <c>$.('zero')</c>accepts both; <c>$.(0)</c>only returns <c>TRUE</c>if the discriminator is set to <c>0</c>. Leaving out the identifier, i.e., <c>$.()</c>, refers to the default value.</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><c>name-value pairs</c></cell>
- <cell align="left" valign="middle"><c>"$.NameValueSeq('myID') == 5"</c>eq.<c>"$.NameValueSeq[1].name == 'myID' and $.NameValueSeq[1].value == 5"</c></cell>
- <cell align="left" valign="middle">The Notification service makes extensive use of <c>name-value pairs</c>sequences within structured events, which allow us to via the identifier <c>name</c>access its <c>value</c>, as shown in the example.</cell>
- </row>
- <tcaption>Table 1: Type and Operator Examples</tcaption>
- </table>
- <p>In the next section we will take a closer look at how it is possible to write constraints using
- different types of notation etc.</p>
- </section>
-
- <section>
- <title>Accessing Data In Events</title>
- <p>To filter events, the supplied constraints must describe the contents of
- the events and desired values. We can, for example, state that we are only
- interested in receiving events which are of type <em>CommunicationsAlarm</em>.
- To be able to achieve this, the constraint must contain information
- that points out which fields to compare with. Figure one illustrates a conceptual overview of a
- structured event. The exact definition is found in the <c>CosNotification.idl</c> file.</p>
- <marker id="eventstructure"></marker>
- <image file="eventstructure.gif">
- <icaption>
-Figure 1: The structure of a structured event.</icaption>
- </image>
- <p>The Notification Service supports different constraint expressions
- notation:</p>
- <list type="bulleted">
- <item>
- <p>Fully scoped, e.g., "$.header.fixed_header.event_type.type_name == 'CommunicationsAlarm'"</p>
- </item>
- <item>
- <p>Short hand, e.g., "$type_name == 'CommunicationsAlarm'"</p>
- </item>
- <item>
- <p>Positional Notation, e.g., "$.0.0.0.1 == 'CommunicationsAlarm'"</p>
- </item>
- </list>
- <note>
- <p>Which notation to use is up to the user, however, the fully scoped may
- be easier to understand, but in some cases, if received from an ORB that do not populate ID:s of
- named parts, the positional notation is the only option.</p>
- </note>
- <note>
- <p>If a constraint, which access fields in a structured event structure,
- is supposed to handle unstructured events as well, the CORBA::Any must contain
- the same type of members.</p>
- </note>
- <p>How to filter against the fixed header fields, is described in the
- table below.</p>
- <table>
- <row>
- <cell align="center" valign="middle">Field</cell>
- <cell align="center" valign="middle">Fully Scoped Constraint</cell>
- <cell align="center" valign="middle">Short Hand Constraint</cell>
- </row>
- <row>
- <cell align="left" valign="middle">type_name</cell>
- <cell align="left" valign="middle">"$.header.fixed_header.event_type.type_name == 'Type'"</cell>
- <cell align="left" valign="middle">"$type_name == 'Type'"</cell>
- </row>
- <row>
- <cell align="left" valign="middle">domain_name</cell>
- <cell align="left" valign="middle">"$.header.fixed_header.event_type.domain_name == 'Domain'"</cell>
- <cell align="left" valign="middle">"$domain_name == 'Domain'"</cell>
- </row>
- <row>
- <cell align="left" valign="middle">event_name</cell>
- <cell align="left" valign="middle">"$.header.fixed_header.event_name == 'Event'"</cell>
- <cell align="left" valign="middle">"$event_name == 'Event'"</cell>
- </row>
- <tcaption>Table 2: Fixed Header Constraint Examples</tcaption>
- </table>
- <p>If we are only interested in receiving events regarding 'Domain', 'Event'
- and 'Type', the constraint can look like
- <c>"$domain_name == 'Domain' and $event_name == 'Event' and $type_name == 'Type'"</c>.</p>
- <p>The variable event header consists of a sequence of <em>name-value pairs</em>. One way to filter on these are to use a constraint that looks
- like <c>"($.header.variable_header[1].name == 'priority' and $.header.variable_header[1].value > 0)"</c>. An easier way to
- accomplish the same result is to use a constraint that treats the name-value
- pair as an associative array, i.e., when given a name the corresponding
- value is returned. Hence, instead we can use
- <c>"$.header.variable_header(priority) > 0"</c>.</p>
- <p>Accessing the event body is done in the same way as for the event header
- fields. The user must, however, be aware of, that if a run-time variable
- (<c>$variable</c>) is used data in the event header may take precedence.
- The order of precedence is:</p>
- <list type="ordered">
- <item>Reserved, e.g., <c>$curtime</c></item>
- <item>A simple-typed member of <c>$.header.fixed_header</c>.</item>
- <item>Properties in <c>$.header.variable_header</c>.</item>
- <item>Properties in <c>$.filterable_data</c>.</item>
- <item>If no match is found it is translated to <c>$.variable</c>.</item>
- </list>
- </section>
-
- <section>
- <title>Mapping Filters</title>
- <p>Mapping Filters may only be associated with Consumer Administrators or Proxy
- Suppliers. The purpose of a Mapping Filter is to override Quality of Service
- settings.</p>
- <p>Initially, Mapping Filters are empty and will always return true. Hence, we must
- add constraints by using <c>'CosNotifyFilter_MappingFilter':add_mapping_constraints/2</c>.
- If a constraint matches, the associated value will be used instead of the
- related Quality of Service system settings.</p>
- <p>As input, the second argument must be a sequence of:</p>
- <code type="none">
-#'CosNotifyFilter_MappingConstraintPair'{
- constraint_expression = #'CosNotifyFilter_ConstraintExp'{
- event_types = [#'CosNotification_EventType'{
- domain_name = string(),
- type_name = string()}],
- constraint_expr = string()},
- result_to_set = any()}
- </code>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosNotification/doc/src/ch_QoS.xml b/lib/cosNotification/doc/src/ch_QoS.xml
deleted file mode 100644
index 7f7a26f69a..0000000000
--- a/lib/cosNotification/doc/src/ch_QoS.xml
+++ /dev/null
@@ -1,252 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Quality Of Service and Admin Properties</title>
- <prepared></prepared>
- <docno></docno>
- <date>2000-05-29</date>
- <rev></rev>
- <file>ch_QoS.xml</file>
- </header>
-
- <section>
- <title>Quality Of Service and Admin Properties</title>
- <p>This chapter explains the allowed properties for
- <seealso marker="CosNotification_QoSAdmin">CosNotification_QoSAdmin</seealso> and
- <seealso marker="CosNotification_AdminPropertiesAdmin">CosNotification_AdminPropertiesAdmin</seealso>.
- </p>
-
- <section>
- <title>Quality Of Service</title>
- <p>The cosNotification application supports the following QoS settings:</p>
- <table>
- <row>
- <cell align="center" valign="middle"><em>QoS</em></cell>
- <cell align="center" valign="middle"><em>Range</em></cell>
- <cell align="center" valign="middle"><em>Default</em></cell>
- </row>
- <row>
- <cell align="left" valign="middle">EventReliability</cell>
- <cell align="left" valign="middle">BestEffort/Persistent</cell>
- <cell align="left" valign="middle">BestEffort</cell>
- </row>
- <row>
- <cell align="left" valign="middle">ConnectionReliability</cell>
- <cell align="left" valign="middle">BestEffort/Persistent</cell>
- <cell align="left" valign="middle">BestEffort</cell>
- </row>
- <row>
- <cell align="left" valign="middle">Priority</cell>
- <cell align="left" valign="middle">+/-32767</cell>
- <cell align="left" valign="middle">0</cell>
- </row>
- <row>
- <cell align="left" valign="middle">OrderPolicy</cell>
- <cell align="left" valign="middle">Any-, Fifo-, Priority- and Deadline-Order</cell>
- <cell align="left" valign="middle">PriorityOrder</cell>
- </row>
- <row>
- <cell align="left" valign="middle">DiscardPolicy</cell>
- <cell align="left" valign="middle">RejectNewEvents, Any-, Fifo-, Lifo-, Priority- and Deadline-Order</cell>
- <cell align="left" valign="middle">RejectNewEvents</cell>
- </row>
- <row>
- <cell align="left" valign="middle">MaximumBatchSize</cell>
- <cell align="left" valign="middle">long() > 0</cell>
- <cell align="left" valign="middle">1</cell>
- </row>
- <row>
- <cell align="left" valign="middle">PacingInterval</cell>
- <cell align="left" valign="middle">TimeBase::TimeT (see cosTime)</cell>
- <cell align="left" valign="middle">0</cell>
- </row>
- <row>
- <cell align="left" valign="middle">StartTimeSupported</cell>
- <cell align="left" valign="middle">boolean</cell>
- <cell align="left" valign="middle">false</cell>
- </row>
- <row>
- <cell align="left" valign="middle">StopTimeSupported</cell>
- <cell align="left" valign="middle">boolean</cell>
- <cell align="left" valign="middle">false</cell>
- </row>
- <row>
- <cell align="left" valign="middle">MaxEventsPerConsumer</cell>
- <cell align="left" valign="middle">long() > 0</cell>
- <cell align="left" valign="middle">100</cell>
- </row>
- <row>
- <cell align="left" valign="middle">Timeout</cell>
- <cell align="left" valign="middle">TimeBase::TimeT (see cosTime)</cell>
- <cell align="left" valign="middle">No timeout</cell>
- </row>
- <tcaption>Table 1: Supported QoS Settings</tcaption>
- </table>
- <br></br>
- <br></br>
- <br></br>
- <br></br>
- <p><em>Comments on the table 'Supported QoS Settings':</em></p>
- <taglist>
- <tag><em>EventReliability</em></tag>
- <item>To allow full Persistent EventReliability, every event must
- be stored in a stable storage which would create a relatively
- huge overhead. Hence, only lightweight version of the Persistent
- QoS is supported. The configuration parameters <c>max_events</c>,
- <c>interval_events</c> and <c>timeout_events</c> determine
- the behavior of this setting.</item>
- <tag><em>ConnectionReliability</em></tag>
- <item>If this QoS is set to BestEffort and a client object returns anything
- other than <c>ok</c> to its associated Proxy, the Proxy will discard
- all events and terminate. Using Persistent and anything other than <c>ok</c>
- is returned, events will be dropped but the proxy will retry later when
- next delivery is due. A child may not have Persistent while its parent
- has BestEffort QoS set, e.g., Proxy vs. Admin. If <c>OBJECT_NOT_EXIST</c>,
- <c>NO_PERMISSION</c> or <c>CosEventComm_Disconnected</c> is thrown,
- the associated object will terminate even if this parameter is
- set to Persistent.</item>
- <tag><em>Priority</em></tag>
- <item>This QoS will treat all events as if they have the Priority equal to
- current value, unless the event itself contains a Priority setting,
- this event will be treated accordingly. Note: for this property to
- have any effect, the DiscardPolicy and/or OrderPolicy must be set
- to PriorityOrder.</item>
- <tag><em>OrderPolicy</em></tag>
- <item>If set to PriorityOrder, events with the highest Priority will be
- delivered first. Deadline order will forward events with shortest
- expiry time first. If two events have the same priority, they will be
- delivered in FIFO-order.</item>
- <tag><em>DiscardPolicy</em></tag>
- <item>If set to PriorityOrder and MaxEventsPerConsumer limit is
- reached, events
- with the lowest Priority will be discarded first. Deadline order will
- discard events with shortest expiry time first.</item>
- <tag><em>MaximumBatchSize</em></tag>
- <item>Only valid if the object is supposed to handle a sequence of structured
- events and determines the largest amount of events that may be passed
- each time.</item>
- <tag><em>PacingInterval</em></tag>
- <item>Determines how long an object will wait before forwarding a structured
- event sequence of length equal to, or less than MaximumBatchSize.
- If set to 0, which is the default behavior, no timeout is used and
- the events are forwarded when the MaximumBatchSize is reached.</item>
- <tag><em>StartTimeSupported</em></tag>
- <item>If set to true events which contains the QoS Property <c>StartTime</c>
- (TimeBase::UtcT - absolute time) will not be delivered until the
- StartTime value have been exceeded. See also the <c>cosTime</c> application.</item>
- <tag><em>StopTimeSupported</em></tag>
- <item>If set to true, events which contain the QoS Properties <c>StopTime</c>
- (TimeBase::UtcT - absolute time) or <c>Timeout</c> (TimeBase::TimeT -
- relative time) will be discarded if the object has not been able to
- deliver the event in time. See also the <c>cosTime</c> application.</item>
- <tag><em>MaxEventsPerConsumer</em></tag>
- <item>The maximum number of events the associated object may store before discarding
- events in the way described by the DiscardPolicy.</item>
- <tag><em>Timeout</em></tag>
- <item>If this QoS property is not included in the event, and the Property
- <c>StopTimeSupported</c> equals true, this setting will be applied
- if events cannot be delivered within its time limit.</item>
- </taglist>
- <warning>
- <p>Several of the above QoS Properties can be changed during run-time but we strongly advice
- not to since, if a relatively large amount of events are waiting for delivery, some of the
- QoS settings would require a total reorder of the events. The QoS property <c>ConnectioReliability</c>
- may <em>never</em> be updated during run-time since it may cause deadlock. Run-time, in this case,
- means activating the Channel by sending the first event.</p>
- </warning>
- </section>
-
- <section>
- <title>Setting Quality Of Service</title>
- <p>Assume we have a Consumer Admin object which we want to change
- the current Quality of Service. Typical usage:</p>
- <code type="none">
-QoSPersistent =
- [#'CosNotification_Property'
- {name='CosNotification':'ConnectionReliability'(),
- value=any:create(orber_tc:short(),
- 'CosNotification':'Persistent'())}],
-'CosNotification_QoSAdmin':set_qos(Ch, QoSPersistent),
- </code>
- <p>If it is not possible to set the requested QoS the <c>UnsupportedQoS</c>
- exception is raised, which includes a sequence of <c>PropertyError</c>'s
- describing which QoS, possible range and why is not allowed. The error
- codes are:</p>
- <list type="bulleted">
- <item>UNSUPPORTED_PROPERTY - QoS not supported for this type of target object.</item>
- <item>UNAVAILABLE_PROPERTY - due to current QoS settings the given property
- is not allowed.</item>
- <item>UNSUPPORTED_VALUE - property value out of range; valid range is returned.</item>
- <item>UNAVAILABLE_VALUE - due to current QoS settings the given value is
- not allowed; valid range is returned.</item>
- <item>BAD_PROPERTY - unrecognized property.</item>
- <item>BAD_TYPE - type of supplied property is incorrect.</item>
- <item>BAD_VALUE - illegal value.</item>
- </list>
- <p>The CosNotification_QoSAdmin interface also supports an operation
- called <c>validate_qos/2</c>. The purpose of this operations is to check
- if a QoS setting is supported by the target object and if so, the operation
- returns additional properties which could be optionally added as well.</p>
- </section>
-
- <section>
- <title>Admin Properties</title>
- <p>The cosNotification application supports the following Admin Properties:</p>
- <table>
- <row>
- <cell align="center" valign="middle"><em>Property</em></cell>
- <cell align="center" valign="middle"><em>Range</em></cell>
- <cell align="center" valign="middle"><em>Default</em></cell>
- </row>
- <row>
- <cell align="left" valign="middle">MaxQueueLength</cell>
- <cell align="left" valign="middle">0</cell>
- <cell align="left" valign="middle">0</cell>
- </row>
- <row>
- <cell align="left" valign="middle">MaxConsumers</cell>
- <cell align="left" valign="middle">long() >= 0</cell>
- <cell align="left" valign="middle">0</cell>
- </row>
- <row>
- <cell align="left" valign="middle">MaxSuppliers</cell>
- <cell align="left" valign="middle">long() >= 0</cell>
- <cell align="left" valign="middle">0</cell>
- </row>
- <tcaption>Table 2: Supported Admin Properties</tcaption>
- </table>
- <p>According to the OMG specification the default values for Admin Properties
- is supposed to be <c>0</c>, which means that no limit applies to these
- properties.</p>
- <note>
- <p>Admin Properties can only be set on a Channel Object level, i.e.,
- they will not have an impact on any Admin or Proxy Objects. Currently,
- setting the Admin Property <c>MaxQueueLength</c> have no effect since
- we cannot discard events accordingly to the Quality of Service Property
- <c>DiscardPolicy</c>.</p>
- </note>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosNotification/doc/src/ch_contents.xml b/lib/cosNotification/doc/src/ch_contents.xml
deleted file mode 100644
index 11014f693b..0000000000
--- a/lib/cosNotification/doc/src/ch_contents.xml
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>The cosNotification Application</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2000-01-31</date>
- <rev>1.0</rev>
- <file>ch-contents.xml</file>
- </header>
-
- <section>
- <title>Content Overview</title>
- <p>The cosNotification documentation is divided into three sections:
- </p>
- <list type="bulleted">
- <item>
- <p>PART ONE - The User's Guide
- <br></br>
-Description of the cosNotification Application including
- services and a small tutorial demonstrating
- the development of a simple service.</p>
- </item>
- <item>
- <p>PART TWO - Release Notes
- <br></br>
-A concise history of cosNotification.</p>
- </item>
- <item>
- <p>PART THREE - The Reference Manual
- <br></br>
- A quick reference guide, including a
- brief description, to all the functions available in cosNotification.</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Brief Description of the User's Guide</title>
- <p>The User's Guide contains the following parts:</p>
- <list type="bulleted">
- <item>
- <p>cosNotification overview</p>
- </item>
- <item>
- <p>cosNotification installation</p>
- </item>
- <item>
- <p>A tutorial example</p>
- </item>
- </list>
- </section>
-</chapter>
-
diff --git a/lib/cosNotification/doc/src/ch_example.xml b/lib/cosNotification/doc/src/ch_example.xml
deleted file mode 100644
index a86aaccc82..0000000000
--- a/lib/cosNotification/doc/src/ch_example.xml
+++ /dev/null
@@ -1,170 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosNotification Examples</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2000-01-31</date>
- <rev>A</rev>
- <file>ch_example.xml</file>
- </header>
-
- <section>
- <title>A Tutorial on How to Create a Simple Service</title>
-
- <section>
- <title>Interface Design</title>
- <p>To use the cosNotification application <em>clients</em> must be implemented.
- There are twelve types of clients: </p>
- <list type="bulleted">
- <item>Structured Push Consumer</item>
- <item>Sequence Push Consumer </item>
- <item>Any Push Consumer</item>
- <item>Structured Pull Consumer</item>
- <item>Sequence Pull Consumer</item>
- <item>Any Pull Consumer</item>
- <item>Structured Push Supplier</item>
- <item>Sequence Push Supplier</item>
- <item>Any Push Supplier</item>
- <item>Structured Pull Supplier</item>
- <item>Sequence Pull Supplier</item>
- <item>Any Pull Supplier</item>
- </list>
- <p>The interfaces for these participants are defined in <em>CosNotification.idl</em>
- and <em>CosNotifyComm.idl</em>.</p>
- </section>
-
- <section>
- <title>Generating a Client Interface</title>
- <p>We start by creating an interface which inherits from the correct interface, e.g., <em>CosNotifyComm::SequencePushConsumer</em>. Hence,
- we must also implement all operations defined in the SequencePushConsumer interface. The IDL-file could look like: </p>
- <code type="c"><![CDATA[
-#ifndef _MYCLIENT_IDL
-#define _MYCLIENT_IDL
-#include <CosNotification.idl>
-#include <CosNotifyComm.idl>
-
-module myClientImpl {
-
- interface ownInterface:CosNotifyComm::SequencePushConsumer {
-
- void ownFunctions(in any NeededArguments)
- raises(Systemexceptions,OwnExceptions);
-
- };
-};
-
-#endif
- ]]></code>
- <p>Run the IDL compiler on this file by calling the <c>ic:gen/1</c> function.
- This will produce the API named <c>myClientImpl_ownInterface.erl</c>.
- After generating the API stubs and the server skeletons it is time to
- implement the servers and if no special options are sent
- to the IDl compiler the file name is <c>myClientImpl_ownInterface_impl.erl</c>.</p>
- <p>The callback module must contain the necessary functions inherited from
- <em>CosNotification.idl</em> and <em>CosNotifyComm.idl</em>.</p>
- </section>
-
- <section>
- <title>How to Run Everything</title>
- <p>Below is a short transcript on how to run cosNotification. </p>
- <code type="none">
-
-%% Start Mnesia and Orber
-mnesia:delete_schema([node()]),
-mnesia:create_schema([node()]),
-orber:install([node()]),
-mnesia:start(),
-orber:start(),
-
-%% If cosEvent not installed before it is necessary to do it now.
-cosEventApp:install(),
-
-%% Install cosNotification in the IFR.
-cosNotificationApp:install(30),
-
-%% Register the application specific Client implementations
-%% in the IFR.
-'oe_myClientImpl':'oe_register'(),
-
-%% Start the cosNotification application.
-cosNotificationApp:start(),
-
-%% Start a factory using the default configuration
-ChFac = cosNotificationApp:start_factory(),
-%% ... or use configuration parameters.
-ChFac = cosNotificationApp:start_factory([]),
-
-%% Create a new event channel. Note, if no QoS- anr/or Admin-properties
-%% are supplied (i.e. empty list) the default settings are used.
-{Ch, ChID} = 'CosNotifyChannelAdmin_EventChannelFactory':
- create_channel(ChFac, DefaultQoS, DefaultAdmin),
-
-%% Retrieve a SupplierAdmin and a Consumer Admin.
-{AdminSupplier, ASID}=
- 'CosNotifyChannelAdmin_EventChannel':new_for_suppliers(Ch, 'OR_OP'),
-{AdminConsumer, ACID}=
- 'CosNotifyChannelAdmin_EventChannel':new_for_consumers(Ch,'OR_OP'),
-
-%% Use the corresponding Admin object to get access to wanted Proxies
-
-%% Create a Push Consumer Proxie, i.e., the Client Push Supplier will
-%% push events to this Proxy.
-{StructuredProxyPushConsumer,ID11}= 'CosNotifyChannelAdmin_SupplierAdmin':
- obtain_notification_push_consumer(AdminSupplier, 'STRUCTURED_EVENT')),
-
-%% Create Push Suppliers Proxies, i.e., the Proxy will push events to the
-%% registered Push Consumers.
-{ProxyPushSupplier,I4D}='CosNotifyChannelAdmin_ConsumerAdmin':
- obtain_notification_push_supplier(AdminConsumer, 'ANY_EVENT'),
-{StructuredProxyPushSupplier,ID5}='CosNotifyChannelAdmin_ConsumerAdmin':
- obtain_notification_push_supplier(AdminConsumer, 'STRUCTURED_EVENT'),
-{SequenceProxyPushSupplier,ID6}='CosNotifyChannelAdmin_ConsumerAdmin':
- obtain_notification_push_supplier(AdminConsumer, 'SEQUENCE_EVENT'),
-
-%% Create application Clients. We can, for example, start the Clients
-%% our selves or look them up in the naming service. This is application
-%% specific.
-SupplierClient = ...
-ConsumerClient1 = ...
-ConsumerClient2 = ...
-ConsumerClient3 = ...
-
-%% Connect each Client to corresponding Proxy.
-'CosNotifyChannelAdmin_StructuredProxyPushConsumer':
- connect_structured_push_supplier(StructuredProxyPushConsumer, SupplierClient),
-'CosNotifyChannelAdmin_ProxyPushSupplier':
- connect_any_push_consumer(ProxyPushSupplier, ConsumerClient1),
-'CosNotifyChannelAdmin_StructuredProxyPushSupplier':
- connect_structured_push_consumer(StructuredProxyPushSupplier, ConsumerClient2),
-'CosNotifyChannelAdmin_SequenceProxyPushSupplier':
- connect_sequence_push_consumer(SequenceProxyPushSupplier, ConsumerClient3),
- </code>
- <p>The example above, exemplifies a notification system where the SupplierClient
- in some way generates event and pushes them to the proxy. The push supplier
- proxies will eventually push the events to each ConsumerClient.</p>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosNotification/doc/src/ch_install.xml b/lib/cosNotification/doc/src/ch_install.xml
deleted file mode 100644
index c76c68cb42..0000000000
--- a/lib/cosNotification/doc/src/ch_install.xml
+++ /dev/null
@@ -1,147 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Installing cosNotification</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2000-01-31</date>
- <rev></rev>
- <file>ch-install.xml</file>
- </header>
-
- <section>
- <title>Installation Process </title>
- <p>This chapter describes how to install <seealso marker="cosNotificationApp">cosNotificationApp</seealso>
- in an Erlang Environment.
- </p>
-
- <section>
- <title>Preparation</title>
- <p>Before starting the installation process for cosNotification,
- the application Orber must be running.</p>
- </section>
-
- <section>
- <title>Configuration</title>
- <p>When using the Notification Service the <c>cosNotification</c> application
- first must be installed using <c>cosNotificationApp:install()</c> or
- <c>cosNotificationApp:install(Seconds)</c>, followed by <c>cosNotificationApp:start()</c>.</p>
- <p>Then the <seealso marker="CosNotifyChannelAdmin_EventChannelFactory">Event Channel Factory</seealso>
- must be started:</p>
- <list type="bulleted">
- <item><c>cosNotificationApp:start_global_factory()</c> - starts and returns a reference to a factory using default configuration parameters.
- This operation should be used for a multi-node Orber.</item>
- <item><c>cosNotificationApp:start_global_factory(Options)</c> - starts and returns a reference to a factory using given configuration parameters.
- This operation should be used for a multi-node Orber.</item>
- <item><c>cosNotificationApp:start_factory()</c> - starts and returns a reference to a factory using default configuration parameters.</item>
- <item><c>cosNotificationApp:start_factory(Options)</c> - starts and returns a reference to a factory using given configuration parameters.</item>
- </list>
- <p>The following options exist:</p>
- <list type="bulleted">
- <item><c>{pullInterval, Seconds}</c> - determine how often Proxy Pull
- Consumers will check for new events with the client application. The
- default value is 20 seconds.</item>
- <item><c>{filterOp, OperationType}</c> - determine which type of Administrator
- objects should be started, i.e., <c>'OR_OP'</c> or <c>'AND_OP'</c>.
- The default value is <c>'OR_OP'</c>.</item>
- <item><c>{timeService, TimeServiceObj | 'undefined'}</c> - to be able to use
- Start and/or Stop QoS this option must be used. See the function <c>start_time_service/2</c>
- in the <c>cosTime</c> application. The default value is <c>'undefined'</c>.</item>
- <item><c>{filterOp, OperationType}</c> - determine which type of Administrator
- objects should be started, i.e., <c>'OR_OP'</c> or <c>'AND_OP'</c>.
- The default value is <c>'OR_OP'</c>.</item>
- <item><c>{gcTime, Seconds}</c> - this option determines how often, for example, proxies
- will garbage collect expired events. The default value is 60.</item>
- <item><c>{gcLimit, Amount}</c> - determines how many events will be stored before, for
- example, proxies will garbage collect expired events. The default value is 50. This
- option is tightly coupled with the QoS property <c>MaxEventsPerConsumer</c>, i.e.,
- the <c>gcLimit</c> should be less than <c>MaxEventsPerConsumer</c> and greater than 0.</item>
- </list>
- <p>It is possible to define a set of global configuration parameters:</p>
- <table>
- <row>
- <cell align="center" valign="middle"><em>Key</em></cell>
- <cell align="center" valign="middle"><em>Range</em></cell>
- <cell align="center" valign="middle"><em>Default</em></cell>
- </row>
- <row>
- <cell align="left" valign="middle">type_check</cell>
- <cell align="left" valign="middle">true | false</cell>
- <cell align="left" valign="middle">true</cell>
- </row>
- <row>
- <cell align="left" valign="middle">notify</cell>
- <cell align="left" valign="middle">atom() | false</cell>
- <cell align="left" valign="middle">false</cell>
- </row>
- <row>
- <cell align="left" valign="middle">max_events</cell>
- <cell align="left" valign="middle">integer() > 0</cell>
- <cell align="left" valign="middle">50</cell>
- </row>
- <row>
- <cell align="left" valign="middle">interval_events</cell>
- <cell align="left" valign="middle">integer() > 0</cell>
- <cell align="left" valign="middle">10000 milliseconds</cell>
- </row>
- <row>
- <cell align="left" valign="middle">timeout_events</cell>
- <cell align="left" valign="middle">integer() > interval_events</cell>
- <cell align="left" valign="middle">3000000 milliseconds</cell>
- </row>
- <tcaption>Global Configuration Parameters</tcaption>
- </table>
- <p><em>Comments on the table 'Global Configuration Parameters':</em></p>
- <taglist>
- <tag><em>type_check</em></tag>
- <item>Determine if supplied IOR:s shall be type checked, i.e. invoking
- corba_object:is_a/2, or not.</item>
- <tag><em>notify</em></tag>
- <item>The given value shall point to an existing module exporting
- a function (arity 1) called <em>terminated</em>. This operation
- is invoked when a proxy terminates and the argument is a list
- containing <c>{proxy, IOR}</c>, <c>{client, IOR}</c> and
- <c>{reason, term()}</c>. The return value is ignored.</item>
- <tag><em>max_events</em></tag>
- <item>If a supplier proxy has not been able to push events to a
- consumer and the queue exceeds this limit, then the proxy will
- terminate. For this option to have any effect, the
- <c>EventReliability</c> and <c>ConnectionReliability</c> QoS
- parameters must be set to <c>Persistent</c>. For more information,
- see also the <seealso marker="ch_QoS">QoS</seealso> chapter.</item>
- <tag><em>interval_events</em></tag>
- <item>The same requirements as for <c>max_events</c>. When a supplier
- proxy detects problems when trying to push events, this parameter
- determines how often it should try to call the consumer.</item>
- <tag><em>timeout_events</em></tag>
- <item>The same requirements as for <c>max_events</c>. If the
- proxy has not been able to contact the consumer and this
- time-limit is reached, then the proxy will terminate.</item>
- </taglist>
- <p>The Factory is now ready to use. For a more detailed description see
- <seealso marker="ch_example">Examples</seealso>.</p>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosNotification/doc/src/ch_introduction.xml b/lib/cosNotification/doc/src/ch_introduction.xml
deleted file mode 100644
index 39cd12f1e6..0000000000
--- a/lib/cosNotification/doc/src/ch_introduction.xml
+++ /dev/null
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Introduction to cosNotification</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2000-01-31</date>
- <rev></rev>
- <file>ch_introduction.xml</file>
- </header>
-
- <section>
- <title>Overview</title>
- <p>The cosNotification application is a Notification Service compliant with the <url href="http://www.omg.org">OMG</url>
- Notification Service CosNotification.
- </p>
-
- <section>
- <title>Purpose and Dependencies</title>
- <p><em>cosNotification</em> is dependent on <em>Orber-3.1.7</em> or later,
- which provides CORBA functionality in an Erlang environment,
- <em>cosTime-1.0.1</em> or later and IDL-files to be compiled using <em>IC-4.0.4</em> or later.</p>
- </section>
-
- <section>
- <title>Prerequisites</title>
- <p>To fully understand the concepts presented in the
- documentation, it is recommended that the user is familiar
- with distributed programming, CORBA and the Orber application.
- </p>
- <p>Recommended reading includes books recommended by the <em>OMG</em>
- and <em>Open Telecom Platform Documentation Set</em>. It is also
- helpful to have read <em>Concurrent Programming in Erlang</em>.</p>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosNotification/doc/src/ch_system.xml b/lib/cosNotification/doc/src/ch_system.xml
deleted file mode 100644
index 91375088a0..0000000000
--- a/lib/cosNotification/doc/src/ch_system.xml
+++ /dev/null
@@ -1,84 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>The Notification Service Components</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2000-04-13</date>
- <rev></rev>
- <file>ch_system.xml</file>
- </header>
-
- <section>
- <title>The Notification Service Components</title>
- <p>This chapter describes the Notification Service Components and how they
- interact.</p>
-
- <section>
- <title>Components</title>
- <p>There are seven components in the OMG Notification Service architecture.
- These are described below: </p>
- <marker id="notificationFlow"></marker>
- <image file="notificationFlow.gif">
- <icaption>
-Figure 1: The Notification Service Components.</icaption>
- </image>
- <list type="bulleted">
- <item><em>Event Channel:</em> acts as a factory for Administrator objects.
- Allows clients to set Administrative Properties.</item>
- <item><em>Supplier Administrators:</em> acts as a factory for Proxy Consumers.
- Administrators are started as <c>'AND_OP'-</c> or <c>'OR_OP'-</c>type,
- which determines if events must be validated using both the Administrators
- associated Filter and/or its Proxy children Filters.</item>
- <item><em>Consumer Administrators:</em> acts in the same way as Supplier Administrators
- but handle Proxy Suppliers.</item>
- <item><em>Consumer Proxy:</em> is connected to a client application. Can be
- started as <c>Pull</c> or <c>Push</c> object. If the proxy is Push style
- the client application must push events to the Proxy, otherwise the Proxy is
- supposed to Pull events. The <c>CosNotification::AdminProperties</c> is
- used to set the pacing interval.</item>
- <item><em>Supplier Proxy:</em> Acts in a similar way as the Consumer Proxy, but
- if started as a <c>Push</c> proxy it will push events to the client
- application.</item>
- <item><em>Filters:</em> used to filter events. May be associated with Proxies
- and Administrators.</item>
- <item><em>Mapping Filters:</em> used to override events Quality of Service
- settings. Can only be associated with Consumer Administrators and
- Proxy Suppliers.</item>
- </list>
- <p>When a Proxy is started it is set to accept <c>CORBA::Any</c>,
- <c>CosNotification::StructuredEvent</c> or <c>CosNotification::EventBatch</c>
- (a sequence of structured events).</p>
- <p>If a Proxy is supposed to deliver structured events to a client application
- and receives an <c>CORBA::Any</c> event, the event is converted to a
- structured event with <c>type_name</c> set to <c>"%ANY"</c> and the
- event is stored in <c>remainder_of_body</c>.</p>
- <p>If a Proxy is supposed to deliver <c>CORBA::Any</c> events to a client application
- and receives a structured event, the event is stored in an Any type. The
- Any Type Code will be equal to the <c>CosNotification::StructuredEvent</c>
- Type Code.</p>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosNotification/doc/src/cosNotificationApp.xml b/lib/cosNotification/doc/src/cosNotificationApp.xml
deleted file mode 100644
index 4f662a5dc4..0000000000
--- a/lib/cosNotification/doc/src/cosNotificationApp.xml
+++ /dev/null
@@ -1,309 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosNotificationApp</title>
- <prepared>Niclas Eklund</prepared>
- <responsible>Niclas Eklund</responsible>
- <docno></docno>
- <approved>Niclas Eklund</approved>
- <checked></checked>
- <date>2000-01-31</date>
- <rev>PA1</rev>
- </header>
- <module>cosNotificationApp</module>
- <modulesummary>The main module of the cosNotification application.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosNotification/include/*.hrl").</c></p>
- <p>This module contains the functions for starting and stopping the application.</p>
- </description>
- <funcs>
- <func>
- <name>install() -> Return</name>
- <fsummary>Install the cosNotification application</fsummary>
- <type>
- <v>Return = ok | {'EXCEPTION', E}</v>
- </type>
- <desc>
- <p>This operation installs the cosNotification application.</p>
- </desc>
- </func>
- <func>
- <name>install(Seconds) -> Return</name>
- <fsummary>Install the cosNotification application</fsummary>
- <type>
- <v>Return = ok | {'EXCEPTION', E}</v>
- </type>
- <desc>
- <p>This operation installs the cosNotification application using <c>Seconds</c>
- delay between each block, currently 6, of IFR-registrations. This approach
- spreads the IFR database access over a period of time to allow other
- applications to run smother.</p>
- </desc>
- </func>
- <func>
- <name>install_event() -> Return</name>
- <fsummary>Install the necessary cosEvent interfaces</fsummary>
- <type>
- <v>Return = ok | {'EXCEPTION', E}</v>
- </type>
- <desc>
- <p>This operation, which may <em>only</em> be used if it is impossible to
- upgrade to <em>cosEvent-2.0</em> or later, installs the necessary
- cosEvent interfaces. If cosEvent-2.0 is available, use
- <c>cosEventApp:install()</c> instead.</p>
- </desc>
- </func>
- <func>
- <name>install_event(Seconds) -> Return</name>
- <fsummary>Install the necessary cosEvent interfaces</fsummary>
- <type>
- <v>Return = ok | {'EXCEPTION', E}</v>
- </type>
- <desc>
- <p>This operation, which may <em>only</em> be used if it is impossible to
- upgrade to <em>cosEvent-2.0</em> or later, installs the necessary cosEvent
- interfaces using <c>Seconds</c> delay between each block of
- IFR-registrations. If cosEvent-2.0 is available, use
- <c>cosEventApp:install()</c> instead.</p>
- </desc>
- </func>
- <func>
- <name>uninstall() -> Return</name>
- <fsummary>Uninstall the cosNotification application</fsummary>
- <type>
- <v>Return = ok | {'EXCEPTION', E}</v>
- </type>
- <desc>
- <p>This operation uninstalls the cosNotification application.</p>
- </desc>
- </func>
- <func>
- <name>uninstall(Seconds) -> Return</name>
- <fsummary>Uninstall the cosNotification application</fsummary>
- <type>
- <v>Return = ok | {'EXCEPTION', E}</v>
- </type>
- <desc>
- <p>This operation uninstalls the cosNotification application using <c>Seconds</c>
- delay between each block, currently 6, of IFR-unregistrations. This approach
- spreads the IFR database access over a period of time to allow other
- applications to run smother.</p>
- </desc>
- </func>
- <func>
- <name>uninstall_event() -> Return</name>
- <fsummary>Uninstall the inherited cosEvent interfaces</fsummary>
- <type>
- <v>Return = ok | {'EXCEPTION', E}</v>
- </type>
- <desc>
- <p>This operation uninstalls the inherited cosEvent interfaces. If cosEvent
- is in use this function may not be used. This function may only be used if
- <c>cosNotificationApp:install_event/1/2</c> was used. If not, use
- <c>cosEventApp:uninstall()</c> instead.</p>
- </desc>
- </func>
- <func>
- <name>uninstall_event(Seconds) -> Return</name>
- <fsummary>Uninstall the inherited cosEvent interfaces</fsummary>
- <type>
- <v>Return = ok | {'EXCEPTION', E}</v>
- </type>
- <desc>
- <p>This operation uninstalls the inherited cosEvent interfaces, using <c>Seconds</c>
- delay between each block of IFR-unregistrations. If cosEvent
- is in use this function may not be used. This function may only be used if
- <c>cosNotificationApp:install_event/1/2</c> was used. If not, use
- <c>cosEventApp:uninstall()</c> instead.</p>
- </desc>
- </func>
- <func>
- <name>start() -> Return</name>
- <fsummary>Start the cosNotification application</fsummary>
- <type>
- <v>Return = ok | {error, Reason}</v>
- </type>
- <desc>
- <p>This operation starts the cosNotification application.</p>
- </desc>
- </func>
- <func>
- <name>stop() -> Return</name>
- <fsummary>Stop the cosNotification application</fsummary>
- <type>
- <v>Return = ok | {error, Reason}</v>
- </type>
- <desc>
- <p>This operation stops the cosNotification application.</p>
- </desc>
- </func>
- <func>
- <name>start_global_factory() -> ChannelFactory</name>
- <fsummary>Start a global channel factory as default</fsummary>
- <type>
- <v>ChannelFactory = #objref</v>
- </type>
- <desc>
- <p>This operation creates a
- <seealso marker="CosNotifyChannelAdmin_EventChannelFactory">Event Channel Factory</seealso>
- should be used for a multi-node Orber.
- The Factory is used to create a new
- <seealso marker="CosNotifyChannelAdmin_EventChannel">channel</seealso>. </p>
- </desc>
- </func>
- <func>
- <name>start_global_factory(Options) -> ChannelFactory</name>
- <fsummary>Start a global channel factory with options</fsummary>
- <type>
- <v>Options = [Option]</v>
- <v>Option = {pullInterval, Seconds} | {filterOp, Op} | {gcTime, Seconds} | {gcLimit, Anount} | {timeService, #objref}</v>
- <v>ChannelFactory = #objref</v>
- </type>
- <desc>
- <p>This operation creates a
- <seealso marker="CosNotifyChannelAdmin_EventChannelFactory">Event Channel Factory</seealso> and
- should be used for a multi-node Orber.
- The Factory is used to create a new
- <seealso marker="CosNotifyChannelAdmin_EventChannel">channel</seealso>. </p>
- <p></p>
- <list type="bulleted">
- <item><c>{pullInterval, Seconds}</c> - determine how often Proxy Pull
- Consumers will check for new events with the client application. The
- default value is 20 seconds.</item>
- <item><c>{filterOp, OperationType}</c> - determine which type of Administrator
- objects should be started, i.e., <c>'OR_OP'</c> or <c>'AND_OP'</c>.
- The default value is <c>'OR_OP'</c>.</item>
- <item><c>{timeService, TimeServiceObj | 'undefined'}</c> - to be able to use
- Start and/or Stop QoS this option must be used. See the function <c>start_time_service/2</c>
- in the <c>cosTime</c> application. The default value is <c>'undefined'</c>.</item>
- <item><c>{filterOp, OperationType}</c> - determine which type of Administrator
- objects should be started, i.e., <c>'OR_OP'</c> or <c>'AND_OP'</c>.
- The default value is <c>'OR_OP'</c>.</item>
- <item><c>{gcTime, Seconds}</c> - this option determines how often, for example, proxies
- will garbage collect expired events. The default value is 60.</item>
- <item><c>{gcLimit, Amount}</c> - determines how many events will be stored before, for
- example, proxies will garbage collect expired events. The default value is 50. This
- option is tightly coupled with the QoS property <c>MaxEventsPerConsumer</c>, i.e.,
- the <c>gcLimit</c> should be less than <c>MaxEventsPerConsumer</c> and greater than 0.</item>
- </list>
- </desc>
- </func>
- <func>
- <name>start_factory() -> ChannelFactory</name>
- <fsummary>Start a channel factory as default</fsummary>
- <type>
- <v>ChannelFactory = #objref</v>
- </type>
- <desc>
- <p>This operation creates a
- <seealso marker="CosNotifyChannelAdmin_EventChannelFactory">Event Channel Factory</seealso>.
- The Factory is used to create a new
- <seealso marker="CosNotifyChannelAdmin_EventChannel">channel</seealso>. </p>
- </desc>
- </func>
- <func>
- <name>start_factory(Options) -> ChannelFactory</name>
- <fsummary>Start a channel factory with options</fsummary>
- <type>
- <v>Options = [Option]</v>
- <v>Option = {pullInterval, Seconds} | {filterOp, Op} | {gcTime, Seconds} | {gcLimit, Amount} | {timeService, #objref}</v>
- <v>ChannelFactory = #objref</v>
- </type>
- <desc>
- <p>This operation creates a
- <seealso marker="CosNotifyChannelAdmin_EventChannelFactory">Event Channel Factory</seealso>.
- The Factory is used to create a new
- <seealso marker="CosNotifyChannelAdmin_EventChannel">channel</seealso>. </p>
- </desc>
- </func>
- <func>
- <name>stop_factory(ChannelFactory) -> Reply</name>
- <fsummary>Terminate the target object</fsummary>
- <type>
- <v>ChannelFactory = #objref</v>
- <v>Reply = ok | {'EXCEPTION', E}</v>
- </type>
- <desc>
- <p>This operation stop the target channel factory.</p>
- </desc>
- </func>
- <func>
- <name>start_filter_factory() -> FilterFactory</name>
- <fsummary>Start a filter factory</fsummary>
- <type>
- <v>FilterFactory = #objref</v>
- </type>
- <desc>
- <p>This operation creates a
- <seealso marker="CosNotifyFilter_FilterFactory">Filter Factory</seealso>.
- The Factory is used to create a new
- <seealso marker="CosNotifyFilter_Filter">Filter's</seealso> and
- <seealso marker="CosNotifyFilter_MappingFilter">MappingFilter's</seealso>. </p>
- </desc>
- </func>
- <func>
- <name>stop_filter_factory(FilterFactory) -> Reply</name>
- <fsummary>Terminate the target object</fsummary>
- <type>
- <v>FilterFactory = #objref</v>
- <v>Reply = ok | {'EXCEPTION', E}</v>
- </type>
- <desc>
- <p>This operation stop the target filter factory.</p>
- </desc>
- </func>
- <func>
- <name>create_structured_event(Domain, Type, Event, VariableHeader, FilterableBody, BodyRemainder) -> Reply</name>
- <fsummary>Create a structured event</fsummary>
- <type>
- <v>Domain = string()</v>
- <v>Type = string()</v>
- <v>Event = string()</v>
- <v>VariableHeader = [CosNotification::Property]</v>
- <v>FilterableBody = [CosNotification::Property]</v>
- <v>BodyRemainder = #any data-type</v>
- <v>Reply = CosNotification::StructuredEvent | {'EXCEPTION', E}</v>
- </type>
- <desc>
- <p>An easy way to create a structured event is to use this function.
- Simple typechecks are performed and if one of the arguments is not
- correct a 'BAD_PARAM' exception is thrown.</p>
- </desc>
- </func>
- <func>
- <name>type_check() -> Reply</name>
- <fsummary>Return the value of the configuration parameter type_check</fsummary>
- <type>
- <v>Reply = true | false</v>
- </type>
- <desc>
- <p>This operation returns the value of the configuration parameter
- <c>type_check</c>.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosNotification/doc/src/eventstructure.gif b/lib/cosNotification/doc/src/eventstructure.gif
deleted file mode 100644
index 879c96f980..0000000000
--- a/lib/cosNotification/doc/src/eventstructure.gif
+++ /dev/null
Binary files differ
diff --git a/lib/cosNotification/doc/src/notes.xml b/lib/cosNotification/doc/src/notes.xml
deleted file mode 100644
index bf0fc73548..0000000000
--- a/lib/cosNotification/doc/src/notes.xml
+++ /dev/null
@@ -1,632 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosNotification Release Notes</title>
- <prepared></prepared>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>2000-01-31</date>
- <rev>A</rev>
- <file>notes.xml</file>
- </header>
-
- <section><title>cosNotification 1.2.3</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> Removed all old unused files in the documentation.
- </p>
- <p>
- Own Id: OTP-14475 Aux Id: ERL-409, PR-1493 </p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosNotification 1.2.2</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Internal changes</p>
- <p>
- Own Id: OTP-13551</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosNotification 1.2.1</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> Suppress Dialyzer warnings. </p>
- <p>
- Own Id: OTP-12862</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosNotification 1.2</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> Remove the usage of erlang:now() from all Corba
- applications and use the new rand module instead of
- random. </p>
- <p>
- Own Id: OTP-12687</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosNotification 1.1.21</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> The default encoding of Erlang files has been changed
- from ISO-8859-1 to UTF-8. </p> <p> The encoding of XML
- files has also been changed to UTF-8. </p>
- <p>
- Own Id: OTP-10907</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosNotification 1.1.20</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> Postscript files no longer needed for the generation
- of PDF files have been removed. </p>
- <p>
- Own Id: OTP-11016</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosNotification 1.1.19</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Misc build updates</p>
- <p>
- Own Id: OTP-10784</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosNotification 1.1.18</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>Erlang/OTP can now be built using parallel make if you
- limit the number of jobs, for instance using '<c>make
- -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not
- work at the moment because of some missing
- dependencies.</p>
- <p>
- Own Id: OTP-9451</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosNotification 1.1.17</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Removed superfluous usage of shy in the documentation since it can cause problem if
- a buggy tool is used.</p>
- <p>
- Own Id: OTP-9319 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section><title>cosNotification 1.1.16</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Eliminated Dialyzer warnings when using exit or throw.</p>
- <p>
- Own Id: OTP-9050</p>
- </item>
- </list>
- </section>
-</section>
-
- <section><title>cosNotification 1.1.15</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Switched from using the deprecated regexp to re instead.</p>
- <p>
- Own Id: OTP-8846</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section>
- <title>cosNotification 1.1.14</title>
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- Test suites published.</p>
- <p>
- Own Id: OTP-8543 Aux Id:</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>Added missing trailing bracket to define in hrl-file.</p>
- <p>Own Id: OTP-8489 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosNotification 1.1.14</title>
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- Test suites published.</p>
- <p>
- Own Id: OTP-8543 Aux Id:</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>Added missing trailing bracket to define in hrl-file.</p>
- <p>Own id: OTP-8489 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosNotification 1.1.13</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>Removed superfluous VT in the documentation.</p>
- <p>Own Id: OTP-8353 Aux Id:</p>
- </item>
- <item>
- <p>Removed superfluous backslash in the documentation.</p>
- <p>Own Id: OTP-8354 Aux Id:</p>
- </item>
- <item>
- <p>The documentation EIX file was not generated.</p>
- <p>Own Id: OTP-8355 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosNotification 1.1.12</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- The documentation is now built with open source tools (xsltproc and fop)
- that exists on most platforms. One visible change is that the frames are removed.</p>
- <p>
- Own Id: OTP-8201 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosNotification 1.1.11</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Obsolete guards, e.g. record vs is_record, has been changed
- to avoid compiler warnings.</p>
- <p>Own Id: OTP-7987</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosNotification 1.1.10</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>Updated file headers.</p>
- <p>Own Id: OTP-7837 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosNotification 1.1.9</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>Documentation source included in open source releases.</p>
- <p>Own Id: OTP-7595 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosNotification 1.1.8</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>The CosNotification proxy objects ignored the gcLimit option, instead
- the gcTime value was used.</p>
- <p>Own Id: OTP-7553 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosNotification 1.1.7</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Updated file headers.</p>
- <p>Own Id: OTP-7011</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosNotification 1.1.6</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>The documentation source has been converted from SGML to XML.</p>
- <p>Own Id: OTP-6754</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosNotification 1.1.5</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Minor Makefile changes.</p>
- <p>Own Id: OTP-6701</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosNotification 1.1.4</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Removed some unused code.</p>
- <p>Own Id: OTP-6527</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosNotification 1.1.3</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>A user can now define the QoS EventReliability to be
- Persistent. Note, this is only a lightweight version
- and events will be lost if a proxy is terminated.</p>
- <p>Own Id: OTP-5923</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosNotification 1.1.2</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Possible to configure cosNotification not to type check,
- by invoking corba_object:is_a/2, supplied IOR:s. When
- a type check fails, the feedback has been improved.</p>
- <p>Own Id: OTP-5823 Aux Id: seq10143</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosNotification 1.1.1</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>The app-file contained duplicated modules.</p>
- <p>Own Id: OTP-4976</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosNotification 1.1</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>The stub/skeleton-files generated by IC have been improved,
- i.e., depending on the IDL-files, reduced the size of the
- erl- and beam-files and decreased dependencies off Orber's
- Interface Repository. It is necessary to re-compile all IDL-files
- and use COS-applications, including Orber, compiled with
- IC-4.2.</p>
- <p>Own Id: OTP-4576</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosNotification 1.0.6</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>The exception CosNotifyFilter::InvalidValue, raised by the operation
- CosNotifyFilter::MappingFilter::add_mapping_constraints, did not contain
- correct data in the body. Hence, it was not possible to pass this
- exception to another ORB.</p>
- <p>Own Id: OTP-4412</p>
- </item>
- <item>
- <p>It was not possible to set the QoS property PacingInterval to zero and
- the default value was not compliant with the OMG specification. The
- default value for MaximumBatchSize have also been changed du to the
- same reason.</p>
- <p>Own Id: OTP-4413, OTP-4414</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <list type="bulleted">
- <item>
- <p>The default value, for the QoS properties PacingInterval and MaximumBatchSize,
- have been changed to zero (i.e. no timeout) and 1 respectively, which is
- compliant with the OMG specification.</p>
- <p>Own Id: OTP-4413, OTP-4414</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosNotification 1.0.5</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>If one tries to set an unavailable/incorrect property or property value, an
- exception is thrown. In some cases the exception was not correct, which
- would cause problems if communicating via IIOP.</p>
- <p>Own Id: OTP-4340</p>
- </item>
- <item>
- <p>When using Filter's, with the QoS OrderPolicy set to FifoOrder,
- and passing a sequence of structured events, they could be
- delivered in the wrong order.</p>
- <p>Own Id: OTP-4272</p>
- </item>
- <item>
- <p>If Filter's where attached to Supplier proxies it could cause
- the Proxy to terminate.</p>
- <p>Own Id: OTP-4272</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosNotification 1.0.4</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>When passing event sequences, the PushSuppliers and PullSuppliers
- could crash if the objects had Filter objects associated and
- only a subset of the sequences where approved. </p>
- <p>Own Id: OTP-4099</p>
- </item>
- <item>
- <p>SupplierAdmin's did not filter any events, even though Filter objects
- had been attached to the SupplierAdmin.</p>
- <p>Own Id: OTP-4098</p>
- </item>
- <item>
- <p>If one used the '_get_default_supplier_admin'/1, exported by the
- CosNotifyChannelAdmin_EventChannel-module, it resulted in a loop
- which overloaded the channel. This is no longer the case.</p>
- <p>Own Id: OTP-4086</p>
- </item>
- <item>
- <p>If one used the '_get_default_filter_factory'/1, exported by the
- CosNotifyChannelAdmin_EventChannel-module, a new instance was created
- each time. Now fixed.</p>
- <p>Own Id: OTP-4092</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <list type="bulleted">
- <item>
- <p>The include paths for <c>CosNotification.idl</c> have been changed.
- Hence, if you include this file in your own IDL-files you must
- update your paths to also point to where the cosEvent IDL-files are
- stored.</p>
- <p>Own Id: OTP-4093</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosNotification 1.0.3</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>It is now possible to start global channel factories.</p>
- <p>Own Id: OTP-4078</p>
- </item>
- <item>
- <p>The Orber, version 3.2.5 or later, configuration parameter
- orber_debug_level can now be used to generate reports when abnormal
- situations occurs. For more information consult the Orber User's Guide.
- Note, it is not recommended to use this option for delivered systems
- since some of the reports is not to be considered as errors.
- The value of orber_debug_level must be 3, or higher, for reports to
- be generated.</p>
- <p>Own Id: OTP-4077, OTP-3962</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>When using the cosEvent API accessing a cosNotification admins
- the objects returned by the functions obtain_push_supplier,
- obtain_pull_supplier, obtain_push_consumer and obtain_pull_consumer
- was not of the correct type. Due to the interface change
- it is not possible to upgrade during runtime.</p>
- <p>Own Id: OTP-4079</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosNotification 1.0.2</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>First release of the cosNotification application.</p>
- <p>Own Id: -</p>
- </item>
- </list>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosNotification/doc/src/notificationFlow.gif b/lib/cosNotification/doc/src/notificationFlow.gif
deleted file mode 100644
index 31d6ee97fb..0000000000
--- a/lib/cosNotification/doc/src/notificationFlow.gif
+++ /dev/null
Binary files differ
diff --git a/lib/cosNotification/doc/src/part.xml b/lib/cosNotification/doc/src/part.xml
deleted file mode 100644
index 9cc5a8a95a..0000000000
--- a/lib/cosNotification/doc/src/part.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE part SYSTEM "part.dtd">
-
-<part xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosNotification User's Guide</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2000-01-31</date>
- <rev>1.0</rev>
- </header>
- <description>
- <p>The <em>cosNotification</em> application is an Erlang implementation
- of the OMG CORBA Notification Service.</p>
- </description>
- <xi:include href="ch_contents.xml"/>
- <xi:include href="ch_introduction.xml"/>
- <xi:include href="ch_install.xml"/>
- <xi:include href="ch_system.xml"/>
- <xi:include href="ch_BNF.xml"/>
- <xi:include href="ch_QoS.xml"/>
- <xi:include href="ch_example.xml"/>
-</part>
-
diff --git a/lib/cosNotification/doc/src/ref_man.xml b/lib/cosNotification/doc/src/ref_man.xml
deleted file mode 100644
index 58fb4febd2..0000000000
--- a/lib/cosNotification/doc/src/ref_man.xml
+++ /dev/null
@@ -1,64 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE application SYSTEM "application.dtd">
-
-<application xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosNotification Reference Manual</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2000-01-31</date>
- <rev>1.0</rev>
- </header>
- <description>
- <p>The <em>cosNotification</em> application is an Erlang implementation
- of the OMG CORBA Notification Service.</p>
- </description>
- <xi:include href="cosNotificationApp.xml"/>
- <xi:include href="CosNotifyChannelAdmin_EventChannelFactory.xml"/>
- <xi:include href="CosNotifyChannelAdmin_EventChannel.xml"/>
- <xi:include href="CosNotification.xml"/>
- <xi:include href="CosNotification_QoSAdmin.xml"/>
- <xi:include href="CosNotification_AdminPropertiesAdmin.xml"/>
- <xi:include href="CosNotifyChannelAdmin_ConsumerAdmin.xml"/>
- <xi:include href="CosNotifyChannelAdmin_SupplierAdmin.xml"/>
- <xi:include href="CosNotifyComm_NotifyPublish.xml"/>
- <xi:include href="CosNotifyComm_NotifySubscribe.xml"/>
- <xi:include href="CosNotifyFilter_FilterAdmin.xml"/>
- <xi:include href="CosNotifyFilter_FilterFactory.xml"/>
- <xi:include href="CosNotifyFilter_Filter.xml"/>
- <xi:include href="CosNotifyFilter_MappingFilter.xml"/>
- <xi:include href="CosNotifyChannelAdmin_ProxyConsumer.xml"/>
- <xi:include href="CosNotifyChannelAdmin_ProxySupplier.xml"/>
- <xi:include href="CosNotifyChannelAdmin_ProxyPullConsumer.xml"/>
- <xi:include href="CosNotifyChannelAdmin_ProxyPullSupplier.xml"/>
- <xi:include href="CosNotifyChannelAdmin_ProxyPushConsumer.xml"/>
- <xi:include href="CosNotifyChannelAdmin_ProxyPushSupplier.xml"/>
- <xi:include href="CosNotifyChannelAdmin_SequenceProxyPullConsumer.xml"/>
- <xi:include href="CosNotifyChannelAdmin_SequenceProxyPullSupplier.xml"/>
- <xi:include href="CosNotifyChannelAdmin_SequenceProxyPushConsumer.xml"/>
- <xi:include href="CosNotifyChannelAdmin_SequenceProxyPushSupplier.xml"/>
- <xi:include href="CosNotifyChannelAdmin_StructuredProxyPullConsumer.xml"/>
- <xi:include href="CosNotifyChannelAdmin_StructuredProxyPullSupplier.xml"/>
- <xi:include href="CosNotifyChannelAdmin_StructuredProxyPushConsumer.xml"/>
- <xi:include href="CosNotifyChannelAdmin_StructuredProxyPushSupplier.xml"/>
-</application>
-
diff --git a/lib/cosNotification/ebin/.gitignore b/lib/cosNotification/ebin/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosNotification/ebin/.gitignore
+++ /dev/null
diff --git a/lib/cosNotification/examples/.gitignore b/lib/cosNotification/examples/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosNotification/examples/.gitignore
+++ /dev/null
diff --git a/lib/cosNotification/include/.gitignore b/lib/cosNotification/include/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosNotification/include/.gitignore
+++ /dev/null
diff --git a/lib/cosNotification/info b/lib/cosNotification/info
deleted file mode 100644
index 1b634eb124..0000000000
--- a/lib/cosNotification/info
+++ /dev/null
@@ -1,3 +0,0 @@
-group: orb
-short: Orber OMG Notification Service
-
diff --git a/lib/cosNotification/priv/.gitignore b/lib/cosNotification/priv/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosNotification/priv/.gitignore
+++ /dev/null
diff --git a/lib/cosNotification/src/CosEvent.cfg b/lib/cosNotification/src/CosEvent.cfg
deleted file mode 100644
index e3399139a4..0000000000
--- a/lib/cosNotification/src/CosEvent.cfg
+++ /dev/null
@@ -1,20 +0,0 @@
-{this, "CosEventChannelAdmin::EventChannel"}.
-{{handle_info, "CosEventChannelAdmin::EventChannel"}, true}.
-{this, "CosEventChannelAdmin::EventChannelFactory"}.
-{{handle_info, "CosEventChannelAdmin::EventChannelFactory"}, true}.
-{this, "CosEventChannelAdmin::SupplierAdmin"}.
-{{handle_info, "CosEventChannelAdmin::SupplierAdmin"}, true}.
-{this, "CosEventChannelAdmin::ConsumerAdmin"}.
-{{handle_info, "CosEventChannelAdmin::ConsumerAdmin"}, true}.
-{this, "CosEventChannelAdmin::ProxyPushSupplier"}.
-{{handle_info, "CosEventChannelAdmin::ProxyPushSupplier"}, true}.
-{{impl, "CosEventChannelAdmin::ProxyPushSupplier"}, "PusherSupplier_impl"}.
-{this, "CosEventChannelAdmin::ProxyPullSupplier"}.
-{{handle_info, "CosEventChannelAdmin::ProxyPullSupplier"}, true}.
-{{impl, "CosEventChannelAdmin::ProxyPullSupplier"}, "PullerSupplier_impl"}.
-{this, "CosEventChannelAdmin::ProxyPushConsumer"}.
-{{handle_info, "CosEventChannelAdmin::ProxyPushConsumer"}, true}.
-{{impl, "CosEventChannelAdmin::ProxyPushConsumer"}, "PusherConsumer_impl"}.
-{this, "CosEventChannelAdmin::ProxyPullConsumer"}.
-{{handle_info, "CosEventChannelAdmin::ProxyPullConsumer"}, true}.
-{{impl, "CosEventChannelAdmin::ProxyPullConsumer"}, "PullerConsumer_impl"}.
diff --git a/lib/cosNotification/src/CosNotification.cfg b/lib/cosNotification/src/CosNotification.cfg
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosNotification/src/CosNotification.cfg
+++ /dev/null
diff --git a/lib/cosNotification/src/CosNotification.idl b/lib/cosNotification/src/CosNotification.idl
deleted file mode 100644
index e080b44b0c..0000000000
--- a/lib/cosNotification/src/CosNotification.idl
+++ /dev/null
@@ -1,146 +0,0 @@
-#ifndef _COS_NOTIFICATION_IDL_
-#define _COS_NOTIFICATION_IDL_
-
-#pragma prefix "omg.org"
-
-#include"CosEventChannelAdmin.idl"
-#include"CosEventComm.idl"
-
-module CosNotification {
- typedef string Istring;
- typedef Istring PropertyName;
- typedef any PropertyValue;
- struct Property {
- PropertyName name;
- PropertyValue value;
- };
- typedef sequence<Property> PropertySeq;
- // The following are the same, but serve different purposes.
- typedef PropertySeq OptionalHeaderFields;
- typedef PropertySeq FilterableEventBody;
- typedef PropertySeq QoSProperties;
- typedef PropertySeq AdminProperties;
- struct EventType {
- string domain_name;
- string type_name;
- };
- typedef sequence<EventType> EventTypeSeq;
- struct PropertyRange {
- PropertyValue low_val;
- PropertyValue high_val;
- };
- struct NamedPropertyRange {
- PropertyName name;
- PropertyRange range;
- };
-
- typedef sequence<NamedPropertyRange> NamedPropertyRangeSeq;
-
- enum QoSError_code {
- UNSUPPORTED_PROPERTY,
- UNAVAILABLE_PROPERTY,
- UNSUPPORTED_VALUE,
- UNAVAILABLE_VALUE,
- BAD_PROPERTY,
- BAD_TYPE,
- BAD_VALUE
- };
-
- struct PropertyError {
- QoSError_code code;
- PropertyName name;
- PropertyRange available_range;
- };
-
- typedef sequence<PropertyError> PropertyErrorSeq;
- exception UnsupportedQoS { PropertyErrorSeq qos_err; };
- exception UnsupportedAdmin { PropertyErrorSeq admin_err; };
-
- // Define the Structured Event structure
- struct FixedEventHeader {
- EventType event_type;
- string event_name;
- };
- struct EventHeader {
- FixedEventHeader fixed_header;
- OptionalHeaderFields variable_header;
- };
-
- struct StructuredEvent {
- EventHeader header;
- FilterableEventBody filterable_data;
- any remainder_of_body;
- }; // StructuredEvent
-
- typedef sequence<StructuredEvent> EventBatch;
-
- // The following constant declarations define the standard
- // QoS property names and the associated values each property
- // can take on. The name/value pairs for each standard property
- // are grouped, beginning with a string constant defined for the
- // property name, followed by the values the property can take on.
- const string EventReliability = "EventReliability";
- const short BestEffort = 0;
- const short Persistent = 1;
- const string ConnectionReliability = "ConnectionReliability";
-
- // Can take on the same values as EventReliability
- const string Priority = "Priority";
- const short LowestPriority = -32767;
- const short HighestPriority = 32767;
- const short DefaultPriority = 0;
- const string StartTime = "StartTime";
-
- // StartTime takes a value of type TimeBase::UtcT.
- const string StopTime = "StopTime";
- // StopTime takes a value of type TimeBase::UtcT.
- const string Timeout = "Timeout";
- // Timeout takes on a value of type TimeBase::TimeT
- const string OrderPolicy = "OrderPolicy";
- const short AnyOrder = 0;
- const short FifoOrder = 1;
- const short PriorityOrder = 2;
- const short DeadlineOrder = 3;
- const string DiscardPolicy = "DiscardPolicy";
- // DiscardPolicy takes on the same values as OrderPolicy, plus
- const short LifoOrder = 4;
- const short RejectNewEvents = 5;
- const string MaximumBatchSize = "MaximumBatchSize";
- // MaximumBatchSize takes on a value of type long
- const string PacingInterval = "PacingInterval";
- // PacingInterval takes on a value of type TimeBase::TimeT
- const string StartTimeSupported = "StartTimeSupported";
- // StartTimeSupported takes on a boolean value
- const string StopTimeSupported = "StopTimeSupported";
- // StopTimeSupported takes on a boolean value
- const string MaxEventsPerConsumer = "MaxEventsPerConsumer";
- // MaxEventsPerConsumer takes on a value of type long
-
- interface QoSAdmin {
- QoSProperties get_qos();
- void set_qos ( in QoSProperties qos)
- raises ( UnsupportedQoS );
- void validate_qos (in QoSProperties required_qos,
- out NamedPropertyRangeSeq available_qos )
- raises ( UnsupportedQoS );
- }; // QosAdmin
-
- // Admin properties are defined in similar manner as QoS
- // properties. The only difference is that these properties
- // are related to channel administration policies, as opposed
- // message quality of service
- const string MaxQueueLength = "MaxQueueLength";
- // MaxQueueLength takes on a value of type long
- const string MaxConsumers = "MaxConsumers";
- // MaxConsumers takes on a value of type long
- const string MaxSuppliers = "MaxSuppliers";
- // MaxSuppliers takes on a value of type long
- interface AdminPropertiesAdmin {
- AdminProperties get_admin();
- void set_admin (in AdminProperties admin)
- raises ( UnsupportedAdmin);
- };// AdminPropertiesAdmin
-}; // CosNotification
-
-#endif /* ifndef _COS_NOTIFICATION_IDL_ */
-
diff --git a/lib/cosNotification/src/CosNotification_Common.erl b/lib/cosNotification/src/CosNotification_Common.erl
deleted file mode 100644
index 530641b7a5..0000000000
--- a/lib/cosNotification/src/CosNotification_Common.erl
+++ /dev/null
@@ -1,1240 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2015. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%--------------------------------------------------------------------
-%% File : CosNotification_Common.erl
-%% Purpose :
-%%--------------------------------------------------------------------
-
--module('CosNotification_Common').
-
-
-%%--------------- INCLUDES -----------------------------------
--include_lib("orber/include/corba.hrl").
-%% Application files
--include("CosNotification.hrl").
--include("CosNotifyChannelAdmin.hrl").
--include("CosNotifyComm.hrl").
--include("CosNotifyFilter.hrl").
-
--include("CosNotification_Definitions.hrl").
-
-%%--------------- EXPORTS ------------------------------------
-%% External MISC
--export([get_option/3,
- create_name/0,
- create_name/1,
- create_name/2,
- create_id/0,
- create_id/1,
- is_debug_compiled/0,
- type_check/2,
- send_stubborn/5,
- create_link/3,
- disconnect/3,
- do_disconnect/3,
- notify/1]).
-
-%% Internal AdminProperties
--export([init_adm/1,
- set_adm/2,
- 'MaxQueueLength'/6,
- 'MaxConsumers'/6,
- 'MaxSuppliers'/6]).
-%% Internal QoS
--export([init_qos/1,
- set_qos/5,
- validate_qos/5,
- validate_event_qos/2,
- 'EventReliability'/6,
- 'ConnectionReliability'/6,
- 'Priority'/6,
- 'StartTimeSupported'/6,
- 'StopTimeSupported'/6,
- 'Timeout'/6,
- 'OrderPolicy'/6,
- 'DiscardPolicy'/6,
- 'MaximumBatchSize'/6,
- 'PacingInterval'/6,
- 'MaxEventsPerConsumer'/6]).
-
-%%--------------- DEFINITIONS OF CONSTANTS -------------------
-%%--------------- EXTERNAL MISC FUNCTIONS --------------------
-%%------------------------------------------------------------
-%% function : create_link
-%% Arguments: Module - which Module to call
-%% Env/ArgList - ordinary oe_create arguments.
-%% Returns :
-%% Exception:
-%% Effect : Necessary since we want the supervisor to be a
-%% 'simple_one_for_one'. Otherwise, using for example,
-%% 'one_for_one', we have to call supervisor:delete_child
-%% to remove the childs startspecification from the
-%% supervisors internal state.
-%%------------------------------------------------------------
-create_link(Module, Env, ArgList) ->
- Module:oe_create_link(Env, ArgList).
-
-%%-----------------------------------------------------------%
-%% function : get_option
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-get_option(Key, OptionList, DefaultList) ->
- case lists:keysearch(Key, 1, OptionList) of
- {value,{Key,Value}} ->
- Value;
- _ ->
- case lists:keysearch(Key, 1, DefaultList) of
- {value,{Key,Value}} ->
- Value;
- _->
- {error, "Invalid option"}
- end
- end.
-
-%%------------------------------------------------------------
-%% function : create_name
-%% Arguments:
-%% Returns :
-%% Effect : Create a unique name to use when, for eaxmple, starting
-%% a new server.
-%%------------------------------------------------------------
-create_name() ->
- Time = erlang:system_time(),
- Unique = erlang:unique_integer([positive]),
- lists:concat(['oe_',node(),'_',Time,'_',Unique]).
-
-
-%%-----------------------------------------------------------%
-%% function : create_name/1
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-create_name(Type) ->
- Time = erlang:system_time(),
- Unique = erlang:unique_integer([positive]),
- lists:concat(['oe_',node(),'_',Type,'_',Time,'_',Unique]).
-
-%%-----------------------------------------------------------%
-%% function : create_name/2
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-create_name(Name,Type) ->
- Time = erlang:system_time(),
- Unique = erlang:unique_integer([positive]),
- lists:concat(['oe_',node(),'_',Type,'_',Name,'_',Time,'_',Unique]).
-
-%%------------------------------------------------------------
-%% function : create_id/0
-%% Arguments: -
-%% Returns : id (long) =/= 0
-%% Both default Admin:s have the unique id 0 (OMG spec, 98-11-01,
-%% Notification p 148), hence, we may not return 0.
-%% Exception:
-%% Purpose : Throughout the CosNotification service we use,
-%% according to the OMG specification, id:s (long),
-%% which must be "unique", to retrieve object references.
-%% For example: CosNotifyChannelAdmin::ChannelId/AdminID.
-%%------------------------------------------------------------
-create_id(-1) ->
- 1;
-create_id(2147483647) ->
- -2147483648;
-create_id(OldID) ->
- OldID+1.
-
-create_id() ->
- {_A,_B,C}=erlang:timestamp(),
- C.
-
-%%------------------------------------------------------------
-%% function : type_check
-%% Arguments: Obj - objectrefernce to test.
-%% Mod - Module which contains typeID/0.
-%% Returns : 'ok' or raises exception.
-%% Effect :
-%%------------------------------------------------------------
-type_check(Obj, Mod) ->
- case cosNotificationApp:type_check() of
- false ->
- ok;
- _ ->
- case catch corba_object:is_a(Obj,Mod:typeID()) of
- true ->
- ok;
- false ->
- orber:dbg("[~p] CosNotification_Common:type_check(~p);~n"
- "The supplied Object is not or does not inherrit from: ~p",
- [?LINE, Obj, Mod], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO});
- {'EXCEPTION', E} ->
- orber:dbg("[~p] CosNotification_Common:type_check(~p, ~p);~n"
- "Failed due to: ~p",
- [?LINE, Obj, Mod, E], ?DEBUG_LEVEL),
- corba:raise(E);
- What ->
- orber:dbg("[~p] CosNotification_Common:type_check(~p, ~p);~n"
- "Failed due to: ~p",
- [?LINE, Obj, Mod, What], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO})
- end
- end.
-
-
-%%-----------------------------------------------------------%
-%% function : notify
-%% Arguments: Items - [Item]
-%% Item - {proxy, IOR} | {client, IOR} | {reason, term()}
-%% Returns : 'ok' or raises exception.
-%% Effect :
-%%------------------------------------------------------------
-notify(Items) ->
- case cosNotificationApp:notify() of
- false ->
- ok;
- Module ->
- catch Module:terminated(Items),
- ok
- end.
-
-
-%%------------------------------------------------------------
-%% function : send_stubborn
-%% Arguments: M - module
-%% F - function
-%% A - arguments
-%% MaxR - Maximum no retries
-%% Wait - sleep Wait seconds before next try.
-%% Returns : see effect
-%% Exception:
-%% Effect : Retries repeatidly untill anything else besides
-%% 'EXIT', 'COMM_FAILURE' or 'OBJECT_NOT_EXIST'
-%%------------------------------------------------------------
-
-send_stubborn(M, F, A, MaxR, Wait) when is_list(A) ->
- send_stubborn(M, F, A, MaxR, Wait, 0);
-send_stubborn(M, F, A, MaxR, Wait) ->
- send_stubborn(M, F, [A], MaxR, Wait, 0).
-send_stubborn(M, F, A, MaxR, _Wait, MaxR) ->
- orber:dbg("[~p] CosNotification_Common:send_stubborn( ~p ~p ~p ~p).~n"
- "Failed to deliver the event.~n", [?LINE, M,F,A,MaxR], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO});
-send_stubborn(M, F, A, MaxR, Wait, Times) ->
- ?debug_print("~p:~p(~p) # of retries: ~p~n", [M,F,A, Times]),
- case catch apply(M,F,A) of
- {'EXCEPTION', E} when is_record(E, 'COMM_FAILURE')->
- NewTimes = Times +1,
- timer:sleep(Wait),
- send_stubborn(M, F, A, MaxR, Wait, NewTimes);
- {'EXIT', _} ->
- NewTimes = Times +1,
- timer:sleep(Wait),
- send_stubborn(M, F, A, MaxR, Wait, NewTimes);
- Other ->
- Other
- end.
-
-
-%%-----------------------------------------------------------%
-%% function : disconnect
-%% Arguments: Module - one of the interfaces defined in CosEventComm.
-%% Function - the appropriate disconnect function.
-%% Object - the client object reference.
-%% Returns : ok
-%% Exception:
-%% Effect : If the process would try to diconnect itself it could
-%% result in a deadlock. Hence, we spawn a new process to do it.
-%%------------------------------------------------------------
-disconnect(Module, Function, Object) ->
- spawn(?MODULE, do_disconnect, [Module, Function, Object]),
- ok.
-
-do_disconnect(Module, Function, Object) ->
- catch Module:Function(Object),
- ?DBG("Disconnect ~p:~p(..).~n", [Module, Function]),
- ok.
-
-
-
-%%------------------------------------------------------------
-%% function : is_debug_compiled
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-
--ifdef(debug).
- is_debug_compiled() -> true.
--else.
- is_debug_compiled() -> false.
--endif.
-
-
-%%------------------------------------------------------------
-%%--------------- AdminPropertiesAdmin -----------------------
-%%------------------------------------------------------------
-%%------------------------------------------------------------
-%% function : init_adm
-%% Arguments: Wanted - requested Admins to be set.
-%% Returns : #'CosNotification_UnsupportedAdmin'{} |
-%% {NewAdmProperties, [MaxQ, MaxC, MaxS]}
-%% Effect : may only be used when creating a channel!!!!!!!!
-%%------------------------------------------------------------
-init_adm(Wanted) ->
- {NewA,_} = set_properties(Wanted, ?not_DEFAULT_ADMINPROPERTIES, channelAdm,
- ?not_SUPPORTED_ADMINPROPERTIES, [], [],
- false, false, false),
- {NewA, [extract_value(NewA, ?not_MaxQueueLength),
- extract_value(NewA, ?not_MaxConsumers),
- extract_value(NewA, ?not_MaxSuppliers)]}.
-
-set_adm(Wanted, Current) ->
- {NewA,_} = set_properties(Wanted, Current, channelAdm,
- ?not_SUPPORTED_ADMINPROPERTIES,
- [], [], false, false, false),
- {NewA, [extract_value(NewA, ?not_MaxQueueLength),
- extract_value(NewA, ?not_MaxConsumers),
- extract_value(NewA, ?not_MaxSuppliers)]}.
-
-'MaxQueueLength'(Req,channelAdm,_, _, _, _) -> admin_ok(Req).
-'MaxConsumers'(Req,channelAdm,_, _, _, _)-> admin_ok(Req).
-'MaxSuppliers'(Req,channelAdm,_, _, _, _)-> admin_ok(Req).
-
-admin_ok(Req) ->
- case any:get_value(Req#'CosNotification_Property'.value) of
- Val when is_integer(Val) andalso Val >= 0 ->
- {ok, Req};
- _ ->
- {unsupported,
- #'CosNotification_PropertyError'{
- code = 'BAD_TYPE',
- name = Req#'CosNotification_Property'.name,
- available_range = #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:null(), null),
- high_val=any:create(orber_tc:null(), null)
- }
- }
- }
- end.
-
-
-%%------------------------------------------------------------
-%%--------------- QOS FUNCTIONS ------------------------------
-%%------------------------------------------------------------
-%%------------------------------------------------------------
-%% function : init_qos
-%% Arguments: Wanted - requested QoS to be set.
-%% Returns : see set_properties/9
-%% Effect : may only be used when creating a channel!!!!!!!!
-%%------------------------------------------------------------
-init_qos(Wanted) ->
- LQS = set_local_qos(?not_DEFAULT_QOS, ?not_CreateInitQoS()),
- set_properties(Wanted, ?not_DEFAULT_QOS, channel, ?not_SUPPORTED_QOS,
- [], [], false, [], LQS).
-
-%%------------------------------------------------------------
-%% function : set_qos/5
-%% Arguments: Wanted - requested QoS to be set.
-%% Current - current QoS OMG style
-%% LQS - local representation of QoS.
-%% Type - channel | admin | proxy
-%% Parent - Factory if Channel, Channel if Admin etc
-%% Childs - Admins if Channel etc
-%% Returns : see set_properties/9
-%%------------------------------------------------------------
-set_qos(Wanted, {Current, LQS}, proxy, Parent, _) ->
- set_properties(Wanted, Current, proxy, ?not_SUPPORTED_QOS, [], [], Parent, false,LQS);
-set_qos(Wanted, {Current, LQS}, admin, Parent, Childs) ->
- set_properties(Wanted, Current, admin, ?not_SUPPORTED_QOS, [], [], Parent, Childs,LQS);
-set_qos(Wanted, {Current, LQS}, channel, _, Childs) ->
- set_properties(Wanted, Current, channel, ?not_SUPPORTED_QOS, [], [], false, Childs,LQS).
-
-%%------------------------------------------------------------
-%% function :
-%% Arguments: Req - Requested QoS, #'CosNotification_Property'{}
-%% Type - Requestee, channel | admin | proxy
-%% Curr - Current QoS, #'CosNotification_Property'{}
-%% Parent - false | ObjRef
-%% Childs - false | [ObjRef1, .., ObjRefN]
-%% LQS - #qos{} defined in CosNotification_Definitions.hrl
-%% Returns : ok - if requested equal to current value.
-%% {ok, Req, LQS} - if new and allowed QoS
-%% {unsupported,#'CosNotification_PropertyError'{}} otherwise.
-%% Effect :
-%%------------------------------------------------------------
-'EventReliability'(Req,channel, _Curr, _Parent, _Childs, LQS) ->
- case {any:get_value(Req#'CosNotification_Property'.value),
- ?not_GetConnectionReliability(LQS), ?not_BestEffort, ?not_Persistent} of
- {Val, Val, _, _} ->
- %% Is the value requested.
- ok;
- {Val, _, Val, _} ->
- {ok, Req, LQS};
- {Val, _, _, Val} ->
- {ok, Req, LQS};
- _->
- {unsupported,
- #'CosNotification_PropertyError'{
- code = 'BAD_TYPE',
- name = Req#'CosNotification_Property'.name,
- available_range = #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:null(), null),
- high_val=any:create(orber_tc:null(), null)
- }
- }
- }
- end;
-'EventReliability'(Req,_,_,_,_,_) ->
- %% only valid to set this QoS for channels (or per-event).
- {unsupported,
- #'CosNotification_PropertyError'{
- code = 'UNAVAILABLE_PROPERTY',
- name = Req#'CosNotification_Property'.name,
- available_range = #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:null(), null),
- high_val=any:create(orber_tc:null(), null)
- }
- }
- }.
-
-%%------------------------------------------------------------
-%% function : 'ConnectionReliability'/6
-%% Arguments: Req - Requested QoS, #'CosNotification_Property'{}
-%% Type - Requestee, channel | admin | proxy
-%% Curr - Current QoS, #'CosNotification_Property'{}
-%% Parent - false | ObjRef
-%% Childs - false | [ObjRef1, .., ObjRefN]
-%% LQS - #qos{} defined in CosNotification_Definitions.hrl
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-%% The most complex QoS to set is ConnectionReliability, and the reason for this
-%% is that we cannot set the Channel to offer best effort while its children
-%% offer persistent. A child may only offer Persistent if its parent do, which
-%% is why we must check the following:
-%%
-%% # Persistent Change to Best Effort
-%% _____
-%% | | (1) -> Check if children BE
-%% |Chann| (2) ok <-
-%% -----
-%% |
-%% _____
-%% | | (3) -> Check if children BE
-%% |Admin| (4) Check if parent Pers. <-
-%% -----
-%% |
-%% _____
-%% | | (5) -> ok
-%% |Proxy| (6) Check if parent Pers. <-
-%% -----
-%% NOTE: a parent always exists but we may change the QoS before creating any
-%% childrens. The cases (2) and (5) is always ok, i.e., no need to confirm
-%% with parent or children.
-%%------------------------------------------------------------
-'ConnectionReliability'(Req, channel, _Curr, _Parent, Childs, LQS) ->
- case {any:get_value(Req#'CosNotification_Property'.value),
- ?not_GetConnectionReliability(LQS), ?not_BestEffort, ?not_Persistent} of
- {Val, Val, _, _} ->
- %% Is the value requested.
- ok;
- {Val, P, Val, P} ->
- %% Requested is BestEffort, Current Persistent => (1)
- check_with_relatives(Childs, Req, LQS);
- {Val, B, B, Val} ->
- %% Requested is Persistent, Current BestEffort => (2)
- {ok, Req, LQS};
- _->
- {unsupported,
- #'CosNotification_PropertyError'{
- code = 'BAD_TYPE',
- name = Req#'CosNotification_Property'.name,
- available_range = #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:null(), null),
- high_val=any:create(orber_tc:null(), null)
- }
- }
- }
- end;
-'ConnectionReliability'(Req, admin, _Curr, Parent, Childs, LQS) ->
- case {any:get_value(Req#'CosNotification_Property'.value),
- ?not_GetConnectionReliability(LQS), ?not_BestEffort, ?not_Persistent} of
- {Val, Val, _, _} ->
- %% Is the value requested.
- ok;
- {Val, P, Val, P} ->
- %% Requested is BestEffort, Current Persistent => (3)
- check_with_relatives(Childs, Req, LQS);
- {Val, B, B, Val} ->
- %% Requested is Persistent, Current BestEffort => (4)
- check_with_relatives([Parent], Req, LQS);
- _->
- {unsupported,
- #'CosNotification_PropertyError'{
- code = 'BAD_TYPE',
- name = Req#'CosNotification_Property'.name,
- available_range = #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:null(), null),
- high_val=any:create(orber_tc:null(), null)
- }
- }
- }
- end;
-'ConnectionReliability'(Req, proxy, _Curr, Parent, _Childs, LQS) ->
- case {any:get_value(Req#'CosNotification_Property'.value),
- ?not_GetConnectionReliability(LQS), ?not_BestEffort, ?not_Persistent} of
- {Val, Val, _, _} ->
- %% Is the value requested.
- ok;
- {Val, P, Val, P} ->
- %% Requested is BestEffort, Current Persistent => (5)
- {ok, Req, LQS};
- {Val, B, B, Val} ->
- %% Requested is Persistent, Current BestEffort => (6)
- check_with_relatives([Parent], Req, LQS);
- _->
- {unsupported,
- #'CosNotification_PropertyError'{
- code = 'BAD_TYPE',
- name = Req#'CosNotification_Property'.name,
- available_range = #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:null(), null),
- high_val=any:create(orber_tc:null(), null)
- }
- }
- }
- end.
-
-%%------------------------------------------------------------
-%% function : 'Priority'/6
-%% Arguments: Req - Requested QoS, #'CosNotification_Property'{}
-%% Type - Requestee, channel | admin | proxy
-%% Curr - Current QoS, #'CosNotification_Property'{}
-%% Parent - false | ObjRef
-%% Childs - false | [ObjRef1, .., ObjRefN]
-%% LQS - #qos{} defined in CosNotification_Definitions.hrl
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-'Priority'(Req, _Type, _Curr, _Parent, _Childs, LQS) ->
- case {any:get_value(Req#'CosNotification_Property'.value),
- ?not_GetPriority(LQS), ?not_HighestPriority, ?not_LowestPriority} of
- {Val, Val, _, _} ->
- ok;
- {Val, _, H, L} when Val =< H, Val >= L ->
- {ok, Req, LQS};
- {_, _, H, L} ->
- {unsupported,
- #'CosNotification_PropertyError'{
- code = 'BAD_VALUE',
- name = Req#'CosNotification_Property'.name,
- available_range =
- #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:short(), L),
- high_val=any:create(orber_tc:short(), H)
- }
- }
- }
- end.
-
-%%------------------------------------------------------------
-%% function : 'StartTimeSupported'/6
-%% Arguments: Req - Requested QoS, #'CosNotification_Property'{}
-%% Type - Requestee, channel | admin | proxy
-%% Curr - Current QoS, #'CosNotification_Property'{}
-%% Parent - false | ObjRef
-%% Childs - false | [ObjRef1, .., ObjRefN]
-%% LQS - #qos{} defined in CosNotification_Definitions.hrl
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-'StartTimeSupported'(Req, _Type, _Curr, _, _, LQS) ->
- case {any:get_value(Req#'CosNotification_Property'.value),
- ?not_GetStartTimeSupported(LQS)} of
- {Val, Val} ->
- ok;
- {Val, _} when Val =/= true, Val =/= false ->
- {unsupported,
- #'CosNotification_PropertyError'{
- code = 'BAD_VALUE',
- name = Req#'CosNotification_Property'.name,
- available_range =
- #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:boolean(), false),
- high_val=any:create(orber_tc:boolean(), true)
- }
- }
- };
- _->
- {ok, Req, LQS}
- end.
-
-%%------------------------------------------------------------
-%% function : 'StopTimeSupported'/6
-%% Arguments: Req - Requested QoS, #'CosNotification_Property'{}
-%% Type - Requestee, channel | admin | proxy
-%% Curr - Current QoS, #'CosNotification_Property'{}
-%% Parent - false | ObjRef
-%% Childs - false | [ObjRef1, .., ObjRefN]
-%% LQS - #qos{} defined in CosNotification_Definitions.hrl
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-'StopTimeSupported'(Req, _Type, _Curr, _, _, LQS) ->
- case {any:get_value(Req#'CosNotification_Property'.value),
- ?not_GetStopTimeSupported(LQS)} of
- {Val, Val} ->
- ok;
- {Val, _} when Val =/= true, Val =/= false ->
- {unsupported,
- #'CosNotification_PropertyError'{
- code = 'BAD_VALUE',
- name = Req#'CosNotification_Property'.name,
- available_range =
- #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:boolean(), false),
- high_val=any:create(orber_tc:boolean(), true)
- }
- }
- };
- _->
- {ok, Req, LQS}
- end.
-
-%%------------------------------------------------------------
-%% function : 'Timeout'/6
-%% Arguments: Req - Requested QoS, #'CosNotification_Property'{}
-%% Type - Requestee, channel | admin | proxy
-%% Curr - Current QoS, #'CosNotification_Property'{}
-%% Parent - false | ObjRef
-%% Childs - false | [ObjRef1, .., ObjRefN]
-%% LQS - #qos{} defined in CosNotification_Definitions.hrl
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-'Timeout'(Req, _Type, _Curr, _Parent, _Childs, LQS) ->
- case {any:get_value(Req#'CosNotification_Property'.value),
- ?not_GetTimeout(LQS)} of
- {Val, Val} ->
- ok;
- {Val, _} when Val >= ?not_MinTimeout, Val =< ?not_MaxTimeout ->
- {ok, Req, LQS};
- {Val, _} when is_integer(Val) ->
- {unsupported,
- #'CosNotification_PropertyError'{
- code = 'BAD_VALUE',
- name = Req#'CosNotification_Property'.name,
- available_range =
- #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:unsigned_long_long(), ?not_MinTimeout),
- high_val=any:create(orber_tc:unsigned_long_long(), ?not_MaxTimeout)
- }
- }
- };
- _->
- {unsupported,
- #'CosNotification_PropertyError'{
- code = 'BAD_TYPE',
- name = Req#'CosNotification_Property'.name,
- available_range = #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:null(), null),
- high_val=any:create(orber_tc:null(), null)
- }
- }
- }
- end.
-
-%%------------------------------------------------------------
-%% function : 'OrderPolicy'/6
-%% Arguments: Req - Requested QoS, #'CosNotification_Property'{}
-%% Type - Requestee, channel | admin | proxy
-%% Curr - Current QoS, #'CosNotification_Property'{}
-%% Parent - false | ObjRef
-%% Childs - false | [ObjRef1, .., ObjRefN]
-%% LQS - #qos{} defined in CosNotification_Definitions.hrl
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-'OrderPolicy'(Req, _Type, _Curr, _Parent, _Childs, LQS) ->
- case {any:get_value(Req#'CosNotification_Property'.value),
- ?not_GetOrderPolicy(LQS), 'CosNotification':'AnyOrder'(),
- 'CosNotification':'PriorityOrder'()} of
- {Val, Val,_,_} ->
- ok;
- {Val, _, L, H} when Val >= L, Val =< H ->
- {ok, Req, LQS};
- {Val, _, L, H} when is_integer(Val) ->
- {unsupported,
- #'CosNotification_PropertyError'{
- code = 'BAD_VALUE',
- name = Req#'CosNotification_Property'.name,
- available_range =
- #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:short(), L),
- high_val=any:create(orber_tc:short(), H)
- }
- }
- };
- _->
- {unsupported,
- #'CosNotification_PropertyError'{
- code = 'BAD_TYPE',
- name = Req#'CosNotification_Property'.name,
- available_range = #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:null(), null),
- high_val=any:create(orber_tc:null(), null)
- }
- }
- }
- end.
-
-
-%%------------------------------------------------------------
-%% function : 'DiscardPolicy'/6
-%% Arguments: Req - Requested QoS, #'CosNotification_Property'{}
-%% Type - Requestee, channel | admin | proxy
-%% Curr - Current QoS, #'CosNotification_Property'{}
-%% Parent - false | ObjRef
-%% Childs - false | [ObjRef1, .., ObjRefN]
-%% LQS - #qos{} defined in CosNotification_Definitions.hrl
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-'DiscardPolicy'(Req, _Type, _Curr, _Parent, _Childs, LQS) ->
- case {any:get_value(Req#'CosNotification_Property'.value),
- ?not_GetDiscardPolicy(LQS), ?not_AnyOrder, ?not_PriorityOrder} of
- {Val, Val,_,_} ->
- ok;
- {Val, _, L, H} when Val >= L, Val =< H ->
- {ok, Req, LQS};
- {Val, _, L, H} when is_integer(Val) ->
- {unsupported,
- #'CosNotification_PropertyError'{
- code = 'BAD_VALUE',
- name = Req#'CosNotification_Property'.name,
- available_range =
- #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:short(), L),
- high_val=any:create(orber_tc:short(), H)
- }
- }
- };
- _->
- {unsupported,
- #'CosNotification_PropertyError'{
- code = 'BAD_TYPE',
- name = Req#'CosNotification_Property'.name,
- available_range = #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:null(), null),
- high_val=any:create(orber_tc:null(), null)
- }
- }
- }
- end.
-
-%%------------------------------------------------------------
-%% function : 'DiscardPolicy'/6
-%% Arguments: Req - Requested QoS, #'CosNotification_Property'{}
-%% Type - Requestee, channel | admin | proxy
-%% Curr - Current QoS, #'CosNotification_Property'{}
-%% Parent - false | ObjRef
-%% Childs - false | [ObjRef1, .., ObjRefN]
-%% LQS - #qos{} defined in CosNotification_Definitions.hrl
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-'MaximumBatchSize'(Req, _Type, _Curr, _Parent, _Childs, LQS) ->
- case {any:get_value(Req#'CosNotification_Property'.value),
- ?not_GetMaximumBatchSize(LQS)} of
- {Val, Val} ->
- ok;
- {Val, _} when Val >= ?not_MinBatchSize, Val =< ?not_MaxBatchSize ->
- {ok, Req, LQS};
- {Val, _} when is_integer(Val) ->
- {unsupported,
- #'CosNotification_PropertyError'{
- code = 'BAD_VALUE',
- name = Req#'CosNotification_Property'.name,
- available_range =
- #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:unsigned_long_long(), ?not_MinBatchSize),
- high_val=any:create(orber_tc:unsigned_long_long(), ?not_MaxBatchSize)
- }
- }
- };
- _->
- {unsupported,
- #'CosNotification_PropertyError'{
- code = 'UNSUPPORTED_VALUE',
- name = Req#'CosNotification_Property'.name,
- available_range =
- #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:long(), ?not_MinBatchSize),
- high_val=any:create(orber_tc:long(), ?not_MaxBatchSize)
- }
- }
- }
- end.
-
-%%------------------------------------------------------------
-%% function : 'PacingInterval'/6
-%% Arguments: Req - Requested QoS, #'CosNotification_Property'{}
-%% Type - Requestee, channel | admin | proxy
-%% Curr - Current QoS, #'CosNotification_Property'{}
-%% Parent - false | ObjRef
-%% Childs - false | [ObjRef1, .., ObjRefN]
-%% LQS - #qos{} defined in CosNotification_Definitions.hrl
-%% Returns :
-%% Comment : PacingInterval is defined to be:
-%% * TimeBase::UtcT (p 57, 2.5.5, OMG TC Document telecom/98-11-01)
-%% * TimeBase::TimeT (p 189, appendix B, OMG TC Document telecom/98-11-01)
-%% This implementation use TimeBase::TimeT, especially since
-%% TimeBase::UtcT contains information which are of no importance.
-%% When writing this, the OMG homepage contained no information
-%% regarding this.
-%%------------------------------------------------------------
-'PacingInterval'(Req, _Type, _Curr, _Parent, _Childs, LQS) ->
- case {any:get_value(Req#'CosNotification_Property'.value),
- ?not_GetPacingInterval(LQS)} of
- {Val, Val} ->
- ok;
- {Val, _} when Val >= ?not_MinPacing, Val =< ?not_MaxPacing ->
- {ok, Req, LQS};
- {Val, _} when is_integer(Val) ->
- {unsupported,
- #'CosNotification_PropertyError'{
- code = 'BAD_VALUE',
- name = Req#'CosNotification_Property'.name,
- available_range =
- #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:unsigned_long_long(), ?not_MinPacing),
- high_val=any:create(orber_tc:unsigned_long_long(), ?not_MaxPacing)
- }
- }
- };
- _->
- {unsupported,
- #'CosNotification_PropertyError'{
- code = 'BAD_TYPE',
- name = Req#'CosNotification_Property'.name,
- available_range = #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:null(), null),
- high_val=any:create(orber_tc:null(), null)
- }
- }
- }
- end.
-
-%%------------------------------------------------------------
-%% function : 'MaxEventsPerConsumer'/6
-%% Arguments: Req - Requested QoS, #'CosNotification_Property'{}
-%% Type - Requestee, channel | admin | proxy
-%% Curr - Current QoS, #'CosNotification_Property'{}
-%% Parent - false | ObjRef
-%% Childs - false | [ObjRef1, .., ObjRefN]
-%% LQS - #qos{} defined in CosNotification_Definitions.hrl
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-'MaxEventsPerConsumer'(Req, _Type, _Curr, _Parent, _Childs, LQS) ->
- case {any:get_value(Req#'CosNotification_Property'.value),
- ?not_GetMaxEventsPerConsumer(LQS)} of
- {Val, Val} ->
- ok;
- {Val, _} when is_integer(Val) andalso
- Val >= ?not_MinConsumerEvents andalso
- Val =< ?not_MaxConsumerEvents ->
- {ok, Req, LQS};
- {Val, _} when is_integer(Val) ->
- {unsupported,
- #'CosNotification_PropertyError'{
- code = 'BAD_VALUE',
- name = Req#'CosNotification_Property'.name,
- available_range =
- #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:unsigned_long_long(), ?not_MinConsumerEvents),
- high_val=any:create(orber_tc:unsigned_long_long(), ?not_MaxConsumerEvents)
- }
- }
- };
- _->
- {unsupported,
- #'CosNotification_PropertyError'{
- code = 'UNSUPPORTED_VALUE',
- name = Req#'CosNotification_Property'.name,
- available_range =
- #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:long(), ?not_MinConsumerEvents),
- high_val=any:create(orber_tc:long(), ?not_MaxConsumerEvents)
- }
- }
- }
- end.
-
-%%------------------------------------------------------------
-%% function : validate_qos/5
-%% Arguments: Wanted - requested QoS to be set.
-%% Curr - current QoS OMG style and LQS, local
-%% representation of QoS, grouped as {OMGQ, LQS}
-%% Type - channel | admin | proxy
-%% Parent - Factory if Channel, Channel if Admin etc
-%% Childs - Admins if Channel etc
-%% Returns : NamedPropertySeq | #'CosNotification_UnsupportedQoS'{}
-%% case 1 if all supported, case 2 if at least 1 QoS not
-%% supported.
-%% See also p59, 2.5.6.4, OMG TC Document telecom/98-11-01. Quote:
-%% "If the supplied QoS is supported, it returns additional QoS
-%% properties which could be optionally added as well."
-%%------------------------------------------------------------
-validate_qos(Wanted, Curr, Type, Parent, Childs) ->
- %% If not supported this function will raise an exception, which we should
- %% not catch, but all we need to is to raise the exception as it is.
- {_, LQS}=set_qos(Wanted, Curr, Type, Parent, Childs),
- NewNPR = check_limits(LQS, ?not_QOS_LIMITS),
- remove_qos(Wanted, LQS, NewNPR).
-
-remove_qos([], _, NPR) ->
- NPR;
-remove_qos([H|T], LQS, NPR) ->
- NewNPR=remove(NPR, H#'CosNotification_Property'.name),
- remove_qos(T, LQS, NewNPR).
-
-check_limits(LQS, NPR) ->
- case {?not_GetEventReliability(LQS), ?not_GetConnectionReliability(LQS),
- ?not_Persistent, ?not_BestEffort} of
- {P,P,P,_B} ->
- New = #'CosNotification_NamedPropertyRange'
- {name=?not_EventReliability,
- range=
- #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:short(), ?not_BestEffort),
- high_val=any:create(orber_tc:short(), ?not_BestEffort)
- }},
- NewNPR=change(NPR, ?not_EventReliability, New),
- remove(NewNPR, ?not_ConnectionReliability);
- {_,B,_P,B} ->
- remove(NPR, ?not_EventReliability);
- {B,P,P,B} ->
- New = #'CosNotification_NamedPropertyRange'
- {name=?not_ConnectionReliability,
- range=
- #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:short(), ?not_BestEffort),
- high_val=any:create(orber_tc:short(), ?not_BestEffort)
- }},
- change(NPR, ?not_ConnectionReliability, New)
- end.
-
-%%------------------------------------------------------------
-%% function : validate_event_qos/2
-%% Arguments: Wanted - requested QoS to be set.
-%% Curr - LQS, local representation of QoS
-%% Returns : NamedPropertySeq | #'CosNotification_UnsupportedQoS'{}
-%% case 1 if all supported, case 2 if at least 1 QoS not
-%% supported.
-%%------------------------------------------------------------
-validate_event_qos(Wanted, Curr) ->
- case v_e_q_helper(Wanted, Curr, []) of
- ok ->
- [];
- {error, Unsupp} ->
- corba:raise(#'CosNotification_UnsupportedQoS'{qos_err = Unsupp})
- end.
-
-v_e_q_helper([], _Curr, []) ->
- %% Parsed all and found no conflicts.
- ok;
-v_e_q_helper([], _Curr, Unsupp) ->
- %% Not possible to use these requested QoS.
- {error, Unsupp};
-
-%%--- EventReliability ---%%
-v_e_q_helper([#'CosNotification_Property'{name=?not_EventReliability,
- value=#any{value=?not_BestEffort}}|T], Curr, Unsupp) ->
- %% Always ok.
- v_e_q_helper(T, Curr, Unsupp);
-v_e_q_helper([#'CosNotification_Property'{name=?not_EventReliability,
- value=#any{value=?not_Persistent}}|T], Curr, Unsupp)
- when ?not_GetConnectionReliability(Curr) =/= ?not_BestEffort,
- ?not_GetEventReliability(Curr) =/= ?not_BestEffort,
- ?not_GetStopTimeSupported(Curr) =/= true ->
- v_e_q_helper(T, Curr, Unsupp);
-v_e_q_helper([#'CosNotification_Property'{name=?not_EventReliability}|T],
- Curr, Unsupp) ->
- %% Impossible to set to Persistent if the connection reliability is best effort.
- v_e_q_helper(T, Curr, [#'CosNotification_PropertyError'
- {code = 'UNAVAILABLE_VALUE', name = ?not_EventReliability,
- available_range =
- #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:null(), null),
- high_val=any:create(orber_tc:null(), null)}}|Unsupp]);
-
-%%--- Priority ---%%
-v_e_q_helper([#'CosNotification_Property'{name=?not_Priority, value=#any{value=V}}|T], Curr,
- Unsupp) ->
- if
- ?not_GetOrderPolicy(Curr) =/= ?not_AnyOrder,
- ?not_GetOrderPolicy(Curr) =/= ?not_Priority,
- ?not_GetDiscardPolicy(Curr) =/= ?not_Priority ->
- %% No use setting Priority since it's not currently used.
- v_e_q_helper(T, Curr, [#'CosNotification_PropertyError'
- {code = 'UNAVAILABLE_VALUE', name = ?not_Priority,
- available_range = #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:null(), null),
- high_val=any:create(orber_tc:null(), null)
- }}|Unsupp]);
- V =< ?not_HighestPriority, V >= ?not_LowestPriority ->
- v_e_q_helper(T, Curr, Unsupp);
- true ->
- v_e_q_helper(T, Curr, [#'CosNotification_PropertyError'
- {code = 'BAD_VALUE', name = ?not_Priority,
- available_range =
- #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:short(),
- ?not_LowestPriority),
- high_val=any:create(orber_tc:short(),
- ?not_HighestPriority)}}|Unsupp])
- end;
-
-%%--- StartTime ---%%
-v_e_q_helper([#'CosNotification_Property'{name=?not_StartTime}|T], Curr, Unsupp)
- when ?not_GetStartTimeSupported(Curr) =/= false,
- ?not_GetEventReliability(Curr) =/= ?not_Persistent ->
- v_e_q_helper(T, Curr, Unsupp);
-v_e_q_helper([#'CosNotification_Property'{name=?not_StartTime}|T], Curr, Unsupp) ->
- v_e_q_helper(T, Curr, [#'CosNotification_PropertyError'
- {code = 'UNAVAILABLE_VALUE', name = ?not_StartTime,
- available_range = #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:null(), null),
- high_val=any:create(orber_tc:null(), null)
- }}|Unsupp]);
-
-%%--- StopTime ---%%
-v_e_q_helper([#'CosNotification_Property'{name=?not_StopTime}|T], Curr, Unsupp)
- when ?not_GetStopTimeSupported(Curr) =/= false,
- ?not_GetEventReliability(Curr) =/= ?not_Persistent ->
- v_e_q_helper(T, Curr, Unsupp);
-v_e_q_helper([#'CosNotification_Property'{name=?not_StopTime}|T], Curr, Unsupp) ->
- v_e_q_helper(T, Curr, [#'CosNotification_PropertyError'
- {code = 'UNAVAILABLE_VALUE', name = ?not_StopTime,
- available_range = #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:null(), null),
- high_val=any:create(orber_tc:null(), null)
- }}|Unsupp]);
-
-%%--- Timeout ---%%
-v_e_q_helper([#'CosNotification_Property'{name=?not_Timeout}|T], Curr, Unsupp)
- when ?not_GetStopTimeSupported(Curr) =/= false,
- ?not_GetEventReliability(Curr) =/= ?not_Persistent ->
- v_e_q_helper(T, Curr, Unsupp);
-v_e_q_helper([#'CosNotification_Property'{name=?not_Timeout}|T], Curr, Unsupp) ->
- v_e_q_helper(T, Curr, [#'CosNotification_PropertyError'
- {code = 'UNAVAILABLE_VALUE', name = ?not_Timeout,
- available_range = #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:null(), null),
- high_val=any:create(orber_tc:null(), null)
- }}|Unsupp]);
-
-%%--- Unknown Event QoS ---%%
-v_e_q_helper([#'CosNotification_Property'{name=Name}|T], Curr, Unsupp) ->
- %% Unsupported property.
- v_e_q_helper(T, Curr, [#'CosNotification_PropertyError'
- {code = 'BAD_PROPERTY', name = Name,
- available_range = #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:null(), null),
- high_val=any:create(orber_tc:null(), null)
- }}|Unsupp]);
-v_e_q_helper(What, _, _) ->
- %% Not a Property struct.
- orber:dbg("[~p] CosNotification_Common:v_e_q_helper(~p);~n"
- "Not a CosNotification_Property struct.",
- [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%-------------- QOS HELP FUNCTIONS --------------------------
-%%------------------------------------------------------------
-%% function : set_properties/9
-%% Arguments: Wanted - requested QoS to be set.
-%% Current - current QoS OMG style
-%% Type - channel | admin | proxy
-%% Supported - List of supported QoS
-%% Unsupp - acc
-%% NewQoS - acc
-%% Parent - Factory if Channel, Channel if Admin etc
-%% Childs - Admins if Channel etc
-%% LQS - local representation of QoS.
-%% Returns : {NewOMGStyleQoS, NewLocalQoS} | #'CosNotification_UnsupportedQoS'{}
-%%------------------------------------------------------------
-set_properties(Wanted, Current, Type, Supported, Unsupp, NewQoS, Parent, Childs, LQS) ->
- case do_set_properties(Wanted, Current, Type, Supported, Unsupp, NewQoS, Parent, Childs, LQS) of
- {error, Exc} ->
- corba:raise(Exc);
- Result ->
- Result
- end.
-
-do_set_properties([], Curr, channelAdm, _, [], NewQoS,_,_,LAS) ->
- merge_properties(NewQoS, Curr, LAS);
-do_set_properties([], Curr, _, _, [], NewQoS,_,_,LQS) ->
- %% set_local_qos and merge_properties are help functions found at the end of QoS
- %% functions.
- NewLQS = set_local_qos(NewQoS, LQS),
- merge_properties(NewQoS, Curr, NewLQS);
-do_set_properties([], _, channelAdm, _, Unsupp, _,_,_,_) ->
- {error, #'CosNotification_UnsupportedAdmin'{admin_err = Unsupp}};
-do_set_properties([], _, _, _, Unsupp, _,_,_,_) ->
- {error, #'CosNotification_UnsupportedQoS'{qos_err = Unsupp}};
-
-do_set_properties([Req|Tail], Curr, Type, Supported, Unsupp, NewQoS, Parent, Childs,LQS) ->
- %% set_values and is_supported are help functions found at the end of QoS
- %% functions.
- case set_values(is_supported(Supported, Req), Req, Type, Curr, Parent, Childs,LQS) of
- {unsupported, U} ->
- do_set_properties(Tail, Curr, Type, Supported, [U|Unsupp], NewQoS, Parent, Childs,LQS);
- {ok, S, NewLQS} ->
- do_set_properties(Tail, Curr, Type, Supported, Unsupp, [S|NewQoS], Parent, Childs,NewLQS);
- {ok, S} ->
- do_set_properties(Tail, Curr, Type, Supported, Unsupp, [S|NewQoS], Parent, Childs,LQS);
- ok ->
- do_set_properties(Tail, Curr, Type, Supported, Unsupp, NewQoS, Parent, Childs,LQS)
- end.
-
-
-set_values(unsupported,Req,_,_,_,_,_) ->
- {unsupported,
- #'CosNotification_PropertyError'{
- code = 'BAD_PROPERTY',
- name = Req#'CosNotification_Property'.name,
- available_range = #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:null(), null),
- high_val=any:create(orber_tc:null(), null)
- }
- }
- };
-set_values({ok, Func}, Req, Type, Curr, Parent, Childs, LQS) ->
- ?MODULE:Func(Req, Type, Curr, Parent, Childs, LQS).
-
-%% Update OMG style QoS list with new values.
-merge_properties([], NewCurrQoS, LQS) ->
- {NewCurrQoS, LQS};
-merge_properties([H|T], Curr, LQS) ->
- merge_properties(T, lists:keyreplace(H#'CosNotification_Property'.name, %% get key.
- #'CosNotification_Property'.name, %% get index.
- Curr, H), LQS).
-
-%% Is the Property S among our supported QoS?
-is_supported([], _) ->
- unsupported;
-is_supported([{Name, Func}|_], #'CosNotification_Property'{name=Name}) ->
- {ok, Func};
-is_supported([_|T], S) ->
- is_supported(T, S).
-
-%% Find matching S-Property from a list of OMG style QoS
-extract([], _) -> unsupported;
-extract([H|_T], S) when H#'CosNotification_Property'.name==
- S#'CosNotification_Property'.name ->
- {ok, H};
-extract([_|T], S) -> extract(T,S).
-
-%% Find matching Property name from a list of OMG style QoS
-extract_value([], _) -> unsupported;
-extract_value([H|_T], Key) when H#'CosNotification_Property'.name== Key ->
- {ok, any:get_value(H#'CosNotification_Property'.value)};
-extract_value([_|T], Key) -> extract(T,Key).
-
-%% Remove matching S-QoS from a list of OMG style QoS
-remove(List, Key) ->
- lists:keydelete(Key,
- #'CosNotification_NamedPropertyRange'.name, %% get index.
- List).
-
-change(List, Key, New) ->
- lists:keyreplace(Key,
- #'CosNotification_NamedPropertyRange'.name, %% get index.
- List, New).
-%% Get QoS from supplied objects and check if it's the same as S.
-check_with_relatives([], S, LQS) ->
- {ok, S, LQS};
-check_with_relatives([undefined|T], S, LQS) ->
- check_with_relatives(T, S, LQS);
-check_with_relatives([H|T], S, LQS) ->
- case catch extract('CosNotification_QoSAdmin':get_qos(H), S) of
- {ok, S} ->
- check_with_relatives(T, S, LQS);
- _->
- %% Varioues reasons for this case (Object not responding, not supported)
- {unsupported,
- #'CosNotification_PropertyError'{
- code = 'UNAVAILABLE_PROPERTY',
- name = S#'CosNotification_Property'.name,
- available_range = #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:null(), null),
- high_val=any:create(orber_tc:null(), null)
- }
- }
- }
- end.
-
-%% Set new values to locally defined representation of QoS. Using this approach is
-%% necessary since we must state the record-field at compile-time.
-set_local_qos([], LQS) -> LQS;
-set_local_qos([#'CosNotification_Property'{name=N,value=V}|T], LQS) ->
- NewLQS =
- case N of
- "EventReliability" ->
- ?not_SetEventReliability(LQS, any:get_value(V));
- "ConnectionReliability" ->
- ?not_SetConnectionReliability(LQS, any:get_value(V));
- "Priority" ->
- ?not_SetPriority(LQS, any:get_value(V));
- "Timeout" ->
- ?not_SetTimeout(LQS, any:get_value(V));
- "OrderPolicy" ->
- ?not_SetOrderPolicy(LQS, any:get_value(V));
- "DiscardPolicy" ->
- ?not_SetDiscardPolicy(LQS, any:get_value(V));
- "MaximumBatchSize" ->
- ?not_SetMaximumBatchSize(LQS, any:get_value(V));
- "PacingInterval" ->
- ?not_SetPacingInterval(LQS, any:get_value(V));
- "StartTimeSupported" ->
- ?not_SetStartTimeSupported(LQS, any:get_value(V));
- "StopTimeSupported" ->
- ?not_SetStopTimeSupported(LQS, any:get_value(V));
- "MaxEventsPerConsumer" ->
- ?not_SetMaxEventsPerConsumer(LQS, any:get_value(V))
- end,
- set_local_qos(T, NewLQS).
-
-%%%%%%%%%%%%%%%%% END QOS FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/cosNotification/src/CosNotification_Definitions.hrl b/lib/cosNotification/src/CosNotification_Definitions.hrl
deleted file mode 100644
index 5d85c77a22..0000000000
--- a/lib/cosNotification/src/CosNotification_Definitions.hrl
+++ /dev/null
@@ -1,343 +0,0 @@
-%%----------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2015. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : CosNotification_Definitions.hrl
-%% Purpose :
-%%----------------------------------------------------------------------
-
--ifndef(COSNOTIFICATION_DEFINITIONS_HRL).
--define(COSNOTIFICATION_DEFINITIONS_HRL, true).
-
-%% ---------------- General comment ------------------------------------
-%% ******* README ********
-%% The prefix 'not' is short for notification, and is used to separate locally
-%% defined macros from the global ones, i.e., do NOT confuse this with a negation!!
-%%
-%% In this file you find globally used data structures, constants etc.
-%%
-
-%%--------------- INCLUDES ---------------------------------------------
-
-%%-------- Constants -------------------------------------------------
--define(not_SupportedGrammars, ["EXTENDED_TCL"]).
-
-%% !!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-%%
-%% If OMG redefines the values for the constants the definitions
-%% below must be redefined!!
-%%
-%% !!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
--define(not_BestEffort, 0).
--define(not_Persistent, 1).
--define(not_EventReliability, "EventReliability").
--define(not_ConnectionReliability, "ConnectionReliability").
--define(not_Priority, "Priority").
--define(not_LowestPriority, -32767).
--define(not_HighestPriority, 32767).
--define(not_DefaultPriority, 0).
--define(not_StartTime, "StartTime").
--define(not_StopTime, "StopTime").
--define(not_Timeout, "Timeout").
--define(not_OrderPolicy, "OrderPolicy").
--define(not_AnyOrder, 0).
--define(not_FifoOrder, 1).
--define(not_PriorityOrder, 2).
--define(not_DeadlineOrder, 3).
--define(not_DiscardPolicy, "DiscardPolicy").
--define(not_LifoOrder, 4).
--define(not_RejectNewEvents, 5).
--define(not_MaximumBatchSize, "MaximumBatchSize").
--define(not_PacingInterval, "PacingInterval").
--define(not_StartTimeSupported, "StartTimeSupported").
--define(not_StopTimeSupported, "StopTimeSupported").
--define(not_MaxEventsPerConsumer, "MaxEventsPerConsumer").
--define(not_MaxQueueLength, "MaxQueueLength").
--define(not_MaxConsumers, "MaxConsumers").
--define(not_MaxSuppliers, "MaxSuppliers").
-
-%%--------------- QOS DEFINITIONS ----------------------------
-%% Limits for QoS. These are our own limits.
--define(not_MaxBatchSize, 10000).
--define(not_MinBatchSize, 1).
--define(not_MinTimeout, 0).
--define(not_MaxTimeout, 100000000000).
--define(not_MinPacing, 0).
--define(not_MaxPacing, 100000000000).
--define(not_MinConsumerEvents, 1).
--define(not_MaxConsumerEvents, 10000).
-
--define(not_QOS_LIMITS,
-[#'CosNotification_NamedPropertyRange'
- {name=?not_EventReliability,
- range=
- #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:short(), ?not_BestEffort),
- high_val=any:create(orber_tc:short(), ?not_Persistent)
- }},
- #'CosNotification_NamedPropertyRange'
- {name=?not_ConnectionReliability,
- range=
- #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:short(), ?not_BestEffort),
- high_val=any:create(orber_tc:short(), ?not_Persistent)
- }},
- #'CosNotification_NamedPropertyRange'
- {name=?not_Priority,
- range=
- #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:short(), ?not_LowestPriority),
- high_val=any:create(orber_tc:short(), ?not_HighestPriority)
- }},
- #'CosNotification_NamedPropertyRange'
- {name=?not_StartTimeSupported,
- range=
- #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:boolean(), false),
- high_val=any:create(orber_tc:boolean(), true)
- }},
- #'CosNotification_NamedPropertyRange'
- {name=?not_StopTimeSupported,
- range=
- #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:boolean(), false),
- high_val=any:create(orber_tc:boolean(), true)
- }},
- #'CosNotification_NamedPropertyRange'
- {name=?not_Timeout,
- range=
- #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:unsigned_long_long(), ?not_MinTimeout),
- high_val=any:create(orber_tc:unsigned_long_long(), ?not_MaxTimeout)
- }},
- #'CosNotification_NamedPropertyRange'
- {name=?not_OrderPolicy,
- range=
- #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:short(), ?not_AnyOrder),
- high_val=any:create(orber_tc:short(), ?not_PriorityOrder)
- }},
- #'CosNotification_NamedPropertyRange'
- {name=?not_DiscardPolicy,
- range=
- #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:short(), ?not_AnyOrder),
- high_val=any:create(orber_tc:short(), ?not_PriorityOrder)
- }},
- #'CosNotification_NamedPropertyRange'
- {name=?not_MaximumBatchSize,
- range=
- #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:long(), ?not_MinBatchSize),
- high_val=any:create(orber_tc:long(), ?not_MaxBatchSize)
- }},
- #'CosNotification_NamedPropertyRange'
- {name=?not_PacingInterval,
- range=
- #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:unsigned_long_long(), ?not_MinPacing),
- high_val=any:create(orber_tc:unsigned_long_long(), ?not_MaxPacing)
- }},
- #'CosNotification_NamedPropertyRange'
- {name=?not_MaxEventsPerConsumer,
- range=
- #'CosNotification_PropertyRange'{
- low_val=any:create(orber_tc:long(), ?not_MinConsumerEvents),
- high_val=any:create(orber_tc:long(), ?not_MaxConsumerEvents)
- }}
-]).
-
-
-
-%% Local record used internally, and the reason for this is we get faster
-%% access to QoS settings.
--record(qos, {'EventReliability',
- 'ConnectionReliability',
- 'Priority',
- 'StartTimeSupported',
- 'StopTimeSupported',
- 'Timeout',
- 'OrderPolicy',
- 'DiscardPolicy',
- 'MaximumBatchSize',
- 'PacingInterval',
- 'MaxEventsPerConsumer'}).
-
-%% Global (OMG) representation of QoS.
--define(not_DEFAULT_QOS,
-[#'CosNotification_Property'{name=?not_MaximumBatchSize,
- value=any:create(orber_tc:long(), 1)},
- #'CosNotification_Property'{name=?not_PacingInterval,
- value=any:create(orber_tc:unsigned_long_long(), 0)},
- #'CosNotification_Property'{name=?not_Timeout,
- value=any:create(orber_tc:unsigned_long_long(), 0)},
- #'CosNotification_Property'{name=?not_MaxEventsPerConsumer,
- value=any:create(orber_tc:long(), 100)},
- #'CosNotification_Property'{name=?not_OrderPolicy,
- value=any:create(orber_tc:short(),
- ?not_PriorityOrder)},
- #'CosNotification_Property'{name=?not_EventReliability,
- value=any:create(orber_tc:short(),
- ?not_BestEffort)},
- #'CosNotification_Property'{name=?not_ConnectionReliability,
- value=any:create(orber_tc:short(),
- ?not_BestEffort)},
- #'CosNotification_Property'{name=?not_DiscardPolicy,
- value=any:create(orber_tc:short(),
- ?not_RejectNewEvents)},
- #'CosNotification_Property'{name=?not_StartTimeSupported,
- value=any:create(orber_tc:boolean(), false)},
- #'CosNotification_Property'{name=?not_StopTimeSupported,
- value=any:create(orber_tc:boolean(), false)},
- #'CosNotification_Property'{name=?not_Priority,
- value=any:create(orber_tc:short(), ?not_DefaultPriority)}]).
-
-%%--------------- QOS CREATORS -------------------------------
--define(not_CreateInitQoS(), #qos{}).
-
-%%--------------- QOS DESTRUCTORS ----------------------------
--define(not_DestroyQoS(Q), ok).
-
-%%--------------- QOS SELECTORS ------------------------------
--define(not_GetEventReliability(Q), Q#qos.'EventReliability').
--define(not_GetConnectionReliability(Q), Q#qos.'ConnectionReliability').
--define(not_GetPriority(Q), Q#qos.'Priority').
--define(not_GetStartTimeSupported(Q), Q#qos.'StartTimeSupported').
--define(not_GetStopTimeSupported(Q), Q#qos.'StopTimeSupported').
--define(not_GetTimeout(Q), Q#qos.'Timeout').
--define(not_GetOrderPolicy(Q), Q#qos.'OrderPolicy').
--define(not_GetDiscardPolicy(Q), Q#qos.'DiscardPolicy').
--define(not_GetMaximumBatchSize(Q), Q#qos.'MaximumBatchSize').
--define(not_GetPacingInterval(Q), Q#qos.'PacingInterval').
--define(not_GetMaxEventsPerConsumer(Q), Q#qos.'MaxEventsPerConsumer').
-
-%%--------------- QOS MODIFIERS ------------------------------
--define(not_SetEventReliability(Q,D), Q#qos{'EventReliability'=D}).
--define(not_SetConnectionReliability(Q,D), Q#qos{'ConnectionReliability'=D}).
--define(not_SetPriority(Q,D), Q#qos{'Priority'=D}).
--define(not_SetStartTimeSupported(Q,D), Q#qos{'StartTimeSupported'=D}).
--define(not_SetStopTimeSupported(Q,D), Q#qos{'StopTimeSupported'=D}).
--define(not_SetTimeout(Q,D), Q#qos{'Timeout'=D}).
--define(not_SetOrderPolicy(Q,D), Q#qos{'OrderPolicy'=D}).
--define(not_SetDiscardPolicy(Q,D), Q#qos{'DiscardPolicy'=D}).
--define(not_SetMaximumBatchSize(Q,D), Q#qos{'MaximumBatchSize'=D}).
--define(not_SetPacingInterval(Q,D), Q#qos{'PacingInterval'=D}).
--define(not_SetMaxEventsPerConsumer(Q,D), Q#qos{'MaxEventsPerConsumer'=D}).
-
-%%--------------- StructuredEvent CREATORS -------------------
--define(not_CreateSE(StrD,StrT,StrE,PSeqV,PSeqF,AnyR),
-#'CosNotification_StructuredEvent'{header =
- #'CosNotification_EventHeader'{fixed_header =
- #'CosNotification_FixedEventHeader'{event_type =
- #'CosNotification_EventType'{domain_name=StrD,
- type_name=StrT},
- event_name = StrE},
- variable_header = PSeqV},
- filterable_data = PSeqF,
- remainder_of_body = AnyR}).
-%% Can be used in guards.
--define(not_isConvertedAny(E),
- (((E#'CosNotification_StructuredEvent'.header)
- #'CosNotification_EventHeader'.fixed_header)
- #'CosNotification_FixedEventHeader'.event_type)
- #'CosNotification_EventType'.type_name == "%ANY").
-%% Can NOT be used in guards!!!!!
--define(not_isConvertedStructured(E),
- any:get_typecode(E) == 'CosNotification_StructuredEvent':tc()).
-
-%%--------------- StructuredEvent DESTRUCTORS ----------------
--define(not_DestroySE(E), ok).
-
-%%--------------- StructuredEvent SELECTORS ------------------
--define(not_GetSEHeader(E), E#'StructuredEvent'.header).
--define(not_GetSEFixedHeader(E), E#'StructuredEvent'.header).
-
-%%--------------- StructuredEvent MODIFIERS ------------------
-
-%%-------- QoS support -----------------------------------------------
--define(not_SUPPORTED_QOS,
-[{?not_EventReliability, 'EventReliability'},
- {?not_ConnectionReliability, 'ConnectionReliability'},
- {?not_Priority, 'Priority'},
- {?not_StartTimeSupported, 'StartTimeSupported'},
- {?not_StopTimeSupported, 'StopTimeSupported'},
- {?not_Timeout, 'Timeout'},
- {?not_OrderPolicy, 'OrderPolicy'},
- {?not_DiscardPolicy, 'DiscardPolicy'},
- {?not_MaximumBatchSize, 'MaximumBatchSize'},
- {?not_PacingInterval, 'PacingInterval'},
- {?not_MaxEventsPerConsumer, 'MaxEventsPerConsumer'}]).
-
-%%-------- ADMINPROPERTIESADMIN --------------------------------------
-
-%% According to the OMG TC Document telecom/98-11-01, p 63 (section 2.5.7), the
-%% default-value for these 3 admin properties is zero, which means that no limit
-%% applies to that property.
--define(not_DEFAULT_ADMINPROPERTIES,
-[#'CosNotification_Property'{name=?not_MaxQueueLength,
- value=any:create(orber_tc:long(), 0)},
- #'CosNotification_Property'{name=?not_MaxConsumers,
- value=any:create(orber_tc:long(), 0)},
- #'CosNotification_Property'{name=?not_MaxSuppliers,
- value=any:create(orber_tc:long(), 0)}]).
-
--define(not_SUPPORTED_ADMINPROPERTIES,
-[{?not_MaxQueueLength, 'MaxQueueLength'},
- {?not_MaxConsumers, 'MaxConsumers'},
- {?not_MaxSuppliers, 'MaxSuppliers'}]).
-
-
-%%-------- MISC --------------------------------------------------------
-
--define(not_DEFAULT_SETTINGS, [{pullInterval, 20},
- {filterOp, 'OR_OP'},
- {gcTime, 60},
- {gcLimit, 50},
- {timeService, undefined},
- {typecheck, true},
- {tty, false},
- {logfile, false},
- {server_options, []}]).
--define(not_CreateDBKey, term_to_binary({{erlang:system_time(),
- erlang:unique_integer()},
- node()})).
-
--define(DEBUG_LEVEL, 3).
-
--ifdef(debug).
-
--define(debug_print(F,A), io:format("[~p(~p)] "++F,[?MODULE, ?LINE]++A)).
--define(DBG(F,A), io:format("[~p(~p)] "++F,[?MODULE, ?LINE]++A)).
--define(not_TypeCheck(O,I), ok).
-%-define(not_TypeCheck(O,M), 'CosNotification_Common':type_check(O,M)).
-
--else.
-
--define(debug_print(F,A), ok).
--define(DBG(F,A), ok).
--define(not_TypeCheck(O,I), ok).
-
--endif.
-
-
-
--endif.
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/cosNotification/src/CosNotifyChannelAdmin.cfg b/lib/cosNotification/src/CosNotifyChannelAdmin.cfg
deleted file mode 100644
index 8647b281a2..0000000000
--- a/lib/cosNotification/src/CosNotifyChannelAdmin.cfg
+++ /dev/null
@@ -1,60 +0,0 @@
-{this, "CosNotifyChannelAdmin::EventChannel"}.
-{from, "CosNotifyChannelAdmin::EventChannel"}.
-{{handle_info, "CosNotifyChannelAdmin::EventChannel"}, true}.
-{this, "CosNotifyChannelAdmin::EventChannelFactory"}.
-{from, "CosNotifyChannelAdmin::EventChannelFactory"}.
-{{handle_info, "CosNotifyChannelAdmin::EventChannelFactory"}, true}.
-{this, "CosNotifyChannelAdmin::SupplierAdmin"}.
-{from, "CosNotifyChannelAdmin::SupplierAdmin"}.
-{{handle_info, "CosNotifyChannelAdmin::SupplierAdmin"}, true}.
-{this, "CosNotifyChannelAdmin::ConsumerAdmin"}.
-{from, "CosNotifyChannelAdmin::ConsumerAdmin"}.
-{{handle_info, "CosNotifyChannelAdmin::ConsumerAdmin"}, true}.
-{this, "CosNotifyChannelAdmin::StructuredProxyPushSupplier"}.
-{from, "CosNotifyChannelAdmin::StructuredProxyPushSupplier"}.
-{{handle_info, "CosNotifyChannelAdmin::StructuredProxyPushSupplier"}, true}.
-{{impl, "CosNotifyChannelAdmin::StructuredProxyPushSupplier"}, "PusherSupplier_impl"}.
-{this, "CosNotifyChannelAdmin::StructuredProxyPullSupplier"}.
-{from, "CosNotifyChannelAdmin::StructuredProxyPullSupplier"}.
-{{handle_info, "CosNotifyChannelAdmin::StructuredProxyPullSupplier"}, true}.
-{{impl, "CosNotifyChannelAdmin::StructuredProxyPullSupplier"}, "PullerSupplier_impl"}.
-{this, "CosNotifyChannelAdmin::ProxyPushSupplier"}.
-{from, "CosNotifyChannelAdmin::ProxyPushSupplier"}.
-{{handle_info, "CosNotifyChannelAdmin::ProxyPushSupplier"}, true}.
-{{impl, "CosNotifyChannelAdmin::ProxyPushSupplier"}, "PusherSupplier_impl"}.
-{this, "CosNotifyChannelAdmin::ProxyPullSupplier"}.
-{from, "CosNotifyChannelAdmin::ProxyPullSupplier"}.
-{{handle_info, "CosNotifyChannelAdmin::ProxyPullSupplier"}, true}.
-{{impl, "CosNotifyChannelAdmin::ProxyPullSupplier"}, "PullerSupplier_impl"}.
-{this, "CosNotifyChannelAdmin::SequenceProxyPushSupplier"}.
-{from, "CosNotifyChannelAdmin::SequenceProxyPushSupplier"}.
-{{handle_info, "CosNotifyChannelAdmin::SequenceProxyPushSupplier"}, true}.
-{{impl, "CosNotifyChannelAdmin::SequenceProxyPushSupplier"}, "PusherSupplier_impl"}.
-{this, "CosNotifyChannelAdmin::SequenceProxyPullSupplier"}.
-{from, "CosNotifyChannelAdmin::SequenceProxyPullSupplier"}.
-{{handle_info, "CosNotifyChannelAdmin::SequenceProxyPullSupplier"}, true}.
-{{impl, "CosNotifyChannelAdmin::SequenceProxyPullSupplier"}, "PullerSupplier_impl"}.
-{this, "CosNotifyChannelAdmin::StructuredProxyPushConsumer"}.
-{from, "CosNotifyChannelAdmin::StructuredProxyPushConsumer"}.
-{{handle_info, "CosNotifyChannelAdmin::StructuredProxyPushConsumer"}, true}.
-{{impl, "CosNotifyChannelAdmin::StructuredProxyPushConsumer"}, "PusherConsumer_impl"}.
-{this, "CosNotifyChannelAdmin::StructuredProxyPullConsumer"}.
-{from, "CosNotifyChannelAdmin::StructuredProxyPullConsumer"}.
-{{handle_info, "CosNotifyChannelAdmin::StructuredProxyPullConsumer"}, true}.
-{{impl, "CosNotifyChannelAdmin::StructuredProxyPullConsumer"}, "PullerConsumer_impl"}.
-{this, "CosNotifyChannelAdmin::ProxyPushConsumer"}.
-{from, "CosNotifyChannelAdmin::ProxyPushConsumer"}.
-{{handle_info, "CosNotifyChannelAdmin::ProxyPushConsumer"}, true}.
-{{impl, "CosNotifyChannelAdmin::ProxyPushConsumer"}, "PusherConsumer_impl"}.
-{this, "CosNotifyChannelAdmin::ProxyPullConsumer"}.
-{from, "CosNotifyChannelAdmin::ProxyPullConsumer"}.
-{{handle_info, "CosNotifyChannelAdmin::ProxyPullConsumer"}, true}.
-{{impl, "CosNotifyChannelAdmin::ProxyPullConsumer"}, "PullerConsumer_impl"}.
-{this, "CosNotifyChannelAdmin::SequenceProxyPushConsumer"}.
-{from, "CosNotifyChannelAdmin::SequenceProxyPushConsumer"}.
-{{handle_info, "CosNotifyChannelAdmin::SequenceProxyPushConsumer"}, true}.
-{{impl, "CosNotifyChannelAdmin::SequenceProxyPushConsumer"}, "PusherConsumer_impl"}.
-{this, "CosNotifyChannelAdmin::SequenceProxyPullConsumer"}.
-{from, "CosNotifyChannelAdmin::SequenceProxyPullConsumer"}.
-{{handle_info, "CosNotifyChannelAdmin::SequenceProxyPullConsumer"}, true}.
-{{impl, "CosNotifyChannelAdmin::SequenceProxyPullConsumer"}, "PullerConsumer_impl"}.
diff --git a/lib/cosNotification/src/CosNotifyChannelAdmin.idl b/lib/cosNotification/src/CosNotifyChannelAdmin.idl
deleted file mode 100644
index b345ff5423..0000000000
--- a/lib/cosNotification/src/CosNotifyChannelAdmin.idl
+++ /dev/null
@@ -1,275 +0,0 @@
-#ifndef _COS_NOTIFYCHANNELADMIN_IDL_
-#define _COS_NOTIFYCHANNELADMIN_IDL_
-
-#pragma prefix "omg.org"
-
-#include<cosNotificationAppComm.idl>
-#include<CosNotifyFilter.idl>
-#include<CosNotifyComm.idl>
-#include<CosNotification.idl>
-
-module CosNotifyChannelAdmin {
- exception ConnectionAlreadyActive {};
- exception ConnectionAlreadyInactive {};
- exception NotConnected {};
- // Forward declarations
- interface ConsumerAdmin;
- interface SupplierAdmin;
- interface EventChannel;
- interface EventChannelFactory;
-
- enum ProxyType {
- PUSH_ANY,
- PULL_ANY,
- PUSH_STRUCTURED,
- PULL_STRUCTURED,
- PUSH_SEQUENCE,
- PULL_SEQUENCE};
-
- enum ObtainInfoMode {
- ALL_NOW_UPDATES_OFF,
- ALL_NOW_UPDATES_ON,
- NONE_NOW_UPDATES_OFF,
- NONE_NOW_UPDATES_ON};
-
- interface ProxyConsumer : CosNotification::QoSAdmin, CosNotifyFilter::FilterAdmin {
- readonly attribute ProxyType MyType;
- readonly attribute SupplierAdmin MyAdmin;
-
- CosNotification::EventTypeSeq obtain_subscription_types(in ObtainInfoMode mode);
-
- void validate_event_qos (in CosNotification::QoSProperties required_qos,
- out CosNotification::NamedPropertyRangeSeq available_qos)
- raises (CosNotification::UnsupportedQoS);
- }; // ProxyConsumer
-
- interface ProxySupplier : CosNotification::QoSAdmin, CosNotifyFilter::FilterAdmin {
- readonly attribute ProxyType MyType;
- readonly attribute ConsumerAdmin MyAdmin;
- attribute CosNotifyFilter::MappingFilter priority_filter;
- attribute CosNotifyFilter::MappingFilter lifetime_filter;
-
- CosNotification::EventTypeSeq obtain_offered_types(in ObtainInfoMode mode);
-
- void validate_event_qos (in CosNotification::QoSProperties required_qos,
- out CosNotification::NamedPropertyRangeSeq available_qos)
- raises (CosNotification::UnsupportedQoS);
- }; // ProxySupplier
-
- interface ProxyPushConsumer : ProxyConsumer, CosNotifyComm::PushConsumer,
- CosEventChannelAdmin::ProxyPushConsumer {
- void connect_any_push_supplier (in CosEventComm::PushSupplier push_supplier)
- raises(CosEventChannelAdmin::AlreadyConnected);
- }; // ProxyPushConsumer
-
- interface StructuredProxyPushConsumer : ProxyConsumer, CosNotifyComm::StructuredPushConsumer {
- void connect_structured_push_supplier (in CosNotifyComm::StructuredPushSupplier push_supplier)
- raises(CosEventChannelAdmin::AlreadyConnected);
- }; // StructuredProxyPushConsumer
-
- interface SequenceProxyPushConsumer : ProxyConsumer, CosNotifyComm::SequencePushConsumer {
- void connect_sequence_push_supplier (in CosNotifyComm::SequencePushSupplier push_supplier)
- raises(CosEventChannelAdmin::AlreadyConnected);
- }; // SequenceProxyPushConsumer
-
- interface ProxyPullSupplier : ProxySupplier, CosNotifyComm::PullSupplier,
- CosEventChannelAdmin::ProxyPullSupplier, oe_CosNotificationComm::Event {
- void connect_any_pull_consumer (in CosEventComm::PullConsumer pull_consumer)
- raises(CosEventChannelAdmin::AlreadyConnected);
- }; // ProxyPullSupplier
-
- interface StructuredProxyPullSupplier : ProxySupplier, CosNotifyComm::StructuredPullSupplier,
- oe_CosNotificationComm::Event {
- void connect_structured_pull_consumer (in CosNotifyComm::StructuredPullConsumer pull_consumer)
- raises(CosEventChannelAdmin::AlreadyConnected);
- }; // StructuredProxyPullSupplier
-
- interface SequenceProxyPullSupplier : ProxySupplier, CosNotifyComm::SequencePullSupplier,
- oe_CosNotificationComm::Event {
- void connect_sequence_pull_consumer (in CosNotifyComm::SequencePullConsumer pull_consumer)
- raises(CosEventChannelAdmin::AlreadyConnected);
- }; // SequenceProxyPullSupplier
-
- interface ProxyPullConsumer : ProxyConsumer, CosNotifyComm::PullConsumer,
- CosEventChannelAdmin::ProxyPullConsumer {
- void connect_any_pull_supplier (in CosEventComm::PullSupplier pull_supplier)
- raises(CosEventChannelAdmin::AlreadyConnected, CosEventChannelAdmin::TypeError);
-
- void suspend_connection()
- raises(ConnectionAlreadyInactive, NotConnected);
-
- void resume_connection()
- raises(ConnectionAlreadyActive, NotConnected);
- }; // ProxyPullConsumer
-
- interface StructuredProxyPullConsumer : ProxyConsumer, CosNotifyComm::StructuredPullConsumer {
- void connect_structured_pull_supplier (in CosNotifyComm::StructuredPullSupplier pull_supplier)
- raises(CosEventChannelAdmin::AlreadyConnected, CosEventChannelAdmin::TypeError);
-
- void suspend_connection()
- raises(ConnectionAlreadyInactive, NotConnected);
-
- void resume_connection()
- raises(ConnectionAlreadyActive, NotConnected);
- }; // StructuredProxyPullConsumer
-
- interface SequenceProxyPullConsumer : ProxyConsumer, CosNotifyComm::SequencePullConsumer {
- void connect_sequence_pull_supplier (in CosNotifyComm::SequencePullSupplier pull_supplier)
- raises(CosEventChannelAdmin::AlreadyConnected, CosEventChannelAdmin::TypeError);
-
- void suspend_connection()
- raises(ConnectionAlreadyInactive, NotConnected);
-
- void resume_connection()
- raises(ConnectionAlreadyActive, NotConnected);
- }; // SequenceProxyPullConsumer
-
- interface ProxyPushSupplier : ProxySupplier, CosNotifyComm::PushSupplier,
- CosEventChannelAdmin::ProxyPushSupplier, oe_CosNotificationComm::Event {
- void connect_any_push_consumer (in CosEventComm::PushConsumer push_consumer)
- raises(CosEventChannelAdmin::AlreadyConnected, CosEventChannelAdmin::TypeError);
-
- void suspend_connection()
- raises(ConnectionAlreadyInactive, NotConnected);
-
- void resume_connection()
- raises(ConnectionAlreadyActive, NotConnected);
- }; // ProxyPushSupplier
-
- interface StructuredProxyPushSupplier : ProxySupplier, CosNotifyComm::StructuredPushSupplier,
- oe_CosNotificationComm::Event {
- void connect_structured_push_consumer (in CosNotifyComm::StructuredPushConsumer push_consumer)
- raises(CosEventChannelAdmin::AlreadyConnected, CosEventChannelAdmin::TypeError);
-
- void suspend_connection()
- raises(ConnectionAlreadyInactive, NotConnected);
-
- void resume_connection()
- raises(ConnectionAlreadyActive, NotConnected);
- }; // StructuredProxyPushSupplier
-
- interface SequenceProxyPushSupplier : ProxySupplier, CosNotifyComm::SequencePushSupplier,
- oe_CosNotificationComm::Event {
- void connect_sequence_push_consumer (in CosNotifyComm::SequencePushConsumer push_consumer)
- raises(CosEventChannelAdmin::AlreadyConnected, CosEventChannelAdmin::TypeError);
-
- void suspend_connection()
- raises(ConnectionAlreadyInactive, NotConnected);
-
- void resume_connection()
- raises(ConnectionAlreadyActive, NotConnected);
- }; // SequenceProxyPushSupplier
-
-
- typedef long ProxyID;
- typedef sequence <ProxyID> ProxyIDSeq;
-
- enum ClientType {
- ANY_EVENT,
- STRUCTURED_EVENT,
- SEQUENCE_EVENT};
-
- enum InterFilterGroupOperator {
- AND_OP,
- OR_OP };
-
- typedef long AdminID;
- typedef sequence<AdminID> AdminIDSeq;
-
- exception AdminNotFound {};
- exception ProxyNotFound {};
-
- struct AdminLimit {
- CosNotification::PropertyName name;
- CosNotification::PropertyValue value;
- };
-
- exception AdminLimitExceeded { AdminLimit admin_property_err; };
-
- interface ConsumerAdmin : CosNotification::QoSAdmin, CosNotifyComm::NotifySubscribe,
- CosNotifyFilter::FilterAdmin, CosEventChannelAdmin::ConsumerAdmin,
- oe_CosNotificationComm::Event {
- readonly attribute AdminID MyID;
- readonly attribute EventChannel MyChannel;
- readonly attribute InterFilterGroupOperator MyOperator;
- attribute CosNotifyFilter::MappingFilter priority_filter;
- attribute CosNotifyFilter::MappingFilter lifetime_filter;
- readonly attribute ProxyIDSeq pull_suppliers;
- readonly attribute ProxyIDSeq push_suppliers;
-
- ProxySupplier get_proxy_supplier (in ProxyID proxy_id)
- raises (ProxyNotFound);
-
- ProxySupplier obtain_notification_pull_supplier (in ClientType ctype, out ProxyID proxy_id)
- raises (AdminLimitExceeded);
-
- ProxySupplier obtain_notification_push_supplier (in ClientType ctype, out ProxyID proxy_id)
- raises (AdminLimitExceeded);
-
- void destroy();
- }; // ConsumerAdmin
-
- interface SupplierAdmin : CosNotification::QoSAdmin, CosNotifyComm::NotifyPublish,
- CosNotifyFilter::FilterAdmin, CosEventChannelAdmin::SupplierAdmin ,
- oe_CosNotificationComm::Event {
- readonly attribute AdminID MyID;
- readonly attribute EventChannel MyChannel;
- readonly attribute InterFilterGroupOperator MyOperator;
- readonly attribute ProxyIDSeq pull_consumers;
- readonly attribute ProxyIDSeq push_consumers;
-
- ProxyConsumer get_proxy_consumer (in ProxyID proxy_id)
- raises (ProxyNotFound);
-
- ProxyConsumer obtain_notification_pull_consumer (in ClientType ctype, out ProxyID proxy_id)
- raises (AdminLimitExceeded);
-
- ProxyConsumer obtain_notification_push_consumer (in ClientType ctype, out ProxyID proxy_id)
- raises (AdminLimitExceeded);
-
- void destroy();
- }; // SupplierAdmin
-
- interface EventChannel : CosNotification::QoSAdmin, CosNotification::AdminPropertiesAdmin,
- CosEventChannelAdmin::EventChannel,
- oe_CosNotificationComm::Event {
- readonly attribute EventChannelFactory MyFactory;
- readonly attribute ConsumerAdmin default_consumer_admin;
- readonly attribute SupplierAdmin default_supplier_admin;
- readonly attribute CosNotifyFilter::FilterFactory default_filter_factory;
-
- ConsumerAdmin new_for_consumers(in InterFilterGroupOperator op, out AdminID id);
-
- SupplierAdmin new_for_suppliers(in InterFilterGroupOperator op, out AdminID id);
-
- ConsumerAdmin get_consumeradmin (in AdminID id)
- raises (AdminNotFound);
-
- SupplierAdmin get_supplieradmin (in AdminID id)
- raises (AdminNotFound);
-
- AdminIDSeq get_all_consumeradmins();
-
- AdminIDSeq get_all_supplieradmins();
- }; // EventChannel
-
- typedef long ChannelID;
- typedef sequence<ChannelID> ChannelIDSeq;
- exception ChannelNotFound {};
-
- interface EventChannelFactory {
- EventChannel create_channel (in CosNotification::QoSProperties initial_qos,
- in CosNotification::AdminProperties initial_admin,
- out ChannelID id)
- raises(CosNotification::UnsupportedQoS, CosNotification::UnsupportedAdmin);
-
- ChannelIDSeq get_all_channels();
-
- EventChannel get_event_channel (in ChannelID id)
- raises (ChannelNotFound);
- }; // EventChannelFactory
-}; // CosNotifyChannelAdmin
-
-
-#endif /* ifndef _COS_NOTIFYCHANNELADMIN_IDL_ */
-
diff --git a/lib/cosNotification/src/CosNotifyChannelAdmin_ConsumerAdmin_impl.erl b/lib/cosNotification/src/CosNotifyChannelAdmin_ConsumerAdmin_impl.erl
deleted file mode 100644
index e7a6a35ea7..0000000000
--- a/lib/cosNotification/src/CosNotifyChannelAdmin_ConsumerAdmin_impl.erl
+++ /dev/null
@@ -1,671 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-------------------------------------------------------------------
-%% File : CosNotifyChannelAdmin_ConsumerAdmin_impl.erl
-%% Purpose :
-%%-------------------------------------------------------------------
-
--module('CosNotifyChannelAdmin_ConsumerAdmin_impl').
-
-%%--------------- INCLUDES -----------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
-%% Application files
--include("CosNotification.hrl").
--include("CosNotifyChannelAdmin.hrl").
--include("CosNotifyComm.hrl").
--include("CosNotifyFilter.hrl").
--include("CosNotification_Definitions.hrl").
-
-%%--------------- EXPORTS ------------------------------------
-%%--------------- External -----------------------------------
-%%----- CosNotifyChannelAdmin::ConsumerAdmin -----------------
--export([get_proxy_supplier/4,
- obtain_notification_pull_supplier/4,
- obtain_notification_push_supplier/4,
- destroy/3]).
-
-%%----- Inherit from CosNotification::QoSAdmin ---------------
--export([get_qos/3,
- set_qos/4,
- validate_qos/4]).
-
-%%----- Inherit from CosNotifyComm::NotifySubscribe ----------
--export([subscription_change/5]).
-
-%%----- Inherit from CosNotifyFilter::FilterAdmin ------------
--export([add_filter/4,
- remove_filter/4,
- get_filter/4,
- get_all_filters/3,
- remove_all_filters/3]).
-
-%%----- Inherit from CosEventChannelAdmin::ConsumerAdmin -----
--export([obtain_push_supplier/3,
- obtain_pull_supplier/3]).
-
-%% Attributes (external)
--export(['_get_MyID'/3,
- '_get_MyChannel'/3,
- '_get_MyOperator'/3,
- '_get_priority_filter'/3,
- '_set_priority_filter'/4,
- '_get_lifetime_filter'/3,
- '_set_lifetime_filter'/4,
- '_get_pull_suppliers'/3,
- '_get_push_suppliers'/3]).
-
-%%--------------- Internal -----------------------------------
-%%----- Inherit from cosNotificationComm ---------------------
--export([callAny/5,
- callSeq/5]).
-
-%%--------------- gen_server specific exports ----------------
--export([handle_info/2, code_change/3]).
--export([init/1, terminate/2]).
-
-%%--------------- LOCAL DEFINITIONS --------------------------
-%% Data structures
--record(state, {myId,
- myChannel,
- myChannelPid,
- myOperator,
- myFilters = [],
- mySuppliers = [],
- idCounter = 0,
- priorityFilter,
- lifetimeFilter,
- etsR,
- qosGlobal,
- qosLocal,
- options}).
-
-%% Data structures constructors
--define(get_InitState(_MyID, _MyCh, _MyChP, _MyOp, _PFil, _LFil, _QoS, _LQS, _O),
- #state{myId = _MyID,
- myChannel = _MyCh,
- myChannelPid = _MyChP,
- myOperator = _MyOp,
- priorityFilter = _PFil,
- lifetimeFilter = _LFil,
- qosGlobal = _QoS,
- qosLocal = _LQS,
- options = _O,
- etsR = ets:new(oe_ets, [set, protected])}).
-
-%% Data structures selectors
--define(get_PushSupplierIDs(S), find_ids(S#state.mySuppliers, pusher)).
--define(get_PullSupplierIDs(S), find_ids(S#state.mySuppliers, puller)).
--define(get_AllSuppliers(S), S#state.mySuppliers).
--define(get_AllSupplierRefs(S), find_refs(S#state.mySuppliers)).
--define(get_Supplier(S, I), find_obj(lists:keysearch(I,1,S#state.mySuppliers),
- supplier)).
-
--define(get_MyID(S), S#state.myId).
--define(get_MyChannel(S), S#state.myChannel).
--define(get_MyChannelPid(S), S#state.myChannelPid).
--define(get_MyOperator(S), S#state.myOperator).
--define(get_PrioFilter(S), S#state.priorityFilter).
--define(get_LifeFilter(S), S#state.lifetimeFilter).
--define(get_GlobalQoS(S), S#state.qosGlobal).
--define(get_LocalQoS(S), S#state.qosLocal).
--define(get_BothQoS(S), {S#state.qosGlobal, S#state.qosLocal}).
--define(get_Filter(S, I), find_obj(lists:keysearch(I, 1, S#state.myFilters),
- filter)).
--define(get_AllFilter(S), S#state.myFilters).
--define(get_AllFilterID(S), find_ids(S#state.myFilters)).
--define(get_Options(S), S#state.options).
--define(get_IdCounter(S), S#state.idCounter).
-
-%% Data structures modifiers
--define(set_PrioFilter(S,D), S#state{priorityFilter=D}).
--define(set_LifeFilter(S,D), S#state{lifetimeFilter=D}).
--define(set_LocalQoS(S,D), S#state{qosLocal=D}).
--define(set_GlobalQoS(S,D), S#state{qosGlobal=D}).
--define(set_BothQoS(S,GD,LD), S#state{qosGlobal=GD, qosLocal=LD}).
--define(add_PushSupplier(S,I,R,P),S#state{mySuppliers=[{I,R,P,pusher}|S#state.mySuppliers]}).
--define(add_PullSupplier(S,I,R,P),S#state{mySuppliers=[{I,R,P,puller}|S#state.mySuppliers]}).
--define(del_Supplier(S,I), S#state{mySuppliers=
- lists:keydelete(I, 1,
- S#state.mySuppliers)}).
--define(del_SupplierRef(S,O), S#state{mySuppliers=
- lists:keydelete(O, 2,
- S#state.mySuppliers)}).
--define(del_SupplierPid(S,P), S#state{mySuppliers=
- lists:keydelete(P, 3,
- S#state.mySuppliers)}).
--define(add_Filter(S,I,O), S#state{myFilters=[{I,O}|S#state.myFilters]}).
--define(del_Filter(S,I), S#state{myFilters=
- delete_filter(lists:keydelete(I, 1,
- S#state.myFilters),
- S#state.myFilters)}).
--define(del_AllFilter(S), S#state{myFilters=[]}).
--define(set_IdCounter(S,V), S#state{idCounter=V}).
--define(new_Id(S), 'CosNotification_Common':create_id(
- S#state.idCounter)).
-
-%% MISC
--define(is_PersistentConnection(S),
- ?not_GetConnectionReliability((S#state.qosLocal)) == ?not_Persistent).
--define(is_PersistentEvent(S),
- ?not_GetEventReliability((S#state.qosLocal)) == ?not_Persistent).
--define(is_ANDOP(S), S#state.myOperator == 'AND_OP').
-
-%%----------------------------------------------------------%
-%% function : handle_info, code_change
-%% Arguments:
-%% Returns :
-%% Effect : Functions demanded by the gen_server module.
-%%-----------------------------------------------------------
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-handle_info(Info, State) ->
- case Info of
- {'EXIT', Pid, Reason} when ?get_MyChannelPid(State) == Pid ->
- ?DBG("PARENT CHANNEL: ~p TERMINATED.~n",[Reason]),
- {stop, Reason, State};
- {'EXIT', Pid, normal} ->
- {noreply, ?del_SupplierPid(State, Pid)};
- _Other ->
- {noreply, State}
- end.
-
-%%----------------------------------------------------------%
-%% function : init, terminate
-%% Arguments:
-%%-----------------------------------------------------------
-
-init([MyId, MyChannel, MyChannelPid, MyOperator, InitQoS, LQS, Options]) ->
- process_flag(trap_exit, true),
- PriorityFilter = corba:create_nil_objref(),
- LifeTimeFilter = corba:create_nil_objref(),
- {ok, ?get_InitState(MyId, MyChannel, MyChannelPid, MyOperator,
- PriorityFilter, LifeTimeFilter, InitQoS, LQS, Options)}.
-
-terminate(_Reason, _State) ->
- ok.
-
-%%-----------------------------------------------------------
-%%----- CosNotifyChannelAdmin_ConsumerAdmin attributes ------
-%%-----------------------------------------------------------
-%%----------------------------------------------------------%
-%% Attribute: '_get_MyID'
-%% Type : readonly
-%% Returns :
-%%-----------------------------------------------------------
-'_get_MyID'(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_MyID(State), State}.
-
-%%----------------------------------------------------------%
-%% Attribute: '_get_MyChannel'
-%% Type : readonly
-%% Returns :
-%%-----------------------------------------------------------
-'_get_MyChannel'(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_MyChannel(State), State}.
-
-%%----------------------------------------------------------%
-%% Attribute: '_get_MyOperator'
-%% Type : readonly
-%% Returns :
-%%-----------------------------------------------------------
-'_get_MyOperator'(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_MyOperator(State), State}.
-
-%%----------------------------------------------------------%
-%% Attribute: '_get_priority_filter'
-%% Type : read and write
-%% Returns :
-%%-----------------------------------------------------------
-'_get_priority_filter'(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_PrioFilter(State), State}.
-
-'_set_priority_filter'(_OE_THIS, _OE_FROM, State, PrioFilter) ->
- {reply, ok, ?set_PrioFilter(State, PrioFilter)}.
-
-%%----------------------------------------------------------%
-%% Attribute: '_get_lifetime_filter'
-%% Type : read and write
-%% Returns :
-%%-----------------------------------------------------------
-'_get_lifetime_filter'(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_LifeFilter(State), State}.
-'_set_lifetime_filter'(_OE_THIS, _OE_FROM, State, LifeFilter) ->
- {reply, ok, ?set_LifeFilter(State, LifeFilter)}.
-
-%%----------------------------------------------------------%
-%% Attribute: '_get_pull_suppliers'
-%% Type : readonly
-%% Returns : ProxyIDSeq
-%%-----------------------------------------------------------
-'_get_pull_suppliers'(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_PullSupplierIDs(State), State}.
-
-%%----------------------------------------------------------%
-%% Attribute: '_get_push_suppliers'
-%% Type : readonly
-%% Returns : ProxyIDSeq
-%%-----------------------------------------------------------
-'_get_push_suppliers'(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_PushSupplierIDs(State), State}.
-
-%%-----------------------------------------------------------
-%%------- Exported external functions -----------------------
-%%-----------------------------------------------------------
-%%----------------------------------------------------------%
-%% function : get_proxy_supplier
-%% Arguments: ProxyID - unique identifier (long)
-%% Returns : ObjRef | {'EXCEPTION', #'ProxyNotFound'{}}
-%%-----------------------------------------------------------
-get_proxy_supplier(_OE_THIS, _OE_FROM, State, Proxy_id) ->
- {reply, ?get_Supplier(State, Proxy_id), State}.
-
-%%----------------------------------------------------------%
-%% function : obtain_notification_pull_supplier
-%% Arguments: Ctype - 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT'
-%% Returns : A Proxy of the requested type.
-%%-----------------------------------------------------------
-obtain_notification_pull_supplier(OE_THIS, _OE_FROM, State, Ctype) ->
- %% Choose which module to use.
- {Mod, Type} =
- case Ctype of
- 'ANY_EVENT' ->
- {'CosNotifyChannelAdmin_ProxyPullSupplier', 'PULL_ANY'};
- 'STRUCTURED_EVENT' ->
- {'CosNotifyChannelAdmin_StructuredProxyPullSupplier', 'PULL_STRUCTURED'};
- 'SEQUENCE_EVENT' ->
- {'CosNotifyChannelAdmin_SequenceProxyPullSupplier', 'PULL_SEQUENCE'};
- _ ->
- orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:"
- "obtain_notification_pull_supplier(~p);~n"
- "Incorrect enumerant",
- [?LINE, Ctype], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO})
- end,
- SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State),
- ?not_DEFAULT_SETTINGS),
- case Mod:oe_create_link([Type, OE_THIS, self(), ?get_GlobalQoS(State),
- ?get_LocalQoS(State), ?get_MyChannel(State),
- ?get_Options(State), ?get_MyOperator(State)],
- [{sup_child, true}|SO]) of
- {ok, Pid, PrRef} ->
- ProxyID = ?new_Id(State),
- NewState = ?add_PullSupplier(State, ProxyID, PrRef, Pid),
- {reply, {PrRef, ProxyID}, ?set_IdCounter(NewState, ProxyID)};
- What ->
- orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:"
- "obtain_notification_pull_supplier();~n"
- "Unable to create: ~p/~p~n"
- "Reason: ~p", [?LINE, Mod, Type, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-%%----------------------------------------------------------%
-%% function : obtain_notification_push_supplier
-%% Arguments: Ctype - 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT'
-%% Returns : A Proxy of the requested type.
-%%-----------------------------------------------------------
-obtain_notification_push_supplier(OE_THIS, _OE_FROM, State, Ctype) ->
- %% Choose which module to use.
- {Mod, Type} =
- case Ctype of
- 'ANY_EVENT' ->
- {'CosNotifyChannelAdmin_ProxyPushSupplier', 'PUSH_ANY'};
- 'STRUCTURED_EVENT' ->
- {'CosNotifyChannelAdmin_StructuredProxyPushSupplier', 'PUSH_STRUCTURED'};
- 'SEQUENCE_EVENT' ->
- {'CosNotifyChannelAdmin_SequenceProxyPushSupplier', 'PUSH_SEQUENCE'};
- _ ->
- orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:"
- "obtain_notification_push_supplier(~p);~n"
- "Incorrect enumerant", [?LINE, Ctype], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO})
- end,
- SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State),
- ?not_DEFAULT_SETTINGS),
- case Mod:oe_create_link([Type, OE_THIS, self(), ?get_GlobalQoS(State),
- ?get_LocalQoS(State), ?get_MyChannel(State),
- ?get_Options(State), ?get_MyOperator(State)],
- [{sup_child, true}|SO]) of
- {ok, Pid, PrRef} ->
- ProxyID = ?new_Id(State),
- NewState = ?add_PushSupplier(State, ProxyID, PrRef, Pid),
- {reply, {PrRef, ProxyID}, ?set_IdCounter(NewState, ProxyID)};
- What ->
- orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:obtain_notification_push_supplier();~n"
- "Unable to create: ~p/~p~n"
- "Reason: ~p",
- [?LINE, Mod, Type, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-
-%%----------------------------------------------------------%
-%% function : destroy
-%% Arguments: -
-%% Returns : ok
-%%------------------------------------------------------------
-destroy(_OE_THIS, _OE_FROM, State) ->
- {stop, normal, ok, State}.
-
-%%----- Inherit from CosNotification::QoSAdmin --------------
-%%----------------------------------------------------------%
-%% function : get_qos
-%% Arguments:
-%% Returns :
-%%-----------------------------------------------------------
-get_qos(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_GlobalQoS(State), State}.
-
-%%----------------------------------------------------------%
-%% function : set_qos
-%% Arguments: QoS - CosNotification::QoSProperties, i.e.,
-%% [#'Property'{name, value}, ...] where name eq. string()
-%% and value eq. any().
-%% Returns : ok | {'EXCEPTION', CosNotification::UnsupportedQoS}
-%%-----------------------------------------------------------
-set_qos(_OE_THIS, _OE_FROM, State, QoS) ->
- {NewQoS, LQS} = 'CosNotification_Common':set_qos(QoS, ?get_BothQoS(State),
- admin, ?get_MyChannel(State),
- ?get_AllSupplierRefs(State)),
- {reply, ok, ?set_BothQoS(State, NewQoS, LQS)}.
-
-%%----------------------------------------------------------%
-%% function : validate_qos
-%% Arguments: Required_qos - CosNotification::QoSProperties
-%% [#'Property'{name, value}, ...] where name eq. string()
-%% and value eq. any().
-%% Returns : {'EXCEPTION', CosNotification::UnsupportedQoS}
-%%-----------------------------------------------------------
-validate_qos(_OE_THIS, _OE_FROM, State, Required_qos) ->
- QoS = 'CosNotification_Common':validate_qos(Required_qos, ?get_BothQoS(State),
- admin, ?get_MyChannel(State),
- ?get_AllSupplierRefs(State)),
- {reply, {ok, QoS}, State}.
-
-%%----- Inherit from CosNotifyComm::NotifySubscribe ---------
-%%----------------------------------------------------------*
-%% function : subscription_change
-%% Arguments:
-%% Returns : ok |
-%% {'EXCEPTION', #'CosNotifyComm_InvalidEventType'{type}}
-%%-----------------------------------------------------------
-subscription_change(_OE_THIS, _OE_FROM, State, _Added, _Removed) ->
- ?DBG("CALLBACK INFORMED: ~p ~p~n",[_Added, _Removed]),
- {reply, ok, State}.
-
-%%----- Inherit from CosNotifyFilter::FilterAdmin -----------
-%%----------------------------------------------------------%
-%% function : add_filter
-%% Arguments: Filter - CosNotifyFilter::Filter
-%% Returns : FilterID - long
-%%-----------------------------------------------------------
-add_filter(_OE_THIS, _OE_FROM, State, Filter) ->
- 'CosNotification_Common':type_check(Filter, 'CosNotifyFilter_Filter'),
- FilterID = ?new_Id(State),
- NewState = ?set_IdCounter(State, FilterID),
- {reply, FilterID, ?add_Filter(NewState, FilterID, Filter)}.
-
-%%----------------------------------------------------------%
-%% function : remove_filter
-%% Arguments: FilterID - long
-%% Returns : ok
-%%-----------------------------------------------------------
-remove_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) ->
- {reply, ok, ?del_Filter(State, FilterID)};
-remove_filter(_,_,_,_) ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------%
-%% function : get_filter
-%% Arguments: FilterID - long
-%% Returns : Filter - CosNotifyFilter::Filter |
-%% {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}}
-%%-----------------------------------------------------------
-get_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) ->
- {reply, ?get_Filter(State, FilterID), State};
-get_filter(_,_,_,_) ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------%
-%% function : get_all_filters
-%% Arguments: -
-%% Returns : Filter - CosNotifyFilter::FilterIDSeq
-%%-----------------------------------------------------------
-get_all_filters(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_AllFilterID(State), State}.
-
-%%----------------------------------------------------------%
-%% function : remove_all_filters
-%% Arguments: -
-%% Returns : ok
-%%-----------------------------------------------------------
-remove_all_filters(_OE_THIS, _OE_FROM, State) ->
- {reply, ok, ?del_AllFilter(State)}.
-
-%%----- Inherit from CosEventChannelAdmin::ConsumerAdmin ----
-%%----------------------------------------------------------%
-%% function : obtain_push_supplier
-%% Arguments: -
-%% Returns : ProxyPushSupplier
-%%-----------------------------------------------------------
-obtain_push_supplier(OE_THIS, _OE_FROM, State) ->
- SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State),
- ?not_DEFAULT_SETTINGS),
- case 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_create_link(['PUSH_ANY', OE_THIS,
- self(),
- ?get_GlobalQoS(State),
- ?get_LocalQoS(State),
- ?get_MyChannel(State),
- ?get_Options(State),
- ?get_MyOperator(State)],
- [{sup_child, true}|SO]) of
- {ok, Pid, PrRef} ->
- ProxyID = ?new_Id(State),
- NewState = ?add_PushSupplier(State, ProxyID, PrRef, Pid),
- {reply, PrRef, ?set_IdCounter(NewState, ProxyID)};
- What ->
- orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:obtain_push_supplier();~n"
- "Unable to create: CosNotifyChannelAdmin_ProxyPushSupplier~n"
- "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-%%----------------------------------------------------------%
-%% function : obtain_pull_supplier
-%% Arguments: -
-%% Returns : ProxyPullSupplier
-%%-----------------------------------------------------------
-obtain_pull_supplier(OE_THIS, _OE_FROM, State) ->
- SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State),
- ?not_DEFAULT_SETTINGS),
- case 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_create_link(['PULL_ANY', OE_THIS,
- self(),
- ?get_GlobalQoS(State),
- ?get_LocalQoS(State),
- ?get_MyChannel(State),
- ?get_Options(State),
- ?get_MyOperator(State)],
- [{sup_child, true}|SO]) of
- {ok, Pid, PrRef} ->
- ProxyID = ?new_Id(State),
- NewState = ?add_PullSupplier(State, ProxyID, PrRef, Pid),
- {reply, PrRef, ?set_IdCounter(NewState, ProxyID)};
- What ->
- orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:obtain_pull_supplier();~n"
- "Unable to create: CosNotifyChannelAdmin_ProxyPullSupplier~n"
- "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-%%--------------- LOCAL FUNCTIONS ----------------------------
-%% To match suppliers
-find_obj({value, {_,Obj,_,_}},_) -> Obj;
-%% To match filters
-find_obj({value, {_,Obj}},_) -> Obj;
-find_obj(_, supplier) -> {'EXCEPTION', #'CosNotifyChannelAdmin_ProxyNotFound'{}};
-find_obj(_, filter) -> {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}}.
-
-find_ids(List) ->
- find_ids(List, [], false).
-find_ids(List, Type) ->
- find_ids(List, [], Type).
-
-find_ids([], Acc, _) ->
- Acc;
-find_ids([{I,_}|T], Acc, Type) ->
- find_ids(T, [I|Acc], Type);
-find_ids([{I,_,_,Type}|T], Acc, Type) ->
- find_ids(T, [I|Acc], Type);
-find_ids([{_I,_,_,_}|T], Acc, Type) ->
- find_ids(T, Acc, Type);
-find_ids(What, _, _) ->
- orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:find_ids();~n"
- "Id corrupt: ~p", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}).
-
-find_refs(List) ->
- find_refs(List, []).
-
-find_refs([], Acc) ->
- Acc;
-find_refs([{_,R,_,_}|T], Acc) ->
- find_refs(T, [R|Acc]);
-find_refs(What, _) ->
- orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:find_refs();~n"
- "Reference corrupt: ~p", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}).
-
-%% Delete a single filter.
-%% The list do not differ, i.e., no filter removed, raise exception.
-delete_filter(List,List) -> corba:raise(#'CosNotifyFilter_FilterNotFound'{});
-delete_filter(List, _) -> List.
-
-
-%%-----------------------------------------------------------
-%% function : callSeq
-%% Arguments:
-%% Returns :
-%%-----------------------------------------------------------
-callSeq(_OE_THIS, OE_FROM, State, Events, _Status) ->
- corba:reply(OE_FROM, ok),
- case cosNotification_eventDB:filter_events(Events, ?get_AllFilter(State)) of
- {[], _} when ?is_ANDOP(State) ->
- %% Since AND it doesn't matter what the proxies 'think'. Done.
- {noreply, State};
- {[], Failed} ->
- %% Is OR but the Proxy may allow the events; pass on.
- forward(seq, State, Failed, 'MATCH');
- {Passed, _} when ?is_ANDOP(State) ->
- %% Since AND we only forward those who passed this objects filters.
- forward(seq, State, Passed, 'MATCH');
- {Passed, []} ->
- %% Since OR we forward and tell the proxy to do no filtering.
- forward(seq, State, Passed, 'MATCHED');
- {Passed, Failed} ->
- %% Since OR we forward both and instruct the proxy to check only
- %% the ones that failed.
- forward(seq, State, Passed, 'MATCHED'),
- forward(seq, State, Failed, 'MATCH')
- end.
-
-
-%%-----------------------------------------------------------
-%% function : callAny
-%% Arguments:
-%% Returns :
-%%-----------------------------------------------------------
-callAny(_OE_THIS, OE_FROM, State, Event, _Status) ->
- corba:reply(OE_FROM, ok),
- case cosNotification_eventDB:filter_events([Event], ?get_AllFilter(State)) of
- {[], _} when ?is_ANDOP(State) ->
- %% Since AND it doesn't matter what the proxies 'think'. Done.
- {noreply, State};
- {[], [Failed]} ->
- %% Is OR but the Proxy may allow the event; pass on.
- forward(any, State, Failed, 'MATCH');
- {[Passed], _} when ?is_ANDOP(State) ->
- %% Since AND we only forward those who passed this objects filters.
- forward(any, State, Passed, 'MATCH');
- {[Passed], _} ->
- %% Since OR we forward and instruct the proxy to do no checks.
- forward(any, State, Passed, 'MATCHED')
- end.
-
-
-
-%% Forward events
-forward(Type, State, Event, Status) ->
- forward(Type, ?get_AllSuppliers(State), State, Event, Status).
-forward(_, [], State, _, _) ->
- {noreply, State};
-forward(any, [{_,H,_,_}|T], State, Event, Status) ->
- case catch oe_CosNotificationComm_Event:callAny(H, Event, Status) of
- ok ->
- ?DBG("CONSUMERADM FORWARD ANY: ~p~n",[Event]),
- forward(any, T, State, Event, Status);
- {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') ->
- orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:forward();~n"
- "Proxy no longer exists; dropping it: ~p",
- [?LINE, H], ?DEBUG_LEVEL),
- NewState = ?del_SupplierRef(State,H),
- forward(any, T, NewState, Event, Status);
- R when ?is_PersistentConnection(State) ->
- orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:forward();~n"
- "Proxy behaves badly: ~p/~p",
- [?LINE, R, H], ?DEBUG_LEVEL),
- forward(any, T, State, Event, Status);
- R ->
- orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:forward();~n"
- "Proxy behaves badly: ~p~n"
- "Dropping it: ~p", [?LINE, R, H], ?DEBUG_LEVEL),
- NewState = ?del_SupplierRef(State, H),
- forward(any, T, NewState, Event, Status)
- end;
-forward(seq, [{_,H,_,_}|T], State, Event, Status) ->
- case catch oe_CosNotificationComm_Event:callSeq(H, Event, Status) of
- ok ->
- ?DBG("CONSUMERADM FORWARD SEQUENCE: ~p~n",[Event]),
- forward(seq, T, State, Event, Status);
- {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') ->
- orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:forward();~n"
- "Proxy no longer exists; dropping it: ~p",
- [?LINE, H], ?DEBUG_LEVEL),
- NewState = ?del_SupplierRef(State,H),
- forward(seq, T, NewState, Event, Status);
- R when ?is_PersistentConnection(State) ->
- orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:forward();~n"
- "Proxy behaves badly: ~p/~p", [?LINE, R, H], ?DEBUG_LEVEL),
- forward(seq, T, State, Event, Status);
- R ->
- orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:forward();~n"
- "Proxy behaves badly: ~p~n"
- "Dropping it: ~p", [?LINE, R, H], ?DEBUG_LEVEL),
- NewState = ?del_SupplierRef(State, H),
- forward(seq, T, NewState, Event, Status)
- end.
-
-
-%%--------------- MISC FUNCTIONS, E.G. DEBUGGING -------------
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/cosNotification/src/CosNotifyChannelAdmin_EventChannelFactory_impl.erl b/lib/cosNotification/src/CosNotifyChannelAdmin_EventChannelFactory_impl.erl
deleted file mode 100644
index eb3fb4a6a3..0000000000
--- a/lib/cosNotification/src/CosNotifyChannelAdmin_EventChannelFactory_impl.erl
+++ /dev/null
@@ -1,143 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-------------------------------------------------------------------
-%% File : CosNotifyChannelAdmin_EventChannelFactory_impl.erl
-%% Purpose :
-%%-------------------------------------------------------------------
-
--module('CosNotifyChannelAdmin_EventChannelFactory_impl').
-
-%%--------------- INCLUDES -----------------------------------
-%% Application files
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
-%% Application files
--include("CosNotification.hrl").
--include("CosNotifyChannelAdmin.hrl").
--include("CosNotifyComm.hrl").
--include("CosNotifyFilter.hrl").
--include("CosNotification_Definitions.hrl").
-
-%%--------------- IMPORTS ------------------------------------
-
-%%--------------- EXPORTS ------------------------------------
-%% External
--export([create_channel/5,
- get_all_channels/3,
- get_event_channel/4]).
-
-%%--------------- gen_server specific exports ----------------
--export([handle_info/2, code_change/3]).
--export([init/1, terminate/2]).
-
-%%--------------- LOCAL DEFINITIONS --------------------------
-%% Data structures
--record(state, {adminProp,
- idCounter = 0,
- options,
- etsR,
- server_options}).
-
-%%-----------------------------------------------------------%
-%% function : handle_info, code_change
-%% Arguments: See gen_server documentation.
-%% Effect : Functions demanded by the gen_server module.
-%%------------------------------------------------------------
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-handle_info(Info, State) ->
- ?debug_print("INFO: ~p~n", [Info]),
- case Info of
- {'EXIT', Pid, normal} ->
- ets:match_delete(State#state.etsR, {'_','_',Pid}),
- {noreply, State};
- _Other ->
- ?debug_print("TERMINATED: ~p~n",[_Other]),
- {noreply, State}
- end.
-
-%%----------------------------------------------------------%
-%% function : init, terminate
-%% Arguments:
-%%-----------------------------------------------------------
-
-init(Options) ->
- process_flag(trap_exit, true),
- SO = 'CosNotification_Common':get_option(server_options, Options, ?not_DEFAULT_SETTINGS),
- {ok, #state{options = Options,
- etsR = ets:new(oe_ets, [set, protected]),
- server_options = SO}}.
-
-terminate(_Reason, _State) ->
- ok.
-
-%%-----------------------------------------------------------
-%%------- Exported external functions -----------------------
-%%-----------------------------------------------------------
-%%----------------------------------------------------------%
-%% function : create_channel
-%% Arguments: InitQoS
-%% InitAdmin
-%% Returns : Ch - Channel obj ref
-%% Id - Channel Id (out-type)
-%%-----------------------------------------------------------
-create_channel(OE_THIS, _OE_FROM, State, InitQoS, InitAdmin) ->
- {QoS, LQoS} = 'CosNotification_Common':init_qos(InitQoS),
- {IAdm, LAdm} = 'CosNotification_Common':init_adm(InitAdmin),
- Id = 'CosNotification_Common':create_id(State#state.idCounter),
- case 'CosNotifyChannelAdmin_EventChannel':oe_create_link([OE_THIS, QoS, IAdm,
- LQoS, LAdm,
- State#state.options],
- [{sup_child, true}|State#state.server_options]) of
- {ok, Pid, Ch} ->
- ets:insert(State#state.etsR, {Id,Ch,Pid}),
- {reply, {Ch, Id}, State#state{idCounter=Id}};
- _ ->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-%%----------------------------------------------------------%
-%% function : get_all_channels
-%% Arguments: -
-%% Returns : ChannelIDSeq - List of alive channels created
-%% by this factory.
-%%-----------------------------------------------------------
-get_all_channels(_OE_THIS, _OE_FROM, State) ->
- {reply, lists:flatten(ets:match(State#state.etsR, {'$1','_','_'})), State}.
-
-%%----------------------------------------------------------%
-%% function : get_event_channel
-%% Arguments: ChannelId
-%% Returns : ChannelRef | 'CosNotifyChannelAdmin_ChannelNotFound'
-%%-----------------------------------------------------------
-get_event_channel(_OE_THIS, _OE_FROM, State, Id) ->
- {reply, find_obj(ets:lookup(State#state.etsR, Id)), State}.
-
-%%--------------- LOCAL FUNCTIONS ----------------------------
-find_obj([]) -> {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}};
-find_obj([{_, Obj,_}]) -> Obj;
-find_obj(_) -> {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}.
-
-%%--------------- MISC FUNCTIONS, E.G. DEBUGGING -------------
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/cosNotification/src/CosNotifyChannelAdmin_EventChannel_impl.erl b/lib/cosNotification/src/CosNotifyChannelAdmin_EventChannel_impl.erl
deleted file mode 100644
index 485c9aeef4..0000000000
--- a/lib/cosNotification/src/CosNotifyChannelAdmin_EventChannel_impl.erl
+++ /dev/null
@@ -1,722 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-------------------------------------------------------------------
-%% File : CosNotifyChannelAdmin_EventChannel_impl.erl
-%% Purpose :
-%% Created : 28 Sep 1999
-%%-------------------------------------------------------------------
-
--module('CosNotifyChannelAdmin_EventChannel_impl').
-
-%%--------------- INCLUDES -----------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
-%% Application files
--include("CosNotification.hrl").
--include("CosNotifyChannelAdmin.hrl").
--include("CosNotifyComm.hrl").
--include("CosNotifyFilter.hrl").
--include("CosNotification_Definitions.hrl").
-
-%%--------------- EXPORTS ------------------------------------
-%%--------------- External -----------------------------------
-%%----- CosNotifyChannelAdmin::EventChannel ------------------
--export([new_for_consumers/4,
- new_for_suppliers/4,
- get_consumeradmin/4,
- get_supplieradmin/4,
- get_all_consumeradmins/3,
- get_all_supplieradmins/3]).
-
-%% Attributes (external)
--export(['_get_MyFactory'/3,
- '_get_default_consumer_admin'/3,
- '_get_default_supplier_admin'/3,
- '_get_default_filter_factory'/3]).
-
-%%----- Inherit from CosNotification::QoSAdmin ---------------
--export([get_qos/3,
- set_qos/4,
- validate_qos/4]).
-
-%%----- Inherit from CosNotification::AdminPropertiesAdmin ---
--export([get_admin/3,
- set_admin/4]).
-
-%%----- Inherit from CosEventChannelAdmin::EventChannel ------
--export([for_consumers/3,
- for_suppliers/3,
- destroy/3]).
-%%--------------- Internal -----------------------------------
-%%----- Inherit from cosNotificationComm ---------------------
--export([callAny/5,
- callSeq/5]).
-
-%%--------------- gen_server specific exports ----------------
--export([handle_info/2, code_change/3]).
--export([init/1, terminate/2]).
-
-%% Data structures
--record(state, {myFac,
- myConsumers = [],
- defConsumerAdmin,
- defSupplierAdmin,
- defConsumerAdminPid,
- defSupplierAdminPid,
- defFilterFac,
- defFilterFacPid,
- etsR,
- qosLocal,
- qosGlobal,
- admGlobal,
- options,
- idCounter = 0,
- 'MaxQueueLength',
- 'MaxConsumers',
- 'MaxSuppliers'}).
-%% Data structures constructors
--define(get_InitState(My, Fil, FilPid, QoS, LQoS, GA, MQ, MC, MS, O),
- #state{myFac = My,
- defFilterFac = Fil,
- defFilterFacPid = FilPid,
- etsR = ets:new(oe_ets, [set, protected]),
- qosLocal = LQoS,
- qosGlobal = QoS,
- admGlobal = GA,
- options = O,
- 'MaxQueueLength' = MQ,
- 'MaxConsumers' = MC,
- 'MaxSuppliers' = MS}).
-
-%% NOTE!!!
-%% When forwarding events, the objects we will contact is ONLY ConsumerAdmins!!
-%% Hence, we will store SupplierAdmins and ConsumerAdmins differently. SupplierAdmins
-%% we store in our ets-table while the ConsumerAdmins will be stored on the local
-%% State.
-
-%% Data structures selectors
--define(get_supplierAdmins(S), [S#state.defSupplierAdmin|
- lists:flatten(ets:match(S#state.etsR,
- {'_','$1','_'}))]).
--define(get_consumerAdmins(S), [{0, S#state.defConsumerAdmin,S#state.defConsumerAdminPid}
- |S#state.myConsumers]).
--define(get_allAdmins(S), [S#state.defSupplierAdmin,
- S#state.defConsumerAdmin|
- lists:flatten(ets:match(S#state.etsR,
- {'_','$1','_'}))++
- find_field(S#state.myConsumers, 2)]).
--define(get_consumerAdmIDs(S), [0|find_field(S#state.myConsumers, 1)]).
--define(get_supplierAdmIDs(S), [0|lists:flatten(ets:match(S#state.etsR,
- {'$1','_','_'}))]).
-
--define(get_supplierAdmin(S, I), find_obj(ets:lookup(S#state.etsR, I))).
--define(get_consumerAdmin(S, I), find_obj(lists:keysearch(I,1,S#state.myConsumers))).
--define(get_supplierAmount(S), ets:info(S#state.etsR, size)).
--define(get_consumerAmount(S), length(S#state.myConsumers)).
-
--define(get_MyFactory(S), S#state.myFac).
--define(get_defConsumerAdm(S), S#state.defConsumerAdmin).
--define(get_defSupplierAdm(S), S#state.defSupplierAdmin).
--define(get_defConsumerAdmPid(S), S#state.defConsumerAdminPid).
--define(get_defSupplierAdmPid(S), S#state.defSupplierAdminPid).
--define(get_defFilterFac(S), S#state.defFilterFac).
--define(get_defFilterFacPid(S), S#state.defFilterFacPid).
--define(get_GlobalQoS(S), S#state.qosGlobal).
--define(get_LocalQoS(S), S#state.qosLocal).
--define(get_BothQoS(S), {S#state.qosGlobal, S#state.qosLocal}).
--define(get_GlobalAdm(S), S#state.admGlobal).
--define(get_Options(S), S#state.options).
--define(get_MaxQueueLength(S), S#state.'MaxQueueLength').
--define(get_MaxConsumers(S), S#state.'MaxConsumers').
--define(get_MaxSuppliers(S), S#state.'MaxSuppliers').
--define(get_IdCounter(S), S#state.idCounter).
-
-%% Data structures modifiers
--define(set_GlobalQoS(S,D), S#state{qosGlobal=D}).
--define(set_BothQoS(S,GD,LD), S#state{qosGlobal=GD, qosLocal=LD}).
--define(set_GlobalAdm(S,D), S#state{admGlobal=D}).
--define(set_AllAdminP(S,GD, MQ, MC, MS),
- S#state{admGlobal=GD,'MaxQueueLength'=MQ,
- 'MaxConsumers'=MC, 'MaxSuppliers'=MS}).
--define(set_MaxQueueLength(S,D), S#state{'MaxQueueLength'=D}).
--define(set_MaxConsumers(S,D), S#state{'MaxConsumers'=D}).
--define(set_MaxSuppliers(S,D), S#state{'MaxSuppliers'=D}).
--define(set_defConsumerAdm(S,D,P), S#state{defConsumerAdmin=D, defConsumerAdminPid=P}).
--define(set_defSupplierAdm(S,D,P), S#state{defSupplierAdmin=D, defSupplierAdminPid=P}).
--define(set_defFilterFac(S,D,P), S#state{defFilterFac=D, defFilterFacPid=P}).
--define(add_supplierAdmin(S,I,O,P), ets:insert(S#state.etsR, {I,O,P})).
--define(add_consumerAdmin(S,I,O,P), S#state{myConsumers= [{I,O,P}|S#state.myConsumers]}).
--define(del_supplierAdmin(S,I), ets:delete(S#state.etsR, I)).
--define(del_consumerAdmin(S,I), S#state{myConsumers=
- lists:keydelete(I, 1,
- S#state.myConsumers)}).
--define(del_consumerAdminRef(S,O), S#state{myConsumers=
- lists:keydelete(O, 2,
- S#state.myConsumers)}).
--define(del_AdminPid(S,P), delete_obj(S, P)).
--define(set_IdCounter(S,V), S#state{idCounter=V}).
--define(new_Id(S), 'CosNotification_Common':create_id(S#state.idCounter)).
-%% MISC
--define(is_UndefDefConsAdm(S), S#state.defConsumerAdmin == undefined).
--define(is_UndefDefSuppAdm(S), S#state.defSupplierAdmin == undefined).
--define(is_UndefDefFilterFac(S), S#state.defFilterFac == undefined).
--define(is_PersistentConnection(S),
- ?not_GetConnectionReliability((S#state.qosLocal)) == ?not_Persistent).
--define(is_PersistentEvent(S),
- ?not_GetEventReliability((S#state.qosLocal)) == ?not_Persistent).
-
-%%-----------------------------------------------------------%
-%% function : handle_info, code_change
-%% Arguments:
-%% Returns :
-%% Effect : Functions demanded by the gen_server module.
-%%------------------------------------------------------------
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-handle_info(Info, State) ->
- ?DBG("INFO: ~p~n", [Info]),
- case Info of
- {'EXIT', Pid, _Reason} when ?get_defConsumerAdmPid(State) == Pid ->
- {noreply, ?set_defConsumerAdm(State, undefined, undefined)};
- {'EXIT', Pid, _Reason} when ?get_defSupplierAdmPid(State) == Pid ->
- {noreply, ?set_defSupplierAdm(State, undefined, undefined)};
- {'EXIT', Pid, _Reason} when ?get_defFilterFacPid(State) == Pid ->
- {noreply, ?set_defFilterFac(State, undefined, undefined)};
- {'EXIT', Pid, normal} ->
- {noreply, ?del_AdminPid(State, Pid)};
- _Other ->
- ?DBG("TERMINATED: ~p~n",[_Other]),
- {noreply, State}
- end.
-
-%%----------------------------------------------------------%
-%% function : init, terminate
-%% Arguments:
-%%-----------------------------------------------------------
-
-init([MyFac, InitQoS, InitAdmin, LocalQoS, [MaxQ, MaxC, MaxS|_], Options]) ->
- process_flag(trap_exit, true),
- SO = 'CosNotification_Common':get_option(server_options, Options,
- ?not_DEFAULT_SETTINGS),
-
- ?DBG("CHANNEL INIT STATE:~n~p~n~p~n~p ~p ~p ~p~n~p~n",
- [InitQoS, InitAdmin, LocalQoS,MaxQ, MaxC, MaxS, Options]),
-
- %% Both default Admin:s have the unique id 0 (OMG spec, 98-11-01,
- %% Notification p 148), hence, no need to create a unique id.
- %% We don't have acces to OE_THIS in this stage so we cannot create the objects
- %% now, even though the specification states that.
- %% DefConAdm = 'CosNotifyChannelAdmin_ConsumerAdmin':oe_create_link([0],[]),
- %% DefSupAdm = 'CosNotifyChannelAdmin_SupplierAdmin':oe_create_link([0],[]),
-
- case 'CosNotifyFilter_FilterFactory':oe_create_link([], [{sup_child, true}|SO]) of
- {ok, Pid, DefFiFac} ->
- {ok, ?get_InitState(MyFac, DefFiFac, Pid, InitQoS, LocalQoS,
- InitAdmin, MaxQ, MaxC, MaxS, Options)};
- Reason ->
- {stop, Reason}
- end.
-
-terminate(_Reason, _State) ->
- ok.
-
-%%-----------------------------------------------------------
-%%----- CosNotifyChannelAdmin_EventChannel attributes -------
-%%-----------------------------------------------------------
-%%----------------------------------------------------------%
-%% Attribute: '_get_MyFactory'
-%% Type : readonly
-%% Returns :
-%%-----------------------------------------------------------
-'_get_MyFactory'(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_MyFactory(State), State}.
-
-%%----------------------------------------------------------%
-%% Attribute: '_get_default_consumer_admin'
-%% Type : readonly
-%% Returns :
-%%-----------------------------------------------------------
-'_get_default_consumer_admin'(OE_THIS, _OE_FROM, State)
- when ?is_UndefDefConsAdm(State) ->
- Op = 'CosNotification_Common':get_option(filterOp, ?get_Options(State),
- ?not_DEFAULT_SETTINGS),
- SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State),
- ?not_DEFAULT_SETTINGS),
- case catch 'CosNotifyChannelAdmin_ConsumerAdmin':oe_create_link([0, OE_THIS,
- self(), Op,
- ?get_GlobalQoS(State),
- ?get_LocalQoS(State),
- ?get_Options(State)],
- [{sup_child, true}|SO]) of
- {ok, Pid, DefConAdm} ->
- {reply, DefConAdm, ?set_defConsumerAdm(State, DefConAdm, Pid)};
- What ->
- orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:_get_default_consumer_admin();~n"
- "Unable to create: CosNotifyChannelAdmin_ConsumerAdmin.~n"
- "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end;
-'_get_default_consumer_admin'(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_defConsumerAdm(State), State}.
-
-%%----------------------------------------------------------%
-%% Attribute: '_get_default_supplier_admin'
-%% Type : readonly
-%% Returns :
-%%-----------------------------------------------------------
-'_get_default_supplier_admin'(OE_THIS, _OE_FROM, State)
- when ?is_UndefDefSuppAdm(State) ->
- Op = 'CosNotification_Common':get_option(filterOp, ?get_Options(State),
- ?not_DEFAULT_SETTINGS),
- SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State),
- ?not_DEFAULT_SETTINGS),
- case catch 'CosNotifyChannelAdmin_SupplierAdmin':oe_create_link([0, OE_THIS,
- self(), Op,
- ?get_GlobalQoS(State),
- ?get_LocalQoS(State),
- ?get_Options(State)],
- [{sup_child, true}|SO]) of
- {ok, Pid, DefSupAdm} ->
- {reply, DefSupAdm, ?set_defSupplierAdm(State, DefSupAdm, Pid)};
- What ->
- orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:_get_default_supplier_admin();~n"
- "Unable to create: CosNotifyChannelAdmin_SupplierAdmin.~n"
- "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end;
-'_get_default_supplier_admin'(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_defSupplierAdm(State), State}.
-
-%%----------------------------------------------------------%
-%% Attribute: '_get_default_filter_factory'
-%% Type : readonly
-%% Returns :
-%%----------------------------------------------------------
-'_get_default_filter_factory'(_OE_THIS, _OE_FROM, State)
- when ?is_UndefDefFilterFac(State) ->
- SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State),
- ?not_DEFAULT_SETTINGS),
- case catch 'CosNotifyFilter_FilterFactory':oe_create_link([], [{sup_child, true}|SO]) of
- {ok, Pid, DefFiFac} ->
- {reply, DefFiFac, ?set_defFilterFac(State, DefFiFac, Pid)};
- What ->
- orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:_get_default_filter_factory();~n"
- "Unable to create: CosNotifyChannelAdmin_FilterFactory.~n"
- "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end;
-'_get_default_filter_factory'(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_defFilterFac(State), State}.
-
-%%-----------------------------------------------------------
-%%------- Exported external functions -----------------------
-%%-----------------------------------------------------------
-%%----------------------------------------------------------%
-%% function : new_for_consumers
-%% Arguments: Op - InterFilterGroupOperator: 'AND_OP' | 'OR_OP'
-%% Determines if the Admin:s proxy-children will
-%% use AND or OR when checking Filters.
-%% Returns : ConsAdm
-%% AdminId (out)
-%%-----------------------------------------------------------
-new_for_consumers(OE_THIS, _OE_FROM, State, Op) ->
- is_admin_limit_reached(?get_MaxConsumers(State), ?get_consumerAmount(State)),
- AdminId = ?new_Id(State),
- SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State),
- ?not_DEFAULT_SETTINGS),
- case catch 'CosNotifyChannelAdmin_ConsumerAdmin':oe_create_link([AdminId, OE_THIS,
- self(), Op,
- ?get_GlobalQoS(State),
- ?get_LocalQoS(State),
- ?get_Options(State)],
- [{sup_child, true}|SO]) of
- {ok, Pid, AdminCo} ->
- %% Due to different storage, adding a new consumer is NOT done in the
- %% same way as for suppliers.
- NewState = ?add_consumerAdmin(State, AdminId, AdminCo, Pid),
- {reply, {AdminCo, AdminId}, ?set_IdCounter(NewState, AdminId)};
- What ->
- orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:nef_for_consumers();~n"
- "Unable to create: CosNotifyChannelAdmin_ConsumerAdmin.~n"
- "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-%%----------------------------------------------------------%
-%% function : new_for_suppliers
-%% Arguments: Op - InterFilterGroupOperator: 'AND_OP' | 'OR_OP'
-%% Determines if the Admin:s proxy-children will
-%% use AND or OR when checking Filters.
-%% Returns : SuppAdm
-%% AdminId (out)
-%%-----------------------------------------------------------
-new_for_suppliers(OE_THIS, _OE_FROM, State, Op) ->
- is_admin_limit_reached(?get_MaxSuppliers(State), ?get_supplierAmount(State)),
- AdminId = ?new_Id(State),
- SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State),
- ?not_DEFAULT_SETTINGS),
- case catch 'CosNotifyChannelAdmin_SupplierAdmin':oe_create_link([AdminId, OE_THIS,
- self(), Op,
- ?get_GlobalQoS(State),
- ?get_LocalQoS(State),
- ?get_Options(State)],
- [{sup_child, true}|SO]) of
- {ok, Pid, AdminSu} ->
- %% Due to different storage, adding a new supplier is NOT done in the
- %% same way as for consumers.
- ?add_supplierAdmin(State, AdminId, AdminSu, Pid),
- {reply, {AdminSu, AdminId}, ?set_IdCounter(State, AdminId)};
- What ->
- orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:new_for_suppliers();~n"
- "Unable to create: CosNotifyChannelAdmin_SupplierAdmin.~n"
- "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-%%----------------------------------------------------------%
-%% function : get_consumeradmin
-%% Arguments: AdminId
-%% Returns : ConsAdmin
-%%-----------------------------------------------------------
-get_consumeradmin(OE_THIS, _OE_FROM, State, 0) when ?is_UndefDefConsAdm(State) ->
- Op = 'CosNotification_Common':get_option(filterOp, ?get_Options(State),
- ?not_DEFAULT_SETTINGS),
- SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State),
- ?not_DEFAULT_SETTINGS),
- case catch 'CosNotifyChannelAdmin_ConsumerAdmin':oe_create_link([0, OE_THIS,
- self(), Op,
- ?get_GlobalQoS(State),
- ?get_LocalQoS(State),
- ?get_Options(State)],
- [{sup_child, true}|SO]) of
- {ok, Pid, DefConAdm} ->
- {reply, DefConAdm, ?set_defConsumerAdm(State, DefConAdm, Pid)};
- What ->
- orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:get_consumer_admin();~n"
- "Unable to create: CosNotifyChannelAdmin_ConsumerAdmin.~n"
- "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end;
-get_consumeradmin(_OE_THIS, _OE_FROM, State, 0) ->
- {reply, ?get_defConsumerAdm(State), State};
-get_consumeradmin(_OE_THIS, _OE_FROM, State, AdminId) when is_integer(AdminId) ->
- {reply, ?get_consumerAdmin(State, AdminId), State};
-get_consumeradmin(_, _, _, What) ->
- orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:get_consumeradmin(~p);~n"
- "Not an integer", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------%
-%% function : get_supplieradmin
-%% Arguments: AdminId
-%% Returns :
-%%-----------------------------------------------------------
-get_supplieradmin(OE_THIS, _OE_FROM, State, 0) when ?is_UndefDefSuppAdm(State) ->
- Op = 'CosNotification_Common':get_option(filterOp, ?get_Options(State),
- ?not_DEFAULT_SETTINGS),
- SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State),
- ?not_DEFAULT_SETTINGS),
- case catch 'CosNotifyChannelAdmin_SupplierAdmin':oe_create_link([0, OE_THIS,
- self(), Op,
- ?get_GlobalQoS(State),
- ?get_LocalQoS(State),
- ?get_Options(State)],
- [{sup_child, true}|SO]) of
- {ok, Pid, DefSupAdm} ->
- {reply, DefSupAdm, ?set_defSupplierAdm(State, DefSupAdm, Pid)};
- What ->
- orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:get_supplieradmin();~n"
- "Unable to create: CosNotifyChannelAdmin_SupplierAdmin.~n"
- "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end;
-get_supplieradmin(_OE_THIS, _OE_FROM, State, 0) ->
- {reply, ?get_defSupplierAdm(State), State};
-get_supplieradmin(_OE_THIS, _OE_FROM, State, AdminId) when is_integer(AdminId) ->
- {reply, ?get_supplierAdmin(State, AdminId), State};
-get_supplieradmin(_, _, _, What) ->
- orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:get_supplieradmin(~p);~n"
- "Not an integer", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------%
-%% function : get_all_consumeradmins
-%% Arguments: -
-%% Returns : AdminIDSeq - a list of all unique ID:s.
-%%-----------------------------------------------------------
-get_all_consumeradmins(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_consumerAdmIDs(State), State}.
-
-%%----------------------------------------------------------%
-%% function : get_all_supplieradmins
-%% Arguments: -
-%% Returns : AdminIDSeq - a list of all unique ID:s.
-%%-----------------------------------------------------------
-get_all_supplieradmins(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_supplierAdmIDs(State), State}.
-
-
-%%----- Inherit from CosNotification::QoSAdmin --------------
-%%----------------------------------------------------------%
-%% function : get_qos
-%% Arguments: -
-%% Returns : CosNotification::QoSProperties
-%% [#'Property'{name, value}, ...] where name eq. string()
-%% and value eq. any().
-%%-----------------------------------------------------------
-get_qos(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_GlobalQoS(State), State}.
-
-%%----------------------------------------------------------%
-%% function : set_qos
-%% Arguments: QoS - CosNotification::QoSProperties, i.e.,
-%% [#'Property'{name, value}, ...] where name eq. string()
-%% and value eq. any().
-%% Returns : ok | {'EXCEPTION', CosNotification::UnsupportedQoS}
-%%-----------------------------------------------------------
-set_qos(_OE_THIS, _OE_FROM, State, QoS) ->
- {GQoS,LQoS} = 'CosNotification_Common':set_qos(QoS, ?get_BothQoS(State),
- channel, false,
- ?get_allAdmins(State)),
- {reply, ok, ?set_BothQoS(State, GQoS,LQoS)}.
-
-%%----------------------------------------------------------%
-%% function : validate_qos
-%% Arguments: Required_qos - CosNotification::QoSProperties
-%% [#'Property'{name, value}, ...] where name eq. string()
-%% and value eq. any().
-%% Returns : {'EXCEPTION', CosNotification::UnsupportedQoS} |
-%% {ok, CosNotification::NamedPropertyRangeSeq}
-%%-----------------------------------------------------------
-validate_qos(_OE_THIS, _OE_FROM, State, Required_qos) ->
- QoS = 'CosNotification_Common':validate_qos(Required_qos, ?get_BothQoS(State),
- channel, false,
- ?get_allAdmins(State)),
- {reply, {ok, QoS}, State}.
-
-%%----- Inherit from CosNotification::AdminPropertiesAdmin --
-%%-----------------------------------------------------------%
-%% function : get_admin
-%% Arguments: -
-%% Returns : AdminProperties
-%%-----------------------------------------------------------
-get_admin(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_GlobalAdm(State), State}.
-
-%%----------------------------------------------------------%
-%% function : set_admin
-%% Arguments: Admin
-%% Returns :
-%%-----------------------------------------------------------
-set_admin(_OE_THIS, _OE_FROM, State, Admin) ->
- {GAdm,[MaxQ, MaxC, MaxS|_]} =
- 'CosNotification_Common':set_adm(Admin, ?get_GlobalAdm(State)),
- {reply, ok, ?set_AllAdminP(State, GAdm, MaxQ, MaxC, MaxS)}.
-
-%%----- Inherit from CosEventChannelAdmin::EventChannel -----
-%%----------------------------------------------------------%
-%% function : for_consumers
-%% Arguments: -
-%% Returns : ConsAdm
-%%-----------------------------------------------------------
-for_consumers(OE_THIS, _OE_FROM, State) ->
- is_admin_limit_reached(?get_MaxConsumers(State), ?get_consumerAmount(State)),
- AdminId = ?new_Id(State),
- SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State),
- ?not_DEFAULT_SETTINGS),
- case catch 'CosNotifyChannelAdmin_ConsumerAdmin':oe_create_link([AdminId, OE_THIS,
- self(), 'AND_OP',
- ?get_GlobalQoS(State),
- ?get_LocalQoS(State),
- ?get_Options(State)],
- [{sup_child, true}|SO]) of
- {ok, Pid, AdminCo} ->
- %% Due to different storage, adding a new consumer is NOT done in the
- %% same way as for suppliers.
- NewState = ?add_consumerAdmin(State, AdminId, AdminCo, Pid),
- {reply, AdminCo, ?set_IdCounter(NewState, AdminId)};
- What ->
- orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:for_consumers();~n"
- "Unable to create: CosNotifyChannelAdmin_ConsumerAdmin.~n"
- "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-%%----------------------------------------------------------%
-%% function : for_suppliers
-%% Arguments: -
-%% Returns : SuppAdm
-%%-----------------------------------------------------------
-for_suppliers(OE_THIS, _OE_FROM, State) ->
- is_admin_limit_reached(?get_MaxSuppliers(State), ?get_supplierAmount(State)),
- AdminId = ?new_Id(State),
- SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State),
- ?not_DEFAULT_SETTINGS),
- case catch 'CosNotifyChannelAdmin_SupplierAdmin':oe_create_link([AdminId, OE_THIS,
- self(), 'AND_OP',
- ?get_GlobalQoS(State),
- ?get_LocalQoS(State),
- ?get_Options(State)],
- [{sup_child, true}|SO]) of
- {ok, Pid, AdminSu} ->
- %% Due to different storage, adding a new supplier is NOT done in the
- %% same way as for consumers.
- ?add_supplierAdmin(State, AdminId, AdminSu, Pid),
- {reply, AdminSu, ?set_IdCounter(State, AdminId)};
- What ->
- orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:for_suppliers();~n"
- "Unable to create: CosNotifyChannelAdmin_SupplierAdmin.~n"
- "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-%%-----------------------------------------------------------%
-%% function : destroy
-%% Arguments: -
-%% Returns : ok
-%%------------------------------------------------------------
-destroy(_OE_THIS, _OE_FROM, State) ->
- {stop, normal, ok, State}.
-
-%%--------------- LOCAL FUNCTIONS ----------------------------
-find_obj([]) -> {'EXCEPTION', #'CosNotifyChannelAdmin_AdminNotFound'{}};
-find_obj([{_, Obj,_}]) -> Obj;
-find_obj({value, {_, Obj,_}}) -> Obj;
-find_obj(_) -> {'EXCEPTION', #'CosNotifyChannelAdmin_AdminNotFound'{}}.
-
-
-find_field(List, Field) ->
- find_field(List, Field, []).
-
-find_field([], _, Acc) ->
- Acc;
-find_field([{I,_,_}|T], 1, Acc) ->
- find_field(T, 1, [I|Acc]);
-find_field([{_,O,_}|T], 2, Acc) ->
- find_field(T, 2, [O|Acc]);
-% Left out for now to avoid dialyzer warning.
-%find_field([{_,_,P}|T], 3, Acc) ->
-% find_field(T, 3, [P|Acc]);
-find_field(What, _, _) ->
- orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:find_field();~n"
- "Data corrupt: ~p", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}).
-
-delete_obj(State, Pid) ->
- case ets:match_object(State#state.etsR, {'_', '_', Pid}) of
- [] ->
- State#state{myConsumers=lists:keydelete(Pid, 3, State#state.myConsumers)};
- [{Id,_Obj,Pid}] ->
- ets:delete(State#state.etsR, Id),
- State
- end.
-
-%% Test if we have reached limit for Admin objects.
-is_admin_limit_reached(0, _) ->
- %% When set to zero it means that there is no limit.
- ok;
-is_admin_limit_reached(Max, Current) when Current >= Max ->
- %% The Current value do not include the default Admin objects, hence
- %% we use >= instead of >.
- corba:raise(#'IMP_LIMIT'{completion_status=?COMPLETED_NO});
-is_admin_limit_reached(_, _) ->
- ok.
-
-%%-----------------------------------------------------------
-%% function : callSeq
-%% Arguments:
-%% Returns :
-%%-----------------------------------------------------------
-callSeq(_OE_THIS, OE_FROM, State, Event, Status) ->
- corba:reply(OE_FROM, ok),
- forward(seq, State, Event, Status).
-
-%%-----------------------------------------------------------
-%% function : callAny
-%% Arguments:
-%% Returns :
-%%-----------------------------------------------------------
-callAny(_OE_THIS, OE_FROM, State, Event, Status) ->
- corba:reply(OE_FROM, ok),
- forward(any, State, Event, Status).
-
-%% Forward events
-forward(Type, State, Event, Status) ->
- forward(Type, ?get_consumerAdmins(State), State, Event, Status).
-
-forward(_, [], State, _, _) ->
- {noreply, State};
-forward(Type, [{_,undefined,_}|T], State, Event, Status) ->
- %% Match if no default objects associated.
- forward(Type, T, State, Event, Status);
-forward(any, [{_,H,_}|T], State, Event, Status) ->
- case catch oe_CosNotificationComm_Event:callAny(H, Event, Status) of
- ok ->
- ?DBG("CHANNEL FORWARD ANY: ~p~n",[Event]),
- forward(any, T, State, Event, Status);
- {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') ->
- orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:forward();~n"
- "Admin no longer exists; dropping it: ~p",
- [?LINE, H], ?DEBUG_LEVEL),
- NewState = ?del_consumerAdminRef(State,H),
- forward(any, T, NewState, Event, Status);
- R when ?is_PersistentConnection(State) ->
- orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:forward();~n"
- "Admin behaves badly: ~p/~p",
- [?LINE, R, H], ?DEBUG_LEVEL),
- forward(any, T, State, Event, Status);
- R ->
- orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:forward();~n"
- "Admin behaves badly: ~p~n"
- "Dropping it: ~p", [?LINE, R, H], ?DEBUG_LEVEL),
- NewState = ?del_consumerAdminRef(State, H),
- forward(any, T, NewState, Event, Status)
- end;
-forward(seq, [{_,H,_}|T], State, Event, Status) ->
- case catch oe_CosNotificationComm_Event:callSeq(H, Event, Status) of
- ok ->
- ?DBG("CHANNEL FORWARD SEQUENCE: ~p~n",[Event]),
- forward(seq, T, State, Event, Status);
- {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') ->
- orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:forward();~n"
- "Admin no longer exists; dropping it: ~p",
- [?LINE, H], ?DEBUG_LEVEL),
- NewState = ?del_consumerAdminRef(State,H),
- forward(seq, T, NewState, Event, Status);
- R when ?is_PersistentConnection(State) ->
- orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:forward();~n"
- "Admin behaves badly: ~p/~p",
- [?LINE, R, H], ?DEBUG_LEVEL),
- forward(seq, T, State, Event, Status);
- R ->
- orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:forward();~n"
- "Admin behaves badly: ~p~n"
- "Dropping it: ~p", [?LINE, R, H], ?DEBUG_LEVEL),
- NewState = ?del_consumerAdminRef(State,H),
- forward(seq, T, NewState, Event, Status)
- end.
-
-
-%%--------------- MISC FUNCTIONS, E.G. DEBUGGING -------------
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/cosNotification/src/CosNotifyChannelAdmin_SupplierAdmin_impl.erl b/lib/cosNotification/src/CosNotifyChannelAdmin_SupplierAdmin_impl.erl
deleted file mode 100644
index 2810bef93d..0000000000
--- a/lib/cosNotification/src/CosNotifyChannelAdmin_SupplierAdmin_impl.erl
+++ /dev/null
@@ -1,580 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-------------------------------------------------------------------
-%% File : CosNotifyChannelAdmin_SupplierAdmin_impl.erl
-%% Purpose :
-%%-------------------------------------------------------------------
-
--module('CosNotifyChannelAdmin_SupplierAdmin_impl').
-
-%%--------------- INCLUDES -----------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
-%% Application files
--include("CosNotification.hrl").
--include("CosNotifyChannelAdmin.hrl").
--include("CosNotifyComm.hrl").
--include("CosNotifyFilter.hrl").
--include("CosNotification_Definitions.hrl").
-
-%%--------------- EXPORTS ------------------------------------
-%%--------------- External -----------------------------------
-%%----- CosNotifyChannelAdmin::SupplierAdmin -----------------
--export([get_proxy_consumer/4,
- obtain_notification_pull_consumer/4,
- obtain_notification_push_consumer/4,
- destroy/3]).
-
-%%----- Inherit from CosNotification::QoSAdmin ---------------
--export([get_qos/3,
- set_qos/4,
- validate_qos/4]).
-
-%%----- Inherit from CosNotifyComm::NotifyPublish ------------
--export([offer_change/5]).
-
-%%----- Inherit from CosNotifyFilter::FilterAdmin ------------
--export([add_filter/4,
- remove_filter/4,
- get_filter/4,
- get_all_filters/3,
- remove_all_filters/3]).
-
-%%----- Inherit from CosEventChannelAdmin::SupplierAdmin -----
--export([obtain_push_consumer/3,
- obtain_pull_consumer/3]).
-
-%% Attributes (external)
--export(['_get_MyID'/3,
- '_get_MyChannel'/3,
- '_get_MyOperator'/3,
- '_get_pull_consumers'/3,
- '_get_push_consumers'/3]).
-
-%%--------------- Internal -----------------------------------
-%%----- Inherit from cosNotificationComm ---------------------
--export([callAny/5,
- callSeq/5]).
-
-%%--------------- gen_server specific exports ----------------
--export([handle_info/2, code_change/3]).
--export([init/1, terminate/2]).
-
-%%--------------- LOCAL DEFINITIONS --------------------------
-%% Data structures
--record(state, {myId,
- myChannel,
- myChannelPid,
- myOperator,
- myFilters = [],
- idCounter = 0,
- etsR,
- qosGlobal,
- qosLocal,
- options}).
-
-%% Data structures constructors
--define(get_InitState(_MyID, _MyCh, _MyChP, _MyOp, _QoS, _LQS, _O),
- #state{myId = _MyID,
- myChannel = _MyCh,
- myChannelPid = _MyChP,
- myOperator = _MyOp,
- qosGlobal = _QoS,
- qosLocal = _LQS,
- options = _O,
- etsR = ets:new(oe_ets, [set, protected])}).
-
-%% Data structures selectors
--define(get_PushConsumers(S), lists:flatten(ets:match(S#state.etsR,
- {'_','$1','_',pusher}))).
--define(get_PullConsumers(S), lists:flatten(ets:match(S#state.etsR,
- {'_','$1','_',puller}))).
--define(get_AllConsumers(S), lists:flatten(ets:match(S#state.etsR,
- {'_','$1','_','_'}))).
--define(get_PushConsumerIDs(S), lists:flatten(ets:match(S#state.etsR,
- {'$1','_','_',pusher}))).
--define(get_PullConsumerIDs(S), lists:flatten(ets:match(S#state.etsR,
- {'$1','_','_',puller}))).
-
--define(get_Consumer(S, I), find_obj(ets:lookup(S#state.etsR, I), consumer)).
-
--define(get_MyID(S), S#state.myId).
--define(get_MyChannel(S), S#state.myChannel).
--define(get_MyChannelPid(S), S#state.myChannelPid).
--define(get_MyOperator(S), S#state.myOperator).
--define(get_GlobalQoS(S), S#state.qosGlobal).
--define(get_LocalQoS(S), S#state.qosLocal).
--define(get_BothQoS(S), {S#state.qosGlobal, S#state.qosLocal}).
--define(get_Filter(S, I), find_obj(lists:keysearch(I, 1, S#state.myFilters),
- filter)).
--define(get_AllFilter(S), S#state.myFilters).
--define(get_AllFilterID(S), find_ids(S#state.myFilters)).
--define(get_Options(S), S#state.options).
--define(get_IdCounter(S), S#state.idCounter).
-
-%% Data structures modifiers
--define(set_LocalQoS(S,D), S#state{qosLocal=D}).
--define(set_GlobalQoS(S,D), S#state{qosGlobal=D}).
--define(set_BothQoS(S,GD,LD), S#state{qosGlobal=GD, qosLocal=LD}).
--define(add_PushConsumer(S,I,R,P),ets:insert(State#state.etsR, {I,R,P,pusher})).
--define(add_PullConsumer(S,I,R,P),ets:insert(State#state.etsR, {I,R,P,puller})).
--define(del_Consumer(S,I), ets:delete(S#state.etsR, I)).
--define(del_ConsumerPid(S,P), ets:match_delete(S#state.etsR, {'_','_',P,'_'})).
--define(add_Filter(S,I,O), S#state{myFilters=[{I,O}|S#state.myFilters]}).
--define(del_Filter(S,I), S#state{myFilters=
- delete_filter(lists:keydelete(I, 1,
- S#state.myFilters),
- S#state.myFilters)}).
--define(del_AllFilter(S), S#state{myFilters=[]}).
--define(set_IdCounter(S,V), S#state{idCounter=V}).
--define(new_Id(S), 'CosNotification_Common':create_id(S#state.idCounter)).
-
-%% MISC
--define(is_PersistentEvent(S),
- ?not_GetEventReliability((S#state.qosLocal)) == ?not_Persistent).
--define(is_PersistentConnection(S),
- ?not_GetConnectionReliability((S#state.qosLocal)) == ?not_Persistent).
-
-%%----------------------------------------------------------%
-%% function : handle_info, code_change
-%% Arguments:
-%% Returns :
-%% Effect : Functions demanded by the gen_server module.
-%%-----------------------------------------------------------
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-handle_info(Info, State) ->
- case Info of
- {'EXIT', Pid, Reason} when ?get_MyChannelPid(State) == Pid ->
- ?DBG("PARENT CHANNEL: ~p TERMINATED.~n",[Reason]),
- {stop, Reason, State};
- {'EXIT', Pid, normal} ->
- ?del_ConsumerPid(State, Pid),
- {noreply, State};
- _Other ->
- {noreply, State}
- end.
-
-%%----------------------------------------------------------%
-%% function : init, terminate
-%% Arguments:
-%%-----------------------------------------------------------
-
-init([MyId, MyChannel, MyChannelPid, MyOperator, InitQoS, LQS, Options]) ->
- process_flag(trap_exit, true),
- {ok, ?get_InitState(MyId, MyChannel, MyChannelPid, MyOperator, InitQoS, LQS, Options)}.
-
-terminate(_Reason, _State) ->
- ok.
-
-%%-----------------------------------------------------------
-%%----- CosNotifyChannelAdmin_ConsumerAdmin attributes ------
-%%-----------------------------------------------------------
-%%----------------------------------------------------------%
-%% Attribute: '_get_MyID'
-%% Type : readonly
-%% Returns :
-%%-----------------------------------------------------------
-'_get_MyID'(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_MyID(State), State}.
-
-%%----------------------------------------------------------%
-%% Attribute: '_get_MyChannel'
-%% Type : readonly
-%% Returns :
-%%-----------------------------------------------------------
-'_get_MyChannel'(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_MyChannel(State), State}.
-
-%%----------------------------------------------------------%
-%% Attribute: '_get_MyOperator'
-%% Type : readonly
-%% Returns :
-%%-----------------------------------------------------------
-'_get_MyOperator'(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_MyOperator(State), State}.
-
-%%----------------------------------------------------------%
-%% Attribute: '_get_pull_consumers'
-%% Type : readonly
-%% Returns : ProxyIDSeq
-%%-----------------------------------------------------------
-'_get_pull_consumers'(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_PullConsumerIDs(State), State}.
-
-%%----------------------------------------------------------%
-%% Attribute: '_get_push_consumers'
-%% Type : readonly
-%% Returns : ProxyIDSeq
-%%-----------------------------------------------------------
-'_get_push_consumers'(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_PushConsumerIDs(State), State}.
-
-%%-----------------------------------------------------------
-%%------- Exported external functions -----------------------
-%%-----------------------------------------------------------
-%%----------------------------------------------------------%
-%% function : get_proxy_consumer
-%% Arguments: ProxyId - unique identifier (long)
-%% Returns : ObjRef | {'EXCEPTION', #'ProxyNotFound'{}}
-%%-----------------------------------------------------------
-get_proxy_consumer(_OE_THIS, _OE_FROM, State, ProxyId) ->
- {reply, ?get_Consumer(State, ProxyId), State}.
-
-%%----------------------------------------------------------%
-%% function : obtain_notification_pull_consumer
-%% Arguments:
-%% Returns :
-%%-----------------------------------------------------------
-obtain_notification_pull_consumer(OE_THIS, _OE_FROM, State, Ctype) ->
- %% Choose which module to use.
- {Mod, Type} =
- case Ctype of
- 'ANY_EVENT' ->
- {'CosNotifyChannelAdmin_ProxyPullConsumer', 'PULL_ANY'};
- 'STRUCTURED_EVENT' ->
- {'CosNotifyChannelAdmin_StructuredProxyPullConsumer', 'PULL_STRUCTURED'};
- 'SEQUENCE_EVENT' ->
- {'CosNotifyChannelAdmin_SequenceProxyPullConsumer', 'PULL_SEQUENCE'};
- _ ->
- orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:"
- "obtain_notification_pull_consumer(~p);~n"
- "Incorrect enumerant",
- [?LINE, Ctype], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO})
- end,
- SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State),
- ?not_DEFAULT_SETTINGS),
- case catch Mod:oe_create_link([Type, OE_THIS, self(), ?get_GlobalQoS(State),
- ?get_LocalQoS(State), ?get_MyChannel(State),
- ?get_Options(State), ?get_MyOperator(State)],
- [{sup_child, true}|SO]) of
- {ok, Pid, Proxy} ->
- ProxyID = ?new_Id(State),
- ?add_PullConsumer(State, ProxyID, Proxy, Pid),
- {reply, {Proxy, ProxyID}, ?set_IdCounter(State, ProxyID)};
- What ->
- orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:"
- "obtain_notification_pull_consumer();~n"
- "Unable to create: ~p/~p~n"
- "Reason: ~p", [?LINE, Mod, Type, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-%%----------------------------------------------------------%
-%% function : obtain_notification_push_supplier
-%% Arguments:
-%% Returns :
-%%-----------------------------------------------------------
-obtain_notification_push_consumer(OE_THIS, _OE_FROM, State, Ctype) ->
- %% Choose which module to use.
- {Mod, Type} =
- case Ctype of
- 'ANY_EVENT' ->
- {'CosNotifyChannelAdmin_ProxyPushConsumer', 'PUSH_ANY'};
- 'STRUCTURED_EVENT' ->
- {'CosNotifyChannelAdmin_StructuredProxyPushConsumer', 'PUSH_STRUCTURED'};
- 'SEQUENCE_EVENT' ->
- {'CosNotifyChannelAdmin_SequenceProxyPushConsumer', 'PUSH_SEQUENCE'};
- _ ->
- orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:"
- "obtain_notification_push_consumer(~p);~n"
- "Incorrect enumerant", [?LINE, Ctype], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO})
- end,
- SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State),
- ?not_DEFAULT_SETTINGS),
- case catch Mod:oe_create_link([Type, OE_THIS, self(), ?get_GlobalQoS(State),
- ?get_LocalQoS(State), ?get_MyChannel(State),
- ?get_Options(State), ?get_MyOperator(State)],
- [{sup_child, true}|SO]) of
- {ok, Pid, Proxy} ->
- ProxyID = ?new_Id(State),
- ?add_PushConsumer(State, ProxyID, Proxy, Pid),
- {reply, {Proxy, ProxyID}, ?set_IdCounter(State, ProxyID)};
- What ->
- orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:"
- "obtain_notification_push_consumer();~n"
- "Unable to create: ~p/~p~n"
- "Reason: ~p", [?LINE, Mod, Type, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-%%----------------------------------------------------------%
-%% function : destroy
-%% Arguments: -
-%% Returns : ok
-%%------------------------------------------------------------
-destroy(_OE_THIS, _OE_FROM, State) ->
- {stop, normal, ok, State}.
-
-%%----- Inherit from CosNotification::QoSAdmin --------------
-%%----------------------------------------------------------%
-%% function : get_qos
-%% Arguments:
-%% Returns :
-%%-----------------------------------------------------------
-get_qos(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_GlobalQoS(State), State}.
-
-%%----------------------------------------------------------%
-%% function : set_qos
-%% Arguments: QoS - CosNotification::QoSProperties, i.e.,
-%% [#'Property'{name, value}, ...] where name eq. string()
-%% and value eq. any().
-%% Returns : ok | {'EXCEPTION', CosNotification::UnsupportedQoS}
-%%-----------------------------------------------------------
-set_qos(_OE_THIS, _OE_FROM, State, QoS) ->
- {NewQoS, LQS} = 'CosNotification_Common':set_qos(QoS, ?get_BothQoS(State),
- admin, ?get_MyChannel(State),
- ?get_AllConsumers(State)),
- {reply, ok, ?set_BothQoS(State, NewQoS, LQS)}.
-
-%%----------------------------------------------------------%
-%% function : validate_qos
-%% Arguments: Required_qos - CosNotification::QoSProperties
-%% [#'Property'{name, value}, ...] where name eq. string()
-%% and value eq. any().
-%% Returns : {'EXCEPTION', CosNotification::UnsupportedQoS}
-%% {ok, CosNotification::NamedPropertyRangeSeq}
-%%-----------------------------------------------------------
-validate_qos(_OE_THIS, _OE_FROM, State, Required_qos) ->
- QoS = 'CosNotification_Common':validate_qos(Required_qos, ?get_BothQoS(State),
- admin, ?get_MyChannel(State),
- ?get_AllConsumers(State)),
- {reply, {ok, QoS}, State}.
-
-%%----- Inherit from CosNotifyComm::NotifyPublish -----------
-%%----------------------------------------------------------*
-%% function : offer_change
-%% Arguments:
-%% Returns :
-%%-----------------------------------------------------------
-offer_change(_OE_THIS, _OE_FROM, State, _Added, _Removed) ->
- {reply, ok, State}.
-
-%%----- Inherit from CosNotifyFilter::FilterAdmin -----------
-%%----------------------------------------------------------%
-%% function : add_filter
-%% Arguments: Filter - CosNotifyFilter::Filter
-%% Returns : FilterID - long
-%%-----------------------------------------------------------
-add_filter(_OE_THIS, _OE_FROM, State, Filter) ->
- 'CosNotification_Common':type_check(Filter, 'CosNotifyFilter_Filter'),
- FilterID = ?new_Id(State),
- NewState = ?set_IdCounter(State, FilterID),
- {reply, FilterID, ?add_Filter(NewState, FilterID, Filter)}.
-
-%%----------------------------------------------------------%
-%% function : remove_filter
-%% Arguments: FilterID - long
-%% Returns : ok
-%%-----------------------------------------------------------
-remove_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) ->
- {reply, ok, ?del_Filter(State, FilterID)};
-remove_filter(_,_,_,What) ->
- orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:remove_filter(~p);~n"
- "Not an integer", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------%
-%% function : get_filter
-%% Arguments: FilterID - long
-%% Returns : Filter - CosNotifyFilter::Filter |
-%% {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}}
-%%-----------------------------------------------------------
-get_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) ->
- {reply, ?get_Filter(State, FilterID), State};
-get_filter(_,_,_,What) ->
- orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:get_filter(~p);~n"
- "Not an integer", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------%
-%% function : get_all_filters
-%% Arguments: -
-%% Returns : Filter - CosNotifyFilter::FilterIDSeq
-%%-----------------------------------------------------------
-get_all_filters(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_AllFilterID(State), State}.
-
-%%----------------------------------------------------------%
-%% function : remove_all_filters
-%% Arguments: -
-%% Returns : ok
-%%-----------------------------------------------------------
-remove_all_filters(_OE_THIS, _OE_FROM, State) ->
- {reply, ok, ?del_AllFilter(State)}.
-
-%%----- Inherit from CosEventChannelAdmin::SupplierAdmin ----
-%%----------------------------------------------------------%
-%% function : obtain_push_consumer
-%% Arguments: -
-%% Returns : ProxyPushConsumer
-%%-----------------------------------------------------------
-obtain_push_consumer(OE_THIS, _OE_FROM, State) ->
- SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State),
- ?not_DEFAULT_SETTINGS),
- case catch 'CosNotifyChannelAdmin_ProxyPushConsumer':
- oe_create_link(['PUSH_ANY', OE_THIS, self(), ?get_GlobalQoS(State),
- ?get_LocalQoS(State), ?get_MyChannel(State),
- ?get_Options(State), ?get_MyOperator(State)],
- [{sup_child, true}|SO]) of
- {ok, Pid, Proxy} ->
- ProxyID = ?new_Id(State),
- ?add_PushConsumer(State, ProxyID, Proxy, Pid),
- {reply, Proxy, ?set_IdCounter(State, ProxyID)};
- What ->
- orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:obtain_push_consumer();~n"
- "Unable to create: CosNotifyChannelAdmin_ProxyPushConsumer~n"
- "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-%%----------------------------------------------------------%
-%% function : obtain_pull_consumer
-%% Arguments: -
-%% Returns : ProxyPullConsumer
-%%-----------------------------------------------------------
-obtain_pull_consumer(OE_THIS, _OE_FROM, State) ->
- SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State),
- ?not_DEFAULT_SETTINGS),
- case catch 'CosNotifyChannelAdmin_ProxyPullConsumer':
- oe_create_link(['PULL_ANY', OE_THIS, self(), ?get_GlobalQoS(State),
- ?get_LocalQoS(State), ?get_MyChannel(State),
- ?get_Options(State), ?get_MyOperator(State)],
- [{sup_child, true}|SO]) of
- {ok, Pid, Proxy} ->
- ProxyID = ?new_Id(State),
- ?add_PullConsumer(State, ProxyID, Proxy, Pid),
- {reply, Proxy, ?set_IdCounter(State, ProxyID)};
- What ->
- orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:obtain_push_consumer();~n"
- "Unable to create: CosNotifyChannelAdmin_ProxyPullConsumer~n"
- "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-%%--------------- LOCAL FUNCTIONS ----------------------------
-find_obj([], consumer) -> {'EXCEPTION', #'CosNotifyChannelAdmin_ProxyNotFound'{}};
-find_obj([], filter) -> {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}};
-%% To match consumers
-find_obj([{_,Obj,_,_}],_) -> Obj;
-%% To match filters
-find_obj({value, {_,Obj}},_) -> Obj;
-find_obj(_,consumer) -> {'EXCEPTION', #'CosNotifyChannelAdmin_ProxyNotFound'{}};
-find_obj(_,filter) -> {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}}.
-
-find_ids(List) -> find_ids(List, []).
-find_ids([], Acc) -> Acc;
-find_ids([{I,_}|T], Acc) -> find_ids(T, [I|Acc]);
-find_ids(What, _) ->
- orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:find_ids();~n"
- "Id corrupt: ~p", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}).
-
-%% Delete a single filter.
-%% The list do not differ, i.e., no filter removed, raise exception.
-delete_filter(List,List) -> corba:raise(#'CosNotifyFilter_FilterNotFound'{});
-delete_filter(List, _) -> List.
-
-%%-----------------------------------------------------------
-%% function : callSeq
-%% Arguments:
-%% Returns :
-%%-----------------------------------------------------------
-callSeq(_OE_THIS, OE_FROM, State, Events, _Status) ->
- corba:reply(OE_FROM, ok),
- case cosNotification_eventDB:filter_events(Events, ?get_AllFilter(State)) of
- {[], _} ->
- {noreply, State};
- {Passed, _} ->
- forward(seq, State, Passed, 'MATCHED')
- end.
-
-%%-----------------------------------------------------------
-%% function : callAny
-%% Arguments:
-%% Returns :
-%%-----------------------------------------------------------
-callAny(_OE_THIS, OE_FROM, State, Event, _Status) ->
- corba:reply(OE_FROM, ok),
- case cosNotification_eventDB:filter_events([Event], ?get_AllFilter(State)) of
- {[], _} ->
- {noreply, State};
- {[Passed], _} ->
- forward(any, State, Passed, 'MATCHED')
- end.
-
-%% Forward events
-forward(any, State, Event, Status) ->
- case catch oe_CosNotificationComm_Event:callAny(?get_MyChannel(State),
- Event, Status) of
- ok ->
- ?DBG("SUPPLIERADM FORWARD ANY: ~p~n",[Event]),
- {noreply, State};
- {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') ->
- orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:forward();~n"
- "Channel no longer exists; terminating and dropping: ~p",
- [?LINE, Event], ?DEBUG_LEVEL),
- {stop, normal, State};
- R when ?is_PersistentConnection(State) ->
- orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:forward();~n"
- "Channel respond incorrect: ~p~n"
- "Dropping: ~p", [?LINE, R, Event], ?DEBUG_LEVEL),
- {noreply, State};
- R ->
- orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:forward();~n"
- "Channel respond incorrect: ~p~n"
- "Terminating and dropping: ~p",
- [?LINE, R, Event], ?DEBUG_LEVEL),
- {stop, normal, State}
- end;
-forward(seq, State, Event, Status) ->
- case catch oe_CosNotificationComm_Event:callSeq(?get_MyChannel(State),
- Event, Status) of
- ok ->
- ?DBG("SUPPLIERADM FORWARD SEQUENCE: ~p~n",[Event]),
- {noreply, State};
- {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') ->
- orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:forward();~n"
- "Channel no longer exists; terminating and dropping: ~p",
- [?LINE, Event], ?DEBUG_LEVEL),
- {stop, normal, State};
- R when ?is_PersistentConnection(State) ->
- orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:forward();~n"
- "Channel respond incorrect: ~p~n"
- "Dropping: ~p", [?LINE, R, Event], ?DEBUG_LEVEL),
- {noreply, State};
- R ->
- orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:forward();~n"
- "Channel respond incorrect: ~p~n"
- "Terminating and dropping: ~p",
- [?LINE, R, Event], ?DEBUG_LEVEL),
- {stop, normal, State}
- end.
-
-
-%%--------------- MISC FUNCTIONS, E.G. DEBUGGING -------------
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/cosNotification/src/CosNotifyComm.cfg b/lib/cosNotification/src/CosNotifyComm.cfg
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosNotification/src/CosNotifyComm.cfg
+++ /dev/null
diff --git a/lib/cosNotification/src/CosNotifyComm.idl b/lib/cosNotification/src/CosNotifyComm.idl
deleted file mode 100644
index f0386f0982..0000000000
--- a/lib/cosNotification/src/CosNotifyComm.idl
+++ /dev/null
@@ -1,83 +0,0 @@
-#ifndef _COS_NOTIFYCOMM_IDL_
-#define _COS_NOTIFYCOMM_IDL_
-
-#pragma prefix "omg.org"
-
-
-#include<CosNotification.idl>
-
-module CosNotifyComm {
- exception InvalidEventType { CosNotification::EventType type; };
-
- interface NotifyPublish {
- void offer_change (in CosNotification::EventTypeSeq added,
- in CosNotification::EventTypeSeq removed)
- raises (InvalidEventType);
- }; // NotifyPublish
-
- interface NotifySubscribe {
- void subscription_change(in CosNotification::EventTypeSeq added,
- in CosNotification::EventTypeSeq removed)
- raises (InvalidEventType);
- }; // NotifySubscribe
-
- interface PushConsumer : NotifyPublish, CosEventComm::PushConsumer { }; // PushConsumer
-
- interface PullConsumer : NotifyPublish, CosEventComm::PullConsumer { }; // PullConsumer
-
- interface PullSupplier : NotifySubscribe, CosEventComm::PullSupplier { }; // PullSupplier
-
- interface PushSupplier : NotifySubscribe, CosEventComm::PushSupplier { };
-
- interface StructuredPushConsumer : NotifyPublish {
- void push_structured_event(in CosNotification::StructuredEvent notification)
- raises(CosEventComm::Disconnected);
-
- void disconnect_structured_push_consumer();
- }; // StructuredPushConsumer
-
- interface StructuredPullConsumer : NotifyPublish {
- void disconnect_structured_pull_consumer();
- }; // StructuredPullConsumer
-
- interface StructuredPullSupplier : NotifySubscribe {
- CosNotification::StructuredEvent pull_structured_event()
- raises(CosEventComm::Disconnected);
-
- CosNotification::StructuredEvent try_pull_structured_event(out boolean has_event)
- raises(CosEventComm::Disconnected);
-
- void disconnect_structured_pull_supplier();
- }; // StructuredPullSupplier
-
- interface StructuredPushSupplier : NotifySubscribe {
- void disconnect_structured_push_supplier();
- }; // StructuredPushSupplier
-
- interface SequencePushConsumer : NotifyPublish {
- void push_structured_events(in CosNotification::EventBatch notifications)
- raises(CosEventComm::Disconnected);
-
- void disconnect_sequence_push_consumer();
- }; // SequencePushConsumer
-
- interface SequencePullConsumer : NotifyPublish {
- void disconnect_sequence_pull_consumer();
- }; // SequencePullConsumer
-
- interface SequencePullSupplier : NotifySubscribe {
- CosNotification::EventBatch pull_structured_events(in long max_number)
- raises(CosEventComm::Disconnected);
- CosNotification::EventBatch try_pull_structured_events(in long max_number, out boolean has_event)
- raises(CosEventComm::Disconnected);
-
- void disconnect_sequence_pull_supplier();
- }; // SequencePullSupplier
-
- interface SequencePushSupplier : NotifySubscribe {
- void disconnect_sequence_push_supplier();
- }; // SequencePushSupplier
-}; // CosNotifyComm
-
-#endif /* ifndef _COS_NOTIFYCOMM_IDL_ */
-
diff --git a/lib/cosNotification/src/CosNotifyFilter.cfg b/lib/cosNotification/src/CosNotifyFilter.cfg
deleted file mode 100644
index 167550e0f5..0000000000
--- a/lib/cosNotification/src/CosNotifyFilter.cfg
+++ /dev/null
@@ -1,6 +0,0 @@
-{this, "CosNotifyFilter::Filter"}.
-{{handle_info, "CosNotifyFilter::Filter"}, true}.
-{this, "CosNotifyFilter::MappingFilter"}.
-{{handle_info, "CosNotifyFilter::MappingFilter"}, true}.
-{this, "CosNotifyFilter::FilterFactory"}.
-{{handle_info, "CosNotifyFilter::FilterFactory"}, true}.
diff --git a/lib/cosNotification/src/CosNotifyFilter.idl b/lib/cosNotification/src/CosNotifyFilter.idl
deleted file mode 100644
index c6498ddcd0..0000000000
--- a/lib/cosNotification/src/CosNotifyFilter.idl
+++ /dev/null
@@ -1,140 +0,0 @@
-#ifndef _COS_NOTIFYFILTER_IDL_
-#define _COS_NOTIFYFILTER_IDL_
-
-#pragma prefix "omg.org"
-
-#include<CosNotifyComm.idl>
-#include<CosNotification.idl>
-
-module CosNotifyFilter {
- typedef long ConstraintID;
- struct ConstraintExp {
- CosNotification::EventTypeSeq event_types;
- string constraint_expr;
- };
-
- typedef sequence<ConstraintID> ConstraintIDSeq;
- typedef sequence<ConstraintExp> ConstraintExpSeq;
- struct ConstraintInfo {
- ConstraintExp constraint_expression;
- ConstraintID constraint_id;
- };
- typedef sequence<ConstraintInfo> ConstraintInfoSeq;
- struct MappingConstraintPair {
- ConstraintExp constraint_expression;
- any result_to_set;
- };
- typedef sequence<MappingConstraintPair> MappingConstraintPairSeq;
- struct MappingConstraintInfo {
- ConstraintExp constraint_expression;
- ConstraintID constraint_id;
- any value;
- };
- typedef sequence<MappingConstraintInfo> MappingConstraintInfoSeq;
- typedef long CallbackID;
- typedef sequence<CallbackID> CallbackIDSeq;
- exception UnsupportedFilterableData {};
- exception InvalidGrammar {};
- exception InvalidConstraint {ConstraintExp constr;};
- exception DuplicateConstraintID {ConstraintID id;};
- exception ConstraintNotFound {ConstraintID id;};
- exception CallbackNotFound {};
- exception InvalidValue {ConstraintExp constr; any value;};
- interface Filter {
- readonly attribute string constraint_grammar;
- ConstraintInfoSeq add_constraints (in ConstraintExpSeq constraint_list)
- raises (InvalidConstraint);
-
- void modify_constraints (in ConstraintIDSeq del_list,
- in ConstraintInfoSeq modify_list)
- raises (InvalidConstraint, ConstraintNotFound);
-
- ConstraintInfoSeq get_constraints(in ConstraintIDSeq id_list)
- raises (ConstraintNotFound);
-
- ConstraintInfoSeq get_all_constraints();
-
- void remove_all_constraints();
- void destroy();
- boolean match (in any filterable_data)
- raises (UnsupportedFilterableData);
-
- boolean match_structured (in CosNotification::StructuredEvent filterable_data)
- raises (UnsupportedFilterableData);
-
- boolean match_typed (in CosNotification::PropertySeq filterable_data)
- raises (UnsupportedFilterableData);
-
- CallbackID attach_callback (in CosNotifyComm::NotifySubscribe callback);
-
- void detach_callback (in CallbackID callback)
- raises ( CallbackNotFound );
-
- CallbackIDSeq get_callbacks();
- }; // Filter
-
- interface MappingFilter {
- readonly attribute string constraint_grammar;
-
- readonly attribute CORBA::TypeCode value_type;
-
- readonly attribute any default_value;
-
- MappingConstraintInfoSeq add_mapping_constraints (in MappingConstraintPairSeq pair_list)
- raises (InvalidConstraint, InvalidValue);
-
- void modify_mapping_constraints (in ConstraintIDSeq del_list,
- in MappingConstraintInfoSeq modify_list)
- raises (InvalidConstraint, InvalidValue, ConstraintNotFound);
-
- MappingConstraintInfoSeq get_mapping_constraints (in ConstraintIDSeq id_list)
- raises (ConstraintNotFound);
-
- MappingConstraintInfoSeq get_all_mapping_constraints();
-
- void remove_all_mapping_constraints();
-
- void destroy();
-
- boolean match (in any filterable_data, out any result_to_set)
- raises (UnsupportedFilterableData);
-
- boolean match_structured (in CosNotification::StructuredEvent filterable_data, out any result_to_set)
- raises (UnsupportedFilterableData);
-
- boolean match_typed (in CosNotification::PropertySeq filterable_data, out any result_to_set)
- raises (UnsupportedFilterableData);
- }; // MappingFilter
-
-
- interface FilterFactory {
-
- Filter create_filter (in string constraint_grammar)
- raises (InvalidGrammar);
-
- MappingFilter create_mapping_filter (in string constraint_grammar, in any default_value)
- raises(InvalidGrammar);
- }; // FilterFactory
-
- typedef long FilterID;
- typedef sequence<FilterID> FilterIDSeq;
- exception FilterNotFound {};
-
- interface FilterAdmin {
- FilterID add_filter (in Filter new_filter);
-
- void remove_filter (in FilterID filter)
- raises (FilterNotFound);
-
- Filter get_filter (in FilterID filter)
- raises (FilterNotFound);
-
- FilterIDSeq get_all_filters();
-
- void remove_all_filters();
- }; // FilterAdmin
-}; // CosNotifyFilter
-
-
-#endif /* ifndef _COS_NOTIFYFILTER_IDL_ */
-
diff --git a/lib/cosNotification/src/CosNotifyFilter_FilterFactory_impl.erl b/lib/cosNotification/src/CosNotifyFilter_FilterFactory_impl.erl
deleted file mode 100644
index 760dcf40b8..0000000000
--- a/lib/cosNotification/src/CosNotifyFilter_FilterFactory_impl.erl
+++ /dev/null
@@ -1,126 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : CosNotifyFilter_FilterFactory_impl.erl
-%% Purpose :
-%%----------------------------------------------------------------------
-
--module('CosNotifyFilter_FilterFactory_impl').
-
-
-%%--------------- INCLUDES -----------------------------------
-%% Application files
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
-%% Application files
--include("CosNotification.hrl").
--include("CosNotifyChannelAdmin.hrl").
--include("CosNotifyComm.hrl").
--include("CosNotifyFilter.hrl").
--include("CosNotification_Definitions.hrl").
-
-%%--------------- IMPORTS ------------------------------------
-
-%%--------------- EXPORTS ------------------------------------
-%% External
--export([create_filter/3,
- create_mapping_filter/4]).
-
-%%--------------- gen_server specific exports ----------------
--export([handle_info/2, code_change/3]).
--export([init/1, terminate/2]).
-
-%%--------------- LOCAL DEFINITIONS --------------------------
-%% Data structures
--record(state, {adminProp,
- etsR,
- options}).
-
-%%-----------------------------------------------------------%
-%% function : handle_info, code_change
-%% Arguments: See gen_server documentation.
-%% Effect : Functions demanded by the gen_server module.
-%%------------------------------------------------------------
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-handle_info(_Info, State) ->
- ?debug_print("INFO: ~p DATA: ~p~n", [State, _Info]),
- {noreply, State}.
-
-%%----------------------------------------------------------%
-%% function : init, terminate
-%% Arguments:
-%%-----------------------------------------------------------
-
-init(Options) ->
- process_flag(trap_exit, true),
- {ok, #state{options = Options}}.
-
-terminate(_Reason, _State) ->
- ok.
-
-%%-----------------------------------------------------------
-%%------- Exported external functions -----------------------
-%%-----------------------------------------------------------
-%%----------------------------------------------------------%
-%% function : create_filter
-%% Arguments: InitGrammar - string()
-%% Returns : CosNotifyFilter::Filter |
-%% {'EXCEPTION', InvalidGrammar}
-%%-----------------------------------------------------------
-create_filter(OE_THIS, State, InitGrammar) ->
- case lists:member(InitGrammar, ?not_SupportedGrammars) of
- true ->
- SO = 'CosNotification_Common':get_option(server_options, State#state.options,
- ?not_DEFAULT_SETTINGS),
- Fi='CosNotifyFilter_Filter':oe_create_link([OE_THIS, self(),
- InitGrammar],
- SO),
- {reply, Fi, State};
- _ ->
- corba:raise(#'CosNotifyFilter_InvalidGrammar'{})
- end.
-
-%%----------------------------------------------------------%
-%% function : create_mapping_filter
-%% Arguments: InitGrammar - string()
-%% Returns : CosNotifyFilter::Filter |
-%% {'EXCEPTION', InvalidGrammar}
-%%-----------------------------------------------------------
-create_mapping_filter(OE_THIS, State, InitGrammar, DefVal) ->
- case lists:member(InitGrammar, ?not_SupportedGrammars) of
- true ->
- SO = 'CosNotification_Common':get_option(server_options, State#state.options,
- ?not_DEFAULT_SETTINGS),
- Fi='CosNotifyFilter_MappingFilter':oe_create_link([OE_THIS, self(),
- InitGrammar, DefVal],
- SO),
- {reply, Fi, State};
- _ ->
- corba:raise(#'CosNotifyFilter_InvalidGrammar'{})
- end.
-
-%%--------------- LOCAL FUNCTIONS ----------------------------
-%%--------------- MISC FUNCTIONS, E.G. DEBUGGING -------------
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/cosNotification/src/CosNotifyFilter_Filter_impl.erl b/lib/cosNotification/src/CosNotifyFilter_Filter_impl.erl
deleted file mode 100644
index 0f997049e0..0000000000
--- a/lib/cosNotification/src/CosNotifyFilter_Filter_impl.erl
+++ /dev/null
@@ -1,672 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : CosNotifyFilter_Filter_impl.erl
-%% Purpose :
-%% Note : For an event to be forwarded it's sufficient that at least
-%% one of the constraints return 'true'.
-%% ALL functions in this module are internal. May NOT be used
-%% externally in ANY WAY; only CosNotification system modules.
-%%----------------------------------------------------------------------
-
--module('CosNotifyFilter_Filter_impl').
-
-%%--------------- INCLUDES -----------------------------------
-%% Application files
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
-%% Application files
--include("CosNotification.hrl").
--include("CosNotifyChannelAdmin.hrl").
--include("CosNotifyComm.hrl").
--include("CosNotifyFilter.hrl").
--include("CosNotification_Definitions.hrl").
-
-%%--------------- IMPORTS ------------------------------------
-
-%%--------------- EXPORTS ------------------------------------
-%% External Attributes
--export(['_get_constraint_grammar'/2]).
-%% External Functions
--export([add_constraints/3,
- modify_constraints/4,
- get_constraints/3,
- get_all_constraints/2,
- remove_all_constraints/2,
- destroy/2,
- match/3,
- match_structured/3,
- match_typed/3,
- attach_callback/3,
- detach_callback/3,
- get_callbacks/2]).
-
-%%--------------- gen_server specific exports ----------------
--export([handle_info/2, code_change/3]).
--export([init/1, terminate/2]).
-
-%%--------------- LOCAL DEFINITIONS --------------------------
-%%######### MISC ##########
--define(create_ConstraintInfo(_Types, _Con, _ID),
- #'CosNotifyFilter_ConstraintInfo'{
- constraint_expression =
- #'CosNotifyFilter_ConstraintExp'{
- event_types = _Types,
- constraint_expr = _Con},
- constraint_id = _ID
- }).
-
-%%#### Data structures ####
--record(state, {constraint_grammar,
- constraints = [],
- filters = [],
- callbacks = [],
- idCounter = 0,
- filterFactory,
- factoryPid,
- etsR}).
-
-%% Data structures constructors
--define(get_InitState(Fac, Pid, Gr),
- #state{constraint_grammar=Gr,
- filterFactory=Fac,
- factoryPid=Pid,
- etsR = ets:new(oe_ets, [bag, protected])}).
-
-%%------------------- Data structures selectors -------------------
-%% Grammar
--define(get_Grammar(S), S#state.constraint_grammar).
-%% Callbacks
-% Left out for now to avoid dialyzer warning.
-%-define(get_Callback(S,I), find_obj(lists:keysearch(I, 1, S#state.callbacks),
-% callback)).
--define(get_AllCallback(S), lists:map(fun({_V, C}) -> C end,
- S#state.callbacks)).
--define(get_AllCallbackID(S), lists:map(fun({V, _C}) -> V end,
- S#state.callbacks)).
-%% ID:s
--define(get_IdCounter(S), S#state.idCounter).
-
-%% Constraints
--define(get_Constraint(S,I), find_obj(lists:keysearch(I, 1, S#state.constraints),
- constraint)).
--define(get_AllConstraints(S), lists:map(fun({I, C, _W, _WC, _K, T}) ->
- ?create_ConstraintInfo(T, C, I)
- end,
- S#state.constraints)).
--define(get_ConstraintAllData(S), S#state.constraints).
--define(get_ConstraintData(S,I), lists:keysearch(I, 1, S#state.constraints)).
--define(match_Type(S,I,ET), ets:lookup(S#state.etsR, {I, ET})).
-%% Parse Tree
--define(get_ParseTree(S,K), find_obj(ets:lookup(S#state.etsR, K), tree)).
-
-%%------------------- Data structures modifiers -------------------
-%% Callbacks
--define(del_Callback(S,I), S#state{callbacks =
- delete_obj(lists:keydelete(I,1,
- S#state.callbacks),
- S#state.callbacks, callback)}).
--define(del_AllCallbacks(S), S#state{callbacks=[]}).
--define(add_Callback(S,V,C), S#state{idCounter=V,
- callbacks = [{V,C}|S#state.callbacks]}).
-%% ID:s
--define(set_IdCounter(S,V), S#state{idCounter=V}).
--define(new_Id(S), 'CosNotification_Common':create_id(S#state.idCounter)).
-
-%% Constraints
--define(del_Constraint(S, I), match_delete(S, S#state.constraints, I)).
--define(del_AllConstraints(S), clear_DB(S)).
--define(add_Constraint(S,I,C,W,_WC,K,T), S#state{constraints =
- [{I, C, W, _WC, K, T}|S#state.constraints]}).
--define(set_Constraints(S,C), S#state{constraints = C}).
-
--define(del_AllTypes(S), ets:match_delete(S#state.etsR, {'_','_',types})).
--define(del_Type(S,I), ets:match_delete(S#state.etsR, {{I, '_'}, '_', types})).
--define(add_Type(S,I,ET,K), ets:insert(S#state.etsR, {{I, ET}, K, types})).
-
-%% Parse Tree
--define(add_ParseTree(S,K,T), ets:insert(S#state.etsR, {K, T, tree})).
--define(del_ParseTree(S,K), ets:delete(S#state.etsR, K)).
--define(del_AllParseTress(S), ets:match_delete(S#state.etsR, {'_','_',tree})).
-
-%%------------------- MISC ----------------------------------------
--define(is_EmptyFilter(S), S#state.constraints==[]).
-
--define(InfoSeq2EventTypeSeq(L), lists:flatten(
- lists:map(fun(#'CosNotifyFilter_ConstraintInfo'
- {constraint_expression=
- #'CosNotifyFilter_ConstraintExp'
- {event_types = ET}}) ->
- ET
- end,
- L))).
-
-%%-----------------------------------------------------------%
-%% Function : handle_info, code_change
-%% Arguments: See gen_server documentation.
-%% Effect : Functions demanded by the gen_server module.
-%%------------------------------------------------------------
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-handle_info(Info, State) ->
- ?debug_print("INFO: ~p DATA: ~p~n", [State, Info]),
- case Info of
- {'EXIT', _Pid, _Reason} ->
- {noreply, State};
- _ ->
- {noreply, State}
- end.
-
-%%----------------------------------------------------------%
-%% Function : init, terminate
-%% Arguments:
-%%-----------------------------------------------------------
-
-init([FiFac, FacPid, ConstraintGr]) ->
- process_flag(trap_exit, true),
- {ok, ?get_InitState(FiFac, FacPid, ConstraintGr)}.
-
-terminate(_Reason, _State) ->
- ok.
-
-%%-----------------------------------------------------------
-%%------- Exported external attributes ----------------------
-%%-----------------------------------------------------------
-%%----------------------------------------------------------%
-%% Function : '_get_constraint_grammar'/2
-%% Type : readonly
-%% Returns : Grammar - string()
-%%-----------------------------------------------------------
-'_get_constraint_grammar'(_OE_THIS, State) ->
- {reply, ?get_Grammar(State), State}.
-
-%%-----------------------------------------------------------
-%%------- Exported external functions -----------------------
-%%-----------------------------------------------------------
-%%----------------------------------------------------------%
-%% Function : add_constraints/3
-%% Arguments: CL - CosNotifyFilter::ConstraintExpSeq
-%% Returns : CosNotifyFilter::ConstraintInfoSeq |
-%% {'EXCEPTION', CosNotifyFilter::InvalidConstraint}
-%%-----------------------------------------------------------
-add_constraints(_OE_THIS, State, CL) ->
- {NewState, Filters, Info, EventTSeq} = try_create_filters(State, CL),
- NewState2=store_filters(NewState, Filters),
- inform_callbacks(?get_AllCallback(NewState2), EventTSeq, []),
- {reply, Info, NewState2}.
-
-%%----------------------------------------------------------%
-%% Function : modify_constraints/4
-%% Arguments: IDs - CosNotifyFilter::ConstraintIDSeq
-%% AddConstraintInfoSeq - CosNotifyFilter::ConstraintInfoSeq
-%% Returns : ok |
-%% {'EXCEPTION', CosNotifyFilter::InvalidConstraint} |
-%% {'EXCEPTION', CosNotifyFilter::ConstraintNotFound}
-%%-----------------------------------------------------------
-%% The OMG specification (TC Document telecom/98-11-01, chapter
-%% 3.2.1.3) states (concerning IDs):
-%%
-%% "If all input values supplied within a particular invocation
-%% of this operation are valid, then the specific constraints
-%% identified by the values contained in the first input parameter
-%% will be deleted from the list of those encapsulated by the target
-%% filter object."
-%%
-%% Hence, first we must check if all ID's exists before deleting.
-modify_constraints(_OE_THIS, State, IDs, AddConstraintInfoSeq) ->
- %% The following functions are 'safe', i.e., they do not alter any data.
- RemoveConstraintInfoSeq = lookup_constraints(IDs, State),
- lookup_constraints(AddConstraintInfoSeq, State),
- {NewState, Filters, _Info, AddedEventTSeq} =
- try_create_filters(State, AddConstraintInfoSeq),
- RemovedEventTSeq = ?InfoSeq2EventTypeSeq(RemoveConstraintInfoSeq),
-
- %% We cannot change anything before our checks (see above). Hence,
- %% do NOT move the following lines above this point.
- NewState2 = delete_constraints(IDs, NewState),
-
-%% The OMG specification (TC Document telecom/98-11-01, chapter
-%% 3.2.1.3) states (concerning AddConstraintInfoSeq):
-%%
-%% "If all input values supplied within a particular invocation of this
-%% operation are valid, then the constraint expression associated with the
-%% already encapsulated constraint identified by the numeric value contained
-%% within each element of the input sequence will be modified to the new
-%% constraint expression that is contained within the same sequence element."
-%%
-%% This, our interpretation, implies that ALL previous data related
-%% to each unique ID should be removed and replaced by the new data.
-
- NewState3 = delete_constraints(AddConstraintInfoSeq, NewState2),
- NewState4 = store_filters(NewState3, Filters),
- inform_callbacks(?get_AllCallback(NewState4),
- AddedEventTSeq, RemovedEventTSeq),
- {reply, ok, NewState4}.
-
-%%----------------------------------------------------------%
-%% Function : get_constraints/3
-%% Arguments: IDs - CosNotifyFilter::ConstraintIDSeq
-%% Returns : CosNotifyFilter::ConstraintInfoSeq |
-%% {'EXCEPTION', CosNotifyFilter::ConstraintNotFound}
-%%-----------------------------------------------------------
-get_constraints(_OE_THIS, State, IDs) ->
- {reply, lookup_constraints(IDs, State), State}.
-
-%%----------------------------------------------------------%
-%% Function : get_all_constraints/2
-%% Arguments: -
-%% Returns : CosNotifyFilter::ConstraintInfoSeq
-%%-----------------------------------------------------------
-get_all_constraints(_OE_THIS, State) ->
- {reply, ?get_AllConstraints(State), State}.
-
-%%----------------------------------------------------------%
-%% Function : remove_all_constraints/2
-%% Arguments: -
-%% Returns : ok
-%%-----------------------------------------------------------
-remove_all_constraints(_OE_THIS, State) ->
- {reply, ok, ?del_AllConstraints(State)}.
-
-%%----------------------------------------------------------%
-%% Function : destroy/2
-%% Arguments: -
-%% Returns : ok
-%%-----------------------------------------------------------
-destroy(_OE_THIS, State) ->
- {stop, normal, ok, State}.
-
-%%----------------------------------------------------------%
-%% Function : match/3
-%% Arguments: Event - #any{}
-%% Returns : boolean() |
-%% {'EXCEPTION', CosNotifyFilter::UnsupportedFilterableData}
-%%-----------------------------------------------------------
-
-match(_OE_THIS, State, Event) when is_record(Event,'any'), ?is_EmptyFilter(State) ->
- {reply, true, State};
-match(_OE_THIS, State, Event) when is_record(Event,'any') ->
- match_any_event(State, Event, ?get_ConstraintAllData(State));
-match(_,_,What) ->
- orber:dbg("[~p] CosNotifyFilter_Filter:match(~p);~n"
- "Not an CORBA::Any", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------%
-%% Function : match_structured/3
-%% Arguments: Event - CosNotification::StructuredEvent
-%% Returns : boolean() |
-%% {'EXCEPTION', CosNotifyFilter::UnsupportedFilterableData}
-%%-----------------------------------------------------------
-match_structured(_OE_THIS, State, Event) when
- is_record(Event,'CosNotification_StructuredEvent') andalso ?is_EmptyFilter(State) ->
- {reply, true, State};
-match_structured(_OE_THIS, State, Event) when
- is_record(Event,'CosNotification_StructuredEvent') ->
- match_str_event(State, Event, ?get_ConstraintAllData(State));
-match_structured(_,_,What) ->
- orber:dbg("[~p] CosNotifyFilter_Filter:match_structured(~p);~n"
- "Not a StructuredEvent", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------*
-%% Function : match_typed/3
-%% Arguments: Data - CosNotification::PropertySeq
-%% Returns : boolean() |
-%% {'EXCEPTION', CosNotifyFilter::UnsupportedFilterableData}
-%%-----------------------------------------------------------
--spec match_typed(_, _, _) -> no_return().
-match_typed(_OE_THIS, _State, _Data) ->
- corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------%
-%% Function : attach_callback/3
-%% Arguments: CB - CosNotifyComm::NotifySubscribe
-%% Returns : ID - CosNotifyFilter::CallbackID
-%%-----------------------------------------------------------
-attach_callback(_OE_THIS, State, CB) ->
- 'CosNotification_Common':type_check(CB, 'CosNotifyComm_NotifySubscribe'),
- CBID = ?new_Id(State),
- {reply, CBID, ?add_Callback(State, CBID, CB)}.
-
-%%----------------------------------------------------------%
-%% Function : detach_callback/3
-%% Arguments: ID - CosNotifyFilter::CallbackID
-%% Returns : ok | {'EXCEPTION', CosNotifyFilter::CallbackNotFound}
-%%-----------------------------------------------------------
-detach_callback(_OE_THIS, State, ID) when is_integer(ID) ->
- {reply, ok, ?del_Callback(State, ID)};
-detach_callback(_,_,What) ->
- orber:dbg("[~p] CosNotifyFilter_Filter:detach_callback(~p);~n"
- "Not an integer", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------%
-%% Function : get_callbacks/2
-%% Arguments: -
-%% Returns : CosNotifyFilter::CallbackIDSeq
-%%-----------------------------------------------------------
-get_callbacks(_OE_THIS, State) ->
- {reply, ?get_AllCallbackID(State), State}.
-
-%%--------------- LOCAL FUNCTIONS ----------------------------
-%% To match callbacks
-find_obj({value, {_, Obj}},_) -> Obj;
-%% To match constraints
-find_obj({value, {Id, Con, _, _, _, Types}}, _) ->
- ?create_ConstraintInfo(Types, Con, Id);
-find_obj([{_, Tree, tree}|_], tree) -> Tree;
-% Left out for now to avoid dialyzer warning.
-%find_obj(_,callback) -> {'EXCEPTION', #'CosNotifyFilter_CallbackNotFound'{}};
-find_obj(_,tree) -> undefined;
-find_obj(_,constraint) -> error.
-
-%% Delete a single object.
-delete_obj(List,List,callback) -> corba:raise(#'CosNotifyFilter_CallbackNotFound'{});
-delete_obj(List,_,_) -> List.
-
-%% Delete given object from list and all related objects in DB (parse tree and types).
-match_delete(State, Constraints, ID) ->
- match_delete(State, Constraints, ID, []).
-match_delete(_, [], _, _) ->
- error;
-match_delete(State, [{ID, _Con, _Which, _WC, Key, _Types}|T], ID, Acc) ->
- ?del_Type(State, ID),
- ?del_ParseTree(State, Key),
- {ok, ?set_Constraints(State, Acc++T)};
-match_delete(State, [H|T], ID, Acc) ->
- match_delete(State, T, ID, [H|Acc]).
-
-%% Remove all data related with constraints; for now, since no other data
-%% stored in DB, we do in a rather brutal way.
-clear_DB(State) ->
- catch ets:delete(State#state.etsR),
- State#state{etsR = ets:new(oe_ets, [bag, protected]), constraints=[]}.
-
-%% Given a list of Constrain IDs we want to find the related constraints.
-%% !!!!!! This function may not alter any data in DB in any way !!!!!!!!!!
-lookup_constraints(IDs, State) ->
- lookup_constraints(IDs, State, []).
-lookup_constraints([], _State, Accum) ->
- Accum;
-lookup_constraints([H|T], State, Accum)
- when is_record(H, 'CosNotifyFilter_ConstraintInfo') ->
- case ?get_Constraint(State, H#'CosNotifyFilter_ConstraintInfo'.constraint_id) of
- error ->
- corba:raise(#'CosNotifyFilter_ConstraintNotFound'
- {id = H#'CosNotifyFilter_ConstraintInfo'.constraint_id});
- _Con ->
- %% We don't need to collect the result since the input already is of
- %% the correct type, i.e., ConstraintInfoSeq
- lookup_constraints(T, State, Accum)
- end;
-lookup_constraints([H|T], State, Accum) when is_integer(H) ->
- case ?get_Constraint(State,H) of
- error ->
- corba:raise(#'CosNotifyFilter_ConstraintNotFound'{id=H});
- Con ->
- lookup_constraints(T, State, [Con|Accum])
- end;
-lookup_constraints(_, _, _) ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%% Given a list of Constrain IDs we want to delet the related constraints.
-%% We need also to return the ConstraintInfoSeq described related to the
-%% given ID's.
-delete_constraints([], State) ->
- State;
-delete_constraints([H|T], State)
- when is_record(H, 'CosNotifyFilter_ConstraintInfo') ->
- case catch ?del_Constraint(State,
- H#'CosNotifyFilter_ConstraintInfo'.constraint_id) of
- {ok, NewState} ->
- delete_constraints(T, NewState);
- Reason ->
- orber:dbg("[~p] 'CosNotifyFilter_Filter':modify_constraints().~n"
- "Unable to remove: ~p~n"
- "Reason: ~p~n",
- [?LINE, H, Reason], ?DEBUG_LEVEL),
- delete_constraints(T, State)
- end;
-delete_constraints([H|T], State) ->
- case catch ?del_Constraint(State,H) of
- {ok, NewState} ->
- delete_constraints(T, NewState);
- Reason ->
- orber:dbg("[~p] 'CosNotifyFilter_Filter':modify_constraints().~n"
- "Unable to remove: ~p~n"
- "Reason: ~p~n",
- [?LINE, H, Reason], ?DEBUG_LEVEL),
- delete_constraints(T, State)
- end.
-
-%% Inform all registered callbacks that the constraints have changed.
-%% Added and Removed must be a CosNotification::EventTypeSeq
-inform_callbacks([],_,_) ->
- ok;
-inform_callbacks([H|T], Added, Removed) ->
- case catch 'CosNotifyComm_NotifySubscribe':subscription_change(H, Added, Removed) of
- ok ->
- ?debug_print("INFORMED CALLBACK: ~p ADDED: ~p REMOVED: ~p",
- [H, Added, Removed]),
- inform_callbacks(T, Added, Removed);
- Other ->
- orber:dbg("[~p] 'CosNotifyComm_NotifySubscribe':subscription_change().~n"
- "Unable to inform callback: ~p~n"
- "Reason: ~p~n",
- [?LINE, H, Other], ?DEBUG_LEVEL),
- inform_callbacks(T, Added, Removed)
- end.
-
-%%-----------------------------------------------------------
-%% Function : try_create_filters/2
-%% Arguments: CL - #'CosNotifyFilter_ConstraintExp'{
-%% event_types = [#'CosNotification_EventType'{
-%% domain_name = Str, type_name = Str}]
-%% constraint_expr = Str}
-%% Returns : {State, AccumList}
-%%-----------------------------------------------------------
-%% !!!!!! This function may not alter any data in DB in any way !!!!!!!!!!
-try_create_filters(State, CL) ->
- try_create_filters(State, CL, [], [], []).
-try_create_filters(State, [], Accum, InfoSeq, EventTSeq) ->
- {State, Accum, InfoSeq, EventTSeq};
-try_create_filters(State, [#'CosNotifyFilter_ConstraintExp'{event_types = Types,
- constraint_expr = Con}|T],
- Accum, InfoSeq, EventTSeq) ->
- case catch cosNotification_Filter:create_filter(Con) of
- {ok, Tree} ->
- case catch cosNotification_Filter:check_types(Types) of
- true ->
- ID = ?new_Id(State),
- Key = ?not_CreateDBKey,
- NewETSeq = Types ++ EventTSeq,
- try_create_filters(?set_IdCounter(State, ID), T,
- [{ID, true, [], Key, Types, Con, Tree}|Accum],
- [?create_ConstraintInfo(Types, Con, ID)|InfoSeq],
- NewETSeq);
- {ok, Which, WC} ->
- ID = ?new_Id(State),
- Key = ?not_CreateDBKey,
- NewETSeq = Types ++ EventTSeq,
- try_create_filters(?set_IdCounter(State, ID), T,
- [{ID, Which, WC, Key, Types, Con, Tree}|Accum],
- [?create_ConstraintInfo(Types, Con, ID)|InfoSeq],
- NewETSeq);
- _ ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO})
- end;
- _ ->
- corba:raise(#'CosNotifyFilter_InvalidConstraint'
- {constr = #'CosNotifyFilter_ConstraintExp'
- {event_types = Types, constraint_expr = Con}})
- end;
-try_create_filters(State, [#'CosNotifyFilter_ConstraintInfo'
- {constraint_expression = #'CosNotifyFilter_ConstraintExp'
- {event_types = Types, constraint_expr = Con},
- constraint_id=ID}|T], Accum, InfoSeq, EventTSeq) ->
- case catch cosNotification_Filter:create_filter(Con) of
- {ok, Tree} ->
- case catch cosNotification_Filter:check_types(Types) of
- true ->
- Key = ?not_CreateDBKey,
- NewETSeq = Types ++ EventTSeq,
- try_create_filters(State, T,
- [{ID, true, [], Key, Types, Con, Tree}|Accum],
- [?create_ConstraintInfo(Types, Con, ID)|InfoSeq],
- NewETSeq);
- {ok, Which, WC} ->
- Key = ?not_CreateDBKey,
- NewETSeq = Types ++ EventTSeq,
- try_create_filters(State, T,
- [{ID, Which, WC, Key, Types, Con, Tree}|Accum],
- [?create_ConstraintInfo(Types, Con, ID)|InfoSeq],
- NewETSeq);
- _ ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO})
- end;
- _ ->
- corba:raise(#'CosNotifyFilter_InvalidConstraint'
- {constr = #'CosNotifyFilter_ConstraintExp'
- {event_types = Types, constraint_expr = Con}})
- end;
-try_create_filters(_,_,_,_,_) ->
- %% The list contained something else but ConstraintExp.
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%-----------------------------------------------------------
-%% Function : store_filters/4
-%% Arguments: Filters - a list of filters.
-%% Returns :
-%%-----------------------------------------------------------
-
-store_filters(State, []) ->
- State;
-store_filters(State, [{ID, Which, WC, Key, Types, Con, Tree}|T]) ->
- ?add_ParseTree(State, Key, Tree),
- write_types(State, Types, ID, Key),
- store_filters(?add_Constraint(State, ID, Con, Which, WC, Key, Types), T).
-
-
-write_types(_State, [],_, _) ->
- ok;
-write_types(State, [EventType|T], ID, Key) ->
- ?add_Type(State, ID, EventType, Key),
- ?debug_print("FILTER: ~p ~p ~p~n", [ID, Key, EventType]),
- write_types(State, T, ID, Key).
-
-%%-----------------------------------------------------------
-%% Function : match_any_event
-%% Arguments:
-%% Returns :
-%%-----------------------------------------------------------
-match_any_event(State, _Event, []) ->
- ?debug_print("FILTER REJECTED: ~p~n", [_Event]),
- {reply, false, State};
-match_any_event(State, Event, [{_, _, _, _, Key, _}|T]) ->
- case catch cosNotification_Filter:eval(?get_ParseTree(State,Key), Event) of
- true ->
- ?debug_print("FILTER APPROVED (WC): ~p~n", [Event]),
- {reply, true, State};
- _ ->
- match_any_event(State, Event, T)
- end.
-
-
-%%-----------------------------------------------------------
-%% Function : match_str_event
-%% Arguments:
-%% Returns :
-%%-----------------------------------------------------------
-
-match_str_event(State, _Event, []) ->
- ?debug_print("FILTER REJECTED: ~p~n", [_Event]),
- {reply, false, State};
-match_str_event(State, Event, [{ID, _Con, Which, WC, Key, _Types}|T]) ->
- ET = ((Event#'CosNotification_StructuredEvent'.header)
- #'CosNotification_EventHeader'.fixed_header)
- #'CosNotification_FixedEventHeader'.event_type,
- CheckList =
- case Which of
- both ->
- [ET];
- domain ->
- [ET,
- ET#'CosNotification_EventType'{type_name=""},
- ET#'CosNotification_EventType'{type_name="*"}];
- type ->
- [ET,
- ET#'CosNotification_EventType'{domain_name=""},
- ET#'CosNotification_EventType'{domain_name="*"}];
- _ ->
- [ET,
- ET#'CosNotification_EventType'{type_name=""},
- ET#'CosNotification_EventType'{type_name="*"},
- ET#'CosNotification_EventType'{domain_name=""},
- ET#'CosNotification_EventType'{domain_name="*"}]
- end,
- case check_DB(State, ID, CheckList) of
- false ->
- %% No match, may have used wildcards, e.g., "dom*".
- case catch cosNotification_Filter:match_types(
- ET#'CosNotification_EventType'.domain_name,
- ET#'CosNotification_EventType'.type_name,
- WC) of
- true ->
- case catch cosNotification_Filter:eval(?get_ParseTree(State,Key),
- Event) of
- true ->
- ?debug_print("FILTER APPROVED (WC): ~p~n", [Event]),
- {reply, true, State};
- _ ->
- match_str_event(State, Event, T)
- end;
- _->
- match_str_event(State, Event, T)
- end;
- Key ->
- case catch cosNotification_Filter:eval(?get_ParseTree(State,Key),
- Event) of
- true ->
- ?debug_print("FILTER APPROVED: ~p~n", [Event]),
- {reply, true, State};
- _ ->
- match_str_event(State, Event, T)
- end
- end.
-
-check_DB(_, _, []) ->
- false;
-check_DB(State, ID, [H|T]) ->
- case ?match_Type(State, ID, H) of
- [] ->
- check_DB(State, ID, T);
- [{_, K, types}|_] ->
- K
- end.
-
-
-%%--------------- MISC FUNCTIONS, E.G. DEBUGGING -------------
-%%--------------- END OF MODULE ------------------------------
-
diff --git a/lib/cosNotification/src/CosNotifyFilter_MappingFilter_impl.erl b/lib/cosNotification/src/CosNotifyFilter_MappingFilter_impl.erl
deleted file mode 100644
index 03c0e03be6..0000000000
--- a/lib/cosNotification/src/CosNotifyFilter_MappingFilter_impl.erl
+++ /dev/null
@@ -1,580 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : CosNotifyFilter_MappingFilter_impl.erl
-%% Purpose :
-%%----------------------------------------------------------------------
-
--module('CosNotifyFilter_MappingFilter_impl').
-
-%%--------------- INCLUDES -----------------------------------
-%% Application files
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
-%% Application files
--include("CosNotification.hrl").
--include("CosNotifyChannelAdmin.hrl").
--include("CosNotifyComm.hrl").
--include("CosNotifyFilter.hrl").
--include("CosNotification_Definitions.hrl").
-
-%%--------------- IMPORTS ------------------------------------
-
-%%--------------- EXPORTS ------------------------------------
-%% External Attributes
--export(['_get_constraint_grammar'/2,
- '_get_value_type'/2,
- '_get_default_value'/2]).
-%% External Functions
--export([add_mapping_constraints/3,
- modify_mapping_constraints/4,
- get_mapping_constraints/3,
- get_all_mapping_constraints/2,
- remove_all_mapping_constraints/2,
- destroy/2,
- match/3,
- match_structured/3,
- match_typed/3]).
-
-%%--------------- gen_server specific exports ----------------
--export([handle_info/2, code_change/3]).
--export([init/1, terminate/2]).
-
-%%--------------- LOCAL DEFINITIONS --------------------------
-%%######### MISC ##########
--define(create_MappingInfo(_Types, _Con, _ID, _A),
- #'CosNotifyFilter_MappingConstraintInfo'{
- constraint_expression =
- #'CosNotifyFilter_ConstraintExp'{
- event_types = _Types,
- constraint_expr = _Con},
- constraint_id = _ID,
- value = _A
- }).
-%%#### Data structures ####
--record(state, {constraint_grammar,
- value,
- typeC,
- constraints = [],
- filters = [],
- idCounter = 0,
- filterFactory,
- factoryPid,
- etsR}).
-
-%% Data structures constructors
--define(get_InitState(Gr, DVal, FF, FP),
- #state{constraint_grammar=Gr,
- value = DVal,
- typeC = any:get_typecode(DVal),
- filterFactory = FF,
- factoryPid = FP,
- etsR = ets:new(oe_ets, [bag, protected])}).
-
-%%------------------- Data structures selectors -------------------
-%% Attributes
--define(get_Grammar(S), S#state.constraint_grammar).
--define(get_DefVal(S), S#state.value).
--define(get_DefTC(S), S#state.typeC).
--define(get_DefAny(S), S#state.value).
-
-%% ID:s
--define(get_IdCounter(S), S#state.idCounter).
-
-%% Constraints
--define(get_Constraint(S,I), find_obj(lists:keysearch(I, 1, S#state.constraints),
- constraint)).
--define(get_AllConstraints(S), lists:map(fun({I, C, _W, _WC, _K, T, A}) ->
- ?create_MappingInfo(T, C, I, A)
- end,
- S#state.constraints)).
--define(get_ConstraintAllData(S), S#state.constraints).
--define(get_ConstraintData(S,I), lists:keysearch(I, 1, S#state.constraints)).
--define(match_Type(S,I,ET), ets:lookup(S#state.etsR, {I, ET})).
-%% Parse Tree
--define(get_ParseTree(S,K), find_obj(ets:lookup(S#state.etsR, K), tree)).
-
-%%------------------- Data structures modifiers -------------------
-%% ID:s
--define(set_IdCounter(S,V), S#state{idCounter=V}).
--define(new_Id(S), 'CosNotification_Common':create_id(S#state.idCounter)).
-
-%% Constraints
--define(del_Constraint(S, I), match_delete(S, S#state.constraints, I)).
--define(del_AllConstraints(S), clear_DB(S)).
--define(add_Constraint(S,I,C,W,_WC,K,T,A), S#state{constraints =
- [{I, C, W, _WC, K, T, A}|S#state.constraints]}).
--define(set_Constraints(S,C), S#state{constraints = C}).
-
--define(del_AllTypes(S), ets:match_delete(S#state.etsR, {'_','_',types})).
--define(del_Type(S,I), ets:match_delete(S#state.etsR, {{I, '_'}, '_', types})).
--define(add_Type(S,I,ET,K), ets:insert(S#state.etsR, {{I, ET}, K, types})).
-
-%% Parse Tree
--define(add_ParseTree(S,K,T), ets:insert(S#state.etsR, {K, T, tree})).
--define(del_ParseTree(S,K), ets:delete(S#state.etsR, K)).
--define(del_AllParseTress(S), ets:match_delete(S#state.etsR, {'_','_',tree})).
-
-%%------------------- MISC ----------------------------------------
--define(is_EmptyFilter(S), S#state.constraints==[]).
--define(is_EqualType(S,T), S#state.typeC==any:get_typecode(T)).
-
-%%-----------------------------------------------------------%
-%% function : handle_info, code_change
-%% Arguments: See gen_server documentation.
-%% Effect : Functions demanded by the gen_server module.
-%%------------------------------------------------------------
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-handle_info(Info, State) ->
- ?debug_print("INFO: ~p DATA: ~p~n", [State, Info]),
- case Info of
- {'EXIT', _Pid, _Reason} ->
- {noreply, State};
- _ ->
- {noreply, State}
- end.
-
-%%----------------------------------------------------------%
-%% function : init, terminate
-%% Arguments:
-%%-----------------------------------------------------------
-
-init([FiFac, FacPid, InitGr, DefVal]) ->
- process_flag(trap_exit, true),
- {ok, ?get_InitState(InitGr, DefVal, FiFac, FacPid)}.
-
-terminate(_Reason, _State) ->
- ok.
-
-%%-----------------------------------------------------------
-%%------- Exported external attributes ----------------------
-%%-----------------------------------------------------------
-%%----------------------------------------------------------%
-%% Function : '_get_constraint_grammar'/2
-%% Type : readonly
-%% Returns : string()
-%%-----------------------------------------------------------
-'_get_constraint_grammar'(_OE_THIS, State) ->
- {reply, ?get_Grammar(State), State}.
-%%----------------------------------------------------------%
-%% Function : '_get_value_type'/2
-%% Type : readonly
-%% Returns : CORBA::TypeCode
-%%-----------------------------------------------------------
-'_get_value_type'(_OE_THIS, State) ->
- {reply, ?get_DefTC(State), State}.
-%%----------------------------------------------------------%
-%% Function : '_get_default_value'/2
-%% Type : readonly
-%% Returns : #any{}
-%%-----------------------------------------------------------
-'_get_default_value'(_OE_THIS, State) ->
- {reply, ?get_DefVal(State), State}.
-
-%%-----------------------------------------------------------
-%%------- Exported external functions -----------------------
-%%-----------------------------------------------------------
-%%----------------------------------------------------------%
-%% Function : add_mapping_constraints/3
-%% Arguments: Pairs - CosNotifyFilter::MappingConstraintPairSeq
-%% Returns : CosNotifyFilter::MappingConstraintInfoSeq |
-%% {'EXCEPTION', CosNotifyFilter::InvalidConstraint} |
-%% {'EXCEPTION', CosNotifyFilter::InvalidValue}
-%%-----------------------------------------------------------
-add_mapping_constraints(_OE_THIS, State, Pairs) ->
- {NewState, Filters, Info} = try_create_filters(State, Pairs),
- NewState2=store_filters(NewState, Filters),
- {reply, Info, NewState2}.
-
-%%----------------------------------------------------------%
-%% Function : modify_mapping_constraints/4
-%% Arguments: IDs - CosNotifyFilter::ConstraintIDSeq
-%% Info - CosNotifyFilter::MappingConstraintInfoSeq
-%% Returns : ok |
-%% {'EXCEPTION', CosNotifyFilter::InvalidConstraint} |
-%% {'EXCEPTION', CosNotifyFilter::InvalidValue} |
-%% {'EXCEPTION', CosNotifyFilter::ConstraintNotFound}
-%%-----------------------------------------------------------
-modify_mapping_constraints(_OE_THIS, State, IDs, InfoSeq) ->
- lookup_constraints(IDs, State),
- lookup_constraints(InfoSeq, State),
- {NewState, Filters, _Info} = try_create_filters(State, InfoSeq),
-
- %% We cannot change anything before our checks (see above). Hence,
- %% do NOT move the following lines above this point.
-
- NewState2 = delete_constraints(IDs, NewState),
- NewState3 = delete_constraints(InfoSeq, NewState2),
- NewState4 = store_filters(NewState3, Filters),
- {reply, ok, NewState4}.
-
-%%----------------------------------------------------------%
-%% Function : get_mapping_constraints/3
-%% Arguments: IDs - CosNotifyFilter::ConstraintIDSeq
-%% Returns : CosNotifyFilter::MappingConstraintInfoSeq |
-%% {'EXCEPTION', CosNotifyFilter::ConstraintNotFound}
-%%-----------------------------------------------------------
-get_mapping_constraints(_OE_THIS, State, IDs) ->
- {reply, lookup_constraints(IDs, State), State}.
-
-%%----------------------------------------------------------%
-%% Function : get_all_mapping_constraints/2
-%% Arguments: -
-%% Returns : CosNotifyFilter::MappingConstraintInfoSeq
-%%-----------------------------------------------------------
-get_all_mapping_constraints(_OE_THIS, State) ->
- {reply, ?get_AllConstraints(State), State}.
-
-%%----------------------------------------------------------%
-%% Function : remove_all_mapping_constraints/2
-%% Arguments: -
-%% Returns : ok
-%%-----------------------------------------------------------
-remove_all_mapping_constraints(_OE_THIS, State) ->
- {reply, ok, ?del_AllConstraints(State)}.
-
-%%----------------------------------------------------------%
-%% Function : destroy/2
-%% Arguments: -
-%% Returns : ok
-%%-----------------------------------------------------------
-destroy(_OE_THIS, State) ->
- {stop, normal, ok, State}.
-
-%%----------------------------------------------------------%
-%% Function : match/3
-%% Arguments: Event - #any{}
-%% Returns : boolean(), #any{} (out-type) |
-%% {'EXCEPTION', CosNotifyFilter::UnsupportedFilterableData}
-%%-----------------------------------------------------------
-match(_OE_THIS, State, Event) when is_record(Event,'any') andalso ?is_EmptyFilter(State) ->
- {reply, {false, ?get_DefAny(State)}, State};
-match(_OE_THIS, State, Event) when is_record(Event,'any') ->
- match_any_event(State, Event, ?get_ConstraintAllData(State));
-match(_,_,_) ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-
-%%----------------------------------------------------------%
-%% Function : match_structured/3
-%% Arguments: Event - CosNotification::StructuredEvent
-%% Returns : boolean(), #any{} (out-type) |
-%% {'EXCEPTION', CosNotifyFilter::UnsupportedFilterableData}
-%%-----------------------------------------------------------
-match_structured(_OE_THIS, State, Event) when
- is_record(Event,'CosNotification_StructuredEvent') andalso ?is_EmptyFilter(State) ->
- {reply, {false, ?get_DefAny(State)}, State};
-match_structured(_OE_THIS, State, Event) when
- is_record(Event,'CosNotification_StructuredEvent') ->
- match_str_event(State, Event, ?get_ConstraintAllData(State));
-match_structured(_,_,_) ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------*
-%% Function : match_typed/3
-%% Arguments: Data - CosNotification::PropertySeq
-%% Returns : boolean() , #any{} (out-type) |
-%% {'EXCEPTION', CosNotifyFilter::UnsupportedFilterableData}
-%%-----------------------------------------------------------
--spec match_typed(_, _, _) -> no_return().
-match_typed(_OE_THIS, _State, _Data) ->
- corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO}).
-
-%%--------------- LOCAL FUNCTIONS ----------------------------
-%% To match constraints
-find_obj({value, {Id, Con, _, _, _, Types, Any}}, _) ->
- ?create_MappingInfo(Types, Con, Id, Any);
-find_obj([{_, Tree, tree}|_], tree) -> Tree;
-find_obj(_,tree) -> undefined;
-find_obj(_,constraint) -> error.
-
-%% Delete given object from list and all related objects in DB (parse tree and types).
-match_delete(State, Constraints, ID) ->
- match_delete(State, Constraints, ID, []).
-match_delete(_, [], _, _) ->
- error;
-match_delete(State, [{ID, _Con, _Which, _WC, Key, _Types, _Any}|T], ID, Acc) ->
- ?del_Type(State, ID),
- ?del_ParseTree(State, Key),
- {ok, ?set_Constraints(State, Acc++T)};
-match_delete(State, [H|T], ID, Acc) ->
- match_delete(State, T, ID, [H|Acc]).
-
-%% Remove all data related with constraints; for now, since no other data
-%% stored in DB, we do in a rather brutal way.
-clear_DB(State) ->
- catch ets:delete(State#state.etsR),
- State#state{etsR = ets:new(oe_ets, [bag, protected]), constraints=[]}.
-
-%% Given a list of Constrain IDs we want to find the related constraints.
-%% !!!!!! This function may not alter any data in DB in any way !!!!!!!!!!
-lookup_constraints(IDs, State) ->
- lookup_constraints(IDs, State, []).
-lookup_constraints([], _State, Accum) ->
- Accum;
-lookup_constraints([H|T], State, Accum)
- when is_record(H, 'CosNotifyFilter_MappingConstraintInfo') ->
- case ?get_Constraint(State, H#'CosNotifyFilter_MappingConstraintInfo'.constraint_id) of
- error ->
- corba:raise(#'CosNotifyFilter_ConstraintNotFound'
- {id = H#'CosNotifyFilter_MappingConstraintInfo'.constraint_id});
- _Con ->
- %% We don't need to collect the result since the input already is of
- %% the correct type, i.e., ConstraintInfoSeq
- lookup_constraints(T, State, Accum)
- end;
-lookup_constraints([H|T], State, Accum) when is_integer(H) ->
- case ?get_Constraint(State,H) of
- error ->
- corba:raise(#'CosNotifyFilter_ConstraintNotFound'{id=H});
- Con ->
- lookup_constraints(T, State, [Con|Accum])
- end;
-lookup_constraints(_, _, _) ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%% Given a list of Constrain IDs we want to delet the related constraints.
-%% We need also to return the ConstraintInfoSeq described related to the
-%% given ID's.
-delete_constraints([], State) ->
- State;
-delete_constraints([H|T], State)
- when is_record(H, 'CosNotifyFilter_MappingConstraintInfo') ->
- case catch ?del_Constraint(State,
- H#'CosNotifyFilter_MappingConstraintInfo'.constraint_id) of
- {ok, NewState} ->
- delete_constraints(T, NewState);
- Reason ->
- orber:dbg("[~p] 'CosNotifyFilter_MappingFilter':modify_mapping_constraints().~n"
- "Unable to remove: ~p~n"
- "Reason: ~p~n",
- [?LINE, H, Reason], ?DEBUG_LEVEL),
- delete_constraints(T, State)
- end;
-delete_constraints([H|T], State) ->
- case catch ?del_Constraint(State,H) of
- {ok, NewState} ->
- delete_constraints(T, NewState);
- Reason ->
- orber:dbg("[~p] 'CosNotifyFilter_MappingFilter':modify_mapping_constraints().~n"
- "Unable to remove: ~p~n"
- "Reason: ~p~n",
- [?LINE, H, Reason], ?DEBUG_LEVEL),
- delete_constraints(T, State)
- end.
-
-%%-----------------------------------------------------------
-%% Function : try_create_filters/2
-%% Arguments: CL - #'CosNotifyFilter_MappingConstraintPair{
-%% constraint_expression =
-%% #'CosNotifyFilter_ConstraintExp'{
-%% event_types =
-%% [#'CosNotification_EventType'{
-%% domain_name = Str, type_name = Str}]
-%% constraint_expr = Str},
-%% result_to_set = Any}
-%% Returns : {State, AccumList}
-%%-----------------------------------------------------------
-%% !!!!!! This function may not alter any data in DB in any way !!!!!!!!!!
-try_create_filters(State, CL) ->
- try_create_filters(State, CL, [], []).
-try_create_filters(State, [], Accum, InfoSeq) ->
- {State, Accum, InfoSeq};
-try_create_filters(State, [#'CosNotifyFilter_MappingConstraintPair'
- {constraint_expression =
- #'CosNotifyFilter_ConstraintExp'{event_types = Types,
- constraint_expr = Con},
- result_to_set=Any}|T], Accum, InfoSeq) ->
- case catch {?is_EqualType(State,Any), cosNotification_Filter:create_filter(Con)} of
- {false, _} ->
- corba:raise(#'CosNotifyFilter_InvalidValue'
- {constr = #'CosNotifyFilter_ConstraintExp'
- {event_types = Types, constraint_expr = Con},
- value=Any});
- {_, {ok, Tree}} ->
- case catch cosNotification_Filter:check_types(Types) of
- true ->
- ID = ?new_Id(State),
- Key = ?not_CreateDBKey,
- try_create_filters(?set_IdCounter(State, ID), T,
- [{ID, true, [], Key, Types, Con, Tree, Any}|Accum],
- [?create_MappingInfo(Types, Con, ID, Any)|InfoSeq]);
- {ok, Which, WC} ->
- ID = ?new_Id(State),
- Key = ?not_CreateDBKey,
- try_create_filters(?set_IdCounter(State, ID), T,
- [{ID, Which, WC, Key, Types, Con, Tree, Any}|Accum],
- [?create_MappingInfo(Types, Con, ID, Any)|InfoSeq]);
- _ ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO})
- end;
- _ ->
- corba:raise(#'CosNotifyFilter_InvalidConstraint'
- {constr = #'CosNotifyFilter_ConstraintExp'
- {event_types = Types, constraint_expr = Con}})
- end;
-try_create_filters(State, [#'CosNotifyFilter_MappingConstraintInfo'
- {constraint_expression = #'CosNotifyFilter_ConstraintExp'
- {event_types = Types, constraint_expr = Con},
- constraint_id=ID,
- value=Any}|T], Accum, InfoSeq) ->
- case catch cosNotification_Filter:create_filter(Con) of
- {ok, Tree} ->
- case catch cosNotification_Filter:check_types(Types) of
- true ->
- Key = ?not_CreateDBKey,
- try_create_filters(State, T,
- [{ID, true, [], Key, Types, Con, Tree, Any}|Accum],
- [?create_MappingInfo(Types, Con, ID, Any)|InfoSeq]);
- {ok, Which, WC} ->
- Key = ?not_CreateDBKey,
- try_create_filters(State, T,
- [{ID, Which, WC, Key, Types, Con, Tree, Any}|Accum],
- [?create_MappingInfo(Types, Con, ID, Any)|InfoSeq]);
- _ ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO})
- end;
- _ ->
- corba:raise(#'CosNotifyFilter_InvalidConstraint'
- {constr = #'CosNotifyFilter_ConstraintExp'
- {event_types = Types, constraint_expr = Con}})
- end;
-try_create_filters(_,_,_,_) ->
- %% The list contained something else but ConstraintExp.
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%-----------------------------------------------------------
-%% Function : store_filters/4
-%% Arguments: Filters - a list of filters.
-%% Returns :
-%%-----------------------------------------------------------
-
-store_filters(State, []) ->
- State;
-store_filters(State, [{ID, Which, WC, Key, Types, Con, Tree, Any}|T]) ->
- ?add_ParseTree(State, Key, Tree),
- write_types(State, Types, ID, Key),
- store_filters(?add_Constraint(State, ID, Con, Which, WC, Key, Types, Any), T).
-
-
-write_types(_State, [],_, _) ->
- ok;
-write_types(State, [EventType|T], ID, Key) ->
- ?add_Type(State, ID, EventType, Key),
- ?debug_print("FILTER: ~p ~p ~p~n", [ID, Key, EventType]),
- write_types(State, T, ID, Key).
-
-%%-----------------------------------------------------------
-%% Function : match_any_event
-%% Arguments: Event - #any{}
-%% Returns :
-%%-----------------------------------------------------------
-match_any_event(State, _Event, []) ->
- ?debug_print("FILTER REJECTED: ~p~n", [_Event]),
- {reply, {false, ?get_DefAny(State)}, State};
-match_any_event(State, Event, [{_, _, _, _, Key, Any}|T]) ->
- case catch cosNotification_Filter:eval(?get_ParseTree(State,Key), Event) of
- true ->
- ?debug_print("FILTER APPROVED (WC): ~p~n", [Event]),
- {reply, {true, Any}, State};
- _ ->
- match_any_event(State, Event, T)
- end.
-
-
-%%-----------------------------------------------------------
-%% Function : match_str_event
-%% Arguments:
-%% Returns :
-%%-----------------------------------------------------------
-
-match_str_event(State, _Event, []) ->
- ?debug_print("FILTER REJECTED: ~p~n", [_Event]),
- {reply, {false, ?get_DefAny(State)}, State};
-match_str_event(State, Event, [{ID, _Con, Which, WC, Key, _Types, Any}|T]) ->
- ET = ((Event#'CosNotification_StructuredEvent'.header)
- #'CosNotification_EventHeader'.fixed_header)
- #'CosNotification_FixedEventHeader'.event_type,
- CheckList =
- case Which of
- both ->
- [ET];
- domain ->
- [ET,
- ET#'CosNotification_EventType'{type_name=""},
- ET#'CosNotification_EventType'{type_name="*"}];
- type ->
- [ET,
- ET#'CosNotification_EventType'{domain_name=""},
- ET#'CosNotification_EventType'{domain_name="*"}];
- _ ->
- [ET,
- ET#'CosNotification_EventType'{type_name=""},
- ET#'CosNotification_EventType'{type_name="*"},
- ET#'CosNotification_EventType'{domain_name=""},
- ET#'CosNotification_EventType'{domain_name="*"}]
- end,
- case check_DB(State, ID, CheckList) of
- false ->
- %% No match, may have used wildcards, e.g., "dom*".
- case catch cosNotification_Filter:match_types(
- ET#'CosNotification_EventType'.domain_name,
- ET#'CosNotification_EventType'.type_name,
- WC) of
- true ->
- case catch cosNotification_Filter:eval(?get_ParseTree(State,Key),
- Event) of
- true ->
- ?debug_print("FILTER APPROVED (WC): ~p~n", [Event]),
- {reply, {true, Any}, State};
- _ ->
- match_str_event(State, Event, T)
- end;
- _->
- match_str_event(State, Event, T)
- end;
- Key ->
- case catch cosNotification_Filter:eval(?get_ParseTree(State,Key),
- Event) of
- true ->
- ?debug_print("FILTER APPROVED: ~p~n", [Event]),
- {reply, {true, Any}, State};
- _ ->
- match_str_event(State, Event, T)
- end
- end.
-
-check_DB(_, _, []) ->
- false;
-check_DB(State, ID, [H|T]) ->
- case ?match_Type(State, ID, H) of
- [] ->
- check_DB(State, ID, T);
- [{_, K, types}|_] ->
- K
- end.
-%%--------------- MISC FUNCTIONS, E.G. DEBUGGING -------------
-%%--------------- END OF MODULE ------------------------------
-
diff --git a/lib/cosNotification/src/CosTypedEvent.idl b/lib/cosNotification/src/CosTypedEvent.idl
deleted file mode 100644
index d77c37731a..0000000000
--- a/lib/cosNotification/src/CosTypedEvent.idl
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef _COS_TYPED_EVENT_IDL_
-#define _COS_TYPED_EVENT_IDL_
-
-#pragma prefix "omg.org"
-
-#include<CosEvent.idl>
-
-module CosTypedEventComm {
-
- interface TypedPushConsumer : CosEventComm::PushConsumer {
- Object get_typed_consumer();
- };
-
- interface TypedPullSupplier : CosEventComm::PullSupplier {
- Object get_typed_supplier();
- };
-};
-
-module CosTypedEventChannelAdmin {
-
- exception InterfaceNotSupported {};
- exception NoSuchImplementation {};
- typedef string Key;
-
-
- interface TypedProxyPushConsumer :
- CosEventChannelAdmin::ProxyPushConsumer,
- CosTypedEventComm::TypedPushConsumer { };
-
- interface TypedProxyPullSupplier :
- CosEventChannelAdmin::ProxyPullSupplier,
- CosTypedEventComm::TypedPullSupplier { };
-
- interface TypedSupplierAdmin :
- CosEventChannelAdmin::SupplierAdmin {
- TypedProxyPushConsumer obtain_typed_push_consumer(in Key supported_interface)
- raises(InterfaceNotSupported);
- CosEventChannelAdmin::ProxyPullConsumer obtain_typed_pull_consumer (in Key uses_interface)
- raises(NoSuchImplementation);
- };
-
- interface TypedConsumerAdmin :
- CosEventChannelAdmin::ConsumerAdmin {
- TypedProxyPullSupplier obtain_typed_pull_supplier(in Key supported_interface)
- raises (InterfaceNotSupported);
- CosEventChannelAdmin::ProxyPushSupplier obtain_typed_push_supplier(in Key uses_interface)
- raises(NoSuchImplementation);
- };
-
- interface TypedEventChannel {
- TypedConsumerAdmin for_consumers();
- TypedSupplierAdmin for_suppliers();
- void destroy ();
- };
-};
-
-#endif /* ifndef _COS_TYPED_EVENT_IDL_ */
diff --git a/lib/cosNotification/src/CosTypedNotification.idl b/lib/cosNotification/src/CosTypedNotification.idl
deleted file mode 100644
index 882cde16e0..0000000000
--- a/lib/cosNotification/src/CosTypedNotification.idl
+++ /dev/null
@@ -1,109 +0,0 @@
-#ifndef _COS_TYPED_NOTIFICATION_IDL_
-#define _COS_TYPED_NOTIFICATION_IDL_
-
-#pragma prefix "omg.org"
-
-#include<CosNotifyChannelAdmin.idl>
-#include<CosTypedEvent.idl>
-#include<CosNotification.idl>
-
-module CosTypedNotifyComm {
- interface TypedPushConsumer : CosTypedEventComm::TypedPushConsumer, CosNotifyComm::NotifyPublish { }; // TypedPushConsumer
-
- interface TypedPullSupplier : CosTypedEventComm::TypedPullSupplier, CosNotifyComm::NotifySubscribe { }; // TypedPullSupplier
-}; // CosTypedNotifyComm
-
-
-module CosTypedNotifyChannelAdmin {
- // Forward declaration
- interface TypedEventChannelFactory;
- typedef string Key;
- interface TypedProxyPushConsumer : CosNotifyChannelAdmin::ProxyConsumer, CosTypedNotifyComm::TypedPushConsumer {
- void connect_typed_push_supplier (in CosEventComm::PushSupplier push_supplier)
- raises (CosEventChannelAdmin::AlreadyConnected);
- }; // TypedProxyPushConsumer
-
- interface TypedProxyPullSupplier : CosNotifyChannelAdmin::ProxySupplier, CosTypedNotifyComm::TypedPullSupplier {
- void connect_typed_pull_consumer (in CosEventComm::PullConsumer pull_consumer)
- raises (CosEventChannelAdmin::AlreadyConnected);
- }; // TypedProxyPullSupplier
-
- interface TypedProxyPullConsumer : CosNotifyChannelAdmin::ProxyConsumer, CosNotifyComm::PullConsumer {
- void connect_typed_pull_supplier (in CosTypedEventComm::TypedPullSupplier pull_supplier)
- raises (CosEventChannelAdmin::AlreadyConnected, CosEventChannelAdmin::TypeError);
-
- void suspend_connection()
- raises (CosNotifyChannelAdmin::ConnectionAlreadyInactive, CosNotifyChannelAdmin::NotConnected);
-
- void resume_connection()
- raises (CosNotifyChannelAdmin::ConnectionAlreadyActive, CosNotifyChannelAdmin::NotConnected);
- }; // TypedProxyPullConsumer
-
- interface TypedProxyPushSupplier : CosNotifyChannelAdmin::ProxySupplier, CosNotifyComm::PushSupplier {
- void connect_typed_push_consumer (in CosTypedEventComm::TypedPushConsumer push_consumer)
- raises (CosEventChannelAdmin::AlreadyConnected, CosEventChannelAdmin::TypeError);
-
- void suspend_connection()
- raises (CosNotifyChannelAdmin::ConnectionAlreadyInactive, CosNotifyChannelAdmin::NotConnected);
-
- void resume_connection()
- raises (CosNotifyChannelAdmin::ConnectionAlreadyActive, CosNotifyChannelAdmin::NotConnected);
- }; // TypedProxyPushSupplier
-
- interface TypedConsumerAdmin : CosNotifyChannelAdmin::ConsumerAdmin, CosTypedEventChannelAdmin::TypedConsumerAdmin {
- TypedProxyPullSupplier obtain_typed_notification_pull_supplier(in Key supported_interface,
- out CosNotifyChannelAdmin::ProxyID proxy_id)
- raises( CosTypedEventChannelAdmin::InterfaceNotSupported, CosNotifyChannelAdmin::AdminLimitExceeded );
-
- TypedProxyPushSupplier obtain_typed_notification_push_supplier(in Key uses_interface,
- out CosNotifyChannelAdmin::ProxyID proxy_id)
- raises(CosTypedEventChannelAdmin::NoSuchImplementation, CosNotifyChannelAdmin::AdminLimitExceeded);
- }; // TypedConsumerAdmin
-
- interface TypedSupplierAdmin : CosNotifyChannelAdmin::SupplierAdmin, CosTypedEventChannelAdmin::TypedSupplierAdmin {
- TypedProxyPushConsumer obtain_typed_notification_push_consumer(in Key supported_interface,
- out CosNotifyChannelAdmin::ProxyID proxy_id)
- raises( CosTypedEventChannelAdmin::InterfaceNotSupported, CosNotifyChannelAdmin::AdminLimitExceeded);
- TypedProxyPullConsumer obtain_typed_notification_pull_consumer(in Key uses_interface,
- out CosNotifyChannelAdmin::ProxyID proxy_id )
- raises(CosTypedEventChannelAdmin::NoSuchImplementation, CosNotifyChannelAdmin::AdminLimitExceeded);
- }; // TypedSupplierAdmin
-
- interface TypedEventChannel : CosNotification::QoSAdmin, CosNotification::AdminPropertiesAdmin,
- CosTypedEventChannelAdmin::TypedEventChannel {
- readonly attribute TypedEventChannelFactory MyFactory;
- readonly attribute TypedConsumerAdmin default_consumer_admin;
- readonly attribute TypedSupplierAdmin default_supplier_admin;
- readonly attribute CosNotifyFilter::FilterFactory default_filter_factory;
-
- TypedConsumerAdmin new_for_typed_notification_consumers(in CosNotifyChannelAdmin::InterFilterGroupOperator op,
- out CosNotifyChannelAdmin::AdminID id);
-
- TypedSupplierAdmin new_for_typed_notification_suppliers(in CosNotifyChannelAdmin::InterFilterGroupOperator op,
- out CosNotifyChannelAdmin::AdminID id);
-
- TypedConsumerAdmin get_consumeradmin (in CosNotifyChannelAdmin::AdminID id )
- raises (CosNotifyChannelAdmin::AdminNotFound);
-
- TypedSupplierAdmin get_supplieradmin (in CosNotifyChannelAdmin::AdminID id)
- raises (CosNotifyChannelAdmin::AdminNotFound);
-
- CosNotifyChannelAdmin::AdminIDSeq get_all_consumeradmins();
-
- CosNotifyChannelAdmin::AdminIDSeq get_all_supplieradmins();
- }; // TypedEventChannel
-
- interface TypedEventChannelFactory {
- TypedEventChannel create_typed_channel (in CosNotification::QoSProperties initial_QoS,
- in CosNotification::AdminProperties initial_admin,
- out CosNotifyChannelAdmin::ChannelID id)
- raises( CosNotification::UnsupportedQoS, CosNotification::UnsupportedAdmin);
-
- CosNotifyChannelAdmin::ChannelIDSeq get_all_typed_channels();
-
- TypedEventChannel get_typed_event_channel (in CosNotifyChannelAdmin::ChannelID id)
- raises (CosNotifyChannelAdmin::ChannelNotFound);
- }; // TypedEventChannelFactory
-}; // CosTypedNotifyChannelAdmin
-
-#endif /* ifndef _COS_TYPED_NOTIFICATION_IDL_ */
diff --git a/lib/cosNotification/src/Makefile b/lib/cosNotification/src/Makefile
deleted file mode 100644
index 009c6be4a5..0000000000
--- a/lib/cosNotification/src/Makefile
+++ /dev/null
@@ -1,379 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1999-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-
-ifeq ($(TYPE),debug)
-ERL_COMPILE_FLAGS += -Ddebug -W
-endif
-
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(COSNOTIFICATION_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/cosNotification-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-
-MODULES = \
- CosNotification_Common \
- CosNotifyChannelAdmin_ConsumerAdmin_impl \
- CosNotifyChannelAdmin_EventChannelFactory_impl \
- CosNotifyChannelAdmin_EventChannel_impl \
- CosNotifyChannelAdmin_SupplierAdmin_impl \
- CosNotifyFilter_Filter_impl \
- CosNotifyFilter_MappingFilter_impl \
- CosNotifyFilter_FilterFactory_impl \
- PullerConsumer_impl \
- PullerSupplier_impl \
- PusherConsumer_impl \
- PusherSupplier_impl \
- cosNotificationApp \
- cosNotification_Scanner \
- cosNotification_Filter \
- cosNotification_eventDB
-
-ERL_FILES = $(MODULES:%=%.erl)
-HRL_FILES = \
- CosNotification_Definitions.hrl
-
-YECC_FILES = cosNotification_Grammar.yrl
-
-GEN_YECC_ERL_FILES = cosNotification_Grammar.erl
-
-GEN_YECC_HRL_FILES =
-
-GEN_NOTIFICATION_ERL_FILES = \
- oe_CosNotification.erl \
- CosNotification.erl \
- CosNotification_AdminPropertiesAdmin.erl \
- CosNotification_EventHeader.erl \
- CosNotification_EventType.erl \
- CosNotification_FixedEventHeader.erl \
- CosNotification_NamedPropertyRange.erl \
- CosNotification_Property.erl \
- CosNotification_PropertyError.erl \
- CosNotification_PropertyRange.erl \
- CosNotification_QoSAdmin.erl \
- CosNotification_StructuredEvent.erl \
- CosNotification_UnsupportedAdmin.erl \
- CosNotification_UnsupportedQoS.erl \
- CosNotification_EventBatch.erl \
- CosNotification_EventTypeSeq.erl \
- CosNotification_NamedPropertyRangeSeq.erl \
- CosNotification_PropertyErrorSeq.erl \
- CosNotification_PropertySeq.erl
-
-GEN_CHANNELADMIN_ERL_FILES = \
- oe_CosNotifyChannelAdmin.erl \
- CosNotifyChannelAdmin_AdminLimit.erl \
- CosNotifyChannelAdmin_AdminLimitExceeded.erl \
- CosNotifyChannelAdmin_AdminNotFound.erl \
- CosNotifyChannelAdmin_ChannelNotFound.erl \
- CosNotifyChannelAdmin_ConnectionAlreadyActive.erl \
- CosNotifyChannelAdmin_ConnectionAlreadyInactive.erl \
- CosNotifyChannelAdmin_ConsumerAdmin.erl \
- CosNotifyChannelAdmin_EventChannel.erl \
- CosNotifyChannelAdmin_EventChannelFactory.erl \
- CosNotifyChannelAdmin_NotConnected.erl \
- CosNotifyChannelAdmin_ProxyConsumer.erl \
- CosNotifyChannelAdmin_ProxyNotFound.erl \
- CosNotifyChannelAdmin_ProxyPullConsumer.erl \
- CosNotifyChannelAdmin_ProxyPullSupplier.erl \
- CosNotifyChannelAdmin_ProxyPushConsumer.erl \
- CosNotifyChannelAdmin_ProxyPushSupplier.erl \
- CosNotifyChannelAdmin_ProxySupplier.erl \
- CosNotifyChannelAdmin_SequenceProxyPullConsumer.erl \
- CosNotifyChannelAdmin_SequenceProxyPullSupplier.erl \
- CosNotifyChannelAdmin_SequenceProxyPushConsumer.erl \
- CosNotifyChannelAdmin_SequenceProxyPushSupplier.erl \
- CosNotifyChannelAdmin_StructuredProxyPullConsumer.erl \
- CosNotifyChannelAdmin_StructuredProxyPullSupplier.erl \
- CosNotifyChannelAdmin_StructuredProxyPushConsumer.erl \
- CosNotifyChannelAdmin_StructuredProxyPushSupplier.erl \
- CosNotifyChannelAdmin_SupplierAdmin.erl \
- CosNotifyChannelAdmin_AdminIDSeq.erl \
- CosNotifyChannelAdmin_ChannelIDSeq.erl \
- CosNotifyChannelAdmin_ProxyIDSeq.erl
-
-GEN_NOTIFYFILTER_ERL_FILES = \
- oe_CosNotifyFilter.erl \
- CosNotifyFilter_CallbackNotFound.erl \
- CosNotifyFilter_ConstraintExp.erl \
- CosNotifyFilter_ConstraintInfo.erl \
- CosNotifyFilter_ConstraintNotFound.erl \
- CosNotifyFilter_DuplicateConstraintID.erl \
- CosNotifyFilter_Filter.erl \
- CosNotifyFilter_FilterAdmin.erl \
- CosNotifyFilter_FilterFactory.erl \
- CosNotifyFilter_FilterNotFound.erl \
- CosNotifyFilter_InvalidConstraint.erl \
- CosNotifyFilter_InvalidGrammar.erl \
- CosNotifyFilter_InvalidValue.erl \
- CosNotifyFilter_MappingConstraintInfo.erl \
- CosNotifyFilter_MappingConstraintPair.erl \
- CosNotifyFilter_MappingFilter.erl \
- CosNotifyFilter_UnsupportedFilterableData.erl \
- CosNotifyFilter_CallbackIDSeq.erl \
- CosNotifyFilter_ConstraintExpSeq.erl \
- CosNotifyFilter_ConstraintIDSeq.erl \
- CosNotifyFilter_ConstraintInfoSeq.erl \
- CosNotifyFilter_FilterIDSeq.erl \
- CosNotifyFilter_MappingConstraintInfoSeq.erl \
- CosNotifyFilter_MappingConstraintPairSeq.erl
-
-GEN_NOTIFYCOMM_ERL_FILES = \
- oe_CosNotifyComm.erl \
- CosNotifyComm_InvalidEventType.erl \
- CosNotifyComm_NotifyPublish.erl \
- CosNotifyComm_NotifySubscribe.erl \
- CosNotifyComm_PullConsumer.erl \
- CosNotifyComm_PullSupplier.erl \
- CosNotifyComm_PushConsumer.erl \
- CosNotifyComm_PushSupplier.erl \
- CosNotifyComm_SequencePullConsumer.erl \
- CosNotifyComm_SequencePullSupplier.erl \
- CosNotifyComm_SequencePushConsumer.erl \
- CosNotifyComm_SequencePushSupplier.erl \
- CosNotifyComm_StructuredPullConsumer.erl \
- CosNotifyComm_StructuredPullSupplier.erl \
- CosNotifyComm_StructuredPushConsumer.erl \
- CosNotifyComm_StructuredPushSupplier.erl \
-
-GEN_OE_EVENTCOMM_ERL_FILES = \
- oe_cosNotificationAppComm.erl \
- oe_CosNotificationComm_Event.erl
-
-EXTERNAL_INC_PATH = ../include
-
-GEN_NOTIFICATION_HRL_FILES = \
- oe_CosNotification.hrl \
- CosNotification.hrl \
- CosNotification_AdminPropertiesAdmin.hrl \
- CosNotification_QoSAdmin.hrl \
-
-EXTERNAL_GEN_NOTIFICATION_HRL_FILES = \
- $(GEN_NOTIFICATION_HRL_FILES:%=$(EXTERNAL_INC_PATH)/%)
-
-GEN_CHANNELADMIN_HRL_FILES = \
- oe_CosNotifyChannelAdmin.hrl \
- CosNotifyChannelAdmin.hrl \
- CosNotifyChannelAdmin_ConsumerAdmin.hrl \
- CosNotifyChannelAdmin_EventChannel.hrl \
- CosNotifyChannelAdmin_EventChannelFactory.hrl \
- CosNotifyChannelAdmin_ProxyConsumer.hrl \
- CosNotifyChannelAdmin_ProxyPullConsumer.hrl \
- CosNotifyChannelAdmin_ProxyPullSupplier.hrl \
- CosNotifyChannelAdmin_ProxyPushConsumer.hrl \
- CosNotifyChannelAdmin_ProxyPushSupplier.hrl \
- CosNotifyChannelAdmin_ProxySupplier.hrl \
- CosNotifyChannelAdmin_SequenceProxyPullConsumer.hrl \
- CosNotifyChannelAdmin_SequenceProxyPullSupplier.hrl \
- CosNotifyChannelAdmin_SequenceProxyPushConsumer.hrl \
- CosNotifyChannelAdmin_SequenceProxyPushSupplier.hrl \
- CosNotifyChannelAdmin_StructuredProxyPullConsumer.hrl \
- CosNotifyChannelAdmin_StructuredProxyPullSupplier.hrl \
- CosNotifyChannelAdmin_StructuredProxyPushConsumer.hrl \
- CosNotifyChannelAdmin_StructuredProxyPushSupplier.hrl \
- CosNotifyChannelAdmin_SupplierAdmin.hrl \
-
-EXTERNAL_GEN_CHANNELADMIN_HRL_FILES = \
- $(GEN_CHANNELADMIN_HRL_FILES:%=$(EXTERNAL_INC_PATH)/%)
-
-GEN_NOTIFYFILTER_HRL_FILES = \
- oe_CosNotifyFilter.hrl \
- CosNotifyFilter.hrl \
- CosNotifyFilter_Filter.hrl \
- CosNotifyFilter_FilterAdmin.hrl \
- CosNotifyFilter_FilterFactory.hrl \
- CosNotifyFilter_MappingFilter.hrl
-
-EXTERNAL_GEN_NOTIFYFILTER_HRL_FILES = \
- $(GEN_NOTIFYFILTER_HRL_FILES:%=$(EXTERNAL_INC_PATH)/%)
-
-GEN_NOTIFYCOMM_HRL_FILES = \
- oe_CosNotifyComm.hrl \
- CosNotifyComm.hrl \
- CosNotifyComm_NotifyPublish.hrl \
- CosNotifyComm_NotifySubscribe.hrl \
- CosNotifyComm_PullConsumer.hrl \
- CosNotifyComm_PullSupplier.hrl \
- CosNotifyComm_PushConsumer.hrl \
- CosNotifyComm_PushSupplier.hrl \
- CosNotifyComm_SequencePullConsumer.hrl \
- CosNotifyComm_SequencePullSupplier.hrl \
- CosNotifyComm_SequencePushConsumer.hrl \
- CosNotifyComm_SequencePushSupplier.hrl \
- CosNotifyComm_StructuredPullConsumer.hrl \
- CosNotifyComm_StructuredPullSupplier.hrl \
- CosNotifyComm_StructuredPushConsumer.hrl \
- CosNotifyComm_StructuredPushSupplier.hrl \
-
-EXTERNAL_GEN_NOTIFYCOMM_HRL_FILES = \
- $(GEN_NOTIFYCOMM_HRL_FILES:%=$(EXTERNAL_INC_PATH)/%)
-
-GEN_OE_EVENTCOMM_HRL_FILES = \
- oe_cosNotificationAppComm.hrl \
- oe_CosNotificationComm.hrl \
- oe_CosNotificationComm_Event.hrl
-
-IDL_GEN_ERL_FILES = \
- $(GEN_NOTIFICATION_ERL_FILES) \
- $(GEN_OE_EVENTCOMM_ERL_FILES) \
- $(GEN_NOTIFYCOMM_ERL_FILES) \
- $(GEN_NOTIFYFILTER_ERL_FILES) \
- $(GEN_CHANNELADMIN_ERL_FILES)
-
-IDL_GEN_HRL_FILES = \
- $(EXTERNAL_GEN_NOTIFICATION_HRL_FILES) \
- $(GEN_OE_EVENTCOMM_HRL_FILES) \
- $(EXTERNAL_GEN_NOTIFYCOMM_HRL_FILES) \
- $(EXTERNAL_GEN_NOTIFYFILTER_HRL_FILES) \
- $(EXTERNAL_GEN_CHANNELADMIN_HRL_FILES)
-
-GEN_ERL_FILES = \
- $(IDL_GEN_ERL_FILES) \
- $(GEN_YECC_ERL_FILES)
-
-GEN_HRL_FILES = \
- $(IDL_GEN_HRL_FILES) \
- $(GEN_YECC_HRL_FILES)
-
-
-GEN_FILES = \
- $(GEN_HRL_FILES) \
- $(GEN_ERL_FILES)
-
-TARGET_FILES = \
- $(GEN_ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR)) \
- $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-
-IDL_FILES = \
- CosNotification.idl \
- CosNotifyChannelAdmin.idl \
- CosNotifyFilter.idl \
- CosNotifyComm.idl \
- cosNotificationAppComm.idl
-
-APPUP_FILE = cosNotification.appup
-APPUP_SRC = $(APPUP_FILE).src
-APPUP_TARGET = $(EBIN)/$(APPUP_FILE)
-
-APP_FILE = cosNotification.app
-APP_SRC = $(APP_FILE).src
-APP_TARGET = $(EBIN)/$(APP_FILE)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_IDL_FLAGS += -pa $(ERL_TOP)/lib/cosNotification/ebin \
- -pa $(ERL_TOP)/lib/ic/ebin\
- -pa $(ERL_TOP)/lib/orber/ebin \
- -pa $(ERL_TOP)/lib/cosEvent/ebin \
- -pa $(ERL_TOP)/lib/cosTime/ebin \
- -I$(ERL_TOP)/lib/cosEvent/src
-
-# The -pa option is just used temporary until erlc can handle
-# includes from other directories than ../include .
-ERL_COMPILE_FLAGS += \
- $(ERL_IDL_FLAGS) \
- -pa $(ERL_TOP)/lib/orber/include \
- -pa $(ERL_TOP)/lib/cosNotification/include \
- -pa $(ERL_TOP)/lib/cosEvent/include \
- -pa $(ERL_TOP)/lib/cosTime/include \
- -I$(ERL_TOP)/lib/orber/include \
- -I$(ERL_TOP)/lib/cosNotification/include \
- -I$(ERL_TOP)/lib/cosEvent/include \
- -I$(ERL_TOP)/lib/cosTime/include \
- +'{parse_transform,sys_pre_attributes}' \
- +'{attribute,insert,app_vsn,"cosNotification_$(COSNOTIFICATION_VSN)"}'
-
-YECC_COMPILE_FLAGS =
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
-
-debug:
- @${MAKE} TYPE=debug
-
-cleanb:
- rm -f $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
- rm -f errs core *~
-
-clean:
- rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET) IDL-GENERATED
- rm -f errs core *~
-
-$(APP_TARGET): $(APP_SRC)
- $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
-
-$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
-
-docs:
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-IDL-GENERATED: CosNotification.idl CosNotifyChannelAdmin.idl \
- CosNotifyFilter.idl cosNotificationAppComm.idl CosNotifyComm.idl
- $(gen_verbose)erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosNotification.cfg"}' CosNotification.idl
- $(V_at)mv $(GEN_NOTIFICATION_HRL_FILES) $(EXTERNAL_INC_PATH)
- $(V_at)erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosNotifyChannelAdmin.cfg"}' CosNotifyChannelAdmin.idl
- $(V_at)mv $(GEN_CHANNELADMIN_HRL_FILES) $(EXTERNAL_INC_PATH)
- $(V_at)erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosNotifyFilter.cfg"}' CosNotifyFilter.idl
- $(V_at)mv $(GEN_NOTIFYFILTER_HRL_FILES) $(EXTERNAL_INC_PATH)
- $(V_at)erlc $(ERL_IDL_FLAGS) +'{cfgfile,"cosNotificationComm.cfg"}' cosNotificationAppComm.idl
- $(V_at)erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosNotifyComm.cfg"}' CosNotifyComm.idl
- $(V_at)mv $(GEN_NOTIFYCOMM_HRL_FILES) $(EXTERNAL_INC_PATH)
- $(V_at)>IDL-GENERATED
-
-$(IDL_GEN_ERL_FILES) $(IDL_GEN_HRL_FILES): IDL-GENERATED
-
-$(TARGET_FILES): IDL-GENERATED
-
-$(GEN_YECC_ERL_FILES) $(GEN_YECC_HRL_FILES): cosNotification_Grammar.yrl
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
- $(INSTALL_DIR) "$(RELSYSDIR)/src"
- $(INSTALL_DATA) $(GEN_FILES) $(IDL_FILES) $(YECC_FILES) "$(RELSYSDIR)/src"
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(IDL_FILES) $(YECC_FILES) "$(RELSYSDIR)/src"
- $(INSTALL_DIR) "$(RELSYSDIR)/include"
- $(INSTALL_DATA) $(GEN_HRL_FILES) "$(RELSYSDIR)/include"
-
-release_docs_spec:
diff --git a/lib/cosNotification/src/PullerConsumer_impl.erl b/lib/cosNotification/src/PullerConsumer_impl.erl
deleted file mode 100644
index 52bd13918f..0000000000
--- a/lib/cosNotification/src/PullerConsumer_impl.erl
+++ /dev/null
@@ -1,774 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : PullerConsumer_impl.erl
-%% Purpose :
-%%----------------------------------------------------------------------
-
--module('PullerConsumer_impl').
-
-%%--------------- INCLUDES -----------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
-%% cosEvent files.
--include_lib("cosEvent/include/CosEventChannelAdmin.hrl").
--include_lib("cosEvent/include/CosEventComm.hrl").
-%% Application files
--include("CosNotification.hrl").
--include("CosNotifyChannelAdmin.hrl").
--include("CosNotifyComm.hrl").
--include("CosNotifyFilter.hrl").
--include("CosNotification_Definitions.hrl").
-
-%%--------------- EXPORTS ------------------------------------
-%%--------------- External -----------------------------------
-%%----- CosNotifyChannelAdmin::ProxyPullConsumer -------------
--export([connect_any_pull_supplier/4]).
-
-%%----- CosNotifyChannelAdmin::SequenceProxyPullConsumer -----
--export([connect_sequence_pull_supplier/4]).
-
-%%----- CosNotifyChannelAdmin::StructuredProxyPullConsumer ---
--export([connect_structured_pull_supplier/4]).
-
-%%----- CosNotifyChannelAdmin::*ProxyPullConsumer ------------
--export([suspend_connection/3,
- resume_connection/3]).
-
-%%----- Inherit from CosNotifyChannelAdmin::ProxyConsumer ----
--export([obtain_subscription_types/4,
- validate_event_qos/4]).
-
-%%----- Inherit from CosNotification::QoSAdmin ---------------
--export([get_qos/3,
- set_qos/4,
- validate_qos/4]).
-
-%%----- Inherit from CosNotifyComm::NotifyPublish ------------
--export([offer_change/5]).
-
-%%----- Inherit from CosNotifyFilter::FilterAdmin ------------
--export([add_filter/4,
- remove_filter/4,
- get_filter/4,
- get_all_filters/3,
- remove_all_filters/3]).
-
-%%----- Inherit from CosEventComm::PullConsumer -------------
--export([disconnect_pull_consumer/3]).
-
-%%----- Inherit from CosNotifyComm::SequencePullConsumer ----
--export([disconnect_sequence_pull_consumer/3]).
-
-%%----- Inherit from CosNotifyComm::StructuredPullConsumer --
--export([disconnect_structured_pull_consumer/3]).
-
-%%----- Inherit from CosEventChannelAdmin::ProxyPullConsumer
--export([connect_pull_supplier/4]).
-
-
-%% Attributes (external) CosNotifyChannelAdmin::ProxySupplier
--export(['_get_MyType'/3,
- '_get_MyAdmin'/3]).
-
-%%--------------- gen_server specific exports ----------------
--export([handle_info/2, code_change/3]).
--export([init/1, terminate/2]).
-
-%%--------------- LOCAL DEFINITIONS --------------------------
-%% Data structures
--record(state, {myType,
- myAdmin,
- myAdminPid,
- myChannel,
- myFilters = [],
- myOperator,
- idCounter = 0,
- client,
- qosGlobal,
- qosLocal,
- suspended = false,
- pullTimer,
- pullInterval,
- publishType = false,
- etsR,
- eventCounter = 0,
- eventDB,
- this}).
-
-%% Data structures constructors
--define(get_InitState(_MyT, _MyA, _MyAP, _QS, _LQS, _Ch, _PI, _MyOP, _GT, _GL, _TR),
- #state{myType = _MyT,
- myAdmin = _MyA,
- myAdminPid = _MyAP,
- myChannel = _Ch,
- myOperator = _MyOP,
- qosGlobal = _QS,
- qosLocal = _LQS,
- pullInterval = _PI,
- etsR = ets:new(oe_ets, [set, protected]),
- eventDB = cosNotification_eventDB:create_db(_LQS, _GT, _GL, _TR)}).
-
-%%-------------- Data structures selectors -----------------
-%% Attributes
--define(get_MyType(S), S#state.myType).
--define(get_MyAdmin(S), S#state.myAdmin).
--define(get_MyAdminPid(S), S#state.myAdminPid).
--define(get_MyChannel(S), S#state.myChannel).
--define(get_MyOperator(S), S#state.myOperator).
-%% Client Object
--define(get_Client(S), S#state.client).
-%% QoS
--define(get_GlobalQoS(S), S#state.qosGlobal).
--define(get_LocalQoS(S), S#state.qosLocal).
--define(get_BothQoS(S), {S#state.qosGlobal, S#state.qosLocal}).
-%% Filters
--define(get_Filter(S, I), find_obj(lists:keysearch(I, 1, S#state.myFilters))).
--define(get_AllFilter(S), S#state.myFilters).
--define(get_AllFilterID(S), find_ids(S#state.myFilters)).
-%% Admin
--define(get_PullInterval(S), S#state.pullInterval).
--define(get_PullTimer(S), S#state.pullTimer).
--define(get_PacingInterval(S), round(?not_GetPacingInterval((S#state.qosLocal))/10000000)).
--define(get_BatchLimit(S), ?not_GetMaximumBatchSize((S#state.qosLocal))).
-%% Publish
--define(get_AllPublish(S), lists:flatten(ets:match(S#state.etsR,
- {'$1',publish}))).
--define(get_PublishType(S), S#state.publishType).
-%% ID
--define(get_IdCounter(S), S#state.idCounter).
-%% Event
--define(get_Event(S), cosNotification_eventDB:get_event(S#state.eventDB)).
--define(get_Events(S,M), cosNotification_eventDB:get_events(S#state.eventDB, M)).
--define(get_EventCounter(S), S#state.eventCounter).
-
-%%-------------- Data structures modifiers -----------------
-%% Client Object
--define(set_Client(S,D), S#state{client=D}).
--define(del_Client(S), S#state{client=undefined}).
--define(set_Suspended(S), S#state{client=true}).
--define(set_NotSuspended(S), S#state{client=false}).
--define(set_Unconnected(S), S#state{client=undefined}).
-%% QoS
--define(set_LocalQoS(S,D), S#state{qosLocal=D}).
--define(set_GlobalQoS(S,D), S#state{qosGlobal=D}).
--define(set_BothQoS(S,GD,LD), S#state{qosGlobal=GD, qosLocal=LD}).
-%% Filters
--define(add_Filter(S,I,O), S#state{myFilters=[{I,O}|S#state.myFilters]}).
--define(del_Filter(S,I), S#state{myFilters=
- delete_obj(lists:keydelete(I, 1, S#state.myFilters),
- S#state.myFilters)}).
--define(del_AllFilter(S), S#state{myFilters=[]}).
-%% Admin
--define(set_PullInterval(S,V), S#state{pullInterval=V}).
--define(set_PullTimer(S,T), S#state{pullTimer=T}).
-%% Publish
--define(add_Publish(S,E), ets:insert(S#state.etsR, {E, publish})).
--define(del_Publish(S,E), ets:delete(S#state.etsR, E)).
--define(set_PublishType(S,T), S#state{publishType=T}).
-%% ID
--define(set_IdCounter(S,V), S#state{idCounter=V}).
--define(new_Id(S), 'CosNotification_Common':create_id(S#state.idCounter)).
-%% Event
--define(add_Event(S,E), cosNotification_eventDB:add_event(S#state.eventDB, E)).
--define(update_EventDB(S,Q), S#state{eventDB=
- cosNotification_eventDB:update(S#state.eventDB, Q)}).
-
--define(set_EventCounter(S,V), S#state{eventCounter=V}).
--define(add_to_EventCounter(S,V),S#state{eventCounter=S#state.eventCounter+V}).
--define(reset_EventCounter(S), S#state{eventCounter=0}).
--define(increase_EventCounter(S),S#state{eventCounter=(S#state.eventCounter+1)}).
--define(decrease_EventCounter(S),S#state{eventCounter=S#state.eventCounter-1}).
--define(add_ToEventCounter(S,A), S#state{eventCounter=(S#state.eventCounter+A)}).
--define(sub_FromEventCounter(S,_A), S#state{eventCounter=(S#state.eventCounter-_A)}).
--define(set_EventCounterTo(S,V), S#state{eventCounter=V}).
-
-%%-------------- MISC ----------------------------------------
--define(is_ANY(S), S#state.myType == 'PULL_ANY').
--define(is_STRUCTURED(S), S#state.myType == 'PULL_STRUCTURED').
--define(is_SEQUENCE(S), S#state.myType == 'PULL_SEQUENCE').
--define(is_ANDOP(S), S#state.myOperator == 'AND_OP').
--define(is_UnConnected(S), S#state.client == undefined).
--define(is_Connected(S), S#state.client =/= undefined).
--define(is_Suspended(S), S#state.suspended == true).
--define(is_NotSuspended(S), S#state.suspended == false).
--define(is_PersistentConnection(S),
- ?not_GetConnectionReliability((S#state.qosLocal)) == ?not_Persistent).
--define(is_PersistentEvent(S),
- ?not_GetEventReliability((S#state.qosLocal)) == ?not_Persistent).
-
-%%-----------------------------------------------------------%
-%% function : handle_info, code_change
-%% Arguments:
-%% Returns :
-%% Effect : Functions demanded by the gen_server module.
-%%------------------------------------------------------------
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-handle_info(Info, State) ->
- ?DBG("INFO: ~p~n", [Info]),
- case Info of
- {'EXIT', Pid, Reason} when ?get_MyAdminPid(State) == Pid->
- ?DBG("PARENT ADMIN: ~p TERMINATED.~n",[Reason]),
- {stop, Reason, State};
- {'EXIT', _Pid, _Reason} ->
- ?DBG("PROXYPUSHSUPPLIER: ~p TERMINATED.~n",[_Reason]),
- {noreply, State};
- pull ->
- try_pull_events(State);
- _ ->
- {noreply, State}
- end.
-
-%%----------------------------------------------------------%
-%% function : init, terminate
-%% Arguments:
-%%-----------------------------------------------------------
-
-init([MyType, MyAdmin, MyAdminPid, InitQoS, LQS, MyChannel, Options, Operator]) ->
- process_flag(trap_exit, true),
- Secs = timer:seconds('CosNotification_Common':get_option(pullInterval,
- Options,
- ?not_DEFAULT_SETTINGS)),
- GCTime = 'CosNotification_Common':get_option(gcTime, Options,
- ?not_DEFAULT_SETTINGS),
- GCLimit = 'CosNotification_Common':get_option(gcLimit, Options,
- ?not_DEFAULT_SETTINGS),
- TimeRef = 'CosNotification_Common':get_option(timeService, Options,
- ?not_DEFAULT_SETTINGS),
- timer:start(),
- {ok, ?get_InitState(MyType, MyAdmin, MyAdminPid, InitQoS,
- LQS, MyChannel, Secs, Operator, GCTime,
- GCLimit, TimeRef)}.
-
-terminate(_Reason, State) when ?is_UnConnected(State) ->
- %% We are currently not connected to a client. Hence, no need for sending
- %% a disconnect request.
- stop_timer(State),
- ok;
-terminate(_Reason, State) when ?is_ANY(State) ->
- stop_timer(State),
- 'CosNotification_Common':disconnect('CosEventComm_PullSupplier',
- disconnect_pull_supplier,
- ?get_Client(State));
-terminate(_Reason, State) when ?is_SEQUENCE(State) ->
- stop_timer(State),
- 'CosNotification_Common':disconnect('CosNotifyComm_SequencePullSupplier',
- disconnect_sequence_pull_supplier,
- ?get_Client(State));
-terminate(_Reason, State) when ?is_STRUCTURED(State) ->
- stop_timer(State),
- 'CosNotification_Common':disconnect('CosNotifyComm_StructuredPullSupplier',
- disconnect_structured_pull_supplier,
- ?get_Client(State)).
-
-%%-----------------------------------------------------------
-%%----- CosNotifyChannelAdmin_ProxyConsumer attributes ------
-%%-----------------------------------------------------------
-%%----------------------------------------------------------%
-%% Attribute: '_get_MyType'
-%% Type : readonly
-%% Returns :
-%%-----------------------------------------------------------
-'_get_MyType'(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_MyType(State), State}.
-
-%%----------------------------------------------------------%
-%% Attribute: '_get_MyAdmin'
-%% Type : readonly
-%% Returns :
-%%-----------------------------------------------------------
-'_get_MyAdmin'(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_MyAdmin(State), State}.
-
-%%-----------------------------------------------------------
-%%------- Exported external functions -----------------------
-%%-----------------------------------------------------------
-%%----- CosEventChannelAdmin::ProxyPullConsumer -------------
-%%----------------------------------------------------------%
-%% function : connect_pull_supplier
-%% Arguments: Client - CosEventComm::PullSupplier
-%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} |
-%% {'EXCEPTION', #'TypeError'{}} |
-%% {'EXCEPTION', #'BAD_OPERATION'{}}
-%% Both exceptions from CosEventChannelAdmin!!!
-%%-----------------------------------------------------------
-connect_pull_supplier(OE_THIS, OE_FROM, State, Client) ->
- connect_any_pull_supplier(OE_THIS, OE_FROM, State, Client).
-
-%%----- CosNotifyChannelAdmin::ProxyPullConsumer ------------
-%%----------------------------------------------------------%
-%% function : connect_any_pull_supplier
-%% Arguments: Client - CosEventComm::PullSupplier
-%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} |
-%% {'EXCEPTION', #'TypeError'{}} |
-%% {'EXCEPTION', #'BAD_OPERATION'{}}
-%% Both exceptions from CosEventChannelAdmin!!!
-%%-----------------------------------------------------------
-connect_any_pull_supplier(OE_THIS, _OE_FROM, State, Client) when ?is_ANY(State) ->
- 'CosNotification_Common':type_check(Client, 'CosEventComm_PullSupplier'),
- if
- ?is_Connected(State) ->
- corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{});
- true ->
- NewState = start_timer(State),
- {reply, ok, NewState#state{client = Client, this = OE_THIS}}
- end;
-connect_any_pull_supplier(_, _, _,_) ->
- corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}).
-
-%%----- CosNotifyChannelAdmin::SequenceProxyPullConsumer ----
-%%----------------------------------------------------------%
-%% function : connect_sequence_pull_supplier
-%% Arguments: Client - CosNotifyComm::SequencePullSupplier
-%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} |
-%% {'EXCEPTION', #'TypeError'{}} |
-%% {'EXCEPTION', #'BAD_OPERATION'{}}
-%%-----------------------------------------------------------
-connect_sequence_pull_supplier(OE_THIS, _OE_FROM, State, Client) when ?is_SEQUENCE(State) ->
- 'CosNotification_Common':type_check(Client, 'CosNotifyComm_SequencePullSupplier'),
- if
- ?is_Connected(State) ->
- corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{});
- true ->
- NewState = start_timer(State),
- {reply, ok, NewState#state{client = Client, this = OE_THIS}}
- end;
-connect_sequence_pull_supplier(_, _, _, _) ->
- corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}).
-
-%%----- CosNotifyChannelAdmin::StructuredProxyPullConsumer --
-%%----------------------------------------------------------%
-%% function : connect_structured_pull_supplier
-%% Arguments: Client - CosNotifyComm::StructuredPullSupplier
-%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} |
-%% {'EXCEPTION', #'TypeError'{}} |
-%% {'EXCEPTION', #'BAD_OPERATION'{}}
-%%-----------------------------------------------------------
-connect_structured_pull_supplier(OE_THIS, _OE_FROM, State, Client) when ?is_STRUCTURED(State) ->
- 'CosNotification_Common':type_check(Client, 'CosNotifyComm_StructuredPullSupplier'),
- if
- ?is_Connected(State) ->
- corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{});
- true ->
- NewState = start_timer(State),
- {reply, ok, NewState#state{client = Client, this = OE_THIS}}
- end;
-connect_structured_pull_supplier(_, _, _, _) ->
- corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}).
-
-%%----- CosNotifyChannelAdmin::*ProxyPullConsumer -----------
-%%----------------------------------------------------------%
-%% function : suspend_connection
-%% Arguments:
-%% Returns : ok | {'EXCEPTION', #'ConnectionAlreadyInactive'{}} |
-%% {'EXCEPTION', #'NotConneced'{}}
-%%-----------------------------------------------------------
-suspend_connection(_OE_THIS, _OE_FROM, State) when ?is_Connected(State) ->
- if
- ?is_Suspended(State) ->
- corba:raise(#'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{});
- true ->
- stop_timer(State),
- {reply, ok, ?set_Suspended(State)}
- end;
-suspend_connection(_, _, _) ->
- corba:raise(#'CosNotifyChannelAdmin_NotConnected'{}).
-
-%%----------------------------------------------------------%
-%% function : resume_connection
-%% Arguments:
-%% Returns : ok | {'EXCEPTION', #'ConnectionAlreadyActive'{}} |
-%% {'EXCEPTION', #'NotConneced'{}}
-%%-----------------------------------------------------------
-resume_connection(_OE_THIS, _OE_FROM, State) when ?is_Connected(State) ->
- if
- ?is_NotSuspended(State) ->
- corba:raise(#'CosNotifyChannelAdmin_ConnectionAlreadyActive'{});
- true ->
- NewState = start_timer(State),
- {reply, ok, ?set_NotSuspended(NewState)}
- end;
-resume_connection(_, _, _) ->
- corba:raise(#'CosNotifyChannelAdmin_NotConnected'{}).
-
-%%----- Inherit from CosNotifyChannelAdmin::ProxyConsumer ---
-%%----------------------------------------------------------%
-%% function : obtain_subscription_types
-%% Arguments: Mode - enum 'ObtainInfoMode' (CosNotifyChannelAdmin)
-%% Returns : CosNotification::EventTypeSeq
-%%-----------------------------------------------------------
-obtain_subscription_types(_OE_THIS, _OE_FROM, State, 'ALL_NOW_UPDATES_OFF') ->
- {reply, ?get_AllPublish(State), ?set_PublishType(State, false)};
-obtain_subscription_types(_OE_THIS, _OE_FROM, State, 'ALL_NOW_UPDATES_ON') ->
- {reply, ?get_AllPublish(State), ?set_PublishType(State, true)};
-obtain_subscription_types(_OE_THIS, _OE_FROM, State, 'NONE_NOW_UPDATES_OFF') ->
- {reply, [], ?set_PublishType(State, false)};
-obtain_subscription_types(_OE_THIS, _OE_FROM, State, 'NONE_NOW_UPDATES_ON') ->
- {reply, [], ?set_PublishType(State, true)};
-obtain_subscription_types(_,_,_,What) ->
- orber:dbg("[~p] PullerConsumer:obtain_subscription_types(~p);~n"
- "Incorrect enumerant", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------%
-%% function : validate_event_qos
-%% Arguments: RequiredQoS - CosNotification::QoSProperties
-%% Returns : ok | {'EXCEPTION', #'UnsupportedQoS'{}}
-%% AvilableQoS - CosNotification::NamedPropertyRangeSeq (out)
-%%-----------------------------------------------------------
-validate_event_qos(_OE_THIS, _OE_FROM, State, RequiredQoS) ->
- AvilableQoS = 'CosNotification_Common':validate_event_qos(RequiredQoS,
- ?get_LocalQoS(State)),
- {reply, {ok, AvilableQoS}, State}.
-
-%%----- Inherit from CosNotification::QoSAdmin --------------
-%%----------------------------------------------------------%
-%% function : get_qos
-%% Arguments:
-%% Returns :
-%%-----------------------------------------------------------
-get_qos(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_GlobalQoS(State), State}.
-
-%%----------------------------------------------------------%
-%% function : set_qos
-%% Arguments: QoS - CosNotification::QoSProperties, i.e.,
-%% [#'Property'{name, value}, ...] where name eq. string()
-%% and value eq. any().
-%% Returns : ok | {'EXCEPTION', CosNotification::UnsupportedQoS}
-%%-----------------------------------------------------------
-set_qos(_OE_THIS, _OE_FROM, State, QoS) ->
- {NewQoS, LQS} = 'CosNotification_Common':set_qos(QoS, ?get_BothQoS(State),
- proxy, ?get_MyAdmin(State),
- false),
- NewState = ?update_EventDB(State, LQS),
- {reply, ok, ?set_BothQoS(NewState, NewQoS, LQS)}.
-
-%%----------------------------------------------------------%
-%% function : validate_qos
-%% Arguments: Required_qos - CosNotification::QoSProperties
-%% [#'Property'{name, value}, ...] where name eq. string()
-%% and value eq. any().
-%% Returns : {'EXCEPTION', CosNotification::UnsupportedQoS}
-%% {ok, CosNotification::NamedPropertyRangeSeq}
-%%-----------------------------------------------------------
-validate_qos(_OE_THIS, _OE_FROM, State, Required_qos) ->
- QoS = 'CosNotification_Common':validate_qos(Required_qos, ?get_BothQoS(State),
- proxy, ?get_MyAdmin(State),
- false),
- {reply, {ok, QoS}, State}.
-
-%%----- Inherit from CosNotifyComm::NotifyPublish -----------
-%%----------------------------------------------------------%
-%% function : offer_change
-%% Arguments: Added - #'CosNotification_EventType'{}
-%% Removed - #'CosNotification_EventType'{}
-%% Returns : ok |
-%% {'EXCEPTION', #'CosNotifyComm_InvalidEventType'{}}
-%%-----------------------------------------------------------
-offer_change(_OE_THIS, _OE_FROM, State, Added, Removed) ->
- cosNotification_Filter:validate_types(Added),
- cosNotification_Filter:validate_types(Removed),
- %% On this "side" we don't really care about which
- %% type of events the client will supply.
- %% Perhaps, later on, if we want to check this against Filters
- %% associated with this object we may change this approach, i.e., if
- %% the filter will not allow passing certain event types. But the
- %% user should see to that that situation never occurs. It would add
- %% extra overhead. Also see PusherSupplier- and PullerSuppler-
- %% 'subscription_change'.
- update_publish(add, State, Added),
- update_publish(remove, State, Removed),
- case ?get_PublishType(State) of
- true ->
- %% Perhaps we should handle exception here?!
- %% Probably not. Better to stay "on-line".
- catch 'CosNotifyComm_NotifySubscribe':
- subscription_change(?get_Client(State), Added, Removed),
- ok;
- _->
- ok
- end,
- {reply, ok, State}.
-
-update_publish(_, _, [])->
- ok;
-update_publish(add, State, [H|T]) ->
- ?add_Publish(State, H),
- update_publish(add, State, T);
-update_publish(remove, State, [H|T]) ->
- ?del_Publish(State, H),
- update_publish(remove, State, T).
-
-%%----- Inherit from CosNotifyFilter::FilterAdmin -----------
-%%----------------------------------------------------------%
-%% function : add_filter
-%% Arguments: Filter - CosNotifyFilter::Filter
-%% Returns : FilterID - long
-%%-----------------------------------------------------------
-add_filter(_OE_THIS, _OE_FROM, State, Filter) ->
- 'CosNotification_Common':type_check(Filter, 'CosNotifyFilter_Filter'),
- FilterID = ?new_Id(State),
- NewState = ?set_IdCounter(State, FilterID),
- {reply, FilterID, ?add_Filter(NewState, FilterID, Filter)}.
-
-%%----------------------------------------------------------%
-%% function : remove_filter
-%% Arguments: FilterID - long
-%% Returns : ok
-%%-----------------------------------------------------------
-remove_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) ->
- {reply, ok, ?del_Filter(State, FilterID)};
-remove_filter(_,_,_,What) ->
- orber:dbg("[~p] PullerConsumer:remove_filter(~p); Not an integer",
- [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------%
-%% function : get_filter
-%% Arguments: FilterID - long
-%% Returns : Filter - CosNotifyFilter::Filter |
-%% {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}}
-%%-----------------------------------------------------------
-get_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) ->
- {reply, ?get_Filter(State, FilterID), State};
-get_filter(_,_,_,What) ->
- orber:dbg("[~p] PullerConsumer:get_filter(~p); Not an integer",
- [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------%
-%% function : get_all_filters
-%% Arguments: -
-%% Returns : Filter - CosNotifyFilter::FilterIDSeq
-%%-----------------------------------------------------------
-get_all_filters(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_AllFilterID(State), State}.
-
-%%----------------------------------------------------------%
-%% function : remove_all_filters
-%% Arguments: -
-%% Returns : ok
-%%-----------------------------------------------------------
-remove_all_filters(_OE_THIS, _OE_FROM, State) ->
- {reply, ok, ?del_AllFilter(State)}.
-
-%%----- Inherit from CosEventComm::PullConsumer -------------
-%%----------------------------------------------------------%
-%% function : disconnect_pull_consumer
-%% Arguments: -
-%% Returns : ok
-%%-----------------------------------------------------------
-disconnect_pull_consumer(_OE_THIS, _OE_FROM, State) ->
- {stop, normal, ok, ?set_Unconnected(State)}.
-
-%%----- Inherit from CosNotifyComm::SequencePullConsumer ----
-%%----------------------------------------------------------%
-%% function : disconnect_sequence_pull_consumer
-%% Arguments: -
-%% Returns : ok
-%%-----------------------------------------------------------
-disconnect_sequence_pull_consumer(_OE_THIS, _OE_FROM, State) ->
- {stop, normal, ok, ?set_Unconnected(State)}.
-
-%%----- Inherit from CosNotifyComm::StructuredPullConsumer ----
-%%----------------------------------------------------------%
-%% function : disconnect_structured_pull_consumer
-%% Arguments: -
-%% Returns : ok
-%%-----------------------------------------------------------
-disconnect_structured_pull_consumer(_OE_THIS, _OE_FROM, State) ->
- {stop, normal, ok, ?set_Unconnected(State)}.
-
-%%--------------- LOCAL FUNCTIONS ----------------------------
-find_obj({value, {_, Obj}}) -> Obj;
-find_obj(_) -> {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}}.
-
-find_ids(List) -> find_ids(List, []).
-find_ids([], Acc) -> Acc;
-find_ids([{I,_}|T], Acc) -> find_ids(T, [I|Acc]);
-find_ids(What, _) ->
- orber:dbg("[~p] PullerConsumer:find_ids();~n"
- "Id corrupt: ~p", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}).
-
-%% Delete a single object.
-%% The list don not differ, i.e., no filter removed, raise exception.
-delete_obj(List,List) -> corba:raise(#'CosNotifyFilter_FilterNotFound'{});
-delete_obj(List,_) -> List.
-
-%% Start timer which send a message each time we should pull for new events.
-start_timer(State) ->
- case catch timer:send_interval(?get_PullInterval(State), pull) of
- {ok,PullTRef} ->
- ?DBG("PULL CONSUMER STARTED PULL TIMER ~p~n",
- [?get_PullInterval(State)]),
- ?set_PullTimer(State, PullTRef);
- What ->
- orber:dbg("[~p] PullerConsumer:start_timer();~n"
- "Unable to invoke timer:send_interval/2: ~p",
- [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-stop_timer(State) ->
- ?DBG("PULL CONSUMER STOPPED TIMER~n",[]),
- timer:cancel(?get_PullTimer(State)).
-
-%% Try pull event(s); which method is determined by which type this proxy is.
-try_pull_events(State) when ?is_ANY(State) ->
- case catch 'CosEventComm_PullSupplier':try_pull(?get_Client(State)) of
- {_,false} ->
- {noreply, State};
- {Event, true} ->
- case ?not_isConvertedStructured(Event) of
- true ->
- forward(seq, State,
- cosNotification_eventDB:filter_events([any:get_value(Event)],
- ?get_AllFilter(State)));
- _ ->
- forward(any, State,
- cosNotification_eventDB:filter_events([Event],
- ?get_AllFilter(State)))
- end;
- _->
- {noreply, State}
- end;
-try_pull_events(State) when ?is_SEQUENCE(State) ->
- case catch 'CosNotifyComm_SequencePullSupplier':
- try_pull_structured_events(?get_Client(State), ?get_BatchLimit(State)) of
- {_,false} ->
- {noreply, State};
- {EventSeq, true} ->
- %% We cannot convert parts of the sequence to any, event though they
- %% are converted from any to structured. Would be 'impossible' to send.
- forward(seq, State,
- cosNotification_eventDB:filter_events(EventSeq,
- ?get_AllFilter(State)));
- _->
- {noreply, State}
- end;
-try_pull_events(State) when ?is_STRUCTURED(State) ->
- case catch 'CosNotifyComm_StructuredPullSupplier':
- try_pull_structured_event(?get_Client(State)) of
- {_,false} ->
- {noreply, State};
- {Event, true} when ?not_isConvertedAny(Event) ->
- forward(any, State,
- cosNotification_eventDB:filter_events([Event#'CosNotification_StructuredEvent'.remainder_of_body],
- ?get_AllFilter(State)));
- {Event, true} ->
- forward(seq, State,
- cosNotification_eventDB:filter_events([Event],
- ?get_AllFilter(State)));
- _->
- {noreply, State}
- end.
-
-
-
-%% Forward events
-forward(_, State, {[], _}) when ?is_ANDOP(State) ->
- %% Did not pass filtering. Since AND no need to pass on.
- {noreply, State};
-forward(Type, State, {[], Failed}) ->
- %% Did not pass filtering, but since OR it may pass Admin filters, hence, pass
- %% on to Admin
- forward(Type, State, Failed, ?get_MyAdmin(State), 'MATCH');
-forward(Type, State, {Passed, _}) when ?is_ANDOP(State) ->
- %% Did pass filtering, but since AND we must pass it to Admin to check against
- %% its Filters. Just ignore the ones that failed.
- forward(Type, State, Passed, ?get_MyAdmin(State), 'MATCH');
-forward(Type, State, {Passed, []}) ->
- %% Did pass filtering, and since OR we can pass it to the Channel directly.
- forward(Type, State, Passed, ?get_MyChannel(State), 'MATCHED');
-forward(Type, State, {Passed, Failed}) ->
- %% Some passed filtering, and since OR we can pass the ones that passed directly
- %% to the channel and the other ones via the admin.
- forward(Type, State, Passed, ?get_MyChannel(State), 'MATCHED'),
- forward(Type, State, Failed, ?get_MyAdmin(State), 'MATCH').
-
-forward(any, State, [Event], SendTo, Status) ->
- case catch oe_CosNotificationComm_Event:callAny(SendTo, Event, Status) of
- ok ->
- ?DBG("PROXY FORWARD ANY: ~p~n",[Event]),
- {noreply, State};
- {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') orelse
- is_record(E, 'NO_PERMISSION') orelse
- is_record(E, 'CosEventComm_Disconnected') ->
- orber:dbg("[~p] PullerConsumer:forward();~n"
- "Admin/Channel no longer exists; terminating and dropping: ~p",
- [?LINE, Event], ?DEBUG_LEVEL),
- 'CosNotification_Common':notify([{proxy, State#state.this},
- {client, ?get_Client(State)},
- {reason, {'EXCEPTION', E}}]),
- {stop, normal, State};
- R when ?is_PersistentConnection(State) ->
- orber:dbg("[~p] PullerConsumer:forward();~n"
- "Admin/Channel respond incorrect: ~p~n"
- "Dropping: ~p", [?LINE, R, Event], ?DEBUG_LEVEL),
- {noreply, State};
- R ->
- orber:dbg("[~p] PullerConsumer:forward();~n"
- "Admin/Channel respond incorrect: ~p~n"
- "Terminating and dropping: ~p",
- [?LINE, R, Event], ?DEBUG_LEVEL),
- 'CosNotification_Common':notify([{proxy, State#state.this},
- {client, ?get_Client(State)},
- {reason, R}]),
- {stop, normal, State}
- end;
-forward(seq, State, Event, SendTo, Status) ->
- case catch oe_CosNotificationComm_Event:callSeq(SendTo, Event, Status) of
- ok ->
- ?DBG("PROXY FORWARD SEQUENCE: ~p~n",[Event]),
- {noreply, State};
- {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') orelse
- is_record(E, 'NO_PERMISSION') orelse
- is_record(E, 'CosEventComm_Disconnected') ->
- orber:dbg("[~p] PullerConsumer:forward();~n"
- "Admin/Channel no longer exists; terminating and dropping: ~p",
- [?LINE, Event], ?DEBUG_LEVEL),
- 'CosNotification_Common':notify([{proxy, State#state.this},
- {client, ?get_Client(State)},
- {reason, {'EXCEPTION', E}}]),
- {stop, normal, State};
- R when ?is_PersistentConnection(State) ->
- orber:dbg("[~p] PullerConsumer:forward();~n"
- "Admin/Channel respond incorrect: ~p~n"
- "Dropping: ~p", [?LINE, R, Event], ?DEBUG_LEVEL),
- {noreply, State};
- R ->
- orber:dbg("[~p] PullerConsumer:forward();~n"
- "Admin/Channel respond incorrect: ~p~n"
- "Terminating and dropping: ~p",
- [?LINE, R, Event], ?DEBUG_LEVEL),
- 'CosNotification_Common':notify([{proxy, State#state.this},
- {client, ?get_Client(State)},
- {reason, R}]),
- {stop, normal, State}
- end.
-
-%%--------------- MISC FUNCTIONS, E.G. DEBUGGING -------------
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/cosNotification/src/PullerSupplier_impl.erl b/lib/cosNotification/src/PullerSupplier_impl.erl
deleted file mode 100644
index e1956cff28..0000000000
--- a/lib/cosNotification/src/PullerSupplier_impl.erl
+++ /dev/null
@@ -1,915 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2015. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : PullerSupplier_impl.erl
-%% Purpose :
-%%----------------------------------------------------------------------
-
--module('PullerSupplier_impl').
-
-%%--------------- INCLUDES -----------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
-%% cosEvent files.
--include_lib("cosEvent/include/CosEventChannelAdmin.hrl").
-%% Application files
--include("CosNotification.hrl").
--include("CosNotifyChannelAdmin.hrl").
--include("CosNotifyComm.hrl").
--include("CosNotifyFilter.hrl").
-
--include("CosNotification_Definitions.hrl").
-
-%%--------------- EXPORTS ------------------------------------
-%%--------------- External -----------------------------------
-%%----- CosNotifyChannelAdmin::ProxyPullSupplier -------------
--export([connect_any_pull_consumer/4]).
-
-%%----- CosNotifyChannelAdmin::SequenceProxyPullSupplier -----
--export([connect_sequence_pull_consumer/4]).
-
-%%----- CosNotifyChannelAdmin::StructuredProxyPullSupplier ---
--export([connect_structured_pull_consumer/4]).
-
-%%----- Inherit from CosNotifyChannelAdmin::ProxySupplier ----
--export([obtain_offered_types/4,
- validate_event_qos/4]).
-
-%%----- Inherit from CosNotification::QoSAdmin ---------------
--export([get_qos/3,
- set_qos/4,
- validate_qos/4]).
-
-%%----- Inherit from CosNotifyComm::NotifySubscribe ----------
--export([subscription_change/5]).
-
-%%----- Inherit from CosNotifyFilter::FilterAdmin ------------
--export([add_filter/4,
- remove_filter/4,
- get_filter/4,
- get_all_filters/3,
- remove_all_filters/3]).
-
-%%----- Inherit from CosEventComm::PullSupplier -------------
--export([pull/3,
- try_pull/3,
- disconnect_pull_supplier/3]).
-
-%%----- Inherit from CosNotifyComm::SequencePullSupplier --
--export([pull_structured_events/4,
- try_pull_structured_events/4,
- disconnect_sequence_pull_supplier/3]).
-
-%%----- Inherit from CosNotifyComm::StructuredPullSupplier --
--export([pull_structured_event/3,
- try_pull_structured_event/3,
- disconnect_structured_pull_supplier/3]).
-
-%%----- Inherit from CosEventChannelAdmin::ProxyPullSupplier
--export([connect_pull_consumer/4]).
-
-%% Attributes (external) CosNotifyChannelAdmin::ProxySupplier
--export(['_get_MyType'/3,
- '_get_MyAdmin'/3,
- '_get_priority_filter'/3,
- '_set_priority_filter'/4,
- '_get_lifetime_filter'/3,
- '_set_lifetime_filter'/4]).
-
-%%--------------- Internal -----------------------------------
-%%----- Inherit from cosNotificationComm --------------------
--export([callAny/5,
- callSeq/5]).
-
-%%--------------- gen_server specific exports ----------------
--export([handle_info/2, code_change/3]).
--export([init/1, terminate/2]).
-
-%%--------------- LOCAL DEFINITIONS --------------------------
-%% Data structures
--record(state, {myType,
- myAdmin,
- myAdminPid,
- myChannel,
- myFilters = [],
- myOperator,
- idCounter = 0,
- prioFil,
- lifetFil,
- client,
- qosGlobal,
- qosLocal,
- pacingTimer,
- respondTo,
- subscribeType = false,
- subscribeData = true,
- etsR,
- eventDB}).
-
-%% Data structures constructors
--define(get_InitState(_MyT, _MyA, _MyAP, _QS, _LQS, _Ch, _MyOp, _GT, _GL, _TR),
- #state{myType = _MyT,
- myAdmin = _MyA,
- myAdminPid= _MyAP,
- myChannel = _Ch,
- myOperator= _MyOp,
- qosGlobal = _QS,
- qosLocal = _LQS,
- etsR = ets:new(oe_ets, [set, protected]),
- eventDB = cosNotification_eventDB:create_db(_LQS, _GT, _GL, _TR)}).
-
-
-%% Data structures selectors
-%% Attributes
--define(get_MyType(S), S#state.myType).
--define(get_MyAdmin(S), S#state.myAdmin).
--define(get_MyAdminPid(S), S#state.myAdmin).
--define(get_MyChannel(S), S#state.myChannel).
--define(get_MyOperator(S), S#state.myOperator).
--define(get_PrioFil(S), S#state.prioFil).
--define(get_LifeTFil(S), S#state.lifetFil).
-%% Client Object
--define(get_Client(S), S#state.client).
-%% QoS
--define(get_GlobalQoS(S), S#state.qosGlobal).
--define(get_LocalQoS(S), S#state.qosLocal).
--define(get_BothQoS(S), {S#state.qosGlobal, S#state.qosLocal}).
-%% Filters
--define(get_Filter(S, I), find_obj(lists:keysearch(I, 1, S#state.myFilters))).
--define(get_AllFilter(S), S#state.myFilters).
--define(get_AllFilterID(S), find_ids(S#state.myFilters)).
-%% Event
--define(get_Event(S), cosNotification_eventDB:get_event(S#state.eventDB)).
--define(get_Events(S,M), cosNotification_eventDB:get_events(S#state.eventDB, M)).
--define(get_RespondTo(S), S#state.respondTo).
-%% Amin
--define(get_PacingTimer(S), S#state.pacingTimer).
--define(get_PacingInterval(S), round(?not_GetPacingInterval((S#state.qosLocal))/10000000)).
--define(get_BatchLimit(S), ?not_GetMaximumBatchSize((S#state.qosLocal))).
-%% Subscribe
--define(get_AllSubscribe(S), lists:flatten(ets:match(S#state.etsR,
- {'$1',subscribe}))).
--define(get_SubscribeType(S), S#state.subscribeType).
--define(get_SubscribeData(S), S#state.subscribeData).
-%% ID
--define(get_IdCounter(S), S#state.idCounter).
--define(get_SubscribeDB(S), S#state.etsR).
-
-%% Data structures modifiers
-%% Attributes
--define(set_PrioFil(S,D), S#state{prioFil=D}).
--define(set_LifeTFil(S,D), S#state{lifetFil=D}).
-%% Client Object
--define(set_Client(S,D), S#state{client=D}).
--define(del_Client(S), S#state{client=undefined}).
-%% QoS
--define(set_LocalQoS(S,D), S#state{qosLocal=D}).
--define(set_GlobalQoS(S,D), S#state{qosGlobal=D}).
--define(set_BothQoS(S,GD,LD), S#state{qosGlobal=GD, qosLocal=LD}).
--define(update_EventDB(S,Q), S#state{eventDB=
- cosNotification_eventDB:update(S#state.eventDB, Q)}).
-%% Filters
--define(add_Filter(S,I,O), S#state{myFilters=[{I,O}|S#state.myFilters]}).
--define(del_Filter(S,I), S#state{myFilters=
- delete_obj(lists:keydelete(I, 1, S#state.myFilters),
- S#state.myFilters)}).
--define(del_AllFilter(S), S#state{myFilters=[]}).
--define(set_Unconnected(S), S#state{client=undefined}).
--define(reset_RespondTo(S), S#state{respondTo=undefined}).
--define(set_RespondTo(S,F), S#state{respondTo=F}).
-%% Event
--define(add_Event(S,E), catch cosNotification_eventDB:
- add_event(S#state.eventDB, E, S#state.lifetFil, S#state.prioFil)).
--define(addAndGet_Event(S,E), catch cosNotification_eventDB:
- add_and_get_event(S#state.eventDB, E, S#state.lifetFil, S#state.prioFil)).
-%% Admin
--define(set_PacingTimer(S,T), S#state{pacingTimer=T}).
-%% Subscribe
--define(add_Subscribe(S,E), ets:insert(S#state.etsR, {E, subscribe})).
--define(del_Subscribe(S,E), ets:delete(S#state.etsR, E)).
--define(set_SubscribeType(S,T), S#state{subscribeType=T}).
--define(set_SubscribeData(S,D), S#state{subscribeData=D}).
-%% ID
--define(set_IdCounter(S,V), S#state{idCounter=V}).
--define(new_Id(S), 'CosNotification_Common':create_id(S#state.idCounter)).
-
-%% MISC
--define(is_ANY(S), S#state.myType == 'PULL_ANY').
--define(is_STRUCTURED(S), S#state.myType == 'PULL_STRUCTURED').
--define(is_SEQUENCE(S), S#state.myType == 'PULL_SEQUENCE').
--define(is_ANDOP(S), S#state.myOperator == 'AND_OP').
--define(is_UnConnected(S), S#state.client == undefined).
--define(is_Connected(S), S#state.client =/= undefined).
--define(is_Waiting(S), S#state.respondTo =/= undefined).
--define(is_SubscribedFor(S,K), ets:lookup(S#state.etsR, K) =/= []).
--define(is_BatchLimitReached(S,M), cosNotification_eventDB:
- status(S#state.eventDB, {batchLimit,
- ?not_GetMaximumBatchSize((S#state.qosLocal)), M})).
-
-%%----------------------------------------------------------%
-%% function : handle_info, code_change
-%% Arguments:
-%% Returns :
-%% Effect : Functions demanded by the gen_server module.
-%%-----------------------------------------------------------
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-handle_info(Info, State) ->
- ?DBG("INFO: ~p~n", [Info]),
- case Info of
- {'EXIT', Pid, Reason} when ?get_MyAdminPid(State)==Pid->
- ?DBG("PARENT ADMIN: ~p TERMINATED.~n",[Reason]),
- {stop, Reason, State};
- {'EXIT', _Pid, _Reason} ->
- ?DBG("PROXYPUSHSUPPLIER: ~p TERMINATED.~n",[_Reason]),
- {noreply, State};
- {pacing, TS} when ?is_Waiting(State) ->
- case ?get_PacingTimer(State) of
- {_, TS} ->
- ?DBG("PULL SUPPLIER PACING LIMIT REACHED~n",[]),
- {RespondTo, Max} = ?get_RespondTo(State),
- {EventSeq, _} = ?get_Events(State, Max),
- corba:reply(RespondTo, EventSeq),
- {noreply, ?reset_RespondTo(State)};
- _ ->
- %% Must have been an old timer event, i.e., we reached the
- %% Batch Limit before Pace limit and we were not able
- %% to stop the timer before it triggered an event.
- ?DBG("PULL SUPPLIER OLD PACING LIMIT REACHED~n",[]),
- {noreply, State}
- end;
- {pacing, _} ->
- ?DBG("PULL SUPPLIER PACING LIMIT REACHED BUT NO CLIENT; IMPOSSIBLE!!!~n",[]),
- {noreply, State};
- _ ->
- {noreply, State}
- end.
-
-%%----------------------------------------------------------%
-%% function : init, terminate
-%% Arguments:
-%%-----------------------------------------------------------
-
-init([MyType, MyAdmin, MyAdminPid, InitQoS, LQS, MyChannel, Options, Operator]) ->
- process_flag(trap_exit, true),
- GCTime = 'CosNotification_Common':get_option(gcTime, Options,
- ?not_DEFAULT_SETTINGS),
- GCLimit = 'CosNotification_Common':get_option(gcLimit, Options,
- ?not_DEFAULT_SETTINGS),
- TimeRef = 'CosNotification_Common':get_option(timeService, Options,
- ?not_DEFAULT_SETTINGS),
- {ok, ?get_InitState(MyType, MyAdmin, MyAdminPid, InitQoS, LQS, MyChannel,
- Operator, GCTime, GCLimit, TimeRef)}.
-
-terminate(_Reason, State) when ?is_UnConnected(State) ->
- ok;
-terminate(_Reason, State) ->
- Client = ?get_Client(State),
- case catch corba_object:is_nil(Client) of
- false when ?is_ANY(State) ->
- 'CosNotification_Common':disconnect('CosEventComm_PullConsumer',
- disconnect_pull_consumer,
- Client);
- false when ?is_SEQUENCE(State) ->
- 'CosNotification_Common':disconnect('CosNotifyComm_SequencePullConsumer',
- disconnect_sequence_pull_consumer,
- Client);
- false when ?is_STRUCTURED(State) ->
- 'CosNotification_Common':disconnect('CosNotifyComm_StructuredPullConsumer',
- disconnect_structured_pull_consumer,
- Client);
- _ ->
- ok
- end.
-
-%%-----------------------------------------------------------
-%%----- CosNotifyChannelAdmin_ProxySupplier attributes ------
-%%-----------------------------------------------------------
-%%----------------------------------------------------------%
-%% Attribute: '_get_MyType'
-%% Type : readonly
-%% Returns :
-%%-----------------------------------------------------------
-'_get_MyType'(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_MyType(State), State}.
-
-%%----------------------------------------------------------%
-%% Attribute: '_get_MyAdmin'
-%% Type : readonly
-%% Returns :
-%%-----------------------------------------------------------
-'_get_MyAdmin'(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_MyAdmin(State), State}.
-
-%%----------------------------------------------------------%
-%% Attribute: '_*et_priority_filter'
-%% Type : read/write
-%% Returns :
-%%-----------------------------------------------------------
-'_get_priority_filter'(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_PrioFil(State), State}.
-'_set_priority_filter'(_OE_THIS, _OE_FROM, State, PrioF) ->
- {reply, ok, ?set_PrioFil(State, PrioF)}.
-
-
-%%----------------------------------------------------------%
-%% Attribute: '_*et_lifetime_filter'
-%% Type : read/write
-%% Returns :
-%%-----------------------------------------------------------
-'_get_lifetime_filter'(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_LifeTFil(State), State}.
-'_set_lifetime_filter'(_OE_THIS, _OE_FROM, State, LifeTF) ->
- {reply, ok, ?set_LifeTFil(State, LifeTF)}.
-
-%%-----------------------------------------------------------
-%%------- Exported external functions -----------------------
-%%-----------------------------------------------------------
-%%----- CosEventChannelAdmin::ProxyPullSupplier -------------
-%%----------------------------------------------------------%
-%% function : connect_pull_consumer
-%% Arguments: Client - CosEventComm::PullConsumer
-%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} |
-%% {'EXCEPTION', #'TypeError'{}} |
-%% {'EXCEPTION', #'BAD_OPERATION'{}}
-%% Both exceptions from CosEventChannelAdmin!!!
-%%-----------------------------------------------------------
-connect_pull_consumer(OE_THIS, OE_FROM, State, Client) ->
- connect_any_pull_consumer(OE_THIS, OE_FROM, State, Client).
-
-%%----- CosNotifyChannelAdmin::ProxyPullSupplier ------------
-%%----------------------------------------------------------%
-%% function : connect_any_pull_consumer
-%% Arguments: Client - CosEventComm::PullConsumer
-%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} |
-%% {'EXCEPTION', #'TypeError'{}} |
-%% {'EXCEPTION', #'BAD_OPERATION'{}}
-%% Both exceptions from CosEventChannelAdmin!!!
-%%-----------------------------------------------------------
-connect_any_pull_consumer(_OE_THIS, _OE_FROM, State, Client) when ?is_ANY(State) ->
- ?not_TypeCheck(Client, 'CosEventComm_PullConsumer'),
- if
- ?is_Connected(State) ->
- corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{});
- true ->
- {reply, ok, ?set_Client(State, Client)}
- end;
-connect_any_pull_consumer(_, _, _, _) ->
- corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}).
-
-%%----- CosNotifyChannelAdmin::SequenceProxyPullSupplier ----
-%%----------------------------------------------------------%
-%% function : connect_sequence_pull_consumer
-%% Arguments: Client - CosNotifyComm::SequencePullConsumer
-%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} |
-%% {'EXCEPTION', #'TypeError'{}} |
-%% {'EXCEPTION', #'BAD_OPERATION'{}}
-%%-----------------------------------------------------------
-connect_sequence_pull_consumer(_OE_THIS, _OE_FROM, State, Client) when ?is_SEQUENCE(State) ->
- ?not_TypeCheck(Client, 'CosNotifyComm_SequencePullConsumer'),
- if
- ?is_Connected(State) ->
- corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{});
- true ->
- {reply, ok, ?set_Client(State, Client)}
- end;
-connect_sequence_pull_consumer(_, _, _, _) ->
- corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}).
-
-%%----- CosNotifyChannelAdmin::StructuredProxyPullSupplier --
-%%----------------------------------------------------------%
-%% function : connect_structured_pull_consumer
-%% Arguments: Client - CosNotifyComm::StructuredPullConsumer
-%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} |
-%% {'EXCEPTION', #'TypeError'{}} |
-%% {'EXCEPTION', #'BAD_OPERATION'{}}
-%%-----------------------------------------------------------
-connect_structured_pull_consumer(_OE_THIS, _OE_FROM, State, Client) when ?is_STRUCTURED(State) ->
- ?not_TypeCheck(Client, 'CosNotifyComm_StructuredPullConsumer'),
- if
- ?is_Connected(State) ->
- corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{});
- true ->
- {reply, ok, ?set_Client(State, Client)}
- end;
-connect_structured_pull_consumer(_, _, _, _) ->
- corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}).
-
-%%----- Inherit from CosNotifyChannelAdmin::ProxySupplier ---
-%%----------------------------------------------------------%
-%% function : obtain_offered_types
-%% Arguments: Mode - enum 'ObtainInfoMode' (CosNotifyChannelAdmin)
-%% Returns : CosNotification::EventTypeSeq
-%%-----------------------------------------------------------
-obtain_offered_types(_OE_THIS, _OE_FROM, State, 'ALL_NOW_UPDATES_OFF') ->
- {reply, ?get_AllSubscribe(State), ?set_SubscribeType(State, false)};
-obtain_offered_types(_OE_THIS, _OE_FROM, State, 'ALL_NOW_UPDATES_ON') ->
- {reply, ?get_AllSubscribe(State), ?set_SubscribeType(State, true)};
-obtain_offered_types(_OE_THIS, _OE_FROM, State, 'NONE_NOW_UPDATES_OFF') ->
- {reply, [], ?set_SubscribeType(State, false)};
-obtain_offered_types(_OE_THIS, _OE_FROM, State, 'NONE_NOW_UPDATES_ON') ->
- {reply, [], ?set_SubscribeType(State, true)};
-obtain_offered_types(_,_,_,What) ->
- orber:dbg("[~p] PullerSupplier:obtain_offered_types(~p);~n"
- "Incorrect enumerant", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------%
-%% function : validate_event_qos
-%% Arguments: RequiredQoS - CosNotification::QoSProperties
-%% Returns : ok | {'EXCEPTION', #'UnsupportedQoS'{}}
-%% AvilableQoS - CosNotification::NamedPropertyRangeSeq (out)
-%%-----------------------------------------------------------
-validate_event_qos(_OE_THIS, _OE_FROM, State, RequiredQoS) ->
- AvilableQoS = 'CosNotification_Common':validate_event_qos(RequiredQoS,
- ?get_LocalQoS(State)),
- {reply, {ok, AvilableQoS}, State}.
-
-%%----- Inherit from CosNotification::QoSAdmin --------------
-%%----------------------------------------------------------%
-%% function : get_qos
-%% Arguments:
-%% Returns :
-%%-----------------------------------------------------------
-get_qos(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_GlobalQoS(State), State}.
-
-%%----------------------------------------------------------%
-%% function : set_qos
-%% Arguments: QoS - CosNotification::QoSProperties, i.e.,
-%% [#'Property'{name, value}, ...] where name eq. string()
-%% and value eq. any().
-%% Returns : ok | {'EXCEPTION', CosNotification::UnsupportedQoS}
-%%-----------------------------------------------------------
-set_qos(_OE_THIS, _OE_FROM, State, QoS) ->
- {NewQoS, LQS} = 'CosNotification_Common':set_qos(QoS, ?get_BothQoS(State),
- proxy, ?get_MyAdmin(State),
- false),
- NewState = ?update_EventDB(State, LQS),
- {reply, ok, ?set_BothQoS(NewState, NewQoS, LQS)}.
-
-%%----------------------------------------------------------%
-%% function : validate_qos
-%% Arguments: Required_qos - CosNotification::QoSProperties
-%% [#'Property'{name, value}, ...] where name eq. string()
-%% and value eq. any().
-%% Returns : {'EXCEPTION', CosNotification::UnsupportedQoS}
-%% {ok, CosNotification::NamedPropertyRangeSeq}
-%%-----------------------------------------------------------
-validate_qos(_OE_THIS, _OE_FROM, State, Required_qos) ->
- QoS = 'CosNotification_Common':validate_qos(Required_qos, ?get_BothQoS(State),
- proxy, ?get_MyAdmin(State),
- false),
- {reply, {ok, QoS}, State}.
-
-%%----- Inherit from CosNotifyComm::NotifySubscribe ---------
-%%----------------------------------------------------------%
-%% function : subscription_change
-%% Arguments: Added - Removed - CosNotification::EventTypeSeq
-%% Returns : ok
-%%-----------------------------------------------------------
-subscription_change(_OE_THIS, _OE_FROM, State, Added, Removed) ->
- cosNotification_Filter:validate_types(Added),
- cosNotification_Filter:validate_types(Removed),
- %% On this "side", we care about which type of events the client
- %% will require, since the client (or an agent) clearly stated
- %% that it's only interested in these types of events.
- %% Also see PusherConsumer- and PullerConsumer-'offer_change'.
- update_subscribe(remove, State, Removed),
- CurrentSub = ?get_AllSubscribe(State),
- NewState =
- case cosNotification_Filter:check_types(Added++CurrentSub) of
- true ->
- %% Types supplied does in some way cause all events to be valid.
- %% Smart? Would have been better to not supply any at all.
- ?set_SubscribeData(State, true);
- {ok, Which, WC} ->
- ?set_SubscribeData(State, {Which, WC})
- end,
- update_subscribe(add, NewState, Added),
- case ?get_SubscribeType(NewState) of
- true ->
- %% Perhaps we should handle exception here?!
- %% Probably not. Better to stay "on-line".
- catch 'CosNotifyComm_NotifyPublish':
- offer_change(?get_Client(NewState), Added, Removed),
- ok;
- _->
- ok
- end,
- {reply, ok, NewState}.
-
-update_subscribe(_, _, [])->
- ok;
-update_subscribe(add, State, [H|T]) ->
- ?add_Subscribe(State, H),
- update_subscribe(add, State, T);
-update_subscribe(remove, State, [H|T]) ->
- ?del_Subscribe(State, H),
- update_subscribe(remove, State, T).
-
-%%----- Inherit from CosNotifyFilter::FilterAdmin -----------
-%%----------------------------------------------------------%
-%% function : add_filter
-%% Arguments: Filter - CosNotifyFilter::Filter
-%% Returns : FilterID - long
-%%-----------------------------------------------------------
-add_filter(_OE_THIS, _OE_FROM, State, Filter) ->
- 'CosNotification_Common':type_check(Filter, 'CosNotifyFilter_Filter'),
- FilterID = ?new_Id(State),
- NewState = ?set_IdCounter(State, FilterID),
- {reply, FilterID, ?add_Filter(NewState, FilterID, Filter)}.
-
-%%----------------------------------------------------------%
-%% function : remove_filter
-%% Arguments: FilterID - long
-%% Returns : ok
-%%-----------------------------------------------------------
-remove_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) ->
- {reply, ok, ?del_Filter(State, FilterID)};
-remove_filter(_,_,_,What) ->
- orber:dbg("[~p] PullerSupplier:remove_filter(~p); Not an integer",
- [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------%
-%% function : get_filter
-%% Arguments: FilterID - long
-%% Returns : Filter - CosNotifyFilter::Filter |
-%% {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}}
-%%-----------------------------------------------------------
-get_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) ->
- {reply, ?get_Filter(State, FilterID), State};
-get_filter(_,_,_,What) ->
- orber:dbg("[~p] PullerSupplier:get_filter(~p); Not an integer",
- [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------%
-%% function : get_all_filters
-%% Arguments: -
-%% Returns : Filter - CosNotifyFilter::FilterIDSeq
-%%-----------------------------------------------------------
-get_all_filters(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_AllFilterID(State), State}.
-
-%%----------------------------------------------------------%
-%% function : remove_all_filters
-%% Arguments: -
-%% Returns : ok
-%%-----------------------------------------------------------
-remove_all_filters(_OE_THIS, _OE_FROM, State) ->
- {reply, ok, ?del_AllFilter(State)}.
-
-%%----- Inherit from CosEventComm::PullSupplier -------------
-%%----------------------------------------------------------%
-%% function : disconnect_pull_supplier
-%% Arguments: -
-%% Returns : ok
-%%-----------------------------------------------------------
-disconnect_pull_supplier(_OE_THIS, _OE_FROM, State) ->
- {stop, normal, ok, ?set_Unconnected(State)}.
-
-%%----------------------------------------------------------%
-%% function : pull
-%% Arguments: -
-%% Returns : any - CORBA::ANY
-%%-----------------------------------------------------------
-pull(_OE_THIS, OE_FROM, State) when ?is_ANY(State) ->
- case ?get_Event(State) of
- {[], _} ->
- {noreply, ?set_RespondTo(State, OE_FROM)};
- {Event,_} ->
- {reply, Event, State}
- end;
-pull(_,_,_) ->
- corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------%
-%% function : try_pull
-%% Arguments: -
-%% Returns : any - CORBA::ANY
-%% HasEvent - boolean (out-type)
-%%-----------------------------------------------------------
-try_pull(_OE_THIS, _OE_FROM, State) when ?is_ANY(State) ->
- case ?get_Event(State) of
- {[], _} ->
- {reply, {any:create(orber_tc:null(), null), false}, State};
- {Event, Bool} ->
- {reply, {Event, Bool}, State}
- end;
-try_pull(_,_,_) ->
- corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}).
-
-%%----- Inherit from CosNotifyComm::SequencePullSupplier ----
-%%----------------------------------------------------------%
-%% function : disconnect_sequence_pull_supplier
-%% Arguments: -
-%% Returns : ok
-%%-----------------------------------------------------------
-disconnect_sequence_pull_supplier(_OE_THIS, _OE_FROM, State) ->
- {stop, normal, ok, ?set_Unconnected(State)}.
-
-%%----------------------------------------------------------%
-%% function : pull_structured_events
-%% Arguments: Max - long()
-%% Returns : [StructuredEvent, ..]
-%%-----------------------------------------------------------
-pull_structured_events(_OE_THIS, OE_FROM, State, Max) when ?is_SEQUENCE(State) ->
- case ?is_BatchLimitReached(State, Max) of
- true ->
- %% This test is not fool-proof; if Events have been stored
- %% using StartTime they will still be there but we cannot
- %% deliver them anyway. To solve this "problem" would cost!
- %% Hence, since it works fine otherwise it will do.
- case ?get_Events(State, Max) of
- {[], false} ->
- NewState = start_timer(State),
- {noreply, ?set_RespondTo(NewState, {OE_FROM, Max})};
- {Event,_} ->
- {reply, Event, State}
- end;
- _->
- NewState = start_timer(State),
- {noreply, ?set_RespondTo(NewState, {OE_FROM, Max})}
- end;
-pull_structured_events(_,_,_,_) ->
- corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------%
-%% function : try_pull_structured_events
-%% Arguments: Max - long()
-%% Returns : [StructuredEvent, ..]
-%% HasEvent - Boolean()
-%%-----------------------------------------------------------
-try_pull_structured_events(_OE_THIS, _OE_FROM, State, Max) when ?is_SEQUENCE(State) ->
- {reply, ?get_Events(State, Max), State};
-try_pull_structured_events(_,_,_,_) ->
- corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}).
-
-%%----- Inherit from CosNotifyComm::StructuredPullSupplier --
-%%----------------------------------------------------------%
-%% function : disconnect_structured_pull_supplier
-%% Arguments: -
-%% Returns : ok
-%%-----------------------------------------------------------
-disconnect_structured_pull_supplier(_OE_THIS, _OE_FROM, State) ->
- {stop, normal, ok, ?set_Unconnected(State)}.
-
-%%----------------------------------------------------------%
-%% function : pull_structured_event
-%% Arguments: -
-%% Returns :
-%%-----------------------------------------------------------
-pull_structured_event(_OE_THIS, OE_FROM, State) when ?is_STRUCTURED(State) ->
- case ?get_Event(State) of
- {[], _} ->
- {noreply, ?set_RespondTo(State, OE_FROM)};
- {Event,_} ->
- {reply, Event, State}
- end;
-pull_structured_event(_,_,_) ->
- corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------%
-%% function : try_pull_structured_event
-%% Arguments: -
-%% Returns :
-%%-----------------------------------------------------------
-try_pull_structured_event(_OE_THIS, _OE_FROM, State) when ?is_STRUCTURED(State) ->
- case ?get_Event(State) of
- {[], _} ->
- {reply,
- {?not_CreateSE("","","",[],[],any:create(orber_tc:null(), null)), false},
- State};
- {Event, Bool} ->
- {reply, {Event, Bool}, State}
- end;
-try_pull_structured_event(_,_,_) ->
- corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}).
-
-
-%%--------------- LOCAL FUNCTIONS ----------------------------
-find_obj({value, {_, Obj}}) -> Obj;
-find_obj(_) -> {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}}.
-
-find_ids(List) -> find_ids(List, []).
-find_ids([], Acc) -> Acc;
-find_ids([{I,_}|T], Acc) -> find_ids(T, [I|Acc]);
-find_ids(_, _) -> corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}).
-
-%% Delete a single object.
-%% The list do not differ, i.e., no filter removed, raise exception.
-delete_obj(List,List) -> corba:raise(#'CosNotifyFilter_FilterNotFound'{});
-delete_obj(List,_) -> List.
-
-
-%%-----------------------------------------------------------
-%% function : callSeq
-%% Arguments:
-%% Returns :
-%%-----------------------------------------------------------
-callSeq(_OE_THIS, OE_FROM, State, EventsIn, Status) ->
- %% We should do something here, i.e., see what QoS this Object offers and
- %% act accordingly.
- corba:reply(OE_FROM, ok),
- case cosNotification_eventDB:validate_event(?get_SubscribeData(State), EventsIn,
- ?get_AllFilter(State),
- ?get_SubscribeDB(State),
- Status) of
- {[], _} ->
- ?DBG("PROXY NOSUBSCRIPTION SEQUENCE/STRUCTURED: ~p~n",[EventsIn]),
- {noreply, State};
- %% Just one event and we got a client waiting => there is no need to store
- %% the event, just transform it and pass it on.
- {[Event], _} when ?is_ANY(State), ?is_Waiting(State) ->
- ?DBG("PROXY RECEIVED SEQUENCE[1]==>ANY: ~p~n",[Event]),
- AnyEvent = any:create('CosNotification_StructuredEvent':tc(),Event),
- case ?addAndGet_Event(State, AnyEvent) of
- {[], _} ->
- ?DBG("PROXY RECEIVED UNDELIVERABLE SEQUENCE[1]: ~p~n",
- [Event]),
- %% Cannot deliver the event at the moment; perhaps Starttime
- %% set or Deadline passed.
- {noreply, State};
- {PossiblyOtherEvent, _} ->
- ?DBG("PROXY RECEIVED SEQUENCE[1] ~p; DELIVER: ~p~n",
- [Event, PossiblyOtherEvent]),
- corba:reply(?get_RespondTo(State), PossiblyOtherEvent),
- {noreply, ?reset_RespondTo(State)}
- end;
- {[Event],_} when ?is_STRUCTURED(State), ?is_Waiting(State) ->
- case ?addAndGet_Event(State, Event) of
- {[], _} ->
- ?DBG("PROXY RECEIVED UNDELIVERABLE SEQUENCE[1]: ~p~n",
- [Event]),
- %% Cannot deliver the event at the moment; perhaps Starttime
- %% set or Deadline passed.
- {noreply, State};
- {PossiblyOtherEvent, _} ->
- ?DBG("PROXY RECEIVED SEQUENCE[1] ~p; DELIVER: ~p~n",
- [Event, PossiblyOtherEvent]),
- corba:reply(?get_RespondTo(State), PossiblyOtherEvent),
- {noreply, ?reset_RespondTo(State)}
- end;
- %% A sequence of events => store them and extract the first (according to QoS)
- %% event and forward it.
- {Events,_} when ?is_ANY(State), ?is_Waiting(State) ->
- ?DBG("PROXY RECEIVED SEQUENCE==>ANY: ~p~n",[Events]),
- store_events(State, Events),
- case ?get_Event(State) of
- {[], _} ->
- {noreply, State};
- {AnyEvent, _} ->
- corba:reply(?get_RespondTo(State), AnyEvent),
- {noreply, ?reset_RespondTo(State)}
- end;
- {Events, _} when ?is_STRUCTURED(State), ?is_Waiting(State) ->
- ?DBG("PROXY RECEIVED SEQUENCE: ~p~n",[Events]),
- store_events(State, Events),
- case ?get_Event(State) of
- {[], _} ->
- {noreply, State};
- {_StrEvent, _} ->
- corba:reply(?get_RespondTo(State), Events),
- {noreply, ?reset_RespondTo(State)}
- end;
- {Events, _} when ?is_SEQUENCE(State), ?is_Waiting(State) ->
- ?DBG("PROXY RECEIVED SEQUENCE: ~p~n",[Events]),
- %% Store them first and extract Max events in QoS order.
- store_events(State, Events),
- {RespondTo, Max} = ?get_RespondTo(State),
- case ?is_BatchLimitReached(State, Max) of
- true ->
- {EventSeq, _} = ?get_Events(State, Max),
- corba:reply(RespondTo, EventSeq),
- stop_timer(State),
- {noreply, ?reset_RespondTo(State)};
- _->
- {noreply, State}
- end;
- %% No client waiting. Store the event(s).
- {Events, _} ->
- ?DBG("PROXY RECEIVED SEQUENCE: ~p~n",[Events]),
- store_events(State, Events),
- {noreply, State}
- end.
-
-store_events(_State, []) ->
- ok;
-store_events(State, [Event|Rest]) when ?is_ANY(State) ->
- AnyEvent = any:create('CosNotification_StructuredEvent':tc(),Event),
- ?add_Event(State,AnyEvent),
- store_events(State, Rest);
-store_events(State, [Event|Rest]) ->
- ?add_Event(State,Event),
- store_events(State, Rest).
-
-%%-----------------------------------------------------------
-%% function : callAny
-%% Arguments:
-%% Returns :
-%%-----------------------------------------------------------
-callAny(_OE_THIS, OE_FROM, State, EventIn, Status) ->
- corba:reply(OE_FROM, ok),
- case cosNotification_eventDB:validate_event(?get_SubscribeData(State), EventIn,
- ?get_AllFilter(State),
- ?get_SubscribeDB(State),
- Status) of
- {[],_} ->
- ?DBG("PROXY NOSUBSCRIPTION ANY: ~p~n",[EventIn]),
- {noreply, State};
- {Event,_} when ?is_ANY(State), ?is_Waiting(State) ->
- ?DBG("PROXY RECEIVED ANY: ~p~n",[Event]),
- case ?addAndGet_Event(State, Event) of
- {[],_} ->
- %% Unable to deliver the event (Starttime, Deadline etc).
- {noreply, State};
- {MaybeOtherEvent , _} ->
- corba:reply(?get_RespondTo(State), MaybeOtherEvent),
- {noreply, ?reset_RespondTo(State)}
- end;
- {Event,_} when ?is_ANY(State) ->
- ?DBG("PROXY RECEIVED ANY: ~p~n",[Event]),
- ?add_Event(State,Event),
- {noreply, State};
- {Event,_} when ?is_STRUCTURED(State), ?is_Waiting(State) ->
- ?DBG("PROXY RECEIVED ANY==>STRUCTURED: ~p~n",[Event]),
- case ?addAndGet_Event(State, ?not_CreateSE("","%ANY","",[],[],Event)) of
- {[],_} ->
- %% Unable to deliver the event (Starttime, Deadline etc).
- {noreply, State};
- {MaybeOtherEvent , _} ->
- corba:reply(?get_RespondTo(State), MaybeOtherEvent),
- {noreply, ?reset_RespondTo(State)}
- end;
- {Event,_} when ?is_SEQUENCE(State), ?is_Waiting(State) ->
- ?DBG("PROXY RECEIVED ANY==>SEQUENCE[1]: ~p~n",[Event]),
- ?add_Event(State,?not_CreateSE("","%ANY","",[],[],Event)),
- {RespondTo, Max} = ?get_RespondTo(State),
- case ?is_BatchLimitReached(State, Max) of
- true ->
- {EventSeq, _} = ?get_Events(State, Max),
- corba:reply(RespondTo, EventSeq),
- stop_timer(State),
- {noreply, ?reset_RespondTo(State)};
- _ ->
- {noreply, State}
- end;
- {Event,_} ->
- ?DBG("PROXY RECEIVED ANY==>STRUCTURED/SEQUENCE: ~p~n",[Event]),
- ?add_Event(State,?not_CreateSE("","%ANY","",[],[],Event)),
- {noreply, State}
- end.
-
-
-
-%% Start timers which send a message each time we should push events. Only used
-%% when this objects is defined to supply sequences.
-start_timer(State) ->
- TS = erlang:timestamp(),
- case catch timer:send_after(timer:seconds(?get_PacingInterval(State)),
- {pacing, TS}) of
- {ok,PacTRef} ->
- ?DBG("PULL SUPPLIER STARTED TIMER, BATCH LIMIT: ~p~n",
- [?get_BatchLimit(State)]),
- ?set_PacingTimer(State, {PacTRef, TS});
- What ->
- orber:dbg("[~p] PullerSupplier:start_timer();~n"
- "Unable to invoke timer:send_interval/2: ~p",
- [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-stop_timer(State) ->
- case ?get_PacingTimer(State) of
- undefined ->
- ok;
- {Timer, _} ->
- ?DBG("PULL SUPPLIER STOPPED TIMER~n",[]),
- timer:cancel(Timer)
- end.
-
-%%--------------- MISC FUNCTIONS, E.G. DEBUGGING -------------
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/cosNotification/src/PusherConsumer_impl.erl b/lib/cosNotification/src/PusherConsumer_impl.erl
deleted file mode 100644
index f82f9d8bbd..0000000000
--- a/lib/cosNotification/src/PusherConsumer_impl.erl
+++ /dev/null
@@ -1,730 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : PusherConsumer_impl.erl
-%% Purpose :
-%%----------------------------------------------------------------------
-
--module('PusherConsumer_impl').
-
-%%--------------- INCLUDES -----------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
-%% cosEvent files.
--include_lib("cosEvent/include/CosEventChannelAdmin.hrl").
--include_lib("cosEvent/include/CosEventComm.hrl").
-%% Application files
--include("CosNotification.hrl").
--include("CosNotifyChannelAdmin.hrl").
--include("CosNotifyComm.hrl").
--include("CosNotifyFilter.hrl").
-
--include("CosNotification_Definitions.hrl").
-
-%%--------------- EXPORTS ------------------------------------
-%%--------------- External -----------------------------------
-%%----- CosNotifyChannelAdmin::ProxyPushConsumer -------------
--export([connect_any_push_supplier/4]).
-
-%%----- CosNotifyChannelAdmin::SequenceProxyPushConsumer -----
--export([connect_sequence_push_supplier/4]).
-
-%%----- CosNotifyChannelAdmin::StructuredProxyPushConsumer ---
--export([connect_structured_push_supplier/4]).
-
-%%----- Inherit from CosNotifyChannelAdmin::ProxyConsumer ----
--export([obtain_subscription_types/4,
- validate_event_qos/4]).
-
-%%----- Inherit from CosNotification::QoSAdmin ---------------
--export([get_qos/3,
- set_qos/4,
- validate_qos/4]).
-
-%%----- Inherit from CosNotifyComm::NotifyPublish ------------
--export([offer_change/5]).
-
-%%----- Inherit from CosNotifyFilter::FilterAdmin ------------
--export([add_filter/4,
- remove_filter/4,
- get_filter/4,
- get_all_filters/3,
- remove_all_filters/3]).
-
-%%----- Inherit from CosEventComm::PushConsumer -------------
--export([push/4,
- disconnect_push_consumer/3]).
-
-%%----- Inherit from CosNotifyComm::SequencePushConsumer ----
--export([push_structured_events/4,
- disconnect_sequence_push_consumer/3]).
-
-%%----- Inherit from CosNotifyComm::StructuredPushConsumer --
--export([push_structured_event/4,
- disconnect_structured_push_consumer/3]).
-
-%%----- Inherit from CosEventChannelAdmin::ProxyPushConsumer
--export([connect_push_supplier/4]).
-
-%% Attributes (external) CosNotifyChannelAdmin::ProxySupplier
--export(['_get_MyType'/3,
- '_get_MyAdmin'/3]).
-
-%%--------------- gen_server specific exports ----------------
--export([handle_info/2, code_change/3]).
--export([init/1, terminate/2]).
-
-%%--------------- LOCAL DEFINITIONS --------------------------
-%% Data structures
--record(state, {myType,
- myAdmin,
- myAdminPid,
- myChannel,
- myFilters = [],
- myOperator,
- idCounter = 0,
- client,
- qosGlobal,
- qosLocal,
- publishType = false,
- etsR,
- eventDB}).
-
-%% Data structures constructors
--define(get_InitState(_MyT, _MyA, _MyAP, _QS, _LQS, _Ch, _EDB, _MyOP),
- #state{myType = _MyT,
- myAdmin = _MyA,
- myAdminPid= _MyAP,
- myChannel = _Ch,
- myOperator= _MyOP,
- qosGlobal = _QS,
- qosLocal = _LQS,
- etsR = ets:new(oe_ets, [set, protected]),
- eventDB = _EDB}).
-
-%%-------------- Data structures selectors -----------------
-%% Attributes
--define(get_MyType(S), S#state.myType).
--define(get_MyAdmin(S), S#state.myAdmin).
--define(get_MyAdminPid(S), S#state.myAdminPid).
--define(get_MyChannel(S), S#state.myChannel).
--define(get_MyOperator(S), S#state.myOperator).
-%% Client Object
--define(get_Client(S), S#state.client).
-%% QoS
--define(get_GlobalQoS(S), S#state.qosGlobal).
--define(get_LocalQoS(S), S#state.qosLocal).
--define(get_BothQoS(S), {S#state.qosGlobal, S#state.qosLocal}).
-%% Filters
--define(get_Filter(S, I), find_obj(lists:keysearch(I, 1, S#state.myFilters))).
--define(get_AllFilter(S), S#state.myFilters).
--define(get_AllFilterID(S), find_ids(S#state.myFilters)).
-%% Publish
--define(get_AllPublish(S), lists:flatten(ets:match(S#state.etsR,
- {'$1',publish}))).
--define(get_PublishType(S), S#state.publishType).
-%% ID
--define(get_IdCounter(S), S#state.idCounter).
-%% Event
--define(get_Event(S), cosNotification_eventDB:get_event(S#state.eventDB)).
--define(get_Events(S,M), cosNotification_eventDB:get_events(S#state.eventDB, M)).
-
--define(get_EventCounter(S), S#state.eventCounter).
-%% Admin
--define(get_BatchLimit(S), ?not_GetMaximumBatchSize((S#state.qosLocal))).
-
-%%-------------- Data structures modifiers -----------------
-%% Client Object
--define(set_Client(S,D), S#state{client=D}).
--define(del_Client(S), S#state{client=undefined}).
--define(set_Unconnected(S), S#state{client=undefined}).
-%% QoS
--define(set_LocalQoS(S,D), S#state{qosLocal=D}).
--define(set_GlobalQoS(S,D), S#state{qosGlobal=D}).
--define(set_BothQoS(S,GD,LD), S#state{qosGlobal=GD, qosLocal=LD}).
-%% Filters
--define(add_Filter(S,I,O), S#state{myFilters=[{I,O}|S#state.myFilters]}).
--define(del_Filter(S,I), S#state{myFilters=
- delete_obj(lists:keydelete(I, 1, S#state.myFilters),
- S#state.myFilters)}).
--define(del_AllFilter(S), S#state{myFilters=[]}).
-%% Publish
--define(add_Publish(S,E), ets:insert(S#state.etsR, {E, publish})).
--define(del_Publish(S,E), ets:delete(S#state.etsR, E)).
--define(set_PublishType(S,T), S#state{publishType=T}).
-%% ID
--define(set_IdCounter(S,V), S#state{idCounter=V}).
--define(new_Id(S), 'CosNotification_Common':create_id(S#state.idCounter)).
-%% Event
--define(add_Event(S,E), cosNotification_eventDB:add_event(S#state.eventDB, E)).
--define(update_EventDB(S,Q), S#state{eventDB=
- cosNotification_eventDB:update(S#state.eventDB, Q)}).
-
--define(set_EventCounter(S,V), S#state{eventCounter=V}).
--define(add_to_EventCounter(S,V),S#state{eventCounter=S#state.eventCounter+V}).
--define(reset_EventCounter(S), S#state{eventCounter=0}).
--define(increase_EventCounter(S),S#state{eventCounter=(S#state.eventCounter+1)}).
--define(decrease_EventCounter(S),S#state{eventCounter=S#state.eventCounter-1}).
--define(add_ToEventCounter(S,A), S#state{eventCounter=(S#state.eventCounter+A)}).
--define(sub_FromEventCounter(S,_A), S#state{eventCounter=(S#state.eventCounter-_A)}).
--define(set_EventCounterTo(S,V), S#state{eventCounter=V}).
-
-%% MISC
--define(is_ANY(S), S#state.myType == 'PUSH_ANY').
--define(is_STRUCTURED(S), S#state.myType == 'PUSH_STRUCTURED').
--define(is_SEQUENCE(S), S#state.myType == 'PUSH_SEQUENCE').
--define(is_ANDOP(S), S#state.myOperator == 'AND_OP').
--define(is_UnConnected(S), S#state.client == undefined).
--define(is_Connected(S), S#state.client =/= undefined).
--define(is_PersistentConnection(S),
- ?not_GetConnectionReliability((S#state.qosLocal)) == ?not_Persistent).
--define(is_PersistentEvent(S),
- ?not_GetEventReliability((S#state.qosLocal)) == ?not_Persistent).
--define(is_BatchLimitReached(S), S#state.eventCounter >=
- ?not_GetMaximumBatchSize((S#state.qosLocal))).
-
-
-%%----------------------------------------------------------%
-%% function : handle_info, code_change
-%% Arguments:
-%% Returns :
-%% Effect : Functions demanded by the gen_server module.
-%%-----------------------------------------------------------
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-handle_info(Info, State) ->
- ?DBG("INFO: ~p~n", [Info]),
- case Info of
- {'EXIT', Pid, Reason} when ?get_MyAdminPid(State)==Pid->
- ?DBG("PARENT ADMIN: ~p TERMINATED.~n",[Reason]),
- {stop, Reason, State};
- {'EXIT', _Pid, _Reason} ->
- ?DBG("PROXYPUSHCONSUMER: ~p TERMINATED.~n",[_Reason]),
- {noreply, State};
- _ ->
- {noreply, State}
- end.
-
-%%----------------------------------------------------------%
-%% function : init, terminate
-%% Arguments:
-%%-----------------------------------------------------------
-
-init(['PUSH_SEQUENCE', MyAdmin, MyAdminPid, InitQoS, LQS,
- MyChannel, Options, Operator]) ->
- process_flag(trap_exit, true),
- %% Only if MyType is 'PUSH_SEQUENCE' we need an ets to store events in.
- %% Otherwise we'll forward them at once. Why? We don't know when the next event
- %% is due.
- GCTime = 'CosNotification_Common':get_option(gcTime, Options,
- ?not_DEFAULT_SETTINGS),
- GCLimit = 'CosNotification_Common':get_option(gcLimit, Options,
- ?not_DEFAULT_SETTINGS),
- TimeRef = 'CosNotification_Common':get_option(timeService, Options,
- ?not_DEFAULT_SETTINGS),
- {ok, ?get_InitState('PUSH_SEQUENCE', MyAdmin, MyAdminPid, InitQoS, LQS, MyChannel,
- cosNotification_eventDB:create_db(LQS, GCTime, GCLimit, TimeRef),
- Operator)};
-init([MyType, MyAdmin, MyAdminPid, InitQoS, LQS, MyChannel, _Options, Operator]) ->
- process_flag(trap_exit, true),
- {ok, ?get_InitState(MyType, MyAdmin, MyAdminPid, InitQoS, LQS, MyChannel,
- undefined, Operator)}.
-
-terminate(_Reason, State) when ?is_UnConnected(State) ->
- ok;
-terminate(_Reason, State) ->
- Client = ?get_Client(State),
- case catch corba_object:is_nil(Client) of
- false when ?is_ANY(State) ->
- 'CosNotification_Common':disconnect('CosEventComm_PushSupplier',
- disconnect_push_supplier,
- Client);
- false when ?is_SEQUENCE(State) ->
- 'CosNotification_Common':disconnect('CosNotifyComm_SequencePushSupplier',
- disconnect_sequence_push_supplier,
- Client);
- false when ?is_STRUCTURED(State) ->
- 'CosNotification_Common':disconnect('CosNotifyComm_StructuredPushSupplier',
- disconnect_structured_push_supplier,
- Client);
- _ ->
- ok
- end.
-
-%%-----------------------------------------------------------
-%%----- CosNotifyChannelAdmin_ProxyConsumer attributes ------
-%%-----------------------------------------------------------
-%%----------------------------------------------------------%
-%% Attribute: '_get_MyType'
-%% Type : readonly
-%% Returns :
-%%-----------------------------------------------------------
-'_get_MyType'(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_MyType(State), State}.
-
-%%----------------------------------------------------------%
-%% Attribute: '_get_MyAdmin'
-%% Type : readonly
-%% Returns :
-%%-----------------------------------------------------------
-'_get_MyAdmin'(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_MyAdmin(State), State}.
-
-%%-----------------------------------------------------------
-%%------- Exported external functions -----------------------
-%%-----------------------------------------------------------
-%%----- CosEventChannelAdmin::ProxyPushConsumer -------------
-%%----------------------------------------------------------%
-%% function : connect_push_supplier
-%% Arguments: Client - CosEventComm::PushSupplier
-%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} |
-%% {'EXCEPTION', #'TypeError'{}}
-%% Both exceptions from CosEventChannelAdmin!!!
-%%-----------------------------------------------------------
-connect_push_supplier(OE_THIS, OE_FROM, State, Client) ->
- connect_any_push_supplier(OE_THIS, OE_FROM, State, Client).
-
-%%----- CosNotifyChannelAdmin::ProxyPushConsumer ------------
-%%----------------------------------------------------------%
-%% function : connect_any_push_supplier
-%% Arguments: Client - CosEventComm::PushSupplier
-%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} |
-%% {'EXCEPTION', #'TypeError'{}}
-%% Both exceptions from CosEventChannelAdmin!!!
-%%-----------------------------------------------------------
-connect_any_push_supplier(_OE_THIS, _OE_FROM, State, Client) when ?is_ANY(State) ->
- ?not_TypeCheck(Client, 'CosEventComm_PushSupplier'),
- if
- ?is_Connected(State) ->
- corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{});
- true ->
- {reply, ok, ?set_Client(State, Client)}
- end;
-connect_any_push_supplier(_, _, _, _) ->
- corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}).
-
-%%----- CosNotifyChannelAdmin::SequenceProxyPushConsumer ----
-%%----------------------------------------------------------%
-%% function : connect_sequence_push_supplier
-%% Arguments: Client - CosNotifyComm::SequencePushSupplier
-%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} |
-%% {'EXCEPTION', #'TypeError'{}}
-%%-----------------------------------------------------------
-connect_sequence_push_supplier(_OE_THIS, _OE_FROM, State, Client) when ?is_SEQUENCE(State) ->
- ?not_TypeCheck(Client, 'CosNotifyComm_SequencePushSupplier'),
- if
- ?is_Connected(State) ->
- corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{});
- true ->
- {reply, ok, ?set_Client(State, Client)}
- end;
-connect_sequence_push_supplier(_, _, _, _) ->
- corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}).
-
-%%----- CosNotifyChannelAdmin::StructuredProxyPushConsumer --
-%%----------------------------------------------------------%
-%% function : connect_structured_push_supplier
-%% Arguments: Client - CosNotifyComm::StructuredPushSupplier
-%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} |
-%% {'EXCEPTION', #'TypeError'{}}
-%%-----------------------------------------------------------
-connect_structured_push_supplier(_OE_THIS, _OE_FROM, State, Client) when ?is_STRUCTURED(State) ->
- ?not_TypeCheck(Client, 'CosNotifyComm_StructuredPushSupplier'),
- if
- ?is_Connected(State) ->
- corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{});
- true ->
- {reply, ok, ?set_Client(State, Client)}
- end;
-connect_structured_push_supplier(_, _, _, _) ->
- corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}).
-
-%%----- Inherit from CosNotifyChannelAdmin::ProxyConsumer ---
-%%----------------------------------------------------------%
-%% function : obtain_subscription_types
-%% Arguments: Mode - enum 'ObtainInfoMode' (CosNotifyChannelAdmin)
-%% Returns : CosNotification::EventTypeSeq
-%%-----------------------------------------------------------
-obtain_subscription_types(_OE_THIS, _OE_FROM, State, 'ALL_NOW_UPDATES_OFF') ->
- {reply, ?get_AllPublish(State), ?set_PublishType(State, false)};
-obtain_subscription_types(_OE_THIS, _OE_FROM, State, 'ALL_NOW_UPDATES_ON') ->
- {reply, ?get_AllPublish(State), ?set_PublishType(State, true)};
-obtain_subscription_types(_OE_THIS, _OE_FROM, State, 'NONE_NOW_UPDATES_OFF') ->
- {reply, [], ?set_PublishType(State, false)};
-obtain_subscription_types(_OE_THIS, _OE_FROM, State, 'NONE_NOW_UPDATES_ON') ->
- {reply, [], ?set_PublishType(State, true)};
-obtain_subscription_types(_,_,_,What) ->
- orber:dbg("[~p] PusherConsumer:obtain_subscription_types(~p);~n"
- "Incorrect enumerant", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------%
-%% function : validate_event_qos
-%% Arguments: RequiredQoS - CosNotification::QoSProperties
-%% Returns : ok | {'EXCEPTION', #'UnsupportedQoS'{}}
-%% AvilableQoS - CosNotification::NamedPropertyRangeSeq (out)
-%%-----------------------------------------------------------
-validate_event_qos(_OE_THIS, _OE_FROM, State, RequiredQoS) ->
- AvilableQoS = 'CosNotification_Common':validate_event_qos(RequiredQoS,
- ?get_LocalQoS(State)),
- {reply, {ok, AvilableQoS}, State}.
-
-%%----- Inherit from CosNotification::QoSAdmin --------------
-%%----------------------------------------------------------%
-%% function : get_qos
-%% Arguments:
-%% Returns :
-%%-----------------------------------------------------------
-get_qos(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_GlobalQoS(State), State}.
-
-%%----------------------------------------------------------%
-%% function : set_qos
-%% Arguments: QoS - CosNotification::QoSProperties, i.e.,
-%% [#'Property'{name, value}, ...] where name eq. string()
-%% and value eq. any().
-%% Returns : ok | {'EXCEPTION', CosNotification::UnsupportedQoS}
-%%-----------------------------------------------------------
-set_qos(_OE_THIS, _OE_FROM, State, QoS) ->
- {NewQoS, LQS} = 'CosNotification_Common':set_qos(QoS, ?get_BothQoS(State),
- proxy, ?get_MyAdmin(State),
- false),
- NewState = ?update_EventDB(State, LQS),
- {reply, ok, ?set_BothQoS(NewState, NewQoS, LQS)}.
-
-%%----------------------------------------------------------%
-%% function : validate_qos
-%% Arguments: Required_qos - CosNotification::QoSProperties
-%% [#'Property'{name, value}, ...] where name eq. string()
-%% and value eq. any().
-%% Returns : {'EXCEPTION', CosNotification::UnsupportedQoS}
-%% {ok, CosNotification::NamedPropertyRangeSeq}
-%%-----------------------------------------------------------
-validate_qos(_OE_THIS, _OE_FROM, State, Required_qos) ->
- QoS = 'CosNotification_Common':validate_qos(Required_qos, ?get_BothQoS(State),
- proxy, ?get_MyAdmin(State),
- false),
- {reply, {ok, QoS}, State}.
-
-%%----- Inherit from CosNotifyComm::NotifyPublish -----------
-%%----------------------------------------------------------%
-%% function : offer_change
-%% Arguments: Added - #'CosNotification_EventType'{}
-%% Removed - #'CosNotification_EventType'{}
-%% Returns : ok |
-%% {'EXCEPTION', #'CosNotifyComm_InvalidEventType'{}}
-%%-----------------------------------------------------------
-offer_change(_OE_THIS, _OE_FROM, State, Added, Removed) ->
- cosNotification_Filter:validate_types(Added),
- cosNotification_Filter:validate_types(Removed),
- %% On this "side" we don't really care about which
- %% type of events the client will supply.
- %% Perhaps, later on, if we want to check this against Filters
- %% associated with this object we may change this approach, i.e., if
- %% the filter will not allow passing certain event types. But the
- %% user should see to that that situation never occurs. It would add
- %% extra overhead. Also see PusherSupplier- and PullerSuppler-
- %% 'subscription_change'.
- update_publish(add, State, Added),
- update_publish(remove, State, Removed),
- case ?get_PublishType(State) of
- true ->
- %% Perhaps we should handle exception here?!
- %% Probably not. Better to stay "on-line".
- catch 'CosNotifyComm_NotifySubscribe':
- subscription_change(?get_Client(State), Added, Removed),
- ok;
- _->
- ok
- end,
- {reply, ok, State}.
-
-update_publish(_, _, [])->
- ok;
-update_publish(add, State, [H|T]) ->
- ?add_Publish(State, H),
- update_publish(add, State, T);
-update_publish(remove, State, [H|T]) ->
- ?del_Publish(State, H),
- update_publish(remove, State, T).
-
-%%----- Inherit from CosNotifyFilter::FilterAdmin -----------
-%%----------------------------------------------------------%
-%% function : add_filter
-%% Arguments: Filter - CosNotifyFilter::Filter
-%% Returns : FilterID - long
-%%-----------------------------------------------------------
-add_filter(_OE_THIS, _OE_FROM, State, Filter) ->
- 'CosNotification_Common':type_check(Filter, 'CosNotifyFilter_Filter'),
- FilterID = ?new_Id(State),
- NewState = ?set_IdCounter(State, FilterID),
- {reply, FilterID, ?add_Filter(NewState, FilterID, Filter)}.
-
-%%----------------------------------------------------------%
-%% function : remove_filter
-%% Arguments: FilterID - long
-%% Returns : ok
-%%-----------------------------------------------------------
-remove_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) ->
- {reply, ok, ?del_Filter(State, FilterID)};
-remove_filter(_,_,_,What) ->
- orber:dbg("[~p] PusherConsumer:remove_filter(~p); Not an integer",
- [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------%
-%% function : get_filter
-%% Arguments: FilterID - long
-%% Returns : Filter - CosNotifyFilter::Filter |
-%% {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}}
-%%-----------------------------------------------------------
-get_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) ->
- {reply, ?get_Filter(State, FilterID), State};
-get_filter(_,_,_,What) ->
- orber:dbg("[~p] PusherConsumer:get_filter(~p); Not an integer",
- [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------%
-%% function : get_all_filters
-%% Arguments: -
-%% Returns : Filter - CosNotifyFilter::FilterIDSeq
-%%-----------------------------------------------------------
-get_all_filters(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_AllFilterID(State), State}.
-
-%%----------------------------------------------------------%
-%% function : remove_all_filters
-%% Arguments: -
-%% Returns : ok
-%%-----------------------------------------------------------
-remove_all_filters(_OE_THIS, _OE_FROM, State) ->
- {reply, ok, ?del_AllFilter(State)}.
-
-%%----- Inherit from CosEventComm::PushConsumer -------------
-%%----------------------------------------------------------%
-%% function : disconnect_push_consumer
-%% Arguments: -
-%% Returns : ok
-%%-----------------------------------------------------------
-disconnect_push_consumer(_OE_THIS, _OE_FROM, State) ->
- {stop, normal, ok, ?set_Unconnected(State)}.
-
-%%----------------------------------------------------------%
-%% function : push
-%% Arguments: AnyEvent
-%% Returns : ok |
-%%-----------------------------------------------------------
-push(OE_THIS, OE_FROM, State, Event) when ?is_ANY(State) ->
- corba:reply(OE_FROM, ok),
- case {?not_isConvertedStructured(Event),
- cosNotification_eventDB:filter_events([Event], ?get_AllFilter(State))} of
- {_, {[],_}} when ?is_ANDOP(State) ->
- {noreply, State};
- {true, {[],[_]}} ->
- %% Is OR and converted, change back and forward to Admin
- forward(seq, ?get_MyAdmin(State), State, [any:get_value(Event)],
- 'MATCH', OE_THIS);
- {_, {[],[_]}} ->
- %% Is OR and not converted, forward to Admin
- forward(any, ?get_MyAdmin(State), State, Event, 'MATCH', OE_THIS);
- {true, {[_],_}} when ?is_ANDOP(State) ->
- %% Is AND and converted, change back and forward to Admin
- forward(seq, ?get_MyAdmin(State), State, [any:get_value(Event)],
- 'MATCH', OE_THIS);
- {true, {[_],_}} ->
- %% Is OR and converted, change back and forward to Channel
- forward(seq, ?get_MyChannel(State), State, [any:get_value(Event)],
- 'MATCHED', OE_THIS);
- {_, {[_],_}} when ?is_ANDOP(State) ->
- %% Is AND and not converted, forward to Admin
- forward(any, ?get_MyAdmin(State), State, Event, 'MATCH', OE_THIS);
- _ ->
- %% Is OR and not converted, forward to Channel
- forward(any, ?get_MyChannel(State), State, Event, 'MATCHED', OE_THIS)
- end;
-push(_, _, _, _) ->
- corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}).
-
-%%----- Inherit from CosNotifyComm::SequencePushConsumer ----
-%%----------------------------------------------------------%
-%% function : disconnect_sequence_push_consumer
-%% Arguments: -
-%% Returns : ok
-%%-----------------------------------------------------------
-disconnect_sequence_push_consumer(_OE_THIS, _OE_FROM, State) ->
- {stop, normal, ok, ?set_Unconnected(State)}.
-
-%%----------------------------------------------------------%
-%% function : push_structured_events
-%% Arguments: CosNotification::EventBatch
-%% Returns : ok |
-%%-----------------------------------------------------------
-push_structured_events(OE_THIS, OE_FROM, State, Events) when ?is_SEQUENCE(State) ->
- corba:reply(OE_FROM, ok),
- %% We cannot convert parts of the sequence to any, event though they
- %% are converted from any to structured. Would be 'impossible' to send.
- case cosNotification_eventDB:filter_events(Events, ?get_AllFilter(State)) of
- {[],_} when ?is_ANDOP(State) ->
- {noreply, State};
- {[],Failed} ->
- forward(seq, ?get_MyAdmin(State), State, Failed, 'MATCH', OE_THIS);
- {Passed, _} when ?is_ANDOP(State) ->
- forward(seq, ?get_MyAdmin(State), State, Passed, 'MATCH', OE_THIS);
- {Passed, []} ->
- forward(seq, ?get_MyChannel(State), State, Passed, 'MATCHED', OE_THIS);
- {Passed, Failed} ->
- %% Is OR, send Passed to channel and Failed to Admin.
- forward(seq, ?get_MyChannel(State), State, Passed, 'MATCHED', OE_THIS),
- forward(seq, ?get_MyAdmin(State), State, Failed, 'MATCH', OE_THIS)
- end;
-push_structured_events(_,_,_,_) ->
- corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}).
-
-%%----- Inherit from CosNotifyComm::StructuredPushConsumer --
-%%----------------------------------------------------------%
-%% function : disconnect_structured_push_consumer
-%% Arguments: -
-%% Returns : ok
-%%-----------------------------------------------------------
-disconnect_structured_push_consumer(_OE_THIS, _OE_FROM, State) ->
- {stop, normal, ok, ?set_Unconnected(State)}.
-
-%%----------------------------------------------------------%
-%% function : push_structured_event
-%% Arguments: CosNotification::StructuredEvent
-%% Returns : ok |
-%%-----------------------------------------------------------
-push_structured_event(OE_THIS, OE_FROM, State, Event) when ?is_STRUCTURED(State) ->
- corba:reply(OE_FROM, ok),
- case {?not_isConvertedAny(Event),
- cosNotification_eventDB:filter_events([Event], ?get_AllFilter(State))} of
- {_, {[],_}} when ?is_ANDOP(State) ->
- {noreply, State};
- {true, {[],[_]}} ->
- %% Is OR and converted, change back and forward to Admin
- forward(any, ?get_MyAdmin(State), State,
- Event#'CosNotification_StructuredEvent'.remainder_of_body,
- 'MATCH', OE_THIS);
- {_, {[],[_]}} ->
- %% Is OR and not converted, forward to Admin
- forward(seq, ?get_MyAdmin(State), State, [Event], 'MATCH', OE_THIS);
- {true, {[_],_}} when ?is_ANDOP(State) ->
- %% Is AND and converted, change back and forward to Admin
- forward(any, ?get_MyAdmin(State), State,
- Event#'CosNotification_StructuredEvent'.remainder_of_body,
- 'MATCH', OE_THIS);
- {true, {[_],_}} ->
- %% Is OR and converted, change back and forward to Channel
- forward(any, ?get_MyChannel(State), State,
- Event#'CosNotification_StructuredEvent'.remainder_of_body,
- 'MATCHED', OE_THIS);
- {_, {[_],_}} when ?is_ANDOP(State) ->
- %% Is AND and not converted, forward to Admin
- forward(seq, ?get_MyAdmin(State), State, [Event], 'MATCH', OE_THIS);
- _ ->
- %% Is OR and not converted, forward to Channel
- forward(seq, ?get_MyChannel(State), State, [Event], 'MATCHED', OE_THIS)
- end;
-push_structured_event(_,_,_,_) ->
- corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}).
-
-%%--------------- LOCAL FUNCTIONS ----------------------------
-find_obj({value, {_, Obj}}) -> Obj;
-find_obj(_) -> {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}}.
-
-find_ids(List) -> find_ids(List, []).
-find_ids([], Acc) -> Acc;
-find_ids([{I,_}|T], Acc) -> find_ids(T, [I|Acc]);
-find_ids(What, _) ->
- orber:dbg("[~p] PusherConsumer:find_ids();~n"
- "Id corrupt: ~p", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}).
-
-%% Delete a single object.
-%% The list don not differ, i.e., no filter removed, raise exception.
-delete_obj(List,List) -> corba:raise(#'CosNotifyFilter_FilterNotFound'{});
-delete_obj(List,_) -> List.
-
-%% Forward events
-forward(any, SendTo, State, Event, Status, OE_THIS) ->
- case catch oe_CosNotificationComm_Event:callAny(SendTo, Event, Status) of
- ok ->
- ?DBG("PROXY FORWARD ANY: ~p~n",[Event]),
- {noreply, State};
- {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') orelse
- is_record(E, 'NO_PERMISSION') orelse
- is_record(E, 'CosEventComm_Disconnected') ->
- orber:dbg("[~p] PusherConsumer:forward();~n"
- "Admin/Channel no longer exists; terminating and dropping: ~p",
- [?LINE, Event], ?DEBUG_LEVEL),
- 'CosNotification_Common':notify([{proxy, OE_THIS},
- {client, ?get_Client(State)},
- {reason, {'EXCEPTION', E}}]),
- {stop, normal, State};
- R when ?is_PersistentConnection(State) ->
- orber:dbg("[~p] PusherConsumer:forward();~n"
- "Admin/Channel respond incorrect: ~p~n"
- "Dropping: ~p", [?LINE, R, Event], ?DEBUG_LEVEL),
- {noreply, State};
- R ->
- orber:dbg("[~p] PusherConsumer:forward();~n"
- "Admin/Channel respond incorrect: ~p~n"
- "Terminating and dropping: ~p",
- [?LINE, R, Event], ?DEBUG_LEVEL),
- 'CosNotification_Common':notify([{proxy, OE_THIS},
- {client, ?get_Client(State)},
- {reason, R}]),
- {stop, normal, State}
- end;
-forward(seq, SendTo, State, Event, Status, OE_THIS) ->
- case catch oe_CosNotificationComm_Event:callSeq(SendTo, Event, Status) of
- ok ->
- {noreply, State};
- {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') orelse
- is_record(E, 'NO_PERMISSION') orelse
- is_record(E, 'CosEventComm_Disconnected') ->
- ?DBG("ADMIN NO LONGER EXIST; DROPPING: ~p~n", [Event]),
- 'CosNotification_Common':notify([{proxy, OE_THIS},
- {client, ?get_Client(State)},
- {reason, {'EXCEPTION', E}}]),
- {stop, normal, State};
- R when ?is_PersistentConnection(State) ->
- orber:dbg("[~p] PusherConsumer:forward();~n"
- "Admin/Channel respond incorrect: ~p~n"
- "Dropping: ~p", [?LINE, R, Event], ?DEBUG_LEVEL),
- {noreply, State};
- R ->
- orber:dbg("[~p] PusherConsumer:forward();~n"
- "Admin/Channel respond incorrect: ~p~n"
- "Terminating and dropping: ~p",
- [?LINE, R, Event], ?DEBUG_LEVEL),
- 'CosNotification_Common':notify([{proxy, OE_THIS},
- {client, ?get_Client(State)},
- {reason, R}]),
- {stop, normal, State}
- end.
-
-%%--------------- MISC FUNCTIONS, E.G. DEBUGGING -------------
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/cosNotification/src/PusherSupplier_impl.erl b/lib/cosNotification/src/PusherSupplier_impl.erl
deleted file mode 100644
index d3e44f3ef9..0000000000
--- a/lib/cosNotification/src/PusherSupplier_impl.erl
+++ /dev/null
@@ -1,1053 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : PusherSupplier_impl.erl
-%% Purpose :
-%%----------------------------------------------------------------------
-
--module('PusherSupplier_impl').
-
-
-%%--------------- INCLUDES -----------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
-%% cosEvent files.
--include_lib("cosEvent/include/CosEventChannelAdmin.hrl").
--include_lib("cosEvent/include/CosEventComm.hrl").
-%% Application files
--include("CosNotification.hrl").
--include("CosNotifyChannelAdmin.hrl").
--include("CosNotifyComm.hrl").
--include("CosNotifyFilter.hrl").
-
--include("CosNotification_Definitions.hrl").
-
-%%--------------- EXPORTS ------------------------------------
-%%--------------- External -----------------------------------
-%%----- CosNotifyChannelAdmin::ProxyPushSupplier -------------
--export([connect_any_push_consumer/4]).
-
-%%----- CosNotifyChannelAdmin::StructuredProxyPushSupplier ---
--export([connect_structured_push_consumer/4]).
-
-%%----- CosNotifyChannelAdmin::SequenceProxyPushSupplier -----
--export([connect_sequence_push_consumer/4]).
-
-%%----- CosNotifyChannelAdmin::*ProxyPushSupplier ------------
--export([suspend_connection/3,
- resume_connection/3]).
-
-%%----- Inherit from CosNotifyChannelAdmin::ProxySupplier ----
--export([obtain_offered_types/4,
- validate_event_qos/4]).
-
-%%----- Inherit from CosNotification::QoSAdmin ---------------
--export([get_qos/3,
- set_qos/4,
- validate_qos/4]).
-
-%%----- Inherit from CosNotifyComm::NotifySubscribe ----------
--export([subscription_change/5]).
-
-%%----- Inherit from CosNotifyFilter::FilterAdmin ------------
--export([add_filter/4,
- remove_filter/4,
- get_filter/4,
- get_all_filters/3,
- remove_all_filters/3]).
-
-%%----- Inherit from CosEventComm::PushSupplier -------------
--export([disconnect_push_supplier/3]).
-
-%%----- Inherit from CosNotifyComm::StructuredPushSupplier --
--export([disconnect_structured_push_supplier/3]).
-
-%%----- Inherit from CosNotifyComm::SequencePushSupplier ----
--export([disconnect_sequence_push_supplier/3]).
-
-%%----- Inherit from CosEventChannelAdmin::ProxyPushSupplier
--export([connect_push_consumer/4]).
-
-%% Attributes (external) CosNotifyChannelAdmin::ProxySupplier
--export(['_get_MyType'/3,
- '_get_MyAdmin'/3,
- '_get_priority_filter'/3,
- '_set_priority_filter'/4,
- '_get_lifetime_filter'/3,
- '_set_lifetime_filter'/4]).
-
-%%--------------- Internal -----------------------------------
-%%----- Inherit from cosNotificationComm ---------------------
--export([callAny/5,
- callSeq/5]).
-
-%%--------------- gen_server specific exports ----------------
--export([handle_info/2, code_change/3]).
--export([init/1, terminate/2]).
-
-%%--------------- LOCAL DEFINITIONS --------------------------
-%% Data structures
--record(state, {myType,
- myAdmin,
- myAdminPid,
- myChannel,
- myFilters = [],
- myOperator,
- idCounter = 0,
- prioFil,
- lifetFil,
- client,
- qosGlobal,
- qosLocal,
- suspended = false,
- pacingTimer,
- subscribeType = false,
- subscribeData = true,
- etsR,
- eventDB,
- this,
- maxCache,
- cacheTimeout,
- cacheInterval}).
-
-%% Data structures constructors
--define(get_InitState(_MyT, _MyA, _MyAP, _QS, _LQS, _Ch, _MyOp, _GT, _GL, _TR),
- #state{myType = _MyT,
- myAdmin = _MyA,
- myAdminPid= _MyAP,
- qosGlobal = _QS,
- qosLocal = _LQS,
- myChannel = _Ch,
- myOperator=_MyOp,
- etsR = ets:new(oe_ets, [set, protected]),
- eventDB = cosNotification_eventDB:create_db(_LQS, _GT, _GL, _TR),
- maxCache = cosNotificationApp:max_events()}).
-
-%% Data structures selectors
-%%-------------- Data structures selectors -----------------
-%% Attributes
--define(get_MyType(S), S#state.myType).
--define(get_MyAdmin(S), S#state.myAdmin).
--define(get_MyAdminPid(S), S#state.myAdminPid).
--define(get_MyChannel(S), S#state.myChannel).
--define(get_MyOperator(S), S#state.myOperator).
--define(get_PrioFil(S), S#state.prioFil).
--define(get_LifeTFil(S), S#state.lifetFil).
-%% Client Object
--define(get_Client(S), S#state.client).
-%% QoS
--define(get_GlobalQoS(S), S#state.qosGlobal).
--define(get_LocalQoS(S), S#state.qosLocal).
--define(get_BothQoS(S), {S#state.qosGlobal, S#state.qosLocal}).
-%% Filters
--define(get_Filter(S, I), find_obj(lists:keysearch(I, 1, S#state.myFilters))).
--define(get_AllFilter(S), S#state.myFilters).
--define(get_AllFilterID(S), find_ids(S#state.myFilters)).
-%% Amin
--define(get_PacingTimer(S), S#state.pacingTimer).
--define(get_PacingInterval(S), round(?not_GetPacingInterval((S#state.qosLocal))/10000000)).
--define(get_BatchLimit(S), ?not_GetMaximumBatchSize((S#state.qosLocal))).
-%% Subscribe
--define(get_AllSubscribe(S), lists:flatten(ets:match(S#state.etsR,
- {'$1',subscribe}))).
--define(get_SubscribeType(S), S#state.subscribeType).
--define(get_SubscribeData(S), S#state.subscribeData).
-%% ID
--define(get_IdCounter(S), S#state.idCounter).
--define(get_SubscribeDB(S), S#state.etsR).
-%% Event
--define(is_PersistentConnection(S),
- (?not_GetConnectionReliability((S#state.qosLocal)) == ?not_Persistent)).
--define(is_PersistentEvent(S),
- (?not_GetEventReliability((S#state.qosLocal)) == ?not_Persistent)).
-
--define(get_Event(S), cosNotification_eventDB:get_event(S#state.eventDB,
- false)).
-% (not ?is_PersistentEvent(S)))).
--define(get_Events(S,M), cosNotification_eventDB:get_events(S#state.eventDB, M, false)).
-% (not ?is_PersistentEvent(S)))).
-
-%%-------------- Data structures modifiers -----------------
-%% Attributes
--define(set_PrioFil(S,D), S#state{prioFil=D}).
--define(set_LifeTFil(S,D), S#state{lifetFil=D}).
-%% Client Object
--define(set_Client(S,D), S#state{client=D}).
--define(del_Client(S), S#state{client=undefined}).
--define(set_Unconnected(S), S#state{client=undefined}).
--define(set_Suspended(S), S#state{suspended=true}).
--define(set_NotSuspended(S), S#state{suspended=false}).
-%% QoS
--define(set_LocalQoS(S,D), S#state{qosLocal=D}).
--define(set_GlobalQoS(S,D), S#state{qosGlobal=D}).
--define(set_BothQoS(S,GD,LD), S#state{qosGlobal=GD, qosLocal=LD}).
-%% Filters
--define(add_Filter(S,I,O), S#state{myFilters=[{I,O}|S#state.myFilters]}).
--define(del_Filter(S,I), S#state{myFilters=
- delete_obj(lists:keydelete(I, 1, S#state.myFilters),
- S#state.myFilters)}).
--define(del_AllFilter(S), S#state{myFilters=[]}).
-%% Admin
--define(set_PacingTimer(S,T), S#state{pacingTimer=T}).
-%% Publish
-%% Subscribe
--define(add_Subscribe(S,E), ets:insert(S#state.etsR, {E, subscribe})).
--define(del_Subscribe(S,E), ets:delete(S#state.etsR, E)).
--define(set_SubscribeType(S,T), S#state{subscribeType=T}).
--define(set_SubscribeData(S,D), S#state{subscribeData=D}).
-%% ID
--define(set_IdCounter(S,V), S#state{idCounter=V}).
--define(new_Id(S), 'CosNotification_Common':create_id(S#state.idCounter)).
-%% Events
--define(add_Event(S,E), catch cosNotification_eventDB:
- add_event(S#state.eventDB, E, S#state.lifetFil, S#state.prioFil)).
--define(addAndGet_Event(S,E), catch cosNotification_eventDB:
- add_and_get_event(S#state.eventDB, E, S#state.lifetFil, S#state.prioFil,
- false)).
-% ?is_PersistentEvent(S))).
--define(update_EventDB(S,Q), S#state{eventDB=
- cosNotification_eventDB:update(S#state.eventDB, Q)}).
-
-
-%%-------------- MISC ----------------------------------------
--define(is_ANY(S), S#state.myType == 'PUSH_ANY').
--define(is_STRUCTURED(S), S#state.myType == 'PUSH_STRUCTURED').
--define(is_SEQUENCE(S), S#state.myType == 'PUSH_SEQUENCE').
--define(is_ANDOP(S), S#state.myOperator == 'AND_OP').
--define(is_UnConnected(S), S#state.client == undefined).
--define(is_Connected(S), S#state.client =/= undefined).
--define(is_Suspended(S), S#state.suspended == true).
--define(is_NotSuspended(S), S#state.suspended == false).
--define(is_BatchLimitReached(S), cosNotification_eventDB:status(S#state.eventDB,
- {batchLimit,
- ?not_GetMaximumBatchSize((S#state.qosLocal))})).
--define(has_Filters(S), S#state.myFilters =/= []).
-
-%%----------------------------------------------------------%
-%% function : handle_info, code_change
-%% Arguments:
-%% Returns :
-%% Effect : Functions demanded by the gen_server module.
-%%-----------------------------------------------------------
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-handle_info(Info, #state{cacheTimeout = Timeout,
- cacheInterval = Interval} = State) ->
- ?DBG("INFO: ~p~n", [Info]),
- case Info of
- {'EXIT', Pid, Reason} when ?get_MyAdminPid(State)==Pid ->
- ?DBG("PARENT ADMIN: ~p TERMINATED.~n",[Reason]),
- {stop, Reason, State};
- {'EXIT', _Pid, _Reason} ->
- ?DBG("PROXYPUSHSUPPLIER: ~p TERMINATED.~n",[_Reason]),
- {noreply, State};
- pacing ->
- lookup_and_push(State, true);
- cacheInterval ->
- lookup_and_push(State, true);
- cacheTimeout when Timeout == undefined, Interval == undefined ->
- %% Late message, do not terminate
- {noreply, State};
- cacheTimeout ->
- 'CosNotification_Common':notify([{proxy, State#state.this},
- {client, State#state.client},
- {reason,
- {timer, "Reached upper limit"}}]),
- {stop, normal, State};
- _ ->
- {noreply, State}
- end.
-
-%%----------------------------------------------------------%
-%% function : init, terminate
-%% Arguments:
-%%-----------------------------------------------------------
-
-init([MyType, MyAdmin, MyAdminPid, InitQoS, LQS, MyChannel, Options, Operator]) ->
- process_flag(trap_exit, true),
- GCTime = 'CosNotification_Common':get_option(gcTime, Options,
- ?not_DEFAULT_SETTINGS),
- GCLimit = 'CosNotification_Common':get_option(gcLimit, Options,
- ?not_DEFAULT_SETTINGS),
- TimeRef = 'CosNotification_Common':get_option(timeService, Options,
- ?not_DEFAULT_SETTINGS),
- timer:start(),
- {ok, ?get_InitState(MyType, MyAdmin, MyAdminPid,
- InitQoS, LQS, MyChannel, Operator, GCTime, GCLimit, TimeRef)}.
-
-terminate(_Reason, State) when ?is_UnConnected(State) ->
- stop_timer(State#state.cacheTimeout),
- stop_timer(State#state.cacheInterval),
- stop_timer(State#state.pacingTimer),
- %% We are not connected to a Client. Hence, no need to invoke disconnect.
- ok;
-terminate(_Reason, State) when ?is_ANY(State) ->
- stop_timer(State#state.cacheTimeout),
- stop_timer(State#state.cacheInterval),
- stop_timer(State#state.pacingTimer),
- 'CosNotification_Common':disconnect('CosEventComm_PushConsumer',
- disconnect_push_consumer,
- ?get_Client(State));
-terminate(_Reason, State) when ?is_SEQUENCE(State) ->
- stop_timer(State#state.cacheTimeout),
- stop_timer(State#state.cacheInterval),
- stop_timer(State#state.pacingTimer),
- 'CosNotification_Common':disconnect('CosNotifyComm_SequencePushConsumer',
- disconnect_sequence_push_consumer,
- ?get_Client(State));
-terminate(_Reason, State) when ?is_STRUCTURED(State) ->
- stop_timer(State#state.cacheTimeout),
- stop_timer(State#state.cacheInterval),
- stop_timer(State#state.pacingTimer),
- 'CosNotification_Common':disconnect('CosNotifyComm_StructuredPushConsumer',
- disconnect_structured_push_consumer,
- ?get_Client(State)).
-
-%%-----------------------------------------------------------
-%%----- CosNotifyChannelAdmin_ProxySupplier attributes ------
-%%-----------------------------------------------------------
-%%----------------------------------------------------------%
-%% Attribute: '_get_MyType'
-%% Type : readonly
-%% Returns :
-%%-----------------------------------------------------------
-'_get_MyType'(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_MyType(State), State}.
-
-%%----------------------------------------------------------%
-%% Attribute: '_get_MyAdmin'
-%% Type : readonly
-%% Returns :
-%%-----------------------------------------------------------
-'_get_MyAdmin'(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_MyAdmin(State), State}.
-
-%%----------------------------------------------------------%
-%% Attribute: '_*et_priority_filter'
-%% Type : read/write
-%% Returns :
-%%-----------------------------------------------------------
-'_get_priority_filter'(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_PrioFil(State), State}.
-'_set_priority_filter'(_OE_THIS, _OE_FROM, State, PrioF) ->
- {reply, ok, ?set_PrioFil(State, PrioF)}.
-
-%%----------------------------------------------------------%
-%% Attribute: '_*et_lifetime_filter'
-%% Type : read/write
-%% Returns :
-%%-----------------------------------------------------------
-'_get_lifetime_filter'(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_LifeTFil(State), State}.
-'_set_lifetime_filter'(_OE_THIS, _OE_FROM, State, LifeTF) ->
- {reply, ok, ?set_LifeTFil(State, LifeTF)}.
-
-%%-----------------------------------------------------------
-%%------- Exported external functions -----------------------
-%%-----------------------------------------------------------
-%%----- CosEventChannelAdmin::ProxyPushSupplier -------------
-%%----------------------------------------------------------%
-%% function : connect_push_consumer
-%% Arguments: Client - CosEventComm::PushConsumer
-%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} |
-%% {'EXCEPTION', #'TypeError'{}}
-%% Both exceptions from CosEventChannelAdmin!!!!
-%%-----------------------------------------------------------
-connect_push_consumer(OE_THIS, OE_FROM, State, Client) ->
- connect_any_push_consumer(OE_THIS, OE_FROM, State, Client).
-
-%%----- CosNotifyChannelAdmin::ProxyPushSupplier ------------
-%%----------------------------------------------------------%
-%% function : connect_any_push_consumer
-%% Arguments: Client - CosEventComm::PushConsumer
-%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} |
-%% {'EXCEPTION', #'TypeError'{}}
-%% Both exceptions from CosEventChannelAdmin!!!!
-%%-----------------------------------------------------------
-connect_any_push_consumer(OE_THIS, _OE_FROM, State, Client) when ?is_ANY(State) ->
- 'CosNotification_Common':type_check(Client, 'CosEventComm_PushConsumer'),
- if
- ?is_Connected(State) ->
- corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{});
- true ->
- {reply, ok, State#state{client = Client, this = OE_THIS}}
- end;
-connect_any_push_consumer(_, _, _, _) ->
- corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}).
-
-%%----- CosNotifyChannelAdmin::SequenceProxyPushSupplier ----
-%%----------------------------------------------------------%
-%% function : connect_sequence_push_consumer
-%% Arguments: Client - CosNotifyComm::SequencePushConsumer
-%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} |
-%% {'EXCEPTION', #'TypeError'{}}
-%%-----------------------------------------------------------
-connect_sequence_push_consumer(OE_THIS, _OE_FROM, State, Client) when ?is_SEQUENCE(State) ->
- 'CosNotification_Common':type_check(Client,
- 'CosNotifyComm_SequencePushConsumer'),
- if
- ?is_Connected(State) ->
- corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{});
- true ->
- NewState = start_timer(State),
- {reply, ok, NewState#state{client = Client, this = OE_THIS}}
- end;
-connect_sequence_push_consumer(_, _, _, _) ->
- corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}).
-
-%%----- CosNotifyChannelAdmin::StructuredProxyPushSupplier ---
-%%----------------------------------------------------------%
-%% function : connect_structured_push_consumer
-%% Arguments: Client - CosNotifyComm::StructuredPushConsumer
-%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} |
-%% {'EXCEPTION', #'TypeError'{}}
-%%-----------------------------------------------------------
-connect_structured_push_consumer(OE_THIS, _OE_FROM, State, Client) when ?is_STRUCTURED(State) ->
- 'CosNotification_Common':type_check(Client,
- 'CosNotifyComm_StructuredPushConsumer'),
- if
- ?is_Connected(State) ->
- corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{});
- true ->
- {reply, ok, State#state{client = Client, this = OE_THIS}}
- end;
-connect_structured_push_consumer(_, _, _, _) ->
- corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}).
-
-%%----- CosNotifyChannelAdmin::*ProxyPushSupplier -----------
-%%----------------------------------------------------------%
-%% function : suspend_connection
-%% Arguments:
-%% Returns : ok | {'EXCEPTION', #'ConnectionAlreadyInactive'{}} |
-%% {'EXCEPTION', #'NotConneced'{}}
-%%-----------------------------------------------------------
-suspend_connection(_OE_THIS, _OE_FROM, State) when ?is_Connected(State) ->
- if
- ?is_Suspended(State) ->
- corba:raise(#'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{});
- true ->
- stop_timer(State#state.pacingTimer),
- {reply, ok, State#state{pacingTimer = undefined,
- suspended=true}}
- end;
-suspend_connection(_,_,_)->
- corba:raise(#'CosNotifyChannelAdmin_NotConnected'{}).
-
-%%----------------------------------------------------------%
-%% function : resume_connection
-%% Arguments:
-%% Returns : ok | {'EXCEPTION', #'ConnectionAlreadyActive'{}} |
-%% {'EXCEPTION', #'NotConneced'{}}
-%%-----------------------------------------------------------
-resume_connection(_OE_THIS, OE_FROM, State) when ?is_Connected(State) ->
- if
- ?is_NotSuspended(State) ->
- corba:raise(#'CosNotifyChannelAdmin_ConnectionAlreadyActive'{});
- true ->
- corba:reply(OE_FROM, ok),
- if
- ?is_SEQUENCE(State) ->
- start_timer(State);
- true ->
- ok
- end,
- lookup_and_push(?set_NotSuspended(State))
- end;
-resume_connection(_,_,_) ->
- corba:raise(#'CosNotifyChannelAdmin_NotConnected'{}).
-
-%%----- Inherit from CosNotifyChannelAdmin::ProxySupplier ---
-%%----------------------------------------------------------%
-%% function : obtain_offered_types
-%% Arguments: Mode - enum 'ObtainInfoMode' (CosNotifyChannelAdmin)
-%% Returns : CosNotification::EventTypeSeq
-%%-----------------------------------------------------------
-obtain_offered_types(_OE_THIS, _OE_FROM, State, 'ALL_NOW_UPDATES_OFF') ->
- {reply, ?get_AllSubscribe(State), ?set_SubscribeType(State, false)};
-obtain_offered_types(_OE_THIS, _OE_FROM, State, 'ALL_NOW_UPDATES_ON') ->
- {reply, ?get_AllSubscribe(State), ?set_SubscribeType(State, true)};
-obtain_offered_types(_OE_THIS, _OE_FROM, State, 'NONE_NOW_UPDATES_OFF') ->
- {reply, [], ?set_SubscribeType(State, false)};
-obtain_offered_types(_OE_THIS, _OE_FROM, State, 'NONE_NOW_UPDATES_ON') ->
- {reply, [], ?set_SubscribeType(State, true)};
-obtain_offered_types(_,_,_,What) ->
- orber:dbg("[~p] PusherSupplier:obtain_offered_types(~p);~n"
- "Bad enumerant", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------%
-%% function : validate_event_qos
-%% Arguments: RequiredQoS - CosNotification::QoSProperties
-%% Returns : ok | {'EXCEPTION', #'UnsupportedQoS'{}}
-%% AvilableQoS - CosNotification::NamedPropertyRangeSeq (out)
-%%-----------------------------------------------------------
-validate_event_qos(_OE_THIS, _OE_FROM, State, RequiredQoS) ->
- AvilableQoS = 'CosNotification_Common':validate_event_qos(RequiredQoS,
- ?get_LocalQoS(State)),
- {reply, {ok, AvilableQoS}, State}.
-
-%%----- Inherit from CosNotification::QoSAdmin --------------
-%%----------------------------------------------------------%
-%% function : get_qos
-%% Arguments:
-%% Returns :
-%%-----------------------------------------------------------
-get_qos(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_GlobalQoS(State), State}.
-
-%%----------------------------------------------------------%
-%% function : set_qos
-%% Arguments: QoS - CosNotification::QoSProperties, i.e.,
-%% [#'Property'{name, value}, ...] where name eq. string()
-%% and value eq. any().
-%% Returns : ok | {'EXCEPTION', CosNotification::UnsupportedQoS}
-%%-----------------------------------------------------------
-set_qos(_OE_THIS, _OE_FROM, State, QoS) ->
- {NewQoS, LQS} = 'CosNotification_Common':set_qos(QoS, ?get_BothQoS(State),
- proxy, ?get_MyAdmin(State),
- false),
- NewState = ?update_EventDB(State, LQS),
- {reply, ok, ?set_BothQoS(NewState, NewQoS, LQS)}.
-
-%%----------------------------------------------------------%
-%% function : validate_qos
-%% Arguments: Required_qos - CosNotification::QoSProperties
-%% [#'Property'{name, value}, ...] where name eq. string()
-%% and value eq. any().
-%% Returns : {'EXCEPTION', CosNotification::UnsupportedQoS}
-%% {ok, CosNotification::NamedPropertyRangeSeq}
-%%-----------------------------------------------------------
-validate_qos(_OE_THIS, _OE_FROM, State, Required_qos) ->
- QoS = 'CosNotification_Common':validate_qos(Required_qos, ?get_BothQoS(State),
- proxy, ?get_MyAdmin(State),
- false),
- {reply, {ok, QoS}, State}.
-
-%%----- Inherit from CosNotifyComm::NotifySubscribe ---------
-%%----------------------------------------------------------%
-%% function : subscription_change
-%% Arguments: Added - #'CosNotification_EventType'{}
-%% Removed - #'CosNotification_EventType'{}
-%% Returns : ok |
-%% {'EXCEPTION', #'CosNotifyComm_InvalidEventType'{}}
-%%-----------------------------------------------------------
-subscription_change(_OE_THIS, _OE_FROM, State, Added, Removed) ->
- cosNotification_Filter:validate_types(Added),
- cosNotification_Filter:validate_types(Removed),
- %% On this "side", we care about which type of events the client
- %% will require, since the client (or an agent) clearly stated
- %% that it's only interested in these types of events.
- %% Also see PusherConsumer- and PullerConsumer-'offer_change'.
- update_subscribe(remove, State, Removed),
- CurrentSub = ?get_AllSubscribe(State),
- NewState =
- case cosNotification_Filter:check_types(Added++CurrentSub) of
- true ->
- %% Types supplied does in some way cause all events to be valid.
- %% Smart? Would have been better to not supply any at all.
- ?set_SubscribeData(State, true);
- {ok, Which, WC} ->
- ?set_SubscribeData(State, {Which, WC})
- end,
- update_subscribe(add, NewState, Added),
- case ?get_SubscribeType(NewState) of
- true ->
- %% Perhaps we should handle exception here?!
- %% Probably not. Better to stay "on-line".
- catch 'CosNotifyComm_NotifyPublish':
- offer_change(?get_Client(NewState), Added, Removed),
- ok;
- _->
- ok
- end,
- {reply, ok, NewState}.
-
-update_subscribe(_, _, [])->
- ok;
-update_subscribe(add, State, [H|T]) ->
- ?add_Subscribe(State, H),
- update_subscribe(add, State, T);
-update_subscribe(remove, State, [H|T]) ->
- ?del_Subscribe(State, H),
- update_subscribe(remove, State, T).
-
-%%----- Inherit from CosNotifyFilter::FilterAdmin -----------
-%%----------------------------------------------------------%
-%% function : add_filter
-%% Arguments: Filter - CosNotifyFilter::Filter
-%% Returns : FilterID - long
-%%-----------------------------------------------------------
-add_filter(_OE_THIS, _OE_FROM, State, Filter) ->
- 'CosNotification_Common':type_check(Filter, 'CosNotifyFilter_Filter'),
- FilterID = ?new_Id(State),
- NewState = ?set_IdCounter(State, FilterID),
- {reply, FilterID, ?add_Filter(NewState, FilterID, Filter)}.
-
-%%----------------------------------------------------------%
-%% function : remove_filter
-%% Arguments: FilterID - long
-%% Returns : ok
-%%-----------------------------------------------------------
-remove_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) ->
- {reply, ok, ?del_Filter(State, FilterID)};
-remove_filter(_,_,_,What) ->
- orber:dbg("[~p] PusherSupplier:remove_filter(~p); Not an integer",
- [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------%
-%% function : get_filter
-%% Arguments: FilterID - long
-%% Returns : Filter - CosNotifyFilter::Filter |
-%% {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}}
-%%-----------------------------------------------------------
-get_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) ->
- {reply, ?get_Filter(State, FilterID), State};
-get_filter(_,_,_,What) ->
- orber:dbg("[~p] PusherSupplier:get_filter(~p); Not an integer",
- [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------%
-%% function : get_all_filters
-%% Arguments: -
-%% Returns : Filter - CosNotifyFilter::FilterIDSeq
-%%-----------------------------------------------------------
-get_all_filters(_OE_THIS, _OE_FROM, State) ->
- {reply, ?get_AllFilterID(State), State}.
-
-%%----------------------------------------------------------%
-%% function : remove_all_filters
-%% Arguments: -
-%% Returns : ok
-%%-----------------------------------------------------------
-remove_all_filters(_OE_THIS, _OE_FROM, State) ->
- {reply, ok, ?del_AllFilter(State)}.
-
-
-%%----- Inherit from CosEventComm::PushSupplier -------------
-%%----------------------------------------------------------%
-%% function : disconnect_push_supplier
-%% Arguments: -
-%% Returns : ok
-%%-----------------------------------------------------------
-disconnect_push_supplier(_OE_THIS, _OE_FROM, State) ->
- {stop, normal, ok, ?set_Unconnected(State)}.
-
-%%----- Inherit from CosNotifyComm::StructuredPushSupplier --
-%%----------------------------------------------------------%
-%% function : disconnect_structured_push_supplier
-%% Arguments: -
-%% Returns : ok
-%%-----------------------------------------------------------
-disconnect_structured_push_supplier(_OE_THIS, _OE_FROM, State) ->
- {stop, normal, ok, ?set_Unconnected(State)}.
-
-%%----- Inherit from CosNotifyComm::SequencePushSupplier ----
-%%----------------------------------------------------------%
-%% function : disconnect_sequence_push_supplier
-%% Arguments: -
-%% Returns : ok
-%%-----------------------------------------------------------
-disconnect_sequence_push_supplier(_OE_THIS, _OE_FROM, State) ->
- {stop, normal, ok, ?set_Unconnected(State)}.
-
-%%--------------- LOCAL FUNCTIONS ----------------------------
-find_obj({value, {_, Obj}}) -> Obj;
-find_obj(_) -> {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}}.
-
-find_ids(List) -> find_ids(List, []).
-find_ids([], Acc) -> Acc;
-find_ids([{I,_}|T], Acc) -> find_ids(T, [I|Acc]);
-find_ids(What, _) ->
- orber:dbg("[~p] PusherSupplier:find_ids();~n"
- "Id corrupt: ~p", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}).
-
-%% Delete a single object.
-%% The list do not differ, i.e., no filter removed, raise exception.
-delete_obj(List,List) -> corba:raise(#'CosNotifyFilter_FilterNotFound'{});
-delete_obj(List,_) -> List.
-
-%%-----------------------------------------------------------
-%% function : callSeq
-%% Arguments:
-%% Returns :
-%%-----------------------------------------------------------
-callSeq(_OE_THIS, OE_FROM, State, EventsIn, Status) ->
- corba:reply(OE_FROM, ok),
- case cosNotification_eventDB:validate_event(?get_SubscribeData(State), EventsIn,
- ?get_AllFilter(State),
- ?get_SubscribeDB(State),
- Status) of
- {[],_} ->
- ?DBG("PROXY NOSUBSCRIPTION SEQUENCE/STRUCTURED: ~p~n",[EventsIn]),
- {noreply, State};
- {Events,_} when ?is_Suspended(State) ->
- store_events(State, Events),
- {noreply, State};
- {Events,_} when ?is_UnConnected(State) ->
- orber:dbg("[~p] PusherSupplier:callAny();~n"
- "Not connected, dropping event(s): ~p",
- [?LINE, Events], ?DEBUG_LEVEL),
- {noreply, State};
- {[Event],_} when ?is_STRUCTURED(State) ->
- ?DBG("PROXY RECEIVED SEQUENCE: ~p~n",[Event]),
- empty_db(State, ?addAndGet_Event(State, Event));
- {[Event],_} when ?is_ANY(State) ->
- ?DBG("PROXY RECEIVED SEQUENCE: ~p~n",[Event]),
- AnyEvent = any:create('CosNotification_StructuredEvent':tc(),Event),
- empty_db(State, ?addAndGet_Event(State, AnyEvent));
- {Events,_} ->
- ?DBG("PROXY RECEIVED SEQUENCE: ~p~n",[Events]),
- store_events(State, Events),
- lookup_and_push(State)
- end.
-
-%%-----------------------------------------------------------
-%% function : callAny
-%% Arguments:
-%% Returns :
-%%-----------------------------------------------------------
-callAny(_OE_THIS, OE_FROM, State, EventIn, Status) ->
- corba:reply(OE_FROM, ok),
- case cosNotification_eventDB:validate_event(?get_SubscribeData(State), EventIn,
- ?get_AllFilter(State),
- ?get_SubscribeDB(State),
- Status) of
- {[],_} ->
- ?DBG("PROXY NOSUBSCRIPTION ANY: ~p~n",[EventIn]),
- %% To be on the safe side, test if there are any events that not
- %% have been forwarded (should only be possible if StartTime is used).
- lookup_and_push(State);
- {Event,_} when ?is_Suspended(State), ?is_ANY(State) ->
- ?add_Event(State, Event),
- {noreply, State};
- {Event,_} when ?is_Suspended(State) ->
- ?add_Event(State, ?not_CreateSE("","%ANY","",[],[],Event)),
- {noreply, State};
- {Event,_} when ?is_UnConnected(State) ->
- orber:dbg("[~p] PusherSupplier:callAny();~n"
- "Not connected, dropping event: ~p",
- [?LINE, Event], ?DEBUG_LEVEL),
- {noreply, State};
- {Event,_} when ?is_ANY(State) ->
- ?DBG("PROXY RECEIVED ANY: ~p~n",[Event]),
- %% We must store the event since there may be other events that should
- %% be delivered first, e.g., higher priority.
- empty_db(State, ?addAndGet_Event(State, Event));
- {Event,_} when ?is_SEQUENCE(State) ->
- ?DBG("PROXY RECEIVED ANY==>SEQUENCE: ~p~n",[Event]),
- StrEvent = ?not_CreateSE("","%ANY","",[],[],Event),
- ?add_Event(State, StrEvent),
- lookup_and_push(State);
- {Event,_} ->
- ?DBG("PROXY RECEIVED ANY==>STRUCTURED: ~p~n",[Event]),
- StrEvent = ?not_CreateSE("","%ANY","",[],[],Event),
- empty_db(State, ?addAndGet_Event(State, StrEvent))
- end.
-
-%% Lookup and push "the correct" amount of events.
-lookup_and_push(State) ->
- %% The boolean indicates, if false, that we will only push events if we have
- %% passed the BatchLimit. If true we will ignore this limit and push events
- %% anyway (typcially invoked when pacing limit passed).
- lookup_and_push(State, false).
-lookup_and_push(State, false) when ?is_SEQUENCE(State) ->
- case ?is_BatchLimitReached(State) of
- true ->
- case ?get_Events(State, ?get_BatchLimit(State)) of
- {[], _, _} ->
- ?DBG("BATCHLIMIT (~p) REACHED BUT NO EVENTS FOUND~n",
- [?get_BatchLimit(State)]),
- {noreply, State};
- {Events, _, Keys} ->
- ?DBG("BATCHLIMIT (~p) REACHED, EVENTS FOUND: ~p~n",
- [?get_BatchLimit(State), Events]),
- case catch 'CosNotifyComm_SequencePushConsumer':
- push_structured_events(?get_Client(State), Events) of
- ok ->
- cosNotification_eventDB:delete_events(Keys),
- lookup_and_push(reset_cache(State), false);
- {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') orelse
- is_record(E, 'NO_PERMISSION') orelse
- is_record(E, 'CosEventComm_Disconnected') ->
- ?DBG("PUSH SUPPLIER CLIENT NO LONGER EXIST~n", []),
- 'CosNotification_Common':notify([{proxy, State#state.this},
- {client, ?get_Client(State)},
- {reason, {'EXCEPTION', E}}]),
- {stop, normal, State};
- What when ?is_PersistentEvent(State),
- ?is_PersistentConnection(State) ->
- orber:dbg("[~p] PusherSupplier:lookup_and_push();~n"
- "Client respond incorrect: ~p",
- [?LINE, What], ?DEBUG_LEVEL),
- check_cache(State);
- What when ?is_PersistentConnection(State) ->
- %% Here we should do something when we want to handle
- %% Persistent EventReliability.
- orber:dbg("[~p] PusherSupplier:lookup_and_push();~n"
- "Client respond incorrect: ~p~n"
- "Dropping events: ~p",
- [?LINE, What, Events], ?DEBUG_LEVEL),
- cosNotification_eventDB:delete_events(Keys),
- {noreply, State};
- WhatII ->
- orber:dbg("[~p] PusherSupplier:lookup_and_push();~n"
- "Client respond incorrect: ~p~n"
- "Terminating and dropping events: ~p",
- [?LINE, WhatII, Events], ?DEBUG_LEVEL),
- 'CosNotification_Common':notify([{proxy, State#state.this},
- {client, ?get_Client(State)},
- {reason, WhatII}]),
- {stop, normal, State}
- end
- end;
- _ ->
- ?DBG("BATCHLIMIT (~p) NOT REACHED~n",[?get_BatchLimit(State)]),
- {noreply, State}
- end;
-lookup_and_push(State, true) when ?is_SEQUENCE(State) ->
- case ?get_Events(State, ?get_BatchLimit(State)) of
- {[], _, _} ->
- ?DBG("PACELIMIT REACHED BUT NO EVENTS FOUND~n", []),
- {noreply, State};
- {Events, _, Keys} ->
- ?DBG("PACELIMIT REACHED, EVENTS FOUND: ~p~n", [Events]),
- case catch 'CosNotifyComm_SequencePushConsumer':
- push_structured_events(?get_Client(State), Events) of
- ok ->
- cosNotification_eventDB:delete_events(Keys),
- lookup_and_push(reset_cache(State), false);
- {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') orelse
- is_record(E, 'NO_PERMISSION') orelse
- is_record(E, 'CosEventComm_Disconnected') ->
- orber:dbg("[~p] PusherSupplier:lookup_and_push();~n"
- "Client no longer exists; terminating and dropping events: ~p",
- [?LINE, Events], ?DEBUG_LEVEL),
- 'CosNotification_Common':notify([{proxy, State#state.this},
- {client, ?get_Client(State)},
- {reason, {'EXCEPTION', E}}]),
- {stop, normal, State};
- What when ?is_PersistentEvent(State),
- ?is_PersistentConnection(State) ->
- orber:dbg("[~p] PusherSupplier:lookup_and_push();~n"
- "Client respond incorrect: ~p",
- [?LINE, What], ?DEBUG_LEVEL),
- check_cache(State);
- What when ?is_PersistentConnection(State) ->
- %% Here we should do something when we want to handle
- %% Persistent EventReliability.
- orber:dbg("[~p] PusherSupplier:lookup_and_push();~n"
- "Client respond incorrect: ~p~n"
- "Dropping events: ~p",
- [?LINE, What, Events], ?DEBUG_LEVEL),
- cosNotification_eventDB:delete_events(Keys),
- {noreply, State};
- WhatII ->
- orber:dbg("[~p] PusherSupplier:lookup_and_push();~n"
- "Client respond incorrect: ~p~n"
- "Terminating and dropping events: ~p",
- [?LINE, WhatII, Events], ?DEBUG_LEVEL),
- 'CosNotification_Common':notify([{proxy, State#state.this},
- {client, ?get_Client(State)},
- {reason, WhatII}]),
- {stop, normal, State}
- end
- end;
-lookup_and_push(State, _) ->
- empty_db(State, ?get_Event(State)).
-
-
-%% Push all events stored while not connected or received in sequence.
-empty_db(State, {[], _, _}) ->
- {noreply, State};
-empty_db(State, {Event, _, Keys}) when ?is_STRUCTURED(State) ->
- case catch 'CosNotifyComm_StructuredPushConsumer':
- push_structured_event(?get_Client(State), Event) of
- ok ->
- cosNotification_eventDB:delete_events(Keys),
- NewState = reset_cache(State),
- empty_db(NewState, ?get_Event(NewState));
- {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') orelse
- is_record(E, 'NO_PERMISSION') orelse
- is_record(E, 'CosEventComm_Disconnected') ->
- orber:dbg("[~p] PusherSupplier:empty_db();~n"
- "Client no longer exists; terminating and dropping: ~p",
- [?LINE, Event], ?DEBUG_LEVEL),
- 'CosNotification_Common':notify([{proxy, State#state.this},
- {client, ?get_Client(State)},
- {reason, {'EXCEPTION', E}}]),
- {stop, normal, State};
- What when ?is_PersistentEvent(State),
- ?is_PersistentConnection(State) ->
- orber:dbg("[~p] PusherSupplier:lookup_and_push();~n"
- "Client respond incorrect: ~p",
- [?LINE, What], ?DEBUG_LEVEL),
- check_cache(State);
- What when ?is_PersistentConnection(State) ->
- %% Here we should do something when we want to handle
- %% Persistent EventReliability.
- orber:dbg("[~p] PusherSupplier:empty_db();~n"
- "Client respond incorrect: ~p~n"
- "Dropping event: ~p",
- [?LINE, What, Event], ?DEBUG_LEVEL),
- cosNotification_eventDB:delete_events(Keys),
- {noreply, State};
- WhatII ->
- orber:dbg("[~p] PusherSupplier:empty_db();~n"
- "Client respond incorrect: ~p~n"
- "Terminating and dropping: ~p",
- [?LINE, WhatII, Event], ?DEBUG_LEVEL),
- 'CosNotification_Common':notify([{proxy, State#state.this},
- {client, ?get_Client(State)},
- {reason, WhatII}]),
- {stop, normal, State}
- end;
-empty_db(State, {Event, _, Keys}) when ?is_ANY(State) ->
- case catch 'CosEventComm_PushConsumer':push(?get_Client(State), Event) of
- ok ->
- cosNotification_eventDB:delete_events(Keys),
- NewState = reset_cache(State),
- empty_db(NewState, ?get_Event(NewState));
- {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') orelse
- is_record(E, 'NO_PERMISSION') orelse
- is_record(E, 'CosEventComm_Disconnected') ->
- orber:dbg("[~p] PusherSupplier:empty_db();~n"
- "Client no longer exists; terminating and dropping: ~p",
- [?LINE, Event], ?DEBUG_LEVEL),
- 'CosNotification_Common':notify([{proxy, State#state.this},
- {client, ?get_Client(State)},
- {reason, {'EXCEPTION', E}}]),
- {stop, normal, State};
- What when ?is_PersistentEvent(State),
- ?is_PersistentConnection(State) ->
- orber:dbg("[~p] PusherSupplier:lookup_and_push();~n"
- "Client respond incorrect: ~p",
- [?LINE, What], ?DEBUG_LEVEL),
- check_cache(State);
- What when ?is_PersistentConnection(State) ->
- %% Here we should do something when we want to handle
- %% Persistent EventReliability.
- orber:dbg("[~p] PusherSupplier:empty_db();~n"
- "Client respond incorrect: ~p~n"
- "Dropping Event: ~p",
- [?LINE, What, Event], ?DEBUG_LEVEL),
- cosNotification_eventDB:delete_events(Keys),
- {noreply, State};
- WhatII ->
- orber:dbg("[~p] PusherSupplier:empty_db();~n"
- "Client respond incorrect: ~p~n"
- "Terminating and dropping: ~p",
- [?LINE, WhatII, Event], ?DEBUG_LEVEL),
- 'CosNotification_Common':notify([{proxy, State#state.this},
- {client, ?get_Client(State)},
- {reason, WhatII}]),
- {stop, normal, State}
- end.
-
-reset_cache(#state{cacheTimeout = undefined,
- cacheInterval = undefined} = State) ->
- State;
-reset_cache(State) ->
- stop_timer(State#state.cacheTimeout),
- stop_timer(State#state.cacheInterval),
- State#state{cacheTimeout = undefined,
- cacheInterval = undefined}.
-
-check_cache(#state{maxCache = Max, cacheTimeout = Timeout,
- cacheInterval = Interval} = State) ->
- case cosNotification_eventDB:status(State#state.eventDB, eventCounter) of
- Count when Count > Max ->
- %% Reached the upper limit, terminate.
- 'CosNotification_Common':notify([{proxy, State#state.this},
- {client, State#state.client},
- {reason, {max_events, Max}}]),
- {stop, normal, State};
- _ when Timeout == undefined, Interval == undefined ->
- case {timer:send_interval(cosNotificationApp:interval_events(),
- cacheInterval),
- timer:send_after(cosNotificationApp:timeout_events(),
- cacheTimeout)} of
- {{ok, IntervalRef}, {ok, TimeoutRef}} ->
- {noreply, State#state{cacheTimeout = TimeoutRef,
- cacheInterval = IntervalRef}};
- Error ->
- orber:dbg("[~p] PusherSupplier:check_cache();~n"
- "Unable to start timers: ~p",
- [?LINE, Error], ?DEBUG_LEVEL),
- 'CosNotification_Common':notify([{proxy, State#state.this},
- {client, State#state.client},
- {reason, {timer, Error}}]),
- {stop, normal, State}
- end;
- _ ->
- %% Timers already started.
- {noreply, State}
- end.
-
-store_events(_State, []) ->
- ok;
-store_events(State, [Event|Rest]) when ?is_ANY(State) ->
- AnyEvent = any:create('CosNotification_StructuredEvent':tc(),Event),
- ?add_Event(State, AnyEvent),
- store_events(State, Rest);
-store_events(State, [Event|Rest]) ->
- ?add_Event(State, Event),
- store_events(State, Rest).
-
-%% Start timers which send a message each time we should push events. Only used
-%% when this objects is defined to supply sequences.
-start_timer(State) ->
- case ?get_PacingInterval(State) of
- 0 ->
- ?DBG("PUSH SUPPLIER STARTED NO TIMER (0), BATCH LIMIT: ~p~n",
- [?get_BatchLimit(State)]),
-
- State;
- PacInt ->
- case catch timer:send_interval(timer:seconds(PacInt), pacing) of
- {ok,PacTRef} ->
- ?DBG("PUSH SUPPLIER STARTED TIMER, BATCH LIMIT: ~p~n",
- [?get_BatchLimit(State)]),
- ?set_PacingTimer(State, PacTRef);
- What ->
- orber:dbg("[~p] PusherSupplier:start_timer();~n"
- "Unable to invoke timer:send_interval/2: ~p",
- [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end
- end.
-
-stop_timer(undefined) ->
- ?DBG("PUSH SUPPLIER HAVE NO TIMER TO STOP~n",[]),
- ok;
-stop_timer(Timer) ->
- ?DBG("PUSH SUPPLIER STOPPED TIMER~n",[]),
- timer:cancel(Timer),
- ok.
-
-
-%%--------------- MISC FUNCTIONS, E.G. DEBUGGING -------------
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/cosNotification/src/cosNotification.app.src b/lib/cosNotification/src/cosNotification.app.src
deleted file mode 100644
index 52ce164d46..0000000000
--- a/lib/cosNotification/src/cosNotification.app.src
+++ /dev/null
@@ -1,122 +0,0 @@
-{application, cosNotification,
- [{description, "The Erlang CosNotification application"},
- {vsn, "%VSN%"},
- {modules,
- [
- 'CosNotification_Common',
- 'CosNotifyChannelAdmin_ConsumerAdmin_impl',
- 'CosNotifyChannelAdmin_EventChannelFactory_impl',
- 'CosNotifyChannelAdmin_EventChannel_impl',
- 'CosNotifyChannelAdmin_SupplierAdmin_impl',
- 'PullerConsumer_impl',
- 'PullerSupplier_impl',
- 'PusherConsumer_impl',
- 'PusherSupplier_impl',
- 'cosNotificationApp',
- 'CosNotifyFilter_Filter_impl',
- 'CosNotifyFilter_MappingFilter_impl',
- 'CosNotifyFilter_FilterFactory_impl',
- 'cosNotification_Scanner',
- 'cosNotification_Grammar',
- 'cosNotification_Filter',
- 'cosNotification_eventDB',
- 'oe_CosNotification',
- 'oe_cosNotificationAppComm',
- 'oe_CosNotificationComm_Event',
- 'CosNotification',
- 'CosNotification_AdminPropertiesAdmin',
- 'CosNotification_EventHeader',
- 'CosNotification_EventType',
- 'CosNotification_FixedEventHeader',
- 'CosNotification_NamedPropertyRange',
- 'CosNotification_Property',
- 'CosNotification_PropertyError',
- 'CosNotification_PropertyRange',
- 'CosNotification_QoSAdmin',
- 'CosNotification_StructuredEvent',
- 'CosNotification_UnsupportedAdmin',
- 'CosNotification_UnsupportedQoS',
- 'CosNotification_EventBatch',
- 'CosNotification_EventTypeSeq',
- 'CosNotification_NamedPropertyRangeSeq',
- 'CosNotification_PropertyErrorSeq',
- 'CosNotification_PropertySeq',
- 'oe_CosNotifyChannelAdmin',
- 'CosNotifyChannelAdmin_AdminLimit',
- 'CosNotifyChannelAdmin_AdminLimitExceeded',
- 'CosNotifyChannelAdmin_AdminNotFound',
- 'CosNotifyChannelAdmin_ChannelNotFound',
- 'CosNotifyChannelAdmin_ConnectionAlreadyActive',
- 'CosNotifyChannelAdmin_ConnectionAlreadyInactive',
- 'CosNotifyChannelAdmin_ConsumerAdmin',
- 'CosNotifyChannelAdmin_EventChannel',
- 'CosNotifyChannelAdmin_EventChannelFactory',
- 'CosNotifyChannelAdmin_NotConnected',
- 'CosNotifyChannelAdmin_ProxyConsumer',
- 'CosNotifyChannelAdmin_ProxyNotFound',
- 'CosNotifyChannelAdmin_ProxyPullConsumer',
- 'CosNotifyChannelAdmin_ProxyPullSupplier',
- 'CosNotifyChannelAdmin_ProxyPushConsumer',
- 'CosNotifyChannelAdmin_ProxyPushSupplier',
- 'CosNotifyChannelAdmin_ProxySupplier',
- 'CosNotifyChannelAdmin_SequenceProxyPullConsumer',
- 'CosNotifyChannelAdmin_SequenceProxyPullSupplier',
- 'CosNotifyChannelAdmin_SequenceProxyPushConsumer',
- 'CosNotifyChannelAdmin_SequenceProxyPushSupplier',
- 'CosNotifyChannelAdmin_StructuredProxyPullConsumer',
- 'CosNotifyChannelAdmin_StructuredProxyPullSupplier',
- 'CosNotifyChannelAdmin_StructuredProxyPushConsumer',
- 'CosNotifyChannelAdmin_StructuredProxyPushSupplier',
- 'CosNotifyChannelAdmin_SupplierAdmin',
- 'CosNotifyChannelAdmin_AdminIDSeq',
- 'CosNotifyChannelAdmin_ChannelIDSeq',
- 'CosNotifyChannelAdmin_ProxyIDSeq',
- 'oe_CosNotifyComm',
- 'CosNotifyComm_InvalidEventType',
- 'CosNotifyComm_NotifyPublish',
- 'CosNotifyComm_NotifySubscribe',
- 'CosNotifyComm_PullConsumer',
- 'CosNotifyComm_PullSupplier',
- 'CosNotifyComm_PushConsumer',
- 'CosNotifyComm_PushSupplier',
- 'CosNotifyComm_SequencePullConsumer',
- 'CosNotifyComm_SequencePullSupplier',
- 'CosNotifyComm_SequencePushConsumer',
- 'CosNotifyComm_SequencePushSupplier',
- 'CosNotifyComm_StructuredPullConsumer',
- 'CosNotifyComm_StructuredPullSupplier',
- 'CosNotifyComm_StructuredPushConsumer',
- 'CosNotifyComm_StructuredPushSupplier',
- 'oe_CosNotifyFilter',
- 'CosNotifyFilter_CallbackNotFound',
- 'CosNotifyFilter_ConstraintExp',
- 'CosNotifyFilter_ConstraintInfo',
- 'CosNotifyFilter_ConstraintNotFound',
- 'CosNotifyFilter_DuplicateConstraintID',
- 'CosNotifyFilter_Filter',
- 'CosNotifyFilter_FilterAdmin',
- 'CosNotifyFilter_FilterFactory',
- 'CosNotifyFilter_FilterNotFound',
- 'CosNotifyFilter_InvalidConstraint',
- 'CosNotifyFilter_InvalidGrammar',
- 'CosNotifyFilter_InvalidValue',
- 'CosNotifyFilter_MappingConstraintInfo',
- 'CosNotifyFilter_MappingConstraintPair',
- 'CosNotifyFilter_MappingFilter',
- 'CosNotifyFilter_UnsupportedFilterableData',
- 'CosNotifyFilter_CallbackIDSeq',
- 'CosNotifyFilter_ConstraintExpSeq',
- 'CosNotifyFilter_ConstraintIDSeq',
- 'CosNotifyFilter_ConstraintInfoSeq',
- 'CosNotifyFilter_FilterIDSeq',
- 'CosNotifyFilter_MappingConstraintInfoSeq',
- 'CosNotifyFilter_MappingConstraintPairSeq'
- ]
- },
- {registered, [cosNotificationSup, oe_cosNotificationFactory]},
- {applications, [orber, stdlib, kernel]},
- {env, []},
- {mod, {cosNotificationApp, []}},
- {runtime_dependencies, ["stdlib-2.5","orber-3.6.27","kernel-3.0","erts-7.0",
- "cosTime-1.1.14","cosEvent-2.1.15"]}
-]}.
diff --git a/lib/cosNotification/src/cosNotification.appup.src b/lib/cosNotification/src/cosNotification.appup.src
deleted file mode 100644
index 6c3b2833b7..0000000000
--- a/lib/cosNotification/src/cosNotification.appup.src
+++ /dev/null
@@ -1,7 +0,0 @@
-{"%VSN%",
- [
- ],
- [
- ]
-}.
-
diff --git a/lib/cosNotification/src/cosNotificationApp.erl b/lib/cosNotification/src/cosNotificationApp.erl
deleted file mode 100644
index f6231ed47e..0000000000
--- a/lib/cosNotification/src/cosNotificationApp.erl
+++ /dev/null
@@ -1,436 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2015. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : cosNotificationApp.erl
-%% Purpose :
-%%----------------------------------------------------------------------
-
--module(cosNotificationApp).
-
-%%--------------- INCLUDES -----------------------------------
-%% Local
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
-%% Application files
--include("CosNotification.hrl").
--include("CosNotifyChannelAdmin.hrl").
--include("CosNotifyComm.hrl").
--include("CosNotifyFilter.hrl").
-
--include("CosNotification_Definitions.hrl").
-%%--------------- EXPORTS-------------------------------------
-%% cosNotification API external
--export([start/0, stop/0,
- start_factory/1, start_factory/0, stop_factory/1,
- start_global_factory/0, start_global_factory/1,
- start_filter_factory/1, start_filter_factory/0, stop_filter_factory/1,
- install/0, install/1, uninstall/0, uninstall/1,
- install_event/0, install_event/1, uninstall_event/0, uninstall_event/1,
- install_typed/0, install_typed/1, uninstall_typed/0, uninstall_typed/1,
- create_structured_event/6, type_check/0, notify/0, max_events/0,
- timeout_events/0, interval_events/0]).
-
-%% Application callbacks
--export([start/2, init/1, stop/1]).
-
-%%--------------- DEFINES ------------------------------------
--define(IDL_MODULES, ['oe_CosNotification',
- 'oe_cosNotificationAppComm',
- 'oe_CosNotifyComm',
- 'oe_CosNotifyFilter',
- 'oe_CosNotifyChannelAdmin']).
--define(EVENT_IDL_MODULES, ['oe_CosEventComm',
- 'oe_CosEventChannelAdmin']).
--define(TYPED_IDL_MODULES, ['oe_CosTypedEvent',
- 'oe_CosTypedNotification']).
-
--define(FACTORY_NAME, oe_cosNotificationFactory).
--define(SUPERVISOR_NAME, cosNotificationSup).
-
-
-%%------------------------------------------------------------
-%% function : install/X
-%% Arguments: - | Time (seconds)
-%% Returns : ok | EXIT | EXCEPTION
-%% Effect : Install necessary data in the IFR DB
-%%------------------------------------------------------------
-
-install() ->
- install(0).
-
-install(Time) when is_integer(Time) ->
- install_loop(?IDL_MODULES, timer:seconds(Time));
-install(_Time) ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%------------------------------------------------------------
-%% function : install_event/X
-%% Arguments: - | Time (seconds)
-%% Returns : ok | EXIT | EXCEPTION
-%% Effect : Install necessary data in the IFR DB
-%%------------------------------------------------------------
-
-install_event() ->
- install_event(0).
-
-install_event(Time) when is_integer(Time) ->
- install_loop(?EVENT_IDL_MODULES, timer:seconds(Time));
-install_event(_Time) ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%------------------------------------------------------------
-%% function : install_typed/X
-%% Arguments: - | Time (seconds)
-%% Returns : ok | EXIT | EXCEPTION
-%% Effect : Install necessary data in the IFR DB
-%%------------------------------------------------------------
-
-install_typed() ->
- install_typed(0).
-
-install_typed(Time) when is_integer(Time) ->
- install_loop(?TYPED_IDL_MODULES, timer:seconds(Time));
-install_typed(_Time) ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-install_loop([], _) ->
- ok;
-install_loop([H|T], Time) ->
- H:'oe_register'(),
- timer:sleep(Time),
- install_loop(T, Time).
-
-%%------------------------------------------------------------
-%% function : uninstall/X
-%% Arguments: - | Time (seconds)
-%% Returns : ok | EXIT | EXCEPTION
-%% Effect : Remove data related to cosNotificationin from the IFR DB
-%%------------------------------------------------------------
-
-uninstall() ->
- uninstall(0).
-
-uninstall(Time) when is_integer(Time) ->
- uninstall_loop(lists:reverse(?IDL_MODULES), timer:seconds(Time));
-uninstall(_Time) ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%------------------------------------------------------------
-%% function : uninstall_event/X
-%% Arguments: - | Time (seconds)
-%% Returns : ok | EXIT | EXCEPTION
-%% Effect : Remove data related to cosNotificationin from the IFR DB
-%%------------------------------------------------------------
-
-uninstall_event() ->
- uninstall_event(0).
-
-uninstall_event(Time) when is_integer(Time) ->
- uninstall_loop(lists:reverse(?EVENT_IDL_MODULES), timer:seconds(Time));
-uninstall_event(_Time) ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%------------------------------------------------------------
-%% function : uninstall_typed/X
-%% Arguments: - | Time (seconds)
-%% Returns : ok | EXIT | EXCEPTION
-%% Effect : Remove data related to cosNotificationin from the IFR DB
-%%------------------------------------------------------------
-
-uninstall_typed() ->
- uninstall_typed(0).
-
-uninstall_typed(Time) when is_integer(Time) ->
- uninstall_loop(lists:reverse(?TYPED_IDL_MODULES), timer:seconds(Time));
-uninstall_typed(_Time) ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-uninstall_loop([], _) ->
- ok;
-uninstall_loop([H|T], Time) ->
- H:'oe_unregister'(),
- timer:sleep(Time),
- uninstall_loop(T, Time).
-
-
-%%------------------------------------------------------------
-%% function : start/stop
-%% Arguments:
-%% Returns :
-%% Effect : Starts or stops the cosTRansaction application.
-%%------------------------------------------------------------
-
-start() ->
- application:start(cosNotification).
-stop() ->
- application:stop(cosNotification).
-
-%%------------------------------------------------------------
-%% function : start_factory
-%% Arguments: none or an argumentlist whith default values.
-%% Returns : ObjectRef | {'EXCEPTION', _} | {'EXIT', Reason}
-%% Effect : Starts a CosNotifyChannelAdmin_EventChannelFactory
-%%------------------------------------------------------------
-start_factory() ->
- start_factory(?not_DEFAULT_SETTINGS).
-
-start_factory(Args) when is_list(Args) ->
- SO = 'CosNotification_Common':get_option(server_options, Args, ?not_DEFAULT_SETTINGS),
- SPEC = ['CosNotifyChannelAdmin_EventChannelFactory',Args,
- [{sup_child, true},
- {regname, {local, oe_cosNotificationFactory}}|SO]],
- case supervisor:start_child(?SUPERVISOR_NAME, SPEC) of
- {ok, Pid, Obj} when is_pid(Pid) ->
- Obj;
- Other->
- orber:dbg("[~p] cosNotificationApp:start_factory( ~p ).~n"
- "Reason: ~p~n", [?LINE, Args, Other], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO})
- end;
-start_factory(Args) ->
- orber:dbg("[~p] cosNotificationApp:start_factory( ~p ).~n"
- "Bad parameters~n", [?LINE, Args], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%------------------------------------------------------------
-%% function : start_global_factory
-%% Arguments: none or an argumentlist whith default values.
-%% Returns : ObjectRef | {'EXCEPTION', _} | {'EXIT', Reason}
-%% Effect : Starts a CosNotifyChannelAdmin_EventChannelFactory
-%%------------------------------------------------------------
-start_global_factory() ->
- start_global_factory(?not_DEFAULT_SETTINGS).
-
-start_global_factory(Args) when is_list(Args) ->
- SO = 'CosNotification_Common':get_option(server_options, Args, ?not_DEFAULT_SETTINGS),
- Name = 'CosNotification_Common':create_name(),
- SPEC = ['CosNotifyChannelAdmin_EventChannelFactory',Args,
- [{sup_child, true},
- {regname, {global, Name}}|SO]],
- case supervisor:start_child(?SUPERVISOR_NAME, SPEC) of
- {ok, Pid, Obj} when is_pid(Pid) ->
- Obj;
- Other->
- orber:dbg("[~p] cosNotificationApp:start_global_factory( ~p ).~n"
- "Reason: ~p~n", [?LINE, Args, Other], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO})
- end;
-start_global_factory(Args) ->
- orber:dbg("[~p] cosNotificationApp:start_global_factory( ~p ).~n"
- "Bad parameters~n", [?LINE, Args], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-
-%%------------------------------------------------------------
-%% function : stop_factory
-%% Arguments: Factory Object Reference
-%% Returns : ok | {'EXCEPTION', _}
-%% Effect :
-%%------------------------------------------------------------
-
-stop_factory(Fac)->
- corba:dispose(Fac).
-
-%%------------------------------------------------------------
-%% function : start_filter_factory
-%% Arguments: none or an argumentlist which by default is defined
-%% in CosNotification_Definitions.hrl, i.e., '?not_FILTERFAC_DEF'
-%% Returns : ObjectRef | {'EXCEPTION', _} | {'EXIT', Reason}
-%% Effect : Starts a CosNotifyChannelAdmin_EventChannelFactory
-%%------------------------------------------------------------
-start_filter_factory() ->
- start_filter_factory([{typecheck, true},
- {tty, false},
- {logfile, false},
- {server_options, []}]).
-start_filter_factory(Args) when is_list(Args) ->
- SO = 'CosNotification_Common':get_option(server_options, Args,
- ?not_DEFAULT_SETTINGS),
- SPEC = ['CosNotifyFilter_FilterFactory',Args, [{sup_child, true}|SO]],
- case supervisor:start_child(?SUPERVISOR_NAME, SPEC) of
- {ok, Pid, Obj} when is_pid(Pid) ->
- Obj;
- Other->
- orber:dbg("[~p] cosNotificationApp:start_filter_factory( ~p ).~n"
- "Reason: ~p~n", [?LINE, Args, Other], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO})
- end;
-start_filter_factory(Args) ->
- orber:dbg("[~p] cosNotificationApp:start_filter_factory( ~p ).~n"
- "Bad parameters~n", [?LINE, Args], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-
-%%------------------------------------------------------------
-%% function : stop_filter_factory
-%% Arguments: FilterFactory Object Reference
-%% Returns : ok | {'EXCEPTION', _}
-%% Effect :
-%%------------------------------------------------------------
-
-stop_filter_factory(Fac)->
- corba:dispose(Fac).
-
-
-%%------------------------------------------------------------
-%% function : create_structured_event
-%% Arguments:
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-create_structured_event(StrD,StrT,StrE,PSeqV,PSeqF,AnyR)
- when is_list(StrD) andalso is_list(StrT) andalso is_list(StrE)
- andalso is_list(PSeqV) andalso is_list(PSeqF) andalso
- is_record(AnyR, any) ->
-#'CosNotification_StructuredEvent'{header =
- #'CosNotification_EventHeader'{fixed_header =
- #'CosNotification_FixedEventHeader'{event_type =
- #'CosNotification_EventType'{domain_name=StrD,
- type_name=StrT},
- event_name = StrE},
- variable_header = PSeqV},
- filterable_data = PSeqF,
- remainder_of_body = AnyR};
-create_structured_event(_StrD,_StrT,_StrE,_PSeqV,_PSeqF,_AnyR) ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-
-%%------------------------------------------------------------
-%% function : type_check
-%% Arguments:
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-type_check() ->
- case application:get_env(cosNotification, type_check) of
- {ok, Boolean} when is_atom(Boolean) ->
- Boolean;
- _ ->
- true
- end.
-
-%%------------------------------------------------------------
-%% function : notify
-%% Arguments:
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-notify() ->
- case application:get_env(cosNotification, notify) of
- {ok, Module} when is_atom(Module) ->
- Module;
- _ ->
- false
- end.
-
-%%------------------------------------------------------------
-%% function : max_events
-%% Arguments:
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-max_events() ->
- case application:get_env(cosNotification, max_events) of
- {ok, Max} when is_integer(Max) ->
- Max;
- _ ->
- 50
- end.
-
-%%------------------------------------------------------------
-%% function : timeout_events
-%% Arguments:
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-timeout_events() ->
- case application:get_env(cosNotification, timeout_events) of
- {ok, Max} when is_integer(Max) ->
- Max;
- _ ->
- 3000000 %% 5 minutes
- end.
-
-
-%%------------------------------------------------------------
-%% function : interval_events
-%% Arguments:
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-interval_events() ->
- case application:get_env(cosNotification, interval_events) of
- {ok, Max} when is_integer(Max) ->
- Max;
- _ ->
- 10000 %% 10 seconds
- end.
-
-
-%%------------------------------------------------------------
-%% function : start
-%% Arguments: Type - see module application
-%% Arg - see module application
-%% Returns :
-%% Effect : Module callback for application
-%%------------------------------------------------------------
-
-start(_, _) ->
- supervisor:start_link({local, ?SUPERVISOR_NAME}, cosNotificationApp, app_init).
-
-
-%%------------------------------------------------------------
-%% function : stop
-%% Arguments: Arg - see module application
-%% Returns :
-%% Effect : Module callback for application
-%%------------------------------------------------------------
-
-stop(_) ->
- ok.
-
-%%------------------------------------------------------------
-%% function : init
-%% Arguments:
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-
-%% Starting using create_factory/X
-init(own_init) ->
- {ok,{{simple_one_for_one,50,10},
- [{"oe_NotChild",
- {'CosNotification_Common',create_link, []},
- transient,100000,worker,
- ['CosNotifyChannelAdmin_EventChannel',
- 'CosNotifyChannelAdmin_EventChannel_impl']}]}};
-%% When starting as an application.
-init(app_init) ->
- {ok,{{simple_one_for_one,50,10},
- [{"oe_NotChild",
- {'CosNotification_Common',create_link, []},
- transient,100000,worker,
- ['CosNotifyChannelAdmin_EventChannel',
- 'CosNotifyChannelAdmin_EventChannel_impl']}]}}.
-
-
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/cosNotification/src/cosNotificationAppComm.idl b/lib/cosNotification/src/cosNotificationAppComm.idl
deleted file mode 100644
index 09e0af2568..0000000000
--- a/lib/cosNotification/src/cosNotificationAppComm.idl
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef _OE_COSNOTIFICATIONCOMM_IDL_
-#define _OE_COSNOTIFICATIONCOMM_IDL_
-
-#include<CosNotification.idl>
-
-module oe_CosNotificationComm {
-
- interface Event {
-
- enum status {MATCH, MATCHED};
- void callSeq(in CosNotification::EventBatch events, in status stat);
- void callAny(in any event, in status stat);
- };
-
-};
-#endif /* ifndef _OE_COSNOTIFICATIONCOMM_IDL_ */
-
diff --git a/lib/cosNotification/src/cosNotificationComm.cfg b/lib/cosNotification/src/cosNotificationComm.cfg
deleted file mode 100644
index 89d207528d..0000000000
--- a/lib/cosNotification/src/cosNotificationComm.cfg
+++ /dev/null
@@ -1,3 +0,0 @@
-{this, "oe_CosNotificationComm::Event"}.
-{from, "oe_CosNotificationComm::Event"}.
-{{handle_info, "oe_CosNotificationComm::Event"}, true}.
diff --git a/lib/cosNotification/src/cosNotification_Filter.erl b/lib/cosNotification/src/cosNotification_Filter.erl
deleted file mode 100644
index a92c9b8d41..0000000000
--- a/lib/cosNotification/src/cosNotification_Filter.erl
+++ /dev/null
@@ -1,965 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : cosNotification_Filter.erl
-%% Purpose :
-%%----------------------------------------------------------------------
-
--module(cosNotification_Filter).
-
-
-%%--------------- INCLUDES -----------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
-%% Application files
--include("CosNotification.hrl").
--include("CosNotifyChannelAdmin.hrl").
--include("CosNotifyComm.hrl").
--include("CosNotifyFilter.hrl").
-
--include("CosNotification_Definitions.hrl").
-
-%%--------------- EXPORTS ------------------------------------
-%% Internal Filter Functions
--export([eval/1,
- eval/2,
- create_filter/1,
- check_types/1,
- match_types/3,
- validate_types/1]).
-
-%%--------------- DEFINES ------------------------------------
--define(EVENT_PATH, [{dotid,"header"}, {dotid,"fixed_header"},
- {dotid,"event_name"}]).
--define(DOMAIN_PATH, [{dotid,"header"}, {dotid,"fixed_header"},
- {dotid,"event_type"}, {dotid,"domain_name"}]).
--define(TYPE_PATH, [{dotid,"header"}, {dotid,"fixed_header"},
- {dotid,"event_type"}, {dotid,"type_name"}]).
--define(VARIABLE_PATH(I), [{dotid,"header"}, {dotid,"variable_header"}, {dotid,I}]).
--define(FILTERABLE_PATH(I), [{dotid,"filterable_data"}, {dotid,I}]).
-
-
-%%------------------------------------------------------------
-%%--------------- FILTER FUNCTIONS ---------------------------
-%%------------------------------------------------------------
-%%------------------------------------------------------------
-%% function : create_filter/1
-%% Arguments: String - Filter grammar
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-create_filter(Str) ->
- {ok, Tokens} = cosNotification_Scanner:scan(Str),
- case cosNotification_Grammar:parse(Tokens) of
- {ok, Filter} ->
- {ok, Filter};
- _->
- corba:raise(#'CosNotifyFilter_InvalidConstraint'{constr = Str})
- end.
-
-%%------------------------------------------------------------
-%% function : eval
-%% Arguments:
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-
-eval('$empty') -> true;
-eval(Tree) -> eval(Tree, []).
-
-
-%% Leaf expressions (literals and idents).
-eval('$empty', _) -> true;
-eval(Lit, _Env) when is_number(Lit) -> Lit;
-eval(Lit, _Env) when is_list(Lit) -> Lit; %list == string
-eval(Lit, _Env) when is_atom(Lit) -> Lit; %atom == bool
-eval({component, V}, []) ->
- %% Cannot evaluate variables at this stage.
- throw({error, {unbound_variable, V}});
-eval({component, V}, Env) ->
- case catch lookup(V, Env, undefined) of
- {ok, Val} ->
- Val;
- _X ->
- {error, {unbound_variable, V}}
- end;
-
-%% CORBA2.3-15/26 states:
-%% "The name parameters in tk_objref, tk_struct, tk_union, tk_enum, tk_alias,
-%% tk_value, tk_value_box, tk_abstract_interface, tk_native and tk_except TypeCodes
-%% and the member name parameters in tk_struct, tk_union, tk_enum, tk_value and
-%% tk_except TypeCodes are not specified by (or significant in) GIOP. Agents should
-%% not make assumptions about type equivalence based on these name values; only the
-%% structural information (including RepositoryId values, if provided) is
-%% significant. If provided, the strings should be the simple, unscoped names
-%% supplied in the OMG IDL definition text. If omitted, they are encoded as empty
-%% strings."
-%% Makes it rather hard to follow the grammar 100 %.
-eval({default_component, V}, Env) ->
- case catch lookup(V, Env, default_component) of
- {ok, false} ->
- false;
- {ok, true} ->
- true;
- _X ->
- {error, {unbound_variable, V}}
- end;
-eval({exist_component, V}, Env) ->
- case catch lookup(V, Env, exist_component) of
- {ok, false} ->
- false;
- {ok, _} ->
- true;
- {error, _} ->
- false;
- _X ->
- {error, {unbound_variable, V}}
- end;
-%% Arithmetic expressions.
-eval({'*', X, Y}, Env) ->
- eval_arith({fun(_X, _Y) -> _X*_Y end, X, Y}, Env);
-eval({'/', X, Y}, Env) ->
- eval_arith({fun(_X, _Y) -> _X/_Y end, X, Y}, Env);
-eval({'+', X, Y}, Env) ->
- eval_arith({fun(_X, _Y) -> _X+_Y end, X, Y}, Env);
-eval({'-', X, Y}, Env) ->
- eval_arith({fun(_X, _Y) -> _X-_Y end, X, Y}, Env);
-eval({'u-', X}, Env) ->
- eval_arith({fun(_X) -> -_X end, X}, Env);
-%% Relational expressions.
-eval({'==', X, Y}, Env) ->
- eval_rel({fun(_X, _Y) -> _X == _Y end, X, Y}, Env);
-eval({'!=', X, Y}, Env) ->
- eval_rel({fun(_X, _Y) -> _X /= _Y end, X, Y}, Env);
-eval({'<', X, Y}, Env) ->
- eval_rel({fun(_X, _Y) -> _X < _Y end, X, Y}, Env);
-eval({'<=', X, Y}, Env) ->
- eval_rel({fun(_X, _Y) -> _X =< _Y end, X, Y}, Env);
-eval({'>', X, Y}, Env) ->
- eval_rel({fun(_X, _Y) -> _X > _Y end, X, Y}, Env);
-eval({'>=', X, Y}, Env) ->
- eval_rel({fun(_X, _Y) -> _X >= _Y end, X, Y}, Env);
-eval({'~', Needle, Haystack}, Env) -> %substring match
- N = eval(Needle, Env),
- H = eval(Haystack, Env),
- if
- is_list(N) andalso is_list(H) ->
- string:str(H, N) /= 0;
- true ->
- throw({error, {bad_type, Needle, Haystack}})
- end;
-eval({'in', Needle, Haystack}, Env) -> %set membership
- N = eval(Needle, Env),
- H = eval(Haystack, Env),
- if
- is_list(H) ->
- lists:member(N, H);
- true ->
- throw({error, {bad_type, Needle, Haystack}})
- end;
-%% Boolean expressions.
-eval({'and', false, _Y}, _Env) ->
- false;
-eval({'and', _X, false}, _Env) ->
- false;
-eval({'and', X, Y}, Env) ->
- eval_and_bool({fun(_X, _Y) -> _X and _Y end, X, Y}, Env);
-
-eval({'or', true, _Y}, _Env) ->
- true;
-eval({'or', _X, true}, _Env) ->
- true;
-eval({'or', X, Y}, Env) ->
- eval_or_bool({fun(_X, _Y) -> _X or _Y end, X, Y}, Env);
-eval({'not', X}, Env) ->
- eval_bool({fun(_X) -> not _X end, X}, Env);
-%% Catch-all
-eval(_T, _Env) ->
- throw({error, internal}).
-
-eval_bool({Fun, X}, Env) ->
- Xe = eval(X, Env),
- if
- is_atom(Xe) ->
- Fun(Xe);
- true ->
- throw({error, {bad_type, X}})
- end.
-eval_and_bool({Fun, X, Y}, Env) ->
- case eval(X, Env) of
- false ->
- %% No need for evaluating the other expression.
- false;
- Xe ->
- Ye = eval(Y, Env),
- if
- is_atom(Xe) andalso is_atom(Ye) ->
- Fun(Xe, Ye);
- true ->
- throw({error, {bad_type, X, Y}})
- end
- end.
-eval_or_bool({Fun, X, Y}, Env) ->
- case eval(X, Env) of
- true ->
- %% No need for evaluating the other expression.
- true;
- Xe ->
- Ye = eval(Y, Env),
- if
- is_atom(Xe) andalso is_atom(Ye) ->
- Fun(Xe, Ye);
- true ->
- throw({error, {bad_type, X, Y}})
- end
- end.
-
-
-%% According to issue 2203, OMG stated that arithmetic operations involving booleans
-%% is allowed. TRUE equals 1 and FALSE 0. They refer to:
-
-%% "We at NEC like this feature, and feel it is both required and
-%% standard with the way CORBA treats boolean values. We feel it's
-%% required because it allows the constraint grammar to handle
-%% expressions that combine the results of boolean comparisons,
-%% which we feel is typically expected of a constraint grammar
-%% (e.g., ($.fruit == apples) + ($.color == red) + ($.kind == macintosh) > 2)
-%% Furthermore, while we have no fundamental opposition to explicitly
-%% stating that TRUE=1 and FALSE=0, we don't necessarily feel it's
-%% necessary because section 12.3.1 of CORBA alread states that
-%% "Boolean values are encoded as single octets, where TRUE is the
-%% value 1, and FALSE is 0." Essentially, we feel CORBA already
-%% defines TRUE to be 1 and FALSE to be 0, however we are not
-%% opposed to adding such a statement into Notification if folks
-%% feel it's necessary."
-%% If still valid, see: ftp://ftp.omg.org/pub/docs/telecom/99-07-06.txt
-
-%% The section they refer to (CORBA-2.0) merely states that TRUE and FALSE are
-%% encoded as 1 and 0 in GIOP. Does not imply that booleans may be used as numeric.
-%% But, they have stated that this should be the case so.....
-
-remap_bool(Num) when is_number(Num) -> Num;
-remap_bool(true) -> 1;
-remap_bool(false) -> 0;
-remap_bool(X) -> throw({error, {bad_type, X}}).
-
-eval_arith({Fun, X}, Env) ->
- Xe = remap_bool(eval(X, Env)),
- Fun(Xe);
-eval_arith({Fun, X, Y}, Env) ->
- Xe = remap_bool(eval(X, Env)),
- Ye = remap_bool(eval(Y, Env)),
- Fun(Xe, Ye).
-
-eval_rel({Fun, X, Y}, Env) ->
- Xe = eval(X, Env),
- Ye = eval(Y, Env),
- if
- is_number(Xe) andalso is_number(Ye) ->
- Fun(Xe, Ye);
- is_list(Xe) andalso is_list(Ye) ->
- Fun(Xe, Ye);
- is_atom(Xe) andalso is_atom(Ye) ->
- Fun(Xe, Ye);
- true ->
- throw({error, {bad_type, X, Y}})
- end.
-
-%%------------------------------------------------------------
-%% function : get_variable
-%% Arguments: A sequence of CosNotification::Property{}, i.e.,
-%% name-value pairs.
-%% ID - name in the Property
-%% Any - remainder of body
-%% Returns : Value in the Property | false
-%% Comment : When searching for a variable we must start with
-%% 'variable_header' followed by 'filterable_body'.
-%% If not found we will then look in the 'remainder_of_body'
-%%------------------------------------------------------------
-
-get_variable([], ID, Any) when is_record(Any, any) ->
- case {any:get_value(Any), any:get_typecode(Any)} of
- {#'CosNotification_Property'{name=ID, value=A}, _} ->
- any:get_value(A);
- {_, TC} when is_atom(TC) ->
- %% Since TC atom it must be a simple type, which don't have members.
- throw({error, {bad_id, ID}});
- {Value, {tk_alias,_,ID,_}} when is_record(Value, any) ->
- %% {tk_alias, IFRId, ID, TypeCode}
- any:get_value(Value);
- {Value, {tk_alias,_,ID,_}} ->
- %% {tk_alias, IFRId, ID, TypeCode}
- Value;
- {Value, _TC} ->
- get_variable([],ID, Value)
- end;
-get_variable([], ID, #'CosNotification_Property'{name=ID, value=Any}) ->
- any:get_value(Any);
-get_variable([], ID, [#'CosNotification_Property'{name=ID, value=Any}|_]) ->
- any:get_value(Any);
-get_variable([], ID, [H|T]) when is_record(H, 'CosNotification_Property') ->
- get_variable([], ID, T);
-get_variable([], ID, false) ->
- throw({error, {bad_id, ID}});
-get_variable([], ID, Value) ->
- M = element(1, Value),
- case catch M:tc() of
- {tk_struct,_,_,SList} ->
- %% {tk_struct, Id, Name, ElementList}.
- Field = get_field(ID, SList),
- element(Field, Value);
- {tk_union,_,_,_, DefNo, UList} ->
- %% {tk_union, Id, Name, DiscrTC, Default, ElementList}
- case id2switch(UList, ID) of
- [default] when DefNo >= 0 ->
- element(3, Value);
- [default] ->
- throw({error, {bad_id, "Bad Union ID supplied"}});
- Found ->
- case catch lists:member(element(2, Value), Found) of
- true ->
- element(3, Value);
- _ ->
- throw({error, {bad_id, "Bad Union ID supplied"}})
- end
- end;
- _->
- throw({error, {bad_id, ID}})
- end;
-get_variable([#'CosNotification_Property'{name=ID, value=A}|_], ID, _) ->
- any:get_value(A);
-get_variable([_|T], ID, Any) ->
- get_variable(T, ID, Any).
-
-%%------------------------------------------------------------
-%% function : lookup
-%% Arguments: T - A parse tree representing the grammar.
-%% S - The event we want to extract data from
-%% Op - which type of lookup should be done on this
-%% component, e.g., 'default' or 'exist'.
-%% Returns : {ok, boolean()} |
-%% {error, _}
-%% Comment : WARNING!!!!
-%% This function uses some Orber core information to
-%% extract data, e.g., TypeCode representation. Why?
-%% We don't want to see the performance take a plunge
-%% due to that users write constraints which they
-%% can/may not know is slow. The alternative would be
-%% to use the IFR. However, these shortcuts aren't
-%% that frequent and we can easily update the code.
-%% To update, investigate:
-%% * lookup/3 cases related to '_type_id'
-%% * lookup/3 cases related to unions
-%% * get_variable/3
-%% * id2switch/2
-%% * switch2alias/2
-%%------------------------------------------------------------
-%% Done parsing, return the result.
-lookup([],S,_) -> {ok, S};
-lookup('$empty', #'CosNotification_StructuredEvent'{remainder_of_body = Any},_) ->
- {ok, any:get_value(Any)};
-lookup('$empty',S,_) when is_record(S, any) ->
- {ok, any:get_value(S)};
-
-%%------- varid --------
-%% CosNotification-revision-98-11-01/46 states:
-%% "The following rules govern translation of a run-time variable, $variable ,
-%% into a specific event field. If the run-time variable is reserved
-%% (e.g., $curtime) this translation takes precedence. Next, the first matching
-%% translation is chosen respectively from:
-%% * a simple-typed member of $.header.fixed_header,
-%% * properties in $.header.variable_header,
-%% and properties in $.header.filterable_data.
-%% If no match is found, the translation defaults to $.variable.
-%% Given these rules, an unstructured event with a $.priority member and a
-%% structured event using $.header.variable_header(priority) can be specified
-%% in a generic constraint using the run-time variable $priority .
-%% Alternatively, a constraint can be written specifically for a structured or
-%% unstructured event by avoiding the use of run-time variables."
-
-%% The above contains one error; $.header.filterable_data is not a part of the
-%% header, but contained in the event body.
-
-%% For any events we must first verify that a path exist, e.g.,
-%% "header"->"fixed_header"->"event_type"->"domain_name", otherwise we will
-%% use {dotid, "xxx"}.
-lookup([{varid, "type_name"}|T],
- #'CosNotification_StructuredEvent'
- {header = #'CosNotification_EventHeader'
- {fixed_header = #'CosNotification_FixedEventHeader'
- {event_type = #'CosNotification_EventType'{type_name=TN}}}}, Op) ->
- lookup(T, TN, Op);
-lookup([{varid, "type_name"}|T], Any, Op) when is_record(Any, any) ->
- case locate_var([?TYPE_PATH, ?VARIABLE_PATH("type_name"),
- ?FILTERABLE_PATH("type_name")], Any, Op) of
- {ok, Val} ->
- lookup(T, Val, Op);
- _ ->
- lookup(T, get_variable([], "type_name", Any), Op)
- end;
-lookup([{varid, "domain_name"}|T],
- #'CosNotification_StructuredEvent'
- {header = #'CosNotification_EventHeader'
- {fixed_header = #'CosNotification_FixedEventHeader'
- {event_type = #'CosNotification_EventType'{domain_name=DN}}}}, Op) ->
- lookup(T, DN, Op);
-lookup([{varid, "domain_name"}|T], Any, Op) when is_record(Any, any) ->
- case locate_var([?DOMAIN_PATH, ?VARIABLE_PATH("domain_name"),
- ?FILTERABLE_PATH("domain_name")], Any, Op) of
- {ok, Val} ->
- lookup(T, Val, Op);
- _ ->
- lookup(T, get_variable([], "domain_name", Any), Op)
- end;
-lookup([{varid, "event_name"}|T],
- #'CosNotification_StructuredEvent'
- {header = #'CosNotification_EventHeader'
- {fixed_header = #'CosNotification_FixedEventHeader'
- {event_name = EN}}}, Op) ->
- lookup(T, EN, Op);
-lookup([{varid, "event_name"}|T], Any, Op) when is_record(Any, any) ->
- case locate_var([?EVENT_PATH, ?VARIABLE_PATH("event_name"),
- ?FILTERABLE_PATH("event_name")], Any, Op) of
- {ok, Val} ->
- lookup(T, Val, Op);
- _ ->
- lookup(T, get_variable([], "event_name", Any), Op)
- end;
-
-lookup([{varid, ID}|T],
- #'CosNotification_StructuredEvent'{header =
- #'CosNotification_EventHeader'{variable_header = VS},
- filterable_data = FS,
- remainder_of_body = Any}, Op) ->
- lookup(T, get_variable(VS++FS, ID, Any), Op);
-lookup([{varid, ID}|T], Any, Op) ->
- case locate_var([?VARIABLE_PATH(ID), ?FILTERABLE_PATH(ID)], Any, Op) of
- {ok, Val} ->
- lookup(T, Val, Op);
- _ ->
- lookup(T, get_variable([], ID, Any), Op)
- end;
-
-%%------- dotid --------
-%% First level
-lookup([{dotid, "header"}|T],
- #'CosNotification_StructuredEvent'{header = S}, Op) ->
- lookup(T, S, Op);
-lookup([{dotid, "filterable_data"}|T],
- #'CosNotification_StructuredEvent'{filterable_data = S}, Op) ->
- lookup(T, S, Op);
-
-lookup([{dotid, remainder_of_body}|T],
- #'CosNotification_StructuredEvent'{remainder_of_body = S}, Op) ->
- lookup(T, S, Op);
-%% Second level. Previous token must have been header
-lookup([{dotid, "fixed_header"}|T],
- #'CosNotification_EventHeader'{fixed_header = S}, Op) ->
- lookup(T, S, Op);
-lookup([{dotid, "variable_header"}|T],
- #'CosNotification_EventHeader'{variable_header = S}, Op) ->
- lookup(T, S, Op);
-%% Third level. Previous token must have been fixed_header.
-lookup([{dotid, "event_type"}|T],
- #'CosNotification_FixedEventHeader'{event_type = S}, Op) ->
- lookup(T, S, Op);
-lookup([{dotid, "event_name"}|T],
- #'CosNotification_FixedEventHeader'{event_name = S}, Op) ->
- lookup(T, S, Op);
-%% Fourth level. Previous token must have been event_type
-lookup([{dotid, "domain_name"}|T], #'CosNotification_EventType'{domain_name = S}, Op) ->
- lookup(T, S, Op);
-lookup([{dotid, "type_name"}|T], #'CosNotification_EventType'{type_name = S}, Op) ->
- lookup(T, S, Op);
-
-%% Leaf expressions
-lookup([{dotid, "name"}|T], #'CosNotification_Property'{name=S}, Op) ->
- lookup(T, S, Op);
-lookup([{dotid, "value"}|T], #'CosNotification_Property'{value=S}, Op) ->
- lookup(T, S, Op);
-
-lookup([{dotid, ID}|T],
- #'CosNotification_StructuredEvent'{remainder_of_body = Any}, Op) ->
- lookup(T, get_variable([], ID, Any), Op);
-lookup([{dotid, ID}|T], Any, Op) ->
- lookup(T, get_variable([], ID, Any), Op);
-
-lookup([{associd, ID}|T], S, Op) when is_list(S) ->
- %% Refers to an associative array, i.e., a list of
- %% #'CosNotification_Property'{name=ID, value=A}
- lookup(T, get_variable(S, ID, false), Op);
-
-lookup([{dotint, Position}|T], S, Op) when is_record(S, any) ->
- lookup(T, element(Position+2, any:get_value(S)), Op);
-lookup([{dotint, Position}|T], S, Op) ->
- lookup(T, element(Position+2, S), Op);
-
-lookup([{uint, ID}|T], S, Op) when is_record(S, any) ->
- lookup([{uint, ID}|T], any:get_value(S), Op);
-lookup([{uint, ID} |T], S, Op) when is_tuple(S) ->
- case catch element(2, S) of
- ID ->
- %% The supplied union do contain the requested discriminator.
- lookup(T, element(3, S), Op);
- _Other when Op == exist_component ->
- throw({error, {bad_id, "Bad Union ID"}});
- Other ->
- %% Check if default is allowed.
- M = element(1, S),
- case catch M:tc() of
- {tk_union,_,_,_,DefNo, UList} ->
- %% {tk_union, Id, Name, DiscrTC, Default, ElementList}
- case switch2alias(UList, ID) of
- {ok, [], _} ->
- throw({error, {bad_id, "Bad Union ID"}});
- {ok, default, _} when DefNo >= 0 ->
- lookup(T, element(3, S), Op);
- {ok, List, _} ->
- case lists:member(Other, List) of
- true ->
- lookup(T, element(3, S), Op);
- _->
- throw({error, {bad_id, "Bad Union ID"}})
- end
- end
- end
- end;
-lookup([{ustr, ID}|T], S, Op) when is_record(S, any) ->
- lookup([{ustr, ID}|T], any:get_value(S), Op);
-lookup([{ustr, ID}|T], S, Op) when is_tuple(S) ->
- M = element(1, S),
- case catch M:tc() of
- {tk_union,_,_,_,DefNo, UList} ->
- case id2switch(UList, ID) of
- [default] when DefNo >= 0 ->
- lookup(T, element(3, S), Op);
- [default] ->
- throw({error, {bad_id, "Bad Union ID supplied"}});
- Found ->
- case catch lists:member(element(2, S), Found) of
- true ->
- lookup(T, element(3, S), Op);
- _ ->
- throw({error, {bad_id, "Bad Union ID supplied"}})
- end
- end
- end;
-lookup([default|T], S, Op) when is_record(S, any) ->
- lookup([default|T], any:get_value(S), Op);
-lookup([default|T], S, Op) when is_tuple(S) ->
- M = element(1, S),
- case catch M:tc() of
- {tk_union,_,_,_,DefNo, _UList} when DefNo < 0 ->
- %% {tk_union, Id, Name, DiscrTC, Default, ElementList}
- throw({error, {bad_id, "No default discriminator"}});
- {tk_union,_,_,_,_DefNo, UList} ->
- %% {tk_union, Id, Name, DiscrTC, Default, ElementList}
- %% Check if the label really is default.
- case lists:keymember(element(2, S), 1, UList) of
- false ->
- lookup(T, element(3, S), Op);
- _->
- throw({error, {bad_id, "Bad Union"}})
- end;
- _->
- throw({error, {bad_id, "Bad Union"}})
- end;
-
-lookup([{arrindex, Index}|T], S, Op) when is_tuple(S) ->
- %% The OMG uses c/c++ index. We must add one.
- lookup(T, element(Index+1,S), Op);
-
-%%%%%%%%%%%%%%%%%%%%%%% LEAF EXPRESSIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% got '$._length', which maps to the 'remainder_of_body'
-lookup(['_length'],
- #'CosNotification_StructuredEvent'{remainder_of_body = Any}, _Op) ->
- {ok, length(any:get_value(Any))};
-lookup(['_length'], S, _Op) when is_record(S, any) ->
- {ok, length(any:get_value(S))};
-lookup(['_length'], S, _Op) when is_list(S) ->
- {ok, length(S)};
-lookup(['_length'], S, _Op) when is_tuple(S) ->
- {ok, length(tuple_to_list(S))};
-
-%% got '$._d', which maps to the 'remainder_of_body'
-%% The discriminator may, accordiong to the CORBA specification, be (2.3/p3-37):
-%% * integer_type
-%% * char_type
-%% * boolean_type
-%% * enum_type
-%% * scoped_name
-lookup(['_d'],
- #'CosNotification_StructuredEvent'{remainder_of_body = Any},
- default_component) ->
- lookup(['_d'], any:get_value(Any), default_component);
-lookup(['_d'], S, default_component) when is_record(S, any) ->
- lookup(['_d'], any:get_value(S), default_component);
-lookup(['_d'], S, default_component) ->
- M = element(1, S),
- case catch M:tc() of
- {tk_union,_,_,_,DefNo,_} when DefNo < 0 ->
- %% '-1' indicates that no default value may exist.
- {ok, false};
- {tk_union,_,_,_,_,UList} ->
- %% May be using the default setting; check if the Value is in the list.
- {ok, not lists:keymember(element(2, S), 1, UList)};
- _ ->
- {ok, false}
- end;
-lookup(['_d'],
- #'CosNotification_StructuredEvent'{remainder_of_body = Any}, _Op) ->
- {ok, element(2, any:get_value(Any))};
-lookup(['_d'], S, _Op) when is_record(S, any) ->
- {ok, element(2, any:get_value(S))};
-lookup(['_d'], S, _Op) ->
- {ok, element(2, S)};
-
-
-lookup(['_type_id'], S, _Op) when is_record(S,'CosNotification_StructuredEvent') ->
- {ok, "StructuredEvent"};
-lookup(['_type_id'], S, _Op) when is_record(S,'CosNotification_EventHeader') ->
- {ok, "EventHeader"};
-lookup(['_type_id'], S, _Op) when is_record(S,'CosNotification_FixedEventHeader') ->
- {ok, "FixedEventHeader"};
-lookup(['_type_id'], S, _Op) when is_record(S,'CosNotification_EventType') ->
- {ok, "EventType"};
-lookup(['_type_id'], S, _Op) when is_record(S,'CosNotification_Property') ->
- {ok, "Property"};
-lookup(['_type_id'], S, _Op) when is_tuple(S) ->
- M=element(1, S),
- Name = case catch M:tc() of
- {tk_union,_,ID,_,_,_} ->
- ID;
- {tk_enum, _, ID, _} ->
- ID;
- {tk_exception, _, ID, _} ->
- ID;
- {tk_alias, _, ID, _} ->
- ID;
- {tk_struct,_,ID,_} ->
- ID
- end,
- {ok, Name};
-
-lookup(['_repos_id'], S, _Op) when is_record(S,'CosNotification_StructuredEvent') ->
- {ok, 'CosNotification_StructuredEvent':id()};
-lookup(['_repos_id'], S, _Op) when is_record(S,'CosNotification_EventHeader') ->
- {ok, 'CosNotification_EventHeader':id()};
-lookup(['_repos_id'], S, _Op) when is_record(S,'CosNotification_FixedEventHeader') ->
- {ok, 'CosNotification_FixedEventHeader':id()};
-lookup(['_repos_id'], S, _Op) when is_record(S,'CosNotification_EventType') ->
- {ok, 'CosNotification_EventType':id()};
-lookup(['_repos_id'], S, _Op) when is_record(S,'CosNotification_Property') ->
- {ok, 'CosNotification_Property':id()};
-lookup(['_repos_id'], S, _Op) when is_tuple(S) ->
- M = element(1, S),
- {ok, M:id()};
-
-lookup(_, _, _) ->
- error.
-
-
-%%------------------------------------------------------------
-%% function : locate_var
-%% Arguments: Paths - A list of path-lists which tells us where
-%% to search for runtime variables and in which
-%% order.
-%% S - Data
-%% Op - se lookup/3
-%% Returns : {error, _} |
-%% {ok, Val}
-%%------------------------------------------------------------
-locate_var([], _S, _) ->
- {error, "not found"};
-locate_var([H|T], S, Op) ->
- case catch lookup(H, S, Op) of
- {ok, Val} ->
- {ok,Val};
- _ ->
- locate_var(T, S, Op)
- end.
-
-%%------------------------------------------------------------
-%% function : id2switch
-%% Arguments: UList - The list of elements contained in the
-%% Union TypeCode.
-%% ID - string() eq name of element.
-%% Returns : Acc - A list of switches related to given ID.
-%%------------------------------------------------------------
-id2switch(UList, ID) ->
- id2switch(UList, ID, [], false).
-id2switch([], _, Acc, _) ->
- Acc;
-id2switch([{Sw, ID, _}|T], ID, Acc, _) ->
- id2switch(T, ID, [Sw|Acc], true);
-id2switch([_|_T], _ID, Acc, true) ->
- Acc;
-id2switch([_|T], ID, Acc, Found) ->
- id2switch(T, ID, Acc, Found).
-
-%%------------------------------------------------------------
-%% function : switch2alias
-%% Arguments: UList - The list of elements contained in the
-%% Union TypeCode.
-%% Switch - the union discriminator.
-%% Returns : Acc - A list of switches that are defined with the same
-%% ID - The switches common ID.
-%% Comment : A union IDL code can look like:
-%% union Union switch(long) {
-%% case 1:
-%% case 2: long ID; };
-%% In this case supplying Switch == 1 (or) the result
-%% should be {ok, [1,2], "ID"}
-%%------------------------------------------------------------
-switch2alias([], _Switch) ->
- %% Is it really possible to define an empty union??
- {ok, [], undefined};
-switch2alias([{Sw, ID, TC}|UList], Switch) ->
- switch2alias([{Sw, ID, TC}|UList], Switch, [], ID, false).
-
-
-switch2alias([{default, ID, _}], _, _, _, false) ->
- {ok, default, ID};
-switch2alias([], _, _Acc, _, false) ->
- {ok, [], undefined};
-switch2alias([], _, Acc, PreviousID, _) ->
- {ok, Acc, PreviousID};
-
-%% Seen the ID before but just found the correct switch, e.g.,
-%% [... {0,"K",{tk_string,0}}, {2,"K",{tk_string,0}}...] and switch eq '2'
-switch2alias([{Switch, PreviousID, _}|T], Switch, Acc, PreviousID, _Found) ->
- switch2alias(T, Switch, [Switch|Acc], PreviousID, true);
-
-%% First time for this ID and found the correct switch
-switch2alias([{Switch, ID, _}|T], Switch, _Acc, _PreviousID, false) ->
- switch2alias(T, Switch, [Switch], ID, true);
-
-%% Seen this ID and found the correct switch before.
-switch2alias([{Sw, PreviousID, _}|T], Switch, Acc, PreviousID, true) ->
- switch2alias(T, Switch, [Sw|Acc], PreviousID, true);
-
-%% Seen this ID but not found the correct switch.
-switch2alias([{Sw, PreviousID, _}|T], Switch, Acc, PreviousID, false) ->
- switch2alias(T, Switch, [Sw|Acc], PreviousID, false);
-
-%% No more of the correct ID/Switch. Done.
-switch2alias([{_, _ID, _}|_], _, Acc, PreviousID, true) ->
- {ok, Acc, PreviousID};
-%% Not found correct switch and ID is updated.
-switch2alias([{Sw, ID, _}|T], Switch, _Acc, _PreviousID, Found) ->
- switch2alias(T, Switch, [Sw], ID, Found).
-
-
-%%------------------------------------------------------------
-%% function : get_field
-%% Arguments: ID - element name
-%% List - The list of elements contained in the
-%% TypeCode.
-%% Returns : false |
-%% offset
-%%------------------------------------------------------------
-get_field(ID, List) ->
- get_field(ID, List, 2).
-get_field(_ID, [], _) ->
- false;
-get_field(ID, [ID|_], I) ->
- %% Memberlists in enum.
- I;
-get_field(ID, [{ID,_}|_], I) ->
- %% Memberlists in structs.
- I;
-get_field(ID, [_|T], I) ->
- get_field(ID, T, I+1).
-
-%%------------------------------------------------------------
-%% function : check_types
-%% Arguments: A sequence of CosNotification::EventType{}, i.e.,
-%% name-value pairs.
-%% Returns : {ok, WhichType, WC}
-%% WhichType - type/domain/both
-%% WC - [Types using wildcard]
-%%------------------------------------------------------------
-%% With check_types we try to determin if one or more EventTypes force us to check
-%% all events against this constraint. For example:
-%% EventType A1 has domain_name="car",type_name = "*"
-%% EventType A2 has domain_name="*",type_name = "DodgeViper"
-%% Since A1 says that we must test against any type_name and A2
-%% against any domain_name, we must test all events using these permutations.
-%% It's better to do these test now instead of when we are up and running. But
-%% if a client change the constraints VERY often it's up to them and they have
-%% to accept the delay.
-%%------------------------------------------------------------
-
-%% If types is an empty list it means that this constraint must be used
-%% for all events.
-check_types([]) -> true;
-check_types(Types) -> check_types(Types, both, []).
-check_types([], Which, WildCard) -> {ok, Which, WildCard};
-%% The following cases means that all events matches.
-check_types([#'CosNotification_EventType'{domain_name="",type_name = ""}|_T],_,_) ->
- true;
-check_types([#'CosNotification_EventType'{domain_name="",type_name = "*"}|_T],_,_) ->
- true;
-check_types([#'CosNotification_EventType'{domain_name="*",type_name = ""}|_T],_,_) ->
- true;
-check_types([#'CosNotification_EventType'{domain_name="*",type_name = "*"}|_T],_,_) ->
- true;
-%% The following cases means that all events must be tested using this constraint.
-check_types([#'CosNotification_EventType'{domain_name="",type_name = Ty}|T], domain,WC) when is_list(Ty) ->
- check_wildcard(T, all, WC, "", Ty);
-check_types([#'CosNotification_EventType'{domain_name="*",type_name = Ty}|T], domain, WC) when is_list(Ty) ->
- check_wildcard(T, all, WC, "", Ty);
-check_types([#'CosNotification_EventType'{domain_name=Do,type_name = ""}|T], type,WC) when is_list(Do) ->
- check_wildcard(T, all, WC, Do, "");
-check_types([#'CosNotification_EventType'{domain_name=Do,type_name = "*"}|T], type,WC) when is_list(Do) ->
- check_wildcard(T, all, WC, Do, "");
-%% The following cases is used to prevent other cases from converting,
-%% for example, all->type.
-check_types([#'CosNotification_EventType'{domain_name="",type_name = Ty}|T], all,WC) when is_list(Ty) ->
- check_wildcard(T, all, WC, "", Ty);
-check_types([#'CosNotification_EventType'{domain_name="*",type_name = Ty}|T], all,WC) when is_list(Ty) ->
- check_wildcard(T, all, WC, "", Ty);
-check_types([#'CosNotification_EventType'{domain_name=Do,type_name = ""}|T], all,WC) when is_list(Do) ->
- check_wildcard(T, all, WC, Do, "");
-check_types([#'CosNotification_EventType'{domain_name=Do,type_name = "*"}|T], all,WC) when is_list(Do) ->
- check_wildcard(T, all, WC, Do, "");
-%% The following cases means that all events with matching Type must be
-%% tested using this constraint.
-check_types([#'CosNotification_EventType'{domain_name="",type_name = Ty}|T], _W,WC) when is_list(Ty) ->
- check_wildcard(T, type, WC, "", Ty);
-check_types([#'CosNotification_EventType'{domain_name="*",type_name = Ty}|T], _W,WC) when is_list(Ty) ->
- check_wildcard(T, type, WC, "", Ty);
-%% The following cases means that all events with matching Domain must be
-%% tested using this constraint.
-check_types([#'CosNotification_EventType'{domain_name=Do,type_name = ""}|T], _W,WC) when is_list(Do) ->
- check_wildcard(T, domain, WC, Do, "");
-check_types([#'CosNotification_EventType'{domain_name=Do,type_name = "*"}|T], _W,WC) when is_list(Do) ->
- check_wildcard(T, domain, WC, Do, "");
-%% Sorry, no shortcuts.
-check_types([#'CosNotification_EventType'{domain_name=Do,type_name=Ty}|T], W,WC) when is_list(Do) andalso is_list(Ty) ->
- check_wildcard(T, W, WC, Do, Ty);
-check_types([H|_], _,_) when is_record(H, 'CosNotification_EventType') ->
- %% Not valid.
- corba:raise(#'CosNotifyComm_InvalidEventType'{type=H});
-check_types(_,_,_) ->
- %% Wasn't even a correct input.
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-check_wildcard(Types, Which, WC, Domain, Type) ->
- NewWC =
- case {string:chr(Domain, $*), string:chr(Type, $*)} of
- {0, 0} ->
- WC;
- {0, _}->
- [{type, Domain, convert_wildcard(Type, [])}|WC];
- {_, 0}->
- [{domain, convert_wildcard(Domain, []), Type}|WC];
- _->
- [{both, convert_wildcard(Domain, []), convert_wildcard(Type, [])}|WC]
- end,
- check_types(Types, Which, NewWC).
-
-%% Change '*' to '.*', see re:compile/1 documentation.
-convert_wildcard([], Acc) ->
- case re:compile(lists:reverse(Acc)) of
- {ok, Expr} ->
- Expr;
- _ ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO})
- end;
-convert_wildcard([$*|T], Acc) ->
- convert_wildcard(T, [$*, $.|Acc]);
-convert_wildcard([H|T], Acc) ->
- convert_wildcard(T, [H|Acc]).
-
-%%------------------------------------------------------------
-%% function : match_types
-%% Arguments: A sequence of {Which, Domain, Type}, i.e., the same as
-%% returned from cosNotification_Filter:check_types/3
-%% Returns : bolean()
-%%------------------------------------------------------------
-match_types(_, _, []) ->
- false;
-match_types(Domain, Type, [{domain, WCDomain, Type}|T]) ->
- L=length(Domain),
- case catch re:run(Domain, WCDomain) of
- nomatch ->
- match_types(Domain, Type, T);
- {match, [{0, L}]} ->
- true;
- _->
- match_types(Domain, Type, T)
- end;
-match_types(Domain, Type, [{type, Domain, WCType}|T]) ->
- L=length(Type),
- case catch re:run(Type, WCType) of
- nomatch ->
- match_types(Domain, Type, T);
- {match, [{0, L}]} ->
- true;
- _->
- match_types(Domain, Type, T)
- end;
-match_types(Domain, Type, [{both, WCDomain, WCType}|T]) ->
- L1=length(Domain),
- case catch re:run(Domain, WCDomain) of
- nomatch ->
- match_types(Domain, Type, T);
- {match, [{0, L1}]} ->
- L2=length(Type),
- case catch re:run(Type, WCType) of
- nomatch ->
- match_types(Domain, Type, T);
- {match, [{0, L2}]} ->
- true;
- _ ->
- match_types(Domain, Type, T)
- end;
- _->
- match_types(Domain, Type, T)
- end;
-match_types(Domain, Type, [_|T]) ->
- match_types(Domain, Type, T).
-
-%%------------------------------------------------------------
-%% function : validate_types
-%% Arguments: A sequence of CosNotification::EventType{}, i.e.,
-%% name-value pairs.
-%% Returns : ok |
-%% {'EXCEPTION', #'CosNotifyComm_InvalidEventType'{}}
-%%------------------------------------------------------------
-
-validate_types([]) ->
- ok;
-validate_types([#'CosNotification_EventType'{domain_name=Do,type_name=Ty}|T])
- when is_list(Do) andalso is_list(Ty) ->
- validate_types(T);
-validate_types([H|_])
- when is_record(H, 'CosNotification_EventType') ->
- %% Not valid.
- corba:raise(#'CosNotifyComm_InvalidEventType'{type=H});
-validate_types(_) ->
- %% Wasn't even a correct input.
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/cosNotification/src/cosNotification_Grammar.yrl b/lib/cosNotification/src/cosNotification_Grammar.yrl
deleted file mode 100644
index f4a42d022e..0000000000
--- a/lib/cosNotification/src/cosNotification_Grammar.yrl
+++ /dev/null
@@ -1,168 +0,0 @@
-%%--------------------------------------------------------------------
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%--------------------------------------------------------------------
-%% File : cosNotification_Grammar.yrl
-%% Purpose : Implement the constraint grammar for CosNotification filters.
-%%--------------------------------------------------------------------
-
-Nonterminals
- '<toplevel>' '<constraint>' '<expr>' '<bool>' '<bool_or>' '<Ident>'
- '<bool_and>' '<bool_compare>' '<expr_in>' '<expr_twiddle>' '<term>'
- '<factor_not>' '<factor>' '<Component>' '<CompExt>' '<CompDot>' '<UnionVal>'.
-
-Terminals
-% 'dbslsh' 'bslshd'
- 'bslsh' 'ident' 'string'
- '_length' '_d''_type_id' '_repos_id'
- 'not' 'or' 'and' 'num'
- 'in' '~' '.' 'dollar'
- 'ADDOP' 'RELOP' 'MULOP' 'default' 'exist'
- 'TRUE' 'FALSE'
- '(' ')' '[' ']' 'int'.
-
-Left 100 'or'.
-Left 200 'and'.
-%Nonassoc 300 'RELOP'. % '==', '!=', '<', '>', '<=', '=>'
-Left 300 'RELOP'.
-%Nonassoc 400 'in'.
-Left 400 'in'.
-%Nonassoc 500 '~'.
-Left 500 '~'.
-Left 600 'ADDOP'. % '+', '-'
-Left 700 'MULOP'. % '*', '/'
-Unary 800 'not'.
-Unary 900 'exist'.
-Unary 900 'default'.
-%Unary 900 'u-'. % unary minus
-
-Rootsymbol '<toplevel>'.
-Endsymbol '$end'.
-
-'<toplevel>' -> '$empty' : '$empty'.
-'<toplevel>' -> '<constraint>' : '$1'.
-
-'<constraint>' -> '<bool>' : '$1'.
-
-'<bool>' -> '<bool_or>' : '$1'.
-
-'<bool_or>' -> '<bool_or>' 'or' '<bool_and>' : {'or', '$1', '$3'}.
-'<bool_or>' -> '<bool_and>' : '$1'.
-
-'<bool_and>' -> '<bool_and>' 'and' '<bool_compare>' : {'and', '$1', '$3'}.
-'<bool_and>' -> '<bool_compare>' : '$1'.
-
-'<bool_compare>' -> '<expr_in>' 'RELOP' '<expr_in>' : {element(2, '$2'), '$1', '$3'}.
-'<bool_compare>' -> '<expr_in>' : '$1'.
-
-'<expr_in>' -> '<expr_twiddle>' : '$1'.
-'<expr_in>' -> '<expr_twiddle>' 'in' '<Ident>' : {'in', '$1', '$3'}.
-'<expr_in>' -> '<expr_twiddle>' 'in' 'dollar' '<Component>' : {'in', '$1', examin_comp({'component', '$4'})}.
-
-'<expr_twiddle>' -> '<expr>' : '$1'.
-'<expr_twiddle>' -> '<expr>' '~' '<expr>' : {'~', '$1', '$3'}.
-
-'<expr>' -> '<term>' : '$1'.
-'<expr>' -> '<expr>' 'ADDOP' '<term>' : {element(2, '$2'), '$1', '$3'}.
-
-'<term>' -> '<factor_not>' : '$1'.
-'<term>' -> '<term>' 'MULOP' '<factor_not>' : {element(2, '$2'), '$1', '$3'}.
-
-'<factor_not>' -> '<factor>' : '$1'.
-'<factor_not>' -> 'not' '<factor>' : {'not', '$2'}.
-
-'<factor>' -> '(' '<bool_or>' ')' : '$2'.
-'<factor>' -> 'num' : element(2, '$1').
-'<factor>' -> 'int' : element(2, '$1').
-'<factor>' -> 'string' : element(2, '$1').
-'<factor>' -> 'TRUE' : 'true'.
-'<factor>' -> 'FALSE' : 'false'.
-'<factor>' -> 'ADDOP' 'num' : create_unary(element(2, '$1'), element(2, '$2')).
-'<factor>' -> 'ADDOP' 'int' : create_unary(element(2, '$1'), element(2, '$2')).
-'<factor>' -> '<Ident>' : list_to_atom('$1').
-'<factor>' -> 'dollar' '<Component>' : examin_comp({component, '$2'}).
-'<factor>' -> 'default' 'dollar' '<Component>' : examin_comp({'default_component', '$3'}).
-'<factor>' -> 'exist' 'dollar' '<Component>' : examin_comp({'exist_component', '$3'}).
-
-%% The following rules are used to create Components. The format used is:
-%% [...]
-'<Component>' -> '.' '<CompDot>' : '$2'.
-'<Component>' -> '[' 'int' ']' '<CompExt>' : [{'arrindex', element(2, '$2')} | '$4']. %% CompArray
-'<Component>' -> '(' '<Ident>' ')' '<CompExt>' : [{'associd', '$2'} | '$4']. %%CompAssoc
-'<Component>' -> '<Ident>' '<CompExt>' : [{'varid', '$1'} | '$2']. %% run-time variable
-'<Component>' -> '$empty' : [].
-
-'<CompExt>' -> '.' '<CompDot>' : '$2'.
-'<CompExt>' -> '[' 'int' ']' '<CompExt>' : [{'arrindex', element(2, '$2')} | '$4']. %% CompArray
-'<CompExt>' -> '(' '<Ident>' ')' '<CompExt>' : [{'associd', '$2'} | '$4']. %%CompAssoc
-'<CompExt>' -> '$empty' : [].
-
-'<CompDot>' -> '<Ident>' '<CompExt>' : [{'dotid', '$1'} | '$2'].
-'<CompDot>' -> 'int' '<CompExt>' : [{'dotint', element(2, '$1')} | '$2']. %% ComPos
-'<CompDot>' -> '(' '<UnionVal>' ')' '<CompExt>' : ['$2' | '$4']. %% UnionPos
-'<CompDot>' -> '_length' : ['_length']. %% arrays or sequences ONLY
-'<CompDot>' -> '_d' : ['_d']. %% discriminated unions ONLY
-'<CompDot>' -> '_type_id' : ['_type_id']. %% ok if info can be obtained
-'<CompDot>' -> '_repos_id' : ['_repos_id']. %% ok if info can be obtained
-
-'<Ident>' -> 'ident' : element(2, '$1').
-'<Ident>' -> 'bslsh' 'ident' : element(2, '$2').
-
-'<UnionVal>' -> 'int' : {'uint', element(2, '$1')}.
-'<UnionVal>' -> 'ADDOP' 'int' : {'uint', create_unary(element(2, '$1'), element(2, '$2'))}.
-'<UnionVal>' -> 'string' : {'ustr', element(2, '$1')}.
-'<UnionVal>' -> '$empty': 'default'.
-
-Erlang code.
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%----------------------------------------------------------------------
-%% File : cosNotification_Grammar.erl
-%% Purpose : THIS FILE HAS BEEN GENERATED. DO NOT EDIT!!!!
-%%----------------------------------------------------------------------
-
--include("CosNotification_Definitions.hrl").
-
-create_unary('+', Val) when is_number(Val) -> Val;
-create_unary('-', Val) when is_number(Val) -> -Val;
-create_unary(_, _) -> return_error(0, "syntax error").
-
-examin_comp({T, []}) ->
- {T, '$empty'};
-examin_comp(V) ->
- V.
-
diff --git a/lib/cosNotification/src/cosNotification_Scanner.erl b/lib/cosNotification/src/cosNotification_Scanner.erl
deleted file mode 100644
index 31f27a8d78..0000000000
--- a/lib/cosNotification/src/cosNotification_Scanner.erl
+++ /dev/null
@@ -1,269 +0,0 @@
-%%----------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : cosNotification_Scanner.erl
-%% Purpose : Scan and pre-process a grammar.
-%%----------------------------------------------------------------------
-
--module('cosNotification_Scanner').
-
--export([scan/1]).
-
-scan(Str) ->
- RSL = scan(Str, 1, [], any),
- {ok, lists:reverse(RSL)}.
-
-
-%% Guard macros used at top scan functions only
--define(is_number(X), X >= $0, X =< $9).
--define(is_upper(X), X >= $A, X =< $Z).
--define(is_lower(X), X >= $a, X =< $z).
-
-%%----------------------------------------------------------------------
-%% scan
-%%
-%% A-Z
-scan([X|Str], Line, Out, Type) when ?is_upper(X) ->
- scan_name(Str, [X], Line, Out, Type);
-%% a-z
-scan([X|Str], Line, Out, Type) when ?is_lower(X) ->
- scan_name(Str, [X], Line, Out, Type);
-%% 0-9
-scan([X|Str], Line, Out, Type) when ?is_number(X) ->
- scan_number(Str, [X], Line, Out, Type);
-
-%% RELOP:s == != <= >= > <
-scan([$=,$= | Str], Line, Out, _Type) ->
- scan(Str, Line, [{'RELOP', '=='} | Out], any);
-scan([$!,$= | Str], Line, Out, _Type) ->
- scan(Str, Line, [{'RELOP', '!='} | Out], any);
-scan([$<,$= | Str], Line, Out, _Type) ->
- scan(Str, Line, [{'RELOP', '<='} | Out], any);
-scan([$>,$= | Str], Line, Out, _Type) ->
- scan(Str, Line, [{'RELOP', '>='} | Out], any);
-scan([$> | Str], Line, Out, _Type) ->
- scan(Str, Line, [{'RELOP', '>'} | Out], any);
-scan([$< | Str], Line, Out, _Type) ->
- scan(Str, Line, [{'RELOP', '<'} | Out], any);
-
-%% ADDOP:s + -
-scan([$+ | Str], Line, Out, Type) ->
- scan(Str, Line, [{'ADDOP', '+'} | Out], Type);
-scan([$- | Str], Line, Out, Type) ->
- scan(Str, Line, [{'ADDOP', '-'} | Out], Type);
-
-%% MULOP:s * /
-scan([$* | Str], Line, Out, _Type) ->
- scan(Str, Line, [{'MULOP', '*'} | Out], any);
-scan([$/ | Str], Line, Out, _Type) ->
- scan(Str, Line, [{'MULOP', '/'} | Out], any);
-
-%% TAB
-scan([9| T], Line, Out, Type) -> scan(T, Line, Out, Type);
-%% SP
-scan([32| T], Line, Out, Type) -> scan(T, Line, Out, Type);
-%% CR
-scan([$\r|Str], Line, Out, Type) ->
- scan(Str, Line, Out, Type);
-%% LF
-scan([$\n|Str], Line, Out, Type) ->
- scan(Str, Line+1, Out, Type);
-%% \\
-scan([92, 92 | Str], Line, Out, Type) ->
- scan(Str, Line, [{'dbslsh', Line} | Out], Type);
-%% \'
-scan([92, 39 | Str], Line, Out, Type) ->
- scan(Str, Line, [{'bslshd', Line} | Out], Type);
-%% '\'
-scan([92 | Str], Line, Out, Type) ->
- scan(Str, Line, [{'bslsh', Line} | Out], Type);
-%% '_'
-scan([$_ | Str], Line, Out, dollar) ->
- scan_name(Str, [$_], Line, Out, dollar);
-%% '$'
-scan([$$, 92 | Str], Line, Out, _Type) ->
- scan(Str, Line, [{'bslsh', Line}, {'dollar', Line} | Out], dollar);
-scan([$$ | Str], Line, Out, _Type) ->
- scan(Str, Line, [{'dollar', Line} | Out], dollar);
-scan([$"|Str], Line, Out, Type) ->
- scan_const(char, Str, [], Line, Out, Type);
-scan([$'|Str], Line, Out, Type) ->
- scan_const(string, Str, [], Line, Out, Type);
-
-%% Writing '+.<CompDot>' is not allowed ('+' or '-' are only allowed
-%% as unary for <UnionVal> (within a component) which must be en integer).
-scan([$. | Str], Line, [{'ADDOP', Op}|Out], _) ->
- scan_frac(Str, [$.], Line, [{'ADDOP', Op}|Out], any);
-%% Must be a <CompDot>
-scan([$. | Str], Line, Out, dollar) ->
- scan(Str, Line, [{'.',Line} | Out], dollar);
-%% Number
-scan([$. | Str], Line, Out, Type) ->
- scan_frac(Str, [$.], Line, Out, Type);
-scan([C|Str], Line, Out, Type) ->
- scan(Str, Line, [{list_to_atom([C]), Line} | Out], Type);
-
-scan([], _Line, Out, _Type) ->
- Out.
-
-%%----------------------------------------------------------------------
-%% scan_name
-%%
-
-scan_number([X|Str], Accum, Line, Out, Type) when ?is_number(X) ->
- scan_number(Str, [X|Accum], Line, Out, Type);
-scan_number([X|Str], Accum, Line, Out, dollar) when X==$. ->
- scan(Str, Line, [{'.', Line},
- {'int', list_to_integer(lists:reverse(Accum))} | Out], dollar);
-scan_number([X|Str], Accum, Line, Out, Type) when X==$. ->
- scan_frac(Str, [X|Accum], Line, Out, Type);
-scan_number([X|Str], Accum, Line, Out, Type) when X==$e ->
- scan_exp(Str, [X|Accum], Line, Out, Type);
-scan_number([X|Str], Accum, Line, Out, Type) when X==$E ->
- scan_exp(Str, [X|Accum], Line, Out, Type);
-scan_number(Str, Accum, Line, Out, Type) ->
- scan(Str, Line, [{'int', list_to_integer(lists:reverse(Accum))} | Out], Type).
-
-
-%% Floating point number scan.
-%%
-%% Non trivial scan. A float consists of an integral part, a
-%% decimal point, a fraction part, an e or E and a signed integer
-%% exponent. Either the integer part or the fraction part but not
-%% both may be missing, and either the decimal point or the
-%% exponent part but not both may be missing. The exponent part
-%% must consist of an e or E and a possibly signed exponent.
-%%
-%% Analysis shows that "1." ".7" "1e2" ".5e-3" "1.7e2" "1.7e-2"
-%% is allowed and "1" ".e9" is not. The sign is only allowed just
-%% after an e or E. The scanner reads a number as an integer
-%% until it encounters a "." so the integer part only error case
-%% will not be caught in the scanner (but rather in expression
-%% evaluation)
-
-scan_frac([$e | _Str], [$.], _Line, _Out, _Type) ->
- {error, "illegal_float"};
-scan_frac([$E | _Str], [$.], _Line, _Out, _Type) ->
- {error, "illegal_float"};
-scan_frac(Str, Accum, Line, Out, Type) ->
- scan_frac2(Str, Accum, Line, Out, Type).
-
-scan_frac2([X|Str], Accum, Line, Out, Type) when ?is_number(X) ->
- scan_frac2(Str, [X|Accum], Line, Out, Type);
-scan_frac2([X|Str], Accum, Line, Out, Type) when X==$e ->
- scan_exp(Str, [X|Accum], Line, Out, Type);
-scan_frac2([X|Str], Accum, Line, Out, Type) when X==$E ->
- scan_exp(Str, [X|Accum], Line, Out, Type);
-%% Since '.2' is allowed, we add '0' in front to be sure (erlang do not allow
-%% list_to_float(".2") and list_to_float("0.2") eq. list_to_float("00.2")).
-scan_frac2(Str, Accum, Line, Out, Type) ->
- scan(Str, Line, [{'num', list_to_float([$0|lists:reverse(Accum)])} | Out], Type).
-
-scan_exp([X|Str], Accum, Line, Out, Type) when X==$- ->
- scan_exp2(Str, [X|Accum], Line, Out, Type);
-scan_exp(Str, Accum, Line, Out, Type) ->
- scan_exp2(Str, Accum, Line, Out, Type).
-
-scan_exp2([X|Str], Accum, Line, Out, Type) when ?is_number(X) ->
- scan_exp2(Str, [X|Accum], Line, Out, Type);
-%% Since '.2' is allowed, we add '0' in front to be sure (erlang do not allow
-%% list_to_float(".2")).
-scan_exp2(Str, Accum, Line, Out, Type) ->
- scan(Str, Line, [{'num', list_to_float([$0|lists:reverse(Accum)])} | Out], Type).
-
-
-scan_name([X|Str], Accum, Line, Out, Type) when ?is_upper(X) ->
- scan_name(Str, [X|Accum], Line, Out, Type);
-scan_name([X|Str], Accum, Line, Out, Type) when ?is_lower(X) ->
- scan_name(Str, [X|Accum], Line, Out, Type);
-scan_name([X|Str], Accum, Line, Out, Type) when ?is_number(X) ->
- scan_name(Str, [X|Accum], Line, Out, Type);
-scan_name([$_|Str], Accum, Line, Out, dollar) ->
- scan_name(Str, [$_|Accum], Line, Out, dollar);
-scan_name(S, Accum, Line, [{bslsh,LL} | Out], Type) ->
- %% An escaped identifier.
- L = lists:reverse(Accum),
- scan(S, Line, [{'ident', L}, {bslsh,LL} | Out], Type);
-scan_name(S, Accum, Line, Out, Type) ->
- L = lists:reverse(Accum),
- {X, NewType} = case check_name(L) of
- false ->
- {{'ident', L}, Type};
- _ ->
- {{list_to_atom(L), Line}, any}
- end,
- scan(S, Line, [X | Out], NewType).
-
-%% Shall scan a constant
-scan_const(char, [$" | Rest], Accum, Line, Out, Type) ->
- scan(Rest, Line,
- [{'ident', list_to_atom(lists:reverse(Accum))} | Out], Type);
-scan_const(char, [], _Accum, _Line, Out, _Type) -> %% Bad string
-% {error, "bad_string"};
- Out;
-scan_const(string, [$' | Rest], Accum, Line, Out, Type) ->
- scan(Rest, Line,
- [{'string', lists:reverse(Accum)} | Out], Type);
-scan_const(Mode, [$\\, C | Rest], Accum, Line, Out, Type) ->
- case escaped_char(C) of
- error ->
- %% Bad escape character
- %% {error, "bad_escape_character"};
- scan_const(Mode, Rest, [C | Accum], Line, Out, Type);
- EC ->
- scan_const(Mode, Rest, [EC | Accum], Line, Out, Type)
- end;
-scan_const(Mode, [C | Rest], Accum, Line, Out, Type) ->
- scan_const(Mode, Rest, [C | Accum], Line, Out, Type).
-
-%% Escaped character. Escaped chars are repr as two characters in the
-%% input list of letters and this is translated into one char.
-escaped_char($n) -> $\n;
-escaped_char($t) -> $\t;
-escaped_char($v) -> $\v;
-escaped_char($b) -> $\b;
-escaped_char($r) -> $ ;
-escaped_char($f) -> $\f;
-escaped_char($a) -> $\a;
-escaped_char($\\) -> $\\;
-escaped_char($?) -> $?;
-escaped_char($') -> $';
-escaped_char($") -> $";
-%% Error
-escaped_char(_Other) -> error.
-
-
-check_name("exist") -> true;
-check_name("default") -> true;
-check_name("_length") -> true;
-check_name("_d") -> true;
-check_name("_type_id") -> true;
-check_name("_repos_id") -> true;
-check_name("not") -> true;
-check_name("or") -> true;
-check_name("and") -> true;
-check_name("FALSE") -> true;
-check_name("TRUE") -> true;
-check_name("in") -> true;
-check_name(_) -> false.
-
-
diff --git a/lib/cosNotification/src/cosNotification_eventDB.erl b/lib/cosNotification/src/cosNotification_eventDB.erl
deleted file mode 100644
index cd3c74d617..0000000000
--- a/lib/cosNotification/src/cosNotification_eventDB.erl
+++ /dev/null
@@ -1,1351 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2015. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : cosNotification_eventDB.erl
-%% Purpose :
-%% Purpose : This module is supposed to centralize Event storage.
-%% Comments:
-%% * Setting Order Policy to AnyOrder eq. Priority order
-%%
-%% * Setting Discard Policy to AnyOrder eq. RejectNewEvents.
-%%
-%% * DB ordering: Since the deliver- and discard-order may differ we need
-%% two ets-tables, both of type 'ordered_set'. They contain:
-%% - table 1 (T1): deliver order key and the associated event.
-%% - table 2 (T2): discard order key.
-%%
-%% When adding a new event we add, if necessary, related keys in T2.
-%% For example, if we should discard events in FIFO order, the delivery
-%% order may be set to Priority order. If the Max Event limit is reached
-%% we first look in T2 to find out which event to discard by using and
-%% reorder the key elements. T2 gives {TimeStamp, Priority}, which is used
-%% to lookup in T1 as {Priority, TimeStamp}.
-%% A TimeStamp is always included in the DB keys, even if FIFO or LIFO
-%% is used, since lots of events probably will have the same prioity and
-%% with a little bit of bad luck some events will never be delivered.
-%%
-%% Note: deliver order AnyOrder and PriorityOrder is equal since the later
-%% is defined as default.
-%% discard order AnyOrder and RejectNewEvents is equal since the later
-%% is defined as default.
-%% The keys used is ('-' indicates T2 is not needed and, thus, not instantiated):
-%%
-%% T1 policy T1 Key T2 Policy T2 Key
-%% ------------------------------------------------------------------
-%% DeadlineOrder {DL, Key, Prio} PriorityOrder {Prio, Key, DL}
-%% DeadlineOrder {DL, Key} FifoOrder {Key, DL}
-%% DeadlineOrder {DL, Key} LifoOrder {Key, DL}
-%% DeadlineOrder {DL, Key} RejectNewEvents -
-%% DeadlineOrder {DL, Key} DeadlineOrder -
-%% FifoOrder {Key, DL} DeadlineOrder {DL, Key}
-%% FifoOrder {Key, Prio} PriorityOrder {Prio, Key}
-%% FifoOrder Key RejectNewEvents -
-%% FifoOrder Key Fifo -
-%% FifoOrder Key Lifo -
-%% PriorityOrder {Prio, Key, DL} DeadlineOrder {DL, Key, Prio}
-%% PriorityOrder {Prio, Key} Fifo {Key, Prio}
-%% PriorityOrder {Prio, Key} Lifo {Key, Prio}
-%% PriorityOrder {Prio, Key} RejectNewEvents -
-%% ------------------------------------------------------------------
-%% DL == Deadline, Key == TimeStamp, Prio == Priority
-%%
-%% NOTE: If defined, the Discard DB Keys are the same as in Event DB, except
-%% that the first and last Key change place. {K1,K2}<->{K2,K1} and
-%% {K1,K2,K3}<->{K3,K2,K1}.
-%%----------------------------------------------------------------------
--module(cosNotification_eventDB).
-
-%%--------------- INCLUDES -----------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
--include_lib("cosTime/include/TimeBase.hrl").
-
-%% Application files
--include("CosNotification.hrl").
--include("CosNotifyChannelAdmin.hrl").
--include("CosNotifyComm.hrl").
--include("CosNotifyFilter.hrl").
-
--include("CosNotification_Definitions.hrl").
-
-%%--------------- EXPORTS ------------------------------------
-%% Internal Filter Functions
--export([validate_event/5,
- create_db/4,
- destroy_db/1,
- get_event/1,
- get_event/2,
- get_events/2,
- get_events/3,
- delete_events/1,
- update/2,
- update/4,
- add_event/2,
- add_event/4,
- add_and_get_event/2,
- add_and_get_event/3,
- add_and_get_event/4,
- add_and_get_event/5,
- gc_events/2,
- gc_events_local/4,
- gc_start/2,
- filter_events/2,
- filter_events/3,
- status/2]).
-
-%%--------------- DATA STRUCTURES ----------------------------
--record(dbRef, {orderRef, discardRef, orderPolicy, discardPolicy,
- defPriority, maxEvents, defStopT, startTsupport,
- stopTsupport, gcTime, gcLimit, timeRef}).
-
-
-
-%%--------------- DEFINES ------------------------------------
-
--define(CreateRef(OR, DR, O, D, DP, ME, DS, StaT, StoT, GT, GL, TR),
- #dbRef{orderRef=OR, discardRef=DR, orderPolicy=O, discardPolicy=D,
- defPriority=DP, maxEvents=ME, defStopT=DS, startTsupport=StaT,
- stopTsupport=StoT, gcTime=GT, gcLimit=round(ME*GL/100),
- timeRef=TR}).
-
-
--define(get_OrderP(DR), DR#dbRef.orderPolicy).
--define(get_DiscardP(DR), DR#dbRef.discardPolicy).
--define(get_OrderRef(DR), DR#dbRef.orderRef).
--define(get_DiscardRef(DR), DR#dbRef.orderRef).
--define(get_DefPriority(DR), DR#dbRef.defPriority).
--define(get_MaxEvents(DR), DR#dbRef.maxEvents).
--define(get_DefStopT(DR), DR#dbRef.defStopT).
--define(get_StartTsupport(DR), DR#dbRef.startTsupport).
--define(get_StopTsupport(DR), DR#dbRef.stopTsupport).
--define(get_GCTime(DR), DR#dbRef.gcTime).
--define(get_GCLimit(DR), DR#dbRef.gcLimit).
--define(get_TimeRef(DR), DR#dbRef.timeRef).
-
--define(set_OrderP(DR, O), DR#dbRef{orderPolicy = O}).
--define(set_DiscardP(DR, D), DR#dbRef{discardPolicy = D}).
--define(set_OrderRef(DR, E), DR#dbRef{orderRef = E}).
--define(set_DiscardRef(DR, E), DR#dbRef{orderRef = E}).
--define(set_DefPriority(DR, DP), DR#dbRef{defPriority = DP}).
--define(set_MaxEvents(DR, ME), DR#dbRef{maxEvents = ME}).
--define(set_DefStopT(DR, DS), DR#dbRef{defStopT = DS}).
--define(set_StartTsupport(DR, B), DR#dbRef{startTsupport = B}).
--define(set_StopTsupport(DR, B), DR#dbRef{stopTsupport = B}).
-
--define(is_StartTNotSupported(DR), DR#dbRef.startTsupport == false).
--define(is_StopTNotSupported(DR), DR#dbRef.stopTsupport == false).
--define(is_TimeoutNotUsed(DR), DR#dbRef.defStopT == 0).
-
-
-%%------------------------------------------------------------
-%% function : status
-%% Arguments: DBRef
-%% Key - which information we want.
-%% Returns : Data related to the Key.
-%%------------------------------------------------------------
-status(DBRef, eventCounter) ->
- ets:info(?get_OrderRef(DBRef), size);
-status(DBRef, {batchLimit, Limit}) ->
- case ets:info(?get_OrderRef(DBRef), size) of
- Current when is_integer(Current) andalso Current >= Limit ->
- ?debug_print("BATCH LIMIT (~p) REACHED, CONTAINS: ~p~n", [Limit, Current]),
- true;
- _Other ->
- ?debug_print("BATCH LIMIT (~p) NOT REACHED, CONTAINS: ~p~n",
- [Limit, _Other]),
- false
- end;
-status(DBRef, {batchLimit, Limit, TemporaryMax}) ->
- case ets:info(?get_OrderRef(DBRef), size) of
- Current when is_integer(Current) andalso Current >= TemporaryMax ->
- ?debug_print("MAX LIMIT (~p) REACHED, CONTAINS: ~p~n",
- [TemporaryMax, Current]),
- true;
- Current when is_integer(Current) andalso Current >= Limit ->
- ?debug_print("BATCH LIMIT (~p) REACHED, CONTAINS: ~p~n", [Limit, Current]),
- true;
- _Other ->
- ?debug_print("BATCH LIMIT (~p) NOT REACHED, CONTAINS: ~p~n",
- [Limit, _Other]),
- false
- end;
-status(_, _) ->
- error.
-
-
-%%------------------------------------------------------------
-%% function : gc_events_local
-%% Arguments: DBRef
-%% Returns :
-%% Comment : This function is intended for "emergency" GC, i.e.,
-%% when the DB must discard events we should first try
-%% to remove events with expired deadlines.
-%%------------------------------------------------------------
-gc_events_local(_, _, false, _) ->
- ok;
-gc_events_local(_, _, _, 0) ->
- ok;
-gc_events_local(ORef, DRef, _, _) ->
- gc_loop(ets:first(ORef), ORef, DRef).
-
-%%------------------------------------------------------------
-%% function : gc_events
-%% Arguments: DBRef
-%% Priority - 'low', 'medium' or 'high'; will determine
-%% how important a fast gc is.
-%% Returns :
-%% Comment : This function is intended for background GC.
-%%------------------------------------------------------------
-gc_events(DBRef, _Priority) when ?is_TimeoutNotUsed(DBRef) ->
- ok;
-gc_events(DBRef, _Priority) when ?is_StopTNotSupported(DBRef) ->
- ok;
-gc_events(DBRef, Priority) ->
- TS = erlang:monotonic_time(),
- {resolution, TR} = lists:keyfind(resolution, 1, erlang:system_info(os_monotonic_time_source)),
- case get(oe_GC_timestamp) of
- Num when TS > Num ->
- put(oe_GC_timestamp, TS + ?get_GCTime(DBRef) * TR),
- spawn_link(?MODULE, gc_start, [DBRef, Priority]);
- _->
- ok
- end.
-
-%%------------------------------------------------------------
-%% function : gc_start
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-gc_start(#dbRef{orderRef = ORef, discardRef = DRef}, Priority) ->
- process_flag(priority, Priority),
- gc_loop(ets:first(ORef), ORef, DRef).
-
-gc_loop('$end_of_table', _, _) ->
- ok;
-gc_loop(Key, ORef, DRef) ->
- [{Keys,DL,_,_,_}]=ets:lookup(ORef, Key),
- case check_deadline(DL) of
- true when DRef == undefined ->
- ets:delete(ORef, Key);
- true ->
- ets:delete(ORef, Key),
- gc_discard_DB(Keys, DRef);
- _ ->
- ok
- end,
- gc_loop(ets:next(ORef, Key), ORef, DRef).
-
-gc_discard_DB({Key1, Key2}, DRef) ->
- ets:delete(DRef, {Key2, Key1});
-gc_discard_DB({Key1, Key2, Key3}, DRef) ->
- ets:delete(DRef, {Key3, Key2, Key1}).
-
-%%------------------------------------------------------------
-%% function : create_FIFO_Key
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-create_FIFO_Key() ->
- {M, S, U} = erlang:timestamp(),
- -M*1000000000000 - S*1000000 - U.
-
-%%------------------------------------------------------------
-%% function : convert_FIFO_Key
-%% Arguments:
-%% Returns : A timestamp tuple
-%% Comment : Used when we must reuse a timestamp, i.e., only
-%% when we must reorder the DB.
-%%------------------------------------------------------------
-convert_FIFO_Key(Key) ->
- K = abs(Key),
- Secs = trunc(K/1000000),
- M = trunc(K/1000000000000),
- S = Secs-M*1000000,
- U = K - S*1000000-M*1000000000000,
- {M, S, U}.
-
-%%------------------------------------------------------------
-%% function : extract_priority
-%% Arguments: Event
-%% Defalt Value
-%% Mapping Filter Value
-%% - false value not needed (depends on QoS type)
-%% - undefined value needed but no filter associated.
-%% Returns :
-%%------------------------------------------------------------
-extract_priority(_, _, false) ->
- false;
-extract_priority(#'CosNotification_StructuredEvent'
- {header = #'CosNotification_EventHeader'
- {variable_header = VH}}, DefPriority, undefined) ->
- extract_value(VH, ?not_Priority, DefPriority);
-%% Maybe a unstructured event.
-extract_priority(_, DefPriority, undefined) ->
- DefPriority;
-extract_priority(_, _, PriorityOverride) ->
- %% Must have an associated MappingFilter for Priority.
- PriorityOverride.
-
-%%------------------------------------------------------------
-%% function : extract_start_time
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-extract_start_time(_, false, _) ->
- false;
-extract_start_time(#'CosNotification_StructuredEvent'
- {header = #'CosNotification_EventHeader'
- {variable_header = VH}}, _, TRef) ->
- ST = case extract_value(VH, ?not_StartTime, undefined) of
- UTC when is_record(UTC, 'TimeBase_UtcT') ->
- UTC;
- _ ->
- false
- end,
- convert_time(ST, TRef, erlang:timestamp());
-extract_start_time(_, _, _) ->
- false.
-
-%%------------------------------------------------------------
-%% function : extract_deadline
-%% Arguments: Structured Event
-%% Default Timeout Value - TimeT or UtcT (see cosTime).
-%% StopTSupported - boolean().
-%% TRef - reference to TimeService
-%% Mapping Filter Value
-%% - false eq. value not needed (depends on QoS type)
-%% - undefined eq. value needed but no filter associated.
-%% Now - used when we want to reuse old TimeStamp which
-%% must be done when changing QoS.
-%% Returns : A modified return from erlang:timestamp().
-%%------------------------------------------------------------
-extract_deadline(_, _, _, _, false) ->
- false;
-extract_deadline(Event, DefaultT, StopTSupported, TRef, MappingVal) ->
- extract_deadline(Event, DefaultT, StopTSupported, TRef, MappingVal, erlang:timestamp()).
-
-extract_deadline(_, _, _, _, false, _) ->
- false;
-extract_deadline(#'CosNotification_StructuredEvent'
- {header = #'CosNotification_EventHeader'
- {variable_header = VH}}, DefaultT, StopTSupported,
- TRef, undefined, Now) ->
- DL = case extract_value(VH, ?not_Timeout, undefined) of
- undefined when StopTSupported == true, TRef =/= undefined ->
- case extract_value(VH, ?not_StopTime, undefined) of
- undefined ->
- DefaultT;
- DefinedTime ->
- DefinedTime
- end;
- undefined ->
- DefaultT;
- DefinedTime ->
- DefinedTime
- end,
- convert_time(DL, TRef, Now);
-%% Maybe a unstructured event.
-extract_deadline(_, Time, _, TRef, undefined, Now) ->
- convert_time(Time, TRef, Now);
-extract_deadline(_, _, _, TRef, DOverride, Now) ->
- %% Must have an associated MappingFilter defining a Deadline.
- convert_time(DOverride, TRef, Now).
-
-convert_time(0, _, _) ->
- false;
-convert_time(UTC, TRef, {M,S,U}) when is_record(UTC, 'TimeBase_UtcT') ->
- case catch get_time_diff(UTC, TRef) of
- {'EXCEPTION', _} ->
- false;
- {'EXIT', _} ->
- false;
- DL ->
- MicroSecs = round(DL/10),
- Secs = round(MicroSecs/1000000),
- MegaSecs = round(Secs/1000000),
- {-M-MegaSecs, -S-Secs+MegaSecs, -U-MicroSecs+Secs}
- end;
-convert_time(DL, _, {M,S,U}) when is_integer(DL) ->
- MicroSecs = round(DL/10),
- Secs = round(MicroSecs/1000000),
- MegaSecs = round(Secs/1000000),
- {-M-MegaSecs, -S-Secs+MegaSecs, -U-MicroSecs+Secs};
-convert_time(_, _, _) ->
- false.
-
-
-get_time_diff(UTC, TRef) ->
- UTO = 'CosTime_TimeService':universal_time(TRef),
- UTO2 = 'CosTime_TimeService':uto_from_utc(TRef, UTC),
- TIO = 'CosTime_UTO':time_to_interval(UTO, UTO2),
- #'TimeBase_IntervalT'{lower_bound=LB, upper_bound = UB} =
- 'CosTime_TIO':'_get_time_interval'(TIO),
- UB-LB.
-
-check_deadline(DL) when is_tuple(DL) ->
- {M,S,U} = erlang:timestamp(),
- DL >= {-M,-S,-U};
-check_deadline(_DL) ->
- %% This case will cover if no timeout is set.
- false.
-
-check_start_time(ST) when is_tuple(ST) ->
- {M,S,U} = erlang:timestamp(),
- ST >= {-M,-S,-U};
-check_start_time(_ST) ->
- %% This case will cover if no earliest delivery time is set.
- true.
-
-%%------------------------------------------------------------
-%% function : extract_value
-%% Arguments: A Property Sequence
-%% ID - wanted property string()
-%% Other - default-value.
-%% Returns : Value associated with given ID or default value.
-%%------------------------------------------------------------
-extract_value([], _, Other) ->
- Other;
-extract_value([#'CosNotification_Property'{name=ID, value=V}|_], ID, _) ->
- any:get_value(V);
-extract_value([_H|T], ID, Other) ->
- extract_value(T, ID, Other).
-
-%%------------------------------------------------------------
-%% function : get_event
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-get_event(DBRef) ->
- get_event(DBRef, true).
-get_event(DBRef, Delete) ->
- case get_events(DBRef, 1, Delete) of
- {[], false} ->
- {[], false};
- {[], false, Keys} ->
- {[], false, Keys};
- {[Event], Bool} ->
- {Event, Bool};
- {[Event], Bool, Keys} ->
- {Event, Bool, Keys}
- end.
-
-%%------------------------------------------------------------
-%% function : get_events
-%% Arguments:
-%% Returns : A list of events (possibly empty) and a boolean
-%% indicating if event found.
-%% Comments : Try to extract Max events from the database.
-%%------------------------------------------------------------
-get_events(#dbRef{orderRef = ORef, discardRef = DRef}, Max) ->
- event_loop(ets:last(ORef), ORef, DRef, Max, [], [], true).
-
-get_events(#dbRef{orderRef = ORef, discardRef = DRef}, Max, Delete) ->
- event_loop(ets:last(ORef), ORef, DRef, Max, [], [], Delete).
-
-event_loop('$end_of_table', _, _, _, [], _, true) ->
- {[], false};
-event_loop('$end_of_table', _, _, _, [], [], _) ->
- {[], false, []};
-event_loop('$end_of_table', _ORef, _, _, Accum, _Keys, true) ->
- {lists:reverse(Accum), true};
-event_loop('$end_of_table', _ORef, _, _, Accum, Keys, _) ->
- {lists:reverse(Accum), true, Keys};
-event_loop(_, _ORef, _, 0, [], _Keys, true) ->
- %% Only possible if some tries to pull a sequence of 0 events.
- %% Should we really test for this case?
- {[], false};
-event_loop(_, _ORef, _, 0, [], Keys, _) ->
- {[], false, Keys};
-event_loop(_, _ORef, _, 0, Accum, _Keys, true) ->
- {lists:reverse(Accum), true};
-event_loop(_, _ORef, _, 0, Accum, Keys, _) ->
- {lists:reverse(Accum), true, Keys};
-event_loop(Key, ORef, undefined, Left, Accum, Keys, Delete) ->
- [{_,DL,ST,_PO,Event}]=ets:lookup(ORef, Key),
- case check_deadline(DL) of
- true ->
- ets:delete(ORef, Key),
- event_loop(ets:prev(ORef, Key), ORef, undefined,
- Left, Accum, Keys, Delete);
- false ->
- case check_start_time(ST) of
- true when Delete == true ->
- ets:delete(ORef, Key),
- event_loop(ets:prev(ORef, Key), ORef, undefined,
- Left-1, [Event|Accum], Keys, Delete);
- true ->
- event_loop(ets:prev(ORef, Key), ORef, undefined,
- Left-1, [Event|Accum], [{ORef, Key}|Keys], Delete);
- false ->
- event_loop(ets:prev(ORef, Key), ORef, undefined,
- Left, Accum, Keys, Delete)
- end
- end;
-event_loop({Key1, Key2}, ORef, DRef, Left, Accum, Keys, Delete) ->
- [{_,DL,ST,_PO,Event}]=ets:lookup(ORef, {Key1, Key2}),
- case check_deadline(DL) of
- true ->
- ets:delete(ORef, {Key1, Key2}),
- ets:delete(DRef, {Key2, Key1}),
- event_loop(ets:prev(ORef, {Key1, Key2}), ORef, DRef,
- Left, Accum, Keys, Delete);
- false ->
- case check_start_time(ST) of
- true when Delete == true ->
- ets:delete(ORef, {Key1, Key2}),
- ets:delete(DRef, {Key2, Key1}),
- event_loop(ets:prev(ORef, {Key1, Key2}), ORef, DRef,
- Left-1, [Event|Accum], Keys, Delete);
- true ->
- event_loop(ets:prev(ORef, {Key1, Key2}), ORef, DRef,
- Left-1, [Event|Accum],
- [{ORef, {Key1, Key2}}, {DRef, {Key2, Key1}}|Keys],
- Delete);
- false ->
- event_loop(ets:prev(ORef, {Key1, Key2}), ORef, DRef,
- Left, Accum, Keys, Delete)
- end
- end;
-event_loop({Key1, Key2, Key3}, ORef, DRef, Left, Accum, Keys, Delete) ->
- [{_,DL,ST,_PO,Event}]=ets:lookup(ORef, {Key1, Key2, Key3}),
- case check_deadline(DL) of
- true ->
- ets:delete(ORef, {Key1, Key2, Key3}),
- ets:delete(DRef, {Key3, Key2, Key1}),
- event_loop(ets:prev(ORef, {Key1, Key2, Key3}), ORef, DRef,
- Left, Accum, Keys, Delete);
- false ->
- case check_start_time(ST) of
- true when Delete == true ->
- ets:delete(ORef, {Key1, Key2, Key3}),
- ets:delete(DRef, {Key3, Key2, Key1}),
- event_loop(ets:prev(ORef, {Key1, Key2, Key3}), ORef, DRef,
- Left-1, [Event|Accum], Keys, Delete);
- true ->
- event_loop(ets:prev(ORef, {Key1, Key2, Key3}), ORef, DRef,
- Left-1, [Event|Accum],
- [{ORef, {Key1, Key2, Key3}},
- {DRef, {Key3, Key2, Key1}}|Keys], Delete);
- false ->
- event_loop(ets:prev(ORef, {Key1, Key2, Key3}), ORef, DRef,
- Left, Accum, Keys, Delete)
- end
- end.
-
-%%------------------------------------------------------------
-%% function : delete_events
-%% Arguments: EventList - what's returned by get_event, get_events
-%% and add_and_get_event.
-%% Returns :
-%% Comment : Shall be invoked when it's safe to premanently remove
-%% the events found in the EventList.
-%%
-%%------------------------------------------------------------
-delete_events([]) ->
- ok;
-delete_events([{DB, Key}|T]) ->
- ets:delete(DB, Key),
- delete_events(T).
-
-%%------------------------------------------------------------
-%% function : update
-%% Arguments:
-%% Returns :
-%% Comment : As default we shall deliver Events in Priority order.
-%% Hence, if AnyOrder set we will still deliver in
-%% Priority order.
-%%------------------------------------------------------------
-update(undefined, _QoS) ->
- ok;
-update(DBRef, QoS) ->
- update(DBRef, QoS, undefined, undefined).
-
-update(DBRef, QoS, LifeFilter, PrioFilter) ->
- case updated_order(DBRef, ?not_GetOrderPolicy(QoS)) of
- false ->
- case updated_discard(DBRef, ?not_GetDiscardPolicy(QoS)) of
- false ->
- DBR2 = ?set_DefPriority(DBRef, ?not_GetPriority(QoS)),
- DBR3 = ?set_MaxEvents(DBR2, ?not_GetMaxEventsPerConsumer(QoS)),
- DBR4 = ?set_DefStopT(DBR3, ?not_GetTimeout(QoS)),
- DBR5 = ?set_StartTsupport(DBR4, ?not_GetStartTimeSupported(QoS)),
- DBR6 = ?set_StopTsupport(DBR5, ?not_GetStopTimeSupported(QoS)),
- case ets:info(?get_OrderRef(DBR6), size) of
- N when N =< ?get_MaxEvents(DBR6) ->
- %% Even if the QoS MaxEvents have been changed
- %% we don't reach the limit.
- DBR6;
- N ->
- %% The QoS MaxEvents must have been decreased.
- discard_events(DBR6, N-?get_MaxEvents(DBR6)),
- DBR6
- end;
- true ->
- destroy_discard_db(DBRef),
- NewDBRef = create_db(QoS, ?get_GCTime(DBRef), ?get_GCLimit(DBRef),
- ?get_TimeRef(DBRef)),
- move_events(DBRef, NewDBRef, ets:first(?get_OrderRef(DBRef)),
- LifeFilter, PrioFilter)
- end;
- true ->
- destroy_discard_db(DBRef),
- NewDBRef = create_db(QoS, ?get_GCTime(DBRef), ?get_GCLimit(DBRef),
- ?get_TimeRef(DBRef)),
- move_events(DBRef, NewDBRef, ets:first(?get_OrderRef(DBRef)),
- LifeFilter, PrioFilter)
- end.
-
-updated_order(#dbRef{orderPolicy = Equal}, Equal) -> false;
-updated_order(#dbRef{orderPolicy = ?not_PriorityOrder}, ?not_AnyOrder) -> false;
-updated_order(#dbRef{orderPolicy = ?not_AnyOrder}, ?not_PriorityOrder) -> false;
-updated_order(_, _) -> true.
-
-updated_discard(#dbRef{discardPolicy = Equal}, Equal) -> false;
-updated_discard(#dbRef{discardPolicy = ?not_RejectNewEvents}, ?not_AnyOrder) -> false;
-updated_discard(#dbRef{discardPolicy = ?not_AnyOrder}, ?not_RejectNewEvents) -> false;
-updated_discard(_, _) -> true.
-
-move_events(DBRef, NewDBRef, '$end_of_table', _, _) ->
- destroy_order_db(DBRef),
- case ets:info(?get_OrderRef(NewDBRef), size) of
- N when N =< ?get_MaxEvents(NewDBRef) ->
- %% Even if the QoS MaxEvents have been changed
- %% we don't reach the limit.
- NewDBRef;
- N ->
- %% The QoS MaxEvents must have been decreased.
- discard_events(DBRef, N-?get_MaxEvents(NewDBRef)),
- NewDBRef
- end;
-move_events(DBRef, NewDBRef, Key, LifeFilter, PrioFilter) ->
- [{Keys, DeadLine, StartTime, PriorityOverride, Event}] =
- ets:lookup(?get_OrderRef(DBRef), Key),
- case check_deadline(DeadLine) of
- true ->
- ok;
- _->
- write_event(?get_OrderP(DBRef),
- {Keys, DeadLine, StartTime, PriorityOverride, Event},
- DBRef, NewDBRef, Key, LifeFilter, PrioFilter)
- end,
- ets:delete(?get_OrderRef(DBRef), Key),
- move_events(DBRef, NewDBRef, ets:next(?get_OrderRef(DBRef), Key),
- LifeFilter, PrioFilter).
-
-%% We cannot use do_add_event directly since we MUST lookup the timestamp (TS).
-write_event(?not_DeadlineOrder, {{_, TS, _Prio}, DL, ST, PO, Event}, _DBRef, NewDBRef,
- _Key, _LifeFilter, _PrioFilter) ->
- StartT = update_starttime(NewDBRef, Event, ST),
- %% Deadline and Priority previously extracted.
- do_add_event(NewDBRef, Event, TS, DL, StartT, PO);
-write_event(?not_DeadlineOrder, {{_, TS}, DL, _ST, PO, Event}, _DBRef, NewDBRef,
- _Key, _LifeFilter, PrioFilter) ->
- %% Priority not previously extracted.
- POverride = update_priority(NewDBRef, PrioFilter, Event, PO),
- StartT = extract_start_time(Event, ?get_StartTsupport(NewDBRef),
- ?get_TimeRef(NewDBRef)),
- do_add_event(NewDBRef, Event, TS, DL, StartT, POverride);
-write_event(?not_FifoOrder, {{TS, _PorD}, DL, ST, PO, Event}, _DBRef, NewDBRef,
- _Key, LifeFilter, PrioFilter) ->
- %% Priority or Deadline have been extracted before but we cannot tell which.
- POverride = update_priority(NewDBRef, PrioFilter, Event, PO),
- DeadL = update_deadline(NewDBRef, LifeFilter, Event, TS, DL),
- StartT = update_starttime(NewDBRef, Event, ST),
- do_add_event(NewDBRef, Event, TS, DeadL, StartT, POverride);
-write_event(?not_FifoOrder, {TS, DL, ST, PO, Event}, _DBRef, NewDBRef,
- _Key, LifeFilter, PrioFilter) ->
- %% Priority and Deadline not extracetd before. Do it now.
- POverride = update_priority(NewDBRef, PrioFilter, Event, PO),
- DeadL = update_deadline(NewDBRef, LifeFilter, Event, TS, DL),
- StartT = update_starttime(NewDBRef, Event, ST),
- do_add_event(NewDBRef, Event, TS, DeadL, StartT, POverride);
-%% Order Policy must be AnyOrder or PriorityOrder.
-write_event(_, {{_Prio, TS}, DL, ST, PO, Event}, _DBRef, NewDBRef,
- _Key, LifeFilter, _PrioFilter) ->
- DeadL = update_deadline(NewDBRef, LifeFilter, Event, TS, DL),
- StartT = update_starttime(NewDBRef, Event, ST),
- do_add_event(NewDBRef, Event, TS, DeadL, StartT, PO);
-write_event(_, {{_Prio, TS, DL}, DL, ST, PO, Event}, _DBRef, NewDBRef, _Key, _, _) ->
- %% Both Deadline and Priority have been extracetd before.
- StartT = update_starttime(NewDBRef, Event, ST),
- do_add_event(NewDBRef, Event, TS, DL, StartT, PO).
-
-
-%%------------------------------------------------------------
-%% function : update_priority
-%% Arguments:
-%% Returns :
-%% Comment : The purpose with this function is to avoid
-%% calling MappingFilter priority again, especially
-%% deadline again (we especially want to avoid calling
-%% since it may require intra-ORB communication.
-%% Use only when doing an update.
-%%------------------------------------------------------------
-update_priority(DBRef, PrioFilter, Event, OldPrio) when is_atom(OldPrio) ->
- get_prio_mapping_value(DBRef, PrioFilter, Event);
-update_priority(_DBRef, _PrioFilter, _Event, OldPrio) ->
- OldPrio.
-
-%%------------------------------------------------------------
-%% function : update_deadline
-%% Arguments:
-%% Returns :
-%% Comment : The purpose with this function is to avoid
-%% calling MappingFilter or parsing the events for
-%% deadline again (we especially want to avoid calling
-%% the MappingFilter since it may require intra-ORB
-%% communication. Use only when doing an update.
-%%------------------------------------------------------------
-update_deadline(DBRef, _LifeFilter, _Event, _TS, _OldDeadL) when
- ?get_DiscardP(DBRef) =/= ?not_DeadlineOrder,
- ?get_OrderP(DBRef) =/= ?not_DeadlineOrder,
- ?is_StopTNotSupported(DBRef) ->
- %% We do not need to extract the Deadline since it will not be used.
- false;
-update_deadline(DBRef, LifeFilter, Event, TS, OldDeadL) when is_atom(OldDeadL) ->
- %% We need the Deadline and it have not been extracetd before.
- DOverride = get_life_mapping_value(DBRef, LifeFilter, Event),
- %% We must find out when the event was delivered; setting a deadline using
- %% a new timestamp would not be accurate since we cannot tell for how long
- %% the event have been waiting.
- OldNow = convert_FIFO_Key(TS),
- extract_deadline(Event, ?get_DefStopT(DBRef), ?get_StopTsupport(DBRef),
- ?get_TimeRef(DBRef), DOverride, OldNow);
-update_deadline(_DBRef, _LifeFilter, _Event, _TS, OldDeadL) ->
- %% We need the Deadline and it have been extracetd before.
- OldDeadL.
-
-%%------------------------------------------------------------
-%% function : update_starttime
-%% Arguments:
-%% Returns :
-%% Comment : The purpose with this function is to avoid
-%% parsing the events for starttime again.
-%% Use only when doing an update.
-%%------------------------------------------------------------
-update_starttime(DBRef, Event, OldStartT) when is_atom(OldStartT) ->
- %% Probably not previously extracted; try to get it.
- extract_start_time(Event, ?get_StartTsupport(DBRef), ?get_TimeRef(DBRef));
-update_starttime(_DBRef, _Event, OldStartT) ->
- %% Previously extracted.
- OldStartT.
-
-%%------------------------------------------------------------
-%% function : discard_events
-%% Arguments: DBRef
-%% N - number of events we must discard.
-%% Returns :
-%% Comment : As default we shall Reject New Events when the limit
-%% is reached. Any discard order will do the same.
-%%
-%% This function can only be used for the discard policies
-%% Fifo, Priority and Deadline. Any or RejectNewEvents
-%% will not allow events to be stored at all, i.e., no events
-%% to discard. Lifo will not be stored either since when
-%% trying to add an event it is definitely the last event in.
-%%------------------------------------------------------------
-%% Since no Discard DB must the same Order policy.
-discard_events(#dbRef{orderRef = ORef, discardRef = undefined,
- discardPolicy = ?not_DeadlineOrder}, N) ->
- ?debug_print("Discarding ~p events Deadline Order.",[N]),
- index_loop_backward(ets:last(ORef), undefined, ORef, N);
-discard_events(#dbRef{orderRef = ORef, discardRef = DRef,
- discardPolicy = ?not_DeadlineOrder}, N) ->
- ?debug_print("Discarding ~p events Deadline Order.",[N]),
- index_loop_backward(ets:last(DRef), DRef, ORef, N);
-%% Fifo.
-discard_events(#dbRef{orderRef = ORef, discardRef = undefined,
- discardPolicy = ?not_FifoOrder}, N) ->
- ?debug_print("Discarding ~p events Fifo Order.",[N]),
- index_loop_backward(ets:last(ORef), undefined, ORef, N);
-discard_events(#dbRef{orderRef = ORef, discardRef = DRef,
- discardPolicy = ?not_FifoOrder}, N) ->
- ?debug_print("Discarding ~p events Fifo Order.",[N]),
- index_loop_backward(ets:last(DRef), DRef, ORef, N);
-%% Lifo- or Priority-Order
-discard_events(#dbRef{orderRef = ORef, discardRef = undefined}, N) ->
- ?debug_print("Discarding ~p events Lifo- or Priority-Order.",[N]),
- index_loop_forward(ets:first(ORef), undefined, ORef, N);
-discard_events(#dbRef{orderRef = ORef, discardRef = DRef}, N) ->
- ?debug_print("Discarding ~p events Lifo- or Priority-Order.",[N]),
- index_loop_forward(ets:first(DRef), DRef, ORef, N).
-
-
-index_loop_forward('$end_of_table', _, _, _Left) ->
- ok;
-index_loop_forward(_, _, _, 0) ->
- ok;
-index_loop_forward(Key, undefined, ORef, Left) ->
- ets:delete(ORef, Key),
- NewKey=ets:next(ORef, Key),
- index_loop_forward(NewKey, undefined, ORef, Left-1);
-
-index_loop_forward({Key1, Key2, Key3}, DRef, ORef, Left) ->
- ets:delete(DRef, {Key1, Key2, Key3}),
- ets:delete(ORef, {Key3, Key2, Key1}),
- NewKey=ets:next(DRef, {Key1, Key2, Key3}),
- index_loop_forward(NewKey, DRef, ORef, Left-1);
-
-index_loop_forward({Key1, Key2}, DRef, ORef, Left) ->
- ets:delete(DRef, {Key1, Key2}),
- ets:delete(ORef, {Key2, Key1}),
- NewKey=ets:next(DRef, {Key1, Key2}),
- index_loop_forward(NewKey, DRef, ORef, Left-1).
-
-index_loop_backward('$end_of_table', _, _, _) ->
- ok;
-index_loop_backward(_, _, _, 0) ->
- ok;
-index_loop_backward(Key, undefined, ORef, Left) ->
- ets:delete(ORef, Key),
- NewKey=ets:prev(ORef, Key),
- index_loop_backward(NewKey, undefined, ORef, Left-1);
-index_loop_backward({Key1, Key2}, DRef, ORef, Left) ->
- ets:delete(DRef, {Key1, Key2}),
- ets:delete(ORef, {Key2, Key1}),
- NewKey=ets:prev(DRef, {Key1, Key2}),
- index_loop_backward(NewKey, DRef, ORef, Left-1);
-index_loop_backward({Key1, Key2, Key3}, DRef, ORef, Left) ->
- ets:delete(DRef, {Key1, Key2, Key3}),
- ets:delete(ORef, {Key3, Key2, Key1}),
- NewKey=ets:prev(DRef, {Key1, Key2, Key3}),
- index_loop_backward(NewKey, DRef, ORef, Left-1).
-
-%%------------------------------------------------------------
-%% function : add_and_get_event
-%% Arguments: DBRef and Event
-%% Returns : {[], bool()} | {Event, bool()}
-%% Comment : This function is a mixture of ad anf get events.
-%% The intended use to avoid storing an event when
-%% not necessary.
-%%------------------------------------------------------------
-add_and_get_event(DBRef, Event) ->
- add_and_get_event(DBRef, Event, undefined, undefined, true).
-
-add_and_get_event(DBRef, Event, Delete) ->
- add_and_get_event(DBRef, Event, undefined, undefined, Delete).
-
-add_and_get_event(DBRef, Event, LifeFilter, PrioFilter) ->
- add_and_get_event(DBRef, Event, LifeFilter, PrioFilter, true).
-
-add_and_get_event(DBRef, Event, LifeFilter, PrioFilter, Delete) ->
- case ets:info(?get_OrderRef(DBRef), size) of
- 0 when ?is_StartTNotSupported(DBRef), ?is_StopTNotSupported(DBRef),
- Delete == true ->
- %% No stored events and no timeouts used; just return the event.
- {Event, false};
- 0 when ?is_StartTNotSupported(DBRef), ?is_StopTNotSupported(DBRef) ->
- %% No stored events and no timeouts used; just return the event.
- {Event, false, []};
- 0 when ?is_StartTNotSupported(DBRef) ->
- %% Only deadline supported, lookup values and cehck if ok.
- DOverride = get_life_mapping_value(DBRef, LifeFilter, Event),
- DL = extract_deadline(Event, ?get_DefStopT(DBRef),
- ?get_StopTsupport(DBRef), ?get_TimeRef(DBRef),
- DOverride),
- case check_deadline(DL) of
- true when Delete == true ->
- %% Expired, just discard the event.
- {[], false};
- true ->
- {[], false, []};
- _ when Delete == true ->
- %% Not expired, we can safely return the event.
- {Event, false};
- _ ->
- %% Not expired, we can safely return the event.
- {Event, false, []}
- end;
- 0 when ?is_StopTNotSupported(DBRef) ->
- %% Only starttime allowed, test if we can deliver the event now.
- ST = extract_start_time(Event, ?get_StartTsupport(DBRef),
- ?get_TimeRef(DBRef)),
- case check_start_time(ST) of
- false when Delete == true ->
- DOverride = get_life_mapping_value(DBRef, LifeFilter, Event),
- POverride = get_prio_mapping_value(DBRef, PrioFilter, Event),
- DL = extract_deadline(Event, ?get_DefStopT(DBRef),
- ?get_StopTsupport(DBRef),
- ?get_TimeRef(DBRef), DOverride),
- do_add_event(DBRef, Event, create_FIFO_Key(), DL, ST, POverride),
- {[], true};
- false ->
- DOverride = get_life_mapping_value(DBRef, LifeFilter, Event),
- POverride = get_prio_mapping_value(DBRef, PrioFilter, Event),
- DL = extract_deadline(Event, ?get_DefStopT(DBRef),
- ?get_StopTsupport(DBRef),
- ?get_TimeRef(DBRef), DOverride),
- do_add_event(DBRef, Event, create_FIFO_Key(), DL, ST, POverride),
- {[], true, []};
- _ when Delete == true ->
- %% Starttime ok, just return the event.
- {Event, false};
- _ ->
- %% Starttime ok, just return the event.
- {Event, false, []}
- end;
- _->
- %% Event already stored, just have to accept the overhead.
- ST = extract_start_time(Event, ?get_StartTsupport(DBRef),
- ?get_TimeRef(DBRef)),
- DOverride = get_life_mapping_value(DBRef, LifeFilter, Event),
- POverride = get_prio_mapping_value(DBRef, PrioFilter, Event),
- DL = extract_deadline(Event, ?get_DefStopT(DBRef),
- ?get_StopTsupport(DBRef),
- ?get_TimeRef(DBRef), DOverride),
- do_add_event(DBRef, Event, create_FIFO_Key(), DL, ST, POverride),
- get_event(DBRef, Delete)
- end.
-
-%%------------------------------------------------------------
-%% function : add_event
-%% Arguments: DBRef and Event
-%% Returns : true (or whatever 'ets:insert' returns) |
-%% {'EXCEPTION', #'IMP_LIMIT'{}}
-%% Comment : As default we shall deliver Events in Priority order.
-%% Hence, if AnyOrder set we will still deliver in
-%% Priority order. But we cannot use only the Priority
-%% value since if "all" events have the same priority
-%% there is a risk that some never will be delivered if
-%% the EventDB always contain events.
-%%
-%% When discard and order policy is equal we only use one
-%% DB since all we have to do is to "read from the other
-%% end" to discard the correct event(s).
-%%
-%% In the discard DB we must also store keys necessary to
-%% lookup the event in the order DB.
-%%
-%% If event limit reached 'IMPL_LIMIT' is raised if
-%% the discard policy is RejectNewEvents or AnyOrder.
-%% Theses two policies we currently define to be equal.
-%%------------------------------------------------------------
-
-add_event(DBRef, Event) ->
- %% Save overhead by first checking if we really need to extract
- %% Deadline and/or Priority.
- Deadline = get_life_mapping_value(DBRef, undefined, Event),
- Priority = get_prio_mapping_value(DBRef, undefined, Event),
- add_event_helper(DBRef, Event, Deadline, Priority).
-
-add_event(DBRef, Event, LifeFilter, PrioFilter) ->
- %% Save overhead by first checking if we really need to extract
- %% Deadline and/or Priority.
- Deadline = get_life_mapping_value(DBRef, LifeFilter, Event),
- Priority = get_prio_mapping_value(DBRef, PrioFilter, Event),
- add_event_helper(DBRef, Event, Deadline, Priority).
-
-add_event_helper(DBRef, Event, DOverride, POverride) ->
- case ets:info(?get_OrderRef(DBRef), size) of
- N when N < ?get_MaxEvents(DBRef), N > ?get_GCLimit(DBRef) ->
- gc_events(DBRef, low),
- DL = extract_deadline(Event, ?get_DefStopT(DBRef),
- ?get_StopTsupport(DBRef), ?get_TimeRef(DBRef),
- DOverride),
- case check_deadline(DL) of
- true ->
- true;
- _ ->
- ST = extract_start_time(Event, ?get_StartTsupport(DBRef),
- ?get_TimeRef(DBRef)),
- do_add_event(DBRef, Event, create_FIFO_Key(), DL, ST, POverride)
- end;
- N when N < ?get_MaxEvents(DBRef) ->
- DL = extract_deadline(Event, ?get_DefStopT(DBRef),
- ?get_StopTsupport(DBRef), ?get_TimeRef(DBRef),
- DOverride),
- case check_deadline(DL) of
- true ->
- true;
- _ ->
- ST = extract_start_time(Event, ?get_StartTsupport(DBRef),
- ?get_TimeRef(DBRef)),
- do_add_event(DBRef, Event, create_FIFO_Key(), DL, ST, POverride)
- end;
- _N when ?get_DiscardP(DBRef) == ?not_RejectNewEvents ->
- gc_events(DBRef, low),
- corba:raise(#'IMP_LIMIT'{completion_status=?COMPLETED_NO});
- _N when ?get_DiscardP(DBRef) == ?not_AnyOrder ->
- gc_events(DBRef, low),
- corba:raise(#'IMP_LIMIT'{completion_status=?COMPLETED_NO});
- _N when ?get_DiscardP(DBRef) == ?not_LifoOrder ->
- gc_events(DBRef, low),
- corba:raise(#'IMP_LIMIT'{completion_status=?COMPLETED_NO});
- _N ->
- gc_events(DBRef, low),
- %% Other discard policy; we must first store the event
- %% and the look up in the Discard DB which event we
- %% should remove.
- DL = extract_deadline(Event, ?get_DefStopT(DBRef),
- ?get_StopTsupport(DBRef), ?get_TimeRef(DBRef),
- DOverride),
- case check_deadline(DL) of
- true ->
- true;
- _ ->
- ST = extract_start_time(Event, ?get_StartTsupport(DBRef),
- ?get_TimeRef(DBRef)),
- do_add_event(DBRef, Event, create_FIFO_Key(), DL, ST, POverride),
- discard_events(DBRef, 1)
- end
- end.
-
-
-do_add_event(#dbRef{orderRef = ORef, orderPolicy = ?not_DeadlineOrder,
- discardRef = DRef, discardPolicy = ?not_PriorityOrder,
- defPriority = DefPrio, defStopT = _DefStopT}, Event, Key, DL, ST, PO) ->
- Prio = extract_priority(Event, DefPrio, PO),
- ets:insert(ORef, {{DL, Key, Prio}, DL, ST, PO, Event}),
- ets:insert(DRef, {{Prio, Key, DL}});
-do_add_event(#dbRef{orderRef = ORef, orderPolicy = ?not_DeadlineOrder,
- discardRef = DRef, discardPolicy = ?not_FifoOrder,
- defStopT = _DefStopT}, Event, Key, DL, ST, PO) ->
- ets:insert(ORef, {{DL, Key}, DL, ST, PO, Event}),
- ets:insert(DRef, {{Key, DL}});
-do_add_event(#dbRef{orderRef = ORef, orderPolicy = ?not_DeadlineOrder,
- discardRef = DRef, discardPolicy = ?not_LifoOrder,
- defStopT = _DefStopT}, Event, Key, DL, ST, PO) ->
- ets:insert(ORef, {{DL, Key}, DL, ST, PO, Event}),
- ets:insert(DRef, {{Key, DL}});
-%% Either the same (DeadlineOrder), RejectNewEvents or AnyOrder. No need
-%% to store anything in the discard policy, i.e., if the same we'll just
-%% read "from the other end" and AnyOrder and RejectNewEvents is equal.
-do_add_event(#dbRef{orderRef = ORef, orderPolicy = ?not_DeadlineOrder,
- defStopT = _DefStopT}, Event, Key, DL, ST, PO) ->
- ets:insert(ORef, {{DL, Key}, DL, ST, PO, Event});
-
-
-do_add_event(#dbRef{orderRef = ORef, orderPolicy = ?not_FifoOrder,
- discardRef = DRef, discardPolicy = ?not_DeadlineOrder,
- defStopT = _DefStopT}, Event, Key, DL, ST, PO) ->
- ets:insert(ORef, {{Key, DL}, DL, ST, PO, Event}),
- ets:insert(DRef, {{DL, Key}});
-do_add_event(#dbRef{orderRef = ORef, orderPolicy = ?not_FifoOrder,
- discardRef = DRef, discardPolicy = ?not_PriorityOrder,
- defPriority = DefPrio}, Event, Key, DL, ST, PO) ->
- Prio = extract_priority(Event, DefPrio, PO),
- ets:insert(ORef, {{Key, Prio}, DL, ST, PO, Event}),
- ets:insert(DRef, {{Prio, Key}});
-%% The discard policy must RejectNewEvents, AnyOrder, Fifo or Lifo order.
-do_add_event(#dbRef{orderRef = ORef, orderPolicy = ?not_FifoOrder,
- discardRef = _DRef}, Event, Key, DL, ST, PO) ->
- ets:insert(ORef, {Key, DL, ST, PO, Event});
-
-%% Order Policy must be AnyOrder or PriorityOrder.
-do_add_event(#dbRef{orderRef = ORef,
- discardRef = DRef, discardPolicy = ?not_DeadlineOrder,
- defPriority = DefPrio, defStopT = _DefStopT}, Event, Key, DL, ST, PO) ->
- Prio = extract_priority(Event, DefPrio, PO),
- ets:insert(ORef, {{Prio, Key, DL}, DL, ST, PO, Event}),
- ets:insert(DRef, {{DL, Key, Prio}});
-do_add_event(#dbRef{orderRef = ORef,
- discardRef = DRef, discardPolicy = ?not_FifoOrder,
- defPriority = DefPrio}, Event, Key, DL, ST, PO) ->
- Prio = extract_priority(Event, DefPrio, PO),
- ets:insert(ORef, {{Prio, Key}, DL, ST, PO, Event}),
- ets:insert(DRef, {{Key, Prio}});
-
-do_add_event(#dbRef{orderRef = ORef,
- discardRef = DRef, discardPolicy = ?not_LifoOrder,
- defPriority = DefPrio}, Event, Key, DL, ST, PO) ->
- Prio = extract_priority(Event, DefPrio, PO),
- ets:insert(ORef, {{Prio, Key}, DL, ST, PO, Event}),
- ets:insert(DRef, {{Key, Prio}});
-
-%% Order Policy must be AnyOrder or PriorityOrder and Discard Policy must be
-%% AnyOrder or RejectNewEvents
-do_add_event(#dbRef{orderRef = ORef, defPriority = DefPrio}, Event, Key, DL, ST, PO) ->
- Prio = extract_priority(Event, DefPrio, PO),
- ets:insert(ORef, {{Prio, Key}, DL, ST, PO, Event}).
-
-%%------------------------------------------------------------
-%% function : destroy_db
-%% Arguments: A DB reference
-%% Returns :
-%%------------------------------------------------------------
-destroy_db(#dbRef{orderRef = ORef, discardRef = undefined}) ->
- ets:delete(ORef);
-destroy_db(#dbRef{orderRef = ORef, discardRef = DRef}) ->
- ets:delete(ORef),
- ets:delete(DRef).
-
-%%------------------------------------------------------------
-%% function : destroy_discard_db
-%% Arguments: A DB reference
-%% Returns :
-%%------------------------------------------------------------
-destroy_discard_db(#dbRef{discardRef = undefined}) ->
- ok;
-destroy_discard_db(#dbRef{discardRef = DRef}) ->
- ets:delete(DRef).
-
-%%------------------------------------------------------------
-%% function : destroy_order_db
-%% Arguments: A DB reference
-%% Returns :
-%%------------------------------------------------------------
-destroy_order_db(#dbRef{orderRef = ORef}) ->
- ets:delete(ORef).
-
-%%------------------------------------------------------------
-%% function : create_db
-%% Arguments: QoS (local representation).
-%% Returns : A DB reference
-%%------------------------------------------------------------
-create_db(QoS, GCTime, GCLimit, TimeRef) ->
- DiscardRef =
- case {?not_GetDiscardPolicy(QoS), ?not_GetOrderPolicy(QoS)} of
- {Equal, Equal} ->
- undefined;
- {?not_PriorityOrder, ?not_AnyOrder} ->
- %% NOTE: Any- and Priority-Order delivery policy is equal.
- undefined;
- {?not_RejectNewEvents, _} ->
- undefined;
- {?not_AnyOrder, _} ->
- undefined;
- {?not_LifoOrder, ?not_FifoOrder} ->
- undefined;
- _ ->
- ets:new(oe_ets, [set, public, ordered_set])
- end,
- DBRef = ?CreateRef(ets:new(oe_ets, [set, public, ordered_set]),
- DiscardRef,
- ?not_GetOrderPolicy(QoS), ?not_GetDiscardPolicy(QoS),
- ?not_GetPriority(QoS), ?not_GetMaxEventsPerConsumer(QoS),
- ?not_GetTimeout(QoS), ?not_GetStartTimeSupported(QoS),
- ?not_GetStopTimeSupported(QoS), GCTime, GCLimit, TimeRef),
- if
- ?is_TimeoutNotUsed(DBRef), ?is_StopTNotSupported(DBRef) ->
- ok;
- true ->
- TS = erlang:monotonic_time(),
- {resolution, TR} = lists:keyfind(resolution, 1,
- erlang:system_info(os_monotonic_time_source)),
- put(oe_GC_timestamp, TS+GCTime*TR)
- end,
- DBRef.
-
-%%------------------------------------------------------------
-%% function : get_prio_mapping_value
-%% Arguments: A MappingFilter reference | undefined
-%% Event (Any or Structured)
-%% Returns : undefined | Data
-%%------------------------------------------------------------
-get_prio_mapping_value(DBRef, _, _) when ?get_DiscardP(DBRef) =/= ?not_PriorityOrder,
- ?get_OrderP(DBRef) =/= ?not_AnyOrder,
- ?get_OrderP(DBRef) =/= ?not_PriorityOrder ->
- false;
-get_prio_mapping_value(_, undefined, _) ->
- undefined;
-get_prio_mapping_value(_, MFilter, Event) when is_record(Event, 'any') ->
- case catch 'CosNotifyFilter_MappingFilter':match(MFilter, Event) of
- {false, DefVal} when is_record(DefVal, 'any') ->
- any:get_value(DefVal);
- {true, Matched} when is_record(Matched, 'any') ->
- any:get_value(Matched);
- _ ->
- undefined
- end;
-get_prio_mapping_value(_, MFilter, Event) ->
- case catch 'CosNotifyFilter_MappingFilter':match_structured(MFilter, Event) of
- {false, DefVal} when is_record(DefVal, 'any') ->
- any:get_value(DefVal);
- {true, Matched} when is_record(Matched, 'any') ->
- any:get_value(Matched);
- _ ->
- undefined
- end.
-
-%%------------------------------------------------------------
-%% function : get_life_mapping_value
-%% Arguments: A MappingFilter reference | undefined
-%% Event (Any or Structured)
-%% Returns : undefined | Data
-%%------------------------------------------------------------
-get_life_mapping_value(DBRef, _, _) when ?get_DiscardP(DBRef) =/= ?not_DeadlineOrder,
- ?get_OrderP(DBRef) =/= ?not_DeadlineOrder,
- ?is_StopTNotSupported(DBRef) ->
- false;
-get_life_mapping_value(_, undefined, _) ->
- undefined;
-get_life_mapping_value(_, MFilter, Event) when is_record(Event, 'any') ->
- case catch 'CosNotifyFilter_MappingFilter':match(MFilter, Event) of
- {false, DefVal} when is_record(DefVal, 'any') ->
- any:get_value(DefVal);
- {true, Matched} when is_record(Matched, 'any') ->
- any:get_value(Matched);
- _ ->
- undefined
- end;
-get_life_mapping_value(_, MFilter, Event) ->
- case catch 'CosNotifyFilter_MappingFilter':match_structured(MFilter, Event) of
- {false, DefVal} when is_record(DefVal, 'any') ->
- any:get_value(DefVal);
- {true, Matched} when is_record(Matched, 'any') ->
- any:get_value(Matched);
- _ ->
- undefined
- end.
-
-%%------------------------------------------------------------
-%% function : validate_event
-%% Arguments: Subscribe data
-%% A sequence of Events, 'structured' or an 'any' record
-%% A list of filter references
-%% Status, i.e., do we have to filter the events or just check subscr.
-%% Returns : A tuple of two lists; list1 the events that passed
-%% and list2 the events that didn't pass.
-%%------------------------------------------------------------
-validate_event(true, Events, Filters, _, 'MATCH') ->
- filter_events(Events, Filters, false);
-validate_event(true, Events, _Filters, _, _) ->
- {Events, []};
-validate_event({_Which, _WC}, Event, Filters, _, 'MATCH') when is_record(Event, any) ->
- filter_events(Event, Filters, false);
-validate_event({_Which, _WC}, Event, _Filters, _, _) when is_record(Event, any) ->
- {Event, []};
-validate_event({Which, WC}, Events, Filters, DBRef, 'MATCH') ->
- Passed=validate_event2(DBRef, Events, Which, WC, []),
- filter_events(Passed, Filters, true);
-validate_event({Which, WC}, Events, _Filters, DBRef, _) ->
- Passed=validate_event2(DBRef, Events, Which, WC, []),
- {lists:reverse(Passed), []}.
-
-validate_event2(_, [], _, _, []) ->
- [];
-validate_event2(_, [], _, _, Acc) ->
- Acc;
-validate_event2(DBRef, [Event|T], Which, WC, Acc) ->
- ET = ((Event#'CosNotification_StructuredEvent'.header)
- #'CosNotification_EventHeader'.fixed_header)
- #'CosNotification_FixedEventHeader'.event_type,
- CheckList =
- case Which of
- both ->
- [ET];
- domain ->
- [ET,
- ET#'CosNotification_EventType'{type_name=""},
- ET#'CosNotification_EventType'{type_name="*"}];
- type ->
- [ET,
- ET#'CosNotification_EventType'{domain_name=""},
- ET#'CosNotification_EventType'{domain_name="*"}];
- _ ->
- [ET,
- ET#'CosNotification_EventType'{type_name=""},
- ET#'CosNotification_EventType'{type_name="*"},
- ET#'CosNotification_EventType'{domain_name=""},
- ET#'CosNotification_EventType'{domain_name="*"}]
- end,
- case check_subscription(DBRef, CheckList) of
- true ->
- validate_event2(DBRef, T, Which, WC, [Event|Acc]);
- _->
- case catch cosNotification_Filter:match_types(
- ET#'CosNotification_EventType'.domain_name,
- ET#'CosNotification_EventType'.type_name,
- WC) of
- true ->
- validate_event2(DBRef, T, Which, WC, [Event|Acc]);
- _->
- validate_event2(DBRef, T, Which, WC, Acc)
- end
- end.
-
-check_subscription(_, []) ->
- false;
-check_subscription(DBRef, [H|T]) ->
- case ets:lookup(DBRef, H) of
- [] ->
- check_subscription(DBRef, T);
- _ ->
- true
- end.
-
-
-%%------------------------------------------------------------
-%% function : filter_events
-%% Arguments: A sequence of structured Events or #any
-%% Returns : A tuple of two lists; list1 the events that passed
-%% and list2 the events that didn't pass.
-%%------------------------------------------------------------
-
-filter_events(Events, []) ->
- {Events, []};
-filter_events(Events, Filters) ->
- filter_events(Events, Filters, [], [], false).
-
-filter_events(Events, [], false) ->
- {Events, []};
-filter_events(Events, [], _) ->
- {lists:reverse(Events), []};
-filter_events(Events, Filters, Reversed) ->
- filter_events(Events, Filters, [], [], Reversed).
-
-filter_events([], _, AccPassed, AccFailed, false) ->
- {lists:reverse(AccPassed), lists:reverse(AccFailed)};
-filter_events([], _, AccPassed, AccFailed, _) ->
- {AccPassed, AccFailed};
-filter_events([H|T], Filters, AccPassed, AccFailed, Reversed) ->
- case call_filters(Filters, H) of
- true ->
- filter_events(T, Filters, [H|AccPassed], AccFailed, Reversed);
- _ ->
- filter_events(T, Filters, AccPassed, [H|AccFailed], Reversed)
- end;
-filter_events(Any, Filters, _AccPassed, _AccFailed, _Reversed) ->
- case call_filters(Filters, Any) of
- true ->
- {Any, []};
- _ ->
- {[], Any}
- end.
-
-call_filters([], _) ->
- false;
-call_filters([{_,H}|T], Event) when is_record(Event, any) ->
- case catch 'CosNotifyFilter_Filter':match(H, Event) of
- true ->
- true;
- _->
- call_filters(T, Event)
- end;
-call_filters([{_,H}|T], Event) when ?not_isConvertedAny(Event) ->
- case catch 'CosNotifyFilter_Filter':match(H,
- Event#'CosNotification_StructuredEvent'.remainder_of_body) of
- true ->
- true;
- _->
- call_filters(T, Event)
- end;
-call_filters([{_,H}|T], Event) ->
- case catch 'CosNotifyFilter_Filter':match_structured(H, Event) of
- true ->
- true;
- _->
- call_filters(T, Event)
- end.
-
-
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/cosNotification/test/Makefile b/lib/cosNotification/test/Makefile
deleted file mode 100644
index 583cca1f42..0000000000
--- a/lib/cosNotification/test/Makefile
+++ /dev/null
@@ -1,192 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1999-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(COSNOTIFICATION_VSN)
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/cosNotification_test
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-TEST_SPEC_FILE = cosNotification.spec
-COVER_FILE = cosNotification.cover
-
-
-IDL_FILES =
-
-IDLOUTDIR = idl_output
-
-MODULES = \
- notification_SUITE \
- grammar_SUITE \
- eventDB_SUITE \
- generated_SUITE \
- notify_test_impl
-
-GEN_MODULES = \
- oe_notify_test_server \
- notify_test_data \
- notify_test_computer \
- notify_test_studies \
- notify_test_ShortArray \
- notify_test_uni1 \
- notify_test_uni2 \
- notify_test_X \
- notify_test_K \
- notify_test_SeqPushC \
- notify_test_StrPushC \
- notify_test_AnyPushC \
- notify_test_SeqPullC \
- notify_test_StrPullC \
- notify_test_AnyPullC \
- notify_test_SeqPushS \
- notify_test_StrPushS \
- notify_test_AnyPushS \
- notify_test_SeqPullS \
- notify_test_StrPullS \
- notify_test_AnyPullS \
- notify_test_funcs
-
-GEN_HRL_FILES = \
- oe_notify_test_server.hrl \
- notify_test_SeqPushC.hrl \
- notify_test_StrPushC.hrl \
- notify_test_AnyPushC.hrl \
- notify_test_SeqPullC.hrl \
- notify_test_StrPullC.hrl \
- notify_test_AnyPullC.hrl \
- notify_test_SeqPushS.hrl \
- notify_test_StrPushS.hrl \
- notify_test_AnyPushS.hrl \
- notify_test_SeqPullS.hrl \
- notify_test_StrPullS.hrl \
- notify_test_AnyPullS.hrl \
- notify_test.hrl \
- notify_test_funcs.hrl
-
-ERL_FILES = $(MODULES:%=%.erl)
-
-HRL_FILES =
-
-GEN_FILES = \
- $(GEN_HRL_FILES:%=$(IDLOUTDIR)/%) \
- $(GEN_MODULES:%=$(IDLOUTDIR)/%.erl)
-
-GEN_TARGET_FILES = $(GEN_MODULES:%=$(IDLOUTDIR)/%.$(EMULATOR))
-
-SUITE_TARGET_FILES = $(MODULES:%=%.$(EMULATOR))
-
-TARGET_FILES = \
- $(GEN_TARGET_FILES) \
- $(SUITE_TARGET_FILES)
-
-
-# ----------------------------------------------------
-# PROGRAMS
-# ----------------------------------------------------
-LOCAL_CLASSPATH = $(ERL_TOP)lib/cosNotification/priv:$(ERL_TOP)lib/cosNotification/test
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_IDL_FLAGS += \
- -pa $(ERL_TOP)/lib/cosNotification/ebin \
- -pa $(ERL_TOP)/lib/cosNotification/src \
- -pa $(ERL_TOP)/lib/cosTime/ebin \
- -pa $(ERL_TOP)/lib/cosTime/include \
- -pa $(ERL_TOP)/lib/orber/ebin \
- -pa $(ERL_TOP)/lib/ic/ebin \
- -pa $(ERL_TOP)/lib/cosNotification/include \
- -I$(ERL_TOP)/lib/cosEvent/src \
- -I$(ERL_TOP)/lib/cosNotification/include \
-
-ERL_COMPILE_FLAGS += \
- $(ERL_IDL_FLAGS) \
- -pa $(ERL_TOP)/lib/orber/include \
- -pa $(ERL_TOP)/lib/cosEvent/ebin \
- -pa $(ERL_TOP)/lib/cosNotification/ebin \
- -pa $(ERL_TOP)/lib/cosNotification/test/idl_output \
- -pa $(ERL_TOP)/lib/cosTime/ebin \
- -pa $(ERL_TOP)/lib/cosTime/include \
- -pa $(ERL_TOP)/lib/cosNotification/include \
- -pa $(ERL_TOP)/lib/ic/ebin \
- -I$(ERL_TOP)/lib/cosTime/ebin \
- -I$(ERL_TOP)/lib/cosTime/include \
- -I$(ERL_TOP)/lib/orber/include \
- -I$(ERL_TOP)/lib/cosNotification/src \
- -I$(ERL_TOP)/lib/cosNotification/include \
- -I$(ERL_TOP)/lib/cosNotification \
- -I$(ERL_TOP)/lib/cosNotification/test/$(IDLOUTDIR)
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-
-tests debug opt: $(TARGET_FILES)
-
-clean:
- rm -f idl_output/*
- rm -f $(TARGET_FILES)
- rm -f errs core *~
-
-docs:
-
-# ----------------------------------------------------
-# Special Targets
-# ----------------------------------------------------
-
-IDL-GENERATED: notify_test_server.idl
- erlc $(ERL_COMPILE_FLAGS) -o$(IDLOUTDIR) \
- +'{cfgfile,"notify_test_server.cfg"}' notify_test_server.idl
- >IDL-GENERATED
-
-$(GEN_FILES): IDL-GENERATED
-
-$(TARGET_FILES): IDL-GENERATED
-
-# ----------------------------------------------------
-# Release Targets
-# ----------------------------------------------------
-# We don't copy generated intermediate erlang and hrl files
-
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec:
-
-release_docs_spec:
-
-release_tests_spec: tests
- $(INSTALL_DIR) "$(RELSYSDIR)"
- $(INSTALL_DATA) $(IDL_FILES) $(TEST_SPEC_FILE) \
- $(COVER_FILE) $(ERL_FILES) "$(RELSYSDIR)"
- $(INSTALL_DIR) "$(RELSYSDIR)/$(IDLOUTDIR)"
- $(INSTALL_DATA) $(GEN_TARGET_FILES) $(GEN_FILES) \
- "$(RELSYSDIR)/$(IDLOUTDIR)"
- $(INSTALL_DATA) $(SUITE_TARGET_FILES) "$(RELSYSDIR)"
-
diff --git a/lib/cosNotification/test/cosNotification.cover b/lib/cosNotification/test/cosNotification.cover
deleted file mode 100644
index 604f313521..0000000000
--- a/lib/cosNotification/test/cosNotification.cover
+++ /dev/null
@@ -1,2 +0,0 @@
-{incl_app,cosNotification,details}.
-
diff --git a/lib/cosNotification/test/cosNotification.spec b/lib/cosNotification/test/cosNotification.spec
deleted file mode 100644
index 8ec1baca33..0000000000
--- a/lib/cosNotification/test/cosNotification.spec
+++ /dev/null
@@ -1 +0,0 @@
-{suites,"../cosNotification_test",all}.
diff --git a/lib/cosNotification/test/eventDB_SUITE.erl b/lib/cosNotification/test/eventDB_SUITE.erl
deleted file mode 100644
index a0c47ad4c7..0000000000
--- a/lib/cosNotification/test/eventDB_SUITE.erl
+++ /dev/null
@@ -1,896 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%--------------------------------------------------------------------
-%% File : eventDB_SUITE.erl
-%% Purpose :
-%%--------------------------------------------------------------------
-
--module(eventDB_SUITE).
-%%--------------- INCLUDES -----------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
-%% cosEvent files.
--include_lib("cosEvent/include/CosEventChannelAdmin.hrl").
-%% cosTime files.
--include_lib("cosTime/include/TimeBase.hrl").
-%% Application files
--include_lib("cosNotification/include/CosNotification.hrl").
--include_lib("cosNotification/include/CosNotifyChannelAdmin.hrl").
--include_lib("cosNotification/include/CosNotifyComm.hrl").
--include_lib("cosNotification/include/CosNotifyFilter.hrl").
-
--include_lib("cosNotification/src/CosNotification_Definitions.hrl").
-
--include("idl_output/notify_test.hrl").
-
--include_lib("common_test/include/ct.hrl").
-
-%%--------------- DEFINES ------------------------------------
--define(default_timeout, test_server:minutes(20)).
--define(match(ExpectedRes, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- io:format("------ CORRECT RESULT ------~n~p~n",
- [AcTuAlReS]),
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
-
--define(EVENT1, ?not_CreateSE("","event1","",
- [#'CosNotification_Property'
- {name="Priority",
- value=any:create(orber_tc:short(), 0)},
- #'CosNotification_Property'
- {name="StartTime",
- value=any:create('TimeBase_UtcT':tc(),
- #'TimeBase_UtcT'
- {time=900000000,
- inacclo=0, inacchi=0, tdf=2})},
- #'CosNotification_Property'
- {name="StopTime",
- value=any:create('TimeBase_UtcT':tc(),
- #'TimeBase_UtcT'
- {time=900000000,
- inacclo=0, inacchi=0, tdf=2})},
- #'CosNotification_Property'
- {name="Timeout",
- value=any:create(orber_tc:unsigned_long_long(), 900000000)}],
- [], any:create(orber_tc:null(), null))).
--define(EVENT2, ?not_CreateSE("","event2","",
- [#'CosNotification_Property'
- {name="Priority",
- value=any:create(orber_tc:short(), 0)},
- #'CosNotification_Property'
- {name="StartTime",
- value=any:create('TimeBase_UtcT':tc(),
- #'TimeBase_UtcT'
- {time=800000000,
- inacclo=0, inacchi=0, tdf=2})},
- #'CosNotification_Property'
- {name="StopTime",
- value=any:create('TimeBase_UtcT':tc(),
- #'TimeBase_UtcT'
- {time=800000000,
- inacclo=0, inacchi=0, tdf=2})},
- #'CosNotification_Property'
- {name="Timeout",
- value=any:create(orber_tc:unsigned_long_long(), 800000000)}],
- [], any:create(orber_tc:null(), null))).
--define(EVENT3, ?not_CreateSE("","event3","",
- [#'CosNotification_Property'
- {name="Priority",
- value=any:create(orber_tc:short(), 0)},
- #'CosNotification_Property'
- {name="StartTime",
- value=any:create('TimeBase_UtcT':tc(),
- #'TimeBase_UtcT'
- {time=700000000,
- inacclo=0, inacchi=0, tdf=2})},
- #'CosNotification_Property'
- {name="StopTime",
- value=any:create('TimeBase_UtcT':tc(),
- #'TimeBase_UtcT'
- {time=700000000,
- inacclo=0, inacchi=0, tdf=2})},
- #'CosNotification_Property'
- {name="Timeout",
- value=any:create(orber_tc:unsigned_long_long(), 700000000)}],
- [], any:create(orber_tc:null(), null))).
--define(EVENT4, ?not_CreateSE("","event4","",
- [#'CosNotification_Property'
- {name="Priority",
- value=any:create(orber_tc:short(), 2)},
- #'CosNotification_Property'
- {name="StartTime",
- value=any:create('TimeBase_UtcT':tc(),
- #'TimeBase_UtcT'
- {time=300000000,
- inacclo=0, inacchi=0, tdf=2})},
- #'CosNotification_Property'
- {name="StopTime",
- value=any:create('TimeBase_UtcT':tc(),
- #'TimeBase_UtcT'
- {time=300000000,
- inacclo=0, inacchi=0, tdf=2})},
- #'CosNotification_Property'
- {name="Timeout",
- value=any:create(orber_tc:unsigned_long_long(), 300000000)}],
- [], any:create(orber_tc:null(), null))).
--define(EVENT5, ?not_CreateSE("","event5","",
- [#'CosNotification_Property'
- {name="Priority",
- value=any:create(orber_tc:short(), 2)},
- #'CosNotification_Property'
- {name="StartTime",
- value=any:create('TimeBase_UtcT':tc(),
- #'TimeBase_UtcT'
- {time=200000000,
- inacclo=0, inacchi=0, tdf=2})},
- #'CosNotification_Property'
- {name="StopTime",
- value=any:create('TimeBase_UtcT':tc(),
- #'TimeBase_UtcT'
- {time=200000000,
- inacclo=0, inacchi=0, tdf=2})},
- #'CosNotification_Property'
- {name="Timeout",
- value=any:create(orber_tc:unsigned_long_long(), 200000000)}],
- [], any:create(orber_tc:null(), null))).
--define(EVENT6, ?not_CreateSE("","event6","",
- [#'CosNotification_Property'
- {name="Priority",
- value=any:create(orber_tc:short(), 0)},
- #'CosNotification_Property'
- {name="StartTime",
- value=any:create('TimeBase_UtcT':tc(),
- #'TimeBase_UtcT'
- {time=500000000,
- inacclo=0, inacchi=0, tdf=2})},
- #'CosNotification_Property'
- {name="StopTime",
- value=any:create('TimeBase_UtcT':tc(),
- #'TimeBase_UtcT'
- {time=500000000,
- inacclo=0, inacchi=0, tdf=2})},
- #'CosNotification_Property'
- {name="Timeout",
- value=any:create(orber_tc:unsigned_long_long(), 500000000)}],
- [], any:create(orber_tc:null(), null))).
--define(EVENT7, ?not_CreateSE("","event7","",
- [#'CosNotification_Property'
- {name="Priority",
- value=any:create(orber_tc:short(), -1)},
- #'CosNotification_Property'
- {name="StartTime",
- value=any:create('TimeBase_UtcT':tc(),
- #'TimeBase_UtcT'
- {time=400000000,
- inacclo=0, inacchi=0, tdf=2})},
- #'CosNotification_Property'
- {name="StopTime",
- value=any:create('TimeBase_UtcT':tc(),
- #'TimeBase_UtcT'
- {time=400000000,
- inacclo=0, inacchi=0, tdf=2})},
- #'CosNotification_Property'
- {name="Timeout",
- value=any:create(orber_tc:unsigned_long_long(), 400000000)}],
- [], any:create(orber_tc:null(), null))).
--define(EVENT8, ?not_CreateSE("","event8","",
- [#'CosNotification_Property'
- {name="Priority",
- value=any:create(orber_tc:short(), -1)},
- #'CosNotification_Property'
- {name="StartTime",
- value=any:create('TimeBase_UtcT':tc(),
- #'TimeBase_UtcT'
- {time=600000000,
- inacclo=0, inacchi=0, tdf=2})},
- #'CosNotification_Property'
- {name="StopTime",
- value=any:create('TimeBase_UtcT':tc(),
- #'TimeBase_UtcT'
- {time=600000000,
- inacclo=0, inacchi=0, tdf=2})},
- #'CosNotification_Property'
- {name="Timeout",
- value=any:create(orber_tc:unsigned_long_long(), 600000000)}],
- [], any:create(orber_tc:null(), null))).
--define(EVENT9, ?not_CreateSE("","event9","",
- [#'CosNotification_Property'
- {name="Priority",
- value=any:create(orber_tc:short(), 0)},
- #'CosNotification_Property'
- {name="StartTime",
- value=any:create('TimeBase_UtcT':tc(),
- #'TimeBase_UtcT'
- {time=100000000,
- inacclo=0, inacchi=0, tdf=2})},
- #'CosNotification_Property'
- {name="StopTime",
- value=any:create('TimeBase_UtcT':tc(),
- #'TimeBase_UtcT'
- {time=100000000,
- inacclo=0, inacchi=0, tdf=2})},
- #'CosNotification_Property'
- {name="Timeout",
- value=any:create(orber_tc:unsigned_long_long(), 100000000)}],
- [], any:create(orber_tc:null(), null))).
-
--define(EVENTS, [?EVENT1, ?EVENT2, ?EVENT3, ?EVENT4, ?EVENT5, ?EVENT6, ?EVENT7,
- ?EVENT8, ?EVENT9]).
-
-
--define(PRIOORDER, [?EVENT4, ?EVENT5, ?EVENT1, ?EVENT2, ?EVENT3, ?EVENT6, ?EVENT9,
- ?EVENT7, ?EVENT8]).
-
--define(FIFOORDER, ?EVENTS).
-
--define(DEADLINEORDER, [?EVENT9, ?EVENT5, ?EVENT4, ?EVENT7, ?EVENT6, ?EVENT8, ?EVENT3,
- ?EVENT2, ?EVENT1]).
-
--define(NO_OF_EVENTS, 9).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
- cases/0, init_per_suite/1, end_per_suite/1, reorder_api/1,
- lookup_api/1,
- discard_api/1, max_events_api/1, gc_api/1, auto_gc_api/1,
- start_stop_time_api/1, mapping_filter_api/1, persisten_event_api/1,
- init_per_testcase/2, end_per_testcase/2]).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- cases().
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-cases() ->
- [persisten_event_api, start_stop_time_api,
- mapping_filter_api, max_events_api, discard_api,
- reorder_api, lookup_api, gc_api, auto_gc_api].
-
-
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-init_per_testcase(_Case, Config) ->
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-init_per_suite(Config) ->
- Path = code:which(?MODULE),
- code:add_pathz(filename:join(filename:dirname(Path), "idl_output")),
- orber:jump_start(),
- cosTime:install_time(),
- cosTime:start(),
- if
- is_list(Config) ->
- Config;
- true ->
- exit("Config not a list")
- end.
-
-end_per_suite(Config) ->
- Path = code:which(?MODULE),
- code:del_path(filename:join(filename:dirname(Path), "idl_output")),
- cosTime:stop(),
- cosTime:uninstall_time(),
- orber:jump_stop(),
- Config.
-
-
-%%-----------------------------------------------------------------
-%% cosNotification_eventDB lookup API tests
-%%-----------------------------------------------------------------
-%% The event DB is used to store events which cannot be
-%% delivered at once. This case is supposed to test
-%% that the events are delivered in the correct order
-%% if a MappingFilter have benn associated.
-mapping_filter_api(_Config) ->
- InitQoS = ?not_CreateInitQoS(),
- InitQoS2 = ?not_SetMaxEventsPerConsumer(InitQoS,100),
- InitQoS3 = ?not_SetStartTimeSupported(InitQoS2, false),
- InitQoS4 = ?not_SetStopTimeSupported(InitQoS3, true),
- QoS = ?not_SetDiscardPolicy(InitQoS4, ?not_AnyOrder),
-
- PriorityQoS = ?not_SetOrderPolicy(QoS, ?not_PriorityOrder),
- DeadlineQoS = ?not_SetOrderPolicy(QoS, ?not_DeadlineOrder),
-
- %% "Calculate" data once:
- %% NOTE! Even though the an Event do not match any of the constarints the
- %% default value will be used. Hence, the events will not be stored in the
- %% way described in the definitions above. For example, when using deadline order
- %% all the events will be stored in FIFO order since the usag of a MappingFilter
- %% all evnts will have the same deadline (except event6).
- Events = ?EVENTS,
- PrioOrder = [?EVENT6, ?EVENT1, ?EVENT2, ?EVENT3, ?EVENT4, ?EVENT5, ?EVENT7,
- ?EVENT8, ?EVENT9],
- DeadlineOrder = [?EVENT1, ?EVENT2, ?EVENT3, ?EVENT4, ?EVENT5, ?EVENT7, ?EVENT8,
- ?EVENT9],
-
-
- FiFac = 'CosNotifyFilter_FilterFactory':oe_create(),
- ?match({_,key,_,_,_,_}, FiFac),
-
- PrioFilter = 'CosNotifyFilter_FilterFactory':
- create_mapping_filter(FiFac, "EXTENDED_TCL", any:create(orber_tc:short(), 0)),
- DLFilter = 'CosNotifyFilter_FilterFactory':
- create_mapping_filter(FiFac, "EXTENDED_TCL", any:create(orber_tc:unsigned_long_long(), 1000000000)),
-
- ?match([_],
- 'CosNotifyFilter_MappingFilter':add_mapping_constraints(PrioFilter,
- [#'CosNotifyFilter_MappingConstraintPair'
- {constraint_expression = #'CosNotifyFilter_ConstraintExp'
- {event_types = [#'CosNotification_EventType'
- {domain_name = "",
- type_name = "event6"}],
- constraint_expr = "2==2"},
- result_to_set = any:create(orber_tc:short(), 10)}])),
- ?match([_],
- 'CosNotifyFilter_MappingFilter':add_mapping_constraints(DLFilter,
- [#'CosNotifyFilter_MappingConstraintPair'
- {constraint_expression = #'CosNotifyFilter_ConstraintExp'
- {event_types = [#'CosNotification_EventType'
- {domain_name = "",
- type_name = "event6"}],
- constraint_expr = "2==2"},
- result_to_set = any:create(orber_tc:unsigned_long_long(), 200000000)}])),
-
-
- do_lookup(PriorityQoS, Events, PrioOrder, "Priority Order", undefined, PrioFilter, 0),
- do_lookup(DeadlineQoS, Events, DeadlineOrder, "Deadline Order", DLFilter, undefined, 23000),
- ok.
-
-do_lookup(QoS, Events, Return, Txt, DLFilter, PrioFilter, Timeout) ->
- io:format("#################### ~s ###################~n", [Txt]),
- Ref = cosNotification_eventDB:create_db(QoS, 60, 50, undefined),
- create_loop(Events, Ref, DLFilter, PrioFilter),
- timer:sleep(Timeout),
- ?match({Return,_}, cosNotification_eventDB:get_events(Ref, ?NO_OF_EVENTS)),
- cosNotification_eventDB:destroy_db(Ref).
-
-%%-----------------------------------------------------------------
-%% cosNotification_eventDB discard API tests
-%%-----------------------------------------------------------------
-%% The event DB is used to store events which cannot be
-%% delivered at once. If MaxEvents limit is reached there
-%% different ways we can discard the. This case will test
-%% all permutations of order and discard policies.
-discard_api(_Config) ->
- InitQoS1 = ?not_CreateInitQoS(),
- InitQoS2 = ?not_SetPriority(InitQoS1, 10),
- InitQoS3 = ?not_SetStartTimeSupported(InitQoS2, false),
- QoS = ?not_SetMaxEventsPerConsumer(InitQoS3, 5),
- %% The different order policies. To each order we must apply every possible
- %% discard policy to each order policy setting. We also have to test and
- %% change the policies for each setting.
- AnyQoS = ?not_SetOrderPolicy(QoS, ?not_AnyOrder),
- PriorityQoS = ?not_SetOrderPolicy(QoS, ?not_PriorityOrder),
- FifoQoS = ?not_SetOrderPolicy(QoS, ?not_FifoOrder),
- DeadlineQoS = ?not_SetOrderPolicy(QoS, ?not_DeadlineOrder),
-
- Events = ?EVENTS,
-
- %% Test using Any discard policy
- do_discard(Events, ?not_SetDiscardPolicy(AnyQoS, ?not_AnyOrder),
- [?EVENT4, ?EVENT5, ?EVENT1, ?EVENT2, ?EVENT3],
- "Discard and Order eq. Any"),
- do_discard(Events, ?not_SetDiscardPolicy(PriorityQoS, ?not_AnyOrder),
- [?EVENT4, ?EVENT5, ?EVENT1, ?EVENT2, ?EVENT3],
- "Discard Any and Order Priority"),
- do_discard(Events, ?not_SetDiscardPolicy(FifoQoS, ?not_AnyOrder),
- [?EVENT1, ?EVENT2, ?EVENT3, ?EVENT4, ?EVENT5],
- "Discard Any and Order Fifo"),
- do_discard(Events, ?not_SetDiscardPolicy(DeadlineQoS, ?not_AnyOrder),
- [?EVENT5, ?EVENT4, ?EVENT3, ?EVENT2, ?EVENT1],
- "Discard Any and Order Deadline"),
-
- %% Test using RejectNewEvents discard policy
- do_discard(Events, ?not_SetDiscardPolicy(AnyQoS, ?not_RejectNewEvents),
- [?EVENT4, ?EVENT5, ?EVENT1, ?EVENT2, ?EVENT3],
- "Discard RejectNewEvents and Order Any"),
- do_discard(Events, ?not_SetDiscardPolicy(PriorityQoS, ?not_RejectNewEvents),
- [?EVENT4, ?EVENT5, ?EVENT1, ?EVENT2, ?EVENT3],
- "Discard RejectNewEvents and Order Priority"),
- do_discard(Events, ?not_SetDiscardPolicy(FifoQoS, ?not_RejectNewEvents),
- [?EVENT1, ?EVENT2, ?EVENT3, ?EVENT4, ?EVENT5],
- "Discard RejectNewEvents and Order Fifo"),
- do_discard(Events, ?not_SetDiscardPolicy(DeadlineQoS, ?not_RejectNewEvents),
- [?EVENT5, ?EVENT4, ?EVENT3, ?EVENT2, ?EVENT1],
- "Discard RejectNewEvents and Order Deadline"),
-
- %% Test using Lifo discard policy
- do_discard(Events, ?not_SetDiscardPolicy(AnyQoS, ?not_LifoOrder),
- [?EVENT4, ?EVENT5, ?EVENT1, ?EVENT2, ?EVENT3],
- "Discard Lifo and Order Any"),
- do_discard(Events, ?not_SetDiscardPolicy(PriorityQoS, ?not_LifoOrder),
- [?EVENT4, ?EVENT5, ?EVENT1, ?EVENT2, ?EVENT3],
- "Discard Lifo and Order Priority"),
- do_discard(Events, ?not_SetDiscardPolicy(FifoQoS, ?not_LifoOrder),
- [?EVENT1, ?EVENT2, ?EVENT3, ?EVENT4, ?EVENT5],
- "Discard Lifo and Order Fifo"),
- do_discard(Events, ?not_SetDiscardPolicy(DeadlineQoS, ?not_LifoOrder),
- [?EVENT5, ?EVENT4, ?EVENT3, ?EVENT2, ?EVENT1],
- "Discard Lifo and Order Deadline"),
-
- %% Test using Fifo discard policy
- do_discard(Events, ?not_SetDiscardPolicy(AnyQoS, ?not_FifoOrder),
- [?EVENT5, ?EVENT6, ?EVENT9, ?EVENT7, ?EVENT8],
- "Discard Fifo and Order Any"),
- do_discard(Events, ?not_SetDiscardPolicy(PriorityQoS, ?not_FifoOrder),
- [?EVENT5, ?EVENT6, ?EVENT9, ?EVENT7, ?EVENT8],
- "Discard Fifo and Order Priority"),
- do_discard(Events, ?not_SetDiscardPolicy(FifoQoS, ?not_FifoOrder),
- [?EVENT5, ?EVENT6, ?EVENT7, ?EVENT8, ?EVENT9],
- "Discard Fifo and Order Fifo"),
- do_discard(Events, ?not_SetDiscardPolicy(DeadlineQoS, ?not_FifoOrder),
- [?EVENT9, ?EVENT5, ?EVENT7, ?EVENT6, ?EVENT8],
- "Discard Fifo and Order Deadline"),
-
- %% Test using Priority discard policy
- do_discard(Events, ?not_SetDiscardPolicy(AnyQoS, ?not_PriorityOrder),
- [?EVENT4, ?EVENT5, ?EVENT1, ?EVENT2, ?EVENT3],
- "Discard Priority and Order Any"),
- do_discard(Events, ?not_SetDiscardPolicy(PriorityQoS, ?not_PriorityOrder),
- [?EVENT4, ?EVENT5, ?EVENT1, ?EVENT2, ?EVENT3],
- "Discard Priority and Order Priority"),
- do_discard(Events, ?not_SetDiscardPolicy(FifoQoS, ?not_PriorityOrder),
- [?EVENT1, ?EVENT2, ?EVENT3, ?EVENT4, ?EVENT5],
- "Discard Priority and Order Fifo"),
- do_discard(Events, ?not_SetDiscardPolicy(DeadlineQoS, ?not_PriorityOrder),
- [?EVENT5, ?EVENT4, ?EVENT3, ?EVENT2, ?EVENT1],
- "Discard Priority and Order Deadline"),
-
- %% Test using Deadline discard policy
- do_discard(Events, ?not_SetDiscardPolicy(AnyQoS, ?not_DeadlineOrder),
- [?EVENT1, ?EVENT2, ?EVENT3, ?EVENT6, ?EVENT8],
- "Discard Deadline and Order Any"),
- do_discard(Events, ?not_SetDiscardPolicy(PriorityQoS, ?not_DeadlineOrder),
- [?EVENT1, ?EVENT2, ?EVENT3, ?EVENT6, ?EVENT8],
- "Discard Deadline and Order Priority"),
- do_discard(Events, ?not_SetDiscardPolicy(FifoQoS, ?not_DeadlineOrder),
- [?EVENT1, ?EVENT2, ?EVENT3, ?EVENT6, ?EVENT8],
- "Discard Deadline and Order Fifo"),
- do_discard(Events, ?not_SetDiscardPolicy(DeadlineQoS, ?not_DeadlineOrder),
- [?EVENT6, ?EVENT8, ?EVENT3, ?EVENT2, ?EVENT1],
- "Discard Deadline and Order Deadline"),
-
- ok.
-
-do_discard(Events, QoS, Reply, Txt) ->
- io:format("################# ~s #################~n", [Txt]),
- Ref = cosNotification_eventDB:create_db(QoS, 60, 50, undefined),
- create_loop(Events, Ref),
- ?match({Reply,_}, cosNotification_eventDB:get_events(Ref, ?NO_OF_EVENTS)),
- cosNotification_eventDB:destroy_db(Ref).
-
-
-%%-----------------------------------------------------------------
-%% cosNotification_eventDB lookup API tests
-%%-----------------------------------------------------------------
-%% The event DB is used to store events which cannot be
-%% delivered at once. This case is supposed to test
-%% that the events are delivered in the correct order.
-lookup_api(_Config) ->
- InitQoS = ?not_CreateInitQoS(),
- InitQoS2 = ?not_SetMaxEventsPerConsumer(InitQoS,100),
- InitQoS3 = ?not_SetStartTimeSupported(InitQoS2, false),
- QoS = ?not_SetDiscardPolicy(InitQoS3, ?not_AnyOrder),
-
- AnyQoS = ?not_SetOrderPolicy(QoS, ?not_AnyOrder),
- PriorityQoS = ?not_SetOrderPolicy(QoS, ?not_PriorityOrder),
- FifoQoS = ?not_SetOrderPolicy(QoS, ?not_FifoOrder),
- DeadlineQoS = ?not_SetOrderPolicy(QoS, ?not_DeadlineOrder),
-
- %% "Calculate" data once:
- Events = ?EVENTS,
- PrioOrder = ?PRIOORDER,
- FifoOrder = ?FIFOORDER,
- DeadlineOrder = ?DEADLINEORDER,
-
- do_lookup(PriorityQoS, Events, PrioOrder, "Priority Order"),
- do_lookup(FifoQoS, Events, FifoOrder, "Fifo Order"),
- do_lookup(DeadlineQoS, Events, DeadlineOrder, "Deadline Order"),
- do_lookup(AnyQoS, Events, PrioOrder, "Any Order"),
- ok.
-
-do_lookup(QoS, Events, Return, Txt) ->
- io:format("#################### ~s ###################~n", [Txt]),
- Ref = cosNotification_eventDB:create_db(QoS, 60, 50, undefined),
- create_loop(Events, Ref),
- ?match({Return,_}, cosNotification_eventDB:get_events(Ref, ?NO_OF_EVENTS)),
- cosNotification_eventDB:destroy_db(Ref).
-
-
-%%-----------------------------------------------------------------
-%% cosNotification_eventDB max events API tests
-%%-----------------------------------------------------------------
-%% The event DB is used to store events which cannot be
-%% delivered at once. If the MaxEvents QoS is updated we must be
-%% able to reduce the amount of stored events.
-max_events_api(_Config) ->
-
- QoS1 = ?not_CreateInitQoS(),
- QoS2 = ?not_SetOrderPolicy(QoS1, ?not_FifoOrder),
- QoS3 = ?not_SetDiscardPolicy(QoS2, ?not_RejectNewEvents),
- QoS4 = ?not_SetStartTimeSupported(QoS3, false),
- QoS_NO_OF_EVENTS = ?not_SetMaxEventsPerConsumer(QoS4, ?NO_OF_EVENTS),
- QoS_5_EVENTS = ?not_SetMaxEventsPerConsumer(QoS4, 5),
-
- Events = ?EVENTS,
- Events5 = [?EVENT1, ?EVENT2, ?EVENT3, ?EVENT4, ?EVENT5],
-
- %% Initiate DB and 'NO_OF_EVENTS' events.
- Ref1 = cosNotification_eventDB:create_db(QoS_NO_OF_EVENTS, 60, 50, undefined),
- create_loop(Events, Ref1),
-
- %% Reduce the limit to 5 and extract all and see if it's ok.
- Ref2 = cosNotification_eventDB:update(Ref1, QoS_5_EVENTS),
- ?match({Events5, true}, cosNotification_eventDB:get_events(Ref2, ?NO_OF_EVENTS)),
-
- %% Add 'NO_OF_EVENTS' events. Since the only allow 5 events the DB will only
- %% contain 5 events.
- create_loop(Events, Ref2),
- Ref3 = cosNotification_eventDB:update(Ref2, QoS_NO_OF_EVENTS),
-
- ?match({Events5, true}, cosNotification_eventDB:get_events(Ref3, ?NO_OF_EVENTS)),
- create_loop(Events, Ref3),
- ?match({Events, true}, cosNotification_eventDB:get_events(Ref3, ?NO_OF_EVENTS)),
- cosNotification_eventDB:destroy_db(Ref3),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% cosNotification_eventDB persisten events API tests
-%%-----------------------------------------------------------------
-%% The event DB is used to store events which cannot be
-%% delivered at once.
-persisten_event_api(_Config) ->
-
- QoS1 = ?not_CreateInitQoS(),
- QoS2 = ?not_SetOrderPolicy(QoS1, ?not_FifoOrder),
- QoS3 = ?not_SetDiscardPolicy(QoS2, ?not_RejectNewEvents),
- QoS4 = ?not_SetStartTimeSupported(QoS3, false),
- QoS = ?not_SetMaxEventsPerConsumer(QoS4, ?NO_OF_EVENTS),
-
- Event1 = ?EVENT1,
-
- Ref = cosNotification_eventDB:create_db(QoS, 60, 50, undefined),
- %% Clean DB, should be empty
- ?match(0, cosNotification_eventDB:status(Ref, eventCounter)),
- cosNotification_eventDB:add_event(Ref, Event1),
- ?match(1, cosNotification_eventDB:status(Ref, eventCounter)),
- %% Get event without removing it. Should still be one event stored
- ?match({[Event1], _, _}, cosNotification_eventDB:get_events(Ref, 2, false)),
- ?match(1, cosNotification_eventDB:status(Ref, eventCounter)),
- {_, _, Keys} =
- ?match({Event1, _, _}, cosNotification_eventDB:get_event(Ref, false)),
- ?match(1, cosNotification_eventDB:status(Ref, eventCounter)),
- %% Clear the events and check that the DB is empty.
- cosNotification_eventDB:delete_events(Keys),
- ?match(0, cosNotification_eventDB:status(Ref, eventCounter)),
- ?match({[], _, []}, cosNotification_eventDB:get_event(Ref, false)),
- ?match({[], _, []}, cosNotification_eventDB:get_events(Ref, 2, false)),
-
- cosNotification_eventDB:destroy_db(Ref),
- ok.
-
-%%-----------------------------------------------------------------
-%% cosNotification_eventDB gc API tests
-%%-----------------------------------------------------------------
-%% The event DB is used to store events which cannot be
-%% delivered at once. If Deadline defined the events that
-%% are older must be discarded.
-gc_api(_Config) ->
-
- QoS1 = ?not_CreateInitQoS(),
- QoS2 = ?not_SetOrderPolicy(QoS1, ?not_FifoOrder),
- QoS3 = ?not_SetDiscardPolicy(QoS2, ?not_RejectNewEvents),
- QoS4 = ?not_SetStartTimeSupported(QoS3, false),
- QoS_NO_OF_EVENTS = ?not_SetMaxEventsPerConsumer(QoS4, ?NO_OF_EVENTS),
-
- Events = ?EVENTS,
- Events6 = [?EVENT1, ?EVENT2, ?EVENT3, ?EVENT4, ?EVENT6, ?EVENT7, ?EVENT8],
- %% Initiate DB and 'NO_OF_EVENTS' events.
- Ref = cosNotification_eventDB:create_db(QoS_NO_OF_EVENTS, 60, 50, undefined),
- create_loop(Events, Ref),
-
- %% Sleep so some events will get 'old'.
- timer:sleep(23000),
-
- %% Reduce the limit to 5 and extract all and see if it's ok.
- cosNotification_eventDB:gc_events(Ref, high),
-
- %% Since gc is done by another process we must wait so it will have a chance
- %% to complete the job.
- timer:sleep(2000),
-
- ?match({Events6, true}, cosNotification_eventDB:get_events(Ref, ?NO_OF_EVENTS)),
-
- create_loop(Events, Ref),
- timer:sleep(23000),
- ?match({Events6, true}, cosNotification_eventDB:get_events(Ref, ?NO_OF_EVENTS)),
- cosNotification_eventDB:destroy_db(Ref),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% cosNotification_eventDB gc API tests
-%%-----------------------------------------------------------------
-%% The event DB is used to store events which cannot be
-%% delivered at once. If Deadline defined the events that
-%% are older must be discarded.
-auto_gc_api(_Config) ->
-
- QoS1 = ?not_CreateInitQoS(),
- QoS2 = ?not_SetOrderPolicy(QoS1, ?not_FifoOrder),
- QoS3 = ?not_SetDiscardPolicy(QoS2, ?not_RejectNewEvents),
- QoS4 = ?not_SetStopTimeSupported(QoS3, true),
- QoS5 = ?not_SetStartTimeSupported(QoS4, false),
- QoS_NO_OF_EVENTS = ?not_SetMaxEventsPerConsumer(QoS5, ?NO_OF_EVENTS),
-
- Events6 = [?EVENT1, ?EVENT2, ?EVENT3, ?EVENT7, ?EVENT8, ?EVENT9],
- %% Initiate DB
- Ref = cosNotification_eventDB:create_db(QoS_NO_OF_EVENTS, 50, 50, undefined),
- create_loop([?EVENT1, ?EVENT2, ?EVENT3, ?EVENT4, ?EVENT6], Ref),
-
- %% Sleep so some events will get 'old'.
- timer:sleep(60000),
- create_loop([?EVENT7, ?EVENT8, ?EVENT9], Ref),
-
- %% Since gc is done by another process we must wait so it will have a chance
- %% to complete the job.
- timer:sleep(2000),
-
- ?match({Events6, true}, cosNotification_eventDB:get_events(Ref, ?NO_OF_EVENTS)),
-
- cosNotification_eventDB:destroy_db(Ref),
-
- ok.
-
-
-%%-----------------------------------------------------------------
-%% cosNotification_eventDB start- and stop-time API tests
-%%-----------------------------------------------------------------
-%% The event DB is used to store events which cannot be
-%% delivered at once. If Deadline defined the events that
-%% are older must be discarded.
-start_stop_time_api(_Config) ->
-
- QoS1 = ?not_CreateInitQoS(),
- QoS2 = ?not_SetOrderPolicy(QoS1, ?not_FifoOrder),
- QoS3 = ?not_SetDiscardPolicy(QoS2, ?not_RejectNewEvents),
- QoS4 = ?not_SetStopTimeSupported(QoS3, true),
- QoS5 = ?not_SetStartTimeSupported(QoS4, true),
- QoS_NO_OF_EVENTS = ?not_SetMaxEventsPerConsumer(QoS5, ?NO_OF_EVENTS),
-
- %% Initiate DB
- TimeService = cosTime:start_time_service(2, 0),
- Ref = cosNotification_eventDB:create_db(QoS_NO_OF_EVENTS, 50, 50, TimeService),
-
- T1 = 'CosTime_UTO':'_get_utc_time'('CosTime_UTO':
- absolute_time('CosTime_TimeService':
- new_universal_time(TimeService,
- 100000000, 0, 2))),
- T2 = 'CosTime_UTO':'_get_utc_time'('CosTime_UTO':
- absolute_time('CosTime_TimeService':
- new_universal_time(TimeService,
- 200000000, 0, 2))),
- T3 = 'CosTime_UTO':'_get_utc_time'('CosTime_UTO':
- absolute_time('CosTime_TimeService':
- new_universal_time(TimeService,
- 300000000, 0, 2))),
- T4 = 'CosTime_UTO':'_get_utc_time'('CosTime_UTO':
- absolute_time('CosTime_TimeService':
- new_universal_time(TimeService,
- 400000000, 0, 2))),
- %% Delivered after 10 seconds discarded after 20.
- EVENT1 = ?not_CreateSE("","event1","",
- [#'CosNotification_Property'
- {name="Priority",
- value=any:create(orber_tc:short(), 1)},
- #'CosNotification_Property'
- {name="StartTime",
- value=any:create('TimeBase_UtcT':tc(), T1)},
- #'CosNotification_Property'
- {name="StopTime",
- value=any:create('TimeBase_UtcT':tc(), T2)}],
- [], any:create(orber_tc:null(), null)),
-
- %% Delivered after 30 seconds discarded after 10, i.e., always discarded.
- EVENT2 = ?not_CreateSE("","event2","",
- [#'CosNotification_Property'
- {name="Priority",
- value=any:create(orber_tc:short(), 3)},
- #'CosNotification_Property'
- {name="StartTime",
- value=any:create('TimeBase_UtcT':tc(), T3)},
- #'CosNotification_Property'
- {name="StopTime",
- value=any:create('TimeBase_UtcT':tc(), T1)}],
- [], any:create(orber_tc:null(), null)),
-
- %% Delivered after 20 seconds discarded after 40
- EVENT3 = ?not_CreateSE("","event3","",
- [#'CosNotification_Property'
- {name="Priority",
- value=any:create(orber_tc:short(), 2)},
- #'CosNotification_Property'
- {name="StartTime",
- value=any:create('TimeBase_UtcT':tc(), T2)},
- #'CosNotification_Property'
- {name="StopTime",
- value=any:create('TimeBase_UtcT':tc(), T4)}],
- [], any:create(orber_tc:null(), null)),
-
-
-
-
- create_loop([EVENT1, EVENT2, EVENT3], Ref),
-
- ?match({[], false}, cosNotification_eventDB:get_events(Ref, ?NO_OF_EVENTS)),
-
- %% Sleep so some events will get 'old'.
- timer:sleep(12000),
-
- ?match({[EVENT1], true}, cosNotification_eventDB:get_events(Ref, ?NO_OF_EVENTS)),
-
- ?match({[], false}, cosNotification_eventDB:get_events(Ref, ?NO_OF_EVENTS)),
-
- timer:sleep(10000),
-
- ?match({[EVENT3], true}, cosNotification_eventDB:get_events(Ref, ?NO_OF_EVENTS)),
-
- timer:sleep(20000),
-
- %% See if EVENT2 really have been discarded.
- ?match({[], false}, cosNotification_eventDB:get_events(Ref, ?NO_OF_EVENTS)),
-
- cosNotification_eventDB:destroy_db(Ref),
-
- cosTime:stop_time_service(TimeService),
-
- ok.
-
-
-%%-----------------------------------------------------------------
-%% cosNotification_eventDB order API tests
-%%-----------------------------------------------------------------
-%% The event DB is used to store events which cannot be
-%% delivered at once. If the QoS is updated we must be
-%% able to change the ordering of events as the discard
-%% and order policies tells us.
-reorder_api(_Config) ->
- %% We need to test switching between:
- %% * Priority -> Fifo
- %% * Priority -> Deadline
- %% * Fifo -> Priority
- %% * Fifo -> Deadline
- %% * Deadline -> Priority
- %% * Deadline -> Fifo
- QoS = ?not_CreateInitQoS(),
- QoS2 = ?not_SetMaxEventsPerConsumer(QoS,100),
- QoS3 = ?not_SetPriority(QoS2, 10),
- QoS4 = ?not_SetStartTimeSupported(QoS3, false),
- QoS5 = ?not_SetOrderPolicy(QoS4, ?not_AnyOrder),
-
-
- %% Test all order policies using Any order discard policy.
- reorder_helper(?not_SetDiscardPolicy(QoS5, ?not_AnyOrder), "Discard Any"),
- reorder_helper(?not_SetDiscardPolicy(QoS5, ?not_PriorityOrder), "Discard Priority"),
- reorder_helper(?not_SetDiscardPolicy(QoS5, ?not_DeadlineOrder), "Discard Deadline"),
- reorder_helper(?not_SetDiscardPolicy(QoS5, ?not_FifoOrder), "Discard Fifo"),
- reorder_helper(?not_SetDiscardPolicy(QoS5, ?not_LifoOrder), "Discard Lifo"),
- reorder_helper(?not_SetDiscardPolicy(QoS5, ?not_RejectNewEvents), "Reject New Events"),
-
- ok.
-
-
-reorder_helper(QoS, Txt) ->
- io:format("$$$$$$$$$$$$$$$$$$$$ ~s $$$$$$$$$$$$$$$$$$$~n", [Txt]),
- %% Create a DB with the above settings.
- Ref = cosNotification_eventDB:create_db(QoS, 60, 50, undefined),
-
- Events = ?EVENTS,
- PrioOrder = ?PRIOORDER,
- FifoOrder = ?FIFOORDER,
- DeadlineOrder = ?DEADLINEORDER,
-
- %% Test all order policies using Any order discard policy.
- Ref2 = do_reorder(Ref, Events, ?not_SetOrderPolicy(QoS, ?not_FifoOrder),
- FifoOrder, "Priority -> Fifo"),
- Ref3 = do_reorder(Ref2, Events, ?not_SetOrderPolicy(QoS, ?not_PriorityOrder),
- PrioOrder, "Fifo -> Priority"),
- Ref4 = do_reorder(Ref3, Events, ?not_SetOrderPolicy(QoS, ?not_DeadlineOrder),
- DeadlineOrder, "Priority -> Deadline"),
-
- Ref5 = do_reorder(Ref4, Events, ?not_SetOrderPolicy(QoS, ?not_PriorityOrder),
- PrioOrder, "Deadline -> Priority"),
-
- Ref6 = do_reorder(Ref5, Events, ?not_SetOrderPolicy(QoS, ?not_FifoOrder),
- FifoOrder, "Priority -> Fifo"),
-
- Ref7 = do_reorder(Ref6, Events, ?not_SetOrderPolicy(QoS, ?not_DeadlineOrder),
- DeadlineOrder, "Fifo -> Deadline"),
-
- Ref8 = do_reorder(Ref7, Events, ?not_SetOrderPolicy(QoS, ?not_FifoOrder),
- FifoOrder, "Deadline -> Fifo"),
- cosNotification_eventDB:destroy_db(Ref8),
- ok.
-
-
-
-do_reorder(Ref, Events, QoS, Reply, Txt) ->
- create_loop(Events, Ref),
- io:format("################# ~s #################~n", [Txt]),
- NewRef = cosNotification_eventDB:update(Ref, QoS),
- ?match({Reply,_}, cosNotification_eventDB:get_events(NewRef, ?NO_OF_EVENTS)),
- NewRef.
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-%% This functions takes as argument a list of structured events.
-create_loop([], _Ref) ->
- ok;
-create_loop([H|T], Ref) ->
- catch cosNotification_eventDB:add_event(Ref, H),
- create_loop(T, Ref).
-
-create_loop([], _Ref, _Life, _Prio) ->
- ok;
-create_loop([H|T], Ref, Life, Prio) ->
- catch cosNotification_eventDB:add_event(Ref, H, Life, Prio),
- create_loop(T, Ref, Life, Prio).
-
-%%-------------------- End of Module ------------------------------
diff --git a/lib/cosNotification/test/generated_SUITE.erl b/lib/cosNotification/test/generated_SUITE.erl
deleted file mode 100644
index 8e3ccbd90e..0000000000
--- a/lib/cosNotification/test/generated_SUITE.erl
+++ /dev/null
@@ -1,1928 +0,0 @@
-%%-----------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File : generated_SUITE.erl
-%% Purpose :
-%%-----------------------------------------------------------------
-
--module(generated_SUITE).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/include/corba.hrl").
-
--define(default_timeout, test_server:minutes(3)).
-
--define(match(ExpectedRes, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
--define(nomatch(Not, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- Not ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS);
- _ ->
- AcTuAlReS
- end
- end()).
-
-
--define(checktc(_Op),
- fun(TC) ->
- case orber_tc:check_tc(TC) of
- false ->
- io:format("###### ERROR ERROR ######~n~p - ~p~n", [Op, TC]),
- exit(TC);
- true ->
- true
- end
- end).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--compile(export_all).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- ['CosNotification',
- 'CosNotification_AdminPropertiesAdmin',
- 'CosNotification_EventHeader',
- 'CosNotification_EventType',
- 'CosNotification_FixedEventHeader',
- 'CosNotification_NamedPropertyRange',
- 'CosNotification_Property',
- 'CosNotification_PropertyError',
- 'CosNotification_PropertyRange',
- 'CosNotification_QoSAdmin',
- 'CosNotification_StructuredEvent',
- 'CosNotification_UnsupportedAdmin',
- 'CosNotification_UnsupportedQoS',
- 'CosNotification_EventBatch',
- 'CosNotification_EventTypeSeq',
- 'CosNotification_NamedPropertyRangeSeq',
- 'CosNotification_PropertyErrorSeq',
- 'CosNotifyChannelAdmin_AdminLimit',
- 'CosNotifyChannelAdmin_AdminNotFound',
- 'CosNotifyChannelAdmin_ChannelNotFound',
- 'CosNotifyChannelAdmin_ConnectionAlreadyActive',
- 'CosNotifyChannelAdmin_ConnectionAlreadyInactive',
- 'CosNotifyChannelAdmin_NotConnected',
- 'CosNotifyChannelAdmin_AdminIDSeq',
- 'CosNotifyChannelAdmin_ChannelIDSeq',
- 'CosNotifyChannelAdmin_ProxyIDSeq',
- 'CosNotifyFilter_CallbackNotFound',
- 'CosNotifyFilter_ConstraintExp',
- 'CosNotifyFilter_ConstraintInfo',
- 'CosNotifyFilter_ConstraintNotFound',
- 'CosNotifyFilter_DuplicateConstraintID',
- 'CosNotifyFilter_FilterNotFound',
- 'CosNotifyFilter_InvalidConstraint',
- 'CosNotifyFilter_InvalidGrammar',
- 'CosNotifyFilter_InvalidValue',
- 'CosNotifyFilter_MappingConstraintInfo',
- 'CosNotifyFilter_MappingConstraintPair',
- 'CosNotifyFilter_UnsupportedFilterableData',
- 'CosNotifyFilter_CallbackIDSeq',
- 'CosNotifyFilter_ConstraintExpSeq',
- 'CosNotifyFilter_ConstraintIDSeq',
- 'CosNotifyFilter_ConstraintInfoSeq',
- 'CosNotifyFilter_FilterIDSeq',
- 'CosNotifyFilter_MappingConstraintInfoSeq',
- 'CosNotifyFilter_MappingConstraintPairSeq',
- 'CosNotifyComm_InvalidEventType',
- 'CosNotifyChannelAdmin_ConsumerAdmin',
- 'CosNotifyChannelAdmin_EventChannel',
- 'CosNotifyChannelAdmin_EventChannelFactory',
- 'CosNotifyChannelAdmin_ProxyConsumer',
- 'CosNotifyChannelAdmin_ProxyNotFound',
- 'CosNotifyChannelAdmin_ProxyPullConsumer',
- 'CosNotifyChannelAdmin_ProxyPullSupplier',
- 'CosNotifyChannelAdmin_ProxyPushConsumer',
- 'CosNotifyChannelAdmin_ProxyPushSupplier',
- 'CosNotifyChannelAdmin_ProxySupplier',
- 'CosNotifyChannelAdmin_SequenceProxyPullConsumer',
- 'CosNotifyChannelAdmin_SequenceProxyPullSupplier',
- 'CosNotifyChannelAdmin_SequenceProxyPushConsumer',
- 'CosNotifyChannelAdmin_SequenceProxyPushSupplier',
- 'CosNotifyChannelAdmin_StructuredProxyPullConsumer',
- 'CosNotifyChannelAdmin_StructuredProxyPullSupplier',
- 'CosNotifyChannelAdmin_StructuredProxyPushConsumer',
- 'CosNotifyChannelAdmin_StructuredProxyPushSupplier',
- 'CosNotifyChannelAdmin_SupplierAdmin',
- 'CosNotifyFilter_Filter', 'CosNotifyFilter_FilterAdmin',
- 'CosNotifyFilter_FilterFactory',
- 'CosNotifyFilter_MappingFilter',
- 'CosNotifyComm_NotifyPublish',
- 'CosNotifyComm_NotifySubscribe',
- 'CosNotifyComm_PullConsumer',
- 'CosNotifyComm_PullSupplier',
- 'CosNotifyComm_PushConsumer',
- 'CosNotifyComm_PushSupplier',
- 'CosNotifyComm_SequencePullConsumer',
- 'CosNotifyComm_SequencePullSupplier',
- 'CosNotifyComm_SequencePushConsumer',
- 'CosNotifyComm_SequencePushSupplier',
- 'CosNotifyComm_StructuredPullConsumer',
- 'CosNotifyComm_StructuredPullSupplier',
- 'CosNotifyComm_StructuredPushConsumer',
- 'CosNotifyComm_StructuredPushSupplier',
- oe_CosNotificationComm_Event,
- 'CosNotification_PropertySeq'].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-init_per_testcase(_Case, Config) ->
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotification'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotification'(_) ->
- ?match("EventReliability", 'CosNotification':'EventReliability'()),
- ?match(0, 'CosNotification':'BestEffort'()),
- ?match(1, 'CosNotification':'Persistent'()),
- ?match("ConnectionReliability", 'CosNotification':'ConnectionReliability'()),
- ?match("Priority", 'CosNotification':'Priority'()),
- ?match(-32767, 'CosNotification':'LowestPriority'()),
- ?match(32767, 'CosNotification':'HighestPriority'()),
- ?match(0, 'CosNotification':'DefaultPriority'()),
- ?match("StartTime", 'CosNotification':'StartTime'()),
- ?match("StopTime", 'CosNotification':'StopTime'()),
- ?match("Timeout", 'CosNotification':'Timeout'()),
- ?match("OrderPolicy", 'CosNotification':'OrderPolicy'()),
- ?match(0, 'CosNotification':'AnyOrder'()),
- ?match(1, 'CosNotification':'FifoOrder'()),
- ?match(2, 'CosNotification':'PriorityOrder'()),
- ?match(3, 'CosNotification':'DeadlineOrder'()),
- ?match("DiscardPolicy", 'CosNotification':'DiscardPolicy'()),
- ?match(4, 'CosNotification':'LifoOrder'()),
- ?match(5, 'CosNotification':'RejectNewEvents'()),
- ?match("MaximumBatchSize", 'CosNotification':'MaximumBatchSize'()),
- ?match("PacingInterval", 'CosNotification':'PacingInterval'()),
- ?match("StartTimeSupported", 'CosNotification':'StartTimeSupported'()),
- ?match("StopTimeSupported", 'CosNotification':'StopTimeSupported'()),
- ?match("MaxEventsPerConsumer", 'CosNotification':'MaxEventsPerConsumer'()),
- ?match("MaxQueueLength", 'CosNotification':'MaxQueueLength'()),
- ?match("MaxConsumers", 'CosNotification':'MaxConsumers'()),
- ?match("MaxSuppliers", 'CosNotification':'MaxSuppliers'()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotification_EventHeader'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotification_EventHeader'(_) ->
- ?match(true, orber_tc:check_tc('CosNotification_EventHeader':tc())),
- ?match("IDL:omg.org/CosNotification/EventHeader:1.0",
- 'CosNotification_EventHeader':id()),
- ?match("CosNotification_EventHeader",
- 'CosNotification_EventHeader':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotification_EventType'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotification_EventType'(_) ->
- ?match(true, orber_tc:check_tc('CosNotification_EventType':tc())),
- ?match("IDL:omg.org/CosNotification/EventType:1.0",
- 'CosNotification_EventType':id()),
- ?match("CosNotification_EventType",
- 'CosNotification_EventType':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotification_FixedEventHeader'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotification_FixedEventHeader'(_) ->
- ?match(true, orber_tc:check_tc('CosNotification_FixedEventHeader':tc())),
- ?match("IDL:omg.org/CosNotification/FixedEventHeader:1.0",
- 'CosNotification_FixedEventHeader':id()),
- ?match("CosNotification_FixedEventHeader",
- 'CosNotification_FixedEventHeader':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotification_NamedPropertyRange'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotification_NamedPropertyRange'(_) ->
- ?match(true, orber_tc:check_tc('CosNotification_NamedPropertyRange':tc())),
- ?match("IDL:omg.org/CosNotification/NamedPropertyRange:1.0",
- 'CosNotification_NamedPropertyRange':id()),
- ?match("CosNotification_NamedPropertyRange",
- 'CosNotification_NamedPropertyRange':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotification_Property'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotification_Property'(_) ->
- ?match(true, orber_tc:check_tc('CosNotification_Property':tc())),
- ?match("IDL:omg.org/CosNotification/Property:1.0",
- 'CosNotification_Property':id()),
- ?match("CosNotification_Property",
- 'CosNotification_Property':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotification_PropertyError'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotification_PropertyError'(_) ->
- ?match(true, orber_tc:check_tc('CosNotification_PropertyError':tc())),
- ?match("IDL:omg.org/CosNotification/PropertyError:1.0",
- 'CosNotification_PropertyError':id()),
- ?match("CosNotification_PropertyError",
- 'CosNotification_PropertyError':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotification_PropertyRange'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotification_PropertyRange'(_) ->
- ?match(true, orber_tc:check_tc('CosNotification_PropertyRange':tc())),
- ?match("IDL:omg.org/CosNotification/PropertyRange:1.0",
- 'CosNotification_PropertyRange':id()),
- ?match("CosNotification_PropertyRange",
- 'CosNotification_PropertyRange':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotification_StructuredEvent'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotification_StructuredEvent'(_) ->
- ?match(true, orber_tc:check_tc('CosNotification_StructuredEvent':tc())),
- ?match("IDL:omg.org/CosNotification/StructuredEvent:1.0",
- 'CosNotification_StructuredEvent':id()),
- ?match("CosNotification_StructuredEvent",
- 'CosNotification_StructuredEvent':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotification_UnsupportedAdmin'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotification_UnsupportedAdmin'(_) ->
- ?match(true, orber_tc:check_tc('CosNotification_UnsupportedAdmin':tc())),
- ?match("IDL:omg.org/CosNotification/UnsupportedAdmin:1.0",
- 'CosNotification_UnsupportedAdmin':id()),
- ?match("CosNotification_UnsupportedAdmin",
- 'CosNotification_UnsupportedAdmin':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotification_UnsupportedQoS'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotification_UnsupportedQoS'(_) ->
- ?match(true, orber_tc:check_tc('CosNotification_UnsupportedQoS':tc())),
- ?match("IDL:omg.org/CosNotification/UnsupportedQoS:1.0",
- 'CosNotification_UnsupportedQoS':id()),
- ?match("CosNotification_UnsupportedQoS",
- 'CosNotification_UnsupportedQoS':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotification_EventBatch'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotification_EventBatch'(_) ->
- ?match(true, orber_tc:check_tc('CosNotification_EventBatch':tc())),
- ?match("IDL:omg.org/CosNotification/EventBatch:1.0",
- 'CosNotification_EventBatch':id()),
- ?match("CosNotification_EventBatch",
- 'CosNotification_EventBatch':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotification_EventTypeSeq'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotification_EventTypeSeq'(_) ->
- ?match(true, orber_tc:check_tc('CosNotification_EventTypeSeq':tc())),
- ?match("IDL:omg.org/CosNotification/EventTypeSeq:1.0",
- 'CosNotification_EventTypeSeq':id()),
- ?match("CosNotification_EventTypeSeq",
- 'CosNotification_EventTypeSeq':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotification_NamedPropertyRangeSeq'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotification_NamedPropertyRangeSeq'(_) ->
- ?match(true, orber_tc:check_tc('CosNotification_NamedPropertyRangeSeq':tc())),
- ?match("IDL:omg.org/CosNotification/NamedPropertyRangeSeq:1.0",
- 'CosNotification_NamedPropertyRangeSeq':id()),
- ?match("CosNotification_NamedPropertyRangeSeq",
- 'CosNotification_NamedPropertyRangeSeq':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotification_PropertyErrorSeq'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotification_PropertyErrorSeq'(_) ->
- ?match(true, orber_tc:check_tc('CosNotification_PropertyErrorSeq':tc())),
- ?match("IDL:omg.org/CosNotification/PropertyErrorSeq:1.0",
- 'CosNotification_PropertyErrorSeq':id()),
- ?match("CosNotification_PropertyErrorSeq",
- 'CosNotification_PropertyErrorSeq':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotification_PropertySeq'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotification_PropertySeq'(_) ->
- ?match(true, orber_tc:check_tc('CosNotification_PropertySeq':tc())),
- ?match("IDL:omg.org/CosNotification/PropertySeq:1.0",
- 'CosNotification_PropertySeq':id()),
- ?match("CosNotification_PropertySeq",
- 'CosNotification_PropertySeq':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_AdminLimit'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_AdminLimit'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyChannelAdmin_AdminLimit':tc())),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/AdminLimit:1.0",
- 'CosNotifyChannelAdmin_AdminLimit':id()),
- ?match("CosNotifyChannelAdmin_AdminLimit",
- 'CosNotifyChannelAdmin_AdminLimit':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_AdminLimitExceeded'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_AdminLimitExceeded'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyChannelAdmin_AdminLimitExceeded':tc())),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/AdminLimitExceeded:1.0",
- 'CosNotifyChannelAdmin_AdminLimitExceeded':id()),
- ?match("CosNotifyChannelAdmin_AdminLimitExceeded",
- 'CosNotifyChannelAdmin_AdminLimitExceeded':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_AdminNotFound'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_AdminNotFound'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyChannelAdmin_AdminNotFound':tc())),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/AdminNotFound:1.0",
- 'CosNotifyChannelAdmin_AdminNotFound':id()),
- ?match("CosNotifyChannelAdmin_AdminNotFound",
- 'CosNotifyChannelAdmin_AdminNotFound':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_ChannelNotFound'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_ChannelNotFound'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyChannelAdmin_ChannelNotFound':tc())),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/ChannelNotFound:1.0",
- 'CosNotifyChannelAdmin_ChannelNotFound':id()),
- ?match("CosNotifyChannelAdmin_ChannelNotFound",
- 'CosNotifyChannelAdmin_ChannelNotFound':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_ConnectionAlreadyActive'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_ConnectionAlreadyActive'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyChannelAdmin_ConnectionAlreadyActive':tc())),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/ConnectionAlreadyActive:1.0",
- 'CosNotifyChannelAdmin_ConnectionAlreadyActive':id()),
- ?match("CosNotifyChannelAdmin_ConnectionAlreadyActive",
- 'CosNotifyChannelAdmin_ConnectionAlreadyActive':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_ConnectionAlreadyInactive'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_ConnectionAlreadyInactive'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyChannelAdmin_ConnectionAlreadyInactive':tc())),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/ConnectionAlreadyInactive:1.0",
- 'CosNotifyChannelAdmin_ConnectionAlreadyInactive':id()),
- ?match("CosNotifyChannelAdmin_ConnectionAlreadyInactive",
- 'CosNotifyChannelAdmin_ConnectionAlreadyInactive':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_NotConnected'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_NotConnected'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyChannelAdmin_NotConnected':tc())),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/NotConnected:1.0",
- 'CosNotifyChannelAdmin_NotConnected':id()),
- ?match("CosNotifyChannelAdmin_NotConnected",
- 'CosNotifyChannelAdmin_NotConnected':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_AdminIDSeq'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_AdminIDSeq'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyChannelAdmin_AdminIDSeq':tc())),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/AdminIDSeq:1.0",
- 'CosNotifyChannelAdmin_AdminIDSeq':id()),
- ?match("CosNotifyChannelAdmin_AdminIDSeq",
- 'CosNotifyChannelAdmin_AdminIDSeq':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_ChannelIDSeq'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_ChannelIDSeq'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyChannelAdmin_ChannelIDSeq':tc())),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/ChannelIDSeq:1.0",
- 'CosNotifyChannelAdmin_ChannelIDSeq':id()),
- ?match("CosNotifyChannelAdmin_ChannelIDSeq",
- 'CosNotifyChannelAdmin_ChannelIDSeq':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_ProxyIDSeq'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_ProxyIDSeq'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyChannelAdmin_ProxyIDSeq':tc())),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/ProxyIDSeq:1.0",
- 'CosNotifyChannelAdmin_ProxyIDSeq':id()),
- ?match("CosNotifyChannelAdmin_ProxyIDSeq",
- 'CosNotifyChannelAdmin_ProxyIDSeq':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyFilter_CallbackNotFound'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyFilter_CallbackNotFound'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyFilter_CallbackNotFound':tc())),
- ?match("IDL:omg.org/CosNotifyFilter/CallbackNotFound:1.0",
- 'CosNotifyFilter_CallbackNotFound':id()),
- ?match("CosNotifyFilter_CallbackNotFound",
- 'CosNotifyFilter_CallbackNotFound':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyFilter_ConstraintExp'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyFilter_ConstraintExp'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyFilter_ConstraintExp':tc())),
- ?match("IDL:omg.org/CosNotifyFilter/ConstraintExp:1.0",
- 'CosNotifyFilter_ConstraintExp':id()),
- ?match("CosNotifyFilter_ConstraintExp",
- 'CosNotifyFilter_ConstraintExp':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyFilter_ConstraintInfo'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyFilter_ConstraintInfo'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyFilter_ConstraintInfo':tc())),
- ?match("IDL:omg.org/CosNotifyFilter/ConstraintInfo:1.0",
- 'CosNotifyFilter_ConstraintInfo':id()),
- ?match("CosNotifyFilter_ConstraintInfo",
- 'CosNotifyFilter_ConstraintInfo':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyFilter_ConstraintNotFound'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyFilter_ConstraintNotFound'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyFilter_ConstraintNotFound':tc())),
- ?match("IDL:omg.org/CosNotifyFilter/ConstraintNotFound:1.0",
- 'CosNotifyFilter_ConstraintNotFound':id()),
- ?match("CosNotifyFilter_ConstraintNotFound",
- 'CosNotifyFilter_ConstraintNotFound':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyFilter_DuplicateConstraintID'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyFilter_DuplicateConstraintID'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyFilter_DuplicateConstraintID':tc())),
- ?match("IDL:omg.org/CosNotifyFilter/DuplicateConstraintID:1.0",
- 'CosNotifyFilter_DuplicateConstraintID':id()),
- ?match("CosNotifyFilter_DuplicateConstraintID",
- 'CosNotifyFilter_DuplicateConstraintID':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyFilter_FilterNotFound'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyFilter_FilterNotFound'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyFilter_FilterNotFound':tc())),
- ?match("IDL:omg.org/CosNotifyFilter/FilterNotFound:1.0",
- 'CosNotifyFilter_FilterNotFound':id()),
- ?match("CosNotifyFilter_FilterNotFound",
- 'CosNotifyFilter_FilterNotFound':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyFilter_InvalidConstraint'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyFilter_InvalidConstraint'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyFilter_InvalidConstraint':tc())),
- ?match("IDL:omg.org/CosNotifyFilter/InvalidConstraint:1.0",
- 'CosNotifyFilter_InvalidConstraint':id()),
- ?match("CosNotifyFilter_InvalidConstraint",
- 'CosNotifyFilter_InvalidConstraint':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyFilter_InvalidGrammar'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyFilter_InvalidGrammar'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyFilter_InvalidGrammar':tc())),
- ?match("IDL:omg.org/CosNotifyFilter/InvalidGrammar:1.0",
- 'CosNotifyFilter_InvalidGrammar':id()),
- ?match("CosNotifyFilter_InvalidGrammar",
- 'CosNotifyFilter_InvalidGrammar':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyFilter_InvalidValue'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyFilter_InvalidValue'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyFilter_InvalidValue':tc())),
- ?match("IDL:omg.org/CosNotifyFilter/InvalidValue:1.0",
- 'CosNotifyFilter_InvalidValue':id()),
- ?match("CosNotifyFilter_InvalidValue",
- 'CosNotifyFilter_InvalidValue':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyFilter_MappingConstraintInfo'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyFilter_MappingConstraintInfo'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyFilter_MappingConstraintInfo':tc())),
- ?match("IDL:omg.org/CosNotifyFilter/MappingConstraintInfo:1.0",
- 'CosNotifyFilter_MappingConstraintInfo':id()),
- ?match("CosNotifyFilter_MappingConstraintInfo",
- 'CosNotifyFilter_MappingConstraintInfo':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyFilter_MappingConstraintPair'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyFilter_MappingConstraintPair'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyFilter_MappingConstraintPair':tc())),
- ?match("IDL:omg.org/CosNotifyFilter/MappingConstraintPair:1.0",
- 'CosNotifyFilter_MappingConstraintPair':id()),
- ?match("CosNotifyFilter_MappingConstraintPair",
- 'CosNotifyFilter_MappingConstraintPair':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyFilter_UnsupportedFilterableData'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyFilter_UnsupportedFilterableData'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyFilter_UnsupportedFilterableData':tc())),
- ?match("IDL:omg.org/CosNotifyFilter/UnsupportedFilterableData:1.0",
- 'CosNotifyFilter_UnsupportedFilterableData':id()),
- ?match("CosNotifyFilter_UnsupportedFilterableData",
- 'CosNotifyFilter_UnsupportedFilterableData':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyFilter_CallbackIDSeq'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyFilter_CallbackIDSeq'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyFilter_CallbackIDSeq':tc())),
- ?match("IDL:omg.org/CosNotifyFilter/CallbackIDSeq:1.0",
- 'CosNotifyFilter_CallbackIDSeq':id()),
- ?match("CosNotifyFilter_CallbackIDSeq",
- 'CosNotifyFilter_CallbackIDSeq':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyFilter_ConstraintExpSeq'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyFilter_ConstraintExpSeq'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyFilter_ConstraintExpSeq':tc())),
- ?match("IDL:omg.org/CosNotifyFilter/ConstraintExpSeq:1.0",
- 'CosNotifyFilter_ConstraintExpSeq':id()),
- ?match("CosNotifyFilter_ConstraintExpSeq",
- 'CosNotifyFilter_ConstraintExpSeq':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyFilter_ConstraintIDSeq'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyFilter_ConstraintIDSeq'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyFilter_ConstraintIDSeq':tc())),
- ?match("IDL:omg.org/CosNotifyFilter/ConstraintIDSeq:1.0",
- 'CosNotifyFilter_ConstraintIDSeq':id()),
- ?match("CosNotifyFilter_ConstraintIDSeq",
- 'CosNotifyFilter_ConstraintIDSeq':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyFilter_ConstraintInfoSeq'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyFilter_ConstraintInfoSeq'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyFilter_ConstraintInfoSeq':tc())),
- ?match("IDL:omg.org/CosNotifyFilter/ConstraintInfoSeq:1.0",
- 'CosNotifyFilter_ConstraintInfoSeq':id()),
- ?match("CosNotifyFilter_ConstraintInfoSeq",
- 'CosNotifyFilter_ConstraintInfoSeq':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyFilter_FilterIDSeq'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyFilter_FilterIDSeq'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyFilter_FilterIDSeq':tc())),
- ?match("IDL:omg.org/CosNotifyFilter/FilterIDSeq:1.0",
- 'CosNotifyFilter_FilterIDSeq':id()),
- ?match("CosNotifyFilter_FilterIDSeq",
- 'CosNotifyFilter_FilterIDSeq':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyFilter_MappingConstraintInfoSeq'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyFilter_MappingConstraintInfoSeq'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyFilter_MappingConstraintInfoSeq':tc())),
- ?match("IDL:omg.org/CosNotifyFilter/MappingConstraintInfoSeq:1.0",
- 'CosNotifyFilter_MappingConstraintInfoSeq':id()),
- ?match("CosNotifyFilter_MappingConstraintInfoSeq",
- 'CosNotifyFilter_MappingConstraintInfoSeq':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyFilter_MappingConstraintPairSeq'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyFilter_MappingConstraintPairSeq'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyFilter_MappingConstraintPairSeq':tc())),
- ?match("IDL:omg.org/CosNotifyFilter/MappingConstraintPairSeq:1.0",
- 'CosNotifyFilter_MappingConstraintPairSeq':id()),
- ?match("CosNotifyFilter_MappingConstraintPairSeq",
- 'CosNotifyFilter_MappingConstraintPairSeq':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyComm_InvalidEventType'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyComm_InvalidEventType'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyComm_InvalidEventType':tc())),
- ?match("IDL:omg.org/CosNotifyComm/InvalidEventType:1.0",
- 'CosNotifyComm_InvalidEventType':id()),
- ?match("CosNotifyComm_InvalidEventType",
- 'CosNotifyComm_InvalidEventType':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_ProxyNotFound'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_ProxyNotFound'(_) ->
- ?match(true, orber_tc:check_tc('CosNotifyChannelAdmin_ProxyNotFound':tc())),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/ProxyNotFound:1.0",
- 'CosNotifyChannelAdmin_ProxyNotFound':id()),
- ?match("CosNotifyChannelAdmin_ProxyNotFound",
- 'CosNotifyChannelAdmin_ProxyNotFound':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotification_AdminPropertiesAdmin'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotification_AdminPropertiesAdmin'(_) ->
- ?nomatch(undefined, 'CosNotification_AdminPropertiesAdmin':oe_tc(get_admin)),
- ?nomatch(undefined, 'CosNotification_AdminPropertiesAdmin':oe_tc(set_admin)),
- ?match(undefined, 'CosNotification_AdminPropertiesAdmin':oe_tc(undefined)),
- ?match([_|_], 'CosNotification_AdminPropertiesAdmin':oe_get_interface()),
- ?match("IDL:omg.org/CosNotification/AdminPropertiesAdmin:1.0",
- 'CosNotification_AdminPropertiesAdmin':typeID()),
- check_tc('CosNotification_AdminPropertiesAdmin':oe_get_interface()),
- ?match(true, 'CosNotification_AdminPropertiesAdmin':oe_is_a('CosNotification_AdminPropertiesAdmin':typeID())),
- ?match(false, 'CosNotification_AdminPropertiesAdmin':oe_is_a("wrong")),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotification_QoSAdmin'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotification_QoSAdmin'(_) ->
- ?nomatch(undefined, 'CosNotification_QoSAdmin':oe_tc(get_qos)),
- ?nomatch(undefined, 'CosNotification_QoSAdmin':oe_tc(set_qos)),
- ?nomatch(undefined, 'CosNotification_QoSAdmin':oe_tc(validate_qos)),
- ?match(undefined, 'CosNotification_QoSAdmin':oe_tc(undefined)),
- ?match([_|_], 'CosNotification_QoSAdmin':oe_get_interface()),
- ?match("IDL:omg.org/CosNotification/QoSAdmin:1.0",
- 'CosNotification_QoSAdmin':typeID()),
- check_tc('CosNotification_QoSAdmin':oe_get_interface()),
- ?match(true, 'CosNotification_QoSAdmin':oe_is_a('CosNotification_QoSAdmin':typeID())),
- ?match(false, 'CosNotification_QoSAdmin':oe_is_a("wrong")),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_ConsumerAdmin'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_ConsumerAdmin'(_) ->
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_tc('_get_MyID')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_tc('_get_MyChannel')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_tc('_get_MyOperator')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_tc('_get_priority_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_tc('_set_priority_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_tc('_get_lifetime_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_tc('_set_lifetime_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_tc('_get_pull_suppliers')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_tc('_get_push_suppliers')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_tc(get_proxy_supplier)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_tc(obtain_notification_pull_supplier)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_tc(obtain_notification_push_supplier)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_tc(destroy)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_tc(get_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_tc(set_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_tc(validate_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_tc(subscription_change)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_tc(add_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_tc(remove_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_tc(get_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_tc(get_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_tc(remove_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_tc(obtain_push_supplier)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_tc(obtain_pull_supplier)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_tc(callSeq)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_tc(callAny)),
- ?match(undefined, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyChannelAdmin_ConsumerAdmin':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/ConsumerAdmin:1.0",
- 'CosNotifyChannelAdmin_ConsumerAdmin':typeID()),
- check_tc('CosNotifyChannelAdmin_ConsumerAdmin':oe_get_interface()),
- ?match(true, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_is_a('CosNotifyChannelAdmin_ConsumerAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_is_a('CosNotification_QoSAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_is_a('CosNotifyComm_NotifySubscribe':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_is_a('CosNotifyFilter_FilterAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_is_a('CosEventChannelAdmin_ConsumerAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_is_a('oe_CosNotificationComm_Event':typeID())),
- ?match(false, 'CosNotifyChannelAdmin_ConsumerAdmin':oe_is_a("wrong")),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_EventChannel'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_EventChannel'(_) ->
- ?nomatch(undefined, 'CosNotifyChannelAdmin_EventChannel':oe_tc('_get_MyFactory')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_EventChannel':oe_tc('_get_default_consumer_admin')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_EventChannel':oe_tc('_get_default_supplier_admin')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_EventChannel':oe_tc('_get_default_filter_factory')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_EventChannel':oe_tc(new_for_consumers)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_EventChannel':oe_tc(new_for_suppliers)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_EventChannel':oe_tc(get_consumeradmin)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_EventChannel':oe_tc(get_supplieradmin)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_EventChannel':oe_tc(get_all_consumeradmins)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_EventChannel':oe_tc(get_all_supplieradmins)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_EventChannel':oe_tc(get_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_EventChannel':oe_tc(set_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_EventChannel':oe_tc(validate_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_EventChannel':oe_tc(get_admin)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_EventChannel':oe_tc(set_admin)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_EventChannel':oe_tc(for_consumers)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_EventChannel':oe_tc(for_suppliers)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_EventChannel':oe_tc(destroy)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_EventChannel':oe_tc(callSeq)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_EventChannel':oe_tc(callAny)),
- ?match(undefined, 'CosNotifyChannelAdmin_EventChannel':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyChannelAdmin_EventChannel':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/EventChannel:1.0",
- 'CosNotifyChannelAdmin_EventChannel':typeID()),
- check_tc('CosNotifyChannelAdmin_EventChannel':oe_get_interface()),
- ?match(true, 'CosNotifyChannelAdmin_EventChannel':oe_is_a('CosNotifyChannelAdmin_EventChannel':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_EventChannel':oe_is_a('CosNotification_QoSAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_EventChannel':oe_is_a('CosNotification_AdminPropertiesAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_EventChannel':oe_is_a('CosEventChannelAdmin_EventChannel':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_EventChannel':oe_is_a('oe_CosNotificationComm_Event':typeID())),
- ?match(false, 'CosNotifyChannelAdmin_EventChannel':oe_is_a("wrong")),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_EventChannelFactory'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_EventChannelFactory'(_) ->
- ?nomatch(undefined, 'CosNotifyChannelAdmin_EventChannelFactory':oe_tc(create_channel)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_EventChannelFactory':oe_tc(get_all_channels)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_EventChannelFactory':oe_tc(get_event_channel)),
- ?match(undefined, 'CosNotifyChannelAdmin_EventChannelFactory':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyChannelAdmin_EventChannelFactory':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/EventChannelFactory:1.0",
- 'CosNotifyChannelAdmin_EventChannelFactory':typeID()),
- check_tc('CosNotifyChannelAdmin_EventChannelFactory':oe_get_interface()),
- ?match(true, 'CosNotifyChannelAdmin_EventChannelFactory':oe_is_a('CosNotifyChannelAdmin_EventChannelFactory':typeID())),
- ?match(false, 'CosNotifyChannelAdmin_EventChannelFactory':oe_is_a("wrong")),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_ProxyConsumer'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_ProxyConsumer'(_) ->
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyConsumer':oe_tc('_get_MyType')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyConsumer':oe_tc('_get_MyAdmin')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyConsumer':oe_tc(obtain_subscription_types)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyConsumer':oe_tc(validate_event_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyConsumer':oe_tc(get_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyConsumer':oe_tc(set_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyConsumer':oe_tc(validate_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyConsumer':oe_tc(add_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyConsumer':oe_tc(remove_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyConsumer':oe_tc(get_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyConsumer':oe_tc(get_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyConsumer':oe_tc(remove_all_filters)),
- ?match(undefined, 'CosNotifyChannelAdmin_ProxyConsumer':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyChannelAdmin_ProxyConsumer':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/ProxyConsumer:1.0",
- 'CosNotifyChannelAdmin_ProxyConsumer':typeID()),
- check_tc('CosNotifyChannelAdmin_ProxyConsumer':oe_get_interface()),
- ?match(true, 'CosNotifyChannelAdmin_ProxyConsumer':oe_is_a('CosNotifyChannelAdmin_ProxyConsumer':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyConsumer':oe_is_a('CosNotification_QoSAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyConsumer':oe_is_a('CosNotifyFilter_FilterAdmin':typeID())),
- ?match(false, 'CosNotifyChannelAdmin_ProxyConsumer':oe_is_a("wrong")),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_ProxyPullConsumer'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_ProxyPullConsumer'(_) ->
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_tc(connect_any_pull_supplier)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_tc(suspend_connection)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_tc(resume_connection)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_tc('_get_MyType')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_tc('_get_MyAdmin')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_tc(obtain_subscription_types)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_tc(validate_event_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_tc(get_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_tc(set_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_tc(validate_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_tc(add_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_tc(remove_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_tc(get_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_tc(get_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_tc(remove_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_tc(offer_change)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_tc(disconnect_pull_consumer)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_tc(connect_pull_supplier)),
- ?match(undefined, 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/ProxyPullConsumer:1.0",
- 'CosNotifyChannelAdmin_ProxyPullConsumer':typeID()),
- check_tc('CosNotifyChannelAdmin_ProxyPullConsumer':oe_get_interface()),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_is_a('CosNotifyChannelAdmin_ProxyPullConsumer':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_is_a('CosNotifyChannelAdmin_ProxyConsumer':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_is_a('CosNotification_QoSAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_is_a('CosNotifyFilter_FilterAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_is_a('CosNotifyComm_PullConsumer':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_is_a('CosNotifyComm_NotifyPublish':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_is_a('CosEventComm_PullConsumer':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_is_a('CosEventChannelAdmin_ProxyPullConsumer':typeID())),
- ?match(false, 'CosNotifyChannelAdmin_ProxyPullConsumer':oe_is_a("wrong")),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_ProxyPullSupplier'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_ProxyPullSupplier'(_) ->
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_tc('_get_MyType')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_tc('_get_MyAdmin')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_tc('_get_priority_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_tc('_set_priority_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_tc('_get_lifetime_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_tc('_set_lifetime_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_tc(obtain_offered_types)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_tc(validate_event_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_tc(get_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_tc(set_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_tc(validate_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_tc(add_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_tc(remove_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_tc(get_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_tc(get_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_tc(remove_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_tc(subscription_change)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_tc(pull)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_tc(try_pull)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_tc(disconnect_pull_supplier)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_tc(connect_pull_consumer)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_tc(callSeq)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_tc(callAny)),
- ?match(undefined, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/ProxyPullSupplier:1.0",
- 'CosNotifyChannelAdmin_ProxyPullSupplier':typeID()),
- check_tc('CosNotifyChannelAdmin_ProxyPullSupplier':oe_get_interface()),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_is_a('CosNotifyChannelAdmin_ProxyPullSupplier':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_is_a('CosNotifyChannelAdmin_ProxySupplier':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_is_a('CosNotification_QoSAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_is_a('CosNotifyFilter_FilterAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_is_a('CosNotifyComm_PullSupplier':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_is_a('CosNotifyComm_NotifySubscribe':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_is_a('CosEventComm_PullSupplier':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_is_a('CosEventChannelAdmin_ProxyPullSupplier':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_is_a('oe_CosNotificationComm_Event':typeID())),
- ?match(false, 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_is_a("wrong")),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_ProxyPushConsumer'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_ProxyPushConsumer'(_) ->
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushConsumer':oe_tc(connect_any_push_supplier)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushConsumer':oe_tc('_get_MyType')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushConsumer':oe_tc('_get_MyAdmin')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushConsumer':oe_tc(obtain_subscription_types)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushConsumer':oe_tc(validate_event_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushConsumer':oe_tc(get_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushConsumer':oe_tc(set_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushConsumer':oe_tc(validate_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushConsumer':oe_tc(add_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushConsumer':oe_tc(remove_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushConsumer':oe_tc(get_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushConsumer':oe_tc(get_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushConsumer':oe_tc(remove_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushConsumer':oe_tc(offer_change)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushConsumer':oe_tc(push)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushConsumer':oe_tc(disconnect_push_consumer)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushConsumer':oe_tc(connect_push_supplier)),
- ?match(undefined, 'CosNotifyChannelAdmin_ProxyPushConsumer':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyChannelAdmin_ProxyPushConsumer':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/ProxyPushConsumer:1.0",
- 'CosNotifyChannelAdmin_ProxyPushConsumer':typeID()),
- check_tc('CosNotifyChannelAdmin_ProxyPushConsumer':oe_get_interface()),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPushConsumer':oe_is_a('CosNotifyChannelAdmin_ProxyPushConsumer':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPushConsumer':oe_is_a('CosNotifyChannelAdmin_ProxyConsumer':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPushConsumer':oe_is_a('CosNotification_QoSAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPushConsumer':oe_is_a('CosNotifyFilter_FilterAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPushConsumer':oe_is_a('CosNotifyComm_PushConsumer':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPushConsumer':oe_is_a('CosNotifyComm_NotifyPublish':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPushConsumer':oe_is_a('CosEventComm_PushConsumer':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPushConsumer':oe_is_a('CosEventChannelAdmin_ProxyPushConsumer':typeID())),
- ?match(false, 'CosNotifyChannelAdmin_ProxyPushConsumer':oe_is_a("wrong")),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_ProxyPushSupplier'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_ProxyPushSupplier'(_) ->
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_tc(connect_any_push_consumer)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_tc(suspend_connection)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_tc(resume_connection)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_tc('_get_MyType')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_tc('_get_MyAdmin')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_tc('_get_priority_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_tc('_set_priority_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_tc('_get_lifetime_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_tc('_set_lifetime_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_tc(obtain_offered_types)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_tc(validate_event_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_tc(get_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_tc(set_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_tc(validate_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_tc(add_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_tc(remove_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_tc(get_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_tc(get_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_tc(remove_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_tc(subscription_change)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_tc(disconnect_push_supplier)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_tc(connect_push_consumer)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_tc(callSeq)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_tc(callAny)),
- ?match(undefined, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/ProxyPushSupplier:1.0",
- 'CosNotifyChannelAdmin_ProxyPushSupplier':typeID()),
- check_tc('CosNotifyChannelAdmin_ProxyPushSupplier':oe_get_interface()),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_is_a('CosNotifyChannelAdmin_ProxyPushSupplier':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_is_a('CosNotifyChannelAdmin_ProxySupplier':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_is_a('CosNotification_QoSAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_is_a('CosNotifyFilter_FilterAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_is_a('CosNotifyComm_PushSupplier':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_is_a('CosNotifyComm_NotifySubscribe':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_is_a('CosEventComm_PushSupplier':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_is_a('CosEventChannelAdmin_ProxyPushSupplier':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_is_a('oe_CosNotificationComm_Event':typeID())),
- ?match(false, 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_is_a("wrong")),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_ProxySupplier'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_ProxySupplier'(_) ->
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxySupplier':oe_tc('_get_MyType')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxySupplier':oe_tc('_get_MyAdmin')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxySupplier':oe_tc('_get_priority_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxySupplier':oe_tc('_set_priority_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxySupplier':oe_tc('_get_lifetime_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxySupplier':oe_tc('_set_lifetime_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxySupplier':oe_tc(obtain_offered_types)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxySupplier':oe_tc(validate_event_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxySupplier':oe_tc(get_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxySupplier':oe_tc(set_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxySupplier':oe_tc(validate_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxySupplier':oe_tc(add_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxySupplier':oe_tc(remove_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxySupplier':oe_tc(get_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxySupplier':oe_tc(get_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_ProxySupplier':oe_tc(remove_all_filters)),
- ?match(undefined, 'CosNotifyChannelAdmin_ProxySupplier':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyChannelAdmin_ProxySupplier':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/ProxySupplier:1.0",
- 'CosNotifyChannelAdmin_ProxySupplier':typeID()),
- check_tc('CosNotifyChannelAdmin_ProxySupplier':oe_get_interface()),
- ?match(true, 'CosNotifyChannelAdmin_ProxySupplier':oe_is_a('CosNotifyChannelAdmin_ProxySupplier':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxySupplier':oe_is_a('CosNotification_QoSAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_ProxySupplier':oe_is_a('CosNotifyFilter_FilterAdmin':typeID())),
- ?match(false, 'CosNotifyChannelAdmin_ProxySupplier':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_SequenceProxyPullConsumer'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_SequenceProxyPullConsumer'(_) ->
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':oe_tc(connect_sequence_pull_supplier)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':oe_tc(suspend_connection)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':oe_tc(resume_connection)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':oe_tc('_get_MyType')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':oe_tc('_get_MyAdmin')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':oe_tc(obtain_subscription_types)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':oe_tc(validate_event_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':oe_tc(get_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':oe_tc(set_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':oe_tc(validate_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':oe_tc(add_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':oe_tc(remove_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':oe_tc(get_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':oe_tc(get_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':oe_tc(remove_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':oe_tc(disconnect_sequence_pull_consumer)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':oe_tc(offer_change)),
- ?match(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/SequenceProxyPullConsumer:1.0",
- 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':typeID()),
- check_tc('CosNotifyChannelAdmin_SequenceProxyPullConsumer':oe_get_interface()),
- ?match(true, 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':oe_is_a('CosNotifyChannelAdmin_SequenceProxyPullConsumer':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':oe_is_a('CosNotifyChannelAdmin_ProxyConsumer':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':oe_is_a('CosNotification_QoSAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':oe_is_a('CosNotifyFilter_FilterAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':oe_is_a('CosNotifyComm_SequencePullConsumer':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':oe_is_a('CosNotifyComm_NotifyPublish':typeID())),
- ?match(false, 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_SequenceProxyPullSupplier'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_SequenceProxyPullSupplier'(_) ->
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_tc(connect_sequence_pull_consumer)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_tc('_get_MyType')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_tc('_get_MyAdmin')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_tc('_get_priority_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_tc('_set_priority_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_tc('_get_lifetime_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_tc('_set_lifetime_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_tc(obtain_offered_types)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_tc(validate_event_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_tc(get_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_tc(set_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_tc(validate_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_tc(add_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_tc(remove_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_tc(get_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_tc(get_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_tc(remove_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_tc(pull_structured_events)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_tc(try_pull_structured_events)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_tc(disconnect_sequence_pull_supplier)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_tc(subscription_change)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_tc(callSeq)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_tc(callAny)),
- ?match(undefined, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/SequenceProxyPullSupplier:1.0",
- 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':typeID()),
- check_tc('CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_get_interface()),
- ?match(true, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_is_a('CosNotifyChannelAdmin_SequenceProxyPullSupplier':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_is_a('CosNotifyChannelAdmin_ProxySupplier':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_is_a('CosNotification_QoSAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_is_a('CosNotifyFilter_FilterAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_is_a('CosNotifyComm_SequencePullSupplier':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_is_a('CosNotifyComm_NotifySubscribe':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_is_a('oe_CosNotificationComm_Event':typeID())),
- ?match(false, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_SequenceProxyPushConsumer'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_SequenceProxyPushConsumer'(_) ->
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':oe_tc(connect_sequence_push_supplier)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':oe_tc('_get_MyType')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':oe_tc('_get_MyAdmin')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':oe_tc(obtain_subscription_types)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':oe_tc(validate_event_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':oe_tc(get_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':oe_tc(set_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':oe_tc(validate_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':oe_tc(add_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':oe_tc(remove_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':oe_tc(get_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':oe_tc(get_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':oe_tc(remove_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':oe_tc(push_structured_events)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':oe_tc(disconnect_sequence_push_consumer)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':oe_tc(offer_change)),
- ?match(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/SequenceProxyPushConsumer:1.0",
- 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':typeID()),
- check_tc('CosNotifyChannelAdmin_SequenceProxyPushConsumer':oe_get_interface()),
- ?match(true, 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':oe_is_a('CosNotifyChannelAdmin_SequenceProxyPushConsumer':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':oe_is_a('CosNotifyChannelAdmin_ProxyConsumer':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':oe_is_a('CosNotification_QoSAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':oe_is_a('CosNotifyFilter_FilterAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':oe_is_a('CosNotifyComm_SequencePushConsumer':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':oe_is_a('CosNotifyComm_NotifyPublish':typeID())),
- ?match(false, 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_SequenceProxyPushSupplier'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_SequenceProxyPushSupplier'(_) ->
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_tc(connect_sequence_push_consumer)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_tc(suspend_connection)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_tc(resume_connection)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_tc('_get_MyType')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_tc('_get_MyAdmin')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_tc('_get_priority_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_tc('_set_priority_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_tc('_get_lifetime_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_tc('_set_lifetime_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_tc(obtain_offered_types)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_tc(validate_event_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_tc(get_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_tc(set_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_tc(validate_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_tc(add_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_tc(remove_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_tc(get_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_tc(get_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_tc(remove_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_tc(disconnect_sequence_push_supplier)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_tc(subscription_change)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_tc(callSeq)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_tc(callAny)),
- ?match(undefined, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/SequenceProxyPushSupplier:1.0",
- 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':typeID()),
- check_tc('CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_get_interface()),
- ?match(true, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_is_a('CosNotifyChannelAdmin_SequenceProxyPushSupplier':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_is_a('CosNotifyChannelAdmin_ProxySupplier':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_is_a('CosNotification_QoSAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_is_a('CosNotifyFilter_FilterAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_is_a('CosNotifyComm_SequencePushSupplier':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_is_a('CosNotifyComm_NotifySubscribe':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_is_a('oe_CosNotificationComm_Event':typeID())),
- ?match(false, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_StructuredProxyPullConsumer'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_StructuredProxyPullConsumer'(_) ->
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':oe_tc(connect_structured_pull_supplier)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':oe_tc(suspend_connection)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':oe_tc(resume_connection)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':oe_tc('_get_MyType')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':oe_tc('_get_MyAdmin')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':oe_tc(obtain_subscription_types)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':oe_tc(validate_event_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':oe_tc(get_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':oe_tc(set_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':oe_tc(validate_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':oe_tc(add_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':oe_tc(remove_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':oe_tc(get_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':oe_tc(get_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':oe_tc(remove_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':oe_tc(disconnect_structured_pull_consumer)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':oe_tc(offer_change)),
- ?match(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/StructuredProxyPullConsumer:1.0",
- 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':typeID()),
- check_tc('CosNotifyChannelAdmin_StructuredProxyPullConsumer':oe_get_interface()),
- ?match(true, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':oe_is_a('CosNotifyChannelAdmin_StructuredProxyPullConsumer':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':oe_is_a('CosNotifyChannelAdmin_ProxyConsumer':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':oe_is_a('CosNotification_QoSAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':oe_is_a('CosNotifyFilter_FilterAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':oe_is_a('CosNotifyComm_StructuredPullConsumer':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':oe_is_a('CosNotifyComm_NotifyPublish':typeID())),
- ?match(false, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_StructuredProxyPullSupplier'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_StructuredProxyPullSupplier'(_) ->
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_tc(connect_structured_pull_consumer)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_tc('_get_MyType')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_tc('_get_MyAdmin')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_tc('_get_priority_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_tc('_set_priority_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_tc('_get_lifetime_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_tc('_set_lifetime_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_tc(obtain_offered_types)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_tc(validate_event_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_tc(get_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_tc(set_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_tc(validate_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_tc(add_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_tc(remove_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_tc(get_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_tc(get_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_tc(remove_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_tc(pull_structured_event)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_tc(try_pull_structured_event)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_tc(disconnect_structured_pull_supplier)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_tc(subscription_change)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_tc(callSeq)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_tc(callAny)),
- ?match(undefined, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/StructuredProxyPullSupplier:1.0",
- 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':typeID()),
- check_tc('CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_get_interface()),
- ?match(true, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_is_a('CosNotifyChannelAdmin_StructuredProxyPullSupplier':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_is_a('CosNotifyChannelAdmin_ProxySupplier':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_is_a('CosNotification_QoSAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_is_a('CosNotifyFilter_FilterAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_is_a('CosNotifyComm_StructuredPullSupplier':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_is_a('CosNotifyComm_NotifySubscribe':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_is_a('oe_CosNotificationComm_Event':typeID())),
- ?match(false, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_StructuredProxyPushConsumer'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_StructuredProxyPushConsumer'(_) ->
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':oe_tc(connect_structured_push_supplier)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':oe_tc('_get_MyType')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':oe_tc('_get_MyAdmin')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':oe_tc(obtain_subscription_types)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':oe_tc(validate_event_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':oe_tc(get_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':oe_tc(set_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':oe_tc(validate_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':oe_tc(add_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':oe_tc(remove_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':oe_tc(get_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':oe_tc(get_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':oe_tc(remove_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':oe_tc(push_structured_event)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':oe_tc(disconnect_structured_push_consumer)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':oe_tc(offer_change)),
- ?match(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/StructuredProxyPushConsumer:1.0",
- 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':typeID()),
- check_tc('CosNotifyChannelAdmin_StructuredProxyPushConsumer':oe_get_interface()),
- ?match(true, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':oe_is_a('CosNotifyChannelAdmin_StructuredProxyPushConsumer':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':oe_is_a('CosNotifyChannelAdmin_ProxyConsumer':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':oe_is_a('CosNotification_QoSAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':oe_is_a('CosNotifyFilter_FilterAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':oe_is_a('CosNotifyComm_StructuredPushConsumer':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':oe_is_a('CosNotifyComm_NotifyPublish':typeID())),
- ?match(false, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_StructuredProxyPushSupplier'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_StructuredProxyPushSupplier'(_) ->
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_tc(connect_structured_push_consumer)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_tc(suspend_connection)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_tc(resume_connection)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_tc('_get_MyType')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_tc('_get_MyAdmin')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_tc('_get_priority_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_tc('_set_priority_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_tc('_get_lifetime_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_tc('_set_lifetime_filter')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_tc(obtain_offered_types)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_tc(validate_event_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_tc(get_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_tc(set_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_tc(validate_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_tc(add_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_tc(remove_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_tc(get_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_tc(get_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_tc(remove_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_tc(disconnect_structured_push_supplier)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_tc(subscription_change)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_tc(callSeq)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_tc(callAny)),
- ?match(undefined, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/StructuredProxyPushSupplier:1.0",
- 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':typeID()),
- check_tc('CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_get_interface()),
- ?match(true, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_is_a('CosNotifyChannelAdmin_StructuredProxyPushSupplier':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_is_a('CosNotifyChannelAdmin_ProxySupplier':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_is_a('CosNotification_QoSAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_is_a('CosNotifyFilter_FilterAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_is_a('CosNotifyComm_StructuredPushSupplier':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_is_a('CosNotifyComm_NotifySubscribe':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_is_a('oe_CosNotificationComm_Event':typeID())),
- ?match(false, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyChannelAdmin_SupplierAdmin'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyChannelAdmin_SupplierAdmin'(_) ->
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SupplierAdmin':oe_tc('_get_MyID')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SupplierAdmin':oe_tc('_get_MyChannel')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SupplierAdmin':oe_tc('_get_MyOperator')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SupplierAdmin':oe_tc('_get_pull_consumers')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SupplierAdmin':oe_tc('_get_push_consumers')),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SupplierAdmin':oe_tc(get_proxy_consumer)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SupplierAdmin':oe_tc(obtain_notification_pull_consumer)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SupplierAdmin':oe_tc(obtain_notification_push_consumer)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SupplierAdmin':oe_tc(destroy)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SupplierAdmin':oe_tc(get_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SupplierAdmin':oe_tc(set_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SupplierAdmin':oe_tc(validate_qos)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SupplierAdmin':oe_tc(offer_change)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SupplierAdmin':oe_tc(add_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SupplierAdmin':oe_tc(remove_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SupplierAdmin':oe_tc(get_filter)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SupplierAdmin':oe_tc(get_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SupplierAdmin':oe_tc(remove_all_filters)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SupplierAdmin':oe_tc(obtain_push_consumer)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SupplierAdmin':oe_tc(obtain_pull_consumer)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SupplierAdmin':oe_tc(callSeq)),
- ?nomatch(undefined, 'CosNotifyChannelAdmin_SupplierAdmin':oe_tc(callAny)),
- ?match(undefined, 'CosNotifyChannelAdmin_SupplierAdmin':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyChannelAdmin_SupplierAdmin':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyChannelAdmin/SupplierAdmin:1.0",
- 'CosNotifyChannelAdmin_SupplierAdmin':typeID()),
- check_tc('CosNotifyChannelAdmin_SupplierAdmin':oe_get_interface()),
- ?match(true, 'CosNotifyChannelAdmin_SupplierAdmin':oe_is_a('CosNotifyChannelAdmin_SupplierAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_SupplierAdmin':oe_is_a('CosNotification_QoSAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_SupplierAdmin':oe_is_a('CosNotifyComm_NotifyPublish':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_SupplierAdmin':oe_is_a('CosNotifyFilter_FilterAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_SupplierAdmin':oe_is_a('CosEventChannelAdmin_SupplierAdmin':typeID())),
- ?match(true, 'CosNotifyChannelAdmin_SupplierAdmin':oe_is_a('oe_CosNotificationComm_Event':typeID())),
- ?match(false, 'CosNotifyChannelAdmin_SupplierAdmin':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyFilter_Filter'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyFilter_Filter'(_) ->
- ?nomatch(undefined, 'CosNotifyFilter_Filter':oe_tc('_get_constraint_grammar')),
- ?nomatch(undefined, 'CosNotifyFilter_Filter':oe_tc(add_constraints)),
- ?nomatch(undefined, 'CosNotifyFilter_Filter':oe_tc(modify_constraints)),
- ?nomatch(undefined, 'CosNotifyFilter_Filter':oe_tc(get_constraints)),
- ?nomatch(undefined, 'CosNotifyFilter_Filter':oe_tc(get_all_constraints)),
- ?nomatch(undefined, 'CosNotifyFilter_Filter':oe_tc(remove_all_constraints)),
- ?nomatch(undefined, 'CosNotifyFilter_Filter':oe_tc(destroy)),
- ?nomatch(undefined, 'CosNotifyFilter_Filter':oe_tc(match)),
- ?nomatch(undefined, 'CosNotifyFilter_Filter':oe_tc(match_structured)),
- ?nomatch(undefined, 'CosNotifyFilter_Filter':oe_tc(match_typed)),
- ?nomatch(undefined, 'CosNotifyFilter_Filter':oe_tc(attach_callback)),
- ?nomatch(undefined, 'CosNotifyFilter_Filter':oe_tc(detach_callback)),
- ?nomatch(undefined, 'CosNotifyFilter_Filter':oe_tc(get_callbacks)),
- ?match(undefined, 'CosNotifyFilter_Filter':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyFilter_Filter':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyFilter/Filter:1.0",
- 'CosNotifyFilter_Filter':typeID()),
- check_tc('CosNotifyFilter_Filter':oe_get_interface()),
- ?match(true, 'CosNotifyFilter_Filter':oe_is_a('CosNotifyFilter_Filter':typeID())),
- ?match(false, 'CosNotifyFilter_Filter':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyFilter_FilterAdmin'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyFilter_FilterAdmin'(_) ->
- ?nomatch(undefined, 'CosNotifyFilter_FilterAdmin':oe_tc(add_filter)),
- ?nomatch(undefined, 'CosNotifyFilter_FilterAdmin':oe_tc(remove_filter)),
- ?nomatch(undefined, 'CosNotifyFilter_FilterAdmin':oe_tc(get_filter)),
- ?nomatch(undefined, 'CosNotifyFilter_FilterAdmin':oe_tc(get_all_filters)),
- ?nomatch(undefined, 'CosNotifyFilter_FilterAdmin':oe_tc(remove_all_filters)),
- ?match(undefined, 'CosNotifyFilter_FilterAdmin':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyFilter_FilterAdmin':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyFilter/FilterAdmin:1.0",
- 'CosNotifyFilter_FilterAdmin':typeID()),
- check_tc('CosNotifyFilter_FilterAdmin':oe_get_interface()),
- ?match(true, 'CosNotifyFilter_FilterAdmin':oe_is_a('CosNotifyFilter_FilterAdmin':typeID())),
- ?match(false, 'CosNotifyFilter_FilterAdmin':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyFilter_FilterFactory'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyFilter_FilterFactory'(_) ->
- ?nomatch(undefined, 'CosNotifyFilter_FilterFactory':oe_tc(create_filter)),
- ?nomatch(undefined, 'CosNotifyFilter_FilterFactory':oe_tc(create_mapping_filter)),
- ?match(undefined, 'CosNotifyFilter_FilterFactory':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyFilter_FilterFactory':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyFilter/FilterFactory:1.0",
- 'CosNotifyFilter_FilterFactory':typeID()),
- check_tc('CosNotifyFilter_FilterFactory':oe_get_interface()),
- ?match(true, 'CosNotifyFilter_FilterFactory':oe_is_a('CosNotifyFilter_FilterFactory':typeID())),
- ?match(false, 'CosNotifyFilter_FilterFactory':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyFilter_MappingFilter'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyFilter_MappingFilter'(_) ->
- ?nomatch(undefined, 'CosNotifyFilter_MappingFilter':oe_tc('_get_constraint_grammar')),
- ?nomatch(undefined, 'CosNotifyFilter_MappingFilter':oe_tc('_get_value_type')),
- ?nomatch(undefined, 'CosNotifyFilter_MappingFilter':oe_tc('_get_default_value')),
- ?nomatch(undefined, 'CosNotifyFilter_MappingFilter':oe_tc(add_mapping_constraints)),
- ?nomatch(undefined, 'CosNotifyFilter_MappingFilter':oe_tc(modify_mapping_constraints)),
- ?nomatch(undefined, 'CosNotifyFilter_MappingFilter':oe_tc(get_mapping_constraints)),
- ?nomatch(undefined, 'CosNotifyFilter_MappingFilter':oe_tc(get_all_mapping_constraints)),
- ?nomatch(undefined, 'CosNotifyFilter_MappingFilter':oe_tc(remove_all_mapping_constraints)),
- ?nomatch(undefined, 'CosNotifyFilter_MappingFilter':oe_tc(destroy)),
- ?nomatch(undefined, 'CosNotifyFilter_MappingFilter':oe_tc(match)),
- ?nomatch(undefined, 'CosNotifyFilter_MappingFilter':oe_tc(match_structured)),
- ?nomatch(undefined, 'CosNotifyFilter_MappingFilter':oe_tc(match_typed)),
- ?match(undefined, 'CosNotifyFilter_MappingFilter':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyFilter_MappingFilter':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyFilter/MappingFilter:1.0",
- 'CosNotifyFilter_MappingFilter':typeID()),
- check_tc('CosNotifyFilter_MappingFilter':oe_get_interface()),
- ?match(true, 'CosNotifyFilter_MappingFilter':oe_is_a('CosNotifyFilter_MappingFilter':typeID())),
- ?match(false, 'CosNotifyFilter_MappingFilter':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyComm_NotifyPublish'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyComm_NotifyPublish'(_) ->
- ?nomatch(undefined, 'CosNotifyComm_NotifyPublish':oe_tc(offer_change)),
- ?match(undefined, 'CosNotifyComm_NotifyPublish':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyComm_NotifyPublish':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyComm/NotifyPublish:1.0",
- 'CosNotifyComm_NotifyPublish':typeID()),
- check_tc('CosNotifyComm_NotifyPublish':oe_get_interface()),
- ?match(true, 'CosNotifyComm_NotifyPublish':oe_is_a('CosNotifyComm_NotifyPublish':typeID())),
- ?match(false, 'CosNotifyComm_NotifyPublish':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyComm_NotifySubscribe'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyComm_NotifySubscribe'(_) ->
- ?nomatch(undefined, 'CosNotifyComm_NotifySubscribe':oe_tc(subscription_change)),
- ?match(undefined, 'CosNotifyComm_NotifySubscribe':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyComm_NotifySubscribe':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyComm/NotifySubscribe:1.0",
- 'CosNotifyComm_NotifySubscribe':typeID()),
- check_tc('CosNotifyComm_NotifySubscribe':oe_get_interface()),
- ?match(true, 'CosNotifyComm_NotifySubscribe':oe_is_a('CosNotifyComm_NotifySubscribe':typeID())),
- ?match(false, 'CosNotifyComm_NotifySubscribe':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyComm_PullConsumer'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyComm_PullConsumer'(_) ->
- ?nomatch(undefined, 'CosNotifyComm_PullConsumer':oe_tc(offer_change)),
- ?nomatch(undefined, 'CosNotifyComm_PullConsumer':oe_tc(disconnect_pull_consumer)),
- ?match(undefined, 'CosNotifyComm_PullConsumer':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyComm_PullConsumer':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyComm/PullConsumer:1.0",
- 'CosNotifyComm_PullConsumer':typeID()),
- check_tc('CosNotifyComm_PullConsumer':oe_get_interface()),
- ?match(true, 'CosNotifyComm_PullConsumer':oe_is_a('CosNotifyComm_PullConsumer':typeID())),
- ?match(true, 'CosNotifyComm_PullConsumer':oe_is_a('CosNotifyComm_NotifyPublish':typeID())),
- ?match(true, 'CosNotifyComm_PullConsumer':oe_is_a('CosEventComm_PullConsumer':typeID())),
- ?match(false, 'CosNotifyComm_PullConsumer':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyComm_PullSupplier'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyComm_PullSupplier'(_) ->
- ?nomatch(undefined, 'CosNotifyComm_PullSupplier':oe_tc(subscription_change)),
- ?nomatch(undefined, 'CosNotifyComm_PullSupplier':oe_tc(pull)),
- ?nomatch(undefined, 'CosNotifyComm_PullSupplier':oe_tc(try_pull)),
- ?nomatch(undefined, 'CosNotifyComm_PullSupplier':oe_tc(disconnect_pull_supplier)),
- ?match(undefined, 'CosNotifyComm_PullSupplier':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyComm_PullSupplier':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyComm/PullSupplier:1.0",
- 'CosNotifyComm_PullSupplier':typeID()),
- check_tc('CosNotifyComm_PullSupplier':oe_get_interface()),
- ?match(true, 'CosNotifyComm_PullSupplier':oe_is_a('CosNotifyComm_PullSupplier':typeID())),
- ?match(true, 'CosNotifyComm_PullSupplier':oe_is_a('CosNotifyComm_NotifySubscribe':typeID())),
- ?match(true, 'CosNotifyComm_PullSupplier':oe_is_a('CosEventComm_PullSupplier':typeID())),
- ?match(false, 'CosNotifyComm_PullSupplier':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyComm_PushConsumer'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyComm_PushConsumer'(_) ->
- ?nomatch(undefined, 'CosNotifyComm_PushConsumer':oe_tc(offer_change)),
- ?nomatch(undefined, 'CosNotifyComm_PushConsumer':oe_tc(push)),
- ?nomatch(undefined, 'CosNotifyComm_PushConsumer':oe_tc(disconnect_push_consumer)),
- ?match(undefined, 'CosNotifyComm_PushConsumer':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyComm_PushConsumer':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyComm/PushConsumer:1.0",
- 'CosNotifyComm_PushConsumer':typeID()),
- check_tc('CosNotifyComm_PushConsumer':oe_get_interface()),
- ?match(true, 'CosNotifyComm_PushConsumer':oe_is_a('CosNotifyComm_PushConsumer':typeID())),
- ?match(true, 'CosNotifyComm_PushConsumer':oe_is_a('CosNotifyComm_NotifyPublish':typeID())),
- ?match(true, 'CosNotifyComm_PushConsumer':oe_is_a('CosEventComm_PushConsumer':typeID())),
- ?match(false, 'CosNotifyComm_PushConsumer':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyComm_PushSupplier'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyComm_PushSupplier'(_) ->
- ?nomatch(undefined, 'CosNotifyComm_PushSupplier':oe_tc(subscription_change)),
- ?nomatch(undefined, 'CosNotifyComm_PushSupplier':oe_tc(disconnect_push_supplier)),
- ?match(undefined, 'CosNotifyComm_PushSupplier':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyComm_PushSupplier':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyComm/PushSupplier:1.0",
- 'CosNotifyComm_PushSupplier':typeID()),
- check_tc('CosNotifyComm_PushSupplier':oe_get_interface()),
- ?match(true, 'CosNotifyComm_PushSupplier':oe_is_a('CosNotifyComm_PushSupplier':typeID())),
- ?match(true, 'CosNotifyComm_PushSupplier':oe_is_a('CosNotifyComm_NotifySubscribe':typeID())),
- ?match(true, 'CosNotifyComm_PushSupplier':oe_is_a('CosEventComm_PushSupplier':typeID())),
- ?match(false, 'CosNotifyComm_PushSupplier':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyComm_SequencePullConsumer'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyComm_SequencePullConsumer'(_) ->
- ?nomatch(undefined, 'CosNotifyComm_SequencePullConsumer':oe_tc(disconnect_sequence_pull_consumer)),
- ?nomatch(undefined, 'CosNotifyComm_SequencePullConsumer':oe_tc(offer_change)),
- ?match(undefined, 'CosNotifyComm_SequencePullConsumer':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyComm_SequencePullConsumer':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyComm/SequencePullConsumer:1.0",
- 'CosNotifyComm_SequencePullConsumer':typeID()),
- check_tc('CosNotifyComm_SequencePullConsumer':oe_get_interface()),
- ?match(true, 'CosNotifyComm_SequencePullConsumer':oe_is_a('CosNotifyComm_SequencePullConsumer':typeID())),
- ?match(true, 'CosNotifyComm_SequencePullConsumer':oe_is_a('CosNotifyComm_NotifyPublish':typeID())),
- ?match(false, 'CosNotifyComm_SequencePullConsumer':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyComm_SequencePullSupplier'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyComm_SequencePullSupplier'(_) ->
- ?nomatch(undefined, 'CosNotifyComm_SequencePullSupplier':oe_tc(pull_structured_events)),
- ?nomatch(undefined, 'CosNotifyComm_SequencePullSupplier':oe_tc(try_pull_structured_events)),
- ?nomatch(undefined, 'CosNotifyComm_SequencePullSupplier':oe_tc(disconnect_sequence_pull_supplier)),
- ?nomatch(undefined, 'CosNotifyComm_SequencePullSupplier':oe_tc(subscription_change)),
- ?match(undefined, 'CosNotifyComm_SequencePullSupplier':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyComm_SequencePullSupplier':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyComm/SequencePullSupplier:1.0",
- 'CosNotifyComm_SequencePullSupplier':typeID()),
- check_tc('CosNotifyComm_SequencePullSupplier':oe_get_interface()),
- ?match(true, 'CosNotifyComm_SequencePullSupplier':oe_is_a('CosNotifyComm_SequencePullSupplier':typeID())),
- ?match(true, 'CosNotifyComm_SequencePullSupplier':oe_is_a('CosNotifyComm_NotifySubscribe':typeID())),
- ?match(false, 'CosNotifyComm_SequencePullSupplier':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyComm_SequencePushConsumer'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyComm_SequencePushConsumer'(_) ->
- ?nomatch(undefined, 'CosNotifyComm_SequencePushConsumer':oe_tc(push_structured_events)),
- ?nomatch(undefined, 'CosNotifyComm_SequencePushConsumer':oe_tc(disconnect_sequence_push_consumer)),
- ?nomatch(undefined, 'CosNotifyComm_SequencePushConsumer':oe_tc(offer_change)),
- ?match(undefined, 'CosNotifyComm_SequencePushConsumer':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyComm_SequencePushConsumer':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyComm/SequencePushConsumer:1.0",
- 'CosNotifyComm_SequencePushConsumer':typeID()),
- check_tc('CosNotifyComm_SequencePushConsumer':oe_get_interface()),
- ?match(true, 'CosNotifyComm_SequencePushConsumer':oe_is_a('CosNotifyComm_SequencePushConsumer':typeID())),
- ?match(true, 'CosNotifyComm_SequencePushConsumer':oe_is_a('CosNotifyComm_NotifyPublish':typeID())),
- ?match(false, 'CosNotifyComm_SequencePushConsumer':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyComm_SequencePushSupplier'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyComm_SequencePushSupplier'(_) ->
- ?nomatch(undefined, 'CosNotifyComm_SequencePushSupplier':oe_tc(disconnect_sequence_push_supplier)),
- ?nomatch(undefined, 'CosNotifyComm_SequencePushSupplier':oe_tc(subscription_change)),
- ?match(undefined, 'CosNotifyComm_SequencePushSupplier':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyComm_SequencePushSupplier':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyComm/SequencePushSupplier:1.0",
- 'CosNotifyComm_SequencePushSupplier':typeID()),
- check_tc('CosNotifyComm_SequencePushSupplier':oe_get_interface()),
- ?match(true, 'CosNotifyComm_SequencePushSupplier':oe_is_a('CosNotifyComm_SequencePushSupplier':typeID())),
- ?match(true, 'CosNotifyComm_SequencePushSupplier':oe_is_a('CosNotifyComm_NotifySubscribe':typeID())),
- ?match(false, 'CosNotifyComm_SequencePushSupplier':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyComm_StructuredPullConsumer'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyComm_StructuredPullConsumer'(_) ->
- ?nomatch(undefined, 'CosNotifyComm_StructuredPullConsumer':oe_tc(disconnect_structured_pull_consumer)),
- ?nomatch(undefined, 'CosNotifyComm_StructuredPullConsumer':oe_tc(offer_change)),
- ?match(undefined, 'CosNotifyComm_StructuredPullConsumer':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyComm_StructuredPullConsumer':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyComm/StructuredPullConsumer:1.0",
- 'CosNotifyComm_StructuredPullConsumer':typeID()),
- check_tc('CosNotifyComm_StructuredPullConsumer':oe_get_interface()),
- ?match(true, 'CosNotifyComm_StructuredPullConsumer':oe_is_a('CosNotifyComm_StructuredPullConsumer':typeID())),
- ?match(true, 'CosNotifyComm_StructuredPullConsumer':oe_is_a('CosNotifyComm_NotifyPublish':typeID())),
- ?match(false, 'CosNotifyComm_StructuredPullConsumer':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyComm_StructuredPullSupplier'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyComm_StructuredPullSupplier'(_) ->
- ?nomatch(undefined, 'CosNotifyComm_StructuredPullSupplier':oe_tc(pull_structured_event)),
- ?nomatch(undefined, 'CosNotifyComm_StructuredPullSupplier':oe_tc(try_pull_structured_event)),
- ?nomatch(undefined, 'CosNotifyComm_StructuredPullSupplier':oe_tc(disconnect_structured_pull_supplier)),
- ?nomatch(undefined, 'CosNotifyComm_StructuredPullSupplier':oe_tc(subscription_change)),
- ?match(undefined, 'CosNotifyComm_StructuredPullSupplier':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyComm_StructuredPullSupplier':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyComm/StructuredPullSupplier:1.0",
- 'CosNotifyComm_StructuredPullSupplier':typeID()),
- check_tc('CosNotifyComm_StructuredPullSupplier':oe_get_interface()),
- ?match(true, 'CosNotifyComm_StructuredPullSupplier':oe_is_a('CosNotifyComm_StructuredPullSupplier':typeID())),
- ?match(true, 'CosNotifyComm_StructuredPullSupplier':oe_is_a('CosNotifyComm_NotifySubscribe':typeID())),
- ?match(false, 'CosNotifyComm_StructuredPullSupplier':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyComm_StructuredPushConsumer'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyComm_StructuredPushConsumer'(_) ->
- ?nomatch(undefined, 'CosNotifyComm_StructuredPushConsumer':oe_tc(push_structured_event)),
- ?nomatch(undefined, 'CosNotifyComm_StructuredPushConsumer':oe_tc(disconnect_structured_push_consumer)),
- ?nomatch(undefined, 'CosNotifyComm_StructuredPushConsumer':oe_tc(offer_change)),
- ?match(undefined, 'CosNotifyComm_StructuredPushConsumer':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyComm_StructuredPushConsumer':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyComm/StructuredPushConsumer:1.0",
- 'CosNotifyComm_StructuredPushConsumer':typeID()),
- check_tc('CosNotifyComm_StructuredPushConsumer':oe_get_interface()),
- ?match(true, 'CosNotifyComm_StructuredPushConsumer':oe_is_a('CosNotifyComm_StructuredPushConsumer':typeID())),
- ?match(true, 'CosNotifyComm_StructuredPushConsumer':oe_is_a('CosNotifyComm_NotifyPublish':typeID())),
- ?match(false, 'CosNotifyComm_StructuredPushConsumer':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNotifyComm_StructuredPushSupplier'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNotifyComm_StructuredPushSupplier'(_) ->
- ?nomatch(undefined, 'CosNotifyComm_StructuredPushSupplier':oe_tc(disconnect_structured_push_supplier)),
- ?nomatch(undefined, 'CosNotifyComm_StructuredPushSupplier':oe_tc(subscription_change)),
- ?match(undefined, 'CosNotifyComm_StructuredPushSupplier':oe_tc(undefined)),
- ?match([_|_], 'CosNotifyComm_StructuredPushSupplier':oe_get_interface()),
- ?match("IDL:omg.org/CosNotifyComm/StructuredPushSupplier:1.0",
- 'CosNotifyComm_StructuredPushSupplier':typeID()),
- check_tc('CosNotifyComm_StructuredPushSupplier':oe_get_interface()),
- ?match(true, 'CosNotifyComm_StructuredPushSupplier':oe_is_a('CosNotifyComm_StructuredPushSupplier':typeID())),
- ?match(true, 'CosNotifyComm_StructuredPushSupplier':oe_is_a('CosNotifyComm_NotifySubscribe':typeID())),
- ?match(false, 'CosNotifyComm_StructuredPushSupplier':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'oe_CosNotificationComm_Event'
-%% Description:
-%%-----------------------------------------------------------------
-'oe_CosNotificationComm_Event'(_) ->
- ?nomatch(undefined, 'oe_CosNotificationComm_Event':oe_tc(callSeq)),
- ?nomatch(undefined, 'oe_CosNotificationComm_Event':oe_tc(callAny)),
- ?match(undefined, 'oe_CosNotificationComm_Event':oe_tc(undefined)),
- ?match([_|_], 'oe_CosNotificationComm_Event':oe_get_interface()),
- ?match("IDL:oe_CosNotificationComm/Event:1.0",
- 'oe_CosNotificationComm_Event':typeID()),
- check_tc('oe_CosNotificationComm_Event':oe_get_interface()),
- ?match(true, 'oe_CosNotificationComm_Event':oe_is_a('oe_CosNotificationComm_Event':typeID())),
- ?match(false, 'oe_CosNotificationComm_Event':oe_is_a("wrong")),
- ok.
-
-
-
-
-%%-----------------------------------------------------------------
-%% MISC functions
-%%-----------------------------------------------------------------
-check_tc([]) ->
- ok;
-check_tc([{Op, {RetType, InParameters, OutParameters}}|T]) ->
- io:format("checked - ~s~n", [Op]),
- lists:all(?checktc(Op), [RetType|InParameters]),
- lists:all(?checktc(Op), OutParameters),
- check_tc(T).
-
-
diff --git a/lib/cosNotification/test/grammar_SUITE.erl b/lib/cosNotification/test/grammar_SUITE.erl
deleted file mode 100644
index 536292fdee..0000000000
--- a/lib/cosNotification/test/grammar_SUITE.erl
+++ /dev/null
@@ -1,1091 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%--------------------------------------------------------------------
-%% File : grammar_SUITE.erl
-%% Purpose : Testing the CosNotification BNF grammar.
-%%--------------------------------------------------------------------
-
--module(grammar_SUITE).
-
-%%--------------- INCLUDES -----------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
-%% cosEvent files.
--include_lib("cosEvent/include/CosEventChannelAdmin.hrl").
-%% Application files
--include_lib("cosNotification/include/CosNotification.hrl").
--include_lib("cosNotification/include/CosNotifyChannelAdmin.hrl").
--include_lib("cosNotification/include/CosNotifyComm.hrl").
--include_lib("cosNotification/include/CosNotifyFilter.hrl").
-
--include_lib("cosNotification/src/CosNotification_Definitions.hrl").
-
--include("idl_output/notify_test.hrl").
-
--include_lib("common_test/include/ct.hrl").
-
-%%--------------- DEFINES ------------------------------------
--define(default_timeout, test_server:minutes(20)).
--define(match(ExpectedRes, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- io:format("------ CORRECT RESULT ------~n~p~n",
- [AcTuAlReS]),
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
- cases/0, init_per_suite/1, end_per_suite/1,
- union_api/1, enum_api/1, simple_types_api/1,
- components_api/1, positional_api/1, variable_api/1,
- init_per_testcase/2, end_per_testcase/2]).
-
--import(cosNotification_Filter, [create_filter/1, eval/2]).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- cases().
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-cases() ->
- [variable_api, union_api, enum_api, simple_types_api,
- components_api, positional_api].
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-init_per_testcase(_Case, Config) ->
- Path = code:which(?MODULE),
- code:add_pathz(filename:join(filename:dirname(Path), "idl_output")),
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- Path = code:which(?MODULE),
- code:del_path(filename:join(filename:dirname(Path), "idl_output")),
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-init_per_suite(Config) ->
- Path = code:which(?MODULE),
- code:add_pathz(filename:join(filename:dirname(Path), "idl_output")),
- if
- is_list(Config) ->
- Config;
- true ->
- exit("Config not a list")
- end.
-
-end_per_suite(Config) ->
- Path = code:which(?MODULE),
- code:del_path(filename:join(filename:dirname(Path), "idl_output")),
- Config.
-
-
-%%-----------------------------------------------------------------
-%% simple types grammar tests
-%%-----------------------------------------------------------------
-simple_types_api(_Config) ->
- %% Will always be true, no matter what kind of event we receive.
- {ok,T1} = ?match({ok, _}, create_filter("2==2 and 3<4")),
- ?match(true, eval(T1, ?not_CreateSE("DomainName","TypeName","EventName",
- [],[], any:create(orber_tc:null(), null)))),
-
- %% Will always be true, no matter what kind of event we receive.
- {ok,T2} = ?match({ok, _}, create_filter("")),
- ?match(true, eval(T2, ?not_CreateSE("DomainName","TypeName","EventName",
- [],[], any:create(orber_tc:null(), null)))),
-
- %% Check if $variable works
- {ok,T3} = ?match({ok, _}, create_filter("$city == \'Berlin\'")),
- ?match(true, eval(T3, ?not_CreateSE("DomainName","TypeName","EventName",
- [#'CosNotification_Property'{name="city",
- value=any:create(orber_tc:string(0), "Berlin")}],
- [], any:create(orber_tc:null(), null)))),
- ?match(false, eval(T3, ?not_CreateSE("DomainName","TypeName", "EventName",
- [#'CosNotification_Property'{name="city",
- value=any:create(orber_tc:string(0), "Dallas")}],
-
- [], any:create(orber_tc:null(), null)))),
-
-
- {ok,T4} = ?match({ok, _}, create_filter("$zip == 44")),
- ?match(true, eval(T4, ?not_CreateSE("DomainName","TypeName", "EventName",
- [#'CosNotification_Property'{name="zip",
- value=any:create(orber_tc:short(), 44)}],
-
- [], any:create(orber_tc:null(), null)))),
- ?match(true, eval(T4, ?not_CreateSE("DomainName","TypeName", "EventName",
- [],[],
- any:create('CosNotification_Property':tc(),
- #'CosNotification_Property'
- {name="zip",
- value=any:create(orber_tc:short(),
- 44)})))),
- ?match(false, eval(T4, ?not_CreateSE("DomainName","TypeName", "EventName",
- [#'CosNotification_Property'{name="zip",
- value=any:create(orber_tc:short(), 33)}],
-
- [], any:create(orber_tc:null(), null)))),
-
- %% Will always be true, no matter what kind of event we receive.
- {ok,T5} = ?match({ok, _}, create_filter("\'oo'\~\'foobar\'")),
- ?match(true, eval(T5, ?not_CreateSE("DomainName","TypeName","EventName",
- [],[], any:create(orber_tc:null(), null)))),
- %% Will always be false, no matter what kind of event we receive.
- {ok,T6} = ?match({ok, _}, create_filter("\'o1'\~\'foobar\'")),
- ?match(false, eval(T6, ?not_CreateSE("DomainName","TypeName","EventName",
- [],[], any:create(orber_tc:null(), null)))),
-
- %% Can we apply the ~ operation as above using a variable
- {ok,T7} = ?match({ok, _}, create_filter("$str~\'foobar\'")),
- ?match(true, eval(T7, ?not_CreateSE("DomainName","TypeName","EventName",
- [#'CosNotification_Property'{name="str",
- value=any:create(orber_tc:string(0), "oo")}],
- [], any:create(orber_tc:null(), null)))),
- ?match(false, eval(T7, ?not_CreateSE("DomainName","TypeName","EventName",
- [#'CosNotification_Property'{name="str",
- value=any:create(orber_tc:string(0), "ok")}],
- [], any:create(orber_tc:null(), null)))),
-
-
-
- {ok,_T8} = ?match({ok, _}, create_filter("$\\zip == 44444")),
-
- ok.
-
-%%-----------------------------------------------------------------
-%% enum grammar tests
-%%-----------------------------------------------------------------
-enum_api(_Config) ->
- %% Accept events whose 'in' enum is set to the value 'HOUSE' or 'CAR'.
- {ok,T1} = ?match({ok, _}, create_filter("$.\\in == HOUSE or $.\\in == CAR")),
-
- ?match(true, eval(T1, any:create(orber_tc:alias("IFRId","in",tk_any),
- any:create({tk_enum, "IFRId", "in", ["HOUSE", "CAR"]},
- 'HOUSE')))),
- ?match(false, eval(T1, any:create(orber_tc:alias("IFRId","in",tk_any),
- any:create({tk_enum, "IFRId", "in", ["HOUSE", "CAR"]},
- 'GARAGE')))),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Union grammar tests
-%%-----------------------------------------------------------------
-union_api(_Config) ->
- {ok,T1} = ?match({ok, _}, create_filter("exist $.uni1._d and $.uni1._d == 1 and $.uni1.(1) == 10")),
- {ok,T2} = ?match({ok, _}, create_filter("default $.uni1._d and $.uni1.() == 10")),
- {ok,T3} = ?match({ok, _}, create_filter("default $.uni1._d and $.uni1.(999) == 10")),
- ?match(true, eval(T1, ?not_CreateSE("DomainName","CommunicationsAlarm",
- "EventName",[],[],
- any:create(orber_tc:alias("IDL:notify_test/namedAny:1.0",
- "uni1",
- tk_any),
- any:create(notify_test_uni1:tc(),
- #notify_test_uni1{label= 1,
- value=10}))))),
- ?match(true, eval(T2, ?not_CreateSE("DomainName","CommunicationsAlarm",
- "EventName",[],[],
- any:create(orber_tc:alias("IDL:notify_test/namedAny:1.0",
- "uni1",
- tk_any),
- any:create(notify_test_uni1:tc(),
- #notify_test_uni1{label= 100,
- value=10}))))),
- ?match(true, eval(T3, ?not_CreateSE("DomainName","CommunicationsAlarm",
- "EventName",[],[],
- any:create(orber_tc:alias("IDL:notify_test/namedAny:1.0",
- "uni1",
- tk_any),
- any:create(notify_test_uni1:tc(),
- #notify_test_uni1{label= 100,
- value=10}))))),
- ?match(true, eval(T1, any:create(orber_tc:alias("IDL:notify_test/namedAny:1.0",
- "uni1",
- tk_any),
- any:create(notify_test_uni1:tc(),
- #notify_test_uni1{label= 1,
- value=10})))),
- ?match(false, eval(T2, any:create(orber_tc:alias("IDL:notify_test/namedAny:1.0",
- "uni1",
- tk_any),
- any:create(notify_test_uni1:tc(),
- #notify_test_uni1{label= 1,
- value=10})))),
- ?match(false, eval(T3, any:create(orber_tc:alias("IDL:notify_test/namedAny:1.0",
- "uni1",
- tk_any),
- any:create(notify_test_uni1:tc(),
- #notify_test_uni1{label= 1,
- value=10})))),
- ?match(true, eval(T1, ?not_CreateSE("DomainName","CommunicationsAlarm",
- "EventName",[],[],
- any:create(notify_test_studies:tc(), #notify_test_studies
- {uni1 = #notify_test_uni1{label= 1, value=10},
- gpa = 90,
- tests = [#'CosNotification_Property'
- {name="midterm", value=any:create(orber_tc:short(), 70)},
- #'CosNotification_Property'
- {name="final", value=any:create(orber_tc:short(), 60)}],
- monthly_attendance = {0,1,2,10}})))),
- ?match(false, eval(T2, ?not_CreateSE("DomainName","CommunicationsAlarm",
- "EventName",[],[],
- any:create(notify_test_studies:tc(), #notify_test_studies
- {uni1 = #notify_test_uni1{label= 1, value=10},
- gpa = 90,
- tests = [#'CosNotification_Property'
- {name="midterm", value=any:create(orber_tc:short(), 70)},
- #'CosNotification_Property'
- {name="final", value=any:create(orber_tc:short(), 60)}],
- monthly_attendance = {0,1,2,10}})))),
- ?match(false, eval(T3, ?not_CreateSE("DomainName","CommunicationsAlarm",
- "EventName",[],[],
- any:create(notify_test_studies:tc(), #notify_test_studies
- {uni1 = #notify_test_uni1{label= 1, value=10},
- gpa = 90,
- tests = [#'CosNotification_Property'
- {name="midterm", value=any:create(orber_tc:short(), 70)},
- #'CosNotification_Property'
- {name="final", value=any:create(orber_tc:short(), 60)}],
- monthly_attendance = {0,1,2,10}})))),
- ?match(true, eval(T1, any:create(notify_test_studies:tc(), #notify_test_studies
- {uni1 = #notify_test_uni1{label= 1, value=10},
- gpa = 90,
- tests = [#'CosNotification_Property'
- {name="midterm", value=any:create(orber_tc:short(), 70)},
- #'CosNotification_Property'
- {name="final", value=any:create(orber_tc:short(), 60)}],
- monthly_attendance = {0,1,2,10}}))),
- ?match(false, eval(T2, any:create(notify_test_studies:tc(), #notify_test_studies
- {uni1 = #notify_test_uni1{label= 1, value=10},
- gpa = 90,
- tests = [#'CosNotification_Property'
- {name="midterm", value=any:create(orber_tc:short(), 70)},
- #'CosNotification_Property'
- {name="final", value=any:create(orber_tc:short(), 60)}],
- monthly_attendance = {0,1,2,10}}))),
- ?match(false, eval(T3, any:create(notify_test_studies:tc(), #notify_test_studies
- {uni1 = #notify_test_uni1{label= 1, value=10},
- gpa = 90,
- tests = [#'CosNotification_Property'
- {name="midterm", value=any:create(orber_tc:short(), 70)},
- #'CosNotification_Property'
- {name="final", value=any:create(orber_tc:short(), 60)}],
- monthly_attendance = {0,1,2,10}}))),
-
- {ok,T4} = ?match({ok, _}, create_filter("exist $.alias.uni1._d and $.alias.uni1._d == 1 and $.alias.uni1.(1) == 10")),
- ?match(true, eval(T4, ?not_CreateSE("DomainName","CommunicationsAlarm",
- "EventName",[],[],
- any:create(orber_tc:alias(notify_test_studies:id(),
- "alias",
- notify_test_studies:tc()),
- #notify_test_studies
- {uni1 = #notify_test_uni1{label= 1, value=10},
- gpa = 90, tests = [],
- monthly_attendance = {0,1,2,10}})))),
- ?match(true, eval(T4, any:create(orber_tc:alias(notify_test_studies:id(),
- "alias",
- notify_test_studies:tc()),
- #notify_test_studies
- {uni1 = #notify_test_uni1{label= 1, value=10},
- gpa = 90, tests = [],
- monthly_attendance = {0,1,2,10}}))),
- %% Accept events with a default union discriminator set to the value 2.
- {ok,T5} = ?match({ok, _}, create_filter("default $._d and $.defvalue == 2")),
- ?match(true, eval(T5, any:create(notify_test_uni1:tc(),
- #notify_test_uni1{label= 100, value=2}))),
- %% label not default.
- ?match(false, eval(T5, any:create(notify_test_uni1:tc(),
- #notify_test_uni1{label= 2, value=2}))),
- %% Default does not exist (nor the component defvalue)
- ?match(false, eval(T5, any:create(notify_test_uni2:tc(),
- #notify_test_uni2{label= 100, value=2}))),
- %% Both wrong
- ?match(false, eval(T5, any:create(notify_test_uni2:tc(),
- #notify_test_uni2{label= 2, value=2}))),
-
- {ok,T6} = ?match({ok, _}, create_filter("default $._d and $.(-8) == 2")),
- ?match(true, eval(T6, any:create(notify_test_uni1:tc(),
- #notify_test_uni1{label= 100, value=2}))),
- %% label not default.
- ?match(false, eval(T6, any:create(notify_test_uni1:tc(),
- #notify_test_uni1{label= 2, value=2}))),
- %% Default does not exist (nor the component defvalue)
- ?match(false, eval(T6, any:create(notify_test_uni2:tc(),
- #notify_test_uni2{label= 100, value=2}))),
- %% Both wrong
- ?match(false, eval(T6, any:create(notify_test_uni2:tc(),
- #notify_test_uni2{label= 2, value=2}))),
- %% the same as the above, but we try to access a label that is not default
- {ok,T7} = ?match({ok, _}, create_filter("default $._d and $.(2) == 2")),
- ?match({error, _}, eval(T7, any:create(notify_test_uni1:tc(),
- #notify_test_uni1{label= 100, value=2}))),
-
- %% Must be a default-union with its 'defvalue' set to 2.
- {ok,T8} = ?match({ok, _}, create_filter("default $._d and $.('defvalue') == 2")),
- ?match(true, eval(T8, any:create(notify_test_uni1:tc(),
- #notify_test_uni1{label= 100, value=2}))),
- %% label not default.
- ?match(false, eval(T8, any:create(notify_test_uni1:tc(),
- #notify_test_uni1{label= 2, value=2}))),
- %% Default does not exist (nor the component defvalue)
- ?match(false, eval(T8, any:create(notify_test_uni2:tc(),
- #notify_test_uni2{label= 100, value=2}))),
- %% Both wrong
- ?match(false, eval(T8, any:create(notify_test_uni2:tc(),
- #notify_test_uni2{label= 2, value=2}))),
-
- %% Must be a default-union with its value set to 2.
- {ok,T9} = ?match({ok, _}, create_filter("default $._d and $.(+100) == 2")),
- ?match(true, eval(T9, any:create(notify_test_uni1:tc(),
- #notify_test_uni1{label= 100, value=2}))),
- %% label not default.
- ?match(false, eval(T9, any:create(notify_test_uni1:tc(),
- #notify_test_uni1{label= 2, value=2}))),
- %% Default does not exist (nor the component defvalue)
- ?match(false, eval(T9, any:create(notify_test_uni2:tc(),
- #notify_test_uni2{label= 100, value=2}))),
- %% Both wrong
- ?match(false, eval(T9, any:create(notify_test_uni2:tc(),
- #notify_test_uni2{label= 2, value=2}))),
-
- %% So far, we have only tested to access the union itself. No will use more
- %% complex union members.
- %% T10 and T11 is "equal"
- {ok,T10} = ?match({ok, _}, create_filter("$.M < 54")),
- {ok,T11} = ?match({ok, _}, create_filter("$.(5) < 54")),
- ?match(false, eval(T10, any:create(notify_test_K:tc(),
- #notify_test_K{label= 5, value=54}))),
- ?match(false, eval(T11, any:create(notify_test_K:tc(),
- #notify_test_K{label= 5, value=54}))),
- ?match(true, eval(T10, any:create(notify_test_K:tc(),
- #notify_test_K{label= 5, value=50}))),
- ?match(true, eval(T11, any:create(notify_test_K:tc(),
- #notify_test_K{label= 5, value=50}))),
- ?match({error,_}, eval(T10, any:create(notify_test_K:tc(),
- #notify_test_K{label= -1, value=50}))),
- ?match({error,_}, eval(T11, any:create(notify_test_K:tc(),
- #notify_test_K{label= -1, value=50}))),
-
- %% T12 and T13 is "equal"
- {ok,T12} = ?match({ok, _}, create_filter("$.L.C < 128")),
- {ok,T13} = ?match({ok, _}, create_filter("$.(3).2 < 128")),
- ?match(true, eval(T12, any:create(notify_test_K:tc(),
- #notify_test_K{label= 3, value=
- #notify_test_X{'A' = 1,
- 'B' = "string",
- 'C' = 120}}))),
- ?match(true, eval(T13, any:create(notify_test_K:tc(),
- #notify_test_K{label= 3, value=
- #notify_test_X{'A' = 1,
- 'B' = "string",
- 'C' = 120}}))),
- ?match(false, eval(T12, any:create(notify_test_K:tc(),
- #notify_test_K{label= 3, value=
- #notify_test_X{'A' = 1,
- 'B' = "string",
- 'C' = 200}}))),
- ?match(false, eval(T13, any:create(notify_test_K:tc(),
- #notify_test_K{label= 3, value=
- #notify_test_X{'A' = 1,
- 'B' = "string",
- 'C' = 200}}))),
-
- %% Test if 'putty' is a substring of K
- {ok,T15} = ?match({ok, _}, create_filter("'putty' ~ $.(2)")),
- {ok,T16} = ?match({ok, _}, create_filter("'putty' ~ $.K")),
- ?match(true, eval(T15, any:create(notify_test_K:tc(),
- #notify_test_K{label= 2, value= "isputtyok"}))),
- ?match(true, eval(T16, any:create(notify_test_K:tc(),
- #notify_test_K{label= 2, value= "isputtyok"}))),
- ?match(false, eval(T15, any:create(notify_test_K:tc(),
- #notify_test_K{label= 2, value= "notputtok"}))),
- ?match(false, eval(T16, any:create(notify_test_K:tc(),
- #notify_test_K{label= 2, value= "notputtok"}))),
-
- {ok,_T17} = ?match({ok, _}, create_filter("'putty' ~ $.(3).1")),
- {ok,_T18} = ?match({ok, _}, create_filter("'putty' ~ $.L.B")),
- ?match(true, eval(T12, any:create(notify_test_K:tc(),
- #notify_test_K{label= 3, value=
- #notify_test_X{'A' = 1,
- 'B' = "isputtyok",
- 'C' = 120}}))),
- ?match(true, eval(T13, any:create(notify_test_K:tc(),
- #notify_test_K{label= 3, value=
- #notify_test_X{'A' = 1,
- 'B' = "isputtyok",
- 'C' = 120}}))),
- ?match(false, eval(T12, any:create(notify_test_K:tc(),
- #notify_test_K{label= 3, value=
- #notify_test_X{'A' = 1,
- 'B' = "notputtok",
- 'C' = 200}}))),
- ?match(false, eval(T13, any:create(notify_test_K:tc(),
- #notify_test_K{label= 3, value=
- #notify_test_X{'A' = 1,
- 'B' = "notputtok",
- 'C' = 200}}))),
-
- %% Please observe that the switch 0 and 2 is defined to be equivalent.
- {ok,T19} = ?match({ok, _}, create_filter("$._d == 2 and $.(0) != 'hoob'")),
- {ok,T20} = ?match({ok, _}, create_filter("$._d == 2 and $.(2) != 'hoob'")),
- ?match(true, eval(T19, any:create(notify_test_K:tc(),
- #notify_test_K{label= 2, value= "nothoob"}))),
- ?match(true, eval(T20, any:create(notify_test_K:tc(),
- #notify_test_K{label= 2, value= "nothoob"}))),
- ?match(false, eval(T19, any:create(notify_test_K:tc(),
- #notify_test_K{label= 2, value= "hoob"}))),
- ?match(false, eval(T20, any:create(notify_test_K:tc(),
- #notify_test_K{label= 2, value= "hoob"}))),
-
- ?match(false, eval(T19, any:create(notify_test_K:tc(),
- #notify_test_K{label= 5, value= 55}))),
- ?match(false, eval(T20, any:create(notify_test_K:tc(),
- #notify_test_K{label= 5, value= 55}))),
-
- ?match(false, eval(T19, any:create(notify_test_K:tc(),
- #notify_test_K{label= 100, value= "nothoob"}))),
- ?match(false, eval(T20, any:create(notify_test_K:tc(),
- #notify_test_K{label= 100, value= "nothoob"}))),
-
- {ok,T21} = ?match({ok, _}, create_filter("exist $.K")),
- {ok,T22} = ?match({ok, _}, create_filter("exist $.(0) or exist $.(2)")),
- ?match(true, eval(T21, any:create(notify_test_K:tc(),
- #notify_test_K{label= 0, value= "hoob"}))),
- ?match(true, eval(T22, any:create(notify_test_K:tc(),
- #notify_test_K{label= 0, value= "hoob"}))),
- ?match(true, eval(T21, any:create(notify_test_K:tc(),
- #notify_test_K{label= 2, value= "hoob"}))),
- ?match(true, eval(T22, any:create(notify_test_K:tc(),
- #notify_test_K{label= 2, value= "hoob"}))),
- ?match(false, eval(T21, any:create(notify_test_K:tc(),
- #notify_test_K{label= 5, value= 55}))),
- ?match(false, eval(T22, any:create(notify_test_K:tc(),
- #notify_test_K{label= 5, value= 55}))),
-
-
- %% Please observe that the switch 0 and 2 is defined to be equivalent.
- {ok,T23} = ?match({ok, _}, create_filter("exist $.(2)")),
- {ok,T24} = ?match({ok, _}, create_filter("exist $.(0)")),
- ?match(true, eval(T23, any:create(notify_test_K:tc(),
- #notify_test_K{label= 2, value= "hoob"}))),
- ?match(false, eval(T24, any:create(notify_test_K:tc(),
- #notify_test_K{label= 2, value= "hoob"}))),
- ?match(false, eval(T23, any:create(notify_test_K:tc(),
- #notify_test_K{label= 0, value= "hoob"}))),
- ?match(true, eval(T24, any:create(notify_test_K:tc(),
- #notify_test_K{label= 0, value= "hoob"}))),
- ?match(false, eval(T23, any:create(notify_test_K:tc(),
- #notify_test_K{label= 5, value= 55}))),
- ?match(false, eval(T24, any:create(notify_test_K:tc(),
- #notify_test_K{label= 5, value= 55}))),
-
- ok.
-
-%%-----------------------------------------------------------------
-%% Variables grammar tests
-%%-----------------------------------------------------------------
-variable_api(_Config) ->
- %% Accept all "CommunicationsAlarm" events
- {ok,T0} = ?match({ok, _}, create_filter("$type_name == 'CommunicationsAlarm'")),
-
- ?match(true, eval(T0, ?not_CreateSE("DomainName","CommunicationsAlarm",
- "EventName",[],[],
- any:create(orber_tc:null(), null)))),
- ?match(false, eval(T0, ?not_CreateSE("DomainName","CommunicationsOK",
- "EventName", [],[],
- any:create(orber_tc:null(), null)))),
- ?match(true, eval(T0, ?not_CreateSE("DomainName","CommunicationsAlarm",
- "EventName", [],[],
- any:create(orber_tc:alias("IFRId", "type_name",
- orber_tc:string(0)),
- "CommunicationsOK")))),
-
- ?match(true, eval(T0, any:create(orber_tc:alias("IFRId", "type_name",
- orber_tc:string(0)),
- "CommunicationsAlarm"))),
- ?match(false, eval(T0, any:create(orber_tc:alias("IFRId", "type_name",
- orber_tc:string(0)),
- "CommunicationsOK"))),
-
-
- %% Accept all "CommunicationsAlarm" events but no "lost_packet" messages.
- {ok,T1} = ?match({ok, _}, create_filter("$type_name == 'CommunicationsAlarm' and not ($event_name == 'lost_packet')")),
-
- ?match(true, eval(T1, ?not_CreateSE("DomainName","CommunicationsAlarm",
- "EventName",[],[],
- any:create(orber_tc:null(), null)))),
- ?match(false, eval(T1, ?not_CreateSE("DomainName","CommunicationsAlarm",
- "lost_packet", [],[],
- any:create(orber_tc:null(), null)))),
- ?match(true,
- eval(T1, any:create(orber_tc:sequence('CosNotification_Property':tc(),0),
- [#'CosNotification_Property'{name="type_name",
- value=any:create(orber_tc:string(0), "CommunicationsAlarm")},
- #'CosNotification_Property'{name="event_name",
- value=any:create(orber_tc:string(0), "EventName")}]))),
- ?match(false,
- eval(T1, any:create(orber_tc:sequence('CosNotification_Property':tc(),0),
- [#'CosNotification_Property'{name="type_name",
- value=any:create(orber_tc:string(0), "CommunicationsAlarm")},
- #'CosNotification_Property'{name="event_name",
- value=any:create(orber_tc:string(0), "lost_packet")}]))),
-
-
- %% Accept "CommunicationsAlarm" events with priorities ranging from 1 to 5.
- {ok,T2} = ?match({ok, _}, create_filter("$type_name == 'CommunicationsAlarm' and $priority >= 1 and $priority <= 5")),
- ?match(true, eval(T2, ?not_CreateSE("DomainName","CommunicationsAlarm",
- "EventName",
- [#'CosNotification_Property'{name="priority",
- value=any:create(orber_tc:short(), 2)}],
- [], any:create(orber_tc:null(), null)))),
- ?match(false, eval(T2, ?not_CreateSE("DomainName","CommunicationsAlarm",
- "EventName",
- [#'CosNotification_Property'{name="priority",
- value=any:create(orber_tc:short(), 20)}],
- [], any:create(orber_tc:null(), null)))),
-
- %% Select "MOVIE" events featuring at least 3 of the Marx Brothers.
- {ok,T3} = ?match({ok, _}, create_filter("$type_name == 'MOVIE' and (('groucho' in $starlist) + ('chico' in $starlist) + ('harpo' in $starlist) + ('zeppo' in $starlist) + ('gummo' in $starlist)) > 2")),
- ?match(true, eval(T3, ?not_CreateSE("DomainName","MOVIE",
- "EventName",
- [#'CosNotification_Property'{name="starlist",
- value=any:create(orber_tc:sequence(orber_tc:string(0),0),
- ["groucho", "harpo", "sam", "gummo"])}],
- [], any:create(orber_tc:null(), null)))),
- ?match(false, eval(T3, ?not_CreateSE("DomainName","MOVIE",
- "EventName",
- [#'CosNotification_Property'{name="starlist",
- value=any:create(orber_tc:sequence(orber_tc:string(0),0),
- ["frodo", "bilbo", "sam", "gummo"])}],
- [], any:create(orber_tc:null(), null)))),
- %% Accept students that took all 3 tests and had an average score of at least 80%.
- {ok,T4} = ?match({ok, _}, create_filter("$test._length == 3 and ($test[0].score + $test[1].score + $test[2].score)/3 >=80")),
- ?match(true, eval(T4, ?not_CreateSE("DomainName","TypeName",
- "EventName", [],
- [#'CosNotification_Property'{name="test",
- value=any:create(orber_tc:array(notify_test_data:tc(),0),
- {#notify_test_data{score=75},
- #notify_test_data{score=80},
- #notify_test_data{score=85}})}],
- any:create(orber_tc:null(), null)))),
- ?match(false, eval(T4, ?not_CreateSE("DomainName","TypeName",
- "EventName", [],
- [#'CosNotification_Property'{name="test",
- value=any:create(orber_tc:array(notify_test_data:tc(),0),
- {#notify_test_data{score=75},
- #notify_test_data{score=80},
- #notify_test_data{score=80}})}],
- any:create(orber_tc:null(), null)))),
- ?match(false, eval(T4, ?not_CreateSE("DomainName","TypeName",
- "EventName", [],
- [#'CosNotification_Property'{name="test",
- value=any:create(orber_tc:array(notify_test_data:tc(),0),
- {#notify_test_data{score=75},
- #notify_test_data{score=85}})}],
- any:create(orber_tc:null(), null)))),
- %% Select processes that exceed a certain usage threshold.
- {ok,T5} = ?match({ok, _}, create_filter("$memsize / 5.5 + $cputime * 1275.0 + $filesize * 1.25 > 500000.0")),
- ?match(true, eval(T5, ?not_CreateSE("DomainName","TypeName",
- "EventName", [],
- [#'CosNotification_Property'{name="memsize",
- value=any:create(orber_tc:float(), 5.5)},
- #'CosNotification_Property'{name="cputime",
- value=any:create(orber_tc:float(), 0.00078431137)},
- #'CosNotification_Property'{name="filesize",
- value=any:create(orber_tc:float(), 500000)}],
- any:create(orber_tc:null(), null)))),
- ?match(false, eval(T5, ?not_CreateSE("DomainName","TypeName",
- "EventName", [],
- [#'CosNotification_Property'{name="memsize",
- value=any:create(orber_tc:float(), 5.5)},
- #'CosNotification_Property'{name="cputime",
- value=any:create(orber_tc:float(), 0.00078431137)},
- #'CosNotification_Property'{name="filesize",
- value=any:create(orber_tc:float(), 500)}],
- any:create(orber_tc:null(), null)))),
- ?match({error, _}, eval(T5, ?not_CreateSE("DomainName","TypeName",
- "EventName", [],
- [#'CosNotification_Property'{name="memsize",
- value=any:create(orber_tc:float(), 5.5)},
- #'CosNotification_Property'{name="filesize",
- value=any:create(orber_tc:float(), 500)}],
- any:create(orber_tc:null(), null)))),
-
- ?match(true, eval(T5, ?not_CreateSE("DomainName","TypeName",
- "EventName", [], [],
- any:create(orber_tc:sequence('CosNotification_Property':tc(),0),
- [#'CosNotification_Property'{name="memsize",
- value=any:create(orber_tc:float(), 5.5)},
- #'CosNotification_Property'{name="cputime",
- value=any:create(orber_tc:float(), 0.00078431137)},
- #'CosNotification_Property'{name="filesize",
- value=any:create(orber_tc:float(), 500000)}])))),
- ?match(false, eval(T5, ?not_CreateSE("DomainName","TypeName",
- "EventName", [], [],
- any:create(orber_tc:sequence('CosNotification_Property':tc(),0),
- [#'CosNotification_Property'{name="memsize",
- value=any:create(orber_tc:float(), 5.5)},
- #'CosNotification_Property'{name="cputime",
- value=any:create(orber_tc:float(), 0.00078431137)},
- #'CosNotification_Property'{name="filesize",
- value=any:create(orber_tc:float(), 500)}])))),
- ?match({error, _}, eval(T5, ?not_CreateSE("DomainName","TypeName",
- "EventName", [], [],
- any:create(orber_tc:sequence('CosNotification_Property':tc(),0),
- [#'CosNotification_Property'{name="memsize",
- value=any:create(orber_tc:float(), 5.5)},
- #'CosNotification_Property'{name="filesize",
- value=any:create(orber_tc:float(), 500)}])))),
-
- ?match(true, eval(T5, any:create(orber_tc:sequence('CosNotification_Property':tc(),0),
- [#'CosNotification_Property'{name="memsize",
- value=any:create(orber_tc:float(), 5.5)},
- #'CosNotification_Property'{name="cputime",
- value=any:create(orber_tc:float(), 0.00078431137)},
- #'CosNotification_Property'{name="filesize",
- value=any:create(orber_tc:float(), 500000)}]))),
- ?match(false, eval(T5, any:create(orber_tc:sequence('CosNotification_Property':tc(),0),
- [#'CosNotification_Property'{name="memsize",
- value=any:create(orber_tc:float(), 5.5)},
- #'CosNotification_Property'{name="cputime",
- value=any:create(orber_tc:float(), 0.00078431137)},
- #'CosNotification_Property'{name="filesize",
- value=any:create(orber_tc:float(), 500)}]))),
- ?match({error, _}, eval(T5, any:create(orber_tc:sequence('CosNotification_Property':tc(),0),
- [#'CosNotification_Property'{name="memsize",
- value=any:create(orber_tc:float(), 5.5)},
- #'CosNotification_Property'{name="filesize",
- value=any:create(orber_tc:float(), 500)}]))),
-
- %% Accept events where a threshold has the unscoped type name 'data'.
- {ok,T6} = ?match({ok, _}, create_filter("exist $threshold._type_id and $threshold._type_id == 'data'")),
- ?match(true, eval(T6, any:create(orber_tc:alias(notify_test_data:id(),
- "threshold",
- notify_test_data:tc()),
- #notify_test_data{score = 10, name = "Erlang"}))),
-
-
-
- ?match(true, eval(T6, ?not_CreateSE("DomainName","TypeName",
- "EventName", [],
- [#'CosNotification_Property'
- {name="threshold",
- value=any:create(notify_test_data:tc(),
- #notify_test_data
- {score = 10,
- name = "Erlang"})}],
- any:create(orber_tc:null(), null)))),
-
-
- ?match(true, eval(T6, ?not_CreateSE("DomainName","TypeName",
- "EventName", [],
- [#'CosNotification_Property'
- {name="NotThreshold",
- value=any:create(notify_test_data:tc(),
- #notify_test_data
- {score = 10,
- name = "Erlang"})}],
- any:create(orber_tc:alias(notify_test_data:id(),
- "threshold",
- notify_test_data:tc()),
- #notify_test_data{score = 10, name = "Erlang"})))),
-
-
-
- %% Accept events with a serviceUser property of the correct standard type.
- {ok,T7} = ?match({ok, _}, create_filter("$violation(TestData)._repos_id == 'IDL:notify_test/data:1.0'")),
- ?match(true, eval(T7, ?not_CreateSE("DomainName","TypeName",
- "EventName", [],
- [#'CosNotification_Property'
- {name="violation",
- value=any:create(orber_tc:array('CosNotification_Property':tc(),0),
- [#'CosNotification_Property'
- {name="TestData",
- value=any:create(notify_test_data:tc(),
- #notify_test_data
- {score=100,
- name="perfect score"})}])}],
- any:create(orber_tc:null(), null)))),
-
- {ok,T8} = ?match({ok, _}, create_filter("$type_name == 'CommunicationsAlarm' and $event_name == 'lost_packet' and $priority < 2")),
- %% All correct
- Event1 = ?not_CreateSE("DomainName","CommunicationsAlarm",
- "lost_packet",
- [#'CosNotification_Property'{name="priority",
- value=any:create(orber_tc:short(), 1)}],
- [], any:create(orber_tc:null(), null)),
- %% Priority to high
- Event2 = ?not_CreateSE("DomainName","CommunicationsAlarm",
- "lost_packet",
- [#'CosNotification_Property'{name="priority",
- value=any:create(orber_tc:short(), 2)}],
- [], any:create(orber_tc:null(), null)),
- %% Misspell event_name, i.e., lost_packets instead of lost_packet
- Event3 = ?not_CreateSE("DomainName","CommunicationsAlarm",
- "lost_packets",
- [#'CosNotification_Property'{name="priority",
- value=any:create(orber_tc:short(), 1)}],
- [], any:create(orber_tc:null(), null)),
- %% Another type_name
- Event4 = ?not_CreateSE("DomainName","TemperatureAlarm",
- "lost_packets",
- [#'CosNotification_Property'{name="priority",
- value=any:create(orber_tc:short(), 1)}],
- [], any:create(orber_tc:null(), null)),
-
- ?match(true, eval(T8, Event1)),
- ?match(false, eval(T8, Event2)),
- ?match(false, eval(T8, Event3)),
- ?match(false, eval(T8, Event4)),
-
- {ok,T9} = ?match({ok, _}, create_filter("$gpa < 80 or $tests(midterm) > $tests(final) or $monthly_attendance[3] < 10")),
-
- %% midterm > final yields true, the others false
- Event5 = ?not_CreateSE("DomainName","TypeName",
- "EventName", [],
- [#'CosNotification_Property'
- {name="tests",
- value=any:create(orber_tc:array('CosNotification_Property':tc(),0),
- [#'CosNotification_Property'{name="midterm",
- value=any:create(orber_tc:short(), 70)},
- #'CosNotification_Property'{name="final",
- value=any:create(orber_tc:short(), 60)}])},
- #'CosNotification_Property'{name="monthly_attendance",
- value=any:create(orber_tc:array(orber_tc:short(), 0),
- {0,1,2,10})},
- #'CosNotification_Property'{name="gpa",
- value=any:create(orber_tc:short(), 90)}],
- any:create(orber_tc:null(), null)),
-
- %% monthly_attendance[3] < 10 yields true, the others false
- Event6 = ?not_CreateSE("DomainName","TypeName",
- "EventName", [],
- [#'CosNotification_Property'{name="tests",
- value=any:create(orber_tc:array('CosNotification_Property':tc(),0),
- [#'CosNotification_Property'{name="midterm",
- value=any:create(orber_tc:short(), 70)},
- #'CosNotification_Property'{name="final",
- value=any:create(orber_tc:short(), 80)}])},
- #'CosNotification_Property'{name="monthly_attendance",
- value=any:create(orber_tc:array(orber_tc:short(), 0),
- {0,1,2,9})},
- #'CosNotification_Property'{name="gpa",
- value=any:create(orber_tc:short(), 90)}],
- any:create(orber_tc:null(), null)),
-
- %% gpa < 80 true, rest false.
- Event7 = ?not_CreateSE("DomainName","TypeName",
- "EventName", [],
- [#'CosNotification_Property'{name="tests",
- value=any:create(orber_tc:array('CosNotification_Property':tc(),0),
- [#'CosNotification_Property'{name="midterm",
- value=any:create(orber_tc:short(), 70)},
- #'CosNotification_Property'{name="final",
- value=any:create(orber_tc:short(), 80)}])},
- #'CosNotification_Property'{name="monthly_attendance",
- value=any:create(orber_tc:array(orber_tc:short(), 0),
- {0,1,2,10})},
- #'CosNotification_Property'{name="gpa",
- value=any:create(orber_tc:short(), 70)}],
- any:create(orber_tc:null(), null)),
-
- %% All false
- Event8 = ?not_CreateSE("DomainName","TypeName",
- "EventName", [],
- [#'CosNotification_Property'{name="tests",
- value=any:create(orber_tc:array('CosNotification_Property':tc(),0),
- [#'CosNotification_Property'{name="midterm",
- value=any:create(orber_tc:short(), 70)},
- #'CosNotification_Property'{name="final",
- value=any:create(orber_tc:short(), 80)}])},
- #'CosNotification_Property'{name="monthly_attendance",
- value=any:create(orber_tc:array(orber_tc:short(), 0),
- {0,1,2,10})},
- #'CosNotification_Property'{name="gpa",
- value=any:create(orber_tc:short(), 80)}],
- any:create(orber_tc:null(), null)),
-
- ?match(true, eval(T9, Event5)),
- ?match(true, eval(T9, Event6)),
- ?match(true, eval(T9, Event7)),
- ?match(false, eval(T9, Event8)),
- ok.
-
-%%-----------------------------------------------------------------
-%% Misc grammar tests
-%%-----------------------------------------------------------------
-positional_api(_Config) ->
- {ok,T1} = ?match({ok, _}, create_filter("$.3 < 80 or $.1(midterm) > $.1(final) or $.2[3] < 10")),
-
- %% midterm > final yields true, the others false
- Event1 = any:create(notify_test_studies:tc(), #notify_test_studies
- {gpa = 90,
- tests = [#'CosNotification_Property'
- {name="midterm", value=any:create(orber_tc:short(), 70)},
- #'CosNotification_Property'
- {name="final", value=any:create(orber_tc:short(), 60)}],
- monthly_attendance = {0,1,2,10}}),
- %% monthly_attendance[3] < 10 yields true, the others false
- Event2 = any:create(notify_test_studies:tc(), #notify_test_studies
- {gpa = 90,
- tests = [#'CosNotification_Property'
- {name="midterm", value=any:create(orber_tc:short(), 70)},
- #'CosNotification_Property'
- {name="final", value=any:create(orber_tc:short(), 80)}],
- monthly_attendance = {0,1,2,9}}),
- %% gpa < 80 true, rest false.
- Event3 = any:create(notify_test_studies:tc(), #notify_test_studies
- {gpa = 70,
- tests = [#'CosNotification_Property'
- {name="midterm", value=any:create(orber_tc:short(), 70)},
- #'CosNotification_Property'
- {name="final", value=any:create(orber_tc:short(), 80)}],
- monthly_attendance = {0,1,2,10}}),
- %% All false
- Event4 = any:create(notify_test_studies:tc(), #notify_test_studies
- {gpa = 80,
- tests = [#'CosNotification_Property'
- {name="midterm", value=any:create(orber_tc:short(), 70)},
- #'CosNotification_Property'
- {name="final", value=any:create(orber_tc:short(), 80)}],
- monthly_attendance = {0,1,2,10}}),
-
- ?match(true, eval(T1, Event1)),
- ?match(true, eval(T1, Event2)),
- ?match(true, eval(T1, Event3)),
- ?match(false, eval(T1, Event4)),
-
- {ok,T2} = ?match({ok, _}, create_filter("$.0.0.0.1 == 'CommunicationsAlarm'")),
-
- Event5 = ?not_CreateSE("DomainName","CommunicationsAlarm",
- "lost_packet", [], [],
- any:create(orber_tc:null(), null)),
-
- ?match(true, eval(T2, Event5)),
-
- ok.
-
-%%-----------------------------------------------------------------
-%% Components grammar tests
-%%-----------------------------------------------------------------
-components_api(_Config) ->
- {ok,T1} = ?match({ok, _}, create_filter("$ == 2")),
- ?match(true, eval(T1, ?not_CreateSE("DomainName","TypeName","EventName",
- [],[], any:create(orber_tc:short(), 2)))),
- ?match(true, eval(T1, any:create(orber_tc:short(), 2))),
- ?match(false, eval(T1, ?not_CreateSE("DomainName","TypeName","EventName",
- [],[], any:create(orber_tc:short(), 3)))),
- ?match(false, eval(T1, any:create(orber_tc:short(), 3))),
-
- %% Select "MOVIE" events featuring at least 3 of the Marx Brothers.
- {ok,T2} = ?match({ok, _}, create_filter("$type_name == 'MOVIE' and (('groucho' in $.starlist) + ('chico' in $.starlist) + ('harpo' in $.starlist) + ('zeppo' in $.starlist) + ('gummo' in $.starlist)) > 2")),
- ?match(true, eval(T2, ?not_CreateSE("DomainName","MOVIE", "EventName", [], [],
- any:create(orber_tc:alias("IFRId","starlist",tk_any),
- any:create(orber_tc:sequence(orber_tc:string(0),0),
- ["groucho", "harpo", "sam", "gummo"]))))),
- ?match(false, eval(T2, ?not_CreateSE("DomainName","MOVIE", "EventName", [], [],
- any:create(orber_tc:alias("IFRId","starlist",tk_any),
- any:create(orber_tc:sequence(orber_tc:string(0),0),
- ["frodo", "bilbo", "sam", "gummo"]))))),
-
- %% Accept only recent events (e.g., generated within the last 15 minutes or so).
- {ok,_T3} = ?match({ok, _}, create_filter("$origination_timestamp.high + 2 < $curtime.high")),
-
-
- %% Accept students that took all 3 tests and had an average score of at least 80%.
- {ok,T4} = ?match({ok, _}, create_filter("$.test._length == 3 and ($.test[0].score + $.test[1].score + $.test[2].score)/3 >=80")),
- ?match(true, eval(T4, ?not_CreateSE("DomainName","TypeName", "EventName", [], [],
- any:create(orber_tc:alias("IFRId","test",tk_any),
- any:create(orber_tc:array(notify_test_data:tc(),0),
- {#notify_test_data{score=75},
- #notify_test_data{score=80},
- #notify_test_data{score=85}}))))),
- ?match(false, eval(T4, ?not_CreateSE("DomainName","TypeName", "EventName", [], [],
- any:create(orber_tc:alias("IFRId","test",tk_any),
- any:create(orber_tc:array(notify_test_data:tc(),0),
- {#notify_test_data{score=75},
- #notify_test_data{score=80},
- #notify_test_data{score=80}}))))),
- ?match(false, eval(T4, ?not_CreateSE("DomainName","TypeName", "EventName", [], [],
- any:create(orber_tc:alias("IFRId","test",tk_any),
- any:create(orber_tc:array(notify_test_data:tc(),0),
- {#notify_test_data{score=75},
- #notify_test_data{score=80}}))))),
-
- %% Select processes that exceed a certain usage threshold.
- {ok,T5} = ?match({ok, _}, create_filter("$.memsize / 5.5 + $.cputime * 1275.0 + $.filesize * 1.25 > 500000.0")),
- ?match(true, eval(T5, ?not_CreateSE("DomainName","TypeName", "EventName", [], [],
- any:create(notify_test_computer:tc(),
- #notify_test_computer
- {memsize=5.5,
- cputime = 0.00078431137,
- filesize = 500000})))),
- ?match(false, eval(T5, ?not_CreateSE("DomainName","TypeName", "EventName", [], [],
- any:create(notify_test_computer:tc(),
- #notify_test_computer
- {memsize=5.5,
- cputime = 0.00078431137,
- filesize = 500})))),
- ?match({error,_}, eval(T5, ?not_CreateSE("DomainName","TypeName", "EventName", [], [],
- any:create(notify_test_computer:tc(),
- #notify_test_computer
- {memsize=5.5,
- cputime = 0.00078431137})))),
-
- %% Accept only Notification Service structured events.
- {ok,T6} = ?match({ok, _}, create_filter("$._repos_id == 'IDL:omg.org/CosNotification/StructuredEvent:1.0'")),
- ?match(true, eval(T6, ?not_CreateSE("DomainName","CommunicationsAlarm",
- "EventName",
- [], [], any:create(orber_tc:null(), null)))),
-
-
-
- %% Accept only those events that have a specified security "rights list".
- {ok,T7} = ?match({ok, _}, create_filter("exist $.header.variable_header(required_rights)")),
- ?match(false, eval(T7, ?not_CreateSE("DomainName","CommunicationsAlarm",
- "lost_packet",
- [#'CosNotification_Property'{name="priority",
- value=any:create(orber_tc:short(), 1)}],
- [], any:create(orber_tc:null(), null)))),
- ?match(true, eval(T7, ?not_CreateSE("DomainName","CommunicationsAlarm",
- "lost_packet",
- [#'CosNotification_Property'{name="required_rights",
- value=any:create(orber_tc:short(), 1)}],
- [], any:create(orber_tc:null(), null)))),
-
-
- {ok,T8} = ?match({ok, _}, create_filter("$.header.fixed_header.event_type.type_name == 'CommunicationsAlarm' and $.header.fixed_header.event_name == 'lost_packet' and $.header.variable_header(priority) < 2")),
- %% All correct
- Event1 = ?not_CreateSE("DomainName","CommunicationsAlarm",
- "lost_packet",
- [#'CosNotification_Property'{name="priority",
- value=any:create(orber_tc:short(), 1)}],
- [], any:create(orber_tc:null(), null)),
- %% Priority to high
- Event2 = ?not_CreateSE("DomainName","CommunicationsAlarm",
- "lost_packet",
- [#'CosNotification_Property'{name="priority",
- value=any:create(orber_tc:short(), 2)}],
- [], any:create(orber_tc:null(), null)),
- %% Misspell event_name, i.e., lost_packets instead of lost_packet
- Event3 = ?not_CreateSE("DomainName","CommunicationsAlarm",
- "lost_packets",
- [#'CosNotification_Property'{name="priority",
- value=any:create(orber_tc:short(), 1)}],
- [], any:create(orber_tc:null(), null)),
- %% Another type_name
- Event4 = ?not_CreateSE("DomainName","TemperatureAlarm",
- "lost_packets",
- [#'CosNotification_Property'{name="priority",
- value=any:create(orber_tc:short(), 1)}],
- [], any:create(orber_tc:null(), null)),
-
- ?match(true, eval(T8, Event1)),
- ?match(false, eval(T8, Event2)),
- ?match(false, eval(T8, Event3)),
- ?match(false, eval(T8, Event4)),
-
-
- {ok,T9} = ?match({ok, _}, create_filter("$.gpa < 80 or $.tests(midterm) > $.tests(final) or $.monthly_attendance[3] < 10")),
-
- %% midterm > final yields true, the others false
- Event5 = ?not_CreateSE("DomainName","TypeName",
- "EventName", [], [],
- any:create(notify_test_studies:tc(), #notify_test_studies
- {gpa = 90,
- tests = [#'CosNotification_Property'
- {name="midterm", value=any:create(orber_tc:short(), 70)},
- #'CosNotification_Property'
- {name="final", value=any:create(orber_tc:short(), 60)}],
- monthly_attendance = {0,1,2,10}})),
- %% monthly_attendance[3] < 10 yields true, the others false
- Event6 = ?not_CreateSE("DomainName","TypeName",
- "EventName", [], [],
- any:create(notify_test_studies:tc(), #notify_test_studies
- {gpa = 90,
- tests = [#'CosNotification_Property'
- {name="midterm", value=any:create(orber_tc:short(), 70)},
- #'CosNotification_Property'
- {name="final", value=any:create(orber_tc:short(), 80)}],
- monthly_attendance = {0,1,2,9}})),
- %% gpa < 80 true, rest false.
- Event7 = ?not_CreateSE("DomainName","TypeName",
- "EventName", [], [],
- any:create(notify_test_studies:tc(), #notify_test_studies
- {gpa = 70,
- tests = [#'CosNotification_Property'
- {name="midterm", value=any:create(orber_tc:short(), 70)},
- #'CosNotification_Property'
- {name="final", value=any:create(orber_tc:short(), 80)}],
- monthly_attendance = {0,1,2,10}})),
- %% All false
- Event8 = ?not_CreateSE("DomainName","TypeName",
- "EventName", [], [],
- any:create(notify_test_studies:tc(), #notify_test_studies
- {gpa = 80,
- tests = [#'CosNotification_Property'
- {name="midterm", value=any:create(orber_tc:short(), 70)},
- #'CosNotification_Property'
- {name="final", value=any:create(orber_tc:short(), 80)}],
- monthly_attendance = {0,1,2,10}})),
-
- ?match(true, eval(T9, Event5)),
- ?match(true, eval(T9, Event6)),
- ?match(true, eval(T9, Event7)),
- ?match(false, eval(T9, Event8)),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-
-%%-------------------- End of Module ------------------------------
diff --git a/lib/cosNotification/test/notification_SUITE.erl b/lib/cosNotification/test/notification_SUITE.erl
deleted file mode 100644
index 624a76c64a..0000000000
--- a/lib/cosNotification/test/notification_SUITE.erl
+++ /dev/null
@@ -1,2163 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%--------------------------------------------------------------------
-%% File : notification_SUITE.erl
-%% Purpose :
-%%--------------------------------------------------------------------
-
--module(notification_SUITE).
-
-%%--------------- INCLUDES -----------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
-%% cosEvent files.
--include_lib("cosEvent/include/CosEventChannelAdmin.hrl").
-%% Application files
--include_lib("cosNotification/include/CosNotification.hrl").
--include_lib("cosNotification/include/CosNotifyChannelAdmin.hrl").
--include_lib("cosNotification/include/CosNotifyComm.hrl").
--include_lib("cosNotification/include/CosNotifyFilter.hrl").
-
--include_lib("cosNotification/src/CosNotification_Definitions.hrl").
-
--include("idl_output/notify_test.hrl").
-
--include_lib("common_test/include/ct.hrl").
-
-%%--------------- DEFINES ------------------------------------
--define(default_timeout, test_server:minutes(20)).
--define(match(ExpectedRes, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- io:format("------ CORRECT RESULT ------~n~p~n",
- [AcTuAlReS]),
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
--define(defaultQoS,
- [#'CosNotification_Property'{name='CosNotification':'MaximumBatchSize'(),
- value=any:create(orber_tc:long(), 100)},
- #'CosNotification_Property'{name='CosNotification':'PacingInterval'(),
- value=any:create(orber_tc:unsigned_long_long(),
- 20000000)},
- #'CosNotification_Property'{name='CosNotification':'OrderPolicy'(),
- value=any:create(orber_tc:short(),
- 'CosNotification':'AnyOrder'())},
- #'CosNotification_Property'{name='CosNotification':'EventReliability'(),
- value=any:create(orber_tc:short(),
- 'CosNotification':'BestEffort'())},
- #'CosNotification_Property'{name='CosNotification':'ConnectionReliability'(),
- value=any:create(orber_tc:short(),
- 'CosNotification':'BestEffort'())},
- #'CosNotification_Property'{name='CosNotification':'DiscardPolicy'(),
- value=any:create(orber_tc:short(),
- 'CosNotification':'AnyOrder'())},
- #'CosNotification_Property'{name='CosNotification':'StartTimeSupported'(),
- value=any:create(orber_tc:boolean(), false)},
- #'CosNotification_Property'{name='CosNotification':'StopTimeSupported'(),
- value=any:create(orber_tc:boolean(), false)},
- #'CosNotification_Property'{name='CosNotification':'Priority'(),
- value=any:create(orber_tc:short(),
- 'CosNotification':'DefaultPriority'())}]).
--define(defaultQoS2,
- [#'CosNotification_Property'{name='CosNotification':'MaximumBatchSize'(),
- value=any:create(orber_tc:long(), 1)},
- #'CosNotification_Property'{name='CosNotification':'PacingInterval'(),
- value=any:create(orber_tc:unsigned_long_long(),
- 0)},
- #'CosNotification_Property'{name='CosNotification':'OrderPolicy'(),
- value=any:create(orber_tc:short(),
- 'CosNotification':'AnyOrder'())},
- #'CosNotification_Property'{name='CosNotification':'EventReliability'(),
- value=any:create(orber_tc:short(),
- 'CosNotification':'BestEffort'())},
- #'CosNotification_Property'{name='CosNotification':'ConnectionReliability'(),
- value=any:create(orber_tc:short(),
- 'CosNotification':'BestEffort'())},
- #'CosNotification_Property'{name='CosNotification':'DiscardPolicy'(),
- value=any:create(orber_tc:short(),
- 'CosNotification':'AnyOrder'())},
- #'CosNotification_Property'{name='CosNotification':'StartTimeSupported'(),
- value=any:create(orber_tc:boolean(), false)},
- #'CosNotification_Property'{name='CosNotification':'StopTimeSupported'(),
- value=any:create(orber_tc:boolean(), false)},
- #'CosNotification_Property'{name='CosNotification':'Priority'(),
- value=any:create(orber_tc:short(),
- 'CosNotification':'DefaultPriority'())}]).
--define(defaultAdm,
- [#'CosNotification_Property'{name='CosNotification':'MaxQueueLength'(),
- value=any:create(orber_tc:long(), 100)},
- #'CosNotification_Property'{name='CosNotification':'MaxConsumers'(),
- value=any:create(orber_tc:long(), 100)},
- #'CosNotification_Property'{name='CosNotification':'MaxSuppliers'(),
- value=any:create(orber_tc:long(), 100)}]).
-
--define(FAC_OPT, []).
-
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2, cases/0,
- init_per_suite/1, end_per_suite/1, qos_api/1, adm_api/1,
- cosevent_api/1, filter_adm_api/1, events_api/1, events2_api/1,
- event_qos_api/1, filter_api/1, mapping_filter_api/1, subscription_api/1,
- init_per_testcase/2, end_per_testcase/2, persistent_max_events_api/1,
- persistent_timeout_events_api/1, persistent_recover_events_api/1,
- app_test/1]).
-
--export([terminated/1]).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- cases().
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-cases() ->
- [persistent_max_events_api,
- persistent_timeout_events_api,
- persistent_recover_events_api, mapping_filter_api,
- filter_api, filter_adm_api, event_qos_api, qos_api,
- adm_api, cosevent_api, subscription_api, events_api,
- events2_api, app_test].
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-init_per_testcase(_Case, Config) ->
- Path = code:which(?MODULE),
- code:add_pathz(filename:join(filename:dirname(Path), "idl_output")),
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-end_per_testcase(_Case, Config) ->
- Path = code:which(?MODULE),
- code:del_path(filename:join(filename:dirname(Path), "idl_output")),
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-init_per_suite(Config) ->
- Path = code:which(?MODULE),
- code:add_pathz(filename:join(filename:dirname(Path), "idl_output")),
- ok = corba:orb_init([{flags, 16#02}, {orber_debug_level, 10}]),
- orber:jump_start(),
- cosNotificationApp:install_event(),
- cosNotificationApp:install(),
- 'oe_notify_test_server':'oe_register'(),
- cosNotificationApp:start(),
- if
- is_list(Config) ->
- Config;
- true ->
- exit("Config not a list")
- end.
-
-end_per_suite(Config) ->
- cosNotificationApp:stop(),
- Path = code:which(?MODULE),
- code:del_path(filename:join(filename:dirname(Path), "idl_output")),
- 'oe_notify_test_server':'oe_unregister'(),
- cosNotificationApp:uninstall(),
- cosNotificationApp:uninstall_event(),
- orber:jump_stop(),
- Config.
-
-
-%%-----------------------------------------------------------------
-%% Tests app file
-%%-----------------------------------------------------------------
-app_test(_Config) ->
- ok=test_server:app_test(cosNotification),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Persistent events max limit
-%%-----------------------------------------------------------------
-persistent_max_events_api(_Config) ->
- QoSPersistent =
- [#'CosNotification_Property'{name='CosNotification':'ConnectionReliability'(),
- value=any:create(orber_tc:short(),
- 'CosNotification':'Persistent'())}],
- QoSEventPersistent =
- [#'CosNotification_Property'{name='CosNotification':'EventReliability'(),
- value=any:create(orber_tc:short(),
- 'CosNotification':'Persistent'())}],
- application:set_env(cosNotification, notify, ?MODULE),
- application:set_env(cosNotification, max_events, 2),
- application:set_env(cosNotification, timeout_events, 300000),
- application:set_env(cosNotification, interval_events, 10000),
- %% Initialize the application.
- Fac = (catch cosNotificationApp:start_global_factory(?FAC_OPT)),
- ?match({_,key,_,_,_,_}, Fac),
- {Ch, _Id1} = (catch 'CosNotifyChannelAdmin_EventChannelFactory':create_channel(Fac, ?defaultQoS2, ?defaultAdm)),
- ?match({_,key,_,_,_,_}, Ch),
-
- ?match(ok, 'CosNotification_QoSAdmin':set_qos(Ch, QoSEventPersistent)),
- ?match(ok, 'CosNotification_QoSAdmin':set_qos(Ch, QoSPersistent)),
-
- %% Create the Admin objects
- {AdminSupplier, _ASID}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_EventChannel':new_for_suppliers(Ch,'AND_OP')),
- {AdminConsumer, _ACID}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_EventChannel':new_for_consumers(Ch,'AND_OP')),
-
- %% Create Proxies and clients
- {SequenceProxyPushSupplier,_ID}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_ConsumerAdmin':obtain_notification_push_supplier(AdminConsumer, 'SEQUENCE_EVENT')),
- PushSeqC=?match({_,key,_,_,_,_}, 'notify_test_SeqPushC':oe_create(['PUSH_SEQUENCE',SequenceProxyPushSupplier],
- [{local_typecheck, false}])),
- ?match(ok, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':connect_sequence_push_consumer(SequenceProxyPushSupplier, PushSeqC)),
-
- {SequenceProxyPushConsumer,_ID}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_SupplierAdmin':obtain_notification_push_consumer(AdminSupplier, 'SEQUENCE_EVENT')),
- PushSeqS=?match({_,key,_,_,_,_}, 'notify_test_SeqPushS':oe_create(['PUSH_SEQUENCE',SequenceProxyPushConsumer],
- [{local_typecheck, false}])),
- ?match(ok, 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':connect_sequence_push_supplier(SequenceProxyPushConsumer, PushSeqS)),
-
- %% Create a couple of Events to test with.
- Event = ?not_CreateSE("DomainName","CommunicationsAlarm",
- "lost_packet",
- [#'CosNotification_Property'{name="priority",
- value=any:create(orber_tc:short(), 1)}],
- [], any:create(orber_tc:null(), null)),
-
- ?match(ok, 'notify_test_SeqPushC':doAction(PushSeqC, {action, action})),
-
- %% Push and check the state.
- ?match(ok,'CosNotifyChannelAdmin_SequenceProxyPushConsumer':push_structured_events(SequenceProxyPushConsumer, [Event])),
- ?match([], 'notify_test_SeqPushC':doAction(PushSeqC, return_data)),
- ?match(false, corba_object:non_existent(SequenceProxyPushSupplier)),
-
- ?match(ok,'CosNotifyChannelAdmin_SequenceProxyPushConsumer':push_structured_events(SequenceProxyPushConsumer, [Event])),
- ?match([], 'notify_test_SeqPushC':doAction(PushSeqC, return_data)),
- ?match(false, corba_object:non_existent(SequenceProxyPushSupplier)),
- %% Now we've reached the limit. This call will terminate the proxy.
- %% We cannot check for data at this point since the broken connection
- %% will result in that the client terminates.
- ?match(ok,'CosNotifyChannelAdmin_SequenceProxyPushConsumer':push_structured_events(SequenceProxyPushConsumer, [Event])),
- timer:sleep(5000),
- ?match(true, corba_object:non_existent(SequenceProxyPushSupplier)),
- ?match(true, corba_object:non_existent(PushSeqC)),
-
-
- catch corba:dispose(SequenceProxyPushConsumer),
- catch corba:dispose(SequenceProxyPushSupplier),
- catch corba:dispose(AdminConsumer),
- catch corba:dispose(AdminSupplier),
- catch corba:dispose(Ch),
- catch cosNotificationApp:stop_factory(Fac),
- catch corba:dispose(PushSeqS),
- catch corba:dispose(PushSeqC),
- application:set_env(cosNotification, notify, undefined),
- application:set_env(cosNotification, max_events, undefined),
- application:set_env(cosNotification, timeout_events, undefined),
- application:set_env(cosNotification, interval_events, undefined),
- ok.
-
-terminated(Items) ->
- io:format("Proxy terminated due to: ~p~n", [Items]).
-
-%%-----------------------------------------------------------------
-%% Persistent events timeout
-%%-----------------------------------------------------------------
-persistent_timeout_events_api(_Config) ->
- QoSPersistent =
- [#'CosNotification_Property'{name='CosNotification':'ConnectionReliability'(),
- value=any:create(orber_tc:short(),
- 'CosNotification':'Persistent'())}],
- QoSEventPersistent =
- [#'CosNotification_Property'{name='CosNotification':'EventReliability'(),
- value=any:create(orber_tc:short(),
- 'CosNotification':'Persistent'())}],
- application:set_env(cosNotification, notify, ?MODULE),
- application:set_env(cosNotification, max_events, 1000),
- application:set_env(cosNotification, timeout_events, 4000),
- application:set_env(cosNotification, interval_events, 1000),
- %% Initialize the application.
- Fac = (catch cosNotificationApp:start_global_factory(?FAC_OPT)),
- ?match({_,key,_,_,_,_}, Fac),
- {Ch, _Id1} = (catch 'CosNotifyChannelAdmin_EventChannelFactory':create_channel(Fac, ?defaultQoS2, ?defaultAdm)),
- ?match({_,key,_,_,_,_}, Ch),
-
- ?match(ok, 'CosNotification_QoSAdmin':set_qos(Ch, QoSEventPersistent)),
- ?match(ok, 'CosNotification_QoSAdmin':set_qos(Ch, QoSPersistent)),
-
- %% Create the Admin objects
- {AdminSupplier, _ASID}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_EventChannel':new_for_suppliers(Ch,'AND_OP')),
- {AdminConsumer, _ACID}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_EventChannel':new_for_consumers(Ch,'AND_OP')),
-
- %% Create Proxies and clients
- {SequenceProxyPushSupplier,_ID}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_ConsumerAdmin':obtain_notification_push_supplier(AdminConsumer, 'SEQUENCE_EVENT')),
- PushSeqC=?match({_,key,_,_,_,_}, 'notify_test_SeqPushC':oe_create(['PUSH_SEQUENCE',SequenceProxyPushSupplier],
- [{local_typecheck, false}])),
- ?match(ok, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':connect_sequence_push_consumer(SequenceProxyPushSupplier, PushSeqC)),
-
- {SequenceProxyPushConsumer,_ID}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_SupplierAdmin':obtain_notification_push_consumer(AdminSupplier, 'SEQUENCE_EVENT')),
- PushSeqS=?match({_,key,_,_,_,_}, 'notify_test_SeqPushS':oe_create(['PUSH_SEQUENCE',SequenceProxyPushConsumer],
- [{local_typecheck, false}])),
- ?match(ok, 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':connect_sequence_push_supplier(SequenceProxyPushConsumer, PushSeqS)),
-
- %% Create a couple of Events to test with.
- Event = ?not_CreateSE("DomainName","CommunicationsAlarm",
- "lost_packet",
- [#'CosNotification_Property'{name="priority",
- value=any:create(orber_tc:short(), 1)}],
- [], any:create(orber_tc:null(), null)),
-
- ?match(ok, 'notify_test_SeqPushC':doAction(PushSeqC, {action, action})),
-
- %% Push and check the state.
- ?match(ok,'CosNotifyChannelAdmin_SequenceProxyPushConsumer':push_structured_events(SequenceProxyPushConsumer, [Event])),
- ?match([], 'notify_test_SeqPushC':doAction(PushSeqC, return_data)),
- ?match(false, corba_object:non_existent(SequenceProxyPushSupplier)),
-
- %% Now we've reached the limit. This call will terminate the proxy.
- %% We cannot check for data at this point since the broken connection
- %% will result in that the client terminates.
- ?match(ok,'CosNotifyChannelAdmin_SequenceProxyPushConsumer':push_structured_events(SequenceProxyPushConsumer, [Event])),
- timer:sleep(10000),
- ?match(true, corba_object:non_existent(SequenceProxyPushSupplier)),
- ?match(true, corba_object:non_existent(PushSeqC)),
-
-
- catch corba:dispose(SequenceProxyPushConsumer),
- catch corba:dispose(SequenceProxyPushSupplier),
- catch corba:dispose(AdminConsumer),
- catch corba:dispose(AdminSupplier),
- catch corba:dispose(Ch),
- catch cosNotificationApp:stop_factory(Fac),
- catch corba:dispose(PushSeqS),
- catch corba:dispose(PushSeqC),
- application:set_env(cosNotification, notify, undefined),
- application:set_env(cosNotification, max_events, undefined),
- application:set_env(cosNotification, timeout_events, undefined),
- application:set_env(cosNotification, interval_events, undefined),
- ok.
-
-%%-----------------------------------------------------------------
-%% Persistent events max limit
-%%-----------------------------------------------------------------
-persistent_recover_events_api(_Config) ->
- QoSPersistent =
- [#'CosNotification_Property'{name='CosNotification':'ConnectionReliability'(),
- value=any:create(orber_tc:short(),
- 'CosNotification':'Persistent'())}],
- QoSEventPersistent =
- [#'CosNotification_Property'{name='CosNotification':'EventReliability'(),
- value=any:create(orber_tc:short(),
- 'CosNotification':'Persistent'())}],
- application:set_env(cosNotification, notify, ?MODULE),
- application:set_env(cosNotification, max_events, 1000),
- application:set_env(cosNotification, timeout_events, 100000),
- application:set_env(cosNotification, interval_events, 1000),
- %% Initialize the application.
- Fac = (catch cosNotificationApp:start_global_factory(?FAC_OPT)),
- ?match({_,key,_,_,_,_}, Fac),
- {Ch, _Id1} = (catch 'CosNotifyChannelAdmin_EventChannelFactory':create_channel(Fac, ?defaultQoS2, ?defaultAdm)),
- ?match({_,key,_,_,_,_}, Ch),
-
- ?match(ok, 'CosNotification_QoSAdmin':set_qos(Ch, QoSEventPersistent)),
- ?match(ok, 'CosNotification_QoSAdmin':set_qos(Ch, QoSPersistent)),
-
- %% Create the Admin objects
- {AdminSupplier, _ASID}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_EventChannel':new_for_suppliers(Ch,'AND_OP')),
- {AdminConsumer, _ACID}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_EventChannel':new_for_consumers(Ch,'AND_OP')),
-
- %% Create Proxies and clients
- {SequenceProxyPushSupplier,_ID}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_ConsumerAdmin':obtain_notification_push_supplier(AdminConsumer, 'SEQUENCE_EVENT')),
- PushSeqC=?match({_,key,_,_,_,_}, 'notify_test_SeqPushC':oe_create(['PUSH_SEQUENCE',SequenceProxyPushSupplier],
- [{local_typecheck, false}])),
- ?match(ok, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':connect_sequence_push_consumer(SequenceProxyPushSupplier, PushSeqC)),
-
- {SequenceProxyPushConsumer,_ID}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_SupplierAdmin':obtain_notification_push_consumer(AdminSupplier, 'SEQUENCE_EVENT')),
- PushSeqS=?match({_,key,_,_,_,_}, 'notify_test_SeqPushS':oe_create(['PUSH_SEQUENCE',SequenceProxyPushConsumer],
- [{local_typecheck, false}])),
- ?match(ok, 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':connect_sequence_push_supplier(SequenceProxyPushConsumer, PushSeqS)),
-
- %% Create a couple of Events to test with.
- Event = ?not_CreateSE("DomainName","CommunicationsAlarm",
- "lost_packet",
- [#'CosNotification_Property'{name="priority",
- value=any:create(orber_tc:short(), 1)}],
- [], any:create(orber_tc:null(), null)),
-
- ?match(ok, 'notify_test_SeqPushC':doAction(PushSeqC, {action, action})),
-
- %% Push and check the state.
- ?match(ok,'CosNotifyChannelAdmin_SequenceProxyPushConsumer':push_structured_events(SequenceProxyPushConsumer, [Event])),
- ?match([], 'notify_test_SeqPushC':doAction(PushSeqC, return_data)),
- ?match(false, corba_object:non_existent(SequenceProxyPushSupplier)),
- %% Allow the proxy to try a few times and then change the client behavior
- timer:sleep(4000),
- ?match(ok, 'notify_test_SeqPushC':doAction(PushSeqC, {action, undefined})),
- %% Wait some time so that the proxy timeout has kicked in.
- timer:sleep(4000),
-
- %% Now the communication should work again.
- ?match([Event], 'notify_test_SeqPushC':doAction(PushSeqC, return_data)),
- ?match(false, corba_object:non_existent(SequenceProxyPushSupplier)),
-
- ?match(ok,'CosNotifyChannelAdmin_SequenceProxyPushConsumer':push_structured_events(SequenceProxyPushConsumer, [Event])),
- timer:sleep(4000),
- ?match([Event], 'notify_test_SeqPushC':doAction(PushSeqC, return_data)),
-
- catch corba:dispose(SequenceProxyPushConsumer),
- catch corba:dispose(SequenceProxyPushSupplier),
- catch corba:dispose(AdminConsumer),
- catch corba:dispose(AdminSupplier),
- catch corba:dispose(Ch),
- catch cosNotificationApp:stop_factory(Fac),
- catch corba:dispose(PushSeqS),
- catch corba:dispose(PushSeqC),
- application:set_env(cosNotification, notify, undefined),
- application:set_env(cosNotification, max_events, undefined),
- application:set_env(cosNotification, timeout_events, undefined),
- application:set_env(cosNotification, interval_events, undefined),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% CosNotifyFilter::Filter API tests
-%%-----------------------------------------------------------------
-mapping_filter_api(_Config) ->
- FiFac = 'CosNotifyFilter_FilterFactory':oe_create(),
- ?match({_,key,_,_,_,_}, FiFac),
-
- Filter = 'CosNotifyFilter_FilterFactory':create_mapping_filter(FiFac,
- "EXTENDED_TCL",
- any:create(orber_tc:short(), 10)),
- ?match({_,key,_,_,_,_}, Filter),
-
- ?match("EXTENDED_TCL", 'CosNotifyFilter_MappingFilter':'_get_constraint_grammar'(Filter)),
-
- %% Test before we add any constarints.
- ?match([], 'CosNotifyFilter_MappingFilter':get_all_mapping_constraints(Filter)),
- ?match({'EXCEPTION', {'CosNotifyFilter_ConstraintNotFound', _, 1}},
- 'CosNotifyFilter_MappingFilter':get_mapping_constraints(Filter, [1])),
- ?match(ok, 'CosNotifyFilter_MappingFilter':remove_all_mapping_constraints(Filter)),
-
- %% Try adding an incorrect constraint_expr
- ?match({'EXCEPTION',{'CosNotifyFilter_InvalidConstraint',_,_}},
- 'CosNotifyFilter_MappingFilter':add_mapping_constraints(Filter,
- [#'CosNotifyFilter_MappingConstraintPair'
- {constraint_expression = #'CosNotifyFilter_ConstraintExp'
- {event_types = [#'CosNotification_EventType'
- {domain_name = "name",
- type_name = "type"}],
- constraint_expr = "2==2 and 3<"},
- result_to_set = any:create(orber_tc:short(), 10)}])),
- %% Try adding two correct constraint_expr
- [{_,_,CID1,_},{_,_,CID2,_}]=
- ?match([{'CosNotifyFilter_MappingConstraintInfo',_,_,_}, {'CosNotifyFilter_MappingConstraintInfo',_,_,_}],
- 'CosNotifyFilter_MappingFilter':add_mapping_constraints(Filter,
- [#'CosNotifyFilter_MappingConstraintPair'
- {constraint_expression = #'CosNotifyFilter_ConstraintExp'
- {event_types = [#'CosNotification_EventType'
- {domain_name = "name",
- type_name = "type"}],
- constraint_expr = "2==2 and 3<4"},
- result_to_set = any:create(orber_tc:short(), 10)},
- #'CosNotifyFilter_MappingConstraintPair'
- {constraint_expression = #'CosNotifyFilter_ConstraintExp'
- {event_types = [#'CosNotification_EventType'
- {domain_name = "name2",
- type_name = "type2"}],
- constraint_expr = "$.test._length == 3 and ($.test[0].score + $.test[1].score + $.test[2].score)/3 >=80"},
- result_to_set = any:create(orber_tc:short(), 10)}])),
-
- ?match([{'CosNotifyFilter_MappingConstraintInfo',_,CID2,_}, {'CosNotifyFilter_MappingConstraintInfo',_,CID1,_}],
- 'CosNotifyFilter_MappingFilter':get_all_mapping_constraints(Filter)),
- ?match([{'CosNotifyFilter_MappingConstraintInfo',_,CID1,_}],
- 'CosNotifyFilter_MappingFilter':get_mapping_constraints(Filter, [CID1])),
- ?match(ok, 'CosNotifyFilter_MappingFilter':remove_all_mapping_constraints(Filter)),
- ?match([], 'CosNotifyFilter_MappingFilter':get_all_mapping_constraints(Filter)),
-
- %% Try adding a constraint_expr with using invalid value, i.e., not short.
- ?match({'EXCEPTION',{'CosNotifyFilter_InvalidValue',_,_,_}},
- 'CosNotifyFilter_MappingFilter':add_mapping_constraints(Filter,
- [#'CosNotifyFilter_MappingConstraintPair'
- {constraint_expression = #'CosNotifyFilter_ConstraintExp'
- {event_types = [#'CosNotification_EventType'
- {domain_name = "name",
- type_name = "type"}],
- constraint_expr = "2==2 and 3<8"},
- result_to_set = any:create(orber_tc:long(), 10)}])),
-
- %% Try adding one correct and one incorrect constraint_expr
- ?match({'EXCEPTION',{'CosNotifyFilter_InvalidConstraint',_,_}},
- 'CosNotifyFilter_MappingFilter':add_mapping_constraints(Filter,
- [#'CosNotifyFilter_MappingConstraintPair'
- {constraint_expression = #'CosNotifyFilter_ConstraintExp'
- {event_types = [#'CosNotification_EventType'
- {domain_name = "name",
- type_name = "type"}],
- constraint_expr = "2==2 and 3<"},
- result_to_set = any:create(orber_tc:short(), 10)},
- #'CosNotifyFilter_MappingConstraintPair'
- {constraint_expression = #'CosNotifyFilter_ConstraintExp'
- {event_types = [#'CosNotification_EventType'
- {domain_name = "name2",
- type_name = "type2"}],
- constraint_expr = "$.test._length == 3 and ($.test[0].score + $.test[1].score + $.test[2].score)/3 >=80"},
- result_to_set = any:create(orber_tc:short(), 10)}])),
-
- %% Following testcases test different domain_name and type_name, e.g.,
- %% wildcards etc.
- [{_,ConInfoData,CID3,_}] =
- ?match([{'CosNotifyFilter_MappingConstraintInfo',_,_,_}],
- 'CosNotifyFilter_MappingFilter':add_mapping_constraints(Filter,
- [#'CosNotifyFilter_MappingConstraintPair'
- {constraint_expression = #'CosNotifyFilter_ConstraintExp'
- {event_types = [#'CosNotification_EventType'
- {domain_name = "domain",
- type_name = ""},
- #'CosNotification_EventType'
- {domain_name = "*",
- type_name = "type"}],
- constraint_expr = "2==2 and 3<4"},
- result_to_set = any:create(orber_tc:short(), 10)}])),
-
- %% Try removing a constraint
- ?match(ok, 'CosNotifyFilter_MappingFilter':modify_mapping_constraints(Filter,[CID3],[])),
- ?match([], 'CosNotifyFilter_MappingFilter':get_all_mapping_constraints(Filter)),
-
- %% Add e new constraint
- [{_,_,CID4,_}] =
- ?match([{'CosNotifyFilter_MappingConstraintInfo',_,_,_}],
- 'CosNotifyFilter_MappingFilter':add_mapping_constraints(Filter,
- [#'CosNotifyFilter_MappingConstraintPair'
- {constraint_expression = #'CosNotifyFilter_ConstraintExp'
- {event_types = [#'CosNotification_EventType'
- {domain_name = "domain1",
- type_name = ""},
- #'CosNotification_EventType'
- {domain_name = "domain2",
- type_name = "*"}],
- constraint_expr = "2==2 and 3<4"},
- result_to_set = any:create(orber_tc:short(), 10)}])),
-
- %% Try to update the constraint associated with CID4 to equal CID3.
- ?match(ok, 'CosNotifyFilter_MappingFilter':modify_mapping_constraints(Filter,[],
- [#'CosNotifyFilter_MappingConstraintInfo'
- {constraint_expression=
- #'CosNotifyFilter_ConstraintExp'
- {event_types =[#'CosNotification_EventType'
- {domain_name = "domain",
- type_name = ""},
- #'CosNotification_EventType'
- {domain_name = "*",
- type_name = "type"}],
- constraint_expr = "2==2 and 3<4"},
- constraint_id=CID4,
- value = any:create(orber_tc:short(), 10)}])),
-
- ?match([{_,ConInfoData,CID4,_}], 'CosNotifyFilter_MappingFilter':get_all_mapping_constraints(Filter)),
-
- ?match({'EXCEPTION', {'CosNotifyFilter_ConstraintNotFound', _, CID3}},
- 'CosNotifyFilter_MappingFilter':get_mapping_constraints(Filter, [CID3])),
- ?match(ok, 'CosNotifyFilter_MappingFilter':remove_all_mapping_constraints(Filter)),
- ?match([], 'CosNotifyFilter_MappingFilter':get_all_mapping_constraints(Filter)),
-
- ?match([{'CosNotifyFilter_MappingConstraintInfo',_,_,_}],
- 'CosNotifyFilter_MappingFilter':add_mapping_constraints(Filter,
- [#'CosNotifyFilter_MappingConstraintPair'
- {constraint_expression = #'CosNotifyFilter_ConstraintExp'
- {event_types = [#'CosNotification_EventType'
- {domain_name = "",
- type_name = "type1"},
- #'CosNotification_EventType'
- {domain_name = "*",
- type_name = "type2"}],
- constraint_expr = "2==2 and 3<4"},
- result_to_set = any:create(orber_tc:short(), 10)}])),
-
- ?match([{'CosNotifyFilter_MappingConstraintInfo',_,_,_}],
- 'CosNotifyFilter_MappingFilter':add_mapping_constraints(Filter,
- [#'CosNotifyFilter_MappingConstraintPair'
- {constraint_expression = #'CosNotifyFilter_ConstraintExp'
- {event_types = [#'CosNotification_EventType'
- {domain_name = "domain1",
- type_name = "type1"},
- #'CosNotification_EventType'
- {domain_name = "domain2",
- type_name = "type2"}],
- constraint_expr = "2==2 and 3<4"},
- result_to_set = any:create(orber_tc:short(), 10)}])),
-
- ?match([{'CosNotifyFilter_MappingConstraintInfo',_,_,_}],
- 'CosNotifyFilter_MappingFilter':add_mapping_constraints(Filter,
- [#'CosNotifyFilter_MappingConstraintPair'
- {constraint_expression = #'CosNotifyFilter_ConstraintExp'
- {event_types = [#'CosNotification_EventType'
- {domain_name = "dom*",
- type_name = "type1"},
- #'CosNotification_EventType'
- {domain_name = "domain2",
- type_name = "typ*"}],
- constraint_expr = "2==2 and 3<4"},
- result_to_set = any:create(orber_tc:short(), 10)}])),
-
- ?match([{'CosNotifyFilter_MappingConstraintInfo',_,_,_}],
- 'CosNotifyFilter_MappingFilter':add_mapping_constraints(Filter,
- [#'CosNotifyFilter_MappingConstraintPair'
- {constraint_expression = #'CosNotifyFilter_ConstraintExp'
- {event_types = [#'CosNotification_EventType'
- {domain_name = "dom*1",
- type_name = "type1"},
- #'CosNotification_EventType'
- {domain_name = "domain2",
- type_name = "typ*2"}],
- constraint_expr = "2==2 and 3<4"},
- result_to_set = any:create(orber_tc:short(), 10)}])),
-
- catch corba:dispose(FiFac),
- catch corba:dispose(Filter),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% CosNotifyFilter::Filter API tests
-%%-----------------------------------------------------------------
-filter_api(_Config) ->
- Fac = cosNotificationApp:start_global_factory(?FAC_OPT),
- ?match({_,key,_,_,_,_}, Fac),
- {Ch, _Id1} = 'CosNotifyChannelAdmin_EventChannelFactory':create_channel(Fac, ?defaultQoS, ?defaultAdm),
- AC= 'CosNotifyChannelAdmin_EventChannel':for_consumers(Ch),
-
- FiFac = 'CosNotifyFilter_FilterFactory':oe_create(),
- ?match({_,key,_,_,_,_}, FiFac),
-
- Filter = 'CosNotifyFilter_FilterFactory':create_filter(FiFac,"EXTENDED_TCL"),
- ?match({_,key,_,_,_,_}, Filter),
-
- ?match("EXTENDED_TCL", 'CosNotifyFilter_Filter':'_get_constraint_grammar'(Filter)),
-
- %% Test Callback management.
- ?match({'EXCEPTION',{'BAD_PARAM',_,_,_}},
- 'CosNotifyFilter_Filter':attach_callback(Filter, Ch)),
- ?match([], 'CosNotifyFilter_Filter':get_callbacks(Filter)),
- ?match({'EXCEPTION',{'CosNotifyFilter_CallbackNotFound',_}},
- 'CosNotifyFilter_Filter':detach_callback(Filter, 0)),
- ID='CosNotifyFilter_Filter':attach_callback(Filter, AC),
- ?match([ID], 'CosNotifyFilter_Filter':get_callbacks(Filter)),
- ?match(ok, 'CosNotifyFilter_Filter':detach_callback(Filter, ID)),
- ?match([], 'CosNotifyFilter_Filter':get_callbacks(Filter)),
-
- %% This callback is just attached so we can test that we can call notify_subscribe.
- _ID2='CosNotifyFilter_Filter':attach_callback(Filter, AC),
-
- %% Test before we add any constarints.
- ?match([], 'CosNotifyFilter_Filter':get_all_constraints(Filter)),
- ?match({'EXCEPTION', {'CosNotifyFilter_ConstraintNotFound', _, 1}},
- 'CosNotifyFilter_Filter':get_constraints(Filter, [1])),
- ?match(ok, 'CosNotifyFilter_Filter':remove_all_constraints(Filter)),
-
- %% Try adding an incorrect constraint_expr
- ?match({'EXCEPTION',{'CosNotifyFilter_InvalidConstraint',_,_}},
- 'CosNotifyFilter_Filter':add_constraints(Filter,
- [#'CosNotifyFilter_ConstraintExp'{event_types =
- [#'CosNotification_EventType'{
- domain_name = "name",
- type_name = "type"}],
- constraint_expr = "2==2 and 3<"}])),
- %% Try adding two correct constraint_expr
- [{_,_,CID1},{_,_,CID2}]=
- ?match([{'CosNotifyFilter_ConstraintInfo',_,_}, {'CosNotifyFilter_ConstraintInfo',_,_}],
- 'CosNotifyFilter_Filter':add_constraints(Filter,
- [#'CosNotifyFilter_ConstraintExp'{event_types =
- [#'CosNotification_EventType'{
- domain_name = "name",
- type_name = "type"}],
- constraint_expr = "2==2 and 3<4"},
- #'CosNotifyFilter_ConstraintExp'{event_types =
- [#'CosNotification_EventType'{
- domain_name = "name2",
- type_name = "type2"}],
- constraint_expr = "$.test._length == 3 and ($.test[0].score + $.test[1].score + $.test[2].score)/3 >=80"}])),
-
- ?match([{'CosNotifyFilter_ConstraintInfo',_,CID2}, {'CosNotifyFilter_ConstraintInfo',_,CID1}],
- 'CosNotifyFilter_Filter':get_all_constraints(Filter)),
- ?match([{'CosNotifyFilter_ConstraintInfo',_,CID1}],
- 'CosNotifyFilter_Filter':get_constraints(Filter, [CID1])),
- ?match(ok, 'CosNotifyFilter_Filter':remove_all_constraints(Filter)),
- ?match([], 'CosNotifyFilter_Filter':get_all_constraints(Filter)),
-
- %% Try adding one correct and one incorrect constraint_expr
- ?match({'EXCEPTION',{'CosNotifyFilter_InvalidConstraint',_,_}},
- 'CosNotifyFilter_Filter':add_constraints(Filter,
- [#'CosNotifyFilter_ConstraintExp'{event_types =
- [#'CosNotification_EventType'{
- domain_name = "name",
- type_name = "type"}],
- constraint_expr = "2==2 and 3<"},
- #'CosNotifyFilter_ConstraintExp'{event_types =
- [#'CosNotification_EventType'{
- domain_name = "name2",
- type_name = "type2"}],
- constraint_expr = "$.test._length == 3 and ($.test[0].score + $.test[1].score + $.test[2].score)/3 >=80"}])),
-
- %% Following testcases test different domain_name and type_name, e.g.,
- %% wildcards etc.
- [{_,ConInfoData,CID3}] =
- ?match([{'CosNotifyFilter_ConstraintInfo',_,_}],
- 'CosNotifyFilter_Filter':add_constraints(Filter,
- [#'CosNotifyFilter_ConstraintExp'{event_types =
- [#'CosNotification_EventType'{
- domain_name = "domain",
- type_name = ""},
- #'CosNotification_EventType'{
- domain_name = "*",
- type_name = "type"}],
- constraint_expr = "2==2 and 3<4"}])),
-
- %% Try removing a constraint
- ?match(ok, 'CosNotifyFilter_Filter':modify_constraints(Filter,[CID3],[])),
- ?match([], 'CosNotifyFilter_Filter':get_all_constraints(Filter)),
-
- %% Add e new constraint
- [{_,_,CID4}] =
- ?match([{'CosNotifyFilter_ConstraintInfo',_,_}],
- 'CosNotifyFilter_Filter':add_constraints(Filter,
- [#'CosNotifyFilter_ConstraintExp'{event_types =
- [#'CosNotification_EventType'{
- domain_name = "domain1",
- type_name = ""},
- #'CosNotification_EventType'{
- domain_name = "domain2",
- type_name = "*"}],
- constraint_expr = "2==2 and 3<4"}])),
-
- %% Try to update the constraint associated with CID4 to equal CID3.
- ?match(ok, 'CosNotifyFilter_Filter':modify_constraints(Filter,[],
- [#'CosNotifyFilter_ConstraintInfo'{constraint_expression=
- #'CosNotifyFilter_ConstraintExp'{event_types =
- [#'CosNotification_EventType'{
- domain_name = "domain",
- type_name = ""},
- #'CosNotification_EventType'{
- domain_name = "*",
- type_name = "type"}],
- constraint_expr = "2==2 and 3<4"},
- constraint_id=CID4}])),
-
- ?match([{_,ConInfoData,CID4}], 'CosNotifyFilter_Filter':get_all_constraints(Filter)),
-
- ?match({'EXCEPTION', {'CosNotifyFilter_ConstraintNotFound', _, CID3}},
- 'CosNotifyFilter_Filter':get_constraints(Filter, [CID3])),
- ?match(ok, 'CosNotifyFilter_Filter':remove_all_constraints(Filter)),
- ?match([], 'CosNotifyFilter_Filter':get_all_constraints(Filter)),
-
- ?match([{'CosNotifyFilter_ConstraintInfo',_,_}],
- 'CosNotifyFilter_Filter':add_constraints(Filter,
- [#'CosNotifyFilter_ConstraintExp'{event_types =
- [#'CosNotification_EventType'{
- domain_name = "",
- type_name = "type1"},
- #'CosNotification_EventType'{
- domain_name = "*",
- type_name = "type2"}],
- constraint_expr = "2==2 and 3<4"}])),
-
- ?match([{'CosNotifyFilter_ConstraintInfo',_,_}],
- 'CosNotifyFilter_Filter':add_constraints(Filter,
- [#'CosNotifyFilter_ConstraintExp'{event_types =
- [#'CosNotification_EventType'{
- domain_name = "domain1",
- type_name = "type1"},
- #'CosNotification_EventType'{
- domain_name = "domain2",
- type_name = "type2"}],
- constraint_expr = "2==2 and 3<4"}])),
-
- ?match([{'CosNotifyFilter_ConstraintInfo',_,_}],
- 'CosNotifyFilter_Filter':add_constraints(Filter,
- [#'CosNotifyFilter_ConstraintExp'{event_types =
- [#'CosNotification_EventType'{
- domain_name = "dom*",
- type_name = "type1"},
- #'CosNotification_EventType'{
- domain_name = "domain2",
- type_name = "typ*"}],
- constraint_expr = "2==2 and 3<4"}])),
-
- ?match([{'CosNotifyFilter_ConstraintInfo',_,_}],
- 'CosNotifyFilter_Filter':add_constraints(Filter,
- [#'CosNotifyFilter_ConstraintExp'{event_types =
- [#'CosNotification_EventType'{
- domain_name = "dom*1",
- type_name = "type1"},
- #'CosNotification_EventType'{
- domain_name = "domain2",
- type_name = "typ*2"}],
- constraint_expr = "2==2 and 3<4"}])),
-
- catch corba:dispose(FiFac),
- catch corba:dispose(Filter),
- catch corba:dispose(AC),
- catch corba:dispose(Ch),
- catch corba:dispose(Fac),
- ok.
-
-%%-----------------------------------------------------------------
-%% Subscription handling API tests
-%%-----------------------------------------------------------------
-subscription_api(_Config) ->
- %% Initialize the application.
- Fac = (catch cosNotificationApp:start_global_factory(?FAC_OPT)),
- ?match({_,key,_,_,_,_}, Fac),
- {Ch, _Id1} = (catch 'CosNotifyChannelAdmin_EventChannelFactory':create_channel(Fac, ?defaultQoS, ?defaultAdm)),
- ?match({_,key,_,_,_,_}, Ch),
-
- %% Create the Admin objects
- {AdminSupplier, _ASID}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_EventChannel':new_for_suppliers(Ch,'OR_OP')),
- {AdminConsumer, _ACID}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_EventChannel':new_for_consumers(Ch,'OR_OP')),
-
- %% Create Suppliers Proxies
- {StructuredProxyPullSupplier,_}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_ConsumerAdmin':obtain_notification_pull_supplier(AdminConsumer, 'STRUCTURED_EVENT')),
- {StructuredProxyPushSupplier,_}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_ConsumerAdmin':obtain_notification_push_supplier(AdminConsumer, 'STRUCTURED_EVENT')),
-
- %% Now we must create a Client for each proxy and connect them.
- PushStrC=?match({_,key,_,_,_,_}, 'notify_test_StrPushC':oe_create(['PUSH_STRUCTURED',StructuredProxyPushSupplier],
- [{local_typecheck, false}])),
- ?match(ok, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':connect_structured_push_consumer(StructuredProxyPushSupplier, PushStrC)),
- PullStrC=?match({_,key,_,_,_,_}, 'notify_test_StrPullC':oe_create(['PULL_STRUCTURED',StructuredProxyPullSupplier],
- [{local_typecheck, false}])),
- ?match(ok, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':connect_structured_pull_consumer(StructuredProxyPullSupplier, PullStrC)),
-
- %% Create Consumers Proxies
- {StructuredProxyPullConsumer,_}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_SupplierAdmin':obtain_notification_pull_consumer(AdminSupplier, 'STRUCTURED_EVENT')),
- {StructuredProxyPushConsumer,_}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_SupplierAdmin':obtain_notification_push_consumer(AdminSupplier, 'STRUCTURED_EVENT')),
-
- %% Now we must create a Client for each proxy and connect them.
- PushStrS=?match({_,key,_,_,_,_}, 'notify_test_StrPushS':oe_create(['PUSH_STRUCTURED',StructuredProxyPushConsumer],
- [{local_typecheck, false}])),
- ?match(ok, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':connect_structured_push_supplier(StructuredProxyPushConsumer, PushStrS)),
-
- PullStrS=?match({_,key,_,_,_,_}, 'notify_test_StrPullS':oe_create(['PULL_STRUCTURED',StructuredProxyPullConsumer],
- [{local_typecheck, false}])),
- ?match(ok, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':connect_structured_pull_supplier(StructuredProxyPullConsumer, PullStrS)),
-
- ES1=[#'CosNotification_EventType'{domain_name = "name1", type_name = "type1"},
- #'CosNotification_EventType'{domain_name = "name2", type_name = "type2"}],
- ES2=[#'CosNotification_EventType'{domain_name = "name3", type_name = "type3"},
- #'CosNotification_EventType'{domain_name = "name4", type_name = "type4"}],
-
- %% Initially it should have no associated types. Test that and set that
- %% all updates should be forwarded to client.
- ?match([], 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':
- obtain_subscription_types(StructuredProxyPushConsumer,
- 'ALL_NOW_UPDATES_ON')),
- ?match([], 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':
- obtain_subscription_types(StructuredProxyPullConsumer,
- 'ALL_NOW_UPDATES_ON')),
-
- %% Update the offered types.
- ?match(ok, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':
- offer_change(StructuredProxyPushConsumer, ES1, [])),
- ?match(ok, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':
- offer_change(StructuredProxyPullConsumer, ES1, [])),
-
- %% To be sure, wait a couple of seconds.
- timer:sleep(5000),
- ?match([{'CosNotification_EventType',_,_},
- {'CosNotification_EventType',_,_}],
- 'notify_test_StrPushC':doAction(PushStrS, return_data)),
- ?match([{'CosNotification_EventType',_,_},
- {'CosNotification_EventType',_,_}],
- 'notify_test_StrPullC':doAction(PullStrS, return_data)),
-
- %% Update the offered types. Remove ES1 and add ES2.
- ?match(ok, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':
- offer_change(StructuredProxyPushConsumer, ES2, ES1)),
- ?match(ok, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':
- offer_change(StructuredProxyPullConsumer, ES2, ES1)),
-
- %% To be sure, wait a couple of seconds.
- timer:sleep(5000),
- ?match([{'CosNotification_EventType',_,_},
- {'CosNotification_EventType',_,_}],
- 'notify_test_StrPushC':doAction(PushStrS, return_data)),
- ?match([{'CosNotification_EventType',_,_},
- {'CosNotification_EventType',_,_}],
- 'notify_test_StrPullC':doAction(PullStrS, return_data)),
-
- %% Now, the objects should only contain 'ES2'. Test it.
- ?match([{'CosNotification_EventType',_,_},
- {'CosNotification_EventType',_,_}],
- 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':
- obtain_subscription_types(StructuredProxyPushConsumer,
- 'ALL_NOW_UPDATES_ON')),
- ?match([{'CosNotification_EventType',_,_},
- {'CosNotification_EventType',_,_}],
- 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':
- obtain_subscription_types(StructuredProxyPullConsumer,
- 'ALL_NOW_UPDATES_ON')),
-
- %% Now we will use wildcards, empty strings and test if they really
- %% are ignored if so requested.
- ES3=[#'CosNotification_EventType'{domain_name = "name1", type_name = "*"},
- #'CosNotification_EventType'{domain_name = "*", type_name = "type2"}],
- ES4=[#'CosNotification_EventType'{domain_name = "name1", type_name = "*"},
- #'CosNotification_EventType'{domain_name = "name2", type_name = ""}],
- ES5=[#'CosNotification_EventType'{domain_name = "na*", type_name = "type1"}],
- ES6=[#'CosNotification_EventType'{domain_name = "n*1", type_name = "type1"}],
- ES7=[#'CosNotification_EventType'{domain_name = "*1", type_name = "type1"}],
- ES8=[#'CosNotification_EventType'{domain_name = "n*m*1", type_name = "type1"}],
- ES9=[#'CosNotification_EventType'{domain_name = "n**1", type_name = "type1"}],
- ES10=[#'CosNotification_EventType'{domain_name = "nam*1", type_name = "type1"}],
-
- Event1 = ?not_CreateSE("name1","type1",
- "event_name",
- [#'CosNotification_Property'{name="property_name",
- value=any:create(orber_tc:short(), 1)}],
- [], any:create(orber_tc:null(), null)),
- Event2 = ?not_CreateSE("name2","type1",
- "event_name",
- [#'CosNotification_Property'{name="property_name",
- value=any:create(orber_tc:short(), 1)}],
- [], any:create(orber_tc:null(), null)),
- Event3 = ?not_CreateSE("mame1","type1",
- "event_name",
- [#'CosNotification_Property'{name="property_name",
- value=any:create(orber_tc:short(), 1)}],
- [], any:create(orber_tc:null(), null)),
- Event4 = ?not_CreateSE("naame1","type1",
- "event_name",
- [#'CosNotification_Property'{name="property_name",
- value=any:create(orber_tc:short(), 1)}],
- [], any:create(orber_tc:null(), null)),
- Event5 = ?not_CreateSE("nname1","type1",
- "event_name",
- [#'CosNotification_Property'{name="property_name",
- value=any:create(orber_tc:short(), 1)}],
- [], any:create(orber_tc:null(), null)),
- Event6 = ?not_CreateSE("name12","type1",
- "event_name",
- [#'CosNotification_Property'{name="property_name",
- value=any:create(orber_tc:short(), 1)}],
- [], any:create(orber_tc:null(), null)),
-
- ?match(ok, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':
- subscription_change(StructuredProxyPullSupplier, ES3, [])),
-
- ?match(ok,'CosNotifyChannelAdmin_StructuredProxyPushConsumer':push_structured_event(StructuredProxyPushConsumer, Event1)),
-
- ?match(Event1, 'notify_test_StrPullC':doAction(PullStrC, pull_str)),
-
- ?match(ok, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':
- subscription_change(StructuredProxyPullSupplier, ES4, ES3)),
- ?match(ok,'CosNotifyChannelAdmin_StructuredProxyPushConsumer':push_structured_event(StructuredProxyPushConsumer, Event1)),
- ?match(Event1, 'notify_test_StrPullC':doAction(PullStrC, pull_str)),
-
- ?match(ok, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':
- subscription_change(StructuredProxyPullSupplier, ES5, ES4)),
- ?match(ok,'CosNotifyChannelAdmin_StructuredProxyPushConsumer':push_structured_event(StructuredProxyPushConsumer, Event1)),
- ?match(Event1, 'notify_test_StrPullC':doAction(PullStrC, pull_str)),
-
- ?match(ok, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':
- subscription_change(StructuredProxyPullSupplier, ES6, ES5)),
- ?match(ok,'CosNotifyChannelAdmin_StructuredProxyPushConsumer':push_structured_event(StructuredProxyPushConsumer, Event1)),
- ?match(Event1, 'notify_test_StrPullC':doAction(PullStrC, pull_str)),
-
- ?match(ok, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':
- subscription_change(StructuredProxyPullSupplier, ES7, ES6)),
- ?match(ok,'CosNotifyChannelAdmin_StructuredProxyPushConsumer':push_structured_event(StructuredProxyPushConsumer, Event1)),
- ?match(Event1, 'notify_test_StrPullC':doAction(PullStrC, pull_str)),
-
- ?match(ok, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':
- subscription_change(StructuredProxyPullSupplier, ES8, ES7)),
- ?match(ok,'CosNotifyChannelAdmin_StructuredProxyPushConsumer':push_structured_event(StructuredProxyPushConsumer, Event1)),
- ?match(Event1, 'notify_test_StrPullC':doAction(PullStrC, pull_str)),
-
- ?match(ok, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':
- subscription_change(StructuredProxyPullSupplier, ES9, ES8)),
- ?match(ok,'CosNotifyChannelAdmin_StructuredProxyPushConsumer':push_structured_event(StructuredProxyPushConsumer, Event1)),
- ?match(Event1, 'notify_test_StrPullC':doAction(PullStrC, pull_str)),
-
- ?match(ok,'CosNotifyChannelAdmin_StructuredProxyPushConsumer':push_structured_event(StructuredProxyPushConsumer, Event2)),
- ?match(ok,'CosNotifyChannelAdmin_StructuredProxyPushConsumer':push_structured_event(StructuredProxyPushConsumer, Event3)),
-
- timer:sleep(5000),
- ?match({_NilStrEvent,false}, 'notify_test_StrPullC':doAction(PullStrC, try_pull_str)),
-
- ?match(ok, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':
- subscription_change(StructuredProxyPullSupplier, ES10, ES9)),
- ?match(ok,'CosNotifyChannelAdmin_StructuredProxyPushConsumer':push_structured_event(StructuredProxyPushConsumer, Event1)),
- ?match(Event1, 'notify_test_StrPullC':doAction(PullStrC, pull_str)),
-
- ?match(ok,'CosNotifyChannelAdmin_StructuredProxyPushConsumer':push_structured_event(StructuredProxyPushConsumer, Event4)),
- ?match(ok,'CosNotifyChannelAdmin_StructuredProxyPushConsumer':push_structured_event(StructuredProxyPushConsumer, Event5)),
- ?match(ok,'CosNotifyChannelAdmin_StructuredProxyPushConsumer':push_structured_event(StructuredProxyPushConsumer, Event6)),
-
- timer:sleep(5000),
- ?match({_NilStrEvent,false}, 'notify_test_StrPullC':doAction(PullStrC, try_pull_str)),
-
-
- catch corba:dispose(StructuredProxyPushConsumer),
- catch corba:dispose(StructuredProxyPullConsumer),
- catch corba:dispose(StructuredProxyPushSupplier),
- catch corba:dispose(StructuredProxyPullSupplier),
- catch corba:dispose(AdminConsumer),
- catch corba:dispose(AdminSupplier),
- catch corba:dispose(Ch),
- catch cosNotificationApp:stop_factory(Fac),
-
- timer:sleep(5000),
- ?match(true, corba_object:non_existent(PullStrS)),
- ?match(true, corba_object:non_existent(PushStrS)),
- ?match(true, corba_object:non_existent(PullStrC)),
- ?match(true, corba_object:non_existent(PushStrC)),
-
- ok.
-
-%%-----------------------------------------------------------------
-%% Filter admin API tests
-%%-----------------------------------------------------------------
-filter_adm_api(_Config) ->
- Fac = (catch cosNotificationApp:start_global_factory(?FAC_OPT)),
- ?match({_,key,_,_,_,_}, Fac),
- {Ch, _Id1} = (catch 'CosNotifyChannelAdmin_EventChannelFactory':create_channel(Fac, ?defaultQoS, ?defaultAdm)),
- ?match({_,key,_,_,_,_}, Ch),
-
- FiFac = 'CosNotifyFilter_FilterFactory':oe_create(),
- ?match({_,key,_,_,_,_}, FiFac),
-
- Filter = 'CosNotifyFilter_FilterFactory':create_filter(FiFac,"EXTENDED_TCL"),
- ?match({_,key,_,_,_,_}, Filter),
-
- AC=?match({_,key,_,_,_,_},
- 'CosNotifyChannelAdmin_EventChannel':for_consumers(Ch)),
- filter_tests('CosNotifyChannelAdmin_ConsumerAdmin', AC, Filter, Ch),
-
- AS=?match({_,key,_,_,_,_},
- 'CosNotifyChannelAdmin_EventChannel':for_suppliers(Ch)),
- filter_tests('CosNotifyChannelAdmin_SupplierAdmin', AS, Filter, Ch),
-
- PushS=?match({_,key,_,_,_,_},
- 'CosNotifyChannelAdmin_ConsumerAdmin':obtain_push_supplier(AC)),
- filter_tests('CosNotifyChannelAdmin_ProxyPushSupplier', PushS, Filter, Ch),
-
- PullS=?match({_,key,_,_,_,_},
- 'CosNotifyChannelAdmin_ConsumerAdmin':obtain_pull_supplier(AC)),
- filter_tests('CosNotifyChannelAdmin_ProxyPullSupplier', PullS, Filter, Ch),
-
- PushC=?match({_,key,_,_,_,_},
- 'CosNotifyChannelAdmin_SupplierAdmin':obtain_push_consumer(AS)),
- filter_tests('CosNotifyChannelAdmin_ProxyPushConsumer', PushC, Filter, Ch),
-
- PullC=?match({_,key,_,_,_,_},
- 'CosNotifyChannelAdmin_SupplierAdmin':obtain_pull_consumer(AS)),
- filter_tests('CosNotifyChannelAdmin_ProxyPullConsumer', PullC, Filter, Ch),
-
- catch corba:dispose(FiFac),
- catch corba:dispose(Filter),
- catch corba:dispose(PushS),
- catch corba:dispose(PullS),
- catch corba:dispose(PushC),
- catch corba:dispose(PullC),
- catch corba:dispose(AC),
- catch corba:dispose(AS),
- catch corba:dispose(Ch),
- catch cosNotificationApp:stop_factory(Fac),
- ok.
-
-filter_tests(Mod, Obj, Filter, Ch) ->
- io:format("############ TESTING MODULE ~p FILTER ############~n", [Mod]),
- %% No filter added.
- ?match([], Mod:get_all_filters(Obj)),
- ?match(ok, Mod:remove_all_filters(Obj)),
- ?match({'EXCEPTION',{'CosNotifyFilter_FilterNotFound',_}},
- Mod:get_filter(Obj, 0)),
- %% Try add a Filter which is not a filter.
- ?match({'EXCEPTION',{'BAD_PARAM',_,_,_}}, Mod:add_filter(Obj, Ch)),
- %% Try to remove a single filter.
- ?match({'EXCEPTION',{'CosNotifyFilter_FilterNotFound',_}},
- Mod:remove_filter(Obj, 0)),
- ID = Mod:add_filter(Obj, Filter),
- ?match([ID], Mod:get_all_filters(Obj)),
- ?match(Filter, Mod:get_filter(Obj, ID)),
- ?match(ok, Mod:remove_filter(Obj, ID)),
- ?match([], Mod:get_all_filters(Obj)),
- ID2 = Mod:add_filter(Obj, Filter),
- ?match([ID2], Mod:get_all_filters(Obj)),
- ?match(ok, Mod:remove_all_filters(Obj)),
- ?match([], Mod:get_all_filters(Obj)),
- ok.
-
-%%-----------------------------------------------------------------
-%% Creating different event pushing and pulling API tests
-%%-----------------------------------------------------------------
-events_api(_Config) ->
- %% Initialize the application.
- Fac = (catch cosNotificationApp:start_global_factory(?FAC_OPT)),
- ?match({_,key,_,_,_,_}, Fac),
- {Ch, Id1} = (catch 'CosNotifyChannelAdmin_EventChannelFactory':create_channel(Fac, ?defaultQoS, ?defaultAdm)),
- ?match({_,key,_,_,_,_}, Ch),
- events_api_helper(Fac, Ch, Id1).
-
-events2_api(doc) -> ["CosNotification event pushing and pulling tests II", ""];
-events2_api(suite) -> [];
-events2_api(_Config) ->
- %% Initialize the application.
- Fac = (catch cosNotificationApp:start_global_factory(?FAC_OPT)),
- ?match({_,key,_,_,_,_}, Fac),
- {Ch, Id1} = (catch 'CosNotifyChannelAdmin_EventChannelFactory':create_channel(Fac, ?defaultQoS2, ?defaultAdm)),
- ?match({_,key,_,_,_,_}, Ch),
- events_api_helper(Fac, Ch, Id1).
-
-events_api_helper(Fac, Ch, _Id1) ->
- %% Now we will set up a test environment, with the following structure:
- %%
- %% Channel
- %% / \
- %% Supplier Adm Consumer Adm
- %% / \
- %% 1 proxy of each possible type
- %% To each proxy we will connect a test client
- %% The events will flow in ===>> direction.
- %%
- %% For the supplier Admins this include:
- %% - ProxyPushConsumer
- %% - SequenceProxyPushConsumer
- %% - StructuredProxyPushConsumer
- %% - ProxyPullConsumer
- %% - SequenceProxyPullConsumer
- %% - StructuredProxyPullConsumer
- %%
- %% For the consumer Admins this include:
- %% - ProxyPushSupplier
- %% - SequenceProxyPushSupplier
- %% - StructuredProxyPushSupplier
- %% - ProxyPullSupplier
- %% - SequenceProxyPullSupplier
- %% - StructuredProxyPullSupplier
- %%
- %%
- %% We will not use any Filters to begin with, just want to make sure we can
- %% deliver events from all start- to end-points.
-
- %% Create the Admin objects
- {AdminSupplier, _ASID}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_EventChannel':new_for_suppliers(Ch,'AND_OP')),
- {AdminConsumer, _ACID}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_EventChannel':new_for_consumers(Ch,'AND_OP')),
-
- %% Create Suppliers Proxies
- {ProxyPullSupplier,_ID1}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_ConsumerAdmin':obtain_notification_pull_supplier(AdminConsumer, 'ANY_EVENT')),
- {StructuredProxyPullSupplier,_ID2}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_ConsumerAdmin':obtain_notification_pull_supplier(AdminConsumer, 'STRUCTURED_EVENT')),
- {SequenceProxyPullSupplier,_ID3}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_ConsumerAdmin':obtain_notification_pull_supplier(AdminConsumer, 'SEQUENCE_EVENT')),
-
- {ProxyPushSupplier,_I4D}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_ConsumerAdmin':obtain_notification_push_supplier(AdminConsumer, 'ANY_EVENT')),
- {StructuredProxyPushSupplier,_ID5}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_ConsumerAdmin':obtain_notification_push_supplier(AdminConsumer, 'STRUCTURED_EVENT')),
- {SequenceProxyPushSupplier,_ID6}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_ConsumerAdmin':obtain_notification_push_supplier(AdminConsumer, 'SEQUENCE_EVENT')),
-
- %% Now we must create a Client for each proxy and connect them.
- PushAnyC=?match({_,key,_,_,_,_}, 'notify_test_AnyPushC':oe_create(['PUSH_ANY', ProxyPushSupplier],
- [{local_typecheck, false}])),
- ?match(ok, 'CosNotifyChannelAdmin_ProxyPushSupplier':connect_any_push_consumer(ProxyPushSupplier, PushAnyC)),
-
- PushStrC=?match({_,key,_,_,_,_}, 'notify_test_StrPushC':oe_create(['PUSH_STRUCTURED',StructuredProxyPushSupplier],
- [{local_typecheck, false}])),
- ?match(ok, 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':connect_structured_push_consumer(StructuredProxyPushSupplier, PushStrC)),
-
- PushSeqC=?match({_,key,_,_,_,_}, 'notify_test_SeqPushC':oe_create(['PUSH_SEQUENCE',SequenceProxyPushSupplier],
- [{local_typecheck, false}])),
- ?match(ok, 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':connect_sequence_push_consumer(SequenceProxyPushSupplier, PushSeqC)),
-
- PullAnyC=?match({_,key,_,_,_,_}, 'notify_test_AnyPullC':oe_create(['PULL_ANY', ProxyPullSupplier],
- [{local_typecheck, false}])),
- ?match(ok, 'CosNotifyChannelAdmin_ProxyPullSupplier':connect_any_pull_consumer(ProxyPullSupplier, PullAnyC)),
-
- PullStrC=?match({_,key,_,_,_,_}, 'notify_test_StrPullC':oe_create(['PULL_STRUCTURED',StructuredProxyPullSupplier],
- [{local_typecheck, false}])),
- ?match(ok, 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':connect_structured_pull_consumer(StructuredProxyPullSupplier, PullStrC)),
-
- PullSeqC=?match({_,key,_,_,_,_}, 'notify_test_SeqPullC':oe_create(['PULL_SEQUENCE',SequenceProxyPullSupplier],
- [{local_typecheck, false}])),
- ?match(ok, 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':connect_sequence_pull_consumer(SequenceProxyPullSupplier, PullSeqC)),
-
-
- %% Create Consumers Proxies
- {ProxyPullConsumer,_ID7}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_SupplierAdmin':obtain_notification_pull_consumer(AdminSupplier, 'ANY_EVENT')),
- {StructuredProxyPullConsumer,_ID8}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_SupplierAdmin':obtain_notification_pull_consumer(AdminSupplier, 'STRUCTURED_EVENT')),
- {SequenceProxyPullConsumer,_ID9}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_SupplierAdmin':obtain_notification_pull_consumer(AdminSupplier, 'SEQUENCE_EVENT')),
-
- {ProxyPushConsumer,_ID10}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_SupplierAdmin':obtain_notification_push_consumer(AdminSupplier, 'ANY_EVENT')),
- {StructuredProxyPushConsumer,_ID11}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_SupplierAdmin':obtain_notification_push_consumer(AdminSupplier, 'STRUCTURED_EVENT')),
- {SequenceProxyPushConsumer,_ID12}=?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_SupplierAdmin':obtain_notification_push_consumer(AdminSupplier, 'SEQUENCE_EVENT')),
-
- %% Now we must create a Client for each proxy and connect them.
- PushAnyS=?match({_,key,_,_,_,_}, 'notify_test_AnyPushS':oe_create(['PUSH_ANY', ProxyPushConsumer],
- [{local_typecheck, false}])),
- ?match(ok, 'CosNotifyChannelAdmin_ProxyPushConsumer':connect_any_push_supplier(ProxyPushConsumer, PushAnyS)),
-
- PushStrS=?match({_,key,_,_,_,_}, 'notify_test_StrPushS':oe_create(['PUSH_STRUCTURED',StructuredProxyPushConsumer],
- [{local_typecheck, false}])),
- ?match(ok, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':connect_structured_push_supplier(StructuredProxyPushConsumer, PushStrS)),
-
- PushSeqS=?match({_,key,_,_,_,_}, 'notify_test_SeqPushS':oe_create(['PUSH_SEQUENCE',SequenceProxyPushConsumer],
- [{local_typecheck, false}])),
- ?match(ok, 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':connect_sequence_push_supplier(SequenceProxyPushConsumer, PushSeqS)),
-
- PullAnyS=?match({_,key,_,_,_,_}, 'notify_test_AnyPullS':oe_create(['PULL_ANY', ProxyPullConsumer],
- [{local_typecheck, false}])),
- ?match(ok, 'CosNotifyChannelAdmin_ProxyPullConsumer':connect_any_pull_supplier(ProxyPullConsumer, PullAnyS)),
-
- PullStrS=?match({_,key,_,_,_,_}, 'notify_test_StrPullS':oe_create(['PULL_STRUCTURED',StructuredProxyPullConsumer],
- [{local_typecheck, false}])),
- ?match(ok, 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':connect_structured_pull_supplier(StructuredProxyPullConsumer, PullStrS)),
-
- PullSeqS=?match({_,key,_,_,_,_}, 'notify_test_SeqPullS':oe_create(['PULL_SEQUENCE',SequenceProxyPullConsumer],
- [{local_typecheck, false}])),
- ?match(ok, 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':connect_sequence_pull_supplier(SequenceProxyPullConsumer, PullSeqS)),
-
-
- %% Create a couple of Events to test with.
- Event = ?not_CreateSE("DomainName","CommunicationsAlarm",
- "lost_packet",
- [#'CosNotification_Property'{name="priority",
- value=any:create(orber_tc:short(), 1)}],
- [], any:create(orber_tc:null(), null)),
-
- Event2 = ?not_CreateSE("DomainName","TemperatureAlarm",
- "over_heated",
- [#'CosNotification_Property'{name="priority",
- value=any:create(orber_tc:short(), 10)}],
- [], any:create(orber_tc:null(), null)),
-
-
- AnyEvent = any:create(orber_tc:long(), 100),
-
- StrEvent = ?not_CreateSE("","%ANY","",[],[],AnyEvent),
- NilAnyEvent = any:create(orber_tc:null(), null),
- NilStrEvent = ?not_CreateSE("","","",[],[],NilAnyEvent),
-
- ConvertedStr = any:create('CosNotification_StructuredEvent':tc(), Event),
-
- io:format("###################### PUSH STRUCTURED ########################"),
-
- %% Test with pushing a structured event.
- ?match(ok,'CosNotifyChannelAdmin_StructuredProxyPushConsumer':push_structured_event(StructuredProxyPushConsumer, Event)),
-
- %% Wait for a while so we are sure that all events have been delivered as far
- %% as the Notification service can automatically.
- timer:sleep(5000),
-
- %% Check if the Clients have received and stored the events.
- ?match([{any,_,Event}], 'notify_test_AnyPushC':doAction(PushAnyC, return_data)),
- ?match([Event], 'notify_test_StrPushC':doAction(PushStrC, return_data)),
- ?match([Event], 'notify_test_SeqPushC':doAction(PushSeqC, return_data)),
-
- %% Instruct the Clients to pull the events and check if they match.
- ?match({any,_,Event}, 'notify_test_AnyPullC':doAction(PullAnyC, pull_any)),
- ?match(Event, 'notify_test_StrPullC':doAction(PullStrC, pull_str)),
- ?match([Event], 'notify_test_SeqPullC':doAction(PullSeqC, {pull_seq,1})),
-
- io:format("###################### PUSH SEQUENCE ########################"),
-
- %% Create an Event Sequence and push it.
- EventSeq = [Event, Event2],
-
- %% Test with pushing a event sequence.
- ?match(ok,'CosNotifyChannelAdmin_SequenceProxyPushConsumer':push_structured_events(SequenceProxyPushConsumer, EventSeq)),
-
- %% Wait for a while so we are sure that all events have been delivered as far
- %% as the Notification service can automatically.
- timer:sleep(5000),
-
- %% Instruct the Clients to pull the events and check if they match.
- ?match({any,_,Event}, 'notify_test_AnyPullC':doAction(PullAnyC, pull_any)),
- ?match(Event, 'notify_test_StrPullC':doAction(PullStrC, pull_str)),
- ?match([Event,Event2], 'notify_test_SeqPullC':doAction(PullSeqC, {pull_seq,2})),
- ?match({any,_,Event2}, 'notify_test_AnyPullC':doAction(PullAnyC, pull_any)),
- ?match(Event2, 'notify_test_StrPullC':doAction(PullStrC, pull_str)),
-
- %% Check if the Push Clients have received and stored the events.
- ?match([{any,_,Event}, {any,_,Event2}], 'notify_test_AnyPushC':doAction(PushAnyC, return_data)),
- ?match([Event, Event2], 'notify_test_StrPushC':doAction(PushStrC, return_data)),
- ?match([Event, Event2], 'notify_test_SeqPushC':doAction(PushSeqC, return_data)),
-
- io:format("###################### PUSH ANY ########################"),
-
- %% Test with pushing an any event.
- ?match(ok,'CosEventChannelAdmin_ProxyPushConsumer':push(ProxyPushConsumer, AnyEvent)),
-
- %% Wait for a while so we are sure that all events have been delivered as far
- %% as the Notification service can automatically.
- timer:sleep(5000),
-
- %% Check if the Clients have received and stored the events.
- ?match([AnyEvent], 'notify_test_AnyPushC':doAction(PushAnyC, return_data)),
- ?match([StrEvent], 'notify_test_StrPushC':doAction(PushStrC, return_data)),
- ?match([StrEvent], 'notify_test_SeqPushC':doAction(PushSeqC, return_data)),
-
- %% Instruct the Clients to pull the events and check if they match.
- ?match(AnyEvent, 'notify_test_AnyPullC':doAction(PullAnyC, pull_any)),
- ?match(StrEvent, 'notify_test_StrPullC':doAction(PullStrC, pull_str)),
- ?match([StrEvent], 'notify_test_SeqPullC':doAction(PullSeqC, {pull_seq,10})),
-
-
-
- io:format("###################### PUSH CONVERTED ANY #############"),
-
- %% Test with pushing a structured event.
- ?match(ok,'CosNotifyChannelAdmin_StructuredProxyPushConsumer':push_structured_event(StructuredProxyPushConsumer, StrEvent)),
-
- %% Wait for a while so we are sure that all events have been delivered as far
- %% as the Notification service can automatically.
- timer:sleep(5000),
-
- %% Check if the Clients have received and stored the events.
- ?match([AnyEvent], 'notify_test_AnyPushC':doAction(PushAnyC, return_data)),
- ?match([StrEvent], 'notify_test_StrPushC':doAction(PushStrC, return_data)),
- ?match([StrEvent], 'notify_test_SeqPushC':doAction(PushSeqC, return_data)),
-
- %% Instruct the Clients to pull the events and check if they match.
- ?match(AnyEvent, 'notify_test_AnyPullC':doAction(PullAnyC, pull_any)),
- ?match(StrEvent, 'notify_test_StrPullC':doAction(PullStrC, pull_str)),
- ?match([StrEvent], 'notify_test_SeqPullC':doAction(PullSeqC, {pull_seq,1})),
-
-
- io:format("###################### PUSH CONVERTED STRUCTURED ########"),
-
- %% Test with pushing an any event.
- ?match(ok,'CosEventChannelAdmin_ProxyPushConsumer':push(ProxyPushConsumer, ConvertedStr)),
-
- %% Wait for a while so we are sure that all events have been delivered as far
- %% as the Notification service can automatically.
- timer:sleep(5000),
-
- %% Check if the Clients have received and stored the events.
- ?match([ConvertedStr], 'notify_test_AnyPushC':doAction(PushAnyC, return_data)),
- ?match([Event], 'notify_test_StrPushC':doAction(PushStrC, return_data)),
- ?match([Event], 'notify_test_SeqPushC':doAction(PushSeqC, return_data)),
-
- %% Instruct the Clients to pull the events and check if they match.
- ?match(ConvertedStr, 'notify_test_AnyPullC':doAction(PullAnyC, pull_any)),
- ?match(Event, 'notify_test_StrPullC':doAction(PullStrC, pull_str)),
- ?match([Event], 'notify_test_SeqPullC':doAction(PullSeqC, {pull_seq,10})),
-
-
- io:format("###################### TRY PULL ########################"),
-
- %% Now we will push an any event after a delay. This means that try_pull-functions,
- %% since it's not blocking, will return, [], NilAny or NilStructured events and
- %% the Boolean false.
- spawn(notify_test_impl, delay, [ProxyPushConsumer, AnyEvent, 20000,
- 'CosEventChannelAdmin_ProxyPushConsumer',push]),
- ?match([], 'notify_test_AnyPushC':doAction(PushAnyC, return_data)),
- ?match([], 'notify_test_StrPushC':doAction(PushStrC, return_data)),
- ?match([], 'notify_test_SeqPushC':doAction(PushSeqC, return_data)),
-
- %% Instruct the Clients to pull the events and check if they match.
- ?match({NilAnyEvent,false}, 'notify_test_AnyPullC':doAction(PullAnyC, try_pull_any)),
- ?match({NilStrEvent,false}, 'notify_test_StrPullC':doAction(PullStrC, try_pull_str)),
- ?match({[],false}, 'notify_test_SeqPullC':doAction(PullSeqC, {try_pull_seq,10})),
-
-
- %% Instruct the Clients to pull the events and check if they match.
- %% Pull is blocking so in the print-out we should see that nothing
- %% is returned until the pushed event reaches the end proxies.
- ?match(AnyEvent, 'notify_test_AnyPullC':doAction(PullAnyC, pull_any)),
- ?match(StrEvent, 'notify_test_StrPullC':doAction(PullStrC, pull_str)),
- ?match([StrEvent], 'notify_test_SeqPullC':doAction(PullSeqC, {pull_seq,1})),
-
- %% To make sure there are no other circumstanses which lead to a delay we
- %% hold for some time.
- timer:sleep(5000),
- %% Check if the Clients have received and stored the events.
- ?match([AnyEvent], 'notify_test_AnyPushC':doAction(PushAnyC, return_data)),
- ?match([StrEvent], 'notify_test_StrPushC':doAction(PushStrC, return_data)),
- ?match([StrEvent], 'notify_test_SeqPushC':doAction(PushSeqC, return_data)),
-
- %% Test with pushing a event sequence but only pull sequences of length 1.
- ?match(ok,'CosNotifyChannelAdmin_SequenceProxyPushConsumer':push_structured_events(SequenceProxyPushConsumer, EventSeq)),
-
- %% Wait for a while so we are sure that all events have been delivered as far
- %% as the Notification service can automatically.
- timer:sleep(5000),
- %% Pull 1 event at a time.
- ?match([Event], 'notify_test_SeqPullC':doAction(PullSeqC, {pull_seq,1})),
- ?match([Event2], 'notify_test_SeqPullC':doAction(PullSeqC, {pull_seq,1})),
-
- %% Following cases already tested; done for clean up.
- ?match({any,_,Event}, 'notify_test_AnyPullC':doAction(PullAnyC, pull_any)),
- ?match(Event, 'notify_test_StrPullC':doAction(PullStrC, pull_str)),
- ?match({any,_,Event2}, 'notify_test_AnyPullC':doAction(PullAnyC, pull_any)),
- ?match(Event2, 'notify_test_StrPullC':doAction(PullStrC, pull_str)),
- ?match([{any,_,Event}, {any,_,Event2}], 'notify_test_AnyPushC':doAction(PushAnyC, return_data)),
- ?match([Event, Event2], 'notify_test_StrPushC':doAction(PushStrC, return_data)),
- ?match([Event, Event2], 'notify_test_SeqPushC':doAction(PushSeqC, return_data)),
- %% clean up done
-
-
- io:format("###################### PROXY PULLER ########################"),
-
- %% Now we will just add Events to a cleint and wait for the Notification service
- %% to pull the events and forward them to the consumer clients.
- ?match(ok, 'notify_test_SeqPushC':doAction(PullAnyS, {set_data, [AnyEvent]})),
-
-
- %% Instruct the Clients to pull the events and check if they match.
- %% Pull is blocking so in the print-out we should see that nothing
- %% is returned until the pushed event reaches the end proxies.
- ?match(AnyEvent, 'notify_test_AnyPullC':doAction(PullAnyC, pull_any)),
- ?match(StrEvent, 'notify_test_StrPullC':doAction(PullStrC, pull_str)),
- ?match([StrEvent], 'notify_test_SeqPullC':doAction(PullSeqC, {pull_seq,10})),
-
- %% To make sure there are no other circumstanses which lead to a delay we
- %% hold for some time.
- timer:sleep(5000),
- %% Check if the Clients have received and stored the events.
- ?match([AnyEvent], 'notify_test_AnyPushC':doAction(PushAnyC, return_data)),
- ?match([StrEvent], 'notify_test_StrPushC':doAction(PushStrC, return_data)),
- ?match([StrEvent], 'notify_test_SeqPushC':doAction(PushSeqC, return_data)),
-
- io:format("###################### SUSPENDED CONNECTION ################"),
-
-
- %% Suspend the connections
- ?match(ok,'CosNotifyChannelAdmin_SequenceProxyPushSupplier':suspend_connection(SequenceProxyPushSupplier)),
- ?match(ok,'CosNotifyChannelAdmin_StructuredProxyPushSupplier':suspend_connection(StructuredProxyPushSupplier)),
-
- %% Test with pushing a event sequence.
- ?match(ok,'CosNotifyChannelAdmin_SequenceProxyPushConsumer':push_structured_events(SequenceProxyPushConsumer, EventSeq)),
-
- %% Wait for a while so we are sure that all events have been delivered as far
- %% as the Notification service can automatically.
- timer:sleep(5000),
-
- %% Instruct the Clients to pull the events and check if they match.
- ?match({any,_,Event}, 'notify_test_AnyPullC':doAction(PullAnyC, pull_any)),
- ?match(Event, 'notify_test_StrPullC':doAction(PullStrC, pull_str)),
- ?match([Event,Event2], 'notify_test_SeqPullC':doAction(PullSeqC, {pull_seq,2})),
- ?match({any,_,Event2}, 'notify_test_AnyPullC':doAction(PullAnyC, pull_any)),
- ?match(Event2, 'notify_test_StrPullC':doAction(PullStrC, pull_str)),
-
- %% Check if the Any Client have received and stored the events.
- ?match([{any,_,Event}, {any,_,Event2}], 'notify_test_AnyPushC':doAction(PushAnyC, return_data)),
-
- %% Check if the other Clients have received any events. Error if have.
- ?match([], 'notify_test_StrPushC':doAction(PushStrC, return_data)),
- ?match([], 'notify_test_SeqPushC':doAction(PushSeqC, return_data)),
-
- ?match(ok,'CosNotifyChannelAdmin_SequenceProxyPushSupplier':resume_connection(SequenceProxyPushSupplier)),
- ?match(ok,'CosNotifyChannelAdmin_StructuredProxyPushSupplier':resume_connection(StructuredProxyPushSupplier)),
-
- %% To be sure the test case don't fail due to time-race, sleep.
- timer:sleep(5000),
-
- ?match([Event, Event2], 'notify_test_StrPushC':doAction(PushStrC, return_data)),
- ?match([Event, Event2], 'notify_test_SeqPushC':doAction(PushSeqC, return_data)),
-
-
- io:format("###################### FILTER EVENTS #######################"),
-
- %% Now we will add filters and see if the system behaves correctly.
- FiFac = 'CosNotifyFilter_FilterFactory':oe_create(),
- Filter = 'CosNotifyFilter_FilterFactory':create_filter(FiFac,"EXTENDED_TCL"),
- %% Add constraints to the Filter
- [{_,_,CID1},{_,_,CID2}]=
- ?match([{'CosNotifyFilter_ConstraintInfo',_,_}, {'CosNotifyFilter_ConstraintInfo',_,_}],
- 'CosNotifyFilter_Filter':add_constraints(Filter,
- [#'CosNotifyFilter_ConstraintExp'{event_types =
- [#'CosNotification_EventType'{
- domain_name = "Spare*",
- type_name = "MOVIE"}],
- constraint_expr = "$type_name == 'MOVIE' and (('groucho' in $starlist) + ('chico' in $starlist) + ('harpo' in $starlist) + ('zeppo' in $starlist) + ('gummo' in $starlist)) > 2"},
- #'CosNotifyFilter_ConstraintExp'{event_types =
- [#'CosNotification_EventType'{
- domain_name = "*",
- type_name = "TestResults"}],
- constraint_expr = "$test._length == 3 and ($test[0].score + $test[1].score + $test[2].score)/3 >=80"}])),
-
- ?match([{'CosNotifyFilter_ConstraintInfo',_,CID2}, {'CosNotifyFilter_ConstraintInfo',_,CID1}],
- 'CosNotifyFilter_Filter':get_all_constraints(Filter)),
- ?match([{'CosNotifyFilter_ConstraintInfo',_,CID1}],
- 'CosNotifyFilter_Filter':get_constraints(Filter, [CID1])),
-
- %% Associate the Filter with different objects.
- %% Since we use the same filter for both objects the events will never reach the admin.
- _FilterID = 'CosNotifyChannelAdmin_ConsumerAdmin':add_filter(AdminConsumer, Filter),
-
- _FilterID2 = 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':add_filter(StructuredProxyPushConsumer, Filter),
- event_filtering(FiFac, Filter, AdminConsumer, StructuredProxyPushConsumer, PushAnyC,
- PushStrC, PushSeqC, PullAnyC, PullStrC, PullSeqC),
- %% Remove the proxy filter so we can check if the events are filtered correctly by the admin.
- ?match(ok, 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':remove_all_filters(StructuredProxyPushConsumer)),
- event_filtering(FiFac, Filter, AdminConsumer, StructuredProxyPushConsumer, PushAnyC,
- PushStrC, PushSeqC, PullAnyC, PullStrC, PullSeqC),
-
-
- catch corba:dispose(Filter),
- catch corba:dispose(FiFac),
- catch corba:dispose(SequenceProxyPushConsumer),
- catch corba:dispose(StructuredProxyPushConsumer),
- catch corba:dispose(ProxyPushConsumer),
- catch corba:dispose(SequenceProxyPullConsumer),
- catch corba:dispose(StructuredProxyPullConsumer),
- catch corba:dispose(ProxyPullConsumer),
- catch corba:dispose(SequenceProxyPushSupplier),
- catch corba:dispose(StructuredProxyPushSupplier),
- catch corba:dispose(ProxyPushSupplier),
- catch corba:dispose(SequenceProxyPullSupplier),
- catch corba:dispose(StructuredProxyPullSupplier),
- catch corba:dispose(ProxyPullSupplier),
- catch corba:dispose(AdminConsumer),
- catch corba:dispose(AdminSupplier),
- catch corba:dispose(Ch),
- catch cosNotificationApp:stop_factory(Fac),
- %% The Clients should have terminated by now. Check if it is so.
- timer:sleep(5000),
- ?match(true, corba_object:non_existent(PullSeqS)),
- ?match(true, corba_object:non_existent(PullStrS)),
- ?match(true, corba_object:non_existent(PullAnyS)),
- ?match(true, corba_object:non_existent(PushSeqS)),
- ?match(true, corba_object:non_existent(PushStrS)),
- ?match(true, corba_object:non_existent(PushAnyS)),
- ?match(true, corba_object:non_existent(PullSeqC)),
- ?match(true, corba_object:non_existent(PullStrC)),
- ?match(true, corba_object:non_existent(PullAnyC)),
- ?match(true, corba_object:non_existent(PushSeqC)),
- ?match(true, corba_object:non_existent(PushStrC)),
- ?match(true, corba_object:non_existent(PushAnyC)),
- ok.
-
-event_filtering(_FiFac, _Filter, _AdminConsumer, StructuredProxyPushConsumer, PushAnyC, PushStrC, PushSeqC, PullAnyC, PullStrC, PullSeqC) ->
- NilAnyEvent = any:create(orber_tc:null(), null),
- NilStrEvent = ?not_CreateSE("","","",[],[],NilAnyEvent),
-
- TrueEvent1 = ?not_CreateSE("SpareTime","MOVIE",
- "EventName",
- [#'CosNotification_Property'{name="starlist",
- value=any:create(orber_tc:sequence(orber_tc:string(0),0),
- ["groucho", "harpo", "sam", "gummo"])}],
- [], any:create(orber_tc:null(), null)),
- TrueEvent2 = ?not_CreateSE("Studies","TestResults",
- "EventName", [],
- [#'CosNotification_Property'{name="test",
- value=any:create(orber_tc:array(notify_test_data:tc(),3),
- {#notify_test_data{score=75,
- name="name"},
- #notify_test_data{score=80,
- name="name"},
- #notify_test_data{score=85,
- name="name"}})}],
- any:create(orber_tc:null(), null)),
-
- FalseEvent1 = ?not_CreateSE("SpareTime","MOVIE",
- "EventName",
- [#'CosNotification_Property'{name="starlist",
- value=any:create(orber_tc:sequence(orber_tc:string(0),0),
- ["frodo", "bilbo", "sam", "gummo"])}],
- [], any:create(orber_tc:null(), null)),
- FalseEvent2 = ?not_CreateSE("Studies","TestResults",
- "EventName", [],
- [#'CosNotification_Property'{name="test",
- value=any:create(orber_tc:array(notify_test_data:tc(),3),
- {#notify_test_data{score=75,
- name="name"},
- #notify_test_data{score=80,
- name="name"},
- #notify_test_data{score=80,
- name="name"}})}],
- any:create(orber_tc:null(), null)),
- %% Test with pushing the first structured event that should not be filtered away.
- ?match(ok,'CosNotifyChannelAdmin_StructuredProxyPushConsumer':push_structured_event(StructuredProxyPushConsumer, TrueEvent1)),
-
- %% Wait for a while so we are sure that all events have been delivered as far
- %% as the Notification service can automatically.
- timer:sleep(5000),
-
- %% Check if the Clients have received and stored the events.
- ?match([{any,_,TrueEvent1}], 'notify_test_AnyPushC':doAction(PushAnyC, return_data)),
- ?match([TrueEvent1], 'notify_test_StrPushC':doAction(PushStrC, return_data)),
- ?match([TrueEvent1], 'notify_test_SeqPushC':doAction(PushSeqC, return_data)),
-
- %% Instruct the Clients to pull the events and check if they match.
- ?match({any,_,TrueEvent1}, 'notify_test_AnyPullC':doAction(PullAnyC, pull_any)),
- ?match(TrueEvent1, 'notify_test_StrPullC':doAction(PullStrC, pull_str)),
- ?match([TrueEvent1], 'notify_test_SeqPullC':doAction(PullSeqC, {pull_seq,1})),
-
- %% Test with pushing the second structured event that should not be filtered away.
- ?match(ok,'CosNotifyChannelAdmin_StructuredProxyPushConsumer':push_structured_event(StructuredProxyPushConsumer, TrueEvent2)),
-
- %% Wait for a while so we are sure that all events have been delivered as far
- %% as the Notification service can automatically.
- timer:sleep(5000),
-
- %% Check if the Clients have received and stored the events.
- ?match([{any,_,TrueEvent2}], 'notify_test_AnyPushC':doAction(PushAnyC, return_data)),
- ?match([TrueEvent2], 'notify_test_StrPushC':doAction(PushStrC, return_data)),
- ?match([TrueEvent2], 'notify_test_SeqPushC':doAction(PushSeqC, return_data)),
-
- %% Instruct the Clients to pull the events and check if they match.
- ?match({any,_,TrueEvent2}, 'notify_test_AnyPullC':doAction(PullAnyC, pull_any)),
- ?match(TrueEvent2, 'notify_test_StrPullC':doAction(PullStrC, pull_str)),
- ?match([TrueEvent2], 'notify_test_SeqPullC':doAction(PullSeqC, {pull_seq,1})),
-
- %% Test with pushing the first structured event that should be filtered away.
- ?match(ok,'CosNotifyChannelAdmin_StructuredProxyPushConsumer':push_structured_event(StructuredProxyPushConsumer, FalseEvent1)),
-
- %% Wait for a while so we are sure that all events have been delivered as far
- %% as the Notification service can automatically.
- timer:sleep(5000),
-
- %% Check if the Clients have received and stored the events.
- ?match([], 'notify_test_AnyPushC':doAction(PushAnyC, return_data)),
- ?match([], 'notify_test_StrPushC':doAction(PushStrC, return_data)),
- ?match([], 'notify_test_SeqPushC':doAction(PushSeqC, return_data)),
-
- %% Instruct the Clients to pull the events and check if they match.
- ?match({NilAnyEvent,false}, 'notify_test_AnyPullC':doAction(PullAnyC, try_pull_any)),
- ?match({NilStrEvent,false}, 'notify_test_StrPullC':doAction(PullStrC, try_pull_str)),
- ?match({[],false}, 'notify_test_SeqPullC':doAction(PullSeqC, {try_pull_seq,10})),
-
- %% Test with pushing the second structured event that should be filtered away.
- ?match(ok,'CosNotifyChannelAdmin_StructuredProxyPushConsumer':push_structured_event(StructuredProxyPushConsumer, FalseEvent2)),
-
- %% Wait for a while so we are sure that all events have been delivered as far
- %% as the Notification service can automatically.
- timer:sleep(5000),
-
- %% Check if the Clients have received and stored the events.
- ?match([], 'notify_test_AnyPushC':doAction(PushAnyC, return_data)),
- ?match([], 'notify_test_StrPushC':doAction(PushStrC, return_data)),
- ?match([], 'notify_test_SeqPushC':doAction(PushSeqC, return_data)),
-
- %% Instruct the Clients to pull the events and check if they match.
- ?match({NilAnyEvent,false}, 'notify_test_AnyPullC':doAction(PullAnyC, try_pull_any)),
- ?match({NilStrEvent,false}, 'notify_test_StrPullC':doAction(PullStrC, try_pull_str)),
- ?match({[],false}, 'notify_test_SeqPullC':doAction(PullSeqC, {try_pull_seq,10})).
-
-
-
-%%-----------------------------------------------------------------
-%% Creating different cosEvent API tests
-%%-----------------------------------------------------------------
-cosevent_api(_Config) ->
- Fac = (catch cosNotificationApp:start_global_factory(?FAC_OPT)),
- ?match({_,key,_,_,_,_}, Fac),
- {Ch, _Id1} = (catch 'CosNotifyChannelAdmin_EventChannelFactory':create_channel(Fac, ?defaultQoS, ?defaultAdm)),
- ?match({_,key,_,_,_,_}, Ch),
- AC=?match({_,key,_,_,_,_},
- 'CosEventChannelAdmin_EventChannel':for_consumers(Ch)),
- AS=?match({_,key,_,_,_,_},
- 'CosEventChannelAdmin_EventChannel':for_suppliers(Ch)),
-
- PushS=?match({_,key,_,_,_,_},
- 'CosEventChannelAdmin_ConsumerAdmin':obtain_push_supplier(AC)),
- PullS=?match({_,key,_,_,_,_},
- 'CosEventChannelAdmin_ConsumerAdmin':obtain_pull_supplier(AC)),
-
- PushC=?match({_,key,_,_,_,_},
- 'CosEventChannelAdmin_SupplierAdmin':obtain_push_consumer(AS)),
- PullC=?match({_,key,_,_,_,_},
- 'CosEventChannelAdmin_SupplierAdmin':obtain_pull_consumer(AS)),
-
- PushAnyC=?match({_,key,_,_,_,_},
- 'notify_test_AnyPushC':oe_create(['PUSH_ANY', PushC],
- [{local_typecheck, false}])),
- PushStrC=?match({_,key,_,_,_,_},
- 'notify_test_StrPushC':oe_create(['PUSH_STRUCTURED',false],
- [{local_typecheck, false}])),
- PushSeqC=?match({_,key,_,_,_,_},
- 'notify_test_SeqPushC':oe_create(['PUSH_SEQUENCE',false],
- [{local_typecheck, false}])),
-
- PullAnyC=?match({_,key,_,_,_,_},
- 'notify_test_AnyPullC':oe_create(['PULL_ANY', PullC],
- [{local_typecheck, false}])),
- PullStrC=?match({_,key,_,_,_,_},
- 'notify_test_StrPullC':oe_create(['PULL_STRUCTURED',false],
- [{local_typecheck, false}])),
- PullSeqC=?match({_,key,_,_,_,_},
- 'notify_test_SeqPullC':oe_create(['PULL_SEQUENCE',false],
- [{local_typecheck, false}])),
-
- PushAnyS=?match({_,key,_,_,_,_},
- 'notify_test_AnyPushS':oe_create(['PUSH_ANY', PushC],
- [{local_typecheck, false}])),
- PushStrS=?match({_,key,_,_,_,_},
- 'notify_test_StrPushS':oe_create(['PUSH_STRUCTURED',false],
- [{local_typecheck, false}])),
- PushSeqS=?match({_,key,_,_,_,_},
- 'notify_test_SeqPushS':oe_create(['PUSH_SEQUENCE',false],
- [{local_typecheck, false}])),
-
- PullAnyS=?match({_,key,_,_,_,_},
- 'notify_test_AnyPullS':oe_create(['PULL_ANY', PullS],
- [{local_typecheck, false}])),
- PullStrS=?match({_,key,_,_,_,_},
- 'notify_test_StrPullS':oe_create(['PULL_STRUCTURED',false],
- [{local_typecheck, false}])),
- PullSeqS=?match({_,key,_,_,_,_},
- 'notify_test_SeqPullS':oe_create(['PULL_SEQUENCE',false],
- [{local_typecheck, false}])),
-
- %% In the OMG specification Proxies do not inherrit from CosEvent. Must use
- %% Notify interface.
- ?match({'EXCEPTION',{'BAD_PARAM',_,_,_}},
- 'CosEventChannelAdmin_ProxyPullConsumer':connect_pull_supplier(PullC, PushStrS)),
-
- ?match(ok,
- 'CosEventChannelAdmin_ProxyPushSupplier':connect_push_consumer(PushS, PushAnyC)),
- ?match(ok,
- 'CosEventChannelAdmin_ProxyPullSupplier':connect_pull_consumer(PullS, PullAnyC)),
-
- ?match(ok,
- 'CosEventChannelAdmin_ProxyPushConsumer':connect_push_supplier(PushC, PushAnyS)),
- ?match(ok,
- 'CosEventChannelAdmin_ProxyPullConsumer':connect_pull_supplier(PullC, PullAnyS)),
-
- ?match({'EXCEPTION',{'CosEventChannelAdmin_AlreadyConnected',_}},
- 'CosEventChannelAdmin_ProxyPullConsumer':connect_pull_supplier(PullC, PullAnyS)),
-
- ?match({'EXCEPTION',{'CosEventChannelAdmin_AlreadyConnected',_}},
- 'CosNotifyChannelAdmin_ProxyPullConsumer':connect_pull_supplier(PullC, PullAnyS)),
-
- ?match(true, corba_object:is_a(PushS, "IDL:omg.org/CosNotifyChannelAdmin/ProxyPushSupplier:1.0")),
- ?match(true, corba_object:is_a(PushS, "IDL:omg.org/CosEventChannelAdmin/ProxyPushSupplier:1.0")),
-
- catch corba:dispose(PushStrC),
- catch corba:dispose(PushSeqC),
- catch corba:dispose(PullStrC),
- catch corba:dispose(PullSeqC),
- catch corba:dispose(PushStrS),
- catch corba:dispose(PushSeqS),
- catch corba:dispose(PullStrS),
- catch corba:dispose(PullSeqS),
- catch corba:dispose(PushS),
- catch corba:dispose(PullS),
- catch corba:dispose(PushC),
- catch corba:dispose(PullC),
- catch corba:dispose(AC),
- catch corba:dispose(AS),
- catch corba:dispose(Ch),
- catch cosNotificationApp:stop_factory(Fac),
-
- %% The Clients should have terminated by now. Check if it is so.
- timer:sleep(5000),
- ?match(true, corba_object:non_existent(PullAnyS)),
- ?match(true, corba_object:non_existent(PushAnyS)),
- ?match(true, corba_object:non_existent(PullAnyC)),
- ?match(true, corba_object:non_existent(PushAnyC)),
-
-
- ok.
-
-%%-----------------------------------------------------------------
-%% AdminPropertiesAdmin API tests
-%%-----------------------------------------------------------------
-adm_api(_Config) ->
- Fac = (catch cosNotificationApp:start_global_factory(?FAC_OPT)),
- ?match({_,key,_,_,_,_}, Fac),
-
- %% We need a few AdminProp:s to "play" with.
- MQ0 = [#'CosNotification_Property'{name='CosNotification':'MaxQueueLength'(),
- value=any:create(orber_tc:long(), 0)}],
- MC0 = [#'CosNotification_Property'{name='CosNotification':'MaxConsumers'(),
- value=any:create(orber_tc:long(), 0)}],
- MS0 = [#'CosNotification_Property'{name='CosNotification':'MaxSuppliers'(),
- value=any:create(orber_tc:long(), 0)}],
- MQError1 = [#'CosNotification_Property'{name='CosNotification':'MaxQueueLength'(),
- value=any:create(orber_tc:'float'(), 1.5)}],
- MQError2 = [#'CosNotification_Property'{name='CosNotification':'MaxQueueLength'(),
- value=any:create(orber_tc:long(), -1)}],
-
- {Ch, _Id1} = (catch 'CosNotifyChannelAdmin_EventChannelFactory':create_channel(Fac, ?defaultQoS, ?defaultAdm)),
- ?match({_,key,_,_,_,_}, Ch),
-
- %% Set new admin
- ?match(ok, 'CosNotification_AdminPropertiesAdmin':set_admin(Ch, MQ0)),
- %% It should be a list of three items. If we support more admin:s this
- %% must be updated.
- ?match([_,_,_], 'CosNotification_AdminPropertiesAdmin':get_admin(Ch)),
-
- %% Try to set admin with an uncorrect value, i.e., not integer >= 0.
- ?match({'EXCEPTION',{'CosNotification_UnsupportedAdmin',_,_}},
- 'CosNotification_AdminPropertiesAdmin':set_admin(Ch, MQError1)),
- ?match({'EXCEPTION',{'CosNotification_UnsupportedAdmin',_,_}},
- 'CosNotification_AdminPropertiesAdmin':set_admin(Ch, MQError2)),
-
- %% Try setting the other two admins and chech if the value is correct.
- ?match(ok, 'CosNotification_AdminPropertiesAdmin':set_admin(Ch, MC0)),
- ?match([_,_,_], 'CosNotification_AdminPropertiesAdmin':get_admin(Ch)),
-
- ?match(ok, 'CosNotification_AdminPropertiesAdmin':set_admin(Ch, MS0)),
- ?match([_,_,_], 'CosNotification_AdminPropertiesAdmin':get_admin(Ch)),
-
- catch corba:dispose(Ch),
- catch cosNotificationApp:stop_factory(Fac),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% QoSAdm API tests
-%%-----------------------------------------------------------------
-qos_api(_Config) ->
- Fac = (catch cosNotificationApp:start_global_factory(?FAC_OPT)),
- ?match({_,key,_,_,_,_}, Fac),
-
- {Ch, _Id1} = (catch 'CosNotifyChannelAdmin_EventChannelFactory':create_channel(Fac, ?defaultQoS, ?defaultAdm)),
- ?match({_,key,_,_,_,_}, Ch),
-
-
- QoSPersistent = [#'CosNotification_Property'{name='CosNotification':'ConnectionReliability'(),
- value=any:create(orber_tc:short(),
- 'CosNotification':'Persistent'())}],
- QoSBestEffort = [#'CosNotification_Property'{name='CosNotification':'ConnectionReliability'(),
- value=any:create(orber_tc:short(),
- 'CosNotification':'BestEffort'())}],
-
- QoSEventPersistent = [#'CosNotification_Property'{name='CosNotification':'EventReliability'(),
- value=any:create(orber_tc:short(),
- 'CosNotification':'Persistent'())}],
- QoSEventBestEffort = [#'CosNotification_Property'{name='CosNotification':'EventReliability'(),
- value=any:create(orber_tc:short(),
- 'CosNotification':'BestEffort'())}],
-
- QoSOKMaxBatchSize = [#'CosNotification_Property'{name='CosNotification':'MaximumBatchSize'(),
- value=any:create(orber_tc:long(), 200)}],
- QoSToHighMaxBatchSize = [#'CosNotification_Property'{name='CosNotification':'MaximumBatchSize'(),
- value=any:create(orber_tc:long(), 100000000)}],
-
- QoSToLowMaxBatchSize = [#'CosNotification_Property'{name='CosNotification':'MaximumBatchSize'(),
- value=any:create(orber_tc:long(), -1)}],
-
- QoSOKStopTimeSupp = [#'CosNotification_Property'{name='CosNotification':'StopTimeSupported'(),
- value=any:create(orber_tc:boolean(), true)}],
- QoSWrongStopTimeSupp = [#'CosNotification_Property'{name="StopTimeSupp",
- value=any:create(orber_tc:boolean(), true)}],
-
- QoSOKStartTimeSupp = [#'CosNotification_Property'{name='CosNotification':'StartTimeSupported'(),
- value=any:create(orber_tc:boolean(), true)}],
- QoSWrongStartTimeSupp = [#'CosNotification_Property'{name="StartTimeSupp",
- value=any:create(orber_tc:boolean(), true)}],
- QoSOKTimout = [#'CosNotification_Property'{name='CosNotification':'Timeout'(),
- value=any:create(orber_tc:unsigned_long_long(), 100)}],
-
-
- %% The most complex QoS to set is ConnectionReliability, and the reason for this
- %% is that we cannot set the Channel to offer best effort while its children
- %% offer persistent. A child may only offer Persistent if its parent do, which
- %% is why we must check the following:
- %%
- %% # Persistent Change to Best Effort
- %% _____
- %% | | (1) -> Check if children BE
- %% |Chann| (2) ok <-
- %% -----
- %% |
- %% _____
- %% | | (3) -> Check if children BE
- %% |Admin| (4) Check if parent Pers. <-
- %% -----
- %% |
- %% _____
- %% | | (5) -> ok
- %% |Proxy| (6) Check if parent Pers. <-
- %% -----
- %% NOTE: a parent always exists but we may change the QoS before creating any
- %% childrens. The cases (2) and (5) is always ok, i.e., no need to confirm
- %% with parent or children.
-
- %% We only have a channel. At the moment we can set ConnectionReliability
- %% without asking anyone.
- Q1='CosNotification_QoSAdmin':get_qos(Ch),
- ?match({ok, _}, 'CosNotification_QoSAdmin':validate_qos(Ch, QoSBestEffort)),
-
- ?match(ok, 'CosNotification_QoSAdmin':set_qos(Ch, QoSPersistent)),
- %% Match if no problems occur if we try to set QoS as is.
- ?match(ok, 'CosNotification_QoSAdmin':set_qos(Ch, QoSPersistent)),
-
- %% Check validate.
- ?match(ok, 'CosNotification_QoSAdmin':set_qos(Ch, QoSEventPersistent)),
- ?match({ok, _}, 'CosNotification_QoSAdmin':validate_qos(Ch, QoSOKTimout)),
- ?match({ok, _}, 'CosNotification_QoSAdmin':validate_qos(Ch, QoSEventBestEffort)),
- ?match(ok, 'CosNotification_QoSAdmin':set_qos(Ch, QoSEventBestEffort)),
- ?match({ok, _}, 'CosNotification_QoSAdmin':validate_qos(Ch, QoSOKTimout)),
-
- Q2='CosNotification_QoSAdmin':get_qos(Ch),
- ?match(ok, 'CosNotification_QoSAdmin':set_qos(Ch, QoSBestEffort)),
- ?match(Q1, 'CosNotification_QoSAdmin':get_qos(Ch)),
-
- %% Now we add an Admin object. An Admin object cannot switch ConnectionReliability
- %% to BestEffort without checking with its children or Persistent without
- %% confirming this with its Parent. At the moment, however, we only have a parent.
- {CAdm, Id2} = 'CosNotifyChannelAdmin_EventChannel':new_for_consumers(Ch, 'AND_OP'),
- ?match(Q1,'CosNotification_QoSAdmin':get_qos(CAdm)),
- ?match({'EXCEPTION',{'CosNotification_UnsupportedQoS',_,_}},
- 'CosNotification_QoSAdmin':set_qos(CAdm, QoSPersistent)),
- ?match(Q1, 'CosNotification_QoSAdmin':get_qos(CAdm)),
- ?match(ok, 'CosNotification_QoSAdmin':set_qos(CAdm, QoSBestEffort)),
- ?match(Q1, 'CosNotification_QoSAdmin':get_qos(CAdm)),
-
- %% Check if we can extract the Admin from the channel correctly.
- ?match([0,Id2],'CosNotifyChannelAdmin_EventChannel':get_all_consumeradmins(Ch)),
- ?match(CAdm,'CosNotifyChannelAdmin_EventChannel':get_consumeradmin(Ch, Id2)),
- ?match(Ch, 'CosNotifyChannelAdmin_ConsumerAdmin':'_get_MyChannel'(CAdm)),
- ?match(Id2, 'CosNotifyChannelAdmin_ConsumerAdmin':'_get_MyID'(CAdm)),
-
- %% Change the channel to provide Persistent service. Now we can set the
- %% Admin service to Persistent to. (4)
- ?match(ok, 'CosNotification_QoSAdmin':set_qos(Ch, QoSPersistent)),
- ?match(ok, 'CosNotification_QoSAdmin':set_qos(CAdm, QoSPersistent)),
- ?match(Q2, 'CosNotification_QoSAdmin':get_qos(CAdm)),
-
- %% Since the Admin object now provide Persistent the Channel cannot switch
- %% to BestEffort. (1)
- ?match({'EXCEPTION',{'CosNotification_UnsupportedQoS',_,_}},
- 'CosNotification_QoSAdmin':set_qos(Ch, QoSBestEffort)),
- %% Should still match Persistent.
- ?match(Q2, 'CosNotification_QoSAdmin':get_qos(Ch)),
- {PSup, _Id3} = 'CosNotifyChannelAdmin_ConsumerAdmin':obtain_notification_push_supplier(CAdm, 'ANY_EVENT'),
- ?match(Q2, 'CosNotification_QoSAdmin':get_qos(CAdm)),
- ?match('PUSH_ANY', 'CosNotifyChannelAdmin_ProxyPushConsumer':'_get_MyType'(PSup)),
- ?match(CAdm, 'CosNotifyChannelAdmin_ProxyPushConsumer':'_get_MyAdmin'(PSup)),
- ?match(Q2, 'CosNotification_QoSAdmin':get_qos(PSup)),
-
- %% At this point they all offer persistent connection, which means we have
- %% to start with the proxy if we want to change to Best Effort. Hence,
- %% the following two cases will fail.
- ?match({'EXCEPTION',{'CosNotification_UnsupportedQoS',_,_}},
- 'CosNotification_QoSAdmin':set_qos(Ch, QoSBestEffort)),
- ?match({'EXCEPTION',{'CosNotification_UnsupportedQoS',_,_}},
- 'CosNotification_QoSAdmin':set_qos(CAdm, QoSBestEffort)),
- ?match(ok, 'CosNotification_QoSAdmin':set_qos(PSup, QoSBestEffort)),
- %% Still not possible to change channel to Best Effort.
- ?match({'EXCEPTION',{'CosNotification_UnsupportedQoS',_,_}},
- 'CosNotification_QoSAdmin':set_qos(Ch, QoSBestEffort)),
- ?match(ok, 'CosNotification_QoSAdmin':set_qos(CAdm, QoSBestEffort)),
- %% Now we change the channel to Best Effort.
- ?match(ok, 'CosNotification_QoSAdmin':set_qos(Ch, QoSBestEffort)),
-
- %% Test if really are Best Effort
- ?match(Q1, 'CosNotification_QoSAdmin':get_qos(Ch)),
- ?match(Q1, 'CosNotification_QoSAdmin':get_qos(CAdm)),
- ?match(Q1, 'CosNotification_QoSAdmin':get_qos(PSup)),
-
- %% Testing MaximumBatchSize (The highest value is defined in
- %% CosNotification_Common.erl
- ?match(ok, 'CosNotification_QoSAdmin':set_qos(Ch, QoSOKMaxBatchSize)),
- ?match({'EXCEPTION',{'CosNotification_UnsupportedQoS',_,_}},
- 'CosNotification_QoSAdmin':set_qos(Ch, QoSToHighMaxBatchSize)),
- ?match({'EXCEPTION',{'CosNotification_UnsupportedQoS',_,_}},
- 'CosNotification_QoSAdmin':set_qos(Ch, QoSToLowMaxBatchSize)),
-
- ?match(ok, 'CosNotification_QoSAdmin':set_qos(Ch, QoSOKStartTimeSupp)),
- ?match(ok, 'CosNotification_QoSAdmin':set_qos(Ch, QoSOKStopTimeSupp)),
- ?match({'EXCEPTION',{'CosNotification_UnsupportedQoS',_,_}},
- 'CosNotification_QoSAdmin':set_qos(Ch, QoSWrongStartTimeSupp)),
- ?match({'EXCEPTION',{'CosNotification_UnsupportedQoS',_,_}},
- 'CosNotification_QoSAdmin':set_qos(Ch, QoSWrongStopTimeSupp)),
-
- catch corba:dispose(CAdm),
- catch corba:dispose(PSup),
- catch corba:dispose(Ch),
- cosNotificationApp:stop_factory(Fac),
- ok.
-
-%%-----------------------------------------------------------------
-%% QoSAdm API tests
-%%-----------------------------------------------------------------
-event_qos_api(_Config) ->
- Fac = (catch cosNotificationApp:start_global_factory(?FAC_OPT)),
- ?match({_,key,_,_,_,_}, Fac),
-
- %% Create some objects to test with. We start with default settings.
- {Ch, _Id1} = (catch 'CosNotifyChannelAdmin_EventChannelFactory':create_channel(Fac, ?defaultQoS, ?defaultAdm)),
- {CAdm, _Id2} = 'CosNotifyChannelAdmin_EventChannel':new_for_consumers(Ch, 'AND_OP'),
- {PSup, _Id3} = 'CosNotifyChannelAdmin_ConsumerAdmin':obtain_notification_push_supplier(CAdm, 'ANY_EVENT'),
-
- %% Try setting an unsupported QoS.
- ?match({'EXCEPTION',{'CosNotification_UnsupportedQoS',_,_}},
- 'CosNotifyChannelAdmin_ProxyConsumer':
- validate_event_qos(PSup,
- [#'CosNotification_Property'{name="Unsupported QoS",
- value=any:create(orber_tc:short(), 1)}])),
- %% Try setting min and max priority.
- ?match({ok, _}, 'CosNotifyChannelAdmin_ProxyConsumer':
- validate_event_qos(PSup,
- [#'CosNotification_Property'{name=?not_Priority,
- value=any:create(orber_tc:short(),
- ?not_LowestPriority)},
- #'CosNotification_Property'{name=?not_Priority,
- value=any:create(orber_tc:short(),
- ?not_HighestPriority)}])),
- %% Try setting priority values which are 1 to high and 1 to low respectively.
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- 'CosNotifyChannelAdmin_ProxyConsumer':
- validate_event_qos(PSup,
- [#'CosNotification_Property'{name=?not_Priority,
- value=any:create(orber_tc:short(),
- ?not_LowestPriority-1)},
- #'CosNotification_Property'{name=?not_Priority,
- value=any:create(orber_tc:short(),
- ?not_HighestPriority+1)}])),
- %% Try setting start- and stop-time (false default). Note the value associated
- %% with this property is not really a short but that is not what we are testing
- %% here so...
- ?match({'EXCEPTION',{'CosNotification_UnsupportedQoS',_,_}},
- 'CosNotifyChannelAdmin_ProxyConsumer':
- validate_event_qos(PSup,
- [#'CosNotification_Property'{name=?not_StartTime,
- value=any:create(orber_tc:short(), 0)}])),
- ?match({'EXCEPTION',{'CosNotification_UnsupportedQoS',_,_}},
- 'CosNotifyChannelAdmin_ProxyConsumer':
- validate_event_qos(PSup,
- [#'CosNotification_Property'{name=?not_StopTime,
- value=any:create(orber_tc:short(), 0)}])),
- %% Allow StopTime
- ?match(ok, 'CosNotification_QoSAdmin':set_qos(PSup, [#'CosNotification_Property'{name='CosNotification':'StopTimeSupported'(),
- value=any:create(orber_tc:boolean(), true)}])),
- ?match({ok,_},
- 'CosNotifyChannelAdmin_ProxyConsumer':
- validate_event_qos(PSup,
- [#'CosNotification_Property'{name=?not_StopTime,
- value=any:create(orber_tc:short(), 0)}])),
- %% Allow StartTime
- ?match(ok, 'CosNotification_QoSAdmin':set_qos(PSup, [#'CosNotification_Property'{name='CosNotification':'StartTimeSupported'(),
- value=any:create(orber_tc:boolean(), true)}])),
- ?match({ok,_},
- 'CosNotifyChannelAdmin_ProxyConsumer':
- validate_event_qos(PSup,
- [#'CosNotification_Property'{name=?not_StopTime,
- value=any:create(orber_tc:short(), 0)},
- #'CosNotification_Property'{name=?not_StartTime,
- value=any:create(orber_tc:short(), 0)}])),
-
- %% We must reset StopTime since we cannot guarantee that an event will be delivered
- %% if risk beeing discarded due to a delay.
- ?match(ok, 'CosNotification_QoSAdmin':set_qos(PSup, [#'CosNotification_Property'{name='CosNotification':'StopTimeSupported'(),
- value=any:create(orber_tc:boolean(), false)}])),
- %% Does it accept Best Effort EventReliability? Must always be true.
- ?match({ok,_},
- 'CosNotifyChannelAdmin_ProxyConsumer':
- validate_event_qos(PSup,
- [#'CosNotification_Property'{name=?not_EventReliability,
- value=any:create(orber_tc:short(), ?not_BestEffort)}])),
- %% Default is Best Effort; test if we can set Persistent EventReliability.
- ?match({'EXCEPTION',{'CosNotification_UnsupportedQoS',_,_}},
- 'CosNotifyChannelAdmin_ProxyConsumer':
- validate_event_qos(PSup,
- [#'CosNotification_Property'{name=?not_EventReliability,
- value=any:create(orber_tc:short(), ?not_Persistent)}])),
-
- %% Set Persistent
- QoSPersistent = [#'CosNotification_Property'{name='CosNotification':'ConnectionReliability'(),
- value=any:create(orber_tc:short(),
- 'CosNotification':'Persistent'())}],
- ?match(ok, 'CosNotification_QoSAdmin':set_qos(Ch, QoSPersistent)),
- ?match(ok, 'CosNotification_QoSAdmin':set_qos(CAdm, QoSPersistent)),
- ?match(ok, 'CosNotification_QoSAdmin':set_qos(PSup, QoSPersistent)),
-
- %% Does it accept Best Effort EventReliability? Must always be true.
- ?match({ok, _},
- 'CosNotifyChannelAdmin_ProxyConsumer':
- validate_event_qos(PSup,
- [#'CosNotification_Property'{name=?not_EventReliability,
- value=any:create(orber_tc:short(), ?not_BestEffort)}])),
- %% Test if we can use Persistent EventReliability.
- ?match({'EXCEPTION',{'CosNotification_UnsupportedQoS',_,_}},
- 'CosNotifyChannelAdmin_ProxyConsumer':
- validate_event_qos(PSup,
- [#'CosNotification_Property'{name=?not_EventReliability,
- value=any:create(orber_tc:short(), ?not_Persistent)}])),
- QoSEventPersistent = [#'CosNotification_Property'{name='CosNotification':'EventReliability'(),
- value=any:create(orber_tc:short(),
- 'CosNotification':'Persistent'())}],
- ?match(ok, 'CosNotification_QoSAdmin':set_qos(Ch, QoSEventPersistent)),
- ?match({'EXCEPTION',{'CosNotification_UnsupportedQoS',_,_}},
- 'CosNotification_QoSAdmin':set_qos(CAdm, QoSEventPersistent)),
- ?match({'EXCEPTION',{'CosNotification_UnsupportedQoS',_,_}},
- 'CosNotification_QoSAdmin':set_qos(PSup, QoSEventPersistent)),
-
- ?match(ok, 'CosNotification_QoSAdmin':set_qos(PSup, [#'CosNotification_Property'{name='CosNotification':'StopTimeSupported'(),
- value=any:create(orber_tc:boolean(), true)}])),
- ?match({ok,_},
- 'CosNotifyChannelAdmin_ProxyConsumer':
- validate_event_qos(PSup,
- [#'CosNotification_Property'{name=?not_StopTime,
- value=any:create(orber_tc:short(), 0)},
- #'CosNotification_Property'{name=?not_StartTime,
- value=any:create(orber_tc:short(), 0)}])),
- catch corba:dispose(CAdm),
- catch corba:dispose(PSup),
- catch corba:dispose(Ch),
- cosNotificationApp:stop_factory(Fac),
- ok.
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-
-%%-------------------- End of Module ------------------------------
diff --git a/lib/cosNotification/test/notify_test_impl.erl b/lib/cosNotification/test/notify_test_impl.erl
deleted file mode 100644
index 6c833f4915..0000000000
--- a/lib/cosNotification/test/notify_test_impl.erl
+++ /dev/null
@@ -1,300 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : notify_test_impl.erl
-%%----------------------------------------------------------------------
-
--module(notify_test_impl).
-
--include_lib("orber/include/corba.hrl").
--include("idl_output/notify_test.hrl").
-
-%%--------------- specified functions ------------------------
--export([stop_normal/2,
- stop_brutal/2,
- print/2,
- doAction/3,
- delay/5,
- %% Exports from CosNotifyComm::StructuredPushConsumer
- push_structured_event/3, disconnect_structured_push_consumer/2,
- %% Exports from "CosNotifyComm::SequencePushConsumer"
- push_structured_events/3, disconnect_sequence_push_consumer/2,
- %% Exports from CosEventComm::PushConsumer
- push/3, disconnect_push_consumer/2,
- %% Exports from CosNotifyComm::NotifyPublish
- disconnect_sequence_pull_consumer/2,
- %% Exports from CosNotifyComm::StructuredPullConsumer
- disconnect_structured_pull_consumer/2,
- %% Exports from CosEventComm::PullConsumer
- disconnect_pull_consumer/2,
- %% Exports from CosNotifyComm::SequencePushSupplier
- disconnect_sequence_push_supplier/2,
- %% Exports from CosNotifyComm::StructuredPushSupplier
- disconnect_structured_push_supplier/2,
- %% Exports from CosEventComm::PushSupplier
- disconnect_push_supplier/2,
- %% Exports from CosNotifyComm::SequencePullSupplier
- pull_structured_events/3,
- try_pull_structured_events/3,
- disconnect_sequence_pull_supplier/2,
- %% Exports from CosNotifyComm::StructuredPullSupplier
- pull_structured_event/2,
- try_pull_structured_event/2,
- disconnect_structured_pull_supplier/2,
- %% Exports from CosEventComm::PullSupplier
- pull/2,
- try_pull/2,
- disconnect_pull_supplier/2,
- %% Exports from CosNotifyComm::SequencePullConsumer
- offer_change/4,
- %% Exports from CosNotifyComm::NotifySubscribe
- subscription_change/4]).
-
-%%--------------- gen_server specific ------------------------
--export([init/1, terminate/2]).
--export([handle_call/3, handle_cast/2, handle_info/2, code_change/3]).
-%% Data structures
--record(state, {myType, proxy, data, action}).
-
-%%--------------- LOCAL DATA ---------------------------------
-
-%%------------------------------------------------------------
-%% function : init, terminate
-%%------------------------------------------------------------
-init([MyType, Proxy]) ->
- process_flag(trap_exit,true),
- {ok, #state{myType=MyType, proxy=Proxy, data=[]}}.
-
-terminate(Reason, State) ->
- io:format("notify_test:terminate(~p ~p)~n",[Reason, State#state.myType]),
- ok.
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-handle_call(_,_, State) ->
- {noreply, State}.
-handle_cast(_, State) ->
- {noreply, State}.
-handle_info(_Info, State) ->
- {noreply, State}.
-
-%%--------------- SERVER FUNCTIONS ---------------------------
-
-print(Self, State) ->
- io:format("notify_test:print(~p ~p)~n",[Self, State]),
- {reply, ok, State}.
-
-doAction(_Self, State, {set_data, Data}) ->
- io:format("notify_test:doAction(add_data) ~p~n",[Data]),
- {reply, ok, State#state{data=Data}};
-doAction(_Self, State, {add_data, Data}) ->
- io:format("notify_test:doAction(add_data) ~p~n",[Data]),
- {reply, ok, State#state{data=State#state.data++Data}};
-doAction(_Self, State, return_data) ->
- io:format("notify_test:doAction(return_data)~n",[]),
- {reply, State#state.data, State#state{data=[]}};
-doAction(_Self, State, clear_data) ->
- io:format("notify_test:doAction(return_data)~n",[]),
- {reply, ok, State#state{data=[]}};
-doAction(_Self, State, pull_any) ->
- io:format("notify_test:doAction(pull_any)~n",[]),
- Event='CosNotifyChannelAdmin_ProxyPullSupplier':pull(State#state.proxy),
- {reply, Event, State};
-doAction(_Self, State, {pull_seq, Max}) ->
- io:format("notify_test:doAction(pull_sequence)~n",[]),
- Event='CosNotifyChannelAdmin_SequenceProxyPullSupplier':pull_structured_events(State#state.proxy, Max),
- {reply, Event, State};
-doAction(_Self, State, pull_str) ->
- Event='CosNotifyChannelAdmin_StructuredProxyPullSupplier':pull_structured_event(State#state.proxy),
- io:format("notify_test:doAction(pull_structured)~n",[]),
- {reply, Event, State};
-doAction(_Self, State, try_pull_any) ->
- io:format("notify_test:doAction(try_pull_any)~n",[]),
- Event='CosNotifyChannelAdmin_ProxyPullSupplier':try_pull(State#state.proxy),
- {reply, Event, State};
-doAction(_Self, State, {try_pull_seq, Max}) ->
- io:format("notify_test:doAction(try_pull_sequence)~n",[]),
- Event='CosNotifyChannelAdmin_SequenceProxyPullSupplier':try_pull_structured_events(State#state.proxy, Max),
- {reply, Event, State};
-doAction(_Self, State, try_pull_str) ->
- Event='CosNotifyChannelAdmin_StructuredProxyPullSupplier':try_pull_structured_event(State#state.proxy),
- io:format("notify_test:doAction(try_pull_structured)~n",[]),
- {reply, Event, State};
-doAction(_Self, State, {action, Action}) ->
- io:format("notify_test:doAction(~p)~n",[Action]),
- {reply, ok, State#state{action = Action}};
-
-doAction(_, State, _) ->
- {reply, nop, State}.
-
-stop_normal(_Self, State) ->
- {stop, normal, ok, State}.
-
-stop_brutal(_Self, _State) ->
- exit("killed_brutal").
-
-
-
-%%--------------- CosNotifyComm::NotifyPublish --------
-offer_change(_Self, State, Added, Removed) ->
- ND=loop(Removed, State#state.data),
- ND2=Added++ND,
- {reply, ok, State#state{data=ND2}}.
-
-loop([],Data) ->
- Data;
-loop([H|T], Data) ->
- ND=lists:delete(H,Data),
- loop(T, ND).
-
-%%--------------- CosNotifyComm::NotifySubscribe --------
-subscription_change(_Self, State, Added, Removed) ->
- ND=loop(Removed, State#state.data),
- ND2=Added++ND,
- {reply, ok, State#state{data=ND2}}.
-
-%%--------------- CosNotifyComm::SequencePushConsumer --------
-push_structured_events(_Self, #state{action = undefined} = State, Event) ->
- io:format("notify_test:push_structured_events(~p)~n",[Event]),
- {reply, ok, State#state{data=State#state.data++Event}};
-push_structured_events(_Self, #state{action = Action} = State, Event) ->
- io:format("notify_test:push_structured_events(~p)~nAction: ~p~n",
- [Event, Action]),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}),
- {reply, ok, State#state{data=State#state.data++Event}}.
-disconnect_sequence_push_consumer(_Self, State) ->
- io:format("disconnect_sequence_push_consumer~n",[]),
- {stop, normal, ok, State}.
-
-%%--------------- CosNotifyComm::StructuredPushConsumer --------
-push_structured_event(_Self, State, Event) ->
- io:format("notify_test:push_structured_event(~p)~n",[Event]),
- {reply, ok, State#state{data=State#state.data++[Event]}}.
-disconnect_structured_push_consumer(_Self, State) ->
- io:format("disconnect_structured_push_consumer~n",[]),
- {stop, normal, ok, State}.
-
-%%--------------- CosEventComm::PushConsumer --------
-push(_Self, State, Event) ->
- io:format("notify_test:push(~p)~n",[Event]),
- {reply, ok, State#state{data=State#state.data++[Event]}}.
-disconnect_push_consumer(_Self, State) ->
- io:format("disconnect_push_consumer~n",[]),
- {stop, normal, ok, State}.
-
-%%--------------- CosNotifyComm::SequencePullConsumer --------
-disconnect_sequence_pull_consumer(_Self, State) ->
- io:format("disconnect_sequence_pull_consumer~n",[]),
- {stop, normal, ok, State}.
-
-%%--------------- CosNotifyComm::StructuredPullConsumer --------
-disconnect_structured_pull_consumer(_Self, State) ->
- io:format("disconnect_structured_pull_consumer~n",[]),
- {stop, normal, ok, State}.
-
-%%--------------- CosEventComm::PullConsumer --------
-disconnect_pull_consumer(_Self, State) ->
- io:format("disconnect_pull_consumer~n",[]),
- {stop, normal, ok, State}.
-
-%%--------------- CosNotifyComm::SequencePushSupplier --------
-disconnect_sequence_push_supplier(_Self, State) ->
- io:format("disconnect_sequence_push_supplier~n",[]),
- {stop, normal, ok, State}.
-
-%%--------------- CosNotifyComm::StructuredPushSupplier --------
-disconnect_structured_push_supplier(_Self, State) ->
- io:format("disconnect_structured_push_supplier~n",[]),
- {stop, normal, ok, State}.
-
-%%--------------- CosEventComm::PushSupplier --------
-disconnect_push_supplier(_Self, State) ->
- io:format("disconnect_push_supplier~n",[]),
- {stop, normal, ok, State}.
-
-%%--------------- CosNotifyComm::SequencePullSupplier --------
-pull_structured_events(_Self, State, _Max) ->
- io:format("notify_test:pullstructured_events()~n",[]),
- {reply, ok, State}.
-try_pull_structured_events(_Self, State, Max) ->
- io:format("notify_test:try_pull_structured_events()~n",[]),
- case State#state.data of
- [] ->
- {reply, {[],false}, State};
- List ->
- R = split(List,Max),
- {reply, {lists:sublist(List, Max), true}, State#state{data=R}}
- end.
-
-split([],_) ->
- [];
-split(R,0) ->
- R;
-split([_H|T],Max) ->
- split(T, Max-1).
-
-disconnect_sequence_pull_supplier(_Self, State) ->
- io:format("disconnect_sequence_pull_supplier~n",[]),
- {stop, normal, ok, State}.
-
-%%--------------- CosNotifyComm::StructuredPullSupplier --------
-pull_structured_event(_Self, State) ->
- io:format("notify_test:pull_structured_event()~n",[]),
- {reply, ok, State}.
-try_pull_structured_event(_Self, State) ->
- io:format("notify_test:try_pull_structured_event()~n",[]),
- case State#state.data of
- [] ->
- {reply, {[],false}, State};
- [H|T] ->
- {reply, {H, true}, State#state{data=T}}
- end.
-disconnect_structured_pull_supplier(_Self, State) ->
- io:format("disconnect_structured_pull_supplier~n",[]),
- {stop, normal, ok, State}.
-
-%%--------------- CosEventComm::PullSupplier --------
-pull(_Self, State) ->
- io:format("notify_test:pull()~n",[]),
- {reply, 'CosEventComm_PullSupplier':pull(State#state.proxy), State}.
-try_pull(_Self, State) ->
- io:format("notify_test:try_pull()~n",[]),
- case State#state.data of
- [] ->
- {reply, {[],false}, State};
- [H|T] ->
- {reply, {H, true}, State#state{data=T}}
- end.
-disconnect_pull_supplier(_Self, State) ->
- io:format("disconnect_pull_supplier~n",[]),
- {stop, normal, ok, State}.
-
-%%--------------- LOCAL FUNCTIONS ----------------------------
-
-delay(Obj, Event, Time, Mod, F) ->
- io:format("notify_test:delay(~p) TIME: ~p~n",[Event, erlang:timestamp()]),
- timer:sleep(Time),
- Mod:F(Obj, Event),
- io:format("notify_test:delay() DONE: ~p~n",[erlang:timestamp()]),
- ok.
-
-%%--------------- END OF MODULE ------------------------------
-
diff --git a/lib/cosNotification/test/notify_test_server.cfg b/lib/cosNotification/test/notify_test_server.cfg
deleted file mode 100644
index 60f50b23bb..0000000000
--- a/lib/cosNotification/test/notify_test_server.cfg
+++ /dev/null
@@ -1,55 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-{this, "notify_test::SeqPushC"}.
-{{handle_info, "notify_test::SeqPushC"}, true}.
-{{impl, "notify_test::SeqPushC"}, "notify_test_impl"}.
-{this, "notify_test::StrPushC"}.
-{{handle_info, "notify_test::StrPushC"}, true}.
-{{impl, "notify_test::StrPushC"}, "notify_test_impl"}.
-{this, "notify_test::AnyPushC"}.
-{{handle_info, "notify_test::AnyPushC"}, true}.
-{{impl, "notify_test::AnyPushC"}, "notify_test_impl"}.
-{this, "notify_test::SeqPullC"}.
-{{handle_info, "notify_test::SeqPullC"}, true}.
-{{impl, "notify_test::SeqPullC"}, "notify_test_impl"}.
-{this, "notify_test::StrPullC"}.
-{{handle_info, "notify_test::StrPullC"}, true}.
-{{impl, "notify_test::StrPullC"}, "notify_test_impl"}.
-{this, "notify_test::AnyPullC"}.
-{{handle_info, "notify_test::AnyPullC"}, true}.
-{{impl, "notify_test::AnyPullC"}, "notify_test_impl"}.
-{this, "notify_test::SeqPushS"}.
-{{handle_info, "notify_test::SeqPushS"}, true}.
-{{impl, "notify_test::SeqPushS"}, "notify_test_impl"}.
-{this, "notify_test::StrPushS"}.
-{{handle_info, "notify_test::StrPushS"}, true}.
-{{impl, "notify_test::StrPushS"}, "notify_test_impl"}.
-{this, "notify_test::AnyPushS"}.
-{{handle_info, "notify_test::AnyPushS"}, true}.
-{{impl, "notify_test::AnyPushS"}, "notify_test_impl"}.
-{this, "notify_test::SeqPullS"}.
-{{handle_info, "notify_test::SeqPullS"}, true}.
-{{impl, "notify_test::SeqPullS"}, "notify_test_impl"}.
-{this, "notify_test::StrPullS"}.
-{{handle_info, "notify_test::StrPullS"}, true}.
-{{impl, "notify_test::StrPullS"}, "notify_test_impl"}.
-{this, "notify_test::AnyPullS"}.
-{{handle_info, "notify_test::AnyPullS"}, true}.
-{{impl, "notify_test::AnyPullS"}, "notify_test_impl"}.
diff --git a/lib/cosNotification/test/notify_test_server.idl b/lib/cosNotification/test/notify_test_server.idl
deleted file mode 100644
index 0334d67717..0000000000
--- a/lib/cosNotification/test/notify_test_server.idl
+++ /dev/null
@@ -1,114 +0,0 @@
-//
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1999-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-//
-
-#ifndef _NOTIFY_TEST_SERVER_IDL
-#define _NOTIFY_TEST_SERVER_IDL
-
-#include <CosNotification.idl>
-#include <CosNotifyComm.idl>
-
-module notify_test {
-
- enum action {PULL_SEQ, PULL_STR, PULL_ANY, PUSH_SEQ, PUSH_STR, PUSH_ANY};
-
- struct data {
- short score;
- string name;
- };
-
- struct computer {
- float memsize;
- float cputime;
- float filesize;
- };
-
- struct X {
- long A;
- string B;
- short C;
- };
-
-
- union K switch(short) {
- case -1: short neg;
- case 0:
- case 2: string K;
- case 3: X L;
- case 5: long M;
- default: short N;
- };
-
- union uni1 switch(long) {
- case 1:
- case 2: long lo;
- case 3: short sh;
- default: short defvalue;
- };
-
- union uni2 switch(long) {
- case 1:
- case 2: long lo;
- case 3: short sh;
- };
-
- typedef any namedAny;
- typedef short ShortArray[4];
- struct studies {
- uni1 uni1;
- CosNotification::PropertySeq tests;
- ShortArray monthly_attendance;
- short gpa;
- };
-
- interface funcs {
- void print();
- void doAction(in action Act);
- };
-
- // interface server
- interface SeqPushC : funcs, CosNotifyComm::SequencePushConsumer {
- };
- interface StrPushC : funcs, CosNotifyComm::StructuredPushConsumer {
- };
- interface AnyPushC : funcs, CosEventComm::PushConsumer {
- };
- interface SeqPullC : funcs, CosNotifyComm::SequencePullConsumer {
- };
- interface StrPullC : funcs, CosNotifyComm::StructuredPullConsumer {
- };
- interface AnyPullC : funcs, CosEventComm::PullConsumer {
- };
-
- interface SeqPushS : funcs, CosNotifyComm::SequencePushSupplier {
- };
- interface StrPushS : funcs, CosNotifyComm::StructuredPushSupplier {
- };
- interface AnyPushS : funcs, CosEventComm::PushSupplier {
- };
- interface SeqPullS : funcs, CosNotifyComm::SequencePullSupplier {
- };
- interface StrPullS : funcs, CosNotifyComm::StructuredPullSupplier {
- };
- interface AnyPullS : funcs, CosEventComm::PullSupplier {
- };
-
-};
-
-#endif
diff --git a/lib/cosNotification/vsn.mk b/lib/cosNotification/vsn.mk
deleted file mode 100644
index 1677057670..0000000000
--- a/lib/cosNotification/vsn.mk
+++ /dev/null
@@ -1,2 +0,0 @@
-COSNOTIFICATION_VSN = 1.2.3
-
diff --git a/lib/cosProperty/AUTHORS b/lib/cosProperty/AUTHORS
deleted file mode 100644
index 55d8059989..0000000000
--- a/lib/cosProperty/AUTHORS
+++ /dev/null
@@ -1,4 +0,0 @@
-Original Authors:
-Niclas Eklund
-
-Contributors:
diff --git a/lib/cosProperty/Makefile b/lib/cosProperty/Makefile
deleted file mode 100644
index 44d1aafade..0000000000
--- a/lib/cosProperty/Makefile
+++ /dev/null
@@ -1,42 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2000-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include vsn.mk
-VSN=$(COSPROPERTY_VSN)
-
-# ----------------------------------------------------
-# Common Macros
-# ----------------------------------------------------
-# SUB_DIRECTORIES = src test examples doc/src
-# At the moment we don't have any example programs.
-SUB_DIRECTORIES = src doc/src
-
-SPECIAL_TARGETS =
-
-# ----------------------------------------------------
-# Default Subdir Targets
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_subdir.mk
diff --git a/lib/cosProperty/doc/html/.gitignore b/lib/cosProperty/doc/html/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosProperty/doc/html/.gitignore
+++ /dev/null
diff --git a/lib/cosProperty/doc/man3/.gitignore b/lib/cosProperty/doc/man3/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosProperty/doc/man3/.gitignore
+++ /dev/null
diff --git a/lib/cosProperty/doc/man6/.gitignore b/lib/cosProperty/doc/man6/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosProperty/doc/man6/.gitignore
+++ /dev/null
diff --git a/lib/cosProperty/doc/pdf/.gitignore b/lib/cosProperty/doc/pdf/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosProperty/doc/pdf/.gitignore
+++ /dev/null
diff --git a/lib/cosProperty/doc/src/CosPropertyService_PropertiesIterator.xml b/lib/cosProperty/doc/src/CosPropertyService_PropertiesIterator.xml
deleted file mode 100644
index 62a1732e99..0000000000
--- a/lib/cosProperty/doc/src/CosPropertyService_PropertiesIterator.xml
+++ /dev/null
@@ -1,95 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>CosPropertyService_PropertiesIterator</title>
- <prepared></prepared>
- <docno></docno>
- <checked></checked>
- <date>2000-07-25</date>
- <rev>1.0</rev>
- </header>
- <module>CosPropertyService_PropertiesIterator</module>
- <modulesummary>This module implements the OMG CosPropertyService::PropertiesIterator interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosProperty/include/CosPropertyService.hrl").</c></p>
- </description>
- <funcs>
- <func>
- <name>reset(Iterator) -> ok</name>
- <fsummary>Reset the position to the first property</fsummary>
- <type>
- <v>Iterator = #objref</v>
- </type>
- <desc>
- <p>This operation resets the position to the first property. </p>
- </desc>
- </func>
- <func>
- <name>next_one(Iterator) -> Reply</name>
- <fsummary>Return true if a Property exists at the current position and the out parameter is a valid Property. Otherwise false and a non-valid property</fsummary>
- <type>
- <v>Iterator = #objref</v>
- <v>Reply = {boolean(), #'CosPropertyService_Property'{property_name = Name, property_value = Value}}</v>
- <v>Name = string()</v>
- <v>Value = #any</v>
- </type>
- <desc>
- <p>This operation returns true . If false is returned the out
- parameter is a non-valid Property.</p>
- </desc>
- </func>
- <func>
- <name>next_n(Iterator, HowMany) -> Reply</name>
- <fsummary>Return true if the requested number of properties can be delivered and there are additional properties. Otherwise false is returned and a sequence of max <c>HowMany</c>properties</fsummary>
- <type>
- <v>Iterator = #objref</v>
- <v>HowMany = long()</v>
- <v>Reply = {boolean(), Properties}</v>
- <v>Properties = [#'CosPropertyService_Property'{property_name = Name, property_value = Value}]</v>
- <v>Name = string()</v>
- <v>Value = #any</v>
- </type>
- <desc>
- <p>This operation returns true if the requested number of properties can be
- delivered and there are additional properties. If false is returned and a
- sequence of max <c>HowMany</c> properties will be returned and no more
- properties can be delivered. </p>
- </desc>
- </func>
- <func>
- <name>destroy(Iterator) -> ok</name>
- <fsummary>Terminate the target object</fsummary>
- <type>
- <v>Iterator = #objref</v>
- </type>
- <desc>
- <p>This operation will terminate the Iterator and all subsequent calls
- will fail. </p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosProperty/doc/src/CosPropertyService_PropertyNamesIterator.xml b/lib/cosProperty/doc/src/CosPropertyService_PropertyNamesIterator.xml
deleted file mode 100644
index 5948490547..0000000000
--- a/lib/cosProperty/doc/src/CosPropertyService_PropertyNamesIterator.xml
+++ /dev/null
@@ -1,97 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosPropertyService_PropertyNamesIterator</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>2000-07-25</date>
- <rev>1.0</rev>
- </header>
- <module>CosPropertyService_PropertyNamesIterator</module>
- <modulesummary>This module implements the OMG CosPropertyService::PropertyNamesIterator interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosProperty/include/CosPropertyService.hrl").</c></p>
- </description>
- <funcs>
- <func>
- <name>reset(Iterator) -> ok</name>
- <fsummary>Reset the position to the first property name</fsummary>
- <type>
- <v>Iterator = #objref</v>
- </type>
- <desc>
- <p>This operation resets the position to the first property name. </p>
- </desc>
- </func>
- <func>
- <name>next_one(Iterator) -> Reply</name>
- <fsummary>Return true if a Property Name exists at the current position and the out parameter is a valid Property Name. Otherwise false and a non-valid Property Name</fsummary>
- <type>
- <v>Iterator = #objref</v>
- <v>Reply = {boolean(), Name}</v>
- <v>Name = string()</v>
- </type>
- <desc>
- <p>This operation returns true if a Property Name exists at the current
- position and the out parameter is a valid Property Name.
- If false is returned the out parameter is a non-valid Property Name.</p>
- </desc>
- </func>
- <func>
- <name>next_n(Iterator, HowMany) -> Reply</name>
- <fsummary>Return <c>HowMany</c>Property Names and a boolean which is true if additional Property Names exists</fsummary>
- <type>
- <v>Iterator = #objref</v>
- <v>HowMany = long()</v>
- <v>Reply = {boolean(), [Name]}</v>
- <v>Name = string()</v>
- </type>
- <desc>
- <p>This operation returns true if the requested number of Property Names can be
- delivered and there are additional property names. If false is returned a
- sequence of max <c>HowMany</c> property names will be returned and no
- more Property Names can be delivered. </p>
- </desc>
- </func>
- <func>
- <name>destroy(Iterator) -> ok</name>
- <fsummary>Terminate the target object</fsummary>
- <type>
- <v>Iterator = #objref</v>
- </type>
- <desc>
- <p>This operation will terminate the Iterator and all subsequent calls
- will fail. </p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosProperty/doc/src/CosPropertyService_PropertySet.xml b/lib/cosProperty/doc/src/CosPropertyService_PropertySet.xml
deleted file mode 100644
index 8e7fbbd80a..0000000000
--- a/lib/cosProperty/doc/src/CosPropertyService_PropertySet.xml
+++ /dev/null
@@ -1,201 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosPropertyService_PropertySet</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>2000-07-25</date>
- <rev>1.0</rev>
- </header>
- <module>CosPropertyService_PropertySet</module>
- <modulesummary>This module implements the OMG CosPropertyService::PropertySet interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosProperty/include/CosPropertyService.hrl").</c></p>
- </description>
- <funcs>
- <func>
- <name>define_property(PropertySet, Name, Value) -> Reply</name>
- <fsummary>Add a new property to the target object</fsummary>
- <type>
- <v>PropertySet = #objref</v>
- <v>Name = non-empty string()</v>
- <v>Value = #any</v>
- <v>Reply = ok | {'EXCEPTION', #CosPropertyService_InvalidPropertyName{}} | {'EXCEPTION', #CosPropertyService_ConflictingProperty{}} | {'EXCEPTION', #CosPropertyService_UnsupportedTypeCode{}} | {'EXCEPTION', #CosPropertyService_UnsupportedProperty{}} | {'EXCEPTION', #CosPropertyService_ReadOnlyProperty{}}</v>
- </type>
- <desc>
- <p>This operation adds a new property to the given object. Depending on
- which initial arguments was supplied when starting the object several
- exceptions may be raised.</p>
- </desc>
- </func>
- <func>
- <name>define_properties(PropertySet, Properties) -> Reply</name>
- <fsummary>Add new properties to the target object</fsummary>
- <type>
- <v>PropertySet = #objref</v>
- <v>Properties = [#'CosPropertyService_Property'{property_name = Name, property_value = Value}]</v>
- <v>Name = string()</v>
- <v>Value = #any</v>
- <v>Reply = ok | {'EXCEPTION', #CosPropertyService_MultipleExceptions{exceptions = Excs}}</v>
- <v>Excs = [#'CosPropertyService_PropertyException{reason = Reason, failing_property_name = Name}]</v>
- <v>Reason = invalid_property_name | conflicting_property | property_not_found | unsupported_type_code | unsupported_property | unsupported_mode | fixed_property | read_only_property</v>
- </type>
- <desc>
- <p>This operation adds several new properties to the given object. Depending on
- which initial arguments was supplied when starting the object an
- exceptions may be raised listing the properties failing.</p>
- </desc>
- </func>
- <func>
- <name>get_number_of_properties(PropertySet) -> ulong()</name>
- <fsummary>Get the number of properties associated with the target object</fsummary>
- <type>
- <v>PropertySet = #objref</v>
- </type>
- <desc>
- <p>This operation returns the number of properties associated with the target
- object.</p>
- </desc>
- </func>
- <func>
- <name>get_all_property_names(PropertySet, Max) -> Reply</name>
- <fsummary>Get <c>Max</c>property names. If the target object have additional associated properties they will be put in the returned Iterator</fsummary>
- <type>
- <v>PropertySet = NamesIterator = #objref</v>
- <v>Max = ulong()</v>
- <v>Reply = {ok, Names, NamesIterator}</v>
- <v>Names = [string()]</v>
- </type>
- <desc>
- <p>This operation returns up to <c>Max</c> property names. If the target
- object have additional associated properties they will be put in the
- returned Iterator, otherwise the Iterator will be a <c>NIL</c> object.</p>
- </desc>
- </func>
- <func>
- <name>get_property_value(PropertySet, Name) -> Reply</name>
- <fsummary>Return the property value associated with given name</fsummary>
- <type>
- <v>PropertySet = #objref</v>
- <v>Name = string()</v>
- <v>Reply = #any | {'EXCEPTION', #CosPropertyService_PropertyNotFound{}} | {'EXCEPTION', #CosPropertyService_InvalidPropertyName{}}</v>
- </type>
- <desc>
- <p>This operation returns the property value associated with given name. If no such property
- exists or the given name is an empty string an exception will be raised.</p>
- </desc>
- </func>
- <func>
- <name>get_properties(PropertySet, Names) -> Reply</name>
- <fsummary>Return all properties associated with given names</fsummary>
- <type>
- <v>PropertySet = #objref</v>
- <v>Names = [string()]</v>
- <v>Reply = {boolean(), Properties}</v>
- <v>Properties = [#'CosPropertyService_Property'{property_name = Name, property_value = Value}]</v>
- </type>
- <desc>
- <p>This operation returns all properties associated with given names. If the
- boolean flag is true all properties where retrieved correctly, otherwise,
- all properties with the type <c>tk_void</c> was not found.</p>
- </desc>
- </func>
- <func>
- <name>get_all_properties(PropertySet, Max) -> Reply</name>
- <fsummary>Return a list <c>Max</c>properties or less. If more properties are associated with the target object they will be put in the<c>PropertiesIterator</c>.</fsummary>
- <type>
- <v>PropertySet = PropertiesIterator = #objref</v>
- <v>Reply = {ok, Properties, PropertiesIterator}</v>
- <v>Properties = [#'CosPropertyService_Property'{property_name = Name, property_value = Value}]</v>
- </type>
- <desc>
- <p>This operation return a list <c>Max</c> properties or less. If more
- properties are associated with the target object they will be put in the
- <c>PropertiesIterator</c>. If the object had less than <c>Max</c>
- associated properties the Iterator will be a <c>NIL</c> object.</p>
- </desc>
- </func>
- <func>
- <name>delete_property(PropertySet, Name) -> Reply</name>
- <fsummary>Delete the property with given Name</fsummary>
- <type>
- <v>PropertySet = #objref</v>
- <v>Name = string()</v>
- <v>Reply = ok | {'EXCEPTION', #CosPropertyService_FixedProperty{}} | {'EXCEPTION', #CosPropertyService_PropertyNotFound{}} | {'EXCEPTION', #CosPropertyService_InvalidPropertyName{}}</v>
- </type>
- <desc>
- <p>This operation tries to delete the property with given Name. An exception
- which indicates why it failed is raised if so needed.</p>
- </desc>
- </func>
- <func>
- <name>delete_properties(PropertySet, Names) -> Reply</name>
- <fsummary>Delete all properties with given Names</fsummary>
- <type>
- <v>PropertySet = #objref</v>
- <v>Names = [string()]</v>
- <v>Reply = ok | {'EXCEPTION', #CosPropertyService_MultipleExceptions{exceptions = Excs}}</v>
- <v>Excs = [#'CosPropertyService_PropertyException{reason = Reason, failing_property_name = Name}]</v>
- <v>Reason = invalid_property_name | conflicting_property | property_not_found | unsupported_type_code | unsupported_property | unsupported_mode | fixed_property | read_only_property</v>
- </type>
- <desc>
- <p>This operation tries to delete all given Properties. If one or more removal
- fails an exception is raised which describe why.</p>
- </desc>
- </func>
- <func>
- <name>delete_all_properties(PropertySet) -> boolean()</name>
- <fsummary>Delete all properties</fsummary>
- <type>
- <v>PropertySet = #objref</v>
- </type>
- <desc>
- <p>This operation deletes all properties. The boolean flag, if set to false,
- indicates that it was not possible to remove one or more properties, e.g.,
- may be read only.</p>
- </desc>
- </func>
- <func>
- <name>is_property_defined(PropertySet, Name) -> Reply</name>
- <fsummary>Return true if the target have an associated property with given name</fsummary>
- <type>
- <v>PropertySet = #objref</v>
- <v>Name = non-empty string()</v>
- <v>Reply = boolean() | {'EXCEPTION', #CosPropertyService_InvalidPropertyName{}}</v>
- </type>
- <desc>
- <p>This operation returns true if the target have an associated property with
- given name.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosProperty/doc/src/CosPropertyService_PropertySetDef.xml b/lib/cosProperty/doc/src/CosPropertyService_PropertySetDef.xml
deleted file mode 100644
index 2cbf2fc4f9..0000000000
--- a/lib/cosProperty/doc/src/CosPropertyService_PropertySetDef.xml
+++ /dev/null
@@ -1,168 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>CosPropertyService_PropertySetDef</title>
- <prepared></prepared>
- <docno></docno>
- <checked></checked>
- <date>2000-07-25</date>
- <rev>1.0</rev>
- </header>
- <module>CosPropertyService_PropertySetDef</module>
- <modulesummary>This module implements the OMG CosPropertyService::PropertySetDef interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosProperty/include/CosPropertyService.hrl").</c></p>
- <p>This module also exports the functions described in</p>
- <p><seealso marker="CosPropertyService_PropertySet">CosPropertyService_PropertySet</seealso></p>
- </description>
- <funcs>
- <func>
- <name>get_allowed_property_types(PropertySetDef) -> Reply</name>
- <fsummary>Return allowed TypeCodes for the target object</fsummary>
- <type>
- <v>PropertySetDef = #objref</v>
- <v>Reply = {ok, PropertyTypes}</v>
- <v>PropertyTypes = [CORBA::TypeCode]</v>
- </type>
- <desc>
- <p>This operation return the TypeCodes which we are allowed to use when adding
- new properties.</p>
- </desc>
- </func>
- <func>
- <name>get_allowed_properties(PropertySetDef) -> Reply</name>
- <fsummary>Return a sequence of the allowed properties</fsummary>
- <type>
- <v>PropertySetDef = #objref</v>
- <v>Reply = {ok, PropertyDefs}</v>
- <v>PropertyDefs = [#'CosPropertyService_PropertyDef'{property_name = Name, property_value = Value, property_mode = Mode}]</v>
- <v>Name = string()</v>
- <v>Value = #any</v>
- <v>Mode = normal | read_only | fixed_normal | fixed_readonly | undefined</v>
- </type>
- <desc>
- <p>This operation a sequence of the allowed properties we may alter; depends on
- which mode associated with a certain property.</p>
- </desc>
- </func>
- <func>
- <name>define_property_with_mode(PropertySetDef, Name, Value, Mode) -> Reply</name>
- <fsummary>Associate a new property with the target object</fsummary>
- <type>
- <v>PropertySetDef = #objref</v>
- <v>Name = non-empty string()</v>
- <v>Value = #any</v>
- <v>Mode = normal | read_only | fixed_normal | fixed_readonly | undefined</v>
- <v>Reply = ok | {'EXCEPTION', #CosPropertyService_InvalidPropertyName{}} | {'EXCEPTION', #CosPropertyService_ConflictingProperty{}} | {'EXCEPTION', #CosPropertyService_UnsupportedTypeCode{}} | {'EXCEPTION', #CosPropertyService_UnsupportedProperty{}} | {'EXCEPTION', #CosPropertyService_UnsupportedMode{}} | {'EXCEPTION', #CosPropertyService_ReadOnlyProperty{}}</v>
- </type>
- <desc>
- <p>This operation attempts to associate a new property with the target object.
- If we fail to do so the appropriate exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>define_properties_with_modes(PropertySetDef, PropertyDefs) -> Reply</name>
- <fsummary>Associate the given Property Definitions with the target object</fsummary>
- <type>
- <v>PropertySetDef = #objref</v>
- <v>PropertyDefs = [#'CosPropertyService_PropertyDef'{property_name = Name, property_value = Value, property_mode = Mode}]</v>
- <v>Name = string()</v>
- <v>Value = #any</v>
- <v>Mode = normal | read_only | fixed_normal | fixed_readonly | undefined</v>
- <v>Reply = ok | {'EXCEPTION', #CosPropertyService_MultipleExceptions{exceptions = Excs}}</v>
- <v>Excs = [#'CosPropertyService_PropertyException{reason = Reason, failing_property_name = Name}]</v>
- <v>Reason = invalid_property_name | conflicting_property | property_not_found | unsupported_type_code | unsupported_property | unsupported_mode | fixed_property | read_only_property</v>
- </type>
- <desc>
- <p>This operation attempts to associate the given Property Definitions with the
- target object. If one or more attempts fail an exception is raised
- describing which properties we where not able to create.</p>
- </desc>
- </func>
- <func>
- <name>get_property_mode(PropertySetDef, Name) -> Reply</name>
- <fsummary>Return the mode of the given property</fsummary>
- <type>
- <v>PropertySetDef = #objref</v>
- <v>Name = string()</v>
- <v>Reply = Mode | {'EXCEPTION', #CosPropertyService_InvalidPropertyName{}} | {'EXCEPTION', #CosPropertyService_PropertyNotFound{}}</v>
- <v>Mode = normal | read_only | fixed_normal | fixed_readonly | undefined</v>
- </type>
- <desc>
- <p>This operation returns the type of the given property.</p>
- </desc>
- </func>
- <func>
- <name>get_property_modes(PropertySetDef, Names) -> Reply</name>
- <fsummary>Return the modes of the given properties</fsummary>
- <type>
- <v>PropertySetDef = #objref</v>
- <v>Names = [string()]</v>
- <v>Reply = {boolean(), PropertyModes}</v>
- <v>PropertyModes = [#'CosPropertyService_PropertyMode'{property_name = Name, property_mode = Mode}]</v>
- <v>Name = string()</v>
- <v>Mode = normal | read_only | fixed_normal | fixed_readonly | undefined</v>
- </type>
- <desc>
- <p>This operation returns the modes of the listed properties. If the boolean
- flag is false, all properties with mode <c>undefined</c> this operation
- failed to comply.</p>
- </desc>
- </func>
- <func>
- <name>set_property_mode(PropertySetDef, Name, Mode) -> Reply</name>
- <fsummary>Change the given property's mode</fsummary>
- <type>
- <v>PropertySetDef = #objref</v>
- <v>Name = string()</v>
- <v>Mode = normal | read_only | fixed_normal | fixed_readonly | undefined</v>
- <v>Reply = ok | {'EXCEPTION', #CosPropertyService_InvalidPropertyName{}} | {'EXCEPTION', #CosPropertyService_UnsupportedMode{}} | {'EXCEPTION', #CosPropertyService_PropertyNotFound{}}</v>
- </type>
- <desc>
- <p>This operation changes the given property's mode. Return the appropriate
- exception if not able to fulfill the request.</p>
- </desc>
- </func>
- <func>
- <name>set_property_modes(PropertySetDef, PropertyModes) -> Reply</name>
- <fsummary>Change the listed properties mode's</fsummary>
- <type>
- <v>PropertySetDef = #objref</v>
- <v>PropertyModes = [#'CosPropertyService_PropertyMode'{property_name = Name, property_mode = Mode}]</v>
- <v>Name = string()</v>
- <v>Mode = normal | read_only | fixed_normal | fixed_readonly | undefined</v>
- <v>Reply = ok | {'EXCEPTION', #CosPropertyService_MultipleExceptions{exceptions = Excs}}</v>
- <v>Excs = [#'CosPropertyService_PropertyException{reason = Reason, failing_property_name = Name}]</v>
- <v>Reason = invalid_property_name | conflicting_property | property_not_found | unsupported_type_code | unsupported_property | unsupported_mode | fixed_property | read_only_property</v>
- </type>
- <desc>
- <p>This operation attempts to update the listed properties mode's. Raises an
- exception which describe which and why an operation failed.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosProperty/doc/src/CosPropertyService_PropertySetDefFactory.xml b/lib/cosProperty/doc/src/CosPropertyService_PropertySetDefFactory.xml
deleted file mode 100644
index d6425db9cf..0000000000
--- a/lib/cosProperty/doc/src/CosPropertyService_PropertySetDefFactory.xml
+++ /dev/null
@@ -1,95 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosPropertyService_PropertySetDefFactory</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved>Niclas Eklund</approved>
- <checked></checked>
- <date>2000-07-25</date>
- <rev>1.0</rev>
- </header>
- <module>CosPropertyService_PropertySetDefFactory</module>
- <modulesummary>This module implements the OMG CosPropertyService::PropertySetDefFactory interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosProperty/include/CosPropertyService.hrl").</c></p>
- </description>
- <funcs>
- <func>
- <name>create_propertysetdef(Factory) -> </name>
- <fsummary>Create a new <c>PropertySetDef</c>with no predefined settings</fsummary>
- <type>
- <v>Factory = PropertySetDef = #objref</v>
- </type>
- <desc>
- <p>This operation creates a new <c>PropertySetDef</c> with no predefined
- settings.</p>
- </desc>
- </func>
- <func>
- <name>create_constrained_propertysetdef(Factory, PropertyTypes, PropertyDefs) -> Reply</name>
- <fsummary>Create a new <c>PropertySetDef</c>with specified constraints</fsummary>
- <type>
- <v>Factory = PropertySetDef = #objref</v>
- <v>PropertyTypes = [CORBA::TypeCode]</v>
- <v>PropertyDefs = [#'CosPropertyService_PropertyDef'{property_name = Name, property_value = Value, property_mode = Mode}]</v>
- <v>Name = string()</v>
- <v>Value = #any</v>
- <v>Mode = normal | read_only | fixed_normal | fixed_readonly | undefined</v>
- <v>Reply = {'EXCEPTION', #CosPropertyService_ConstraintNotSupported{}} | PropertySetDef</v>
- <v>PropertySetDef = #objref</v>
- </type>
- <desc>
- <p>This operation creates a new <c>PropertySetDef</c> with specific
- constraints. PropertyTypes states allowed TypeCode's and PropertyDefs valid
- <c>CosPropertyService::PropertyDef</c> data.</p>
- </desc>
- </func>
- <func>
- <name>create_initial_propertysetdef(Factory, PropertyDefs) -> Reply</name>
- <fsummary>Create a new <c>PropertySetDef</c>with specified initial properties</fsummary>
- <type>
- <v>Factory = PropertySetDef = #objref</v>
- <v>PropertyDefs = [#'CosPropertyService_PropertyDef'{property_name = Name, property_value = Value, property_mode = Mode}]</v>
- <v>Name = string()</v>
- <v>Value = #any</v>
- <v>Mode = normal | read_only | fixed_normal | fixed_readonly | undefined</v>
- <v>Reply = {'EXCEPTION', #CosPropertyService_MultipleExceptions{exceptions = Excs}} | PropertySetDef</v>
- <v>Excs = [#'CosPropertyService_PropertyException{reason = Reason, failing_property_name = Name}]</v>
- <v>Reason = invalid_property_name | conflicting_property | property_not_found | unsupported_type_code | unsupported_property | unsupported_mode | fixed_property | read_only_property</v>
- <v>PropertySetDef = #objref</v>
- </type>
- <desc>
- <p>This operation creates a new <c>PropertySetDef</c> with specific
- initial properties.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosProperty/doc/src/CosPropertyService_PropertySetFactory.xml b/lib/cosProperty/doc/src/CosPropertyService_PropertySetFactory.xml
deleted file mode 100644
index 0aa22dd716..0000000000
--- a/lib/cosProperty/doc/src/CosPropertyService_PropertySetFactory.xml
+++ /dev/null
@@ -1,93 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosPropertyService_PropertySetFactory</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>2000-07-25</date>
- <rev>1.0</rev>
- </header>
- <module>CosPropertyService_PropertySetFactory</module>
- <modulesummary>This module implements the OMG CosPropertyService::PropertySetFactory interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosProperty/include/CosPropertyService.hrl").</c></p>
- </description>
- <funcs>
- <func>
- <name>create_propertyset(Factory) -> PropertySet</name>
- <fsummary>Create a new <c>PropertySe</c>t with no predefined properties</fsummary>
- <type>
- <v>Factory = PropertySet = #objref</v>
- </type>
- <desc>
- <p>This operation creates a new <c>PropertySe</c>t with no predefined
- properties.</p>
- </desc>
- </func>
- <func>
- <name>create_constrained_propertyset(Factory, PropertyTypes, Properties) -> Reply</name>
- <fsummary>Create a new <c>PropertySet</c>with specified constraints</fsummary>
- <type>
- <v>Factory = #objref</v>
- <v>PropertyTypes = [CORBA::TypeCode]</v>
- <v>Properties = [#'CosPropertyService_Property'{property_name = Name, property_value = Value}]</v>
- <v>Name = string()</v>
- <v>Value = #any</v>
- <v>Reply = {'EXCEPTION', #CosPropertyService_ConstraintNotSupported{}} | PropertySet</v>
- <v>PropertySet = #objref</v>
- </type>
- <desc>
- <p>This operation creates a new <c>PropertySet</c> with specific constraints.
- PropertyTypes states allowed TypeCode's and Properties valid
- <c>CosPropertyService::Property</c> data.</p>
- </desc>
- </func>
- <func>
- <name>create_initial_propertyset(Factory, Properties) -> Reply</name>
- <fsummary>Create a new <c>PropertySet</c>with specified initial properties</fsummary>
- <type>
- <v>Factory = #objref</v>
- <v>Properties = [#'CosPropertyService_Property'{property_name = Name, property_value = Value}]</v>
- <v>Name = string()</v>
- <v>Value = #any</v>
- <v>Reply = {'EXCEPTION', #CosPropertyService_MultipleExceptions{exceptions = Excs}} | PropertySet</v>
- <v>Excs = [#'CosPropertyService_PropertyException{reason = Reason, failing_property_name = Name}]</v>
- <v>Reason = invalid_property_name | conflicting_property | property_not_found | unsupported_type_code | unsupported_property | unsupported_mode | fixed_property | read_only_property</v>
- <v>PropertySet = #objref</v>
- </type>
- <desc>
- <p>This operation creates a new <c>PropertySet</c> with specific
- initial properties.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosProperty/doc/src/Makefile b/lib/cosProperty/doc/src/Makefile
deleted file mode 100644
index ec11ca1735..0000000000
--- a/lib/cosProperty/doc/src/Makefile
+++ /dev/null
@@ -1,144 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2000-2017. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../../vsn.mk
-VSN=$(COSPROPERTY_VSN)
-APPLICATION=cosProperty
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-XML_APPLICATION_FILES = ref_man.xml
-XML_REF3_FILES = \
- cosProperty.xml \
- CosPropertyService_PropertySetFactory.xml \
- CosPropertyService_PropertySetDefFactory.xml \
- CosPropertyService_PropertySet.xml \
- CosPropertyService_PropertySetDef.xml \
- CosPropertyService_PropertiesIterator.xml \
- CosPropertyService_PropertyNamesIterator.xml
-
-XML_REF6_FILES =
-
-XML_PART_FILES = \
- part.xml
-XML_CHAPTER_FILES = \
- ch_contents.xml \
- ch_introduction.xml \
- ch_install.xml \
- ch_example.xml \
- notes.xml
-
-BOOK_FILES = book.xml
-
-XML_FILES = $(BOOK_FILES) $(XML_APPLICATION_FILES) $(XML_REF3_FILES) \
- $(XML_PART_FILES) $(XML_CHAPTER_FILES)
-
-TECHNICAL_DESCR_FILES =
-
-GIF_FILES =
-
-PS_FILES =
-
-# ----------------------------------------------------
-
-INTERNAL_HTML_FILES = $(TECHNICAL_DESCR_FILES:%.xml=$(HTMLDIR)/%.html)
-
-HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \
- $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html)
-
-INFO_FILE = ../../info
-
-EXTRA_FILES = \
- $(DEFAULT_GIF_FILES) \
- $(DEFAULT_HTML_FILES) \
- $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html) \
- $(XML_REF6_FILES:%.xml=$(HTMLDIR)/%.html) \
- $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html)
-
-MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-MAN6_FILES = $(XML_REF6_FILES:%.xml=$(MAN6DIR)/%.6)
-
-HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
-
-TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-XML_FLAGS +=
-DVIPS_FLAGS +=
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-$(HTMLDIR)/%.gif: %.gif
- $(INSTALL_DATA) $< $@
-
-docs: pdf html man
-
-$(TOP_PDF_FILE): $(XML_FILES)
-
-pdf: $(TOP_PDF_FILE)
-
-html: gifs $(HTML_REF_MAN_FILE)
-
-clean clean_docs:
- rm -rf $(HTMLDIR)/*
- rm -f $(MAN3DIR)/*
- rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
- rm -f errs core *~
-
-man: $(MAN3_FILES) $(MAN6_FILES)
-
-gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
-
-$(INDEX_TARGET): $(INDEX_SRC)
- sed -e 's;%VSN%;$(VSN);' $(INDEX_SRC) > $(INDEX_TARGET)
-
-debug opt:
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_docs_spec: docs
- $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
- $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
- $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
- $(INSTALL_DATA) $(HTMLDIR)/* \
- "$(RELSYSDIR)/doc/html"
- $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
- $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
- $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
-
-release_spec:
diff --git a/lib/cosProperty/doc/src/book.xml b/lib/cosProperty/doc/src/book.xml
deleted file mode 100644
index 9ee681b057..0000000000
--- a/lib/cosProperty/doc/src/book.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE book SYSTEM "book.dtd">
-
-<book xmlns:xi="http://www.w3.org/2001/XInclude">
- <header titlestyle="normal">
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosProperty</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2000-06-07</date>
- <rev>1.0</rev>
- </header>
- <insidecover>
- </insidecover>
- <pagetext>cosProperty</pagetext>
- <preamble>
- <contents level="2"></contents>
- </preamble>
- <parts lift="no">
- <xi:include href="part.xml"/>
- </parts>
- <applications>
- <xi:include href="ref_man.xml"/>
- </applications>
- <releasenotes>
- <xi:include href="notes.xml"/>
- </releasenotes>
- <listofterms></listofterms>
- <index></index>
-</book>
-
diff --git a/lib/cosProperty/doc/src/ch_contents.xml b/lib/cosProperty/doc/src/ch_contents.xml
deleted file mode 100644
index 5c3112a644..0000000000
--- a/lib/cosProperty/doc/src/ch_contents.xml
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>The cosProperty Application</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2000-06-07</date>
- <rev>1.0</rev>
- <file>ch_contents.xml</file>
- </header>
-
- <section>
- <title>Content Overview</title>
- <p>The cosProperty documentation is divided into three sections:
- </p>
- <list type="bulleted">
- <item>
- <p>PART ONE - The User's Guide
- <br></br>
-Description of the cosProperty Application including
- services and a small tutorial demonstrating
- the development of a simple service.</p>
- </item>
- <item>
- <p>PART TWO - Release Notes
- <br></br>
-A concise history of cosProperty.</p>
- </item>
- <item>
- <p>PART THREE - The Reference Manual
- <br></br>
- A quick reference guide, including a
- brief description, to all the functions available in cosProperty.</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Brief description of the User's Guide</title>
- <p>The User's Guide contains the following parts:</p>
- <list type="bulleted">
- <item>
- <p>cosProperty overview</p>
- </item>
- <item>
- <p>cosProperty installation</p>
- </item>
- <item>
- <p>A tutorial example</p>
- </item>
- </list>
- </section>
-</chapter>
-
diff --git a/lib/cosProperty/doc/src/ch_example.xml b/lib/cosProperty/doc/src/ch_example.xml
deleted file mode 100644
index da13af2312..0000000000
--- a/lib/cosProperty/doc/src/ch_example.xml
+++ /dev/null
@@ -1,76 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosProperty Examples</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2000-06-07</date>
- <rev>A</rev>
- <file>ch_example.xml</file>
- </header>
-
- <section>
- <title>A tutorial on how to create a simple service</title>
-
- <section>
- <title>Initiate the application</title>
- <p>To use the cosProperty application Orber must be running.</p>
- </section>
-
- <section>
- <title>How to run everything</title>
- <p>Below is a short transcript on how to run cosProperty. </p>
- <code type="none">
-
-%% Start Mnesia and Orber
-mnesia:delete_schema([node()]),
-mnesia:create_schema([node()]),
-orber:install([node()]),
-mnesia:start(),
-orber:start(),
-
-%% Install Property Service in the IFR.
-cosProperty:install(),
-
-%% Install Property Service in mnesia.
-cosProperty:install_db(),
-
-%% Now start the application.
-cosProperty:start(),
-
-%% To be able to create Property objects we must first a Factory
-%% of our preferred type.
-Fac = cosProperty:start_SetDefFactory(),
-
-%% Now we can create a Property object.
-'CosPropertyService_PropertySetDefFactory':
- create_propertysetdef(Fac),
-
-%% Now we can create any allowed properties. There are many
-%% options which are all described further in the documentation.
- </code>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosProperty/doc/src/ch_install.xml b/lib/cosProperty/doc/src/ch_install.xml
deleted file mode 100644
index a1aa2914b4..0000000000
--- a/lib/cosProperty/doc/src/ch_install.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Installing cosProperty</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2000-06-07</date>
- <rev></rev>
- <file>ch-install.xml</file>
- </header>
-
- <section>
- <title>Installation Process</title>
- <p>This chapter describes how to install
- <seealso marker="cosProperty">cosProperty</seealso> in an Erlang Environment.
- </p>
-
- <section>
- <title>Preparation</title>
- <p>Before starting the installation process for cosProperty,
- the application Orber must be running.</p>
- </section>
-
- <section>
- <title>Configuration</title>
- <p>First the cosProperty application must be installed by using
- <c>cosProperty:install()</c> and, if requested, <c>cosProperty:install_db()</c>,
- followed by <c>cosProperty:start()</c>.
- Now we can start the desired Factory type by using either
- <c>cosProperty:start_SetFactory()</c> or
- <c>cosProperty:start_SetDefFactory()</c>.</p>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosProperty/doc/src/ch_introduction.xml b/lib/cosProperty/doc/src/ch_introduction.xml
deleted file mode 100644
index 03ef6f619c..0000000000
--- a/lib/cosProperty/doc/src/ch_introduction.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Introduction to cosProperty</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2000-06-07</date>
- <rev></rev>
- <file>ch_introduction.xml</file>
- </header>
-
- <section>
- <title>Overview</title>
- <p>The cosProperty application is compliant with the <url href="http://www.omg.org">OMG</url>
- Service CosProperty Service.
- </p>
-
- <section>
- <title>Purpose and Dependencies</title>
- <p><em>cosProperty</em> is dependent on <em>Orber</em>, which provides CORBA functionality in an Erlang environment.</p>
- </section>
-
- <section>
- <title>Prerequisites</title>
- <p>To fully understand the concepts presented in the
- documentation, it is recommended that the user is familiar
- with distributed programming, CORBA and the Orber application.
- </p>
- <p>Recommended reading includes <em>CORBA, Fundamentals and Programming - Jon Siegel</em> and <em>Open Telecom Platform Documentation Set</em>. It is also helpful to have read <em>Concurrent Programming in Erlang</em>.</p>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosProperty/doc/src/cosProperty.xml b/lib/cosProperty/doc/src/cosProperty.xml
deleted file mode 100644
index d9310b3113..0000000000
--- a/lib/cosProperty/doc/src/cosProperty.xml
+++ /dev/null
@@ -1,150 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosProperty</title>
- <prepared></prepared>
- <docno></docno>
- <checked></checked>
- <date>2000-06-07</date>
- <rev>PA1</rev>
- </header>
- <module>cosProperty</module>
- <modulesummary>The main module of the cosProperty application</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosProperty/include/*.hrl").</c></p>
- <p>This module contains the functions for starting and stopping the application.</p>
- </description>
- <funcs>
- <func>
- <name>install() -> Return</name>
- <fsummary>Install the cosProperty application in the IFR</fsummary>
- <type>
- <v>Return = ok | {'EXIT', Reason}</v>
- </type>
- <desc>
- <p>This operation installs the cosProperty application in the IFR.</p>
- </desc>
- </func>
- <func>
- <name>install_db() -> Return</name>
- <fsummary>Install data in mnesia necessary for running the cosProperty application</fsummary>
- <type>
- <v>Return = ok | {'EXIT', Reason}</v>
- </type>
- <desc>
- <p>This operation installs data in mnesia necessary for running the
- cosProperty application.</p>
- </desc>
- </func>
- <func>
- <name>uninstall() -> Return</name>
- <fsummary>Remove all data in the IFR related to the cosProperty application</fsummary>
- <type>
- <v>Return = ok | {'EXIT', Reason}</v>
- </type>
- <desc>
- <p>This operation removes all data in the IFR related to the cosProperty
- application.</p>
- </desc>
- </func>
- <func>
- <name>uninstall_db() -> Return</name>
- <fsummary>Remove all data from mnesia related to the cosProperty application</fsummary>
- <type>
- <v>Return = ok | {'EXIT', Reason}</v>
- </type>
- <desc>
- <p>This operation removes all data from mnesia related to the cosProperty
- application.</p>
- </desc>
- </func>
- <func>
- <name>start() -> Return</name>
- <fsummary>Start the cosProperty application</fsummary>
- <type>
- <v>Return = ok | {error, Reason}</v>
- </type>
- <desc>
- <p>This operation starts the cosProperty application.</p>
- </desc>
- </func>
- <func>
- <name>start_SetDefFactory() -> Return</name>
- <fsummary>Start a PropertySetDef Factory</fsummary>
- <type>
- <v>Return = Factory | {'EXCEPTION', E}</v>
- <v>Factory = CosPropertyService::PropertySetDefFactory reference.</v>
- </type>
- <desc>
- <p>This operation starts a PropertySetDef Factory.</p>
- </desc>
- </func>
- <func>
- <name>start_SetFactory() -> Return</name>
- <fsummary>Start a PropertySet Factory</fsummary>
- <type>
- <v>Return = Factory | {'EXCEPTION', E}</v>
- <v>Factory = CosPropertyService::PropertySetDefFactory reference.</v>
- </type>
- <desc>
- <p>This operation starts a PropertySet Factory.</p>
- </desc>
- </func>
- <func>
- <name>stop_SetDefFactory(Factory) -> Return</name>
- <fsummary>Stop the given PropertySetDef Factory</fsummary>
- <type>
- <v>Factory = CosPropertyService::PropertySetDefFactory reference.</v>
- <v>Return = ok | {'EXCEPTION', E}</v>
- </type>
- <desc>
- <p>This operation stops the supplied PropertySetDef Factory.</p>
- </desc>
- </func>
- <func>
- <name>stop_SetFactory(Factory) -> Return</name>
- <fsummary>Stop the given PropertySet Factory</fsummary>
- <type>
- <v>Factory = CosPropertyService::PropertySetFactory reference.</v>
- <v>Return = ok | {'EXCEPTION', E}</v>
- </type>
- <desc>
- <p>This operation stops the supplied PropertySet Factory.</p>
- </desc>
- </func>
- <func>
- <name>stop() -> Return</name>
- <fsummary>Stop the cosProperty application</fsummary>
- <type>
- <v>Return = ok | {error, Reason}</v>
- </type>
- <desc>
- <p>This operation stops the cosProperty application.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosProperty/doc/src/notes.xml b/lib/cosProperty/doc/src/notes.xml
deleted file mode 100644
index 4de246de67..0000000000
--- a/lib/cosProperty/doc/src/notes.xml
+++ /dev/null
@@ -1,377 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosProperty Release Notes</title>
- <prepared></prepared>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>2000-06-07</date>
- <rev>A</rev>
- <file>notes.xml</file>
- </header>
-
-
- <section><title>cosProperty 1.2.3</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> Removed all old unused files in the documentation.
- </p>
- <p>
- Own Id: OTP-14475 Aux Id: ERL-409, PR-1493 </p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosProperty 1.2.2</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Fix dialyzer warnings.</p>
- <p>
- Own Id: OTP-14006</p>
- </item>
- </list>
- </section>
-
- </section>
-
- <section><title>cosProperty 1.2.1</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Internal changes</p>
- <p>
- Own Id: OTP-13551</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosProperty 1.2</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> Remove the usage of erlang:now() from all Corba
- applications and use the new rand module instead of
- random. </p>
- <p>
- Own Id: OTP-12687</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosProperty 1.1.17</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> The default encoding of Erlang files has been changed
- from ISO-8859-1 to UTF-8. </p> <p> The encoding of XML
- files has also been changed to UTF-8. </p>
- <p>
- Own Id: OTP-10907</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosProperty 1.1.16</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Misc build updates</p>
- <p>
- Own Id: OTP-10784</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosProperty 1.1.15</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>Erlang/OTP can now be built using parallel make if you
- limit the number of jobs, for instance using '<c>make
- -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not
- work at the moment because of some missing
- dependencies.</p>
- <p>
- Own Id: OTP-9451</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section>
- <title>cosProperty 1.1.14</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- Removed superfluous usage of shy in the documentation since it can cause problem if
- a buggy tool is used.</p>
- <p>
- Own Id: OTP-9319 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosProperty 1.1.13</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Eliminated Dialyzer warnings when using exit or throw.</p>
- <p>Own id: OTP-9050 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosProperty 1.1.12</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>Test suites published.</p>
- <p>Own id: OTP-8543 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosProperty 1.1.11</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>The documentation EIX file was not generated.</p>
- <p>Own id: OTP-8355 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosProperty 1.1.10</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- The documentation is now built with open source tools (xsltproc and fop)
- that exists on most platforms. One visible change is that the frames are removed.</p>
- <p>
- Own Id: OTP-8201 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosProperty 1.1.9</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Obsolete guards, e.g. record vs is_record, has been changed
- to avoid compiler warnings.</p>
- <p>Own id: OTP-7987</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosProperty 1.1.8</title>
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Updated file headers.</p>
- <p>Own id: OTP-7837</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosProperty 1.1.7</title>
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Documentation source included in open source releases.</p>
- <p>Own id: OTP-7595</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosProperty 1.1.6</title>
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Updated file headers.</p>
- <p>Own id: OTP-7011</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosProperty 1.1.5</title>
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>The documentation source has been converted from SGML to XML.</p>
- <p>Own Id: OTP-6754 Aux Id: </p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosProperty 1.1.4</title>
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Minor Makefile changes.</p>
- <p>Own Id: OTP-6701 Aux Id: </p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosProperty 1.1.3</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>The appup source file was missing a trailing newline.</p>
- <p>Own id: OTP-6626</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosProperty 1.1.2</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Removed some unused code.</p>
- <p>Own Id: OTP-6527 Aux Id: </p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosProperty 1.1.1</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>The app-file contained duplicated modules.</p>
- <p>Own id: OTP-4976</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosProperty 1.1</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>The stub/skeleton-files generated by IC have been improved,
- i.e., depending on the IDL-files, reduced the size of the
- erl- and beam-files and decreased dependencies off Orber's
- Interface Repository. It is necessary to re-compile all IDL-files
- and use COS-applications, including Orber, compiled with
- IC-4.2.</p>
- <p>Own id: OTP-4576</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosProperty 1.0.1</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>First release of the cosProperty application.</p>
- <p>Own Id: -</p>
- </item>
- </list>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosProperty/doc/src/part.xml b/lib/cosProperty/doc/src/part.xml
deleted file mode 100644
index 9d28c6dda4..0000000000
--- a/lib/cosProperty/doc/src/part.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE part SYSTEM "part.dtd">
-
-<part xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosProperty User's Guide</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2000-06-07</date>
- <rev>1.0</rev>
- </header>
- <description>
- <p>The cosProperty Application is an Erlang implementation of the OMG
- CORBA Property Service.</p>
- </description>
- <xi:include href="ch_contents.xml"/>
- <xi:include href="ch_introduction.xml"/>
- <xi:include href="ch_install.xml"/>
- <xi:include href="ch_example.xml"/>
-</part>
-
diff --git a/lib/cosProperty/doc/src/ref_man.xml b/lib/cosProperty/doc/src/ref_man.xml
deleted file mode 100644
index a315c0285f..0000000000
--- a/lib/cosProperty/doc/src/ref_man.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE application SYSTEM "application.dtd">
-
-<application xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosProperty Reference Manual</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2000-06-07</date>
- <rev>1.0</rev>
- </header>
- <description>
- <p>The cosProperty Application is an Erlang implementation of the OMG
- CORBA Property Service.</p>
- </description>
- <xi:include href="cosProperty.xml"/>
- <xi:include href="CosPropertyService_PropertySetFactory.xml"/>
- <xi:include href="CosPropertyService_PropertySetDefFactory.xml"/>
- <xi:include href="CosPropertyService_PropertySet.xml"/>
- <xi:include href="CosPropertyService_PropertySetDef.xml"/>
- <xi:include href="CosPropertyService_PropertiesIterator.xml"/>
- <xi:include href="CosPropertyService_PropertyNamesIterator.xml"/>
-</application>
-
diff --git a/lib/cosProperty/ebin/.gitignore b/lib/cosProperty/ebin/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosProperty/ebin/.gitignore
+++ /dev/null
diff --git a/lib/cosProperty/examples/.gitignore b/lib/cosProperty/examples/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosProperty/examples/.gitignore
+++ /dev/null
diff --git a/lib/cosProperty/include/.gitignore b/lib/cosProperty/include/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosProperty/include/.gitignore
+++ /dev/null
diff --git a/lib/cosProperty/info b/lib/cosProperty/info
deleted file mode 100644
index 67c56e92ed..0000000000
--- a/lib/cosProperty/info
+++ /dev/null
@@ -1,2 +0,0 @@
-group: orb
-short: Orber OMG Property Service
diff --git a/lib/cosProperty/priv/.gitignore b/lib/cosProperty/priv/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosProperty/priv/.gitignore
+++ /dev/null
diff --git a/lib/cosProperty/src/CosProperty.cfg b/lib/cosProperty/src/CosProperty.cfg
deleted file mode 100644
index f10bf843d6..0000000000
--- a/lib/cosProperty/src/CosProperty.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-{this, "CosPropertyService::PropertySet"}.
-{this, "CosPropertyService::PropertySetDef"}.
-{this, "CosPropertyService::PropertySetDefFactory"}.
-{this, "CosPropertyService::PropertySetFactory"}.
-
diff --git a/lib/cosProperty/src/CosProperty.idl b/lib/cosProperty/src/CosProperty.idl
deleted file mode 100644
index 156fb37ccc..0000000000
--- a/lib/cosProperty/src/CosProperty.idl
+++ /dev/null
@@ -1,192 +0,0 @@
-#ifndef _COSPROPERTY_IDL
-#define _COSPROPERTY_IDL
-
-#pragma prefix "omg.org"
-
-module CosPropertyService {
- /*****************************************************/
- /* Data Types */
- /*****************************************************/
- typedef string PropertyName;
-
- struct Property {
- PropertyName property_name;
- any property_value;
- };
-
- enum PropertyModeType {
- normal, read_only, fixed_normal, fixed_readonly, undefined };
-
- struct PropertyDef {
- PropertyName property_name;
- any property_value;
- PropertyModeType property_mode;
- };
-
- struct PropertyMode {
- PropertyName property_name;
- PropertyModeType property_mode;
- };
-
- typedef sequence<PropertyName> PropertyNames;
- typedef sequence<Property> Properties;
- typedef sequence<PropertyDef> PropertyDefs;
- typedef sequence<PropertyMode> PropertyModes;
- typedef sequence<CORBA::TypeCode> PropertyTypes;
-
- interface PropertyNamesIterator;
- interface PropertiesIterator;
- interface PropertySetFactory;
- interface PropertySetDef;
- interface PropertySet;
-
- /*****************************************************/
- /* Exceptions */
- /*****************************************************/
- exception ConstraintNotSupported{};
- exception InvalidPropertyName {};
- exception ConflictingProperty {};
- exception PropertyNotFound {};
- exception UnsupportedTypeCode {};
- exception UnsupportedProperty {};
- exception UnsupportedMode {};
- exception FixedProperty {};
- exception ReadOnlyProperty {};
-
- enum ExceptionReason { invalid_property_name, conflicting_property,
- property_not_found, unsupported_type_code,
- unsupported_property, unsupported_mode,
- fixed_property, read_only_property };
-
- struct PropertyException {
- ExceptionReason reason;
- PropertyName failing_property_name;
- };
-
- typedef sequence<PropertyException> PropertyExceptions;
- exception MultipleExceptions { PropertyExceptions exceptions; };
-
- /*****************************************************/
- /* Interface Definitions */
- /*****************************************************/
- interface PropertySetFactory {
- PropertySet create_propertyset();
-
- PropertySet create_constrained_propertyset( in PropertyTypes allowed_property_types,
- in Properties allowed_properties)
- raises(ConstraintNotSupported);
-
- PropertySet create_initial_propertyset( in Properties initial_properties)
- raises(MultipleExceptions); };
-
- /*---------------------------------------------------*/
- interface PropertySetDefFactory {
- PropertySetDef create_propertysetdef();
-
- PropertySetDef create_constrained_propertysetdef( in PropertyTypes allowed_property_types,
- in PropertyDefs allowed_property_defs)
- raises(ConstraintNotSupported);
-
- PropertySetDef create_initial_propertysetdef( in PropertyDefs initial_property_defs)
- raises(MultipleExceptions);
- };
-
- /*---------------------------------------------------*/
- interface PropertySet {
- /* Support for defining and modifying properties */
- void define_property( in PropertyName property_name, in any property_value)
- raises(InvalidPropertyName, ConflictingProperty, UnsupportedTypeCode,
- UnsupportedProperty, ReadOnlyProperty);
-
- void define_properties( in Properties nproperties)
- raises(MultipleExceptions);
-
- /* Support for Getting Properties and their Names */
- unsigned long get_number_of_properties();
-
- void get_all_property_names( in unsigned long how_many,
- out PropertyNames property_names,
- out PropertyNamesIterator rest);
-
- any get_property_value( in PropertyName property_name)
- raises(PropertyNotFound, InvalidPropertyName);
-
- boolean get_properties( in PropertyNames property_names,
- out Properties nproperties);
-
- void get_all_properties( in unsigned long how_many,
- out Properties nproperties,
- out PropertiesIterator rest);
-
- /* Support for Deleting Properties */
- void delete_property( in PropertyName property_name)
- raises(PropertyNotFound, InvalidPropertyName, FixedProperty);
-
- void delete_properties( in PropertyNames property_names)
- raises(MultipleExceptions);
-
- boolean delete_all_properties();
-
- /* Support for Existence Check */
- boolean is_property_defined( in PropertyName property_name)
- raises(InvalidPropertyName);
- };
-
- /*---------------------------------------------------*/
- interface PropertySetDef:PropertySet {
- /* Support for retrieval of PropertySet constraints*/
- void get_allowed_property_types( out PropertyTypes property_types);
-
- void get_allowed_properties( out PropertyDefs property_defs);
-
- /* Support for defining and modifying properties */
- void define_property_with_mode( in PropertyName property_name,
- in any property_value,
- in PropertyModeType property_mode)
- raises(InvalidPropertyName, ConflictingProperty, UnsupportedTypeCode,
- UnsupportedProperty, UnsupportedMode, ReadOnlyProperty);
-
- void define_properties_with_modes( in PropertyDefs property_defs)
- raises(MultipleExceptions);
-
- /* Support for Getting and Setting Property Modes */
- PropertyModeType get_property_mode( in PropertyName property_name)
- raises(PropertyNotFound, InvalidPropertyName);
-
- boolean get_property_modes( in PropertyNames property_names,
- out PropertyModes property_modes);
-
- void set_property_mode( in PropertyName property_name,
- in PropertyModeType property_mode)
- raises(InvalidPropertyName, PropertyNotFound, UnsupportedMode);
-
- void set_property_modes( in PropertyModes property_modes)
- raises(MultipleExceptions);
- };
-
- /*---------------------------------------------------*/
- interface PropertyNamesIterator{
- void reset();
-
- boolean next_one( out PropertyName property_name);
-
- boolean next_n ( in unsigned long how_many,
- out PropertyNames property_names);
-
- void destroy();
- };
-
- /*---------------------------------------------------*/
- interface PropertiesIterator {
- void reset();
-
- boolean next_one( out Property aproperty);
-
- boolean next_n( in unsigned long how_many,
- out Properties nproperties);
-
- void destroy();
- };
-};
-
-#endif
diff --git a/lib/cosProperty/src/CosPropertyService_PropertiesIterator_impl.erl b/lib/cosProperty/src/CosPropertyService_PropertiesIterator_impl.erl
deleted file mode 100644
index 5972e8f4d2..0000000000
--- a/lib/cosProperty/src/CosPropertyService_PropertiesIterator_impl.erl
+++ /dev/null
@@ -1,167 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : CosPropertyService_PropertiesIterator_impl.erl
-%% Description :
-%%
-%%----------------------------------------------------------------------
--module('CosPropertyService_PropertiesIterator_impl').
-
-%%----------------------------------------------------------------------
-%% Include files
-%%----------------------------------------------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
--include("CosPropertyService.hrl").
--include("cosProperty.hrl").
-
-
-%%----------------------------------------------------------------------
-%% External exports
-%%----------------------------------------------------------------------
-%% Mandatory server functions
--export([init/1,
- terminate/2,
- code_change/3]).
-
--export([reset/1,
- next_one/1,
- next_n/2,
- destroy/1]).
-
-%%----------------------------------------------------------------------
-%% Internal exports
-%%----------------------------------------------------------------------
--export([
- ]).
-
-%%----------------------------------------------------------------------
-%% Records
-%%----------------------------------------------------------------------
--record(state, {properties, counter=1, length}).
-
-%%----------------------------------------------------------------------
-%% Macros
-%%----------------------------------------------------------------------
--define(CreateInitState(L), #state{properties = L, length = length(L)}).
--define(get_Properties(S), S#state.properties).
--define(get_Counter(S), S#state.counter).
--define(get_Length(S), S#state.length).
-
--define(set_Properties(S, P), S#state{properties = P}).
--define(set_Counter(S, C), S#state{counter = C}).
--define(set_Length(S, L), S#state{length = L}).
-
--define(increment_Counter(S), S#state{counter = S#state.counter+1}).
--define(decrement_Counter(S), S#state{counter = S#state.counter-1}).
--define(addto_Counter(S, N), S#state{counter = S#state.counter+N}).
--define(subfrom_Counter(S, N), S#state{counter = S#state.counter-N}).
-
-
-%%======================================================================
-%% External functions
-%%======================================================================
-%%----------------------------------------------------------------------
-%% Function : init/1
-%% Description: Initiates the server
-%% Returns : {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
-%%----------------------------------------------------------------------
-init(Properties) ->
- {ok, ?CreateInitState(Properties)}.
-
-%%----------------------------------------------------------------------
-%% Function : terminate/2
-%% Description: Shutdown the server
-%% Returns : any (ignored by gen_server)
-%%----------------------------------------------------------------------
-terminate(_Reason, _State) ->
- ok.
-
-%%----------------------------------------------------------------------
-%% Function : code_change/3
-%% Description: Convert process state when code is changed
-%% Returns : {ok, NewState}
-%%----------------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : reset
-%% Arguments : -
-%% Description:
-%% Returns : {ok, NewState}
-%%----------------------------------------------------------------------
-reset(State) ->
- {reply, ok, ?set_Counter(State, 1)}.
-
-%%----------------------------------------------------------------------
-%% Function : next_one
-%% Arguments : -
-%% Description:
-%% Returns : {ok, {bool(), PropertyList}, NewState}
-%%----------------------------------------------------------------------
-next_one(State) when ?get_Counter(State) > ?get_Length(State) ->
- {reply, {false,
- #'CosPropertyService_Property'
- {property_name = "",
- property_value = any:create(orber_tc:null(), null)}},
- State};
-next_one(State) ->
- {reply, {true, lists:nth(?get_Counter(State), ?get_Properties(State))},
- ?set_Counter(State, 1+?get_Counter(State))}.
-
-%%----------------------------------------------------------------------
-%% Function : next_n
-%% Arguments : N - how many properties we should return.
-%% Description:
-%% Returns : {ok, {bool(), PropertyList}, NewState}
-%%----------------------------------------------------------------------
-next_n(State, N) ->
- case lists:sublist(?get_Properties(State),
- ?get_Counter(State),
- N) of
- Properties when N+?get_Counter(State) < ?get_Length(State) ->
- {reply, {true, Properties}, ?set_Counter(State, N+?get_Counter(State))};
- Properties ->
- {reply, {false, Properties}, ?set_Counter(State, ?get_Length(State))}
- end.
-
-%%---------------------------------------------------------------------%
-%% Function : destroy
-%% Arguments : -
-%% Description: Terminate the object
-%% Returns : {ok, NewState}
-%%----------------------------------------------------------------------
-destroy(State) ->
- {stop, normal, ok, State}.
-
-%%======================================================================
-%% Internal functions
-%%=====================================================================
-
-%%======================================================================
-%% END OF MODULE
-%%======================================================================
-
diff --git a/lib/cosProperty/src/CosPropertyService_PropertyNamesIterator_impl.erl b/lib/cosProperty/src/CosPropertyService_PropertyNamesIterator_impl.erl
deleted file mode 100644
index 7ce4f6b303..0000000000
--- a/lib/cosProperty/src/CosPropertyService_PropertyNamesIterator_impl.erl
+++ /dev/null
@@ -1,159 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : CosPropertyService_PropertyNamesIterator_impl.erl
-%% Description :
-%%
-%%----------------------------------------------------------------------
--module('CosPropertyService_PropertyNamesIterator_impl').
-
-%%----------------------------------------------------------------------
-%% Include files
-%%----------------------------------------------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
--include("CosPropertyService.hrl").
--include("cosProperty.hrl").
-
-%%----------------------------------------------------------------------
-%% External exports
-%%----------------------------------------------------------------------
-%% Mandatory server functions
--export([init/1,
- terminate/2,
- code_change/3]).
-
--export([reset/1,
- next_one/1,
- next_n/2,
- destroy/1]).
-
-%%----------------------------------------------------------------------
-%% Internal exports
-%%----------------------------------------------------------------------
--export([
- ]).
-
-%%----------------------------------------------------------------------
-%% Records
-%%----------------------------------------------------------------------
--record(state, {properties, counter=1, length}).
-
-%%----------------------------------------------------------------------
-%% Macros
-%%----------------------------------------------------------------------
--define(CreateInitState(L), #state{properties = L, length = length(L)}).
--define(get_Properties(S), S#state.properties).
--define(get_Counter(S), S#state.counter).
--define(get_Length(S), S#state.length).
-
--define(set_Properties(S, P), S#state{properties = P}).
--define(set_Counter(S, C), S#state{counter = C}).
--define(set_Length(S, L), S#state{length = L}).
-
--define(increment_Counter(S), S#state{counter = S#state.counter+1}).
--define(decrement_Counter(S), S#state{counter = S#state.counter-1}).
--define(addto_Counter(S, N), S#state{counter = S#state.counter+N}).
--define(subfrom_Counter(S, N), S#state{counter = S#state.counter-N}).
-
-
-%%======================================================================
-%% External functions
-%%======================================================================
-%%----------------------------------------------------------------------
-%% Function : init/1
-%% Description: Initiates the server
-%% Returns : {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
-%%----------------------------------------------------------------------
-init(Properties) ->
- {ok, ?CreateInitState(Properties)}.
-
-%%----------------------------------------------------------------------
-%% Function : terminate/2
-%% Description: Shutdown the server
-%% Returns : any (ignored by gen_server)
-%%----------------------------------------------------------------------
-terminate(_Reason, _State) ->
- ok.
-
-%%----------------------------------------------------------------------
-%% Function : code_change/3
-%% Description: Convert process state when code is changed
-%% Returns : {ok, NewState}
-%%----------------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : reset
-%% Arguments : -
-%% Description:
-%% Returns : {ok, NewState}
-%%----------------------------------------------------------------------
-reset(State) ->
- {reply, ok, ?set_Counter(State, 1)}.
-
-%%---------------------------------------------------------------------%
-%% Function : next_one
-%% Arguments : -
-%% Description:
-%% Returns : {ok, {bool(), PropertyName}, NewState}
-%%----------------------------------------------------------------------
-next_one(State) when ?get_Counter(State) > ?get_Length(State) ->
- {reply, {false, ""}, State};
-next_one(State) ->
- {reply, {true, lists:nth(?get_Counter(State), ?get_Properties(State))},
- ?set_Counter(State, 1+?get_Counter(State))}.
-
-%%---------------------------------------------------------------------%
-%% Function : next_n
-%% Arguments : N - how many properties we should return.
-%% Description:
-%% Returns : {ok, {bool(), PropertyNameList}, NewState}
-%%----------------------------------------------------------------------
-next_n(State, N) ->
- case lists:sublist(?get_Properties(State), ?get_Counter(State), N) of
- Properties when N+?get_Counter(State) < ?get_Length(State) ->
- {reply, {true, Properties}, ?set_Counter(State, N+?get_Counter(State))};
- Properties ->
- {reply, {false, Properties}, ?set_Counter(State, ?get_Length(State))}
- end.
-
-%%---------------------------------------------------------------------%
-%% Function : destroy
-%% Arguments : -
-%% Description: Terminate the object
-%% Returns : {ok, NewState}
-%%----------------------------------------------------------------------
-destroy(State) ->
- {stop, normal, ok, State}.
-
-%%======================================================================
-%% Internal functions
-%%======================================================================
-
-%%======================================================================
-%% END OF MODULE
-%%======================================================================
diff --git a/lib/cosProperty/src/CosPropertyService_PropertySetDefFactory_impl.erl b/lib/cosProperty/src/CosPropertyService_PropertySetDefFactory_impl.erl
deleted file mode 100644
index 722bb45eb7..0000000000
--- a/lib/cosProperty/src/CosPropertyService_PropertySetDefFactory_impl.erl
+++ /dev/null
@@ -1,186 +0,0 @@
-%%----------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : CosPropertyService_PropertySetDefFactory_impl.erl
-%% Description :
-%%
-%%----------------------------------------------------------------------
--module('CosPropertyService_PropertySetDefFactory_impl').
-
-%%----------------------------------------------------------------------
-%% Include files
-%%----------------------------------------------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
--include("CosPropertyService.hrl").
--include("cosProperty.hrl").
-
-%%----------------------------------------------------------------------
-%% External exports
-%%----------------------------------------------------------------------
--export([init/1,
- terminate/2,
- code_change/3]).
-
--export([create_propertysetdef/2,
- create_constrained_propertysetdef/4,
- create_initial_propertysetdef/3]).
-
-%%----------------------------------------------------------------------
-%% Internal exports
-%%----------------------------------------------------------------------
--export([]).
-
-%%----------------------------------------------------------------------
-%% Records
-%%----------------------------------------------------------------------
--record(state, {}).
-
-%%----------------------------------------------------------------------
-%% Macros
-%%----------------------------------------------------------------------
--define(checkTCfun, fun(TC) -> orber_tc:check_tc(TC) end).
-
-%%======================================================================
-%% External functions
-%%======================================================================
-%%----------------------------------------------------------------------
-%% Function : init/1
-%% Returns : {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
-%% Description: Initiates the server
-%%----------------------------------------------------------------------
-init([]) ->
- {ok, #state{}}.
-
-%%----------------------------------------------------------------------
-%% Function : terminate/2
-%% Returns : any (ignored by gen_server)
-%% Description: Shutdown the server
-%%----------------------------------------------------------------------
-terminate(_Reason, _State) ->
- ok.
-
-%%----------------------------------------------------------------------
-%% Function : code_change/3
-%% Returns : {ok, NewState}
-%% Description: Convert process state when code is changed
-%%----------------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : create_propertysetdef
-%% Arguments :
-%% Returns : CosPropertyService::PropertySetDef reference.
-%% Description:
-%%----------------------------------------------------------------------
-create_propertysetdef(_OE_This, State) ->
- {reply,
- 'CosPropertyService_PropertySetDef':
- oe_create({normal, [], [], [], ?PropertySetDef}, [{pseudo, true}]),
- State}.
-
-%%---------------------------------------------------------------------%
-%% Function : create_constrained_propertysetdef
-%% Arguments : PropTypes - list of property types.
-%% PropDefs - list of property defs.
-%% Returns : CosPropertyService::PropertySetDef |
-%% {'EXCEPTION', CosPropertyService::ConstraintNotSupported}
-%% Description:
-%%----------------------------------------------------------------------
-create_constrained_propertysetdef(_OE_This, State, PropTypes, PropDefs) ->
- case lists:all(?checkTCfun, PropTypes) of
- true ->
- crosscheckTC(PropDefs, PropTypes),
- {reply,
- 'CosPropertyService_PropertySetDef':
- oe_create({normal, PropTypes, PropDefs, [], ?PropertySetDef}, [{pseudo, true}]),
- State};
- false ->
- corba:raise(#'CosPropertyService_ConstraintNotSupported'{})
- end.
-
-crosscheckTC([], _) ->
- ok;
-crosscheckTC([#'CosPropertyService_PropertyDef'
- {property_name = Name,
- property_value = Value,
- property_mode = _Mode}|T], TCs) ->
- case lists:member(any:get_typecode(Value), TCs) of
- true when Name =/= "" ->
- crosscheckTC(T, TCs);
- _ ->
- corba:raise(#'CosPropertyService_ConstraintNotSupported'{})
- end.
-
-%%---------------------------------------------------------------------%
-%% Function : create_initial_propertysetdef
-%% Arguments :
-%% Returns : CosPropertyService::PropertySetDef |
-%% {'EXCEPTION', CosPropertyService::MultipleExceptions}
-%% Description:
-%%----------------------------------------------------------------------
-create_initial_propertysetdef(_OE_This, State, PropDefs) ->
- InitProps = evaluate_propertysetdef(PropDefs),
- {reply,
- 'CosPropertyService_PropertySetDef':
- oe_create({normal, [], [], InitProps, ?PropertySetDef}, [{pseudo, true}]),
- State}.
-
-%%======================================================================
-%% Internal functions
-%%======================================================================
-evaluate_propertysetdef(SetDefs) ->
- case evaluate_propertysetdef(SetDefs, [], []) of
- {ok, NewProperties} ->
- NewProperties;
- {error, Exc} ->
- corba:raise(#'CosPropertyService_MultipleExceptions'{exceptions = Exc})
- end.
-
-evaluate_propertysetdef([], NewProperties, []) ->
- %% No exceptions found.
- {ok, NewProperties};
-evaluate_propertysetdef([], _, Exc) ->
- {error, Exc};
-evaluate_propertysetdef([#'CosPropertyService_PropertyDef'
- {property_name = Name,
- property_value = Value,
- property_mode = Mode}|T], X, Exc) ->
- case orber_tc:check_tc(any:get_typecode(Value)) of
- true ->
- evaluate_propertysetdef(T, [{Name, Value, Mode}|X], Exc);
- false ->
- evaluate_propertysetdef(T, X, [#'CosPropertyService_PropertyException'
- {reason = unsupported_type_code,
- failing_property_name = Name}|Exc])
- end.
-
-
-
-%%======================================================================
-%% END OF MODULE
-%%======================================================================
-
diff --git a/lib/cosProperty/src/CosPropertyService_PropertySetDef_impl.erl b/lib/cosProperty/src/CosPropertyService_PropertySetDef_impl.erl
deleted file mode 100644
index cc67daa9e0..0000000000
--- a/lib/cosProperty/src/CosPropertyService_PropertySetDef_impl.erl
+++ /dev/null
@@ -1,1042 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2017. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: CosPropertyService_PropertySetDef_impl.erl
-%% Modified:
-%%
-%%-----------------------------------------------------------------
-%% README:
-%% (1) The OMG specification states that a property name may not
-%% be an empty string (""). We may restrict this further
-%% but there is no reason for that.
-%%-----------------------------------------------------------------
--module('CosPropertyService_PropertySetDef_impl').
-
-%%----------------------------------------------------------------------
-%% Include files
-%%----------------------------------------------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
--include_lib("cosProperty/include/CosPropertyService.hrl").
--include("cosProperty.hrl").
-
-%%----------------------------------------------------------------------
-%% External exports
-%%----------------------------------------------------------------------
-%% Mandatory callbacks
--export([init/1,
- terminate/2,
- code_change/3]).
-
-%% Inherrit from CosPropertyService::PropertySet
--export([define_property/4,
- define_properties/3,
- get_number_of_properties/2,
- get_all_property_names/3,
- get_property_value/3,
- get_properties/3,
- get_all_properties/3,
- delete_property/3,
- delete_properties/3,
- delete_all_properties/2,
- is_property_defined/3]).
-
-%% CosPropertyService::PropertySetDef
--export([get_allowed_property_types/2,
- get_allowed_properties/2,
- define_property_with_mode/5,
- define_properties_with_modes/3,
- get_property_mode/3,
- get_property_modes/3,
- set_property_mode/4,
- set_property_modes/3]).
-
-%%----------------------------------------------------------------------
-%% Internal exports
-%%----------------------------------------------------------------------
--export([dump/0]).
-
-%%----------------------------------------------------------------------
-%% Records
-%%----------------------------------------------------------------------
--record(state, {dbKey, defaultMode, okTypes, okProperties, myType}).
-
-%%----------------------------------------------------------------------
-%% Macros
-%%----------------------------------------------------------------------
-
--define(create_InitState(K, D, AT, AP, MT), #state{dbKey = K, defaultMode = D,
- okTypes = AT, okProperties = AP,
- myType = MT}).
-%% Selectors
--define(get_DBKey(S), S#state.dbKey).
--define(get_DefaultMode(S), S#state.defaultMode).
--define(get_okTypes(S), S#state.okTypes).
--define(get_okProperties(S), S#state.okProperties).
-%% MISC
--define(is_NotSetDef(S), S#state.myType =/= ?PropertySetDef).
--define(no_PropertyLimits(S), S#state.okProperties == []).
--define(no_TypeLimits(S), S#state.okTypes == []).
--define(is_NotStatic(S), is_binary(S#state.dbKey)).
-
-%% Fun:s
--define(Local2Property, fun({N,V,_M}) ->
- #'CosPropertyService_Property'{property_name = N,
- property_value = V}
- end).
--define(Local2Names, fun({N,_V,_M}) ->
- N
- end).
--define(MemberName(N), fun(R) ->
- case R of
- Property when is_record(R, 'CosPropertyService_Property') ->
- Property#'CosPropertyService_Property'.property_name == N;
- PropertyDef when is_record(R, 'CosPropertyService_PropertyDef') ->
- PropertyDef#'CosPropertyService_PropertyDef'.property_name == N;
- _->
- false
- end
- end).
-
-%%======================================================================
-%% External functions
-%%======================================================================
-%%----------------------------------------------------------------------
-%% Function : init/1
-%% Description: Initiates the server
-%% Returns : {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
-%%----------------------------------------------------------------------
-init({DefMode, AllowedTypes, AllowedProperties, InitProperties, MyType}) ->
- Key = term_to_binary({{erlang:system_time(),
- erlang:unique_integer()},
- node()}),
- _F = ?write_function(#oe_CosPropertyService{key=Key,
- properties=InitProperties}),
- write_result(mnesia:transaction(_F)),
- {ok, ?create_InitState(Key, DefMode, AllowedTypes, AllowedProperties, MyType)};
-init({static, DefMode, AllowedTypes, AllowedProperties, InitProperties, MyType}) ->
- {ok, ?create_InitState(InitProperties, DefMode, AllowedTypes,
- AllowedProperties, MyType)}.
-
-%%---------------------------------------------------------------------%
-%% Function : terminate
-%% Description: Shutdown the server
-%% Returns : any (ignored by gen_server)
-%%----------------------------------------------------------------------
-terminate(_Reason, State) when ?is_NotStatic(State) ->
- _DF = ?delete_function({oe_CosPropertyService, ?get_DBKey(State)}),
- catch write_result(mnesia:transaction(_DF)),
- ok;
-terminate(_Reason, _State) ->
- ok.
-
-%%---------------------------------------------------------------------%
-%% Function : code_change
-%% Description: Convert process state when code is changed
-%% Returns : {ok, State}
-%%----------------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-
-%%----------------------------------------------------------------------
-%% Interface CosPropertyService::PropertySet
-%%----------------------------------------------------------------------
-%%---------------------------------------------------------------------%
-%% Function : define_property
-%% Arguments :
-%% Description:
-%% Returns : {ok, State}
-%%----------------------------------------------------------------------
-define_property(_, _, "", _) ->
- corba:raise(#'CosPropertyService_InvalidPropertyName'{});
-define_property(_OE_This, State, Name, Value) when ?is_NotStatic(State) ->
- evaluate_property_data(State, Value, Name),
- _DF =
- fun() ->
- case mnesia_read(State) of
- {'EXCEPTION', E} ->
- {'EXCEPTION', E};
- X ->
- case catch update_property(X, Name, value, Value,
- ?get_DefaultMode(State)) of
- {'EXCEPTION', E} when
- is_record(E, 'CosPropertyService_PropertyNotFound') ->
- mnesia_write(State, [{Name, Value, ?get_DefaultMode(State)}|X]);
- {'EXCEPTION', E} ->
- {'EXCEPTION', E};
- NewProperties ->
- mnesia_write(State, NewProperties)
- end
- end
- end,
- {reply, mnesia_transaction(_DF), State};
-define_property(_OE_This, State, Name, Value) ->
- evaluate_property_data(State, Value, Name),
- X = ?get_DBKey(State),
- case catch update_property(X, Name, value, Value, ?get_DefaultMode(State)) of
- {'EXCEPTION', E} when is_record(E, 'CosPropertyService_PropertyNotFound') ->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO});
- {'EXCEPTION', E} ->
- corba:raise(E);
- _NewProperties ->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-
-%%---------------------------------------------------------------------%
-%% Function : get_property_value
-%% Arguments :
-%% Description:
-%% Returns : {ok, State}
-%%----------------------------------------------------------------------
-get_property_value(_, _, "") ->
- corba:raise(#'CosPropertyService_InvalidPropertyName'{});
-get_property_value(_OE_THIS, State, Name) ->
- X = lookup_table(?get_DBKey(State)),
- {reply, find_property(X, Name, value), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : delete_property
-%% Arguments :
-%% Description:
-%% Returns : {ok, State}
-%%----------------------------------------------------------------------
-delete_property(_, _, "") ->
- corba:raise(#'CosPropertyService_InvalidPropertyName'{});
-delete_property(_OE_THIS, State, Name) when ?is_NotStatic(State) ->
- _DF =
- fun() ->
- case mnesia_read(State) of
- {'EXCEPTION', E} ->
- {'EXCEPTION', E};
- X ->
- case catch remove_property(X, Name) of
- {'EXCEPTION', E} ->
- {'EXCEPTION', E};
- NewProperties ->
- mnesia_write(State, NewProperties)
- end
- end
- end,
- {reply, mnesia_transaction(_DF), State};
-delete_property(_OE_THIS, State, Name) ->
- X = lookup_table(?get_DBKey(State)),
- %% Check the properties; must raise an exception.
- remove_property(X, Name),
- %% Something is not correct.
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}).
-
-
-%%---------------------------------------------------------------------%
-%% Function : define_properties
-%% Arguments :
-%% Description:
-%% Returns : {ok, State}
-%%----------------------------------------------------------------------
-define_properties(_OE_THIS, State, PropertySeq) when ?is_NotStatic(State) ->
- {OKProperties, Exc} = evaluate_properties_data(State, PropertySeq),
- _DF =
- fun() ->
- case mnesia_read(State) of
- {'EXCEPTION', E} ->
- {'EXCEPTION', E};
- X ->
- case catch define_properties_helper(State,
- OKProperties, X, Exc) of
- {'EXCEPTION', E} ->
- {'EXCEPTION', E};
- NewProperties ->
- mnesia_write(State, NewProperties)
- end
- end
- end,
- {reply, mnesia_transaction(_DF), State};
-define_properties(_OE_THIS, State, PropertySeq) ->
- {OKProperties, Exc} = evaluate_properties_data(State, PropertySeq),
- X = lookup_table(?get_DBKey(State)),
- case define_properties_helper(State, OKProperties, X, Exc) of
- {'EXCEPTION', E} ->
- corba:raise(E);
- _ ->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-define_properties_helper(_State, [], NewProperties, []) ->
- %% No exceptions, insert the properties.
- NewProperties;
-define_properties_helper(_State, [], _, MultipleExceptions) ->
- {'EXCEPTION', #'CosPropertyService_MultipleExceptions'{exceptions = MultipleExceptions}};
-define_properties_helper(State, [#'CosPropertyService_Property'
- {property_name = Name,
- property_value = Value}|T], Properties, Exc) ->
- case catch update_property(Properties, Name, value, Value, ?get_DefaultMode(State)) of
- {'EXCEPTION', E} when is_record(E, 'CosPropertyService_PropertyNotFound') ->
- define_properties_helper(State, T, [{Name, Value, ?get_DefaultMode(State)}|Properties], Exc);
- {'EXCEPTION', E} ->
- define_properties_helper(State, T, Properties,
- [#'CosPropertyService_PropertyException'
- {reason = remap_exception(E),
- failing_property_name = Name}|Exc]);
- NewProperties ->
- define_properties_helper(State, T, NewProperties, Exc)
- end.
-
-%%---------------------------------------------------------------------%
-%% Function : get_number_of_properties
-%% Arguments : -
-%% Description: Returns the number of properties currently associated
-%% with this object.
-%% Returns : {ok, ulong(), State}
-%%----------------------------------------------------------------------
-get_number_of_properties(_OE_THIS, State) ->
- X = lookup_table(?get_DBKey(State)),
- {reply, length(X), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : get_all_property_names
-%% Arguments :
-%% Description:
-%% Returns : {ok, State}
-%%----------------------------------------------------------------------
-get_all_property_names(_OE_THIS, State, Max) ->
- X = lookup_table(?get_DBKey(State)),
- {reply, get_all_property_names_helper(X, [], Max), State}.
-
-get_all_property_names_helper([], Acc, _) ->
- %% There are no more properties; return a nil-object refernce.
- {ok, Acc, corba:create_nil_objref()};
-get_all_property_names_helper(Left, Acc, 0) ->
- %% There are more properties; create Name Iterartor.
- PropertyNames = lists:map(?Local2Names, Left),
- {ok, Acc, cosProperty:start_PropertyNamesIterator(PropertyNames)};
-get_all_property_names_helper([{Name, _, _}|T], Acc, No) ->
- get_all_property_names_helper(T, [Name|Acc], No-1).
-
-
-%%---------------------------------------------------------------------%
-%% Function : get_properties
-%% Arguments : A list of property names, i.e., string()
-%% Description:
-%% Returns : {ok, State}
-%%----------------------------------------------------------------------
-get_properties(_OE_THIS, State, PropertyNames) ->
- X = lookup_table(?get_DBKey(State)),
- {reply, locate_names(PropertyNames, X, true, []), State}.
-
-locate_names([], _, AllOK, Acc) ->
- {AllOK, Acc};
-locate_names([""|T], X, _AllOK, Acc) ->
- locate_names(T, X, false, [#'CosPropertyService_Property'
- {property_name = "",
- property_value =
- any:create(tk_void, ok)}|Acc]);
-locate_names([H|T], X, AllOK, Acc) ->
- case catch find_property(X, H, value) of
- {'EXCEPTION', _} ->
- locate_names(T, X, false, [#'CosPropertyService_Property'
- {property_name = H,
- property_value =
- any:create(tk_void, ok)}|Acc]);
- Val ->
- locate_names(T, X, AllOK, [#'CosPropertyService_Property'
- {property_name = H,
- property_value = Val}|Acc])
- end.
-
-%%---------------------------------------------------------------------%
-%% Function : get_all_properties
-%% Arguments :
-%% Description:
-%% Returns : {ok, State}
-%%----------------------------------------------------------------------
-get_all_properties(_OE_THIS, State, Max) ->
- X = lookup_table(?get_DBKey(State)),
- {reply, get_all_properties_helper(X, [], Max), State}.
-
-get_all_properties_helper([], Acc, _) ->
-%% There are no more properties; return a nil-object refernce.
- {ok, Acc, corba:create_nil_objref()};
-get_all_properties_helper(Left, Acc, 0) ->
- %% There are more properties; create Iterartor.
- Properties = lists:map(?Local2Property, Left),
- {ok, Acc, cosProperty:start_PropertiesIterator(Properties)};
-get_all_properties_helper([{Name, Val, _}|T], Acc, No) ->
- get_all_properties_helper(T, [#'CosPropertyService_Property'
- {property_name = Name,
- property_value = Val}|Acc], No-1).
-
-%%---------------------------------------------------------------------%
-%% Function : delete_properties
-%% Arguments :
-%% Description:
-%% Returns : {ok, State}
-%%----------------------------------------------------------------------
-delete_properties(_OE_THIS, State, []) ->
- {reply, ok, State};
-delete_properties(_OE_THIS, State, PropertyNames) when ?is_NotStatic(State) ->
- _DF =
- fun() ->
- case mnesia_read(State) of
- {'EXCEPTION', E} ->
- {'EXCEPTION', E};
- X ->
- case catch delete_properties_helper(X, [], [],
- PropertyNames, State,
- length(X)) of
- {'EXCEPTION', E} ->
- {'EXCEPTION', E};
- {{'EXCEPTION', E}, NotDeleted} ->
- ok = mnesia_write(State, NotDeleted),
- {'EXCEPTION', E};
- {ok, NotDeleted} ->
- mnesia_write(State, NotDeleted)
- end
- end
- end,
- {reply, mnesia_transaction(_DF), State};
-delete_properties(_OE_THIS, State, PropertyNames) ->
- X = lookup_table(?get_DBKey(State)),
- case delete_properties_helper(X, [], [], PropertyNames, State, length(X)) of
- {'EXCEPTION', E} ->
- corba:raise(E);
- _->
- %% Not acceptable if it was possible to delete one or more Properties.
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-delete_properties_helper([], [], NotDeleted, [], _State, _Len) ->
- %% Since there are no exceptions we have been able to delete all
- %% properties.
- {ok, NotDeleted};
-delete_properties_helper([], MultipleExc, NotDeleted, Names, _State, Len) ->
- %% Write remaining events to DB.
- case length(NotDeleted) of
- Len ->
- {'EXCEPTION', #'CosPropertyService_MultipleExceptions'
- {exceptions = add_not_found(Names, MultipleExc)}};
- _->
- {{'EXCEPTION', #'CosPropertyService_MultipleExceptions'
- {exceptions = add_not_found(Names, MultipleExc)}},
- NotDeleted}
- end;
-delete_properties_helper([{Name, Val, Mode}|T], MultipleExc, NotDeleted,
- Names, State, Len) ->
- case lists:member(Name, Names) of
- true when Mode =/= fixed_normal, Mode =/= fixed_readonly ->
- delete_properties_helper(T, MultipleExc, NotDeleted,
- lists:delete(Name, Names), State, Len);
- true ->
- delete_properties_helper(T, [#'CosPropertyService_PropertyException'
- {reason = fixed_property,
- failing_property_name = Name}|MultipleExc],
- [{Name, Val, Mode}|NotDeleted],
- lists:delete(Name, Names), State, Len);
- false ->
- delete_properties_helper(T, MultipleExc, [{Name, Val, Mode}|NotDeleted],
- Names, State, Len)
- end.
-
-add_not_found([], MultipleExc) ->
- MultipleExc;
-add_not_found([Name|T], MultipleExc) ->
- add_not_found(T, [#'CosPropertyService_PropertyException'
- {reason = property_not_found,
- failing_property_name = Name}|MultipleExc]).
-
-
-
-%%---------------------------------------------------------------------%
-%% Function : delete_all_properties
-%% Arguments :
-%% Description:
-%% Returns : {ok, State}
-%%----------------------------------------------------------------------
-delete_all_properties(_OE_THIS, State) when ?is_NotStatic(State) ->
- _DF =
- fun() ->
- case mnesia_read(State) of
- {'EXCEPTION', E} ->
- {'EXCEPTION', E};
- X ->
- case catch delete_all_properties_helper(X, [], State,
- length(X)) of
- {'EXCEPTION', E} ->
- {'EXCEPTION', E};
- true ->
- ok = mnesia_write(State, []),
- true;
- false ->
- false;
- {false, NotDeleted} ->
- ok = mnesia_write(State, NotDeleted),
- false
- end
- end
- end,
- {reply, mnesia_transaction(_DF), State};
-delete_all_properties(_OE_THIS, State) ->
- X = lookup_table(?get_DBKey(State)),
- case delete_all_properties_helper(X, [], State, length(X)) of
- false ->
- {reply, false, State};
- _->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-delete_all_properties_helper([], [], _State, _) ->
- %% Was able to delete all properties.
- true;
-delete_all_properties_helper([], NotDeleted, _State, Len) ->
- %% Write remaining events to DB.
- case length(NotDeleted) of
- Len ->
- false;
- _->
- {false, NotDeleted}
- end;
-delete_all_properties_helper([{Name, Val, fixed_normal}|T], NotDeleted, State, Len) ->
- delete_all_properties_helper(T, [{Name, Val, fixed_normal}|NotDeleted], State, Len);
-delete_all_properties_helper([{Name, Val, fixed_readonly}|T], NotDeleted, State, Len) ->
- delete_all_properties_helper(T, [{Name, Val, fixed_readonly}|NotDeleted], State, Len);
-delete_all_properties_helper([_|T], NotDeleted, State, Len) ->
- delete_all_properties_helper(T, NotDeleted, State, Len).
-
-%%---------------------------------------------------------------------%
-%% Function : is_property_defined
-%% Arguments :
-%% Description:
-%% Returns : {ok, State}
-%%----------------------------------------------------------------------
-is_property_defined(_, _, "") ->
- corba:raise(#'CosPropertyService_InvalidPropertyName'{});
-is_property_defined(_OE_THIS, State, Name) ->
- X = lookup_table(?get_DBKey(State)),
- {reply, lists:keymember(Name, 1, X), State}.
-
-%%----------------------------------------------------------------------
-%% Interface CosPropertyService::PropertySetDef
-%%----------------------------------------------------------------------
-%%---------------------------------------------------------------------%
-%% Function : get_allowed_property_types
-%% Arguments : -
-%% Description: Returns the initially supplied restrictions. An empty
-%% list means no restrictions.
-%% Returns : {ok, TypeCodeList,State}
-%%----------------------------------------------------------------------
-get_allowed_property_types(_OE_THIS, State) when ?is_NotSetDef(State) ->
- corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO});
-get_allowed_property_types(_OE_THIS, State) ->
- {reply, {ok, ?get_okTypes(State)}, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : get_allowed_properties
-%% Arguments :
-%% Description: Returns the initially supplied restrictions. An empty
-%% list means no restrictions.
-%% Returns : {ok, PropertyDefList, State}
-%%----------------------------------------------------------------------
-get_allowed_properties(_OE_THIS, State) when ?is_NotSetDef(State) ->
- corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO});
-get_allowed_properties(_OE_THIS, State) ->
- {reply, {ok, ?get_okProperties(State)}, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : define_property_with_mode
-%% Arguments :
-%% Description:
-%% Returns : {ok, State}
-%%----------------------------------------------------------------------
-define_property_with_mode(_OE_THIS, State, _, _, _) when ?is_NotSetDef(State) ->
- corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO});
-define_property_with_mode(_, _, "", _, _) ->
- corba:raise(#'CosPropertyService_InvalidPropertyName'{});
-define_property_with_mode(_OE_THIS, State, Name, Value, Mode)
- when ?is_NotStatic(State) ->
- evaluate_property_data(State, Value, Name),
- _DF =
- fun() ->
- case mnesia_read(State) of
- {'EXCEPTION', E} ->
- {'EXCEPTION', E};
- X ->
- case catch update_property(X, Name, both, Value, Mode) of
- {'EXCEPTION', E}
- when is_record(E, 'CosPropertyService_PropertyNotFound') ->
- mnesia_write(State, [{Name, Value, Mode}|X]);
- {'EXCEPTION', E} ->
- {'EXCEPTION', E};
- NewProperties ->
- mnesia_write(State, NewProperties)
- end
- end
- end,
- {reply, mnesia_transaction(_DF), State};
-define_property_with_mode(_OE_THIS, State, Name, Value, Mode) ->
- evaluate_property_data(State, Value, Name),
- X = lookup_table(?get_DBKey(State)),
- case catch update_property(X, Name, both, Value, Mode) of
- {'EXCEPTION', E} when is_record(E, 'CosPropertyService_PropertyNotFound') ->
- %% Should get not allowed exception.
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO});
- {'EXCEPTION', E} ->
- corba:raise(E);
- _ ->
- %% Should be impossible.
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-%%---------------------------------------------------------------------%
-%% Function : define_properties_with_modes
-%% Arguments :
-%% Description:
-%% Returns : {ok, State}
-%%----------------------------------------------------------------------
-define_properties_with_modes(_OE_THIS, State, _) when ?is_NotSetDef(State) ->
- corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO});
-define_properties_with_modes(_OE_THIS, State, PropertyDefSeq)
- when ?is_NotStatic(State)->
- {OKProperteDefs, Exc} = evaluate_properties_data(State, PropertyDefSeq),
- _DF =
- fun() ->
- case mnesia_read(State) of
- {'EXCEPTION', E} ->
- {'EXCEPTION', E};
- X ->
- case catch define_properties_with_modes_helper(OKProperteDefs,
- X, Exc, State) of
- {'EXCEPTION', E} ->
- {'EXCEPTION', E};
- NewProperties ->
- mnesia_write(State, NewProperties)
- end
- end
- end,
- {reply, mnesia_transaction(_DF), State};
-define_properties_with_modes(_OE_THIS, State, PropertyDefSeq) ->
- {OKProperteDefs, Exc} = evaluate_properties_data(State, PropertyDefSeq),
- X = lookup_table(?get_DBKey(State)),
- case define_properties_with_modes_helper(OKProperteDefs, X, Exc, State) of
- {'EXCEPTION', E} ->
- corba:raise(E);
- _ ->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-
-define_properties_with_modes_helper([], NewPropertyDefs, [], _State) ->
- %% No exceptions found.
- NewPropertyDefs;
-define_properties_with_modes_helper([], _, Exc, _) ->
- {'EXCEPTION', #'CosPropertyService_MultipleExceptions'{exceptions = Exc}};
-define_properties_with_modes_helper([#'CosPropertyService_PropertyDef'
- {property_name = Name,
- property_value = Value,
- property_mode = Mode}|T], X, Exc, State) ->
- case catch update_property(X, Name, both, Value, Mode) of
- {'EXCEPTION', E} when is_record(E, 'CosPropertyService_PropertyNotFound') ->
- define_properties_with_modes_helper(T, [{Name, Value, Mode}|X], Exc, State);
- {'EXCEPTION', E} ->
- define_properties_with_modes_helper(T, X,
- [#'CosPropertyService_PropertyException'
- {reason = remap_exception(E),
- failing_property_name = Name}|Exc],
- State);
- NewX ->
- define_properties_with_modes_helper(T, NewX, Exc, State)
- end.
-
-%%---------------------------------------------------------------------%
-%% Function : get_property_mode
-%% Arguments :
-%% Description:
-%% Returns : {ok, State}
-%%----------------------------------------------------------------------
-get_property_mode(_OE_THIS, State, _) when ?is_NotSetDef(State) ->
- corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO});
-get_property_mode(_, _, "") ->
- corba:raise(#'CosPropertyService_InvalidPropertyName'{});
-get_property_mode(_OE_THIS, State, Name) ->
- X = lookup_table(?get_DBKey(State)),
- {reply, find_property(X, Name, mode), State}.
-
-%%---------------------------------------------------------------------%
-%% Function : get_property_modes
-%% Arguments :
-%% Description:
-%% Returns : {ok, State}
-%%----------------------------------------------------------------------
-get_property_modes(_OE_THIS, State, _) when ?is_NotSetDef(State) ->
- corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO});
-get_property_modes(_OE_THIS, State, PropertyNames) ->
- X = lookup_table(?get_DBKey(State)),
- {reply, get_property_modes_helper(PropertyNames, X, [], true), State}.
-
-get_property_modes_helper([], _, Acc, Bool) ->
- {Bool, Acc};
-get_property_modes_helper([""|T], Properties, Acc, _) ->
- get_property_modes_helper(T, Properties,
- [#'CosPropertyService_PropertyMode'
- {property_name = "",
- property_mode = undefined}|Acc], false);
-get_property_modes_helper([Name|T], Properties, Acc, Bool) ->
- case lists:keysearch(Name, 1, Properties) of
- {value, {Name, _, Mode}} ->
- get_property_modes_helper(T, Properties,
- [#'CosPropertyService_PropertyMode'
- {property_name = Name,
- property_mode = Mode}|Acc], Bool);
- false ->
- get_property_modes_helper(T, Properties,
- [#'CosPropertyService_PropertyMode'
- {property_name = Name,
- property_mode = undefined}|Acc], false)
- end.
-
-%%---------------------------------------------------------------------%
-%% Function : set_property_mode
-%% Arguments :
-%% Description:
-%% Returns : {ok, State}
-%%----------------------------------------------------------------------
-set_property_mode(_OE_THIS, State, _, _) when ?is_NotSetDef(State) ->
- corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO});
-set_property_mode(_, _, "", _) ->
- corba:raise(#'CosPropertyService_InvalidPropertyName'{});
-set_property_mode(_OE_THIS, State, Name, Mode) when ?is_NotStatic(State) ->
- _DF =
- fun() ->
- case mnesia_read(State) of
- {'EXCEPTION', E} ->
- {'EXCEPTION', E};
- X ->
- case catch update_property(X, Name, mode, undefined, Mode) of
- {'EXCEPTION', E} ->
- {'EXCEPTION', E};
- NewProperties ->
- mnesia_write(State, NewProperties)
- end
- end
- end,
- {reply, mnesia_transaction(_DF), State};
-set_property_mode(_OE_THIS, State, Name, Mode) ->
- X = lookup_table(?get_DBKey(State)),
- update_property(X, Name, mode, undefined, Mode),
- %% Something is not correct, shouldn't be allowed to update a property when
- %% static.
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}).
-
-%%---------------------------------------------------------------------%
-%% Function : set_property_modes
-%% Arguments :
-%% Description:
-%% Returns : {ok, State}
-%%----------------------------------------------------------------------
-set_property_modes(_OE_THIS, State, _) when ?is_NotSetDef(State) ->
- corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO});
-set_property_modes(_OE_THIS, State, PropertyModes) when ?is_NotStatic(State) ->
- _DF =
- fun() ->
- case mnesia_read(State) of
- {'EXCEPTION', E} ->
- {'EXCEPTION', E};
- X ->
- case catch set_property_modes_helper(PropertyModes, X, [],
- State) of
- {'EXCEPTION', E} ->
- {'EXCEPTION', E};
- NewProperties ->
- mnesia_write(State, NewProperties)
- end
- end
- end,
- {reply, mnesia_transaction(_DF), State};
-set_property_modes(_OE_THIS, State, PropertyModes) ->
- X = lookup_table(?get_DBKey(State)),
- case set_property_modes_helper(PropertyModes, X, [], State) of
- {'EXCEPTION', E} ->
- corba:raise(E);
- _ ->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-set_property_modes_helper([], NewProperties, [], _State) ->
- %% No exceptions, write to DB.
- NewProperties;
-set_property_modes_helper([], _, Exc, _) ->
- {'EXCEPTION', #'CosPropertyService_MultipleExceptions'{exceptions = Exc}};
-set_property_modes_helper([#'CosPropertyService_PropertyMode'
- {property_name = Name,
- property_mode = Mode}|T], X, Exc, State) ->
- case catch update_property(X, Name, mode, undefined, Mode) of
- {'EXCEPTION', E} ->
- set_property_modes_helper(T, X,
- [#'CosPropertyService_PropertyException'
- {reason = remap_exception(E),
- failing_property_name = Name}|Exc],
- State);
- NewX ->
- set_property_modes_helper(T, NewX, Exc, State)
- end.
-
-
-%%======================================================================
-%% Internal functions
-%%======================================================================
-
-remap_exception(#'CosPropertyService_ConflictingProperty'{}) -> conflicting_property;
-remap_exception(#'CosPropertyService_FixedProperty'{}) -> fixed_property;
-remap_exception(#'CosPropertyService_InvalidPropertyName'{}) -> invalid_property_name;
-remap_exception(#'CosPropertyService_PropertyNotFound'{}) -> property_not_found;
-remap_exception(#'CosPropertyService_UnsupportedTypeCode'{}) -> unsupported_type_code;
-remap_exception(#'CosPropertyService_UnsupportedProperty'{}) -> unsupported_property;
-remap_exception(#'CosPropertyService_ReadOnlyProperty'{}) -> read_only_property;
-remap_exception(#'CosPropertyService_UnsupportedMode'{}) -> unsupported_mode.
-
-find_property([], _, _) ->
- corba:raise(#'CosPropertyService_PropertyNotFound'{});
-find_property([{Name, Value, _}|_], Name, value) ->
- Value;
-find_property([{Name, _, Mode}|_], Name, mode) ->
- Mode;
-% Left out for now to avoid dialyzer warning.
-%find_property([{Name, Value, Mode}|_], Name, all) ->
-% {Name, Value, Mode};
-find_property([_|T], Name, Which) ->
- find_property(T, Name, Which).
-
-remove_property(PropertList, Name) ->
- remove_property(PropertList, Name, []).
-remove_property([], _, _) ->
- corba:raise(#'CosPropertyService_PropertyNotFound'{});
-remove_property([{Name, _, fixed_normal}|_T], Name, _) ->
- corba:raise(#'CosPropertyService_FixedProperty'{});
-remove_property([{Name, _, fixed_readonly}|_T], Name, _) ->
- corba:raise(#'CosPropertyService_FixedProperty'{});
-remove_property([{Name, _, _}|T], Name, Acc) ->
- T++Acc;
-remove_property([H|T], Name, Acc) ->
- remove_property(T, Name, [H|Acc]).
-
-
-update_property(_, "", _, _, _) ->
- corba:raise(#'CosPropertyService_InvalidPropertyName'{});
-update_property(PropertyList, Name, Which, Value, Mode) ->
- update_property(PropertyList, Name, Which, Value, Mode, []).
-
-update_property([], _, _, _, _, _) ->
- corba:raise(#'CosPropertyService_PropertyNotFound'{});
-update_property([{Name, _, fixed_readonly}|_], Name, value, _, _, _) ->
- corba:raise(#'CosPropertyService_FixedProperty'{});
-update_property([{Name, _, fixed_normal}|_], Name, both, _, _, _) ->
- corba:raise(#'CosPropertyService_FixedProperty'{});
-update_property([{Name, _, fixed_readonly}|_], Name, both, _, _, _) ->
- corba:raise(#'CosPropertyService_FixedProperty'{});
-update_property([{Name, #any{typecode = TC}, Mode}|T], Name,
- value, #any{typecode = TC, value = Value}, _Mod, Acc) ->
- [{Name, #any{typecode = TC, value = Value}, Mode}|T]++Acc;
-update_property([{Name, #any{typecode = TC}, _Mode}|T], Name,
- both, #any{typecode = TC, value = Value}, Mod, Acc) ->
- [{Name, #any{typecode = TC, value = Value}, Mod}|T]++Acc;
-update_property([{Name, _, _}|_], Name, value, _, _, _) ->
- corba:raise(#'CosPropertyService_ConflictingProperty'{});
-update_property([{Name, _, _}|_], Name, both, _, _, _) ->
- corba:raise(#'CosPropertyService_ConflictingProperty'{});
-%% Normally we don't need to raise an exception for the two following cases but
-%% to be able to manage static Properties we must raise an exception. Well,
-%% on the other hand, why should a user try to change a mode to the same value?!
-%% But we have no other option.
-update_property([{Name, _Value, fixed_normal}|_T], Name, mode, _, fixed_normal, _Acc) ->
- corba:raise(#'CosPropertyService_FixedProperty'{});
-update_property([{Name, _Value, fixed_readonly}|_T], Name, mode, _, fixed_readonly, _Acc) ->
- corba:raise(#'CosPropertyService_FixedProperty'{});
-update_property([{Name, _Value, fixed_normal}|_T], Name, mode, _, _Mode, _Acc) ->
- corba:raise(#'CosPropertyService_UnsupportedMode'{});
-update_property([{Name, _Value, fixed_readonly}|_T], Name, mode, _, _Mode, _Acc) ->
- corba:raise(#'CosPropertyService_UnsupportedMode'{});
-update_property([{Name, Value, _}|T], Name, mode, _, Mode, Acc) ->
- [{Name, Value, Mode}|T]++Acc;
-update_property([H|T], Name, Which, Value, Mode, Acc) ->
- update_property(T, Name, Which, Value, Mode, [H|Acc]).
-
-
-lookup_table(Key) when is_binary(Key) ->
- _RF = ?read_function({oe_CosPropertyService, Key}),
- case mnesia:transaction(_RF) of
- {atomic, [#oe_CosPropertyService{properties=Properties}]} ->
- Properties;
- {atomic, []} ->
- corba:raise(#'OBJECT_NOT_EXIST'{completion_status=?COMPLETED_NO});
- _Other ->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end;
-lookup_table(Key) when is_list(Key) ->
- Key;
-lookup_table(_) ->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}).
-
-mnesia_transaction(Fun) ->
- case mnesia:transaction(Fun) of
- {atomic, {'EXCEPTION', E}} ->
- corba:raise(E);
- {atomic, ok} ->
- ok;
- {atomic, Reply} ->
- Reply;
- _Other ->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-mnesia_read(State) ->
- case mnesia:wread({oe_CosPropertyService, ?get_DBKey(State)}) of
- [#oe_CosPropertyService{properties = X}] ->
- X;
- _Other ->
- {'EXCEPTION', #'INTERNAL'{completion_status=?COMPLETED_NO}}
- end.
-
-mnesia_write(State, X) ->
- mnesia:write(#oe_CosPropertyService{key = ?get_DBKey(State), properties = X}).
-
-%% Check a write transaction
-write_result({atomic,ok}) -> ok;
-write_result(_Foo) ->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}).
-
-evaluate_properties_data(State, PropertySeq) ->
- evaluate_properties_data(State, PropertySeq, [], []).
-
-evaluate_properties_data(_State, [], OKProperties, Exc) ->
- {OKProperties, Exc};
-
-evaluate_properties_data(State, [#'CosPropertyService_Property'
- {property_name = Name,
- property_value = Value}|T], Acc, Exc) ->
- case catch evaluate_property_data(State, Value, Name) of
- ok ->
- evaluate_properties_data(State, T, [#'CosPropertyService_Property'
- {property_name = Name,
- property_value = Value}|Acc], Exc);
- {'EXCEPTION', E} when is_record(E, 'CosPropertyService_UnsupportedTypeCode') ->
- evaluate_properties_data(State, T, Acc,
- [#'CosPropertyService_PropertyException'
- {reason = unsupported_type_code,
- failing_property_name = Name}|Exc]);
- {'EXCEPTION', E} when is_record(E, 'CosPropertyService_UnsupportedProperty') ->
- evaluate_properties_data(State, T, Acc,
- [#'CosPropertyService_PropertyException'
- {reason = unsupported_property,
- failing_property_name = Name}|Exc])
- end;
-evaluate_properties_data(State, [#'CosPropertyService_PropertyDef'
- {property_name = Name,
- property_value = Value,
- property_mode = Mode}|T], Acc, Exc) ->
- case catch evaluate_property_data(State, Value, Name) of
- ok ->
- evaluate_properties_data(State, T, [#'CosPropertyService_PropertyDef'
- {property_name = Name,
- property_value = Value,
- property_mode = Mode}|Acc], Exc);
- {'EXCEPTION', E} when is_record(E, 'CosPropertyService_UnsupportedTypeCode') ->
- evaluate_properties_data(State, T, Acc,
- [#'CosPropertyService_PropertyException'
- {reason = unsupported_type_code,
- failing_property_name = Name}|Exc]);
- {'EXCEPTION', E} when is_record(E, 'CosPropertyService_UnsupportedProperty') ->
- evaluate_properties_data(State, T, Acc,
- [#'CosPropertyService_PropertyException'
- {reason = unsupported_property,
- failing_property_name = Name}|Exc])
- end;
-evaluate_properties_data(_, _, _, _) ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-evaluate_property_data(State, _, _) when ?no_PropertyLimits(State),
- ?no_TypeLimits(State) ->
- ok;
-evaluate_property_data(State, Value, _Name) when ?no_PropertyLimits(State) ->
- case lists:member(any:get_typecode(Value), ?get_okTypes(State)) of
- true ->
- ok;
- _ ->
- corba:raise(#'CosPropertyService_UnsupportedTypeCode'{})
- end;
-evaluate_property_data(State, _Value, Name) when ?no_TypeLimits(State) ->
- case lists:any(?MemberName(Name), ?get_okProperties(State)) of
- true ->
- ok;
- _ ->
- corba:raise(#'CosPropertyService_UnsupportedProperty'{})
- end;
-evaluate_property_data(State, Value, Name) ->
- case lists:any(?MemberName(Name), ?get_okProperties(State)) of
- true ->
- case lists:member(any:get_typecode(Value), ?get_okTypes(State)) of
- true ->
- ok;
- _ ->
- corba:raise(#'CosPropertyService_UnsupportedTypeCode'{})
- end;
- _ ->
- corba:raise(#'CosPropertyService_UnsupportedProperty'{})
- end.
-
-
-%%----------------------------------------------------------------------
-%% Debugging functions
-%%----------------------------------------------------------------------
-dump() ->
- case catch mnesia:dirty_first('oe_CosPropertyService') of
- {'EXIT', R} ->
- io:format("Exited with ~p\n",[R]);
- Key ->
- dump_print(Key),
- dump_loop(Key)
- end.
-
-dump_loop(PreviousKey) ->
- case catch mnesia:dirty_next('oe_CosPropertyService', PreviousKey) of
- {'EXIT', R} ->
- io:format("Exited with ~p\n",[R]);
- '$end_of_table' ->
- ok;
- Key ->
- dump_print(Key),
- dump_loop(Key)
- end.
-
-dump_print(Key) ->
- case catch mnesia:dirty_read({'oe_CosPropertyService', Key}) of
- {'EXIT', R} ->
- io:format("Exited with ~p\n",[R]);
- [{_,_,X}] ->
- io:format("Property: ~p~n", [X]);
- _ ->
- ok
- end.
-
-
-%%-------------------------- END OF MODULE -----------------------------
diff --git a/lib/cosProperty/src/CosPropertyService_PropertySetFactory_impl.erl b/lib/cosProperty/src/CosPropertyService_PropertySetFactory_impl.erl
deleted file mode 100644
index bc6572b634..0000000000
--- a/lib/cosProperty/src/CosPropertyService_PropertySetFactory_impl.erl
+++ /dev/null
@@ -1,183 +0,0 @@
-%%----------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : CosPropertyService_PropertySetFactory_impl.erl
-%% Description :
-%%
-%%----------------------------------------------------------------------
--module('CosPropertyService_PropertySetFactory_impl').
-
-%%----------------------------------------------------------------------
-%% Include files
-%%----------------------------------------------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
--include("CosPropertyService.hrl").
--include("cosProperty.hrl").
-
-%%----------------------------------------------------------------------
-%% External exports
-%%----------------------------------------------------------------------
--export([init/1,
- terminate/2,
- code_change/3]).
-
--export([create_propertyset/2,
- create_constrained_propertyset/4,
- create_initial_propertyset/3]).
-
-
-%%----------------------------------------------------------------------
-%% Internal exports
-%%----------------------------------------------------------------------
--export([]).
-
-%%----------------------------------------------------------------------
-%% Records
-%%----------------------------------------------------------------------
--record(state, {}).
-
-%%----------------------------------------------------------------------
-%% Macros
-%%----------------------------------------------------------------------
--define(checkTCfun, fun(TC) -> orber_tc:check_tc(TC) end).
-
-%%======================================================================
-%% External functions
-%%======================================================================
-%%----------------------------------------------------------------------
-%% Function : init/1
-%% Returns : {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
-%% Description: Initiates the server
-%%----------------------------------------------------------------------
-init([]) ->
- {ok, #state{}}.
-
-%%----------------------------------------------------------------------
-%% Function : terminate/2
-%% Returns : any (ignored by gen_server)
-%% Description: Shutdown the server
-%%----------------------------------------------------------------------
-terminate(_Reason, _State) ->
- ok.
-
-%%----------------------------------------------------------------------
-%% Function : code_change/3
-%% Returns : {ok, NewState}
-%% Description: Convert process state when code is changed
-%%----------------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%----------------------------------------------------------------------
-%% Function : create_propertyset
-%% Arguments :
-%% Returns : CosPropertyService::PropertySet reference.
-%% Description:
-%%----------------------------------------------------------------------
-create_propertyset(_OE_This, State) ->
- {reply,
- 'CosPropertyService_PropertySetDef':
- oe_create({normal, [], [], [], ?PropertySet}, [{pseudo, true}]),
- State}.
-
-%%----------------------------------------------------------------------
-%% Function : create_constrained_propertyset
-%% Arguments : PropTypes - list of property types.
-%% Properties - list of properties.
-%% Returns : CosPropertyService::PropertySet |
-%% {'EXCEPTION', CosPropertyService::ConstraintNotSupported}
-%% Description:
-%%----------------------------------------------------------------------
-create_constrained_propertyset(_OE_This, State, PropTypes, Properties) ->
- case lists:all(?checkTCfun, PropTypes) of
- true ->
- crosscheckTC(Properties, PropTypes),
- {reply,
- 'CosPropertyService_PropertySetDef':
- oe_create({normal, PropTypes, Properties, [], ?PropertySet},
- [{pseudo, true}]),
- State};
- false ->
- corba:raise(#'CosPropertyService_ConstraintNotSupported'{})
- end.
-
-crosscheckTC([], _) ->
- ok;
-crosscheckTC([#'CosPropertyService_Property'
- {property_name = Name,
- property_value = Value}|T], TCs) ->
- case lists:member(any:get_typecode(Value), TCs) of
- true when Name =/= "" ->
- crosscheckTC(T, TCs);
- _ ->
- corba:raise(#'CosPropertyService_ConstraintNotSupported'{})
- end.
-
-%%----------------------------------------------------------------------
-%% Function : create_initial_propertyset
-%% Arguments : Properties - list of properties.
-%% Returns : CosPropertyService::PropertySetDef |
-%% {'EXCEPTION', CosPropertyService::MultipleExceptions}
-%% Description:
-%%----------------------------------------------------------------------
-create_initial_propertyset(_OE_This, State, Properties) ->
- InitProps = evaluate_propertyset(Properties),
- {reply,
- 'CosPropertyService_PropertySetDef':
- oe_create({normal, [], [], InitProps, ?PropertySet}, [{pseudo, true}]),
- State}.
-
-%%======================================================================
-%% Internal functions
-%%======================================================================
-evaluate_propertyset(Sets) ->
- case evaluate_propertyset(Sets, [], []) of
- {ok, NewProperties} ->
- NewProperties;
- {error, Exc} ->
- corba:raise(#'CosPropertyService_MultipleExceptions'{exceptions = Exc})
- end.
-
-evaluate_propertyset([], NewProperties, []) ->
- %% No exceptions found.
- {ok, NewProperties};
-evaluate_propertyset([], _, Exc) ->
- {error, Exc};
-evaluate_propertyset([#'CosPropertyService_Property'
- {property_name = Name,
- property_value = Value}|T], X, Exc) ->
- case orber_tc:check_tc(any:get_typecode(Value)) of
- true ->
- evaluate_propertyset(T, [{Name, Value, normal}|X], Exc);
- false ->
- evaluate_propertyset(T, X, [#'CosPropertyService_PropertyException'
- {reason = unsupported_type_code,
- failing_property_name = Name}|Exc])
- end.
-
-%%======================================================================
-%% END OF MODULE
-%%======================================================================
diff --git a/lib/cosProperty/src/Makefile b/lib/cosProperty/src/Makefile
deleted file mode 100644
index 1fdc258a6d..0000000000
--- a/lib/cosProperty/src/Makefile
+++ /dev/null
@@ -1,188 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2000-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-
-ifeq ($(TYPE),debug)
-ERL_COMPILE_FLAGS += -Ddebug -W
-endif
-
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(COSPROPERTY_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/cosProperty-$(VSN)
-
-EXTERNAL_INC_PATH = ../include
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-
-MODULES = \
- cosProperty \
- CosPropertyService_PropertySetDefFactory_impl \
- CosPropertyService_PropertySetDef_impl \
- CosPropertyService_PropertySetFactory_impl \
- CosPropertyService_PropertiesIterator_impl \
- CosPropertyService_PropertyNamesIterator_impl
-
-
-ERL_FILES = $(MODULES:%=%.erl)
-HRL_FILES = \
- cosProperty.hrl \
-
-GEN_ERL_FILES = \
- oe_CosProperty.erl \
- CosPropertyService_ConflictingProperty.erl \
- CosPropertyService_ConstraintNotSupported.erl \
- CosPropertyService_FixedProperty.erl \
- CosPropertyService_InvalidPropertyName.erl \
- CosPropertyService_MultipleExceptions.erl \
- CosPropertyService_Properties.erl \
- CosPropertyService_PropertiesIterator.erl \
- CosPropertyService_Property.erl \
- CosPropertyService_PropertyDef.erl \
- CosPropertyService_PropertyDefs.erl \
- CosPropertyService_PropertyException.erl \
- CosPropertyService_PropertyExceptions.erl \
- CosPropertyService_PropertyMode.erl \
- CosPropertyService_PropertyModes.erl \
- CosPropertyService_PropertyNames.erl \
- CosPropertyService_PropertyNamesIterator.erl \
- CosPropertyService_PropertyNotFound.erl \
- CosPropertyService_PropertySet.erl \
- CosPropertyService_PropertySetDef.erl \
- CosPropertyService_PropertySetDefFactory.erl \
- CosPropertyService_PropertySetFactory.erl \
- CosPropertyService_PropertyTypes.erl \
- CosPropertyService_ReadOnlyProperty.erl \
- CosPropertyService_UnsupportedMode.erl \
- CosPropertyService_UnsupportedProperty.erl \
- CosPropertyService_UnsupportedTypeCode.erl
-
-LOCAL_HRL_FILES = \
- oe_CosProperty.hrl \
- CosPropertyService.hrl \
- CosPropertyService_PropertiesIterator.hrl \
- CosPropertyService_PropertyNamesIterator.hrl \
- CosPropertyService_PropertySet.hrl \
- CosPropertyService_PropertySetDef.hrl \
- CosPropertyService_PropertySetDefFactory.hrl \
- CosPropertyService_PropertySetFactory.hrl
-
-GEN_HRL_FILES = $(LOCAL_HRL_FILES:%=$(EXTERNAL_INC_PATH)/%)
-
-GEN_FILES = \
- $(GEN_HRL_FILES) \
- $(GEN_ERL_FILES)
-
-TARGET_FILES = \
- $(GEN_ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR)) \
- $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-
-IDL_FILES = \
- CosProperty.idl
-
-APPUP_FILE = cosProperty.appup
-APPUP_SRC = $(APPUP_FILE).src
-APPUP_TARGET = $(EBIN)/$(APPUP_FILE)
-
-APP_FILE = cosProperty.app
-APP_SRC = $(APP_FILE).src
-APP_TARGET = $(EBIN)/$(APP_FILE)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_IDL_FLAGS += -pa $(ERL_TOP)/lib/cosProperty/ebin \
- -pa $(ERL_TOP)/lib/ic/ebin\
- -pa $(ERL_TOP)/lib/orber/ebin
-
-# The -pa option is just used temporary until erlc can handle
-# includes from other directories than ../include .
-ERL_COMPILE_FLAGS += \
- $(ERL_IDL_FLAGS) \
- -pa $(ERL_TOP)/lib/orber/include \
- -pa $(ERL_TOP)/lib/cosProperty/include \
- -I$(ERL_TOP)/lib/cosProperty/include \
- -I$(ERL_TOP)/lib/orber/include \
- +'{parse_transform,sys_pre_attributes}' \
- +'{attribute,insert,app_vsn,"cosProperty_$(COSPROPERTY_VSN)"}'
-
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
-
-debug:
- @${MAKE} TYPE=debug opt
-
-cleanb:
- rm -f $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
- rm -f errs core *~
-
-clean:
- rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET) IDL-GENERATED
- rm -f errs core *~
-
-$(APP_TARGET): $(APP_SRC)
- $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
-
-$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
-
-docs:
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-IDL-GENERATED: CosProperty.idl
- $(gen_verbose)erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosProperty.cfg"}' CosProperty.idl
- $(V_at)mv $(LOCAL_HRL_FILES) $(EXTERNAL_INC_PATH)
- $(V_at)>IDL-GENERATED
-
-$(GEN_FILES): IDL-GENERATED
-
-$(TARGET_FILES): IDL-GENERATED
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
- $(INSTALL_DIR) "$(RELSYSDIR)/src"
- $(INSTALL_DATA) $(GEN_FILES) $(IDL_FILES) "$(RELSYSDIR)/src"
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(GEN_ERL_FILES) $(IDL_FILES) "$(RELSYSDIR)/src"
- $(INSTALL_DIR) "$(RELSYSDIR)/include"
- $(INSTALL_DATA) $(GEN_HRL_FILES) "$(RELSYSDIR)/include"
-
-release_docs_spec:
diff --git a/lib/cosProperty/src/cosProperty.app.src b/lib/cosProperty/src/cosProperty.app.src
deleted file mode 100644
index 7fad7a602a..0000000000
--- a/lib/cosProperty/src/cosProperty.app.src
+++ /dev/null
@@ -1,47 +0,0 @@
-{application, cosProperty,
- [{description, "The Erlang CosProperty application"},
- {vsn, "%VSN%"},
- {modules,
- [
- 'cosProperty',
- 'CosPropertyService_PropertySetDefFactory_impl',
- 'CosPropertyService_PropertySetDef_impl',
- 'CosPropertyService_PropertySetFactory_impl',
- 'CosPropertyService_PropertiesIterator_impl',
- 'CosPropertyService_PropertyNamesIterator_impl',
- 'oe_CosProperty',
- 'CosPropertyService_ConflictingProperty',
- 'CosPropertyService_ConstraintNotSupported',
- 'CosPropertyService_FixedProperty',
- 'CosPropertyService_InvalidPropertyName',
- 'CosPropertyService_MultipleExceptions',
- 'CosPropertyService_Properties',
- 'CosPropertyService_PropertiesIterator',
- 'CosPropertyService_Property',
- 'CosPropertyService_PropertyDef',
- 'CosPropertyService_PropertyDefs',
- 'CosPropertyService_PropertyException',
- 'CosPropertyService_PropertyExceptions',
- 'CosPropertyService_PropertyMode',
- 'CosPropertyService_PropertyModes',
- 'CosPropertyService_PropertyNames',
- 'CosPropertyService_PropertyNamesIterator',
- 'CosPropertyService_PropertyNotFound',
- 'CosPropertyService_PropertySet',
- 'CosPropertyService_PropertySetDef',
- 'CosPropertyService_PropertySetDefFactory',
- 'CosPropertyService_PropertySetFactory',
- 'CosPropertyService_PropertyTypes',
- 'CosPropertyService_ReadOnlyProperty',
- 'CosPropertyService_UnsupportedMode',
- 'CosPropertyService_UnsupportedProperty',
- 'CosPropertyService_UnsupportedTypeCode'
- ]
- },
- {registered, [oe_cosPropertySup]},
- {applications, [orber, stdlib, kernel]},
- {env, []},
- {mod, {cosProperty, []}},
- {runtime_dependencies, ["stdlib-2.0","orber-3.6.27","mnesia-4.12",
- "kernel-3.0","erts-7.0"]}
-]}.
diff --git a/lib/cosProperty/src/cosProperty.appup.src b/lib/cosProperty/src/cosProperty.appup.src
deleted file mode 100644
index f3eead4a0c..0000000000
--- a/lib/cosProperty/src/cosProperty.appup.src
+++ /dev/null
@@ -1,6 +0,0 @@
-{"%VSN%",
- [
- ],
- [
- ]
-}.
diff --git a/lib/cosProperty/src/cosProperty.erl b/lib/cosProperty/src/cosProperty.erl
deleted file mode 100644
index e94d200c2f..0000000000
--- a/lib/cosProperty/src/cosProperty.erl
+++ /dev/null
@@ -1,416 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2015. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : cosProperty.erl
-%% Purpose :
-%%----------------------------------------------------------------------
-
--module(cosProperty).
-
-%%--------------- INCLUDES -----------------------------------
--include("cosProperty.hrl").
--include_lib("cosProperty/include/CosPropertyService.hrl").
-
-%%--------------- EXPORTS-------------------------------------
-%% cosProperty API external
--export([start/0,
- start_SetDefFactory/0,
- start_SetFactory/0,
- stop_SetDefFactory/1,
- stop_SetFactory/1,
- stop/0,
- install/0,
- install/1,
- install_db/0,
- install_db/1,
- install_db/2,
- uninstall/0,
- uninstall/1,
- uninstall_db/0]).
-
-%% cosProperty API internal
--export([create_link/3,
- get_option/3,
- type_check/2,
- query_result/1,
- start_PropertiesIterator/1,
- start_PropertyNamesIterator/1,
- create_static_SetDef/2]).
-
-%% Application callbacks
--export([start/2, init/1, stop/1]).
-
-%%--------------- DEFINES ------------------------------------
-
--define(SUPERVISOR_NAME, oe_cosPropertySup).
--define(SUP_FLAG, {simple_one_for_one,50,10}).
--define(SUP_PROP_SPEC(T,I),
- ['CosPropertyService_PropertiesIterator',I,
- [{sup_child, true}, {regname, {global, T}}]]).
--define(SUP_NAMES_SPEC(T,I),
- ['CosPropertyService_PropertyNamesIterator',I,
- [{sup_child, true}, {regname, {global, T}}]]).
--define(SUP_CHILD,
- {"oe_PropertyChild",
- {cosProperty,create_link, []},
- transient,100000,worker,
- []}).
-
-%%------------------------------------------------------------
-%% function : install
-%% Arguments: -
-%% Returns : ok | EXIT | EXCEPTION
-%% Effect : Install necessary data in the IFR DB
-%%------------------------------------------------------------
-install() ->
- install([]).
-install(_Options) ->
- case catch oe_CosProperty:'oe_register'() of
- ok ->
- ok;
- {'EXIT',{unregistered,App}} ->
- ?write_ErrorMsg("Unable to register cosProperty; application ~p not registered.~n",
- [App]),
- exit({unregistered,App});
- {'EXCEPTION',_} ->
- ?write_ErrorMsg("Unable to register cosProperty; propably already registered.
-You are adviced to confirm this.~n", []),
- exit({error, "Register in the IFR failed."});
- Reason ->
- ?write_ErrorMsg("Unable to register cosProperty; reason ~p", [Reason]),
- exit({error, "Register in the IFR failed."})
- end.
-
-%%------------------------------------------------------------
-%% function : install_db
-%% Arguments: -
-%% Returns : ok | EXIT | EXCEPTION
-%% Effect : Install necessary data in the IFR DB
-%%------------------------------------------------------------
-install_db() ->
- install_db(infinity, []).
-install_db(Timeout) ->
- install_db(Timeout, []).
-install_db(Timeout, Options) ->
- case install_table(Timeout, Options) of
- ok ->
- ok;
- {error, [DB_tables_created, Wait]} ->
- ?write_ErrorMsg("Able to register cosProperty but failed adding table in mnesia (~p, ~p)",
- [DB_tables_created, Wait]),
- exit({error, "Adding data in mnesia failed."});
- Why ->
- ?write_ErrorMsg("Able to register cosProperty but failed adding table in mnesia with reason ~p",
- [Why]),
- exit({error, "Adding data in mnesia failed."})
- end.
-
-%%------------------------------------------------------------
-%% function : install_table
-%% Arguments: -
-%% Returns : ok | {error, Data}
-%% Effect : Install necessary data in mnesia
-%%------------------------------------------------------------
-install_table(Timeout, Options) ->
- %% Fetch a list of the defined tables to see if 'oe_CosPropertyService'
- %% is defined.
- AllTabs = mnesia:system_info(tables),
- DB_tables_created =
- case lists:member('oe_CosPropertyService', AllTabs) of
- true ->
- case lists:member({local_content, true},
- Options) of
- true->
- mnesia:add_table_copy('oe_CosPropertyService',
- node(),
- ram_copies);
- _->
- mnesia:create_table('oe_CosPropertyService',[{attributes,
- record_info(fields,
- 'oe_CosPropertyService')}
- |Options])
- end;
- _ ->
- mnesia:create_table('oe_CosPropertyService',[{attributes,
- record_info(fields,
- 'oe_CosPropertyService')}
- |Options])
- end,
- Wait = mnesia:wait_for_tables(['oe_CosPropertyService'], Timeout),
- %% Check if any error has occured yet. If there are errors, return them.
- if
- DB_tables_created == {atomic, ok},
- Wait == ok ->
- ok;
- true ->
- {error, [DB_tables_created, Wait]}
- end.
-
-
-%%------------------------------------------------------------
-%% function : query_result
-%% Arguments: -
-%% Returns : error | Data
-%% Effect : Check a read transaction
-%%------------------------------------------------------------
-query_result(Qres) ->
- case Qres of
- {atomic, [Hres]} ->
- Hres#oe_CosPropertyService.properties;
- {atomic, [_Hres | _Tres]} ->
- error;
- {atomic, []} ->
- error;
- _Other ->
- error
- end.
-
-%%------------------------------------------------------------
-%% function : uninstall
-%% Arguments: -
-%% Returns : ok | EXIT | EXCEPTION
-%% Effect : Remove data related to cosProperty from the IFR DB
-%%------------------------------------------------------------
-uninstall() ->
- uninstall([]).
-uninstall(_Options) ->
- application:stop(cosProperty),
- oe_CosProperty:oe_unregister().
-
-%%------------------------------------------------------------
-%% function : uninstall
-%% Arguments: -
-%% Returns : ok | EXIT | EXCEPTION
-%% Effect : Remove data related to cosProperty from the IFR DB
-%%------------------------------------------------------------
-uninstall_db() ->
- application:stop(cosProperty),
- case mnesia:delete_table('oe_CosPropertyService') of
- {atomic, ok} ->
- ok;
- {aborted, _Reason} ->
- exit({error, "Removing data from mnesia failed."})
- end.
-
-%%------------------------------------------------------------
-%% function : create_static_SetDef
-%% Arguments:
-%% Returns :
-%% Effect : Starts or stops the cosProperty application.
-%%------------------------------------------------------------
-create_static_SetDef(PropTypes, PropDefs) ->
- InitProps = propertyDef2local(PropDefs, []),
- 'CosPropertyService_PropertySetDef':oe_create({static, fixed_readonly, PropTypes,
- PropDefs, InitProps,
- ?PropertySetDef},
- [{pseudo, true}]).
-propertyDef2local([#'CosPropertyService_PropertyDef'
- {property_name = Name,
- property_value = Value,
- property_mode = fixed_readonly}|T], Acc) ->
- propertyDef2local(T, [{Name, Value, fixed_readonly}|Acc]);
-propertyDef2local([], Acc) ->
- Acc;
-propertyDef2local(_, _) ->
- exit({error, "Bad Mode type supplied. Must be fixed_readonly"}).
-
-%%------------------------------------------------------------
-%% function : start/stop
-%% Arguments:
-%% Returns :
-%% Effect : Starts or stops the cosProperty application.
-%%------------------------------------------------------------
-start() ->
- application:start(cosProperty).
-stop() ->
- application:stop(cosProperty).
-
-
-
-%%-----------------------------------------------------------%
-%% function : start_SetDefFactory
-%% Arguments: -
-%% Returns : A PropertySetDefFactory reference.
-%% Effect :
-%%------------------------------------------------------------
-start_SetDefFactory() ->
- 'CosPropertyService_PropertySetDefFactory':oe_create([], [{pseudo, true}]).
-
-%%-----------------------------------------------------------%
-%% function : start_SetFactory
-%% Arguments: -
-%% Returns : A PropertySetFactory reference.
-%% Effect :
-%%------------------------------------------------------------
-start_SetFactory() ->
- 'CosPropertyService_PropertySetFactory':oe_create([], [{pseudo, true}]).
-
-%%-----------------------------------------------------------%
-%% function : stop_SetDefFactory
-%% Arguments: Factory - A PropertySetDefFactory reference.
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-stop_SetDefFactory(Factory) ->
- corba:dispose(Factory).
-
-%%-----------------------------------------------------------%
-%% function : stop_SetFactory
-%% Arguments: Factory - A PropertySetFactory reference.
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-stop_SetFactory(Factory) ->
- corba:dispose(Factory).
-
-%%------------------------------------------------------------
-%% function : start
-%% Arguments: Type - see module application
-%% Arg - see module application
-%% Returns :
-%% Effect : Module callback for application
-%%------------------------------------------------------------
-start(_, _) ->
- supervisor:start_link({local, ?SUPERVISOR_NAME}, cosProperty, app_init).
-
-
-%%------------------------------------------------------------
-%% function : stop
-%% Arguments: Arg - see module application
-%% Returns :
-%% Effect : Module callback for application
-%%------------------------------------------------------------
-stop(_) ->
- ok.
-
-%%-----------------------------------------------------------%
-%% function : init
-%% Arguments:
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-%% Starting using create_factory/X
-init(own_init) ->
- {ok,{?SUP_FLAG, [?SUP_CHILD]}};
-%% When starting as an application.
-init(app_init) ->
- {ok,{?SUP_FLAG, [?SUP_CHILD]}}.
-
-%%-----------------------------------------------------------%
-%% function : create_link
-%% Arguments: Module - which Module to call
-%% Env/ArgList - ordinary oe_create arguments.
-%% Returns :
-%% Exception:
-%% Effect : Necessary since we want the supervisor to be a
-%% 'simple_one_for_one'. Otherwise, using for example,
-%% 'one_for_one', we have to call supervisor:delete_child
-%% to remove the childs startspecification from the
-%% supervisors internal state.
-%%------------------------------------------------------------
-create_link(Module, Env, ArgList) ->
- Module:oe_create_link(Env, ArgList).
-
-%%-----------------------------------------------------------%
-%% function : start_PropertiesIterator
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-start_PropertiesIterator(Args) ->
- Name = create_name(propertiesIterator),
- case supervisor:start_child(?SUPERVISOR_NAME, ?SUP_PROP_SPEC(Name, Args)) of
- {ok, Pid, Obj} when is_pid(Pid) ->
- Obj;
- _Other->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-%%-----------------------------------------------------------%
-%% function : start_PropertyNamesIterator
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-start_PropertyNamesIterator(Args) ->
- Name = create_name(propertiesIterator),
- case supervisor:start_child(?SUPERVISOR_NAME, ?SUP_NAMES_SPEC(Name, Args)) of
- {ok, Pid, Obj} when is_pid(Pid) ->
- Obj;
- _Other->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-
-%%-----------------------------------------------------------%
-%% function : get_option
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-get_option(Key, OptionList, DefaultList) ->
- case lists:keysearch(Key, 1, OptionList) of
- {value,{Key,Value}} ->
- Value;
- _ ->
- case lists:keysearch(Key, 1, DefaultList) of
- {value,{Key,Value}} ->
- Value;
- _->
- {error, "Invalid option"}
- end
- end.
-
-%%-----------------------------------------------------------%
-%% function : type_check
-%% Arguments: Obj - objectrefernce to test.
-%% Mod - Module which contains typeID/0.
-%% Returns : 'ok' or raises exception.
-%% Effect :
-%%------------------------------------------------------------
-type_check(Obj, Mod) ->
- case catch corba_object:is_a(Obj,Mod:typeID()) of
- true ->
- ok;
- _ ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO})
- end.
-
-
-%%-----------------------------------------------------------%
-%% function : create_name/1
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-create_name(Type) ->
- Time = erlang:system_time(),
- Unique = erlang:unique_integer([positive]),
- lists:concat(['oe_',node(),'_',Type,'_',Time,'_',Unique]).
-
-%%--------------- END OF MODULE ------------------------------
-
-
diff --git a/lib/cosProperty/src/cosProperty.hrl b/lib/cosProperty/src/cosProperty.hrl
deleted file mode 100644
index 0225a43ebd..0000000000
--- a/lib/cosProperty/src/cosProperty.hrl
+++ /dev/null
@@ -1,82 +0,0 @@
-%%----------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : cosProperty.hrl
-%% Purpose :
-%%----------------------------------------------------------------------
-
-
-%%--------------- INCLUDES -----------------------------------
-%% External
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
-
-%%-----------------------------------------------------------------
-%% Mnesia Table definition record
-%%-----------------------------------------------------------------
--record('oe_CosPropertyService', {key, properties}).
-
-%%-----------------------------------------------------------------
-%% Macros
-%%-----------------------------------------------------------------
--define(PropertySet, 0).
--define(PropertySetDef, 1).
-
-%% This macro returns a read fun suitable for evaluation in a transaction
--define(read_function(Objkey),
- fun() ->
- mnesia:read(Objkey)
- end).
-
-%% This macro returns a write fun suitable for evaluation in a transaction
--define(write_function(R),
- fun() ->
- mnesia:write(R)
- end).
-
-%% This macro returns a delete fun suitable for evaluation in a transaction
--define(delete_function(R),
- fun() ->
- mnesia:delete(R)
- end).
-
--define(query_check(Q_res), {atomic, Q_res}).
-
-
--define(write_ErrorMsg(Txt, Arg),
-error_logger:error_msg("================ CosProperty ==============~n"
- Txt
- "===========================================~n",
- Arg)).
-
-
-
--ifdef(debug).
--define(debug_print(F,A),
- io:format("[LINE: ~p MODULE: ~p] "++F,[?LINE, ?MODULE]++A)).
--define(property_TypeCheck(O,M), 'cosProperty':type_check(O,M)).
--else.
--define(debug_print(F,A), ok).
--define(property_TypeCheck(O,I), ok).
--endif.
-
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/cosProperty/test/Makefile b/lib/cosProperty/test/Makefile
deleted file mode 100644
index 5f599c9621..0000000000
--- a/lib/cosProperty/test/Makefile
+++ /dev/null
@@ -1,129 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2000-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(COSPROPERTY_VSN)
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/cosProperty_test
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-TEST_SPEC_FILE = cosProperty.spec
-COVER_FILE = cosProperty.cover
-
-
-IDL_FILES =
-
-IDLOUTDIR = idl_output
-
-MODULES = \
- property_SUITE \
- generated_SUITE
-
-GEN_MODULES = \
-
-GEN_HRL_FILES = \
-
-ERL_FILES = $(MODULES:%=%.erl)
-
-HRL_FILES =
-
-GEN_FILES = \
- $(GEN_HRL_FILES:%=$(IDLOUTDIR)/%) \
- $(GEN_MODULES:%=$(IDLOUTDIR)/%.erl)
-
-GEN_TARGET_FILES = $(GEN_MODULES:%=$(IDLOUTDIR)/%.$(EMULATOR))
-
-SUITE_TARGET_FILES = $(MODULES:%=%.$(EMULATOR))
-
-TARGET_FILES = \
- $(GEN_TARGET_FILES) \
- $(SUITE_TARGET_FILES)
-
-
-# ----------------------------------------------------
-# PROGRAMS
-# ----------------------------------------------------
-LOCAL_CLASSPATH = $(ERL_TOP)lib/cosProperty/priv:$(ERL_TOP)lib/cosProperty/test
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_IDL_FLAGS += -pa $(ERL_TOP)/lib/cosProperty/ebin \
- -pa $(ERL_TOP)/lib/cosProperty/src \
- -pa $(ERL_TOP)/lib/orber/ebin \
- -pa $(ERL_TOP)/lib/ic/ebin
-
-ERL_COMPILE_FLAGS += \
- $(ERL_IDL_FLAGS) \
- -pa $(ERL_TOP)/lib/orber/include \
- -pa $(ERL_TOP)/lib/cosProperty/ebin \
- -pa $(ERL_TOP)/lib/cosProperty/test/idl_output \
- -I$(ERL_TOP)/lib/orber/include \
- -I$(ERL_TOP)/lib/cosProperty/src \
- -I$(ERL_TOP)/lib/cosProperty \
- -I$(ERL_TOP)/lib/cosProperty/test/$(IDLOUTDIR)
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-
-tests debug opt: $(TARGET_FILES)
-
-clean:
- rm -f idl_output/*
- rm -f $(TARGET_FILES)
- rm -f errs core *~
-
-docs:
-
-# ----------------------------------------------------
-# Special Targets
-# ----------------------------------------------------
-
-# ----------------------------------------------------
-# Release Targets
-# ----------------------------------------------------
-# We don't copy generated intermediate erlang and hrl files
-
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec:
-
-release_docs_spec:
-
-release_tests_spec: tests
- $(INSTALL_DIR) "$(RELSYSDIR)"
- $(INSTALL_DATA) $(IDL_FILES) $(TEST_SPEC_FILE) \
- $(COVER_FILE) $(ERL_FILES) "$(RELSYSDIR)"
- $(INSTALL_DATA) $(SUITE_TARGET_FILES) "$(RELSYSDIR)"
-# $(INSTALL_DIR) "$(RELSYSDIR)/$(IDLOUTDIR)"
-# $(INSTALL_DATA) $(GEN_TARGET_FILES) $(GEN_FILES) \
-# "$(RELSYSDIR)/$(IDLOUTDIR)"
-
diff --git a/lib/cosProperty/test/cosProperty.cover b/lib/cosProperty/test/cosProperty.cover
deleted file mode 100644
index a0f5f17671..0000000000
--- a/lib/cosProperty/test/cosProperty.cover
+++ /dev/null
@@ -1,2 +0,0 @@
-{incl_app,cosProperty,details}.
-
diff --git a/lib/cosProperty/test/cosProperty.spec b/lib/cosProperty/test/cosProperty.spec
deleted file mode 100644
index d3d44321c8..0000000000
--- a/lib/cosProperty/test/cosProperty.spec
+++ /dev/null
@@ -1 +0,0 @@
-{suites,"../cosProperty_test",all}.
diff --git a/lib/cosProperty/test/generated_SUITE.erl b/lib/cosProperty/test/generated_SUITE.erl
deleted file mode 100644
index 313f5bf8f9..0000000000
--- a/lib/cosProperty/test/generated_SUITE.erl
+++ /dev/null
@@ -1,546 +0,0 @@
-%%-----------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File : generated_SUITE.erl
-%% Purpose :
-%%-----------------------------------------------------------------
-
--module(generated_SUITE).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/include/corba.hrl").
-
--define(default_timeout, test_server:minutes(3)).
-
--define(match(ExpectedRes, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
--define(nomatch(Not, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- Not ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS);
- _ ->
- AcTuAlReS
- end
- end()).
-
-
--define(checktc(_Op),
- fun(TC) ->
- case orber_tc:check_tc(TC) of
- false ->
- io:format("###### ERROR ERROR ######~n~p - ~p~n", [Op, TC]),
- exit(TC);
- true ->
- true
- end
- end).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--compile(export_all).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- ['CosPropertyService_ConflictingProperty',
- 'CosPropertyService_ConstraintNotSupported',
- 'CosPropertyService_FixedProperty',
- 'CosPropertyService_InvalidPropertyName',
- 'CosPropertyService_MultipleExceptions',
- 'CosPropertyService_Properties',
- 'CosPropertyService_Property',
- 'CosPropertyService_PropertyDef',
- 'CosPropertyService_PropertyDefs',
- 'CosPropertyService_PropertyException',
- 'CosPropertyService_PropertyExceptions',
- 'CosPropertyService_PropertyMode',
- 'CosPropertyService_PropertyModes',
- 'CosPropertyService_PropertyNames',
- 'CosPropertyService_PropertyNotFound',
- 'CosPropertyService_PropertyTypes',
- 'CosPropertyService_ReadOnlyProperty',
- 'CosPropertyService_UnsupportedMode',
- 'CosPropertyService_UnsupportedProperty',
- 'CosPropertyService_UnsupportedTypeCode',
- 'CosPropertyService_PropertyNamesIterator',
- 'CosPropertyService_PropertiesIterator',
- 'CosPropertyService_PropertySet',
- 'CosPropertyService_PropertySetDef',
- 'CosPropertyService_PropertySetDefFactory',
- 'CosPropertyService_PropertySetFactory'].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-init_per_testcase(_Case, Config) ->
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-end_per_testcase(_Case, Config) ->
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosPropertyService_ConflictingProperty'
-%% Description:
-%%-----------------------------------------------------------------
-'CosPropertyService_ConflictingProperty'(_) ->
- ?match(true, orber_tc:check_tc('CosPropertyService_ConflictingProperty':tc())),
- ?match("IDL:omg.org/CosPropertyService/ConflictingProperty:1.0",
- 'CosPropertyService_ConflictingProperty':id()),
- ?match("CosPropertyService_ConflictingProperty",
- 'CosPropertyService_ConflictingProperty':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosPropertyService_ConstraintNotSupported'
-%% Description:
-%%-----------------------------------------------------------------
-'CosPropertyService_ConstraintNotSupported'(_) ->
- ?match(true, orber_tc:check_tc('CosPropertyService_ConstraintNotSupported':tc())),
- ?match("IDL:omg.org/CosPropertyService/ConstraintNotSupported:1.0",
- 'CosPropertyService_ConstraintNotSupported':id()),
- ?match("CosPropertyService_ConstraintNotSupported",
- 'CosPropertyService_ConstraintNotSupported':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosPropertyService_FixedProperty'
-%% Description:
-%%-----------------------------------------------------------------
-'CosPropertyService_FixedProperty'(_) ->
- ?match(true, orber_tc:check_tc('CosPropertyService_FixedProperty':tc())),
- ?match("IDL:omg.org/CosPropertyService/FixedProperty:1.0",
- 'CosPropertyService_FixedProperty':id()),
- ?match("CosPropertyService_FixedProperty",
- 'CosPropertyService_FixedProperty':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosPropertyService_InvalidPropertyName'
-%% Description:
-%%-----------------------------------------------------------------
-'CosPropertyService_InvalidPropertyName'(_) ->
- ?match(true, orber_tc:check_tc('CosPropertyService_InvalidPropertyName':tc())),
- ?match("IDL:omg.org/CosPropertyService/InvalidPropertyName:1.0",
- 'CosPropertyService_InvalidPropertyName':id()),
- ?match("CosPropertyService_InvalidPropertyName",
- 'CosPropertyService_InvalidPropertyName':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosPropertyService_MultipleExceptions'
-%% Description:
-%%-----------------------------------------------------------------
-'CosPropertyService_MultipleExceptions'(_) ->
- ?match(true, orber_tc:check_tc('CosPropertyService_MultipleExceptions':tc())),
- ?match("IDL:omg.org/CosPropertyService/MultipleExceptions:1.0",
- 'CosPropertyService_MultipleExceptions':id()),
- ?match("CosPropertyService_MultipleExceptions",
- 'CosPropertyService_MultipleExceptions':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosPropertyService_Properties'
-%% Description:
-%%-----------------------------------------------------------------
-'CosPropertyService_Properties'(_) ->
- ?match(true, orber_tc:check_tc('CosPropertyService_Properties':tc())),
- ?match("IDL:omg.org/CosPropertyService/Properties:1.0",
- 'CosPropertyService_Properties':id()),
- ?match("CosPropertyService_Properties",
- 'CosPropertyService_Properties':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosPropertyService_Property'
-%% Description:
-%%-----------------------------------------------------------------
-'CosPropertyService_Property'(_) ->
- ?match(true, orber_tc:check_tc('CosPropertyService_Property':tc())),
- ?match("IDL:omg.org/CosPropertyService/Property:1.0",
- 'CosPropertyService_Property':id()),
- ?match("CosPropertyService_Property",
- 'CosPropertyService_Property':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosPropertyService_PropertyDef'
-%% Description:
-%%-----------------------------------------------------------------
-'CosPropertyService_PropertyDef'(_) ->
- ?match(true, orber_tc:check_tc('CosPropertyService_PropertyDef':tc())),
- ?match("IDL:omg.org/CosPropertyService/PropertyDef:1.0",
- 'CosPropertyService_PropertyDef':id()),
- ?match("CosPropertyService_PropertyDef",
- 'CosPropertyService_PropertyDef':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosPropertyService_PropertyDefs'
-%% Description:
-%%-----------------------------------------------------------------
-'CosPropertyService_PropertyDefs'(_) ->
- ?match(true, orber_tc:check_tc('CosPropertyService_PropertyDefs':tc())),
- ?match("IDL:omg.org/CosPropertyService/PropertyDefs:1.0",
- 'CosPropertyService_PropertyDefs':id()),
- ?match("CosPropertyService_PropertyDefs",
- 'CosPropertyService_PropertyDefs':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosPropertyService_PropertyException'
-%% Description:
-%%-----------------------------------------------------------------
-'CosPropertyService_PropertyException'(_) ->
- ?match(true, orber_tc:check_tc('CosPropertyService_PropertyException':tc())),
- ?match("IDL:omg.org/CosPropertyService/PropertyException:1.0",
- 'CosPropertyService_PropertyException':id()),
- ?match("CosPropertyService_PropertyException",
- 'CosPropertyService_PropertyException':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosPropertyService_PropertyExceptions'
-%% Description:
-%%-----------------------------------------------------------------
-'CosPropertyService_PropertyExceptions'(_) ->
- ?match(true, orber_tc:check_tc('CosPropertyService_PropertyExceptions':tc())),
- ?match("IDL:omg.org/CosPropertyService/PropertyExceptions:1.0",
- 'CosPropertyService_PropertyExceptions':id()),
- ?match("CosPropertyService_PropertyExceptions",
- 'CosPropertyService_PropertyExceptions':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosPropertyService_PropertyMode'
-%% Description:
-%%-----------------------------------------------------------------
-'CosPropertyService_PropertyMode'(_) ->
- ?match(true, orber_tc:check_tc('CosPropertyService_PropertyMode':tc())),
- ?match("IDL:omg.org/CosPropertyService/PropertyMode:1.0",
- 'CosPropertyService_PropertyMode':id()),
- ?match("CosPropertyService_PropertyMode",
- 'CosPropertyService_PropertyMode':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosPropertyService_PropertyModes'
-%% Description:
-%%-----------------------------------------------------------------
-'CosPropertyService_PropertyModes'(_) ->
- ?match(true, orber_tc:check_tc('CosPropertyService_PropertyModes':tc())),
- ?match("IDL:omg.org/CosPropertyService/PropertyModes:1.0",
- 'CosPropertyService_PropertyModes':id()),
- ?match("CosPropertyService_PropertyModes",
- 'CosPropertyService_PropertyModes':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosPropertyService_PropertyNames'
-%% Description:
-%%-----------------------------------------------------------------
-'CosPropertyService_PropertyNames'(_) ->
- ?match(true, orber_tc:check_tc('CosPropertyService_PropertyNames':tc())),
- ?match("IDL:omg.org/CosPropertyService/PropertyNames:1.0",
- 'CosPropertyService_PropertyNames':id()),
- ?match("CosPropertyService_PropertyNames",
- 'CosPropertyService_PropertyNames':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosPropertyService_PropertyNotFound'
-%% Description:
-%%-----------------------------------------------------------------
-'CosPropertyService_PropertyNotFound'(_) ->
- ?match(true, orber_tc:check_tc('CosPropertyService_PropertyNotFound':tc())),
- ?match("IDL:omg.org/CosPropertyService/PropertyNotFound:1.0",
- 'CosPropertyService_PropertyNotFound':id()),
- ?match("CosPropertyService_PropertyNotFound",
- 'CosPropertyService_PropertyNotFound':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosPropertyService_PropertyTypes'
-%% Description:
-%%-----------------------------------------------------------------
-'CosPropertyService_PropertyTypes'(_) ->
- ?match(true, orber_tc:check_tc('CosPropertyService_PropertyTypes':tc())),
- ?match("IDL:omg.org/CosPropertyService/PropertyTypes:1.0",
- 'CosPropertyService_PropertyTypes':id()),
- ?match("CosPropertyService_PropertyTypes",
- 'CosPropertyService_PropertyTypes':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosPropertyService_ReadOnlyProperty'
-%% Description:
-%%-----------------------------------------------------------------
-'CosPropertyService_ReadOnlyProperty'(_) ->
- ?match(true, orber_tc:check_tc('CosPropertyService_ReadOnlyProperty':tc())),
- ?match("IDL:omg.org/CosPropertyService/ReadOnlyProperty:1.0",
- 'CosPropertyService_ReadOnlyProperty':id()),
- ?match("CosPropertyService_ReadOnlyProperty",
- 'CosPropertyService_ReadOnlyProperty':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosPropertyService_UnsupportedMode'
-%% Description:
-%%-----------------------------------------------------------------
-'CosPropertyService_UnsupportedMode'(_) ->
- ?match(true, orber_tc:check_tc('CosPropertyService_UnsupportedMode':tc())),
- ?match("IDL:omg.org/CosPropertyService/UnsupportedMode:1.0",
- 'CosPropertyService_UnsupportedMode':id()),
- ?match("CosPropertyService_UnsupportedMode",
- 'CosPropertyService_UnsupportedMode':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosPropertyService_UnsupportedProperty'
-%% Description:
-%%-----------------------------------------------------------------
-'CosPropertyService_UnsupportedProperty'(_) ->
- ?match(true, orber_tc:check_tc('CosPropertyService_UnsupportedProperty':tc())),
- ?match("IDL:omg.org/CosPropertyService/UnsupportedProperty:1.0",
- 'CosPropertyService_UnsupportedProperty':id()),
- ?match("CosPropertyService_UnsupportedProperty",
- 'CosPropertyService_UnsupportedProperty':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosPropertyService_UnsupportedTypeCode'
-%% Description:
-%%-----------------------------------------------------------------
-'CosPropertyService_UnsupportedTypeCode'(_) ->
- ?match(true, orber_tc:check_tc('CosPropertyService_UnsupportedTypeCode':tc())),
- ?match("IDL:omg.org/CosPropertyService/UnsupportedTypeCode:1.0",
- 'CosPropertyService_UnsupportedTypeCode':id()),
- ?match("CosPropertyService_UnsupportedTypeCode",
- 'CosPropertyService_UnsupportedTypeCode':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosPropertyService_PropertyNamesIterator'
-%% Description:
-%%-----------------------------------------------------------------
-'CosPropertyService_PropertyNamesIterator'(_) ->
- ?nomatch(undefined, 'CosPropertyService_PropertyNamesIterator':oe_tc(reset)),
- ?nomatch(undefined, 'CosPropertyService_PropertyNamesIterator':oe_tc(next_one)),
- ?nomatch(undefined, 'CosPropertyService_PropertyNamesIterator':oe_tc(next_n)),
- ?nomatch(undefined, 'CosPropertyService_PropertyNamesIterator':oe_tc(destroy)),
- ?match(undefined, 'CosPropertyService_PropertyNamesIterator':oe_tc(undefined)),
- ?match([_|_], 'CosPropertyService_PropertyNamesIterator':oe_get_interface()),
- ?match("IDL:omg.org/CosPropertyService/PropertyNamesIterator:1.0",
- 'CosPropertyService_PropertyNamesIterator':typeID()),
- check_tc('CosPropertyService_PropertyNamesIterator':oe_get_interface()),
- ?match(true, 'CosPropertyService_PropertyNamesIterator':oe_is_a('CosPropertyService_PropertyNamesIterator':typeID())),
- ?match(false, 'CosPropertyService_PropertyNamesIterator':oe_is_a("wrong")),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosPropertyService_PropertiesIterator'
-%% Description:
-%%-----------------------------------------------------------------
-'CosPropertyService_PropertiesIterator'(_) ->
- ?nomatch(undefined, 'CosPropertyService_PropertiesIterator':oe_tc(reset)),
- ?nomatch(undefined, 'CosPropertyService_PropertiesIterator':oe_tc(next_one)),
- ?nomatch(undefined, 'CosPropertyService_PropertiesIterator':oe_tc(next_n)),
- ?nomatch(undefined, 'CosPropertyService_PropertiesIterator':oe_tc(destroy)),
- ?match(undefined, 'CosPropertyService_PropertiesIterator':oe_tc(undefined)),
- ?match([_|_], 'CosPropertyService_PropertiesIterator':oe_get_interface()),
- ?match("IDL:omg.org/CosPropertyService/PropertiesIterator:1.0",
- 'CosPropertyService_PropertiesIterator':typeID()),
- check_tc('CosPropertyService_PropertiesIterator':oe_get_interface()),
- ?match(true, 'CosPropertyService_PropertiesIterator':oe_is_a('CosPropertyService_PropertiesIterator':typeID())),
- ?match(false, 'CosPropertyService_PropertiesIterator':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosPropertyService_PropertySet'
-%% Description:
-%%-----------------------------------------------------------------
-'CosPropertyService_PropertySet'(_) ->
- ?nomatch(undefined, 'CosPropertyService_PropertySet':oe_tc(define_property)),
- ?nomatch(undefined, 'CosPropertyService_PropertySet':oe_tc(define_properties)),
- ?nomatch(undefined, 'CosPropertyService_PropertySet':oe_tc(get_number_of_properties)),
- ?nomatch(undefined, 'CosPropertyService_PropertySet':oe_tc(get_all_property_names)),
- ?nomatch(undefined, 'CosPropertyService_PropertySet':oe_tc(get_property_value)),
- ?nomatch(undefined, 'CosPropertyService_PropertySet':oe_tc(get_properties)),
- ?nomatch(undefined, 'CosPropertyService_PropertySet':oe_tc(get_all_properties)),
- ?nomatch(undefined, 'CosPropertyService_PropertySet':oe_tc(delete_property)),
- ?nomatch(undefined, 'CosPropertyService_PropertySet':oe_tc(delete_properties)),
- ?nomatch(undefined, 'CosPropertyService_PropertySet':oe_tc(delete_all_properties)),
- ?nomatch(undefined, 'CosPropertyService_PropertySet':oe_tc(is_property_defined)),
- ?match(undefined, 'CosPropertyService_PropertySet':oe_tc(undefined)),
- ?match([_|_], 'CosPropertyService_PropertySet':oe_get_interface()),
- ?match("IDL:omg.org/CosPropertyService/PropertySet:1.0",
- 'CosPropertyService_PropertySet':typeID()),
- check_tc('CosPropertyService_PropertySet':oe_get_interface()),
- ?match(true, 'CosPropertyService_PropertySet':oe_is_a('CosPropertyService_PropertySet':typeID())),
- ?match(false, 'CosPropertyService_PropertySet':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosPropertyService_PropertySetDef'
-%% Description:
-%%-----------------------------------------------------------------
-'CosPropertyService_PropertySetDef'(_) ->
- ?nomatch(undefined, 'CosPropertyService_PropertySetDef':oe_tc(get_allowed_property_types)),
- ?nomatch(undefined, 'CosPropertyService_PropertySetDef':oe_tc(get_allowed_properties)),
- ?nomatch(undefined, 'CosPropertyService_PropertySetDef':oe_tc(define_property_with_mode)),
- ?nomatch(undefined, 'CosPropertyService_PropertySetDef':oe_tc(define_properties_with_modes)),
- ?nomatch(undefined, 'CosPropertyService_PropertySetDef':oe_tc(get_property_mode)),
- ?nomatch(undefined, 'CosPropertyService_PropertySetDef':oe_tc(get_property_modes)),
- ?nomatch(undefined, 'CosPropertyService_PropertySetDef':oe_tc(set_property_mode)),
- ?nomatch(undefined, 'CosPropertyService_PropertySetDef':oe_tc(set_property_modes)),
- ?nomatch(undefined, 'CosPropertyService_PropertySetDef':oe_tc(define_property)),
- ?nomatch(undefined, 'CosPropertyService_PropertySetDef':oe_tc(define_properties)),
- ?nomatch(undefined, 'CosPropertyService_PropertySetDef':oe_tc(get_number_of_properties)),
- ?nomatch(undefined, 'CosPropertyService_PropertySetDef':oe_tc(get_all_property_names)),
- ?nomatch(undefined, 'CosPropertyService_PropertySetDef':oe_tc(get_property_value)),
- ?nomatch(undefined, 'CosPropertyService_PropertySetDef':oe_tc(get_properties)),
- ?nomatch(undefined, 'CosPropertyService_PropertySetDef':oe_tc(get_all_properties)),
- ?nomatch(undefined, 'CosPropertyService_PropertySetDef':oe_tc(delete_property)),
- ?nomatch(undefined, 'CosPropertyService_PropertySetDef':oe_tc(delete_properties)),
- ?nomatch(undefined, 'CosPropertyService_PropertySetDef':oe_tc(delete_all_properties)),
- ?nomatch(undefined, 'CosPropertyService_PropertySetDef':oe_tc(is_property_defined)),
- ?match(undefined, 'CosPropertyService_PropertySetDef':oe_tc(undefined)),
- ?match([_|_], 'CosPropertyService_PropertySetDef':oe_get_interface()),
- ?match("IDL:omg.org/CosPropertyService/PropertySetDef:1.0",
- 'CosPropertyService_PropertySetDef':typeID()),
- check_tc('CosPropertyService_PropertySetDef':oe_get_interface()),
- ?match(true, 'CosPropertyService_PropertySetDef':oe_is_a('CosPropertyService_PropertySetDef':typeID())),
- ?match(true, 'CosPropertyService_PropertySetDef':oe_is_a('CosPropertyService_PropertySet':typeID())),
- ?match(false, 'CosPropertyService_PropertySetDef':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosPropertyService_PropertySetDefFactory'
-%% Description:
-%%-----------------------------------------------------------------
-'CosPropertyService_PropertySetDefFactory'(_) ->
- ?nomatch(undefined, 'CosPropertyService_PropertySetDefFactory':oe_tc(create_propertysetdef)),
- ?nomatch(undefined, 'CosPropertyService_PropertySetDefFactory':oe_tc(create_constrained_propertysetdef)),
- ?nomatch(undefined, 'CosPropertyService_PropertySetDefFactory':oe_tc(create_initial_propertysetdef)),
- ?match(undefined, 'CosPropertyService_PropertySetDefFactory':oe_tc(undefined)),
- ?match([_|_], 'CosPropertyService_PropertySetDefFactory':oe_get_interface()),
- ?match("IDL:omg.org/CosPropertyService/PropertySetDefFactory:1.0",
- 'CosPropertyService_PropertySetDefFactory':typeID()),
- check_tc('CosPropertyService_PropertySetDefFactory':oe_get_interface()),
- ?match(true, 'CosPropertyService_PropertySetDefFactory':oe_is_a('CosPropertyService_PropertySetDefFactory':typeID())),
- ?match(false, 'CosPropertyService_PropertySetDefFactory':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosPropertyService_PropertySetFactory'
-%% Description:
-%%-----------------------------------------------------------------
-'CosPropertyService_PropertySetFactory'(_) ->
- ?nomatch(undefined, 'CosPropertyService_PropertySetFactory':oe_tc(create_propertyset)),
- ?nomatch(undefined, 'CosPropertyService_PropertySetFactory':oe_tc(create_constrained_propertyset)),
- ?nomatch(undefined, 'CosPropertyService_PropertySetFactory':oe_tc(create_initial_propertyset)),
- ?match(undefined, 'CosPropertyService_PropertySetFactory':oe_tc(undefined)),
- ?match([_|_], 'CosPropertyService_PropertySetFactory':oe_get_interface()),
- ?match("IDL:omg.org/CosPropertyService/PropertySetFactory:1.0",
- 'CosPropertyService_PropertySetFactory':typeID()),
- check_tc('CosPropertyService_PropertySetFactory':oe_get_interface()),
- ?match(true, 'CosPropertyService_PropertySetFactory':oe_is_a('CosPropertyService_PropertySetFactory':typeID())),
- ?match(false, 'CosPropertyService_PropertySetFactory':oe_is_a("wrong")),
- ok.
-
-
-
-%%-----------------------------------------------------------------
-%% MISC functions
-%%-----------------------------------------------------------------
-check_tc([]) ->
- ok;
-check_tc([{Op, {RetType, InParameters, OutParameters}}|T]) ->
- io:format("checked - ~s~n", [Op]),
- lists:all(?checktc(Op), [RetType|InParameters]),
- lists:all(?checktc(Op), OutParameters),
- check_tc(T).
-
-
diff --git a/lib/cosProperty/test/property_SUITE.erl b/lib/cosProperty/test/property_SUITE.erl
deleted file mode 100644
index 77f35c319a..0000000000
--- a/lib/cosProperty/test/property_SUITE.erl
+++ /dev/null
@@ -1,736 +0,0 @@
-%%----------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : property_SUITE.erl
-%% Description :
-%%
-%%----------------------------------------------------------------------
--module(property_SUITE).
-
-
-%%--------------- INCLUDES -----------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
--include_lib("cosProperty/src/cosProperty.hrl").
--include_lib("cosProperty/include/CosPropertyService.hrl").
-
--include_lib("common_test/include/ct.hrl").
-
-%%--------------- DEFINES ------------------------------------
--define(default_timeout, test_server:minutes(20)).
--define(match(ExpectedRes, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- io:format("------ CORRECT RESULT ------~n~p~n",
- [AcTuAlReS]),
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
--define(match_inverse(NotExpectedRes, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- NotExpectedRes ->
- io:format("###### ERROR ERROR ######~n ~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS);
- _ ->
- io:format("------ CORRECT RESULT ------~n~p~n",
- [AcTuAlReS]),
- AcTuAlReS
- end
- end()).
-
-
--define(val1, #any{typecode=tk_short, value=1}).
--define(val2, #any{typecode=tk_short, value=2}).
--define(val3, #any{typecode=tk_short, value=3}).
--define(val4, #any{typecode=tk_short, value=4}).
--define(val5, #any{typecode=tk_long, value=5}).
--define(badval, #any{typecode=tk_shirt, value=5}).
-
--define(id1, "id1").
--define(id2, "id2").
--define(id3, "id3").
--define(id4, "id4").
--define(id5, "id5").
--define(badid, "").
-
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
-%% Fixed exports
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2, cases/0,
- init_per_suite/1, end_per_suite/1,
- init_per_testcase/2, end_per_testcase/2]).
-%% Test cases
--export([create_setdef_api/1, create_set_api/1, define_with_mode_api/1,
- define_api/1, names_iterator_api/1, properties_iterator_api/1,
- app_test/1]).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- cases().
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-cases() ->
- [create_setdef_api, create_set_api,
- define_with_mode_api, define_api, names_iterator_api,
- properties_iterator_api, app_test].
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-init_per_testcase(_Case, Config) ->
- Path = code:which(?MODULE),
- code:add_pathz(filename:join(filename:dirname(Path), "idl_output")),
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- Path = code:which(?MODULE),
- code:del_path(filename:join(filename:dirname(Path), "idl_output")),
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-init_per_suite(Config) ->
- Path = code:which(?MODULE),
- code:add_pathz(filename:join(filename:dirname(Path), "idl_output")),
- orber:jump_start(),
- cosProperty:install(),
- cosProperty:install_db(),
- ?match(ok, application:start(cosProperty)),
- if
- is_list(Config) ->
- Config;
- true ->
- exit("Config not a list")
- end.
-
-end_per_suite(Config) ->
- Path = code:which(?MODULE),
- code:del_path(filename:join(filename:dirname(Path), "idl_output")),
- application:stop(cosProperty),
- cosProperty:uninstall_db(),
- cosProperty:uninstall(),
- orber:jump_stop(),
- Config.
-
-%%-----------------------------------------------------------------
-%% Tests app file
-%%-----------------------------------------------------------------
-app_test(_Config) ->
- ok=test_server:app_test(cosProperty),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% CosPropertyService_PropertySetDefFactory API tests
-%%-----------------------------------------------------------------
-create_setdef_api(_Config) ->
-
- ValidDefs = [#'CosPropertyService_PropertyDef'
- {property_name = ?id1,
- property_value = ?val1,
- property_mode = normal},
- #'CosPropertyService_PropertyDef'
- {property_name = ?id2,
- property_value = ?val2,
- property_mode = normal}],
- InvalidDefs = [#'CosPropertyService_PropertyDef'
- {property_name = ?id1,
- property_value = ?val1,
- property_mode = normal},
- #'CosPropertyService_PropertyDef'
- {property_name = ?badid,
- property_value = ?badval,
- property_mode = normal}],
-
- Fac = ?match({_,pseudo,_,_,_,_}, cosProperty:start_SetDefFactory()),
-
- Obj1 = ?match({_,pseudo,_,_,_,_}, 'CosPropertyService_PropertySetDefFactory':
- create_propertysetdef(Fac)),
- 'CosPropertyService_PropertySetDef_impl':dump(),
- corba:dispose(Obj1),
-
-
- Obj2 = ?match({_,pseudo,_,_,_,_}, 'CosPropertyService_PropertySetDefFactory':
- create_constrained_propertysetdef(Fac, [tk_short], ValidDefs)),
- 'CosPropertyService_PropertySetDef_impl':dump(),
- corba:dispose(Obj2),
-
- %% Both arguments correct but 'ValidDefs' contain other TC:s than
- %% tk_null.
- ?match({'EXCEPTION', _}, 'CosPropertyService_PropertySetDefFactory':
- create_constrained_propertysetdef(Fac, [tk_null], ValidDefs)),
- 'CosPropertyService_PropertySetDef_impl':dump(),
-
- ?match({'EXCEPTION', _}, 'CosPropertyService_PropertySetDefFactory':
- create_constrained_propertysetdef(Fac, [tk_null], InvalidDefs)),
- 'CosPropertyService_PropertySetDef_impl':dump(),
-
- %% The allowed TC not supported.
- ?match({'EXCEPTION', _}, 'CosPropertyService_PropertySetDefFactory':
- create_constrained_propertysetdef(Fac, [tk_noll], ValidDefs)),
- 'CosPropertyService_PropertySetDef_impl':dump(),
-
- Obj4 = ?match({_,pseudo,_,_,_,_}, 'CosPropertyService_PropertySetDefFactory':
- create_initial_propertysetdef(Fac, ValidDefs)),
- 'CosPropertyService_PropertySetDef_impl':dump(),
- corba:dispose(Obj4),
-
- ?match({'EXCEPTION', _}, 'CosPropertyService_PropertySetDefFactory':
- create_initial_propertysetdef(Fac, InvalidDefs)),
-
- ?match(ok, cosProperty:stop_SetDefFactory(Fac)),
-
- ok.
-
-
-%%-----------------------------------------------------------------
-%% CosPropertyService_PropertySetFactory API tests
-%%-----------------------------------------------------------------
-create_set_api(_Config) ->
- Valid = [#'CosPropertyService_Property'
- {property_name = ?id1,
- property_value = ?val1},
- #'CosPropertyService_Property'
- {property_name = ?id2,
- property_value = ?val2}],
- Invalid = [#'CosPropertyService_Property'
- {property_name = ?id1,
- property_value = ?val1},
- #'CosPropertyService_Property'
- {property_name = ?badid,
- property_value = ?badval}],
-
- Fac = ?match({_,pseudo,_,_,_,_}, cosProperty:start_SetFactory()),
- Obj1 = ?match({_,pseudo,_,_,_,_}, 'CosPropertyService_PropertySetFactory':
- create_propertyset(Fac)),
- 'CosPropertyService_PropertySetDef_impl':dump(),
- corba:dispose(Obj1),
-
-
- Obj2 = ?match({_,pseudo,_,_,_,_}, 'CosPropertyService_PropertySetFactory':
- create_constrained_propertyset(Fac, [tk_short], Valid)),
- 'CosPropertyService_PropertySetDef_impl':dump(),
- corba:dispose(Obj2),
-
- %% Both arguments correct but 'Valid' contain other TC:s than
- %% tk_null.
- ?match({'EXCEPTION', _}, 'CosPropertyService_PropertySetFactory':
- create_constrained_propertyset(Fac, [tk_null], Valid)),
- 'CosPropertyService_PropertySetDef_impl':dump(),
-
- ?match({'EXCEPTION', _}, 'CosPropertyService_PropertySetFactory':
- create_constrained_propertyset(Fac, [tk_null], Invalid)),
- 'CosPropertyService_PropertySetDef_impl':dump(),
-
- %% The allowed TC not supported.
- ?match({'EXCEPTION', _}, 'CosPropertyService_PropertySetFactory':
- create_constrained_propertyset(Fac, [tk_noll], Valid)),
- 'CosPropertyService_PropertySetDef_impl':dump(),
-
- Obj4 = ?match({_,pseudo,_,_,_,_}, 'CosPropertyService_PropertySetFactory':
- create_initial_propertyset(Fac, Valid)),
- 'CosPropertyService_PropertySetDef_impl':dump(),
- corba:dispose(Obj4),
-
- ?match({'EXCEPTION', _}, 'CosPropertyService_PropertySetFactory':
- create_initial_propertyset(Fac, Invalid)),
- ?match(ok, cosProperty:stop_SetFactory(Fac)),
- ok.
-
-%%-----------------------------------------------------------------
-%% CosPropertyService_PropertySetDef API tests
-%%-----------------------------------------------------------------
-define_api(_Config) ->
- ValidDefs = [#'CosPropertyService_Property'
- {property_name = ?id1,
- property_value = ?val1},
- #'CosPropertyService_Property'
- {property_name = ?id2,
- property_value = ?val2},
- #'CosPropertyService_Property'
- {property_name = ?id3,
- property_value = ?val3}],
-
- Fac = ?match({_,pseudo,_,_,_,_}, cosProperty:start_SetFactory()),
-
- io:format("@@@@ Testing PropertySet returned by the factory operation create_propertyset/1 @@@@", []),
- Obj = ?match({_,pseudo,_,_,_,_}, 'CosPropertyService_PropertySetFactory':
- create_propertyset(Fac)),
- ?match(ok, 'CosPropertyService_PropertySet':define_property(Obj, ?id1, ?val1)),
- ?match(ok, 'CosPropertyService_PropertySet':define_property(Obj, ?id1, ?val1)),
-
- ?match(1, 'CosPropertyService_PropertySet':get_number_of_properties(Obj)),
- ?match(ok, 'CosPropertyService_PropertySet':
- define_properties(Obj, [#'CosPropertyService_Property'{property_name = ?id2,
- property_value = ?val2},
- #'CosPropertyService_Property'{property_name = ?id3,
- property_value = ?val3}])),
-
- ?match(3, 'CosPropertyService_PropertySet':get_number_of_properties(Obj)),
-
- ?match({true, [_]}, 'CosPropertyService_PropertySet':get_properties(Obj, [?id1])),
- ?match({true, [_, _, _]}, 'CosPropertyService_PropertySet':get_properties(Obj, [?id1, ?id2, ?id3])),
- ?match({false,[_, _, _]}, 'CosPropertyService_PropertySet':get_properties(Obj, [?id1, "wrong", ?id3])),
-
- ?match(?val2, 'CosPropertyService_PropertySet':get_property_value(Obj, ?id2)),
- ?match(ok, 'CosPropertyService_PropertySet':delete_property(Obj, ?id1)),
-
- ?match(2, 'CosPropertyService_PropertySet':get_number_of_properties(Obj)),
-
- ?match(ok, 'CosPropertyService_PropertySet':define_property(Obj, ?id1, ?val1)),
- ?match(ok, 'CosPropertyService_PropertySet':define_property(Obj, ?id2, ?val2)),
- ?match(ok, 'CosPropertyService_PropertySet':define_property(Obj, ?id3, ?val3)),
-
- ?match(true, 'CosPropertyService_PropertySet':delete_all_properties(Obj)),
- ?match(0, 'CosPropertyService_PropertySet':get_number_of_properties(Obj)),
-
- ?match(ok, 'CosPropertyService_PropertySet':
- define_properties(Obj, [#'CosPropertyService_Property'{property_name = ?id1,
- property_value = ?val1},
- #'CosPropertyService_Property'{property_name = ?id2,
- property_value = ?val2},
- #'CosPropertyService_Property'{property_name = ?id3,
- property_value = ?val3}])),
-
- ?match(3, 'CosPropertyService_PropertySet':get_number_of_properties(Obj)),
- ?match(?val2, 'CosPropertyService_PropertySet':get_property_value(Obj, ?id2)),
-
- ?match({'EXCEPTION',{'CosPropertyService_PropertyNotFound',_}},
- 'CosPropertyService_PropertySet':get_property_value(Obj, "wrongID")),
- ?match({'EXCEPTION',{'CosPropertyService_InvalidPropertyName',_}},
- 'CosPropertyService_PropertySet':get_property_value(Obj, "")),
- ?match({'EXCEPTION',{'CosPropertyService_InvalidPropertyName',_}},
- 'CosPropertyService_PropertySet':is_property_defined(Obj, "")),
- ?match(false, 'CosPropertyService_PropertySet':is_property_defined(Obj, "wrongID")),
- ?match(true, 'CosPropertyService_PropertySet':is_property_defined(Obj, ?id1)),
-
- %% This function is not supported by PropertySet.
- ?match({'EXCEPTION',{'NO_IMPLEMENT',_,_,_}},
- 'CosPropertyService_PropertySetDef':get_property_modes(Obj, [?id1, ?id2, ?id3])),
-
- ?match({'EXCEPTION',{'CosPropertyService_MultipleExceptions',_,_}},
- 'CosPropertyService_PropertySet':delete_properties(Obj, [?id1, ?id2, ?id3, "wrongID"])),
- ?match(0, 'CosPropertyService_PropertySet':get_number_of_properties(Obj)),
- corba:dispose(Obj),
-
- io:format("@@@@ Testing PropertySet returned by the factory operation create_constrained_propertyset/3 @@@@", []),
- Obj2 = ?match({_,pseudo,_,_,_,_}, 'CosPropertyService_PropertySetFactory':
- create_constrained_propertyset(Fac, [tk_short], ValidDefs)),
-
- ?match(0, 'CosPropertyService_PropertySet':get_number_of_properties(Obj2)),
- ?match({'EXCEPTION', {'CosPropertyService_UnsupportedProperty',_}},
- 'CosPropertyService_PropertySet':define_property(Obj2, ?id4, ?val4)),
- ?match({'EXCEPTION', {'CosPropertyService_UnsupportedTypeCode',_}},
- 'CosPropertyService_PropertySet':define_property(Obj2, ?id1, ?val5)),
- ?match(ok, 'CosPropertyService_PropertySet':define_property(Obj2, ?id1, ?val1)),
- ?match(1, 'CosPropertyService_PropertySet':get_number_of_properties(Obj2)),
- ?match({'EXCEPTION',{'CosPropertyService_MultipleExceptions',_,_}},
- 'CosPropertyService_PropertySet':
- define_properties(Obj2, [#'CosPropertyService_Property'{property_name = ?id2,
- property_value = ?val2},
- #'CosPropertyService_Property'{property_name = ?id3,
- property_value = ?val3},
- #'CosPropertyService_Property'{property_name = "wrongId",
- property_value = ?val2}])),
- ?match(ok,'CosPropertyService_PropertySet':
- define_properties(Obj2, [#'CosPropertyService_Property'{property_name = ?id2,
- property_value = ?val2},
- #'CosPropertyService_Property'{property_name = ?id3,
- property_value = ?val3}])),
- ?match(3, 'CosPropertyService_PropertySet':get_number_of_properties(Obj2)),
- ?match({'EXCEPTION',{'CosPropertyService_PropertyNotFound',_}},
- 'CosPropertyService_PropertySet':get_property_value(Obj2, "wrongID")),
- ?match(?val2, 'CosPropertyService_PropertySet':get_property_value(Obj2, ?id2)),
- ?match({'EXCEPTION',{'CosPropertyService_InvalidPropertyName',_}},
- 'CosPropertyService_PropertySet':get_property_value(Obj2, "")),
- ?match({'EXCEPTION',{'CosPropertyService_InvalidPropertyName',_}},
- 'CosPropertyService_PropertySet':is_property_defined(Obj2, "")),
- ?match(false, 'CosPropertyService_PropertySet':is_property_defined(Obj2, "wrongID")),
- ?match(true, 'CosPropertyService_PropertySet':is_property_defined(Obj2, ?id1)),
-
-
- ?match({'EXCEPTION',{'CosPropertyService_PropertyNotFound',_}},
- 'CosPropertyService_PropertySet':delete_property(Obj2, "wrongID")),
- ?match(3, 'CosPropertyService_PropertySet':get_number_of_properties(Obj2)),
- ?match(ok, 'CosPropertyService_PropertySet':delete_property(Obj2, ?id1)),
- ?match(2, 'CosPropertyService_PropertySet':get_number_of_properties(Obj2)),
-
- ?match(ok, 'CosPropertyService_PropertySet':delete_properties(Obj2, [?id2])),
- ?match(1, 'CosPropertyService_PropertySet':get_number_of_properties(Obj2)),
-
- ?match({'EXCEPTION',{'CosPropertyService_MultipleExceptions',_,_}},
- 'CosPropertyService_PropertySet':delete_properties(Obj2, [?id3, "wrongID"])),
- ?match(0, 'CosPropertyService_PropertySet':get_number_of_properties(Obj2)),
- corba:dispose(Obj2),
-
- io:format("@@@@ Testing PropertySet returned by the factory operation create_initial_propertyset/2 @@@@", []),
- Obj3 = ?match({_,pseudo,_,_,_,_}, 'CosPropertyService_PropertySetFactory':
- create_initial_propertyset(Fac, ValidDefs)),
- ?match(3, 'CosPropertyService_PropertySet':get_number_of_properties(Obj3)),
-
- ?match(ok, 'CosPropertyService_PropertySet':define_property(Obj3, ?id4, ?val4)),
- ?match(4, 'CosPropertyService_PropertySet':get_number_of_properties(Obj3)),
-
- ?match(ok,'CosPropertyService_PropertySet':
- define_properties(Obj3, [#'CosPropertyService_Property'{property_name = ?id5,
- property_value = ?val5}])),
-
- ?match(5, 'CosPropertyService_PropertySet':get_number_of_properties(Obj3)),
-
- ?match({'EXCEPTION',{'CosPropertyService_PropertyNotFound',_}},
- 'CosPropertyService_PropertySet':get_property_value(Obj3, "wrongID")),
- ?match(?val2, 'CosPropertyService_PropertySet':get_property_value(Obj3, ?id2)),
- ?match({'EXCEPTION',{'CosPropertyService_InvalidPropertyName',_}},
- 'CosPropertyService_PropertySet':get_property_value(Obj3, "")),
- ?match({'EXCEPTION',{'CosPropertyService_InvalidPropertyName',_}},
- 'CosPropertyService_PropertySet':is_property_defined(Obj3, "")),
- ?match(false, 'CosPropertyService_PropertySet':is_property_defined(Obj3, "wrongID")),
- ?match(true, 'CosPropertyService_PropertySet':is_property_defined(Obj3, ?id1)),
-
- ?match({'EXCEPTION',{'CosPropertyService_PropertyNotFound',_}},
- 'CosPropertyService_PropertySet':delete_property(Obj3, "wrongId")),
- ?match(ok, 'CosPropertyService_PropertySet':delete_property(Obj3, ?id5)),
- ?match(4, 'CosPropertyService_PropertySet':get_number_of_properties(Obj3)),
-
- ?match({'EXCEPTION',{'CosPropertyService_MultipleExceptions',_,_}},
- 'CosPropertyService_PropertySet':delete_properties(Obj3, [?id1, ?id2, ?id3, "wrongID"])),
- ?match(1, 'CosPropertyService_PropertySet':get_number_of_properties(Obj3)),
-
- ?match(true, 'CosPropertyService_PropertySet':delete_all_properties(Obj3)),
- ?match(0, 'CosPropertyService_PropertySet':get_number_of_properties(Obj3)),
-
- corba:dispose(Obj3),
- ?match(ok, cosProperty:stop_SetFactory(Fac)),
-
- ok.
-
-%%-----------------------------------------------------------------
-%% CosPropertyService_PropertySetDef API tests
-%%-----------------------------------------------------------------
-define_with_mode_api(_Config) ->
- ValidDefs = [#'CosPropertyService_PropertyDef'
- {property_name = ?id1,
- property_value = ?val1,
- property_mode = normal},
- #'CosPropertyService_PropertyDef'
- {property_name = ?id2,
- property_value = ?val2,
- property_mode = normal},
- #'CosPropertyService_PropertyDef'
- {property_name = ?id3,
- property_value = ?val3,
- property_mode = normal}],
-
- Fac = ?match({_,pseudo,_,_,_,_}, cosProperty:start_SetDefFactory()),
-
- io:format("@@@@ Testing PropertySetDef returned by the factory operation create_propertysetdef/1 @@@@", []),
- Obj = ?match({_,pseudo,_,_,_,_}, 'CosPropertyService_PropertySetDefFactory':
- create_propertysetdef(Fac)),
-
- %% Initally no prop's created and no restrictions at all
- ?match(0, 'CosPropertyService_PropertySetDef':get_number_of_properties(Obj)),
- ?match({ok, []}, 'CosPropertyService_PropertySetDef':get_allowed_property_types(Obj)),
- ?match({ok, []}, 'CosPropertyService_PropertySetDef':get_allowed_properties(Obj)),
-
- %% Add two properties.
- ?match(ok, 'CosPropertyService_PropertySetDef':define_property_with_mode(Obj, ?id4, ?val4, read_only)),
- ?match(ok, 'CosPropertyService_PropertySetDef':define_property_with_mode(Obj, ?id5, ?val5, normal)),
- %% Try to add the same property again (shouldn't add another since using the sam Id).
- ?match(ok, 'CosPropertyService_PropertySetDef':define_property_with_mode(Obj, ?id5, ?val5, normal)),
-
- %% Try to add another identical proprty with wrong TC.
- ?match({'EXCEPTION',{'CosPropertyService_ConflictingProperty',_}},
- 'CosPropertyService_PropertySetDef':define_property_with_mode(Obj, ?id5, ?val4, normal)),
-
-
- %% Should be two now.
- ?match(2, 'CosPropertyService_PropertySetDef':get_number_of_properties(Obj)),
-
- ?match(read_only, 'CosPropertyService_PropertySetDef':get_property_mode(Obj, ?id4)),
- ?match(normal, 'CosPropertyService_PropertySetDef':get_property_mode(Obj, ?id5)),
- ?match(ok, 'CosPropertyService_PropertySetDef':
- define_properties_with_modes(Obj,
- [#'CosPropertyService_PropertyDef'{property_name = ?id1,
- property_value = ?val1,
- property_mode = normal},
- #'CosPropertyService_PropertyDef'{property_name = ?id2,
- property_value = ?val2,
- property_mode = normal},
- #'CosPropertyService_PropertyDef'{property_name = ?id3,
- property_value = ?val3,
- property_mode = normal}])),
- %% Should be five now.
- ?match(5, 'CosPropertyService_PropertySetDef':get_number_of_properties(Obj)),
- ?match({true, [_,_]}, 'CosPropertyService_PropertySetDef':get_property_modes(Obj, [?id1, ?id3])),
- ?match({false, [_,_,_]}, 'CosPropertyService_PropertySetDef':get_property_modes(Obj, [?id1, ?id3, "wrongID"])),
-
- ?match(ok, 'CosPropertyService_PropertySetDef':set_property_mode(Obj, ?id1, read_only)),
- ?match(read_only, 'CosPropertyService_PropertySetDef':get_property_mode(Obj, ?id1)),
-
- ?match({'EXCEPTION',{'CosPropertyService_PropertyNotFound',_}},
- 'CosPropertyService_PropertySetDef':set_property_mode(Obj, "wrongID", read_only)),
-
- ?match({'EXCEPTION',{'CosPropertyService_MultipleExceptions',_,_}},
- 'CosPropertyService_PropertySetDef':
- set_property_modes(Obj,
- [#'CosPropertyService_PropertyMode'{property_name = ?id2,
- property_mode = read_only},
- #'CosPropertyService_PropertyMode'{property_name = ?id3,
- property_mode = read_only},
- #'CosPropertyService_PropertyMode'{property_name = "wrongID",
- property_mode = read_only}])),
- ?match(normal, 'CosPropertyService_PropertySetDef':get_property_mode(Obj, ?id2)),
- ?match(ok,
- 'CosPropertyService_PropertySetDef':
- set_property_modes(Obj,
- [#'CosPropertyService_PropertyMode'{property_name = ?id2,
- property_mode = read_only},
- #'CosPropertyService_PropertyMode'{property_name = ?id3,
- property_mode = read_only}])),
- ?match(read_only, 'CosPropertyService_PropertySetDef':get_property_mode(Obj, ?id2)),
-
- corba:dispose(Obj),
-
-
- io:format("@@@@ Testing PropertySetDef returned by the factory operation create_constrained_propertysetdef/3 @@@@", []),
- Obj2 = ?match({_,pseudo,_,_,_,_}, 'CosPropertyService_PropertySetDefFactory':
- create_constrained_propertysetdef(Fac, [tk_short], ValidDefs)),
-
- %% Initally no prop's created and the restrictions that only Properties eq. to ValidDefs
- %% may be handled.
- ?match(0, 'CosPropertyService_PropertySetDef':get_number_of_properties(Obj2)),
- ?match({ok, [tk_short]}, 'CosPropertyService_PropertySetDef':get_allowed_property_types(Obj2)),
- %% We cannot be sure in which order it's returned. Hmm, that's not really true but it
- %% may change in the future.
- ?match({ok, [_,_,_]}, 'CosPropertyService_PropertySetDef':get_allowed_properties(Obj2)),
- %% Try to add a Property with and Id not eq. to ?id1, ?id2 or ?id3; must fail.
- ?match({'EXCEPTION', {'CosPropertyService_UnsupportedProperty',_}},
- 'CosPropertyService_PropertySetDef':define_property_with_mode(Obj2, ?id4, ?val4, read_only)),
- %% To be sure that nothing was updated.
- ?match(0, 'CosPropertyService_PropertySetDef':get_number_of_properties(Obj2)),
- %% Add a valid Property.
- ?match(ok, 'CosPropertyService_PropertySetDef':define_property_with_mode(Obj2, ?id1, ?val1, normal)),
- ?match(1, 'CosPropertyService_PropertySetDef':get_number_of_properties(Obj2)),
- %% Add a sequence of 1 valid and one invalid Prop's
- ?match({'EXCEPTION', {'CosPropertyService_MultipleExceptions',_,_}},
- 'CosPropertyService_PropertySetDef':
- define_properties_with_modes(Obj2,
- [#'CosPropertyService_PropertyDef'{property_name = ?id2,
- property_value = ?val2,
- property_mode = normal},
- #'CosPropertyService_PropertyDef'{property_name = "wrongID",
- property_value = ?val2,
- property_mode = normal}])),
- %% One should be added.
- ?match(1, 'CosPropertyService_PropertySetDef':get_number_of_properties(Obj2)),
- ?match(ok, 'CosPropertyService_PropertySetDef':
- define_properties_with_modes(Obj2,
- [#'CosPropertyService_PropertyDef'{property_name = ?id3,
- property_value = ?val3,
- property_mode = normal}])),
- %% Add a sequence of 1 valid Prop.
- ?match(2, 'CosPropertyService_PropertySetDef':get_number_of_properties(Obj2)),
- ?match(normal, 'CosPropertyService_PropertySetDef':get_property_mode(Obj2, ?id1)),
- ?match(normal, 'CosPropertyService_PropertySetDef':get_property_mode(Obj2, ?id3)),
-
-
- ?match({true, [_,_]}, 'CosPropertyService_PropertySetDef':get_property_modes(Obj2, [?id1, ?id3])),
- ?match({false, [_,_,_]}, 'CosPropertyService_PropertySetDef':get_property_modes(Obj2, [?id1, ?id3, "wrongID"])),
-
- ?match(ok, 'CosPropertyService_PropertySetDef':set_property_mode(Obj2, ?id1, read_only)),
- ?match(read_only, 'CosPropertyService_PropertySetDef':get_property_mode(Obj2, ?id1)),
- ?match(ok, 'CosPropertyService_PropertySetDef':
- set_property_modes(Obj2,
- [#'CosPropertyService_PropertyMode'{property_name = ?id1,
- property_mode = read_only},
- #'CosPropertyService_PropertyMode'{property_name = ?id3,
- property_mode = read_only}])),
- ?match(read_only, 'CosPropertyService_PropertySetDef':get_property_mode(Obj2, ?id1)),
- ?match(read_only, 'CosPropertyService_PropertySetDef':get_property_mode(Obj2, ?id3)),
- ?match({'EXCEPTION',{'CosPropertyService_MultipleExceptions',_,_}},
- 'CosPropertyService_PropertySetDef':
- set_property_modes(Obj2,
- [#'CosPropertyService_PropertyMode'{property_name = ?id1,
- property_mode = normal},
- #'CosPropertyService_PropertyMode'{property_name = ?id3,
- property_mode = normal},
- #'CosPropertyService_PropertyMode'{property_name = "wrongID",
- property_mode = normal}])),
-
- ?match(read_only, 'CosPropertyService_PropertySetDef':get_property_mode(Obj2, ?id1)),
- ?match(read_only, 'CosPropertyService_PropertySetDef':get_property_mode(Obj2, ?id3)),
- corba:dispose(Obj2),
-
- io:format("@@@@ Testing PropertySetDef returned by the factory operation create_initial_propertysetdef/2 @@@@", []),
- Obj3 = ?match({_,pseudo,_,_,_,_}, 'CosPropertyService_PropertySetDefFactory':
- create_initial_propertysetdef(Fac, ValidDefs)),
-
- %% Initally the supplied prop's are created and no restrictions.
- ?match(3, 'CosPropertyService_PropertySetDef':get_number_of_properties(Obj3)),
- ?match({ok, []}, 'CosPropertyService_PropertySetDef':get_allowed_property_types(Obj3)),
- ?match({ok, []}, 'CosPropertyService_PropertySetDef':get_allowed_properties(Obj3)),
-
- %% Add a new properties an test if they have been inserted.
- ?match(ok, 'CosPropertyService_PropertySetDef':define_property_with_mode(Obj3, ?id4, ?val4, read_only)),
- ?match(4, 'CosPropertyService_PropertySetDef':get_number_of_properties(Obj3)),
- ?match(ok, 'CosPropertyService_PropertySetDef':define_property_with_mode(Obj3, ?id5, ?val5, read_only)),
- ?match(5, 'CosPropertyService_PropertySetDef':get_number_of_properties(Obj3)),
-
- %% Lookup each Property's mode.
- ?match(normal, 'CosPropertyService_PropertySetDef':get_property_mode(Obj3, ?id1)),
- ?match(normal, 'CosPropertyService_PropertySetDef':get_property_mode(Obj3, ?id2)),
- ?match(normal, 'CosPropertyService_PropertySetDef':get_property_mode(Obj3, ?id3)),
- ?match(read_only, 'CosPropertyService_PropertySetDef':get_property_mode(Obj3, ?id4)),
- ?match(read_only, 'CosPropertyService_PropertySetDef':get_property_mode(Obj3, ?id5)),
-
- ?match({true, [_,_,_,_,_]},
- 'CosPropertyService_PropertySetDef':get_property_modes(Obj3, [?id1, ?id2, ?id3, ?id4, ?id5])),
- ?match({false, [_,_]},
- 'CosPropertyService_PropertySetDef':get_property_modes(Obj3, [?id1, "wrongID"])),
- ?match(ok, 'CosPropertyService_PropertySetDef':set_property_mode(Obj3, ?id4, normal)),
- ?match(normal, 'CosPropertyService_PropertySetDef':get_property_mode(Obj3, ?id4)),
-
- ?match(ok, 'CosPropertyService_PropertySetDef':
- set_property_modes(Obj3,
- [#'CosPropertyService_PropertyMode'{property_name = ?id1,
- property_mode = read_only},
- #'CosPropertyService_PropertyMode'{property_name = ?id2,
- property_mode = read_only}])),
- ?match(read_only, 'CosPropertyService_PropertySetDef':get_property_mode(Obj3, ?id1)),
- ?match(read_only, 'CosPropertyService_PropertySetDef':get_property_mode(Obj3, ?id2)),
- ?match({'EXCEPTION',{'CosPropertyService_MultipleExceptions',_,_}},
- 'CosPropertyService_PropertySetDef':
- set_property_modes(Obj3,
- [#'CosPropertyService_PropertyMode'{property_name = ?id3,
- property_mode = read_only},
- #'CosPropertyService_PropertyMode'{property_name = ?id4,
- property_mode = read_only},
- #'CosPropertyService_PropertyMode'{property_name = "wrongID",
- property_mode = read_only}])),
-
- ?match(normal, 'CosPropertyService_PropertySetDef':get_property_mode(Obj3, ?id3)),
- ?match(normal, 'CosPropertyService_PropertySetDef':get_property_mode(Obj3, ?id4)),
-
- corba:dispose(Obj3),
-
- ?match(ok, cosProperty:stop_SetDefFactory(Fac)),
-
- ok.
-
-
-
-%%-----------------------------------------------------------------
-%% CosPropertyService_PropertyNamesIterator API tests
-%%-----------------------------------------------------------------
-names_iterator_api(_Config) ->
- Fac = ?match({_,pseudo,_,_,_,_}, cosProperty:start_SetFactory()),
- Obj = ?match({_,pseudo,_,_,_,_}, 'CosPropertyService_PropertySetFactory':
- create_propertyset(Fac)),
- ?match(ok, 'CosPropertyService_PropertySet':
- define_properties(Obj, [#'CosPropertyService_Property'{property_name = ?id1,
- property_value = ?val1},
- #'CosPropertyService_Property'{property_name = ?id2,
- property_value = ?val2},
- #'CosPropertyService_Property'{property_name = ?id3,
- property_value = ?val3}])),
-
- ?match(3, 'CosPropertyService_PropertySetDef':get_number_of_properties(Obj)),
- {_, _,ItObj} = ?match({ok, [], _}, 'CosPropertyService_PropertySetDef':get_all_property_names(Obj, 0)),
- ?match({false, [_,_,_]}, 'CosPropertyService_PropertyNamesIterator':next_n(ItObj,3)),
- ?match(ok, 'CosPropertyService_PropertyNamesIterator':reset(ItObj)),
- ?match({false, [_,_,_]}, 'CosPropertyService_PropertyNamesIterator':next_n(ItObj,4)),
- ?match(ok, 'CosPropertyService_PropertyNamesIterator':reset(ItObj)),
- ?match({true, [_]}, 'CosPropertyService_PropertyNamesIterator':next_n(ItObj,1)),
- ?match({true, _}, 'CosPropertyService_PropertyNamesIterator':next_one(ItObj)),
- ?match({true, _}, 'CosPropertyService_PropertyNamesIterator':next_one(ItObj)),
- ?match({false, _}, 'CosPropertyService_PropertyNamesIterator':next_one(ItObj)),
- ?match(ok, 'CosPropertyService_PropertyNamesIterator':destroy(ItObj)),
-
- corba:dispose(Obj),
- ok.
-
-%%-----------------------------------------------------------------
-%% CosPropertyService_PropertiesIterator API tests
-%%-----------------------------------------------------------------
-properties_iterator_api(_Config) ->
- Fac = ?match({_,pseudo,_,_,_,_}, cosProperty:start_SetFactory()),
- Obj = ?match({_,pseudo,_,_,_,_}, 'CosPropertyService_PropertySetFactory':
- create_propertyset(Fac)),
-
- ?match(ok, 'CosPropertyService_PropertySet':
- define_properties(Obj, [#'CosPropertyService_Property'{property_name = ?id1,
- property_value = ?val1},
- #'CosPropertyService_Property'{property_name = ?id2,
- property_value = ?val2},
- #'CosPropertyService_Property'{property_name = ?id3,
- property_value = ?val3}])),
-
- ?match(3, 'CosPropertyService_PropertySetDef':get_number_of_properties(Obj)),
- {_, _,ItObj} = ?match({ok, [], _},
- 'CosPropertyService_PropertySetDef':get_all_properties(Obj, 0)),
- ?match({false, [_,_,_]}, 'CosPropertyService_PropertiesIterator':next_n(ItObj,3)),
- ?match(ok, 'CosPropertyService_PropertiesIterator':reset(ItObj)),
- ?match({false, [_,_,_]}, 'CosPropertyService_PropertiesIterator':next_n(ItObj,4)),
- ?match(ok, 'CosPropertyService_PropertiesIterator':reset(ItObj)),
- ?match({true, [_]}, 'CosPropertyService_PropertiesIterator':next_n(ItObj,1)),
- ?match({true, {'CosPropertyService_Property',_,_}},
- 'CosPropertyService_PropertiesIterator':next_one(ItObj)),
- ?match({true, {'CosPropertyService_Property',_,_}},
- 'CosPropertyService_PropertiesIterator':next_one(ItObj)),
- ?match({false, {'CosPropertyService_Property',_,_}},
- 'CosPropertyService_PropertiesIterator':next_one(ItObj)),
- ?match(ok, 'CosPropertyService_PropertiesIterator':destroy(ItObj)),
- corba:dispose(Obj),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% END OF MODULE
-%%-----------------------------------------------------------------
diff --git a/lib/cosProperty/vsn.mk b/lib/cosProperty/vsn.mk
deleted file mode 100644
index a3a952346e..0000000000
--- a/lib/cosProperty/vsn.mk
+++ /dev/null
@@ -1,2 +0,0 @@
-COSPROPERTY_VSN = 1.2.3
-
diff --git a/lib/cosTime/AUTHORS b/lib/cosTime/AUTHORS
deleted file mode 100644
index 55d8059989..0000000000
--- a/lib/cosTime/AUTHORS
+++ /dev/null
@@ -1,4 +0,0 @@
-Original Authors:
-Niclas Eklund
-
-Contributors:
diff --git a/lib/cosTime/Makefile b/lib/cosTime/Makefile
deleted file mode 100644
index e1b0b27284..0000000000
--- a/lib/cosTime/Makefile
+++ /dev/null
@@ -1,42 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2000-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include vsn.mk
-VSN=$(COSTIME_VSN)
-
-# ----------------------------------------------------
-# Common Macros
-# ----------------------------------------------------
-# SUB_DIRECTORIES = src test examples doc/src
-# At the moment we don't have any example programs.
-SUB_DIRECTORIES = src doc/src
-
-SPECIAL_TARGETS =
-
-# ----------------------------------------------------
-# Default Subdir Targets
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_subdir.mk
diff --git a/lib/cosTime/doc/html/.gitignore b/lib/cosTime/doc/html/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosTime/doc/html/.gitignore
+++ /dev/null
diff --git a/lib/cosTime/doc/man3/.gitignore b/lib/cosTime/doc/man3/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosTime/doc/man3/.gitignore
+++ /dev/null
diff --git a/lib/cosTime/doc/man6/.gitignore b/lib/cosTime/doc/man6/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosTime/doc/man6/.gitignore
+++ /dev/null
diff --git a/lib/cosTime/doc/pdf/.gitignore b/lib/cosTime/doc/pdf/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosTime/doc/pdf/.gitignore
+++ /dev/null
diff --git a/lib/cosTime/doc/src/CosTime_TIO.xml b/lib/cosTime/doc/src/CosTime_TIO.xml
deleted file mode 100644
index c01154a2c5..0000000000
--- a/lib/cosTime/doc/src/CosTime_TIO.xml
+++ /dev/null
@@ -1,109 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosTime_TIO</title>
- <prepared>Niclas Eklund</prepared>
- <responsible>Niclas Eklund</responsible>
- <docno></docno>
- <approved>Niclas Eklund</approved>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosTime_TIO</module>
- <modulesummary>This module implements the OMG CosTime::TIO interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosTime/include/*.hrl").</c></p>
- </description>
- <funcs>
- <func>
- <name>'_get_time_interval'(TIO) -> TimeInterval</name>
- <fsummary>Return the interval associated with the target object</fsummary>
- <type>
- <v>TIO = #objref</v>
- <v>TimeInterval = #'TimeBase_IntervalT{lower_bound, upper_bound}</v>
- <v>lower_bound = upper_bound = ulonglong</v>
- </type>
- <desc>
- <p>This operation returns the interval associated with the target object.</p>
- </desc>
- </func>
- <func>
- <name>spans(TIO, UTO) -> Reply</name>
- <fsummary>Return an OverlapType which describe how the interval in the target object and the timerange represented by the UTO object overlap</fsummary>
- <type>
- <v>TIO = UTO = OtherTIO = #objref</v>
- <v>Reply = {OverlapType, OtherTIO}</v>
- <v>OverlapType = 'OTContainer' | 'OTContained' | 'OTOverlap' | 'OTNoOverlap'</v>
- </type>
- <desc>
- <p>This operation returns a <em>OverlapType</em> depending on how the interval
- in the target object and the timerange represented by the UTO object
- overlap. If the OverlapType is 'OTNoOverlap' the out parameter represents
- the gap between the two intervals. If OverlapType is one of the others, the
- out parameter represents the overlap interval.
- The definitions of the OverlapType's are:</p>
- <p></p>
- <list type="bulleted">
- <item>'OTContainer' - target objects lower and upper limits are,
- respectively, less or equal to and greater or equal to given object's.</item>
- <item>'OTContained' - target objects lower and upper limits are,
- respectively, greater or equal to and less or equal to given object's.</item>
- <item>'OTOverlap' - target objects interval overlap given object's.</item>
- <item>'OTNoOverlap' - target objects interval do not overlap given object's.</item>
- </list>
- </desc>
- </func>
- <func>
- <name>overlaps(TIO, OtherTIO) -> Reply</name>
- <fsummary>Return an OverlapType which describe how the interval in the target object and the timerange represented by the TIO object overlap</fsummary>
- <type>
- <v>TIO = OtherTIO = AnotherTIO = #objref</v>
- <v>Reply = {OverlapType, AnotherTIO}</v>
- <v>OverlapType = 'OTContainer' | 'OTContained' | 'OTOverlap' | 'OTNoOverlap'</v>
- </type>
- <desc>
- <p>This operation returns a <em>OverlapType</em> depending on how the interval
- in the target object and the timerange represented by the TIO object
- overlap. The OverlapType's are described under spans/2.</p>
- </desc>
- </func>
- <func>
- <name>time(TIO) -> UTO</name>
- <fsummary>Return a UTO in which the interval equals the time interval in the target object and time value is the midpoint of the interval</fsummary>
- <type>
- <v>TIO = UTO = #objref</v>
- </type>
- <desc>
- <p>This operation returns a UTO in which the interval equals the time interval
- in the target object and time value is the midpoint of the interval.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosTime/doc/src/CosTime_TimeService.xml b/lib/cosTime/doc/src/CosTime_TimeService.xml
deleted file mode 100644
index b578128277..0000000000
--- a/lib/cosTime/doc/src/CosTime_TimeService.xml
+++ /dev/null
@@ -1,104 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosTime_TimeService</title>
- <prepared>Niclas Eklund</prepared>
- <responsible>Niclas Eklund</responsible>
- <docno></docno>
- <approved>Niclas Eklund</approved>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosTime_TimeService</module>
- <modulesummary>This module implements the OMG CosTime::TimeService interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosTime/include/*.hrl").</c></p>
- </description>
- <funcs>
- <func>
- <name>universal_time(TimeService) -> Reply</name>
- <fsummary>Return the current time and the Inaccuracy given when starting this application in a UTO</fsummary>
- <type>
- <v>TimeService = #objref</v>
- <v>Reply = UTO | {'EXCEPTION", #'TimerService_TimeUnavailable'{}}</v>
- <v>UTO = #objref</v>
- </type>
- <desc>
- <p>This operation returns the current time and the Inaccuracy given
- when starting this application in a UTO. The time base is
- <em>15 october 1582 00:00</em>. Comparing two time objects which use
- different time base is, by obvious reasons, pointless.</p>
- </desc>
- </func>
- <func>
- <name>new_universal_time(TimeService, Time, Inaccuracy, Tdf) -> UTO</name>
- <fsummary>Create a new UTO object representing the time parameters given</fsummary>
- <type>
- <v>TimeService = UTO = #objref</v>
- <v>Time = Inaccuracy = ulonglong()</v>
- <v>Tdf = short()</v>
- </type>
- <desc>
- <p>This operation creates a new UTO object representing the time
- parameters given. This is the only way to create a UTO with an
- arbitrary time from its components. This is useful when using the
- Timer Event Service.</p>
- </desc>
- </func>
- <func>
- <name>uto_from_utc(TimeService, Utc) -> UTO</name>
- <fsummary>Create a UTO representing the given time in Utc form</fsummary>
- <type>
- <v>TimeService = UTO = #objref</v>
- <v>Utc = #'TimeBase_UtcT'{time, inacclo, inacchi, tdf}</v>
- <v>time = ulonglong()</v>
- <v>inacclo = ulong()</v>
- <v>inacchi = ushort()</v>
- <v>tdf = short()</v>
- </type>
- <desc>
- <p>This operation is used to create a UTO given a time in the Utc form.</p>
- </desc>
- </func>
- <func>
- <name>new_interval(TimeService, Lower, Upper) -> TIO</name>
- <fsummary>Create a new TIO object representing the input parameters</fsummary>
- <type>
- <v>TimeService = TIO = #objref</v>
- <v>Lower = Upper = ulonglong()</v>
- </type>
- <desc>
- <p>This operation is used to create a new TIO object, representing
- the input parameters. If <em>Lower</em> is greater than Upper
- BAD_PARAM is raised.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosTime/doc/src/CosTime_UTO.xml b/lib/cosTime/doc/src/CosTime_UTO.xml
deleted file mode 100644
index 432d9d92f9..0000000000
--- a/lib/cosTime/doc/src/CosTime_UTO.xml
+++ /dev/null
@@ -1,156 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosTime_UTO</title>
- <prepared>Niclas Eklund</prepared>
- <responsible>Niclas Eklund</responsible>
- <docno></docno>
- <approved>Niclas Eklund</approved>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosTime_UTO</module>
- <modulesummary>This module implements the OMG CosTime::UTO interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosTime/include/*.hrl").</c></p>
- </description>
- <funcs>
- <func>
- <name>'_get_time'(UTO) -> ulonglong()</name>
- <fsummary>Return the time associated with the target object</fsummary>
- <type>
- <v>UTO = #objref</v>
- </type>
- <desc>
- <p>This operation returns the time associated with the target object.</p>
- </desc>
- </func>
- <func>
- <name>'_get_inaccuracy'(UTO) -> ulonglong()</name>
- <fsummary>Return the inaccuracy associated with the target object</fsummary>
- <type>
- <v>UTO = #objref</v>
- </type>
- <desc>
- <p>This operation returns the inaccuracy associated with the target object.</p>
- </desc>
- </func>
- <func>
- <name>'_get_tdf'(UTO) -> short()</name>
- <fsummary>Return the time displacement factor associated with the target object</fsummary>
- <type>
- <v>UTO = #objref</v>
- </type>
- <desc>
- <p>This operation returns the time displacement factor associated with
- the target object.</p>
- </desc>
- </func>
- <func>
- <name>'_get_utc_time'(UTO) -> UtcT</name>
- <fsummary>Return the data associated with the target object in Utc form</fsummary>
- <type>
- <v>UTO = #objref</v>
- <v>Utc = #'TimeBase_UtcT'{time, inacclo, inacchi, tdf}</v>
- <v>time = ulonglong()</v>
- <v>inacclo = ulong()</v>
- <v>inacchi = ushort()</v>
- <v>tdf = short()</v>
- </type>
- <desc>
- <p>This operation returns the data associated with the target object in
- Utc form.</p>
- </desc>
- </func>
- <func>
- <name>absolute_time(UTO) -> OtherUTO</name>
- <fsummary>Create a new UTO object representing the time in the target object added to current time (UTC)</fsummary>
- <type>
- <v>UTO = OtherUTO = #objref</v>
- </type>
- <desc>
- <p>This operation create a new UTO object representing the time in the target
- object added to current time (UTC). The time base is
- <em>15 october 1582 00:00</em>. Comparing two time objects which use
- different time base is, by obvious reasons, pointless.
- Raises DATA_CONVERSION if causes an overflow. This operation is only useful
- if the target object represents a relative time.</p>
- </desc>
- </func>
- <func>
- <name>compare_time(UTO, ComparisonType, OtherUTO) -> Reply</name>
- <fsummary>Compare the time associated with the target object and the given UTO object</fsummary>
- <type>
- <v>UTO = OtherUTO = #objref</v>
- <v>ComparisonType = 'IntervalC' | 'MidC'</v>
- <v>Reply = 'TCEqualTo' | 'TCLessThan' | 'TCGreaterThan' | 'TCIndeterminate'</v>
- </type>
- <desc>
- <p>This operation compares the time associated with the target object and the
- given UTO object. The different <c>ComparisonType</c> are:</p>
- <p></p>
- <list type="bulleted">
- <item>'MidC' - only compare the time represented by each object. Furthermore,
- the target object is always used as the first parameter in the
- comparison, i.e., if the target object's time is larger
- 'TCGreaterThan' will be returned.</item>
- <item>'IntervalC' - also takes the inaccuracy into consideration, i.e.,
- if the two objects interval overlaps 'TCIndeterminate' is returned,
- otherwise the as for 'MidC'.</item>
- </list>
- </desc>
- </func>
- <func>
- <name>time_to_interval(UTO, OtherUTO) -> TIO</name>
- <fsummary>Create a TIO representing the interval between the target object and the given UTO midpoint times</fsummary>
- <type>
- <v>UTO = OtherUTO = TIO = #objref</v>
- </type>
- <desc>
- <p>This operation returns a TIO representing the interval between the target
- object and the given UTO midpoint times. The inaccuracy in the objects are
- not taken into consideration.</p>
- </desc>
- </func>
- <func>
- <name>interval(UTO) -> TIO</name>
- <fsummary>Create a TIO object representing the error interval around the time value represented by the target object</fsummary>
- <type>
- <v>UTO = TIO = #objref</v>
- </type>
- <desc>
- <p>This operation creates a TIO object representing the error interval
- around the time value represented by the target object, i.e.,
- <c>TIO.upper_bound = UTO.time+UTO.inaccuracy</c> and
- <c>TIO.lower_bound = UTO.time-UTO.inaccuracy</c>.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosTime/doc/src/CosTimerEvent_TimerEventHandler.xml b/lib/cosTime/doc/src/CosTimerEvent_TimerEventHandler.xml
deleted file mode 100644
index 4b43b0b12e..0000000000
--- a/lib/cosTime/doc/src/CosTimerEvent_TimerEventHandler.xml
+++ /dev/null
@@ -1,125 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosTimerEvent_TimerEventHandler</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved>Niclas Eklund</approved>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosTimerEvent_TimerEventHandler</module>
- <modulesummary>This module implements the OMG CosTimerEvent::TimerEventHandler interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosTime/include/*.hrl").</c></p>
- </description>
- <funcs>
- <func>
- <name>'_get_status'(TimerEventHandler) -> Reply</name>
- <fsummary>Return the status of the target object</fsummary>
- <type>
- <v>TimerEventHandler = #objref</v>
- <v>Reply = 'ESTimeSet' | 'ESTimeCleared' | 'ESTriggered' | 'ESFailedTrigger'</v>
- </type>
- <desc>
- <p>This operation returns the status of the target object. </p>
- <list type="bulleted">
- <item>'ESTimeSet' - timer is set to trigger event(s).</item>
- <item>'ESTimeCleared' - no time set or the timer have been reset.</item>
- <item>'ESTriggered' - event has already been sent.</item>
- <item>'ESFailedTrigger' - tried to, but failed, sending the event.</item>
- </list>
- <p>If the target object is of type 'TTPeriodic' the status value
- 'ESTriggered' is not valid.</p>
- </desc>
- </func>
- <func>
- <name>time_set(TimerEventHandler) -> Reply</name>
- <fsummary>Return <c>true</c>if the time has been set for an event that is yet to be triggered, <c>false</c>otherwise. The outparameter represents the current time value of the target object</fsummary>
- <type>
- <v>TimerEventHandler = #objref</v>
- <v>Reply = {boolean(), UTO}</v>
- <v>UTO = #objref</v>
- </type>
- <desc>
- <p>This operation returns <c>true</c> if the time has been set for an event that
- is yet to be triggered, <c>false</c> otherwise. The outparameter represents
- the current time value of the target object.</p>
- </desc>
- </func>
- <func>
- <name>set_timer(TimerEventHandler, TimeType, TriggerTime) -> void()</name>
- <fsummary>Terminate terminate any previous set trigger, and set a new trigger specified by the <c>TimeType</c>and <c>UTO</c>objects</fsummary>
- <type>
- <v>TimerEventHandler = #objref</v>
- <v>TimeType = 'TTAbsolute' | 'TTRelative' | 'TTPeriodic'</v>
- <v>TriggerTime = UTO</v>
- <v>UTO = #objref</v>
- </type>
- <desc>
- <p>This operation terminates any previous set trigger, and set a new trigger
- specified by the <c>TimeType</c> and <c>UTO</c> objects.</p>
- <p>The relation between the UTO object and the TimeTypes are:</p>
- <list type="bulleted">
- <item>'TTAbsolute' - the UTO object must represent absolute time, i.e.,
- number of 100 nanoseconds passed since 15 october
- 1582 00:00.</item>
- <item>'TTRelative' - the UTO object must represent the from now until when
- the event should be triggered, e.g., within 30*10^7 nanoseconds.</item>
- <item>'TTPeriodic' - the same as for 'TTRelative', but this option
- will trigger an event periodically until timer cancelled.</item>
- </list>
- </desc>
- </func>
- <func>
- <name>cancel_timer(TimerEventHandler) -> boolean()</name>
- <fsummary>Cancel, if possible, triggering of event(s). Return<c>true</c>if an event is actually cancelled, <c>false</c>otherwise</fsummary>
- <type>
- <v>TimerEventHandler = #objref</v>
- </type>
- <desc>
- <p>This operation cancel, if possible, the triggering of event(s). Returns
- <c>true</c> if an event is actually cancelled, <c>false</c> otherwise.</p>
- </desc>
- </func>
- <func>
- <name>set_data(TimerEventHandler, EventData) -> ok</name>
- <fsummary>Change the event data sent when triggered</fsummary>
- <type>
- <v>TimerEventHandler = #objref</v>
- <v>EventData = #any</v>
- </type>
- <desc>
- <p>This operation changes the event data sent when triggered.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosTime/doc/src/CosTimerEvent_TimerEventService.xml b/lib/cosTime/doc/src/CosTimerEvent_TimerEventService.xml
deleted file mode 100644
index 1db4760c81..0000000000
--- a/lib/cosTime/doc/src/CosTimerEvent_TimerEventService.xml
+++ /dev/null
@@ -1,84 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosTimerEvent_TimerEventService</title>
- <prepared>Niclas Eklund</prepared>
- <responsible>Niclas Eklund</responsible>
- <docno></docno>
- <approved>Niclas Eklund</approved>
- <checked></checked>
- <date>2000-02-01</date>
- <rev>1.0</rev>
- </header>
- <module>CosTimerEvent_TimerEventService</module>
- <modulesummary>This module implements the OMG CosTimerEvent::TimerEventService interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosTime/include/*.hrl").</c></p>
- </description>
- <funcs>
- <func>
- <name>register(TimerEventService, CosEventCommPushConsumer, Data) -> TimerEventHandler</name>
- <fsummary>Create a new <c>TimerEventHandler</c>object which push the given<c>Data</c>to given <c>CosEventCommPushConsumer</c>after the timer have been set</fsummary>
- <type>
- <v>TimerEventService = CosEventCommPushConsumer = TimerEventHandler = #objref</v>
- <v>Data = #any</v>
- </type>
- <desc>
- <p>This operation will create a new <c>TimerEventHandler</c> object which
- will push given <c>Data</c> to given <c>CosEventCommPushConsumer</c> after
- the timer have been set.</p>
- </desc>
- </func>
- <func>
- <name>unregister(TimerEventService, TimerEventHandler) -> ok</name>
- <fsummary>Terminate the target TimerEventHandler object</fsummary>
- <type>
- <v>TimerEventService = TimerEventHandler = #objref</v>
- </type>
- <desc>
- <p>This operation will terminate the given TimerEventHandler.</p>
- </desc>
- </func>
- <func>
- <name>event_time(TimerEventService, TimerEvent) -> UTO</name>
- <fsummary>Return a UTO containing the time at which the associated event was triggered</fsummary>
- <type>
- <v>TimerEventService = #objref</v>
- <v>TimerEvent = #'CosTimerEvent_TimerEvent'{utc, event_data}</v>
- <v>utc = </v>
- <v>event_data = #any}</v>
- <v>UTO = #objref</v>
- </type>
- <desc>
- <p>This operation returns a UTO containing the time at which the associated
- event was triggered.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosTime/doc/src/Makefile b/lib/cosTime/doc/src/Makefile
deleted file mode 100644
index 6886d2812c..0000000000
--- a/lib/cosTime/doc/src/Makefile
+++ /dev/null
@@ -1,138 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2000-2017. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../../vsn.mk
-VSN=$(COSTIME_VSN)
-APPLICATION=cosTime
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-XML_APPLICATION_FILES = ref_man.xml
-XML_REF3_FILES = \
- cosTime.xml \
- CosTime_TIO.xml \
- CosTime_TimeService.xml \
- CosTime_UTO.xml \
- CosTimerEvent_TimerEventHandler.xml \
- CosTimerEvent_TimerEventService.xml \
-
-XML_PART_FILES = \
- part.xml
-XML_CHAPTER_FILES = \
- ch_contents.xml \
- ch_introduction.xml \
- ch_install.xml \
- ch_example.xml \
- notes.xml
-
-BOOK_FILES = book.xml
-
-XML_FILES = $(BOOK_FILES) $(XML_APPLICATION_FILES) $(XML_REF3_FILES) \
- $(XML_PART_FILES) $(XML_CHAPTER_FILES)
-
-TECHNICAL_DESCR_FILES =
-
-GIF_FILES =
-
-PS_FILES =
-
-# ----------------------------------------------------
-
-INTERNAL_HTML_FILES = $(TECHNICAL_DESCR_FILES:%.xml=$(HTMLDIR)/%.html)
-
-HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \
- $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html)
-
-INFO_FILE = ../../info
-EXTRA_FILES = \
- $(DEFAULT_GIF_FILES) \
- $(DEFAULT_HTML_FILES) \
- $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html) \
- $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html)
-
-MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-
-HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
-
-TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-XML_FLAGS +=
-DVIPS_FLAGS +=
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-$(HTMLDIR)/%.gif: %.gif
- $(INSTALL_DATA) $< $@
-
-docs: pdf html man
-
-$(TOP_PDF_FILE): $(XML_FILES)
-
-pdf: $(TOP_PDF_FILE)
-
-html: gifs $(HTML_REF_MAN_FILE)
-
-clean clean_docs:
- rm -rf $(HTMLDIR)/*
- rm -f $(MAN3DIR)/*
- rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
- rm -f errs core *~
-
-man: $(MAN3_FILES)
-
-gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
-
-$(INDEX_TARGET): $(INDEX_SRC)
- sed -e 's;%VSN%;$(VSN);' $(INDEX_SRC) > $(INDEX_TARGET)
-
-debug opt:
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_docs_spec: docs
- $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
- $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
- $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
- $(INSTALL_DATA) $(HTMLDIR)/* \
- "$(RELSYSDIR)/doc/html"
- $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
- $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
- $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
-
-release_spec:
diff --git a/lib/cosTime/doc/src/book.xml b/lib/cosTime/doc/src/book.xml
deleted file mode 100644
index a89b005e84..0000000000
--- a/lib/cosTime/doc/src/book.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE book SYSTEM "book.dtd">
-
-<book xmlns:xi="http://www.w3.org/2001/XInclude">
- <header titlestyle="normal">
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosTime</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2000-01-31</date>
- <rev>1.0</rev>
- </header>
- <insidecover>
- </insidecover>
- <pagetext>cosTime</pagetext>
- <preamble>
- <contents level="2"></contents>
- </preamble>
- <parts lift="no">
- <xi:include href="part.xml"/>
- </parts>
- <applications>
- <xi:include href="ref_man.xml"/>
- </applications>
- <releasenotes>
- <xi:include href="notes.xml"/>
- </releasenotes>
- <listofterms></listofterms>
- <index></index>
-</book>
-
diff --git a/lib/cosTime/doc/src/ch_contents.xml b/lib/cosTime/doc/src/ch_contents.xml
deleted file mode 100644
index 8b1c9dd646..0000000000
--- a/lib/cosTime/doc/src/ch_contents.xml
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>The cosTime Application</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2000-01-31</date>
- <rev>1.0</rev>
- <file>ch_contents.xml</file>
- </header>
-
- <section>
- <title>Content Overview</title>
- <p>The cosTime documentation is divided into three sections:
- </p>
- <list type="bulleted">
- <item>
- <p>PART ONE - The User's Guide
- <br></br>
-Description of the cosTime Application including
- services and a small tutorial demonstrating
- the development of a simple service.</p>
- </item>
- <item>
- <p>PART TWO - Release Notes
- <br></br>
-A concise history of cosTime.</p>
- </item>
- <item>
- <p>PART THREE - The Reference Manual
- <br></br>
- A quick reference guide, including a
- brief description, to all the functions available in cosTime.</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Brief Description of the User's Guide</title>
- <p>The User's Guide contains the following parts:</p>
- <list type="bulleted">
- <item>
- <p>cosTime overview</p>
- </item>
- <item>
- <p>cosTime installation</p>
- </item>
- <item>
- <p>A tutorial example</p>
- </item>
- </list>
- </section>
-</chapter>
-
diff --git a/lib/cosTime/doc/src/ch_example.xml b/lib/cosTime/doc/src/ch_example.xml
deleted file mode 100644
index 690fba8d93..0000000000
--- a/lib/cosTime/doc/src/ch_example.xml
+++ /dev/null
@@ -1,113 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosTime Examples</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2000-01-31</date>
- <rev>A</rev>
- <file>ch_example.xml</file>
- </header>
-
- <section>
- <title>A Tutorial on How to Create a Simple Service</title>
-
- <section>
- <title>Initiate the Application</title>
- <p>To use the complete cosTime application Time and Timer Event Services
- must be installed. The application is then started by using
- <c>cosTime:start()</c>. To get access to Time Service or Timer Event Service,
- use <c>start_time_service/2</c> or <c>start_timerevent_service/1.</c></p>
- <p>The Time Service are global, i.e., there may only exist one instance per
- Orber domain.</p>
- <p>The Timer Event Service is locally registered, i.e., there may only exist
- one instance per node.</p>
- <note>
- <p>The Time and Timer Event Service use the time base
- <em>15 october 1582 00:00</em>. Performing operations using other time
- bases will not yield correct result. Furthermore, time and inaccuracy
- must be expressed in 100 nano seconds.</p>
- </note>
- </section>
-
- <section>
- <title>How to Run Everything</title>
- <p>Below is a short transcript on how to run cosTime. </p>
- <code type="none">
-
-%% Start Mnesia and Orber
-mnesia:delete_schema([node()]),
-mnesia:create_schema([node()]),
-orber:install([node()]),
-mnesia:start(),
-orber:start(),
-
-%% Install Time Service in the IFR.
-cosTime:install_time(),
-
-%% Install Timer Event Service in the IFR. Which, require
-%% the Time Service and cosEvent or cosNotification
-%% application to be installed.
-cosNotification:install(),
-cosTime:install_timerevent(),
-
-%% Now start the application and necessary services.
-cosTime:start(),
-%% Tdf == Time displacement factor
-%% Inaccuracy measured in 100 nano seconds
-TS=cosTime:start_time_service(TDF, Inaccuracy),
-TES=cosTime:start_timerevent_service(TS),
-
-%% Access a cosNotification Proxy Push Consumer. How this is
-%% done is implementation specific.
-ProxyPushConsumer = ....
-
-%% How we construct the event is also implementation specific.
-AnyEvent = ....
-
-%% Create a new relative universal time.
-%% Time measured in 100 nano seconds.
-UTO='CosTime_TimeService':
- new_universal_time(TS, Time, Inaccuracy, TDF),
-EH='CosTimerEvent_TimerEventService':
- register(TES, ProxyPushConsumer, AnyEvent),
-
-%% If we want to trigger one event Time*10^-7 seconds from now:
-'CosTimerEvent_TimerEventHandler':set_timer(EH, 'TTRelative', UTO),
-
-%% If we want to trigger an event every Time*10^-7 seconds, starting
-%% Time*10^-7 seconds from now:
-'CosTimerEvent_TimerEventHandler':set_timer(EH, 'TTPeriodic', UTO),
-
-%% If we want to use absolute time we must retrieve such an object.
-%% One way is to convert the one we got, UTO, by using:
-UTO2='CosTime_UTO':absolute_time(UTO),
-%% If any other way is used, the correct time base MUST be used, i.e.,
-%% 15 october 1582 00:00.
-'CosTimerEvent_TimerEventHandler':set_timer(EH, 'TTAbsolute', UTO2),
- </code>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosTime/doc/src/ch_install.xml b/lib/cosTime/doc/src/ch_install.xml
deleted file mode 100644
index 9d819a7be7..0000000000
--- a/lib/cosTime/doc/src/ch_install.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Installing cosTime</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2000-01-31</date>
- <rev></rev>
- <file>ch_install.xml</file>
- </header>
-
- <section>
- <title>Installation Process </title>
- <p>This chapter describes how to install
- <seealso marker="cosTime">cosTime</seealso> in an Erlang Environment.
- </p>
-
- <section>
- <title>Preparation</title>
- <p>Before starting the installation process for cosTime,
- the application Orber must be running.</p>
- </section>
-
- <section>
- <title>Configuration</title>
- <p>When using both the Time and TimerEvent Services the <c>cosTime</c> application
- first must be installed using <c>cosTime:install_time()</c> and
- <c>cosTime:install_timerevent()</c>, followed by <c>cosTime:start()</c>.
- Now we can choose which can start the servers by using
- <c>cosTime:start_time_service(Tdf, Inaccuracy)</c>
- and <c>cosTime:start_timerevent_service(TimeService)</c>.</p>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosTime/doc/src/ch_introduction.xml b/lib/cosTime/doc/src/ch_introduction.xml
deleted file mode 100644
index 1a11606716..0000000000
--- a/lib/cosTime/doc/src/ch_introduction.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Introduction to cosTime</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2000-01-31</date>
- <rev></rev>
- <file>ch_introduction.xml</file>
- </header>
-
- <section>
- <title>Overview</title>
- <p>The cosTime application is Time and TimerEvent Services compliant with the <url href="http://www.omg.org">OMG</url>
- Services CosTime and CosTimerEvent.
- </p>
-
- <section>
- <title>Purpose and Dependencies</title>
- <p>This application use <c>calender:now_to_universal_time(Now)</c> to create a
- UTC. Hence, the underlying OS must deliver a correct result when calling
- <c>erlang:now()</c>.</p>
- <p><em>cosTime</em> is dependent on <em>Orber</em>, which provides CORBA functionality in an Erlang environment.</p>
- <p><em>cosTimerEvent</em> is dependent on <em>Orber</em> and <em>cosNotification</em>,
- which provides CORBA functionality and Event handling in an Erlang environment.</p>
- </section>
-
- <section>
- <title>Prerequisites</title>
- <p>To fully understand the concepts presented in the
- documentation, it is recommended that the user is familiar
- with distributed programming, CORBA, the Orber and cosNotification applications.
- </p>
- <p>Recommended reading includes <em>CORBA, Fundamentals and Programming - Jon Siegel</em> and <em>Open Telecom Platform Documentation Set</em>. It is also helpful to have read <em>Concurrent Programming in Erlang</em>.</p>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosTime/doc/src/cosTime.xml b/lib/cosTime/doc/src/cosTime.xml
deleted file mode 100644
index 02aef1401c..0000000000
--- a/lib/cosTime/doc/src/cosTime.xml
+++ /dev/null
@@ -1,175 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>cosTime</title>
- <prepared>Niclas Eklund</prepared>
- <responsible>Niclas Eklund</responsible>
- <docno></docno>
- <approved>Niclas Eklund</approved>
- <checked></checked>
- <date>2000-01-31</date>
- <rev>PA1</rev>
- </header>
- <module>cosTime</module>
- <modulesummary>The main module of the cosTime application</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosTime/include/*.hrl").</c></p>
- <p>This module contains the functions for starting and stopping the application.</p>
- <p>This application use the time base <em>15 october 1582 00:00</em>.
- Performing operations using other time bases will not yield correct result.</p>
- <p>The OMG CosTime specification defines the operation
- <c>secure_universal_time</c>. As of today we cannot provide this functionality
- considering the criteria demanded to fulfill the OMG specification.</p>
- <p>When using this application, time and inaccuracy supplied by the user must
- be given in number of <em>100 nano seconds</em>. The
- <em>Time Displacement Factor</em> is positive east of the meridian, while
- those to the west are negative.</p>
- <p>This application use <c>calender:now_to_universal_time(Now)</c> to create a
- UTC. Hence, the underlying OS must deliver a correct result when calling
- <c>erlang:now()</c>.</p>
- <p>When determining the inaccuracy of the system, the user should consider the
- way the time objects will be used. Communicating with other ORB's, add a
- substantial overhead and should be taken into consideration.</p>
- </description>
- <funcs>
- <func>
- <name>install_time() -> Return</name>
- <fsummary>Install the cosTime Time Service part application</fsummary>
- <type>
- <v>Return = ok | {'EXIT', Reason}</v>
- </type>
- <desc>
- <p>This operation installs the cosTime Time Service part application.</p>
- </desc>
- </func>
- <func>
- <name>uninstall_time() -> Return</name>
- <fsummary>Uninstall the cosTime Time Service part application</fsummary>
- <type>
- <v>Return = ok | {'EXIT', Reason}</v>
- </type>
- <desc>
- <p>This operation uninstalls the cosTime Time Service part application.</p>
- </desc>
- </func>
- <func>
- <name>install_timerevent() -> Return</name>
- <fsummary>Install the cosTime Timer Event Service part application</fsummary>
- <type>
- <v>Return = ok | {'EXIT', Reason}</v>
- </type>
- <desc>
- <p>This operation installs the cosTime Timer Event Service part application.</p>
- <note>
- <p>The Timer Event Service part requires <em>Time Service</em> part and
- <em>cosEvent</em> or the <em>cosNotification</em> application to be installed
- first.</p>
- </note>
- </desc>
- </func>
- <func>
- <name>uninstall_timerevent() -> Return</name>
- <fsummary>Uninstall the cosTime Timer Event Service part application</fsummary>
- <type>
- <v>Return = ok | {'EXIT', Reason}</v>
- </type>
- <desc>
- <p>This operation uninstalls the cosTime Timer Event Service part application.</p>
- </desc>
- </func>
- <func>
- <name>start() -> Return</name>
- <fsummary>Start the cosTime application</fsummary>
- <type>
- <v>Return = ok | {error, Reason}</v>
- </type>
- <desc>
- <p>This operation starts the cosTime application.</p>
- </desc>
- </func>
- <func>
- <name>stop() -> Return</name>
- <fsummary>Stop the cosTime application</fsummary>
- <type>
- <v>Return = ok | {error, Reason}</v>
- </type>
- <desc>
- <p>This operation stops the cosTime application.</p>
- </desc>
- </func>
- <func>
- <name>start_time_service(Tdf, Inaccuracy) -> Return</name>
- <fsummary>Start a Time Service object</fsummary>
- <type>
- <v>Tdf = short()</v>
- <v>Inaccuracy = ulonglong(), eq. #100 nano seconds</v>
- <v>Return = ok | {'EXCEPTION', #'BAD_PARAM'{}}</v>
- </type>
- <desc>
- <p>This operation starts a Time Service server. Please note that there
- may only be exactly one Time Service active at a time. The <c>Inaccuracy</c>
- parameter defines the inaccuracy the underlying OS will introduce. Remember
- to take into account latency when passing time object between nodes.</p>
- </desc>
- </func>
- <func>
- <name>stop_time_service(TimeService) -> ok</name>
- <fsummary>Stop the target Time Service object</fsummary>
- <type>
- <v>TimeService = #objref</v>
- </type>
- <desc>
- <p>This operation stops the Time Service object.</p>
- </desc>
- </func>
- <func>
- <name>start_timerevent_service(TimeService) -> ok</name>
- <fsummary>Start a Timer Event Service object</fsummary>
- <type>
- <v>TimeService = #objref</v>
- </type>
- <desc>
- <p>This operation starts a Timer Event Service server. Please note that there
- may only be exactly one Timer Event Service per node active at a time. The
- supplied TimeServcie reference will be the object Timer Event Service
- contacts to get access to a new UTC.</p>
- </desc>
- </func>
- <func>
- <name>stop_timerevent_service(TimerEventService) -> ok</name>
- <fsummary>Stop the target Timer Event Service object</fsummary>
- <type>
- <v>TimerEventService = #objref</v>
- </type>
- <desc>
- <p>This operation stops the Timer Event Service object.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosTime/doc/src/notes.xml b/lib/cosTime/doc/src/notes.xml
deleted file mode 100644
index 16e02f8b1f..0000000000
--- a/lib/cosTime/doc/src/notes.xml
+++ /dev/null
@@ -1,360 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosTime Release Notes</title>
- <prepared>Niclas Eklund</prepared>
- <responsible>Niclas Eklund</responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>2000-01-31</date>
- <rev>A</rev>
- <file>notes.xml</file>
- </header>
-
- <section><title>cosTime 1.2.3</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> Removed all old unused files in the documentation.
- </p>
- <p>
- Own Id: OTP-14475 Aux Id: ERL-409, PR-1493 </p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosTime 1.2.2</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Internal changes</p>
- <p>
- Own Id: OTP-13551</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosTime 1.2.1</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> Suppress Dialyzer warnings. </p>
- <p>
- Own Id: OTP-12862</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosTime 1.2</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> Remove the usage of erlang:now() from all Corba
- applications and use the new rand module instead of
- random. </p>
- <p>
- Own Id: OTP-12687</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosTime 1.1.14</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> The default encoding of Erlang files has been changed
- from ISO-8859-1 to UTF-8. </p> <p> The encoding of XML
- files has also been changed to UTF-8. </p>
- <p>
- Own Id: OTP-10907</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosTime 1.1.13</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Misc build updates</p>
- <p>
- Own Id: OTP-10784</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosTime 1.1.12</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>Erlang/OTP can now be built using parallel make if you
- limit the number of jobs, for instance using '<c>make
- -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not
- work at the moment because of some missing
- dependencies.</p>
- <p>
- Own Id: OTP-9451</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section>
- <title>cosTime 1.1.11</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- Removed superfluous usage of shy in the documentation since it can cause problem if
- a buggy tool is used.</p>
- <p>
- Own Id: OTP-9319 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosTime 1.1.10</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- Eliminated Dialyzer warnings when using exit or throw.</p>
- <p>
- Own Id: OTP-9050 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosTime 1.1.9</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- Test suites published.</p>
- <p>
- Own Id: OTP-8543 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosTime 1.1.8</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>The documentation EIX file was not generated.</p>
- <p>Own id: OTP-8355 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosTime 1.1.7</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- The documentation is now built with open source tools (xsltproc and fop)
- that exists on most platforms. One visible change is that the frames are removed.</p>
- <p>
- Own Id: OTP-8201 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosTime 1.1.6</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Obsolete guards, e.g. record vs is_record, has been changed
- to avoid compiler warnings.</p>
- <p>Own id: OTP-7987</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosTime 1.1.5</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Updated file headers.</p>
- <p>Own id: OTP-7837</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosTime 1.1.4</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Documentation source included in open source releases.</p>
- <p>Own id: OTP-7595</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosTime 1.1.3</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Updated file headers.</p>
- <p>Own id: OTP-7011</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosTime 1.1.2</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>The documentation source has been converted from SGML to XML.</p>
- <p>Own id: OTP-6754</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosTime 1.1.1</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Minor Makefile changes.</p>
- <p>Own id: OTP-6701</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosTime 1.1</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>The stub/skeleton-files generated by IC have been improved,
- i.e., depending on the IDL-files, reduced the size of the
- erl- and beam-files and decreased dependencies off Orber's
- Interface Repository. It is necessary to re-compile all IDL-files
- and use COS-applications, including Orber, compiled with
- IC-4.2.</p>
- <p>Own id: OTP-4576</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosTime 1.0.1.1</title>
-
- <section>
- <title>Incompatibilities</title>
- <list type="bulleted">
- <item>
- <p>An includepath in <c>CosTimerEvent.idl</c> have been
- changed. Hence, if you include this file you should check
- your include paths for your IDL-file(s), i.e., add
- the path to CosEventComm.idl.</p>
- <p>Own Id: OTP-4093</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosTime 1.0.1</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>First release of the cosTime application.</p>
- <p>Own Id: -</p>
- </item>
- </list>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosTime/doc/src/part.xml b/lib/cosTime/doc/src/part.xml
deleted file mode 100644
index f0b26d4a56..0000000000
--- a/lib/cosTime/doc/src/part.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE part SYSTEM "part.dtd">
-
-<part xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosTime User's Guide</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2000-01-31</date>
- <rev>1.0</rev>
- </header>
- <description>
- <p>The <em>cosTime</em> application is an Erlang implementation of the OMG
- CORBA Time and TimerEvent Services.</p>
- </description>
- <xi:include href="ch_contents.xml"/>
- <xi:include href="ch_introduction.xml"/>
- <xi:include href="ch_install.xml"/>
- <xi:include href="ch_example.xml"/>
-</part>
-
diff --git a/lib/cosTime/doc/src/ref_man.xml b/lib/cosTime/doc/src/ref_man.xml
deleted file mode 100644
index 66bca4af0e..0000000000
--- a/lib/cosTime/doc/src/ref_man.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE application SYSTEM "application.dtd">
-
-<application xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>2000</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosTime Reference Manual</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2000-01-31</date>
- <rev>1.0</rev>
- </header>
- <description>
- <p>The <em>cosTime</em> application is an Erlang implementation of the OMG
- CORBA Time and TimerEvent Services.</p>
- </description>
- <xi:include href="cosTime.xml"/>
- <xi:include href="CosTime_TIO.xml"/>
- <xi:include href="CosTime_TimeService.xml"/>
- <xi:include href="CosTime_UTO.xml"/>
- <xi:include href="CosTimerEvent_TimerEventHandler.xml"/>
- <xi:include href="CosTimerEvent_TimerEventService.xml"/>
-</application>
-
diff --git a/lib/cosTime/ebin/.gitignore b/lib/cosTime/ebin/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosTime/ebin/.gitignore
+++ /dev/null
diff --git a/lib/cosTime/examples/.gitignore b/lib/cosTime/examples/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosTime/examples/.gitignore
+++ /dev/null
diff --git a/lib/cosTime/include/.gitignore b/lib/cosTime/include/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosTime/include/.gitignore
+++ /dev/null
diff --git a/lib/cosTime/info b/lib/cosTime/info
deleted file mode 100644
index 7820f3fdaa..0000000000
--- a/lib/cosTime/info
+++ /dev/null
@@ -1,12 +0,0 @@
-group: orb
-short: Orber OMG Timer and TimerEvent Services
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/cosTime/priv/.gitignore b/lib/cosTime/priv/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosTime/priv/.gitignore
+++ /dev/null
diff --git a/lib/cosTime/src/CosTime.cfg b/lib/cosTime/src/CosTime.cfg
deleted file mode 100644
index 1aad9ebb94..0000000000
--- a/lib/cosTime/src/CosTime.cfg
+++ /dev/null
@@ -1,6 +0,0 @@
-{this, "CosTime::UTO"}.
-{{handle_info, "CosTime::UTO"}, true}.
-{this, "CosTime::TIO"}.
-{{handle_info, "CosTime::TIO"}, true}.
-{this, "CosTime::TimeService"}.
-{{handle_info, "CosTime::TimeService"}, true}.
diff --git a/lib/cosTime/src/CosTime.idl b/lib/cosTime/src/CosTime.idl
deleted file mode 100644
index 2bf32681c1..0000000000
--- a/lib/cosTime/src/CosTime.idl
+++ /dev/null
@@ -1,59 +0,0 @@
-#ifndef _COS_TIME_IDL_
-#define _COS_TIME_IDL_
-
-#pragma prefix "omg.org"
-
-#include<TimeBase.idl>
-
-module CosTime {
- enum TimeComparison {
- TCEqualTo,
- TCLessThan,
- TCGreaterThan,
- TCIndeterminate
- };
- enum ComparisonType{
- IntervalC,
- MidC };
- enum OverlapType {
- OTContainer,
- OTContained,
- OTOverlap,
- OTNoOverlap
- };
-
- exception TimeUnavailable {};
- interface TIO; // forward declaration
-
- interface UTO {
- readonly attribute TimeBase::TimeT time;
- readonly attribute TimeBase::InaccuracyT inaccuracy;
- readonly attribute TimeBase::TdfT tdf;
- readonly attribute TimeBase::UtcT utc_time;
-
- UTO absolute_time();
- TimeComparison compare_time( in ComparisonType comparison_type, in UTO uto );
- TIO time_to_interval( in UTO uto );
- TIO interval();
- };
-
- interface TIO {
- readonly attribute TimeBase::IntervalT time_interval;
-
- OverlapType spans ( in UTO time, out TIO overlap );
- OverlapType overlaps ( in TIO interval, out TIO overlap );
- UTO time ();
- };
-
- interface TimeService {
- UTO universal_time()
- raises(TimeUnavailable );
- UTO secure_universal_time()
- raises(TimeUnavailable );
- UTO new_universal_time( in TimeBase::TimeT time, in TimeBase::InaccuracyT inaccuracy, in TimeBase::TdfT tdf );
- UTO uto_from_utc( in TimeBase::UtcT utc );
- TIO new_interval( in TimeBase::TimeT lower, in TimeBase::TimeT upper );
- };
-};
-
-#endif
diff --git a/lib/cosTime/src/CosTime_TIO_impl.erl b/lib/cosTime/src/CosTime_TIO_impl.erl
deleted file mode 100644
index 6d4046d428..0000000000
--- a/lib/cosTime/src/CosTime_TIO_impl.erl
+++ /dev/null
@@ -1,201 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : CosTime_TIO_impl.erl
-%% Purpose :
-%%----------------------------------------------------------------------
-
--module('CosTime_TIO_impl').
-
-%%--------------- INCLUDES -----------------------------------
--include("cosTimeApp.hrl").
-
-%%--------------- EXPORTS ------------------------------------
-%%--------------- External -----------------------------------
-%% Attributes (external)
--export(['_get_time_interval'/2]).
-
-%% Interface functions
--export([spans/3, overlaps/3, time/2]).
-
-%%--------------- gen_server specific exports ----------------
--export([handle_info/2, code_change/3]).
--export([init/1, terminate/2]).
-
-
-%% Data structures
--record(state, {interval,
- tdf,
- timer}).
-%% Data structures constructors
--define(get_InitState(I,T,TO),
- #state{interval = I,
- tdf = T,
- timer = TO}).
-
-%% Data structures selectors
--define(get_IntervalT(S), S#state.interval).
--define(get_Lower(S), (S#state.interval)#'TimeBase_IntervalT'.lower_bound).
--define(get_Upper(S), (S#state.interval)#'TimeBase_IntervalT'.upper_bound).
--define(get_Tdf(S), S#state.tdf).
--define(get_TimerObj(S), S#state.timer).
-
-%%-----------------------------------------------------------%
-%% function : handle_info, code_change
-%% Arguments:
-%% Returns :
-%% Effect : Functions demanded by the gen_server module.
-%%------------------------------------------------------------
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-handle_info(_Info, State) ->
- {noreply, State}.
-
-%%----------------------------------------------------------%
-%% function : init, terminate
-%% Arguments:
-%%-----------------------------------------------------------
-
-init([Interval, Tdf, Timer]) ->
- {ok, ?get_InitState(Interval, Tdf, Timer)}.
-
-terminate(_Reason, _State) ->
- ok.
-
-%%-----------------------------------------------------------
-%%------------------------ attributes -----------------------
-%%-----------------------------------------------------------
-%%----------------------------------------------------------%
-%% Attribute: '_get_time_interval'
-%% Type : readonly
-%% Returns :
-%%-----------------------------------------------------------
-'_get_time_interval'(_OE_THIS, State) ->
- {reply, ?get_IntervalT(State), State}.
-
-%%-----------------------------------------------------------
-%%------- Exported external functions -----------------------
-%%-----------------------------------------------------------
-%%----------------------------------------------------------%
-%% function : spans
-%% Arguments: Time - UTO
-%% Returns : CosTime::OverLapType - enum()
-%% TIO - out-parameter.
-%%-----------------------------------------------------------
-spans(_OE_THIS, State, Time) ->
- ?time_TypeCheck(Time, 'CosTime_UTO'),
- case catch 'CosTime_UTO':'_get_utc_time'(Time) of
- #'TimeBase_UtcT'{time = Btime, inacclo = InaccL, inacchi=InaccH} ->
- Inaccuarcy = ?concat_TimeT(InaccH, InaccL),
- BL = Btime - Inaccuarcy,
- BU = Btime + Inaccuarcy,
- L = ?get_Lower(State),
- U = ?get_Upper(State),
- {Type, NewL, NewU} =
- if
- L=<BL, U>=BU ->
- {'OTContainer',BL,BU};
- L>=BL, U=<BU ->
- {'OTContained',L,U};
- L<BL, U=<BU, U>=BL ->
- {'OTOverlap',BL,U};
- L>=BL, L=<BU, U>BU ->
- {'OTOverlap',L,BU};
- L>BU ->
- {'OTNoOverlap',BU,L};
- true ->
- {'OTNoOverlap',U,BL}
- end,
- {reply,
- {Type,
- 'CosTime_TIO':oe_create([#'TimeBase_IntervalT'{lower_bound=NewL,
- upper_bound=NewU},
- ?get_Tdf(State),
- ?get_TimerObj(State)],
- [{pseudo,true}|?CREATE_OPTS])},
- State};
- _ ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO})
- end.
-
-
-%%----------------------------------------------------------%
-%% function : overlaps
-%% Arguments: Interval - TIO
-%% Returns : CosTime::OverLapType - enum()
-%% TIO - out-parameter.
-%%-----------------------------------------------------------
-overlaps(_OE_THIS, State, Interval) ->
- ?time_TypeCheck(Interval, 'CosTime_TIO'),
- case catch 'CosTime_TIO':'_get_time_interval'(Interval) of
- #'TimeBase_IntervalT'{lower_bound=BL, upper_bound=BU} ->
- L = ?get_Lower(State),
- U = ?get_Upper(State),
- {Type, NewL, NewU} =
- if
- L=<BL, U>=BU ->
- {'OTContainer',BL,BU};
- L>=BL, U=<BU ->
- {'OTContained',L,U};
- L<BL, U=<BU, U>=BL ->
- {'OTOverlap',BL,U};
- L>=BL, L=<BU, U>BU ->
- {'OTOverlap',L,BU};
- L>BU ->
- {'OTNoOverlap',BU,L};
- true ->
- {'OTNoOverlap',U,BL}
- end,
- {reply,
- {Type,
- 'CosTime_TIO':oe_create([#'TimeBase_IntervalT'{lower_bound=NewL,
- upper_bound=NewU},
- ?get_Tdf(State),
- ?get_TimerObj(State)],
- [{pseudo,true}|?CREATE_OPTS])},
- State};
- _ ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO})
- end.
-
-%%----------------------------------------------------------%
-%% function : time
-%% Arguments: -
-%% Returns : UTO
-%%-----------------------------------------------------------
-time(_OE_THIS, State) ->
- L = ?get_Lower(State),
- H = ?get_Upper(State),
- Utc = #'TimeBase_UtcT'{time=(erlang:trunc(((H-L)/2))+L),
- inacclo=L,
- inacchi=H,
- tdf=?get_Tdf(State)},
- {reply,
- 'CosTime_UTO':oe_create([Utc, ?get_TimerObj(State)], [{pseudo,true}|?CREATE_OPTS]),
- State}.
-
-
-%%--------------- LOCAL FUNCTIONS ----------------------------
-
-%%--------------- MISC FUNCTIONS, E.G. DEBUGGING -------------
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/cosTime/src/CosTime_TimeService_impl.erl b/lib/cosTime/src/CosTime_TimeService_impl.erl
deleted file mode 100644
index 72c65757ad..0000000000
--- a/lib/cosTime/src/CosTime_TimeService_impl.erl
+++ /dev/null
@@ -1,182 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : CosTime_TimeService_impl.erl
-%% Purpose :
-%%----------------------------------------------------------------------
-
--module('CosTime_TimeService_impl').
-
-%%--------------- INCLUDES -----------------------------------
--include("cosTimeApp.hrl").
-
-%%--------------- EXPORTS ------------------------------------
-%%--------------- External -----------------------------------
-%% Interface functions
--export([universal_time/2, secure_universal_time/2, new_universal_time/5]).
--export([uto_from_utc/3, new_interval/4]).
-
-%%--------------- gen_server specific exports ----------------
--export([handle_info/2, code_change/3]).
--export([init/1, terminate/2]).
-
-
-%% Data structures
--record(state,
- {tdf,
- inaccuracy}).
-%% Data structures constructors
--define(get_InitState(T,I),
- #state{tdf = T,
- inaccuracy = I}).
-
-%% Data structures selectors
--define(get_Inaccuracy(S), S#state.inaccuracy).
--define(get_Tdf(S), S#state.tdf).
-
-%% Data structures modifiers
-
-%% MISC
-
-%%-----------------------------------------------------------%
-%% function : handle_info, code_change
-%% Arguments:
-%% Returns :
-%% Effect : Functions demanded by the gen_server module.
-%%------------------------------------------------------------
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-handle_info(_Info, State) ->
- ?debug_print("INFO: ~p~n", [_Info]),
- {noreply, State}.
-
-%%----------------------------------------------------------%
-%% function : init, terminate
-%% Arguments:
-%%-----------------------------------------------------------
-
-init([Tdf, Inaccuracy]) ->
- process_flag(trap_exit, true),
- {ok, ?get_InitState(Tdf, Inaccuracy)}.
-
-terminate(_Reason, _State) ->
- ok.
-
-%%-----------------------------------------------------------
-%%------- Exported external functions -----------------------
-%%-----------------------------------------------------------
-%%----------------------------------------------------------%
-%% function : universal_time
-%% Arguments: -
-%% Returns : CosTime::UTO |
-%% {'EXCEPTION", #'CosTime_TimeUnavailable'{}}
-%% NOTE : cosTime:create_universal_time will raise the correct
-%% exception.
-%%-----------------------------------------------------------
-universal_time(OE_THIS, State) ->
- {ok, Time} = create_universal_time(),
- Inaccuracy = ?get_Inaccuracy(State),
- Utc = #'TimeBase_UtcT'{time=Time, inacclo = ?low_TimeT(Inaccuracy),
- inacchi = ?high_TimeT(Inaccuracy),
- tdf = ?get_Tdf(State)},
- {reply, 'CosTime_UTO':oe_create([Utc, OE_THIS], [{pseudo,true}|?CREATE_OPTS]), State}.
-
-%%----------------------------------------------------------%
-%% function : secure_universal_time
-%% Arguments:
-%% Returns : {'EXCEPTION", #'CosTime_TimeUnavailable'{}}
-%%-----------------------------------------------------------
--spec secure_universal_time(_, _) -> no_return().
-secure_universal_time(_OE_THIS, _State) ->
- corba:raise(#'CosTime_TimeUnavailable'{}).
-
-%%----------------------------------------------------------%
-%% function : new_universal_time
-%% Arguments: Time - TimeBase::TimeT
-%% Inaccuracy - TimeBase::InaccuracyT inaccuracy
-%% Tdf - TimeBase::TdfT
-%% Returns : CosTime::UTO
-%%-----------------------------------------------------------
-new_universal_time(OE_THIS, State, Time, Inaccuracy, Tdf) when
- is_integer(Time) andalso is_integer(Inaccuracy) andalso is_integer(Tdf) andalso
- Tdf=<12 andalso Inaccuracy=<?max_Inaccuracy andalso Time=<?max_TimeT ->
- Utc = #'TimeBase_UtcT'{time=Time, inacclo = ?low_TimeT(Inaccuracy),
- inacchi = ?high_TimeT(Inaccuracy), tdf = Tdf},
- {reply, 'CosTime_UTO':oe_create([Utc, OE_THIS], [{pseudo,true}|?CREATE_OPTS]), State};
-new_universal_time(_, _, _, _, _) ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------%
-%% function : uto_from_utc
-%% Arguments: Utc - TimeBase::UtcT
-%% Returns : CosTime::UTO
-%%-----------------------------------------------------------
-uto_from_utc(OE_THIS, State, Utc) when is_record(Utc, 'TimeBase_UtcT') ->
- {reply, 'CosTime_UTO':oe_create([Utc, OE_THIS],[{pseudo,true}|?CREATE_OPTS]),State};
-uto_from_utc(_, _, _) ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------%
-%% function : new_interval
-%% Arguments: Lower - TimeBase::TimeT
-%% Upper - TimeBase::TimeT
-%% Returns : CosTime::TIO
-%%-----------------------------------------------------------
-new_interval(OE_THIS, State, Lower, Upper) when is_integer(Lower) andalso is_integer(Upper) andalso
- Lower=<Upper ->
- {reply, 'CosTime_TIO':oe_create([#'TimeBase_IntervalT'{lower_bound=Lower,
- upper_bound=Upper},
- ?get_Tdf(State),
- OE_THIS],
- [{pseudo,true}|?CREATE_OPTS]), State};
-new_interval(_, _, _, _) ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-
-%%--------------- LOCAL FUNCTIONS ----------------------------
-%%-----------------------------------------------------------%
-%% function : create_universal_utc
-%% Arguments: -
-%% Returns : TimeT or raises exception.
-%% Effect : Creates a universal time; if time unavailable we
-%% must raise CosTime_TimeUnavailable.
-%% NOTE : 'datetime_to_gregorian_seconds' use year 0 as time
-%% base. We want to use 15 october 1582, 00:00 as base.
-%%------------------------------------------------------------
-
-create_universal_time() ->
- %% Time is supposed to be #100 nano-secs passed.
- %% We add micro secs for a greater precision.
- {MS,S,US} = erlang:timestamp(),
- case catch calendar:datetime_to_gregorian_seconds(
- calendar:now_to_universal_time({MS,S,US})) of
- Secs when is_integer(Secs) ->
- {ok, (Secs-?ABSOLUTE_TIME_DIFF)*10000000 + US*10};
- _ ->
- corba:raise(#'CosTime_TimeUnavailable'{})
- end.
-
-%%--------------- MISC FUNCTIONS, E.G. DEBUGGING -------------
-%%--------------- END OF MODULE ------------------------------
-
diff --git a/lib/cosTime/src/CosTime_UTO_impl.erl b/lib/cosTime/src/CosTime_UTO_impl.erl
deleted file mode 100644
index 09f3eb2fdb..0000000000
--- a/lib/cosTime/src/CosTime_UTO_impl.erl
+++ /dev/null
@@ -1,242 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : CosTime_UTO_impl.erl
-%% Purpose :
-%%----------------------------------------------------------------------
-
--module('CosTime_UTO_impl').
-
-%%--------------- INCLUDES -----------------------------------
--include("cosTimeApp.hrl").
-
-
-%%--------------- EXPORTS ------------------------------------
-%%--------------- External -----------------------------------
-%% Attributes (external)
--export(['_get_time'/2,
- '_get_inaccuracy'/2,
- '_get_tdf'/2,
- '_get_utc_time'/2]).
-
-%% Interface functions
--export([absolute_time/2, compare_time/4]).
--export([time_to_interval/3, interval/2]).
-
-%%--------------- gen_server specific exports ----------------
--export([handle_info/2, code_change/3]).
--export([init/1, terminate/2]).
-
-
-%% Data structures
--record(state, {timer, utc}).
-%% Data structures constructors
--define(get_InitState(U, T), #state{timer = T, utc = U}).
-
-%% Data structures selectors
--define(get_Time(S), (S#state.utc)#'TimeBase_UtcT'.time).
--define(get_Inaccuracy(S), ?concat_TimeT((S#state.utc)#'TimeBase_UtcT'.inacchi,
- (S#state.utc)#'TimeBase_UtcT'.inacclo)).
--define(get_Tdf(S), (S#state.utc)#'TimeBase_UtcT'.tdf).
--define(get_Utc(S), S#state.utc).
--define(get_TimeObj(S), S#state.timer).
-
-
-%%-----------------------------------------------------------%
-%% function : handle_info, code_change
-%% Arguments:
-%% Returns :
-%% Effect : Functions demanded by the gen_server module.
-%%------------------------------------------------------------
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-handle_info(_Info, State) ->
- {noreply, State}.
-
-%%----------------------------------------------------------%
-%% function : init, terminate
-%% Arguments:
-%%-----------------------------------------------------------
-
-init([Utc, TimeObj]) ->
- {ok, ?get_InitState(Utc, TimeObj)}.
-
-terminate(_Reason, _State) ->
- ok.
-
-%%-----------------------------------------------------------
-%%------------------------ attributes -----------------------
-%%-----------------------------------------------------------
-%%----------------------------------------------------------%
-%% Attribute: '_get_time'
-%% Type : readonly
-%% Returns :
-%%-----------------------------------------------------------
-'_get_time'(_OE_THIS, State) ->
- {reply, ?get_Time(State), State}.
-
-%%----------------------------------------------------------%
-%% Attribute: '_get_inaccuracy'
-%% Type : readonly
-%% Returns :
-%%-----------------------------------------------------------
-'_get_inaccuracy'(_OE_THIS, State) ->
- {reply, ?get_Inaccuracy(State), State}.
-
-%%----------------------------------------------------------%
-%% Attribute: '_get_tdf'
-%% Type : readonly
-%% Returns :
-%%-----------------------------------------------------------
-'_get_tdf'(_OE_THIS, State) ->
- {reply, ?get_Tdf(State), State}.
-
-%%----------------------------------------------------------%
-%% Attribute: '_get_utc_time'
-%% Type : readonly
-%% Returns :
-%%-----------------------------------------------------------
-'_get_utc_time'(_OE_THIS, State) ->
- {reply, ?get_Utc(State), State}.
-
-%%-----------------------------------------------------------
-%%------- Exported external functions -----------------------
-%%-----------------------------------------------------------
-%%----------------------------------------------------------%
-%% function : absolute_time
-%% Arguments: -
-%% Returns : UTO
-%% NOTE : Return the base time to the relative time in the object.
-%%-----------------------------------------------------------
-absolute_time(_OE_THIS, State) ->
- case catch 'CosTime_UTO':'_get_time'(
- 'CosTime_TimeService':universal_time(?get_TimeObj(State)))+
- ?get_Time(State) of
- UniTime when is_integer(UniTime) andalso UniTime =< ?max_TimeT ->
- Utc=?get_Utc(State),
- {reply, 'CosTime_UTO':oe_create([Utc#'TimeBase_UtcT'{time=UniTime},
- ?get_TimeObj(State)],
- [{pseudo,true}|?CREATE_OPTS]), State};
- UniTime when is_integer(UniTime) ->
- %% Oopss, overflow!
- corba:raise(#'DATA_CONVERSION'{completion_status=?COMPLETED_NO});
- _ ->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-%%----------------------------------------------------------%
-%% function : compare_time
-%% Arguments: Comparison_type - CosTime::ComparisonType
-%% Uto - ObjRef
-%% Returns : TimeComparison - 'TCEqualTo' | 'TCLessThan' |
-%% 'TCGreaterThan' | 'TCIndeterminate'
-%%-----------------------------------------------------------
-compare_time(_OE_THIS, State, 'IntervalC', Uto) ->
- ?time_TypeCheck(Uto, 'CosTime_UTO'),
- case catch {'CosTime_UTO':'_get_time'(Uto),
- 'CosTime_UTO':'_get_inaccuracy'(Uto)} of
- {Time,Inaccuracy} when is_integer(Time) andalso is_integer(Inaccuracy) ->
- OwnInacc = ?get_Inaccuracy(State),
- if
- ?get_Time(State)+OwnInacc < Time-Inaccuracy ->
- {reply, 'TCLessThan', State};
- ?get_Time(State)-OwnInacc > Time+Inaccuracy ->
- {reply, 'TCGreaterThan', State};
- ?get_Time(State) == Time, Inaccuracy==0, OwnInacc==0 ->
- %% TimeService specification (july 1997, p14-7:2) states
- %% that they are only equal if both UTO's Inaccuracy
- %% equals zero.
- {reply, 'TCEqualTo', State};
- true ->
- {reply, 'TCIndeterminate', State}
- end;
- _ ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO})
- end;
-compare_time(_OE_THIS, State, 'MidC', Uto) ->
- ?time_TypeCheck(Uto, 'CosTime_UTO'),
- case catch 'CosTime_UTO':'_get_time'(Uto) of
- Time when is_integer(Time) ->
- if
- ?get_Time(State) < Time ->
- {reply, 'TCLessThan', State};
- ?get_Time(State) > Time ->
- {reply, 'TCGreaterThan', State};
- true ->
- {reply, 'TCEqualTo', State}
- end;
- _ ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO})
- end;
-compare_time(_OE_THIS, _State, _, _) ->
- %% Comparison_type given not correct?!
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------%
-%% function : time_to_interval
-%% Arguments:
-%% Returns : TIO
-%%-----------------------------------------------------------
-time_to_interval(_OE_THIS, State, Uto) ->
- ?time_TypeCheck(Uto, 'CosTime_UTO'),
- case catch 'CosTime_UTO':'_get_time'(Uto) of
- Time when is_integer(Time) ->
- OwnTime = ?get_Time(State),
- if
- Time > OwnTime ->
- {reply, 'CosTime_TIO':oe_create([#'TimeBase_IntervalT'{lower_bound=OwnTime,
- upper_bound=Time},
- ?get_Tdf(State),
- ?get_TimeObj(State)],
- [{pseudo,true}|?CREATE_OPTS]), State};
- true ->
- {reply, 'CosTime_TIO':oe_create([#'TimeBase_IntervalT'{lower_bound=Time,
- upper_bound=OwnTime},
- ?get_Tdf(State),
- ?get_TimeObj(State)],
- [{pseudo,true}|?CREATE_OPTS]), State}
- end;
- _ ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO})
- end.
-
-%%----------------------------------------------------------%
-%% function : interval
-%% Arguments:
-%% Returns : TIO
-%%-----------------------------------------------------------
-interval(_OE_THIS, State) ->
- Lower = ?get_Time(State) - ?get_Inaccuracy(State),
- Upper = ?get_Time(State) + ?get_Inaccuracy(State),
- {reply, 'CosTime_TIO':oe_create([#'TimeBase_IntervalT'{lower_bound=Lower,
- upper_bound=Upper},
- ?get_Tdf(State),
- ?get_TimeObj(State)],
- [{pseudo,true}|?CREATE_OPTS]), State}.
-
-
-%%--------------- LOCAL FUNCTIONS ----------------------------
-
-%%--------------- MISC FUNCTIONS, E.G. DEBUGGING -------------
-%%--------------- END OF MODULE ------------------------------
-
diff --git a/lib/cosTime/src/CosTimerEvent.cfg b/lib/cosTime/src/CosTimerEvent.cfg
deleted file mode 100644
index 7f16197168..0000000000
--- a/lib/cosTime/src/CosTimerEvent.cfg
+++ /dev/null
@@ -1,4 +0,0 @@
-{this, "CosTimerEvent::TimerEventHandler"}.
-{{handle_info, "CosTimerEvent::TimerEventHandler"}, true}.
-{this, "CosTimerEvent::TimerEventService"}.
-{{handle_info, "CosTimerEvent::TimerEventService"}, true}.
diff --git a/lib/cosTime/src/CosTimerEvent.idl b/lib/cosTime/src/CosTimerEvent.idl
deleted file mode 100644
index b845862f98..0000000000
--- a/lib/cosTime/src/CosTimerEvent.idl
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef _COS_TIMEREVENT_IDL_
-#define _COS_TIMEREVENT_IDL_
-
-#pragma prefix "omg.org"
-
-#include"CosEventComm.idl"
-#include<CosTime.idl>
-#include<TimeBase.idl>
-
-module CosTimerEvent{
-
- enum TimeType {
- TTAbsolute,
- TTRelative,
- TTPeriodic
- };
- enum EventStatus {
- ESTimeSet,
- ESTimeCleared,
- ESTriggered,
- ESFailedTrigger
- };
-
- struct TimerEventT {
- TimeBase::UtcT utc;
- any event_data;
- };
-
- interface TimerEventHandler {
- readonly attribute EventStatus status;
- boolean time_set( out CosTime::UTO uto );
- void set_timer( in TimeType time_type, in CosTime::UTO trigger_time );
- boolean cancel_timer();
- void set_data( in any event_data );
- };
-
- interface TimerEventService {
-
- TimerEventHandler register( in CosEventComm::PushConsumer event_interface, in any data );
- void unregister( in TimerEventHandler timer_event_handler );
- CosTime::UTO event_time( in TimerEventT timer_event );
- };
-};
-
-#endif
diff --git a/lib/cosTime/src/CosTimerEvent_TimerEventHandler_impl.erl b/lib/cosTime/src/CosTimerEvent_TimerEventHandler_impl.erl
deleted file mode 100644
index 5bc751dfb1..0000000000
--- a/lib/cosTime/src/CosTimerEvent_TimerEventHandler_impl.erl
+++ /dev/null
@@ -1,305 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : CosTimerEvent_TimerEventHandler_impl.erl
-%% Purpose :
-%%----------------------------------------------------------------------
-
--module('CosTimerEvent_TimerEventHandler_impl').
-
-%%--------------- INCLUDES -----------------------------------
--include("cosTimeApp.hrl").
-
-
-%%--------------- EXPORTS ------------------------------------
-%%--------------- External -----------------------------------
-%% Attributes (external)
--export(['_get_status'/2]).
-%% Interface functions
--export([time_set/2, set_timer/4]).
--export([cancel_timer/2, set_data/3]).
-
-%%--------------- gen_server specific exports ----------------
--export([handle_info/2, code_change/3]).
--export([init/1, terminate/2]).
-
-
-%% Data structures
--record(state, {parent,
- parentPid,
- event,
- status = 'ESTimeCleared',
- timer,
- time,
- timeObj,
- myType,
- pushConsumer,
- uto}).
-%% Data structures constructors
--define(get_InitState(P,PP,E,PC,TO),
- #state{parent=P,
- parentPid=PP,
- event=E,
- pushConsumer=PC,
- timeObj=TO}).
-
-%% Data structures selectors
--define(get_Status(S), S#state.status).
--define(get_ParentPid(S), S#state.parentPid).
--define(get_Parent(S), S#state.parent).
--define(get_Event(S), S#state.event).
--define(get_Timer(S), S#state.timer).
--define(get_Time(S), S#state.time).
--define(get_TimeObj(S), S#state.timeObj).
--define(get_MyType(S), S#state.myType).
--define(get_PushConsumer(S), S#state.pushConsumer).
--define(get_Uto(S), S#state.uto).
-
-%% Data structures modifiers
--define(set_Status(S,V), S#state{status=V}).
--define(set_ParentPid(S,PP), S#state{parentPid=PP}).
--define(set_Parent(S,P), S#state{parent=P}).
--define(set_Event(S,E), S#state{event=E}).
--define(set_Timer(S,T), S#state{timer=T}).
--define(set_Time(S,T), S#state{time=T}).
--define(set_MyType(S,Ty), S#state{myType=Ty}).
--define(set_PushConsumer(S,P), S#state{pushConsumer=P}).
--define(set_Uto(S,U,Type), S#state{uto=U, myType=Type}).
--define(set_TimeData(S,U,Ty,Ti),S#state{uto=U, myType=Ty, time=Ti}).
-
-%% MISC
--define(not_Cancelled(S), S#state.status =/= 'ESTimeCleared').
--define(is_TimeSet(S), S#state.status == 'ESTimeSet').
--define(is_UtoSet(S), S#state.uto =/= undefined).
--define(is_NotAbsolute(S), S#state.myType =/= 'TTAbsolute').
-
-%%-----------------------------------------------------------%
-%% function : handle_info, code_change
-%% Arguments:
-%% Returns :
-%% Effect : Functions demanded by the gen_server module.
-%%------------------------------------------------------------
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-handle_info(Info, State) ->
- ?debug_print("INFO: ~p~n", [Info]),
- case Info of
- {'EXIT', Pid, _Reason} when Pid == ?get_ParentPid(State) ->
- ?debug_print("PARENT TERMINATED with reason: ~p~n",[_Reason]),
- {noreply, State};
- oe_event when ?not_Cancelled(State) ->
- %% Push event
- case catch 'CosEventComm_PushConsumer':push(?get_PushConsumer(State),
- ?get_Event(State)) of
- ok ->
- ?debug_print("PUSHED: ~p~n", [?get_Event(State)]),
- {noreply, ?set_Status(State, 'ESTriggered')};
- _Other->
- ?debug_print("FAILED PUSH: ~p ~p~n", [?get_Event(State), _Other]),
- {noreply, ?set_Status(State, 'ESFailedTrigger')}
- end;
- oe_periodic_event when ?not_Cancelled(State) ->
- %% Push event
- catch 'CosEventComm_PushConsumer':push(?get_PushConsumer(State),
- ?get_Event(State)),
- {noreply, State};
- _ ->
- {noreply, State}
- end.
-
-%%----------------------------------------------------------%
-%% function : init, terminate
-%% Arguments:
-%%-----------------------------------------------------------
-
-init([Parent, ParentPid, PushConsumer, Event, TimeObj]) ->
- process_flag(trap_exit, true),
- {ok, ?get_InitState(Parent, ParentPid, Event, PushConsumer, TimeObj)}.
-
-terminate(_Reason, State) ->
- clear_timer(State),
- ok.
-
-%%-----------------------------------------------------------
-%%------------------------ attributes -----------------------
-%%-----------------------------------------------------------
-%%----------------------------------------------------------%
-%% Attribute: '_get_status'
-%% Type : readonly
-%% Returns : 'ESTimeSet' | 'ESTimeCleared' | 'ESTriggered' |
-%% 'ESFailedTrigger'
-%%-----------------------------------------------------------
-'_get_status'(_OE_THIS, State) ->
- {reply, ?get_Status(State), State}.
-
-%%-----------------------------------------------------------
-%%------- Exported external functions -----------------------
-%%-----------------------------------------------------------
-%%----------------------------------------------------------%
-%% function : time_set
-%% Arguments: -
-%% Returns : {boolean(), CosTime::UTO}
-%%-----------------------------------------------------------
-time_set(_OE_THIS, State) when ?is_UtoSet(State) ->
- {reply, {?is_TimeSet(State), ?get_Uto(State)}, State};
-time_set(_OE_THIS, State) ->
- Utc = #'TimeBase_UtcT'{time=0, inacclo = 0,inacchi = 0, tdf = 0},
- {reply,
- {?is_TimeSet(State),
- 'CosTime_UTO':oe_create([Utc, ?get_TimeObj(State)], [{pseudo,true}|?CREATE_OPTS])},
- State}.
-
-
-%%-----------------------------------------------------------
-%% function : set_timer
-%% Arguments: TimeType - 'TTAbsolute' | 'TTRelative' | 'TTPeriodic'
-%% TriggerTime - CosTime::UTO
-%% Returns : ok
-%%-----------------------------------------------------------
-set_timer(_OE_THIS, State, 'TTAbsolute', TriggerTime) ->
- NewState = clear_timer(State),
- ?time_TypeCheck(TriggerTime, 'CosTime_UTO'),
- case catch {'CosTime_UTO':'_get_time'(TriggerTime),
- 'CosTime_UTO':'_get_time'(
- 'CosTime_TimeService':universal_time(?get_TimeObj(State)))} of
- {Time, CurrentTime} when is_integer(Time) andalso is_integer(CurrentTime) andalso
- Time > CurrentTime ->
- %% Set a timer to send a message in (Time-CurrentTime)*10^-7 secs.
- case timer:send_after(?convert_TimeT2TimerT(Time-CurrentTime), oe_event) of
- {ok, TRef} ->
- NewState1 = ?set_Timer(NewState, TRef),
- NewState2 = ?set_Uto(NewState1, TriggerTime, 'TTAbsolute'),
- ?debug_print("TIMER SET: ~p~n", [?convert_TimeT2TimerT(Time-CurrentTime)]),
- {reply, ok, ?set_Status(NewState2, 'ESTimeSet')};
- _->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end;
- {Time, CurrentTime} when is_integer(Time) andalso is_integer(CurrentTime) ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO});
- _->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end;
-set_timer(_OE_THIS, State, 'TTRelative', TriggerTime) ->
- NewState = clear_timer(State),
- ?time_TypeCheck(TriggerTime, 'CosTime_UTO'),
- case catch {'CosTime_UTO':'_get_time'(TriggerTime), ?get_Time(State)} of
- {0,OldTime} when ?is_NotAbsolute(NewState) andalso is_integer(OldTime) ->
- %% Set a timer to send a message within Time*10^-7 secs
- case timer:send_after(OldTime, oe_event) of
- {ok, TRef} ->
- NewState1 = ?set_Timer(NewState, TRef),
- NewState2 = ?set_Uto(NewState1, TriggerTime, 'TTRelative'),
- ?debug_print("TIMER SET: ~p~n", [?convert_TimeT2TimerT(OldTime)]),
- {reply, ok, ?set_Status(NewState2, 'ESTimeSet')};
- _->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end;
- {UtoTime,_} when is_integer(UtoTime) ->
- %% Set a timer to send a message within Time*10^-7 secs
- Time = ?convert_TimeT2TimerT(UtoTime),
- case timer:send_after(Time, oe_event) of
- {ok, TRef} ->
- NewState1 = ?set_Timer(NewState, TRef),
- NewState2 = ?set_TimeData(NewState1, TriggerTime,
- 'TTRelative', Time),
- ?debug_print("TIMER SET: ~p~n", [?convert_TimeT2TimerT(Time)]),
- {reply, ok, ?set_Status(NewState2, 'ESTimeSet')};
- _->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end;
-
- _->
- {reply, {'EXCEPTION', #'BAD_PARAM'{completion_status=?COMPLETED_NO}}, NewState}
- end;
-set_timer(_OE_THIS, State, 'TTPeriodic', TriggerTime) ->
- NewState = clear_timer(State),
- ?time_TypeCheck(TriggerTime, 'CosTime_UTO'),
- case catch {'CosTime_UTO':'_get_time'(TriggerTime), ?get_Time(State)} of
- {0,OldTime} when ?is_NotAbsolute(NewState) andalso is_integer(OldTime) ->
- %% Set a timer to send a message within Time*10^-7 secs
- case timer:send_interval(OldTime, oe_periodic_event) of
- {ok, TRef} ->
- NewState1 = ?set_Timer(NewState, TRef),
- NewState2 = ?set_Uto(NewState1, TriggerTime, 'TTPeriodic'),
- ?debug_print("TIMER SET: ~p~n", [?convert_TimeT2TimerT(OldTime)]),
- {reply, ok, ?set_Status(NewState2, 'ESTimeSet')};
- _->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end;
- {UtoTime,_} when is_integer(UtoTime) ->
- %% Set a timer to send a message within Time*10^-7 secs
- Time = ?convert_TimeT2TimerT(UtoTime),
- case timer:send_interval(Time, oe_periodic_event) of
- {ok, TRef} ->
- NewState1 = ?set_Timer(NewState, TRef),
- NewState2 = ?set_TimeData(NewState1, TriggerTime,
- 'TTPeriodic', Time),
- ?debug_print("TIMER SET: ~p~n", [?convert_TimeT2TimerT(Time)]),
- {reply, ok, ?set_Status(NewState2, 'ESTimeSet')};
- _->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end;
-
- _->
- {reply, {'EXCEPTION', #'BAD_PARAM'{completion_status=?COMPLETED_NO}}, NewState}
- end;
-set_timer(_OE_THIS, _State, _, _) ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------%
-%% function : cancel_timer
-%% Arguments: -
-%% Returns : boolean()
-%%-----------------------------------------------------------
-cancel_timer(_OE_THIS, State) ->
- NewState=clear_timer(State),
- case ?get_Status(NewState) of
- 'ESTriggered' ->
- {reply, false, NewState};
- 'ESFailedTrigger' ->
- {reply, false, NewState};
- _ ->
- {reply, true, ?set_Status(NewState, 'ESTimeCleared')}
- end.
-
-%%----------------------------------------------------------%
-%% function : set_data
-%% Arguments: EventData - any#
-%% Returns : ok
-%%-----------------------------------------------------------
-set_data(_OE_THIS, State, EventData) when is_record(EventData, any) ->
- {reply, ok, ?set_Event(State, EventData)};
-set_data(_OE_THIS, _State, _EventData) ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-
-%%--------------- LOCAL FUNCTIONS ----------------------------
-clear_timer(State) when ?get_Timer(State) == undefined ->
- State;
-clear_timer(State) ->
- catch timer:cancel(?get_Timer(State)),
- ?set_Timer(State, undefined).
-
-%%--------------- MISC FUNCTIONS, E.G. DEBUGGING -------------
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/cosTime/src/CosTimerEvent_TimerEventService_impl.erl b/lib/cosTime/src/CosTimerEvent_TimerEventService_impl.erl
deleted file mode 100644
index 59552e4b1b..0000000000
--- a/lib/cosTime/src/CosTimerEvent_TimerEventService_impl.erl
+++ /dev/null
@@ -1,119 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : CosTimerEvent_TimerEventService_impl.erl
-%% Purpose :
-%%----------------------------------------------------------------------
-
--module('CosTimerEvent_TimerEventService_impl').
-
-%%--------------- INCLUDES -----------------------------------
--include("cosTimeApp.hrl").
-
-
-%%--------------- EXPORTS ------------------------------------
-%%--------------- External -----------------------------------
-%% Interface functions
--export([register/4, unregister/3, event_time/3]).
-
-%%--------------- gen_server specific exports ----------------
--export([handle_info/2, code_change/3]).
--export([init/1, terminate/2]).
-
-
-%% Data structures
--record(state, {timer}).
-%% Data structures constructors
--define(get_InitState(T),
- #state{timer=T}).
-
-%% Data structures selectors
--define(get_TimerObj(S), S#state.timer).
-
-%% Data structures modifiers
-
-%% MISC
-
-%%-----------------------------------------------------------%
-%% function : handle_info, code_change
-%% Arguments:
-%% Returns :
-%% Effect : Functions demanded by the gen_server module.
-%%------------------------------------------------------------
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-handle_info(_Info, State) ->
- ?debug_print("INFO: ~p~n", [_Info]),
- {noreply, State}.
-
-%%----------------------------------------------------------%
-%% function : init, terminate
-%% Arguments:
-%%-----------------------------------------------------------
-
-init([Timer]) ->
- process_flag(trap_exit, true),
- timer:start(),
- {ok, ?get_InitState(Timer)}.
-
-terminate(_Reason, _State) ->
- ok.
-
-%%-----------------------------------------------------------
-%%------- Exported external functions -----------------------
-%%-----------------------------------------------------------
-%%----------------------------------------------------------%
-%% function : register
-%% Arguments: EventInterface - CosEventComm::PushConsumer
-%% Data - #any
-%% Returns : TimerEventHandler - objref#
-%%-----------------------------------------------------------
-register(OE_THIS, State, EventInterface, Data) ->
- {reply,
- cosTime:start_event_handler([OE_THIS, self(),EventInterface, Data,
- ?get_TimerObj(State)]),
- State}.
-
-%%----------------------------------------------------------%
-%% function : unregister
-%% Arguments: TimerEventHandler - objref#
-%% Returns : ok
-%%-----------------------------------------------------------
-unregister(_OE_THIS, State, TimerEventHandler) ->
- catch corba:dispose(TimerEventHandler),
- {reply, ok, State}.
-
-%%----------------------------------------------------------%
-%% function : event_time
-%% Arguments: TimerEvent - #'CosTimerEvent_TimerEventT'{utc, event_data}
-%% Returns : CosTime::UTO
-%%-----------------------------------------------------------
-event_time(_OE_THIS, State, #'CosTimerEvent_TimerEventT'{utc=Utc}) ->
- {reply, 'CosTime_UTO':oe_create([Utc],[{pseudo,true}]), State}.
-
-
-%%--------------- LOCAL FUNCTIONS ----------------------------
-
-%%--------------- MISC FUNCTIONS, E.G. DEBUGGING -------------
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/cosTime/src/Makefile b/lib/cosTime/src/Makefile
deleted file mode 100644
index 55d59baea3..0000000000
--- a/lib/cosTime/src/Makefile
+++ /dev/null
@@ -1,207 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2000-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-
-ifeq ($(TYPE),debug)
-ERL_COMPILE_FLAGS += -Ddebug -W
-endif
-
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(COSTIME_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/cosTime-$(VSN)
-
-EXTERNAL_INC_PATH = ../include
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-
-MODULES = \
- cosTime \
- CosTime_TIO_impl \
- CosTime_TimeService_impl \
- CosTime_UTO_impl \
- CosTimerEvent_TimerEventHandler_impl \
- CosTimerEvent_TimerEventService_impl \
-
-ERL_FILES = $(MODULES:%=%.erl)
-HRL_FILES = \
- cosTimeApp.hrl \
-
-GEN_TIMEBASE_ERL_FILES = \
- oe_TimeBase.erl \
- TimeBase_IntervalT.erl \
- TimeBase_UtcT.erl
-
-GEN_COSTIME_ERL_FILES = \
- oe_CosTime.erl \
- CosTime_TIO.erl \
- CosTime_TimeService.erl \
- CosTime_TimeUnavailable.erl \
- CosTime_UTO.erl \
-
-GEN_COSTIMEREVENT_ERL_FILES = \
- oe_CosTimerEvent.erl \
- CosTimerEvent_TimerEventHandler.erl \
- CosTimerEvent_TimerEventService.erl \
- CosTimerEvent_TimerEventT.erl \
-
-GEN_TIMEBASE_HRL_FILES = \
- oe_TimeBase.hrl \
- TimeBase.hrl \
-
-EXTERNAL_TIMEBASE_HRL_FILES = $(GEN_TIMEBASE_HRL_FILES:%=$(EXTERNAL_INC_PATH)/%)
-
-GEN_COSTIME_HRL_FILES = \
- oe_CosTime.hrl \
- CosTime.hrl \
- CosTime_TIO.hrl \
- CosTime_TimeService.hrl \
- CosTime_UTO.hrl
-
-EXTERNAL_COSTIME_HRL_FILES = $(GEN_COSTIME_HRL_FILES:%=$(EXTERNAL_INC_PATH)/%)
-
-GEN_COSTIMEREVENT_HRL_FILES = \
- oe_CosTimerEvent.hrl \
- CosTimerEvent.hrl \
- CosTimerEvent_TimerEventHandler.hrl \
- CosTimerEvent_TimerEventService.hrl \
-
-EXTERNAL_COSTIMEREVENT_HRL_FILES = $(GEN_COSTIMEREVENT_HRL_FILES:%=$(EXTERNAL_INC_PATH)/%)
-
-
-GEN_ERL_FILES = \
- $(GEN_TIMEBASE_ERL_FILES) \
- $(GEN_COSTIME_ERL_FILES) \
- $(GEN_COSTIMEREVENT_ERL_FILES)
-
-GEN_HRL_FILES = \
- $(EXTERNAL_TIMEBASE_HRL_FILES) \
- $(EXTERNAL_COSTIME_HRL_FILES) \
- $(EXTERNAL_COSTIMEREVENT_HRL_FILES) \
-
-GEN_FILES = \
- $(GEN_HRL_FILES) \
- $(GEN_ERL_FILES)
-
-TARGET_FILES = \
- $(GEN_TIMEBASE_ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR)) \
- $(GEN_COSTIME_ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR)) \
- $(GEN_COSTIMEREVENT_ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR)) \
- $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-
-IDL_FILES = \
- TimeBase.idl \
- CosTime.idl \
- CosTimerEvent.idl
-
-APPUP_FILE = cosTime.appup
-APPUP_SRC = $(APPUP_FILE).src
-APPUP_TARGET = $(EBIN)/$(APPUP_FILE)
-
-APP_FILE = cosTime.app
-APP_SRC = $(APP_FILE).src
-APP_TARGET = $(EBIN)/$(APP_FILE)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_IDL_FLAGS += -pa $(ERL_TOP)/lib/cosTime/ebin \
- -pa $(ERL_TOP)/lib/ic/ebin\
- -pa $(ERL_TOP)/lib/orber/ebin \
- -I$(ERL_TOP)/lib/cosEvent/src
-
-# The -pa option is just used temporary until erlc can handle
-# includes from other directories than ../include .
-ERL_COMPILE_FLAGS += \
- $(ERL_IDL_FLAGS) \
- -pa $(ERL_TOP)/lib/orber/include \
- -pa $(ERL_TOP)/lib/cosTime/include \
- -I$(ERL_TOP)/lib/cosTime/include \
- -I$(ERL_TOP)/lib/orber/include \
- +'{parse_transform,sys_pre_attributes}' \
- +'{attribute,insert,app_vsn,"cosTime_$(COSTIME_VSN)"}'
-
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
-
-debug:
- @${MAKE} TYPE=debug opt
-
-cleanb:
- rm -f $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
- rm -f errs core *~
-
-clean:
- rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET) IDL-GENERATED
- rm -f errs core *~
-
-$(APP_TARGET): $(APP_SRC)
- $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
-
-$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
-
-docs:
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-IDL-GENERATED: TimeBase.idl CosTime.idl CosTimerEvent.idl
- $(gen_verbose)erlc $(ERL_IDL_FLAGS) TimeBase.idl
- $(V_at)mv $(GEN_TIMEBASE_HRL_FILES) $(EXTERNAL_INC_PATH)
- $(V_at)erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosTime.cfg"}' CosTime.idl
- $(V_at)mv $(GEN_COSTIME_HRL_FILES) $(EXTERNAL_INC_PATH)
- $(V_at)erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosTimerEvent.cfg"}' CosTimerEvent.idl
- $(V_at)mv $(GEN_COSTIMEREVENT_HRL_FILES) $(EXTERNAL_INC_PATH)
- $(V_at)>IDL-GENERATED
-
-$(GEN_FILES): IDL-GENERATED
-
-$(TARGET_FILES): IDL-GENERATED
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
- $(INSTALL_DIR) "$(RELSYSDIR)/src"
- $(INSTALL_DATA) $(GEN_FILES) $(IDL_FILES) "$(RELSYSDIR)/src"
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(GEN_ERL_FILES) $(IDL_FILES) "$(RELSYSDIR)/src"
- $(INSTALL_DIR) "$(RELSYSDIR)/include"
- $(INSTALL_DATA) $(GEN_HRL_FILES) "$(RELSYSDIR)/include"
-
-release_docs_spec:
diff --git a/lib/cosTime/src/TimeBase.idl b/lib/cosTime/src/TimeBase.idl
deleted file mode 100644
index 92a0c652d8..0000000000
--- a/lib/cosTime/src/TimeBase.idl
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef _TIMEBASE_IDL_
-#define _TIMEBASE_IDL_
-
-#pragma prefix "omg.org"
-
-module TimeBase {
- typedef unsigned long long TimeT;
- typedef TimeT InaccuracyT;
- typedef short TdfT;
- struct UtcT {
- TimeT time; // 8 octets
- unsigned long inacclo; // 4 octets
- unsigned short inacchi; // 2 octets
- TdfT tdf; // 2 octets // total 16 octets.
- };
- struct IntervalT {
- TimeT lower_bound;
- TimeT upper_bound;
- };
-};
-
-#endif
diff --git a/lib/cosTime/src/cosTime.app.src b/lib/cosTime/src/cosTime.app.src
deleted file mode 100644
index ac71fe1b29..0000000000
--- a/lib/cosTime/src/cosTime.app.src
+++ /dev/null
@@ -1,32 +0,0 @@
-{application, cosTime,
- [{description, "The Erlang CosTime application"},
- {vsn, "%VSN%"},
- {modules,
- [
- 'cosTime',
- 'oe_TimeBase',
- 'oe_CosTime',
- 'oe_CosTimerEvent',
- 'CosTime_TIO',
- 'CosTime_TimeService',
- 'CosTime_TimeUnavailable',
- 'CosTime_UTO',
- 'CosTimerEvent_TimerEventHandler',
- 'CosTimerEvent_TimerEventService',
- 'CosTimerEvent_TimerEventT',
- 'TimeBase_IntervalT',
- 'TimeBase_UtcT',
- 'CosTime_TIO_impl',
- 'CosTime_TimeService_impl',
- 'CosTime_UTO_impl',
- 'CosTimerEvent_TimerEventHandler_impl',
- 'CosTimerEvent_TimerEventService_impl'
- ]
- },
- {registered, [oe_cosTimeSup, oe_cosTimerEventService]},
- {applications, [orber, stdlib, kernel]},
- {env, []},
- {mod, {cosTime, []}},
- {runtime_dependencies, ["stdlib-2.0","orber-3.6.27","kernel-3.0","erts-7.0",
- "cosEvent-2.1.15"]}
-]}.
diff --git a/lib/cosTime/src/cosTime.appup.src b/lib/cosTime/src/cosTime.appup.src
deleted file mode 100644
index f3eead4a0c..0000000000
--- a/lib/cosTime/src/cosTime.appup.src
+++ /dev/null
@@ -1,6 +0,0 @@
-{"%VSN%",
- [
- ],
- [
- ]
-}.
diff --git a/lib/cosTime/src/cosTime.erl b/lib/cosTime/src/cosTime.erl
deleted file mode 100644
index a32e210a26..0000000000
--- a/lib/cosTime/src/cosTime.erl
+++ /dev/null
@@ -1,343 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : cosTime.erl
-%% Purpose :
-%%----------------------------------------------------------------------
-
--module(cosTime).
-
-%%--------------- INCLUDES -----------------------------------
--include("cosTimeApp.hrl").
-
-%%--------------- EXPORTS-------------------------------------
-%% cosTime API external
--export([start/0, stop/0,
- install_time/0, uninstall_time/0,
- install_timerevent/0, uninstall_timerevent/0,
- start_time_service/2, start_timerevent_service/1, stop_timerevent_service/1,
- stop_time_service/1]).
-
-%% cosTime API internal
--export([create_link/3, get_option/3, type_check/2, start_event_handler/1]).
-
-%% Application callbacks
--export([start/2, init/1, stop/1]).
-
-%%--------------- DEFINES ------------------------------------
--define(IDL_TIME_MODULES, ['oe_TimeBase',
- 'oe_CosTime']).
--define(IDL_TIMEREVENT_MODULES, ['oe_CosTimerEvent']).
--define(SUPERVISOR_NAME, oe_cosTimeSup).
--define(SUP_FLAG, {simple_one_for_one,50,10}).
--define(SUP_TIMESERVICE_SPEC(T,I),
- ['CosTime_TimeService',[T, I],
- [{sup_child, true}, {regname, {global, "oe_cosTimeService"}}]]).
--define(SUP_TIMEREVENTSERVICE_SPEC(Args),
- ['CosTimerEvent_TimerEventService', Args,
- [{sup_child, true}, {regname, {local, 'oe_cosTimerEventService'}}]]).
--define(SUP_TIMEREVENTHANDLER_SPEC(Name, Args),
- ['CosTimerEvent_TimerEventHandler',Args,
- [{sup_child, true}, {regname, {global, Name}}]]).
--define(SUP_CHILD,
- {"oe_TimeChild",
- {cosTime,create_link, []},
- transient,100000,worker,
- []}).
-
-%%------------------------------------------------------------
-%% function : install_*/X
-%% Arguments: - | Time (seconds)
-%% Returns : ok | EXIT | EXCEPTION
-%% Effect : Install necessary data in the IFR DB
-%%------------------------------------------------------------
-
-install_time() ->
- case install_loop(?IDL_TIME_MODULES,[]) of
- ok ->
- ok;
- {error, Reason} ->
- exit(Reason)
- end.
-
-install_timerevent() ->
- case install_loop(?IDL_TIMEREVENT_MODULES,[]) of
- ok ->
- ok;
- {error, Reason} ->
- exit(Reason)
- end.
-
-install_loop([], _) ->
- ok;
-install_loop([H|T], Accum) ->
- case catch H:'oe_register'() of
- {'EXIT',{unregistered,App}} ->
- ?write_ErrorMsg("Unable to register '~p'; application ~p not registered.\n"
- "Trying to unregister ~p\n", [H,App,Accum]),
- uninstall_loop(Accum, {exit, register});
- {'EXCEPTION',_} ->
- ?write_ErrorMsg("Unable to register '~p'; propably already registered.\n"
- "You are adviced to confirm this.\n"
- "Trying to unregister ~p\n", [H,Accum]),
- uninstall_loop(Accum, {exit, register});
- ok ->
- install_loop(T, [H|Accum]);
- _ ->
- ?write_ErrorMsg("Unable to register '~p'; reason unknown.\n"
- "Trying to unregister ~p\n", [H,Accum]),
- uninstall_loop(Accum, {exit, register})
- end.
-
-%%------------------------------------------------------------
-%% function : uninstall_*/X
-%% Arguments: - | Time (seconds)
-%% Returns : ok | EXIT | EXCEPTION
-%% Effect : Remove data related to cosTime from the IFR DB
-%%------------------------------------------------------------
-
-uninstall_time() ->
- case uninstall_loop(lists:reverse(?IDL_TIME_MODULES),ok) of
- ok ->
- ok;
- {error, Reason} ->
- exit(Reason)
- end.
-
-uninstall_timerevent() ->
- case uninstall_loop(lists:reverse(?IDL_TIMEREVENT_MODULES),ok) of
- ok ->
- ok;
- {error, Reason} ->
- exit(Reason)
- end.
-
-uninstall_loop([],ok) ->
- ok;
-uninstall_loop([],{exit, register}) ->
- {error, {?MODULE, "oe_register failed"}};
-uninstall_loop([],{exit, unregister}) ->
- {error, {?MODULE, "oe_unregister failed"}};
-uninstall_loop([],{exit, both}) ->
- {error, {?MODULE, "oe_register and, for some of those already registered, oe_unregister failed"}};
-uninstall_loop([H|T], Status) ->
- case catch H:'oe_unregister'() of
- ok ->
- uninstall_loop(T, Status);
- _ when Status == ok ->
- ?write_ErrorMsg("Unable to unregister '~p'; propably already unregistered.\n"
- "You are adviced to confirm this.~n",[H]),
- uninstall_loop(T, {exit, unregister});
- _ ->
- ?write_ErrorMsg("Unable to unregister '~p'; propably already unregistered.\n"
- "You are adviced to confirm this.~n",[H]),
- uninstall_loop(T, {exit, both})
- end.
-
-%%------------------------------------------------------------
-%% function : start/stop
-%% Arguments:
-%% Returns :
-%% Effect : Starts or stops the cosTime application.
-%%------------------------------------------------------------
-
-start() ->
- application:start(cosTime).
-stop() ->
- application:stop(cosTime).
-
-%%------------------------------------------------------------
-%% function : start
-%% Arguments: Type - see module application
-%% Arg - see module application
-%% Returns :
-%% Effect : Module callback for application
-%%------------------------------------------------------------
-
-start(_, _) ->
- supervisor:start_link({local, ?SUPERVISOR_NAME}, cosTime, app_init).
-
-
-%%------------------------------------------------------------
-%% function : stop
-%% Arguments: Arg - see module application
-%% Returns :
-%% Effect : Module callback for application
-%%------------------------------------------------------------
-
-stop(_) ->
- ok.
-
-%%------------------------------------------------------------
-%% function : start_time_service
-%% Arguments: Tdf - time difference to UTC
-%% Inaccuracy - ulonglong
-%% Upper - inaccuracy high
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-start_time_service(Tdf, Inaccuracy) when is_integer(Tdf) andalso is_integer(Inaccuracy) ->
- case supervisor:start_child(?SUPERVISOR_NAME,
- ?SUP_TIMESERVICE_SPEC(Tdf, Inaccuracy)) of
- {ok, Pid, Obj} when is_pid(Pid) ->
- Obj;
- _Other->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end;
-start_time_service(_Tdf, _Inaccuracy) ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-
-%%------------------------------------------------------------
-%% function : stop_time_service
-%% Arguments: Obj - TimeService objref
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-stop_time_service(Obj) ->
- corba:dispose(Obj).
-
-%%------------------------------------------------------------
-%% function : start_timerevent_service
-%% Arguments: Timer - Timer Service Reference
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-start_timerevent_service(Timer) ->
- case supervisor:start_child(?SUPERVISOR_NAME,
- ?SUP_TIMEREVENTSERVICE_SPEC([Timer])) of
- {ok, Pid, Obj} when is_pid(Pid) ->
- Obj;
- _Other->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-%%-----------------------------------------------------------%
-%% function : stop_timerevent_service
-%% Arguments: Obj - TimerEventService objref
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-stop_timerevent_service(Obj) ->
- corba:dispose(Obj).
-
-%%-----------------------------------------------------------%
-%% function : init
-%% Arguments:
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-
-%% Starting using create_factory/X
-init(own_init) ->
- {ok,{?SUP_FLAG, [?SUP_CHILD]}};
-%% When starting as an application.
-init(app_init) ->
- {ok,{?SUP_FLAG, [?SUP_CHILD]}}.
-
-%%-----------------------------------------------------------%
-%% function : create_link
-%% Arguments: Module - which Module to call
-%% Env/ArgList - ordinary oe_create arguments.
-%% Returns :
-%% Exception:
-%% Effect : Necessary since we want the supervisor to be a
-%% 'simple_one_for_one'. Otherwise, using for example,
-%% 'one_for_one', we have to call supervisor:delete_child
-%% to remove the childs startspecification from the
-%% supervisors internal state.
-%%------------------------------------------------------------
-create_link(Module, Env, ArgList) ->
- Module:oe_create_link(Env, ArgList).
-
-%%-----------------------------------------------------------%
-%% function : start_event_handler
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-
-start_event_handler(Args) ->
- Name = create_name(eventhandler),
- case supervisor:start_child(?SUPERVISOR_NAME, ?SUP_TIMEREVENTHANDLER_SPEC(Name,Args)) of
- {ok, Pid, Obj} when is_pid(Pid) ->
- Obj;
- _Other->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-
-%%-----------------------------------------------------------%
-%% function : get_option
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-
-get_option(Key, OptionList, DefaultList) ->
- case lists:keysearch(Key, 1, OptionList) of
- {value,{Key,Value}} ->
- Value;
- _ ->
- case lists:keysearch(Key, 1, DefaultList) of
- {value,{Key,Value}} ->
- Value;
- _->
- {error, "Invalid option"}
- end
- end.
-
-%%-----------------------------------------------------------%
-%% function : type_check
-%% Arguments: Obj - objectrefernce to test.
-%% Mod - Module which contains typeID/0.
-%% Returns : 'ok' or raises exception.
-%% Effect :
-%%------------------------------------------------------------
-
-type_check(Obj, Mod) ->
- case catch corba_object:is_a(Obj,Mod:typeID()) of
- true ->
- ok;
- _ ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO})
- end.
-
-
-%%-----------------------------------------------------------%
-%% function : create_name/1
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-
-create_name(Type) ->
- Time = erlang:system_time(),
- Unique = erlang:unique_integer([positive]),
- lists:concat(['oe_',node(),'_',Type,'_',Time,'_',Unique]).
-
-%%--------------- END OF MODULE ------------------------------
-
-
diff --git a/lib/cosTime/src/cosTimeApp.hrl b/lib/cosTime/src/cosTimeApp.hrl
deleted file mode 100644
index 7c084dc585..0000000000
--- a/lib/cosTime/src/cosTimeApp.hrl
+++ /dev/null
@@ -1,77 +0,0 @@
-%%----------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : cosTimeApp.hrl
-%% Purpose :
-%%----------------------------------------------------------------------
-
-
-%%--------------- INCLUDES -----------------------------------
-%% External
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
-
-%% Local
--include("CosTimerEvent.hrl").
--include("CosTime.hrl").
--include("CosTimerEvent.hrl").
--include("TimeBase.hrl").
-
--define(CREATE_OPTS, [{no_security, orber:partial_security()}]).
-
--define(max_Inaccuracy, 281474976710655).
--define(max_TimeT, 18446744073709551616).
-
-%% The calendar module uses year 0 as base for gregorian functions.
-%% 'ABSOULTE_TIME_DIFF' is #seconds from year 0 until 15 october 1582, 00:00.
--define(ABSOLUTE_TIME_DIFF, 49947926400).
-%% As above but diff year 0 to 00:00 GMT, January 1, 1970
--define(STANDARD_TIME_DIFF, 62167219200).
-
--define(split_TimeT(T), {((T band 16#0000ffff00000000) bsr 32),
- (T band 16#00000000ffffffff)}).
-
--define(high_TimeT(T), ((T band 16#0000ffff00000000) bsr 32)).
--define(low_TimeT(T), (T band 16#00000000ffffffff)).
-
--define(concat_TimeT(H,L), ((H bsl 32) + L)).
-
--define(convert_TimeT2TimerT(N), erlang:trunc(N*1.0e-4)).
-
--define(write_ErrorMsg(Txt, Arg),
-error_logger:error_msg("================ CosTime ==================~n"
- Txt
- "===========================================~n",
- Arg)).
-
-
-
--ifdef(debug).
--define(debug_print(F,A),
- io:format("[LINE: ~p MODULE: ~p] "++F,[?LINE, ?MODULE]++A)).
--define(time_TypeCheck(O,M), 'cosTime':type_check(O,M)).
--else.
--define(debug_print(F,A), ok).
--define(time_TypeCheck(O,I), ok).
--endif.
-
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/cosTime/test/Makefile b/lib/cosTime/test/Makefile
deleted file mode 100644
index 91d3eccf43..0000000000
--- a/lib/cosTime/test/Makefile
+++ /dev/null
@@ -1,135 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2000-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(COSTIME_VSN)
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/cosTime_test
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-TEST_SPEC_FILE = cosTime.spec
-COVER_FILE = cosTime.cover
-
-
-IDL_FILES =
-
-IDLOUTDIR = idl_output
-
-MODULES = \
- time_SUITE \
- generated_SUITE
-
-GEN_MODULES = \
-
-GEN_HRL_FILES = \
-
-ERL_FILES = $(MODULES:%=%.erl)
-
-HRL_FILES =
-
-GEN_FILES = \
- $(GEN_HRL_FILES:%=$(IDLOUTDIR)/%) \
- $(GEN_MODULES:%=$(IDLOUTDIR)/%.erl)
-
-GEN_TARGET_FILES = $(GEN_MODULES:%=$(IDLOUTDIR)/%.$(EMULATOR))
-
-SUITE_TARGET_FILES = $(MODULES:%=%.$(EMULATOR))
-
-TARGET_FILES = \
- $(GEN_TARGET_FILES) \
- $(SUITE_TARGET_FILES)
-
-
-# ----------------------------------------------------
-# PROGRAMS
-# ----------------------------------------------------
-LOCAL_CLASSPATH = $(ERL_TOP)lib/cosTime/priv:$(ERL_TOP)lib/cosTime/test
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_IDL_FLAGS += -pa $(ERL_TOP)/lib/cosTime/ebin \
- -pa $(ERL_TOP)/lib/cosTime/src \
- -pa $(ERL_TOP)/lib/cosTime/include \
- -pa $(ERL_TOP)/lib/cosNotification/ebin \
- -pa $(ERL_TOP)/lib/orber/ebin \
- -pa $(ERL_TOP)/lib/ic/ebin
-
-ERL_COMPILE_FLAGS += \
- $(ERL_IDL_FLAGS) \
- -pa $(ERL_TOP)/lib/orber/include \
- -pa $(ERL_TOP)/lib/cosNotification/include \
- -pa $(ERL_TOP)/lib/cosTime/ebin \
- -pa $(ERL_TOP)/lib/cosTime/include \
- -pa $(ERL_TOP)/lib/cosTime/test/idl_output \
- -I$(ERL_TOP)/lib/orber/include \
- -I$(ERL_TOP)/lib/cosNotification/include \
- -I$(ERL_TOP)/lib/cosTime/src \
- -I$(ERL_TOP)/lib/cosTime/include \
- -I$(ERL_TOP)/lib/cosTime \
- -I$(ERL_TOP)/lib/cosTime/test/$(IDLOUTDIR)
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-
-tests debug opt: $(TARGET_FILES)
-
-clean:
- rm -f idl_output/*
- rm -f $(TARGET_FILES)
- rm -f errs core *~
-
-docs:
-
-# ----------------------------------------------------
-# Special Targets
-# ----------------------------------------------------
-
-# ----------------------------------------------------
-# Release Targets
-# ----------------------------------------------------
-# We don't copy generated intermediate erlang and hrl files
-
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec:
-
-release_docs_spec:
-
-release_tests_spec: tests
- $(INSTALL_DIR) "$(RELSYSDIR)"
- $(INSTALL_DATA) $(IDL_FILES) $(TEST_SPEC_FILE) \
- $(COVER_FILE) $(ERL_FILES) "$(RELSYSDIR)"
- $(INSTALL_DATA) $(SUITE_TARGET_FILES) "$(RELSYSDIR)"
-# $(INSTALL_DIR) "$(RELSYSDIR)/$(IDLOUTDIR)"
-# $(INSTALL_DATA) $(GEN_TARGET_FILES) $(GEN_FILES) \
-# "$(RELSYSDIR)/$(IDLOUTDIR)"
-
diff --git a/lib/cosTime/test/cosTime.cover b/lib/cosTime/test/cosTime.cover
deleted file mode 100644
index 81a05b8cfd..0000000000
--- a/lib/cosTime/test/cosTime.cover
+++ /dev/null
@@ -1,2 +0,0 @@
-{incl_app,cosTime,details}.
-
diff --git a/lib/cosTime/test/cosTime.spec b/lib/cosTime/test/cosTime.spec
deleted file mode 100644
index 8bf6f740fe..0000000000
--- a/lib/cosTime/test/cosTime.spec
+++ /dev/null
@@ -1 +0,0 @@
-{suites,"../cosTime_test",all}.
diff --git a/lib/cosTime/test/generated_SUITE.erl b/lib/cosTime/test/generated_SUITE.erl
deleted file mode 100644
index b030155340..0000000000
--- a/lib/cosTime/test/generated_SUITE.erl
+++ /dev/null
@@ -1,289 +0,0 @@
-%%-----------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File : generated_SUITE.erl
-%% Purpose :
-%%-----------------------------------------------------------------
-
--module(generated_SUITE).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/include/corba.hrl").
-
--define(default_timeout, test_server:minutes(3)).
-
--define(match(ExpectedRes, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
--define(nomatch(Not, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- Not ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS);
- _ ->
- AcTuAlReS
- end
- end()).
-
-
--define(checktc(_Op),
- fun(TC) ->
- case orber_tc:check_tc(TC) of
- false ->
- io:format("###### ERROR ERROR ######~n~p - ~p~n", [Op, TC]),
- exit(TC);
- true ->
- true
- end
- end).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--compile(export_all).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- ['TimeBase_IntervalT', 'TimeBase_UtcT',
- 'CosTime_TimeUnavailable', 'CosTimerEvent_TimerEventT',
- 'CosTime_TIO', 'CosTime_TimeService', 'CosTime_UTO',
- 'CosTimerEvent_TimerEventHandler',
- 'CosTimerEvent_TimerEventService'].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-init_per_testcase(_Case, Config) ->
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'TimeBase_IntervalT'
-%% Description:
-%%-----------------------------------------------------------------
-'TimeBase_IntervalT'(_) ->
- ?match(true, orber_tc:check_tc('TimeBase_IntervalT':tc())),
- ?match("IDL:omg.org/TimeBase/IntervalT:1.0",
- 'TimeBase_IntervalT':id()),
- ?match("TimeBase_IntervalT",
- 'TimeBase_IntervalT':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'TimeBase_UtcT'
-%% Description:
-%%-----------------------------------------------------------------
-'TimeBase_UtcT'(_) ->
- ?match(true, orber_tc:check_tc('TimeBase_UtcT':tc())),
- ?match("IDL:omg.org/TimeBase/UtcT:1.0",
- 'TimeBase_UtcT':id()),
- ?match("TimeBase_UtcT",
- 'TimeBase_UtcT':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTime_TimeUnavailable'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTime_TimeUnavailable'(_) ->
- ?match(true, orber_tc:check_tc('CosTime_TimeUnavailable':tc())),
- ?match("IDL:omg.org/CosTime/TimeUnavailable:1.0",
- 'CosTime_TimeUnavailable':id()),
- ?match("CosTime_TimeUnavailable",
- 'CosTime_TimeUnavailable':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTimerEvent_TimerEventT'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTimerEvent_TimerEventT'(_) ->
- ?match(true, orber_tc:check_tc('CosTimerEvent_TimerEventT':tc())),
- ?match("IDL:omg.org/CosTimerEvent/TimerEventT:1.0",
- 'CosTimerEvent_TimerEventT':id()),
- ?match("CosTimerEvent_TimerEventT",
- 'CosTimerEvent_TimerEventT':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTime_TIO'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTime_TIO'(_) ->
- ?nomatch(undefined, 'CosTime_TIO':oe_tc('_get_time_interval')),
- ?nomatch(undefined, 'CosTime_TIO':oe_tc(spans)),
- ?nomatch(undefined, 'CosTime_TIO':oe_tc(overlaps)),
- ?nomatch(undefined, 'CosTime_TIO':oe_tc(time)),
- ?match(undefined, 'CosTime_TIO':oe_tc(undefined)),
- ?match([_|_], 'CosTime_TIO':oe_get_interface()),
- ?match("IDL:omg.org/CosTime/TIO:1.0", 'CosTime_TIO':typeID()),
- check_tc('CosTime_TIO':oe_get_interface()),
- ?match(true, 'CosTime_TIO':oe_is_a('CosTime_TIO':typeID())),
- ?match(false, 'CosTime_TIO':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTime_TimeService'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTime_TimeService'(_) ->
- ?nomatch(undefined, 'CosTime_TimeService':oe_tc(universal_time)),
- ?nomatch(undefined, 'CosTime_TimeService':oe_tc(secure_universal_time)),
- ?nomatch(undefined, 'CosTime_TimeService':oe_tc(new_universal_time)),
- ?nomatch(undefined, 'CosTime_TimeService':oe_tc(uto_from_utc)),
- ?nomatch(undefined, 'CosTime_TimeService':oe_tc(new_interval)),
- ?match(undefined, 'CosTime_TimeService':oe_tc(undefined)),
- ?match([_|_], 'CosTime_TimeService':oe_get_interface()),
- ?match("IDL:omg.org/CosTime/TimeService:1.0",
- 'CosTime_TimeService':typeID()),
- check_tc('CosTime_TimeService':oe_get_interface()),
- ?match(true, 'CosTime_TimeService':oe_is_a('CosTime_TimeService':typeID())),
- ?match(false, 'CosTime_TimeService':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTime_UTO'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTime_UTO'(_) ->
- ?nomatch(undefined, 'CosTime_UTO':oe_tc('_get_time')),
- ?nomatch(undefined, 'CosTime_UTO':oe_tc('_get_inaccuracy')),
- ?nomatch(undefined, 'CosTime_UTO':oe_tc('_get_tdf')),
- ?nomatch(undefined, 'CosTime_UTO':oe_tc('_get_utc_time')),
- ?nomatch(undefined, 'CosTime_UTO':oe_tc(absolute_time)),
- ?nomatch(undefined, 'CosTime_UTO':oe_tc(compare_time)),
- ?nomatch(undefined, 'CosTime_UTO':oe_tc(time_to_interval)),
- ?nomatch(undefined, 'CosTime_UTO':oe_tc(interval)),
- ?match(undefined, 'CosTime_UTO':oe_tc(undefined)),
- ?match([_|_], 'CosTime_UTO':oe_get_interface()),
- ?match("IDL:omg.org/CosTime/UTO:1.0", 'CosTime_UTO':typeID()),
- check_tc('CosTime_UTO':oe_get_interface()),
- ?match(true, 'CosTime_UTO':oe_is_a('CosTime_UTO':typeID())),
- ?match(false, 'CosTime_UTO':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTimerEvent_TimerEventHandler'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTimerEvent_TimerEventHandler'(_) ->
- ?nomatch(undefined, 'CosTimerEvent_TimerEventHandler':oe_tc('_get_status')),
- ?nomatch(undefined, 'CosTimerEvent_TimerEventHandler':oe_tc(time_set)),
- ?nomatch(undefined, 'CosTimerEvent_TimerEventHandler':oe_tc(set_timer)),
- ?nomatch(undefined, 'CosTimerEvent_TimerEventHandler':oe_tc(cancel_timer)),
- ?nomatch(undefined, 'CosTimerEvent_TimerEventHandler':oe_tc(set_data)),
- ?match(undefined, 'CosTimerEvent_TimerEventHandler':oe_tc(undefined)),
- ?match([_|_], 'CosTimerEvent_TimerEventHandler':oe_get_interface()),
- ?match("IDL:omg.org/CosTimerEvent/TimerEventHandler:1.0",
- 'CosTimerEvent_TimerEventHandler':typeID()),
- check_tc('CosTimerEvent_TimerEventHandler':oe_get_interface()),
- ?match(true, 'CosTimerEvent_TimerEventHandler':oe_is_a('CosTimerEvent_TimerEventHandler':typeID())),
- ?match(false, 'CosTimerEvent_TimerEventHandler':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTimerEvent_TimerEventService'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTimerEvent_TimerEventService'(_) ->
- ?nomatch(undefined, 'CosTimerEvent_TimerEventService':oe_tc(register)),
- ?nomatch(undefined, 'CosTimerEvent_TimerEventService':oe_tc(unregister)),
- ?nomatch(undefined, 'CosTimerEvent_TimerEventService':oe_tc(event_time)),
- ?match(undefined, 'CosTimerEvent_TimerEventService':oe_tc(undefined)),
- ?match([_|_], 'CosTimerEvent_TimerEventService':oe_get_interface()),
- ?match("IDL:omg.org/CosTimerEvent/TimerEventService:1.0",
- 'CosTimerEvent_TimerEventService':typeID()),
- check_tc('CosTimerEvent_TimerEventService':oe_get_interface()),
- ?match(true, 'CosTimerEvent_TimerEventService':oe_is_a('CosTimerEvent_TimerEventService':typeID())),
- ?match(false, 'CosTimerEvent_TimerEventService':oe_is_a("wrong")),
- ok.
-
-
-
-
-%%-----------------------------------------------------------------
-%% MISC functions
-%%-----------------------------------------------------------------
-check_tc([]) ->
- ok;
-check_tc([{Op, {RetType, InParameters, OutParameters}}|T]) ->
- io:format("checked - ~s~n", [Op]),
- lists:all(?checktc(Op), [RetType|InParameters]),
- lists:all(?checktc(Op), OutParameters),
- check_tc(T).
-
-
diff --git a/lib/cosTime/test/time_SUITE.erl b/lib/cosTime/test/time_SUITE.erl
deleted file mode 100644
index f85f13badb..0000000000
--- a/lib/cosTime/test/time_SUITE.erl
+++ /dev/null
@@ -1,301 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : time_SUITE.erl
-%% Purpose :
-%%----------------------------------------------------------------------
-
--module(time_SUITE).
-
-
-%%--------------- INCLUDES -----------------------------------
--include_lib("cosTime/src/cosTimeApp.hrl").
-
--include_lib("common_test/include/ct.hrl").
-
-%%--------------- DEFINES ------------------------------------
--define(default_timeout, test_server:minutes(20)).
--define(match(ExpectedRes, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- io:format("------ CORRECT RESULT ------~n~p~n",
- [AcTuAlReS]),
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
--define(match_inverse(NotExpectedRes, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- NotExpectedRes ->
- io:format("###### ERROR ERROR ######~n ~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS);
- _ ->
- io:format("------ CORRECT RESULT ------~n~p~n",
- [AcTuAlReS]),
- AcTuAlReS
- end
- end()).
-
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2, cases/0,
- init_per_suite/1, end_per_suite/1, time_api/1, timerevent_api/1,
- init_per_testcase/2, end_per_testcase/2,
- app_test/1]).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- cases().
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-cases() ->
- [time_api, timerevent_api, app_test].
-
-
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-
-init_per_testcase(_Case, Config) ->
- Path = code:which(?MODULE),
- code:add_pathz(filename:join(filename:dirname(Path), "idl_output")),
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- Path = code:which(?MODULE),
- code:del_path(filename:join(filename:dirname(Path), "idl_output")),
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-init_per_suite(Config) ->
- Path = code:which(?MODULE),
- code:add_pathz(filename:join(filename:dirname(Path), "idl_output")),
- mnesia:delete_schema([node()]),
- mnesia:create_schema([node()]),
- orber:install([node()]),
- application:start(mnesia),
- application:start(orber),
- cosNotificationApp:install_event(),
- cosNotificationApp:install(),
- cosTime:install_time(),
- cosTime:install_timerevent(),
- if
- is_list(Config) ->
- Config;
- true ->
- exit("Config not a list")
- end.
-
-end_per_suite(Config) ->
- Path = code:which(?MODULE),
- code:del_path(filename:join(filename:dirname(Path), "idl_output")),
- cosTime:uninstall_time(),
- cosTime:uninstall_timerevent(),
- cosNotificationApp:uninstall(),
- cosNotificationApp:uninstall_event(),
- application:stop(orber),
- application:stop(mnesia),
- mnesia:delete_schema([node()]),
- Config.
-
-%%-----------------------------------------------------------------
-%% Tests app file
-%%-----------------------------------------------------------------
-app_test(_Config) ->
- ok=test_server:app_test(cosTime),
- ok.
-
-%%-----------------------------------------------------------------
-%% CosTime API tests
-%%-----------------------------------------------------------------
-time_api(_Config) ->
- ?match(ok, application:start(cosTime)),
- TS=cosTime:start_time_service(0, 500),
- Time=calendar:datetime_to_gregorian_seconds({{1582,1,1},{0,0,0}}),
- Inaccuracy = 1000,
- Tdf =1,
- Utc = #'TimeBase_UtcT'{time=Time, inacclo = ?low_TimeT(Inaccuracy),
- inacchi = ?high_TimeT(Inaccuracy), tdf = Tdf},
- UTO1='CosTime_TimeService':new_universal_time(TS, Time, Inaccuracy, Tdf),
- UTO2='CosTime_TimeService':uto_from_utc(TS, Utc),
- ?match(Time, 'CosTime_UTO':'_get_time'(UTO1)),
- ?match(Inaccuracy, 'CosTime_UTO':'_get_inaccuracy'(UTO1)),
- ?match(Tdf, 'CosTime_UTO':'_get_tdf'(UTO1)),
- ?match(Utc, 'CosTime_UTO':'_get_utc_time'(UTO1)),
-
- ?match(Time, 'CosTime_UTO':'_get_time'(UTO2)),
- ?match(Inaccuracy, 'CosTime_UTO':'_get_inaccuracy'(UTO2)),
- ?match(Tdf, 'CosTime_UTO':'_get_tdf'(UTO2)),
- ?match(Utc, 'CosTime_UTO':'_get_utc_time'(UTO2)),
-
- TIO1='CosTime_TimeService':new_interval(TS, 2, 5),
- _TIO2='CosTime_TimeService':new_interval(TS, 3, 6),
- TIO3='CosTime_TimeService':new_interval(TS, 1, 3),
- TIO4='CosTime_TimeService':new_interval(TS, 3, 4),
- TIO5='CosTime_TimeService':new_interval(TS, 7, 8),
- TIO6='CosTime_TimeService':new_interval(TS, 2, 6),
- TIO7='CosTime_TimeService':new_interval(TS, 3, 7),
-
- {_,TIO8} = ?match({'OTContained', _}, 'CosTime_TIO':overlaps(TIO1, TIO6)),
- {_,TIO9} = ?match({'OTContainer', _}, 'CosTime_TIO':overlaps(TIO1, TIO1)),
- {_,TIO10} = ?match({'OTContainer', _}, 'CosTime_TIO':overlaps(TIO1, TIO4)),
- {_,TIO11} = ?match({'OTOverlap', _}, 'CosTime_TIO':overlaps(TIO1, TIO3)),
- {_,TIO12} = ?match({'OTOverlap', _}, 'CosTime_TIO':overlaps(TIO1, TIO7)),
- {_,TIO13} = ?match({'OTNoOverlap', _}, 'CosTime_TIO':overlaps(TIO1, TIO5)),
-
- ?match({'TimeBase_IntervalT',2,5},'CosTime_TIO':'_get_time_interval'(TIO8)),
- ?match({'TimeBase_IntervalT',2,5},'CosTime_TIO':'_get_time_interval'(TIO9)),
- ?match({'TimeBase_IntervalT',3,4},'CosTime_TIO':'_get_time_interval'(TIO10)),
- ?match({'TimeBase_IntervalT',2,3},'CosTime_TIO':'_get_time_interval'(TIO11)),
- ?match({'TimeBase_IntervalT',3,5},'CosTime_TIO':'_get_time_interval'(TIO12)),
- ?match({'TimeBase_IntervalT',5,7},'CosTime_TIO':'_get_time_interval'(TIO13)),
-
- UTO3='CosTime_TimeService':new_universal_time(TS, 4, 2, 0), %% 2-6
- UTO4='CosTime_TimeService':new_universal_time(TS, 2, 1, 0), %% 1-3
- UTO5='CosTime_TimeService':new_universal_time(TS, 3, 0, 0), %% 3-3
- UTO6='CosTime_TimeService':new_universal_time(TS, 9, 1, 0), %% 8-10
- UTO7='CosTime_TimeService':new_universal_time(TS, 4, 3, 0), %% 1-7
- UTO8='CosTime_TimeService':new_universal_time(TS, 5, 2, 0), %% 3-7
-
- {_,TIO14} = ?match({'OTContained', _}, 'CosTime_TIO':spans(TIO1, UTO7)),
- {_,TIO15} = ?match({'OTContainer', _}, 'CosTime_TIO':spans(TIO1, UTO5)),
- {_,TIO16} = ?match({'OTOverlap', _}, 'CosTime_TIO':spans(TIO1, UTO4)),
- {_,TIO17} = ?match({'OTOverlap', _}, 'CosTime_TIO':spans(TIO1, UTO8)),
- {_,TIO18} = ?match({'OTNoOverlap', _}, 'CosTime_TIO':spans(TIO1, UTO6)),
- {_,TIO19} = ?match({'OTContained', _}, 'CosTime_TIO':spans(TIO1, UTO3)),
-
- ?match({'TimeBase_IntervalT',2,5},'CosTime_TIO':'_get_time_interval'(TIO14)),
- ?match({'TimeBase_IntervalT',3,3},'CosTime_TIO':'_get_time_interval'(TIO15)),
- ?match({'TimeBase_IntervalT',2,3},'CosTime_TIO':'_get_time_interval'(TIO16)),
- ?match({'TimeBase_IntervalT',3,5},'CosTime_TIO':'_get_time_interval'(TIO17)),
- ?match({'TimeBase_IntervalT',5,8},'CosTime_TIO':'_get_time_interval'(TIO18)),
- ?match({'TimeBase_IntervalT',2,5},'CosTime_TIO':'_get_time_interval'(TIO19)),
-
-
- cosTime:stop_time_service(TS),
- application:stop(cosTime),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% CosTimerEvent API tests
-%%-----------------------------------------------------------------
-timerevent_api(_Config) ->
- %% Init cosTime apps.
- ?match(ok, application:start(cosTime)),
- TS=cosTime:start_time_service(0, 500),
- TES=cosTime:start_timerevent_service(TS),
-
- %%----- Initialize the cosNotification application. -----
- cosNotificationApp:start(),
- Fac = (catch cosNotificationApp:start_factory([])),
- {Ch, _Id1} = (catch 'CosNotifyChannelAdmin_EventChannelFactory':create_channel(Fac, [], [])),
- %% Create the Admin objects
- {AdminSupplier, _ASID}= ?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_EventChannel':new_for_suppliers(Ch,'OR_OP')),
- {AdminConsumer, _ACID}= ?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_EventChannel':new_for_consumers(Ch,'OR_OP')),
-
- %% Create a push consumer TimerEventService will push events to.
- {ProxyPushConsumer,_ID10}= ?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_SupplierAdmin':obtain_notification_push_consumer(AdminSupplier, 'ANY_EVENT')),
-
- %% Create a pull suppliers so we can check we actually got the event.
- {ProxyPullSupplier,_ID1} = ?match({{_,key,_,_,_,_},_},
- 'CosNotifyChannelAdmin_ConsumerAdmin':obtain_notification_pull_supplier(AdminConsumer, 'ANY_EVENT')),
-
- AnyEvent = any:create(orber_tc:long(), 100),
- UTO=?match({_,pseudo,_,_,_,_}, 'CosTime_TimeService':new_universal_time(TS, 10*10000000,1,1)),
- EH=?match({_,key,_,_,_,_}, 'CosTimerEvent_TimerEventService':register(TES, ProxyPushConsumer, AnyEvent)),
-
- ?match('ESTimeCleared','CosTimerEvent_TimerEventHandler':'_get_status'(EH)),
- ?match({false,_},'CosTimerEvent_TimerEventHandler':time_set(EH)),
- ?match(ok,'CosTimerEvent_TimerEventHandler':set_timer(EH, 'TTRelative', UTO)),
- ?match({true,_},'CosTimerEvent_TimerEventHandler':time_set(EH)),
- ?match('ESTimeSet','CosTimerEvent_TimerEventHandler':'_get_status'(EH)),
-
- ?match({{any,tk_null,null}, false},
- 'CosNotifyChannelAdmin_ProxyPullSupplier':try_pull(ProxyPullSupplier)),
-
- ?match(AnyEvent, 'CosNotifyChannelAdmin_ProxyPullSupplier':pull(ProxyPullSupplier)),
- ?match('ESTriggered','CosTimerEvent_TimerEventHandler':'_get_status'(EH)),
-
- %% It's allowed to send an UTO with time eq. to 0 if the server is TTRelative.
- %% When TTAbsolute BAD_PARAM is raised.
- UTO2=?match({_,pseudo,_,_,_,_}, 'CosTime_TimeService':new_universal_time(TS, 0,1,1)),
- ?match({'EXCEPTION',_},'CosTimerEvent_TimerEventHandler':set_timer(EH, 'TTAbsolute', UTO2)),
- ?match(ok,'CosTimerEvent_TimerEventHandler':set_timer(EH, 'TTRelative', UTO2)),
- ?match(AnyEvent, 'CosNotifyChannelAdmin_ProxyPullSupplier':pull(ProxyPullSupplier)),
-
- %% TTPeriodic is defined to be relative, i.e., we can use the tactic as above.
- ?match(ok,'CosTimerEvent_TimerEventHandler':set_timer(EH, 'TTPeriodic', UTO2)),
-
- %% Sleep for UTO*2+4 secs. At this point the Timer should have delivered 2 events.
- timer:sleep(24000),
- %% Cancel the timer so no more events will be delivered.
- ?match(true,'CosTimerEvent_TimerEventHandler':cancel_timer(EH)),
-
- ?match({AnyEvent, true}, 'CosNotifyChannelAdmin_ProxyPullSupplier':try_pull(ProxyPullSupplier)),
- ?match({AnyEvent, true}, 'CosNotifyChannelAdmin_ProxyPullSupplier':try_pull(ProxyPullSupplier)),
- ?match({{any,tk_null,null}, false},
- 'CosNotifyChannelAdmin_ProxyPullSupplier':try_pull(ProxyPullSupplier)),
-
-
-
- %% Clean up.
- cosNotificationApp:stop(),
- cosTime:stop_timerevent_service(TES),
- cosTime:stop_time_service(TS),
- application:stop(cosTime),
- ok.
-
-
diff --git a/lib/cosTime/vsn.mk b/lib/cosTime/vsn.mk
deleted file mode 100644
index 7d6fcbebcd..0000000000
--- a/lib/cosTime/vsn.mk
+++ /dev/null
@@ -1,2 +0,0 @@
-COSTIME_VSN = 1.2.3
-
diff --git a/lib/cosTransactions/AUTHORS b/lib/cosTransactions/AUTHORS
deleted file mode 100644
index 6d03df4c5a..0000000000
--- a/lib/cosTransactions/AUTHORS
+++ /dev/null
@@ -1,4 +0,0 @@
-Original Authors:
-Niclas Eklund
-
-Contributors:
diff --git a/lib/cosTransactions/Makefile b/lib/cosTransactions/Makefile
deleted file mode 100644
index e8d0d1c0cd..0000000000
--- a/lib/cosTransactions/Makefile
+++ /dev/null
@@ -1,42 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1999-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include vsn.mk
-VSN=$(COSTRANSACTIONS_VSN)
-
-# ----------------------------------------------------
-# Common Macros
-# ----------------------------------------------------
-# SUB_DIRECTORIES = src test examples doc/src
-# At the moment we don't have any example programs.
-SUB_DIRECTORIES = src doc/src
-
-SPECIAL_TARGETS =
-
-# ----------------------------------------------------
-# Default Subdir Targets
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_subdir.mk
diff --git a/lib/cosTransactions/doc/html/.gitignore b/lib/cosTransactions/doc/html/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosTransactions/doc/html/.gitignore
+++ /dev/null
diff --git a/lib/cosTransactions/doc/man3/.gitignore b/lib/cosTransactions/doc/man3/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosTransactions/doc/man3/.gitignore
+++ /dev/null
diff --git a/lib/cosTransactions/doc/man6/.gitignore b/lib/cosTransactions/doc/man6/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosTransactions/doc/man6/.gitignore
+++ /dev/null
diff --git a/lib/cosTransactions/doc/pdf/.gitignore b/lib/cosTransactions/doc/pdf/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosTransactions/doc/pdf/.gitignore
+++ /dev/null
diff --git a/lib/cosTransactions/doc/src/CosTransactions_Control.xml b/lib/cosTransactions/doc/src/CosTransactions_Control.xml
deleted file mode 100644
index bf5e25a701..0000000000
--- a/lib/cosTransactions/doc/src/CosTransactions_Control.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1999</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosTransactions_Control</title>
- <prepared>Niclas Eklund</prepared>
- <responsible>Niclas Eklund</responsible>
- <docno></docno>
- <approved>Niclas Eklund</approved>
- <checked></checked>
- <date>1999-04-12</date>
- <rev>PA1</rev>
- </header>
- <module>CosTransactions_Control</module>
- <modulesummary>This module implements the OMG CosTransactions::Control interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosTransactions/include/CosTransactions.hrl").</c></p>
- </description>
- <funcs>
- <func>
- <name>get_coordinator(Control) -> Return</name>
- <fsummary>Return the Coordinator object associated with the target object</fsummary>
- <type>
- <v>Control = #objref</v>
- <v>Return = Coordinator | {'EXCEPTION', E}</v>
- <v>Coordinator = #objref</v>
- <v>E = #'CosTransactions_Unavailable' {}</v>
- </type>
- <desc>
- <p>This operation returns the Coordinator object associated with the target object.
- The Coordinator supports operations for termination of a transaction.</p>
- </desc>
- </func>
- <func>
- <name>get_terminator(Control) -> Return</name>
- <fsummary>Return the Terminator object associated with the target object</fsummary>
- <type>
- <v>Control = #objref</v>
- <v>Return = Terminator | {'EXCEPTION', E}</v>
- <v>Terminator = #objref</v>
- <v>E = #'CosTransactions_Unavailable' {}</v>
- </type>
- <desc>
- <p>This operation returns the Terminator object associated with the target object.
- The Terminator supports operations for termination of a transaction.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosTransactions/doc/src/CosTransactions_Coordinator.xml b/lib/cosTransactions/doc/src/CosTransactions_Coordinator.xml
deleted file mode 100644
index 006ba4cc29..0000000000
--- a/lib/cosTransactions/doc/src/CosTransactions_Coordinator.xml
+++ /dev/null
@@ -1,230 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1999</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>CosTransactions_Coordinator</title>
- <prepared></prepared>
- <docno></docno>
- <checked></checked>
- <date>1999-04-12</date>
- <rev>PA1</rev>
- </header>
- <module>CosTransactions_Coordinator</module>
- <modulesummary>This module implements the OMG CosTransactions::Coordinator interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosTransactions/include/CosTransactions.hrl").</c></p>
- </description>
- <funcs>
- <func>
- <name>create_subtransaction(Coordinator) -> Control</name>
- <fsummary>Create a new subtransaction.</fsummary>
- <type>
- <v>Coordinator = #objref</v>
- <v>Control = #objref</v>
- </type>
- <desc>
- <p>A new subtransaction is created whose parent is the Coordinator argument.</p>
- <p>Raises exception:</p>
- <list type="bulleted">
- <item>'SubtransactionsUnavailable' - if nested transactions are not supported.</item>
- <item>'Inactive' - if target transaction has already been prepared.</item>
- </list>
- </desc>
- </func>
- <func>
- <name>get_transaction_name(Coordinator) -> Name</name>
- <fsummary>Return the name associated with the object.</fsummary>
- <type>
- <v>Coordinator = #objref</v>
- <v>Name = string() of type "oe_name@machine_type_timestamp"</v>
- </type>
- <desc>
- <p>Returns a printable string, which describe the transaction. The main purpose is to support debugging.</p>
- </desc>
- </func>
- <func>
- <name>get_parent_status(Coordinator) -> Status</name>
- <fsummary>Return the status of the parent transaction.</fsummary>
- <type>
- <v>Coordinator = #objref</v>
- <v>Status = atom()</v>
- </type>
- <desc>
- <p>Returns the status of the parent transaction
- associated with the target object. If the target object is a top-level
- transaction this operation is equivalent to <c>get_status/1</c> operation. </p>
- <p>Possible Status replies:</p>
- <list type="bulleted">
- <item>'StatusCommitted'</item>
- <item>'StatusCommitting'</item>
- <item>'StatusMarkedRollback'</item>
- <item>'StatusRollingBack'</item>
- <item>'StatusRolledBack'</item>
- <item>'StatusActive'</item>
- <item>'StatusPrepared'</item>
- <item>'StatusUnknown'</item>
- <item>'StatusNoTransaction'</item>
- <item>'StatusPreparing'</item>
- </list>
- </desc>
- </func>
- <func>
- <name>get_status(Coordinator) -> Status</name>
- <fsummary>Return the status of the transaction associated with the target object</fsummary>
- <type>
- <v>Coordinator = #objref</v>
- <v>Status = atom()</v>
- </type>
- <desc>
- <p>Returns the status of the transaction associated with the target object.</p>
- </desc>
- </func>
- <func>
- <name>get_top_level_status(Coordinator) -> Status</name>
- <fsummary>Return the status of the top-level transaction associated with the target object</fsummary>
- <type>
- <v>Coordinator = #objref</v>
- <v>Status = atom()</v>
- </type>
- <desc>
- <p>Returns the status of the top-level transaction associated with the target object.</p>
- </desc>
- </func>
- <func>
- <name>hash_top_level_tran(Coordinator) -> Return</name>
- <fsummary>Return a hash code for the top-level transaction associated with the target object</fsummary>
- <type>
- <v>Coordinator = #objref</v>
- <v>Return = integer()</v>
- </type>
- <desc>
- <p>Returns a hash code for the top-level transaction
- associated with the target object. Equals the operation
- <c>hash_transaction/1</c> if the target object is a top-level transaction.</p>
- </desc>
- </func>
- <func>
- <name>hash_transaction(Coordinator) -> Return</name>
- <fsummary>Return a hash code for the transaction associated with the target object.</fsummary>
- <type>
- <v>Coordinator = #objref</v>
- <v>Return = integer()</v>
- </type>
- <desc>
- <p>Returns a hash code for the transaction associated with the target object.</p>
- </desc>
- </func>
- <func>
- <name>is_descendant_transaction(Coordinator, OtherCoordinator) -> Return</name>
- <fsummary>Return a boolean which indicates whether the transaction associated with the target object is a descendant of the transaction associated with the parameter object</fsummary>
- <type>
- <v>Coordinator = #objref</v>
- <v>OtherCoordinator = #objref</v>
- <v>Return = Boolean</v>
- </type>
- <desc>
- <p>Returns true if the transaction associated with the target object is a
- descendant of the transaction associated with the parameter object.</p>
- </desc>
- </func>
- <func>
- <name>is_same_transaction(Coordinator, OtherCoordinator) -> Return</name>
- <fsummary>Return true if the transaction associated with the target object is related to the transaction associated with the parameter object</fsummary>
- <type>
- <v>Coordinator = #objref</v>
- <v>OtherCoordinator = #objref</v>
- <v>Return = Boolean</v>
- </type>
- <desc>
- <p>Returns true if the transaction associated with the target object is
- related to the transaction associated with the parameter object.</p>
- </desc>
- </func>
- <func>
- <name>is_top_level_transaction(Coordinator) -> Return</name>
- <fsummary>Return true if the transaction associated with the target object is a top-level transaction</fsummary>
- <type>
- <v>Coordinator = #objref</v>
- <v>Return = Boolean</v>
- </type>
- <desc>
- <p>Returns true if the transaction associated with the target object is
- a top-level transaction.</p>
- </desc>
- </func>
- <func>
- <name>register_resource(Coordinator, Resource) -> RecoveryCoordinator</name>
- <fsummary>Register the parameter <c>Resource</c>object as a participant in the transaction associated with the target object</fsummary>
- <type>
- <v>Coordinator = #objref</v>
- <v>Resource = #objref</v>
- <v>RecoveryCoordinator = #objref</v>
- </type>
- <desc>
- <p>This operation registers the parameter <c>Resource</c> object as a participant in the
- transaction associated with the target object. The <c>RecoveryCoordinator</c> returned
- by this operation can be used by this Resource during recovery.</p>
- <note>
- <p>The Resources will be called in FIFO-order when preparing or committing.
- Hence, be sure to register the Resources in the correct order.</p>
- </note>
- <p>Raises exception:</p>
- <list type="bulleted">
- <item>'Inactive' - if target transaction has already been prepared.</item>
- </list>
- </desc>
- </func>
- <func>
- <name>register_subtran_aware(Coordinator, SubtransactionAwareResource) -> Return</name>
- <fsummary>Register the parameter <c>SubtransactionAwareResource</c>object such that it will be notified when the transaction, associated wit the target object, has committed or rolled back</fsummary>
- <type>
- <v>Coordinator = #objref</v>
- <v>Return = ok</v>
- </type>
- <desc>
- <p>This operation registers the parameter <c>SubtransactionAwareResource</c> object such that
- it will be notified when the transaction, associated wit the target object,
- has committed or rolled back.</p>
- <note>
- <p>The Resources will be called in FIFO-order.
- Hence, be sure to register the Resources in the correct order.</p>
- </note>
- </desc>
- </func>
- <func>
- <name>rollback_only(Coordinator) -> Return</name>
- <fsummary>Modify the transaction associated with the target object so the only possible outcome is to rollback the transaction</fsummary>
- <type>
- <v>Coordinator = #objref</v>
- <v>Return = ok</v>
- </type>
- <desc>
- <p>The transaction associated with the target object is modified so the only
- possible outcome is to rollback the transaction.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosTransactions/doc/src/CosTransactions_RecoveryCoordinator.xml b/lib/cosTransactions/doc/src/CosTransactions_RecoveryCoordinator.xml
deleted file mode 100644
index 2d61f815a3..0000000000
--- a/lib/cosTransactions/doc/src/CosTransactions_RecoveryCoordinator.xml
+++ /dev/null
@@ -1,82 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1999</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>CosTransactions_RecoveryCoordinator</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>1999-04-12</date>
- <rev>PA1</rev>
- </header>
- <module>CosTransactions_RecoveryCoordinator</module>
- <modulesummary>This module implements the OMG CosTransactions::RecoveryCoordinator interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosTransactions/include/CosTransactions.hrl").</c></p>
- </description>
- <funcs>
- <func>
- <name>replay_completion(RecoveryCoordinator, Timeout, Resource) -> Return</name>
- <fsummary>Return the current status of the transaction</fsummary>
- <type>
- <v>RecoveryCoordinator = #objref</v>
- <v>Timeout = integer(), milliseconds | 'infinity'</v>
- <v>Resource = #objref</v>
- <v>Return = Status | {'EXCEPTION', E}</v>
- <v>E = #'CosTransactions_NotPrepared'{}</v>
- <v>Status = atom()</v>
- </type>
- <desc>
- <p>The <c>RecoveryCoordinator</c> object is returned by the operation
- <c>CosTransactions_Coordinator:register_resource/3</c>. The <c>replay_completion/2</c>
- may only be used by the registered Resource and returns the current status
- of the transaction. The operation is used when recovering after a failure.</p>
- <p>Possible Status replies:</p>
- <list type="bulleted">
- <item>'StatusCommitted'</item>
- <item>'StatusCommitting'</item>
- <item>'StatusMarkedRollback'</item>
- <item>'StatusRollingBack'</item>
- <item>'StatusRolledBack'</item>
- <item>'StatusActive'</item>
- <item>'StatusPrepared'</item>
- <item>'StatusUnknown'</item>
- <item>'StatusNoTransaction'</item>
- <item>'StatusPreparing'</item>
- </list>
- <warning>
- <p><em>replay_completion/3</em> is blocking and may cause dead-lock if a child
- calls this function at the same time as its parent invokes an operation
- on the child. Dead-lock will not occur if the timeout has any value except 'infinity'.</p>
- <p>If the call is external incoming (intra-ORB) the timeout will not be activated.
- Hence, similar action must be taken if the Resource resides on another vendors ORB.</p>
- </warning>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosTransactions/doc/src/CosTransactions_Resource.xml b/lib/cosTransactions/doc/src/CosTransactions_Resource.xml
deleted file mode 100644
index 40006b55d9..0000000000
--- a/lib/cosTransactions/doc/src/CosTransactions_Resource.xml
+++ /dev/null
@@ -1,129 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1999</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>CosTransactions_Resource</title>
- <prepared></prepared>
- <docno></docno>
- <checked></checked>
- <date>1999-04-12</date>
- <rev>PA1</rev>
- </header>
- <module>CosTransactions_Resource</module>
- <modulesummary>This module implements the OMG CosTransactions::Resource interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosTransactions/include/CosTransactions.hrl").</c></p>
- </description>
- <funcs>
- <func>
- <name>commit(Resource) -> Return</name>
- <fsummary>Instruct the target object to commit the transaction</fsummary>
- <type>
- <v>Resource = #objref</v>
- <v>Return = ok | {'EXCEPTION', E}</v>
- <v>E = #'CosTransactions_NotPrepared'{} | #'CosTransactions_HeuristicRollback'{} | #'CosTransactions_HeuristicMixed'{} | #'CosTransactions_HeuristicHazard'{}</v>
- </type>
- <desc>
- <p>This operation instructs the Resource to commit all changes made as a part of the transaction.</p>
- <p>The Resource can raise:</p>
- <list type="bulleted">
- <item>Heuristic Exception - if a Heuristic decision is made which differ
- from the true outcome of the transaction. The Resource must remember
- the Heuristic outcome until the <c>forget</c> operation is performed.</item>
- </list>
- </desc>
- </func>
- <func>
- <name>commit_one_phase(Resource) -> Return</name>
- <fsummary>Instruct the target object to commit the transaction</fsummary>
- <type>
- <v>Resource = #objref</v>
- <v>Return = ok | {'EXCEPTION', E}</v>
- <v>E = #'CosTransactions_HeuristicHazard'{} | #'CosTransactions_TransactionRolledBack'{}</v>
- </type>
- <desc>
- <p>If possible, the Resource should commit all changes made as part of the transaction,
- else it should raise the TRANSACTION_ROLLEDBACK exception.
- This operation can only be used if the Resource is the only child of its parent.</p>
- </desc>
- </func>
- <func>
- <name>forget(Resource) -> Return</name>
- <fsummary>Instruct the target object to forget any heuristic decisions</fsummary>
- <type>
- <v>Resource = #objref</v>
- <v>Return = ok</v>
- </type>
- <desc>
- <p>This operation informs the Resource that it is safe to forget any Heuristic
- decisions and the knowledge of the transaction.</p>
- </desc>
- </func>
- <func>
- <name>prepare(Resource) -> Return</name>
- <fsummary>Instruct the target object to begin the two-phase commit protocol</fsummary>
- <type>
- <v>Resource = #objref</v>
- <v>Return = Vote | {'EXCEPTION', E}</v>
- <v>Vote = 'VoteReadOnly' | 'VoteCommit' | 'VoteRollback'</v>
- <v>E = #'CosTransactions_HeuristicMixed'{} | #'CosTransactions_HeuristicHazard'{}</v>
- </type>
- <desc>
- <p>This operation is invoked on the Resource to begin the two-phase commit protocol.</p>
- <p>The Resource can reply:</p>
- <list type="bulleted">
- <item>'VoteReadOnly' - if no persistent data has been modified by the transaction.
- The Resource can forget all knowledge of the transaction. </item>
- <item>'VoteCommit' - if the Resource has been prepared and is able to write all the
- data needed to commit the transaction to stable storage.</item>
- <item>'VoteRollback' - under any circumstances but must do so if none of the alternatives above
- are applicable.</item>
- <item>Heuristic Exception - if a Heuristic decision is made which differ
- from the true outcome of the transaction. The Resource must remember
- the Heuristic outcome until the <c>forget</c> operation is performed.</item>
- </list>
- </desc>
- </func>
- <func>
- <name>rollback(Resource) -> Return</name>
- <fsummary>Instruct the target object to rollback the transaction</fsummary>
- <type>
- <v>Resource = #objref</v>
- <v>Return = ok | {'EXCEPTION', E}</v>
- <v>E = #'CosTransactions_HeuristicCommit'{} | #'CosTransactions_HeuristicMixed'{} | #'CosTransactions_HeuristicHazard'{}</v>
- </type>
- <desc>
- <p>This operation instructs the Resource to rollback all changes made as a part of the transaction.</p>
- <p>The Resource can raise:</p>
- <list type="bulleted">
- <item>Heuristic Exception - if a Heuristic decision is made which differ
- from the true outcome of the transaction. The Resource must remember
- the Heuristic outcome until the <c>forget</c> operation is performed.</item>
- </list>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosTransactions/doc/src/CosTransactions_SubtransactionAwareResource.xml b/lib/cosTransactions/doc/src/CosTransactions_SubtransactionAwareResource.xml
deleted file mode 100644
index 30102d18d9..0000000000
--- a/lib/cosTransactions/doc/src/CosTransactions_SubtransactionAwareResource.xml
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1999</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>CosTransactions_SubtransactionAwareResource</title>
- <prepared></prepared>
- <docno></docno>
- <checked></checked>
- <date>1999-04-12</date>
- <rev>PA1</rev>
- </header>
- <module>CosTransactions_SubtransactionAwareResource</module>
- <modulesummary>This module implements the OMG CosTransactions::SubtransactionAwareResource interface.</modulesummary>
- <description>
- <p>This interface inherits the CosTransactions::Resource interface. Hence,
- it must also support all operations defined in the Resource interface.</p>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosTransactions/include/CosTransactions.hrl").</c></p>
- </description>
- <funcs>
- <func>
- <name>commit_subtransaction(SubtransactionAwareResource, Coordinator) -> Return</name>
- <fsummary>Notify the target object that the transaction has committed</fsummary>
- <type>
- <v>SubtransactionAwareResource = #objref</v>
- <v>Coordinator = #objref</v>
- <v>Return = ok</v>
- </type>
- <desc>
- <p>If the <c>SubtransactionAwareResource</c> have been registered with a <em>subtransaction</em>
- using the operation <c>CosTransactions_Coordinator:register_subtran_aware/2</c>,
- it will be notified when the transaction has committed.</p>
- <note>
- <p>The results of a committed subtransaction are relative to the completion of its ancestor
- transactions, that is, these results can be undone if any ancestor transaction is rolled back.</p>
- </note>
- </desc>
- </func>
- <func>
- <name>rollback_subtransaction(SubtransactionAwareResource) -> Return</name>
- <fsummary>Notify the target object that the transaction has been rolled back</fsummary>
- <type>
- <v>SubtransactionAwareResource = #objref</v>
- <v>Return = ok</v>
- </type>
- <desc>
- <p>If the <c>SubtransactionAwareResource</c> have been registered with a transactions
- using the operation <c>CosTransactions_Coordinator:register_subtran_aware/2</c>
- it will be notified when the transaction has rolled back.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosTransactions/doc/src/CosTransactions_Synchronization.xml b/lib/cosTransactions/doc/src/CosTransactions_Synchronization.xml
deleted file mode 100644
index c21e7c559d..0000000000
--- a/lib/cosTransactions/doc/src/CosTransactions_Synchronization.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1999</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosTransactions_Synchronization</title>
- <prepared>Niclas Eklund</prepared>
- <responsible>Niclas Eklund</responsible>
- <docno></docno>
- <approved>Niclas Eklund</approved>
- <checked></checked>
- <date>1999-04-12</date>
- <rev>PA1</rev>
- </header>
- <module>CosTransactions_Synchronization</module>
- <modulesummary>This module implements the OMG CosTransactions::Synchronization interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosTransactions/CosTransactions.hrl").</c></p>
- </description>
- <funcs>
- <func>
- <name>before_completion(Synchronization) -> Return</name>
- <fsummary>Notify the target object that the transaction is about to enter the prepare phase</fsummary>
- <type>
- <v>Synchronization = #objref</v>
- <v>Return = ok</v>
- </type>
- <desc>
- <p>If the target object is a transaction using the operation <c>register_synchronization/2</c>
- it will be notified to perform necessary processing prior to the prepare phase.</p>
- </desc>
- </func>
- <func>
- <name>after_completion(Synchronization) -> Return</name>
- <fsummary>Notify the target object that the transaction is completed</fsummary>
- <type>
- <v>Synchronization = #objref</v>
- <v>Return = ok</v>
- </type>
- <desc>
- <p>If the target object is a transaction using the operation <c>register_synchronization/2</c>
- it will be notified to perform necessary processing after terminating the transaction.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosTransactions/doc/src/CosTransactions_Terminator.xml b/lib/cosTransactions/doc/src/CosTransactions_Terminator.xml
deleted file mode 100644
index f75f4d912d..0000000000
--- a/lib/cosTransactions/doc/src/CosTransactions_Terminator.xml
+++ /dev/null
@@ -1,73 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1999</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosTransactions_Terminator</title>
- <prepared>Niclas Eklund</prepared>
- <responsible>Niclas Eklund</responsible>
- <docno></docno>
- <approved>Niclas Eklund</approved>
- <checked></checked>
- <date>1999-04-12</date>
- <rev>PA1</rev>
- </header>
- <module>CosTransactions_Terminator</module>
- <modulesummary>This module implements the OMG CosTransactions::Terminator interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosTransactions/include/CosTransactions.hrl").</c></p>
- </description>
- <funcs>
- <func>
- <name>commit(Terminator, ReportHeuristics) -> Return</name>
- <fsummary>Try to commit a transaction</fsummary>
- <type>
- <v>Terminator = #objref</v>
- <v>ReportHeuristics = boolean()</v>
- <v>Return = ok | {'EXCEPTION', E}</v>
- <v>E = #'CosTransactions_HeuristicMixed'{} | #'CosTransactions_HeuristicHazrd'{} | #'CosTransactions_TransactionRolledBack'{}</v>
- </type>
- <desc>
- <p>This operation initiates the two-phase commit protocol. If the transaction has not been marked
- <c>'rollback only'</c> and all the participants agree to commit, the operation terminates normally. Otherwise,
- the TransactionRolledBack is raised. If the parameter <c>ReportHeuristics</c> is true and inconsistent
- outcomes by raising an Heuristic Exception.</p>
- </desc>
- </func>
- <func>
- <name>rollback(Terminator) -> Return</name>
- <fsummary>Rollback a transaction</fsummary>
- <type>
- <v>Terminator = #objref</v>
- <v>Return = ok</v>
- </type>
- <desc>
- <p>This operation roles back the transaction. </p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosTransactions/doc/src/CosTransactions_TransactionFactory.xml b/lib/cosTransactions/doc/src/CosTransactions_TransactionFactory.xml
deleted file mode 100644
index c4469ef850..0000000000
--- a/lib/cosTransactions/doc/src/CosTransactions_TransactionFactory.xml
+++ /dev/null
@@ -1,64 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1999</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosTransactions_TransactionFactory</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>1999-04-12</date>
- <rev>PA1</rev>
- </header>
- <module>CosTransactions_TransactionFactory</module>
- <modulesummary>This module implements the OMG CosTransactions::TransactionFactory interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosTransactions/include/CosTransactions.hrl").</c></p>
- </description>
- <funcs>
- <func>
- <name>create(TransactionFactory, Timeout) -> Control</name>
- <fsummary>Create a new top-level transaction</fsummary>
- <type>
- <v>TransactionFactory = #objref</v>
- <v>Timeout = integer()</v>
- <v>Control = #objref</v>
- </type>
- <desc>
- <p>This operation creates a new top-level transaction.</p>
- <p>The <c>Timeout</c> argument can be:</p>
- <list type="bulleted">
- <item>0 - no timeout.</item>
- <item>N (integer() > 0) - the transaction will be subject to being rolled back
- if it does not complete before N seconds have elapsed.</item>
- </list>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosTransactions/doc/src/CosTransactions_TransactionalObject.xml b/lib/cosTransactions/doc/src/CosTransactions_TransactionalObject.xml
deleted file mode 100644
index 319da2bd16..0000000000
--- a/lib/cosTransactions/doc/src/CosTransactions_TransactionalObject.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1999</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>CosTransactions_TransactionalObject</title>
- <prepared></prepared>
- <docno></docno>
- <checked></checked>
- <date>1999-04-12</date>
- <rev>PA1</rev>
- </header>
- <module>CosTransactions_TransactionalObject</module>
- <modulesummary>This module implements the OMG CosTransactions::TransactionalObject interface.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosTransactions/CosTransactions.hrl").</c></p>
- <p>The TransactionalObject interface is used by an object to indicate that it is transactional.
- By supporting this interface, an object indicates that it wants the transaction context associated with
- the client to be associated with all operation on its interface. No operations are defined.</p>
- </description>
-
-</erlref>
-
diff --git a/lib/cosTransactions/doc/src/Makefile b/lib/cosTransactions/doc/src/Makefile
deleted file mode 100644
index 3c054593a9..0000000000
--- a/lib/cosTransactions/doc/src/Makefile
+++ /dev/null
@@ -1,142 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1999-2017. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../../vsn.mk
-VSN=$(COSTRANSACTIONS_VSN)
-APPLICATION=cosTransactions
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-XML_APPLICATION_FILES = ref_man.xml
-XML_REF3_FILES = \
- cosTransactions.xml \
- CosTransactions_Control.xml \
- CosTransactions_Coordinator.xml \
- CosTransactions_RecoveryCoordinator.xml \
- CosTransactions_Resource.xml \
- CosTransactions_SubtransactionAwareResource.xml \
- CosTransactions_Terminator.xml \
- CosTransactions_TransactionFactory.xml
-# CosTransactions_Synchronization.xml
-
-XML_PART_FILES = \
- part.xml
-XML_CHAPTER_FILES = \
- ch_contents.xml \
- ch_introduction.xml \
- ch_install.xml \
- ch_example.xml \
- ch_skeletons.xml \
- notes.xml
-
-BOOK_FILES = book.xml
-
-XML_FILES = $(BOOK_FILES) $(XML_APPLICATION_FILES) $(XML_REF3_FILES) \
- $(XML_PART_FILES) $(XML_CHAPTER_FILES)
-
-TECHNICAL_DESCR_FILES =
-
-GIF_FILES =
-
-PS_FILES =
-
-# ----------------------------------------------------
-
-INTERNAL_HTML_FILES = $(TECHNICAL_DESCR_FILES:%.xml=$(HTMLDIR)/%.html)
-
-HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \
- $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html)
-
-INFO_FILE = ../../info
-EXTRA_FILES = \
- $(DEFAULT_GIF_FILES) \
- $(DEFAULT_HTML_FILES) \
- $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html) \
- $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html)
-
-MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-
-HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
-
-TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-XML_FLAGS +=
-DVIPS_FLAGS +=
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-$(HTMLDIR)/%.gif: %.gif
- $(INSTALL_DATA) $< $@
-
-docs: pdf html man
-
-$(TOP_PDF_FILE): $(XML_FILES)
-
-pdf: $(TOP_PDF_FILE)
-
-html: gifs $(HTML_REF_MAN_FILE)
-
-clean clean_docs:
- rm -rf $(HTMLDIR)/*
- rm -f $(MAN3DIR)/*
- rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
- rm -f errs core *~
-
-man: $(MAN3_FILES)
-
-gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
-
-$(INDEX_TARGET): $(INDEX_SRC)
- sed -e 's;%VSN%;$(VSN);' $(INDEX_SRC) > $(INDEX_TARGET)
-
-debug opt:
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_docs_spec: docs
- $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
- $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
- $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
- $(INSTALL_DATA) $(HTMLDIR)/* \
- "$(RELSYSDIR)/doc/html"
- $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
- $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
- $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
-
-release_spec:
diff --git a/lib/cosTransactions/doc/src/book.xml b/lib/cosTransactions/doc/src/book.xml
deleted file mode 100644
index 33a8c323bb..0000000000
--- a/lib/cosTransactions/doc/src/book.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE book SYSTEM "book.dtd">
-
-<book xmlns:xi="http://www.w3.org/2001/XInclude">
- <header titlestyle="normal">
- <copyright>
- <year>1999</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosTransactions</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>1999-04-14</date>
- <rev>2.0</rev>
- </header>
- <insidecover>
- </insidecover>
- <pagetext>cosTransactions</pagetext>
- <preamble>
- <contents level="2"></contents>
- </preamble>
- <parts lift="no">
- <xi:include href="part.xml"/>
- </parts>
- <applications>
- <xi:include href="ref_man.xml"/>
- </applications>
- <releasenotes>
- <xi:include href="notes.xml"/>
- </releasenotes>
- <listofterms></listofterms>
- <index></index>
-</book>
-
diff --git a/lib/cosTransactions/doc/src/ch_contents.xml b/lib/cosTransactions/doc/src/ch_contents.xml
deleted file mode 100644
index 9b2832a032..0000000000
--- a/lib/cosTransactions/doc/src/ch_contents.xml
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1999</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>The cosTransactions Application</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>1999-04-14</date>
- <rev>B</rev>
- <file>ch_contents.xml</file>
- </header>
-
- <section>
- <title>Content Overview</title>
- <p>The cosTransactions documentation is divided into three sections:
- </p>
- <list type="bulleted">
- <item>
- <p>PART ONE - The User's Guide
- <br></br>
-Description of the cosTransactions Application including
- services and a small tutorial demonstrating
- the development of a simple service.</p>
- </item>
- <item>
- <p>PART TWO - Release Notes
- <br></br>
-A concise history of cosTransactions.</p>
- </item>
- <item>
- <p>PART THREE - The Reference Manual
- <br></br>
- A quick reference guide, including a
- brief description, to all the functions available in cosTransactions.</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Brief Description of the User's Guide</title>
- <p>The User's Guide contains the following parts:</p>
- <list type="bulleted">
- <item>
- <p>cosTransactions overview</p>
- </item>
- <item>
- <p>cosTransactions installation</p>
- </item>
- <item>
- <p>A tutorial example</p>
- </item>
- </list>
- </section>
-</chapter>
-
diff --git a/lib/cosTransactions/doc/src/ch_example.xml b/lib/cosTransactions/doc/src/ch_example.xml
deleted file mode 100644
index a2451e5fbc..0000000000
--- a/lib/cosTransactions/doc/src/ch_example.xml
+++ /dev/null
@@ -1,283 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1999</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosTransactions Examples</title>
- <prepared></prepared>
- <docno></docno>
- <date>1999-04-27</date>
- <rev>A</rev>
- <file>ch_example.xml</file>
- </header>
-
- <section>
- <title>A Tutorial on How to Create a Simple Service</title>
-
- <section>
- <title>Interface design</title>
- <p>To use the cosTransactions application <em>participants</em> must be implemented.
- There are two types of participants: </p>
- <list type="bulleted">
- <item><seealso marker="CosTransactions_Resource">CosTransactions_Resource</seealso> - operations used to commit or rollback resources.</item>
- <item><seealso marker="CosTransactions_SubtransactionAwareResource">CosTransactions_SubtransactionAwareResource</seealso> -
- operations used when the resources want to be notified when a subtransaction commits.
- This interface inherits the CosTransactions_Resource</item>
- </list>
- <p>The interfaces for these participants are defined in <em>CosTransactions.idl</em></p>
- </section>
-
- <section>
- <title>Generating a Participant Interface</title>
- <p>We start by creating an interface which inherits from <em>CosTransactions::Resource</em>. Hence,
- we must also implement all operations defined in the Resource interface. The IDL-file could look like: </p>
- <code type="c"><![CDATA[
-#ifndef _OWNRESOURCEIMPL_IDL
-#define _OWNRESOURCEIMPL_IDL
-#include <CosTransactions.idl>
-
-module ownResourceImpl {
-
- interface ownInterface:CosTransactions::Resource {
-
- void ownFunctions(in any NeededArguments)
- raises(Systemexceptions,OwnExceptions);
-
- };
-};
-
-#endif
- ]]></code>
- <p>Run the IDL compiler on this file by calling the <c>ic:gen/1</c> function.
- This will produce the API named <c>ownResourceImpl_ownInterface.erl</c>.
- After generating the API stubs and the server skeletons it is time to
- implement the servers and if no special options are sent
- to the IDl compiler the file name is <c>ownResourceImpl_ownInterface_impl.erl</c>.</p>
- </section>
-
- <section>
- <title>Implementation of Participant interface</title>
- <p>If the participant is intended to be a plain Resource, we must implement the following operations:</p>
- <list type="bulleted">
- <item><c>prepare/1</c> - this operation is invoked on the Resource to begin the two-phase commit protocol.</item>
- <item><c>rollback/1</c> - this operation instructs the Resource to rollback all changes made as a part of the transaction. </item>
- <item><c>commit/1</c> - this operation instructs the Resource to commit all changes made as a part of the transaction.</item>
- <item><c>commit_one_phase/1</c> - if possible, the Resource should commit all changes made as part of the transaction.
- This operation can only be used if the Resource is the only child of its parent. </item>
- <item><c>forget/1</c> - this operation informs the Resource that it is safe to forget any
- <term id="Heuristic decisions"><termdef>Heuristic decisions is a unilateral decision by a participant to commit
- or rollback without receiving the true outcome of the transaction from its parent's coordinator.</termdef></term>
- and the knowledge of the transaction.</item>
- <item><c>ownFunctions</c> - all application specific operations.</item>
- </list>
- <p>If the participant wants to be notified when a subtransaction commits, we must also implement the following operations
- (besides the operations above):</p>
- <list type="bulleted">
- <item><c>commit_subtransaction/2</c> - if the <c>SubtransactionAwareResource</c> have been registered
- with a transactions using the operation <c>CosTransactions_Coordinator:register_subtran_aware/2</c> it will
- be notified when the transaction has
- committed. </item>
- <item><c>rollback_subtransaction/1</c> - if the <c>SubtransactionAwareResource</c> have been registered
- with a transactions using the operation <c>CosTransactions_Coordinator:register_subtran_aware/2</c>
- it will be notified when the transaction has
- rolled back. </item>
- </list>
- <note>
- <p>The results of a committed subtransaction are relative to the completion of its ancestor transactions,
- that is, these results can be undone if any ancestor transaction is rolled back. </p>
- </note>
- </section>
-
- <section>
- <title>Participant Operations Behavior</title>
- <p>Each application participant must behave in a certain way to ensure that the two-phase commit protocol
- can complete the transactions correctly.</p>
-
- <section>
- <title>prepare</title>
- <p>This operation ask the participant to vote on the outcome of the transaction. Possible replies are:</p>
- <list type="bulleted">
- <item><em>'VoteReadOnly'</em> - if no data associated with the transaction has been modified VoteReadOnly may be returned.
- The Resource can forget all knowledge of the transaction and terminate.</item>
- <item><em>'VoteCommit'</em> - if the Resource is able to write all the data needed to commit the transaction to a stable storage,
- VoteCommit may be returned. The Resource will then wait until it is informed of the outcome of the transaction.
- The Resource may, however, make a unilateral decision (Heuristic) to commit or rollback changes associated
- with the transaction. When the Resource is informed of the true outcome (rollback/commit) and it is equal to
- the Heuristic decision the Resource just return 'ok'. But, if there is a mismatch and the commit-operation is irreversible,
- the Resource must raise a <seealso marker="CosTransactions_Resource">Heuristic Exception</seealso> and wait
- until the <c>forget</c> operation is invoked. The Heuristic Decision must be recorded in stable storage.</item>
- <item><em>'VoteRollback'</em> - the Resource may vote VoteRollback under any circumstances.
- The Resource can forget all knowledge of the transaction and terminate.</item>
- </list>
- <note>
- <p>Before replying to the prepare operation, the Resource must record the prepare state, the reference of its
- superior <seealso marker="CosTransactions_RecoveryCoordinator">RecoveryCoordinator</seealso> in stable storage.
- The RecoveryCoordinator is obtained when registering as a participant in a transaction.</p>
- </note>
- </section>
-
- <section>
- <title>rollback</title>
- <p>The Resource should, if necessary, rollback all changes made as part of the transaction. If the Resource is not aware of the
- transaction it should do nothing, e.g., recovered after a failure and have no data in stable storage. Heuristic Decisions
- must be handled as described above.</p>
- </section>
-
- <section>
- <title>commit</title>
- <p>The Resource should, if necessary, commit all changes made as part of the transaction. If the Resource is not aware of the
- transaction it should do nothing, e.g., recovered after a failure and have no data in stable storage. Heuristic Decisions
- must be handled as described above.</p>
- </section>
-
- <section>
- <title>commit_one_phase</title>
- <p>If possible, the Resource should commit all changes made as part of the transaction. If it cannot, it should raise the
- TRANSACTION_ROLLEDBACK exception. This operation can only be used if the Resource is the only child of its parent.
- If a failure occurs the completion of the operation must be retried when the failure is repaired. Heuristic Decisions
- must be handled as described above.</p>
- </section>
-
- <section>
- <title>forget</title>
- <p>If the Resource raised a Heuristic Exception to <c>commit</c>, <c>rollback</c> or <c>commit_one_phase</c> this operation
- will be performed. The Resource can forget all knowledge of the transaction and terminate.</p>
- </section>
-
- <section>
- <title>commit_subtransaction</title>
- <p>If the <c>SubtransactionAwareResource</c> have been registered with a <em>subtransaction</em>
- using the operation <c>CosTransactions_Coordinator:register_subtran_aware/2</c>
- it will be notified when the transaction has committed. The Resource may raise the exception
- <c>'TRANSACTION_ROLLEDBACK'</c>.</p>
- <note>
- <p>The result of a committed subtransaction is relative to the completion of its ancestor
- transactions, that is, these results can be undone if any ancestor transaction is rolled back.</p>
- </note>
- </section>
-
- <section>
- <title>rollback_subtransaction</title>
- <p>If the <c>SubtransactionAwareResource</c> have been registered with a <em>subtransaction</em>
- using the operation <c>CosTransactions_Coordinator:register_subtran_aware/2</c>
- it will be notified when the subtransaction has rolled back.</p>
- </section>
- </section>
-
- <section>
- <title>How to Run Everything</title>
- <p>Below is a short transcript on how to run cosTransactions. </p>
- <code type="none">
-
-%% Start Mnesia and Orber
-mnesia:delete_schema([node()]),
-mnesia:create_schema([node()]),
-orber:install([node()]),
-application:start(mnesia),
-application:start(orber),
-
-%% Register CosTransactions in the IFR.
-'oe_CosTransactions':'oe_register'(),
-
-%% Register the application specific Resource implementations
-%% in the IFR.
-'oe_ownResourceImpl':'oe_register'(),
-
-%%-- Set parameters --
-%% Timeout can be either 0 (no timeout) or an integer N > 0.
-%% The later state that the transaction should be rolled
-%% back if the transaction have not completed within N seconds.
-TimeOut = 0,
-
-%% Do we want the transaction to report Heuristic Exceptions?
-%% This variable must be boolean and indicates the way the
-%% Terminator should behave.
-Heuristics = true,
-
-%% Start the cosTransactions application.
-cosTransactions:start(), %% or application:start(cosTransactions),
-
-%% Start a factory using the default configuration
-TrFac = cosTransactions:start_factory(),
-%% ... or use configuration parameters.
-TrFac = cosTransactions:start_factory([{typecheck, false}, {hash_max, 3013}]),
-
-%% Create a new top-level transaction.
-Control = 'CosTransactions_TransactionFactory':create(TrFac, TimeOut),
-
-%% Retrieve the Coordinator and Terminator object references from
-%% the Control Object.
-Term = 'CosTransactions_Control':get_terminator(Control),
-Coord = 'CosTransactions_Control':get_coordinator(Control),
-
-%% Create two SubTransactions with the root-Coordinator as parent.
-SubCont1 = 'CosTransactions_Coordinator':create_subtransaction(Coord),
-SubCont2 = 'CosTransactions_Coordinator':create_subtransaction(Coord),
-
-%% Retrieve the Coordinator references from the Control Objects.
-SubCoord1 = 'CosTransactions_Control':get_coordinator(SubCont1),
-SubCoord2 = 'CosTransactions_Control':get_coordinator(SubCont2),
-
-%% Create application Resources. We can, for example, start the Resources
-%% our selves or look them up in the naming service. This is application
-%% specific.
-Res1 = ...
-Res2 = ...
-Res3 = ...
-Res4 = ...
-
-%% Register Resources with respective Coordinator. Each call returns
-%% a RecoveryCoordinator object reference.
-RC1 = 'CosTransactions_Coordinator':register_resource(SubCoord1, Res1),
-RC2 = 'CosTransactions_Coordinator':register_resource(SubCoord1, Res2),
-RC3 = 'CosTransactions_Coordinator':register_resource(SubCoord2, Res3),
-RC4 = 'CosTransactions_Coordinator':register_resource(SubCoord2, Res4),
-
-%% Register Resource 4 with SubCoordinator 1 so that the Resource will be
-%% informed when the SubCoordinator commits or roll-back.
-'CosTransactions_Coordinator':register_subtran_aware(SubCoord1, Res4),
-
-%% We are now ready to try to commit the transaction. The second argument
-%% must be a boolean
-Outcome = (catch 'CosTransactions_Terminator':commit(Term, Heuristics)),
- </code>
- <note>
- <p>For the cosTransaction application to be able to recognize if a Resource is
- dead or in the process of restarting the Resource must be started as persistent,
- e.g., 'OwnResource':oe_create_link(Env, [{regname, {global, RegName}}, {persistent, true}]).
- For more information see the Orber documentation.</p>
- </note>
- <p>The outcome of the transaction can be:</p>
- <list type="bulleted">
- <item>ok - the transaction was successfully committed.</item>
- <item>{'EXCEPTION', HeuristicExc} - at least one participant made a
- Heuristic decision or, due to a failure, one or more participants
- where unreachable.</item>
- <item>{'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{}} -
- the transaction was successfully rolled back.</item>
- <item>Any system exception -
- the transaction failed with unknown reason.</item>
- </list>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosTransactions/doc/src/ch_install.xml b/lib/cosTransactions/doc/src/ch_install.xml
deleted file mode 100644
index 4270c320b5..0000000000
--- a/lib/cosTransactions/doc/src/ch_install.xml
+++ /dev/null
@@ -1,104 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1999</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Installing cosTransactions</title>
- <prepared></prepared>
- <docno></docno>
- <date>1999-04-20</date>
- <rev></rev>
- <file>ch_install.xml</file>
-</header>
-
- <section>
- <title>Installation Process </title>
- <p>This chapter describes how to install
- <seealso marker="cosTransactions">cosTransactions</seealso>
- in an Erlang Environment.
- </p>
-
- <section>
- <title>Preparation</title>
- <p>Before starting the installation process for cosTransactions,
- the application Orber must be running.</p>
- <p>The cosTransactions application must be able to log progress to disk. The log files are
- created in the current directory as "oe_name@machine_type_timestamp". Hence, <c>read</c> and
- <c>write</c> rights must be granted. If the transaction completes in an orderly fashion the
- logfiles are removed, but not if an error, which demands human intervention, occur.</p>
- </section>
-
- <section>
- <title>Configuration</title>
- <p>When using the Transaction Service the <c>cosTransactions</c> application
- must be started using either <c>cosTransactions:start()</c> or
- <c>application:start(cosTransactions)</c>.
- </p>
- <p>The following application configuration parameters exist:</p>
- <list type="bulleted">
- <item><c>maxRetries</c> - default is 40 times, i.e., if a transaction participant is unreachable
- the application will retry to contact it <c>N</c> times. Reaching the maximum is considered to be a disaster.</item>
- <item><c>comFailWait</c> - default is 5000 milliseconds, i.e., before the application
- retries to contact unreachable transaction participants the application wait <c>Time</c> milliseconds.</item>
- </list>
- <p>Then the <seealso marker="CosTransactions_TransactionFactory">Transaction Factory</seealso>
- must be started:</p>
- <list type="bulleted">
- <item><c>cosTransactions:start_factory()</c> - starts and returns a reference to a factory using default configuration parameters.</item>
- <item><c>cosTransactions:start_factory(Options)</c> - starts and returns a reference to a factory using given configuration parameters.</item>
- </list>
- <p>The following options exist:
- </p>
- <list type="bulleted">
- <item><c>{hash_max, HashValue}</c> -
- This value denotes the upper bound of the hash value the <seealso marker="CosTransactions_Coordinator">Coordinator</seealso> uses.
- Default is <c>1013</c>. HashValue must be an integer.</item>
- <item><c>{allow_subtr, Boolean}</c> -
- If set to true it is possible to create <seealso marker="CosTransactions_Coordinator">subtransactions</seealso>.
- Default is <c>true</c>.</item>
- <item><c>{typecheck, Boolean}</c> -
- If set to to true all transaction operation's arguments will be type-checked.
- Default is <c>true</c>.</item>
- <item><c>{tty, Boolean}</c> -
- Enables or disables error printouts to the tty.
- If Flag is false, all text that the error logger would have sent to the terminal is discarded.
- If Flag is true, error messages are sent to the terminal screen. </item>
- <item><c>{logfile, FileName}</c> -
- This function makes it possible to store all system information in <c>FileName</c> (string()).
- It can be used in combination with the tty(false) item to have a silent system,
- where all system information are logged to a file.
- As default no logfile is used.</item>
- <item><c>{maxRetries, Integer}</c> -
- default is 40 times, i.e., if a transaction participant is unreachable the application will
- retry to contact it <c>N</c> times. Reaching the maximum is considered to be a disaster.
- This option overrides the application configuration parameter.</item>
- <item><c>{comFailWait, Integer}</c> -
- default is 5000 milliseconds, i.e., before the application retries to contact unreachable
- transaction participants the application wait <c>Time</c> milliseconds.
- This option overrides the application configuration parameter.</item>
- </list>
- <p>The Factory is now ready to use. For a more detailed description see <seealso marker="ch_example">Examples</seealso>.
- </p>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosTransactions/doc/src/ch_introduction.xml b/lib/cosTransactions/doc/src/ch_introduction.xml
deleted file mode 100644
index 43d25360bc..0000000000
--- a/lib/cosTransactions/doc/src/ch_introduction.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1999</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Introduction to cosTransactions</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>1999-04-26</date>
- <rev></rev>
- <file>ch_introduction.xml</file>
-</header>
-
- <section>
- <title>Overview</title>
- <p>The cosTransactions application is a Transaction Service compliant with the <url href="http://www.omg.org">OMG</url>
- Transaction Service CosTransactions 1.1.
- </p>
-
- <section>
- <title>Purpose and Dependencies</title>
- <p><em>cosTransactions</em> is dependent on <em>Orber version 3.0.1</em> or later(see the Orber
- documentation), which provides CORBA functionality in an Erlang environment.</p>
- <p><em>cosTransactions</em> is dependent on <em>supervisor/stdlib-1.7</em> or later.</p>
- <p>Basically, cosTransaction implements a <em>two-phase commit protocol</em> and allows objects running
- on different platforms to participate in a transaction.</p>
- </section>
-
- <section>
- <title>Prerequisites</title>
- <p>To fully understand the concepts presented in the
- documentation, it is recommended that the user is familiar
- with distributed programming, CORBA and the Orber application.
- </p>
- <p>Recommended reading includes <em>CORBA, Fundamentals and Programming - Jon Siegel</em> and <em>Open Telecom Platform Documentation Set</em>. It is also helpful to have read
- <em>Concurrent Programming in Erlang</em> and, for example, <em>Transaction Processing: concepts and techniques - Jim Gray, Andreas Reuter</em>.</p>
- <note>
- <p>The cosTransaction application is compliant with the OMG CosTransactions specification 1.1. Using
- other vendors transaction service, compliant with the OMG CosTransactions specification 1.0, may
- not work since the <c>'TRANSACTION_REQUIRED', 'TRANSACTION_ROLLEDBACK'</c> and <c>'INVALID_TRANSACTION'</c>
- exceptions have been redefined to be system exceptions, i.e., used to be transaction-specific ('CosTransactions_Exc').</p>
- </note>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosTransactions/doc/src/ch_skeletons.xml b/lib/cosTransactions/doc/src/ch_skeletons.xml
deleted file mode 100644
index e101cff5da..0000000000
--- a/lib/cosTransactions/doc/src/ch_skeletons.xml
+++ /dev/null
@@ -1,214 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1999</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Resource Skeletons</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>1999-04-29</date>
- <rev></rev>
- <file>ch_skeletons.xml</file>
- </header>
-
- <section>
- <title>Resource Skeletons</title>
- <p>This chapter provides a skeleton for application Resources. For more information
- see the Orber documentation.</p>
- <code type="none">
-%%%-----------------------------------------------------------
-%%% File : Module_Interface_impl.erl
-%%% Author :
-%%% Purpose :
-%%% Created :
-%%%-----------------------------------------------------------
-
--module('Module_Interface_impl').
-
-%%--------------- INCLUDES -----------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("cosTransactions/include/CosTransactions.hrl").
-
-%%--------------- EXPORTS-------------------------------------
-%%- Inherit from CosTransactions::Resource -------------------
--export([prepare/2,
- rollback/2,
- commit/2,
- commit_one_phase/2,
- forget/2]).
-
-%%- Inherit from CosTransactions::SubtransactionAwareResource
--export([commit_subtransaction/3,
- rollback_subtransaction/2]).
-
-%%--------------- gen_server specific ------------------------
--export([init/1, terminate/2, code_change/3, handle_info/2]).
-
-%%------------------------------------------------------------
-%% function : gen_server specific
-%%------------------------------------------------------------
-init(Env) ->
- %% 'trap_exit' optional
- process_flag(trap_exit,true),
-
- %%--- Possible replies ---
- %% Reply and await next request
- {ok, State}.
-
- %% Reply and if no more requests within Time the special
- %% timeout message should be handled in the
- %% Module_Interface_impl:handle_info/2 call-back function (use the
- %% IC option {{handle_info, "Module::Interface"}, true}).
- {ok, State, TimeOut}.
-
- %% Return ignore in order to inform the parent, especially if it is a
- %% supervisor, that the server, as an example, did not start in
- %% accordance with the configuration data.
- ignore.
-
- %% If the initializing procedure fails, the reason
- %% is supplied as StopReason.
- {stop, StopReason}.
-
-
-terminate(Reason, State) ->
- ok.
-
-code_change(OldVsn, State, Extra) ->
- {ok, NewState}.
-
-%% If use IC option {{handle_info, "Module::Interface"}, true}
-handle_info(Info, State) ->
- %%--- Possible replies ---
- %% Await the next invocation.
- {noreply, State}.
- %% Stop with Reason.
- {stop, Reason, State}.
-
-
-%%- Inherit from CosTransactions::Resource -------------------
-prepare(State) ->
-
- %%% Do application specific actions here %%%
-
- %%-- Reply: --
- %% If no data related to the transaction changed.
- {reply, 'VoteReadOnly', State}
- %% .. or (for example):
- {stop, normal, 'VoteReadOnly', State}.
-
- %% If able to commit
- {reply, 'VoteCommit', State}
-
- %% If not able to commit
- {reply, 'VoteRollback', State}
- %% .. or (for example):
- {stop, normal, 'VoteRollback', State}.
-
-rollback(State) ->
-
- %%% Do application specific actions here %%%
-
- %%-- Reply: --
- %% If able to rollback successfully
- {reply, ok, State}
- %% .. or (for example):
- {stop, normal, ok, State}.
-
- %% If Heuristic Decision. Raise exception:
- corba:raise(#'CosTransactions_HeuristicMixed' {})
- corba:raise(#'CosTransactions_HeuristicHazard' {})
- corba:raise(#'CosTransactions_HeuristicCommit'{})
-
-
-commit(State) ->
-
- %%% Do application specific actions here %%%
-
- %%-- Reply: --
- %% If able to commit successfully
- {reply, ok, State}
- %% .. or (for example):
- {stop, normal, ok, State}.
-
- %% If the prepare operation never been invoked:
- corba:raise(#'CosTransactions_NotPrepared'{})
-
- %% If Heuristic Decision. Raise exception:
- corba:raise(#'CosTransactions_HeuristicMixed' {})
- corba:raise(#'CosTransactions_HeuristicHazard' {})
- corba:raise(#'CosTransactions_HeuristicRollback'{})
-
-
-commit_one_phase(State) ->
-
- %%% Do application specific actions here %%%
-
- %%-- Reply: --
- %% If able to commit successfully
- {reply, ok, State}
- %% .. or (for example):
- {stop, normal, ok, State}.
-
- %% If fails. Raise exception:
- corba:raise(#'CosTransactions_HeuristicHazard' {})
-
- %% If able to rollback successfully
- corba:raise(#'CosTransactions_TransactionRolledBack' {})
-
-
-forget(State) ->
-
- %%% Do application specific actions here %%%
-
- %%-- Reply: --
- {reply, ok, State}.
- %% .. or (for example):
- {stop, normal, ok, State}.
-
-
-
-%%%%%% If the Resource is also supposed to be a %%%%%%
-%%%%%% SubtransactionAwareResource implement these. %%%%%%
-
-%%- Inherit from CosTransactions::SubtransactionAwareResource
-commit_subtransaction(State, Parent) ->
- %%% Do application specific actions here %%%
-
- %%-- Reply: --
- {reply, ok, State}.
- %% .. or (for example):
- {stop, normal, ok, State}.
-
-rollback_subtransaction(State) ->
- %%% Do application specific actions here %%%
-
- %%-- Reply: --
- {reply, ok, State}.
- %% .. or (for example):
- {stop, normal, ok, State}.
-
-%%--------------- END OF MODULE ------------------------------
- </code>
- </section>
-</chapter>
-
diff --git a/lib/cosTransactions/doc/src/cosTransactions.xml b/lib/cosTransactions/doc/src/cosTransactions.xml
deleted file mode 100644
index 772baaf18a..0000000000
--- a/lib/cosTransactions/doc/src/cosTransactions.xml
+++ /dev/null
@@ -1,142 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1999</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>cosTransactions</title>
- <prepared>Niclas Eklund</prepared>
- <responsible>Niclas Eklund</responsible>
- <docno></docno>
- <approved>Niclas Eklund</approved>
- <checked></checked>
- <date>1999-04-23</date>
- <rev>PA1</rev>
- </header>
- <module>cosTransactions</module>
- <modulesummary>The main module of the cosTransactions application.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-<c>-include_lib("cosTransactions/include/CosTransactions.hrl").</c></p>
- <p>This module contains the functions for starting and stopping the application.
- If the application is started using <c>application:start(cosTransactions)</c> the
- default configuration is used (see listing below). The Factory reference is stored using the CosNaming Service
- under the id <c>"oe_cosTransactionsFac_IPNo"</c>.</p>
- <p>The following application configuration parameters exist:</p>
- <list type="bulleted">
- <item><em>maxRetries</em> - default is 40 times, i.e., if a transaction participant is unreachable
- the application will retry to contact it <c>N</c> times. Reaching the maximum is considered to be a disaster.</item>
- <item><em>comFailWait</em> - default is 5000 milliseconds, i.e., before the application
- retries to contact unreachable transaction participants the application wait <c>Time</c> milliseconds.</item>
- </list>
- </description>
- <funcs>
- <func>
- <name>start() -> Return</name>
- <fsummary>Start the cosTransactions application</fsummary>
- <type>
- <v>Return = ok | {error, Reason}</v>
- </type>
- <desc>
- <p>This operation starts the cosTransactions application.</p>
- </desc>
- </func>
- <func>
- <name>stop() -> Return</name>
- <fsummary>Stop the cosTransactions application</fsummary>
- <type>
- <v>Return = ok | {error, Reason}</v>
- </type>
- <desc>
- <p>This operation stops the cosTransactions application.</p>
- </desc>
- </func>
- <func>
- <name>start_factory() -> TransactionFactory</name>
- <fsummary>Start a <c>Transaction Factory</c></fsummary>
- <type>
- <v>TransactionFactory = #objref</v>
- </type>
- <desc>
- <p>This operation creates a <seealso marker="CosTransactions_TransactionFactory">Transaction Factory</seealso>.
- The Factory is used to create a new top-level <seealso marker="CosTransactions_Control">transaction</seealso> using default options (see listing below).</p>
- </desc>
- </func>
- <func>
- <name>start_factory(FacDef) -> TransactionFactory</name>
- <fsummary>Start a <c>Transaction Factory</c>with given options</fsummary>
- <type>
- <v>FacDef = [Options], see Option listing below.</v>
- <v>TransactionFactory = #objref</v>
- </type>
- <desc>
- <p>This operation creates a <seealso marker="CosTransactions_TransactionFactory">Transaction Factory</seealso>.
- The Factory is used to create a new top-level transaction. </p>
- <p>The FacDef list must be a list of {Item, Value} tuples,
- where the following values are allowed: </p>
- <list type="bulleted">
- <item>{hash_max, HashValue} -
- This value denotes the upper bound of the hash value the
- <seealso marker="CosTransactions_Coordinator">Coordinator</seealso> uses.
- Default is <c>1013</c>. HashValue must be an integer.</item>
- <item>{allow_subtr, Boolean} -
- If set to true it is possible to create <seealso marker="CosTransactions_Coordinator">subtransactions</seealso>.
- Default is <c>true</c>.</item>
- <item>{typecheck, Boolean} -
- If set to to true all transaction operation's arguments will be type-checked.
- Default is <c>true</c>.</item>
- <item>{tty, Boolean} -
- Enables or disables error printouts to the tty.
- If Flag is false, all text that the error logger would have sent to the terminal is discarded.
- If Flag is true, error messages are sent to the terminal screen. </item>
- <item>{logfile, FileName} -
- This function makes it possible to store all system information in <c>FileName</c> (string()).
- It can be used in combination with the tty(false) item in to have a silent system,
- where all system information are logged to a file.
- As default no logfile is used.</item>
- <item><c>{maxRetries, Integer}</c> -
- default is 40 times, i.e., if a transaction participant is unreachable the application will
- retry to contact it <c>N</c> times. Reaching the maximum is considered to be a disaster.
- This option overrides the application configuration parameter.</item>
- <item><c>{comFailWait, Integer}</c> -
- default is 5000 milliseconds, i.e., before the application retries to contact unreachable
- transaction participants the application wait <c>Time</c> milliseconds.
- This option overrides the application configuration parameter.</item>
- </list>
- </desc>
- </func>
- <func>
- <name>stop_factory(TransactionFactory) -> Reply</name>
- <fsummary>Terminate the target object</fsummary>
- <type>
- <v>TransactionFactory = #objref</v>
- <v>Reply = ok | {'EXCEPTION', E}</v>
- </type>
- <desc>
- <p>This operation stop the target transaction factory.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/cosTransactions/doc/src/notes.xml b/lib/cosTransactions/doc/src/notes.xml
deleted file mode 100644
index 2401c04c3f..0000000000
--- a/lib/cosTransactions/doc/src/notes.xml
+++ /dev/null
@@ -1,407 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1999</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosTransactions Release Notes</title>
- <prepared>Niclas Eklund</prepared>
- <responsible>Niclas Eklund</responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>99-04-14</date>
- <rev>A</rev>
- <file>notes.xml</file>
- </header>
-
- <section><title>cosTransactions 1.3.3</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> Removed all old unused files in the documentation.
- </p>
- <p>
- Own Id: OTP-14475 Aux Id: ERL-409, PR-1493 </p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosTransactions 1.3.2</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Internal changes</p>
- <p>
- Own Id: OTP-13551</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosTransactions 1.3.1</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> Suppress Dialyzer warnings. </p>
- <p>
- Own Id: OTP-12862</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosTransactions 1.3</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> Remove the usage of erlang:now() from all Corba
- applications and use the new rand module instead of
- random. </p>
- <p>
- Own Id: OTP-12687</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosTransactions 1.2.14</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> The default encoding of Erlang files has been changed
- from ISO-8859-1 to UTF-8. </p> <p> The encoding of XML
- files has also been changed to UTF-8. </p>
- <p>
- Own Id: OTP-10907</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosTransactions 1.2.13</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Misc build updates</p>
- <p>
- Own Id: OTP-10784</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosTransactions 1.2.12</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>Erlang/OTP can now be built using parallel make if you
- limit the number of jobs, for instance using '<c>make
- -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not
- work at the moment because of some missing
- dependencies.</p>
- <p>
- Own Id: OTP-9451</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section>
- <title>cosTransactions 1.2.11</title>
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- Removed superfluous usage of shy in the documentation since it can cause problem if
- a buggy tool is used.</p>
- <p>
- Own Id: OTP-9319 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosTransactions 1.2.10</title>
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- Test suites published.</p>
- <p>
- Own Id: OTP-8543 Aux Id:</p>
- </item>
- </list>
- </section>
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>Added missing trailing bracket to define in hrl-file.</p>
- <p>Own id: OTP-8489 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosTransactions 1.2.9</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>The documentation EIX file was not generated.</p>
- <p>Own id: OTP-8355 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosTransactions 1.2.8</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- The documentation is now built with open source tools (xsltproc and fop)
- that exists on most platforms. One visible change is that the frames are removed.</p>
- <p>
- Own Id: OTP-8201 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosTransactions 1.2.7</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Obsolete guards, e.g. record vs is_record, has been changed
- to avoid compiler warnings.</p>
- <p>Own id: OTP-7987</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosTransactions 1.2.6</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Updated file headers.</p>
- <p>Own id: OTP-7837</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosTransactions 1.2.5</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Documentation source included in open source releases.</p>
- <p>Own id: OTP-7595</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosTransactions 1.2.4</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Updated file headers.</p>
- <p>Own id: OTP-7011</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosTransactions 1.2.3</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>The documentation source has been converted from SGML to XML.</p>
- <p>Own id: OTP-6754 Aux Id: </p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosTransactions 1.2.2</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Minor Makefile changes.</p>
- <p>Own id: OTP-6701 Aux Id: </p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosTransactions 1.2.1</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Removed some unused code.</p>
- <p>Own id: OTP-6527 Aux Id: </p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosTransactions 1.2</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>The stub/skeleton-files generated by IC have been improved,
- i.e., depending on the IDL-files, reduced the size of the
- erl- and beam-files and decreased dependencies off Orber's
- Interface Repository. It is necessary to re-compile all IDL-files
- and use COS-applications, including Orber, compiled with
- IC-4.2.</p>
- <p>Own id: OTP-4576</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosTransactions 1.1.2</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>To avoid un-necessary Heuristic decisions cosTransactions now
- recognize more systems exceptions.</p>
- <p>Own Id: OTP-4485</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosTransactions 1.1.1.1</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Updated internal documentation.</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosTransactions 1.1.1</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>cosTransactions is now able to handle upgrade properly.</p>
- <p>Own Id: -</p>
- </item>
- <item>
- <p>The cosTransactions factory now accepts <c>maxRetries</c> and
- <c>comFailWait</c> options, which overrides the configuration parameters.</p>
- <p>Own Id: -</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <list type="bulleted">
- <item>
- <p>The configuration parameters <c>comm_failure_wait</c> and <c>max_retries</c>
- changed to <c>maxRetries</c> and <c>comFailWait</c>. The default value for
- <c>maxRetries</c> have been raised from 20 to 40.</p>
- <p>Own Id: -</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>cosTransactions 1.1</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>First release of the cosTransactions application.</p>
- <p>Own Id: OTP-1741</p>
- </item>
- </list>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/cosTransactions/doc/src/part.xml b/lib/cosTransactions/doc/src/part.xml
deleted file mode 100644
index 6777d7d979..0000000000
--- a/lib/cosTransactions/doc/src/part.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE part SYSTEM "part.dtd">
-
-<part xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>1999</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosTransactions User's Guide</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>1999-04-20</date>
- <rev>2.2</rev>
- </header>
- <description>
- <p>The <em>cosTransactions</em> application is an Erlang implementation
- of the OMG CORBA Transaction Service.</p>
- </description>
- <xi:include href="ch_contents.xml"/>
- <xi:include href="ch_introduction.xml"/>
- <xi:include href="ch_install.xml"/>
- <xi:include href="ch_example.xml"/>
- <xi:include href="ch_skeletons.xml"/>
-</part>
-
diff --git a/lib/cosTransactions/doc/src/ref_man.xml b/lib/cosTransactions/doc/src/ref_man.xml
deleted file mode 100644
index 9d296967b3..0000000000
--- a/lib/cosTransactions/doc/src/ref_man.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE application SYSTEM "application.dtd">
-
-<application xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>1999</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>cosTransactions Reference Manual</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>1999-04-14</date>
- <rev>2.0</rev>
- </header>
- <description>
- <p>The <em>cosTransactions</em> application is an Erlang implementation
- of the OMG CORBA Transaction Service.</p>
- </description>
- <xi:include href="cosTransactions.xml"/>
- <xi:include href="CosTransactions_Control.xml"/>
- <xi:include href="CosTransactions_Coordinator.xml"/>
- <xi:include href="CosTransactions_RecoveryCoordinator.xml"/>
- <xi:include href="CosTransactions_Resource.xml"/>
- <xi:include href="CosTransactions_SubtransactionAwareResource.xml"/>
- <xi:include href="CosTransactions_Terminator.xml"/>
- <xi:include href="CosTransactions_TransactionFactory.xml"/>
-</application>
-
diff --git a/lib/cosTransactions/ebin/.gitignore b/lib/cosTransactions/ebin/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosTransactions/ebin/.gitignore
+++ /dev/null
diff --git a/lib/cosTransactions/examples/Makefile b/lib/cosTransactions/examples/Makefile
deleted file mode 100644
index 57a51f5932..0000000000
--- a/lib/cosTransactions/examples/Makefile
+++ /dev/null
@@ -1,158 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1999-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-
-EBIN= ../ebin
-
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(COSTRANSACTIONS_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/cosTransactions-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-
-INETRC_EXAMPLE = \
-# inetrc
-
-IDL_FILES = \
-# hotel.idl \
-# travelAgency.idl
-
-GEN_ERL_MODULES = \
-# oe_travelAgency \
-# travelAgency_book \
-
-MODULES= \
-# travelAgency_book_impl \
-
-GEN_HRL_FILES = \
-# oe_travelAgency.hrl \
-# travelAgency_book.hrl
-
-HRL_FILES=
-
-ERL_FILES= $(MODULES:%=%.erl)
-
-JAVA_CLASSES = \
-# HotelResource
-
-JAVA_FILES= $(JAVA_CLASSES:%=%.java)
-CLASS_FILES= $(JAVA_CLASSES:%=%.class)
-
-TARGET_FILES = \
- $(GEN_ERL_MODULES:%=$(EBIN)/%.$(EMULATOR)) \
- $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-
-
-ifeq ($(findstring sparc-sun-solaris2, $(TARGET)),sparc-sun-solaris2)
- JAVA_TARGET=java
-endif
-
-# ----------------------------------------------------
-# PROGRAMS
-# ----------------------------------------------------
-JAVA_IDL = idl
-LOCAL_CLASSPATH = $(ERL_TOP)/lib/cosTransactions/priv:$(ERL_TOP)/lib/cosTransactions/examples/java_output:$(ERL_TOP)/lib/cosTransactions/src:$(ERL_TOP)/lib/cosTransactions/examples:$(ERL_TOP)/lib/cosTransactions/examples/java_output/hotel
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_IDL_FLAGS += -pa /clearcase/otp/libraries/cosTransactions/ebin -pa /clearcase/otp/libraries/ic/ebin
-# includes from other directories than ../include .
-ERL_COMPILE_FLAGS += \
- $(ERL_IDL_FLAGS) \
- -pa /clearcase/otp/libraries/cosTransactions -I/clearcase/otp/libraries/cosTransactions
-YRL_FLAGS =
-
-JAVA_OPTIONS = -classpath ../priv:/opt/local/pgm/OrbixWeb2.0.1
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-tests debug opt: $(TARGET_FILES) $(JAVA_TARGET)
-
-java: java_costransactions_idl java_objects
-# java_hotel_idl
-
-clean:
- rm -f $(TARGET_FILES) $(GEN_ERL_MODULES:%=%.erl) $(GEN_HRL_FILES) $(CLASS_FILES)
- rm -rf java_costransactions_idl
- rm -rf java_output/*
- rm -f errs core *~
-# rm -rf java_hotel_idl
-
-docs:
-
-java_costransactions_idl:
- $(JAVA_IDL) ../src/CosTransactions.idl
- @if [ -d java_output ]; then \
- echo "compiling java classes for CosTransactions ... This will take a while!!"; \
- CLASSPATH="${CLASSPATH}:${LOCAL_CLASSPATH}"; \
- export CLASSPATH;\
- (cd java_output/CosTransactions; $(JAVA) *.java;); \
- fi
- @touch java_costransactions_idl
-
-#java_hotel_idl:
-# $(JAVA_IDL) hotel.idl
-# @if [ -d java_output ]; then \
-# echo "compiling java classes for hotel ..."; \
-# CLASSPATH="${CLASSPATH}:${LOCAL_CLASSPATH}"; \
-# export CLASSPATH;\
-# (cd java_output/hotel; $(JAVA) *.java;); \
-# fi
-# @touch java_hotel_idl
-
-#java_objects:
-# @if [ -d java_output ]; then \
-# echo "compiling java example files ..."; \
-# CLASSPATH="${CLASSPATH}:${LOCAL_CLASSPATH}"; \
-# export CLASSPATH;\
-# $(JAVA) *.java; \
-# fi
-# @touch java_hotel_resource
-
-#oe_travelAgency.erl: travelAgency.idl
-# erlc $(ERL_IDL_FLAGS) travelAgency.idl
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/examples"
- $(INSTALL_DATA) $(ERL_FILES) $(JAVA_FILES) $(IDL_FILES) "$(RELSYSDIR)/examples"
- $(INSTALL_DATA) $(INETRC_EXAMPLE) "$(RELSYSDIR)/examples"
- @tar cf - java_output | (cd $(RELSYSDIR); tar xf -)
-
-release_docs_spec:
diff --git a/lib/cosTransactions/include/.gitignore b/lib/cosTransactions/include/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosTransactions/include/.gitignore
+++ /dev/null
diff --git a/lib/cosTransactions/info b/lib/cosTransactions/info
deleted file mode 100644
index e5d7c53ac0..0000000000
--- a/lib/cosTransactions/info
+++ /dev/null
@@ -1,2 +0,0 @@
-group: orb
-short: Orber OMG Transaction Service
diff --git a/lib/cosTransactions/priv/.gitignore b/lib/cosTransactions/priv/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/cosTransactions/priv/.gitignore
+++ /dev/null
diff --git a/lib/cosTransactions/src/CosTransactions.cfg b/lib/cosTransactions/src/CosTransactions.cfg
deleted file mode 100644
index 05709d21cf..0000000000
--- a/lib/cosTransactions/src/CosTransactions.cfg
+++ /dev/null
@@ -1,15 +0,0 @@
-{this, "CosTransactions::Coordinator"}.
-{this, "CosTransactions::RecoveryCoordinator"}.
-{this, "CosTransactions::Terminator"}.
-{this, "CosTransactions::Control"}.
-{this, "CosTransactions::Resource"}.
-{this, "CosTransactions::TransactionFactory"}.
-{{handle_info, "CosTransactions::Terminator"}, true}.
-{{handle_info, "CosTransactions::TransactionFactory"}, true}.
-{this, "ETraP::Server"}.
-{{handle_info, "ETraP::Server"}, true}.
-{{impl, "CosTransactions::Coordinator"}, "ETraP_Server_impl"}.
-{{impl, "CosTransactions::RecoveryCoordinator"}, "ETraP_Server_impl"}.
-{{impl, "CosTransactions::Control"}, "ETraP_Server_impl"}.
-{{impl, "CosTransactions::Resource"}, "ETraP_Server_impl"}.
-{timeout,"CosTransactions::RecoveryCoordinator"}.
diff --git a/lib/cosTransactions/src/CosTransactions.idl b/lib/cosTransactions/src/CosTransactions.idl
deleted file mode 100644
index 11ec5cbf5b..0000000000
--- a/lib/cosTransactions/src/CosTransactions.idl
+++ /dev/null
@@ -1,193 +0,0 @@
-#ifndef _COSTRANSACTIONS_IDL
-#define _COSTRANSACTIONS_IDL
-
-#pragma prefix "omg.org"
-
-module CosTransactions {
-
-// DATATYPES
- enum Status {
- StatusActive,
- StatusMarkedRollback,
- StatusPrepared,
- StatusCommitted,
- StatusRolledBack,
- StatusUnknown,
- StatusNoTransaction,
- StatusPreparing,
- StatusCommitting,
- StatusRollingBack
- };
-
- enum Vote {
- VoteCommit,
- VoteRollback,
- VoteReadOnly
- };
-
- // Forward references for interfaces defined later in module
- interface Control;
- interface Terminator;
- interface Coordinator;
- interface Resource;
- interface RecoveryCoordinator;
- interface SubtransactionAwareResource;
- interface TransactionFactory;
- interface TransactionalObject;
- // interface Synchronization;
-
- // Structure definitions
- struct otid_t {
- long formatID; /*format identifier. 0 is OSI TP */
- long bqual_length;
- sequence <octet> tid;
- };
- struct TransIdentity {
- Coordinator coord;
- Terminator term;
- otid_t otid;
- };
- struct PropagationContext {
- unsigned long timeout;
- TransIdentity current;
- sequence <TransIdentity> parents;
- any implementation_specific_data;
- };
- // interface Current;
-
- // Standard exceptions
- // Defined in orber/include/corba.hrl
- // exception TransactionRequired {};
- // exception TransactionRolledBack {};
- // exception InvalidTransaction {};
-
- // Heuristic exceptions
- exception HeuristicRollback {};
- exception HeuristicCommit {};
- exception HeuristicMixed {};
- exception HeuristicHazard {};
-
- // Exception from Orb operations
- exception WrongTransaction {};
-
- // Other transaction-specific exceptions
- exception SubtransactionsUnavailable {};
- exception NotSubtransaction {};
- exception Inactive {};
- exception NotPrepared {};
- exception NoTransaction {};
- exception InvalidControl {};
- exception Unavailable {};
- exception SynchronizationUnavailable {};
-
- interface TransactionFactory {
- Control create(in unsigned long time_out);
- Control recreate(in PropagationContext ctx);
- };
-
- interface Control {
- Terminator get_terminator()
- raises(Unavailable);
- Coordinator get_coordinator()
- raises(Unavailable);
- };
-
- interface Terminator {
- void commit(in boolean report_heuristics)
- raises( HeuristicMixed,
- HeuristicHazard );
- void rollback();
- };
-
- interface Coordinator {
-
- Status get_status();
- Status get_parent_status();
- Status get_top_level_status();
-
- boolean is_same_transaction(in Coordinator tc);
- boolean is_related_transaction(in Coordinator tc);
- boolean is_ancestor_transaction(in Coordinator tc);
- boolean is_descendant_transaction(in Coordinator tc);
- boolean is_top_level_transaction();
-
- unsigned long hash_transaction();
- unsigned long hash_top_level_tran();
-
- RecoveryCoordinator register_resource(in Resource r)
- raises(Inactive);
-
-// void register_synchronization (in Synchronization sync)
-// raises(Inactive, SynchronizationUnavailable);
-
- void register_subtran_aware(in SubtransactionAwareResource r)
- raises(Inactive, NotSubtransaction);
-
- void rollback_only()
- raises(Inactive);
-
- string get_transaction_name();
- Control create_subtransaction()
- raises(SubtransactionsUnavailable, Inactive);
-
- PropagationContext get_txcontext ()
- raises(Unavailable);
- };
-
-
- interface RecoveryCoordinator {
- Status replay_completion(in Resource r)
- raises(NotPrepared);
- };
-
- interface Resource {
- Vote prepare()
- raises(HeuristicMixed,
- HeuristicHazard);
- void rollback()
- raises( HeuristicCommit,
- HeuristicMixed,
- HeuristicHazard );
- void commit()
- raises( NotPrepared,
- HeuristicRollback,
- HeuristicMixed,
- HeuristicHazard );
- void commit_one_phase()
- raises( HeuristicHazard,
- HeuristicRollback,
- HeuristicMixed);
- void forget();
- };
-
-// interface TransactionalObject {
-// };
-
-// interface Synchronization : TransactionalObject {
-// void before_completion();
-// void after_completion(in CosTransactions::Status status);
-// };
-
- interface SubtransactionAwareResource : Resource {
- void commit_subtransaction(in Coordinator parent);
- void rollback_subtransaction();
- };
-
-}; // End of CosTransactions Module
-
-module ETraP {
-
- // interface Server
- interface Server :
- CosTransactions::Coordinator, CosTransactions::Resource,
- CosTransactions::RecoveryCoordinator, CosTransactions::Control {
- };
-// interface Server :
-// CosTransactions::Coordinator, CosTransactions::Resource,
-// CosTransactions::RecoveryCoordinator, CosTransactions::Control,
-// CosTransactions::Synchronization {
-// };
-
-}; // End of ETraP Module
-
-#endif
diff --git a/lib/cosTransactions/src/CosTransactions_Terminator_impl.erl b/lib/cosTransactions/src/CosTransactions_Terminator_impl.erl
deleted file mode 100644
index d995eb64e4..0000000000
--- a/lib/cosTransactions/src/CosTransactions_Terminator_impl.erl
+++ /dev/null
@@ -1,363 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : CosTransactions_Terminator_impl.erl
-%% Purpose : Support operations to commit or roll-back a transaction.
-%%----------------------------------------------------------------------
-
--module('CosTransactions_Terminator_impl').
-
-%%--------------- INCLUDES -----------------------------------
--include_lib("orber/include/corba.hrl").
-%% Local
--include_lib("ETraP_Common.hrl").
--include_lib("CosTransactions.hrl").
-
-%%--------------- IMPORTS-------------------------------------
--import(etrap_logmgr, [log_safe/2, get_next/2]).
-
-%%--------------- EXPORTS-------------------------------------
-%%-compile(export_all).
--export([commit/3, rollback/2]).
--export([init/1, terminate/2]).
--export([handle_call/3, handle_cast/2, handle_info/2, code_change/3]).
-
-%%--------------- LOCAL DATA ---------------------------------
-%-record(terminator, {reg_resources, rollback_only, regname, coordinator}).
-
-%%------------------------------------------------------------
-%% function : init, terminate
-%% Arguments:
-%% Returns :
-%% Effect : Functions demanded by the module ic. Used to initiate
-%% and terminate a gen_server.
-%%------------------------------------------------------------
-
-init(State) ->
- process_flag(trap_exit,true),
- case catch start_object(State) of
- {'EXIT', Reason} ->
- %% Happens when, for example, we encounter an
- %% error when reading from the log file.
- {stop, Reason};
- Other ->
- Other
- end.
-
-start_object(State) ->
- case catch file:read_file_info(?tr_get_terminator(State)) of
- {error, enoent} ->
- %% File does not exist. It's the first time. No restart.
- ?debug_print("Terminator:init(~p)~n", [?tr_get_terminator(State)]),
- etrap_logmgr:start(?tr_get_terminator(State)),
- {ok, State, ?tr_get_timeout(State)};
- {error, Reason} -> % File exist but error occurred.
- ?tr_error_msg("CosTransactions_Terminator( ~p ) Cannot open log file: ~p~n",
- [?tr_get_terminator(State), Reason]),
- {stop, {error, "unable_to_open_log"}};
- _ -> % File exists, perform restart.
- etrap_logmgr:start(?tr_get_terminator(State)),
- ?debug_print("RESTART Terminator:init(~p)~n",
- [?tr_get_terminator(State)]),
- do_restart(State, get_next(?tr_get_terminator(State), start), init)
- end.
-
-
-terminate(Reason, State) ->
- ?debug_print("STOP ~p ~p~n", [?tr_get_terminator(State), Reason]),
- case Reason of
- normal ->
- %% normal termination. Transaction completed.
- log_safe(?tr_get_terminator(State), done),
- etrap_logmgr:stop(?tr_get_terminator(State)),
- file:delete(?tr_get_terminator(State)),
- ok;
- _ ->
- ok
- end.
-
-%%------------------------------------------------------------
-%% function : handle_call, handle_cast, handle_info, code_change
-%% Arguments:
-%% Returns :
-%% Effect : Functions demanded by the module ic.
-%%------------------------------------------------------------
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-handle_call(_,_, State) ->
- {noreply, State}.
-
-
-handle_cast(_, State) ->
- {noreply, State}.
-
-
-handle_info(Info, State) ->
- ?debug_print("Terminator:handle_info(~p)~n", [Info]),
- Pid = self(),
- case Info of
- timeout ->
- ?tr_error_msg("Object( ~p ) timeout. Rolling back.~n",
- [?tr_get_terminator(State)]),
- {stop, normal, State};
- {suicide, Pid} ->
- {stop, normal, State};
- _->
- {noreply, State}
- end.
-
-%%------------------------------------------------------------
-%% function : commit
-%% Arguments: Self - its own object reference.
-%% State - Gen-Server State
-%% Heuristics - boolean; report heuristic decisions?
-%% Returns : ok - equal to void
-%% Effect :
-%% Exception: HeuristicMixed - Highest priority
-%% HeuristicHazard - Lowest priority
-%%------------------------------------------------------------
-
-commit(_Self, State, _Heuristics) when ?tr_is_retransmit(State) ->
- ?debug_print("Terminator:commit() recalled.~n", []),
- {stop, normal, ?tr_get_reportH(State), State};
-commit(Self, State, Heuristics) ->
- ?debug_print("Terminator:commit() called.~n", []),
- NewState = ?tr_set_reportH(State, Heuristics),
- log_safe(?tr_get_terminator(NewState), {init_commit, NewState}),
- transmit(Self, NewState, Heuristics).
-
-
-transmit(Self, State, Heuristics) ->
- case catch 'ETraP_Common':try_timeout(?tr_get_alarm(State)) of
- false ->
-% catch 'ETraP_Server':before_completion(?tr_get_etrap(State)),
- case catch 'CosTransactions_Resource':prepare(?tr_get_etrap(State)) of
- 'VoteCommit' ->
- evaluate_answer(Self, State, Heuristics,
- 'ETraP_Common':try_timeout(?tr_get_alarm(State)));
- 'VoteRollback' ->
- {stop, normal,
- {'EXCEPTION',
- #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
- State};
- 'VoteReadOnly' ->
- {stop, normal, ok, State};
- {'EXCEPTION', E} when is_record(E,'CosTransactions_HeuristicMixed'),
- Heuristics==true->
- catch 'ETraP_Server':forget(?tr_get_etrap(State)),
- {stop, normal, {'EXCEPTION', E}, State};
- {'EXCEPTION', E} when is_record(E,'CosTransactions_HeuristicHazard'),
- Heuristics==true->
- catch 'ETraP_Server':forget(?tr_get_etrap(State)),
- {stop, normal, {'EXCEPTION', E}, State};
- {'EXCEPTION', E} when is_record(E,'CosTransactions_HeuristicMixed') ->
- catch 'ETraP_Server':forget(?tr_get_etrap(State)),
- {stop, normal,
- {'EXCEPTION',#'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
- State};
- {'EXCEPTION', E} when is_record(E,'CosTransactions_HeuristicHazard') ->
- catch 'ETraP_Server':forget(?tr_get_etrap(State)),
- {stop, normal,
- {'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
- State};
- Other ->
- ?tr_error_msg("Coordinator:prepare( ~p ) failed. REASON ~p~n",
- [?tr_get_etrap(State), Other]),
- {stop, normal,
- {'EXCEPTION',
- #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
- State}
- end;
- _ ->
- %% Timeout, rollback.
- log_safe(?tr_get_terminator(State), rolled_back),
- catch 'ETraP_Server':rollback(?tr_get_etrap(State)),
-% catch 'ETraP_Server':after_completion(?tr_get_etrap(State),
-% 'StatusRolledBack'),
- {stop, normal,
- {'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
- State}
- end.
-
-evaluate_answer(Self, State, Heuristics, false) ->
- evaluate_answer(Self, State, Heuristics, commit);
-evaluate_answer(Self, State, Heuristics, true) ->
- evaluate_answer(Self, State, Heuristics, rollback);
-evaluate_answer(_Self, State, Heuristics, Vote) ->
- case catch 'ETraP_Common':send_stubborn('ETraP_Server', Vote,
- ?tr_get_etrap(State),
- ?tr_get_maxR(State),
- ?tr_get_maxW(State)) of
- ok ->
- ?eval_debug_fun({_Self, commit_ok1}, State),
- log_safe(?tr_get_terminator(State), committed),
- ?eval_debug_fun({_Self, commit_ok2}, State),
-% catch 'ETraP_Server':after_completion(?tr_get_etrap(State),
-% 'StatusCommitted'),
- {stop, normal, ok, State};
- {'EXCEPTION', E} when Heuristics == true andalso
- is_record(E,'CosTransactions_HeuristicMixed') ->
- log_safe(?tr_get_terminator(State), {heuristic, State, E}),
- ?eval_debug_fun({_Self, commit_heuristic1}, State),
- catch 'ETraP_Server':forget(?tr_get_etrap(State)),
-% catch 'ETraP_Server':after_completion(?tr_get_etrap(State),
-% 'StatusRolledBack'),
- {stop, normal, {'EXCEPTION', E}, State};
- {'EXCEPTION', E} when Heuristics == true andalso
- is_record(E, 'CosTransactions_HeuristicHazard') ->
- log_safe(?tr_get_terminator(State), {heuristic, State, E}),
- catch 'ETraP_Server':forget(?tr_get_etrap(State)),
-% catch 'ETraP_Server':after_completion(?tr_get_etrap(State),
-% 'StatusRolledBack'),
- {stop, normal, {'EXCEPTION', E}, State};
- {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') ->
- log_safe(?tr_get_terminator(State), rolled_back),
- {stop, normal, {'EXCEPTION', ?tr_hazard}, State};
- {'EXCEPTION', E} when is_record(E, 'TRANSACTION_ROLLEDBACK') ->
- log_safe(?tr_get_terminator(State), rolled_back),
-% catch 'ETraP_Server':after_completion(?tr_get_etrap(State),
-% 'StatusRolledBack'),
- {stop, normal, {'EXCEPTION', E}, State};
- {'EXCEPTION', E} when is_record(E, 'CosTransactions_HeuristicCommit') ->
- catch 'ETraP_Server':forget(?tr_get_etrap(State)),
-% catch 'ETraP_Server':after_completion(?tr_get_etrap(State),
-% 'StatusRolledBack'),
- {stop, normal, ok, State};
- {'EXCEPTION', E} when is_record(E, 'CosTransactions_HeuristicRollback') ->
- catch 'ETraP_Server':forget(?tr_get_etrap(State)),
-% catch 'ETraP_Server':after_completion(?tr_get_etrap(State),
-% 'StatusCommitted'),
- {stop, normal,
- {'EXCEPTION',
- #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
- State};
- _Other when Heuristics == true ->
- log_safe(?tr_get_terminator(State), rolled_back),
-% catch 'ETraP_Server':after_completion(?tr_get_etrap(State),
-% 'StatusRolledBack'),
- {stop, normal, {'EXCEPTION', ?tr_hazard}, State};
- _Other ->
- log_safe(?tr_get_terminator(State), rolled_back),
-% catch 'ETraP_Server':after_completion(?tr_get_etrap(State),
-% 'StatusRolledBack'),
- {stop, normal, ok, State}
- end.
-
-%%-----------------------------------------------------------%
-%% function : rollback
-%% Arguments: Self - its own object reference.
-%% State - Gen-Server State
-%% Returns : ok - equal to void
-%% Effect :
-%%------------------------------------------------------------
-
-rollback(_Self, State) ->
- ?debug_print("Terminator:rollback() called.~n", []),
- log_safe(?tr_get_terminator(State), rolled_back),
- catch 'ETraP_Server':rollback(?tr_get_etrap(State)),
- {stop, normal, ok, State}.
-
-%%-----------------------------------------------------------%
-%% function : do_restart
-%% Arguments: State - server context
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-
-%% No data in file. Commit never initiated so we rollback (presumed rollback.
-do_restart(State, eof, init) ->
- log_safe(?tr_get_terminator(State), rolled_back),
- catch 'ETraP_Server':rollback(?tr_get_etrap(State)),
-% catch 'ETraP_Server':after_completion(?tr_get_etrap(State), 'StatusRolledBack'),
- self() ! {suicide, self()},
- {ok, State};
-
-do_restart(State, {error, Reason}, _) ->
- ?tr_error_msg("CosTransactions_Terminator (~p) failed. Cannot read log file: ~p~n",
- [?tr_get_terminator(State), Reason]),
- {stop, Reason};
-do_restart(State, eof, Phase) ->
- ?debug_print("Terminator:do_restart(~p)~n", [Phase]),
- case Phase of
- committed ->
- {ok, ?tr_set_reportH(State, ok)};
- rolled_back ->
- self() ! {suicide, self()},
- {ok, State};
- init_commit ->
- case catch corba_object:non_existent(?tr_get_etrap(State)) of
- true ->
- self() ! {suicide, self()},
- {ok, State};
- _->
- case transmit(false, State, ?tr_get_reportH(State)) of
- {stop, normal, ok, NewState} ->
- {ok, NewState};
- {stop, normal,
- {'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
- NewState} ->
- self() ! {suicide, self()},
- {ok, NewState};
- {stop, normal, {'EXCEPTION', Exc}, NewState} ->
- if
- ?tr_dont_reportH(State) ->
- self() ! {suicide, self()},
- {ok, NewState};
- true ->
- {ok, ?tr_set_reportH(NewState, Exc)}
- end
- end
- end;
- {heuristic, Exc} ->
- catch 'ETraP_Server':forget(?tr_get_etrap(State)),
-% catch 'ETraP_Server':after_completion(?tr_get_etrap(State),
-% 'StatusRolledBack'),
- if
- ?tr_dont_reportH(State) ->
- self() ! {suicide, self()},
- {ok, State};
- true ->
- {ok, ?tr_set_reportH(State, {'EXCEPTION',Exc})}
- end
- end;
-%% All done.
-do_restart(State, {done, _Cursor}, _Phase) ->
- ?debug_print("Terminator:do_restart(~p)~n", [_Phase]),
- self() ! {suicide, self()},
- {ok, State};
-do_restart(State, {rolled_back, Cursor}, _Phase) ->
- ?debug_print("Terminator:do_restart(~p)~n", [_Phase]),
- do_restart(State, get_next(?tr_get_terminator(State), Cursor), rolled_back);
-do_restart(State, {committed, Cursor}, _Phase) ->
- ?debug_print("Terminator:do_restart(~p)~n", [_Phase]),
- do_restart(State, get_next(?tr_get_terminator(State), Cursor), committed);
-do_restart(State, {{heuristic, SavedState, Exc}, Cursor}, _Phase) ->
- ?debug_print("Terminator:do_restart(~p)~n", [_Phase]),
- do_restart(SavedState, get_next(?tr_get_terminator(State), Cursor),
- {heuristic, Exc});
-do_restart(State, {{init_commit, SavedState}, Cursor}, _) ->
- ?debug_print("Terminator:do_restart(~p)~n", [init_commit]),
- do_restart(SavedState, get_next(?tr_get_terminator(State), Cursor), init_commit).
-
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/cosTransactions/src/CosTransactions_TransactionFactory_impl.erl b/lib/cosTransactions/src/CosTransactions_TransactionFactory_impl.erl
deleted file mode 100644
index e24bcb9a04..0000000000
--- a/lib/cosTransactions/src/CosTransactions_TransactionFactory_impl.erl
+++ /dev/null
@@ -1,180 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : CosTransactions_TransactionFactory_impl.erl
-%% Purpose : Is provided to allow the transaction originator to begin
-%% a transaction.
-%%----------------------------------------------------------------------
-
--module('CosTransactions_TransactionFactory_impl').
-
-%%--------------- INCLUDES -----------------------------------
--include_lib("orber/include/corba.hrl").
-
-%% Local
--include_lib("ETraP_Common.hrl").
--include_lib("CosTransactions.hrl").
-%%--------------- IMPORTS-------------------------------------
--import('ETraP_Common', [get_option/3]).
-
-%%--------------- EXPORTS-------------------------------------
--export([create/3, recreate/3, init/1, terminate/2]).
--export([handle_call/3, handle_cast/2, handle_info/2, code_change/3]).
-
-%%--------------- LOCAL DATA ---------------------------------
--record(factory, {hashMax, subtrOK, typeCheck, maxRetries, comFailWait}).
-
-%%--------------- LOCAL DEFINITIONS --------------------------
-
-%%------------------------------------------------------------
-%% function : init
-%% Arguments:
-%% Returns :
-%% Effect : Functions demanded by the module ic. Used to initiate
-%% a gen_server.
-%%------------------------------------------------------------
-
-init(Options) when is_list(Options) ->
- ?debug_print("Factory:init(~p)~n", [Options]),
- process_flag(trap_exit,true),
- DefaultValues = [{maxRetries, ?tr_max_retries},
- {comFailWait, ?tr_comm_failure_wait}|?tr_FAC_DEF],
- Hash = get_option(hash_max, Options, DefaultValues),
- SubtrOK = get_option(allow_subtr, Options, DefaultValues),
- TypeCheck = get_option(typecheck, Options, DefaultValues),
- TTY = get_option(tty, Options, DefaultValues),
- LogFile = get_option(logfile, Options, DefaultValues),
- MaxRetries = get_option(maxRetries, Options, DefaultValues),
- ComFailWait = get_option(comFailWait, Options, DefaultValues),
- error_logger:tty(TTY),
- case LogFile of
- false ->
- ok;
- _->
- error_logger:logfile({open, LogFile})
- end,
- {ok, #factory{typeCheck = TypeCheck, hashMax = Hash, subtrOK = SubtrOK,
- maxRetries = MaxRetries, comFailWait = ComFailWait}};
-
-init(Options) ->
- ?tr_error_msg("TransactionFactory~nBad argument: ~p~n", [Options]),
- corba:raise(?tr_badparam).
-
-
-%%------------------------------------------------------------
-%% function : terminate
-%% Arguments:
-%% Returns :
-%% Effect : Function demanded by the module ic. Used to
-%% terminate a gen_server.
-%%------------------------------------------------------------
-
-terminate(_Reason, _State) ->
- ?debug_print("Factory:terminate(~p)~n", [_Reason]),
- ok.
-
-%%------------------------------------------------------------
-%% function : handle_call, handle_cast, handle_info, code_change
-%% Arguments:
-%% Returns :
-%% Effect : Functions demanded by the module ic.
-%%------------------------------------------------------------
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-handle_call(_,_, State) ->
- {noreply, State}.
-
-
-handle_cast(_, State) ->
- {noreply, State}.
-
-
-handle_info({'EXIT',_From,shutdown}, State) ->
- ?debug_print("Factory:handle_info(~p)~n", [shutdown]),
- {stop, shutdown, State};
-handle_info(_Info, State) ->
- ?debug_print("Factory:handle_info(~p)~n", [_Info]),
- {noreply, State}.
-
-%%------------------------------------------------------------
-%% function : create
-%% Arguments: TimeOut - rollback the transaction after TimeOut
-%% seconds. If 0 no timeout.
-%% Returns : a Control object
-%% Effect : Creates a new top-level transaction. The Control
-%% can be used to manage or control participation
-%% in the new transaction. Used for direct context
-%% management.
-%%------------------------------------------------------------
-
-create(_Self, State, TimeOut) when is_integer(TimeOut) ->
- %% Generate objectnames.
- ETraPName = 'ETraP_Common':create_name("root"),
- TermName = 'ETraP_Common':create_name("term"),
- EState = ?tr_create_context(ETraPName, TermName,
- State#factory.typeCheck,
- State#factory.hashMax,
- State#factory.subtrOK,
- State#factory.maxRetries,
- State#factory.comFailWait),
-
- case TimeOut of
- 0 ->
- ETraP = ?tr_start_child(?SUP_ETRAP(EState)),
- {reply, ETraP, State};
- _ ->
- if
- TimeOut > 0 ->
- TimeStampSec = erlang:monotonic_time(seconds),
- EState2 = ?tr_set_alarm(EState, TimeStampSec+TimeOut),
- EState3 = ?tr_set_timeout(EState2, TimeOut*1000),
- ETraP = ?tr_start_child(?SUP_ETRAP(EState3)),
- {reply, ETraP, State};
- true ->
- ?tr_error_msg("TransactionFactory:create( Integer >= 0 )~nBad argument. Not an integer.~n", []),
- corba:raise(?tr_badparam)
- end
- end;
-
-create(_Self, _State, _TimeOut) ->
- ?tr_error_msg("TransactionFactory:create( Integer >= 0 )~nBad argument. Not an integer.~n", []),
- corba:raise(?tr_badparam).
-
-
-%%------------------------------------------------------------
-%% function : recreate
-%% Arguments: PropagationContext
-%% Returns : a Control object
-%% Effect :
-%%------------------------------------------------------------
-
--spec recreate(_, _, _) -> no_return().
-recreate(_Self, _State, #'CosTransactions_PropagationContext'{current = _C}) ->
- corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_YES}).
-%recreate(Self, State, #'CosTransactions_PropagationContext'{current = C}) ->
-% {reply, C#'CosTransactions_TransIdentity'.coord, State}.
-
-
-%%--------------- END OF MODULE ------------------------------
-
diff --git a/lib/cosTransactions/src/ETraP_Common.erl b/lib/cosTransactions/src/ETraP_Common.erl
deleted file mode 100644
index a5f2bf4831..0000000000
--- a/lib/cosTransactions/src/ETraP_Common.erl
+++ /dev/null
@@ -1,187 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2015. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : ETraP_Common.erl
-%% Purpose :
-%%----------------------------------------------------------------------
-
--module('ETraP_Common').
-
-%%--------------- INCLUDES ----------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
-%% Local
--include_lib("ETraP_Common.hrl").
--include_lib("CosTransactions.hrl").
-
-%%--------------- EXPORTS -----------------------------------
--export([try_timeout/1,
- get_option/3,
- create_name/2,
- create_name/1,
- is_debug_compiled/0,
- send_stubborn/5,
- create_link/3]).
-
-%%--------------- DEFINITIONS OF CONSTANTS ------------------
-%%------------------------------------------------------------
-%% function : create_link
-%% Arguments: Module - which Module to call
-%% Env/ARgList - ordinary oe_create arguments.
-%% Returns :
-%% Exception:
-%% Effect : Necessary since we want the supervisor to be a
-%% 'simple_one_for_one'. Otherwise, using for example,
-%% 'one_for_one', we have to call supervisor:delete_child
-%% to remove the childs startspecification from the
-%% supervisors internal state.
-%%------------------------------------------------------------
-create_link(Module, Env, ArgList) ->
- Module:oe_create_link(Env, ArgList).
-
-%%------------------------------------------------------------
-%% function : get_option
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-
-get_option(Key, OptionList, DefaultList) ->
- case lists:keysearch(Key, 1, OptionList) of
- {value,{Key,Value}} ->
- Value;
- _ ->
- case lists:keysearch(Key, 1, DefaultList) of
- {value,{Key,Value}} ->
- Value;
- _->
- {error, "Invalid option"}
- end
- end.
-%%------------------------------------------------------------
-%% function : create_name/2
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-
-create_name(Name,Type) ->
- Time = erlang:system_time(),
- Unique = erlang:unique_integer([positive]),
- lists:concat(['oe_',node(),'_',Type,'_',Name,'_',Time,'_',Unique]).
-
-%%------------------------------------------------------------
-%% function : create_name/1
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-
-create_name(Type) ->
- Time = erlang:system_time(),
- Unique = erlang:unique_integer([positive]),
- lists:concat(['oe_',node(),'_',Type,'_',Time,'_',Unique]).
-
-%%------------------------------------------------------------
-%% function : try_timeout
-%% Arguments: Id - name of the timeoutSrv server.
-%% Returns : Boolean
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-
-try_timeout(TimeoutAt) ->
- case TimeoutAt of
- infinity ->
- false;
- _->
- TimeSec = erlang:monotonic_time(seconds),
- if
- TimeSec < TimeoutAt ->
- false;
- true ->
- true
- end
- end.
-
-%%------------------------------------------------------------
-%% function : send_stubborn
-%% Arguments: M - module
-%% F - function
-%% A - arguments
-%% MaxR - Maximum no retries
-%% Wait - sleep Wait seconds before next try.
-%% Returns : see effect
-%% Exception:
-%% Effect : Retries repeatedly until anything else besides
-%% 'EXIT', 'COMM_FAILURE' or 'OBJECT_NOT_EXIST'
-%%------------------------------------------------------------
-
-send_stubborn(M, F, A, MaxR, Wait) when is_list(A) ->
- send_stubborn(M, F, A, MaxR, Wait, 0);
-send_stubborn(M, F, A, MaxR, Wait) ->
- send_stubborn(M, F, [A], MaxR, Wait, 0).
-send_stubborn(M, F, A, MaxR, _Wait, MaxR) ->
- ?tr_error_msg("~p:~p( ~p ) failed!! Tried ~p times.~n", [M,F,A,MaxR]),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO});
-send_stubborn(M, F, A, MaxR, Wait, Times) ->
- ?debug_print("~p:~p(~p) # of retries: ~p~n", [M,F,A, Times]),
- case catch apply(M,F,A) of
- {'EXCEPTION', E} when is_record(E, 'COMM_FAILURE')->
- NewTimes = Times +1,
- timer:sleep(Wait),
- send_stubborn(M, F, A, MaxR, Wait, NewTimes);
- {'EXCEPTION', E} when is_record(E, 'TRANSIENT')->
- NewTimes = Times +1,
- timer:sleep(Wait),
- send_stubborn(M, F, A, MaxR, Wait, NewTimes);
- {'EXCEPTION', E} when is_record(E, 'TIMEOUT')->
- NewTimes = Times +1,
- timer:sleep(Wait),
- send_stubborn(M, F, A, MaxR, Wait, NewTimes);
- {'EXIT', _} ->
- NewTimes = Times +1,
- timer:sleep(Wait),
- send_stubborn(M, F, A, MaxR, Wait, NewTimes);
- Other ->
- ?debug_print("~p:~p(~p) Resulted in: ~p~n", [M,F,A, Other]),
- Other
- end.
-
-%%------------------------------------------------------------
-%% function : is_debug_compiled
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-
--ifdef(debug).
- is_debug_compiled() -> true.
--else.
- is_debug_compiled() -> false.
--endif.
-
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/cosTransactions/src/ETraP_Common.hrl b/lib/cosTransactions/src/ETraP_Common.hrl
deleted file mode 100644
index 906e984a5b..0000000000
--- a/lib/cosTransactions/src/ETraP_Common.hrl
+++ /dev/null
@@ -1,341 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%---------------------------------------------------------------------
-%% File : ETraP_Common.hrl
-%% Purpose :
-%%---------------------------------------------------------------------
-
--ifndef(ETRAP_COMMON_HRL).
--define(ETRAP_COMMON_HRL, true).
-
-%%--------------- INCLUDES ---------------------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("cosTransactions/include/CosTransactions.hrl").
-
-%%-------- CONSTANTS ---------------------------------------------------
-%% Timeouts
--define(tr_comm_failure_wait,
- case catch application:get_env(cosTransactions, comFailWait) of
- {ok, _Time} when is_integer(_Time) ->
- _Time;
- _ ->
- 5000
- end).
-
--define(tr_max_retries,
- case catch application:get_env(cosTransactions, maxRetries) of
- {ok, _Max} when is_integer(_Max) ->
- _Max;
- _ ->
- 40
- end).
-
-%% Exceptions
-% Heuristic
--define(tr_mixed,
- #'CosTransactions_HeuristicMixed' {}).
--define(tr_hazard,
- #'CosTransactions_HeuristicHazard' {}).
--define(tr_commit,
- #'CosTransactions_HeuristicCommit' {}).
--define(tr_rollback,
- #'CosTransactions_HeuristicRollback' {}).
-%% Standard
--define(tr_subunavailable,
- #'CosTransactions_SubtransactionsUnavailable' {}).
--define(tr_unavailable,
- #'CosTransactions_Unavailable' {}).
--define(tr_unprepared,
- #'CosTransactions_NotPrepared' {}).
--define(tr_inactive,
- #'CosTransactions_Inactive' {}).
--define(tr_nosync,
- #'CosTransactions_SynchronizationUnavailable' {}).
--define(tr_badparam,
- #'BAD_PARAM'{completion_status=?COMPLETED_NO}).
--define(tr_NotSubtr,
- #'CosTransactions_NotSubtransaction' {}).
-
-%% TypeID:s
--define(tr_Terminator,
- 'CosTransactions_Terminator':typeID()).
--define(tr_Coordinator,
- 'CosTransactions_Coordinator':typeID()).
--define(tr_Control,
- 'CosTransactions_Control':typeID()).
--define(tr_RecoveryCoordinator,
- 'CosTransactions_RecoveryCoordinator':typeID()).
--define(tr_SubtransactionAwareResource,
- 'CosTransactions_SubtransactionAwareResource':typeID()).
--define(tr_Synchronization,
- 'CosTransactions_Synchronization':typeID()).
--define(tr_Resource,
- 'CosTransactions_Resource':typeID()).
--define(tr_ETraP,
- 'ETraP_Server':typeID()).
--define(tr_TransactionalObject,
- 'CosTransactions_TransactionalObject':typeID()).
-
-
-%%-------- MISC --------------------------------------------------------
-
--define(tr_error_msg(Txt, Arg),
-error_logger:error_msg("============ CosTransactions ==============~n"
- Txt
- "===========================================~n",
- Arg)).
-
-
--define(tr_NIL_OBJ_REF, corba:create_nil_objref()).
-
--define(tr_FAC_DEF, [{hash_max, 1013},
- {allow_subtr, true},
- {typecheck, true},
- {tty, false},
- {logfile, false}]).
-
-
-%%-------- Supervisor child-specs ------------------------------------
--define(FACTORY_NAME, oe_cosTransactionsFactory).
--define(SUPERVISOR_NAME, cosTransactions_sup).
--define(SUP_FLAG, {simple_one_for_one,50,10}).
-
--define(SUP_FAC(Env),
- ['CosTransactions_TransactionFactory',Env,
- [{sup_child, true}, {regname, {local, ?FACTORY_NAME}}]]).
-
--define(SUP_ETRAP(Env),
- ['ETraP_Server', Env,
- [{sup_child, true}, {persistent, true},
- {regname, {global, ?tr_get_etrap(Env)}}]]).
-
--define(SUP_TERMINATOR(Env),
- ['CosTransactions_Terminator', Env,
- [{sup_child, true}, {persistent, true},
- {regname, {global, ?tr_get_etrap(Env)}}]]).
-
--define(SUP_CHILD,
- {"oe_child",
- {'ETraP_Common',create_link, []},
- transient,100000,worker,
- ['ETraP_Common',
- 'ETraP_Server_impl',
- 'ETraP_Server',
- 'CosTransactions_Terminator_impl',
- 'CosTransactions_Terminator',
- 'CosTransactions_TransactionFactory_impl',
- 'CosTransactions_TransactionFactory']}).
-
-
--define(tr_start_child(SPEC),
- case supervisor:start_child(?SUPERVISOR_NAME, SPEC) of
- {ok, Pid, Obj} when is_pid(Pid) ->
- Obj;
- _Other->
- corba:raise(?tr_badparam)
- end).
-
--define(tr_start_child_pid(SPEC),
- supervisor:start_child(?SUPERVISOR_NAME, SPEC)).
-
--define(tr_terminate_child(Child),
- supervisor:terminate_child(?SUPERVISOR_NAME, Child)).
-
--define(tr_delete_child(Child),
- supervisor:delete_child(?SUPERVISOR_NAME, Child)).
-
-%%-------- DATASTRUCTURES ----------------------------------------------
-%% tr_*_*
--record(context, {terminator, etrap, recCoord, alarm = infinity,
- timeout = infinity, parents=[], trid, typeCheck,
- sub_tr_allowed, hashMax, local, rollback=false,
- reportH, maxRetries, comFailWait}).
-
-
-%%-------- FUNS --------------------------------------------------------
--define(tr_IS_MEMBER(Obj),
- fun(X) ->
- case catch corba_object:is_equivalent(Obj, X) of
- true ->
- true;
- _ ->
- false
- end
- end).
-
-%% Managing conditional debug functions
--define(is_debug_compiled, 'ETraP_Common':is_debug_compiled()).
--define(set_debug_context(L, C),
- etrap_test_lib:set_debug_context(L, C, ?FILE, ?LINE)).
-
-
--ifdef(debug).
--define(put_debug_data(Key, Data), erlang:put(Key, Data)).
--define(get_debug_data(Key), erlang:get(Key)).
--define(eval_debug_fun(I, E),
- etrap_test_lib:eval_debug_fun(I, E, ?FILE, ?LINE)).
--define(activate_debug_fun(I, F, C),
- etrap_test_lib:activate_debug_fun(I, F, C, ?FILE, ?LINE)).
--define(deactivate_debug_fun(I),
- etrap_test_lib:deactivate_debug_fun(I, ?FILE, ?LINE)).
--define(debug_print(F,A),
- io:format("[LINE: ~p] "++F,[?LINE]++A)).
--define(scratch_debug_fun,
- etrap_test_lib:scratch_debug_fun()).
--else.
--define(put_debug_data(Key, Data), ok).
--define(get_debug_data(Key), ok).
--define(eval_debug_fun(I, E), ok).
--define(activate_debug_fun(I, F, C), ok).
--define(deactivate_debug_fun(I), ok).
--define(debug_print(F,A), ok).
--define(scratch_debug_fun, ok).
--endif.
-
-
-%%-------- CONSTRUCTORS ------------------------------------------------
-
--define(tr_create_context(ETraP, Terminator, TypeCheck, HM, SubtrOK, MaxRetries,
- ComFailWait),
- #context{etrap = ETraP, terminator = Terminator, typeCheck = TypeCheck,
- hashMax = HM, sub_tr_allowed = SubtrOK, maxRetries = MaxRetries,
- comFailWait = ComFailWait}).
-
-
-%%-------- MISC --------------------------------------------------------
--define(tr_notimeout(Context),
- 'ETraP_Common':try_timeout(Context#context.alarm) == false).
--define(tr_is_root(Context), Context#context.parents == []).
--define(tr_dont_reportH(Context), Context#context.reportH == false).
--define(tr_is_retransmit(Context),
- Context#context.reportH =/= undefined,
- Context#context.reportH =/= true,
- Context#context.reportH =/= false).
-
-%%-------- SELECTORS ---------------------------------------------------
-
--define(tr_get_reportH(Context),
- Context#context.reportH).
-
--define(tr_get_rollback(Context),
- Context#context.rollback).
-
--define(tr_get_subTraOK(Context),
- Context#context.sub_tr_allowed).
-
--define(tr_get_hashMax(Context),
- Context#context.hashMax).
-
--define(tr_get_local(Context),
- Context#context.local).
-
--define(tr_get_trid(Context),
- Context#context.trid).
-
--define(tr_get_typeCheck(Context),
- Context#context.typeCheck).
-
--define(tr_get_recCoord(Context),
- Context#context.recCoord).
-
--define(tr_get_alarm(Context),
- Context#context.alarm).
-
--define(tr_get_timeout(Context),
- Context#context.timeout).
-
--define(tr_get_etrap(Context),
- Context#context.etrap).
-
--define(tr_get_terminator(Context),
- Context#context.terminator).
-
--define(tr_get_id(Context),
- Context#context.self).
-
--define(tr_get_maxW(Context),
- Context#context.comFailWait).
-
--define(tr_get_maxR(Context),
- Context#context.maxRetries).
-
--define(tr_get_parents(Context),
- Context#context.parents).
-
--define(tr_get_parent(Context),
- lists:nth(1, Context#context.parents)).
-
-%%-------- MODIFIERS ---------------------------------------------------
-
--define(tr_set_reportH(Context, Bool),
- Context#context{reportH = Bool}).
-
--define(tr_set_rollback(Context, Bool),
- Context#context{rollback = Bool}).
-
--define(tr_set_subTraOK(Context, Bool),
- Context#context{sub_tr_allowed = Bool}).
-
--define(tr_set_hashMax(Context, HM),
- Context#context{hashMax = HM}).
-
--define(tr_reset_local(Context),
- Context#context{local = undefined}).
-
--define(tr_set_local(Context, Local),
- Context#context{local = Local}).
-
--define(tr_set_trid(Context, TRID),
- Context#context{trid = TRID}).
-
--define(tr_set_typeCheck(Context, Bool),
- Context#context{typeCheck = Bool}).
-
--define(tr_set_id(Context, ID),
- Context#context{self = ID}).
-
--define(tr_set_parents(Context, Parents),
- Context#context{parents = Parents}).
-
--define(tr_add_parent(Context, Parent),
- Context#context{parents = [Parent] ++ Context#context.parents}).
-
--define(tr_set_recCoord(Context, R),
- Context#context{recCoord = R}).
-
--define(tr_set_alarm(Context, EC),
- Context#context{alarm = EC}).
-
--define(tr_set_timeout(Context, T),
- Context#context{timeout = T}).
-
--define(tr_set_etrap(Context, ETraP),
- Context#context{etrap = ETraP}).
-
--define(tr_set_terminator(Context, T),
- Context#context{terminator = T}).
-
--endif.
-
-%%-------------- EOF ---------------------------------------------------
-
-
diff --git a/lib/cosTransactions/src/ETraP_Server_impl.erl b/lib/cosTransactions/src/ETraP_Server_impl.erl
deleted file mode 100644
index 5c7b5f6350..0000000000
--- a/lib/cosTransactions/src/ETraP_Server_impl.erl
+++ /dev/null
@@ -1,1745 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : ETraP_Server_impl.erl
-%% Purpose :
-%%----------------------------------------------------------------------
-%% GENERAL CODE COMMENTS:
-%% ######################
-%% TypeChecking incoming arguments:
-%% --------------------------------
-%% We allow the user to configure the system so that external calls
-%% (not CosTransactions calls) may be typechecked or not when calling
-%% for example 'replay_completion'. With typecheck the user will get
-%% instant feedback. But since 'is_a' add quiet a lot extra overhead
-%% if the object is located on a remote ORB. Hence, it is up to the
-%% user to decide; speed vs. "safety".
-%%
-%% Log behavior
-%% ------------
-%% Log files are created in the current directory, which is why the
-%% application requires read/write rights for current directory. The
-%% file name looks like:
-%% "oe_nonode@nohost_subc_1429872479809947099_438" (the two last parts are
-%% erlang:system_time() and erlang:unique_integer([positive]))
-%% It is equal to what the object is started as, i.e., {regname, {global, X}}.
-%%
-%% If the application is unable to read the log it will exit and the
-%% supervisor definitions (found in ETraP_Common.hrl) determines how
-%% many times we will retry. If it's impossible to read the log it's
-%% considered as a disaster, i.e., user intervention is needed.
-%%
-%% If an Object is unreachable when a Coordinator is trying to inform
-%% of the true outcome of the transaction the application will retry N
-%% times with T seconds wait in between. If it's still impossible to
-%% reach the object it's considered as a disaster, i.e., user
-%% intervention is needed.
-%%
-%%----------------------------------------------------------------------
-
--module('ETraP_Server_impl').
-
-%%--------------- INCLUDES -----------------------------------
--include_lib("orber/include/corba.hrl").
-
-%% Local
--include_lib("cosTransactions/src/ETraP_Common.hrl").
--include_lib("cosTransactions/include/CosTransactions.hrl").
-
-
-%%--------------- IMPORTS-------------------------------------
--import('ETraP_Common', [try_timeout/1]).
-
-%%--------------- EXPORTS-------------------------------------
-%%--------------- Inherit from CosTransactions::Resource ----
--export([prepare/2,
- rollback/2,
- commit/2,
- commit_one_phase/2,
- forget/2]).
-
-%%--------------- Inherit from CosTransactions::Control -----
--export([get_terminator/2,
- get_coordinator/2]).
-
-%%----- Inherit from CosTransactions::RecoveryCoordinator ---
--export([replay_completion/3]).
-
-%%--------------- Inherit from CosTransactions::Coordinator -
--export([create_subtransaction/2,
- get_txcontext/2,
- get_transaction_name/2,
- get_parent_status/2,
- get_status/2,
- get_top_level_status/2,
- hash_top_level_tran/2,
- hash_transaction/2,
- is_ancestor_transaction/3,
- is_descendant_transaction/3,
- is_related_transaction/3,
- is_same_transaction/3,
- is_top_level_transaction/2,
- register_resource/3,
- register_subtran_aware/3,
- register_synchronization/3,
- rollback_only/2]).
-
-%%--------- Inherit from CosTransactions::Synchronization ---
-%-export([before_completion/2,
-% after_completion/3]).
-
-
-%%--------------- gen_server specific ------------------------
--export([init/1, terminate/2]).
--export([handle_call/3, handle_cast/2, handle_info/2, code_change/3]).
-
-
-
-%%--------------- LOCAL DATA ---------------------------------
--record(exc,
- {rollback = false,
- mixed = false,
- hazard = false,
- unprepared = false,
- commit = false}).
-
-%%--------------- LOCAL DEFINITIONS --------------------------
-
-%%--------------- MISC MACROS --------------------------------
--define(etr_log(Log, Data), etrap_logmgr:log_safe(Log, Data)).
--define(etr_read(Log, Cursor), etrap_logmgr:get_next(Log, Cursor)).
-
--record(coord,
- {status, %% Status of the transaction.
- members = [], %% List of registred resources.
- votedCommit = [], %% List of the ones that voted commit.
- raisedHeuristic = [], %% The members which raised an Heur. exc.
- subAw = [], %% Resorces which want to be informed of outcome.
- sync = [],
- exc = void,
- self,
- etsR}).
-
-%% Selectors
--define(etr_get_status(L), L#coord.status).
--define(etr_get_members(L), lists:reverse(L#coord.members)).
--define(etr_get_vc(L), lists:reverse(L#coord.votedCommit)).
--define(etr_get_raisedH(L), lists:reverse(L#coord.raisedHeuristic)).
--define(etr_get_exc(L), L#coord.exc).
--define(etr_get_subAw(L), lists:reverse(L#coord.subAw)).
--define(etr_get_sync(L), lists:reverse(L#coord.sync)).
--define(etr_get_self(L), L#coord.self).
--define(etr_get_etsR(L), L#coord.etsR).
--define(etr_get_init(Env), #coord{}).
--define(etr_get_exc_init(), #exc{}).
-%% Modifiers
--define(etr_set_status(L, D), L#coord{status = D}).
--define(etr_set_members(L, D), L#coord{members = D}).
--define(etr_add_member(L, D), L#coord{members = [D|L#coord.members]}).
--define(etr_set_vc(L, D), L#coord{votedCommit = D}).
--define(etr_add_vc(L, D), L#coord{votedCommit = [D|L#coord.votedCommit]}).
--define(etr_remove_vc(L, D), L#coord{votedCommit =
- lists:delete(D, ?etr_get_vc(L))}).
--define(etr_set_raisedH(L, D), L#coord{raisedHeuristic = [D]}).
--define(etr_add_raisedH(L, D), L#coord{raisedHeuristic =
- [D|L#coord.raisedHeuristic]}).
--define(etr_remove_raisedH(L, D), L#coord{raisedHeuristic =
- lists:delete(D, ?etr_get_raisedH(L))}).
--define(etr_set_exc(L, D), L#coord{exc = D}).
--define(etr_set_subAw(L, D), L#coord{subAw = [D]}).
--define(etr_add_subAw(L, D), L#coord{subAw = [D|L#coord.subAw]}).
--define(etr_remove_subAw(L, D), L#coord{subAw =
- lists:delete(D,?etr_get_subAw(L))}).
--define(etr_set_sync(L, D), L#coord{sync = [D]}).
--define(etr_add_sync(L, D), L#coord{sync = [D|L#coord.sync]}).
--define(etr_remove_sync(L, D), L#coord{sync = lists:delete(D,?etr_get_sync(L))}).
--define(etr_set_self(L, D), L#coord{self = D}).
--define(etr_set_etsR(L, D), L#coord{etsR = D}).
-
-
-%%------------------------------------------------------------
-%% function : init, terminate
-%% Arguments:
-%% Returns :
-%% Effect : Functions demanded by the module ic.
-%%------------------------------------------------------------
-
-init(Env) ->
- process_flag(trap_exit,true),
- case catch start_object(Env) of
- {'EXIT', Reason} ->
- %% Happens when, for example, we encounter an
- %% error when reading from the log file.
- {stop, Reason};
- {'EXCEPTION', E} ->
- self() ! {suicide, self()},
- corba:raise(E);
- Other ->
- Other
- end.
-
-
-
-terminate(Reason, {Env, _Local}) ->
- ?debug_print("STOP ~p ~p~n", [?tr_get_etrap(Env), Reason]),
- case Reason of
- normal ->
- %% normal termination. Transaction completed.
- etrap_logmgr:stop(?tr_get_etrap(Env)),
- file:delete(?tr_get_etrap(Env)),
- ok;
- _ ->
- ?tr_error_msg("Object(~p) terminated abnormal.~n",[?tr_get_etrap(Env)]),
- ok
- end.
-
-
-%%------------------------------------------------------------
-%% function : handle_call, handle_cast, handle_info, code_change
-%% Arguments:
-%% Returns :
-%% Effect : Functions demanded by the gen_server module.
-%%------------------------------------------------------------
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-handle_call(_,_, State) ->
- {noreply, State}.
-
-handle_cast(_, State) ->
- {noreply, State}.
-
-
-handle_info(Info, {Env, Local}) ->
- ?debug_print("ETraP_Server:handle_info(~p)~n", [Info]),
- Pid = self(),
- case Info of
- timeout ->
- ?tr_error_msg("Object( ~p ) timeout. Rolling back.~n",
- [?tr_get_etrap(Env)]),
- {stop, normal, {Env, Local}};
- {suicide, Pid} ->
- {stop, normal, {Env, Local}};
- _->
- {noreply, {Env, Local}}
- end.
-
-
-%%--------------- Inherit from CosTransactions::Control -----
-%%-----------------------------------------------------------%
-%% function : get_terminator
-%% Arguments: Self - its own object reference.
-%% State - Gen-Server State
-%% Returns : a Terminator object reference.
-%% Effect : Supports operations for termination of a transaction
-%%------------------------------------------------------------
-
-get_terminator(Self, {Env, Local}) ->
- %% Only allows the root-coordinator to export the termonator.
- %% The reason for this is that only the root-coordinator is allowed
- %% to initiate termination of a transaction. This is however possible
- %% to change and add restictions elsewhere, i.e. to verify if the
- %% commit or rollback call is ok.
- case catch ?tr_get_parents(Env) of
- [] -> % No parents, it's a root-coordinator.
- % Create terminators environment.
- TEnv = ?tr_set_etrap(Env, Self),
- T = ?tr_start_child(?SUP_TERMINATOR(TEnv)),
- {reply, T, {Env, Local}, ?tr_get_timeout(TEnv)};
- _ ->
- corba:raise(?tr_unavailable)
- end.
-
-%%-----------------------------------------------------------%
-%% function : get_coordinator
-%% Arguments: Self - its own object reference.
-%% State - Gen-Server State
-%% Returns : a Coordinator object reference. The OMG specification
-%% states that a object reference must be returned.
-%% Effect : Supports operations needed by resources to participate
-%% in the transaction.
-%%------------------------------------------------------------
-
-get_coordinator(Self, State) ->
- {reply, Self, State}.
-
-%%----- Inherit from CosTransactions::RecoveryCoordinator ---
-%%-----------------------------------------------------------%
-%% function : replay_completion
-%% Arguments:
-%% Returns : Status
-%% Effect : Provides a hint to the Coordinator that the commit
-%% or rollback operations have not been performed on
-%% the resource.
-%%------------------------------------------------------------
-
-replay_completion(_Self, {Env, Local}, Resource) ->
- type_check(?tr_get_typeCheck(Env), ?tr_Resource,
- "RecoveryCoordinator:replay_completion", Resource),
- case ?etr_get_status(Local) of
- 'StatusActive' ->
- corba:raise(?tr_unprepared);
- Status ->
- case lists:any(?tr_IS_MEMBER(Resource), ?etr_get_members(Local)) of
- true ->
- {reply, Status, {Env, Local}};
- _ ->
- corba:raise(#'NO_PERMISSION'{completion_status=?COMPLETED_YES})
- end
- end.
-
-%%--------------- Inherit from CosTransactions::Resource ----
-%%-----------------------------------------------------------%
-%% function : prepare
-%% Arguments:
-%% Returns : a Vote
-%% Effect : Is invoked to begin the two-phase-commit on the
-%% resource.
-%%------------------------------------------------------------
-
-prepare(_Self, {Env, Local}) ->
- %% Set status as prepared. No new Resources are allowed to register.
- NewL = ?etr_set_status(Local, 'StatusPrepared'),
-
- ?eval_debug_fun({?tr_get_etrap(Env), root_delay}, Env),
-
- case catch send_prepare(?etr_get_members(NewL),
- ?tr_get_alarm(Env)) of
- readOnly ->
- %% All voted ReadOnly, done. No need to log.
- {stop, normal, 'VoteReadOnly', {Env, NewL}};
- %% Replace the reply above if allow synchronization
-% case ?etr_get_sync(Local) of
-% [] ->
-% {stop, normal, 'VoteReadOnly', {Env, NewL}};
-% _ ->
-% {reply, 'VoteReadOnly', {Env, NewL}}
-% end;
- {commit, VC} ->
- %% All voted Commit.
- NewL2 = ?etr_set_vc(NewL, VC),
- case catch try_timeout(?tr_get_alarm(Env)) of
- false ->
- case ?etr_log(?tr_get_etrap(Env), {pre_vote, commit, NewL2}) of
- ok ->
- ?eval_debug_fun({?tr_get_etrap(Env), prepare1}, Env),
- {reply, 'VoteCommit', {Env, NewL2}};
- _->
- %% Cannot log. Better to be safe than sorry; do rollback.
- %% However, try to log rollback.
- ?etr_log(?tr_get_etrap(Env),{pre_vote, rollback, NewL2}),
- send_decision({Env, NewL2}, 'VoteRollback', rollback)
- end;
- _->
- ?etr_log(?tr_get_etrap(Env),
- {pre_vote, rollback, NewL2}),
- %% timeout, reply rollback.
- send_decision({Env, NewL2}, 'VoteRollback', rollback)
- end;
- {rollback, VC} ->
- %% Rollback vote received.
- %% Send rollback to commit voters.
- N2 = ?etr_set_vc(NewL, VC),
- NewL2 = ?etr_set_status(N2,'StatusRolledBack'),
- ?etr_log(?tr_get_etrap(Env), {pre_vote, rollback, NewL2}),
- send_decision({Env, NewL2}, 'VoteRollback', rollback);
- {'EXCEPTION', E, VC, Obj} ->
- NewL2 = case is_heuristic(E) of
- true ->
- N2 = ?etr_set_vc(NewL, VC),
- N3 = ?etr_set_exc(N2, E),
- ?etr_set_raisedH(N3, Obj);
- _->
- ?etr_set_vc(NewL, VC)
- end,
- ?etr_log(?tr_get_etrap(Env),{pre_vote,rollback, NewL2}),
- ?eval_debug_fun({?tr_get_etrap(Env), prepare2}, Env),
- send_decision({Env, NewL2}, {'EXCEPTION', E}, rollback);
- {failed, VC} ->
- NewL2 = ?etr_set_vc(NewL, VC),
- ?etr_log(?tr_get_etrap(Env),{pre_vote, rollback, NewL2}),
- send_decision({Env, NewL2},
- {'EXCEPTION', ?tr_hazard}, rollback)
- end.
-
-
-%%-----------------------------------------------------------%
-%% function : rollback
-%% Arguments: Self - the servers own objref.
-%% {Env, Local} - the servers internal state.
-%% Returns : ok
-%% Effect : Rollback the transaction. If its status is
-%% "StatusRolledBack", this is not the first
-%% rollback call to this server. Might occur if
-%% the parent coordinator just recoeverd from a crasch.
-%% Exception: HeuristicCommit, HeuristicMixed, HeuristicHazard
-%%------------------------------------------------------------
-
-rollback(Self, {Env, Local}) ->
- case ?etr_get_status(Local) of
- 'StatusRolledBack' ->
- case ?etr_get_exc(Local) of
- void ->
- {stop, normal, ok, {Env, Local}};
- %% Replace the reply above if allow synchronization
- %% Rolled back successfullly earlier.
-% case ?etr_get_sync(Local) of
-% [] ->
-% {stop, normal, ok, {Env, Local}};
-% _ ->
-% {reply, ok, {Env, Local}}
-% end;
- E ->
- %% Already rolledback with heuristic decision
- corba:raise(E)
- end;
- 'StatusPrepared' ->
- NewL = ?etr_set_status(Local, 'StatusRolledBack'),
- ?eval_debug_fun({?tr_get_etrap(Env), rollback}, Env),
- ?etr_log(?tr_get_etrap(Env), rollback),
- ?eval_debug_fun({?tr_get_etrap(Env), rollback2}, Env),
- send_decision({Env, NewL}, ok, rollback);
- 'StatusActive' ->
- NewL = ?etr_set_status(Local, 'StatusRolledBack'),
- ?etr_log(?tr_get_etrap(Env), {rollback, NewL}),
- send_info(?etr_get_members(NewL), 'CosTransactions_Resource', rollback),
- notify_subtrAware(rollback, ?etr_get_subAw(NewL), Self),
- {stop, normal, ok, {Env, NewL}}
-%% Replace the reply above if allow synchronization
-% case ?etr_get_sync(Local) of
-% [] ->
-% {stop, normal, ok, {NewEnv, NewL}};
-% _ ->
-% {reply, ok, {NewEnv, NewL}}
-% end;
- end.
-
-
-%%-----------------------------------------------------------%
-%% function : commit
-%% Arguments: Self - the servers own objref.
-%% {Env, Local} - the servers internal state.
-%% Returns : ok
-%% Effect : Commit the transaction.
-%% Exception: HeuristicRollback, HeuristicMixed, HeuristicHazard,
-%% NotPrepared
-%%------------------------------------------------------------
-
-commit(_Self, {Env, Local}) ->
- case ?etr_get_status(Local) of
- 'StatusPrepared' ->
- ?eval_debug_fun({?tr_get_etrap(Env), commit}, Env),
- NewL = ?etr_set_status(Local, 'StatusCommitted'),
- ?etr_log(?tr_get_etrap(Env),commit),
- ?eval_debug_fun({?tr_get_etrap(Env), commit2}, Env),
- send_decision({Env, NewL}, ok, commit);
- 'StatusCommitted' ->
- case ?etr_get_exc(Local) of
- void ->
- {stop, normal, ok, {Env, Local}};
- %% Replace the reply above if allow synchronization
-% case ?etr_get_sync(Local) of
-% [] ->
-% {stop, normal, ok, {Env, Local}};
-% _ ->
-% {reply, ok, {Env, Local}}
-% end;
- E->
- corba:raise(E)
- end;
- _ ->
- corba:raise(?tr_unprepared)
- end.
-
-%%-----------------------------------------------------------%
-%% function : commit_one_phase
-%% Arguments: Self - the servers own objref.
-%% {Env, Local} - the servers internal state.
-%% Returns : ok
-%% Effect : Commit the transaction using one-phase commit.
-%% Use ONLY when there is only one registered Resource.
-%% Exception: HeuristicRollback, HeuristicMixed, HeuristicHazard,
-%% TRANSACTION_ROLLEDBACK
-%%------------------------------------------------------------
-
-commit_one_phase(_Self, {Env, Local}) ->
- case ?etr_get_members(Local) of
- [Resource] ->
- case ?etr_get_status(Local) of
- 'StatusActive' ->
- %% Set status as prepared. No new Resources are allowed to register.
- NewL = ?etr_set_status(Local, 'StatusPrepared'),
- ?eval_debug_fun({?tr_get_etrap(Env), onePC}, Env),
- case try_timeout(?tr_get_alarm(Env)) of
- false ->
- case catch 'CosTransactions_Resource':prepare(Resource) of
- 'VoteCommit' ->
- case try_timeout(?tr_get_alarm(Env)) of
- false ->
- send_decision({Env, NewL}, ok, commit, [Resource]);
- _->
- %% Timeout, rollback.
- send_decision({Env, NewL},
- {'EXCEPTION',
- #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
- rollback, [Resource])
- end;
- 'VoteRollback' ->
- {stop, normal,
- {'EXCEPTION',
- #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
- {Env, NewL}};
- 'VoteReadOnly' ->
- {stop, normal, ok, {Env, NewL}};
- {'EXCEPTION', E}
- when is_record(E, 'CosTransactions_HeuristicMixed') ->
- {reply, {'EXCEPTION', E}, {Env, NewL}};
- {'EXCEPTION', E}
- when is_record(E, 'CosTransactions_HeuristicHazard') ->
- {reply, {'EXCEPTION', E}, {Env, NewL}};
- Other ->
- ?tr_error_msg("Coordinator:prepare( ~p ) failed. REASON ~p~n",
- [Resource, Other]),
- {stop, normal,
- {'EXCEPTION',
- #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
- {Env, NewL}}
- end;
- _->
- NewL2 = ?etr_set_status(NewL, 'StatusRolledBack'),
- send_info(Resource, 'CosTransactions_Resource', rollback),
- {stop, normal,
- {'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
- {Env, NewL2}}
- %% Replace the reply above if allow synchronization
-% case ?etr_get_sync(NewL2) of
-% [] ->
-% send_info(Resource, 'CosTransactions_Resource', rollback),
-% {stop, normal,
-% {'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
-% {Env, NewL2}};
-% _ ->
-% send_info(Resource, 'CosTransactions_Resource', rollback),
-% {reply,
-% {'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
-% {Env, NewL2}}
-% end
- end;
- _ ->
- case evaluate_status(?etr_get_status(Local)) of
- commit ->
- test_exc(set_exception(?etr_get_exc_init(),
- ?etr_get_exc(Local)),
- commit, ok, {Env, Local});
- _->
- test_exc(set_exception(?etr_get_exc_init(),
- ?etr_get_exc(Local)),
- rollback,
- {'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
- {Env, Local})
- end
- end;
- _->
- {reply, {'EXCEPTION', #'NO_PERMISSION'{completion_status=?COMPLETED_NO}},
- {Env, Local}}
- end.
-
-%%-----------------------------------------------------------%
-%% function : forget
-%% Arguments: Self - the servers own objref.
-%% State - the servers internal state.
-%% Returns : ok
-%% Effect : The resource can forget all knowledge about the
-%% transaction. Terminate this server.
-%%------------------------------------------------------------
-
-forget(_Self, {Env, Local}) ->
- ?etr_log(?tr_get_etrap(Env), forget_phase),
- send_forget(?etr_get_raisedH(Local), ?tr_get_etrap(Env)),
- {stop, normal, ok, {Env, ?etr_set_exc(Local, void)}}.
-%% Replace the reply above if allow synchronization
-% case ?etr_get_sync(Local) of
-% [] ->
-% {stop, normal, ok, {Env, ?etr_set_exc(Local, void)}};
-% _ ->
-% {reply, ok, {Env, ?etr_set_exc(Local, void)}}
-% end.
-
-%%--------------- Inherrit from CosTransactions::Coordinator -
-
-%%-----------------------------------------------------------%
-%% function : get_status
-%% Arguments: Self - its own object reference.
-%% State - Gen-Server State
-%% Returns : Status
-%% Effect : Returns the status of the transaction associated
-%% with the target object.
-%%------------------------------------------------------------
-
-get_status(_Self, {Env, Local}) ->
- {reply, ?etr_get_status(Local), {Env, Local}}.
-
-
-%%-----------------------------------------------------------%
-%% function : get_parent_status
-%% Arguments: Self - its own object reference.
-%% State - Gen-Server State
-%% Returns : Status
-%% Effect : Returns the status of the parent transaction
-%% associated with the target object. If top-level
-%% transaction equal to get_status.
-%%------------------------------------------------------------
-
-get_parent_status(_Self, {Env, Local}) ->
- case catch ?tr_get_parents(Env) of
- [] ->
- {reply, ?etr_get_status(Local), {Env, Local}};
- [Parent|_] ->
- case catch 'CosTransactions_Coordinator':get_status(Parent) of
- {'EXCEPTION', _E} ->
- corba:raise(?tr_unavailable);
- {'EXIT', _} ->
- corba:raise(?tr_unavailable);
- Status ->
- {reply, Status, {Env, Local}}
- end
- end.
-
-
-%%-----------------------------------------------------------%
-%% function : get_top_level_status
-%% Arguments: Self - its own object reference.
-%% State - Gen-Server State
-%% Returns : Status
-%% Effect : Returns the status of the top-level transaction
-%% associated with the target object. If top-level
-%% transaction equal to get_status.
-%%------------------------------------------------------------
-
-get_top_level_status(_Self, {Env, Local}) ->
- case catch ?tr_get_parents(Env) of
- [] ->
- {reply, ?etr_get_status(Local), {Env, Local}};
- Ancestrors ->
- case catch 'CosTransactions_Coordinator':get_status(lists:last(Ancestrors)) of
- {'EXCEPTION', _E} ->
- corba:raise(?tr_unavailable);
- {'EXIT', _} ->
- corba:raise(?tr_unavailable);
- Status ->
- {reply, Status, {Env, Local}}
- end
- end.
-
-
-%%-----------------------------------------------------------%
-%% function : is_same_transaction
-%% Arguments: Self - its own object reference.
-%% State - Gen-Server State
-%% Coordinator object reference
-%% Returns : boolean
-%% Effect :
-%%------------------------------------------------------------
-
-is_same_transaction(Self, {Env, Local}, Coordinator) ->
- type_check(?tr_get_typeCheck(Env), ?tr_Coordinator,
- "Coordinator:is_same_transaction", Coordinator),
- {reply, corba_object:is_equivalent(Self, Coordinator), {Env, Local}}.
-
-%%------------------------------------------------------------
-%% function : is_related_transaction
-%% Arguments: Self - its own object reference.
-%% State - Gen-Server State
-%% Coordinator object reference
-%% Returns : boolean
-%% Effect :
-%%------------------------------------------------------------
-
--spec is_related_transaction(_, _, _) -> no_return().
-is_related_transaction(_Self, {_Env, _Local}, _Coordinator) ->
- corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_YES}).
-% type_check(?tr_get_typeCheck(Env), ?tr_Coordinator,
-% "Coordinator:is_related_transaction", Coordinator),
-% {reply, false, {Env, Local}}.
-
-
-%%------------------------------------------------------------
-%% function : is_ancestor_transaction
-%% Coordinator object reference
-%% Returns : boolean
-%% Effect :
-%%------------------------------------------------------------
-
--spec is_ancestor_transaction(_, _, _) -> no_return().
-is_ancestor_transaction(_Self, {_Env, _Local}, _Coordinator) ->
- corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_YES}).
-% type_check(?tr_get_typeCheck(Env), ?tr_Coordinator,
-% "Coordinator:is_ancestor_transaction", Coordinator),
-% {reply, false, {Env, Local}}.
-
-
-%%-----------------------------------------------------------%
-%% function : is_descendant_transaction
-%% Arguments: Self - its own object reference.
-%% State - Gen-Server State
-%% Coordinator object reference
-%% Returns : boolean
-%% Effect :
-%%------------------------------------------------------------
-
-is_descendant_transaction(Self, {Env, Local}, Coordinator) ->
- type_check(?tr_get_typeCheck(Env), ?tr_Coordinator,
- "Coordinator:is_descendant_transaction", Coordinator),
- {reply,
- lists:any(?tr_IS_MEMBER(Coordinator), [Self|?tr_get_parents(Env)]),
- {Env, Local}}.
-
-%%-----------------------------------------------------------%
-%% function : is_top_level_transaction
-%% Arguments: Self - its own object reference.
-%% State - Gen-Server State
-%% Returns : boolean
-%% Effect :
-%%------------------------------------------------------------
-
-is_top_level_transaction(_Self, {Env, Local}) ->
- case catch ?tr_get_parents(Env) of
- [] ->
- {reply, true, {Env, Local}};
- _ ->
- {reply, false, {Env, Local}}
- end.
-
-%%-----------------------------------------------------------%
-%% function : hash_transaction
-%% Arguments: Self - its own object reference.
-%% State - Gen-Server State
-%% Returns : hash code
-%% Effect : Returns a hash code for the transaction associated
-%% with the target object.
-%%------------------------------------------------------------
-
-hash_transaction(Self, {Env, Local}) ->
- {reply, corba_object:hash(Self, ?tr_get_hashMax(Env)), {Env, Local}}.
-
-
-%%-----------------------------------------------------------%
-%% function : hash_top_level_tran
-%% Arguments: Self - its own object reference.
-%% State - Gen-Server State
-%% Returns : hash code
-%% Effect : Returns a hash code for the top-level transaction
-%% associated with the target object. Equals
-%% hash_transaction if it's a top-level transaction.
-%%------------------------------------------------------------
-
-hash_top_level_tran(Self, {Env, Local}) ->
- case ?tr_get_parents(Env) of
- [] ->
- {reply,
- corba_object:hash(Self, ?tr_get_hashMax(Env)),
- {Env, Local}};
- Ancestrors ->
- case catch corba_object:hash(lists:last(Ancestrors),
- ?tr_get_hashMax(Env)) of
- {'EXCEPTION', _E} ->
- corba:raise(?tr_unavailable);
- Hash ->
- {reply, Hash, {Env, Local}}
- end
- end.
-
-
-
-%%-----------------------------------------------------------%
-%% function : register_resource
-%% Arguments: Self - its own object reference.
-%% State - Gen-Server State
-%% Resource object reference
-%% Returns : RecoveryCoordinator (can be used during recovery)
-%% Effect : Registers the specified resource as as participant
-%% in the transaction associated with the target object.
-%% Exception: Inactive - Is prepared or terminated.
-%%------------------------------------------------------------
-
-register_resource(Self, {Env, Local}, Resource) ->
- type_check(?tr_get_typeCheck(Env), ?tr_Resource,
- "Coordinator:register_resource", Resource),
- case ?etr_get_status(Local) of
- 'StatusActive' -> % ok to register the Resource.
- NewLocal = ?etr_add_member(Local, Resource),
- RecoveryCoord = corba:create_subobject_key(Self, ?tr_get_etrap(Env)),
- {reply, RecoveryCoord, {Env, NewLocal}, ?tr_get_timeout(Env)};
- _-> % Not active anymore. New members not ok.
- corba:raise(?tr_inactive)
- end.
-
-
-
-%%-----------------------------------------------------------%
-%% function : register_subtran_aware
-%% Arguments: Self - its own object reference.
-%% State - Gen-Server State
-%% SubTransactionAwareResource object reference
-%% Returns : -
-%% Effect : Registers the specified object such that it
-%% will be notified when the subtransaction has
-%% commited or rolled back.
-%%------------------------------------------------------------
-
-register_subtran_aware(Self, {Env, Local}, SubTrAwareResource) ->
- case ?tr_get_parents(Env) of
- [] ->
- corba:raise(?tr_NotSubtr);
- _->
- type_check(?tr_get_typeCheck(Env), ?tr_SubtransactionAwareResource,
- "Coordinator:register_subtran_aware", SubTrAwareResource),
- NewL = ?etr_add_subAw(Local, SubTrAwareResource),
- {reply, ok, {Env, ?etr_set_self(NewL, Self)},
- ?tr_get_timeout(Env)}
- end.
-
-%%-----------------------------------------------------------%
-%% function : register_synchronization
-%% Arguments: Self - its own object reference.
-%% State - Gen-Server State
-%% Synchronization
-%% Returns : -
-%% Effect :
-%%------------------------------------------------------------
-
--spec register_synchronization(_, _, _) -> no_return().
-register_synchronization(_Self, {_Env, _Local}, _Synchronization) ->
- corba:raise(#'CosTransactions_SynchronizationUnavailable'{}).
-
-%register_synchronization(Self, {Env, Local}, Synchronization) ->
-% type_check(?tr_get_typeCheck(Env), ?tr_Synchronization,
-% "Coordinator:register_synchronization", Synchronization),
-% case ?etr_get_status(Local) of
-% 'StatusActive' ->
-% case catch ?tr_get_parents(Env) of
-% [] ->
-% {reply, ok, {Env, ?etr_add_sync(Local, Synchronization)},
-% ?tr_get_timeout(Env)};
-% [Parent|_] ->
-% case catch 'ETraP_Server':register_synchronization(Parent, Self) of
-% {'EXCEPTION', E} ->
-% corba:raise(E);
-% ok ->
-% {reply, ok, {Env, ?etr_add_sync(Local, Synchronization)},
-% ?tr_get_timeout(Env)};
-% What ->
-% corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_MAYBE})
-% end
-% end;
-% _ ->
-% corba:raise(?tr_inactive)
-% end.
-
-%%-----------------------------------------------------------%
-%% function : rollback_only
-%% Arguments: Self - its own object reference.
-%% State - Gen-Server State
-%% Returns : -
-%% Effect : The transaction associated with the target object
-%% is modified so that rollback IS the result.
-%%------------------------------------------------------------
-
-rollback_only(Self, {Env, Local}) ->
- case ?etr_get_status(Local) of
- 'StatusActive' ->
- NewL = ?etr_set_status(Local, 'StatusRolledBack'),
- NewEnv = ?tr_set_rollback(Env, true),
- ?etr_log(?tr_get_etrap(Env),{rollback, NewL}),
- send_info(?etr_get_members(NewL), 'CosTransactions_Resource', rollback),
- notify_subtrAware(rollback, ?etr_get_subAw(NewL), Self),
- {stop, normal, ok, {NewEnv, NewL}};
-%% Replace the reply above if allow synchronization
-% case ?etr_get_sync(Local) of
-% [] ->
-% {stop, normal, ok, {NewEnv, NewL}};
-% _ ->
-% {reply, ok, {NewEnv, NewL}}
-% end;
- _ ->
- corba:raise(?tr_inactive)
- end.
-
-%%-----------------------------------------------------------%
-%% function : get_transaction_name
-%% Arguments: Self - its own object reference.
-%% State - Gen-Server State
-%% Returns : string - which describes the transaction associated
-%% with the target object.
-%% Effect : Intended for debugging.
-%%------------------------------------------------------------
-
-get_transaction_name(_Self, {Env, Local}) ->
- {reply, ?tr_get_etrap(Env), {Env, Local}}.
-
-%%-----------------------------------------------------------%
-%% function : create_subtransaction
-%% Arguments: Self - its own object reference.
-%% State - Gen-Server State
-%% Returns : A control object if subtransactions are allowed,
-%% otherwise an exception is raised.
-%% Effect : A new subtransaction is created whos parent is
-%% the transaction associated with the target object.
-%% Exception: SubtransactionUnavailabe - no support for nested
-%% transactions.
-%% Inactive - already been prepared.
-%%------------------------------------------------------------
-
-create_subtransaction(Self, {Env, Local}) ->
- case ?etr_get_status(Local) of
- 'StatusActive' ->
- case ?tr_get_subTraOK(Env) of
- true ->
- ETraPName = 'ETraP_Common':create_name("subc"),
- Tname = 'ETraP_Common':create_name("subt"),
-
- %% Create context for the new object.
- State = ?tr_create_context(ETraPName, Tname,
- ?tr_get_typeCheck(Env),
- ?tr_get_hashMax(Env),
- ?tr_get_subTraOK(Env),
- ?tr_get_maxR(Env),
- ?tr_get_maxW(Env)),
-
-
- State2 = ?tr_add_parent(State, Self),
-
- State3 = ?tr_set_alarm(State2, ?tr_get_alarm(Env)),
-
- State4 = ?tr_set_timeout(State3, ?tr_get_timeout(Env)),
-
- Control = ?tr_start_child(?SUP_ETRAP(State4)),
- %% Set the SubCoordinator object reference and register it as participant.
- SubCoord = 'CosTransactions_Control':get_coordinator(Control),
- NewLocal = ?etr_add_member(Local, SubCoord),
- {reply, Control, {Env, NewLocal}, ?tr_get_timeout(Env)};
- _ ->
- %% subtransactions not allowed, raise exception.
- corba:raise(?tr_subunavailable)
- end;
- _->
- corba:raise(?tr_inactive)
- end.
-
-%%-----------------------------------------------------------%
-%% function : get_txcontext
-%% Arguments:
-%% Returns : PropagationContext
-%% Effect :
-%%------------------------------------------------------------
-
--spec get_txcontext(_, _) -> no_return().
-get_txcontext(_Self, {_Env, _Local}) ->
- corba:raise(#'CosTransactions_Unavailable'{}).
-
-%get_txcontext(Self, {Env, Local}) ->
-% Otid = #'CosTransactions_otid_t'{formatID=0,
-% bqual_length=0,
-% tid=[corba_object:hash(Self,
-% ?tr_get_hashMax(Env))]},
-% TrIDs = create_TransIdentities(?tr_get_parents(Env), Env, [], Otid),
-% C=case ?tr_get_parents(Env) of
-% [] ->
-% #'CosTransactions_TransIdentity'{coord=Self,
-% term=?tr_get_terminator(Env),
-% otid=Otid};
-% _->
-% #'CosTransactions_TransIdentity'{coord=Self,
-% term=?tr_NIL_OBJ_REF,
-% otid=Otid}
-% end,
-% case ?tr_get_timeout(Env) of
-% infinity ->
-% #'CosTransactions_PropagationContext'{timeout=0,
-% current= C,
-% parents=TrIDs};
-% T ->
-% #'CosTransactions_PropagationContext'{timeout=T/1000,
-% current= C,
-% parents=TrIDs}
-% end.
-
-%create_TransIdentities([], _, Parents, _) -> Parents;
-%create_TransIdentities([Phead|Ptail], Env, Parents, Otid) ->
-% NO=Otid#'CosTransactions_TransIdentity'{otid=
-% corba_object:hash(Phead,
-% ?tr_get_hashMax(Env))},
-% create_TransIdentities([Phead|Ptail], Env, Parents++
-% [#'CosTransactions_TransIdentity'{coord=Phead,
-% term=?tr_NIL_OBJ_REF,
-% otid=NO}],
-% Otid).
-
-
-%%--------- Inherit from CosTransactions::Synchronization ---
-
-%%-----------------------------------------------------------%
-%% function : before_completion
-%% Arguments:
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-
-%before_completion(Self, {Env, Local}) ->
-% send_info(?etr_get_sync(Local),
-% 'CosTransactions_Synchronization', before_completion),
-% {reply, ok, {Env, Local}}.
-
-%%-----------------------------------------------------------%
-%% function : after_completion
-%% Arguments:
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-
-%after_completion(Self, {Env, Local}, Status) ->
-% send_info(?etr_get_sync(Local), Status,
-% 'CosTransactions_Synchronization', after_completion),
-% {stop, normal, ok, {Env, Local}}.
-
-%%--------------- IMPLEMENTATION SPECIFIC -------------------
-%%-----------------------------------------------------------%
-%% function : start_object
-%% Arguments:
-%% Returns : EXIT, EXCEPTION, or {ok, State}
-%% Effect : used by init/1 only.
-%%------------------------------------------------------------
-
-start_object(Env)->
- ?put_debug_data(self, Env),
- Local = ?etr_get_init(Env),
- LogName = ?tr_get_etrap(Env),
- case catch file:read_file_info(LogName) of
- {error, enoent} ->
- %% File does not exist. It's the first time. No restart.
- ?debug_print("ETraP_Server:init(~p)~n",[?tr_get_etrap(Env)]),
- etrap_logmgr:start(LogName),
- {ok,
- {Env, ?etr_set_status(Local, 'StatusActive')},
- ?tr_get_timeout(Env)};
- {error, Reason} ->
- %% File exist but error occurred.
- ?tr_error_msg("Control (~p) Cannot open log file: ~p~n",
- [LogName, Reason]),
- {stop, "unable_to_open_log"};
- _ ->
- %% File exists, perform restart.
- etrap_logmgr:start(LogName),
- ?debug_print("RESTART ~p~n", [?tr_get_etrap(Env)]),
- prepare_restart({Env, ?etr_set_status(Local, 'StatusUnknown')},
- ?etr_read(?tr_get_etrap(Env), start))
- end.
-
-
-%%-----------------------------------------------------------%
-%% function : send_prepare
-%% Arguments: List of registred resources.
-%% Returns : ok - equal to void
-%% Effect : calls send_prepare/3, which sends a prepare call
-%% to resources participating in the transaction and then collect
-%% their votes. send_prepare will block until
-%% it recieves a reply from the resource.
-%%------------------------------------------------------------
-
-send_prepare(RegResources, Alarm) ->
- send_prepare(RegResources, [], Alarm).
-
-% All voted ReadOnly. We are done.
-send_prepare([], [], _) ->
- readOnly;
-
-% All voted commit (VC) or ReadOnly.
-send_prepare([], VC, Alarm) ->
- case catch try_timeout(Alarm) of
- false ->
- {commit, VC};
- _->
- {rollback, VC}
- end;
-
-send_prepare([Rhead|Rtail], VC, Alarm) ->
- ?debug_print("send_prepare()~n",[]),
- case catch 'CosTransactions_Resource':prepare(Rhead) of
- 'VoteCommit' ->
- case catch try_timeout(Alarm) of
- false ->
- _Env = ?get_debug_data(self),
- ?eval_debug_fun({?tr_get_etrap(_Env), send_prepare}, _Env),
- send_prepare(Rtail, VC++[Rhead], Alarm);
- _->
- %% Timeout, rollback. However, the resource did vote
- %% commit. Add it to the list.
- send_info(Rtail, 'CosTransactions_Resource', rollback),
- {rollback, VC++[Rhead]}
- end;
- 'VoteRollback' ->
- %% Don't care about timeout since we voted rollback.
- %% A rollback received. No need for more prepare-calls.
- %% See OMG 10-51, Transaction Service:v1.0
- send_info(Rtail, 'CosTransactions_Resource', rollback),
- {rollback, VC};
- 'VoteReadOnly' ->
- case catch try_timeout(Alarm) of
- false ->
- send_prepare(Rtail, VC, Alarm);
- _->
- %% timeout, reply rollback.
- send_info(Rtail, 'CosTransactions_Resource', rollback),
- {rollback, VC}
- end;
- {'EXCEPTION',E} when is_record(E, 'TIMEOUT') ->
- ?tr_error_msg("Coordinator:prepare( ~p )~nObject unreachable.~n",
- [Rhead]),
- %% Since we use presumed abort we will rollback the transaction.
- send_info(Rtail, 'CosTransactions_Resource', rollback),
- {rollback, VC};
- {'EXCEPTION',E} when is_record(E, 'TRANSIENT') ->
- ?tr_error_msg("Coordinator:prepare( ~p )~nObject unreachable.~n",
- [Rhead]),
- %% Since we use presumed abort we will rollback the transaction.
- send_info(Rtail, 'CosTransactions_Resource', rollback),
- {rollback, VC};
- {'EXCEPTION',E} when is_record(E, 'COMM_FAILURE') ->
- ?tr_error_msg("Coordinator:prepare( ~p )~nObject unreachable.~n",
- [Rhead]),
- %% Since we use presumed abort we will rollback the transaction.
- send_info(Rtail, 'CosTransactions_Resource', rollback),
- {rollback, VC};
- {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') ->
- ?tr_error_msg("Coordinator:prepare( ~p )~nObject unreachable.~n",
- [Rhead]),
- send_info(Rtail, 'CosTransactions_Resource', rollback),
- {rollback, VC};
- {'EXCEPTION', Exc} ->
- ?tr_error_msg("Coordinator:prepare( ~p )~nThe Object raised exception: ~p~n",
- [Rhead, Exc]),
- send_info(Rtail, 'CosTransactions_Resource', rollback),
- %% This can occur if a subtransaction get one or more
- %% "VoteCommit" followed by a "VoteRollback".
- %% The subtransaction then do a send_decision(rollback),
- %% which can generate Heuristic decisions. Must rollback
- %% since at least one participant voted rollback.
- {'EXCEPTION', Exc, VC, Rhead};
- Other ->
- ?tr_error_msg("Coordinator:prepare( ~p ) failed. REASON ~p~n",
- [Rhead, Other]),
- send_info(Rtail, 'CosTransactions_Resource', rollback),
- {failed, VC}
- end.
-
-%%-----------------------------------------------------------%
-%% function : type_check
-%% Arguments: Bool - perform typecheck?
-%% ID - Type it should be.
-%% Func - Name of the function (for error_msg)
-%% Obj - objectrefernce to test.
-%% Returns : 'ok' or raises exception.
-%% Effect :
-%%------------------------------------------------------------
-type_check(false, _, _, _) ->
- ok;
-type_check(_, ID, Func, Obj) ->
- case catch corba_object:is_a(Obj,ID) of
- true ->
- ok;
- _ ->
- ?tr_error_msg("~p( ~p ) Bad argument!!~n", [Func, Obj]),
- corba:raise(?tr_badparam)
- end.
-
-%%-----------------------------------------------------------%
-%% function : is_heuristic
-%% Arguments: Exception
-%% Returns : boolean
-%% Effect : Returns true if the exception is a heuristic exc.
-%%------------------------------------------------------------
-
-is_heuristic(E) when is_record(E, 'CosTransactions_HeuristicMixed') -> true;
-is_heuristic(E) when is_record(E, 'CosTransactions_HeuristicHazard') -> true;
-is_heuristic(E) when is_record(E, 'CosTransactions_HeuristicCommit') -> true;
-is_heuristic(E) when is_record(E, 'CosTransactions_HeuristicRollback') -> true;
-is_heuristic(_) -> false.
-
-%%-----------------------------------------------------------%
-%% function : exception_set
-%% Arguments: Genserver state
-%% Returns :
-%% Effect : Used when restarting.
-%%------------------------------------------------------------
-
-exception_set({Env,Local}) ->
- case ?etr_get_exc(Local) of
- void ->
- self() ! {suicide, self()},
- {ok, {Env, Local}};
- _ ->
- {ok, {Env, Local}}
- end.
-
-%%-----------------------------------------------------------%
-%% function : set_exception
-%% Arguments: Locally defined #exc{}
-%% Heuristic mixed or hazard Exeption
-%% Returns : Altered locally defined #exc{}
-%% Effect : Set the correct tuple member to true.
-%%------------------------------------------------------------
-
-set_exception(Exc, E) when is_record(E, 'CosTransactions_HeuristicMixed') ->
- Exc#exc{mixed = true};
-set_exception(Exc, E) when is_record(E, 'CosTransactions_HeuristicHazard') ->
- Exc#exc{hazard = true};
-set_exception(Exc, _) -> Exc.
-
-%%-----------------------------------------------------------%
-%% function : send_forget
-%% Arguments:
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-
-send_forget([], _) -> ok;
-send_forget([Rhead|Rtail], LogName) ->
- ?debug_print("send_forget()~n",[]),
- _Env = ?get_debug_data(self),
- case catch 'CosTransactions_Resource':forget(Rhead) of
- ok ->
- ?eval_debug_fun({?tr_get_etrap(_Env), send_forget1}, _Env),
- ?etr_log(LogName, {forgotten, Rhead}),
- ?eval_debug_fun({?tr_get_etrap(_Env), send_forget2}, _Env),
- send_forget(Rtail, LogName);
- Other ->
- ?tr_error_msg("CosTransactions_Coordinator failed sending forget to ~p~nREASON: ~p~n",
- [Rhead, Other]),
- ?eval_debug_fun({?tr_get_etrap(_Env), send_forget3}, _Env),
- ?etr_log(LogName, {not_forgotten, Rhead}),
- ?eval_debug_fun({?tr_get_etrap(_Env), send_forget4}, _Env),
- send_forget(Rtail, LogName)
- end.
-
-%%-----------------------------------------------------------%
-%% function : send_decision
-%% Arguments: List of registred resources which vote commit.
-%% Vote - the outcome of the transaction.
-%% Returns : ok - equal to void
-%% Effect : Inform those who voted commit of the outcome.
-%% They who voted rollback already knows the outcome.
-%% They who voted ReadOnly are not affected.
-%%------------------------------------------------------------
-
-%%-- Adding extra parameters
-send_decision({Env, Local}, Reply, Vote) ->
- send_decision({Env, Local}, Reply, ?etr_get_vc(Local), Vote, #exc{}, [], 0).
-send_decision({Env, Local}, Reply, Vote, VC) ->
- send_decision({Env, Local}, Reply, VC, Vote, #exc{}, [], 0).
-send_decision(State, no_reply, VC, Vote, Exc) ->
- send_decision(State, no_reply, VC, Vote, Exc, [], 0).
-
-%%-- Decision sent to all members. Do not reply (used when restarting).
-send_decision({Env, Local}, no_reply, [], _, #exc{mixed = true}, [], _) ->
- {Env, ?etr_set_exc(Local, ?tr_mixed)};
-send_decision({Env, Local}, no_reply, [], _, #exc{hazard = true}, [], _) ->
- {Env, ?etr_set_exc(Local, ?tr_hazard)};
-send_decision({Env, Local}, no_reply, [], _, _, [], _) ->
- {Env, Local};
-send_decision({Env, Local}, no_reply, [], Vote, Exc, Failed, Times) ->
- case ?tr_get_maxR(Env) of
- Times ->
- ?tr_error_msg("MAJOR ERROR, failed sending commit decision to: ~p. Tried ~p times.", [Failed,Times]),
- {Env, ?etr_set_exc(Local, ?tr_hazard)};
- _->
- timer:sleep(?tr_get_maxW(Env)),
- NewTimes = Times+1,
- send_decision({Env, Local}, no_reply, Failed, Vote, Exc, [], NewTimes)
- end;
-%%-- end special cases.
-
-%% Decision sent to all members. Test exceptions.
-send_decision({Env, Local}, Reply, [], Vote, Exc, [], _) ->
- notify_subtrAware(Vote, ?etr_get_subAw(Local), ?etr_get_self(Local)),
- test_exc(Exc, Vote, Reply, {Env, Local});
-%% Decision not sent to all members (one or more failed). Retry.
-send_decision({Env, Local}, Reply, [], Vote, Exc, Failed, Times) ->
- case ?tr_get_maxR(Env) of
- Times ->
- ?tr_error_msg("MAJOR ERROR, failed sending commit decision to: ~p. Tried ~p times.", [Failed,Times]),
- notify_subtrAware(Vote, ?etr_get_subAw(Local), ?etr_get_self(Local)),
- test_exc(Exc#exc{hazard = true}, Vote, Reply, {Env, Local});
- _->
- NewTimes = Times+1,
- timer:sleep(?tr_get_maxW(Env)),
- send_decision({Env, Local}, Reply, Failed, Vote, Exc, [], NewTimes)
- end;
-
-send_decision({Env, Local}, Reply, [Rhead|Rtail], Vote, Exc, Failed, Times) ->
- ?debug_print("Coordinator:send_decision(~p) Try: ~p~n",[Vote, Times]),
- case catch 'CosTransactions_Resource':Vote(Rhead) of
- ok ->
- ?etr_log(?tr_get_etrap(Env),{sent, Rhead}),
- send_decision({Env, Local}, Reply, Rtail, Vote, Exc, Failed, Times);
- {'EXCEPTION', E} when Vote == commit andalso
- is_record(E, 'CosTransactions_NotPrepared') ->
- ?debug_print("send_decision resource unprepared~n",[]),
- case catch 'CosTransactions_Resource':prepare(Rhead) of
- 'VoteCommit' ->
- send_decision({Env, Local}, Reply, [Rhead|Rtail], Vote, Exc, Failed, Times);
- 'VoteRollback' ->
- send_decision({Env, Local}, Reply, Rtail, Vote, Exc#exc{mixed = true}, Failed, Times);
- {'EXCEPTION', E} ->
- {SetExc, NewL, DidFail} =
- evaluate_answer(E, Rhead, Vote, Exc,
- ?tr_get_etrap(Env), Local),
- send_decision({Env, NewL}, Reply, Rtail, Vote, SetExc, DidFail++Failed, Times)
- end;
- {'EXCEPTION', E} ->
- {SetExc, NewL, DidFail} =
- evaluate_answer(E, Rhead, Vote, Exc, ?tr_get_etrap(Env), Local),
- ?tr_error_msg("Resource:~p( ~p )~nRaised Exception: ~p~n",
- [Vote, Rhead, E]),
- send_decision({Env, NewL}, Reply, Rtail, Vote, SetExc, DidFail++Failed, Times);
- {'EXIT', _} ->
- send_decision({Env, Local}, Reply, Rtail,
- Vote, Exc, [Rhead|Failed], Times);
- Other ->
- ?tr_error_msg("Resource:~p( ~p ) failed.~nREASON: ~p~n",
- [Vote, Rhead, Other]),
- case catch corba_object:non_existent(Rhead) of
- true when Vote == commit ->
- %% Presumed rollback
- send_decision({Env, Local}, Reply, Rtail, Vote,
- Exc#exc{mixed = true}, Failed, Times);
- true ->
- %% Presumed rollback
- send_decision({Env, Local}, Reply, Rtail, Vote,
- Exc#exc{hazard = true}, Failed, Times);
- _ ->
- send_decision({Env, Local}, Reply, Rtail,
- Vote, Exc, [Rhead|Failed], Times)
- end
- end.
-
-%%-----------------------------------------------------------%
-%% function : notify_subtrAware,
-%% Arguments:
-%% Returns :
-%% Effect : Invoke an operation on a list of objects. We don't
-%% care about return values or exceptions.
-%%------------------------------------------------------------
-
-notify_subtrAware(commit, Resources, Self) ->
- send_info(Resources, Self,
- 'CosTransactions_SubtransactionAwareResource',
- commit_subtransaction);
-notify_subtrAware(_, Resources, _) ->
- send_info(Resources, 'CosTransactions_SubtransactionAwareResource',
- rollback_subtransaction).
-
-%%-----------------------------------------------------------%
-%% function : send_info
-%% Arguments: ObjectList - List of object refernces to call.
-%% M - Module
-%% F - Function
-%% (Arg - required arguments)
-%% Returns : ok
-%% Effect : A lightweight function to be used when we don't
-%% "care" about the return value.
-%%------------------------------------------------------------
-
-send_info([], _, _, _) ->
- ok;
-send_info([Rhead|Rtail], Arg, M, F) ->
- ?debug_print("~p( ~p )~n",[F, Arg]),
- case catch M:F(Rhead, Arg) of
- {'EXIT',R} ->
- ?tr_error_msg("~p:~p(~p, ~p) returned {'EXIT',~p}", [M,F,Rhead,Arg,R]);
- {'EXCEPTION',E} ->
- ?tr_error_msg("~p:~p(~p, ~p) returned {'EXCEPTION',~p}", [M,F,Rhead,Arg,E]);
- _->
- ok
- end,
- send_info(Rtail, Arg, M, F).
-
-send_info([], _, _) ->
- ok;
-send_info([Rhead|Rtail], M, F) ->
- ?debug_print("~p( )~n",[F]),
- case catch M:F(Rhead) of
- {'EXIT',R} ->
- ?tr_error_msg("~p:~p(~p) returned {'EXIT',~p}", [M,F,Rhead,R]);
- {'EXCEPTION',E} ->
- ?tr_error_msg("~p:~p(~p) returned {'EXCEPTION',~p}", [M,F,Rhead,E]);
- _->
- ok
- end,
- send_info(Rtail, M, F).
-
-%%-----------------------------------------------------------%
-%% function : evaluate_answer
-%% Arguments:
-%% Returns :
-%% Effect : Check what kind of exception we received.
-%%------------------------------------------------------------
-
-evaluate_answer(E, Rhead, _Vote, Exc, Log, Local)
- when is_record(E, 'CosTransactions_HeuristicMixed') ->
- ?etr_log(Log, {heuristic, {Rhead, E}}),
- {Exc#exc{mixed = true}, ?etr_add_raisedH(Local, Rhead), []};
-evaluate_answer(E, Rhead, _Vote, Exc, Log, Local)
- when is_record(E, 'CosTransactions_HeuristicHazard') ->
- ?etr_log(Log, {heuristic, {Rhead, E}}),
- {Exc#exc{hazard = true}, ?etr_add_raisedH(Local, Rhead), []};
-evaluate_answer(E, Rhead, Vote, Exc, Log, Local)
- when is_record(E, 'CosTransactions_HeuristicCommit') ->
- case Vote of
- commit ->
- ?etr_log(Log, {heuristic, {Rhead, E}}),
- {Exc, ?etr_add_raisedH(Local, Rhead), []};
- _->
- ?etr_log(Log, {heuristic, {Rhead, ?tr_mixed}}),
- {Exc#exc{mixed = true}, ?etr_add_raisedH(Local, Rhead), []}
- end;
-evaluate_answer(E, Rhead, Vote, Exc, Log, Local)
- when is_record(E, 'CosTransactions_HeuristicRollback')->
- case Vote of
- rollback ->
- ?etr_log(Log, {heuristic, {Rhead, ?tr_rollback}}),
- {Exc, ?etr_add_raisedH(Local, Rhead), []};
- _->
- ?etr_log(Log, {heuristic, {Rhead, ?tr_mixed}}),
- {Exc#exc{mixed = true}, ?etr_add_raisedH(Local, Rhead), []}
- end;
-evaluate_answer(E, Rhead, Vote, Exc, Log, Local)
- when Vote == commit andalso is_record(E, 'TRANSACTION_ROLLEDBACK') ->
- ?etr_log(Log, {heuristic, {Rhead, ?tr_mixed}}),
- {Exc#exc{mixed = true}, ?etr_add_raisedH(Local, Rhead), []};
-evaluate_answer(E, Rhead, Vote, Exc, Log, Local) when is_record(E, 'TIMEOUT') ->
- ?tr_error_msg("Coordinator:~p( ~p ) Object unreachable.~nReason: ~p~n",
- [Vote, Rhead, E]),
- case catch corba_object:non_existent(Rhead) of
- true ->
- %% Since we have presumed abort, the child will
- %% assume rollback if this server do not exist any more.
- ?etr_log(Log, {heuristic, {Rhead, ?tr_hazard}}),
- {Exc#exc{hazard = true}, Local, []};
- _ ->
- {Exc, Local, [Rhead]}
- end;
-evaluate_answer(E, Rhead, Vote, Exc, Log, Local) when is_record(E, 'TRANSIENT') ->
- ?tr_error_msg("Coordinator:~p( ~p ) Object unreachable.~nReason: ~p~n",
- [Vote, Rhead, E]),
- case catch corba_object:non_existent(Rhead) of
- true ->
- %% Since we have presumed abort, the child will
- %% assume rollback if this server do not exist any more.
- ?etr_log(Log, {heuristic, {Rhead, ?tr_hazard}}),
- {Exc#exc{hazard = true}, Local, []};
- _ ->
- {Exc, Local, [Rhead]}
- end;
-evaluate_answer(E, Rhead, Vote, Exc, Log, Local) when is_record(E, 'COMM_FAILURE') ->
- ?tr_error_msg("Coordinator:~p( ~p ) Object unreachable.~nReason: ~p~n",
- [Vote, Rhead, E]),
- case catch corba_object:non_existent(Rhead) of
- true ->
- %% Since we have presumed abort, the child will
- %% assume rollback if this server do not exist any more.
- ?etr_log(Log, {heuristic, {Rhead, ?tr_hazard}}),
- {Exc#exc{hazard = true}, Local, []};
- _ ->
- {Exc, Local, [Rhead]}
- end;
-evaluate_answer(E, Rhead, Vote, Exc, Log, Local)when is_record(E, 'OBJECT_NOT_EXIST') ->
- ?tr_error_msg("Coordinator:~p( ~p ) Object unreachable.~nReason: ~p~n",
- [Vote, Rhead, E]),
- %% Since we have presumed abort, the child will
- %% assume rollback if this server do not exist any more.
- ?etr_log(Log, {heuristic, {Rhead, ?tr_hazard}}),
- {Exc#exc{hazard = true}, Local, []};
-evaluate_answer(Unknown, Rhead, Vote, Exc, _Log, Local)->
- ?tr_error_msg("Coordinator:~p( ~p ). Unknown reply: ~p.~n",
- [Vote, Rhead, Unknown]),
- {Exc, Local, []}.
-
-
-%%-----------------------------------------------------------%
-%% function : test_exc
-%% Arguments: Exc - instance of #exc{} locally declared.
-%% Vote - 'rollback' or 'commit'
-%% Reply - If no exceptions this is the default reply.
-%% State - genserver state
-%% Returns :
-%% Effect : Raise the correct exception or simply reply to
-%% the genserver. NOTE that the testing for exceptions
-%% differs if we are performing a rollback or commit.
-%% Check if Mixed first; takes priority over Hazard.
-%% HeuristicRollback and VoteCommit together give
-%% HeuristicMixed
-%% HeuristicCommit and VoteRollback together give
-%% HeuristicMixed
-%%------------------------------------------------------------
-
-test_exc(#exc{mixed = true}, _, _, {Env, Local}) ->
- {reply, {'EXCEPTION', ?tr_mixed}, {Env, ?etr_set_exc(Local, ?tr_mixed)}};
-% Left out for now to avoid dialyzer warning.
-%test_exc(#exc{rollback = true}, commit, _, {Env, Local}) ->
-% {reply, {'EXCEPTION', ?tr_mixed}, {Env, ?etr_set_exc(Local, ?tr_mixed)}};
-% Left out for now to avoid dialyzer warning.
-%test_exc(#exc{commit = true}, rollback, _, {Env, Local}) ->
-% {reply, {'EXCEPTION', ?tr_mixed}, {Env, ?etr_set_exc(Local, ?tr_mixed)}};
-test_exc(#exc{hazard = true}, _, _, {Env, Local}) ->
- {reply, {'EXCEPTION', ?tr_hazard}, {Env, ?etr_set_exc(Local, ?tr_hazard)}};
-test_exc(_, _, {'EXCEPTION', E}, {Env, Local})
- when is_record(E, 'TRANSACTION_ROLLEDBACK')->
- {stop, normal, {'EXCEPTION', E}, {Env, Local}};
-%% Replace the case above if allow synchronization
-%test_exc(_, _, {'EXCEPTION', E}, {Env, Local})
-% when record(E, 'TRANSACTION_ROLLEDBACK')->
-% case ?etr_get_sync(Local) of
-% [] ->
-% {stop, normal, {'EXCEPTION', E}, {Env, Local}};
-% _->
-% {reply, {'EXCEPTION', E}, {Env, Local}}
-% end;
-test_exc(_, _, {'EXCEPTION', E}, State) ->
- {reply, {'EXCEPTION', E}, State};
-test_exc(_, _, Reply, {Env, Local}) ->
- {stop, normal, Reply, {Env, Local}}.
-%% Replace the case above if allow synchronization
-%test_exc(_, _, Reply, {Env, Local}) ->
-% case ?etr_get_sync(Local) of
-% [] ->
-% {stop, normal, Reply, {Env, Local}};
-% _ ->
-% {reply, Reply, {Env, Local}}
-% end.
-
-%%-----------------------------------------------------------%
-%% function : evaluate_status
-%% Arguments:
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-
-evaluate_status(Status) ->
- case Status of
- 'StatusCommitted' -> commit;
- 'StatusCommitting' -> commit;
- 'StatusMarkedRollback' -> rollback;
- 'StatusRollingBack' -> rollback;
- 'StatusRolledBack' -> rollback;
- 'StatusActive' -> rollback;
- 'StatusPrepared' -> rollback;
- 'StatusUnknown' -> rollback;
- 'StatusNoTransaction' -> rollback;
- 'StatusPreparing' -> rollback;
- _-> rollback
- end.
-
-
-%%-----------------------------------------------------------%
-%% function : prepare_restart
-%% Arguments:
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-
-%% The file contains no data. The coordinator crashed before
-%% a prepare-call was made. Presumed rollback.
-prepare_restart(State, eof) ->
- ?debug_print("prepare_restart: eof, init~n",[]),
- self() ! {suicide, self()},
- {ok, State};
-%% Collected all necessary votes. Do commit_restart.
-prepare_restart({Env, _}, {{pre_vote, _Vote, Data}, Cursor}) ->
- ?debug_print("prepare_restart: pre_vote( ~p )~n",[_Vote]),
- if
- ?tr_is_root(Env) ->
- commit_restart({Env, Data},
- ?etr_read(?tr_get_etrap(Env), Cursor), root);
- true ->
- commit_restart({Env, Data},
- ?etr_read(?tr_get_etrap(Env), Cursor), subCoord)
- end;
-%% 'rollback' called without 'prepare'. This case occurs if the Coordinator
-%% crashes when send_info or notify_subtrAware.
-prepare_restart({Env, _}, {{rollback, NewL}, _Cursor}) ->
- ?debug_print("prepare_restart: pre_vote( rollback )~n",[]),
- send_info(?etr_get_members(NewL), 'CosTransactions_Resource', rollback),
- notify_subtrAware(rollback, ?etr_get_subAw(NewL), ?etr_get_self(NewL)),
- self() ! {suicide, self()},
- {ok, {Env, NewL}};
-%% Something is wrong in the log.
-prepare_restart(_, _) ->
- ?tr_error_msg("Internal log read failed:~n", []),
- {stop, {error, "restart failed"}}.
-
-%%-----------------------------------------------------------%
-%% function : commit_restart
-%% Arguments: Env - server context
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-commit_restart({Env, Local}, Data, Phase) ->
- Exc = set_exception(#exc{}, ?etr_get_exc(Local)),
- commit_restart({Env, Local}, Data, Phase, Exc).
-
-%% Normal case. No errors no exceptions.
-commit_restart({Env, Local}, {{sent, Obj}, Cursor}, Vote, Exc) ->
- ?debug_print("commit_restart: sent~n",[]),
- commit_restart({Env, ?etr_remove_vc(Local, Obj)},
- ?etr_read(?tr_get_etrap(Env), Cursor), Vote, Exc);
-commit_restart({Env, Local}, {{heuristic, {Obj,E}}, Cursor}, Vote, Exc) ->
- ?debug_print("commit_restart: heuristic ~p~n",[E]),
- NewExc = set_exception(Exc, E),
- commit_restart({Env, ?etr_add_raisedH(Local, Obj)},
- ?etr_read(?tr_get_etrap(Env), Cursor), Vote, NewExc);
-
-
-%% --- cases which only can occure once in the log ------------
-
-%% The file contains no data. The coordinator crashed before
-%% a decision was made. Causes rollback.
-commit_restart({E, L}, eof, root, Exc) ->
- ?debug_print("commit_restart: eof init (root only)~n",[]),
- {Env, Local} = send_decision({E, L}, no_reply, ?etr_get_vc(L),
- rollback, Exc),
- exception_set({Env, Local});
-%% Replace the reply above if allow synchronization
-% case ?etr_get_sync(Local) of
-% [] ->
-% exception_set({Env, Local});
-% SynchObjs ->
-% {ok, {Env, Local}}
-% end;
-
-
-%% Passed the prepare_restart. Not received a commit decision from the
-%% parent.
-commit_restart({E, L}, eof, subCoord, Exc) ->
- ?debug_print("commit_restart: eof init (subcoord only)~n",[]),
- case catch corba_object:non_existent(?tr_get_parent(E)) of
- true ->
- %% Presumed rollback.
- {Env, Local} = send_decision({E, L}, no_reply, ?etr_get_vc(L),
- rollback, Exc),
- self() ! {suicide, self()},
- {ok, {Env, Local}};
-%% Replace the reply above if allow synchronization
-% case ?etr_get_sync(Local) of
-% [] ->
-% self() ! {suicide, self()},
-% {ok, {Env, Local}};
-% SynchObjs ->
-% case ?tr_get_parents(Env) of
-% [] ->
-% send_info(SynchObjs, ?etr_get_status(Local),
-% 'CosTransactions_Synchronization', after_completion);
-% _->
-% ok
-% end,
-% self() ! {suicide, self()},
-% {ok, {Env, Local}}
-% end;
- _->
- {ok, {E, L}}
- end;
-
-commit_restart({Env, Local}, eof, Vote, Exc) ->
- ?debug_print("commit_restart: eof VOTE: ~p~n",[Vote]),
- case ?etr_get_vc(Local) of
- [] ->
- ?debug_print("commit_restart: all sent, test exc~n",[]),
- exception_set({Env, Local});
- VC ->
- ?debug_print("commit_restart: note done. send more~n",[]),
- State = send_decision({Env, Local}, no_reply, VC, Vote, Exc),
- exception_set(State)
- end;
-
-%% Decision made, i.e. rollback or commit.
-commit_restart({Env, Local}, {rollback, Cursor}, _Phase, Exc) ->
- ?debug_print("commit_restart: decided rollback~n",[]),
- commit_restart({Env, ?etr_set_status(Local, 'StatusRolledBack')},
- ?etr_read(?tr_get_etrap(Env), Cursor), rollback, Exc);
-commit_restart({Env, Local}, {commit, Cursor}, _Phase, Exc) ->
- ?debug_print("commit_restart: decided commit~n",[]),
- commit_restart({Env, ?etr_set_status(Local, 'StatusCommitted')},
- ?etr_read(?tr_get_etrap(Env), Cursor), commit, Exc);
-commit_restart({Env, Local}, {forget_phase, Cursor}, _, _) ->
- ?debug_print("commit_restart: start sending forget~n",[]),
- forget_restart({Env, Local}, ?etr_read(?tr_get_etrap(Env), Cursor));
-
-commit_restart({_Env, _Local}, _R, _, _) ->
- ?debug_print("RESTART FAIL: ~p~n",[_R]),
- ?tr_error_msg("Internal log read failed:~n", []),
- exit("restart failed").
-
-%%-----------------------------------------------------------%
-%% function : forget_restart
-%% Arguments: {Env, Local} - server context
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-
-%% Exception logged. Test if we issued a 'forget()' to the Resource.
-forget_restart({Env, Local}, eof) ->
- case ?etr_get_raisedH(Local) of
- [] ->
- ?debug_print("forget_restart: all done~n",[]);
- Left ->
- ?debug_print("forget_restart: not done. send more~n",[]),
- send_forget(Left, ?tr_get_etrap(Env))
- end,
- self() ! {suicide, self()},
- {ok, {Env, Local}};
-%% Replace the reply above if allow synchronization
-% case ?etr_get_sync(Local) of
-% [] ->
-% self() ! {suicide, self()},
-% {ok, {Env, Local}};
-% SynchObjs ->
-% case ?tr_get_parents(Env) of
-% [] ->
-% send_info(SynchObjs, ?etr_get_status(Local),
-% 'CosTransactions_Synchronization', after_completion),
-% self() ! {suicide, self()},
-% {ok, {Env, Local}};
-% _->
-% {ok, {Env, Local}}
-% end
-% end;
-forget_restart({Env, Local}, {{forgotten, Obj}, Cursor}) ->
- ?debug_print("forget_restart: forgotten heuristic~n",[]),
- NewL = ?etr_remove_raisedH(Local, Obj),
- forget_restart({Env, NewL}, ?etr_read(?tr_get_etrap(Env), Cursor));
-forget_restart({Env, Local}, {{not_forgotten, Obj}, Cursor}) ->
- ?debug_print("forget_restart: not_forgotten~n",[]),
- NewL = ?etr_remove_raisedH(Local, Obj),
- send_forget([Obj], dummy),
- forget_restart({Env, NewL}, ?etr_read(?tr_get_etrap(Env), Cursor)).
-
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/cosTransactions/src/Makefile b/lib/cosTransactions/src/Makefile
deleted file mode 100644
index 4cc1e487c2..0000000000
--- a/lib/cosTransactions/src/Makefile
+++ /dev/null
@@ -1,181 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1999-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-EBIN=../ebin
-
-ifeq ($(TYPE),debug)
-ERL_COMPILE_FLAGS += -Ddebug -W
-endif
-
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(COSTRANSACTIONS_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/cosTransactions-$(VSN)
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-
-MODULES = \
- ETraP_Common \
- etrap_logmgr \
- ETraP_Server_impl \
- CosTransactions_Terminator_impl \
- CosTransactions_TransactionFactory_impl \
- cosTransactions
-
-ERL_FILES = $(MODULES:%=%.erl)
-HRL_FILES = \
- ETraP_Common.hrl
-
-GEN_ERL_FILES = \
- oe_CosTransactions.erl \
- CosTransactions_Control.erl \
- CosTransactions_Coordinator.erl \
- CosTransactions_HeuristicCommit.erl \
- CosTransactions_HeuristicHazard.erl \
- CosTransactions_HeuristicMixed.erl \
- CosTransactions_HeuristicRollback.erl \
- CosTransactions_Inactive.erl \
- CosTransactions_InvalidControl.erl \
- CosTransactions_NoTransaction.erl \
- CosTransactions_NotPrepared.erl \
- CosTransactions_NotSubtransaction.erl \
- CosTransactions_RecoveryCoordinator.erl \
- CosTransactions_Resource.erl \
- CosTransactions_SubtransactionAwareResource.erl \
- CosTransactions_SubtransactionsUnavailable.erl \
- CosTransactions_Terminator.erl \
- CosTransactions_TransactionFactory.erl \
- CosTransactions_Unavailable.erl \
- CosTransactions_SynchronizationUnavailable.erl \
- CosTransactions_TransIdentity.erl \
- CosTransactions_PropagationContext.erl \
- CosTransactions_otid_t.erl \
- CosTransactions_WrongTransaction.erl \
- ETraP_Server.erl
-# CosTransactions_Synchronization.erl \
-
-EXTERNAL_INC_PATH = ../include
-
-GEN_HRL_FILES = \
- oe_CosTransactions.hrl \
- CosTransactions.hrl \
- CosTransactions_Control.hrl \
- CosTransactions_Coordinator.hrl \
- CosTransactions_RecoveryCoordinator.hrl \
- CosTransactions_Resource.hrl \
- CosTransactions_SubtransactionAwareResource.hrl \
- CosTransactions_Terminator.hrl \
- CosTransactions_TransactionFactory.hrl \
- ETraP.hrl \
- ETraP_Server.hrl
-# CosTransactions_Synchronization.hrl \
-
-EXTERNAL_GEN_HRL_FILES = $(GEN_HRL_FILES:%=$(EXTERNAL_INC_PATH)/%)
-
-GEN_FILES = $(GEN_ERL_FILES) $(EXTERNAL_GEN_HRL_FILES)
-
-TARGET_FILES = \
- $(GEN_ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR)) \
- $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-
-IDL_FILE = \
- CosTransactions.idl
-
-APPUP_FILE = cosTransactions.appup
-APPUP_SRC = $(APPUP_FILE).src
-APPUP_TARGET = $(EBIN)/$(APPUP_FILE)
-
-APP_FILE = cosTransactions.app
-APP_SRC = $(APP_FILE).src
-APP_TARGET = $(EBIN)/$(APP_FILE)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_IDL_FLAGS += -pa $(ERL_TOP)/lib/cosTransactions/ebin \
- -pa $(ERL_TOP)/lib/ic/ebin\
- -pa $(ERL_TOP)/lib/orber/ebin
-
-# The -pa option is just used temporary until erlc can handle
-# includes from other directories than ../include .
-ERL_COMPILE_FLAGS += \
- $(ERL_IDL_FLAGS) \
- -I$(ERL_TOP)/lib/cosTransactions/include \
- -I$(ERL_TOP)/lib/orber/include \
- +'{parse_transform,sys_pre_attributes}' \
- +'{attribute,insert,app_vsn,"cosTransactions_$(COSTRANSACTIONS_VSN)"}'
-
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
-
-debug:
- @${MAKE} TYPE=debug
-
-clean:
- rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET) IDL-GENERATED
- rm -f errs core *~
-
-$(APP_TARGET): $(APP_SRC)
- $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $(APP_SRC) > $(APP_TARGET)
-
-$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
-
-docs:
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-IDL-GENERATED: CosTransactions.idl
- $(gen_verbose)erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosTransactions.cfg"}' CosTransactions.idl
- $(V_at)mv $(GEN_HRL_FILES) $(EXTERNAL_INC_PATH)
- $(V_at)>IDL-GENERATED
-
-$(GEN_FILES): IDL-GENERATED
-
-$(TARGET_FILES): IDL-GENERATED
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
- $(INSTALL_DIR) "$(RELSYSDIR)/src"
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(GEN_ERL_FILES) $(IDL_FILE) "$(RELSYSDIR)/src"
- $(INSTALL_DIR) "$(RELSYSDIR)/include"
- $(INSTALL_DATA) $(EXTERNAL_GEN_HRL_FILES) "$(RELSYSDIR)/include"
-
-release_docs_spec:
diff --git a/lib/cosTransactions/src/cosTransactions.app.src b/lib/cosTransactions/src/cosTransactions.app.src
deleted file mode 100644
index 074d82f487..0000000000
--- a/lib/cosTransactions/src/cosTransactions.app.src
+++ /dev/null
@@ -1,44 +0,0 @@
-{application, cosTransactions,
- [{description, "The Erlang CosTransactions application"},
- {vsn, "%VSN%"},
- {modules,
- [
- etrap_logmgr,
- 'ETraP_Server_impl',
- 'CosTransactions_Terminator_impl',
- 'CosTransactions_TransactionFactory_impl',
- 'ETraP_Common',
- oe_CosTransactions,
- 'CosTransactions_Control',
- 'CosTransactions_Coordinator',
- 'CosTransactions_HeuristicCommit',
- 'CosTransactions_HeuristicHazard',
- 'CosTransactions_HeuristicMixed',
- 'CosTransactions_HeuristicRollback',
- 'CosTransactions_Inactive',
- 'CosTransactions_InvalidControl',
- 'CosTransactions_NoTransaction',
- 'CosTransactions_NotPrepared',
- 'CosTransactions_NotSubtransaction',
- 'CosTransactions_RecoveryCoordinator',
- 'CosTransactions_Resource',
- 'CosTransactions_SubtransactionAwareResource',
- 'CosTransactions_SubtransactionsUnavailable',
- 'CosTransactions_Terminator',
- 'CosTransactions_TransactionFactory',
- 'CosTransactions_Unavailable',
- 'CosTransactions_SynchronizationUnavailable',
- 'CosTransactions_TransIdentity',
- 'CosTransactions_PropagationContext',
- 'CosTransactions_otid_t',
- 'CosTransactions_WrongTransaction',
- 'ETraP_Server',
- cosTransactions
- ]
- },
- {registered, [cosTransactions_sup, oe_cosTransactionsFactory]},
- {applications, [orber, stdlib, kernel]},
- {env, []},
- {mod, {cosTransactions, []}},
- {runtime_dependencies, ["stdlib-2.0","orber-3.6.27","kernel-3.0","erts-7.0"]}
-]}.
diff --git a/lib/cosTransactions/src/cosTransactions.appup.src b/lib/cosTransactions/src/cosTransactions.appup.src
deleted file mode 100644
index f3eead4a0c..0000000000
--- a/lib/cosTransactions/src/cosTransactions.appup.src
+++ /dev/null
@@ -1,6 +0,0 @@
-{"%VSN%",
- [
- ],
- [
- ]
-}.
diff --git a/lib/cosTransactions/src/cosTransactions.erl b/lib/cosTransactions/src/cosTransactions.erl
deleted file mode 100644
index 60e5fff46d..0000000000
--- a/lib/cosTransactions/src/cosTransactions.erl
+++ /dev/null
@@ -1,116 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : cosTransactions.erl
-%% Purpose : Initialize the 'cosTransactions' application
-%%----------------------------------------------------------------------
-
--module(cosTransactions).
-
-%%--------------- INCLUDES -----------------------------------
-%% Local
--include_lib("ETraP_Common.hrl").
--include_lib("CosTransactions.hrl").
-%%--------------- EXPORTS-------------------------------------
-%% cosTransactions API external
--export([start/0, stop/0, start_factory/1, start_factory/0, stop_factory/1]).
-
-%% Application callbacks
--export([start/2, init/1, stop/1]).
-
-%%------------------------------------------------------------
-%% function : start/stop
-%% Arguments:
-%% Returns :
-%% Effect : Starts or stops the cosTRansaction application.
-%%------------------------------------------------------------
-
-start() ->
- application:start(cosTransactions).
-stop() ->
- application:stop(cosTransactions).
-
-%%------------------------------------------------------------
-%% function : start_factory
-%% Arguments: none or an argumentlist which by default is defined
-%% in ETraP_Common.hrl, i.e., '?tr_FAC_DEF'
-%% Returns : ObjectRef | {'EXCEPTION', _} | {'EXIT', Reason}
-%% Effect : Starts a CosTransactions_TransactionFactory
-%%------------------------------------------------------------
-
-start_factory() ->
- ?tr_start_child(?SUP_FAC(?tr_FAC_DEF)).
-
-start_factory(Args) when is_list(Args) ->
- ?tr_start_child(?SUP_FAC(Args));
-start_factory(Args) ->
- ?tr_error_msg("applications:start( ~p ) failed. Bad parameters~n", [Args]),
- exit("applications:start failed. Bad parameters").
-
-%%------------------------------------------------------------
-%% function : stop_factory
-%% Arguments: Factory Object Reference
-%% Returns : ok | {'EXCEPTION', _}
-%% Effect :
-%%------------------------------------------------------------
-
-stop_factory(Fac)->
- corba:dispose(Fac).
-
-%%------------------------------------------------------------
-%% function : start
-%% Arguments: Type - see module application
-%% Arg - see module application
-%% Returns :
-%% Effect : Module callback for application
-%%------------------------------------------------------------
-
-start(_, _) ->
- supervisor:start_link({local, ?SUPERVISOR_NAME}, cosTransactions, app_init).
-
-
-%%------------------------------------------------------------
-%% function : stop
-%% Arguments: Arg - see module application
-%% Returns :
-%% Effect : Module callback for application
-%%------------------------------------------------------------
-
-stop(_) ->
- ok.
-
-%%------------------------------------------------------------
-%% function : init
-%% Arguments:
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-
-%% Starting using create_factory/X
-init(own_init) ->
- {ok,{?SUP_FLAG, [?SUP_CHILD]}};
-%% When starting as an application.
-init(app_init) ->
- {ok,{?SUP_FLAG, [?SUP_CHILD]}}.
-
-
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/cosTransactions/src/etrap_logmgr.erl b/lib/cosTransactions/src/etrap_logmgr.erl
deleted file mode 100644
index a5d9affe7d..0000000000
--- a/lib/cosTransactions/src/etrap_logmgr.erl
+++ /dev/null
@@ -1,201 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : etrap_logmgr.erl
-%% Purpose : Make it easier to use disk_log.
-%%----------------------------------------------------------------------
-
--module(etrap_logmgr).
-
-%%--------------- INCLUDES -----------------------------------
-%% Local
--include_lib("ETraP_Common.hrl").
-%%--------------- IMPORTS-------------------------------------
-%%--------------- EXPORTS-------------------------------------
--export([start/1, stop/1, log_safe/2, log_lazy/2, get_next/2]).
-
-
-%%------------------------------------------------------------
-%% function : start
-%% Arguments: LogName - name of the disk_log.
-%% Returns :
-%% Effect : creating linked log
-%%------------------------------------------------------------
-
-start(LogName) ->
- case catch disk_log:open([{name, LogName},
- {file, LogName},
- {type, halt},
- {size, infinity}]) of
- {ok, LogName} ->
- ok;
- {error, Reason} ->
- ?tr_error_msg("Initiating internal log failed: ~p", [Reason]),
- exit({error, Reason});
- {repaired, LogName, {recovered, _Rec}, {badbytes, _Bad}} ->
- ok;
- Other ->
- ?tr_error_msg("Initiating internal log failed: ~p", [Other]),
- exit({error, Other})
- end.
-
-%%------------------------------------------------------------
-%% function : stop
-%% Arguments: LogName - name of the disk_log.
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-
-stop(LogName) ->
- case catch disk_log:close(LogName) of
- ok ->
- ok;
- {error, Reason} ->
- ?tr_error_msg("Stopping internal log failed: ~p", [Reason]),
- {error, Reason};
- Other ->
- ?tr_error_msg("Stopping internal log failed: ~p", [Other]),
- {error, Other}
- end.
-
-
-%%------------------------------------------------------------
-%% function : log_safe
-%% Arguments: LogName - name of the disk_log. If 'dummy' is
-%% used nothing should be logged. Reason, reuse code.
-%% LogRecord - record to store in the log.
-%% Returns :
-%% Effect : Writes a logrecord and synchronizes to make sure
-%% that the record is stored.
-%%------------------------------------------------------------
-
-log_safe(dummy, _) ->
- ok;
-log_safe(LogName, LogRecord) ->
- case write_safe(LogName, LogRecord) of
- ok ->
- ok;
- _ ->
- %% We have to catch the exit because in some cases
- %% it's not possible to abort action in the 2PC-protocol.
- case catch start(LogName) of
- ok ->
- write_safe(LogName, LogRecord);
- {'EXIT', Reason} ->
- {error, Reason}
- end
- end.
-
-
-write_safe(LogName, LogRecord) ->
- case catch disk_log:log(LogName, LogRecord) of
- ok -> % wrote to kernel successfully
- case catch disk_log:sync(LogName) of
- ok -> % Written to disk successfully
- ok;
- {error, Reason} ->
- ?tr_error_msg("Internal log write failed: ~p ~p",
- [Reason, LogName]),
- {error, Reason};
- Other ->
- ?tr_error_msg("Internal log write failed: ~p ~p",
- [Other, LogName]),
- {error, Other}
- end;
- {error, Reason} ->
- ?tr_error_msg("Internal log write failed: ~p ~p", [Reason, LogName]),
- {error, Reason};
- Other ->
- ?tr_error_msg("Internal log write failed: ~p ~p", [Other, LogName]),
- {error, Other}
- end.
-
-
-%%------------------------------------------------------------
-%% function : log_lazy
-%% Arguments: LogName - name of the disk_log. If 'dummy' is
-%% used nothing should be logged. Reason, reuse code.
-%% LogRecord - record to store in the log.
-%% Returns :
-%% Effect : Writes a logrecord. The record may be lost.
-%%------------------------------------------------------------
-
-log_lazy(dummy, _LogRecord) ->
- ok;
-log_lazy(LogName, LogRecord) ->
- case write_lazy(LogName, LogRecord) of
- ok ->
- ok;
- _ ->
- %% We have to catch the exit because in some cases
- %% it's not possible to abort action in the 2PC-protocol.
- case catch start(LogName) of
- ok ->
- write_lazy(LogName, LogRecord);
- {'EXIT', Reason} ->
- {error, Reason}
- end
- end.
-
-write_lazy(LogName, LogRecord) ->
- case catch disk_log:log(LogName, LogRecord) of
- ok ->
- %% wrote to kernel successfully
- ok;
- {error, Reason} ->
- %% Write to kernel failed with Reason
- ?tr_error_msg("Internal log write failed: ~p", [Reason]),
- {error, Reason};
- Other ->
- %% unknown message received.
- ?tr_error_msg("Internal log write failed: ~p", [Other]),
- {error, Other}
- end.
-
-
-%%------------------------------------------------------------
-%% function : get_next
-%% Arguments: LogName - name of the disk_log.
-%% Cursor - place to read from.
-%% Returns : {Cursor, LogRecs} - A cursor and up to N logrecords.
-%% eof - the atom 'eof', indicating logfile empty.
-%% {error, Reason} - error.
-%% Effect :
-%% Purpose : Used when performing a REDO scan
-%%------------------------------------------------------------
-
-get_next(LogName, Cursor) ->
- case catch disk_log:chunk(LogName, Cursor, 1) of
- {NewCursor, [Data]} ->
- {Data, NewCursor};
- eof ->
- eof;
- {error, Reason} ->
- ?tr_error_msg("Internal log '~p' read failed: ~p",
- [LogName, Reason]),
- exit({error, Reason});
- _Other ->
- ?tr_error_msg("Internal log '~p' read failed: 'log_corrupt'", [LogName]),
- exit({error, "log_corrupt"})
- end.
-
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/cosTransactions/test/Makefile b/lib/cosTransactions/test/Makefile
deleted file mode 100644
index 58199248d1..0000000000
--- a/lib/cosTransactions/test/Makefile
+++ /dev/null
@@ -1,151 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1999-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-#ifeq ($(TYPE),debug)
-#ERL_COMPILE_FLAGS += -Ddebug -W
-#endif
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(COSTRANSACTIONS_VSN)
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/cosTransactions_test
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-TEST_SPEC_FILE = cosTransactions.spec
-COVER_FILE = cosTransactions.cover
-
-
-IDL_FILES = \
- etrap_test.idl
-
-IDLOUTDIR = idl_output
-
-MODULES = \
- transactions_SUITE \
- etrap_test_server_impl \
- etrap_test_lib \
- generated_SUITE
-
-GEN_MODULES = \
- oe_etrap_test \
- etrap_test_server
-
-GEN_HRL_FILES = \
- oe_etrap_test.hrl \
- etrap_test_server.hrl
-
-ERL_FILES = $(MODULES:%=%.erl)
-
-HRL_FILES = \
- etrap_test_lib.hrl
-
-GEN_FILES = \
- $(GEN_HRL_FILES:%=$(IDLOUTDIR)/%) \
- $(GEN_MODULES:%=$(IDLOUTDIR)/%.erl)
-
-GEN_TARGET_FILES = $(GEN_MODULES:%=$(IDLOUTDIR)/%.$(EMULATOR))
-
-SUITE_TARGET_FILES = $(MODULES:%=%.$(EMULATOR))
-
-TARGET_FILES = \
- $(GEN_TARGET_FILES) \
- $(SUITE_TARGET_FILES)
-
-
-# ----------------------------------------------------
-# PROGRAMS
-# ----------------------------------------------------
-LOCAL_CLASSPATH = $(ERL_TOP)/lib/cosTransactions/priv:$(ERL_TOP)/lib/cosTransactions/test
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_IDL_FLAGS += -pa $(ERL_TOP)/lib/cosTransactions/ebin\
- -pa $(ERL_TOP)/lib/orber/ebin \
- -pa $(ERL_TOP)/lib/ic/ebin
-
-ERL_COMPILE_FLAGS += \
- $(ERL_IDL_FLAGS) \
- -pa $(ERL_TOP)/lib/orber/include \
- -pa $(ERL_TOP)/lib/cosTransactions/ebin \
- -pa $(ERL_TOP)/lib/cosTransactions/test/idl_output \
- -I$(ERL_TOP)/lib/orber/include \
- -I$(ERL_TOP)/lib/cosTransactions \
- -I$(ERL_TOP)/lib/cosTransactions/test/$(IDLOUTDIR)
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-
-tests debug opt: $(TARGET_FILES)
-
-clean:
- rm -f idl_output/*
- rm -f $(TARGET_FILES)
- rm -f errs core *~
-
-#debug:
-# @${MAKE} TYPE=debug
-
-docs:
-
-# ----------------------------------------------------
-# Special Targets
-# ----------------------------------------------------
-
-IDL-GENERATED: etrap_test.idl
- erlc $(ERL_IDL_FLAGS) -o$(IDLOUTDIR) \
- +'{cfgfile,"etrap_test.cfg"}' etrap_test.idl
- >IDL-GENERATED
-
-$(GEN_FILES): IDL-GENERATED
-
-$(TARGET_FILES): IDL-GENERATED
-
-# ----------------------------------------------------
-# Release Targets
-# ----------------------------------------------------
-# We don't copy generated intermediate erlang and hrl files
-
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec:
-
-release_docs_spec:
-
-release_tests_spec: tests
- $(INSTALL_DIR) "$(RELSYSDIR)"
- $(INSTALL_DATA) $(IDL_FILES) $(TEST_SPEC_FILE) \
- $(COVER_FILE) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)"
- $(INSTALL_DATA) $(SUITE_TARGET_FILES) "$(RELSYSDIR)"
- $(INSTALL_DIR) "$(RELSYSDIR)/$(IDLOUTDIR)"
- $(INSTALL_DATA) $(GEN_TARGET_FILES) $(GEN_FILES) \
- "$(RELSYSDIR)/$(IDLOUTDIR)"
-
diff --git a/lib/cosTransactions/test/cosTransactions.cover b/lib/cosTransactions/test/cosTransactions.cover
deleted file mode 100644
index b27bae999d..0000000000
--- a/lib/cosTransactions/test/cosTransactions.cover
+++ /dev/null
@@ -1,2 +0,0 @@
-{incl_app,cosTransactions,details}.
-
diff --git a/lib/cosTransactions/test/cosTransactions.spec b/lib/cosTransactions/test/cosTransactions.spec
deleted file mode 100644
index 9918c8ca16..0000000000
--- a/lib/cosTransactions/test/cosTransactions.spec
+++ /dev/null
@@ -1 +0,0 @@
-{suites,"../cosTransactions_test",all}.
diff --git a/lib/cosTransactions/test/etrap_test.cfg b/lib/cosTransactions/test/etrap_test.cfg
deleted file mode 100644
index a2bc7d3fb7..0000000000
--- a/lib/cosTransactions/test/etrap_test.cfg
+++ /dev/null
@@ -1,21 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-{this, "etrap_test::server"}.
-{{handle_info, "etrap_test::server"}, true}.
diff --git a/lib/cosTransactions/test/etrap_test.idl b/lib/cosTransactions/test/etrap_test.idl
deleted file mode 100644
index 7379115be7..0000000000
--- a/lib/cosTransactions/test/etrap_test.idl
+++ /dev/null
@@ -1,39 +0,0 @@
-//
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1999-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-//
-
-#ifndef _TEST_IDL
-#define _TEST_IDL
-#include <../src/CosTransactions.idl>
-module etrap_test {
-
- // interface server
- interface server :
- CosTransactions::Coordinator, CosTransactions::SubtransactionAwareResource,
- CosTransactions::RecoveryCoordinator, CosTransactions::Control {
- };
-// interface Server :
-// CosTransactions::Coordinator, CosTransactions::SubtransactionAwareResource,
-// CosTransactions::RecoveryCoordinator, CosTransactions::Control,
-// CosTransactions::Synchronization {
-// };
-
-}; // End of test Module
-
-#endif
diff --git a/lib/cosTransactions/test/etrap_test_lib.erl b/lib/cosTransactions/test/etrap_test_lib.erl
deleted file mode 100644
index e8d8c3a429..0000000000
--- a/lib/cosTransactions/test/etrap_test_lib.erl
+++ /dev/null
@@ -1,126 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(etrap_test_lib).
-
-%%--------------- INCLUDES ---------------------------------------------
--include("etrap_test_lib.hrl").
--include_lib("cosTransactions/src/ETraP_Common.hrl").
-
-%%--------------- EXPORTS ----------------------------------------------
--export([scratch_debug_fun/0,
- activate_debug_fun/5,
- update_debug_info/1,
- deactivate_debug_fun/3,
- eval_debug_fun/4,
- set_debug_context/4]).
-
-%%--------------- CONSTANTS/DEFINITIONS --------------------------------
--define(DEBUG_TAB, etrap_debug).
--record(debug_info, {id, function, type, file, line}).
-
-%%--------------- DEBUG FUNCTIONS --------------------------------------
-%% Managing conditional debug functions
-%%
-%% The main idea with the debug_fun's is to allow test programs
-%% to control the internal behaviour of CosTransactions.
-%%
-%% First should calls to ?eval_debug_fun be inserted at well
-%% defined places in CosTransaction's code. E.g. in critical situations
-%% of startup, transaction commit, backups etc.
-%%
-%% Then compile CosTransactions with the compiler option 'debug'.
-%%
-%% In test programs ?activate_debug_fun should be called
-%% in order to bind a fun to the debug identifier stated
-%% in the call to ?eval_debug_fun.
-
-scratch_debug_fun() ->
- catch ets:delete(?DEBUG_TAB),
- ets:new(?DEBUG_TAB,
- [set, public, named_table, {keypos, 2}]).
-
-activate_debug_fun(FunId, Fun, Type, File, Line) ->
- io:format("Activiating ~p RETRIES: ~p WAIT: ~p~n",
- [FunId, ?tr_max_retries, ?tr_comm_failure_wait]),
- Info = #debug_info{id = FunId,
- function = Fun,
- type = Type,
- file = File,
- line = Line},
- update_debug_info(Info).
-
-update_debug_info(Info) ->
- case catch ets:insert(?DEBUG_TAB, Info) of
- {'EXIT', _} ->
- scratch_debug_fun(),
- ets:insert(?DEBUG_TAB, Info);
- _ ->
- ok
- end,
- ok.
-
-deactivate_debug_fun(FunId, _File, _Line) ->
- catch ets:delete(?DEBUG_TAB, FunId),
- ok.
-
-eval_debug_fun(FunId, Env, File, Line) ->
- case catch ets:lookup(?DEBUG_TAB, FunId) of
- [] ->
- ok;
- [Info] ->
- Fun = Info#debug_info.function,
- case Info#debug_info.type of
- transient ->
- deactivate_debug_fun(FunId, File, Line);
- _->
- ok
- end,
- io:format("Running debug fun ~p:~p (LINE: ~p)~n", [File, FunId, Line]),
- Fun(Env);
- {'EXIT', _R} ->
- ok
- end.
-
-
-set_debug_context([], [], _, _)-> ok;
-set_debug_context([], _, _, _)->
- ets:delete(?DEBUG_TAB),
- exit("failed transactions_SUITE. Bad configuration.");
-set_debug_context(_, [], _, _)->
- ets:delete(?DEBUG_TAB),
- exit("failed transactions_SUITE Bad configuration.");
-set_debug_context([RHead|RTail], [CHead|CTail], File, Line)->
- write_context(RHead, CHead, File, Line),
- set_debug_context(RTail, CTail, File, Line).
-
-write_context(_Resource, [], _, _)-> ok;
-write_context(Resource, [{Func, Fun, Type}|PTail], File, Line)->
- etrap_test_lib:activate_debug_fun({Resource, Func},
- Fun, Type,
- File, Line),
- write_context(Resource, PTail, File, Line);
-write_context(_,_, _, _) ->
- ets:delete(?DEBUG_TAB),
- exit("failed transactions_SUITE. Bad configuration.").
-
-
-%%--------------- END OF MODULE ----------------------------------------
diff --git a/lib/cosTransactions/test/etrap_test_lib.hrl b/lib/cosTransactions/test/etrap_test_lib.hrl
deleted file mode 100644
index 6fe61a4d45..0000000000
--- a/lib/cosTransactions/test/etrap_test_lib.hrl
+++ /dev/null
@@ -1,101 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--ifndef(ETRAP_TEST_LIB_HRL).
--define(ETRAP_TEST_LIB_HRL, true).
-
--define(match(ExpectedRes, Expr, Msg),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- io:format("~n------ CORRECT RESULT ------~n~p~n~p~n",
- [AcTuAlReS, Msg]),
- ok;
- _ ->
- io:format("~n###### ERROR ERROR ######~n~p~n~p~n",
- [AcTuAlReS, Msg]),
- exit(AcTuAlReS)
- end
- end()).
-
--define(match_inverse(NotExpectedRes, Expr, Msg),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- NotExpectedRes ->
- io:format("~n###### ERROR ERROR ######~n ~p~n~p~n",
- [AcTuAlReS, Msg]),
- exit(AcTuAlReS);
- _ ->
- io:format("~n------ CORRECT RESULT ------~n~p~n~p~n",
- [AcTuAlReS, Msg]),
- ok
- end
- end()).
-
-
--define(crash_and_recover, fun(_Env)-> exit(crash_and_burn) end).
-
--define(crash_no_recovery, fun(Env)-> throw({stop,normal,{Env,state}}) end).
-
--define(delay(Time), fun(_Id) -> timer:sleep(Time*1000) end).
-
--define(TIMEOUT, 4).
--define(SUP_TEST(Env, Name),
- ['etrap_test_server', Env,
- [{sup_child, true}, {persistent, true},
- {regname, {global, Name}}]]).
-
--define(no_context, [[],[],[], []]).
--define(nop, []).
--define(delay_transient(Tag, Ti),
- [{Tag, ?delay(Ti), transient}]).
--define(crash_transient(Tag),
- [{Tag, ?crash_and_recover, transient}]).
--define(crash_permanent(Tag),
- [{Tag, ?crash_no_recovery, permanent}]).
-
-%%-----------------------------------------------------------
-%% Definition of 'Resource' action.
-%% function action reply
-%%-----------------------------------------------------------
-%% raise #'CosTransactions_HeuristicMixed' {}
--define(rollback_mix, [{rollback, exc, ?tr_mixed}]).
--define(commit_mix, [{commit, exc, ?tr_mixed}]).
--define(prepare_mix, [{prepare, exc, ?tr_mixed}]).
-%% raise #'CosTransactions_HeuristicRollback' {}
--define(rollback_rb, [{rollback, exc, ?tr_rollback}]).
--define(commit_rb, [{commit, exc, ?tr_rollback}]).
-%% raise #'CosTransactions_HeuristicCommit' {}
--define(rollback_cm, [{rollback, exc, ?tr_commit}]).
--define(commit_cm, [{commit, exc, ?tr_commit}]).
-%% delay reply
--define(rollback_delay, [{rollback, delay, ?TIMEOUT*2}]).
--define(commit_delay, [{commit, delay, ?TIMEOUT*2}]).
--define(prepare_delay, [{prepare, delay, ?TIMEOUT*2}]).
-%% other reply than default
--define(prepare_commit, [{prepare, reply, 'VoteCommit'}]).
--define(prepare_rollback, [{prepare, stop_reply, 'VoteRollback'}]).
-
--endif.
-
-%%-------------- EOF ---------------------------------------------------
diff --git a/lib/cosTransactions/test/etrap_test_server_impl.erl b/lib/cosTransactions/test/etrap_test_server_impl.erl
deleted file mode 100644
index 8a244b42c7..0000000000
--- a/lib/cosTransactions/test/etrap_test_server_impl.erl
+++ /dev/null
@@ -1,211 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(etrap_test_server_impl).
-
-%%--------------- INCLUDES -----------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
-%% Local
--include_lib("cosTransactions/src/ETraP_Common.hrl").
--include_lib("cosTransactions/include/CosTransactions.hrl").
-%%--------------- IMPORTS-------------------------------------
-%%--------------- EXPORTS-------------------------------------
--export([prepare/2,
- rollback/2,
- commit/2,
- commit_one_phase/2,
- forget/2,
-% before_completion/2,
-% after_completion/3,
- commit_subtransaction/3,
- rollback_subtransaction/2]).
-
-
-%%--------------- gen_server specific ------------------------
--export([init/1, terminate/2]).
--export([handle_call/3, handle_cast/2, handle_info/2, code_change/3]).
-
-%%------------------------------------------------------------
-%% function : init, terminate
-%%------------------------------------------------------------
-init(State) ->
- process_flag(trap_exit,true),
- io:format("etrap_test_server:init ~p~n", [State]),
- ?debug_print("STARTING etrap_test_server( ~p )~n", [State]),
- {ok, State}.
-
-terminate(Reason, _State) ->
- io:format("etrap_test_server:terminate ~p~n", [Reason]),
- ?debug_print("STOPREASON etrap_test_server( ~p )~n", [Reason]),
- ok.
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-handle_call(_,_, State) ->
- {noreply, State}.
-handle_cast(_, State) ->
- {noreply, State}.
-handle_info(_Info, State) ->
- {noreply, State}.
-
-%%-- Inherit from CosTransactions::SubtransactionAwareResource --
-prepare(_Self, State) ->
- case ?is_debug_compiled of
- true ->
- io:format("etrap_test_server:prepare ~p~n", [State]);
- _->
- ok
- end,
-% ?debug_print("etrap_test_server:prepare ~p~n", [State]),
- action(prepare, State, {reply, 'VoteCommit', State}).
-
-rollback(_Self, State) ->
- case ?is_debug_compiled of
- true ->
- io:format("etrap_test_server:rollback ~p~n", [State]);
- _->
- ok
- end,
-% ?debug_print("etrap_test_server:rollback ~p~n", [State]),
- case sync_test(State) of
- true ->
- action(rollback, State, {reply, ok, State});
- _->
- action(rollback, State, {stop, normal, ok, State})
- end.
-
-commit(_Self, State) ->
- case ?is_debug_compiled of
- true ->
- io:format("etrap_test_server:commit ~p~n", [State]);
- _->
- ok
- end,
-% ?debug_print("etrap_test_server:commit ~p~n", [State]),
- case sync_test(State) of
- true ->
- action(commit, State, {reply, ok, State});
- _->
- action(commit, State, {stop, normal, ok, State})
- end.
-
-commit_one_phase(_Self, State) ->
- case ?is_debug_compiled of
- true ->
- io:format("etrap_test_server:commit_one_phase ~p~n", [State]);
- _->
- ok
- end,
-% ?debug_print("etrap_test_server:commit_one_phase ~p~n", [State]),
- case sync_test(State) of
- true ->
- {reply, ok, State};
- _->
- {stop, normal, ok, State}
- end.
-
-forget(_Self, State) ->
- case ?is_debug_compiled of
- true ->
- io:format("etrap_test_server:forget ~p~n", [State]);
- _->
- ok
- end,
-% ?debug_print("etrap_test_server:forget ~p~n", [State]),
- case sync_test(State) of
- true ->
- {reply, ok, State};
- _->
- {stop, normal, ok, State}
- end.
-
-commit_subtransaction(_Self, State, Parent) ->
- case ?is_debug_compiled of
- true ->
- io:format("etrap_test_server:commit_subtransaction( ~p )~n", [Parent]);
- _->
- ok
- end,
-% ?debug_print("etrap_test_server:commit_subtransaction( ~p )~n", [Parent]),
- {reply, ok, State}.
-rollback_subtransaction(_Self, State) ->
- case ?is_debug_compiled of
- true ->
- io:format("etrap_test_server:rollback_subtransaction()~n", []);
- _->
- ok
- end,
-% ?debug_print("etrap_test_server:rollback_subtransaction()~n", []),
- {reply, ok, State}.
-
-%before_completion(_Self, State) ->
-% case ?is_debug_compiled of
-% true ->
-% io:format("etrap_test_server:before_completion()~n", []);
-% _->
-% ok
-% end,
-%% ?debug_print("etrap_test_server:before_completion()~n", []),
-% {reply, ok, State}.
-%after_completion(_Self, State, Status) ->
-% case ?is_debug_compiled of
-% true ->
-% io:format("etrap_test_server:after_completion( ~p )~n", [Status]);
-% _->
-% ok
-% end,
-%% ?debug_print("etrap_test_server:after_completion( ~p )~n", [Status]),
-% {stop, normal, ok, State}.
-
-%%--------------- LOCAL FUNCTIONS ----------------------------
-action(Key, State, Default) ->
- case catch lists:keysearch(Key, 1, State) of
- {value,{Key, stop_reply, R}} ->
- case sync_test(State) of
- true ->
- {reply, R, State};
- _->
- {stop, normal, R, State}
- end;
- {value,{Key, reply, R}} ->
- {reply, R, State};
- {value,{Key, exc, E}} ->
- corba:raise(E);
- {value,{Key, delay, Time}} ->
- timer:sleep(Time*1000),
- Default;
- {value,{Key,Value}} ->
- Value;
- _ ->
- Default
- end.
-
-sync_test(State) ->
- case catch lists:keysearch(sync, 1, State) of
- {value,{sync, true}} ->
- true;
- _ ->
- false
- end.
-
-
-%%--------------- END OF MODULE ------------------------------
-
diff --git a/lib/cosTransactions/test/generated_SUITE.erl b/lib/cosTransactions/test/generated_SUITE.erl
deleted file mode 100644
index 52b850b189..0000000000
--- a/lib/cosTransactions/test/generated_SUITE.erl
+++ /dev/null
@@ -1,543 +0,0 @@
-%%-----------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File : generated_SUITE.erl
-%% Purpose :
-%% Created : 27 Jan 2004
-%%-----------------------------------------------------------------
-
--module(generated_SUITE).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/include/corba.hrl").
-
--define(default_timeout, test_server:minutes(3)).
-
--define(match(ExpectedRes, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
--define(nomatch(Not, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- Not ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS);
- _ ->
- AcTuAlReS
- end
- end()).
-
-
--define(checktc(_Op),
- fun(TC) ->
- case orber_tc:check_tc(TC) of
- false ->
- io:format("###### ERROR ERROR ######~n~p - ~p~n", [Op, TC]),
- exit(TC);
- true ->
- true
- end
- end).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--compile(export_all).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- ['CosTransactions_Control',
- 'CosTransactions_Coordinator',
- 'CosTransactions_HeuristicCommit',
- 'CosTransactions_HeuristicHazard',
- 'CosTransactions_HeuristicMixed',
- 'CosTransactions_HeuristicRollback',
- 'CosTransactions_Inactive',
- 'CosTransactions_InvalidControl',
- 'CosTransactions_NoTransaction',
- 'CosTransactions_NotPrepared',
- 'CosTransactions_NotSubtransaction',
- 'CosTransactions_RecoveryCoordinator',
- 'CosTransactions_Resource',
- 'CosTransactions_SubtransactionAwareResource',
- 'CosTransactions_SubtransactionsUnavailable',
- 'CosTransactions_Terminator',
- 'CosTransactions_TransactionFactory',
- 'CosTransactions_Unavailable',
- 'CosTransactions_SynchronizationUnavailable',
- 'CosTransactions_TransIdentity',
- 'CosTransactions_PropagationContext',
- 'CosTransactions_otid_t',
- 'CosTransactions_WrongTransaction', 'ETraP_Server'].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-init_per_testcase(_Case, Config) ->
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-end_per_testcase(_Case, Config) ->
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTransactions_HeuristicCommit'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTransactions_HeuristicCommit'(_) ->
- ?match(true, orber_tc:check_tc('CosTransactions_HeuristicCommit':tc())),
- ?match("IDL:omg.org/CosTransactions/HeuristicCommit:1.0",
- 'CosTransactions_HeuristicCommit':id()),
- ?match("CosTransactions_HeuristicCommit",
- 'CosTransactions_HeuristicCommit':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTransactions_HeuristicHazard'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTransactions_HeuristicHazard'(_) ->
- ?match(true, orber_tc:check_tc('CosTransactions_HeuristicHazard':tc())),
- ?match("IDL:omg.org/CosTransactions/HeuristicHazard:1.0",
- 'CosTransactions_HeuristicHazard':id()),
- ?match("CosTransactions_HeuristicHazard",
- 'CosTransactions_HeuristicHazard':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTransactions_HeuristicMixed'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTransactions_HeuristicMixed'(_) ->
- ?match(true, orber_tc:check_tc('CosTransactions_HeuristicMixed':tc())),
- ?match("IDL:omg.org/CosTransactions/HeuristicMixed:1.0",
- 'CosTransactions_HeuristicMixed':id()),
- ?match("CosTransactions_HeuristicMixed",
- 'CosTransactions_HeuristicMixed':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTransactions_HeuristicRollback'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTransactions_HeuristicRollback'(_) ->
- ?match(true, orber_tc:check_tc('CosTransactions_HeuristicRollback':tc())),
- ?match("IDL:omg.org/CosTransactions/HeuristicRollback:1.0",
- 'CosTransactions_HeuristicRollback':id()),
- ?match("CosTransactions_HeuristicRollback",
- 'CosTransactions_HeuristicRollback':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTransactions_Inactive'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTransactions_Inactive'(_) ->
- ?match(true, orber_tc:check_tc('CosTransactions_Inactive':tc())),
- ?match("IDL:omg.org/CosTransactions/Inactive:1.0",
- 'CosTransactions_Inactive':id()),
- ?match("CosTransactions_Inactive",
- 'CosTransactions_Inactive':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTransactions_InvalidControl'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTransactions_InvalidControl'(_) ->
- ?match(true, orber_tc:check_tc('CosTransactions_InvalidControl':tc())),
- ?match("IDL:omg.org/CosTransactions/InvalidControl:1.0",
- 'CosTransactions_InvalidControl':id()),
- ?match("CosTransactions_InvalidControl",
- 'CosTransactions_InvalidControl':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTransactions_NoTransaction'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTransactions_NoTransaction'(_) ->
- ?match(true, orber_tc:check_tc('CosTransactions_NoTransaction':tc())),
- ?match("IDL:omg.org/CosTransactions/NoTransaction:1.0",
- 'CosTransactions_NoTransaction':id()),
- ?match("CosTransactions_NoTransaction",
- 'CosTransactions_NoTransaction':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTransactions_NotPrepared'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTransactions_NotPrepared'(_) ->
- ?match(true, orber_tc:check_tc('CosTransactions_NotPrepared':tc())),
- ?match("IDL:omg.org/CosTransactions/NotPrepared:1.0",
- 'CosTransactions_NotPrepared':id()),
- ?match("CosTransactions_NotPrepared",
- 'CosTransactions_NotPrepared':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTransactions_NotSubtransaction'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTransactions_NotSubtransaction'(_) ->
- ?match(true, orber_tc:check_tc('CosTransactions_NotSubtransaction':tc())),
- ?match("IDL:omg.org/CosTransactions/NotSubtransaction:1.0",
- 'CosTransactions_NotSubtransaction':id()),
- ?match("CosTransactions_NotSubtransaction",
- 'CosTransactions_NotSubtransaction':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTransactions_SubtransactionsUnavailable'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTransactions_SubtransactionsUnavailable'(_) ->
- ?match(true, orber_tc:check_tc('CosTransactions_SubtransactionsUnavailable':tc())),
- ?match("IDL:omg.org/CosTransactions/SubtransactionsUnavailable:1.0",
- 'CosTransactions_SubtransactionsUnavailable':id()),
- ?match("CosTransactions_SubtransactionsUnavailable",
- 'CosTransactions_SubtransactionsUnavailable':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTransactions_Unavailable'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTransactions_Unavailable'(_) ->
- ?match(true, orber_tc:check_tc('CosTransactions_Unavailable':tc())),
- ?match("IDL:omg.org/CosTransactions/Unavailable:1.0",
- 'CosTransactions_Unavailable':id()),
- ?match("CosTransactions_Unavailable",
- 'CosTransactions_Unavailable':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTransactions_SynchronizationUnavailable'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTransactions_SynchronizationUnavailable'(_) ->
- ?match(true, orber_tc:check_tc('CosTransactions_SynchronizationUnavailable':tc())),
- ?match("IDL:omg.org/CosTransactions/SynchronizationUnavailable:1.0",
- 'CosTransactions_SynchronizationUnavailable':id()),
- ?match("CosTransactions_SynchronizationUnavailable",
- 'CosTransactions_SynchronizationUnavailable':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTransactions_TransIdentity'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTransactions_TransIdentity'(_) ->
- ?match(true, orber_tc:check_tc('CosTransactions_TransIdentity':tc())),
- ?match("IDL:omg.org/CosTransactions/TransIdentity:1.0",
- 'CosTransactions_TransIdentity':id()),
- ?match("CosTransactions_TransIdentity",
- 'CosTransactions_TransIdentity':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTransactions_PropagationContext'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTransactions_PropagationContext'(_) ->
- ?match(true, orber_tc:check_tc('CosTransactions_PropagationContext':tc())),
- ?match("IDL:omg.org/CosTransactions/PropagationContext:1.0",
- 'CosTransactions_PropagationContext':id()),
- ?match("CosTransactions_PropagationContext",
- 'CosTransactions_PropagationContext':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTransactions_otid_t'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTransactions_otid_t'(_) ->
- ?match(true, orber_tc:check_tc('CosTransactions_otid_t':tc())),
- ?match("IDL:omg.org/CosTransactions/otid_t:1.0",
- 'CosTransactions_otid_t':id()),
- ?match("CosTransactions_otid_t",
- 'CosTransactions_otid_t':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTransactions_WrongTransaction'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTransactions_WrongTransaction'(_) ->
- ?match(true, orber_tc:check_tc('CosTransactions_WrongTransaction':tc())),
- ?match("IDL:omg.org/CosTransactions/WrongTransaction:1.0",
- 'CosTransactions_WrongTransaction':id()),
- ?match("CosTransactions_WrongTransaction",
- 'CosTransactions_WrongTransaction':name()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTransactions_Control'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTransactions_Control'(_) ->
- ?nomatch(undefined, 'CosTransactions_Control':oe_tc(get_terminator)),
- ?nomatch(undefined, 'CosTransactions_Control':oe_tc(get_coordinator)),
- ?match(undefined, 'CosTransactions_Control':oe_tc(undefined)),
- ?match([_|_], 'CosTransactions_Control':oe_get_interface()),
- ?match("IDL:omg.org/CosTransactions/Control:1.0",
- 'CosTransactions_Control':typeID()),
- check_tc('CosTransactions_Control':oe_get_interface()),
- ?match(true, 'CosTransactions_Control':oe_is_a('CosTransactions_Control':typeID())),
- ?match(false, 'CosTransactions_Control':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTransactions_Coordinator'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTransactions_Coordinator'(_) ->
- ?nomatch(undefined, 'CosTransactions_Coordinator':oe_tc(get_status)),
- ?nomatch(undefined, 'CosTransactions_Coordinator':oe_tc(get_parent_status)),
- ?nomatch(undefined, 'CosTransactions_Coordinator':oe_tc(get_top_level_status)),
- ?nomatch(undefined, 'CosTransactions_Coordinator':oe_tc(is_same_transaction)),
- ?nomatch(undefined, 'CosTransactions_Coordinator':oe_tc(is_related_transaction)),
- ?nomatch(undefined, 'CosTransactions_Coordinator':oe_tc(is_ancestor_transaction)),
- ?nomatch(undefined, 'CosTransactions_Coordinator':oe_tc(is_descendant_transaction)),
- ?nomatch(undefined, 'CosTransactions_Coordinator':oe_tc(is_top_level_transaction)),
- ?nomatch(undefined, 'CosTransactions_Coordinator':oe_tc(hash_transaction)),
- ?nomatch(undefined, 'CosTransactions_Coordinator':oe_tc(hash_top_level_tran)),
- ?nomatch(undefined, 'CosTransactions_Coordinator':oe_tc(register_resource)),
- ?nomatch(undefined, 'CosTransactions_Coordinator':oe_tc(register_subtran_aware)),
- ?nomatch(undefined, 'CosTransactions_Coordinator':oe_tc(rollback_only)),
- ?nomatch(undefined, 'CosTransactions_Coordinator':oe_tc(get_transaction_name)),
- ?nomatch(undefined, 'CosTransactions_Coordinator':oe_tc(create_subtransaction)),
- ?nomatch(undefined, 'CosTransactions_Coordinator':oe_tc(get_txcontext)),
- ?match(undefined, 'CosTransactions_Coordinator':oe_tc(undefined)),
- ?match([_|_], 'CosTransactions_Coordinator':oe_get_interface()),
- ?match("IDL:omg.org/CosTransactions/Coordinator:1.0",
- 'CosTransactions_Coordinator':typeID()),
- check_tc('CosTransactions_Coordinator':oe_get_interface()),
- ?match(true, 'CosTransactions_Coordinator':oe_is_a('CosTransactions_Coordinator':typeID())),
- ?match(false, 'CosTransactions_Coordinator':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTransactions_RecoveryCoordinator'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTransactions_RecoveryCoordinator'(_) ->
- ?nomatch(undefined, 'CosTransactions_RecoveryCoordinator':oe_tc(replay_completion)),
- ?match(undefined, 'CosTransactions_RecoveryCoordinator':oe_tc(undefined)),
- ?match([_|_], 'CosTransactions_RecoveryCoordinator':oe_get_interface()),
- ?match("IDL:omg.org/CosTransactions/RecoveryCoordinator:1.0",
- 'CosTransactions_RecoveryCoordinator':typeID()),
- check_tc('CosTransactions_RecoveryCoordinator':oe_get_interface()),
- ?match(true, 'CosTransactions_RecoveryCoordinator':oe_is_a('CosTransactions_RecoveryCoordinator':typeID())),
- ?match(false, 'CosTransactions_RecoveryCoordinator':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTransactions_Resource'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTransactions_Resource'(_) ->
- ?nomatch(undefined, 'CosTransactions_Resource':oe_tc(prepare)),
- ?nomatch(undefined, 'CosTransactions_Resource':oe_tc(rollback)),
- ?nomatch(undefined, 'CosTransactions_Resource':oe_tc(commit)),
- ?nomatch(undefined, 'CosTransactions_Resource':oe_tc(commit_one_phase)),
- ?nomatch(undefined, 'CosTransactions_Resource':oe_tc(forget)),
- ?match(undefined, 'CosTransactions_Resource':oe_tc(undefined)),
- ?match([_|_], 'CosTransactions_Resource':oe_get_interface()),
- ?match("IDL:omg.org/CosTransactions/Resource:1.0",
- 'CosTransactions_Resource':typeID()),
- check_tc('CosTransactions_Resource':oe_get_interface()),
- ?match(true, 'CosTransactions_Resource':oe_is_a('CosTransactions_Resource':typeID())),
- ?match(false, 'CosTransactions_Resource':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTransactions_SubtransactionAwareResource'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTransactions_SubtransactionAwareResource'(_) ->
- ?nomatch(undefined, 'CosTransactions_SubtransactionAwareResource':oe_tc(commit_subtransaction)),
- ?nomatch(undefined, 'CosTransactions_SubtransactionAwareResource':oe_tc(rollback_subtransaction)),
- ?nomatch(undefined, 'CosTransactions_SubtransactionAwareResource':oe_tc(prepare)),
- ?nomatch(undefined, 'CosTransactions_SubtransactionAwareResource':oe_tc(rollback)),
- ?nomatch(undefined, 'CosTransactions_SubtransactionAwareResource':oe_tc(commit)),
- ?nomatch(undefined, 'CosTransactions_SubtransactionAwareResource':oe_tc(commit_one_phase)),
- ?nomatch(undefined, 'CosTransactions_SubtransactionAwareResource':oe_tc(forget)),
- ?match(undefined, 'CosTransactions_SubtransactionAwareResource':oe_tc(undefined)),
- ?match([_|_], 'CosTransactions_SubtransactionAwareResource':oe_get_interface()),
- ?match("IDL:omg.org/CosTransactions/SubtransactionAwareResource:1.0",
- 'CosTransactions_SubtransactionAwareResource':typeID()),
- check_tc('CosTransactions_SubtransactionAwareResource':oe_get_interface()),
- ?match(true, 'CosTransactions_SubtransactionAwareResource':oe_is_a('CosTransactions_SubtransactionAwareResource':typeID())),
- ?match(true, 'CosTransactions_SubtransactionAwareResource':oe_is_a('CosTransactions_Resource':typeID())),
- ?match(false, 'CosTransactions_SubtransactionAwareResource':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTransactions_Terminator'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTransactions_Terminator'(_) ->
- ?nomatch(undefined, 'CosTransactions_Terminator':oe_tc(commit)),
- ?nomatch(undefined, 'CosTransactions_Terminator':oe_tc(rollback)),
- ?match(undefined, 'CosTransactions_Terminator':oe_tc(undefined)),
- ?match([_|_], 'CosTransactions_Terminator':oe_get_interface()),
- ?match("IDL:omg.org/CosTransactions/Terminator:1.0",
- 'CosTransactions_Terminator':typeID()),
- check_tc('CosTransactions_Terminator':oe_get_interface()),
- ?match(true, 'CosTransactions_Terminator':oe_is_a('CosTransactions_Terminator':typeID())),
- ?match(false, 'CosTransactions_Terminator':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosTransactions_TransactionFactory'
-%% Description:
-%%-----------------------------------------------------------------
-'CosTransactions_TransactionFactory'(_) ->
- ?nomatch(undefined, 'CosTransactions_TransactionFactory':oe_tc(create)),
- ?nomatch(undefined, 'CosTransactions_TransactionFactory':oe_tc(recreate)),
- ?match(undefined, 'CosTransactions_TransactionFactory':oe_tc(undefined)),
- ?match([_|_], 'CosTransactions_TransactionFactory':oe_get_interface()),
- ?match("IDL:omg.org/CosTransactions/TransactionFactory:1.0",
- 'CosTransactions_TransactionFactory':typeID()),
- check_tc('CosTransactions_TransactionFactory':oe_get_interface()),
- ?match(true, 'CosTransactions_TransactionFactory':oe_is_a('CosTransactions_TransactionFactory':typeID())),
- ?match(false, 'CosTransactions_TransactionFactory':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'ETraP_Server'
-%% Description:
-%%-----------------------------------------------------------------
-'ETraP_Server'(_) ->
- ?nomatch(undefined, 'ETraP_Server':oe_tc(get_status)),
- ?nomatch(undefined, 'ETraP_Server':oe_tc(get_parent_status)),
- ?nomatch(undefined, 'ETraP_Server':oe_tc(get_top_level_status)),
- ?nomatch(undefined, 'ETraP_Server':oe_tc(is_same_transaction)),
- ?nomatch(undefined, 'ETraP_Server':oe_tc(is_related_transaction)),
- ?nomatch(undefined, 'ETraP_Server':oe_tc(is_ancestor_transaction)),
- ?nomatch(undefined, 'ETraP_Server':oe_tc(is_descendant_transaction)),
- ?nomatch(undefined, 'ETraP_Server':oe_tc(is_top_level_transaction)),
- ?nomatch(undefined, 'ETraP_Server':oe_tc(hash_transaction)),
- ?nomatch(undefined, 'ETraP_Server':oe_tc(hash_top_level_tran)),
- ?nomatch(undefined, 'ETraP_Server':oe_tc(register_resource)),
- ?nomatch(undefined, 'ETraP_Server':oe_tc(register_subtran_aware)),
- ?nomatch(undefined, 'ETraP_Server':oe_tc(rollback_only)),
- ?nomatch(undefined, 'ETraP_Server':oe_tc(get_transaction_name)),
- ?nomatch(undefined, 'ETraP_Server':oe_tc(create_subtransaction)),
- ?nomatch(undefined, 'ETraP_Server':oe_tc(get_txcontext)),
- ?nomatch(undefined, 'ETraP_Server':oe_tc(prepare)),
- ?nomatch(undefined, 'ETraP_Server':oe_tc(rollback)),
- ?nomatch(undefined, 'ETraP_Server':oe_tc(commit)),
- ?nomatch(undefined, 'ETraP_Server':oe_tc(commit_one_phase)),
- ?nomatch(undefined, 'ETraP_Server':oe_tc(forget)),
- ?nomatch(undefined, 'ETraP_Server':oe_tc(replay_completion)),
- ?nomatch(undefined, 'ETraP_Server':oe_tc(get_terminator)),
- ?nomatch(undefined, 'ETraP_Server':oe_tc(get_coordinator)),
- ?match(undefined, 'ETraP_Server':oe_tc(undefined)),
- ?match([_|_], 'ETraP_Server':oe_get_interface()),
- ?match("IDL:omg.org/ETraP/Server:1.0",
- 'ETraP_Server':typeID()),
- check_tc('ETraP_Server':oe_get_interface()),
- ?match(true, 'ETraP_Server':oe_is_a('ETraP_Server':typeID())),
- ?match(true, 'ETraP_Server':oe_is_a('CosTransactions_Coordinator':typeID())),
- ?match(true, 'ETraP_Server':oe_is_a('CosTransactions_Resource':typeID())),
- ?match(true, 'ETraP_Server':oe_is_a('CosTransactions_RecoveryCoordinator':typeID())),
- ?match(true, 'ETraP_Server':oe_is_a('CosTransactions_Control':typeID())),
- ?match(false, 'ETraP_Server':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% MISC functions
-%%-----------------------------------------------------------------
-check_tc([]) ->
- ok;
-check_tc([{Op, {RetType, InParameters, OutParameters}}|T]) ->
- io:format("checked - ~s~n", [Op]),
- lists:all(?checktc(Op), [RetType|InParameters]),
- lists:all(?checktc(Op), OutParameters),
- check_tc(T).
-
-
diff --git a/lib/cosTransactions/test/transactions_SUITE.erl b/lib/cosTransactions/test/transactions_SUITE.erl
deleted file mode 100644
index 00753a4e6e..0000000000
--- a/lib/cosTransactions/test/transactions_SUITE.erl
+++ /dev/null
@@ -1,396 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(transactions_SUITE).
-
-%%--------------- INCLUDES -----------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
-
-%% Local
--include_lib("cosTransactions/src/ETraP_Common.hrl").
--include_lib("cosTransactions/include/CosTransactions.hrl").
--include("etrap_test_lib.hrl").
-
--include_lib("common_test/include/ct.hrl").
-
--define(default_timeout, test_server:minutes(20)).
-
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2, cases/0,
- init_per_suite/1, end_per_suite/1, resource_api/1, etrap_api/1,
- init_per_testcase/2, end_per_testcase/2, app_test/1]).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- cases().
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-cases() ->
- [etrap_api, resource_api, app_test].
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-init_per_testcase(_Case, Config) ->
- Path = code:which(?MODULE),
- code:add_pathz(filename:join(filename:dirname(Path), "idl_output")),
- 'oe_CosTransactions':'oe_register'(),
- 'oe_etrap_test':'oe_register'(),
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- 'oe_etrap_test':'oe_unregister'(),
- 'oe_CosTransactions':'oe_unregister'(),
- Path = code:which(?MODULE),
- code:del_path(filename:join(filename:dirname(Path), "idl_output")),
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-init_per_suite(Config) ->
- mnesia:delete_schema([node()]),
- mnesia:create_schema([node()]),
- orber:install([node()]),
- application:start(mnesia),
- application:start(orber),
- if
- is_list(Config) ->
- Config;
- true ->
- exit("Config not a list")
- end.
-
-end_per_suite(Config) ->
- application:stop(orber),
- application:stop(mnesia),
- mnesia:delete_schema([node()]),
- Config.
-
-%%-----------------------------------------------------------------
-%% Tests app file
-%%-----------------------------------------------------------------
-app_test(_Config) ->
- ok=test_server:app_test(cosTransactions),
- ok.
-
-%%-----------------------------------------------------------------
-%% API tests
-%%-----------------------------------------------------------------
-etrap_api(_Config) ->
- ?match(ok, application:start(cosTransactions),
- "Starting the cosTransactions application"),
- TrFac = cosTransactions:start_factory(),
- %% Start a new transaction:
- %% RootCoord
- %% / \
- %% SubCoord1 SubCoord2
- Control = 'CosTransactions_TransactionFactory':create(TrFac, 0),
- Term = 'CosTransactions_Control':get_terminator(Control),
- Coord = 'CosTransactions_Control':get_coordinator(Control),
- SubCont1 = 'CosTransactions_Coordinator':create_subtransaction(Coord),
- SubCont2 = 'CosTransactions_Coordinator':create_subtransaction(Coord),
- SubCoord1 = 'CosTransactions_Control':get_coordinator(SubCont1),
- SubCoord2 = 'CosTransactions_Control':get_coordinator(SubCont2),
-
-
- %%------ Test CosTransactions::Coordinator ------
- ?match(true,
- 'CosTransactions_Coordinator':is_same_transaction(Coord, Coord),
- "'CosTransactions_Coordinator':is_same_transaction"),
- ?match(false,
- 'CosTransactions_Coordinator':is_same_transaction(Coord, SubCoord1),
- "'CosTransactions_Coordinator':is_same_transaction"),
- ?match(true,
- 'CosTransactions_Coordinator':is_descendant_transaction(Coord, Coord),
- "'CosTransactions_Coordinator':is_descendant_transaction"),
- ?match(false,
- 'CosTransactions_Coordinator':is_descendant_transaction(Coord, SubCoord1),
- "'CosTransactions_Coordinator':is_descendant_transaction"),
- ?match(true,
- 'CosTransactions_Coordinator':is_descendant_transaction(SubCoord1, Coord),
- "'CosTransactions_Coordinator':is_descendant_transaction"),
- ?match(false,
- 'CosTransactions_Coordinator':is_descendant_transaction(SubCoord1, SubCoord2),
- "'CosTransactions_Coordinator':is_descendant_transaction"),
- ?match(true,
- 'CosTransactions_Coordinator':is_top_level_transaction(Coord),
- "'CosTransactions_Coordinator':is_top_level_transaction"),
- ?match(false,
- 'CosTransactions_Coordinator':is_top_level_transaction(SubCoord2),
- "'CosTransactions_Coordinator':is_top_level_transaction"),
-
- RootHash = 'CosTransactions_Coordinator':hash_transaction(Coord),
- RepeatHash= 'CosTransactions_Coordinator':hash_transaction(Coord),
- RootHash2 = 'CosTransactions_Coordinator':hash_top_level_tran(SubCoord1),
- RootHash3 = 'CosTransactions_Coordinator':hash_top_level_tran(Coord),
- _SubHash = 'CosTransactions_Coordinator':hash_transaction(SubCoord2),
- ?match(RootHash, RepeatHash,
- "'CosTransactions_Coordinator':hash_transaction"),
- ?match(RootHash, RootHash2,
- "'CosTransactions_Coordinator':hash_top_level_tran"),
- ?match(RootHash, RootHash3,
- "'CosTransactions_Coordinator':hash_top_level_tran"),
-% ?match_inverse(RootHash, SubHash,
-% "'CosTransactions_Coordinator':hash_transaction"),
-
- ?match('StatusActive',
- 'CosTransactions_Coordinator':get_status(Coord),
- "'CosTransactions_Coordinator':get_status"),
- ?match('StatusActive',
- 'CosTransactions_Coordinator':get_status(SubCoord1),
- "'CosTransactions_Coordinator':get_status"),
- ?match('StatusActive',
- 'CosTransactions_Coordinator':get_parent_status(Coord),
- "'CosTransactions_Coordinator':get_parent_status"),
- ?match('StatusActive',
- 'CosTransactions_Coordinator':get_parent_status(SubCoord1),
- "'CosTransactions_Coordinator':get_parent_status"),
- ?match('StatusActive',
- 'CosTransactions_Coordinator':get_top_level_status(Coord),
- "'CosTransactions_Coordinator':get_top_level_status"),
- ?match('StatusActive',
- 'CosTransactions_Coordinator':get_top_level_status(SubCoord1),
- "'CosTransactions_Coordinator':get_top_level_status"),
-
- %% Create a CosTransactions::Resource to experiments with.
- %% Start a new transaction:
- %% RootCoord
- %% / \
- %% SubCoord1 SubCoord2
- %% /
- %% Resource
- N1 = 'ETraP_Common':create_name("test"),
- O1 = etrap_test_server:oe_create(?nop, {global, N1}),
- _RC1 = 'CosTransactions_Coordinator':register_resource(SubCoord1, O1),
-% 'CosTransactions_Coordinator':register_synchronization(SubCoord1, O1),
-
- ?match('VoteCommit',
- 'CosTransactions_Resource':prepare(SubCoord1),
- "'CosTransactions_Coordinator':prepare"),
- %% The Transaction are no longer in 'StatusActive' state. No new
- %% "members" allowed.
- ?match('StatusPrepared',
- 'CosTransactions_Coordinator':get_status(SubCoord1),
- "'CosTransactions_Coordinator':get_status"),
-% ?match({'EXCEPTION', ?tr_inactive},
-% 'CosTransactions_Coordinator':register_synchronization(SubCoord1, O1),
-% "'CosTransactions_Coordinator':register_synchronization"),
- ?match({'EXCEPTION', ?tr_inactive},
- 'CosTransactions_Coordinator':register_resource(SubCoord1, O1),
- "'CosTransactions_Coordinator':register_resource"),
- ?match({'EXCEPTION', ?tr_inactive},
- 'CosTransactions_Coordinator':create_subtransaction(SubCoord1),
- "'CosTransactions_Coordinator':create_subtransaction"),
-
- catch corba:dispose(SubCoord1),
- catch corba:dispose(SubCoord2),
- catch corba:dispose(SubCont1),
- catch corba:dispose(SubCont2),
- catch corba:dispose(Term),
- catch corba:dispose(Control),
- catch corba:dispose(Coord),
- catch corba:dispose(O1),
-
- cosTransactions:stop_factory(TrFac),
- application:stop(cosTransactions),
- ok.
-
-%%-----------------------------------------------------------------
-%% API tests
-%%-----------------------------------------------------------------
-resource_api(_Config) ->
- ?match(ok, application:start(cosTransactions),
- "Starting the cosTransactions application"),
- TrFac = cosTransactions:start_factory([{typecheck, true}]),
-
- ?match({'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
- run(TrFac, 0, {?nop, ?nop, ?nop, ?prepare_rollback}),
- "TESTCASE #1: Prepare rollback Resource 4"),
- ?match({'EXCEPTION', ?tr_mixed},
- run(TrFac, 0, {?nop, ?nop, ?commit_mix, ?nop}),
- "TESTCASE #2: Heuristic Mixed exception Resource 3"),
- ?match(ok,
- run(TrFac, 0, {?nop, ?nop, ?nop, ?nop}),
- "TESTCASE #3: Normal completion. No errors."),
- ?match(ok,
- run(TrFac, 0, {?nop, ?nop, ?nop, ?commit_cm}),
- "TESTCASE #4: Heuristic Commit Exception Resource 4"),
- ?match({'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
- run(TrFac, 0, {?nop, ?rollback_rb, ?nop, ?prepare_rollback}),
- "TESTCASE #5: Heuristic Rollbac Resource 2, Resource 4 reply 'VoteRollback'"),
- ?match({'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
- run(TrFac, 0, {?nop, ?nop, ?prepare_rollback, ?rollback_rb}),
- "TESTCASE #6: Heuristic Rollbac Resource 4, Resource 3 reply 'VoteRollback'"),
- ?match(ok,
- run(TrFac, 0, {?nop, ?nop, ?commit_delay, ?nop}),
- "TESTCASE #7: Resource 3 delay during commit. No timeout."),
- ?match(ok,
- run(TrFac, 0, {?nop, ?nop, ?prepare_delay, ?nop}),
- "TESTCASE #8: Resource 3 delay during prepare. No timeout."),
- ?match(ok,
- run(TrFac, ?TIMEOUT, {?nop, ?commit_delay, ?nop, ?nop}),
- "TESTCASE #9: Resource 3 delay during commit. Timeout."),
- ?match({'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
- run(TrFac, ?TIMEOUT, {?nop, ?prepare_delay, ?nop, ?nop}),
- "TESTCASE #10: Resource 3 delay during prepare. Timeout."),
- case ?is_debug_compiled of
- true ->
- %% Testing the Coordinators (root and sub).
- ?match(ok,
- run(TrFac, 0, {?nop, ?nop, ?nop, ?nop, [?nop, ?nop,?crash_transient(commit), ?nop]}),
- "TESTCASE #11: SubCoord 3 crash transient during commit."),
- ?match({'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{}},
- run(TrFac, 0, {?nop, ?nop, ?nop, ?nop, [?nop, ?nop,?crash_transient(send_prepare), ?nop]}),
- "TESTCASE #12: SubCoord 3 crash transient during send prepare."),
- ?match({'EXCEPTION', ?tr_hazard},
- run(TrFac, 0, {?nop, ?nop, ?nop, ?nop, [?nop, ?nop,?crash_permanent(commit), ?nop]}),
- "TESTCASE #13: SubCoord 3 crash permanent during commit."),
- ?match({'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{}},
- run(TrFac, 0, {?nop, ?nop, ?nop, ?nop, [?nop, ?nop,?crash_permanent(send_prepare), ?nop]}),
- "TESTCASE #14: SubCoord 3 crash permanent during prepare."),
- ?match({'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{}},
- run(TrFac, 0, {?nop, ?nop, ?nop, ?nop, [?nop, ?crash_transient(send_prepare), ?crash_transient(commit), ?nop]}),
- "TESTCASE #15: SubCoord 2 crash transient during prepare. SubCoord 3 crash transient during commit"),
- ?match({'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
- run(TrFac, 0, {?nop, ?nop, ?nop, ?nop, [?crash_transient(send_prepare), ?nop, ?nop, ?nop]}),
- "TESTCASE #16: RootCoord crash transient during send prepare."),
- ?match({'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{}},
- run(TrFac, 0, {?nop, ?nop, ?nop, ?nop, [?nop, ?crash_transient(prepare1), ?nop, ?nop]}),
- "TESTCASE #17: SubCoord 1 crash transient during prepare1."),
- ?match({'EXCEPTION', ?tr_mixed},
- run(TrFac, 0, {?nop, ?prepare_mix, ?nop, ?nop, [?nop, ?nop, ?crash_transient(prepare2), ?nop]}),
- "TESTCASE #18: SubCoord 3 crash transient during prepare2. Resource 2 raise Heuristic Mixed during prepare"),
- ?match({'EXCEPTION', ?tr_mixed},
- run(TrFac, 0, {?nop, ?commit_mix, ?nop, ?nop, [?nop, ?nop, ?crash_transient(commit2), ?nop]}),
- "TESTCASE #19: Resource 2 raise Heurist mixed during commit. SubCoord crash transient commit2"),
- ?match({'EXCEPTION', ?tr_mixed},
- run(TrFac, 0, {?nop, ?rollback_cm, ?nop, ?prepare_rollback, [?nop, ?crash_transient(rollback2), ?nop, ?nop]}),
- "TESTCASE #20: Resource 2 raise Heuristic Commit during rollback. Resource 4 'VoteRollback'. SubCoord 2 crash transient rollback2."),
- ?match({'EXCEPTION', ?tr_mixed},
- run(TrFac, 0, {?nop, ?nop, ?nop, ?commit_mix, [?nop, ?nop, ?crash_transient(send_forget1), ?nop]}),
- "TESTCASE #21: Resource 4 raise Heuristic Mixed during commit. SubCoord 2 crash transient send_forget1."),
- ?match({'EXCEPTION', ?tr_mixed},
- run(TrFac, 0, {?nop, ?nop, ?nop, ?commit_mix, [?crash_transient(send_forget1), ?nop, ?nop, ?nop]}),
- "TESTCASE #22: Resource 4 raise Heuristic Mixed during commit. Root Coord crash transient send_forget1."),
- ?match({'EXCEPTION', ?tr_mixed},
- run(TrFac, 0, {?nop, ?nop, ?nop, ?commit_mix, [?crash_transient(send_forget3), ?nop, ?crash_transient(send_forget1), ?nop]}),
- "TESTCASE #23: Resource 4 raise Heuristic Mixed during commit. Root Coord crash transient send_forget3. SubCoord 3 crash transient send_forget1."),
- ?match({'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
- run(TrFac, ?TIMEOUT, {?nop, ?nop, ?nop, ?nop, [?delay_transient(root_delay, ?TIMEOUT*2), ?nop, ?nop, ?nop]}),
- "TESTCASE #24: Delay RootCoord. Timeout."),
- %% Testing the Terminator.
- ?match({'EXCEPTION', ?tr_mixed},
- run(TrFac, ?TIMEOUT, {?nop, ?prepare_mix, ?nop, ?nop, [?nop, ?nop, ?nop, ?crash_transient(commit_heuristic1)]}),
- "TESTCASE #25: Terminator crash transient after received and logged Heuristic mix."),
- ?match(ok,
- run(TrFac, ?TIMEOUT, {?nop, ?nop, ?nop, ?nop, [?nop, ?nop, ?nop, ?crash_transient(commit_ok2)]}),
- "TESTCASE #26: Terminator crash transient after received and logged 'ok'.");
- _ ->
- ok
- end,
-
- cosTransactions:stop_factory(TrFac),
- application:stop(cosTransactions),
- ok.
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-
-run(TrFac, Time, Spec) ->
- Control = 'CosTransactions_TransactionFactory':create(TrFac, Time),
- Term = 'CosTransactions_Control':get_terminator(Control),
- Coord = 'CosTransactions_Control':get_coordinator(Control),
- SubCont1 = 'CosTransactions_Coordinator':create_subtransaction(Coord),
- SubCont2 = 'CosTransactions_Coordinator':create_subtransaction(Coord),
- SubCoord1 = 'CosTransactions_Control':get_coordinator(SubCont1),
- SubCoord2 = 'CosTransactions_Control':get_coordinator(SubCont2),
- %% Start resources/participants.
- {O1, O2, O3, O4, Ctx} = start_resources(Spec),
-
- %% Get generated names to use for debugging.
- CoordN = 'CosTransactions_Coordinator':get_transaction_name(Coord),
- SubC1N = 'CosTransactions_Coordinator':get_transaction_name(SubCoord1),
- SubC2N = 'CosTransactions_Coordinator':get_transaction_name(SubCoord2),
-
- ?set_debug_context([CoordN, SubC1N, SubC2N, Term], Ctx),
-
- %% Register the resources as participants.
- _RC1 = 'CosTransactions_Coordinator':register_resource(SubCoord1, O1),
- _RC2 = 'CosTransactions_Coordinator':register_resource(SubCoord1, O2),
- _RC3 = 'CosTransactions_Coordinator':register_resource(SubCoord2, O3),
- _RC4 = 'CosTransactions_Coordinator':register_resource(SubCoord2, O4),
-
- 'CosTransactions_Coordinator':register_subtran_aware(SubCoord1, O4),
-% 'CosTransactions_Coordinator':register_synchronization(SubCoord1, O2),
-
-% Reply = (catch 'CosTransactions_Terminator':commit(Term, true)),
- Reply = (catch 'ETraP_Common':send_stubborn('CosTransactions_Terminator',
- commit, [Term, true],
- ?tr_max_retries,
- ?tr_comm_failure_wait)),
-
- catch corba:dispose(SubCoord1),
- catch corba:dispose(SubCoord2),
- catch corba:dispose(SubCont1),
- catch corba:dispose(SubCont2),
- catch corba:dispose(Term),
- catch corba:dispose(Control),
- catch corba:dispose(Coord),
- catch corba:dispose(O1),
- catch corba:dispose(O2),
- catch corba:dispose(O3),
- catch corba:dispose(O4),
- Reply.
-
-start_resources({A1, A2, A3, A4})->
- start_resources({A1, A2, A3, A4, ?no_context});
-start_resources({A1, A2, A3, A4, Ctx})->
- N1 = 'ETraP_Common':create_name("test"),
- N2 = 'ETraP_Common':create_name("test"),
- N3 = 'ETraP_Common':create_name("test"),
- N4 = 'ETraP_Common':create_name("test"),
- {_,_,O1} = supervisor:start_child(?SUPERVISOR_NAME, ?SUP_TEST(A1, N1)),
- {_,_,O2} = supervisor:start_child(?SUPERVISOR_NAME, ?SUP_TEST(A2, N2)),
-% {_,_,O2} = supervisor:start_child(?SUPERVISOR_NAME, ?SUP_TEST([{sync,true}|A2], N2)),
- {_,_,O3} = supervisor:start_child(?SUPERVISOR_NAME, ?SUP_TEST(A3, N3)),
- {_,_,O4} = supervisor:start_child(?SUPERVISOR_NAME, ?SUP_TEST(A4, N4)),
- {O1, O2, O3, O4, Ctx}.
diff --git a/lib/cosTransactions/vsn.mk b/lib/cosTransactions/vsn.mk
deleted file mode 100644
index bba2058231..0000000000
--- a/lib/cosTransactions/vsn.mk
+++ /dev/null
@@ -1 +0,0 @@
-COSTRANSACTIONS_VSN = 1.3.3
diff --git a/lib/crypto/c_src/Makefile.in b/lib/crypto/c_src/Makefile.in
index 31124ba477..b6a65d7488 100644
--- a/lib/crypto/c_src/Makefile.in
+++ b/lib/crypto/c_src/Makefile.in
@@ -19,7 +19,6 @@
#
include $(ERL_TOP)/make/target.mk
include $(ERL_TOP)/make/$(TARGET)/otp.mk
-include $(ERL_TOP)/make/$(TARGET)/otp_ded.mk
# ----------------------------------------------------
# Application version
@@ -31,23 +30,20 @@ VSN=$(CRYPTO_VSN)
# The following variables differ between systems.
# Set by configure.
# ----------------------------------------------------
-CC = $(DED_CC)
-LD = $(DED_LD)
+CC = @DED_CC@
+LD = @DED_LD@
SHELL = /bin/sh
-LIBS = $(DED_LIBS)
-LDFLAGS += $(DED_LDFLAGS)
-CFLAGS = $(DED_CFLAGS)
+LIBS = @DED_LIBS@
+LDFLAGS += @DED_LDFLAGS@
+CFLAGS = @DED_CFLAGS@ @SSL_FLAGS@
# From erts/configure
SSL_LIBDIR = @SSL_LIBDIR@
SSL_INCLUDE = @SSL_INCLUDE@
SSL_CRYPTO_LIBNAME = @SSL_CRYPTO_LIBNAME@
SSL_SSL_LIBNAME = @SSL_SSL_LIBNAME@
-SSL_FLAGS = @SSL_FLAGS@
-
-INCLUDES = $(SSL_INCLUDE) $(DED_INCLUDES)
-CFLAGS += $(SSL_FLAGS)
+INCLUDES = $(SSL_INCLUDE) @DED_INCLUDE@
ifeq ($(TYPE),debug)
TYPEMARKER = .debug
@@ -70,7 +66,38 @@ RELSYSDIR = $(RELEASE_PATH)/lib/crypto-$(VSN)
# ----------------------------------------------------
# Misc Macros
# ----------------------------------------------------
-CRYPTO_OBJS = $(OBJDIR)/crypto$(TYPEMARKER).o
+
+PRIVDIR = ../priv
+OBJDIR = $(PRIVDIR)/obj/$(TARGET)
+LIBDIR = $(PRIVDIR)/lib/$(TARGET)
+
+CRYPTO_OBJS = $(OBJDIR)/crypto$(TYPEMARKER).o \
+ $(OBJDIR)/aead$(TYPEMARKER).o \
+ $(OBJDIR)/aes$(TYPEMARKER).o \
+ $(OBJDIR)/algorithms$(TYPEMARKER).o \
+ $(OBJDIR)/api_ng$(TYPEMARKER).o \
+ $(OBJDIR)/atoms$(TYPEMARKER).o \
+ $(OBJDIR)/bn$(TYPEMARKER).o \
+ $(OBJDIR)/cipher$(TYPEMARKER).o \
+ $(OBJDIR)/cmac$(TYPEMARKER).o \
+ $(OBJDIR)/dh$(TYPEMARKER).o \
+ $(OBJDIR)/digest$(TYPEMARKER).o \
+ $(OBJDIR)/dss$(TYPEMARKER).o \
+ $(OBJDIR)/ec$(TYPEMARKER).o \
+ $(OBJDIR)/ecdh$(TYPEMARKER).o \
+ $(OBJDIR)/eddsa$(TYPEMARKER).o \
+ $(OBJDIR)/engine$(TYPEMARKER).o \
+ $(OBJDIR)/evp$(TYPEMARKER).o \
+ $(OBJDIR)/fips$(TYPEMARKER).o \
+ $(OBJDIR)/hash$(TYPEMARKER).o \
+ $(OBJDIR)/hmac$(TYPEMARKER).o \
+ $(OBJDIR)/info$(TYPEMARKER).o \
+ $(OBJDIR)/math$(TYPEMARKER).o \
+ $(OBJDIR)/pkey$(TYPEMARKER).o \
+ $(OBJDIR)/poly1305$(TYPEMARKER).o \
+ $(OBJDIR)/rand$(TYPEMARKER).o \
+ $(OBJDIR)/rsa$(TYPEMARKER).o \
+ $(OBJDIR)/srp$(TYPEMARKER).o
CALLBACK_OBJS = $(OBJDIR)/crypto_callback$(TYPEMARKER).o
NIF_MAKEFILE = $(PRIVDIR)/Makefile
CRYPTO_STATIC_OBJS = $(OBJDIR)/crypto_static$(TYPEMARKER).o\
@@ -80,19 +107,10 @@ NIF_ARCHIVE = $(LIBDIR)/crypto$(TYPEMARKER).a
TEST_ENGINE_OBJS = $(OBJDIR)/otp_test_engine$(TYPEMARKER).o
-ifeq ($(findstring win32,$(TARGET)), win32)
-NIF_LIB = $(LIBDIR)/crypto$(TYPEMARKER).dll
-CALLBACK_LIB = $(LIBDIR)/crypto_callback$(TYPEMARKER).dll
-TEST_ENGINE_LIB = $(LIBDIR)/otp_test_engine$(TYPEMARKER).dll
-else
-NIF_LIB = $(LIBDIR)/crypto$(TYPEMARKER).so
-CALLBACK_LIB = $(LIBDIR)/crypto_callback$(TYPEMARKER).so
-TEST_ENGINE_LIB = $(LIBDIR)/otp_test_engine$(TYPEMARKER).so
-endif
+NIF_LIB = $(LIBDIR)/crypto$(TYPEMARKER).@DED_EXT@
+CALLBACK_LIB = $(LIBDIR)/crypto_callback$(TYPEMARKER).@DED_EXT@
+TEST_ENGINE_LIB = $(LIBDIR)/otp_test_engine$(TYPEMARKER).@DED_EXT@
-ifeq ($(HOST_OS),)
-HOST_OS := $(shell $(ERL_TOP)/erts/autoconf/config.guess)
-endif
DYNAMIC_CRYPTO_LIB=@SSL_DYNAMIC_ONLY@
ifeq ($(DYNAMIC_CRYPTO_LIB),yes)
@@ -125,7 +143,7 @@ RANLIB=true
endif
ALL_CFLAGS = $(TYPE_FLAGS) $(EXTRA_FLAGS) $(INCLUDES)
-ALL_STATIC_CFLAGS = $(DED_STATIC_CFLAGS) $(INCLUDES)
+ALL_STATIC_CFLAGS = @DED_STATIC_CFLAGS@ $(INCLUDES)
# ----------------------------------------------------
# Targets
@@ -180,32 +198,21 @@ $(LIBDIR)/crypto_callback$(TYPEMARKER).dll: $(CALLBACK_OBJS)
endif
-clean:
-ifeq ($(findstring win32,$(TARGET)), win32)
- rm -f $(LIBDIR)/crypto.dll
- rm -f $(LIBDIR)/crypto.debug.dll
- rm -f $(LIBDIR)/crypto_callback.dll
- rm -f $(LIBDIR)/crypto_callback.debug.dll
- rm -f $(LIBDIR)/otp_test_engine.dll
-else
- rm -f $(LIBDIR)/crypto.so
- rm -f $(LIBDIR)/crypto.debug.so
- rm -f $(LIBDIR)/crypto.valgrind.so
- rm -f $(LIBDIR)/crypto_callback.so
- rm -f $(LIBDIR)/crypto_callback.debug.so
- rm -f $(LIBDIR)/crypto_callback.valgrind.so
- rm -f $(LIBDIR)/otp_test_engine.so
-endif
- rm -f $(OBJDIR)/crypto.o
- rm -f $(OBJDIR)/crypto_static.o
- rm -f $(OBJDIR)/crypto.debug.o
- rm -f $(OBJDIR)/crypto_static.debug.o
- rm -f $(OBJDIR)/crypto.valgrind.o
- rm -f $(OBJDIR)/crypto_static.valgrind.o
- rm -f $(OBJDIR)/crypto_callback.o
- rm -f $(OBJDIR)/crypto_callback.debug.o
- rm -f $(OBJDIR)/crypto_callback.valgrind.o
- rm -f $(OBJDIR)/otp_test_engine.o
+CLEAN_OBJS_RAW = $(CRYPTO_OBJS) $(CALLBACK_OBJS) $(CRYPTO_STATIC_OBJS) $(TEST_ENGINE_OBJS)
+CLEAN_OBJS_O = $(patsubst %.debug.o,%.o,$(CLEAN_OBJS_RAW:.valgrind.o=.o))
+
+CLEAN_LIBS_RAW = $(NIF_LIB) $(CALLBACK_LIB) $(TEST_ENGINE_LIB)
+CLEAN_LIBS_SO = $(patsubst %.debug.@DED_EXT@,%.@DED_EXT@,$(CLEAN_LIBS_RAW:.valgrind.@DED_EXT@=.@DED_EXT@))
+
+clean_dynamic_libs:
+ rm -f $(CLEAN_LIBS_SO)
+ rm -f $(foreach T,.valgrind.@DED_EXT@ .debug.@DED_EXT@,$(CLEAN_LIBS_SO:.@DED_EXT@=$T))
+
+clean_objs:
+ rm -f $(CLEAN_OBJS_O)
+ rm -f $(foreach T,.valgrind.o .debug.o,$(CLEAN_OBJS_O:.o=$T))
+
+clean: clean_objs clean_dynamic_libs
rm -f core *~
docs:
diff --git a/lib/crypto/c_src/aead.c b/lib/crypto/c_src/aead.c
new file mode 100644
index 0000000000..ab0e609130
--- /dev/null
+++ b/lib/crypto/c_src/aead.c
@@ -0,0 +1,182 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "aead.h"
+#include "aes.h"
+#include "cipher.h"
+
+
+
+ERL_NIF_TERM aead_cipher(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/*
+ (Type,Key,Iv,AAD,In,TagLen,true)
+ (Type,Key,Iv,AAD,In,Tag,false)
+ */
+#if defined(HAVE_AEAD)
+ const struct cipher_type_t *cipherp;
+ EVP_CIPHER_CTX *ctx = NULL;
+ const EVP_CIPHER *cipher = NULL;
+ ErlNifBinary key, iv, aad, in, tag;
+ unsigned int tag_len;
+ unsigned char *outp, *tagp, *tag_data;
+ ERL_NIF_TERM type, out, out_tag, ret, encflg_arg;
+ int len, encflg;
+
+ encflg_arg = argv[6];
+
+ /* Fetch the flag telling if we are going to encrypt (=true) or decrypt (=false) */
+ if (encflg_arg == atom_true)
+ encflg = 1;
+ else if (encflg_arg == atom_false)
+ encflg = 0;
+ else if (encflg_arg == atom_undefined)
+ /* For compat funcs in crypto.erl */
+ encflg = -1;
+ else
+ {
+ ret = EXCP_BADARG(env, "Bad enc flag");
+ goto done;
+ }
+
+ type = argv[0];
+
+ if (!enif_is_atom(env, type))
+ {ret = EXCP_BADARG(env, "non-atom cipher type"); goto done;}
+ if (!enif_inspect_iolist_as_binary(env, argv[1], &key))
+ {ret = EXCP_BADARG(env, "non-binary key"); goto done;}
+ if (!enif_inspect_iolist_as_binary(env, argv[2], &iv))
+ {ret = EXCP_BADARG(env, "non-binary iv"); goto done;}
+ if (!enif_inspect_iolist_as_binary(env, argv[3], &in))
+ {ret = EXCP_BADARG(env, "non-binary text"); goto done;}
+ if (!enif_inspect_iolist_as_binary(env, argv[4], &aad))
+ {ret = EXCP_BADARG(env, "non-binary AAD"); goto done;}
+
+ if (encflg) {
+ if (!enif_get_uint(env, argv[5], &tag_len))
+ {ret = EXCP_BADARG(env, "Bad Tag length"); goto done;}
+ tag_data = NULL;
+ } else {
+ if (!enif_inspect_iolist_as_binary(env, argv[5], &tag))
+ {ret = EXCP_BADARG(env, "non-binary Tag"); goto done;}
+ tag_len = tag.size;
+ tag_data = tag.data;
+ }
+
+ if (tag_len > INT_MAX
+ || key.size > INT_MAX
+ || iv.size > INT_MAX
+ || in.size > INT_MAX
+ || aad.size > INT_MAX)
+ {ret = EXCP_BADARG(env, "binary too long"); goto done;}
+
+ if ((cipherp = get_cipher_type(type, key.size)) == NULL)
+ {ret = EXCP_BADARG(env, "Unknown cipher"); goto done;}
+ if (cipherp->flags & NON_EVP_CIPHER)
+ {ret = EXCP_BADARG(env, "Bad cipher"); goto done;}
+ if (! (cipherp->flags & AEAD_CIPHER) )
+ {ret = EXCP_BADARG(env, "Not aead cipher"); goto done;}
+ if ((cipher = cipherp->cipher.p) == NULL)
+ {ret = EXCP_NOTSUP(env, "Cipher not supported in this libcrypto version"); goto done;}
+
+#if defined(HAVE_GCM_EVP_DECRYPT_BUG)
+ if ( !encflg && (cipherp->flags & GCM_MODE))
+ return aes_gcm_decrypt_NO_EVP(env, argc, argv);
+#endif
+
+ if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
+ {ret = EXCP_ERROR(env, "Can't allocate ctx"); goto done;}
+
+ if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, encflg) != 1)
+ {ret = EXCP_ERROR(env, "CipherInit failed"); goto done;}
+ if (EVP_CIPHER_CTX_ctrl(ctx, cipherp->extra.aead.ctx_ctrl_set_ivlen, (int)iv.size, NULL) != 1)
+ {ret = EXCP_BADARG(env, "Bad IV length"); goto done;}
+
+#if defined(HAVE_CCM)
+ if (cipherp->flags & CCM_MODE) {
+ if (EVP_CIPHER_CTX_ctrl(ctx, cipherp->extra.aead.ctx_ctrl_set_tag, (int)tag_len, tag_data) != 1)
+ {ret = EXCP_BADARG(env, "Can't set tag"); goto done;}
+ if (EVP_CipherInit_ex(ctx, NULL, NULL, key.data, iv.data, -1) != 1)
+ {ret = EXCP_BADARG(env, "Can't set key or iv"); goto done;}
+ if (EVP_CipherUpdate(ctx, NULL, &len, NULL, (int)in.size) != 1)
+ {ret = EXCP_BADARG(env, "Can't set text size"); goto done;}
+ } else
+#endif
+ {
+ if (EVP_CipherInit_ex(ctx, NULL, NULL, key.data, iv.data, -1) != 1)
+ {ret = EXCP_BADARG(env, "Can't set key or iv"); goto done;}
+ }
+
+ if (EVP_CipherUpdate(ctx, NULL, &len, aad.data, (int)aad.size) != 1)
+ {ret = EXCP_BADARG(env, "Can't set AAD"); goto done;}
+
+ if ((outp = enif_make_new_binary(env, in.size, &out)) == NULL)
+ {ret = EXCP_ERROR(env, "Can't make 'Out' binary"); goto done;}
+
+ if (EVP_CipherUpdate(ctx, outp, &len, in.data, (int)in.size) != 1)
+ {
+ if (encflg)
+ ret = EXCP_BADARG(env, "Can't set in-text");
+ else
+ /* Decrypt error */
+ ret = atom_error;
+ goto done;
+ }
+
+ if (encflg)
+ {
+ if (EVP_CipherFinal_ex(ctx, outp/*+len*/, &len) != 1)
+ {ret = EXCP_ERROR(env, "Encrypt error"); goto done;}
+
+ if ((tagp = enif_make_new_binary(env, tag_len, &out_tag)) == NULL)
+ {ret = EXCP_ERROR(env, "Can't make 'Out' binary"); goto done;}
+
+ if (EVP_CIPHER_CTX_ctrl(ctx, cipherp->extra.aead.ctx_ctrl_get_tag, (int)tag_len, tagp) != 1)
+ {ret = EXCP_ERROR(env, "Can't get Tag"); goto done;}
+
+ ret = enif_make_tuple2(env, out, out_tag);
+ }
+ else
+ {
+#if defined(HAVE_GCM)
+ if (cipherp->flags & GCM_MODE) {
+ if (EVP_CIPHER_CTX_ctrl(ctx, cipherp->extra.aead.ctx_ctrl_set_tag, (int)tag_len, tag.data) != 1)
+ /* Decrypt error */
+ {ret = atom_error; goto done;}
+ if (EVP_DecryptFinal_ex(ctx, outp+len, &len) != 1)
+ /* Decrypt error */
+ {ret = atom_error; goto done;}
+ }
+#endif
+ ret = out;
+ }
+
+ CONSUME_REDS(env, in);
+
+done:
+ if (ctx)
+ EVP_CIPHER_CTX_free(ctx);
+ return ret;
+
+#else
+ return EXCP_NOTSUP(env, "Unsupported Cipher");
+#endif
+}
+
+
diff --git a/lib/crypto/c_src/aead.h b/lib/crypto/c_src/aead.h
new file mode 100644
index 0000000000..2ec7a8a930
--- /dev/null
+++ b/lib/crypto/c_src/aead.h
@@ -0,0 +1,28 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_AEAD_H__
+#define E_AEAD_H__ 1
+
+#include "common.h"
+
+ERL_NIF_TERM aead_cipher(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+#endif /* E_AEAD_H__ */
diff --git a/lib/crypto/c_src/aes.c b/lib/crypto/c_src/aes.c
new file mode 100644
index 0000000000..4b01e629f9
--- /dev/null
+++ b/lib/crypto/c_src/aes.c
@@ -0,0 +1,302 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "aes.h"
+#include "cipher.h"
+
+ERL_NIF_TERM aes_cfb_8_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key, IVec, Data, IsEncrypt) */
+ ErlNifBinary key, ivec, text;
+ AES_KEY aes_key;
+ unsigned char ivec_clone[16]; /* writable copy */
+ int new_ivlen = 0;
+ ERL_NIF_TERM ret;
+ unsigned char *outp;
+
+ CHECK_NO_FIPS_MODE();
+
+ ASSERT(argc == 4);
+
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &key))
+ goto bad_arg;
+ if (key.size != 16 && key.size != 24 && key.size != 32)
+ goto bad_arg;
+ if (!enif_inspect_binary(env, argv[1], &ivec))
+ goto bad_arg;
+ if (ivec.size != 16)
+ goto bad_arg;
+ if (!enif_inspect_iolist_as_binary(env, argv[2], &text))
+ goto bad_arg;
+
+ memcpy(ivec_clone, ivec.data, 16);
+
+ /* NOTE: This function returns 0 on success unlike most OpenSSL functions */
+ if (AES_set_encrypt_key(key.data, (int)key.size * 8, &aes_key) != 0)
+ goto err;
+ if ((outp = enif_make_new_binary(env, text.size, &ret)) == NULL)
+ goto err;
+ AES_cfb8_encrypt((unsigned char *) text.data,
+ outp,
+ text.size, &aes_key, ivec_clone, &new_ivlen,
+ (argv[3] == atom_true));
+ CONSUME_REDS(env,text);
+ return ret;
+
+ bad_arg:
+ err:
+ return enif_make_badarg(env);
+}
+
+ERL_NIF_TERM aes_cfb_128_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key, IVec, Data, IsEncrypt) */
+ ErlNifBinary key, ivec, text;
+ AES_KEY aes_key;
+ unsigned char ivec_clone[16]; /* writable copy */
+ int new_ivlen = 0;
+ ERL_NIF_TERM ret;
+ unsigned char *outp;
+
+ ASSERT(argc == 4);
+
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &key))
+ goto bad_arg;
+ if (key.size != 16 && key.size != 24 && key.size != 32)
+ goto bad_arg;
+ if (!enif_inspect_binary(env, argv[1], &ivec))
+ goto bad_arg;
+ if (ivec.size != 16)
+ goto bad_arg;
+ if (!enif_inspect_iolist_as_binary(env, argv[2], &text))
+ goto bad_arg;
+
+ memcpy(ivec_clone, ivec.data, 16);
+
+ /* NOTE: This function returns 0 on success unlike most OpenSSL functions */
+ if (AES_set_encrypt_key(key.data, (int)key.size * 8, &aes_key) != 0)
+ goto err;
+
+ if ((outp = enif_make_new_binary(env, text.size, &ret)) == NULL)
+ goto err;
+ AES_cfb128_encrypt((unsigned char *) text.data,
+ outp,
+ text.size, &aes_key, ivec_clone, &new_ivlen,
+ (argv[3] == atom_true));
+ CONSUME_REDS(env,text);
+ return ret;
+
+ bad_arg:
+ err:
+ return enif_make_badarg(env);
+}
+
+ERL_NIF_TERM aes_ige_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key, IVec, Data, IsEncrypt) */
+#ifdef HAVE_AES_IGE
+ ErlNifBinary key_bin, ivec_bin, data_bin;
+ AES_KEY aes_key;
+ unsigned char ivec[32];
+ int type;
+ unsigned char* ret_ptr;
+ ERL_NIF_TERM ret;
+
+ CHECK_NO_FIPS_MODE();
+
+ ASSERT(argc == 4);
+
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin))
+ goto bad_arg;
+ if (key_bin.size != 16 && key_bin.size != 32)
+ goto bad_arg;
+ if (!enif_inspect_binary(env, argv[1], &ivec_bin))
+ goto bad_arg;
+ if (ivec_bin.size != 32)
+ goto bad_arg;
+ if (!enif_inspect_iolist_as_binary(env, argv[2], &data_bin))
+ goto bad_arg;
+ if (data_bin.size % 16 != 0)
+ goto bad_arg;
+
+ if (argv[3] == atom_true) {
+ type = AES_ENCRYPT;
+ /* NOTE: This function returns 0 on success unlike most OpenSSL functions */
+ if (AES_set_encrypt_key(key_bin.data, (int)key_bin.size * 8, &aes_key) != 0)
+ goto err;
+ }
+ else {
+ type = AES_DECRYPT;
+ /* NOTE: This function returns 0 on success unlike most OpenSSL functions */
+ if (AES_set_decrypt_key(key_bin.data, (int)key_bin.size * 8, &aes_key) != 0)
+ goto err;
+ }
+
+ if ((ret_ptr = enif_make_new_binary(env, data_bin.size, &ret)) == NULL)
+ goto err;
+
+ memcpy(ivec, ivec_bin.data, 32); /* writable copy */
+
+ AES_ige_encrypt(data_bin.data, ret_ptr, data_bin.size, &aes_key, ivec, type);
+
+ CONSUME_REDS(env,data_bin);
+ return ret;
+
+ bad_arg:
+ err:
+ return enif_make_badarg(env);
+
+#else
+ return atom_notsup;
+#endif
+}
+
+
+#if !defined(HAVE_EVP_AES_CTR)
+ERL_NIF_TERM aes_ctr_stream_encrypt_compat(ErlNifEnv* env, const ERL_NIF_TERM state_arg, const ERL_NIF_TERM data_arg)
+{/* ({Key, IVec, ECount, Num}, Data) */
+ ErlNifBinary key_bin, ivec_bin, text_bin, ecount_bin;
+ AES_KEY aes_key;
+ unsigned int num;
+ ERL_NIF_TERM ret, num2_term, cipher_term, ivec2_term, ecount2_term, new_state_term;
+ int state_arity;
+ const ERL_NIF_TERM *state_term;
+ unsigned char * ivec2_buf;
+ unsigned char * ecount2_buf;
+ unsigned char *outp;
+
+ if (!enif_get_tuple(env, state_arg, &state_arity, &state_term))
+ goto bad_arg;
+ if (state_arity != 4)
+ goto bad_arg;
+ if (!enif_inspect_iolist_as_binary(env, state_term[0], &key_bin))
+ goto bad_arg;
+ if (key_bin.size > INT_MAX / 8)
+ goto bad_arg;
+ if (!enif_inspect_binary(env, state_term[1], &ivec_bin))
+ goto bad_arg;
+ if (ivec_bin.size != 16)
+ goto bad_arg;
+ if (!enif_inspect_binary(env, state_term[2], &ecount_bin))
+ goto bad_arg;
+ if (ecount_bin.size != AES_BLOCK_SIZE)
+ goto bad_arg;
+ if (!enif_get_uint(env, state_term[3], &num))
+ goto bad_arg;
+ if (!enif_inspect_iolist_as_binary(env, data_arg, &text_bin))
+ goto bad_arg;
+
+ /* NOTE: This function returns 0 on success unlike most OpenSSL functions */
+ if (AES_set_encrypt_key(key_bin.data, (int)key_bin.size * 8, &aes_key) != 0)
+ goto bad_arg;
+
+ if ((ivec2_buf = enif_make_new_binary(env, ivec_bin.size, &ivec2_term)) == NULL)
+ goto err;
+ if ((ecount2_buf = enif_make_new_binary(env, ecount_bin.size, &ecount2_term)) == NULL)
+ goto err;
+
+ memcpy(ivec2_buf, ivec_bin.data, 16);
+ memcpy(ecount2_buf, ecount_bin.data, ecount_bin.size);
+
+ if ((outp = enif_make_new_binary(env, text_bin.size, &cipher_term)) == NULL)
+ goto err;
+
+ AES_ctr128_encrypt((unsigned char *) text_bin.data,
+ outp,
+ text_bin.size, &aes_key, ivec2_buf, ecount2_buf, &num);
+
+ num2_term = enif_make_uint(env, num);
+ new_state_term = enif_make_tuple4(env, state_term[0], ivec2_term, ecount2_term, num2_term);
+ ret = enif_make_tuple2(env, new_state_term, cipher_term);
+ CONSUME_REDS(env,text_bin);
+ return ret;
+
+ bad_arg:
+ err:
+ return enif_make_badarg(env);
+}
+#endif /* !HAVE_EVP_AES_CTR */
+
+#ifdef HAVE_GCM_EVP_DECRYPT_BUG
+ERL_NIF_TERM aes_gcm_decrypt_NO_EVP(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Type,Key,Iv,AAD,In,Tag) */
+ GCM128_CONTEXT *ctx = NULL;
+ ErlNifBinary key, iv, aad, in, tag;
+ AES_KEY aes_key;
+ unsigned char *outp;
+ ERL_NIF_TERM out, ret;
+
+ ASSERT(argc == 6);
+
+ if (!enif_inspect_iolist_as_binary(env, argv[1], &key))
+ goto bad_arg;
+ if (key.size > INT_MAX / 8)
+ goto bad_arg;
+ if (!enif_inspect_binary(env, argv[2], &iv))
+ goto bad_arg;
+ if (iv.size == 0)
+ goto bad_arg;
+ if (!enif_inspect_iolist_as_binary(env, argv[3], &aad))
+ goto bad_arg;
+ if (!enif_inspect_iolist_as_binary(env, argv[4], &in))
+ goto bad_arg;
+ if (!enif_inspect_iolist_as_binary(env, argv[5], &tag))
+ goto bad_arg;
+
+ /* NOTE: This function returns 0 on success unlike most OpenSSL functions */
+ if (AES_set_encrypt_key(key.data, (int)key.size * 8, &aes_key) != 0)
+ goto bad_arg;
+
+ if ((ctx = CRYPTO_gcm128_new(&aes_key, (block128_f)AES_encrypt)) == NULL)
+ goto err;
+
+ CRYPTO_gcm128_setiv(ctx, iv.data, iv.size);
+
+ /* NOTE: This function returns 0 on success unlike most OpenSSL functions */
+ if (CRYPTO_gcm128_aad(ctx, aad.data, aad.size) != 0)
+ goto err;
+
+ if ((outp = enif_make_new_binary(env, in.size, &out)) == NULL)
+ goto err;
+
+ /* NOTE: This function returns 0 on success unlike most OpenSSL functions */
+ if (CRYPTO_gcm128_decrypt(ctx, in.data, outp, in.size) != 0)
+ goto err;
+
+ /* calculate and check the tag */
+ /* NOTE: This function returns 0 on success unlike most OpenSSL functions */
+ if (CRYPTO_gcm128_finish(ctx, tag.data, tag.size) != 0)
+ goto err;
+
+ CONSUME_REDS(env, in);
+ ret = out;
+ goto done;
+
+ bad_arg:
+ ret = enif_make_badarg(env);
+ goto done;
+
+ err:
+ ret = atom_error;
+
+ done:
+ if (ctx)
+ CRYPTO_gcm128_release(ctx);
+ return ret;
+}
+#endif /* HAVE_GCM_EVP_DECRYPT_BUG */
+
diff --git a/lib/crypto/c_src/aes.h b/lib/crypto/c_src/aes.h
new file mode 100644
index 0000000000..c0b2b91f8d
--- /dev/null
+++ b/lib/crypto/c_src/aes.h
@@ -0,0 +1,38 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_AES_H__
+#define E_AES_H__ 1
+
+#include "common.h"
+
+ERL_NIF_TERM aes_cfb_8_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM aes_cfb_128_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM aes_ige_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+#if !defined(HAVE_EVP_AES_CTR)
+ERL_NIF_TERM aes_ctr_stream_encrypt_compat(ErlNifEnv* env, const ERL_NIF_TERM state_arg, const ERL_NIF_TERM data_arg);
+#endif
+
+#ifdef HAVE_GCM_EVP_DECRYPT_BUG
+ERL_NIF_TERM aes_gcm_decrypt_NO_EVP(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+#endif
+
+#endif /* E_AES_H__ */
diff --git a/lib/crypto/c_src/algorithms.c b/lib/crypto/c_src/algorithms.c
new file mode 100644
index 0000000000..75cddeb1e9
--- /dev/null
+++ b/lib/crypto/c_src/algorithms.c
@@ -0,0 +1,320 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "algorithms.h"
+#include "cipher.h"
+
+static unsigned int algo_hash_cnt, algo_hash_fips_cnt;
+static ERL_NIF_TERM algo_hash[14]; /* increase when extending the list */
+static unsigned int algo_pubkey_cnt, algo_pubkey_fips_cnt;
+static ERL_NIF_TERM algo_pubkey[12]; /* increase when extending the list */
+static unsigned int algo_mac_cnt, algo_mac_fips_cnt;
+static ERL_NIF_TERM algo_mac[3]; /* increase when extending the list */
+static unsigned int algo_curve_cnt, algo_curve_fips_cnt;
+static ERL_NIF_TERM algo_curve[89]; /* increase when extending the list */
+static unsigned int algo_rsa_opts_cnt, algo_rsa_opts_fips_cnt;
+static ERL_NIF_TERM algo_rsa_opts[11]; /* increase when extending the list */
+
+void init_algorithms_types(ErlNifEnv* env)
+{
+ // Validated algorithms first
+ algo_hash_cnt = 0;
+ algo_hash[algo_hash_cnt++] = atom_sha;
+#ifdef HAVE_SHA224
+ algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha224");
+#endif
+#ifdef HAVE_SHA256
+ algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha256");
+#endif
+#ifdef HAVE_SHA384
+ algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha384");
+#endif
+#ifdef HAVE_SHA512
+ algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha512");
+#endif
+#ifdef HAVE_SHA3_224
+ algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha3_224");
+#endif
+#ifdef HAVE_SHA3_256
+ algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha3_256");
+#endif
+#ifdef HAVE_SHA3_384
+ algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha3_384");
+#endif
+#ifdef HAVE_SHA3_512
+ algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha3_512");
+#endif
+#ifdef HAVE_BLAKE2
+ algo_hash[algo_hash_cnt++] = enif_make_atom(env, "blake2b");
+ algo_hash[algo_hash_cnt++] = enif_make_atom(env, "blake2s");
+#endif
+
+ // Non-validated algorithms follow
+ algo_hash_fips_cnt = algo_hash_cnt;
+#ifdef HAVE_MD4
+ algo_hash[algo_hash_cnt++] = enif_make_atom(env, "md4");
+#endif
+#ifdef HAVE_MD5
+ algo_hash[algo_hash_cnt++] = enif_make_atom(env, "md5");
+#endif
+#ifdef HAVE_RIPEMD160
+ algo_hash[algo_hash_cnt++] = enif_make_atom(env, "ripemd160");
+#endif
+
+ algo_pubkey_cnt = 0;
+ algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "rsa");
+#ifdef HAVE_DSA
+ algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "dss");
+#endif
+#ifdef HAVE_DH
+ algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "dh");
+#endif
+#if defined(HAVE_EC)
+#if !defined(OPENSSL_NO_EC2M)
+ algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "ec_gf2m");
+#endif
+ algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "ecdsa");
+ algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "ecdh");
+#endif
+ // Non-validated algorithms follow
+ algo_pubkey_fips_cnt = algo_pubkey_cnt;
+ // Don't know if Edward curves are fips validated
+#if defined(HAVE_EDDSA)
+ algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "eddsa");
+#endif
+ algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "srp");
+
+
+ // Validated algorithms first
+ algo_mac_cnt = 0;
+ algo_mac[algo_mac_cnt++] = enif_make_atom(env,"hmac");
+#ifdef HAVE_CMAC
+ algo_mac[algo_mac_cnt++] = enif_make_atom(env,"cmac");
+#endif
+#ifdef HAVE_POLY1305
+ algo_mac[algo_mac_cnt++] = enif_make_atom(env,"poly1305");
+#endif
+ // Non-validated algorithms follow
+ algo_mac_fips_cnt = algo_mac_cnt;
+
+ // Validated algorithms first
+ algo_curve_cnt = 0;
+#if defined(HAVE_EC)
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp160k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp160r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp160r2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp192r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp192k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp224k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp224r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp256k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp256r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp384r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp521r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"prime192v1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"prime192v2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"prime192v3");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"prime239v1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"prime239v2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"prime239v3");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"prime256v1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls7");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls9");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls12");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP160r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP160t1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP192r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP192t1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP224r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP224t1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP256r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP256t1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP320r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP320t1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP384r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP384t1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP512r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP512t1");
+#if !defined(OPENSSL_NO_EC2M)
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect163k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect163r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect163r2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect193r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect193r2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect233k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect233r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect239k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect283k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect283r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect409k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect409r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect571k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect571r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb163v1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb163v2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb163v3");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb176v1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb191v1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb191v2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb191v3");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb208w1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb239v1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb239v2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb239v3");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb272w1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb304w1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb359v1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb368w1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb431r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls3");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls5");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls10");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls11");
+#endif
+#endif
+ // Non-validated algorithms follow
+ algo_curve_fips_cnt = algo_curve_cnt;
+#if defined(HAVE_EC)
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp112r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp112r2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp128r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp128r2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls6");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls8");
+#if !defined(OPENSSL_NO_EC2M)
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect113r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect113r2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect131r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect131r2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls4");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"ipsec3");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"ipsec4");
+#endif
+#endif
+ //--
+#ifdef HAVE_EDDSA
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"ed25519");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"ed448");
+#endif
+#ifdef HAVE_ED_CURVE_DH
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"x25519");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"x448");
+#endif
+
+ // Validated algorithms first
+ algo_rsa_opts_cnt = 0;
+#ifdef HAS_EVP_PKEY_CTX
+# ifdef HAVE_RSA_PKCS1_PSS_PADDING
+ algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_pkcs1_pss_padding");
+ algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_pss_saltlen");
+# endif
+# ifdef HAVE_RSA_MGF1_MD
+ algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_mgf1_md");
+# endif
+# ifdef HAVE_RSA_OAEP_PADDING
+ algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_pkcs1_oaep_padding");
+# endif
+# ifdef HAVE_RSA_OAEP_MD
+ algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_oaep_label");
+ algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_oaep_md");
+# endif
+ algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"signature_md");
+#endif
+ algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_pkcs1_padding");
+ algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_x931_padding");
+#ifdef HAVE_RSA_SSLV23_PADDING
+ algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_sslv23_padding");
+#endif
+ algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_no_padding");
+ algo_rsa_opts_fips_cnt = algo_rsa_opts_cnt;
+
+
+ // Check that the max number of algos is updated
+ ASSERT(algo_hash_cnt <= sizeof(algo_hash)/sizeof(ERL_NIF_TERM));
+ ASSERT(algo_pubkey_cnt <= sizeof(algo_pubkey)/sizeof(ERL_NIF_TERM));
+ ASSERT(algo_mac_cnt <= sizeof(algo_mac)/sizeof(ERL_NIF_TERM));
+ ASSERT(algo_curve_cnt <= sizeof(algo_curve)/sizeof(ERL_NIF_TERM));
+ ASSERT(algo_rsa_opts_cnt <= sizeof(algo_rsa_opts)/sizeof(ERL_NIF_TERM));
+}
+
+
+ERL_NIF_TERM hash_algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ unsigned int cnt =
+#ifdef FIPS_SUPPORT
+ FIPS_mode() ? algo_hash_fips_cnt :
+#endif
+ algo_hash_cnt;
+
+ return enif_make_list_from_array(env, algo_hash, cnt);
+}
+
+ERL_NIF_TERM pubkey_algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ unsigned int cnt =
+#ifdef FIPS_SUPPORT
+ FIPS_mode() ? algo_pubkey_fips_cnt :
+#endif
+ algo_pubkey_cnt;
+
+ return enif_make_list_from_array(env, algo_pubkey, cnt);
+}
+
+
+ERL_NIF_TERM cipher_algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ return cipher_types_as_list(env); /* Exclude old api ciphers */
+}
+
+ERL_NIF_TERM mac_algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ unsigned int cnt =
+#ifdef FIPS_SUPPORT
+ FIPS_mode() ? algo_mac_fips_cnt :
+#endif
+ algo_mac_cnt;
+
+ return enif_make_list_from_array(env, algo_mac, cnt);
+}
+
+
+ERL_NIF_TERM curve_algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ unsigned int cnt =
+#ifdef FIPS_SUPPORT
+ FIPS_mode() ? algo_curve_fips_cnt :
+#endif
+ algo_curve_cnt;
+
+ return enif_make_list_from_array(env, algo_curve, cnt);
+}
+
+
+ERL_NIF_TERM rsa_opts_algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ unsigned int cnt =
+#ifdef FIPS_SUPPORT
+ FIPS_mode() ? algo_rsa_opts_fips_cnt :
+#endif
+ algo_rsa_opts_cnt;
+
+ return enif_make_list_from_array(env, algo_rsa_opts, cnt);
+}
diff --git a/lib/crypto/c_src/algorithms.h b/lib/crypto/c_src/algorithms.h
new file mode 100644
index 0000000000..4ad8b56db8
--- /dev/null
+++ b/lib/crypto/c_src/algorithms.h
@@ -0,0 +1,35 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_ALGORITHMS_H__
+#define E_ALGORITHMS_H__ 1
+
+#include "common.h"
+
+void init_algorithms_types(ErlNifEnv* env);
+
+ERL_NIF_TERM hash_algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM pubkey_algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM cipher_algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM mac_algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM curve_algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM rsa_opts_algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+#endif /* E_ALGORITHMS_H__ */
diff --git a/lib/crypto/c_src/api_ng.c b/lib/crypto/c_src/api_ng.c
new file mode 100644
index 0000000000..3408ba1b88
--- /dev/null
+++ b/lib/crypto/c_src/api_ng.c
@@ -0,0 +1,569 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "api_ng.h"
+#include "aes.h"
+#include "cipher.h"
+
+/*
+ * A unified set of functions for encryption/decryption.
+ *
+ */
+ERL_NIF_TERM ng_crypto_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM ng_crypto_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+#ifdef HAVE_ECB_IVEC_BUG
+ /* <= 0.9.8l returns faulty ivec length */
+# define GET_IV_LEN(Ciph) ((Ciph)->flags & ECB_BUG_0_9_8L) ? 0 : EVP_CIPHER_iv_length((Ciph)->cipher.p)
+#else
+# define GET_IV_LEN(Ciph) EVP_CIPHER_iv_length((Ciph)->cipher.p)
+#endif
+
+/*************************************************************************/
+/* Get the arguments for the initialization of the EVP_CIPHER_CTX. Check */
+/* them and initialize that context. */
+/*************************************************************************/
+static int get_init_args(ErlNifEnv* env,
+ struct evp_cipher_ctx *ctx_res,
+ const ERL_NIF_TERM cipher_arg,
+ const ERL_NIF_TERM key_arg,
+ const ERL_NIF_TERM ivec_arg,
+ const ERL_NIF_TERM encflg_arg,
+ const struct cipher_type_t **cipherp,
+ ERL_NIF_TERM *return_term)
+{
+ int ivec_len;
+ ErlNifBinary key_bin;
+ ErlNifBinary ivec_bin;
+ int encflg;
+
+ ctx_res->ctx = NULL; /* For testing if *ctx should be freed after errors */
+
+ /* Fetch the flag telling if we are going to encrypt (=true) or decrypt (=false) */
+ if (encflg_arg == atom_true)
+ encflg = 1;
+ else if (encflg_arg == atom_false)
+ encflg = 0;
+ else if (encflg_arg == atom_undefined)
+ /* For compat funcs in crypto.erl */
+ encflg = -1;
+ else
+ {
+ *return_term = EXCP_BADARG(env, "Bad enc flag");
+ goto err;
+ }
+
+ /* Fetch the key */
+ if (!enif_inspect_iolist_as_binary(env, key_arg, &key_bin))
+ {
+ *return_term = EXCP_BADARG(env, "Bad key");
+ goto err;
+ }
+
+ /* Fetch cipher type */
+ if (!enif_is_atom(env, cipher_arg))
+ {
+ *return_term = EXCP_BADARG(env, "Cipher id is not an atom");
+ goto err;
+ }
+
+ if (!(*cipherp = get_cipher_type(cipher_arg, key_bin.size)))
+ {
+ if (!get_cipher_type_no_key(cipher_arg))
+ *return_term = EXCP_BADARG(env, "Unknown cipher");
+ else
+ *return_term = EXCP_BADARG(env, "Bad key size");
+ goto err;
+ }
+
+ if ((*cipherp)->flags & AEAD_CIPHER)
+ {
+ *return_term = EXCP_BADARG(env, "Missing arguments for this cipher");
+ goto err;
+ }
+
+
+ if (FORBIDDEN_IN_FIPS(*cipherp))
+ {
+ *return_term = EXCP_NOTSUP(env, "Forbidden in FIPS");
+ goto err;
+ }
+
+ /* Get ivec_len for this cipher (if we found one) */
+#if !defined(HAVE_EVP_AES_CTR)
+ /* This code is for historic OpenSSL where EVP_aes_*_ctr is not defined.... */
+ if ((*cipherp)->cipher.p) {
+ /* Not aes_ctr compatibility code since EVP_*
+ was defined and assigned to (*cipherp)->cipher.p */
+ ivec_len = GET_IV_LEN(*cipherp);
+ } else {
+ /* No EVP_* was found */
+ if ((*cipherp)->flags & AES_CTR_COMPAT)
+ /* Use aes_ctr compatibility code later */
+ ivec_len = 16;
+ else {
+ /* Unsupported crypto */
+ *return_term = EXCP_NOTSUP(env, "Cipher not supported in this libcrypto version");
+ goto err;
+ }
+ }
+#else
+ /* Normal code */
+ if (!((*cipherp)->cipher.p)) {
+ *return_term = EXCP_NOTSUP(env, "Cipher not supported in this libcrypto version");
+ goto err;
+ }
+ ivec_len = GET_IV_LEN(*cipherp);
+#endif
+
+ /* (*cipherp)->cipher.p != NULL and ivec_len has a value */
+
+ /* Fetch IV */
+ if (ivec_len && (ivec_arg != atom_undefined)) {
+ if (!enif_inspect_iolist_as_binary(env, ivec_arg, &ivec_bin))
+ {
+ *return_term = EXCP_BADARG(env, "Bad iv type");
+ goto err;
+ }
+
+ if (ivec_len != ivec_bin.size)
+ {
+ *return_term = EXCP_BADARG(env, "Bad iv size");
+ goto err;
+ }
+ }
+
+ ctx_res->iv_len = ivec_len;
+
+#if !defined(HAVE_EVP_AES_CTR)
+ if (!((*cipherp)->cipher.p)
+ && ((*cipherp)->flags & AES_CTR_COMPAT)
+ ) {
+ /* Must use aes_ctr compatibility code */
+ ERL_NIF_TERM ecount_bin;
+ unsigned char *outp;
+ if ((outp = enif_make_new_binary(env, AES_BLOCK_SIZE, &ecount_bin)) == NULL) {
+ *return_term = EXCP_ERROR(env, "Can't allocate ecount_bin");
+ goto err;
+ }
+ memset(outp, 0, AES_BLOCK_SIZE);
+
+ ctx_res->env = enif_alloc_env();
+ if (!ctx_res->env) {
+ *return_term = EXCP_ERROR(env, "Can't allocate env");
+ goto err;
+ }
+ ctx_res->state =
+ enif_make_copy(ctx_res->env,
+ enif_make_tuple4(env, key_arg, ivec_arg, ecount_bin, enif_make_int(env, 0)));
+ goto success;
+ } else {
+ /* Flag for subsequent calls that no aes_ctr compatibility code should be called */
+ ctx_res->state = atom_undefined;
+ ctx_res->env = NULL;
+ }
+#endif
+
+ /* Initialize the EVP_CIPHER_CTX */
+
+ ctx_res->ctx = EVP_CIPHER_CTX_new();
+ if (! ctx_res->ctx)
+ {
+ *return_term = EXCP_ERROR(env, "Can't allocate context");
+ goto err;
+ }
+
+ if (!EVP_CipherInit_ex(ctx_res->ctx, (*cipherp)->cipher.p, NULL, NULL, NULL, encflg))
+ {
+ *return_term = EXCP_ERROR(env, "Can't initialize context, step 1");
+ goto err;
+ }
+
+ if (!EVP_CIPHER_CTX_set_key_length(ctx_res->ctx, (int)key_bin.size))
+ {
+ *return_term = EXCP_ERROR(env, "Can't initialize context, key_length");
+ goto err;
+ }
+
+#ifdef HAVE_RC2
+ if (EVP_CIPHER_type((*cipherp)->cipher.p) == NID_rc2_cbc) {
+ if (key_bin.size > INT_MAX / 8) {
+ *return_term = EXCP_BADARG(env, "To large rc2_cbc key");
+ goto err;
+ }
+ if (!EVP_CIPHER_CTX_ctrl(ctx_res->ctx, EVP_CTRL_SET_RC2_KEY_BITS, (int)key_bin.size * 8, NULL)) {
+ *return_term = EXCP_ERROR(env, "ctrl rc2_cbc key");
+ goto err;
+ }
+ }
+#endif
+
+ if (ivec_arg == atom_undefined || ivec_len == 0)
+ {
+ if (!EVP_CipherInit_ex(ctx_res->ctx, NULL, NULL, key_bin.data, NULL, -1)) {
+ *return_term = EXCP_ERROR(env, "Can't initialize key");
+ goto err;
+ }
+ }
+ else
+ if (!EVP_CipherInit_ex(ctx_res->ctx, NULL, NULL, key_bin.data, ivec_bin.data, -1))
+ {
+ *return_term = EXCP_ERROR(env, "Can't initialize key or iv");
+ goto err;
+ }
+
+ EVP_CIPHER_CTX_set_padding(ctx_res->ctx, 0);
+
+ *return_term = atom_ok;
+
+#if !defined(HAVE_EVP_AES_CTR)
+ success:
+#endif
+ return 1;
+
+ err:
+ if (ctx_res->ctx) EVP_CIPHER_CTX_free(ctx_res->ctx);
+ return 0;
+}
+
+/*************************************************************************/
+/* Get the arguments for the EVP_CipherUpdate function, and call it. */
+/*************************************************************************/
+
+static int get_update_args(ErlNifEnv* env,
+ struct evp_cipher_ctx *ctx_res,
+ const ERL_NIF_TERM indata_arg,
+ ERL_NIF_TERM *return_term)
+{
+ ErlNifBinary in_data_bin, out_data_bin;
+ int out_len, block_size;
+
+ if (!enif_inspect_binary(env, indata_arg, &in_data_bin) )
+ {
+ *return_term = EXCP_BADARG(env, "Bad 2:nd arg");
+ goto err;
+ }
+
+ ASSERT(in_data_bin.size <= INT_MAX);
+
+#if !defined(HAVE_EVP_AES_CTR)
+ if (ctx_res->state != atom_undefined) {
+ ERL_NIF_TERM state0, newstate_and_outdata;
+ const ERL_NIF_TERM *tuple_argv;
+ int tuple_argc;
+
+ state0 = enif_make_copy(env, ctx_res->state);
+
+ if (enif_get_tuple(env, state0, &tuple_argc, &tuple_argv) && (tuple_argc == 4)) {
+ /* A compatibility state term */
+ /* encrypt and decrypt is performed by calling the same function */
+ newstate_and_outdata = aes_ctr_stream_encrypt_compat(env, state0, indata_arg);
+
+ if (enif_get_tuple(env, newstate_and_outdata, &tuple_argc, &tuple_argv) && (tuple_argc == 2)) {
+ /* newstate_and_outdata = {NewState, OutData} */
+ ctx_res->state = enif_make_copy(ctx_res->env, tuple_argv[0]);
+ /* Return the OutData (from the newstate_and_outdata tuple) only: */
+ *return_term = tuple_argv[1];
+ }
+ }
+ } else
+#endif
+ {
+ block_size = EVP_CIPHER_CTX_block_size(ctx_res->ctx);
+
+ if (!enif_alloc_binary((size_t)in_data_bin.size+block_size, &out_data_bin))
+ {
+ *return_term = EXCP_ERROR(env, "Can't allocate outdata");
+ goto err;
+ }
+
+ if (!EVP_CipherUpdate(ctx_res->ctx, out_data_bin.data, &out_len, in_data_bin.data, in_data_bin.size))
+ {
+ *return_term = EXCP_ERROR(env, "Can't update");
+ goto err;
+ }
+
+ if (!enif_realloc_binary(&out_data_bin, (size_t)out_len))
+ {
+ *return_term = EXCP_ERROR(env, "Can't reallocate");
+ goto err;
+ }
+
+ CONSUME_REDS(env, in_data_bin);
+ /* return the result text as a binary: */
+ *return_term = enif_make_binary(env, &out_data_bin);
+ }
+
+ /* success: */
+ return 1;
+
+ err:
+ return 0;
+}
+
+/*************************************************************************/
+/* Initialize the state for (de/en)cryption */
+/*************************************************************************/
+
+ERL_NIF_TERM ng_crypto_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Cipher, Key, IVec, Encrypt) % if no IV for the Cipher, set IVec = <<>>
+ */
+ struct evp_cipher_ctx *ctx_res = NULL;
+ const struct cipher_type_t *cipherp;
+ ERL_NIF_TERM ret;
+ int encflg;
+
+ if (enif_is_atom(env, argv[0])) {
+ if ((ctx_res = enif_alloc_resource(evp_cipher_ctx_rtype, sizeof(struct evp_cipher_ctx))) == NULL)
+ return EXCP_ERROR(env, "Can't allocate resource");
+
+ if (!get_init_args(env, ctx_res, argv[0], argv[1], argv[2], argv[argc-1],
+ &cipherp, &ret))
+ /* Error msg in &ret */
+ goto ret;
+
+ ret = enif_make_resource(env, ctx_res);
+ if(ctx_res) enif_release_resource(ctx_res);
+
+ } else if (enif_get_resource(env, argv[0], (ErlNifResourceType*)evp_cipher_ctx_rtype, (void**)&ctx_res)) {
+ /* Fetch the flag telling if we are going to encrypt (=true) or decrypt (=false) */
+ if (argv[3] == atom_true)
+ encflg = 1;
+ else if (argv[3] == atom_false)
+ encflg = 0;
+ else {
+ ret = EXCP_BADARG(env, "Bad enc flag");
+ goto ret;
+ }
+ if (ctx_res->ctx) {
+ /* It is *not* a ctx_res for the compatibility handling of non-EVP aes_ctr */
+ if (!EVP_CipherInit_ex(ctx_res->ctx, NULL, NULL, NULL, NULL, encflg)) {
+ ret = EXCP_ERROR(env, "Can't initialize encflag");
+ goto ret;
+ }
+ }
+ ret = argv[0];
+ } else {
+ ret = EXCP_BADARG(env, "Bad 1:st arg");
+ goto ret;
+ }
+
+ ret:
+ return ret;
+}
+
+
+/*************************************************************************/
+/* Encrypt/decrypt */
+/*************************************************************************/
+
+#if !defined(HAVE_EVP_CIPHER_CTX_COPY)
+/*
+ The EVP_CIPHER_CTX_copy is not available in older cryptolibs although
+ the function is needed.
+ Instead of implement it in-place, we have a copy here as a compatibility
+ function
+*/
+
+int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in);
+
+int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in)
+{
+ if ((in == NULL) || (in->cipher == NULL))
+ {
+ return 0;
+ }
+#ifdef HAS_ENGINE_SUPPORT
+ /* Make sure it's safe to copy a cipher context using an ENGINE */
+ if (in->engine && !ENGINE_init(in->engine))
+ return 0;
+#endif
+
+ EVP_CIPHER_CTX_cleanup(out);
+ memcpy(out,in,sizeof *out);
+
+ if (in->cipher_data && in->cipher->ctx_size)
+ {
+ out->cipher_data=OPENSSL_malloc(in->cipher->ctx_size);
+ if (!out->cipher_data)
+ return 0;
+ memcpy(out->cipher_data,in->cipher_data,in->cipher->ctx_size);
+ }
+
+#if defined(EVP_CIPH_CUSTOM_COPY) && defined(EVP_CTRL_COPY)
+ if (in->cipher->flags & EVP_CIPH_CUSTOM_COPY)
+ return in->cipher->ctrl((EVP_CIPHER_CTX *)in, EVP_CTRL_COPY, 0, out);
+#endif
+ return 1;
+}
+/****** End of compatibility function ******/
+#endif
+
+
+ERL_NIF_TERM ng_crypto_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Context, Data [, IV]) */
+ struct evp_cipher_ctx *ctx_res;
+ struct evp_cipher_ctx ctx_res_copy;
+ ERL_NIF_TERM ret;
+
+ ctx_res_copy.ctx = NULL;
+
+ if (!enif_get_resource(env, argv[0], (ErlNifResourceType*)evp_cipher_ctx_rtype, (void**)&ctx_res))
+ return EXCP_BADARG(env, "Bad 1:st arg");
+
+ if (argc == 3) {
+ ErlNifBinary ivec_bin;
+
+ memcpy(&ctx_res_copy, ctx_res, sizeof ctx_res_copy);
+#if !defined(HAVE_EVP_AES_CTR)
+ if (ctx_res_copy.state == atom_undefined)
+ /* Not going to use aes_ctr compat functions */
+#endif
+ {
+ ctx_res_copy.ctx = EVP_CIPHER_CTX_new();
+
+ if (!EVP_CIPHER_CTX_copy(ctx_res_copy.ctx, ctx_res->ctx)) {
+ ret = EXCP_ERROR(env, "Can't copy ctx_res");
+ goto err;
+ }
+ }
+
+ ctx_res = &ctx_res_copy;
+
+ if (!enif_inspect_iolist_as_binary(env, argv[2], &ivec_bin))
+ {
+ ret = EXCP_BADARG(env, "Bad iv type");
+ goto err;
+ }
+
+ if (ctx_res_copy.iv_len != ivec_bin.size)
+ {
+ ret = EXCP_BADARG(env, "Bad iv size");
+ goto err;
+ }
+
+#if !defined(HAVE_EVP_AES_CTR)
+ if ((ctx_res_copy.state != atom_undefined) ) {
+ /* replace the iv in state with argv[2] */
+ ERL_NIF_TERM state0;
+ const ERL_NIF_TERM *tuple_argv;
+ int tuple_argc;
+ state0 = enif_make_copy(env, ctx_res_copy.state);
+ if (enif_get_tuple(env, state0, &tuple_argc, &tuple_argv) && (tuple_argc == 4)) {
+ /* A compatibility state term */
+ ctx_res_copy.state = enif_make_tuple4(env, tuple_argv[0], argv[2], tuple_argv[2], tuple_argv[3]);
+ }
+ } else
+#endif
+ if (!EVP_CipherInit_ex(ctx_res_copy.ctx, NULL, NULL, NULL, ivec_bin.data, -1))
+ {
+ ret = EXCP_ERROR(env, "Can't set iv");
+ goto err;
+ }
+
+ get_update_args(env, &ctx_res_copy, argv[1], &ret);
+ } else
+ get_update_args(env, ctx_res, argv[1], &ret);
+
+ err:
+ if (ctx_res_copy.ctx)
+ EVP_CIPHER_CTX_free(ctx_res_copy.ctx);
+
+ return ret; /* Both success and error */
+}
+
+
+ERL_NIF_TERM ng_crypto_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Context, Data [, IV]) */
+ ErlNifBinary data_bin;
+
+ ASSERT(argc <= 3);
+
+ if (!enif_inspect_binary(env, argv[1], &data_bin))
+ return EXCP_BADARG(env, "expected binary as data");
+
+ if (data_bin.size > INT_MAX)
+ return EXCP_BADARG(env, "to long data");
+
+ /* Run long jobs on a dirty scheduler to not block the current emulator thread */
+ if (data_bin.size > MAX_BYTES_TO_NIF) {
+ return enif_schedule_nif(env, "ng_crypto_update",
+ ERL_NIF_DIRTY_JOB_CPU_BOUND,
+ ng_crypto_update, argc, argv);
+ }
+
+ return ng_crypto_update(env, argc, argv);
+}
+
+/*************************************************************************/
+/* One shot */
+/*************************************************************************/
+
+ERL_NIF_TERM ng_crypto_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Cipher, Key, IVec, Data, Encrypt) */
+ struct evp_cipher_ctx ctx_res;
+ const struct cipher_type_t *cipherp;
+ ERL_NIF_TERM ret;
+
+ ctx_res.ctx = NULL;
+#if !defined(HAVE_EVP_AES_CTR)
+ ctx_res.env = NULL;
+#endif
+
+ if (!get_init_args(env, &ctx_res, argv[0], argv[1], argv[2], argv[4], &cipherp, &ret))
+ goto ret;
+
+ get_update_args(env, &ctx_res, argv[3], &ret);
+
+ ret:
+ if (ctx_res.ctx)
+ EVP_CIPHER_CTX_free(ctx_res.ctx);
+
+#if !defined(HAVE_EVP_AES_CTR)
+ if (ctx_res.env)
+ enif_free_env(ctx_res.env);
+#endif
+
+ return ret;
+}
+
+
+ERL_NIF_TERM ng_crypto_one_time_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Cipher, Key, IVec, Data, Encrypt) % if no IV for the Cipher, set IVec = <<>>
+ */
+ ErlNifBinary data_bin;
+
+ ASSERT(argc == 5);
+
+ if (!enif_inspect_binary(env, argv[3], &data_bin))
+ return EXCP_BADARG(env, "expected binary as data");
+
+ if (data_bin.size > INT_MAX)
+ return EXCP_BADARG(env, "to long data");
+
+ /* Run long jobs on a dirty scheduler to not block the current emulator thread */
+ if (data_bin.size > MAX_BYTES_TO_NIF) {
+ return enif_schedule_nif(env, "ng_crypto_one_time",
+ ERL_NIF_DIRTY_JOB_CPU_BOUND,
+ ng_crypto_one_time, argc, argv);
+ }
+
+ return ng_crypto_one_time(env, argc, argv);
+}
diff --git a/lib/crypto/c_src/api_ng.h b/lib/crypto/c_src/api_ng.h
new file mode 100644
index 0000000000..aaf67524ae
--- /dev/null
+++ b/lib/crypto/c_src/api_ng.h
@@ -0,0 +1,30 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_API_NG_H__
+#define E_API_NG_H__ 1
+
+#include "common.h"
+
+ERL_NIF_TERM ng_crypto_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM ng_crypto_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM ng_crypto_one_time_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+#endif /* E_AES_H__ */
diff --git a/lib/crypto/c_src/atoms.c b/lib/crypto/c_src/atoms.c
new file mode 100644
index 0000000000..059c14690f
--- /dev/null
+++ b/lib/crypto/c_src/atoms.c
@@ -0,0 +1,252 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "atoms.h"
+
+ERL_NIF_TERM atom_true;
+ERL_NIF_TERM atom_false;
+ERL_NIF_TERM atom_sha;
+ERL_NIF_TERM atom_error;
+ERL_NIF_TERM atom_rsa_pkcs1_padding;
+ERL_NIF_TERM atom_rsa_pkcs1_oaep_padding;
+ERL_NIF_TERM atom_rsa_no_padding;
+ERL_NIF_TERM atom_signature_md;
+ERL_NIF_TERM atom_undefined;
+
+ERL_NIF_TERM atom_ok;
+ERL_NIF_TERM atom_none;
+ERL_NIF_TERM atom_notsup;
+ERL_NIF_TERM atom_badarg;
+ERL_NIF_TERM atom_digest;
+#ifdef FIPS_SUPPORT
+ERL_NIF_TERM atom_enabled;
+ERL_NIF_TERM atom_not_enabled;
+#else
+ERL_NIF_TERM atom_not_supported;
+#endif
+
+ERL_NIF_TERM atom_type;
+ERL_NIF_TERM atom_size;
+ERL_NIF_TERM atom_block_size;
+ERL_NIF_TERM atom_key_length;
+ERL_NIF_TERM atom_iv_length;
+ERL_NIF_TERM atom_mode;
+ERL_NIF_TERM atom_ecb_mode;
+ERL_NIF_TERM atom_cbc_mode;
+ERL_NIF_TERM atom_cfb_mode;
+ERL_NIF_TERM atom_ofb_mode;
+ERL_NIF_TERM atom_ctr_mode;
+ERL_NIF_TERM atom_gcm_mode;
+ERL_NIF_TERM atom_ccm_mode;
+ERL_NIF_TERM atom_xts_mode;
+ERL_NIF_TERM atom_wrap_mode;
+ERL_NIF_TERM atom_ocb_mode;
+ERL_NIF_TERM atom_stream_cipher;
+
+#if defined(HAVE_EC)
+ERL_NIF_TERM atom_prime_field;
+ERL_NIF_TERM atom_characteristic_two_field;
+ERL_NIF_TERM atom_tpbasis;
+ERL_NIF_TERM atom_ppbasis;
+ERL_NIF_TERM atom_onbasis;
+#endif
+
+ERL_NIF_TERM atom_aes_cfb8;
+ERL_NIF_TERM atom_aes_cfb128;
+ERL_NIF_TERM atom_aes_ige256;
+#ifdef HAVE_GCM
+ERL_NIF_TERM atom_aes_gcm;
+#endif
+#ifdef HAVE_CCM
+ERL_NIF_TERM atom_aes_ccm;
+#endif
+
+ERL_NIF_TERM atom_rsa;
+ERL_NIF_TERM atom_dss;
+ERL_NIF_TERM atom_ecdsa;
+
+#ifdef HAVE_ED_CURVE_DH
+ERL_NIF_TERM atom_x25519;
+ERL_NIF_TERM atom_x448;
+#endif
+
+ERL_NIF_TERM atom_eddsa;
+#ifdef HAVE_EDDSA
+ERL_NIF_TERM atom_ed25519;
+ERL_NIF_TERM atom_ed448;
+#endif
+
+ERL_NIF_TERM atom_rsa_mgf1_md;
+ERL_NIF_TERM atom_rsa_oaep_label;
+ERL_NIF_TERM atom_rsa_oaep_md;
+ERL_NIF_TERM atom_rsa_pad; /* backwards compatibility */
+ERL_NIF_TERM atom_rsa_padding;
+ERL_NIF_TERM atom_rsa_pkcs1_pss_padding;
+#ifdef HAVE_RSA_SSLV23_PADDING
+ERL_NIF_TERM atom_rsa_sslv23_padding;
+#endif
+ERL_NIF_TERM atom_rsa_x931_padding;
+ERL_NIF_TERM atom_rsa_pss_saltlen;
+
+#ifdef HAVE_BLAKE2
+ERL_NIF_TERM atom_blake2b;
+ERL_NIF_TERM atom_blake2s;
+#endif
+
+#ifdef HAS_ENGINE_SUPPORT
+
+ERL_NIF_TERM atom_engine_method_rsa;
+ERL_NIF_TERM atom_engine_method_dsa;
+ERL_NIF_TERM atom_engine_method_dh;
+ERL_NIF_TERM atom_engine_method_rand;
+ERL_NIF_TERM atom_engine_method_ecdh;
+ERL_NIF_TERM atom_engine_method_ecdsa;
+ERL_NIF_TERM atom_engine_method_ciphers;
+ERL_NIF_TERM atom_engine_method_digests;
+ERL_NIF_TERM atom_engine_method_store;
+ERL_NIF_TERM atom_engine_method_pkey_meths;
+ERL_NIF_TERM atom_engine_method_pkey_asn1_meths;
+ERL_NIF_TERM atom_engine_method_ec;
+
+ERL_NIF_TERM atom_engine;
+ERL_NIF_TERM atom_key_id;
+ERL_NIF_TERM atom_password;
+#endif
+
+int init_atoms(ErlNifEnv *env, const ERL_NIF_TERM fips_mode, const ERL_NIF_TERM load_info) {
+ atom_true = enif_make_atom(env,"true");
+ atom_false = enif_make_atom(env,"false");
+ /* Enter FIPS mode */
+ if (fips_mode == atom_true) {
+#ifdef FIPS_SUPPORT
+ if (!FIPS_mode_set(1)) {
+#else
+ {
+#endif
+ PRINTF_ERR0("CRYPTO: Could not setup FIPS mode");
+ return 0;
+ }
+ } else if (fips_mode != atom_false) {
+ PRINTF_ERR1("CRYPTO: Invalid load_info '%T'", load_info);
+ return 0;
+ }
+
+ atom_sha = enif_make_atom(env,"sha");
+ atom_error = enif_make_atom(env,"error");
+ atom_rsa_pkcs1_padding = enif_make_atom(env,"rsa_pkcs1_padding");
+ atom_rsa_pkcs1_oaep_padding = enif_make_atom(env,"rsa_pkcs1_oaep_padding");
+ atom_rsa_no_padding = enif_make_atom(env,"rsa_no_padding");
+ atom_signature_md = enif_make_atom(env,"signature_md");
+ atom_undefined = enif_make_atom(env,"undefined");
+ atom_ok = enif_make_atom(env,"ok");
+ atom_none = enif_make_atom(env,"none");
+ atom_notsup = enif_make_atom(env,"notsup");
+ atom_badarg = enif_make_atom(env,"badarg");
+ atom_digest = enif_make_atom(env,"digest");
+
+ atom_type = enif_make_atom(env,"type");
+ atom_size = enif_make_atom(env,"size");
+ atom_block_size = enif_make_atom(env,"block_size");
+ atom_key_length = enif_make_atom(env,"key_length");
+ atom_iv_length = enif_make_atom(env,"iv_length");
+ atom_mode = enif_make_atom(env,"mode");
+ atom_ecb_mode = enif_make_atom(env,"ecb_mode");
+ atom_cbc_mode = enif_make_atom(env,"cbc_mode");
+ atom_cfb_mode = enif_make_atom(env,"cfb_mode");
+ atom_ofb_mode = enif_make_atom(env,"ofb_mode");
+ atom_ctr_mode = enif_make_atom(env,"ctr_mode");
+ atom_gcm_mode = enif_make_atom(env,"gcm_mode");
+ atom_ccm_mode = enif_make_atom(env,"ccm_mode");
+ atom_xts_mode = enif_make_atom(env,"xts_mode");
+ atom_wrap_mode = enif_make_atom(env,"wrap_mode");
+ atom_ocb_mode = enif_make_atom(env,"ocb_mode");
+ atom_stream_cipher = enif_make_atom(env,"stream_cipher");
+
+#if defined(HAVE_EC)
+ atom_prime_field = enif_make_atom(env,"prime_field");
+ atom_characteristic_two_field = enif_make_atom(env,"characteristic_two_field");
+ atom_tpbasis = enif_make_atom(env,"tpbasis");
+ atom_ppbasis = enif_make_atom(env,"ppbasis");
+ atom_onbasis = enif_make_atom(env,"onbasis");
+#endif
+
+ atom_aes_cfb8 = enif_make_atom(env, "aes_cfb8");
+ atom_aes_cfb128 = enif_make_atom(env, "aes_cfb128");
+ atom_aes_ige256 = enif_make_atom(env, "aes_ige256");
+#ifdef HAVE_GCM
+ atom_aes_gcm = enif_make_atom(env, "aes_gcm");
+#endif
+#ifdef HAVE_CCM
+ atom_aes_ccm = enif_make_atom(env, "aes_ccm");
+#endif
+
+#ifdef FIPS_SUPPORT
+ atom_enabled = enif_make_atom(env,"enabled");
+ atom_not_enabled = enif_make_atom(env,"not_enabled");
+#else
+ atom_not_supported = enif_make_atom(env,"not_supported");
+#endif
+ atom_rsa = enif_make_atom(env,"rsa");
+ atom_dss = enif_make_atom(env,"dss");
+ atom_ecdsa = enif_make_atom(env,"ecdsa");
+
+#ifdef HAVE_ED_CURVE_DH
+ atom_x25519 = enif_make_atom(env,"x25519");
+ atom_x448 = enif_make_atom(env,"x448");
+#endif
+ atom_eddsa = enif_make_atom(env,"eddsa");
+#ifdef HAVE_EDDSA
+ atom_ed25519 = enif_make_atom(env,"ed25519");
+ atom_ed448 = enif_make_atom(env,"ed448");
+#endif
+ atom_rsa_mgf1_md = enif_make_atom(env,"rsa_mgf1_md");
+ atom_rsa_oaep_label = enif_make_atom(env,"rsa_oaep_label");
+ atom_rsa_oaep_md = enif_make_atom(env,"rsa_oaep_md");
+ atom_rsa_pad = enif_make_atom(env,"rsa_pad"); /* backwards compatibility */
+ atom_rsa_padding = enif_make_atom(env,"rsa_padding");
+ atom_rsa_pkcs1_pss_padding = enif_make_atom(env,"rsa_pkcs1_pss_padding");
+#ifdef HAVE_RSA_SSLV23_PADDING
+ atom_rsa_sslv23_padding = enif_make_atom(env,"rsa_sslv23_padding");
+#endif
+ atom_rsa_x931_padding = enif_make_atom(env,"rsa_x931_padding");
+ atom_rsa_pss_saltlen = enif_make_atom(env,"rsa_pss_saltlen");
+
+#ifdef HAS_ENGINE_SUPPORT
+
+ atom_engine_method_rsa = enif_make_atom(env,"engine_method_rsa");
+ atom_engine_method_dsa = enif_make_atom(env,"engine_method_dsa");
+ atom_engine_method_dh = enif_make_atom(env,"engine_method_dh");
+ atom_engine_method_rand = enif_make_atom(env,"engine_method_rand");
+ atom_engine_method_ecdh = enif_make_atom(env,"engine_method_ecdh");
+ atom_engine_method_ecdsa = enif_make_atom(env,"engine_method_ecdsa");
+ atom_engine_method_store = enif_make_atom(env,"engine_method_store");
+ atom_engine_method_ciphers = enif_make_atom(env,"engine_method_ciphers");
+ atom_engine_method_digests = enif_make_atom(env,"engine_method_digests");
+ atom_engine_method_pkey_meths = enif_make_atom(env,"engine_method_pkey_meths");
+ atom_engine_method_pkey_asn1_meths = enif_make_atom(env,"engine_method_pkey_asn1_meths");
+ atom_engine_method_ec = enif_make_atom(env,"engine_method_ec");
+
+ atom_engine = enif_make_atom(env,"engine");
+ atom_key_id = enif_make_atom(env,"key_id");
+ atom_password = enif_make_atom(env,"password");
+#endif
+
+ return 1;
+}
diff --git a/lib/crypto/c_src/atoms.h b/lib/crypto/c_src/atoms.h
new file mode 100644
index 0000000000..f5913de96f
--- /dev/null
+++ b/lib/crypto/c_src/atoms.h
@@ -0,0 +1,134 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_ATOMS_H__
+#define E_ATOMS_H__ 1
+
+#include <erl_nif.h>
+#include "openssl_config.h"
+
+extern ERL_NIF_TERM atom_true;
+extern ERL_NIF_TERM atom_false;
+extern ERL_NIF_TERM atom_sha;
+extern ERL_NIF_TERM atom_error;
+extern ERL_NIF_TERM atom_rsa_pkcs1_padding;
+extern ERL_NIF_TERM atom_rsa_pkcs1_oaep_padding;
+extern ERL_NIF_TERM atom_rsa_no_padding;
+extern ERL_NIF_TERM atom_signature_md;
+extern ERL_NIF_TERM atom_undefined;
+
+extern ERL_NIF_TERM atom_ok;
+extern ERL_NIF_TERM atom_none;
+extern ERL_NIF_TERM atom_notsup;
+extern ERL_NIF_TERM atom_badarg;
+extern ERL_NIF_TERM atom_digest;
+#ifdef FIPS_SUPPORT
+extern ERL_NIF_TERM atom_enabled;
+extern ERL_NIF_TERM atom_not_enabled;
+#else
+extern ERL_NIF_TERM atom_not_supported;
+#endif
+
+extern ERL_NIF_TERM atom_type;
+extern ERL_NIF_TERM atom_size;
+extern ERL_NIF_TERM atom_block_size;
+extern ERL_NIF_TERM atom_key_length;
+extern ERL_NIF_TERM atom_iv_length;
+extern ERL_NIF_TERM atom_mode;
+extern ERL_NIF_TERM atom_ecb_mode;
+extern ERL_NIF_TERM atom_cbc_mode;
+extern ERL_NIF_TERM atom_cfb_mode;
+extern ERL_NIF_TERM atom_ofb_mode;
+extern ERL_NIF_TERM atom_ctr_mode;
+extern ERL_NIF_TERM atom_gcm_mode;
+extern ERL_NIF_TERM atom_ccm_mode;
+extern ERL_NIF_TERM atom_xts_mode;
+extern ERL_NIF_TERM atom_wrap_mode;
+extern ERL_NIF_TERM atom_ocb_mode;
+extern ERL_NIF_TERM atom_stream_cipher;
+
+#if defined(HAVE_EC)
+extern ERL_NIF_TERM atom_prime_field;
+extern ERL_NIF_TERM atom_characteristic_two_field;
+extern ERL_NIF_TERM atom_tpbasis;
+extern ERL_NIF_TERM atom_ppbasis;
+extern ERL_NIF_TERM atom_onbasis;
+#endif
+
+extern ERL_NIF_TERM atom_aes_cfb8;
+extern ERL_NIF_TERM atom_aes_cfb128;
+extern ERL_NIF_TERM atom_aes_ige256;
+#ifdef HAVE_GCM
+extern ERL_NIF_TERM atom_aes_gcm;
+#endif
+#ifdef HAVE_CCM
+extern ERL_NIF_TERM atom_aes_ccm;
+#endif
+
+extern ERL_NIF_TERM atom_rsa;
+extern ERL_NIF_TERM atom_dss;
+extern ERL_NIF_TERM atom_ecdsa;
+
+#ifdef HAVE_ED_CURVE_DH
+extern ERL_NIF_TERM atom_x25519;
+extern ERL_NIF_TERM atom_x448;
+#endif
+
+extern ERL_NIF_TERM atom_eddsa;
+#ifdef HAVE_EDDSA
+extern ERL_NIF_TERM atom_ed25519;
+extern ERL_NIF_TERM atom_ed448;
+#endif
+
+extern ERL_NIF_TERM atom_rsa_mgf1_md;
+extern ERL_NIF_TERM atom_rsa_oaep_label;
+extern ERL_NIF_TERM atom_rsa_oaep_md;
+extern ERL_NIF_TERM atom_rsa_pad; /* backwards compatibility */
+extern ERL_NIF_TERM atom_rsa_padding;
+extern ERL_NIF_TERM atom_rsa_pkcs1_pss_padding;
+#ifdef HAVE_RSA_SSLV23_PADDING
+extern ERL_NIF_TERM atom_rsa_sslv23_padding;
+#endif
+extern ERL_NIF_TERM atom_rsa_x931_padding;
+extern ERL_NIF_TERM atom_rsa_pss_saltlen;
+
+#ifdef HAS_ENGINE_SUPPORT
+
+extern ERL_NIF_TERM atom_engine_method_rsa;
+extern ERL_NIF_TERM atom_engine_method_dsa;
+extern ERL_NIF_TERM atom_engine_method_dh;
+extern ERL_NIF_TERM atom_engine_method_rand;
+extern ERL_NIF_TERM atom_engine_method_ecdh;
+extern ERL_NIF_TERM atom_engine_method_ecdsa;
+extern ERL_NIF_TERM atom_engine_method_ciphers;
+extern ERL_NIF_TERM atom_engine_method_digests;
+extern ERL_NIF_TERM atom_engine_method_store;
+extern ERL_NIF_TERM atom_engine_method_pkey_meths;
+extern ERL_NIF_TERM atom_engine_method_pkey_asn1_meths;
+extern ERL_NIF_TERM atom_engine_method_ec;
+
+extern ERL_NIF_TERM atom_engine;
+extern ERL_NIF_TERM atom_key_id;
+extern ERL_NIF_TERM atom_password;
+#endif
+
+int init_atoms(ErlNifEnv *env, const ERL_NIF_TERM fips_mode, const ERL_NIF_TERM load_info);
+
+#endif /* E_ATOMS_H__ */
diff --git a/lib/crypto/c_src/bn.c b/lib/crypto/c_src/bn.c
new file mode 100644
index 0000000000..34ed4f7ebc
--- /dev/null
+++ b/lib/crypto/c_src/bn.c
@@ -0,0 +1,186 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "bn.h"
+
+
+int get_bn_from_mpint(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp)
+{
+ BIGNUM *ret;
+ ErlNifBinary bin;
+ int sz;
+
+ if (!enif_inspect_binary(env, term, &bin))
+ goto err;
+ if (bin.size > INT_MAX - 4)
+ goto err;
+
+ ERL_VALGRIND_ASSERT_MEM_DEFINED(bin.data, bin.size);
+
+ if (bin.size < 4)
+ goto err;
+ sz = (int)bin.size - 4;
+ if (get_int32(bin.data) != sz)
+ goto err;
+
+ if ((ret = BN_bin2bn(bin.data+4, sz, NULL)) == NULL)
+ goto err;
+
+ *bnp = ret;
+ return 1;
+
+ err:
+ return 0;
+}
+
+int get_bn_from_bin(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp)
+{
+ BIGNUM *ret;
+ ErlNifBinary bin;
+
+ if (!enif_inspect_binary(env, term, &bin))
+ goto err;
+ if (bin.size > INT_MAX)
+ goto err;
+
+ ERL_VALGRIND_ASSERT_MEM_DEFINED(bin.data, bin.size);
+
+ if ((ret = BN_bin2bn(bin.data, (int)bin.size, NULL)) == NULL)
+ goto err;
+
+ *bnp = ret;
+ return 1;
+
+ err:
+ return 0;
+}
+
+ERL_NIF_TERM bin_from_bn(ErlNifEnv* env, const BIGNUM *bn)
+{
+ int bn_len;
+ unsigned char *bin_ptr;
+ ERL_NIF_TERM term;
+
+ /* Copy the bignum into an erlang binary. */
+ if ((bn_len = BN_num_bytes(bn)) < 0)
+ goto err;
+ if ((bin_ptr = enif_make_new_binary(env, (size_t)bn_len, &term)) == NULL)
+ goto err;
+
+ if (BN_bn2bin(bn, bin_ptr) < 0)
+ goto err;
+
+ return term;
+
+ err:
+ return atom_error;
+}
+
+ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Base,Exponent,Modulo,bin_hdr) */
+ BIGNUM *bn_base = NULL, *bn_exponent = NULL, *bn_modulo = NULL, *bn_result = NULL;
+ BN_CTX *bn_ctx = NULL;
+ unsigned char* ptr;
+ int dlen;
+ unsigned bin_hdr; /* return type: 0=plain binary, 4: mpint */
+ unsigned extra_byte;
+ ERL_NIF_TERM ret;
+
+ ASSERT(argc == 4);
+
+ if (!get_bn_from_bin(env, argv[0], &bn_base))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, argv[1], &bn_exponent))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, argv[2], &bn_modulo))
+ goto bad_arg;
+ if (!enif_get_uint(env, argv[3], &bin_hdr))
+ goto bad_arg;
+ if (bin_hdr != 0 && bin_hdr != 4)
+ goto bad_arg;
+
+ if ((bn_result = BN_new()) == NULL)
+ goto err;
+ if ((bn_ctx = BN_CTX_new()) == NULL)
+ goto err;
+
+ if (!BN_mod_exp(bn_result, bn_base, bn_exponent, bn_modulo, bn_ctx))
+ goto err;
+
+ dlen = BN_num_bytes(bn_result);
+ if (dlen < 0 || dlen > INT_MAX / 8)
+ goto bad_arg;
+ extra_byte = bin_hdr && BN_is_bit_set(bn_result, dlen * 8 - 1);
+
+ if ((ptr = enif_make_new_binary(env, bin_hdr + extra_byte + (unsigned int)dlen, &ret)) == NULL)
+ goto err;
+
+ if (bin_hdr) {
+ put_uint32(ptr, extra_byte + (unsigned int)dlen);
+ ptr[4] = 0; /* extra zeroed byte to ensure a positive mpint */
+ ptr += bin_hdr + extra_byte;
+ }
+
+ BN_bn2bin(bn_result, ptr);
+ goto done;
+
+ bad_arg:
+ err:
+ ret = enif_make_badarg(env);
+
+ done:
+ if (bn_base)
+ BN_free(bn_base);
+ if (bn_exponent)
+ BN_free(bn_exponent);
+ if (bn_modulo)
+ BN_free(bn_modulo);
+ if (bn_result)
+ BN_free(bn_result);
+ if (bn_ctx)
+ BN_CTX_free(bn_ctx);
+ return ret;
+}
+
+#ifdef HAVE_EC
+ERL_NIF_TERM bn2term(ErlNifEnv* env, const BIGNUM *bn)
+{
+ int dlen;
+ unsigned char* ptr;
+ ERL_NIF_TERM ret;
+
+ if (bn == NULL)
+ return atom_undefined;
+
+ dlen = BN_num_bytes(bn);
+ if (dlen < 0)
+ goto err;
+ if ((ptr = enif_make_new_binary(env, (size_t)dlen, &ret)) == NULL)
+ goto err;
+
+ BN_bn2bin(bn, ptr);
+
+ ERL_VALGRIND_MAKE_MEM_DEFINED(ptr, dlen);
+ return ret;
+
+ err:
+ return enif_make_badarg(env);
+}
+#endif
diff --git a/lib/crypto/c_src/bn.h b/lib/crypto/c_src/bn.h
new file mode 100644
index 0000000000..332b06e79d
--- /dev/null
+++ b/lib/crypto/c_src/bn.h
@@ -0,0 +1,36 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_BN_H__
+#define E_BN_H__ 1
+
+#include "common.h"
+
+ERL_NIF_TERM bin_from_bn(ErlNifEnv* env, const BIGNUM *bn);
+ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+#ifdef HAVE_EC
+ERL_NIF_TERM bn2term(ErlNifEnv* env, const BIGNUM *bn);
+#endif
+
+int get_bn_from_mpint(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp);
+int get_bn_from_bin(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp);
+
+#endif /* E_BN_H__ */
diff --git a/lib/crypto/c_src/check_erlang.cocci b/lib/crypto/c_src/check_erlang.cocci
new file mode 100644
index 0000000000..b2a981f2ac
--- /dev/null
+++ b/lib/crypto/c_src/check_erlang.cocci
@@ -0,0 +1,196 @@
+// %CopyrightBegin%
+//
+// Copyright Doug Hogan 2019. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// %CopyrightEnd%
+
+// Coccinelle script to help verify Erlang calls.
+// http://coccinelle.lip6.fr
+// https://github.com/coccinelle/coccinelle
+//
+// These work with the Erlang code because it has a rigid coding pattern.
+// $ spatch.opt --all-includes -sp_file check_erlang.cocci -dir .
+
+// Make sure resources are cleaned up properly in all paths.
+// Need 'strict' so it's also checked in error handling paths.
+@enif_alloc_resource@
+type T;
+identifier CTX, L;
+identifier virtual.enif_alloc_resource, virtual.enif_release_resource;
+position p, pr;
+@@
+
+ T *CTX = NULL;
+
+ ...
+ if ((CTX = enif_alloc_resource(...)@p) == NULL)
+ goto L;
+
+ ... when strict, forall
+ if (CTX)
+ enif_release_resource(CTX)@pr;
+
+
+// After calling enif_alloc_binary(), you must either release it with
+// enif_release_binary() or transfer ownership to Erlang via enif_make_binary().
+@enif_alloc_binary@
+expression SZ;
+identifier BIN, RET, ENV, X, L;
+identifier TUPLE =~ "^enif_make_tuple[0-9]+$";
+identifier virtual.enif_alloc_binary, virtual.enif_make_binary;
+identifier virtual.enif_release_binary;
+position pa, pm, pr;
+@@
+
+// This construct is used in engine.c
+(
+ if (!enif_alloc_binary(SZ, &BIN)@pa)
+ goto L;
+
+ ... when strict, forall
+ return
+(
+ enif_make_binary(ENV, &BIN)@pm
+|
+ TUPLE(..., enif_make_binary(ENV, &BIN)@pm)@pm
+);
+
+|
+// This is the typical way we allocate and use binaries.
+ int X = 0;
+
+ ...
+ if (!enif_alloc_binary(SZ, &BIN)@pa)
+ goto L;
+ X = 1;
+
+ ... when strict, forall
+(
+ RET = enif_make_binary(ENV, &BIN)@pm;
+ X = 0;
+|
+ if (X)
+ enif_release_binary(&BIN)@pr;
+|
+ return enif_make_binary(ENV, &BIN)@pm;
+)
+)
+
+// TODO: These don't have single checks that handle all cases.
+//
+// enif_consume_timeslice returns 1 if exhausted or else 0
+// enif_has_pending_exception returns true if exception pending
+
+@erlang_check_void@
+identifier FUNCVOID =~ "^(enif_mutex_destroy|enif_mutex_lock|enif_mutex_unlock|enif_rwlock_destroy|enif_rwlock_rlock|enif_rwlock_runlock|enif_rwlock_rwlock|enif_rwlock_rwunlock|enif_system_info)$";
+position p;
+@@
+
+ FUNCVOID(...)@p;
+
+
+@erlang_check_null@
+expression X;
+identifier L;
+identifier FUNCNULL =~ "^(enif_alloc|enif_alloc_resource|enif_dlopen|enif_dlsym|enif_make_new_binary|enif_mutex_create|enif_open_resource_type|enif_realloc|enif_rwlock_create)$";
+position p;
+@@
+
+(
+ if ((X = FUNCNULL(...)@p) == NULL)
+ goto L;
+|
+ X = FUNCNULL(...)@p;
+ if (X == NULL)
+ goto L;
+|
+ return FUNCNULL(...)@p;
+)
+
+
+@erlang_check_not@
+identifier L;
+identifier FUNCNOT =~ "^(enif_alloc_binary|enif_get_int|enif_get_list_cell|enif_get_list_length|enif_get_long|enif_get_map_value|enif_get_resource|enif_get_tuple|enif_get_uint|enif_get_ulong|enif_inspect_binary|enif_inspect_iolist_as_binary|enif_is_atom|enif_is_binary|enif_is_current_process_alive|enif_is_empty_list|enif_is_list|enif_is_map|enif_is_tuple|enif_realloc_binary)$";
+position p;
+@@
+
+(
+ if (!FUNCNOT(...)@p)
+ goto L;
+|
+ return FUNCNOT(...)@p;
+)
+
+
+@erlang_check_null_free@
+expression X;
+identifier FUNCFREE =~ "^(enif_free|enif_free_env|enif_free_iovec|enif_release_binary|enif_release_resource)$";
+position p;
+@@
+
+ if (
+(
+ X
+|
+ X != NULL
+)
+ )
+ FUNCFREE(X)@p;
+
+
+@erlang_check_new@
+expression RET;
+identifier FUNCNEW =~ "^(enif_make_atom|enif_make_badarg|enif_make_binary|enif_make_int|enif_make_list|enif_make_list_from_array|enif_make_resource|enif_make_tuple|enif_raise_exception|enif_schedule_nif|enif_thread_self)$";
+position p;
+@@
+
+(
+ RET = FUNCNEW(...)@p;
+|
+ return FUNCNEW(...)@p;
+)
+
+
+// Flag any calls that aren't part of the above pattern.
+@enif_alloc_not_free@
+
+identifier FUNCVOID =~ "^(enif_mutex_destroy|enif_mutex_lock|enif_mutex_unlock|enif_rwlock_destroy|enif_rwlock_rlock|enif_rwlock_runlock|enif_rwlock_rwlock|enif_rwlock_rwunlock|enif_system_info)$";
+position pvoid != {erlang_check_void.p,enif_alloc_binary.pr};
+
+identifier FUNCNULL =~ "^(enif_alloc|enif_alloc_resource|enif_dlopen|enif_dlsym|enif_make_new_binary|enif_mutex_create|enif_open_resource_type|enif_realloc|enif_rwlock_create)$";
+position pnull != {erlang_check_null.p,enif_alloc_resource.p};
+
+identifier FUNCNOT =~ "^(enif_alloc_binary|enif_get_int|enif_get_list_cell|enif_get_list_length|enif_get_long|enif_get_map_value|enif_get_resource|enif_get_tuple|enif_get_uint|enif_get_ulong|enif_inspect_binary|enif_inspect_iolist_as_binary|enif_is_atom|enif_is_binary|enif_is_current_process_alive|enif_is_empty_list|enif_is_list|enif_is_map|enif_is_tuple|enif_realloc_binary)$";
+position pnot != {erlang_check_not.p,enif_alloc_binary.pa};
+
+identifier FUNCNEW =~ "^(enif_make_atom|enif_make_badarg|enif_make_binary|enif_make_int|enif_make_list|enif_make_list_from_array|enif_make_resource|enif_make_tuple|enif_raise_exception|enif_schedule_nif|enif_thread_self)$";
+position pnew != {erlang_check_new.p,enif_alloc_binary.pm};
+
+identifier FUNCFREE =~ "^(enif_free|enif_free_env|enif_free_iovec|enif_release_binary|enif_release_resource)$";
+position pfree != {enif_alloc_resource.pr,enif_alloc_binary.pr,erlang_check_null_free.p};
+
+@@
+
+(
+* FUNCVOID(...)@pvoid
+|
+* FUNCNULL(...)@pnull
+|
+* FUNCNOT(...)@pnot
+|
+* FUNCNEW(...)@pnew
+|
+* FUNCFREE(...)@pfree
+)
diff --git a/lib/crypto/c_src/check_openssl.cocci b/lib/crypto/c_src/check_openssl.cocci
new file mode 100644
index 0000000000..75d1a6e44b
--- /dev/null
+++ b/lib/crypto/c_src/check_openssl.cocci
@@ -0,0 +1,281 @@
+// %CopyrightBegin%
+//
+// Copyright Doug Hogan 2019. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// %CopyrightEnd%
+
+// Coccinelle script to help verify the subset of OpenSSL calls used by Erlang.
+// http://coccinelle.lip6.fr
+// https://github.com/coccinelle/coccinelle
+//
+// These work with the Erlang code because it has a rigid coding pattern.
+// $ spatch.opt --all-includes -sp_file check_openssl.cocci -dir .
+
+// TODO: These APIs may not have a single check that covers all cases
+// or may not be necessary to check.
+//
+// BN_GENCB_get_arg
+// BN_bn2bin
+// BN_cmp
+// BN_is_bit_set
+// BN_is_negative
+// BN_is_zero
+// BN_num_bits
+// DH_get0_key
+// DH_size
+// EC_GROUP_get_degree
+// EC_KEY_get0_group
+// EC_KEY_get0_private_key
+// EC_KEY_get0_public_key
+// EC_KEY_get_conv_form
+// EVP_CIPHER_block_size
+// EVP_CIPHER_iv_length
+// EVP_CIPHER_type
+// EVP_MD_CTX_md
+// EVP_MD_size
+// EVP_aes_128_cbc
+// EVP_aes_128_ccm
+// EVP_aes_128_cfb128
+// EVP_aes_128_cfb8
+// EVP_aes_128_ctr
+// EVP_aes_128_ecb
+// EVP_aes_128_gcm
+// EVP_aes_192_cbc
+// EVP_aes_192_ccm
+// EVP_aes_192_ctr
+// EVP_aes_192_ecb
+// EVP_aes_192_gcm
+// EVP_aes_256_cbc
+// EVP_aes_256_ccm
+// EVP_aes_256_ctr
+// EVP_aes_256_ecb
+// EVP_aes_256_gcm
+// EVP_bf_cbc
+// EVP_bf_cfb64
+// EVP_bf_ecb
+// EVP_bf_ofb
+// EVP_chacha20
+// EVP_chacha20_poly1305
+// EVP_des_cbc
+// EVP_des_cfb8
+// EVP_des_ecb
+// EVP_des_ede3_cbc
+// EVP_des_ede3_cfb8
+// EVP_md4
+// EVP_md5
+// EVP_rc2_cbc
+// EVP_ripemd160
+// EVP_sha1
+// EVP_sha224
+// EVP_sha256
+// EVP_sha384
+// EVP_sha3_224
+// EVP_sha3_256
+// EVP_sha3_384
+// EVP_sha3_512
+// EVP_sha512
+// OpenSSL_version
+// OpenSSL_version_num
+// PEM_read_PrivateKey
+// PEM_read_PUBKEY
+// RSA_size
+
+// Unusual API for OpenSSL: 0 or positive on success and negative value(s) on error.
+@openssl_check_negative@
+identifier FUNCNEG =~ "^(DH_compute_key|RSA_padding_check_SSLv23)$";
+expression X;
+identifier L;
+position p;
+@@
+
+ if (
+(
+ FUNCNEG(...)@p < 0
+|
+ (X = FUNCNEG(...)@p) < 0
+)
+ )
+ goto L;
+
+// Unusual API for OpenSSL: positive on success or else error
+@openssl_check_positive@
+identifier FUNCPOS =~ "^(ECDH_compute_key|EVP_CIPHER_asn1_to_param|EVP_CIPHER_param_to_asn1|EVP_PKEY_CTX_ctrl|RSA_pkey_ctx_ctrl)$";
+identifier L;
+expression X;
+position p;
+@@
+
+ if (
+(
+ FUNCPOS(...)@p < 1
+|
+ (X = FUNCPOS(...)@p) < 1
+)
+ )
+ goto L;
+
+// Unusual API for OpenSSL: 0=success.
+@openssl_check_0@
+identifier L;
+expression X;
+identifier FUNC0 =~ "^(AES_set_decrypt_key|AES_set_encrypt_key|CRYPTO_gcm128_aad|CRYPTO_gcm128_decrypt|CRYPTO_gcm128_finish)$";
+position p;
+@@
+
+ if (
+(
+ FUNC0(...)@p != 0
+|
+ (X = FUNC0(...)@p) != 0
+)
+ )
+ goto L;
+
+// These do not necessarily allocate resources but they may return NULL.
+@openssl_check_null@
+expression X;
+identifier L;
+identifier FUNCNULL =~ "^(BN_CTX_new|BN_GENCB_new|BN_MONT_CTX_new|BN_bin2bn|BN_dup|BN_generate_prime|BN_new|CMAC_CTX_new|CRYPTO_clear_realloc|CRYPTO_gcm128_new|CRYPTO_malloc|CRYPTO_realloc|CRYPTO_zalloc|DH_generate_parameters|DH_new|DSA_new|EC_GROUP_dup|EC_GROUP_get0_generator|EC_GROUP_method_of|EC_GROUP_new_curve_GFm|EC_GROUP_new_curve_GFp|EC_KEY_copy|EC_KEY_dup|EC_KEY_get0_engine|EC_KEY_new|EC_KEY_new_by_curve_name|EC_POINT_bn2point|EC_POINT_dup|EC_POINT_new|EC_POINT_point2bn|ENGINE_by_id|ENGINE_get_cipher_engine|ENGINE_get_default_DH|ENGINE_get_default_DSA|ENGINE_get_default_RAND|ENGINE_get_default_RSA|ENGINE_get_digest_engine|ENGINE_get_first|ENGINE_get_id|ENGINE_get_last|ENGINE_get_name|ENGINE_get_next|ENGINE_get_prev|ENGINE_load_private_key|ENGINE_load_public_key|ENGINE_new|EVP_CIPHER_CTX_new|EVP_MAC_CTX_new|EVP_MAC_CTX_new_id|EVP_MD_CTX_new|EVP_MD_meth_new|EVP_PKEY_CTX_new|EVP_PKEY_CTX_new_id|EVP_PKEY_get1_DH|EVP_PKEY_get1_DSA|EVP_PKEY_get1_EC_KEY|EVP_PKEY_get1_RSA|EVP_PKEY_new|EVP_PKEY_new_raw_private_key|EVP_PKEY_new_raw_public_key|EVP_get_cipherbyname|EVP_get_cipherbynid|EVP_get_cipherbyobj|EVP_get_macbyname|EVP_get_macbynid|EVP_get_macbyobj|HMAC|HMAC_CTX_new|OPENSSL_buf2hexstr|OPENSSL_clear_realloc|OPENSSL_hexstr2buf|OPENSSL_malloc|OPENSSL_realloc|OPENSSL_strdup|OPENSSL_strndup|OPENSSL_zalloc|RSA_meth_dup|RSA_meth_new|RSA_new)$";
+position p;
+@@
+
+(
+ if ((X = FUNCNULL(...)@p) == NULL)
+ goto L;
+|
+ X = FUNCNULL(...)@p;
+ if (X == NULL)
+ goto L;
+)
+
+// non-zero=success, 0=failure. These can be safely used with !
+@openssl_check_not@
+expression X;
+identifier L;
+identifier FUNCNOT =~ "^(BN_add|BN_div|BN_exp|BN_from_montgomery|BN_gcd|BN_generate_prime_ex|BN_mod|BN_mod_add|BN_mod_exp|BN_mod_mul|BN_mod_mul_montgomery|BN_mod_sqr|BN_mod_sub|BN_mul|BN_nnmod|BN_priv_rand|BN_priv_rand_range|BN_pseudo_rand|BN_pseudo_rand_range|BN_rand|BN_rand_range|BN_set_bit|BN_set_word|BN_sqr|BN_sub|BN_to_montgomery|CMAC_Final|CMAC_Init|CMAC_Update|CRYPTO_set_mem_debug|CRYPTO_set_mem_functions|DH_check|DH_check_ex|DH_check_params|DH_check_pub_key_ex|DH_generate_key|DH_generate_parameters_ex|DH_set0_key|DH_set0_pqg|DH_set_length|DSA_set0_key|DSA_set0_pqg|EC_GROUP_check|EC_GROUP_check_discriminant|EC_GROUP_copy|EC_GROUP_get_curve_name|EC_GROUP_get_pentanomial_basis|EC_GROUP_get_trinomial_basis|EC_GROUP_precompute_mult|EC_GROUP_set_generator|EC_GROUP_set_seed|EC_KEY_check_key|EC_KEY_generate_key|EC_KEY_key2buf|EC_KEY_oct2key|EC_KEY_oct2priv|EC_KEY_precompute_mult|EC_KEY_priv2buf|EC_KEY_priv2oct|EC_KEY_set_group|EC_KEY_set_private_key|EC_KEY_set_public_key|EC_KEY_set_public_key_affine_coordinates|EC_KEY_up_ref|EC_POINT_add|EC_POINT_copy|EC_POINT_dbl|EC_POINT_get_Jprojective_coordinates_GFp|EC_POINT_get_affine_coordinates_GF2m|EC_POINT_get_affine_coordinates_GFp|EC_POINT_invert|EC_POINT_make_affine|EC_POINT_mul|EC_POINT_oct2point|EC_POINT_point2oct|EC_POINT_set_Jprojective_coordinates_GFp|EC_POINT_set_affine_coordinates_GF2m|EC_POINT_set_affine_coordinates_GFp|EC_POINT_set_compressed_coordinates_GF2m|EC_POINT_set_compressed_coordinates_GFp|EC_POINT_set_to_infinity|EC_POINTs_make_affine|EC_POINTs_mul|ENGINE_add|ENGINE_ctrl_cmd|ENGINE_ctrl_cmd_string|ENGINE_finish|ENGINE_free|ENGINE_init|ENGINE_register_DH|ENGINE_register_DSA|ENGINE_register_EC|ENGINE_register_RAND|ENGINE_register_RSA|ENGINE_register_all_complete|ENGINE_register_ciphers|ENGINE_register_complete|ENGINE_register_digests|ENGINE_register_pkey_asn1_meths|ENGINE_register_pkey_meths|ENGINE_remove|ENGINE_set_RSA|ENGINE_set_default|ENGINE_set_default_DH|ENGINE_set_default_DSA|ENGINE_set_default_EC|ENGINE_set_default_RAND|ENGINE_set_default_RSA|ENGINE_set_digests|ENGINE_set_id|ENGINE_set_init_function|ENGINE_set_load_privkey_function|ENGINE_set_load_pubkey_function|ENGINE_set_name|ENGINE_up_ref|HMAC_CTX_copy|HMAC_CTX_reset|HMAC_Final|HMAC_Init_ex|HMAC_Update|MD2_Init|MD2_Update|MD2_Final|MD4_Init|MD4_Update|MD4_Final|MD5_Init|MD5_Update|MD5_Final|OPENSSL_init_crypto|OPENSSL_mem_debug_pop|OPENSSL_mem_debug_push|RSA_generate_key_ex|RSA_generate_multi_prime_key|RSA_meth_set_finish|RSA_meth_set_sign|RSA_meth_set_verify|RSA_padding_add_SSLv23|RSA_set0_crt_params|RSA_set0_factors|RSA_set0_key|RSA_set0_multi_prime_params)$";
+position p;
+@@
+
+ if (
+(
+ !FUNCNOT(...)@p
+|
+ !(X = FUNCNOT)@p
+)
+ )
+ goto L;
+
+// 1=success. These may have == 0 or <= 0 or non-one failure so we explicitly check for success.
+// Since some EVP_* functions use failure == 0 and others use <= 0, we consolidate all
+// EVP_* calls into here so it's less error prone. In such cases, they all use 1 for success.
+@openssl_check_1@
+expression X;
+identifier L;
+identifier FUNC1 =~ "^(EVP_CIPHER_CTX_copy|EVP_CIPHER_CTX_ctrl|EVP_CIPHER_CTX_rand_key|EVP_CIPHER_CTX_reset|EVP_CIPHER_CTX_set_key_length|EVP_CIPHER_CTX_set_padding|EVP_CipherFinal_ex|EVP_CipherInit_ex|EVP_CipherUpdate|EVP_DecryptFinal_ex|EVP_DecryptInit_ex|EVP_DecryptUpdate|EVP_Digest|EVP_DigestFinal|EVP_DigestFinal_ex|EVP_DigestInit|EVP_DigestInit_ex|EVP_DigestSign|EVP_DigestSignInit|EVP_DigestSignUpdate|EVP_DigestSignaFinal|EVP_DigestUpdate|EVP_DigestVerify|EVP_DigestVerifyInit|EVP_EncryptFinal_ex|EVP_EncryptInit_ex|EVP_EncryptUpdate|EVP_MAC_CTX_copy|EVP_MAC_ctrl|EVP_MAC_ctrl_str|EVP_MAC_hex2ctrl|EVP_MAC_init|EVP_MAC_reset|EVP_MAC_str2ctrl|EVP_MAC_update|EVP_MD_CTX_copy|EVP_MD_CTX_copy_ex|EVP_MD_CTX_ctrl|EVP_MD_meth_set_app_datasize|EVP_MD_meth_set_cleanup|EVP_MD_meth_set_copy|EVP_MD_meth_set_ctrl|EVP_MD_meth_set_final|EVP_MD_meth_set_flags|EVP_MD_meth_set_init|EVP_MD_meth_set_input_blocksize|EVP_MD_meth_set_result_size|EVP_MD_meth_set_update|EVP_PKEY_CTX_set_rsa_mgf1_md|EVP_PKEY_CTX_set_rsa_padding|EVP_PKEY_CTX_set_rsa_pss_saltlen|EVP_PKEY_CTX_set_signature|EVP_PKEY_assign|EVP_PKEY_assign_DSA|EVP_PKEY_assign_EC_KEY|EVP_PKEY_assign_RSA|EVP_PKEY_decrypt|EVP_PKEY_decrypt_init|EVP_PKEY_derive|EVP_PKEY_derive_init|EVP_PKEY_derive_set_peer|EVP_PKEY_encrypt|EVP_PKEY_encrypt_init|EVP_PKEY_get1_DH|EVP_PKEY_get_raw_private_key|EVP_PKEY_get_raw_public_key|EVP_PKEY_keygen|EVP_PKEY_keygen_init|EVP_PKEY_set1_DH|EVP_PKEY_sign|EVP_PKEY_sign_init|EVP_PKEY_verify|EVP_PKEY_verify_init|EVP_PKEY_verify_recover|EVP_PKEY_verify_recover_init|EVP_add_mac|RAND_bytes|RAND_priv_bytes)$";
+position p;
+@@
+
+ if (
+(
+ FUNC1(...)@p != 1
+|
+ (X = FUNC1(...)@p) != 1
+)
+ )
+ goto L;
+
+
+// These are void but here for completeness
+@openssl_void@
+identifier FUNCVOID =~ "^(AES_cfb128_encrypt|AES_cfb8_encrypt|AES_ige_encrypt|BN_GENCB_set|DSA_get0_key|DSA_get0_pqg|EC_GROUP_set_asn1_flag|EC_GROUP_set_point_conversion_form|ENGINE_get_static_state|ENGINE_unregister_DH|ENGINE_unregister_DSA|ENGINE_unregister_EC|ENGINE_unregister_RAND|ENGINE_unregister_RSA|ENGINE_unregister_ciphers|ENGINE_unregister_digests|ENGINE_unregister_pkey_asn1_meths|ENGINE_unregister_pkey_meths|OpenSSL_add_all_ciphers|OpenSSL_add_all_digests|RAND_seed|RC4|RC4_set_key|RSA_get0_crt_params|RSA_get0_factors|RSA_get0_key)$";
+position p;
+@@
+
+ FUNCVOID(...)@p;
+
+
+// Traditionally, OpenSSL didn't adhere to the semantics of free() calls
+// allowing for NULL. However, they have been changing it over time.
+// Since Erlang allows for unmaintained versions of OpenSSL, be conservative
+// and assume the worst.
+@openssl_free@
+expression X;
+identifier FUNCFREE =~ "^(BN_CTX_free|BN_GENCB_free|BN_clear_free|BN_free|CMAC_CTX_free|CRYPTO_free|DH_free|DSA_free|EC_GROUP_free|EC_KEY_free|EC_POINT_free|EVP_CIPHER_CTX_free|EVP_MD_CTX_free|EVP_PKEY_CTX_free|EVP_PKEY_free|HMAC_CTX_free|RSA_free|RSA_meth_free)$";
+position p;
+@@
+
+ if (
+(
+ X
+|
+ X != NULL
+)
+ )
+ FUNCFREE(X)@p;
+
+
+// NOTE: Keep these in sync with the above definitions!
+//
+// Find all of the cases that we haven't marked safe positions of.
+//
+// This will flag a few false positives because the code isn't using the
+// standard pattern.
+//
+// NOTE: You have to copy the regexps because there doesn't appear to be a way in
+// coccinelle to reference a regexp identifier from another rule properly.
+@openssl_check_NOT_SAFE@
+
+identifier FUNCNEG =~ "^(DH_compute_key|RSA_padding_check_SSLv23)$";
+position pneg != openssl_check_negative.p;
+
+identifier FUNCPOS =~ "^(ECDH_compute_key|EVP_CIPHER_asn1_to_param|EVP_CIPHER_param_to_asn1|EVP_PKEY_CTX_ctrl|RSA_pkey_ctx_ctrl)$";
+position ppos != openssl_check_positive.p;
+
+identifier FUNC0 =~ "^(AES_set_decrypt_key|AES_set_encrypt_key|CRYPTO_gcm128_aad|CRYPTO_gcm128_decrypt|CRYPTO_gcm128_finish)$";
+position p0 != openssl_check_0.p;
+
+identifier FUNCNULL =~ "^(BN_CTX_new|BN_GENCB_new|BN_MONT_CTX_new|BN_bin2bn|BN_dup|BN_generate_prime|BN_new|CMAC_CTX_new|CRYPTO_clear_realloc|CRYPTO_gcm128_new|CRYPTO_malloc|CRYPTO_realloc|CRYPTO_zalloc|DH_generate_parameters|DH_new|DSA_new|EC_GROUP_dup|EC_GROUP_get0_generator|EC_GROUP_method_of|EC_GROUP_new_curve_GFm|EC_GROUP_new_curve_GFp|EC_KEY_copy|EC_KEY_dup|EC_KEY_get0_engine|EC_KEY_new|EC_KEY_new_by_curve_name|EC_POINT_bn2point|EC_POINT_dup|EC_POINT_new|EC_POINT_point2bn|ENGINE_by_id|ENGINE_get_cipher_engine|ENGINE_get_default_DH|ENGINE_get_default_DSA|ENGINE_get_default_RAND|ENGINE_get_default_RSA|ENGINE_get_digest_engine|ENGINE_get_first|ENGINE_get_id|ENGINE_get_last|ENGINE_get_name|ENGINE_get_next|ENGINE_get_prev|ENGINE_load_private_key|ENGINE_load_public_key|ENGINE_new|EVP_CIPHER_CTX_new|EVP_MAC_CTX_new|EVP_MAC_CTX_new_id|EVP_MD_CTX_new|EVP_MD_meth_new|EVP_PKEY_CTX_new|EVP_PKEY_CTX_new_id|EVP_PKEY_get1_DH|EVP_PKEY_get1_DSA|EVP_PKEY_get1_EC_KEY|EVP_PKEY_get1_RSA|EVP_PKEY_new|EVP_PKEY_new_raw_private_key|EVP_PKEY_new_raw_public_key|EVP_get_cipherbyname|EVP_get_cipherbynid|EVP_get_cipherbyobj|EVP_get_macbyname|EVP_get_macbynid|EVP_get_macbyobj|HMAC|HMAC_CTX_new|OPENSSL_buf2hexstr|OPENSSL_clear_realloc|OPENSSL_hexstr2buf|OPENSSL_malloc|OPENSSL_realloc|OPENSSL_strdup|OPENSSL_strndup|OPENSSL_zalloc|RSA_meth_dup|RSA_meth_new|RSA_new)$";
+position pnull != openssl_check_null.p;
+
+identifier FUNCNOT =~ "^(BN_add|BN_div|BN_exp|BN_from_montgomery|BN_gcd|BN_generate_prime_ex|BN_mod|BN_mod_add|BN_mod_exp|BN_mod_mul|BN_mod_mul_montgomery|BN_mod_sqr|BN_mod_sub|BN_mul|BN_nnmod|BN_priv_rand|BN_priv_rand_range|BN_pseudo_rand|BN_pseudo_rand_range|BN_rand|BN_rand_range|BN_set_bit|BN_set_word|BN_sqr|BN_sub|BN_to_montgomery|CMAC_Final|CMAC_Init|CMAC_Update|CRYPTO_set_mem_debug|CRYPTO_set_mem_functions|DH_check|DH_check_ex|DH_check_params|DH_check_pub_key_ex|DH_generate_key|DH_generate_parameters_ex|DH_set0_key|DH_set0_pqg|DH_set_length|DSA_set0_key|DSA_set0_pqg|EC_GROUP_check|EC_GROUP_check_discriminant|EC_GROUP_copy|EC_GROUP_get_curve_name|EC_GROUP_get_pentanomial_basis|EC_GROUP_get_trinomial_basis|EC_GROUP_precompute_mult|EC_GROUP_set_generator|EC_GROUP_set_seed|EC_KEY_check_key|EC_KEY_generate_key|EC_KEY_key2buf|EC_KEY_oct2key|EC_KEY_oct2priv|EC_KEY_precompute_mult|EC_KEY_priv2buf|EC_KEY_priv2oct|EC_KEY_set_group|EC_KEY_set_private_key|EC_KEY_set_public_key|EC_KEY_set_public_key_affine_coordinates|EC_KEY_up_ref|EC_POINT_add|EC_POINT_copy|EC_POINT_dbl|EC_POINT_get_Jprojective_coordinates_GFp|EC_POINT_get_affine_coordinates_GF2m|EC_POINT_get_affine_coordinates_GFp|EC_POINT_invert|EC_POINT_make_affine|EC_POINT_mul|EC_POINT_oct2point|EC_POINT_point2oct|EC_POINT_set_Jprojective_coordinates_GFp|EC_POINT_set_affine_coordinates_GF2m|EC_POINT_set_affine_coordinates_GFp|EC_POINT_set_compressed_coordinates_GF2m|EC_POINT_set_compressed_coordinates_GFp|EC_POINT_set_to_infinity|EC_POINTs_make_affine|EC_POINTs_mul|ENGINE_add|ENGINE_ctrl_cmd|ENGINE_ctrl_cmd_string|ENGINE_finish|ENGINE_free|ENGINE_init|ENGINE_register_DH|ENGINE_register_DSA|ENGINE_register_EC|ENGINE_register_RAND|ENGINE_register_RSA|ENGINE_register_all_complete|ENGINE_register_ciphers|ENGINE_register_complete|ENGINE_register_digests|ENGINE_register_pkey_asn1_meths|ENGINE_register_pkey_meths|ENGINE_remove|ENGINE_set_RSA|ENGINE_set_default|ENGINE_set_default_DH|ENGINE_set_default_DSA|ENGINE_set_default_EC|ENGINE_set_default_RAND|ENGINE_set_default_RSA|ENGINE_set_digests|ENGINE_set_id|ENGINE_set_init_function|ENGINE_set_load_privkey_function|ENGINE_set_load_pubkey_function|ENGINE_set_name|ENGINE_up_ref|HMAC_CTX_copy|HMAC_CTX_reset|HMAC_Final|HMAC_Init_ex|HMAC_Update|MD2_Init|MD2_Update|MD2_Final|MD4_Init|MD4_Update|MD4_Final|MD5_Init|MD5_Update|MD5_Final|OPENSSL_init_crypto|OPENSSL_mem_debug_pop|OPENSSL_mem_debug_push|RSA_generate_key_ex|RSA_generate_multi_prime_key|RSA_meth_set_finish|RSA_meth_set_sign|RSA_meth_set_verify|RSA_padding_add_SSLv23|RSA_set0_crt_params|RSA_set0_factors|RSA_set0_key|RSA_set0_multi_prime_params)$";
+position pnot != openssl_check_not.p;
+
+identifier FUNC1 =~ "^(EVP_CIPHER_CTX_copy|EVP_CIPHER_CTX_ctrl|EVP_CIPHER_CTX_rand_key|EVP_CIPHER_CTX_reset|EVP_CIPHER_CTX_set_key_length|EVP_CIPHER_CTX_set_padding|EVP_CipherFinal_ex|EVP_CipherInit_ex|EVP_CipherUpdate|EVP_DecryptFinal_ex|EVP_DecryptInit_ex|EVP_DecryptUpdate|EVP_Digest|EVP_DigestFinal|EVP_DigestFinal_ex|EVP_DigestInit|EVP_DigestInit_ex|EVP_DigestSign|EVP_DigestSignInit|EVP_DigestSignUpdate|EVP_DigestSignaFinal|EVP_DigestUpdate|EVP_DigestVerify|EVP_DigestVerifyInit|EVP_EncryptFinal_ex|EVP_EncryptInit_ex|EVP_EncryptUpdate|EVP_MAC_CTX_copy|EVP_MAC_ctrl|EVP_MAC_ctrl_str|EVP_MAC_hex2ctrl|EVP_MAC_init|EVP_MAC_reset|EVP_MAC_str2ctrl|EVP_MAC_update|EVP_MD_CTX_copy|EVP_MD_CTX_copy_ex|EVP_MD_CTX_ctrl|EVP_MD_meth_set_app_datasize|EVP_MD_meth_set_cleanup|EVP_MD_meth_set_copy|EVP_MD_meth_set_ctrl|EVP_MD_meth_set_final|EVP_MD_meth_set_flags|EVP_MD_meth_set_init|EVP_MD_meth_set_input_blocksize|EVP_MD_meth_set_result_size|EVP_MD_meth_set_update|EVP_PKEY_CTX_set_rsa_mgf1_md|EVP_PKEY_CTX_set_rsa_padding|EVP_PKEY_CTX_set_rsa_pss_saltlen|EVP_PKEY_CTX_set_signature|EVP_PKEY_assign|EVP_PKEY_assign_DSA|EVP_PKEY_assign_EC_KEY|EVP_PKEY_assign_RSA|EVP_PKEY_decrypt|EVP_PKEY_decrypt_init|EVP_PKEY_derive|EVP_PKEY_derive_init|EVP_PKEY_derive_set_peer|EVP_PKEY_encrypt|EVP_PKEY_encrypt_init|EVP_PKEY_get1_DH|EVP_PKEY_get_raw_private_key|EVP_PKEY_get_raw_public_key|EVP_PKEY_keygen|EVP_PKEY_keygen_init|EVP_PKEY_set1_DH|EVP_PKEY_sign|EVP_PKEY_sign_init|EVP_PKEY_verify|EVP_PKEY_verify_init|EVP_PKEY_verify_recover|EVP_PKEY_verify_recover_init|EVP_add_mac|RAND_bytes|RAND_priv_bytes)$";
+position p1 != openssl_check_1.p;
+
+identifier FUNCVOID =~ "^(AES_cfb128_encrypt|AES_cfb8_encrypt|AES_ige_encrypt|BN_GENCB_set|DSA_get0_key|DSA_get0_pqg|EC_GROUP_set_asn1_flag|EC_GROUP_set_point_conversion_form|ENGINE_get_static_state|ENGINE_unregister_DH|ENGINE_unregister_DSA|ENGINE_unregister_EC|ENGINE_unregister_RAND|ENGINE_unregister_RSA|ENGINE_unregister_ciphers|ENGINE_unregister_digests|ENGINE_unregister_pkey_asn1_meths|ENGINE_unregister_pkey_meths|OpenSSL_add_all_ciphers|OpenSSL_add_all_digests|RAND_seed|RC4|RC4_set_key|RSA_get0_crt_params|RSA_get0_factors|RSA_get0_key)$";
+position pvoid != openssl_void.p;
+
+identifier FUNCFREE =~ "^(BN_CTX_free|BN_GENCB_free|BN_clear_free|BN_free|CMAC_CTX_free|CRYPTO_free|DH_free|DSA_free|EC_GROUP_free|EC_KEY_free|EC_POINT_free|EVP_CIPHER_CTX_free|EVP_MD_CTX_free|EVP_PKEY_CTX_free|EVP_PKEY_free|HMAC_CTX_free|RSA_free|RSA_meth_free)$";
+position pfree != openssl_free.p;
+@@
+
+(
+* FUNCNEG(...)@pneg
+|
+* FUNCPOS(...)@ppos
+|
+* FUNCNULL(...)@pnull
+|
+* FUNC0(...)@p0
+|
+* FUNC1(...)@p1
+|
+* FUNCNOT(...)@pnot
+|
+* FUNCVOID(...)@pvoid
+|
+* FUNCFREE(...)@pfree
+)
diff --git a/lib/crypto/c_src/cipher.c b/lib/crypto/c_src/cipher.c
new file mode 100644
index 0000000000..00072af632
--- /dev/null
+++ b/lib/crypto/c_src/cipher.c
@@ -0,0 +1,344 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "cipher.h"
+
+#ifdef HAVE_DES
+#define COND_NO_DES_PTR(Ptr) (Ptr)
+#else
+#define COND_NO_DES_PTR(Ptr) (NULL)
+#endif
+
+static struct cipher_type_t cipher_types[] =
+{
+#ifdef HAVE_RC2
+ {{"rc2_cbc"}, {&EVP_rc2_cbc}, 0, NO_FIPS_CIPHER},
+#else
+ {{"rc2_cbc"}, {NULL}, 0, NO_FIPS_CIPHER},
+#endif
+#ifdef HAVE_RC4
+ {{"rc4"}, {&EVP_rc4}, 0, NO_FIPS_CIPHER},
+#else
+ {{"rc4"}, {NULL}, 0, NO_FIPS_CIPHER},
+#endif
+ {{"des_cbc"}, {COND_NO_DES_PTR(&EVP_des_cbc)}, 0, NO_FIPS_CIPHER},
+ {{"des_cfb"}, {COND_NO_DES_PTR(&EVP_des_cfb8)}, 0, NO_FIPS_CIPHER},
+ {{"des_ecb"}, {COND_NO_DES_PTR(&EVP_des_ecb)}, 0, NO_FIPS_CIPHER | ECB_BUG_0_9_8L},
+
+ {{"des_ede3_cbc"}, {COND_NO_DES_PTR(&EVP_des_ede3_cbc)}, 0, 0},
+
+#ifdef HAVE_DES_ede3_cfb_encrypt
+ {{"des_ede3_cfb"}, {COND_NO_DES_PTR(&EVP_des_ede3_cfb8)}, 0, 0},
+#else
+ {{"des_ede3_cfb"}, {NULL}, 0, 0},
+#endif
+
+#ifdef HAVE_BF
+ {{"blowfish_cbc"}, {&EVP_bf_cbc}, 0, NO_FIPS_CIPHER},
+ {{"blowfish_cfb64"}, {&EVP_bf_cfb64}, 0, NO_FIPS_CIPHER},
+ {{"blowfish_ofb64"}, {&EVP_bf_ofb}, 0, NO_FIPS_CIPHER},
+ {{"blowfish_ecb"}, {&EVP_bf_ecb}, 0, NO_FIPS_CIPHER | ECB_BUG_0_9_8L},
+#else
+ {{"blowfish_cbc"}, {NULL}, 0, 0},
+ {{"blowfish_cfb64"}, {NULL}, 0, 0},
+ {{"blowfish_ofb64"}, {NULL}, 0, 0},
+ {{"blowfish_ecb"}, {NULL}, 0, 0},
+#endif
+
+ {{"aes_128_cbc"}, {&EVP_aes_128_cbc}, 16, 0},
+ {{"aes_192_cbc"}, {&EVP_aes_192_cbc}, 24, 0},
+ {{"aes_256_cbc"}, {&EVP_aes_256_cbc}, 32, 0},
+
+ {{"aes_128_cfb8"}, {&EVP_aes_128_cfb8}, 16, NO_FIPS_CIPHER | AES_CFBx},
+ {{"aes_192_cfb8"}, {&EVP_aes_192_cfb8}, 24, NO_FIPS_CIPHER | AES_CFBx},
+ {{"aes_256_cfb8"}, {&EVP_aes_256_cfb8}, 32, NO_FIPS_CIPHER | AES_CFBx},
+
+ {{"aes_128_cfb128"}, {&EVP_aes_128_cfb128}, 16, NO_FIPS_CIPHER | AES_CFBx},
+ {{"aes_192_cfb128"}, {&EVP_aes_192_cfb128}, 24, NO_FIPS_CIPHER | AES_CFBx},
+ {{"aes_256_cfb128"}, {&EVP_aes_256_cfb128}, 32, NO_FIPS_CIPHER | AES_CFBx},
+
+ {{"aes_128_ecb"}, {&EVP_aes_128_ecb}, 16, ECB_BUG_0_9_8L},
+ {{"aes_192_ecb"}, {&EVP_aes_192_ecb}, 24, ECB_BUG_0_9_8L},
+ {{"aes_256_ecb"}, {&EVP_aes_256_ecb}, 32, ECB_BUG_0_9_8L},
+
+#if defined(HAVE_EVP_AES_CTR)
+ {{"aes_128_ctr"}, {&EVP_aes_128_ctr}, 16, 0},
+ {{"aes_192_ctr"}, {&EVP_aes_192_ctr}, 24, 0},
+ {{"aes_256_ctr"}, {&EVP_aes_256_ctr}, 32, 0},
+#else
+ {{"aes_128_ctr"}, {NULL}, 16, AES_CTR_COMPAT},
+ {{"aes_192_ctr"}, {NULL}, 24, AES_CTR_COMPAT},
+ {{"aes_256_ctr"}, {NULL}, 32, AES_CTR_COMPAT},
+#endif
+
+#if defined(HAVE_CHACHA20)
+ {{"chacha20"}, {&EVP_chacha20}, 32, NO_FIPS_CIPHER},
+#else
+ {{"chacha20"}, {NULL}, 0, NO_FIPS_CIPHER},
+#endif
+
+ /*==== AEAD ciphers ====*/
+#if defined(HAVE_CHACHA20_POLY1305)
+ {{"chacha20_poly1305"}, {&EVP_chacha20_poly1305}, 0, NO_FIPS_CIPHER | AEAD_CIPHER, {{EVP_CTRL_AEAD_SET_IVLEN,EVP_CTRL_AEAD_GET_TAG,EVP_CTRL_AEAD_SET_TAG}}},
+#else
+ {{"chacha20_poly1305"}, {NULL}, 0, NO_FIPS_CIPHER | AEAD_CIPHER, {{0,0,0}}},
+#endif
+
+#if defined(HAVE_GCM)
+ {{"aes_128_gcm"}, {&EVP_aes_128_gcm}, 16, AEAD_CIPHER|GCM_MODE, {{EVP_CTRL_GCM_SET_IVLEN,EVP_CTRL_GCM_GET_TAG,EVP_CTRL_GCM_SET_TAG}}},
+ {{"aes_192_gcm"}, {&EVP_aes_192_gcm}, 24, AEAD_CIPHER|GCM_MODE, {{EVP_CTRL_GCM_SET_IVLEN,EVP_CTRL_GCM_GET_TAG,EVP_CTRL_GCM_SET_TAG}}},
+ {{"aes_256_gcm"}, {&EVP_aes_256_gcm}, 32, AEAD_CIPHER|GCM_MODE, {{EVP_CTRL_GCM_SET_IVLEN,EVP_CTRL_GCM_GET_TAG,EVP_CTRL_GCM_SET_TAG}}},
+#else
+ {{"aes_128_gcm"}, {NULL}, 16, AEAD_CIPHER|GCM_MODE, {{0,0,0}}},
+ {{"aes_192_gcm"}, {NULL}, 24, AEAD_CIPHER|GCM_MODE, {{0,0,0}}},
+ {{"aes_256_gcm"}, {NULL}, 32, AEAD_CIPHER|GCM_MODE, {{0,0,0}}},
+#endif
+
+#if defined(HAVE_CCM)
+ {{"aes_128_ccm"}, {&EVP_aes_128_ccm}, 16, AEAD_CIPHER|CCM_MODE, {{EVP_CTRL_CCM_SET_IVLEN,EVP_CTRL_CCM_GET_TAG,EVP_CTRL_CCM_SET_TAG}}},
+ {{"aes_192_ccm"}, {&EVP_aes_192_ccm}, 24, AEAD_CIPHER|CCM_MODE, {{EVP_CTRL_CCM_SET_IVLEN,EVP_CTRL_CCM_GET_TAG,EVP_CTRL_CCM_SET_TAG}}},
+ {{"aes_256_ccm"}, {&EVP_aes_256_ccm}, 32, AEAD_CIPHER|CCM_MODE, {{EVP_CTRL_CCM_SET_IVLEN,EVP_CTRL_CCM_GET_TAG,EVP_CTRL_CCM_SET_TAG}}},
+#else
+ {{"aes_128_ccm"}, {NULL}, 16, AEAD_CIPHER|CCM_MODE, {{0,0,0}}},
+ {{"aes_192_ccm"}, {NULL}, 24, AEAD_CIPHER|CCM_MODE, {{0,0,0}}},
+ {{"aes_256_ccm"}, {NULL}, 32, AEAD_CIPHER|CCM_MODE, {{0,0,0}}},
+#endif
+
+ /*==== Specialy handled ciphers, only for inclusion in algorithm's list ====*/
+#ifdef HAVE_AES_IGE
+ {{"aes_ige256"}, {NULL}, 0, NO_FIPS_CIPHER | NON_EVP_CIPHER},
+#endif
+
+ /*==== End of list ==== */
+
+ {{NULL},{NULL},0,0}
+};
+
+ErlNifResourceType* evp_cipher_ctx_rtype;
+
+static size_t num_cipher_types = 0;
+
+static void evp_cipher_ctx_dtor(ErlNifEnv* env, struct evp_cipher_ctx* ctx) {
+ if (ctx == NULL)
+ return;
+
+ if (ctx->ctx)
+ EVP_CIPHER_CTX_free(ctx->ctx);
+
+#if !defined(HAVE_EVP_AES_CTR)
+ if (ctx->env)
+ enif_free_env(ctx->env);
+#endif
+}
+
+int init_cipher_ctx(ErlNifEnv *env) {
+ evp_cipher_ctx_rtype = enif_open_resource_type(env, NULL, "EVP_CIPHER_CTX",
+ (ErlNifResourceDtor*) evp_cipher_ctx_dtor,
+ ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER,
+ NULL);
+ if (evp_cipher_ctx_rtype == NULL)
+ goto err;
+
+ return 1;
+
+ err:
+ PRINTF_ERR0("CRYPTO: Could not open resource type 'EVP_CIPHER_CTX'");
+ return 0;
+}
+
+void init_cipher_types(ErlNifEnv* env)
+{
+ struct cipher_type_t* p = cipher_types;
+
+ num_cipher_types = 0;
+ for (p = cipher_types; p->type.str; p++) {
+ num_cipher_types++;
+ p->type.atom = enif_make_atom(env, p->type.str);
+ if (p->cipher.funcp)
+ p->cipher.p = p->cipher.funcp();
+ }
+ p->type.atom = atom_false; /* end marker */
+
+ qsort(cipher_types, num_cipher_types, sizeof(cipher_types[0]), cmp_cipher_types);
+}
+
+const struct cipher_type_t* get_cipher_type(ERL_NIF_TERM type, size_t key_len)
+{
+ struct cipher_type_t key;
+
+ key.type.atom = type;
+ key.key_len = key_len;
+
+ return bsearch(&key, cipher_types, num_cipher_types, sizeof(cipher_types[0]), cmp_cipher_types);
+}
+
+
+int cmp_cipher_types(const void *keyp, const void *elemp) {
+ const struct cipher_type_t *key = keyp;
+ const struct cipher_type_t *elem = elemp;
+
+ if (key->type.atom < elem->type.atom) return -1;
+ else if (key->type.atom > elem->type.atom) return 1;
+ else /* key->type.atom == elem->type.atom */
+ if (!elem->key_len || key->key_len == elem->key_len) return 0;
+ else if (key->key_len < elem->key_len) return -1;
+ else return 1;
+}
+
+
+ERL_NIF_TERM cipher_info_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Type) */
+ const struct cipher_type_t *cipherp;
+ const EVP_CIPHER *cipher;
+ ERL_NIF_TERM ret, ret_mode;
+ unsigned type;
+ unsigned long mode;
+
+ if ((cipherp = get_cipher_type_no_key(argv[0])) == NULL)
+ return enif_make_badarg(env);
+
+ if (FORBIDDEN_IN_FIPS(cipherp))
+ return enif_raise_exception(env, atom_notsup);
+ if ((cipher = cipherp->cipher.p) == NULL)
+ return enif_raise_exception(env, atom_notsup);
+
+ ret = enif_make_new_map(env);
+
+ type = EVP_CIPHER_type(cipher);
+ enif_make_map_put(env, ret, atom_type,
+ type == NID_undef ? atom_undefined : enif_make_int(env, type),
+ &ret);
+
+ enif_make_map_put(env, ret, atom_key_length,
+ enif_make_int(env, EVP_CIPHER_key_length(cipher)), &ret);
+ enif_make_map_put(env, ret, atom_iv_length,
+ enif_make_int(env, EVP_CIPHER_iv_length(cipher)), &ret);
+ enif_make_map_put(env, ret, atom_block_size,
+ enif_make_int(env, EVP_CIPHER_block_size(cipher)), &ret);
+
+ mode = EVP_CIPHER_mode(cipher);
+ switch (mode) {
+ case EVP_CIPH_ECB_MODE:
+ ret_mode = atom_ecb_mode;
+ break;
+
+ case EVP_CIPH_CBC_MODE:
+ ret_mode = atom_cbc_mode;
+ break;
+
+ case EVP_CIPH_CFB_MODE:
+ ret_mode = atom_cfb_mode;
+ break;
+
+ case EVP_CIPH_OFB_MODE:
+ ret_mode = atom_ofb_mode;
+ break;
+
+#ifdef EVP_CIPH_CTR_MODE
+ case EVP_CIPH_CTR_MODE:
+ ret_mode = atom_ctr_mode;
+ break;
+#endif
+
+#ifdef EVP_CIPH_GCM_MODE
+ case EVP_CIPH_GCM_MODE:
+ ret_mode = atom_gcm_mode;
+ break;
+#endif
+
+#ifdef EVP_CIPH_CCM_MODE
+ case EVP_CIPH_CCM_MODE:
+ ret_mode = atom_ccm_mode;
+ break;
+#endif
+
+#ifdef EVP_CIPH_XTS_MODE
+ case EVP_CIPH_XTS_MODE:
+ ret_mode = atom_xts_mode;
+ break;
+#endif
+
+#ifdef EVP_CIPH_WRAP_MODE
+ case EVP_CIPH_WRAP_MODE:
+ ret_mode = atom_wrap_mode;
+ break;
+#endif
+
+#ifdef EVP_CIPH_OCB_MODE
+ case EVP_CIPH_OCB_MODE:
+ ret_mode = atom_ocb_mode;
+ break;
+#endif
+
+ case EVP_CIPH_STREAM_CIPHER:
+ ret_mode = atom_stream_cipher;
+ break;
+
+ default:
+ ret_mode = atom_undefined;
+ break;
+ }
+
+ enif_make_map_put(env, ret, atom_mode, ret_mode, &ret);
+
+ return ret;
+}
+
+const struct cipher_type_t* get_cipher_type_no_key(ERL_NIF_TERM type)
+{
+ struct cipher_type_t key;
+
+ key.type.atom = type;
+
+ return bsearch(&key, cipher_types, num_cipher_types, sizeof(cipher_types[0]), cmp_cipher_types_no_key);
+}
+
+int cmp_cipher_types_no_key(const void *keyp, const void *elemp) {
+ const struct cipher_type_t *key = keyp;
+ const struct cipher_type_t *elem = elemp;
+
+ if (key->type.atom < elem->type.atom) return -1;
+ else if (key->type.atom > elem->type.atom) return 1;
+ else /* key->type.atom == elem->type.atom */ return 0;
+}
+
+
+ERL_NIF_TERM cipher_types_as_list(ErlNifEnv* env)
+{
+ struct cipher_type_t* p;
+ ERL_NIF_TERM prev, hd;
+
+ hd = enif_make_list(env, 0);
+ prev = atom_undefined;
+
+ for (p = cipher_types; (p->type.atom & (p->type.atom != atom_false)); p++) {
+ if ((prev == p->type.atom) ||
+ FORBIDDEN_IN_FIPS(p) )
+ continue;
+
+ if ((p->cipher.p != NULL) ||
+ (p->type.atom == atom_aes_ige256)) /* Special handling. Bad indeed... */
+ {
+ hd = enif_make_list_cell(env, p->type.atom, hd);
+ }
+ }
+
+ return hd;
+}
diff --git a/lib/crypto/c_src/cipher.h b/lib/crypto/c_src/cipher.h
new file mode 100644
index 0000000000..0e51c410eb
--- /dev/null
+++ b/lib/crypto/c_src/cipher.h
@@ -0,0 +1,84 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_CIPHER_H__
+#define E_CIPHER_H__ 1
+
+#include "common.h"
+
+struct cipher_type_t {
+ union {
+ const char* str; /* before init */
+ ERL_NIF_TERM atom; /* after init */
+ }type;
+ union {
+ const EVP_CIPHER* (*funcp)(void); /* before init, NULL if notsup */
+ const EVP_CIPHER* p; /* after init, NULL if notsup */
+ }cipher;
+ size_t key_len; /* != 0 to also match on key_len */
+ unsigned flags;
+ union {
+ struct aead_ctrl {int ctx_ctrl_set_ivlen, ctx_ctrl_get_tag, ctx_ctrl_set_tag;} aead;
+ } extra;
+};
+
+/* masks in the flags field if cipher_type_t */
+#define NO_FIPS_CIPHER 1
+#define AES_CFBx 2
+#define ECB_BUG_0_9_8L 4
+#define AEAD_CIPHER 8
+#define NON_EVP_CIPHER 16
+#define AES_CTR_COMPAT 32
+#define CCM_MODE 64
+#define GCM_MODE 128
+
+
+#ifdef FIPS_SUPPORT
+/* May have FIPS support, must check dynamically if it is enabled */
+# define FORBIDDEN_IN_FIPS(P) (((P)->flags & NO_FIPS_CIPHER) && FIPS_mode())
+#else
+/* No FIPS support since the symbol FIPS_SUPPORT is undefined */
+# define FORBIDDEN_IN_FIPS(P) 0
+#endif
+
+extern ErlNifResourceType* evp_cipher_ctx_rtype;
+struct evp_cipher_ctx {
+ EVP_CIPHER_CTX* ctx;
+ int iv_len;
+#if !defined(HAVE_EVP_AES_CTR)
+ ErlNifEnv* env;
+ ERL_NIF_TERM state;
+#endif
+};
+
+ERL_NIF_TERM cipher_info_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+int init_cipher_ctx(ErlNifEnv *env);
+
+void init_cipher_types(ErlNifEnv* env);
+const struct cipher_type_t* get_cipher_type_no_key(ERL_NIF_TERM type);
+const struct cipher_type_t* get_cipher_type(ERL_NIF_TERM type, size_t key_len);
+
+int cmp_cipher_types(const void *keyp, const void *elemp);
+int cmp_cipher_types_no_key(const void *keyp, const void *elemp);
+
+ERL_NIF_TERM cipher_types_as_list(ErlNifEnv* env);
+
+#endif /* E_CIPHER_H__ */
diff --git a/lib/crypto/c_src/cmac.c b/lib/crypto/c_src/cmac.c
new file mode 100644
index 0000000000..49e67ccf29
--- /dev/null
+++ b/lib/crypto/c_src/cmac.c
@@ -0,0 +1,88 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "cmac.h"
+#include "cipher.h"
+
+ERL_NIF_TERM cmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Type, Key, Data) */
+#if defined(HAVE_CMAC)
+ const struct cipher_type_t *cipherp;
+ const EVP_CIPHER *cipher;
+ CMAC_CTX *ctx = NULL;
+ ErlNifBinary key;
+ ErlNifBinary data;
+ ERL_NIF_TERM ret;
+ size_t ret_size;
+ unsigned char *outp;
+ int cipher_len;
+
+ ASSERT(argc == 3);
+
+ if (!enif_inspect_iolist_as_binary(env, argv[1], &key))
+ goto bad_arg;
+ if ((cipherp = get_cipher_type(argv[0], key.size)) == NULL)
+ goto bad_arg;
+ if (cipherp->flags & (NON_EVP_CIPHER | AEAD_CIPHER))
+ goto bad_arg;
+ if (!enif_inspect_iolist_as_binary(env, argv[2], &data))
+ goto bad_arg;
+
+ if (FORBIDDEN_IN_FIPS(cipherp))
+ return enif_raise_exception(env, atom_notsup);
+ if ((cipher = cipherp->cipher.p) == NULL)
+ return enif_raise_exception(env, atom_notsup);
+
+ if ((ctx = CMAC_CTX_new()) == NULL)
+ goto err;
+ if (!CMAC_Init(ctx, key.data, key.size, cipher, NULL))
+ goto err;
+ if (!CMAC_Update(ctx, data.data, data.size))
+ goto err;
+ if ((cipher_len = EVP_CIPHER_block_size(cipher)) < 0)
+ goto err;
+ if ((outp = enif_make_new_binary(env, (size_t)cipher_len, &ret)) == NULL)
+ goto err;
+ if (!CMAC_Final(ctx, outp, &ret_size))
+ goto err;
+
+ ASSERT(ret_size == (unsigned)EVP_CIPHER_block_size(cipher));
+ CONSUME_REDS(env, data);
+ goto done;
+
+ bad_arg:
+ return enif_make_badarg(env);
+
+ err:
+ ret = atom_notsup;
+
+ done:
+ if (ctx)
+ CMAC_CTX_free(ctx);
+ return ret;
+
+#else
+ /* The CMAC functionality was introduced in OpenSSL 1.0.1
+ * Although OTP requires at least version 0.9.8, the versions 0.9.8 and 1.0.0 are
+ * no longer maintained. */
+ return atom_notsup;
+#endif
+}
+
diff --git a/lib/crypto/c_src/cmac.h b/lib/crypto/c_src/cmac.h
new file mode 100644
index 0000000000..14488def58
--- /dev/null
+++ b/lib/crypto/c_src/cmac.h
@@ -0,0 +1,28 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_CMAC_H__
+#define E_CMAC_H__ 1
+
+#include "common.h"
+
+ERL_NIF_TERM cmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+#endif /* E_CMAC_H__ */
diff --git a/lib/crypto/c_src/common.h b/lib/crypto/c_src/common.h
new file mode 100644
index 0000000000..a7e59d5d01
--- /dev/null
+++ b/lib/crypto/c_src/common.h
@@ -0,0 +1,52 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_COMMON_H__
+#define E_COMMON_H__ 1
+
+#ifdef __WIN32__
+# include <windows.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <stdint.h>
+
+#include <erl_nif.h>
+#include "openssl_config.h"
+#include "atoms.h"
+
+
+/* All nif functions return a valid value or throws an exception */
+#define EXCP(Env, Id, Str) enif_raise_exception((Env), \
+ enif_make_tuple3((Env), \
+ (Id), \
+ enif_make_tuple2((Env), \
+ enif_make_string((Env),__FILE__,(ERL_NIF_LATIN1)), \
+ enif_make_int((Env), __LINE__)), \
+ enif_make_string((Env),(Str),(ERL_NIF_LATIN1)) ))
+
+#define EXCP_NOTSUP(Env, Str) EXCP((Env), atom_notsup, (Str))
+#define EXCP_BADARG(Env, Str) EXCP((Env), atom_badarg, (Str))
+#define EXCP_ERROR(Env, Str) EXCP((Env), atom_error, (Str))
+
+#endif /* E_COMMON_H__ */
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 9a3ea07c97..d533cba140 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2010-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,859 +23,116 @@
* Based on OpenSSL.
*/
-#ifdef __WIN32__
- #include <windows.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <erl_nif.h>
-
-#define OPENSSL_THREAD_DEFINES
-#include <openssl/opensslconf.h>
-
-#include <openssl/crypto.h>
-#ifndef OPENSSL_NO_DES
-#include <openssl/des.h>
-#endif /* #ifndef OPENSSL_NO_DES */
-/* #include <openssl/idea.h> This is not supported on the openssl OTP requires */
-#include <openssl/dsa.h>
-#include <openssl/rsa.h>
-#include <openssl/aes.h>
-#include <openssl/md5.h>
-#include <openssl/md4.h>
-#include <openssl/sha.h>
-#include <openssl/ripemd.h>
-#include <openssl/bn.h>
-#include <openssl/objects.h>
-#ifndef OPENSSL_NO_RC4
- #include <openssl/rc4.h>
-#endif /* OPENSSL_NO_RC4 */
-#ifndef OPENSSL_NO_RC2
- #include <openssl/rc2.h>
-#endif
-#include <openssl/blowfish.h>
-#include <openssl/rand.h>
-#include <openssl/evp.h>
-#include <openssl/hmac.h>
-#include <openssl/engine.h>
-#include <openssl/err.h>
-
-/* Helper macro to construct a OPENSSL_VERSION_NUMBER.
- * See openssl/opensslv.h
- */
-#define PACKED_OPENSSL_VERSION(MAJ, MIN, FIX, P) \
- ((((((((MAJ << 8) | MIN) << 8 ) | FIX) << 8) | (P-'a'+1)) << 4) | 0xf)
-
-#define PACKED_OPENSSL_VERSION_PLAIN(MAJ, MIN, FIX) \
- PACKED_OPENSSL_VERSION(MAJ,MIN,FIX,('a'-1))
-
-
-/* LibreSSL was cloned from OpenSSL 1.0.1g and claims to be API and BPI compatible
- * with 1.0.1.
- *
- * LibreSSL has the same names on include files and symbols as OpenSSL, but defines
- * the OPENSSL_VERSION_NUMBER to be >= 2.0.0
- *
- * Therefor works tests like this as intendend:
- * OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0)
- * (The test is for example "2.4.2" >= "1.0.0" although the test
- * with the cloned OpenSSL test would be "1.0.1" >= "1.0.0")
- *
- * But tests like this gives wrong result:
- * OPENSSL_VERSION_NUMBER < PACKED_OPENSSL_VERSION_PLAIN(1,1,0)
- * (The test is false since "2.4.2" < "1.1.0". It should have been
- * true because the LibreSSL API version is "1.0.1")
- *
- */
-
-#ifdef LIBRESSL_VERSION_NUMBER
-/* A macro to test on in this file */
-#define HAS_LIBRESSL
-#endif
-
-#ifdef HAS_LIBRESSL
-/* LibreSSL dislikes FIPS */
-# ifdef FIPS_SUPPORT
-# undef FIPS_SUPPORT
-# endif
-
-/* LibreSSL wants the 1.0.1 API */
-# define NEED_EVP_COMPATIBILITY_FUNCTIONS
-#endif
-
-
-#if OPENSSL_VERSION_NUMBER < PACKED_OPENSSL_VERSION_PLAIN(1,1,0)
-# define NEED_EVP_COMPATIBILITY_FUNCTIONS
-#endif
-
-
-#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0)
-# define HAS_EVP_PKEY_CTX
-#endif
-
-
-#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0)
-#include <openssl/modes.h>
-#endif
-
-#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION(0,9,8,'h')
-#define HAS_ENGINE_SUPPORT
-#endif
-
-#include "crypto_callback.h"
-
-#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(0,9,8) \
- && !defined(OPENSSL_NO_SHA224) && defined(NID_sha224) \
- && !defined(OPENSSL_NO_SHA256) /* disabled like this in my sha.h (?) */
-# define HAVE_SHA224
-#endif
-#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(0,9,8) \
- && !defined(OPENSSL_NO_SHA256) && defined(NID_sha256)
-# define HAVE_SHA256
-#endif
-#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(0,9,8) \
- && !defined(OPENSSL_NO_SHA384) && defined(NID_sha384)\
- && !defined(OPENSSL_NO_SHA512) /* disabled like this in my sha.h (?) */
-# define HAVE_SHA384
-#endif
-#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(0,9,8) \
- && !defined(OPENSSL_NO_SHA512) && defined(NID_sha512)
-# define HAVE_SHA512
-#endif
-#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION(0,9,7,'e')
-# define HAVE_DES_ede3_cfb_encrypt
-#endif
-
-#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION(0,9,8,'o') \
- && !defined(OPENSSL_NO_EC) \
- && !defined(OPENSSL_NO_ECDH) \
- && !defined(OPENSSL_NO_ECDSA)
-# define HAVE_EC
-#endif
-
-#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION(0,9,8,'c')
-# define HAVE_AES_IGE
-#endif
-
-#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,1)
-# define HAVE_EVP_AES_CTR
-# define HAVE_GCM
-# define HAVE_CMAC
-# if OPENSSL_VERSION_NUMBER < PACKED_OPENSSL_VERSION(1,0,1,'d')
-# define HAVE_GCM_EVP_DECRYPT_BUG
-# endif
-#endif
-
-#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,1,0)
-# ifndef HAS_LIBRESSL
-# define HAVE_CHACHA20_POLY1305
-# endif
-#endif
-
-#if OPENSSL_VERSION_NUMBER <= PACKED_OPENSSL_VERSION(0,9,8,'l')
-# define HAVE_ECB_IVEC_BUG
-#endif
-
-#define HAVE_RSA_SSLV23_PADDING
-#if defined(HAS_LIBRESSL) \
- && LIBRESSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(2,6,1)
-# undef HAVE_RSA_SSLV23_PADDING
-#endif
-
-#if defined(HAVE_CMAC)
-#include <openssl/cmac.h>
-#endif
-
-#if defined(HAVE_EC)
-#include <openssl/ec.h>
-#include <openssl/ecdh.h>
-#include <openssl/ecdsa.h>
-#endif
-
-#ifdef VALGRIND
- # include <valgrind/memcheck.h>
-
-/* libcrypto mixes supplied buffer contents into its entropy pool,
- which makes valgrind complain about the use of uninitialized data.
- We use this valgrind "request" to make sure that no such seemingly
- undefined data is returned.
-*/
- # define ERL_VALGRIND_MAKE_MEM_DEFINED(ptr,size) \
- VALGRIND_MAKE_MEM_DEFINED(ptr,size)
-
- # define ERL_VALGRIND_ASSERT_MEM_DEFINED(Ptr,Size) \
- do { \
- int __erl_valgrind_mem_defined = VALGRIND_CHECK_MEM_IS_DEFINED((Ptr),(Size)); \
- if (__erl_valgrind_mem_defined != 0) { \
- fprintf(stderr,"\r\n####### VALGRIND_ASSSERT(%p,%ld) failed at %s:%d\r\n", \
- (Ptr),(long)(Size), __FILE__, __LINE__); \
- abort(); \
- } \
- } while (0)
-
-#else
- # define ERL_VALGRIND_MAKE_MEM_DEFINED(ptr,size)
- # define ERL_VALGRIND_ASSERT_MEM_DEFINED(ptr,size)
-#endif
-
-#ifdef DEBUG
- # define ASSERT(e) \
- ((void) ((e) ? 1 : (fprintf(stderr,"Assert '%s' failed at %s:%d\n",\
- #e, __FILE__, __LINE__), abort(), 0)))
-#else
- # define ASSERT(e) ((void) 1)
-#endif
-
-#ifdef __GNUC__
- # define INLINE __inline__
-#elif defined(__WIN32__)
- # define INLINE __forceinline
-#else
- # define INLINE
-#endif
-
-
-#define get_int32(s) ((((unsigned char*) (s))[0] << 24) | \
- (((unsigned char*) (s))[1] << 16) | \
- (((unsigned char*) (s))[2] << 8) | \
- (((unsigned char*) (s))[3]))
-
-#define put_int32(s,i) \
-{ (s)[0] = (char)(((i) >> 24) & 0xff);\
- (s)[1] = (char)(((i) >> 16) & 0xff);\
- (s)[2] = (char)(((i) >> 8) & 0xff);\
- (s)[3] = (char)((i) & 0xff);\
-}
-
-/* This shall correspond to the similar macro in crypto.erl */
-/* Current value is: erlang:system_info(context_reductions) * 10 */
-#define MAX_BYTES_TO_NIF 20000
-
-#define CONSUME_REDS(NifEnv, Ibin) \
-do { \
- int _cost = ((Ibin).size * 100) / MAX_BYTES_TO_NIF;\
- if (_cost) { \
- (void) enif_consume_timeslice((NifEnv), \
- (_cost > 100) ? 100 : _cost); \
- } \
- } while (0)
-
-
-#ifdef NEED_EVP_COMPATIBILITY_FUNCTIONS
-/*
- * In OpenSSL 1.1.0, most structs are opaque. That means that
- * the structs cannot be allocated as automatic variables on the
- * C stack (because the size is unknown) and that it is necessary
- * to use access functions.
- *
- * For backward compatibility to previous versions of OpenSSL, define
- * on our versions of the new functions defined in 1.1.0 here, so that
- * we don't have to sprinkle ifdefs throughout the code.
- */
-
-static HMAC_CTX *HMAC_CTX_new(void);
-static void HMAC_CTX_free(HMAC_CTX *ctx);
-
-static HMAC_CTX *HMAC_CTX_new()
-{
- HMAC_CTX *ctx = CRYPTO_malloc(sizeof(HMAC_CTX), __FILE__, __LINE__);
- HMAC_CTX_init(ctx);
- return ctx;
-}
-
-static void HMAC_CTX_free(HMAC_CTX *ctx)
-{
- HMAC_CTX_cleanup(ctx);
- CRYPTO_free(ctx);
-}
-
-#define EVP_MD_CTX_new() EVP_MD_CTX_create()
-#define EVP_MD_CTX_free(ctx) EVP_MD_CTX_destroy(ctx)
-
-static INLINE void *BN_GENCB_get_arg(BN_GENCB *cb);
-
-static INLINE void *BN_GENCB_get_arg(BN_GENCB *cb)
-{
- return cb->arg;
-}
-
-static INLINE int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d);
-static INLINE void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d);
-static INLINE int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q);
-static INLINE void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q);
-static INLINE int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp);
-static INLINE void RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp);
-
-static INLINE int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
-{
- r->n = n;
- r->e = e;
- r->d = d;
- return 1;
-}
-
-static INLINE void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
-{
- *n = r->n;
- *e = r->e;
- *d = r->d;
-}
-
-static INLINE int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q)
-{
- r->p = p;
- r->q = q;
- return 1;
-}
-
-static INLINE void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q)
-{
- *p = r->p;
- *q = r->q;
-}
-
-static INLINE int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp)
-{
- r->dmp1 = dmp1;
- r->dmq1 = dmq1;
- r->iqmp = iqmp;
- return 1;
-}
-
-static INLINE void RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp)
-{
- *dmp1 = r->dmp1;
- *dmq1 = r->dmq1;
- *iqmp = r->iqmp;
-}
-
-static INLINE int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key);
-static INLINE int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g);
-static INLINE void DSA_get0_pqg(const DSA *dsa,
- const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
-static INLINE void DSA_get0_key(const DSA *dsa,
- const BIGNUM **pub_key, const BIGNUM **priv_key);
-
-static INLINE int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
-{
- d->pub_key = pub_key;
- d->priv_key = priv_key;
- return 1;
-}
-
-static INLINE int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
-{
- d->p = p;
- d->q = q;
- d->g = g;
- return 1;
-}
-
-static INLINE void
-DSA_get0_pqg(const DSA *dsa, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
-{
- *p = dsa->p;
- *q = dsa->q;
- *g = dsa->g;
-}
-
-static INLINE void
-DSA_get0_key(const DSA *dsa, const BIGNUM **pub_key, const BIGNUM **priv_key)
-{
- if (pub_key) *pub_key = dsa->pub_key;
- if (priv_key) *priv_key = dsa->priv_key;
-}
-
-
-
-static INLINE int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key);
-static INLINE int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g);
-static INLINE int DH_set_length(DH *dh, long length);
-static INLINE void DH_get0_pqg(const DH *dh,
- const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
-static INLINE void DH_get0_key(const DH *dh,
- const BIGNUM **pub_key, const BIGNUM **priv_key);
-
-static INLINE int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
-{
- dh->pub_key = pub_key;
- dh->priv_key = priv_key;
- return 1;
-}
-
-static INLINE int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
-{
- dh->p = p;
- dh->q = q;
- dh->g = g;
- return 1;
-}
-
-static INLINE int DH_set_length(DH *dh, long length)
-{
- dh->length = length;
- return 1;
-}
-
-
-
-static INLINE void
-DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
-{
- *p = dh->p;
- *q = dh->q;
- *g = dh->g;
-}
-
-static INLINE void
-DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key)
-{
- if (pub_key) *pub_key = dh->pub_key;
- if (priv_key) *priv_key = dh->priv_key;
-}
-
-#else /* End of compatibility definitions. */
-
-#define HAVE_OPAQUE_BN_GENCB
-
-#endif
+#include "common.h"
+
+#include "aead.h"
+#include "aes.h"
+#include "algorithms.h"
+#include "api_ng.h"
+#include "bn.h"
+#include "cipher.h"
+#include "cmac.h"
+#include "dh.h"
+#include "digest.h"
+#include "dss.h"
+#include "ec.h"
+#include "ecdh.h"
+#include "eddsa.h"
+#include "engine.h"
+#include "evp.h"
+#include "fips.h"
+#include "hash.h"
+#include "hmac.h"
+#include "info.h"
+#include "math.h"
+#include "pkey.h"
+#include "poly1305.h"
+#include "rand.h"
+#include "rsa.h"
+#include "srp.h"
/* NIF interface declarations */
static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info);
static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info);
static void unload(ErlNifEnv* env, void* priv_data);
-/* The NIFs: */
-static ERL_NIF_TERM info_lib(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM info_fips(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM enable_fips_mode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM hash_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM hash_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM hash_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM hmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM hmac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM hmac_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM hmac_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM cmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM block_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM aes_cfb_8_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM aes_cfb_128_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM aes_ige_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM aes_ctr_stream_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM strong_rand_bytes_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM strong_rand_range_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM do_exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM rc4_set_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM rc4_encrypt_with_state(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM pkey_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM pkey_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM rsa_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM dh_generate_parameters_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM privkey_to_pubkey_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM srp_user_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM srp_host_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-
-static ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-
-static ERL_NIF_TERM rand_seed_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-
-static ERL_NIF_TERM aes_gcm_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM aes_gcm_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-#ifdef HAVE_GCM_EVP_DECRYPT_BUG
-static ERL_NIF_TERM aes_gcm_decrypt_NO_EVP(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-#endif
-
-static ERL_NIF_TERM chacha20_poly1305_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM chacha20_poly1305_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-
-static int get_engine_load_cmd_list(ErlNifEnv* env, const ERL_NIF_TERM term, char **cmds, int i);
-static ERL_NIF_TERM engine_by_id_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM engine_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM engine_finish_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM engine_free_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM engine_load_dynamic_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM engine_ctrl_cmd_strings_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM engine_register_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM engine_unregister_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM engine_add_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM engine_remove_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM engine_get_first_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM engine_get_next_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM engine_get_id_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM engine_get_all_methods_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-
-/* helpers */
-static void init_algorithms_types(ErlNifEnv*);
-static void init_digest_types(ErlNifEnv* env);
-static void init_cipher_types(ErlNifEnv* env);
-#ifdef HAVE_EC
-static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg);
-static int term2point(ErlNifEnv* env, ERL_NIF_TERM term,
- EC_GROUP *group, EC_POINT **pptr);
-#endif
-static ERL_NIF_TERM bin_from_bn(ErlNifEnv* env, const BIGNUM *bn);
-
-#ifdef HAS_ENGINE_SUPPORT
-static int zero_terminate(ErlNifBinary bin, char **buf);
-#endif
-
static int library_refc = 0; /* number of users of this dynamic library */
+static int library_initialized = 0;
static ErlNifFunc nif_funcs[] = {
- {"info_lib", 0, info_lib},
- {"info_fips", 0, info_fips},
- {"enable_fips_mode", 1, enable_fips_mode},
- {"algorithms", 0, algorithms},
- {"hash_nif", 2, hash_nif},
- {"hash_init_nif", 1, hash_init_nif},
- {"hash_update_nif", 2, hash_update_nif},
- {"hash_final_nif", 1, hash_final_nif},
- {"hmac_nif", 3, hmac_nif},
- {"hmac_nif", 4, hmac_nif},
- {"hmac_init_nif", 2, hmac_init_nif},
- {"hmac_update_nif", 2, hmac_update_nif},
- {"hmac_final_nif", 1, hmac_final_nif},
- {"hmac_final_nif", 2, hmac_final_nif},
- {"cmac_nif", 3, cmac_nif},
- {"block_crypt_nif", 5, block_crypt_nif},
- {"block_crypt_nif", 4, block_crypt_nif},
- {"aes_ige_crypt_nif", 4, aes_ige_crypt_nif},
- {"aes_ctr_stream_init", 2, aes_ctr_stream_init},
- {"aes_ctr_stream_encrypt", 2, aes_ctr_stream_encrypt},
- {"aes_ctr_stream_decrypt", 2, aes_ctr_stream_encrypt},
- {"strong_rand_bytes_nif", 1, strong_rand_bytes_nif},
- {"strong_rand_range_nif", 1, strong_rand_range_nif},
- {"rand_uniform_nif", 2, rand_uniform_nif},
- {"mod_exp_nif", 4, mod_exp_nif},
- {"do_exor", 2, do_exor},
- {"rc4_set_key", 1, rc4_set_key},
- {"rc4_encrypt_with_state", 2, rc4_encrypt_with_state},
- {"pkey_sign_nif", 5, pkey_sign_nif},
- {"pkey_verify_nif", 6, pkey_verify_nif},
- {"pkey_crypt_nif", 6, pkey_crypt_nif},
- {"rsa_generate_key_nif", 2, rsa_generate_key_nif},
- {"dh_generate_parameters_nif", 2, dh_generate_parameters_nif},
- {"dh_check", 1, dh_check},
- {"dh_generate_key_nif", 4, dh_generate_key_nif},
- {"dh_compute_key_nif", 3, dh_compute_key_nif},
- {"privkey_to_pubkey_nif", 2, privkey_to_pubkey_nif},
- {"srp_value_B_nif", 5, srp_value_B_nif},
- {"srp_user_secret_nif", 7, srp_user_secret_nif},
- {"srp_host_secret_nif", 5, srp_host_secret_nif},
-
- {"ec_key_generate", 2, ec_key_generate},
- {"ecdh_compute_key_nif", 3, ecdh_compute_key_nif},
-
- {"rand_seed_nif", 1, rand_seed_nif},
-
- {"aes_gcm_encrypt", 5, aes_gcm_encrypt},
- {"aes_gcm_decrypt", 5, aes_gcm_decrypt},
-
- {"chacha20_poly1305_encrypt", 4, chacha20_poly1305_encrypt},
- {"chacha20_poly1305_decrypt", 5, chacha20_poly1305_decrypt},
-
- {"engine_by_id_nif", 1, engine_by_id_nif},
- {"engine_init_nif", 1, engine_init_nif},
- {"engine_finish_nif", 1, engine_finish_nif},
- {"engine_free_nif", 1, engine_free_nif},
- {"engine_load_dynamic_nif", 0, engine_load_dynamic_nif},
- {"engine_ctrl_cmd_strings_nif", 3, engine_ctrl_cmd_strings_nif},
- {"engine_register_nif", 2, engine_register_nif},
- {"engine_unregister_nif", 2, engine_unregister_nif},
- {"engine_add_nif", 1, engine_add_nif},
- {"engine_remove_nif", 1, engine_remove_nif},
- {"engine_get_first_nif", 0, engine_get_first_nif},
- {"engine_get_next_nif", 1, engine_get_next_nif},
- {"engine_get_id_nif", 1, engine_get_id_nif},
- {"engine_get_all_methods_nif", 0, engine_get_all_methods_nif}
-
+ {"info_lib", 0, info_lib, 0},
+ {"info_fips", 0, info_fips, 0},
+ {"enable_fips_mode", 1, enable_fips_mode, 0},
+ {"hash_algorithms", 0, hash_algorithms, 0},
+ {"pubkey_algorithms", 0, pubkey_algorithms, 0},
+ {"cipher_algorithms", 0, cipher_algorithms, 0},
+ {"mac_algorithms", 0, mac_algorithms, 0},
+ {"curve_algorithms", 0, curve_algorithms, 0},
+ {"rsa_opts_algorithms", 0, rsa_opts_algorithms, 0},
+ {"hash_info", 1, hash_info_nif, 0},
+ {"hash_nif", 2, hash_nif, 0},
+ {"hash_init_nif", 1, hash_init_nif, 0},
+ {"hash_update_nif", 2, hash_update_nif, 0},
+ {"hash_final_nif", 1, hash_final_nif, 0},
+ {"hmac_nif", 3, hmac_nif, 0},
+ {"hmac_nif", 4, hmac_nif, 0},
+ {"hmac_init_nif", 2, hmac_init_nif, 0},
+ {"hmac_update_nif", 2, hmac_update_nif, 0},
+ {"hmac_final_nif", 1, hmac_final_nif, 0},
+ {"hmac_final_nif", 2, hmac_final_nif, 0},
+ {"cmac_nif", 3, cmac_nif, 0},
+ {"cipher_info_nif", 1, cipher_info_nif, 0},
+ {"aes_ige_crypt_nif", 4, aes_ige_crypt_nif, 0},
+ {"ng_crypto_init_nif", 4, ng_crypto_init_nif, 0},
+ {"ng_crypto_update_nif", 2, ng_crypto_update_nif, 0},
+ {"ng_crypto_update_nif", 3, ng_crypto_update_nif, 0},
+ {"ng_crypto_one_time_nif", 5, ng_crypto_one_time_nif, 0},
+ {"strong_rand_bytes_nif", 1, strong_rand_bytes_nif, 0},
+ {"strong_rand_range_nif", 1, strong_rand_range_nif, 0},
+ {"rand_uniform_nif", 2, rand_uniform_nif, 0},
+ {"mod_exp_nif", 4, mod_exp_nif, 0},
+ {"do_exor", 2, do_exor, 0},
+ {"pkey_sign_nif", 5, pkey_sign_nif, 0},
+ {"pkey_verify_nif", 6, pkey_verify_nif, 0},
+ {"pkey_crypt_nif", 6, pkey_crypt_nif, 0},
+ {"rsa_generate_key_nif", 2, rsa_generate_key_nif, 0},
+ {"dh_generate_key_nif", 4, dh_generate_key_nif, 0},
+ {"dh_compute_key_nif", 3, dh_compute_key_nif, 0},
+ {"evp_compute_key_nif", 3, evp_compute_key_nif, 0},
+ {"evp_generate_key_nif", 1, evp_generate_key_nif, 0},
+ {"privkey_to_pubkey_nif", 2, privkey_to_pubkey_nif, 0},
+ {"srp_value_B_nif", 5, srp_value_B_nif, 0},
+ {"srp_user_secret_nif", 7, srp_user_secret_nif, 0},
+ {"srp_host_secret_nif", 5, srp_host_secret_nif, 0},
+
+ {"ec_key_generate", 2, ec_key_generate, 0},
+ {"ecdh_compute_key_nif", 3, ecdh_compute_key_nif, 0},
+
+ {"rand_seed_nif", 1, rand_seed_nif, 0},
+
+ {"aead_cipher", 7, aead_cipher, 0},
+
+ {"poly1305_nif", 2, poly1305_nif, 0},
+
+ {"engine_by_id_nif", 1, engine_by_id_nif, 0},
+ {"engine_init_nif", 1, engine_init_nif, 0},
+ {"engine_finish_nif", 1, engine_finish_nif, 0},
+ {"engine_free_nif", 1, engine_free_nif, 0},
+ {"engine_load_dynamic_nif", 0, engine_load_dynamic_nif, 0},
+ {"engine_ctrl_cmd_strings_nif", 3, engine_ctrl_cmd_strings_nif, 0},
+ {"engine_register_nif", 2, engine_register_nif, 0},
+ {"engine_unregister_nif", 2, engine_unregister_nif, 0},
+ {"engine_add_nif", 1, engine_add_nif, 0},
+ {"engine_remove_nif", 1, engine_remove_nif, 0},
+ {"engine_get_first_nif", 0, engine_get_first_nif, 0},
+ {"engine_get_next_nif", 1, engine_get_next_nif, 0},
+ {"engine_get_id_nif", 1, engine_get_id_nif, 0},
+ {"engine_get_name_nif", 1, engine_get_name_nif, 0},
+ {"engine_get_all_methods_nif", 0, engine_get_all_methods_nif, 0}
};
ERL_NIF_INIT(crypto,nif_funcs,load,NULL,upgrade,unload)
-#define MD5_CTX_LEN (sizeof(MD5_CTX))
-#define MD4_CTX_LEN (sizeof(MD4_CTX))
-#define RIPEMD160_CTX_LEN (sizeof(RIPEMD160_CTX))
-
-
-static ERL_NIF_TERM atom_true;
-static ERL_NIF_TERM atom_false;
-static ERL_NIF_TERM atom_sha;
-static ERL_NIF_TERM atom_error;
-static ERL_NIF_TERM atom_rsa_pkcs1_padding;
-static ERL_NIF_TERM atom_rsa_pkcs1_oaep_padding;
-static ERL_NIF_TERM atom_rsa_no_padding;
-static ERL_NIF_TERM atom_signature_md;
-static ERL_NIF_TERM atom_undefined;
-
-static ERL_NIF_TERM atom_ok;
-static ERL_NIF_TERM atom_not_prime;
-static ERL_NIF_TERM atom_not_strong_prime;
-static ERL_NIF_TERM atom_unable_to_check_generator;
-static ERL_NIF_TERM atom_not_suitable_generator;
-static ERL_NIF_TERM atom_check_failed;
-static ERL_NIF_TERM atom_unknown;
-static ERL_NIF_TERM atom_none;
-static ERL_NIF_TERM atom_notsup;
-static ERL_NIF_TERM atom_digest;
-#ifdef FIPS_SUPPORT
-static ERL_NIF_TERM atom_enabled;
-static ERL_NIF_TERM atom_not_enabled;
-#else
-static ERL_NIF_TERM atom_not_supported;
-#endif
-
-#if defined(HAVE_EC)
-static ERL_NIF_TERM atom_ec;
-static ERL_NIF_TERM atom_prime_field;
-static ERL_NIF_TERM atom_characteristic_two_field;
-static ERL_NIF_TERM atom_tpbasis;
-static ERL_NIF_TERM atom_ppbasis;
-static ERL_NIF_TERM atom_onbasis;
-#endif
-
-static ERL_NIF_TERM atom_aes_cfb8;
-static ERL_NIF_TERM atom_aes_cfb128;
-#ifdef HAVE_ECB_IVEC_BUG
-static ERL_NIF_TERM atom_aes_ecb;
-static ERL_NIF_TERM atom_des_ecb;
-static ERL_NIF_TERM atom_blowfish_ecb;
-#endif
-
-static ERL_NIF_TERM atom_rsa;
-static ERL_NIF_TERM atom_dss;
-static ERL_NIF_TERM atom_ecdsa;
-static ERL_NIF_TERM atom_rsa_mgf1_md;
-static ERL_NIF_TERM atom_rsa_oaep_label;
-static ERL_NIF_TERM atom_rsa_oaep_md;
-static ERL_NIF_TERM atom_rsa_pad; /* backwards compatibility */
-static ERL_NIF_TERM atom_rsa_padding;
-static ERL_NIF_TERM atom_rsa_pkcs1_pss_padding;
-#ifdef HAVE_RSA_SSLV23_PADDING
-static ERL_NIF_TERM atom_rsa_sslv23_padding;
-#endif
-static ERL_NIF_TERM atom_rsa_x931_padding;
-static ERL_NIF_TERM atom_rsa_pss_saltlen;
-static ERL_NIF_TERM atom_sha224;
-static ERL_NIF_TERM atom_sha256;
-static ERL_NIF_TERM atom_sha384;
-static ERL_NIF_TERM atom_sha512;
-static ERL_NIF_TERM atom_md5;
-static ERL_NIF_TERM atom_ripemd160;
-
-#ifdef HAS_ENGINE_SUPPORT
-static ERL_NIF_TERM atom_bad_engine_method;
-static ERL_NIF_TERM atom_bad_engine_id;
-static ERL_NIF_TERM atom_ctrl_cmd_failed;
-static ERL_NIF_TERM atom_engine_init_failed;
-static ERL_NIF_TERM atom_register_engine_failed;
-static ERL_NIF_TERM atom_add_engine_failed;
-static ERL_NIF_TERM atom_remove_engine_failed;
-static ERL_NIF_TERM atom_engine_method_not_supported;
-
-static ERL_NIF_TERM atom_engine_method_rsa;
-static ERL_NIF_TERM atom_engine_method_dsa;
-static ERL_NIF_TERM atom_engine_method_dh;
-static ERL_NIF_TERM atom_engine_method_rand;
-static ERL_NIF_TERM atom_engine_method_ecdh;
-static ERL_NIF_TERM atom_engine_method_ecdsa;
-static ERL_NIF_TERM atom_engine_method_ciphers;
-static ERL_NIF_TERM atom_engine_method_digests;
-static ERL_NIF_TERM atom_engine_method_store;
-static ERL_NIF_TERM atom_engine_method_pkey_meths;
-static ERL_NIF_TERM atom_engine_method_pkey_asn1_meths;
-static ERL_NIF_TERM atom_engine_method_ec;
-
-static ERL_NIF_TERM atom_engine;
-static ERL_NIF_TERM atom_key_id;
-static ERL_NIF_TERM atom_password;
-#endif
-
-static ErlNifResourceType* hmac_context_rtype;
-struct hmac_context
-{
- ErlNifMutex* mtx;
- int alive;
- HMAC_CTX* ctx;
-};
-static void hmac_context_dtor(ErlNifEnv* env, struct hmac_context*);
-
-struct digest_type_t {
- union {
- const char* str; /* before init, NULL for end-of-table */
- ERL_NIF_TERM atom; /* after init, 'false' for end-of-table */
- }type;
- union {
- const EVP_MD* (*funcp)(void); /* before init, NULL if notsup */
- const EVP_MD* p; /* after init, NULL if notsup */
- }md;
-};
-
-static struct digest_type_t digest_types[] =
-{
- {{"md4"}, {&EVP_md4}},
- {{"md5"}, {&EVP_md5}},
- {{"ripemd160"}, {&EVP_ripemd160}},
- {{"sha"}, {&EVP_sha1}},
- {{"sha224"},
-#ifdef HAVE_SHA224
- {&EVP_sha224}
-#else
- {NULL}
-#endif
- },
- {{"sha256"},
-#ifdef HAVE_SHA256
- {&EVP_sha256}
-#else
- {NULL}
-#endif
- },
- {{"sha384"},
-#ifdef HAVE_SHA384
- {&EVP_sha384}
-#else
- {NULL}
-#endif
- },
- {{"sha512"},
-#ifdef HAVE_SHA512
- {&EVP_sha512}
-#else
- {NULL}
-#endif
- },
- {{NULL}}
-};
-
-static struct digest_type_t* get_digest_type(ERL_NIF_TERM type);
-
-struct cipher_type_t {
- union {
- const char* str; /* before init */
- ERL_NIF_TERM atom; /* after init */
- }type;
- union {
- const EVP_CIPHER* (*funcp)(void); /* before init, NULL if notsup */
- const EVP_CIPHER* p; /* after init, NULL if notsup */
- }cipher;
- const size_t key_len; /* != 0 to also match on key_len */
-};
-
-#ifdef OPENSSL_NO_DES
-#define COND_NO_DES_PTR(Ptr) (NULL)
-#else
-#define COND_NO_DES_PTR(Ptr) (Ptr)
-#endif
-
-static struct cipher_type_t cipher_types[] =
-{
- {{"rc2_cbc"},
-#ifndef OPENSSL_NO_RC2
- {&EVP_rc2_cbc}
-#else
- {NULL}
-#endif
- },
- {{"des_cbc"}, {COND_NO_DES_PTR(&EVP_des_cbc)}},
- {{"des_cfb"}, {COND_NO_DES_PTR(&EVP_des_cfb8)}},
- {{"des_ecb"}, {COND_NO_DES_PTR(&EVP_des_ecb)}},
- {{"des_ede3_cbc"}, {COND_NO_DES_PTR(&EVP_des_ede3_cbc)}},
- {{"des_ede3_cbf"}, /* Misspelled, retained */
-#ifdef HAVE_DES_ede3_cfb_encrypt
- {COND_NO_DES_PTR(&EVP_des_ede3_cfb8)}
-#else
- {NULL}
-#endif
- },
- {{"des_ede3_cfb"},
-#ifdef HAVE_DES_ede3_cfb_encrypt
- {COND_NO_DES_PTR(&EVP_des_ede3_cfb8)}
-#else
- {NULL}
-#endif
- },
- {{"blowfish_cbc"}, {&EVP_bf_cbc}},
- {{"blowfish_cfb64"}, {&EVP_bf_cfb64}},
- {{"blowfish_ofb64"}, {&EVP_bf_ofb}},
- {{"blowfish_ecb"}, {&EVP_bf_ecb}},
- {{"aes_cbc"}, {&EVP_aes_128_cbc}, 16},
- {{"aes_cbc"}, {&EVP_aes_192_cbc}, 24},
- {{"aes_cbc"}, {&EVP_aes_256_cbc}, 32},
- {{"aes_cbc128"}, {&EVP_aes_128_cbc}},
- {{"aes_cbc256"}, {&EVP_aes_256_cbc}},
- {{"aes_cfb8"}, {&EVP_aes_128_cfb8}},
- {{"aes_cfb128"}, {&EVP_aes_128_cfb128}},
- {{"aes_ecb"}, {&EVP_aes_128_ecb}, 16},
- {{"aes_ecb"}, {&EVP_aes_192_ecb}, 24},
- {{"aes_ecb"}, {&EVP_aes_256_ecb}, 32},
- {{NULL}}
-};
-
-static struct cipher_type_t* get_cipher_type(ERL_NIF_TERM type, size_t key_len);
-
-
-/*
-#define PRINTF_ERR0(FMT) enif_fprintf(stderr, FMT "\n")
-#define PRINTF_ERR1(FMT, A1) enif_fprintf(stderr, FMT "\n", A1)
-#define PRINTF_ERR2(FMT, A1, A2) enif_fprintf(stderr, FMT "\n", A1, A2)
-*/
-
-#define PRINTF_ERR0(FMT)
-#define PRINTF_ERR1(FMT,A1)
-#define PRINTF_ERR2(FMT,A1,A2)
-
-#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0)
-/* Define resource types for OpenSSL context structures. */
-static ErlNifResourceType* evp_md_ctx_rtype;
-struct evp_md_ctx {
- EVP_MD_CTX* ctx;
-};
-static void evp_md_ctx_dtor(ErlNifEnv* env, struct evp_md_ctx *ctx) {
- EVP_MD_CTX_free(ctx->ctx);
-}
-#endif
-
-#ifdef HAVE_EVP_AES_CTR
-static ErlNifResourceType* evp_cipher_ctx_rtype;
-struct evp_cipher_ctx {
- EVP_CIPHER_CTX* ctx;
-};
-static void evp_cipher_ctx_dtor(ErlNifEnv* env, struct evp_cipher_ctx* ctx) {
- EVP_CIPHER_CTX_free(ctx->ctx);
-}
-#endif
-
-// Engine
-#ifdef HAS_ENGINE_SUPPORT
-static ErlNifResourceType* engine_ctx_rtype;
-struct engine_ctx {
- ENGINE *engine;
- char *id;
-};
-static void engine_ctx_dtor(ErlNifEnv* env, struct engine_ctx* ctx) {
- PRINTF_ERR0("engine_ctx_dtor");
- if(ctx->id) {
- PRINTF_ERR1(" non empty ctx->id=%s", ctx->id);
- enif_free(ctx->id);
- } else
- PRINTF_ERR0(" empty ctx->id=NULL");
-}
-#endif
static int verify_lib_version(void)
{
@@ -892,46 +149,6 @@ static int verify_lib_version(void)
return 1;
}
-#ifdef FIPS_SUPPORT
-/* In FIPS mode non-FIPS algorithms are disabled and return badarg. */
-#define CHECK_NO_FIPS_MODE() { if (FIPS_mode()) return atom_notsup; }
-#else
-#define CHECK_NO_FIPS_MODE()
-#endif
-
-#ifdef HAVE_DYNAMIC_CRYPTO_LIB
-
-# if defined(DEBUG)
-static char crypto_callback_name[] = "crypto_callback.debug";
-# elif defined(VALGRIND)
-static char crypto_callback_name[] = "crypto_callback.valgrind";
-# else
-static char crypto_callback_name[] = "crypto_callback";
-# endif
-
-static int change_basename(ErlNifBinary* bin, char* buf, int bufsz, const char* newfile)
-{
- int i;
-
- for (i = bin->size; i > 0; i--) {
- if (bin->data[i-1] == '/')
- break;
- }
- if (i + strlen(newfile) >= bufsz) {
- PRINTF_ERR0("CRYPTO: lib name too long");
- return 0;
- }
- memcpy(buf, bin->data, i);
- strcpy(buf+i, newfile);
- return 1;
-}
-
-static void error_handler(void* null, const char* errstr)
-{
- PRINTF_ERR1("CRYPTO LOADING ERROR: '%s'", errstr);
-}
-#endif /* HAVE_DYNAMIC_CRYPTO_LIB */
-
static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info)
{
#ifdef OPENSSL_THREADS
@@ -945,190 +162,57 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info)
int vernum;
ErlNifBinary lib_bin;
char lib_buf[1000];
+#ifdef HAVE_DYNAMIC_CRYPTO_LIB
+ void *handle;
+#endif
if (!verify_lib_version())
return __LINE__;
/* load_info: {302, <<"/full/path/of/this/library">>,true|false} */
- if (!enif_get_tuple(env, load_info, &tpl_arity, &tpl_array)
- || tpl_arity != 3
- || !enif_get_int(env, tpl_array[0], &vernum)
- || vernum != 302
- || !enif_inspect_binary(env, tpl_array[1], &lib_bin)) {
-
- PRINTF_ERR1("CRYPTO: Invalid load_info '%T'", load_info);
- return __LINE__;
- }
+ if (!enif_get_tuple(env, load_info, &tpl_arity, &tpl_array))
+ return __LINE__;
+ if (tpl_arity != 3)
+ return __LINE__;
+ if (!enif_get_int(env, tpl_array[0], &vernum))
+ return __LINE__;
+ if (vernum != 302)
+ return __LINE__;
+ if (!enif_inspect_binary(env, tpl_array[1], &lib_bin))
+ return __LINE__;
- hmac_context_rtype = enif_open_resource_type(env, NULL, "hmac_context",
- (ErlNifResourceDtor*) hmac_context_dtor,
- ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER,
- NULL);
- if (!hmac_context_rtype) {
- PRINTF_ERR0("CRYPTO: Could not open resource type 'hmac_context'");
+ if (!init_hmac_ctx(env)) {
return __LINE__;
}
-#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0)
- evp_md_ctx_rtype = enif_open_resource_type(env, NULL, "EVP_MD_CTX",
- (ErlNifResourceDtor*) evp_md_ctx_dtor,
- ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER,
- NULL);
- if (!evp_md_ctx_rtype) {
- PRINTF_ERR0("CRYPTO: Could not open resource type 'EVP_MD_CTX'");
+ if (!init_hash_ctx(env)) {
return __LINE__;
}
-#endif
-#ifdef HAVE_EVP_AES_CTR
- evp_cipher_ctx_rtype = enif_open_resource_type(env, NULL, "EVP_CIPHER_CTX",
- (ErlNifResourceDtor*) evp_cipher_ctx_dtor,
- ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER,
- NULL);
- if (!evp_cipher_ctx_rtype) {
- PRINTF_ERR0("CRYPTO: Could not open resource type 'EVP_CIPHER_CTX'");
+ if (!init_cipher_ctx(env)) {
return __LINE__;
}
-#endif
-#ifdef HAS_ENGINE_SUPPORT
- engine_ctx_rtype = enif_open_resource_type(env, NULL, "ENGINE_CTX",
- (ErlNifResourceDtor*) engine_ctx_dtor,
- ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER,
- NULL);
- if (!engine_ctx_rtype) {
- PRINTF_ERR0("CRYPTO: Could not open resource type 'ENGINE_CTX'");
+ if (!init_engine_ctx(env)) {
return __LINE__;
}
- if (library_refc > 0) {
+ if (library_initialized) {
/* Repeated loading of this library (module upgrade).
* Atoms and callbacks are already set, we are done.
*/
return 0;
}
-#endif
- atom_true = enif_make_atom(env,"true");
- atom_false = enif_make_atom(env,"false");
- /* Enter FIPS mode */
- if (tpl_array[2] == atom_true) {
-#ifdef FIPS_SUPPORT
- if (!FIPS_mode_set(1)) {
-#else
- {
-#endif
- PRINTF_ERR0("CRYPTO: Could not setup FIPS mode");
- return 0;
- }
- } else if (tpl_array[2] != atom_false) {
- PRINTF_ERR1("CRYPTO: Invalid load_info '%T'", load_info);
- return 0;
+ if (!init_atoms(env, tpl_array[2], load_info)) {
+ return __LINE__;
}
- atom_sha = enif_make_atom(env,"sha");
- atom_error = enif_make_atom(env,"error");
- atom_rsa_pkcs1_padding = enif_make_atom(env,"rsa_pkcs1_padding");
- atom_rsa_pkcs1_oaep_padding = enif_make_atom(env,"rsa_pkcs1_oaep_padding");
- atom_rsa_no_padding = enif_make_atom(env,"rsa_no_padding");
- atom_signature_md = enif_make_atom(env,"signature_md");
- atom_undefined = enif_make_atom(env,"undefined");
- atom_ok = enif_make_atom(env,"ok");
- atom_not_prime = enif_make_atom(env,"not_prime");
- atom_not_strong_prime = enif_make_atom(env,"not_strong_prime");
- atom_unable_to_check_generator = enif_make_atom(env,"unable_to_check_generator");
- atom_not_suitable_generator = enif_make_atom(env,"not_suitable_generator");
- atom_check_failed = enif_make_atom(env,"check_failed");
- atom_unknown = enif_make_atom(env,"unknown");
- atom_none = enif_make_atom(env,"none");
- atom_notsup = enif_make_atom(env,"notsup");
- atom_digest = enif_make_atom(env,"digest");
-
-#if defined(HAVE_EC)
- atom_ec = enif_make_atom(env,"ec");
- atom_prime_field = enif_make_atom(env,"prime_field");
- atom_characteristic_two_field = enif_make_atom(env,"characteristic_two_field");
- atom_tpbasis = enif_make_atom(env,"tpbasis");
- atom_ppbasis = enif_make_atom(env,"ppbasis");
- atom_onbasis = enif_make_atom(env,"onbasis");
-#endif
- atom_aes_cfb8 = enif_make_atom(env, "aes_cfb8");
- atom_aes_cfb128 = enif_make_atom(env, "aes_cfb128");
-#ifdef HAVE_ECB_IVEC_BUG
- atom_aes_ecb = enif_make_atom(env, "aes_ecb");
- atom_des_ecb = enif_make_atom(env, "des_ecb");
- atom_blowfish_ecb = enif_make_atom(env, "blowfish_ecb");
-#endif
-
-#ifdef FIPS_SUPPORT
- atom_enabled = enif_make_atom(env,"enabled");
- atom_not_enabled = enif_make_atom(env,"not_enabled");
-#else
- atom_not_supported = enif_make_atom(env,"not_supported");
-#endif
- atom_rsa = enif_make_atom(env,"rsa");
- atom_dss = enif_make_atom(env,"dss");
- atom_ecdsa = enif_make_atom(env,"ecdsa");
- atom_rsa_mgf1_md = enif_make_atom(env,"rsa_mgf1_md");
- atom_rsa_oaep_label = enif_make_atom(env,"rsa_oaep_label");
- atom_rsa_oaep_md = enif_make_atom(env,"rsa_oaep_md");
- atom_rsa_pad = enif_make_atom(env,"rsa_pad"); /* backwards compatibility */
- atom_rsa_padding = enif_make_atom(env,"rsa_padding");
- atom_rsa_pkcs1_pss_padding = enif_make_atom(env,"rsa_pkcs1_pss_padding");
-#ifdef HAVE_RSA_SSLV23_PADDING
- atom_rsa_sslv23_padding = enif_make_atom(env,"rsa_sslv23_padding");
-#endif
- atom_rsa_x931_padding = enif_make_atom(env,"rsa_x931_padding");
- atom_rsa_pss_saltlen = enif_make_atom(env,"rsa_pss_saltlen");
- atom_sha224 = enif_make_atom(env,"sha224");
- atom_sha256 = enif_make_atom(env,"sha256");
- atom_sha384 = enif_make_atom(env,"sha384");
- atom_sha512 = enif_make_atom(env,"sha512");
- atom_md5 = enif_make_atom(env,"md5");
- atom_ripemd160 = enif_make_atom(env,"ripemd160");
-
-#ifdef HAS_ENGINE_SUPPORT
- atom_bad_engine_method = enif_make_atom(env,"bad_engine_method");
- atom_bad_engine_id = enif_make_atom(env,"bad_engine_id");
- atom_ctrl_cmd_failed = enif_make_atom(env,"ctrl_cmd_failed");
- atom_engine_init_failed = enif_make_atom(env,"engine_init_failed");
- atom_engine_method_not_supported = enif_make_atom(env,"engine_method_not_supported");
- atom_add_engine_failed = enif_make_atom(env,"add_engine_failed");
- atom_remove_engine_failed = enif_make_atom(env,"remove_engine_failed");
-
- atom_engine_method_rsa = enif_make_atom(env,"engine_method_rsa");
- atom_engine_method_dsa = enif_make_atom(env,"engine_method_dsa");
- atom_engine_method_dh = enif_make_atom(env,"engine_method_dh");
- atom_engine_method_rand = enif_make_atom(env,"engine_method_rand");
- atom_engine_method_ecdh = enif_make_atom(env,"engine_method_ecdh");
- atom_engine_method_ecdsa = enif_make_atom(env,"engine_method_ecdsa");
- atom_engine_method_store = enif_make_atom(env,"engine_method_store");
- atom_engine_method_ciphers = enif_make_atom(env,"engine_method_ciphers");
- atom_engine_method_digests = enif_make_atom(env,"engine_method_digests");
- atom_engine_method_pkey_meths = enif_make_atom(env,"engine_method_pkey_meths");
- atom_engine_method_pkey_asn1_meths = enif_make_atom(env,"engine_method_pkey_asn1_meths");
- atom_engine_method_ec = enif_make_atom(env,"engine_method_ec");
-
- atom_engine = enif_make_atom(env,"engine");
- atom_key_id = enif_make_atom(env,"key_id");
- atom_password = enif_make_atom(env,"password");
-#endif
-
- init_digest_types(env);
- init_cipher_types(env);
- init_algorithms_types(env);
-
#ifdef HAVE_DYNAMIC_CRYPTO_LIB
- {
- void* handle;
- if (!change_basename(&lib_bin, lib_buf, sizeof(lib_buf), crypto_callback_name)) {
- return __LINE__;
- }
- if (!(handle = enif_dlopen(lib_buf, &error_handler, NULL))) {
- return __LINE__;
- }
- if (!(funcp = (get_crypto_callbacks_t*) enif_dlsym(handle, "get_crypto_callbacks",
- &error_handler, NULL))) {
- return __LINE__;
- }
- }
+ if (!change_basename(&lib_bin, lib_buf, sizeof(lib_buf), crypto_callback_name))
+ return __LINE__;
+ if ((handle = enif_dlopen(lib_buf, &error_handler, NULL)) == NULL)
+ return __LINE__;
+ if ((funcp = (get_crypto_callbacks_t*) enif_dlsym(handle, "get_crypto_callbacks",
+ &error_handler, NULL)) == NULL)
+ return __LINE__;
#else /* !HAVE_DYNAMIC_CRYPTO_LIB */
funcp = &get_crypto_callbacks;
#endif
@@ -1148,7 +232,10 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info)
return __LINE__;
}
- CRYPTO_set_mem_functions(ccb->crypto_alloc, ccb->crypto_realloc, ccb->crypto_free);
+#ifdef HAS_CRYPTO_MEM_FUNCTIONS
+ if (!CRYPTO_set_mem_functions(ccb->crypto_alloc, ccb->crypto_realloc, ccb->crypto_free))
+ return __LINE__;
+#endif
#ifdef OPENSSL_THREADS
if (nlocks > 0) {
@@ -1160,6 +247,11 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info)
}
#endif /* OPENSSL_THREADS */
+ init_digest_types(env);
+ init_cipher_types(env);
+ init_algorithms_types(env);
+
+ library_initialized = 1;
return 0;
}
@@ -1197,4298 +289,3 @@ static void unload(ErlNifEnv* env, void* priv_data)
{
--library_refc;
}
-
-static int algo_hash_cnt, algo_hash_fips_cnt;
-static ERL_NIF_TERM algo_hash[8]; /* increase when extending the list */
-static int algo_pubkey_cnt, algo_pubkey_fips_cnt;
-static ERL_NIF_TERM algo_pubkey[7]; /* increase when extending the list */
-static int algo_cipher_cnt, algo_cipher_fips_cnt;
-static ERL_NIF_TERM algo_cipher[24]; /* increase when extending the list */
-static int algo_mac_cnt, algo_mac_fips_cnt;
-static ERL_NIF_TERM algo_mac[2]; /* increase when extending the list */
-
-static void init_algorithms_types(ErlNifEnv* env)
-{
- // Validated algorithms first
- algo_hash_cnt = 0;
- algo_hash[algo_hash_cnt++] = atom_sha;
-#ifdef HAVE_SHA224
- algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha224");
-#endif
-#ifdef HAVE_SHA256
- algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha256");
-#endif
-#ifdef HAVE_SHA384
- algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha384");
-#endif
-#ifdef HAVE_SHA512
- algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha512");
-#endif
- // Non-validated algorithms follow
- algo_hash_fips_cnt = algo_hash_cnt;
- algo_hash[algo_hash_cnt++] = enif_make_atom(env, "md4");
- algo_hash[algo_hash_cnt++] = enif_make_atom(env, "md5");
- algo_hash[algo_hash_cnt++] = enif_make_atom(env, "ripemd160");
-
- algo_pubkey_cnt = 0;
- algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "rsa");
- algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "dss");
- algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "dh");
-#if defined(HAVE_EC)
-#if !defined(OPENSSL_NO_EC2M)
- algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "ec_gf2m");
-#endif
- algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "ecdsa");
- algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "ecdh");
-#endif
- // Non-validated algorithms follow
- algo_pubkey_fips_cnt = algo_pubkey_cnt;
- algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "srp");
-
- // Validated algorithms first
- algo_cipher_cnt = 0;
-#ifndef OPENSSL_NO_DES
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "des3_cbc");
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "des_ede3");
-#ifdef HAVE_DES_ede3_cfb_encrypt
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "des3_cbf");
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "des3_cfb");
-#endif
-#endif
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_cbc");
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_cbc128");
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_cfb8");
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_cfb128");
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_cbc256");
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_ctr");
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_ecb");
-#if defined(HAVE_GCM)
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"aes_gcm");
-#endif
- // Non-validated algorithms follow
- algo_cipher_fips_cnt = algo_cipher_cnt;
-#ifdef HAVE_AES_IGE
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"aes_ige256");
-#endif
-#ifndef OPENSSL_NO_DES
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"des_cbc");
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"des_cfb");
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"des_ecb");
-#endif
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"blowfish_cbc");
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"blowfish_cfb64");
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"blowfish_ofb64");
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"blowfish_ecb");
-#ifndef OPENSSL_NO_RC2
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"rc2_cbc");
-#endif
-#ifndef OPENSSL_NO_RC4
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"rc4");
-#endif
-#if defined(HAVE_CHACHA20_POLY1305)
- algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"chacha20_poly1305");
-#endif
-
- // Validated algorithms first
- algo_mac_cnt = 0;
- algo_mac[algo_mac_cnt++] = enif_make_atom(env,"hmac");
-#ifdef HAVE_CMAC
- algo_mac[algo_mac_cnt++] = enif_make_atom(env,"cmac");
-#endif
- // Non-validated algorithms follow
- algo_mac_fips_cnt = algo_mac_cnt;
-
- ASSERT(algo_hash_cnt <= sizeof(algo_hash)/sizeof(ERL_NIF_TERM));
- ASSERT(algo_pubkey_cnt <= sizeof(algo_pubkey)/sizeof(ERL_NIF_TERM));
- ASSERT(algo_cipher_cnt <= sizeof(algo_cipher)/sizeof(ERL_NIF_TERM));
- ASSERT(algo_mac_cnt <= sizeof(algo_mac)/sizeof(ERL_NIF_TERM));
-}
-
-static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{
-#ifdef FIPS_SUPPORT
- int fips_mode = FIPS_mode();
- int hash_cnt = fips_mode ? algo_hash_fips_cnt : algo_hash_cnt;
- int pubkey_cnt = fips_mode ? algo_pubkey_fips_cnt : algo_pubkey_cnt;
- int cipher_cnt = fips_mode ? algo_cipher_fips_cnt : algo_cipher_cnt;
- int mac_cnt = fips_mode ? algo_mac_fips_cnt : algo_mac_cnt;
-#else
- int hash_cnt = algo_hash_cnt;
- int pubkey_cnt = algo_pubkey_cnt;
- int cipher_cnt = algo_cipher_cnt;
- int mac_cnt = algo_mac_cnt;
-#endif
- return enif_make_tuple4(env,
- enif_make_list_from_array(env, algo_hash, hash_cnt),
- enif_make_list_from_array(env, algo_pubkey, pubkey_cnt),
- enif_make_list_from_array(env, algo_cipher, cipher_cnt),
- enif_make_list_from_array(env, algo_mac, mac_cnt)
- );
-}
-
-static ERL_NIF_TERM info_lib(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{
- /* [{<<"OpenSSL">>,9470143,<<"OpenSSL 0.9.8k 25 Mar 2009">>}] */
-
- static const char libname[] = "OpenSSL";
- unsigned name_sz = strlen(libname);
- const char* ver = SSLeay_version(SSLEAY_VERSION);
- unsigned ver_sz = strlen(ver);
- ERL_NIF_TERM name_term, ver_term;
- int ver_num = OPENSSL_VERSION_NUMBER;
- /* R16:
- * Ignore library version number from SSLeay() and instead show header
- * version. Otherwise user might try to call a function that is implemented
- * by a newer library but not supported by the headers used at compile time.
- * Example: DES_ede3_cfb_encrypt in 0.9.7i but not in 0.9.7d.
- *
- * Version string is still from library though.
- */
-
- memcpy(enif_make_new_binary(env, name_sz, &name_term), libname, name_sz);
- memcpy(enif_make_new_binary(env, ver_sz, &ver_term), ver, ver_sz);
-
- return enif_make_list1(env, enif_make_tuple3(env, name_term,
- enif_make_int(env, ver_num),
- ver_term));
-}
-
-static ERL_NIF_TERM info_fips(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{
-#ifdef FIPS_SUPPORT
- return FIPS_mode() ? atom_enabled : atom_not_enabled;
-#else
- return atom_not_supported;
-#endif
-}
-
-static ERL_NIF_TERM enable_fips_mode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Boolean) */
- if (argv[0] == atom_true) {
-#ifdef FIPS_SUPPORT
- if (FIPS_mode_set(1)) {
- return atom_true;
- }
-#endif
- PRINTF_ERR0("CRYPTO: Could not setup FIPS mode");
- return atom_false;
- } else if (argv[0] == atom_false) {
-#ifdef FIPS_SUPPORT
- if (!FIPS_mode_set(0)) {
- return atom_false;
- }
-#endif
- return atom_true;
- } else {
- return enif_make_badarg(env);
- }
-}
-
-
-#if defined(HAVE_EC)
-static ERL_NIF_TERM make_badarg_maybe(ErlNifEnv* env)
-{
- ERL_NIF_TERM reason;
- if (enif_has_pending_exception(env, &reason))
- return reason; /* dummy return value ignored */
- else
- return enif_make_badarg(env);
-}
-#endif
-
-static ERL_NIF_TERM hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Type, Data) */
- struct digest_type_t *digp = NULL;
- const EVP_MD *md;
- ErlNifBinary data;
- ERL_NIF_TERM ret;
- unsigned ret_size;
-
- digp = get_digest_type(argv[0]);
- if (!digp ||
- !enif_inspect_iolist_as_binary(env, argv[1], &data)) {
- return enif_make_badarg(env);
- }
- md = digp->md.p;
- if (!md) {
- return atom_notsup;
- }
-
- ret_size = (unsigned)EVP_MD_size(md);
- ASSERT(0 < ret_size && ret_size <= EVP_MAX_MD_SIZE);
- if (!EVP_Digest(data.data, data.size,
- enif_make_new_binary(env, ret_size, &ret), &ret_size,
- md, NULL)) {
- return atom_notsup;
- }
- ASSERT(ret_size == (unsigned)EVP_MD_size(md));
-
- CONSUME_REDS(env, data);
- return ret;
-}
-
-#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0)
-
-static ERL_NIF_TERM hash_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Type) */
- struct digest_type_t *digp = NULL;
- struct evp_md_ctx *ctx;
- ERL_NIF_TERM ret;
-
- digp = get_digest_type(argv[0]);
- if (!digp) {
- return enif_make_badarg(env);
- }
- if (!digp->md.p) {
- return atom_notsup;
- }
-
- ctx = enif_alloc_resource(evp_md_ctx_rtype, sizeof(struct evp_md_ctx));
- ctx->ctx = EVP_MD_CTX_new();
- if (!EVP_DigestInit(ctx->ctx, digp->md.p)) {
- enif_release_resource(ctx);
- return atom_notsup;
- }
- ret = enif_make_resource(env, ctx);
- enif_release_resource(ctx);
- return ret;
-}
-static ERL_NIF_TERM hash_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Context, Data) */
- struct evp_md_ctx *ctx, *new_ctx;
- ErlNifBinary data;
- ERL_NIF_TERM ret;
-
- if (!enif_get_resource(env, argv[0], evp_md_ctx_rtype, (void**)&ctx) ||
- !enif_inspect_iolist_as_binary(env, argv[1], &data)) {
- return enif_make_badarg(env);
- }
-
- new_ctx = enif_alloc_resource(evp_md_ctx_rtype, sizeof(struct evp_md_ctx));
- new_ctx->ctx = EVP_MD_CTX_new();
- if (!EVP_MD_CTX_copy(new_ctx->ctx, ctx->ctx) ||
- !EVP_DigestUpdate(new_ctx->ctx, data.data, data.size)) {
- enif_release_resource(new_ctx);
- return atom_notsup;
- }
-
- ret = enif_make_resource(env, new_ctx);
- enif_release_resource(new_ctx);
- CONSUME_REDS(env, data);
- return ret;
-}
-static ERL_NIF_TERM hash_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Context) */
- struct evp_md_ctx *ctx;
- EVP_MD_CTX *new_ctx;
- ERL_NIF_TERM ret;
- unsigned ret_size;
-
- if (!enif_get_resource(env, argv[0], evp_md_ctx_rtype, (void**)&ctx)) {
- return enif_make_badarg(env);
- }
-
- ret_size = (unsigned)EVP_MD_CTX_size(ctx->ctx);
- ASSERT(0 < ret_size && ret_size <= EVP_MAX_MD_SIZE);
-
- new_ctx = EVP_MD_CTX_new();
- if (!EVP_MD_CTX_copy(new_ctx, ctx->ctx) ||
- !EVP_DigestFinal(new_ctx,
- enif_make_new_binary(env, ret_size, &ret),
- &ret_size)) {
- EVP_MD_CTX_free(new_ctx);
- return atom_notsup;
- }
- EVP_MD_CTX_free(new_ctx);
- ASSERT(ret_size == (unsigned)EVP_MD_CTX_size(ctx->ctx));
-
- return ret;
-}
-
-#else /* if OPENSSL_VERSION_NUMBER < 1.0 */
-
-static ERL_NIF_TERM hash_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Type) */
- typedef int (*init_fun)(unsigned char*);
- struct digest_type_t *digp = NULL;
- ERL_NIF_TERM ctx;
- size_t ctx_size = 0;
- init_fun ctx_init = 0;
-
- digp = get_digest_type(argv[0]);
- if (!digp) {
- return enif_make_badarg(env);
- }
- if (!digp->md.p) {
- return atom_notsup;
- }
-
- switch (EVP_MD_type(digp->md.p))
- {
- case NID_md4:
- ctx_size = MD4_CTX_LEN;
- ctx_init = (init_fun)(&MD4_Init);
- break;
- case NID_md5:
- ctx_size = MD5_CTX_LEN;
- ctx_init = (init_fun)(&MD5_Init);
- break;
- case NID_ripemd160:
- ctx_size = RIPEMD160_CTX_LEN;
- ctx_init = (init_fun)(&RIPEMD160_Init);
- break;
- case NID_sha1:
- ctx_size = sizeof(SHA_CTX);
- ctx_init = (init_fun)(&SHA1_Init);
- break;
-#ifdef HAVE_SHA224
- case NID_sha224:
- ctx_size = sizeof(SHA256_CTX);
- ctx_init = (init_fun)(&SHA224_Init);
- break;
-#endif
-#ifdef HAVE_SHA256
- case NID_sha256:
- ctx_size = sizeof(SHA256_CTX);
- ctx_init = (init_fun)(&SHA256_Init);
- break;
-#endif
-#ifdef HAVE_SHA384
- case NID_sha384:
- ctx_size = sizeof(SHA512_CTX);
- ctx_init = (init_fun)(&SHA384_Init);
- break;
-#endif
-#ifdef HAVE_SHA512
- case NID_sha512:
- ctx_size = sizeof(SHA512_CTX);
- ctx_init = (init_fun)(&SHA512_Init);
- break;
-#endif
- default:
- return atom_notsup;
- }
- ASSERT(ctx_size);
- ASSERT(ctx_init);
-
- ctx_init(enif_make_new_binary(env, ctx_size, &ctx));
- return enif_make_tuple2(env, argv[0], ctx);
-}
-static ERL_NIF_TERM hash_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* ({Type, Context}, Data) */
- typedef int (*update_fun)(unsigned char*, const unsigned char*, size_t);
- ERL_NIF_TERM new_ctx;
- ErlNifBinary ctx, data;
- const ERL_NIF_TERM *tuple;
- int arity;
- struct digest_type_t *digp = NULL;
- unsigned char *ctx_buff;
- size_t ctx_size = 0;
- update_fun ctx_update = 0;
-
- if (!enif_get_tuple(env, argv[0], &arity, &tuple) ||
- arity != 2 ||
- !(digp = get_digest_type(tuple[0])) ||
- !enif_inspect_binary(env, tuple[1], &ctx) ||
- !enif_inspect_iolist_as_binary(env, argv[1], &data)) {
- return enif_make_badarg(env);
- }
- if (!digp->md.p) {
- return atom_notsup;
- }
-
- switch (EVP_MD_type(digp->md.p))
- {
- case NID_md4:
- ctx_size = MD4_CTX_LEN;
- ctx_update = (update_fun)(&MD4_Update);
- break;
- case NID_md5:
- ctx_size = MD5_CTX_LEN;
- ctx_update = (update_fun)(&MD5_Update);
- break;
- case NID_ripemd160:
- ctx_size = RIPEMD160_CTX_LEN;
- ctx_update = (update_fun)(&RIPEMD160_Update);
- break;
- case NID_sha1:
- ctx_size = sizeof(SHA_CTX);
- ctx_update = (update_fun)(&SHA1_Update);
- break;
-#ifdef HAVE_SHA224
- case NID_sha224:
- ctx_size = sizeof(SHA256_CTX);
- ctx_update = (update_fun)(&SHA224_Update);
- break;
-#endif
-#ifdef HAVE_SHA256
- case NID_sha256:
- ctx_size = sizeof(SHA256_CTX);
- ctx_update = (update_fun)(&SHA256_Update);
- break;
-#endif
-#ifdef HAVE_SHA384
- case NID_sha384:
- ctx_size = sizeof(SHA512_CTX);
- ctx_update = (update_fun)(&SHA384_Update);
- break;
-#endif
-#ifdef HAVE_SHA512
- case NID_sha512:
- ctx_size = sizeof(SHA512_CTX);
- ctx_update = (update_fun)(&SHA512_Update);
- break;
-#endif
- default:
- return atom_notsup;
- }
- ASSERT(ctx_size);
- ASSERT(ctx_update);
-
- if (ctx.size != ctx_size) {
- return enif_make_badarg(env);
- }
-
- ctx_buff = enif_make_new_binary(env, ctx_size, &new_ctx);
- memcpy(ctx_buff, ctx.data, ctx_size);
- ctx_update(ctx_buff, data.data, data.size);
-
- CONSUME_REDS(env, data);
- return enif_make_tuple2(env, tuple[0], new_ctx);
-}
-static ERL_NIF_TERM hash_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* ({Type, Context}) */
- typedef int (*final_fun)(unsigned char*, void*);
- ERL_NIF_TERM ret;
- ErlNifBinary ctx;
- const ERL_NIF_TERM *tuple;
- int arity;
- struct digest_type_t *digp = NULL;
- const EVP_MD *md;
- void *new_ctx;
- size_t ctx_size = 0;
- final_fun ctx_final = 0;
-
- if (!enif_get_tuple(env, argv[0], &arity, &tuple) ||
- arity != 2 ||
- !(digp = get_digest_type(tuple[0])) ||
- !enif_inspect_binary(env, tuple[1], &ctx)) {
- return enif_make_badarg(env);
- }
- md = digp->md.p;
- if (!md) {
- return atom_notsup;
- }
-
-
- switch (EVP_MD_type(md))
- {
- case NID_md4:
- ctx_size = MD4_CTX_LEN;
- ctx_final = (final_fun)(&MD4_Final);
- break;
- case NID_md5:
- ctx_size = MD5_CTX_LEN;
- ctx_final = (final_fun)(&MD5_Final);
- break;
- case NID_ripemd160:
- ctx_size = RIPEMD160_CTX_LEN;
- ctx_final = (final_fun)(&RIPEMD160_Final);
- break;
- case NID_sha1:
- ctx_size = sizeof(SHA_CTX);
- ctx_final = (final_fun)(&SHA1_Final);
- break;
-#ifdef HAVE_SHA224
- case NID_sha224:
- ctx_size = sizeof(SHA256_CTX);
- ctx_final = (final_fun)(&SHA224_Final);
- break;
-#endif
-#ifdef HAVE_SHA256
- case NID_sha256:
- ctx_size = sizeof(SHA256_CTX);
- ctx_final = (final_fun)(&SHA256_Final);
- break;
-#endif
-#ifdef HAVE_SHA384
- case NID_sha384:
- ctx_size = sizeof(SHA512_CTX);
- ctx_final = (final_fun)(&SHA384_Final);
- break;
-#endif
-#ifdef HAVE_SHA512
- case NID_sha512:
- ctx_size = sizeof(SHA512_CTX);
- ctx_final = (final_fun)(&SHA512_Final);
- break;
-#endif
- default:
- return atom_notsup;
- }
- ASSERT(ctx_size);
- ASSERT(ctx_final);
-
- if (ctx.size != ctx_size) {
- return enif_make_badarg(env);
- }
-
- new_ctx = enif_alloc(ctx_size);
- memcpy(new_ctx, ctx.data, ctx_size);
- ctx_final(enif_make_new_binary(env, (size_t)EVP_MD_size(md), &ret),
- new_ctx);
- enif_free(new_ctx);
-
- return ret;
-}
-#endif /* OPENSSL_VERSION_NUMBER < 1.0 */
-
-static ERL_NIF_TERM hmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Type, Key, Data) or (Type, Key, Data, MacSize) */
- struct digest_type_t *digp = NULL;
- ErlNifBinary key, data;
- unsigned char buff[EVP_MAX_MD_SIZE];
- unsigned size = 0, req_size = 0;
- ERL_NIF_TERM ret;
-
- digp = get_digest_type(argv[0]);
- if (!digp ||
- !enif_inspect_iolist_as_binary(env, argv[1], &key) ||
- !enif_inspect_iolist_as_binary(env, argv[2], &data) ||
- (argc == 4 && !enif_get_uint(env, argv[3], &req_size))) {
- return enif_make_badarg(env);
- }
-
- if (!digp->md.p ||
- !HMAC(digp->md.p,
- key.data, key.size,
- data.data, data.size,
- buff, &size)) {
- return atom_notsup;
- }
- ASSERT(0 < size && size <= EVP_MAX_MD_SIZE);
- CONSUME_REDS(env, data);
-
- if (argc == 4) {
- if (req_size <= size) {
- size = req_size;
- }
- else {
- return enif_make_badarg(env);
- }
- }
- memcpy(enif_make_new_binary(env, size, &ret), buff, size);
- return ret;
-}
-
-static void hmac_context_dtor(ErlNifEnv* env, struct hmac_context *obj)
-{
- if (obj->alive) {
- HMAC_CTX_free(obj->ctx);
- obj->alive = 0;
- }
- enif_mutex_destroy(obj->mtx);
-}
-
-static ERL_NIF_TERM hmac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Type, Key) */
- struct digest_type_t *digp = NULL;
- ErlNifBinary key;
- ERL_NIF_TERM ret;
- struct hmac_context *obj;
-
- digp = get_digest_type(argv[0]);
- if (!digp ||
- !enif_inspect_iolist_as_binary(env, argv[1], &key)) {
- return enif_make_badarg(env);
- }
- if (!digp->md.p) {
- return atom_notsup;
- }
-
- obj = enif_alloc_resource(hmac_context_rtype, sizeof(struct hmac_context));
- obj->mtx = enif_mutex_create("crypto.hmac");
- obj->alive = 1;
- obj->ctx = HMAC_CTX_new();
-#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0)
- // Check the return value of HMAC_Init: it may fail in FIPS mode
- // for disabled algorithms
- if (!HMAC_Init_ex(obj->ctx, key.data, key.size, digp->md.p, NULL)) {
- enif_release_resource(obj);
- return atom_notsup;
- }
-#else
- HMAC_Init_ex(obj->ctx, key.data, key.size, digp->md.p, NULL);
-#endif
-
- ret = enif_make_resource(env, obj);
- enif_release_resource(obj);
- return ret;
-}
-
-static ERL_NIF_TERM hmac_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Context, Data) */
- ErlNifBinary data;
- struct hmac_context* obj;
-
- if (!enif_get_resource(env, argv[0], hmac_context_rtype, (void**)&obj)
- || !enif_inspect_iolist_as_binary(env, argv[1], &data)) {
- return enif_make_badarg(env);
- }
- enif_mutex_lock(obj->mtx);
- if (!obj->alive) {
- enif_mutex_unlock(obj->mtx);
- return enif_make_badarg(env);
- }
- HMAC_Update(obj->ctx, data.data, data.size);
- enif_mutex_unlock(obj->mtx);
-
- CONSUME_REDS(env,data);
- return argv[0];
-}
-
-static ERL_NIF_TERM hmac_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Context) or (Context, HashLen) */
- ERL_NIF_TERM ret;
- struct hmac_context* obj;
- unsigned char mac_buf[EVP_MAX_MD_SIZE];
- unsigned char * mac_bin;
- unsigned int req_len = 0;
- unsigned int mac_len;
-
- if (!enif_get_resource(env,argv[0],hmac_context_rtype, (void**)&obj)
- || (argc == 2 && !enif_get_uint(env, argv[1], &req_len))) {
- return enif_make_badarg(env);
- }
-
- enif_mutex_lock(obj->mtx);
- if (!obj->alive) {
- enif_mutex_unlock(obj->mtx);
- return enif_make_badarg(env);
- }
-
- HMAC_Final(obj->ctx, mac_buf, &mac_len);
- HMAC_CTX_free(obj->ctx);
- obj->alive = 0;
- enif_mutex_unlock(obj->mtx);
-
- if (argc == 2 && req_len < mac_len) {
- /* Only truncate to req_len bytes if asked. */
- mac_len = req_len;
- }
- mac_bin = enif_make_new_binary(env, mac_len, &ret);
- memcpy(mac_bin, mac_buf, mac_len);
-
- return ret;
-}
-
-static ERL_NIF_TERM cmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Type, Key, Data) */
-#if defined(HAVE_CMAC)
- struct cipher_type_t *cipherp = NULL;
- const EVP_CIPHER *cipher;
- CMAC_CTX *ctx;
- ErlNifBinary key;
- ErlNifBinary data;
- ERL_NIF_TERM ret;
- size_t ret_size;
-
- if (!enif_inspect_iolist_as_binary(env, argv[1], &key)
- || !(cipherp = get_cipher_type(argv[0], key.size))
- || !enif_inspect_iolist_as_binary(env, argv[2], &data)) {
- return enif_make_badarg(env);
- }
- cipher = cipherp->cipher.p;
- if (!cipher) {
- return enif_raise_exception(env, atom_notsup);
- }
-
- ctx = CMAC_CTX_new();
- if (!CMAC_Init(ctx, key.data, key.size, cipher, NULL)) {
- CMAC_CTX_free(ctx);
- return atom_notsup;
- }
-
- if (!CMAC_Update(ctx, data.data, data.size) ||
- !CMAC_Final(ctx,
- enif_make_new_binary(env, EVP_CIPHER_block_size(cipher), &ret),
- &ret_size)) {
- CMAC_CTX_free(ctx);
- return atom_notsup;
- }
- ASSERT(ret_size == (unsigned)EVP_CIPHER_block_size(cipher));
-
- CMAC_CTX_free(ctx);
- CONSUME_REDS(env, data);
- return ret;
-#else
- /* The CMAC functionality was introduced in OpenSSL 1.0.1
- * Although OTP requires at least version 0.9.8, the versions 0.9.8 and 1.0.0 are
- * no longer maintained. */
- return atom_notsup;
-#endif
-}
-
-static ERL_NIF_TERM block_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Type, Key, Ivec, Text, IsEncrypt) or (Type, Key, Text, IsEncrypt) */
- struct cipher_type_t *cipherp = NULL;
- const EVP_CIPHER *cipher;
- ErlNifBinary key, ivec, text;
- EVP_CIPHER_CTX* ctx;
- ERL_NIF_TERM ret;
- unsigned char *out;
- int ivec_size, out_size = 0;
-
- if (!enif_inspect_iolist_as_binary(env, argv[1], &key)
- || !(cipherp = get_cipher_type(argv[0], key.size))
- || !enif_inspect_iolist_as_binary(env, argv[argc - 2], &text)) {
- return enif_make_badarg(env);
- }
- cipher = cipherp->cipher.p;
- if (!cipher) {
- return enif_raise_exception(env, atom_notsup);
- }
-
- if (argv[0] == atom_aes_cfb8
- && (key.size == 24 || key.size == 32)) {
- /* Why do EVP_CIPHER_CTX_set_key_length() fail on these key sizes?
- * Fall back on low level API
- */
- return aes_cfb_8_crypt(env, argc-1, argv+1);
- }
- else if (argv[0] == atom_aes_cfb128
- && (key.size == 24 || key.size == 32)) {
- /* Why do EVP_CIPHER_CTX_set_key_length() fail on these key sizes?
- * Fall back on low level API
- */
- return aes_cfb_128_crypt_nif(env, argc-1, argv+1);
- }
-
- ivec_size = EVP_CIPHER_iv_length(cipher);
-
-#ifdef HAVE_ECB_IVEC_BUG
- if (argv[0] == atom_aes_ecb || argv[0] == atom_blowfish_ecb ||
- argv[0] == atom_des_ecb)
- ivec_size = 0; /* 0.9.8l returns faulty ivec_size */
-#endif
-
- if (text.size % EVP_CIPHER_block_size(cipher) != 0 ||
- (ivec_size == 0 ? argc != 4
- : (argc != 5 ||
- !enif_inspect_iolist_as_binary(env, argv[2], &ivec) ||
- ivec.size != ivec_size))) {
- return enif_make_badarg(env);
- }
-
- out = enif_make_new_binary(env, text.size, &ret);
-
- ctx = EVP_CIPHER_CTX_new();
- if (!EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL,
- (argv[argc - 1] == atom_true)) ||
- !EVP_CIPHER_CTX_set_key_length(ctx, key.size) ||
- !(EVP_CIPHER_type(cipher) != NID_rc2_cbc ||
- EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_SET_RC2_KEY_BITS, key.size * 8, NULL)) ||
- !EVP_CipherInit_ex(ctx, NULL, NULL,
- key.data, ivec_size ? ivec.data : NULL, -1) ||
- !EVP_CIPHER_CTX_set_padding(ctx, 0)) {
-
- EVP_CIPHER_CTX_free(ctx);
- return enif_raise_exception(env, atom_notsup);
- }
-
- if (text.size > 0 && /* OpenSSL 0.9.8h asserts text.size > 0 */
- (!EVP_CipherUpdate(ctx, out, &out_size, text.data, text.size)
- || (ASSERT(out_size == text.size), 0)
- || !EVP_CipherFinal_ex(ctx, out + out_size, &out_size))) {
-
- EVP_CIPHER_CTX_free(ctx);
- return enif_raise_exception(env, atom_notsup);
- }
- ASSERT(out_size == 0);
- EVP_CIPHER_CTX_free(ctx);
- CONSUME_REDS(env, text);
-
- return ret;
-}
-
-static ERL_NIF_TERM aes_cfb_8_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Key, IVec, Data, IsEncrypt) */
- ErlNifBinary key, ivec, text;
- AES_KEY aes_key;
- unsigned char ivec_clone[16]; /* writable copy */
- int new_ivlen = 0;
- ERL_NIF_TERM ret;
-
- CHECK_NO_FIPS_MODE();
-
- if (!enif_inspect_iolist_as_binary(env, argv[0], &key)
- || !(key.size == 16 || key.size == 24 || key.size == 32)
- || !enif_inspect_binary(env, argv[1], &ivec) || ivec.size != 16
- || !enif_inspect_iolist_as_binary(env, argv[2], &text)) {
- return enif_make_badarg(env);
- }
-
- memcpy(ivec_clone, ivec.data, 16);
- AES_set_encrypt_key(key.data, key.size * 8, &aes_key);
- AES_cfb8_encrypt((unsigned char *) text.data,
- enif_make_new_binary(env, text.size, &ret),
- text.size, &aes_key, ivec_clone, &new_ivlen,
- (argv[3] == atom_true));
- CONSUME_REDS(env,text);
- return ret;
-}
-
-static ERL_NIF_TERM aes_cfb_128_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Key, IVec, Data, IsEncrypt) */
- ErlNifBinary key, ivec, text;
- AES_KEY aes_key;
- unsigned char ivec_clone[16]; /* writable copy */
- int new_ivlen = 0;
- ERL_NIF_TERM ret;
-
- if (!enif_inspect_iolist_as_binary(env, argv[0], &key)
- || !(key.size == 16 || key.size == 24 || key.size == 32)
- || !enif_inspect_binary(env, argv[1], &ivec) || ivec.size != 16
- || !enif_inspect_iolist_as_binary(env, argv[2], &text)) {
- return enif_make_badarg(env);
- }
-
- memcpy(ivec_clone, ivec.data, 16);
- AES_set_encrypt_key(key.data, key.size * 8, &aes_key);
- AES_cfb128_encrypt((unsigned char *) text.data,
- enif_make_new_binary(env, text.size, &ret),
- text.size, &aes_key, ivec_clone, &new_ivlen,
- (argv[3] == atom_true));
- CONSUME_REDS(env,text);
- return ret;
-}
-
-static ERL_NIF_TERM aes_ige_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Key, IVec, Data, IsEncrypt) */
-#ifdef HAVE_AES_IGE
- ErlNifBinary key_bin, ivec_bin, data_bin;
- AES_KEY aes_key;
- unsigned char ivec[32];
- int i;
- unsigned char* ret_ptr;
- ERL_NIF_TERM ret;
-
- CHECK_NO_FIPS_MODE();
-
- if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin)
- || (key_bin.size != 16 && key_bin.size != 32)
- || !enif_inspect_binary(env, argv[1], &ivec_bin)
- || ivec_bin.size != 32
- || !enif_inspect_iolist_as_binary(env, argv[2], &data_bin)
- || data_bin.size % 16 != 0) {
-
- return enif_make_badarg(env);
- }
-
- if (argv[3] == atom_true) {
- i = AES_ENCRYPT;
- AES_set_encrypt_key(key_bin.data, key_bin.size*8, &aes_key);
- }
- else {
- i = AES_DECRYPT;
- AES_set_decrypt_key(key_bin.data, key_bin.size*8, &aes_key);
- }
-
- ret_ptr = enif_make_new_binary(env, data_bin.size, &ret);
- memcpy(ivec, ivec_bin.data, 32); /* writable copy */
- AES_ige_encrypt(data_bin.data, ret_ptr, data_bin.size, &aes_key, ivec, i);
- CONSUME_REDS(env,data_bin);
- return ret;
-#else
- return atom_notsup;
-#endif
-}
-
-
-/* Initializes state for ctr streaming (de)encryption
-*/
-#ifdef HAVE_EVP_AES_CTR
-static ERL_NIF_TERM aes_ctr_stream_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Key, IVec) */
- ErlNifBinary key_bin, ivec_bin;
- struct evp_cipher_ctx *ctx;
- const EVP_CIPHER *cipher;
- ERL_NIF_TERM ret;
-
- if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin)
- || !enif_inspect_binary(env, argv[1], &ivec_bin)
- || ivec_bin.size != 16) {
- return enif_make_badarg(env);
- }
-
- switch (key_bin.size)
- {
- case 16: cipher = EVP_aes_128_ctr(); break;
- case 24: cipher = EVP_aes_192_ctr(); break;
- case 32: cipher = EVP_aes_256_ctr(); break;
- default: return enif_make_badarg(env);
- }
-
- ctx = enif_alloc_resource(evp_cipher_ctx_rtype, sizeof(struct evp_cipher_ctx));
- ctx->ctx = EVP_CIPHER_CTX_new();
- EVP_CipherInit_ex(ctx->ctx, cipher, NULL,
- key_bin.data, ivec_bin.data, 1);
- EVP_CIPHER_CTX_set_padding(ctx->ctx, 0);
- ret = enif_make_resource(env, ctx);
- enif_release_resource(ctx);
- return ret;
-}
-static ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Context, Data) */
- struct evp_cipher_ctx *ctx, *new_ctx;
- ErlNifBinary data_bin;
- ERL_NIF_TERM ret, cipher_term;
- unsigned char *out;
- int outl = 0;
-
- if (!enif_get_resource(env, argv[0], evp_cipher_ctx_rtype, (void**)&ctx)
- || !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) {
- return enif_make_badarg(env);
- }
- new_ctx = enif_alloc_resource(evp_cipher_ctx_rtype, sizeof(struct evp_cipher_ctx));
- new_ctx->ctx = EVP_CIPHER_CTX_new();
- EVP_CIPHER_CTX_copy(new_ctx->ctx, ctx->ctx);
- out = enif_make_new_binary(env, data_bin.size, &cipher_term);
- EVP_CipherUpdate(new_ctx->ctx, out, &outl, data_bin.data, data_bin.size);
- ASSERT(outl == data_bin.size);
-
- ret = enif_make_tuple2(env, enif_make_resource(env, new_ctx), cipher_term);
- enif_release_resource(new_ctx);
- CONSUME_REDS(env,data_bin);
- return ret;
-}
-
-#else /* if not HAVE_EVP_AES_CTR */
-
-static ERL_NIF_TERM aes_ctr_stream_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Key, IVec) */
- ErlNifBinary key_bin, ivec_bin;
- ERL_NIF_TERM ecount_bin;
-
- if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin)
- || !enif_inspect_binary(env, argv[1], &ivec_bin)
- || !(key_bin.size == 16 || key_bin.size == 24 || key_bin.size ==32)
- || ivec_bin.size != 16) {
- return enif_make_badarg(env);
- }
-
- memset(enif_make_new_binary(env, AES_BLOCK_SIZE, &ecount_bin),
- 0, AES_BLOCK_SIZE);
- return enif_make_tuple4(env, argv[0], argv[1], ecount_bin, enif_make_int(env, 0));
-}
-
-static ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* ({Key, IVec, ECount, Num}, Data) */
- ErlNifBinary key_bin, ivec_bin, text_bin, ecount_bin;
- AES_KEY aes_key;
- unsigned int num;
- ERL_NIF_TERM ret, num2_term, cipher_term, ivec2_term, ecount2_term, new_state_term;
- int state_arity;
- const ERL_NIF_TERM *state_term;
- unsigned char * ivec2_buf;
- unsigned char * ecount2_buf;
-
- if (!enif_get_tuple(env, argv[0], &state_arity, &state_term)
- || state_arity != 4
- || !enif_inspect_iolist_as_binary(env, state_term[0], &key_bin)
- || AES_set_encrypt_key(key_bin.data, key_bin.size*8, &aes_key) != 0
- || !enif_inspect_binary(env, state_term[1], &ivec_bin) || ivec_bin.size != 16
- || !enif_inspect_binary(env, state_term[2], &ecount_bin) || ecount_bin.size != AES_BLOCK_SIZE
- || !enif_get_uint(env, state_term[3], &num)
- || !enif_inspect_iolist_as_binary(env, argv[1], &text_bin)) {
- return enif_make_badarg(env);
- }
-
- ivec2_buf = enif_make_new_binary(env, ivec_bin.size, &ivec2_term);
- ecount2_buf = enif_make_new_binary(env, ecount_bin.size, &ecount2_term);
-
- memcpy(ivec2_buf, ivec_bin.data, 16);
- memcpy(ecount2_buf, ecount_bin.data, ecount_bin.size);
-
- AES_ctr128_encrypt((unsigned char *) text_bin.data,
- enif_make_new_binary(env, text_bin.size, &cipher_term),
- text_bin.size, &aes_key, ivec2_buf, ecount2_buf, &num);
-
- num2_term = enif_make_uint(env, num);
- new_state_term = enif_make_tuple4(env, state_term[0], ivec2_term, ecount2_term, num2_term);
- ret = enif_make_tuple2(env, new_state_term, cipher_term);
- CONSUME_REDS(env,text_bin);
- return ret;
-}
-#endif /* !HAVE_EVP_AES_CTR */
-
-static ERL_NIF_TERM aes_gcm_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Key,Iv,AAD,In) */
-#if defined(HAVE_GCM)
- EVP_CIPHER_CTX *ctx;
- const EVP_CIPHER *cipher = NULL;
- ErlNifBinary key, iv, aad, in;
- unsigned int tag_len;
- unsigned char *outp, *tagp;
- ERL_NIF_TERM out, out_tag;
- int len;
-
- if (!enif_inspect_iolist_as_binary(env, argv[0], &key)
- || (key.size != 16 && key.size != 24 && key.size != 32)
- || !enif_inspect_binary(env, argv[1], &iv) || iv.size == 0
- || !enif_inspect_iolist_as_binary(env, argv[2], &aad)
- || !enif_inspect_iolist_as_binary(env, argv[3], &in)
- || !enif_get_uint(env, argv[4], &tag_len) || tag_len < 1 || tag_len > 16) {
- return enif_make_badarg(env);
- }
-
- if (key.size == 16)
- cipher = EVP_aes_128_gcm();
- else if (key.size == 24)
- cipher = EVP_aes_192_gcm();
- else if (key.size == 32)
- cipher = EVP_aes_256_gcm();
-
- ctx = EVP_CIPHER_CTX_new();
-
- if (EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1)
- goto out_err;
-
- EVP_CIPHER_CTX_set_padding(ctx, 0);
-
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv.size, NULL) != 1)
- goto out_err;
- if (EVP_EncryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1)
- goto out_err;
- if (EVP_EncryptUpdate(ctx, NULL, &len, aad.data, aad.size) != 1)
- goto out_err;
-
- outp = enif_make_new_binary(env, in.size, &out);
-
- if (EVP_EncryptUpdate(ctx, outp, &len, in.data, in.size) != 1)
- goto out_err;
- if (EVP_EncryptFinal_ex(ctx, outp+len, &len) != 1)
- goto out_err;
-
- tagp = enif_make_new_binary(env, tag_len, &out_tag);
-
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, tag_len, tagp) != 1)
- goto out_err;
-
- EVP_CIPHER_CTX_free(ctx);
-
- CONSUME_REDS(env, in);
-
- return enif_make_tuple2(env, out, out_tag);
-
-out_err:
- EVP_CIPHER_CTX_free(ctx);
- return atom_error;
-
-#else
- return enif_raise_exception(env, atom_notsup);
-#endif
-}
-
-static ERL_NIF_TERM aes_gcm_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Key,Iv,AAD,In,Tag) */
-#if defined(HAVE_GCM_EVP_DECRYPT_BUG)
- return aes_gcm_decrypt_NO_EVP(env, argc, argv);
-#elif defined(HAVE_GCM)
- EVP_CIPHER_CTX *ctx;
- const EVP_CIPHER *cipher = NULL;
- ErlNifBinary key, iv, aad, in, tag;
- unsigned char *outp;
- ERL_NIF_TERM out;
- int len;
-
- if (!enif_inspect_iolist_as_binary(env, argv[0], &key)
- || (key.size != 16 && key.size != 24 && key.size != 32)
- || !enif_inspect_binary(env, argv[1], &iv) || iv.size == 0
- || !enif_inspect_iolist_as_binary(env, argv[2], &aad)
- || !enif_inspect_iolist_as_binary(env, argv[3], &in)
- || !enif_inspect_iolist_as_binary(env, argv[4], &tag)) {
- return enif_make_badarg(env);
- }
-
- if (key.size == 16)
- cipher = EVP_aes_128_gcm();
- else if (key.size == 24)
- cipher = EVP_aes_192_gcm();
- else if (key.size == 32)
- cipher = EVP_aes_256_gcm();
-
- ctx = EVP_CIPHER_CTX_new();
-
- if (EVP_DecryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1)
- goto out_err;
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv.size, NULL) != 1)
- goto out_err;
- if (EVP_DecryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1)
- goto out_err;
- if (EVP_DecryptUpdate(ctx, NULL, &len, aad.data, aad.size) != 1)
- goto out_err;
-
- outp = enif_make_new_binary(env, in.size, &out);
-
- if (EVP_DecryptUpdate(ctx, outp, &len, in.data, in.size) != 1)
- goto out_err;
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tag.size, tag.data) != 1)
- goto out_err;
- if (EVP_DecryptFinal_ex(ctx, outp+len, &len) != 1)
- goto out_err;
-
- EVP_CIPHER_CTX_free(ctx);
-
- CONSUME_REDS(env, in);
-
- return out;
-
-out_err:
- EVP_CIPHER_CTX_free(ctx);
- return atom_error;
-#else
- return enif_raise_exception(env, atom_notsup);
-#endif
-}
-
-#ifdef HAVE_GCM_EVP_DECRYPT_BUG
-static ERL_NIF_TERM aes_gcm_decrypt_NO_EVP(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{
- GCM128_CONTEXT *ctx;
- ErlNifBinary key, iv, aad, in, tag;
- AES_KEY aes_key;
- unsigned char *outp;
- ERL_NIF_TERM out;
-
- if (!enif_inspect_iolist_as_binary(env, argv[0], &key)
- || AES_set_encrypt_key(key.data, key.size*8, &aes_key) != 0
- || !enif_inspect_binary(env, argv[1], &iv) || iv.size == 0
- || !enif_inspect_iolist_as_binary(env, argv[2], &aad)
- || !enif_inspect_iolist_as_binary(env, argv[3], &in)
- || !enif_inspect_iolist_as_binary(env, argv[4], &tag)) {
- return enif_make_badarg(env);
- }
-
- if (!(ctx = CRYPTO_gcm128_new(&aes_key, (block128_f)AES_encrypt)))
- return atom_error;
-
- CRYPTO_gcm128_setiv(ctx, iv.data, iv.size);
-
- if (CRYPTO_gcm128_aad(ctx, aad.data, aad.size))
- goto out_err;
-
- outp = enif_make_new_binary(env, in.size, &out);
-
- /* decrypt */
- if (CRYPTO_gcm128_decrypt(ctx, in.data, outp, in.size))
- goto out_err;
-
- /* calculate and check the tag */
- if (CRYPTO_gcm128_finish(ctx, tag.data, tag.size))
- goto out_err;
-
- CRYPTO_gcm128_release(ctx);
- CONSUME_REDS(env, in);
-
- return out;
-
-out_err:
- CRYPTO_gcm128_release(ctx);
- return atom_error;
-}
-#endif /* HAVE_GCM_EVP_DECRYPT_BUG */
-
-
-static ERL_NIF_TERM chacha20_poly1305_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Key,Iv,AAD,In) */
-#if defined(HAVE_CHACHA20_POLY1305)
- EVP_CIPHER_CTX *ctx;
- const EVP_CIPHER *cipher = NULL;
- ErlNifBinary key, iv, aad, in;
- unsigned char *outp, *tagp;
- ERL_NIF_TERM out, out_tag;
- int len;
-
- if (!enif_inspect_iolist_as_binary(env, argv[0], &key) || key.size != 32
- || !enif_inspect_binary(env, argv[1], &iv) || iv.size == 0 || iv.size > 16
- || !enif_inspect_iolist_as_binary(env, argv[2], &aad)
- || !enif_inspect_iolist_as_binary(env, argv[3], &in)) {
- return enif_make_badarg(env);
- }
-
- cipher = EVP_chacha20_poly1305();
-
- ctx = EVP_CIPHER_CTX_new();
-
- if (EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1)
- goto out_err;
-
- EVP_CIPHER_CTX_set_padding(ctx, 0);
-
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, iv.size, NULL) != 1)
- goto out_err;
- if (EVP_EncryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1)
- goto out_err;
- if (EVP_EncryptUpdate(ctx, NULL, &len, aad.data, aad.size) != 1)
- goto out_err;
-
- outp = enif_make_new_binary(env, in.size, &out);
-
- if (EVP_EncryptUpdate(ctx, outp, &len, in.data, in.size) != 1)
- goto out_err;
- if (EVP_EncryptFinal_ex(ctx, outp+len, &len) != 1)
- goto out_err;
-
- tagp = enif_make_new_binary(env, 16, &out_tag);
-
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, tagp) != 1)
- goto out_err;
-
- EVP_CIPHER_CTX_free(ctx);
-
- CONSUME_REDS(env, in);
-
- return enif_make_tuple2(env, out, out_tag);
-
-out_err:
- EVP_CIPHER_CTX_free(ctx);
- return atom_error;
-#else
- return enif_raise_exception(env, atom_notsup);
-#endif
-}
-
-static ERL_NIF_TERM chacha20_poly1305_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Key,Iv,AAD,In,Tag) */
-#if defined(HAVE_CHACHA20_POLY1305)
- EVP_CIPHER_CTX *ctx;
- const EVP_CIPHER *cipher = NULL;
- ErlNifBinary key, iv, aad, in, tag;
- unsigned char *outp;
- ERL_NIF_TERM out;
- int len;
-
- if (!enif_inspect_iolist_as_binary(env, argv[0], &key) || key.size != 32
- || !enif_inspect_binary(env, argv[1], &iv) || iv.size == 0 || iv.size > 16
- || !enif_inspect_iolist_as_binary(env, argv[2], &aad)
- || !enif_inspect_iolist_as_binary(env, argv[3], &in)
- || !enif_inspect_iolist_as_binary(env, argv[4], &tag) || tag.size != 16) {
- return enif_make_badarg(env);
- }
-
- cipher = EVP_chacha20_poly1305();
-
- ctx = EVP_CIPHER_CTX_new();
-
- if (EVP_DecryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1)
- goto out_err;
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, iv.size, NULL) != 1)
- goto out_err;
- if (EVP_DecryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1)
- goto out_err;
- if (EVP_DecryptUpdate(ctx, NULL, &len, aad.data, aad.size) != 1)
- goto out_err;
-
- outp = enif_make_new_binary(env, in.size, &out);
-
- if (EVP_DecryptUpdate(ctx, outp, &len, in.data, in.size) != 1)
- goto out_err;
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag.size, tag.data) != 1)
- goto out_err;
- if (EVP_DecryptFinal_ex(ctx, outp+len, &len) != 1)
- goto out_err;
-
- EVP_CIPHER_CTX_free(ctx);
-
- CONSUME_REDS(env, in);
-
- return out;
-
-out_err:
- EVP_CIPHER_CTX_free(ctx);
- return atom_error;
-#else
- return enif_raise_exception(env, atom_notsup);
-#endif
-}
-
-static ERL_NIF_TERM strong_rand_bytes_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Bytes) */
- unsigned bytes;
- unsigned char* data;
- ERL_NIF_TERM ret;
-
- if (!enif_get_uint(env, argv[0], &bytes)) {
- return enif_make_badarg(env);
- }
- data = enif_make_new_binary(env, bytes, &ret);
- if ( RAND_bytes(data, bytes) != 1) {
- return atom_false;
- }
- ERL_VALGRIND_MAKE_MEM_DEFINED(data, bytes);
- return ret;
-}
-
-
-static int get_bn_from_mpint(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp)
-{
- ErlNifBinary bin;
- int sz;
- if (!enif_inspect_binary(env,term,&bin)) {
- return 0;
- }
- ERL_VALGRIND_ASSERT_MEM_DEFINED(bin.data, bin.size);
- sz = bin.size - 4;
- if (sz < 0 || get_int32(bin.data) != sz) {
- return 0;
- }
- *bnp = BN_bin2bn(bin.data+4, sz, NULL);
- return 1;
-}
-
-static int get_bn_from_bin(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp)
-{
- ErlNifBinary bin;
- if (!enif_inspect_binary(env,term,&bin)) {
- return 0;
- }
- ERL_VALGRIND_ASSERT_MEM_DEFINED(bin.data, bin.size);
- *bnp = BN_bin2bn(bin.data, bin.size, NULL);
- return 1;
-}
-
-static ERL_NIF_TERM bin_from_bn(ErlNifEnv* env, const BIGNUM *bn)
-{
- int bn_len;
- unsigned char *bin_ptr;
- ERL_NIF_TERM term;
-
- /* Copy the bignum into an erlang binary. */
- bn_len = BN_num_bytes(bn);
- bin_ptr = enif_make_new_binary(env, bn_len, &term);
- BN_bn2bin(bn, bin_ptr);
-
- return term;
-}
-
-static ERL_NIF_TERM strong_rand_range_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Range) */
- BIGNUM *bn_range, *bn_rand;
- ERL_NIF_TERM ret;
-
- if(!get_bn_from_bin(env, argv[0], &bn_range)) {
- return enif_make_badarg(env);
- }
-
- bn_rand = BN_new();
- if (BN_rand_range(bn_rand, bn_range) != 1) {
- ret = atom_false;
- }
- else {
- ret = bin_from_bn(env, bn_rand);
- }
- BN_free(bn_rand);
- BN_free(bn_range);
- return ret;
-}
-
-static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Lo,Hi) */
- BIGNUM *bn_from = NULL, *bn_to, *bn_rand;
- unsigned char* data;
- unsigned dlen;
- ERL_NIF_TERM ret;
-
- if (!get_bn_from_mpint(env, argv[0], &bn_from)
- || !get_bn_from_mpint(env, argv[1], &bn_rand)) {
- if (bn_from) BN_free(bn_from);
- return enif_make_badarg(env);
- }
-
- bn_to = BN_new();
- BN_sub(bn_to, bn_rand, bn_from);
- BN_pseudo_rand_range(bn_rand, bn_to);
- BN_add(bn_rand, bn_rand, bn_from);
- dlen = BN_num_bytes(bn_rand);
- data = enif_make_new_binary(env, dlen+4, &ret);
- put_int32(data, dlen);
- BN_bn2bin(bn_rand, data+4);
- ERL_VALGRIND_MAKE_MEM_DEFINED(data+4, dlen);
- BN_free(bn_rand);
- BN_free(bn_from);
- BN_free(bn_to);
- return ret;
-}
-
-static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Base,Exponent,Modulo,bin_hdr) */
- BIGNUM *bn_base=NULL, *bn_exponent=NULL, *bn_modulo=NULL, *bn_result;
- BN_CTX *bn_ctx;
- unsigned char* ptr;
- unsigned dlen;
- unsigned bin_hdr; /* return type: 0=plain binary, 4: mpint */
- unsigned extra_byte;
- ERL_NIF_TERM ret;
-
- if (!get_bn_from_bin(env, argv[0], &bn_base)
- || !get_bn_from_bin(env, argv[1], &bn_exponent)
- || !get_bn_from_bin(env, argv[2], &bn_modulo)
- || !enif_get_uint(env,argv[3],&bin_hdr) || (bin_hdr & ~4)) {
-
- if (bn_base) BN_free(bn_base);
- if (bn_exponent) BN_free(bn_exponent);
- if (bn_modulo) BN_free(bn_modulo);
- return enif_make_badarg(env);
- }
- bn_result = BN_new();
- bn_ctx = BN_CTX_new();
- BN_mod_exp(bn_result, bn_base, bn_exponent, bn_modulo, bn_ctx);
- dlen = BN_num_bytes(bn_result);
- extra_byte = bin_hdr && BN_is_bit_set(bn_result, dlen*8-1);
- ptr = enif_make_new_binary(env, bin_hdr+extra_byte+dlen, &ret);
- if (bin_hdr) {
- put_int32(ptr, extra_byte+dlen);
- ptr[4] = 0; /* extra zeroed byte to ensure a positive mpint */
- ptr += bin_hdr + extra_byte;
- }
- BN_bn2bin(bn_result, ptr);
- BN_free(bn_result);
- BN_CTX_free(bn_ctx);
- BN_free(bn_modulo);
- BN_free(bn_exponent);
- BN_free(bn_base);
- return ret;
-}
-
-static void init_digest_types(ErlNifEnv* env)
-{
- struct digest_type_t* p = digest_types;
-
- for (p = digest_types; p->type.str; p++) {
- p->type.atom = enif_make_atom(env, p->type.str);
- if (p->md.funcp)
- p->md.p = p->md.funcp();
- }
- p->type.atom = atom_false; /* end marker */
-}
-
-static void init_cipher_types(ErlNifEnv* env)
-{
- struct cipher_type_t* p = cipher_types;
-
- for (p = cipher_types; p->type.str; p++) {
- p->type.atom = enif_make_atom(env, p->type.str);
- if (p->cipher.funcp)
- p->cipher.p = p->cipher.funcp();
- }
- p->type.atom = atom_false; /* end marker */
-}
-
-static struct digest_type_t* get_digest_type(ERL_NIF_TERM type)
-{
- struct digest_type_t* p = NULL;
- for (p = digest_types; p->type.atom != atom_false; p++) {
- if (type == p->type.atom) {
- return p;
- }
- }
- return NULL;
-}
-
-static struct cipher_type_t* get_cipher_type(ERL_NIF_TERM type, size_t key_len)
-{
- struct cipher_type_t* p = NULL;
- for (p = cipher_types; p->type.atom != atom_false; p++) {
- if (type == p->type.atom && (!p->key_len || key_len == p->key_len)) {
- return p;
- }
- }
- return NULL;
-}
-
-
-static ERL_NIF_TERM do_exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Data1, Data2) */
- ErlNifBinary d1, d2;
- unsigned char* ret_ptr;
- int i;
- ERL_NIF_TERM ret;
-
- if (!enif_inspect_iolist_as_binary(env,argv[0], &d1)
- || !enif_inspect_iolist_as_binary(env,argv[1], &d2)
- || d1.size != d2.size) {
- return enif_make_badarg(env);
- }
- ret_ptr = enif_make_new_binary(env, d1.size, &ret);
-
- for (i=0; i<d1.size; i++) {
- ret_ptr[i] = d1.data[i] ^ d2.data[i];
- }
- CONSUME_REDS(env,d1);
- return ret;
-}
-
-static ERL_NIF_TERM rc4_set_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Key) */
-#ifndef OPENSSL_NO_RC4
- ErlNifBinary key;
- ERL_NIF_TERM ret;
-
- CHECK_NO_FIPS_MODE();
-
- if (!enif_inspect_iolist_as_binary(env,argv[0], &key)) {
- return enif_make_badarg(env);
- }
- RC4_set_key((RC4_KEY*)enif_make_new_binary(env, sizeof(RC4_KEY), &ret),
- key.size, key.data);
- return ret;
-#else
- return enif_raise_exception(env, atom_notsup);
-#endif
-}
-
-static ERL_NIF_TERM rc4_encrypt_with_state(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (State, Data) */
-#ifndef OPENSSL_NO_RC4
- ErlNifBinary state, data;
- RC4_KEY* rc4_key;
- ERL_NIF_TERM new_state, new_data;
-
- CHECK_NO_FIPS_MODE();
-
- if (!enif_inspect_iolist_as_binary(env,argv[0], &state)
- || state.size != sizeof(RC4_KEY)
- || !enif_inspect_iolist_as_binary(env,argv[1], &data)) {
- return enif_make_badarg(env);
- }
- rc4_key = (RC4_KEY*)enif_make_new_binary(env, sizeof(RC4_KEY), &new_state);
- memcpy(rc4_key, state.data, sizeof(RC4_KEY));
- RC4(rc4_key, data.size, data.data,
- enif_make_new_binary(env, data.size, &new_data));
- CONSUME_REDS(env,data);
- return enif_make_tuple2(env,new_state,new_data);
-#else
- return enif_raise_exception(env, atom_notsup);
-#endif
-}
-
-static int get_rsa_private_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa)
-{
- /* key=[E,N,D]|[E,N,D,P1,P2,E1,E2,C] */
- ERL_NIF_TERM head, tail;
- BIGNUM *e, *n, *d;
- BIGNUM *p, *q;
- BIGNUM *dmp1, *dmq1, *iqmp;
-
- if (!enif_get_list_cell(env, key, &head, &tail)
- || !get_bn_from_bin(env, head, &e)
- || !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_bin(env, head, &n)
- || !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_bin(env, head, &d)) {
- return 0;
- }
- (void) RSA_set0_key(rsa, n, e, d);
- if (enif_is_empty_list(env, tail)) {
- return 1;
- }
- if (!enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_bin(env, head, &p)
- || !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_bin(env, head, &q)
- || !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_bin(env, head, &dmp1)
- || !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_bin(env, head, &dmq1)
- || !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_bin(env, head, &iqmp)
- || !enif_is_empty_list(env, tail)) {
- return 0;
- }
- (void) RSA_set0_factors(rsa, p, q);
- (void) RSA_set0_crt_params(rsa, dmp1, dmq1, iqmp);
- return 1;
-}
-
-
-static int get_rsa_public_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa)
-{
- /* key=[E,N] */
- ERL_NIF_TERM head, tail;
- BIGNUM *e, *n;
-
- if (!enif_get_list_cell(env, key, &head, &tail)
- || !get_bn_from_bin(env, head, &e)
- || !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_bin(env, head, &n)
- || !enif_is_empty_list(env, tail)) {
- return 0;
- }
-
- (void) RSA_set0_key(rsa, n, e, NULL);
- return 1;
-}
-
-static int get_dss_private_key(ErlNifEnv* env, ERL_NIF_TERM key, DSA *dsa)
-{
- /* key=[P,Q,G,KEY] */
- ERL_NIF_TERM head, tail;
- BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL;
- BIGNUM *dummy_pub_key, *priv_key = NULL;
-
- if (!enif_get_list_cell(env, key, &head, &tail)
- || !get_bn_from_bin(env, head, &dsa_p)
- || !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_bin(env, head, &dsa_q)
- || !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_bin(env, head, &dsa_g)
- || !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_bin(env, head, &priv_key)
- || !enif_is_empty_list(env,tail)) {
- if (dsa_p) BN_free(dsa_p);
- if (dsa_q) BN_free(dsa_q);
- if (dsa_g) BN_free(dsa_g);
- if (priv_key) BN_free(priv_key);
- return 0;
- }
-
- /* Note: DSA_set0_key() does not allow setting only the
- * private key, although DSA_sign() does not use the
- * public key. Work around this limitation by setting
- * the public key to a copy of the private key.
- */
- dummy_pub_key = BN_dup(priv_key);
-
- DSA_set0_pqg(dsa, dsa_p, dsa_q, dsa_g);
- DSA_set0_key(dsa, dummy_pub_key, priv_key);
- return 1;
-}
-
-
-static int get_dss_public_key(ErlNifEnv* env, ERL_NIF_TERM key, DSA *dsa)
-{
- /* key=[P, Q, G, Y] */
- ERL_NIF_TERM head, tail;
- BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_y = NULL;
-
- if (!enif_get_list_cell(env, key, &head, &tail)
- || !get_bn_from_bin(env, head, &dsa_p)
- || !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_bin(env, head, &dsa_q)
- || !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_bin(env, head, &dsa_g)
- || !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_bin(env, head, &dsa_y)
- || !enif_is_empty_list(env,tail)) {
- if (dsa_p) BN_free(dsa_p);
- if (dsa_q) BN_free(dsa_q);
- if (dsa_g) BN_free(dsa_g);
- if (dsa_y) BN_free(dsa_y);
- return 0;
- }
-
- DSA_set0_pqg(dsa, dsa_p, dsa_q, dsa_g);
- DSA_set0_key(dsa, dsa_y, NULL);
- return 1;
-}
-
-/* Creates a term which can be parsed by get_rsa_private_key(). This is a list of plain integer binaries (not mpints). */
-static ERL_NIF_TERM put_rsa_private_key(ErlNifEnv* env, const RSA *rsa)
-{
- ERL_NIF_TERM result[8];
- const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp;
-
- /* Return at least [E,N,D] */
- n = NULL; e = NULL; d = NULL;
- RSA_get0_key(rsa, &n, &e, &d);
-
- result[0] = bin_from_bn(env, e); // Exponent E
- result[1] = bin_from_bn(env, n); // Modulus N = p*q
- result[2] = bin_from_bn(env, d); // Exponent D
-
- /* Check whether the optional additional parameters are available */
- p = NULL; q = NULL;
- RSA_get0_factors(rsa, &p, &q);
- dmp1 = NULL; dmq1 = NULL; iqmp = NULL;
- RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
-
- if (p && q && dmp1 && dmq1 && iqmp) {
- result[3] = bin_from_bn(env, p); // Factor p
- result[4] = bin_from_bn(env, q); // Factor q
- result[5] = bin_from_bn(env, dmp1); // D mod (p-1)
- result[6] = bin_from_bn(env, dmq1); // D mod (q-1)
- result[7] = bin_from_bn(env, iqmp); // (1/q) mod p
-
- return enif_make_list_from_array(env, result, 8);
- } else {
- return enif_make_list_from_array(env, result, 3);
- }
-}
-
-static int check_erlang_interrupt(int maj, int min, BN_GENCB *ctxt)
-{
- ErlNifEnv *env = BN_GENCB_get_arg(ctxt);
-
- if (!enif_is_current_process_alive(env)) {
- return 0;
- } else {
- return 1;
- }
-}
-
-static ERL_NIF_TERM rsa_generate_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (ModulusSize, PublicExponent) */
- int modulus_bits;
- BIGNUM *pub_exp, *three;
- RSA *rsa;
- int success;
- ERL_NIF_TERM result;
- BN_GENCB *intr_cb;
-#ifndef HAVE_OPAQUE_BN_GENCB
- BN_GENCB intr_cb_buf;
-#endif
-
- if (!enif_get_int(env, argv[0], &modulus_bits) || modulus_bits < 256) {
- return enif_make_badarg(env);
- }
-
- if (!get_bn_from_bin(env, argv[1], &pub_exp)) {
- return enif_make_badarg(env);
- }
-
- /* Make sure the public exponent is large enough (at least 3).
- * Without this, RSA_generate_key_ex() can run forever. */
- three = BN_new();
- BN_set_word(three, 3);
- success = BN_cmp(pub_exp, three);
- BN_free(three);
- if (success < 0) {
- BN_free(pub_exp);
- return enif_make_badarg(env);
- }
-
- /* For large keys, prime generation can take many seconds. Set up
- * the callback which we use to test whether the process has been
- * interrupted. */
-#ifdef HAVE_OPAQUE_BN_GENCB
- intr_cb = BN_GENCB_new();
-#else
- intr_cb = &intr_cb_buf;
-#endif
- BN_GENCB_set(intr_cb, check_erlang_interrupt, env);
-
- rsa = RSA_new();
- success = RSA_generate_key_ex(rsa, modulus_bits, pub_exp, intr_cb);
- BN_free(pub_exp);
-
-#ifdef HAVE_OPAQUE_BN_GENCB
- BN_GENCB_free(intr_cb);
-#endif
-
- if (!success) {
- RSA_free(rsa);
- return atom_error;
- }
-
- result = put_rsa_private_key(env, rsa);
- RSA_free(rsa);
-
- return result;
-}
-
-static ERL_NIF_TERM rsa_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{
- /* RSA key generation can take a long time (>1 sec for a large
- * modulus), so schedule it as a CPU-bound operation. */
- return enif_schedule_nif(env, "rsa_generate_key",
- ERL_NIF_DIRTY_JOB_CPU_BOUND,
- rsa_generate_key, argc, argv);
-}
-
-static ERL_NIF_TERM dh_generate_parameters_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (PrimeLen, Generator) */
- int prime_len, generator;
- DH* dh_params = NULL;
- int p_len, g_len;
- unsigned char *p_ptr, *g_ptr;
- ERL_NIF_TERM ret_p, ret_g;
- const BIGNUM *dh_p, *dh_q, *dh_g;
-
- if (!enif_get_int(env, argv[0], &prime_len)
- || !enif_get_int(env, argv[1], &generator)) {
-
- return enif_make_badarg(env);
- }
-
- if (DH_generate_parameters_ex(dh_params, prime_len, generator, NULL)) {
- return atom_error;
- }
- DH_get0_pqg(dh_params, &dh_p, &dh_q, &dh_g);
- DH_free(dh_params);
- p_len = BN_num_bytes(dh_p);
- g_len = BN_num_bytes(dh_g);
- p_ptr = enif_make_new_binary(env, p_len, &ret_p);
- g_ptr = enif_make_new_binary(env, g_len, &ret_g);
- BN_bn2bin(dh_p, p_ptr);
- BN_bn2bin(dh_g, g_ptr);
- ERL_VALGRIND_MAKE_MEM_DEFINED(p_ptr, p_len);
- ERL_VALGRIND_MAKE_MEM_DEFINED(g_ptr, g_len);
- return enif_make_list2(env, ret_p, ret_g);
-}
-
-static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* ([PrimeLen, Generator]) */
- DH* dh_params;
- int i;
- ERL_NIF_TERM ret, head, tail;
- BIGNUM *dh_p, *dh_g;
-
- if (!enif_get_list_cell(env, argv[0], &head, &tail)
- || !get_bn_from_bin(env, head, &dh_p)
- || !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_bin(env, head, &dh_g)
- || !enif_is_empty_list(env,tail)) {
-
- return enif_make_badarg(env);
- }
-
- dh_params = DH_new();
- DH_set0_pqg(dh_params, dh_p, NULL, dh_g);
- if (DH_check(dh_params, &i)) {
- if (i == 0) ret = atom_ok;
- else if (i & DH_CHECK_P_NOT_PRIME) ret = atom_not_prime;
- else if (i & DH_CHECK_P_NOT_SAFE_PRIME) ret = atom_not_strong_prime;
- else if (i & DH_UNABLE_TO_CHECK_GENERATOR) ret = atom_unable_to_check_generator;
- else if (i & DH_NOT_SUITABLE_GENERATOR) ret = atom_not_suitable_generator;
- else ret = enif_make_tuple2(env, atom_unknown, enif_make_uint(env, i));
- }
- else { /* Check Failed */
- ret = enif_make_tuple2(env, atom_error, atom_check_failed);
- }
- DH_free(dh_params);
- return ret;
-}
-
-static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (PrivKey|undefined, DHParams=[P,G], Mpint, Len|0) */
- DH* dh_params;
- int pub_len, prv_len;
- unsigned char *pub_ptr, *prv_ptr;
- ERL_NIF_TERM ret, ret_pub, ret_prv, head, tail;
- int mpint; /* 0 or 4 */
- BIGNUM *priv_key = NULL;
- BIGNUM *dh_p = NULL, *dh_g = NULL;
- unsigned long len = 0;
-
- if (!(get_bn_from_bin(env, argv[0], &priv_key)
- || argv[0] == atom_undefined)
- || !enif_get_list_cell(env, argv[1], &head, &tail)
- || !get_bn_from_bin(env, head, &dh_p)
- || !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_bin(env, head, &dh_g)
- || !enif_is_empty_list(env, tail)
- || !enif_get_int(env, argv[2], &mpint) || (mpint & ~4)
- || !enif_get_ulong(env, argv[3], &len) ) {
-
- if (priv_key) BN_free(priv_key);
- if (dh_p) BN_free(dh_p);
- if (dh_g) BN_free(dh_g);
- return enif_make_badarg(env);
- }
-
- dh_params = DH_new();
- DH_set0_key(dh_params, NULL, priv_key);
- DH_set0_pqg(dh_params, dh_p, NULL, dh_g);
-
- if (len) {
- if (len < BN_num_bits(dh_p))
- DH_set_length(dh_params, len);
- else {
- DH_free(dh_params);
- return enif_make_badarg(env);
- }
- }
-
- if (DH_generate_key(dh_params)) {
- const BIGNUM *pub_key, *priv_key;
- DH_get0_key(dh_params, &pub_key, &priv_key);
- pub_len = BN_num_bytes(pub_key);
- prv_len = BN_num_bytes(priv_key);
- pub_ptr = enif_make_new_binary(env, pub_len+mpint, &ret_pub);
- prv_ptr = enif_make_new_binary(env, prv_len+mpint, &ret_prv);
- if (mpint) {
- put_int32(pub_ptr, pub_len); pub_ptr += 4;
- put_int32(prv_ptr, prv_len); prv_ptr += 4;
- }
- BN_bn2bin(pub_key, pub_ptr);
- BN_bn2bin(priv_key, prv_ptr);
- ERL_VALGRIND_MAKE_MEM_DEFINED(pub_ptr, pub_len);
- ERL_VALGRIND_MAKE_MEM_DEFINED(prv_ptr, prv_len);
- ret = enif_make_tuple2(env, ret_pub, ret_prv);
- }
- else {
- ret = atom_error;
- }
- DH_free(dh_params);
- return ret;
-}
-
-static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (OthersPublicKey, MyPrivateKey, DHParams=[P,G]) */
- DH* dh_params;
- BIGNUM *dummy_pub_key = NULL, *priv_key = NULL;
- BIGNUM *other_pub_key;
- BIGNUM *dh_p = NULL, *dh_g = NULL;
- int i;
- ErlNifBinary ret_bin;
- ERL_NIF_TERM ret, head, tail;
-
- dh_params = DH_new();
-
- if (!get_bn_from_bin(env, argv[0], &other_pub_key)
- || !get_bn_from_bin(env, argv[1], &priv_key)
- || !enif_get_list_cell(env, argv[2], &head, &tail)
- || !get_bn_from_bin(env, head, &dh_p)
- || !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_bin(env, head, &dh_g)
- || !enif_is_empty_list(env, tail)) {
- if (dh_p) BN_free(dh_p);
- if (dh_g) BN_free(dh_g);
- ret = enif_make_badarg(env);
- }
- else {
- /* Note: DH_set0_key() does not allow setting only the
- * private key, although DH_compute_key() does not use the
- * public key. Work around this limitation by setting
- * the public key to a copy of the private key.
- */
- dummy_pub_key = BN_dup(priv_key);
- DH_set0_key(dh_params, dummy_pub_key, priv_key);
- DH_set0_pqg(dh_params, dh_p, NULL, dh_g);
- enif_alloc_binary(DH_size(dh_params), &ret_bin);
- i = DH_compute_key(ret_bin.data, other_pub_key, dh_params);
- if (i > 0) {
- if (i != ret_bin.size) {
- enif_realloc_binary(&ret_bin, i);
- }
- ret = enif_make_binary(env, &ret_bin);
- }
- else {
- enif_release_binary(&ret_bin);
- ret = atom_error;
- }
- }
- if (other_pub_key) BN_free(other_pub_key);
- DH_free(dh_params);
- return ret;
-}
-
-static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Multiplier, Verifier, Generator, Exponent, Prime) */
- BIGNUM *bn_verifier = NULL;
- BIGNUM *bn_exponent = NULL, *bn_generator = NULL, *bn_prime = NULL, *bn_multiplier = NULL, *bn_result;
- BN_CTX *bn_ctx;
- unsigned char* ptr;
- unsigned dlen;
- ERL_NIF_TERM ret;
-
- CHECK_NO_FIPS_MODE();
-
- if (!get_bn_from_bin(env, argv[0], &bn_multiplier)
- || !get_bn_from_bin(env, argv[1], &bn_verifier)
- || !get_bn_from_bin(env, argv[2], &bn_generator)
- || !get_bn_from_bin(env, argv[3], &bn_exponent)
- || !get_bn_from_bin(env, argv[4], &bn_prime)) {
- if (bn_multiplier) BN_free(bn_multiplier);
- if (bn_verifier) BN_free(bn_verifier);
- if (bn_generator) BN_free(bn_generator);
- if (bn_exponent) BN_free(bn_exponent);
- if (bn_prime) BN_free(bn_prime);
- return enif_make_badarg(env);
- }
-
- bn_result = BN_new();
- bn_ctx = BN_CTX_new();
-
- /* B = k*v + g^b % N */
-
- /* k * v */
- BN_mod_mul(bn_multiplier, bn_multiplier, bn_verifier, bn_prime, bn_ctx);
-
- /* g^b % N */
- BN_mod_exp(bn_result, bn_generator, bn_exponent, bn_prime, bn_ctx);
-
- /* k*v + g^b % N */
- BN_mod_add(bn_result, bn_result, bn_multiplier, bn_prime, bn_ctx);
-
- /* check that B % N != 0, reuse bn_multiplier */
- BN_nnmod(bn_multiplier, bn_result, bn_prime, bn_ctx);
- if (BN_is_zero(bn_multiplier)) {
- ret = atom_error;
- } else {
- dlen = BN_num_bytes(bn_result);
- ptr = enif_make_new_binary(env, dlen, &ret);
- BN_bn2bin(bn_result, ptr);
- }
- BN_free(bn_result);
- BN_CTX_free(bn_ctx);
- BN_free(bn_prime);
- BN_free(bn_generator);
- BN_free(bn_multiplier);
- BN_free(bn_exponent);
- BN_free(bn_verifier);
- return ret;
-}
-
-static ERL_NIF_TERM srp_user_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (a, u, B, Multiplier, Prime, Exponent, Generator) */
-/*
- <premaster secret> = (B - (k * g^x)) ^ (a + (u * x)) % N
-*/
- BIGNUM *bn_exponent = NULL, *bn_a = NULL;
- BIGNUM *bn_u = NULL, *bn_multiplier = NULL, *bn_exp2,
- *bn_base, *bn_prime = NULL, *bn_generator = NULL,
- *bn_B = NULL, *bn_result;
- BN_CTX *bn_ctx;
- unsigned char* ptr;
- unsigned dlen;
- ERL_NIF_TERM ret;
-
- CHECK_NO_FIPS_MODE();
-
- if (!get_bn_from_bin(env, argv[0], &bn_a)
- || !get_bn_from_bin(env, argv[1], &bn_u)
- || !get_bn_from_bin(env, argv[2], &bn_B)
- || !get_bn_from_bin(env, argv[3], &bn_multiplier)
- || !get_bn_from_bin(env, argv[4], &bn_generator)
- || !get_bn_from_bin(env, argv[5], &bn_exponent)
- || !get_bn_from_bin(env, argv[6], &bn_prime))
- {
- if (bn_exponent) BN_free(bn_exponent);
- if (bn_a) BN_free(bn_a);
- if (bn_u) BN_free(bn_u);
- if (bn_B) BN_free(bn_B);
- if (bn_multiplier) BN_free(bn_multiplier);
- if (bn_generator) BN_free(bn_generator);
- if (bn_prime) BN_free(bn_prime);
- return enif_make_badarg(env);
- }
-
- bn_ctx = BN_CTX_new();
- bn_result = BN_new();
-
- /* check that B % N != 0 */
- BN_nnmod(bn_result, bn_B, bn_prime, bn_ctx);
- if (BN_is_zero(bn_result)) {
- BN_free(bn_exponent);
- BN_free(bn_a);
- BN_free(bn_generator);
- BN_free(bn_prime);
- BN_free(bn_u);
- BN_free(bn_B);
- BN_CTX_free(bn_ctx);
-
- return atom_error;
- }
-
- /* (B - (k * g^x)) */
- bn_base = BN_new();
- BN_mod_exp(bn_result, bn_generator, bn_exponent, bn_prime, bn_ctx);
- BN_mod_mul(bn_result, bn_multiplier, bn_result, bn_prime, bn_ctx);
- BN_mod_sub(bn_base, bn_B, bn_result, bn_prime, bn_ctx);
-
- /* a + (u * x) */
- bn_exp2 = BN_new();
- BN_mul(bn_result, bn_u, bn_exponent, bn_ctx);
- BN_add(bn_exp2, bn_a, bn_result);
-
- /* (B - (k * g^x)) ^ (a + (u * x)) % N */
- BN_mod_exp(bn_result, bn_base, bn_exp2, bn_prime, bn_ctx);
-
- dlen = BN_num_bytes(bn_result);
- ptr = enif_make_new_binary(env, dlen, &ret);
- BN_bn2bin(bn_result, ptr);
- BN_free(bn_result);
- BN_CTX_free(bn_ctx);
-
- BN_free(bn_multiplier);
- BN_free(bn_exp2);
- BN_free(bn_u);
- BN_free(bn_exponent);
- BN_free(bn_a);
- BN_free(bn_B);
- BN_free(bn_base);
- BN_free(bn_generator);
- BN_free(bn_prime);
- return ret;
-}
-
-static ERL_NIF_TERM srp_host_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Verifier, b, u, A, Prime) */
-/*
- <premaster secret> = (A * v^u) ^ b % N
-*/
- BIGNUM *bn_b = NULL, *bn_verifier = NULL;
- BIGNUM *bn_prime = NULL, *bn_A = NULL, *bn_u = NULL, *bn_base, *bn_result;
- BN_CTX *bn_ctx;
- unsigned char* ptr;
- unsigned dlen;
- ERL_NIF_TERM ret;
-
- CHECK_NO_FIPS_MODE();
-
- if (!get_bn_from_bin(env, argv[0], &bn_verifier)
- || !get_bn_from_bin(env, argv[1], &bn_b)
- || !get_bn_from_bin(env, argv[2], &bn_u)
- || !get_bn_from_bin(env, argv[3], &bn_A)
- || !get_bn_from_bin(env, argv[4], &bn_prime))
- {
- if (bn_verifier) BN_free(bn_verifier);
- if (bn_b) BN_free(bn_b);
- if (bn_u) BN_free(bn_u);
- if (bn_A) BN_free(bn_A);
- if (bn_prime) BN_free(bn_prime);
- return enif_make_badarg(env);
- }
-
- bn_ctx = BN_CTX_new();
- bn_result = BN_new();
-
- /* check that A % N != 0 */
- BN_nnmod(bn_result, bn_A, bn_prime, bn_ctx);
- if (BN_is_zero(bn_result)) {
- BN_free(bn_b);
- BN_free(bn_verifier);
- BN_free(bn_prime);
- BN_free(bn_A);
- BN_CTX_free(bn_ctx);
-
- return atom_error;
- }
-
- /* (A * v^u) */
- bn_base = BN_new();
- BN_mod_exp(bn_base, bn_verifier, bn_u, bn_prime, bn_ctx);
- BN_mod_mul(bn_base, bn_A, bn_base, bn_prime, bn_ctx);
-
- /* (A * v^u) ^ b % N */
- BN_mod_exp(bn_result, bn_base, bn_b, bn_prime, bn_ctx);
-
- dlen = BN_num_bytes(bn_result);
- ptr = enif_make_new_binary(env, dlen, &ret);
- BN_bn2bin(bn_result, ptr);
- BN_free(bn_result);
- BN_CTX_free(bn_ctx);
-
- BN_free(bn_u);
- BN_free(bn_base);
- BN_free(bn_verifier);
- BN_free(bn_prime);
- BN_free(bn_A);
- BN_free(bn_b);
- return ret;
-}
-
-#if defined(HAVE_EC)
-static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg)
-{
- EC_KEY *key = NULL;
- int c_arity = -1;
- const ERL_NIF_TERM* curve;
- ErlNifBinary seed;
- BIGNUM *p = NULL;
- BIGNUM *a = NULL;
- BIGNUM *b = NULL;
- BIGNUM *bn_order = NULL;
- BIGNUM *cofactor = NULL;
- EC_GROUP *group = NULL;
- EC_POINT *point = NULL;
-
- /* {Field, Prime, Point, Order, CoFactor} = Curve */
- if (enif_get_tuple(env,curve_arg,&c_arity,&curve)
- && c_arity == 5
- && get_bn_from_bin(env, curve[3], &bn_order)
- && (curve[4] != atom_none && get_bn_from_bin(env, curve[4], &cofactor))) {
-
- int f_arity = -1;
- const ERL_NIF_TERM* field;
- int p_arity = -1;
- const ERL_NIF_TERM* prime;
-
- long field_bits;
-
- /* {A, B, Seed} = Prime */
- if (!enif_get_tuple(env,curve[1],&p_arity,&prime)
- || !get_bn_from_bin(env, prime[0], &a)
- || !get_bn_from_bin(env, prime[1], &b))
- goto out_err;
-
- if (!enif_get_tuple(env,curve[0],&f_arity,&field))
- goto out_err;
-
- if (f_arity == 2 && field[0] == atom_prime_field) {
- /* {prime_field, Prime} */
-
- if (!get_bn_from_bin(env, field[1], &p))
- goto out_err;
-
- if (BN_is_negative(p) || BN_is_zero(p))
- goto out_err;
-
- field_bits = BN_num_bits(p);
- if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS)
- goto out_err;
-
- /* create the EC_GROUP structure */
- group = EC_GROUP_new_curve_GFp(p, a, b, NULL);
-
- } else if (f_arity == 3 && field[0] == atom_characteristic_two_field) {
-#if defined(OPENSSL_NO_EC2M)
- enif_raise_exception(env, atom_notsup);
- goto out_err;
-#else
- /* {characteristic_two_field, M, Basis} */
-
- int b_arity = -1;
- const ERL_NIF_TERM* basis;
- unsigned int k1, k2, k3;
-
- if ((p = BN_new()) == NULL)
- goto out_err;
-
- if (!enif_get_long(env, field[1], &field_bits)
- || field_bits > OPENSSL_ECC_MAX_FIELD_BITS)
- goto out_err;
-
- if (enif_get_tuple(env,field[2],&b_arity,&basis)) {
- if (b_arity == 2
- && basis[0] == atom_tpbasis
- && enif_get_uint(env, basis[1], &k1)) {
- /* {tpbasis, k} = Basis */
-
- if (!(field_bits > k1 && k1 > 0))
- goto out_err;
-
- /* create the polynomial */
- if (!BN_set_bit(p, (int)field_bits)
- || !BN_set_bit(p, (int)k1)
- || !BN_set_bit(p, 0))
- goto out_err;
-
- } else if (b_arity == 4
- && basis[0] == atom_ppbasis
- && enif_get_uint(env, basis[1], &k1)
- && enif_get_uint(env, basis[2], &k2)
- && enif_get_uint(env, basis[3], &k3)) {
- /* {ppbasis, k1, k2, k3} = Basis */
-
- if (!(field_bits > k3 && k3 > k2 && k2 > k1 && k1 > 0))
- goto out_err;
-
- /* create the polynomial */
- if (!BN_set_bit(p, (int)field_bits)
- || !BN_set_bit(p, (int)k1)
- || !BN_set_bit(p, (int)k2)
- || !BN_set_bit(p, (int)k3)
- || !BN_set_bit(p, 0))
- goto out_err;
-
- } else
- goto out_err;
- } else if (field[2] == atom_onbasis) {
- /* onbasis = Basis */
- /* no parameters */
- goto out_err;
-
- } else
- goto out_err;
-
- group = EC_GROUP_new_curve_GF2m(p, a, b, NULL);
-#endif
- } else
- goto out_err;
-
- if (!group)
- goto out_err;
-
- if (enif_inspect_binary(env, prime[2], &seed)) {
- EC_GROUP_set_seed(group, seed.data, seed.size);
- }
-
- if (!term2point(env, curve[2], group, &point))
- goto out_err;
-
- if (BN_is_negative(bn_order)
- || BN_is_zero(bn_order)
- || BN_num_bits(bn_order) > (int)field_bits + 1)
- goto out_err;
-
- if (!EC_GROUP_set_generator(group, point, bn_order, cofactor))
- goto out_err;
-
- EC_GROUP_set_asn1_flag(group, 0x0);
-
- key = EC_KEY_new();
- if (!key)
- goto out_err;
- EC_KEY_set_group(key, group);
- }
- else {
- goto out_err;
- }
-
-
- goto out;
-
-out_err:
- if (key) EC_KEY_free(key);
- key = NULL;
-
-out:
- /* some OpenSSL structures are mem-dup'ed into the key,
- so we have to free our copies here */
- if (p) BN_free(p);
- if (a) BN_free(a);
- if (b) BN_free(b);
- if (bn_order) BN_free(bn_order);
- if (cofactor) BN_free(cofactor);
- if (group) EC_GROUP_free(group);
- if (point) EC_POINT_free(point);
-
- return key;
-}
-
-
-static ERL_NIF_TERM bn2term(ErlNifEnv* env, const BIGNUM *bn)
-{
- unsigned dlen;
- unsigned char* ptr;
- ERL_NIF_TERM ret;
-
- if (!bn)
- return atom_undefined;
-
- dlen = BN_num_bytes(bn);
- ptr = enif_make_new_binary(env, dlen, &ret);
- BN_bn2bin(bn, ptr);
- ERL_VALGRIND_MAKE_MEM_DEFINED(ptr, dlen);
- return ret;
-}
-
-static ERL_NIF_TERM point2term(ErlNifEnv* env,
- const EC_GROUP *group,
- const EC_POINT *point,
- point_conversion_form_t form)
-{
- unsigned dlen;
- ErlNifBinary bin;
-
- dlen = EC_POINT_point2oct(group, point, form, NULL, 0, NULL);
- if (dlen == 0)
- return atom_undefined;
-
- if (!enif_alloc_binary(dlen, &bin))
- return enif_make_badarg(env);
-
- if (!EC_POINT_point2oct(group, point, form, bin.data, bin.size, NULL)) {
- enif_release_binary(&bin);
- return enif_make_badarg(env);
- }
- ERL_VALGRIND_MAKE_MEM_DEFINED(bin.data, bin.size);
- return enif_make_binary(env, &bin);
-}
-
-static int term2point(ErlNifEnv* env, ERL_NIF_TERM term,
- EC_GROUP *group, EC_POINT **pptr)
-{
- int ret = 0;
- ErlNifBinary bin;
- EC_POINT *point;
-
- if (!enif_inspect_binary(env,term,&bin)) {
- return 0;
- }
-
- if ((*pptr = point = EC_POINT_new(group)) == NULL) {
- return 0;
- }
-
- /* set the point conversion form */
- EC_GROUP_set_point_conversion_form(group, (point_conversion_form_t)(bin.data[0] & ~0x01));
-
- /* extract the ec point */
- if (!EC_POINT_oct2point(group, point, bin.data, bin.size, NULL)) {
- EC_POINT_free(point);
- *pptr = NULL;
- } else
- ret = 1;
-
- return ret;
-}
-
-static int get_ec_key(ErlNifEnv* env,
- ERL_NIF_TERM curve, ERL_NIF_TERM priv, ERL_NIF_TERM pub,
- EC_KEY** res)
-{
- EC_KEY *key = NULL;
- BIGNUM *priv_key = NULL;
- EC_POINT *pub_key = NULL;
- EC_GROUP *group = NULL;
-
- if (!(priv == atom_undefined || get_bn_from_bin(env, priv, &priv_key))
- || !(pub == atom_undefined || enif_is_binary(env, pub))) {
- goto out_err;
- }
-
- key = ec_key_new(env, curve);
-
- if (!key) {
- goto out_err;
- }
-
- if (!group)
- group = EC_GROUP_dup(EC_KEY_get0_group(key));
-
- if (term2point(env, pub, group, &pub_key)) {
- if (!EC_KEY_set_public_key(key, pub_key)) {
- goto out_err;
- }
- }
- if (priv != atom_undefined
- && !BN_is_zero(priv_key)) {
- if (!EC_KEY_set_private_key(key, priv_key))
- goto out_err;
-
- /* calculate public key (if necessary) */
- if (EC_KEY_get0_public_key(key) == NULL)
- {
- /* the public key was not included in the SEC1 private
- * key => calculate the public key */
- pub_key = EC_POINT_new(group);
- if (pub_key == NULL
- || !EC_POINT_copy(pub_key, EC_GROUP_get0_generator(group))
- || !EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, NULL)
- || !EC_KEY_set_public_key(key, pub_key))
- goto out_err;
- }
- }
-
- goto out;
-
-out_err:
- if (key) EC_KEY_free(key);
- key = NULL;
-
-out:
- /* some OpenSSL structures are mem-dup'ed into the key,
- so we have to free our copies here */
- if (priv_key) BN_clear_free(priv_key);
- if (pub_key) EC_POINT_free(pub_key);
- if (group) EC_GROUP_free(group);
- if (!key)
- return 0;
- *res = key;
- return 1;
-}
-#endif /* HAVE_EC */
-
-static ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{
-#if defined(HAVE_EC)
- EC_KEY *key = NULL;
- const EC_GROUP *group;
- const EC_POINT *public_key;
- ERL_NIF_TERM priv_key;
- ERL_NIF_TERM pub_key = atom_undefined;
-
- if (!get_ec_key(env, argv[0], argv[1], atom_undefined, &key))
- goto badarg;
-
- if (argv[1] == atom_undefined) {
- if (!EC_KEY_generate_key(key))
- goto badarg;
- }
-
- group = EC_KEY_get0_group(key);
- public_key = EC_KEY_get0_public_key(key);
-
- if (group && public_key) {
- pub_key = point2term(env, group, public_key,
- EC_KEY_get_conv_form(key));
- }
- priv_key = bn2term(env, EC_KEY_get0_private_key(key));
- EC_KEY_free(key);
- return enif_make_tuple2(env, pub_key, priv_key);
-
-badarg:
- if (key)
- EC_KEY_free(key);
- return make_badarg_maybe(env);
-#else
- return atom_notsup;
-#endif
-}
-
-/*
- (_OthersPublicKey, _MyPrivateKey)
- (_OthersPublicKey, _MyEC_Point)
-*/
-static ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-/* (OtherPublicKey, Curve, My) */
-{
-#if defined(HAVE_EC)
- ERL_NIF_TERM ret;
- unsigned char *p;
- EC_KEY* key = NULL;
- int field_size = 0;
- int i;
- EC_GROUP *group;
- const BIGNUM *priv_key;
- EC_POINT *my_ecpoint;
- EC_KEY *other_ecdh = NULL;
-
- if (!get_ec_key(env, argv[1], argv[2], atom_undefined, &key))
- return make_badarg_maybe(env);
-
- group = EC_GROUP_dup(EC_KEY_get0_group(key));
- priv_key = EC_KEY_get0_private_key(key);
-
- if (!term2point(env, argv[0], group, &my_ecpoint)) {
- goto out_err;
- }
-
- if ((other_ecdh = EC_KEY_new()) == NULL
- || !EC_KEY_set_group(other_ecdh, group)
- || !EC_KEY_set_private_key(other_ecdh, priv_key))
- goto out_err;
-
- field_size = EC_GROUP_get_degree(group);
- if (field_size <= 0)
- goto out_err;
-
- p = enif_make_new_binary(env, (field_size+7)/8, &ret);
- i = ECDH_compute_key(p, (field_size+7)/8, my_ecpoint, other_ecdh, NULL);
-
- if (i < 0)
- goto out_err;
-out:
- if (group) EC_GROUP_free(group);
- if (my_ecpoint) EC_POINT_free(my_ecpoint);
- if (other_ecdh) EC_KEY_free(other_ecdh);
- if (key) EC_KEY_free(key);
-
- return ret;
-
-out_err:
- ret = enif_make_badarg(env);
- goto out;
-#else
- return atom_notsup;
-#endif
-}
-
-/*================================================================*/
-#define PKEY_BADARG -1
-#define PKEY_NOTSUP 0
-#define PKEY_OK 1
-
-typedef struct PKeyCryptOptions {
- const EVP_MD *rsa_mgf1_md;
- ErlNifBinary rsa_oaep_label;
- const EVP_MD *rsa_oaep_md;
- int rsa_padding;
- const EVP_MD *signature_md;
-} PKeyCryptOptions;
-
-typedef struct PKeySignOptions {
- const EVP_MD *rsa_mgf1_md;
- int rsa_padding;
- int rsa_pss_saltlen;
-} PKeySignOptions;
-
-static int get_pkey_digest_type(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM type,
- const EVP_MD **md)
-{
- struct digest_type_t *digp = NULL;
- *md = NULL;
-
- if (type == atom_none && algorithm == atom_rsa) return PKEY_OK;
-
- digp = get_digest_type(type);
- if (!digp) return PKEY_BADARG;
- if (!digp->md.p) return PKEY_NOTSUP;
-
- *md = digp->md.p;
- return PKEY_OK;
-}
-
-
-static int get_pkey_sign_digest(ErlNifEnv *env, ERL_NIF_TERM algorithm,
- ERL_NIF_TERM type, ERL_NIF_TERM data,
- unsigned char *md_value, const EVP_MD **mdp,
- unsigned char **tbsp, size_t *tbslenp)
-{
- int i;
- const ERL_NIF_TERM *tpl_terms;
- int tpl_arity;
- ErlNifBinary tbs_bin;
- EVP_MD_CTX *mdctx;
- const EVP_MD *md = *mdp;
- unsigned char *tbs = *tbsp;
- size_t tbslen = *tbslenp;
- unsigned int tbsleni;
-
- if ((i = get_pkey_digest_type(env, algorithm, type, &md)) != PKEY_OK) {
- return i;
- }
- if (enif_get_tuple(env, data, &tpl_arity, &tpl_terms)) {
- if (tpl_arity != 2 || tpl_terms[0] != atom_digest
- || !enif_inspect_binary(env, tpl_terms[1], &tbs_bin)
- || (md != NULL && tbs_bin.size != EVP_MD_size(md))) {
- return PKEY_BADARG;
- }
- /* We have a digest (= hashed text) in tbs_bin */
- tbs = tbs_bin.data;
- tbslen = tbs_bin.size;
- } else if (md == NULL) {
- if (!enif_inspect_binary(env, data, &tbs_bin)) {
- return PKEY_BADARG;
- }
- /* md == NULL, that is no hashing because DigestType argument was atom_none */
- tbs = tbs_bin.data;
- tbslen = tbs_bin.size;
- } else {
- if (!enif_inspect_binary(env, data, &tbs_bin)) {
- return PKEY_BADARG;
- }
- /* We have the cleartext in tbs_bin and the hash algo info in md */
- tbs = md_value;
- mdctx = EVP_MD_CTX_create();
- if (!mdctx) {
- return PKEY_BADARG;
- }
- /* Looks well, now hash the plain text into a digest according to md */
- if (EVP_DigestInit_ex(mdctx, md, NULL) <= 0) {
- EVP_MD_CTX_destroy(mdctx);
- return PKEY_BADARG;
- }
- if (EVP_DigestUpdate(mdctx, tbs_bin.data, tbs_bin.size) <= 0) {
- EVP_MD_CTX_destroy(mdctx);
- return PKEY_BADARG;
- }
- if (EVP_DigestFinal_ex(mdctx, tbs, &tbsleni) <= 0) {
- EVP_MD_CTX_destroy(mdctx);
- return PKEY_BADARG;
- }
- tbslen = (size_t)(tbsleni);
- EVP_MD_CTX_destroy(mdctx);
- }
-
- *mdp = md;
- *tbsp = tbs;
- *tbslenp = tbslen;
-
- return PKEY_OK;
-}
-
-
-static int get_pkey_sign_options(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM options,
- const EVP_MD *md, PKeySignOptions *opt)
-{
- ERL_NIF_TERM head, tail;
- const ERL_NIF_TERM *tpl_terms;
- int tpl_arity;
- const EVP_MD *opt_md;
- int i;
-
- if (!enif_is_list(env, options)) {
- return PKEY_BADARG;
- }
-
- /* defaults */
- if (algorithm == atom_rsa) {
- opt->rsa_mgf1_md = NULL;
- opt->rsa_padding = RSA_PKCS1_PADDING;
- opt->rsa_pss_saltlen = -2;
- }
-
- if (enif_is_empty_list(env, options)) {
- return PKEY_OK;
- }
-
- if (algorithm == atom_rsa) {
- tail = options;
- while (enif_get_list_cell(env, tail, &head, &tail)) {
- if (enif_get_tuple(env, head, &tpl_arity, &tpl_terms) && tpl_arity == 2) {
- if (tpl_terms[0] == atom_rsa_mgf1_md && enif_is_atom(env, tpl_terms[1])) {
- i = get_pkey_digest_type(env, algorithm, tpl_terms[1], &opt_md);
- if (i != PKEY_OK) {
- return i;
- }
- opt->rsa_mgf1_md = opt_md;
- } else if (tpl_terms[0] == atom_rsa_padding) {
- if (tpl_terms[1] == atom_rsa_pkcs1_padding) {
- opt->rsa_padding = RSA_PKCS1_PADDING;
- } else if (tpl_terms[1] == atom_rsa_pkcs1_pss_padding) {
-#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0)
- opt->rsa_padding = RSA_PKCS1_PSS_PADDING;
- if (opt->rsa_mgf1_md == NULL) {
- opt->rsa_mgf1_md = md;
- }
-#else
- return PKEY_NOTSUP;
-#endif
- } else if (tpl_terms[1] == atom_rsa_x931_padding) {
- opt->rsa_padding = RSA_X931_PADDING;
- } else if (tpl_terms[1] == atom_rsa_no_padding) {
- opt->rsa_padding = RSA_NO_PADDING;
- } else {
- return PKEY_BADARG;
- }
- } else if (tpl_terms[0] == atom_rsa_pss_saltlen) {
- if (!enif_get_int(env, tpl_terms[1], &(opt->rsa_pss_saltlen))
- || opt->rsa_pss_saltlen < -2) {
- return PKEY_BADARG;
- }
- } else {
- return PKEY_BADARG;
- }
- } else {
- return PKEY_BADARG;
- }
- }
- } else {
- return PKEY_BADARG;
- }
-
- return PKEY_OK;
-}
-
-
-#ifdef HAS_ENGINE_SUPPORT
-static int get_engine_and_key_id(ErlNifEnv *env, ERL_NIF_TERM key, char ** id, ENGINE **e)
-{
- ERL_NIF_TERM engine_res, key_id_term;
- struct engine_ctx *ctx;
- ErlNifBinary key_id_bin;
-
- if (!enif_get_map_value(env, key, atom_engine, &engine_res) ||
- !enif_get_resource(env, engine_res, engine_ctx_rtype, (void**)&ctx) ||
- !enif_get_map_value(env, key, atom_key_id, &key_id_term) ||
- !enif_inspect_binary(env, key_id_term, &key_id_bin)) {
- return 0;
- }
- else {
- *e = ctx->engine;
- return zero_terminate(key_id_bin, id);
- }
-}
-
-
-static char *get_key_password(ErlNifEnv *env, ERL_NIF_TERM key) {
- ERL_NIF_TERM tmp_term;
- ErlNifBinary pwd_bin;
- char *pwd;
- if (enif_get_map_value(env, key, atom_password, &tmp_term) &&
- enif_inspect_binary(env, tmp_term, &pwd_bin) &&
- zero_terminate(pwd_bin, &pwd)
- ) return pwd;
-
- return NULL;
-}
-
-static int zero_terminate(ErlNifBinary bin, char **buf) {
- *buf = enif_alloc(bin.size+1);
- if (!*buf)
- return 0;
- memcpy(*buf, bin.data, bin.size);
- *(*buf+bin.size) = 0;
- return 1;
-}
-#endif
-
-static int get_pkey_private_key(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM key, EVP_PKEY **pkey)
-{
- if (enif_is_map(env, key)) {
-#ifdef HAS_ENGINE_SUPPORT
- /* Use key stored in engine */
- ENGINE *e;
- char *id;
- char *password;
-
- if (!get_engine_and_key_id(env, key, &id, &e))
- return PKEY_BADARG;
- password = get_key_password(env, key);
- *pkey = ENGINE_load_private_key(e, id, NULL, password);
- if (!*pkey)
- return PKEY_BADARG;
- enif_free(id);
-#else
- return PKEY_BADARG;
-#endif
- }
- else if (algorithm == atom_rsa) {
- RSA *rsa = RSA_new();
-
- if (!get_rsa_private_key(env, key, rsa)) {
- RSA_free(rsa);
- return PKEY_BADARG;
- }
-
- *pkey = EVP_PKEY_new();
- if (!EVP_PKEY_assign_RSA(*pkey, rsa)) {
- EVP_PKEY_free(*pkey);
- RSA_free(rsa);
- return PKEY_BADARG;
- }
- } else if (algorithm == atom_ecdsa) {
-#if defined(HAVE_EC)
- EC_KEY *ec = NULL;
- const ERL_NIF_TERM *tpl_terms;
- int tpl_arity;
-
- if (enif_get_tuple(env, key, &tpl_arity, &tpl_terms) && tpl_arity == 2
- && enif_is_tuple(env, tpl_terms[0]) && enif_is_binary(env, tpl_terms[1])
- && get_ec_key(env, tpl_terms[0], tpl_terms[1], atom_undefined, &ec)) {
-
- *pkey = EVP_PKEY_new();
- if (!EVP_PKEY_assign_EC_KEY(*pkey, ec)) {
- EVP_PKEY_free(*pkey);
- EC_KEY_free(ec);
- return PKEY_BADARG;
- }
- } else {
- return PKEY_BADARG;
- }
-#else
- return PKEY_NOTSUP;
-#endif
- } else if (algorithm == atom_dss) {
- DSA *dsa = DSA_new();
-
- if (!get_dss_private_key(env, key, dsa)) {
- DSA_free(dsa);
- return PKEY_BADARG;
- }
-
- *pkey = EVP_PKEY_new();
- if (!EVP_PKEY_assign_DSA(*pkey, dsa)) {
- EVP_PKEY_free(*pkey);
- DSA_free(dsa);
- return PKEY_BADARG;
- }
- } else {
- return PKEY_BADARG;
- }
-
- return PKEY_OK;
-}
-
-
-static int get_pkey_public_key(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM key,
- EVP_PKEY **pkey)
-{
- if (enif_is_map(env, key)) {
-#ifdef HAS_ENGINE_SUPPORT
- /* Use key stored in engine */
- ENGINE *e;
- char *id;
- char *password;
-
- if (!get_engine_and_key_id(env, key, &id, &e))
- return PKEY_BADARG;
- password = get_key_password(env, key);
- *pkey = ENGINE_load_public_key(e, id, NULL, password);
- if (!pkey)
- return PKEY_BADARG;
- enif_free(id);
-#else
- return PKEY_BADARG;
-#endif
- } else if (algorithm == atom_rsa) {
- RSA *rsa = RSA_new();
-
- if (!get_rsa_public_key(env, key, rsa)) {
- RSA_free(rsa);
- return PKEY_BADARG;
- }
-
- *pkey = EVP_PKEY_new();
- if (!EVP_PKEY_assign_RSA(*pkey, rsa)) {
- EVP_PKEY_free(*pkey);
- RSA_free(rsa);
- return PKEY_BADARG;
- }
- } else if (algorithm == atom_ecdsa) {
-#if defined(HAVE_EC)
- EC_KEY *ec = NULL;
- const ERL_NIF_TERM *tpl_terms;
- int tpl_arity;
-
- if (enif_get_tuple(env, key, &tpl_arity, &tpl_terms) && tpl_arity == 2
- && enif_is_tuple(env, tpl_terms[0]) && enif_is_binary(env, tpl_terms[1])
- && get_ec_key(env, tpl_terms[0], atom_undefined, tpl_terms[1], &ec)) {
-
- *pkey = EVP_PKEY_new();
- if (!EVP_PKEY_assign_EC_KEY(*pkey, ec)) {
- EVP_PKEY_free(*pkey);
- EC_KEY_free(ec);
- return PKEY_BADARG;
- }
- } else {
- return PKEY_BADARG;
- }
-#else
- return PKEY_NOTSUP;
-#endif
- } else if (algorithm == atom_dss) {
- DSA *dsa = DSA_new();
-
- if (!get_dss_public_key(env, key, dsa)) {
- DSA_free(dsa);
- return PKEY_BADARG;
- }
-
- *pkey = EVP_PKEY_new();
- if (!EVP_PKEY_assign_DSA(*pkey, dsa)) {
- EVP_PKEY_free(*pkey);
- DSA_free(dsa);
- return PKEY_BADARG;
- }
- } else {
- return PKEY_BADARG;
- }
-
- return PKEY_OK;
-}
-
-static ERL_NIF_TERM pkey_sign_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
-{/* (Algorithm, Type, Data|{digest,Digest}, Key|#{}, Options) */
- int i;
- const EVP_MD *md = NULL;
- unsigned char md_value[EVP_MAX_MD_SIZE];
- EVP_PKEY *pkey;
-#ifdef HAS_EVP_PKEY_CTX
- EVP_PKEY_CTX *ctx;
- size_t siglen;
-#else
- unsigned len, siglen;
-#endif
- PKeySignOptions sig_opt;
- ErlNifBinary sig_bin; /* signature */
- unsigned char *tbs; /* data to be signed */
- size_t tbslen;
-/*char buf[1024];
-enif_get_atom(env,argv[0],buf,1024,ERL_NIF_LATIN1); printf("algo=%s ",buf);
-enif_get_atom(env,argv[1],buf,1024,ERL_NIF_LATIN1); printf("hash=%s ",buf);
-printf("\r\n");
-*/
-
-#ifndef HAS_ENGINE_SUPPORT
- if (enif_is_map(env, argv[3])) {
- return atom_notsup;
- }
-#endif
-
- i = get_pkey_sign_digest(env, argv[0], argv[1], argv[2], md_value, &md, &tbs, &tbslen);
- if (i != PKEY_OK) {
- if (i == PKEY_NOTSUP)
- return atom_notsup;
- else
- return enif_make_badarg(env);
- }
-
- i = get_pkey_sign_options(env, argv[0], argv[4], md, &sig_opt);
- if (i != PKEY_OK) {
- if (i == PKEY_NOTSUP)
- return atom_notsup;
- else
- return enif_make_badarg(env);
- }
-
- if (get_pkey_private_key(env, argv[0], argv[3], &pkey) != PKEY_OK) {
- return enif_make_badarg(env);
- }
-
-#ifdef HAS_EVP_PKEY_CTX
- ctx = EVP_PKEY_CTX_new(pkey, NULL);
- if (!ctx) goto badarg;
-
- if (EVP_PKEY_sign_init(ctx) <= 0) goto badarg;
- if (md != NULL && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) goto badarg;
-
- if (argv[0] == atom_rsa) {
- if (EVP_PKEY_CTX_set_rsa_padding(ctx, sig_opt.rsa_padding) <= 0) goto badarg;
- if (sig_opt.rsa_padding == RSA_PKCS1_PSS_PADDING) {
- if (sig_opt.rsa_mgf1_md != NULL) {
-#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,1)
- if (EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, sig_opt.rsa_mgf1_md) <= 0) goto badarg;
-#else
- EVP_PKEY_CTX_free(ctx);
- EVP_PKEY_free(pkey);
- return atom_notsup;
-#endif
- }
- if (sig_opt.rsa_pss_saltlen > -2
- && EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, sig_opt.rsa_pss_saltlen) <= 0)
- goto badarg;
- }
- }
-
- if (EVP_PKEY_sign(ctx, NULL, &siglen, tbs, tbslen) <= 0) goto badarg;
- enif_alloc_binary(siglen, &sig_bin);
-
- if (md != NULL) {
- ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, EVP_MD_size(md));
- }
- i = EVP_PKEY_sign(ctx, sig_bin.data, &siglen, tbs, tbslen);
-
- EVP_PKEY_CTX_free(ctx);
-#else
-/*printf("Old interface\r\n");
- */
- if (argv[0] == atom_rsa) {
- RSA *rsa = EVP_PKEY_get1_RSA(pkey);
- enif_alloc_binary(RSA_size(rsa), &sig_bin);
- len = EVP_MD_size(md);
- ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, len);
- i = RSA_sign(md->type, tbs, len, sig_bin.data, &siglen, rsa);
- RSA_free(rsa);
- } else if (argv[0] == atom_dss) {
- DSA *dsa = EVP_PKEY_get1_DSA(pkey);
- enif_alloc_binary(DSA_size(dsa), &sig_bin);
- len = EVP_MD_size(md);
- ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, len);
- i = DSA_sign(md->type, tbs, len, sig_bin.data, &siglen, dsa);
- DSA_free(dsa);
- } else if (argv[0] == atom_ecdsa) {
-#if defined(HAVE_EC)
- EC_KEY *ec = EVP_PKEY_get1_EC_KEY(pkey);
- enif_alloc_binary(ECDSA_size(ec), &sig_bin);
- len = EVP_MD_size(md);
- ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, len);
- i = ECDSA_sign(md->type, tbs, len, sig_bin.data, &siglen, ec);
- EC_KEY_free(ec);
-#else
- EVP_PKEY_free(pkey);
- return atom_notsup;
-#endif
- } else {
- goto badarg;
- }
-#endif
-
- EVP_PKEY_free(pkey);
- if (i == 1) {
- ERL_VALGRIND_MAKE_MEM_DEFINED(sig_bin.data, siglen);
- if (siglen != sig_bin.size) {
- enif_realloc_binary(&sig_bin, siglen);
- ERL_VALGRIND_ASSERT_MEM_DEFINED(sig_bin.data, siglen);
- }
- return enif_make_binary(env, &sig_bin);
- } else {
- enif_release_binary(&sig_bin);
- return atom_error;
- }
-
- badarg:
-#ifdef HAS_EVP_PKEY_CTX
- EVP_PKEY_CTX_free(ctx);
-#endif
- EVP_PKEY_free(pkey);
- return enif_make_badarg(env);
-}
-
-
-static ERL_NIF_TERM pkey_verify_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
-{/* (Algorithm, Type, Data|{digest,Digest}, Signature, Key, Options) */
- int i;
- const EVP_MD *md = NULL;
- unsigned char md_value[EVP_MAX_MD_SIZE];
- EVP_PKEY *pkey;
-#ifdef HAS_EVP_PKEY_CTX
- EVP_PKEY_CTX *ctx;
-#else
-#endif
- PKeySignOptions sig_opt;
- ErlNifBinary sig_bin; /* signature */
- unsigned char *tbs; /* data to be signed */
- size_t tbslen;
-
-#ifndef HAS_ENGINE_SUPPORT
- if (enif_is_map(env, argv[4])) {
- return atom_notsup;
- }
-#endif
-
- if (!enif_inspect_binary(env, argv[3], &sig_bin)) {
- return enif_make_badarg(env);
- }
-
- i = get_pkey_sign_digest(env, argv[0], argv[1], argv[2], md_value, &md, &tbs, &tbslen);
- if (i != PKEY_OK) {
- if (i == PKEY_NOTSUP)
- return atom_notsup;
- else
- return enif_make_badarg(env);
- }
-
- i = get_pkey_sign_options(env, argv[0], argv[5], md, &sig_opt);
- if (i != PKEY_OK) {
- if (i == PKEY_NOTSUP)
- return atom_notsup;
- else
- return enif_make_badarg(env);
- }
-
- if (get_pkey_public_key(env, argv[0], argv[4], &pkey) != PKEY_OK) {
- return enif_make_badarg(env);
- }
-
-#ifdef HAS_EVP_PKEY_CTX
-/* printf("EVP interface\r\n");
- */
- ctx = EVP_PKEY_CTX_new(pkey, NULL);
- if (!ctx) goto badarg;
- if (EVP_PKEY_verify_init(ctx) <= 0) goto badarg;
- if (md != NULL && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) goto badarg;
-
- if (argv[0] == atom_rsa) {
- if (EVP_PKEY_CTX_set_rsa_padding(ctx, sig_opt.rsa_padding) <= 0) goto badarg;
- if (sig_opt.rsa_padding == RSA_PKCS1_PSS_PADDING) {
- if (sig_opt.rsa_mgf1_md != NULL) {
-#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,1)
- if (EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, sig_opt.rsa_mgf1_md) <= 0) goto badarg;
-#else
- EVP_PKEY_CTX_free(ctx);
- EVP_PKEY_free(pkey);
- return atom_notsup;
-#endif
- }
- if (sig_opt.rsa_pss_saltlen > -2
- && EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, sig_opt.rsa_pss_saltlen) <= 0)
- goto badarg;
- }
- }
-
- if (md != NULL) {
- ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, EVP_MD_size(md));
- }
- i = EVP_PKEY_verify(ctx, sig_bin.data, sig_bin.size, tbs, tbslen);
-
- EVP_PKEY_CTX_free(ctx);
-#else
-/*printf("Old interface\r\n");
-*/
- if (argv[0] == atom_rsa) {
- RSA *rsa = EVP_PKEY_get1_RSA(pkey);
- i = RSA_verify(md->type, tbs, tbslen, sig_bin.data, sig_bin.size, rsa);
- RSA_free(rsa);
- } else if (argv[0] == atom_dss) {
- DSA *dsa = EVP_PKEY_get1_DSA(pkey);
- i = DSA_verify(0, tbs, tbslen, sig_bin.data, sig_bin.size, dsa);
- DSA_free(dsa);
- } else if (argv[0] == atom_ecdsa) {
-#if defined(HAVE_EC)
- EC_KEY *ec = EVP_PKEY_get1_EC_KEY(pkey);
- i = ECDSA_verify(EVP_MD_type(md), tbs, tbslen, sig_bin.data, sig_bin.size, ec);
- EC_KEY_free(ec);
-#else
- EVP_PKEY_free(pkey);
- return atom_notsup;
-#endif
- } else {
- goto badarg;
- }
-#endif
-
- EVP_PKEY_free(pkey);
- if (i == 1) {
- return atom_true;
- } else {
- return atom_false;
- }
-
- badarg:
-#ifdef HAS_EVP_PKEY_CTX
- EVP_PKEY_CTX_free(ctx);
-#endif
- EVP_PKEY_free(pkey);
- return enif_make_badarg(env);
-}
-
-
-/*--------------------------------*/
-
-static int get_pkey_crypt_options(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM options,
- PKeyCryptOptions *opt)
-{
- ERL_NIF_TERM head, tail;
- const ERL_NIF_TERM *tpl_terms;
- int tpl_arity;
- const EVP_MD *opt_md;
- int i;
-
- if (!enif_is_list(env, options)) {
- return PKEY_BADARG;
- }
-
- /* defaults */
- if (algorithm == atom_rsa) {
- opt->rsa_mgf1_md = NULL;
- opt->rsa_oaep_label.data = NULL;
- opt->rsa_oaep_label.size = 0;
- opt->rsa_oaep_md = NULL;
- opt->rsa_padding = RSA_PKCS1_PADDING;
- opt->signature_md = NULL;
- }
-
- if (enif_is_empty_list(env, options)) {
- return PKEY_OK;
- }
-
- if (algorithm == atom_rsa) {
- tail = options;
- while (enif_get_list_cell(env, tail, &head, &tail)) {
- if (enif_get_tuple(env, head, &tpl_arity, &tpl_terms) && tpl_arity == 2) {
- if (tpl_terms[0] == atom_rsa_padding
- || tpl_terms[0] == atom_rsa_pad /* Compatibility */
- ) {
- if (tpl_terms[1] == atom_rsa_pkcs1_padding) {
- opt->rsa_padding = RSA_PKCS1_PADDING;
- } else if (tpl_terms[1] == atom_rsa_pkcs1_oaep_padding) {
- opt->rsa_padding = RSA_PKCS1_OAEP_PADDING;
-#ifdef HAVE_RSA_SSLV23_PADDING
- } else if (tpl_terms[1] == atom_rsa_sslv23_padding) {
- opt->rsa_padding = RSA_SSLV23_PADDING;
-#endif
- } else if (tpl_terms[1] == atom_rsa_x931_padding) {
- opt->rsa_padding = RSA_X931_PADDING;
- } else if (tpl_terms[1] == atom_rsa_no_padding) {
- opt->rsa_padding = RSA_NO_PADDING;
- } else {
- return PKEY_BADARG;
- }
- } else if (tpl_terms[0] == atom_signature_md && enif_is_atom(env, tpl_terms[1])) {
- i = get_pkey_digest_type(env, algorithm, tpl_terms[1], &opt_md);
- if (i != PKEY_OK) {
- return i;
- }
- opt->signature_md = opt_md;
- } else if (tpl_terms[0] == atom_rsa_mgf1_md && enif_is_atom(env, tpl_terms[1])) {
-#ifndef HAVE_RSA_OAEP_MD
- if (tpl_terms[1] != atom_sha)
- return PKEY_NOTSUP;
-#endif
- i = get_pkey_digest_type(env, algorithm, tpl_terms[1], &opt_md);
- if (i != PKEY_OK) {
- return i;
- }
- opt->rsa_mgf1_md = opt_md;
- } else if (tpl_terms[0] == atom_rsa_oaep_label
- && enif_inspect_binary(env, tpl_terms[1], &(opt->rsa_oaep_label))) {
-#ifdef HAVE_RSA_OAEP_MD
- continue;
-#else
- return PKEY_NOTSUP;
-#endif
- } else if (tpl_terms[0] == atom_rsa_oaep_md && enif_is_atom(env, tpl_terms[1])) {
-#ifndef HAVE_RSA_OAEP_MD
- if (tpl_terms[1] != atom_sha)
- return PKEY_NOTSUP;
-#endif
- i = get_pkey_digest_type(env, algorithm, tpl_terms[1], &opt_md);
- if (i != PKEY_OK) {
- return i;
- }
- opt->rsa_oaep_md = opt_md;
- } else {
- return PKEY_BADARG;
- }
- } else {
- return PKEY_BADARG;
- }
- }
- } else {
- return PKEY_BADARG;
- }
-
- return PKEY_OK;
-}
-
-static ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
-{/* (Algorithm, Data, PublKey=[E,N]|[E,N,D]|[E,N,D,P1,P2,E1,E2,C], Options, IsPrivate, IsEncrypt) */
- int i;
- EVP_PKEY *pkey;
-#ifdef HAS_EVP_PKEY_CTX
- EVP_PKEY_CTX *ctx;
-#else
- RSA *rsa;
-#endif
- PKeyCryptOptions crypt_opt;
- ErlNifBinary in_bin, out_bin, tmp_bin;
- size_t outlen;
-#ifdef HAVE_RSA_SSLV23_PADDING
- size_t tmplen;
-#endif
- int is_private = (argv[4] == atom_true),
- is_encrypt = (argv[5] == atom_true);
- int algo_init = 0;
-
-/* char algo[1024]; */
-
-#ifndef HAS_ENGINE_SUPPORT
- if (enif_is_map(env, argv[2])) {
- return atom_notsup;
- }
-#endif
-
- if (!enif_inspect_binary(env, argv[1], &in_bin)) {
- return enif_make_badarg(env);
- }
-
- i = get_pkey_crypt_options(env, argv[0], argv[3], &crypt_opt);
- if (i != PKEY_OK) {
- if (i == PKEY_NOTSUP)
- return atom_notsup;
- else
- return enif_make_badarg(env);
- }
-
- if (is_private) {
- if (get_pkey_private_key(env, argv[0], argv[2], &pkey) != PKEY_OK) {
- return enif_make_badarg(env);
- }
- } else {
- if (get_pkey_public_key(env, argv[0], argv[2], &pkey) != PKEY_OK) {
- return enif_make_badarg(env);
- }
- }
-
- out_bin.data = NULL;
- out_bin.size = 0;
- tmp_bin.data = NULL;
- tmp_bin.size = 0;
-
-#ifdef HAS_EVP_PKEY_CTX
- ctx = EVP_PKEY_CTX_new(pkey, NULL);
- if (!ctx) goto badarg;
-
-/* enif_get_atom(env,argv[0],algo,1024,ERL_NIF_LATIN1); */
-
- if (is_private) {
- if (is_encrypt) {
- /* private encrypt */
- if ((algo_init=EVP_PKEY_sign_init(ctx)) <= 0) {
- /* fprintf(stderr,"BADARG %s private encrypt algo_init=%d %s:%d\r\n", algo, algo_init, __FILE__, __LINE__); */
- goto badarg;
- }
- } else {
- /* private decrypt */
- if ((algo_init=EVP_PKEY_decrypt_init(ctx)) <= 0) {
- /* fprintf(stderr,"BADARG %s private decrypt algo_init=%d %s:%d\r\n", algo, algo_init, __FILE__, __LINE__); */
- goto badarg;
- }
- }
- } else {
- if (is_encrypt) {
- /* public encrypt */
- if ((algo_init=EVP_PKEY_encrypt_init(ctx)) <= 0) {
- /* fprintf(stderr,"BADARG %s public encrypt algo_init=%d %s:%d\r\n", algo,algo_init,__FILE__, __LINE__); */
- goto badarg;
- }
- } else {
- /* public decrypt */
- if ((algo_init=EVP_PKEY_verify_recover_init(ctx)) <= 0) {
- /* fprintf(stderr,"BADARG %s public decrypt algo_init=%d %s:%d\r\n", algo,algo_init,__FILE__, __LINE__); */
- goto badarg;
- }
- }
- }
-
- if (argv[0] == atom_rsa) {
- if (crypt_opt.signature_md != NULL
- && EVP_PKEY_CTX_set_signature_md(ctx, crypt_opt.signature_md) <= 0)
- goto badarg;
-#ifdef HAVE_RSA_SSLV23_PADDING
- if (crypt_opt.rsa_padding == RSA_SSLV23_PADDING) {
- if (is_encrypt) {
- RSA *rsa = EVP_PKEY_get1_RSA(pkey);
- if (rsa == NULL) goto badarg;
- tmplen = RSA_size(rsa);
- if (!enif_alloc_binary(tmplen, &tmp_bin)) goto badarg;
- if (RSA_padding_add_SSLv23(tmp_bin.data, tmplen, in_bin.data, in_bin.size) <= 0)
- goto badarg;
- in_bin = tmp_bin;
- }
- if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING) <= 0) goto badarg;
- } else
-#endif
- {
- if (EVP_PKEY_CTX_set_rsa_padding(ctx, crypt_opt.rsa_padding) <= 0) goto badarg;
- }
-#ifdef HAVE_RSA_OAEP_MD
- if (crypt_opt.rsa_padding == RSA_PKCS1_OAEP_PADDING) {
- if (crypt_opt.rsa_oaep_md != NULL
- && EVP_PKEY_CTX_set_rsa_oaep_md(ctx, crypt_opt.rsa_oaep_md) <= 0)
- goto badarg;
- if (crypt_opt.rsa_mgf1_md != NULL
- && EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, crypt_opt.rsa_mgf1_md) <= 0) goto badarg;
- if (crypt_opt.rsa_oaep_label.data != NULL && crypt_opt.rsa_oaep_label.size > 0) {
- unsigned char *label_copy;
- label_copy = OPENSSL_malloc(crypt_opt.rsa_oaep_label.size);
- if (label_copy == NULL) goto badarg;
- memcpy((void *)(label_copy), (const void *)(crypt_opt.rsa_oaep_label.data),
- crypt_opt.rsa_oaep_label.size);
- if (EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, label_copy,
- crypt_opt.rsa_oaep_label.size) <= 0) {
- OPENSSL_free(label_copy);
- label_copy = NULL;
- goto badarg;
- }
- }
- }
-#endif
- }
-
- if (is_private) {
- if (is_encrypt) {
- /* private_encrypt */
- i = EVP_PKEY_sign(ctx, NULL, &outlen, in_bin.data, in_bin.size);
- } else {
- /* private_decrypt */
- i = EVP_PKEY_decrypt(ctx, NULL, &outlen, in_bin.data, in_bin.size);
- }
- } else {
- if (is_encrypt) {
- /* public_encrypt */
- i = EVP_PKEY_encrypt(ctx, NULL, &outlen, in_bin.data, in_bin.size);
- } else {
- /* public_decrypt */
- i = EVP_PKEY_verify_recover(ctx, NULL, &outlen, in_bin.data, in_bin.size);
- }
- }
- /* fprintf(stderr,"i = %d %s:%d\r\n", i, __FILE__, __LINE__); */
-
- if (i != 1) goto badarg;
-
- enif_alloc_binary(outlen, &out_bin);
-
- if (is_private) {
- if (is_encrypt) {
- /* private_encrypt */
- i = EVP_PKEY_sign(ctx, out_bin.data, &outlen, in_bin.data, in_bin.size);
- } else {
- /* private_decrypt */
- i = EVP_PKEY_decrypt(ctx, out_bin.data, &outlen, in_bin.data, in_bin.size);
- }
- } else {
- if (is_encrypt) {
- /* public_encrypt */
- i = EVP_PKEY_encrypt(ctx, out_bin.data, &outlen, in_bin.data, in_bin.size);
- } else {
- /* public_decrypt */
- i = EVP_PKEY_verify_recover(ctx, out_bin.data, &outlen, in_bin.data, in_bin.size);
- }
- }
-
-#else
- /* Non-EVP cryptolib. Only support RSA */
-
- if (argv[0] != atom_rsa) {
- algo_init = -2; /* exitcode: notsup */
- goto badarg;
- }
- rsa = EVP_PKEY_get1_RSA(pkey);
- enif_alloc_binary(RSA_size(rsa), &out_bin);
-
- if (is_private) {
- if (is_encrypt) {
- /* non-evp rsa private encrypt */
- ERL_VALGRIND_ASSERT_MEM_DEFINED(in_bin.data,in_bin.size);
- i = RSA_private_encrypt(in_bin.size, in_bin.data,
- out_bin.data, rsa, crypt_opt.rsa_padding);
- if (i > 0) {
- ERL_VALGRIND_MAKE_MEM_DEFINED(out_bin.data, i);
- }
- } else {
- /* non-evp rsa private decrypt */
- i = RSA_private_decrypt(in_bin.size, in_bin.data,
- out_bin.data, rsa, crypt_opt.rsa_padding);
- if (i > 0) {
- ERL_VALGRIND_MAKE_MEM_DEFINED(out_bin.data, i);
- enif_realloc_binary(&out_bin, i);
- }
- }
- } else {
- if (is_encrypt) {
- /* non-evp rsa public encrypt */
- ERL_VALGRIND_ASSERT_MEM_DEFINED(in_bin.data,in_bin.size);
- i = RSA_public_encrypt(in_bin.size, in_bin.data,
- out_bin.data, rsa, crypt_opt.rsa_padding);
- if (i > 0) {
- ERL_VALGRIND_MAKE_MEM_DEFINED(out_bin.data, i);
- }
- } else {
- /* non-evp rsa public decrypt */
- i = RSA_public_decrypt(in_bin.size, in_bin.data,
- out_bin.data, rsa, crypt_opt.rsa_padding);
- if (i > 0) {
- ERL_VALGRIND_MAKE_MEM_DEFINED(out_bin.data, i);
- enif_realloc_binary(&out_bin, i);
- }
- }
- }
-
- outlen = i;
- RSA_free(rsa);
-#endif
-
- if ((i > 0) && argv[0] == atom_rsa && !is_encrypt) {
-#ifdef HAVE_RSA_SSLV23_PADDING
- if (crypt_opt.rsa_padding == RSA_SSLV23_PADDING) {
- RSA *rsa = EVP_PKEY_get1_RSA(pkey);
- unsigned char *p;
- if (rsa == NULL) goto badarg;
- tmplen = RSA_size(rsa);
- if (!enif_alloc_binary(tmplen, &tmp_bin)) goto badarg;
- p = out_bin.data;
- p++;
- i = RSA_padding_check_SSLv23(tmp_bin.data, tmplen, p, out_bin.size - 1, tmplen);
- if (i >= 0) {
- outlen = i;
- in_bin = out_bin;
- out_bin = tmp_bin;
- tmp_bin = in_bin;
- i = 1;
- }
- }
-#endif
- }
-
- if (tmp_bin.data != NULL) {
- enif_release_binary(&tmp_bin);
- }
-
-#ifdef HAS_EVP_PKEY_CTX
- EVP_PKEY_CTX_free(ctx);
-#else
-#endif
- EVP_PKEY_free(pkey);
- if (i > 0) {
- ERL_VALGRIND_MAKE_MEM_DEFINED(out_bin.data, outlen);
- if (outlen != out_bin.size) {
- enif_realloc_binary(&out_bin, outlen);
- ERL_VALGRIND_ASSERT_MEM_DEFINED(out_bin.data, outlen);
- }
- return enif_make_binary(env, &out_bin);
- } else {
- enif_release_binary(&out_bin);
- return atom_error;
- }
-
- badarg:
- if (out_bin.data != NULL) {
- enif_release_binary(&out_bin);
- }
- if (tmp_bin.data != NULL) {
- enif_release_binary(&tmp_bin);
- }
-#ifdef HAS_EVP_PKEY_CTX
- EVP_PKEY_CTX_free(ctx);
-#else
-#endif
- EVP_PKEY_free(pkey);
- if (algo_init == -2)
- return atom_notsup;
- else
- return enif_make_badarg(env);
-}
-
-
-
-/*--------------------------------*/
-static ERL_NIF_TERM privkey_to_pubkey_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{ /* (Algorithm, PrivKey | KeyMap) */
- EVP_PKEY *pkey;
- ERL_NIF_TERM alg = argv[0];
- ERL_NIF_TERM result[8];
- if (get_pkey_private_key(env, alg, argv[1], &pkey) != PKEY_OK) {
- return enif_make_badarg(env);
- }
-
- if (alg == atom_rsa) {
- const BIGNUM *n = NULL, *e = NULL, *d = NULL;
- RSA *rsa = EVP_PKEY_get1_RSA(pkey);
- if (rsa) {
- RSA_get0_key(rsa, &n, &e, &d);
- result[0] = bin_from_bn(env, e); // Exponent E
- result[1] = bin_from_bn(env, n); // Modulus N = p*q
- EVP_PKEY_free(pkey);
- return enif_make_list_from_array(env, result, 2);
- }
-
- } else if (argv[0] == atom_dss) {
- const BIGNUM *p = NULL, *q = NULL, *g = NULL, *pub_key = NULL;
- DSA *dsa = EVP_PKEY_get1_DSA(pkey);
- if (dsa) {
- DSA_get0_pqg(dsa, &p, &q, &g);
- DSA_get0_key(dsa, &pub_key, NULL);
- result[0] = bin_from_bn(env, p);
- result[1] = bin_from_bn(env, q);
- result[2] = bin_from_bn(env, g);
- result[3] = bin_from_bn(env, pub_key);
- EVP_PKEY_free(pkey);
- return enif_make_list_from_array(env, result, 4);
- }
-
- } else if (argv[0] == atom_ecdsa) {
-#if defined(HAVE_EC)
- /* not yet implemented
- EC_KEY *ec = EVP_PKEY_get1_EC_KEY(pkey);
- if (ec) {
- / * Example of result:
- {
- Curve = {Field, Prime, Point, Order, CoFactor} =
- {
- Field = {prime_field,<<255,...,255>>},
- Prime = {<<255,...,252>>,
- <<90,...,75>>,
- <<196,...,144>>
- },
- Point = <<4,...,245>>,
- Order = <<255,...,81>>,
- CoFactor = <<1>>
- },
- Key = <<151,...,62>>
- }
- or
- {
- Curve =
- {characteristic_two_field,
- M,
- Basis = {tpbasis, _}
- | {ppbasis, k1, k2, k3}
- },
- Key
- }
- * /
- EVP_PKEY_free(pkey);
- return enif_make_list_from_array(env, ..., ...);
- */
-#endif
- }
-
- if (pkey) EVP_PKEY_free(pkey);
- return enif_make_badarg(env);
-}
-
-/*================================================================*/
-
-static ERL_NIF_TERM rand_seed_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{
- ErlNifBinary seed_bin;
-
- if (!enif_inspect_binary(env, argv[0], &seed_bin))
- return enif_make_badarg(env);
- RAND_seed(seed_bin.data,seed_bin.size);
- return atom_ok;
-}
-
-/*================================================================*/
-/* Engine */
-/*================================================================*/
-static ERL_NIF_TERM engine_by_id_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (EngineId) */
-#ifdef HAS_ENGINE_SUPPORT
- ERL_NIF_TERM ret;
- ErlNifBinary engine_id_bin;
- char *engine_id;
- ENGINE *engine;
- struct engine_ctx *ctx;
-
- // Get Engine Id
- if(!enif_inspect_binary(env, argv[0], &engine_id_bin)) {
- PRINTF_ERR0("engine_by_id_nif Leaved: badarg");
- return enif_make_badarg(env);
- } else {
- engine_id = enif_alloc(engine_id_bin.size+1);
- (void) memcpy(engine_id, engine_id_bin.data, engine_id_bin.size);
- engine_id[engine_id_bin.size] = '\0';
- }
-
- engine = ENGINE_by_id(engine_id);
- if(!engine) {
- enif_free(engine_id);
- PRINTF_ERR0("engine_by_id_nif Leaved: {error, bad_engine_id}");
- return enif_make_tuple2(env, atom_error, atom_bad_engine_id);
- }
-
- ctx = enif_alloc_resource(engine_ctx_rtype, sizeof(struct engine_ctx));
- ctx->engine = engine;
- ctx->id = engine_id;
-
- ret = enif_make_resource(env, ctx);
- enif_release_resource(ctx);
-
- return enif_make_tuple2(env, atom_ok, ret);
-#else
- return atom_notsup;
-#endif
-}
-
-static ERL_NIF_TERM engine_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Engine) */
-#ifdef HAS_ENGINE_SUPPORT
- ERL_NIF_TERM ret = atom_ok;
- struct engine_ctx *ctx;
-
- // Get Engine
- if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) {
- PRINTF_ERR0("engine_init_nif Leaved: Parameter not an engine resource object");
- return enif_make_badarg(env);
- }
- if (!ENGINE_init(ctx->engine)) {
- //ERR_print_errors_fp(stderr);
- PRINTF_ERR0("engine_init_nif Leaved: {error, engine_init_failed}");
- return enif_make_tuple2(env, atom_error, atom_engine_init_failed);
- }
-
- return ret;
-#else
- return atom_notsup;
-#endif
-}
-
-static ERL_NIF_TERM engine_free_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Engine) */
-#ifdef HAS_ENGINE_SUPPORT
- struct engine_ctx *ctx;
-
- // Get Engine
- if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) {
- PRINTF_ERR0("engine_free_nif Leaved: Parameter not an engine resource object");
- return enif_make_badarg(env);
- }
-
- ENGINE_free(ctx->engine);
- return atom_ok;
-#else
- return atom_notsup;
-#endif
-}
-
-static ERL_NIF_TERM engine_finish_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Engine) */
-#ifdef HAS_ENGINE_SUPPORT
- struct engine_ctx *ctx;
-
- // Get Engine
- if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) {
- PRINTF_ERR0("engine_finish_nif Leaved: Parameter not an engine resource object");
- return enif_make_badarg(env);
- }
-
- ENGINE_finish(ctx->engine);
- return atom_ok;
-#else
- return atom_notsup;
-#endif
-}
-
-static ERL_NIF_TERM engine_load_dynamic_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* () */
-#ifdef HAS_ENGINE_SUPPORT
- ENGINE_load_dynamic();
- return atom_ok;
-#else
- return atom_notsup;
-#endif
-}
-
-static ERL_NIF_TERM engine_ctrl_cmd_strings_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Engine, Commands) */
-#ifdef HAS_ENGINE_SUPPORT
- ERL_NIF_TERM ret = atom_ok;
- unsigned int cmds_len = 0;
- char **cmds = NULL;
- struct engine_ctx *ctx;
- int i, optional = 0;
-
- // Get Engine
- if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) {
- PRINTF_ERR0("engine_ctrl_cmd_strings_nif Leaved: Parameter not an engine resource object");
- return enif_make_badarg(env);
- }
-
- PRINTF_ERR1("Engine Id: %s\r\n", ENGINE_get_id(ctx->engine));
-
- // Get Command List
- if(!enif_get_list_length(env, argv[1], &cmds_len)) {
- PRINTF_ERR0("engine_ctrl_cmd_strings_nif Leaved: Bad Command List");
- return enif_make_badarg(env);
- } else {
- cmds_len *= 2; // Key-Value list from erlang
- cmds = enif_alloc((cmds_len+1)*sizeof(char*));
- if(get_engine_load_cmd_list(env, argv[1], cmds, 0)) {
- PRINTF_ERR0("engine_ctrl_cmd_strings_nif Leaved: Couldn't read Command List");
- ret = enif_make_badarg(env);
- goto error;
- }
- }
-
- if(!enif_get_int(env, argv[2], &optional)) {
- PRINTF_ERR0("engine_ctrl_cmd_strings_nif Leaved: Parameter optional not an integer");
- return enif_make_badarg(env);
- }
-
- for(i = 0; i < cmds_len; i+=2) {
- PRINTF_ERR2("Cmd: %s:%s\r\n",
- cmds[i] ? cmds[i] : "(NULL)",
- cmds[i+1] ? cmds[i+1] : "(NULL)");
- if(!ENGINE_ctrl_cmd_string(ctx->engine, cmds[i], cmds[i+1], optional)) {
- PRINTF_ERR2("Command failed: %s:%s\r\n",
- cmds[i] ? cmds[i] : "(NULL)",
- cmds[i+1] ? cmds[i+1] : "(NULL)");
- //ENGINE_free(ctx->engine);
- ret = enif_make_tuple2(env, atom_error, atom_ctrl_cmd_failed);
- PRINTF_ERR0("engine_ctrl_cmd_strings_nif Leaved: {error, ctrl_cmd_failed}");
- goto error;
- }
- }
-
- error:
- for(i = 0; cmds != NULL && cmds[i] != NULL; i++)
- enif_free(cmds[i]);
- enif_free(cmds);
- return ret;
-#else
- return atom_notsup;
-#endif
-}
-
-static ERL_NIF_TERM engine_add_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Engine) */
-#ifdef HAS_ENGINE_SUPPORT
- struct engine_ctx *ctx;
-
- // Get Engine
- if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) {
- PRINTF_ERR0("engine_add_nif Leaved: Parameter not an engine resource object");
- return enif_make_badarg(env);
- }
-
- if (!ENGINE_add(ctx->engine)) {
- PRINTF_ERR0("engine_add_nif Leaved: {error, add_engine_failed}");
- return enif_make_tuple2(env, atom_error, atom_add_engine_failed);
- }
- return atom_ok;
-#else
- return atom_notsup;
-#endif
-}
-
-static ERL_NIF_TERM engine_remove_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Engine) */
-#ifdef HAS_ENGINE_SUPPORT
- struct engine_ctx *ctx;
-
- // Get Engine
- if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) {
- PRINTF_ERR0("engine_remove_nif Leaved: Parameter not an engine resource object");
- return enif_make_badarg(env);
- }
-
- if (!ENGINE_remove(ctx->engine)) {
- PRINTF_ERR0("engine_remove_nif Leaved: {error, remove_engine_failed}");
- return enif_make_tuple2(env, atom_error, atom_remove_engine_failed);
- }
- return atom_ok;
-#else
- return atom_notsup;
-#endif
-}
-
-static ERL_NIF_TERM engine_register_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Engine, EngineMethod) */
-#ifdef HAS_ENGINE_SUPPORT
- struct engine_ctx *ctx;
- unsigned int method;
-
- // Get Engine
- if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) {
- PRINTF_ERR0("engine_register_nif Leaved: Parameter not an engine resource object");
- return enif_make_badarg(env);
- }
- // Get Method
- if (!enif_get_uint(env, argv[1], &method)) {
- PRINTF_ERR0("engine_register_nif Leaved: Parameter Method not an uint");
- return enif_make_badarg(env);
- }
-
- switch(method)
- {
-#ifdef ENGINE_METHOD_RSA
- case ENGINE_METHOD_RSA:
- if (!ENGINE_register_RSA(ctx->engine))
- return enif_make_tuple2(env, atom_error, atom_register_engine_failed);
- break;
-#endif
-#ifdef ENGINE_METHOD_DSA
- case ENGINE_METHOD_DSA:
- if (!ENGINE_register_DSA(ctx->engine))
- return enif_make_tuple2(env, atom_error, atom_register_engine_failed);
- break;
-#endif
-#ifdef ENGINE_METHOD_DH
- case ENGINE_METHOD_DH:
- if (!ENGINE_register_DH(ctx->engine))
- return enif_make_tuple2(env, atom_error, atom_register_engine_failed);
- break;
-#endif
-#ifdef ENGINE_METHOD_RAND
- case ENGINE_METHOD_RAND:
- if (!ENGINE_register_RAND(ctx->engine))
- return enif_make_tuple2(env, atom_error, atom_register_engine_failed);
- break;
-#endif
-#ifdef ENGINE_METHOD_ECDH
- case ENGINE_METHOD_ECDH:
- if (!ENGINE_register_ECDH(ctx->engine))
- return enif_make_tuple2(env, atom_error, atom_register_engine_failed);
- break;
-#endif
-#ifdef ENGINE_METHOD_ECDSA
- case ENGINE_METHOD_ECDSA:
- if (!ENGINE_register_ECDSA(ctx->engine))
- return enif_make_tuple2(env, atom_error, atom_register_engine_failed);
- break;
-#endif
-#ifdef ENGINE_METHOD_STORE
- case ENGINE_METHOD_STORE:
- if (!ENGINE_register_STORE(ctx->engine))
- return enif_make_tuple2(env, atom_error, atom_register_engine_failed);
- break;
-#endif
-#ifdef ENGINE_METHOD_CIPHERS
- case ENGINE_METHOD_CIPHERS:
- if (!ENGINE_register_ciphers(ctx->engine))
- return enif_make_tuple2(env, atom_error, atom_register_engine_failed);
- break;
-#endif
-#ifdef ENGINE_METHOD_DIGESTS
- case ENGINE_METHOD_DIGESTS:
- if (!ENGINE_register_digests(ctx->engine))
- return enif_make_tuple2(env, atom_error, atom_register_engine_failed);
- break;
-#endif
-#ifdef ENGINE_METHOD_PKEY_METHS
- case ENGINE_METHOD_PKEY_METHS:
- if (!ENGINE_register_pkey_meths(ctx->engine))
- return enif_make_tuple2(env, atom_error, atom_register_engine_failed);
- break;
-#endif
-#ifdef ENGINE_METHOD_PKEY_ASN1_METHS
- case ENGINE_METHOD_PKEY_ASN1_METHS:
- if (!ENGINE_register_pkey_asn1_meths(ctx->engine))
- return enif_make_tuple2(env, atom_error, atom_register_engine_failed);
- break;
-#endif
-#ifdef ENGINE_METHOD_EC
- case ENGINE_METHOD_EC:
- if (!ENGINE_register_EC(ctx->engine))
- return enif_make_tuple2(env, atom_error, atom_register_engine_failed);
- break;
-#endif
- default:
- return enif_make_tuple2(env, atom_error, atom_engine_method_not_supported);
- break;
- }
- return atom_ok;
-#else
- return atom_notsup;
-#endif
-}
-
-static ERL_NIF_TERM engine_unregister_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Engine, EngineMethod) */
-#ifdef HAS_ENGINE_SUPPORT
- struct engine_ctx *ctx;
- unsigned int method;
-
- // Get Engine
- if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) {
- PRINTF_ERR0("engine_unregister_nif Leaved: Parameter not an engine resource object");
- return enif_make_badarg(env);
- }
- // Get Method
- if (!enif_get_uint(env, argv[1], &method)) {
- PRINTF_ERR0("engine_unregister_nif Leaved: Parameter Method not an uint");
- return enif_make_badarg(env);
- }
-
- switch(method)
- {
-#ifdef ENGINE_METHOD_RSA
- case ENGINE_METHOD_RSA:
- ENGINE_unregister_RSA(ctx->engine);
- break;
-#endif
-#ifdef ENGINE_METHOD_DSA
- case ENGINE_METHOD_DSA:
- ENGINE_unregister_DSA(ctx->engine);
- break;
-#endif
-#ifdef ENGINE_METHOD_DH
- case ENGINE_METHOD_DH:
- ENGINE_unregister_DH(ctx->engine);
- break;
-#endif
-#ifdef ENGINE_METHOD_RAND
- case ENGINE_METHOD_RAND:
- ENGINE_unregister_RAND(ctx->engine);
- break;
-#endif
-#ifdef ENGINE_METHOD_ECDH
- case ENGINE_METHOD_ECDH:
- ENGINE_unregister_ECDH(ctx->engine);
- break;
-#endif
-#ifdef ENGINE_METHOD_ECDSA
- case ENGINE_METHOD_ECDSA:
- ENGINE_unregister_ECDSA(ctx->engine);
- break;
-#endif
-#ifdef ENGINE_METHOD_STORE
- case ENGINE_METHOD_STORE:
- ENGINE_unregister_STORE(ctx->engine);
- break;
-#endif
-#ifdef ENGINE_METHOD_CIPHERS
- case ENGINE_METHOD_CIPHERS:
- ENGINE_unregister_ciphers(ctx->engine);
- break;
-#endif
-#ifdef ENGINE_METHOD_DIGESTS
- case ENGINE_METHOD_DIGESTS:
- ENGINE_unregister_digests(ctx->engine);
- break;
-#endif
-#ifdef ENGINE_METHOD_PKEY_METHS
- case ENGINE_METHOD_PKEY_METHS:
- ENGINE_unregister_pkey_meths(ctx->engine);
- break;
-#endif
-#ifdef ENGINE_METHOD_PKEY_ASN1_METHS
- case ENGINE_METHOD_PKEY_ASN1_METHS:
- ENGINE_unregister_pkey_asn1_meths(ctx->engine);
- break;
-#endif
-#ifdef ENGINE_METHOD_EC
- case ENGINE_METHOD_EC:
- ENGINE_unregister_EC(ctx->engine);
- break;
-#endif
- default:
- break;
- }
- return atom_ok;
-#else
- return atom_notsup;
-#endif
-}
-
-static ERL_NIF_TERM engine_get_first_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Engine) */
-#ifdef HAS_ENGINE_SUPPORT
- ERL_NIF_TERM ret;
- ENGINE *engine;
- ErlNifBinary engine_bin;
- struct engine_ctx *ctx;
-
- engine = ENGINE_get_first();
- if(!engine) {
- enif_alloc_binary(0, &engine_bin);
- engine_bin.size = 0;
- return enif_make_tuple2(env, atom_ok, enif_make_binary(env, &engine_bin));
- }
-
- ctx = enif_alloc_resource(engine_ctx_rtype, sizeof(struct engine_ctx));
- ctx->engine = engine;
- ctx->id = NULL;
-
- ret = enif_make_resource(env, ctx);
- enif_release_resource(ctx);
-
- return enif_make_tuple2(env, atom_ok, ret);
-#else
- return atom_notsup;
-#endif
-}
-
-static ERL_NIF_TERM engine_get_next_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Engine) */
-#ifdef HAS_ENGINE_SUPPORT
- ERL_NIF_TERM ret;
- ENGINE *engine;
- ErlNifBinary engine_bin;
- struct engine_ctx *ctx, *next_ctx;
-
- // Get Engine
- if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) {
- PRINTF_ERR0("engine_get_next_nif Leaved: Parameter not an engine resource object");
- return enif_make_badarg(env);
- }
- engine = ENGINE_get_next(ctx->engine);
- if (!engine) {
- enif_alloc_binary(0, &engine_bin);
- engine_bin.size = 0;
- return enif_make_tuple2(env, atom_ok, enif_make_binary(env, &engine_bin));
- }
-
- next_ctx = enif_alloc_resource(engine_ctx_rtype, sizeof(struct engine_ctx));
- next_ctx->engine = engine;
- next_ctx->id = NULL;
-
- ret = enif_make_resource(env, next_ctx);
- enif_release_resource(next_ctx);
-
- return enif_make_tuple2(env, atom_ok, ret);
-#else
- return atom_notsup;
-#endif
-}
-
-static ERL_NIF_TERM engine_get_id_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Engine) */
-#ifdef HAS_ENGINE_SUPPORT
- ErlNifBinary engine_id_bin;
- const char *engine_id;
- int size;
- struct engine_ctx *ctx;
-
- // Get Engine
- if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) {
- PRINTF_ERR0("engine_get_id_nif Leaved: Parameter not an engine resource object");
- return enif_make_badarg(env);
- }
-
- engine_id = ENGINE_get_id(ctx->engine);
- if (!engine_id) {
- enif_alloc_binary(0, &engine_id_bin);
- engine_id_bin.size = 0;
- return enif_make_tuple2(env, atom_ok, enif_make_binary(env, &engine_id_bin));
- }
-
- size = strlen(engine_id);
- enif_alloc_binary(size, &engine_id_bin);
- engine_id_bin.size = size;
- memcpy(engine_id_bin.data, engine_id, size);
-
- return enif_make_tuple2(env, atom_ok, enif_make_binary(env, &engine_id_bin));
-#else
- return atom_notsup;
-#endif
-}
-
-static int get_engine_load_cmd_list(ErlNifEnv* env, const ERL_NIF_TERM term, char **cmds, int i)
-{
-#ifdef HAS_ENGINE_SUPPORT
- ERL_NIF_TERM head, tail;
- const ERL_NIF_TERM *tmp_tuple;
- ErlNifBinary tmpbin;
- int arity;
- char* tmpstr;
-
- if(!enif_is_empty_list(env, term)) {
- if(!enif_get_list_cell(env, term, &head, &tail)) {
- cmds[i] = NULL;
- return -1;
- } else {
- if(!enif_get_tuple(env, head, &arity, &tmp_tuple) || arity != 2) {
- cmds[i] = NULL;
- return -1;
- } else {
- if(!enif_inspect_binary(env, tmp_tuple[0], &tmpbin)) {
- cmds[i] = NULL;
- return -1;
- } else {
- tmpstr = enif_alloc(tmpbin.size+1);
- (void) memcpy(tmpstr, tmpbin.data, tmpbin.size);
- tmpstr[tmpbin.size] = '\0';
- cmds[i++] = tmpstr;
- }
- if(!enif_inspect_binary(env, tmp_tuple[1], &tmpbin)) {
- cmds[i] = NULL;
- return -1;
- } else {
- if(tmpbin.size == 0)
- cmds[i++] = NULL;
- else {
- tmpstr = enif_alloc(tmpbin.size+1);
- (void) memcpy(tmpstr, tmpbin.data, tmpbin.size);
- tmpstr[tmpbin.size] = '\0';
- cmds[i++] = tmpstr;
- }
- }
- return get_engine_load_cmd_list(env, tail, cmds, i);
- }
- }
- } else {
- cmds[i] = NULL;
- return 0;
- }
-#else
- return atom_notsup;
-#endif
-}
-
-static ERL_NIF_TERM engine_get_all_methods_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* () */
-#ifdef HAS_ENGINE_SUPPORT
- ERL_NIF_TERM method_array[12];
- int i = 0;
-
-#ifdef ENGINE_METHOD_RSA
- method_array[i++] = atom_engine_method_rsa;
-#endif
-#ifdef ENGINE_METHOD_DSA
- method_array[i++] = atom_engine_method_dsa;
-#endif
-#ifdef ENGINE_METHOD_DH
- method_array[i++] = atom_engine_method_dh;
-#endif
-#ifdef ENGINE_METHOD_RAND
- method_array[i++] = atom_engine_method_rand;
-#endif
-#ifdef ENGINE_METHOD_ECDH
- method_array[i++] = atom_engine_method_ecdh;
-#endif
-#ifdef ENGINE_METHOD_ECDSA
- method_array[i++] = atom_engine_method_ecdsa;
-#endif
-#ifdef ENGINE_METHOD_STORE
- method_array[i++] = atom_engine_method_store;
-#endif
-#ifdef ENGINE_METHOD_CIPHERS
- method_array[i++] = atom_engine_method_ciphers;
-#endif
-#ifdef ENGINE_METHOD_DIGESTS
- method_array[i++] = atom_engine_method_digests;
-#endif
-#ifdef ENGINE_METHOD_PKEY_METHS
- method_array[i++] = atom_engine_method_pkey_meths;
-#endif
-#ifdef ENGINE_METHOD_PKEY_ASN1_METHS
- method_array[i++] = atom_engine_method_pkey_asn1_meths;
-#endif
-#ifdef ENGINE_METHOD_EC
- method_array[i++] = atom_engine_method_ec;
-#endif
-
- return enif_make_list_from_array(env, method_array, i);
-#else
- return atom_notsup;
-#endif
-}
diff --git a/lib/crypto/c_src/crypto_callback.c b/lib/crypto/c_src/crypto_callback.c
index 23d2bed057..0141ccd840 100644
--- a/lib/crypto/c_src/crypto_callback.c
+++ b/lib/crypto/c_src/crypto_callback.c
@@ -21,6 +21,7 @@
#include <stdio.h>
#include <string.h>
#include <openssl/opensslconf.h>
+#include <stdint.h>
#include <erl_nif.h>
#include "crypto_callback.h"
@@ -64,22 +65,36 @@ static void nomem(size_t size, const char* op)
static void* crypto_alloc(size_t size CCB_FILE_LINE_ARGS)
{
- void *ret = enif_alloc(size);
+ void *ret;
- if (!ret && size)
- nomem(size, "allocate");
+ if ((ret = enif_alloc(size)) == NULL)
+ goto err;
return ret;
+
+ err:
+ if (size)
+ nomem(size, "allocate");
+ return NULL;
}
static void* crypto_realloc(void* ptr, size_t size CCB_FILE_LINE_ARGS)
{
- void* ret = enif_realloc(ptr, size);
+ void* ret;
- if (!ret && size)
- nomem(size, "reallocate");
+ if ((ret = enif_realloc(ptr, size)) == NULL)
+ goto err;
return ret;
+
+ err:
+ if (size)
+ nomem(size, "reallocate");
+ return NULL;
}
+
static void crypto_free(void* ptr CCB_FILE_LINE_ARGS)
{
+ if (ptr == NULL)
+ return;
+
enif_free(ptr);
}
@@ -160,25 +175,36 @@ DLLEXPORT struct crypto_callbacks* get_crypto_callbacks(int nlocks)
#ifdef OPENSSL_THREADS
if (nlocks > 0) {
int i;
- lock_vec = enif_alloc(nlocks*sizeof(*lock_vec));
- if (lock_vec==NULL) return NULL;
- memset(lock_vec, 0, nlocks*sizeof(*lock_vec));
-
+
+ if ((size_t)nlocks > SIZE_MAX / sizeof(*lock_vec))
+ goto err;
+ if ((lock_vec = enif_alloc((size_t)nlocks * sizeof(*lock_vec))) == NULL)
+ goto err;
+
+ memset(lock_vec, 0, (size_t)nlocks * sizeof(*lock_vec));
+
for (i=nlocks-1; i>=0; --i) {
- lock_vec[i] = enif_rwlock_create("crypto_stat");
- if (lock_vec[i]==NULL) return NULL;
+ if ((lock_vec[i] = enif_rwlock_create("crypto_stat")) == NULL)
+ goto err;
}
}
#endif
is_initialized = 1;
}
return &the_struct;
+
+ err:
+ return NULL;
}
#ifdef HAVE_DYNAMIC_CRYPTO_LIB
/* This is not really a NIF library, but we use ERL_NIF_INIT in order to
* get access to the erl_nif API (on Windows).
*/
-ERL_NIF_INIT(dummy, (ErlNifFunc*)NULL , NULL, NULL, NULL, NULL)
+static struct {
+ int dummy__;
+ ErlNifFunc funcv[0];
+} empty;
+ERL_NIF_INIT(dummy, empty.funcv, NULL, NULL, NULL, NULL)
#endif
diff --git a/lib/crypto/c_src/dh.c b/lib/crypto/c_src/dh.c
new file mode 100644
index 0000000000..13a2336f25
--- /dev/null
+++ b/lib/crypto/c_src/dh.c
@@ -0,0 +1,302 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "dh.h"
+#include "bn.h"
+
+ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (PrivKey|undefined, DHParams=[P,G], Mpint, Len|0) */
+#ifdef HAVE_DH
+ DH *dh_params = NULL;
+ unsigned int mpint; /* 0 or 4 */
+ ERL_NIF_TERM head, tail;
+ BIGNUM *dh_p = NULL;
+ BIGNUM *dh_p_shared;
+ BIGNUM *dh_g = NULL;
+ BIGNUM *priv_key_in = NULL;
+ unsigned long len = 0;
+ unsigned char *pub_ptr, *prv_ptr;
+ int pub_len, prv_len;
+ ERL_NIF_TERM ret_pub, ret_prv, ret;
+ const BIGNUM *pub_key_gen, *priv_key_gen;
+#ifdef HAS_EVP_PKEY_CTX
+ EVP_PKEY_CTX *ctx = NULL;
+ EVP_PKEY *dhkey = NULL, *params = NULL;
+#endif
+
+ ASSERT(argc == 4);
+
+ if (argv[0] != atom_undefined) {
+ if (!get_bn_from_bin(env, argv[0], &priv_key_in))
+ goto bad_arg;
+ }
+ if (!enif_get_list_cell(env, argv[1], &head, &tail))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, head, &dh_p))
+ goto bad_arg;
+
+ if (!enif_get_list_cell(env, tail, &head, &tail))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, head, &dh_g))
+ goto bad_arg;
+
+ if (!enif_is_empty_list(env, tail))
+ goto bad_arg;
+
+ if (!enif_get_uint(env, argv[2], &mpint))
+ goto bad_arg;
+ if (mpint != 0 && mpint != 4)
+ goto bad_arg;
+
+ if (!enif_get_ulong(env, argv[3], &len))
+ goto bad_arg;
+ if (len > LONG_MAX)
+ goto bad_arg;
+
+ /* Load dh_params with values to use by the generator.
+ Mem mgmnt transfered from dh_p etc to dh_params */
+ if ((dh_params = DH_new()) == NULL)
+ goto bad_arg;
+ if (priv_key_in) {
+ if (!DH_set0_key(dh_params, NULL, priv_key_in))
+ goto bad_arg;
+ /* On success, dh_params owns priv_key_in */
+ priv_key_in = NULL;
+ }
+ if (!DH_set0_pqg(dh_params, dh_p, NULL, dh_g))
+ goto bad_arg;
+ dh_p_shared = dh_p; /* Don't free this because dh_params owns it */
+ /* On success, dh_params owns dh_p and dh_g */
+ dh_p = NULL;
+ dh_g = NULL;
+
+ if (len) {
+ int bn_len;
+
+ if ((bn_len = BN_num_bits(dh_p_shared)) < 0)
+ goto bad_arg;
+ dh_p_shared = NULL; /* dh_params owns the reference */
+ if (len >= (size_t)bn_len)
+ goto bad_arg;
+
+ if (!DH_set_length(dh_params, (long)len))
+ goto bad_arg;
+ }
+
+#ifdef HAS_EVP_PKEY_CTX
+ if ((params = EVP_PKEY_new()) == NULL)
+ goto err;
+
+ /* set the key referenced by params to dh_params... */
+ if (EVP_PKEY_set1_DH(params, dh_params) != 1)
+ goto err;
+
+ if ((ctx = EVP_PKEY_CTX_new(params, NULL)) == NULL)
+ goto err;
+
+ if (EVP_PKEY_keygen_init(ctx) != 1)
+ goto err;
+
+ if ((dhkey = EVP_PKEY_new()) == NULL)
+ goto err;
+
+ /* key gen op, key written to ppkey (=last arg) */
+ if (EVP_PKEY_keygen(ctx, &dhkey) != 1)
+ goto err;
+
+ DH_free(dh_params);
+ if ((dh_params = EVP_PKEY_get1_DH(dhkey)) == NULL)
+ goto err;
+
+#else
+ if (!DH_generate_key(dh_params))
+ goto err;
+#endif
+
+ DH_get0_key(dh_params, &pub_key_gen, &priv_key_gen);
+
+ if ((pub_len = BN_num_bytes(pub_key_gen)) < 0)
+ goto err;
+ if ((prv_len = BN_num_bytes(priv_key_gen)) < 0)
+ goto err;
+
+ if ((pub_ptr = enif_make_new_binary(env, (size_t)pub_len+mpint, &ret_pub)) == NULL)
+ goto err;
+ if ((prv_ptr = enif_make_new_binary(env, (size_t)prv_len+mpint, &ret_prv)) == NULL)
+ goto err;
+
+ if (mpint) {
+ put_uint32(pub_ptr, (unsigned int)pub_len);
+ pub_ptr += 4;
+
+ put_uint32(prv_ptr, (unsigned int)prv_len);
+ prv_ptr += 4;
+ }
+
+ if (BN_bn2bin(pub_key_gen, pub_ptr) < 0)
+ goto err;
+ if (BN_bn2bin(priv_key_gen, prv_ptr) < 0)
+ goto err;
+
+ ERL_VALGRIND_MAKE_MEM_DEFINED(pub_ptr, pub_len);
+ ERL_VALGRIND_MAKE_MEM_DEFINED(prv_ptr, prv_len);
+
+ ret = enif_make_tuple2(env, ret_pub, ret_prv);
+ goto done;
+
+ bad_arg:
+ ret = enif_make_badarg(env);
+ goto done;
+
+ err:
+ ret = atom_error;
+
+ done:
+ if (priv_key_in)
+ BN_free(priv_key_in);
+ if (dh_p)
+ BN_free(dh_p);
+ if (dh_g)
+ BN_free(dh_g);
+ if (dh_params)
+ DH_free(dh_params);
+
+#ifdef HAS_EVP_PKEY_CTX
+ if (ctx)
+ EVP_PKEY_CTX_free(ctx);
+ if (dhkey)
+ EVP_PKEY_free(dhkey);
+ if (params)
+ EVP_PKEY_free(params);
+#endif
+
+ return ret;
+#else
+ return enif_raise_exception(env, atom_notsup);
+#endif
+}
+
+ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (OthersPublicKey, MyPrivateKey, DHParams=[P,G]) */
+#ifdef HAVE_DH
+ BIGNUM *other_pub_key = NULL;
+ BIGNUM *dh_p = NULL;
+ BIGNUM *dh_g = NULL;
+ BIGNUM *dummy_pub_key = NULL;
+ BIGNUM *priv_key = NULL;
+ DH *dh_priv = NULL;
+ ERL_NIF_TERM head, tail, ret;
+ ErlNifBinary ret_bin;
+ int size;
+ int ret_bin_alloc = 0;
+ int dh_size;
+
+ /* Check the arguments and get
+ my private key (dh_priv),
+ the peer's public key (other_pub_key),
+ the parameters p & q
+ */
+ ASSERT(argc == 3);
+
+ if (!get_bn_from_bin(env, argv[0], &other_pub_key))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, argv[1], &priv_key))
+ goto bad_arg;
+
+ if (!enif_get_list_cell(env, argv[2], &head, &tail))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, head, &dh_p))
+ goto bad_arg;
+
+ if (!enif_get_list_cell(env, tail, &head, &tail))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, head, &dh_g))
+ goto bad_arg;
+
+ if (!enif_is_empty_list(env, tail))
+ goto bad_arg;
+
+ /* Note: DH_set0_key() does not allow setting only the
+ * private key, although DH_compute_key() does not use the
+ * public key. Work around this limitation by setting
+ * the public key to a copy of the private key.
+ */
+ if ((dummy_pub_key = BN_dup(priv_key)) == NULL)
+ goto err;
+ if ((dh_priv = DH_new()) == NULL)
+ goto err;
+
+ if (!DH_set0_key(dh_priv, dummy_pub_key, priv_key))
+ goto err;
+ /* dh_priv owns dummy_pub_key and priv_key now */
+ dummy_pub_key = NULL;
+ priv_key = NULL;
+
+ if (!DH_set0_pqg(dh_priv, dh_p, NULL, dh_g))
+ goto err;
+ /* dh_priv owns dh_p and dh_g now */
+ dh_p = NULL;
+ dh_g = NULL;
+
+ if ((dh_size = DH_size(dh_priv)) < 0)
+ goto err;
+ if (!enif_alloc_binary((size_t)dh_size, &ret_bin))
+ goto err;
+ ret_bin_alloc = 1;
+
+ if ((size = DH_compute_key(ret_bin.data, other_pub_key, dh_priv)) < 0)
+ goto err;
+ if (size == 0)
+ goto err;
+
+ if ((size_t)size != ret_bin.size) {
+ if (!enif_realloc_binary(&ret_bin, (size_t)size))
+ goto err;
+ }
+
+ ret = enif_make_binary(env, &ret_bin);
+ ret_bin_alloc = 0;
+ goto done;
+
+ bad_arg:
+ err:
+ if (ret_bin_alloc)
+ enif_release_binary(&ret_bin);
+ ret = enif_make_badarg(env);
+
+ done:
+ if (other_pub_key)
+ BN_free(other_pub_key);
+ if (priv_key)
+ BN_free(priv_key);
+ if (dh_p)
+ BN_free(dh_p);
+ if (dh_g)
+ BN_free(dh_g);
+ if (dummy_pub_key)
+ BN_free(dummy_pub_key);
+ if (dh_priv)
+ DH_free(dh_priv);
+
+ return ret;
+#else
+ return enif_raise_exception(env, atom_notsup);
+#endif
+}
diff --git a/lib/crypto/c_src/dh.h b/lib/crypto/c_src/dh.h
new file mode 100644
index 0000000000..a996b0ea28
--- /dev/null
+++ b/lib/crypto/c_src/dh.h
@@ -0,0 +1,29 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_DH_H__
+#define E_DH_H__ 1
+
+#include "common.h"
+
+ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+#endif /* E_DH_H__ */
diff --git a/lib/crypto/c_src/digest.c b/lib/crypto/c_src/digest.c
new file mode 100644
index 0000000000..c987a664d5
--- /dev/null
+++ b/lib/crypto/c_src/digest.c
@@ -0,0 +1,156 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "digest.h"
+
+static struct digest_type_t digest_types[] =
+{
+ {{"md4"},
+#ifdef HAVE_MD4
+ {&EVP_md4}
+#else
+ {NULL}
+#endif
+ },
+
+ {{"md5"},
+#ifdef HAVE_MD5
+ {&EVP_md5}
+#else
+ {NULL}
+#endif
+ },
+
+ {{"ripemd160"},
+#ifdef HAVE_RIPEMD160
+ {&EVP_ripemd160}
+#else
+ {NULL}
+#endif
+ },
+
+ {{"sha"}, {&EVP_sha1}},
+
+ {{"sha224"},
+#ifdef HAVE_SHA224
+ {&EVP_sha224}
+#else
+ {NULL}
+#endif
+ },
+
+ {{"sha256"},
+#ifdef HAVE_SHA256
+ {&EVP_sha256}
+#else
+ {NULL}
+#endif
+ },
+
+ {{"sha384"},
+#ifdef HAVE_SHA384
+ {&EVP_sha384}
+#else
+ {NULL}
+#endif
+ },
+
+ {{"sha512"},
+#ifdef HAVE_SHA512
+ {&EVP_sha512}
+#else
+ {NULL}
+#endif
+ },
+
+ {{"sha3_224"},
+#ifdef HAVE_SHA3_224
+ {&EVP_sha3_224}
+#else
+ {NULL}
+#endif
+ },
+
+ {{"sha3_256"},
+#ifdef HAVE_SHA3_256
+ {&EVP_sha3_256}
+#else
+ {NULL}
+#endif
+ },
+
+ {{"sha3_384"},
+#ifdef HAVE_SHA3_384
+ {&EVP_sha3_384}
+#else
+ {NULL}
+#endif
+ },
+
+ {{"sha3_512"},
+#ifdef HAVE_SHA3_512
+ {&EVP_sha3_512}
+#else
+ {NULL}
+#endif
+ },
+
+ {{"blake2b"},
+#ifdef HAVE_BLAKE2
+ {&EVP_blake2b512}
+#else
+ {NULL}
+#endif
+ },
+
+ {{"blake2s"},
+#ifdef HAVE_BLAKE2
+ {&EVP_blake2s256}
+#else
+ {NULL}
+#endif
+ },
+
+ {{NULL}, {NULL}}
+};
+
+void init_digest_types(ErlNifEnv* env)
+{
+ struct digest_type_t* p = digest_types;
+
+ for (p = digest_types; p->type.str; p++) {
+ p->type.atom = enif_make_atom(env, p->type.str);
+ if (p->md.funcp)
+ p->md.p = p->md.funcp();
+ }
+ p->type.atom = atom_false; /* end marker */
+}
+
+struct digest_type_t* get_digest_type(ERL_NIF_TERM type)
+{
+ struct digest_type_t* p = NULL;
+ for (p = digest_types; p->type.atom != atom_false; p++) {
+ if (type == p->type.atom) {
+ return p;
+ }
+ }
+ return NULL;
+}
+
diff --git a/lib/crypto/c_src/digest.h b/lib/crypto/c_src/digest.h
new file mode 100644
index 0000000000..06852416cf
--- /dev/null
+++ b/lib/crypto/c_src/digest.h
@@ -0,0 +1,40 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_DIGEST_H__
+#define E_DIGEST_H__ 1
+
+#include "common.h"
+
+struct digest_type_t {
+ union {
+ const char* str; /* before init, NULL for end-of-table */
+ ERL_NIF_TERM atom; /* after init, 'false' for end-of-table */
+ }type;
+ union {
+ const EVP_MD* (*funcp)(void); /* before init, NULL if notsup */
+ const EVP_MD* p; /* after init, NULL if notsup */
+ }md;
+};
+
+void init_digest_types(ErlNifEnv* env);
+struct digest_type_t* get_digest_type(ERL_NIF_TERM type);
+
+#endif /* E_DIGEST_H__ */
diff --git a/lib/crypto/c_src/dss.c b/lib/crypto/c_src/dss.c
new file mode 100644
index 0000000000..63268f0f2b
--- /dev/null
+++ b/lib/crypto/c_src/dss.c
@@ -0,0 +1,148 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "dss.h"
+#include "bn.h"
+
+#ifdef HAVE_DSA
+
+int get_dss_private_key(ErlNifEnv* env, ERL_NIF_TERM key, DSA *dsa)
+{
+ /* key=[P,Q,G,KEY] */
+ ERL_NIF_TERM head, tail;
+ BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL;
+ BIGNUM *dummy_pub_key = NULL, *priv_key = NULL;
+
+ if (!enif_get_list_cell(env, key, &head, &tail))
+ goto err;
+ if (!get_bn_from_bin(env, head, &dsa_p))
+ goto err;
+
+ if (!enif_get_list_cell(env, tail, &head, &tail))
+ goto err;
+ if (!get_bn_from_bin(env, head, &dsa_q))
+ goto err;
+
+ if (!enif_get_list_cell(env, tail, &head, &tail))
+ goto err;
+ if (!get_bn_from_bin(env, head, &dsa_g))
+ goto err;
+
+ if (!enif_get_list_cell(env, tail, &head, &tail))
+ goto err;
+ if (!get_bn_from_bin(env, head, &priv_key))
+ goto err;
+
+ if (!enif_is_empty_list(env, tail))
+ goto err;
+
+ /* Note: DSA_set0_key() does not allow setting only the
+ * private key, although DSA_sign() does not use the
+ * public key. Work around this limitation by setting
+ * the public key to a copy of the private key.
+ */
+ if ((dummy_pub_key = BN_dup(priv_key)) == NULL)
+ goto err;
+
+ if (!DSA_set0_pqg(dsa, dsa_p, dsa_q, dsa_g))
+ goto err;
+ /* dsa takes ownership on success */
+ dsa_p = NULL;
+ dsa_q = NULL;
+ dsa_g = NULL;
+
+ if (!DSA_set0_key(dsa, dummy_pub_key, priv_key))
+ goto err;
+ /* dsa takes ownership on success */
+ dummy_pub_key = NULL;
+ priv_key = NULL;
+
+ return 1;
+
+ err:
+ if (dsa_p)
+ BN_free(dsa_p);
+ if (dsa_q)
+ BN_free(dsa_q);
+ if (dsa_g)
+ BN_free(dsa_g);
+ if (priv_key)
+ BN_free(priv_key);
+ if (dummy_pub_key)
+ BN_free(dummy_pub_key);
+ return 0;
+}
+
+int get_dss_public_key(ErlNifEnv* env, ERL_NIF_TERM key, DSA *dsa)
+{
+ /* key=[P, Q, G, Y] */
+ ERL_NIF_TERM head, tail;
+ BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_y = NULL;
+
+ if (!enif_get_list_cell(env, key, &head, &tail))
+ goto err;
+ if (!get_bn_from_bin(env, head, &dsa_p))
+ goto err;
+
+ if (!enif_get_list_cell(env, tail, &head, &tail))
+ goto err;
+ if (!get_bn_from_bin(env, head, &dsa_q))
+ goto err;
+
+ if (!enif_get_list_cell(env, tail, &head, &tail))
+ goto err;
+ if (!get_bn_from_bin(env, head, &dsa_g))
+ goto err;
+
+ if (!enif_get_list_cell(env, tail, &head, &tail))
+ goto err;
+ if (!get_bn_from_bin(env, head, &dsa_y))
+ goto err;
+
+ if (!enif_is_empty_list(env,tail))
+ goto err;
+
+ if (!DSA_set0_pqg(dsa, dsa_p, dsa_q, dsa_g))
+ goto err;
+ /* dsa takes ownership on success */
+ dsa_p = NULL;
+ dsa_q = NULL;
+ dsa_g = NULL;
+
+ if (!DSA_set0_key(dsa, dsa_y, NULL))
+ goto err;
+ /* dsa takes ownership on success */
+ dsa_y = NULL;
+
+ return 1;
+
+ err:
+ if (dsa_p)
+ BN_free(dsa_p);
+ if (dsa_q)
+ BN_free(dsa_q);
+ if (dsa_g)
+ BN_free(dsa_g);
+ if (dsa_y)
+ BN_free(dsa_y);
+ return 0;
+}
+
+#endif
diff --git a/lib/crypto/c_src/dss.h b/lib/crypto/c_src/dss.h
new file mode 100644
index 0000000000..07e28ca7c5
--- /dev/null
+++ b/lib/crypto/c_src/dss.h
@@ -0,0 +1,31 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_DSS_H__
+#define E_DSS_H__ 1
+
+#include "common.h"
+
+#ifdef HAVE_DSA
+int get_dss_private_key(ErlNifEnv* env, ERL_NIF_TERM key, DSA *dsa);
+int get_dss_public_key(ErlNifEnv* env, ERL_NIF_TERM key, DSA *dsa);
+#endif
+
+#endif /* E_DSS_H__ */
diff --git a/lib/crypto/c_src/ec.c b/lib/crypto/c_src/ec.c
new file mode 100644
index 0000000000..51a3547694
--- /dev/null
+++ b/lib/crypto/c_src/ec.c
@@ -0,0 +1,414 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "ec.h"
+#include "bn.h"
+
+#ifdef HAVE_EC
+static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg);
+static ERL_NIF_TERM point2term(ErlNifEnv* env,
+ const EC_GROUP *group,
+ const EC_POINT *point,
+ point_conversion_form_t form);
+
+ERL_NIF_TERM make_badarg_maybe(ErlNifEnv* env)
+{
+ ERL_NIF_TERM reason;
+ if (enif_has_pending_exception(env, &reason))
+ return reason; /* dummy return value ignored */
+ else
+ return enif_make_badarg(env);
+}
+
+static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg)
+{
+ EC_KEY *key = NULL;
+ int c_arity = -1;
+ const ERL_NIF_TERM* curve;
+ ErlNifBinary seed;
+ BIGNUM *p = NULL;
+ BIGNUM *a = NULL;
+ BIGNUM *b = NULL;
+ BIGNUM *bn_order = NULL;
+ BIGNUM *cofactor = NULL;
+ EC_GROUP *group = NULL;
+ EC_POINT *point = NULL;
+ int f_arity = -1;
+ const ERL_NIF_TERM *field;
+ int p_arity = -1;
+ const ERL_NIF_TERM *prime;
+ long field_bits;
+
+ /* {Field, Prime, Point, Order, CoFactor} = Curve */
+ if (!enif_get_tuple(env, curve_arg, &c_arity, &curve))
+ goto err;
+ if (c_arity != 5)
+ goto err;
+ if (!get_bn_from_bin(env, curve[3], &bn_order))
+ goto err;
+ if (curve[4] != atom_none) {
+ if (!get_bn_from_bin(env, curve[4], &cofactor))
+ goto err;
+ }
+
+ /* {A, B, Seed} = Prime */
+ if (!enif_get_tuple(env, curve[1], &p_arity, &prime))
+ goto err;
+ if (!get_bn_from_bin(env, prime[0], &a))
+ goto err;
+ if (!get_bn_from_bin(env, prime[1], &b))
+ goto err;
+
+ if (!enif_get_tuple(env, curve[0], &f_arity, &field))
+ goto err;
+
+ if (f_arity == 2 && field[0] == atom_prime_field) {
+ /* {prime_field, Prime} */
+ if (!get_bn_from_bin(env, field[1], &p))
+ goto err;
+ if (BN_is_negative(p))
+ goto err;
+ if (BN_is_zero(p))
+ goto err;
+
+ field_bits = BN_num_bits(p);
+ if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS)
+ goto err;
+
+ /* create the EC_GROUP structure */
+ if ((group = EC_GROUP_new_curve_GFp(p, a, b, NULL)) == NULL)
+ goto err;
+
+ } else if (f_arity == 3 && field[0] == atom_characteristic_two_field) {
+#if defined(OPENSSL_NO_EC2M)
+ enif_raise_exception(env, atom_notsup);
+ goto err;
+#else
+ /* {characteristic_two_field, M, Basis} */
+ int b_arity = -1;
+ const ERL_NIF_TERM* basis;
+
+ if ((p = BN_new()) == NULL)
+ goto err;
+ if (!enif_get_long(env, field[1], &field_bits))
+ goto err;
+ if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS || field_bits > INT_MAX)
+ goto err;
+
+ if (enif_get_tuple(env, field[2], &b_arity, &basis)) {
+ if (b_arity == 2) {
+ unsigned int k1;
+
+ if (basis[0] != atom_tpbasis)
+ goto err;
+ if (!enif_get_uint(env, basis[1], &k1))
+ goto err;
+
+ /* {tpbasis, k} = Basis */
+ if (field_bits <= k1 || k1 == 0 || k1 > INT_MAX)
+ goto err;
+
+ /* create the polynomial */
+ if (!BN_set_bit(p, (int)field_bits))
+ goto err;
+ if (!BN_set_bit(p, (int)k1))
+ goto err;
+ if (!BN_set_bit(p, 0))
+ goto err;
+
+ } else if (b_arity == 4) {
+ unsigned int k1, k2, k3;
+
+ if (basis[0] != atom_ppbasis)
+ goto err;
+ if (!enif_get_uint(env, basis[1], &k1))
+ goto err;
+ if (!enif_get_uint(env, basis[2], &k2))
+ goto err;
+ if (!enif_get_uint(env, basis[3], &k3))
+ goto err;
+
+ /* {ppbasis, k1, k2, k3} = Basis */
+ if (field_bits <= k3 || k3 <= k2 || k2 <= k1 || k1 == 0 || k3 > INT_MAX || k2 > INT_MAX || k1 > INT_MAX)
+ goto err;
+
+ /* create the polynomial */
+ if (!BN_set_bit(p, (int)field_bits))
+ goto err;
+ if (!BN_set_bit(p, (int)k1))
+ goto err;
+ if (!BN_set_bit(p, (int)k2))
+ goto err;
+ if (!BN_set_bit(p, (int)k3))
+ goto err;
+ if (!BN_set_bit(p, 0))
+ goto err;
+
+ } else
+ goto err;
+ } else if (field[2] == atom_onbasis) {
+ /* onbasis = Basis */
+ /* no parameters */
+ goto err;
+
+ } else
+ goto err;
+
+ if ((group = EC_GROUP_new_curve_GF2m(p, a, b, NULL)) == NULL)
+ goto err;
+#endif
+ } else
+ goto err;
+
+ if (enif_inspect_binary(env, prime[2], &seed)) {
+ if (!EC_GROUP_set_seed(group, seed.data, seed.size))
+ goto err;
+ }
+
+ if (!term2point(env, curve[2], group, &point))
+ goto err;
+
+ if (BN_is_negative(bn_order))
+ goto err;
+ if (BN_is_zero(bn_order))
+ goto err;
+ if (BN_num_bits(bn_order) > (int)field_bits + 1)
+ goto err;
+
+ if (!EC_GROUP_set_generator(group, point, bn_order, cofactor))
+ goto err;
+
+ EC_GROUP_set_asn1_flag(group, 0x0);
+
+ if ((key = EC_KEY_new()) == NULL)
+ goto err;
+
+ if (!EC_KEY_set_group(key, group))
+ goto err;
+
+ goto done;
+
+ err:
+ if (key)
+ EC_KEY_free(key);
+ key = NULL;
+
+ done:
+ /* some OpenSSL structures are mem-dup'ed into the key,
+ so we have to free our copies here */
+ if (bn_order)
+ BN_free(bn_order);
+ if (cofactor)
+ BN_free(cofactor);
+ if (a)
+ BN_free(a);
+ if (b)
+ BN_free(b);
+ if (p)
+ BN_free(p);
+ if (group)
+ EC_GROUP_free(group);
+ if (point)
+ EC_POINT_free(point);
+
+ return key;
+}
+
+static ERL_NIF_TERM point2term(ErlNifEnv* env,
+ const EC_GROUP *group,
+ const EC_POINT *point,
+ point_conversion_form_t form)
+{
+ ERL_NIF_TERM ret;
+ size_t dlen;
+ ErlNifBinary bin;
+ int bin_alloc = 0;
+
+ if ((dlen = EC_POINT_point2oct(group, point, form, NULL, 0, NULL)) == 0)
+ return atom_undefined;
+
+ if (!enif_alloc_binary(dlen, &bin))
+ goto err;
+ bin_alloc = 1;
+
+ if (!EC_POINT_point2oct(group, point, form, bin.data, bin.size, NULL))
+ goto err;
+
+ ERL_VALGRIND_MAKE_MEM_DEFINED(bin.data, bin.size);
+
+ ret = enif_make_binary(env, &bin);
+ bin_alloc = 0;
+ goto done;
+
+ err:
+ if (bin_alloc)
+ enif_release_binary(&bin);
+ ret = enif_make_badarg(env);
+
+ done:
+ return ret;
+}
+
+int term2point(ErlNifEnv* env, ERL_NIF_TERM term, EC_GROUP *group, EC_POINT **pptr)
+{
+ ErlNifBinary bin;
+ EC_POINT *point = NULL;
+
+ if (!enif_inspect_binary(env, term, &bin))
+ goto err;
+
+ if ((point = EC_POINT_new(group)) == NULL)
+ goto err;
+
+ /* set the point conversion form */
+ EC_GROUP_set_point_conversion_form(group, (point_conversion_form_t)(bin.data[0] & ~0x01));
+
+ /* extract the ec point */
+ if (!EC_POINT_oct2point(group, point, bin.data, bin.size, NULL))
+ goto err;
+
+ *pptr = point;
+ return 1;
+
+ err:
+ if (point)
+ EC_POINT_free(point);
+ return 0;
+}
+
+int get_ec_key(ErlNifEnv* env,
+ ERL_NIF_TERM curve, ERL_NIF_TERM priv, ERL_NIF_TERM pub,
+ EC_KEY** res)
+{
+ EC_KEY *key = NULL;
+ BIGNUM *priv_key = NULL;
+ EC_POINT *pub_key = NULL;
+ EC_GROUP *group = NULL;
+
+ if (priv != atom_undefined) {
+ if (!get_bn_from_bin(env, priv, &priv_key))
+ goto err;
+ }
+ if (pub != atom_undefined) {
+ if (!enif_is_binary(env, pub))
+ goto err;
+ }
+
+ if ((key = ec_key_new(env, curve)) == NULL)
+ goto err;
+
+ if ((group = EC_GROUP_dup(EC_KEY_get0_group(key))) == NULL)
+ goto err;
+
+ if (term2point(env, pub, group, &pub_key)) {
+ if (!EC_KEY_set_public_key(key, pub_key))
+ goto err;
+ }
+
+ if (priv != atom_undefined && !BN_is_zero(priv_key)) {
+ if (!EC_KEY_set_private_key(key, priv_key))
+ goto err;
+
+ /* calculate public key (if necessary) */
+ if (EC_KEY_get0_public_key(key) == NULL) {
+ /* the public key was not included in the SEC1 private
+ * key => calculate the public key */
+ if ((pub_key = EC_POINT_new(group)) == NULL)
+ goto err;
+ if (!EC_POINT_copy(pub_key, EC_GROUP_get0_generator(group)))
+ goto err;
+ if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, NULL))
+ goto err;
+ if (!EC_KEY_set_public_key(key, pub_key))
+ goto err;
+ }
+ }
+ goto done;
+
+ err:
+ if (key)
+ EC_KEY_free(key);
+ key = NULL;
+
+ done:
+ /* some OpenSSL structures are mem-dup'ed into the key,
+ so we have to free our copies here */
+ if (priv_key)
+ BN_clear_free(priv_key);
+ if (group)
+ EC_GROUP_free(group);
+ if (pub_key)
+ EC_POINT_free(pub_key);
+
+ if (key == NULL)
+ return 0;
+
+ *res = key;
+ return 1;
+}
+
+#endif /* HAVE_EC */
+
+ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+#if defined(HAVE_EC)
+ EC_KEY *key = NULL;
+ const EC_GROUP *group;
+ const EC_POINT *public_key;
+ ERL_NIF_TERM priv_key;
+ ERL_NIF_TERM pub_key;
+ ERL_NIF_TERM ret;
+
+ if (!get_ec_key(env, argv[0], argv[1], atom_undefined, &key))
+ goto bad_arg;
+
+ if (argv[1] == atom_undefined) {
+ if (!EC_KEY_generate_key(key))
+ goto err;
+ }
+
+ group = EC_KEY_get0_group(key);
+ public_key = EC_KEY_get0_public_key(key);
+
+ if (group == NULL || public_key == NULL) {
+ pub_key = atom_undefined;
+
+ } else {
+ pub_key = point2term(env, group, public_key,
+ EC_KEY_get_conv_form(key));
+ }
+
+ priv_key = bn2term(env, EC_KEY_get0_private_key(key));
+ ret = enif_make_tuple2(env, pub_key, priv_key);
+ goto done;
+
+ err:
+ bad_arg:
+ ret = make_badarg_maybe(env);
+
+ done:
+ if (key)
+ EC_KEY_free(key);
+ return ret;
+
+#else
+ return atom_notsup;
+#endif
+}
diff --git a/lib/crypto/c_src/ec.h b/lib/crypto/c_src/ec.h
new file mode 100644
index 0000000000..b7e1cc5a46
--- /dev/null
+++ b/lib/crypto/c_src/ec.h
@@ -0,0 +1,35 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_EC_H__
+#define E_EC_H__ 1
+
+#include "common.h"
+
+#if defined(HAVE_EC)
+int get_ec_key(ErlNifEnv* env, ERL_NIF_TERM curve, ERL_NIF_TERM priv, ERL_NIF_TERM pub,
+ EC_KEY** res);
+int term2point(ErlNifEnv* env, ERL_NIF_TERM term, EC_GROUP *group, EC_POINT **pptr);
+ERL_NIF_TERM make_badarg_maybe(ErlNifEnv* env);
+#endif
+
+ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+#endif /* E_EC_H__ */
diff --git a/lib/crypto/c_src/ecdh.c b/lib/crypto/c_src/ecdh.c
new file mode 100644
index 0000000000..9e3f460519
--- /dev/null
+++ b/lib/crypto/c_src/ecdh.c
@@ -0,0 +1,94 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "ecdh.h"
+#include "ec.h"
+
+/*
+ (_OthersPublicKey, _MyPrivateKey)
+ (_OthersPublicKey, _MyEC_Point)
+*/
+ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+/* (OtherPublicKey, Curve, My) */
+{
+#if defined(HAVE_EC)
+ ERL_NIF_TERM ret;
+ unsigned char *p;
+ EC_KEY* key = NULL;
+ int degree;
+ size_t field_size;
+ EC_GROUP *group = NULL;
+ const BIGNUM *priv_key;
+ EC_POINT *my_ecpoint = NULL;
+ EC_KEY *other_ecdh = NULL;
+
+ ASSERT(argc == 3);
+
+ if (!get_ec_key(env, argv[1], argv[2], atom_undefined, &key))
+ goto bad_arg;
+ if ((group = EC_GROUP_dup(EC_KEY_get0_group(key))) == NULL)
+ goto bad_arg;
+ priv_key = EC_KEY_get0_private_key(key);
+
+ if (!term2point(env, argv[0], group, &my_ecpoint)) {
+ goto err;
+ }
+
+ if ((other_ecdh = EC_KEY_new()) == NULL)
+ goto err;
+ if (!EC_KEY_set_group(other_ecdh, group))
+ goto err;
+ if (!EC_KEY_set_private_key(other_ecdh, priv_key))
+ goto err;
+
+ if ((degree = EC_GROUP_get_degree(group)) <= 0)
+ goto err;
+
+ field_size = (size_t)degree;
+ if ((p = enif_make_new_binary(env, (field_size+7)/8, &ret)) == NULL)
+ goto err;
+ if (ECDH_compute_key(p, (field_size+7)/8, my_ecpoint, other_ecdh, NULL) < 1)
+ goto err;
+
+ goto done;
+
+ bad_arg:
+ ret = make_badarg_maybe(env);
+ goto done;
+
+ err:
+ ret = enif_make_badarg(env);
+
+ done:
+ if (group)
+ EC_GROUP_free(group);
+ if (my_ecpoint)
+ EC_POINT_free(my_ecpoint);
+ if (other_ecdh)
+ EC_KEY_free(other_ecdh);
+ if (key)
+ EC_KEY_free(key);
+
+ return ret;
+
+#else
+ return atom_notsup;
+#endif
+}
diff --git a/lib/crypto/c_src/ecdh.h b/lib/crypto/c_src/ecdh.h
new file mode 100644
index 0000000000..5ed331e676
--- /dev/null
+++ b/lib/crypto/c_src/ecdh.h
@@ -0,0 +1,28 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_ECDH_H__
+#define E_ECDH_H__ 1
+
+#include "common.h"
+
+ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+#endif /* E_ECDH_H__ */
diff --git a/lib/crypto/c_src/eddsa.c b/lib/crypto/c_src/eddsa.c
new file mode 100644
index 0000000000..0c89f9f6db
--- /dev/null
+++ b/lib/crypto/c_src/eddsa.c
@@ -0,0 +1,63 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "eddsa.h"
+
+#ifdef HAVE_EDDSA
+int get_eddsa_key(ErlNifEnv* env, int public, ERL_NIF_TERM key, EVP_PKEY **pkey)
+{
+ /* key=[K] */
+ EVP_PKEY *result;
+ ERL_NIF_TERM head, tail, tail2, algo;
+ ErlNifBinary bin;
+ int type;
+
+ if (!enif_get_list_cell(env, key, &head, &tail))
+ goto err;
+ if (!enif_inspect_binary(env, head, &bin))
+ goto err;
+ if (!enif_get_list_cell(env, tail, &algo, &tail2))
+ goto err;
+ if (!enif_is_empty_list(env, tail2))
+ goto err;
+
+ if (algo == atom_ed25519) {
+ type = EVP_PKEY_ED25519;
+ } else if (algo == atom_ed448) {
+ type = EVP_PKEY_ED448;
+ } else {
+ goto err;
+ }
+
+ if (public)
+ result = EVP_PKEY_new_raw_public_key(type, NULL, bin.data, bin.size);
+ else
+ result = EVP_PKEY_new_raw_private_key(type, NULL, bin.data, bin.size);
+
+ if (result == NULL)
+ goto err;
+
+ *pkey = result;
+ return 1;
+
+ err:
+ return 0;
+}
+#endif
diff --git a/lib/crypto/c_src/eddsa.h b/lib/crypto/c_src/eddsa.h
new file mode 100644
index 0000000000..4b30247cab
--- /dev/null
+++ b/lib/crypto/c_src/eddsa.h
@@ -0,0 +1,30 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_EDDSA_H__
+#define E_EDDSA_H__ 1
+
+#include "common.h"
+
+#ifdef HAVE_EDDSA
+int get_eddsa_key(ErlNifEnv* env, int public, ERL_NIF_TERM key, EVP_PKEY **pkey);
+#endif
+
+#endif /* E_EDDSA_H__ */
diff --git a/lib/crypto/c_src/engine.c b/lib/crypto/c_src/engine.c
new file mode 100644
index 0000000000..ea5d9a588f
--- /dev/null
+++ b/lib/crypto/c_src/engine.c
@@ -0,0 +1,840 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "engine.h"
+
+#ifdef HAS_ENGINE_SUPPORT
+struct engine_ctx {
+ ENGINE *engine;
+ char *id;
+};
+
+#define ERROR_Term(Env, ReasonTerm) enif_make_tuple2((Env), atom_error, (ReasonTerm))
+#define ERROR_Atom(Env, ReasonString) ERROR_Term((Env), enif_make_atom((Env),(ReasonString)))
+
+static ErlNifResourceType* engine_ctx_rtype;
+
+static int get_engine_load_cmd_list(ErlNifEnv* env, const ERL_NIF_TERM term, char **cmds, int i);
+static int zero_terminate(ErlNifBinary bin, char **buf);
+
+static void engine_ctx_dtor(ErlNifEnv* env, struct engine_ctx* ctx) {
+ if (ctx == NULL)
+ return;
+
+ PRINTF_ERR0("engine_ctx_dtor");
+ if(ctx->id) {
+ PRINTF_ERR1(" non empty ctx->id=%s", ctx->id);
+ enif_free(ctx->id);
+ } else
+ PRINTF_ERR0(" empty ctx->id=NULL");
+}
+
+int get_engine_and_key_id(ErlNifEnv *env, ERL_NIF_TERM key, char ** id, ENGINE **e)
+{
+ ERL_NIF_TERM engine_res, key_id_term;
+ struct engine_ctx *ctx;
+ ErlNifBinary key_id_bin;
+
+ if (!enif_get_map_value(env, key, atom_engine, &engine_res))
+ goto err;
+ if (!enif_get_resource(env, engine_res, engine_ctx_rtype, (void**)&ctx))
+ goto err;
+ if (!enif_get_map_value(env, key, atom_key_id, &key_id_term))
+ goto err;
+ if (!enif_inspect_binary(env, key_id_term, &key_id_bin))
+ goto err;
+
+ *e = ctx->engine;
+ return zero_terminate(key_id_bin, id);
+
+ err:
+ return 0;
+}
+
+char *get_key_password(ErlNifEnv *env, ERL_NIF_TERM key) {
+ ERL_NIF_TERM tmp_term;
+ ErlNifBinary pwd_bin;
+ char *pwd = NULL;
+
+ if (!enif_get_map_value(env, key, atom_password, &tmp_term))
+ goto err;
+ if (!enif_inspect_binary(env, tmp_term, &pwd_bin))
+ goto err;
+ if (!zero_terminate(pwd_bin, &pwd))
+ goto err;
+
+ return pwd;
+
+ err:
+ return NULL;
+}
+
+static int zero_terminate(ErlNifBinary bin, char **buf) {
+ if ((*buf = enif_alloc(bin.size + 1)) == NULL)
+ goto err;
+
+ memcpy(*buf, bin.data, bin.size);
+ *(*buf + bin.size) = 0;
+
+ return 1;
+
+ err:
+ return 0;
+}
+#endif /* HAS_ENGINE_SUPPORT */
+
+int init_engine_ctx(ErlNifEnv *env) {
+#ifdef HAS_ENGINE_SUPPORT
+ engine_ctx_rtype = enif_open_resource_type(env, NULL, "ENGINE_CTX",
+ (ErlNifResourceDtor*) engine_ctx_dtor,
+ ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER,
+ NULL);
+ if (engine_ctx_rtype == NULL) {
+ PRINTF_ERR0("CRYPTO: Could not open resource type 'ENGINE_CTX'");
+ return 0;
+ }
+#endif
+
+ return 1;
+}
+
+ERL_NIF_TERM engine_by_id_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (EngineId) */
+#ifdef HAS_ENGINE_SUPPORT
+ ERL_NIF_TERM ret, result;
+ ErlNifBinary engine_id_bin;
+ char *engine_id = NULL;
+ ENGINE *engine;
+ struct engine_ctx *ctx = NULL;
+
+ // Get Engine Id
+ ASSERT(argc == 1);
+
+ if (!enif_inspect_binary(env, argv[0], &engine_id_bin))
+ goto bad_arg;
+
+ if ((engine_id = enif_alloc(engine_id_bin.size+1)) == NULL)
+ goto err;
+ (void) memcpy(engine_id, engine_id_bin.data, engine_id_bin.size);
+ engine_id[engine_id_bin.size] = '\0';
+
+ if ((engine = ENGINE_by_id(engine_id)) == NULL) {
+ PRINTF_ERR0("engine_by_id_nif Leaved: {error, bad_engine_id}");
+ ret = ERROR_Atom(env, "bad_engine_id");
+ goto done;
+ }
+
+ if ((ctx = enif_alloc_resource(engine_ctx_rtype, sizeof(struct engine_ctx))) == NULL)
+ goto err;
+ ctx->engine = engine;
+ ctx->id = engine_id;
+ /* ctx now owns engine_id */
+ engine_id = NULL;
+
+ result = enif_make_resource(env, ctx);
+ ret = enif_make_tuple2(env, atom_ok, result);
+ goto done;
+
+ bad_arg:
+ err:
+ ret = enif_make_badarg(env);
+
+ done:
+ if (engine_id)
+ enif_free(engine_id);
+ if (ctx)
+ enif_release_resource(ctx);
+ return ret;
+
+#else
+ return atom_notsup;
+#endif
+}
+
+ERL_NIF_TERM engine_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Engine) */
+#ifdef HAS_ENGINE_SUPPORT
+ struct engine_ctx *ctx;
+
+ // Get Engine
+ ASSERT(argc == 1);
+
+ if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx))
+ goto bad_arg;
+
+ if (!ENGINE_init(ctx->engine))
+ return ERROR_Atom(env, "engine_init_failed");
+
+ return atom_ok;
+
+ bad_arg:
+ return enif_make_badarg(env);
+
+#else
+ return atom_notsup;
+#endif
+}
+
+ERL_NIF_TERM engine_free_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Engine) */
+#ifdef HAS_ENGINE_SUPPORT
+ struct engine_ctx *ctx;
+
+ // Get Engine
+ ASSERT(argc == 1);
+
+ if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx))
+ goto bad_arg;
+
+ if (!ENGINE_free(ctx->engine))
+ goto err;
+ return atom_ok;
+
+ bad_arg:
+ err:
+ return enif_make_badarg(env);
+#else
+ return atom_notsup;
+#endif
+}
+
+ERL_NIF_TERM engine_finish_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Engine) */
+#ifdef HAS_ENGINE_SUPPORT
+ struct engine_ctx *ctx;
+
+ // Get Engine
+ ASSERT(argc == 1);
+
+ if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx))
+ goto bad_arg;
+
+ if (!ENGINE_finish(ctx->engine))
+ goto err;
+ return atom_ok;
+
+ bad_arg:
+ err:
+ return enif_make_badarg(env);
+
+#else
+ return atom_notsup;
+#endif
+}
+
+ERL_NIF_TERM engine_load_dynamic_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* () */
+#ifdef HAS_ENGINE_SUPPORT
+ ASSERT(argc == 0);
+
+ ENGINE_load_dynamic();
+ return atom_ok;
+#else
+ return atom_notsup;
+#endif
+}
+
+ERL_NIF_TERM engine_ctrl_cmd_strings_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Engine, Commands, Optional) */
+#ifdef HAS_ENGINE_SUPPORT
+ ERL_NIF_TERM ret;
+ unsigned int cmds_len = 0;
+ char **cmds = NULL;
+ struct engine_ctx *ctx;
+ unsigned int i;
+ int optional = 0;
+ int cmds_loaded = 0;
+
+ // Get Engine
+ ASSERT(argc == 3);
+
+ if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx))
+ goto bad_arg;
+
+ PRINTF_ERR1("Engine Id: %s\r\n", ENGINE_get_id(ctx->engine));
+ // Get Command List
+ if (!enif_get_list_length(env, argv[1], &cmds_len))
+ goto bad_arg;
+
+ if (cmds_len > (UINT_MAX / 2) - 1)
+ goto err;
+ cmds_len *= 2; // Key-Value list from erlang
+
+ if ((size_t)cmds_len + 1 > SIZE_MAX / sizeof(char*))
+ goto err;
+ if ((cmds = enif_alloc((cmds_len + 1) * sizeof(char*))) == NULL)
+ goto err;
+ if (get_engine_load_cmd_list(env, argv[1], cmds, 0))
+ goto err;
+ cmds_loaded = 1;
+ if (!enif_get_int(env, argv[2], &optional))
+ goto err;
+
+ for(i = 0; i < cmds_len; i+=2) {
+ PRINTF_ERR2("Cmd: %s:%s\r\n",
+ cmds[i] ? cmds[i] : "(NULL)",
+ cmds[i+1] ? cmds[i+1] : "(NULL)");
+ if(!ENGINE_ctrl_cmd_string(ctx->engine, cmds[i], cmds[i+1], optional)) {
+ PRINTF_ERR2("Command failed: %s:%s\r\n",
+ cmds[i] ? cmds[i] : "(NULL)",
+ cmds[i+1] ? cmds[i+1] : "(NULL)");
+ goto cmd_failed;
+ }
+ }
+ ret = atom_ok;
+ goto done;
+
+ bad_arg:
+ err:
+ ret = enif_make_badarg(env);
+ goto done;
+
+ cmd_failed:
+ ret = ERROR_Atom(env, "ctrl_cmd_failed");
+
+ done:
+ if (cmds_loaded) {
+ for (i = 0; cmds != NULL && cmds[i] != NULL; i++)
+ enif_free(cmds[i]);
+ }
+
+ if (cmds != NULL)
+ enif_free(cmds);
+
+ return ret;
+
+#else
+ return atom_notsup;
+#endif
+}
+
+ERL_NIF_TERM engine_add_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Engine) */
+#ifdef HAS_ENGINE_SUPPORT
+ struct engine_ctx *ctx;
+
+ // Get Engine
+ ASSERT(argc == 1);
+
+ if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx))
+ goto bad_arg;
+
+ if (!ENGINE_add(ctx->engine))
+ goto failed;
+
+ return atom_ok;
+
+ bad_arg:
+ return enif_make_badarg(env);
+
+ failed:
+ return ERROR_Atom(env, "add_engine_failed");
+
+#else
+ return atom_notsup;
+#endif
+}
+
+ERL_NIF_TERM engine_remove_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Engine) */
+#ifdef HAS_ENGINE_SUPPORT
+ struct engine_ctx *ctx;
+
+ // Get Engine
+ ASSERT(argc == 1);
+
+ if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx))
+ goto bad_arg;
+
+ if (!ENGINE_remove(ctx->engine))
+ goto failed;
+
+ return atom_ok;
+
+ bad_arg:
+ return enif_make_badarg(env);
+
+ failed:
+ return ERROR_Atom(env, "remove_engine_failed");
+#else
+ return atom_notsup;
+#endif
+}
+
+ERL_NIF_TERM engine_register_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Engine, EngineMethod) */
+#ifdef HAS_ENGINE_SUPPORT
+ struct engine_ctx *ctx;
+ unsigned int method;
+
+ // Get Engine
+ ASSERT(argc == 2);
+
+ if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx))
+ goto bad_arg;
+ if (!enif_get_uint(env, argv[1], &method))
+ goto bad_arg;
+
+ switch(method)
+ {
+#ifdef ENGINE_METHOD_RSA
+ case ENGINE_METHOD_RSA:
+ if (!ENGINE_register_RSA(ctx->engine))
+ goto failed;
+ break;
+#endif
+#ifdef ENGINE_METHOD_DSA
+ case ENGINE_METHOD_DSA:
+ if (!ENGINE_register_DSA(ctx->engine))
+ goto failed;
+ break;
+#endif
+#ifdef ENGINE_METHOD_DH
+ case ENGINE_METHOD_DH:
+ if (!ENGINE_register_DH(ctx->engine))
+ goto failed;
+ break;
+#endif
+#ifdef ENGINE_METHOD_RAND
+ case ENGINE_METHOD_RAND:
+ if (!ENGINE_register_RAND(ctx->engine))
+ goto failed;
+ break;
+#endif
+#ifdef ENGINE_METHOD_ECDH
+ case ENGINE_METHOD_ECDH:
+ if (!ENGINE_register_ECDH(ctx->engine))
+ goto failed;
+ break;
+#endif
+#ifdef ENGINE_METHOD_ECDSA
+ case ENGINE_METHOD_ECDSA:
+ if (!ENGINE_register_ECDSA(ctx->engine))
+ goto failed;
+ break;
+#endif
+#ifdef ENGINE_METHOD_STORE
+ case ENGINE_METHOD_STORE:
+ if (!ENGINE_register_STORE(ctx->engine))
+ goto failed;
+ break;
+#endif
+#ifdef ENGINE_METHOD_CIPHERS
+ case ENGINE_METHOD_CIPHERS:
+ if (!ENGINE_register_ciphers(ctx->engine))
+ goto failed;
+ break;
+#endif
+#ifdef ENGINE_METHOD_DIGESTS
+ case ENGINE_METHOD_DIGESTS:
+ if (!ENGINE_register_digests(ctx->engine))
+ goto failed;
+ break;
+#endif
+#ifdef ENGINE_METHOD_PKEY_METHS
+ case ENGINE_METHOD_PKEY_METHS:
+ if (!ENGINE_register_pkey_meths(ctx->engine))
+ goto failed;
+ break;
+#endif
+#ifdef ENGINE_METHOD_PKEY_ASN1_METHS
+ case ENGINE_METHOD_PKEY_ASN1_METHS:
+ if (!ENGINE_register_pkey_asn1_meths(ctx->engine))
+ goto failed;
+ break;
+#endif
+#ifdef ENGINE_METHOD_EC
+ case ENGINE_METHOD_EC:
+ if (!ENGINE_register_EC(ctx->engine))
+ goto failed;
+ break;
+#endif
+ default:
+ return ERROR_Atom(env, "engine_method_not_supported");
+ }
+
+ return atom_ok;
+
+ bad_arg:
+ return enif_make_badarg(env);
+
+ failed:
+ return ERROR_Atom(env, "register_engine_failed");
+
+#else
+ return atom_notsup;
+#endif
+}
+
+ERL_NIF_TERM engine_unregister_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Engine, EngineMethod) */
+#ifdef HAS_ENGINE_SUPPORT
+ struct engine_ctx *ctx;
+ unsigned int method;
+
+ // Get Engine
+ ASSERT(argc == 2);
+
+ if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx))
+ goto bad_arg;
+ if (!enif_get_uint(env, argv[1], &method))
+ goto bad_arg;
+
+ switch(method)
+ {
+#ifdef ENGINE_METHOD_RSA
+ case ENGINE_METHOD_RSA:
+ ENGINE_unregister_RSA(ctx->engine);
+ break;
+#endif
+#ifdef ENGINE_METHOD_DSA
+ case ENGINE_METHOD_DSA:
+ ENGINE_unregister_DSA(ctx->engine);
+ break;
+#endif
+#ifdef ENGINE_METHOD_DH
+ case ENGINE_METHOD_DH:
+ ENGINE_unregister_DH(ctx->engine);
+ break;
+#endif
+#ifdef ENGINE_METHOD_RAND
+ case ENGINE_METHOD_RAND:
+ ENGINE_unregister_RAND(ctx->engine);
+ break;
+#endif
+#ifdef ENGINE_METHOD_ECDH
+ case ENGINE_METHOD_ECDH:
+ ENGINE_unregister_ECDH(ctx->engine);
+ break;
+#endif
+#ifdef ENGINE_METHOD_ECDSA
+ case ENGINE_METHOD_ECDSA:
+ ENGINE_unregister_ECDSA(ctx->engine);
+ break;
+#endif
+#ifdef ENGINE_METHOD_STORE
+ case ENGINE_METHOD_STORE:
+ ENGINE_unregister_STORE(ctx->engine);
+ break;
+#endif
+#ifdef ENGINE_METHOD_CIPHERS
+ case ENGINE_METHOD_CIPHERS:
+ ENGINE_unregister_ciphers(ctx->engine);
+ break;
+#endif
+#ifdef ENGINE_METHOD_DIGESTS
+ case ENGINE_METHOD_DIGESTS:
+ ENGINE_unregister_digests(ctx->engine);
+ break;
+#endif
+#ifdef ENGINE_METHOD_PKEY_METHS
+ case ENGINE_METHOD_PKEY_METHS:
+ ENGINE_unregister_pkey_meths(ctx->engine);
+ break;
+#endif
+#ifdef ENGINE_METHOD_PKEY_ASN1_METHS
+ case ENGINE_METHOD_PKEY_ASN1_METHS:
+ ENGINE_unregister_pkey_asn1_meths(ctx->engine);
+ break;
+#endif
+#ifdef ENGINE_METHOD_EC
+ case ENGINE_METHOD_EC:
+ ENGINE_unregister_EC(ctx->engine);
+ break;
+#endif
+ default:
+ break;
+ }
+
+ return atom_ok;
+
+ bad_arg:
+ return enif_make_badarg(env);
+
+#else
+ return atom_notsup;
+#endif
+}
+
+ERL_NIF_TERM engine_get_first_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* () */
+#ifdef HAS_ENGINE_SUPPORT
+ ERL_NIF_TERM ret, result;
+ ENGINE *engine;
+ ErlNifBinary engine_bin;
+ struct engine_ctx *ctx = NULL;
+
+ ASSERT(argc == 0);
+
+ if ((engine = ENGINE_get_first()) == NULL) {
+ if (!enif_alloc_binary(0, &engine_bin))
+ goto err;
+ engine_bin.size = 0;
+ return enif_make_tuple2(env, atom_ok, enif_make_binary(env, &engine_bin));
+ }
+
+ if ((ctx = enif_alloc_resource(engine_ctx_rtype, sizeof(struct engine_ctx))) == NULL)
+ goto err;
+ ctx->engine = engine;
+ ctx->id = NULL;
+
+ result = enif_make_resource(env, ctx);
+ ret = enif_make_tuple2(env, atom_ok, result);
+ goto done;
+
+ err:
+ ret = enif_make_badarg(env);
+
+ done:
+ if (ctx)
+ enif_release_resource(ctx);
+ return ret;
+
+#else
+ return atom_notsup;
+#endif
+}
+
+ERL_NIF_TERM engine_get_next_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Engine) */
+#ifdef HAS_ENGINE_SUPPORT
+ ERL_NIF_TERM ret, result;
+ ENGINE *engine;
+ ErlNifBinary engine_bin;
+ struct engine_ctx *ctx, *next_ctx = NULL;
+
+ // Get Engine
+ ASSERT(argc == 1);
+
+ if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx))
+ goto bad_arg;
+
+ if ((engine = ENGINE_get_next(ctx->engine)) == NULL) {
+ if (!enif_alloc_binary(0, &engine_bin))
+ goto err;
+ engine_bin.size = 0;
+ return enif_make_tuple2(env, atom_ok, enif_make_binary(env, &engine_bin));
+ }
+
+ if ((next_ctx = enif_alloc_resource(engine_ctx_rtype, sizeof(struct engine_ctx))) == NULL)
+ goto err;
+ next_ctx->engine = engine;
+ next_ctx->id = NULL;
+
+ result = enif_make_resource(env, next_ctx);
+ ret = enif_make_tuple2(env, atom_ok, result);
+ goto done;
+
+ bad_arg:
+ err:
+ ret = enif_make_badarg(env);
+
+ done:
+ if (next_ctx)
+ enif_release_resource(next_ctx);
+ return ret;
+
+#else
+ return atom_notsup;
+#endif
+}
+
+ERL_NIF_TERM engine_get_id_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Engine) */
+#ifdef HAS_ENGINE_SUPPORT
+ ErlNifBinary engine_id_bin;
+ const char *engine_id;
+ size_t size;
+ struct engine_ctx *ctx = NULL;
+
+ // Get Engine
+ ASSERT(argc == 1);
+
+ if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx))
+ goto bad_arg;
+
+ if ((engine_id = ENGINE_get_id(ctx->engine)) == NULL) {
+ if (!enif_alloc_binary(0, &engine_id_bin))
+ goto err;
+ engine_id_bin.size = 0;
+ return enif_make_binary(env, &engine_id_bin);
+ }
+
+ size = strlen(engine_id);
+ if (!enif_alloc_binary(size, &engine_id_bin))
+ goto err;
+ engine_id_bin.size = size;
+ memcpy(engine_id_bin.data, engine_id, size);
+
+ return enif_make_binary(env, &engine_id_bin);
+
+ bad_arg:
+ err:
+ return enif_make_badarg(env);
+
+#else
+ return atom_notsup;
+#endif
+}
+
+ERL_NIF_TERM engine_get_name_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Engine) */
+#ifdef HAS_ENGINE_SUPPORT
+ ErlNifBinary engine_name_bin;
+ const char *engine_name;
+ size_t size;
+ struct engine_ctx *ctx;
+
+ // Get Engine
+ ASSERT(argc == 1);
+
+ if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx))
+ goto bad_arg;
+
+ if ((engine_name = ENGINE_get_name(ctx->engine)) == NULL) {
+ if (!enif_alloc_binary(0, &engine_name_bin))
+ goto err;
+ engine_name_bin.size = 0;
+ return enif_make_binary(env, &engine_name_bin);
+ }
+
+ size = strlen(engine_name);
+ if (!enif_alloc_binary(size, &engine_name_bin))
+ goto err;
+ engine_name_bin.size = size;
+ memcpy(engine_name_bin.data, engine_name, size);
+
+ return enif_make_binary(env, &engine_name_bin);
+
+ bad_arg:
+ err:
+ return enif_make_badarg(env);
+
+#else
+ return atom_notsup;
+#endif
+}
+
+#ifdef HAS_ENGINE_SUPPORT
+static int get_engine_load_cmd_list(ErlNifEnv* env, const ERL_NIF_TERM term, char **cmds, int i)
+{
+ ERL_NIF_TERM head, tail;
+ const ERL_NIF_TERM *tmp_tuple;
+ ErlNifBinary tmpbin;
+ int arity;
+ char *tuple1 = NULL, *tuple2 = NULL;
+
+ if (enif_is_empty_list(env, term)) {
+ cmds[i] = NULL;
+ return 0;
+ }
+
+ if (!enif_get_list_cell(env, term, &head, &tail))
+ goto err;
+ if (!enif_get_tuple(env, head, &arity, &tmp_tuple))
+ goto err;
+ if (arity != 2)
+ goto err;
+ if (!enif_inspect_binary(env, tmp_tuple[0], &tmpbin))
+ goto err;
+
+ if ((tuple1 = enif_alloc(tmpbin.size + 1)) == NULL)
+ goto err;
+
+ (void) memcpy(tuple1, tmpbin.data, tmpbin.size);
+ tuple1[tmpbin.size] = '\0';
+ cmds[i] = tuple1;
+ i++;
+
+ if (!enif_inspect_binary(env, tmp_tuple[1], &tmpbin))
+ goto err;
+
+ if (tmpbin.size == 0) {
+ cmds[i] = NULL;
+ } else {
+ if ((tuple2 = enif_alloc(tmpbin.size + 1)) == NULL)
+ goto err;
+ (void) memcpy(tuple2, tmpbin.data, tmpbin.size);
+ tuple2[tmpbin.size] = '\0';
+ cmds[i] = tuple2;
+ }
+ i++;
+ return get_engine_load_cmd_list(env, tail, cmds, i);
+
+ err:
+ if (tuple1 != NULL) {
+ i--;
+ enif_free(tuple1);
+ }
+ cmds[i] = NULL;
+ return -1;
+}
+#endif /* HAS_ENGINE_SUPPORT */
+
+ERL_NIF_TERM engine_get_all_methods_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* () */
+#ifdef HAS_ENGINE_SUPPORT
+ ERL_NIF_TERM method_array[12];
+ unsigned int i = 0;
+
+ ASSERT(argc == 0);
+
+#ifdef ENGINE_METHOD_RSA
+ method_array[i++] = atom_engine_method_rsa;
+#endif
+#ifdef ENGINE_METHOD_DSA
+ method_array[i++] = atom_engine_method_dsa;
+#endif
+#ifdef ENGINE_METHOD_DH
+ method_array[i++] = atom_engine_method_dh;
+#endif
+#ifdef ENGINE_METHOD_RAND
+ method_array[i++] = atom_engine_method_rand;
+#endif
+#ifdef ENGINE_METHOD_ECDH
+ method_array[i++] = atom_engine_method_ecdh;
+#endif
+#ifdef ENGINE_METHOD_ECDSA
+ method_array[i++] = atom_engine_method_ecdsa;
+#endif
+#ifdef ENGINE_METHOD_STORE
+ method_array[i++] = atom_engine_method_store;
+#endif
+#ifdef ENGINE_METHOD_CIPHERS
+ method_array[i++] = atom_engine_method_ciphers;
+#endif
+#ifdef ENGINE_METHOD_DIGESTS
+ method_array[i++] = atom_engine_method_digests;
+#endif
+#ifdef ENGINE_METHOD_PKEY_METHS
+ method_array[i++] = atom_engine_method_pkey_meths;
+#endif
+#ifdef ENGINE_METHOD_PKEY_ASN1_METHS
+ method_array[i++] = atom_engine_method_pkey_asn1_meths;
+#endif
+#ifdef ENGINE_METHOD_EC
+ method_array[i++] = atom_engine_method_ec;
+#endif
+
+ return enif_make_list_from_array(env, method_array, i);
+#else
+ return atom_notsup;
+#endif
+}
diff --git a/lib/crypto/c_src/engine.h b/lib/crypto/c_src/engine.h
new file mode 100644
index 0000000000..4a2eed9672
--- /dev/null
+++ b/lib/crypto/c_src/engine.h
@@ -0,0 +1,49 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_ENGINE_H__
+#define E_ENGINE_H__ 1
+
+#include "common.h"
+
+#ifdef HAS_ENGINE_SUPPORT
+int get_engine_and_key_id(ErlNifEnv *env, ERL_NIF_TERM key, char ** id, ENGINE **e);
+char *get_key_password(ErlNifEnv *env, ERL_NIF_TERM key);
+#endif /* HAS_ENGINE_SUPPORT */
+
+int init_engine_ctx(ErlNifEnv *env);
+
+ERL_NIF_TERM engine_by_id_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM engine_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM engine_finish_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM engine_free_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM engine_load_dynamic_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM engine_ctrl_cmd_strings_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM engine_register_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM engine_unregister_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM engine_add_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM engine_remove_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM engine_get_first_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM engine_get_next_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM engine_get_id_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM engine_get_name_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM engine_get_all_methods_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+#endif /* E_ENGINE_H__ */
diff --git a/lib/crypto/c_src/evp.c b/lib/crypto/c_src/evp.c
new file mode 100644
index 0000000000..3bf66bfffe
--- /dev/null
+++ b/lib/crypto/c_src/evp.c
@@ -0,0 +1,164 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "evp.h"
+
+ERL_NIF_TERM evp_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+ /* (Curve, PeerBin, MyBin) */
+{
+#ifdef HAVE_ED_CURVE_DH
+ ERL_NIF_TERM ret;
+ int type;
+ EVP_PKEY_CTX *ctx = NULL;
+ ErlNifBinary peer_bin, my_bin, key_bin;
+ EVP_PKEY *peer_key = NULL, *my_key = NULL;
+ size_t max_size;
+ int key_bin_alloc = 0;
+
+ ASSERT(argc == 3);
+
+ if (argv[0] == atom_x25519)
+ type = EVP_PKEY_X25519;
+ else if (argv[0] == atom_x448)
+ type = EVP_PKEY_X448;
+ else
+ goto bad_arg;
+
+ if (!enif_inspect_binary(env, argv[1], &peer_bin))
+ goto bad_arg;
+ if (!enif_inspect_binary(env, argv[2], &my_bin))
+ goto bad_arg;
+
+ if ((my_key = EVP_PKEY_new_raw_private_key(type, NULL, my_bin.data, my_bin.size)) == NULL)
+ goto err;
+ if ((ctx = EVP_PKEY_CTX_new(my_key, NULL)) == NULL)
+ goto err;
+
+ if (EVP_PKEY_derive_init(ctx) != 1)
+ goto err;
+
+ if ((peer_key = EVP_PKEY_new_raw_public_key(type, NULL, peer_bin.data, peer_bin.size)) == NULL)
+ goto err;
+ if (EVP_PKEY_derive_set_peer(ctx, peer_key) != 1)
+ goto err;
+
+ if (EVP_PKEY_derive(ctx, NULL, &max_size) != 1)
+ goto err;
+
+ if (!enif_alloc_binary(max_size, &key_bin))
+ goto err;
+ key_bin_alloc = 1;
+ if (EVP_PKEY_derive(ctx, key_bin.data, &key_bin.size) != 1)
+ goto err;
+
+ if (key_bin.size < max_size) {
+ if (!enif_realloc_binary(&key_bin, (size_t)key_bin.size))
+ goto err;
+ }
+
+ ret = enif_make_binary(env, &key_bin);
+ key_bin_alloc = 0;
+ goto done;
+
+ bad_arg:
+ err:
+ if (key_bin_alloc)
+ enif_release_binary(&key_bin);
+ ret = enif_make_badarg(env);
+
+ done:
+ if (my_key)
+ EVP_PKEY_free(my_key);
+ if (peer_key)
+ EVP_PKEY_free(peer_key);
+ if (ctx)
+ EVP_PKEY_CTX_free(ctx);
+
+ return ret;
+
+#else
+ return atom_notsup;
+#endif
+}
+
+ERL_NIF_TERM evp_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+/* (Curve) */
+{
+#ifdef HAVE_ED_CURVE_DH
+ int type;
+ EVP_PKEY_CTX *ctx = NULL;
+ EVP_PKEY *pkey = NULL;
+ ERL_NIF_TERM ret_pub, ret_prv, ret;
+ size_t key_len;
+ unsigned char *out_pub = NULL, *out_priv = NULL;
+
+ ASSERT(argc == 1);
+
+ if (argv[0] == atom_x25519)
+ type = EVP_PKEY_X25519;
+ else if (argv[0] == atom_x448)
+ type = EVP_PKEY_X448;
+ else
+ goto bad_arg;
+
+ if ((ctx = EVP_PKEY_CTX_new_id(type, NULL)) == NULL)
+ goto bad_arg;
+
+ if (EVP_PKEY_keygen_init(ctx) != 1)
+ goto err;
+ if (EVP_PKEY_keygen(ctx, &pkey) != 1)
+ goto err;
+
+ if (EVP_PKEY_get_raw_public_key(pkey, NULL, &key_len) != 1)
+ goto err;
+ if ((out_pub = enif_make_new_binary(env, key_len, &ret_pub)) == NULL)
+ goto err;
+ if (EVP_PKEY_get_raw_public_key(pkey, out_pub, &key_len) != 1)
+ goto err;
+
+ if (EVP_PKEY_get_raw_private_key(pkey, NULL, &key_len) != 1)
+ goto err;
+ if ((out_priv = enif_make_new_binary(env, key_len, &ret_prv)) == NULL)
+ goto err;
+ if (EVP_PKEY_get_raw_private_key(pkey, out_priv, &key_len) != 1)
+ goto err;
+
+ ret = enif_make_tuple2(env, ret_pub, ret_prv);
+ goto done;
+
+ bad_arg:
+ ret = enif_make_badarg(env);
+ goto done;
+
+ err:
+ ret = atom_error;
+
+ done:
+ if (pkey)
+ EVP_PKEY_free(pkey);
+ if (ctx)
+ EVP_PKEY_CTX_free(ctx);
+ return ret;
+
+#else
+ return atom_notsup;
+#endif
+}
+
diff --git a/lib/crypto/c_src/evp.h b/lib/crypto/c_src/evp.h
new file mode 100644
index 0000000000..d767260262
--- /dev/null
+++ b/lib/crypto/c_src/evp.h
@@ -0,0 +1,29 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_EVP_H__
+#define E_EVP_H__ 1
+
+#include "common.h"
+
+ERL_NIF_TERM evp_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM evp_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+#endif /* E_EVP_H__ */
diff --git a/lib/crypto/c_src/evp_compat.h b/lib/crypto/c_src/evp_compat.h
new file mode 100644
index 0000000000..dc94a61d8e
--- /dev/null
+++ b/lib/crypto/c_src/evp_compat.h
@@ -0,0 +1,210 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_EVP_COMPAT_H__
+#define E_EVP_COMPAT_H__ 1
+
+/*
+ * In OpenSSL 1.1.0, most structs are opaque. That means that
+ * the structs cannot be allocated as automatic variables on the
+ * C stack (because the size is unknown) and that it is necessary
+ * to use access functions.
+ *
+ * For backward compatibility to previous versions of OpenSSL, define
+ * on our versions of the new functions defined in 1.1.0 here, so that
+ * we don't have to sprinkle ifdefs throughout the code.
+ */
+
+static INLINE HMAC_CTX *HMAC_CTX_new(void);
+static INLINE void HMAC_CTX_free(HMAC_CTX *ctx);
+
+static INLINE HMAC_CTX *HMAC_CTX_new()
+{
+ HMAC_CTX *ctx;
+
+ if ((ctx = CRYPTO_malloc(sizeof(HMAC_CTX), __FILE__, __LINE__)) == NULL)
+ return NULL;
+
+ HMAC_CTX_init(ctx);
+ return ctx;
+}
+
+static INLINE void HMAC_CTX_free(HMAC_CTX *ctx)
+{
+ if (ctx == NULL)
+ return;
+
+ HMAC_CTX_cleanup(ctx);
+ CRYPTO_free(ctx);
+}
+
+/* Renamed in 1.1.0 */
+#define EVP_MD_CTX_new() EVP_MD_CTX_create()
+#define EVP_MD_CTX_free(ctx) EVP_MD_CTX_destroy((ctx))
+
+static INLINE void *BN_GENCB_get_arg(BN_GENCB *cb);
+
+static INLINE void *BN_GENCB_get_arg(BN_GENCB *cb)
+{
+ return cb->arg;
+}
+
+static INLINE int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d);
+static INLINE void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d);
+static INLINE int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q);
+static INLINE void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q);
+static INLINE int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp);
+static INLINE void RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp);
+
+static INLINE int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
+{
+ r->n = n;
+ r->e = e;
+ r->d = d;
+ return 1;
+}
+
+static INLINE void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
+{
+ *n = r->n;
+ *e = r->e;
+ *d = r->d;
+}
+
+static INLINE int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q)
+{
+ r->p = p;
+ r->q = q;
+ return 1;
+}
+
+static INLINE void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q)
+{
+ *p = r->p;
+ *q = r->q;
+}
+
+static INLINE int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp)
+{
+ r->dmp1 = dmp1;
+ r->dmq1 = dmq1;
+ r->iqmp = iqmp;
+ return 1;
+}
+
+static INLINE void RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp)
+{
+ *dmp1 = r->dmp1;
+ *dmq1 = r->dmq1;
+ *iqmp = r->iqmp;
+}
+
+static INLINE int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key);
+static INLINE int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g);
+static INLINE void DSA_get0_pqg(const DSA *dsa,
+ const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
+static INLINE void DSA_get0_key(const DSA *dsa,
+ const BIGNUM **pub_key, const BIGNUM **priv_key);
+
+static INLINE int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
+{
+ d->pub_key = pub_key;
+ d->priv_key = priv_key;
+ return 1;
+}
+
+static INLINE int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
+{
+ d->p = p;
+ d->q = q;
+ d->g = g;
+ return 1;
+}
+
+static INLINE void
+DSA_get0_pqg(const DSA *dsa, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
+{
+ *p = dsa->p;
+ *q = dsa->q;
+ *g = dsa->g;
+}
+
+static INLINE void
+DSA_get0_key(const DSA *dsa, const BIGNUM **pub_key, const BIGNUM **priv_key)
+{
+ if (pub_key)
+ *pub_key = dsa->pub_key;
+
+ if (priv_key)
+ *priv_key = dsa->priv_key;
+}
+
+
+
+static INLINE int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key);
+static INLINE int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g);
+static INLINE int DH_set_length(DH *dh, long length);
+static INLINE void DH_get0_pqg(const DH *dh,
+ const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
+static INLINE void DH_get0_key(const DH *dh,
+ const BIGNUM **pub_key, const BIGNUM **priv_key);
+
+static INLINE int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
+{
+ dh->pub_key = pub_key;
+ dh->priv_key = priv_key;
+ return 1;
+}
+
+static INLINE int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
+{
+ dh->p = p;
+ dh->q = q;
+ dh->g = g;
+ return 1;
+}
+
+static INLINE int DH_set_length(DH *dh, long length)
+{
+ dh->length = length;
+ return 1;
+}
+
+
+
+static INLINE void
+DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
+{
+ *p = dh->p;
+ *q = dh->q;
+ *g = dh->g;
+}
+
+static INLINE void
+DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key)
+{
+ if (pub_key)
+ *pub_key = dh->pub_key;
+
+ if (priv_key)
+ *priv_key = dh->priv_key;
+}
+
+#endif /* E_EVP_COMPAT_H__ */
diff --git a/lib/crypto/c_src/fips.c b/lib/crypto/c_src/fips.c
new file mode 100644
index 0000000000..b2d892d00b
--- /dev/null
+++ b/lib/crypto/c_src/fips.c
@@ -0,0 +1,52 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "fips.h"
+
+ERL_NIF_TERM info_fips(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+#ifdef FIPS_SUPPORT
+ return FIPS_mode() ? atom_enabled : atom_not_enabled;
+#else
+ return atom_not_supported;
+#endif
+}
+
+ERL_NIF_TERM enable_fips_mode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Boolean) */
+ if (argv[0] == atom_true) {
+#ifdef FIPS_SUPPORT
+ if (FIPS_mode_set(1)) {
+ return atom_true;
+ }
+#endif
+ PRINTF_ERR0("CRYPTO: Could not setup FIPS mode");
+ return atom_false;
+ } else if (argv[0] == atom_false) {
+#ifdef FIPS_SUPPORT
+ if (!FIPS_mode_set(0)) {
+ return atom_false;
+ }
+#endif
+ return atom_true;
+ } else {
+ return enif_make_badarg(env);
+ }
+}
diff --git a/lib/crypto/c_src/fips.h b/lib/crypto/c_src/fips.h
new file mode 100644
index 0000000000..9a436bd202
--- /dev/null
+++ b/lib/crypto/c_src/fips.h
@@ -0,0 +1,29 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_FIPS_H__
+#define E_FIPS_H__ 1
+
+#include "common.h"
+
+ERL_NIF_TERM info_fips(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM enable_fips_mode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+#endif /* E_FIPS_H__ */
diff --git a/lib/crypto/c_src/hash.c b/lib/crypto/c_src/hash.c
new file mode 100644
index 0000000000..9b79258585
--- /dev/null
+++ b/lib/crypto/c_src/hash.c
@@ -0,0 +1,549 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "hash.h"
+#include "digest.h"
+
+#ifdef HAVE_MD5
+# define MD5_CTX_LEN (sizeof(MD5_CTX))
+#endif
+#ifdef HAVE_MD4
+# define MD4_CTX_LEN (sizeof(MD4_CTX))
+#endif
+#ifdef HAVE_RIPEMD160
+# define RIPEMD160_CTX_LEN (sizeof(RIPEMD160_CTX))
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0)
+struct evp_md_ctx {
+ EVP_MD_CTX* ctx;
+};
+
+/* Define resource types for OpenSSL context structures. */
+static ErlNifResourceType* evp_md_ctx_rtype;
+
+static void evp_md_ctx_dtor(ErlNifEnv* env, struct evp_md_ctx *ctx) {
+ if (ctx == NULL)
+ return;
+
+ if (ctx->ctx)
+ EVP_MD_CTX_free(ctx->ctx);
+}
+#endif
+
+int init_hash_ctx(ErlNifEnv* env) {
+#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0)
+ evp_md_ctx_rtype = enif_open_resource_type(env, NULL, "EVP_MD_CTX",
+ (ErlNifResourceDtor*) evp_md_ctx_dtor,
+ ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER,
+ NULL);
+ if (evp_md_ctx_rtype == NULL)
+ goto err;
+#endif
+
+ return 1;
+
+#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0)
+ err:
+ PRINTF_ERR0("CRYPTO: Could not open resource type 'EVP_MD_CTX'");
+ return 0;
+#endif
+}
+
+ERL_NIF_TERM hash_info_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Type) */
+ struct digest_type_t *digp = NULL;
+ const EVP_MD *md;
+ ERL_NIF_TERM ret;
+
+ ASSERT(argc == 1);
+
+ if ((digp = get_digest_type(argv[0])) == NULL)
+ return enif_make_badarg(env);
+
+ if ((md = digp->md.p) == NULL)
+ return atom_notsup;
+
+ ret = enif_make_new_map(env);
+
+ enif_make_map_put(env, ret, atom_type,
+ enif_make_int(env, EVP_MD_type(md)), &ret);
+ enif_make_map_put(env, ret, atom_size,
+ enif_make_int(env, EVP_MD_size(md)), &ret);
+ enif_make_map_put(env, ret, atom_block_size,
+ enif_make_int(env, EVP_MD_block_size(md)), &ret);
+
+ return ret;
+}
+
+ERL_NIF_TERM hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Type, Data) */
+ struct digest_type_t *digp = NULL;
+ const EVP_MD *md;
+ ErlNifBinary data;
+ ERL_NIF_TERM ret;
+ unsigned ret_size;
+ unsigned char *outp;
+
+ ASSERT(argc == 2);
+
+ if ((digp = get_digest_type(argv[0])) == NULL)
+ goto bad_arg;
+ if (!enif_inspect_iolist_as_binary(env, argv[1], &data))
+ goto bad_arg;
+
+ if ((md = digp->md.p) == NULL)
+ goto err;
+
+ ret_size = (unsigned)EVP_MD_size(md);
+ ASSERT(0 < ret_size && ret_size <= EVP_MAX_MD_SIZE);
+
+ if ((outp = enif_make_new_binary(env, ret_size, &ret)) == NULL)
+ goto err;
+ if (EVP_Digest(data.data, data.size, outp, &ret_size, md, NULL) != 1)
+ goto err;
+
+ ASSERT(ret_size == (unsigned)EVP_MD_size(md));
+
+ CONSUME_REDS(env, data);
+ return ret;
+
+ bad_arg:
+ return enif_make_badarg(env);
+
+ err:
+ return atom_notsup;
+}
+
+#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0)
+
+ERL_NIF_TERM hash_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Type) */
+ struct digest_type_t *digp = NULL;
+ struct evp_md_ctx *ctx = NULL;
+ ERL_NIF_TERM ret;
+
+ ASSERT(argc == 1);
+
+ if ((digp = get_digest_type(argv[0])) == NULL)
+ goto bad_arg;
+ if (digp->md.p == NULL)
+ goto err;
+
+ if ((ctx = enif_alloc_resource(evp_md_ctx_rtype, sizeof(struct evp_md_ctx))) == NULL)
+ goto err;
+ if ((ctx->ctx = EVP_MD_CTX_new()) == NULL)
+ goto err;
+ if (EVP_DigestInit(ctx->ctx, digp->md.p) != 1)
+ goto err;
+
+ ret = enif_make_resource(env, ctx);
+ goto done;
+
+ bad_arg:
+ return enif_make_badarg(env);
+
+ err:
+ ret = atom_notsup;
+
+ done:
+ if (ctx)
+ enif_release_resource(ctx);
+ return ret;
+}
+
+ERL_NIF_TERM hash_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Context, Data) */
+ struct evp_md_ctx *ctx, *new_ctx = NULL;
+ ErlNifBinary data;
+ ERL_NIF_TERM ret;
+
+ ASSERT(argc == 2);
+
+ if (!enif_get_resource(env, argv[0], evp_md_ctx_rtype, (void**)&ctx))
+ goto bad_arg;
+ if (!enif_inspect_iolist_as_binary(env, argv[1], &data))
+ goto bad_arg;
+
+ if ((new_ctx = enif_alloc_resource(evp_md_ctx_rtype, sizeof(struct evp_md_ctx))) == NULL)
+ goto err;
+ if ((new_ctx->ctx = EVP_MD_CTX_new()) == NULL)
+ goto err;
+ if (EVP_MD_CTX_copy(new_ctx->ctx, ctx->ctx) != 1)
+ goto err;
+ if (EVP_DigestUpdate(new_ctx->ctx, data.data, data.size) != 1)
+ goto err;
+
+ ret = enif_make_resource(env, new_ctx);
+ CONSUME_REDS(env, data);
+ goto done;
+
+ bad_arg:
+ return enif_make_badarg(env);
+
+ err:
+ ret = atom_notsup;
+
+ done:
+ if (new_ctx)
+ enif_release_resource(new_ctx);
+ return ret;
+}
+
+ERL_NIF_TERM hash_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Context) */
+ struct evp_md_ctx *ctx;
+ EVP_MD_CTX *new_ctx;
+ ERL_NIF_TERM ret;
+ unsigned ret_size;
+ unsigned char *outp;
+
+ ASSERT(argc == 1);
+
+ if (!enif_get_resource(env, argv[0], evp_md_ctx_rtype, (void**)&ctx))
+ goto bad_arg;
+
+ ret_size = (unsigned)EVP_MD_CTX_size(ctx->ctx);
+ ASSERT(0 < ret_size && ret_size <= EVP_MAX_MD_SIZE);
+
+ if ((new_ctx = EVP_MD_CTX_new()) == NULL)
+ goto err;
+ if (EVP_MD_CTX_copy(new_ctx, ctx->ctx) != 1)
+ goto err;
+ if ((outp = enif_make_new_binary(env, ret_size, &ret)) == NULL)
+ goto err;
+ if (EVP_DigestFinal(new_ctx, outp, &ret_size) != 1)
+ goto err;
+
+ ASSERT(ret_size == (unsigned)EVP_MD_CTX_size(ctx->ctx));
+ goto done;
+
+ bad_arg:
+ return enif_make_badarg(env);
+
+ err:
+ ret = atom_notsup;
+
+ done:
+ if (new_ctx)
+ EVP_MD_CTX_free(new_ctx);
+ return ret;
+}
+
+#else /* if OPENSSL_VERSION_NUMBER < 1.0 */
+
+ERL_NIF_TERM hash_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Type) */
+ typedef int (*init_fun)(unsigned char*);
+ struct digest_type_t *digp = NULL;
+ ERL_NIF_TERM ctx;
+ size_t ctx_size = 0;
+ init_fun ctx_init = 0;
+ unsigned char *outp;
+
+ ASSERT(argc == 1);
+
+ if ((digp = get_digest_type(argv[0])) == NULL)
+ goto bad_arg;
+ if (digp->md.p == NULL)
+ goto err;
+
+ switch (EVP_MD_type(digp->md.p))
+ {
+#ifdef HAVE_MD4
+ case NID_md4:
+ ctx_size = MD4_CTX_LEN;
+ ctx_init = (init_fun)(&MD4_Init);
+ break;
+#endif
+#ifdef HAVE_MD5
+ case NID_md5:
+ ctx_size = MD5_CTX_LEN;
+ ctx_init = (init_fun)(&MD5_Init);
+ break;
+#endif
+#ifdef HAVE_RIPEMD160
+ case NID_ripemd160:
+ ctx_size = RIPEMD160_CTX_LEN;
+ ctx_init = (init_fun)(&RIPEMD160_Init);
+ break;
+#endif
+ case NID_sha1:
+ ctx_size = sizeof(SHA_CTX);
+ ctx_init = (init_fun)(&SHA1_Init);
+ break;
+#ifdef HAVE_SHA224
+ case NID_sha224:
+ ctx_size = sizeof(SHA256_CTX);
+ ctx_init = (init_fun)(&SHA224_Init);
+ break;
+#endif
+#ifdef HAVE_SHA256
+ case NID_sha256:
+ ctx_size = sizeof(SHA256_CTX);
+ ctx_init = (init_fun)(&SHA256_Init);
+ break;
+#endif
+#ifdef HAVE_SHA384
+ case NID_sha384:
+ ctx_size = sizeof(SHA512_CTX);
+ ctx_init = (init_fun)(&SHA384_Init);
+ break;
+#endif
+#ifdef HAVE_SHA512
+ case NID_sha512:
+ ctx_size = sizeof(SHA512_CTX);
+ ctx_init = (init_fun)(&SHA512_Init);
+ break;
+#endif
+ default:
+ goto err;
+ }
+ ASSERT(ctx_size);
+ ASSERT(ctx_init);
+
+ if ((outp = enif_make_new_binary(env, ctx_size, &ctx)) == NULL)
+ goto err;
+
+ if (ctx_init(outp) != 1)
+ goto err;
+
+ return enif_make_tuple2(env, argv[0], ctx);
+
+ bad_arg:
+ return enif_make_badarg(env);
+
+ err:
+ return atom_notsup;
+}
+
+ERL_NIF_TERM hash_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* ({Type, Context}, Data) */
+ typedef int (*update_fun)(unsigned char*, const unsigned char*, size_t);
+ ERL_NIF_TERM new_ctx;
+ ErlNifBinary ctx, data;
+ const ERL_NIF_TERM *tuple;
+ int arity;
+ struct digest_type_t *digp = NULL;
+ unsigned char *ctx_buff;
+ size_t ctx_size = 0;
+ update_fun ctx_update = 0;
+
+ ASSERT(argc == 2);
+
+ if (!enif_get_tuple(env, argv[0], &arity, &tuple))
+ goto bad_arg;
+ if (arity != 2)
+ goto bad_arg;
+ if ((digp = get_digest_type(tuple[0])) == NULL)
+ goto bad_arg;
+ if (!enif_inspect_binary(env, tuple[1], &ctx))
+ goto bad_arg;
+ if (!enif_inspect_iolist_as_binary(env, argv[1], &data))
+ goto bad_arg;
+
+ if (digp->md.p == NULL)
+ goto err;
+
+ switch (EVP_MD_type(digp->md.p))
+ {
+#ifdef HAVE_MD4
+ case NID_md4:
+ ctx_size = MD4_CTX_LEN;
+ ctx_update = (update_fun)(&MD4_Update);
+ break;
+#endif
+#ifdef HAVE_MD5
+ case NID_md5:
+ ctx_size = MD5_CTX_LEN;
+ ctx_update = (update_fun)(&MD5_Update);
+ break;
+#endif
+#ifdef HAVE_RIPEMD160
+ case NID_ripemd160:
+ ctx_size = RIPEMD160_CTX_LEN;
+ ctx_update = (update_fun)(&RIPEMD160_Update);
+ break;
+#endif
+ case NID_sha1:
+ ctx_size = sizeof(SHA_CTX);
+ ctx_update = (update_fun)(&SHA1_Update);
+ break;
+#ifdef HAVE_SHA224
+ case NID_sha224:
+ ctx_size = sizeof(SHA256_CTX);
+ ctx_update = (update_fun)(&SHA224_Update);
+ break;
+#endif
+#ifdef HAVE_SHA256
+ case NID_sha256:
+ ctx_size = sizeof(SHA256_CTX);
+ ctx_update = (update_fun)(&SHA256_Update);
+ break;
+#endif
+#ifdef HAVE_SHA384
+ case NID_sha384:
+ ctx_size = sizeof(SHA512_CTX);
+ ctx_update = (update_fun)(&SHA384_Update);
+ break;
+#endif
+#ifdef HAVE_SHA512
+ case NID_sha512:
+ ctx_size = sizeof(SHA512_CTX);
+ ctx_update = (update_fun)(&SHA512_Update);
+ break;
+#endif
+ default:
+ goto err;
+ }
+ ASSERT(ctx_size);
+ ASSERT(ctx_update);
+
+ if (ctx.size != ctx_size)
+ goto bad_arg;
+
+ if ((ctx_buff = enif_make_new_binary(env, ctx_size, &new_ctx)) == NULL)
+ goto err;
+ memcpy(ctx_buff, ctx.data, ctx_size);
+
+ if (ctx_update(ctx_buff, data.data, data.size) != 1)
+ goto err;
+
+ CONSUME_REDS(env, data);
+ return enif_make_tuple2(env, tuple[0], new_ctx);
+
+ bad_arg:
+ return enif_make_badarg(env);
+
+ err:
+ return atom_notsup;
+}
+
+ERL_NIF_TERM hash_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* ({Type, Context}) */
+ typedef int (*final_fun)(unsigned char*, void*);
+ ERL_NIF_TERM ret;
+ ErlNifBinary ctx;
+ const ERL_NIF_TERM *tuple;
+ int arity;
+ struct digest_type_t *digp = NULL;
+ const EVP_MD *md;
+ void *new_ctx = NULL;
+ size_t ctx_size = 0;
+ final_fun ctx_final = 0;
+ unsigned char *outp;
+
+ ASSERT(argc == 1);
+
+ if (!enif_get_tuple(env, argv[0], &arity, &tuple))
+ goto bad_arg;
+ if (arity != 2)
+ goto bad_arg;
+ if ((digp = get_digest_type(tuple[0])) == NULL)
+ goto bad_arg;
+ if (!enif_inspect_binary(env, tuple[1], &ctx))
+ goto bad_arg;
+
+ if ((md = digp->md.p) == NULL)
+ goto err;
+
+ switch (EVP_MD_type(md))
+ {
+#ifdef HAVE_MD4
+ case NID_md4:
+ ctx_size = MD4_CTX_LEN;
+ ctx_final = (final_fun)(&MD4_Final);
+ break;
+#endif
+#ifdef HAVE_MD5
+ case NID_md5:
+ ctx_size = MD5_CTX_LEN;
+ ctx_final = (final_fun)(&MD5_Final);
+ break;
+#endif
+#ifdef HAVE_RIPEMD160
+ case NID_ripemd160:
+ ctx_size = RIPEMD160_CTX_LEN;
+ ctx_final = (final_fun)(&RIPEMD160_Final);
+ break;
+#endif
+ case NID_sha1:
+ ctx_size = sizeof(SHA_CTX);
+ ctx_final = (final_fun)(&SHA1_Final);
+ break;
+#ifdef HAVE_SHA224
+ case NID_sha224:
+ ctx_size = sizeof(SHA256_CTX);
+ ctx_final = (final_fun)(&SHA224_Final);
+ break;
+#endif
+#ifdef HAVE_SHA256
+ case NID_sha256:
+ ctx_size = sizeof(SHA256_CTX);
+ ctx_final = (final_fun)(&SHA256_Final);
+ break;
+#endif
+#ifdef HAVE_SHA384
+ case NID_sha384:
+ ctx_size = sizeof(SHA512_CTX);
+ ctx_final = (final_fun)(&SHA384_Final);
+ break;
+#endif
+#ifdef HAVE_SHA512
+ case NID_sha512:
+ ctx_size = sizeof(SHA512_CTX);
+ ctx_final = (final_fun)(&SHA512_Final);
+ break;
+#endif
+ default:
+ goto err;
+ }
+ ASSERT(ctx_size);
+ ASSERT(ctx_final);
+
+ if (ctx.size != ctx_size)
+ goto bad_arg;
+
+ if ((new_ctx = enif_alloc(ctx_size)) == NULL)
+ goto err;
+
+ memcpy(new_ctx, ctx.data, ctx_size);
+
+ if ((outp = enif_make_new_binary(env, (size_t)EVP_MD_size(md), &ret)) == NULL)
+ goto err;
+
+ if (ctx_final(outp, new_ctx) != 1)
+ goto err;
+
+ goto done;
+
+ bad_arg:
+ return enif_make_badarg(env);
+
+ err:
+ ret = atom_notsup;
+
+ done:
+ if (new_ctx)
+ enif_free(new_ctx);
+ return ret;
+}
+
+#endif /* OPENSSL_VERSION_NUMBER < 1.0 */
diff --git a/lib/crypto/c_src/hash.h b/lib/crypto/c_src/hash.h
new file mode 100644
index 0000000000..92a25cedb7
--- /dev/null
+++ b/lib/crypto/c_src/hash.h
@@ -0,0 +1,34 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_HASH_H__
+#define E_HASH_H__ 1
+
+#include "common.h"
+
+int init_hash_ctx(ErlNifEnv *env);
+
+ERL_NIF_TERM hash_info_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM hash_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM hash_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM hash_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+#endif /* E_HASH_H__ */
diff --git a/lib/crypto/c_src/hmac.c b/lib/crypto/c_src/hmac.c
new file mode 100644
index 0000000000..ff7005d75e
--- /dev/null
+++ b/lib/crypto/c_src/hmac.c
@@ -0,0 +1,270 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "hmac.h"
+#include "digest.h"
+
+struct hmac_context
+{
+ ErlNifMutex* mtx;
+ int alive;
+ HMAC_CTX* ctx;
+};
+
+static ErlNifResourceType* hmac_context_rtype;
+
+static void hmac_context_dtor(ErlNifEnv* env, struct hmac_context*);
+
+int init_hmac_ctx(ErlNifEnv *env) {
+ hmac_context_rtype = enif_open_resource_type(env, NULL, "hmac_context",
+ (ErlNifResourceDtor*) hmac_context_dtor,
+ ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER,
+ NULL);
+ if (hmac_context_rtype == NULL)
+ goto err;
+
+ return 1;
+
+ err:
+ PRINTF_ERR0("CRYPTO: Could not open resource type 'hmac_context'");
+ return 0;
+}
+
+ERL_NIF_TERM hmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Type, Key, Data) or (Type, Key, Data, MacSize) */
+ struct digest_type_t *digp = NULL;
+ ErlNifBinary key, data;
+ unsigned char buff[EVP_MAX_MD_SIZE];
+ unsigned size = 0, req_size = 0;
+ ERL_NIF_TERM ret;
+ unsigned char *outp;
+
+ ASSERT(argc == 3 || argc == 4);
+
+ if ((digp = get_digest_type(argv[0])) == NULL)
+ goto bad_arg;
+ if (!enif_inspect_iolist_as_binary(env, argv[1], &key))
+ goto bad_arg;
+ if (key.size > INT_MAX)
+ goto bad_arg;
+ if (!enif_inspect_iolist_as_binary(env, argv[2], &data))
+ goto bad_arg;
+ if (argc == 4) {
+ if (!enif_get_uint(env, argv[3], &req_size))
+ goto bad_arg;
+ }
+
+ if (digp->md.p == NULL)
+ goto err;
+ if (HMAC(digp->md.p,
+ key.data, (int)key.size,
+ data.data, data.size,
+ buff, &size) == NULL)
+ goto err;
+
+ ASSERT(0 < size && size <= EVP_MAX_MD_SIZE);
+ CONSUME_REDS(env, data);
+
+ if (argc == 4) {
+ if (req_size > size)
+ goto bad_arg;
+
+ size = req_size;
+ }
+
+ if ((outp = enif_make_new_binary(env, size, &ret)) == NULL)
+ goto err;
+
+ memcpy(outp, buff, size);
+ return ret;
+
+ bad_arg:
+ return enif_make_badarg(env);
+
+ err:
+ return atom_notsup;
+}
+
+static void hmac_context_dtor(ErlNifEnv* env, struct hmac_context *obj)
+{
+ if (obj == NULL)
+ return;
+
+ if (obj->alive) {
+ if (obj->ctx)
+ HMAC_CTX_free(obj->ctx);
+ obj->alive = 0;
+ }
+
+ if (obj->mtx != NULL)
+ enif_mutex_destroy(obj->mtx);
+}
+
+ERL_NIF_TERM hmac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Type, Key) */
+ struct digest_type_t *digp = NULL;
+ ErlNifBinary key;
+ ERL_NIF_TERM ret;
+ struct hmac_context *obj = NULL;
+
+ ASSERT(argc == 2);
+
+ if ((digp = get_digest_type(argv[0])) == NULL)
+ goto bad_arg;
+ if (!enif_inspect_iolist_as_binary(env, argv[1], &key))
+ goto bad_arg;
+ if (key.size > INT_MAX)
+ goto bad_arg;
+
+ if (digp->md.p == NULL)
+ goto err;
+
+ if ((obj = enif_alloc_resource(hmac_context_rtype, sizeof(struct hmac_context))) == NULL)
+ goto err;
+ obj->ctx = NULL;
+ obj->mtx = NULL;
+ obj->alive = 0;
+
+ if ((obj->ctx = HMAC_CTX_new()) == NULL)
+ goto err;
+ obj->alive = 1;
+ if ((obj->mtx = enif_mutex_create("crypto.hmac")) == NULL)
+ goto err;
+
+#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0)
+ // Check the return value of HMAC_Init: it may fail in FIPS mode
+ // for disabled algorithms
+ if (!HMAC_Init_ex(obj->ctx, key.data, (int)key.size, digp->md.p, NULL))
+ goto err;
+#else
+ // In ancient versions of OpenSSL, this was a void function.
+ HMAC_Init_ex(obj->ctx, key.data, (int)key.size, digp->md.p, NULL);
+#endif
+
+ ret = enif_make_resource(env, obj);
+ goto done;
+
+ bad_arg:
+ return enif_make_badarg(env);
+
+ err:
+ ret = atom_notsup;
+
+ done:
+ if (obj)
+ enif_release_resource(obj);
+ return ret;
+}
+
+ERL_NIF_TERM hmac_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Context, Data) */
+ ERL_NIF_TERM ret;
+ ErlNifBinary data;
+ struct hmac_context *obj = NULL;
+
+ ASSERT(argc == 2);
+
+ if (!enif_get_resource(env, argv[0], (ErlNifResourceType*)hmac_context_rtype, (void**)&obj))
+ goto bad_arg;
+ if (!enif_inspect_iolist_as_binary(env, argv[1], &data))
+ goto bad_arg;
+
+ enif_mutex_lock(obj->mtx);
+ if (!obj->alive)
+ goto err;
+
+#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0)
+ if (!HMAC_Update(obj->ctx, data.data, data.size))
+ goto err;
+#else
+ // In ancient versions of OpenSSL, this was a void function.
+ HMAC_Update(obj->ctx, data.data, data.size);
+#endif
+
+ CONSUME_REDS(env,data);
+ ret = argv[0];
+ goto done;
+
+ bad_arg:
+ return enif_make_badarg(env);
+
+ err:
+ ret = enif_make_badarg(env);
+
+ done:
+ enif_mutex_unlock(obj->mtx);
+ return ret;
+}
+
+ERL_NIF_TERM hmac_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Context) or (Context, HashLen) */
+ ERL_NIF_TERM ret;
+ struct hmac_context* obj;
+ unsigned char mac_buf[EVP_MAX_MD_SIZE];
+ unsigned char * mac_bin;
+ unsigned int req_len = 0;
+ unsigned int mac_len;
+
+ ASSERT(argc == 1 || argc == 2);
+
+ if (!enif_get_resource(env, argv[0], (ErlNifResourceType*)hmac_context_rtype, (void**)&obj))
+ goto bad_arg;
+ if (argc == 2) {
+ if (!enif_get_uint(env, argv[1], &req_len))
+ goto bad_arg;
+ }
+
+ enif_mutex_lock(obj->mtx);
+ if (!obj->alive)
+ goto err;
+
+#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0)
+ if (!HMAC_Final(obj->ctx, mac_buf, &mac_len))
+ goto err;
+#else
+ // In ancient versions of OpenSSL, this was a void function.
+ HMAC_Final(obj->ctx, mac_buf, &mac_len);
+#endif
+
+ if (obj->ctx)
+ HMAC_CTX_free(obj->ctx);
+ obj->alive = 0;
+
+ if (argc == 2 && req_len < mac_len) {
+ /* Only truncate to req_len bytes if asked. */
+ mac_len = req_len;
+ }
+ if ((mac_bin = enif_make_new_binary(env, mac_len, &ret)) == NULL)
+ goto err;
+
+ memcpy(mac_bin, mac_buf, mac_len);
+ goto done;
+
+ bad_arg:
+ return enif_make_badarg(env);
+
+ err:
+ ret = enif_make_badarg(env);
+
+ done:
+ enif_mutex_unlock(obj->mtx);
+ return ret;
+}
+
diff --git a/lib/crypto/c_src/hmac.h b/lib/crypto/c_src/hmac.h
new file mode 100644
index 0000000000..1f0e0ca632
--- /dev/null
+++ b/lib/crypto/c_src/hmac.h
@@ -0,0 +1,33 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_HMAC_H__
+#define E_HMAC_H__ 1
+
+#include "common.h"
+
+int init_hmac_ctx(ErlNifEnv *env);
+
+ERL_NIF_TERM hmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM hmac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM hmac_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM hmac_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+#endif /* E_HMAC_H__ */
diff --git a/lib/crypto/c_src/info.c b/lib/crypto/c_src/info.c
new file mode 100644
index 0000000000..42f477fead
--- /dev/null
+++ b/lib/crypto/c_src/info.c
@@ -0,0 +1,107 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "info.h"
+
+#ifdef HAVE_DYNAMIC_CRYPTO_LIB
+
+# if defined(DEBUG)
+char *crypto_callback_name = "crypto_callback.debug";
+# elif defined(VALGRIND)
+char *crypto_callback_name = "crypto_callback.valgrind";
+# else
+char *crypto_callback_name = "crypto_callback";
+# endif
+
+int change_basename(ErlNifBinary* bin, char* buf, size_t bufsz, const char* newfile)
+{
+ size_t i;
+ size_t newlen;
+
+ for (i = bin->size; i > 0; i--) {
+ if (bin->data[i-1] == '/')
+ break;
+ }
+
+ newlen = strlen(newfile);
+ if (i > SIZE_MAX - newlen)
+ goto err;
+
+ if (i + newlen >= bufsz)
+ goto err;
+
+ memcpy(buf, bin->data, i);
+ strcpy(buf+i, newfile);
+
+ return 1;
+
+ err:
+ return 0;
+}
+
+void error_handler(void* null, const char* errstr)
+{
+ PRINTF_ERR1("CRYPTO LOADING ERROR: '%s'", errstr);
+}
+#endif /* HAVE_DYNAMIC_CRYPTO_LIB */
+
+ERL_NIF_TERM info_lib(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
+{/* () */
+ /* [{<<"OpenSSL">>,9470143,<<"OpenSSL 0.9.8k 25 Mar 2009">>}] */
+
+ ERL_NIF_TERM name_term, ver_term;
+ static const char libname[] = "OpenSSL";
+ size_t name_sz;
+ const char* ver;
+ size_t ver_sz;
+ int ver_num;
+ unsigned char *out_name, *out_ver;
+
+ ASSERT(argc == 0);
+
+ name_sz = strlen(libname);
+ ver = SSLeay_version(SSLEAY_VERSION);
+ ver_sz = strlen(ver);
+ ver_num = OPENSSL_VERSION_NUMBER;
+
+ /* R16:
+ * Ignore library version number from SSLeay() and instead show header
+ * version. Otherwise user might try to call a function that is implemented
+ * by a newer library but not supported by the headers used at compile time.
+ * Example: DES_ede3_cfb_encrypt in 0.9.7i but not in 0.9.7d.
+ *
+ * Version string is still from library though.
+ */
+
+ if ((out_name = enif_make_new_binary(env, name_sz, &name_term)) == NULL)
+ goto err;
+ if ((out_ver = enif_make_new_binary(env, ver_sz, &ver_term)) == NULL)
+ goto err;
+
+ memcpy(out_name, libname, name_sz);
+ memcpy(out_ver, ver, ver_sz);
+
+ return enif_make_list1(env, enif_make_tuple3(env, name_term,
+ enif_make_int(env, ver_num),
+ ver_term));
+
+ err:
+ return enif_make_badarg(env);
+}
diff --git a/lib/crypto/c_src/info.h b/lib/crypto/c_src/info.h
new file mode 100644
index 0000000000..67690625c9
--- /dev/null
+++ b/lib/crypto/c_src/info.h
@@ -0,0 +1,35 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_INFO_H__
+#define E_INFO_H__ 1
+
+#include "common.h"
+
+#ifdef HAVE_DYNAMIC_CRYPTO_LIB
+extern char *crypto_callback_name;
+
+int change_basename(ErlNifBinary* bin, char* buf, size_t bufsz, const char* newfile);
+void error_handler(void* null, const char* errstr);
+#endif
+
+ERL_NIF_TERM info_lib(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+#endif /* E_INFO_H__ */
diff --git a/lib/crypto/c_src/math.c b/lib/crypto/c_src/math.c
new file mode 100644
index 0000000000..85494bbc93
--- /dev/null
+++ b/lib/crypto/c_src/math.c
@@ -0,0 +1,53 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "math.h"
+
+ERL_NIF_TERM do_exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Data1, Data2) */
+ ErlNifBinary d1, d2;
+ unsigned char* ret_ptr;
+ size_t i;
+ ERL_NIF_TERM ret;
+
+ ASSERT(argc == 2);
+
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &d1))
+ goto bad_arg;
+ if (!enif_inspect_iolist_as_binary(env, argv[1], &d2))
+ goto bad_arg;
+ if (d1.size != d2.size)
+ goto bad_arg;
+
+ if ((ret_ptr = enif_make_new_binary(env, d1.size, &ret)) == NULL)
+ goto err;
+
+ for (i=0; i<d1.size; i++) {
+ ret_ptr[i] = d1.data[i] ^ d2.data[i];
+ }
+
+ CONSUME_REDS(env,d1);
+ return ret;
+
+ bad_arg:
+ err:
+ return enif_make_badarg(env);
+}
+
diff --git a/lib/crypto/c_src/math.h b/lib/crypto/c_src/math.h
new file mode 100644
index 0000000000..b8d68ea654
--- /dev/null
+++ b/lib/crypto/c_src/math.h
@@ -0,0 +1,28 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_MATH_H__
+#define E_MATH_H__ 1
+
+#include "common.h"
+
+ERL_NIF_TERM do_exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+#endif /* E_MATH_H__ */
diff --git a/lib/crypto/c_src/openssl_config.h b/lib/crypto/c_src/openssl_config.h
new file mode 100644
index 0000000000..339eb5b8f4
--- /dev/null
+++ b/lib/crypto/c_src/openssl_config.h
@@ -0,0 +1,405 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_OPENSSL_CONFIG_H__
+#define E_OPENSSL_CONFIG_H__ 1
+
+#define OPENSSL_THREAD_DEFINES
+#include <openssl/opensslconf.h>
+
+#include <openssl/crypto.h>
+#include <openssl/des.h>
+
+/* #include <openssl/idea.h> This is not supported on the openssl OTP requires */
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
+#include <openssl/aes.h>
+#include <openssl/md5.h>
+#include <openssl/md4.h>
+#include <openssl/sha.h>
+#include <openssl/ripemd.h>
+#include <openssl/bn.h>
+#include <openssl/objects.h>
+#ifndef OPENSSL_NO_RC4
+ #include <openssl/rc4.h>
+#endif /* OPENSSL_NO_RC4 */
+#ifndef OPENSSL_NO_RC2
+ #include <openssl/rc2.h>
+#endif
+#include <openssl/blowfish.h>
+#include <openssl/rand.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/err.h>
+
+/* Helper macro to construct a OPENSSL_VERSION_NUMBER.
+ * See openssl/opensslv.h
+ */
+#define PACKED_OPENSSL_VERSION(MAJ, MIN, FIX, P) \
+ ((((((((MAJ << 8) | MIN) << 8 ) | FIX) << 8) | (P-'a'+1)) << 4) | 0xf)
+
+#define PACKED_OPENSSL_VERSION_PLAIN(MAJ, MIN, FIX) \
+ PACKED_OPENSSL_VERSION(MAJ,MIN,FIX,('a'-1))
+
+
+/* LibreSSL was cloned from OpenSSL 1.0.1g and claims to be API and BPI compatible
+ * with 1.0.1.
+ *
+ * LibreSSL has the same names on include files and symbols as OpenSSL, but defines
+ * the OPENSSL_VERSION_NUMBER to be >= 2.0.0
+ *
+ * Therefor works tests like this as intendend:
+ * OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0)
+ * (The test is for example "2.4.2" >= "1.0.0" although the test
+ * with the cloned OpenSSL test would be "1.0.1" >= "1.0.0")
+ *
+ * But tests like this gives wrong result:
+ * OPENSSL_VERSION_NUMBER < PACKED_OPENSSL_VERSION_PLAIN(1,1,0)
+ * (The test is false since "2.4.2" < "1.1.0". It should have been
+ * true because the LibreSSL API version is "1.0.1")
+ *
+ */
+
+#ifdef LIBRESSL_VERSION_NUMBER
+/* A macro to test on in this file */
+#define HAS_LIBRESSL
+#endif
+
+#ifdef HAS_LIBRESSL
+/* LibreSSL dislikes FIPS */
+# ifdef FIPS_SUPPORT
+# undef FIPS_SUPPORT
+# endif
+
+/* LibreSSL has never supported the custom mem functions */
+#ifndef HAS_LIBRESSL
+# define HAS_CRYPTO_MEM_FUNCTIONS
+#endif
+
+# if LIBRESSL_VERSION_NUMBER < PACKED_OPENSSL_VERSION_PLAIN(2,7,0)
+/* LibreSSL wants the 1.0.1 API */
+# define NEED_EVP_COMPATIBILITY_FUNCTIONS
+# endif
+#endif
+
+
+#if OPENSSL_VERSION_NUMBER < PACKED_OPENSSL_VERSION_PLAIN(1,1,0)
+# define NEED_EVP_COMPATIBILITY_FUNCTIONS
+#endif
+
+
+#ifndef HAS_LIBRESSL
+# if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0)
+# define HAS_EVP_PKEY_CTX
+# define HAVE_EVP_CIPHER_CTX_COPY
+# endif
+#endif
+
+
+#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0)
+#include <openssl/modes.h>
+#endif
+
+#include "crypto_callback.h"
+
+#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(0,9,8) \
+ && !defined(OPENSSL_NO_SHA224) && defined(NID_sha224) \
+ && !defined(OPENSSL_NO_SHA256) /* disabled like this in my sha.h (?) */
+# define HAVE_SHA224
+#endif
+#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(0,9,8) \
+ && !defined(OPENSSL_NO_SHA256) && defined(NID_sha256)
+# define HAVE_SHA256
+#endif
+#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(0,9,8) \
+ && !defined(OPENSSL_NO_SHA384) && defined(NID_sha384)\
+ && !defined(OPENSSL_NO_SHA512) /* disabled like this in my sha.h (?) */
+# define HAVE_SHA384
+#endif
+#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(0,9,8) \
+ && !defined(OPENSSL_NO_SHA512) && defined(NID_sha512)
+# define HAVE_SHA512
+#endif
+#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION(0,9,7,'e')
+# define HAVE_DES_ede3_cfb_encrypt
+#endif
+
+// SHA3:
+#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,1,1)
+// An error in beta releases of 1.1.1 fixed in production release
+# ifdef NID_sha3_224
+# define HAVE_SHA3_224
+# endif
+# ifdef NID_sha3_256
+# define HAVE_SHA3_256
+# endif
+#endif
+# ifdef NID_sha3_384
+# define HAVE_SHA3_384
+# endif
+# ifdef NID_sha3_512
+# define HAVE_SHA3_512
+# endif
+
+// BLAKE2:
+#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,1,1) \
+ && !defined(HAS_LIBRESSL) \
+ && !defined(OPENSSL_NO_BLAKE2)
+# define HAVE_BLAKE2
+#endif
+
+#ifndef OPENSSL_NO_BF
+# define HAVE_BF
+#endif
+
+#ifndef OPENSSL_NO_DES
+# define HAVE_DES
+#endif
+
+#ifndef OPENSSL_NO_DH
+# define HAVE_DH
+#endif
+
+#ifndef OPENSSL_NO_DSA
+# define HAVE_DSA
+#endif
+
+#ifndef OPENSSL_NO_MD4
+# define HAVE_MD4
+#endif
+
+#ifndef OPENSSL_NO_MD5
+# define HAVE_MD5
+#endif
+
+#ifndef OPENSSL_NO_RC2
+# define HAVE_RC2
+#endif
+
+#ifndef OPENSSL_NO_RC4
+# define HAVE_RC4
+#endif
+
+#ifndef OPENSSL_NO_RMD160
+/* Note RMD160 vs RIPEMD160 */
+# define HAVE_RIPEMD160
+#endif
+
+
+#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION(0,9,8,'o') \
+ && !defined(OPENSSL_NO_EC) \
+ && !defined(OPENSSL_NO_ECDH) \
+ && !defined(OPENSSL_NO_ECDSA)
+# define HAVE_EC
+#endif
+
+// (test for >= 1.1.1pre8)
+#if OPENSSL_VERSION_NUMBER >= (PACKED_OPENSSL_VERSION_PLAIN(1,1,1) -7) \
+ && !defined(HAS_LIBRESSL) \
+ && defined(HAVE_EC)
+# define HAVE_ED_CURVE_DH
+# if OPENSSL_VERSION_NUMBER >= (PACKED_OPENSSL_VERSION_PLAIN(1,1,1))
+# define HAVE_EDDSA
+# endif
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION(0,9,8,'c')
+# define HAVE_AES_IGE
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,1)
+# define HAVE_EVP_AES_CTR
+# define HAVE_AEAD
+# define HAVE_GCM
+# define HAVE_CCM
+# ifndef OPENSSL_NO_CMAC
+# define HAVE_CMAC
+# endif
+# if defined(RSA_PKCS1_OAEP_PADDING)
+# define HAVE_RSA_OAEP_PADDING
+# endif
+# define HAVE_RSA_MGF1_MD
+# if OPENSSL_VERSION_NUMBER < PACKED_OPENSSL_VERSION(1,0,1,'d')
+# define HAVE_GCM_EVP_DECRYPT_BUG
+# endif
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,1,0)
+# ifndef HAS_LIBRESSL
+# if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305)
+# define HAVE_CHACHA20_POLY1305
+# endif
+# define HAVE_RSA_OAEP_MD
+# endif
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION(1,1,0,'d')
+# ifndef HAS_LIBRESSL
+# ifndef OPENSSL_NO_CHACHA
+# define HAVE_CHACHA20
+# endif
+# endif
+#endif
+
+// OPENSSL_VERSION_NUMBER >= 1.1.1-pre8
+#if OPENSSL_VERSION_NUMBER >= (PACKED_OPENSSL_VERSION_PLAIN(1,1,1)-7)
+# ifndef HAS_LIBRESSL
+# if !defined(OPENSSL_NO_POLY1305)
+# define HAVE_POLY1305
+# endif
+# endif
+#endif
+
+#if OPENSSL_VERSION_NUMBER <= PACKED_OPENSSL_VERSION(0,9,8,'l')
+# define HAVE_ECB_IVEC_BUG
+#endif
+
+#ifndef HAS_LIBRESSL
+# ifdef RSA_SSLV23_PADDING
+# define HAVE_RSA_SSLV23_PADDING
+# endif
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0)
+# ifdef RSA_PKCS1_PSS_PADDING
+# define HAVE_RSA_PKCS1_PSS_PADDING
+# endif
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION(0,9,8,'h') \
+ && defined(HAVE_EC)
+/* If OPENSSL_NO_EC is set, there will be an error in ec.h included from engine.h
+ So if EC is disabled, you can't use Engine either....
+*/
+# define HAS_ENGINE_SUPPORT
+#endif
+
+
+#if defined(HAS_ENGINE_SUPPORT)
+# include <openssl/engine.h>
+#endif
+
+#if defined(HAVE_CMAC)
+#include <openssl/cmac.h>
+#endif
+
+#if defined(HAVE_EC)
+#include <openssl/ec.h>
+#include <openssl/ecdh.h>
+#include <openssl/ecdsa.h>
+#endif
+
+#ifdef VALGRIND
+ # include <valgrind/memcheck.h>
+
+/* libcrypto mixes supplied buffer contents into its entropy pool,
+ which makes valgrind complain about the use of uninitialized data.
+ We use this valgrind "request" to make sure that no such seemingly
+ undefined data is returned.
+*/
+ # define ERL_VALGRIND_MAKE_MEM_DEFINED(ptr,size) \
+ VALGRIND_MAKE_MEM_DEFINED(ptr,size)
+
+ # define ERL_VALGRIND_ASSERT_MEM_DEFINED(Ptr,Size) \
+ do { \
+ int __erl_valgrind_mem_defined = VALGRIND_CHECK_MEM_IS_DEFINED((Ptr),(Size)); \
+ if (__erl_valgrind_mem_defined != 0) { \
+ fprintf(stderr,"\r\n####### VALGRIND_ASSSERT(%p,%ld) failed at %s:%d\r\n", \
+ (Ptr),(long)(Size), __FILE__, __LINE__); \
+ abort(); \
+ } \
+ } while (0)
+
+#else
+ # define ERL_VALGRIND_MAKE_MEM_DEFINED(ptr,size)
+ # define ERL_VALGRIND_ASSERT_MEM_DEFINED(ptr,size)
+#endif
+
+#ifdef DEBUG
+ # define ASSERT(e) \
+ ((void) ((e) ? 1 : (fprintf(stderr,"Assert '%s' failed at %s:%d\n",\
+ #e, __FILE__, __LINE__), abort(), 0)))
+#else
+ # define ASSERT(e) ((void) 1)
+#endif
+
+#ifdef __GNUC__
+ # define INLINE __inline__
+#elif defined(__WIN32__)
+ # define INLINE __forceinline
+#else
+ # define INLINE
+#endif
+
+
+#define get_int32(s) ((((unsigned char*) (s))[0] << 24) | \
+ (((unsigned char*) (s))[1] << 16) | \
+ (((unsigned char*) (s))[2] << 8) | \
+ (((unsigned char*) (s))[3]))
+
+#define put_uint32(s,i) \
+{ (s)[0] = (unsigned char)(((i) >> 24) & 0xff);\
+ (s)[1] = (unsigned char)(((i) >> 16) & 0xff);\
+ (s)[2] = (unsigned char)(((i) >> 8) & 0xff);\
+ (s)[3] = (unsigned char)((i) & 0xff);\
+}
+
+/* This shall correspond to the similar macro in crypto.erl */
+/* Current value is: erlang:system_info(context_reductions) * 10 */
+#define MAX_BYTES_TO_NIF 20000
+
+#define CONSUME_REDS(NifEnv, Ibin) \
+do { \
+ size_t _cost = (Ibin).size; \
+ if (_cost > SIZE_MAX / 100) \
+ _cost = 100; \
+ else \
+ _cost = (_cost * 100) / MAX_BYTES_TO_NIF; \
+ \
+ if (_cost) { \
+ (void) enif_consume_timeslice((NifEnv), \
+ (_cost > 100) ? 100 : (int)_cost); \
+ } \
+ } while (0)
+
+#ifdef NEED_EVP_COMPATIBILITY_FUNCTIONS
+# include "evp_compat.h"
+#else
+# define HAVE_OPAQUE_BN_GENCB
+#endif
+
+#if 0
+# define PRINTF_ERR0(FMT) enif_fprintf(stderr, FMT "\n")
+# define PRINTF_ERR1(FMT, A1) enif_fprintf(stderr, FMT "\n", A1)
+# define PRINTF_ERR2(FMT, A1, A2) enif_fprintf(stderr, FMT "\n", A1, A2)
+#else
+# define PRINTF_ERR0(FMT)
+# define PRINTF_ERR1(FMT,A1)
+# define PRINTF_ERR2(FMT,A1,A2)
+#endif
+
+#ifdef FIPS_SUPPORT
+/* In FIPS mode non-FIPS algorithms are disabled and return badarg. */
+#define CHECK_NO_FIPS_MODE() { if (FIPS_mode()) return atom_notsup; }
+#else
+#define CHECK_NO_FIPS_MODE()
+#endif
+
+#endif /* E_OPENSSL_CONFIG_H__ */
diff --git a/lib/crypto/c_src/otp_test_engine.c b/lib/crypto/c_src/otp_test_engine.c
index 5c6122c06a..c3bd9dfb55 100644
--- a/lib/crypto/c_src/otp_test_engine.c
+++ b/lib/crypto/c_src/otp_test_engine.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2017-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2017-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,13 +21,14 @@
#ifdef _WIN32
#define OPENSSL_OPT_WINDLL
#endif
+
#include <stdio.h>
#include <string.h>
+#include <limits.h>
+#include <stdint.h>
-#include <openssl/engine.h>
#include <openssl/md5.h>
#include <openssl/rsa.h>
-#include <openssl/pem.h>
#define PACKED_OPENSSL_VERSION(MAJ, MIN, FIX, P) \
((((((((MAJ << 8) | MIN) << 8 ) | FIX) << 8) | (P-'a'+1)) << 4) | 0xf)
@@ -37,23 +38,77 @@
#if OPENSSL_VERSION_NUMBER < PACKED_OPENSSL_VERSION_PLAIN(1,1,0) \
|| defined(LIBRESSL_VERSION_NUMBER)
-#define OLD
+# define OLD
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,1,0) \
+ && !defined(LIBRESSL_VERSION_NUMBER)
+# define FAKE_RSA_IMPL
#endif
+#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION(0,9,8,'o') \
+ && !defined(OPENSSL_NO_EC) \
+ && !defined(OPENSSL_NO_ECDH) \
+ && !defined(OPENSSL_NO_ECDSA)
+# define HAVE_EC
+#endif
+
+#if defined(HAVE_EC)
+/* If OPENSSL_NO_EC is set, there will be an error in ec.h included from engine.h
+ So if EC is disabled, you can't use Engine either....
+*/
+#include <openssl/engine.h>
+#include <openssl/pem.h>
+
+
static const char *test_engine_id = "MD5";
static const char *test_engine_name = "MD5 test engine";
-/* The callback that does the job of fetching keys on demand by the Engine */
-EVP_PKEY* test_key_load(ENGINE *er, const char *id, UI_METHOD *ui_method, void *callback_data);
+#if defined(FAKE_RSA_IMPL)
+/*-------- test of private/public keys and RSA in engine ---------*/
+static RSA_METHOD *test_rsa_method = NULL;
+
+/* Our on "RSA" implementation */
+static int test_rsa_sign(int dtype, const unsigned char *m,
+ unsigned int m_len, unsigned char *sigret,
+ unsigned int *siglen, const RSA *rsa);
+static int test_rsa_verify(int dtype, const unsigned char *m,
+ unsigned int m_len, const unsigned char *sigret,
+ unsigned int siglen, const RSA *rsa);
+static int test_rsa_free(RSA *rsa);
+#endif /* if defined(FAKE_RSA_IMPL) */
+
+/* The callbacks that does the job of fetching keys on demand by the Engine */
+EVP_PKEY* test_privkey_load(ENGINE *eng, const char *id, UI_METHOD *ui_method, void *callback_data);
+EVP_PKEY* test_pubkey_load(ENGINE *eng, const char *id, UI_METHOD *ui_method, void *callback_data);
+
+EVP_PKEY* test_key_load(ENGINE *er, const char *id, UI_METHOD *ui_method, void *callback_data, int priv);
+/*----------------------------------------------------------------*/
static int test_init(ENGINE *e) {
printf("OTP Test Engine Initializatzion!\r\n");
+#if defined(FAKE_RSA_IMPL)
+ if (!RSA_meth_set_finish(test_rsa_method, test_rsa_free))
+ goto err;
+ if (!RSA_meth_set_sign(test_rsa_method, test_rsa_sign))
+ goto err;
+ if (!RSA_meth_set_verify(test_rsa_method, test_rsa_verify))
+ goto err;
+#endif /* if defined(FAKE_RSA_IMPL) */
+
/* Load all digest and cipher algorithms. Needed for password protected private keys */
- OpenSSL_add_all_algorithms();
+ OpenSSL_add_all_ciphers();
+ OpenSSL_add_all_digests();
return 111;
+
+#if defined(FAKE_RSA_IMPL)
+err:
+ fprintf(stderr, "Setup RSA_METHOD failed\r\n");
+ return 0;
+#endif
}
static void add_test_data(unsigned char *md, unsigned int len)
@@ -65,6 +120,19 @@ static void add_test_data(unsigned char *md, unsigned int len)
}
}
+#if defined(FAKE_RSA_IMPL)
+static int chk_test_data(const unsigned char *md, unsigned int len)
+{
+ unsigned int i;
+
+ for (i=0; i<len; i++) {
+ if (md[i] != (unsigned char)(i & 0xff))
+ return 0;
+ }
+ return 1;
+}
+#endif /* if defined(FAKE_RSA_IMPL) */
+
/* MD5 part */
#undef data
#ifdef OLD
@@ -92,15 +160,15 @@ static int test_engine_md5_update(EVP_MD_CTX *ctx,const void *data, size_t count
static int test_engine_md5_final(EVP_MD_CTX *ctx,unsigned char *md) {
#ifdef OLD
- int ret;
+ fprintf(stderr, "MD5 final size of EVP_MD: %lu\r\n", (unsigned long)sizeof(EVP_MD));
+ if (!MD5_Final(md, data(ctx)))
+ goto err;
- fprintf(stderr, "MD5 final size of EVP_MD: %lu\r\n", sizeof(EVP_MD));
- ret = MD5_Final(md, data(ctx));
+ add_test_data(md, MD5_DIGEST_LENGTH);
+ return 1;
- if (ret > 0) {
- add_test_data(md, MD5_DIGEST_LENGTH);
- }
- return ret;
+ err:
+ return 0;
#else
fprintf(stderr, "MD5 final\r\n");
add_test_data(md, MD5_DIGEST_LENGTH);
@@ -130,7 +198,6 @@ static int test_digest_ids[] = {NID_md5};
static int test_engine_digest_selector(ENGINE *e, const EVP_MD **digest,
const int **nids, int nid) {
- int ok = 1;
if (!digest) {
*nids = test_digest_ids;
fprintf(stderr, "Digest is empty! Nid:%d\r\n", nid);
@@ -141,49 +208,82 @@ static int test_engine_digest_selector(ENGINE *e, const EVP_MD **digest,
#ifdef OLD
*digest = &test_engine_md5_method;
#else
- EVP_MD *md = EVP_MD_meth_new(NID_md5, NID_undef);
- if (!md ||
- !EVP_MD_meth_set_result_size(md, MD5_DIGEST_LENGTH) ||
- !EVP_MD_meth_set_flags(md, 0) ||
- !EVP_MD_meth_set_init(md, test_engine_md5_init) ||
- !EVP_MD_meth_set_update(md, test_engine_md5_update) ||
- !EVP_MD_meth_set_final(md, test_engine_md5_final) ||
- !EVP_MD_meth_set_copy(md, NULL) ||
- !EVP_MD_meth_set_cleanup(md, NULL) ||
- !EVP_MD_meth_set_input_blocksize(md, MD5_CBLOCK) ||
- !EVP_MD_meth_set_app_datasize(md, sizeof(EVP_MD *) + sizeof(MD5_CTX)) ||
- !EVP_MD_meth_set_ctrl(md, NULL))
- {
- ok = 0;
- *digest = NULL;
- } else
- {
- *digest = md;
- }
+ EVP_MD *md;
+
+ if ((md = EVP_MD_meth_new(NID_md5, NID_undef)) == NULL)
+ goto err;
+ if (EVP_MD_meth_set_result_size(md, MD5_DIGEST_LENGTH) != 1)
+ goto err;
+ if (EVP_MD_meth_set_flags(md, 0) != 1)
+ goto err;
+ if (EVP_MD_meth_set_init(md, test_engine_md5_init) != 1)
+ goto err;
+ if (EVP_MD_meth_set_update(md, test_engine_md5_update) != 1)
+ goto err;
+ if (EVP_MD_meth_set_final(md, test_engine_md5_final) != 1)
+ goto err;
+ if (EVP_MD_meth_set_copy(md, NULL) != 1)
+ goto err;
+ if (EVP_MD_meth_set_cleanup(md, NULL) != 1)
+ goto err;
+ if (EVP_MD_meth_set_input_blocksize(md, MD5_CBLOCK) != 1)
+ goto err;
+ if (EVP_MD_meth_set_app_datasize(md, sizeof(EVP_MD *) + sizeof(MD5_CTX)) != 1)
+ goto err;
+ if (EVP_MD_meth_set_ctrl(md, NULL) != 1)
+ goto err;
+
+ *digest = md;
#endif
}
else {
- ok = 0;
- *digest = NULL;
+ goto err;
}
- return ok;
-}
+ return 1;
+ err:
+ *digest = NULL;
+ return 0;
+}
static int bind_helper(ENGINE * e, const char *id)
{
- if (!ENGINE_set_id(e, test_engine_id) ||
- !ENGINE_set_name(e, test_engine_name) ||
- !ENGINE_set_init_function(e, test_init) ||
- !ENGINE_set_digests(e, &test_engine_digest_selector) ||
- /* For testing of key storage in an Engine: */
- !ENGINE_set_load_privkey_function(e, &test_key_load) ||
- !ENGINE_set_load_pubkey_function(e, &test_key_load)
- )
- return 0;
+#if defined(FAKE_RSA_IMPL)
+ if ((test_rsa_method = RSA_meth_new("OTP test RSA method", 0)) == NULL) {
+ fprintf(stderr, "RSA_meth_new failed\r\n");
+ goto err;
+ }
+#endif /* if defined(FAKE_RSA_IMPL) */
+
+ if (!ENGINE_set_id(e, test_engine_id))
+ goto err;
+ if (!ENGINE_set_name(e, test_engine_name))
+ goto err;
+ if (!ENGINE_set_init_function(e, test_init))
+ goto err;
+ if (!ENGINE_set_digests(e, &test_engine_digest_selector))
+ goto err;
+ /* For testing of key storage in an Engine: */
+ if (!ENGINE_set_load_privkey_function(e, &test_privkey_load))
+ goto err;
+ if (!ENGINE_set_load_pubkey_function(e, &test_pubkey_load))
+ goto err;
+
+#if defined(FAKE_RSA_IMPL)
+ if (!ENGINE_set_RSA(e, test_rsa_method))
+ goto err;
+#endif /* if defined(FAKE_RSA_IMPL) */
return 1;
+
+ err:
+#if defined(FAKE_RSA_IMPL)
+ if (test_rsa_method)
+ RSA_meth_free(test_rsa_method);
+ test_rsa_method = NULL;
+#endif
+ return 0;
}
IMPLEMENT_DYNAMIC_CHECK_FN();
@@ -197,24 +297,29 @@ IMPLEMENT_DYNAMIC_BIND_FN(bind_helper);
*/
int pem_passwd_cb_fun(char *buf, int size, int rwflag, void *password);
-EVP_PKEY* test_key_load(ENGINE *er, const char *id, UI_METHOD *ui_method, void *callback_data)
+EVP_PKEY* test_privkey_load(ENGINE *eng, const char *id, UI_METHOD *ui_method, void *callback_data) {
+ return test_key_load(eng, id, ui_method, callback_data, 1);
+}
+
+EVP_PKEY* test_pubkey_load(ENGINE *eng, const char *id, UI_METHOD *ui_method, void *callback_data) {
+ return test_key_load(eng, id, ui_method, callback_data, 0);
+}
+
+EVP_PKEY* test_key_load(ENGINE *eng, const char *id, UI_METHOD *ui_method, void *callback_data, int priv)
{
EVP_PKEY *pkey = NULL;
FILE *f = fopen(id, "r");
if (!f) {
- fprintf(stderr, "%s:%d fopen(%s) failed\r\n", __FILE__,__LINE__,id);
- return NULL;
+ fprintf(stderr, "%s:%d fopen(%s) failed\r\n", __FILE__,__LINE__,id);
+ return NULL;
}
- /* First try to read as a private key. If that fails, try to read as a public key: */
- pkey = PEM_read_PrivateKey(f, NULL, pem_passwd_cb_fun, callback_data);
- if (!pkey) {
- /* ERR_print_errors_fp (stderr); */
- fclose(f);
- f = fopen(id, "r");
- pkey = PEM_read_PUBKEY(f, NULL, NULL, NULL);
- }
+ pkey =
+ priv
+ ? PEM_read_PrivateKey(f, NULL, pem_passwd_cb_fun, callback_data)
+ : PEM_read_PUBKEY(f, NULL, NULL, NULL);
+
fclose(f);
if (!pkey) {
@@ -224,7 +329,7 @@ EVP_PKEY* test_key_load(ENGINE *er, const char *id, UI_METHOD *ui_method, void *
fprintf(stderr, "Contents of file \"%s\":\r\n",id);
f = fopen(id, "r");
{ /* Print the contents of the key file */
- char c;
+ int c;
while (!feof(f)) {
switch (c=fgetc(f)) {
case '\n':
@@ -244,21 +349,106 @@ EVP_PKEY* test_key_load(ENGINE *er, const char *id, UI_METHOD *ui_method, void *
int pem_passwd_cb_fun(char *buf, int size, int rwflag, void *password)
{
- int i;
+ size_t i;
+
+ if (size < 0)
+ return 0;
fprintf(stderr, "In pem_passwd_cb_fun\r\n");
if (!password)
return 0;
i = strlen(password);
- if (i < size) {
- /* whole pwd (incl terminating 0) fits */
- fprintf(stderr, "Got FULL pwd %d(%d) chars\r\n", i, size);
- memcpy(buf, (char*)password, i+1);
- return i+1;
- } else {
- fprintf(stderr, "Got TO LONG pwd %d(%d) chars\r\n", i, size);
- /* meaningless with a truncated password */
- return 0;
+ if (i >= (size_t)size || i > INT_MAX - 1)
+ goto err;
+
+ /* whole pwd (incl terminating 0) fits */
+ fprintf(stderr, "Got FULL pwd %zu(%d) chars\r\n", i, size);
+ memcpy(buf, (char*)password, i+1);
+ return (int)i+1;
+
+ err:
+ fprintf(stderr, "Got TO LONG pwd %zu(%d) chars\r\n", i, size);
+ /* meaningless with a truncated password */
+ return 0;
+}
+
+#endif
+
+#if defined(FAKE_RSA_IMPL)
+/* RSA sign. This returns a fixed string so the test case can test that it was called
+ instead of the cryptolib default RSA sign */
+
+static unsigned char fake_flag[] = {255,3,124,180,35,10,180,151,101,247,62,59,80,122,220,
+ 142,24,180,191,34,51,150,112,27,43,142,195,60,245,213,80,179};
+
+int test_rsa_sign(int dtype,
+ /* The digest to sign */
+ const unsigned char *m, unsigned int m_len,
+ /* The allocated buffer to fill with the signature */
+ unsigned char *sigret, unsigned int *siglen,
+ /* The key */
+ const RSA *rsa)
+{
+ fprintf(stderr, "test_rsa_sign (dtype=%i) called m_len=%u *siglen=%u\r\n", dtype, m_len, *siglen);
+ if (!sigret) {
+ fprintf(stderr, "sigret = NULL\r\n");
+ goto err;
}
+
+ /* {int i;
+ fprintf(stderr, "Digest =\r\n");
+ for(i=0; i<m_len; i++)
+ fprintf(stderr, "%i,", m[i]);
+ fprintf(stderr, "\r\n");
+ } */
+
+ if ((sizeof(fake_flag) == m_len)
+ && memcmp(m,fake_flag,m_len) == 0) {
+ int slen;
+
+ printf("To be faked\r\n");
+ /* To be faked */
+ if ((slen = RSA_size(rsa)) < 0)
+ goto err;
+ add_test_data(sigret, (unsigned int)slen); /* The signature is 0,1,2...255,0,1... */
+ *siglen = (unsigned int)slen; /* Must set this. Why? */
+ return 1; /* 1 = success */
+ }
+ return 0;
+
+ err:
+ return -1;
}
+
+int test_rsa_verify(int dtype,
+ /* The digest to verify */
+ const unsigned char *m, unsigned int m_len,
+ /* The signature */
+ const unsigned char *sigret, unsigned int siglen,
+ /* The key */
+ const RSA *rsa)
+{
+ printf("test_rsa_verify (dtype=%i) called m_len=%u siglen=%u\r\n", dtype, m_len, siglen);
+
+ if ((sizeof(fake_flag) == m_len)
+ && memcmp(m,fake_flag,m_len) == 0) {
+ int size;
+
+ if ((size = RSA_size(rsa)) < 0)
+ return 0;
+
+ printf("To be faked\r\n");
+ return (siglen == (unsigned int)size)
+ && chk_test_data(sigret, siglen);
+ }
+ return 0;
+}
+
+static int test_rsa_free(RSA *rsa)
+{
+ printf("test_rsa_free called\r\n");
+ return 1;
+}
+
+#endif /* if defined(FAKE_RSA_IMPL) */
diff --git a/lib/crypto/c_src/pkey.c b/lib/crypto/c_src/pkey.c
new file mode 100644
index 0000000000..a1e2677b34
--- /dev/null
+++ b/lib/crypto/c_src/pkey.c
@@ -0,0 +1,1486 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "pkey.h"
+#include "bn.h"
+#include "digest.h"
+#include "dss.h"
+#include "ec.h"
+#include "eddsa.h"
+#include "engine.h"
+#include "rsa.h"
+
+#define PKEY_BADARG -1
+#define PKEY_NOTSUP 0
+#define PKEY_OK 1
+
+typedef struct PKeyCryptOptions {
+ const EVP_MD *rsa_mgf1_md;
+ ErlNifBinary rsa_oaep_label;
+ const EVP_MD *rsa_oaep_md;
+ int rsa_padding;
+ const EVP_MD *signature_md;
+} PKeyCryptOptions;
+
+typedef struct PKeySignOptions {
+ const EVP_MD *rsa_mgf1_md;
+ int rsa_padding;
+ int rsa_pss_saltlen;
+} PKeySignOptions;
+
+
+static int get_pkey_digest_type(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM type,
+ const EVP_MD **md);
+static int get_pkey_sign_digest(ErlNifEnv *env, ERL_NIF_TERM algorithm,
+ ERL_NIF_TERM type, ERL_NIF_TERM data,
+ unsigned char *md_value, const EVP_MD **mdp,
+ unsigned char **tbsp, size_t *tbslenp);
+static int get_pkey_sign_options(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM options,
+ const EVP_MD *md, PKeySignOptions *opt);
+static int get_pkey_private_key(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM key, EVP_PKEY **pkey);
+static int get_pkey_public_key(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM key,
+ EVP_PKEY **pkey);
+static int get_pkey_crypt_options(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM options,
+ PKeyCryptOptions *opt);
+static size_t size_of_RSA(EVP_PKEY *pkey);
+
+
+static int get_pkey_digest_type(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM type,
+ const EVP_MD **md)
+{
+ struct digest_type_t *digp = NULL;
+ *md = NULL;
+
+ if (type == atom_none && algorithm == atom_rsa)
+ return PKEY_OK;
+ if (algorithm == atom_eddsa) {
+#ifdef HAVE_EDDSA
+ if (!FIPS_mode()) return PKEY_OK;
+#else
+ return PKEY_NOTSUP;
+#endif
+ }
+ if ((digp = get_digest_type(type)) == NULL)
+ return PKEY_BADARG;
+ if (digp->md.p == NULL)
+ return PKEY_NOTSUP;
+
+ *md = digp->md.p;
+ return PKEY_OK;
+}
+
+static int get_pkey_sign_digest(ErlNifEnv *env, ERL_NIF_TERM algorithm,
+ ERL_NIF_TERM type, ERL_NIF_TERM data,
+ unsigned char *md_value, const EVP_MD **mdp,
+ unsigned char **tbsp, size_t *tbslenp)
+{
+ int i, ret;
+ const ERL_NIF_TERM *tpl_terms;
+ int tpl_arity;
+ ErlNifBinary tbs_bin;
+ EVP_MD_CTX *mdctx = NULL;
+ const EVP_MD *md;
+ unsigned char *tbs;
+ size_t tbslen;
+ unsigned int tbsleni;
+
+ md = *mdp;
+ tbs = *tbsp;
+ tbslen = *tbslenp;
+
+ if ((i = get_pkey_digest_type(env, algorithm, type, &md)) != PKEY_OK)
+ return i;
+
+ if (enif_get_tuple(env, data, &tpl_arity, &tpl_terms)) {
+ if (tpl_arity != 2)
+ goto bad_arg;
+ if (tpl_terms[0] != atom_digest)
+ goto bad_arg;
+ if (!enif_inspect_iolist_as_binary(env, tpl_terms[1], &tbs_bin))
+ goto bad_arg;
+ if (tbs_bin.size > INT_MAX)
+ goto bad_arg;
+ if (md != NULL) {
+ if ((int)tbs_bin.size != EVP_MD_size(md))
+ goto bad_arg;
+ }
+
+ /* We have a digest (= hashed text) in tbs_bin */
+ tbs = tbs_bin.data;
+ tbslen = tbs_bin.size;
+ } else if (md == NULL) {
+ if (!enif_inspect_iolist_as_binary(env, data, &tbs_bin))
+ goto bad_arg;
+
+ /* md == NULL, that is no hashing because DigestType argument was atom_none */
+ tbs = tbs_bin.data;
+ tbslen = tbs_bin.size;
+ } else {
+ if (!enif_inspect_iolist_as_binary(env, data, &tbs_bin))
+ goto bad_arg;
+
+ /* We have the cleartext in tbs_bin and the hash algo info in md */
+ tbs = md_value;
+
+ if ((mdctx = EVP_MD_CTX_create()) == NULL)
+ goto err;
+
+ /* Looks well, now hash the plain text into a digest according to md */
+ if (EVP_DigestInit_ex(mdctx, md, NULL) != 1)
+ goto err;
+ if (EVP_DigestUpdate(mdctx, tbs_bin.data, tbs_bin.size) != 1)
+ goto err;
+ if (EVP_DigestFinal_ex(mdctx, tbs, &tbsleni) != 1)
+ goto err;
+
+ tbslen = (size_t)tbsleni;
+ }
+
+ *mdp = md;
+ *tbsp = tbs;
+ *tbslenp = tbslen;
+
+ ret = PKEY_OK;
+ goto done;
+
+ bad_arg:
+ err:
+ ret = PKEY_BADARG;
+
+ done:
+ if (mdctx)
+ EVP_MD_CTX_destroy(mdctx);
+ return ret;
+}
+
+static int get_pkey_sign_options(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM options,
+ const EVP_MD *md, PKeySignOptions *opt)
+{
+ ERL_NIF_TERM head, tail;
+ const ERL_NIF_TERM *tpl_terms;
+ int tpl_arity;
+ const EVP_MD *opt_md;
+
+ if (!enif_is_list(env, options))
+ goto bad_arg;
+
+ /* defaults */
+ if (algorithm == atom_rsa) {
+ opt->rsa_mgf1_md = NULL;
+ opt->rsa_padding = RSA_PKCS1_PADDING;
+ opt->rsa_pss_saltlen = -2;
+ }
+
+ if (enif_is_empty_list(env, options))
+ return PKEY_OK;
+
+ if (algorithm != atom_rsa)
+ goto bad_arg;
+
+ tail = options;
+ while (enif_get_list_cell(env, tail, &head, &tail)) {
+ if (!enif_get_tuple(env, head, &tpl_arity, &tpl_terms))
+ goto bad_arg;
+ if (tpl_arity != 2)
+ goto bad_arg;
+
+ if (tpl_terms[0] == atom_rsa_mgf1_md && enif_is_atom(env, tpl_terms[1])) {
+ int result;
+
+ result = get_pkey_digest_type(env, algorithm, tpl_terms[1], &opt_md);
+ if (result != PKEY_OK)
+ return result;
+
+ opt->rsa_mgf1_md = opt_md;
+
+ } else if (tpl_terms[0] == atom_rsa_padding) {
+ if (tpl_terms[1] == atom_rsa_pkcs1_padding) {
+ opt->rsa_padding = RSA_PKCS1_PADDING;
+
+ } else if (tpl_terms[1] == atom_rsa_pkcs1_pss_padding) {
+#ifdef HAVE_RSA_PKCS1_PSS_PADDING
+ opt->rsa_padding = RSA_PKCS1_PSS_PADDING;
+ if (opt->rsa_mgf1_md == NULL)
+ opt->rsa_mgf1_md = md;
+#else
+ return PKEY_NOTSUP;
+#endif
+
+ } else if (tpl_terms[1] == atom_rsa_x931_padding) {
+ opt->rsa_padding = RSA_X931_PADDING;
+
+ } else if (tpl_terms[1] == atom_rsa_no_padding) {
+ opt->rsa_padding = RSA_NO_PADDING;
+
+ } else {
+ goto bad_arg;
+ }
+
+ } else if (tpl_terms[0] == atom_rsa_pss_saltlen) {
+ if (!enif_get_int(env, tpl_terms[1], &(opt->rsa_pss_saltlen)))
+ goto bad_arg;
+ if (opt->rsa_pss_saltlen < -2)
+ goto bad_arg;
+
+ } else {
+ goto bad_arg;
+ }
+ }
+
+ return PKEY_OK;
+
+ bad_arg:
+ return PKEY_BADARG;
+}
+
+static int get_pkey_private_key(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM key, EVP_PKEY **pkey)
+{
+ EVP_PKEY *result = NULL;
+ RSA *rsa = NULL;
+#ifdef HAVE_DSA
+ DSA *dsa = NULL;
+#endif
+#if defined(HAVE_EC)
+ EC_KEY *ec = NULL;
+#endif
+ char *id = NULL;
+ char *password = NULL;
+
+ if (enif_is_map(env, key)) {
+#ifdef HAS_ENGINE_SUPPORT
+ /* Use key stored in engine */
+ ENGINE *e;
+
+ if (!get_engine_and_key_id(env, key, &id, &e))
+ goto err;
+
+ password = get_key_password(env, key);
+ result = ENGINE_load_private_key(e, id, NULL, password);
+
+#else
+ return PKEY_BADARG;
+#endif
+ } else if (algorithm == atom_rsa) {
+ if ((rsa = RSA_new()) == NULL)
+ goto err;
+
+ if (!get_rsa_private_key(env, key, rsa))
+ goto err;
+ if ((result = EVP_PKEY_new()) == NULL)
+ goto err;
+ if (EVP_PKEY_assign_RSA(result, rsa) != 1)
+ goto err;
+ /* On success, result owns rsa */
+ rsa = NULL;
+
+ } else if (algorithm == atom_ecdsa) {
+#if defined(HAVE_EC)
+ const ERL_NIF_TERM *tpl_terms;
+ int tpl_arity;
+
+ if (!enif_get_tuple(env, key, &tpl_arity, &tpl_terms))
+ goto err;
+ if (tpl_arity != 2)
+ goto err;
+ if (!enif_is_tuple(env, tpl_terms[0]))
+ goto err;
+ if (!enif_is_binary(env, tpl_terms[1]))
+ goto err;
+ if (!get_ec_key(env, tpl_terms[0], tpl_terms[1], atom_undefined, &ec))
+ goto err;
+
+ if ((result = EVP_PKEY_new()) == NULL)
+ goto err;
+ if (EVP_PKEY_assign_EC_KEY(result, ec) != 1)
+ goto err;
+ /* On success, result owns ec */
+ ec = NULL;
+
+#else
+ return PKEY_NOTSUP;
+#endif
+ } else if (algorithm == atom_eddsa) {
+#ifdef HAVE_EDDSA
+ if (!FIPS_mode())
+ {
+ if (!get_eddsa_key(env, 0, key, &result))
+ goto err;
+ else
+ goto done; // Not nice....
+ }
+#else
+ return PKEY_NOTSUP;
+#endif
+ } else if (algorithm == atom_dss) {
+#ifdef HAVE_DSA
+ if ((dsa = DSA_new()) == NULL)
+ goto err;
+ if (!get_dss_private_key(env, key, dsa))
+ goto err;
+
+ if ((result = EVP_PKEY_new()) == NULL)
+ goto err;
+ if (EVP_PKEY_assign_DSA(result, dsa) != 1)
+ goto err;
+ /* On success, result owns dsa */
+ dsa = NULL;
+
+ } else {
+#endif
+ return PKEY_BADARG;
+ }
+ goto done;
+
+ err:
+ if (result)
+ EVP_PKEY_free(result);
+ result = NULL;
+
+ done:
+ if (password)
+ enif_free(password);
+ if (id)
+ enif_free(id);
+ if (rsa)
+ RSA_free(rsa);
+#ifdef HAVE_DSA
+ if (dsa)
+ DSA_free(dsa);
+#endif
+#ifdef HAVE_EC
+ if (ec)
+ EC_KEY_free(ec);
+#endif
+
+ if (result == NULL) {
+ return PKEY_BADARG;
+ } else {
+ *pkey = result;
+ return PKEY_OK;
+ }
+}
+
+static int get_pkey_public_key(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM key,
+ EVP_PKEY **pkey)
+{
+ EVP_PKEY *result = NULL;
+ RSA *rsa = NULL;
+#ifdef HAVE_DSA
+ DSA *dsa = NULL;
+#endif
+#if defined(HAVE_EC)
+ EC_KEY *ec = NULL;
+#endif
+ char *id = NULL;
+ char *password = NULL;
+
+ if (enif_is_map(env, key)) {
+#ifdef HAS_ENGINE_SUPPORT
+ /* Use key stored in engine */
+ ENGINE *e;
+
+ if (!get_engine_and_key_id(env, key, &id, &e))
+ goto err;
+
+ password = get_key_password(env, key);
+ result = ENGINE_load_public_key(e, id, NULL, password);
+
+#else
+ return PKEY_BADARG;
+#endif
+ } else if (algorithm == atom_rsa) {
+ if ((rsa = RSA_new()) == NULL)
+ goto err;
+
+ if (!get_rsa_public_key(env, key, rsa))
+ goto err;
+
+ if ((result = EVP_PKEY_new()) == NULL)
+ goto err;
+ if (EVP_PKEY_assign_RSA(result, rsa) != 1)
+ goto err;
+ /* On success, result owns rsa */
+ rsa = NULL;
+
+ } else if (algorithm == atom_ecdsa) {
+#if defined(HAVE_EC)
+ const ERL_NIF_TERM *tpl_terms;
+ int tpl_arity;
+
+ if (!enif_get_tuple(env, key, &tpl_arity, &tpl_terms))
+ goto err;
+ if (tpl_arity != 2)
+ goto err;
+ if (!enif_is_tuple(env, tpl_terms[0]))
+ goto err;
+ if (!enif_is_binary(env, tpl_terms[1]))
+ goto err;
+ if (!get_ec_key(env, tpl_terms[0], atom_undefined, tpl_terms[1], &ec))
+ goto err;
+
+ if ((result = EVP_PKEY_new()) == NULL)
+ goto err;
+
+ if (EVP_PKEY_assign_EC_KEY(result, ec) != 1)
+ goto err;
+ /* On success, result owns ec */
+ ec = NULL;
+
+#else
+ return PKEY_NOTSUP;
+#endif
+ } else if (algorithm == atom_eddsa) {
+#ifdef HAVE_EDDSA
+ if (!FIPS_mode()) {
+ if (!get_eddsa_key(env, 1, key, &result))
+ goto err;
+ }
+#else
+ return PKEY_NOTSUP;
+#endif
+ } else if (algorithm == atom_dss) {
+#ifdef HAVE_DSA
+ if ((dsa = DSA_new()) == NULL)
+ goto err;
+
+ if (!get_dss_public_key(env, key, dsa))
+ goto err;
+
+ if ((result = EVP_PKEY_new()) == NULL)
+ goto err;
+ if (EVP_PKEY_assign_DSA(result, dsa) != 1)
+ goto err;
+ /* On success, result owns dsa */
+ dsa = NULL;
+#else
+ return PKEY_NOTSUP;
+#endif
+ } else {
+ return PKEY_BADARG;
+ }
+
+ goto done;
+
+ err:
+ if (result)
+ EVP_PKEY_free(result);
+ result = NULL;
+
+ done:
+ if (password)
+ enif_free(password);
+ if (id)
+ enif_free(id);
+ if (rsa)
+ RSA_free(rsa);
+#ifdef HAVE_DSA
+ if (dsa)
+ DSA_free(dsa);
+#endif
+#ifdef HAVE_EC
+ if (ec)
+ EC_KEY_free(ec);
+#endif
+
+ if (result == NULL) {
+ return PKEY_BADARG;
+ } else {
+ *pkey = result;
+ return PKEY_OK;
+ }
+}
+
+ERL_NIF_TERM pkey_sign_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
+{/* (Algorithm, Type, Data|{digest,Digest}, Key|#{}, Options) */
+ int i;
+ int sig_bin_alloc = 0;
+ ERL_NIF_TERM ret;
+ const EVP_MD *md = NULL;
+ unsigned char md_value[EVP_MAX_MD_SIZE];
+ EVP_PKEY *pkey = NULL;
+#ifdef HAVE_EDDSA
+ EVP_MD_CTX *mdctx = NULL;
+#endif
+#ifdef HAS_EVP_PKEY_CTX
+ EVP_PKEY_CTX *ctx = NULL;
+ size_t siglen;
+#else
+ int len;
+ unsigned int siglen;
+#endif
+ PKeySignOptions sig_opt;
+ ErlNifBinary sig_bin; /* signature */
+ unsigned char *tbs; /* data to be signed */
+ size_t tbslen;
+ RSA *rsa = NULL;
+#ifdef HAVE_DSA
+ DSA *dsa = NULL;
+#endif
+#if defined(HAVE_EC)
+ EC_KEY *ec = NULL;
+#endif
+/*char buf[1024];
+enif_get_atom(env,argv[0],buf,1024,ERL_NIF_LATIN1); printf("algo=%s ",buf);
+enif_get_atom(env,argv[1],buf,1024,ERL_NIF_LATIN1); printf("hash=%s ",buf);
+*/
+
+#ifndef HAS_ENGINE_SUPPORT
+ if (enif_is_map(env, argv[3]))
+ return atom_notsup;
+#endif
+
+ i = get_pkey_sign_digest(env, argv[0], argv[1], argv[2], md_value, &md, &tbs, &tbslen);
+ switch (i) {
+ case PKEY_OK:
+ break;
+ case PKEY_NOTSUP:
+ goto notsup;
+ default:
+ goto bad_arg;
+ }
+
+ i = get_pkey_sign_options(env, argv[0], argv[4], md, &sig_opt);
+ switch (i) {
+ case PKEY_OK:
+ break;
+ case PKEY_NOTSUP:
+ goto notsup;
+ default:
+ goto bad_arg;
+ }
+
+ if (get_pkey_private_key(env, argv[0], argv[3], &pkey) != PKEY_OK)
+ goto bad_arg;
+
+#ifdef HAS_EVP_PKEY_CTX
+ if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL)
+ goto err;
+
+ if (argv[0] != atom_eddsa) {
+ if (EVP_PKEY_sign_init(ctx) != 1)
+ goto err;
+ if (md != NULL) {
+ if (EVP_PKEY_CTX_set_signature_md(ctx, md) != 1)
+ goto err;
+ }
+ }
+
+ if (argv[0] == atom_rsa) {
+ if (EVP_PKEY_CTX_set_rsa_padding(ctx, sig_opt.rsa_padding) != 1)
+ goto err;
+# ifdef HAVE_RSA_PKCS1_PSS_PADDING
+ if (sig_opt.rsa_padding == RSA_PKCS1_PSS_PADDING) {
+ if (sig_opt.rsa_mgf1_md != NULL) {
+# ifdef HAVE_RSA_MGF1_MD
+ if (EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, sig_opt.rsa_mgf1_md) != 1)
+ goto err;
+# else
+ goto notsup;
+# endif
+ }
+ if (sig_opt.rsa_pss_saltlen > -2) {
+ if (EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, sig_opt.rsa_pss_saltlen) != 1)
+ goto err;
+ }
+ }
+#endif
+ }
+
+ if (argv[0] == atom_eddsa) {
+#ifdef HAVE_EDDSA
+ if (!FIPS_mode()) {
+ if ((mdctx = EVP_MD_CTX_new()) == NULL)
+ goto err;
+
+ if (EVP_DigestSignInit(mdctx, NULL, NULL, NULL, pkey) != 1)
+ goto err;
+ if (EVP_DigestSign(mdctx, NULL, &siglen, tbs, tbslen) != 1)
+ goto err;
+ if (!enif_alloc_binary(siglen, &sig_bin))
+ goto err;
+ sig_bin_alloc = 1;
+
+ if (EVP_DigestSign(mdctx, sig_bin.data, &siglen, tbs, tbslen) != 1)
+ goto bad_key;
+ }
+ else
+#endif
+ goto notsup;
+ } else {
+ if (EVP_PKEY_sign(ctx, NULL, &siglen, tbs, tbslen) != 1)
+ goto err;
+ if (!enif_alloc_binary(siglen, &sig_bin))
+ goto err;
+ sig_bin_alloc = 1;
+
+ if (md != NULL) {
+ ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, EVP_MD_size(md));
+ }
+ if (EVP_PKEY_sign(ctx, sig_bin.data, &siglen, tbs, tbslen) != 1)
+ goto bad_key;
+ }
+#else
+/*printf("Old interface\r\n");
+ */
+ if (argv[0] == atom_rsa) {
+ if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL)
+ goto err;
+ if ((len = RSA_size(rsa)) < 0)
+ goto err;
+ if (!enif_alloc_binary((size_t)len, &sig_bin))
+ goto err;
+ sig_bin_alloc = 1;
+
+ if ((len = EVP_MD_size(md)) < 0)
+ goto err;
+ ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, len);
+
+ if (RSA_sign(md->type, tbs, (unsigned int)len, sig_bin.data, &siglen, rsa) != 1)
+ goto bad_key;
+ } else if (argv[0] == atom_dss) {
+ if ((dsa = EVP_PKEY_get1_DSA(pkey)) == NULL)
+ goto err;
+ if ((len = DSA_size(dsa)) < 0)
+ goto err;
+ if (!enif_alloc_binary((size_t)len, &sig_bin))
+ goto err;
+ sig_bin_alloc = 1;
+
+ if ((len = EVP_MD_size(md)) < 0)
+ goto err;
+ ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, len);
+
+ if (DSA_sign(md->type, tbs, len, sig_bin.data, &siglen, dsa) != 1)
+ goto bad_key;
+ } else if (argv[0] == atom_ecdsa) {
+#if defined(HAVE_EC)
+ if ((ec = EVP_PKEY_get1_EC_KEY(pkey)) == NULL)
+ goto err;
+ if ((len = ECDSA_size(ec)) < 0)
+ goto err;
+ if (!enif_alloc_binary((size_t)len, &sig_bin))
+ goto err;
+ sig_bin_alloc = 1;
+
+ len = EVP_MD_size(md);
+ ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, len);
+
+ if (ECDSA_sign(md->type, tbs, len, sig_bin.data, &siglen, ec) != 1)
+ goto bad_key;
+#else
+ goto notsup;
+#endif
+ } else {
+ goto bad_arg;
+ }
+#endif
+
+ ERL_VALGRIND_MAKE_MEM_DEFINED(sig_bin.data, siglen);
+ if (siglen != sig_bin.size) {
+ if (!enif_realloc_binary(&sig_bin, siglen))
+ goto err;
+ ERL_VALGRIND_ASSERT_MEM_DEFINED(sig_bin.data, siglen);
+ }
+ ret = enif_make_binary(env, &sig_bin);
+ sig_bin_alloc = 0;
+ goto done;
+
+ bad_key:
+ ret = atom_error;
+ goto done;
+
+ notsup:
+ ret = atom_notsup;
+ goto done;
+
+ bad_arg:
+ err:
+ ret = enif_make_badarg(env);
+ goto done;
+
+ done:
+ if (sig_bin_alloc)
+ enif_release_binary(&sig_bin);
+ if (rsa)
+ RSA_free(rsa);
+#ifdef HAVE_DSA
+ if (dsa)
+ DSA_free(dsa);
+#endif
+#ifdef HAVE_EC
+ if (ec)
+ EC_KEY_free(ec);
+#endif
+#ifdef HAS_EVP_PKEY_CTX
+ if (ctx)
+ EVP_PKEY_CTX_free(ctx);
+#endif
+ if (pkey)
+ EVP_PKEY_free(pkey);
+
+#ifdef HAVE_EDDSA
+ if (mdctx)
+ EVP_MD_CTX_free(mdctx);
+#endif
+
+ return ret;
+}
+
+ERL_NIF_TERM pkey_verify_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
+{/* (Algorithm, Type, Data|{digest,Digest}, Signature, Key, Options) */
+ int i;
+ int result;
+ const EVP_MD *md = NULL;
+ unsigned char md_value[EVP_MAX_MD_SIZE];
+ EVP_PKEY *pkey = NULL;
+#ifdef HAS_EVP_PKEY_CTX
+ EVP_PKEY_CTX *ctx = NULL;
+#else
+#endif
+ PKeySignOptions sig_opt;
+ ErlNifBinary sig_bin; /* signature */
+ unsigned char *tbs; /* data to be signed */
+ size_t tbslen;
+ ERL_NIF_TERM ret;
+ RSA *rsa = NULL;
+#ifdef HAVE_DSA
+ DSA *dsa = NULL;
+#endif
+#ifdef HAVE_EC
+ EC_KEY *ec = NULL;
+#endif
+#ifdef HAVE_EDDSA
+ EVP_MD_CTX *mdctx = NULL;
+#endif
+
+#ifndef HAS_ENGINE_SUPPORT
+ if (enif_is_map(env, argv[4]))
+ return atom_notsup;
+#endif
+
+ if (!enif_inspect_binary(env, argv[3], &sig_bin))
+ return enif_make_badarg(env);
+
+ i = get_pkey_sign_digest(env, argv[0], argv[1], argv[2], md_value, &md, &tbs, &tbslen);
+ switch (i) {
+ case PKEY_OK:
+ break;
+ case PKEY_NOTSUP:
+ goto notsup;
+ default:
+ goto bad_arg;
+ }
+
+ i = get_pkey_sign_options(env, argv[0], argv[5], md, &sig_opt);
+ switch (i) {
+ case PKEY_OK:
+ break;
+ case PKEY_NOTSUP:
+ goto notsup;
+ default:
+ goto bad_arg;
+ }
+
+ if (get_pkey_public_key(env, argv[0], argv[4], &pkey) != PKEY_OK) {
+ goto bad_arg;
+ }
+
+#ifdef HAS_EVP_PKEY_CTX
+/* printf("EVP interface\r\n");
+ */
+ if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL)
+ goto err;
+
+ if (argv[0] != atom_eddsa) {
+ if (EVP_PKEY_verify_init(ctx) != 1)
+ goto err;
+ if (md != NULL) {
+ if (EVP_PKEY_CTX_set_signature_md(ctx, md) != 1)
+ goto err;
+ }
+ }
+
+ if (argv[0] == atom_rsa) {
+ if (EVP_PKEY_CTX_set_rsa_padding(ctx, sig_opt.rsa_padding) != 1)
+ goto err;
+ if (sig_opt.rsa_padding == RSA_PKCS1_PSS_PADDING) {
+ if (sig_opt.rsa_mgf1_md != NULL) {
+# ifdef HAVE_RSA_MGF1_MD
+ if (EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, sig_opt.rsa_mgf1_md) != 1)
+ goto err;
+# else
+ goto notsup;
+# endif
+ }
+ if (sig_opt.rsa_pss_saltlen > -2) {
+ if (EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, sig_opt.rsa_pss_saltlen) != 1)
+ goto err;
+ }
+ }
+ }
+
+ if (argv[0] == atom_eddsa) {
+#ifdef HAVE_EDDSA
+ if (!FIPS_mode()) {
+ if ((mdctx = EVP_MD_CTX_new()) == NULL)
+ goto err;
+
+ if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) != 1)
+ goto err;
+
+ result = EVP_DigestVerify(mdctx, sig_bin.data, sig_bin.size, tbs, tbslen);
+ }
+ else
+#endif
+ goto notsup;
+ } else {
+ if (md != NULL) {
+ ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, EVP_MD_size(md));
+ }
+ result = EVP_PKEY_verify(ctx, sig_bin.data, sig_bin.size, tbs, tbslen);
+ }
+#else
+/*printf("Old interface\r\n");
+*/
+ if (tbslen > INT_MAX)
+ goto bad_arg;
+ if (sig_bin.size > INT_MAX)
+ goto bad_arg;
+ if (argv[0] == atom_rsa) {
+ if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL)
+ goto err;
+ result = RSA_verify(md->type, tbs, (unsigned int)tbslen, sig_bin.data, (unsigned int)sig_bin.size, rsa);
+ } else if (argv[0] == atom_dss) {
+ if ((dsa = EVP_PKEY_get1_DSA(pkey)) == NULL)
+ goto err;
+ result = DSA_verify(0, tbs, (int)tbslen, sig_bin.data, (int)sig_bin.size, dsa);
+ } else if (argv[0] == atom_ecdsa) {
+#if defined(HAVE_EC)
+ if ((ec = EVP_PKEY_get1_EC_KEY(pkey)) == NULL)
+ goto err;
+ result = ECDSA_verify(EVP_MD_type(md), tbs, (int)tbslen, sig_bin.data, (int)sig_bin.size, ec);
+#else
+ goto notsup;
+#endif
+ } else {
+ goto bad_arg;
+ }
+#endif
+
+ ret = (result == 1 ? atom_true : atom_false);
+ goto done;
+
+ bad_arg:
+ err:
+ ret = enif_make_badarg(env);
+ goto done;
+
+ notsup:
+ ret = atom_notsup;
+
+ done:
+#ifdef HAS_EVP_PKEY_CTX
+ if (ctx)
+ EVP_PKEY_CTX_free(ctx);
+#endif
+#ifdef HAVE_EDDSA
+ if (mdctx)
+ EVP_MD_CTX_free(mdctx);
+#endif
+ if (pkey)
+ EVP_PKEY_free(pkey);
+ if (rsa)
+ RSA_free(rsa);
+#ifdef HAVE_DSA
+ if (dsa)
+ DSA_free(dsa);
+#endif
+#ifdef HAVE_EC
+ if (ec)
+ EC_KEY_free(ec);
+#endif
+
+ return ret;
+}
+
+static int get_pkey_crypt_options(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM options,
+ PKeyCryptOptions *opt)
+{
+ ERL_NIF_TERM head, tail;
+ const ERL_NIF_TERM *tpl_terms;
+ int tpl_arity;
+ const EVP_MD *opt_md;
+
+ if (!enif_is_list(env, options))
+ goto bad_arg;
+
+ /* defaults */
+ if (algorithm == atom_rsa) {
+ opt->rsa_mgf1_md = NULL;
+ opt->rsa_oaep_label.data = NULL;
+ opt->rsa_oaep_label.size = 0;
+ opt->rsa_oaep_md = NULL;
+ opt->rsa_padding = RSA_PKCS1_PADDING;
+ opt->signature_md = NULL;
+ }
+
+ if (enif_is_empty_list(env, options))
+ return PKEY_OK;
+
+ if (algorithm != atom_rsa)
+ goto bad_arg;
+
+ tail = options;
+ while (enif_get_list_cell(env, tail, &head, &tail)) {
+ if (!enif_get_tuple(env, head, &tpl_arity, &tpl_terms))
+ goto bad_arg;
+ if (tpl_arity != 2)
+ goto bad_arg;
+
+ if (tpl_terms[0] == atom_rsa_padding
+ || tpl_terms[0] == atom_rsa_pad /* Compatibility */
+ ) {
+ if (tpl_terms[1] == atom_rsa_pkcs1_padding) {
+ opt->rsa_padding = RSA_PKCS1_PADDING;
+
+#ifdef HAVE_RSA_OAEP_PADDING
+ } else if (tpl_terms[1] == atom_rsa_pkcs1_oaep_padding) {
+ opt->rsa_padding = RSA_PKCS1_OAEP_PADDING;
+#endif
+
+#ifdef HAVE_RSA_SSLV23_PADDING
+ } else if (tpl_terms[1] == atom_rsa_sslv23_padding) {
+ opt->rsa_padding = RSA_SSLV23_PADDING;
+#endif
+
+ } else if (tpl_terms[1] == atom_rsa_x931_padding) {
+ opt->rsa_padding = RSA_X931_PADDING;
+
+ } else if (tpl_terms[1] == atom_rsa_no_padding) {
+ opt->rsa_padding = RSA_NO_PADDING;
+
+ } else {
+ goto bad_arg;
+ }
+
+ } else if (tpl_terms[0] == atom_signature_md && enif_is_atom(env, tpl_terms[1])) {
+ int i;
+ i = get_pkey_digest_type(env, algorithm, tpl_terms[1], &opt_md);
+ if (i != PKEY_OK) {
+ return i;
+ }
+ opt->signature_md = opt_md;
+
+ } else if (tpl_terms[0] == atom_rsa_mgf1_md && enif_is_atom(env, tpl_terms[1])) {
+ int i;
+#ifndef HAVE_RSA_MGF1_MD
+ if (tpl_terms[1] != atom_sha)
+ return PKEY_NOTSUP;
+#endif
+ i = get_pkey_digest_type(env, algorithm, tpl_terms[1], &opt_md);
+ if (i != PKEY_OK) {
+ return i;
+ }
+ opt->rsa_mgf1_md = opt_md;
+
+ } else if (tpl_terms[0] == atom_rsa_oaep_label
+ && enif_inspect_binary(env, tpl_terms[1], &(opt->rsa_oaep_label))) {
+#ifdef HAVE_RSA_OAEP_MD
+ continue;
+#else
+ return PKEY_NOTSUP;
+#endif
+
+ } else if (tpl_terms[0] == atom_rsa_oaep_md && enif_is_atom(env, tpl_terms[1])) {
+ int i;
+#ifndef HAVE_RSA_OAEP_MD
+ if (tpl_terms[1] != atom_sha)
+ return PKEY_NOTSUP;
+#endif
+ i = get_pkey_digest_type(env, algorithm, tpl_terms[1], &opt_md);
+ if (i != PKEY_OK) {
+ return i;
+ }
+ opt->rsa_oaep_md = opt_md;
+
+ } else {
+ goto bad_arg;
+ }
+ }
+
+ return PKEY_OK;
+
+ bad_arg:
+ return PKEY_BADARG;
+}
+
+static size_t size_of_RSA(EVP_PKEY *pkey) {
+ int ret = 0;
+ RSA *rsa = NULL;
+
+ if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL)
+ goto err;
+ ret = RSA_size(rsa);
+
+ err:
+ if (rsa)
+ RSA_free(rsa);
+
+ return (ret < 0) ? 0 : (size_t)ret;
+}
+
+ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
+{/* (Algorithm, Data, PublKey=[E,N]|[E,N,D]|[E,N,D,P1,P2,E1,E2,C], Options, IsPrivate, IsEncrypt) */
+ ERL_NIF_TERM ret;
+ int i;
+ int result = 0;
+ int tmp_bin_alloc = 0;
+ int out_bin_alloc = 0;
+ EVP_PKEY *pkey = NULL;
+#ifdef HAS_EVP_PKEY_CTX
+ EVP_PKEY_CTX *ctx = NULL;
+#else
+ int len;
+ RSA *rsa = NULL;
+#endif
+ PKeyCryptOptions crypt_opt;
+ ErlNifBinary in_bin, out_bin, tmp_bin;
+ size_t outlen;
+#ifdef HAVE_RSA_SSLV23_PADDING
+ size_t tmplen;
+#endif
+ int is_private, is_encrypt;
+ int algo_init = 0;
+ unsigned char *label_copy = NULL;
+
+ ASSERT(argc == 6);
+
+ is_private = (argv[4] == atom_true);
+ is_encrypt = (argv[5] == atom_true);
+
+/* char algo[1024]; */
+
+#ifndef HAS_ENGINE_SUPPORT
+ if (enif_is_map(env, argv[2]))
+ return atom_notsup;
+#endif
+
+ if (!enif_inspect_binary(env, argv[1], &in_bin))
+ goto bad_arg;
+
+ i = get_pkey_crypt_options(env, argv[0], argv[3], &crypt_opt);
+ switch (i) {
+ case PKEY_OK:
+ break;
+ case PKEY_NOTSUP:
+ goto notsup;
+ default:
+ goto bad_arg;
+ }
+
+ if (is_private) {
+ if (get_pkey_private_key(env, argv[0], argv[2], &pkey) != PKEY_OK)
+ goto bad_arg;
+ } else {
+ if (get_pkey_public_key(env, argv[0], argv[2], &pkey) != PKEY_OK)
+ goto bad_arg;
+ }
+
+#ifdef HAS_EVP_PKEY_CTX
+ if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL)
+ goto err;
+
+/* enif_get_atom(env,argv[0],algo,1024,ERL_NIF_LATIN1); */
+
+ if (is_private) {
+ if (is_encrypt) {
+ /* private encrypt */
+ if ((algo_init = EVP_PKEY_sign_init(ctx)) != 1)
+ goto bad_arg;
+ } else {
+ /* private decrypt */
+ if ((algo_init = EVP_PKEY_decrypt_init(ctx)) != 1)
+ goto bad_arg;
+ }
+ } else {
+ if (is_encrypt) {
+ /* public encrypt */
+ if ((algo_init = EVP_PKEY_encrypt_init(ctx)) != 1)
+ goto bad_arg;
+ } else {
+ /* public decrypt */
+ if ((algo_init = EVP_PKEY_verify_recover_init(ctx)) != 1)
+ goto bad_arg;
+ }
+ }
+
+ if (argv[0] == atom_rsa) {
+ if (crypt_opt.signature_md != NULL) {
+ if (EVP_PKEY_CTX_set_signature_md(ctx, crypt_opt.signature_md) != 1)
+ goto bad_arg;
+ }
+
+#ifdef HAVE_RSA_SSLV23_PADDING
+ if (crypt_opt.rsa_padding == RSA_SSLV23_PADDING) {
+ if (is_encrypt) {
+ tmplen = size_of_RSA(pkey);
+ if (tmplen < 1 || tmplen > INT_MAX)
+ goto err;
+ if (!enif_alloc_binary(tmplen, &tmp_bin))
+ goto err;
+ tmp_bin_alloc = 1;
+ if (in_bin.size > INT_MAX)
+ goto err;
+ if (!RSA_padding_add_SSLv23(tmp_bin.data, (int)tmplen, in_bin.data, (int)in_bin.size))
+ goto err;
+ in_bin = tmp_bin;
+ }
+ if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING) != 1)
+ goto err;
+ } else
+#endif
+ {
+ if (EVP_PKEY_CTX_set_rsa_padding(ctx, crypt_opt.rsa_padding) != 1)
+ goto err;
+ }
+
+#ifdef HAVE_RSA_OAEP_MD
+ if (crypt_opt.rsa_padding == RSA_PKCS1_OAEP_PADDING) {
+ if (crypt_opt.rsa_oaep_md != NULL) {
+ if (EVP_PKEY_CTX_set_rsa_oaep_md(ctx, crypt_opt.rsa_oaep_md) != 1)
+ goto err;
+ }
+
+ if (crypt_opt.rsa_mgf1_md != NULL) {
+ if (EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, crypt_opt.rsa_mgf1_md) != 1)
+ goto err;
+ }
+
+ if (crypt_opt.rsa_oaep_label.data != NULL && crypt_opt.rsa_oaep_label.size > 0) {
+ if (crypt_opt.rsa_oaep_label.size > INT_MAX)
+ goto err;
+ if ((label_copy = OPENSSL_malloc(crypt_opt.rsa_oaep_label.size)) == NULL)
+ goto err;
+
+ memcpy((void *)(label_copy), (const void *)(crypt_opt.rsa_oaep_label.data),
+ crypt_opt.rsa_oaep_label.size);
+
+ if (EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, label_copy,
+ (int)crypt_opt.rsa_oaep_label.size) != 1)
+ goto err;
+ /* On success, label_copy is owned by ctx */
+ label_copy = NULL;
+ }
+ }
+#endif
+ }
+
+ if (is_private) {
+ if (is_encrypt) {
+ /* private_encrypt */
+ result = EVP_PKEY_sign(ctx, NULL, &outlen, in_bin.data, in_bin.size);
+ } else {
+ /* private_decrypt */
+ result = EVP_PKEY_decrypt(ctx, NULL, &outlen, in_bin.data, in_bin.size);
+ }
+ } else {
+ if (is_encrypt) {
+ /* public_encrypt */
+ result = EVP_PKEY_encrypt(ctx, NULL, &outlen, in_bin.data, in_bin.size);
+ } else {
+ /* public_decrypt */
+ result = EVP_PKEY_verify_recover(ctx, NULL, &outlen, in_bin.data, in_bin.size);
+ }
+ }
+ /* fprintf(stderr,"i = %d %s:%d\r\n", i, __FILE__, __LINE__); */
+
+ if (result != 1)
+ goto err;
+
+ if (!enif_alloc_binary(outlen, &out_bin))
+ goto err;
+ out_bin_alloc = 1;
+
+ if (is_private) {
+ if (is_encrypt) {
+ /* private_encrypt */
+ result = EVP_PKEY_sign(ctx, out_bin.data, &outlen, in_bin.data, in_bin.size);
+ } else {
+ /* private_decrypt */
+ result = EVP_PKEY_decrypt(ctx, out_bin.data, &outlen, in_bin.data, in_bin.size);
+ }
+ } else {
+ if (is_encrypt) {
+ /* public_encrypt */
+ result = EVP_PKEY_encrypt(ctx, out_bin.data, &outlen, in_bin.data, in_bin.size);
+ } else {
+ /* public_decrypt */
+ result = EVP_PKEY_verify_recover(ctx, out_bin.data, &outlen, in_bin.data, in_bin.size);
+ }
+ }
+
+#else
+ /* Non-EVP cryptolib. Only support RSA */
+
+ if (argv[0] != atom_rsa) {
+ algo_init = -2; /* exitcode: notsup */
+ goto bad_arg;
+ }
+
+ if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL)
+ goto err;
+ if ((len = RSA_size(rsa)) < 0)
+ goto err;
+ if (!enif_alloc_binary((size_t)len, &out_bin))
+ goto err;
+ out_bin_alloc = 1;
+
+ if (in_bin.size > INT_MAX)
+ goto err;
+ if (is_private) {
+ if (is_encrypt) {
+ /* non-evp rsa private encrypt */
+ ERL_VALGRIND_ASSERT_MEM_DEFINED(in_bin.data,in_bin.size);
+ result = RSA_private_encrypt((int)in_bin.size, in_bin.data,
+ out_bin.data, rsa, crypt_opt.rsa_padding);
+ if (result > 0) {
+ ERL_VALGRIND_MAKE_MEM_DEFINED(out_bin.data, result);
+ }
+ } else {
+ /* non-evp rsa private decrypt */
+ result = RSA_private_decrypt((int)in_bin.size, in_bin.data,
+ out_bin.data, rsa, crypt_opt.rsa_padding);
+ if (result > 0) {
+ ERL_VALGRIND_MAKE_MEM_DEFINED(out_bin.data, result);
+ if (!enif_realloc_binary(&out_bin, (size_t)result))
+ goto err;
+ }
+ }
+ } else {
+ if (is_encrypt) {
+ /* non-evp rsa public encrypt */
+ ERL_VALGRIND_ASSERT_MEM_DEFINED(in_bin.data,in_bin.size);
+ result = RSA_public_encrypt((int)in_bin.size, in_bin.data,
+ out_bin.data, rsa, crypt_opt.rsa_padding);
+ if (result > 0) {
+ ERL_VALGRIND_MAKE_MEM_DEFINED(out_bin.data, result);
+ }
+ } else {
+ /* non-evp rsa public decrypt */
+ result = RSA_public_decrypt((int)in_bin.size, in_bin.data,
+ out_bin.data, rsa, crypt_opt.rsa_padding);
+ if (result > 0) {
+ ERL_VALGRIND_MAKE_MEM_DEFINED(out_bin.data, result);
+ if (!enif_realloc_binary(&out_bin, (size_t)result))
+ goto err;
+ }
+ }
+ }
+
+ outlen = (size_t)result;
+#endif
+
+ if ((result > 0) && argv[0] == atom_rsa && !is_encrypt) {
+#ifdef HAVE_RSA_SSLV23_PADDING
+ if (crypt_opt.rsa_padding == RSA_SSLV23_PADDING) {
+ unsigned char *p;
+
+ tmplen = size_of_RSA(pkey);
+ if (tmplen < 1 || tmplen > INT_MAX)
+ goto err;
+ if (!enif_alloc_binary(tmplen, &tmp_bin))
+ goto err;
+ tmp_bin_alloc = 1;
+ if (out_bin.size > INT_MAX)
+ goto err;
+
+ p = out_bin.data;
+ p++;
+
+ result = RSA_padding_check_SSLv23(tmp_bin.data, (int)tmplen, p, (int)out_bin.size - 1, (int)tmplen);
+ if (result >= 0) {
+ outlen = (size_t)result;
+ in_bin = out_bin;
+ out_bin = tmp_bin;
+ tmp_bin = in_bin;
+ result = 1;
+ }
+ }
+#endif
+ }
+
+ if (result > 0) {
+ ERL_VALGRIND_MAKE_MEM_DEFINED(out_bin.data, outlen);
+ if (outlen != out_bin.size) {
+ if (!enif_realloc_binary(&out_bin, outlen))
+ goto err;
+ ERL_VALGRIND_ASSERT_MEM_DEFINED(out_bin.data, outlen);
+ }
+ ret = enif_make_binary(env, &out_bin);
+ out_bin_alloc = 0;
+ } else {
+ ret = atom_error;
+ }
+ goto done;
+
+ notsup:
+ ret = atom_notsup;
+ goto done;
+
+ bad_arg:
+ err:
+ if (algo_init == -2)
+ ret = atom_notsup;
+ else
+ ret = enif_make_badarg(env);
+
+ done:
+ if (out_bin_alloc)
+ enif_release_binary(&out_bin);
+ if (tmp_bin_alloc)
+ enif_release_binary(&tmp_bin);
+
+#ifdef HAS_EVP_PKEY_CTX
+ if (ctx)
+ EVP_PKEY_CTX_free(ctx);
+#else
+ if (rsa)
+ RSA_free(rsa);
+#endif
+ if (pkey)
+ EVP_PKEY_free(pkey);
+
+ if (label_copy)
+ OPENSSL_free(label_copy);
+
+ return ret;
+}
+
+ERL_NIF_TERM privkey_to_pubkey_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{ /* (Algorithm, PrivKey | KeyMap) */
+ ERL_NIF_TERM ret;
+ EVP_PKEY *pkey = NULL;
+ RSA *rsa = NULL;
+#ifdef HAVE_DSA
+ DSA *dsa = NULL;
+#endif
+ ERL_NIF_TERM result[8];
+
+ ASSERT(argc == 2);
+
+ if (get_pkey_private_key(env, argv[0], argv[1], &pkey) != PKEY_OK)
+ goto bad_arg;
+
+ if (argv[0] == atom_rsa) {
+ const BIGNUM *n = NULL, *e = NULL, *d = NULL;
+
+ if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL)
+ goto err;
+
+ RSA_get0_key(rsa, &n, &e, &d);
+
+ // Exponent E
+ if ((result[0] = bin_from_bn(env, e)) == atom_error)
+ goto err;
+ // Modulus N = p*q
+ if ((result[1] = bin_from_bn(env, n)) == atom_error)
+ goto err;
+
+ ret = enif_make_list_from_array(env, result, 2);
+
+#ifdef HAVE_DSA
+ } else if (argv[0] == atom_dss) {
+ const BIGNUM *p = NULL, *q = NULL, *g = NULL, *pub_key = NULL;
+
+ if ((dsa = EVP_PKEY_get1_DSA(pkey)) == NULL)
+ goto err;
+
+ DSA_get0_pqg(dsa, &p, &q, &g);
+ DSA_get0_key(dsa, &pub_key, NULL);
+
+ if ((result[0] = bin_from_bn(env, p)) == atom_error)
+ goto err;
+ if ((result[1] = bin_from_bn(env, q)) == atom_error)
+ goto err;
+ if ((result[2] = bin_from_bn(env, g)) == atom_error)
+ goto err;
+ if ((result[3] = bin_from_bn(env, pub_key)) == atom_error)
+ goto err;
+
+ ret = enif_make_list_from_array(env, result, 4);
+#endif
+ } else if (argv[0] == atom_ecdsa) {
+#if defined(HAVE_EC)
+ /* not yet implemented
+ EC_KEY *ec = EVP_PKEY_get1_EC_KEY(pkey);
+ if (ec) {
+ / * Example of result:
+ {
+ Curve = {Field, Prime, Point, Order, CoFactor} =
+ {
+ Field = {prime_field,<<255,...,255>>},
+ Prime = {<<255,...,252>>,
+ <<90,...,75>>,
+ <<196,...,144>>
+ },
+ Point = <<4,...,245>>,
+ Order = <<255,...,81>>,
+ CoFactor = <<1>>
+ },
+ Key = <<151,...,62>>
+ }
+ or
+ {
+ Curve =
+ {characteristic_two_field,
+ M,
+ Basis = {tpbasis, _}
+ | {ppbasis, k1, k2, k3}
+ },
+ Key
+ }
+ * /
+ EVP_PKEY_free(pkey);
+ return enif_make_list_from_array(env, ..., ...);
+ */
+#endif
+ goto bad_arg;
+ } else {
+ goto bad_arg;
+ }
+
+ goto done;
+
+ bad_arg:
+ err:
+ ret = enif_make_badarg(env);
+
+ done:
+ if (rsa)
+ RSA_free(rsa);
+#ifdef HAVE_DSA
+ if (dsa)
+ DSA_free(dsa);
+#endif
+ if (pkey)
+ EVP_PKEY_free(pkey);
+
+ return ret;
+}
diff --git a/lib/crypto/c_src/pkey.h b/lib/crypto/c_src/pkey.h
new file mode 100644
index 0000000000..f647a4a160
--- /dev/null
+++ b/lib/crypto/c_src/pkey.h
@@ -0,0 +1,31 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_PKEY_H__
+#define E_PKEY_H__ 1
+
+#include "common.h"
+
+ERL_NIF_TERM pkey_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM pkey_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM privkey_to_pubkey_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+#endif /* E_PKEY_H__ */
diff --git a/lib/crypto/c_src/poly1305.c b/lib/crypto/c_src/poly1305.c
new file mode 100644
index 0000000000..76579c0a29
--- /dev/null
+++ b/lib/crypto/c_src/poly1305.c
@@ -0,0 +1,90 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "poly1305.h"
+
+/* For OpenSSL >= 1.1.1 the hmac_nif and cmac_nif could be integrated into poly1305 (with 'type' as parameter) */
+ERL_NIF_TERM poly1305_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key, Text) */
+#ifdef HAVE_POLY1305
+ ErlNifBinary key_bin, text, ret_bin;
+ ERL_NIF_TERM ret;
+ EVP_PKEY *key = NULL;
+ EVP_MD_CTX *mctx = NULL;
+ EVP_PKEY_CTX *pctx = NULL;
+ const EVP_MD *md = NULL;
+ size_t size;
+ int ret_bin_alloc = 0;
+
+ ASSERT(argc == 2);
+
+ if (!enif_inspect_binary(env, argv[0], &key_bin))
+ goto bad_arg;
+ if (key_bin.size != 32)
+ goto bad_arg;
+ if (!enif_inspect_binary(env, argv[1], &text))
+ goto bad_arg;
+
+ if ((key = EVP_PKEY_new_raw_private_key(EVP_PKEY_POLY1305, /*engine*/ NULL, key_bin.data, key_bin.size)) == NULL)
+ goto err;
+
+ if ((mctx = EVP_MD_CTX_new()) == NULL)
+ goto err;
+ if (EVP_DigestSignInit(mctx, &pctx, md, /*engine*/ NULL, key) != 1)
+ goto err;
+ if (EVP_DigestSignUpdate(mctx, text.data, text.size) != 1)
+ goto err;
+
+ if (EVP_DigestSignFinal(mctx, NULL, &size) != 1)
+ goto err;
+ if (!enif_alloc_binary(size, &ret_bin))
+ goto err;
+ ret_bin_alloc = 1;
+ if (EVP_DigestSignFinal(mctx, ret_bin.data, &size) != 1)
+ goto err;
+
+ if (size != ret_bin.size) {
+ if (!enif_realloc_binary(&ret_bin, size))
+ goto err;
+ }
+
+ ret = enif_make_binary(env, &ret_bin);
+ ret_bin_alloc = 0;
+ goto done;
+
+ bad_arg:
+ return enif_make_badarg(env);
+
+ err:
+ if (ret_bin_alloc)
+ enif_release_binary(&ret_bin);
+ ret = atom_error;
+
+ done:
+ if (mctx)
+ EVP_MD_CTX_free(mctx);
+ if (key)
+ EVP_PKEY_free(key);
+ return ret;
+
+#else
+ return enif_raise_exception(env, atom_notsup);
+#endif
+}
diff --git a/lib/crypto/c_src/poly1305.h b/lib/crypto/c_src/poly1305.h
new file mode 100644
index 0000000000..4bf45e6218
--- /dev/null
+++ b/lib/crypto/c_src/poly1305.h
@@ -0,0 +1,28 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_POLY1305_H__
+#define E_POLY1305_H__ 1
+
+#include "common.h"
+
+ERL_NIF_TERM poly1305_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+#endif /* E_POLY1305_H__ */
diff --git a/lib/crypto/c_src/rand.c b/lib/crypto/c_src/rand.c
new file mode 100644
index 0000000000..3812ae0991
--- /dev/null
+++ b/lib/crypto/c_src/rand.c
@@ -0,0 +1,149 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "rand.h"
+#include "bn.h"
+
+ERL_NIF_TERM strong_rand_bytes_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Bytes) */
+ unsigned bytes;
+ unsigned char* data;
+ ERL_NIF_TERM ret;
+
+ ASSERT(argc == 1);
+
+ if (!enif_get_uint(env, argv[0], &bytes))
+ goto bad_arg;
+ if (bytes > INT_MAX)
+ goto bad_arg;
+
+ if ((data = enif_make_new_binary(env, bytes, &ret)) == NULL)
+ goto err;
+ if (RAND_bytes(data, (int)bytes) != 1)
+ goto err;
+
+ ERL_VALGRIND_MAKE_MEM_DEFINED(data, bytes);
+ return ret;
+
+ bad_arg:
+ return enif_make_badarg(env);
+
+ err:
+ return atom_false;
+}
+
+ERL_NIF_TERM strong_rand_range_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Range) */
+ BIGNUM *bn_range = NULL, *bn_rand = NULL;
+ ERL_NIF_TERM ret;
+
+ ASSERT(argc == 1);
+
+ if (!get_bn_from_bin(env, argv[0], &bn_range))
+ goto bad_arg;
+
+ if ((bn_rand = BN_new()) == NULL)
+ goto err;
+ if (!BN_rand_range(bn_rand, bn_range))
+ goto err;
+
+ if ((ret = bin_from_bn(env, bn_rand)) == atom_error)
+ goto err;
+ goto done;
+
+ bad_arg:
+ return enif_make_badarg(env);
+
+ err:
+ ret = atom_false;
+
+ done:
+ if (bn_rand)
+ BN_free(bn_rand);
+ if (bn_range)
+ BN_free(bn_range);
+ return ret;
+}
+
+ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Lo,Hi) */
+ BIGNUM *bn_from = NULL, *bn_to = NULL, *bn_rand = NULL;
+ unsigned char* data;
+ int dlen;
+ ERL_NIF_TERM ret;
+
+ ASSERT(argc == 2);
+
+ if (!get_bn_from_mpint(env, argv[0], &bn_from))
+ goto bad_arg;
+ if (!get_bn_from_mpint(env, argv[1], &bn_rand))
+ goto bad_arg;
+
+ if ((bn_to = BN_new()) == NULL)
+ goto err;
+
+ if (!BN_sub(bn_to, bn_rand, bn_from))
+ goto err;
+ if (!BN_pseudo_rand_range(bn_rand, bn_to))
+ goto err;
+ if (!BN_add(bn_rand, bn_rand, bn_from))
+ goto err;
+
+ if ((dlen = BN_num_bytes(bn_rand)) < 0)
+ goto err;
+ if ((data = enif_make_new_binary(env, (size_t)dlen+4, &ret)) == NULL)
+ goto err;
+
+ put_uint32(data, (unsigned int)dlen);
+ BN_bn2bin(bn_rand, data+4);
+ ERL_VALGRIND_MAKE_MEM_DEFINED(data+4, dlen);
+ goto done;
+
+ bad_arg:
+ err:
+ ret = enif_make_badarg(env);
+
+ done:
+ if (bn_rand)
+ BN_free(bn_rand);
+ if (bn_from)
+ BN_free(bn_from);
+ if (bn_to)
+ BN_free(bn_to);
+ return ret;
+}
+
+ERL_NIF_TERM rand_seed_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Seed) */
+ ErlNifBinary seed_bin;
+
+ ASSERT(argc == 1);
+
+ if (!enif_inspect_binary(env, argv[0], &seed_bin))
+ goto bad_arg;
+ if (seed_bin.size > INT_MAX)
+ goto bad_arg;
+
+ RAND_seed(seed_bin.data, (int)seed_bin.size);
+ return atom_ok;
+
+ bad_arg:
+ return enif_make_badarg(env);
+}
diff --git a/lib/crypto/c_src/rand.h b/lib/crypto/c_src/rand.h
new file mode 100644
index 0000000000..9c23d343ec
--- /dev/null
+++ b/lib/crypto/c_src/rand.h
@@ -0,0 +1,31 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_RAND_H__
+#define E_RAND_H__ 1
+
+#include "common.h"
+
+ERL_NIF_TERM strong_rand_bytes_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM strong_rand_range_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM rand_seed_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+#endif /* E_RAND_H__ */
diff --git a/lib/crypto/c_src/rsa.c b/lib/crypto/c_src/rsa.c
new file mode 100644
index 0000000000..e9f29aa496
--- /dev/null
+++ b/lib/crypto/c_src/rsa.c
@@ -0,0 +1,282 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "rsa.h"
+#include "bn.h"
+
+static ERL_NIF_TERM rsa_generate_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM put_rsa_private_key(ErlNifEnv* env, const RSA *rsa);
+static int check_erlang_interrupt(int maj, int min, BN_GENCB *ctxt);
+
+int get_rsa_private_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa)
+{
+ /* key=[E,N,D]|[E,N,D,P1,P2,E1,E2,C] */
+ ERL_NIF_TERM head, tail;
+ BIGNUM *e = NULL, *n = NULL, *d = NULL;
+ BIGNUM *p = NULL, *q = NULL;
+ BIGNUM *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL;
+
+ if (!enif_get_list_cell(env, key, &head, &tail))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, head, &e))
+ goto bad_arg;
+ if (!enif_get_list_cell(env, tail, &head, &tail))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, head, &n))
+ goto bad_arg;
+ if (!enif_get_list_cell(env, tail, &head, &tail))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, head, &d))
+ goto bad_arg;
+
+ if (!RSA_set0_key(rsa, n, e, d))
+ goto err;
+ /* rsa now owns n, e, and d */
+ n = NULL;
+ e = NULL;
+ d = NULL;
+
+ if (enif_is_empty_list(env, tail))
+ return 1;
+
+ if (!enif_get_list_cell(env, tail, &head, &tail))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, head, &p))
+ goto bad_arg;
+ if (!enif_get_list_cell(env, tail, &head, &tail))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, head, &q))
+ goto bad_arg;
+ if (!enif_get_list_cell(env, tail, &head, &tail))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, head, &dmp1))
+ goto bad_arg;
+ if (!enif_get_list_cell(env, tail, &head, &tail))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, head, &dmq1))
+ goto bad_arg;
+ if (!enif_get_list_cell(env, tail, &head, &tail))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, head, &iqmp))
+ goto bad_arg;
+ if (!enif_is_empty_list(env, tail))
+ goto bad_arg;
+
+ if (!RSA_set0_factors(rsa, p, q))
+ goto err;
+ /* rsa now owns p and q */
+ p = NULL;
+ q = NULL;
+
+ if (!RSA_set0_crt_params(rsa, dmp1, dmq1, iqmp))
+ goto err;
+ /* rsa now owns dmp1, dmq1, and iqmp */
+ dmp1 = NULL;
+ dmq1 = NULL;
+ iqmp = NULL;
+
+ return 1;
+
+ bad_arg:
+ err:
+ if (e)
+ BN_free(e);
+ if (n)
+ BN_free(n);
+ if (d)
+ BN_free(d);
+ if (p)
+ BN_free(p);
+ if (q)
+ BN_free(q);
+ if (dmp1)
+ BN_free(dmp1);
+ if (dmq1)
+ BN_free(dmq1);
+ if (iqmp)
+ BN_free(iqmp);
+
+ return 0;
+}
+
+int get_rsa_public_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa)
+{
+ /* key=[E,N] */
+ ERL_NIF_TERM head, tail;
+ BIGNUM *e = NULL, *n = NULL;
+
+ if (!enif_get_list_cell(env, key, &head, &tail))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, head, &e))
+ goto bad_arg;
+ if (!enif_get_list_cell(env, tail, &head, &tail))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, head, &n))
+ goto bad_arg;
+ if (!enif_is_empty_list(env, tail))
+ goto bad_arg;
+
+ if (!RSA_set0_key(rsa, n, e, NULL))
+ goto err;
+ /* rsa now owns n and e */
+ n = NULL;
+ e = NULL;
+
+ return 1;
+
+ bad_arg:
+ err:
+ if (e)
+ BN_free(e);
+ if (n)
+ BN_free(n);
+
+ return 0;
+}
+
+/* Creates a term which can be parsed by get_rsa_private_key(). This is a list of plain integer binaries (not mpints). */
+static ERL_NIF_TERM put_rsa_private_key(ErlNifEnv* env, const RSA *rsa)
+{
+ ERL_NIF_TERM result[8];
+ const BIGNUM *n = NULL, *e = NULL, *d = NULL, *p = NULL, *q = NULL, *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL;
+
+ /* Return at least [E,N,D] */
+ RSA_get0_key(rsa, &n, &e, &d);
+
+ if ((result[0] = bin_from_bn(env, e)) == atom_error) // Exponent E
+ goto err;
+ if ((result[1] = bin_from_bn(env, n)) == atom_error) // Modulus N = p*q
+ goto err;
+ if ((result[2] = bin_from_bn(env, d)) == atom_error) // Exponent D
+ goto err;
+
+ /* Check whether the optional additional parameters are available */
+ RSA_get0_factors(rsa, &p, &q);
+ RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
+
+ if (p && q && dmp1 && dmq1 && iqmp) {
+ if ((result[3] = bin_from_bn(env, p)) == atom_error) // Factor p
+ goto err;
+ if ((result[4] = bin_from_bn(env, q)) == atom_error) // Factor q
+ goto err;
+ if ((result[5] = bin_from_bn(env, dmp1)) == atom_error) // D mod (p-1)
+ goto err;
+ if ((result[6] = bin_from_bn(env, dmq1)) == atom_error) // D mod (q-1)
+ goto err;
+ if ((result[7] = bin_from_bn(env, iqmp)) == atom_error) // (1/q) mod p
+ goto err;
+
+ return enif_make_list_from_array(env, result, 8);
+ } else {
+ return enif_make_list_from_array(env, result, 3);
+ }
+
+ err:
+ return enif_make_badarg(env);
+}
+
+static int check_erlang_interrupt(int maj, int min, BN_GENCB *ctxt)
+{
+ ErlNifEnv *env = BN_GENCB_get_arg(ctxt);
+
+ if (!enif_is_current_process_alive(env)) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+static ERL_NIF_TERM rsa_generate_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (ModulusSize, PublicExponent) */
+ ERL_NIF_TERM ret;
+ int modulus_bits;
+ BIGNUM *pub_exp = NULL, *three = NULL;
+ RSA *rsa = NULL;
+ BN_GENCB *intr_cb = NULL;
+#ifndef HAVE_OPAQUE_BN_GENCB
+ BN_GENCB intr_cb_buf;
+#endif
+
+ ASSERT(argc == 2);
+
+ if (!enif_get_int(env, argv[0], &modulus_bits))
+ goto bad_arg;
+ if (modulus_bits < 256)
+ goto bad_arg;
+ if (!get_bn_from_bin(env, argv[1], &pub_exp))
+ goto bad_arg;
+
+ /* Make sure the public exponent is large enough (at least 3).
+ * Without this, RSA_generate_key_ex() can run forever. */
+ if ((three = BN_new()) == NULL)
+ goto err;
+ if (!BN_set_word(three, 3))
+ goto err;
+ if (BN_cmp(pub_exp, three) < 0)
+ goto err;
+
+ /* For large keys, prime generation can take many seconds. Set up
+ * the callback which we use to test whether the process has been
+ * interrupted. */
+#ifdef HAVE_OPAQUE_BN_GENCB
+ if ((intr_cb = BN_GENCB_new()) == NULL)
+ goto err;
+#else
+ intr_cb = &intr_cb_buf;
+#endif
+ BN_GENCB_set(intr_cb, check_erlang_interrupt, env);
+
+ if ((rsa = RSA_new()) == NULL)
+ goto err;
+
+ if (!RSA_generate_key_ex(rsa, modulus_bits, pub_exp, intr_cb))
+ goto err;
+
+ ret = put_rsa_private_key(env, rsa);
+ goto done;
+
+ bad_arg:
+ return enif_make_badarg(env);
+
+ err:
+ ret = atom_error;
+
+ done:
+ if (pub_exp)
+ BN_free(pub_exp);
+ if (three)
+ BN_free(three);
+#ifdef HAVE_OPAQUE_BN_GENCB
+ if (intr_cb)
+ BN_GENCB_free(intr_cb);
+#endif
+ if (rsa)
+ RSA_free(rsa);
+ return ret;
+}
+
+ERL_NIF_TERM rsa_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ /* RSA key generation can take a long time (>1 sec for a large
+ * modulus), so schedule it as a CPU-bound operation. */
+ return enif_schedule_nif(env, "rsa_generate_key",
+ ERL_NIF_DIRTY_JOB_CPU_BOUND,
+ rsa_generate_key, argc, argv);
+}
diff --git a/lib/crypto/c_src/rsa.h b/lib/crypto/c_src/rsa.h
new file mode 100644
index 0000000000..69c02aa2cb
--- /dev/null
+++ b/lib/crypto/c_src/rsa.h
@@ -0,0 +1,31 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_RSA_H__
+#define E_RSA_H__ 1
+
+#include "common.h"
+
+int get_rsa_public_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa);
+int get_rsa_private_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa);
+
+ERL_NIF_TERM rsa_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+#endif /* E_RSA_H__ */
diff --git a/lib/crypto/c_src/srp.c b/lib/crypto/c_src/srp.c
new file mode 100644
index 0000000000..2979048006
--- /dev/null
+++ b/lib/crypto/c_src/srp.c
@@ -0,0 +1,307 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "srp.h"
+#include "bn.h"
+
+ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Multiplier, Verifier, Generator, Exponent, Prime) */
+ BIGNUM *bn_verifier = NULL;
+ BIGNUM *bn_exponent = NULL, *bn_generator = NULL, *bn_prime = NULL, *bn_multiplier = NULL, *bn_result = NULL;
+ BN_CTX *bn_ctx = NULL;
+ unsigned char* ptr;
+ int dlen;
+ ERL_NIF_TERM ret;
+
+ CHECK_NO_FIPS_MODE();
+
+ ASSERT(argc == 5);
+
+ if (!get_bn_from_bin(env, argv[0], &bn_multiplier))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, argv[1], &bn_verifier))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, argv[2], &bn_generator))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, argv[3], &bn_exponent))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, argv[4], &bn_prime))
+ goto bad_arg;
+
+ if ((bn_result = BN_new()) == NULL)
+ goto err;
+ if ((bn_ctx = BN_CTX_new()) == NULL)
+ goto err;
+
+ /* B = k*v + g^b % N */
+
+ /* k * v */
+ if (!BN_mod_mul(bn_multiplier, bn_multiplier, bn_verifier, bn_prime, bn_ctx))
+ goto err;
+
+ /* g^b % N */
+ if (!BN_mod_exp(bn_result, bn_generator, bn_exponent, bn_prime, bn_ctx))
+ goto err;
+
+ /* k*v + g^b % N */
+ if (!BN_mod_add(bn_result, bn_result, bn_multiplier, bn_prime, bn_ctx))
+ goto err;
+
+ /* check that B % N != 0, reuse bn_multiplier */
+ if (!BN_nnmod(bn_multiplier, bn_result, bn_prime, bn_ctx))
+ goto err;
+
+ if (BN_is_zero(bn_multiplier))
+ goto err;
+
+ if ((dlen = BN_num_bytes(bn_result)) < 0)
+ goto err;
+ if ((ptr = enif_make_new_binary(env, (size_t)dlen, &ret)) == NULL)
+ goto err;
+
+ if (BN_bn2bin(bn_result, ptr) < 0)
+ goto err;
+
+ goto done;
+
+ bad_arg:
+ ret = enif_make_badarg(env);
+ goto done;
+
+ err:
+ ret = atom_error;
+
+ done:
+ if (bn_multiplier)
+ BN_free(bn_multiplier);
+ if (bn_verifier)
+ BN_free(bn_verifier);
+ if (bn_generator)
+ BN_free(bn_generator);
+ if (bn_exponent)
+ BN_free(bn_exponent);
+ if (bn_prime)
+ BN_free(bn_prime);
+ if (bn_result)
+ BN_free(bn_result);
+ if (bn_ctx)
+ BN_CTX_free(bn_ctx);
+
+ return ret;
+}
+
+ERL_NIF_TERM srp_user_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (a, u, B, Multiplier, Prime, Exponent, Generator) */
+/*
+ <premaster secret> = (B - (k * g^x)) ^ (a + (u * x)) % N
+*/
+ BIGNUM *bn_exponent = NULL, *bn_a = NULL;
+ BIGNUM *bn_u = NULL, *bn_multiplier = NULL, *bn_exp2 = NULL;
+ BIGNUM *bn_base = NULL, *bn_prime = NULL, *bn_generator = NULL;
+ BIGNUM *bn_B = NULL, *bn_result = NULL;
+ BN_CTX *bn_ctx = NULL;
+ unsigned char *ptr;
+ int dlen;
+ ERL_NIF_TERM ret;
+
+ CHECK_NO_FIPS_MODE();
+
+ ASSERT(argc == 7);
+
+ if (!get_bn_from_bin(env, argv[0], &bn_a))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, argv[1], &bn_u))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, argv[2], &bn_B))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, argv[3], &bn_multiplier))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, argv[4], &bn_generator))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, argv[5], &bn_exponent))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, argv[6], &bn_prime))
+ goto bad_arg;
+
+ if ((bn_ctx = BN_CTX_new()) == NULL)
+ goto err;
+ if ((bn_result = BN_new()) == NULL)
+ goto err;
+
+ /* check that B % N != 0 */
+ if (!BN_nnmod(bn_result, bn_B, bn_prime, bn_ctx))
+ goto err;
+ if (BN_is_zero(bn_result))
+ goto err;
+
+ /* (B - (k * g^x)) */
+ if ((bn_base = BN_new()) == NULL)
+ goto err;
+ if (!BN_mod_exp(bn_result, bn_generator, bn_exponent, bn_prime, bn_ctx))
+ goto err;
+ if (!BN_mod_mul(bn_result, bn_multiplier, bn_result, bn_prime, bn_ctx))
+ goto err;
+ if (!BN_mod_sub(bn_base, bn_B, bn_result, bn_prime, bn_ctx))
+ goto err;
+
+ /* a + (u * x) */
+ if ((bn_exp2 = BN_new()) == NULL)
+ goto err;
+ if (!BN_mul(bn_result, bn_u, bn_exponent, bn_ctx))
+ goto err;
+ if (!BN_add(bn_exp2, bn_a, bn_result))
+ goto err;
+
+ /* (B - (k * g^x)) ^ (a + (u * x)) % N */
+ if (!BN_mod_exp(bn_result, bn_base, bn_exp2, bn_prime, bn_ctx))
+ goto err;
+
+ if ((dlen = BN_num_bytes(bn_result)) < 0)
+ goto err;
+ if ((ptr = enif_make_new_binary(env, (size_t)dlen, &ret)) == NULL)
+ goto err;
+
+ if (BN_bn2bin(bn_result, ptr) < 0)
+ goto err;
+
+ goto done;
+
+ bad_arg:
+ ret = enif_make_badarg(env);
+ goto done;
+
+ err:
+ ret = atom_error;
+
+ done:
+ if (bn_a)
+ BN_free(bn_a);
+ if (bn_u)
+ BN_free(bn_u);
+ if (bn_B)
+ BN_free(bn_B);
+ if (bn_multiplier)
+ BN_free(bn_multiplier);
+ if (bn_generator)
+ BN_free(bn_generator);
+ if (bn_exponent)
+ BN_free(bn_exponent);
+ if (bn_prime)
+ BN_free(bn_prime);
+ if (bn_ctx)
+ BN_CTX_free(bn_ctx);
+ if (bn_result)
+ BN_free(bn_result);
+ if (bn_base)
+ BN_free(bn_base);
+ if (bn_exp2)
+ BN_free(bn_exp2);
+
+ return ret;
+}
+
+ERL_NIF_TERM srp_host_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Verifier, b, u, A, Prime) */
+/*
+ <premaster secret> = (A * v^u) ^ b % N
+*/
+ BIGNUM *bn_b = NULL, *bn_verifier = NULL;
+ BIGNUM *bn_prime = NULL, *bn_A = NULL, *bn_u = NULL, *bn_base = NULL, *bn_result = NULL;
+ BN_CTX *bn_ctx = NULL;
+ unsigned char *ptr;
+ int dlen;
+ ERL_NIF_TERM ret;
+
+ CHECK_NO_FIPS_MODE();
+
+ ASSERT(argc == 5);
+
+ if (!get_bn_from_bin(env, argv[0], &bn_verifier))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, argv[1], &bn_b))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, argv[2], &bn_u))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, argv[3], &bn_A))
+ goto bad_arg;
+ if (!get_bn_from_bin(env, argv[4], &bn_prime))
+ goto bad_arg;
+
+ if ((bn_ctx = BN_CTX_new()) == NULL)
+ goto err;
+ if ((bn_result = BN_new()) == NULL)
+ goto err;
+
+ /* check that A % N != 0 */
+ if (!BN_nnmod(bn_result, bn_A, bn_prime, bn_ctx))
+ goto err;
+ if (BN_is_zero(bn_result))
+ goto err;
+
+ /* (A * v^u) */
+ if ((bn_base = BN_new()) == NULL)
+ goto err;
+ if (!BN_mod_exp(bn_base, bn_verifier, bn_u, bn_prime, bn_ctx))
+ goto err;
+ if (!BN_mod_mul(bn_base, bn_A, bn_base, bn_prime, bn_ctx))
+ goto err;
+
+ /* (A * v^u) ^ b % N */
+ if (!BN_mod_exp(bn_result, bn_base, bn_b, bn_prime, bn_ctx))
+ goto err;
+
+ if ((dlen = BN_num_bytes(bn_result)) < 0)
+ goto err;
+ if ((ptr = enif_make_new_binary(env, (size_t)dlen, &ret)) == NULL)
+ goto err;
+
+ if (BN_bn2bin(bn_result, ptr) < 0)
+ goto err;
+
+ goto done;
+
+ bad_arg:
+ ret = enif_make_badarg(env);
+ goto done;
+
+ err:
+ ret = atom_error;
+
+ done:
+ if (bn_verifier)
+ BN_free(bn_verifier);
+ if (bn_b)
+ BN_free(bn_b);
+ if (bn_u)
+ BN_free(bn_u);
+ if (bn_A)
+ BN_free(bn_A);
+ if (bn_prime)
+ BN_free(bn_prime);
+ if (bn_ctx)
+ BN_CTX_free(bn_ctx);
+ if (bn_result)
+ BN_free(bn_result);
+ if (bn_base)
+ BN_free(bn_base);
+
+ return ret;
+}
+
diff --git a/lib/crypto/c_src/srp.h b/lib/crypto/c_src/srp.h
new file mode 100644
index 0000000000..c356690470
--- /dev/null
+++ b/lib/crypto/c_src/srp.h
@@ -0,0 +1,30 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef E_SRP_H__
+#define E_SRP_H__ 1
+
+#include "common.h"
+
+ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM srp_user_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+ERL_NIF_TERM srp_host_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+#endif /* E_SRP_H__ */
diff --git a/lib/crypto/configure.in b/lib/crypto/configure.in
new file mode 100644
index 0000000000..a3b6673f29
--- /dev/null
+++ b/lib/crypto/configure.in
@@ -0,0 +1,775 @@
+dnl Process this file with autoconf to produce a configure script. -*-m4-*-
+dnl
+dnl %CopyrightBegin%
+dnl
+dnl Copyright Ericsson AB 2018. All Rights Reserved.
+dnl
+dnl Licensed under the Apache License, Version 2.0 (the "License");
+dnl you may not use this file except in compliance with the License.
+dnl You may obtain a copy of the License at
+dnl
+dnl http://www.apache.org/licenses/LICENSE-2.0
+dnl
+dnl Unless required by applicable law or agreed to in writing, software
+dnl distributed under the License is distributed on an "AS IS" BASIS,
+dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+dnl See the License for the specific language governing permissions and
+dnl limitations under the License.
+dnl
+dnl %CopyrightEnd%
+dnl
+
+dnl define([AC_CACHE_LOAD], )dnl
+dnl define([AC_CACHE_SAVE], )dnl
+
+
+AC_INIT(vsn.mk)
+
+if test -z "$ERL_TOP" || test ! -d "$ERL_TOP" ; then
+ AC_CONFIG_AUX_DIRS(autoconf)
+else
+ erl_top=${ERL_TOP}
+ AC_CONFIG_AUX_DIRS($erl_top/erts/autoconf)
+fi
+
+if test "X$host" != "Xfree_source" -a "X$host" != "Xwin32"; then
+ AC_CANONICAL_HOST
+else
+ host_os=win32
+fi
+
+LM_PRECIOUS_VARS
+
+if test "$cross_compiling" = "yes"; then
+ CROSS_COMPILING=yes
+else
+ CROSS_COMPILING=no
+fi
+AC_SUBST(CROSS_COMPILING)
+
+ERL_XCOMP_SYSROOT_INIT
+
+AC_PROG_CC
+LM_WINDOWS_ENVIRONMENT
+
+ERL_DED
+
+dnl
+dnl SSL, SSH and CRYPTO need the OpenSSL libraries
+dnl
+dnl Check flags --with-ssl, --without-ssl --with-ssl=PATH.
+dnl If no option is given or --with-ssl is set without a path then we
+dnl search for OpenSSL libraries and header files in the standard locations.
+dnl If set to --without-ssl we disable the use of SSL, SSH and CRYPTO.
+dnl If set to --with-ssl=PATH we use that path as the prefix, i.e. we
+dnl use "PATH/include" and "PATH/lib".
+
+AC_CHECK_SIZEOF(void *)
+
+std_ssl_locations="/usr/local /usr/sfw /usr /opt/local /usr/pkg /usr/local/openssl /usr/lib/openssl /usr/openssl /usr/local/ssl /usr/lib/ssl /usr/ssl /"
+
+AC_ARG_WITH(ssl-zlib,
+AS_HELP_STRING([--with-ssl-zlib=PATH],
+ [specify location of ZLib to be used by OpenSSL])
+AS_HELP_STRING([--with-ssl-zlib],
+ [link SSL with Zlib (default if found)])
+AS_HELP_STRING([--without-ssl-zlib],
+ [don't link SSL with ZLib]))
+
+if test "x$with_ssl_zlib" = "xno"; then
+ SSL_LINK_WITH_ZLIB=no
+ STATIC_ZLIB_LIBS=
+elif test "x$with_ssl_zlib" = "xyes" || test "x$with_ssl_zlib" = "x"; then
+ if test $erl_xcomp_without_sysroot = yes; then
+ AC_MSG_WARN([Cannot search for zlib; missing cross system root (erl_xcomp_sysroot).])
+ SSL_LINK_WITH_ZLIB=no
+ STATIC_ZLIB_LIBS=
+ elif test "x$MIXED_CYGWIN" = "xyes" -o "x$MIXED_MSYS" = "xyes"; then
+ SSL_LINK_WITH_ZLIB=no
+ STATIC_ZLIB_LIBS=
+ else
+ SSL_LINK_WITH_ZLIB=no
+ STATIC_ZLIB_LIBS=
+ AC_MSG_CHECKING(for static ZLib to be used by SSL in standard locations)
+ for rdir in $std_ssl_locations; do
+ dir="$erl_xcomp_sysroot$rdir"
+ if test "x$ac_cv_sizeof_void_p" = "x8"; then
+ if test -f "$dir/lib64/libz.a"; then
+ SSL_LINK_WITH_ZLIB=yes
+ STATIC_ZLIB_LIBS="$dir/lib64/libz.a"
+ break
+ elif test -f "$dir/lib/64/libz.a"; then
+ SSL_LINK_WITH_ZLIB=yes
+ STATIC_ZLIB_LIBS="$dir/lib/64/libz.a"
+ break
+ fi
+ fi
+ if test -f "$dir/lib/libz.a"; then
+ SSL_LINK_WITH_ZLIB=yes
+ STATIC_ZLIB_LIBS="$dir/lib/libz.a"
+ break
+ fi
+ done
+ if test "x$SSL_LINK_WITH_ZLIB" = "xno"; then
+ AC_MSG_RESULT([no])
+ else
+ AC_MSG_RESULT([$STATIC_ZLIB_LIBS])
+ fi
+ fi
+else
+ SSL_LINK_WITH_ZLIB=no
+ STATIC_ZLIB_LIBS=
+ if test -f "$with_ssl_zlib/libz.a"; then
+ SSL_LINK_WITH_ZLIB=yes
+ STATIC_ZLIB_LIBS=$with_ssl_zlib/libz.a
+ elif test -f "$with_ssl_zlib/lib/libz.a"; then
+ SSL_LINK_WITH_ZLIB=yes
+ STATIC_ZLIB_LIBS=$with_ssl_zlib/lib/libz.a
+ fi
+ if test "x$ac_cv_sizeof_void_p" = "x8"; then
+ if test -f "$with_ssl_zlib/lib64/libz.a"; then
+ SSL_LINK_WITH_ZLIB=yes
+ STATIC_ZLIB_LIBS=$with_ssl_zlib/lib64/libz.a
+ elif test -f "$with_ssl_zlib/lib/64/libz.a"; then
+ SSL_LINK_WITH_ZLIB=yes
+ STATIC_ZLIB_LIBS=$with_ssl_zlib/lib/64/libz.a
+ fi
+ fi
+ if test "x$SSL_LINK_WITH_ZLIB" = "xno"; then
+ AC_MSG_ERROR(Invalid path to option --with-ssl-zlib=PATH)
+ fi
+fi
+
+
+AC_ARG_WITH(ssl,
+AS_HELP_STRING([--with-ssl=PATH], [specify location of OpenSSL include and lib])
+AS_HELP_STRING([--with-ssl], [use SSL (default)])
+AS_HELP_STRING([--without-ssl], [don't use SSL]))
+
+AC_ARG_WITH(ssl-incl,
+AS_HELP_STRING([--with-ssl-incl=PATH], [location of OpenSSL include dir, if different than specified by --with-ssl=PATH]),
+[
+case X$with_ssl in
+ X | Xyes | Xno) AC_MSG_ERROR([--with-ssl-incl=PATH set without --with-ssl=PATH]);;
+esac
+],
+[with_ssl_incl=$with_ssl]) #default
+
+AC_ARG_WITH(ssl-rpath,
+AS_HELP_STRING([--with-ssl-rpath=yes|no|PATHS],
+ [runtime library path for OpenSSL. Default is "yes", which equates to a
+ number of standard locations. If "no", then no runtime
+ library paths will be used. Anything else should be a
+ comma separated list of paths.]),
+[
+case X$with_ssl in
+ Xno) AC_MSG_ERROR([--with-ssl-rpath set without --with-ssl]);;
+esac
+],
+[with_ssl_rpath=yes]) #default
+
+
+AC_ARG_ENABLE(dynamic-ssl-lib,
+AS_HELP_STRING([--disable-dynamic-ssl-lib],
+ [disable using dynamic openssl libraries]),
+[ case "$enableval" in
+ no) enable_dynamic_ssl=no ;;
+ *) enable_dynamic_ssl=yes ;;
+ esac ], enable_dynamic_ssl=yes)
+
+#----------------------------------------------------------------------
+# We actually might do the SSL tests twice due to late discovery of
+# kerberos problems with static linking, in case we redo it all trying
+# dynamic SSL libraries instead.
+#----------------------------------------------------------------------
+
+ssl_done=no
+
+while test "x$ssl_done" != "xyes"; do
+
+ssl_done=yes # Default only one run
+
+# Remove all SKIP files from previous runs
+for a in ssl crypto ssh; do
+ rm -f "$ERL_TOP/lib/$a/SKIP"
+done
+
+SSL_DYNAMIC_ONLY=$enable_dynamic_ssl
+SSL_STATIC_ONLY=no
+
+case "$erl_xcomp_without_sysroot-$with_ssl" in
+ yes-* | no-no)
+ SSL_APP=
+ CRYPTO_APP=
+ SSH_APP=
+ if test "$with_ssl" = "no"; then
+ skip="User gave --without-ssl option"
+ else
+ skip="Cannot search for ssl; missing cross system root (erl_xcomp_sysroot)."
+ fi
+ for a in ssl crypto ssh; do
+ echo "$skip" > $ERL_TOP/lib/$a/SKIP
+ done
+ ;;
+ no-yes | no- )
+ # On windows, we could try to find the installation
+ # of Shining Light OpenSSL, which can be found by poking in
+ # the uninstall section in the registry, it's worth a try...
+ extra_dir=""
+ if test "x$MIXED_CYGWIN" = "xyes"; then
+ AC_CHECK_PROG(REGTOOL, regtool, regtool, false)
+ if test "$ac_cv_prog_REGTOOL" != false; then
+ wrp="/machine/software/microsoft/windows/currentversion/"
+ if test "x$ac_cv_sizeof_void_p" = "x8"; then
+ urp="uninstall/openssl (64-bit)_is1/inno setup: app path"
+ regtool_subsystem=-w
+ else
+ urp="uninstall/openssl (32-bit)_is1/inno setup: app path"
+ regtool_subsystem=-W
+ fi
+ rp="$wrp$urp"
+ if regtool -q $regtool_subsystem get "$rp" > /dev/null; then
+ true
+ else
+ # Fallback to unspecified wordlength
+ urp="uninstall/openssl_is1/inno setup: app path"
+ rp="$wrp$urp"
+ fi
+ if regtool -q $regtool_subsystem get "$rp" > /dev/null; then
+ ssl_install_dir=`regtool -q $regtool_subsystem get "$rp"`
+ # Try hard to get rid of spaces...
+ if cygpath -d "$ssl_install_dir" > /dev/null 2>&1; then
+ ssl_install_dir=`cygpath -d "$ssl_install_dir"`
+ fi
+ extra_dir=`cygpath $ssl_install_dir`
+ fi
+ fi
+ elif test "x$MIXED_MSYS" = "xyes"; then
+ AC_CHECK_PROG(REGTOOL, reg_query.sh, reg_query.sh, false)
+ if test "$ac_cv_prog_REGTOOL" != false; then
+ if test "x$ac_cv_sizeof_void_p" = "x8"; then
+ rp="HKLM/SOFTWARE/Microsoft/Windows/CurrentVersion/Uninstall/OpenSSL (64-bit)_is1"
+ else
+ rp="HKLM/SOFTWARE/Microsoft/Windows/CurrentVersion/Uninstall/OpenSSL_is1"
+ fi
+ key="Inno Setup: App Path"
+ if "$ac_cv_prog_REGTOOL" "$rp" "$key" > /dev/null; then
+ ssl_install_dir=`"$ac_cv_prog_REGTOOL" "$rp" "$key"`
+ extra_dir=`win2msys_path.sh "$ssl_install_dir"`
+ fi
+ fi
+ fi
+ # We search for OpenSSL in the common OS standard locations.
+ SSL_APP=ssl
+ CRYPTO_APP=crypto
+ SSH_APP=ssh
+
+ SSL_CRYPTO_LIBNAME=crypto
+ SSL_SSL_LIBNAME=ssl
+
+ if test "x$MIXED_CYGWIN" = "xyes" -o "x$MIXED_MSYS" = "xyes"; then
+ if test "x$ac_cv_sizeof_void_p" = "x8"; then
+ std_win_ssl_locations="/cygdrive/c/OpenSSL-Win64 /c/OpenSSL-Win64 /opt/local64/pgm/OpenSSL"
+ else
+ std_win_ssl_locations="/cygdrive/c/OpenSSL-Win32 /c/OpenSSL-Win32 /cygdrive/c/OpenSSL /c/OpenSSL /opt/local/pgm/OpenSSL"
+ fi
+ else
+ std_win_ssl_locations=""
+ fi
+
+
+ AC_MSG_CHECKING(for OpenSSL >= 0.9.8c in standard locations)
+ for rdir in $extra_dir $std_win_ssl_locations $std_ssl_locations; do
+ dir="$erl_xcomp_sysroot$rdir"
+ if test -f "$erl_xcomp_isysroot$rdir/include/openssl/opensslv.h"; then
+ is_real_ssl=yes
+ SSL_INCDIR="$dir"
+ if test "x$MIXED_CYGWIN" = "xyes" -o "x$MIXED_MSYS" = "xyes"; then
+ if test -f "$dir/lib/VC/libeay32.lib"; then
+ SSL_RUNTIME_LIBDIR="$rdir/lib/VC"
+ SSL_LIBDIR="$dir/lib/VC"
+ SSL_CRYPTO_LIBNAME=libeay32
+ SSL_SSL_LIBNAME=ssleay32
+ elif test -f "$dir/lib/VC/openssl.lib"; then
+ SSL_RUNTIME_LIBDIR="$rdir/lib/VC"
+ SSL_LIBDIR="$dir/lib/VC"
+ elif test -f $dir/lib/VC/libeay32MD.lib; then
+ SSL_CRYPTO_LIBNAME=libeay32MD
+ SSL_SSL_LIBNAME=ssleay32MD
+ if test "x$enable_dynamic_ssl" = "xno" && \
+ test -f $dir/lib/VC/static/libeay32MD.lib; then
+ SSL_RUNTIME_LIBDIR="$rdir/lib/VC/static"
+ SSL_LIBDIR="$dir/lib/VC/static"
+ else
+ SSL_RUNTIME_LIBDIR="$rdir/lib/VC"
+ SSL_LIBDIR="$dir/lib/VC"
+ fi
+ elif test -f "$dir/lib/libeay32.lib"; then
+ SSL_RUNTIME_LIBDIR="$rdir/lib"
+ SSL_LIBDIR="$dir/lib"
+ SSL_CRYPTO_LIBNAME=libeay32
+ SSL_SSL_LIBNAME=ssleay32
+ elif test -f "$dir/lib/openssl.lib"; then
+ SSL_RUNTIME_LIBDIR="$rdir/lib"
+ SSL_LIBDIR="$dir/lib"
+ else
+ is_real_ssl=no
+ fi
+ elif test -f "$dir/lib/powerpc/libsslcrypto.a"; then
+ SSL_CRYPTO_LIBNAME=sslcrypto
+ SSL_LIBDIR="$dir/lib/powerpc/"
+ SSL_RUNTIME_LIBDIR="$rdir/lib/powerpc/"
+ else
+ if test "x$ac_cv_sizeof_void_p" = "x8"; then
+ if test -f "$dir/lib64/libcrypto.a"; then
+ SSL_RUNTIME_LIBDIR="$rdir/lib64"
+ SSL_LIBDIR="$dir/lib64"
+ elif test -f "$dir/lib/64/libcrypto.a"; then
+ SSL_RUNTIME_LIBDIR="$rdir/lib/64"
+ SSL_LIBDIR="$dir/lib/64"
+ elif test -f "$dir/lib64/libcrypto.so"; then
+ SSL_RUNTIME_LIBDIR="$rdir/lib64"
+ SSL_LIBDIR="$dir/lib64"
+ elif test -f "$dir/lib/64/libcrypto.so"; then
+ SSL_RUNTIME_LIBDIR="$rdir/lib/64"
+ SSL_LIBDIR="$dir/lib/64"
+ else
+ SSL_RUNTIME_LIBDIR="$rdir/lib"
+ SSL_LIBDIR="$dir/lib"
+ fi
+ else
+ SSL_RUNTIME_LIBDIR="$rdir/lib"
+ SSL_LIBDIR="$dir/lib"
+ fi
+ fi
+ if test '!' -f "$SSL_LIBDIR/lib${SSL_CRYPTO_LIBNAME}.a"; then
+ SSL_DYNAMIC_ONLY=yes
+ elif test '!' -f "$SSL_LIBDIR/lib${SSL_CRYPTO_LIBNAME}.so" -a '!' -f "$SSL_LIBDIR/lib${SSL_CRYPTO_LIBNAME}.dylib"; then
+ SSL_STATIC_ONLY=yes
+ fi
+ SSL_BINDIR="$rdir/bin"
+ if test "x$is_real_ssl" = "xyes" ; then
+ SSL_INCLUDE="-I$dir/include"
+ old_CPPFLAGS=$CPPFLAGS
+ CPPFLAGS=$SSL_INCLUDE
+ AC_EGREP_CPP(^yes$,[
+#include <openssl/opensslv.h>
+#if OPENSSL_VERSION_NUMBER >= 0x0090803fL
+yes
+#endif
+ ],[
+ ssl_found=yes
+ ],[
+ SSL_APP=
+ ssl_found=no
+ ])
+ CPPFLAGS=$old_CPPFLAGS
+ if test "x$ssl_found" = "xyes"; then
+ if test "x$MIXED_CYGWIN" = "xyes" -o "x$MIXED_MSYS" = "xyes"; then
+ ssl_linkable=yes
+ elif test "x${SSL_CRYPTO_LIBNAME}" = "xsslcrypto"; then
+ # This should only be triggered seen OSE
+ ssl_linkable=yes
+ else
+ saveCFLAGS="$CFLAGS"
+ saveLDFLAGS="$LDFLAGS"
+ saveLIBS="$LIBS"
+ CFLAGS="$CFLAGS $SSL_INCLUDE"
+ if test "x$SSL_STATIC_ONLY" = "xyes"; then
+ LIBS="${SSL_LIBDIR}/lib${SSL_CRYPTO_LIBNAME}.a"
+ else
+ LDFLAGS="$LDFLAGS -L$SSL_LIBDIR"
+ LIBS="$LIBS -l${SSL_CRYPTO_LIBNAME}"
+ fi
+ AC_TRY_LINK([
+ #include <stdio.h>
+ #include <openssl/hmac.h>],
+ [
+ HMAC(0, 0, 0, 0, 0, 0, 0);
+ ],
+ [ssl_linkable=yes],
+ [ssl_linkable=no])
+ CFLAGS="$saveCFLAGS"
+ LDFLAGS="$saveLDFLAGS"
+ LIBS="$saveLIBS"
+ fi
+ fi
+ if test "x$ssl_found" = "xyes" && test "x$ssl_linkable" = "xyes"; then
+ AC_MSG_RESULT([$dir])
+ break;
+ fi
+ fi
+ fi
+ done
+
+ if test "x$ssl_found" != "xyes" ; then
+ dnl
+ dnl If no SSL found above, check whether we are running on OpenBSD.
+ dnl
+ case $host_os in
+ openbsd*)
+ if test -f "$erl_xcomp_isysroot/usr/include/openssl/opensslv.h"; then
+ # Trust OpenBSD to have everything the in the correct locations.
+ ssl_found=yes
+ ssl_linkable=yes
+ SSL_INCDIR="$erl_xcomp_sysroot/usr"
+ AC_MSG_RESULT([$SSL_INCDIR])
+ SSL_RUNTIME_LIB="/usr/lib"
+ SSL_LIB="$erl_xcomp_sysroot/usr/lib"
+ SSL_BINDIR="/usr/sbin"
+ dnl OpenBSD requires us to link with -L and -l
+ SSL_DYNAMIC_ONLY="yes"
+ fi
+ ;;
+ esac
+ fi
+dnl Now, certain linuxes have a 64bit libcrypto
+dnl that cannot build shared libraries (i.e. not PIC)
+dnl One could argue that this is wrong, but
+dnl so it is - be adoptable
+ if test "$ssl_found" = "yes" && test "$ssl_linkable" = "yes" && test "$SSL_DYNAMIC_ONLY" != "yes"; then
+ case $host_os in
+ linux*)
+ saveCFLAGS="$CFLAGS"
+ saveLDFLAGS="$LDFLAGS"
+ saveLIBS="$LIBS"
+ CFLAGS="$DED_CFLAGS $SSL_INCLUDE"
+ LDFLAGS="$DED_LDFLAGS"
+ LIBS="$SSL_LIBDIR/libcrypto.a $STATIC_ZLIB_LIBS"
+ AC_TRY_LINK([
+ #include <stdio.h>
+ #include <openssl/hmac.h>],
+ [
+ HMAC(0, 0, 0, 0, 0, 0, 0);
+ ],
+ [ssl_dyn_linkable=yes],
+ [ssl_dyn_linkable=no])
+ CFLAGS="$saveCFLAGS"
+ LDFLAGS="$saveLDFLAGS"
+ LIBS="$saveLIBS"
+ if test "x$ssl_dyn_linkable" != "xyes"; then
+ SSL_DYNAMIC_ONLY=yes
+ AC_MSG_WARN([SSL will be linked against dynamic lib as static lib is not purely relocatable])
+ fi
+ ;;
+ esac
+ fi
+
+
+
+
+ if test "x$ssl_found" != "xyes" || test "x$ssl_linkable" != "xyes"; then
+ if test "x$ssl_found" = "xyes"; then
+ AC_MSG_RESULT([found; but not usable])
+ else
+ AC_MSG_RESULT([no])
+ fi
+ SSL_APP=
+ CRYPTO_APP=
+ SSH_APP=
+ AC_MSG_WARN([No (usable) OpenSSL found, skipping ssl, ssh and crypto applications])
+
+ for a in ssl crypto ssh; do
+ echo "No usable OpenSSL found" > $ERL_TOP/lib/$a/SKIP
+ done
+ fi
+ ;;
+ *)
+ # Option given with PATH to package
+ if test ! -d "$with_ssl" ; then
+ AC_MSG_ERROR(Invalid path to option --with-ssl=PATH)
+ fi
+ if test ! -d "$with_ssl_incl" ; then
+ AC_MSG_ERROR(Invalid path to option --with-ssl-incl=PATH)
+ fi
+ SSL_INCDIR="$with_ssl_incl"
+ SSL_CRYPTO_LIBNAME=crypto
+ SSL_SSL_LIBNAME=ssl
+ if test "x$MIXED_CYGWIN" = "xyes" -o "x$MIXED_MSYS" = "xyes" && test -d "$with_ssl/lib/VC"; then
+ if test -f "$with_ssl/lib/VC/libeay32.lib"; then
+ SSL_LIBDIR="$with_ssl/lib/VC"
+ SSL_CRYPTO_LIBNAME=libeay32
+ SSL_SSL_LIBNAME=ssleay32
+ elif test -f "$with_ssl/lib/VC/openssl.lib"; then
+ SSL_LIBDIR="$with_ssl/lib/VC"
+ elif test -f $with_ssl/lib/VC/libeay32MD.lib; then
+ SSL_CRYPTO_LIBNAME=libeay32MD
+ SSL_SSL_LIBNAME=ssleay32MD
+ if test "x$enable_dynamic_ssl" = "xno" && \
+ test -f $with_ssl/lib/VC/static/libeay32MD.lib; then
+ SSL_LIBDIR="$with_ssl/lib/VC/static"
+ else
+ SSL_LIBDIR="$with_ssl/lib/VC"
+ fi
+ elif test -f "$with_ssl/lib/libeay32.lib"; then
+ SSL_LIBDIR="$with_ssl/lib"
+ SSL_CRYPTO_LIBNAME=libeay32
+ SSL_SSL_LIBNAME=ssleay32
+ else
+ # This probably wont work, but that's what the user said, so...
+ SSL_LIBDIR="$with_ssl/lib"
+ fi
+ elif test -f "$dir/lib/powerpc/libsslcrypto.a"; then
+ SSL_CRYPTO_LIBNAME=sslcrypto
+ SSL_LIBDIR="$with_ssl/lib/powerpc/"
+ elif test "x$ac_cv_sizeof_void_p" = "x8"; then
+ if test -f "$with_ssl/lib64/libcrypto.a"; then
+ SSL_LIBDIR="$with_ssl/lib64"
+ elif test -f "$with_ssl/lib/64/libcrypto.a"; then
+ SSL_LIBDIR="$with_ssl/lib/64"
+ elif test -f "$with_ssl/lib64/libcrypto.so"; then
+ SSL_LIBDIR="$with_ssl/lib64"
+ elif test -f "$with_ssl/lib/64/libcrypto.so"; then
+ SSL_LIBDIR="$with_ssl/lib/64"
+ else
+ SSL_LIBDIR="$with_ssl/lib"
+ fi
+ else
+ SSL_LIBDIR="$with_ssl/lib"
+ fi
+ if test '!' -f "${SSL_LIBDIR}/lib${SSL_CRYPTO_LIBNAME}.a"; then
+ SSL_DYNAMIC_ONLY=yes
+ elif test '!' -f ${SSL_LIBDIR}/lib${SSL_CRYPTO_LIBNAME}.so -a '!' -f "$SSL_LIBDIR/lib${SSL_CRYPTO_LIBNAME}.dylib"; then
+ SSL_STATIC_ONLY=yes
+ fi
+ SSL_INCLUDE="-I$with_ssl_incl/include"
+ SSL_APP=ssl
+ CRYPTO_APP=crypto
+ SSH_APP=ssh
+ if test "$cross_compiling" = "yes"; then
+ SSL_RUNTIME_LIBDIR=`echo "$SSL_LIBDIR" | sed -n "s|^$erl_xcomp_sysroot\(/*\)\(.*\)\$|/\2|p"`
+ else
+ SSL_RUNTIME_LIBDIR="$SSL_LIBDIR"
+ fi
+esac
+
+if test "x$SSL_APP" != "x" ; then
+ dnl We found openssl, now check if we use kerberos 5 support
+ dnl FIXME: Do we still support platforms that have Kerberos?
+ AC_MSG_CHECKING(for OpenSSL kerberos 5 support)
+ old_CPPFLAGS=$CPPFLAGS
+ CPPFLAGS=$SSL_INCLUDE
+ AC_EGREP_CPP(^yes$,[
+#include <openssl/opensslv.h>
+#include <openssl/opensslconf.h>
+#if OPENSSL_VERSION_NUMBER < 0x1010000fL && !defined(OPENSSL_NO_KRB5)
+yes
+#endif
+ ],[
+ AC_MSG_RESULT([yes])
+ ssl_krb5_enabled=yes
+ if test "x$SSL_DYNAMIC_ONLY" != "xyes"; then
+ if test -f "$SSL_LIBDIR/libkrb5.a"; then
+ SSL_LINK_WITH_KERBEROS=yes
+ STATIC_KERBEROS_LIBS="$SSL_LIBDIR/libkrb5.a"
+ if test -f "$SSL_LIBDIR/libkrb5support.a"; then
+ STATIC_KERBEROS_LIBS="$STATIC_KERBEROS_LIBS $SSL_LIBDIR/libkrb5support.a"
+ fi
+ if test -f "$SSL_LIBDIR/libk5crypto.a"; then
+ STATIC_KERBEROS_LIBS="$STATIC_KERBEROS_LIBS $SSL_LIBDIR/libk5crypto.a"
+ fi
+ if test -f "$SSL_LIBDIR/libresolv.a"; then
+ STATIC_KERBEROS_LIBS="$STATIC_KERBEROS_LIBS $SSL_LIBDIR/libresolv.a"
+ fi
+ if test -f "$SSL_LIBDIR/libcom_err.a"; then
+ STATIC_KERBEROS_LIBS="$STATIC_KERBEROS_LIBS $SSL_LIBDIR/libcom_err.a"
+ fi
+ else
+ AC_MSG_WARN([Kerberos needed but no kerberos static libraries found])
+ AC_MSG_WARN([Rescanning for dynamic SSL libraries])
+ enable_dynamic_ssl=yes
+ ssl_done=no
+ SSL_LINK_WITH_KERBEROS=no
+ STATIC_KERBEROS_LIBS=""
+ ssl_krb5_enabled=no
+ SSL_WITH_KERBEROS=no
+ fi
+ else
+ SSL_LINK_WITH_KERBEROS=no
+ STATIC_KERBEROS_LIBS=""
+ fi
+ ],[
+ AC_MSG_RESULT([no])
+ ssl_krb5_enabled=no
+ SSL_WITH_KERBEROS=no
+ ])
+ CPPFLAGS=$old_CPPFLAGS
+ SSL_KRB5_INCLUDE=
+ if test "x$ssl_krb5_enabled" = "xyes" ; then
+ AC_MSG_CHECKING(for krb5.h in standard locations)
+ for dir in $extra_dir "$SSL_INCDIR/include" "$SSL_INCDIR/include/openssl" \
+ "$SSL_INCDIR/include/kerberos" \
+ "$erl_xcomp_isysroot/cygdrive/c/kerberos/include" \
+ "$erl_xcomp_isysroot/usr/local/kerberos/include" \
+ "$erl_xcomp_isysroot/usr/kerberos/include" \
+ "$erl_xcomp_isysroot/usr/include"
+ do
+ if test -f "$dir/krb5.h" ; then
+ SSL_KRB5_INCLUDE="$dir"
+ break
+ fi
+ done
+ if test "x$SSL_KRB5_INCLUDE" = "x" ; then
+ AC_MSG_RESULT([not found])
+ SSL_APP=
+ CRYPTO_APP=
+ SSH_APP=
+ AC_MSG_WARN([OpenSSL is configured for kerberos but no krb5.h found])
+ for a in ssl crypto ssh ; do
+ echo "OpenSSL is configured for kerberos but no krb5.h found" > $ERL_TOP/lib/$a/SKIP
+ done
+ else
+ AC_MSG_RESULT([found in $SSL_KRB5_INCLUDE])
+ SSL_INCLUDE="$SSL_INCLUDE -I$SSL_KRB5_INCLUDE"
+ fi
+ fi
+fi
+
+done # while test ssl_done != yes
+
+SSL_DED_LD_RUNTIME_LIBRARY_PATH=
+ded_ld_rflg="$DED_LD_FLAG_RUNTIME_LIBRARY_PATH"
+
+
+case "$with_ssl_rpath" in
+
+yes) # Use standard lib locations for ssl runtime library path
+
+ if test "$SSL_APP" != "" && test "$SSL_DYNAMIC_ONLY" = "yes" && test "$ded_ld_rflg" != ""; then
+
+ AC_MSG_CHECKING(for ssl runtime library path to use)
+
+ libdirs="/lib"
+
+ if test "$ac_cv_sizeof_void_p" = "8"; then
+ dir_lib64=no
+ dir_lib_64=no
+
+ case "$SSL_RUNTIME_LIBDIR" in
+ */lib/64 | */lib/64/ ) dir_lib_64=yes;;
+ */lib64 | */lib64/ ) dir_lib64=yes;;
+ *) ;;
+ esac
+
+ for dir in $std_ssl_locations; do
+ test $dir_lib_64 = no &&
+ test -d "$erl_xcomp_sysroot$dir/lib/64" &&
+ dir_lib_64=yes
+ test $dir_lib64 = no &&
+ test -d "$erl_xcomp_sysroot$dir/lib64" &&
+ dir_lib64=yes
+ done
+
+ test $dir_lib_64 = yes && libdirs="/lib/64 $libdirs"
+ test $dir_lib64 = yes && libdirs="/lib64 $libdirs"
+ fi
+
+ for type in std x_std curr; do
+
+ ded_ld_rpath="$ded_ld_rflg$SSL_RUNTIME_LIBDIR"
+ rpath="$SSL_RUNTIME_LIBDIR"
+
+ if test $type != curr; then
+ for ldir in $libdirs; do
+ for dir in $std_ssl_locations; do
+ test "$SSL_LIBDIR" != "$dir$ldir" || continue
+ test $type != x_std || test -d "$dir$ldir" || continue
+ if test "$dir" = "/"; then
+ libdir="$ldir"
+ else
+ libdir="$dir$ldir"
+ fi
+ ded_ld_rpath="$ded_ld_rpath $ded_ld_rflg$libdir"
+ rpath="$rpath:$libdir"
+ done
+ done
+ fi
+
+ saveCFLAGS="$CFLAGS"
+ saveLDFLAGS="$LDFLAGS"
+ saveLIBS="$LIBS"
+ CFLAGS="$CFLAGS $SSL_INCLUDE"
+ LDFLAGS="$LDFLAGS $ld_rpath -L$SSL_LIBDIR"
+ LIBS="-lcrypto"
+ AC_TRY_LINK([
+ #include <stdio.h>
+ #include <openssl/hmac.h>
+ ],
+ [
+ HMAC(0, 0, 0, 0, 0, 0, 0);
+ ],
+ [rpath_success=yes],
+ [rpath_success=no])
+ CFLAGS="$saveCFLAGS"
+ LDFLAGS="$saveLDFLAGS"
+ LIBS="$saveLIBS"
+
+ test "$rpath_success" = "yes" && break
+ done
+
+ test "$rpath_success" = "yes" || { ded_ld_rpath=; rpath=; }
+
+ SSL_DED_LD_RUNTIME_LIBRARY_PATH="$ded_ld_rpath"
+
+ AC_MSG_RESULT([$rpath])
+ test "$rpath" != "" || AC_MSG_WARN([Cannot set run path during linking])
+ fi
+ ;;
+
+no) # Use no ssl runtime library path
+ SSL_DED_LD_RUNTIME_LIBRARY_PATH=
+ ;;
+
+*) # Use ssl runtime library paths set by --with-ssl-rpath (without any check)
+ ded_ld_rpath=
+ delimit=
+ for dir in `echo $with_ssl_rpath | sed "s/,/ /g"`; do
+ ded_ld_rpath="$ded_ld_rpath$delimit$ded_ld_rflg$dir"
+ delimit=" "
+ done
+ SSL_DED_LD_RUNTIME_LIBRARY_PATH="$ded_ld_rpath"
+ ;;
+
+esac
+
+
+AC_ARG_ENABLE(fips,
+AS_HELP_STRING([--enable-fips], [enable OpenSSL FIPS mode support])
+AS_HELP_STRING([--disable-fips], [disable OpenSSL FIPS mode support (default)]),
+[ case "$enableval" in
+ yes) enable_fips_support=yes ;;
+ *) enable_fips_support=no ;;
+ esac ], enable_fips_support=no)
+
+if test "x$enable_fips_support" = "xyes" && test "$CRYPTO_APP" != ""; then
+ saveCFLAGS="$CFLAGS"
+ saveLDFLAGS="$LDFLAGS"
+ saveLIBS="$LIBS"
+ CFLAGS="$CFLAGS $SSL_INCLUDE"
+ LDFLAGS="$LDFLAGS $ded_ld_rpath -L$SSL_LIBDIR"
+ LIBS="-lcrypto"
+ AC_CHECK_FUNC([FIPS_mode_set],
+ [SSL_FLAGS="-DFIPS_SUPPORT"],
+ [SSL_FLAGS=])
+ CFLAGS="$saveCFLAGS"
+ LDFLAGS="$saveLDFLAGS"
+ LIBS="$saveLIBS"
+else
+ SSL_FLAGS=
+fi
+
+AC_SUBST(SSL_INCLUDE)
+AC_SUBST(SSL_INCDIR)
+AC_SUBST(SSL_LIBDIR)
+AC_SUBST(SSL_FLAGS)
+AC_SUBST(SSL_CRYPTO_LIBNAME)
+AC_SUBST(SSL_SSL_LIBNAME)
+AC_SUBST(SSL_DED_LD_RUNTIME_LIBRARY_PATH)
+AC_SUBST(SSL_DYNAMIC_ONLY)
+AC_SUBST(SSL_LINK_WITH_KERBEROS)
+AC_SUBST(STATIC_KERBEROS_LIBS)
+AC_SUBST(SSL_LINK_WITH_ZLIB)
+AC_SUBST(STATIC_ZLIB_LIBS)
+
+AC_OUTPUT(c_src/$host/Makefile:c_src/Makefile.in)
+
diff --git a/lib/crypto/doc/specs/.gitignore b/lib/crypto/doc/specs/.gitignore
new file mode 100644
index 0000000000..322eebcb06
--- /dev/null
+++ b/lib/crypto/doc/specs/.gitignore
@@ -0,0 +1 @@
+specs_*.xml
diff --git a/lib/crypto/doc/src/Makefile b/lib/crypto/doc/src/Makefile
index aa987d2b39..8da494dad6 100644
--- a/lib/crypto/doc/src/Makefile
+++ b/lib/crypto/doc/src/Makefile
@@ -39,7 +39,8 @@ XML_REF3_FILES = crypto.xml
XML_REF6_FILES = crypto_app.xml
XML_PART_FILES = usersguide.xml
-XML_CHAPTER_FILES = notes.xml licenses.xml fips.xml engine_load.xml engine_keys.xml
+XML_CHAPTER_FILES = notes.xml licenses.xml fips.xml engine_load.xml engine_keys.xml \
+ algorithm_details.xml new_api.xml
BOOK_FILES = book.xml
@@ -62,11 +63,17 @@ HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
+SPECS_FILES = $(XML_REF3_FILES:%.xml=$(SPECDIR)/specs_%.xml)
+
+TOP_SPECS_FILE = specs.xml
+
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
XML_FLAGS +=
+#in ssh it looks like this: SPECS_FLAGS = -I../../../public_key/include -I../../../public_key/src -I../../..
+
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
@@ -89,9 +96,11 @@ debug opt valgrind:
clean clean_docs clean_tex:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(MAN6DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
+ rm -f $(SPECS_FILES)
rm -f errs core *~
# ----------------------------------------------------
diff --git a/lib/crypto/doc/src/algorithm_details.xml b/lib/crypto/doc/src/algorithm_details.xml
new file mode 100644
index 0000000000..854bfbb4b1
--- /dev/null
+++ b/lib/crypto/doc/src/algorithm_details.xml
@@ -0,0 +1,355 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2014</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Algorithm Details</title>
+ <prepared>Hans Nilsson</prepared>
+ <docno></docno>
+ <date>2018-08-22</date>
+ <rev>A</rev>
+ <file>algorithm_details.xml</file>
+ </header>
+ <p>
+ This chapter describes details of algorithms in the crypto application.
+ </p>
+ <p>The tables only documents the supported cryptos and key lengths. The user should not draw any conclusion
+ on security from the supplied tables.
+ </p>
+
+ <section>
+ <title>Ciphers</title>
+ <section>
+ <title>Block Ciphers</title>
+ <p>To be used in
+ <seealso marker="crypto#block_encrypt-3">block_encrypt/3</seealso>,
+ <seealso marker="crypto#block_encrypt-4">block_encrypt/4</seealso>,
+ <seealso marker="crypto#block_decrypt-3">block_decrypt/3</seealso> and
+ <seealso marker="crypto#block_decrypt-4">block_decrypt/4</seealso>.
+ </p>
+ <p>Available in all OpenSSL compatible with Erlang CRYPTO if not disabled by configuration.
+ </p>
+ <p>To dynamically check availability, check that the name in the <i>Cipher and Mode</i> column is present in the
+ list with the <c>cipher</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ </p>
+ <table>
+ <row><cell><strong>Cipher and Mode</strong></cell><cell><strong>Key length</strong><br/><strong>[bytes]</strong></cell><cell><strong>IV length</strong><br/><strong>[bytes]</strong></cell><cell><strong>Block size</strong><br/><strong>[bytes]</strong></cell></row>
+ <row><cell><c>aes_cbc</c></cell> <cell>16, 24, 32</cell><cell>16</cell><cell>16</cell></row>
+ <row><cell><c>aes_cbc128</c></cell><cell>16</cell><cell>16</cell><cell>16</cell></row>
+ <row><cell><c>aes_cbc256</c></cell><cell>32</cell><cell>16</cell><cell>16</cell></row>
+
+ <row><cell><c>aes_cfb8</c></cell> <cell>16, 24, 32</cell><cell>16</cell><cell>any</cell></row>
+
+ <row><cell><c>aes_ecb</c></cell><cell>16, 24, 32</cell><cell> </cell><cell>16</cell></row>
+
+ <row><cell><c>aes_ige256</c></cell><cell>16</cell><cell>32</cell><cell>16</cell></row>
+ <row><cell><c>blowfish_cbc</c></cell> <cell>4-56</cell> <cell>8</cell> <cell>8</cell></row>
+ <row><cell><c>blowfish_cfb64</c></cell> <cell>&#8805;1</cell> <cell>8</cell> <cell>any</cell></row>
+ <row><cell><c>blowfish_ecb</c></cell><cell>&#8805;1</cell><cell> </cell><cell>8</cell></row>
+ <row><cell><c>blowfish_ofb64</c></cell><cell>&#8805;1</cell><cell>8</cell><cell>any</cell></row>
+
+ <row><cell><c>des3_cbc</c><br/><i>(=DES EDE3 CBC)</i></cell><cell>[8,8,8]</cell><cell>8</cell><cell>8</cell></row>
+ <row><cell><c>des3_cfb</c><br/><i>(=DES EDE3 CFB)</i></cell><cell>[8,8,8]</cell><cell>8</cell><cell>any</cell></row>
+
+ <row><cell><c>des_cbc</c></cell><cell>8</cell><cell>8</cell> <cell>8</cell></row>
+ <row><cell><c>des_cfb</c></cell><cell>8</cell><cell>8</cell><cell>any</cell></row>
+ <row><cell><c>des_ecb</c></cell><cell>8</cell><cell> </cell><cell>8</cell></row>
+ <row><cell><c>des_ede3</c><br/><i>(=DES EDE3 CBC)</i></cell><cell>[8,8,8]</cell><cell>8</cell><cell>8</cell></row>
+ <row><cell><c>rc2_cbc</c></cell><cell>&#8805;1</cell><cell>8</cell><cell>8</cell></row>
+ <tcaption>Block cipher key lengths</tcaption>
+ </table>
+ </section>
+
+ <section>
+ <title>AEAD Ciphers</title>
+ <p>To be used in <seealso marker="crypto#block_encrypt-4">block_encrypt/4</seealso> and
+ <seealso marker="crypto#block_decrypt-4">block_decrypt/4</seealso>.
+ </p>
+ <p>To dynamically check availability, check that the name in the <i>Cipher and Mode</i> column is present in the
+ list with the <c>cipher</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ </p>
+ <table>
+ <row><cell><strong>Cipher and Mode</strong></cell><cell><strong>Key length</strong><br/><strong>[bytes]</strong></cell><cell><strong>IV length</strong><br/><strong>[bytes]</strong></cell><cell><strong>AAD length</strong><br/><strong>[bytes]</strong></cell><cell><strong>Tag length</strong><br/><strong>[bytes]</strong></cell><cell><strong>Block size</strong><br/><strong>[bytes]</strong></cell><cell><strong>Supported with</strong><br/><strong>OpenSSL versions</strong></cell></row>
+ <row><cell><c>aes_ccm</c></cell> <cell>16,24,32</cell> <cell>7-13</cell> <cell>any</cell> <cell>even 4-16<br/>default: 12</cell> <cell>any</cell><cell>&#8805;1.1.0</cell></row>
+ <row><cell><c>aes_gcm</c></cell> <cell>16,24,32</cell> <cell>&#8805;1</cell> <cell>any</cell> <cell>1-16<br/>default: 16</cell> <cell>any</cell><cell>&#8805;1.1.0</cell></row>
+ <row><cell><c>chacha20_poly1305</c></cell><cell>32</cell> <cell>1-16</cell> <cell>any</cell> <cell>16</cell> <cell>any</cell><cell>&#8805;1.1.0</cell></row>
+ <tcaption>AEAD cipher key lengths</tcaption>
+ </table>
+ </section>
+
+ <section>
+ <title>Stream Ciphers</title>
+ <p>To be used in <seealso marker="crypto#stream_init-2">stream_init/2</seealso> and
+ <seealso marker="crypto#stream_init/3">stream_init/3</seealso>.
+ </p>
+ <p>To dynamically check availability, check that the name in the <i>Cipher and Mode</i> column is present in the
+ list with the <c>cipher</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ </p>
+ <table>
+ <row><cell><strong>Cipher and Mode</strong></cell><cell><strong>Key length</strong><br/><strong>[bytes]</strong></cell><cell><strong>IV length</strong><br/><strong>[bytes]</strong></cell><cell><strong>Supported with</strong><br/><strong>OpenSSL versions</strong></cell></row>
+ <row><cell><c>aes_ctr</c></cell><cell>16, 24, 32</cell><cell>16</cell><cell>&#8805;1.0.1</cell></row>
+ <row><cell><c>rc4</c></cell><cell>&#8805;1</cell><cell> </cell> <cell>all</cell></row>
+ <tcaption>Stream cipher key lengths</tcaption>
+ </table>
+ </section>
+ </section>
+
+ <section>
+ <title>Message Authentication Codes (MACs)</title>
+
+ <section>
+ <title>CMAC</title>
+ <p>To be used in <seealso marker="crypto#cmac-3">cmac/3</seealso> and
+ <seealso marker="crypto#cmac-3">cmac/4</seealso>.
+ </p>
+ <p>CMAC with the following ciphers are available with OpenSSL 1.0.1 or later if not disabled by configuration.
+ </p>
+
+ <p>To dynamically check availability, check that the name <c>cmac</c> is present in the
+ list with the <c>macs</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ Also check that the name in the <i>Cipher and Mode</i> column is present in the
+ list with the <c>cipher</c> tag in the return value.
+ </p>
+ <table>
+ <row><cell><strong>Cipher and Mode</strong></cell><cell><strong>Key length</strong><br/><strong>[bytes]</strong></cell><cell><strong>Max Mac Length</strong><br/><strong>[bytes]</strong></cell></row>
+ <row><cell><c>aes_cbc</c></cell> <cell>16, 24, 32</cell><cell>16</cell></row>
+ <row><cell><c>aes_cbc128</c></cell><cell>16</cell><cell>16</cell></row>
+ <row><cell><c>aes_cbc256</c></cell><cell>32</cell><cell>16</cell></row>
+
+ <row><cell><c>aes_cfb8</c></cell> <cell>16</cell><cell>1</cell></row>
+
+ <row><cell><c>blowfish_cbc</c></cell> <cell>4-56</cell> <cell>8</cell></row>
+ <row><cell><c>blowfish_cfb64</c></cell> <cell>&#8805;1</cell> <cell>1</cell></row>
+ <row><cell><c>blowfish_ecb</c></cell><cell>&#8805;1</cell> <cell>8</cell></row>
+ <row><cell><c>blowfish_ofb64</c></cell><cell>&#8805;1</cell> <cell>1</cell></row>
+
+ <row><cell><c>des3_cbc</c><br/><i>(=DES EDE3 CBC)</i></cell><cell>[8,8,8]</cell><cell>8</cell></row>
+ <row><cell><c>des3_cfb</c><br/><i>(=DES EDE3 CFB)</i></cell><cell>[8,8,8]</cell><cell>1</cell></row>
+
+ <row><cell><c>des_cbc</c></cell><cell>8</cell><cell>8</cell></row>
+
+ <row><cell><c>des_cfb</c></cell><cell>8</cell><cell>1</cell></row>
+ <row><cell><c>des_ecb</c></cell><cell>8</cell><cell>1</cell></row>
+ <row><cell><c>rc2_cbc</c></cell><cell>&#8805;1</cell><cell>8</cell></row>
+ <tcaption>CMAC cipher key lengths</tcaption>
+ </table>
+ </section>
+
+ <section>
+ <title>HMAC</title>
+ <p>Available in all OpenSSL compatible with Erlang CRYPTO if not disabled by configuration.
+ </p>
+ <p>To dynamically check availability, check that the name <c>hmac</c> is present in the
+ list with the <c>macs</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ </p>
+ </section>
+
+ <section>
+ <title>POLY1305</title>
+ <p>POLY1305 is available with OpenSSL 1.1.1 or later if not disabled by configuration.
+ </p>
+ <p>To dynamically check availability, check that the name <c>poly1305</c> is present in the
+ list with the <c>macs</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ </p>
+ </section>
+
+ </section>
+
+ <section>
+ <title>Hash</title>
+
+ <p>To dynamically check availability, check that the wanted name in the <i>Names</i> column is present in the
+ list with the <c>hashs</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ </p>
+
+
+ <table>
+ <row><cell><strong>Type</strong></cell>
+ <cell><strong>Names</strong></cell>
+ <cell><strong>Supported with</strong><br/><strong>OpenSSL versions</strong></cell>
+ </row>
+ <row><cell>SHA1</cell><cell>sha</cell><cell>all</cell></row>
+ <row><cell>SHA2</cell><cell>sha224, sha256, sha384, sha512</cell><cell>all</cell></row>
+ <row><cell>SHA3</cell><cell>sha3_224, sha3_256, sha3_384, sha3_512</cell><cell>&#8805;1.1.1</cell></row>
+ <row><cell>MD4</cell><cell>md4</cell><cell>all</cell></row>
+ <row><cell>MD5</cell><cell>md5</cell><cell>all</cell></row>
+ <row><cell>RIPEMD</cell><cell>ripemd160</cell><cell>all</cell></row>
+ <tcaption></tcaption>
+ </table>
+ </section>
+
+ <section>
+ <title>Public Key Cryptography</title>
+
+ <section>
+ <title>RSA</title>
+ <p>RSA is available with all OpenSSL versions compatible with Erlang CRYPTO if not disabled by configuration.
+ To dynamically check availability, check that the atom <c>rsa</c> is present in the
+ list with the <c>public_keys</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ </p>
+ <warning>
+ <!-- In RefMan rsa_opt(), rsa_sign_verify_opt() and User's man RSA -->
+ <p>The RSA options are experimental.
+ </p>
+ <p>The exact set of options and there syntax <em>may</em> be changed
+ without prior notice.</p>
+ </warning>
+ <table>
+ <row><cell><strong>Option</strong></cell>
+ <cell><strong>sign/verify</strong></cell>
+ <cell><strong>public encrypt</strong><br/><strong>private decrypt</strong></cell>
+ <cell><strong>private encrypt</strong><br/><strong>public decrypt</strong></cell>
+ </row>
+ <row><cell>{rsa_padding,rsa_x931_padding}</cell>
+ <cell>x</cell>
+ <cell></cell>
+ <cell>x</cell>
+ </row>
+ <row><cell>{rsa_padding,rsa_pkcs1_padding}</cell>
+ <cell>x</cell>
+ <cell>x</cell>
+ <cell>x</cell>
+ </row>
+ <row><cell>{rsa_padding,rsa_pkcs1_pss_padding}<br/>
+ {rsa_pss_saltlen, -2..}<br/>
+ {rsa_mgf1_md, atom()}
+ </cell>
+ <cell>x (2)<br/>
+ x (2)<br/>
+ x (2)</cell>
+ <cell></cell>
+ <cell></cell>
+ </row>
+ <row><cell>{rsa_padding,rsa_pkcs1_oaep_padding}<br/>
+ {rsa_mgf1_md, atom()}<br/>
+ {rsa_oaep_label, binary()}}<br/>
+ {rsa_oaep_md, atom()}
+ </cell>
+ <cell></cell>
+ <cell>x (2)<br/>
+ x (2)<br/>
+ x (3)<br/>
+ x (3)
+ </cell>
+ <cell></cell>
+ </row>
+ <row><cell>{rsa_padding,rsa_no_padding}</cell>
+ <cell>x (1)</cell>
+ <cell></cell>
+ <cell></cell>
+ </row>
+ <!-- row><cell>{rsa_padding,rsa_sslv23_padding}</cell>
+ <cell></cell>
+ <cell></cell>
+ <cell></cell>
+ </row -->
+ <tcaption></tcaption>
+ </table>
+ <p>Notes:</p>
+ <list type="ordered">
+ <item>(1) OpenSSL &#8804; 1.0.0</item>
+ <item>(2) OpenSSL &#8805; 1.0.1</item>
+ <item>(3) OpenSSL &#8805; 1.1.0</item>
+ </list>
+ </section>
+
+ <section>
+ <title>DSS</title>
+ <p>DSS is available with OpenSSL versions compatible with Erlang CRYPTO if not disabled by configuration.
+ To dynamically check availability, check that the atom <c>dss</c> is present in the
+ list with the <c>public_keys</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ </p>
+ </section>
+
+ <section>
+ <title>ECDSA</title>
+ <p>ECDSA is available with OpenSSL 0.9.8o or later if not disabled by configuration.
+ To dynamically check availability, check that the atom <c>ecdsa</c> is present in the
+ list with the <c>public_keys</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ If the atom <c>ec_gf2m</c> characteristic two field curves are available.
+ </p>
+ <p>The actual supported named curves could be checked by examining the list with the
+ <c>curves</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ </p>
+ </section>
+
+ <section>
+ <title>EdDSA</title>
+ <p>EdDSA is available with OpenSSL 1.1.1 or later if not disabled by configuration.
+ To dynamically check availability, check that the atom <c>eddsa</c> is present in the
+ list with the <c>public_keys</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ </p>
+ <p>Support for the curves ed25519 and ed448 is implemented.
+ The actual supported named curves could be checked by examining the list with the
+ <c>curves</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ </p>
+ </section>
+
+ <section>
+ <title>Diffie-Hellman</title>
+ <p>Diffie-Hellman computations are available with OpenSSL versions compatible with Erlang CRYPTO
+ if not disabled by configuration.
+ To dynamically check availability, check that the atom <c>dh</c> is present in the
+ list with the <c>public_keys</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ </p>
+ </section>
+
+ <section>
+ <title>Elliptic Curve Diffie-Hellman</title>
+ <p>Elliptic Curve Diffie-Hellman is available with OpenSSL 0.9.8o or later if not disabled by configuration.
+ To dynamically check availability, check that the atom <c>ecdh</c> is present in the
+ list with the <c>public_keys</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ </p>
+
+ <p>The Edward curves <c>x25519</c> and <c>x448</c> are supported with OpenSSL 1.1.1 or later
+ if not disabled by configuration.
+ </p>
+
+ <p>The actual supported named curves could be checked by examining the list with the
+ <c>curves</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ </p>
+ </section>
+
+ </section>
+
+
+</chapter>
+
+
+
+
+
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 464799b320..d1d1252f29 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -1,10 +1,9 @@
-<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>1999</year><year>2017</year>
+ <year>1999</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -23,275 +22,777 @@
<title>crypto</title>
</header>
- <module>crypto</module>
+ <module since="">crypto</module>
<modulesummary>Crypto Functions</modulesummary>
<description>
<p>This module provides a set of cryptographic functions.
</p>
- <list type="bulleted">
- <item>
- <p>Hash functions -
- <url href="http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf"> Secure Hash Standard</url>,
- <url href="http://www.ietf.org/rfc/rfc1321.txt"> The MD5 Message Digest Algorithm (RFC 1321)</url> and
- <url href="http://www.ietf.org/rfc/rfc1320.txt">The MD4 Message Digest Algorithm (RFC 1320)</url>
- </p>
- </item>
- <item>
- <p>Hmac functions - <url href="http://www.ietf.org/rfc/rfc2104.txt"> Keyed-Hashing for Message Authentication (RFC 2104) </url></p>
- </item>
- <item>
- <p>Cmac functions - <url href="http://www.ietf.org/rfc/rfc4493.txt">The AES-CMAC Algorithm (RFC 4493)</url></p>
- </item>
- <item>
- <p>Block ciphers - <url href="http://csrc.nist.gov/groups/ST/toolkit/block_ciphers.html"> </url> DES and AES in
- Block Cipher Modes - <url href="http://csrc.nist.gov/groups/ST/toolkit/BCM/index.html"> ECB, CBC, CFB, OFB, CTR and GCM </url></p>
- </item>
- <item>
- <p><url href="http://www.ietf.org/rfc/rfc1321.txt"> RSA encryption RFC 1321 </url> </p>
- </item>
- <item>
- <p>Digital signatures <url href="http://csrc.nist.gov/publications/drafts/fips186-3/fips_186-3.pdf">Digital Signature Standard (DSS)</url> and<url href="http://csrc.nist.gov/groups/STM/cavp/documents/dss2/ecdsa2vs.pdf"> Elliptic Curve Digital
- Signature Algorithm (ECDSA) </url> </p>
- </item>
- <item>
- <p><url href="http://www.ietf.org/rfc/rfc2945.txt"> Secure Remote Password Protocol (SRP - RFC 2945) </url></p>
- </item>
- <item>
- <p>gcm: Dworkin, M., "Recommendation for Block Cipher Modes of
- Operation: Galois/Counter Mode (GCM) and GMAC",
- National Institute of Standards and Technology SP 800-
- 38D, November 2007.</p>
- </item>
- </list>
+ <taglist>
+ <tag>Hash functions</tag>
+ <item>
+ <p></p>
+ <taglist>
+ <tag>SHA1, SHA2</tag>
+ <item>
+ <url href="https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf">
+ Secure Hash Standard [FIPS PUB 180-4]
+ </url>
+ </item>
+ <tag>SHA3</tag>
+ <item>
+ <url href="https://www.nist.gov/publications/sha-3-standard-permutation-based-hash-and-extendable-output-functions?pub_id=919061">
+ SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions [FIPS PUB 202]
+ </url>
+ </item>
+ <tag>BLAKE2</tag>
+ <item>
+ <url href="https://blake2.net/">BLAKE2 — fast secure hashing</url>
+ </item>
+ <tag>MD5</tag>
+ <item>
+ <url href="http://www.ietf.org/rfc/rfc1321.txt">The MD5 Message Digest Algorithm [RFC 1321]</url>
+ </item>
+ <tag>MD4</tag>
+ <item>
+ <url href="http://www.ietf.org/rfc/rfc1320.txt">The MD4 Message Digest Algorithm [RFC 1320]</url>
+ </item>
+ </taglist>
+ <p></p>
+ </item>
+
+ <tag>MACs - Message Authentication Codes</tag>
+ <item>
+ <p></p>
+ <taglist>
+ <tag>Hmac functions</tag>
+ <item>
+ <url href="http://www.ietf.org/rfc/rfc2104.txt">
+ Keyed-Hashing for Message Authentication [RFC 2104]
+ </url>
+ </item>
+ <tag>Cmac functions</tag>
+ <item>
+ <url href="http://www.ietf.org/rfc/rfc4493.txt">
+ The AES-CMAC Algorithm [RFC 4493]
+ </url>
+ </item>
+ <tag>POLY1305</tag>
+ <item>
+ <url href="http://www.ietf.org/rfc/rfc7539.txt">
+ ChaCha20 and Poly1305 for IETF Protocols [RFC 7539]
+ </url>
+ </item>
+ </taglist>
+ <p></p>
+ </item>
+
+ <tag>Symmetric Ciphers</tag>
+ <item>
+ <p></p>
+ <taglist>
+ <tag>DES, 3DES and AES</tag>
+ <item>
+ <url href="https://csrc.nist.gov/projects/block-cipher-techniques">Block Cipher Techniques [NIST]</url>
+ </item>
+ <tag>Blowfish</tag>
+ <item>
+ <url href="https://www.schneier.com/academic/archives/1994/09/description_of_a_new.html">
+ Fast Software Encryption, Cambridge Security Workshop Proceedings (December 1993), Springer-Verlag, 1994, pp. 191-204.
+ </url>
+ </item>
+ <tag>Chacha20</tag>
+ <item>
+ <url href="http://www.ietf.org/rfc/rfc7539.txt">
+ ChaCha20 and Poly1305 for IETF Protocols [RFC 7539]
+ </url>
+ </item>
+ <tag>Chacha20_poly1305</tag>
+ <item>
+ <url href="http://www.ietf.org/rfc/rfc7539.txt">
+ ChaCha20 and Poly1305 for IETF Protocols [RFC 7539]
+ </url>
+ </item>
+ </taglist>
+ <p></p>
+ </item>
+
+ <tag>Modes</tag>
+ <item>
+ <p></p>
+ <taglist>
+ <tag>ECB, CBC, CFB, OFB and CTR</tag>
+ <item>
+ <url href="https://csrc.nist.gov/publications/detail/sp/800-38a/final">
+ Recommendation for Block Cipher Modes of Operation: Methods and Techniques [NIST SP 800-38A]
+ </url>
+ </item>
+ <tag>GCM</tag>
+ <item>
+ <url href="https://csrc.nist.gov/publications/detail/sp/800-38d/final">
+ Recommendation for Block Cipher Modes of Operation: Galois/Counter Mode (GCM) and GMAC [NIST SP 800-38D]
+ </url>
+ </item>
+ <tag>CCM</tag>
+ <item>
+ <url href="https://nvlpubs.nist.gov/nistpubs/legacy/sp/nistspecialpublication800-38c.pdf">
+ Recommendation for Block Cipher Modes of Operation:
+ The CCM Mode for Authentication and Confidentiality [NIST SP 800-38C]
+ </url>
+ </item>
+ </taglist>
+ <p></p>
+ </item>
+
+ <tag>Asymetric Ciphers - Public Key Techniques</tag>
+ <item>
+ <p></p>
+ <taglist>
+ <tag>RSA</tag>
+ <item>
+ <url href="http://www.ietf.org/rfc/rfc3447.txt">
+ PKCS #1: RSA Cryptography Specifications [RFC 3447]
+ </url>
+ </item>
+ <tag>DSS</tag>
+ <item>
+ <url href="https://csrc.nist.gov/publications/detail/fips/186/4/final">
+ Digital Signature Standard (DSS) [FIPS 186-4]
+ </url>
+ </item>
+ <tag>ECDSA</tag>
+ <item>
+ <url href="http://csrc.nist.gov/groups/STM/cavp/documents/dss2/ecdsa2vs.pdf">
+ Elliptic Curve Digital Signature Algorithm [ECDSA]
+ </url>
+ </item>
+ <tag>SRP</tag>
+ <item>
+ <url href="http://www.ietf.org/rfc/rfc2945.txt">
+ The SRP Authentication and Key Exchange System [RFC 2945]
+ </url>
+ </item>
+ </taglist>
+ <p></p>
+ </item>
+ </taglist>
+
+ <note>
+ <p>The actual supported algorithms and features depends on their availability in the actual libcrypto used.
+ See the <seealso marker="crypto:crypto_app">crypto (App)</seealso> about dependencies.
+ </p>
+ <p>Enabling FIPS mode will also disable algorithms and features.
+ </p>
+ </note>
+
+ <p>The <seealso marker="users_guide">CRYPTO User's Guide</seealso> has more information on
+ FIPS, Engines and Algorithm Details like key lengths.
+ </p>
</description>
- <section>
- <title>DATA TYPES </title>
+ <datatypes>
+ <datatype_title>Ciphers, new API</datatype_title>
+ <datatype>
+ <name name="cipher"/>
+ <desc>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="cipher_no_iv"/>
+ <desc>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="cipher_iv"/>
+ <desc>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="cipher_aead"/>
+ <desc>
+ <p>Ciphers known by the CRYPTO application when using the
+ <seealso marker="crypto:new_api#the-new-api">new API</seealso>.</p>
+ <p>Note that this list might be reduced if the underlying libcrypto does not support all of them.</p>
+ </desc>
+ </datatype>
- <code>key_value() = integer() | binary() </code>
- <p>Always <c>binary()</c> when used as return value</p>
+ <datatype_title>Ciphers, old API</datatype_title>
+ <datatype>
+ <name name="block_cipher_with_iv"/>
+ <desc>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="block_cipher_without_iv"/>
+ <desc>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="stream_cipher"/>
+ <desc>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="aead_cipher"/>
+ <desc>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="cbc_cipher"/>
+ <desc>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="cfb_cipher"/>
+ <desc>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="ctr_cipher"/>
+ <desc>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="ecb_cipher"/>
+ <desc>
+ <p>Ciphers known by the CRYPTO application when using the
+ <seealso marker="crypto:new_api#the-old-api">old API</seealso>.</p>
+ <p>Note that this list might be reduced if the underlying libcrypto does not support all of them.</p>
+ </desc>
+ </datatype>
- <code>rsa_public() = [key_value()] = [E, N] </code>
- <p> Where E is the public exponent and N is public modulus. </p>
+ <datatype>
+ <name name="retired_cbc_cipher_aliases"/>
+ <desc>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="retired_cfb_cipher_aliases"/>
+ <desc>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="retired_ctr_cipher_aliases"/>
+ <desc>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="retired_ecb_cipher_aliases"/>
+ <desc>
+ <p>Alternative, old names of ciphers known by the CRYPTO application when using the
+ <seealso marker="crypto:new_api#the-old-api">old API</seealso>.
+ See <seealso marker="crypto:new_api#retired-cipher-names">Retired cipher names</seealso> for names to
+ use instead to be prepared for an easy convertion to the
+ <seealso marker="crypto:new_api#the-new-api">new API</seealso>.
+ </p>
+ <p>Note that this list might be reduced if the underlying libcrypto does not support all of them.</p>
+ </desc>
+ </datatype>
- <code>rsa_private() = [key_value()] = [E, N, D] | [E, N, D, P1, P2, E1, E2, C] </code>
- <p>Where E is the public exponent, N is public modulus and D is
- the private exponent. The longer key format contains redundant
- information that will make the calculation faster. P1,P2 are first
- and second prime factors. E1,E2 are first and second exponents. C
- is the CRT coefficient. Terminology is taken from <url href="http://www.ietf.org/rfc/rfc3477.txt"> RFC 3447</url>.</p>
+ <datatype_title>Digests and hash</datatype_title>
+ <datatype>
+ <name name="hash_algorithm"/>
+ <desc>
+ </desc>
+ </datatype>
- <code>dss_public() = [key_value()] = [P, Q, G, Y] </code>
- <p>Where P, Q and G are the dss parameters and Y is the public key.</p>
+ <datatype>
+ <name name="hmac_hash_algorithm"/>
+ <desc>
+ </desc>
+ </datatype>
- <code>dss_private() = [key_value()] = [P, Q, G, X] </code>
- <p>Where P, Q and G are the dss parameters and X is the private key.</p>
+ <datatype>
+ <name name="rsa_digest_type"/>
+ <desc>
+ </desc>
+ </datatype>
- <code>srp_public() = key_value() </code>
- <p>Where is <c>A</c> or <c>B</c> from <url href="http://srp.stanford.edu/design.html">SRP design</url></p>
+ <datatype>
+ <name name="dss_digest_type"/>
+ <desc>
+ </desc>
+ </datatype>
- <code>srp_private() = key_value() </code>
- <p>Where is <c>a</c> or <c>b</c> from <url href="http://srp.stanford.edu/design.html">SRP design</url></p>
+ <datatype>
+ <name name="ecdsa_digest_type"/>
+ <desc>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="sha1"/>
+ <name name="sha2"/>
+ <name name="sha3"/>
+ <name name="blake2"/>
+ <name name="compatibility_only_hash"/>
+ <desc>
+ <p>The <c>compatibility_only_hash()</c> algorithms are recommended only for compatibility with existing applications.</p>
+ </desc>
+ </datatype>
- <p>Where Verifier is <c>v</c>, Generator is <c>g</c> and Prime is<c> N</c>, DerivedKey is <c>X</c>, and Scrambler is
- <c>u</c> (optional will be generated if not provided) from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- Version = '3' | '6' | '6a'
- </p>
+ <datatype_title>Elliptic Curves</datatype_title>
+ <datatype>
+ <name name="ec_named_curve"/>
+ <name name="edwards_curve_dh"/>
+ <name name="edwards_curve_ed"/>
+ <desc>
+ <p>Note that some curves are disabled if FIPS is enabled.</p>
+ </desc>
+ </datatype>
- <code>dh_public() = key_value() </code>
+ <datatype>
+ <name name="ec_explicit_curve"/>
+ <name name="ec_field"/>
+ <name name="ec_curve"/>
+ <desc>
+ <p>Parametric curve definition.</p>
+ </desc>
+ </datatype>
- <code>dh_private() = key_value() </code>
+ <datatype>
+ <name name="ec_prime_field"/>
+ <name name="ec_characteristic_two_field"/>
+ <name name="ec_basis"/>
+ <desc>
+ <p>Curve definition details.</p>
+ </desc>
+ </datatype>
- <code>dh_params() = [key_value()] = [P, G] | [P, G, PrivateKeyBitLength]</code>
+ <datatype_title>Keys</datatype_title>
+ <datatype>
+ <name name="key"/>
+ <name name="des3_key"/>
+ <desc>
+ <p>For keylengths, iv-sizes and blocksizes see the
+ <seealso marker="crypto:algorithm_details#ciphers">User's Guide</seealso>.
+ </p>
+ <p>A key for des3 is a list of three iolists</p>
+ </desc>
+ </datatype>
- <code>ecdh_public() = key_value() </code>
+ <datatype>
+ <name name="key_integer"/>
+ <desc>
+ <p>Always <c>binary()</c> when used as return value</p>
+ </desc>
+ </datatype>
- <code>ecdh_private() = key_value() </code>
+ <datatype_title>Public/Private Keys</datatype_title>
+ <datatype>
+ <name name="rsa_public"/>
+ <name name="rsa_private"/>
+ <name name="rsa_params"/>
+ <desc>
+ <code>rsa_public() = [E, N]</code>
+ <code>rsa_private() = [E, N, D] | [E, N, D, P1, P2, E1, E2, C]</code>
+ <p>Where E is the public exponent, N is public modulus and D is
+ the private exponent. The longer key format contains redundant
+ information that will make the calculation faster. P1,P2 are first
+ and second prime factors. E1,E2 are first and second exponents. C
+ is the CRT coefficient. Terminology is taken from <url href="http://www.ietf.org/rfc/rfc3477.txt"> RFC 3447</url>.</p>
+ </desc>
+ </datatype>
- <code>ecdh_params() = ec_named_curve() | ec_explicit_curve()</code>
+ <datatype>
+ <name name="dss_public"/>
+ <name name="dss_private"/>
+ <desc>
+ <code>dss_public() = [P, Q, G, Y] </code>
+ <p>Where P, Q and G are the dss parameters and Y is the public key.</p>
- <code>ec_explicit_curve() =
- {ec_field(), Prime :: key_value(), Point :: key_value(), Order :: integer(),
- CoFactor :: none | integer()} </code>
+ <code>dss_private() = [P, Q, G, X] </code>
+ <p>Where P, Q and G are the dss parameters and X is the private key.</p>
+ </desc>
+ </datatype>
- <code>ec_field() = {prime_field, Prime :: integer()} |
- {characteristic_two_field, M :: integer(), Basis :: ec_basis()}</code>
+ <datatype>
+ <name name="ecdsa_public"/>
+ <name name="ecdsa_private"/>
+ <name name="ecdsa_params"/>
+ <desc>
+ </desc>
+ </datatype>
- <code>ec_basis() = {tpbasis, K :: non_neg_integer()} |
- {ppbasis, K1 :: non_neg_integer(), K2 :: non_neg_integer(), K3 :: non_neg_integer()} |
- onbasis</code>
+ <datatype>
+ <name name="eddsa_public"/>
+ <name name="eddsa_private"/>
+ <name name="eddsa_params"/>
+ <desc>
+ </desc>
+ </datatype>
- <code>ec_named_curve() ->
- sect571r1| sect571k1| sect409r1| sect409k1| secp521r1| secp384r1| secp224r1| secp224k1|
- secp192k1| secp160r2| secp128r2| secp128r1| sect233r1| sect233k1| sect193r2| sect193r1|
- sect131r2| sect131r1| sect283r1| sect283k1| sect163r2| secp256k1| secp160k1| secp160r1|
- secp112r2| secp112r1| sect113r2| sect113r1| sect239k1| sect163r1| sect163k1| secp256r1|
- secp192r1|
- brainpoolP160r1| brainpoolP160t1| brainpoolP192r1| brainpoolP192t1| brainpoolP224r1|
- brainpoolP224t1| brainpoolP256r1| brainpoolP256t1| brainpoolP320r1| brainpoolP320t1|
- brainpoolP384r1| brainpoolP384t1| brainpoolP512r1| brainpoolP512t1
- </code>
- <p>Note that the <em>sect</em> curves are GF2m (characteristic two) curves and are only supported if the
- underlying OpenSSL has support for them.
- See also <seealso marker="#supports-0">crypto:supports/0</seealso>
- </p>
+ <datatype>
+ <name name="srp_public"/>
+ <name name="srp_private"/>
+ <desc>
+ <code>srp_public() = key_integer() </code>
+ <p>Where is <c>A</c> or <c>B</c> from <url href="http://srp.stanford.edu/design.html">SRP design</url></p>
+
+ <code>srp_private() = key_integer() </code>
+ <p>Where is <c>a</c> or <c>b</c> from <url href="http://srp.stanford.edu/design.html">SRP design</url></p>
+ </desc>
+ </datatype>
- <marker id="engine_key_ref_type"/>
- <code>engine_key_ref() = #{engine := engine_ref(),
- key_id := key_id(),
- password => password()}</code>
+ <datatype>
+ <name name="srp_gen_params"/>
+ <name name="srp_comp_params"/>
+ <desc>
+ <marker id="type-srp_user_gen_params"/>
+ <code>srp_user_gen_params() = [DerivedKey::binary(), Prime::binary(), Generator::binary(), Version::atom()]</code>
+ <marker id="type-srp_host_gen_params"/>
+ <code>srp_host_gen_params() = [Verifier::binary(), Prime::binary(), Version::atom() ]</code>
+ <marker id="type-srp_user_comp_params"/>
+ <code>srp_user_comp_params() = [DerivedKey::binary(), Prime::binary(), Generator::binary(), Version::atom() | ScramblerArg::list()]</code>
+ <marker id="type-srp_host_comp_params"/>
+ <code>srp_host_comp_params() = [Verifier::binary(), Prime::binary(), Version::atom() | ScramblerArg::list()]</code>
+ <p>Where Verifier is <c>v</c>, Generator is <c>g</c> and Prime is<c> N</c>, DerivedKey is <c>X</c>, and Scrambler is
+ <c>u</c> (optional will be generated if not provided) from <url href="http://srp.stanford.edu/design.html">SRP design</url>
+ Version = '3' | '6' | '6a'
+ </p>
+ </desc>
+ </datatype>
- <code>engine_ref() = term()</code>
- <p>The result of a call to <seealso marker="#engine_load-3">engine_load/3</seealso>.
- </p>
+ <datatype_title>Public Key Ciphers</datatype_title>
- <code>key_id() = string() | binary()</code>
- <p>Identifies the key to be used. The format depends on the loaded engine. It is passed to
- the <c>ENGINE_load_(private|public)_key</c> functions in libcrypto.
- </p>
+ <datatype>
+ <name name="pk_encrypt_decrypt_algs"/>
+ <desc>
+ <p>Algorithms for public key encrypt/decrypt. Only RSA is supported.</p>
+ </desc>
+ </datatype>
- <code>password() = string() | binary()</code>
- <p>The key's password
- </p>
+ <datatype>
+ <name name="pk_encrypt_decrypt_opts"/>
+ <name name="rsa_opt"/>
+ <name name="rsa_padding"/>
+ <desc>
+ <p>Options for public key encrypt/decrypt. Only RSA is supported.</p>
+ <warning>
+ <!-- In RefMan rsa_opt(), rsa_sign_verify_opt() and User's man RSA -->
+ <p>The RSA options are experimental.
+ </p>
+ <p>The exact set of options and there syntax <em>may</em> be changed
+ without prior notice.</p>
+ </warning>
+ </desc>
+ </datatype>
- <code>stream_cipher() = rc4 | aes_ctr </code>
+ <datatype>
+ <name name="rsa_compat_opts"/>
+ <desc>
+ <p>Those option forms are kept only for compatibility and should not be used in new code.</p>
+ </desc>
+ </datatype>
- <code>block_cipher() = aes_cbc | aes_cfb8 | aes_cfb128 | aes_ige256 | blowfish_cbc |
- blowfish_cfb64 | des_cbc | des_cfb | des3_cbc | des3_cfb | des_ede3 | rc2_cbc </code>
+ <datatype_title>Public Key Sign and Verify</datatype_title>
- <code>aead_cipher() = aes_gcm | chacha20_poly1305 </code>
+ <datatype>
+ <name name="pk_sign_verify_algs"/>
+ <desc>
+ <p>Algorithms for sign and verify.</p>
+ </desc>
+ </datatype>
- <code>stream_key() = aes_key() | rc4_key() </code>
+ <datatype>
+ <name name="pk_sign_verify_opts"/>
+ <name name="rsa_sign_verify_opt"/>
+ <name name="rsa_sign_verify_padding"/>
+ <desc>
+ <p>Options for sign and verify.</p>
+ <warning>
+ <!-- In RefMan rsa_opt(), rsa_sign_verify_opt() and User's man RSA -->
+ <p>The RSA options are experimental.
+ </p>
+ <p>The exact set of options and there syntax <em>may</em> be changed
+ without prior notice.</p>
+ </warning>
+ </desc>
+ </datatype>
- <code>block_key() = aes_key() | blowfish_key() | des_key()| des3_key() </code>
+ <datatype_title>Diffie-Hellman Keys and parameters</datatype_title>
+ <datatype>
+ <name name="dh_public"/>
+ <name name="dh_private"/>
+ <desc>
+ </desc>
+ </datatype>
- <code>aes_key() = iodata() </code> <p>Key length is 128, 192 or 256 bits</p>
+ <datatype>
+ <name name="dh_params"/>
+ <desc>
+ <code>dh_params() = [P, G] | [P, G, PrivateKeyBitLength]</code>
+ </desc>
+ </datatype>
- <code>rc4_key() = iodata() </code> <p>Variable key length from 8 bits up to 2048 bits (usually between 40 and 256)</p>
+ <datatype>
+ <name name="ecdh_public"/>
+ <name name="ecdh_private"/>
+ <name name="ecdh_params"/>
+ <desc>
+ </desc>
+ </datatype>
- <code>blowfish_key() = iodata() </code> <p>Variable key length from 32 bits up to 448 bits</p>
+ <datatype_title>Types for Engines</datatype_title>
- <code>des_key() = iodata() </code> <p>Key length is 64 bits (in CBC mode only 8 bits are used)</p>
+ <datatype>
+ <name name="engine_key_ref"/>
+ <name name="engine_ref"/>
+ <desc>
+ <p>The result of a call to <seealso marker="#engine_load-3">engine_load/3</seealso>.
+ </p>
+ </desc>
+ </datatype>
- <code>des3_key() = [binary(), binary(), binary()] </code> <p>Each key part is 64 bits (in CBC mode only 8 bits are used)</p>
+ <datatype>
+ <name name="key_id"/>
+ <desc>
+ <p>Identifies the key to be used. The format depends on the loaded engine. It is passed to
+ the <c>ENGINE_load_(private|public)_key</c> functions in libcrypto.
+ </p>
+ </desc>
+ </datatype>
- <code>digest_type() = md5 | sha | sha224 | sha256 | sha384 | sha512</code>
+ <datatype>
+ <name name="password"/>
+ <desc>
+ <p>The password of the key stored in an engine.
+ </p>
+ </desc>
+ </datatype>
- <code>rsa_digest_type() = md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512</code>
+ <datatype>
+ <name name="engine_method_type"/>
+ </datatype>
- <code>dss_digest_type() = sha | sha224 | sha256 | sha384 | sha512</code> <p>Note that the actual supported
- dss_digest_type depends on the underlying crypto library. In OpenSSL version >= 1.0.1 the listed digest are supported, while in 1.0.0 only sha, sha224 and sha256 are supported. In version 0.9.8 only sha is supported.</p>
+ <datatype>
+ <name name="engine_cmnd"/>
+ <desc>
+ <p>Pre and Post commands for <seealso marker="#engine_load-3">engine_load/3 and /4</seealso>.
+ </p>
+ </desc>
+ </datatype>
+
+ <datatype_title>Internal data types</datatype_title>
+
+ <datatype>
+ <name name="stream_state"/>
+ <name name="hmac_state"/>
+ <name name="hash_state"/>
+ <name name="crypto_state"/>
+ <desc>
+ <p>Contexts with an internal state that should not be manipulated but passed between function calls.
+ </p>
+ </desc>
+ </datatype>
- <code>ecdsa_digest_type() = sha | sha224 | sha256 | sha384 | sha512</code>
+ <datatype_title>Error types</datatype_title>
- <code>sign_options() = [{rsa_pad, rsa_sign_padding()} | {rsa_pss_saltlen, integer()}]</code>
+ <datatype>
+ <name name="run_time_error"/>
+ <desc>
+ <p>The exception <c>error:badarg</c> signifies that one or more arguments are of wrong data type,
+ or are otherwise badly formed.
+ </p>
+ <p>The exception <c>error:notsup</c> signifies that the algorithm is known but is not supported
+ by current underlying libcrypto or explicitly disabled when building that.
+ </p>
+ <p>For a list of supported algorithms, see <seealso marker="#supports-0">supports/0</seealso>.
+ </p>
+ </desc>
+ </datatype>
- <code>rsa_sign_padding() = rsa_pkcs1_padding | rsa_pkcs1_pss_padding</code>
+ <datatype>
+ <name name="descriptive_error"/>
+ <desc>
+ <p>This is a more developed variant of the older
+ <seealso marker="#type-run_time_error">run_time_error()</seealso>.
+ </p>
+ <p>The exception is:</p>
+ <pre>
+ {Tag, {C_FileName,LineNumber}, Description}
+
+ Tag = badarg | notsup | error
+ C_FileName = string()
+ LineNumber = integer()
+ Description = string()
+ </pre>
+
+ <p>It is like the older type an exception of the <c>error</c> class. In addition they contain
+ a descriptive text in English. That text is targeted to a developer. Examples are "Bad key size"
+ or "Cipher id is not an atom".
+ </p>
+ <p>The exception tags are:</p>
+ <taglist>
+ <tag><c>badarg</c></tag>
+ <item><p>Signifies that one or more arguments are of wrong data type or are otherwise badly formed.</p>
+ </item>
+
+ <tag><c>notsup</c></tag>
+ <item><p>Signifies that the algorithm is known but is not supported by current underlying libcrypto
+ or explicitly disabled when building that one.</p>
+ </item>
+
+ <tag><c>error</c></tag>
+ <item><p>An error condition that should not occur, for example a memory allocation failed or
+ the underlying cryptolib returned an error code, for example "Can't initialize context, step 1".
+ Thoose text usually needs searching the C-code to be understood.</p>
+ </item>
+ </taglist>
+ <p>To catch the exception, use for example:</p>
+ <code>
+ try crypto:crypto_init(Ciph, Key, IV, true)
+ catch
+ error:{Tag, {C_FileName,LineNumber}, Description} ->
+ do_something(......)
+ .....
+ end
+ </code>
+ </desc>
+ </datatype>
- <code> hash_algorithms() = md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512 </code> <p>md4 is also supported for hash_init/1 and hash/2.
- Note that both md4 and md5 are recommended only for compatibility with existing applications.
- </p>
- <code> cipher_algorithms() = aes_cbc | aes_cfb8 | aes_cfb128 | aes_ctr | aes_gcm |
- aes_ige256 | blowfish_cbc | blowfish_cfb64 | chacha20_poly1305 | des_cbc |
- des_cfb | des3_cbc | des3_cfb | des_ede3 | rc2_cbc | rc4 </code>
- <code> mac_algorithms() = hmac | cmac</code>
- <code> public_key_algorithms() = rsa |dss | ecdsa | dh | ecdh | ec_gf2m</code>
- <p>Note that ec_gf2m is not strictly a public key algorithm, but a restriction on what curves are supported
- with ecdsa and ecdh.
- </p>
- <code>engine_method_type() = engine_method_rsa | engine_method_dsa | engine_method_dh |
- engine_method_rand | engine_method_ecdh | engine_method_ecdsa |
- engine_method_ciphers | engine_method_digests | engine_method_store |
- engine_method_pkey_meths | engine_method_pkey_asn1_meths</code>
+ </datatypes>
- </section>
+ <!--================ FUNCTIONS ================-->
+ <section>
+ <title>New API</title>
+ </section>
<funcs>
<func>
- <name>block_encrypt(Type, Key, PlainText) -> CipherText</name>
- <fsummary>Encrypt <c>PlainText</c> according to <c>Type</c> block cipher</fsummary>
- <type>
- <v>Type = des_ecb | blowfish_ecb | aes_ecb </v>
- <v>Key = block_key() </v>
- <v>PlainText = iodata() </v>
- </type>
+ <name name="crypto_init" arity="3" since="OTP 22.0"/>
+ <fsummary>Initializes a series of encryptions or decryptions</fsummary>
<desc>
- <p>Encrypt <c>PlainText</c> according to <c>Type</c> block cipher.</p>
- <p>May throw exception <c>notsup</c> in case the chosen <c>Type</c>
- is not supported by the underlying OpenSSL implementation.</p>
+ <p>As <seealso marker="#crypto_init/4">crypto_init/4</seealso> but for ciphers without IVs.</p>
</desc>
</func>
<func>
- <name>block_decrypt(Type, Key, CipherText) -> PlainText</name>
- <fsummary>Decrypt <c>CipherText</c> according to <c>Type</c> block cipher</fsummary>
- <type>
- <v>Type = des_ecb | blowfish_ecb | aes_ecb </v>
- <v>Key = block_key() </v>
- <v>PlainText = iodata() </v>
- </type>
+ <name name="crypto_init" arity="4" since="OTP 22.0"/>
+ <fsummary>Initializes a series of encryptions or decryptions</fsummary>
<desc>
- <p>Decrypt <c>CipherText</c> according to <c>Type</c> block cipher.</p>
- <p>May throw exception <c>notsup</c> in case the chosen <c>Type</c>
- is not supported by the underlying OpenSSL implementation.</p>
+ <p>Part of the <seealso marker="crypto:new_api#the-new-api">new API</seealso>.
+ Initializes a series of encryptions or decryptions and creates an internal state
+ with a reference that is returned.
+ The actual encryption or decryption is done by
+ <seealso marker="crypto#crypto_update/2">crypto_update/2</seealso>.
+ </p>
+ <p>For encryption, set the <c>EncryptFlag</c> to <c>true</c>. For decryption, set it to <c>false</c>.
+ </p>
+ <p>See <seealso marker="crypto:new_api#examples-of-crypto_init-4-and-crypto_update-2">
+ examples in the User's Guide.</seealso>
+ </p>
</desc>
</func>
<func>
- <name>block_encrypt(Type, Key, Ivec, PlainText) -> CipherText</name>
- <name>block_encrypt(AeadType, Key, Ivec, {AAD, PlainText}) -> {CipherText, CipherTag}</name>
- <name>block_encrypt(aes_gcm, Key, Ivec, {AAD, PlainText, TagLength}) -> {CipherText, CipherTag}</name>
- <fsummary>Encrypt <c>PlainText</c> according to <c>Type</c> block cipher</fsummary>
- <type>
- <v>Type = block_cipher() </v>
- <v>AeadType = aead_cipher() </v>
- <v>Key = block_key() </v>
- <v>PlainText = iodata() </v>
- <v>AAD = IVec = CipherText = CipherTag = binary()</v>
- <v>TagLength = 1..16</v>
- </type>
+ <name name="crypto_update" arity="2" since="OTP 22.0"/>
+ <fsummary>Do an actual crypto operation on a part of the full text</fsummary>
<desc>
- <p>Encrypt <c>PlainText</c> according to <c>Type</c> block cipher.
- <c>IVec</c> is an arbitrary initializing vector.</p>
- <p>In AEAD (Authenticated Encryption with Associated Data) mode, encrypt
- <c>PlainText</c>according to <c>Type</c> block cipher and calculate
- <c>CipherTag</c> that also authenticates the <c>AAD</c> (Associated Authenticated Data).</p>
- <p>May throw exception <c>notsup</c> in case the chosen <c>Type</c>
- is not supported by the underlying OpenSSL implementation.</p>
+ <p>Part of the <seealso marker="crypto:new_api#the-new-api">new API</seealso>.
+ It does an actual crypto operation on a part of the full text. If the part is less
+ than a number of full blocks, only the full blocks (possibly none) are encrypted
+ or decrypted and the remaining bytes are saved to the next <c>crypto_update</c> operation.
+ The <c>State</c> should be created with
+ <seealso marker="crypto#crypto_init/3">crypto_init/3</seealso>
+ or
+ <seealso marker="crypto#crypto_init/4">crypto_init/4</seealso>.
+ </p>
+ <p>See <seealso marker="crypto:new_api#examples-of-crypto_init-4-and-crypto_update-2">
+ examples in the User's Guide.</seealso>
+ </p>
</desc>
</func>
<func>
- <name>block_decrypt(Type, Key, Ivec, CipherText) -> PlainText</name>
- <name>block_decrypt(AeadType, Key, Ivec, {AAD, CipherText, CipherTag}) -> PlainText | error</name>
- <fsummary>Decrypt <c>CipherText</c> according to <c>Type</c> block cipher</fsummary>
- <type>
- <v>Type = block_cipher() </v>
- <v>AeadType = aead_cipher() </v>
- <v>Key = block_key() </v>
- <v>PlainText = iodata() </v>
- <v>AAD = IVec = CipherText = CipherTag = binary()</v>
- </type>
+ <name name="crypto_dyn_iv_init" arity="3" since="OTP 22.0"/>
+ <fsummary>Initializes a series of encryptions or decryptions where the IV is provided later</fsummary>
<desc>
- <p>Decrypt <c>CipherText</c> according to <c>Type</c> block cipher.
- <c>IVec</c> is an arbitrary initializing vector.</p>
- <p>In AEAD (Authenticated Encryption with Associated Data) mode, decrypt
- <c>CipherText</c>according to <c>Type</c> block cipher and check the authenticity
- the <c>PlainText</c> and <c>AAD</c> (Associated Authenticated Data) using the
- <c>CipherTag</c>. May return <c>error</c> if the decryption or validation fail's</p>
- <p>May throw exception <c>notsup</c> in case the chosen <c>Type</c>
- is not supported by the underlying OpenSSL implementation.</p>
+ <p>Part of the <seealso marker="crypto:new_api#the-new-api">new API</seealso>.
+ Initializes a series of encryptions or decryptions where the IV is provided later.
+ The actual encryption or decryption is done by
+ <seealso marker="crypto#crypto_dyn_iv_update/3">crypto_dyn_iv_update/3</seealso>.
+ </p>
+ <p>For encryption, set the <c>EncryptFlag</c> to <c>true</c>. For decryption, set it to <c>false</c>.
+ </p>
</desc>
</func>
- <func>
- <name>bytes_to_integer(Bin) -> Integer </name>
- <fsummary>Convert binary representation, of an integer, to an Erlang integer.</fsummary>
- <type>
- <v>Bin = binary() - as returned by crypto functions</v>
+ <func>
+ <name name="crypto_dyn_iv_update" arity="3" since="OTP 22.0"/>
+ <fsummary>Do an actual crypto operation on a part of the full text and the IV is supplied for each part</fsummary>
+ <desc>
+ <p>Part of the <seealso marker="crypto:new_api#the-new-api">new API</seealso>.
+ Do an actual crypto operation on a part of the full text and the IV is supplied for each part.
+ The <c>State</c> should be created with
+ <seealso marker="crypto#crypto_dyn_iv_init/3">crypto_dyn_iv_init/3</seealso>.
+ </p>
+ </desc>
+ </func>
- <v>Integer = integer() </v>
- </type>
+ <func>
+ <name name="crypto_one_time" arity="4" since="OTP 22.0"/>
+ <fsummary>Do a complete encrypt or decrypt of the full text</fsummary>
+ <desc>
+ <p>As <seealso marker="#crypto_one_time/5">crypto_one_time/5</seealso> but for ciphers without IVs.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="crypto_one_time" arity="5" since="OTP 22.0"/>
+ <fsummary>Do a complete encrypt or decrypt of the full text</fsummary>
+ <desc>
+ <p>Part of the <seealso marker="crypto:new_api#the-new-api">new API</seealso>.
+ Do a complete encrypt or decrypt of the full text in the argument <c>Data</c>.
+ </p>
+ <p>For encryption, set the <c>EncryptFlag</c> to <c>true</c>. For decryption, set it to <c>false</c>.
+ </p>
+ <p>See <seealso marker="crypto:new_api#example-of-crypto_one_time-5">examples in the User's Guide.</seealso>
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="crypto_one_time_aead" arity="6" since="OTP 22.0"/>
+ <name name="crypto_one_time_aead" arity="7" since="OTP 22.0"/>
+ <fsummary>Do a complete encrypt or decrypt with an AEAD cipher of the full text</fsummary>
+ <desc>
+ <p>Part of the <seealso marker="crypto:new_api#the-new-api">new API</seealso>.
+ Do a complete encrypt or decrypt with an AEAD cipher of the full text.
+ </p>
+ <p>For encryption, set the <c>EncryptFlag</c> to <c>true</c> and set the <c>TagOrTagLength</c>
+ to the wanted size of the tag, that is, the tag length. If the default length is wanted, the
+ <c>crypto_aead/6</c> form may be used.
+ </p>
+ <p>For decryption, set the <c>EncryptFlag</c> to <c>false</c> and put the tag to be checked
+ in the argument <c>TagOrTagLength</c>.
+ </p>
+ <p>See <seealso marker="crypto:new_api#example-of-crypto_one_time_aead-6">examples in the User's Guide.</seealso>
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="supports" arity="1" since="OTP 22.0"/>
+ <fsummary>Provide a list of available crypto algorithms.</fsummary>
+ <desc>
+ <p> Can be used to determine which crypto algorithms that are supported
+ by the underlying libcrypto library</p>
+ <p>See <seealso marker="#hash_info-1">hash_info/1</seealso> and <seealso marker="#cipher_info-1">cipher_info/1</seealso>
+ for information about the hash and cipher algorithms.
+ </p>
+ </desc>
+ </func>
+
+ </funcs>
+
+ <section>
+ <title>API kept from previous versions</title>
+ </section>
+
+ <funcs>
+ <func>
+ <name name="bytes_to_integer" arity="1" since="OTP R16B01"/>
+ <fsummary>Convert binary representation, of an integer, to an Erlang integer.</fsummary>
<desc>
<p>Convert binary representation, of an integer, to an Erlang integer.
</p>
@@ -299,17 +800,8 @@
</func>
<func>
- <name>compute_key(Type, OthersPublicKey, MyKey, Params) -> SharedSecret</name>
+ <name name="compute_key" arity="4" since="OTP R16B01"/>
<fsummary>Computes the shared secret</fsummary>
- <type>
- <v> Type = dh | ecdh | srp </v>
- <v>OthersPublicKey = dh_public() | ecdh_public() | srp_public() </v>
- <v>MyKey = dh_private() | ecdh_private() | {srp_public(),srp_private()}</v>
- <v>Params = dh_params() | ecdh_params() | SrpUserParams | SrpHostParams</v>
- <v>SrpUserParams = {user, [DerivedKey::binary(), Prime::binary(), Generator::binary(), Version::atom() | [Scrambler:binary()]]} </v>
- <v>SrpHostParams = {host, [Verifier::binary(), Prime::binary(), Version::atom() | [Scrambler::binary]]} </v>
- <v>SharedSecret = binary()</v>
- </type>
<desc>
<p>Computes the shared secret from the private key and the other party's public key.
See also <seealso marker="public_key:public_key#compute_key-2">public_key:compute_key/2</seealso>
@@ -318,85 +810,61 @@
</func>
<func>
- <name>exor(Data1, Data2) -> Result</name>
+ <name name="exor" arity="2" since=""/>
<fsummary>XOR data</fsummary>
- <type>
- <v>Data1, Data2 = iodata()</v>
- <v>Result = binary()</v>
- </type>
<desc>
<p>Performs bit-wise XOR (exclusive or) on the data supplied.</p>
</desc>
</func>
- <func>
- <name>generate_key(Type, Params) -> {PublicKey, PrivKeyOut} </name>
- <name>generate_key(Type, Params, PrivKeyIn) -> {PublicKey, PrivKeyOut} </name>
+
+ <func>
+ <name name="generate_key" arity="2" since="OTP R16B01"/>
+ <name name="generate_key" arity="3" since="OTP R16B01"/>
<fsummary>Generates a public key of type <c>Type</c></fsummary>
- <type>
- <v> Type = dh | ecdh | rsa | srp </v>
- <v>Params = dh_params() | ecdh_params() | RsaParams | SrpUserParams | SrpHostParams </v>
- <v>RsaParams = {ModulusSizeInBits::integer(), PublicExponent::key_value()}</v>
- <v>SrpUserParams = {user, [Generator::binary(), Prime::binary(), Version::atom()]}</v>
- <v>SrpHostParams = {host, [Verifier::binary(), Generator::binary(), Prime::binary(), Version::atom()]}</v>
- <v>PublicKey = dh_public() | ecdh_public() | rsa_public() | srp_public() </v>
- <v>PrivKeyIn = undefined | dh_private() | ecdh_private() | srp_private() </v>
- <v>PrivKeyOut = dh_private() | ecdh_private() | rsa_private() | srp_private() </v>
- </type>
<desc>
<p>Generates a public key of type <c>Type</c>.
See also <seealso marker="public_key:public_key#generate_key-1">public_key:generate_key/1</seealso>.
- May throw exception an exception of class <c>error</c>:
+ May raise exception:
</p>
<list type="bulleted">
- <item><c>badarg</c>: an argument is of wrong type or has an illegal value,</item>
- <item><c>low_entropy</c>: the random generator failed due to lack of secure "randomness",</item>
- <item><c>computation_failed</c>: the computation fails of another reason than <c>low_entropy</c>.</item>
+ <item><c>error:badarg</c>: an argument is of wrong type or has an illegal value,</item>
+ <item><c>error:low_entropy</c>: the random generator failed due to lack of secure "randomness",</item>
+ <item><c>error:computation_failed</c>: the computation fails of another reason than <c>low_entropy</c>.</item>
</list>
<note>
<p>RSA key generation is only available if the runtime was
built with dirty scheduler support. Otherwise, attempting to
- generate an RSA key will throw exception <c>error:notsup</c>.</p>
+ generate an RSA key will raise exception <c>error:notsup</c>.</p>
</note>
</desc>
</func>
<func>
- <name>hash(Type, Data) -> Digest</name>
+ <name name="hash" arity="2" since="OTP R15B02"/>
<fsummary></fsummary>
- <type>
- <v>Type = md4 | hash_algorithms()</v>
- <v>Data = iodata()</v>
- <v>Digest = binary()</v>
- </type>
<desc>
<p>Computes a message digest of type <c>Type</c> from <c>Data</c>.</p>
- <p>May throw exception <c>notsup</c> in case the chosen <c>Type</c>
- is not supported by the underlying OpenSSL implementation.</p>
+ <p>May raise exception <c>error:notsup</c> in case the chosen <c>Type</c>
+ is not supported by the underlying libcrypto implementation.</p>
</desc>
</func>
<func>
- <name>hash_init(Type) -> Context</name>
+ <name name="hash_init" arity="1" since="OTP R15B02"/>
<fsummary></fsummary>
- <type>
- <v>Type = md4 | hash_algorithms()</v>
- </type>
<desc>
<p>Initializes the context for streaming hash operations. <c>Type</c> determines
which digest to use. The returned context should be used as argument
to <seealso marker="#hash_update-2">hash_update</seealso>.</p>
- <p>May throw exception <c>notsup</c> in case the chosen <c>Type</c>
- is not supported by the underlying OpenSSL implementation.</p>
+ <p>May raise exception <c>error:notsup</c> in case the chosen <c>Type</c>
+ is not supported by the underlying libcrypto implementation.</p>
</desc>
</func>
<func>
- <name>hash_update(Context, Data) -> NewContext</name>
+ <name name="hash_update" arity="2" since="OTP R15B02"/>
<fsummary></fsummary>
- <type>
- <v>Data = iodata()</v>
- </type>
<desc>
<p>Updates the digest represented by <c>Context</c> using the given <c>Data</c>. <c>Context</c>
must have been generated using <seealso marker="#hash_init-1">hash_init</seealso>
@@ -405,12 +873,10 @@
or <seealso marker="#hash_final-1">hash_final</seealso>.</p>
</desc>
</func>
+
<func>
- <name>hash_final(Context) -> Digest</name>
+ <name name="hash_final" arity="1" since="OTP R15B02"/>
<fsummary></fsummary>
- <type>
- <v>Digest = binary()</v>
- </type>
<desc>
<p>Finalizes the hash operation referenced by <c>Context</c> returned
from a previous call to <seealso marker="#hash_update-2">hash_update</seealso>.
@@ -420,16 +886,9 @@
</func>
<func>
- <name>hmac(Type, Key, Data) -> Mac</name>
- <name>hmac(Type, Key, Data, MacLength) -> Mac</name>
+ <name name="hmac" arity="3" since="OTP R16B"/>
+ <name name="hmac" arity="4" since="OTP R16B"/>
<fsummary></fsummary>
- <type>
- <v>Type = hash_algorithms() - except ripemd160</v>
- <v>Key = iodata()</v>
- <v>Data = iodata()</v>
- <v>MacLength = integer()</v>
- <v>Mac = binary()</v>
- </type>
<desc>
<p>Computes a HMAC of type <c>Type</c> from <c>Data</c> using
<c>Key</c> as the authentication key.</p> <p><c>MacLength</c>
@@ -438,13 +897,8 @@
</func>
<func>
- <name>hmac_init(Type, Key) -> Context</name>
+ <name name="hmac_init" arity="2" since="OTP R14B03"/>
<fsummary></fsummary>
- <type>
- <v>Type = hash_algorithms() - except ripemd160</v>
- <v>Key = iodata()</v>
- <v>Context = binary()</v>
- </type>
<desc>
<p>Initializes the context for streaming HMAC operations. <c>Type</c> determines
which hash function to use in the HMAC operation. <c>Key</c> is the authentication
@@ -453,12 +907,8 @@
</func>
<func>
- <name>hmac_update(Context, Data) -> NewContext</name>
+ <name name="hmac_update" arity="2" since="OTP R14B03"/>
<fsummary></fsummary>
- <type>
- <v>Context = NewContext = binary()</v>
- <v>Data = iodata()</v>
- </type>
<desc>
<p>Updates the HMAC represented by <c>Context</c> using the given <c>Data</c>. <c>Context</c>
must have been generated using an HMAC init function (such as
@@ -471,16 +921,13 @@
call to hmac_update or hmac_final. The semantics of reusing old contexts
in any way is undefined and could even crash the VM in earlier releases.
The reason for this limitation is a lack of support in the underlying
- OpenSSL API.</p></warning>
+ libcrypto API.</p></warning>
</desc>
</func>
<func>
- <name>hmac_final(Context) -> Mac</name>
+ <name name="hmac_final" arity="1" since="OTP R14B03"/>
<fsummary></fsummary>
- <type>
- <v>Context = Mac = binary()</v>
- </type>
<desc>
<p>Finalizes the HMAC operation referenced by <c>Context</c>. The size of the resultant MAC is
determined by the type of hash function used to generate it.</p>
@@ -488,12 +935,8 @@
</func>
<func>
- <name>hmac_final_n(Context, HashLen) -> Mac</name>
+ <name name="hmac_final_n" arity="2" since="OTP R14B03"/>
<fsummary></fsummary>
- <type>
- <v>Context = Mac = binary()</v>
- <v>HashLen = non_neg_integer()</v>
- </type>
<desc>
<p>Finalizes the HMAC operation referenced by <c>Context</c>. <c>HashLen</c> must be greater than
zero. <c>Mac</c> will be a binary with at most <c>HashLen</c> bytes. Note that if HashLen is greater than the actual number of bytes returned from the underlying hash, the returned hash will have fewer than <c>HashLen</c> bytes.</p>
@@ -501,16 +944,9 @@
</func>
<func>
- <name>cmac(Type, Key, Data) -> Mac</name>
- <name>cmac(Type, Key, Data, MacLength) -> Mac</name>
+ <name name="cmac" arity="3" since="OTP 20.0"/>
+ <name name="cmac" arity="4" since="OTP 20.0"/>
<fsummary>Calculates the Cipher-based Message Authentication Code.</fsummary>
- <type>
- <v>Type = block_cipher()</v>
- <v>Key = iodata()</v>
- <v>Data = iodata()</v>
- <v>MacLength = integer()</v>
- <v>Mac = binary()</v>
- </type>
<desc>
<p>Computes a CMAC of type <c>Type</c> from <c>Data</c> using
<c>Key</c> as the authentication key.</p> <p><c>MacLength</c>
@@ -519,20 +955,21 @@
</func>
<func>
- <name>info_fips() -> Status</name>
+ <name name="info_fips" arity="0" since="OTP 20.0"/>
<fsummary>Provides information about the FIPS operating status.</fsummary>
- <type>
- <v>Status = enabled | not_enabled | not_supported</v>
- </type>
<desc>
<p>Provides information about the FIPS operating status of
- crypto and the underlying OpenSSL library. If crypto was built
+ crypto and the underlying libcrypto library. If crypto was built
with FIPS support this can be either <c>enabled</c> (when
running in FIPS mode) or <c>not_enabled</c>. For other builds
- this value is always <c>not_supported</c>.</p>
+ this value is always <c>not_supported</c>.
+ </p>
+ <p>See <seealso marker="#enable_fips_mode-1">enable_fips_mode/1</seealso> about how to enable
+ FIPS mode.
+ </p>
<warning>
<p>In FIPS mode all non-FIPS compliant algorithms are
- disabled and throw exception <c>not_supported</c>. Check
+ disabled and raise exception <c>error:notsup</c>. Check
<seealso marker="#supports-0">supports</seealso> that in
FIPS mode returns the restricted list of available
algorithms.</p>
@@ -541,13 +978,23 @@
</func>
<func>
- <name>info_lib() -> [{Name,VerNum,VerStr}]</name>
+ <name name="enable_fips_mode" arity="1" since="OTP 21.1"/>
+ <fsummary>Change FIPS mode.</fsummary>
+ <desc>
+ <p>Enables (<c>Enable = true</c>) or disables (<c>Enable = false</c>) FIPS mode. Returns <c>true</c> if
+ the operation was successful or <c>false</c> otherwise.
+ </p>
+ <p>Note that to enable FIPS mode succesfully, OTP must be built with the configure option <c>--enable-fips</c>,
+ and the underlying libcrypto must also support FIPS.
+ </p>
+ <p>See also <seealso marker="#info_fips-0">info_fips/0</seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="info_lib" arity="0" since=""/>
<fsummary>Provides information about the libraries used by crypto.</fsummary>
- <type>
- <v>Name = binary()</v>
- <v>VerNum = integer()</v>
- <v>VerStr = binary()</v>
- </type>
<desc>
<p>Provides the name and version of the libraries used by crypto.</p>
<p><c>Name</c> is the name of the library. <c>VerNum</c> is
@@ -560,52 +1007,78 @@
<note><p>
From OTP R16 the <em>numeric version</em> represents the version of the OpenSSL
<em>header files</em> (<c>openssl/opensslv.h</c>) used when crypto was compiled.
- The text variant represents the OpenSSL library used at runtime.
+ The text variant represents the libcrypto library used at runtime.
In earlier OTP versions both numeric and text was taken from the library.
</p></note>
</desc>
</func>
<func>
- <name>mod_pow(N, P, M) -> Result</name>
+ <name name="hash_info" arity="1" since="OTP 22.0"/>
+ <fsummary>Information about supported hash algorithms.</fsummary>
+ <desc>
+ <p>Provides a map with information about block_size, size and possibly other properties of the
+ hash algorithm in question.
+ </p>
+ <p>For a list of supported hash algorithms, see <seealso marker="#supports-0">supports/0</seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="cipher_info" arity="1" since="OTP 22.0"/>
+ <fsummary>Information about supported ciphers.</fsummary>
+ <desc>
+ <p>Provides a map with information about block_size, key_length, iv_length and possibly other properties of the
+ cipher algorithm in question.
+ </p>
+ <note>
+ <p>The ciphers <c>aes_cbc</c>, <c>aes_cfb8</c>, <c>aes_cfb128</c>, <c>aes_ctr</c>,
+ <c>aes_ecb</c>, <c>aes_gcm</c> and <c>aes_ccm</c>
+ has no keylength in the <c>Type</c> as opposed to for example <c>aes_128_ctr</c>. They adapt to the length of
+ the key provided in the encrypt and decrypt function. Therefor it is impossible to return a valid keylength
+ in the map.</p>
+ <p>Always use a <c>Type</c> with an explicit key length,
+ </p>
+ </note>
+ <p>For a list of supported cipher algorithms, see <seealso marker="#supports-0">supports/0</seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="mod_pow" arity="3" since="OTP R16B01"/>
<fsummary>Computes the function: N^P mod M</fsummary>
- <type>
- <v>N, P, M = binary() | integer()</v>
- <v>Result = binary() | error</v>
- </type>
<desc>
<p>Computes the function <c>N^P mod M</c>.</p>
</desc>
</func>
<func>
- <name>next_iv(Type, Data) -> NextIVec</name>
- <name>next_iv(Type, Data, IVec) -> NextIVec</name>
- <fsummary></fsummary>
- <type>
- <v>Type = des_cbc | des3_cbc | aes_cbc | des_cfb</v>
- <v>Data = iodata()</v>
- <v>IVec = NextIVec = binary()</v>
- </type>
- <desc>
- <p>Returns the initialization vector to be used in the next
- iteration of encrypt/decrypt of type <c>Type</c>. <c>Data</c> is the
- encrypted data from the previous iteration step. The <c>IVec</c>
- argument is only needed for <c>des_cfb</c> as the vector used
- in the previous iteration step.</p>
- </desc>
+ <name name="next_iv" arity="2" since="OTP R16B01"/>
+ <name name="next_iv" arity="3" since="OTP R16B01"/>
+ <fsummary></fsummary>
+ <desc>
+ <p>Returns the initialization vector to be used in the next
+ iteration of encrypt/decrypt of type <c>Type</c>. <c>Data</c> is the
+ encrypted data from the previous iteration step. The <c>IVec</c>
+ argument is only needed for <c>des_cfb</c> as the vector used
+ in the previous iteration step.</p>
+ </desc>
</func>
<func>
- <name>private_decrypt(Type, CipherText, PrivateKey, Padding) -> PlainText</name>
+ <name name="poly1305" arity="2" since="OTP 21.1"/>
+ <fsummary></fsummary>
+ <desc>
+ <p>Computes a POLY1305 message authentication code (<c>Mac</c>) from <c>Data</c> using
+ <c>Key</c> as the authentication key.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="private_decrypt" arity="4" since="OTP R16B01"/>
<fsummary>Decrypts CipherText using the private Key.</fsummary>
- <type>
- <v>Type = rsa</v>
- <v>CipherText = binary()</v>
- <v>PrivateKey = rsa_private() | engine_key_ref()</v>
- <v>Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding</v>
- <v>PlainText = binary()</v>
- </type>
<desc>
<p>Decrypts the <c>CipherText</c>, encrypted with
<seealso marker="#public_encrypt-4">public_encrypt/4</seealso> (or equivalent function)
@@ -618,34 +1091,8 @@
</func>
<func>
- <name>privkey_to_pubkey(Type, EnginePrivateKeyRef) -> PublicKey</name>
- <fsummary>Fetches a public key from an Engine stored private key.</fsummary>
- <type>
- <v>Type = rsa | dss</v>
- <v>EnginePrivateKeyRef = engine_key_ref()</v>
- <v>PublicKey = rsa_public() | dss_public()</v>
- </type>
- <desc>
- <p>Fetches the corresponding public key from a private key stored in an Engine.
- The key must be of the type indicated by the Type parameter.
- </p>
- </desc>
- </func>
-
- <func>
- <name>private_encrypt(Type, PlainText, PrivateKey, Padding) -> CipherText</name>
+ <name name="private_encrypt" arity="4" since="OTP R16B01"/>
<fsummary>Encrypts PlainText using the private Key.</fsummary>
- <type>
- <v>Type = rsa</v>
- <v>PlainText = binary()</v>
- <d> The size of the <c>PlainText</c> must be less
- than <c>byte_size(N)-11</c> if <c>rsa_pkcs1_padding</c> is
- used, and <c>byte_size(N)</c> if <c>rsa_no_padding</c> is
- used, where N is public modulus of the RSA key.</d>
- <v>PrivateKey = rsa_private() | engine_key_ref()</v>
- <v>Padding = rsa_pkcs1_padding | rsa_no_padding</v>
- <v>CipherText = binary()</v>
- </type>
<desc>
<p>Encrypts the <c>PlainText</c> using the <c>PrivateKey</c>
and returns the ciphertext. This is a low level signature operation
@@ -655,16 +1102,10 @@
</p>
</desc>
</func>
+
<func>
- <name>public_decrypt(Type, CipherText, PublicKey, Padding) -> PlainText</name>
+ <name name="public_decrypt" arity="4" since="OTP R16B01"/>
<fsummary>Decrypts CipherText using the public Key.</fsummary>
- <type>
- <v>Type = rsa</v>
- <v>CipherText = binary()</v>
- <v>PublicKey = rsa_public() | engine_key_ref()</v>
- <v>Padding = rsa_pkcs1_padding | rsa_no_padding</v>
- <v>PlainText = binary()</v>
- </type>
<desc>
<p>Decrypts the <c>CipherText</c>, encrypted with
<seealso marker="#private_encrypt-4">private_encrypt/4</seealso>(or equivalent function)
@@ -677,19 +1118,8 @@
</func>
<func>
- <name>public_encrypt(Type, PlainText, PublicKey, Padding) -> CipherText</name>
+ <name name="public_encrypt" arity="4" since="OTP R16B01"/>
<fsummary>Encrypts PlainText using the public Key.</fsummary>
- <type>
- <v>Type = rsa</v>
- <v>PlainText = binary()</v>
- <d> The size of the <c>PlainText</c> must be less
- than <c>byte_size(N)-11</c> if <c>rsa_pkcs1_padding</c> is
- used, and <c>byte_size(N)</c> if <c>rsa_no_padding</c> is
- used, where N is public modulus of the RSA key.</d>
- <v>PublicKey = rsa_public() | engine_key_ref()</v>
- <v>Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding</v>
- <v>CipherText = binary()</v>
- </type>
<desc>
<p>Encrypts the <c>PlainText</c> (message digest) using the <c>PublicKey</c>
and returns the <c>CipherText</c>. This is a low level signature operation
@@ -700,23 +1130,20 @@
</func>
<func>
- <name>rand_seed(Seed) -> ok</name>
+ <name name="rand_seed" arity="1" since="OTP 17.0"/>
<fsummary>Set the seed for random bytes generation</fsummary>
- <type>
- <v>Seed = binary()</v>
- </type>
<desc>
<p>Set the seed for PRNG to the given binary. This calls the
RAND_seed function from openssl. Only use this if the system
you are running on does not have enough "randomness" built in.
Normally this is when
<seealso marker="#strong_rand_bytes/1">strong_rand_bytes/1</seealso>
- throws <c>low_entropy</c></p>
+ raises <c>error:low_entropy</c></p>
</desc>
</func>
<func>
- <name>rand_uniform(Lo, Hi) -> N</name>
+ <name since="">rand_uniform(Lo, Hi) -> N</name>
<fsummary>Generate a random number</fsummary>
<type>
<v>Lo, Hi, N = integer()</v>
@@ -729,36 +1156,15 @@
</func>
<func>
- <name>sign(Algorithm, DigestType, Msg, Key) -> binary()</name>
- <name>sign(Algorithm, DigestType, Msg, Key, Options) -> binary()</name>
- <fsummary> Create digital signature.</fsummary>
- <type>
- <v>Algorithm = rsa | dss | ecdsa </v>
- <v>Msg = binary() | {digest,binary()}</v>
- <d>The msg is either the binary "cleartext" data to be
- signed or it is the hashed value of "cleartext" i.e. the
- digest (plaintext).</d>
- <v>DigestType = rsa_digest_type() | dss_digest_type() | ecdsa_digest_type()</v>
- <v>Key = rsa_private() | dss_private() | [ecdh_private(),ecdh_params()] | engine_key_ref()</v>
- <v>Options = sign_options()</v>
- </type>
- <desc>
- <p>Creates a digital signature.</p>
- <p>Algorithm <c>dss</c> can only be used together with digest type
- <c>sha</c>.</p>
- <p>See also <seealso marker="public_key:public_key#sign-3">public_key:sign/3</seealso>.</p>
- </desc>
- </func>
-
- <func>
- <name>start() -> ok</name>
+ <name name="start" arity="0" since=""/>
<fsummary> Equivalent to application:start(crypto). </fsummary>
<desc>
<p> Equivalent to application:start(crypto).</p>
</desc>
</func>
+
<func>
- <name>stop() -> ok</name>
+ <name name="stop" arity="0" since=""/>
<fsummary> Equivalent to application:stop(crypto).</fsummary>
<desc>
<p> Equivalent to application:stop(crypto).</p>
@@ -766,23 +1172,20 @@
</func>
<func>
- <name>strong_rand_bytes(N) -> binary()</name>
+ <name name="strong_rand_bytes" arity="1" since="OTP R14B03"/>
<fsummary>Generate a binary of random bytes</fsummary>
- <type>
- <v>N = integer()</v>
- </type>
<desc>
<p>Generates N bytes randomly uniform 0..255, and returns the
result in a binary. Uses a cryptographically secure prng seeded and
periodically mixed with operating system provided entropy. By default
this is the <c>RAND_bytes</c> method from OpenSSL.</p>
- <p>May throw exception <c>low_entropy</c> in case the random generator
+ <p>May raise exception <c>error:low_entropy</c> in case the random generator
failed due to lack of secure "randomness".</p>
</desc>
</func>
<func>
- <name>rand_seed() -> rand:state()</name>
+ <name name="rand_seed" arity="0" since="OTP 20.0"/>
<fsummary>Strong random number generation plugin state</fsummary>
<desc>
<p>
@@ -790,9 +1193,16 @@
<seealso marker="stdlib:rand">random number generation</seealso>,
in order to generate cryptographically strong random numbers
(based on OpenSSL's <c>BN_rand_range</c>),
- and saves it on process dictionary before returning it as well.
+ and saves it in the process dictionary before returning it as well.
See also
- <seealso marker="stdlib:rand#seed-1">rand:seed/1</seealso>.
+ <seealso marker="stdlib:rand#seed-1">rand:seed/1</seealso> and
+ <seealso marker="#rand_seed_s-0">rand_seed_s/0</seealso>.
+ </p>
+ <p>
+ When using the state object from this function the
+ <seealso marker="stdlib:rand">rand</seealso> functions using it
+ may raise exception <c>error:low_entropy</c> in case the random generator
+ failed due to lack of secure "randomness".
</p>
<p><em>Example</em></p>
<pre>
@@ -803,7 +1213,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
</func>
<func>
- <name>rand_seed_s() -> rand:state()</name>
+ <name name="rand_seed_s" arity="0" since="OTP 20.0"/>
<fsummary>Strong random number generation plugin state</fsummary>
<desc>
<p>
@@ -814,127 +1224,258 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
See also
<seealso marker="stdlib:rand#seed_s-1">rand:seed_s/1</seealso>.
</p>
+ <p>
+ When using the state object from this function the
+ <seealso marker="stdlib:rand">rand</seealso> functions using it
+ may raise exception <c>error:low_entropy</c> in case the random generator
+ failed due to lack of secure "randomness".
+ </p>
+ <note>
+ <p>
+ The state returned from this function cannot be used
+ to get a reproducable random sequence as from
+ the other
+ <seealso marker="stdlib:rand">rand</seealso>
+ functions,
+ since reproducability does not match cryptographically safe.
+ </p>
+ <p>
+ The only supported usage is to generate one distinct
+ random sequence from this start state.
+ </p>
+ </note>
</desc>
</func>
<func>
- <name>stream_init(Type, Key) -> State</name>
- <fsummary></fsummary>
- <type>
- <v>Type = rc4 </v>
- <v>State = opaque() </v>
- <v>Key = iodata()</v>
- </type>
- <desc>
- <p>Initializes the state for use in RC4 stream encryption
- <seealso marker="#stream_encrypt-2">stream_encrypt</seealso> and
- <seealso marker="#stream_decrypt-2">stream_decrypt</seealso></p>
- </desc>
- </func>
-
- <func>
- <name>stream_init(Type, Key, IVec) -> State</name>
- <fsummary></fsummary>
+ <name since="OTP 21.0">rand_seed_alg(Alg) -> rand:state()</name>
+ <fsummary>Strong random number generation plugin state</fsummary>
<type>
- <v>Type = aes_ctr </v>
- <v>State = opaque() </v>
- <v>Key = iodata()</v>
- <v>IVec = binary()</v>
+ <v>Alg = crypto | crypto_cache</v>
</type>
<desc>
- <p>Initializes the state for use in streaming AES encryption using Counter mode (CTR).
- <c>Key</c> is the AES key and must be either 128, 192, or 256 bits long. <c>IVec</c> is
- an arbitrary initializing vector of 128 bits (16 bytes). This state is for use with
- <seealso marker="#stream_encrypt-2">stream_encrypt</seealso> and
- <seealso marker="#stream_decrypt-2">stream_decrypt</seealso>.</p>
+ <marker id="rand_seed_alg-1" />
+ <p>
+ Creates state object for
+ <seealso marker="stdlib:rand">random number generation</seealso>,
+ in order to generate cryptographically strong random numbers,
+ and saves it in the process dictionary before returning it as well.
+ See also
+ <seealso marker="stdlib:rand#seed-1">rand:seed/1</seealso> and
+ <seealso marker="#rand_seed_alg_s-1">rand_seed_alg_s/1</seealso>.
+ </p>
+ <p>
+ When using the state object from this function the
+ <seealso marker="stdlib:rand">rand</seealso> functions using it
+ may raise exception <c>error:low_entropy</c> in case the random generator
+ failed due to lack of secure "randomness".
+ </p>
+ <p><em>Example</em></p>
+ <pre>
+_ = crypto:rand_seed_alg(crypto_cache),
+_IntegerValue = rand:uniform(42), % [1; 42]
+_FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
</desc>
</func>
<func>
- <name>stream_encrypt(State, PlainText) -> { NewState, CipherText}</name>
- <fsummary></fsummary>
+ <name since="OTP-22.0">rand_seed_alg(Alg, Seed) -> rand:state()</name>
+ <fsummary>Strong random number generation plugin state</fsummary>
<type>
- <v>Text = iodata()</v>
- <v>CipherText = binary()</v>
+ <v>Alg = crypto_aes</v>
</type>
<desc>
- <p>Encrypts <c>PlainText</c> according to the stream cipher <c>Type</c> specified in stream_init/3.
- <c>Text</c> can be any number of bytes. The initial <c>State</c> is created using
- <seealso marker="#stream_init-2">stream_init</seealso>.
- <c>NewState</c> must be passed into the next call to <c>stream_encrypt</c>.</p>
+ <marker id="rand_seed_alg-2" />
+ <p>
+ Creates a state object for
+ <seealso marker="stdlib:rand">random number generation</seealso>,
+ in order to generate cryptographically unpredictable random numbers,
+ and saves it in the process dictionary before returning it as well.
+ See also
+ <seealso marker="#rand_seed_alg_s-2">rand_seed_alg_s/2</seealso>.
+ </p>
+ <p><em>Example</em></p>
+ <pre>
+_ = crypto:rand_seed_alg(crypto_aes, "my seed"),
+IntegerValue = rand:uniform(42), % [1; 42]
+FloatValue = rand:uniform(), % [0.0; 1.0[
+_ = crypto:rand_seed_alg(crypto_aes, "my seed"),
+IntegerValue = rand:uniform(42), % Same values
+FloatValue = rand:uniform(). % again
+ </pre>
</desc>
</func>
<func>
- <name>stream_decrypt(State, CipherText) -> { NewState, PlainText }</name>
- <fsummary></fsummary>
+ <name since="OTP 21.0">rand_seed_alg_s(Alg) -> rand:state()</name>
+ <fsummary>Strong random number generation plugin state</fsummary>
<type>
- <v>CipherText = iodata()</v>
- <v>PlainText = binary()</v>
+ <v>Alg = crypto | crypto_cache</v>
</type>
<desc>
- <p>Decrypts <c>CipherText</c> according to the stream cipher <c>Type</c> specified in stream_init/3.
- <c>PlainText</c> can be any number of bytes. The initial <c>State</c> is created using
- <seealso marker="#stream_init-2">stream_init</seealso>.
- <c>NewState</c> must be passed into the next call to <c>stream_decrypt</c>.</p>
+ <marker id="rand_seed_alg_s-1" />
+ <p>
+ Creates state object for
+ <seealso marker="stdlib:rand">random number generation</seealso>,
+ in order to generate cryptographically strongly random numbers.
+ See also
+ <seealso marker="stdlib:rand#seed_s-1">rand:seed_s/1</seealso>.
+ </p>
+ <p>
+ If <c>Alg</c> is <c>crypto</c> this function behaves exactly like
+ <seealso marker="#rand_seed_s-0">rand_seed_s/0</seealso>.
+ </p>
+ <p>
+ If <c>Alg</c> is <c>crypto_cache</c> this function
+ fetches random data with OpenSSL's <c>RAND_bytes</c>
+ and caches it for speed using an internal word size
+ of 56 bits that makes calculations fast on 64 bit machines.
+ </p>
+ <p>
+ When using the state object from this function the
+ <seealso marker="stdlib:rand">rand</seealso> functions using it
+ may raise exception <c>error:low_entropy</c> in case the random generator
+ failed due to lack of secure "randomness".
+ </p>
+ <p>
+ The cache size can be changed from its default value using the
+ <seealso marker="crypto_app">
+ crypto app's
+ </seealso> configuration parameter <c>rand_cache_size</c>.
+ </p>
+ <p>
+ When using the state object from this function the
+ <seealso marker="stdlib:rand">rand</seealso> functions using it
+ may throw exception <c>low_entropy</c> in case the random generator
+ failed due to lack of secure "randomness".
+ </p>
+ <note>
+ <p>
+ The state returned from this function cannot be used
+ to get a reproducable random sequence as from
+ the other
+ <seealso marker="stdlib:rand">rand</seealso>
+ functions,
+ since reproducability does not match cryptographically safe.
+ </p>
+ <p>
+ In fact since random data is cached some numbers may
+ get reproduced if you try, but this is unpredictable.
+ </p>
+ <p>
+ The only supported usage is to generate one distinct
+ random sequence from this start state.
+ </p>
+ </note>
</desc>
</func>
- <func>
- <name>supports() -> AlgorithmList </name>
- <fsummary>Provide a list of available crypto algorithms.</fsummary>
+ <func>
+ <name since="OTP 22.0">rand_seed_alg_s(Alg, Seed) -> rand:state()</name>
+ <fsummary>Strong random number generation plugin state</fsummary>
<type>
- <v> AlgorithmList = [{hashs, [hash_algorithms()]},
- {ciphers, [cipher_algorithms()]},
- {public_keys, [public_key_algorithms()]},
- {macs, [mac_algorithms()]}]
- </v>
+ <v>Alg = crypto_aes</v>
</type>
<desc>
- <p> Can be used to determine which crypto algorithms that are supported
- by the underlying OpenSSL library</p>
+ <marker id="rand_seed_alg_s-2" />
+ <p>
+ Creates a state object for
+ <seealso marker="stdlib:rand">random number generation</seealso>,
+ in order to generate cryptographically unpredictable random numbers.
+ See also
+ <seealso marker="#rand_seed_alg-1">rand_seed_alg/1</seealso>.
+ </p>
+ <p>
+ To get a long period the Xoroshiro928 generator from the
+ <seealso marker="stdlib:rand">rand</seealso>
+ module is used as a counter (with period 2^928 - 1)
+ and the generator states are scrambled through AES
+ to create 58-bit pseudo random values.
+ </p>
+ <p>
+ The result should be statistically completely unpredictable
+ random values, since the scrambling is cryptographically strong
+ and the period is ridiculously long. But the generated numbers
+ are not to be regarded as cryptographically strong since
+ there is no re-keying schedule.
+ </p>
+ <list type="bulleted">
+ <item>
+ <p>
+ If you need cryptographically strong random numbers use
+ <seealso marker="#rand_seed_alg_s-1">rand_seed_alg_s/1</seealso>
+ with <c>Alg =:= crypto</c> or <c>Alg =:= crypto_cache</c>.
+ </p>
+ </item>
+ <item>
+ <p>
+ If you need to be able to repeat the sequence use this function.
+ </p>
+ </item>
+ <item>
+ <p>
+ If you do not need the statistical quality of this function,
+ there are faster algorithms in the
+ <seealso marker="stdlib:rand">rand</seealso>
+ module.
+ </p>
+ </item>
+ </list>
+ <p>
+ Thanks to the used generator the state object supports the
+ <seealso marker="stdlib:rand#jump-0"><c>rand:jump/0,1</c></seealso>
+ function with distance 2^512.
+ </p>
+ <p>
+ Numbers are generated in batches and cached for speed reasons.
+ The cache size can be changed from its default value using the
+ <seealso marker="crypto_app">
+ crypto app's
+ </seealso> configuration parameter <c>rand_cache_size</c>.
+ </p>
</desc>
</func>
<func>
- <name>ec_curves() -> EllipticCurveList </name>
+ <name name="ec_curves" arity="0" since="OTP 17.0"/>
<fsummary>Provide a list of available named elliptic curves.</fsummary>
- <type>
- <v>EllipticCurveList = [ec_named_curve()]</v>
- </type>
<desc>
<p>Can be used to determine which named elliptic curves are supported.</p>
</desc>
</func>
<func>
- <name>ec_curve(NamedCurve) -> EllipticCurve </name>
+ <name name="ec_curve" arity="1" since="OTP 17.0"/>
<fsummary>Get the defining parameters of a elliptic curve.</fsummary>
- <type>
- <v>NamedCurve = ec_named_curve()</v>
- <v>EllipticCurve = ec_explicit_curve()</v>
- </type>
<desc>
<p>Return the defining parameters of a elliptic curve.</p>
</desc>
</func>
- <func>
- <name>verify(Algorithm, DigestType, Msg, Signature, Key) -> boolean()</name>
- <name>verify(Algorithm, DigestType, Msg, Signature, Key, Options) -> boolean()</name>
+ <func>
+ <name name="sign" arity="4" since="OTP R16B01"/>
+ <name name="sign" arity="5" since="OTP 20.1"/>
+ <fsummary> Create digital signature.</fsummary>
+ <desc>
+ <p>Creates a digital signature.</p>
+ <p>The msg is either the binary "cleartext" data to be
+ signed or it is the hashed value of "cleartext" i.e. the
+ digest (plaintext).</p>
+ <p>Algorithm <c>dss</c> can only be used together with digest type
+ <c>sha</c>.</p>
+ <p>See also <seealso marker="public_key:public_key#sign-3">public_key:sign/3</seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="verify" arity="5" since="OTP R16B01"/>
+ <name name="verify" arity="6" since="OTP 20.1"/>
<fsummary>Verifies a digital signature.</fsummary>
- <type>
- <v> Algorithm = rsa | dss | ecdsa </v>
- <v>Msg = binary() | {digest,binary()}</v>
- <d>The msg is either the binary "cleartext" data
- or it is the hashed value of "cleartext" i.e. the digest (plaintext).</d>
- <v>DigestType = rsa_digest_type() | dss_digest_type() | ecdsa_digest_type()</v>
- <v>Signature = binary()</v>
- <v>Key = rsa_public() | dss_public() | [ecdh_public(),ecdh_params()] | engine_key_ref()</v>
- <v>Options = sign_options()</v>
- </type>
<desc>
<p>Verifies a digital signature</p>
+ <p>The msg is either the binary "cleartext" data to be
+ signed or it is the hashed value of "cleartext" i.e. the
+ digest (plaintext).</p>
<p>Algorithm <c>dss</c> can only be used together with digest type
<c>sha</c>.</p>
@@ -942,19 +1483,32 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
</desc>
</func>
+ </funcs>
+ <section>
+ <title>Engine API</title>
+ </section>
+
+ <funcs>
<!-- Engine functions -->
<func>
- <name>engine_get_all_methods() -> Result</name>
+ <name name="privkey_to_pubkey" arity="2" since="OTP 20.2"/>
+ <fsummary>Fetches a public key from an Engine stored private key.</fsummary>
+ <desc>
+ <p>Fetches the corresponding public key from a private key stored in an Engine.
+ The key must be of the type indicated by the Type parameter.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="engine_get_all_methods" arity="0" since="OTP 20.2"/>
<fsummary>Return list of all possible engine methods</fsummary>
- <type>
- <v>Result = [EngineMethod::atom()]</v>
- </type>
<desc>
<p>
Returns a list of all possible engine methods.
</p>
- <p>
- May throw exception notsup in case there is
+ <p>
+ May raise exception <c>error:notsup</c> in case there is
no engine support in the underlying OpenSSL implementation.
</p>
<p>
@@ -965,23 +1519,18 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
</func>
<func>
- <name>engine_load(EngineId, PreCmds, PostCmds) -> Result</name>
+ <name name="engine_load" arity="3" since="OTP 20.2"/>
<fsummary>Dynamical load an encryption engine</fsummary>
- <type>
- <v>EngineId = unicode:chardata()</v>
- <v>PreCmds, PostCmds = [{unicode:chardata(), unicode:chardata()}]</v>
- <v>Result = {ok, Engine::term()} | {error, Reason::term()}</v>
- </type>
<desc>
<p>
Loads the OpenSSL engine given by <c>EngineId</c> if it is available and then returns ok and
- an engine handle. This function is the same as calling <c>engine_load/4</c> with
- <c>EngineMethods</c> set to a list of all the possible methods. An error tuple is
+ an engine handle. This function is the same as calling <c>engine_load/4</c> with
+ <c>EngineMethods</c> set to a list of all the possible methods. An error tuple is
returned if the engine can't be loaded.
</p>
<p>
- The function throws a badarg if the parameters are in wrong format.
- It may also throw the exception notsup in case there is
+ The function raises a <c>error:badarg</c> if the parameters are in wrong format.
+ It may also raise the exception <c>error:notsup</c> in case there is
no engine support in the underlying OpenSSL implementation.
</p>
<p>
@@ -992,22 +1541,16 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
</func>
<func>
- <name>engine_load(EngineId, PreCmds, PostCmds, EngineMethods) -> Result</name>
+ <name name="engine_load" arity="4" since="OTP 20.2"/>
<fsummary>Dynamical load an encryption engine</fsummary>
- <type>
- <v>EngineId = unicode:chardata()</v>
- <v>PreCmds, PostCmds = [{unicode:chardata(), unicode:chardata()}]</v>
- <v>EngineMethods = [engine_method_type()]</v>
- <v>Result = {ok, Engine::term()} | {error, Reason::term()}</v>
- </type>
<desc>
<p>
Loads the OpenSSL engine given by <c>EngineId</c> if it is available and then returns ok and
an engine handle. An error tuple is returned if the engine can't be loaded.
</p>
<p>
- The function throws a badarg if the parameters are in wrong format.
- It may also throw the exception notsup in case there is
+ The function raises a <c>error:badarg</c> if the parameters are in wrong format.
+ It may also raise the exception <c>error:notsup</c> in case there is
no engine support in the underlying OpenSSL implementation.
</p>
<p>
@@ -1018,20 +1561,16 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
</func>
<func>
- <name>engine_unload(Engine) -> Result</name>
+ <name name="engine_unload" arity="1" since="OTP 20.2"/>
<fsummary>Dynamical load an encryption engine</fsummary>
- <type>
- <v>Engine = term()</v>
- <v>Result = ok | {error, Reason::term()}</v>
- </type>
<desc>
<p>
- Unloads the OpenSSL engine given by <c>EngineId</c>.
+ Unloads the OpenSSL engine given by <c>Engine</c>.
An error tuple is returned if the engine can't be unloaded.
</p>
<p>
- The function throws a badarg if the parameter is in wrong format.
- It may also throw the exception notsup in case there is
+ The function raises a <c>error:badarg</c> if the parameter is in wrong format.
+ It may also raise the exception <c>error:notsup</c> in case there is
no engine support in the underlying OpenSSL implementation.
</p>
<p>
@@ -1042,146 +1581,387 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
</func>
<func>
- <name>engine_list() -> Result</name>
- <fsummary>List the known engine ids</fsummary>
- <type>
- <v>Result = [EngineId::unicode:chardata()]</v>
- </type>
+ <name name="engine_by_id" arity="1" since="OTP 21.0.6"/>
+ <fsummary>Get a reference to an already loaded engine</fsummary>
<desc>
- <p>List the id's of all engines in OpenSSL's internal list.</p>
<p>
- It may also throw the exception notsup in case there is
+ Get a reference to an already loaded engine with <c>EngineId</c>.
+ An error tuple is returned if the engine can't be unloaded.
+ </p>
+ <p>
+ The function raises a <c>error:badarg</c> if the parameter is in wrong format.
+ It may also raise the exception <c>error:notsup</c> in case there is
no engine support in the underlying OpenSSL implementation.
</p>
<p>
- See also the chapter <seealso marker="crypto:engine_load#engine_load">Engine Load</seealso>
+ See also the chapter <seealso marker="crypto:engine_load#engine_load">Engine Load</seealso>
in the User's Guide.
</p>
</desc>
</func>
<func>
- <name>engine_ctrl_cmd_string(Engine, CmdName, CmdArg) -> Result</name>
+ <name name="engine_ctrl_cmd_string" arity="3" since="OTP 20.2"/>
<fsummary>Sends ctrl commands to an OpenSSL engine</fsummary>
- <type>
- <v>Engine = term()</v>
- <v>CmdName = unicode:chardata()</v>
- <v>CmdArg = unicode:chardata()</v>
- <v>Result = ok | {error, Reason::term()}</v>
- </type>
<desc>
<p>
Sends ctrl commands to the OpenSSL engine given by <c>Engine</c>.
- This function is the same as calling <c>engine_ctrl_cmd_string/4</c> with
+ This function is the same as calling <c>engine_ctrl_cmd_string/4</c> with
<c>Optional</c> set to <c>false</c>.
</p>
<p>
- The function throws a badarg if the parameters are in wrong format.
- It may also throw the exception notsup in case there is
+ The function raises a <c>error:badarg</c> if the parameters are in wrong format.
+ It may also raise the exception <c>error:notsup</c> in case there is
no engine support in the underlying OpenSSL implementation.
</p>
</desc>
</func>
<func>
- <name>engine_ctrl_cmd_string(Engine, CmdName, CmdArg, Optional) -> Result</name>
+ <name name="engine_ctrl_cmd_string" arity="4" since="OTP 20.2"/>
<fsummary>Sends ctrl commands to an OpenSSL engine</fsummary>
- <type>
- <v>Engine = term()</v>
- <v>CmdName = unicode:chardata()</v>
- <v>CmdArg = unicode:chardata()</v>
- <v>Optional = boolean()</v>
- <v>Result = ok | {error, Reason::term()}</v>
- </type>
<desc>
<p>
Sends ctrl commands to the OpenSSL engine given by <c>Engine</c>.
- <c>Optional</c> is a boolean argument that can relax the semantics of the function.
- If set to <c>true</c> it will only return failure if the ENGINE supported the given
- command name but failed while executing it, if the ENGINE doesn't support the command
- name it will simply return success without doing anything. In this case we assume
+ <c>Optional</c> is a boolean argument that can relax the semantics of the function.
+ If set to <c>true</c> it will only return failure if the ENGINE supported the given
+ command name but failed while executing it, if the ENGINE doesn't support the command
+ name it will simply return success without doing anything. In this case we assume
the user is only supplying commands specific to the given ENGINE so we set this to
<c>false</c>.
</p>
<p>
- The function throws a badarg if the parameters are in wrong format.
- It may also throw the exception notsup in case there is
+ The function raises a <c>error:badarg</c> if the parameters are in wrong format.
+ It may also raise the exception <c>error:notsup</c> in case there is
no engine support in the underlying OpenSSL implementation.
</p>
</desc>
</func>
+ <func>
+ <name name="engine_add" arity="1" since="OTP 21.0.6"/>
+ <fsummary>Add engine to OpenSSL internal list</fsummary>
+ <desc>
+ <p>Add the engine to OpenSSL's internal list.</p>
+ <p>
+ The function raises a <c>error:badarg</c> if the parameters are in wrong format.
+ It may also raise the exception <c>error:notsup</c> in case there is
+ no engine support in the underlying OpenSSL implementation.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="engine_remove" arity="1" since="OTP 21.0.6"/>
+ <fsummary>Remove engine to OpenSSL internal list</fsummary>
+ <desc>
+ <p>Remove the engine from OpenSSL's internal list.</p>
+ <p>
+ The function raises a <c>error:badarg</c> if the parameters are in wrong format.
+ It may also raise the exception <c>error:notsup</c> in case there is
+ no engine support in the underlying OpenSSL implementation.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="engine_get_id" arity="1" since="OTP 21.0.6"/>
+ <fsummary>Fetch engine ID</fsummary>
+ <desc>
+ <p>Return the ID for the engine, or an empty binary if there is no id set.</p>
+ <p>
+ The function raises a <c>error:badarg</c> if the parameters are in wrong format.
+ It may also raise the exception <c>error:notsup</c> in case there is
+ no engine support in the underlying OpenSSL implementation.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="engine_get_name" arity="1" since="OTP 21.0.6"/>
+ <fsummary>Fetch engine name</fsummary>
+ <desc>
+ <p>Return the name (eg a description) for the engine, or an empty binary if there is no name set.</p>
+ <p>
+ The function raises a <c>error:badarg</c> if the parameters are in wrong format.
+ It may also raise the exception <c>error:notsup</c> in case there is
+ no engine support in the underlying OpenSSL implementation.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="engine_list" arity="0" since="OTP 20.2"/>
+ <fsummary>List the known engine ids</fsummary>
+ <desc>
+ <p>List the id's of all engines in OpenSSL's internal list.</p>
+ <p>
+ It may also raise the exception <c>error:notsup</c> in case there is
+ no engine support in the underlying OpenSSL implementation.
+ </p>
+ <p>
+ See also the chapter <seealso marker="crypto:engine_load#engine_load">Engine Load</seealso>
+ in the User's Guide.
+ </p>
+ <p>
+ May raise exception <c>error:notsup</c> in case engine functionality is not supported by the underlying
+ OpenSSL implementation.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="ensure_engine_loaded" arity="2" since="OTP 21.0.6"/>
+ <fsummary>Ensure encryption engine just loaded once</fsummary>
+ <desc>
+ <p>
+ Loads the OpenSSL engine given by <c>EngineId</c> and the path to the dynamic library
+ implementing the engine. This function is the same as calling <c>ensure_engine_loaded/3</c> with
+ <c>EngineMethods</c> set to a list of all the possible methods. An error tuple is
+ returned if the engine can't be loaded.
+ </p>
+ <p>
+ The function raises a <c>error:badarg</c> if the parameters are in wrong format.
+ It may also raise the exception <c>error:notsup</c> in case there is
+ no engine support in the underlying OpenSSL implementation.
+ </p>
+ <p>
+ See also the chapter <seealso marker="crypto:engine_load#engine_load">Engine Load</seealso>
+ in the User's Guide.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="ensure_engine_loaded" arity="3" since="OTP 21.0.6"/>
+ <fsummary>Ensure encryption engine just loaded once</fsummary>
+ <desc>
+ <p>
+ Loads the OpenSSL engine given by <c>EngineId</c> and the path to the dynamic library
+ implementing the engine. This function differs from the normal engine_load in that sense it
+ also add the engine id to the internal list in OpenSSL. Then in the following calls to the function
+ it just fetch the reference to the engine instead of loading it again.
+ An error tuple is returned if the engine can't be loaded.
+ </p>
+ <p>
+ The function raises a <c>error:badarg</c> if the parameters are in wrong format.
+ It may also raise the exception <c>error:notsup</c> in case there is
+ no engine support in the underlying OpenSSL implementation.
+ </p>
+ <p>
+ See also the chapter <seealso marker="crypto:engine_load#engine_load">Engine Load</seealso>
+ in the User's Guide.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="ensure_engine_unloaded" arity="1" since="OTP 21.0.6"/>
+ <fsummary>Unload an engine loaded with the ensure function</fsummary>
+ <desc>
+ <p>
+ Unloads an engine loaded with the <c>ensure_engine_loaded</c> function.
+ It both removes the label from the OpenSSL internal engine list and unloads the engine.
+ This function is the same as calling <c>ensure_engine_unloaded/2</c> with
+ <c>EngineMethods</c> set to a list of all the possible methods. An error tuple is
+ returned if the engine can't be unloaded.
+ </p>
+ <p>
+ The function raises a <c>error:badarg</c> if the parameters are in wrong format.
+ It may also raise the exception <c>error:notsup</c> in case there is
+ no engine support in the underlying OpenSSL implementation.
+ </p>
+ <p>
+ See also the chapter <seealso marker="crypto:engine_load#engine_load">Engine Load</seealso>
+ in the User's Guide.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="ensure_engine_unloaded" arity="2" since="OTP 21.0.6"/>
+ <fsummary>Unload an engine loaded with the ensure function</fsummary>
+ <desc>
+ <p>
+ Unloads an engine loaded with the <c>ensure_engine_loaded</c> function.
+ It both removes the label from the OpenSSL internal engine list and unloads the engine.
+ An error tuple is returned if the engine can't be unloaded.
+ </p>
+ <p>
+ The function raises a <c>error:badarg</c> if the parameters are in wrong format.
+ It may also raise the exception <c>error:notsup</c> in case there is
+ no engine support in the underlying OpenSSL implementation.
+ </p>
+ <p>
+ See also the chapter <seealso marker="crypto:engine_load#engine_load">Engine Load</seealso>
+ in the User's Guide.
+ </p>
+ </desc>
+ </func>
+
</funcs>
- <!-- Maybe put this in the users guide -->
- <!-- <section> -->
- <!-- <title>DES in CBC mode</title> -->
- <!-- <p>The Data Encryption Standard (DES) defines an algorithm for -->
- <!-- encrypting and decrypting an 8 byte quantity using an 8 byte key -->
- <!-- (actually only 56 bits of the key is used). -->
- <!-- </p> -->
- <!-- <p>When it comes to encrypting and decrypting blocks that are -->
- <!-- multiples of 8 bytes various modes are defined (NIST SP -->
- <!-- 800-38A). One of those modes is the Cipher Block Chaining (CBC) -->
- <!-- mode, where the encryption of an 8 byte segment depend not only -->
- <!-- of the contents of the segment itself, but also on the result of -->
- <!-- encrypting the previous segment: the encryption of the previous -->
- <!-- segment becomes the initializing vector of the encryption of the -->
- <!-- current segment. -->
- <!-- </p> -->
- <!-- <p>Thus the encryption of every segment depends on the encryption -->
- <!-- key (which is secret) and the encryption of the previous -->
- <!-- segment, except the first segment which has to be provided with -->
- <!-- an initial initializing vector. That vector could be chosen at -->
- <!-- random, or be a counter of some kind. It does not have to be -->
- <!-- secret. -->
- <!-- </p> -->
- <!-- <p>The following example is drawn from the old FIPS 81 standard -->
- <!-- (replaced by NIST SP 800-38A), where both the plain text and the -->
- <!-- resulting cipher text is settled. The following code fragment -->
- <!-- returns `true'. -->
- <!-- </p> -->
- <!-- <pre><![CDATA[ -->
-
- <!-- Key = <<16#01,16#23,16#45,16#67,16#89,16#ab,16#cd,16#ef>>, -->
- <!-- IVec = <<16#12,16#34,16#56,16#78,16#90,16#ab,16#cd,16#ef>>, -->
- <!-- P = "Now is the time for all ", -->
- <!-- C = crypto:des_cbc_encrypt(Key, IVec, P), -->
- <!-- % Which is the same as -->
- <!-- P1 = "Now is t", P2 = "he time ", P3 = "for all ", -->
- <!-- C1 = crypto:des_cbc_encrypt(Key, IVec, P1), -->
- <!-- C2 = crypto:des_cbc_encrypt(Key, C1, P2), -->
- <!-- C3 = crypto:des_cbc_encrypt(Key, C2, P3), -->
-
- <!-- C = <<C1/binary, C2/binary, C3/binary>>, -->
- <!-- C = <<16#e5,16#c7,16#cd,16#de,16#87,16#2b,16#f2,16#7c, -->
- <!-- 16#43,16#e9,16#34,16#00,16#8c,16#38,16#9c,16#0f, -->
- <!-- 16#68,16#37,16#88,16#49,16#9a,16#7c,16#05,16#f6>>, -->
- <!-- <<"Now is the time for all ">> == -->
- <!-- crypto:des_cbc_decrypt(Key, IVec, C). -->
- <!-- ]]></pre> -->
- <!-- <p>The following is true for the DES CBC mode. For all -->
- <!-- decompositions <c>P1 ++ P2 = P</c> of a plain text message -->
- <!-- <c>P</c> (where the length of all quantities are multiples of 8 -->
- <!-- bytes), the encryption <c>C</c> of <c>P</c> is equal to <c>C1 ++ -->
- <!-- C2</c>, where <c>C1</c> is obtained by encrypting <c>P1</c> with -->
- <!-- <c>Key</c> and the initializing vector <c>IVec</c>, and where -->
- <!-- <c>C2</c> is obtained by encrypting <c>P2</c> with <c>Key</c> -->
- <!-- and the initializing vector <c>last8(C1)</c>, -->
- <!-- where <c>last(Binary)</c> denotes the last 8 bytes of the -->
- <!-- binary <c>Binary</c>. -->
- <!-- </p> -->
- <!-- <p>Similarly, for all decompositions <c>C1 ++ C2 = C</c> of a -->
- <!-- cipher text message <c>C</c> (where the length of all quantities -->
- <!-- are multiples of 8 bytes), the decryption <c>P</c> of <c>C</c> -->
- <!-- is equal to <c>P1 ++ P2</c>, where <c>P1</c> is obtained by -->
- <!-- decrypting <c>C1</c> with <c>Key</c> and the initializing vector -->
- <!-- <c>IVec</c>, and where <c>P2</c> is obtained by decrypting -->
- <!-- <c>C2</c> with <c>Key</c> and the initializing vector -->
- <!-- <c>last8(C1)</c>, where <c>last8(Binary)</c> is as above. -->
- <!-- </p> -->
- <!-- <p>For DES3 (which uses three 64 bit keys) the situation is the -->
- <!-- same. -->
- <!-- </p> -->
- <!-- </section> -->
+<section>
+ <title>Old API</title>
+</section>
+
+ <funcs>
+ <func>
+ <name name="block_encrypt" arity="3" since="OTP 18.0"/>
+ <fsummary>Encrypt <c>PlainText</c> according to <c>Type</c> block cipher</fsummary>
+ <desc>
+ <dont><p>Don't use this function for new programs! Use <seealso marker="crypto:new_api">the-new-api</seealso>.</p></dont>
+ <p>Encrypt <c>PlainText</c> according to <c>Type</c> block cipher.</p>
+ <p>May raise exception <c>error:notsup</c> in case the chosen <c>Type</c>
+ is not supported by the underlying libcrypto implementation.</p>
+ <p>For keylengths and blocksizes see the
+ <seealso marker="crypto:algorithm_details#ciphers">User's Guide</seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="block_decrypt" arity="3" since="OTP 18.0"/>
+ <fsummary>Decrypt <c>CipherText</c> according to <c>Type</c> block cipher</fsummary>
+ <desc>
+ <dont><p>Don't use this function for new programs! Use <seealso marker="crypto:new_api">the new api</seealso>.</p></dont>
+ <p>Decrypt <c>CipherText</c> according to <c>Type</c> block cipher.</p>
+ <p>May raise exception <c>error:notsup</c> in case the chosen <c>Type</c>
+ is not supported by the underlying libcrypto implementation.</p>
+ <p>For keylengths and blocksizes see the
+ <seealso marker="crypto:algorithm_details#ciphers">User's Guide</seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP R16B01">block_encrypt(Type, Key, Ivec, PlainText) -> CipherText | Error</name>
+ <name since="OTP R16B01">block_encrypt(AeadType, Key, Ivec, {AAD, PlainText}) -> {CipherText, CipherTag} | Error</name>
+ <name since="OTP R16B01">block_encrypt(aes_gcm | aes_ccm, Key, Ivec, {AAD, PlainText, TagLength}) -> {CipherText, CipherTag} | Error </name>
+ <fsummary>Encrypt <c>PlainText</c> according to <c>Type</c> block cipher</fsummary>
+ <type>
+ <v>Type = <seealso marker="#type-block_cipher_with_iv">block_cipher_with_iv()</seealso></v>
+ <v>AeadType = <seealso marker="#type-aead_cipher">aead_cipher()</seealso></v>
+ <v>Key = <seealso marker="#type-key">key()</seealso> | <seealso marker="#type-des3_key">des3_key()</seealso></v>
+ <v>PlainText = iodata()</v>
+ <v>AAD = IVec = CipherText = CipherTag = binary()</v>
+ <v>TagLength = 1..16</v>
+ <v>Error = <seealso marker="#type-run_time_error">run_time_error()</seealso></v>
+ </type>
+ <desc>
+ <dont><p>Don't use this function for new programs! Use <seealso marker="crypto:new_api">the new api</seealso>.</p></dont>
+ <p>Encrypt <c>PlainText</c> according to <c>Type</c> block cipher.
+ <c>IVec</c> is an arbitrary initializing vector.</p>
+ <p>In AEAD (Authenticated Encryption with Associated Data) mode, encrypt
+ <c>PlainText</c>according to <c>Type</c> block cipher and calculate
+ <c>CipherTag</c> that also authenticates the <c>AAD</c> (Associated Authenticated Data).</p>
+ <p>May raise exception <c>error:notsup</c> in case the chosen <c>Type</c>
+ is not supported by the underlying libcrypto implementation.</p>
+ <p>For keylengths, iv-sizes and blocksizes see the
+ <seealso marker="crypto:algorithm_details#ciphers">User's Guide</seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP R16B01">block_decrypt(Type, Key, Ivec, CipherText) -> PlainText | Error</name>
+ <name since="OTP R16B01">block_decrypt(AeadType, Key, Ivec, {AAD, CipherText, CipherTag}) -> PlainText | Error</name>
+ <fsummary>Decrypt <c>CipherText</c> according to <c>Type</c> block cipher</fsummary>
+ <type>
+ <v>Type = <seealso marker="#type-block_cipher_with_iv">block_cipher_with_iv()</seealso></v>
+ <v>AeadType = <seealso marker="#type-aead_cipher">aead_cipher()</seealso></v>
+ <v>Key = <seealso marker="#type-key">key()</seealso> | <seealso marker="#type-des3_key">des3_key()</seealso></v>
+ <v>PlainText = iodata()</v>
+ <v>AAD = IVec = CipherText = CipherTag = binary()</v>
+ <v>Error = BadTag | <seealso marker="#type-run_time_error">run_time_error()</seealso></v>
+ <v>BadTag = error</v>
+ </type>
+ <desc>
+ <dont><p>Don't use this function for new programs! Use <seealso marker="crypto:new_api">the new api</seealso>.</p></dont>
+ <p>Decrypt <c>CipherText</c> according to <c>Type</c> block cipher.
+ <c>IVec</c> is an arbitrary initializing vector.</p>
+ <p>In AEAD (Authenticated Encryption with Associated Data) mode, decrypt
+ <c>CipherText</c>according to <c>Type</c> block cipher and check the authenticity
+ the <c>PlainText</c> and <c>AAD</c> (Associated Authenticated Data) using the
+ <c>CipherTag</c>. May return <c>error</c> if the decryption or validation fail's</p>
+ <p>May raise exception <c>error:notsup</c> in case the chosen <c>Type</c>
+ is not supported by the underlying libcrypto implementation.</p>
+ <p>For keylengths, iv-sizes and blocksizes see the
+ <seealso marker="crypto:algorithm_details#ciphers">User's Guide</seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="stream_init" arity="2" since="OTP R16B01"/>
+ <fsummary></fsummary>
+ <desc>
+ <dont><p>Don't use this function for new programs! Use <seealso marker="crypto:new_api">the new api</seealso>.</p></dont>
+ <p>Initializes the state for use in RC4 stream encryption
+ <seealso marker="#stream_encrypt-2">stream_encrypt</seealso> and
+ <seealso marker="#stream_decrypt-2">stream_decrypt</seealso></p>
+ <p>For keylengths see the
+ <seealso marker="crypto:algorithm_details#stream-ciphers">User's Guide</seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="stream_init" arity="3" since="OTP R16B01"/>
+ <fsummary></fsummary>
+ <desc>
+ <dont><p>Don't use this function for new programs! Use <seealso marker="crypto:new_api">the new api</seealso>.</p></dont>
+ <p>Initializes the state for use in streaming AES encryption using Counter mode (CTR).
+ <c>Key</c> is the AES key and must be either 128, 192, or 256 bits long. <c>IVec</c> is
+ an arbitrary initializing vector of 128 bits (16 bytes). This state is for use with
+ <seealso marker="#stream_encrypt-2">stream_encrypt</seealso> and
+ <seealso marker="#stream_decrypt-2">stream_decrypt</seealso>.</p>
+ <p>For keylengths and iv-sizes see the
+ <seealso marker="crypto:algorithm_details#stream-ciphers">User's Guide</seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="stream_encrypt" arity="2" since="OTP R16B01"/>
+ <fsummary></fsummary>
+ <desc>
+ <dont><p>Don't use this function for new programs! Use <seealso marker="crypto:new_api">the new api</seealso>.</p></dont>
+ <p>Encrypts <c>PlainText</c> according to the stream cipher <c>Type</c> specified in stream_init/3.
+ <c>Text</c> can be any number of bytes. The initial <c>State</c> is created using
+ <seealso marker="#stream_init-2">stream_init</seealso>.
+ <c>NewState</c> must be passed into the next call to <c>stream_encrypt</c>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="stream_decrypt" arity="2" since="OTP R16B01"/>
+ <fsummary></fsummary>
+ <desc>
+ <dont><p>Don't use this function for new programs! Use <seealso marker="crypto:new_api">the new api</seealso>.</p></dont>
+ <p>Decrypts <c>CipherText</c> according to the stream cipher <c>Type</c> specified in stream_init/3.
+ <c>PlainText</c> can be any number of bytes. The initial <c>State</c> is created using
+ <seealso marker="#stream_init-2">stream_init</seealso>.
+ <c>NewState</c> must be passed into the next call to <c>stream_decrypt</c>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="supports" arity="0" since="OTP R16B01"/>
+ <fsummary>Provide a list of available crypto algorithms.</fsummary>
+ <desc>
+ <dont><p>Don't use this function for new programs! Use
+ <seealso marker="crypto#supports-1">supports/1</seealso> in
+ <seealso marker="crypto:new_api">the new api</seealso>.</p></dont>
+ <p> Can be used to determine which crypto algorithms that are supported
+ by the underlying libcrypto library</p>
+ <p>See <seealso marker="#hash_info-1">hash_info/1</seealso> and <seealso marker="#cipher_info-1">cipher_info/1</seealso>
+ for information about the hash and cipher algorithms.
+ </p>
+ </desc>
+ </func>
+
+ </funcs>
+
+
</erlref>
diff --git a/lib/crypto/doc/src/crypto_app.xml b/lib/crypto/doc/src/crypto_app.xml
index ba22557480..8296b1bc77 100644
--- a/lib/crypto/doc/src/crypto_app.xml
+++ b/lib/crypto/doc/src/crypto_app.xml
@@ -68,6 +68,24 @@
thus the crypto module will fail to load. This mechanism
prevents the accidental use of non-validated algorithms.</p>
</item>
+ <tag><c>rand_cache_size = integer()</c></tag>
+ <item>
+ <p>
+ Sets the cache size in bytes to use by
+ <seealso marker="crypto#rand_seed_alg-1">
+ <c>crypto:rand_seed_alg(crypto_cache)</c>
+ </seealso> and
+ <seealso marker="crypto#rand_seed_alg_s-1">
+ <c>crypto:rand_seed_alg_s(crypto_cache)</c>
+ </seealso>.
+ This parameter is read when a seed function is called,
+ and then kept in generators state object. It has a rather
+ small default value that causes reads of strong random bytes
+ about once per hundred calls for a random value.
+ The set value is rounded up to an integral number of words
+ of the size these seed functions use.
+ </p>
+ </item>
</taglist>
</section>
diff --git a/lib/crypto/doc/src/engine_keys.xml b/lib/crypto/doc/src/engine_keys.xml
index 38714fed8a..f78bb81bba 100644
--- a/lib/crypto/doc/src/engine_keys.xml
+++ b/lib/crypto/doc/src/engine_keys.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2017</year><year>2017</year>
+ <year>2017</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -40,7 +40,7 @@
</p>
<p>
An engine could among other tasks provide a storage for
- private or public keys. Such a storage could be made safer than the normal file system. Thoose techniques are not
+ private or public keys. Such a storage could be made safer than the normal file system. Those techniques are not
described in this User's Guide. Here we concentrate on how to use private or public keys stored in
such an engine.
</p>
@@ -51,7 +51,7 @@
<p>
OTP/Crypto requires that the user provides two or three items of information about the key. The application used
by the user is usually on a higher level, for example in
- <seealso marker="ssl:ssl#key_option_def">SSL</seealso>. If using
+ <seealso marker="ssl:ssl#type-key">SSL</seealso>. If using
the crypto application directly, it is required that:
</p>
<list>
@@ -62,7 +62,7 @@
on the Engine loaded
</item>
<item>an Erlang map is constructed with the Engine reference, the key reference and possibly a key passphrase if
- needed by the Engine. See the <seealso marker="crypto:crypto#engine_key_ref_type">Reference Manual</seealso> for
+ needed by the Engine. See the <seealso marker="crypto:crypto#type-engine_key_ref">Reference Manual</seealso> for
details of the map.
</item>
</list>
diff --git a/lib/crypto/doc/src/engine_load.xml b/lib/crypto/doc/src/engine_load.xml
index e5c3f5d561..5f7ccc784b 100644
--- a/lib/crypto/doc/src/engine_load.xml
+++ b/lib/crypto/doc/src/engine_load.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2017</year><year>2017</year>
+ <year>2017</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -42,6 +42,9 @@
operations. The hardware implementation usually offers improved performance over its
software-based counterpart, which is known as cryptographic acceleration.
</p>
+ <note>
+ <p>The file name requirement on the engine dynamic library can differ between SSL versions.</p>
+ </note>
</section>
<section>
@@ -54,9 +57,6 @@
<code>
1> {ok, Engine} = crypto:engine_load(&lt;&lt;"otp_test_engine">>, [], []).
{ok, #Ref}</code>
- <note>
- <p>The file name requirement on the engine dynamic library can differ between SSL versions.</p>
- </note>
</section>
<section>
@@ -72,9 +72,6 @@
&lt;&lt;"LOAD">>],
[]).
{ok, #Ref}</code>
- <note>
- <p>The dynamic engine is not supported in LibreSSL from version 2.2.1</p>
- </note>
</section>
<section>
@@ -100,6 +97,28 @@ engine_method_pkey_meths, engine_method_pkey_asn1_meths].
</section>
<section>
+ <title>Load with the ensure loaded function</title>
+ <p>
+ This function makes sure the engine is loaded just once and the ID is added to the internal
+ engine list of OpenSSL. The following calls to the function will check if the ID is loaded
+ and then just get a new reference to the engine.
+ </p>
+ <code>
+ 5> {ok, Engine} = crypto:ensure_engine_loaded(&lt;&lt;"MD5">>,
+ &lt;&lt;"/some/path/otp_test_engine.so">>).
+ {ok, #Ref}</code>
+ <p>
+ To unload it use crypto:ensure_engine_unloaded/1 which removes the ID from the internal list
+ before unloading the engine.
+ </p>
+ <code>
+ 6> crypto:ensure_engine_unloaded(&lt;&lt;"MD5">>).
+ ok</code>
+ </section>
+
+
+
+ <section>
<title>List all engines currently loaded</title>
<code>
5> crypto:engine_list().
diff --git a/lib/crypto/doc/src/new_api.xml b/lib/crypto/doc/src/new_api.xml
new file mode 100644
index 0000000000..bd2334ac9f
--- /dev/null
+++ b/lib/crypto/doc/src/new_api.xml
@@ -0,0 +1,260 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2014</year><year>2019</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>New and Old API</title>
+ <prepared>Hans Nilsson</prepared>
+ <docno></docno>
+ <date>2019-08-22</date>
+ <rev>A</rev>
+ <file>new_api.xml</file>
+ </header>
+ <p>
+ This chapter describes the new api to encryption and decryption.
+ </p>
+
+ <section>
+ <title>Background</title>
+ <p>The CRYPTO app has evolved during its lifetime. Since also the OpenSSL cryptolib has changed the
+ API several times, there are parts of the CRYPTO app that uses a very old one internally and
+ other parts that uses the latest one. The internal definitions of e.g cipher names was a bit hard
+ to maintain.
+ </p>
+ <p>It turned out that using the old api in the new way (more about that later), and still keep it
+ backwards compatible, was not possible. Specially as more precision in the error messages was wanted
+ it could not be combined with the old standard.
+ </p>
+ <p>Therefore the old api (see next section) is kept for now but internally implemented with new primitives.
+ </p>
+ </section>
+
+ <section>
+ <title>The old API</title>
+ <p>The old functions - not recommended for new programs - are:</p>
+ <list>
+ <item><seealso marker="crypto#block_encrypt-3">block_encrypt/3</seealso></item>
+ <item><seealso marker="crypto#block_encrypt-4">block_encrypt/4</seealso></item>
+ <item><seealso marker="crypto#block_decrypt-3">block_decrypt/3</seealso></item>
+ <item><seealso marker="crypto#block_decrypt-4">block_decrypt/4</seealso></item>
+ <item><seealso marker="crypto#stream_init-2">stream_init/2</seealso></item>
+ <item><seealso marker="crypto#stream_init-2">stream_init/3</seealso></item>
+ <item><seealso marker="crypto#stream_encrypt-2">stream_encrypt/2</seealso></item>
+ <item><seealso marker="crypto#stream_decrypt-2">stream_decrypt/2</seealso></item>
+ <item><seealso marker="crypto#supports-0">supports/0</seealso></item>
+ </list>
+ <p>They are not deprecated for now, but may be in a future release.
+ </p>
+ </section>
+
+ <section>
+ <title>The new API</title>
+ <p>The new functions for encrypting or decrypting one single binary are:
+ </p>
+ <list>
+ <item><seealso marker="crypto#crypto_one_time/4">crypto_one_time/4</seealso></item>
+ <item><seealso marker="crypto#crypto_one_time/5">crypto_one_time/5</seealso></item>
+ <item><seealso marker="crypto#crypto_one_time_aead/6">crypto_one_time_aead/6</seealso></item>
+ <item><seealso marker="crypto#crypto_one_time_aead/7">crypto_one_time_aead/7</seealso></item>
+ </list>
+ <p>In those functions the internal crypto state is first created and initialized
+ with the cipher type, the key and possibly other data. Then the single binary is encrypted
+ or decrypted,
+ the crypto state is de-allocated and the result of the crypto operation is returned.
+ </p>
+ <p>The <c>crypto_one_time_aead</c> functions are for the ciphers of mode <c>ccm</c> or
+ <c>gcm</c>, and for the cipher <c>chacha20-poly1305</c>.
+ </p>
+ <p>For repeated encryption or decryption of a text divided in parts, where the internal
+ crypto state is initialized once, and then many binaries are encrypted or decrypted with
+ the same state, the functions are:
+ </p>
+ <list>
+ <item><seealso marker="crypto#crypto_init/4">crypto_init/4</seealso></item>
+ <item><seealso marker="crypto#crypto_init/3">crypto_init/3</seealso></item>
+ <item><seealso marker="crypto#crypto_update/2">crypto_update/2</seealso></item>
+ </list>
+ <p>The <c>crypto_init</c> initialies an internal cipher state, and one or more calls of
+ <c>crypto_update</c> does the acual encryption or decryption. Note that AEAD ciphers
+ can't be handled this way due to their nature.
+ </p>
+ <p>For repeated encryption or decryption of a text divided in parts where the
+ same cipher and same key is used, but a new initialization vector (nounce) should be applied
+ for each part, the functions are:
+ </p>
+ <list>
+ <item><seealso marker="crypto#crypto_dyn_iv_init/3">crypto_dyn_iv_init/3</seealso></item>
+ <item><seealso marker="crypto#crypto_dyn_iv_update/3">crypto_dyn_iv_update/3</seealso></item>
+ </list>
+ <p>An example of where those functions are needed, is when handling the TLS protocol.</p>
+ <p>For information about available algorithms, use:
+ </p>
+ <list>
+ <item><seealso marker="crypto#supports-1">supports/1</seealso></item>
+ <item><seealso marker="crypto#hash_info-1">hash_info/1</seealso></item>
+ <item><seealso marker="crypto#cipher_info-1">cipher_info/1</seealso></item>
+ </list>
+
+ <section>
+ <title>Examples of crypto_init/4 and crypto_update/2</title>
+ <p>The functions <seealso marker="crypto#crypto_init/4">crypto_init/4</seealso>
+ and <seealso marker="crypto#crypto_update/2">crypto_update/2</seealso> are intended
+ to be used for encrypting or decrypting a sequence of blocks. First one call of
+ <c>crypto_init/4</c> initialises the crypto context. One or more calls <c>crypto_update/2</c>
+ does the actual encryption or decryption for each block.
+ </p>
+ <p>This example shows first the encryption of two blocks and then decryptions of the cipher
+ text, but divided into three blocks just to show that it is possible to divide the plain text and
+ cipher text differently for some ciphers:</p>
+ <code type="erl">
+ 1> crypto:start().
+ ok
+ 2> Key = &lt;&lt;1:128>>.
+ &lt;&lt;0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1>>
+ 3> IV = &lt;&lt;0:128>>.
+ &lt;&lt;0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>
+ 4> StateEnc = crypto:crypto_init(aes_128_ctr, Key, IV, true). % encrypt -> true
+ #Ref&lt;0.3768901617.1128660993.124047>
+ 5> crypto:crypto_update(StateEnc, &lt;&lt;"First bytes">>).
+ &lt;&lt;67,44,216,166,25,130,203,5,66,6,162>>
+ 6> crypto:crypto_update(StateEnc, &lt;&lt;"Second bytes">>).
+ &lt;&lt;16,79,94,115,234,197,94,253,16,144,151,41>>
+ 7>
+ 7> StateDec = crypto:crypto_init(aes_128_ctr, Key, IV, false). % decrypt -> false
+ #Ref&lt;0.3768901617.1128660994.124255>
+ 8> crypto:crypto_update(StateDec, &lt;&lt;67,44,216,166,25,130,203>>).
+ &lt;&lt;"First b">>
+ 9> crypto:crypto_update(StateDec, &lt;&lt;5,66,6,162,16,79,94,115,234,197,
+ 94,253,16,144,151>>).
+ &lt;&lt;"ytesSecond byte">>
+ 10> crypto:crypto_update(StateDec, &lt;&lt;41>>).
+ &lt;&lt;"s">>
+ 11>
+ </code>
+ <p>Note that the internal data that the <c>StateEnc</c> and <c>StateDec</c> references are
+ destructivly updated by the calls to <seealso marker="crypto#crypto_update/2">crypto_update/2</seealso>.
+ This is to gain time in the calls of the nifs interfacing the cryptolib. In a loop where the
+ state is saved in the loop's state, it also saves one update of the loop state per crypto operation.
+ </p>
+ <p>For example, a simple server receiving text parts to encrypt and send the result back to the
+ one who sent them (the <c>Requester</c>):
+ </p>
+ <code type="erl">
+ encode(Crypto, Key, IV) ->
+ crypto_loop(crypto:crypto_init(Crypto, Key, IV, true)).
+
+ crypto_loop(State) ->
+ receive
+ {Text, Requester} ->
+ Requester ! crypto:crypto_update(State, Text),
+ loop(State)
+ end.
+ </code>
+ </section>
+
+ <section>
+ <title>Example of crypto_one_time/5</title>
+ <p>The same example as in the
+ <seealso marker="#examples-of-crypto_init-4-and-crypto_update-2">previous section</seealso>,
+ but now with one call to <seealso marker="crypto#crypto_one_time/5">crypto_one_time/5</seealso>:
+ </p>
+ <code>
+ 1> Key = &lt;&lt;1:128>>.
+ &lt;&lt;0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1>>
+ 2> IV = &lt;&lt;0:128>>.
+ &lt;&lt;0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>
+ 3> Txt = [&lt;&lt;"First bytes">>,&lt;&lt;"Second bytes">>].
+ [&lt;&lt;"First bytes">>,&lt;&lt;"Second bytes">>]
+ 4> crypto:crypto_one_time(aes_128_ctr, Key, IV, Txt, true).
+ &lt;&lt;67,44,216,166,25,130,203,5,66,6,162,16,79,94,115,234,
+ 197,94,253,16,144,151,41>>
+ 5>
+ </code>
+ <p>The <c>[&lt;&lt;"First bytes">>,&lt;&lt;"Second bytes">>]</c> could of course have been one
+ single binary: <c>&lt;&lt;"First bytesSecond bytes">></c>.
+ </p>
+ </section>
+
+ <section>
+ <title>Example of crypto_one_time_aead/6</title>
+ <p>The same example as in the
+ <seealso marker="#example-of-crypto_one_time-5">previous section</seealso>,
+ but now with one call to <seealso marker="crypto#crypto_one_time_aead/6">crypto_one_time_aead/6</seealso>:
+ </p>
+ <code>
+ 1> Key = &lt;&lt;1:128>>.
+ &lt;&lt;0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1>>
+ 2> IV = &lt;&lt;0:128>>.
+ &lt;&lt;0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>
+ 3> Txt = [&lt;&lt;"First bytes">>,&lt;&lt;"Second bytes">>].
+ [&lt;&lt;"First bytes">>,&lt;&lt;"Second bytes">>]
+ 4> AAD = &lt;&lt;"Some bytes">>.
+ &lt;&lt;"Some bytes">>
+ 5> crypto:crypto_one_time_aead(aes_128_gcm, Key, IV, Txt, AAD, true).
+ {&lt;&lt;240,130,38,96,130,241,189,52,3,190,179,213,132,1,72,
+ 192,103,176,90,104,15,71,158>>,
+ &lt;&lt;131,47,45,91,142,85,9,244,21,141,214,71,31,135,2,155>>}
+ 9>
+ </code>
+ <p>The <c>[&lt;&lt;"First bytes">>,&lt;&lt;"Second bytes">>]</c> could of course have been one
+ single binary: <c>&lt;&lt;"First bytesSecond bytes">></c>.
+ </p>
+ </section>
+
+ </section>
+
+ <section>
+ <title>Retired cipher names</title>
+ <p>This table lists the retired cipher names in the first column and suggests names to replace them with
+ in the second column.
+ </p>
+ <p>The new names follows the OpenSSL libcrypto names. The format is ALGORITM_KEYSIZE_MODE.
+ </p>
+ <p>Examples of algorithms are aes, chacha20 and des. The keysize is the number of bits
+ and examples of the mode are cbc, ctr and gcm. The mode may be followed by a number depending
+ on the mode. An example is the ccm mode which has a variant called ccm8 where the so called tag
+ has a length of eight bits.
+ </p>
+ <p>The old names had by time lost any common naming which the new names now introduces. The new names include
+ the key length which improves the error checking in the lower levels of the crypto application.
+ </p>
+
+ <table>
+ <row><cell><strong>Instead of:</strong></cell> <cell><strong>Use:</strong> </cell></row>
+
+ <row><cell><c>aes_cbc128</c> </cell> <cell> <c>aes_128_cbc</c> </cell></row>
+ <row><cell><c>aes_cbc256</c> </cell> <cell> <c>aes_256_cbc</c> </cell></row>
+ <row><cell><c>aes_cbc</c> </cell> <cell> <c>aes_128_cbc, aes_192_cbc, aes_256_cbc</c></cell></row>
+ <row><cell><c>aes_ccm</c> </cell> <cell> <c>aes_128_ccm, aes_192_ccm, aes_256_ccm</c></cell></row>
+ <row><cell><c>aes_cfb128</c> </cell> <cell> <c>aes_128_cfb128, aes_192_cfb128, aes_256_cfb128</c></cell></row>
+ <row><cell><c>aes_cfb8</c> </cell> <cell> <c>aes_128_cfb8, aes_192_cfb8, aes_256_cfb8</c></cell></row>
+ <row><cell><c>aes_ctr</c> </cell> <cell> <c>aes_128_ctr, aes_192_ctr, aes_256_ctr</c></cell></row>
+ <row><cell><c>aes_gcm</c> </cell> <cell> <c>aes_128_gcm, aes_192_gcm, aes_256_gcm</c></cell></row>
+ <row><cell><c>des3_cbc</c> </cell> <cell> <c>des_ede3_cbc</c></cell></row>
+ <row><cell><c>des3_cbf</c> </cell> <cell> <c>des_ede3_cfb</c></cell></row>
+ <row><cell><c>des3_cfb</c> </cell> <cell> <c>des_ede3_cfb</c></cell></row>
+ <row><cell><c>des_ede3</c> </cell> <cell> <c>des_ede3_cbc</c></cell></row>
+ <row><cell><c>des_ede3_cbf</c> </cell> <cell> <c>des_ede3_cfb</c></cell></row>
+ <tcaption></tcaption>
+ </table>
+ </section>
+
+</chapter>
diff --git a/lib/crypto/doc/src/notes.xml b/lib/crypto/doc/src/notes.xml
index 1f788a4e35..b69657bfa8 100644
--- a/lib/crypto/doc/src/notes.xml
+++ b/lib/crypto/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1999</year><year>2017</year>
+ <year>1999</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,6 +31,465 @@
</header>
<p>This document describes the changes made to the Crypto application.</p>
+<section><title>Crypto 4.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed a bug in error return for <c>crypto:poly1305/2</c>.
+ It returned the atom <c>notsup</c> instead of the
+ exception <c>notsup</c>.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15677</p>
+ </item>
+ <item>
+ <p>
+ The cipher chacha20 was introduced in OpenSSL 1.1.0.
+ However, it could in a very odd situation, fail for
+ versions less than OpenSSL 1.1.0d. It is therefore
+ disabled for those versions.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15678</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> A new <c>rand</c> module algorithm, <c>exro928ss</c>
+ (Xoroshiro928**), has been implemented. It has got a
+ really long period and good statistical quality for all
+ output bits, while still being only about 50% slower than
+ the default algorithm. </p><p> The same generator is also
+ used as a long period counter in a new <c>crypto</c>
+ plugin for the <c>rand</c> module, algorithm
+ <c>crypto_aes</c>. This plugin uses AES-256 to scramble
+ the counter which buries any detectable statistical
+ artifacts. Scrambling is done in chunks which are cached
+ to get good amortized speed (about half of the default
+ algorithm). </p>
+ <p>
+ Own Id: OTP-14461 Aux Id: PR-1857 </p>
+ </item>
+ <item>
+ <p>
+ Crypto's single C-file is split into multiple files. The
+ different coding styles in the different parts are
+ unified into a single style.</p>
+ <p>
+ Own Id: OTP-14732 Aux Id: PR-2068, PR-2095 </p>
+ </item>
+ <item>
+ <p>
+ Build configuration of the <c>crypto</c> application has
+ been moved from the <c>erts</c> application into the
+ <c>crypto</c> application.</p>
+ <p>
+ Own Id: OTP-15129</p>
+ </item>
+ <item>
+ <p>
+ Adds two hash functions <c>blake2b</c> and <c>blake2s</c>
+ (64 bit hash and 32 bit hash respectively). These are
+ modern and standard hash functions used in blockchains
+ and encrypted communication protocols. The hash functions
+ are available in OpenSSL since version 1.1.1.</p>
+ <p>
+ Own Id: OTP-15564 Aux Id: PR-2129 </p>
+ </item>
+ <item>
+ <p>
+ A new API is implemented in crypto. See the CRYPTO user's
+ guide, chapter <i>New and Old API</i> for more
+ information.</p>
+ <p>
+ The old api with the <c>crypto:block_*</c> and
+ <c>crypto:stream_*</c> interfaces are kept for
+ compatibility, but implemented with the new api. Please
+ note that since the error checking is more thorough,
+ there <i>might</i> be arguments with for example faulty
+ lengths that are no longer accepted.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15644 Aux Id: OTP-14732 , OTP-15451, PR-1857
+ , PR-2068, PR-2095 </p>
+ </item>
+ <item>
+ <p>
+ The new hash_info/1 and cipher_info/1 functions returns
+ maps with information about the hash or cipher in the
+ argument.</p>
+ <p>
+ Own Id: OTP-15655 Aux Id: PR-2173, ERL-864, PR-2186 </p>
+ </item>
+ <item>
+ <p>
+ Obey additional OpenSSL configure flags when compiling
+ the C-part of the CRYPTO application: <c>no-bf</c>,
+ <c>no-blake2</c>, <c>no-chacha</c>, <c>no-cmac</c>,
+ <c>no-dh</c>, <c>no-dsa</c>, <c>no-md4</c>,
+ <c>no-poly1305</c>, <c>no-rc2</c>, <c>no-rc4</c> and
+ <c>no-rmd160</c>.</p>
+ <p>
+ Own Id: OTP-15683</p>
+ </item>
+ <item>
+ <p>
+ A new function <c>crypto:supports/1</c> is introduced.
+ The single argument takes an atom as argument:
+ <c>hashes</c>, <c>public_keys</c>, <c>ciphers</c>,
+ <c>macs</c>, <c>curves</c> or <c>rsa_opts</c>. The return
+ value is a list of supported algorithms.</p>
+ <p>
+ The difference with the existing <c>crypto:supports/0</c>
+ is, apart from the argument and the return value, that
+ the old function reports what is supported by the old
+ api, and the new function reports algorithms in the new
+ api.</p>
+ <p>
+ Own Id: OTP-15771</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Crypto 4.4.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed build link error on Windows. Unresolved symbol
+ 'bcmp'.</p>
+ <p>
+ Own Id: OTP-15750 Aux Id: ERL-905 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Crypto 4.4.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixes a bug that caused <c>crypto:sign</c> and
+ <c>crypto:verify</c> to return the error message
+ <c>badarg</c> instead of <c>notsup</c> in one case. That
+ case was when signing or verifying with eddsa keys (that
+ is, ed15519 or ed448), but only when FIPS was supported
+ and enabled.</p>
+ <p>
+ Own Id: OTP-15634</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Added a crypto benchmark test suite.</p>
+ <p>
+ Own Id: OTP-15447</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Crypto 4.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Updated the RSA options part in the crypto application's
+ C-code, documentation and tests.</p>
+ <p>
+ Own Id: OTP-15302</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Added ed25519 and ed448 sign/verify.</p>
+ <p>
+ Requires OpenSSL 1.1.1 or higher as cryptolib under the
+ OTP application <c>crypto</c>.</p>
+ <p>
+ Own Id: OTP-15419 Aux Id: OTP-15094 </p>
+ </item>
+ <item>
+ <p>
+ Fixed valgrind warnings.</p>
+ <p>
+ Own Id: OTP-15467</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Crypto 4.3.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The RSA options <c>rsa_mgf1_md</c>, <c>rsa_oaep_md</c>,
+ and <c>rsa_oaep_label</c> were always disabled. They will
+ now be enabled when a suitable cryptolib is used.</p>
+ <p>
+ They are still experimental and may change without prior
+ notice.</p>
+ <p>
+ Own Id: OTP-15212 Aux Id: ERL-675, PR1899, PR838 </p>
+ </item>
+ <item>
+ <p>
+ The ciphers <c>aes_ige256</c> and <c>blowfish_cbc</c> had
+ naming issues in <c>crypto:next_iv/2</c>.</p>
+ <p>
+ Own Id: OTP-15283</p>
+ </item>
+ <item>
+ <p>
+ the <c>RSA_SSLV23_PADDING</c> is disabled if LibreSSL is
+ used as cryptlib. This is due to compilation problems.</p>
+ <p>
+ This will be investigated further in the future.</p>
+ <p>
+ Own Id: OTP-15303</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The supported named elliptic curves are now reported in
+ <c>crypto:supports/0</c> in a new entry tagged by
+ <c>'curves'</c>.</p>
+ <p>
+ The function <c>crypto:ec_curves/0</c> is kept for
+ compatibility.</p>
+ <p>
+ Own Id: OTP-14717 Aux Id: OTP-15244 </p>
+ </item>
+ <item>
+ <p>
+ The typing in the CRYPTO and PUBLIC_KEY applications are
+ reworked and a few mistakes are corrected.</p>
+ <p>
+ The documentation is now generated from the typing and
+ some clarifications are made.</p>
+ <p>
+ A new chapter on Algorithm Details such as key sizes and
+ availability is added to the CRYPTO User's Guide.</p>
+ <p>
+ Own Id: OTP-15134</p>
+ </item>
+ <item>
+ <p>
+ Support for SHA3 both as a separate hash and in HMAC is
+ now available if OpenSSL 1.1.1 or higher is used as
+ cryptolib.</p>
+ <p>
+ Available lengths are reported in the <c>'hashs'</c>
+ entry in <c>crypto:supports/0</c> as <c>sha3_*</c>.</p>
+ <p>
+ Own Id: OTP-15153</p>
+ </item>
+ <item>
+ <p>
+ The mac algorithm <c>poly1305</c> and the cipher
+ algorithm <c>chacha20</c> are now supported if OpenSSL
+ 1.1.1 or higher is used as cryptolib.</p>
+ <p>
+ Own Id: OTP-15164 Aux Id: OTP-15209 </p>
+ </item>
+ <item>
+ <p>
+ The key exchange Edward curves <c>x25519</c> and
+ <c>x448</c> are now supported if OpenSSL 1.1.1 or higher
+ is used as cryptolib.</p>
+ <p>
+ Own Id: OTP-15240 Aux Id: OTP-15133 </p>
+ </item>
+ <item>
+ <p>
+ The supported RSA options for sign/verify and
+ encrypt/decrypt are now reported in
+ <c>crypto:supports/0</c> in a new entry tagged by
+ '<c>rsa_opts</c>'.</p>
+ <p>
+ The exakt set is still experimental and may change
+ without prior notice.</p>
+ <p>
+ Own Id: OTP-15260</p>
+ </item>
+ <item>
+ <p>
+ The cipher <c>aes_ccm</c> is added.</p>
+ <p>
+ Own Id: OTP-15286</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Crypto 4.3.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Update the crypto engine functions to handle multiple
+ loads of an engine. </p> <p><c>engine_load/3/4</c> is
+ updated so it doesn't add the engine ID to OpenSSLs
+ internal list of engines which makes it possible to run
+ the engine_load more than once if it doesn't contain
+ global data.</p> <p>Added <c>ensure_engine_loaded/2/3</c>
+ which guarantees that the engine just is loaded once and
+ the following calls just returns a reference to it. This
+ is done by add the ID to the internal OpenSSL list and
+ check if it is already registered when the function is
+ called.</p> <p>Added <c>ensure_engine_unloaded/1/2</c> to
+ unload engines loaded with ensure_engine_loaded.</p>
+ <p>Then some more utility functions are added.</p>
+ <p><c>engine_add/1</c>, adds the engine to OpenSSL
+ internal list</p> <p><c>engine_remove/1</c>, remove the
+ engine from OpenSSL internal list</p>
+ <p><c>engine_get_id/1</c>, fetch the engines id</p>
+ <p><c>engine_get_name/1</c>, fetch the engine name</p>
+ <p>
+ Own Id: OTP-15233</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Crypto 4.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a node crash in <c>crypto:compute_key(ecdh,
+ ...)</c> when passing a wrongly typed Others
+ argument.</p>
+ <p>
+ Own Id: OTP-15194 Aux Id: ERL-673 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Crypto 4.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Removed two undocumented and erroneous functions
+ (<c>crypto:dh_generate_parameters/2</c> and
+ <c>crypto:dh_check/1</c>).</p>
+ <p>
+ Own Id: OTP-14956 Aux Id: ERL-579 </p>
+ </item>
+ <item>
+ <p>
+ Fixed bug causing VM crash if doing runtime upgrade of a
+ crypto module built against OpenSSL older than 0.9.8h.
+ Bug exists since OTP-20.2.</p>
+ <p>
+ Own Id: OTP-15088</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ A new <c>rand</c> plugin algorithm has been implemented
+ in <c>crypto</c>, that is: <c>crypto_cache</c>. It uses
+ strong random bytes as randomness source and caches them
+ to get good speed. See <c>crypto:rand_seed_alg/1</c>.</p>
+ <p>
+ Own Id: OTP-13370 Aux Id: PR-1573 </p>
+ </item>
+ <item>
+ <p>
+ Diffie-Hellman key functions are re-written with the
+ EVP_PKEY api.</p>
+ <p>
+ Own Id: OTP-14864</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Crypto 4.2.2.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a node crash in <c>crypto:compute_key(ecdh,
+ ...)</c> when passing a wrongly typed Others
+ argument.</p>
+ <p>
+ Own Id: OTP-15194 Aux Id: ERL-673 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Crypto 4.2.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ If OPENSSL_NO_EC was set, the compilation of the crypto
+ nifs failed.</p>
+ <p>
+ Own Id: OTP-15073</p>
+ </item>
+ <item>
+ <p>
+ C-compile errors for LibreSSL 2.7.0 - 2.7.2 fixed</p>
+ <p>
+ Own Id: OTP-15074 Aux Id: ERL-618 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Crypto 4.2.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/crypto/doc/src/specs.xml b/lib/crypto/doc/src/specs.xml
new file mode 100644
index 0000000000..66c79a906b
--- /dev/null
+++ b/lib/crypto/doc/src/specs.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<specs xmlns:xi="http://www.w3.org/2001/XInclude">
+ <xi:include href="../specs/specs_crypto.xml"/>
+</specs>
diff --git a/lib/crypto/doc/src/usersguide.xml b/lib/crypto/doc/src/usersguide.xml
index e2ba1fe160..134f900d4c 100644
--- a/lib/crypto/doc/src/usersguide.xml
+++ b/lib/crypto/doc/src/usersguide.xml
@@ -4,7 +4,7 @@
<part xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>2003</year><year>2016</year>
+ <year>2003</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -50,4 +50,6 @@
<xi:include href="fips.xml"/>
<xi:include href="engine_load.xml"/>
<xi:include href="engine_keys.xml"/>
+ <xi:include href="algorithm_details.xml"/>
+ <xi:include href="new_api.xml"/>
</part>
diff --git a/lib/crypto/src/Makefile b/lib/crypto/src/Makefile
index edad0e6b61..1753ba4f36 100644
--- a/lib/crypto/src/Makefile
+++ b/lib/crypto/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2016. All Rights Reserved.
+# Copyright Ericsson AB 1999-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/crypto/src/crypto.app.src b/lib/crypto/src/crypto.app.src
index 1d3f35e465..492aa10e51 100644
--- a/lib/crypto/src/crypto.app.src
+++ b/lib/crypto/src/crypto.app.src
@@ -24,7 +24,7 @@
crypto_ec_curves]},
{registered, []},
{applications, [kernel, stdlib]},
- {env, [{fips_mode, false}]},
+ {env, [{fips_mode, false}, {rand_cache_size, 896}]},
{runtime_dependencies, ["erts-9.0","stdlib-3.4","kernel-5.3"]}]}.
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 1a1b4f98b5..8ffdde2b90 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,46 +24,98 @@
-export([start/0, stop/0, info_lib/0, info_fips/0, supports/0, enable_fips_mode/1,
version/0, bytes_to_integer/1]).
+-export([cipher_info/1, hash_info/1]).
-export([hash/2, hash_init/1, hash_update/2, hash_final/1]).
-export([sign/4, sign/5, verify/5, verify/6]).
-export([generate_key/2, generate_key/3, compute_key/4]).
-export([hmac/3, hmac/4, hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]).
-export([cmac/3, cmac/4]).
+-export([poly1305/2]).
-export([exor/2, strong_rand_bytes/1, mod_pow/3]).
--export([rand_seed/0]).
--export([rand_seed_s/0]).
+-export([rand_seed/0, rand_seed_alg/1, rand_seed_alg/2]).
+-export([rand_seed_s/0, rand_seed_alg_s/1, rand_seed_alg_s/2]).
-export([rand_plugin_next/1]).
+-export([rand_plugin_aes_next/1, rand_plugin_aes_jump/1]).
-export([rand_plugin_uniform/1]).
-export([rand_plugin_uniform/2]).
+-export([rand_cache_plugin_next/1]).
-export([rand_uniform/2]).
--export([block_encrypt/3, block_decrypt/3, block_encrypt/4, block_decrypt/4]).
-export([next_iv/2, next_iv/3]).
--export([stream_init/2, stream_init/3, stream_encrypt/2, stream_decrypt/2]).
-export([public_encrypt/4, private_decrypt/4]).
-export([private_encrypt/4, public_decrypt/4]).
--export([dh_generate_parameters/2, dh_check/1]). %% Testing see
-export([privkey_to_pubkey/2]).
-export([ec_curve/1, ec_curves/0]).
-export([rand_seed/1]).
+
+%% Old interface. Now implemented with the New interface
+-export([stream_init/2, stream_init/3,
+ stream_encrypt/2,
+ stream_decrypt/2,
+ block_encrypt/3, block_encrypt/4,
+ block_decrypt/3, block_decrypt/4
+ ]).
+
+%% New interface
+-export([crypto_init/4, crypto_init/3,
+ crypto_update/2,
+ crypto_one_time/4, crypto_one_time/5,
+ crypto_one_time_aead/6, crypto_one_time_aead/7,
+ crypto_dyn_iv_init/3,
+ crypto_dyn_iv_update/3,
+ supports/1
+ ]).
+
+
%% Engine
-export([
engine_get_all_methods/0,
engine_load/3,
engine_load/4,
engine_unload/1,
+ engine_by_id/1,
engine_list/0,
engine_ctrl_cmd_string/3,
- engine_ctrl_cmd_string/4
+ engine_ctrl_cmd_string/4,
+ engine_add/1,
+ engine_remove/1,
+ engine_get_id/1,
+ engine_get_name/1,
+ ensure_engine_loaded/2,
+ ensure_engine_loaded/3,
+ ensure_engine_unloaded/1,
+ ensure_engine_unloaded/2
]).
+-export_type([ %% A minimum exported: only what public_key needs.
+ dh_private/0,
+ dh_public/0,
+ dss_digest_type/0,
+ ec_named_curve/0,
+ ecdsa_digest_type/0,
+ pk_encrypt_decrypt_opts/0,
+ pk_sign_verify_opts/0,
+ rsa_digest_type/0,
+ sha1/0,
+ sha2/0
+ ]).
+
-export_type([engine_ref/0,
key_id/0,
password/0
]).
-
+%%% Opaque types must be exported :(
+-export_type([
+ stream_state/0,
+ hmac_state/0,
+ hash_state/0,
+ crypto_state/0
+ ]).
+
%% Private. For tests.
--export([packed_openssl_version/4, engine_methods_convert_to_bitmask/2, get_test_engine/0]).
+-export([packed_openssl_version/4, engine_methods_convert_to_bitmask/2,
+ get_test_engine/0]).
+-export([rand_plugin_aes_jump_2pow20/1]).
-deprecated({rand_uniform, 2, next_major_release}).
@@ -73,17 +125,338 @@
%% Used by strong_rand_float/0
-define(HALF_DBL_EPSILON, 1.1102230246251565e-16). % math:pow(2, -53)
-%%-type ecdsa_digest_type() :: 'md5' | 'sha' | 'sha256' | 'sha384' | 'sha512'.
+
+%%% ===== BEGIN NEW TYPING ====
+
+%%% Basic
+-type key_integer() :: integer() | binary(). % Always binary() when used as return value
+
+%%% Keys
+-type rsa_public() :: [key_integer()] . % [E, N]
+-type rsa_private() :: [key_integer()] . % [E, N, D] | [E, N, D, P1, P2, E1, E2, C]
+-type rsa_params() :: {ModulusSizeInBits::integer(), PublicExponent::key_integer()} .
+
+-type dss_public() :: [key_integer()] . % [P, Q, G, Y]
+-type dss_private() :: [key_integer()] . % [P, Q, G, X]
+
+-type ecdsa_public() :: key_integer() .
+-type ecdsa_private() :: key_integer() .
+-type ecdsa_params() :: ec_named_curve() | ec_explicit_curve() .
+
+-type eddsa_public() :: key_integer() .
+-type eddsa_private() :: key_integer() .
+-type eddsa_params() :: edwards_curve_ed() .
+
+-type srp_public() :: key_integer() .
+-type srp_private() :: key_integer() .
+-type srp_gen_params() :: {user,srp_user_gen_params()} | {host,srp_host_gen_params()}.
+-type srp_comp_params() :: {user,srp_user_comp_params()} | {host,srp_host_comp_params()}.
+-type srp_user_gen_params() :: list(binary() | atom() | list()) .
+-type srp_host_gen_params() :: list(binary() | atom() | list()) .
+-type srp_user_comp_params() :: list(binary() | atom()) .
+-type srp_host_comp_params() :: list(binary() | atom()) .
+
+-type dh_public() :: key_integer() .
+-type dh_private() :: key_integer() .
+-type dh_params() :: [key_integer()] . % [P, G] | [P, G, PrivateKeyBitLength]
+
+-type ecdh_public() :: key_integer() .
+-type ecdh_private() :: key_integer() .
+-type ecdh_params() :: ec_named_curve() | edwards_curve_dh() | ec_explicit_curve() .
+
+
+%%% Curves
+
+-type ec_explicit_curve() :: {Field :: ec_field(),
+ Curve :: ec_curve(),
+ BasePoint :: binary(),
+ Order :: binary(),
+ CoFactor :: none | % FIXME: Really?
+ binary()
+ } .
+
+-type ec_curve() :: {A :: binary(),
+ B :: binary(),
+ Seed :: none | binary()
+ } .
+
+-type ec_field() :: ec_prime_field() | ec_characteristic_two_field() .
+
+-type ec_prime_field() :: {prime_field, Prime :: integer()} .
+-type ec_characteristic_two_field() :: {characteristic_two_field, M :: integer(), Basis :: ec_basis()} .
+
+-type ec_basis() :: {tpbasis, K :: non_neg_integer()}
+ | {ppbasis, K1 :: non_neg_integer(), K2 :: non_neg_integer(), K3 :: non_neg_integer()}
+ | onbasis .
+
+-type ec_named_curve() :: brainpoolP160r1
+ | brainpoolP160t1
+ | brainpoolP192r1
+ | brainpoolP192t1
+ | brainpoolP224r1
+ | brainpoolP224t1
+ | brainpoolP256r1
+ | brainpoolP256t1
+ | brainpoolP320r1
+ | brainpoolP320t1
+ | brainpoolP384r1
+ | brainpoolP384t1
+ | brainpoolP512r1
+ | brainpoolP512t1
+ | c2pnb163v1
+ | c2pnb163v2
+ | c2pnb163v3
+ | c2pnb176v1
+ | c2pnb208w1
+ | c2pnb272w1
+ | c2pnb304w1
+ | c2pnb368w1
+ | c2tnb191v1
+ | c2tnb191v2
+ | c2tnb191v3
+ | c2tnb239v1
+ | c2tnb239v2
+ | c2tnb239v3
+ | c2tnb359v1
+ | c2tnb431r1
+ | ipsec3
+ | ipsec4
+ | prime192v1
+ | prime192v2
+ | prime192v3
+ | prime239v1
+ | prime239v2
+ | prime239v3
+ | prime256v1
+ | secp112r1
+ | secp112r2
+ | secp128r1
+ | secp128r2
+ | secp160k1
+ | secp160r1
+ | secp160r2
+ | secp192k1
+ | secp192r1
+ | secp224k1
+ | secp224r1
+ | secp256k1
+ | secp256r1
+ | secp384r1
+ | secp521r1
+ | sect113r1
+ | sect113r2
+ | sect131r1
+ | sect131r2
+ | sect163k1
+ | sect163r1
+ | sect163r2
+ | sect193r1
+ | sect193r2
+ | sect233k1
+ | sect233r1
+ | sect239k1
+ | sect283k1
+ | sect283r1
+ | sect409k1
+ | sect409r1
+ | sect571k1
+ | sect571r1
+ | wtls1
+ | wtls10
+ | wtls11
+ | wtls12
+ | wtls3
+ | wtls4
+ | wtls5
+ | wtls6
+ | wtls7
+ | wtls8
+ | wtls9
+ .
+
+-type edwards_curve_dh() :: x25519 | x448 .
+
+-type edwards_curve_ed() :: ed25519 | ed448 .
+
+%%%----------------------------------------------------------------
+%%% New cipher schema
+%%%
+-type cipher() :: cipher_no_iv()
+ | cipher_iv()
+ | cipher_aead() .
+
+-type cipher_no_iv() :: aes_128_ecb
+ | aes_192_ecb
+ | aes_256_ecb
+
+ | blowfish_ecb
+ | des_ecb
+ | rc4 .
+
+-type cipher_iv() :: aes_128_cbc
+ | aes_192_cbc
+ | aes_256_cbc
+
+ | aes_128_cfb128
+ | aes_192_cfb128
+ | aes_256_cfb128
+
+ | aes_128_cfb8
+ | aes_192_cfb8
+ | aes_256_cfb8
+
+ | aes_128_ctr
+ | aes_192_ctr
+ | aes_256_ctr
+
+ | aes_ige256
+
+ | blowfish_cbc
+ | blowfish_cfb64
+ | blowfish_ofb64
+ | chacha20
+ | des_ede3_cbc
+ | des_ede3_cfb
+
+ | des_cbc
+ | des_cfb
+ | rc2_cbc .
+
+
+-type cipher_aead() :: aes_128_ccm
+ | aes_192_ccm
+ | aes_256_ccm
+
+ | aes_128_gcm
+ | aes_192_gcm
+ | aes_256_gcm
+
+ | chacha20_poly1305 .
+
+
+%% -type retired_cipher_no_iv_aliases() :: aes_ecb .
+
+%% -type retired_cipher_iv_aliases() :: aes_cbc
+%% | aes_cbc128 % aes_128_cbc
+%% | aes_cbc256 % aes_256_cbc
+%% | aes_cfb128
+%% | aes_cfb8
+%% | aes_ctr
+%% | des3_cbc % des_ede3_cbc
+%% | des_ede3 % des_ede3_cbc
+%% | des_ede3_cbf % des_ede3_cfb
+%% | des3_cbf % des_ede3_cfb
+%% | des3_cfb . % des_ede3_cfb
+
+%% -type retired_cipher_aead_aliases() :: aes_ccm
+%% | aes_gcm .
+
+%%%----------------------------------------------------------------
+%%% Old cipher scheme
+%%%
+%%%
+-type block_cipher_without_iv() :: ecb_cipher() .
+
+-type block_cipher_with_iv() :: cbc_cipher()
+ | cfb_cipher()
+ | blowfish_ofb64
+ | aes_ige256 .
+
+-type stream_cipher() :: ctr_cipher()
+ | chacha20
+ | rc4 .
+
+
+%%%----
+-type cbc_cipher() :: aes_128_cbc
+ | aes_192_cbc
+ | aes_256_cbc
+ | blowfish_cbc
+ | des_cbc
+ | des_ede3_cbc
+ | rc2_cbc
+ | retired_cbc_cipher_aliases() .
+
+-type retired_cbc_cipher_aliases() :: aes_cbc % aes_*_cbc
+ | aes_cbc128 % aes_128_cbc
+ | aes_cbc256 % aes_256_cbc
+ | des3_cbc % des_ede3_cbc
+ | des_ede3 . % des_ede3_cbc
+
+%%%----
+-type cfb_cipher() :: aes_128_cfb128
+ | aes_192_cfb128
+ | aes_256_cfb128
+ | aes_128_cfb8
+ | aes_192_cfb8
+ | aes_256_cfb8
+ | blowfish_cfb64
+ | des_cfb
+ | des_ede3_cfb
+ | retired_cfb_cipher_aliases() .
+
+-type retired_cfb_cipher_aliases() :: aes_cfb8 % aes_*_cfb8
+ | aes_cfb128 % aes_*_cfb128
+ | des3_cbf % des_ede3_cfb, cfb misspelled
+ | des3_cfb % des_ede3_cfb
+ | des_ede3_cbf .% cfb misspelled
+
+
+%%%----
+-type ctr_cipher() :: aes_128_ctr
+ | aes_192_ctr
+ | aes_256_ctr
+ | retired_ctr_cipher_aliases() .
+
+-type retired_ctr_cipher_aliases() :: aes_ctr . % aes_*_ctr
+
+%%%----
+-type ecb_cipher() :: aes_128_ecb
+ | aes_192_ecb
+ | aes_256_ecb
+ | blowfish_ecb
+ | retired_ecb_cipher_aliases() .
+
+-type retired_ecb_cipher_aliases() :: aes_ecb .
+
+%%%----
+-type aead_cipher() :: aes_gcm | aes_ccm | chacha20_poly1305 .
+
+
+%%%----- end old cipher schema ------------------------------------
+%%%----------------------------------------------------------------
+
+-type key() :: iodata().
+-type des3_key() :: [key()].
+
+%%%
+-type rsa_digest_type() :: sha1() | sha2() | md5 | ripemd160 .
+-type dss_digest_type() :: sha1() | sha2() .
+-type ecdsa_digest_type() :: sha1() | sha2() .
+
+-type sha1() :: sha .
+-type sha2() :: sha224 | sha256 | sha384 | sha512 .
+-type sha3() :: sha3_224 | sha3_256 | sha3_384 | sha3_512 .
+-type blake2() :: blake2b | blake2s .
+
+-type compatibility_only_hash() :: md5 | md4 .
+
-type crypto_integer() :: binary() | integer().
-%%-type ec_named_curve() :: atom().
-%%-type ec_point() :: crypto_integer().
-%%-type ec_basis() :: {tpbasis, K :: non_neg_integer()} | {ppbasis, K1 :: non_neg_integer(), K2 :: non_neg_integer(), K3 :: non_neg_integer()} | onbasis.
-%%-type ec_field() :: {prime_field, Prime :: integer()} | {characteristic_two_field, M :: integer(), Basis :: ec_basis()}.
-%%-type ec_prime() :: {A :: crypto_integer(), B :: crypto_integer(), Seed :: binary() | none}.
-%%-type ec_curve_spec() :: {Field :: ec_field(), Prime :: ec_prime(), Point :: crypto_integer(), Order :: integer(), CoFactor :: none | integer()}.
-%%-type ec_curve() :: ec_named_curve() | ec_curve_spec().
-%%-type ec_key() :: {Curve :: ec_curve(), PrivKey :: binary() | undefined, PubKey :: ec_point() | undefined}.
+%%%
+%% Exceptions
+%% error:badarg
+%% error:notsup
+-type run_time_error() :: no_return().
+
+%% Exceptions
+%% error:{badarg,Reason::term()}
+%% error:{notsup,Reason::term()}
+%% error:{error,Reason::term()}
+-type descriptive_error() :: no_return() .
+
+
+%%--------------------------------------------------------------------
-compile(no_native).
-on_load(on_load/0).
-define(CRYPTO_NIF_VSN,302).
@@ -98,186 +471,433 @@ nif_stub_error(Line) ->
%% Crypto app version history:
%% (no version): Driver implementation
%% 2.0 : NIF implementation, requires OTP R14
+
+%% When generating documentation from crypto.erl, the macro ?CRYPTO_VSN is not defined.
+%% That causes the doc generation to stop...
+-ifndef(CRYPTO_VSN).
+-define(CRYPTO_VSN, "??").
+-endif.
version() -> ?CRYPTO_VSN.
+-spec start() -> ok | {error, Reason::term()}.
start() ->
application:start(crypto).
+-spec stop() -> ok | {error, Reason::term()}.
stop() ->
application:stop(crypto).
-supports()->
- {Hashs, PubKeys, Ciphers, Macs} = algorithms(),
-
- [{hashs, Hashs},
- {ciphers, Ciphers},
- {public_keys, PubKeys},
- {macs, Macs}
- ].
-
+-spec supports() -> [Support]
+ when Support :: {hashs, Hashs}
+ | {ciphers, Ciphers}
+ | {public_keys, PKs}
+ | {macs, Macs}
+ | {curves, Curves}
+ | {rsa_opts, RSAopts},
+ Hashs :: [sha1() | sha2() | sha3() | blake2() | ripemd160 | compatibility_only_hash()],
+ Ciphers :: [cipher()],
+ PKs :: [rsa | dss | ecdsa | dh | ecdh | ec_gf2m],
+ Macs :: [hmac | cmac | poly1305],
+ Curves :: [ec_named_curve() | edwards_curve_dh() | edwards_curve_ed()],
+ RSAopts :: [rsa_sign_verify_opt() | rsa_opt()] .
+supports() ->
+ [{hashs, hash_algorithms()},
+ {ciphers, prepend_old_aliases( cipher_algorithms())},
+ {public_keys, pubkey_algorithms()},
+ {macs, mac_algorithms()},
+ {curves, curve_algorithms()},
+ {rsa_opts, rsa_opts_algorithms()}
+ ].
+
+
+-spec supports(Type) -> Support
+ when Type :: hashs
+ | ciphers
+ | public_keys
+ | macs
+ | curves
+ | rsa_opts,
+ Support :: Hashs
+ | Ciphers
+ | PKs
+ | Macs
+ | Curves
+ | RSAopts,
+ Hashs :: [sha1() | sha2() | sha3() | blake2() | ripemd160 | compatibility_only_hash()],
+ Ciphers :: [cipher()],
+ PKs :: [rsa | dss | ecdsa | dh | ecdh | ec_gf2m],
+ Macs :: [hmac | cmac | poly1305],
+ Curves :: [ec_named_curve() | edwards_curve_dh() | edwards_curve_ed()],
+ RSAopts :: [rsa_sign_verify_opt() | rsa_opt()] .
+
+supports(hashs) -> hash_algorithms();
+supports(public_keys) -> pubkey_algorithms();
+supports(ciphers) -> cipher_algorithms();
+supports(macs) -> mac_algorithms();
+supports(curves) -> curve_algorithms();
+supports(rsa_opts) -> rsa_opts_algorithms().
+
+
+-spec info_lib() -> [{Name,VerNum,VerStr}] when Name :: binary(),
+ VerNum :: integer(),
+ VerStr :: binary() .
info_lib() -> ?nif_stub.
-spec info_fips() -> not_supported | not_enabled | enabled.
info_fips() -> ?nif_stub.
--spec enable_fips_mode(boolean()) -> boolean().
-
+-spec enable_fips_mode(Enable) -> Result when Enable :: boolean(),
+ Result :: boolean().
enable_fips_mode(_) -> ?nif_stub.
--spec hash(_, iodata()) -> binary().
+%%%================================================================
+%%%
+%%% Hashing
+%%%
+%%%================================================================
+
+-type hash_algorithm() :: sha1() | sha2() | sha3() | blake2() | ripemd160 | compatibility_only_hash() .
+
+-spec hash_info(Type) -> Result | run_time_error()
+ when Type :: hash_algorithm(),
+ Result :: #{size := integer(),
+ block_size := integer(),
+ type := integer()
+ } .
+hash_info(Type) ->
+ notsup_to_error(hash_info_nif(Type)).
+
+-spec hash(Type, Data) -> Digest when Type :: hash_algorithm(),
+ Data :: iodata(),
+ Digest :: binary().
+hash(Type, Data) ->
+ Data1 = iolist_to_binary(Data),
+ MaxBytes = max_bytes(),
+ hash(Type, Data1, erlang:byte_size(Data1), MaxBytes).
+
+-opaque hash_state() :: reference().
-hash(Hash, Data0) ->
- Data = iolist_to_binary(Data0),
+-spec hash_init(Type) -> State when Type :: hash_algorithm(),
+ State :: hash_state().
+hash_init(Type) ->
+ notsup_to_error(hash_init_nif(Type)).
+
+-spec hash_update(State, Data) -> NewState when State :: hash_state(),
+ NewState :: hash_state(),
+ Data :: iodata() .
+hash_update(Context, Data) ->
+ Data1 = iolist_to_binary(Data),
MaxBytes = max_bytes(),
- hash(Hash, Data, erlang:byte_size(Data), MaxBytes).
+ hash_update(Context, Data1, erlang:byte_size(Data1), MaxBytes).
--spec hash_init('md5'|'md4'|'ripemd160'|
- 'sha'|'sha224'|'sha256'|'sha384'|'sha512') -> any().
+-spec hash_final(State) -> Digest when State :: hash_state(),
+ Digest :: binary().
+hash_final(Context) ->
+ notsup_to_error(hash_final_nif(Context)).
-hash_init(Hash) ->
- notsup_to_error(hash_init_nif(Hash)).
+%%%================================================================
+%%%
+%%% MACs (Message Authentication Codes)
+%%%
+%%%================================================================
--spec hash_update(_, iodata()) -> any().
+%%%---- HMAC
-hash_update(State, Data0) ->
- Data = iolist_to_binary(Data0),
- MaxBytes = max_bytes(),
- hash_update(State, Data, erlang:byte_size(Data), MaxBytes).
+-type hmac_hash_algorithm() :: sha1() | sha2() | sha3() | compatibility_only_hash().
--spec hash_final(_) -> binary().
+%%%---- hmac/3,4
-hash_final(State) ->
- notsup_to_error(hash_final_nif(State)).
+-spec hmac(Type, Key, Data) ->
+ Mac when Type :: hmac_hash_algorithm(),
+ Key :: iodata(),
+ Data :: iodata(),
+ Mac :: binary() .
+hmac(Type, Key, Data) ->
+ Data1 = iolist_to_binary(Data),
+ hmac(Type, Key, Data1, undefined, erlang:byte_size(Data1), max_bytes()).
+-spec hmac(Type, Key, Data, MacLength) ->
+ Mac when Type :: hmac_hash_algorithm(),
+ Key :: iodata(),
+ Data :: iodata(),
+ MacLength :: integer(),
+ Mac :: binary() .
--spec hmac(_, iodata(), iodata()) -> binary().
--spec hmac(_, iodata(), iodata(), integer()) -> binary().
--spec hmac_init(atom(), iodata()) -> binary().
--spec hmac_update(binary(), iodata()) -> binary().
--spec hmac_final(binary()) -> binary().
--spec hmac_final_n(binary(), integer()) -> binary().
+hmac(Type, Key, Data, MacLength) ->
+ Data1 = iolist_to_binary(Data),
+ hmac(Type, Key, Data1, MacLength, erlang:byte_size(Data1), max_bytes()).
-hmac(Type, Key, Data0) ->
- Data = iolist_to_binary(Data0),
- hmac(Type, Key, Data, undefined, erlang:byte_size(Data), max_bytes()).
-hmac(Type, Key, Data0, MacSize) ->
- Data = iolist_to_binary(Data0),
- hmac(Type, Key, Data, MacSize, erlang:byte_size(Data), max_bytes()).
+%%%---- hmac_init, hamc_update, hmac_final
+-opaque hmac_state() :: binary().
+
+-spec hmac_init(Type, Key) ->
+ State when Type :: hmac_hash_algorithm(),
+ Key :: iodata(),
+ State :: hmac_state() .
hmac_init(Type, Key) ->
notsup_to_error(hmac_init_nif(Type, Key)).
+%%%---- hmac_update
+
+-spec hmac_update(State, Data) -> NewState when Data :: iodata(),
+ State :: hmac_state(),
+ NewState :: hmac_state().
hmac_update(State, Data0) ->
Data = iolist_to_binary(Data0),
hmac_update(State, Data, erlang:byte_size(Data), max_bytes()).
+%%%---- hmac_final
+
+-spec hmac_final(State) -> Mac when State :: hmac_state(),
+ Mac :: binary().
hmac_final(Context) ->
notsup_to_error(hmac_final_nif(Context)).
+
+-spec hmac_final_n(State, HashLen) -> Mac when State :: hmac_state(),
+ HashLen :: integer(),
+ Mac :: binary().
hmac_final_n(Context, HashLen) ->
notsup_to_error(hmac_final_nif(Context, HashLen)).
--spec cmac(_, iodata(), iodata()) -> binary().
--spec cmac(_, iodata(), iodata(), integer()) -> binary().
+%%%---- CMAC
+
+-define(CMAC_CIPHER_ALGORITHM, cbc_cipher() | cfb_cipher() | blowfish_cbc | des_ede3 | rc2_cbc ).
+-spec cmac(Type, Key, Data) ->
+ Mac when Type :: ?CMAC_CIPHER_ALGORITHM,
+ Key :: iodata(),
+ Data :: iodata(),
+ Mac :: binary().
cmac(Type, Key, Data) ->
- notsup_to_error(cmac_nif(Type, Key, Data)).
-cmac(Type, Key, Data, MacSize) ->
- erlang:binary_part(cmac(Type, Key, Data), 0, MacSize).
-
-%% Ecrypt/decrypt %%%
-
--spec block_encrypt(des_cbc | des_cfb |
- des3_cbc | des3_cbf | des3_cfb | des_ede3 |
- blowfish_cbc | blowfish_cfb64 | blowfish_ofb64 |
- aes_cbc128 | aes_cfb8 | aes_cfb128 | aes_cbc256 | aes_ige256 |
- aes_cbc |
- rc2_cbc,
- Key::iodata(), Ivec::binary(), Data::iodata()) -> binary();
- (aes_gcm | chacha20_poly1305, Key::iodata(), Ivec::binary(), {AAD::binary(), Data::iodata()}) -> {binary(), binary()};
- (aes_gcm, Key::iodata(), Ivec::binary(), {AAD::binary(), Data::iodata(), TagLength::1..16}) -> {binary(), binary()}.
-
-block_encrypt(Type, Key, Ivec, Data) when Type =:= des_cbc;
- Type =:= des_cfb;
- Type =:= blowfish_cbc;
- Type =:= blowfish_cfb64;
- Type =:= blowfish_ofb64;
- Type =:= aes_cbc128;
- Type =:= aes_cfb8;
- Type =:= aes_cfb128;
- Type =:= aes_cbc256;
- Type =:= aes_cbc;
- Type =:= rc2_cbc ->
- block_crypt_nif(Type, Key, Ivec, Data, true);
-block_encrypt(Type, Key0, Ivec, Data) when Type =:= des3_cbc;
- Type =:= des_ede3 ->
- Key = check_des3_key(Key0),
- block_crypt_nif(des_ede3_cbc, Key, Ivec, Data, true);
-block_encrypt(des3_cbf, Key0, Ivec, Data) ->
- Key = check_des3_key(Key0),
- block_crypt_nif(des_ede3_cbf, Key, Ivec, Data, true);
-block_encrypt(des3_cfb, Key0, Ivec, Data) ->
- Key = check_des3_key(Key0),
- block_crypt_nif(des_ede3_cfb, Key, Ivec, Data, true);
-block_encrypt(aes_ige256, Key, Ivec, Data) ->
- notsup_to_error(aes_ige_crypt_nif(Key, Ivec, Data, true));
-block_encrypt(aes_gcm, Key, Ivec, {AAD, Data}) ->
- aes_gcm_encrypt(Key, Ivec, AAD, Data);
-block_encrypt(aes_gcm, Key, Ivec, {AAD, Data, TagLength}) ->
- aes_gcm_encrypt(Key, Ivec, AAD, Data, TagLength);
-block_encrypt(chacha20_poly1305, Key, Ivec, {AAD, Data}) ->
- chacha20_poly1305_encrypt(Key, Ivec, AAD, Data).
-
--spec block_decrypt(des_cbc | des_cfb |
- des3_cbc | des3_cbf | des3_cfb | des_ede3 |
- blowfish_cbc | blowfish_cfb64 | blowfish_ofb64 |
- aes_cbc128 | aes_cfb8 | aes_cfb128 | aes_cbc256 | aes_ige256 |
- aes_cbc |
- rc2_cbc,
- Key::iodata(), Ivec::binary(), Data::iodata()) -> binary();
- (aes_gcm | chacha20_poly1305, Key::iodata(), Ivec::binary(),
- {AAD::binary(), Data::iodata(), Tag::binary()}) -> binary() | error.
-block_decrypt(Type, Key, Ivec, Data) when Type =:= des_cbc;
- Type =:= des_cfb;
- Type =:= blowfish_cbc;
- Type =:= blowfish_cfb64;
- Type =:= blowfish_ofb64;
- Type =:= aes_cbc;
- Type =:= aes_cbc128;
- Type =:= aes_cfb8;
- Type =:= aes_cfb128;
- Type =:= aes_cbc256;
- Type =:= rc2_cbc ->
- block_crypt_nif(Type, Key, Ivec, Data, false);
-block_decrypt(Type, Key0, Ivec, Data) when Type =:= des3_cbc;
- Type =:= des_ede3 ->
- Key = check_des3_key(Key0),
- block_crypt_nif(des_ede3_cbc, Key, Ivec, Data, false);
-block_decrypt(des3_cbf, Key0, Ivec, Data) ->
- Key = check_des3_key(Key0),
- block_crypt_nif(des_ede3_cbf, Key, Ivec, Data, false);
-block_decrypt(des3_cfb, Key0, Ivec, Data) ->
- Key = check_des3_key(Key0),
- block_crypt_nif(des_ede3_cfb, Key, Ivec, Data, false);
-block_decrypt(aes_ige256, Key, Ivec, Data) ->
- notsup_to_error(aes_ige_crypt_nif(Key, Ivec, Data, false));
-block_decrypt(aes_gcm, Key, Ivec, {AAD, Data, Tag}) ->
- aes_gcm_decrypt(Key, Ivec, AAD, Data, Tag);
-block_decrypt(chacha20_poly1305, Key, Ivec, {AAD, Data, Tag}) ->
- chacha20_poly1305_decrypt(Key, Ivec, AAD, Data, Tag).
+ notsup_to_error(cmac_nif(alias(Type), Key, Data)).
+
+-spec cmac(Type, Key, Data, MacLength) ->
+ Mac when Type :: ?CMAC_CIPHER_ALGORITHM,
+ Key :: iodata(),
+ Data :: iodata(),
+ MacLength :: integer(),
+ Mac :: binary().
--spec block_encrypt(des_ecb | blowfish_ecb | aes_ecb, Key::iodata(), Data::iodata()) -> binary().
+cmac(Type, Key, Data, MacLength) ->
+ erlang:binary_part(cmac(alias(Type), Key, Data), 0, MacLength).
-block_encrypt(Type, Key, Data) ->
- block_crypt_nif(Type, Key, Data, true).
+%%%---- POLY1305
--spec block_decrypt(des_ecb | blowfish_ecb | aes_ecb, Key::iodata(), Data::iodata()) -> binary().
+-spec poly1305(iodata(), iodata()) -> Mac when Mac :: binary().
-block_decrypt(Type, Key, Data) ->
- block_crypt_nif(Type, Key, Data, false).
+poly1305(Key, Data) ->
+ poly1305_nif(Key, Data).
--spec next_iv(des_cbc | des3_cbc | aes_cbc | aes_ige, Data::iodata()) -> binary().
+%%%================================================================
+%%%
+%%% Encrypt/decrypt, The "Old API"
+%%%
+%%%================================================================
+
+-define(COMPAT(CALL),
+ try begin CALL end
+ catch
+ error:{error, {_File,_Line}, _Reason} ->
+ error(badarg);
+ error:{E, {_File,_Line}, _Reason} when E==notsup ; E==badarg ->
+ error(E)
+ end).
+
+%%%---- Cipher info
+%%%----------------------------------------------------------------
+-spec cipher_info(Type) -> Result | run_time_error()
+ when Type :: cipher(),
+ Result :: #{key_length := integer(),
+ iv_length := integer(),
+ block_size := integer(),
+ mode := CipherModes,
+ type := undefined | integer()
+ },
+ CipherModes :: undefined
+ | cbc_mode
+ | ccm_mode
+ | cfb_mode
+ | ctr_mode
+ | ecb_mode
+ | gcm_mode
+ | ige_mode
+ | ocb_mode
+ | ofb_mode
+ | wrap_mode
+ | xts_mode
+ .
+
+%% %% These ciphers are not available via the EVP interface on older cryptolibs.
+cipher_info(aes_ctr) ->
+ #{block_size => 1,iv_length => 16,key_length => 32,mode => ctr_mode,type => undefined};
+cipher_info(aes_128_ctr) ->
+ #{block_size => 1,iv_length => 16,key_length => 16,mode => ctr_mode,type => undefined};
+cipher_info(aes_192_ctr) ->
+ #{block_size => 1,iv_length => 16,key_length => 24,mode => ctr_mode,type => undefined};
+cipher_info(aes_256_ctr) ->
+ #{block_size => 1,iv_length => 16,key_length => 32,mode => ctr_mode,type => undefined};
+%% %% This cipher is handled specialy.
+cipher_info(aes_ige256) ->
+ #{block_size => 16,iv_length => 32,key_length => 16,mode => ige_mode,type => undefined};
+%% %% These ciphers belong to the "old" interface:
+%% cipher_info(aes_cbc) ->
+%% #{block_size => 16,iv_length => 16,key_length => 24,mode => cbc_mode,type => 423};
+%% cipher_info(aes_cbc128) ->
+%% #{block_size => 16,iv_length => 16,key_length => 16,mode => cbc_mode,type => 419};
+%% cipher_info(aes_cbc256) ->
+%% #{block_size => 16,iv_length => 16,key_length => 32,mode => cbc_mode,type => 427};
+%% cipher_info(aes_ccm) ->
+%% #{block_size => 1,iv_length => 12,key_length => 24,mode => ccm_mode,type => 899};
+%% cipher_info(aes_cfb128) ->
+%% #{block_size => 1,iv_length => 16,key_length => 32,mode => cfb_mode,type => 429};
+%% cipher_info(aes_cfb8) ->
+%% #{block_size => 1,iv_length => 16,key_length => 32,mode => cfb_mode,type => 429};
+%% cipher_info(aes_ecb) ->
+%% #{block_size => 16,iv_length => 0,key_length => 24,mode => ecb_mode,type => 422};
+%% cipher_info(aes_gcm) ->
+%% #{block_size => 1,iv_length => 12,key_length => 24,mode => gcm_mode,type => 898};
+%% cipher_info(des3_cbc) ->
+%% #{block_size => 8,iv_length => 8,key_length => 24,mode => cbc_mode,type => 44};
+%% cipher_info(des3_cbf) ->
+%% #{block_size => 1,iv_length => 8,key_length => 24,mode => cfb_mode,type => 30};
+%% cipher_info(des3_cfb) ->
+%% #{block_size => 1,iv_length => 8,key_length => 24,mode => cfb_mode,type => 30};
+%% cipher_info(des_ede3) ->
+%% #{block_size => 8,iv_length => 8,key_length => 24,mode => cbc_mode,type => 44};
+%% cipher_info(des_ede3_cbf) ->
+%% #{block_size => 1,iv_length => 8,key_length => 24,mode => cfb_mode,type => 30};
+cipher_info(Type) ->
+ cipher_info_nif(alias(Type)).
+
+%%%---- Block ciphers
+%%%----------------------------------------------------------------
+-spec block_encrypt(Type::block_cipher_with_iv(), Key::key()|des3_key(), Ivec::binary(), PlainText::iodata()) ->
+ binary() | run_time_error();
+ (Type::aead_cipher(), Key::iodata(), Ivec::binary(), {AAD::binary(), PlainText::iodata()}) ->
+ {binary(), binary()} | run_time_error();
+ (aes_gcm | aes_ccm, Key::iodata(), Ivec::binary(), {AAD::binary(), PlainText::iodata(), TagLength::1..16}) ->
+ {binary(), binary()} | run_time_error().
+
+
+block_encrypt(aes_ige256, Key, Ivec, PlainText) ->
+ notsup_to_error(aes_ige_crypt_nif(Key, Ivec, PlainText, true));
+block_encrypt(Type, Key0, Ivec, Data) ->
+ Key = iolist_to_binary(Key0),
+ ?COMPAT(
+ case Data of
+ {AAD, PlainText} ->
+ crypto_one_time_aead(alias(Type,Key), Key, Ivec, PlainText, AAD, true);
+ {AAD, PlainText, TagLength} ->
+ crypto_one_time_aead(alias(Type,Key), Key, Ivec, PlainText, AAD, TagLength, true);
+ PlainText ->
+ crypto_one_time(alias(Type,Key), Key, Ivec, PlainText, true)
+ end).
+
+-spec block_encrypt(Type::block_cipher_without_iv(), Key::key(), PlainText::iodata()) ->
+ binary() | run_time_error().
+
+block_encrypt(Type, Key0, PlainText) ->
+ Key = iolist_to_binary(Key0),
+ ?COMPAT(crypto_one_time(alias(Type,Key), Key, PlainText, true)).
+
+
+%%%----------------------------------------------------------------
+%%%----------------------------------------------------------------
+-spec block_decrypt(Type::block_cipher_with_iv(), Key::key()|des3_key(), Ivec::binary(), Data::iodata()) ->
+ binary() | run_time_error();
+ (Type::aead_cipher(), Key::iodata(), Ivec::binary(),
+ {AAD::binary(), Data::iodata(), Tag::binary()}) ->
+ binary() | error | run_time_error() .
+
+block_decrypt(aes_ige256, Key, Ivec, Data) ->
+ notsup_to_error(aes_ige_crypt_nif(Key, Ivec, Data, false));
+
+block_decrypt(Type, Key0, Ivec, Data) ->
+ Key = iolist_to_binary(Key0),
+ ?COMPAT(
+ case Data of
+ {AAD, CryptoText, Tag} ->
+ crypto_one_time_aead(alias(Type,Key), Key, Ivec, CryptoText, AAD, Tag, false);
+ CryptoText ->
+ crypto_one_time(alias(Type,Key), Key, Ivec, CryptoText, false)
+ end).
+
+
+-spec block_decrypt(Type::block_cipher_without_iv(), Key::key(), Data::iodata()) ->
+ binary() | run_time_error().
+
+block_decrypt(Type, Key0, CryptoText) ->
+ Key = iolist_to_binary(Key0),
+ ?COMPAT(crypto_one_time(alias(Type,Key), Key, CryptoText, false)).
+
+%%%-------- Stream ciphers API
+
+-opaque stream_state() :: {stream_cipher(),
+ crypto_state() | {crypto_state(),flg_undefined}
+ }.
+
+%%%---- stream_init
+-spec stream_init(Type, Key, IVec) -> State | run_time_error()
+ when Type :: stream_cipher(),
+ Key :: iodata(),
+ IVec ::binary(),
+ State :: stream_state() .
+stream_init(Type, Key0, IVec) when is_binary(IVec) ->
+ Key = iolist_to_binary(Key0),
+ Ref = ?COMPAT(ng_crypto_init_nif(alias(Type,Key),
+ Key, iolist_to_binary(IVec),
+ undefined)
+ ),
+ {Type, {Ref,flg_undefined}}.
+
+
+-spec stream_init(Type, Key) -> State | run_time_error()
+ when Type :: rc4,
+ Key :: iodata(),
+ State :: stream_state() .
+stream_init(rc4 = Type, Key0) ->
+ Key = iolist_to_binary(Key0),
+ Ref = ?COMPAT(ng_crypto_init_nif(alias(Type,Key),
+ Key, <<>>,
+ undefined)
+ ),
+ {Type, {Ref,flg_undefined}}.
+
+%%%---- stream_encrypt
+-spec stream_encrypt(State, PlainText) -> {NewState, CipherText} | run_time_error()
+ when State :: stream_state(),
+ PlainText :: iodata(),
+ NewState :: stream_state(),
+ CipherText :: iodata() .
+stream_encrypt(State, Data) ->
+ crypto_stream_emulate(State, Data, true).
+
+%%%---- stream_decrypt
+-spec stream_decrypt(State, CipherText) -> {NewState, PlainText} | run_time_error()
+ when State :: stream_state(),
+ CipherText :: iodata(),
+ NewState :: stream_state(),
+ PlainText :: iodata() .
+stream_decrypt(State, Data) ->
+ crypto_stream_emulate(State, Data, false).
+
+%%%-------- helpers
+crypto_stream_emulate({Cipher,{Ref0,flg_undefined}}, Data, EncryptFlag) when is_reference(Ref0) ->
+ ?COMPAT(begin
+ Ref = ng_crypto_init_nif(Ref0, <<>>, <<>>, EncryptFlag),
+ {{Cipher,Ref}, crypto_update(Ref, Data)}
+ end);
+
+crypto_stream_emulate({Cipher,Ref}, Data, _) when is_reference(Ref) ->
+ ?COMPAT({{Cipher,Ref}, crypto_update(Ref, Data)}).
+
+%%%----------------------------------------------------------------
+-spec next_iv(Type:: cbc_cipher(), Data) -> NextIVec when % Type :: cbc_cipher(), %des_cbc | des3_cbc | aes_cbc | aes_ige,
+ Data :: iodata(),
+ NextIVec :: binary().
next_iv(Type, Data) when is_binary(Data) ->
IVecSize = case Type of
des_cbc -> 8;
@@ -290,7 +910,9 @@ next_iv(Type, Data) when is_binary(Data) ->
next_iv(Type, Data) when is_list(Data) ->
next_iv(Type, list_to_binary(Data)).
--spec next_iv(des_cfb, Data::iodata(), Ivec::binary()) -> binary().
+-spec next_iv(des_cfb, Data, IVec) -> NextIVec when Data :: iodata(),
+ IVec :: binary(),
+ NextIVec :: binary().
next_iv(des_cfb, Data, IVec) ->
IVecAndData = list_to_binary([IVec, Data]),
@@ -299,30 +921,284 @@ next_iv(des_cfb, Data, IVec) ->
next_iv(Type, Data, _Ivec) ->
next_iv(Type, Data).
-stream_init(aes_ctr, Key, Ivec) ->
- {aes_ctr, aes_ctr_stream_init(Key, Ivec)}.
-stream_init(rc4, Key) ->
- {rc4, notsup_to_error(rc4_set_key(Key))}.
+%%%================================================================
+%%%
+%%% Encrypt/decrypt, The "New API"
+%%%
+%%%================================================================
-stream_encrypt(State, Data0) ->
- Data = iolist_to_binary(Data0),
- MaxByts = max_bytes(),
- stream_crypt(fun do_stream_encrypt/2, State, Data, erlang:byte_size(Data), MaxByts, []).
+-opaque crypto_state() :: reference() .
-stream_decrypt(State, Data0) ->
- Data = iolist_to_binary(Data0),
- MaxByts = max_bytes(),
- stream_crypt(fun do_stream_decrypt/2, State, Data, erlang:byte_size(Data), MaxByts, []).
-%%
-%% RAND - pseudo random numbers using RN_ and BN_ functions in crypto lib
-%%
--spec strong_rand_bytes(non_neg_integer()) -> binary().
--spec rand_seed() -> rand:state().
--spec rand_seed_s() -> rand:state().
--spec rand_uniform(crypto_integer(), crypto_integer()) ->
- crypto_integer().
+%%%----------------------------------------------------------------
+%%%
+%%% Create and initialize a new state for encryption or decryption
+%%%
+
+-spec crypto_init(Cipher, Key, EncryptFlag) -> State | descriptive_error()
+ when Cipher :: cipher_no_iv(),
+ Key :: iodata(),
+ EncryptFlag :: boolean(),
+ State :: crypto_state() .
+crypto_init(Cipher, Key, EncryptFlag) ->
+ %% The IV is supposed to be supplied by calling crypto_update/3
+ ng_crypto_init_nif(Cipher, iolist_to_binary(Key), <<>>, EncryptFlag).
+
+
+-spec crypto_init(Cipher, Key, IV, EncryptFlag) -> State | descriptive_error()
+ when Cipher :: cipher_iv(),
+ Key :: iodata(),
+ IV :: iodata(),
+ EncryptFlag :: boolean(),
+ State :: crypto_state() .
+crypto_init(Cipher, Key, IV, EncryptFlag) ->
+ ng_crypto_init_nif(Cipher, iolist_to_binary(Key), iolist_to_binary(IV), EncryptFlag).
+
+
+
+%%%----------------------------------------------------------------
+-spec crypto_dyn_iv_init(Cipher, Key, EncryptFlag) -> State | descriptive_error()
+ when Cipher :: cipher_iv(),
+ Key :: iodata(),
+ EncryptFlag :: boolean(),
+ State :: crypto_state() .
+crypto_dyn_iv_init(Cipher, Key, EncryptFlag) ->
+ %% The IV is supposed to be supplied by calling crypto_update/3
+ ng_crypto_init_nif(Cipher, iolist_to_binary(Key), undefined, EncryptFlag).
+
+%%%----------------------------------------------------------------
+%%%
+%%% Encrypt/decrypt a sequence of bytes. The sum of the sizes
+%%% of all blocks must be an integer multiple of the crypto's
+%%% blocksize.
+%%%
+
+-spec crypto_update(State, Data) -> Result | descriptive_error()
+ when State :: crypto_state(),
+ Data :: iodata(),
+ Result :: binary() .
+crypto_update(State, Data0) ->
+ case iolist_to_binary(Data0) of
+ <<>> ->
+ <<>>; % Known to fail on OpenSSL 0.9.8h
+ Data ->
+ ng_crypto_update_nif(State, Data)
+ end.
+
+
+%%%----------------------------------------------------------------
+-spec crypto_dyn_iv_update(State, Data, IV) -> Result | descriptive_error()
+ when State :: crypto_state(),
+ Data :: iodata(),
+ IV :: iodata(),
+ Result :: binary() .
+crypto_dyn_iv_update(State, Data0, IV) ->
+ %% When State is from State = crypto_init(Cipher, Key, undefined, EncryptFlag)
+ case iolist_to_binary(Data0) of
+ <<>> ->
+ <<>>; % Known to fail on OpenSSL 0.9.8h
+ Data ->
+ ng_crypto_update_nif(State, Data, iolist_to_binary(IV))
+ end.
+
+%%%----------------------------------------------------------------
+%%%
+%%% Encrypt/decrypt one set bytes.
+%%% The size must be an integer multiple of the crypto's blocksize.
+%%%
+
+-spec crypto_one_time(Cipher, Key, Data, EncryptFlag) ->
+ Result | descriptive_error()
+ when Cipher :: cipher_no_iv(),
+ Key :: iodata(),
+ Data :: iodata(),
+ EncryptFlag :: boolean(),
+ Result :: binary() .
+
+crypto_one_time(Cipher, Key, Data, EncryptFlag) ->
+ crypto_one_time(Cipher, Key, <<>>, Data, EncryptFlag).
+
+-spec crypto_one_time(Cipher, Key, IV, Data, EncryptFlag) ->
+ Result | descriptive_error()
+ when Cipher :: cipher_iv(),
+ Key :: iodata(),
+ IV :: iodata(),
+ Data :: iodata(),
+ EncryptFlag :: boolean(),
+ Result :: binary() .
+
+crypto_one_time(Cipher, Key, IV, Data0, EncryptFlag) ->
+ case iolist_to_binary(Data0) of
+ <<>> ->
+ <<>>; % Known to fail on OpenSSL 0.9.8h
+ Data ->
+ ng_crypto_one_time_nif(Cipher,
+ iolist_to_binary(Key), iolist_to_binary(IV), Data,
+ EncryptFlag)
+ end.
+
+
+-spec crypto_one_time_aead(Cipher, Key, IV, InText, AAD, EncFlag::true) ->
+ Result | descriptive_error()
+ when Cipher :: cipher_aead(),
+ Key :: iodata(),
+ IV :: iodata(),
+ InText :: iodata(),
+ AAD :: iodata(),
+ Result :: EncryptResult,
+ EncryptResult :: {OutCryptoText, OutTag},
+ OutCryptoText :: binary(),
+ OutTag :: binary().
+
+crypto_one_time_aead(Cipher, Key, IV, PlainText, AAD, true) ->
+ crypto_one_time_aead(Cipher, Key, IV, PlainText, AAD, aead_tag_len(Cipher), true).
+
+
+-spec crypto_one_time_aead(Cipher, Key, IV, InText, AAD, TagOrTagLength, EncFlag) ->
+ Result | descriptive_error()
+ when Cipher :: cipher_aead(),
+ Key :: iodata(),
+ IV :: iodata(),
+ InText :: iodata(),
+ AAD :: iodata(),
+ TagOrTagLength :: EncryptTagLength | DecryptTag,
+ EncryptTagLength :: non_neg_integer(), % or pos_integer() 1..
+ DecryptTag :: iodata(),
+ EncFlag :: boolean(),
+ Result :: EncryptResult | DecryptResult,
+ EncryptResult :: {OutCryptoText, OutTag},
+ DecryptResult :: OutPlainText | error,
+ OutCryptoText :: binary(),
+ OutTag :: binary(),
+ OutPlainText :: binary().
+
+crypto_one_time_aead(Cipher, Key, IV, TextIn, AAD, TagOrTagLength, EncFlg) ->
+ aead_cipher(Cipher, Key, IV, TextIn, AAD, TagOrTagLength, EncFlg).
+
+
+aead_tag_len(chacha20_poly1305) -> 16;
+aead_tag_len(aes_ccm ) -> 12;
+aead_tag_len(aes_128_ccm) -> 12;
+aead_tag_len(aes_192_ccm) -> 12;
+aead_tag_len(aes_256_ccm) -> 12;
+aead_tag_len(aes_gcm ) -> 16;
+aead_tag_len(aes_128_gcm) -> 16;
+aead_tag_len(aes_192_gcm) -> 16;
+aead_tag_len(aes_256_gcm) -> 16;
+aead_tag_len(_) -> error({badarg, "Not an AEAD cipher"}).
+
+%%%----------------------------------------------------------------
+%%% NIFs
+
+-spec ng_crypto_init_nif(atom(), binary(), binary()|undefined, boolean()|undefined ) ->
+ crypto_state() | descriptive_error()
+ ; (crypto_state(), <<>>, <<>>, boolean())
+ -> crypto_state() | descriptive_error().
+
+ng_crypto_init_nif(_Cipher, _Key, _IVec, _EncryptFlg) -> ?nif_stub.
+
+
+-spec ng_crypto_update_nif(crypto_state(), binary()) ->
+ binary() | descriptive_error() .
+ng_crypto_update_nif(_State, _Data) -> ?nif_stub.
+
+-spec ng_crypto_update_nif(crypto_state(), binary(), binary()) ->
+ binary() | descriptive_error() .
+ng_crypto_update_nif(_State, _Data, _IV) -> ?nif_stub.
+
+-spec ng_crypto_one_time_nif(atom(), binary(), binary(), binary(), boolean() ) ->
+ binary() | descriptive_error().
+ng_crypto_one_time_nif(_Cipher, _Key, _IVec, _Data, _EncryptFlg) -> ?nif_stub.
+
+%%%----------------------------------------------------------------
+%%% Cipher aliases
+%%%
+-define(if_also(Cipher, Ciphers, AliasCiphers),
+ case lists:member(Cipher, Ciphers) of
+ true ->
+ AliasCiphers;
+ false ->
+ Ciphers
+ end).
+
+
+prepend_old_aliases(L0) ->
+ L1 = ?if_also(des_ede3_cbc, L0,
+ [des3_cbc, des_ede3, des_ede3_cbf, des3_cbf, des3_cfb | L0]),
+ L2 = ?if_also(aes_128_cbc, L1,
+ [aes_cbc, aes_cbc128, aes_cbc256 | L1]),
+ L3 = ?if_also(aes_128_ctr, L2,
+ [aes_ctr | L2]),
+ L4 = ?if_also(aes_128_ccm, L3,
+ [aes_ccm | L3]),
+ L5 = ?if_also(aes_128_gcm, L4,
+ [aes_gcm | L4]),
+ L6 = ?if_also(aes_128_cfb8, L5,
+ [aes_cfb8 | L5]),
+ L7 = ?if_also(aes_128_cfb128, L6,
+ [aes_cfb128 | L6]),
+ L8 = ?if_also(aes_128_ecb, L7,
+ [aes_ecb | L7]),
+ L8.
+
+
+
+%%%---- des_ede3_cbc
+alias(des3_cbc) -> des_ede3_cbc;
+alias(des_ede3) -> des_ede3_cbc;
+%%%---- des_ede3_cfb
+alias(des_ede3_cbf) -> des_ede3_cfb;
+alias(des3_cbf) -> des_ede3_cfb;
+alias(des3_cfb) -> des_ede3_cfb;
+%%%---- aes_*_cbc
+alias(aes_cbc128) -> aes_128_cbc;
+alias(aes_cbc256) -> aes_256_cbc;
+
+alias(Alg) -> Alg.
+
+
+alias(Ciph, Key) -> alias2(alias(Ciph), Key).
+
+alias2(aes_cbc, Key) when size(Key)==16 -> aes_128_cbc;
+alias2(aes_cbc, Key) when size(Key)==24 -> aes_192_cbc;
+alias2(aes_cbc, Key) when size(Key)==32 -> aes_256_cbc;
+
+alias2(aes_cfb8, Key) when size(Key)==16 -> aes_128_cfb8;
+alias2(aes_cfb8, Key) when size(Key)==24 -> aes_192_cfb8;
+alias2(aes_cfb8, Key) when size(Key)==32 -> aes_256_cfb8;
+
+alias2(aes_cfb128, Key) when size(Key)==16 -> aes_128_cfb128;
+alias2(aes_cfb128, Key) when size(Key)==24 -> aes_192_cfb128;
+alias2(aes_cfb128, Key) when size(Key)==32 -> aes_256_cfb128;
+
+alias2(aes_ctr, Key) when size(Key)==16 -> aes_128_ctr;
+alias2(aes_ctr, Key) when size(Key)==24 -> aes_192_ctr;
+alias2(aes_ctr, Key) when size(Key)==32 -> aes_256_ctr;
+
+alias2(aes_ecb, Key) when size(Key)==16 -> aes_128_ecb;
+alias2(aes_ecb, Key) when size(Key)==24 -> aes_192_ecb;
+alias2(aes_ecb, Key) when size(Key)==32 -> aes_256_ecb;
+
+alias2(aes_gcm, Key) when size(Key)==16 -> aes_128_gcm;
+alias2(aes_gcm, Key) when size(Key)==24 -> aes_192_gcm;
+alias2(aes_gcm, Key) when size(Key)==32 -> aes_256_gcm;
+
+alias2(aes_ccm, Key) when size(Key)==16 -> aes_128_ccm;
+alias2(aes_ccm, Key) when size(Key)==24 -> aes_192_ccm;
+alias2(aes_ccm, Key) when size(Key)==32 -> aes_256_ccm;
+
+alias2(Alg, _) -> Alg.
+
+%%%================================================================
+%%%
+%%% RAND - pseudo random numbers using RN_ and BN_ functions in crypto lib
+%%%
+%%%================================================================
+-type rand_cache_seed() ::
+ nonempty_improper_list(non_neg_integer(), binary()).
+
+-spec strong_rand_bytes(N::non_neg_integer()) -> binary().
strong_rand_bytes(Bytes) ->
case strong_rand_bytes_nif(Bytes) of
false -> erlang:error(low_entropy);
@@ -331,16 +1207,87 @@ strong_rand_bytes(Bytes) ->
strong_rand_bytes_nif(_Bytes) -> ?nif_stub.
+-spec rand_seed() -> rand:state().
rand_seed() ->
rand:seed(rand_seed_s()).
+-spec rand_seed_s() -> rand:state().
rand_seed_s() ->
- {#{ type => ?MODULE,
- bits => 64,
- next => fun ?MODULE:rand_plugin_next/1,
- uniform => fun ?MODULE:rand_plugin_uniform/1,
- uniform_n => fun ?MODULE:rand_plugin_uniform/2},
- no_seed}.
+ rand_seed_alg_s(?MODULE).
+
+-spec rand_seed_alg(Alg :: atom()) ->
+ {rand:alg_handler(),
+ atom() | rand_cache_seed()}.
+rand_seed_alg(Alg) ->
+ rand:seed(rand_seed_alg_s(Alg)).
+
+-spec rand_seed_alg(Alg :: atom(), Seed :: term()) ->
+ {rand:alg_handler(),
+ atom() | rand_cache_seed()}.
+rand_seed_alg(Alg, Seed) ->
+ rand:seed(rand_seed_alg_s(Alg, Seed)).
+
+-define(CRYPTO_CACHE_BITS, 56).
+-define(CRYPTO_AES_BITS, 58).
+
+-spec rand_seed_alg_s(Alg :: atom()) ->
+ {rand:alg_handler(),
+ atom() | rand_cache_seed()}.
+rand_seed_alg_s({AlgHandler, _AlgState} = State) when is_map(AlgHandler) ->
+ State;
+rand_seed_alg_s({Alg, AlgState}) when is_atom(Alg) ->
+ {mk_alg_handler(Alg),AlgState};
+ rand_seed_alg_s(Alg) when is_atom(Alg) ->
+ {mk_alg_handler(Alg),mk_alg_state(Alg)}.
+%%
+-spec rand_seed_alg_s(Alg :: atom(), Seed :: term()) ->
+ {rand:alg_handler(),
+ atom() | rand_cache_seed()}.
+rand_seed_alg_s(Alg, Seed) when is_atom(Alg) ->
+ {mk_alg_handler(Alg),mk_alg_state({Alg,Seed})}.
+
+mk_alg_handler(?MODULE = Alg) ->
+ #{ type => Alg,
+ bits => 64,
+ next => fun ?MODULE:rand_plugin_next/1,
+ uniform => fun ?MODULE:rand_plugin_uniform/1,
+ uniform_n => fun ?MODULE:rand_plugin_uniform/2};
+mk_alg_handler(crypto_cache = Alg) ->
+ #{ type => Alg,
+ bits => ?CRYPTO_CACHE_BITS,
+ next => fun ?MODULE:rand_cache_plugin_next/1};
+mk_alg_handler(crypto_aes = Alg) ->
+ #{ type => Alg,
+ bits => ?CRYPTO_AES_BITS,
+ next => fun ?MODULE:rand_plugin_aes_next/1,
+ jump => fun ?MODULE:rand_plugin_aes_jump/1}.
+
+mk_alg_state(?MODULE) ->
+ no_seed;
+mk_alg_state(crypto_cache) ->
+ CacheBits = ?CRYPTO_CACHE_BITS,
+ BytesPerWord = (CacheBits + 7) div 8,
+ GenBytes =
+ ((rand_cache_size() + (2*BytesPerWord - 1)) div BytesPerWord)
+ * BytesPerWord,
+ {CacheBits, GenBytes, <<>>};
+mk_alg_state({crypto_aes,Seed}) ->
+ %% 16 byte words (128 bit crypto blocks)
+ GenWords = (rand_cache_size() + 31) div 16,
+ Key = crypto:hash(sha256, Seed),
+ {F,Count} = longcount_seed(Seed),
+ {Key,GenWords,F,Count}.
+
+rand_cache_size() ->
+ DefaultCacheSize = 1024,
+ CacheSize =
+ application:get_env(crypto, rand_cache_size, DefaultCacheSize),
+ if
+ is_integer(CacheSize), 0 =< CacheSize ->
+ CacheSize;
+ true ->
+ DefaultCacheSize
+ end.
rand_plugin_next(Seed) ->
{bytes_to_integer(strong_rand_range(1 bsl 64)), Seed}.
@@ -352,6 +1299,97 @@ rand_plugin_uniform(Max, State) ->
{bytes_to_integer(strong_rand_range(Max)) + 1, State}.
+rand_cache_plugin_next({CacheBits, GenBytes, <<>>}) ->
+ rand_cache_plugin_next(
+ {CacheBits, GenBytes, strong_rand_bytes(GenBytes)});
+rand_cache_plugin_next({CacheBits, GenBytes, Cache}) ->
+ <<I:CacheBits, NewCache/binary>> = Cache,
+ {I, {CacheBits, GenBytes, NewCache}}.
+
+
+%% Encrypt 128 bit counter values and use the 58 lowest
+%% encrypted bits as random numbers.
+%%
+%% The 128 bit counter is handled as 4 32 bit words
+%% to avoid bignums. Generate a bunch of numbers
+%% at the time and cache them.
+%%
+-dialyzer({no_improper_lists, rand_plugin_aes_next/1}).
+rand_plugin_aes_next([V|Cache]) ->
+ {V,Cache};
+rand_plugin_aes_next({Key,GenWords,F,Count}) ->
+ rand_plugin_aes_next(Key, GenWords, F, Count);
+rand_plugin_aes_next({Key,GenWords,F,_JumpBase,Count}) ->
+ rand_plugin_aes_next(Key, GenWords, F, Count).
+%%
+rand_plugin_aes_next(Key, GenWords, F, Count) ->
+ {Cleartext,NewCount} = aes_cleartext(<<>>, F, Count, GenWords),
+ Encrypted = crypto:block_encrypt(aes_ecb, Key, Cleartext),
+ [V|Cache] = aes_cache(Encrypted, {Key,GenWords,F,Count,NewCount}),
+ {V,Cache}.
+
+%% A jump advances the counter 2^512 steps; the jump function
+%% is applied to the jump base and then the number of used
+%% numbers from the cache has to be wasted for the jump to be correct
+%%
+rand_plugin_aes_jump({#{type := crypto_aes} = Alg, Cache}) ->
+ {Alg,rand_plugin_aes_jump(fun longcount_jump/1, 0, Cache)}.
+%% Count cached words and subtract their number from jump
+-dialyzer({no_improper_lists, rand_plugin_aes_jump/3}).
+rand_plugin_aes_jump(Jump, J, [_|Cache]) ->
+ rand_plugin_aes_jump(Jump, J + 1, Cache);
+rand_plugin_aes_jump(Jump, J, {Key,GenWords,F,JumpBase, _Count}) ->
+ rand_plugin_aes_jump(Jump, GenWords - J, Key, GenWords, F, JumpBase);
+rand_plugin_aes_jump(Jump, 0, {Key,GenWords,F,JumpBase}) ->
+ rand_plugin_aes_jump(Jump, 0, Key, GenWords, F, JumpBase).
+%%
+rand_plugin_aes_jump(Jump, Skip, Key, GenWords, F, JumpBase) ->
+ Count = longcount_next_count(Skip, Jump(JumpBase)),
+ {Key,GenWords,F,Count}.
+
+rand_plugin_aes_jump_2pow20(Cache) ->
+ rand_plugin_aes_jump(fun longcount_jump_2pow20/1, 0, Cache).
+
+
+longcount_seed(Seed) ->
+ <<X:64, _:6, F:12, S2:58, S1:58, S0:58>> =
+ crypto:hash(sha256, [Seed,<<"Xoroshiro928">>]),
+ {F,rand:exro928_seed([S0,S1,S2|rand:seed58(13, X)])}.
+
+longcount_next_count(0, Count) ->
+ Count;
+longcount_next_count(N, Count) ->
+ longcount_next_count(N - 1, rand:exro928_next_state(Count)).
+
+longcount_next(Count) ->
+ rand:exro928_next(Count).
+
+longcount_jump(Count) ->
+ rand:exro928_jump_2pow512(Count).
+
+longcount_jump_2pow20(Count) ->
+ rand:exro928_jump_2pow20(Count).
+
+
+%% Build binary with counter values to cache
+aes_cleartext(Cleartext, _F, Count, 0) ->
+ {Cleartext,Count};
+aes_cleartext(Cleartext, F, Count, GenWords) ->
+ {{S0,S1}, NewCount} = longcount_next(Count),
+ aes_cleartext(
+ <<Cleartext/binary, F:12, S1:58, S0:58>>,
+ F, NewCount, GenWords - 1).
+
+%% Parse and cache encrypted counter values aka random numbers
+-dialyzer({no_improper_lists, aes_cache/2}).
+aes_cache(<<>>, Cache) ->
+ Cache;
+aes_cache(
+ <<_:(128 - ?CRYPTO_AES_BITS), V:?CRYPTO_AES_BITS, Encrypted/binary>>,
+ Cache) ->
+ [V|aes_cache(Encrypted, Cache)].
+
+
strong_rand_range(Range) when is_integer(Range), Range > 0 ->
BinRange = int_to_bin(Range),
strong_rand_range(BinRange);
@@ -368,7 +1406,9 @@ strong_rand_float() ->
WholeRange = strong_rand_range(1 bsl 53),
?HALF_DBL_EPSILON * bytes_to_integer(WholeRange).
-rand_uniform(From,To) when is_binary(From), is_binary(To) ->
+-spec rand_uniform(crypto_integer(), crypto_integer()) ->
+ crypto_integer().
+rand_uniform(From, To) when is_binary(From), is_binary(To) ->
case rand_uniform_nif(From,To) of
<<Len:32/integer, MSB, Rest/binary>> when MSB > 127 ->
<<(Len + 1):32/integer, 0, MSB, Rest/binary>>;
@@ -398,121 +1438,239 @@ rand_uniform_nif(_From,_To) -> ?nif_stub.
-spec rand_seed(binary()) -> ok.
-rand_seed(Seed) ->
+rand_seed(Seed) when is_binary(Seed) ->
rand_seed_nif(Seed).
rand_seed_nif(_Seed) -> ?nif_stub.
--spec mod_pow(binary()|integer(), binary()|integer(), binary()|integer()) -> binary() | error.
-mod_pow(Base, Exponent, Prime) ->
- case mod_exp_nif(ensure_int_as_bin(Base), ensure_int_as_bin(Exponent), ensure_int_as_bin(Prime), 0) of
- <<0>> -> error;
- R -> R
- end.
+%%%================================================================
+%%%
+%%% Sign/verify
+%%%
+%%%================================================================
+-type pk_sign_verify_algs() :: rsa | dss | ecdsa | eddsa .
-verify(Algorithm, Type, Data, Signature, Key) ->
- verify(Algorithm, Type, Data, Signature, Key, []).
+-type pk_sign_verify_opts() :: [ rsa_sign_verify_opt() ] .
-%% Backwards compatible
-verify(Algorithm = dss, none, Digest, Signature, Key, Options) ->
- verify(Algorithm, sha, {digest, Digest}, Signature, Key, Options);
-verify(Algorithm, Type, Data, Signature, Key, Options) ->
- case pkey_verify_nif(Algorithm, Type, Data, Signature, format_pkey(Algorithm, Key), Options) of
- notsup -> erlang:error(notsup);
- Boolean -> Boolean
- end.
+-type rsa_sign_verify_opt() :: {rsa_padding, rsa_sign_verify_padding()}
+ | {rsa_pss_saltlen, integer()}
+ | {rsa_mgf1_md, sha2()}.
+
+-type rsa_sign_verify_padding() :: rsa_pkcs1_padding | rsa_pkcs1_pss_padding
+ | rsa_x931_padding | rsa_no_padding
+ .
+%%%----------------------------------------------------------------
+%%% Sign
+
+-spec sign(Algorithm, DigestType, Msg, Key)
+ -> Signature
+ when Algorithm :: pk_sign_verify_algs(),
+ DigestType :: rsa_digest_type()
+ | dss_digest_type()
+ | ecdsa_digest_type(),
+ Msg :: iodata() | {digest,iodata()},
+ Key :: rsa_private()
+ | dss_private()
+ | [ecdsa_private() | ecdsa_params()]
+ | [eddsa_private() | eddsa_params()]
+ | engine_key_ref(),
+ Signature :: binary() .
+
sign(Algorithm, Type, Data, Key) ->
sign(Algorithm, Type, Data, Key, []).
-%% Backwards compatible
-sign(Algorithm = dss, none, Digest, Key, Options) ->
- sign(Algorithm, sha, {digest, Digest}, Key, Options);
-sign(Algorithm, Type, Data, Key, Options) ->
+
+-spec sign(Algorithm, DigestType, Msg, Key, Options)
+ -> Signature
+ when Algorithm :: pk_sign_verify_algs(),
+ DigestType :: rsa_digest_type()
+ | dss_digest_type()
+ | ecdsa_digest_type()
+ | none,
+ Msg :: iodata() | {digest,iodata()},
+ Key :: rsa_private()
+ | dss_private()
+ | [ecdsa_private() | ecdsa_params()]
+ | [eddsa_private() | eddsa_params()]
+ | engine_key_ref(),
+ Options :: pk_sign_verify_opts(),
+ Signature :: binary() .
+
+sign(Algorithm0, Type0, Data, Key, Options) ->
+ {Algorithm, Type} = sign_verify_compatibility(Algorithm0, Type0, Data),
case pkey_sign_nif(Algorithm, Type, Data, format_pkey(Algorithm, Key), Options) of
error -> erlang:error(badkey, [Algorithm, Type, Data, Key, Options]);
notsup -> erlang:error(notsup);
Signature -> Signature
end.
+pkey_sign_nif(_Algorithm, _Type, _Digest, _Key, _Options) -> ?nif_stub.
+%%%----------------------------------------------------------------
+%%% Verify
+
+-spec verify(Algorithm, DigestType, Msg, Signature, Key)
+ -> Result
+ when Algorithm :: pk_sign_verify_algs(),
+ DigestType :: rsa_digest_type()
+ | dss_digest_type()
+ | ecdsa_digest_type()
+ | none,
+ Msg :: iodata() | {digest,iodata()},
+ Signature :: binary(),
+ Key :: rsa_public()
+ | dss_public()
+ | [ecdsa_public() | ecdsa_params()]
+ | [eddsa_public() | eddsa_params()]
+ | engine_key_ref(),
+ Result :: boolean().
--type key_id() :: string() | binary() .
--type password() :: string() | binary() .
-
--type engine_key_ref() :: #{engine := engine_ref(),
- key_id := key_id(),
- password => password(),
- term() => term()
- }.
-
--type pk_algs() :: rsa | ecdsa | dss .
--type pk_key() :: engine_key_ref() | [integer() | binary()] .
--type pk_opt() :: list() | rsa_padding() .
-
--spec public_encrypt(pk_algs(), binary(), pk_key(), pk_opt()) -> binary().
--spec public_decrypt(pk_algs(), binary(), pk_key(), pk_opt()) -> binary().
--spec private_encrypt(pk_algs(), binary(), pk_key(), pk_opt()) -> binary().
--spec private_decrypt(pk_algs(), binary(), pk_key(), pk_opt()) -> binary().
+verify(Algorithm, Type, Data, Signature, Key) ->
+ verify(Algorithm, Type, Data, Signature, Key, []).
-public_encrypt(Algorithm, In, Key, Options) when is_list(Options) ->
- case pkey_crypt_nif(Algorithm, In, format_pkey(Algorithm, Key), Options, false, true) of
- error -> erlang:error(encrypt_failed, [Algorithm, In, Key, Options]);
+-spec verify(Algorithm, DigestType, Msg, Signature, Key, Options)
+ -> Result
+ when Algorithm :: pk_sign_verify_algs(),
+ DigestType :: rsa_digest_type()
+ | dss_digest_type()
+ | ecdsa_digest_type(),
+ Msg :: iodata() | {digest,iodata()},
+ Signature :: binary(),
+ Key :: rsa_public()
+ | dss_public()
+ | [ecdsa_public() | ecdsa_params()]
+ | [eddsa_public() | eddsa_params()]
+ | engine_key_ref(),
+ Options :: pk_sign_verify_opts(),
+ Result :: boolean().
+
+verify(Algorithm0, Type0, Data, Signature, Key, Options) ->
+ {Algorithm, Type} = sign_verify_compatibility(Algorithm0, Type0, Data),
+ case pkey_verify_nif(Algorithm, Type, Data, Signature, format_pkey(Algorithm, Key), Options) of
notsup -> erlang:error(notsup);
- Out -> Out
- end;
-%% Backwards compatible
-public_encrypt(Algorithm = rsa, In, Key, Padding) when is_atom(Padding) ->
- public_encrypt(Algorithm, In, Key, [{rsa_padding, Padding}]).
+ Boolean -> Boolean
+ end.
-private_decrypt(Algorithm, In, Key, Options) when is_list(Options) ->
- case pkey_crypt_nif(Algorithm, In, format_pkey(Algorithm, Key), Options, true, false) of
- error -> erlang:error(decrypt_failed, [Algorithm, In, Key, Options]);
- notsup -> erlang:error(notsup);
- Out -> Out
- end;
-%% Backwards compatible
-private_decrypt(Algorithm = rsa, In, Key, Padding) when is_atom(Padding) ->
- private_decrypt(Algorithm, In, Key, [{rsa_padding, Padding}]).
+pkey_verify_nif(_Algorithm, _Type, _Data, _Signature, _Key, _Options) -> ?nif_stub.
-private_encrypt(Algorithm, In, Key, Options) when is_list(Options) ->
- case pkey_crypt_nif(Algorithm, In, format_pkey(Algorithm, Key), Options, true, true) of
- error -> erlang:error(encrypt_failed, [Algorithm, In, Key, Options]);
- notsup -> erlang:error(notsup);
- Out -> Out
- end;
-%% Backwards compatible
-private_encrypt(Algorithm = rsa, In, Key, Padding) when is_atom(Padding) ->
- private_encrypt(Algorithm, In, Key, [{rsa_padding, Padding}]).
+%% Backwards compatible:
+sign_verify_compatibility(dss, none, Digest) ->
+ {sha, {digest, Digest}};
+sign_verify_compatibility(Algorithm0, Type0, _Digest) ->
+ {Algorithm0, Type0}.
-public_decrypt(Algorithm, In, Key, Options) when is_list(Options) ->
- case pkey_crypt_nif(Algorithm, In, format_pkey(Algorithm, Key), Options, false, false) of
- error -> erlang:error(decrypt_failed, [Algorithm, In, Key, Options]);
+%%%================================================================
+%%%
+%%% Public/private encrypt/decrypt
+%%%
+%%% Only rsa works so far (although ecdsa | dss should do it)
+%%%================================================================
+-type pk_encrypt_decrypt_algs() :: rsa .
+
+-type pk_encrypt_decrypt_opts() :: [rsa_opt()] | rsa_compat_opts().
+
+-type rsa_compat_opts() :: [{rsa_pad, rsa_padding()}]
+ | rsa_padding() .
+
+-type rsa_padding() :: rsa_pkcs1_padding
+ | rsa_pkcs1_oaep_padding
+ | rsa_sslv23_padding
+ | rsa_x931_padding
+ | rsa_no_padding.
+
+-type rsa_opt() :: {rsa_padding, rsa_padding()}
+ | {signature_md, atom()}
+ | {rsa_mgf1_md, sha}
+ | {rsa_oaep_label, binary()}
+ | {rsa_oaep_md, sha} .
+
+%%%---- Encrypt with public key
+
+-spec public_encrypt(Algorithm, PlainText, PublicKey, Options) ->
+ CipherText when Algorithm :: pk_encrypt_decrypt_algs(),
+ PlainText :: binary(),
+ PublicKey :: rsa_public() | engine_key_ref(),
+ Options :: pk_encrypt_decrypt_opts(),
+ CipherText :: binary().
+public_encrypt(Algorithm, PlainText, PublicKey, Options) ->
+ pkey_crypt(Algorithm, PlainText, PublicKey, Options, false, true).
+
+%%%---- Decrypt with private key
+
+-spec private_decrypt(Algorithm, CipherText, PrivateKey, Options) ->
+ PlainText when Algorithm :: pk_encrypt_decrypt_algs(),
+ CipherText :: binary(),
+ PrivateKey :: rsa_private() | engine_key_ref(),
+ Options :: pk_encrypt_decrypt_opts(),
+ PlainText :: binary() .
+private_decrypt(Algorithm, CipherText, PrivateKey, Options) ->
+ pkey_crypt(Algorithm, CipherText, PrivateKey, Options, true, false).
+
+%%%---- Encrypt with private key
+
+-spec private_encrypt(Algorithm, PlainText, PrivateKey, Options) ->
+ CipherText when Algorithm :: pk_encrypt_decrypt_algs(),
+ PlainText :: binary(),
+ PrivateKey :: rsa_private() | engine_key_ref(),
+ Options :: pk_encrypt_decrypt_opts(),
+ CipherText :: binary().
+private_encrypt(Algorithm, PlainText, PrivateKey, Options) ->
+ pkey_crypt(Algorithm, PlainText, PrivateKey, Options, true, true).
+
+%%%---- Decrypt with public key
+
+-spec public_decrypt(Algorithm, CipherText, PublicKey, Options) ->
+ PlainText when Algorithm :: pk_encrypt_decrypt_algs(),
+ CipherText :: binary(),
+ PublicKey :: rsa_public() | engine_key_ref(),
+ Options :: pk_encrypt_decrypt_opts(),
+ PlainText :: binary() .
+public_decrypt(Algorithm, CipherText, PublicKey, Options) ->
+ pkey_crypt(Algorithm, CipherText, PublicKey, Options, false, false).
+
+%%%---- Call the nif, but fix a compatibility issue first
+
+%% Backwards compatible (rsa_pad -> rsa_padding is handled by the pkey_crypt_nif):
+pkey_crypt(rsa, Text, Key, Padding, PubPriv, EncDec) when is_atom(Padding) ->
+ pkey_crypt(rsa, Text, Key, [{rsa_padding, Padding}], PubPriv, EncDec);
+
+pkey_crypt(Alg, Text, Key, Options, PubPriv, EncDec) ->
+ case pkey_crypt_nif(Alg, Text, format_pkey(Alg,Key), Options, PubPriv, EncDec) of
+ error when EncDec==true -> erlang:error(encrypt_failed, [Alg, Text, Key, Options]);
+ error when EncDec==false -> erlang:error(decrypt_failed, [Alg, Text, Key, Options]);
notsup -> erlang:error(notsup);
Out -> Out
- end;
-%% Backwards compatible
-public_decrypt(Algorithm = rsa, In, Key, Padding) when is_atom(Padding) ->
- public_decrypt(Algorithm, In, Key, [{rsa_padding, Padding}]).
-
-
-%%
-%% XOR - xor to iolists and return a binary
-%% NB doesn't check that they are the same size, just concatenates
-%% them and sends them to the driver
-%%
--spec exor(iodata(), iodata()) -> binary().
+ end.
-exor(Bin1, Bin2) ->
- Data1 = iolist_to_binary(Bin1),
- Data2 = iolist_to_binary(Bin2),
- MaxBytes = max_bytes(),
- exor(Data1, Data2, erlang:byte_size(Data1), MaxBytes, []).
+pkey_crypt_nif(_Algorithm, _In, _Key, _Options, _IsPrivate, _IsEncrypt) -> ?nif_stub.
+%%%================================================================
+%%%
+%%%
+%%%
+%%%================================================================
+
+-spec generate_key(Type, Params)
+ -> {PublicKey, PrivKeyOut}
+ when Type :: dh | ecdh | rsa | srp,
+ PublicKey :: dh_public() | ecdh_public() | rsa_public() | srp_public(),
+ PrivKeyOut :: dh_private() | ecdh_private() | rsa_private() | {srp_public(),srp_private()},
+ Params :: dh_params() | ecdh_params() | rsa_params() | srp_gen_params()
+ .
generate_key(Type, Params) ->
generate_key(Type, Params, undefined).
+-spec generate_key(Type, Params, PrivKeyIn)
+ -> {PublicKey, PrivKeyOut}
+ when Type :: dh | ecdh | rsa | srp,
+ PublicKey :: dh_public() | ecdh_public() | rsa_public() | srp_public(),
+ PrivKeyIn :: undefined | dh_private() | ecdh_private() | rsa_private() | {srp_public(),srp_private()},
+ PrivKeyOut :: dh_private() | ecdh_private() | rsa_private() | {srp_public(),srp_private()},
+ Params :: dh_params() | ecdh_params() | rsa_params() | srp_comp_params()
+ .
+
generate_key(dh, DHParameters0, PrivateKey) ->
{DHParameters, Len} =
case DHParameters0 of
@@ -548,9 +1706,26 @@ generate_key(rsa, {ModulusSize, PublicExponent}, undefined) ->
{lists:sublist(Private, 2), Private}
end;
+
+generate_key(ecdh, Curve, undefined) when Curve == x448 ;
+ Curve == x25519 ->
+ evp_generate_key_nif(Curve);
generate_key(ecdh, Curve, PrivKey) ->
ec_key_generate(nif_curve_params(Curve), ensure_int_as_bin(PrivKey)).
+
+evp_generate_key_nif(_Curve) -> ?nif_stub.
+
+
+-spec compute_key(Type, OthersPublicKey, MyPrivateKey, Params)
+ -> SharedSecret
+ when Type :: dh | ecdh | srp,
+ SharedSecret :: binary(),
+ OthersPublicKey :: dh_public() | ecdh_public() | srp_public(),
+ MyPrivateKey :: dh_private() | ecdh_private() | {srp_public(),srp_private()},
+ Params :: dh_params() | ecdh_params() | srp_comp_params()
+ .
+
compute_key(dh, OthersPublicKey, MyPrivateKey, DHParameters) ->
case dh_compute_key_nif(ensure_int_as_bin(OthersPublicKey),
ensure_int_as_bin(MyPrivateKey),
@@ -590,76 +1765,137 @@ compute_key(srp, UserPublic, {HostPublic, HostPrivate},
srp_host_secret_nif(Verifier, ensure_int_as_bin(HostPrivate), Scrambler,
UserPubBin, Prime));
+compute_key(ecdh, Others, My, Curve) when Curve == x448 ;
+ Curve == x25519 ->
+ evp_compute_key_nif(Curve, ensure_int_as_bin(Others), ensure_int_as_bin(My));
+
compute_key(ecdh, Others, My, Curve) ->
ecdh_compute_key_nif(ensure_int_as_bin(Others),
nif_curve_params(Curve),
ensure_int_as_bin(My)).
-%%======================================================================
-%% Engine functions
-%%======================================================================
+
+evp_compute_key_nif(_Curve, _OthersBin, _MyBin) -> ?nif_stub.
+
+
+%%%================================================================
+%%%
+%%% XOR - xor to iolists and return a binary
+%%% NB doesn't check that they are the same size, just concatenates
+%%% them and sends them to the driver
+%%%
+%%%================================================================
+
+-spec exor(iodata(), iodata()) -> binary().
+
+exor(Bin1, Bin2) ->
+ Data1 = iolist_to_binary(Bin1),
+ Data2 = iolist_to_binary(Bin2),
+ MaxBytes = max_bytes(),
+ exor(Data1, Data2, erlang:byte_size(Data1), MaxBytes, []).
+
+
+%%%================================================================
+%%%
+%%% Exponentiation modulo
+%%%
+%%%================================================================
+
+-spec mod_pow(N, P, M) -> Result when N :: binary() | integer(),
+ P :: binary() | integer(),
+ M :: binary() | integer(),
+ Result :: binary() | error .
+mod_pow(Base, Exponent, Prime) ->
+ case mod_exp_nif(ensure_int_as_bin(Base), ensure_int_as_bin(Exponent), ensure_int_as_bin(Prime), 0) of
+ <<0>> -> error;
+ R -> R
+ end.
+
+%%%======================================================================
+%%%
+%%% Engine functions
+%%%
+%%%======================================================================
+
+%%%---- Refering to keys stored in an engine:
+-type key_id() :: string() | binary() .
+-type password() :: string() | binary() .
+
+-type engine_key_ref() :: #{engine := engine_ref(),
+ key_id := key_id(),
+ password => password(),
+ term() => term()
+ }.
+
+%%%---- Commands:
+-type engine_cmnd() :: {unicode:chardata(), unicode:chardata()}.
+
%%----------------------------------------------------------------------
%% Function: engine_get_all_methods/0
%%----------------------------------------------------------------------
-type engine_method_type() :: engine_method_rsa | engine_method_dsa | engine_method_dh |
engine_method_rand | engine_method_ecdh | engine_method_ecdsa |
engine_method_ciphers | engine_method_digests | engine_method_store |
- engine_method_pkey_meths | engine_method_pkey_asn1_meths |
+ engine_method_pkey_meths | engine_method_pkey_asn1_meths |
engine_method_ec.
-type engine_ref() :: term().
--spec engine_get_all_methods() ->
- [engine_method_type()].
+-spec engine_get_all_methods() -> Result when Result :: [engine_method_type()].
engine_get_all_methods() ->
notsup_to_error(engine_get_all_methods_nif()).
%%----------------------------------------------------------------------
%% Function: engine_load/3
%%----------------------------------------------------------------------
--spec engine_load(EngineId::unicode:chardata(),
- PreCmds::[{unicode:chardata(), unicode:chardata()}],
- PostCmds::[{unicode:chardata(), unicode:chardata()}]) ->
- {ok, Engine::engine_ref()} | {error, Reason::term()}.
-engine_load(EngineId, PreCmds, PostCmds) when is_list(PreCmds), is_list(PostCmds) ->
+-spec engine_load(EngineId, PreCmds, PostCmds) ->
+ Result when EngineId::unicode:chardata(),
+ PreCmds::[engine_cmnd()],
+ PostCmds::[engine_cmnd()],
+ Result :: {ok, Engine::engine_ref()} | {error, Reason::term()}.
+engine_load(EngineId, PreCmds, PostCmds) when is_list(PreCmds),
+ is_list(PostCmds) ->
engine_load(EngineId, PreCmds, PostCmds, engine_get_all_methods()).
%%----------------------------------------------------------------------
%% Function: engine_load/4
%%----------------------------------------------------------------------
--spec engine_load(EngineId::unicode:chardata(),
- PreCmds::[{unicode:chardata(), unicode:chardata()}],
- PostCmds::[{unicode:chardata(), unicode:chardata()}],
- EngineMethods::[engine_method_type()]) ->
- {ok, Engine::term()} | {error, Reason::term()}.
+-spec engine_load(EngineId, PreCmds, PostCmds, EngineMethods) ->
+ Result when EngineId::unicode:chardata(),
+ PreCmds::[engine_cmnd()],
+ PostCmds::[engine_cmnd()],
+ EngineMethods::[engine_method_type()],
+ Result :: {ok, Engine::engine_ref()} | {error, Reason::term()}.
engine_load(EngineId, PreCmds, PostCmds, EngineMethods) when is_list(PreCmds),
is_list(PostCmds) ->
try
ok = notsup_to_error(engine_load_dynamic_nif()),
case notsup_to_error(engine_by_id_nif(ensure_bin_chardata(EngineId))) of
{ok, Engine} ->
- ok = engine_load_1(Engine, PreCmds, PostCmds, EngineMethods),
- {ok, Engine};
+ engine_load_1(Engine, PreCmds, PostCmds, EngineMethods);
{error, Error1} ->
{error, Error1}
end
catch
- throw:Error2 ->
- Error2
+ throw:Error2 ->
+ Error2
end.
engine_load_1(Engine, PreCmds, PostCmds, EngineMethods) ->
try
ok = engine_nif_wrapper(engine_ctrl_cmd_strings_nif(Engine, ensure_bin_cmds(PreCmds), 0)),
- ok = engine_nif_wrapper(engine_add_nif(Engine)),
ok = engine_nif_wrapper(engine_init_nif(Engine)),
engine_load_2(Engine, PostCmds, EngineMethods),
- ok
+ {ok, Engine}
catch
- throw:Error ->
- %% The engine couldn't initialise, release the structural reference
- ok = engine_free_nif(Engine),
- throw(Error)
+ throw:Error ->
+ %% The engine couldn't initialise, release the structural reference
+ ok = engine_free_nif(Engine),
+ throw(Error);
+ error:badarg ->
+ %% For example bad argument list, release the structural reference
+ ok = engine_free_nif(Engine),
+ error(badarg)
end.
engine_load_2(Engine, PostCmds, EngineMethods) ->
@@ -678,18 +1914,18 @@ engine_load_2(Engine, PostCmds, EngineMethods) ->
%%----------------------------------------------------------------------
%% Function: engine_unload/1
%%----------------------------------------------------------------------
--spec engine_unload(Engine::term()) ->
- ok | {error, Reason::term()}.
+-spec engine_unload(Engine) -> Result when Engine :: engine_ref(),
+ Result :: ok | {error, Reason::term()}.
engine_unload(Engine) ->
engine_unload(Engine, engine_get_all_methods()).
--spec engine_unload(Engine::term(), EngineMethods::[engine_method_type()]) ->
- ok | {error, Reason::term()}.
+-spec engine_unload(Engine, EngineMethods) -> Result when Engine :: engine_ref(),
+ EngineMethods :: [engine_method_type()],
+ Result :: ok | {error, Reason::term()}.
engine_unload(Engine, EngineMethods) ->
try
[ok = engine_nif_wrapper(engine_unregister_nif(Engine, engine_method_atom_to_int(Method))) ||
Method <- EngineMethods],
- ok = engine_nif_wrapper(engine_remove_nif(Engine)),
%% Release the functional reference from engine_init_nif
ok = engine_nif_wrapper(engine_finish_nif(Engine)),
%% Release the structural reference from engine_by_id_nif
@@ -700,19 +1936,63 @@ engine_unload(Engine, EngineMethods) ->
end.
%%----------------------------------------------------------------------
+%% Function: engine_by_id/1
+%%----------------------------------------------------------------------
+-spec engine_by_id(EngineId) -> Result when EngineId :: unicode:chardata(),
+ Result :: {ok, Engine::engine_ref()} | {error, Reason::term()} .
+engine_by_id(EngineId) ->
+ try
+ notsup_to_error(engine_by_id_nif(ensure_bin_chardata(EngineId)))
+ catch
+ throw:Error ->
+ Error
+ end.
+
+%%----------------------------------------------------------------------
+%% Function: engine_add/1
+%%----------------------------------------------------------------------
+-spec engine_add(Engine) -> Result when Engine :: engine_ref(),
+ Result :: ok | {error, Reason::term()} .
+engine_add(Engine) ->
+ notsup_to_error(engine_add_nif(Engine)).
+
+%%----------------------------------------------------------------------
+%% Function: engine_remove/1
+%%----------------------------------------------------------------------
+-spec engine_remove(Engine) -> Result when Engine :: engine_ref(),
+ Result :: ok | {error, Reason::term()} .
+engine_remove(Engine) ->
+ notsup_to_error(engine_remove_nif(Engine)).
+
+%%----------------------------------------------------------------------
+%% Function: engine_get_id/1
+%%----------------------------------------------------------------------
+-spec engine_get_id(Engine) -> EngineId when Engine :: engine_ref(),
+ EngineId :: unicode:chardata().
+engine_get_id(Engine) ->
+ notsup_to_error(engine_get_id_nif(Engine)).
+
+%%----------------------------------------------------------------------
+%% Function: engine_get_name/1
+%%----------------------------------------------------------------------
+-spec engine_get_name(Engine) -> EngineName when Engine :: engine_ref(),
+ EngineName :: unicode:chardata().
+engine_get_name(Engine) ->
+ notsup_to_error(engine_get_name_nif(Engine)).
+
+%%----------------------------------------------------------------------
%% Function: engine_list/0
%%----------------------------------------------------------------------
--spec engine_list() ->
- [EngineId::binary()].
+-spec engine_list() -> Result when Result :: [EngineId::unicode:chardata()].
engine_list() ->
case notsup_to_error(engine_get_first_nif()) of
{ok, <<>>} ->
[];
{ok, Engine} ->
case notsup_to_error(engine_get_id_nif(Engine)) of
- {ok, <<>>} ->
+ <<>> ->
engine_list(Engine, []);
- {ok, EngineId} ->
+ EngineId ->
engine_list(Engine, [EngineId])
end
end.
@@ -723,9 +2003,9 @@ engine_list(Engine0, IdList) ->
lists:reverse(IdList);
{ok, Engine1} ->
case notsup_to_error(engine_get_id_nif(Engine1)) of
- {ok, <<>>} ->
+ <<>> ->
engine_list(Engine1, IdList);
- {ok, EngineId} ->
+ EngineId ->
engine_list(Engine1, [EngineId |IdList])
end
end.
@@ -733,24 +2013,26 @@ engine_list(Engine0, IdList) ->
%%----------------------------------------------------------------------
%% Function: engine_ctrl_cmd_string/3
%%----------------------------------------------------------------------
--spec engine_ctrl_cmd_string(Engine::term(),
- CmdName::unicode:chardata(),
- CmdArg::unicode:chardata()) ->
- ok | {error, Reason::term()}.
+-spec engine_ctrl_cmd_string(Engine, CmdName, CmdArg) ->
+ Result when Engine::term(),
+ CmdName::unicode:chardata(),
+ CmdArg::unicode:chardata(),
+ Result :: ok | {error, Reason::term()}.
engine_ctrl_cmd_string(Engine, CmdName, CmdArg) ->
engine_ctrl_cmd_string(Engine, CmdName, CmdArg, false).
%%----------------------------------------------------------------------
%% Function: engine_ctrl_cmd_string/4
%%----------------------------------------------------------------------
--spec engine_ctrl_cmd_string(Engine::term(),
- CmdName::unicode:chardata(),
- CmdArg::unicode:chardata(),
- Optional::boolean()) ->
- ok | {error, Reason::term()}.
+-spec engine_ctrl_cmd_string(Engine, CmdName, CmdArg, Optional) ->
+ Result when Engine::term(),
+ CmdName::unicode:chardata(),
+ CmdArg::unicode:chardata(),
+ Optional::boolean(),
+ Result :: ok | {error, Reason::term()}.
engine_ctrl_cmd_string(Engine, CmdName, CmdArg, Optional) ->
- case engine_ctrl_cmd_strings_nif(Engine,
- ensure_bin_cmds([{CmdName, CmdArg}]),
+ case engine_ctrl_cmd_strings_nif(Engine,
+ ensure_bin_cmds([{CmdName, CmdArg}]),
bool_to_int(Optional)) of
ok ->
ok;
@@ -760,6 +2042,97 @@ engine_ctrl_cmd_string(Engine, CmdName, CmdArg, Optional) ->
{error, Error}
end.
+%%----------------------------------------------------------------------
+%% Function: ensure_engine_loaded/2
+%% Special version of load that only uses dynamic engine to load
+%%----------------------------------------------------------------------
+-spec ensure_engine_loaded(EngineId, LibPath) ->
+ Result when EngineId :: unicode:chardata(),
+ LibPath :: unicode:chardata(),
+ Result :: {ok, Engine::engine_ref()} | {error, Reason::term()}.
+ensure_engine_loaded(EngineId, LibPath) ->
+ ensure_engine_loaded(EngineId, LibPath, engine_get_all_methods()).
+
+%%----------------------------------------------------------------------
+%% Function: ensure_engine_loaded/3
+%% Special version of load that only uses dynamic engine to load
+%%----------------------------------------------------------------------
+-spec ensure_engine_loaded(EngineId, LibPath, EngineMethods) ->
+ Result when EngineId :: unicode:chardata(),
+ LibPath :: unicode:chardata(),
+ EngineMethods :: [engine_method_type()],
+ Result :: {ok, Engine::engine_ref()} | {error, Reason::term()}.
+ensure_engine_loaded(EngineId, LibPath, EngineMethods) ->
+ try
+ List = crypto:engine_list(),
+ case lists:member(EngineId, List) of
+ true ->
+ notsup_to_error(engine_by_id_nif(ensure_bin_chardata(EngineId)));
+ false ->
+ ok = notsup_to_error(engine_load_dynamic_nif()),
+ case notsup_to_error(engine_by_id_nif(ensure_bin_chardata(<<"dynamic">>))) of
+ {ok, Engine} ->
+ PreCommands = [{<<"SO_PATH">>, ensure_bin_chardata(LibPath)},
+ {<<"ID">>, ensure_bin_chardata(EngineId)},
+ <<"LOAD">>],
+ ensure_engine_loaded_1(Engine, PreCommands, EngineMethods);
+ {error, Error1} ->
+ {error, Error1}
+ end
+ end
+ catch
+ throw:Error2 ->
+ Error2
+ end.
+
+ensure_engine_loaded_1(Engine, PreCmds, Methods) ->
+ try
+ ok = engine_nif_wrapper(engine_ctrl_cmd_strings_nif(Engine, ensure_bin_cmds(PreCmds), 0)),
+ ok = engine_nif_wrapper(engine_add_nif(Engine)),
+ ok = engine_nif_wrapper(engine_init_nif(Engine)),
+ ensure_engine_loaded_2(Engine, Methods),
+ {ok, Engine}
+ catch
+ throw:Error ->
+ %% The engine couldn't initialise, release the structural reference
+ ok = engine_free_nif(Engine),
+ throw(Error)
+ end.
+
+ensure_engine_loaded_2(Engine, Methods) ->
+ try
+ [ok = engine_nif_wrapper(engine_register_nif(Engine, engine_method_atom_to_int(Method))) ||
+ Method <- Methods],
+ ok
+ catch
+ throw:Error ->
+ %% The engine registration failed, release the functional reference
+ ok = engine_finish_nif(Engine),
+ throw(Error)
+ end.
+%%----------------------------------------------------------------------
+%% Function: ensure_engine_unloaded/1
+%%----------------------------------------------------------------------
+-spec ensure_engine_unloaded(Engine) -> Result when Engine :: engine_ref(),
+ Result :: ok | {error, Reason::term()}.
+ensure_engine_unloaded(Engine) ->
+ ensure_engine_unloaded(Engine, engine_get_all_methods()).
+
+%%----------------------------------------------------------------------
+%% Function: ensure_engine_unloaded/2
+%%----------------------------------------------------------------------
+-spec ensure_engine_unloaded(Engine, EngineMethods) ->
+ Result when Engine :: engine_ref(),
+ EngineMethods :: [engine_method_type()],
+ Result :: ok | {error, Reason::term()}.
+ensure_engine_unloaded(Engine, EngineMethods) ->
+ case engine_remove(Engine) of
+ ok ->
+ engine_unload(Engine, EngineMethods);
+ {error, E} ->
+ {error, E}
+ end.
+
%%--------------------------------------------------------------------
%%% On load
%%--------------------------------------------------------------------
@@ -809,8 +2182,13 @@ on_load() ->
case Status of
ok -> ok;
{error, {E, Str}} ->
- error_logger:error_msg("Unable to load crypto library. Failed with error:~n\"~p, ~s\"~n"
- "OpenSSL might not be installed on this system.~n",[E,Str]),
+ Fmt = "Unable to load crypto library. Failed with error:~n\"~p, ~s\"~n~s",
+ Extra = case E of
+ load_failed ->
+ "OpenSSL might not be installed on this system.\n";
+ _ -> ""
+ end,
+ error_logger:error_msg(Fmt, [E,Str,Extra]),
Status
end.
@@ -821,13 +2199,17 @@ path2bin(Path) when is_list(Path) ->
Bin
end.
-%%--------------------------------------------------------------------
+%%%================================================================
+%%%================================================================
+%%%
%%% Internal functions
-%%--------------------------------------------------------------------
+%%%
+%%%================================================================
+
max_bytes() ->
?MAX_BYTES_TO_NIF.
-notsup_to_error(notsup) ->
+notsup_to_error(notsup) ->
erlang:error(notsup);
notsup_to_error(Other) ->
Other.
@@ -847,6 +2229,7 @@ hash_update(State0, Data, _, MaxBytes) ->
State = notsup_to_error(hash_update_nif(State0, Increment)),
hash_update(State, Rest, erlang:byte_size(Rest), MaxBytes).
+hash_info_nif(_Hash) -> ?nif_stub.
hash_nif(_Hash, _Data) -> ?nif_stub.
hash_init_nif(_Hash) -> ?nif_stub.
hash_update_nif(_State, _Data) -> ?nif_stub.
@@ -883,38 +2266,21 @@ hmac_final_nif(_Context) -> ?nif_stub.
hmac_final_nif(_Context, _MacSize) -> ?nif_stub.
%% CMAC
-
cmac_nif(_Type, _Key, _Data) -> ?nif_stub.
-%% CIPHERS --------------------------------------------------------------------
+%% POLY1305
+poly1305_nif(_Key, _Data) -> ?nif_stub.
-block_crypt_nif(_Type, _Key, _Ivec, _Text, _IsEncrypt) -> ?nif_stub.
-block_crypt_nif(_Type, _Key, _Text, _IsEncrypt) -> ?nif_stub.
-check_des3_key(Key) ->
- case lists:map(fun erlang:iolist_to_binary/1, Key) of
- ValidKey = [B1, B2, B3] when byte_size(B1) =:= 8,
- byte_size(B2) =:= 8,
- byte_size(B3) =:= 8 ->
- ValidKey;
- _ ->
- error(badarg)
- end.
+%% CIPHERS --------------------------------------------------------------------
+
+cipher_info_nif(_Type) -> ?nif_stub.
%%
%% AES - in Galois/Counter Mode (GCM)
%%
%% The default tag length is EVP_GCM_TLS_TAG_LEN(16),
-aes_gcm_encrypt(Key, Ivec, AAD, In) ->
- aes_gcm_encrypt(Key, Ivec, AAD, In, 16).
-aes_gcm_encrypt(_Key, _Ivec, _AAD, _In, _TagLength) -> ?nif_stub.
-aes_gcm_decrypt(_Key, _Ivec, _AAD, _In, _Tag) -> ?nif_stub.
-
-%%
-%% Chacha20/Ppoly1305
-%%
-chacha20_poly1305_encrypt(_Key, _Ivec, _AAD, _In) -> ?nif_stub.
-chacha20_poly1305_decrypt(_Key, _Ivec, _AAD, _In, _Tag) -> ?nif_stub.
+aead_cipher(_Type, _Key, _Ivec, _AAD, _In, _TagOrTagLength, _EncFlg) -> ?nif_stub.
%%
%% AES - with 256 bit key in infinite garble extension mode (IGE)
@@ -922,54 +2288,7 @@ chacha20_poly1305_decrypt(_Key, _Ivec, _AAD, _In, _Tag) -> ?nif_stub.
aes_ige_crypt_nif(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub.
-
-%% Stream ciphers --------------------------------------------------------------------
-
-stream_crypt(Fun, State, Data, Size, MaxByts, []) when Size =< MaxByts ->
- Fun(State, Data);
-stream_crypt(Fun, State0, Data, Size, MaxByts, Acc) when Size =< MaxByts ->
- {State, Cipher} = Fun(State0, Data),
- {State, list_to_binary(lists:reverse([Cipher | Acc]))};
-stream_crypt(Fun, State0, Data, _, MaxByts, Acc) ->
- <<Increment:MaxByts/binary, Rest/binary>> = Data,
- {State, CipherText} = Fun(State0, Increment),
- stream_crypt(Fun, State, Rest, erlang:byte_size(Rest), MaxByts, [CipherText | Acc]).
-
-do_stream_encrypt({aes_ctr, State0}, Data) ->
- {State, Cipher} = aes_ctr_stream_encrypt(State0, Data),
- {{aes_ctr, State}, Cipher};
-do_stream_encrypt({rc4, State0}, Data) ->
- {State, Cipher} = rc4_encrypt_with_state(State0, Data),
- {{rc4, State}, Cipher}.
-
-do_stream_decrypt({aes_ctr, State0}, Data) ->
- {State, Text} = aes_ctr_stream_decrypt(State0, Data),
- {{aes_ctr, State}, Text};
-do_stream_decrypt({rc4, State0}, Data) ->
- {State, Text} = rc4_encrypt_with_state(State0, Data),
- {{rc4, State}, Text}.
-
-
-%%
-%% AES - in counter mode (CTR) with state maintained for multi-call streaming
-%%
--type ctr_state() :: { iodata(), binary(), binary(), integer() } | binary().
-
--spec aes_ctr_stream_init(iodata(), binary()) -> ctr_state().
--spec aes_ctr_stream_encrypt(ctr_state(), binary()) ->
- { ctr_state(), binary() }.
--spec aes_ctr_stream_decrypt(ctr_state(), binary()) ->
- { ctr_state(), binary() }.
-
-aes_ctr_stream_init(_Key, _IVec) -> ?nif_stub.
-aes_ctr_stream_encrypt(_State, _Data) -> ?nif_stub.
-aes_ctr_stream_decrypt(_State, _Cipher) -> ?nif_stub.
-
-%%
-%% RC4 - symmetric stream cipher
-%%
-rc4_set_key(_Key) -> ?nif_stub.
-rc4_encrypt_with_state(_State, _Data) -> ?nif_stub.
+%%%================================================================
%% Secure remote password -------------------------------------------------------------------
@@ -1037,11 +2356,6 @@ srp_user_secret_nif(_A, _U, _B, _Multiplier, _Generator, _Exponent, _Prime) -> ?
srp_value_B_nif(_Multiplier, _Verifier, _Generator, _Exponent, _Prime) -> ?nif_stub.
-%% Digital signatures --------------------------------------------------------------------
-
-pkey_sign_nif(_Algorithm, _Type, _Digest, _Key, _Options) -> ?nif_stub.
-pkey_verify_nif(_Algorithm, _Type, _Data, _Signature, _Key, _Options) -> ?nif_stub.
-
%% Public Keys --------------------------------------------------------------------
%% RSA Rivest-Shamir-Adleman functions
%%
@@ -1051,27 +2365,6 @@ rsa_generate_key_nif(_Bits, _Exp) -> ?nif_stub.
%% DH Diffie-Hellman functions
%%
-%% Generate (and check) Parameters is not documented because they are implemented
-%% for testing (and offline parameter generation) only.
-%% From the openssl doc:
-%% DH_generate_parameters() may run for several hours before finding a suitable prime.
-%% Thus dh_generate_parameters may in this implementation block
-%% the emulator for several hours.
-%%
-%% usage: dh_generate_parameters(1024, 2 or 5) ->
-%% [Prime=mpint(), SharedGenerator=mpint()]
-dh_generate_parameters(PrimeLen, Generator) ->
- case dh_generate_parameters_nif(PrimeLen, Generator) of
- error -> erlang:error(generation_failed, [PrimeLen,Generator]);
- Ret -> Ret
- end.
-
-dh_generate_parameters_nif(_PrimeLen, _Generator) -> ?nif_stub.
-
-%% Checks that the DHParameters are ok.
-%% DHParameters = [P (Prime)= mpint(), G(Generator) = mpint()]
-dh_check([_Prime,_Gen]) -> ?nif_stub.
-
%% DHParameters = [P (Prime)= mpint(), G(Generator) = mpint()]
%% PrivKey = mpint()
dh_generate_key_nif(_PrivateKey, _DHParameters, _Mpint, _Length) -> ?nif_stub.
@@ -1084,13 +2377,22 @@ ec_key_generate(_Curve, _Key) -> ?nif_stub.
ecdh_compute_key_nif(_Others, _Curve, _My) -> ?nif_stub.
+-spec ec_curves() -> [EllipticCurve] when EllipticCurve :: ec_named_curve()
+ | edwards_curve_dh()
+ | edwards_curve_ed() .
+
ec_curves() ->
crypto_ec_curves:curves().
+-spec ec_curve(CurveName) -> ExplicitCurve when CurveName :: ec_named_curve(),
+ ExplicitCurve :: ec_explicit_curve() .
ec_curve(X) ->
crypto_ec_curves:curve(X).
+-spec privkey_to_pubkey(Type, EnginePrivateKeyRef) -> PublicKey when Type :: rsa | dss,
+ EnginePrivateKeyRef :: engine_key_ref(),
+ PublicKey :: rsa_public() | dss_public() .
privkey_to_pubkey(Alg, EngineMap) when Alg == rsa; Alg == dss; Alg == ecdsa ->
try privkey_to_pubkey_nif(Alg, format_pkey(Alg,EngineMap))
of
@@ -1104,7 +2406,7 @@ privkey_to_pubkey(Alg, EngineMap) when Alg == rsa; Alg == dss; Alg == ecdsa ->
error:notsup ->
{error, notsup}
end.
-
+
privkey_to_pubkey_nif(_Alg, _EngineMap) -> ?nif_stub.
@@ -1116,13 +2418,23 @@ term_to_nif_prime({prime_field, Prime}) ->
{prime_field, ensure_int_as_bin(Prime)};
term_to_nif_prime(PrimeField) ->
PrimeField.
+
term_to_nif_curve({A, B, Seed}) ->
{ensure_int_as_bin(A), ensure_int_as_bin(B), Seed}.
+
nif_curve_params({PrimeField, Curve, BasePoint, Order, CoFactor}) ->
- {term_to_nif_prime(PrimeField), term_to_nif_curve(Curve), ensure_int_as_bin(BasePoint), ensure_int_as_bin(Order), ensure_int_as_bin(CoFactor)};
+ {term_to_nif_prime(PrimeField),
+ term_to_nif_curve(Curve),
+ ensure_int_as_bin(BasePoint),
+ ensure_int_as_bin(Order),
+ ensure_int_as_bin(CoFactor)};
nif_curve_params(Curve) when is_atom(Curve) ->
%% named curve
- crypto_ec_curves:curve(Curve).
+ case Curve of
+ x448 -> {evp,Curve};
+ x25519 -> {evp,Curve};
+ _ -> crypto_ec_curves:curve(Curve)
+ end.
%% MISC --------------------------------------------------------------------
@@ -1140,7 +2452,13 @@ exor(Data1, Data2, _Size, MaxByts, Acc) ->
do_exor(_A, _B) -> ?nif_stub.
-algorithms() -> ?nif_stub.
+hash_algorithms() -> ?nif_stub.
+pubkey_algorithms() -> ?nif_stub.
+cipher_algorithms() -> ?nif_stub.
+mac_algorithms() -> ?nif_stub.
+curve_algorithms() -> ?nif_stub.
+rsa_opts_algorithms() -> ?nif_stub.
+
int_to_bin(X) when X < 0 -> int_to_bin_neg(X, []);
int_to_bin(X) -> int_to_bin_pos(X, []).
@@ -1155,6 +2473,7 @@ int_to_bin_neg(-1, Ds=[MSB|_]) when MSB >= 16#80 ->
int_to_bin_neg(X,Ds) ->
int_to_bin_neg(X bsr 8, [(X band 255)|Ds]).
+-spec bytes_to_integer(binary()) -> integer() .
bytes_to_integer(Bin) ->
bin_to_int(Bin).
@@ -1202,9 +2521,6 @@ format_pwd(M) -> M.
%%--------------------------------------------------------------------
%%
--type rsa_padding() :: 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding' | 'rsa_no_padding'.
-
-pkey_crypt_nif(_Algorithm, _In, _Key, _Options, _IsPrivate, _IsEncrypt) -> ?nif_stub.
%% large integer in a binary with 32bit length
%% MP representaion (SSH2)
@@ -1266,6 +2582,7 @@ engine_unregister_nif(_Engine, _EngineMethod) -> ?nif_stub.
engine_get_first_nif() -> ?nif_stub.
engine_get_next_nif(_Engine) -> ?nif_stub.
engine_get_id_nif(_Engine) -> ?nif_stub.
+engine_get_name_nif(_Engine) -> ?nif_stub.
engine_get_all_methods_nif() -> ?nif_stub.
%%--------------------------------------------------------------------
@@ -1323,7 +2640,7 @@ get_test_engine() ->
Type = erlang:system_info(system_architecture),
LibDir = filename:join([code:priv_dir(crypto), "lib"]),
ArchDir = filename:join([LibDir, Type]),
- case filelib:is_dir(ArchDir) of
+ case filelib:is_dir(ArchDir) of
true -> check_otp_test_engine(ArchDir);
false -> check_otp_test_engine(LibDir)
end.
@@ -1332,7 +2649,7 @@ check_otp_test_engine(LibDir) ->
case filelib:wildcard("otp_test_engine*", LibDir) of
[] ->
{error, notexist};
- [LibName] ->
+ [LibName|_] -> % In case of Valgrind there could be more than one
LibPath = filename:join(LibDir,LibName),
case filelib:is_file(LibPath) of
true ->
@@ -1341,4 +2658,5 @@ check_otp_test_engine(LibDir) ->
{error, notexist}
end
end.
-
+
+
diff --git a/lib/crypto/src/crypto_ec_curves.erl b/lib/crypto/src/crypto_ec_curves.erl
index 9602a7e24b..a0a2f99601 100644
--- a/lib/crypto/src/crypto_ec_curves.erl
+++ b/lib/crypto/src/crypto_ec_curves.erl
@@ -3,41 +3,7 @@
-export([curve/1, curves/0]).
curves() ->
- CryptoSupport = crypto:supports(),
- PubKeys = proplists:get_value(public_keys, CryptoSupport),
- HasEC = proplists:get_bool(ecdh, PubKeys),
- HasGF2m = proplists:get_bool(ec_gf2m, PubKeys),
- FIPSMode = crypto:info_fips() == enabled,
- prime_curves(HasEC, FIPSMode) ++ characteristic_two_curves(HasGF2m, FIPSMode).
-
-
-prime_curves(true, true) ->
- [secp160k1,secp160r1,secp160r2,
- secp192r1,secp192k1,secp224k1,secp224r1,secp256k1,secp256r1,secp384r1,
- secp521r1,prime192v1,prime192v2,prime192v3,prime239v1,prime239v2,prime239v3,
- prime256v1,wtls7,wtls9,wtls12,
- brainpoolP160r1,brainpoolP160t1,brainpoolP192r1,brainpoolP192t1,
- brainpoolP224r1,brainpoolP224t1,brainpoolP256r1,brainpoolP256t1,
- brainpoolP320r1,brainpoolP320t1,brainpoolP384r1,brainpoolP384t1,
- brainpoolP512r1,brainpoolP512t1];
-prime_curves(true, false) ->
- [secp112r1,secp112r2,secp128r1,secp128r2,wtls6,wtls8]
- ++ prime_curves(true, true);
-prime_curves(_, _) ->
- [].
-
-characteristic_two_curves(true, true) ->
- [sect163k1,sect163r1,
- sect163r2,sect193r1,sect193r2,sect233k1,sect233r1,sect239k1,sect283k1,
- sect283r1,sect409k1,sect409r1,sect571k1,sect571r1,c2pnb163v1,c2pnb163v2,
- c2pnb163v3,c2pnb176v1,c2tnb191v1,c2tnb191v2,c2tnb191v3,c2pnb208w1,c2tnb239v1,
- c2tnb239v2,c2tnb239v3,c2pnb272w1,c2pnb304w1,c2tnb359v1,c2pnb368w1,c2tnb431r1,
- wtls3,wtls5,wtls10,wtls11];
-characteristic_two_curves(true, _) ->
- [sect113r1,sect113r2,sect131r1,sect131r2,wtls1,wtls4,ipsec3,ipsec4]
- ++ characteristic_two_curves(true, true);
-characteristic_two_curves(_, _) ->
- [].
+ proplists:get_value(curves, crypto:supports()) -- [x25519,x448].
curve(secp112r1) ->
{
diff --git a/lib/crypto/test/Makefile b/lib/crypto/test/Makefile
index e046a25338..988d95a8bc 100644
--- a/lib/crypto/test/Makefile
+++ b/lib/crypto/test/Makefile
@@ -6,7 +6,7 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
# ----------------------------------------------------
MODULES = \
- blowfish_SUITE \
+ crypto_bench_SUITE \
crypto_SUITE \
engine_SUITE
@@ -77,7 +77,7 @@ release_spec:
release_tests_spec: $(TEST_TARGET)
$(INSTALL_DIR) "$(RELSYSDIR)"
- $(INSTALL_DATA) crypto.spec crypto.cover $(RELTEST_FILES) "$(RELSYSDIR)"
+ $(INSTALL_DATA) crypto.spec crypto_bench.spec crypto.cover $(RELTEST_FILES) "$(RELSYSDIR)"
@tar cfh - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
chmod -R u+w "$(RELSYSDIR)"
diff --git a/lib/crypto/test/blowfish_SUITE.erl b/lib/crypto/test/blowfish_SUITE.erl
deleted file mode 100644
index c9033ac4f8..0000000000
--- a/lib/crypto/test/blowfish_SUITE.erl
+++ /dev/null
@@ -1,300 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
--module(blowfish_SUITE).
-
-%% Note: This directive should only be used in test suites.
--compile(export_all).
-
--include_lib("common_test/include/ct.hrl").
-
--define(TIMEOUT, 120000). % 2 min
-
--define(KEY, to_bin("0123456789ABCDEFF0E1D2C3B4A59687")).
--define(IVEC, to_bin("FEDCBA9876543210")).
-%% "7654321 Now is the time for " (includes trailing '\0')
--define(DATA, to_bin("37363534333231204E6F77206973207468652074696D6520666F722000")).
--define(DATA_PADDED, to_bin("37363534333231204E6F77206973207468652074696D6520666F722000000000")).
-
-%% Test server callback functions
-%%--------------------------------------------------------------------
-%% Function: init_per_suite(Config) -> Config
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Initialization before the whole suite
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
-%%--------------------------------------------------------------------
-init_per_suite(Config) ->
- case catch crypto:start() of
- ok ->
- catch ct:comment("~s",[element(3,hd(crypto:info_lib()))]),
- catch ct:log("crypto:info_lib() -> ~p~n"
- "crypto:supports() -> ~p~n"
- "crypto:version() -> ~p~n"
- ,[crypto:info_lib(), crypto:supports(), crypto:version()]),
- Config;
- _Else ->
- {skip,"Could not start crypto!"}
- end.
-
-%%--------------------------------------------------------------------
-%% Function: end_per_suite(Config) -> _
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after the whole suite
-%%--------------------------------------------------------------------
-end_per_suite(_Config) ->
- crypto:stop().
-
-%%--------------------------------------------------------------------
-%% Function: init_per_testcase(TestCase, Config) -> Config
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%%
-%% Description: Initialization before each test case
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
-%% Description: Initialization before each test case
-%%--------------------------------------------------------------------
-init_per_testcase(_TestCase, Config0) ->
- Config = lists:keydelete(watchdog, 1, Config0),
- Dog = test_server:timetrap(?TIMEOUT),
- [{watchdog, Dog} | Config].
-
-%%--------------------------------------------------------------------
-%% Function: end_per_testcase(TestCase, Config) -> _
-%% Case - atom()
-%% Name of the test case that is about to be run.
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after each test case
-%%--------------------------------------------------------------------
-end_per_testcase(_TestCase, Config) ->
- Dog = ?config(watchdog, Config),
- case Dog of
- undefined ->
- ok;
- _ ->
- test_server:timetrap_cancel(Dog)
- end.
-
-%%--------------------------------------------------------------------
-%% Function: all(Clause) -> TestCases
-%% Clause - atom() - suite | doc
-%% TestCases - [Case]
-%% Case - atom()
-%% Name of a test case.
-%% Description: Returns a list of all test cases in this test suite
-%%--------------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
-[{group, fips},
- {group, non_fips}].
-
-groups() ->
- [{fips, [], [no_ecb, no_cbc, no_cfb64, no_ofb64]},
- {non_fips, [], [ecb, cbc, cfb64, ofb64]}].
-
-init_per_group(fips, Config) ->
- case crypto:info_fips() of
- enabled ->
- Config;
- not_enabled ->
- case crypto:enable_fips_mode(true) of
- true ->
- enabled = crypto:info_fips(),
- Config;
- false ->
- {skip, "Failed to enable FIPS mode"}
- end;
- not_supported ->
- {skip, "FIPS mode not supported"}
- end;
-init_per_group(non_fips, Config) ->
- case crypto:info_fips() of
- enabled ->
- true = crypto:enable_fips_mode(false),
- not_enabled = crypto:info_fips(),
- Config;
- _NotEnabled ->
- Config
- end;
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%% Test cases start here.
-%%--------------------------------------------------------------------
-
-ecb_test(KeyBytes, ClearBytes, CipherBytes) ->
- {Key, Clear, Cipher} =
- {to_bin(KeyBytes), to_bin(ClearBytes), to_bin(CipherBytes)},
- ?line m(crypto:block_encrypt(blowfish_ecb, Key, Clear), Cipher),
- true.
-
-ecb(doc) ->
- "Test that ECB mode is OK";
-ecb(suite) ->
- [];
-ecb(Config) when is_list(Config) ->
- true = ecb_test("0000000000000000", "0000000000000000", "4EF997456198DD78"),
- true = ecb_test("FFFFFFFFFFFFFFFF", "FFFFFFFFFFFFFFFF", "51866FD5B85ECB8A"),
- true = ecb_test("3000000000000000", "1000000000000001", "7D856F9A613063F2"),
- true = ecb_test("1111111111111111", "1111111111111111", "2466DD878B963C9D"),
- true = ecb_test("0123456789ABCDEF", "1111111111111111", "61F9C3802281B096"),
- true = ecb_test("1111111111111111", "0123456789ABCDEF", "7D0CC630AFDA1EC7"),
- true = ecb_test("0000000000000000", "0000000000000000", "4EF997456198DD78"),
- true = ecb_test("FEDCBA9876543210", "0123456789ABCDEF", "0ACEAB0FC6A0A28D"),
- true = ecb_test("7CA110454A1A6E57", "01A1D6D039776742", "59C68245EB05282B"),
- true = ecb_test("0131D9619DC1376E", "5CD54CA83DEF57DA", "B1B8CC0B250F09A0"),
- true = ecb_test("07A1133E4A0B2686", "0248D43806F67172", "1730E5778BEA1DA4"),
- true = ecb_test("3849674C2602319E", "51454B582DDF440A", "A25E7856CF2651EB"),
- true = ecb_test("04B915BA43FEB5B6", "42FD443059577FA2", "353882B109CE8F1A"),
- true = ecb_test("0113B970FD34F2CE", "059B5E0851CF143A", "48F4D0884C379918"),
- true = ecb_test("0170F175468FB5E6", "0756D8E0774761D2", "432193B78951FC98"),
- true = ecb_test("43297FAD38E373FE", "762514B829BF486A", "13F04154D69D1AE5"),
- true = ecb_test("07A7137045DA2A16", "3BDD119049372802", "2EEDDA93FFD39C79"),
- true = ecb_test("04689104C2FD3B2F", "26955F6835AF609A", "D887E0393C2DA6E3"),
- true = ecb_test("37D06BB516CB7546", "164D5E404F275232", "5F99D04F5B163969"),
- true = ecb_test("1F08260D1AC2465E", "6B056E18759F5CCA", "4A057A3B24D3977B"),
- true = ecb_test("584023641ABA6176", "004BD6EF09176062", "452031C1E4FADA8E"),
- true = ecb_test("025816164629B007", "480D39006EE762F2", "7555AE39F59B87BD"),
- true = ecb_test("49793EBC79B3258F", "437540C8698F3CFA", "53C55F9CB49FC019"),
- true = ecb_test("4FB05E1515AB73A7", "072D43A077075292", "7A8E7BFA937E89A3"),
- true = ecb_test("49E95D6D4CA229BF", "02FE55778117F12A", "CF9C5D7A4986ADB5"),
- true = ecb_test("018310DC409B26D6", "1D9D5C5018F728C2", "D1ABB290658BC778"),
- true = ecb_test("1C587F1C13924FEF", "305532286D6F295A", "55CB3774D13EF201"),
- true = ecb_test("0101010101010101", "0123456789ABCDEF", "FA34EC4847B268B2"),
- true = ecb_test("1F1F1F1F0E0E0E0E", "0123456789ABCDEF", "A790795108EA3CAE"),
- true = ecb_test("E0FEE0FEF1FEF1FE", "0123456789ABCDEF", "C39E072D9FAC631D"),
- true = ecb_test("0000000000000000", "FFFFFFFFFFFFFFFF", "014933E0CDAFF6E4"),
- true = ecb_test("FFFFFFFFFFFFFFFF", "0000000000000000", "F21E9A77B71C49BC"),
- true = ecb_test("0123456789ABCDEF", "0000000000000000", "245946885754369A"),
- true = ecb_test("FEDCBA9876543210", "FFFFFFFFFFFFFFFF", "6B5C5A9C5D9E0A5A"),
- ok.
-
-cbc(doc) ->
- "Test that CBC mode is OK";
-cbc(suite) ->
- [];
-cbc(Config) when is_list(Config) ->
- true = crypto:block_encrypt(blowfish_cbc, ?KEY, ?IVEC, ?DATA_PADDED) =:=
- to_bin("6B77B4D63006DEE605B156E27403979358DEB9E7154616D959F1652BD5FF92CC"),
- ok.
-
-cfb64(doc) ->
- "Test that CFB64 mode is OK";
-cfb64(suite) ->
- [];
-cfb64(Config) when is_list(Config) ->
- true = crypto:block_encrypt(blowfish_cfb64, ?KEY, ?IVEC, ?DATA) =:=
- to_bin("E73214A2822139CAF26ECF6D2EB9E76E3DA3DE04D1517200519D57A6C3"),
- ok.
-
-ofb64(doc) ->
- "Test that OFB64 mode is OK";
-ofb64(suite) ->
- [];
-ofb64(Config) when is_list(Config) ->
- true = crypto:block_encrypt(blowfish_ofb64, ?KEY, ?IVEC, ?DATA) =:=
- to_bin("E73214A2822139CA62B343CC5B65587310DD908D0C241B2263C2CF80DA"),
- ok.
-
-no_ecb(doc) ->
- "Test that ECB mode is disabled";
-no_ecb(suite) ->
- [];
-no_ecb(Config) when is_list(Config) ->
- notsup(fun crypto:block_encrypt/3,
- [blowfish_ecb,
- to_bin("0000000000000000"),
- to_bin("FFFFFFFFFFFFFFFF")]).
-
-no_cbc(doc) ->
- "Test that CBC mode is disabled";
-no_cbc(suite) ->
- [];
-no_cbc(Config) when is_list(Config) ->
- notsup(fun crypto:block_encrypt/4,
- [blowfish_cbc, ?KEY, ?IVEC, ?DATA_PADDED]).
-
-no_cfb64(doc) ->
- "Test that CFB64 mode is disabled";
-no_cfb64(suite) ->
- [];
-no_cfb64(Config) when is_list(Config) ->
- notsup(fun crypto:block_encrypt/4,
- [blowfish_cfb64, ?KEY, ?IVEC, ?DATA]),
- ok.
-
-no_ofb64(doc) ->
- "Test that OFB64 mode is disabled";
-no_ofb64(suite) ->
- [];
-no_ofb64(Config) when is_list(Config) ->
- notsup(fun crypto:block_encrypt/4,
- [blowfish_ofb64, ?KEY, ?IVEC, ?DATA]).
-
-%% Helper functions
-
-%% Assert function fails with notsup error
-notsup(Fun, Args) ->
- ok = try
- {error, {return, apply(Fun, Args)}}
- catch
- error:notsup ->
- ok;
- Class:Error ->
- {error, {Class, Error}}
- end.
-
-
-%% Convert a hexadecimal string to a binary.
--spec(to_bin(L::string()) -> binary()).
-to_bin(L) ->
- to_bin(L, []).
-
-%% @spec dehex(char()) -> integer()
-%% @doc Convert a hex digit to its integer value.
--spec(dehex(char()) -> integer()).
-dehex(C) when C >= $0, C =< $9 ->
- C - $0;
-dehex(C) when C >= $a, C =< $f ->
- C - $a + 10;
-dehex(C) when C >= $A, C =< $F ->
- C - $A + 10.
-
--spec(to_bin(L::string(), list()) -> binary()).
-to_bin([], Acc) ->
- iolist_to_binary(lists:reverse(Acc));
-to_bin([C1, C2 | Rest], Acc) ->
- to_bin(Rest, [(dehex(C1) bsl 4) bor dehex(C2) | Acc]).
-
-m(X,X) -> ok.
diff --git a/lib/crypto/test/crypto.spec b/lib/crypto/test/crypto.spec
index cc09970cb3..4a95275687 100644
--- a/lib/crypto/test/crypto.spec
+++ b/lib/crypto/test/crypto.spec
@@ -1 +1,6 @@
{suites,"../crypto_test",all}.
+
+{skip_suites, "../crypto_test", [crypto_bench_SUITE
+ ],
+ "Benchmarks run separately"}.
+
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 6dab459df6..56691223c4 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -1,7 +1,7 @@
-%%
+%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -9,7 +9,7 @@
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
-%% Unless required by applicable law or agreed to in writing, software
+
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
@@ -31,53 +31,118 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[app,
+ {group, api_errors},
appup,
{group, fips},
{group, non_fips},
mod_pow,
exor,
rand_uniform,
+ rand_threads,
rand_plugin,
- rand_plugin_s
+ rand_plugin_s,
+ cipher_info,
+ hash_info
].
+-define(NEW_CIPHER_TYPE_SCHEMA,
+ {group, des_ede3_cbc},
+ {group, des_ede3_cfb},
+ {group, aes_128_cbc},
+ {group, aes_192_cbc},
+ {group, aes_256_cbc},
+ {group, aes_128_ctr},
+ {group, aes_192_ctr},
+ {group, aes_256_ctr},
+ {group, aes_128_ccm},
+ {group, aes_192_ccm},
+ {group, aes_256_ccm},
+ {group, aes_128_ecb},
+ {group, aes_192_ecb},
+ {group, aes_256_ecb},
+ {group, aes_128_gcm},
+ {group, aes_192_gcm},
+ {group, aes_256_gcm},
+ {group, des_ede3_cbc},
+ {group, des_ede3_cfb}
+ ).
+
+-define(RETIRED_TYPE_ALIASES,
+ {group, aes_cbc},
+ {group, aes_cbc128},
+ {group, aes_cbc256},
+ {group, aes_ccm},
+ {group, aes_ctr},
+ {group, aes_gcm},
+ {group, aes_ecb},
+ {group, des3_cfb},
+ {group, des3_cbc},
+ {group, des3_cbf},
+ {group, des_ede3}
+ ).
+
groups() ->
- [{non_fips, [], [{group, md4},
+ [{non_fips, [], [
+ {group, blake2b},
+ {group, blake2s},
+ {group, dss},
+ {group, ecdsa},
+ {group, ed25519},
+ {group, ed448},
+ {group, rsa},
+
+ {group, md4},
{group, md5},
{group, ripemd160},
- {group, sha},
{group, sha224},
{group, sha256},
{group, sha384},
+ {group, sha3_224},
+ {group, sha3_256},
+ {group, sha3_384},
+ {group, sha3_512},
{group, sha512},
- {group, rsa},
- {group, dss},
- {group, ecdsa},
+ {group, sha},
+ {group, poly1305},
+
{group, dh},
{group, ecdh},
{group, srp},
- {group, des_cbc},
- {group, des_cfb},
- {group, des3_cbc},
- {group, des3_cbf},
- {group, des3_cfb},
- {group, des_ede3},
+
+ {group, chacha20_poly1305},
+ {group, chacha20},
{group, blowfish_cbc},
- {group, blowfish_ecb},
{group, blowfish_cfb64},
+ {group, blowfish_ecb},
{group, blowfish_ofb64},
- {group, aes_cbc128},
- {group, aes_cfb8},
- {group, aes_cfb128},
- {group, aes_cbc256},
+
{group, aes_ige256},
+ {group, des_cbc},
+ {group, des_cfb},
{group, rc2_cbc},
{group, rc4},
- {group, aes_ctr},
- {group, aes_gcm},
- {group, chacha20_poly1305},
- {group, aes_cbc}]},
- {fips, [], [{group, no_md4},
+
+ ?NEW_CIPHER_TYPE_SCHEMA,
+ {group, aes_128_cfb128},
+ {group, aes_192_cfb128},
+ {group, aes_256_cfb128},
+ {group, aes_128_cfb8},
+ {group, aes_192_cfb8},
+ {group, aes_256_cfb8},
+ ?RETIRED_TYPE_ALIASES,
+ {group, aes_cfb128},
+ {group, aes_cfb8}
+ ]},
+ {fips, [], [
+ {group, no_blake2b},
+ {group, no_blake2s},
+ {group, dss},
+ {group, ecdsa},
+ {group, no_ed25519},
+ {group, no_ed448},
+ {group, rsa},
+
+ {group, no_md4},
{group, no_md5},
{group, no_ripemd160},
{group, sha},
@@ -85,91 +150,148 @@ groups() ->
{group, sha256},
{group, sha384},
{group, sha512},
- {group, rsa},
- {group, dss},
- {group, ecdsa},
+ {group, no_poly1305},
+
{group, dh},
{group, ecdh},
{group, no_srp},
- {group, no_des_cbc},
- {group, no_des_cfb},
- {group, des3_cbc},
- {group, des3_cbf},
- {group, des3_cfb},
- {group, des_ede3},
+
+ {group, no_chacha20_poly1305},
+ {group, no_chacha20},
{group, no_blowfish_cbc},
- {group, no_blowfish_ecb},
{group, no_blowfish_cfb64},
+ {group, no_blowfish_ecb},
{group, no_blowfish_ofb64},
- {group, aes_cbc128},
- {group, aes_cfb8},
- {group, aes_cfb128},
- {group, aes_cbc256},
+
+ {group, no_aes_cfb128},
+ {group, no_aes_cfb8},
{group, no_aes_ige256},
+ {group, no_des_cbc},
+ {group, no_des_cfb},
{group, no_rc2_cbc},
{group, no_rc4},
- {group, aes_ctr},
- {group, aes_gcm},
- {group, no_chacha20_poly1305},
- {group, aes_cbc}]},
- {md4, [], [hash]},
- {md5, [], [hash, hmac]},
- {ripemd160, [], [hash]},
- {sha, [], [hash, hmac]},
- {sha224, [], [hash, hmac]},
- {sha256, [], [hash, hmac]},
- {sha384, [], [hash, hmac]},
- {sha512, [], [hash, hmac]},
- {rsa, [], [sign_verify,
- public_encrypt,
- private_encrypt,
- generate
- ]},
- {dss, [], [sign_verify
- %% Does not work yet: ,public_encrypt, private_encrypt
- ]},
- {ecdsa, [], [sign_verify
- %% Does not work yet: ,public_encrypt, private_encrypt
- ]},
- {dh, [], [generate_compute]},
- {ecdh, [], [compute, generate]},
- {srp, [], [generate_compute]},
- {des_cbc, [], [block]},
- {des_cfb, [], [block]},
- {des3_cbc,[], [block]},
- {des_ede3,[], [block]},
- {des3_cbf,[], [block]},
- {des3_cfb,[], [block]},
- {rc2_cbc,[], [block]},
- {aes_cbc128,[], [block, cmac]},
- {aes_cfb8,[], [block]},
- {aes_cfb128,[], [block]},
- {aes_cbc256,[], [block, cmac]},
- {aes_ecb,[], [block]},
- {aes_ige256,[], [block]},
- {blowfish_cbc, [], [block]},
- {blowfish_ecb, [], [block]},
- {blowfish_cfb64, [], [block]},
- {blowfish_ofb64,[], [block]},
- {rc4, [], [stream]},
- {aes_ctr, [], [stream]},
- {aes_gcm, [], [aead]},
- {chacha20_poly1305, [], [aead]},
- {aes_cbc, [], [block]},
- {no_md4, [], [no_support, no_hash]},
- {no_md5, [], [no_support, no_hash, no_hmac]},
- {no_ripemd160, [], [no_support, no_hash]},
- {no_srp, [], [no_support, no_generate_compute]},
- {no_des_cbc, [], [no_support, no_block]},
- {no_des_cfb, [], [no_support, no_block]},
- {no_blowfish_cbc, [], [no_support, no_block]},
- {no_blowfish_ecb, [], [no_support, no_block]},
- {no_blowfish_cfb64, [], [no_support, no_block]},
- {no_blowfish_ofb64, [], [no_support, no_block]},
- {no_aes_ige256, [], [no_support, no_block]},
+
+ ?NEW_CIPHER_TYPE_SCHEMA,
+ ?RETIRED_TYPE_ALIASES
+ ]},
+
+ {md4, [], [hash]},
+ {md5, [], [hash, hmac]},
+ {ripemd160, [], [hash]},
+ {sha, [], [hash, hmac]},
+ {sha224, [], [hash, hmac]},
+ {sha256, [], [hash, hmac]},
+ {sha384, [], [hash, hmac]},
+ {sha512, [], [hash, hmac]},
+ {sha3_224, [], [hash, hmac]},
+ {sha3_256, [], [hash, hmac]},
+ {sha3_384, [], [hash, hmac]},
+ {sha3_512, [], [hash, hmac]},
+ {blake2b, [], [hash, hmac]},
+ {blake2s, [], [hash, hmac]},
+ {no_blake2b, [], [no_hash, no_hmac]},
+ {no_blake2s, [], [no_hash, no_hmac]},
+ {rsa, [], [sign_verify,
+ public_encrypt,
+ private_encrypt,
+ generate
+ ]},
+ {dss, [], [sign_verify
+ %% Does not work yet: ,public_encrypt, private_encrypt
+ ]},
+ {ecdsa, [], [sign_verify
+ %% Does not work yet: ,public_encrypt, private_encrypt
+ ]},
+ {ed25519, [], [sign_verify
+ %% Does not work yet: ,public_encrypt, private_encrypt
+ ]},
+ {ed448, [], [sign_verify
+ %% Does not work yet: ,public_encrypt, private_encrypt
+ ]},
+ {dh, [], [generate_compute, compute_bug]},
+ {ecdh, [], [use_all_elliptic_curves, compute, generate]},
+ {srp, [], [generate_compute]},
+ {des_cbc, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
+ {des_cfb, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
+ {des_ede3_cbc, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
+ {des_ede3_cfb, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
+ {rc2_cbc, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
+ {aes_cfb8, [], [block]},
+ {aes_128_cfb8, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
+ {aes_192_cfb8, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
+ {aes_256_cfb8, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
+ {no_aes_cfb8, [], [no_support, no_block]},
+ {aes_cfb128, [], [block]},
+ {aes_128_cfb128, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
+ {aes_192_cfb128, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
+ {aes_256_cfb128, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
+ {no_aes_cfb128, [], [no_support, no_block]},
+ {aes_ige256, [], [block]},
+ {no_aes_ige256, [], [no_support, no_block]},
+ {blowfish_cbc, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
+ {blowfish_ecb, [], [block, api_ng, api_ng_one_shot]},
+ {blowfish_cfb64, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
+ {blowfish_ofb64, [], [block, api_ng, api_ng_one_shot, api_ng_tls]},
+ {rc4, [], [stream, api_ng, api_ng_one_shot, api_ng_tls]},
+ {aes_ctr, [], [stream]},
+ {chacha20_poly1305, [], [aead]},
+ {chacha20, [], [stream, api_ng, api_ng_one_shot, api_ng_tls]},
+ {poly1305, [], [poly1305]},
+ {no_poly1305, [], [no_poly1305]},
+ {no_aes_cfb128, [], [no_support, no_block]},
+ {no_md4, [], [no_support, no_hash]},
+ {no_md5, [], [no_support, no_hash, no_hmac]},
+ {no_ed25519, [], [no_support, no_sign_verify
+ %% Does not work yet: ,public_encrypt, private_encrypt
+ ]},
+ {no_ed448, [], [no_support, no_sign_verify
+ %% Does not work yet: ,public_encrypt, private_encrypt
+ ]},
+ {no_ripemd160, [], [no_support, no_hash]},
+ {no_srp, [], [no_support, no_generate_compute]},
+ {no_des_cbc, [], [no_support, no_block]},
+ {no_des_cfb, [], [no_support, no_block]},
+ {no_blowfish_cbc, [], [no_support, no_block]},
+ {no_blowfish_ecb, [], [no_support, no_block]},
+ {no_blowfish_cfb64, [], [no_support, no_block]},
+ {no_blowfish_ofb64, [], [no_support, no_block]},
+ {no_aes_ige256, [], [no_support, no_block]},
{no_chacha20_poly1305, [], [no_support, no_aead]},
- {no_rc2_cbc, [], [no_support, no_block]},
- {no_rc4, [], [no_support, no_stream]}
+ {no_chacha20, [], [no_support, no_stream_ivec]},
+ {no_rc2_cbc, [], [no_support, no_block]},
+ {no_rc4, [], [no_support, no_stream]},
+ {api_errors, [], [api_errors_ecdh]},
+
+ %% New cipher nameing schema
+ {des_ede3_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls]},
+ {des_ede3_cfb, [], [api_ng, api_ng_one_shot, api_ng_tls]},
+ {aes_128_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls]},
+ {aes_192_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls]},
+ {aes_256_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls]},
+ {aes_128_ctr, [], [api_ng, api_ng_one_shot, api_ng_tls]},
+ {aes_192_ctr, [], [api_ng, api_ng_one_shot, api_ng_tls]},
+ {aes_256_ctr, [], [api_ng, api_ng_one_shot, api_ng_tls]},
+ {aes_128_ccm, [], [aead]},
+ {aes_192_ccm, [], [aead]},
+ {aes_256_ccm, [], [aead]},
+ {aes_128_ecb, [], [api_ng, api_ng_one_shot]},
+ {aes_192_ecb, [], [api_ng, api_ng_one_shot]},
+ {aes_256_ecb, [], [api_ng, api_ng_one_shot]},
+ {aes_128_gcm, [], [aead]},
+ {aes_192_gcm, [], [aead]},
+ {aes_256_gcm, [], [aead]},
+
+ %% Retired aliases
+ {aes_cbc, [], [block]},
+ {aes_cbc128, [], [block]},
+ {aes_cbc256, [], [block]},
+ {aes_ccm, [], [aead]},
+ {aes_ecb, [], [block]},
+ {aes_gcm, [], [aead]},
+ {des3_cbc, [], [block]},
+ {des_ede3, [], [block]},
+ {des3_cbf, [], [block]},
+ {des3_cfb, [], [block]}
].
%%-------------------------------------------------------------------
@@ -204,7 +326,7 @@ init_per_suite(Config) ->
Config
end
catch _:_ ->
- {skip, "Crypto did not start"}
+ {fail, "Crypto did not start"}
end.
end_per_suite(_Config) ->
@@ -222,7 +344,7 @@ init_per_group(fips, Config) ->
enabled = crypto:info_fips(),
FIPSConfig;
false ->
- {skip, "Failed to enable FIPS mode"}
+ {fail, "Failed to enable FIPS mode"}
end;
not_supported ->
{skip, "FIPS mode not supported"}
@@ -237,6 +359,8 @@ init_per_group(non_fips, Config) ->
_NotEnabled ->
NonFIPSConfig
end;
+init_per_group(api_errors, Config) ->
+ Config;
init_per_group(GroupName, Config) ->
case atom_to_list(GroupName) of
"no_" ++ TypeStr ->
@@ -260,12 +384,11 @@ end_per_group(_GroupName, Config) ->
init_per_testcase(info, Config) ->
Config;
init_per_testcase(cmac, Config) ->
- case crypto:info_lib() of
- [{<<"OpenSSL">>,LibVer,_}] when is_integer(LibVer), LibVer > 16#10001000 ->
+ case is_supported(cmac) of
+ true ->
Config;
- _Else ->
- % The CMAC functionality was introduced in OpenSSL 1.0.1
- {skip, "OpenSSL is too old"}
+ false ->
+ {skip, "CMAC is not supported"}
end;
init_per_testcase(generate, Config) ->
case proplists:get_value(type, Config) of
@@ -351,23 +474,33 @@ cmac(Config) when is_list(Config) ->
lists:foreach(fun cmac_check/1, Pairs),
lists:foreach(fun cmac_check/1, cmac_iolistify(Pairs)).
%%--------------------------------------------------------------------
+poly1305() ->
+ [{doc, "Test poly1305 function"}].
+poly1305(Config) ->
+ lists:foreach(
+ fun({Key, Txt, Expect}) ->
+ case crypto:poly1305(Key,Txt) of
+ Expect ->
+ ok;
+ Other ->
+ ct:fail({{crypto, poly1305, [Key, Txt]}, {expected, Expect}, {got, Other}})
+ end
+ end, proplists:get_value(poly1305, Config)).
+
+%%--------------------------------------------------------------------
+no_poly1305() ->
+ [{doc, "Test disabled poly1305 function"}].
+no_poly1305(_Config) ->
+ Key = <<133,214,190,120,87,85,109,51,127,68,82,254,66,213,6,168,1,
+ 3,128,138,251,13,178,253,74,191,246,175,65,73,245,27>>,
+ Txt = <<"Cryptographic Forum Research Group">>,
+ notsup(fun crypto:poly1305/2, [Key,Txt]).
+
+%%--------------------------------------------------------------------
block() ->
[{doc, "Test block ciphers"}].
block(Config) when is_list(Config) ->
- Fips = proplists:get_bool(fips, Config),
- Type = ?config(type, Config),
- %% See comment about EVP_CIPHER_CTX_set_key_length in
- %% block_crypt_nif in crypto.c.
- case {Fips, Type} of
- {true, aes_cfb8} ->
- throw({skip, "Cannot test aes_cfb8 in FIPS mode because of key length issue"});
- {true, aes_cfb128} ->
- throw({skip, "Cannot test aes_cfb128 in FIPS mode because of key length issue"});
- _ ->
- ok
- end,
-
- Blocks = lazy_eval(proplists:get_value(block, Config)),
+ [_|_] = Blocks = lazy_eval(proplists:get_value(cipher, Config)),
lists:foreach(fun block_cipher/1, Blocks),
lists:foreach(fun block_cipher/1, block_iolistify(Blocks)),
lists:foreach(fun block_cipher_increment/1, block_iolistify(Blocks)).
@@ -376,7 +509,7 @@ block(Config) when is_list(Config) ->
no_block() ->
[{doc, "Test disabled block ciphers"}].
no_block(Config) when is_list(Config) ->
- Blocks = lazy_eval(proplists:get_value(block, Config)),
+ [_|_] = Blocks = lazy_eval(proplists:get_value(cipher, Config)),
Args = case Blocks of
[{_Type, _Key, _PlainText} = A | _] ->
tuple_to_list(A);
@@ -389,20 +522,172 @@ no_block(Config) when is_list(Config) ->
notsup(fun crypto:block_encrypt/N, Args),
notsup(fun crypto:block_decrypt/N, Args).
%%--------------------------------------------------------------------
+api_ng() ->
+ [{doc, "Test new api"}].
+
+api_ng(Config) when is_list(Config) ->
+ [_|_] = Ciphers = lazy_eval(proplists:get_value(cipher, Config, [])),
+ lists:foreach(fun api_ng_cipher_increment/1, Ciphers).
+
+api_ng_cipher_increment({Type, Key, PlainTexts}=_X) ->
+ ct:log("~p",[_X]),
+ api_ng_cipher_increment({Type, Key, <<>>, PlainTexts});
+
+api_ng_cipher_increment({Type, Key, IV, PlainTexts}=_X) ->
+ ct:log("~p",[_X]),
+ api_ng_cipher_increment({Type, Key, IV, PlainTexts, undefined});
+
+api_ng_cipher_increment({Type, Key, IV, PlainText0, ExpectedEncText}=_X) ->
+ ct:log("~p",[_X]),
+ PlainTexts = iolistify(PlainText0),
+ RefEnc = crypto:crypto_init(Type, Key, IV, true),
+ RefDec = crypto:crypto_init(Type, Key, IV, false),
+ EncTexts = api_ng_cipher_increment_loop(RefEnc, PlainTexts),
+ Enc = iolist_to_binary(EncTexts),
+ case ExpectedEncText of
+ undefined ->
+ ok;
+ Enc ->
+ ok;
+ _ ->
+ ct:log("encode~nIn: ~p~nExpected: ~p~nEnc: ~p~n", [{Type,Key,IV,PlainTexts}, ExpectedEncText, Enc]),
+ ct:fail("api_ng_cipher_increment (encode)",[])
+ end,
+ Plain = iolist_to_binary(PlainTexts),
+ case iolist_to_binary(api_ng_cipher_increment_loop(RefDec, EncTexts)) of
+ Plain ->
+ ok;
+ OtherPT ->
+ ct:log("decode~nIn: ~p~nExpected: ~p~nDec: ~p~n", [{Type,Key,IV,EncTexts}, Plain, OtherPT]),
+ ct:fail("api_ng_cipher_increment (encode)",[])
+ end.
+
+
+api_ng_cipher_increment_loop(Ref, InTexts) ->
+ lists:map(fun(Txt) ->
+ try crypto:crypto_update(Ref, Txt)
+ of
+ Bin when is_binary(Bin) ->
+ Bin
+ catch
+ error:Error ->
+ ct:pal("Txt = ~p",[Txt]),
+ ct:fail("~p",[Error])
+ end
+ end, InTexts).
+
+%%--------------------------------------------------------------------
+api_ng_one_shot() ->
+ [{doc, "Test new api"}].
+
+api_ng_one_shot(Config) when is_list(Config) ->
+ [_|_] = Ciphers = lazy_eval(proplists:get_value(cipher, Config, [])),
+ lists:foreach(fun do_api_ng_one_shot/1, Ciphers).
+
+do_api_ng_one_shot({Type, Key, PlainTexts}=_X) ->
+ ct:log("~p",[_X]),
+ do_api_ng_one_shot({Type, Key, <<>>, PlainTexts});
+
+do_api_ng_one_shot({Type, Key, IV, PlainTexts}=_X) ->
+ ct:log("~p",[_X]),
+ do_api_ng_one_shot({Type, Key, IV, PlainTexts, undefined});
+
+do_api_ng_one_shot({Type, Key, IV, PlainText0, ExpectedEncText}=_X) ->
+ ct:log("~p",[_X]),
+ PlainText = iolist_to_binary(lazy_eval(PlainText0)),
+ EncTxt = crypto:crypto_one_time(Type, Key, IV, PlainText, true),
+ case ExpectedEncText of
+ undefined ->
+ ok;
+ EncTxt ->
+ ok;
+ _ ->
+ ct:log("encode~nIn: ~p~nExpected: ~p~nEnc: ~p~n", [{Type,Key,IV,PlainText}, ExpectedEncText, EncTxt]),
+ ct:fail("api_ng_one_time (encode)",[])
+ end,
+ case crypto:crypto_one_time(Type, Key, IV, EncTxt, false) of
+ PlainText ->
+ ok;
+ OtherPT ->
+ ct:log("decode~nIn: ~p~nExpected: ~p~nDec: ~p~n", [{Type,Key,IV,EncTxt}, PlainText, OtherPT]),
+ ct:fail("api_ng_one_time (decode)",[])
+ end.
+
+%%--------------------------------------------------------------------
+api_ng_tls() ->
+ [{doc, "Test special tls api"}].
+
+api_ng_tls(Config) when is_list(Config) ->
+ [_|_] = Ciphers = lazy_eval(proplists:get_value(cipher, Config, [])),
+ lists:foreach(fun do_api_ng_tls/1, Ciphers).
+
+
+do_api_ng_tls({Type, Key, PlainTexts}=_X) ->
+ ct:log("~p",[_X]),
+ do_api_ng_tls({Type, Key, <<>>, PlainTexts});
+
+do_api_ng_tls({Type, Key, IV, PlainTexts}=_X) ->
+ ct:log("~p",[_X]),
+ do_api_ng_tls({Type, Key, IV, PlainTexts, undefined});
+
+do_api_ng_tls({Type, Key, IV, PlainText0, ExpectedEncText}=_X) ->
+ ct:log("~p",[_X]),
+ PlainText = iolist_to_binary(lazy_eval(PlainText0)),
+ Renc = crypto:crypto_dyn_iv_init(Type, Key, true),
+ Rdec = crypto:crypto_dyn_iv_init(Type, Key, false),
+ EncTxt = crypto:crypto_dyn_iv_update(Renc, PlainText, IV),
+ case ExpectedEncText of
+ undefined ->
+ ok;
+ EncTxt ->
+ %% Now check that the state is NOT updated:
+ case crypto:crypto_dyn_iv_update(Renc, PlainText, IV) of
+ EncTxt ->
+ ok;
+ EncTxt2 ->
+ ct:log("2nd encode~nIn: ~p~nExpected: ~p~nEnc: ~p~n", [{Type,Key,IV,PlainText}, EncTxt, EncTxt2]),
+ ct:fail("api_ng_tls (second encode)",[])
+ end;
+ OtherEnc ->
+ ct:log("1st encode~nIn: ~p~nExpected: ~p~nEnc: ~p~n", [{Type,Key,IV,PlainText}, ExpectedEncText, OtherEnc]),
+ ct:fail("api_ng_tls (encode)",[])
+ end,
+ case crypto:crypto_dyn_iv_update(Rdec, EncTxt, IV) of
+ PlainText ->
+ %% Now check that the state is NOT updated:
+ case crypto:crypto_dyn_iv_update(Rdec, EncTxt, IV) of
+ PlainText ->
+ ok;
+ PlainText2 ->
+ ct:log("2nd decode~nIn: ~p~nExpected: ~p~nDec: ~p~n", [{Type,Key,IV,EncTxt}, PlainText, PlainText2]),
+ ct:fail("api_ng_tls (second decode)",[])
+ end;
+ OtherPT ->
+ ct:log("1st decode~nIn: ~p~nExpected: ~p~nDec: ~p~n", [{Type,Key,IV,EncTxt}, PlainText, OtherPT]),
+ ct:fail("api_ng_tlst (decode)",[])
+ end.
+
+%%--------------------------------------------------------------------
no_aead() ->
[{doc, "Test disabled aead ciphers"}].
no_aead(Config) when is_list(Config) ->
- [{Type, Key, PlainText, Nonce, AAD, CipherText, CipherTag} | _] =
- lazy_eval(proplists:get_value(aead, Config)),
- EncryptArgs = [Type, Key, Nonce, {AAD, PlainText}],
+ EncArg4 =
+ case lazy_eval(proplists:get_value(cipher, Config)) of
+ [{Type, Key, PlainText, Nonce, AAD, CipherText, CipherTag, TagLen, _Info} | _] ->
+ {AAD, PlainText, TagLen};
+ [{Type, Key, PlainText, Nonce, AAD, CipherText, CipherTag, _Info} | _] ->
+ {AAD, PlainText}
+ end,
+ EncryptArgs = [Type, Key, Nonce, EncArg4],
DecryptArgs = [Type, Key, Nonce, {AAD, CipherText, CipherTag}],
notsup(fun crypto:block_encrypt/4, EncryptArgs),
notsup(fun crypto:block_decrypt/4, DecryptArgs).
+
%%--------------------------------------------------------------------
stream() ->
[{doc, "Test stream ciphers"}].
stream(Config) when is_list(Config) ->
- Streams = lazy_eval(proplists:get_value(stream, Config)),
+ [_|_] = Streams = lazy_eval(proplists:get_value(cipher, Config)),
lists:foreach(fun stream_cipher/1, Streams),
lists:foreach(fun stream_cipher/1, stream_iolistify(Streams)),
@@ -415,11 +700,17 @@ no_stream(Config) when is_list(Config) ->
notsup(fun crypto:stream_init/2, [Type, <<"Key">>]).
%%--------------------------------------------------------------------
+no_stream_ivec() ->
+ [{doc, "Test disabled stream ciphers that uses ivec"}].
+no_stream_ivec(Config) when is_list(Config) ->
+ Type = ?config(type, Config),
+ notsup(fun crypto:stream_init/3, [Type, <<"Key">>, <<"Ivec">>]).
+
+%%--------------------------------------------------------------------
aead() ->
[{doc, "Test AEAD ciphers"}].
aead(Config) when is_list(Config) ->
- AEADs = lazy_eval(proplists:get_value(aead, Config)),
-
+ [_|_] = AEADs = lazy_eval(proplists:get_value(cipher, Config)),
FilteredAEADs =
case proplists:get_bool(fips, Config) of
false ->
@@ -432,7 +723,6 @@ aead(Config) when is_list(Config) ->
IVLen >= 12
end, AEADs)
end,
-
lists:foreach(fun aead_cipher/1, FilteredAEADs).
%%--------------------------------------------------------------------
@@ -442,18 +732,25 @@ sign_verify(Config) when is_list(Config) ->
SignVerify = proplists:get_value(sign_verify, Config),
lists:foreach(fun do_sign_verify/1, SignVerify).
+%%--------------------------------------------------------------------
+no_sign_verify() ->
+ [{doc, "Test disabled sign/verify digital signatures"}].
+no_sign_verify(Config) when is_list(Config) ->
+ [SignVerifyHd|_] = proplists:get_value(sign_verify, Config),
+ notsup(fun do_sign_verify/1, [SignVerifyHd]).
+
%%--------------------------------------------------------------------
public_encrypt() ->
[{doc, "Test public_encrypt/decrypt "}].
public_encrypt(Config) when is_list(Config) ->
- Params = proplists:get_value(pub_priv_encrypt, Config),
+ Params = proplists:get_value(pub_pub_encrypt, Config, []),
lists:foreach(fun do_public_encrypt/1, Params).
%%--------------------------------------------------------------------
private_encrypt() ->
[{doc, "Test private_encrypt/decrypt functions. "}].
private_encrypt(Config) when is_list(Config) ->
- Params = proplists:get_value(pub_priv_encrypt, Config),
+ Params = proplists:get_value(pub_priv_encrypt, Config, []),
lists:foreach(fun do_private_encrypt/1, Params).
%%--------------------------------------------------------------------
@@ -463,6 +760,24 @@ generate_compute(Config) when is_list(Config) ->
GenCom = proplists:get_value(generate_compute, Config),
lists:foreach(fun do_generate_compute/1, GenCom).
%%--------------------------------------------------------------------
+compute_bug() ->
+ [{doc, "Test that it works even if the Secret is smaller than expected"}].
+compute_bug(_Config) ->
+ ExpectedSecret = <<118,89,171,16,156,18,156,103,189,134,130,49,28,144,111,241,247,82,79,32,228,11,209,141,119,176,251,80,105,143,235,251,203,121,223,211,129,3,233,133,45,2,31,157,24,111,5,75,153,66,135,185,128,115,229,178,216,39,73,52,80,151,8,241,34,52,226,71,137,167,53,48,59,224,175,154,89,110,76,83,24,117,149,21,72,6,186,78,149,74,188,56,98,244,30,77,108,248,88,194,195,237,23,51,20,242,254,123,21,12,209,74,217,168,230,65,7,60,211,139,128,239,234,153,22,229,180,59,159,121,41,156,121,200,177,130,163,162,54,224,93,1,94,11,177,254,118,28,156,26,116,10,207,145,219,166,214,189,214,230,221,170,228,15,69,88,31,68,94,255,113,58,49,82,86,192,248,176,131,133,39,186,194,172,206,84,184,16,66,68,153,128,178,227,27,118,52,130,122,92,24,222,102,195,221,207,255,13,152,175,65,32,167,84,54,244,243,109,244,18,234,16,159,224,188,2,106,123,27,17,131,171,226,34,111,251,62,119,155,124,221,124,254,62,97,167,1,105,116,98,98,19,197,30,72,180,79,221,100,134,120,117,124,85,73,132,224,223,222,41,155,137,218,130,238,237,157,161,134,150,69,206,91,141,17,89,120,218,235,229,37,150,76,197,7,157,56,144,42,203,137,100,200,72,141,194,239,1,67,236,238,183,48,214,75,76,108,235,3,237,67,40,137,45,182,236,246,37,116,103,144,237,142,211,88,233,11,24,21,218,41,245,250,51,130,250,104,74,189,17,69,145,70,50,50,215,253,155,10,128,41,114,185,211,82,164,72,92,17,145,104,66,6,140,226,80,43,62,1,166,216,153,118,96,15,147,126,137,118,191,192,75,149,241,206,18,92,17,154,215,219,18,6,139,190,103,210,156,184,29,224,213,157,60,112,189,104,220,125,40,186,50,119,17,143,136,149,38,74,107,21,192,59,61,59,42,231,144,59,175,3,176,87,23,16,122,54,31,82,34,230,211,44,81,41,47,86,37,228,175,130,148,88,136,131,254,241,202,99,199,175,1,141,215,124,155,120,43,141,89,11,140,120,141,29,35,82,219,155,204,75,12,66,241,253,33,250,84,24,85,68,13,80,85,142,227,34,139,26,146,24>>,
+ OthersPublicKey = 635619632099733175381667940709387641100492974601603060984753028943194386334921787463327680809776598322996634648015962954045728174069768874873236397421720142610982770302060309928552098274817978606093380781524199673890631795310930242601197479471368910519338301177304682162189801040921618559902948819107531088646753320486728060005223263561551402855338732899079439899705951063999951507319258050864346087428042978411873495523439615429804957374639092580169417598963105885529553632847023899713490485619763926900318508906706745060947269748612049634207985438016935262521715769812475329234748426647554362991758104620357149045960316987533503707855364806010494793980069245562784050236811004893018183726397041999426883788660276453352521120006817370050691205529335316794439089316232980047277245051173281601960196573681285904611182521967067911862467395705665888521948321299521549941618586026714676885890192323289343756440666276226084448279082483536164085883288884231665240707495770544705648564889889198060417915693315346959170105413290799314390963124178046425737828369059171472978294050322371452255088799865552038756937873388385970088906560408959959429398326288750834357514847891423941047433478384621074116184703014798814515161475596555032391555842,
+ MyPrivateKey = 387759582879975726965038486537011291913744975764132199838375902680222019267527675651273586836110220500657652661706223760165097275862806031329642160439090779625708664007910974206651834216043397115514725827856461492311499129200688538220719685637154290305617686974719521885238198226075381217068175824097878445476010193039590876624464274744156624589136789060427283492343902761765833713520850870233407503430180028104167029073459918756981323130062648615262139444306321256382009848217866984408901761817655567071716275177768316006340055589170095799943481591033461616307776069027985761229636731465482676467627154100912586936231051371168178564599296638350391246393336702334311781595616786107810962134407697848002331639021101685320844880636050048769216986088652236979636019052557155807310341483407890060105599892252118584570558049301477535792498672552850760356632076013402382600669875697284264329434950712239302528367835155163504374877787288116104285944993818319105835423479332617802010952731990182088670508346704423006877514817882782443833997288652405892920173712497948376815825396272381214976859009518623799156300136570204539240675245115597412280078940442452936425561984312708387584800789375684525365060589104566195610526570099527133097201479,
+ P = 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024329058480379,
+ G = 2,
+ DHParameters = [P, G],
+ case crypto:compute_key(dh, OthersPublicKey, MyPrivateKey, DHParameters) of
+ ExpectedSecret ->
+ ok;
+ Others ->
+ ct:log("Got ~p",[Others]),
+ {fail, "crypto:compute_key(dh,...) failed for the bug test"}
+ end.
+
+%%--------------------------------------------------------------------
no_generate_compute() ->
[{doc, "Test crypto:genarate_key and crypto:compute_key "
"for disabled algorithms"}].
@@ -487,6 +802,45 @@ compute(Config) when is_list(Config) ->
Gen = proplists:get_value(compute, Config),
lists:foreach(fun do_compute/1, Gen).
%%--------------------------------------------------------------------
+use_all_elliptic_curves() ->
+ [{doc, " Test that all curves from crypto:ec_curves/0"}].
+use_all_elliptic_curves(_Config) ->
+ Msg = <<"hello world!">>,
+ Sups = crypto:supports(),
+ Curves = proplists:get_value(curves, Sups),
+ Hashs = proplists:get_value(hashs, Sups),
+ ct:log("Lib: ~p~nFIPS: ~p~nCurves:~n~p~nHashs: ~p", [crypto:info_lib(),
+ crypto:info_fips(),
+ Curves,
+ Hashs]),
+ Results =
+ [{{Curve,Hash},
+ try
+ {Pub,Priv} = crypto:generate_key(ecdh, Curve),
+ true = is_binary(Pub),
+ true = is_binary(Priv),
+ Sig = crypto:sign(ecdsa, Hash, Msg, [Priv, Curve]),
+ crypto:verify(ecdsa, Hash, Msg, Sig, [Pub, Curve])
+ catch
+ C:E ->
+ {C,E}
+ end}
+ || Curve <- Curves -- [ed25519, ed448, x25519, x448, ipsec3, ipsec4],
+ Hash <- Hashs -- [md4, md5, ripemd160, sha3_224, sha3_256, sha3_384, sha3_512, blake2b, blake2s]
+ ],
+ Fails =
+ lists:filter(fun({_,true}) -> false;
+ (_) -> true
+ end, Results),
+ case Fails of
+ [] ->
+ ok;
+ _ ->
+ ct:log("Fails:~n~p",[Fails]),
+ ct:fail("Bad curve(s)",[])
+ end.
+
+%%--------------------------------------------------------------------
generate() ->
[{doc, " Test crypto:generate_key"}].
generate(Config) when is_list(Config) ->
@@ -511,6 +865,25 @@ rand_uniform(Config) when is_list(Config) ->
10 = byte_size(crypto:strong_rand_bytes(10)).
%%--------------------------------------------------------------------
+rand_threads() ->
+ [{doc, "strong_rand_bytes in parallel threads"}].
+rand_threads(Config) when is_list(Config) ->
+ %% This will crash the emulator on at least one version of libcrypto
+ %% with buggy multithreading in RAND_bytes().
+ %% The test needs to run at least a few minutes...
+ NofThreads = 4,
+ Fun = fun F() -> crypto:strong_rand_bytes(16), F() end,
+ PidRefs = [spawn_monitor(Fun) || _ <- lists:seq(1, NofThreads)],
+%%% The test case takes too much time to run.
+%%% Keep it around for reference by setting it down to just 10 seconds.
+%%% receive after 10 * 60 * 1000 -> ok end, % 10 minutes
+ receive after 10 * 1000 -> ok end, % 10 seconds
+ spawn_link(fun () -> receive after 5000 -> exit(timeout) end end),
+ [exit(Pid, stop) || {Pid,_Ref} <- PidRefs],
+ [receive {'DOWN',Ref,_,_,stop} -> ok end || {_Pid,Ref} <- PidRefs],
+ ok.
+
+%%--------------------------------------------------------------------
rand_plugin() ->
[{doc, "crypto rand plugin testing (implicit state / process dictionary)"}].
rand_plugin(Config) when is_list(Config) ->
@@ -522,6 +895,41 @@ rand_plugin_s(Config) when is_list(Config) ->
rand_plugin_aux(explicit_state).
%%--------------------------------------------------------------------
+cipher_info() ->
+ [{doc, "crypto cipher_info testing"}].
+cipher_info(Config) when is_list(Config) ->
+ #{type := _,key_length := _,iv_length := _,
+ block_size := _,mode := _} = crypto:cipher_info(aes_128_cbc),
+ {'EXIT',_} = (catch crypto:cipher_info(not_a_cipher)),
+ case lists:foldl(fun(C,Ok) ->
+ try crypto:cipher_info(C)
+ of
+ _ -> Ok
+ catch Cls:Exc ->
+ ct:pal("~p:~p ~p",[Cls,Exc,C]),
+ false
+ end
+ end,
+ true,
+crypto:supports(ciphers)) of
+%% proplists:get_value(ciphers, crypto:supports())) of
+ true ->
+ ok;
+ false ->
+ ct:fail('Cipher unsupported',[])
+ end.
+
+
+%%--------------------------------------------------------------------
+hash_info() ->
+ [{doc, "crypto hash_info testing"}].
+hash_info(Config) when is_list(Config) ->
+ #{type := _,size := _,block_size := _} = crypto:hash_info(sha256),
+ {'EXIT',_} = (catch crypto:hash_info(not_a_hash)),
+ lists:foreach(fun(H) -> crypto:hash_info(H) end,
+ proplists:get_value(hashs, crypto:supports())).
+
+%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
hash(_, [], []) ->
@@ -552,31 +960,29 @@ hash_increment(State0, [Increment | Rest]) ->
hmac(_, [],[],[]) ->
ok;
hmac(sha = Type, [Key | Keys], [ <<"Test With Truncation">> = Data| Rest], [Expected | Expects]) ->
- case crypto:hmac(Type, Key, Data, 20) of
- Expected ->
- ok;
- Other ->
- ct:fail({{crypto, hmac, [Type, Key, Data]}, {expected, Expected}, {got, Other}})
- end,
+ call_crypto_hmac([Type, Key, Data, 20], Type, Expected),
hmac(Type, Keys, Rest, Expects);
-
hmac(Type, [Key | Keys], [ <<"Test With Truncation">> = Data| Rest], [Expected | Expects]) ->
- case crypto:hmac(Type, Key, Data, 16) of
- Expected ->
- ok;
- Other ->
- ct:fail({{crypto, hmac, [Type, Key, Data]}, {expected, Expected}, {got, Other}})
- end,
+ call_crypto_hmac([Type, Key, Data, 16], Type, Expected),
hmac(Type, Keys, Rest, Expects);
-
hmac(Type, [Key | Keys], [Data| Rest], [Expected | Expects]) ->
- case crypto:hmac(Type, Key, Data) of
+ call_crypto_hmac([Type, Key, Data], Type, Expected),
+ hmac(Type, Keys, Rest, Expects).
+
+call_crypto_hmac(Args, Type, Expected) ->
+ try apply(crypto, hmac, Args)
+ of
Expected ->
ok;
Other ->
- ct:fail({{crypto, hmac, [Type, Key, Data]}, {expected, Expected}, {got, Other}})
- end,
- hmac(Type, Keys, Rest, Expects).
+ ct:fail({{crypto,hmac,Args}, {expected,Expected}, {got,Other}})
+ catch
+ error:notsup ->
+ ct:fail("HMAC ~p not supported", [Type]);
+ Class:Cause ->
+ ct:fail({{crypto,hmac,Args}, {expected,Expected}, {got,{Class,Cause}}})
+ end.
+
hmac_increment(Type) ->
Key = hmac_key(Type),
@@ -613,6 +1019,7 @@ cmac_check({Type, Key, Text, Size, CMac}) ->
ct:fail({{crypto, cmac, [Type, Key, Text, Size]}, {expected, ExpCMac}, {got, Other}})
end.
+
block_cipher({Type, Key, PlainText}) ->
Plain = iolist_to_binary(PlainText),
CipherText = crypto:block_encrypt(Type, Key, PlainText),
@@ -648,13 +1055,27 @@ block_cipher({Type, Key, IV, PlainText, CipherText}) ->
ct:fail({{crypto, block_decrypt, [Type, Key, IV, CipherText]}, {expected, Plain}, {got, Other1}})
end.
-block_cipher_increment({Type, Key, IV, PlainTexts})
- when Type == des_cbc; Type == aes_cbc; Type == des3_cbc ->
+block_cipher_increment({Type, Key, IV, PlainTexts}) when Type == des_cbc ;
+ Type == des3_cbc ;
+ Type == aes_128_cbc ;
+ Type == aes_192_cbc ;
+ Type == aes_256_cbc
+ ->
block_cipher_increment(Type, Key, IV, IV, PlainTexts, iolist_to_binary(PlainTexts), []);
-block_cipher_increment({Type, Key, IV, PlainTexts, CipherText})
- when Type == des_cbc; Type == des3_cbc ->
+block_cipher_increment({Type, Key, IV, PlainTexts, CipherText}) when Type == des_cbc;
+ Type == des_ede3_cbc ;
+ Type == des3_cbc ;
+ Type == des_ede3 ;
+ Type == des_ede3_cfb ;
+ Type == des_ede3_cbf ;
+ Type == des3_cbf ;
+ Type == des3_cfb
+ ->
block_cipher_increment(Type, Key, IV, IV, PlainTexts, iolist_to_binary(PlainTexts), CipherText, []);
-block_cipher_increment({Type, Key, IV, PlainTexts, _CipherText}) when Type == aes_cbc ->
+block_cipher_increment({Type, Key, IV, PlainTexts, _CipherText}) when Type == aes_128_cbc ;
+ Type == aes_192_cbc ;
+ Type == aes_256_cbc
+ ->
Plain = iolist_to_binary(PlainTexts),
Blocks = [iolistify(Block) || << Block:128/bitstring >> <= Plain],
block_cipher_increment(Type, Key, IV, IV, Blocks, Plain, []);
@@ -688,35 +1109,60 @@ block_cipher_increment(Type, Key, IV0, IV, [PlainText | PlainTexts], Plain, Ciph
NextIV = crypto:next_iv(Type, CT),
block_cipher_increment(Type, Key, IV0, NextIV, PlainTexts, Plain, CipherText, [CT | Acc]).
-stream_cipher({Type, Key, PlainText}) ->
- Plain = iolist_to_binary(PlainText),
- State = crypto:stream_init(Type, Key),
- {_, CipherText} = crypto:stream_encrypt(State, PlainText),
- case crypto:stream_decrypt(State, CipherText) of
+stream_cipher({Type, Key, PlainText0}) ->
+ PlainText = lazy_eval(PlainText0),
+ Plain = iolist_to_binary(lazy_eval(PlainText)),
+ StateE = crypto:stream_init(Type, Key),
+ StateD = crypto:stream_init(Type, Key),
+ {_, CipherText} = crypto:stream_encrypt(StateE, PlainText),
+ case crypto:stream_decrypt(StateD, CipherText) of
{_, Plain} ->
ok;
Other ->
- ct:fail({{crypto, stream_decrypt, [State, CipherText]}, {expected, PlainText}, {got, Other}})
+ ct:fail({{crypto, stream_decrypt, [StateD, CipherText]}, {expected, PlainText}, {got, Other}})
end;
-stream_cipher({Type, Key, IV, PlainText}) ->
+stream_cipher({Type, Key, IV, PlainText0}) ->
+ PlainText = lazy_eval(PlainText0),
Plain = iolist_to_binary(PlainText),
- State = crypto:stream_init(Type, Key, IV),
- {_, CipherText} = crypto:stream_encrypt(State, PlainText),
- case crypto:stream_decrypt(State, CipherText) of
+ StateE = crypto:stream_init(Type, Key, IV),
+ StateD = crypto:stream_init(Type, Key, IV),
+ {_, CipherText} = crypto:stream_encrypt(StateE, PlainText),
+ case crypto:stream_decrypt(StateD, CipherText) of
{_, Plain} ->
ok;
Other ->
- ct:fail({{crypto, stream_decrypt, [State, CipherText]}, {expected, PlainText}, {got, Other}})
+ ct:fail({{crypto, stream_decrypt, [StateD, CipherText]}, {expected, PlainText}, {got, Other}})
+ end;
+stream_cipher({Type, Key, IV, PlainText0, CipherText}) ->
+ PlainText = lazy_eval(PlainText0),
+ Plain = iolist_to_binary(PlainText),
+ StateE = crypto:stream_init(Type, Key, IV),
+ StateD = crypto:stream_init(Type, Key, IV),
+ case crypto:stream_encrypt(StateE, PlainText) of
+ {_, CipherText} ->
+ ok;
+ {_, Other0} ->
+ ct:fail({{crypto, stream_encrypt, [StateE, Type, Key, IV, Plain]}, {expected, CipherText}, {got, Other0}})
+ end,
+ case crypto:stream_decrypt(StateD, CipherText) of
+ {_, Plain} ->
+ ok;
+ Other1 ->
+ ct:fail({{crypto, stream_decrypt, [StateD, CipherText]}, {expected, PlainText}, {got, Other1}})
end.
stream_cipher_incment({Type, Key, PlainTexts}) ->
- State = crypto:stream_init(Type, Key),
- stream_cipher_incment(State, State, PlainTexts, [], iolist_to_binary(PlainTexts));
+ StateE = crypto:stream_init(Type, Key),
+ StateD = crypto:stream_init(Type, Key),
+ stream_cipher_incment_loop(StateE, StateD, PlainTexts, [], iolist_to_binary(PlainTexts));
stream_cipher_incment({Type, Key, IV, PlainTexts}) ->
- State = crypto:stream_init(Type, Key, IV),
- stream_cipher_incment(State, State, PlainTexts, [], iolist_to_binary(PlainTexts)).
+ StateE = crypto:stream_init(Type, Key, IV),
+ StateD = crypto:stream_init(Type, Key, IV),
+ stream_cipher_incment_loop(StateE, StateD, PlainTexts, [], iolist_to_binary(PlainTexts));
+stream_cipher_incment({Type, Key, IV, PlainTexts, _CipherText}) ->
+ stream_cipher_incment({Type, Key, IV, PlainTexts}).
-stream_cipher_incment(_State, OrigState, [], Acc, Plain) ->
+stream_cipher_incment_loop(_State, OrigState, [], Acc, Plain) ->
CipherText = iolist_to_binary(lists:reverse(Acc)),
case crypto:stream_decrypt(OrigState, CipherText) of
{_, Plain} ->
@@ -724,40 +1170,92 @@ stream_cipher_incment(_State, OrigState, [], Acc, Plain) ->
Other ->
ct:fail({{crypto, stream_decrypt, [OrigState, CipherText]}, {expected, Plain}, {got, Other}})
end;
-stream_cipher_incment(State0, OrigState, [PlainText | PlainTexts], Acc, Plain) ->
+stream_cipher_incment_loop(State0, OrigState, [PlainText | PlainTexts], Acc, Plain) ->
{State, CipherText} = crypto:stream_encrypt(State0, PlainText),
- stream_cipher_incment(State, OrigState, PlainTexts, [CipherText | Acc], Plain).
+ stream_cipher_incment_loop(State, OrigState, PlainTexts, [CipherText | Acc], Plain).
-aead_cipher({Type, Key, PlainText, IV, AAD, CipherText, CipherTag}) ->
+aead_cipher({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, Info}) ->
Plain = iolist_to_binary(PlainText),
case crypto:block_encrypt(Type, Key, IV, {AAD, Plain}) of
{CipherText, CipherTag} ->
ok;
Other0 ->
- ct:fail({{crypto, block_encrypt, [Plain, PlainText]}, {expected, {CipherText, CipherTag}}, {got, Other0}})
+ ct:fail({{crypto,
+ block_encrypt,
+ [{info,Info}, {key,Key}, {pt,PlainText}, {iv,IV}, {aad,AAD}, {ct,CipherText}, {tag,CipherTag}]},
+ {expected, {CipherText, CipherTag}},
+ {got, Other0}})
end,
case crypto:block_decrypt(Type, Key, IV, {AAD, CipherText, CipherTag}) of
Plain ->
ok;
Other1 ->
- ct:fail({{crypto, block_decrypt, [CipherText]}, {expected, Plain}, {got, Other1}})
+ ct:fail({{crypto,
+ block_decrypt,
+ [{info,Info}, {key,Key}, {pt,PlainText}, {iv,IV}, {aad,AAD}, {ct,CipherText}, {tag,CipherTag}]},
+ {expected, Plain},
+ {got, Other1}})
end;
-aead_cipher({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, TagLen}) ->
+aead_cipher({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, TagLen, Info}) ->
<<TruncatedCipherTag:TagLen/binary, _/binary>> = CipherTag,
Plain = iolist_to_binary(PlainText),
- case crypto:block_encrypt(Type, Key, IV, {AAD, Plain, TagLen}) of
+ try crypto:block_encrypt(Type, Key, IV, {AAD, Plain, TagLen}) of
{CipherText, TruncatedCipherTag} ->
ok;
Other0 ->
- ct:fail({{crypto, block_encrypt, [Plain, PlainText]}, {expected, {CipherText, TruncatedCipherTag}}, {got, Other0}})
+ ct:fail({{crypto,
+ block_encrypt,
+ [{info,Info}, {key,Key}, {pt,PlainText}, {iv,IV}, {aad,AAD}, {ct,CipherText}, {tag,CipherTag}, {taglen,TagLen}]},
+ {expected, {CipherText, TruncatedCipherTag}},
+ {got, Other0}})
+ catch
+ error:E ->
+ ct:log("~p",[{Type, Key, PlainText, IV, AAD, CipherText, CipherTag, TagLen, Info}]),
+ try crypto:crypto_one_time_aead(Type, Key, IV, PlainText, AAD, TagLen, true)
+ of
+ RR ->
+ ct:log("Works: ~p",[RR])
+ catch
+ CC:EE ->
+ ct:log("~p:~p", [CC,EE])
+ end,
+ ct:fail("~p",[E])
end,
case crypto:block_decrypt(Type, Key, IV, {AAD, CipherText, TruncatedCipherTag}) of
Plain ->
ok;
Other1 ->
- ct:fail({{crypto, block_decrypt, [CipherText]}, {expected, Plain}, {got, Other1}})
+ ct:fail({{crypto,
+ block_decrypt,
+ [{info,Info}, {key,Key}, {pt,PlainText}, {iv,IV}, {aad,AAD}, {ct,CipherText}, {tag,CipherTag},
+ {truncated,TruncatedCipherTag}]},
+ {expected, Plain},
+ {got, Other1}})
end.
+do_sign_verify({Type, undefined=Hash, Private, Public, Msg, Signature}) ->
+ case crypto:sign(eddsa, Hash, Msg, [Private,Type]) of
+ Signature ->
+ ct:log("OK crypto:sign(eddsa, ~p, Msg, [Private,~p])", [Hash,Type]),
+ case crypto:verify(eddsa, Hash, Msg, Signature, [Public,Type]) of
+ true ->
+ ct:log("OK crypto:verify(eddsa, ~p, Msg, Signature, [Public,~p])", [Hash,Type]),
+ negative_verify(eddsa, Hash, Msg, <<10,20>>, [Public,Type]);
+ false ->
+ ct:log("ERROR crypto:verify(eddsa, ~p, Msg= ~p, Signature= ~p, [Public= ~p,~p])",
+ [Hash,Msg,Signature,Public,Type]),
+ ct:fail({{crypto, verify, [eddsa, Hash, Msg, Signature, [Public,Type]]}})
+ end;
+ ErrorSig ->
+ ct:log("ERROR crypto:sign(~p, ~p, ..., [Private= ~p,~p])", [eddsa,Hash,Private,Type]),
+ ct:log("ERROR crypto:verify(eddsa, ~p, Msg= ~p, [Public= ~p,~p])~n"
+ "ErrorSig = ~p~n"
+ "CorrectSig = ~p~n"
+ ,
+ [Hash,Msg,Public,Type,ErrorSig,Signature]),
+ ct:fail({{crypto, sign, [Type, Hash, Msg, ErrorSig, [Private]]}})
+ end;
+
do_sign_verify({Type, Hash, Public, Private, Msg}) ->
Signature = crypto:sign(Type, Hash, Msg, Private),
case crypto:verify(Type, Hash, Msg, Signature, Public) of
@@ -792,7 +1290,7 @@ do_sign_verify({Type, Hash, Public, Private, Msg, Options}) ->
error:notsup when NotSupLow == true,
is_integer(LibVer),
LibVer < 16#10001000 ->
- %% Thoose opts where introduced in 1.0.1
+ %% Those opts where introduced in 1.0.1
ct:log("notsup but OK in old cryptolib crypto:sign(~p, ~p, ..., ..., ..., ~p)",
[Type,Hash,Options]),
true;
@@ -818,25 +1316,48 @@ negative_verify(Type, Hash, Msg, Signature, Public, Options) ->
end.
do_public_encrypt({Type, Public, Private, Msg, Padding}) ->
- PublicEcn = (catch crypto:public_encrypt(Type, Msg, Public, Padding)),
- case crypto:private_decrypt(Type, PublicEcn, Private, Padding) of
- Msg ->
- ok;
- Other ->
- ct:fail({{crypto, private_decrypt, [Type, PublicEcn, Private, Padding]}, {expected, Msg}, {got, Other}})
+ try
+ crypto:public_encrypt(Type, Msg, Public, Padding)
+ of
+ PublicEcn ->
+ try
+ crypto:private_decrypt(Type, PublicEcn, Private, Padding)
+ of
+ Msg ->
+ ok;
+ Other ->
+ ct:fail({{crypto, private_decrypt, [Type, PublicEcn, Private, Padding]}, {expected, Msg}, {got, Other}})
+ catch
+ CC:EE ->
+ ct:fail({{crypto, private_decrypt, [Type, PublicEcn, Private, Padding]}, {expected, Msg}, {got, {CC,EE}}})
+ end
+ catch
+ CC:EE ->
+ ct:fail({{crypto, public_encrypt, [Type, Msg, Public, Padding]}, {got, {CC,EE}}})
end.
-do_private_encrypt({_Type, _Public, _Private, _Msg, rsa_pkcs1_oaep_padding}) ->
- ok; %% Not supported by openssl
+
do_private_encrypt({Type, Public, Private, Msg, Padding}) ->
- PrivEcn = (catch crypto:private_encrypt(Type, Msg, Private, Padding)),
- case crypto:public_decrypt(Type, PrivEcn, Public, Padding) of
- Msg ->
- ok;
- Other ->
- ct:fail({{crypto, public_decrypt, [Type, PrivEcn, Public, Padding]}, {expected, Msg}, {got, Other}})
+ try
+ crypto:private_encrypt(Type, Msg, Private, Padding)
+ of
+ PrivEcn ->
+ try
+ crypto:public_decrypt(Type, PrivEcn, Public, Padding)
+ of
+ Msg ->
+ ok;
+ Other ->
+ ct:fail({{crypto, public_decrypt, [Type, PrivEcn, Public, Padding]}, {expected, Msg}, {got, Other}})
+ catch
+ CC:EE ->
+ ct:fail({{crypto, public_decrypt, [Type, PrivEcn, Public, Padding]}, {expected, Msg}, {got, {CC,EE}}})
+ end
+ catch
+ CC:EE ->
+ ct:fail({{crypto, private_encrypt, [Type, Msg, Private, Padding]}, {got, {CC,EE}}})
end.
-
+
do_generate_compute({srp = Type, UserPrivate, UserGenParams, UserComParams,
HostPublic, HostPrivate, HostGenParams, HostComParam, SessionKey}) ->
{UserPublic, UserPrivate} = crypto:generate_key(Type, UserGenParams, UserPrivate),
@@ -905,6 +1426,8 @@ hexstr2bin(S) when is_binary(S) ->
hexstr2bin(S) ->
list_to_binary(hexstr2list(S)).
+hexstr2list([$ |T]) ->
+ hexstr2list(T);
hexstr2list([X,Y|T]) ->
[mkint(X)*16 + mkint(Y) | hexstr2list(T)];
hexstr2list([]) ->
@@ -916,6 +1439,14 @@ mkint(C) when $A =< C, C =< $F ->
mkint(C) when $a =< C, C =< $f ->
C - $a + 10.
+bin2hexstr(B) when is_binary(B) ->
+ io_lib:format("~.16b",[crypto:bytes_to_integer(B)]).
+
+decstr2int(S) when is_binary(S) ->
+ list_to_integer(binary:bin_to_list(S));
+decstr2int(S) ->
+ list_to_integer(S).
+
is_supported(Group) ->
lists:member(Group, lists:append([Algo || {_, Algo} <- crypto:supports()])).
@@ -934,17 +1465,18 @@ do_cmac_iolistify({Type, Key, Text, Size, CMac}) ->
do_stream_iolistify({Type, Key, PlainText}) ->
{Type, iolistify(Key), iolistify(PlainText)};
do_stream_iolistify({Type, Key, IV, PlainText}) ->
- {Type, iolistify(Key), IV, iolistify(PlainText)}.
-
-do_block_iolistify({des_cbc = Type, Key, IV, PlainText}) ->
- {Type, Key, IV, des_iolistify(PlainText)};
-do_block_iolistify({des3_cbc = Type, Key, IV, PlainText}) ->
- {Type, Key, IV, des_iolistify(PlainText)};
-do_block_iolistify({des3_cbf = Type, Key, IV, PlainText}) ->
- {Type, Key, IV, des_iolistify(PlainText)};
-do_block_iolistify({des3_cfb = Type, Key, IV, PlainText}) ->
- {Type, Key, IV, des_iolistify(PlainText)};
-do_block_iolistify({des_ede3 = Type, Key, IV, PlainText}) ->
+ {Type, iolistify(Key), IV, iolistify(PlainText)};
+do_stream_iolistify({Type, Key, IV, PlainText, CipherText}) ->
+ {Type, iolistify(Key), IV, iolistify(PlainText), CipherText}.
+do_block_iolistify({Type, Key, IV, PlainText}) when Type == des_cbc ;
+ Type == des_ede3_cbc ;
+ Type == des3_cbc ;
+ Type == des_ede3 ;
+ Type == des_ede3_cfb ;
+ Type == des_ede3_cbf ;
+ Type == des3_cbf ;
+ Type == des3_cfb
+ ->
{Type, Key, IV, des_iolistify(PlainText)};
do_block_iolistify({Type, Key, PlainText}) ->
{Type, iolistify(Key), iolistify(PlainText)};
@@ -953,10 +1485,13 @@ do_block_iolistify({Type, Key, IV, PlainText}) ->
do_block_iolistify({Type, Key, IV, PlainText, CipherText}) ->
{Type, iolistify(Key), IV, iolistify(PlainText), CipherText}.
-iolistify(<<"Test With Truncation">>)->
+iolistify(X) ->
+ iolistify1(lazy_eval(X)).
+
+iolistify1(<<"Test With Truncation">>)->
%% Do not iolistify as it spoils this special case
<<"Test With Truncation">>;
-iolistify(Msg) when is_binary(Msg) ->
+iolistify1(Msg) when is_binary(Msg) ->
Length = erlang:byte_size(Msg),
Split = Length div 2,
List0 = binary_to_list(Msg),
@@ -966,8 +1501,8 @@ iolistify(Msg) when is_binary(Msg) ->
{List1, List2}->
[List1, List2]
end;
-iolistify(Msg) ->
- iolistify(list_to_binary(Msg)).
+iolistify1(Msg) when is_list(Msg) ->
+ iolistify1(list_to_binary(Msg)).
des_iolistify(Msg) ->
des_iolist(erlang:byte_size(Msg) div 8, Msg, []).
@@ -1046,7 +1581,7 @@ rand_uniform_aux_test(N) ->
rand_uniform_aux_test(N-1).
crypto_rand_uniform(L,H) ->
- R1 = crypto:rand_uniform(L, H),
+ R1 = (L-1) + rand:uniform(H-L),
case (R1 >= L) and (R1 < H) of
true ->
ok;
@@ -1180,7 +1715,7 @@ group_config(sha224 = Type, Config) ->
Keys = rfc_4231_keys(),
Data = rfc_4231_msgs(),
Hmac = rfc4231_hmac_sha224(),
- [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config];
+ [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config];
group_config(sha256 = Type, Config) ->
Msgs = [rfc_4634_test1(), rfc_4634_test2_1(), long_msg()],
Digests = rfc_4634_sha256_digests() ++ [long_sha256_digest()],
@@ -1202,31 +1737,60 @@ group_config(sha512 = Type, Config) ->
Data = rfc_4231_msgs() ++ [long_msg()],
Hmac = rfc4231_hmac_sha512() ++ [long_hmac(sha512)],
[{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config];
-group_config(rsa = Type, Config) ->
+group_config(sha3_224 = Type, Config) ->
+ {Msgs,Digests} = sha3_test_vectors(Type),
+ [{hash, {Type, Msgs, Digests}}, {hmac, hmac_sha3(Type)} | Config];
+group_config(sha3_256 = Type, Config) ->
+ {Msgs,Digests} = sha3_test_vectors(Type),
+ [{hash, {Type, Msgs, Digests}}, {hmac, hmac_sha3(Type)} | Config];
+group_config(sha3_384 = Type, Config) ->
+ {Msgs,Digests} = sha3_test_vectors(Type),
+ [{hash, {Type, Msgs, Digests}}, {hmac, hmac_sha3(Type)} | Config];
+group_config(sha3_512 = Type, Config) ->
+ {Msgs,Digests} = sha3_test_vectors(Type),
+ [{hash, {Type, Msgs, Digests}}, {hmac, hmac_sha3(Type)} | Config];
+group_config(blake2b = Type, Config) ->
+ {Msgs, Digests} = blake2_test_vectors(Type),
+ [{hash, {Type, Msgs, Digests}}, {hmac, blake2_hmac(Type)} | Config];
+group_config(blake2s = Type, Config) ->
+ {Msgs, Digests} = blake2_test_vectors(Type),
+ [{hash, {Type, Msgs, Digests}}, {hmac, blake2_hmac(Type)} | Config];
+group_config(rsa, Config) ->
Msg = rsa_plain(),
Public = rsa_public(),
Private = rsa_private(),
PublicS = rsa_public_stronger(),
PrivateS = rsa_private_stronger(),
- SignVerify =
- case ?config(fips, Config) of
- true ->
- %% Use only the strong keys in FIPS mode
- sign_verify_tests(Type, Msg,
- PublicS, PrivateS,
- PublicS, PrivateS);
- false ->
- sign_verify_tests(Type, Msg,
- Public, Private,
- PublicS, PrivateS)
- end,
MsgPubEnc = <<"7896345786348 Asldi">>,
- PubPrivEnc = [{rsa, PublicS, PrivateS, MsgPubEnc, rsa_pkcs1_padding},
- rsa_oaep(),
- no_padding()
+ SignVerify_OptsToTry = [[{rsa_padding, rsa_x931_padding}],
+ [{rsa_padding, rsa_pkcs1_padding}],
+ [{rsa_padding, rsa_pkcs1_pss_padding}],
+ [{rsa_padding, rsa_pkcs1_pss_padding}, {rsa_pss_saltlen, -2}],
+ [{rsa_padding, rsa_pkcs1_pss_padding}, {rsa_pss_saltlen, 5}],
+ [{rsa_padding, rsa_pkcs1_pss_padding}, {rsa_mgf1_md,sha}],
+ [{rsa_padding, rsa_pkcs1_pss_padding}, {rsa_mgf1_md,sha}, {rsa_pss_saltlen, 5}]
+ ],
+ PrivEnc_OptsToTry = [rsa_pkcs1_padding, % Compatibility
+ [{rsa_pad, rsa_pkcs1_padding}], % Compatibility
+ [{rsa_padding, rsa_pkcs1_padding}],
+ [{rsa_padding,rsa_x931_padding}]
+ ],
+ PubEnc_OptsToTry = [rsa_pkcs1_padding, % Compatibility
+ [{rsa_pad, rsa_pkcs1_padding}], % Compatibility
+ [{rsa_padding, rsa_pkcs1_padding}],
+ [{rsa_padding,rsa_pkcs1_oaep_padding}],
+ [{rsa_padding,rsa_pkcs1_oaep_padding}, {rsa_oaep_label, <<"Hej hopp">>}],
+ [{rsa_padding,rsa_pkcs1_oaep_padding}, {rsa_oaep_md,sha}],
+ [{rsa_padding,rsa_pkcs1_oaep_padding}, {rsa_oaep_md,sha}, {rsa_oaep_label, <<"Hej hopp">>}],
+ [{rsa_padding,rsa_pkcs1_oaep_padding}, {rsa_mgf1_md,sha}],
+ [{rsa_padding,rsa_pkcs1_oaep_padding}, {rsa_mgf1_md,sha}, {rsa_oaep_label, <<"Hej hopp">>}],
+ [{rsa_padding,rsa_pkcs1_oaep_padding}, {rsa_mgf1_md,sha}, {rsa_oaep_md,sha}, {rsa_oaep_label, <<"Hej hopp">>}]
],
- Generate = [{rsa, 1024, 3}, {rsa, 2048, 17}, {rsa, 3072, 65537}],
- [{sign_verify, SignVerify}, {pub_priv_encrypt, PubPrivEnc}, {generate, Generate} | Config];
+ [{sign_verify, rsa_sign_verify_tests(Config, Msg, Public, Private, PublicS, PrivateS, SignVerify_OptsToTry)},
+ {pub_priv_encrypt, gen_rsa_pub_priv_tests(PublicS, PrivateS, MsgPubEnc, PrivEnc_OptsToTry)},
+ {pub_pub_encrypt, gen_rsa_pub_priv_tests(PublicS, PrivateS, MsgPubEnc, PubEnc_OptsToTry)},
+ {generate, [{rsa, 1024, 3}, {rsa, 2048, 17}, {rsa, 3072, 65537}]}
+ | Config];
group_config(dss = Type, Config) ->
Msg = dss_plain(),
Public = dss_params() ++ [dss_public()],
@@ -1247,7 +1811,6 @@ group_config(dss = Type, Config) ->
MsgPubEnc = <<"7896345786348 Asldi">>,
PubPrivEnc = [{dss, Public, Private, MsgPubEnc, []}],
[{sign_verify, SignVerify}, {pub_priv_encrypt, PubPrivEnc} | Config];
-
group_config(ecdsa = Type, Config) ->
{Private, Public} = ec_key_named(),
Msg = ec_msg(),
@@ -1259,9 +1822,13 @@ group_config(ecdsa = Type, Config) ->
MsgPubEnc = <<"7896345786348 Asldi">>,
PubPrivEnc = [{ecdsa, Public, Private, MsgPubEnc, []}],
[{sign_verify, SignVerify}, {pub_priv_encrypt, PubPrivEnc} | Config];
+group_config(Type, Config) when Type == ed25519 ; Type == ed448 ->
+ TestVectors = eddsa(Type),
+ [{sign_verify,TestVectors} | Config];
group_config(srp, Config) ->
GenerateCompute = [srp3(), srp6(), srp6a(), srp6a_smaller_prime()],
[{generate_compute, GenerateCompute} | Config];
+
group_config(ecdh, Config) ->
Compute = ecdh(),
Generate = ecc(),
@@ -1269,111 +1836,103 @@ group_config(ecdh, Config) ->
group_config(dh, Config) ->
GenerateCompute = [dh()],
[{generate_compute, GenerateCompute} | Config];
-group_config(des_cbc, Config) ->
- Block = des_cbc(),
- [{block, Block} | Config];
-group_config(des_cfb, Config) ->
- Block = des_cfb(),
- [{block, Block} | Config];
-group_config(des3_cbc, Config) ->
- Block = des3_cbc(),
- [{block, Block} | Config];
-group_config(des3_cbf, Config) ->
- Block = des3_cbf(),
- [{block, Block} | Config];
-group_config(des3_cfb, Config) ->
- Block = des3_cfb(),
- [{block, Block} | Config];
-group_config(des_ede3, Config) ->
- Block = des_ede3(),
- [{block, Block} | Config];
-group_config(rc2_cbc, Config) ->
- Block = rc2_cbc(),
- [{block, Block} | Config];
+
group_config(aes_cbc128 = Type, Config) ->
Block = fun() -> aes_cbc128(Config) end,
Pairs = fun() -> cmac_nist(Config, Type) end,
- [{block, Block}, {cmac, Pairs} | Config];
+ [{cipher, Block}, {cmac, Pairs} | Config];
group_config(aes_cbc256 = Type, Config) ->
Block = fun() -> aes_cbc256(Config) end,
Pairs = fun() -> cmac_nist(Config, Type) end,
- [{block, Block}, {cmac, Pairs} | Config];
-group_config(aes_ecb, Config) ->
- Block = fun() -> aes_ecb(Config) end,
- [{block, Block} | Config];
-group_config(aes_ige256, Config) ->
- Block = aes_ige256(),
- [{block, Block} | Config];
-group_config(aes_cfb8, Config) ->
- Block = fun() -> aes_cfb8(Config) end,
- [{block, Block} | Config];
-group_config(aes_cfb128, Config) ->
- Block = fun() -> aes_cfb128(Config) end,
- [{block, Block} | Config];
-group_config(blowfish_cbc, Config) ->
- Block = blowfish_cbc(),
- [{block, Block} | Config];
-group_config(blowfish_ecb, Config) ->
- Block = blowfish_ecb(),
- [{block, Block} | Config];
-group_config(blowfish_cfb64, Config) ->
- Block = blowfish_cfb64(),
- [{block, Block} | Config];
-group_config(blowfish_ofb64, Config) ->
- Block = blowfish_ofb64(),
- [{block, Block} | Config];
-group_config(rc4, Config) ->
- Stream = rc4(),
- [{stream, Stream} | Config];
-group_config(aes_ctr, Config) ->
- Stream = aes_ctr(),
- [{stream, Stream} | Config];
-group_config(aes_gcm, Config) ->
- AEAD = fun() -> aes_gcm(Config) end,
- [{aead, AEAD} | Config];
+ [{cipher, Block}, {cmac, Pairs} | Config];
group_config(chacha20_poly1305, Config) ->
- AEAD = chacha20_poly1305(),
- [{aead, AEAD} | Config];
-group_config(aes_cbc, Config) ->
- Block = aes_cbc(Config),
- [{block, Block} | Config];
-group_config(_, Config) ->
- Config.
+ AEAD = chacha20_poly1305(Config),
+ [{cipher, AEAD} | Config];
+
+group_config(poly1305, Config) ->
+ V = [%% {Key, Txt, Expect}
+ {%% RFC7539 2.5.2
+ crypto_SUITE:hexstr2bin("85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b"),
+ <<"Cryptographic Forum Research Group">>,
+ crypto_SUITE:hexstr2bin("a8061dc1305136c6c22b8baf0c0127a9")
+ }
+ ],
+ [{poly1305,V} | Config];
-sign_verify_tests(Type, Msg, Public, Private, PublicS, PrivateS) ->
- gen_sign_verify_tests(Type, [md5, ripemd160, sha, sha224, sha256], Msg, Public, Private,
- [undefined,
- [{rsa_padding, rsa_pkcs1_pss_padding}],
- [{rsa_padding, rsa_pkcs1_pss_padding}, {rsa_pss_saltlen, 0}],
- [{rsa_padding, rsa_x931_padding}]
- ]) ++
- gen_sign_verify_tests(Type, [sha384, sha512], Msg, PublicS, PrivateS,
- [undefined,
- [{rsa_padding, rsa_pkcs1_pss_padding}],
- [{rsa_padding, rsa_pkcs1_pss_padding}, {rsa_pss_saltlen, 0}],
- [{rsa_padding, rsa_x931_padding}]
- ]).
-
-gen_sign_verify_tests(Type, Hashs, Msg, Public, Private, Opts) ->
+group_config(F, Config) ->
+ TestVectors = fun() -> ?MODULE:F(Config) end,
+ [{cipher, TestVectors} | Config].
+
+
+
+rsa_sign_verify_tests(Config, Msg, Public, Private, PublicS, PrivateS, OptsToTry) ->
+ case ?config(fips, Config) of
+ true ->
+ %% Use only the strong keys in FIPS mode
+ rsa_sign_verify_tests(Msg,
+ PublicS, PrivateS,
+ PublicS, PrivateS,
+ OptsToTry);
+ false ->
+ rsa_sign_verify_tests(Msg,
+ Public, Private,
+ PublicS, PrivateS,
+ OptsToTry)
+ end.
+
+rsa_sign_verify_tests(Msg, Public, Private, PublicS, PrivateS, OptsToTry) ->
+ gen_rsa_sign_verify_tests([md5, ripemd160, sha, sha224, sha256], Msg, Public, Private,
+ [undefined | OptsToTry]) ++
+ gen_rsa_sign_verify_tests([sha384, sha512], Msg, PublicS, PrivateS,
+ [undefined | OptsToTry]).
+
+gen_rsa_sign_verify_tests(Hashs, Msg, Public, Private, Opts) ->
+ SupOpts = proplists:get_value(rsa_opts, crypto:supports(), []),
lists:foldr(fun(Hash, Acc0) ->
case is_supported(Hash) of
true ->
lists:foldr(fun
(undefined, Acc1) ->
- [{Type, Hash, Public, Private, Msg} | Acc1];
+ [{rsa, Hash, Public, Private, Msg} | Acc1];
([{rsa_padding, rsa_x931_padding} | _], Acc1)
when Hash =:= md5
orelse Hash =:= ripemd160
orelse Hash =:= sha224 ->
Acc1;
(Opt, Acc1) ->
- [{Type, Hash, Public, Private, Msg, Opt} | Acc1]
+ case rsa_opt_is_supported(Opt, SupOpts) of
+ true ->
+ [{rsa, Hash, Public, Private, Msg, Opt} | Acc1];
+ false ->
+ Acc1
+ end
end, Acc0, Opts);
false ->
Acc0
end
end, [], Hashs).
+
+gen_rsa_pub_priv_tests(Public, Private, Msg, OptsToTry) ->
+ SupOpts = proplists:get_value(rsa_opts, crypto:supports(), []),
+ lists:foldr(fun(Opt, Acc) ->
+ case rsa_opt_is_supported(Opt, SupOpts) of
+ true ->
+ [{rsa, Public, Private, Msg, Opt} | Acc];
+ false ->
+ Acc
+ end
+ end, [], OptsToTry).
+
+
+rsa_opt_is_supported([_|_]=Opt, Sup) ->
+ lists:all(fun(O) -> rsa_opt_is_supported(O,Sup) end, Opt);
+rsa_opt_is_supported({A,B}, Sup) ->
+ rsa_opt_is_supported(A,Sup) orelse rsa_opt_is_supported(B,Sup);
+rsa_opt_is_supported(Opt, Sup) ->
+ lists:member(Opt, Sup).
+
+
rfc_1321_msgs() ->
[<<"">>,
<<"a">>,
@@ -1402,6 +1961,225 @@ rfc_1321_md5_digests() ->
hexstr2bin("d174ab98d277d9f5a5611c2c9f419d9f"),
hexstr2bin("57edf4a22be3c955ac49da2e2107b67a")].
+
+%% BLAKE2 re-use SHA3 test vectors.
+blake2_test_vectors(blake2b) ->
+ {sha3_msgs(),
+ [ <<186,128,165,63,152,28,77,13,106,39,151,182,159,18,246,233,76,33,47,20,104,90,196,183,75,18,187,111,219,255,162,209,125,135,197,57,42,171,121,45,194,82,213,222,69,51,204,149,24,211,138,168,219,241,146,90,185,35,134,237,212,0,153,35>>
+ , <<120,106,2,247,66,1,89,3,198,198,253,133,37,82,210,114,145,47,71,64,225,88,71,97,138,134,226,23,247,31,84,25,210,94,16,49,175,238,88,83,19,137,100,68,147,78,176,75,144,58,104,91,20,72,183,85,213,111,112,26,254,155,226,206>>
+ , <<114,133,255,62,139,215,104,214,155,230,43,59,241,135,101,163,37,145,127,169,116,74,194,245,130,162,8,80,188,43,17,65,237,27,62,69,40,89,90,204,144,119,43,223,45,55,220,138,71,19,11,68,243,58,2,232,115,14,90,216,225,102,232,136>>
+ , <<206,116,26,197,147,15,227,70,129,17,117,197,34,123,183,191,205,71,244,38,18,250,228,108,8,9,81,79,158,14,58,17,238,23,115,40,113,71,205,234,238,223,245,7,9,170,113,99,65,254,101,36,15,74,214,119,125,107,250,249,114,110,94,82>>
+ , <<152,251,62,251,114,6,253,25,235,246,155,111,49,44,247,182,78,59,148,219,225,161,113,7,145,57,117,167,147,241,119,225,208,119,96,157,127,186,54,60,187,160,13,5,247,170,78,79,168,113,93,100,40,16,76,10,117,100,59,15,243,253,62,175>>
+ ]};
+blake2_test_vectors(blake2s) ->
+ {sha3_msgs(),
+ [ <<80,140,94,140,50,124,20,226,225,167,43,163,78,235,69,47,55,69,139,32,158,214,58,41,77,153,155,76,134,103,89,130>>
+ , <<105,33,122,48,121,144,128,148,225,17,33,208,66,53,74,124,31,85,182,72,44,161,165,30,27,37,13,253,30,208,238,249>>
+ , <<111,77,245,17,106,111,51,46,218,177,217,225,14,232,125,246,85,123,234,182,37,157,118,99,243,188,213,114,44,19,241,137>>
+ , <<53,141,210,237,7,128,212,5,78,118,203,111,58,91,206,40,65,232,226,245,71,67,29,77,9,219,33,182,109,148,31,199>>
+ , <<190,192,192,230,205,229,182,122,203,115,184,31,121,166,122,64,121,174,28,96,218,201,210,102,26,241,142,159,139,80,223,165>>
+ ]}.
+
+blake2_hmac(Type) ->
+ {Ks, Ds, Hs} = lists:unzip3(
+ [ {hexstr2bin(K), hexstr2bin(D), H}
+ || {{K, D}, H} <- lists:zip(blake2_hmac_key_data(), blake2_hmac_hmac(Type)) ]),
+ {Type, Ks, Ds, Hs}.
+
+blake2_hmac_key_data() ->
+ [ {"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b 0b0b0b0b",
+ "4869205468657265"}
+ , {"4a656665",
+ "7768617420646f2079612077616e7420 666f72206e6f7468696e673f"}
+ , {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaa",
+ "dddddddddddddddddddddddddddddddd dddddddddddddddddddddddddddddddd dddddddddddddddddddddddddddddddd dddd"}
+ , {"0102030405060708090a0b0c0d0e0f10 111213141516171819",
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd cdcd"}
+ , {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaa",
+ "54657374205573696e67204c61726765 72205468616e20426c6f636b2d53697a 65204b6579202d2048617368204b6579 204669727374"}
+ , {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaa",
+ "54657374205573696e67204c61726765 72205468616e20426c6f636b2d53697a 65204b6579202d2048617368204b6579 204669727374"}
+ , {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaa",
+ "54686973206973206120746573742075 73696e672061206c6172676572207468 616e20626c6f636b2d73697a65206b65 7920616e642061206c61726765722074 68616e20626c6f636b2d73697a652064 6174612e20546865206b6579206e6565 647320746f2062652068617368656420 6265666f7265206265696e6720757365 642062792074686520484d414320616c 676f726974686d2e"}
+ , {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaa",
+ "54686973206973206120746573742075 73696e672061206c6172676572207468 616e20626c6f636b2d73697a65206b65 7920616e642061206c61726765722074 68616e20626c6f636b2d73697a652064 6174612e20546865206b6579206e6565 647320746f2062652068617368656420 6265666f7265206265696e6720757365 642062792074686520484d414320616c 676f726974686d2e"}
+ ].
+
+blake2_hmac_hmac(blake2b) ->
+ [ <<53,138,106,24,73,36,137,79,195,75,238,86,128,238,223,87,216,74,55,187,56,131,47,40,142,59,39,220,99,169,140,200,201,30,118,218,71,107,80,139,198,178,212,8,162,72,133,116,82,144,110,74,32,180,140,107,75,85,210,223,15,225,221,36>>
+ , <<111,248,132,248,221,194,166,88,107,60,152,164,205,110,189,241,78,193,2,4,182,113,0,115,235,88,101,173,227,122,38,67,184,128,124,19,53,209,7,236,219,159,254,174,182,130,140,70,37,186,23,44,102,55,158,252,210,34,194,222,17,114,122,180>>
+ , <<244,59,198,44,122,153,53,60,59,44,96,232,239,36,251,189,66,233,84,120,102,220,156,91,228,237,198,244,167,212,188,10,198,32,194,198,0,52,208,64,240,219,175,134,249,233,205,120,145,160,149,89,94,237,85,226,169,150,33,95,12,21,192,24>>
+ , <<229,219,182,222,47,238,66,161,202,160,110,78,123,132,206,64,143,250,92,74,157,226,99,46,202,118,156,222,136,117,1,76,114,208,114,15,234,245,63,118,230,161,128,53,127,82,141,123,244,132,250,58,20,232,204,31,15,59,173,167,23,180,52,145>>
+ , <<165,75,41,67,178,162,2,39,212,28,164,108,9,69,175,9,188,31,174,251,47,73,137,76,35,174,188,85,127,183,156,72,137,220,167,68,8,220,134,80,134,102,122,237,238,74,49,133,197,58,73,200,11,129,76,76,88,19,234,12,139,56,168,248>>
+ , <<180,214,140,139,182,82,151,170,52,132,168,110,29,51,183,138,70,159,33,234,170,158,212,218,159,236,145,218,71,23,34,61,44,15,163,134,170,47,209,241,255,207,89,23,178,103,84,96,53,237,48,238,164,178,19,162,133,148,211,211,169,179,140,170>>
+ , <<171,52,121,128,166,75,94,130,93,209,14,125,50,253,67,160,26,142,109,234,38,122,185,173,125,145,53,36,82,102,24,146,83,17,175,188,176,196,149,25,203,235,221,112,149,64,168,215,37,251,145,26,194,174,233,178,163,170,67,215,150,18,51,147>>
+ , <<97,220,242,140,166,12,169,92,130,89,147,39,171,215,169,161,152,111,242,219,211,199,73,69,198,227,35,186,203,76,159,26,94,103,82,93,20,186,141,98,36,177,98,229,102,23,21,37,83,3,69,169,178,86,8,178,125,251,163,180,146,115,213,6>>
+ ];
+blake2_hmac_hmac(blake2s) ->
+ [ <<101,168,183,197,204,145,54,212,36,232,44,55,226,112,126,116,233,19,192,101,91,153,199,95,64,237,243,135,69,58,50,96>>
+ , <<144,182,40,30,47,48,56,201,5,106,240,180,167,231,99,202,230,254,93,158,180,56,106,14,201,82,55,137,12,16,79,240>>
+ , <<252,196,245,149,41,80,46,52,195,216,218,63,253,171,130,150,106,44,182,55,255,94,155,215,1,19,92,46,148,105,231,144>>
+ , <<70,68,52,220,190,206,9,93,69,106,29,98,214,236,86,248,152,230,37,163,158,92,82,189,249,77,175,17,27,173,131,170>>
+ , <<210,61,121,57,79,83,213,54,160,150,230,81,68,71,238,170,187,5,222,208,27,227,44,25,55,218,106,143,113,3,188,78>>
+ , <<92,76,83,46,110,69,89,83,133,78,21,16,149,38,110,224,127,213,88,129,190,223,139,57,8,217,95,13,190,54,159,234>>
+ , <<203,96,246,167,145,241,64,191,138,162,229,31,243,88,205,178,204,92,3,51,4,91,127,183,122,186,122,179,176,207,178,55>>
+ , <<190,53,233,217,99,171,215,108,1,184,171,181,22,36,240,209,16,96,16,92,213,22,16,58,114,241,117,214,211,189,30,202>>
+ ].
+
+%%% https://www.di-mgt.com.au/sha_testvectors.html
+sha3_msgs() ->
+ ["abc",
+ "",
+ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", % length 448 bits
+ "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", % length 896 bits
+ lists:duplicate(1000000,$a)
+ ].
+
+sha3_test_vectors(sha3_224) ->
+ {sha3_msgs(),
+ [hexstr2bin("e642824c3f8cf24a d09234ee7d3c766f c9a3a5168d0c94ad 73b46fdf"),
+ hexstr2bin("6b4e03423667dbb7 3b6e15454f0eb1ab d4597f9a1b078e3f 5b5a6bc7"),
+ hexstr2bin("8a24108b154ada21 c9fd5574494479ba 5c7e7ab76ef264ea d0fcce33"),
+ hexstr2bin("543e6868e1666c1a 643630df77367ae5 a62a85070a51c14c bf665cbc"),
+ hexstr2bin("d69335b93325192e 516a912e6d19a15c b51c6ed5c15243e7 a7fd653c")
+ ]
+ };
+sha3_test_vectors(sha3_256) ->
+ {sha3_msgs(),
+ [hexstr2bin("3a985da74fe225b2 045c172d6bd390bd 855f086e3e9d525b 46bfe24511431532"),
+ hexstr2bin("a7ffc6f8bf1ed766 51c14756a061d662 f580ff4de43b49fa 82d80a4b80f8434a"),
+ hexstr2bin("41c0dba2a9d62408 49100376a8235e2c 82e1b9998a999e21 db32dd97496d3376"),
+ hexstr2bin("916f6061fe879741 ca6469b43971dfdb 28b1a32dc36cb325 4e812be27aad1d18"),
+ hexstr2bin("5c8875ae474a3634 ba4fd55ec85bffd6 61f32aca75c6d699 d0cdcb6c115891c1")
+ ]
+ };
+sha3_test_vectors(sha3_384) ->
+ {sha3_msgs(),
+ [hexstr2bin("ec01498288516fc9 26459f58e2c6ad8d f9b473cb0fc08c25 96da7cf0e49be4b2 98d88cea927ac7f5 39f1edf228376d25"),
+ hexstr2bin("0c63a75b845e4f7d 01107d852e4c2485 c51a50aaaa94fc61 995e71bbee983a2a c3713831264adb47 fb6bd1e058d5f004"),
+ hexstr2bin("991c665755eb3a4b 6bbdfb75c78a492e 8c56a22c5c4d7e42 9bfdbc32b9d4ad5a a04a1f076e62fea1 9eef51acd0657c22"),
+ hexstr2bin("79407d3b5916b59c 3e30b09822974791 c313fb9ecc849e40 6f23592d04f625dc 8c709b98b43b3852 b337216179aa7fc7"),
+ hexstr2bin("eee9e24d78c18553 37983451df97c8ad 9eedf256c6334f8e 948d252d5e0e7684 7aa0774ddb90a842 190d2c558b4b8340")
+ ]
+ };
+sha3_test_vectors(sha3_512) ->
+ {sha3_msgs(),
+ [hexstr2bin("b751850b1a57168a 5693cd924b6b096e 08f621827444f70d 884f5d0240d2712e 10e116e9192af3c9 1a7ec57647e39340 57340b4cf408d5a5 6592f8274eec53f0"),
+ hexstr2bin("a69f73cca23a9ac5 c8b567dc185a756e 97c982164fe25859 e0d1dcc1475c80a6 15b2123af1f5f94c 11e3e9402c3ac558 f500199d95b6d3e3 01758586281dcd26"),
+ hexstr2bin("04a371e84ecfb5b8 b77cb48610fca818 2dd457ce6f326a0f d3d7ec2f1e91636d ee691fbe0c985302 ba1b0d8dc78c0863 46b533b49c030d99 a27daf1139d6e75e"),
+ hexstr2bin("afebb2ef542e6579 c50cad06d2e578f9 f8dd6881d7dc824d 26360feebf18a4fa 73e3261122948efc fd492e74e82e2189 ed0fb440d187f382 270cb455f21dd185"),
+ hexstr2bin("3c3a876da14034ab 60627c077bb98f7e 120a2a5370212dff b3385a18d4f38859 ed311d0a9d5141ce 9cc5c66ee689b266 a8aa18ace8282a0e 0db596c90b0a7b87")
+ ]
+ }.
+
+
+
+%%% http://www.wolfgang-ehrhardt.de/hmac-sha3-testvectors.html
+
+hmac_sha3(Type) ->
+ N = case Type of
+ sha3_224 -> 1;
+ sha3_256 -> 2;
+ sha3_384 -> 3;
+ sha3_512 -> 4
+ end,
+ {Keys, Datas, Hmacs} =
+ lists:unzip3(
+ [{hexstr2bin(Key), hexstr2bin(Data), hexstr2bin(element(N,Hmacs))}
+ || {Key,Data,Hmacs} <- hmac_sha3_data()]),
+ {Type, Keys, Datas, Hmacs}.
+
+
+hmac_sha3_data() ->
+ [
+ {"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b 0b0b0b0b",
+ "4869205468657265",
+ {"3b16546bbc7be2706a031dcafd56373d 9884367641d8c59af3c860f7",
+ "ba85192310dffa96e2a3a40e69774351 140bb7185e1202cdcc917589f95e16bb",
+ "68d2dcf7fd4ddd0a2240c8a437305f61 fb7334cfb5d0226e1bc27dc10a2e723a 20d370b47743130e26ac7e3d532886bd",
+ "eb3fbd4b2eaab8f5c504bd3a41465aac ec15770a7cabac531e482f860b5ec7ba 47ccb2c6f2afce8f88d22b6dc61380f2 3a668fd3888bb80537c0a0b86407689e"
+ }},
+
+ {"4a656665",
+ "7768617420646f2079612077616e7420 666f72206e6f7468696e673f",
+ {"7fdb8dd88bd2f60d1b798634ad386811 c2cfc85bfaf5d52bbace5e66",
+ "c7d4072e788877ae3596bbb0da73b887 c9171f93095b294ae857fbe2645e1ba5",
+ "f1101f8cbf9766fd6764d2ed61903f21 ca9b18f57cf3e1a23ca13508a93243ce 48c045dc007f26a21b3f5e0e9df4c20a",
+ "5a4bfeab6166427c7a3647b747292b83 84537cdb89afb3bf5665e4c5e709350b 287baec921fd7ca0ee7a0c31d022a95e 1fc92ba9d77df883960275beb4e62024"
+ }},
+
+ {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaa",
+ "dddddddddddddddddddddddddddddddd dddddddddddddddddddddddddddddddd dddddddddddddddddddddddddddddddd dddd",
+ {"676cfc7d16153638780390692be142d2 df7ce924b909c0c08dbfdc1a",
+ "84ec79124a27107865cedd8bd82da996 5e5ed8c37b0ac98005a7f39ed58a4207",
+ "275cd0e661bb8b151c64d288f1f782fb 91a8abd56858d72babb2d476f0458373 b41b6ab5bf174bec422e53fc3135ac6e",
+ "309e99f9ec075ec6c6d475eda1180687 fcf1531195802a99b5677449a8625182 851cb332afb6a89c411325fbcbcd42af cb7b6e5aab7ea42c660f97fd8584bf03"
+ }},
+
+ {"0102030405060708090a0b0c0d0e0f10 111213141516171819",
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd cdcd",
+ {"a9d7685a19c4e0dbd9df2556cc8a7d2a 7733b67625ce594c78270eeb",
+ "57366a45e2305321a4bc5aa5fe2ef8a9 21f6af8273d7fe7be6cfedb3f0aea6d7",
+ "3a5d7a879702c086bc96d1dd8aa15d9c 46446b95521311c606fdc4e308f4b984 da2d0f9449b3ba8425ec7fb8c31bc136",
+ "b27eab1d6e8d87461c29f7f5739dd58e 98aa35f8e823ad38c5492a2088fa0281 993bbfff9a0e9c6bf121ae9ec9bb09d8 4a5ebac817182ea974673fb133ca0d1d"
+ }},
+
+ %% {"0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c 0c0c0c0c",
+ %% "546573742057697468205472756e6361 74696f6e",
+ %% {"49fdd3abd005ebb8ae63fea946d1883c",
+ %% "6e02c64537fb118057abb7fb66a23b3c",
+ %% "47c51ace1ffacffd7494724682615783",
+ %% "0fa7475948f43f48ca0516671e18978c"
+ %% }},
+
+ {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaa",
+ "54657374205573696e67204c61726765 72205468616e20426c6f636b2d53697a 65204b6579202d2048617368204b6579 204669727374",
+ {"b4a1f04c00287a9b7f6075b313d279b8 33bc8f75124352d05fb9995f",
+ "ed73a374b96c005235f948032f09674a 58c0ce555cfc1f223b02356560312c3b",
+ "0fc19513bf6bd878037016706a0e57bc 528139836b9a42c3d419e498e0e1fb96 16fd669138d33a1105e07c72b6953bcc",
+ "00f751a9e50695b090ed6911a4b65524 951cdc15a73a5d58bb55215ea2cd839a c79d2b44a39bafab27e83fde9e11f634 0b11d991b1b91bf2eee7fc872426c3a4"
+ }},
+
+ {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaa",
+ "54657374205573696e67204c61726765 72205468616e20426c6f636b2d53697a 65204b6579202d2048617368204b6579 204669727374",
+ {
+ "b96d730c148c2daad8649d83defaa371 9738d34775397b7571c38515",
+ "a6072f86de52b38bb349fe84cd6d97fb 6a37c4c0f62aae93981193a7229d3467",
+ "713dff0302c85086ec5ad0768dd65a13 ddd79068d8d4c6212b712e4164944911 1480230044185a99103ed82004ddbfcc",
+ "b14835c819a290efb010ace6d8568dc6 b84de60bc49b004c3b13eda763589451 e5dd74292884d1bdce64e6b919dd61dc 9c56a282a81c0bd14f1f365b49b83a5b"
+ }},
+
+ {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaa",
+ "54686973206973206120746573742075 73696e672061206c6172676572207468 616e20626c6f636b2d73697a65206b65 7920616e642061206c61726765722074 68616e20626c6f636b2d73697a652064 6174612e20546865206b6579206e6565 647320746f2062652068617368656420 6265666f7265206265696e6720757365 642062792074686520484d414320616c 676f726974686d2e",
+ {
+ "05d8cd6d00faea8d1eb68ade28730bbd 3cbab6929f0a086b29cd62a0",
+ "65c5b06d4c3de32a7aef8763261e49ad b6e2293ec8e7c61e8de61701fc63e123",
+ "026fdf6b50741e373899c9f7d5406d4e b09fc6665636fc1a530029ddf5cf3ca5 a900edce01f5f61e2f408cdf2fd3e7e8",
+ "38a456a004bd10d32c9ab83366841128 62c3db61adcca31829355eaf46fd5c73 d06a1f0d13fec9a652fb3811b577b1b1 d1b9789f97ae5b83c6f44dfcf1d67eba"
+ }},
+
+ {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaa",
+ "54686973206973206120746573742075 73696e672061206c6172676572207468 616e20626c6f636b2d73697a65206b65 7920616e642061206c61726765722074 68616e20626c6f636b2d73697a652064 6174612e20546865206b6579206e6565 647320746f2062652068617368656420 6265666f7265206265696e6720757365 642062792074686520484d414320616c 676f726974686d2e",
+ {
+ "c79c9b093424e588a9878bbcb089e018 270096e9b4b1a9e8220c866a",
+ "e6a36d9b915f86a093cac7d110e9e04c f1d6100d30475509c2475f571b758b5a",
+ "cad18a8ff6c4cc3ad487b95f9769e9b6 1c062aefd6952569e6e6421897054cfc 70b5fdc6605c18457112fc6aaad45585",
+ "dc030ee7887034f32cf402df34622f31 1f3e6cf04860c6bbd7fa488674782b46 59fdbdf3fd877852885cfe6e22185fe7 b2ee952043629bc9d5f3298a41d02c66"
+ }}
+ %%,
+
+ %% {"4a656665",
+ %% "'11001' or LSB 13 or MSB c8",
+ %% {
+ %% "5f8c0ea7fafecd0c3463aad09742cece b142fe0ab6f4539438c59de8",
+ %% "ec8222773fac68b3d3dcb182aec8b050 7ace4448d20a1147e682118da4e3f44c",
+ %% "21fbd3bf3ebba3cfc9ef64c0591c92c5 acb265e92d8761d1f91a52a103a6c796 94cfd67a9a2ac1324f02fea63b81effc",
+ %% "27f9388c1567ef4ef200602a6cf871d6 8a6fb048d4737ac4418a2f021289d13d 1fd1120fecb9cf964c5b117ab5b11c61 4b2da39dadd51f2f5e22aaccec7d576e"
+ %% }}
+ ].
+
+
+
rfc_4634_test1() ->
<<"abc">>.
rfc_4634_test2_1() ->
@@ -1676,19 +2454,19 @@ rfc4231_hmac_sha512() ->
"debd71f8867289865df5a32d20cdc944"
"b6022cac3c4982b10d5eeb55c3e4de15"
"134676fb6de0446065c97440fa8c6a58")].
-des_cbc() ->
+des_cbc(_) ->
[{des_cbc,
hexstr2bin("0123456789abcdef"),
hexstr2bin("1234567890abcdef"),
<<"Now is the time for all ">> }].
-des_cfb() ->
+des_cfb(_) ->
[{des_cfb,
hexstr2bin("0123456789abcdef"),
hexstr2bin("1234567890abcdef"),
<<"Now is the">>}].
-des3_cbc() ->
+des3_cbc(_) ->
[{des3_cbc,
[hexstr2bin("0123456789abcdef"),
hexstr2bin("fedcba9876543210"),
@@ -1697,7 +2475,7 @@ des3_cbc() ->
<<"Now is the time for all ">>
}].
-des_ede3() ->
+des_ede3(_) ->
[{des_ede3,
[hexstr2bin("8000000000000000"),
hexstr2bin("4000000000000000"),
@@ -1706,7 +2484,23 @@ des_ede3() ->
hexstr2bin("0000000000000000")
}].
-des3_cbf() ->
+des_ede3_cbc(_) ->
+ [{des_ede3_cbc,
+ [hexstr2bin("0123456789abcdef"),
+ hexstr2bin("fedcba9876543210"),
+ hexstr2bin("0f2d4b6987a5c3e1")],
+ hexstr2bin("1234567890abcdef"),
+ <<"Now is the time for all ">>
+ },
+ {des_ede3_cbc,
+ [hexstr2bin("8000000000000000"),
+ hexstr2bin("4000000000000000"),
+ hexstr2bin("2000000000000000")],
+ hexstr2bin("7AD16FFB79C45926"),
+ hexstr2bin("0000000000000000")
+ }].
+
+des3_cbf(_) ->
[{des3_cbf,
[hexstr2bin("0123456789abcdef"),
hexstr2bin("fedcba9876543210"),
@@ -1715,7 +2509,7 @@ des3_cbf() ->
<<"Now is the time for all ">>
}].
-des3_cfb() ->
+des3_cfb(_) ->
[{des3_cfb,
[hexstr2bin("0123456789abcdef"),
hexstr2bin("fedcba9876543210"),
@@ -1724,7 +2518,16 @@ des3_cfb() ->
<<"Now is the time for all ">>
}].
-rc2_cbc() ->
+des_ede3_cfb(_) ->
+ [{des_ede3_cfb,
+ [hexstr2bin("0123456789abcdef"),
+ hexstr2bin("fedcba9876543210"),
+ hexstr2bin("0f2d4b6987a5c3e1")],
+ hexstr2bin("1234567890abcdef"),
+ <<"Now is the time for all ">>
+ }].
+
+rc2_cbc(_) ->
[{rc2_cbc,
<<146,210,160,124,215,227,153,239,227,17,222,140,3,93,27,191>>,
<<72,91,135,182,25,42,35,210>>,
@@ -1733,7 +2536,8 @@ rc2_cbc() ->
%% AES CBC test vectors from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
aes_cbc(Config) ->
- read_rsp(Config, aes_cbc,
+ %% RETIRED aes_*_cbc
+ read_rsp(Config, aes_cbc,
["CBCVarTxt128.rsp", "CBCVarKey128.rsp", "CBCGFSbox128.rsp", "CBCKeySbox128.rsp",
"CBCVarTxt192.rsp", "CBCVarKey192.rsp", "CBCGFSbox192.rsp", "CBCKeySbox192.rsp",
"CBCVarTxt256.rsp", "CBCVarKey256.rsp", "CBCGFSbox256.rsp", "CBCKeySbox256.rsp",
@@ -1741,15 +2545,32 @@ aes_cbc(Config) ->
]).
aes_cbc128(Config) ->
+ %% RETIRED aes_128_cbc
read_rsp(Config, aes_cbc128,
["CBCVarTxt128.rsp", "CBCVarKey128.rsp", "CBCGFSbox128.rsp", "CBCKeySbox128.rsp",
"CBCMMT128.rsp"]).
aes_cbc256(Config) ->
+ %% RETIRED aes_256_cbc
read_rsp(Config, aes_cbc256,
["CBCVarTxt256.rsp", "CBCVarKey256.rsp", "CBCGFSbox256.rsp", "CBCKeySbox256.rsp",
"CBCMMT256.rsp"]).
+aes_128_cbc(Config) ->
+ read_rsp(Config, aes_128_cbc,
+ ["CBCVarTxt128.rsp", "CBCVarKey128.rsp", "CBCGFSbox128.rsp", "CBCKeySbox128.rsp",
+ "CBCMMT128.rsp"]).
+
+aes_192_cbc(Config) ->
+ read_rsp(Config, aes_192_cbc,
+ ["CBCVarTxt192.rsp", "CBCVarKey192.rsp", "CBCGFSbox192.rsp", "CBCKeySbox192.rsp",
+ "CBCMMT192.rsp"]).
+
+aes_256_cbc(Config) ->
+ read_rsp(Config, aes_256_cbc,
+ ["CBCVarTxt256.rsp", "CBCVarKey256.rsp", "CBCGFSbox256.rsp", "CBCKeySbox256.rsp",
+ "CBCMMT256.rsp"]).
+
aes_ecb(Config) ->
read_rsp(Config, aes_ecb,
["ECBVarTxt128.rsp", "ECBVarKey128.rsp", "ECBGFSbox128.rsp", "ECBKeySbox128.rsp",
@@ -1757,7 +2578,22 @@ aes_ecb(Config) ->
"ECBVarTxt256.rsp", "ECBVarKey256.rsp", "ECBGFSbox256.rsp", "ECBKeySbox256.rsp",
"ECBMMT128.rsp", "ECBMMT192.rsp", "ECBMMT256.rsp"]).
-aes_ige256() ->
+aes_128_ecb(Config) ->
+ read_rsp(Config, aes_128_ecb,
+ ["ECBVarTxt128.rsp", "ECBVarKey128.rsp", "ECBGFSbox128.rsp", "ECBKeySbox128.rsp",
+ "ECBMMT128.rsp"]).
+
+aes_192_ecb(Config) ->
+ read_rsp(Config, aes_192_ecb,
+ ["ECBVarTxt192.rsp", "ECBVarKey192.rsp", "ECBGFSbox192.rsp", "ECBKeySbox192.rsp",
+ "ECBMMT192.rsp"]).
+
+aes_256_ecb(Config) ->
+ read_rsp(Config, aes_256_ecb,
+ ["ECBVarTxt256.rsp", "ECBVarKey256.rsp", "ECBGFSbox256.rsp", "ECBKeySbox256.rsp",
+ "ECBMMT256.rsp"]).
+
+aes_ige256(_) ->
[{aes_ige256,
hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
hexstr2bin("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"),
@@ -1783,6 +2619,22 @@ aes_cfb8(Config) ->
"CFB8VarTxt256.rsp", "CFB8VarKey256.rsp", "CFB8GFSbox256.rsp", "CFB8KeySbox256.rsp",
"CFB8MMT128.rsp", "CFB8MMT192.rsp", "CFB8MMT256.rsp"]).
+aes_128_cfb8(Config) ->
+ read_rsp(Config, aes_128_cfb8,
+ ["CFB8VarTxt128.rsp", "CFB8VarKey128.rsp", "CFB8GFSbox128.rsp", "CFB8KeySbox128.rsp",
+ "CFB8MMT128.rsp"]).
+
+aes_192_cfb8(Config) ->
+ read_rsp(Config, aes_192_cfb8,
+ ["CFB8VarTxt192.rsp", "CFB8VarKey192.rsp", "CFB8GFSbox192.rsp", "CFB8KeySbox192.rsp",
+ "CFB8MMT192.rsp"]).
+
+aes_256_cfb8(Config) ->
+ read_rsp(Config, aes_256_cfb8,
+ ["CFB8VarTxt256.rsp", "CFB8VarKey256.rsp", "CFB8GFSbox256.rsp", "CFB8KeySbox256.rsp",
+ "CFB8MMT256.rsp"]).
+
+
aes_cfb128(Config) ->
read_rsp(Config, aes_cfb128,
["CFB128VarTxt128.rsp", "CFB128VarKey128.rsp", "CFB128GFSbox128.rsp", "CFB128KeySbox128.rsp",
@@ -1790,14 +2642,30 @@ aes_cfb128(Config) ->
"CFB128VarTxt256.rsp", "CFB128VarKey256.rsp", "CFB128GFSbox256.rsp", "CFB128KeySbox256.rsp",
"CFB128MMT128.rsp", "CFB128MMT192.rsp", "CFB128MMT256.rsp"]).
-blowfish_cbc() ->
+aes_128_cfb128(Config) ->
+ read_rsp(Config, aes_128_cfb128,
+ ["CFB128VarTxt128.rsp", "CFB128VarKey128.rsp", "CFB128GFSbox128.rsp", "CFB128KeySbox128.rsp",
+ "CFB128MMT128.rsp"]).
+
+aes_192_cfb128(Config) ->
+ read_rsp(Config, aes_192_cfb128,
+ ["CFB128VarTxt192.rsp", "CFB128VarKey192.rsp", "CFB128GFSbox192.rsp", "CFB128KeySbox192.rsp",
+ "CFB128MMT192.rsp"]).
+
+aes_256_cfb128(Config) ->
+ read_rsp(Config, aes_256_cfb128,
+ ["CFB128VarTxt256.rsp", "CFB128VarKey256.rsp", "CFB128GFSbox256.rsp", "CFB128KeySbox256.rsp",
+ "CFB128MMT256.rsp"]).
+
+
+blowfish_cbc(_) ->
[{blowfish_cbc,
hexstr2bin("0123456789ABCDEFF0E1D2C3B4A59687"),
hexstr2bin("FEDCBA9876543210"),
hexstr2bin("37363534333231204E6F77206973207468652074696D6520666F722000000000")
}].
-blowfish_ecb() ->
+blowfish_ecb(_) ->
[
{blowfish_ecb,
hexstr2bin("0000000000000000"),
@@ -1894,26 +2762,26 @@ blowfish_ecb() ->
hexstr2bin("FFFFFFFFFFFFFFFF")}
].
-blowfish_cfb64() ->
+blowfish_cfb64(_) ->
[{blowfish_cfb64,
hexstr2bin("0123456789ABCDEFF0E1D2C3B4A59687"),
hexstr2bin("FEDCBA9876543210"),
hexstr2bin("37363534333231204E6F77206973207468652074696D6520666F722000")
}].
-blowfish_ofb64() ->
+blowfish_ofb64(_) ->
[{blowfish_ofb64,
hexstr2bin("0123456789ABCDEFF0E1D2C3B4A59687"),
hexstr2bin("FEDCBA9876543210"),
hexstr2bin("37363534333231204E6F77206973207468652074696D6520666F722000")
}].
-rc4() ->
+rc4(_) ->
[{rc4, <<"apaapa">>, <<"Yo baby yo">>},
{rc4, <<"apaapa">>, list_to_binary(lists:seq(0, 255))},
{rc4, <<"apaapa">>, long_msg()}
].
-aes_ctr() ->
+aes_ctr(_) ->
[ %% F.5.3 CTR-AES192.Encrypt
{aes_ctr, hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"),
@@ -1962,17 +2830,109 @@ aes_ctr() ->
].
+aes_128_ctr(_) ->
+ [ %% F.5.3 CTR-AES192.Encrypt
+ {aes_128_ctr, hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"),
+ hexstr2bin("6bc1bee22e409f96e93d7e117393172a")},
+ {aes_128_ctr, hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff00"),
+ hexstr2bin("ae2d8a571e03ac9c9eb76fac45af8e51")},
+ {aes_128_ctr, hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff01"),
+ hexstr2bin("30c81c46a35ce411e5fbc1191a0a52ef") },
+ {aes_128_ctr, hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff02"),
+ hexstr2bin("f69f2445df4f9b17ad2b417be66c3710")}
+ ].
+
+aes_192_ctr(_) ->
+ [ %% F.5.3 CTR-AES192.Encrypt
+ {aes_192_ctr, hexstr2bin("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"),
+ hexstr2bin("6bc1bee22e409f96e93d7e117393172a")},
+ {aes_192_ctr, hexstr2bin("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff00"),
+ hexstr2bin("ae2d8a571e03ac9c9eb76fac45af8e51")},
+ {aes_192_ctr, hexstr2bin("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff01"),
+ hexstr2bin("30c81c46a35ce411e5fbc1191a0a52ef")},
+ {aes_192_ctr, hexstr2bin("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff02"),
+ hexstr2bin("f69f2445df4f9b17ad2b417be66c3710")}
+ ].
+
+aes_256_ctr(_) ->
+ [ %% F.5.5 CTR-AES256.Encrypt
+ {aes_256_ctr, hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"),
+ hexstr2bin("6bc1bee22e409f96e93d7e117393172a")},
+ {aes_256_ctr, hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff00"),
+ hexstr2bin("ae2d8a571e03ac9c9eb76fac45af8e51")},
+ {aes_256_ctr, hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff01"),
+ hexstr2bin("30c81c46a35ce411e5fbc1191a0a52ef")},
+ {aes_256_ctr, hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff02"),
+ hexstr2bin("f69f2445df4f9b17ad2b417be66c3710")},
+
+ {aes_256_ctr, hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"),
+ long_msg()}
+ ].
+
+
aes_gcm(Config) ->
- read_rsp(Config, aes_gcm,
+ %% RETIRED aes_*_gcm
+ read_rsp(Config, aes_gcm,
+ ["gcmDecrypt128.rsp",
+ "gcmDecrypt192.rsp",
+ "gcmDecrypt256.rsp",
+ "gcmEncryptExtIV128.rsp",
+ "gcmEncryptExtIV192.rsp",
+ "gcmEncryptExtIV256.rsp"]).
+
+aes_128_gcm(Config) ->
+ read_rsp(Config, aes_128_gcm,
["gcmDecrypt128.rsp",
- "gcmDecrypt192.rsp",
- "gcmDecrypt256.rsp",
- "gcmEncryptExtIV128.rsp",
- "gcmEncryptExtIV192.rsp",
+ "gcmEncryptExtIV128.rsp"]).
+
+aes_192_gcm(Config) ->
+ read_rsp(Config, aes_192_gcm,
+ ["gcmDecrypt192.rsp",
+ "gcmEncryptExtIV192.rsp"]).
+
+aes_256_gcm(Config) ->
+ read_rsp(Config, aes_256_gcm,
+ ["gcmDecrypt256.rsp",
"gcmEncryptExtIV256.rsp"]).
+
+aes_ccm(Config) ->
+ %% RETIRED aes_*_ccm
+ read_rsp(Config, aes_ccm,
+ ["VADT128.rsp", "VADT192.rsp", "VADT256.rsp",
+ "VNT128.rsp", "VNT192.rsp", "VNT256.rsp",
+ "VPT128.rsp", "VPT192.rsp", "VPT256.rsp"
+ ]).
+
+aes_128_ccm(Config) ->
+ read_rsp(Config, aes_128_ccm,
+ ["VADT128.rsp", "VNT128.rsp", "VPT128.rsp"]).
+
+aes_192_ccm(Config) ->
+ read_rsp(Config, aes_192_ccm,
+ ["VADT192.rsp", "VNT192.rsp", "VPT192.rsp"]).
+
+aes_256_ccm(Config) ->
+ read_rsp(Config, aes_256_ccm,
+ ["VADT256.rsp", "VNT256.rsp", "VPT256.rsp"]).
+
+
+
%% https://tools.ietf.org/html/rfc7539#appendix-A.5
-chacha20_poly1305() ->
+chacha20_poly1305(_) ->
[
{chacha20_poly1305,
hexstr2bin("1c9240a5eb55d38af333888604f6b5f0" %% Key
@@ -2013,9 +2973,108 @@ chacha20_poly1305() ->
"49e617d91d361094fa68f0ff77987130"
"305beaba2eda04df997b714d6c6f2c29"
"a6ad5cb4022b02709b"),
- hexstr2bin("eead9d67890cbb22392336fea1851f38")} %% CipherTag
+ hexstr2bin("eead9d67890cbb22392336fea1851f38"), %% CipherTag
+ no_info
+ }
].
+
+chacha20(_) ->
+%%% chacha20 (no mode) test vectors from RFC 7539 A.2
+ [
+ %% Test Vector #1:
+ {chacha20,
+ hexstr2bin("00000000000000000000000000000000"
+ "00000000000000000000000000000000"), %% Key
+ hexstr2bin("00000000" % Initial counter = 0, little-endian
+ "000000000000000000000000"), %% IV
+ hexstr2bin("00000000000000000000000000000000" %% PlainText
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000"),
+ hexstr2bin("76b8e0ada0f13d90405d6ae55386bd28" %% CipherText
+ "bdd219b8a08ded1aa836efcc8b770dc7"
+ "da41597c5157488d7724e03fb8d84a37"
+ "6a43b8f41518a11cc387b669b2ee6586")},
+ %% Test Vector #2:
+ {chacha20,
+ hexstr2bin("00000000000000000000000000000000"
+ "00000000000000000000000000000001"), %% Key
+ hexstr2bin("01000000" % Initial counter = 1, little-endian
+ "000000000000000000000002"), %% IV
+ hexstr2bin("416e79207375626d697373696f6e2074" %% PlainText
+ "6f20746865204945544620696e74656e"
+ "6465642062792074686520436f6e7472"
+ "696275746f7220666f72207075626c69"
+ "636174696f6e20617320616c6c206f72"
+ "2070617274206f6620616e2049455446"
+ "20496e7465726e65742d447261667420"
+ "6f722052464320616e6420616e792073"
+ "746174656d656e74206d616465207769"
+ "7468696e2074686520636f6e74657874"
+ "206f6620616e20494554462061637469"
+ "7669747920697320636f6e7369646572"
+ "656420616e20224945544620436f6e74"
+ "7269627574696f6e222e205375636820"
+ "73746174656d656e747320696e636c75"
+ "6465206f72616c2073746174656d656e"
+ "747320696e2049455446207365737369"
+ "6f6e732c2061732077656c6c20617320"
+ "7772697474656e20616e6420656c6563"
+ "74726f6e696320636f6d6d756e696361"
+ "74696f6e73206d61646520617420616e"
+ "792074696d65206f7220706c6163652c"
+ "20776869636820617265206164647265"
+ "7373656420746f"),
+ hexstr2bin("a3fbf07df3fa2fde4f376ca23e827370" %% CipherText
+ "41605d9f4f4f57bd8cff2c1d4b7955ec"
+ "2a97948bd3722915c8f3d337f7d37005"
+ "0e9e96d647b7c39f56e031ca5eb6250d"
+ "4042e02785ececfa4b4bb5e8ead0440e"
+ "20b6e8db09d881a7c6132f420e527950"
+ "42bdfa7773d8a9051447b3291ce1411c"
+ "680465552aa6c405b7764d5e87bea85a"
+ "d00f8449ed8f72d0d662ab052691ca66"
+ "424bc86d2df80ea41f43abf937d3259d"
+ "c4b2d0dfb48a6c9139ddd7f76966e928"
+ "e635553ba76c5c879d7b35d49eb2e62b"
+ "0871cdac638939e25e8a1e0ef9d5280f"
+ "a8ca328b351c3c765989cbcf3daa8b6c"
+ "cc3aaf9f3979c92b3720fc88dc95ed84"
+ "a1be059c6499b9fda236e7e818b04b0b"
+ "c39c1e876b193bfe5569753f88128cc0"
+ "8aaa9b63d1a16f80ef2554d7189c411f"
+ "5869ca52c5b83fa36ff216b9c1d30062"
+ "bebcfd2dc5bce0911934fda79a86f6e6"
+ "98ced759c3ff9b6477338f3da4f9cd85"
+ "14ea9982ccafb341b2384dd902f3d1ab"
+ "7ac61dd29c6f21ba5b862f3730e37cfd"
+ "c4fd806c22f221")},
+ %%Test Vector #3:
+ {chacha20,
+ hexstr2bin("1c9240a5eb55d38af333888604f6b5f0"
+ "473917c1402b80099dca5cbc207075c0"), %% Key
+ hexstr2bin("2a000000" % Initial counter = 42 (decimal), little-endian
+ "000000000000000000000002"), %% IV
+ hexstr2bin("2754776173206272696c6c69672c2061" %% PlainText
+ "6e642074686520736c6974687920746f"
+ "7665730a446964206779726520616e64"
+ "2067696d626c6520696e207468652077"
+ "6162653a0a416c6c206d696d73792077"
+ "6572652074686520626f726f676f7665"
+ "732c0a416e6420746865206d6f6d6520"
+ "7261746873206f757467726162652e"),
+ hexstr2bin("62e6347f95ed87a45ffae7426f27a1df" %% CipherText
+ "5fb69110044c0d73118effa95b01e5cf"
+ "166d3df2d721caf9b21e5fb14c616871"
+ "fd84c54f9d65b283196c7fe4f60553eb"
+ "f39c6402c42234e32a356b3e764312a6"
+ "1a5532055716ead6962568f87d3f3f77"
+ "04c6a8d1bcd1bf4d50d6154b6da731b1"
+ "87b58dfd728afa36757a797ac188d1")}
+ ].
+
+
rsa_plain() ->
<<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger"
"09812312908312378623487263487623412039812 huagasd">>.
@@ -2209,9 +3268,397 @@ srp(ClientPrivate, Generator, Prime, Version, Verifier, ServerPublic, ServerPriv
ServerPublic, ServerPrivate, {host, [Verifier, Generator, Prime, Version]},
{host, [Verifier, Prime, Version, Scrambler]},
SessionKey}.
+
+eddsa(ed25519) ->
+ %% https://tools.ietf.org/html/rfc8032#section-7.1
+ %% {ALGORITHM, (SHA)}, SECRET KEY, PUBLIC KEY, MESSAGE, SIGNATURE}
+ [
+ %% TEST 1
+ {ed25519, undefined,
+ hexstr2bin("9d61b19deffd5a60ba844af492ec2cc4"
+ "4449c5697b326919703bac031cae7f60"),
+ hexstr2bin("d75a980182b10ab7d54bfed3c964073a"
+ "0ee172f3daa62325af021a68f707511a"),
+ hexstr2bin(""),
+ hexstr2bin("e5564300c360ac729086e2cc806e828a"
+ "84877f1eb8e5d974d873e06522490155"
+ "5fb8821590a33bacc61e39701cf9b46b"
+ "d25bf5f0595bbe24655141438e7a100b")},
+ %% TEST 2
+ {ed25519, undefined,
+ hexstr2bin("4ccd089b28ff96da9db6c346ec114e0f"
+ "5b8a319f35aba624da8cf6ed4fb8a6fb"),
+ hexstr2bin("3d4017c3e843895a92b70aa74d1b7ebc"
+ "9c982ccf2ec4968cc0cd55f12af4660c"),
+ hexstr2bin("72"),
+ hexstr2bin("92a009a9f0d4cab8720e820b5f642540"
+ "a2b27b5416503f8fb3762223ebdb69da"
+ "085ac1e43e15996e458f3613d0f11d8c"
+ "387b2eaeb4302aeeb00d291612bb0c00")},
+ %% TEST 3
+ {ed25519, undefined,
+ hexstr2bin("c5aa8df43f9f837bedb7442f31dcb7b1"
+ "66d38535076f094b85ce3a2e0b4458f7"),
+ hexstr2bin("fc51cd8e6218a1a38da47ed00230f058"
+ "0816ed13ba3303ac5deb911548908025"),
+ hexstr2bin("af82"),
+ hexstr2bin("6291d657deec24024827e69c3abe01a3"
+ "0ce548a284743a445e3680d7db5ac3ac"
+ "18ff9b538d16f290ae67f760984dc659"
+ "4a7c15e9716ed28dc027beceea1ec40a")},
+ %% TEST 1024
+ {ed25519, undefined,
+ hexstr2bin("f5e5767cf153319517630f226876b86c"
+ "8160cc583bc013744c6bf255f5cc0ee5"),
+ hexstr2bin("278117fc144c72340f67d0f2316e8386"
+ "ceffbf2b2428c9c51fef7c597f1d426e"),
+ hexstr2bin("08b8b2b733424243760fe426a4b54908"
+ "632110a66c2f6591eabd3345e3e4eb98"
+ "fa6e264bf09efe12ee50f8f54e9f77b1"
+ "e355f6c50544e23fb1433ddf73be84d8"
+ "79de7c0046dc4996d9e773f4bc9efe57"
+ "38829adb26c81b37c93a1b270b20329d"
+ "658675fc6ea534e0810a4432826bf58c"
+ "941efb65d57a338bbd2e26640f89ffbc"
+ "1a858efcb8550ee3a5e1998bd177e93a"
+ "7363c344fe6b199ee5d02e82d522c4fe"
+ "ba15452f80288a821a579116ec6dad2b"
+ "3b310da903401aa62100ab5d1a36553e"
+ "06203b33890cc9b832f79ef80560ccb9"
+ "a39ce767967ed628c6ad573cb116dbef"
+ "efd75499da96bd68a8a97b928a8bbc10"
+ "3b6621fcde2beca1231d206be6cd9ec7"
+ "aff6f6c94fcd7204ed3455c68c83f4a4"
+ "1da4af2b74ef5c53f1d8ac70bdcb7ed1"
+ "85ce81bd84359d44254d95629e9855a9"
+ "4a7c1958d1f8ada5d0532ed8a5aa3fb2"
+ "d17ba70eb6248e594e1a2297acbbb39d"
+ "502f1a8c6eb6f1ce22b3de1a1f40cc24"
+ "554119a831a9aad6079cad88425de6bd"
+ "e1a9187ebb6092cf67bf2b13fd65f270"
+ "88d78b7e883c8759d2c4f5c65adb7553"
+ "878ad575f9fad878e80a0c9ba63bcbcc"
+ "2732e69485bbc9c90bfbd62481d9089b"
+ "eccf80cfe2df16a2cf65bd92dd597b07"
+ "07e0917af48bbb75fed413d238f5555a"
+ "7a569d80c3414a8d0859dc65a46128ba"
+ "b27af87a71314f318c782b23ebfe808b"
+ "82b0ce26401d2e22f04d83d1255dc51a"
+ "ddd3b75a2b1ae0784504df543af8969b"
+ "e3ea7082ff7fc9888c144da2af58429e"
+ "c96031dbcad3dad9af0dcbaaaf268cb8"
+ "fcffead94f3c7ca495e056a9b47acdb7"
+ "51fb73e666c6c655ade8297297d07ad1"
+ "ba5e43f1bca32301651339e22904cc8c"
+ "42f58c30c04aafdb038dda0847dd988d"
+ "cda6f3bfd15c4b4c4525004aa06eeff8"
+ "ca61783aacec57fb3d1f92b0fe2fd1a8"
+ "5f6724517b65e614ad6808d6f6ee34df"
+ "f7310fdc82aebfd904b01e1dc54b2927"
+ "094b2db68d6f903b68401adebf5a7e08"
+ "d78ff4ef5d63653a65040cf9bfd4aca7"
+ "984a74d37145986780fc0b16ac451649"
+ "de6188a7dbdf191f64b5fc5e2ab47b57"
+ "f7f7276cd419c17a3ca8e1b939ae49e4"
+ "88acba6b965610b5480109c8b17b80e1"
+ "b7b750dfc7598d5d5011fd2dcc5600a3"
+ "2ef5b52a1ecc820e308aa342721aac09"
+ "43bf6686b64b2579376504ccc493d97e"
+ "6aed3fb0f9cd71a43dd497f01f17c0e2"
+ "cb3797aa2a2f256656168e6c496afc5f"
+ "b93246f6b1116398a346f1a641f3b041"
+ "e989f7914f90cc2c7fff357876e506b5"
+ "0d334ba77c225bc307ba537152f3f161"
+ "0e4eafe595f6d9d90d11faa933a15ef1"
+ "369546868a7f3a45a96768d40fd9d034"
+ "12c091c6315cf4fde7cb68606937380d"
+ "b2eaaa707b4c4185c32eddcdd306705e"
+ "4dc1ffc872eeee475a64dfac86aba41c"
+ "0618983f8741c5ef68d3a101e8a3b8ca"
+ "c60c905c15fc910840b94c00a0b9d0"),
+ hexstr2bin("0aab4c900501b3e24d7cdf4663326a3a"
+ "87df5e4843b2cbdb67cbf6e460fec350"
+ "aa5371b1508f9f4528ecea23c436d94b"
+ "5e8fcd4f681e30a6ac00a9704a188a03")},
+ %% TEST SHA(abc)
+ {ed25519, undefined,
+ hexstr2bin("833fe62409237b9d62ec77587520911e"
+ "9a759cec1d19755b7da901b96dca3d42"),
+ hexstr2bin("ec172b93ad5e563bf4932c70e1245034"
+ "c35467ef2efd4d64ebf819683467e2bf"),
+ hexstr2bin("ddaf35a193617abacc417349ae204131"
+ "12e6fa4e89a97ea20a9eeee64b55d39a"
+ "2192992a274fc1a836ba3c23a3feebbd"
+ "454d4423643ce80e2a9ac94fa54ca49f"),
+ hexstr2bin("dc2a4459e7369633a52b1bf277839a00"
+ "201009a3efbf3ecb69bea2186c26b589"
+ "09351fc9ac90b3ecfdfbc7c66431e030"
+ "3dca179c138ac17ad9bef1177331a704")}
+ ];
+
+eddsa(ed448) ->
+ %% https://tools.ietf.org/html/rfc8032#section-7.4
+ [{ed448, undefined,
+ hexstr2bin("6c82a562cb808d10d632be89c8513ebf"
+ "6c929f34ddfa8c9f63c9960ef6e348a3"
+ "528c8a3fcc2f044e39a3fc5b94492f8f"
+ "032e7549a20098f95b"),
+ hexstr2bin("5fd7449b59b461fd2ce787ec616ad46a"
+ "1da1342485a70e1f8a0ea75d80e96778"
+ "edf124769b46c7061bd6783df1e50f6c"
+ "d1fa1abeafe8256180"),
+ hexstr2bin(""),
+ hexstr2bin("533a37f6bbe457251f023c0d88f976ae"
+ "2dfb504a843e34d2074fd823d41a591f"
+ "2b233f034f628281f2fd7a22ddd47d78"
+ "28c59bd0a21bfd3980ff0d2028d4b18a"
+ "9df63e006c5d1c2d345b925d8dc00b41"
+ "04852db99ac5c7cdda8530a113a0f4db"
+ "b61149f05a7363268c71d95808ff2e65"
+ "2600")},
+ %% 1 octet
+ {ed448, undefined,
+ hexstr2bin("c4eab05d357007c632f3dbb48489924d"
+ "552b08fe0c353a0d4a1f00acda2c463a"
+ "fbea67c5e8d2877c5e3bc397a659949e"
+ "f8021e954e0a12274e"),
+ hexstr2bin("43ba28f430cdff456ae531545f7ecd0a"
+ "c834a55d9358c0372bfa0c6c6798c086"
+ "6aea01eb00742802b8438ea4cb82169c"
+ "235160627b4c3a9480"),
+ hexstr2bin("03"),
+ hexstr2bin("26b8f91727bd62897af15e41eb43c377"
+ "efb9c610d48f2335cb0bd0087810f435"
+ "2541b143c4b981b7e18f62de8ccdf633"
+ "fc1bf037ab7cd779805e0dbcc0aae1cb"
+ "cee1afb2e027df36bc04dcecbf154336"
+ "c19f0af7e0a6472905e799f1953d2a0f"
+ "f3348ab21aa4adafd1d234441cf807c0"
+ "3a00")},
+
+ %% %% 1 octet (with context)
+ %% {ed448, undefined,
+ %% hexstr2bin("c4eab05d357007c632f3dbb48489924d"
+ %% "552b08fe0c353a0d4a1f00acda2c463a"
+ %% "fbea67c5e8d2877c5e3bc397a659949e"
+ %% "f8021e954e0a12274e"),
+ %% hexstr2bin("43ba28f430cdff456ae531545f7ecd0a"
+ %% "c834a55d9358c0372bfa0c6c6798c086"
+ %% "6aea01eb00742802b8438ea4cb82169c"
+ %% "235160627b4c3a9480"),
+ %% hexstr2bin("03"),
+ %% hexstr2bin("666f6f"), % Context
+ %% hexstr2bin("d4f8f6131770dd46f40867d6fd5d5055"
+ %% "de43541f8c5e35abbcd001b32a89f7d2"
+ %% "151f7647f11d8ca2ae279fb842d60721"
+ %% "7fce6e042f6815ea000c85741de5c8da"
+ %% "1144a6a1aba7f96de42505d7a7298524"
+ %% "fda538fccbbb754f578c1cad10d54d0d"
+ %% "5428407e85dcbc98a49155c13764e66c"
+ %% "3c00")},
+
+ %% 11 octets
+ {ed448, undefined,
+ hexstr2bin("cd23d24f714274e744343237b93290f5"
+ "11f6425f98e64459ff203e8985083ffd"
+ "f60500553abc0e05cd02184bdb89c4cc"
+ "d67e187951267eb328"),
+ hexstr2bin("dcea9e78f35a1bf3499a831b10b86c90"
+ "aac01cd84b67a0109b55a36e9328b1e3"
+ "65fce161d71ce7131a543ea4cb5f7e9f"
+ "1d8b00696447001400"),
+ hexstr2bin("0c3e544074ec63b0265e0c"),
+ hexstr2bin("1f0a8888ce25e8d458a21130879b840a"
+ "9089d999aaba039eaf3e3afa090a09d3"
+ "89dba82c4ff2ae8ac5cdfb7c55e94d5d"
+ "961a29fe0109941e00b8dbdeea6d3b05"
+ "1068df7254c0cdc129cbe62db2dc957d"
+ "bb47b51fd3f213fb8698f064774250a5"
+ "028961c9bf8ffd973fe5d5c206492b14"
+ "0e00")},
+ %% 12 octets
+ {ed448, undefined,
+ hexstr2bin("258cdd4ada32ed9c9ff54e63756ae582"
+ "fb8fab2ac721f2c8e676a72768513d93"
+ "9f63dddb55609133f29adf86ec9929dc"
+ "cb52c1c5fd2ff7e21b"),
+ hexstr2bin("3ba16da0c6f2cc1f30187740756f5e79"
+ "8d6bc5fc015d7c63cc9510ee3fd44adc"
+ "24d8e968b6e46e6f94d19b945361726b"
+ "d75e149ef09817f580"),
+ hexstr2bin("64a65f3cdedcdd66811e2915"),
+ hexstr2bin("7eeeab7c4e50fb799b418ee5e3197ff6"
+ "bf15d43a14c34389b59dd1a7b1b85b4a"
+ "e90438aca634bea45e3a2695f1270f07"
+ "fdcdf7c62b8efeaf00b45c2c96ba457e"
+ "b1a8bf075a3db28e5c24f6b923ed4ad7"
+ "47c3c9e03c7079efb87cb110d3a99861"
+ "e72003cbae6d6b8b827e4e6c143064ff"
+ "3c00")},
+ %% 13 octets
+ {ed448, undefined,
+ hexstr2bin("7ef4e84544236752fbb56b8f31a23a10"
+ "e42814f5f55ca037cdcc11c64c9a3b29"
+ "49c1bb60700314611732a6c2fea98eeb"
+ "c0266a11a93970100e"),
+ hexstr2bin("b3da079b0aa493a5772029f0467baebe"
+ "e5a8112d9d3a22532361da294f7bb381"
+ "5c5dc59e176b4d9f381ca0938e13c6c0"
+ "7b174be65dfa578e80"),
+ hexstr2bin("64a65f3cdedcdd66811e2915e7"),
+ hexstr2bin("6a12066f55331b6c22acd5d5bfc5d712"
+ "28fbda80ae8dec26bdd306743c5027cb"
+ "4890810c162c027468675ecf645a8317"
+ "6c0d7323a2ccde2d80efe5a1268e8aca"
+ "1d6fbc194d3f77c44986eb4ab4177919"
+ "ad8bec33eb47bbb5fc6e28196fd1caf5"
+ "6b4e7e0ba5519234d047155ac727a105"
+ "3100")},
+ %% 64 octets
+ {ed448, undefined,
+ hexstr2bin("d65df341ad13e008567688baedda8e9d"
+ "cdc17dc024974ea5b4227b6530e339bf"
+ "f21f99e68ca6968f3cca6dfe0fb9f4fa"
+ "b4fa135d5542ea3f01"),
+ hexstr2bin("df9705f58edbab802c7f8363cfe5560a"
+ "b1c6132c20a9f1dd163483a26f8ac53a"
+ "39d6808bf4a1dfbd261b099bb03b3fb5"
+ "0906cb28bd8a081f00"),
+ hexstr2bin("bd0f6a3747cd561bdddf4640a332461a"
+ "4a30a12a434cd0bf40d766d9c6d458e5"
+ "512204a30c17d1f50b5079631f64eb31"
+ "12182da3005835461113718d1a5ef944"),
+ hexstr2bin("554bc2480860b49eab8532d2a533b7d5"
+ "78ef473eeb58c98bb2d0e1ce488a98b1"
+ "8dfde9b9b90775e67f47d4a1c3482058"
+ "efc9f40d2ca033a0801b63d45b3b722e"
+ "f552bad3b4ccb667da350192b61c508c"
+ "f7b6b5adadc2c8d9a446ef003fb05cba"
+ "5f30e88e36ec2703b349ca229c267083"
+ "3900")},
+ %% 256 octets
+ {ed448, undefined,
+ hexstr2bin("2ec5fe3c17045abdb136a5e6a913e32a"
+ "b75ae68b53d2fc149b77e504132d3756"
+ "9b7e766ba74a19bd6162343a21c8590a"
+ "a9cebca9014c636df5"),
+ hexstr2bin("79756f014dcfe2079f5dd9e718be4171"
+ "e2ef2486a08f25186f6bff43a9936b9b"
+ "fe12402b08ae65798a3d81e22e9ec80e"
+ "7690862ef3d4ed3a00"),
+ hexstr2bin("15777532b0bdd0d1389f636c5f6b9ba7"
+ "34c90af572877e2d272dd078aa1e567c"
+ "fa80e12928bb542330e8409f31745041"
+ "07ecd5efac61ae7504dabe2a602ede89"
+ "e5cca6257a7c77e27a702b3ae39fc769"
+ "fc54f2395ae6a1178cab4738e543072f"
+ "c1c177fe71e92e25bf03e4ecb72f47b6"
+ "4d0465aaea4c7fad372536c8ba516a60"
+ "39c3c2a39f0e4d832be432dfa9a706a6"
+ "e5c7e19f397964ca4258002f7c0541b5"
+ "90316dbc5622b6b2a6fe7a4abffd9610"
+ "5eca76ea7b98816af0748c10df048ce0"
+ "12d901015a51f189f3888145c03650aa"
+ "23ce894c3bd889e030d565071c59f409"
+ "a9981b51878fd6fc110624dcbcde0bf7"
+ "a69ccce38fabdf86f3bef6044819de11"),
+ hexstr2bin("c650ddbb0601c19ca11439e1640dd931"
+ "f43c518ea5bea70d3dcde5f4191fe53f"
+ "00cf966546b72bcc7d58be2b9badef28"
+ "743954e3a44a23f880e8d4f1cfce2d7a"
+ "61452d26da05896f0a50da66a239a8a1"
+ "88b6d825b3305ad77b73fbac0836ecc6"
+ "0987fd08527c1a8e80d5823e65cafe2a"
+ "3d00")},
+ %% 1023 octets
+ {ed448, undefined,
+ hexstr2bin("872d093780f5d3730df7c212664b37b8"
+ "a0f24f56810daa8382cd4fa3f77634ec"
+ "44dc54f1c2ed9bea86fafb7632d8be19"
+ "9ea165f5ad55dd9ce8"),
+ hexstr2bin("a81b2e8a70a5ac94ffdbcc9badfc3feb"
+ "0801f258578bb114ad44ece1ec0e799d"
+ "a08effb81c5d685c0c56f64eecaef8cd"
+ "f11cc38737838cf400"),
+ hexstr2bin("6ddf802e1aae4986935f7f981ba3f035"
+ "1d6273c0a0c22c9c0e8339168e675412"
+ "a3debfaf435ed651558007db4384b650"
+ "fcc07e3b586a27a4f7a00ac8a6fec2cd"
+ "86ae4bf1570c41e6a40c931db27b2faa"
+ "15a8cedd52cff7362c4e6e23daec0fbc"
+ "3a79b6806e316efcc7b68119bf46bc76"
+ "a26067a53f296dafdbdc11c77f7777e9"
+ "72660cf4b6a9b369a6665f02e0cc9b6e"
+ "dfad136b4fabe723d2813db3136cfde9"
+ "b6d044322fee2947952e031b73ab5c60"
+ "3349b307bdc27bc6cb8b8bbd7bd32321"
+ "9b8033a581b59eadebb09b3c4f3d2277"
+ "d4f0343624acc817804728b25ab79717"
+ "2b4c5c21a22f9c7839d64300232eb66e"
+ "53f31c723fa37fe387c7d3e50bdf9813"
+ "a30e5bb12cf4cd930c40cfb4e1fc6225"
+ "92a49588794494d56d24ea4b40c89fc0"
+ "596cc9ebb961c8cb10adde976a5d602b"
+ "1c3f85b9b9a001ed3c6a4d3b1437f520"
+ "96cd1956d042a597d561a596ecd3d173"
+ "5a8d570ea0ec27225a2c4aaff26306d1"
+ "526c1af3ca6d9cf5a2c98f47e1c46db9"
+ "a33234cfd4d81f2c98538a09ebe76998"
+ "d0d8fd25997c7d255c6d66ece6fa56f1"
+ "1144950f027795e653008f4bd7ca2dee"
+ "85d8e90f3dc315130ce2a00375a318c7"
+ "c3d97be2c8ce5b6db41a6254ff264fa6"
+ "155baee3b0773c0f497c573f19bb4f42"
+ "40281f0b1f4f7be857a4e59d416c06b4"
+ "c50fa09e1810ddc6b1467baeac5a3668"
+ "d11b6ecaa901440016f389f80acc4db9"
+ "77025e7f5924388c7e340a732e554440"
+ "e76570f8dd71b7d640b3450d1fd5f041"
+ "0a18f9a3494f707c717b79b4bf75c984"
+ "00b096b21653b5d217cf3565c9597456"
+ "f70703497a078763829bc01bb1cbc8fa"
+ "04eadc9a6e3f6699587a9e75c94e5bab"
+ "0036e0b2e711392cff0047d0d6b05bd2"
+ "a588bc109718954259f1d86678a579a3"
+ "120f19cfb2963f177aeb70f2d4844826"
+ "262e51b80271272068ef5b3856fa8535"
+ "aa2a88b2d41f2a0e2fda7624c2850272"
+ "ac4a2f561f8f2f7a318bfd5caf969614"
+ "9e4ac824ad3460538fdc25421beec2cc"
+ "6818162d06bbed0c40a387192349db67"
+ "a118bada6cd5ab0140ee273204f628aa"
+ "d1c135f770279a651e24d8c14d75a605"
+ "9d76b96a6fd857def5e0b354b27ab937"
+ "a5815d16b5fae407ff18222c6d1ed263"
+ "be68c95f32d908bd895cd76207ae7264"
+ "87567f9a67dad79abec316f683b17f2d"
+ "02bf07e0ac8b5bc6162cf94697b3c27c"
+ "d1fea49b27f23ba2901871962506520c"
+ "392da8b6ad0d99f7013fbc06c2c17a56"
+ "9500c8a7696481c1cd33e9b14e40b82e"
+ "79a5f5db82571ba97bae3ad3e0479515"
+ "bb0e2b0f3bfcd1fd33034efc6245eddd"
+ "7ee2086ddae2600d8ca73e214e8c2b0b"
+ "db2b047c6a464a562ed77b73d2d841c4"
+ "b34973551257713b753632efba348169"
+ "abc90a68f42611a40126d7cb21b58695"
+ "568186f7e569d2ff0f9e745d0487dd2e"
+ "b997cafc5abf9dd102e62ff66cba87"),
+ hexstr2bin("e301345a41a39a4d72fff8df69c98075"
+ "a0cc082b802fc9b2b6bc503f926b65bd"
+ "df7f4c8f1cb49f6396afc8a70abe6d8a"
+ "ef0db478d4c6b2970076c6a0484fe76d"
+ "76b3a97625d79f1ce240e7c576750d29"
+ "5528286f719b413de9ada3e8eb78ed57"
+ "3603ce30d8bb761785dc30dbc320869e"
+ "1a00")}
+ ].
+
ecdh() ->
%% http://csrc.nist.gov/groups/STM/cavp/
- Curves = crypto:ec_curves(),
+ Curves = crypto:ec_curves() ++
+ [X || X <- proplists:get_value(curves, crypto:supports(), []),
+ lists:member(X, [x25519,x448])],
TestCases =
[{ecdh, hexstr2point("42ea6dd9969dd2a61fea1aac7f8e98edcc896c6e55857cc0", "dfbe5d7c61fac88b11811bde328e8a0d12bf01a9d204b523"),
hexstr2bin("f17d3fea367b74d340851ca4270dcb24c271f445bed9d527"),
@@ -2294,7 +3741,32 @@ ecdh() ->
"2FDC313095BCDD5FB3A91636F07A959C8E86B5636A1E930E8396049CB481961D365CC11453A06C719835475B12CB52FC3C383BCE35E27EF194512B71876285FA"),
hexstr2bin("16302FF0DBBB5A8D733DAB7141C1B45ACBC8715939677F6A56850A38BD87BD59B09E80279609FF333EB9D4C061231FB26F92EEB04982A5F1D1764CAD57665422"),
brainpoolP512r1,
- hexstr2bin("A7927098655F1F9976FA50A9D566865DC530331846381C87256BAF3226244B76D36403C024D7BBF0AA0803EAFF405D3D24F11A9B5C0BEF679FE1454B21C4CD1F")}],
+ hexstr2bin("A7927098655F1F9976FA50A9D566865DC530331846381C87256BAF3226244B76D36403C024D7BBF0AA0803EAFF405D3D24F11A9B5C0BEF679FE1454B21C4CD1F")},
+
+ %% RFC 7748, 6.1
+ {ecdh,
+ 16#8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a,
+ 16#5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb,
+ x25519,
+ hexstr2bin("4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742")},
+ {ecdh,
+ 16#de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f,
+ 16#77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a,
+ x25519,
+ hexstr2bin("4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742")},
+
+ %% RFC 7748, 6.2
+ {ecdh,
+ 16#9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0,
+ 16#1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d,
+ x448,
+ hexstr2bin("07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d")},
+ {ecdh,
+ 16#3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609,
+ 16#9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b,
+ x448,
+ hexstr2bin("07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d")}
+ ],
lists:filter(fun ({_Type, _Pub, _Priv, Curve, _SharedSecret}) ->
lists:member(Curve, Curves)
end,
@@ -2303,6 +3775,8 @@ ecdh() ->
dh() ->
{dh, 90970053988169282502023478715631717259407236400413906591937635666709823903223997309250405131675572047545403771567755831138144089197560332757755059848492919215391041119286178688014693040542889497092308638580104031455627238700168892909539193174537248629499995652186913900511641708112112482297874449292467498403, 2}.
+
+
rsa_oaep() ->
%% ftp://ftp.rsa.com/pub/rsalabs/tmp/pkcs1v15crypt-vectors.txt
Public = [hexstr2bin("010001"),
@@ -2315,7 +3789,32 @@ rsa_oaep() ->
hexstr2bin("4f456c502493bdc0ed2ab756a3a6ed4d67352a697d4216e93212b127a63d5411ce6fa98d5dbefd73263e3728142743818166ed7dd63687dd2a8ca1d2f4fbd8e1")],
%%Msg = hexstr2bin("6628194e12073db03ba94cda9ef9532397d50dba79b987004afefe34"),
Msg = hexstr2bin("750c4047f547e8e41411856523298ac9bae245efaf1397fbe56f9dd5"),
- {rsa, Public, Private, Msg, rsa_pkcs1_oaep_padding}.
+ {rsa, Public, Private, Msg, [{rsa_padding, rsa_pkcs1_oaep_padding}]}.
+
+rsa_oaep_label() ->
+ Public = [hexstr2bin("010001"),
+ hexstr2bin("a8b3b284af8eb50b387034a860f146c4919f318763cd6c5598c8ae4811a1e0abc4c7e0b082d693a5e7fced675cf4668512772c0cbc64a742c6c630f533c8cc72f62ae833c40bf25842e984bb78bdbf97c0107d55bdb662f5c4e0fab9845cb5148ef7392dd3aaff93ae1e6b667bb3d4247616d4f5ba10d4cfd226de88d39f16fb")],
+ Private = Public ++ [hexstr2bin("53339cfdb79fc8466a655c7316aca85c55fd8f6dd898fdaf119517ef4f52e8fd8e258df93fee180fa0e4ab29693cd83b152a553d4ac4d1812b8b9fa5af0e7f55fe7304df41570926f3311f15c4d65a732c483116ee3d3d2d0af3549ad9bf7cbfb78ad884f84d5beb04724dc7369b31def37d0cf539e9cfcdd3de653729ead5d1"),
+ hexstr2bin("d32737e7267ffe1341b2d5c0d150a81b586fb3132bed2f8d5262864a9cb9f30af38be448598d413a172efb802c21acf1c11c520c2f26a471dcad212eac7ca39d"),
+ hexstr2bin("cc8853d1d54da630fac004f471f281c7b8982d8224a490edbeb33d3e3d5cc93c4765703d1dd791642f1f116a0dd852be2419b2af72bfe9a030e860b0288b5d77"),
+ hexstr2bin("0e12bf1718e9cef5599ba1c3882fe8046a90874eefce8f2ccc20e4f2741fb0a33a3848aec9c9305fbecbd2d76819967d4671acc6431e4037968db37878e695c1"),
+ hexstr2bin("95297b0f95a2fa67d00707d609dfd4fc05c89dafc2ef6d6ea55bec771ea333734d9251e79082ecda866efef13c459e1a631386b7e354c899f5f112ca85d71583"),
+ hexstr2bin("4f456c502493bdc0ed2ab756a3a6ed4d67352a697d4216e93212b127a63d5411ce6fa98d5dbefd73263e3728142743818166ed7dd63687dd2a8ca1d2f4fbd8e1")],
+ Msg = hexstr2bin("750c4047f547e8e41411856523298ac9bae245efaf1397fbe56f9dd5"),
+ Lbl = hexstr2bin("1332a67ca7088f75c9b8fb5e3d072882"),
+ {rsa, Public, Private, Msg, [{rsa_padding, rsa_pkcs1_oaep_padding}, {rsa_oaep_label, Lbl}]}.
+
+rsa_oaep256() ->
+ Public = [hexstr2bin("010001"),
+ hexstr2bin("a8b3b284af8eb50b387034a860f146c4919f318763cd6c5598c8ae4811a1e0abc4c7e0b082d693a5e7fced675cf4668512772c0cbc64a742c6c630f533c8cc72f62ae833c40bf25842e984bb78bdbf97c0107d55bdb662f5c4e0fab9845cb5148ef7392dd3aaff93ae1e6b667bb3d4247616d4f5ba10d4cfd226de88d39f16fb")],
+ Private = Public ++ [hexstr2bin("53339cfdb79fc8466a655c7316aca85c55fd8f6dd898fdaf119517ef4f52e8fd8e258df93fee180fa0e4ab29693cd83b152a553d4ac4d1812b8b9fa5af0e7f55fe7304df41570926f3311f15c4d65a732c483116ee3d3d2d0af3549ad9bf7cbfb78ad884f84d5beb04724dc7369b31def37d0cf539e9cfcdd3de653729ead5d1"),
+ hexstr2bin("d32737e7267ffe1341b2d5c0d150a81b586fb3132bed2f8d5262864a9cb9f30af38be448598d413a172efb802c21acf1c11c520c2f26a471dcad212eac7ca39d"),
+ hexstr2bin("cc8853d1d54da630fac004f471f281c7b8982d8224a490edbeb33d3e3d5cc93c4765703d1dd791642f1f116a0dd852be2419b2af72bfe9a030e860b0288b5d77"),
+ hexstr2bin("0e12bf1718e9cef5599ba1c3882fe8046a90874eefce8f2ccc20e4f2741fb0a33a3848aec9c9305fbecbd2d76819967d4671acc6431e4037968db37878e695c1"),
+ hexstr2bin("95297b0f95a2fa67d00707d609dfd4fc05c89dafc2ef6d6ea55bec771ea333734d9251e79082ecda866efef13c459e1a631386b7e354c899f5f112ca85d71583"),
+ hexstr2bin("4f456c502493bdc0ed2ab756a3a6ed4d67352a697d4216e93212b127a63d5411ce6fa98d5dbefd73263e3728142743818166ed7dd63687dd2a8ca1d2f4fbd8e1")],
+ Msg = hexstr2bin("750c4047f547e8e41411856523298ac9bae245efaf1397fbe56f9dd5"),
+ {rsa, Public, Private, Msg, [{rsa_padding, rsa_pkcs1_oaep_padding}, {rsa_oaep_md, sha256}]}.
ecc() ->
%% http://point-at-infinity.org/ecc/nisttv
@@ -2352,13 +3851,6 @@ cmac_nist(Config, aes_cbc256 = Type) ->
read_rsp(Config, Type,
["CMACGenAES256.rsp", "CMACVerAES256.rsp"]).
-no_padding() ->
- Public = [_, Mod] = rsa_public_stronger(),
- Private = rsa_private_stronger(),
- MsgLen = erlang:byte_size(int_to_bin(Mod)),
- Msg = list_to_binary(lists:duplicate(MsgLen, $X)),
- {rsa, Public, Private, Msg, rsa_no_padding}.
-
int_to_bin(X) when X < 0 -> int_to_bin_neg(X, []);
int_to_bin(X) -> int_to_bin_pos(X, []).
@@ -2400,29 +3892,45 @@ read_rsp(Config, Type, Files) ->
Tests =
lists:foldl(
fun(FileName, Acc) ->
- read_rsp_file(filename:join(datadir(Config), FileName),
- Type, Acc)
+ NewAcc = read_rsp_file(filename:join(datadir(Config), FileName),
+ Type, Acc),
+ ct:log("~p: ~p tests read.~n",[FileName,length(NewAcc)-length(Acc)]),
+ NewAcc
end, [], Files),
log_rsp_size(Type, Tests),
Tests.
read_rsp_file(FileName, Type, Acc) ->
- {ok, Raw} = file:read_file(FileName),
- Split = binary:split(Raw, [<<"\r">>, <<"\n">>], [global, trim_all]),
- parse_rsp(Type, Split, Acc).
+ case file:read_file(FileName) of
+ {ok, Raw} ->
+ Split = binary:split(Raw, [<<"\r">>, <<"\n">>], [global, trim_all]),
+ parse_rsp(Type, Split, #{file => FileName}, Acc);
+ Other ->
+ ct:fail("~p ~p",[FileName, Other])
+ end.
-parse_rsp(_Type, [], Acc) ->
+parse_rsp(_Type, [], _State, Acc) ->
+ Acc;
+parse_rsp(_Type, [<<"DECRYPT">>|_], _State, Acc) ->
Acc;
-parse_rsp(_Type, [<<"DECRYPT">>|_], Acc) ->
+parse_rsp(_Type, [<<"ENCRYPT">>|_], _State, Acc) ->
Acc;
%% AES format
parse_rsp(Type, [<<"COUNT = ", _/binary>>,
<<"KEY = ", Key/binary>>,
+ <<"PLAINTEXT = ", PlainText/binary>>,
+ <<"CIPHERTEXT = ", CipherText/binary>>|Next], State, Acc) ->
+ parse_rsp(Type, Next, State,
+ [{Type, hexstr2bin(Key),
+ hexstr2bin(PlainText), hexstr2bin(CipherText)}|Acc]);
+parse_rsp(Type, [<<"COUNT = ", _/binary>>,
+ <<"KEY = ", Key/binary>>,
<<"IV = ", IV/binary>>,
<<"PLAINTEXT = ", PlainText/binary>>,
- <<"CIPHERTEXT = ", CipherText/binary>>|Next], Acc) ->
- parse_rsp(Type, Next, [{Type, hexstr2bin(Key), hexstr2bin(IV),
- hexstr2bin(PlainText), hexstr2bin(CipherText)}|Acc]);
+ <<"CIPHERTEXT = ", CipherText/binary>>|Next], State, Acc) ->
+ parse_rsp(Type, Next, State,
+ [{Type, hexstr2bin(Key), hexstr2bin(IV),
+ hexstr2bin(PlainText), hexstr2bin(CipherText)}|Acc]);
%% CMAC format
parse_rsp(Type, [<<"Count = ", _/binary>>,
<<"Klen = ", _/binary>>,
@@ -2430,23 +3938,23 @@ parse_rsp(Type, [<<"Count = ", _/binary>>,
<<"Tlen = ", Tlen/binary>>,
<<"Key = ", Key/binary>>,
<<"Msg = ", Msg/binary>>,
- <<"Mac = ", MAC/binary>>|Rest], Acc) ->
+ <<"Mac = ", MAC/binary>>|Rest], State, Acc) ->
case Rest of
[<<"Result = P">>|Next] ->
- parse_rsp_cmac(Type, Key, Msg, Mlen, Tlen, MAC, Next, Acc);
+ parse_rsp_cmac(Type, Key, Msg, Mlen, Tlen, MAC, Next, State, Acc);
[<<"Result = ", _/binary>>|Next] ->
- parse_rsp(Type, Next, Acc);
+ parse_rsp(Type, Next, State, Acc);
_ ->
- parse_rsp_cmac(Type, Key, Msg, Mlen, Tlen, MAC, Rest, Acc)
+ parse_rsp_cmac(Type, Key, Msg, Mlen, Tlen, MAC, Rest, State, Acc)
end;
%% GCM format decode format
-parse_rsp(Type, [<<"Count = ", _/binary>>,
+parse_rsp(Type, [<<"Count = ", Count/binary>>,
<<"Key = ", Key/binary>>,
<<"IV = ", IV/binary>>,
<<"CT = ", CipherText/binary>>,
<<"AAD = ", AAD/binary>>,
<<"Tag = ", CipherTag0/binary>>,
- <<"PT = ", PlainText/binary>>|Next], Acc) ->
+ <<"PT = ", PlainText/binary>>|Next], #{file:=File}=State, Acc) ->
CipherTag = hexstr2bin(CipherTag0),
TestCase = {Type,
hexstr2bin(Key),
@@ -2455,16 +3963,17 @@ parse_rsp(Type, [<<"Count = ", _/binary>>,
hexstr2bin(AAD),
hexstr2bin(CipherText),
CipherTag,
- size(CipherTag)},
- parse_rsp(Type, Next, [TestCase|Acc]);
+ size(CipherTag),
+ {File,decstr2int(Count)}},
+ parse_rsp(Type, Next, State, [TestCase|Acc]);
%% GCM format encode format
-parse_rsp(Type, [<<"Count = ", _/binary>>,
+parse_rsp(Type, [<<"Count = ", Count/binary>>,
<<"Key = ", Key/binary>>,
<<"IV = ", IV/binary>>,
<<"PT = ", PlainText/binary>>,
<<"AAD = ", AAD/binary>>,
<<"CT = ", CipherText/binary>>,
- <<"Tag = ", CipherTag0/binary>>|Next], Acc) ->
+ <<"Tag = ", CipherTag0/binary>>|Next], #{file:=File}=State, Acc) ->
CipherTag = hexstr2bin(CipherTag0),
TestCase = {Type,
hexstr2bin(Key),
@@ -2473,13 +3982,88 @@ parse_rsp(Type, [<<"Count = ", _/binary>>,
hexstr2bin(AAD),
hexstr2bin(CipherText),
CipherTag,
- size(CipherTag)},
- parse_rsp(Type, Next, [TestCase|Acc]);
+ size(CipherTag),
+ {File,decstr2int(Count)}},
+ parse_rsp(Type, Next, State, [TestCase|Acc]);
+%% CCM-VADT format
+parse_rsp(Type, [<<"[Alen = ", AlenB0/binary>>|Next], State0, Acc) ->
+ AlenSize = size(AlenB0) - 1, % remove closing ']'
+ Alen = decstr2int(<<AlenB0:AlenSize/binary>>),
+ State = State0#{alen => Alen},
+ parse_rsp(Type, Next, State, Acc);
+parse_rsp(Type, [<<"[Nlen = ", NlenB0/binary>>|Next], State0, Acc) ->
+ NlenSize = size(NlenB0) - 1, % remove closing ']'
+ Nlen = decstr2int(<<NlenB0:NlenSize/binary>>),
+ State = State0#{nlen => Nlen},
+ parse_rsp(Type, Next, State, Acc);
+parse_rsp(Type, [<<"[Plen = ", PlenB0/binary>>|Next], State0, Acc) ->
+ PlenSize = size(PlenB0) - 1, % remove closing ']'
+ Plen = decstr2int(<<PlenB0:PlenSize/binary>>),
+ State = State0#{plen => Plen},
+ parse_rsp(Type, Next, State, Acc);
+parse_rsp(Type, [<<"[Tlen = ", TlenB0/binary>>|Next], State0, Acc) ->
+ TlenSize = size(TlenB0) - 1, % remove closing ']'
+ Tlen = decstr2int(<<TlenB0:TlenSize/binary>>),
+ State = State0#{tlen => Tlen},
+ parse_rsp(Type, Next, State, Acc);
+parse_rsp(Type, [<<"Alen = ", B/binary>>|Next], State0, Acc) ->
+ State = State0#{alen => decstr2int(B)},
+ parse_rsp(Type, Next, State, Acc);
+parse_rsp(Type, [<<"Plen = ", B/binary>>|Next], State0, Acc) ->
+ State = State0#{plen => decstr2int(B)},
+ parse_rsp(Type, Next, State, Acc);
+parse_rsp(Type, [<<"Count = ", B/binary>>|Next], State0, Acc) ->
+ State = State0#{count => B},
+ parse_rsp(Type, Next, State, Acc);
+parse_rsp(Type, [<<"Nlen = ", B/binary>>|Next], State0, Acc) ->
+ State = State0#{nlen => decstr2int(B)},
+ parse_rsp(Type, Next, State, Acc);
+parse_rsp(Type, [<<"Tlen = ", B/binary>>|Next], State0, Acc) ->
+ State = State0#{tlen => decstr2int(B)},
+ parse_rsp(Type, Next, State, Acc);
+parse_rsp(Type, [<<"Key = ",Key/binary>>|Next], State0, Acc) ->
+ State = State0#{key => hexstr2bin(Key)},
+ parse_rsp(Type, Next, State, Acc);
+parse_rsp(Type, [<<"Nonce = ",Nonce/binary>>|Next], State0, Acc) ->
+ State = State0#{nonce => hexstr2bin(Nonce)},
+ parse_rsp(Type, Next, State, Acc);
+parse_rsp(Type, [<<"Adata = ",Adata/binary>>|Next], State0, Acc) ->
+ State = State0#{adata => hexstr2bin(Adata)},
+ parse_rsp(Type, Next, State, Acc);
+parse_rsp(Type, [<<"Payload = ",Payload/binary>>|Next], State0, Acc) ->
+ State = State0#{payload => hexstr2bin(Payload)},
+ parse_rsp(Type, Next, State, Acc);
+parse_rsp(Type,
+ [<<"CT = ", CT/binary>>|Next],
+ #{count := Count,
+ file := File,
+ alen := Alen,
+ plen := Plen,
+ nlen := _Nlen,
+ tlen := Tlen,
+ key := Key,
+ nonce := IV,
+ adata := Adata,
+ payload := Payload
+ } = State, Acc) ->
+ AAD = <<Adata:Alen/binary>>,
+ PlainText = <<Payload:Plen/binary>>,
+ <<CipherText:Plen/binary, CipherTag:Tlen/binary>> = hexstr2bin(CT),
+ TestCase = {Type,
+ Key,
+ PlainText,
+ IV,
+ AAD,
+ CipherText,
+ CipherTag,
+ Tlen,
+ {File,decstr2int(Count)}},
+ parse_rsp(Type, Next, State, [TestCase|Acc]);
+parse_rsp(Type, [_|Next], State, Acc) ->
+ parse_rsp(Type, Next, State, Acc).
-parse_rsp(Type, [_|Next], Acc) ->
- parse_rsp(Type, Next, Acc).
-parse_rsp_cmac(Type, Key0, Msg0, Mlen0, Tlen, MAC0, Next, Acc) ->
+parse_rsp_cmac(Type, Key0, Msg0, Mlen0, Tlen, MAC0, Next, State, Acc) ->
Key = hexstr2bin(Key0),
Mlen = binary_to_integer(Mlen0),
<<Msg:Mlen/bytes, _/binary>> = hexstr2bin(Msg0),
@@ -2487,7 +4071,18 @@ parse_rsp_cmac(Type, Key0, Msg0, Mlen0, Tlen, MAC0, Next, Acc) ->
case binary_to_integer(Tlen) of
0 ->
- parse_rsp(Type, Next, [{Type, Key, Msg, MAC}|Acc]);
+ parse_rsp(Type, Next, State, [{Type, Key, Msg, MAC}|Acc]);
I ->
- parse_rsp(Type, Next, [{Type, Key, Msg, I, MAC}|Acc])
+ parse_rsp(Type, Next, State, [{Type, Key, Msg, I, MAC}|Acc])
end.
+
+api_errors_ecdh(Config) when is_list(Config) ->
+ %% Check that we don't segfault when fed garbage.
+ Test = fun(Others, Curve) ->
+ {_Pub, Priv} = crypto:generate_key(ecdh, Curve),
+ crypto:compute_key(ecdh, Others, Priv, Curve)
+ end,
+ Others = [gurka, 0, <<0>>],
+ Curves = [gaffel, 0, sect571r1],
+ [_= (catch Test(O, C)) || O <- Others, C <- Curves],
+ ok.
diff --git a/lib/crypto/test/crypto_SUITE_data/VADT128.rsp b/lib/crypto/test/crypto_SUITE_data/VADT128.rsp
new file mode 100644
index 0000000000..a4fe9130a0
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/VADT128.rsp
@@ -0,0 +1,1823 @@
+# CAVS 11.0
+# "CCM-VADT" information
+# AES Keylen: 128
+# Generated on Tue Mar 15 08:09:24 2011
+
+Plen = 24
+Nlen = 13
+Tlen = 16
+
+[Alen = 0]
+
+Key = d24a3d3dde8c84830280cb87abad0bb3
+Nonce = f1100035bb24a8d26004e0e24b
+
+Count = 0
+Adata = 00
+Payload = 7c86135ed9c2a515aaae0e9a208133897269220f30870006
+CT = 1faeb0ee2ca2cd52f0aa3966578344f24e69b742c4ab37ab1123301219c70599b7c373ad4b3ad67b
+
+Count = 1
+Adata = 00
+Payload = 48df73208cdc63d716752df7794807b1b2a80794a2433455
+CT = 2bf7d09079bc0b904c711a0b0e4a70ca8ea892d9566f03f8b77a140819f39ef045103e785e1df8c2
+
+Count = 2
+Adata = 00
+Payload = b99de8168e8c13ea4aef66bdb93133dff5d57e9837ff6ccb
+CT = dab54ba67bec7bad10eb5141ce3344a4c9d5ebd5c3d35b664b01098842a618390619b86e00850b2e
+
+Count = 3
+Adata = 00
+Payload = 09fc21ac4a1f43de29621cacf3ad84e055c6b220721af7ce
+CT = 6ad4821cbf7f2b9973662b5084aff39b69c6276d8636c0638bd518724ab84fb814fe7b5570769f7f
+
+Count = 4
+Adata = 00
+Payload = cb43320d7488dfd6eed9efd88f440ea3f6f77a0df09d0727
+CT = a86b91bd81e8b791b4ddd824f84679d8caf7ef4004b1308a7229cbcecef221570cee8345b38cd6ec
+
+Count = 5
+Adata = 00
+Payload = a350ed58c04473e113b9088b1fb9dad92807f6b63b0d690c
+CT = c0784ee835241ba649bd3f7768bbada2140763fbcf215ea1fee47fec27d7764e5e2819c850088bac
+
+Count = 6
+Adata = 00
+Payload = 0709e691faf41383fab5d1848a8eee77101d1c99e526a264
+CT = 642145210f947bc4a0b1e678fd8c990c2c1d89d4110a95c954d610bc1ab4bc9a8a28c7306f7c539e
+
+Count = 7
+Adata = 00
+Payload = e7b913c2f0630562eb1c16b3b1ed84090c011a15c09e5471
+CT = 8491b07205036d25b118214fc6eff37230018f5834b263dc2e31657ecc51f5ec8590482fc053230d
+
+Count = 8
+Adata = 00
+Payload = 6b909697074900d41ce8c7d559b229af11fb3cec334784d4
+CT = 08b83527f229689346ecf0292eb05ed42dfba9a1c76bb379d500827f2081b00397102f90fc9ccd88
+
+Count = 9
+Adata = 00
+Payload = 495ff03335bcb39a317b9ea3f8bb6306fa771f3c55adebce
+CT = 2a775383c0dcdbdd6b7fa95f8fb9147dc6778a71a181dc63e2e7997803029476598c0e8d4fc63857
+
+[Alen = 1]
+
+Key = 08b0da255d2083808a1b4d367090bacc
+Nonce = 777828b13679a9e2ca89568233
+
+Count = 10
+Adata = dd
+Payload = 1b156d7e2bf7c9a25ad91cff7b0b02161cb78ff9162286b0
+CT = e8b80af4960d5417c15726406e345c5c46831192b03432eed16b6282283e16602331bcca9d51ce76
+
+Count = 11
+Adata = c5
+Payload = 032fee9dbffccc751e6a1ee6d07bb218b3a7ec6bf5740ead
+CT = f0828917020651c085e42459c544ec52e99372005362baf308ebeed45f67ef8733737c9c6f82daad
+
+Count = 12
+Adata = 68
+Payload = 9c4cd65b92070bc382fd18146611defb4204acddfdf6b276
+CT = 6fe1b1d12ffd9676197322ab732e80b1183032b65be00628f9b477e3a23bfdfdb619c7bc531fbcce
+
+Count = 13
+Adata = be
+Payload = 2ff93ef2fc5fe2c297ace05f3f7585aed75ef90ade3acf89
+CT = dc54597841a57f770c22dae02a4adbe48d6a6761782c7bd7aa82130f5a86c0cd0433585e5c208cf7
+
+Count = 14
+Adata = 7a
+Payload = 62766e9acd41285eeed9b4007340dbb611699624274ad117
+CT = 91db091070bbb5eb75578ebf667f85fc4b5d084f815c65499d60012a2f25463e036ceecea57b3c97
+
+Count = 15
+Adata = 13
+Payload = ea689c268a04912d0527b16d9d9406df38302fb11cb64a99
+CT = 19c5fbac37fe0c989ea98bd288ab58956204b1dabaa0fec7e337897c90eb260729a729aed1c8a244
+
+Count = 16
+Adata = e5
+Payload = f31e35953beb211efcce487ba8c0cd1a8446343d5851b9fd
+CT = 00b3521f8611bcab674072c4bdff9350de72aa56fe470da373dc2911c75b37cd995481d42b04524a
+
+Count = 17
+Adata = e3
+Payload = c4ac3c645387584c2a95b1f16b8317730592924dd831a388
+CT = 37015beeee7dc5f9b11b8b4e7ebc49395fa60c267e2717d684f76ecf3dc5f3307ce982f185321248
+
+Count = 18
+Adata = d5
+Payload = 81af394c2ea3a85e1ea954596e3772f01635d007794c0b19
+CT = 72025ec6935935eb85276ee67b082cba4c014e6cdf5abf472c38d0fe4e4eba054c1420c39a3dcc61
+
+Count = 19
+Adata = ed
+Payload = e013a2edd5b86bab8df5c9940d0a0c864478c1ad42668304
+CT = 13bec5676842f61e167bf32b183552cc1e4c5fc6e470375a7cfa6c9945f5aee3c799eee37b0605db
+
+[Alen = 2]
+
+Key = 1538cc03b60880bf3e7d388e29f27739
+Nonce = 9e734de325026b5d7128193973
+
+Count = 20
+Adata = c93c
+Payload = e7b819a853ffe79baaa72097ff0d04f02640ae62bcfd3da5
+CT = 1d8f42f9730424fa27240bd6277f4882604f440324b11b003ca01d874439b4e1f79a26d8c6dc433a
+
+Count = 21
+Adata = 4cf9
+Payload = dc6cf325ed6d968efba9f57e48a58f4578cc3540fe121ba2
+CT = 265ba874cd9655ef762ade3f90d7c3373ec3df21665e3d07b40653cd23afc7cc7a31fa13ba8f4e49
+
+Count = 22
+Adata = b469
+Payload = 22ab6a0daf953165dda864cceeeb782e275c0b072aedd284
+CT = d89c315c8f6ef204502b4f8d3699345c6153e166b2a1f421c8c10aaf90b1116be216f912c82ca96a
+
+Count = 23
+Adata = cf6b
+Payload = a35f62a431fee63468dc02fdf7bef78d3a5937de56151939
+CT = 596839f511052555e55f29bc2fccbbff7c56ddbfce593f9c2f568ef41324189fb3644edcd76dc19c
+
+Count = 24
+Adata = af7c
+Payload = 548840cb0400824af809fb68447500b77e977128200d3b81
+CT = aebf1b9a24fb412b758ad0299c074cc538989b49b8411d242548c244a875d3681d715db3da19962f
+
+Count = 25
+Adata = 61dc
+Payload = 440b6095c77495e73fff54c785b7ceb5eb358731c213ffcd
+CT = be3c3bc4e78f5686b27c7f865dc582c7ad3a6d505a5fd968b599bc8927ad8d43067807f4b858f854
+
+Count = 26
+Adata = b97e
+Payload = 50c59ca54eb64575b82b13c6dac96488af369e9f5f86cdf2
+CT = aaf2c7f46e4d861435a8388702bb28fae93974fec7caeb577454774ee78f76e555cf743df340381e
+
+Count = 27
+Adata = 57ab
+Payload = 21b8eb1f0bda26ca36167ce7bc2e796818bf11fc8c192885
+CT = db8fb04e2b21e5abbb9557a6645c351a5eb0fb9d14550e20e0a22a5ee031978271c7dd2a0d4e7018
+
+Count = 28
+Adata = 5f9c
+Payload = b4d84fb1e81e18c89391a7a59fc05fedaf160e0d0d027a7c
+CT = 4eef14e0c8e5dba91e128ce447b2139fe919e46c954e5cd99a242ebae5c6da57ee38e5c227c46b32
+
+Count = 29
+Adata = e0c4
+Payload = 54dc5a0e1b67577cda4e7dbd48b769c120c1d13dd567cfad
+CT = aeeb015f3b9c941d57cd56fc90c525b366ce3b5c4d2be908a5f8a92f4201c4658289307167cee810
+
+[Alen = 3]
+
+Key = f149e41d848f59276cfddd743bafa9a9
+Nonce = 14b756d66fc51134e203d1c6f9
+
+Count = 30
+Adata = f5827e
+Payload = 9759e6f21f5a588010f57e6d6eae178d8b20ab59cda66f42
+CT = f634bf00f1f9f1f93f41049d7f3797b05e805f0b14850f4e78e2a23411147a6187da6818506232ee
+
+Count = 31
+Adata = e9699b
+Payload = 1555bc87d6c688fd221a2c75cd1e4dd1c1693207ac421d24
+CT = 7438e575386521840dae5685dc87cdec14c9c65575617d28f10835db9897b7528e3204fe3a81424f
+
+Count = 32
+Adata = 972896
+Payload = b72b2a080d92f3f3bb7d96222982de82a28c9eebaddba247
+CT = d64673fae3315a8a94c9ecd2381b5ebf772c6ab974f8c24b3efa05ba4a73ec2234461d459f54acd2
+
+Count = 33
+Adata = 3053f3
+Payload = b5417ed6933ffe2b57ea601d77e97eb12fa1fb8fdc06c86f
+CT = d42c27247d9c5752785e1aed6670fe8cfa010fdd0525a863b557537c6525e827750917a1ed49602f
+
+Count = 34
+Adata = 24db75
+Payload = 4e7f42666035a00e62783283c54b027603917685d27326bc
+CT = 2f121b948e9609774dcc4873d4d2824bd63182d70b5046b0dfd06b037e9094f120eb3d8649d48918
+
+Count = 35
+Adata = ff27a4
+Payload = 7bf180699c294421ad9565cacc27227a4b3a7cf9637290c6
+CT = 1a9cd99b728aed5882211f3addbea2479e9a88abba51f0cabfa8cfabbd79b3e3210482e6f3822fee
+
+Count = 36
+Adata = 77ec24
+Payload = 3d47071c13f994cb42fb2887e5c6e53a542be7ddad9779e0
+CT = 5c2a5eeefd5a3db26d4f5277f45f6507818b138f74b419ec3b9575e347051e98d0c8646ad46318e6
+
+Count = 37
+Adata = 6d7748
+Payload = 317d5da0a2ec12c3b96c83dd61cc955242a9c1c640e2b92f
+CT = 501004524c4fbbba96d8f92d7055156f9709359499c1d92378e7af65eb0388ae7a52f58f6ba32109
+
+Count = 38
+Adata = 029674
+Payload = c9bb21306ee1b4a6c4fa5443af2e181716993cbb374e177c
+CT = a8d678c280421ddfeb4e2eb3beb7982ac339c8e9ee6d77708019fa97ff70d4d21c0bd83caa434b3a
+
+Count = 39
+Adata = 60dfe8
+Payload = 44eb7edd6bee501ad97873aa7ecbf7ed8b613760d7c95e15
+CT = 2586272f854df963f6cc095a6f5277d05ec1c3320eea3e191814ed48a21d97ea02e86d7e6e8834cb
+
+[Alen = 4]
+
+Key = 9a57a22c7f26feff8ca6cceff214e4c2
+Nonce = 88f30fd2b04fb8ddbce8fc26e6
+
+Count = 40
+Adata = a95bdff6
+Payload = 035c516776c706a7dd5f181fa6aa891b04dd423042ea0667
+CT = b92f7ec2ebecebdbd2977b3874e61bf496a382153b2529fc9b6443a35f329b2068916fb6ab8227eb
+
+Count = 41
+Adata = d2672cbb
+Payload = 3ba306bcec94615c347f990b62841a16df7b321f113f1714
+CT = 81d0291971bf8c203bb7fa2cb0c888f94d05f23a68f0388f19e2aa492ce9ddfb6de0ab7a447f5351
+
+Count = 42
+Adata = 737f4d00
+Payload = 68313a29ace3efe521c3ca1e5bac8e98d6b4434c80a7dc74
+CT = d242158c31c802992e0ba93989e01c7744ca8369f968f3ef2bf683b1209f104e82ba39f7c62cd666
+
+Count = 43
+Adata = 3610b1ae
+Payload = 963bfe556138317bebe3936b18a2c1dd100dc73be6fde556
+CT = 2c48d1f0fc13dc07e42bf04ccaee53328273071e9f32cacd4fc7d5cac043f182edbe5c2658f73092
+
+Count = 44
+Adata = f1aa7f72
+Payload = 52d5c53ee4f23cb050a95db54112b44033c34ac31de96be8
+CT = e8a6ea9b79d9d1cc5f613e92935e26afa1bd8ae664264473b8234f3fbaca3dc2c497418219151b05
+
+Count = 45
+Adata = 6b1013aa
+Payload = a302aebc0f8fd61badc8371991beacf5933de46effacb8ce
+CT = 1971811992a43b67a200543e43f23e1a0143244b866397558fa5f9539e0500f139016e4a4337d86b
+
+Count = 46
+Adata = 33028129
+Payload = f7d653c23254875625b20e1ef60ae92847046d84bb4ce857
+CT = 4da57c67af7f6a2a2a7a6d3924467bc7d57aada1c283c7ccfa2379fde155e64b5b84e336056445c3
+
+Count = 47
+Adata = 2cab4a09
+Payload = 872a3f7230e626abff519e5aeecc93897249405daeaffc98
+CT = 3d5910d7adcdcbd7f099fd7d3c800166e0378078d760d30358208335cb81e4fb10923fca4ddb9ff9
+
+Count = 48
+Adata = 73142ba7
+Payload = 766f94e7d9b1ce74bbaf2c99d215350f060122767fc1953f
+CT = cc1cbb42449a2308b4674fbe0059a7e0947fe253060ebaa42d6ecfb49ac8983415503efef1e21950
+
+Count = 49
+Adata = bc9f967e
+Payload = 5f089ed9267363bc23c6c7b8f73208a36f61fa8ea8084ff7
+CT = e57bb17cbb588ec02c0ea49f257e9a4cfd1f3aabd1c7606c1978a62d15430fc20b87940292b49641
+
+[Alen = 5]
+
+Key = 54caf96ef6d448734700aadab50faf7a
+Nonce = a3803e752ae849c910d8da36af
+
+Count = 50
+Adata = 5f476348dd
+Payload = c69f7c5a50f3e72123371bbfd6bdf532b99ef78500508dfe
+CT = 20c43ad83610880249f1632dd418ec9a5ed333b50e996d1a4e5a32fbe7961b832b722bc07a18595b
+
+Count = 51
+Adata = 07db8aada5
+Payload = 9cf8b638f2b295b85cf782fabab11153dc091b4afcd761a9
+CT = 7aa3f0ba9451fa9b3631fa68b81408fb3b44df7af21e814d401a2222443696021b5faa520129b563
+
+Count = 52
+Adata = 31ef6561ff
+Payload = 62b8263dc015ef873cd16272e4da89799b910f2b04204420
+CT = 84e360bfa6f680a456171ae0e67f90d17cdccb1b0ae9a4c4f842681d2e90da5718234ed893197662
+
+Count = 53
+Adata = e97dfcbafb
+Payload = 810bed3a2bc0f9d75389155b7a39d9d014c08646814f9718
+CT = 6750abb84d2396f4394f6dc9789cc078f38d42768f8677fc33a08eb30ee154f71279682ab02eff27
+
+Count = 54
+Adata = 4981c51fcc
+Payload = 063d23fc3ec344c1ba3486802e01e55617455d5cfbfb5279
+CT = e066657e58202be2d0f2fe122ca4fcfef008996cf532b29d8d3071c79f0cf86fe4148cb5e8ace0ce
+
+Count = 55
+Adata = c8437dba76
+Payload = 41db5b245ea0fab985b93e7fc0a00cd3cca5bdbb642b7ebf
+CT = a7801da63843959aef7f46edc205157b2be8798b6ae29e5b842700619dc1599603f3f3f6cfdf5e0b
+
+Count = 56
+Adata = 6f65a24344
+Payload = b0e36734b2ba871d59df0b029c7f32af68e003a689ac4911
+CT = 56b821b6d459e83e331973909eda2b078fadc7968765a9f539a0cd8d8bbf211b907f34411f868c79
+
+Count = 57
+Adata = cd62d6d203
+Payload = 747e53e627eabde0cd77d78d1bd720bea518f8a2f76e57a2
+CT = 922515644109d2c3a7b1af1f1972391642553c92f9a7b746c4a90e5fc11266bab77eea1d24fbdbb9
+
+Count = 58
+Adata = 9663b3c8e6
+Payload = c70c92ec4c518802662fa4c41a6a33a22599f79f8f7264b3
+CT = 2157d46e2ab2e7210ce9dc5618cf2a0ac2d433af81bb8457b3c1246f7dd6462ce757db82db45f36e
+
+Count = 59
+Adata = 35c4720d3c
+Payload = a26835605b66fc08abdbb5dc77e39783d60b8e8f2314e95f
+CT = 443373e23d85932bc11dcd4e75468e2b31464abf2ddd09bbd472c06a5f4c04f97d06ec401d3e7fd9
+
+[Alen = 6]
+
+Key = cc0c084d7de011e2f031616a302e7a31
+Nonce = f0b4522847f6f8336fe534a4e7
+
+Count = 60
+Adata = da853a27aee2
+Payload = 15b369889699b6de1fa3ee73e5fe19814e46f129074c965b
+CT = f39755d160a64611368a8eccf6fcbc45ef7f1f56240eb19a2e3ca4ec3c776ab58843f617d605fd72
+
+Count = 61
+Adata = d4ed4584678e
+Payload = a18c0460b56a5bcd5bf6842cec6ed44d90b2bfa968a6a7e7
+CT = 47a838394355ab0272dfe493ff6c7189318b51d64be48026327804c44c8f17a4446a3d5ba85f9c7f
+
+Count = 62
+Adata = 590a27721a36
+Payload = 41cee0ecaf9c65cef740440af37954ef49a585779d2abbca
+CT = a7eadcb559a39501de6924b5e07bf12be89c6b08be689c0bbcd00e9cb726d75e4283820ee81d933a
+
+Count = 63
+Adata = 58830fb0b1f3
+Payload = dce983e4e3734a9bd8848dba0d744d07bbeba602f4006025
+CT = 3acdbfbd154cba54f1aded051e76e8c31ad2487dd74247e4d5d71a1f0f1b6518c35f0632a30931fd
+
+Count = 64
+Adata = eedd0d767a25
+Payload = 4653b3e879ab18b65c5c3706a5139698262cb830a22d943b
+CT = a0778fb18f94e879757557b9b611335c8715564f816fb3fa3ad112899e9ba442660eb5dfe33b2f96
+
+Count = 65
+Adata = 618bcf2e3e79
+Payload = 8586383281925363ac15fb19c26d64c639c75920c792dc2c
+CT = 63a2046b77ada3ac853c9ba6d16fc10298feb75fe4d0fbed54fba446028919342b2fe86ee67efcc7
+
+Count = 66
+Adata = 549c9b84c7f7
+Payload = 95c25ae4445cd8c4d267df82687484667e309992fcf1e737
+CT = 73e666bdb263280bfb4ebf3d7b7621a2df0977eddfb3c0f69fc23013142f62881ccfa3037067e1ef
+
+Count = 67
+Adata = 92d7fa6a8135
+Payload = e58034bbb0e6f5e724e32ee56896dadae25c2a3efb8c6f2f
+CT = 03a408e246d905280dca4e5a7b947f1e4365c441d8ce48ee8263568d56fae8bf35b2f2cdecbffe0a
+
+Count = 68
+Adata = f43e126c0f83
+Payload = d98f0dddfe9cb3cae1336970d5efb55316a65e2c51e316f4
+CT = 3fab318408a34305c81a09cfc6ed1097b79fb05372a13135de2c2fbfdddc7dd6672714af174c5121
+
+Count = 69
+Adata = f02074812dde
+Payload = 548747b1669c6383b793054d93957f9e99d605761c6c23b5
+CT = b2a37be890a3934c9eba65f28097da5a38efeb093f2e04743704560ff23ce0000fba8812c45940ad
+
+[Alen = 7]
+
+Key = d7572ed0e37261efa02f8c83e695efdc
+Nonce = f4f96d7b4384a3930b3d830f82
+
+Count = 70
+Adata = 922340ec94861f
+Payload = 1edef80c57d17f969f8bde10ab38a1a8811a124de72c526e
+CT = de14558cc686e1836f1f121ea1b941a9ebd4f0fb916dc870fd541b988a801cb5751c7faaf5b0c164
+
+Count = 71
+Adata = 4eb379f21b1531
+Payload = ddd5282a207c1dcb03c1c3bbc9eb12a7bd28534118db2735
+CT = 1d1f85aab12b83def3550fb5c36af2a6d7e6b1f76e9abd2bc068bd1b1c309dfbd52d9a24be07c630
+
+Count = 72
+Adata = 7fa89e9d6e3fec
+Payload = c5b7c462eb166f48bb59c8102ee7b3dc67a28e5de7570c51
+CT = 057d69e27a41f15d4bcd041e246653dd0d6c6ceb9116964f2d114d6ab082738d05d60acca8e8ccfb
+
+Count = 73
+Adata = fda8665f87c618
+Payload = af793815e147e3180f5146aa6a582e343dc479f26b4226b2
+CT = 6fb3959570107d0dffc58aa460d9ce35570a9b441d03bcac1cc84bd77fe00e1a13433f2c10e3b799
+
+Count = 74
+Adata = 46bde207491ebd
+Payload = 47c76a0bbd5b1616b278089d41a050c509c7a1c280574bf7
+CT = 870dc78b2c0c880342ecc4934b21b0c463094374f616d1e9990c81f1bae32c953bf02ddbde047632
+
+Count = 75
+Adata = a799f5f895fd7a
+Payload = d554806ffc3900a0952a3c094c745808950697a6e5d62c1d
+CT = 159e2def6d6e9eb565bef00746f5b809ffc875109397b6031af19f1f080dd1dd2da799059755e49f
+
+Count = 76
+Adata = 20225831a9ee06
+Payload = ba45e1859efae362a44a0116a14e488ba369da6c76c3913b
+CT = 7a8f4c050fad7d7754decd18abcfa88ac9a738da00820b2523d3b9a0060834ac4860dae0eac570ef
+
+Count = 77
+Adata = 785360916464eb
+Payload = 57bc338946ff78cf76adf5021e2e44e34e687fb68ad703f3
+CT = 97769e09d7a8e6da8639390c14afa4e224a69d00fc9699edff96e7cf841a66c50bbb6fb2bac7ef51
+
+Count = 78
+Adata = 57b946369226db
+Payload = 9ac5be9929c4fe5a9992749a38dc69874866db3d4747da97
+CT = 5a0f1319b893604f6906b894325d898622a8398b3106408986e1c33a45f9d52755c374650635bef6
+
+Count = 79
+Adata = 73e4da8973c1e3
+Payload = 5a05410aa3a71f5f1a253b8576eba269c06a4c30591144cc
+CT = 9acfec8a32f0814aeab1f78b7c6a4268aaa4ae862f50ded2d78592c2d89c15edc5bb7486aa93f896
+
+[Alen = 8]
+
+Key = 98a42d7a0c5917deaf3b4de3f0cbe0a1
+Nonce = 03d33ab0c2df7bfce88b5ee4c4
+
+Count = 80
+Adata = 2d5438b728b950d9
+Payload = 9aa9c8358117564371366beeec923051ef433252197aaad5
+CT = 9ff942baa60f440c17a78e9581216b9a947a67f04d54911feecfff971fdfaa856310b014aa59c978
+
+Count = 81
+Adata = 6e430b497a16e7f5
+Payload = 5758a500978c71a9b90f6e5beae9d96ef05a41486b10ea2e
+CT = 52082f8fb09463e6df9e8b20875a82a58b6314ea3f3ed1e46a4d7b4b4df6c831ee32116ee4dad98c
+
+Count = 82
+Adata = e12f98507d6514c3
+Payload = 49efe18c76a8355127d914a3a830c1c6ff2a163d728526e1
+CT = 4cbf6b0351b0271e4148f1d8c5839a0d8413439f26ab1d2b3243fc75cd1624e152f451678edcac87
+
+Count = 83
+Adata = eecf8d641ee0bee9
+Payload = 49ae2309fbe6ce4e9421516b8f79ae64b1316cb849eaf638
+CT = 4cfea986dcfedc01f2b0b410e2caf5afca08391a1dc4cdf2dd6d8ca57da1880e1baff43736b3da34
+
+Count = 84
+Adata = 9066367c784de0a4
+Payload = b1bda5fa4242aa6aad0f5a5b1d31d86b8d4a97588b3e315d
+CT = b4ed2f75655ab825cb9ebf20708283a0f673c2fadf100a97f05439a661001513a96b896de46b7081
+
+Count = 85
+Adata = edf848b2510f7803
+Payload = eaa8608f6763d968576a7e89056b9828a1686c8441b06377
+CT = eff8ea00407bcb2731fb9bf268d8c3e3da513926159e58bdcf20709b2dc2ff9946094190b5ea09d1
+
+Count = 86
+Adata = 0f49cae81c8628d2
+Payload = f32029cf51609f0df9832ad1b283ea94a5356f70112c1328
+CT = f670a34076788d429f12cfaadf30b15fde0c3ad2450228e2a5bb6b4f87b9b198665203e4fdf9e7f7
+
+Count = 87
+Adata = b0c47e9cce46a276
+Payload = 7a550ef9254a8da6e4fee290a76ea838ffb61d3533d4d31f
+CT = 7f05847602529fe9826f07ebcaddf3f3848f489767fae8d529f416f89f1a34bbbf2ce40d943c6d8b
+
+Count = 88
+Adata = a6fe7c9ce2d49f85
+Payload = e67c486dd7ba9a9061844b9354f55890321ae626efaa28cc
+CT = e32cc2e2f0a288df0715aee83946035b4923b384bb8413067eb95550b91b955d5c2d72d5c189b704
+
+Count = 89
+Adata = eb1d11cc4876f58f
+Payload = 35f2c810091e930a52e4a3f28c9c8184967f1554c2675eb5
+CT = 30a2429f2e06814534754689e12fda4fed4640f69649657f0e8e8a5a7e0ea6860bab4a4320f03ae5
+
+[Alen = 9]
+
+Key = 2a68e3fe746f593c1b97cb637079c3e5
+Nonce = cd62d0f27b7f4864dc7c343acd
+
+Count = 90
+Adata = abe4f1d3812bfe3ccf
+Payload = 13b4a874888db0e5d8fd814b5e7e04f7fdfbc1601ccc02bc
+CT = 032835a3dbf688d09cf2a32a92b101959d33ff47500f92f4fd49840440f866d1a22b0854996111d8
+
+Count = 91
+Adata = 2e21f466814d3d6340
+Payload = 08b5c773364cded74d7b308984313c17ff90eed496a27a2b
+CT = 18295aa46537e6e2097412e848fe39759f58d0f3da61ea63de2f5c335df537fbbc6ae59cd562732f
+
+Count = 92
+Adata = dba22aabcea0e694fc
+Payload = bbac1790abb7aafe272ec472c897e6363e335b3c4126c762
+CT = ab308a47f8cc92cb6321e6130458e3545efb651b0de5572acc5ed6e4a907ff4742ab6c835a427f92
+
+Count = 93
+Adata = 97e9d16bd757395ec1
+Payload = 7249612dc09809bbca9dd311e720f7da2cb54ce33e3eb9c3
+CT = 62d5fcfa93e3318e8e92f1702beff2b84c7d72c472fd298b1714b5a3df454f3bc35869da75adc882
+
+Count = 94
+Adata = 866cf710470cac74d3
+Payload = 060ae0ab9857324a3b2ac79f3b6e6f90f5de884ce9c7b930
+CT = 16967d7ccb2c0a7f7f25e5fef7a16af29516b66ba5042978aa33dffe2596832f98a9c8413bd898b9
+
+Count = 95
+Adata = 2dd7a7f832b29ccce2
+Payload = f77a9fd5363836deefd34e1bea0882484a7ab746b4495d59
+CT = e7e6020265430eebabdc6c7a26c7872a2ab28961f88acd11dd5049f7c53d6a7fe5d7f959689ee960
+
+Count = 96
+Adata = 502349a60e897356b5
+Payload = 96118dbfe53434d8aed88769a535eb0c8b5849dca1c81c34
+CT = 868d1068b64f0cedead7a50869faee6eeb9077fbed0b8c7ced9c3a0d0de8788471c5f6c2f9638b7c
+
+Count = 97
+Adata = debed45c9acf129268
+Payload = df5a47d3eb5c0b6cabb6711a45400602d205b82ecae9e849
+CT = cfc6da04b8273359efb9537b898f0360b2cd8609862a7801d49b4b9bead1b7de2021cff280d6f93b
+
+Count = 98
+Adata = 2726702dd62a6e5344
+Payload = 5a7649cb001fbb6f653cbca17756c5c1a078c2e240d92085
+CT = 4aead41c5364835a21339ec0bb99c0a3c0b0fcc50c1ab0cd69df31aba209d87ee22bd6a1dcadb168
+
+Count = 99
+Adata = e8006cfb0536696ac7
+Payload = 95186d41f927cdbef42157f21d966e88061b6558b5ec932f
+CT = 8584f096aa5cf58bb02e7593d1596bea66d35b7ff92f03677cc5b60c881fe834a789d28447d8fb54
+
+[Alen = 10]
+
+Key = 46b067cf9b1a28cf187002e90b14e130
+Nonce = bad8c03292bf01cfd8d34f860c
+
+Count = 100
+Adata = 8d65880eddb9fd96d276
+Payload = cc0915194218d4536e467433cd6d79ff1d9eb9ff160ab684
+CT = bd56edc015692c6ab9bec493a9893863598414a3d11a6a0f27ecdcb257d0d30491e5bf1aa8f90958
+
+Count = 101
+Adata = 8a65cde13149d9d54a5b
+Payload = 28257133b1d8b0b2be4faecd6e819ac783707a5c5f50c302
+CT = 597a89eae6a9488b69b71e6d0a65db5bc76ad70098401f89b10f9fc201e4128696dcd899dd2e24ea
+
+Count = 102
+Adata = e999ec3e1bfb25b5877c
+Payload = 96ab0cfc204bafc4f5851d6c682d631d0c5ad03ac925a943
+CT = e7f4f425773a57fd227dadcc0cc9228148407d660e3575c8c522e5ba5adbc6a639cbd06f103ebc9e
+
+Count = 103
+Adata = a8554441e073d6065dce
+Payload = 50925853a84a33ff392154e4e737efc18dcfc98f4d5235a9
+CT = 21cda08aff3bcbc6eed9e44483d3ae5dc9d564d38a42e922e1a4e0f7ebc3cff3915d27971cce7e91
+
+Count = 104
+Adata = 838f0be8d04d28d77549
+Payload = d0700658d5f4010ff21091f3d119c99645e339198029c3a9
+CT = a12ffe818285f93625e82153b5fd880a01f9944547391f22c215c88d80bffc881aff10ba40f11976
+
+Count = 105
+Adata = 20f014d928d5b25fbaf4
+Payload = 4bdf28748a0c281dd49c7294ae8e55fe7a52d45ff6384db3
+CT = 3a80d0addd7dd0240364c234ca6a14623e487903312891382cc9391bc06aa6ca9d486a4e2a218c54
+
+Count = 106
+Adata = 56c026b8a71974ff7ecd
+Payload = f75db057f0276fff85014f54ecdec8f90b96a2a982db14cb
+CT = 8602488ea75697c652f9fff4883a89654f8c0ff545cbc840778b05c6c582a0bb7d1d9dcf6a46b9f6
+
+Count = 107
+Adata = 75c3b9e52648a4f9aca9
+Payload = c15c554169dbb9b08494afaa44819a10dc9ddad54199ab54
+CT = b003ad983eaa4189536c1f0a2065db8c98877789868977dff47d9ebbd3cff14623b10cecc94b53d6
+
+Count = 108
+Adata = 1c76c3014a14b7fa1ca8
+Payload = 19eef6f798fc68086aad1cda6d7976cdcfe6b8af74598032
+CT = 68b10e2ecf8d9031bd55ac7a099d37518bfc15f3b3495cb9d2b74b84dc170c00dce85b56e346a976
+
+Count = 109
+Adata = a4eb60d4eb7ead1bd0e6
+Payload = e06e5dba5ac35cfd07949e5cc12ad70507d4a86a952ecca3
+CT = 9131a5630db2a4c4d06c2efca5ce969943ce0536523e1028d92e19fd8b5c1fcbff36adaa5e47ae84
+
+[Alen = 11]
+
+Key = e94dac9c90984790a7c0c867536615ff
+Nonce = c19f06f91e645d4199365f18c0
+
+Count = 110
+Adata = 537038b5357e358a930bd6
+Payload = 4d64461c55eb16bf7b9120f22be349598f2f394da8460dc6
+CT = e9fc5004c2359724e1e4411ae6f834ef6bea046d549753c88790c1648f461a31c84e62ea8592a074
+
+Count = 111
+Adata = 7e3d7b3eada988668f3784
+Payload = eab7d5dbd91d4cbbac8d79fadd70b5dcb3baadac5cb713a3
+CT = 4e2fc3c34ec3cd2036f81812106bc86a577f908ca0664dadacb1d1c9231d2c22ecfeed622792dfd0
+
+Count = 112
+Adata = 78b107b29c4878ff18f749
+Payload = 3c6ae2e2578875a1f5611582528e058aece2ddc33a4dde3d
+CT = 98f2f4fac056f43a6f14746a9f95783c0827e0e3c69c8033fffe60299768f048e7098033cde046b0
+
+Count = 113
+Adata = d293908bb516c5f3a411b9
+Payload = d7a46e726ed43f1580eb52141a93390982cc809dc833e3f0
+CT = 733c786af90abe8e1a9e33fcd78844bf6609bdbd34e2bdfe4ee6ebc0d90a0de05b428495c93e1801
+
+Count = 114
+Adata = 33ef208faad4d2948c9e67
+Payload = b1fe5d9d34157193fc0608cd8ecb872e17720f5f6814a466
+CT = 15664b85a3cbf0086673692543d0fa98f3b7327f94c5fa687e7e64cc0fcd6a92c79ceb6ce2abd8ee
+
+Count = 115
+Adata = b7f7ed9ccac3c2b4fbfee0
+Payload = de6bb539fb7a9c87414f62a7cf25a4cfca176509e991af41
+CT = 7af3a3216ca41d1cdb3a034f023ed9792ed258291540f14fb02b53bc779e0976b634b0d1b88fc0a9
+
+Count = 116
+Adata = a6e287383927f76e4927af
+Payload = 8719d20c20c8959068b8adcd65e6f6bc7b3693828f0735a0
+CT = 2381c414b716140bf2cdcc25a8fd8b0a9ff3aea273d66bae3c37fa936243b393f07fcccb0fc13e41
+
+Count = 117
+Adata = 70828be6dd93954f4e7b6b
+Payload = 30b39426831f61c8ba5f2ef5b71f0c4b2f916e3b5a578110
+CT = 942b823e14c1e053202a4f1d7a0471fdcb54531ba686df1e0d7534a489e6d242966ebea4455f8f79
+
+Count = 118
+Adata = 506015fc2831df293f4da0
+Payload = 818d5d810f678629f078723f5c6c3657271077533bfb7c29
+CT = 25154b9998b907b26a0d13d791774be1c3d54a73c72a2227ccbf64f04e95b180d09e843847d22104
+
+Count = 119
+Adata = e9394b0245b379e68e3dea
+Payload = f0613205a7a0822849df9e8a3cf6caf281f3adfa966c5507
+CT = 54f9241d307e03b3d3aaff62f1edb744653690da6abd0b0927b546ef8cd717073832584fb25a0645
+
+[Alen = 12]
+
+Key = f6bb5d59b0fa9de0828b115303bf94aa
+Nonce = 05358f33e1fc6a53ab5a5c98ce
+
+Count = 120
+Adata = 040b25771239cc2a39446e3c
+Payload = 011fc50329bfd63a85ebd4f7693363602f1a4147371270b7
+CT = 4432d7eb42980734d34f19c50cf8abf71ac1b19ed75a727854e5d050a405f755047d09cb0f49546a
+
+Count = 121
+Adata = 50a1d37fa2f3462bd304631b
+Payload = c90e40540d372ab1eb00ea5d5b8de5bf7c94ce4e376d6949
+CT = 8c2352bc6610fbbfbda4276f3e462d28494f3e97d7256b862abee8547ee3f24cfa677468ecc1d121
+
+Count = 122
+Adata = ac3bb872a41df35e415d2b0c
+Payload = 9e7be78c0ab9e6a4c6c257e77c63681bea35d951f168b0c5
+CT = db56f564619e37aa90669ad519a8a08cdfee29881120b20a61cef865ce4080e7c7abfc43f62c03a3
+
+Count = 123
+Adata = e3106ae6456153dd922640a1
+Payload = 00df0c5a5d3eceb2bd293066529799544f846672a9a1d31b
+CT = 45f21eb236191fbceb8dfd54375c51c37a5f96ab49e9d1d4e1d19c321a1e0852adba939b447220ab
+
+Count = 124
+Adata = 297b4498bf5427e6341aa927
+Payload = 14967a0476dbaea03b07fa8d40d344eabaf479be2443243a
+CT = 51bb68ec1dfc7fae6da337bf25188c7d8f2f8967c40b26f579ea5fb65018abdcde1a39f6859ecb56
+
+Count = 125
+Adata = 5de60dc0e3b5bda0b33a9520
+Payload = 2da3716d76d10b6766a1f9cbf9f420316fd5f396e7b9a2ba
+CT = 688e63851df6da69300534f99c3fe8a65a0e034f07f1a075c2629ff871ee15745fd8c1ddbdae4c29
+
+Count = 126
+Adata = 1c9b8541943ad50b4243c179
+Payload = 8c1b3ba18d1f5cff74a457aadd6b3e7d093d06ad2622e6a0
+CT = c9362949e6388df122009a98b8a0f6ea3ce6f674c66ae46f04e198ad16ad1106d3ba6172f4a13a8f
+
+Count = 127
+Adata = 51e926d2542ac8faef61465a
+Payload = 88936e97db070c0ec2aa58d1c6f5b34df3d32ddf7db34a8b
+CT = cdbe7c7fb020dd00940e95e3a33e7bdac608dd069dfb484475981131e3934ec6d41e00d502729799
+
+Count = 128
+Adata = ebefbac97b363e6f32526aac
+Payload = c20742e4b410c5b661da373a905fb0ed55b20e0e879eff5c
+CT = 872a500cdf3714b8377efa08f594787a6069fed767d6fd93e2c005b5bebe07ff578b1b4bc51971cd
+
+Count = 129
+Adata = 1ef059ac7d648e9e32d9b1f2
+Payload = 65c55ca21a89a8325365bf2be861d700559de2eabb41b37f
+CT = 20e84e4a71ae793c05c172198daa1f97604612335b09b1b021a25f15b5b4229a872a9199972c85b3
+
+[Alen = 13]
+
+Key = d1da2e961e78063af8de41865b226873
+Nonce = 03739f5474857006340cce554d
+
+Count = 130
+Adata = e3afd091d2b588465872a6300f
+Payload = 8e5fa1a6662a8378cda15697e926841594f2f394fa5a34ab
+CT = ca0d95e3ff186ad6b88d45fc4079e6b7b4a615e7e8dd5f4742d522cc9dc19c47a4fa0b1528069cf8
+
+Count = 131
+Adata = ce3186bb737753b59ee76b748c
+Payload = 311ebc5ff2f625944562ea699b2690df3e6e64a17c62bd3a
+CT = 754c881a6bc4cc3a304ef9023279f27d1e3a82d26ee5d6d659b26510b8f25610799e011d7c850ecd
+
+Count = 132
+Adata = bfd636989dfbcb0edc9f014cc8
+Payload = c96cee5ba7b799f16254a17b1870cdb85fe0ef3f42110c13
+CT = 8d3eda1e3e85705f1778b210b12faf1a7fb4094c509667ff52942aa0d39649f3d9ed535bebc2b603
+
+Count = 133
+Adata = 4812b092aa59d57451bfd812c3
+Payload = 13b1b4404dc5735655139414fcbd02c5327ae9fb148bd324
+CT = 57e38005d4f79af8203f877f55e26067122e0f88060cb8c8c1e61efb9c1d84ddac2d24f43531f569
+
+Count = 134
+Adata = f6ef9ac4f4c9ce1e4309c64fa8
+Payload = 6c5b59319e2710f5d63407f85b424d1860425ef8ce0cfe53
+CT = 28096d740715f95ba3181493f21d2fba4016b88bdc8b95bf13350de0ef34df12fb945b0ae0a0d9bd
+
+Count = 135
+Adata = 9bf12168bb3d79ebd25262f2b4
+Payload = 968e1d78008da78611e82985c4028e86770858cfe61c3723
+CT = d2dc293d99bf4e2864c43aee6d5dec24575cbebcf49b5ccfa0734563638598d8c4bf1fcd94009925
+
+Count = 136
+Adata = 7d870d7e52d3053c65eefad477
+Payload = 6a1306d911434cc7400d2f9a95e36aedceddca2b3d583f51
+CT = 2e41329c8871a56935213cf13cbc084fee892c582fdf54bda1f5fc53b08aca82bccfba6fbcb27e69
+
+Count = 137
+Adata = e95099f04371e445e5eaa1d80e
+Payload = b9197eb50c8168d16b8a12bd261d553ffcc521d979b26fee
+CT = fd4b4af095b3817f1ea601d68f42379ddc91c7aa6b3504027d1a922953facbd630d7fea6b63594ec
+
+Count = 138
+Adata = 3e80eb03db6545204ef4241ad6
+Payload = 95f59e36eac8eb3b51709d635b07fa2da0976ea20e25807f
+CT = d1a7aa7373fa0295245c8e08f258988f80c388d11ca2eb9383fa000d10078256b71249d9d1f1846c
+
+Count = 139
+Adata = 9748798c0f3cc766795c8ce0e4
+Payload = a48db9add9ecdeb49e51d3ab7bb2075202ed2aa50c0195b1
+CT = e0df8de840de371aeb7dc0c0d2ed65f022b9ccd61e86fe5d2773c2f55b752477c489facee812c614
+
+[Alen = 14]
+
+Key = 1eee667267ef10b03624cf9c341e3f75
+Nonce = 0630a3eae27e505c61c56e6560
+
+Count = 140
+Adata = d24651ef0561282d3e20e834960c
+Payload = 798e31cce0a83702a95171fb1162a17b9ce00ec3592ce262
+CT = f3c3e52f1a1ff528a8d3783ee4e75f114e3e6416334815d2d9236d5c5c9319092078411b72c51ba8
+
+Count = 141
+Adata = c527d309ab29ee91c5fc53117e71
+Payload = d79cd4c8891ec4ce2c51136712d23b32266b2b73768aeb1e
+CT = 5dd1002b73a906e42dd31aa2e757c558f4b541a61cee1caed8ad2a48cb734e3f93e602c15c7c775e
+
+Count = 142
+Adata = a93dfc3944514ddfc5acdd89fab7
+Payload = d7fa81c949f1f2af29dbd56529b307e3b348e996d0936455
+CT = 5db7552ab34630852859dca0dc36f98961968343baf793e5f34b297f3f106a9cdae255f7634fbd0f
+
+Count = 143
+Adata = e502abe21c7b22120693a08ef3e6
+Payload = 6330caaeddf0473d564d175b9408c6f12e6d3cd4ee2c423f
+CT = e97d1e4d2747851757cf1e9e618d389bfcb356018448b58f4f5d9c3dbfe3e2fe03a002e55039ebe6
+
+Count = 144
+Adata = a49b34dfad43333fb2ffd701a2d6
+Payload = 45671482c390e65f75de15ca91b93596e9bf3d6fc9178bcb
+CT = cf2ac06139272475745c1c0f643ccbfc3b6157baa3737c7b6f7bb0749c99d75740f2d193fef36c60
+
+Count = 145
+Adata = 9e4d8aa3dbdc4d4b4b8d72734f52
+Payload = c8f34bea8bdc403a48d8ed9268429141cd03c29558050ef4
+CT = 42be9f09716b8210495ae4579dc76f2b1fdda8403261f944ceec82fc674da9efa6926e8641729ed8
+
+Count = 146
+Adata = 052327ad59cc791259817fd0ed96
+Payload = d8d1c57b16c23894b66023c29f8648ce4a6074647e1f5f69
+CT = 529c1198ec75fabeb7e22a076a03b6a498be1eb1147ba8d92ff19e93f60c8f3a511300fddc38ee59
+
+Count = 147
+Adata = 14bc3c44c001ccb261a2a0526523
+Payload = 71c14a7031033db15bfe23b75fed9daf8886dd11392a0b78
+CT = fb8c9e93cbb4ff9b5a7c2a72aa6863c55a58b7c4534efcc87fa00fb244eda0d77cf6c05c8fd590af
+
+Count = 148
+Adata = 3477384c396a9e9efb3e169722cb
+Payload = afa795f836763a1210bb36fef167864f73ba3b6abc593537
+CT = 25ea411bccc1f83811393f3b04e27825a16451bfd63dc287bae19612657c87d3bb73cfb8cee7c8a8
+
+Count = 149
+Adata = 0c3b9a6924ad506038cb2d6590c9
+Payload = ca4a186f116a179579e3d327aec3f5be358bc7094f853bc3
+CT = 4007cc8cebddd5bf7861dae25b460bd4e755addc25e1cc733d9713d2e916c23ac3039de34c295fc4
+
+[Alen = 15]
+
+Key = dbbd26f5d9e970e4e384b2273961be5a
+Nonce = 0b1eabe504ef4822542e397fec
+
+Count = 150
+Adata = 477937301c83ba02d50760b603e0ea
+Payload = 553714e17a208a2eceb847a4a2d95088388b1ac8d8ca43e0
+CT = 1c80213268bad5402c4dc9b5d836ab7499810d0d8a974716df9a0e986ab2890736423bb3772cec3e
+
+Count = 151
+Adata = c91eb5a07ff19c044023e5cf339203
+Payload = c94d0b9e728413c58202cb3f6b82dba7aa9e3ca0a72c40c7
+CT = 80fa3e4d601e4cab60f7452e116d205b0b942b65f571443139f907a92cb01215e3cda84ae13af48b
+
+Count = 152
+Adata = 38c71a8e9b279c605c7f0418a0afc1
+Payload = b4e8c4fd5ad98a1be8b5a11677c57ca1c1694e3528092aa9
+CT = fd5ff12e4843d5750a402f070d2a875d606359f07a542e5f3dbd8dbf7485106cdf9ea0e7088a5650
+
+Count = 153
+Adata = f2c76ef617fa2bfc8a4d6bcbb15fe8
+Payload = 578ce26cdb5ba2e8798e23588e5cd04ef782820b80e49a42
+CT = 1e3bd7bfc9c1fd869b7bad49f4b32bb2568895ced2b99eb4853fde6f4dca88ff11bbce20ed9e5012
+
+Count = 154
+Adata = 36004342dd74e7966692a848b2c11e
+Payload = 78733c635d4d4e8b0729732f1e174dfcec4e020a7ac3870d
+CT = 31c409b04fd711e5e5dcfd3e64f8b6004d4415cf289e83fbd94e979108fcecbd32f6bdf72f0ccb4d
+
+Count = 155
+Adata = db92bc3fe5d4141aeb39baea6f114c
+Payload = c7aafe7760945e45703c1e19f1032dfd56ddc216c3b03826
+CT = 8e1dcba4720e012b92c990088becd601f7d7d5d391ed3cd0229c8f9d4e39fc16cbdb44236ef125c7
+
+Count = 156
+Adata = 34ec2d5b6f0d950509b47a0637d74c
+Payload = 2345e36a63be0b78df95e60907c78da0e48e61e70685a1f3
+CT = 6af2d6b9712454163d6068187d28765c4584762254d8a5051c9ab7cb0a779c3fa78c9ee12603802b
+
+Count = 157
+Adata = 6ab658d177c2dd87c9b8787cd70182
+Payload = b0725f735543eb0c0ec88ae69b140f5787d28ef4a2e36d57
+CT = f9c56aa047d9b462ec3d04f7e1fbf4ab26d89931f0be69a1648c6307ec5ea304045a7cdc93f36b9d
+
+Count = 158
+Adata = 483f135c61250fa610b4d14b99ecf0
+Payload = 315a947bf5291278d446d332ee5ca0def7655d5c957a8fb4
+CT = 78eda1a8e7b34d1636b35d2394b35b22566f4a99c7278b42364ff3b1ad915347b1c7f062b10d3da4
+
+Count = 159
+Adata = bb022aed60819ef84ae83ce27db9d0
+Payload = f78d00755bcb45e6822121fe7cb03c8e627c9f548ccd7e7c
+CT = be3a35a649511a8860d4afef065fc772c3768891de907a8a7569808dab58d42181543b2e2d05992c
+
+[Alen = 16]
+
+Key = 10a7720f2e18f739c26924925af6b670
+Nonce = 8c4e7813ab9bce9dafee01c628
+
+Count = 160
+Adata = a209941fab710fda38d11c68b13d930f
+Payload = e59782a9aea45f467b90e51a0fdf166baba05663def2d8b6
+CT = e357b1ccdaca6f3506dc45279c2e4c59f5307a5fd6a99cd72341ea8c0785569973f90ee9ee645acc
+
+Count = 161
+Adata = 2e2f6f9755a492ee54df77b2ecab9808
+Payload = 042a072f6ebf11f79fcb4f5a64f7946dc837d9d2355785ea
+CT = 02ea344a1ad12184e287ef67f706ce5f96a7f5ee3d0cc18b703eb81224cdb1fd2e1cfb2fbfe1e402
+
+Count = 162
+Adata = 99e98c9983c85d1f49ae43ebad67a652
+Payload = 5db6bda27910e7b8b61ac476c6532570b71b3932bd6a698c
+CT = 5b768ec70d7ed7cbcb56644b55a27f42e98b150eb5312ded64c4aea7f17f18f068897557c93ffaaa
+
+Count = 163
+Adata = 37a837d73fa15793f6f823fb99c2ea74
+Payload = 8cac261a461c3ddd2642b8e4e5c3389e491fcb2ff8356412
+CT = 8a6c157f32720dae5b0e18d9763262ac178fe713f06e20736f3b2e70e6e2dc7acc74a823a7f49722
+
+Count = 164
+Adata = 11119a4e779cfb64c736d425e4ff554d
+Payload = 3429f9b088b501d7944c462694d0799568282e7ce07d3e61
+CT = 32e9cad5fcdb31a4e900e61b072123a736b80240e8267a000dc3b57096f0df1d4eb5328c416921bc
+
+Count = 165
+Adata = 962d7d4305f23d1692747b504960c0a4
+Payload = a46ae4c71d4c9eb72fabfa76b8074aa02e07653eca10eef5
+CT = a2aad7a26922aec452e75a4b2bf6109270974902c24baa94f62ed804e9f2ac0f7001d0f35ea9f3c1
+
+Count = 166
+Adata = bbb1fdfefcf3657ba6cd93ff341a04e1
+Payload = 92f5e3083f57c77ac9553a2024a66489698bd2261f05d415
+CT = 9435d06d4b39f709b4199a1db7573ebb371bfe1a175e9074907dcd7ac1e0bb248d46c3036c39fb02
+
+Count = 167
+Adata = 74be126f7c596642dafa8fe3da904e69
+Payload = 41ecc3aae5cfebfad7921a47a0684601ffe73816380f8716
+CT = 472cf0cf91a1db89aadeba7a33991c33a177142a3054c37787cbb80fd21127feca7e76fd6947d5b7
+
+Count = 168
+Adata = d72cc521c90a468522af8966c24799f3
+Payload = 8850bdda4bd0271e333db344a47b837183eb48269c3dc0b6
+CT = 8e908ebf3fbe176d4e711379378ad943dd7b641a946684d7cdb5d1243b6e73b8e380d8ca041647db
+
+Count = 169
+Adata = 28f427fba8d0bb0380bbe5072ccfa519
+Payload = fdd3ca2f193f93f5a349b50357d26748b767cde6ab5cbfe7
+CT = fb13f94a6d51a386de05153ec4233d7ae9f7e1daa307fb864a0ae8604b103f882f17db893ed5c576
+
+[Alen = 17]
+
+Key = 6bffab1f4f4c1ff66b4a669b515b2f8d
+Nonce = ddb34d5e0140fb96d690e1a2b7
+
+Count = 170
+Adata = 5cbba9ea778e01af00afb2a934f28c7211
+Payload = d91b12e8655dd92b1332fc1d71c391c96a17111562d90ba3
+CT = d302e5b2d5d90433186b804cd7717e2db2f22cdc34fb2942ab30780a2c4f12af8f35350d65284c59
+
+Count = 171
+Adata = 1583138aa307401dddc40804ac0f414d33
+Payload = eeafb08d4a4819f5682a01d44371e34cc5729079e74e73a6
+CT = e4b647d7faccc4ed63737d85e5c30ca81d97adb0b16c514746577901b7f6feb88b8e2b8562f9cb5f
+
+Count = 172
+Adata = 23931c258c84086500c6a3b6eda457e6b5
+Payload = b8737d5bbfc976c2d8d9786148dea664dd83cee98df537b5
+CT = b26a8a010f4dabdad3800430ee6c49800566f320dbd715548735a59390ba7a892741694f3a89b0bf
+
+Count = 173
+Adata = e12f98507d6514c3b551d240595346bc9e
+Payload = eb021b63c61c0b194bd44870608d7ef0b932b6104412d7a9
+CT = e11bec397698d601408d3421c63f911461d78bd91230f548f4f81ed18cc1820375a7bec2318cde1e
+
+Count = 174
+Adata = e14b87d49d231c0199eec627fd7f1b5332
+Payload = 93b42584c4956078359d77e80aef52281b9228a1f66aa36b
+CT = 99add2de7411bd603ec40bb9ac5dbdccc3771568a048818a187b430caa60d98dc3e2aeefe6249b44
+
+Count = 175
+Adata = ca095aec96a8b093e62b10f0950ce35ce7
+Payload = 6a788d8238c7b313b8eba27b210a71c36819d719115b9b76
+CT = 60617ad888436e0bb3b2de2a87b89e27b0fcead04779b9970a77372b727408e1bf5a70790b9eba3a
+
+Count = 176
+Adata = d1cac02b34ad33c0e77a5bda2c3baf5e5d
+Payload = 3bc1ee54d0094603dfc68eee118e547d031fb36e464e776d
+CT = 31d8190e608d9b1bd49ff2bfb73cbb99dbfa8ea7106c558cdc1f5cb4d4fa2204e82eedcb3784443d
+
+Count = 177
+Adata = 065c06b49a49898e20bb679e35edbb1f76
+Payload = 8a12adb8b746216baa8a418725e608e4377f13816a036a10
+CT = 800b5ae207c2fc73a1d33dd68354e700ef9a2e483c2148f12413f9496592a75a1d6e42ee3a258607
+
+Count = 178
+Adata = 98a42d7a0c5917deaf3b4de3f0cbe0a191
+Payload = 30a226c07401d0ae24c73d682e3a6e7e377ec1613bafba17
+CT = 3abbd19ac4850db62f9e41398888819aef9bfca86d8d98f6b571a3150887df1ac5f813676b2eb24f
+
+Count = 179
+Adata = e245a7528931841b52a5f59d861d98d7b7
+Payload = 3d17bcdf30445ebd8a9b6aa2fe11d443c1161bb1ee69ced0
+CT = 370e4b8580c083a581c216f358a33ba719f32678b84bec3131aa5e4657c92e31c69ab18d447d3578
+
+[Alen = 18]
+
+Key = ae6136df9ab43631ef143515dacedbe7
+Nonce = c5c445792208a50c8e93d64aa3
+
+Count = 180
+Adata = e04006b68c83a5dd4ceac3cde238e48895ae
+Payload = 6a493c5ef3769ccc4101dbb2eb36e1e5bbc577a057ce0731
+CT = c7584c0203c2535c5702c6ae93b7cbfb066f4a055c627a180d6d676d11fce907b5c93fa1ed7bff2b
+
+Count = 181
+Adata = 5da64e368f45153ea5b7ddca966b6c5b699a
+Payload = 15e0c672c6764f3699d9d3e7120f8ce5daab166f08fdd074
+CT = b8f1b62e36c280a68fdacefb6a8ea6fb67012bca0351ad5d2cd45f211b1a1364c91ad07959bf0ee5
+
+Count = 182
+Adata = 1b315d024bb5d1e03d7510e61f37d8adb10a
+Payload = de907d58cd8f5a72acaa1d329b937dfbbfed65a4e45eb029
+CT = 73810d043d3b95e2baa9002ee31257e502475801eff2cd0018f021a98b2edfb0b7500363099c2a1a
+
+Count = 183
+Adata = 8691ba4f9232ca86f919fe72ddb39c91d707
+Payload = c7fa314d27be79f9d3e2d1e188c1785b0c970f91b8ed4290
+CT = 6aeb4111d70ab669c5e1ccfdf0405245b13d3234b3413fb92ac9aeb018c48f3902276ac759710b6d
+
+Count = 184
+Adata = ff0baf1cbb5884a9290ea7b5ee49915efb4b
+Payload = 33b05b20f3c849fac091a5028cbfa0bc9a1c32514136fee3
+CT = 9ea12b7c037c866ad692b81ef43e8aa227b60ff44a9a83ca7dac49f606dadb9f7034e0a1860d519b
+
+Count = 185
+Adata = 2d118cda20700bc2748ea1753fbca6f74933
+Payload = f43832e420e2eccd5d80502bea2ba1804e17d4433318fc86
+CT = 592942b8d056235d4b834d3792aa8b9ef3bde9e638b481af623ccbab19c1442806e21c5a820945da
+
+Count = 186
+Adata = 0c7a5fd2010c999a8a0efa81f89ff5bfefe0
+Payload = ceb203c842a962183f22e602644fc66e4290b3d5be445fb4
+CT = 63a37394b21dad882921fb1e1cceec70ff3a8e70b5e8229ddbcd18947ac1800856c9c92eb0388c70
+
+Count = 187
+Adata = 73fdddb9e0a64f5671fd70c4ea8443507789
+Payload = d6015b6bd5f5eabb2a649129f8f727c06a3ad59499f21caf
+CT = 7b102b372541252b3c678c3580760dded790e831925e618639c29ea73b0c5aa130d8b14f7b9926a9
+
+Count = 188
+Adata = 82c4484e3a6e18b6bbfd78b69b00c40b30c5
+Payload = c288b810fb533441bd549d02c0b28d5b834293683eaacda2
+CT = 6f99c84c0be7fbd1ab57801eb833a7453ee8aecd3506b08bf0a0f148ae138c2ea02538c8fd7ac76c
+
+Count = 189
+Adata = 267d8385b14721eded743cffd69e4d595f7e
+Payload = 667cc47d13c34923be2441300066a6c150b24d66c947ca7b
+CT = cb6db421e37786b3a8275c2c78e78cdfed1870c3c2ebb75285eb537e7583f04e040a0ddc41106213
+
+[Alen = 19]
+
+Key = f1908328edf2996ebfc9655472ca5ad0
+Nonce = 4c693364546930b6c5250e2699
+
+Count = 190
+Adata = 4a3634e5028df97fbe00eb016e8ea4f1918faa
+Payload = eede01b08f9a303cdf14c99d7a45732972c6eff2a1db06eb
+CT = 90c850790b0b380f5aeb2488fdf43c9d5ef1759861e86f6e52570e769629dcc2e568737ba53a1195
+
+Count = 191
+Adata = 041b93e3fc059fa44aa755e88df277b9b6e499
+Payload = e61ca7310172eec16745a73e34516f65844eecd0dbc5566a
+CT = 980af6f885e3e6f2e2ba4a2bb3e020d1a87976ba1bf63feff1d82ec19a2e3ec43bbdb34e10999d90
+
+Count = 192
+Adata = d1be393376cb5d23cf8139da0fd92f3d520ae9
+Payload = ea887edee68ad5fa6bae928aa480dda898037f820700ec52
+CT = 949e2f17621bddc9ee517f9f2331921cb434e5e8c73385d7f2abb0ce4de9eeb5e8af9cdf3391d3cc
+
+Count = 193
+Adata = f3e551b34d2db1286a9f41085e4dda95ec3f75
+Payload = 71fe1ba5d299495d2a56039c64032ec6263d437f55e3f5be
+CT = 0fe84a6c5608416eafa9ee89e3b261720a0ad91595d09c3b239c73b01ba49a8498b5ff4833851069
+
+Count = 194
+Adata = a69ddc66e63a3415f21009d53adcf26bc1a9a5
+Payload = bd04d854216740a6ceb9827cbddd83761d19feb2a21d78ef
+CT = c312899da5f648954b466f693a6cccc2312e64d8622e116a2248dacd3903c26a2dc5ae649566ad67
+
+Count = 195
+Adata = 5735d6f5882d8f27155eb4cc285a65138ad64a
+Payload = 33b44873a7a1e5b0fdbb7e7347623e4fa1ccd937feb26fda
+CT = 4da219ba2330ed8378449366c0d371fb8dfb435d3e81065fd4156cf7d97b2e744351b6960a807cf8
+
+Count = 196
+Adata = 5d94ed976ab2063512690ae704c3b115519742
+Payload = d3909d577a4e89642227cc6fc146b61bc18392175e342898
+CT = ad86cc9efedf8157a7d8217a46f7f9afedb4087d9e07411d5a50086b6711ac72533c3c5717f6892c
+
+Count = 197
+Adata = db20b384620ab8691aed2fed14a745188d94c0
+Payload = ba0716355fffb8ef947d2a15eb58375a1ff1084c56699029
+CT = c41147fcdb6eb0dc1182c7006ce978ee33c69226965af9ac54fb74ecb9a5163b01b9dbf97ff2f999
+
+Count = 198
+Adata = 94897cdd04e0c8480b2ef7b5201dda37558ba9
+Payload = 5f4b4f97b6aa48adb3336c451aac377fde4adf47897fd9cc
+CT = 215d1e5e323b409e36cc81509d1d78cbf27d452d494cb049d2a81702f665ff5c54f586defd268c94
+
+Count = 199
+Adata = 95c44e1e5ad256b3ce1cc1d87137a1e09f1fd4
+Payload = 598e91d39c414496fd5e69f2cf80826b4e7d59ba28e0a0d8
+CT = 2798c01a18d04ca578a184e74831cddf624ac3d0e8d3c95dfa641889723e163825ab65727e8a5343
+
+[Alen = 20]
+
+Key = 61cb8eb792e95d099a1455fb789d8d16
+Nonce = 1f37b3e59137f2a60dc09d16ac
+
+Count = 200
+Adata = 09db3efac9473f713da630ae92c2c8604c61c51e
+Payload = 6ad541695a37c32d73ff6d5f870abd5b0f362a8968c4fce0
+CT = e65fcc975865c1499b088b58ba163283085d8ca68dc3b235d89756e5d78753ef22c012ae34b39a20
+
+Count = 201
+Adata = b6d07035aed9c141c713cc3bce60f7ba8ac2545f
+Payload = 9cce4c82fe9d38ef64ac8abdf0619f201a25ce6903675627
+CT = 1044c17cfccf3a8b8c5b6cbacd7d10f81d4e6846e66018f2fc78ebae9c143a7283b0641e1f83f5a0
+
+Count = 202
+Adata = 80a5ab693378af29cd5a33555cb3579f9ae540aa
+Payload = 7295a7aed3e987baef19ad68c33ba5a5dcbff27875ff5236
+CT = fe1f2a50d1bb85de07ee4b6ffe272a7ddbd4545790f81ce35a7e44348d2b3085348f787128a4e96a
+
+Count = 203
+Adata = 220817144a15a0a654fc1beaabce60270aa72df8
+Payload = eb21fe20fc4f92452b261eac0d7b70016f7469afdff7a3f5
+CT = 67ab73defe1d9021c3d1f8ab3067ffd9681fcf803af0ed2024dfc096cd8a09d2d81f6146fb54082a
+
+Count = 204
+Adata = 5a2423c2ff2d642c80ac1ca27dd779321f3e9c01
+Payload = 23bf80f51dfd83f63986910e69d54a315c2bfb43f432b7de
+CT = af350d0b1faf8192d171770954c9c5e95b405d6c1135f90b5da82204f4dd8f535cb2fec2f133d882
+
+Count = 205
+Adata = f2c76ef617fa2bfc8a4d6bcbb15fe88436fdc216
+Payload = fc3a50cc8a68778327923ea697f5388da4c814381e29c5e4
+CT = 70b0dd32883a75e7cf65d8a1aae9b755a3a3b217fb2e8b31108630135498ba409f4b6c8caee8a85b
+
+Count = 206
+Adata = b40c8c1d2cee490653105ca2443356cdb63e4fd0
+Payload = 465e41c69928d08c33e063ea119595a04d0de6bffd17bba5
+CT = cad4cc389b7ad2e8db1785ed2c891a784a6640901810f570f89c515837d129ba41f9c24b0229ddcf
+
+Count = 207
+Adata = 6ebfa1e8f80b3cdb1bedf2e3c7e74f30f55c38e1
+Payload = 3f98ee3922f8f1086e3135ae66c5465426b13c8794954880
+CT = b31263c720aaf36c86c6d3a95bd9c98c21da9aa871920655a352fa6b9c4e40733ddcd3fcdaf9ae63
+
+Count = 208
+Adata = 6d0159861031c1a5f01aab35927fe2ab28154d19
+Payload = 5b43067a5ab3a9f9e633fdc084c44ffa7f11edd12ea5873d
+CT = d7c98b8458e1ab9d0ec41bc7b9d8c022787a4bfecba2c9e82c1aa13f062c0f1f5008e27ff2191942
+
+Count = 209
+Adata = 15e5ade017b30ab41878a2747e93aa91c61c2908
+Payload = e40b7e9e46e339e64891526e730b3bf6562fa37acefce307
+CT = 6881f36044b13b82a066b4694e17b42e514405552bfbadd2e149dd02bc7face0c4dfe4e501c2ac2a
+
+[Alen = 21]
+
+Key = be1ed49e2cb0caf6b6a0940c58453b93
+Nonce = b78ad129457681fa7346435b97
+
+Count = 210
+Adata = 161d92c7df1ebb0924719e066e08b95eb4914a5eda
+Payload = a9eec383f63892521e4616fcbadc5485942ffaf4669c43a7
+CT = 949be340720c4fdc4adc05cb777dd81a2549628d33fba07e62d2b338a7b34ebd9d85c244c952d681
+
+Count = 211
+Adata = 6b1d94bc0c6e45fc905c509ea667853e4b2c5a8848
+Payload = 7b44a093162bfc8b4d65f1031d890a6b08a3705b142c0c26
+CT = 46318050921f210519ffe234d02886f4b9c5e822414befff8a4defafeb3d61dad8c007b68d8fb9b3
+
+Count = 212
+Adata = 868dd3e241f60f097a7a2fe571307ee5eb961218ca
+Payload = 28c4d6de3e2ce51b849b135d9cfd3084f0e3155447cad9d5
+CT = 15b1f61dba183895d001006a515cbc1b41858d2d12ad3a0c57cbab553b511d68a4f41db211d0a2fc
+
+Count = 213
+Adata = 3776f37fbf8803bdfd246ffaff2e59658a6c3f0ebb
+Payload = 16d345606a315ad2406abbcb43cd8cabe948107ba6d17a72
+CT = 2ba665a3ee05875c14f0a8fc8e6c0034582e8802f3b699ab0290fd7dbf0afa3e597274e3c9fe170b
+
+Count = 214
+Adata = d0f2769eba9b8e618f00eed6b34c261c59322a253b
+Payload = fcbbcdd9599a86e7c8ccb9347065789a9728ca1220fa51ca
+CT = c1ceed1addae5b699c56aa03bdc4f405264e526b759db2139c7dec3960e6aba3174d793b4e08f449
+
+Count = 215
+Adata = 2be180892faed0bb75887668d187807666d3c66c68
+Payload = 8d145b1f792cc31a2e5b86216609bb018e7aea3012ff70a5
+CT = b0617bdcfd181e947ac19516aba8379e3f1c72494798937c7057b9e2d844e86ee5c3ecfb3270804e
+
+Count = 216
+Adata = 52859849a5b7c1d432c3bfb35271cd8141db2ec774
+Payload = 741db990b43ef34993c33d1c4953b67b128b9299dfe86d74
+CT = 49689953300a2ec7c7592e2b84f23ae4a3ed0ae08a8f8ead1150fa899152eef7a30ae0f20986818e
+
+Count = 217
+Adata = aa192759625f4e42d1d1fa73dc0f62199142155615
+Payload = 51dca5c0f8e5d49596f32d3eb87437bcae866640310ce1e3
+CT = 6ca985037cd1091bc2693e0975d5bb231fe0fe39646b023aba7ff9203608089558698ec29472dda7
+
+Count = 218
+Adata = 6de564226884188ec7bea3894535a875cff2a42fdb
+Payload = dfaa7aa8b28626210d5c24e2ddfe516189be05aabe26f3b2
+CT = e2df5a6b36b2fbaf59c637d5105fddfe38d89dd3eb41106b85bd0a5074ef852575baf5f12c22663e
+
+Count = 219
+Adata = f245f2ee23755df863dee55d7ef0c3c09a0b6f0b0c
+Payload = eedf00aab5edefdd6549d37ed44358e11c588c24f141dc57
+CT = d3aa206931d9325331d3c04919e2d47ead3e145da4263f8e9eb617436bae012331daf020fce24e47
+
+[Alen = 22]
+
+Key = 34ab6fd7f54a2e0276fcb7cf1e203aba
+Nonce = 6091afb62c1a8eed4da5624dd7
+
+Count = 220
+Adata = 1ab5cc3d7b01dc74e6cf838bb565fea3187d33d552a2
+Payload = 8d164f598ea141082b1069776fccd87baf6a2563cbdbc9d1
+CT = 0d30ab07153b5153637969e6bd3539448c541e42b3d432fd7ef14622a9b621d1721b944c60f7fd67
+
+Count = 221
+Adata = 1f1ac4674b272bc7a4ee9f4eae33e969b16fa90a69ba
+Payload = 14e99a2ef0de650adbd785c692342cdb765e6d20d5fca09a
+CT = 94cf7e706b44755193be855740cdcde455605601adf35bb6dfa4ec2c92671c64ee07946527be67f0
+
+Count = 222
+Adata = 43ee77f12ea42e82a02275a68aa95cbd1bb440442bcf
+Payload = 383242c709fe5f2ce782bf8c83b645d171f2bd238abc655d
+CT = b814a69992644f77afebbf1d514fa4ee52cc8602f2b39e71173572fbf3d9495760aae4347397b110
+
+Count = 223
+Adata = ae2ff288199be25bf640811541394ad7e1dd0dc0d24d
+Payload = 9c16a5b638c35c97c5c981c1b8dbcba11aec30e72e45a936
+CT = 1c3041e8a3594ccc8da081506a222a9e39d20bc6564a521a4d2327956e030b9df753e063b5b71201
+
+Count = 224
+Adata = 4ccfb4281852b5ca7e787723d689384a68ff9437db31
+Payload = ec9d8edff25645520801b6e8d14a2fc3b193db70d5e5e878
+CT = 6cbb6a8169cc55094068b67903b3cefc92ade051adea1354e4dac0c9130f5641afd035dd884b6271
+
+Count = 225
+Adata = d3a2fffc798fd9cc2f409471faf18caa2ff3dcf4e652
+Payload = 0db33eda4188a9165147e24e40f79fee1985eb68d5162728
+CT = 8d95da84da12b94d192ee2df920e7ed13abbd049ad19dc0448807dd50a9cf41651083c49c7493ceb
+
+Count = 226
+Adata = 7b5121aa4d1e314f209ffe3e92cd26ee4f74d91e27f2
+Payload = e0d3ea4308376423c4322503f56e427a64e2e6d8b4f5e668
+CT = 60f50e1d93ad74788c5b25922797a34547dcddf9ccfa1d448ea0da53046733f522ded40a09c6d7a6
+
+Count = 227
+Adata = 6e12c112720ef346bbbe7d1c19483721b1c52c438dad
+Payload = 491f2bca585d6b5fdf38d18890e4d1bc923fe26930b3d2f1
+CT = c939cf94c3c77b049751d119421d3083b101d94848bc29dd345cb5a968f39654b994686699d532c2
+
+Count = 228
+Adata = 20433402a2d869c95ac4a070c7a3da838c928a385f89
+Payload = f45908d691ddaf89c0bc129ffada94c3ceda5f47d63ef76a
+CT = 747fec880a47bfd288d5120e282375fcede46466ae310c46cce85eb55339b886b7121b306fccc0b2
+
+Count = 229
+Adata = 42f944c21cc221beaacb288115ac628346b8a1d94bd5
+Payload = e300fc7a5b96806382c35af5b2c2e8e26382751b59010d4b
+CT = 63261824c00c9038caaa5a64603b09dd40bc4e3a210ef667a37ca5ce12aa6f0659467642deb8bfcd
+
+[Alen = 23]
+
+Key = ea96f90fbae12a857f5c97e0cba57943
+Nonce = 21cc46d9ced1539b0ad946e600
+
+Count = 230
+Adata = 105258d2f25f62675aee975cfdb668aff833f05b61eb2a
+Payload = 49db80f22bc267a70e5636dfbc8a21c83d9691fe4b9c3051
+CT = d2fcc8b7809b5fc07e44083e437d8180157f1782a9ce9f65c7fa9ee2e7cdc1b755258f2212a8a8f4
+
+Count = 231
+Adata = 0f5938540651fa4ca03867e67518eb2b73f60dd8750fa0
+Payload = 26618e21099a79d6c517335389551323065ad89c8848ea12
+CT = bd46c664a2c341b1b5050db276a2b36b2eb35ee06a1a4526bfdb9bfcd3b969fb2e41221eb92b0147
+
+Count = 232
+Adata = d6b228960fcbcf07c7bede616139db62b3808718a5b511
+Payload = 4de1d6d57144896ddea1c30f49afecd27bdf4840ed9928b5
+CT = d6c69e90da1db10aaeb3fdeeb6584c9a5336ce3c0fcb8781f8beea22cba93203c912209c78c03aa1
+
+Count = 233
+Adata = 75f8f071e229355e286882917ce5dd4f1db591fee51b6c
+Payload = 785359b1dc754a1e1b6d8731bd2d917ce3e91507401310e8
+CT = e37411f4772c72796b7fb9d042da3134cb00937ba241bfdc69a2e3ea4a40f7c491912c1a0778ebde
+
+Count = 234
+Adata = 4afb62aa8648ac7474dd16fcc376f8909c69e1ce36e6d1
+Payload = ab627aac1496d011ed2edcb2fc6b2afbcc394654f56124f6
+CT = 304532e9bfcfe8769d3ce253039c8ab3e4d0c02817338bc2a75c7ba2a769c27903e99b72639b0841
+
+Count = 235
+Adata = 736fdf94db820a2efe89e7fc9dcfe7c23d5754ac2bcc7c
+Payload = 40722cffb37f1455c2618408e777ed0f4b1bd039952730cc
+CT = db5564ba18262c32b273bae918804d4763f2564577759ff8f84f4ca4a69fde75d7207e50494819b6
+
+Count = 236
+Adata = 8a9a0367137c28db4c4e78d9cd9a68cde0d1b4583532ae
+Payload = dcaabf7a061502618541c09ea59dbbbd52b2692fd0064747
+CT = 478df73fad4c3a06f553fe7f5a6a1bf57a5bef533254e873a0c34a24d3ee0946034c71fba4dbb333
+
+Count = 237
+Adata = 34dbbff560ef04ea731b8979aef2ae50972f4db3efe14a
+Payload = dd641a893b16e0e173ea2eda20638bb01849ac11e64e8ddb
+CT = 464352cc904fd88603f8103bdf942bf830a02a6d041c22ef0f5e24a435a39a716c39f43dabdc4281
+
+Count = 238
+Adata = f3d1fcd912252431db9d8ccfc3e203d5b34d537468b4c6
+Payload = 9aa3e8ad92777dfeb121a646ce2e918d1e12b30754bc0947
+CT = 0184a0e8392e4599c13398a731d931c536fb357bb6eea673f623d59f66764d859a772bb50ec91fc3
+
+Count = 239
+Adata = 513b4cdc551c203ed5f1e659813584862023911590b672
+Payload = c8f44ae4b02fffdbce0df773c24075f877945fc7a86be460
+CT = 53d302a11b76c7bcbe1fc9923db7d5b05f7dd9bb4a394b543b6549eb16fba96318afb3df51f4675f
+
+[Alen = 24]
+
+Key = 35b403a15212097085d6e2b77ec3d4f2
+Nonce = daa423bf9256c3fcc347a293aa
+
+Count = 240
+Adata = d3c0ed74e5f25e4c1e479e1a51182bb018698ec267269149
+Payload = 7dd7396db6613eb80909a3b8c0029b624912aabedda0659b
+CT = 5b00cf8a66baa7fe22502ed6f4861af71fa64b550d643f95eee82c19ecba34280604b58d92dacd3f
+
+Count = 241
+Adata = 62f4fe53e99a9b0c51e9561d910d7e2ffe19a5176c9dec06
+Payload = 897f0dfd90213f64a9277a0eda4f134f303fa89f56ca54fb
+CT = afa8fb1a40faa622827ef760eecb92da668b4974860e0ef5ab4999e9689d52b8afeb87923efa3b48
+
+Count = 242
+Adata = 191c4dfa653c20292657f7694c6b6a4a410c49a879abd217
+Payload = 2b7cf9e6e2d6abcd7775f8a6eb6294e822041c4c45f09c3c
+CT = 0dab0f01320d328b5c2c75c8dfe6157d74b0fda79534c632cdc71e556c34fd4e1b5ebc50d38da8b3
+
+Count = 243
+Adata = ba34741f8edb51470eb20f891869aabeab562d92571ac943
+Payload = dccb9a4625512496b372a2b8b768f75741d8c2e30e57d638
+CT = fa1c6ca1f58abdd0982b2fd683ec76c2176c2308de938c3646223d381090661c2ee2370d29a572a9
+
+Count = 244
+Adata = 8b922aca6125722ec490b134a45864397f4e2c281d6e2089
+Payload = e0e452c990665465160b02cad6367ca89723613488d8efbf
+CT = c633a42e40bdcd233d528fa4e2b2fd3dc19780df581cb5b1f78af50466646b7c7e652f787afe5357
+
+Count = 245
+Adata = afb9fd78e3f8eaf4e8c91da62b2da534508e54f7dfa214fc
+Payload = b536fdb8839f87080ae65ec35da347e792622ffe18a61d46
+CT = 93e10b5f53441e4e21bfd3ad6927c672c4d6ce15c8624748cc9d9a1270f78648a6b66cb8c0f2471b
+
+Count = 246
+Adata = ecf942ccee7396cb3ee177eadd4d96a4af1d90afdce97376
+Payload = c81233826e5125e1f31fe275184ccba8f1a743e58e146e4d
+CT = eec5c565be8abca7d8466f1b2cc84a3da713a20e5ed03443b17d3d6f1fc4f530841b749d9f3a0a7a
+
+Count = 247
+Adata = 16fea92ffcaad563792aa924bffe7ef690edc90ea4e29cc0
+Payload = 24ab253b5b06552665c3c810254c0ed15e68a783180d7eee
+CT = 027cd3dc8bddcc604e9a457e11c88f4408dc4668c8c924e05852ed48cf88d9ab2326aa46b6541b60
+
+Count = 248
+Adata = 76f110eecd369d79e21fb208058359d3a2f37581d1f7f691
+Payload = 7f596bc7a815d103ed9f6dc428b60e72aeadcb9382ccde4a
+CT = 598e9d2078ce4845c6c6e0aa1c328fe7f8192a7852088444c62dff6bcade5ac2edb8ec9797ce433e
+
+Count = 249
+Adata = 8834c776a3237f060ae0ab9857324a3b2ac79f3b6e6f90f5
+Payload = 11cbfb3d348c7abef99f562607e289de34a2bb379a5dfe50
+CT = 371c0ddae457e3f8d2c6db483366084b62165adc4a99a45eb936ac4764575f85352c24ab23209d42
+
+[Alen = 25]
+
+Key = 7a459aadb48f1a528edae71fcf698b84
+Nonce = fa4616b715ea898772b0e89dd4
+
+Count = 250
+Adata = 0c0b4a45df5c3919c1e1669c5af5d398d9545e44307d95c481
+Payload = 0b3d947de8632dc8ff752f619ba7c84716fac7a23e101641
+CT = 7db9f3f7dc26fc2adf58d4525d26d5601e977de5a7c33911a1138cff7b624f9908b5b4d7e90a824a
+
+Count = 251
+Adata = aa27a28a36b5a2cee57ffeca0233feb4bdd4eacb2cae28e98f
+Payload = e6dedce2c278c44e5678d13e7d5b5d3501d61bb0bb6b5558
+CT = 905abb68f63d15ac76552a0dbbda401209bba1f722b87a08e23f92b598f7a248a894e6b8f5691bee
+
+Count = 252
+Adata = 66220aa9b40a1772caba7749a544bff938e804dbc6e556498f
+Payload = a276b0922fbd5094bf89b9329d07341e039d6204397b81c0
+CT = d4f2d7181bf881769fa442015b8629390bf0d843a0a8ae90e94043c0d80fd651469232fe9d47a81f
+
+Count = 253
+Adata = 3d765d20e03a4cebfda50316c4b7d8b6c55078d5b3e9cbc567
+Payload = b99afbc2dbb377350cc58d4bfe8e954cef25d7b27b82fad4
+CT = cf1e9c48eff6a6d72ce87678380f886be7486df5e251d58425088b522fc0731097e729448236b317
+
+Count = 254
+Adata = e91b6265879153e1692b00a112b4205111c8eb1a7b7f2c6898
+Payload = 56114cc783b80ca2dd2881387b6d92a59a237dfc8e976d8b
+CT = 20952b4db7fddd40fd057a0bbdec8f82924ec7bb174442db2208cf07574cc4f3f83ed6301b904404
+
+Count = 255
+Adata = 340b16f352817babb4fb70e9e6e18784b3e67bdd449872158c
+Payload = eb21fe20fc4f92452b261eac0d7b70016f7469afdff7a3f5
+CT = 9da599aac80a43a70b0be59fcbfa6d266719d3e846248ca514b0a900068e55cd24c92bbb78c521ad
+
+Count = 256
+Adata = 5a2423c2ff2d642c80ac1ca27dd779321f3e9c01445be684dc
+Payload = b15083a73607c9d7e197a8cc884ad3be98ac343f6493df67
+CT = c7d4e42d02421835c1ba53ff4ecbce9990c18e78fd40f0373f8ba66d74321c80c057f010078d2f28
+
+Count = 257
+Adata = 5fe8bb27a59a5f4e370adbba96484c2365fc0d8c6e58d7d3e6
+Payload = 07542d18e8f2d3e199fca0f90cabb78b169525fdce81666a
+CT = 71d04a92dcb70203b9d15bcaca2aaaac1ef89fba5752493a0a189319e4f06d53c1405d37b06cc8eb
+
+Count = 258
+Adata = 23e5422e8d7560a9e65642b5e723a47536c16791f3a0cf918d
+Payload = cd574ed56bdfd1408f7831e0b24b4345ee979ac906a7aa22
+CT = bbd3295f5f9a00a2af55cad374ca5e62e6fa208e9f748572dd72f48ae03670249d74f8460b63b1ae
+
+Count = 259
+Adata = fcc9422ba5023a9997baa9c4ee6cb196ffe96e08eb9c2b8a75
+Payload = 8c9abe94beed4c9bd46adb1d04fbfe7016dd50d324525abb
+CT = fa1ed91e8aa89d79f447202ec27ae3571eb0ea94bd8175eb1717c00c93d36a77141b723d573c8c65
+
+[Alen = 26]
+
+Key = ca748225057f735f712ecc64791367f0
+Nonce = 1341a6998eb1f50d4b710a13ac
+
+Count = 260
+Adata = 5fb96b045f494808c02014f06074bd45b8a8ad12b4cb448ec162
+Payload = e92cd0cb97afe4fb00c4f12e9b9abe1d08db98f49a27f461
+CT = 82b666694232e86e82295beae66ae67d56aceb5d6b1484ceb4a6843ec16078038c10afedc41f5362
+
+Count = 261
+Adata = 87db0d9d69bc0cf69cabeb92570e482bbc8ff3e1ba72f12f3225
+Payload = a6dbad96ad23ff61479df39b99f0673a09f2a7eaebbd34b9
+CT = cd411b3478bef3f4c570595fe4003f5a5785d4431a8e4416a7c6566d0b8ff97f946d7c7773a845f2
+
+Count = 262
+Adata = a061a09024f1e03b223695d4703ee202e90e07156b95859a22e3
+Payload = b1dd81cc3b2b0efe540a3194d6fe304cd2de53db7929ebe1
+CT = da47376eeeb6026bd6e79b50ab0e682c8ca92072881a9b4ee1d66a4728b67b42602e23c8500b0115
+
+Count = 263
+Adata = 0dd513c5d8d62b723ab8b0a3aaa477e843d9149dc8a2f878e585
+Payload = fb30c2e98f3d7e4ed7431da285711d3d287884db13a474e7
+CT = 90aa744b5aa072db55aeb766f881455d760ff772e297044803c51e8c59ed13b3e5d9b489d4ea2ccf
+
+Count = 264
+Adata = 3ff59c40bd796048e586eccc23a82e4d09fc5e779f38eb4afbed
+Payload = 886f9f91a6566ceb99c39462ab675a3ae3be98f68787626f
+CT = e3f5293373cb607e1b2e3ea6d697025abdc9eb5f76b412c0f1ec270b43fc5a9811b56ccf033789c6
+
+Count = 265
+Adata = 0df7ef91f7124da867e992bcbc6fb38232ff6d5205f38768da72
+Payload = ed370d1c2d6dc03e4fae4deb9343a7d4339562cffd427587
+CT = 86adbbbef8f0ccabcd43e72feeb3ffb46de211660c710528bb4ed25940d58cba64271fe1d2e8013d
+
+Count = 266
+Adata = 6777de159c34d005b94f67c33ae4a35ebab09d9cb9c56b4c9c81
+Payload = 2f77c2eb07db14bd713c5af10c0760ea3a6ca5ff8d046d36
+CT = 44ed7449d2461828f3d1f03571f7388a641bd6567c371d99392636a5e373c1354ea9b969abb4932a
+
+Count = 267
+Adata = 75559898f4ba03c55afc25ea91aa61a93c2f8270a5fa51b6f6dc
+Payload = 360fb89429dc9b48358097d930c8561b2bd18dc0a470d1d6
+CT = 5d950e36fc4197ddb76d3d1d4d380e7b75a6fe695543a17959a7e8bc0570f19159f91fc14ac6532a
+
+Count = 268
+Adata = 5e03fc430473c5de96d68907fa506f9da353ae48a965445e1f24
+Payload = f2d8d67b9f291c3edc264893922622b2693f3e7231137eba
+CT = 994260d94ab410ab5ecbe257efd67ad237484ddbc0200e1507e559568c27a30b5676f98cc66f57d6
+
+Count = 269
+Adata = 7eee4869e77f6db12c91d1f647cad2340d33a3defaeb362d311d
+Payload = 7fd6fb81c36e44b150af10e04683b1ec9b5dda87c71ff939
+CT = 144c4d2316f34824d242ba243b73e98cc52aa92e362c89964910615920f6f3c3421a9c2bec1bec7e
+
+[Alen = 27]
+
+Key = fdf2b2c7fcb3789b4e90abe607dca2af
+Nonce = a69ddc66e63a3415f21009d53a
+
+Count = 270
+Adata = c76846da496ed87b9c0f65c6266c9a822224acde9775efb186a4a5
+Payload = d7aa4efa5d75195a400018bd38f7d8cd53fdffe88df1837f
+CT = 150d9a8b78d9c04239d66207a1f95021bbb1b7c70d7c354825d05e5a2e76a90f6fe489fd74cab2a3
+
+Count = 271
+Adata = 4efbd225553b541c3f53cabe8a1ac03845b0e846c8616b3ea2cc7d
+Payload = 5f94a2e48d348a1d56c55a659306e319c3d2ad78b9fe43a7
+CT = 9d337695a89853052f1320df0a086bf52b9ee5573973f590be6af49ce97d5e0e77c7fd5d9cc6d932
+
+Count = 272
+Adata = 7631cf7822a545daefa16a5ec43c877d475a82d5aa2d51cec7fbb4
+Payload = a44b010fc1c659eac9241a58b11a73d7ce33156ddfc54c3c
+CT = 66ecd57ee46a80f2b0f260e22814fb3b267f5d425f48fa0b924b268cab915f999aea3e1cc3a88ccd
+
+Count = 273
+Adata = e4da34663edc44370bfd8aa8315945471a893a1cc069628a071ee0
+Payload = 28d157f5741f1be057d5219711414c0638b47d165a905a6a
+CT = ea76838451b3c2f82e035b2d884fc4ead0f83539da1dec5dc368f5af8e311e67209e02dfa2613377
+
+Count = 274
+Adata = 077509eae1dc367540f87832c5780f6c5b29e180bc6c1fee38e826
+Payload = ba7432a8e34bfaa91b35c8dfd822d86850be39e63150257f
+CT = 78d3e6d9c6e723b162e3b265412c5084b8f271c9b1dd9348ad175fcad35d29396380b79a28784cff
+
+Count = 275
+Adata = a513d750ca1e8bf6cb7b8cea5204e064c15c2dc40d742b31cf5459
+Payload = 3f5830b0ce8849a660af7d58a60c19a9824a3033bb5fed43
+CT = fdffe4c1eb2490be197907e23f0291456a06781c3bd25b7493b4b3e33d325359c9c651290ce73bed
+
+Count = 276
+Adata = e439db829c1291df49fc42c2fa1a92118c2665f11e13f28dc6f11a
+Payload = e69b2a243340df5dc70b2cb05be12e5992ee36f7d9f4ca84
+CT = 243cfe5516ec0645bedd560ac2efa6b57aa27ed859797cb371f88ca5857c6d801e726a01c621a0c3
+
+Count = 277
+Adata = a12c690568114fd7a677f49d74e84fc1a6b7f7d2a08693266c0a91
+Payload = 9de35b840a69a84701ffae1b1d2bf13c34b42a57d14c524d
+CT = 5f448ff52fc5715f7829d4a1842579d0dcf8627851c1e47a0592d360fc6a46aa18c4ce5d74fa4532
+
+Count = 278
+Adata = 1813bf176a1127f4d508d7663ae750f9c4bcb84a6e26811ac60d46
+Payload = 9e2fa20bf76768a5a1467d90a048bb503a2c33bbbaa71653
+CT = 5c88767ad2cbb1bdd890072a394633bcd2607b943a2aa0648b772cef893495cf0a94e8ebf06e920b
+
+Count = 279
+Adata = cc6e9cc2699d3ba0e624e715599480d6b7dbc6eeea0d12a9236444
+Payload = 6681b1cbeceea57a828324831407280b00f4917ed52a10df
+CT = a42665bac9427c62fb555e398d09a0e7e8b8d95155a7a6e8b1851d571a1ef8aed565b784dcaaac4e
+
+[Alen = 28]
+
+Key = 7d870d7e52d3053c65eefad47764cfeb
+Nonce = 37d888f4aa452d7bf217f5a529
+
+Count = 280
+Adata = 9610949f6d23d5b1f3989b2f4e524fab4f297a5bec8ddad4f16cb616
+Payload = 109317556c21c969eda65a94176d7a11462c9ae18a865b6d
+CT = 4e6b967b1571c6d7b9e118b112b7ac949a4a175650316a242dd579cb0d201d22c86bbc7fbe47bd0d
+
+Count = 281
+Adata = 96118dbfe53434d8aed88769a535eb0c8b5849dca1c81c34626ac9b9
+Payload = 3e6c914a196e175079315b1c92b2b8a844deb472e249e3d3
+CT = 60941064603e18ee2d76193997686e2d98b839c538fed29af0dd7aef4a609f3587652173446ebd82
+
+Count = 282
+Adata = 21fc96f73975298207f818909088295d6d6861677130ca258c2174f6
+Payload = e0014147d5771b4380dc0192d45f36f7d60776d1ba47374d
+CT = bef9c069ac2714fdd49b43b7d185e0720a61fb6660f0060463e4405d45caf4836467edbf35089d87
+
+Count = 283
+Adata = 72a5151abcb55933ff7c9314f3235eba2a400121454144c2670e8359
+Payload = 0f1c6dffeda98f7a159f9cc61820bfb29910d8eaa41b751a
+CT = 51e4ecd194f980c441d8dee31dfa69374576555d7eac44537441c813e90fac775eddb7290df059d9
+
+Count = 284
+Adata = dbbf192914b1ad73666e9f5e9c22c08ca398f7524af62b1046a863bd
+Payload = c1ddd14e380cc91324cf2a381df1da1ccffd90ae436a373a
+CT = 9f255060415cc6ad7088681d182b0c99139b1d1999dd067334d9316f1f1c3142c1c9b26e5c220a32
+
+Count = 285
+Adata = 28e4b88fbf04e9897057ff5bfde7eb04fa480256817a50fa281030b4
+Payload = d4dae9c4cae92afb80f9a5c99383ff16e23a2ec942eed4d2
+CT = 8a2268eab3b92545d4bee7ec965929933e5ca37e9859e59bc0b188e33bfab29b237d6c6920ce3418
+
+Count = 286
+Adata = d9ebc1cbfab9034317132a72e0f11c341331146a59e7a2f26bf4f3d7
+Payload = 8a188d40a6e6fbb06a9f06304349a7a808b092cc2fc10b9e
+CT = d4e00c6edfb6f40e3ed844154693712dd4d61f7bf5763ad7fdde04d21b876468bd9184101b5f32d0
+
+Count = 287
+Adata = 34ad69f192ae4dcab771aeeacf01bbd32609bcbbea8ff9df31ded719
+Payload = 590c1aac30ab166b1caff748452fc146765c372e226ffc26
+CT = 07f49b8249fb19d548e8b56d40f517c3aa3aba99f8d8cd6f068c65e9d0e5f1b81c86393900e64c19
+
+Count = 288
+Adata = f5e50ce1f99ed5e9f2baa54b96ae7039234b1131e734ec190695d28d
+Payload = 16d0522b2e691e42bd80ce95e00c8a7a1fc738169e904bdb
+CT = 4828d305573911fce9c78cb0e5d65cffc3a1b5a144277a9206ab3b72c56c8df4a12dba89a2f21276
+
+Count = 289
+Adata = 9b1e7e52ea1a12444d884866e11dcf367b70b816460936fdaebba36d
+Payload = 0bddf342121b82f906368b0d7b04df1c682ecd4c2b2b43df
+CT = 5525726c6b4b8d475271c9287ede0999b44840fbf19c72960170ca7b16d23537eeb3034105334699
+
+[Alen = 29]
+
+Key = 8fcac40527c0e7ca8eaff265ca12c053
+Nonce = ae9f012fd9af60a400e20b1690
+
+Count = 290
+Adata = 9ce65598cd1f86afc9aaaf172809570cc306333c25523f863c6d0e0154
+Payload = 78d1e96af8cebdcc7e7e2a4ddcfa34f6cf9a24fb85672ad7
+CT = 9adb9a95a9379ad795d8d3ffd4e37a045160d6d727f974a6cb3b5151f327e65447e52c7525562c91
+
+Count = 291
+Adata = e7c78ef4c4b959ee00cb1a09d71221a43892ef8ad705edd27ed85d03a3
+Payload = bc59f18c8473941abc681a92741ab5ee13679829f542b8f4
+CT = 5e538273d58ab30157cee3207c03fb1c8d9d6a0557dce68534e5b08e27d8f5eeef0f064ff620652a
+
+Count = 292
+Adata = f1bce6f2a4bdd3a07ebf5f8d47f931d27e7e63389d70e1059f701216be
+Payload = 5575d950312c14c89ac609dfb0b2fd1af732bb6aae5e8651
+CT = b77faaaf60d533d37160f06db8abb3e869c849460cc0d82044c0a96baae318f4714f0206812516b5
+
+Count = 293
+Adata = 3da3bb091016e54477dae88af1c84c1a51b59c1bb49a05deb6f32064e6
+Payload = df5947d8c6094ccc25816639ec42214b28731bfd7b8312dc
+CT = 3d53342797f06bd7ce279f8be45b6fb9b689e9d1d91d4cad4e7bdce2dc6aae24178aab6984f31028
+
+Count = 294
+Adata = c4cd183071c37a8157c6930a7d4d530cf4b7eb021682327810bd48209e
+Payload = 2fbb6dc235761875411ef59ae06110df8f15f66b721b0fd6
+CT = cdb11e3d648f3f6eaab80c28e8785e2d11ef0447d08551a7f18ece8260bd56ecdee768022d0dd8d1
+
+Count = 295
+Adata = 0e0fece7b6b659b642668e8ba3dca330523e70279155f485f3f6f8041e
+Payload = cd149d17dba7ec50000b8c5390d114697fafb61025301f4e
+CT = 2f1eeee88a5ecb4bebad75e198c85a9be155443c87ae413f6f0fb3b7440b84ddc3cc53819c2e93be
+
+Count = 296
+Adata = a35c6f70f637a9a5e6f215c694fdf65b6fd85f794ed3eaa1bc19abe592
+Payload = 030390adb572f2bd2a6a4454fd68236cd1d465574328aa00
+CT = e109e352e48bd5a6c1ccbde6f5716d9e4f2e977be1b6f47129ca778c51f9320f121dd803ece8d5da
+
+Count = 297
+Adata = c2992096828325820e2d7acaa17ac789b6830ec3128dd7f904398afbec
+Payload = f2d9cf953c8d3a051d9b3eae4307a3cb4fffaa2435b49586
+CT = 10d3bc6a6d741d1ef63dc71c4b1eed39d1055808972acbf79c223a5ad65120bfca4a5992e5ebc6fc
+
+Count = 298
+Adata = c023763a285ea934bc5bc7ddfc2aefe2b3f9eafe7b87c61383dcc07990
+Payload = 4b92e8d2ffaa4af8f3e0ac037a900bd18e195f490a3d71e1
+CT = a9989b2dae536de3184655b17289452310e3ad65a8a32f905c3bc4f618ffb3a159f4e2d0622cea6e
+
+Count = 299
+Adata = 0a39ec0163c7aeb1b4fbe7cb4fa5b0592fade70f430e23730a23ed4160
+Payload = 7c0e6a0d35f8ac854c7245ebc73693731bbbc3e6fab64446
+CT = 9e0419f264018b9ea7d4bc59cf2fdd81854131ca58281a376f099dce6e18435fba4d26c1e93bda0c
+
+[Alen = 30]
+
+Key = ddf9f150cc3f1c15e8e773663c5b061c
+Nonce = 98c5036b7d54da9a1177105600
+
+Count = 300
+Adata = 20c5ab290e6d97f53c74121951f39ba865b3acc465fa3f0fb8a591622277
+Payload = 79d8841ab83279724ce35e1a8abd4e158168dcf388ab4c3d
+CT = d00d29396ffa9e691290d746527777bf96a851f306d4da0b1816df1e0e82bb7bc8105930ad6a2232
+
+Count = 301
+Adata = 0e205a4dc5d5ead0d9ff7f182dc140fc49511c01b0fdbc7e6d6cb5fdf027
+Payload = 88b2572fbe7cf2b46df04db476ffedb41778ae2eb3c3aae4
+CT = 2167fa0c69b415af3383c4e8ae35d41e00b8232e3dbc3cd2df823c8ccd466807f2bd1c4032f0cfeb
+
+Count = 302
+Adata = 48043560d60381e83c11d4bc9d997d3ee2add6b0524b779c62dfaa73ce0a
+Payload = d44bf28b010e076b45db1b053af03db718b60748da51db1f
+CT = 7d9e5fa8d6c6e0701ba89259e23a041d0f768a48542e4d2931f5be8c9965345c760c72cc1b7908d1
+
+Count = 303
+Adata = f0729a8a2fd073699ab87b521cbe0420b43529556a505f5f87874d1a053c
+Payload = eab8cffb512eabe267cd64353552513defe97c2d10f35503
+CT = 436d62d886e64cf939beed69ed986897f829f12d9e8cc335381d94a828a95872ebdfda8a4c6a196b
+
+Count = 304
+Adata = fc2cd69bb61223f713e33a5071d09bf2783640c307c22d836dd94952dd37
+Payload = 001056926546c261fbbdf92b94498e038c2bcfd0b6345497
+CT = a9c5fbb1b28e257aa5ce70774c83b7a99beb42d0384bc2a163931808533f4f70d7a78242ced110eb
+
+Count = 305
+Adata = 8f653c5c003c807d16d17f833eebb97c9c2f0e5aae3780a52ce53a6c33f7
+Payload = 29ffaef9415fd300127ffd26ef324083a9d90e0f60e2ab4f
+CT = 802a03da9697341b4c0c747a37f87929be19830fee9d3d79f34553198f8e40fde6473f9cf04f1de6
+
+Count = 306
+Adata = 8d05e7d3077151c6d9378cb08e049e4d7c28a908f7f7c079c46ff92cd01b
+Payload = 9874dc5ca1b541f7b21c7b3860fa6b0c3ab1b712ab0fca98
+CT = 31a1717f767da6ecec6ff264b83052a62d713a1225705cae0fac20e8d45d2b0771d140b5e4a47c87
+
+Count = 307
+Adata = d4feb3ea76ac2945651f557406f3f38a2d7e9232ed55ff4eaf1201dd8255
+Payload = 1e01c7128c821fb9c971a27fc7c6f9bb902fa735de583b8a
+CT = b7d46a315b4af8a297022b231f0cc01187ef2a355027adbcd3cacfe4281e52d79e60eeb38319bc3a
+
+Count = 308
+Adata = 7cbb4ae995a3367a256cafd11cd6c6cab5bf3252fa97f27a8a1434ca9a27
+Payload = 51cd306fac7d20e3c7043eae3a6dfec046c5c24a666a0723
+CT = f8189d4c7bb5c7f89977b7f2e2a7c76a51054f4ae81591158f0d7646a799b14288bb2f354b5d8847
+
+Count = 309
+Adata = bd40b06a4beded2be3d176266b10772c7fa2949f0a9b20d613af90c2daf5
+Payload = fc5b26befc633a3e8ace011aa7a42bd0258a9f3dc14fc1c8
+CT = 558e8b9d2babdd25d4bd88467f6e127a324a123d4f3057fefd7f95e1d331e700aa9ef83f09b689fd
+
+[Alen = 31]
+
+Key = b1dc81d116d94f5eced526b37c004b95
+Nonce = 97c8f69fb91b17299461fd8d63
+
+Count = 310
+Adata = f8b08aa83bed09ca342249b2cf9e2b45a89dcfb8711a120395e455921af481
+Payload = 54390715b6e7c7bd51a234db059a51ba030cf22ee00b7277
+CT = cb629994c3418a662a8cde1b5f4d99aa7df66e24c53dc6df11297930fd44c63675b7cca70671ef4d
+
+Count = 311
+Adata = 0351c969dd38eeaa4b9b0000e346eeb1a2cd462033c59d9e6e3331822045cd
+Payload = 65b5e856a8cf35dffd42c5ba105cba4c434aa1c2a0390352
+CT = faee76d7dd697804866c2f7a4a8b725c3db03dc8850fb7fa7e77f5566ca2fd9293835bceb461dbaa
+
+Count = 312
+Adata = 5db8b6bc16740680f78fba917733a6899cdba5e4c10a8058963d1265681eaa
+Payload = 9a7685e3daac43ccf22cad0df900ba8acddc5d420846118d
+CT = 052d1b62af0a0e17890247cda3d7729ab326c1482d70a525ec2cf9f5d35521c1c000685e49d2ed42
+
+Count = 313
+Adata = e7d6024611210da0cfb90a9955195aa0a0539280a3a7c792a1540930daae2d
+Payload = c18d9e7971e2ae5fc128777086338fbe194443324e2d2cd1
+CT = 5ed600f80444e384ba069db0dce447ae67bedf386b1b987966f33dfb44ae413283b238616c6b99fb
+
+Count = 314
+Adata = 77a878c9c76f3e6a4ddd330d1d8828949d08e0fedffe0d8e2e557b29e7c78c
+Payload = fcf8982f7342f1b953658453cd5ea413700eff00f1ee7d6f
+CT = 63a306ae06e4bc62284b6e9397896c030ef4630ad4d8c9c731df6fc6b4cf0b6332936ed7cfe9455e
+
+Count = 315
+Adata = aa540554ee80dbffa475f702d862d6b60e0a4090792420a26d02926517723e
+Payload = 0d5690d2a7083ad6daf22b308314b8f5363aca77ca72835e
+CT = 920d0e53d2ae770da1dcc1f0d9c370e548c0567def4437f67c8162a815f2809601ad02595e2e0ff4
+
+Count = 316
+Adata = fae86f95dd06fb7fbae63a646615555aec8153dc328bdf79da5d4cc9677ed6
+Payload = f6e313cc35e8f8812b10a44f8ad00b6893f8084d942effe0
+CT = 69b88d4d404eb55a503e4e8fd007c378ed029447b1184b487fcaa11bdeab86f60f9cd0a2b45cee1a
+
+Count = 317
+Adata = fd525302d2fb246a47cf4e3a27808bda89d8488cf450f1a1c7df6eedd810ee
+Payload = 91e961ea2eb750577c5137c609602dbfcc4c07955ba429ec
+CT = 0eb2ff6b5b111d8c077fdd0653b7e5afb2b69b9f7e929d440a86a810881bd969744ad80f579400f1
+
+Count = 318
+Adata = 767b1bdf9793a512d3a84e99ef77b43011a3bcb8de4cd375dfe47a79293e01
+Payload = 98438c4411bead6f30c89ead762a12bf39391d3652b78b7a
+CT = 071812c56418e0b44be6746d2cfddaaf47c3813c77813fd2250ca00d3231819ecdf501ad39c864f3
+
+Count = 319
+Adata = aac7014f606df6feec415a75e29015891007f07518c955875fbf5619262ff2
+Payload = 540cb00c0eface3d1b2d632d80a642f53c78ff672a1ff6ff
+CT = cb572e8d7b5c83e6600389edda718ae54282636d0f2942571224d1d0294d46981d7dc39114a693d2
+
+[Alen = 32]
+
+Key = 5a33980e71e7d67fd6cf171454dc96e5
+Nonce = 33ae68ebb8010c6b3da6b9cb29
+
+Count = 320
+Adata = eca622a37570df619e10ebb18bebadb2f2b49c4d2b2ff715873bb672e30fc0ff
+Payload = a34dfa24847c365291ce1b54bcf8d9a75d861e5133cc3a74
+CT = 7a60fa7ee8859e283cce378fb6b95522ab8b70efcdb0265f7c4b4fa597666b86dd1353e400f28864
+
+Count = 321
+Adata = 55a62968c222a8501d1ae56a9a815667f8a9554607b7c56e6753f8fa92a4d054
+Payload = 764dbefb42644d18d23e5e4568685d14dbacfa418d36c4ef
+CT = af60bea12e9de5627f3e729e6229d1912da194ff734ad8c4423862a715dda2f63a4197f894515803
+
+Count = 322
+Adata = f8436e35b7a1c810ac6aabe8e2d48a3678d19e1e96337dada514ee5fc075fce4
+Payload = cecef24b62676a5623bedae8087b9b05d7e22b41a14dd2d5
+CT = 17e3f2110e9ec22c8ebef633023a178021ef45ff5f31cefec200f190bd700f6108f9959f6d12f0f0
+
+Count = 323
+Adata = 548e2152f3a15b8fb81dc01062d99f7b4fc8f074e5cbdc1030c97f8ccc02ec3f
+Payload = 53c164a4990c6e0637267ff2556c1542712fc584f6ff7458
+CT = 8aec64fef5f5c67c9a2653295f2d99c78722ab3a088368733a66ebc4e0777a6fc140a51e04a10f86
+
+Count = 324
+Adata = d100f1d08ef1e3eda4aef22cd970c2b785c4ff9b523c401b4064324aecf7f2d9
+Payload = 15681d2121ac56a63b9d0a38b9c4eccf84fdb746d32c14b4
+CT = cc451d7b4d55fedc969d26e3b385604a72f0d9f82d50089fb810cdc08db0a9966dffeb43ba26446e
+
+Count = 325
+Adata = eece934a807c9f21487cd810f15fd55d7bb4421882333ff2c43b0353de7fc5a6
+Payload = 412a8ef924ca156de860f147575e5731825f0a3759688928
+CT = 98078ea34833bd174560dd9c5d1fdbb474526489a7149503cfc5b397578f8d02a0b936ffac29b99a
+
+Count = 326
+Adata = 86311ff444d9be90459b6ee3652e1705ed0b5cdac3d27293ddea3378fb686ee5
+Payload = 54ba8a020d0876fa369dc32e8627f565ba3dda862ea0bcfe
+CT = 8d978a5861f1de809b9deff58c6679e04c30b438d0dca0d52c3fcd6d618c260d51724126f257534a
+
+Count = 327
+Adata = ab6efbc44a8906d5c067eaed71af467e130aaf170827a58beb03c55069674125
+Payload = 7a15506fd1dae444d77b2a3ae7b57a8d5b4f10e25a9f78e2
+CT = a3385035bd234c3e7a7b06e1edf4f608ad427e5ca4e364c9bf8b2821920640b992b00cd1c9618025
+
+Count = 328
+Adata = ddb640923d083725587aced81ae1d7409983d1f1e3ccc8dcf94376dc1bbcae8b
+Payload = b18a61a89cd698f32e059b7a2a9f62a46be2c248790a9915
+CT = 68a761f2f02f30898305b7a120deee219defacf68776853e4cd52d41a968284af8907ccbb4588cc0
+
+Count = 329
+Adata = d95ec4a6f594be1ba39fa1aa933dc0a5dafff5ce44509577ebb3a3e8084c4401
+Payload = 16ee3bc9ec8b4448e292b8973618e02a99da1c348539d5c7
+CT = cfc33b938072ec324f92944c3c596caf6fd7728a7b45c9ec47449a5cb4943ff2846c589b7c98ef49
diff --git a/lib/crypto/test/crypto_SUITE_data/VADT192.rsp b/lib/crypto/test/crypto_SUITE_data/VADT192.rsp
new file mode 100644
index 0000000000..1a7a5875fe
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/VADT192.rsp
@@ -0,0 +1,1823 @@
+# CAVS 11.0
+# "CCM-VADT" information
+# AES Keylen: 192
+# Generated on Tue Mar 15 08:09:25 2011
+
+Plen = 24
+Nlen = 13
+Tlen = 16
+
+[Alen = 0]
+
+Key = 26511fb51fcfa75cb4b44da75a6e5a0eb8d9c8f3b906f886
+Nonce = 15b369889699b6de1fa3ee73e5
+
+Count = 0
+Adata = 00
+Payload = 39f08a2af1d8da6212550639b91fb2573e39a8eb5d801de8
+CT = 6342b8700edec97a960eb16e7cb1eb4412fb4e263ddd2206b090155d34a76c8324e5550c3ef426ed
+
+Count = 1
+Adata = 00
+Payload = 296fbda0017351491c2187273fbde2c3a427170e430a703c
+CT = 73dd8ffafe754251987a3070fa13bbd088e5f1c323574fd2167ee33e75d05023a7d63c770cfef2ea
+
+Count = 2
+Adata = 00
+Payload = eb61c284fe009921039ef6a9ce50e702823e44b35357923f
+CT = b1d3f0de01068a3987c541fe0bfebe11aefca27e330aadd170647420f79c0d91cbbd69b806fe96a5
+
+Count = 3
+Adata = 00
+Payload = ffeccc6460d23fdcc387c697e75dbb959b78013a8282eaa4
+CT = a55efe3e9fd42cc447dc71c022f3e286b7bae7f7e2dfd54a8a3ef2324754539ac774872282534386
+
+Count = 4
+Adata = 00
+Payload = 90958d7f458d98c48cbb464c74bf495a49846dd468c514e9
+CT = ca27bf25ba8b8bdc08e0f11bb111104965468b1908982b07e292cd0e32535a848e327bc53cdae94c
+
+Count = 5
+Adata = 00
+Payload = a4fad5205d38206e25097075687ca86032b95b3fe7e82a07
+CT = fe48e77aa23e3376a152c722add2f1731e7bbdf287b515e9bb21701af36936be5f62d02b84df87c3
+
+Count = 6
+Adata = 00
+Payload = b37114c65372b052cbeecf83d05a5da44f7b5bbff7d986b5
+CT = e9c3269cac74a34a4fb578d415f404b763b9bd729784b95b7da7f975367be24341e4af51b8bb156a
+
+Count = 7
+Adata = 00
+Payload = 9c0f0426f171ff18b2a4392f61fb4ee4a44c476fe03dc930
+CT = c6bd367c0e77ec0036ff8e78a45517f7888ea1a28060f6de360c6d50a96f316eda0b216cbb6380ef
+
+Count = 8
+Adata = 00
+Payload = 7b6e0a480a40585545b0e940e8d97c9ec987bd3c0e9c16a8
+CT = 21dc3812f5464b4dc1eb5e172d77258de5455bf16ec1294634cd1bd98e8137b578a174e39efe09b8
+
+Count = 9
+Adata = 00
+Payload = 34dac6dbc28be62332a6935efc122e37b26ee100eb4033f8
+CT = 6e68f4813d8df53bb6fd240939bc77249eac07cd8b1d0c16909a895a3b08b63d7a2a1e75d25e7861
+
+[Alen = 1]
+
+Key = 9748798c0f3cc766795c8ce0e4c979c1930dfe7faefea84a
+Nonce = cdf4ba655acfe8e2134fa0542f
+
+Count = 10
+Adata = 67
+Payload = 100fa71462277d76ca81f2cfdb3d39d3894b0ca28074a0f0
+CT = 36e2415b4f888a6072f260d7e786d803be16f8b9cbee112d7ff74e3b05b7d7c13284573bd3e7e481
+
+Count = 11
+Adata = 17
+Payload = 0217eb6778691f8dfe2d0e5241f05fcbcf97b9171f4de3f0
+CT = 24fa0d2855c6e89b465e9c4a7d4bbe1bf8ca4d0c54d7522d3ee7ce845f85dfc770d96dee9ca54ccd
+
+Count = 12
+Adata = dc
+Payload = a78b7bc6c1a7250c5fc236f2a8343725a9a7bd3ca81b53e4
+CT = 81669d89ec08d21ae7b1a4ea948fd6f59efa4927e381e239dc14ddd8ae0aa5d810040a8d1d4da1e9
+
+Count = 13
+Adata = 0c
+Payload = 390c808d998582793bb10ee60568eb8d975c51d68b4e4da9
+CT = 1fe166c2b42a756f83c29cfe39d30a5da001a5cdc0d4fc746b40dec7e647720f1f5e8474bf570c2f
+
+Count = 14
+Adata = 3e
+Payload = bcd9747fb54184b61b2e9e049caa75e22006e250f3722c0e
+CT = 9a34923098ee73a0a35d0c1ca0119432175b164bb8e89dd3c10c4aac45d90119cce490cc8681a49f
+
+Count = 15
+Adata = 7e
+Payload = d0342e3cd2c1142b642da7297ee3b9978cec405e6810f12f
+CT = f6d9c873ff6ee33ddc5e353142585847bbb1b445238a40f2f9a95091d2cab7d3d9fa3e10d3e67ac9
+
+Count = 16
+Adata = e3
+Payload = 7fab91d1aa072947d22f0dc322355a022fe7f0747f4a184b
+CT = 5946779e87a8de516a5c9fdb1e8ebbd218ba046f34d0a996180f7818c373e89f7ff3003f53260060
+
+Count = 17
+Adata = 3e
+Payload = e487143dc4d98dcc6a2dfe6ee0f85d565d1f46bb0fafe62a
+CT = c26af272e9767adad25e6c76dc43bc866a42b2a0443557f71905f581585e59e3c8c038b5bf966559
+
+Count = 18
+Adata = 3b
+Payload = 976b489244ed6789a34251500057d1d4a3229367a42b9066
+CT = b186aedd6942909f1b31c3483cec3004947f677cefb121bbea56569c34f8d9eea23e85fec18cfc51
+
+Count = 19
+Adata = a5
+Payload = 71efa75961dfd60ad533082a8cfe111214eb02573adc4591
+CT = 570241164c70211c6d409a32b045f0c223b6f64c7146f44c212da23548f2ca4e9a8a07962be6422c
+
+[Alen = 2]
+
+Key = 393dcac5a28d77297946d7ab471ae03bd303ba3499e2ce26
+Nonce = fe7329f343f6e726a90b11ae37
+
+Count = 20
+Adata = 1c8b
+Payload = 262f4ac988812500cb437f52f0c182148e85a0bec67a2736
+CT = e6d43f822ad168aa9c2e29c07f4592d7bbeb0203f418f3020ecdbc200be353112faf20e2be711908
+
+Count = 21
+Adata = 9db5
+Payload = d5982c462ad40458660cd7b120ce07fce9afe812caedcebd
+CT = 1563590d888449f231618123af4a173fdcc14aaff88f1a89015e5cd97b7dd3d981321ae0b2d99e1a
+
+Count = 22
+Adata = 69cf
+Payload = 1a95f06b821879df3fd3ac52fc99a7c1d3e9775263b7d036
+CT = da6e85202048347568befac0731db702e687d5ef51d50402bf3e75863c7acd2699caba3cc301f4b2
+
+Count = 23
+Adata = 6c6e
+Payload = 373c157e59b934a1afb57d4c5dd9ca7fb736b206a6210bef
+CT = f7c76035fbe9790bf8d82bded25ddabc825810bb9443dfdb5d6a8f7a9f52a8038aa9dc1bdc9ed876
+
+Count = 24
+Adata = dafa
+Payload = 26e10a2ed8cc883a6552aee162c5542ff8bb8e758a1975f8
+CT = e61a7f657a9cc590323ff873ed4144eccdd52cc8b87ba1cc8a15603f10cbfdb041f8b2b12cc8f037
+
+Count = 25
+Adata = c8b1
+Payload = dd235b05c15479dfe0326ba206ac784eca50038bbeb35d32
+CT = 1dd82e4e63043475b75f3d308928688dff3ea1368cd189061278bf62ba6a4819513d49fdcdb45480
+
+Count = 26
+Adata = af48
+Payload = a0818342a5cae4a90ef281d3d1289d83f273f418a545fcbf
+CT = 607af609079aa903599fd7415eac8d40c71d56a59727288b8b4d00309b50f9ea72f8105c94475b52
+
+Count = 27
+Adata = b1cd
+Payload = 33c0d06b6583bb4d15b4a07364c4be70ac6e72795c3dae0f
+CT = f33ba520c7d3f6e742d9f6e1eb40aeb39900d0c46e5f7a3b220ba58e97936612c4183ba86705b2f9
+
+Count = 28
+Adata = 649a
+Payload = 3ba11282d61fe36e38cab7b559c2fd9cbe8bf7eb5863bde9
+CT = fb5a67c9744faec46fa7e127d646ed5f8be555566a0169dd87d602dc85bb260fb3df1221e2fbd10c
+
+Count = 29
+Adata = 593c
+Payload = a97faefcae36732fcfe47736c2334ea7d411bf7638b0c019
+CT = 6984dbb70c663e85988921a44db75e64e17f1dcb0ad2142deb3835b7eecad6dac9785ad1d370ede4
+
+[Alen = 3]
+
+Key = a74abc4347e4be0acb0a73bb8f7d25c35bae13b77f80233a
+Nonce = 6a850e94940da8781159ba97ef
+
+Count = 30
+Adata = a4490e
+Payload = 6372824bf416cd072a7ad0ae5f9f596c6127520c1b688ab4
+CT = b14a07bdc119d87611342c4c6935c5786ff1f9ae2eb49e6191c88a3cb4fbafcb8a4a157d587d7e39
+
+Count = 31
+Adata = 5cad2e
+Payload = 295f4f3417a77fcf0bbda17b0fd629ad57a6086573c87eb1
+CT = fb67cac222a86abe30f35d99397cb5b95970a3c746146a64235c34d1390bba5b008c3fb29c2df958
+
+Count = 32
+Adata = ebdf4c
+Payload = 86f354a505de941d34cd98e3af3706d56a938ab9a2797182
+CT = 54cbd15330d1816c0f836401999d9ac16445211b97a565575a733bba0a6992d0664dc77d2b5d194c
+
+Count = 33
+Adata = 7c0d70
+Payload = 88c3bfb546abe2f6bfc92a7c56c627e24ab92a8a87a6b43c
+CT = 5afb3a4373a4f7878487d69e606cbbf6446f8128b27aa0e90902a31b15eed99c2dc4ed1bf11cad96
+
+Count = 34
+Adata = 8fa501
+Payload = 75d4216bad77943bfe82be216157843b0da0fd16eeee8471
+CT = a7eca49d9878814ac5cc42c357fd182f037656b4db3290a42f25595ae00103d4eb20288158132e7d
+
+Count = 35
+Adata = b7aca7
+Payload = bf1401e8dcf6f681ed6dd74c7e23b7e54b384608b0e5ec52
+CT = 6d2c841ee9f9e3f0d6232bae48892bf145eeedaa8539f88760e67693b509ea4795b7da32c5c5d17f
+
+Count = 36
+Adata = 1f283f
+Payload = 7e623e7ef7d0a678b5d22a8402d89220f4f1bf759e3084dd
+CT = ac5abb88c2dfb3098e9cd66634720e34fa2714d7abec900880ef8ea380a1a0a38b2c20288e637a9f
+
+Count = 37
+Adata = e93f31
+Payload = 14f80e7a6298d85d31fb80376a394a8f88b0ae47f00450c7
+CT = c6c08b8c5797cd2c0ab57cd55c93d69b866605e5c5d84412d553aafe8536385d34c412c14d3a1563
+
+Count = 38
+Adata = 27e9a5
+Payload = 3330df12249639961f562a74b34f60b0a8bc7c783f6572fd
+CT = e1085ae411992ce72418d69685e5fca4a66ad7da0ab96628f594d366c8fc826ce58309e9053c27f7
+
+Count = 39
+Adata = 72d566
+Payload = 1a1860ac8c11c5d262f8141738cae8ff91ca05906dc98bb4
+CT = c820e55ab91ed0a359b6e8f50e6074eb9f1cae3258159f61cdd6ac6c42cd3d11e0344a9c1001e253
+
+[Alen = 4]
+
+Key = df052e95aea3769a433ce4e4e800b8418649bbe8c6297eb0
+Nonce = ba356d392c3f700f4f2706a4ca
+
+Count = 40
+Adata = 8ffc0e3d
+Payload = e8c1a89228d8212f75c136bab7923a89f9fea18e781cb836
+CT = 66b5d782323925e1bd0a8413a9a5a881356453d5df2cbeb199b2e1e803550dcdde55fd66ecb45edd
+
+Count = 41
+Adata = 2b4f9cfc
+Payload = a12c6324e022affd61b7e0d8cccbeb23e2e6c65355c1d586
+CT = 2f581c34fac3ab33a97c5271d2fc792b2e7c3408f2f1d3019e8fbc507244ba234a0581dc69962a66
+
+Count = 42
+Adata = b4de3039
+Payload = 7cccb26f1dd227bc77458b99fd9e00f8e801adaece7bfcd1
+CT = f2b8cd7f07332372bf8e3930e3a992f0249b5ff5694bfa5628a2857099af20a4ae08e687bdb02c75
+
+Count = 43
+Adata = bc59f18c
+Payload = 692b53c1355475c71ceff0b0952a8b3541b2938270247d44
+CT = e75f2cd12fb57109d42442198b1d193d8d2861d9d7147bc3e33a6416e387d9e571a1954471ec9cc7
+
+Count = 44
+Adata = 4fd9fd39
+Payload = 7e3e755e25bbe78d4a7770f9356ab9f4ff1bbfdba46383f5
+CT = f04a0a4e3f5ae34382bcc2502b5d2bfc33814d8003538572180f9735f994c8335e593f30b331a920
+
+Count = 45
+Adata = 296cd04c
+Payload = 997b712cd9295dc43cc19b40679f218c27af3e8c638d2e5d
+CT = 170f0e3cc3c8590af40a29e979a8b384eb35ccd7c4bd28da91990fa537d2657d01f66872ba9af22f
+
+Count = 46
+Adata = 88037d3e
+Payload = 577981ccb6c893dfe6405075fcb41507de7f9bfda860791f
+CT = d90dfedcac2997112e8be2dce283870f12e569a60f507f984915cb93e84028c7aedce1a2dadbb6bb
+
+Count = 47
+Adata = fc4bb852
+Payload = 37ba9f57ec230675ce060ba3d388095adf15907aa0b0673d
+CT = b9cee047f6c202bb06cdb90acdbf9b52138f6221078061ba25baa6385af8d7b807a2d2ab19aa4999
+
+Count = 48
+Adata = f40ec14f
+Payload = 401e0cdc132a9e4a9b5ceeed3c181f67e5203ea69508deff
+CT = ce6a73cc09cb9a8453975c44222f8d6f29baccfd3238d8786adcdb44870e1105b7318d8bad0af957
+
+Count = 49
+Adata = 90e2c63b
+Payload = 0234dae5bd7ae66c67ff0c1a3f1a191a0d7bceb451bc2b7d
+CT = 8c40a5f5a79be2a2af34beb3212d8b12c1e13ceff68c2dfa8b079fb71d45bd985bffd343c3362653
+
+[Alen = 5]
+
+Key = 16d345606a315ad2406abbcb43cd8cabe948107ba6d17a72
+Nonce = d4ef3e9e04f1b7f20ffc5a022e
+
+Count = 50
+Adata = a468f08d07
+Payload = d3bef460223c81e4579c9d1d463ac5e0881685de1420a411
+CT = abb85db49a9b1c8724ecbc734cc8373bd20083cfa4007b1cfe4d3a3bb25f89f692884be230c6035c
+
+Count = 51
+Adata = 4497649a54
+Payload = 81ad3f386bedcbf656ff535c63580d1f87e3c72326461ee1
+CT = f9ab96ecd34a5695258f723269aaffc4ddf5c1329666c1ecd05ae56511a230627e02d066c52a919e
+
+Count = 52
+Adata = c30ddd994e
+Payload = 84b88264afec06b370dfcebf5e1d3e2c1f005faf248b3215
+CT = fcbe2bb0174b9bd003afefd154efccf7451659be94abed188ef92fc17dca026f1ac1eaf78a05017c
+
+Count = 53
+Adata = 9573270f7e
+Payload = 9e4c8aa9b58a8eabc5586892f5541000b43f17d9a051a040
+CT = e64a237d0d2d13c8b62849fcffa6e2dbee2911c810717f4d38eddff1e60e2d9ae74a936364b8df21
+
+Count = 54
+Adata = 40336790fc
+Payload = 260f67122dfbe03365bc9e35e9d4ac4b2eb150eddb30857d
+CT = 5e09cec6955c7d5016ccbf5be3265e9074a756fc6b105a70aa3d464ad89cae59b474d019a5a7605c
+
+Count = 55
+Adata = 0b310c8529
+Payload = 1d55e7352bd895c4ef77389a7225c664f72b38c8de778d57
+CT = 65534ee1937f08a79c0719f478d734bfad3d3ed96e57525abeab0c520e64939c6950c0fa406eafb1
+
+Count = 56
+Adata = 5756b2c681
+Payload = fbd315e1f5bd0f0e60ee6684c88f3543452c62ea0701d11d
+CT = 83d5bc354d1a926d139e47eac27dc7981f3a64fbb7210e10d22d339c382343bf39c239fd64c2a64f
+
+Count = 57
+Adata = 3b919e3665
+Payload = d68d6556c5a5b1f5a123389b3ce966d5837cb8fcf5accfff
+CT = ae8bcc827d022c96d25319f5361b940ed96abeed458c10f2fcd6b562a1b6aa10be92a81f99ed540c
+
+Count = 58
+Adata = 58749b643f
+Payload = 062cb6962fa5b3a6239b95f3a51b478a1f32b081dc538a80
+CT = 7e2a1f4297022ec550ebb49dafe9b5514524b6906c73558d4b853022237d94d253b375bf2150e699
+
+Count = 59
+Adata = a5d50c008b
+Payload = 08c62ff9bd7bcf189f530d5065f8764532d2692f69858483
+CT = 70c0862d05dc527bec232c3e6f0a849e68c46f3ed9a55b8ee7aee0d403b2cf6f8b993eebd6b93615
+
+[Alen = 6]
+
+Key = 1c476cfd7dd300d961fd3f24a6fe0e80742b00851676ca63
+Nonce = e300fc7a5b96806382c35af5b2
+
+Count = 60
+Adata = 28130f938c45
+Payload = 6f3938932b5c1280311e892280d8a822a828a0be7fdb1bcd
+CT = df48662fe134e75a85abc2cece2c3b6236c88a70fa792e9beadc9601adf9fbdf4e3e94b395b0a332
+
+Count = 61
+Adata = f600024a7bf9
+Payload = 0af7345e71f4e8886503395ade0b0296a5856e086638b06a
+CT = ba866ae2bb9c1d52d1b672b690ff91d63b6544c6e39a853c0692a40a6aba8d7c5addae21de90fea9
+
+Count = 62
+Adata = 4eef510d1f48
+Payload = 37f57772f056f45a5ce9f46d27be1858980c8935b9c839b7
+CT = 878429ce3a3e0180e85cbf81694a8b1806eca3fb3c6a0ce122f64becb581070411957e632e19bb8f
+
+Count = 63
+Adata = 4c9c76b6fad5
+Payload = 8bb10c82bcabb7fb2b169252ab443b01df217cf908b8c241
+CT = 3bc0523e76c342219fa3d9bee5b0a84141c156378d1af71708c59f83aa97d069b6d83d9387051f43
+
+Count = 64
+Adata = 5572ecfc7e53
+Payload = d1ccb4654a22b1afe32f3d3035fdccd87e9cbed83c679007
+CT = 61bdead9804a4475579a76dc7b095f98e07c9416b9c5a551f04686ee1d7b985d903f1de6cf78f8f4
+
+Count = 65
+Adata = bffdf9d20d74
+Payload = f990a8f6ba14065d48665db36eb470c49f38e2b6376a9bde
+CT = 49e1f64a707cf387fcd3165f2040e38401d8c878b2c8ae88f8118f1b9f39b51965ae9ef1bdb40111
+
+Count = 66
+Adata = 3f27e678c580
+Payload = f8c7d89639ab742a8bcfffe776e868d671e1fbdd55807a8a
+CT = 48b6862af3c381f03f7ab40b381cfb96ef01d113d0224fdca3236d02f33f49759f281315e449bfef
+
+Count = 67
+Adata = 1294cb9db5f5
+Payload = 8601cfd7d935e8a8487b9c39d55ca27096255f2eb9e009e3
+CT = 3670916b135d1d72fcced7d59ba8313008c575e03c423cb5e74770a07c242c3854ceb242dadc1976
+
+Count = 68
+Adata = cec271332b75
+Payload = 77c85b8022f58337b364142a2474fe5cfddb31cfca48af46
+CT = c7b9053ce89d76ed07d15fc66a806d1c633b1b014fea9a10d6c65f19175cfa49898655ccdddb864a
+
+Count = 69
+Adata = da06bd140502
+Payload = b0f2db802475fa70af02057373844f637a3244cda4b4f93d
+CT = 0083853cee1d0faa1bb74e9f3d70dc23e4d26e032116cc6b458822e49e69031431b3eea872a72eb7
+
+[Alen = 7]
+
+Key = 79d1e38a70df1cf239be168833dcd0570bc8f37b3aa26c37
+Nonce = 8229d6d7e9e21fdc789bff5dcf
+
+Count = 70
+Adata = 076887d2abe900
+Payload = 83c24f3a77b83b4ef45277ba90225f3ba1722312f52b1a07
+CT = 19d880f1d959a68f162de243d4a45747ace704613359b27218d1531a066de60a95d2924a6910e990
+
+Count = 71
+Adata = 7535bcc6fbd1a0
+Payload = 24f85ef683cc521387f484bc0b2ad9172f61884c09a9718c
+CT = bee2913d2d2dcfd2658b11454facd16b22f4af3fcfdbd9f96dbf58406020e6df7b312b6825127f9a
+
+Count = 72
+Adata = f4f96d7b4384a3
+Payload = 212bedfa06b5e1a2c3a2f31f6f791dd9df8ef26077821c0a
+CT = bb312231a8547c6321dd66e62bff15a5d21bd513b1f0b47f64dd755177efc87f8b1daf1fd88e51a6
+
+Count = 73
+Adata = 3b7e3d9c1a7fa2
+Payload = 8b9036914bb0f440c8dbcfde9b9547be5e5ef1f56492c75e
+CT = 118af95ae55169812aa45a27df134fc253cbd686a2e06f2b0be31cab31f1a20805d5c07dc516d707
+
+Count = 74
+Adata = a8c35fae8912d6
+Payload = 50f3f3a91bf6fd9573d5ef54b9bb5805205b2f9865d81fd7
+CT = cae93c62b517605491aa7aadfd3d50792dce08eba3aab7a2399df9a45ad153c0dfb3fec3b9d6f7c5
+
+Count = 75
+Adata = db636541f2429d
+Payload = 6fbda8d435555e735443f1e6bc09e96065092efd89edd64a
+CT = f5a7671f9bb4c3b2b63c641ff88fe11c689c098e4f9f7e3fe20b7da94eac8c7ef8478671165e0d82
+
+Count = 76
+Adata = a8de55170c6dc0
+Payload = 640ef4c246a2c6e16ddc49072a5aeef70319149ffba071ef
+CT = fe143b09e8435b208fa3dcfe6edce68b0e8c33ec3dd2d99a4979c35bdbf9538666b6fa57f0f915d8
+
+Count = 77
+Adata = f8d64ce2aa66e6
+Payload = a14e3910766f31594a28ad2c3678c31d0c3aee88484ca6d6
+CT = 3b54f6dbd88eac98a85738d572fecb6101afc9fb8e3e0ea3752824a691da2e99374ae6c031d74ffb
+
+Count = 78
+Adata = b3c340afdc53a8
+Payload = 1b8e0a09e6364020b4cac704dc19bfa79455295604cf9c9a
+CT = 8194c5c248d7dde156b552fd989fb7db99c00e25c2bd34ef04159a68706faa2e8c3376b4dbeb423a
+
+Count = 79
+Adata = 73824034001519
+Payload = 52c84a0735eea6c5c230644075ebfc5db0c3128056e7a8f4
+CT = c8d285cc9b0f3b04204ff1b9316df421bd5635f390950081e5adc7564721ead2af75cb98e61148b4
+
+[Alen = 8]
+
+Key = 72e6cebdaf88205c4e74428664bc0d7eb4687a272217b7ca
+Nonce = 3820db475c7cb04a0f74d8e449
+
+Count = 80
+Adata = f427c47e10c45bb3
+Payload = 54bc7e3c227df4e83252a5848fea12dfdb2d14b9e67c1629
+CT = 91e7baff2b42af63e26c87ce6991af22422c1f82906858b1721961de5c768f4d19bd3034f44f08d2
+
+Count = 81
+Adata = ca25504f3f5559aa
+Payload = ff4493fea916f49fbb3cae2838bc84e293531092cc0904ab
+CT = 3a1f573da029af146b028c62dec7391f0a521ba9ba1d4a3342968c638ecb8a2b358e8eaefd931efb
+
+Count = 82
+Adata = 8215753d9efc5132
+Payload = af16ab8558269a93d8e8c9e38f12a8768947d8b69be0e259
+CT = 6a4d6f465119c11808d6eba96969158b1046d38dedf4acc1f8ac11752fe51e354f3f8a68815539aa
+
+Count = 83
+Adata = 9e7cdbc6202e6492
+Payload = 744a167ae31a8ca20df82290766429de9ef0b7dfe199a78d
+CT = b111d2b9ea25d729ddc600da901f942307f1bce4978de915489de8e241dcab16bdcbf1a1ff4d8d10
+
+Count = 84
+Adata = b8d511d0ab86a07f
+Payload = eeb39de1fe21b5aba654da45fe1481decb22365fa4cbe49d
+CT = 2be85922f71eee20766af80f186f3c2352233d64d2dfaa053fab212a1b6dc7b953e2bc211be194ae
+
+Count = 85
+Adata = c74a5d4265f9f3d5
+Payload = e95c20e80153bae3fde3c3d82b6b33b35fc1959fa31a5d11
+CT = 2c07e42b086ce1682ddde192cd108e4ec6c09ea4d50e138973918ab70fe048d6c5b63a01725eddfb
+
+Count = 86
+Adata = fd849d3ada03181a
+Payload = 6d00606c72cea3deaea5b51ae09e61924355e167058ef42c
+CT = a85ba4af7bf1f8557e9b975006e5dc6fda54ea5c739abab487089bc20867f474c1127aa1320f0000
+
+Count = 87
+Adata = 56825a68681f498c
+Payload = c47705d897a6c7e7aed710b96e2d8532c23b82090e21b114
+CT = 012cc11b9e999c6c7ee932f3885638cf5b3a89327835ff8c34a23b0b6ac4d297dd7832a5e2102272
+
+Count = 88
+Adata = 72e4da839913a26e
+Payload = c822a1ee581cf85b0482c821473385bd3f28528e5e5760d9
+CT = 0d79652d5123a3d0d4bcea6ba1483840a62959b528432e41dd665766c7af21ff890bd40178f1c660
+
+Count = 89
+Adata = 138457571ee8dafd
+Payload = 3ffb82a83308da66e95ac63ae92931b09ffe0e42afbb4979
+CT = faa0466b3a3781ed3964e4700f528c4d06ff0579d9af07e16a6a58bb772c79481dc26861ffbd68c6
+
+[Alen = 9]
+
+Key = 39c03a0c8634047b1635348f284d3dc1e752ab40548eb337
+Nonce = 9e2ea8eb7f56087ee506925648
+
+Count = 90
+Adata = 28d157f09a71da80dd
+Payload = 0662e63c88e963d3e0cf2c4653515ae4474a2c78ab0394c0
+CT = 01dcd4dd3b8c1369518136ce45e8bb9df565b0ad231a887b02ada34addf0aa2f4744ed2e07995491
+
+Count = 91
+Adata = c17d311362c41d442b
+Payload = d6df8b60c697093987b3d89a3667b36504b6ddddf12b0900
+CT = d161b98175f2798336fdc21220de521cb6994108793215bb38a27466b8741bffce44ef04b23af321
+
+Count = 92
+Adata = 006669ef1a11b65b1d
+Payload = 49ad29ef5e82b08752ac5a50dd982e4bcb700005454ade6c
+CT = 4e131b0eede7c03de3e240d8cb21cf32795f9cd0cd53c2d77d11372fb0dab1c99b159e5fe9f91118
+
+Count = 93
+Adata = 8eafce9ba466fd53eb
+Payload = 385f9fb139dbf88561b7a500b0c7b835fe57e2698c6d9f76
+CT = 3fe1ad508abe883fd0f9bf88a67e594c4c787ebc047483cd09e4898a4046f6ec9f40e412915007e4
+
+Count = 94
+Adata = 796e55fbe7bed46d02
+Payload = 4ebb149b01cbacba32d11168ca61928ea149dcf2ee2c1001
+CT = 4905267ab2aedc00839f0be0dcd873f71366402766350cba5d40a9902481bfac7ff33d08fb4b3d31
+
+Count = 95
+Adata = 8f958d796be0566512
+Payload = 0d974e5621caa1d86eaaee689ccbca57843373fcf20db407
+CT = 0a297cb792afd162dfe4f4e08a722b2e361cef297a14a8bcd972d09a17172161eb68a30b593b1bd6
+
+Count = 96
+Adata = cc879ff2d583a7288c
+Payload = f8e0dac6a691dfb231411b5c5f70a0daff83cc637b0c7bb3
+CT = ff5ee82715f4af08800f01d449c941a34dac50b6f3156708119cc26a80c152c253fbc36cb886e0fc
+
+Count = 97
+Adata = 4765d696d19dec58bc
+Payload = 096a36396ccfa260f28fb0919157a5076b53506c51a2a4ef
+CT = 0ed404d8dfaad2da43c1aa1987ee447ed97cccb9d9bbb8549de06cc5c3bc4ad75076c774576843fb
+
+Count = 98
+Adata = a004f283afc3309c31
+Payload = 5b943269be41e2758a4ea6a3cc621b711a8ba6002783aa72
+CT = 5c2a00880d2492cf3b00bc2bdadbfa08a8a43ad5af9ab6c9135493b44f79a5774df6b2943b0bec67
+
+Count = 99
+Adata = cdd5d8aefe49a315ad
+Payload = 5f27867109e74862ce0dbc9ba73c420b93067bdede17ae51
+CT = 5899b490ba8238d87f43a613b185a3722129e70b560eb2ea7a5da4a29a9012d78b6de6f1b3e8c9ed
+
+[Alen = 10]
+
+Key = e2a92ffbb0b5eb68cb82687f12449fae5167d375131b0b10
+Nonce = 441ad5e1382e083a95224f395d
+
+Count = 100
+Adata = 2352648299b0413cb2ce
+Payload = 048c9ba4597c3bb595bfd5048e5e9a1296f30e5c0118b177
+CT = 25247a258e4ac0a988d8def60cc174a9d4578cd5346fb5150c96e8ab8774baa421f39c64a386c418
+
+Count = 101
+Adata = ce003c836a6f5f066053
+Payload = 02ea8e7e488c863584f828df13dfeb68433294d11d9ca9d7
+CT = 23426fff9fba7d29999f232d914005d30196165828ebadb5d453036cdc6bad0c5e770a6249a52e74
+
+Count = 102
+Adata = d11be73a104ccc6346d5
+Payload = 6d5573c9279897d7d1602d8a95c04bb5ca3fad2dbe89a024
+CT = 4cfd9248f0ae6ccbcc072678175fa50e889b2fa48bfea4464627ad75bbfe17f3f5ddfd3dbc1045f3
+
+Count = 103
+Adata = 6a7b80b6738ff0a23ad5
+Payload = 97a813e75d95d25c2edb1c705c4ffe4d7c08c756761fbc0b
+CT = b600f2668aa3294033bc1782ded010f63eac45df4368b869af8943f74706cc3394a170fd49f7011a
+
+Count = 104
+Adata = a391acdb3a06dae4a671
+Payload = a78981ac244307451e4d3fd7f654b70cc4e6518aa47a3c18
+CT = 8621602df375fc59032a342574cb59b78642d303910d387af22597f63074ca3533bb5e107860481f
+
+Count = 105
+Adata = 0b9f28f2d3215785f569
+Payload = 5d649d79ff0e304e164a383c74f13d7ffab145d00cb0ec2c
+CT = 7ccc7cf82838cb520b2d33cef66ed3c4b815c75939c7e84e905b5609f593c6ea9281f66cd2e646dd
+
+Count = 106
+Adata = 7928b1091cbfb2eef0fe
+Payload = 83a273687dced7b94d569f81d75508595cde668f06406183
+CT = a20a92e9aaf82ca55031947355cae6e21e7ae406333765e1428195355618ea0cf87260ad20b6d7b9
+
+Count = 107
+Adata = 3b74afb81f54a93c79d5
+Payload = b4dc3c059cf7b47dd0bb7f165a63fc80b5c6b5f3ca7eeb73
+CT = 9574dd844bc14f61cddc74e4d8fc123bf762377aff09ef1155019659f41a5f0430695b4ada9d8b8d
+
+Count = 108
+Adata = a46ae4c71d4c9eb72fab
+Payload = 7e919581c5105d98717d0613e1ca869c6516506ea482d5c2
+CT = 5f3974001226a6846c1a0de16355682727b2d2e791f5d1a01514b252f33dc870c42260e48c4fa9fd
+
+Count = 109
+Adata = a1ace61711f0a09ac17d
+Payload = 3a4558b55214f21cbd2ae2eda5a2321cfc2f102e059b744a
+CT = 1bedb93485220900a04de91f273ddca7be8b92a730ec7028c263c667d7ed58907452c092905d0b31
+
+[Alen = 11]
+
+Key = ef1ad3eb0bde7d4728389da2255d1f8a66ecb72e6f2f1ac4
+Nonce = 8e7d8a44244daa7df2b340993e
+
+Count = 110
+Adata = 521583c25eb4a3b2e46120
+Payload = 9f580cc6c62a05ce125c6bec109a48ca527ee26a64b14b68
+CT = ff0ff95bcb0bccd5e4aadd77ac6770f5013654eb3c6386fded2c87135861b43a99f258b6938f66e3
+
+Count = 111
+Adata = 31adb39e947f8883fa4b69
+Payload = f16bba081bddda83546eabc9a55c81a439720dd8562ce964
+CT = 913c4f9516fc1398a2981d5219a1b99b6a3abb590efe24f132b87476d66a1bd405f484ef9ac8ab7e
+
+Count = 112
+Adata = f05f39eb0a3d6460076aa8
+Payload = 6baf784f63cf45a1836fa8f3609fff7870ce8cbd1e91268c
+CT = 0bf88dd26eee8cba75991e68dc62c74723863a3c4643eb19a120b455b366cb104fd8b6dc2c80471e
+
+Count = 113
+Adata = 74c7a633ff73ff507009c5
+Payload = d8176a6de1c15a14c8b8b58725c179dc84c9308268d718d5
+CT = b8409ff0ece0930f3e4e031c993c41e3d78186033005d5400c8ca09f4bf06b1c27e75abf15112e49
+
+Count = 114
+Adata = ab322a88cf44b9ca774415
+Payload = 3706e4d8ff748574f382e5f9b0a3b6258f1f360fd87001b0
+CT = 57511145f2554c6f057453620c5e8e1adc57808e80a2cc25b3159274a7de3550baf759f7fae53dbc
+
+Count = 115
+Adata = d6fe6e17221d4e06ed3ab9
+Payload = e02217394772deffe218c405e40f2a3a56ca01d55d6d3330
+CT = 8075e2a44a5317e414ee729e58f212050582b75405bffea516fba8d193e133e6f78daa39681cb262
+
+Count = 116
+Adata = 2739d2cdfcbe7d5cd7d28c
+Payload = bb713f74a884bd1a994adba87561d637853c6181290ef5e8
+CT = db26cae9a5a574016fbc6d33c99cee08d674d70071dc387d65f92db3b3d1c2de04c69c5d06b0e001
+
+Count = 117
+Adata = 5841571299cd064a6262b7
+Payload = 9641dedd50d80ac0abf7591436065fa2e23e4687abbb86e4
+CT = f6162b405df9c3db5d01ef8f8afb679db176f006f3694b716e4d20ab5ffad6f71155f6839dfdbb25
+
+Count = 118
+Adata = dc5d7fd97bb3243ba585fa
+Payload = aefda8501193edacb8abb94fff875529a537a462c4b9b69c
+CT = ceaa5dcd1cb224b74e5d0fd4437a6d16f67f12e39c6b7b090ebc3af2de52b8bee3d130fa973f716b
+
+Count = 119
+Adata = 8789e0b3e0dc13d9725b37
+Payload = 65e53f549b62aca03f21ab2a494b93805e02cfecf4f12aa4
+CT = 05b2cac9964365bbc9d71db1f5b6abbf0d4a796dac23e731b5cd5a004a0ef28e30383bdaed8f93c7
+
+[Alen = 12]
+
+Key = 44cba20b7204ed85327c9c71c6fea00b47ce7bdde9dea490
+Nonce = f3329154d8908f4e4a5b079992
+
+Count = 120
+Adata = f1e0af185180d2eb63e50e37
+Payload = 6333bde218b784ccd8370492f7c8c722f8ef143af66d71d7
+CT = b9401a4927b34dc15e9193db00212f85f0c319781ec90e3b4484d93cb422cb564acc63d3d18e169c
+
+Count = 121
+Adata = ea74231e49e667ca1c21d46d
+Payload = 3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e
+CT = e67d8fbeec794d42fc64d7f36a87d2ac22aafa440021ea72c4c151d9927e6a9f19d47ff7d79ca6f6
+
+Count = 122
+Adata = 7f5871a8300471dc325f8289
+Payload = c642c9722d84d708682350dc70bdaa9a1181a415a9e72b93
+CT = 1c316ed912801e05ee85c7958754423d19ada9574143547f959eee29be1415ab03444de0fa42707d
+
+Count = 123
+Adata = ee7e6075ba52846de5d62549
+Payload = 2286a1eddd80737a724ca941217e9f0232870b6c2f20d29c
+CT = f8f50646e284ba77f4ea3e08d69777a53aab062ec784ad70ce97c1c8aea70de04580d7b37f8c014d
+
+Count = 124
+Adata = a30f2fd445820cdf80014554
+Payload = 92577d5db20391110309d490f52acecdfc18382f368bbe42
+CT = 4824daf68d07581c85af43d902c3266af434356dde2fc1ae23b536f993381e525a14599dd5c02e80
+
+Count = 125
+Adata = 0cfec933831644b468724e80
+Payload = 6803dc3f7c06568ca78ee5aa2e9b1b354a4f1e067ff6a25b
+CT = b2707b9443029f81212872e3d972f392426313449752ddb7d6ea722fdd82ede2c7b8832dde3cbe80
+
+Count = 126
+Adata = 6bd14e3bf91dc7fd6be07647
+Payload = 5580672e52aacb9d714a34c31c33fc221e13e8f90849adba
+CT = 8ff3c0856dae0290f7eca38aebda1485163fe5bbe0edd2565c2994b2b469ad977564d83db1ebfe38
+
+Count = 127
+Adata = 6c6ad35e97d023217018162f
+Payload = 1bd1bcc6766d251144376d91ff93ef83033d0e0ee546266f
+CT = c1a21b6d4969ec1cc291fad8087a07240b11034c0de25983ac31ebf9e255eecf3c69ddf198760556
+
+Count = 128
+Adata = 52c35db85cc34b6efed180ee
+Payload = 28f71a2fe498f89203a5d23e8f8fa64b124aea6459fe721d
+CT = f284bd84db9c319f8503457778664eec1a66e726b15a0df13424079e3de87fa59c3d10fd62380a90
+
+Count = 129
+Adata = a96e4776270683ee7d0c9b6e
+Payload = 5be078ead1926074afca81f9a97dc93dcb954c955e4343e4
+CT = 8193df41ee96a979296c16b05e94219ac3b941d7b6e73c082258e1f3fc3eb7e976c86c8a21bd6569
+
+[Alen = 13]
+
+Key = b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731
+Nonce = 13501aebda19a9bf1b5ffaa42a
+
+Count = 130
+Adata = ead4c45ff9db54f9902a6de181
+Payload = 3726c1aaf85ee8099a7ebd3268700e07d4b3f292c65bba34
+CT = fd80e88f07dad09eed5569a4f9bb65c42ef426dda40450119503d811701642143013f28ce384d912
+
+Count = 131
+Adata = e63b89e95df8338ecdcc885c3b
+Payload = 37f86aa62b1e31e9ded3e1a38a7e1a8a638d619ac109694f
+CT = fd5e4383d49a097ea9f835351bb5714999cab5d5a356836ac6d3f9c7b9f25e09ce164a11370b8b05
+
+Count = 132
+Adata = a2161536e263459e0b0a29a225
+Payload = 1749f5977197359a5d318d5fea38aba95b3603f1d7011e66
+CT = ddefdcb28e130d0d2a1a59c97bf3c06aa171d7beb55ef443e02b848b006c28803303fd97bdc35476
+
+Count = 133
+Adata = 8ac95a6ae0bce0fb07f85368ab
+Payload = 0842bfb8b38283257c2ea58b29c8350775f1dbf15f73c905
+CT = c2e4969d4c06bbb20b05711db8035ec48fb60fbe3d2c2320431de2bc45b2b726bfda92939a11f68b
+
+Count = 134
+Adata = 44cc9b2510680c4d73f1938c77
+Payload = 68d09fce5e89e4ef6d453b8ee326090cedb97b75b886c7b3
+CT = a276b6eba10ddc781a6eef1872ed62cf17feaf3adad92d96786add8c2619f0782ca12312a1d64266
+
+Count = 135
+Adata = d8a662ab8449bd037da0346a24
+Payload = 45245de4ac6a6196a0b15b77c622a21bb50627379ddb4256
+CT = 8f8274c153ee5901d79a8fe157e9c9d84f41f378ff84a873b6bd4a09f9b4aa2864d39ff1a03e0ff7
+
+Count = 136
+Adata = 8ed39da1d9179e77156eb909f3
+Payload = e928e37dbe8389a53c650edc86f83cd3589a53dc8e45adfd
+CT = 238eca584107b1324b4eda4a17335710a2dd8793ec1a47d819b6935778ffbc0953974de0a9d87a31
+
+Count = 137
+Adata = 423515f7bd592d6a7a2408661a
+Payload = 4c3bdc6186297896097b3297ba90bcde78dc8a9efe3bd8b1
+CT = 869df54479ad40017e50e6012b5bd71d829b5ed19c64329400a3da0d3ce34a272b51582a998f461e
+
+Count = 138
+Adata = 5a6bc2cd6890a473d478a582b4
+Payload = 1c5ebaeb7b926a39b8aaf65a4c484b113d6f2caafadc33ea
+CT = d6f893ce841652aecf8122ccdd8320d2c728f8e59883d9cf4ef28c338f497a40f550f2945734ad1a
+
+Count = 139
+Adata = 7bdc26b5b4df58af539d91eb2e
+Payload = be5c9fee6babf569c66e6a0d0f3c4dc314f40c0aeca493f7
+CT = 74fab6cb942fcdfeb145be9b9ef72600eeb3d8458efb79d2e07f1998e57ba9b611568632dc5cb9fe
+
+[Alen = 14]
+
+Key = 13f179aa2a23bc90a85660306394940e9bb226ce3885ec01
+Nonce = aaa52c63ca1f74a203d08c2078
+
+Count = 140
+Adata = 5cc924222692979a8e28ab1e0018
+Payload = d3b36c6289ad6ae7c5d885fe83d62a76270689ce05fa3b48
+CT = bc4fcef401c2e1d1c335734ff23ea52c3474d2e6f31648a7f58649400ac9e825b038d67f0c2a6f1c
+
+Count = 141
+Adata = 21fb9cdd9b110bbbc6832275dfa7
+Payload = a7742dd9c3e8bbad08157fbd01ebfb94e1639117c4b4eb5d
+CT = c8888f4f4b87309b0ef8890c700374cef211ca3f325898b23fa5ad4142e0b4650fa5cc8f7ef70d62
+
+Count = 142
+Adata = 9919ddb6ee6c330646cd15953d39
+Payload = 297b4498bf5427e6341aa9275c1f62e3b0c9b150a195ae72
+CT = 4687e60e373bacd032f75f962df7edb9a3bbea785779dd9dfec551d11b8647432cc4320173939600
+
+Count = 143
+Adata = f94cfd1f8c7902a57784c10b9a5a
+Payload = 2218868033e17220655f0196dab6193c58293ca105d467d9
+CT = 4de42416bb8ef91663b2f727ab5e96664b5b6789f3381436a79a075ec2cacee1482b8328b697a3b2
+
+Count = 144
+Adata = 63f3fe58c348dc6bcbb44c3c370f
+Payload = 4a9bc26fb10000a57b9e73a8a3d30f66ef9de8782201ffa8
+CT = 256760f9396f8b937d738519d23b803cfcefb350d4ed8c4739cbe17b4edd64a3dcd2b8ae3352c04a
+
+Count = 145
+Adata = dec0ce763833305aa9c9efdc2c65
+Payload = 1b61b3ff3e4847a17f55f7565826b0e2ccc1368f4de32022
+CT = 749d1169b627cc9779b801e729ce3fb8dfb36da7bb0f53cdf54665c476d0741164685b0d81caca31
+
+Count = 146
+Adata = 592ef6784ee839a049e0d96257fa
+Payload = 32e5998b37987a38800f5bfe3132979ca1447314570aaef7
+CT = 5d193b1dbff7f10e86e2ad4f40da18c6b236283ca1e6dd18500d93b11fecc8b4560320878ba53550
+
+Count = 147
+Adata = 4a47a82b999a2a739959f153a091
+Payload = 84acfb6cf10b301558e5acbf41bbbe0b145dc66dc600f4df
+CT = eb5059fa7964bb235e085a0e30533151072f9d4530ec87303c2a41443578adaf31483bbb6b9f10b0
+
+Count = 148
+Adata = 4ceba98cc0ff5de1a7d580cf23d2
+Payload = d7c73d77a286df38aad116843620911c92e11486be5fcb0c
+CT = b83b9fe12ae9540eac3ce03547c81e4681934fae48b3b8e32232a856c07999e99a4701988b486ef2
+
+Count = 149
+Adata = 15e3b3c5794fececd703ac58ccb2
+Payload = 140882c5d3534bb0861e7ba9423e67439a02ee6f0b0b00f3
+CT = 7bf420535b3cc08680f38d1833d6e8198970b547fde7731cb3a6d50a92f3183c0c5090edc3c7f822
+
+[Alen = 15]
+
+Key = c1dfc48273d406a3a7b9176f80b2dc4e9a7f68134bab66d2
+Nonce = 1ac53ba965cdaeeef7326a37e4
+
+Count = 150
+Adata = 39ba54a410a58a5d11615a2163cc3b
+Payload = 67d9728a88f1fac3af43ed6d634ba902896bd226858697d9
+CT = 360f0fc714994e3b59448b50cdd61d511b4f09e0e5fb5ac826a51fe5b9b598a17eb3da10f936813b
+
+Count = 151
+Adata = 38b0cca09d69320105d24ee3f96684
+Payload = a8365ba9fcfff060b28895f7a2d786c5991a8f7758962caa
+CT = f9e026e460974498448ff3ca0c4a32960b3e54b138ebe1bbba673a94f4280e84724f4a2510165e9a
+
+Count = 152
+Adata = 76718dfb9c68acdd82592d96def39a
+Payload = 497be597dd695cb159d8a64f44049c3b549ac927837b1b90
+CT = 18ad98da4101e849afdfc072ea992868c6be12e1e306d68118865ab37be6f015316e0d177b6c2e91
+
+Count = 153
+Adata = dd719ba1710916a546233c1494a7a7
+Payload = ca452c21383ebc3fb584f0d59a227374854983f243a3f460
+CT = 9b93516ca45608c7438396e834bfc727176d583423de39713d903f67ad0d72fb8ffea2035216b769
+
+Count = 154
+Adata = d893fa2bd7c70e21a5934dc2e99037
+Payload = 3dd118ed65453d3d7844d8de78d7a43587ac5e9305b11464
+CT = 6c0765a0f92d89c58e43bee3d64a10661588855565ccd9750b885e3e054f519d0355db1bd589bb35
+
+Count = 155
+Adata = 97c60265a3a6993b97ac1b375a79b8
+Payload = a7375ba32251af0138bd9fd8fcd56a7c43ab2ca9a7fc0117
+CT = f6e126eebe391bf9cebaf9e55248de2fd18ff76fc781cc064a950e4bed4137e38787839e39924821
+
+Count = 156
+Adata = acfdf302ed116ac4755069d1704423
+Payload = d39d188f28521e4fb0a0c5e48e6d6efe4383c95b2535ea8d
+CT = 824b65c2b43aaab746a7a3d920f0daadd1a7129d4548279cca94dd97fd2a5d50eb7dd6234b40c525
+
+Count = 157
+Adata = d449f97164aae9a3046624e98810bc
+Payload = 758102470e221e30d87d2807b5f8b793a7a56c83eecf32a4
+CT = 24577f0a924aaac82e7a4e3a1b6503c03581b7458eb2ffb596f11450d5d2ba55ffb4a6cf7eab847a
+
+Count = 158
+Adata = 3e6c914a196e175079315b1c92b2b8
+Payload = 1db875c4b4f9dd4926dfb5604d6c4d21aba7d905aed9d1b0
+CT = 4c6e0889289169b1d0d8d35de3f1f972398302c3cea41ca164894e9218ecacd143fb62df69a13d33
+
+Count = 159
+Adata = e2b7b00d0cfbdfcc24f1819ae1869f
+Payload = d7a75bc621addccbbe162b86d536d69c887c278384af54e7
+CT = 8671268bbdc5683348114dbb7bab62cf1a58fc45e4d299f685a7c19bc9c2f8e36ed95015ebb679ae
+
+[Alen = 16]
+
+Key = d8a662ab8449bd037da0346a24565683a3bbbbd1800e3c1c
+Nonce = 166fb8d0e110124c09013e0568
+
+Count = 160
+Adata = 1c1c082eeb5b8548283d50cc2ace1c35
+Payload = 61fdd10938557080191d13dd6c3002dd445d9af988029199
+CT = 23c05927502a4ee6e61e4e10552d49b020643eab476eeacc867601fe79a122a7817819655183283e
+
+Count = 161
+Adata = cae884fa25adedd883ef4e7c855def19
+Payload = 8c7ae2c3c503e9072d6e04e44c2ea78fd24994503567a136
+CT = ce476aedad7cd761d26d59297533ece2b6703002fa0bda63160bb976ab072aec8fcea8eab3dc5aff
+
+Count = 162
+Adata = a350ed58c04473e113b9088b1fb9dad9
+Payload = 863f9a26182f131c594972398b52b3a01a9d314fd9390bf4
+CT = c402120870502d7aa64a2ff4b24ff8cd7ea4951d165570a1291b2c13a3f5e49ce35b9047ee1e8627
+
+Count = 163
+Adata = cb7090f7a465782f680fd44cbc558107
+Payload = bd94c9ad6253c25dc417f87b6e52e03621ccf4b3bff5b402
+CT = ffa941830a2cfc3b3b14a5b6574fab5b45f550e17099cf57fdd9fd1d469a9042b80e6458d25292b4
+
+Count = 164
+Adata = 914cf55a3fc739b5f87ac7518cc4171b
+Payload = c313bd213dc29c00691e25ce028884192e21a820003aece4
+CT = 812e350f55bda266961d78033b95cf744a180c72cf5697b1a8b8e82175ff30c69ea71d2cfb814ada
+
+Count = 165
+Adata = adc8b69d84ef7ae62f9ca9f371d3488e
+Payload = 85e4e053b976e06a64dfa8523130cdd802d3e7c3d6d797c2
+CT = c7d9687dd109de0c9bdcf59f082d86b566ea439119bbec9776fa36db27b2f84d1b8ab55e2fc89ab8
+
+Count = 166
+Adata = 29ed477994dd231d3a71157eb56d219d
+Payload = c77aae5fd09dc9bceee7428e0734d4b0556528396a58f909
+CT = 85472671b8e2f7da11e41f433e299fdd315c8c6ba534825c0e32058ea939036805a735198934a072
+
+Count = 167
+Adata = 494c8f931029a4919e2dcbc16512a8bf
+Payload = 1f47273103f265f963e498878361c06c01a5ffcfb630a161
+CT = 5d7aaf1f6b8d5b9f9ce7c54aba7c8b01659c5b9d795cda3437098c81475f8a1d8f3b0e63d499d387
+
+Count = 168
+Adata = 53200bc5d1f1fb0eeff02d2bc42f7d54
+Payload = a38231af405dc7b70c8dbc8cb84e6be8a0dc2e95fddc2ce8
+CT = e1bfb9812822f9d1f38ee14181532085c4e58ac732b057bd9d7317973878957e8fc1fa57a025a3e9
+
+Count = 169
+Adata = 61e0e28bf344a9a1b04b15156e06498e
+Payload = a0d3a94ba6bb3bedf38220d1cba7e91273ad19f9a1c436c0
+CT = e2ee2165cec4058b0c817d1cf2baa27f1794bdab6ea84d95b0aa1befae96e71b9d221673844b1cb7
+
+[Alen = 17]
+
+Key = 116f4855121d6aa53e8b8b43a2e23d468c8568c744f49de5
+Nonce = 924322a3ef0c64412f460a91b2
+
+Count = 170
+Adata = 03c2d22a3bb08bbb96b2811ce4b1110a83
+Payload = 1bd3b5db392402790be16e8d0a715453928f17f3384c13a7
+CT = ad736402626df0f9393fe4491eb812725ad39d6facf20b5b2f9340b0d48a17ae1cc71d7515e61ee9
+
+Count = 171
+Adata = f390387610741d560325b5d2010d8cd4a0
+Payload = c93aaa04279e451b6880ed7b7fdb3ca9e80ab76180434937
+CT = 7f9a7bdd7cd7b79b5a5e67bf6b127a8820563dfd14fd51cb717bae4c040561bcfcf80fd842ae8dd8
+
+Count = 172
+Adata = 891d7988a56415a7b433f463b1e80eaa62
+Payload = 2611612ccb5ffefaa73195509bb52c641472bca0dfd09d49
+CT = 90b1b0f590160c7a95ef1f948f7c6a45dc2e363c4b6e85b5bc9fb15d874feccb6b5f581fa470734f
+
+Count = 173
+Adata = 831c0fed5e600dd82d7d55669262a9a17d
+Payload = 08136e946e306cde0544ddc2f3f4a529c89c7b77a5e635c1
+CT = beb3bf4d35799e5e379a5706e73de30800c0f1eb31582d3da72589ee50d23f925f7998ab3ccac37f
+
+Count = 174
+Adata = 32ca9d412d4ef0e89928496e96c9de7f2e
+Payload = 695aaac402942de7d899cc3f741c7fb2b2d8247a7676cf29
+CT = dffa7b1d59dddf67ea4746fb60d539937a84aee6e2c8d7d555c0b608f331dca47c65f5c879f2d532
+
+Count = 175
+Adata = 0746b2e6149c7f55854e9ca3e6861bf0e9
+Payload = 8f958d796be0566512f0512dcebd2e12f3160b05b72ae955
+CT = 39355ca030a9a4e5202edbe9da7468333b4a81992394f1a9b039bd916e923e2fc1f7c60eb59916fd
+
+Count = 176
+Adata = 0e4cbd1c574d656112bf6e70a8f23347f0
+Payload = 367ecd1b71dfb96a84e2369f28705dfaebf0c73ed35d5364
+CT = 80de1cc22a964beab63cbc5b3cb91bdb23ac4da247e34b98ac07f2c0847069fe5be26e623033f532
+
+Count = 177
+Adata = 1a05ff12412bf728497536534c234901ce
+Payload = a9ccee975feb10f635d548a8502f7c8b6adbd2be74117257
+CT = 1f6c3f4e04a2e276070bc26c44e63aaaa2875822e0af6aabf4e66a2b210e5a03bb10ff2926ed8a48
+
+Count = 178
+Adata = 3bd063a51c71fab5aeb47e7f8f958d796b
+Payload = 7df6220599d6235eb450989b6f0cd6c96db62b0d13afc4f4
+CT = cb56f3dcc29fd1de868e125f7bc590e8a5eaa1918711dc08ec90169d0c5c11fff8f255fedb13a99a
+
+Count = 179
+Adata = f0d334e0a27c3d00d56b15c2ee426e6347
+Payload = 6f65a24344c32debaf9f8c3fa426fe0b139e8ad1c8b1fbbb
+CT = d9c5739a1f8adf6b9d4106fbb0efb82adbc2004d5c0fe347170141cf3f207c4f0fc1b0238477cfad
+
+[Alen = 18]
+
+Key = e67f3ba11282d61fe36e38cab7b559c2fd9cbe8bf7eb5863
+Nonce = a727ed373886dd872859b92ccd
+
+Count = 180
+Adata = 68d199e8fced02b7aeba31aa94068a25d27a
+Payload = d7a954dae563b93385c02c82e0143b6c17ce3067d8b54120
+CT = c6cfaa1f54d041089bd81f89197e57a53b2880cefc3f9d877e30b2bcc3f1ea9ec2b8f28bf0af4ecf
+
+Count = 181
+Adata = fc4bbe329a86089ebe2a2f3320dad55a9bda
+Payload = a206a1eb70a9d24bb5e72f314e7d91de074f59055653bdd2
+CT = b3605f2ec11a2a70abff1c3ab717fd172ba9e9ac72d961753a6e6844102d6bb86986c030765d3393
+
+Count = 182
+Adata = d8741e540330692d83cc806a8ac1c4742be6
+Payload = 56ef76dbec6b8b46f5b7b4e311c0baaa6fcf54c69c0b9c3b
+CT = 4789881e5dd8737debaf87e8e8aad6634329e46fb881409c3f92a80b1d82f8c1dc32bfe64adca12a
+
+Count = 183
+Adata = c8b1992dfba55b4ab86b480546c861655e1a
+Payload = 2729636112f2abe2c76ea5e52a3f80b0f882f0f3b6f7c806
+CT = 364f9da4a34153d9d97696eed355ec79d464405a927d14a12fb48ad162b0c0678674d79d26a6b5ef
+
+Count = 184
+Adata = 347e12eec56e95aafcc7d25bf10fc756b4e4
+Payload = dd433eb7422c7c4dccee57a1679633ced3b5f08df763d457
+CT = cc25c072f39f8476d2f664aa9efc5f07ff534024d3e908f081c7cd81c974d985bf24b7fe9542141a
+
+Count = 185
+Adata = 45b35a04d6e2645e9a5aef206ed4e36199c9
+Payload = 70523bc397417e09d791a4976960e02636ca7144a5681cf7
+CT = 6134c50626f28632c989979c900a8cef1a2cc1ed81e2c050a7f6a5c04e59896074e1594706ab27e9
+
+Count = 186
+Adata = 378b48531fe34f55125b2f14f59715dd6ef0
+Payload = 514cb462dd4b117f26cac22062fcbeb353650c71649a7b3d
+CT = 402a4aa76cf8e94438d2f12b9b96d27a7f83bcd84010a79aa9d16c3ab79276cff345444511940a9d
+
+Count = 187
+Adata = 73ed686d6fecdc031cd97653137f269d6537
+Payload = 7f0c2b261db3f3de0ce3a733f4b8c446c374567d96d00379
+CT = 6e6ad5e3ac000be512fb94380dd2a88fef92e6d4b25adfdef92bf8aa6facbe6f9607ea02b54a1bf0
+
+Count = 188
+Adata = 5b0441107e5560be94f030a41cedbdb116d9
+Payload = ebb3e2ad7803508ba46e81e220b1cff33ea8381504110e9f
+CT = fad51c68c9b0a8b0ba76b2e9d9dba33a124e88bc209bd238e4936ee93b5c7a302913292df33c1700
+
+Count = 189
+Adata = feedcc5f8524fe7d49bcd178415b9f4c450a
+Payload = 3216dce3b8b1ce0e79e40fffcac728ab191aaaf319d971d3
+CT = 237022260902363567fc3cf433ad446235fc1a5a3d53ad7493426b6193afe765a76b3dec00266e69
+
+[Alen = 19]
+
+Key = e0a29a2c7840cf9b41de49780b9ee92d646a4bfc5b9da74a
+Nonce = fc9fd876b1edded09f70b18824
+
+Count = 190
+Adata = 36e15baafa0002efbb4bb26503b7e3b79f6c68
+Payload = 344dc8b6bd66a1fbbe330a95af5dd2a8783dc264d6a9267d
+CT = 43b3b96aa5a54378f3bb573ffda3e154aa7f425fc3008175b60a77b9d38740356b544b1c0f259086
+
+Count = 191
+Adata = 712b788f0276e2b5a58be80f9114a12ab2a268
+Payload = 6d0546d4e95d1cfcb37a8f88a62064f5d95791311511535b
+CT = 1afb3708f19efe7ffef2d222f4de57090b15110a00b8f4535f750bb4cd42db3038e2c1622b72cea8
+
+Count = 192
+Adata = 07f77f114d7264a122a7e9db4fc8d091334a03
+Payload = 05024ce13b9057dd2c509db7dbcbd5585e4e64a1e2e380ff
+CT = 72fc3d3d2353b55e61d8c01d8935e6a48c0ce49af74a27f761e77b59ef7eeeae35bb53bb9543b64a
+
+Count = 193
+Adata = 899b036138cee77cd28382ba27984d858a6351
+Payload = 77b8e735b13b10e45e411ab94c6fe1a9eb89f0a7af40ff1a
+CT = 004696e9a9f8f26713c947131e91d25539cb709cbae9581244a60fdb473098a11b2176d37b2c4643
+
+Count = 194
+Adata = 4b000440a8484a5201cd54aec058919769772e
+Payload = 6b21800ae599a15254bb33f0bb080788fb6e9fa054bfd8b2
+CT = 1cdff1d6fd5a43d119336e5ae9f63474292c1f9b41167fba58d4afc30a7f672ea34e05ec1843d848
+
+Count = 195
+Adata = 73a222e681ed1ca47d92a6dd90625d895fbf29
+Payload = bfa9d9af6e1f32b6626a1cd89b1c32513b5b50a18ddab028
+CT = c857a87376dcd0352fe24172c9e201ade919d09a987317204ef270e0f3b5e3ca0b8440af65c76e85
+
+Count = 196
+Adata = 7109a3a36b286059bc1a1abb2767c92f884e3f
+Payload = c68b1bc0050e19780ab53efbea175634f70a7245d966966e
+CT = b1756a1c1dcdfbfb473d6351b8e965c82548f27ecccf3166ffb66991b38a0345fbbff5f2362f87de
+
+Count = 197
+Adata = cd15973753b94b77bb4b778de8b3b0cabbde85
+Payload = 4256f1c9b64390fe2120df9fd38e497c2903c2ca5679ab75
+CT = 35a88015ae80727d6ca8823581707a80fb4142f143d00c7dd033a087c44c2e44adbeb333aa9ded10
+
+Count = 198
+Adata = 6e5e0793855f7145e13a5872f563e5ec61cfd2
+Payload = bb0036b34b0c20094d335a8c74f6b3dea42eeccf4145192e
+CT = ccfe476f53cfc28a00bb072626088022766c6cf454ecbe26ff9c8713422fe38d5bbf2dedccbffe10
+
+Count = 199
+Adata = f844684f5404e7d8eedfa20394b40b4f5d910a
+Payload = 86afa9cdd743916563ebfd3adbdd56e015ea3a4ebc61cfe2
+CT = f151d811cf8073e62e63a0908923651cc7a8ba75a9c868eae75de56eabcf8e02c1a27705adef2732
+
+[Alen = 20]
+
+Key = 26d0a3a8509d97f81379d21981fe1a02c579121ab7356ca0
+Nonce = 8015c0f07a7acd4b1cbdd21b54
+
+Count = 200
+Adata = 093ed26ada5628cfb8cfc1391526b3bcc4af97d9
+Payload = 37ab2a0b7b69942278e21032fc83eba6cdc34f5285a8b711
+CT = a3a60b422eb070b499cf6da0a404b13a05cedda549c6b93e6ca0e07e04674f21a46df2659a5905fb
+
+Count = 201
+Adata = 7df13c9d2247aa40af7bbe2da98bd366d8b47b43
+Payload = 93925579b6367ff592ecbd59495fdeccb50f31ea4fa390bc
+CT = 079f7430e3ef9b6373c1c0cb11d884507d02a31d83cd9e93836597806f5da1d176c745d95c4fa46a
+
+Count = 202
+Adata = 7f369bbc99b6f08049eeb43566269a174829d4dd
+Payload = 8363aef9c7c34e1f8149de46c97d5ac79d38c6ed31ab1d12
+CT = 176e8fb0921aaa896064a3d491fa005b5535541afdc5133df826dda99111691993027628c70ff6ae
+
+Count = 203
+Adata = 04aa8442179f62babad0c006e36af0c21105f27a
+Payload = 17281acb525b13653000ab45d86e70106c10a93c99b18f76
+CT = 83253b820782f7f3d12dd6d780e92a8ca41d3bcb55df8159d074b018143a7ea1b5369b7f80eae20d
+
+Count = 204
+Adata = 997e646014f19a53beab8877ca6022bef23016f1
+Payload = 5d48a71557608736eded309027a80349a18e9ce5dee2bc6a
+CT = c945865c02b963a00cc04d027f2f59d569830e12128cb2455db17d3f75214c3cf39858617cfee57a
+
+Count = 205
+Adata = 60ffcb23d6b88e485b920af81d1083f6291d06ac
+Payload = 6c9d11cfb64d96bfab61c04a25d9e19294fb7330fb4847c8
+CT = f8903086e39472294a4cbdd87d5ebb0e5cf6e1c7372649e79550998376e61e11a5a69e9f8fe1c329
+
+Count = 206
+Adata = d574632658bf456dfbb11c2653602ed0f4dae777
+Payload = 7d41688c86d5e3bc53966810f2299fdd732e3471fb0a88f9
+CT = e94c49c5d30c072ab2bb1582aaaec541bb23a686376486d6a1b0d05a7ebc657c3235479893bf7e5d
+
+Count = 207
+Adata = d896ed60128f4bb0277d3af94c5138cf91697aa9
+Payload = 8c7ae2c3c503e9072d6e04e44c2ea78fd24994503567a136
+CT = 1877c38a90da0d91cc43797614a9fd131a4406a7f909af1980c98c8959c158ce209aebcbd554f250
+
+Count = 208
+Adata = a350ed58c04473e113b9088b1fb9dad92807f6b6
+Payload = 49bc9d3bcf3c22daa8cf55c1b59d4bffddc2412d60518e98
+CT = ddb1bc729ae5c64c49e22853ed1a116315cfd3daac3f80b7573175f9105cd16ee384465ebb232200
+
+Count = 209
+Adata = 1db5887001204194e8b5dcee92c8af8fa5f7321f
+Payload = 25f3788e0d3dd8f5821faa4e45a9d6b3995fd881f927135c
+CT = b1fe59c758e43c636332d7dc1d2e8c2f51524a7635491d732b67e993384f2e7229d1838efd040d99
+
+[Alen = 21]
+
+Key = aac60835c309d837aacc635931af95702a4784c214283ebb
+Nonce = 0e20602d4dc38baa1ebf94ded5
+
+Count = 210
+Adata = 796e55fbe7bed46d025599c258964a99574c523f6a
+Payload = e8610756528f75607b83926597ef515f4b32a8386437e6d4
+CT = e0a3d5f43e688ce104f4ae1a4fcd85500aa6b8fdbcd1b8d3003c0c3b7369e79339433e1754c0937f
+
+Count = 211
+Adata = 5170836711fcb1a350b087907d8a17c7637aa1595b
+Payload = c61b0c1845fa9b2e0013b3fa9a8cb4f4fbbc6846f63ed180
+CT = ced9deba291d62af7f648f8542ae60fbba2878832ed88f87120a7f18d021833b167bf330c4858239
+
+Count = 212
+Adata = 2a68e3fe746f593c1b97cb637079c3e5ee352c107a
+Payload = 10c654c78a9e3c0628f004b061e28c39a3c23e7250f53615
+CT = 18048665e679c587578738cfb9c05836e2562eb788136812ca9698d9a88e892c364e57dd35c2f17a
+
+Count = 213
+Adata = bf38ca0e89b8f5ccd29387f7f193ab5a967caa715b
+Payload = fa3a959fdff853c39f76da626094a1ea6dbc78bd2f091a79
+CT = f2f8473db31faa42e001e61db8b675e52c286878f7ef447ef3839d6f7e20a2e343f4c4da9eb9be13
+
+Count = 214
+Adata = bee00f2f75a4415ce993d2d14a6d8e01d1d59a48f6
+Payload = 76d12e3c4c5d990bf563c60aa4999e52998d887f97477f6d
+CT = 7e13fc9e20ba608a8a14fa757cbb4a5dd81998ba4fa1216a6630bfb7a2a2441e020efdf36274b72f
+
+Count = 215
+Adata = d5b614e4e8f72a5d8b1ec2b375da5dac64c2cc30b1
+Payload = 693fae7af84aa397f0b2baaed9b3c7953f75e7424c49b634
+CT = 61fd7cd894ad5a168fc586d10191139a7ee1f78794afe833866bcee343ec5aae61f9effa19b99d3b
+
+Count = 216
+Adata = 33f11aa36d8ab0fc53486839a576b31ee915dbd769
+Payload = 56ce9a09f38127b14dbbdcaa59f363c92a3b9843ad20e2b7
+CT = 5e0c48ab9f66de3032cce0d581d1b7c66baf888675c6bcb00331b60eb252f744a06b4a95aa9f4e7c
+
+Count = 217
+Adata = f40bce1a6817b29b9e8b56f214fcca7dfde17e7ee6
+Payload = 5cd8986e974d09ede34ba68fd81d6109a64092e7fbbaf87d
+CT = 541a4accfbaaf06c9c3c9af0003fb506e7d48222235ca67a4153778a644cb2469cef3ad125e257bc
+
+Count = 218
+Adata = 53c457d8d4d4ab95ba116c28b82c16743cb09de9fe
+Payload = 9c3c610f204d98702dd91ea28e0cc14830b26bb5e2ee0349
+CT = 94feb3ad4caa61f152ae22dd562e154771267b703a085d4e7013e1c34dbc5efc7bcd4f8e52797644
+
+Count = 219
+Adata = c7acf1b17609dc336df1006ffac6497777cdfd497c
+Payload = 90c5dd9db0316dac89db18f70491bdf0a06a6a7f72b77d9a
+CT = 98070f3fdcd6942df6ac2488dcb369ffe1fe7abaaa51239d66aed667c761b7dea44822e30cff671f
+
+[Alen = 22]
+
+Key = 671544bf2988056f7f9ccd526861391a27233793a23f811f
+Nonce = 0a259148a1d081e0df381ecd0c
+
+Count = 220
+Adata = 61dafc237cb52f83ab773ba8a885462b6f77d4924611
+Payload = 576b069ae2713f53d2924c1fd68f786cb2eec68892f9e1be
+CT = ce06b3d09b02921f290544032a081a7766612940048867281bb089af0245792c16e6320cf5ffa19e
+
+Count = 221
+Adata = 87e49b8164e7052becfa0c966991637b38df833fc5f7
+Payload = d7eb0d7dd737805cd3b8dbf451aeea2fa1f6a96eb58cb428
+CT = 4e86b837ae442d10282fd3e8ad298834757946a623fd32be3cec29bd5df92363d6bb75456f5cd32b
+
+Count = 222
+Adata = d302a518d7c625756d3e4c8cc2b1d973a19107c945fc
+Payload = 77d8c9e6321314524afd05b7ad599c29f4eedda9e9f0763f
+CT = eeb57cac4b60b91eb16a0dab51defe32206132617f81f0a901ca82cddb78a2fe3904d1d8bf6fe5b2
+
+Count = 223
+Adata = 6566bb616a94bb03df5c26b722bcd38d516285c5f6c1
+Payload = abbf28b3ae164051648293d0b94e11f5af8468450005c7c0
+CT = 32d29df9d765ed1d9f159bcc45c973ee7b0b878d96744156d095ad121f0f76f07b715cad996def52
+
+Count = 224
+Adata = 141be3601e38185a9fa1596d2ee406415c9673af32f5
+Payload = b67d50110f844b36a00d352123012a1123c7c3cba959dc48
+CT = 2f10e55b76f7e67a5b9a3d3ddf86480af7482c033f285ade8529ec8f477462dc2409482c3479756d
+
+Count = 225
+Adata = a2969243b0955402ab45a430fef2ef9e0c025006732b
+Payload = 2a63f7b09b43fee65738e8115bd8419b3ef3e8f86eca707f
+CT = b30e42fae23053aaacafe00da75f2380ea7c0730f8bbf6e9b14fe8dbb3c361ea61d7b44e689a1c48
+
+Count = 226
+Adata = 87faef55c54250c30232ccaf5efa1ff41b6243b2a5bc
+Payload = 59dad755af92c29522da4348ab9b3037fe87004f5fa1394a
+CT = c0b7621fd6e16fd9d94d4b54571c522c2a08ef87c9d0bfdc54f0659fae291f943f2f3b33688602cb
+
+Count = 227
+Adata = 5d895fb949344e603ce5de029842b20d2bb614ecbbb8
+Payload = 64d8bd3c646f76dc6ce89defd40777fe17316729e22ba90f
+CT = fdb508761d1cdb90977f95f3288015e5c3be88e1745a2f993af4e3a7a20390a8da264299712a34e3
+
+Count = 228
+Adata = 74cc8da150b0bacdefa8943900b4ea047611d96be70a
+Payload = 0c3c9a634a000f00be003846eac7482e303a5bef3a70fe75
+CT = 95512f293373a24c4597305a16402a35e4b5b427ac0178e3a7f79d2b5a9bde5bd453bc8a03e971d8
+
+Count = 229
+Adata = 65f6adbaaa803dbad5ba9cb6d231314d55147cc61399
+Payload = 712c788928c8a1562bc1f3f0eb1286e15c3405f6a6fa0443
+CT = e841cdc351bb0c1ad056fbec1795e4fa88bbea3e308b82d5ffccebfb8c833833db40e98a1950fb70
+
+[Alen = 23]
+
+Key = 90e2c63b6e5394b1aeec03f95a9d13a01a7d4e9d58610786
+Nonce = dada5465eb9b7229807a39e557
+
+Count = 230
+Adata = f5629ca0eea589f6cf963d875a7d2efb656983f2dd2231
+Payload = 44dd098b1f869d670a8a841900c4bef023a1946a0c278354
+CT = 6b38ca85450e05e7b9362ed7e6e291a130ff233b5a561cdef7ec84dd992fdf98514f845dac8f656e
+
+Count = 231
+Adata = d43d7753530a7280b76221906dca85d396b6cf05125018
+Payload = cea19562328bd1fea889f575db6a28a14b7d06fb9f9c98bb
+CT = e144566c6803497e1b355fbb3d4c07f05823b1aac9ed07313613ed15d527d9dc58ab6893e723db58
+
+Count = 232
+Adata = 75650ce366757618af20205b69af7e5d4e82c398c00101
+Payload = f0641f595b791edd860977fcf699688587a354e053e9c7fe
+CT = df81dc5701f1865d35b5dd3210bf47d494fde3b105985874ef8728d1bf3a2d93db3266bafadb7c26
+
+Count = 233
+Adata = c00f1b8066677c63e898fddfb8a1b482b536963da0628d
+Payload = c7486a084f8475e6f5138e8d6e9f42a1de90f05aa88a362d
+CT = e8ada906150ced6646af244388b96df0cdce470bfefba9a7a5bce94d7564d297fe87730f1a36acf4
+
+Count = 234
+Adata = 5a89ab6b26b2ca78f98a8f8409fe8008b97ba9ef185d41
+Payload = 091ef698e16dc43a11d3ea005d5a5cdb7f1bdb5665a6c81e
+CT = 26fb3596bbe55cbaa26f40cebb7c738a6c456c0733d75794cd971b07fc14c512b8df6dd964b129d0
+
+Count = 235
+Adata = 5d24d80f22afe713c4076c200c1bab36917907fde7b6d3
+Payload = 62f204394b367c4410746001e02dfd171858396568fdd43b
+CT = 4d17c73711bee4c4a3c8cacf060bd2460b068e343e8c4bb1a192b781dc94448d4a0f6a439a716339
+
+Count = 236
+Adata = 4a47a82b999a2a739959f153a091a65c4d7387646da66b
+Payload = ac1cd5ba4997af91dbd74aee7730f9ee92cf8a360ca96a8a
+CT = 83f916b4131f3711686be0209116d6bf81913d675ad8f500cade9533b272e0a3edeba68362b057b4
+
+Count = 237
+Adata = d9fc295082e8f48569eb073ac1b9566246728fc62ccaab
+Payload = d0a249a97b5f1486721a50d4c4ab3f5d674a0e29925d5bf2
+CT = ff478aa721d78c06c1a6fa1a228d100c7414b978c42cc4785d68df8ff28345be4d83541a72071059
+
+Count = 238
+Adata = 720a9dc3e33ac080775a06f67f4a6591c37d0e101944a0
+Payload = 77fb98f24172f5d5edadbf466ee910855a71d46090b789ee
+CT = 581e5bfc1bfa6d555e11158888cf3fd4492f6331c6c61664caa7ec8892be6a18458c663665495035
+
+Count = 239
+Adata = 13cdaaa4f5721c6d7e709cc048063cfb8b9d92e6425903
+Payload = 77fb98f24172f5d5edadbf466ee910855a71d46090b789ee
+CT = 581e5bfc1bfa6d555e11158888cf3fd4492f6331c6c61664862fda880e45e891a3a50da7e14344c8
+
+[Alen = 24]
+
+Key = 13cdaaa4f5721c6d7e709cc048063cfb8b9d92e6425903e6
+Nonce = f97b532259babac5322e9d9a79
+
+Count = 240
+Adata = ad6622279832502839a82348486d42e9b38626e8f06317c4
+Payload = d7c837971b973f5f651102bf8d032e7dcd10e306739a0d6c
+CT = 4709600418f2839841e6d126359f6982bdb53acc7ff209635623d15b24184481eadc63bb8c878fc4
+
+Count = 241
+Adata = ad4833aa53218949cfd724814a43889a74a2114bbef4cf37
+Payload = 7d672bccd0fb01ce79320ed61779146aa432038daa13cb41
+CT = eda67c5fd39ebd095dc5dd4fafe55395d497da47a67bcf4e614c3e546273f0aeef207bd3f4d32fca
+
+Count = 242
+Adata = 54a723826086c7175e8fdc854b62d780de6ac1f90b57dd3a
+Payload = 0e1b73df74982f535a5fb08bc13d22515ee10969efe033bb
+CT = 9eda244c77fd93947ea8631279a165ae2e44d0a3e38837b413c6395ce9aee2e22ac0606beb140185
+
+Count = 243
+Adata = bec02d7df4cc3deefdd7e7d3ea82d381c870ad46bc06d64f
+Payload = 9a55aff269b180118ff0ea99e851c7474d19d23e641f16a9
+CT = 0a94f8616ad43cd6ab07390050cd80b83dbc0bf4687712a661e4f02150bedd86dfa49f52b214239d
+
+Count = 244
+Adata = 1b8090d712e0ec95a01bc3aeb6f5230c67c355e0ed68043a
+Payload = ff19294e8faed8353dbcab0b146e2ef928dd2680833424bd
+CT = 6fd87edd8ccb64f2194b7892acf269065878ff4a8f5c20b2f0e82b9f04bfc0cc0ba432b5135450c2
+
+Count = 245
+Adata = 5ed0b9f25d07b26717cdcb2507bef9d681ecd9389831ac15
+Payload = db1eba6ac4a79aa1d97838d263c7c4ffa7d354770e762805
+CT = 4bdfedf9c7c22666fd8feb4bdb5b8300d7768dbd021e2c0a2e64c82b60880c5c7506321a1060a481
+
+Count = 246
+Adata = 55f16fefaf2168aebc61b5e01d9e1f7bfe215eaaef118974
+Payload = 012d45168505ca9fde5aed123875639a207d473b993dc7b8
+CT = 91ec128586607658faad3e8b80e9246550d89ef19555c3b77152f64dc993b36ad9d5d12bb52b1ad5
+
+Count = 247
+Adata = 9893bf14fd3a86c418a35c5667e642d5998507e396596c50
+Payload = b205f26d6c8a8d6085ab28d595703cae046f96d82093082b
+CT = 22c4a5fe6fef31a7a15cfb4c2dec7b5174ca4f122cfb0c243e5c69256b6326ebb7ee6e677d396765
+
+Count = 248
+Adata = 244b840085bda9576c8424bb05a925a6b09cad2d0528ab8d
+Payload = 549ba26a299391538b56ce4bd71dbbfd96995836f8915ca5
+CT = c45af5f92af62d94afa11dd26f81fc02e63c81fcf4f958aa2083dac565c7a63908f0022e2867bb68
+
+Count = 249
+Adata = 9e8d492c304cf6ad59102bca0e0b23620338c15fc9ecd1e9
+Payload = 9e9dbd78a1066800ae33253be6104015158a0187e4f38116
+CT = 0e5ceaeba263d4c78ac4f6a25e8c07ea652fd84de89b851968242fe32958ea32e670ae1b3543974f
+
+[Alen = 25]
+
+Key = 90851933d4d3257137984cdb9cba2ca737322dac4dbd64bc
+Nonce = be02df3a840322df8d448c600c
+
+Count = 250
+Adata = 69a9dd9ac8be489c3a3f7f070bdaca10699171f66ab3da9351
+Payload = ba1785a149cb8b69a4e011c11a3ff06f6d7218f525ac81b5
+CT = 89ab2efefa8406336d9e2245199fbc9454f0ef650b9ed0f446c7246bd3130803bf8d703ef5bdf15c
+
+Count = 251
+Adata = 0c39a72f0f38d2713c164b0f870646fc65b9838a322ecfddd0
+Payload = 263dc4fb5cd8798ce0f183a816e51fafba167533dde1bf96
+CT = 15816fa4ef97f4d6298fb02c15455354839482a3f3d3eed7096a6a4422e582c5d02973952ac80e5f
+
+Count = 252
+Adata = 911d9f5c4c34c2f4b69be1e253d43fe729e2ab2622130394b1
+Payload = 7b5da2c283116713f3d80c7907114270964541e03ab80d50
+CT = 48e1099d305eea493aa63ffd04b10e8bafc7b670148a5c115965f6df4332fe7a2cdc4d1b80e28a34
+
+Count = 253
+Adata = 8a961df9c23f6d5ecdafa94c61164a22f460a1bf7415258d39
+Payload = 541a2b3ee25022c92fdc6783a6cbde90680ad3dc41868e5f
+CT = 67a68061511faf93e6a25407a56b926b5188244c6fb4df1e18bed174081b2170ffc6ab53b54c9ddb
+
+Count = 254
+Adata = cac7a248a4d4e96a9733627e247234995d6aa57e491498118a
+Payload = ebb2e893da9f32c363f98bc76fd14eda59e7cc620070f6d3
+CT = d80e43cc69d0bf99aa87b8436c71022160653bf22e42a792bac3d3a2b9ef6d4c8715f9a5c6fe8245
+
+Count = 255
+Adata = 41eacf70d05a6d0cdbdd38f197a52987def8fde37f332eebd9
+Payload = 199cca0d0e1c70ec405d6816cbddc69f8ada624f2c168891
+CT = 2a206152bd53fdb689235b92c87d8a64b35895df0224d9d07f9610c82fe9a7c78e8f1980e886b446
+
+Count = 256
+Adata = 78b6ed20ed85337c969618bd41917cd85c37e7c35c3a12e25f
+Payload = ca481f557306f9ce386edd0cfde375a550cb5b574be524f7
+CT = f9f4b40ac0497494f110ee88fe43395e6949acc765d775b6aab366637ec41d0bf557f578be424a8b
+
+Count = 257
+Adata = 87faef55c54250c30232ccaf5efa1ff41b6243b2a5bc93e7cf
+Payload = 6f1b4ff66d3aec7b0c0d9e202acc52722e15bca0983291e0
+CT = 5ca7e4a9de756121c573ada4296c1e8917974b30b600c0a1e57a5b3ae26469d229425f887ad5a2a1
+
+Count = 258
+Adata = 7f19ac3e53a629a2df1cb56d68fde0c80a46be40a996830e2a
+Payload = 7533c88ce55c2243b64b6c5bd01aed4dd6ac8bb9fd333e06
+CT = 468f63d35613af197f355fdfd3baa1b6ef2e7c29d3016f476ce4fe492062f74bff4c3c0e9ea849a4
+
+Count = 259
+Adata = 0516a69bfd8785ad001367b51e5410b75c11b761be08b9eea5
+Payload = 19ea09a9bfd10db2a74e398859d8f4831fa5749767773acf
+CT = 2a56a2f60c9e80e86e300a0c5a78b8782627830749456b8ead47ffc17b871f530f62b9f9aec98509
+
+[Alen = 26]
+
+Key = 5c5d02c93faa74a848e5046fc52f236049e28cd8096dcac6
+Nonce = 54cbf2889437673b8875a0f567
+
+Count = 260
+Adata = 09fc21ac4a1f43de29621cacf3ad84e055c6b220721af7ce33bb
+Payload = b4da43ebfe9396b68f4689fba8837c68d0064841c6ddd4a7
+CT = d40725397229021a18f3481e3a85f70445557bb2a85e4ae8101a34c777e918e16186fda05a386572
+
+Count = 261
+Adata = 10f0c45d06a138a964fb11b2d450620a2977bcd2952afe371cad
+Payload = 7b628930d44e22907277db057395601b82b65479fbd59613
+CT = 1bbfefe258f4b63ce5c21ae0e193eb7717e5678a9556085cc1e79234882846d916dabae40b1bd055
+
+Count = 262
+Adata = 64dbb170a037b36beed28a2637c87830e2b23f8eea6cd9a7331c
+Payload = 9db30b669fc5d25f05e0dc708d597da6ddce2dacc85ae99c
+CT = fd6e6db4137f46f392551d951f5ff6ca489d1e5fa6d977d3e35499e3c09dc384eb41344ee8be3769
+
+Count = 263
+Adata = c47de6608546a02c6eebd6628c9123f6936c0154d3df52a367e5
+Payload = 62036cbed3666d85624d3dc9c1f437454b9ab5c03ce0de92
+CT = 02de0a6c5fdcf929f5f8fc2c53f2bc29dec98633526340ddd605189608ce40b237dde7bed6fde487
+
+Count = 264
+Adata = bab7e36098d59d3a31d7784d549aebfc6938bbd0612c85c0edb7
+Payload = 5c9bc739f6b6fe4214f3c6aad307d1f208892d79de010e37
+CT = 3c46a1eb7a0c6aee8346074f41015a9e9dda1e8ab0829078c31f69c847440be20bd08cfef330002f
+
+Count = 265
+Adata = 8a9716135fa38c250e249f6712f7cb3ad9210d7278b53d599df9
+Payload = 0df109298083d3896214b84ff6edb11e9cfdbd88f5702839
+CT = 6d2c6ffb0c394725f5a179aa64eb3a7209ae8e7b9bf3b676ca83622b127fa50fc9637998c0ddd44d
+
+Count = 266
+Adata = 2d52447d1244d2ebc28650e7b05654bad35b3a68eedc7f851530
+Payload = 518f651f6d82f670b63767ad8476ed8fc24df12a45110611
+CT = 315203cde13862dc2182a648167066e3571ec2d92b92985e81e738b9e4b0dc7b7a39eb7d03adc64a
+
+Count = 267
+Adata = 3cba0fd2bb16ae1d997cbe659a2dd101885c97f2322b0172b5d6
+Payload = e91a694bea2d351928b6098660d49f382c087f6777de159c
+CT = 89c70f996697a1b5bf03c863f2d21454b95b4c94195d8bd3d298c05b1d2e597f44f8621ecd11ed16
+
+Count = 268
+Adata = c7f93152016bba584dadc6002ec493a46305726068886d2340da
+Payload = 2d14792ed349a878b2b879e7fa5f438a50e36947ce827e73
+CT = 4dc91ffc5ff33cd4250db8026859c8e6c5b05ab4a001e03c5fd5221fceecbf0dc7211a1aec06793a
+
+Count = 269
+Adata = 799cac048eaccded37ca6a70dd89595e1ee04606212da5572679
+Payload = 315b8d95938d304015bbc94ea03c21f6dc25c90f991ba680
+CT = 5186eb471f37a4ec820e08ab323aaa9a4976fafcf79838cf5c25f00b862b49fcfe8447949f39787c
+
+[Alen = 27]
+
+Key = 0234dae5bd7ae66c67ff0c1a3f1a191a0d7bceb451bc2b7d
+Nonce = 16d345606a315ad2406abbcb43
+
+Count = 270
+Adata = c37fdf7449fd7e943595d75e977089c623be0a3926e63fdbbfdf4a
+Payload = 0f960a89a7e806f8709047cb7a2e7c4211ad724692c88a05
+CT = 3907880d25f910eab12dd14e704d1b33ea7c453634d54da2a461f44dac1112ae3f9c65671a931d3e
+
+Count = 271
+Adata = 85f647d940a6d1acb6b7851912f807063515631eaabaa019dcfb99
+Payload = ab40a4baa39b0e568bf2193fecbc36b84c76bb50523b2912
+CT = 9dd1263e218a18444a4f8fbae6df51c9b7a78c20f426eeb5ed15db6e142ee07b59eb5b0ad3a59194
+
+Count = 272
+Adata = 79ae14843b2e7ccf0fd85218184f7844fbb35e934476841b056b3a
+Payload = b74c06d9077c568762796d5be14f3563e7205a6e9bc65bcb
+CT = 81dd845d856d4095a3c4fbdeeb2c52121cf16d1e3ddb9c6c203f11f66b74366caeca8dbded2bf17a
+
+Count = 273
+Adata = 542d86fd7ff591f97e6926a090553538bc3b8a6bcd45f2e29c7d9f
+Payload = f2179beb5635a6d8a8340acea0ffcf4428e5de1306a8c12b
+CT = c486196fd424b0ca69899c4baa9ca835d334e963a0b5068ced925fb9a4cf6b6bf17f72ab044653d1
+
+Count = 274
+Adata = 4392c3043287dd096b43b4a37ea7f5dc1d298b0623ccbf4fd650a4
+Payload = d1a9e4593bc3d02c407e84a1736e587c1819c72195a07d57
+CT = e73866ddb9d2c63e81c31224790d3f0de3c8f05133bdbaf0d1f677deca1bfda83c1b9223aaaedbfc
+
+Count = 275
+Adata = 966954582e78e99ba68d6ffaf794b55a82325834ec4f373b2bd227
+Payload = 15b94910853a8f23dfb8b31c0262b8461f777075cc0937e9
+CT = 2328cb94072b99311e0525990801df37e4a647056a14f04e12937871932a7ca3e1e27a90a7f73694
+
+Count = 276
+Adata = b7aca715dcc402565cb711b001f21e8e95ec54c4afab2e2dcc8a2f
+Payload = fd1681cc306518bf77766f55226afac3eb21e31ed897075c
+CT = cb870348b2740eadb6cbf9d028099db210f0d46e7e8ac0fba0464ff4ddeccbd523a5ed3b32337f7c
+
+Count = 277
+Adata = 290a36f7daeeeafca4431446b396dbec0bea0a1f6f081418811656
+Payload = 0804fa48fc76f98bb021e3501bef8875b64a3b508adf8594
+CT = 3e9578cc7e67ef99719c75d5118cef044d9b0c202cc242332f68ed5e44a71c5ba8bade07b7bf5495
+
+Count = 278
+Adata = f0739a855422310a21ed863376bce9d75dc7c687b9b535cb7a05cc
+Payload = 4f5c6d80a3955f12f4d2594e02a045c42fabb11d90817fff
+CT = 79cdef0421844900356fcfcb08c322b5d47a866d369cb8583b5dc1fbe32743e257b7c1c9d624adc8
+
+Count = 279
+Adata = ffac0edb0b62977bb5040e4128a48deaf711f5e6a84d8f677341f3
+Payload = 5c29c458212d010a0d9c5a547aba1138eb4ce94742fef01e
+CT = 6ab846dca33c1718cc21ccd170d97649109dde37e4e337b9e53b654de1976294897cae0476ac6248
+
+[Alen = 28]
+
+Key = 6351a67fd6daabd2fd49ee944dd41dd37301f958dd17fcc3
+Nonce = b8d517b033754058128d13d11a
+
+Count = 280
+Adata = 511c6924fa96db716f6b053b7a48aebdc1504145a56cd02d6be2590d
+Payload = 0c0663dd69ccbffbbd0c8c2e9473d0354451ae7a20fa3695
+CT = 19f2745df5007619c79c84d174e4521b942776478a0601d982c560fede4741e2fd3b54b3a48f3e38
+
+Count = 281
+Adata = d9ccd93317441e9d6ccc358f31e7e2ccef8c921b23d742993eff9d53
+Payload = 34a882834172924d39d2df5d637d9d273a99a9222971701c
+CT = 215c9503ddbe5baf4342d7a283ea1f09eaef711f838d4750ee82d927a2aa678e792acdeb615409f8
+
+Count = 282
+Adata = c268d65f7a7b30d3d198b2045fc8d1db7adda56604fa567d8855d1a5
+Payload = 5b7450b73d68de079e92bba56c7860f11126b8fdedd3334d
+CT = 4e804737a1a417e5e402b35a8cefe2dfc15060c0472f04017a48226389d24ed3ec3da2da1a9bdf7c
+
+Count = 283
+Adata = 4c2b6815156f0643b4573825e28b9f2a668a4976e3342884f48bc310
+Payload = 140c6933248f052e05bd4a36aec185ee86730108cc2989b6
+CT = 01f87eb3b843cccc7f2d42c94e5607c05605d93566d5befa16fe6bd83993ccbdd50e1ca061f4845f
+
+Count = 284
+Adata = f11c873354b3c0cff2c8f8010e9e364582b9c05c62efdefbdcc2e1c0
+Payload = 2a083de317380d94dd991349a7b8761c7c98013b1b0227e0
+CT = 3ffc2a638bf4c476a7091bb6472ff432aceed906b1fe10ac577c5893cb3896400012e48f5b190b73
+
+Count = 285
+Adata = d0a056754098d7f7ef2f639d61ea3d2b9cc936c48a1b2c5a9e96d169
+Payload = 02769283d5a06c363c2cc66c09b1ac954134e3ec7df773f2
+CT = 17828503496ca5d446bcce93e9262ebb91423bd1d70b44be80c80101fdfe6dc4cfce080bf921582e
+
+Count = 286
+Adata = 56de0e55653b9a04a3ded71c31f8807c3c8dd96bc82892e4acccef30
+Payload = 4890404bc5b24822b4cf7a2fe28abc52fbefb919ae0629ec
+CT = 5d6457cb597e81c0ce5f72d0021d3e7c2b99612404fa1ea0122dfc20e3088dcd33b6706a0c1fdfa8
+
+Count = 287
+Adata = 794a86f5b20d344ad86fd5523d08f1864737be57731440c29aa6b425
+Payload = 161f8501f59338f72026815c77cad6d8d581859192cd5644
+CT = 03eb9281695ff1155ab689a3975d54f605f75dac3831610828f0a78ce798448529afe26eec875aa6
+
+Count = 288
+Adata = b1eafc03ea2fa3e9e3842a09a225e83055de8a1f412badd6fc9ead12
+Payload = b3f38aedbf08dd7ead9d402c5aaa1ec9279c7e4bfd4a2967
+CT = a6079d6d23c4149cd70d48d3ba3d9ce7f7eaa67657b61e2ba48856a266c0d404474316f418f8f4e4
+
+Count = 289
+Adata = 8fec99f1be0e69267620c0b934bf984d60c1437f74c6ac19610fe188
+Payload = 5c09e2a6a055fe9c21e06e5519cf56b8e2e7fb44094e79f9
+CT = 49fdf5263c99377e5b7066aaf958d49632912379a3b24eb56412292d8015285efaa6f1154580eb57
+
+[Alen = 29]
+
+Key = 9a5a9560baed3b8e0e90b92655d4e5f33889e5d7253d9f6c
+Nonce = c0049382cdd8646756d4e6bff5
+
+Count = 290
+Adata = c95a86d52088a8b0107cc5b437a8938b2c9e74e46e2e03bb9bceecdbe3
+Payload = 5bbe9c1fb2563e3e82999fe097b28da4dc6ff2e020f3b4f3
+CT = 6d5401db42b5c48b79203b6ad82806d7460ac4c82ad0809b811020480e834f6fe55900a162a4e61a
+
+Count = 291
+Adata = 1dd56442fa09a42890b1b4274b950770ea8beea2e048193dfa755a5943
+Payload = 8a85a9b32a323c6af156a3fa2f1448b6387cc3660aa8a0f4
+CT = bc6f3477dad1c6df0aef0770608ec3c5a219f54e008b949cba9827513c7f1de970d316b6f81c109d
+
+Count = 292
+Adata = c834096e059ea73ddc90b0c982f9a3a31bfc6b1b81a03f9d41c9c741e7
+Payload = 1e02c13104937fe084b18eba1ea8951dcc5e75b692937dea
+CT = 28e85cf5f47085557f082a3051321e6e563b439e98b04982c9d79dd3255a8323f8229ac1c6d76ae4
+
+Count = 293
+Adata = 9249022bdead3d86ef5bd03acf053132d08663ba1f2426e19c126b22e9
+Payload = 3225570fb15ae13a13c71e364ae9a9fef03d1c9a7fa5dfa0
+CT = 04cfcacb41b91b8fe87ebabc0573228d6a582ab27586ebc8425dc81f93257ae8399fc2d48b4a7685
+
+Count = 294
+Adata = 3c3a92c4ece49fb9f84243d7c1bc91f595fce118305a758c83985c34b4
+Payload = fa0a458174537ddba25708b8d0c22d5517d57b122517b0c9
+CT = cce0d84584b0876e59eeac329f58a6268db04d3a2f3484a1b595003c58e69600c2a3b9ec45c0e15a
+
+Count = 295
+Adata = b49b845ccf76acf508f9db8543c73375d530d91f3b0e4ed70decfd2c2d
+Payload = b7fbdaeaa3ee1d0bbf5ec47898b069ec4ba6a140a3e83996
+CT = 8111472e530de7be44e760f2d72ae29fd1c39768a9cb0dfe0da009261c43c6640303696655e2981f
+
+Count = 296
+Adata = 3aabdf589eeb1709bb3d60b08bc71eaa3ffeba4e2903a5dbd8339aae85
+Payload = 9aea86b9fbd9bd4504ee2e25054942b33d3cdbd84215db7e
+CT = ac001b7d0b3a47f0ff578aaf4ad3c9c0a759edf04836ef16dfdcdbd4ad711c493d3176f032a02af0
+
+Count = 297
+Adata = 6a79879cd62bd1dbf9609897d2ebf2dc4dda43cc15fcb241aaa0deb4b3
+Payload = 3a861638ccd6591e51e2a525be59447e4a28bab32e36a5f3
+CT = 0c6c8bfc3c35a3abaa5b01aff1c3cf0dd04d8c9b2415919bfd59b45c05873c670f5f8bb47732d59f
+
+Count = 298
+Adata = c5b6ca474eb251817ae4d2f47c0632c381e222aae3b6f585a0dcae120a
+Payload = c7da4e9ba6e5758be726e6e227d7bddb0332228f7e3ecb6b
+CT = f130d35f56068f3e1c9f4268684d36a8995714a7741dff031572a24bc00b40a6b4b172b3648142e7
+
+Count = 299
+Adata = 64a96d191f1d5f95f5fed6259e33e7206adc07b0279e16cb453a9c6438
+Payload = 2b9347d3e195152dce22afdb92acd179eb484872285704c3
+CT = 1d79da171176ef98359b0b51dd365a0a712d7e5a227430ab828bc33396179ac39ce0027a1d62e0fe
+
+[Alen = 30]
+
+Key = 3e61094c80df0053e86d43fccf4e1d3ee2cdb862d3237b0a
+Nonce = 63f00b2488809fdc49ca5f05d5
+
+Count = 300
+Adata = a08763ca936abdeece06467bef8c3c47c3a473636a039d4db540c867d3e3
+Payload = 1fada8f4c7daea0d1c370184c169485b80a278708ed41451
+CT = 680dd22f16a1290bde42c9792dfa997aed24d5bd2265b6e095aa6b99d3f894d3790c2aa2dae1ba2c
+
+Count = 301
+Adata = 19508a6c83b992c660a1a28597e07c729ea2ed39401aadbf9d7586b5720d
+Payload = e9f1f2cf0b8d563e2d20f39f9f464a808b136dba364a6446
+CT = 9e518814daf69538ef553b6273d59ba1e695c0779afbc6f72d9d77109f4597e9c4c8cf7023dc5f3b
+
+Count = 302
+Adata = e5929c3b5d68a4c9fcf1168ea35bf8c0bf3043cb1ed54ff301578b3b7266
+Payload = 07a74c3b874849ecbf013713b80a84337c90b690cea0b837
+CT = 700736e056338aea7d74ffee5499551211161b5d62111a86b2544ecc3c7d5accd22ac075e7b44d5a
+
+Count = 303
+Adata = caa5cc5d0d87680eafc29429bac55c9e33167d485789c7c124b5c57a1ba8
+Payload = 4255f2cf90f0d15e9bead4be799165c57f7225980713d609
+CT = 35f58814418b1258599f1c439502b4e412f48855aba274b8f1a8a1db25de0fab7cabb11a18497584
+
+Count = 304
+Adata = f61cf7ae23a66777bd3fabc3d542feed2b00c6d4f46a772fda11b5214551
+Payload = 70b1e2e4cf260b108f5a52d0d8234838ffd6ffe7b4acd78d
+CT = 0711983f1e5dc8164d2f9a2d34b099199250522a181d753c5a9718ed0257a50e38de86154054fc3a
+
+Count = 305
+Adata = 85f647d940a6d1acb6b7851912f807063515631eaabaa019dcfb993e86f4
+Payload = af4be10b3a59ea99dadc75fbe5651f6f7630852bb556aa39
+CT = d8eb9bd0eb22299f18a9bd0609f6ce4e1bb628e619e70888550d1acca34c28ba8a3b890bb0542b23
+
+Count = 306
+Adata = 296cd04c4d9ab493def7aeb6841a45309e777028868efe45166235c56b2d
+Payload = 72d5663727592f1bfc9c65be83f4d3508126fecc4e34ae72
+CT = 05751cecf622ec1d3ee9ad436f670271eca05301e2850cc3a268dc1596a7855639c63fa76ad8479b
+
+Count = 307
+Adata = f380ca0a26a94adcf2c1ce26d226d3bf520268c72412e58a71acd9a66d00
+Payload = 3e2ccce03c10ce1527ef8e002adb265edba5779fbd4fcaf6
+CT = 498cb63bed6b0d13e59a46fdc648f77fb623da5211fe6847e3416c75fc28924a21cc123e62a7894c
+
+Count = 308
+Adata = 8825532a31680cb3b5bdb027802d2d8718755e135367e0c8c88e21288311
+Payload = a18dfe7f2d7bbaf316366f67445170afcbe18e2a1de1e947
+CT = d62d84a4fc0079f5d443a79aa8c2a18ea66723e7b1504bf6ff1a47f23d08485951aab18b393584ef
+
+Count = 309
+Adata = f768375589b687fb17c56673af4263626da69eb991007d94d4f5a163fd05
+Payload = 17ca72a440c944fefd6c08ecc3a8ecb54d96b9cad9d2aa4c
+CT = 606a087f91b287f83f19c0112f3b3d9420101407756308fd7d024456bcb69a4f77008773a3f48805
+
+[Alen = 31]
+
+Key = b5664dd6ed435df006052f6ded74bb7ce9482ca9229886f7
+Nonce = 7a1649896f3e030c18f0205599
+
+Count = 310
+Adata = c5f1a26351e53e6509c8bbbed03c42c23ad81c65fccec7ffa1cb494c7f1fc4
+Payload = 0b6de49b530703affc94010c2b793ddc6de0c44d48037ff2
+CT = 56b02fea595cc24e798691ae905be3d466ca68ca744005dba260b5ea3b047020b73b5bafa17e5084
+
+Count = 311
+Adata = 89899be18b4c389afa769b11ecd22e9fad8f38fd614ea5f8eb7a066c0ed8d8
+Payload = 2f1821aa57e5278ffd33c17d46615b77363149dbc9847041
+CT = 72c5eadb5dbee66e782151dffd43857f3d1be55cf5c70a685e4bd97b9dc83134867c00c2acea0aaf
+
+Count = 312
+Adata = d43b841f174335f1347834590b0984a2cb35f7a00a0ee993157d2d4f848748
+Payload = c7da4e95cb38342c6d5bf0c381d5a192adc3bfc1cda3a1d7
+CT = 9a0785e4c163f5cde84960613af77f9aa6e91346f1e0dbfe55202ba34bb9918fe915776de65947c0
+
+Count = 313
+Adata = c1093518efd80245e3c42371f220b21f2034e6738fe02ef43e828190f01aef
+Payload = 414a70aba5a219dbd41cdc46b84812b28cc4f7399218004d
+CT = 1c97bbdaaff9d83a510e4ce4036accba87ee5bbeae5b7a642fdf807b5a6880f2d4c36d558b40eb90
+
+Count = 314
+Adata = 90f627d5b939625bc76fe1bd4643b39edc11d3dc7f4bfe16e61bc26c3d49d8
+Payload = 58b260d3f645a35bad7a3842440bc03608248bd46e725e60
+CT = 056faba2fc1e62ba2868a8e0ff291e3e030e2753523124495a9307ca4239380a45bb7f87e41c4cf7
+
+Count = 315
+Adata = 2f360a4715074e942244ab7f9b6db127b0442df9af2efa2e78db1a94312905
+Payload = 5505caa97218957e90247fde60275bdafce4b16bcb36c263
+CT = 08d801d87843549f1536ef7cdb0585d2f7ce1decf775b84af3aeadff9dd60468aef2a8e2c56dda7d
+
+Count = 316
+Adata = 7db564811f14bc5c2098d5635655c3671fbd8288ea14944af925eaec653408
+Payload = b93e40f556a786e39126b8834a6ecacd2dc9f0f528bab135
+CT = e4e38b845cfc470214342821f14c14c526e35c7214f9cb1c8335f2e31a0468b830c5009cd02dbd5f
+
+Count = 317
+Adata = 36be91854d3d02a5d62503bb9047ef4354280510f7576c4272fd757240b621
+Payload = 543a070fdb3a855dd7d83fbc5f983671ad9e905f307148e4
+CT = 09e7cc7ed16144bc52caaf1ee4bae879a6b43cd80c3232cd5d772a599e91504e022b9dbfb124b71a
+
+Count = 318
+Adata = 6aa6ea668df60b0db85592d0a819c9df9e1099916272aafb8813ccc2f2dd96
+Payload = 86ef67572cb339c6706eb5909b96848aba5246a196972a1e
+CT = db32ac2626e8f827f57c253220b45a82b178ea26aad450379846cd12430f7adc910d1f0c51d80636
+
+Count = 319
+Adata = 3a64414c3588d7c26871d7d054ac6c8420d4917e3baad4a343685916265321
+Payload = cecef24b62676a5623bedae8087b9b05d7e22b41a14dd2d5
+CT = 9313393a683cabb7a6ac4a4ab359450ddcc887c69d0ea8fcd9ee65ac3a8fae1b00a4f1dfe2577293
+
+[Alen = 32]
+
+Key = 50925853a84a33ff392154e4e737efc18dcfc98f4d5235a9
+Nonce = 809343e986f6ff47f54d4cac22
+
+Count = 320
+Adata = d70aef3532bdc5293a3ebb11589ac1f801c9f93ea0d656e1d04068facf9f768b
+Payload = 718f061e8b972a3adcf465d66c5b28e8661f080127f6722f
+CT = bad3b0e6772e9c4c9c631c095e259d99692292932efb72b8966e91a19617bb748f3495aa433585bb
+
+Count = 321
+Adata = 1ee0eb409398bc252175cb460ef9a2da4c9beab2ef6d8206e4fcce74df785246
+Payload = 72e6cebdaf88205c4e74428664bc0d7eb4687a272217b7ca
+CT = b9ba78455331962a0ee33b5956c2b80fbb55e0b52b1ab75dc8f70aa565a12ca3545e68110968040f
+
+Count = 322
+Adata = 3820db475c7cb04a0f74d8e449f026ec951fa59667738698b0ed5c8cb09a8c96
+Payload = d959dd38a458039e2400d21d27b9a2faee8fe23683330cb5
+CT = 12056bc058e1b5e86497abc215c7178be1b278a48a3e0c22daf38076c810e14a7843444a02f010e0
+
+Count = 323
+Adata = f555216840a1f40b411d44128e567617e2694caf16216ea74c604a8d6ec01e72
+Payload = 337f12e8ebc0544b82fcdd3c4a0dab0e5e75c9f433a27d66
+CT = f823a4101779e23dc26ba4e378731e7f514853663aaf7df1594aebf9b8318877bdec2900a22df858
+
+Count = 324
+Adata = 2311a6fe1feeda3a1f16310d635496c0dd662024f0b0f1de79325e030cb850e5
+Payload = 463c65fa7becae5605af80d1feca59075ee88c0abfc72cb4
+CT = 8d60d302875518204538f90eccb4ec7651d51698b6ca2c231d9872d1c10a6594b5c349b84f710d64
+
+Count = 325
+Adata = b2c633e3181ae5fe7828707ed5b70e0460088a84465eadeecdbcfa0e9ff19bb1
+Payload = 23c1732959c4bf85bc707e45cc964b6227acd3a8fc73e675
+CT = e89dc5d1a57d09f3fce7079afee8fe132891493af57ee6e2a9db7c4bcaf6087e158c1a5d4eb1c2cc
+
+Count = 326
+Adata = 791f23252094b9b99fafe7fac1d8ff3ba09305c476041e75afb245ac438b4069
+Payload = 02f60f967e7fbcf957313619882407ea8a03fc943062296c
+CT = c9aab96e82c60a8f17a64fc6ba5ab29b853e6606396f29fb5e1c87d9e1c1f3b7d30fdc2f0ccac783
+
+Count = 327
+Adata = 22197f9ad14591e7a6d5f8b18c969a553de9a85309757fa5d319cc505c24f438
+Payload = 6c1aa088d1a6086d0e72636744a6840c80ab8223409c61b7
+CT = a74616702d1fbe1b4ee51ab876d8317d8f9618b1499161201514b449a741e07f9287f7e9090fa54b
+
+Count = 328
+Adata = 0bb18f7280a30767cd769cb5ffd3edd1c18914b92d1b2192e27ac88f57135616
+Payload = 57275bc3b4d63b9b01b0b0760235c9785d45761cace23f1e
+CT = 9c7bed3b486f8ded4127c9a9304b7c095278ec8ea5ef3f892c889b610157e16e9f31558c669298a7
+
+Count = 329
+Adata = 3e5f0f32e27be18ca6f84de11e6e9c25fc0c4cb0cf83633eea1f033aa1373f3c
+Payload = eba27a27f0d4604a5296a41b3fe995c50c66bcba302d0447
+CT = 20feccdf0c6dd63c1201ddc40d9720b4035b2628392004d0fbe19321dc22c748a17aa5eda29d8cf3
diff --git a/lib/crypto/test/crypto_SUITE_data/VADT256.rsp b/lib/crypto/test/crypto_SUITE_data/VADT256.rsp
new file mode 100644
index 0000000000..af4f5c1df7
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/VADT256.rsp
@@ -0,0 +1,1823 @@
+# CAVS 11.0
+# "CCM-VADT" information
+# AES Keylen: 256
+# Generated on Tue Mar 15 08:09:25 2011
+
+Plen = 24
+Nlen = 13
+Tlen = 16
+
+[Alen = 0]
+
+Key = 26511fb51fcfa75cb4b44da75a6e5a0eb8d9c8f3b906f886df3ba3e6da3a1389
+Nonce = 72a60f345a1978fb40f28a2fa4
+
+Count = 0
+Adata = 00
+Payload = 30d56ff2a25b83fee791110fcaea48e41db7c7f098a81000
+CT = 55f068c0bbba8b598013dd1841fd740fda2902322148ab5e935753e601b79db4ae730b6ae3500731
+
+Count = 1
+Adata = 00
+Payload = e44b4307234281209bd41f89dbe2cc3fbf68e14df2f7fce4
+CT = 816e44353aa38987fc56d39e50f5f0d478f6248f4b1747ba003abc6a4b020625adc8b6cd7bafbd42
+
+Count = 2
+Adata = 00
+Payload = 8db7a73856bcb4007346bb3e00096f69e75e97c0bb960f3b
+CT = e892a00a4f5dbca714c477298b1e538220c052020276b465e7cfa7a208a8b3e6b6377236045df17d
+
+Count = 3
+Adata = 00
+Payload = 48f3ceda4fd390a7eb38f7f5bcd14310af6b5a557e676d44
+CT = 2dd6c9e8563298008cba3be237c67ffb68f59f97c787d61a81b39a0c55822e32042b4f8981021090
+
+Count = 4
+Adata = 00
+Payload = 7cdb2c9b167b3ae811289acf7dc1814bbe241f553447699f
+CT = 19fe2ba90f9a324f76aa56d8f6d6bda079bada978da7d2c1091117e2ad77db510d902038743b5a98
+
+Count = 5
+Adata = 00
+Payload = 41eacf70d05a6d0cdbdd38f197a52987def8fde37f332eeb
+CT = 24cfc842c9bb65abbc5ff4e61cb2156c19663821c6d395b5ac7379b8e51592b98e4874f4592278a8
+
+Count = 6
+Adata = 00
+Payload = bde9e3eb9f0c57302c9185b1cb912ef76d88f2f9c3b51e9a
+CT = d8cce4d986ed5f974b1349a64086121caa16373b7a55a5c4d08c1c902c4c2f078452dd6943b85028
+
+Count = 7
+Adata = 00
+Payload = 6f9ccc033c6bfbdfad4719ad033c927e2175727a9a021dc6
+CT = 0ab9cb31258af378cac5d5ba882bae95e6ebb7b823e2a69832fefb87445f1ca42811899acc0cdf68
+
+Count = 8
+Adata = 00
+Payload = cc67bc3b7afd625b2610226d3b30e111e6aa47a3254f711a
+CT = a942bb09631c6afc4192ee7ab027ddfa213482619cafca4481d605a1019c8e9778b8928b4636053e
+
+Count = 9
+Adata = 00
+Payload = a10c81725f49ab9075fbf4d96be030a2d881d8501b115d61
+CT = c429864046a8a337127938cee0f70c491f1f1d92a2f1e63f96a82e8411e5b04426dc608298c6408d
+
+[Alen = 1]
+
+Key = a4490ed6ab51dbfccd6f3702a857575dad44da3a27eaf31178abc97da60d1e4b
+Nonce = 26ceaf6e3b28190a17c4f0c378
+
+Count = 10
+Adata = 9e
+Payload = 1b5cc6b1651dec4bbbf5130343852e971c7ff1774100d9be
+CT = 789bce069a725a96c484e64a9e54dcb7a7c268c85df47815a462ff2dd8ba44a381e1f6edab12b5a9
+
+Count = 11
+Adata = 4e
+Payload = e7ab98901c0cb1d7d76e125d8ac8e86edf6f469fa937bc10
+CT = 846c9027e363070aa81fe71457191a4e64d2df20b5c31dbb6b0789c5866b7e3312ad992e228d6d20
+
+Count = 12
+Adata = cc
+Payload = 53bc7e3648d0b389b887b065e9e8f79685beb2eb36e2eb95
+CT = 307b7681b7bf0554c7f6452c343905b63e032b542a164a3e39b1b1a480fdd268c1c75b131cde798b
+
+Count = 13
+Adata = 45
+Payload = 6d7262476da95db63b322c5193ea05030923c3cbf0f8e8b1
+CT = 0eb56af092c6eb6b4443d9184e3bf723b29e5a74ec0c491a32060fea35c3e9528fd18994fae9fce8
+
+Count = 14
+Adata = 2c
+Payload = 8246bf7b81b287411777df7ecb53a1795e54b150ff3dd584
+CT = e181b7cc7edd319c68062a3716825359e5e928efe3c9742fb4e0a604ab30a764e8c98a9cafbca8d4
+
+Count = 15
+Adata = a9
+Payload = 2596ca8772bc69b50bcbf33088c6efbab614b691ed836f92
+CT = 4651c2308dd3df6874ba067955171d9a0da92f2ef177ce397ca72f1acf6dfd078b6f4eb82fa01e9b
+
+Count = 16
+Adata = 85
+Payload = 703065d701f4fcadee20d64300b3082c0c76490eb2dc4ba7
+CT = 13f76d60fe9b4a709151230add62fa0cb7cbd0b1ae28ea0c2a85c9252ee62612dc29cffa7289b2ca
+
+Count = 17
+Adata = dc
+Payload = a1aeda4b4cb8dd2943675181561bac48ba07e8de5b327837
+CT = c269d2fcb3d76bf43c16a4c88bca5e6801ba716147c6d99c9fbdac729413152c089d3939e30b8602
+
+Count = 18
+Adata = ce
+Payload = aa17341f4cead054d41c171dd34c459f7052da225c6c365d
+CT = c9d03ca8b3856689ab6de2540e9db7bfcbef439d409897f6f86266c273f8184e901b50c04845b8ab
+
+Count = 19
+Adata = a6
+Payload = 448cdd9cbbf863eb666fda36b825f3798827da3c1349611f
+CT = 274bd52b4497d536191e2f7f65f40159339a43830fbdc0b4ddd02d5c9ae2bbac47a7a076edb1d207
+
+[Alen = 2]
+
+Key = df594db94ef8eca56a417afe946085eaed444c7cc648d07d58132e6cb5bc2bc3
+Nonce = c1ad812bf2bbb2cdaee4636ee7
+
+Count = 20
+Adata = c0c3
+Payload = f4d7978fad36223623ccb5bb18a7373cba8a6e3b1c921259
+CT = bea778540a90033b2c0d087e3cc447711ea25f7eea96855506ec97f23bd6ea97834f92f7263c3195
+
+Count = 21
+Adata = 34b9
+Payload = f6c043c70136585d012ae0df6f42b25584e374649d0116c5
+CT = bcb0ac1ca69079500eeb5d1a4b21c21820cb45216b0581c9f3230df0b52b5cb7ac907dcadcb662ca
+
+Count = 22
+Adata = d4ab
+Payload = dec0c896b04490816409da1783478ef2510231d0a28c5b39
+CT = 94b0274d17e2b18c6bc867d2a724febff52a00955488cc35a99c3165ce83102891ef3885088ed6eb
+
+Count = 23
+Adata = 2a3a
+Payload = cbfd94fc31785d30214271dab2264134805fee6e52aa0b5c
+CT = 818d7b2796de7c3d2e83cc1f964531792477df2ba4ae9c50c9d8078607994ae5dff0de6526fb53d1
+
+Count = 24
+Adata = 4eb1
+Payload = 134d2d9726400d09dd3521326f96fbef993ddc0c40887700
+CT = 593dc24c81e62c04d2f49cf74bf58ba23d15ed49b68ce00c7e84da7d2564533e7ad55390ec3a6ff9
+
+Count = 25
+Adata = 0a79
+Payload = 1ccdcf789d42caba80d7893feaf26d3853fbcaf7d964df0b
+CT = 56bd20a33ae4ebb78f1634face911d75f7d3fbb22f604807520849295a56191367a696999ffef8e9
+
+Count = 26
+Adata = 865f
+Payload = 4042dbe148db3e6dc542b25d57a5787af535d38e8c34c71b
+CT = 0a32343aef7d1f60ca830f9873c60837511de2cb7a305017bc4aceed1a10309b6402b9e9420b33a3
+
+Count = 27
+Adata = f4ae
+Payload = 85b6894fec36294aa934cdc3523fd95c90ad56cbd18545dd
+CT = cfc666944b900847a6f57006765ca9113485678e2781d2d176c180d2e299ccf0b8781ba6de8a72ce
+
+Count = 28
+Adata = 10bf
+Payload = 0f27f4fc8538a676a763b3e5db845a1bfb20d5fab340dee3
+CT = 45571b27229e877ba8a20e20ffe72a565f08e4bf454449ef98d91c68d94873a5d6557611a5402a0a
+
+Count = 29
+Adata = b92e
+Payload = 1b5ec0cb03810a12fc6a0a1ff565afb001405d2a45a1f18a
+CT = 512e2f10a4272b1ff3abb7dad106dffda5686c6fb3a566865321cedf1122354636e130acbd69718b
+
+[Alen = 3]
+
+Key = d98193ab2a465e3fcd85651aaeca18b8e91489b73b7c7e93b518c4b5b81fc6ac
+Nonce = 2247dc7e2674e9e0a63fe70613
+
+Count = 30
+Adata = 4dc2f4
+Payload = edba7d6312144e90ec9eaace7576045a46e553dcb8ee5a98
+CT = 44b9ea727c847336fd739ad11f4b906b292edb810462f06ef59626ad5cdac2e4d4cb07b538a1fd8f
+
+Count = 31
+Adata = 2f3bf0
+Payload = 52a9626f5279c11e17e96f5dc5e1c1f58c1e913020d8499b
+CT = fbaaf57e3ce9fcb806045f42afdc55c4e3d5196d9c54e36ded0d53402253453e494ad350994ca77a
+
+Count = 32
+Adata = 95d2cf
+Payload = 87b6447d97a74d0b315031078aa06fffc7b9f246bfa5f147
+CT = 2eb5d36cf93770ad20bd0118e09dfbcea8727a1b03295bb196dbc3bff865a1d94b164df23d708e8e
+
+Count = 33
+Adata = 0caba9
+Payload = 1852848046706f2e274ba381a2bee1422df4f61d93219af7
+CT = b151139128e0528836a6939ec8837573423f7e402fad3001791b4469fe50d45f8efb81217cd68580
+
+Count = 34
+Adata = f8d459
+Payload = 99aac82fa66a15e4f76b76cf4590150999d5cf8468df7f42
+CT = 30a95f3ec8fa2842e68646d02fad8138f61e47d9d453d5b4587106da25012f92f01cc2db8d11ac29
+
+Count = 35
+Adata = e883dd
+Payload = 4e2f0f91990b855a00d27fbb2e8db7184cd82909de361b52
+CT = e72c9880f79bb8fc113f4fa444b023292313a15462bab1a464148536847290e4fdda7966fe6d5e3b
+
+Count = 36
+Adata = e45da4
+Payload = e558be3fd246170b294d18ffa708842242681890baf8bed9
+CT = 4c5b292ebcd62aad38a028e0cd3510132da390cd0674142fcc4cb33472825363940e2b26424b7802
+
+Count = 37
+Adata = 3b6fc8
+Payload = f8b284c2d851289275973fcd807fac5d8e5e3b6a75ba2ace
+CT = 51b113d3b6c11534647a0fd2ea42386ce195b337c9368038a99dd8dbe89b3ecf663eda1b0f92be7f
+
+Count = 38
+Adata = 043d68
+Payload = 8edf1eb90f0ad33be8a7c6446899e06addc10b3badc4ea25
+CT = 27dc89a8619aee9df94af65b02a4745bb20a8366114840d3dc4894c8fa0a1e1aa760acf9360042f5
+
+Count = 39
+Adata = e89257
+Payload = 8fe9a6bd82462c97f436d382d1ff971c95406b1a6c847d81
+CT = 26ea31acecd61131e5dbe39dbbc2032dfa8be347d008d777cdad1590fd8bf2d7ea919e60d0316566
+
+[Alen = 4]
+
+Key = 45c8afd7373cb0f6b092af3a633d9fd97c4ca378e19d75f9b74d089429726c29
+Nonce = fdb1fa230ae0b172ff98fc7496
+
+Count = 40
+Adata = 270981af
+Payload = 0b92adbb251dc29a67f0bb97f8e7160862b6c4e843d07fd9
+CT = 274e2faea3271ea6fa0494c1951f115b5491a893056c3ee4c76fc350e585277e373e9119bf9595cb
+
+Count = 41
+Adata = 633f3efa
+Payload = 1f88dfd4f5c52c22b1db47f9f4fb6e2f8bcd78d593061369
+CT = 33545dc173fff01e2c2f68af9903697cbdea14aed5ba52540fa7e55dc54e80488a05ee7f1fc96e9d
+
+Count = 42
+Adata = aad86fb5
+Payload = b2b4cb5e90ebf4bd265093b7f5efd4d62dc60e29737aa496
+CT = 9e68494b16d12881bba4bce19817d3851be1625235c6e5ab18151c17d9e3f97244000a3b2d3c2f95
+
+Count = 43
+Adata = ed42941a
+Payload = f312b47d05f8eb5a29943b41347cb1983c75cb7a458a3868
+CT = dfce366883c23766b46014175984b6cb0a52a7010336795562d521c4b5c7a6f2c5ac65f2fd15b066
+
+Count = 44
+Adata = e5b085d8
+Payload = e9fb86938ea7f04cc230296859e7c96fcc352f968c9473e4
+CT = c5270486089d2c705fc4063e341fce3cfa1243edca2832d9e491a31218f688744098851672a09a64
+
+Count = 45
+Adata = 3776f37f
+Payload = 8af6b7540f997954812e38dbd99ccfaedd5c69963c353a4e
+CT = a62a354189a3a5681cda178db464c8fdeb7b05ed7a897b730ece28347d7ebf8291d7eb66b7651b4e
+
+Count = 46
+Adata = 4eb08c9e
+Payload = b90cfd9dd58e320d98510483b1d939bdb5f3b81666ecee59
+CT = 95d07f8853b4ee3105a52bd5dc213eee83d4d46d2050af64cbd25fb40480d15c039878b5d2f25afb
+
+Count = 47
+Adata = c7f93152
+Payload = 02caabc6ed0641681e7148c10cf3159fe35e44013252071e
+CT = 2e1629d36b3c9d5483856797610b12ccd579287a74ee4623fbfd98c8567b78d4b9c3a49a4641908e
+
+Count = 48
+Adata = 57957630
+Payload = 2f29882fdf1418d04f0b9d44272995a56973c4369c687a99
+CT = 03f50a3a592ec4ecd2ffb2124ad192f65f54a84ddad43ba4655c1abcb3ed1a175f12721a407c5d00
+
+Count = 49
+Adata = 19da955d
+Payload = 4e427130be9e94639320529ec135715e65da1117b5ba3c76
+CT = 629ef32538a4485f0ed47dc8accd760d53fd7d6cf3067d4b90621a5e5683df421a0dc52341485d1b
+
+[Alen = 5]
+
+Key = a2e6bf39efd1ceddc92b4333ed92d65efeea6c031ca345adb93a7770a8039bcd
+Nonce = 693cbb46bc8366086ec7cd7776
+
+Count = 50
+Adata = 3ba11282d6
+Payload = d822f84b023f12ea9e3ce16b904278e4aaab5e11c2c23f3f
+CT = 9f91fd2f6472e33b02b1eabb9d6655729d44c44dad6b3883fe0667bcc5806b225224b04ade8b21c1
+
+Count = 51
+Adata = 3f3a4718ea
+Payload = af87b347b59e37a424004a00907dcbcf6a554e6782a9be12
+CT = e834b623d3d3c675b88d41d09d59e6595dbad43bed00b9aea6750fffa5a487540ce65770cd836e99
+
+Count = 52
+Adata = ff79ca8965
+Payload = 82b7cd168b6a82cb2d837f41ceda0c27adc5f5b28030454b
+CT = c504c872ed27731ab10e7491c3fe21b19a2a6feeef9942f7e7cfafe32bd71ea9813607c5df446c9d
+
+Count = 53
+Adata = 0021be18ed
+Payload = 1c1a0f144df76781e7c85ab178ed9b1ce8c6dc3f15c59149
+CT = 5ba90a702bba96507b45516175c9b68adf2946637a6c96f576716fe674c33ad3b9d3e54cc86bfccf
+
+Count = 54
+Adata = 9ae7996547
+Payload = d9bb71ad90152d5c1af358c8501fa89ebd4b17bf4ff43841
+CT = 9e0874c9f658dc8d867e53185d3b85088aa48de3205d3ffdab55dbee34f1bab555bbb196095fb5fd
+
+Count = 55
+Adata = fa292d1958
+Payload = fc7d028a1aa05c74b7ffe333ba6f676913b0f9f1ffa050b8
+CT = bbce07ee7cedada52b72e8e3b74b4aff245f63ad9009570476a4e9e759d5bb79c187a157099e3d12
+
+Count = 56
+Adata = 88800df7b6
+Payload = c9ea772e61742a6706da3ab3e81df14b31506ae58b063ece
+CT = 8e59724a0739dbb69a573163e539dcdd06bff0b9e4af39729f0f3699c9743ad6c9f09dc00ea10487
+
+Count = 57
+Adata = 715041afd4
+Payload = 70d2b8d64121ceccf1961444e8d33b7b7f998aeb58d3d270
+CT = 3761bdb2276c3f1d6d1b1f94e5f716ed487610b7377ad5cc560d78cba6d9f50e9c2677a710f92155
+
+Count = 58
+Adata = 14682301a9
+Payload = 1013946815001a2c08acca4196e0d6668ffbb3883cf111e7
+CT = 57a0910c734debfd9421c1919bc4fbf0b81429d45358165b95ffb6e29172a283d47e4478e2e1f7c4
+
+Count = 59
+Adata = e44c3c21c1
+Payload = f40dc834067bd163e0004d0ec5dd4b96e2a1ea31ea431c98
+CT = b3becd50603620b27c8d46dec8f96600d54e706d85ea1b24ccf233caf0bad9f68f71d78ee58512ec
+
+[Alen = 6]
+
+Key = c5a850167a5bfdf56636ce9e56e2952855504e35cc4f5d24ee5e168853be82d8
+Nonce = c45b165477e8bfa9ca3a1cd3ca
+
+Count = 60
+Adata = 4759557e9bab
+Payload = e758796d7db73bccb1697c42df691ac57974b40ca9186a43
+CT = 93ad58bd5f4f77ac4f92b0ae16c62489e4074c7f152e2ed8a88179e0d32f4928eff13b4ce2873338
+
+Count = 61
+Adata = 2ea07d393a0a
+Payload = ce60ddbe40b70bd55a9147036ad079dec1558ef4c2c625b3
+CT = ba95fc6e624f47b5a46a8befa37f47925c2676877ef06128b7d812c4d69f1f53ee9158382e56625b
+
+Count = 62
+Adata = aa6667faedc1
+Payload = 89eb3056770a6157f06921bc153834447c4b6d862d10d185
+CT = fd1e118655f22d370e92ed50dc970a08e13895f59126951e26fdbed62b228db008a1b14bd7942e12
+
+Count = 63
+Adata = 9e2127d92311
+Payload = 132f3e19e12f462a7463226b716c41a05a59c76f0e1a2f72
+CT = 67da1fc9c3d70a4a8a98ee87b8c37fecc72a3f1cb22c6be9124e1eb78de01b8af83b684baf3e43ad
+
+Count = 64
+Adata = 2f191bc9cff6
+Payload = b8611cbb9a3667b9458ca57eb636eb1dc580e7dbb5701692
+CT = cc943d6bb8ce2bd9bb7769927f99d55158f31fa809465209cb0f79736d1a810d06a776094f9fb67f
+
+Count = 65
+Adata = ad739d5f4736
+Payload = 112f89ccbdadc2433008d3ede2290f9ce81e5c736abf42a8
+CT = 65daa81c9f558e23cef31f012b8631d0756da400d6890633bfba2348f629471c232c9ff7e5f6f85a
+
+Count = 66
+Adata = 01acc909b7d3
+Payload = d47f2ff745de39a9055ad002de6334971fde480bef268b33
+CT = a08a0e27672675c9fba11cee17cc0adb82adb0785310cfa8c0f694d03ffed043787343827ea2603f
+
+Count = 67
+Adata = ce003c836a6f
+Payload = 13be365884b8a91a284ca24f70011e48794b51be275153b9
+CT = 674b1788a640e57ad6b76ea3b9ae2004e438a9cd9b671722279b553998a6fee0a86e177a448573a4
+
+Count = 68
+Adata = 6a759a4efd00
+Payload = d5c87c649579da3f632ba95cb0a07c924095e4bdd4e0376e
+CT = a13d5db4b781965f9dd065b0790f42dedde61cce68d673f54eeb434cca3ea719827417e94d6ed564
+
+Count = 69
+Adata = 02b84a26c773
+Payload = b7bc1580c68fd5d06c1bf75c31dad7a3e26d636d7eee20b9
+CT = c3493450e47799b092e03bb0f875e9ef7f1e9b1ec2d86422a74b5e4e2edb91fbbe722bfaf1500db4
+
+[Alen = 7]
+
+Key = ae8f93c3efe38e2af07e256961dd33028faa0716e5320a7ab319a10d2f4c5548
+Nonce = 6333bde218b784ccd8370492f7
+
+Count = 70
+Adata = 0b1fabdf2a4107
+Payload = bc9ca92a9c9919e39095d3e53fb148694620ae61227e0069
+CT = 45811b0c8f754bf03950e520cd4afc81c2e3eb8a11f4fd386d5a6e4b1fbee15d35939c721004502e
+
+Count = 71
+Adata = 2fc7f5c0ce052f
+Payload = f25a4ca20bbf4969bed6b93c1c77e3d7415f60fe3784216b
+CT = 0b47fe8418531b7a17138ff9ee8c573fc59c2515040edc3a24a68f98716190fb55f743a8bf62a085
+
+Count = 72
+Adata = 8a74412da3034b
+Payload = 3237bf953989d17c65a0fafd2bb1e32c237f98f55389e8f8
+CT = cb2a0db32a65836fcc65cc38d94a57c4a7bcdd1e600315a923afef7b4955d7d1e8f1abef9933bf9f
+
+Count = 73
+Adata = 7139f3c1d6cc36
+Payload = 55d86dc0423cfc2616ef996a3316e776707f8d25c985884a
+CT = acc5dfe651d0ae35bf2aafafc1ed539ef4bcc8cefa0f751b8e824c62632dff5cbc103d3060fbd174
+
+Count = 74
+Adata = af7a380f079aa1
+Payload = ac48398adb10292314973946f261ec39397442ca09b98dd8
+CT = 55558bacc8fc7b30bd520f83009a58d1bdb707213a33708980202d518ca871c9544f4a8c55fd8d20
+
+Count = 75
+Adata = e602abe8f72964
+Payload = 2fb78654e4395df8c37f260d74def234a3a4e3d2b1fe8614
+CT = d6aa3472f7d50feb6aba10c8862546dc2767a63982747b454b33ea6e4344033f74f513d1e41b82ae
+
+Count = 76
+Adata = 82741c5fd6e1df
+Payload = d488bdda400932de56a9f105f0e74ee79c2ed869faaadc31
+CT = 2d950ffc53e560cdff6cc7c0021cfa0f18ed9d82c920216073ccf18c7ea7dce79d0be1204c593234
+
+Count = 77
+Adata = 78f0cc22535402
+Payload = b22aba8d3e9f4b4bf006e26062de15daf94597731a600912
+CT = 4b3708ab2d73195859c3d4a59025a1327d86d29829eaf443b81b8af57b85093778690266e20e2fbb
+
+Count = 78
+Adata = 18e468139dd16f
+Payload = bd864f7b8efd6ed2b068f425482d449bf53a203ea88e1ca1
+CT = 449bfd5d9d113cc119adc2e0bad6f07371f965d59b04e1f09b94a857e7a0423ef6c9cbebde1f9c40
+
+Count = 79
+Adata = a6dab47c0fbfe1
+Payload = 47d9d18b6addc5f88986f0457b666faae59aba4fa3a02abb
+CT = bec463ad793197eb2043c680899ddb426159ffa4902ad7ea64718820065a739fbd3ba560a416895c
+
+[Alen = 8]
+
+Key = 548c2d1eb7d91e003633d4d9ff199e4a8447180edd89ac7867d25a1db288b5ce
+Nonce = 23b205bd6ff8ed0bab0c98999c
+
+Count = 80
+Adata = a6601111cd92c943
+Payload = 49fd5cbe4aff89dc3b8718f9ce545d612cbbebb289ecbf42
+CT = 3cfc6211e359ae322802fc9566f377b0dfe17d1dfe0878ebf2a9047e37cc0be1fab0006af8db8dc4
+
+Count = 81
+Adata = 96f0b7cd7439721d
+Payload = 94a95e945f660d1571b4d7d22709b000b45ff98b2129a4ae
+CT = e1a8603bf6c02afb623133be8fae9ad147056f2456cd6307106a430b04938e97f2e4cda81108ad3e
+
+Count = 82
+Adata = 2ee135dc2ddd9501
+Payload = aeed3aea01755c912213c8c276a2b75dad24f888a611efa3
+CT = dbec0445a8d37b7f31962caede059d8c5e7e6e27d1f5280ab2ab219c6c4952d52505cd9f904b0e04
+
+Count = 83
+Adata = 10c361934fd6ff77
+Payload = be1fcebea4c22a1d71e08047b028d7f4ccab0a6b8085d344
+CT = cb1ef0110d640df36265642b188ffd253ff19cc4f76114edfc1f7b2fe314faea28ab0dae349feb9c
+
+Count = 84
+Adata = 3f6c8a69917f7776
+Payload = 87680ac26fe1511e0f1f745aa4c2a5b9f6c0117dcf08feaa
+CT = f269346dc64776f01c9a90360c658f68059a87d2b8ec390308e529d64e786a29661cccddc0366f3b
+
+Count = 85
+Adata = 0f7a1426ff3b5ee1
+Payload = 9e004b072a27b085e59ca201c157c7d3c906a2c3b455c56e
+CT = eb0175a88381976bf619466d69f0ed023a5c346cc3b102c797c6510b85dfd097f3eac276aff00ba2
+
+Count = 86
+Adata = faa5bed84dcf168e
+Payload = a1bf47b15cd66e43daff420edf014a14b11994b97ada4030
+CT = d4be791ef57049adc97aa66277a660c5424302160d3e87998e522b6f13f99ecb553b6de845940907
+
+Count = 87
+Adata = 2851dae3cb3fcb1c
+Payload = 2d15734871adc63ff32d7002ab40c4a235a4d5fad223953f
+CT = 58144de7d80be1d1e0a8946e03e7ee73c6fe4355a5c752967a9ca39566189ee96c86462bfea78af5
+
+Count = 88
+Adata = 35a29c1bcbe2182f
+Payload = 5a84c4fdd47510fb7aebc0f79d7b625ccd0a96575740b8e6
+CT = 2f85fa527dd33715696e249b35dc488d3e5000f820a47f4fa613b5fbbe73a2df6c630a00ff4b1b92
+
+Count = 89
+Adata = 45820ae66c3e8e77
+Payload = 2052a94e1392dc1db0e89be19ea8f7379ee4cb607a914c89
+CT = 555397e1ba34fbf3a36d7f8d360fdde66dbe5dcf0d758b20d19feb067e9f6225376da21b4899d296
+
+[Alen = 9]
+
+Key = aab793e377a12484dbdd74c9b3a85c74c286e1cc498663fbd7c718b5633bb91a
+Nonce = 10022cddb323e88b3c08f95a0f
+
+Count = 90
+Adata = 82b8c736037ce2f2e8
+Payload = 7c0889854658d3408c5d8043aad2f4ae4a89449a36f8a3b8
+CT = 1044250f58857c69f72b5d3454d43949e5c02b3822970b280de1a3f7fc5d06cc30f06075f5504ed7
+
+Count = 91
+Adata = 8f2777ec4930f7e349
+Payload = bd845561f099500a6ff3fd09964dc3820f7ab48ba4ed04d5
+CT = d1c8f9ebee44ff231485207e684b0e65a033db29b082ac45835840df6fa96f5c972ac09d94148cbc
+
+Count = 92
+Adata = 5cab3b846870709569
+Payload = a6e09404fe60badfc63dc228057485e6f563ba82acdabd7c
+CT = caac388ee0bd15f6bd4b1f5ffb7248015a2ad520b8b515ec2f83ef84b299cfdb61d2b5039d536c3f
+
+Count = 93
+Adata = 0938f2e2ebb64f8af8
+Payload = 33404d7e0e620c1030b91020e33619c5f53d8b210fa86489
+CT = 5f0ce1f410bfa3394bcfcd571d30d4225a74e4831bc7cc19db04e655cbe22b9ea508d2a03757b97c
+
+Count = 94
+Adata = 82f78ca0e0da2b2d3a
+Payload = 617868ae91f705c6b583b5fd7e1e4086a1bb9f087a50bf50
+CT = 0d34c4248f2aaaefcef5688a80188d610ef2f0aa6e3f17c04bd88dc6985f819004c2b634c5303ed8
+
+Count = 95
+Adata = 401191aa3fd34abe87
+Payload = 949cdd7c2973d7519e7bca98b2c5947e6d8e91c90e632319
+CT = f8d071f637ae7878e50d17ef4cc35999c2c7fe6b1a0c8b894ff3572e4ebf78473760d8cb4b0366b4
+
+Count = 96
+Adata = 4df4377596d8987671
+Payload = f6720a0bd8705c70e0f923338965e810b3ea939bad652327
+CT = 9a3ea681c6adf3599b8ffe44776325f71ca3fc39b90a8bb7de95ec3eee17753e60fb3c0661bdd098
+
+Count = 97
+Adata = 6593194b9970545c5a
+Payload = de9b0556661e726f3e6e34515ff7196420fe61b4f38419f2
+CT = b2d7a9dc78c3dd464518e926a1f1d4838fb70e16e7ebb162b8590ff04f967e51fbd1be84f01b4dcb
+
+Count = 98
+Adata = ab2d432058b540ac72
+Payload = 6cad7f3b9f196839bbc5a7f755c09aa8e17c83d9cb8b3954
+CT = 00e1d3b181c4c710c0b37a80abc6574f4e35ec7bdfe491c471d67b75b2da855a12ffb24ddd64a048
+
+Count = 99
+Adata = 5dc631eeeacb5a0b0b
+Payload = 70a55aec1144357377612fd0bbc2c817f33465a656219957
+CT = 1ce9f6660f999a5a0c17f2a745c405f05c7d0a04424e31c71fc798dd16c1fadef607a9297cbfbfef
+
+[Alen = 10]
+
+Key = 06ac39896073a44283611a66ccab067e2dd2faa8da82ff9a45bb29e54d2e6e77
+Nonce = 6c7942c9819cf69b817bfcdb0a
+
+Count = 100
+Adata = 215e2a6c24325340fdec
+Payload = 3216dce3b8b1ce0e79e40fffcac728ab191aaaf319d971d3
+CT = c5b3b50ed8a7b7b96b02ba9464b6a2ff80e90548605699a63d70e6dffb31a376a1eb7f94526dca48
+
+Count = 101
+Adata = e0a29a2c7840cf9b41de
+Payload = 7e5e5710a693ebfa36335cf7965574740880acdddd13fb1a
+CT = 89fb3efdc685924d24d5e99c3824fe2091730366a49c136fcbf516608fe20e06bbff931e84683545
+
+Count = 102
+Adata = b8026fbada6339d84802
+Payload = 08c342a50aa23362622934dfab55d9b22c22c249ad08138c
+CT = ff662b486ab44ad570cf81b4052453e6b5d16df2d487fbf9d70eb14f3fa0229906b9e0360be3d3f9
+
+Count = 103
+Adata = 65f4b3a00c1c1ef39445
+Payload = e085aba85882c75d5e41559167731496cf17d3907894352a
+CT = 1720c2453894beea4ca7e0fac9029ec256e47c2b011bdd5f4184771199a427861bf17cd8401e794e
+
+Count = 104
+Adata = 96118dbfe53434d8aed8
+Payload = 710f890be2b8da77c1eff429ede9cc931d50f059748cbcb6
+CT = 86aae0e682aea3c0d3094142439846c784a35fe20d0354c34e20b2db52fde68f88bfb886fdcb2c47
+
+Count = 105
+Adata = cdf4b485d2e04709cf8f
+Payload = cda96efee4e188ab3048bc1904ac2c36ab018f2ab7602682
+CT = 3a0c071384f7f11c22ae0972aadda66232f22091ceefcef782ee3df38ddea8e269eb47e39900345e
+
+Count = 106
+Adata = 50e57e57cf8e49e3a4e6
+Payload = 3dc596d52e520779a50bcba3049388b340dbf6d0f2eb94cf
+CT = ca60ff384e447eceb7ed7ec8aae202e7d928596b8b647cba44aaac4ed86f687cfc031f22827725f1
+
+Count = 107
+Adata = 48c670f11ff7f74e7003
+Payload = a33105c0dccf8e3b687212a870af9f710462756705fe09b3
+CT = 54946c2dbcd9f78c7a94a7c3dede15259d91dadc7c71e1c6d75255006ac037d6a4d048f1fc338012
+
+Count = 108
+Adata = 465e3be6113a2fb2ee20
+Payload = 573ac2436158eb7dd9be981e3cfbe75d3a188ea9cf2b1ee2
+CT = a09fabae014e92cacb582d75928a6d09a3eb2112b6a4f6976c1da33a80bc8157cece1acf9400b2bb
+
+Count = 109
+Adata = ee4e10574faeae85e9b6
+Payload = ca35bdb54e73eac5a5200a296b3aba5f37c87349746102d4
+CT = 3d90d4582e659372b7c6bf42c54b300bae3bdcf20deeeaa165c1cb98da4a1a920ca1ed9a7b6ec514
+
+[Alen = 11]
+
+Key = 50412c6444bcf9829506ab019e98234af1541061557412740bc120b456052763
+Nonce = 85684f94c3702c5d870310166d
+
+Count = 110
+Adata = f706a3e09df95d3e21d2e0
+Payload = 6cdbd63f6d591f59776f828533b28e2453a214d1d0dd8a39
+CT = 8c8b4ae854a5d5c265b25e3b54bded9444cc454b3e0e6a24d6c05eaf406a5ebd578e19edd5227380
+
+Count = 111
+Adata = e46b25b9a41a858e87900a
+Payload = 100132c315bfc9c4fb93023f5d3500d7208a68acb4d2c630
+CT = f051ae142c43035fe94ede813a3a636737e439365a01262d5088446e42591c0ede68e82334d97cfa
+
+Count = 112
+Adata = 28d34b29afe6586fd9bf0e
+Payload = d5460c1db0d24dedc63c4c78ce6d1f0b2d46f3b01934525c
+CT = 351690ca892e8776d4e190c6a9627cbb3a28a22af7e7b2413eaaef2823f5ac3f313f560bd774d10e
+
+Count = 113
+Adata = 2852d4fd68a3e9e47d44a7
+Payload = d2d73b62e3b1c9ab75f3544ff8616741e0adbae84b8cf9d0
+CT = 3287a7b5da4d0330672e88f19f6e04f1f7c3eb72a55f19cd62d30d99bb7dadec34e2891c156a1f5d
+
+Count = 114
+Adata = ec1c17b2ab13d7c8ac874f
+Payload = 74796d78d6ad03634ed80800af530212baa7e5093651cedf
+CT = 9429f1afef51c9f85c05d4bec85c61a2adc9b493d8822ec241c9a05ebf9ed27792bbced83b5dc582
+
+Count = 115
+Adata = 4f1ab5ddb1c199e9a5daab
+Payload = fb432488b5d08d576a90f085181ad883407a6ce9ea29950a
+CT = 1b13b85f8c2c47cc784d2c3b7f15bb3357143d7304fa75171ffc24020e86b1314724104e6b57b3ce
+
+Count = 116
+Adata = 864e0e728aea856fae6c6d
+Payload = 2b82d96ed1778412378abe4e09c633acf3359b9709ae3dcb
+CT = cbd245b9e88b4e89255762f06ec9501ce45bca0de77dddd6539bbb0af8ecf77b4508533247b3501a
+
+Count = 117
+Adata = 21ee21a5ed0d75d0380a28
+Payload = 85143071241bb65261fe7afcc102416e59b9e46ee0c90073
+CT = 6544aca61de77cc97323a642a60d22de4ed7b5f40e1ae06ef8981ec6ce7c4687b178f2103fa8c8be
+
+Count = 118
+Adata = 2b63f7b676f13f45d103dd
+Payload = 185577b48237acbdaa3590b8057fe374f875ce829b62c98f
+CT = f805eb63bbcb6626b8e84c06627080c4ef1b9f1875b1299265d9d899c6b71c0ab3049ea1dbfaf6a9
+
+Count = 119
+Adata = a33e86d813c2c4ff3bab20
+Payload = f051beb936e60fd4f3bca31964f1ad3e6fa16dd27b65a6db
+CT = 1001226e0f1ac54fe1617fa703fece8e78cf3c4895b646c6b246474c4e79822f5fd55f2fb0067a40
+
+[Alen = 12]
+
+Key = 8a56588fe5e125237b6cdc30f940b8d88b2863ec501a0cb00b1abade1b5ce0ed
+Nonce = d80210b9f9776ea36dc0e0a787
+
+Count = 120
+Adata = e4296d1c8cf4ffc4b2635135
+Payload = c825952293e434ea866db558aaf486ef09a92bf366988f71
+CT = b8b3b15fdf6a4a0b5abc313afc769e4e8413bd887552583ede3ed995d1b70561c8e28a7b1a7e3dc8
+
+Count = 121
+Adata = d18bfcc1584eeb8695388ebe
+Payload = a1e0248355bfd1d881fb1a4798cda2f6f6ad513c69c5f9b4
+CT = d17600fe1931af395d2a9e25ce4fba577b17c7477a0f2efb561575f6743c5759494be59afa0c3e11
+
+Count = 122
+Adata = 14682301a99bf680805d1ffe
+Payload = ded135fcbf62219bfba2cba40c2d2cbe4815ddaac1342231
+CT = ae471181f3ec5f7a27734fc65aaf341fc5af4bd1d2fef57e34f689367228cbaf3cd76fb407109cf6
+
+Count = 123
+Adata = 8853aa2dfea9c4d370678bb6
+Payload = 12d3900c6c01968b8344762e0e883e5e219f42b052dc6215
+CT = 6245b471208fe86a5f95f24c580a26ffac25d4cb4116b55a2cacb7fc3856abcf759feb8dc0998ab1
+
+Count = 124
+Adata = c5d3b9c593c3185fe4b6d1bc
+Payload = 8c3c1193fe1a1ebad7e01a1eed1a32c08a0091b1c948e184
+CT = fcaa35eeb294605b0b319e7cbb982a6107ba07cada8236cb42a740cd3262424a2c3d77849ead6149
+
+Count = 125
+Adata = dfb9e8149b51f89b1ec00a8e
+Payload = 8219618b7728ac89237705ecf84012cc7c80293c4cf171d8
+CT = f28f45f63ba6d268ffa6818eaec20a6df13abf475f3ba69747d4dbe0f9415d40843070e1e93059eb
+
+Count = 126
+Adata = 08a4590d262e4dbcb7e23ffc
+Payload = b344b7dc239617fa51b9ea10a349e940c3163779f5284c9c
+CT = c3d293a16f18691b8d686e72f5cbf1e14eaca102e6e29bd31215b3dccba4ca5de64be7fab8a7a22c
+
+Count = 127
+Adata = 74aab7b5b96238710637c6e5
+Payload = 740d4b25ca7221d0826057701a6bfd66c50a82f010a57be8
+CT = 049b6f5886fc5f315eb1d3124ce9e5c748b0148b036faca734e09945ee44c95c7923d8b9249ade7b
+
+Count = 128
+Adata = 420aac47a3f212fffca40549
+Payload = 5d9000489186abdf4f0a2794f0222fcaa156fe6309c10f79
+CT = 2d062435dd08d53e93dba3f6a6a0376b2cec68181a0bd8360a568dd779526a0058d522af1dafde30
+
+Count = 129
+Adata = 6e80dd7f1badf3a1c9ab25c7
+Payload = ac2c44263363810bec3a309aa618b303e05099dfdbeb5c16
+CT = dcba605b7fedffea30ebb4f8f09aaba26dea0fa4c8218b59279442c88d612ed1a39ae0005f88155d
+
+[Alen = 13]
+
+Key = a4cc7e1c90f8684e6a5f95e6898ab4e3c194cb46e196d8228062b9f3fa744930
+Nonce = cdc2712e51c7f333d6bad78eee
+
+Count = 130
+Adata = 569c56b27268d3db54e728aac0
+Payload = 10d4cff95ef490923c9e0906880729d4d05412e7675cce76
+CT = be3ce3e9dc72499839a98ae52abb17415e8547687e8a3c7b8aaaac20d4c9276f2851cbba2b04d185
+
+Count = 131
+Adata = d75635b6450e43285fba966835
+Payload = c9db03e2efbab713b0b640421018d3971ffe2abd70fe8fa1
+CT = 67332ff26d3c6e19b581c3a1b2a4ed02912f7f3269287dacc121ff83891335dd1214ea6fc25f6a68
+
+Count = 132
+Adata = 70750acea6a05f8b7b425d262b
+Payload = add631ce5846ce71434aad4998f8e429aed430e7d38bdbb2
+CT = 033e1ddedac0177b467d2eaa3a44dabc20056568ca5d29bf549e71ec517cd65150f42b3cb53f936e
+
+Count = 133
+Adata = 2a567c7ec7edaa5a438ae3bb35
+Payload = a514d170422feb1d87bb7725a9e77cc6fc8afb45c2af6d90
+CT = 0bfcfd60c0a93217828cf4c60b5b4253725baecadb799f9d0e432ec394ddbb65205dc40a5a8e90a4
+
+Count = 134
+Adata = 0f8795385b805246a0a2573afc
+Payload = 79d8841ab83279724ce35e1a8abd4e158168dcf388ab4c3d
+CT = d730a80a3ab4a07849d4ddf9280170800fb9897c917dbe30926b0d977107a3918717f79b63f36b0a
+
+Count = 135
+Adata = 111d224c102b136159fbeb44a7
+Payload = 2edd498e54b23aab6f4fd7b3f22c4c787e3a4f1fb06c9ec7
+CT = 8035659ed634e3a16a785450509072edf0eb1a90a9ba6ccac2cd61599bb93db3dd3dabc12aa90932
+
+Count = 136
+Adata = df0821c9ea6ab329c626d11b4b
+Payload = 6e3e25db29da2c787bb37755ee770e2402fb8208da23389d
+CT = c0d609cbab5cf5727e84f4b64ccb30b18c2ad787c3f5ca90bd027ecd00cc6dc5ffd5d746d92281e9
+
+Count = 137
+Adata = aacaf4839c35338d6e2b47ac45
+Payload = d4ed4584678e982ace8664e77d0e55be356be558cead3755
+CT = 7a056994e5084120cbb1e704dfb26b2bbbbab0d7d77bc5583c01354a450eda2588be7578530e38c0
+
+Count = 138
+Adata = dc6eed3f8bd1b5563c1eeb9afa
+Payload = 4ebf00eadaf70711f630f5badf0214d8518a200afb0e5765
+CT = e0572cfa5871de1bf30776597dbe2a4ddf5b7585e2d8a5688d7a1d546e25ba026cd46556eb2c4b7e
+
+Count = 139
+Adata = fbfe7e910f242a78dd6e69a2ec
+Payload = 2729636112f2abe2c76ea5e52a3f80b0f882f0f3b6f7c806
+CT = 89c14f71907472e8c25926068883be257653a57caf213a0b0e951aee790239e7067ef37f497b4bf4
+
+[Alen = 14]
+
+Key = 347e12eec56e95aafcc7d25bf10fc756b4e42bc2e43da7f97df24331f27f1f5c
+Nonce = b8d517b033754058128d13d11a
+
+Count = 140
+Adata = 511c6924fa96db716f6b053b7a48
+Payload = ca88dddfc876a12f45f19562bc9ca250f43267ab251a7f34
+CT = eeedcfa8f5b5b48c1d7e277526eecb7294213b9f5785167ae949b93003dfe63c95c1d49edfb4de3f
+
+Count = 141
+Adata = 10c26d5939618189a9503623f55f
+Payload = de0c0d17c3950e7f8985b56d60623cbd010cd765da4df5ab
+CT = fa691f60fe561bdcd10a077afa10559f611f8b51a8d29ce585c32a90d77fed97eb0ac164ed616e1c
+
+Count = 142
+Adata = bc09c59d20e55a9e184d70af2c7c
+Payload = 2f35102d78a32fcde1cfb563ea8d310ecb83c146ab8de362
+CT = 0b50025a45603a6eb940077470ff582cab909d72d9128a2c180fdf5f63045f326057cf74fd4cee6b
+
+Count = 143
+Adata = b75887f13d6e8c4b35b27b965693
+Payload = a3fcce3420effdd6edb37271735a0d30c10c65233aee173f
+CT = 8799dc431d2ce875b53cc066e9286412a11f391748717e7134959a180fc2cf2ba99af21cc1bc8e5c
+
+Count = 144
+Adata = 603401a9b8ecde4d5c86b6107363
+Payload = 4ac918727e41b8c536484e3781c403e260c278712853508d
+CT = 6eac0a054382ad666ec7fc201bb66ac000d124455acc39c32ca2e5195dbd44f0a119538c95788510
+
+Count = 145
+Adata = 7206b06f306124ca3a302e84c5a6
+Payload = 97d770cbb2c42a552e450cc4e35e5668b2ff89cec735cc91
+CT = b3b262bc8f073ff676cabed3792c3f4ad2ecd5fab5aaa5df74a4e1198878a76291594b9826d4b563
+
+Count = 146
+Adata = b15efed90a5d1d62f545ac22af6e
+Payload = 86bb2ae50e36c72936240a74502172625cbca210cf285077
+CT = a2de389233f5d28a6eabb863ca531b403caffe24bdb73939ff5f993dcfbd048274da7439c0f9ef5a
+
+Count = 147
+Adata = c9eb714ed9858a8dc11a26ee3f00
+Payload = 0dc79993047fd6e7260aac4d847fdb4d16483f28b13b5f17
+CT = 29a28be439bcc3447e851e5a1e0db26f765b631cc3a436590e87710559a375ece6ef2953b6aa2542
+
+Count = 148
+Adata = 07ca22271e95cb48a872046822b7
+Payload = f950e96d65a55efb3be3a55daffb421afad1d5625e3440a1
+CT = dd35fb1a58664b58636c174a35892b389ac289562cab29ef998035c81716e2d1ed4b4d56ff18af5d
+
+Count = 149
+Adata = b65f6773516124317cfb4b1fcdf5
+Payload = e160e28e601a49d16db18f25410756b330b036c42e615fd6
+CT = c505f0f95dd95c72353e3d32db753f9150a36af05cfe36981ae73a9b6896d8fc1b8c0d772d632983
+
+[Alen = 15]
+
+Key = 520902aa27c16dee112812b2e685aa203aeb8b8633bd1bfc99728a482d96c1fe
+Nonce = ddf50502f414c1bf24888f1328
+
+Count = 150
+Adata = 22b4f8f1aac02a9b2ef785d0ff6f93
+Payload = 533fee7d2c7740db55770e48cb1b541d990ea3f8f08ed1a6
+CT = fc867b319e0e4ab45ec518a1b5dcec4f29982173f3abfd4d8a8f8d14d2bdac84c3737cfbd75b7c0b
+
+Count = 151
+Adata = d0a43de391d492746ecf322acd6e5b
+Payload = cced20b59a6b2c3c45ea6c87802440c9c47b1015e83d86c3
+CT = 6354b5f9281226534e587a6efee3f89b74ed929eeb18aa28fce59f5e6e3cee284b4cc747ff5ee13f
+
+Count = 152
+Adata = 3a789c06f87f05933c34a1cf9834a8
+Payload = 90939a4530181ad6900664f66bfc2ce0289432a0afe9babe
+CT = 3f2a0f09826110b99bb4721f153b94b29802b02baccc9655ddaef56d8255125f7c316c6c59ce779f
+
+Count = 153
+Adata = 785260973f112c56d9f891160c4c11
+Payload = 86cd926b9565b76a88fde73c31e9ac908ffd1e6ca30b59ce
+CT = 29740727271cbd05834ff1d54f2e14c23f6b9ce7a02e752555810cbcdf48f05d0a7808673c82d08d
+
+Count = 154
+Adata = bf6a144591c0ea7b10274fbd3345a1
+Payload = 6ecd1c1acc6290672f9cf639ed0cebcb21ed0c56f35a5ce3
+CT = c17489567e1b9a08242ee0d093cb5399917b8eddf07f700849e41e5d34a698ae1d96f16bc68da944
+
+Count = 155
+Adata = 7d9488b500d89a27f367f34a448a87
+Payload = b01e3f4fb5ee7501e8c2f4ccefb542ae20d7fd61a2c41c8b
+CT = 1fa7aa0307977f6ee370e2259172fafc90417feaa1e130601bc54e546d1a6fcf6187169feb1ea533
+
+Count = 156
+Adata = 060fc718e994edc7bac9962ca7f28d
+Payload = 22ab6a0daf953165dda864cceeeb782e275c0b072aedd284
+CT = 8d12ff411dec3b0ad61a7225902cc07c97ca898c29c8fe6ff2eb6c0ab42acf42985c721bfd576e71
+
+Count = 157
+Adata = cb6f96dd06015967279ade310a7401
+Payload = f96ed20b23c784015ff58f5f040798ca75e3b98045deca8e
+CT = 56d7474791be8e6e544799b67ac02098c5753b0b46fbe665ac502b8e65cc1329b6895afdd354f5db
+
+Count = 158
+Adata = 9aa6d501455019b4ef4c7fb789d22f
+Payload = 648a84813ca97aef4ab7e143ee29acb946388660f18eb671
+CT = cb3311cd8ed070804105f7aa90ee14ebf6ae04ebf2ab9a9a87e5f8a8148f21adf721477c36bd99ca
+
+Count = 159
+Adata = ebd1d12bbd14176a0d4080aa1edb89
+Payload = 32d71e59634126ac6c6156a80a0dfa0175b29e9f40a31696
+CT = 9d6e8b15d1382cc367d3404174ca4253c5241c1443863a7dda9ea0427522dbeaa509a11755434760
+
+[Alen = 16]
+
+Key = 57da1c2704219ed59abfdf04743a9a93c87a63d471818de0f1564b2db6421562
+Nonce = 4b60a47b7e90f622fa0bf803e1
+
+Count = 160
+Adata = 0ae8c012ff39753510df3ee80707e4e2
+Payload = ddc3c1aa73fb6de92bb4db138e26f3c2e0543ab4f5924871
+CT = daa8256d4753fdf9cfef876295badaba89b45cc497f54d220ec2c6fb687753bca4580adc6aa2f296
+
+Count = 161
+Adata = d5b22e7697ba70e00c7ef32709563f01
+Payload = 34270576724083e9989764d08a0d5c1b4738f34927a1e436
+CT = 334ce1b146e813f97ccc38a1919175632ed8953945c6e1658f30b9c8e380c98bb939a4e8a85af758
+
+Count = 162
+Adata = 6b4edef415763aabcef01863e8197aec
+Payload = 904fe88e7a8e76447a64b488ef84184d0f1ab1b67f0c5a7d
+CT = 97240c494e26e6549e3fe8f9f418313566fad7c61d6b5f2e53e80d8ccc687fd303f4cdef44b6e8b9
+
+Count = 163
+Adata = 4c099809061024c010a77e9621fc2bcf
+Payload = 51fe7bac8f3255f17f64fb9322210fb7d8da8e762498b233
+CT = 56959f6bbb9ac5e19b3fa7e239bd26cfb13ae80646ffb7600c635dac5b70338dac3f33ce16a99145
+
+Count = 164
+Adata = 9d329439588164d5a96675a85c07a039
+Payload = eab6dbc13bb92df36b1882df2b8f34c3cefa41f95717fbd7
+CT = eddd3f060f11bde38f43deae30131dbba71a27893570fe84f996e8163affb1494bb3c12eeadf16b6
+
+Count = 165
+Adata = b768fc3daf29ff9e8bd575072d986e99
+Payload = c44c9c287d3eac7c30570d9c4adf2e4857c598f7c54cd126
+CT = c32778ef49963c6cd40c51ed514307303e25fe87a72bd47598b4206a9622d5631751a497dfb1f662
+
+Count = 166
+Adata = 3efc7cc2d16bf82d2bcfbc559a09b2c9
+Payload = c11b9c9d7607f387359c0038d3e8ec4d527562ce63c3384c
+CT = c670785a42af6397d1c75c49c874c5353b9504be01a43d1f7dd300167d267ad700dea37fb475ecdd
+
+Count = 167
+Adata = 0ff89eff92a530b66684cd75a39481e7
+Payload = cc17904b166f28df82f57889f391159a4a308e752d714ee5
+CT = cb7c748c22c7b8cf66ae24f8e80d3ce223d0e8054f164bb6303e9c9bd0d8e4aac42894ca03d6ab06
+
+Count = 168
+Adata = fbd11bc75759f0461e796f6917aeb42b
+Payload = 6f97e595ea2f40612ea84a2097b974d235055fe1dae59403
+CT = 68fc0152de87d071caf316518c255daa5ce53991b88291500953f46e0e9cf1369e9eb018a4df3c09
+
+Count = 169
+Adata = b79940952f42537484aa2907c72dffa9
+Payload = a48cbf933b88c0ec5ddcdd8fcad186391c2cbef308607de5
+CT = a3e75b540f2050fcb98781fed14daf4175ccd8836a0778b68a1702dfa0cd9c290c5ff9c35cc83705
+
+[Alen = 17]
+
+Key = 9267ebc99ccf648b146cba3c251187e24a9947d806ceb0ced6894211641a1e0d
+Nonce = 9b7298950280e8762ecdc9bbe4
+
+Count = 170
+Adata = 5824689453bc406bf891b85e4576e38fe8
+Payload = 967daf12f16f166b7b5038f83a1cf0b980f5abf4c7746f2a
+CT = 7cfe2a7a54306eb8d8a63d3d1ae86794f9a2c22198b2cb4f10ca926f1a430c08c12e23db3d913e93
+
+Count = 171
+Adata = cd15973753b94b77bb4b778de8b3b0cabb
+Payload = c4a756f6024a9dceabf6e264fffff9c719217fb418141ac5
+CT = 2e24d39ea715e51d0800e7a1df0b6eea6076166147d2bea05d5b674fd15410cc235dba6d8c8d82a8
+
+Count = 172
+Adata = ed8540f7ce451c522c1ff5d2d1030d7b3f
+Payload = e0d5de7d1eace211c0e70859ff315ff485d1200c6dd13f93
+CT = 0a565b15bbf39ac263110d9cdfc5c8d9fc8649d932179bf688750b5f36c86e7eda9015e960a7471a
+
+Count = 173
+Adata = cbbecf92551a15f5cf00a5be4a50b0eb17
+Payload = 05a4a4ba28fe8876f9bcfa5ec60651fd3fd4732f22049bd5
+CT = ef2721d28da1f0a55a4aff9be6f2c6d046831afa7dc23fb0d5fa842209dbbc04c87965f78500fec1
+
+Count = 174
+Adata = 873ba7f8b71517ec50297b21cf94cdb7a5
+Payload = 9cdebaeee8690b68751070691f49593668a6de12d3a948b3
+CT = 765d3f864d3673bbd6e675ac3fbdce1b11f1b7c78c6fecd67d147edbe114bfdb3f3b9b37d5719ef5
+
+Count = 175
+Adata = ac087420feb1e1e8c2546c2a8b8a5af0d0
+Payload = 5672e61cf664d73918dc1ca84df1fce82db0e305a61d57b9
+CT = bcf16374533bafeabb2a196d6d056bc554e78ad0f9dbf3dc57b4c2bbc377937d15b3b89543e29d0e
+
+Count = 176
+Adata = a12c690568114fd7a677f49d74e84fc1a6
+Payload = 0f5452e6b51540cf219998590995cd7f8785fa40b4f217fc
+CT = e5d7d78e104a381c826f9d9c29615a52fed29395eb34b3992e6ca774074b47b59adabeaf8835582d
+
+Count = 177
+Adata = 7a78ddfe5afb2dc90ee4a600c2fc014b0f
+Payload = 9ad338cbfd1b52e6ae4178f05e00062274f8b0b25eae72f7
+CT = 7050bda358442a350db77d357ef4910f0dafd9670168d692bd320f48a7221537e3cbed5ac4154a56
+
+Count = 178
+Adata = 6053e466ed1f647a3cd88c4d2052ec00cb
+Payload = d17b8d556e83190c84d4a812957c64ffa7f336298f4e2c72
+CT = 3bf8083dcbdc61df2722add7b588f3d2dea45ffcd088881740574e201f9a26932a87c8d822505814
+
+Count = 179
+Adata = f7673e3beb526834d6507058fe62e34987
+Payload = 2eaef86b0f602364f86510eabc58bc9ad1e6f0a6f6df0b83
+CT = c42d7d03aa3f5bb75b93152f9cac2bb7a8b19973a919afe6837dfa3fdef2f012b6609de2ac5dd9d6
+
+[Alen = 18]
+
+Key = 7a855e1690ee638de01db43b37401dcd569c1ae03dc73dd0a917d0cadb5abc29
+Nonce = 8f160a873a1166c8b32bccbba7
+
+Count = 180
+Adata = 72674aca7eba2fc0eeafbd143c2c4d8aa6c8
+Payload = 33ae68ebb8010c6b3da6b9cb29fe9f8bd09b59ec39f4ce4b
+CT = b22afdf4f12c43ec23e01ac1215a3f5286059211207e957057e9a9203da74387a9468f8af5e27547
+
+Count = 181
+Adata = f7da3f100b80e2ade812f1700aab6b72f746
+Payload = dbb29817b86cb80e0d008742cedfbf52b236f15ee8cad50e
+CT = 5a360d08f141f78913462448c67b1f8be4a83aa3f1408e35a3985f12a49eac424a35c94645917e91
+
+Count = 182
+Adata = 4b05eaadf98505d0806c233b2cdcaf4254e8
+Payload = 145aa8cfd544a2f46bae1aa83cbdb3d21c3d1350078a3af4
+CT = 95de3dd09c69ed7375e8b9a23419130b4aa3d8ad1e0061cf4ab089a8724b87a1167180963d44ec65
+
+Count = 183
+Adata = 05a3aaa08b9a6aaeb84704431425d0e45a14
+Payload = 6b32e8906dc89194a69410b79cd041b62eb01afb28a3e10a
+CT = eab67d8f24e5de13b8d2b3bd9474e16f782ed1063129ba310a7d1520141892e140448292185c41c7
+
+Count = 184
+Adata = 74db01edc26a2d2044cb8eaad8b907b78863
+Payload = 545ed03588fd85a8bbfeee66d2082ae6f8e2f3c9dbd8725f
+CT = d5da452ac1d0ca2fa5b84d6cdaac8a3fae7c3834c252296472d3eee219d94bd788f62df4add5ec40
+
+Count = 185
+Adata = 5f2c6ddf5a2403e04dac8b2813c060b67e76
+Payload = 66dd5fd8611c551973a3d0c078ec2b4d39ad163d9168de3c
+CT = e759cac728311a9e6de573ca70488b946f33ddc088e28507c600496f4f8b1b7da118ee36d8cd57f8
+
+Count = 186
+Adata = a650a2a5e3c6f7c95614570aaefd0cdd9a42
+Payload = 6f364b3f778376cbf3f4b0b0c5350a8fa278f9d8c25faad6
+CT = eeb2de203eae394cedb213bacd91aa56f4e63225dbd5f1ed4710004d06ce7a7efbd19da4e3ce3cf7
+
+Count = 187
+Adata = 477c2484cf5c56b813313927be8387b1024f
+Payload = 3de4798d8ad84c460b92abc10b7f5e7c9fae46a1dd353687
+CT = bc60ec92c3f503c115d408cb03dbfea5c9308d5cc4bf6dbc304099641c4ec3dc2c54fdf4f48dbef2
+
+Count = 188
+Adata = 564e1df74aa2d7ee33b66cfeda810774e16c
+Payload = 7769b45fea11f530fb9a67f1b5b1964a34cfa32bbb03f4b1
+CT = f6ed2140a33cbab7e5dcc4fbbd153693625168d6a289af8a905c1b05e8945685f8688faea777eb43
+
+Count = 189
+Adata = d5e66502529b0045883d935e05acd242baa8
+Payload = 0c0a502b42f81b51806c7080a8155280f493f2922cdc7df8
+CT = 8d8ec5340bd554d69e2ad38aa0b1f259a20d396f355626c3ea5a3b6a8bafde4006b993cfb3b13557
+
+[Alen = 19]
+
+Key = 0ebdc6ddb4c502725dd6ee8da95d56a0d1044b4694d6ba8475a4434f23a8474f
+Nonce = fb717a8c82114477253acc14f6
+
+Count = 190
+Adata = 41e9d65632f74f449a6842d5e6c4a86ef83791
+Payload = c7360282c85484a5a33ab1c68dd70873ab4e74ffd4a62cd5
+CT = 2e961b3a2fa1609a4e6fd04bff6ac5e306ae2638706f997b42be2e2ba05c54b619850db5c9d684fe
+
+Count = 191
+Adata = 555304659bde926cb2553b8a4605251fcddd92
+Payload = 1332314d1cf783b9f64e0fa2d42d43d225da9fd5165b5f0a
+CT = fa9228f5fb0267861b1b6e2fa6908e42883acd12b292eaa4bbdee2605bc69601b1e83d1e7a0b400d
+
+Count = 192
+Adata = 69ea953dbb910ec589372d797c7379d3f3b9e9
+Payload = f264da8606ea429e0e25da3f2efafe28beaff05b42097369
+CT = 1bc4c33ee11fa6a1e370bbb25c4733b8134fa29ce6c0c6c7304611baf530932da7954f714514d228
+
+Count = 193
+Adata = d7186a67061319b44eedc0677ebf5d932d5bce
+Payload = c9ee6482144dc61c43041324a2c18ede370011cb4882b0c5
+CT = 204e7d3af3b82223ae5172a9d07c434e9ae0430cec4b056b6d1d44e26404b7324767f0b3f7486f8b
+
+Count = 194
+Adata = 38f37d5e2da017f1953ff3701be0b38809ba80
+Payload = 40524a4d32a711e7d5a59809878c318f42b6e2375b77b8a7
+CT = a9f253f5d552f5d838f0f984f531fc1fef56b0f0ffbe0d095453724d2db19f606c85d00e49b0bb38
+
+Count = 195
+Adata = b3b2d249cd3517555fa692bbe9116f069e7405
+Payload = 961c15bd7dc34cd5409c9e8869988676ec6845ecb0ee85fd
+CT = 7fbc0c059a36a8eaadc9ff051b254be64188172b142730536db1e4112fcd650e8c0f0f6fbf2d07e1
+
+Count = 196
+Adata = f5b5bcc38efaff01f69bd3a106dcfca3cc6414
+Payload = 879568ab9ebdea768a5459ced1d3181d822536c3d1ba38c3
+CT = 6e35711379480e4967013843a36ed58d2fc5640475738d6d1cedb29e68322e47ff9997f859257d98
+
+Count = 197
+Adata = a2098e3e23826e01f31107a208202f710eff00
+Payload = 47cb57599686716c75d7ecef5541d20fb908e6d98c39925a
+CT = ae6b4ee17173955398828d6227fc1f9f14e8b41e28f027f41c12bf2a3571ed672592b27e986e9058
+
+Count = 198
+Adata = 20a3d53e77201599540344c4e746c3ae3a5f84
+Payload = 4a8667b5ee09d3d4a6dca9a95f4ad406f1da94b846dcc6b8
+CT = a3267e0d09fc37eb4b89c8242df719965c3ac67fe2157316f12b2be8f5966d96602111c28f87b104
+
+Count = 199
+Adata = 92c592ead4b3f193cc36687593d4f0f412a5d5
+Payload = 1dc9e32ac4176f64bd78a6edd651ebeea3ba85dfcd8298a8
+CT = f469fa9223e28b5b502dc760a4ec267e0e5ad718694b2d06776df0a0cf048892e65bd8ad77cb2255
+
+[Alen = 20]
+
+Key = 2ff64bbec197a63315c2f328dcb4837d0cdc21a5d6f89ff1d97cb51195330cd8
+Nonce = a235f8ee3de9896b71910ac02c
+
+Count = 200
+Adata = 2b411bea57b51d10a4d2fb17ef0f204aa53cf112
+Payload = 4a17522da707b4b2587a0ae367a2cd2831bb593a18ef442a
+CT = 1bf122798bd8ee8e73391d589bd046a294d1615794e69cb9e6f3ba30143acbc3a1c1c6ec74333107
+
+Count = 201
+Adata = 0248359f8071143c3cc1d61882a3547a0b3d2175
+Payload = 4a6a7151465c2abd7e7fa1fd13019ad098b6ebcd190e96f7
+CT = 1b8c01056a837081553cb646ef73115a3ddcd3a095074e6436cb510c13a039f4df8cc26a942f9911
+
+Count = 202
+Adata = cca77bc4cf6c0abd3393dac3fbe90fbc8a1154f7
+Payload = a94f5ede43929d48d2c5a58c3262d9127d2ac3cb2fbd5768
+CT = f8a92e8a6f4dc774f986b237ce105298d840fba6a3b48ffb7fe0dedc2899dff81a251cff16bf5897
+
+Count = 203
+Adata = 9c082a84646c070bb11b7d6b92b62f06ee5b5b71
+Payload = 7303bd41cf47289a3111366d08e8e21548baf293052029eb
+CT = 22e5cd15e39872a61a5221d6f49a699fedd0cafe8929f17886c43ac23800de60a1fd2caef0f03261
+
+Count = 204
+Adata = 1c3ede1982a807a410ae1e21947bf430f8db7027
+Payload = fa9743a67978c20316cb91801d7789e350079aae3aadbd43
+CT = ab7133f255a7983f3d88863be1050269f56da2c3b6a465d026f7907e235c09d3322c4092d2e88f88
+
+Count = 205
+Adata = deb05a30a026ff66ce71e98afa62f0255aef84f5
+Payload = 99599b4042dcdb685350cdecfdf24992fd5b165670025d0c
+CT = c8bfeb146e0381547813da570180c21858312e3bfc0b859f6bb44a28c145d49f49f2821d4044e4b6
+
+Count = 206
+Adata = 93dd9b00a3353e5331338dcfcb7ca7e0bb873a4e
+Payload = 451101250ec6f26652249d59dc974b7361d571a8101cdfd3
+CT = 14f771712219a85a79678ae220e5c0f9c4bf49c59c1507400f7d20aa3d792d6a3ebc5ee0df2fd89c
+
+Count = 207
+Adata = 0855263860043207543c8c34648d53ec51c4f47e
+Payload = b2db87b7787531968d603098cb20ca7c438b4af72623fea9
+CT = e33df7e354aa6baaa6232723375241f6e6e1729aaa2a263a7ca4733f0208668b0a7879305e861d71
+
+Count = 208
+Adata = ee2d3a66deb3ebca867a902bb9202226ed516ded
+Payload = ca18ce38086223e63b4f0b616d110010f9e45eac42f2ba46
+CT = 9bfebe6c24bd79da100c1cda91638b9a5c8e66c1cefb62d5d76b482ff20429da8f60f0f863e1af50
+
+Count = 209
+Adata = 8e531aaea849addab6a83497cbc504f489505952
+Payload = 5717ed5da5b8aa806a18bfe979502bab6632c9428d3a7725
+CT = 06f19d098967f0bc415ba8528522a021c358f12f0133afb6aab66e1ac2346ef97850a4985c64b737
+
+[Alen = 21]
+
+Key = 24e9f08a9a007f9976919e10dc432002e2e078a339677f00105c72ed35633a3f
+Nonce = 15977424eeec0ec7f647e6c798
+
+Count = 210
+Adata = 2d838eb51a4bc69a001a18adf2084a680f02a3c5fc
+Payload = d3416a81b4246eb0bf8119a72a886bbc0ac9449c69f71d2f
+CT = e001a8fae390dc5d672cdd18f86a1f728158ec83a002050def9af5679edbcbb7db20ab6af30698db
+
+Count = 211
+Adata = d83ee7ce22fd1a2882d8d552346e4d7b3efdd67da4
+Payload = 22b6f10b482448626f6c7bebb14f1497896d071738133b4d
+CT = 11f633701f90fa8fb7c1bf5463ad605902fcaf08f1e6236fd435a5a38f84387f63b13407f65ec86c
+
+Count = 212
+Adata = 2d5537b24d0b0f7a45703c1e131656ec9edc12cdf7
+Payload = d60edc830be8207ffd9e9f646d3b4343b10b3d56acb89d44
+CT = e54e1ef85c5c929225335bdbbfd9378d3a9a9549654d85662ede8a705f8c988f55459542bd631b1c
+
+Count = 213
+Adata = 1a750eb326923412d94ccb35f5acd0f87415268178
+Payload = 716d3132f449a9def383978102ae50ed3ccae0cb346ba1df
+CT = 422df349a3fd1b332b2e533ed04c2423b75b48d4fd9eb9fd986de774a612230ce6c71449d26732ce
+
+Count = 214
+Adata = b10fc523bc4562d44edfe5956f93c15c4ab38bba3c
+Payload = 063c2ae2a15f26f979bf90657d20643e3184f1a9f75a3aad
+CT = 357ce899f6eb9414a11254daafc210f0ba1559b63eaf228fe710431005264fa7d3fc04bac50fc1ec
+
+Count = 215
+Adata = fe4f60ce9634e7dbc5e56204c4bf8aa9be577027ec
+Payload = bdc513e56a5bb70c02abc041af04d6e45e735d10cc88357f
+CT = 8e85d19e3def05e1da0604fe7de6a22ad5e2f50f057d2d5d5c13bea6ad0cad724e6cd02c89517ffc
+
+Count = 216
+Adata = 48f3ceda4fd390a7eb38f7f5bcd14310af6b5a557e
+Payload = 7dc5d8cd90ce2faf76bbd0d52e5ae11b310fc2b0051c4377
+CT = 4e851ab6c77a9d42ae16146afcb895d5ba9e6aafcce95b55d2a5531655aae01e249f213e0e04af0d
+
+Count = 217
+Adata = 199ec321d1d24d5408076912d6bb2b6f192d6b347f
+Payload = 66c2696edec26ba3d07bd3f485a0d6ce8a1b0a85b20083e7
+CT = 5582ab158976d94e08d6174b5742a200018aa29a7bf59bc52a127ef341345f9641b26e91265e1482
+
+Count = 218
+Adata = 8b013f5782d5d1af8dbd451a4202866095dac975fc
+Payload = f4da8ac3e8fe5ec6a5b6a2f27b68396e850b46a024d441f0
+CT = c79a48b8bf4aec2b7d1b664da98a4da00e9aeebfed2159d2a005ca13c4bf715c3b7b2782f799b23a
+
+Count = 219
+Adata = e320df32b71cc530e8493b12b9afbeabc255c5eb44
+Payload = 244891cb4af66cc8e99a3784a2e82475e51bd5c7fde67cf5
+CT = 170853b01d42de253137f33b700a50bb6e8a7dd8341364d704642aff9cb9288d49f0e567dd837e05
+
+[Alen = 22]
+
+Key = 0ec1b22b8df05dc92135d2dfbefed8ea81458f5ea1b801e8a218faf6cbdf1a79
+Nonce = 97ebcb8575bb58260208d5c227
+
+Count = 220
+Adata = a2f6337f86dd00d1a58448851e95d8c9bace4a5c8710
+Payload = 2f59d94d4ab8eeb84c2a6fefb7fb0a3ac059c1e1a65ae34a
+CT = 7ca0b1dbe34b0391e524b868b0af08b3e096917664d6aa2cabc1f9d0132394149c9062b74b82f04b
+
+Count = 221
+Adata = abf26b05558252c8e38c52b1ace087bbd1eb3d561239
+Payload = c25381853f73a3dc4195fdcbc45dfa1a40eb8324749adb2e
+CT = 91aae91396804ef5e89b2a4cc309f8936024d3b3b61692486d7df57c6a792f6f6b24cb5f87e92123
+
+Count = 222
+Adata = a13ade56b47803897666e42ef2ef88be0e779ac86c28
+Payload = 8dc5226a2a13088c87f4bf94262e0c0413f06b35d2fda79b
+CT = de3c4afc83e0e5a52efa6813217a0e8d333f3ba21071eefd4ac19b0b74cd9d5e100598b96c9f1f2e
+
+Count = 223
+Adata = 3c5b68b65edf62755b7e064bd26c843816bf6c1cd481
+Payload = ee4b23039cd512cfab8c7a2d0f2c78d66764520bc88759e1
+CT = bdb24b953526ffe60282adaa08787a5f47ab029c0a0b1087a77a27eabfc79f192c0ac491280af8d0
+
+Count = 224
+Adata = 0213fe13c49083d7c00335e1864dc139c9e7123162d1
+Payload = 30b48d4021838090fbd5251069ff8c631452daee5ef899db
+CT = 634de5d688706db952dbf2976eab8eea349d8a799c74d0bd39935f91c1e29fc1e4c5c5427ca9da79
+
+Count = 225
+Adata = a32291746b151be8134e183798aa82bef210343feaf6
+Payload = 2286a1eddd80737a724ca941217e9f0232870b6c2f20d29c
+CT = 717fc97b74739e53db427ec6262a9d8b12485bfbedac9bfaaeaec90ada2a1ffef64c3873af645a40
+
+Count = 226
+Adata = a30f2fd445820cdf800145540602c877da0e4c311272
+Payload = fe703ca0901e4a706ce1393c7d8ce18a03eb2caadbfa7b8e
+CT = ad89543639eda759c5efeebb7ad8e30323247c3d197632e87932952831d0ba25c77c18fe154d8ed8
+
+Count = 227
+Adata = ed438e393e0e37629cb25044ae89de9fd0d42d60c1a3
+Payload = 7043c67726870bb5816da925925bc2722478311c8a606cca
+CT = 23baaee18f74e69c28637ea2950fc0fb04b7618b48ec25ac234fd0241d00f3890a23ccd0bf16dcbf
+
+Count = 228
+Adata = 1013946815001a2c08acca4196e0d6668ffbb3883cf1
+Payload = 695e9712dbbf883e9bf8af9188bd01fc631968928258168d
+CT = 3aa7ff84724c651732f678168fe9037543d6380540d45febaf43498b0c3f70c119f82d5812db940f
+
+Count = 229
+Adata = 44cc9b2510680c4d73f1938c77de21242c8ee790ed7f
+Payload = 67ba90d22c6bb5f649bc0c505c5ed23a299882559a3bf520
+CT = 3443f844859858dfe0b2dbd75b0ad0b30957d2c258b7bc46db66dbb03a4c943ac089ed11eb214bbb
+
+[Alen = 23]
+
+Key = 0875020959ed969cfb38636d1d5aabce9658b00171a7614ea9e5395331c7659c
+Nonce = 451101250ec6f26652249d59dc
+
+Count = 230
+Adata = 7cc9c51b69f98a06391ab32742fb6365e15106c811fe8a
+Payload = 065ef9eeafbe077c1c7049f43eb0d8999708e8609f214d5c
+CT = 990065322a438e136860f7b019807e9feff52a642bf3d44a9163fa7a867f04cab6f52dc250070f31
+
+Count = 231
+Adata = 7bb1bc069a783d45d51d8ecd0a53ab7a386fa1f5ef12a1
+Payload = 69b2b056f2265e707d3e31e68bff6a060544c8a737b2a9b9
+CT = f6ec2c8a77dbd71f092e8fa2accfcc007db90aa3836030affd33dd9155619fb040dcd6038c7b7367
+
+Count = 232
+Adata = 0dd220919d0eeee3b7cec36c47e376b778583b38bf61c8
+Payload = b98d79aaa4c04171398c7f1189497acaa7546ef068bc7a3f
+CT = 26d3e576213dc81e4d9cc155ae79dcccdfa9acf4dc6ee3294fcba5a886b1f33cf1cf44618d28f01f
+
+Count = 233
+Adata = 1c1915fab09348b9a5536495c70d1a040305708c112479
+Payload = eeaeb773ade5fb2d27b50bb892916333e0b123c6e3ae5bdb
+CT = 71f02baf2818724253a5b5fcb5a1c535984ce1c2577cc2cdeafe2c670eac203d5e90b9d520e7a618
+
+Count = 234
+Adata = 614b0ac4611b6c6d3b4ed089510dcd2215567bc3789f85
+Payload = f2198e1f91fde2672a1ef60403c0d175f366b6780ee9f1c2
+CT = 6d4712c314006b085e0e484024f077738b9b747cba3b68d4f0388746438e83b731b5588fef53f1f3
+
+Count = 235
+Adata = 866fea4483d4e903566844e31c24283571832dfae32c74
+Payload = ba37617342b4eefd4bdce8fad30c4751b206d47814973b3a
+CT = 2569fdafc74967923fcc56bef43ce157cafb167ca045a22cfca81f8b36d16698a600fd701f2c6424
+
+Count = 236
+Adata = 9d7546f7e8b949c539d21a357f81d0151e278d0bf2c5a5
+Payload = 69adcae8a1e9a3f2fe9e62591f7b4c5b19d3b50e769521f6
+CT = f6f3563424142a9d8a8edc1d384bea5d612e770ac247b8e04c15a6d292c7ed2f31cf9512435ec7d2
+
+Count = 237
+Adata = 42b692048c8b3cce1b5e83f4f33232a7d7d0bc20695e7e
+Payload = e0753d4248643642c7a96404de8d76c9d80527b659ec6d31
+CT = 7f2ba19ecd99bf2db3b9da40f9bdd0cfa0f8e5b2ed3ef427a2ad73179d0314b5fe52dd7217518cb8
+
+Count = 238
+Adata = f1dfb6fdb31cb423226f181c0988a52ee4015aef4536f4
+Payload = 79ba959c7221b293e2115f538d9394c64284c756563c04b0
+CT = e6e40940f7dc3bfc9601e117aaa332c03a790552e2ee9da69ccc5ba1caf933b80bfc6f281109688f
+
+Count = 239
+Adata = 8eafce9ba466fd53eb87f499d7c76bd486db0e90a3d281
+Payload = e1590206717a708cad9cca7d23a3b8ee5f7fb7786aa3be47
+CT = 7e079edaf487f9e3d98c743904931ee82782757cde71275173271ec36d92fff34609169f579c8f1d
+
+[Alen = 24]
+
+Key = ef4c1d2314e671f666cc6667660f1438a293208c7cc29b412d81277f0a635c91
+Nonce = 50b23b052922366c25dd40e348
+
+Count = 240
+Adata = cd0522ebe1fed82465277d1c10ae9316a98b4469be63b180
+Payload = c99c3e79125b6fd95e737326a842424eb6c6ecea4c0475c4
+CT = 76df4be4ec8373864399acda11294b220b9f7c3a7d2b3660b25764e40ac6a171e7e6bab4fdee4288
+
+Count = 241
+Adata = ce5bf070678cb07e963263b1562ff79311144addb6e4de4f
+Payload = eede01b08f9a303cdf14c99d7a45732972c6eff2a1db06eb
+CT = 519d742d71422c63c2fe1661c32e7a45cf9f7f2290f4454ffca49758d17f2073066b82667eae6ce3
+
+Count = 242
+Adata = 07175be2475cc735c9a3c1140895277378debf8fb1c87c24
+Payload = 6d5579aaaf8737b01620424f3ddeaf538f10dfad094e5ec4
+CT = d2160c37515f2bef0bca9db384b5a63f32494f7d38611d607c1d64d7e9de47a6ad7878283da9d870
+
+Count = 243
+Adata = c821a8d4bab9d993c20dd206955304a55968e6db5ab6480d
+Payload = d0628b2027f06c246497977d05f211b2c2e302d5b82700b5
+CT = 6f21febdd928707b797d4881bc9918de7fba920589084311adc2bb471862d25cfe25e66fedb8e28c
+
+Count = 244
+Adata = 68439bc9d176feeeb4119d00ed5449dfefb72b5a582bfd97
+Payload = 6cc9749f48c61050e421afa3a10ad3dd3aa02cc3f8586915
+CT = d38a0102b61e0c0ff9cb705f1861dab187f9bc13c9772ab1319a493abc947945f1312395ea98d937
+
+Count = 245
+Adata = adb262c924942e4e1964e9d97c6a8c159fbf9bfedc5ff296
+Payload = 92d50736466e64e6225962e76bd90da824f716a3301a1a90
+CT = 2d9672abb8b678b93fb3bd1bd2b204c499ae86730135593421d0602d29447ba6b24a67509eaee1e8
+
+Count = 246
+Adata = fc7b08707d3c3dac7689ec18088ee6502ef08d3ffbff38ed
+Payload = 87c7ac031fd63e4c83280dce6b68a92dfafb6ea19388fa9f
+CT = 3884d99ee10e22139ec2d232d203a04147a2fe71a2a7b93be52a2eeacb1f023e849161b6306b6cfa
+
+Count = 247
+Adata = fd43dfb66041b117f2ac54c94f7b6e2677860864d9494175
+Payload = 6b53c46266b2f4284d8fe7f0549c98977344d67e178e9a8e
+CT = d410b1ff986ae8775065380cedf791fbce1d46ae26a1d92a0d8c5b1e96b21460e0b5414639abeb0b
+
+Count = 248
+Adata = ef1ad3eb0bde7d4728389da2255d1f8a66ecb72e6f2f1ac4
+Payload = 8e7d8a44244daa7df2b340993e32dac50e05d7b2e103be98
+CT = 313effd9da95b622ef599f658759d3a9b35c4762d02cfd3c1c97260d20797d374c595cbc2ff080bc
+
+Count = 249
+Adata = 9895b24d12b004b215583eac70a95f4fba7442164f35c57b
+Payload = cec07df916ffb7a453d0eb588b7462096f22874bd5abf814
+CT = 71830864e827abfb4e3a34a4321f6b65d27b179be484bbb06cd287afcbdbc5531f11246080b22677
+
+[Alen = 25]
+
+Key = 8544808e8fbf8c3a5e1d4ca751d4b603af9fe119eabc6923205815e0e748b7e7
+Nonce = b44a58724596b4d8dea827c1a0
+
+Count = 250
+Adata = f5b2c88f5232c37273b1e66aa31cfa7201e33c21d60054d025
+Payload = 617d54fc6a23601c79e3984f93bfc2d151fde420863206b3
+CT = 57b3414db48982c6567265e1e0173bf38fdfaffe4461fbebc1411af83237c0f9eb0bfe8ed914da66
+
+Count = 251
+Adata = 8fabe14dcb3aa2fd28281147c326e98ad699ca7997f03a105d
+Payload = 337290d0b4ce1e87afc3cf01d6c98f8c17a4603120dcfcd1
+CT = 05bc85616a64fc5d805232afa56176aec9862befe28f01897ed6e23720b60ffe54bbb9f7ff371008
+
+Count = 252
+Adata = cf193eb3d755cb8e06c5be2334b5c8b7a22b6524d46d547ba3
+Payload = 01ef7ac6470aa02ccd8c1712827e52699d05751b78e4c5a6
+CT = 37216f7799a042f6e21deabcf1d6ab4b43273ec5bab738feb6aa6b284e7720acbd027a50317f816a
+
+Count = 253
+Adata = b4cadb5f9cb66415c3a3b71421b926f147566a174160a0bcc0
+Payload = 64fb9322210fb7d8da8e762498b233b0eb172c91231c50cb
+CT = 52358693ffa55502f51f8b8aeb1aca923535674fe14fad937058e9c0164ca079668097fde19e5302
+
+Count = 254
+Adata = 48400d76ff882d6d5129c8674acc71f445356c9db9c91f8256
+Payload = 291aa463c4babc76b4a6faf2e27e9401586b1ac83e4b06a4
+CT = 1fd4b1d21a105eac9b37075c91d66d2386495116fc18fbfcf988611d5ce0f65b217bb4787bf59bbc
+
+Count = 255
+Adata = 749d369d837002ad33feb8aa22c3f68705eb4872e1b8f85a7f
+Payload = 141cdd7f964a78815be144a785c6a2a298c54230e73039e2
+CT = 22d2c8ce48e09a5b7470b909f66e5b8046e709ee2563c4bad6251a5fd375a48583a6d0f8eb75cbb4
+
+Count = 256
+Adata = 80214108b16d030feff6e056c9a07a00a1d5e3ebb07abd3f4a
+Payload = fa2441cb7f9d072b8a3f1a496b2be6728a38b94a4f44c9be
+CT = ccea547aa137e5f1a5aee7e718831f50541af2948d1734e6af1dab0f105414293cb130bea285fd6a
+
+Count = 257
+Adata = 8b9fabe29718a8f297c9bf6f199c80bbc71f94eb3034a11ecb
+Payload = c8ce88ab40b62229223d46cc44f21bb39cfef27aa9fdccad
+CT = fe009d1a9e1cc0f30dacbb62375ae29142dcb9a46bae31f51cc3f7640a42460be877fb7059a3ed61
+
+Count = 258
+Adata = 8812f28a0cd5fdaa226fdd44ed857241007377057be3bea577
+Payload = cf59f75ca4d6d216cf8862b44b5192c382c140f862def117
+CT = f997e2ed7a7c30cce0199f1a38f96be15ce30b26a08d0c4fbbe0ddd2e7f4aa2024b3fec9281b6cac
+
+Count = 259
+Adata = c8f05e96d703a4850bae1421ae9ff3aec7531baf9b899dfd75
+Payload = 4eed58f381e500902ba5c56864f6249d191e14d1b1fad3dd
+CT = 78234d425f4fe24a043438c6175eddbfc73c5f0f73a92e85e5df1e5e96bb84f730fcb253d468278f
+
+[Alen = 26]
+
+Key = e19eaddd9f1574447e7e6525f7fd67e3b42807e44fbb60e75d8c3e98abc18361
+Nonce = a8c459ce0223358826fb1ec0f0
+
+Count = 260
+Adata = ef88f4393d6c1e7b7be55a12144209ee051bb779e440432721ef
+Payload = b3b0de10b7c0996662f1b064e04e528b7d85ca1166985d33
+CT = d63e6082c95c6c5ff2bc0771321a4f883ef61cff7b99e0ea8a20a1abe7c842ebc08c8c81a2743c81
+
+Count = 261
+Adata = a4c891c9dd1fcc982c35bc74cfe71651bae424602519672b466d
+Payload = 4f0b40913f07269550b7b06ab9027a4d9331f8ef98a45dca
+CT = 2a85fe03419bd3acc0fa077f6b56674ed0422e0185a5e013845e2d6de83ab729dd200a21088a1ec3
+
+Count = 262
+Adata = 4db5730cb9794f3b1facc9d6738115d02ba9f27ba02330fbb856
+Payload = 841e032773d58bc72a3237bc9b24c61b9efdd850fc2ea605
+CT = e190bdb50d497efeba7f80a94970db18dd8e0ebee12f1bdc10ed272c732247a696a608ef67510f9c
+
+Count = 263
+Adata = 471a900ee49f2cfa1d3eb37c951d810c349364d4cc3b5b64fc47
+Payload = b4db42e523e65557157b93dc0281601f7997e6731543a914
+CT = d155fc775d7aa06e853624c9d0d57d1c3ae4309d084214cd15f0df52e392c37ec15f7458469dae84
+
+Count = 264
+Adata = 7b40b3443d00a0348a060db109e8882157612c43084ac5c3e9c5
+Payload = 73e0ed35c0e847188e607cde46586eb9e237fbdc5d59163c
+CT = 166e53a7be74b2211e2dcbcb940c73baa1442d324058abe5421433dafea2b5484ba87b5050e1fb49
+
+Count = 265
+Adata = d563f5c048a1b45265182b99ca7b9004fdc73a9cb07806dd44fc
+Payload = 4f7669caaedee961dbba6bde9d09fee1a20eee55baaf98f5
+CT = 2af8d758d0421c584bf7dccb4f5de3e2e17d38bba7ae252cdf91749fe3cd52a9431d9a847a8c2a9a
+
+Count = 266
+Adata = d301a61eb17366d4e70942ab69b4f4bcf8ff6a97f5972ee5780a
+Payload = 154454fb74e9565c56775a8e4654f75a38b954dd28c4e939
+CT = 70caea690a75a365c63aed9b9400ea597bca823335c554e07563d37846f5185bb44d71be1ea6a73c
+
+Count = 267
+Adata = f74b48d168f77fbd3429728c0b168ecbd854264eaef70b74fffb
+Payload = 716b371857e68a17b20ea06651cdcfd4560a741830ca8a13
+CT = 14e5898a297a7f2e224317738399d2d71579a2f62dcb37ca55e93bc2d3f05d7016747690fb920e12
+
+Count = 268
+Adata = 3a257ce3592a8f88162f0bb4ecd5db3bb79b54ab17b0bbc61506
+Payload = cfdb7363985aa01af6f8e8237dbfb7871eb39303b4135269
+CT = aa55cdf1e6c6552366b55f36afebaa845dc045eda912efb01c46822f839f09c41b7aa6dc06035c93
+
+Count = 269
+Adata = 21916ebeca9e66b77cf55d1cac80a4c85d8b6b014f268ffa73ca
+Payload = b4b67ac551d1966caa20d951351387f384c2e5d81a76a92c
+CT = d138c4572f4d63553a6d6e44e7479af0c7b13336077714f54f8e77600c5bbc6d028fa25ba61a1719
+
+[Alen = 27]
+
+Key = 9498f02e50487cfbda1ce6459e241233bd4c4cb10281dcb51915dbc7fb6545c0
+Nonce = e3bd4bc3a60cddd26c20aa8636
+
+Count = 270
+Adata = 70cfcb828d483216b46c3cd22e2f9ee879e9e3059b566179b6e16c
+Payload = 0d16cc69caa9f19b88b05e151b3d26accd018ca4a5786a80
+CT = f1c4bedb8d6f91676881daa37656a7e6402f472735b04a0f1f8332f4236437737438e7aa1b5100c7
+
+Count = 271
+Adata = e7e5779282db80f424dc050b2c1e7754b2a5d3a8beae77beb74e34
+Payload = 148de640f3c11591a6f8c5c48632c5fb79d3b7e1cef9159c
+CT = e85f94f2b407756d46c94172eb5944b1f4fd7c625e3135138be2f6f356c2eb401468be15104e7763
+
+Count = 272
+Adata = d17e8189a94a559b07be9549f73d653172740e8e978f5b0a38ad43
+Payload = 00a23b25bca7c206edd051814d81083db1cd00048ce8ead5
+CT = fc704997fb61a2fa0de1d53720ea89773ce3cb871c20ca5a9646f2b6c2455603f1a6f20ea5a4611a
+
+Count = 273
+Adata = fda37ff136895de7ebeaf81e701e5751245201baed2e13d7e1b591
+Payload = a89409b0977f60a029dc4c1560ba6dbe7c65b068633acf74
+CT = 54467b02d0b9005cc9edc8a30dd1ecf4f14b7bebf3f2effb303fa5d8321241b1c9e18a5909d6e428
+
+Count = 274
+Adata = 9c179fd0d6277a5e073e77dd6abb4cba00ad9c9932e6c002b951c7
+Payload = e16c69861efc206e85aab1255e69d6d33c52cf058dec9d0b
+CT = 1dbe1b34593a4092659b359333025799b17c04861d24bd849e8cb01db1da077502814db1610662ce
+
+Count = 275
+Adata = cf5703228e615428d3d3805e428e754961d205c5aa0297ecdea71d
+Payload = 62036cbed3666d85624d3dc9c1f437454b9ab5c03ce0de92
+CT = 9ed11e0c94a00d79827cb97fac9fb60fc6b47e43ac28fe1d40a02a49857d7b280330b8105efac854
+
+Count = 276
+Adata = bab7e36098d59d3a31d7784d549aebfc6938bbd0612c85c0edb796
+Payload = 790ac86c5e9d8ce8cbec1dfb7e4fc4dca3d0b1039adfe585
+CT = 85d8bade195bec142bdd994d132445962efe7a800a17c50a5ecfa9dd03e2db70aa212ee7dcb573fd
+
+Count = 277
+Adata = 96f0b7cd7439721d4c9cc4f69585f8c90a95bed8fea22150efffba
+Payload = 3cfacd61ea3398de20ca6bdb00e81af482320614bdfb8642
+CT = c028bfd3adf5f822c0fbef6d6d839bbe0f1ccd972d33a6cde17a7a0cd162945a3616892e101e3e93
+
+Count = 278
+Adata = ee71e53d0b4eef82575c2bd38d7bd21b41fabe58c6f571954fe159
+Payload = d75c153e34ae1c6d1fcf5b1052190d8882041e1f9c5490e2
+CT = 2b8e678c73687c91fffedfa63f728cc20f2ad59c0c9cb06d15fadc2d79841d230cd55c04379f22b4
+
+Count = 279
+Adata = 18a4aa894861c7720ddb43809c3d2ed2af2f1bfe8f9fd4f872c14c
+Payload = 0e728056c7c64214be8f1f1727408d8cca8c42e2ac7bf67e
+CT = f2a0f2e4800022e85ebe9ba14a2b0cc647a289613cb3d6f1b229b9bae4634eea6b723f432e19ae55
+
+[Alen = 28]
+
+Key = 3ac7d5bc4698c021e49a685cd71057e09821633957d1d59c3c30cbc3f2d1dbf8
+Nonce = 54c8ff5459702aac058bb3be04
+
+Count = 280
+Adata = ecbd7091732e49c0f4bda2e63235ea43bbf8c8730f955f9c049dd1ec
+Payload = 89198d3acc39b950f0d411119c478c60b2422ffe7e26e00b
+CT = 7717b8e4447afcea1eeebf3e39ffdab2f52828e7931ef27e475acd27900478f09fec1f479ab3a7c8
+
+Count = 281
+Adata = 9a04820205234795ecd540b6a0b2fbd0b19f18106c42f374a2b98425
+Payload = c0f61950f98110db4226e269cf197c7e2794c5b87ad68cf9
+CT = 3ef82c8e71c25561ac1c4c466aa12aac60fec2a197ee9e8cf7b7ed6e8ede6ef5a73b484bf13b3424
+
+Count = 282
+Adata = 0e4dbd167da0240298f4795102ef18ff9a8772c6fd73b3374cdfa30a
+Payload = 7960dbc9136880e2eea7956c3271adfe2aba7dca53da917d
+CT = 876eee179b2bc558009d3b4397c9fb2c6dd07ad3bee28308e47d08ea0788f7ca0ecd846689c8027a
+
+Count = 283
+Adata = 2de4291068a5d290b599a73c6a8ecff4f9fd6c9cc48f14c233e18581
+Payload = 0c5d7055bbfbd2bc213cfbbafa763b71b1fde6f4de96fa59
+CT = f253458b33b89706cf0655955fce6da3f697e1ed33aee82cd081f66b1c7b70718dc50367c3da6792
+
+Count = 284
+Adata = dedeb714f555575fcedbd9de8171484090e6466dd4fba3c6b7c42eae
+Payload = b5654edcc8f09e4f80d0258c9376d7c53fb68f78d333b18b
+CT = 4b6b7b0240b3dbf56eea8ba336ce811778dc88613e0ba3fece672883438da186741e6c542b3f805d
+
+Count = 285
+Adata = 03d340904ace1cd52d4b72a96d96afd77aee68ac3936415005ed0d56
+Payload = d796f3409a7eeb896c3d4ebef46e9c6e553aab28b1cc4a90
+CT = 2998c69e123dae338207e09151d6cabc1250ac315cf458e5cf58d4a5552bc8ed1b1dda46703a256e
+
+Count = 286
+Adata = c67f9aa8cf1be3b4377c30c175d33ab2af390982c6a015d99209acdd
+Payload = e4dd279a79a381c68de777df941a4779e50a1381c8aa9122
+CT = 1ad31244f1e0c47c63ddd9f031a211aba260149825928357f95cf2b57e06de4d01bbb6c0e39f37e1
+
+Count = 287
+Adata = fef1b2ccd661b9fac85ba005addebdf8317ab104920549d3a490a21a
+Payload = bbf0c267d952aeb6f810601b9cf1962a92dcaba7273e6902
+CT = 45fef7b95111eb0c162ace343949c0f8d5b6acbeca067b777589cd12984286af98908db88920323c
+
+Count = 288
+Adata = 693fae7af84aa397f0b2baaed9b3c7953f75e7424c49b6349c2fc20f
+Payload = e8b13a263e0c4fb5645e500e88ab8074ab7d92e5a8dac6aa
+CT = 16bf0ff8b64f0a0f8a64fe212d13d6a6ec1795fc45e2d4dfee8fc441da990dd92c0caeac9d956699
+
+Count = 289
+Adata = 85e5df4ddec99f0bea14b3338b2eb190ab6584f5253c6c2ee3064637
+Payload = 067de2869333ed22c7b63ed7eeba1301bbac69b0d430adb5
+CT = f873d7581b70a898298c90f84b0245d3fcc66ea93908bfc0d502f5434bea8c3c13ad5422ff90e218
+
+[Alen = 29]
+
+Key = 948882c3667caa81c9b900996e3d591e6fcb3d08333eeb29911e9c6338710c17
+Nonce = 43b0aca2f0a9030f90559fa6d3
+
+Count = 290
+Adata = a516ca8405e5c8854e667921b5c5e1968bdd052915b55ac9984b7eefb3
+Payload = 8b9130b0c3c15366831bbb19f377e3209a8dbf7619cd09bd
+CT = 4646b2acdeb11174171da23999cd54e297daa32bbc13d30512e57c576b315f48c11877178389aaa0
+
+Count = 291
+Adata = db3121ea71294983b185207a9d8de3e484a66c0431bf07c962eb82977c
+Payload = 7f369bbc99b6f08049eeb43566269a174829d4dddb05cb9b
+CT = b2e119a084c6b292dde8ad150c9c2dd5457ec8807edb112366775e693f93af6575dccc7903538065
+
+Count = 292
+Adata = 1651cf38fd9b2da65ebb4922b97dcb861128eeefa060d6c1c94b25eb4e
+Payload = fd0900b5fa72e2fba43d611bad25de40a3507a5cc5d186c7
+CT = 30de82a9e702a0e9303b783bc79f6982ae076601600f5c7fb70d8de40c2068de96a274d3b5086b5a
+
+Count = 293
+Adata = af87b347b59e37a424004a00907dcbcf6a554e6782a9be12cb3047625e
+Payload = 36318d80c02a1da41ef1652d9a752e155526b5f597fba226
+CT = fbe60f9cdd5a5fb68af77c0df0cf99d75871a9a83225789ee7da096d2fb28f20f64a000fe93e96e2
+
+Count = 294
+Adata = 0680d5bacefa2ab14aa12b0e517a1432862d4215dc72dc4d5ac6b96c1c
+Payload = 7a29aa2994d11215ab3ef3382b3db6ed581164a235c4b1d1
+CT = b7fe283589a150073f38ea184187012f554678ff901a6b69b88748a2de31261534cdb2237565bf8a
+
+Count = 295
+Adata = 9af701f0a9de52309267289bd170fb97c03c131c0a169d736137ff3d74
+Payload = 3542fbe0f59a6d5f3abf619b7d58b199f7caff0205093f8b
+CT = f89579fce8ea2f4daeb978bb17e2065bfa9de35fa0d7e5330c003eb65ceedc98ae4e38ef341ee47d
+
+Count = 296
+Adata = dab7845fb7ead205569475753c7e26540c09d3a74312f2de25181511f8
+Payload = 83c15520d9541c86b3dd809ede42de22bbb2b75ff18a023b
+CT = 4e16d73cc4245e9427db99beb4f869e0b6e5ab025454d8835c2fb596d8ff6a863604cd224fa3be42
+
+Count = 297
+Adata = a844d6dbd05545ecc736994dc9fc2260c5ab63ed6ffdc40b915f8744a1
+Payload = 793a188fa3efa32f41d6e4c5b42353b95024117d546c79ca
+CT = b4ed9a93be9fe13dd5d0fde5de99e47b5d730d20f1b2a3722ac782e2cd8ecb06172eef2cb9b0e331
+
+Count = 298
+Adata = f9112503884615c0e8a1d8414724b0d19298988f393a27c436b2b6734c
+Payload = 6b237444fb0e1f4150701546c4cb24021c5edad30d9b31dd
+CT = a6f4f658e67e5d53c4760c66ae7193c01109c68ea845eb65f814492b42571033f4dffc0282ea2f51
+
+Count = 299
+Adata = d633a5a3defdde6a68f959ef39a91c6ea6e13ef1a7859d2c2c94d3a5b4
+Payload = 6342312e8a72f71f2e5afe04cfcde4d60a41556111752103
+CT = ae95b3329702b50dba5ce724a57753140716493cb4abfbbb75999099df2de6e436bd99f0341423f4
+
+[Alen = 30]
+
+Key = 3bf52cc5ee86b9a0190f390a5c0366a560b557000dbe5115fd9ee11630a62769
+Nonce = f9fbd02f28ecc929d369182752
+
+Count = 300
+Adata = ebf0b3e3199a5c3773c761c725c7600add5f9d8321c9f8e5e5fd1c7a5d2f
+Payload = 094b538110495e938b08cf748a6bcf3e0c80ff9c66570237
+CT = 4d8b53016fc8bc9677184c0fa15bbd3d671b9366d82ecb67f8562eadcdcbcdbad1299bea1523f5d2
+
+Count = 301
+Adata = a865b88d512e485ab3f2844c29e6dde0cf1151efa9ad3b3021d06fffb74b
+Payload = 23edddd8732cdbf03af08162f0e4a24c9222bdbb4549c663
+CT = 672ddd580cad39f5c6e00219dbd4d04ff9b9d141fb300f3359ff77cf0962455b3539dbf91f3077cc
+
+Count = 302
+Adata = 16918dbc785d94a8f1720c5ad234dde860219874c9fb076a5c290903f85b
+Payload = 1798286c37c1504fc0d7402681f6f70711ef506dcc3e29d0
+CT = 535828ec4840b24a3cc7c35daac685047a743c977247e0806dbed76d94c90595b49d50c84c3efc76
+
+Count = 303
+Adata = a2969243b0955402ab45a430fef2ef9e0c025006732bf8e592e3d3884918
+Payload = 0d02778f90a164a4f9ada9dc7fd24eeb941069621418ef32
+CT = 49c2770fef2086a105bd2aa754e23ce8ff8b0598aa61266248fbe60c146056e5cb01268403e4b9f5
+
+Count = 304
+Adata = 2de5222a0609f058f60e9e581b6e4f0ddebed84fc8302c8e985d17b89241
+Payload = b0c3858231e284af6d231f043b95772f5e7b16a34ffcd2ec
+CT = f40385024e6366aa91339c7f10a5052c35e07a59f1851bbcacff35df1ec942b43eef5aef980cb038
+
+Count = 305
+Adata = 3fc7453df038a92829dc103d44b63ad097d7cd7f9ae7996547012090c7c4
+Payload = 319f396cc02834f8e69d65f77496d0eb31ce1a7b7e324820
+CT = 755f39ecbfa9d6fd1a8de68c5fa6a2e85a557681c04b817091a93f5fc28e5f4f351cfb888da763dc
+
+Count = 306
+Adata = 18f1e92bd3c4a597ed970911d03a78ff9a6790147c9bb0ca5f23b70cce7a
+Payload = 25550c03f8fa02b3781330f96e0fdc58681b0c0bc5e83fe9
+CT = 61950c83877be0b68403b382453fae5b038060f17b91f6b92c6a90ef2e9a969ec0576fae1d126a85
+
+Count = 307
+Adata = 09ecb2406054716418ff3600c3c5cacb0845a377a2d80542abc36ec81bb1
+Payload = 210ff7975e08388b9a46eb732230e3a3856a497549b5eb49
+CT = 65cff7172189da8e66566808090091a0eef1258ff7cc221959fd6aeb047200907911621e8756b45f
+
+Count = 308
+Adata = 62d515bb0525b565a6a3613ae20343c8da7424c8368e8cad6a862b7d37a5
+Payload = 5d867265965bb2aafebb0691de9e157a24066d06fe3cbd7c
+CT = 194672e5e9da50af02ab85eaf5ae67794f9d01fc4045742cc4db6d5fd910c83fd77aefba3f7665d8
+
+Count = 309
+Adata = 00617ca141e55b045a188e4934caf6db63d4577f634db92c22010e1cbf1e
+Payload = 396b27afd16a1081f37bbc1f742b549f5f68df799b93083f
+CT = 7dab272faeebf2840f6b3f645f1b269c34f3b38325eac16fdf5f21f32cbe5d272004f1c104cbcae9
+
+[Alen = 31]
+
+Key = e45bb1730d0d539aab3805350ac986540de9f0f6c239ee70395c291397b70309
+Nonce = d5c7824af715bb7822b6b340fe
+
+Count = 310
+Adata = 860f4a09ad8b3d345c2aa18ffb803f0bc3b734a4d047a1437701a5e3d95288
+Payload = bc8b3bc48c7a88c9fafde258b6ccaa9d4f0d018703d63871
+CT = 95f083ad6bbaee6ab540fe023858f8baf25e333fd3e89c00e678a392d228b210dc5c991905dacf3f
+
+Count = 311
+Adata = 8a84b57915bdbe7bf5a1c1a426512b3c178d883251cc46c95a8bbc8ed9e56b
+Payload = 9499ea48edab9bc21b91dd614f04934ca20db8630622f481
+CT = bde252210a6bfd61542cc13bc190c16b1f5e8adbd61c50f010fbdd3b305522dae6b652322d89d9ac
+
+Count = 312
+Adata = ed8540f7ce451c522c1ff5d2d1030d7b3fbd1219a21aaa84044c4f23c08f5d
+Payload = 73843a4e9e7937fed24bb1fae15822213b1aa86c07f1b5d1
+CT = 5aff822779b9515d9df6ada06fcc700686499ad4d7cf11a08b6b08548e794eaf85ad9f5de80b1c00
+
+Count = 313
+Adata = 61bb196b212feab645f05a8aa1986f6210a384c15bc749245d840b3565fb36
+Payload = a8e24266e5981b2ed14213a29f961cbbf7f02f63a33c987e
+CT = 8199fa0f02587d8d9eff0ff811024e9c4aa31ddb73023c0fcc73643a7ee9291e15137d7046a92f3f
+
+Count = 314
+Adata = a49c2df94ba65107f375ce1c53b72406143f6bcd270945de5b7811682fe361
+Payload = 3e3c402caeca41687d12897102e04312edf7b8c7d8567a22
+CT = 1747f845490a27cb32af952b8c74113550a48a7f0868de53204438662ea82f423a69c6e4e3c0623a
+
+Count = 315
+Adata = 7c48480e9bc87ba299e03899698b2259eef150ee0f2efff40a5583b80ab484
+Payload = cfa9292b9052ac6bb863205d3c0dc2d9e20d2ba6a680d2ed
+CT = e6d291427792cac8f7de3c07b29990fe5f5e191e76be769c6ea00b9cd881e3f4b1e838dfa31f6560
+
+Count = 316
+Adata = 5cf9744090366d828b477dc890eab8ebebd44f6aeaa5b101291bf67d12867e
+Payload = e0fe4e139ab0deb4fdf2145b719f35c50b869e6cb20608b5
+CT = c985f67a7d70b817b24f0801ff0b67e2b6d5acd46238acc4c59b3b87d722a58cd1de58f3963d12b3
+
+Count = 317
+Adata = 761d74be5fae170a1bdfa16081b44c1e49972e15ce0818df1390bf7204f619
+Payload = 665fdcdf55a1231e9912562eaa5a5011d69f6948e29e3f8f
+CT = 4f2464b6b26145bdd6af4a7424ce02366bcc5bf032a09bfe158759886124f1f0ce8147c94f4e7114
+
+Count = 318
+Adata = 9815353b69d0b4effa52cefff13703fa71a6296f9cca0f02568661be4b64cb
+Payload = 7b2d52a5186d912cf6b83ace7740ceda3f5f443530c5a49f
+CT = 5256eaccffadf78fb9052694f9d49cfd820c768de0fb00ee6310a79c9932456dbc00515b264f3168
+
+Count = 319
+Adata = 69dd1a050c8d79dafbbe3403af4dc1f070b9b2b980888aa796e6cff68d9060
+Payload = 3cea5ff50167c5641066852fd00061df35b1f66bedb894b7
+CT = 1591e79ce6a7a3c75fdb99755e9433f888e2c4d33d8630c6da7e97f9984a7db3b93aefb4316d9acb
+
+[Alen = 32]
+
+Key = 2e6e34070caf1b8820ed39edfa83459abe1c15a1827f1c39f7ac316c4c27910f
+Nonce = c49ccef869bb86d21932cb443b
+
+Count = 320
+Adata = d37e35d7cdccd9824a1ae4c787819735e4af798a3beb49d4705336d6496853ad
+Payload = 771a7baa9cf83aa253349f6475d5e74dba4525307b022ba7
+CT = eebac2475004970071dfa2cfb855c4e78b1add8dcbccfc0bd6b14027324b657a56263df148665393
+
+Count = 321
+Adata = ab22bc22bf2628b0e0ab245c3db2fc5128d13a011c2cc9b9fea05a79a3410704
+Payload = dad95a4b4d3754613f0542caa62cfe4e375dfbdd369ec32e
+CT = 4379e3a681cbf9c31dee7f616bacdde40602036086501482a8c810b6944815fd2e434193520b1d5b
+
+Count = 322
+Adata = c48c5aacf701137fc40fd0d3649641aaa5be427ceee702cf7ddf6408f458a581
+Payload = 3f28df9263e473be648fabad163aa4142b633388b16d8392
+CT = a688667faf18de1c46649606dbba87be1a3ccb3501a3543e8aa447b79284c588bef50b423de97908
+
+Count = 323
+Adata = 477c2484cf5c56b813313927be8387b1024f995e98fc87f1029091c01424bdc2
+Payload = f83107b50a1f192ed45cc43fa80e6b519bfd859173ea9ee9
+CT = 6191be58c6e3b48cf6b7f994658e48fbaaa27d2cc3244945d4f4a413eb3ac2c474134995d4db9a16
+
+Count = 324
+Adata = 143bc037f1d0bd4ec16825c58cb3796bf8989200d27bda9beabbbc49247f59f7
+Payload = dfeb324ba459ec4a5c54d2534e98002412e67db19cfc66bb
+CT = 464b8ba668a541e87ebfeff88318238e23b9850c2c32b11756a3fb2e06734b28fbd57942a609d914
+
+Count = 325
+Adata = ffc416f1dae4e43c1a01339a604c44d6a0f25ab9ca3978c6aacb6d270d510ee6
+Payload = 0765949e6f22c422ebd47dc1ed73f1b849d7a058a1656fc2
+CT = 9ec52d73a3de6980c93f406a20f3d212788858e511abb86edb94280d3c4a1cd8cb00705f60ae36f2
+
+Count = 326
+Adata = 6090b596b4082ec6926576137f6561cf13916860ad1cfc43650d1b5142a12041
+Payload = 6db320cbe76bc5b8cee9ef89aca11765571c6c501993195a
+CT = f41399262b97681aec02d222612134cf664394eda95dcef612caca26cc3bbb289da3be0616b3445f
+
+Count = 327
+Adata = 178ba75adb7c5bea6769270bb3b4f6ce208d4a786913d3ced7bb4090b5f65544
+Payload = 0875020959ed969cfb38636d1d5aabce9658b00171a7614e
+CT = 91d5bbe495113b3ed9d35ec6d0da8864a70748bcc169b6e26cc8c665289d907628eb0e299c2d411e
+
+Count = 328
+Adata = 90f0474dca998916075b1b1428df14d90be05491bb8d5d88e32e65ec890ba9d3
+Payload = 4f89ca6ad371f86a6e073ec12fb1b928bb10d6639233b918
+CT = d62973871f8d55c84cec036ae2319a828a4f2ede22fd6eb4f7e481607a2a0529f9cda1d5903325b7
+
+Count = 329
+Adata = 5ad8dd40ecdce52d5b30424ca0bccb666f34f66b0c9a4c1260051ac04ca06aab
+Payload = fe2009d0a4a1711b83057b948cd0b174a3a042fd97579ab8
+CT = 6780b03d685ddcb9a1ee463f415092de92ffba4027994d140a1b9ba2bfe5bf778b859f0ff0c29a67
diff --git a/lib/crypto/test/crypto_SUITE_data/VNT128.rsp b/lib/crypto/test/crypto_SUITE_data/VNT128.rsp
new file mode 100644
index 0000000000..b796541cf5
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/VNT128.rsp
@@ -0,0 +1,456 @@
+# CAVS 11.0
+# "CCM-VNT" information
+# AES Keylen: 128
+# Generated on Tue Mar 15 08:09:25 2011
+
+Alen = 32
+Plen = 24
+Tlen = 16
+
+[Nlen = 7]
+
+Key = c0425ed20cd28fda67a2bcc0ab342a49
+
+Count = 0
+Nonce = 37667f334dce90
+Adata = 0b3e8d9785c74c8f41ea257d4d87495ffbbb335542b12e0d62bb177ec7a164d9
+Payload = 4f065a23eeca6b18d118e1de4d7e5ca1a7c0e556d786d407
+CT = 768fccdf4898bca099e33c3d40565497dec22dd6e33dcf4384d71be8565c21a455db45816da8158c
+
+Count = 1
+Nonce = f7a5098b2a4d92
+Adata = bc498326755503ff25d02805eb3517221b54eb4fd79af0fcdf9312b2a9ad95f7
+Payload = 3e2144e2a381b718962a77e167778bf579957a8fae29612c
+CT = 98ce91033fabaa8fe853d347be6cbe5de102fdccf042e7be697b41c9a69acaf8386140ee6e36f406
+
+Count = 2
+Nonce = 732d2dd64b4a25
+Adata = 495b03df82e317e4f351c5323d17c673f4c77856983179d7c7cb75c2b0573c72
+Payload = 4bb0d170bdcc70fd18f19605cf9c6181082c4367f1e6fbce
+CT = 9bd9304259962448fa8487bc15d950303621213afd88f1e32d442ff663242fa269c4a742a220edc5
+
+Count = 3
+Nonce = fefd3ac595428f
+Adata = 91ffb6be8e129cef9189f7e0fec8e937afcfc6083b6a79a778a724bb3e8d0794
+Payload = 9e8c4f1292e8d7e5179b34ae5d2ba2491d7754acc54bb91d
+CT = a5d012b3062cc93b831860d76539169c88854b85550c67fc564a2f1cb7d77e0223287740d5ff9003
+
+Count = 4
+Nonce = e14d81ee3b873a
+Adata = ecdc5249ceb48e8d5a4483043921c00c1acb1843fae00155a28f3a127150b1c4
+Payload = f99e23288e6b5ae85c14610994d90d5fcbcab62b4ed1333e
+CT = cc4ee711d0202deb58664e00cf0cf70b737f48ddadcefd6cd217fb611daeb66fa2d8e1bd43cb2131
+
+Count = 5
+Nonce = 2cbeaba94dbbd1
+Adata = d129674c6c91c1c89f4408139afe187026b8114893d0f172f16469b183fee97e
+Payload = 1b42cb685bd462fbd40e0273a81c767aa81cb43f17d3c0c9
+CT = 1a1b1c7130aa63098dea17ffbb2216d1d276cb10145b0762a45116736e95d823e579d73dc31dc487
+
+Count = 6
+Nonce = 8a961df9c23f6d
+Adata = 07185502bf6d275c84e3ac4f5f77c3d4b30d8e106603be84410c11849a3c18ea
+Payload = 434e182d04ecda519a6119fbaa4c45e8c9803a9a3eb51dae
+CT = 3f603939c6226d8208b2b0e675b82557609ceaeeee4032c7837ed517dbd7e6fe34ea42b01c69d370
+
+Count = 7
+Nonce = d3604d390faab3
+Adata = c95e7329d36145664da69d25f24b301d334e1bca2baa74b2d5c325ed7d04fae4
+Payload = ee104be898a225eb1da99163bbf768d8ae6d5850af6f8767
+CT = 3e6a7683d9d804f791f77d2b69996102ba82477ec4557747ef2e0b322f51abb366a1e8e37f4fe4ee
+
+Count = 8
+Nonce = db5004a1cdae8e
+Adata = 1370fc9d5bf1ad2d071be5a28b235402a85270f536b5601c221519a3b329c71a
+Payload = 59bee7d18fd4ba573f3e4f61076f5b9f6a3487e47d98c729
+CT = 6db54d6f5c3f3efa6da67aea1234d46e8b679a5c257c66d82e4ef944778281ed186b4a8099b47fff
+
+Count = 9
+Nonce = 783477f981ef05
+Adata = 04bbf2a826bdf3d55069b1936c4f8e8e08189f54066a035c950c7347604b1b65
+Payload = 6150f132b25727ebbaed9f16bd91ebce00c68e5b39bc0ef9
+CT = 36f78cef22cacaf9f3d4464821737f7fbacd79be517b4727bc5c098625c51ac7fdd15da2cc9ef4b6
+
+[Nlen = 8]
+
+Key = 0b6256bd328a4cda2510d527c0f73ed4
+
+Count = 10
+Nonce = 21fd9011d6d9484a
+Adata = 66ff35c4f86ad7755b149e14e299034763023e7384f4af8c35277d2c7e1a7de2
+Payload = 78a292662b8e05abc2d44fbefd0840795e7493028015d9f2
+CT = 5a0be834c57b59d47a4590d8d19a1206d3c06e937a9b57f74034d9fdb43c3f48932aa72177b23bf6
+
+Count = 11
+Nonce = 97f940d7c1230bd8
+Adata = 78337ddfe38be7897372b0f805603a9a9e55598452285764641c3bb7aeb54a3c
+Payload = 772aeff60eb3adf5a9589ad54dda0401cc9765589609dbd3
+CT = ef5c408dc6d0b501925a47def54d8deb9880a07a3e6380bca20a3995cf25c5a7b9477d8916adff73
+
+Count = 12
+Nonce = acfdf302ed116ac4
+Adata = fe9d9989bffae3c9e6161eb0aa9d54ee8f5051f0dcabb5a750c5478c11798ce1
+Payload = 99ffe16de323a9b65fe60305a2d062cae490ccca6d9fe9da
+CT = 1bbc2c7877d845591660636cb6ccf4edcd4c156996a26a707d0e2fe322f203c08f44d7f9bd7258c3
+
+Count = 13
+Nonce = c8d36e13b7459c47
+Adata = 3f3c3a4c26dba18f385274ac5ac3df73282686488d91bc8190b7f61071b07f62
+Payload = 316ee95430329f706348886b8ac7779e3056809e25da0a03
+CT = fd2db9611a26a3e90f4861467df60edcc595f442332b089905fdd72307c3355b19ea66d4a16ef17d
+
+Count = 14
+Nonce = 5822755a3e47c27d
+Adata = 1d72d6b371e85ca359483761704f80b3360f4d6610e6d5e490b0d509f73c3233
+Payload = af4ae8f19cf6cbd199677fe033859f56906f1979b1b5926d
+CT = d5ed6f8d5c42f4f3ea527094173b278724a2ba787e416ad759124db19ab1373a5376f46ec7095ef4
+
+Count = 15
+Nonce = 6c1c94c2e71b865b
+Adata = 298cac1e4684182786f386ef3de79c11e30b2dab7579b8ca18d0312200860403
+Payload = 6e4d992d7541e02a4aa167e56c7e47206abc25fea6c5125d
+CT = 560cd43a502a6e8b1af478a3b640a68937d1a83057110d38eaa52d69ab9790edc384b9a5d8c91dbf
+
+Count = 16
+Nonce = ce7ec65cfeda31da
+Adata = 13c1298cbf7fe6a9ab378f86d3c2207944cc2a232f9383513ceb3b202086d365
+Payload = 196c80d02b663bdd89fdaa31e329b5a8f7c596236ee8dd80
+CT = 00174dd83a7f8edc71afbe5da095160336be9184f693db3db1f45de395e021c6fb1b2991c91bd643
+
+Count = 17
+Nonce = ddb739acda6c56ec
+Adata = 7f89bbe513b9a7ebe9be3f6eb88782080593c83e8cbe47fbe15bdc3e5782090f
+Payload = e95e142217c838d1f998a52e342e4f2d80b1cfd35cf6b73d
+CT = 819d73dadaf095652cf39729b2e2cad7fc7783887a5acc15713d941b845d96a5bf65e9f80ae7f923
+
+Count = 18
+Nonce = d9bb71ad90152d5c
+Adata = 20bfcba120cdbeb07c5f4d70338ffce493822d78a03c9e80b5b934e16e39f70e
+Payload = f1fe98b50ea2f9f088f6f93910757cf744d5aabf3081966d
+CT = 36decda8ade6ab104a201c6d370412b907a559738eef59665e99761cb1ac77d772b9cce9345d9a75
+
+Count = 19
+Nonce = 2c9ec9f1f1358c50
+Adata = 96f0b1edec4ad14407dcaf30ed68942b46c48d58b2dd63af60fccd5bdd48e560
+Payload = d74badb8ad7f2c2bcdf67e497151d35a4fc2a3c4c871868a
+CT = 0e9066270da6e03cb4307c43adc71b4b596213a63fc8032085ce60506ac3bd97327904ad2e072a6a
+
+[Nlen = 9]
+
+Key = afdccc84f257cb768b7ad735edbd1990
+
+Count = 20
+Nonce = b7776aa998f4d1189b
+Adata = 9f9ac464de508b98e789243fdb32db458538f8a291ed93ddf8aeaacfbfc371aa
+Payload = 56d0942490e546798f30d3c60ad4e3e110fc04f5b1c1fa83
+CT = 96f124c74fd737819008ddef440320f4a3733d0062c83c893e259aecf12ba08f2a2e966a3341d6d4
+
+Count = 21
+Nonce = 278cf1f09b13f467fe
+Adata = af9627922758a9f7792345716782e8837ca78e8f9db16e3fe12a7124a3d4e99d
+Payload = aa9b9e80cef47b6db3816b1d665f233e696337e21bb8333a
+CT = 5eba7e3b3ecab78121b0d56acb9dbfc6756c1255b42f145d11751638ed36c1fd3c7268b71633c1cf
+
+Count = 22
+Nonce = 4ae701103c63deca5b
+Adata = 5872a1507c833c581ac2750b2b54add4b92be14e45d72db7679f8fa2b4d1eeeb
+Payload = e832b053854fbd40c0d8b6d6b8fd5de2da0c173f5fe594ef
+CT = 3b2b964c3a90d51c0ace186db79818b4d0f7b81236d36017d3635aa1d8167087600b01643b0a5ce5
+
+Count = 23
+Nonce = cfb5b12928e1c36849
+Adata = febe755bb8e4475d8d12f5e96269abd0d4e40d73cb966e2c523343e9a6d2d71a
+Payload = f46d6970dcc37d32d93ff062e68034c1906ee487fd28eefa
+CT = 0d5332a42fc583f4f81744b899cdf2a64cad1e78d577112fee6f8c4b252e10b42fbaf8c7af1e9f3e
+
+Count = 24
+Nonce = 68d5863cafc69e6ceb
+Adata = 048ba28abb191ded5449dfe9dc7d19f9b132a2a9fd779aab7da44d2887485954
+Payload = dd4438d7ba3edc73872e42dbbf78cf300fe4bf0eac9e16b6
+CT = 874d3ef7f916db2c2799b6892ef4bfbeb4729ecbf26ac4983a8639f21f8548fae45dc76de57bcee0
+
+Count = 25
+Nonce = ea09fbe5da0fa4fe91
+Adata = 63ee18eb720b21ee4c157dafcb8c7bcc6817f54d5c1b8dd7058c37228a03f8ad
+Payload = c1811d613bf0789beeef693611ef733cd173da703b66ab3c
+CT = cbe5c799952b28fadf414607a6cf8194e9f41194abace4541d3853a52971b0ab46cc0a3eded435c1
+
+Count = 26
+Nonce = 0021be18ed76b3a34c
+Adata = bb5eded483f0ae1106fd08c5e2b91cf06d3a7a73518ad4c479fb05e631ba5399
+Payload = 2d5531d1c51c6ea100b028596bf9f24dd90be14eab58f07b
+CT = 7af0449f7359b7f3e5f6c1e7bc264c7724037f4f16077fd0a2a8e3cfb827c7e6edabb34f7bbafd01
+
+Count = 27
+Nonce = 449b51ee0760179e35
+Adata = e99bdf783070a3a48431704e90277ca65a9704c12eeae2e2d70b62f816115267
+Payload = c4896d58442877c986e4f862a9f3a3179f0e9b96316a90d8
+CT = af7531c073df01077fd5c8ea9a5530c2fe1688d529e5c2f24aa8feae6a500919a336dbba1d9fb7e9
+
+Count = 28
+Nonce = 232114642e0c6b55b5
+Adata = da288d2014616f16a2abf5923dea49aded1748592adbcd97415c33ebfa57150d
+Payload = 11fd3f94b5a5ce94f2740a27a0771aeeac77f3155d2bc12c
+CT = f0c174a7927da0bb88e92917af8ae1df4ffc3527004e9e2d0b25cea7ed6e4fe9069a2ce49875230d
+
+Count = 29
+Nonce = 660cb6d654afcbdab4
+Adata = bd96c3c225099fc58cc1f97779304606b11efe9712fba13abf74fc1d7d44a900
+Payload = 793c0bc3deb6e0bec4c1d1fc17e455eb1aa5e9e25cada861
+CT = fa4b14a381ee41fec7b7279e58f0d06a3beec26d645f81336218635754d5563f2cd48bdbb267e5ca
+
+[Nlen = 10]
+
+Key = 6ccb68d3838d4ddf660b9cd904cad40f
+
+Count = 30
+Nonce = c4fb7519a19f13d9d1fc
+Adata = 092e64fef08b5655a86cdb8de63ffaa7772e8730844e9016141af8bad2216246
+Payload = 5ea35c082e2b190e9d98e6b2daad8672f587b4f2968072fc
+CT = cda5fe3d15d00150b99120c7f206b88a4c2c4a39ca9143425603ab284a73a38cc916f8b653c92ab4
+
+Count = 31
+Nonce = 45927852550961f1ae9e
+Adata = 53ae030474795ffda4d9ac0fc3c45afb592ddd761f7b5335c13a6747e21075a7
+Payload = 6c5f468077536b4c9a94ea4a6fe3cf621083a210daee45b6
+CT = 694847b6429cbc3902d9cb7049625aef1e97b569e1e3169035bb811491d142cf1b26350f8451bd14
+
+Count = 32
+Nonce = d8c54463dfcf02d0e327
+Adata = ff95c0ed0da32d1b5f57570b815a50592ecdc9c1c4e727e0f6dfd93fc10ce88d
+Payload = 7321a6de8d694ea05623206f5df438c5c2cdd6b1eccab4d8
+CT = 9cf8ef119aa5cf3d6305d50b2b520a0b10bcd240e27276749c68e8e641b0120f7dd66e8f0cfa4205
+
+Count = 33
+Nonce = f690f3a996928275050b
+Adata = 41c05fda535770699ed22cef253753b658437f833afe65c9c393581d835f0fea
+Payload = 56520a4bfd7b73a471e0446f9524a407e81c2681b7329e35
+CT = 14aa15f9f64c4c64f6e88094e012ecb24193249f044c033dda44a62f97c0fead3f65b28928bfbcc3
+
+Count = 34
+Nonce = 26eb9ef25be62148fa61
+Adata = 8f45608a07521de86ed5a84a851e629b579b51d7bf4cc7202a773e0f9e9d8748
+Payload = c68094c26c7f017b79f126dc26b3bbcb95f97535ca412da5
+CT = 7ba8a0c2fe2b230768d1c1874085ddff8926931961bc4558f0d5444466bcc631bef8e58fe5818af7
+
+Count = 35
+Nonce = fad21bc27dabafe7a4ae
+Adata = dc5d7fd97bb3243ba585fa0d71a07191667af418e30a6b76bedd05b32c673403
+Payload = c247fa8d8091cd3f299cdacba7fb7af93549e9e3160f9cf8
+CT = 3097d2ec0f8bf00b22504ab03a75e740d3e59c269c3ee3f00b5419293a67eb008aef0f9f675201df
+
+Count = 36
+Nonce = c911348848fe67406dea
+Adata = 50d50a0b5ed4d6904ec3045263af0255a6494b7a7e2e95ea806c4bb788423dc1
+Payload = d846c170ae0111348362901503b26d58f5efc17b6d296aba
+CT = 5d72562f7dfb47bf34b90ee4ea11ff9f726c915b07f4d843dec5a554f4bbecbf6943ffdab8d8a26a
+
+Count = 37
+Nonce = bb921b46a16d20ae4046
+Adata = 7d17f8f60ad1e61a168b5b0e7fbbc90cee79b612b6d6c0d7ff6ede042341e8a1
+Payload = 71bb6ae84262646c9be95e0f4289ffeab7555ec6746c6ae9
+CT = bac123320888b553666249756e6d63b3498760791cbe9e34e5b1162b7489a59a50c0f0f3618e6c2e
+
+Count = 38
+Nonce = 61a8b8cbfc9bdbadb2a3
+Adata = 51cf2a8949e13eaa087a34c9ec4d7fd92b862efd6a0b1fef8b016fa2c6933426
+Payload = 362f9a46aab59fb6213c83d791b2129b34367ac2de2048fb
+CT = b8a57e8714d8789f4ef2af29e0efec21b1ef67fdabc7cdf0ed5505f1f0ff77723771338585c456b7
+
+Count = 39
+Nonce = 6bc4cd23c32a913998a7
+Adata = 92fbc970b5e64198ce2a138de92767edff8d82f12f8832444b346d159657356b
+Payload = fa442383da234cf8f0c5fb667218bc3bea0c091b3a8e6b77
+CT = cdfe3e83aba43a9804c5a1832e0e47a9a153359cc32db907714025f485c7f40256049f16f859b859
+
+[Nlen = 11]
+
+Key = e6ab9e70a4fb51b01c2e262233e64c0d
+
+Count = 40
+Nonce = 74e689eb5af9441dd690a6
+Adata = 42f6518ee0fbe42f28e13b4bb2eb60517b37c9744394d9143393a879c3e107c7
+Payload = ba15916733550d7aa82b2f6b117cd3f54c83ddc16cd0288a
+CT = dcc151443288f35d39ed8fae6f0ce1d1eb656f4f7fd65c0b16f322ce85d7c54e71ac560fd4da9651
+
+Count = 41
+Nonce = eb118fb41284bfcb1bc338
+Adata = b5a6067fbac46578cfc8d3fe04108588c9de077eb009249374f205553bba9d02
+Payload = 863da00c7accf45418d47c1eda72338734dcc49cd599f328
+CT = d64de7a56146b971e21bf5784d67bab32dd837cfb81591da4a0177883346dc896eb39e8a32bc1393
+
+Count = 42
+Nonce = caba2716d07e95de83855e
+Adata = 0e0ff2c73ea5fa8f8726a3514cf906ce1610a1a6dc19b22682f9e4619f762d82
+Payload = 2af6d5636ab65db2058b2ba16df257369fc4e8aef8b9481c
+CT = 3c9e006c7d8eff5f448b0cc9c27c964713241aa7fed3665d775ea25fb272981de8b8aa0a637498fb
+
+Count = 43
+Nonce = 314c136999e41d137bd7ba
+Adata = 366c659bc45d0a88acd54ef7eeaa3e140e1cafb1b01474a065a9d460c5e83bfd
+Payload = 217b19ea6a431a1f66bd9d02b718e8507a08ab8e6f603e3f
+CT = 33d7b672b23e8b03a39ff3fd1e7b0f2be67163e3e3bae072f2aaa211dec623947a50b1252bc5aad3
+
+Count = 44
+Nonce = 6fe51f5013f53d4e4fd907
+Adata = ff182f2e179d790e827cbfd0bd8b9297ecae57ffcef9e25ef114474a22e4ec5b
+Payload = c6bf582b49dd4ab6cb33f3f88e8a4d14fe32b308ee3b4682
+CT = 26cd5dc5eac2acda283ca03354260ad57af79e20c5e92f5775ed171bb0fbaa6f431c5411cf9b536d
+
+Count = 45
+Nonce = 24bc8dc1e2354667b79ba4
+Adata = d0d48d01fc79685c6bee04d45e40d06cdf1f4607542b1ece556fc2d1bb2b03f1
+Payload = 90f52ebb1bd5439386faeaa194623285f750672a7baae64b
+CT = a7f43f56c50705a1a101044b954414fdfbe32b518e934d38f391749ea3acd624c01e4583ab1506b7
+
+Count = 46
+Nonce = 89ce46b3de3afaf2518d41
+Adata = 5767202c913584d653f37d926a0c5ac1c67db3efd1dc58fbff998778a6856254
+Payload = b2ab379a0dd15baf91415eee3a4e56e7eca54d4c1c3094f8
+CT = 9f530e455a54b86835eacd8801b34c884a3b2ac819ba38f894e43a6b1cf73cb2d6a1dd8331549520
+
+Count = 47
+Nonce = d3208eb695e84c7a925037
+Adata = 91d8fa65a6885f162a795afe2898f391990a8b3a87c11f94734dcbddf5f58da8
+Payload = f15e39f0e4eaa5bf81359d8e30186522f1a1a415436668cf
+CT = 7f1d9fcd9e5cce3a81e3495bfecec817fd7180d8bbfe0abab27fb6425fcc3537ce471425a5b17dcf
+
+Count = 48
+Nonce = 067de2869333ed22c7b63e
+Adata = c31e441fd551b3fdfbe23ceec5ec1f838f31a5300f6055ad2a936a9d0c1c856e
+Payload = 1536d9c9a09302d142c85638202f5bbf0c287f68115d51d8
+CT = b1a5c7a7fd23228dc7ea26885802daa0719f6a23681e1d65dfb879c21b46f3307ef22f1da579303f
+
+Count = 49
+Nonce = 15f61b4526d19bceae1093
+Adata = b97b122af73e928e617e98684f845be4cb80566345739b7a884c6a3eec5102bf
+Payload = 37c81988c07a5b01e2b40ff9f9ada5f50ca764efb717ff9e
+CT = 0d93a5c77482d573b7f1b8c5e283f2571efc9f54216a4c01900504a73c8817ff2b55618b2602bf38
+
+[Nlen = 12]
+
+Key = 005e8f4d8e0cbf4e1ceeb5d87a275848
+
+Count = 50
+Nonce = 0ec3ac452b547b9062aac8fa
+Adata = 2f1821aa57e5278ffd33c17d46615b77363149dbc98470413f6543a6b749f2ca
+Payload = b6f345204526439daf84998f380dcfb4b4167c959c04ff65
+CT = 9575e16f35da3c88a19c26a7b762044f4d7bbbafeff05d754829e2a7752fa3a14890972884b511d8
+
+Count = 51
+Nonce = 472711261a9262bef077c0b7
+Adata = 17c87889a2652636bcf712d111c86b9d68d64d18d531928030a5ec97c59931a4
+Payload = 9d63df773b3799e361c5328d44bbb12f4154747ecf7cc667
+CT = 53323b82d7a754d82cebf0d4bc930ef06d11e162c5c027c4715a641834bbb75bb6572ca5a45c3183
+
+Count = 52
+Nonce = 6a7b80b6738ff0a23ad58fb2
+Adata = 26c12e5cdfe225a5be56d7a8aaf9fd4eb327d2f29c2ebc7396022f884f33ce54
+Payload = ba1978d58492c7f827cafef87d00f1a137f3f05a2dedb14d
+CT = aa1d9eacabdcdd0f54681653ac44042a3dd47e338d15604e86a0e926daf21d17b359253d0d5d5d00
+
+Count = 53
+Nonce = d8e133e7ff8e0a0ec6c4096e
+Adata = ef9e432c15d8c93a4b5c0666608e61c824cd466d7940d642acd3dc33057c0395
+Payload = 2836de99c0f641cd55e89f5af76638947b8227377ef88bfb
+CT = 5edb056d85dafeaaf74bdf4caa47339d6a75bf1ee998565e9f9cdf6ab825f6e026f5be2ad895033e
+
+Count = 54
+Nonce = 2fa8120398d1a946f391367c
+Adata = 377cd407ad28dc02bd3835a31d92f8295c9dbe597f56662ceda112c588dc73a5
+Payload = 7a37255b682766a0bfecf78e5162528885a339174c2a4932
+CT = 701f5f506fc7e9ea4a27a4db5cb890f7be3b4f6bcb20f97ed3021f6ad620648b8196ab1693710398
+
+Count = 55
+Nonce = 8d638ef43f56dece910139e9
+Adata = 87ea7b095388de70ac0ed23e86f502400910028a8ab5e3bbb91d05821c0d2d61
+Payload = 7370d9b453936955b9c9d336f4b283237986232de007bf41
+CT = be2f03f6ce1731418a5f53b6f6e467b73992a0c8102d8ffc2d236162688096d80b8733d2afbcd244
+
+Count = 56
+Nonce = f479ea8812b6b2f6ac78fe9d
+Adata = 20c2b8f5d3a65a66ba8a25e2ee339a779a32d45f5db91077efae6cf308feef50
+Payload = 59ff9f7581a781808d36fed378080963f35c00ea5a6e3932
+CT = d127c956349c16e2186f55b72254c677f03c61f1c4ada9e661bb9415b32d6a58f5f7647ed41de685
+
+Count = 57
+Nonce = 423515f7bd592d6a7a240866
+Adata = 19eef6f798fc68086aad1cda6d7976cdcfe6b8af74598032972c939db300d8c1
+Payload = 3c379f90b11c622a765756a15efc8fc3ca7b08b3281945f5
+CT = 15792e01fc17f5294c3405484291082c00a8f46dd9af8ca230ba95c4058501234a1b97543c998e9d
+
+Count = 58
+Nonce = c3f3da69e13c5733039744b1
+Adata = eedf00aab5edefdd6549d37ed44358e11c588c24f141dc5731303fe0bd56b11e
+Payload = 9db6fe9adb8c0fee87cac9a7f01a7ed8a84f0512d09b1834
+CT = 9b6b829ca1dc4e90d4402188632ea3377cbec2ba60f0f072afca1b08b6dd589a17a32d49b6f7135b
+
+Count = 59
+Nonce = 0a57d59f21ead5b6d80cd2ce
+Adata = de5f2d413c98c6ea2a5640a7b1c424aebe75cbc78b06710b5bff8bec6afb5a76
+Payload = 0b5f6389f7c20f4ba326e8f05d373ca27b7ebe59e6d729f0
+CT = 0b704e14bc7d2977d89e0b2e7ed7fe3c9e0f2ea80d2d6165f344f2f1b2218d9b4283fe640a6d315b
+
+[Nlen = 13]
+
+Key = ac87fef3b76e725d66d905625a387e82
+
+Count = 60
+Nonce = 61bf06b9fa5a450d094f3ddcb5
+Adata = 0245484bcd987787fe97fda6c8ffb6e7058d7b8f7064f27514afaac4048767fd
+Payload = 959403e0771c21a416bd03f3898390e90d0a0899f69f9552
+CT = cabf8aa613d5357aa3e70173d43f1f202b628a61d18e8b572eb66bb8213a515aa61e5f0945cd57f4
+
+Count = 61
+Nonce = 2a27257bfaadf23a87df082c57
+Adata = 0001dc666c9daf3560daeaf514270db0b5075d295068e6caf231c1de0e1a9300
+Payload = 6cbbfa6d736fbcc4cf73ab4d7be537420e0e574ee1f2d1b5
+CT = 72d525e6bb312bf2c20b91f41108779789c25720797ebffa4cd9d735f51430275387c565cf1a69bc
+
+Count = 62
+Nonce = b94ac8ed14895c80a91fda8367
+Adata = e1eaf35fb266f243a3fa407cd41815ae6432ad79877bfa59d8f196cbf19bfbb2
+Payload = e6ec561496ce18d96b26d594a47ffad02d68ef25d2d2edb9
+CT = c63500445239bbdf71a8dfe3f8c01061d659cfeb038b825dc89fb5f507f5aeefaa9365f0b18dcb3c
+
+Count = 63
+Nonce = bbae10aa491ac9c668a3ba8d7a
+Adata = 981fc31e64fbad244ba1ef0303ba1e4beef5bacca74f60ffdb9142a25a1ad5a3
+Payload = b9bec3e2adc83620772048d6cbfb6f78e4fad74d754ffbbb
+CT = 9c629c375f014e162895cfc25a972c29839f97407e7c7cca83d0a61d453d596fbc5c2e315d9780bf
+
+Count = 64
+Nonce = e0b10e78e9fb41ee970143e9e3
+Adata = 399b71ecb41f4590abda79045cdf6495f27daaa559c1b34f513b5c4ac105ec10
+Payload = 4b81804d777a59b6a107cf3c99c9d1a35bd8e4ed36596789
+CT = 867799b30558697d6efb4afcfe458cfad8da21139a0b43128e8f8e13b7896b244d0c9aa52ed31a95
+
+Count = 65
+Nonce = 17b61109f5e37754e4e92a28d7
+Adata = 0bc2fdd890c19882640f8d4188b88b9db99cc1934cc3e98a5df08589287968a6
+Payload = 347c1eb4aff917bc0012f005e74caadc93f4f18f2b614ece
+CT = ee19f3120991b67b2389e6f36543d99590f2e6d785c9c8ecc40eb85585cc3b7520a940a4e993327d
+
+Count = 66
+Nonce = db3ca9e80ab761804349379961
+Adata = ce01369d08d37dcda2c899c9fc0d11ccf94a0051b2816a1d6c3ad07fc8dd02d7
+Payload = f0e1af1276d2918be91a191814660bfe735463d3983de1ed
+CT = 0f1b1228729b181772d7cf55ad257fbcb19cd46f7b31a885401358c7b44aea27617b429583103a1a
+
+Count = 67
+Nonce = 1f57959cecbd377374477e33b3
+Adata = de1c7c83ac61e1f99ae99b198f4af5d24f8de60ea98fe637f3a801fab38b2a4b
+Payload = 42a42b84df098ceb43519c4cb86c14c2fafca39346159e13
+CT = 12425453de653d0fe8103013fde1ebf4a8fe18f76f0c9d60e93525fe8048c3b2147a149f12eaecd3
+
+Count = 68
+Nonce = c9db03e2efbab713b0b6404210
+Adata = a2969243b0955402ab45a430fef2ef9e0c025006732bf8e592e3d3884918696a
+Payload = d633a5a3defdde6a68f959ef39a91c6ea6e13ef1a7859d2c
+CT = 5cdc183c32b4c1878eb83e8473a17c55c88e2ad6b944ab1f64ddee42614aa737231207636c114575
+
+Count = 69
+Nonce = 89ed296a3ac03fbfb71422b921
+Adata = 1ffbe1aff0a1e7fa3e68be31a74612a1519b59397e7007ef61fc015f316d55b5
+Payload = bff42516e30c92ed46710013c656600406a48a84c1fa32ce
+CT = e08c1ab4ae7edb5184c30ffb3e74689ea855f50b0e890392f26b130720f75c422fdf66fb174383b5
diff --git a/lib/crypto/test/crypto_SUITE_data/VNT192.rsp b/lib/crypto/test/crypto_SUITE_data/VNT192.rsp
new file mode 100644
index 0000000000..06e9ff5655
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/VNT192.rsp
@@ -0,0 +1,456 @@
+# CAVS 11.0
+# "CCM-VNT" information
+# AES Keylen: 192
+# Generated on Tue Mar 15 08:09:25 2011
+
+Alen = 32
+Plen = 24
+Tlen = 16
+
+[Nlen = 7]
+
+Key = ceb009aea4454451feadf0e6b36f45555dd04723baa448e8
+
+Count = 0
+Nonce = 764043c49460b7
+Adata = 6e80dd7f1badf3a1c9ab25c75f10bde78c23fa0eb8f9aaa53adefbf4cbf78fe4
+Payload = c8d275f919e17d7fe69c2a1f58939dfe4d403791b5df1310
+CT = 8a0f3d8229e48e7487fd95a28ad392c80b3681d4fbc7bbfd2dd6ef1c45d4ccb723dc074414db506d
+
+Count = 1
+Nonce = 026a0b8b17be95
+Adata = 44caa8ecfaf38e5e773cb0366e1b04aa0b9fac5c34a362310f471960c4a1e1c9
+Payload = 0e52a384cedcdf7f179348de6e7336aa86f8855fbd903cfa
+CT = 3417044bad5fddd9455579123dda4fd342c273a57ff6333dfedf191496d88cbe17c6271b65096e66
+
+Count = 2
+Nonce = ea09fbe5da0fa4
+Adata = 1d9799f2bb0f7ab57fe3de27949ff64066131c81bfee172b308f9bb0b3171067
+Payload = 469ff9698cfc96b581d7115c822e4363d7355ec5daed2eae
+CT = 1dae7cc16f1b469290902cfad47b959784b4d6f48a79e690d47e30b635d10d1663477d61d7ffb55d
+
+Count = 3
+Nonce = 8d27bcbf9ebfd3
+Adata = a7070b85b7add9193c9dcd2e6c03f6e7ecc52ffe9e099866baf7472f20c03aab
+Payload = 225651d072dc9d93762dd79691ac2b6ddba00ec1252d69eb
+CT = 5da819adefbf794612eb458519debcd524c283763eb3d7252eca8766bdf0db6bb2dcc793e1749c21
+
+Count = 4
+Nonce = 13f560187b6077
+Adata = c4ab4244db75f8256e55c5b613a07b11c963c3cc24f66128aad4ba8b7ca99331
+Payload = a38231af405dc7b70c8dbc8cb84e6be8a0dc2e95fddc2ce8
+CT = 3aedcf8347aa23fd3325ce08b6b00462536baed69968a753feab6761c55431bb5668e1f5b7505e89
+
+Count = 5
+Nonce = 61e0e28bf344a9
+Adata = 5f998952de70449ad46428f2ff8a01c5af43c0107a1bcc6930f19d4112598666
+Payload = db21b37e875d7709a02239ce6ea529cf37255d5b617c153d
+CT = b8f5fed39c723d7643d6dcf2efd3bbd1ba0da1ec901305fd64b2302ace4f66216ca8b4d776197692
+
+Count = 6
+Nonce = f6be4aad63d33a
+Adata = 18339be863fb8a887d04ae9ff3b4a7db095075cd5d113a9ec87b41fe85ea405e
+Payload = e53101e6eabcda32c13d7b1dd1d88e7c2ca3ddc2064f64c6
+CT = b758858ab60e1630a0883d4d330119a593729a3015c42525effb985b9c2dd9ec954bd25d9c464c67
+
+Count = 7
+Nonce = 2c1c59aa0d8eff
+Adata = d44af86b89fda8448a9b2fcae20ea156dd8738c8251699c02b785811c830bf72
+Payload = 1fd7188a43dee7b059420e8634d71d2c0658f6d0d308dc73
+CT = d046f845a67800a5a58f461e5a8641e8fc9b4c53b32e61d172adafffbacb297d67f6b5c02b982e04
+
+Count = 8
+Nonce = 48e4598edd191e
+Adata = 61588bdc980ea2310e87dec4c651e9a55c27e3858b6505cbf3bf85e51931badc
+Payload = c25868f390af5e59c035cb5830e018c62c5b96bd35b764f1
+CT = 0ece161bd77b7f969b3b20c818769a98c178d84524544664500ff4cfe66ade1832babc019778acc3
+
+Count = 9
+Nonce = 6d576ce3c5fcb5
+Adata = 92c598cb5ca2926c11f67c3b3cf25493d77606fa60d7290430e0e975091644a6
+Payload = bcd97479db934357a163a9e5f5a85999ca987f8243d8017b
+CT = bee185e11b3d42bac846b9d92c70a078aebfa630ab763840391031b3a22b2adeb9791ee35765c8cc
+
+[Nlen = 8]
+
+Key = 1dd56442fa09a42890b1b4274b950770ea8beea2e048193d
+
+Count = 10
+Nonce = ad749d596d88a4b4
+Adata = c67219909828adef64422286008e1e306867a1c0b3da95444507a68b45c953e4
+Payload = bd92d6744cde446fc8621625658fc4bc00dcb97f06195ad7
+CT = 076cffd0ca978fe2bad411ced45a090abafb22a99896f6a75a1969276aa2b0cdb37ccaf2845dbf6e
+
+Count = 11
+Nonce = b1dc81d116d94f5e
+Adata = aa4b71906b6642f10f66c2391ec157c7cde97eb322db10045af4c5248807f691
+Payload = 9aa6dbe1cd3eb98d330c937d31ef93bee8938b6c5cfd38de
+CT = 720f6876ac91665f20147483f0655fdbe21963a01e36f1daa67e36d7cc8d54cfec0762514475127b
+
+Count = 12
+Nonce = e758738df5c89af3
+Adata = 5715fa238f432c926e62dd93708d0e3145428e0ed45e1efa8148d2c4ab6cba50
+Payload = ce80b99039a16e69018d1e3c239dd1bf06e94a78b0b1df37
+CT = acdf7ba3edca1563727ed85cabf085c2f0c8f27556c3c064ef50d85bc3ade6a773d956b2660ac367
+
+Count = 13
+Nonce = d586c4c67d535476
+Adata = 1e8dc63c6c54a540b6b02067ba7c719221cf289fa3897299722c9a2bd6eed05b
+Payload = 2f88305117f9a5d807d54b7e95ecfeb7327e52d9acac352f
+CT = e42b86e619be1a38973c934babeb4688243a9012c85d643d81e024aaf0a62b353f9bed36681288d2
+
+Count = 14
+Nonce = 77e83758f68d272b
+Adata = 25c80edef3d5bd8b049fa731215b80ca2ee9ee6fb051326e8c6d0b9e11e3d7ef
+Payload = 92e47b82b728d639777d5d5843de2a5c364956cb4b21cabd
+CT = 1b9177f5b76403cb8c690b39c3dd22b55da35cebccb9b64e05fe32f796f0b4a75a459fce6c7d740c
+
+Count = 15
+Nonce = 311dc245549206cd
+Adata = 87767f13bb4904d0df0d64eb22c9ddb65e81b5739baad86ad5e2c239ffde9f6c
+Payload = 8691c0301a216a5f3ed9123886d100309bd85630d6b845f5
+CT = f39fe3620a03b37a4bf457909e0770447b498ad2a2f0f9d7b75f9e4239e43bbf93066897e60f6fbe
+
+Count = 16
+Nonce = 2a17b70f10e120c0
+Adata = 981fc31e64fbad244ba1ef0303ba1e4beef5bacca74f60ffdb9142a25a1ad5a3
+Payload = b9bec3e2adc83620772048d6cbfb6f78e4fad74d754ffbbb
+CT = 92187955ee1ae702ef01a385537119b2bd4545402e8b2384a0c069a2439a2d8843302c6a9999e658
+
+Count = 17
+Nonce = e0b10e78e9fb41ee
+Adata = 9d072b8a3f1a496b2be6728a38b94a4f44c9be40c8793b69afd81d01696a6b4a
+Payload = cea28e7cd0eff0c5eafeec908d4aa8ba303e72ada33db087
+CT = c605e48f2e66e8e0a92471e466981ae5e31db3e4ad80b09f5005b06d15f63f2f015cfe447828da09
+
+Count = 18
+Nonce = 02d72dde23f9772c
+Adata = 2dc44c39940e2d9c94d2dbe40bbf5cca5efb4d4b250a31aa24f208b87e9c2453
+Payload = 809343e986f6ff47f54d4cac22ed39babd12271d4c7edb58
+CT = 0bb59581f22f6b15de76c0066645495a5c19e44381c349263ed92ebb789c314a89c83542b15ed694
+
+Count = 19
+Nonce = 28c4d6de3e2ce51b
+Adata = 913a8eda924589d3206ce0a951fef93668c6c0c454824b217997bff6b3026d54
+Payload = a19f65ffdafd6ad5ee43570f7e168f94a8b4a7b7402ac80b
+CT = f0c91a29f1222b906550ef5c7c0944c5c4236cb6c31122cfada8e796f2ce7f9449f42de504873868
+
+[Nlen = 9]
+
+Key = 8cc622645065c72d0d2aca75802cf1bbbd81096721627c08
+
+Count = 20
+Nonce = cd84acbe9abb6a990a
+Adata = 447b6f36acdad2d1cfd6e9a92f4055ad90142e61f4a19927caea9dbe634d3208
+Payload = 597b3614ff9cd567afd1aad4e5f52cc3fa4ca32b9b213c55
+CT = 2d7fb83e6621eed9073e0386d032c6941bef37b2cf36a4c6c5e36222d17c6fb0631c3f560a3ce4a4
+
+Count = 21
+Nonce = 1fc7a43ed124745d04
+Adata = c892b095173076a40e24522297be27fd3a765c8d417f24c71a9f03b3fe3d8e20
+Payload = 415cd8312dd20a1c26f4b90d98104cdfbe06739466fc0aa5
+CT = 7bebd6f55f15ae57ab73f92f7be6ff37ddd99740e988f01a7a2a13c22df4a156e6d6063235452c85
+
+Count = 22
+Nonce = 19ff5e7c1f2c594abc
+Adata = effcea4e4dbc57410426b39fcf51c9daecd9d310888590d77827973a29c4ebff
+Payload = 97fd2c259a4e672e9555a9a5b98f4c0ec8c4c49c7ade26a4
+CT = a460674c2f358762e97dfc958d90973e1e419dbc6a832e987579b2c4a6bcf0356f48cf8959cfa54a
+
+Count = 23
+Nonce = 64d9bd368ac2357cf2
+Adata = 62c5a16f946b4312517f67c80afe2614c822e3a01b87dc81538c00bbf3fc0108
+Payload = b6ada12f7a28211e9d2c07cbb3d39fa77aadc077b34c46f9
+CT = 8fb5e0954388b9b58519482962487e9b0768f0cee08afe9a92be2b06a0ecd2d00877abded7d9634c
+
+Count = 24
+Nonce = b4aaf2cd93efc0ce93
+Adata = 79d8841ab83279724ce35e1a8abd4e158168dcf388ab4c3d1ae70413e4e43d14
+Payload = dd42449da4c95e858b796085b6b5b3b5eef484dbf3c2bc8b
+CT = 893f86e29972928c1f3c3e25c73947c8d677814bca7fff2cf8d301ceace678f9bf91fc361dff5812
+
+Count = 25
+Nonce = 132f3e19e12f462a74
+Adata = 176cc5a280f6171d00e247edacc81f05c1b9faa87fc831163ac9d76aae59a6c3
+Payload = 8ea05a5033ab8b009664fa2800c24e217488ce6888cad147
+CT = 4771d210ea678dbfab96e320e9c44b68f47cb05b01826ccf42ca4f4ccf986eb6a6b85b99db2fcd93
+
+Count = 26
+Nonce = de709ba64cb75704c0
+Adata = 0cf8e9ab95766b6fa85e88d86e4f349a17c0d90509939e343eede988e7462255
+Payload = 51dd9fda9549f25dd868245a6a54b8d59346d2f336adf9af
+CT = fccc3e44afa6bd2fbcfc5c834db63dc9d152c04c0dc0b43d393162252ae91ca46fb8e8338cbeb75d
+
+Count = 27
+Nonce = b11b4c1b7a26387265
+Adata = 14ed867cc909c0619f366918a7d5ae25279fb137e1dee7fd98ddbe3bd19d841d
+Payload = e35ea4a16e274fcab457fd4dc7886c3d81fc668c19e0f374
+CT = dcca8aa2eab8ac3f5db9cd9560ae0758d7df40d7d868d1f71f498ea6ec8251a6d149c7ca38b25fe4
+
+Count = 28
+Nonce = 20d03227a7fcaef1ce
+Adata = c5c15245e641687d0ca9e913406acd2de3f21fbaf2dc5e4e8963222da61d02a6
+Payload = 6775e5faffd0b13e78da70a789042245d5ef31eab5245380
+CT = 4bb8ed2207f36f40f62d3a2c90f8e3bd8f589059b69037118ce3ab864545ea81943ef0ea9489d223
+
+Count = 29
+Nonce = 267f76b9ec0f5e7c6f
+Adata = 2b421be47d07dcb12a0706f7490d05024fce8f433079e18ec78f4c8678f5f155
+Payload = 9330bb23428ab45f573923e977db74882282cbe1371da68e
+CT = c6ae24f82ac5cf9c18a2d98e610027eb2566a1ccfcf99945655e14c7bc8be97ea47388cb7b18bcf0
+
+[Nlen = 10]
+
+Key = ab72eef2aba30205c986e2052d6e2c67881d24ae5fceaa8f
+
+Count = 30
+Nonce = d7a46e726ed43f1580eb
+Adata = baa86f14271b2be7dbb37ddc7c95ce4857e57aa94624d594d7bd6ceeaada8d5f
+Payload = 2a794b84fc9e4a7e6d70a82b5141fd132177a86b4e8fc13a
+CT = 2d7f76464417613bb61d3657481346b74fc9d6abc6a3babd39365dce86859cd82395d11bfc8cf188
+
+Count = 31
+Nonce = d0afcbc1b2524a4a4553
+Adata = 7c267223047af946b06f6a45ffde4a5ec49c28b81ca22da4a36bf523e89e9da8
+Payload = bfc5ce1316ccdbcd8ac62484e7656c87947ff98cbba8e1e9
+CT = 4772c121367d0e8d3edade883342395f3ea065fe7dd7be8c8355b915ca2633fd557ca7ed41e00926
+
+Count = 32
+Nonce = 6eecffd227e8d5349523
+Adata = df7736560b1a13aa8e536500ea6cdb9a6757309aadf25a6a9189055a309c3f8b
+Payload = 19eef017100dc82f26ed0815c55c122e0b1587302894c391
+CT = e2864c6e12ac089daaa1e94af4b2ed04060d7ef65d2f72f0e7d017514d498f1f3c07d650afde8293
+
+Count = 33
+Nonce = a67c0675753f725a8fd4
+Adata = 7dd546397a9a0129861fb6815d419a307f90d259d55f3503961754126cd1b776
+Payload = 80f1f1ea46c92d28f2d60eab39ce056a4aefe63fa688538e
+CT = 882c687c03eaaad9d7f591649e736f0c1c78f95e40d40cd77499a8544bc2a8fe95f55fefc7316f8d
+
+Count = 34
+Nonce = eb83928f0d5f7aa3a74f
+Adata = 060cd3e4aecdb03837dfa9f544318c0a16cdc37fa2a3135be7888ac67e7eb26b
+Payload = 81e9174e9472777b6b184707108c01d6ea6b5d108ec3c6c8
+CT = 243cfa0a0a36a4c20333968910e6f52acc04c6f74e704180623f3a13fc13db958cbac49f7421d6af
+
+Count = 35
+Nonce = 5757abe01f7a1183fdcf
+Adata = 744629263041f0eccfce4a1ebcc18c4c984010f9241d35966263a8b2f72ee26b
+Payload = 991049f26b529af8b0bee0cc83989cf817d248254182f332
+CT = b20469b5f33f0996e8de869ad10ce09924a0bdd7b67a89a09c447a3132fbe5213133650000d50b06
+
+Count = 36
+Nonce = d9adfc5b44ad7aa94b05
+Adata = aa6a5448c6ec87be75eca35725ad2e902dbccf840d25b2bdf7e62e4a8fa4a511
+Payload = 14682301a99bf680805d1ffe62e1506d48cee8c51ef1d255
+CT = 9b44efa185b0c10325bb4c3c0815e6a6e46eea366b9a416b5ae554cb440eadd875657fd5cecc214a
+
+Count = 37
+Nonce = dc3ca30782c9c0a7fe89
+Adata = e788c98ae85b11b3ae884eed6f3b8f5bcf5ab1b7b20ad3f44f760b2287cc5793
+Payload = f9cb86f24536931a1b095b426a07e4621c000cf09b472bf8
+CT = 463f9124d1cc387a0f8b971d1e2da448f0efffc3956ebb2af8312986315522081f0989838ef0429b
+
+Count = 38
+Nonce = 9523f53f92b6e4ba86e5
+Adata = c3b123ccc916d26a2e6a8b5e30041ad69a944217e9b402b7acc0170c31e8c2e4
+Payload = b9bdcac80f64175836ab51bb1a1bee5ffe3a6b9b71afe3ef
+CT = c356b5a78cebd123808fb740754dc47a8ec7c9448bfacf39768e94f062e86129cc9210dfcd3e6128
+
+Count = 39
+Nonce = 16bdf18c09d60f3a2a32
+Adata = eedd0796f23612749e9fd282c864f3118d0683409d3bef1fda352e1422273c7e
+Payload = cc96133e473d197be1bafdfc1a21d58e57d0d89b2ba1c3ff
+CT = f9d78e9e3a41b3bcbfe756385a3715776eb84bb7d8d15432978757883f07802b25e9a5b15c43b451
+
+[Nlen = 11]
+
+Key = af84c6f302c59aeee6d5728ed5da2e3c64a5a781c52c4d1b
+
+Count = 40
+Nonce = df990c42a268950677c433
+Adata = a6ab5d78427f297a4b7e21f1091ff3a5b20caa3fe1cbcb09459d9df596a6c8e1
+Payload = 6db41aeb5f7c24df8929dbc30483b3c7934b3bd1cdce5bb9
+CT = 8c9328258bf71970d33e23a3ff81cc1c9cbe196a1294264bfd6a7255e4801963bb30a63de3fc5b82
+
+Count = 41
+Nonce = b7ea72641bbe2dca6d85e7
+Adata = 4e0f2ddf183281ec131693bdcea3fc9743733c07a486a42d5737735b3f6e3fdf
+Payload = 726844e41b1e4d883024b32fee0dcea38c889cb328885b7c
+CT = 9a133e4582c2ebc445862a9c6f2f4e39223c84081e322c8f262de30da6ef505fe640c53d765f672c
+
+Count = 42
+Nonce = 446fee1e75e79c0dfc9ddc
+Adata = 42b598eaee271e06d9e98dd94152b28ef10f506d65bd660b2fb8b1be9a2d7254
+Payload = 0cdcf348ecc9c3588001802c2106fb64be9c301adcc66e73
+CT = 0c2657b0482b6ca92e1b1c8fdf75eae3b0cd3af205e9bca396ecb1e46beb16000d585e1d9559ee22
+
+Count = 43
+Nonce = 2e6e34070caf1b8820ed39
+Adata = 8bd1ef3a1831fcc8919d736fb23111ca3ef4cccaf20264fab8eb3b071e56667f
+Payload = ca0860cc1e96506c2beb25b53d2947fbab634f0372afc8ba
+CT = 19e4774030e43e6853ab5bf176ba9c4b59f29f285977e3c15198cbe3e34c884c3f56a732974aa1d6
+
+Count = 44
+Nonce = 428542ecfb94a745980aa6
+Adata = 8efe01716b9018084e2ea7616f85b7333d945c0c970f8cdd400130b98db67cda
+Payload = bc6b59120ba2845b0e41f65a55e2ef1c45a81485c926c14c
+CT = cb48b0af6fad251d409d14ce0fbfae9cd9c40bf4a0c1e2b7e7cec415030997e1ac5db974b617b5a7
+
+Count = 45
+Nonce = eff703e6d72ddd23ff52d9
+Adata = d7fc74035e66709d2590b7bb3276245dd43824c9896fbd801ec1d07018b39b6b
+Payload = 1a5432e8085511ddac1be91be3e2945f85f0cdcc3a1c9f8d
+CT = c0a00cbaec65b7ca525fb26e80ee0cd18c7ef47c39c704833e59bfecf263bfdb24686627fd95e120
+
+Count = 46
+Nonce = 6a652ce21334a40a259dcf
+Adata = 5d24d80f22afe713c4076c200c1bab36917907fde7b6d34e141066f543526db6
+Payload = eb8f1988cb405041bf48d138ad41da7ef364d4ac59a9e324
+CT = d4f23166c09a15466c7e0e2b30627ee5a84f22d7e6135b4a0652b67d559a84b4a915ca6a420fd300
+
+Count = 47
+Nonce = 9382e12d447c0ca23cc9c3
+Adata = 239129eb760f8a770410c160e4e13a6b9497077c3e463b65397393fcd3cb5c70
+Payload = b40e80564263c7f450c53ef84df67247d72e8a04dbb284bc
+CT = 6de2ba26caa80874814816154784912c55e3d6da83488e7250f5a52f82211542b4e2661cf870c80c
+
+Count = 48
+Nonce = 2c3a4148cbb02504a2483f
+Adata = 33c3bdbf185b580353de79e51e675b03b31e195f19ba1f063d44def0441dc528
+Payload = 60a31736d99c3dcf25b349f6110e1c152b93506e85a01e67
+CT = 4d5e705d08f3ed1ca6f1caa74b46e4b1eee18a0783686f207de16aaa41d06bc071657dacf14da754
+
+Count = 49
+Nonce = 691cdf6fe9ecc2154d0101
+Adata = dc096596644c4e09c44078b86e5e0887c45094042eb0d74a6a13aa2524463076
+Payload = 77e6441ee017a93dd876ff2c7980540c77ee15edb0f23933
+CT = 24cecc81c8ac7ca9906372dc5263f2220b4dd162f1e08283f07f23e65475a20fd96e45c6c695cd83
+
+[Nlen = 12]
+
+Key = d49b255aed8be1c02eb6d8ae2bac6dcd7901f1f61df3bbf5
+
+Count = 50
+Nonce = 1af29e721c98e81fb6286370
+Adata = 64f8a0eee5487a4958a489ed35f1327e2096542c1bdb2134fb942ca91804c274
+Payload = 062eafb0cd09d26e65108c0f56fcc7a305f31c34e0f3a24c
+CT = 721344e2fd05d2ee50713531052d75e4071103ab0436f65f0af2a663da51bac626c9f4128ba5ec0b
+
+Count = 51
+Nonce = ca650ed993c4010c1b0bd1f2
+Adata = 4efbd225553b541c3f53cabe8a1ac03845b0e846c8616b3ea2cc7d50d344340c
+Payload = fc375d984fa13af4a5a7516f3434365cd9473cd316e8964c
+CT = 5b300c718d5a64f537f6cbb4d212d0f903b547ab4b21af56ef7662525021c5777c2d74ea239a4c44
+
+Count = 52
+Nonce = 318adeb8d8df47878ca59117
+Adata = feccf08d8c3a9be9a2c0f93f888e486b0076e2e9e2fd068c04b2db735cbeb23a
+Payload = 610a52216f47a544ec562117e0741e5f8b2e02bc9bc9122e
+CT = 83f14f6ba09a6e6b50f0d94d7d79376561f891f9a6162d0f8925c37cc35c1c8530b0be4817814a8e
+
+Count = 53
+Nonce = b4cadb5f9cb66415c3a3b714
+Adata = c4384069e09a3d4de2c94e7e6055d8a00394e268398d6ea32914097aec37a1f4
+Payload = 22bade59214fa4b933cb5e3dc5f096e239af4c2f44f582b0
+CT = 2296e3f8a2245224d274f1b90ed1287cbeeb464c70a89ee475ecb546efb8872a3f8b0281b3901752
+
+Count = 54
+Nonce = 72e6cebdaf88205c4e744286
+Adata = feaf010f462ad40a38eefb788b648e1cc292cd4bb08ebeff3c39182862296042
+Payload = 30655a6b5a5965db992e7248d24141055e988d726abb8e72
+CT = 69b27f2bbaa61c4f24e1c25e0779147fef79ec1582486b4651cffa571570618e2ada3376bd9f3e5f
+
+Count = 55
+Nonce = d8030fb31eca2c43f3f5eb88
+Adata = 66704365ddd0145febeb33f68b228a3f09e1e5a4b68149e6e06d886301841295
+Payload = 9d014a02507a6f266bd1ace21b55ab8b73983ff503bb9adb
+CT = 233a883650538ab8c0da30b90527f880fcad5b16bd435e762beeeea7a638c717e63764b3a5118a0c
+
+Count = 56
+Nonce = 58038cc35ad3dcd75195e125
+Adata = 3da7a757e942409a3b39ccdc0669ce6401f7e133c07c4c42e366d70a8e9bdd49
+Payload = eccfd817fa5e3a0146967fae13fc2471ee3944cee37969f4
+CT = 415a36872a04f5b4b5372f63394ab9fb353e0eb9b430450133a87fa29e5fbfa9bc0430b0cac00b7e
+
+Count = 57
+Nonce = acd82ae31bfcabd90af5af45
+Adata = ce22126f01bde16249c47102b4da68ad3edebcd4a16c24a16ea7ccdd5d364d10
+Payload = 9d2126d34963d3ba12cd841bd321036cb82cfb78f2a6535f
+CT = 88a5b889e6fd74fc15336e23374b430988416c7e6b6e7248b336cbbeb64fbebf2e7076a98ecf5bbe
+
+Count = 58
+Nonce = d24457d567fd0a65fdabf219
+Adata = 0091d39f3478d2c59bf874b96db9ce0f7e8b85a9b805e07dc96b219819d51663
+Payload = 6da3ac85505e93c4f391ea367a9e15fa9b388ef7ae2693c1
+CT = 7039a8a49cfa6402b4ba3b840e69200c13ac4a3eb1c709a30ea909047af4998c660afbaf346ed65b
+
+Count = 59
+Nonce = 50c59ca54eb64575b82b13c6
+Adata = 5e4e42cbf172853c351d597c7d6d38b1a9cbb7ac92c00863a80ac4a2d9f0e7fd
+Payload = 25b2ba0a937b71f3ee68e7172cf2c4524b662efcd08ce2b3
+CT = e95fc44287ce39c5ad6b91c88582563fa68a9e304094deb8b193dd767f17783f0b51ac0fb7323301
+
+[Nlen = 13]
+
+Key = 36ad1e3fb630d1b1fbccfd685f44edd8984427b78deae7a9
+
+Count = 60
+Nonce = 3af625df8be9d7685a842f260e
+Adata = 308443033ecd4a814475672b814b7c6d813d0ec2a0caeecbcaba18a2840cdb6c
+Payload = 8b9db1c8f9b4892a5654c85467bcffa2e15e28392c938952
+CT = 6bc6890fee299c712fb8d9df9c141f24ee1572b8f15112c2f8c99ccf2d82788cf613a61d60dae458
+
+Count = 61
+Nonce = 24eaeaa437649e61b706942b8d
+Adata = fff75462f96157d9554bddb6aac156fefd88fd4a90a8536dfc28cc577f19c83a
+Payload = 49ff4ff85f7407ca383cfa4fd7177adb4dab26e642c8186d
+CT = 3647fae50c588d792442f43a20125e77ab5db3c469391d24d0a421bbbc002eb9ac9ad01f625f824b
+
+Count = 62
+Nonce = 7325932d6694aaf61a8204c172
+Adata = be20ceb8ca14e9bef7158b280a26bcac763da79cd0eba9b1833ea808c5e7a66a
+Payload = 2861494eb40b9d964d339797c1b6aac63c6674187768957c
+CT = 286dc74001e2a6000a23db164f4b2912de4afcf1df8c3aa5ee32a7ffd4e7bc303d3482fbac431828
+
+Count = 63
+Nonce = 61c9949df5853e42599e5ee0c7
+Adata = 243d09ceb16755cb58d62065df84890b840ad9b7eec1132c6427cd7c3d843fcc
+Payload = 943a49073db6ae94a88844ed895f8fd99ed25c3f42a2f78c
+CT = d3c56bd265a2cb0811dd218f248800ceade4f02b5403b9635eb30cbec49cbb51c41cd5032b7fd759
+
+Count = 64
+Nonce = 07b6c18dd3b0fd9e8ff026a436
+Adata = e85f141c3d1af7727fcdb00f8e2c34e42a436d04ac5b8ca9f321a178a2056806
+Payload = a18b0a4618063c0519818d113b8e5435aaf153f664058f1b
+CT = 69f933a2a5e774e8d013cbf78c6ab0b73e6ca323d0c52691acb5cf2631987d3d963349b035324aac
+
+Count = 65
+Nonce = 0c075df70630dec2fe81834945
+Adata = f3f5c5ffbfe8247bc0c33c793652f749fe91b6dd141cf0db56e71cef8a2fd266
+Payload = ddc4bac4115e8cb06d29d22e400674dbc615a667f933603d
+CT = 26bdd25c9f204fc7520d26c161464c28fb35e395b295b3db4e239d33283d18415b54c2aad4bde354
+
+Count = 66
+Nonce = 0c2d20375057fcd4241d290f6a
+Adata = 70ff1b9ff8ec08fdb18b0e7dbe01127ed0cfe0b0a449ca2ace4992b7b6248b71
+Payload = dacbdf1979e000d52b573e74800761b30acc26681f372acd
+CT = 6a642c389433a3464fc64783ae6a14a9a45f0998b56a5b9162d7e0320dc930df3640a786d7ea9ae4
+
+Count = 67
+Nonce = ea0801cb3dab853750a922dd25
+Adata = d83360d0896e022bf014bd33710ab212ddedda6d95a54996f33db304e5f12f01
+Payload = 46cc5653bbd8300dfb0df6d0af3fb7c7639a830bdc9f68c7
+CT = f1b0728920351d9edfdbe7df360b21f6cc5b628dcf43a3f10d06b4a545609a2128a95d4d73471559
+
+Count = 68
+Nonce = 97e6de379c90fccf3fa8f27013
+Adata = 539f8eb802bfecaa4fb5b19debbf3d4847db9c4e0473a308ab3f3c859e68fecf
+Payload = 8b013f52a828905013f250fb9c006a173f6c66a64b5ba317
+CT = 556a439bc979dac1cfea8c5b64aa78547f52a62896c19893f3512baf72cd79ba9301194be204bcc0
+
+Count = 69
+Nonce = e832b6330d3e5e190598cb9c61
+Adata = 093be516277e8b197ba5e9c85a831529befff0f3971510ab611dfe0dfb50a2ad
+Payload = 635d2d7894bb816f154210946a369df37ea492993ba23af9
+CT = d8e19c67e5aa7f14a16ecaaac414a2b15a15bb5f966932e6b0bfe9a5857fd36df94aeadda7f83a79
diff --git a/lib/crypto/test/crypto_SUITE_data/VNT256.rsp b/lib/crypto/test/crypto_SUITE_data/VNT256.rsp
new file mode 100644
index 0000000000..2817684910
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/VNT256.rsp
@@ -0,0 +1,456 @@
+# CAVS 11.0
+# "CCM-VNT" information
+# AES Keylen: 256
+# Generated on Tue Mar 15 08:09:25 2011
+
+Alen = 32
+Plen = 24
+Tlen = 16
+
+[Nlen = 7]
+
+Key = 553521a765ab0c3fd203654e9916330e189bdf951feee9b44b10da208fee7acf
+
+Count = 0
+Nonce = aaa23f101647d8
+Adata = a355d4c611812e5f9258d7188b3df8851477094ffc2af2cf0c8670db903fbbe0
+Payload = 644eb34b9a126e437b5e015eea141ca1a88020f2d5d6cc2c
+CT = 27ed90668174ebf8241a3c74b35e1246b6617e4123578f153bdb67062a13ef4e986f5bb3d0bb4307
+
+Count = 1
+Nonce = 195c0b84baacc8
+Adata = c7d9557b2ed415652ce6faa8cff5217ac803530ec902890b31eaaf3eeb0aa98b
+Payload = fe012718481b2c4e1d7f9a7685e3daac43ccf22cad0df900
+CT = 893af0f130f1317de9f217234274b0c04fcc202cea9a0df882c00b5b463654adbf82888099a7d258
+
+Count = 2
+Nonce = 363e0e921c6f11
+Adata = 805678936d4e94746ab4818dc5f50c41e32cf32e7a8aafb300fb91af6406108c
+Payload = 7e7e33e1a07d4e8fde2f33304f21cb564d146860ccfeb49f
+CT = 645cdd11a1c232815ce1e07ca3ea83f372eba46cedafddd980adf2762a1617adfd4d8356bb48aa8a
+
+Count = 3
+Nonce = e323cc866af462
+Adata = 163c747f3ba4ffd68af87f2475f48f2714659a2ec43b9ed115e02fe0e3c8be99
+Payload = 2bfc76f3b108ba3118b07433c4d3d5f41564d22547c12822
+CT = 0db04c6b068e73e3c4d71059bdeee3d27622f99dfd07d868fb9c02753c57fec7e1a5fa8f3860501b
+
+Count = 4
+Nonce = 03ae777078b95d
+Adata = f1dacf9062dff9a6a3d0498f9d058782f891475684196bf2d8e7e905393acff7
+Payload = 38c4275a5f605fd1d99517e13deebf0c9794ef586070fa9a
+CT = df8f524872b5f06f3f219ba76524990b466409894930d7e0d104990e598eabd88cc8342ac16424b5
+
+Count = 5
+Nonce = 1c6c351d4fe9be
+Adata = 14285e97cc3cae452e1a52e2fa0bbe24df96abf2faf6b9779acc59764612eadd
+Payload = 9e2220f3c17532e1ce0d6f562b049fcef35bcaf9a7e196be
+CT = c274b28228a6b13b670c325080f88d188d40d78d385481eae004894b1861db5d2d8ae98ed8926c1e
+
+Count = 6
+Nonce = a121dc27479397
+Adata = 359421e9f78cc4a31f4f019977d7fd29780524e20288798c50002a682a6368b9
+Payload = d42b16b32e77637724144eaddb21ca8d7db4e7f73acbf707
+CT = 56e3e3e59e978161355e7d8573dc0657db400ca0b083dae8ed2ac2cb63e1b9d7dc598634198fe4fc
+
+Count = 7
+Nonce = b1f0e26b60bf1d
+Adata = 2ab4239fffd13762fb5391f5a4760d12d96ea12666a793b4d651e9f4891c22c1
+Payload = 9a2851083ad4e7b915bb0526bb4054e4c0b4adf8626edc90
+CT = 5b2e0215523ff37f0df46e84f996fc9fc779986c766fa51595b8a23ee377d5c2850f4ed95a385253
+
+Count = 8
+Nonce = 50412c6444bcf9
+Adata = 09cdcaa87ddf8bbe6db8411d14bb9064e4a121286cc8a6e97fce1844935f436b
+Payload = b28a5bc814e7f71ae94586b58281ff05a71191c92e45db74
+CT = 05cbc32a6ca797684636dedd16ce65a1eed69bcab1b1bdbd514ef5cbf9991a919fb4974d55506ce1
+
+Count = 9
+Nonce = 225557b0faca3d
+Adata = 21611da060fa90cf7fd68b721caf303307a56e56453326495b628c7dc93cd175
+Payload = e831b739e8eb9f787f63c0bb071ddcc9f44cab8d5b447d23
+CT = a97e0879407eb3b7f93118ca73f17eb34e9f4baf43b07be2e8a3f7b848054cb235e1b58d6a12c5cb
+
+[Nlen = 8]
+
+Key = 472bf7946bce1d3c6f168f4475e5bb3a67d5df2fa01e64bce8bb6e43a6c8b177
+
+Count = 10
+Nonce = 790134a8db83f2da
+Adata = a7a86a4407b7ecebc89434baa65ef173e88bd2dad9899b717ca578867c2d916f
+Payload = 59eb45bbbeb054b0b97334d53580ce03f699ac2a7e490143
+CT = db4961070f528ccd1a5a0681ee4d0ce3515fb890bccedc2dbc00b1d8b2bc393a8d09e87af7811f55
+
+Count = 11
+Nonce = fb2441d1594a488a
+Adata = 0875020959ed969cfb38636d1d5aabce9658b00171a7614ea9e5395331c7659c
+Payload = 451101250ec6f26652249d59dc974b7361d571a8101cdfd3
+CT = 1bca7b0d35a68c0ffc568ffc8221cca738b67b95e3ab26efee21c5738d1f7fddf3030d004a702704
+
+Count = 12
+Nonce = 0855263860043207
+Adata = c7fc24863c33f7e8cf97b337918495d52d864ac570c99cbb09d151758d6b504e
+Payload = 61fcd7ef9bf151b9d8a81dc1ba4f82c45e9c2e4784627acd
+CT = 9b939b6b188e1d0fe016f366fb01eb79a99ef7b1b57c6f7ab223454c57c714d96681cd4d55615afd
+
+Count = 13
+Nonce = 415cd251a5e36943
+Adata = 1a393c7e85fb286709f4eb50f09640e1d65ec1135cb4443820136b3cec69772a
+Payload = 66ae08d494dc9df9b7f8f53199fa37d0c88885458b168c57
+CT = 1731e260ae31b8068ad1099313b167d9e6cbe49f471da61a9af96d3ce4ea94213b60cb69d92050e6
+
+Count = 14
+Nonce = d95bd65242bb2265
+Adata = d0e20e1358be5cc1c45c1cf02c82d0a6d0824cfcb65774cf95f047b9f2cc1d3f
+Payload = 312c3791c64d79205a11eebfc14b2d7a6b00391793c9559b
+CT = c3fbe558ff9ea83ed86b7d66503ee38eee94e4a41fd53f0f627a352d056712e0d44404c61712e2ab
+
+Count = 15
+Nonce = 3f0bf0141dd3ace0
+Adata = 9dd4ed18209dd6cdf19cc76fee443827e7331aaf020960c15d7bbed0f6a3b1f7
+Payload = 08354480047eee3beeb5ab165da17d23f2f1a4ad98720611
+CT = 2db9d2c54134d37ebefcecb9e2076034b975677fde58ef6032645a322fa9bc8aace600f942a84db4
+
+Count = 16
+Nonce = 3fd8b3a3ff563a42
+Adata = e58327efebad3276a7cd1b1ccb56db0caddd02a303cd9fc7ea5c607a2ebefaae
+Payload = d1abd89351384e1a3c3366f77c3175f6390801554d7cd783
+CT = be284dcb357ae99ada7cc891730320ebb32ca627eb8c80623957a2a5b6164218fc83e12c42d5c532
+
+Count = 17
+Nonce = 14db1ffc1c87117f
+Adata = 6c2b091433833a0ed915354dcb70d982095b614dc51a95a22cec417184d8e786
+Payload = 0594307491f157821e63f50c94034f9284f095d5b897153c
+CT = a114c84a10071e359bba2b2ba4ea67f893e27e6ea880aa4b2cf16ce68a93f8839245baebb2278300
+
+Count = 18
+Nonce = 40b0f74ff27a3fc8
+Adata = 3b9e1f4e9b57a6dfb5e0ca7ef601fc6af30a1f8650228e51e0dc61180d0bec6b
+Payload = fc8b7dbceef6b0ffcbade789e09303044042cd671607e819
+CT = d00ef56074a8213740af8b8f974f778db560ac365d6ce916b8d191130e864bcfcd1dec94a1aaeaef
+
+Count = 19
+Nonce = 96cbe9cd19351359
+Adata = cf498fd042f9a07503e490cec4873d4df91162cfde60bd2cbb2b710c6681a9fd
+Payload = 315e81c9ce556dcf97a5b68503fd2228a7a6a174a15cd618
+CT = 7383c2de08bce3f0b7e504dc03d062f44396bcedd2180fd954e6ec9f6ae1e0976ecf04dbee6463c2
+
+[Nlen = 9]
+
+Key = 58ae7965a508e8dd2eda69b5d888a28a1cb3783bad55d59d5b0da87137b72e93
+
+Count = 20
+Nonce = caa3d928d2bf2b7f2c
+Adata = 304678b3ffd3200e33a8912bcb556b3cfec53ca17f70ecba00d359f9f51d3e3b
+Payload = e61bad17640ecff926d0b0238271ee4c9f8e801dd7243e9e
+CT = 7bb1137c14cb4d324a4a8f1115c619ebf74927f0bed60a8d5a9140ff50dc4da375c7d2de80de097f
+
+Count = 21
+Nonce = cf09ca67659a583bb1
+Adata = 5507c4c3107cb446d19975f91207dbf3e2a51d1dcfd7da2f082159dbc3f41547
+Payload = 1887bb0c02500093a30a44b99e137483704b06615d308c6b
+CT = 834d3b2e5f0915c2348c706b4d2ff2717983ab4490edcc63971f02b7122d1e4f78de9c3376520f5a
+
+Count = 22
+Nonce = 97f940d7c1230bd8d2
+Adata = 56be2c9e09b555373d58f6fe2a0ca9b4ddba899addddf12b0fda860ad791773a
+Payload = 5ac67c9bec9b95c54e187a4a6812f5d701c4ac8f847c005b
+CT = 9f372ba1c87a115847cd708aaf5b8a143b6981ffc2c61cefd30ece13481609809b218de04c4e5ed0
+
+Count = 23
+Nonce = 147c7ebb6c92245054
+Adata = f95d64a513a9f3e6c95c9ed27b22fafd7dd10da52636029523142149116aff53
+Payload = 08f199a8d7e3ea821dd3106e8947cd2e9d485342b25a6471
+CT = c438aa6d187643d030dfe4d6b5b578f84838f4dc5c396d700c0986ecd7dab44e5e97db37392a485a
+
+Count = 24
+Nonce = b9bad794d49cdac9b3
+Adata = de9ff2a43f49cdc502cd17a373989bafd13fa6ccff6660557ce05b6295186d47
+Payload = 40d1cd4063750184356a1d7cae1cf1824f552c5d59a62dc1
+CT = 9952b25f4f4f375440cd958456184fe61610381ba92ca48f38dd977042c4d97da84e4effa650799a
+
+Count = 25
+Nonce = bbe054fbef86db3ce7
+Adata = dcec76181e3b872a5a6e79f070354e38866c7f67fc428fbca29ae6d929b1dd7f
+Payload = 5f29808ba74b672a0f82b3b7581dc32478c6e790e2b8c61c
+CT = 4d176f48b09b772dde8adbdaef720aba128a8d38a902847ebf22c81a5d824b4916660be6f9b513e6
+
+Count = 26
+Nonce = 6a35e1a4307f6efc6d
+Adata = af28120505a84a75b0f6b18cc9d8c75c661bf143be29c11d8ede78b9bb98c98a
+Payload = 5e2f601395ec406fcf96785f768162e849f867dca77667ab
+CT = 4e305e26d34711c6aa775f490939cc6560d3cb6905f5b0f5588ace6fc303600abc8e5825cbaedc7c
+
+Count = 27
+Nonce = f6c237fb3cfe95ec84
+Adata = 038f8ed89444784417a9c23bf11e9b436174e6c10959e00faa1704ce2f7f2c7e
+Payload = dfd9cacbf7d73d688447ebab13d2e13f3613652379b386f6
+CT = fb16c17a6b22a8658f446203ad46a48b34808083b271cabb015a1f78abc287bd2a63381ead07c558
+
+Count = 28
+Nonce = 50d024a3e7455d7249
+Adata = 8513365786b7988b208984e11022c15573f978bbdc29e8a7a4745c8a81885a1d
+Payload = 400317786b7df63373ffe541efcee6318cfc95bb673aad3e
+CT = d33b3141fea3a9ebdeb80d1da32dae42680be78471fb3023721f714120162514555b60560afa4256
+
+Count = 29
+Nonce = 02769283d5a06c363c
+Adata = 292c0be3713c6c588cb4e29a1c43b3e6353e33556194e568e800e4e44e8281e0
+Payload = 12ba8eddff1c2a03ddd25bb924ff065a93fd712b2c4f61eb
+CT = b15b1789c323a68568f86f35483bd7e204beff8f318ae14351f5e62b3b923a937e6c307af202fab3
+
+[Nlen = 10]
+
+Key = aecc5e18088bf9fd7b17f089bdd5607b69903b04b726361f8a81e221b1c91891
+
+Count = 30
+Nonce = c527d309ab29ee91c5fc
+Adata = 8f9a73e7bc1c11e2919020ba3a404cbddf861e9e78477218e3be2cd4337b278d
+Payload = d4291c99901345afe29f58912a414a7498f37b44362bdf3c
+CT = 392784a9e0b14bcd37639ec5409d6ead3e75f855e5a92c33ffc040ef3977e0035ce6ea6d157c18d3
+
+Count = 31
+Nonce = eebc31a5813b4fb93b63
+Adata = 9c87ad77953bf8a811e001ddb946eefafbfaa598150e85f0701853fa307d77d6
+Payload = ebcfd71120b0f9a2cccb898e6dfa082998cbe10032de3e61
+CT = e38eaad1e2df77e85e7129a8ce0f82cfc32b0aef79ab651bade65aa17e4dfb0aafe18cf71a72b180
+
+Count = 32
+Nonce = 231b33dc406c9210f59a
+Adata = 38be46d271bf868c198052391f8a2147c663700d9bb25a0caaa36974f18dacea
+Payload = 9032f910347daf661092b5c1f15b5ffed1369b194d9e12f0
+CT = 868b85288828501cf1d06610fec25e8b8a4b437e2e4f5563b7f3b898a2356909784598f8a8916f5a
+
+Count = 33
+Nonce = f2a88c3ebc74e62f24c7
+Adata = 5f495c5da035cabeb77e8aef10e91a05bd5aa414d1a37fa1099af959b26e5403
+Payload = cfe8ee9b475e36058471e2984ae66f6ba1b3cb477b15155e
+CT = 22c16333ac651cd9c183e78aba3e9312fb3b77dd6f9199502788860aae5534cf84979e30c3327d37
+
+Count = 34
+Nonce = 9cbaf1c83ba60b1e90ea
+Adata = 7ef136bd9a5809676abbaa68016d6fc713e34ac4b768a8246b1198c959f43085
+Payload = c3bcb0aaea93893f05eeb6439c8619dec17670a6439e2921
+CT = ebd9fb86563aa8f10062624441336f982c161ce5717d990a599ca6ec1c61a14c37b5902389e47aee
+
+Count = 35
+Nonce = e25322845d87d8a76753
+Adata = 2a89b9f0e56a1cf87dd38ed78028b6286ef8b7141dd2b3c65c5a8e1ed79bf4aa
+Payload = ae622ff9381854f831892c318bae5c003e74b15199bc12c0
+CT = 144c920f0fe278f353d0b053563d907c7589e4f1479d7a93a0604deb3fd9cea2d89987833ff5c2f1
+
+Count = 36
+Nonce = f4d7978fad36223623cc
+Adata = 8671de7e994967f2521d263925e745af9273682d9c08ced07d4a98fc985f68a0
+Payload = ef9b4ff8da108cabc972192ffecd5f96594c6d0871ffa6aa
+CT = ae4948b3bc1e50beb9f5d005871fc0d3dbde295de1c9ec3cbc866ab47bea7a4d0070e52b492fb8f6
+
+Count = 37
+Nonce = 6597ffb9eaad0fd9d830
+Adata = d2967ddf69ef62a9e23c9118dfaa55df92b4116322f1c9275131e3875dc92faa
+Payload = 5015c894b2437ff15c46bca9236830ff4bb057cd5764f027
+CT = 0b1dcb3cb0b4c32f398f3c43eccfe8f4242f33c99a2a2283efcb3dacac25bed0304f227fd5b77b8f
+
+Count = 38
+Nonce = 80e376b87272d99cde28
+Adata = c9cc8f967dff45c05b9345d03813b6e30dace99556f7df75b7120bb6e5f55827
+Payload = 615f657e24129a3e0f119988959608821219ce8354c4be26
+CT = d3e8b8f7ff8faa666ffe2509187fa7befc7412fd4e3bdb06cd2f7494b1fb0a0c6a2184e5c4787fea
+
+Count = 39
+Nonce = 344cce96455541d403f3
+Adata = 748cce18fb40126ce125dbe341fbbc59d2aacc170ed5ef0293b15713c9184a07
+Payload = 828b6a4cd49f499a6e8e8508f9ab35255d8e9fed33ba4d91
+CT = b67e582a74d7f022a16ada2de7ec18caafdefa6b104baf4ed93b6f8c8a1bf72be75976e4ebe6dd1f
+
+[Nlen = 11]
+
+Key = 97bc7482a87ba005475dfa3448f59d4b3f9c4c969d08b39b1b21ef965c0f5125
+
+Count = 40
+Nonce = 0bcf78103ec52d6df28887
+Adata = 049c10f0cb37ae08eae2d0766563b7c5a8454f841c2061a4f71a0a2158ae6ce5
+Payload = b99bf4dc781795fc4d3a8467b06e1665d4e543657f23129f
+CT = 0d3891fa0caac1f7ebe41b480920ffd34d4155064c24f3b17a483163dd8f228d1f20cd4f86cf38fd
+
+Count = 41
+Nonce = ab6374c6b2faefd92fa3d3
+Adata = f19c044023e5cf339203738ee70e76527519763664c06ae00e002a5ba94c32c6
+Payload = a2e5c51f516db01688b64c173bb25645182a005018022ee1
+CT = f70c598df3c64d3527ebb7fc8408b7de2cfaa1da7984ec361f1ad61758d828b70d4881b7d6ae8cd0
+
+Count = 42
+Nonce = cfb89e7ddcba601e875110
+Adata = 052714010da516c896ac5842a839ae845324643cddb080e6206148432d0d0407
+Payload = 037f206cab78a6ca0745dc8fc137e22e14f3d7183917ef83
+CT = ccd675862502a2e2520a33250150b8b7b220e84db854888c316dd62075fc761e2bc80edc5c564bdf
+
+Count = 43
+Nonce = 967cb6f8530bf8a43adb42
+Adata = cf391a84d03e2e22aec1965cec821f99e7bf21a7c3580dffa531464b22d83225
+Payload = caa3d928d2bf2b7f2cd8a7f357055b6d6895a5e34f47972a
+CT = 4f4f509debe6e52eae4af8b1740dde0a5338f78711a3b4ebfc8b5aca6d606222d6af7cfea0d1f4e1
+
+Count = 44
+Nonce = f5b7b5dd2b5e1ec93710c9
+Adata = e7a6b228a67d37b9d29a38efc547e50b4a6d95d599b45ee189ece21101ac6b5b
+Payload = 4a74ff35418723f2cecec1012484b52114067b2b2393e7f4
+CT = 25b140922a9d4f2ce153a4ff86596a49d7de6a6184e931e8b2ff27a98029b23484e00c2a5d291887
+
+Count = 45
+Nonce = 713de00faff892977d99d0
+Adata = 14ea93488d4284d21d4c7ce14414adf45c1ed9d2d99db866d0e59accb6234dac
+Payload = 3820db475c7cb04a0f74d8e449f026ec951fa59667738698
+CT = e4d92ab8d1ffb0976670d891cc8338da12f86d5d79b334103d2ae816edf857c810b6fdc7f2c71f1d
+
+Count = 46
+Nonce = ba87934808de09b2ae829b
+Adata = 30e2ea2a505f19e8760a0a84961000c7a0b7fe3460a9d3f5a38f54149be2e9ee
+Payload = 0e52a384cedcdf7f179348de6e7336aa86f8855fbd903cfa
+CT = 6df893eed2be958e5f542f8cb4adb392b34786cb4ce821ec93fc57997b977948d55bdb026db5bc48
+
+Count = 47
+Nonce = ea09fbe5da0fa4fe911e18
+Adata = 237dc8512b29bccdeb8ee39cf83b9b6dd203823d175c44d5f605b194e7ec136e
+Payload = 41cee0ecaf9c65cef740440af37954ef49a585779d2abbca
+CT = 2f204ebcf549ee2a800d870e6341b9a89a41ab4ae91b6902ff704a2bcfb8becd0226f76d68fbb08b
+
+Count = 48
+Nonce = 5b80d7affc4ab4a4b68bdd
+Adata = 3a38dd7da30f5c312fb1e978d87b7a39792fd9ea3e9ab1565874e99df587327c
+Payload = 5ff92f6d3ca791421363e10cc84b4e8e21e0ebe5d8c55d6c
+CT = 05472db7875d59f8bed45606f355a516de93740aa2baeba18df9400df42baee6b9a0d75b45840104
+
+Count = 49
+Nonce = 514bba483fe7f2b7e555cc
+Adata = ac8beb419099cdb42a39e9b46fd900cc52eec4b43a96ed18b37b899b63fb931c
+Payload = b0b11dfca9b3936d1b4a423c5acd3d012b399a487c19c994
+CT = fa20629d514c4ce7bf727629bca5aa1c0c7e7851fc1bfc5c847729a70d7b4cff5281aece37006015
+
+[Nlen = 12]
+
+Key = d6ff67379a2ead2ca87aa4f29536258f9fb9fc2e91b0ed18e7b9f5df332dd1dc
+
+Count = 50
+Nonce = 2f1d0717a822e20c7cd28f0a
+Adata = d50741d34c8564d92f396b97be782923ff3c855ea9757bde419f632c83997630
+Payload = 98626ffc6c44f13c964e7fcb7d16e988990d6d063d012d33
+CT = 50e22db70ac2bab6d6af7059c90d00fbf0fb52eee5eb650e08aca7dec636170f481dcb9fefb85c05
+
+Count = 51
+Nonce = 819ecbe71f851743871163cc
+Adata = 48e06c3b2940819e58eb24122a2988c997697347a6e34c21267d76049febdcf8
+Payload = 8d164f598ea141082b1069776fccd87baf6a2563cbdbc9d1
+CT = 70fd9d3c7d9e8af610edb3d329f371cf3052d820e79775a932d42f9954f9d35d989a09e4292949fc
+
+Count = 52
+Nonce = 22168c66967d545823ea0b7a
+Adata = 7f596bc7a815d103ed9f6dc428b60e72aeadcb9382ccde4ac9f3b61e7e8047fd
+Payload = b28a5bc814e7f71ae94586b58281ff05a71191c92e45db74
+CT = 30254fe7c249c0125c56c90bad3983c7f852df91fa4e828b7522efcd96cd4de4cf41e9b67c708f9f
+
+Count = 53
+Nonce = 225557b0faca3d6cbaedec5c
+Adata = c7aafe7d3b419fa4ea06143897054846ac4b25e4744b62ba8a809cc19253a94b
+Payload = 0e71863c2962244c7d1a28fc755f0c73e5cbd630a8dbdeb3
+CT = 2369b56f21336aba9ac3e9ba428e0d648842a7971182d5ffac57f6ae1080efab4ed93f8b4ce1d355
+
+Count = 54
+Nonce = 78912be1a35e156a70fb72f7
+Adata = 12ba8eddff1c2a03ddd25bb924ff065a93fd712b2c4f61eb80d77fab2c4900e0
+Payload = 113efd182f683596862ccd5eba2e2d4ffa709d9b85c6f1d5
+CT = 835a22eb8d718c0ee1531a2d1bb95f58215c997c612908eeed3ccaeb7a814f69d3ec1fbf2ee9792d
+
+Count = 55
+Nonce = 91ad90b58d2044abacf957e1
+Adata = 4fc795b9126c23dd7fd514c2e5a8ca583e88a783b28cbb2a5df09f8b520ba0d1
+Payload = ed55f6b9eb8fe74474c037ede94ffd84ada846ede4ecff74
+CT = ecb595276fd5d412a7cc3f5cfe960f47a0d0e2df0b08a11ac257d67143722a976c9d7f44b09a767d
+
+Count = 56
+Nonce = 4bbe4ca29122c4892ca09b5b
+Adata = 367ecd1b71dfb96a84e2369f28705dfaebf0c73ed35d5364449b2391230be846
+Payload = 8dd497bb777bbc3e56e3af25a43545007bb00f2b9e9f815c
+CT = 563d61fc0a5b82804a580a7d752a8e61d3342fb39372b39b6843a685bde3175695796f6e64f35901
+
+Count = 57
+Nonce = 218e7b8a8fd62927f90b70e5
+Adata = 01815f599d6ba0d1c09f6f673bb6cca4c2a7a74f4e985be4c0f37842c7bbc5a4
+Payload = 80f3e4245c3eab16ef8bf001429122e46bde21735f63adba
+CT = aaceb16589b9de253c99d0d32409a631db71e8df8a7644bfd027e3466e8220144cb0552f9b2800e6
+
+Count = 58
+Nonce = eecc9f106a0721334cc7f5ba
+Adata = bf38d0ee11a796a517539bbc9ab00ff85a4ddbf0a612d46e2bc635180ad34c50
+Payload = 36cefa10af1a3446a2c8d4a1171144b9ddd8e33a7cd5a02d
+CT = 9bf3b2df93cf5b587ecc96f45fc75e6eb066cb286cb06f284c9027fc41bb8c848025fcf9d092a873
+
+Count = 59
+Nonce = e41af8ca408c4c12e37561a4
+Adata = e0b20892875f60b5d8763a04958487fa5b7cf8d67a456e430475b337245d671c
+Payload = 32a4da08bdd51336ed5798c7177b853a534bc98f2e6f7d4e
+CT = 95ffdc68f721cf2294d0d88002e3814167306fd906dbebdb7e6e0e5dc0a03826e51bd94269d7a41d
+
+[Nlen = 13]
+
+Key = 4a75ff2f66dae2935403cce27e829ad8be98185c73f8bc61d3ce950a83007e11
+
+Count = 60
+Nonce = 46eb390b175e75da6193d7edb6
+Adata = 282f05f734f249c0535ee396282218b7c4913c39b59ad2a03ffaf5b0e9b0f780
+Payload = 205f2a664a8512e18321a91c13ec13b9e6b633228c57cc1e
+CT = 58f1584f761983bef4d0060746b5d5ee610ecfda31101a7f5460e9b7856d60a5ad9803c0762f8176
+
+Count = 61
+Nonce = 8a56588fe5e125237b6cdc30f9
+Adata = b3aee5fbf409bcfe9b46ae68d570edbbed32c12d13926ffb5ddc60ff0bdb7f85
+Payload = eca81bbd12d3fd28df85e2cc3dcc2ecbd87408002fd00fe1
+CT = 9aad62a5443550d11f9efdab2de0eba74d47ae4f7d16adf4276664f6567f2f978bd4be4d80cd07be
+
+Count = 62
+Nonce = d908b04840caca2280e5293ade
+Adata = 314a202f836f9f257e22d8c11757832ae5131d357a72df88f3eff0ffcee0da4e
+Payload = ad1109ea5c79bb55d22e9713eb2df42767cb29a2eba3ad2c
+CT = 61fdcebb158cd03151697ae7871c0a998802997e0672e5886e5a9df1b1d6284ef657cde6f74734bb
+
+Count = 63
+Nonce = 6df8c5c28d1728975a0b766cd7
+Adata = 080f82469505118842e5fa70df5323de175a37609904ee5e76288f94ca84b3c5
+Payload = 1a95f06b821879df3fd3ac52fc99a7c1d3e9775263b7d036
+CT = 704f60f9cc3ef7bc00b4f7a271ca70a89f4d5605387b3e2f8cc80aa08572b90e9598d0a73712b720
+
+Count = 64
+Nonce = 6c6ebacce80dde9fefb7e5bb47
+Adata = 93f0fca0c8c84d5cc48160b25e246226d489225c0f8275e52856da592c715aa6
+Payload = 46820aec46ebd0d61706129584058a1498514928a87fe620
+CT = 00f6cccf45f046da1e6266afe61eed61c60c28515b2e1ab386b2c952055899184f0d95ffe3959f89
+
+Count = 65
+Nonce = b94bc20d8c9abca7645fc6bebf
+Adata = e1c083c93663f5a066ef337a61aa3fddde7c301a42463137c375cc2dcdd76954
+Payload = f1fca581d3dbbc61060c0c02adb47bc57954d25a283f66d6
+CT = 90c65d23e0e1786cebb95f9b1306d001b2e503842cdedb75e37a53d77b9e38605febdd7b2b666f98
+
+Count = 66
+Nonce = a4974791d417d7e9eea0f4ae8d
+Adata = 33602f308f3a0f7e1c75fc1e4321d545ffa278234958dbadd37f59a0f85349c3
+Payload = 41712c058d2d56b43b2c79278e790858a289320746c15a60
+CT = aab5656a1ef060c9b1ef7e2f3cc0bda40ff067900401182563ceb824708a20724c99c83f1caacd70
+
+Count = 67
+Nonce = 6003b771afe4e99e1ef1ed4a31
+Adata = f60d8362b2ebf523681bb051fd3ee13919ad86acd963c703c4178a5f01a84236
+Payload = b766022311c5e1d74a607fec7cb8ee805b8397a6c5f374c1
+CT = f73b2a6dbf8f798d4bfb489a6578c9c79152e42aa3b81b64a84e7af3116a18f7ce44ae93f420270b
+
+Count = 68
+Nonce = 27861168ac731a223dc35c03e8
+Adata = b7ba1c66282cb6092ba601407ff9578afdadf7ba7a4d08edef06dbbfd87171bf
+Payload = 0822e3e6ba982091d532cd5271fbde25305d1f6e71880f81
+CT = 5ab3e5296cd1f08704c82f6b42939702515b7733853d723d4009312bdae46958d844eca502bcb005
+
+Count = 69
+Nonce = ef284d1ddf35d1d23de6a2f84b
+Adata = 0b90b3a087b9a4d3267bc57c470695ef7cf658353f2f680ee00ccc32c2ba0bdc
+Payload = bf35ddbad5e059169468ae8537f00ec790cc038b9ed0a5d7
+CT = b702ad593b4169fd7011f0288e4e62620543095186b32c122389523b5ccc33c6b41b139108a99442
diff --git a/lib/crypto/test/crypto_SUITE_data/VPT128.rsp b/lib/crypto/test/crypto_SUITE_data/VPT128.rsp
new file mode 100644
index 0000000000..f79db90b4d
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/VPT128.rsp
@@ -0,0 +1,1383 @@
+# CAVS 11.0
+# "CCM-VPT" information
+# AES Keylen: 128
+# Generated on Tue Mar 15 08:09:24 2011
+
+Alen = 32
+Nlen = 13
+Tlen = 16
+
+[Plen = 0]
+
+Key = 2ebf60f0969013a54a3dedb19d20f6c8
+Nonce = 1de8c5e21f9db33123ff870add
+
+Count = 0
+Adata = e1de6c6119d7db471136285d10b47a450221b16978569190ef6a22b055295603
+Payload = 00
+CT = 0ead29ef205fbb86d11abe5ed704b880
+
+Count = 1
+Adata = 98d477b7ef0e4ded679b0bc8d880f09823ad80e9732fde59c3a87da6a1fcf70b
+Payload = 00
+CT = 5b85d144bb51d4927074d3536a2db83a
+
+Count = 2
+Adata = 28f32de10b6c9d3c3f46efec7aee24006208a54c4d1c2bba4b8cdce166cab7d9
+Payload = 00
+CT = 01045de4a09486eea5efa33ecc6cd299
+
+Count = 3
+Adata = af397a8b8dd73ab702ce8e53aa9f0189995c6c9e920dcb75795149550b499deb
+Payload = 00
+CT = dfd75400b59c3ad387bc86dfbbfb52ac
+
+Count = 4
+Adata = 3fa956bfaa27e249bf0a1276468d808259f3b8e2687851d780885d44cc2f04bd
+Payload = 00
+CT = 2b11d2549b4e2f0a81c07ee90af4d081
+
+Count = 5
+Adata = babbd1b44cae3af06e0150bf0e3d898f6fe862b71ea9f6b727accfc18848fc79
+Payload = 00
+CT = 10f76ab445f4ec158ccc1f7c6fee3ede
+
+Count = 6
+Adata = 7fba0bfda3b03c736c121cf9a257db55060b621be5168619ec4182f13ef6a408
+Payload = 00
+CT = 59e02d6a6aa3fb2692b04e65a0e735da
+
+Count = 7
+Adata = 057354a29808f4ed77671ed3dc36f8b03f5cd952caac5cb80dc3b319f3333e29
+Payload = 00
+CT = 367a2ade4087964dcb0ca2984d44657e
+
+Count = 8
+Adata = ec08b618602d091e9304715cb552b357c16fd1d7f7f023a28d84a98ba21ca0ab
+Payload = 00
+CT = 47cb92cd40bc89328d4dd44fbd727032
+
+Count = 9
+Adata = 45622834ea658b09b17f32777d18b34b387ef957bd344468f68e7178417a7c24
+Payload = 00
+CT = f5185afb8359b5ef995483c0bc4192c3
+
+[Plen = 1]
+
+Key = 6ae7a8e907b8720f4b0d5507c1d0dc41
+Nonce = 7f18ad442e536a0159e7aa8c0f
+
+Count = 10
+Adata = 9c9b0f11e020c6512a63dfa1a5ec8df8bd8e2ad83cf87b80b38635621c5dc0d7
+Payload = 0e
+CT = 4c201784bdab19e255787fecd02000c49d
+
+Count = 11
+Adata = 73616a428f1a567b2e9af86b1fc8aec6d597b1b55f2aa2219b3b662fa6bd3407
+Payload = 30
+CT = 72f14519f06b63fac3d5b2d9bbfa0cb758
+
+Count = 12
+Adata = 6d62f4e15e8bcc9ba4993bc50a046737121016f0d15020b90068250551167b1c
+Payload = 34
+CT = 7676b581a28ca0a0ba5178eba7fe028da6
+
+Count = 13
+Adata = 8f0b8289a1834ecc2167b59ce3c9d3b58465c4cfaad50c728d04360cb7e5bc41
+Payload = ec
+CT = aed99b805c0a4785ff2913cab3e50f6205
+
+Count = 14
+Adata = 477b2a6932f838f0d1bc420c0ca306981d8e2dab945b6f259e15fe888667220a
+Payload = ec
+CT = aeb50e41cd7af84a8fdb6aee144e904616
+
+Count = 15
+Adata = d6518d409b1f05708d0b44f18fb5721f20f3220f8d2f2718650aa9932e4579e0
+Payload = d1
+CT = 9312639c863974f077fe8236c943b464c4
+
+Count = 16
+Adata = 865e7cde73b558e9bfd05356923f8a697970811fc484acad2d5b3528baf1f986
+Payload = 24
+CT = 66d7265cde50bc7a3989458437baf06db5
+
+Count = 17
+Adata = f0c3c67a935eace53ed32435655dd0974fafe283622e8294a15d70977398eae2
+Payload = c5
+CT = 87063144b25d2268063815d1b42ebbac34
+
+Count = 18
+Adata = 341e71b2ef26e9db03882e06d06cde2c0617326cd157d5984d22f6f3407a9c39
+Payload = 34
+CT = 767da45c10d0d6498716bcf3f13ca7e26c
+
+Count = 19
+Adata = 31fce6735ba9a3385df11c153179b8e4141a3c6b8ad6eceaa211f3f17bfd0474
+Payload = 7d
+CT = 3fcb0a6f562974cfb3fb7c8d5cafd50f2b
+
+[Plen = 2]
+
+Key = 3d746ae6cac5cefd01f021c0bbf4bc3c
+Nonce = 597b3614ff9cd567afd1aad4e5
+
+Count = 20
+Adata = 90446190e1ff5e48e8a09d692b217de3ad0ab4a670e7f1b437f9c07a902cad60
+Payload = 4360
+CT = e38fdb77c1f8bbac2903a2ec7bc0f9c5654d
+
+Count = 21
+Adata = 6bc3d30925c67371573271f1a4273ad76e91e07dfab65f7bce0b241b5e4cd00e
+Payload = 17c6
+CT = b72955210d62e1393e4fda647c2b2e59a47d
+
+Count = 22
+Adata = d1bb4cdfc3f2c16d92576068543692aa4b5a427d688387af0f1583e91a0e8b3c
+Payload = 6575
+CT = c59ad54fd88a47b9f6e39cb4606af86d13e8
+
+Count = 23
+Adata = ae6136df9ab43631ef143515dacedbe759b3459e951bfaf4712a21c86352f1c0
+Payload = b1dd
+CT = 11326de841af64b55bb7ebe3fd30ba493c7d
+
+Count = 24
+Adata = ffead34ac26e21158212d07c367c3a7cb6b795887ee2d3d8ae25c60556ea88d3
+Payload = cd16
+CT = 6df93a206339de534271f6469edfa5ed07d3
+
+Count = 25
+Adata = e768e7d867820d46c1cc62ee0e51d4dac6f5c4b5785b5ccfbf05236871bdce2a
+Payload = 12f5
+CT = b21aa8f65144f2ec5809e2ccb38c8760f7bc
+
+Count = 26
+Adata = 402e802885e4119df17fe85f141c3d1af7727fcdb00f8e2c34e42a436d04ac5b
+Payload = 39c0
+CT = 992f9af825957abe7d89e175b6e8c0b84b5f
+
+Count = 27
+Adata = 8a3a622b3d347c0c5210d484adf77fa33205ba02224ddceea71d89c9ad8429ae
+Payload = 912f
+CT = 31c025d6a12e91e84e355934547f6b5dceb8
+
+Count = 28
+Adata = 636114e5e5f83cec94e1df21d6babb9f6a14a532fcbfc3bcf649fbd79ac1abbb
+Payload = cb6d
+CT = 6b826db959a21e9e4ebf25ca4f98501b560d
+
+Count = 29
+Adata = 04e84f9156998c2eca9e96079a6001f2947dc49a081b3d75e47d75f71ed4a606
+Payload = 5bd2
+CT = fb3d2006ff22ff231a6646ae561923818a21
+
+[Plen = 3]
+
+Key = 3e4fa1c6f8b00f1296956735ee86e310
+Nonce = c6a170936568651020edfe15df
+
+Count = 30
+Adata = 00d57896da2435a4271afb9c98f61a650e63a4955357c47d073c5165dd4ea318
+Payload = 3a6734
+CT = 384be657bfc5f385b179be7333eb3f57df546b
+
+Count = 31
+Adata = 50f6e6dd57bd3a24f6bfdc8b1c7b5a36ebdd07fd6d194e6e82da47151d9c88fb
+Payload = 4ffad3
+CT = 4dd601b8ca97bda492546d82dccdebef441f8b
+
+Count = 32
+Adata = 70e132023acae1f88c7a237b68f5bdce56bcfc92be9f403d95d3bcc93b4477a9
+Payload = 8a594b
+CT = 887599fa0f3e397d9a580aa39c7028e1a508c9
+
+Count = 33
+Adata = 08d2b011f36e05dc728c1a8bda3d92c779a3d2f27c4b041810bd6222c852b14d
+Payload = 1f89df
+CT = 1da50d593460d335e2f7a6d40b8fe305b0f690
+
+Count = 34
+Adata = b207eb870aeeab27c6201ef04650bdc7ea30028a243420f7d198f1c9c9a43023
+Payload = 72e9c1
+CT = 70c513a2d49e1a113767ea4219107819d88b65
+
+Count = 35
+Adata = 74294088721fc9e7aabd5f1c66b5369b1e2d2cdb3e73abaa28ecd1c37d4ecea2
+Payload = 016083
+CT = 034c51dab1c819778be8453db163c882063af8
+
+Count = 36
+Adata = abbd347999a1c26368cdb17ab08bf57a8e942d1248296e952f5f42f2cabbf0e6
+Payload = 25f665
+CT = 27dab7537eb435df8d0e48c3f7e0bd1877c866
+
+Count = 37
+Adata = 231b33dc406c9210f59a5df1cfd595c803474db34b9b1848f0bcbe7b28df33c2
+Payload = 158606
+CT = 17aad4da549fc63d55b5910bbbf64435b95220
+
+Count = 38
+Adata = 69b851e63a78baef90637978e3dfe8c47be4b21e85bb89bf67051cf251004376
+Payload = b07452
+CT = b25880d5ee29fb2af47f8040fad585921057f5
+
+Count = 39
+Adata = 9b1f786c887d310b8efd3e8192fe504f603024c94aaa4ec9123736a40bf1605d
+Payload = 65187c
+CT = 6734aebc3ee43e10205f83143e0d3794a6734c
+
+[Plen = 4]
+
+Key = 7ccbb8557f6e08f436d0957d4bbe7fdf
+Nonce = bb8e2ef2ed9484f9021cda7073
+
+Count = 40
+Adata = fba1d18a74a3bb38671ab2842ffaa434cd572a0b45320e4145930b3008d8d350
+Payload = 4cabeb02
+CT = 32501f4235c4dd96e83d5ab4c3c31c523453c317
+
+Count = 41
+Adata = 78b3faecb2bdf6ed14ac2b86ded07aa791b60f5d54f9e24a965a8453f5131898
+Payload = 5ff73653
+CT = 210cc2137907d6a03e66403a7d9330d30d934a8d
+
+Count = 42
+Adata = db1239528eb464dd063e2a97ee83a87d6002ebb4fbafa77036f72c14f3fe959b
+Payload = 062fa9ca
+CT = 78d45d8a44f4bc78fbb969935076134437df82b4
+
+Count = 43
+Adata = 0071f1edb3a0ce57af3c88bb0ccf138f752697a77e55695838fb39de04c78dfb
+Payload = cad710b4
+CT = b42ce4f459692911fea2e0034d06c3b2e89af3d1
+
+Count = 44
+Adata = 7381471a62b1fa6f5061c4c37e9721f07099d007ffaf8639aa2ae3f82da5a559
+Payload = 7ac716b4
+CT = 043ce2f468484e22381923bfcaed16e0cb85b0f8
+
+Count = 45
+Adata = 19bea6d92d5892216e8e4a30dda802387800bb046a6717817fc46c7edafe17b0
+Payload = 362da02c
+CT = 48d6546cd081de39c247df309c4b56c31c03690d
+
+Count = 46
+Adata = 8503c8eb9cebc6110f259e35e03a0740267768130ce6f61b1c7d1d25be942274
+Payload = de52b209
+CT = a0a94649c6c6bd7b3a9d7c4dfa2738847ea3cb33
+
+Count = 47
+Adata = d2445db6efecaa3f426b06de8d496ceed54a1d0171384cc762e21b31e265c6d5
+Payload = 8fe8b383
+CT = f11347c32ca874d18d0b790856837555f4d4699a
+
+Count = 48
+Adata = 8cda7d1e135cf5fde1ec9473c4b42c1bbb445c27fd87b5f73df61ceb2d0b6f75
+Payload = d8d6b2c9
+CT = a62d4689932c2f8d78e322aaffc90846025190f1
+
+Count = 49
+Adata = b506a6ba900c1147c806775324b36eb376aa01d4c3eef6f5a4c25393ecbf2025
+Payload = 6a029e53
+CT = 14f96a13c346a4084918081b4bbe53b50d896788
+
+[Plen = 5]
+
+Key = 3725c7905bfaca415908c617b78f8dee
+Nonce = c98ec4473e051a4d4ac56fd082
+
+Count = 50
+Adata = 11bc87f1c2d2076ba47c5cb530dd6c2a224f7a0f7f554e23d7d29077c7787680
+Payload = f5499a7082
+CT = e378b776242066751af249d521c6eaebdff40b2642
+
+Count = 51
+Adata = d54219ef4fb851bebd1c546011ae3922b8337e19c28d4d58428efd66f80edcf0
+Payload = 513c46fcce
+CT = 470d6bfa68e7258df363e0e9af67a543c86db3c994
+
+Count = 52
+Adata = a92e88edd297da8c7089e21822b3e6cffd6837c78b975c8413fd6cca1b99bcb0
+Payload = 9d62e557c3
+CT = 8b53c8516572b7573e5b27a1d0e15cdb7b06c8857f
+
+Count = 53
+Adata = 77d9c306aa257379053cf1f2043c388a301dac2a9e2bb89eb8bab6eb3f150fe3
+Payload = 7a05db235f
+CT = 6c34f625f9de691a412ad54bbdb6ceac45ed45902b
+
+Count = 54
+Adata = 081568ae0b948aa647b9d4dda5d42641ad5de72aa9874d8d0717d872007720a8
+Payload = 30a22ca0fc
+CT = 269301a65a8a1bb8ba3d6763dcb1bdd3400e3459f7
+
+Count = 55
+Adata = 695ba4dea0f84baf190ec25a25fc00cb9898902d7a17e6f5ff2df323b974f7c4
+Payload = 35e25aa51f
+CT = 23d377a3b9403897d496cabcd5bd9de3282199a8ed
+
+Count = 56
+Adata = 1f3ba0336a634efdd11f8168c0fe25039f9403bfa70b3898f4dbe577dbd52957
+Payload = 8bde704c74
+CT = 9def5d4ad270a81f7cb0ab7ab2b495f51d66abeee5
+
+Count = 57
+Adata = 097b9ebff3ff93a143678d59721fdf359e95cbc82585ae47727a773317925d38
+Payload = 428542ecfb
+CT = 54b46fea5dce68e9b01a4462a2221bd2f3cadf64c0
+
+Count = 58
+Adata = 76d0341dd44c39e43a23dbcf4cb602f15d5fb9fee20c3d0d262d539c3fd1dfd5
+Payload = bd6866ded0
+CT = ab594bd876f2545964ef3978cad3387d61104bab84
+
+Count = 59
+Adata = 7e7c40ad64b511005b4546f9ec61ca24829390fbc4bd8507225bc348ae0807d7
+Payload = 5822755a3e
+CT = 4e13585c98002c41938a935d51905b2a708a2c5194
+
+[Plen = 6]
+
+Key = 80bead98a05d1bb173cd4fca463b8fa3
+Nonce = 8a14a6d255aa4032ebff37a3d7
+
+Count = 60
+Adata = bb4e706e73d21df66f64173859d47e247527cd9832e20dccff8548ed5f554108
+Payload = e479990bf082
+CT = 89c9246238878427f36b1f6c633e4542f32b50ca8edb
+
+Count = 61
+Adata = 9db2182c8a4f5471082bfa1a8496602cbcdef2790f7e8f71f791303bd48dcb05
+Payload = 017a7fd1aecb
+CT = 6ccac2b866ced76fe54da69af5edf8309c7f013bb07e
+
+Count = 62
+Adata = bf483f59fb73681f27b68168c998c90ea8ceea997654c6fab2bd737dcdc884f9
+Payload = 512fc5e4973a
+CT = 3c9f788d5f3f662f53d17f7cb6673415bb2324ca0666
+
+Count = 63
+Adata = b91e641d8210e1ef705fec2beb9f58a391c7d1a38935cd1d13f2c00363388ff5
+Payload = 06212e989616
+CT = 6b9193f15e1340c86156b1065b64af1e4d6c89b32603
+
+Count = 64
+Adata = 5cebf908e232d797fcce8453c4c3000868d4172622a4ee0d6a1bdd876a0b7c96
+Payload = c45629069ebc
+CT = a9e6946f56b9c07ef5349903b928e39e99e2e32625de
+
+Count = 65
+Adata = ab92cbc97f3aa6f9ea4dae5d8c3d9e91231f43ffff548da7b668e61c183ac2cf
+Payload = b949ced37725
+CT = d4f973babf205e40654ea16e83cc6faeaad668c416f3
+
+Count = 66
+Adata = 2c3d2f9c7e89c2b9e07317c4db6e9f00f5faadfad531c5bea79d164ac24d4543
+Payload = 517ff7b383b7
+CT = 3ccf4ada4bb23102a502dbba0c280e1d5fc627fe3a9e
+
+Count = 67
+Adata = d798e77ab0f3697768f23014fd31b9e8762ae65b6aa8a4bbc17ecb8cbe78461f
+Payload = b40d863ca4ff
+CT = d9bd3b556cfa6745fd4c954396e696697731e1f9a262
+
+Count = 68
+Adata = 45b44e3dec57e24d960fd1767797ffdbbab81e38bab37e6974df262c3d932327
+Payload = 56e00289a003
+CT = 3b50bfe06806bdf2b2dd47077c98234eae5d47c3b594
+
+Count = 69
+Adata = 645d27970ccce096d082fccfc1183955bad2611af0dd7c58c9d54430f28bd992
+Payload = aa22bb1de579
+CT = c79206742d7cea66649ad7e204a344d3234125aa324b
+
+[Plen = 7]
+
+Key = dc8ec91184ba18eae31ac2d3b252673f
+Nonce = 0da4c988f521f5648259f2bec2
+
+Count = 70
+Adata = 6d5573c9279897d7d1602d8a95c04bb5ca3fad2dbe89a024b3651eb227e73bb5
+Payload = 2a5775986551c8
+CT = 4f259f2a718faea852a7c4358dfa9f5467357638acac90
+
+Count = 71
+Adata = ff0ab5021ef466e2e898b0993d691145168be558682c74914c172f2b5e863754
+Payload = 8db3c1ca0580f9
+CT = e8c12b78115e9f8767c76e707d48a2144e090812e0192d
+
+Count = 72
+Adata = 2ee03cc28f79773af139c4ea55ec4daa48bb2885b8adcd5f066eceda5c4ec27b
+Payload = 3c69e2e83236b6
+CT = 591b085a26e8d05486df740083c959fb62ef7e2e221602
+
+Count = 73
+Adata = f041504d4c1b3d5be358bd6d350af42921205d29ab22b44ffe221358adef5bb4
+Payload = 777828ab5ccb68
+CT = 120ac21948150ebdc4d2b86b2528f75db4a7f5423f4395
+
+Count = 74
+Adata = 81ea116832d69542ac8d3d22c16c82eecf2ccac39264dd933c4f9c13c8d0f1d4
+Payload = af556fef3584e3
+CT = ca27855d215a85a7b06d1b710baa15daef19069ecf46f0
+
+Count = 75
+Adata = 8a0a120ed290a62456f002da1c250a0ddb1ebd57185a733d8fb562aad482679d
+Payload = 98f26635351f14
+CT = fd808c8721c1723811129add52e1406d50cbff4aa82802
+
+Count = 76
+Adata = 12b5a76faedf6f855e328c2cb87be8aea78c5e926b32d828e167b46205c86de5
+Payload = bd22c1ec05dc26
+CT = d8502b5e1102401563d3da8a6cabb7515f642e42fb4b2e
+
+Count = 77
+Adata = 8dc32f35ef4bcbfd040ad25dc36d0bd2486f93d0cabb7704cd1582dc99f65449
+Payload = 2a87c0d64806fe
+CT = 4ff52a645cd89817609a21f703253e5e56beef4ac71759
+
+Count = 78
+Adata = 83ced632359a11eb0c4c99baad84df5cac15bc5453b6593d9ffb4c5e8c84037f
+Payload = f05f39eb0a3d64
+CT = 952dd3591ee302236c72f98da859b54be7c598d85c37eb
+
+Count = 79
+Adata = 771a818a24e7da7b98f4b4291ef34bec7e1656b0c6c6e9474a989a04ea7de385
+Payload = 59dad755af92c2
+CT = 3ca83de7bb4ca464c8cd38cbcc46e7f09bf3e1c6590c71
+
+[Plen = 8]
+
+Key = 19f97ef5318b8005fc7133fa31dd1236
+Nonce = 01ce9814c6329dbee1d02b1321
+
+Count = 80
+Adata = 85853f120981f33cf1d50fde6b8bc865fe988a9f12579acdb336f9f992b08b89
+Payload = 6d972a673fbe1ca1
+CT = 2f12a7e7acecae5d2563309efc19368cdee8266538ca89d3
+
+Count = 81
+Adata = a4ec5aee89e2cce2115b6c1f42570bc5062887cad08192a682d0b4508fcd936a
+Payload = 68b1b6367a15fe49
+CT = 2a343bb6e9474cb528096a5fec5e5359c369833eac3b7efb
+
+Count = 82
+Adata = f5499a7082bf1e6e2923211271f5f7f6d7c7b26db7963071705a58ddc4dca0dd
+Payload = 707023615563a40e
+CT = 32f5aee1c63116f2754a65863efb60c98dbb536e2b5a69d8
+
+Count = 83
+Adata = 765f267befe6fcfaaa4b46eda32e7bfab87f12ceb07fa3b37be74965bb664a21
+Payload = b56454bc50df3e28
+CT = f7e1d93cc38d8cd40b6e9b7f3b3541ffee66a1f668f67d28
+
+Count = 84
+Adata = 9ce65598cd1f86afc9aaaf172809570cc306333c25523f863c6d0e0154c55e40
+Payload = 962f765da3565bde
+CT = d4aafbdd3004e9227018c9db8baf6be349d93d4eef7d7c9d
+
+Count = 85
+Adata = d0125e30c36232a8c07cee9abc53453b276849a7c04ade80ad586ed8cbcede51
+Payload = 4f18bcc8ee0bbb80
+CT = 0d9d31487d59097c501b28887f05fd66f050525943d101f8
+
+Count = 86
+Adata = 90dfd9e7bb7bf8fb70c22a879ffa760d14cda7b79ce4968f69b8a7f2b7a59642
+Payload = ca293c9e1780b401
+CT = 88acb11e84d206fdda53dde2e1aef96b3658a7635ee54188
+
+Count = 87
+Adata = 58f518710e6b282482a7f1950fa353b13bdda10c9aaea6d5f0d7ea0a965d31e8
+Payload = b9df9fb4a6b299b4
+CT = fb5a123435e02b48b62a5ec234f1efd1b52c8fad1cf09890
+
+Count = 88
+Adata = df052e95aea3769a433ce4e4e800b8418649bbe8c6297eb07545e6802de7e807
+Payload = fb2441d1594a488a
+CT = b9a1cc51ca18fa76bc051ede6f37cf67543a7252d7d9b203
+
+Count = 89
+Adata = 0875020959ed969cfb38636d1d5aabce9658b00171a7614ea9e5395331c7659c
+Payload = 451101250ec6f266
+CT = 07948ca59d94409a5be4be6bc6b18104fac167b6e3fc15f7
+
+[Plen = 9]
+
+Key = c17944bfaeeb808eed66ae7242ab545f
+Nonce = 910b3db64df3728ca98219e01b
+
+Count = 90
+Adata = edf64f98b3ab593cbcf68ab37a8c9472e49cb849d4a744deae925a5a43faf262
+Payload = 7caae2640e734539d3
+CT = 0dae8b3ccf0b439f6ff8ee4a233dfb7753f6bfe321b3e26959
+
+Count = 91
+Adata = 29ac8fd6a20a5df4ec79660c44d373da42de7d7c5fc35982b6c29b480723b484
+Payload = e574b3a37af3bf2251
+CT = 9470dafbbb8bb984ed63b1477d9506a51ae23abbac179d8b02
+
+Count = 92
+Adata = 9ae5a04baa9d02c8854e609899c6240851cbc83f81f752bc04c71affa4eed385
+Payload = 2e3cf0af8c96c7b227
+CT = 5f3899f74deec1149bdb0986198bce2e486581c041029a81d9
+
+Count = 93
+Adata = cc8e789462879e348d20be4e1161d7b7fc6f8371d8f8cb2d25d13f0e07de47b0
+Payload = 16f22817c5b79f9fa6
+CT = 67f6414f04cf99391a0cbb2df2079a6eb964c3469f4f326122
+
+Count = 94
+Adata = c63061f2800228269015693336f78bb535ae8b88869e4ccf4ead2f3b0ea4e48a
+Payload = 64fe8076d4e8538e18
+CT = 15fae92e15905528a4a40ca7622acf7266b7c24cf0c3202e4c
+
+Count = 95
+Adata = 71c14a7031033db15bfe23b75fed9daf8886dd11392a0b787660e7b1a581af11
+Payload = 4814aaac48bdf43c92
+CT = 3910c3f489c5f29a2e7de20e98586cd5d684bf015a7abbe82c
+
+Count = 96
+Adata = 8f4947f8588ed866ed7477d7f1a28046430c6470806a50e3c9e80958c61f1b42
+Payload = 392a692b57a8a97f60
+CT = 482e007396d0afd9dc8d503f5d87818f7c0e173b857cef4288
+
+Count = 97
+Adata = 9d44f6df58c2b43db67e3daa95b176c81daff32e996d670e86405e15eae72e93
+Payload = cba1e00e345b0cb7eb
+CT = baa58956f5230a1157c85e2283d9e80700268a6459d1451d00
+
+Count = 98
+Adata = b6ada12f7a28211e9d2c07cbb3d39fa77aadc077b34c46f93006c1ca2ff66f87
+Payload = 22f5b6752582919dc1
+CT = 53f1df2de4fa973b7d1056aea3d3e4f7a5219170aaa52465e1
+
+Count = 99
+Adata = d6411fd5b25433f67ca75e4560ceb809d3721266beec358dde126b2f6a514137
+Payload = 6e1b55d6f5288c5451
+CT = 1f1f3c8e34508af2edfbfcf8200a8a3f8d995f50284a7280c8
+
+[Plen = 10]
+
+Key = 0fb9df6f638847f5de371f003dd938f4
+Nonce = c9ddf61c052f3502ad6b229819
+
+Count = 100
+Adata = 4f9938d5bc3dcbe47f6b256d5e99723d0891e50c6175aba41b011e4686113c49
+Payload = e10cc36bc1c5d3c646ab
+CT = 7f797367de50be6dc04e4cf0d8c24189affd35060cb7ca3dd136
+
+Count = 101
+Adata = e013a2edd5b86bab8df5c9940d0a0c864478c1ad42668304a643141855adac10
+Payload = 15841284c959febe63f9
+CT = 8bf1a288d6cc9315e51c4148ef85caab151488c1a6b3df540d21
+
+Count = 102
+Adata = 147d77d509f642189594df17574a0ce62b52a838feb62310e11533995ba4c851
+Payload = a8b4e5829069c335d1d8
+CT = 36c1558e8ffcae9e573ddaaa1e7c22b3efa8362abb3d31ee8884
+
+Count = 103
+Adata = 0bb09658e23fe8a08c01a6994ef36cb8dcc9a806297a09c67efe3558ca56bb5d
+Payload = 1bb2da0f1ae7e044deb0
+CT = 85c76a0305728def5855317b141383ad38dd78569d5f846f2520
+
+Count = 104
+Adata = 34eb2e6149bad764837f6f25ddd96865e5b05d5cbf233c4f6cc2aa654dfea3b7
+Payload = 63af538196add9b3fad2
+CT = fddae38d8938b4187c374e6432971aecf6bf7cf5244d21f7f173
+
+Count = 105
+Adata = b69f26fda6d1cd92897e03758cae020c4e1beb019ce5ad987f872940780a9468
+Payload = 6ef2df5a1688ae795537
+CT = f0876f56091dc3d2d3d2e4d0ffc0f0add38a80c7ffe6b4701e54
+
+Count = 106
+Adata = a7375ba32251af0138bd9fd8fcd56a7c43ab2ca9a7fc0117d25f6d4ef9c2fcbc
+Payload = 3f46c83021069ac488a1
+CT = a133783c3e93f76f0e4447fdd0b2f29f39094ba5a7375e278349
+
+Count = 107
+Adata = f9b91f7298b4e43843fc739a2f41c57c3f2cf36378fe4c34b574a43f9cedee7b
+Payload = 86c10a6dfdd6a06ef638
+CT = 18b4ba61e243cdc570dd57500f913ee3f46801e1bba9d4db7ecf
+
+Count = 108
+Adata = 9d35876d9449a1642b5062dfbfc7a26a7ac080b7198f4aeff2c79e463565cfd2
+Payload = 196c80d02b663bdd89fd
+CT = 871930dc34f356760f1856a6b87519b4807a2114ced587f72189
+
+Count = 109
+Adata = f2d5e927eb507f889efc6f21d783851f638f978c74960cc347f89f2703476114
+Payload = bd27ae3ade0781a33d5f
+CT = 23521e36c192ec08bbba2101012808adefe9b8166e04685bd537
+
+[Plen = 11]
+
+Key = 006ff7d3153caf906ec7929f5aef9276
+Nonce = 57db1541a185bd9cdc34d62025
+
+Count = 110
+Adata = 7d9681cac38e778fba11f4464f69ed9ebfea31b7ffcaf2925b3381c65d975974
+Payload = 31be1b241cae79c54c2446
+CT = 9dd8a4244fbdb30b624578a625c43233476bbb959acd9edebe2883
+
+Count = 111
+Adata = 1b0012c468009bd2851653013782c7b71ef43c393afd4dc0aec4d6d0c3fa11c5
+Payload = 8802831e22092b30110cf7
+CT = 24643c1e711ae1fe3f6dc9d477ca066ec2befa854a1faef018ea8b
+
+Count = 112
+Adata = 48b216375c00ca7e9c4048834b37944d2543e24fa091fb3c7290e11c53a6b6a0
+Payload = 3b3f782d637319d7fd161d
+CT = 9759c72d3060d319d37723eb6be9a78dfbd9e16181679b782969ad
+
+Count = 113
+Adata = f3e06a45fcf1f6abeb00727bf2c9bcea00ce621d38f7b7eba17c27e51f04c793
+Payload = e98f5e5a20d02c80372d6d
+CT = 45e9e15a73c3e64e194c533d9574d95b821a5170e9b61d8e6b2ff3
+
+Count = 114
+Adata = b36e27729f9a139d8ec4f61215b7bf1149cbb4d93a5c14bebd7cfb7c6fe585cb
+Payload = ceeed4fde3406ec40f7ac6
+CT = 62886bfdb053a40a211bf8aa193d257907be1330abaa56bc4f431a
+
+Count = 115
+Adata = 8886ed7fa414d74aef704a9751b197cbab02c41c6aedcaf65cda019dc2d2d815
+Payload = b38f03449883773135c0cd
+CT = 1fe9bc44cb90bdff1ba1f31d92029a6428748664b5c815f15ca1b7
+
+Count = 116
+Adata = 816d81af167d2294497d9b06a39fdf75e37cbacf4d10c3a444068c891b361bba
+Payload = 8efb141db7b77c521003cf
+CT = 229dab1de4a4b69c3e62f1386e4ad7c72ce0081a85d4cfd34254c7
+
+Count = 117
+Adata = f427c47e10c45bb3c7e75e9e604503b3560427691470358efdef48ddaf3794d2
+Payload = 6dc38e37d1379732df4dd5
+CT = c1a5313782245dfcf12ceb98eeb05bc376a1042735569d5b63f8fa
+
+Count = 118
+Adata = f3df712b5e8dd8e4aa8b7c5f41e93bd11b0df66a3456a01f3d0094ad91482cdb
+Payload = e0e358aff203369dd5960c
+CT = 4c85e7afa110fc53fbf732065b03ebeb68a9153cb4ed152ce0d64c
+
+Count = 119
+Adata = 264f2c7b095a296eb8ff6b5151ab3d9497ea8dc0002a9e5b09c2fd0ccd32b6ff
+Payload = 57b940550a383b40f3c308
+CT = fbdfff55592bf18edda236fcd16c8360a408e2787f930ed275bf3f
+
+[Plen = 12]
+
+Key = 026331e98aba9e8c23a9e8a91d0b0c97
+Nonce = bccfe69bba168b81cbdf7d018a
+
+Count = 120
+Adata = 26e011143a686a7224ddb8c5b1e5d31713fa22c386785e2c34f498ae56d07ed5
+Payload = a82200ef3a08c390dec5cbf9
+CT = adf4fc6f9be113066c09248fcb56a9c1a1c3bb16fbb9fbaedacdb12b
+
+Count = 121
+Adata = 97a720ae4720546e31263a1a538ce1d35c198c23bd4362e0023a67536328ab9a
+Payload = 7fc58d1bb450b396b9161f53
+CT = 7a13719b15b963000bdaf025002120b619a391fbd23402e5edd4949e
+
+Count = 122
+Adata = aff6c8cefda055c67262e9c68825d1ad2a7488e5b09640a111fabf6254d96cc0
+Payload = e9ea182d7f895f312b9738db
+CT = ec3ce4adde608fa7995bd7ad48b6e9a8de0099a28cebbf5c2bad42ff
+
+Count = 123
+Adata = 35a3963b43f47855ef3df12af5de3626e0c5c8d9cd2a534c737cd695609b05a9
+Payload = cfbc8bcbb5e5bb744bb1f340
+CT = ca6a774b140c6be2f97d1c36df80fd62e751757bb0a32a987980afe6
+
+Count = 124
+Adata = 46a2e6bd3fd5336abf02eace3cd1e1f6dde505ab976a9fa596edd6fbde7175de
+Payload = a334f8f41897cbcaeb5cffdf
+CT = a6e20474b97e1b5c599010a93b211350c70adf9bab5c01081bdc6a99
+
+Count = 125
+Adata = d110651c00ac5540f9d1ed9eb175e06b97163fc36d43f048565e5d0c30a069b1
+Payload = 3f781267290e8e73c6355e75
+CT = 3aaeeee788e75ee574f9b103d7f65690d9a2fb6759d658c9bdfdfc37
+
+Count = 126
+Adata = 978644dc4e36f1d98a2a63e19bbf8af11785d09fce58a95c00cc6bf6cecf6161
+Payload = 3dc39dbb91efe8b16396d488
+CT = 3815613b30063827d15a3bfe0d5df472f49e7f713cd1373293810906
+
+Count = 127
+Adata = 5ae7528c5e965880b1533cbd78c1e81a8187379327a2fc3f76ff45829049e183
+Payload = 6caa8c0764512baa39dabac0
+CT = 697c7087c5b8fb3c8b1655b64bfca9ef00b0f2bbb03c1a3f7a0862e7
+
+Count = 128
+Adata = afe754828be6e3731d3eee54b021b4fa182247bd958e9074fb0094a11030f5e8
+Payload = b19bc92e2305883580dd7742
+CT = b44d35ae82ec58a332119834a03be1d1d262b03c0ab425d533fe4ec1
+
+Count = 129
+Adata = 0650859c635654ca4d815963c0a99f9d2f47456ad37f739c425e924d4360bd7e
+Payload = dab87e79544df1cc98096b91
+CT = df6e82f9f5a4215a2ac584e7da61ca8461925996880e2874393232d6
+
+[Plen = 13]
+
+Key = d32088d50df9aba14d9022c870a0cb85
+Nonce = e16c69861efc206e85aab1255e
+
+Count = 130
+Adata = 0eff7d7bcceb873c3203a8df74f4e91b04bd607ec11202f96cfeb99f5bcdb7aa
+Payload = 4b10788c1a03bca656f04f1f98
+CT = 89f15b1cb665a8851da03b874ca6f73242f2f227350c0277e4e72cdaa6
+
+Count = 131
+Adata = a533b3279db530eaed425842b0d3528f5c5e4c16acfa0f49de43d6491f0060a9
+Payload = de6ea86d3641d916c4394fdd31
+CT = 1c8f8bfd9a27cd358f693b45e594271cc06f81d510075728cfeb89222c
+
+Count = 132
+Adata = 8e6c1cde142e18635c1b4f0cb54d3cf817f22ad7c25bf6a022501682f6a7da1c
+Payload = 6f3b32adc8c0314872947f3d31
+CT = adda113d64a6256b39c40ba5e5ab1aefed75400a41447b2bd8f0605542
+
+Count = 133
+Adata = 248a4389da2d51b87907dc11c46253515503ba80de5d06c9b505cb89906614a6
+Payload = 0cc992a8c736b44fedb4ad498f
+CT = ce28b1386b50a06ca6e4d9d15b46b3a6463876f1a43a287748f339e913
+
+Count = 134
+Adata = 2e2c8244a2cbf53816b59e413207fb75f9c5ce1af06e67d182d3250ea3283bcb
+Payload = 98104fd3f3413ad1f57ef4912c
+CT = 5af16c435f272ef2be2e8009f8f625786bdc58af24b17c1ba34fa87baa
+
+Count = 135
+Adata = 4ada86d88d5f49dfcde13fc30ba9a1af58d5254b47fb1885a20fad915c87952e
+Payload = 3b4fec79d52d8b2a533917b75f
+CT = f9aecfe9794b9f091869632f8bd4a918290cf97208232c76908514b07a
+
+Count = 136
+Adata = 9e3b23232e5a9e69747f8bcb148cd6d282fd9b7ecd6d97e8bb5cdc261b2fc86f
+Payload = f10c19c76ae7ed55e1651155df
+CT = 33ed3a57c681f976aa3565cd0b01d6306bb91c315bb4a23fe23d496d09
+
+Count = 137
+Adata = ccea2c815ea4efadc3007f511d633e98f9fa38b0e0fb572b282ed6a610adf7a9
+Payload = fa34af376868d9a49aa200f59a
+CT = 38d58ca7c40ecd87d1f2746d4e620d9d3004587c5d510e2a857fc857ea
+
+Count = 138
+Adata = f7277fb296e2c0d2c9ceb7013ea8b59fe37e26b3b42a0b8cd01aaaa8d35283d4
+Payload = abe2fd996bb6804ed3286c057d
+CT = 6903de09c7d0946d9878189da982d2438a5138977bde5f514e2335c28c
+
+Count = 139
+Adata = 14dd1810df3eeee78ed3836c77edf510d91ea28f119bf57111e580d70da94b74
+Payload = 395ea6979b77dabd2042aee4ff
+CT = fbbf85073711ce9e6b12da7c2b78100a05448fa6e74bd3ed16c3bd364e
+
+[Plen = 14]
+
+Key = 7301c907b9d2aaac355c5416ff25c59b
+Nonce = 7304b65b6dab466273862c88b9
+
+Count = 140
+Adata = 2c5d114eff62c527cc2e03c33c595a80fe609bfc0fe13ce3380efe05d85cceac
+Payload = 484300aa3a506afcd313b49ead8d
+CT = 928ca58b0d373dc50c52afac787ce8eeb5d5b493661259a9d91ea31a5f7e
+
+Count = 141
+Adata = d9ebc1cbfab9034317132a72e0f11c341331146a59e7a2f26bf4f3d778da52c4
+Payload = 8b318f75ed79a7978adc17c4d2d4
+CT = 51fe2a54da1ef0ae559d0cf60725552193439abfedda67d765d030cef30b
+
+Count = 142
+Adata = 9aea86b9fbd9bd4504ee2e25054942b33d3cdbd84215db7ea337e548cb706780
+Payload = 0256b0d154c768c85070da6ea8c7
+CT = d89915f063a03ff18f31c15c7d3615013c2bc9338868fad0d2fac11df019
+
+Count = 143
+Adata = 08afe10bbfbd65b948a6561bbeaf3ab46a8e3d0a861f1cfc46584156197f30a3
+Payload = 89ed296a3ac03fbfb71422b92117
+CT = 53228c4b0da768866855398bf4e66c3c4cb8c50891d6523245e4c619aa99
+
+Count = 144
+Adata = 7d653792bb8683e07c7d2c800db6f7f08343c85af2377115df4fc86ff7d8fcaa
+Payload = 414b6acb1db479028f5cc8800f2b
+CT = 9b84cfea2ad32e3b501dd3b2dada792d2cb93e45811a4c897ae9d907c9cf
+
+Count = 145
+Adata = 4d73c1484f9429eb15742f29ab05cbab6552abf40e127b93427d649d195ed25a
+Payload = 163f67b3766c3c650ce26c5bd8b5
+CT = ccf0c292410b6b5cd3a377690d441983a87812eaa7b66c5a0e54a01cb882
+
+Count = 146
+Adata = 2fba7a881f019a8745691343d79ef3656e25bb37b93fb5ab7311889f92010a5f
+Payload = 9c5b4aa703c27d16d82013853e16
+CT = 4694ef8634a52a2f076108b7ebe7b0afabd23b33765a63753cad66b0e6db
+
+Count = 147
+Adata = a640343fd4a866aec07b667d25176e11a32fb4d8bfc08fde2c46dc9b492fa010
+Payload = 99eb86b3202c7ce68a2339065f47
+CT = 43242392174b2bdf556222348ab639b8d0f97540373a7b9061aa3b2f7044
+
+Count = 148
+Adata = 9efd58d3ef5f74f663b2b5ca5e96c5a2fe85ca5eac1495d7f1751c7d8b412b3e
+Payload = 3f5c1d038161e65c9ed955c961af
+CT = e593b822b606b16541984efbb45e312c803e29f7be7c5eb236401037a320
+
+Count = 149
+Adata = a7d7ba684c0903323f7efc83dc32815195df325394162fb5a18f201047be7999
+Payload = be8dea2b4e602a787ecd28f2f7f0
+CT = 64424f0a79077d41a18c33c02201fd929c717d75388387dc25bfcf90b707
+
+[Plen = 15]
+
+Key = 38be46d271bf868c198052391f8a2147
+Nonce = 6758f67db9bfea5f0e0972e08b
+
+Count = 150
+Adata = c6de3be97f11d0e2ab85c9353b783f25b37366a78a2012cecf5b7a87138b3c86
+Payload = 61bd1385be92097e866550a55278f0
+CT = 7c9fa8d99b38f825315ece6a2613f55e902f296dcce870263ae50cda4fadae
+
+Count = 151
+Adata = 7c8cf9c650511f33af82e807e60336ec086bd2d9400a5f35652b8c3fcf968ead
+Payload = 7e5e51301fa44a21f2734731ee3710
+CT = 637cea6c3a0ebb7a4548d9fe9a5c15cae8a9e4b606f5fbeac2b829b42a150a
+
+Count = 152
+Adata = 5f8b1400920891e8057639618183c9c847821c1aae79f2a90d75f114db21e975
+Payload = 9cea3b061e5c402d48497ea4948d75
+CT = 81c8805a3bf6b176ff72e06be0e670f5419c6085e5434f056162cf80f6729d
+
+Count = 153
+Adata = 238d3c9d9de32f2040b1dd0dd040b921e456c3653263f4020cffdc552b948a46
+Payload = 20660408d6890aed84aa65dfe23032
+CT = 3d44bf54f323fbb63391fb10965b377fedcc743389a9d48e6b871dc0dd63b2
+
+Count = 154
+Adata = 3b5d61ca21953fdd22280747dd4ae908a511750127875da84dfe7d0063a318c9
+Payload = 9ab83c81f2d2c896c6596660c3974d
+CT = 879a87ddd77839cd7162f8afb7fc488137e0a856d3d911af9f420b68d8110d
+
+Count = 155
+Adata = 78c1751e86144a78285a30dc04f51742bd47e3d36b607bab48d91cddabfff4b7
+Payload = c1ec469aa9c73b677af225a9f5f6f8
+CT = dccefdc68c6dca3ccdc9bb66819dfd5644448fa8445b6cd185bdf9b3718033
+
+Count = 156
+Adata = add33e9a1d7e91e2c160c1123537e3f7e3535881cb4aac1a80ecbe367379212c
+Payload = 9df1d6b6debffdd316aeb27143508e
+CT = 80d36deafb150c88a1952cbe373b8bbd38e4dc44f768cef0c51344e3a7f7b8
+
+Count = 157
+Adata = df7736560b1a13aa8e536500ea6cdb9a6757309aadf25a6a9189055a309c3f8b
+Payload = 19eef017100dc82f26ed0815c55c12
+CT = 04cc4b4b35a7397491d696dab137172e7f2ec918099898b843a34c385f2a57
+
+Count = 158
+Adata = b40c8d22069b8a65cddb51c1ea3571160cacb19fd371552436b19c7122b28d08
+Payload = 2af5db43f2a5fe8b494b40661510bb
+CT = 37d7601fd70f0fd0fe70dea9617bbe94c2709685b0827cc42f3a25b579db28
+
+Count = 159
+Adata = 9de5559ea8ccc70f4375a436ce0b72551a75960ad5ed6a1949ee8f6c47548558
+Payload = 5de41a8ca8ed8011304fa9e9f36498
+CT = 40c6a1d08d47714a87743726870f9d63bf4b40ce7e672587816fdcda16efbe
+
+[Plen = 16]
+
+Key = 70010ed90e6186ecad41f0d3c7c42ff8
+Nonce = a5f4f4986e98472965f5abcc4b
+
+Count = 160
+Adata = 3fec0e5cc24d67139437cbc8112414fc8daccd1a94b49a4c76e2d39303547317
+Payload = be322f58efa7f8c68a635e0b9cce77f2
+CT = 8e4425ae573974f0f0693a188b525812eef08e3fb15f4227e0d989a4d587a8cf
+
+Count = 161
+Adata = b6fecd1edeb55a9a4148b1aefb716a1e162779a5ab2a682e4adce4479c527bd2
+Payload = 0e6118d0409751d36cb642504678535e
+CT = 3e171226f809dde516bc264351e47cbedf7f186e8d3d7c21c549c41ebcc7f505
+
+Count = 162
+Adata = 5c3933c30bf9d4841eff4000aaa1cb4d39cdf8ef1240e2aabbf9da95bdee5270
+Payload = 5c8a5fb36f860d00c21ae9e3f24097c4
+CT = 6cfc5545d7188136b8108df0e5dcb824810a68be1814f53c09aca4066527fef8
+
+Count = 163
+Adata = 7ca7ef30d3ac08aa51a9e5d3d84e8b6bb7fdde921e72b98ad6a93ebf2efc6b04
+Payload = ebd1cb4b35257790c9806be476bd25a3
+CT = dba7c1bd8dbbfba6b38a0ff761210a43cc30245a6e64625c4f6531d7497fb144
+
+Count = 164
+Adata = 90f1416768fca7dd48d01230dabf95f2f1a0c044bf2d755448aaf72316c8448c
+Payload = 842b7e5f22d921b2b8ab3131684b7eff
+CT = b45d74a99a47ad84c2a155227fd7511f10d85725dacc274034669acf7f34fed7
+
+Count = 165
+Adata = adc5c36849283d57acb2bcbc0e12465cb7c1830cb4e314b9ce6e25acbd8d460c
+Payload = f0c2cc5a1b4c4cbe839338fa0d7a3435
+CT = c0b4c6aca3d2c088f9995ce91ae61bd5f731b465eb59c4989e42020d86102a59
+
+Count = 166
+Adata = 80a7a483d1dbcdf00ed02a700e93d8b87fa6ac5c7368d1e81bd1b32cd1621cd7
+Payload = 2c1a5f906f2ae0373cc25e3519df2ba4
+CT = 1c6c5566d7b46c0146c83a260e43044484bcd2775448447ed801b3b0ff071c19
+
+Count = 167
+Adata = 13c02992992d2708250184a579c43bc29a3a8cf1e02dade4496cbd8b1214f97d
+Payload = 1da5190517546f1ad852f64263e1f679
+CT = 2dd313f3afcae32ca2589251747dd99901d1919f1451ad16f115cde863f15303
+
+Count = 168
+Adata = f6f18dfe093e4c0c3fbfa8a5b1f4a703c08addc2ab959741611a594b93d08bf7
+Payload = 13ccb08a580efea53dfba6a59626bbe2
+CT = 23baba7ce090729347f1c2b681ba9402ccae4f6ec07bf73d6f086cf09e2e14ed
+
+Count = 169
+Adata = 63708e12dfa14f192ec5ee5856dc3cf2403817d9628c31899b4613f65e1e61c2
+Payload = e0b5fbc6c2269d445a60273bf844892b
+CT = d0c3f1307ab81172206a4328efd8a6cb2bad8bf67d32a855c3940ac908397a5f
+
+[Plen = 17]
+
+Key = 79eae5baddc5887bdf3031fd1d65085b
+Nonce = 9da59614535d1fad35f2ece00f
+
+Count = 170
+Adata = 46603500af9e4e7a2f9545411a58b21a6efd21f2b5f315d02d964c09270145b3
+Payload = 001343e6191f5f1738e7d19d4eec2b9592
+CT = 2162e27bfbf1d00f2404754a254665fd9270f0edb415993588b2535e2e0e4fd086
+
+Count = 171
+Adata = 278afebc604bb7d87bed3574a2c5053de17eb8ca7e18ddc7892f2c54b38104a8
+Payload = ba47d5bfb36f6150a100e36caa116405c4
+CT = 9b3674225181ee48bde347bbc1bb2a6dc4778e3c4a11f3f9dc42554d45796379ef
+
+Count = 172
+Adata = 3239b2ce4efe4f6a6255dc53347400a6446ed3280c65422386fab471ef09eed6
+Payload = 96eccb7f9b0e16c6883de0a381e4767f5a
+CT = b79d6ae279e099de94de4474ea4e38175aab5540cc01d867f641c9b196fa159291
+
+Count = 173
+Adata = e2a5488d5f7930ea4ce399f2a6c0810265f7c0dc52fe824d19a0fa0d9ffd55e6
+Payload = d68f5990da1a2fe39ed81af145ab834fa4
+CT = f7fef80d38f4a0fb823bbe262e01cd27a46366fbe302e142dcf6aa16337d98550f
+
+Count = 174
+Adata = 0071f1edb3a0ce57af3c88bb0ccf138f752697a77e55695838fb39de04c78dfb
+Payload = cdd4d8b3d8f6e4742793b456cefc9e686d
+CT = eca5792e3a186b6c3b701081a556d0006df88c07797267bf5a49b3d0f601a225ce
+
+Count = 175
+Adata = f5d6989587e463969d97aadabea9538511f8d109cc2d3cecf09ba7cc346aaea0
+Payload = e7d7fc60ae852b68102e01b506f9dab986
+CT = c6a65dfd4c6ba4700ccda5626d5394d1865c9fbf69d81cef238ac513562d4a0dd5
+
+Count = 176
+Adata = e0b5fbc6c2269d445a60273bf844892b26fed03b82869edacd6dd7a63fd69e8d
+Payload = be9f51abfbe2da5a56db0f9a31b67c9f83
+CT = 9feef036190c55424a38ab4d5a1c32f783e2c748c8c9e3190de095de8eb0650203
+
+Count = 177
+Adata = e6bd0010c98e60b9af7cf905c58e0653bc425e2ccc809bd4f9cd7b1f95c18786
+Payload = 81b9c73029cea1936ef8755c80ba8d4093
+CT = a0c866adcb202e8b721bd18beb10c3289305cf563c5b4ba4ebd5bf107f2ad3555b
+
+Count = 178
+Adata = b1688cbc058816974694cd26c0f28ba9418e9912867fc8c5f4e7bd9c891a8d2e
+Payload = 618dc26853ee339689467ffbc2a77be69e
+CT = 40fc63f5b100bc8e95a5db2ca90d358e9e60dbbd8f46343c8442b03a472da4e23f
+
+Count = 179
+Adata = 469e004fee9878ed40621b41d04ec34af175f213d64d16e2f77d0bb2b6efe2e3
+Payload = 4f18bcc8ee0bbb80de30a9e08629323116
+CT = 6e691d550ce53498c2d30d37ed837c591643352e46995e8c1aee43dbdb26b46c30
+
+[Plen = 18]
+
+Key = c14eda0f958465246fe6ab541e5dfd75
+Nonce = 32b63ca7e269223f80a56baaaa
+
+Count = 180
+Adata = 733f8e7670de3446016916510dfe722ce671570121d91331a64feb3d03f210e6
+Payload = 617868ae91f705c6b583b5fd7e1e4086a1bb
+CT = b2dc1e548b3d3f225a34082f4391980a0788b4cc36852fd64a423fb8e872252b248e
+
+Count = 181
+Adata = b6ec659856866959ef6fd4e71ba930f0e3e5fd49d7465fd65f6813ab4ca1a770
+Payload = b8b342c49c28bffc2a1c457db0b537ad46bb
+CT = 6b17343e86e28518c5abf8af8d3aef21e08895a66eb5b902bb23a1a8584249409fda
+
+Count = 182
+Adata = 89eb3636fff80230352a3582be5698e3401c9e0579d48f2680c6e5e24d99f74b
+Payload = 37d694ba94d0af8df662134f20d142903839
+CT = e472e2408e1a956919d5ae9d1d5e9a1c9e0a7fa792fb7246218f7d56d5fa4a5476bd
+
+Count = 183
+Adata = 03434f3709e19a1e37edfcaabc215116763b71ab1c5e053dbdb599f86959f25d
+Payload = 90e4c0550cb7b279ef61f9140b7d94b8003d
+CT = 4340b6af167d889d00d644c636f24c34a60ea83dc3f0012ae6da32a15fd1684835ef
+
+Count = 184
+Adata = 0e2ddb65fcc72094ac388d53a1055c7e902285c4c3c33c13bb6fbb4f1956414a
+Payload = 69b851e63a78baef90637978e3dfe8c47be4
+CT = ba1c271c20b2800b7fd4c4aade503048ddd7f09d38d3dba01995e36bd685c8ea3371
+
+Count = 185
+Adata = a42b2538ee2fb5f6a85d4d00524b01ad3331f61c404069243f35f28e2c2d0a82
+Payload = b7dbf8382115199dd2a2d87938c6ae6c4241
+CT = 647f8ec23bdf23793d1565ab054976e0e472c89becf8d2bb935cb17f44b950df3ef5
+
+Count = 186
+Adata = 09bc5c426dc1faa4d71f50908bd6f297ec8e754d4d20def005585b4bc1fa31da
+Payload = d53698d719c51bf9eae346269c6a1da07162
+CT = 0692ee2d030f211d0554fbf4a1e5c52cd75196e28badf0202097e80561451796194d
+
+Count = 187
+Adata = 2ac87e59c2c86532cf165af3e8ff4871d730f5e742cccca38bbcdffff4472c93
+Payload = cfdb7363985aa01af6f8e8237dbfb7871eb3
+CT = 1c7f059982909afe194f55f140306f0bb880710d4d7f66660891ac655d6eca4a3f3e
+
+Count = 188
+Adata = 05d2fbc3d0ec81f52f31cb0c4bf960c2076867f6d9f0174ed9176e20177b2693
+Payload = 56fdf10dc0c1dfd10965b83938e557459c61
+CT = 855987f7da0be535e6d205eb056a8fc93a52f90ab18925fea6964490f364a975a473
+
+Count = 189
+Adata = c2c3902cfe8622254b3787cc13e79c5a3c388c2357c29f1c1ab5539a10bfae5c
+Payload = e7c9812eda2ed7dcfc80fc5fe0d43e1e5982
+CT = 346df7d4c0e4ed381337418ddd5be692ffb168a00e5e7a39b371024927d3ac98fe43
+
+[Plen = 19]
+
+Key = c5e7147f56ba4530b8799ababeb82772
+Nonce = bdd38e173fb20b981659c597d6
+
+Count = 190
+Adata = 3a069a2bfda44abbb0a82a97e5e9047258c803da2c66190d77149e0f010b3af9
+Payload = 2f3bf0b566440912a1e47a0c07f1cfd39cb440
+CT = bd6265dcba9e14c59e515e395dc60bd053345fa6d7568c738e3a7fdf142d8f2d1562c0
+
+Count = 191
+Adata = 7709132415c94960025cc39c950ead208703a9d5a71e224fd022dc0a1817d0f4
+Payload = 7c880d787726c4ddeb2304b5d161b4a257298e
+CT = eed19811abfcd90ad49620808b5670a198a991f22337efa5cb7db7240e7518b67ffbb1
+
+Count = 192
+Adata = aad77595f87a27f2c7995fc7149317f4cbebcece8336db2068380070784a4283
+Payload = 08c43bbfa706512aa39e2bfa5c365aca11e22e
+CT = 9a9daed67bdc4cfd9c2b0fcf06019ec9de623140bac6094528f02eeda093312fcf716f
+
+Count = 193
+Adata = bdb1b82ba864893c2ee8f7426c7b9a8460b00a50f164fc8f2ff2ae9cddab8657
+Payload = a531c0ed8840b2fcf08d76eca71036153b6e11
+CT = 37685584549aaf2bcf3852d9fd27f216f4ee0e0c041d86dd483c1d6da366e91bd826dd
+
+Count = 194
+Adata = 38b3b9f45041ceb743fc2655b409213fa081427e41c833a2321a09fbd566c80c
+Payload = 177946b4dc3b0b825a505f097a0a203eb21c00
+CT = 8520d3dd00e1165565e57b3c203de43d7d9c1ffde45ca2a83dec2f930bb652a6fcdc5f
+
+Count = 195
+Adata = ec9d8edff25645520801b6e8d14a2fc3b193db70d5e5e878742de83154a578da
+Payload = a2634ef20a2a418b2c3be64f0b5f79d7ea9b7b
+CT = 303adb9bd6f05c5c138ec27a5168bdd4251b648b89aa22cd7d0170a975565cd3a33dc1
+
+Count = 196
+Adata = 8f6c1de4efdc5ac2d6e5452b5b4f58416d618da672f521332fd297ede8350134
+Payload = 40e52edaad5acf2d4eedfb3f9ac2908112e9b1
+CT = d2bcbbb37180d2fa7158df0ac0f55482dd69aed960b33c3df5cd38a82980dc0950ada4
+
+Count = 197
+Adata = b0f1dc85fe223bcf29cdfa9319866bacd0a0a79c554e24d1f10889279e31c0af
+Payload = bf97780f498c23adcf1c49f60873780a235969
+CT = 2dceed6695563e7af0a96dc35244bc09ecd97638fa273c4102b5ca050b23044ac2064f
+
+Count = 198
+Adata = 7d02a323aa769a8201549bf48a520d940bf6f69ed6106f1ce68856c22a594216
+Payload = 58bfe1eb2d38d91f80b3467db94fdcb84ff5f3
+CT = cae67482f1e2c4c8bf066248e37818bb8075ecc15438af1bafac3eac61e1c24ed00ab7
+
+Count = 199
+Adata = d4b90ef8abad08c552c8c3b080b8c37df314d514049d45e27ec4527cb06cdf85
+Payload = a206a1eb70a9d24bb5e72f314e7d91de074f59
+CT = 305f3482ac73cf9c8a520b04144a55ddc8cf464422d9e2f4f84fde49e9701296294d5a
+
+[Plen = 20]
+
+Key = 78c46e3249ca28e1ef0531d80fd37c12
+Nonce = 5de41a86ce3f3fb1b685b3ca4d
+
+Count = 200
+Adata = e98a77f2a941b36232589486b05f4278275588665a06d98aec98915cc5607e06
+Payload = 4802422c9b3b4459ba26e7863ad87b0c172cfe4b
+CT = daea2234ea433533bf0716abe1aa3844b6d3c51e9d5ca3d8ec5065630d2de0717cdeb7d5
+
+Count = 201
+Adata = 5970a836de1f1e91d94d7eef79742cbbd46a759c413715eb0224fd6a27145333
+Payload = 796a69ad0e9379173ef6b66f44f5c84fa70a0e28
+CT = eb8209b57feb087d3bd747429f878b0706f5357d0ff0648ddb07f42f815b38bfc95688b1
+
+Count = 202
+Adata = e3f08834c4894f6fa66a55a280c0e677a79e97c1ef9488b21384e74e57b1b51f
+Payload = 98e1f8cf250183b13ad418024dc40c1a6a7ee8ac
+CT = 0a0998d75479f2db3ff5e92f96b64f52cb81d3f93ddd9a6977ea8e7adf5c5234346e560f
+
+Count = 203
+Adata = 18349be2894d49290339b97f4db28c92b3e112ffac77100abbf9c093935b1a46
+Payload = 4a856d9b50a5b40d6566b38eae6a53ed0c192805
+CT = d86d0d8321ddc567604742a3751810a5ade61350bdee05328a7ea8cc6c2e42bf3faeeda0
+
+Count = 204
+Adata = 7355e34ad13880de17a1d66b02672ea5c9f51774019f64ecbe36747ffcd9b671
+Payload = ad048eb2ad75266b43b59d9d1f073c44e4cbf25e
+CT = 3feceeaadc0d570146946cb0c4757f0c4534c90bafb1435cf929db35ec5986aabaf4a7d1
+
+Count = 205
+Adata = 4be21ba2eb26234ddcbb6aac6b4c3be7ef644af64edf51b7c29ffc3ddd80036b
+Payload = 5b527ac6cc6d1b4c3c56f8315bc96dae91632df9
+CT = c9ba1adebd156a263977091c80bb2ee6309c16ac736be6563cf9f5bce97486b7cc6f1c18
+
+Count = 206
+Adata = 266e0e3365e06d3b1e864c6e5897145df7bdde90eb744013a7b36632d4cf6580
+Payload = cee059cb0fe91a39faccc2914340baeab4b644ce
+CT = 5c0839d37e916b53ffed33bc9832f9a215497f9b2e90335fcea56b969b4fce65442768dd
+
+Count = 207
+Adata = 55a723883a340877d85ad1a5f264f2c834d824c7bbf207cdd8500c9d11ef9225
+Payload = 85321fef6a2b7d31cbd079c4bf2bfbbc979df90b
+CT = 17da7ff71b530c5bcef188e96459b8f43662c25eacd6afdb3578ebc75e8a408d32758931
+
+Count = 208
+Adata = 773864475a1a60a778468a66cbe13dfe3458094e62abb593f50c8495e3a8b81e
+Payload = e227b8d44320bd3ce9d3f7d688f3de887947b1e9
+CT = 70cfd8cc3258cc56ecf206fb53819dc0d8b88abca19fb73fc0488d9f29a09c1b47e3e066
+
+Count = 209
+Adata = f64f3b00c9117aed3c486aa4c8d574b44d679be4069e1078bb7100af38cdb190
+Payload = 206e9eb2bc3f8534d844a38debf1306df808744a
+CT = b286feaacd47f45edd6552a03083732559f74f1fce2c5ef8cdce76b358739e2a1b173fb3
+
+[Plen = 21]
+
+Key = 8883002bf13b3a94b2467225970df938
+Nonce = 818a702d5c8ee973b34e9acda1
+
+Count = 210
+Adata = 545aeac737c0ca2a3d5e1fd966840c3a0d71e0301abbe99c7af18d24cc7e9633
+Payload = d516bbff452e7706c91c7ace3e9baa76d65ff7050f
+CT = b85242fdc06344f2bd9a97b408902ebcd22aece3d42f2da4dd4d817c9fa2d44bc02163a0a9
+
+Count = 211
+Adata = f032db01da60ca078d35c3fb5d05d6750fce1c01911a0422e827e8976946e4dc
+Payload = 590d1aa655fed50ca2e402299f2da6fe20eed56071
+CT = 3449e3a4d0b3e6f8d662ef53a9262234249bce86aa180f41bccbcd47c8b7890754c032269b
+
+Count = 212
+Adata = 71ecb4252518997b53491cf42a3e0fe1496a2af2329a16f9fcd9c4f249900341
+Payload = ecd86cdb7d78d310dca5b477cd9da2612f5a05ab39
+CT = 819c95d9f835e0e4a823590dfb9626ab2b2f1e4de21d6ba58cc2eb474401851bf9502c3413
+
+Count = 213
+Adata = ec7abed9bda4a52fdf1bf278b6bdd6b0a27d4688deb9ff5ca9c8c865a4d2f730
+Payload = 0024b14c283df032cf80c22ad8d2c96289ee229092
+CT = 6d60484ead70c3c6bb062f50eed94da88d9b3976499b94d4b7a2044696c72322e850537b6d
+
+Count = 214
+Adata = c2c77d7ad7b27d7c0f976a1e28881ea4ec7ad03b63a4e67f47280a40b8f58086
+Payload = bc6965d8f62d066d118c14044c1fd2a224b9d95110
+CT = d12d9cda73603599650af97e7a14566820ccc2b7cb9d8da8e718570caf8bed7909fbff3ec6
+
+Count = 215
+Adata = 28929286bd1391468ac75f5c03689f74780ddd7585fc16f9a9bf7b00357a72e5
+Payload = da4a630cabaff0728a1cc3e6a79721a7176b708f1d
+CT = b70e9a0e2ee2c386fe9a2e9c919ca56d131e6b69c6e671012690c61fe3c9abd50a78eb4736
+
+Count = 216
+Adata = ed360d22081b019dc979420a3a45c21c8903c59daedd9f1b4ef2bfdedff0ec1d
+Payload = a95058f8e1f6bc0f143a9ca7e4425a2a63eb2f7e33
+CT = c414a1fa64bb8ffb60bc71ddd249dee0679e3498e8e657e2250427130acef7032454cde7b6
+
+Count = 217
+Adata = 2b4022d0b951fe48635d04fb3e2fa032c07c855fdd73f45670953bb9ddc77cb4
+Payload = fcbbc7f9d1ace60e830ca56ec84814fbd2579993d4
+CT = 91ff3efb54e1d5faf78a4814fe439031d62282750faac6ff0a264b8199550d93c1f06063da
+
+Count = 218
+Adata = 48e553a87a7d3c1bd68af39f96aca67583da86e06701d5e4c4ed404dc66d70f3
+Payload = b95d298d391c6b893c6cad66f9780534516e71455e
+CT = d419d08fbc51587d48ea401ccf7381fe551b6aa3857e68bf636e81c332f72063dc0d6fc2b6
+
+Count = 219
+Adata = e8e2835e47144365a2f218d4c95d7522e824fb43b66d4727ee570f8303dd6dd3
+Payload = bc79d444dff9d9e722effab07b068cb7723ae8fae0
+CT = d13d2d465ab4ea13566917ca4d0d087d764ff31c3bdf3af9e9c4e04bad261dc17cf00a00dd
+
+[Plen = 22]
+
+Key = 5cea00ee44cfb9cfbb598d3812e380ef
+Nonce = 948788a9c8188cb988430a7ebd
+
+Count = 220
+Adata = 50422c5e6a0fb8231b3bb6e2f89607019be6ad92a4dae8e0fe3f9e486476004b
+Payload = 33bfd0713f30fcac8f7f95920ac6d9b803ddd5480dd8
+CT = b168747dea3ae0fbede4402af9a3dc3185d6d162f859d828101682de32923788c70262b84814
+
+Count = 221
+Adata = bb0036b34b0c20094d335a8c74f6b3dea42eeccf4145192eada64ae00c726b2e
+Payload = 5576d94b577ed26820fb13c00ab0e2d1a1c3589bfdc4
+CT = d7a17d478274ce3f4260c678f9d5e75827c85cb10845bafc4ae4d31907def6f648b081174e2a
+
+Count = 222
+Adata = 5140324aa758dbbb5391b5e6edb8a2310c94a4ae51d4fba8a7458d7cc8488baa
+Payload = 13303e14068205cbfa992d4ccb6a265804ea64a15d7f
+CT = 91e79a18d388199c9802f8f4380f23d182e1608ba8fe314e378e9ed6e725a14c07632b02bdbd
+
+Count = 223
+Adata = 74da07d324060e590356988f27d9879fa3a3ade0fe71e2a0e49054211cfa1fe1
+Payload = 567e6d14b446add630d53ea86a537c0938537c4604a8
+CT = d4a9c918614cb181524eeb1099367980be58786cf1295bc2f2f9331536f7f70be09c41bda0ad
+
+Count = 224
+Adata = 0e403cff47adee3ec5bb6b178dabfc7d53b60a04eaad33a2fedd9db705358a4c
+Payload = 9f3d165d44cf1c5770346d211d4ff34ca2ecd6b28549
+CT = 1deab25191c5000012afb899ee2af6c524e7d29870c86b59cc9c3c008bc5876ef86327859cbe
+
+Count = 225
+Adata = 211e6ce3d0c3abdef069e6e4fa35015797bd8a9d64bc9b75f20b028b12cca04a
+Payload = d726e599db6a6d40629bc4bda5e3fa2e5aeda229cea4
+CT = 55f141950e607117000011055686ffa7dce6a6033b25135e6d59a5385a78658d60d254f99962
+
+Count = 226
+Adata = 3c5c67b083322115e1b3112c2b6968efc050094e23e646dce982eac9d6e67d10
+Payload = 42646cfb8a99e48a35cee3f5f9b3e6175695973f6de0
+CT = c0b3c8f75f93f8dd5755364d0ad6e39ed09e93159861e234e83d9a0570dbf2b2fa59ce3cdbd9
+
+Count = 227
+Adata = 37a931f1dd05755b376d1a164aa36b8de802e39f8108a0453c1114754665fe46
+Payload = e814c7b5c72d973a9bc7ccd463f107325ffa3321783b
+CT = 6ac363b912278b6df95c196c909402bbd9f1370b8dba2084e352b1b157267228576dd056c1a3
+
+Count = 228
+Adata = f1ddc2c49da7363526ba36c600c589b4c3121fbb8c5b9a8aa0de0e7453b30568
+Payload = 4f7a5618870945b89f194e31b1aa802c5350326dc691
+CT = cdadf214520359effd829b8942cf85a5d55b36473310bf88ad35ee338e489e55bb49732447cf
+
+Count = 229
+Adata = d14b3d3803df432488b5d66704abef6a500d397e855bc2c2574df746a515cf70
+Payload = f555216840a1f40b411d44128e567617e2694caf1621
+CT = 7782856495abe85c238691aa7d33739e64624885e3a07ab67f9397a81371ef6ebc775cb7007b
+
+[Plen = 23]
+
+Key = cb83f77751e72711401cbbf4f61aa0ed
+Nonce = c0b461b2e15b8b116ef9281704
+
+Count = 230
+Adata = 2bd112231f903fa0dff085db48a2e2a96ec0199249b005d5ab4c2eab753f9ad0
+Payload = eede01b08f9a303cdf14c99d7a45732972c6eff2a1db06
+CT = feb114b7bd3b43497b62454a675a632c3546d2802462c6af57647efda119c59862cd5dd3904efc
+
+Count = 231
+Adata = 864e0e728aea856fae6c6daa6357d1542cef7177f441ba21a563f6c4f6fdc1dd
+Payload = 8a56588fe5e125237b6cdc30f940b8d88b2863ec501a0c
+CT = 9a394d88d7405656df1a50e7e45fa8ddcca85e9ed5a3cc2af4027ca5824b41c7bb238d3e8eeebf
+
+Count = 232
+Adata = dac7f3cba0b5a47f67f85b226b66df695a8ae2501355e36aad105375bb95f732
+Payload = 66e34540d7accf377877aa2d3e6d2db0cfafc608a1eb3d
+CT = 768c5047e50dbc42dc0126fa23723db5882ffb7a2452fdf7fbd7044ce1d7b266bdf545247a3c2b
+
+Count = 233
+Adata = 07f48cdc12aa27119fbdfda4ec07ce6068c92ba7ba9c930905aadd156b1dd56e
+Payload = a9ebd04fba7155c39b5c29c5571b5354c9ae228f5e5b13
+CT = b984c54888d026b63f2aa5124a0443518e2e1ffddbe2d3afabc559b552cf7c7730c7dca25bc3ed
+
+Count = 234
+Adata = 2d24e79abd157af2c21b60932947fd9f9d6478f09ec56fffd341ea04a17b8e5f
+Payload = f179353aef342f0f691caf1fcb811e3f6504e14d6d9381
+CT = e116203ddd955c7acd6a23c8d69e0e3a2284dc3fe82a41488ca99e0f85ac388f981ce25560b8f9
+
+Count = 235
+Adata = fea280f710379e4665b5ed3d1620729a7bc164899dc83e6aee3612d538fa20db
+Payload = 6c19a18eab544acc883c5886eaa89f54d61ae5f1f1368c
+CT = 7c76b48999f539b92c4ad451f7b78f51919ad883748f4c9156faae3d8860bed216e8d497a75962
+
+Count = 236
+Adata = 18f2e3457127c35f2e0cff2d821af8178028fcc7803bc795c49f4a435b37abeb
+Payload = d0df1bdf1df6203241722fb9c9c1cf7405017497ae1545
+CT = c0b00ed82f575347e504a36ed4dedf71428149e52bac8588cd7791c544d1098b2de49d04b1e0c1
+
+Count = 237
+Adata = 35221f0efcb109cb93c38a62c58b5ab8b236437e171e8507cf417a569af1767c
+Payload = 479526b33c42c240b9a4549ca70cbfb691f16ae3be8888
+CT = 57fa33b40ee3b1351dd2d84bba13afb3d67157913b3148c523fd8a2524717f63dac75c22268fa6
+
+Count = 238
+Adata = 95f2ab02af01aeacce86b02cf846f9fbd516963d06e350e8b7f6df2778765a01
+Payload = aa6761148b254a2ff202b620c2ec2c5e623bf61f05e483
+CT = ba087413b984395a56743af7dff33c5b25bbcb6d805d4392904f05dc2397596543df73de5aa708
+
+Count = 239
+Adata = 3746a36154e42dd600049d506f5ce4d034864263b1a65cecd24c8e25fb9c82e1
+Payload = 2f298f106703b8a994cbb20acf47f9442e44f6b5e82c38
+CT = 3f469a1755a2cbdc30bd3eddd258e94169c4cbc76d95f8c3cbfecfa3f75fb111ef0011222b7948
+
+[Plen = 24]
+
+Key = 43c1142877d9f450e12d7b6db47a85ba
+Nonce = 76becd9d27ca8a026215f32712
+
+Count = 240
+Adata = 6a59aacadd416e465264c15e1a1e9bfa084687492710f9bda832e2571e468224
+Payload = b506a6ba900c1147c806775324b36eb376aa01d4c3eef6f5
+CT = 14b14fe5b317411392861638ec383ae40ba95fefe34255dc2ec067887114bc370281de6f00836ce4
+
+Count = 241
+Adata = e82fc3ffd276218a82aede65fe5abf4fd35c7059a26923f8dbb97a59c903a7f4
+Payload = eab8cef576816a82ed036f158e5036f5987b195e60582a6f
+CT = 4b0f27aa559a3ad6b7830e7e46db62a2e578476540f489460d2d30268e9f1ce0e7c762993297d828
+
+Count = 242
+Adata = 776aae7f62225556b6da522c0c9432ac70fe72ac6f3f361071ef3deb4a6715e8
+Payload = 566ef9ce1d397be2547c385639507a9e7d6f9eed9a3b1055
+CT = f7d910913e222bb60efc593df1db2ec9006cc0d6ba97b37c0939e56f0b7200d1b1409f3f8e8179cc
+
+Count = 243
+Adata = d9aef0955922f89747ba4a8ddcdb8c1c7579aefd3c2eb8ad0589c66576a8504c
+Payload = 8c28b6d93b23f1ea031d5020aa92f6608c3d3df0ee24a895
+CT = 2d9f5f861838a1be599d314b6219a237f13e63cbce880bbc138e3b817023993608be06fe92efca8b
+
+Count = 244
+Adata = 13c222a65ce30570ecac85a185a2a0922a8c96d633339a1ca067ce57ae426e1d
+Payload = f0c1cd60f5fa8d1efd5e2e1ab37c4f7e6aef76d15e8d6ac8
+CT = 5176243fd6e1dd4aa7de4f717bf71b2917ec28ea7e21c9e1f3ca13b4ab7fd0d4badf158972570c06
+
+Count = 245
+Adata = ce40fb0cbfdf07676ed55b040ae6be5db8f0a0f28816ae8ea71da3cbd71661d8
+Payload = 570d5f79aa8db14b1ac99ee567cc105ae9e238e482b52628
+CT = f6bab6268996e11f4049ff8eaf47440d94e166dfa21985010a79fa4e8b27a31ff360a1b6c05ff844
+
+Count = 246
+Adata = 446b01d09cbc41b6393ef81ca65ab7e099018187d5f9d22f5074dfc491e72077
+Payload = 7c267223047af946b06f6a45ffde4a5ec49c28b81ca22da4
+CT = dd919b7c2761a912eaef0b2e37551e09b99f76833c0e8e8d5d34ef0ca0b47d6a2ec7442cbb739504
+
+Count = 247
+Adata = 01ec87920b42639d4ba22adb1fbe5138d2849db670a2960fd94a399c1532ed75
+Payload = cbf112e4fb85276c4e09649f3de225b2398e86ac3fe48bc7
+CT = 6a46fbbbd89e7738148905f4f56971e5448dd8971f4828ee8f607d154393e35fd1efc1ae8cb244e4
+
+Count = 248
+Adata = 5032b818d202872f3fe2b08fc7940696df02cf393a6d6247f5c6f5f2125cb08b
+Payload = 4324a89788e8ddae5d560cf937df701743cbbc3bf980558c
+CT = e29341c8abf38dfa07d66d92ff5424403ec8e200d92cf6a5617d9cebea38591a00c9fba4ef9c8e71
+
+Count = 249
+Adata = 27b661861717f00a3ae22ead78f4dc3f32b40e8fcb8ed58167a31a61f2becd77
+Payload = db72d98d63fc10acff7dceec0e2691a80ecee50a0e957ad1
+CT = 7ac530d240e740f8a5fdaf87c6adc5ff73cdbb312e39d9f897062a1ec759a515b938780f902fa7c2
diff --git a/lib/crypto/test/crypto_SUITE_data/VPT192.rsp b/lib/crypto/test/crypto_SUITE_data/VPT192.rsp
new file mode 100644
index 0000000000..abf1775dd1
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/VPT192.rsp
@@ -0,0 +1,1383 @@
+# CAVS 11.0
+# "CCM-VPT" information
+# AES Keylen: 192
+# Generated on Tue Mar 15 08:09:25 2011
+
+Alen = 32
+Nlen = 13
+Tlen = 16
+
+[Plen = 0]
+
+Key = 086e2967cde99e90faaea8a94e168bf0e066c503a849a9f3
+Nonce = 929542cd690f1babcf1696cb03
+
+Count = 0
+Adata = 58f70bab24e0a6137e5cd3eb18656f2b5ccddc3f538a0000c65190e4a3668e71
+Payload = 00
+CT = 3bf9d93af6ffac9ac84cd3202d4e0cc8
+
+Count = 1
+Adata = 760d065275e345900a7bbab451cc9309fb161e6cfec526538b98800e4102e14d
+Payload = 00
+CT = b0078a769ab68db44e723993da382abc
+
+Count = 2
+Adata = ffedc67efd355ea404fcbcb3993d3bae81386ded86230270771deb747163bf44
+Payload = 00
+CT = 31fbff2d715a2eb9af54e8320a8e42e1
+
+Count = 3
+Adata = 55153ff5e4d208d2e647794f382c788e0e36f293e63e7290ba9ff2657ae0f167
+Payload = 00
+CT = 945839d62c9d1b899f6dcd0ca9517e68
+
+Count = 4
+Adata = f8813985f59bf284bd3882e899ca9b67fb496f3eb78d7ebe6ffbad084f639915
+Payload = 00
+CT = 903f90d23321a6882d6c4c1955b14847
+
+Count = 5
+Adata = 7b95cd827ab93507f1819ae76627d6e2a31d29890c092e5c300f0e2f9e4ef4d2
+Payload = 00
+CT = 652ec5ab43088eb568186d0d9887b30f
+
+Count = 6
+Adata = bd144c9bb974729aaa1188ceefdf85e1d9fddc0b0c8afe8828ba204aa9293feb
+Payload = 00
+CT = e6c1455d1117eec49338c96f51007309
+
+Count = 7
+Adata = 92b911cdc3137a6f7f32651b788eb82975660aea52b2c03b4759755a6da4a0f8
+Payload = 00
+CT = 1cf3c32fb229dac209523eaa517bb59a
+
+Count = 8
+Adata = a8200dbbfe4086015cdbdec2fc8e4934d0d663527430c424627ed44065ade091
+Payload = 00
+CT = ee10bfeb1cf9b3cd5a0faebd4d8f3fe1
+
+Count = 9
+Adata = 3b7f37b6b8e3c1390a99d59c47f7c102cf659d361a132ef8b4e70b9585bafebb
+Payload = 00
+CT = c51ed994253adb9bb5b9a8c34a27f225
+
+[Plen = 1]
+
+Key = 992d38768b11a236945bd4b327c3728fac24c091238b6553
+Nonce = b248a90b84b0122a5ad8e12760
+
+Count = 10
+Adata = 27cabc40da0e1eda0ea5f8abbb7c179e30776250a7b30d711b0e106c5ee9d84a
+Payload = 1c
+CT = 1a96f58c3f38c44d1a345f3e2da6679f20
+
+Count = 11
+Adata = dc2e28d5ae726c1beadb1e7e92ae7d14f5546320deb81a910bf170cbe0210eaa
+Payload = e9
+CT = ef0579aee7c17482691f3f832d867ffea7
+
+Count = 12
+Adata = c579f912ac1b45d5aa8cf20f78f0a1ace32abd3dc7fd0b3f3a7182a008795c7f
+Payload = 97
+CT = 913452d8ece38ffa1d4107d6a053acd8c8
+
+Count = 13
+Adata = 69ea953dbb910ec589372d797c7379d3f3b9e9fd48894c9b55e6e8eb360a6211
+Payload = f4
+CT = f20d760b9fe29530738157db0ba2d253f0
+
+Count = 14
+Adata = 622835dea57b2c70cca8f7548d6210714070b55b36adde7a4c547269c07aba9c
+Payload = 9f
+CT = 996fc21f24dee7b52f51d69eea30819f4a
+
+Count = 15
+Adata = 67ebda0a3573a9a58751d4169e10c7e8663febb3a8cf769d81bc872113f0720f
+Payload = 43
+CT = 4594c5b8db0064426a77dc536814c56147
+
+Count = 16
+Adata = 255412e380e9a28cbcd345be172c40f72dec3e8a10adfd8a9ab147e9022524e1
+Payload = c1
+CT = c76d36c0b0d699a22da3116dfb8f453181
+
+Count = 17
+Adata = c7c8e7151eb6844a954d091b460f83add0f0a634aa5ac213b774f2451aa497fb
+Payload = 31
+CT = 370c3a1690acc3f0eb09c9cfd3396c7fa9
+
+Count = 18
+Adata = 63f00b2488809fdc49ca5f05d54e98468906308115f7e702da05ddfd970b5537
+Payload = a7
+CT = a1ad45070fe4c61270c13cc52247fee411
+
+Count = 19
+Adata = 8e2c5e55c0bf70014e9897b6f6940e4e738b1e84e8269b6382f0b1fe59b0e162
+Payload = 40
+CT = 46b2a2a8b283ff7eeff5c2670f77b8809d
+
+[Plen = 2]
+
+Key = 5012db40ff6ae23c1e1ce43768c5936c4400b0e79ae77f30
+Nonce = b67e500b35d60ad7264240027c
+
+Count = 20
+Adata = 40affd355416200191ba64edec8d7d27ead235a7b2e01a12662273deb36379b8
+Payload = 0c6c
+CT = c996ef3d6ef9f981557506ecc8797bbaaaa7
+
+Count = 21
+Adata = c5e12e17e02bcc12b3a4c14cf837250e2886db3ee1c717d28bd11e8a3b764ddf
+Payload = 23df
+CT = e6254405257a837c5343b59d5689d6de5269
+
+Count = 22
+Adata = 213b5b6015d472bd593be5acf85ebba6d6a09f3a962be302ba83c6d70c61f241
+Payload = 0dc2
+CT = c838e93e67d37d2367bb1f27f71b54b29317
+
+Count = 23
+Adata = fc1b6e152fe232b6c10b5d89900961c445f4c46833df242c826678b68c869811
+Payload = dc88
+CT = 1972ca3744a4ab375af9060621a9dc4f4c32
+
+Count = 24
+Adata = 5b2eb1a6fa585d61d1fb3da68f5b93829c8e2d5e4fe03782617553d7a130ecf1
+Payload = 8179
+CT = 4483172626e930d24052bc056d8609c4175f
+
+Count = 25
+Adata = e2b3c3bf33cf847660929e48cce51d9d9289945169651aaecb1e939756e93105
+Payload = 01fd
+CT = c407852310207be8d3417de800b372700da2
+
+Count = 26
+Adata = 6051f12cd8aae68b4023aaf7178fd086aa582b8d8821e36637abc97025f5e858
+Payload = ca18
+CT = 0fe228553bc037954dbf4ce5db99792c2c7a
+
+Count = 27
+Adata = 2d3555faf285caaddfe95c010c2a7f233e09c2fc0cd30d644035269280527ad7
+Payload = a855
+CT = 6daf904725668634d6345bd8f90a3831b452
+
+Count = 28
+Adata = 4fca820dc545bf93bdffed33a04b67eb45384e696f092c2197e5d79cecd09913
+Payload = 5555
+CT = 90afdf6098cb3135c3045a54ffce88efaceb
+
+Count = 29
+Adata = 1789ae403e183d2225f431f001d475b53bccdec66572bb027340ae592839ba8b
+Payload = 11dd
+CT = d4278568e8c08ff5ee5ea0a608589c2fc029
+
+[Plen = 3]
+
+Key = fa15cc7f0de294d7341b1fd79326c8be78e67822343c1992
+Nonce = e5257aed2bda0495aa44591db4
+
+Count = 30
+Adata = 31a0338c3839931fa1dd5131cb796c4c6cfde9fb336d8a80ac35dec463be7a94
+Payload = bcb898
+CT = 68f08298d9a2147776dca9c1a42382bce323b2
+
+Count = 31
+Adata = 4863dd810ee70ef0f5da81f60c5ce550abb96454619032322e34657af25207de
+Payload = d1da2e
+CT = 059234a9a77755b324f3a557217752ade14ed7
+
+Count = 32
+Adata = 173594fc26b167f044aeaf9bfe920cab99a27eb2b01827d61f7553cb2018b5fe
+Payload = 394f31
+CT = ed072ba4441a79a90e228a28069fe109d5d876
+
+Count = 33
+Adata = 71cdd16eca9255aeedc23bd623513918ea97da21485074415fe75bcc42f454c0
+Payload = 868bda
+CT = 52c3c065f272f44c5210b5bcc571e819580910
+
+Count = 34
+Adata = e84418d332d16d2298e69e7ff3c37bc7b6e030cc822e73b3f4a0029bc2ea4d80
+Payload = 52d6bf
+CT = 869ea559c5f7f73a1b5f419c9f63ca401894a8
+
+Count = 35
+Adata = 42d962109bea1d50be0f3d83b4c2a6033d53b3d7112591866b1ae52dc84cb5d0
+Payload = 6f8d58
+CT = bbc542220b828cf5365137fb3f1df67cc8d2a1
+
+Count = 36
+Adata = 943b4327b5c70dba63c82f27e0412b3ada012bc0f7dd39ebb13db2f864daf80e
+Payload = fda286
+CT = 29ea9c422b0f41075ac79a0afa2d1047cbbfb5
+
+Count = 37
+Adata = 6076b94caabfa476ab7e6482e4fda9b29f2e2b2883efe44d668c7c74628505bb
+Payload = 8651fb
+CT = 5219e1ae68cd6d6815ecbfd01293d160d4d38a
+
+Count = 38
+Adata = 3e4bb5781f84b4bbd23583e3dae561c6ff4af8eff35e2a4f35b50d2f360d3469
+Payload = c3e179
+CT = 17a963fbaa81cfdbcaee476860cd5102f556e4
+
+Count = 39
+Adata = 364008acbad330d0b8d574641a97b0682c49279cfdc80ff309b7514514d18a44
+Payload = 4a97d5
+CT = 9edfcf7ad1520564b68824a3a939371c21a336
+
+[Plen = 4]
+
+Key = b5330a8447d74a7987fb718cfae246b5c7e057991064eeaf
+Nonce = 2ef29d62b40d8643848797cde8
+
+Count = 40
+Adata = 1225b036e6044df52314016760e92750de0936120395de750a2c54a7fa0cea82
+Payload = b46b343e
+CT = c2c39d6f9344e2de064f269d065a2a6108605916
+
+Count = 41
+Adata = aaa6257d6783936a4445833c2ac3bea8cb7334f22ade9c035d515bbc91d6a78a
+Payload = cb216301
+CT = bd89ca50693d90b8297b90bc41c231d08b0204fb
+
+Count = 42
+Adata = 1c1915fab09348b9a5536495c70d1a040305708c1124797e564b63e008e7b8ab
+Payload = 697a8696
+CT = 1fd22fc79d0146fe373437c529fb2eeb169e4bd7
+
+Count = 43
+Adata = 864d0f786497c7ce283762ca0959ec9c825ed445a5dbe5b4b2e5772fe88ce7f5
+Payload = 6bee3db9
+CT = 1d4694e8e389c549bfc4ede936d7896e544b23ad
+
+Count = 44
+Adata = d5388b0b548c58886dcd335dff2b1ed23ce3eebbb708fb5bbd831c83e959d3fa
+Payload = 85d95855
+CT = f371f10495177a9fe6d9329a585c8737c92a4d29
+
+Count = 45
+Adata = 83cddd189736f224cad6a29efba45e43c75450a14f1541713b7fb926ffc768c6
+Payload = e8b23340
+CT = 9e1a9a113914431a10b1f94a2b99b9e442f3dca4
+
+Count = 46
+Adata = 8fccbd1fc5240691cf24e8807bf3416c1b2d87fc86dbf3955fa2e52b9a3a8457
+Payload = 595c4d7c
+CT = 2ff4e42d383d8dc98b22010dd93cd0cbb396d9e3
+
+Count = 47
+Adata = 513d45f6f37f3f051667dc743215059e06e4fdc8945789b16d50556a2e839368
+Payload = 314e0c7d
+CT = 47e6a52c40c513bfc92d1a7db5ed7cab2d8212b0
+
+Count = 48
+Adata = 70828be102e554f0d4b07641fa3254bc8db06eefaf5b85a7c97e01c217fc8f3f
+Payload = 35753e32
+CT = 43dd9763ea98f4ac6b3eabd483f1e6ab92f3b83c
+
+Count = 49
+Adata = 343d5a4ad39acf81adcf24e9807618932abcb3bc076734f179174c77c8cb89e9
+Payload = a531c0ed
+CT = d39969bcf99fb67b1e2aba2d232db2445e6aec2a
+
+[Plen = 5]
+
+Key = 30419145ae966591b408c29e5fd14d9112542909be5363f7
+Nonce = 27e6b2a482bbc6f13702005708
+
+Count = 50
+Adata = e04e81e860daf9696098c723085d8023c240ebe7a643131e35359ab04bd650fe
+Payload = 8ceaeb89fd
+CT = ec9d5ed36243ddf77b33d8cf2963ba76fd4e19f3c5
+
+Count = 51
+Adata = 6217cd581d4b3b2f7bcf1b8dad9ad6430e2e3a0063cad52260e0a1cd6fc9e73a
+Payload = 7e51d6f870
+CT = 1e2663a2ef6b73fe9e638e205b27f78ed1bb9b0ed0
+
+Count = 52
+Adata = 8aa7847e496f5e9f1f87851442de844f27a21c1b48f82fe525f0dd5a88b8ec38
+Payload = e0023b674d
+CT = 80758e3dd25936115e23158aff1916edec241fad56
+
+Count = 53
+Adata = 3612abc865a4d8d7b86a84109388584df6526525adb1006ec6c8d00048d725bc
+Payload = e2b5b6f36e
+CT = 82c203a9f1f15aae4b70dbee244be1daa74475d7e2
+
+Count = 54
+Adata = 849a99c6f1cae0ad4bcde4bd0811e87ca5ed7b913de1a8285a206e980b4b7043
+Payload = 9a17e4a22a
+CT = fa6051f8b5bbff424487848385f8501ab5a77f327c
+
+Count = 55
+Adata = 9066367c784de0a4d1116bbe95ce55ded85edddb6273c2049ee24e0fb3429352
+Payload = d4e765fc78
+CT = b490d0a6e772d8d5da6f593a8d9956731b42645aa9
+
+Count = 56
+Adata = e7aa9f767fa8920f96f91c41d9e86755faaedaeda596a444b65f99b7a9e23e85
+Payload = 1074349e10
+CT = 700381c48fe3eca12b835dcfd08166ac8831585626
+
+Count = 57
+Adata = bc0db1ebf910b6f4dcad5401401d6bc2272e23130947dc236ca664d5b5ed6d66
+Payload = a46dd7fb58
+CT = c41a62a1c72bcce66018e9e552d2c8a229301361df
+
+Count = 58
+Adata = fcbeba2d0d73239d05f691a52b08152c9dd871f8dc76c2c18b8a638a74460d31
+Payload = 2e0ca09221
+CT = 4e7b15c8be3e41a50a28ea3be14baadf12964a37c4
+
+Count = 59
+Adata = dcdefce64ae4339f46c0759a4a10b29d59daaaf1e5dbf75cf11b4e4f73c5025f
+Payload = 2e108ce0fa
+CT = 4e6739ba65bee2ab25bfafa76dc3e54832b2f76864
+
+[Plen = 6]
+
+Key = 748ad503388a34041a7bdae6361d57894357c333bacf02ca
+Nonce = 518b79d194579b19f2d8845b70
+
+Count = 60
+Adata = 691dd98f61fd213b0840ec5a6f06ef9a1420be0d59bde5e43546347a2a865a94
+Payload = 24d6880aed7e
+CT = 270120f9634ec15536e21d961c675070ec4cff9037bc
+
+Count = 61
+Adata = d1fd047cdb18463766841abb1fcd25257f1458b595bfcf24066ff9385232fa97
+Payload = 2298028d0213
+CT = 214faa7e8c239b303af0b098f902dc24e66fe56adc6e
+
+Count = 62
+Adata = 65a480d120a0459dab69e8f23094801e10092666cc56f9fb2549662982bda6d0
+Payload = f248e5225e3d
+CT = f19f4dd1d00d1b657925a9740d6828bd85cd12205764
+
+Count = 63
+Adata = b738a53fbc9689dd49f68f97f5a99665258cd52e74dc653b594cffec045508aa
+Payload = 611dade00cec
+CT = 62ca051382dc395a1c49129ef6cce0ad5f6ef378aa1c
+
+Count = 64
+Adata = 7006f54184f0ff0ab215ca408d46325b86c1cbae6da7838435b1826ff81f55dd
+Payload = 5871a8300471
+CT = 5ba600c38a415e68468d1b2b516be3d688567d84ab80
+
+Count = 65
+Adata = 9e6e6675d4c6b1e0f3894aac071f4c99a364708edea12f319cbc27b40fabc0f1
+Payload = 3ca8a7520e94
+CT = 3f7f0fa180a40ba1af163049d16817021665d183bc9e
+
+Count = 66
+Adata = 10ceef716f54b74d7c8a435d6aa38a10ff23939ca29e2de7b6c3e0a8269a23c9
+Payload = 9c2a0070fbba
+CT = 9ffda883758a670f35869da9821b6ff1fab3e6062ad4
+
+Count = 67
+Adata = 3ee0865f29be50160273b4a94ec078932b9cd10a858e31838d5b607867e1ce69
+Payload = 436179c74fd2
+CT = 40b6d134c1e208f395250fd79087c858b83755411114
+
+Count = 68
+Adata = ec2b8bfe1ccd491b02aa4a9178fd6f099556963e39e2ca5fe6ecb6b5d2a46085
+Payload = ecfa41c614c5
+CT = ef2de9359af5afcbd9af2d584a0f638d066f2496d9be
+
+Count = 69
+Adata = 5b6f6369643d83b1db33d75257d7dea761e574e6e1f1ecead64e5e354a2f4235
+Payload = b48c10105dbc
+CT = b75bb8e3d38c17861882b8930296fd51d969a1e9489e
+
+[Plen = 7]
+
+Key = b930cca30a3fd230c237c8f3cc6792d0c4084dff5c18d775
+Nonce = 7574802fd82fe96c05431acd40
+
+Count = 70
+Adata = 1cf83928b6a9e525fe578c5c0f40c322be71b3092239bff954dd6883738d6d71
+Payload = 2a755e362373ef
+CT = f06238b0450fd1f4b6cab1383adb420c4724aa7bdfefb7
+
+Count = 71
+Adata = bb5450f66273f63b2f79dce177381ce846584ce4f7a0ad5a0171a56e149370bb
+Payload = fab43224bf8989
+CT = 20a354a2d9f5b7a1f99175d3dff5a73f0053a95c36fd8d
+
+Count = 72
+Adata = 3e5e1037bd2922eb20c34200c470b76e537baf7e7f1d8dd2f7a184a593c66554
+Payload = e3aed6715aa429
+CT = 39b9b0f73cd81734b4ad0e41117940abf530093dac648e
+
+Count = 73
+Adata = 3cc88a096a1a440827f5b7da675389e50b5cce35fa2cc36674d6bfc5a3a966b2
+Payload = e78db0f83997cb
+CT = 3d9ad67e5febf5663a8324014550430c7eaeffbd8568f7
+
+Count = 74
+Adata = 2cca33a10b9da7ba99a6b552d1405f2df3fdfd15358d8fdab5e15296b38f9135
+Payload = 726557906845b1
+CT = a87231160e398f34ab635c4eb5b38b86e71da8af3840ae
+
+Count = 75
+Adata = 2fe5dd58b17914187e29029c53cfe5b015ca74cab750d8f95e05f818c3cdf947
+Payload = 043a759b578be4
+CT = de2d131d31f7dabd9961766e03eaa7e8888227c98d1f42
+
+Count = 76
+Adata = 8b8e3d7c88fa16d70130cee290b7e2eecf0ce711118cd9265093b11467e63554
+Payload = f31f2fb4b3fd80
+CT = 29084932d581be637842d96d13c4aab97e296458745a9d
+
+Count = 77
+Adata = 6341370e126097f9721a13c977eb4875cf1286e15c3adfa4e7597e0e13d93b6a
+Payload = 7e3c8224104669
+CT = a42be4a2763a57a51ac46611366c666cab6bfd3d1baaa5
+
+Count = 78
+Adata = 227926b62f7cdd90e4d3b0cb5457e71fb087d329671f0fa891ec06eb8edeb58a
+Payload = 26a0528ae6f9c1
+CT = fcb7340c8085ff8c7d7e5aec14845f844ad38544a2f11d
+
+Count = 79
+Adata = 05b50c40b02e79b74b94d726a7ce8b2b7216ef8af6e7a42d041d2a692a58ad83
+Payload = 61dcf53d1a184e
+CT = bbcb93bb7c6470f1605ab8a2332012b759ccd2eedbed24
+
+[Plen = 8]
+
+Key = 314c136999e41d137bd7ba17201a9fa406025868334e39b3
+Nonce = 65f7a0f4c0f5bba9d26f7e0ddb
+
+Count = 80
+Adata = 5c7ce4819b30b975ae6ce58dcc1bfa29a8b6dda8f4b76c7e23516487745e829c
+Payload = 4d54d8b06b204445
+CT = 2baf90c490b11f9607482362ab3f157c42d0e9c6c5cffcf0
+
+Count = 81
+Adata = 90257ed88679197b8219bc4c2434a71a4e3664d5859c4ffb9a075654898ffedf
+Payload = b2a35df881cd63a2
+CT = d458158c7a5c38715389509b5b6f2df1faf7e8c39203970f
+
+Count = 82
+Adata = dff8ad83525d8235eacdccc91abeb80795e6b5f463fd28af35c46199f646ceb8
+Payload = e98f5e5a20d02c80
+CT = 8f74162edb41775395328747ca544e987df28883d0377b35
+
+Count = 83
+Adata = cde159c5343cd9d98001cd719d3e9ea25e47e1ff13fc87055d4a53b741f59285
+Payload = 90c3e48313cd4fe4
+CT = f638acf7e85c1437a4ba841883a0d7aeda398c043161966f
+
+Count = 84
+Adata = fa88cf5a08be4fb0c1a7960f45726c303eb559861fa60d17aa8dfe8bb5795382
+Payload = 8ad6d5a28ec075e6
+CT = ec2d9dd675512e3509195efe66c5faf413e0f68df8cb647d
+
+Count = 85
+Adata = fe9e93a9370b43efa1560aeb017ff04fca7f207191e6f707c1c35b2e90c44eb2
+Payload = eb83928f0d5f7aa3
+CT = 8d78dafbf6ce2170b51af067ad69ad96009e50ead3d03f02
+
+Count = 86
+Adata = 35792c854fdf1c8cf7f3f8ed2b8ec4f31fe17bf8d4ba49caec03f954bd8bb17a
+Payload = 4cd74ed2fd083011
+CT = 2a2c06a606996bc26b1cb03ee76587f84364825f7c1fcbe9
+
+Count = 87
+Adata = c084108f9c0a74cbf70f614dceae592546865006930db0401828a0eecff98671
+Payload = 52365f94579e0646
+CT = 34cd17e0ac0f5d958fa70c5e195f1f955d64892f532b7683
+
+Count = 88
+Adata = e8045949de61c5c18a63e628330a4d1d12782379a8f9187755409d1825f453c5
+Payload = 8fb85c857a3e38e7
+CT = e94314f181af63342ddf297bdad58083645a052815d29a83
+
+Count = 89
+Adata = 53cfdfd66d63c2924bd583487b90b1dd9ec199f90d660cb9c3a763a4776abfe1
+Payload = 43d2828e86f7856b
+CT = 2529cafa7d66deb81ad3b2be41dbc39df4c0145dcbae3e76
+
+[Plen = 9]
+
+Key = a19f6be062ec0aaf33046bd52734f3336c85d8368bef86ab
+Nonce = 7f2d07f8169c5672b4df7f6cac
+
+Count = 90
+Adata = d68d5f763db6111c5d6324d694cb0236beab877daae8115ecb75d60530777b58
+Payload = 13511ae5ff6c6860a1
+CT = b3859b757802ebd048467fd8e139eb9ee8fcdca45ed87dc1c8
+
+Count = 91
+Adata = f6e219b29884dab9ea9bad34d9ef8a50ae389c9a908de7154a1f2e894f27141f
+Payload = 7e7e33e1a07d4e8fde
+CT = deaab2712713cd3f3789d0ee8323ea2ee7a68aaaa9c49b98df
+
+Count = 92
+Adata = bcca002d69d9d1044c40ae741ea33ce6b8463f5a28d0514e044fdae2fe7d3c3b
+Payload = cc88980c73e6c5f0cd
+CT = 6c5c199cf48846402437c9fe3d9feb0485e6d7c04423b77a53
+
+Count = 93
+Adata = 39cac8f0825ffdb0668455933ad1581263a23b9e5f1305340528f0320d4b1269
+Payload = 34cb528f50d073cfdc
+CT = 941fd31fd7bef07f35b87e90a71ffe6c30bee1771078a701ab
+
+Count = 94
+Adata = 510a02a44d142c8e975d1d933f828fd7e47d28b88223f1698cf009dc3b079be6
+Payload = cbce3df86438a61065
+CT = 6b1abc68e35625a08c9e9c5be0657649448c38692e8d703d30
+
+Count = 95
+Adata = 40e0418cd52f74d78a8e18ed86210e3661a86d8574aedcee540340d8996d9852
+Payload = 80a2b835f8b0729a4b
+CT = 207639a57fdef12aa213e5f2bfd33101597cfae7cf334a8528
+
+Count = 96
+Adata = 1f2938b3bde19e1af91299c08638061dc3c1ea3284c259d415e996477cb37b0e
+Payload = dd04794e65ce34127a
+CT = 7dd0f8dee2a0b7a293516a7310fbd4ceb90d8db9a86cb6311b
+
+Count = 97
+Adata = cbae5b46e35fa2a279dcaa4c724b923805d4707412a84252b64228c91cedd019
+Payload = 00c4101052f54462d5
+CT = a0109180d59bc7d23cef6165af65f3522dfbfed0293db39ecd
+
+Count = 98
+Adata = d0f27c7f42892f3ad4c0029c5b698abb1d035ba5869a665b1de8861db6c055e8
+Payload = d0865445d3b26b6f49
+CT = 7052d5d554dce8dfa00726434c1349e3e874a2d6bf598d05fc
+
+Count = 99
+Adata = ab0f5a829a9319a74d5d5179aa0a410a0fcf52f344a7a896aeb1f7a6c5d398ea
+Payload = 7c7c8580b944ed3fd3
+CT = dca804103e2a6e8f3aab491e60fc97b3cb5248291e4866dcab
+
+[Plen = 10]
+
+Key = de1c8263345081d2dfa9afdf37675971135e178df554a4d8
+Nonce = a301bb82f91a582db01355c388
+
+Count = 100
+Adata = 9ad52c041390d0d4aaf65a4667c3239c95e7eae6178acc23fb4e70a852d483c6
+Payload = f777aba1fa70f94e6de9
+CT = 9d8bff6d2dcde77104ac6aba025abc01416a7ca9f096ab2529cb
+
+Count = 101
+Adata = b49c7e7b47870c1cc339c7c09aaacfd6115fa8a0f04990367eea10cfacb9d23c
+Payload = 349feebfbe58f93ea3c3
+CT = 5e63ba7369e5e701ca864acb200e85a0d4753a8ba226aca72f98
+
+Count = 102
+Adata = e61ca7310172eec16745a73e34516f65844eecd0dbc5566ac5213626b9096ef1
+Payload = 678a40b4c2c7df0e4c9d
+CT = 0d761478157ac13125d87869784e3321183d8c044657a020e9b9
+
+Count = 103
+Adata = 690f5e5d8da6cdb0f492e80449e152ffe88fea9742564d8383c79cef739a7f74
+Payload = 2b81e0533313664bf615
+CT = 417db49fe4ae78749f5070634d00b1facf0e9e9979ca257a71e2
+
+Count = 104
+Adata = 78e34b0a1d61ccd411cbfd306ea2ef3ce89c0b085deb4cfbaec2ab72ce16daa9
+Payload = 1ac63aa38a206d8e7d68
+CT = 703a6e6f5d9d73b1142d994630ed92e2973b22773f229b45bdad
+
+Count = 105
+Adata = 51bacfcf87ea11da34b76acba8c444792ec3db3c8ee6e600d69679975a682a54
+Payload = 027a7fd7897808ec7a56
+CT = 68862b1b5ec516d3131304571b015bb6b4651f1eb9f6fb3a7b74
+
+Count = 106
+Adata = 5159357a133e4743f903d05bd641da369a3675337760fcd2424a99221ba70b78
+Payload = 1086953d352e94a51a6d
+CT = 7a7ac1f1e2938a9a7328bb0e11ac4608081fd0702a137da0aea3
+
+Count = 107
+Adata = f567820865340314d46a17f520ff315efb6b33bdeda590ca9c4fad604c2d8e8d
+Payload = b8b148aafec4a035e9a7
+CT = d24d1c662979be0a80e252c9ec1317ce30dffeb4c9bf3fd0bbdd
+
+Count = 108
+Adata = 0cfec933831644b468724e808bb3d25fe8f15850ce513fc341da46089c845208
+Payload = 884242a87779d3921f8e
+CT = e2be1664a0c4cdad76cb691e32be3cdd9721a13aabad26dba58c
+
+Count = 109
+Adata = 8edc2b85d44297ac66bdd90d05d8df38124033d6a583bb8dda18a2246ba096e8
+Payload = 25c32770a299020d8500
+CT = 4f3f73bc75241c32ec45333a381be77800654aac335bf9220ac9
+
+[Plen = 11]
+
+Key = 248d36bd15f58e47fcf1c948272355821f8492e6e69f3661
+Nonce = 9e8d492c304cf6ad59102bca0e
+
+Count = 110
+Adata = 9ec08c7ed6b70823d819e9ab019e9929249f966fdb2069311a0ddc680ac468f5
+Payload = 33709d9c7906e2f82dd9e2
+CT = 9114d36b79b1918b2720f40cddce66df9b4802f737bea4bd8f5378
+
+Count = 111
+Adata = ba13974d95f2eeb367b63850609c53dc66c2710f682f10bef0142d48f851b430
+Payload = 84172985e7d194ba28a87c
+CT = 26736772e766e7c922516a12c94615be2bd81bd598f3022f5775a4
+
+Count = 112
+Adata = 5f16180bfac9b7483774cb0e1d57a43e9bf3cf03bf6fe758293aadcbbef25b80
+Payload = 9a34d32070c71d7de8f512
+CT = 38509dd770706e0ee20c042758e936750e335702542bc598e211c4
+
+Count = 113
+Adata = 4352057bdd1735a85dc0fc4dbeedc73279c27eb24a97641236f03f11cdafb8c0
+Payload = 2054a268b1f6fae4f15d91
+CT = 8230ec9fb1418997fba4870762bb2a7d04ba2ad251d595d0619dc4
+
+Count = 114
+Adata = ddf118ae403b2509e75eb7a26d17e73e527acbacfbe49a56fa3210169030144b
+Payload = f71afe9a60f08a0ef694aa
+CT = 557eb06d6047f97dfc6dbc27d85594da3fd35bd8498d7e389ee7cd
+
+Count = 115
+Adata = 973904409e8154132439926f0dc45c0d81bbbd5793f7f81e20eb818bfa374d58
+Payload = cdf5b47ff73306aa55c496
+CT = 6f91fa88f78475d95f3d80055936db383a8ad10b152046d721d3f7
+
+Count = 116
+Adata = 06bca7ef6f91355d19f90bf25590a44a24e5a782f92bc693c031e6de1e948008
+Payload = 9ebf93643854ea5c97a4f3
+CT = 3cdbdd9338e3992f9d5de5d57e228369e24fe955fd8924526af6e5
+
+Count = 117
+Adata = 8321f65baf9dc856ac1c24f3fee5c74d697eb0b50470d59d8f4a14b506e86c53
+Payload = 685116faa5cc527ac8bfa1
+CT = ca35580da57b2109c246b76c23abfb3b4eb39deb8da2064390dfa8
+
+Count = 118
+Adata = a4e7738038a5116592bb9d92d6d4ed191ab774310f6409e4e45fe907674c006f
+Payload = 9e8c4f1292e8d7e5179b34
+CT = 3ce801e5925fa4961d6222b4272c0639e8e6a1d356fb4fea86762c
+
+Count = 119
+Adata = 0df202431ee7f251a38aaf6aa8cd313782bd293af9114005adfe9faab253b572
+Payload = 3ecc2ba566c723462eb0ea
+CT = 9ca86552667050352449fc0633a0f9cdc9490231ec2dd69f6e35db
+
+[Plen = 12]
+
+Key = 77a67fb504b961028633321111aac2c30eb6d71a8cf72056
+Nonce = acadc0330194906f8c75ac287f
+
+Count = 120
+Adata = 8c18486d52571f70f2ba6a747aaa3d4b3ebc2e481ee1b70907dddb94bdfa0ca6
+Payload = 10554c062d269ff6dcd98493
+CT = 7f8b0cad79b545e5addf0b04ff4b0f2b2a5067283210aba8630d0306
+
+Count = 121
+Adata = 4e0b4771c7f6c66f9577c430611fdeec5702296ee3691b6bb8c6a81217edabe4
+Payload = 1c9e7875cf02129ac52daeb0
+CT = 734038de9b91c889b42b21275b16dbdf0b9be3c8c82ac652992d630d
+
+Count = 122
+Adata = 4a687e1d0a95ed2efb95b4c6b040999fcd35136811cd665f934d10224b6064c2
+Payload = 34575694dde459d195b7357a
+CT = 5b89163f897783c2e4b1baede629274d654ef5a4480e24f6bef3bc8c
+
+Count = 123
+Adata = b5330a8447d74a7987fb718cfae246b5c7e057991064eeaf823641a12bfce9f5
+Payload = ab20c8e8aab1aac1e4f64206
+CT = c4fe8843fe2270d295f0cd9142ab5407a08b648ce24e9955e28fe47e
+
+Count = 124
+Adata = 4f19bbc3135d7a216465b4c1df2616e8bfc3cc64af0bf52bdc42543f4d2448d4
+Payload = e556ca05bcd1991d2c9836a9
+CT = 8a888aaee842430e5d9eb93e151e94d311c7cd2c1b9048575076ceac
+
+Count = 125
+Adata = b6ffc7387b19786282bda7caad52eb37fbe7e557afcb80faaf57767e2a0f178a
+Payload = e5b665600a2aa413e117c538
+CT = 8a6825cb5eb97e0090114aaf61b71330d72506050368186a5619f180
+
+Count = 126
+Adata = 6a493c5ef3769ccc4101dbb2eb36e1e5bbc577a057ce0731203ba3f25b52497b
+Payload = 870864a611aa0475d120bc40
+CT = e8d6240d4539de66a02633d7ea21e36f99e5aab6ffa85994d13d5bb0
+
+Count = 127
+Adata = 8215753d9efc51325f182199e39f9082cc3fe524400f2a7434c68df7eb2b06d4
+Payload = 71afe8d00c6f2ea8c8b050d4
+CT = 1e71a87b58fcf4bbb9b6df437cc93a50dea11c5e0b19f14b9c8f16bd
+
+Count = 128
+Adata = eb8f198da6ee92a03913c6575343f6c749d2377a09430eb751b13c041e6edbea
+Payload = 7021f18b8f398a5999fcdcd1
+CT = 1fffb120dbaa504ae8fa534699cbfd1beafa2d2942f6812b8dfc88e6
+
+Count = 129
+Adata = de2ee30359e390db72f682c2ca0f14b72b60ff9bccd8c6fbd19a512b12add794
+Payload = affca856eb412f0b3276ae6e
+CT = c022e8fdbfd2f518437021f9337405235dce6161441caa25cc6007c6
+
+[Plen = 13]
+
+Key = 0d423519e4110c06063061323f8c7c95387776b6ee4e4b6e
+Nonce = 39abe53826d9b8e300fe747533
+
+Count = 130
+Adata = cdd9bf1b4f865e922c678ec4947ea0cb02e78bd5c1538f33aeb818ad3f47e519
+Payload = 4021ff104ff1dbd91e46db249f
+CT = 7953d3cd66d093785d123f65ba37f16761dd6aedbfc789ad96edf1490d
+
+Count = 131
+Adata = 342de5fe61e05c2e58ac2978a871fbdf186a7294ec5f85c4631c21b584231211
+Payload = 95050ca1d494bdb561d4840f8a
+CT = ac77207cfdb5f5142280604eaf8f8e855ae975a1fc64bcce3e7492e9d6
+
+Count = 132
+Adata = 7871482948d8d09d0a7491d915543082cb5fc7d6c1e82ee2218279f54c15c154
+Payload = c45823203b20821a48502f9c67
+CT = fd2a0ffd1201cabb0b04cbdd42017a6515156691b3161b747576078da4
+
+Count = 133
+Adata = 65781d018f27ca0c72a9fa9ab4648ed369646dd3ce45d7ad3a54f6b051f1b6e9
+Payload = e901661b7d47c9918244ee1077
+CT = d0734ac654668130c1100a515225cec7d2566a07cd78181ae94577befe
+
+Count = 134
+Adata = 05556b04dae5cde8525633d1862aa200c54af534e302d2cbd34ddc2b78532a60
+Payload = 5556f799d6a6cffb343f28c1a9
+CT = 6c24db44ff87875a776bcc808c133f51dac00f973fd42e0948fab70ea9
+
+Count = 135
+Adata = 151304e3e4f3c2d4d3227e035d849e0d3841ba00cf6cab1cf2e3e4d6cc760623
+Payload = 56bf26be81c7b55ef898e23981
+CT = 6fcd0a63a8e6fdffbbcc0678a4fe78bdeaa8d408ffe8fe64811aa87742
+
+Count = 136
+Adata = f870cc1fe67d6169279f905b0fe5fd9a0436c36498e4b7c6f584f00f7efe8784
+Payload = 36b304a72dbf4acfffa1d7d624
+CT = 0fc1287a049e026ebcf533970197228d155dda2bc814ff33ebeb9a7ffd
+
+Count = 137
+Adata = 5692c9d452ea1c067e62fdc554ddd2b18c8433d59067f971316797fd9853ae6a
+Payload = fb529eb5ae79a0830474ffbc98
+CT = c220b2688758e82247201bfdbde7ba03e144e34a4ab34791a372a2b8ab
+
+Count = 138
+Adata = dcf7fe16b7ca9e27ec3291103398eaa2e77c7b770b67f8858c215af4c523822d
+Payload = 6218c778955d9a56360f06c704
+CT = 5b6aeba5bc7cd2f7755be2862103c2eb5ef0657306d12b753a0694efcc
+
+Count = 139
+Adata = b0f1e2668611dca86e8d0f58c2a4cf4a9472d81ba013e271800b75841fe5ffde
+Payload = bf6b143fb713a81c965c5a9d8d
+CT = 861938e29e32e0bdd508bedca87cc6119151393461ecf65bfe06e0163b
+
+[Plen = 14]
+
+Key = a60cf7ceb62bf3118532bc61daa25ce946991047f951b536
+Nonce = 7499494faa44a7576f9ed5580d
+
+Count = 140
+Adata = baa482c64eefd09118549a8968f44cfea7a436913a428e30aa4ab44802a4ba35
+Payload = d64f9426febce6a84c954dd5ded5
+CT = f7580f17266d68237747bf57c7ed8242ac1a1979c5a9e7bc67d7698c7efa
+
+Count = 141
+Adata = 2ad8ecc5ac9437ace079419f17e6018625b10490120fbe2f12b41e64b73b653c
+Payload = fcd9b67717bcadeceddea336c671
+CT = ddce2d46cf6d2367d60c51b4df4918abced491c063d8bfd0e7341febddc3
+
+Count = 142
+Adata = 7585ee95e74d7a869bdc0b59ca9939dd57e7b09afab179079d467bfe0668416c
+Payload = 18232d7c792fb80e6ca1c8f2c3cc
+CT = 3934b64da1fe368557733a70daf4659ecbb3dbfbcdb0f913abedf8afab05
+
+Count = 143
+Adata = 41be6ca6188f34da1ce83fb8c27652848dc2a71e32bd3631fb9b33ae69e5d879
+Payload = 764dbefb42644d18d23e5e456868
+CT = 575a25ca9ab5c393e9ecacc77150a220d5ec0b5397d6b4e323b5dc7d1b63
+
+Count = 144
+Adata = 197cee3b15320d57996191dd13106fbd4546a5cc3d2bcf0c886af52ea3d9a855
+Payload = 8003586af34bdd0acae4f5547394
+CT = a114c35b2b9a5381f13607d66aac3a5f713f5d0793b732c6e114805cc9b3
+
+Count = 145
+Adata = ee0b647a47656a6e9e09c2d64f734a2cc3fd45b7ee52fea51c24af59ee22a006
+Payload = da143266516a4145cde92c93f961
+CT = fb03a95789bbcfcef63bde11e059ed90e8650bc16f590789dcc625b9e63d
+
+Count = 146
+Adata = 9f5bfffa01f1425d95465723735b49fc1dffbad06cf37a00ca4b59efa21739c1
+Payload = 3842b033f3ca31a6f8e5a638b39e
+CT = 19552b022b1bbf2dc33754baaaa6bda183dda1aef021d92210e27cdd7c5e
+
+Count = 147
+Adata = 64e92ba2748d07f602808f7c5ded15cb0e43140400d37107e59a01e7d45b4c9c
+Payload = cedf60b17185fc71b957cb759260
+CT = efc8fb80a95472fa828539f78b585e4087fb314f893937e95383e66745c0
+
+Count = 148
+Adata = 6ebcaeb4bd44ff4c990305ac64264dfe2ada5f7cd4b294eb9f492865cd28905c
+Payload = 035f449bb28f43365f4a0556096a
+CT = 2248dfaa6a5ecdbd6498f7d410520a71ce5813c578532b742d704fa92276
+
+Count = 149
+Adata = db617207dccd1f6baea5f2242d5e577adb8d69af3bb1707a7a53a8b75452455c
+Payload = 9a2a45424f4965a71270e77cc403
+CT = bb3dde739798eb2c29a215fedd3bb7fc45d15d6939668065d2282fc589c7
+
+[Plen = 15]
+
+Key = 82d4bc9aac298b09112073277205e1bf42176d1e6339b76c
+Nonce = 70325ef19e581b743095cd5eb1
+
+Count = 150
+Adata = 6d14bb2635c5d0ae83687f1824279cf141173527e1b32d1baf8a27f7fe34a542
+Payload = 25a53fd3e476dc0860eeeea25fcb0c
+CT = 4a1cfd0023557a184b929965b0a445cb3993ca35acf354cb2b4254ff672e7f
+
+Count = 151
+Adata = 9f8a56fecf32fa7d50f033b2524c3d798e254bc87245cce57e38edd6ee5d5f1a
+Payload = 797dca47597947c057789433309b67
+CT = 16c408949e5ae1d07c04e3f4dff42ea25b5eb103bac224cad66ec0f100875c
+
+Count = 152
+Adata = 86f15b8b677b7655f358a2c7fd5785bc84d31e079ed859b6af88e198debd36fc
+Payload = e61f9a663d3a2b50ea2f9475971270
+CT = 89a658b5fa198d40c153e3b2787d39b598cc6ec2295c586e7ae270a01846d1
+
+Count = 153
+Adata = 4de6bd43c28143ea5d40919cb5330a7e674f5bd8aeb7b178343a2851281c8668
+Payload = df990c42a268950677c433555319b3
+CT = b020ce91654b33165cb84492bc76fa97ff732093f7d0a96b30d8cdfd1bd583
+
+Count = 154
+Adata = a5c3a480dea1b2a1e3a0ce416148b04f60104217c9d24a5b267b4aa6aa07a4dd
+Payload = a7e72fb4bec3768594a2f6f5b4379e
+CT = c85eed6779e0d095bfde81325b58d7ad98e32a9156e125ff021ef6951b0c40
+
+Count = 155
+Adata = 51b041f1666c59045d333fe63d43457107e1adad34fcbf965e0d191f3e414776
+Payload = d3d1550047cf90eceaea7000d8e280
+CT = bc6897d380ec36fcc19607c7378dc9390f10df08a84c21031626861b201fbd
+
+Count = 156
+Adata = 22f8a3c9d85b2d53ffd92078d3c94373f855ecd01a8ac521d1abd0f2c7cba9ff
+Payload = 756412c4ee6416f2f4e0342011cde2
+CT = 1addd0172947b0e2df9c43e7fea2abdd5d840bb8c4348a9a548482e6b93043
+
+Count = 157
+Adata = da08b14e1b770b81faaf1e59851df1cba8838cd63bef141340ee378e65fdcbd4
+Payload = 666e4a4b3f6cf598aa763cdada4109
+CT = 09d78898f84f5388810a4b1d352e403f0d49927cd6103e3705ba201e8f73c6
+
+Count = 158
+Adata = 2db3ded385ef9c82fd39ea5782d9befe66e8a070066269b2aa7c4bbfac3711c3
+Payload = eb9013a74352b0677a88bd73052477
+CT = 8429d1748471167751f4cab4ea4b3e2d97f7c2b3b42bf570cce79bf30ccc50
+
+Count = 159
+Adata = 194c9e1eaa8e376f9c41bf33823efa28ee60a9213438665b7002cf0fcad7e644
+Payload = e3126400e3c571a4d39b37bc938a22
+CT = 8caba6d324e6d7b4f8e7407b7ce56bd3c2a4fc45d014a0c54edab2930a5bdc
+
+[Plen = 16]
+
+Key = 6873f1c6c30975aff6f08470264321130a6e5984ade324e9
+Nonce = 7c4d2f7cec04361f187f0726d5
+
+Count = 160
+Adata = 77743b5d83a00d2c8d5f7e10781531b496e09f3bc9295d7ae9799e64668ef8c5
+Payload = 5051a0b0b6766cd6ea29a672769d40fe
+CT = 0ce5ac8d6b256fb7580bf6acc76426af40bce58fd4cd6548df90a0337c842004
+
+Count = 161
+Adata = e883dd42e9ddf7bc64f460ba019c28597587d06e57c3b7242f84d5e7d124ab81
+Payload = b31dfa833b0cda20eaa84d2ecd18f49a
+CT = efa9f6bee65fd941588a1df07ce192cb8707b1a4d9ce3def33703e19eaab6dda
+
+Count = 162
+Adata = 409401eb49cd96b1aad2525c5124c509766ff86f88b2011c67a1d501d3485e31
+Payload = 24bc8dc1e2354667b79ba4d7061448ff
+CT = 780881fc3f66450605b9f409b7ed2eaefd9041ddce37d88e79fba28e385b2327
+
+Count = 163
+Adata = 83bf5c063bf1febf71688a832d615e09d6f14badedeaeb6ffbfe343fc7274e78
+Payload = d41d95a1d2326e12cba636910ddfca53
+CT = 88a9999c0f616d737984664fbc26ac0291d971893543868bd8c69078fc2bdb24
+
+Count = 164
+Adata = 8cdd70524e24318c64d681aa27752d4c86c5348c05c9e48f06ed41594785a6e6
+Payload = e8a4b80e081919f1912542d3136764f2
+CT = b410b433d54a1a902307120da29e02a3866b23e4c991f4007e56a1ee9265c6cf
+
+Count = 165
+Adata = 615985f63571c0f94ffcd4df77326abd41e84f388f061d97573a181da7ee5695
+Payload = 7fca7388058d6d1438b6eee0292131cb
+CT = 237e7fb5d8de6e758a94be3e98d8579a2abbea637996b954027efa9464ced6b9
+
+Count = 166
+Adata = 17aa90f2bff0419011b01dee62be31354431cbc89f22332704b096143d4743f4
+Payload = aa540554ee80dbffa475f702d862d6b6
+CT = f6e0096933d3d89e1657a7dc699bb0e757bc8d48d82ebefc76f17323c518ecc2
+
+Count = 167
+Adata = 85288b2be612e42335c144fb058a7dcd567c382fbcee3962bd5be4cc7a7000a8
+Payload = 6d745581831edba437e70ea89cad217d
+CT = 31c059bc5e4dd8c585c55e762d54472c65470c81e487a26cdc26830f2b51bd1c
+
+Count = 168
+Adata = 288f9f52824b54b608dd7226a0a89d43ae8c05107dbae761e1c756911a003b74
+Payload = 811a61869c7a6b2aa9ac0fcc523ef784
+CT = ddae6dbb4129684b1b8e5f12e3c791d5a3043722be9448c3ef144f2288066f75
+
+Count = 169
+Adata = 51dbaba180d4746edbb3420461919b5b735797bf7dd19f84d80475f5efc2748d
+Payload = 378a4e39817f308ed1e639f943b694c4
+CT = 6b3e42045c2c33ef63c46927f24ff29549aba95e04e11cf18ddf73773d395c1a
+
+[Plen = 17]
+
+Key = 3cf8da27d5be1af024158985f725fd7a6242cbe0041f2c17
+Nonce = 07f77f114d7264a122a7e9db4f
+
+Count = 170
+Adata = 30457e99616f0247f1339b101974ea231904d0ef7bd0d5ee9b57c6c16761a282
+Payload = f6dd2c64bf597e63263ccae1c54e0805fe
+CT = ce3031c3a70600e9340b2ddfe56aa72cffdc5e53e68c51ee55b276eb3f85d2cf63
+
+Count = 171
+Adata = 42370f115bbd4b31bb99fe82cca273b3c93072f96b2e09bdc6718d926d48db69
+Payload = f45fee3e086c28a7c590ec0cc05b972664
+CT = ccb2f3991033562dd7a70b32e07f380f65c6328a7476db2c10ec7bca3f6bd3df42
+
+Count = 172
+Adata = e2d692c5678124998a7862b8e87276b0a19e293a609103c99583b36305bcb2b0
+Payload = 4ad69a8ab433ed8909825c71f6081f64a7
+CT = 723b872dac6c93031bb5bb4fd62cb04da68080f0d51d3b8841683eff361984f7e4
+
+Count = 173
+Adata = b5b38791160959dd2836ec1ad25286c1ba410d7212347a95b5738a3d725bb651
+Payload = 3d47071c13f994cb42fb2887e5c6e53a54
+CT = 05aa1abb0ba6ea4150cccfb9c5e24a1355c1428ef5d40bc9e363817f219af2ed56
+
+Count = 174
+Adata = 02691171795a77d1e3bdad513b6fab5b50d1def81bcc1df15012de3433a6aa78
+Payload = e8a4b80e081919f1912542d3136764f264
+CT = d049a5a91046677b8312a5ed3343cbdb65fdfb37dfd1236198035c8461b304152b
+
+Count = 175
+Adata = 7371d8ae79e628f53ffede174eb068db2318c05e2f6d94ad2233a59369b16db0
+Payload = 549aa84bb182312dd016e3107f3b1f9c5b
+CT = 6c77b5eca9dd4fa7c221042e5f1fb0b55acefde0e84a3ce0cb702ceb73ca1dd9a5
+
+Count = 176
+Adata = bb1e1f51082e470f7245458ec902098e1e41d0ed28efa31be71d21ce86527ff7
+Payload = 31a12ca6d69db2e6e252474d7d59ed6552
+CT = 094c3101cec2cc6cf065a0735d7d424c53f8441d46dc5456a587b765e1a820c11c
+
+Count = 177
+Adata = 7584f57b49e95bbf5a67153e18b9b8c4722644e8f611613c39cbe8c679aba5b4
+Payload = 5bb121e70452a954f420a56aca8cd5c059
+CT = 635c3c401c0dd7dee6174254eaa87ae958d0daddcfcc92349ef059149c54a25cd0
+
+Count = 178
+Adata = 505687182c06e6f4effe7fe03c1f436199a9015380ff21d0b2aa9453cfa10b1d
+Payload = 5b80d1cf745b14cb71cbc8dfe0bc7c7358
+CT = 636dcc686c046a4163fc2fe1c098d35a5948c1242b89490c6ee69dedc1e91286ee
+
+Count = 179
+Adata = 7ebb051741145a3bad87131553375c6debcbcecee9b79ee451bd1429cbb33fc1
+Payload = 79ac204a26b9fee1132370c20f8c5bcada
+CT = 41413ded3ee6806b011497fc2fa8f4e3dba2ddd54e509bca0a45dcf2fd514e1496
+
+[Plen = 18]
+
+Key = b46a3a24c66eb846ca6413c001153dc6998970c12e7acd5a
+Nonce = b79c33c96a0a90030694163e2a
+
+Count = 180
+Adata = ea9405d6a46cac9783a7b48ac2e25cc9a3a519c4658b2a8770a37240d41587fb
+Payload = 56d18d3e2e496440d0a5c9e1bcb464faf5bc
+CT = 01baba2e0d5b49d600d03a7ed84ee878926c0ca478f40a6fbde01f584d938a1c91bf
+
+Count = 181
+Adata = 72340d595f3dbd23b46513f8f2b73b6249328c705e7968084bcb647fe734a967
+Payload = 7a76eac44486afdb112fc4aab939e4d1eedb
+CT = 2d1dddd46794824dc15a3735ddc36853890be4646492b6f4cb169383c075756073b6
+
+Count = 182
+Adata = d5c87c649579da3f632ba95cb0a07c924095e4bdd4e0376e06bb90e07460172e
+Payload = 48348c5ec996f7a97ef0ba2cd6885572fe64
+CT = 1f5fbb4eea84da3fae8549b3b272d9f099b4f584289f560cbf76606942fe1a92dd63
+
+Count = 183
+Adata = ffa6277395d31d5db13034d362228a87610e441c98ca3038e252a9db12bdbcef
+Payload = d5c58f10e1a03d8a2501d1eaf5fcdfff3ae5
+CT = 82aeb800c2b2101cf57422759106537d5d355964f5f5532d7cddd7207f0e9a6aace9
+
+Count = 184
+Adata = daf83d02a9bd992ea58c23e7ad18d41796314bae20e864e729f40ccc215454fc
+Payload = da2a863ab1c58ddde320ecadeecac9c5d2d8
+CT = 8d41b12a92d7a04b33551f328a304547b50890ae047e35aecfc38ffdc07e7d8f5705
+
+Count = 185
+Adata = 21ddad5f550044dc5cb123ade17eeef549c4e0173b216bcc602c1e736764cca8
+Payload = 4573969afa831c244817230406fe51183091
+CT = 1218a18ad99131b29862d09b6204dd9a5741b2bdf539ceaa35015712dd15265ca476
+
+Count = 186
+Adata = 9228265ae5c3daf1485ff8011738da508bf2a73731396c5d9aa56fc554e0c00b
+Payload = edf5557e15473b747a819398c9ac1459ffdb
+CT = ba9e626e365516e2aaf46007ad5698db980b241412124ae20b84c13b0c3671d305c9
+
+Count = 187
+Adata = c0a2ff0de21b3ba961e06015ccd71374856a65a4c57cf8cde0a1643aca8ed868
+Payload = e139263478900df806a0f3446bd6600c1aeb
+CT = b65211245b82206ed6d500db0f2cec8e7d3bee9803747bf9fa63412bfc4e10aea89e
+
+Count = 188
+Adata = b54378f031a31cf3985f573829c9ffca14616742e0a7e03b0a2d7f05eff0219e
+Payload = 660eaff0f113eaa2f5f7ad4b62bb849a3a25
+CT = 316598e0d201c73425825ed4064108185df55afdf430b57845dcf622d4f25cdeb2a3
+
+Count = 189
+Adata = e67f35c18a9336469eae23040f98f52338ca8d0cab269ac32fe6bc7605d3ea56
+Payload = 0f89897271f5d0349d57399005ea60c0cadc
+CT = 58e2be6252e7fda24d22ca0f6110ec42ad0c7ed4c04c4b4dd585891ecfddeab8cc87
+
+[Plen = 19]
+
+Key = 7b71045ccef735bd0c5bea3cf3b7e16e58d9c62061a204e0
+Nonce = 2b9ecfd179242c295fe6c6fa55
+
+Count = 190
+Adata = b89166f97deb9cc7fdeb63639eeafb145895b307749ec1a293b27115f3aa8232
+Payload = 890d05420d57e3b3d8dbef117fe60c3fa6a095
+CT = f842ff6662684de8785af275fa2d82d587de0687ebe35e883cbd53b82f2a4624c03894
+
+Count = 191
+Adata = 4392c3043287dd096b43b4a37ea7f5dc1d298b0623ccbf4fd650a49569a5b27b
+Payload = 6b425cdcdf8304e7fbb70b2973d55e6940025b
+CT = 1a0da6f8b0bcaabc5b36164df61ed083617cc807d4824f0a98db2d87365a42ca3b80e1
+
+Count = 192
+Adata = 9b4fc98fcdcf485205e7054bc9d1e02d0d8584420537e20d3821de2fd6824787
+Payload = c8bf145fcffbafd6cd1a4c5b6cedfe008aacb2
+CT = b9f0ee7ba0c4018d6d9b513fe92670eaabd221404e631735c544edeeb4c0105c55bf0b
+
+Count = 193
+Adata = 45622e1472542be2f63f463d253617eafd4f2ad609f9020884905dd5c22fba53
+Payload = 12b5a76faedf6f855e328c2cb87be8aea78c5e
+CT = 63fa5d4bc1e0c1defeb391483db0664486f2cdc16a4cf37e8e96eed1217d21133e83d1
+
+Count = 194
+Adata = 958689aea3c6cd19020eff9d635ef44ee0793424df38fdf13a238b969d429777
+Payload = f0927c3cb0a876d7877466507da8bfa0bd9a16
+CT = 81dd8618df97d88c27f57b34f863314a9ce4859facf81a636351f6e67d6ec12636ae0b
+
+Count = 195
+Adata = c22911efc36fa739048af0c951ef2449bb3605c52f65120c4d71fe5976026032
+Payload = d2c5d4e2362f19c99de66da7bd9c495c03d9a1
+CT = a38a2ec65910b7923d6770c33857c7b622a7327ce73a7e2db69d30441f89a03fd0e84e
+
+Count = 196
+Adata = 799da61e2c10ebb4783f618b8f69da7704a1b2b925cebc228af57d7ceebb9825
+Payload = 1c9d7f5b329ef4d384b8b7955a20f8a3fc15cd
+CT = 6dd2857f5da15a882439aaf1dfeb7649dd6b5e8d787a9d06b8533ca96fb1db8aecc8e5
+
+Count = 197
+Adata = 14a8e18afe0b9fe18ddfd754219a7e18ed36f419f8262d91678e10daffb31c81
+Payload = 3a64414c3588d7c26871d7d054ac6c8420d491
+CT = 4b2bbb685ab77999c8f0cab4d167e26e01aa028ff5f819d552c08054b5ac02063e102a
+
+Count = 198
+Adata = 7294a8b4ad97c81969e4a2876a3dc0ee322d554726997dc9ed98c5601985ee5b
+Payload = 545dd71bea9967e07a89f84a2027aacd132187
+CT = 25122d3f85a6c9bbda08e52ea5ec2427325f141cde5af8fada67c47cbb5787a6b2d9c9
+
+Count = 199
+Adata = 99294b22d73805805630fb416d20d4fca67419ab660ff45cd19a3729e81b9f69
+Payload = ec1b17b885c018272652453f47fa6e9ed972b9
+CT = 9d54ed9ceaffb67c86d3585bc231e074f80c2a7412640b179bd3e8a417dc38462c16e8
+
+[Plen = 20]
+
+Key = dc7c67715f2709e150cceff020aaacf88a1e7568191acbcf
+Nonce = da56ea046990c70fa216e5e6c4
+
+Count = 200
+Adata = f799818d91be7bab555a2e39f1f45810a94d07179f94fe1151d95ab963c47611
+Payload = f383bd3e6270876b74abbb5d35e7d4f11d83412c
+CT = 377b5df263c5c74f63603692cbb61ea37b6d686c743f71e15490ca41d245768988719ede
+
+Count = 201
+Adata = 69adcae8a1e9a3f2fe9e62591f7b4c5b19d3b50e769521f67e7ea8d7b58d9fc8
+Payload = 615d724ae94a5daf8d27ad5132d507504898f61e
+CT = a5a59286e8ff1d8b9aec209ecc84cd022e76df5ea9bc8cfaf2a1734a792076618c4b9690
+
+Count = 202
+Adata = 4586f73a1f162b2cdb65f6e798a60b5f48938d40b4612d84c1f39244f14efdce
+Payload = 6e923e1f404002aa5cf8f8aaf1b9772da425e21c
+CT = aa6aded341f5428e4b3375650fe8bd7fc2cbcb5cc5122df904b052e4d5580fdeddf5297c
+
+Count = 203
+Adata = 9f7ae892e5662803408d4d062265846441a43c1fa202da59f640ae722a692671
+Payload = 68115771505daa18bb3ce90054bfb7d077e1f37c
+CT = ace9b7bd51e8ea3cacf764cfaaee7d82110fda3ce0ba1bb1af18e15ade3316c21d6b41fb
+
+Count = 204
+Adata = 1f0769a7ae82bd985661e031c4a892c15d3ef37bdcfb45243d02f40fdb51d34b
+Payload = 681fd2a324b3fea4cfebed567ae4546ba373c8f1
+CT = ace7326f2506be80d820609984b59e39c59de1b1dc71e342fbc44289ef7e53e28edf3839
+
+Count = 205
+Adata = bf957ef5ab2805e58ea752da5793f7f23d98fce1b2b67738929e5de8a15f9801
+Payload = a7b9d2d069941e8b943706a02d2847ea713bb103
+CT = 6341321c68215eaf83fc8b6fd3798db817d59843ced1fb4a2a3e349aa590aabbfc3d13bc
+
+Count = 206
+Adata = 833264c1bebb597043b4158087cb651960915d9023189c9509c0d2aed84e7fe4
+Payload = 9b946e8198ce69d2173e970f4e0c103a47ee4160
+CT = 5f6c8e4d997b29f600f51ac0b05dda68210068205079f6c2739e2b789b6e3d3c60389374
+
+Count = 207
+Adata = 94c8414cbbec52e2d73bb8f02ef687c91432495c0c744666317d02e6d46706d2
+Payload = 81ac4618f3db6bcf9bbf67220b7671be4bb4f8a2
+CT = 4554a6d4f26e2beb8c74eaedf527bbec2d5ad1e22a02f287db7217148317d897f65f6a0c
+
+Count = 208
+Adata = fced1131dab3dabdc1a16d3409fa09a90ffe02f0e2c814a63f77f771c08c3389
+Payload = 90851933d4d3257137984cdb9cba2ca737322dac
+CT = 547df9ffd56665552053c11462ebe6f551dc04ec362df9f8b41b1dd4821f8f14e9e633d7
+
+Count = 209
+Adata = 495dfcf91f4735ab35c6bc4deef8468bd988e4099cd291a32b4707f93e13d82b
+Payload = c14ce6d57f0fe7367331c9fe159ae1fb8f1ccb2c
+CT = 05b406197ebaa71264fa4431ebcb2ba9e9f2e26cf61ffb51e56497ca9f39c6665fcbdfa8
+
+[Plen = 21]
+
+Key = f41e369a1599627e76983e9a4fc2e963dab4960b09ebe390
+Nonce = 68ef8285b90f28bcd3cb1bacea
+
+Count = 210
+Adata = dbe3e82e49624d968f5463ceb8af189fb3ad8b3b4122142b110d848a286dae71
+Payload = 81ad3f386bedcbf656ff535c63580d1f87e3c72326
+CT = 9f6028153e06d14d30b862a99a35413413c04a49dc6f68a03a11cf00d58f062a7b36465d13
+
+Count = 211
+Adata = d9acfd611e5bbb08c5d05d56791b8aebabf8d69734ec89153c91a1f65b2e1adb
+Payload = 35f6bb3f6a388f3a5a039b0a495b676d0b928aeb19
+CT = 2b3bac123fd395813c44aaffb0362b469fb10781e3ca1fb470b666523a19f83481f16481ed
+
+Count = 212
+Adata = 6003b771afe4e99e1ef1ed4a31b10540d95f4ac49885f0c8e5cdcb63d213127e
+Payload = 6aa7e3802b5a29d4f9ca88eb59f94af783d1054466
+CT = 746af4ad7eb1336f9f8db91ea09406dc17f2882e9c53cb05bfcd64da2b45c2e9a89a380b49
+
+Count = 213
+Adata = c371644275a6290821e7d308714bec2bf62d36c30f7fa77a0d60b28894f1c82a
+Payload = 13332b67ba5ba18137c306bd860dc3eb0a9a0b871a
+CT = 0dfe3c4aefb0bb3a518437487f608fc09eb986ede048f70fbc680cf7092b3dd90b943fc6e5
+
+Count = 214
+Adata = 8eceb15300ec4220510ed5b7deb3429de6ae5f618e1c222c28990a9ab4b4bac8
+Payload = 05981dc26a1db2d8e2c3d85ea9a4d1dc3432d9edc4
+CT = 1b550aef3ff6a8638484e9ab50c99df7a01154873ee386f33c0b8da8d0c5934e617dd618e5
+
+Count = 215
+Adata = 96d1cf3690c48c77a155ce13e67bbd62e6f03d88c893c1f7c30a6435d5ab36e0
+Payload = 60249343a8cd4d33c6edc583ea7e5c221ef3064787
+CT = 7ee9846efd265788a0aaf476131310098ad08b2d7d3d2db1360fb1121893f4d197731bce4f
+
+Count = 216
+Adata = 379bbc9f919dc2a8687f2a86cc9c3291804240a9b566c58519956848102e6155
+Payload = 79003a8d3d20d412f468f11712cec4d37cee847440
+CT = 67cd2da068cbcea9922fc0e2eba388f8e8cd091eba335ce1bfafc0948f2523e75f2aad86f9
+
+Count = 217
+Adata = 9bff9c9a8f94cd77e7016748da31f86d1b9c68465cbf954511c93a4776981524
+Payload = 7d078a8b200514a00628756250d410f7a0f8a769e6
+CT = 63ca9da675ee0e1b606f4497a9b95cdc34db2a031c7dc265e281307f0f4c38cddc556ac725
+
+Count = 218
+Adata = 25125a4668c31dc2e8a68b6c4c95ad7cf9322852e371b415a357d09acb01b587
+Payload = d9b0eaaff786165f882f41a98dbc0c355b3a1aaf40
+CT = c77dfd82a26d0ce4ee68705c74d1401ecf1997c5ba61c78a2f85a447c3e62b6197d65b9065
+
+Count = 219
+Adata = ad34d8f0902a5b79fb145b8206bb4d3b77e0bd8ae2d0964815389eacb33b4007
+Payload = 17b517ef577f588da374340d2522cc9ea642c8d8ae
+CT = 097800c202944236c53305f8dc4f80b5326145b2540312d067c08a9b4400e1df8bb7ed671a
+
+[Plen = 22]
+
+Key = 3289e59e3a7b29bf4a309afc253030bba4b9bdd64f0722f9
+Nonce = 30259ce106e9bd7a8bacbaf212
+
+Count = 220
+Adata = 2870bd9a26c510e9a256920899bbc77a4eb9b53f927045a943d5ed6b13638cf3
+Payload = 53911a67b65738f87fc7c20d6db8044bde1af95838d1
+CT = 70cf37d4b6f7e707376b1574ce17c040b5143da47abb2fe9afafc2fccd98ccf63b0fdec30eac
+
+Count = 221
+Adata = 611032a95ee87f89ad6be7c0fed8bd245c5f81076087b3bda4cde5587b8d14b6
+Payload = 46917e38b8a542296d290d065b0aa7c8aaa38950c386
+CT = 65cf538bb8059dd62585da7ff8a563c3c1ad4dac81ec102dfd8c231d6a355f079c213ce6858e
+
+Count = 222
+Adata = 2e7ea26d1cceaca3b7862a7a8469e366b52ec27ca127e3317222ee651d8da4a0
+Payload = b527828c89f674dc6f024f8cdd80c694bb3ebd57b2d9
+CT = 9679af3f8956ab2327ae98f57e2f029fd03079abf0b36df11febe34dd568da12c374674b9ac4
+
+Count = 223
+Adata = 0bf4413010daec585de34142224d1cad3072f9720f91ac664ad152820e838741
+Payload = 78230f73f9c0150f630eca4cd679818551d449db82e6
+CT = 5b7d22c0f960caf02ba21d3575d6458e3ada8d27c08cb2916540d9439b832aa44236a7e187ac
+
+Count = 224
+Adata = 2e7cae3306582eb5bad148247aa6c6ec943f8748e84b8a069ca9488b11844716
+Payload = 847bb12e0e56fa07a086eeda5907ae148148fa4107d2
+CT = a7259c9d0ef625f8e82a39a3faa86a1fea463ebd45b80d0768a18dead55700901408aa3f901a
+
+Count = 225
+Adata = 63036dc4ad13aee5dc1832e867f7538da108188fec7b08262af440d07579c451
+Payload = ec59e208c4bb429a371f1b3ffdf07fce5dea8a05f0ce
+CT = cf07cfbbc41b9d657fb3cc465e5fbbc536e44ef9b2a45f2073605d2a441805b6ff89d8beb68c
+
+Count = 226
+Adata = f9ec5ce4b63156d57e451eb67ab6d7a59cc397f43f6d26dc07d1036f0fb4a8cf
+Payload = fb12d94bd21b5748b23132a03065c78dae65a0bd2cfb
+CT = d84cf4f8d2bb88b7fa9de5d993ca0386c56b64416e91dcabef6907811c6b7df4e74c7a63d83b
+
+Count = 227
+Adata = e13a204e16f42bbf4716e95f1cb7e125ffac66a87f591c8ef2c7b8485ff707fd
+Payload = 239fa31d4a65de0318bfc5b60a06d706c129dcf255ac
+CT = 00c18eae4ac501fc501312cfa9a9130daa27180e17c626aa8aa37e858cd990f5593d9ef35f2a
+
+Count = 228
+Adata = c4591c3ad984a1e189c526b719212f8248289eeb277827272b8205d78191eb2d
+Payload = 57caadbb1a56cc5b8a5cf9584552e17e7af9542ba13e
+CT = 749480081af613a4c2f02e21e6fd257511f790d7e354d81e424d6b4528901ae46fb35f8b3106
+
+Count = 229
+Adata = cf4795bc7f43c30d3c3a8fd1b8a9d77d69bf59eb8b59d0f464315f40cb52335d
+Payload = a68c74e05f0a44d4a0372c0e5915b83d8e6729efacbb
+CT = 85d259535faa9b2be89bfb77faba7c36e569ed13eed1f25a4bfda35e1390f3f16f638dcd4047
+
+[Plen = 23]
+
+Key = 40f1aff2e44d05f12126097a0f07ac0359ba1a609356a4e6
+Nonce = 0df3fc6396f851785fca9aa5ff
+
+Count = 230
+Adata = e9699b20b0574fce8b5cbc4ef792eb96e2c1cce36b1b1f06ea2a95fe300633cc
+Payload = 8d98c580fb366f330dbfda20f91d99a0878b47efd14c6d
+CT = 579cdf9da62a2df471e03450516adb4ce99ae0f70b1776a39c3b429a1f922fac0b59e29a122e43
+
+Count = 231
+Adata = bd94c9ad6253c25dc417f87b6e52e03621ccf4b3bff5b402677aeb51e216335f
+Payload = 7391ba60fabe2c632bbaca16af9a235b2c7dae61691c0b
+CT = a995a07da7a26ea457e5246607ed61b7426c0979b3471067bf538e40f9366adf8758968f06ce8a
+
+Count = 232
+Adata = 4f263cda4a50b0e5379ec2fb546b326a07943527c1d175c029455a917753883b
+Payload = 7e1e93a6ca35a2c0e4f08fdb2e7ee22b9f486f0ab919e2
+CT = a41a89bb9729e00798af61ab8609a0c7f159c8126342f964a1199251b54f419720a30de83161de
+
+Count = 233
+Adata = 4d43702be4f0530319555d7f1a3356160f6cae48051f12e22a153d7e405c1149
+Payload = f94ff053c7413f34f96eae41fd1ac101151069af5a9428
+CT = 234bea4e9a5d7df385314031556d83ed7b01ceb780cf33b417e4cceb8dcf45ef33cc0007755bbc
+
+Count = 234
+Adata = f4d7978fad36223623ccb5bb18a7373cba8a6e3b1c921259e319266042db8887
+Payload = ba0716355fffb8ef947d2a15eb58375a1ff1084c566990
+CT = 60030c2802e3fa28e822c465432f75b671e0af548c328bd35aed57f49dcfecf248cf9d246ac024
+
+Count = 235
+Adata = 12e4fe727b1f27a619dd67bb976ddc2b18b2ef8b7184290d9553494a500d933e
+Payload = 872940780a94680a791c937994ceafd2c8b7a22b5f4927
+CT = 5d2d5a6557882acd05437d093cb9ed3ea6a6053385123c97cda0e04d2ff65c2e06a8276bdf6f97
+
+Count = 236
+Adata = 2c16724296ff85e079627be3053ea95adf35722c21886baba343bd6c79b5cb57
+Payload = d71864877f2578db092daba2d6a1f9f4698a9c356c7830
+CT = 0d1c7e9a22393a1c757245d27ed6bb18079b3b2db6232b3494dd2ee0a0fe5bfc9f69234c8142ed
+
+Count = 237
+Adata = cefc4f2fb796c2502329ca3d8f8af3200dd9edb8f164e15acec90536a15b6fdc
+Payload = cda681aa3109ebf5f21ee3a849098ea3a551e844fae4b4
+CT = 17a29bb76c15a9328e410dd8e17ecc4fcb404f5c20bfaf9008ead8e923997508eebf5e776198dc
+
+Count = 238
+Adata = 94fc7eb8febb832097ba6eecd2697da91b5a8a1f2248f67a7659e0ac55a09a0d
+Payload = d4f8d262870b5000a40b8fcce88f55c65c4d12e729975e
+CT = 0efcc87fda1712c7d85461bc40f8172a325cb5fff3cc45f136cc6ea1b0fdb554e0803053875b89
+
+Count = 239
+Adata = 459085184094e302b2e921cc04270b676e75bbcf0e4b53ed387df2bd0e75e0ac
+Payload = 732f211061c0a32c6ad124c58418d560ef5eab2602314c
+CT = a92b3b0d3cdce1eb168ecab52c6f978c814f0c3ed86a575da8ceccae093888daaf92c95817fc3d
+
+[Plen = 24]
+
+Key = 91f9d636a071c3aad1743137e0644a73de9e47bd76acd919
+Nonce = 1bf491ac320d660eb2dd45c6c3
+
+Count = 240
+Adata = 3bdfd7f18d2b6d0804d779f0679aaa2d7d32978c2df8015ae4b758d337be81dd
+Payload = 4eaf9384cad976f65f98042d561d760b5a787330dc658f6c
+CT = 635530cab14e3d0a135bb6eebb5829412676e6dd4995f99cb7e17f235bd660e7e17b2c65320e9fd4
+
+Count = 241
+Adata = 9de45b7e30bb67e88735b8fb7729d6f3de46c78921b228bad8f17cc9c709c387
+Payload = 59bee7d18fd4ba573f3e4f61076f5b9f6a3487e47d98c729
+CT = 7444449ff443f1ab73fdfda2ea2a04d5163a1209e868b1d99f40890c7d650afccda40fb2a4cd603b
+
+Count = 242
+Adata = 783477f981ef0551b5e7a714b640bbb38316c53756c96e30c898cdee3b72e6f4
+Payload = 4e7f3c86d846ff351db81dbe1d2e9ed73ec0450587ae681b
+CT = 63859fc8a3d1b4c9517baf7df06bc19d42ced0e8125e1eeb50236cf1a12a9e3542a4051788f9775a
+
+Count = 243
+Adata = 2851d40243512a43f70f9c25e9b18c122a1433f05c61e65017e197e88b129e43
+Payload = 2db7cb2739c839383b64c2c93c7d5c906d984756c3dedaa9
+CT = 004d6869425f72c477a7700ad13803da1196d2bb562eac59b1bbad9861192df356c6678b2f561ea3
+
+Count = 244
+Adata = 1cfa2d62cc1f6313fb0c6eb21803e09cdf61ee3ddb15192529560e5d8096cafb
+Payload = 2f2b82497c78369890809460d80a16be4f3330e8a0089165
+CT = 02d1210707ef7d64dc4326a3354f49f4333da50535f8e7951da4211d4c28d2d91568117fc99fd911
+
+Count = 245
+Adata = 5a14b556156191b2704936f64df0bf1dd2bd8d587418f4f85472338fcf86aa52
+Payload = 7cfefca725da1b6bb5d9545e3e50f5a624a8160bdb0e7d4e
+CT = 51045fe95e4d5097f91ae69dd315aaec58a683e64efe0bbeda99be0e054bb881a25a74b547d3ed5e
+
+Count = 246
+Adata = 148de640f3c11591a6f8c5c48632c5fb79d3b7e1cef9159c680d71fd1f9801fa
+Payload = 5205165c4e9612974dc92f60d1e328d68aa9466e27dbd499
+CT = 7fffb5123501596b010a9da33ca6779cf6a7d383b22ba2694c1fedb47fa30ff2ead6bf382431b2de
+
+Count = 247
+Adata = f852e38703097cc37c589b7860dbc333e091411462d5576dc9909a8cf6ac99d4
+Payload = f968f2833427abbc9fe1cab7e7a3f905a3b23a35802029ff
+CT = d49251cd4fb0e040d32278740ae6a64fdfbcafd815d05f0f338762a4e4299615c67130a28b56a383
+
+Count = 248
+Adata = 43df03a0e23c7ad0d13485150ca224c0b3f39d4e5f2d718db6308e003d3dc683
+Payload = 67da6ca42655188af0b8e389152b2a1b6e2c3ed88926afa5
+CT = 4a20cfea5dc25376bc7b514af86e75511222ab351cd6d9559dbdf61387294812f483aad76d48d899
+
+Count = 249
+Adata = b297dce04ada2ddebc7e94eff7c51b87eee2f98c410c5c0919d0652653ab7458
+Payload = 9777cf90dd7c7e863506686fc3ba6d3d05328f78b350f92f
+CT = ba8d6cdea6eb357a79c5daac2eff3277793c1a9526a08fdf078177541e19b11dfec995f40c99af70
diff --git a/lib/crypto/test/crypto_SUITE_data/VPT256.rsp b/lib/crypto/test/crypto_SUITE_data/VPT256.rsp
new file mode 100644
index 0000000000..e9cd7eefe9
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/VPT256.rsp
@@ -0,0 +1,1383 @@
+# CAVS 11.0
+# "CCM-VPT" information
+# AES Keylen: 256
+# Generated on Tue Mar 15 08:09:25 2011
+
+Alen = 32
+Nlen = 13
+Tlen = 16
+
+[Plen = 0]
+
+Key = c6c14c655e52c8a4c7e8d54e974d698e1f21ee3ba717a0adfa6136d02668c476
+Nonce = 291e91b19de518cd7806de44f6
+
+Count = 0
+Adata = b4f8326944a45d95f91887c2a6ac36b60eea5edef84c1c358146a666b6878335
+Payload = 00
+CT = ca482c674b599046cc7d7ee0d00eec1e
+
+Count = 1
+Adata = 36c17fd901169e5b144fdb2c4bea8cd65ad8acf7b4d3dd39acf2ad83da7b1971
+Payload = 00
+CT = 67747defe5da5fecc00b9bf3b249f434
+
+Count = 2
+Adata = 9a37c654ab8e5a0c6bdfff9793457197d206ed207d768cbc8318cfb39f077b89
+Payload = 00
+CT = c57ef5d0faf49149c311707493a4cfd4
+
+Count = 3
+Adata = 5ab80169184541393a6975f442ee583cd432d71a6d1568fa51159df7c5b8f959
+Payload = 00
+CT = bc2fb5571a7563bb90689a229d2f63a7
+
+Count = 4
+Adata = c78a22a667aafab0c94047e03837d51b11490693d5c57ea27b901ff80b6a38f9
+Payload = 00
+CT = 428888c6420c56806f465b415a66e65a
+
+Count = 5
+Adata = e11e30cbf63623816379f578788b0c8e6b59ee3c9c50aa6e1dcd749172d48fed
+Payload = 00
+CT = 9f1b7520025e1075731adc946b80121d
+
+Count = 6
+Adata = 05716168829276ff7ab23b7dd373db361e6d9e1f11d0028d374a0d3fe62be19f
+Payload = 00
+CT = bd36b053b6a90f19e3b6622cba93105d
+
+Count = 7
+Adata = 3e915389639435629fcc01e1b7022d3574e2848e9151261ad801d03387425dd7
+Payload = 00
+CT = 458595a3413b965b189de46703760aa0
+
+Count = 8
+Adata = 2f496be73a9a5d9db5927e622e166c6ec946150687b21c51c8ca7e680f9775ac
+Payload = 00
+CT = 8b259b84a6ee5669e175affca8ba3b1a
+
+Count = 9
+Adata = 0a8725bd8c8eab9ed52ca47835837b9f00a6c8d834ab17105b01eb4eb30402e7
+Payload = 00
+CT = c5f35fdf2b63e77a18d154f0ddcfedbf
+
+[Plen = 1]
+
+Key = cc49d4a397887cb57bc92c8a8c26a7aac205c653ef4011c1f48390ad35f5df14
+Nonce = 6df8c5c28d1728975a0b766cd7
+
+Count = 10
+Adata = 080f82469505118842e5fa70df5323de175a37609904ee5e76288f94ca84b3c5
+Payload = 1a
+CT = a5f24e87a11a95374d4c190945bf08ef2f
+
+Count = 11
+Adata = f6cfb81373f1cbb0574dda514747d0099635b48cb809c6f1fa30cbb671baa505
+Payload = 40
+CT = ffd43c5f39be92778fdce3c832d2d3a019
+
+Count = 12
+Adata = 5a88b14bada16b513d4aa349b11ce4a77d4cda6f6322ff4939ad77d8ecb63748
+Payload = 41
+CT = fe753b7b661f1aad57c24c889b1c4fe513
+
+Count = 13
+Adata = a92b95b997cf9efded9ff5e1bff2e49d32e65f6283552ded4b05485b011f853f
+Payload = 06
+CT = b91c5ac66e89bf2769ef5f38a3f1738b24
+
+Count = 14
+Adata = a206a1eb70a9d24bb5e72f314e7d91de074f59055653bdd24aab5f2bbe112436
+Payload = c8
+CT = 773fe64379cea1a8ae3627418dd3e489a2
+
+Count = 15
+Adata = d3029f384fd7859c287e38c61a9475d5ddbfd64af93746b1dc86b8842a8c194c
+Payload = e2
+CT = 5dabc529442ff93005551b7689bcb748f7
+
+Count = 16
+Adata = 51ca3d3b70b5e354451a5177d7acfd8e7b44eae55e29d88b5e8eb8fc1e5c62fc
+Payload = 1a
+CT = a5ee68e416617ac974b3d1af7320cd51f6
+
+Count = 17
+Adata = 8c6c6791f1ac957b18bf008e260a0af4a5b7bfdb1e0008d6eaaa227f45cf4f62
+Payload = dd
+CT = 6243883d93d7066991e0fac453400b4fbf
+
+Count = 18
+Adata = b0a1af969a95025385b251afd1e89f353426ed6e5d71019cd73366aa31d5b464
+Payload = 4c
+CT = f3b940d416f3435812f9d1b18f441b7721
+
+Count = 19
+Adata = 7e72b2ca698a18cb0bf625f5daddb0d40643009db938340a9e4fe164a052fee1
+Payload = 88
+CT = 371d27e9a32feea28a6a7e7da2d27e1cc4
+
+[Plen = 2]
+
+Key = 36b0175379e7ae19c277fe656a2252a82796309be0f0d4e1c07fdde88aca4510
+Nonce = 021bd8b551947be4c18cf1a455
+
+Count = 20
+Adata = b5c6e8313b9c68e6bb84bffd65fa4108d243f580eab99bb80563ed1050c8266b
+Payload = be80
+CT = ecacc3152e43d9efea26e16c1d1793e2a8c4
+
+Count = 21
+Adata = 38e5032c5949c2668191ef1af5bb17eddc28abdb4e5bb41eaffec2523b2525d6
+Payload = 82c9
+CT = d0e5d06bf4b50ccce0b2acfd16ce90a8854d
+
+Count = 22
+Adata = 0b50f5173249fb7118f80d25874d6745d88e4ce265fa0dd141ad67ae26c31122
+Payload = 8239
+CT = d0158d784f486c1dc4a2bafd5b02ca1e1c05
+
+Count = 23
+Adata = 0296743a3125b103a2b2a78a109e825ea10834bd684215ab2e85cc4172e37348
+Payload = 16c1
+CT = 44eda3377002a48f9fe306d157358e6df37d
+
+Count = 24
+Adata = a94e64becb803e211785ba51db7f3db042fbf44a7a821509156a6828b0f207e9
+Payload = 2801
+CT = 7a2df6c09bf1dcb1c82bd98c6e2c13a8d7a5
+
+Count = 25
+Adata = 105358cc17b12107e023a23d57b44c66a2c58d8db05100311575e1ea152fc350
+Payload = 65e7
+CT = 37cb2ea363c0d8864363056467570959ba03
+
+Count = 26
+Adata = 669f9a63cf638a202dca1965c4116273249813ce0b39703887d89bdf5b3b12d6
+Payload = 819d
+CT = d3b16519377e6d0252b5f80cdf3d0253eccf
+
+Count = 27
+Adata = e288590a3eba28ac6847a50b0294ab6bd0a548716ff5102c44a5b656b2d9ddd6
+Payload = 761e
+CT = 24329a4dee6ca2cde473f08f76f779856c3c
+
+Count = 28
+Adata = 5b222aae3c7786c3b9021ba672f9136190ec931cf055f84c85706127f74c6d5b
+Payload = 56de
+CT = 04f29e65c0f01e644e74092253b470cd5511
+
+Count = 29
+Adata = 2082f96c7e36b204ad076d8b2f796cccf5cbc80b8384b53a504e07706b07f596
+Payload = b275
+CT = e059809fa107f379957b52ac29fe0bc8a1e2
+
+[Plen = 3]
+
+Key = ddb739acda6c56ec9aefc4f4cbc258587f443da4e76ddfa85dbe0813a8784944
+Nonce = 0bddf342121b82f906368b0d7b
+
+Count = 30
+Adata = 887486fff7922768186363ef17eb78e5cf2fab8f47a4eb327de8b16d63b02acb
+Payload = db457c
+CT = 54473c3f65d6be431e79700378049ac06f2599
+
+Count = 31
+Adata = 0683c20e82d3c66787cb047f0b1eb1c58cdde9fb99ee4e4494bbf27eb62777d1
+Payload = 62a6c5
+CT = eda4853b186edc15c22ba24e470eb5a072da9f
+
+Count = 32
+Adata = 413074619b598f8bed34cab51ddf59941861ba0169ebe7570a5ed01d790c08e5
+Payload = cc67bc
+CT = 4365fc52a1fb5a58bd51931230c1a7dfb1a8c1
+
+Count = 33
+Adata = 2d65a5175c29a095dc082dab9cfcf4b895efbfa715c57614589d4db159543ce9
+Payload = 33800b
+CT = bc824b7d3810f59176cb108c7e969da51d4d79
+
+Count = 34
+Adata = 6a831b6059456be98e6fce608d8c71cb8efb04a96b45c2dfbdaeabf5420a1482
+Payload = b2c826
+CT = 3dca6646ffea832595c9c86e6517215541ddbd
+
+Count = 35
+Adata = 3a04a01160402bf36f33337c340883597207972728c5014213980cd7744e9e41
+Payload = d7e620
+CT = 58e460e89a6725f0fc35622d89d2f3e34be90a
+
+Count = 36
+Adata = 64d8bd3c646f76dc6ce89defd40777fe17316729e22ba90f6a2443ee03f6390b
+Payload = 795af4
+CT = f658b4b1bd7ad5d81686aeb44caa6025d488bd
+
+Count = 37
+Adata = 7bef8d35616108922aab78936967204980b8a4945b31602f5ef2feec9b144841
+Payload = 66efcd
+CT = e9ed8d0553c801f37c2b6f82861a3cd68a75e3
+
+Count = 38
+Adata = 92f7dc22dcbbe6420aca303bd586e5a24f4c3ed923a6ebe01ec1b66eee216341
+Payload = 78b00d
+CT = f7b24de3eeb8ea6c08b466baf246b3667feb3f
+
+Count = 39
+Adata = 71bf573cf63b0022d8143780fc2d9c7dbd0505ac31e9dce0ad68c2428b0878a0
+Payload = 9dd5e1
+CT = 12d7a11db811640c533794bfec6eeb977233ec
+
+[Plen = 4]
+
+Key = 62b82637e567ad27c3066d533ed76e314522ac5c53851a8c958ce6c64b82ffd0
+Nonce = 5bc2896d8b81999546f88232ab
+
+Count = 40
+Adata = fffb40b0d18cb23018aac109bf62d849adca42629d8a9ad1299b83fe274f9a63
+Payload = 87294078
+CT = 2bc22735ab21dfdcfe95bd83592fb6b4168d9a23
+
+Count = 41
+Adata = 75c3b3059e59032067e9cd94d872e66f168e503bcf46bc78d82a4d4a15a29f6e
+Payload = 0f28ee1c
+CT = a3c38951b5de3331078aa13bd3742b59df4f661a
+
+Count = 42
+Adata = 8fb9569f18a256aff71601d8412d22863e5a6e6f639214d180b095fa3b18d60e
+Payload = d41c9c87
+CT = 78f7fbcae52afe7326a12a9aaf22255a38d4bd0d
+
+Count = 43
+Adata = 8b62d9adf6819c46c870df8a1486f0a329672f7d137bb7d8659f419c361a466c
+Payload = 046bc0d8
+CT = a880a7957543692a72f0d599de48b5e5f5a9413f
+
+Count = 44
+Adata = fd98f8f39dfa46ea5926e0ffacbabbe8c34205aade08aa0df82e1d4eaaf95515
+Payload = 39bd4db8
+CT = 95562af530fc357f5482b9004d466bf858586acb
+
+Count = 45
+Adata = 09bf4f77a9883733590a3cc7ee97f3c9b70f4db255620e88cd5080badc73684c
+Payload = b43cdd3a
+CT = 18d7ba77a9e8db046fdd548b52d40375c1e9a448
+
+Count = 46
+Adata = 40326d765e0f6cf4b4deccb128bebf65a7b3c3e5bcf1d58f6158e1e9153b7e85
+Payload = e0052e9b
+CT = 4cee49d64efbdd4ad8d3e863172d9372fca07c20
+
+Count = 47
+Adata = aa5ae6dcdc21b5446489bdabf5c6747bdf3bbfdb3de2c03170efefe5ccb06d69
+Payload = 696825f6
+CT = c58342bb95bd661b32bc18025808f8b4035acad6
+
+Count = 48
+Adata = d3d34f140a856e55b29471fde4c0e5f7306b76d03faab26db79c10f95ffb3122
+Payload = 7eb07739
+CT = d25b1074ac05b072264e31a4b2801a6d790512d7
+
+Count = 49
+Adata = 648a84813ca97aef4ab7e143ee29acb946388660f18eb671194646e0b0136432
+Payload = 9cad70b1
+CT = 304617fcc00514d260e1d211de361c254369e93a
+
+[Plen = 5]
+
+Key = bc29a16e19cfbe32bf4948e8e4484159bc819b7eec504e4441a1a98ca210e576
+Nonce = 4f18bcc8ee0bbb80de30a9e086
+
+Count = 50
+Adata = 574931ae4b24bdf7e9217eca6ce2a07287999e529f6e106e3721c42dacf00f5d
+Payload = 3e8c6d1b12
+CT = 45f3795fcf9c66e1a43103d9a18f5fba5fab83f994
+
+Count = 51
+Adata = 99cd9d15630a55e166114f04093bd1bb6dbb94ecaad126fe5c408dee5f012d9f
+Payload = 76fc98ec66
+CT = 0d838ca8bb6f3cd579294f706213ed0f0bf32f00c5
+
+Count = 52
+Adata = 1516fdf7a7a99f3c9acc7fff686203dec794c3e52272985449ddf5a268a47bc3
+Payload = 6564c247cc
+CT = 1e1bd603117d38e026f706c9273dbcb6dc982751d0
+
+Count = 53
+Adata = 0c9c35be98591bf6737fc8d5624dcdba1a3523c6029013363b9153f0de77725b
+Payload = c11b9c9d76
+CT = ba6488d9abc3e46166767c6ad2aeffb347168b1b55
+
+Count = 54
+Adata = e74afe3ba960e6409dba78ecb9457e2a4ce2e09792b1d2e3858f4c79f7ddba62
+Payload = 45a4e0d7dd
+CT = 3edbf4930033a7dca78bcbf4d75d651ee5fadff31b
+
+Count = 55
+Adata = 96cbe9cd193513599c81f5a520fabaff51ee8cbdb81063c8311b1a57a0b8c8fd
+Payload = e5861b2327
+CT = 9ef90f67fa11585167c83105ee16828a574c84ac86
+
+Count = 56
+Adata = 2e7ea84da4bc4d7cfb463e3f2c8647057afff3fbececa1d20024dac29e41e2cf
+Payload = f5b5bcc38e
+CT = 8ecaa88753ffaba456f78e431f4baa5665f14e1845
+
+Count = 57
+Adata = be125386f5be9532e36786d2e4011f1149abd227b9841150d1c00f7d0efbca4a
+Payload = b6cc89c75d
+CT = cdb39d838034714731f9503993df357954ecb19cd3
+
+Count = 58
+Adata = 3fa8628594b2645bc35530203dca640838037daeaf9cf8acaa0fb76abf27a733
+Payload = 3802f2aa9e
+CT = 437de6ee436c1b008b7572752f04362b2bfdc296bb
+
+Count = 59
+Adata = 642ae3466661ce1f51783deece86c38e986b8c0adea9e410e976f8a2fe0fe10f
+Payload = e082b8741c
+CT = 9bfdac30c1a3f7c3c29dc312c1f51a675400500e32
+
+[Plen = 6]
+
+Key = 5f4b4f97b6aa48adb3336c451aac377fde4adf47897fd9ccdf139f33be76b18c
+Nonce = 7a76eac44486afdb112fc4aab9
+
+Count = 60
+Adata = a66c980f6621e03ff93b55d5a148615c4ad36d6cbdd0b22b173b4b1479fb8ff7
+Payload = 1b62ad19dcac
+CT = 4ad1fcf57c12b14e0e659a6305b4aeffae82f8a66c94
+
+Count = 61
+Adata = c13f65bd491cb172a0f7bbc4a056c579484b62695e90383358d605307d5be0a5
+Payload = 3ef0faaa9b79
+CT = 6f43ab463bc779fa7932d365e2da9b05c00a7318384a
+
+Count = 62
+Adata = 59dcca8fc50740831f8f259eb55d4db11f763a83187d93758d78d166f4d73cd5
+Payload = 1a98ddbf35f1
+CT = 4b2b8c53954f813229912137b7a4945dc07cea24a974
+
+Count = 63
+Adata = 578509ca4f57aadb78056794bf18b0714090970db786e2e838105e672165761c
+Payload = f46a7b1c28ea
+CT = a5d92af088546e045f19f737a24c8addf832ed3f7a42
+
+Count = 64
+Adata = 696c0c6427273cf06be79f2206c43af9cbda0b884efaf04deba0c4bf0a25cb26
+Payload = e98f5e5a20d0
+CT = b83c0fb6806edaae8a7dcd3b0fbb59438f88743ec6e8
+
+Count = 65
+Adata = 95a66b60249ed086eecaeb9bc449afcee9de212619e87516ca947351b25120df
+Payload = 06319c0480e2
+CT = 5782cde8205cd9cb636ca6543c4e35964f47341f2814
+
+Count = 66
+Adata = 2b411bea57b51d10a4d2fb17ef0f204aa53cf112e1130c21d411cdf16a84176d
+Payload = f4c723433b7c
+CT = a57472af9bc2ec82eadf4eb1f055da1a92a82052ab8b
+
+Count = 67
+Adata = ff3bff3a26fc5a91252d795f7e1b06f352314eb676bff50dc9fbe881c446941e
+Payload = 02f809b01ce3
+CT = 534b585cbc5d01b10a7ae24a4ca2bfb07ea2a3b31a97
+
+Count = 68
+Adata = f6be4aad63d33a96c0b5e9c4be62323c9e2308b29961fff980ba0dbda0549274
+Payload = 2b6004823a29
+CT = 7ad3556e9a97231323a4b88af5d7d0b07c0e73ddce1d
+
+Count = 69
+Adata = c3706a28d7420b41e072dcecc06b6b13116cca110bde8faea8e51f5107352d71
+Payload = 236c60cba4fa
+CT = 72df31270444db30eb33d2ede33abbe22f37704fe68b
+
+[Plen = 7]
+
+Key = f7aaeff3a1dc0cc5ecf220c67ad9f6dda060b4f1be3cc609cb4f18b2342a88a2
+Nonce = d0d6871b9adc8623ac63faf00f
+
+Count = 70
+Adata = e97175c23c5b47da8ce67811c6d60a7499b3b7e1347ad860519285b67201fe38
+Payload = d48daa2919348d
+CT = eb32ab153a8e092fa325bafc176a07c31e6cc0a852d288
+
+Count = 71
+Adata = ba45e1859efae362a44a0116a14e488ba369da6c76c3913b6df8e69e5e1111fa
+Payload = f95b716bfe3475
+CT = c6e47057dd8ef1a24840f4f40a7963becde3a85968b29c
+
+Count = 72
+Adata = efcaa6f6cda3036b0b52ff9f36bc38ca74049c32c6b7cdfb8a46ca4144bacd64
+Payload = 4862e3677083f0
+CT = 77dde25b5339748f2a4a5c276727e0a210fc2efb5aeabe
+
+Count = 73
+Adata = 360bcb407603fe92f856bf677625b9882521e6dae8f35fdfc3dc737f9398f609
+Payload = 7f1ca0728f6d65
+CT = 40a3a14eacd7e1051734fc31232ab2ab63474020ab4dc9
+
+Count = 74
+Adata = f12ee9d37946cfd88516cbe4a046f08c9bbba76a3973ff1e2cb14493405bd384
+Payload = 67478ef73290fa
+CT = 58f88fcb112a7ec715244f307609ffa253e4e3659b0ece
+
+Count = 75
+Adata = 5833dde0c577b2be4eb4b3d01d7b0042fa8441ad7043ea462bbbbd56a59790ea
+Payload = 36bb9e511276c5
+CT = 09049f6d31cc41f11047da612d2987fa2e50ada5ae7f9d
+
+Count = 76
+Adata = 1e103c63d8ead36b985f921044cd32b8f9f04a2ba9fa154a09e676ffaa093970
+Payload = d68d6556c5a5b1
+CT = e932646ae61f35382f7648718127ebae7eb7443ebd2c2c
+
+Count = 77
+Adata = a1cfb61d45a140bdea6329ba0fe80429ff9aa4624a1d31bc752f7c97f1d390a0
+Payload = 0568cca4ff79dc
+CT = 3ad7cd98dcc358cc40a5e7fffb1fb9a5dd9d6ba91bede1
+
+Count = 78
+Adata = 116b5b015e44ceef0061b2d2e73fa0b386d5c1e187782beebdfc6efb5a1c6935
+Payload = bd93d08eea4263
+CT = 822cd1b2c9f8e7468d2b70c311732f11ed72b57d83e500
+
+Count = 79
+Adata = 3d55882e6f3f89309b6940a3b408e573458eedd10fc3d0e1f3170eb313367475
+Payload = 4fb62753024e92
+CT = 7009266f21f416b41a70f548e359add30c0e5746fbeb2b
+
+[Plen = 8]
+
+Key = 493e14623cd250058a7fc66a3fee0c24b6e363b966c2314aff53b276b6c2ea7b
+Nonce = fe2d8ae8da94a6df563f89ce00
+
+Count = 80
+Adata = 579a637e37a0974cd2fc3b735d9ed088e8e488ffe210f043e0f9d2079a015ad6
+Payload = e5653e512d8b0b70
+CT = 75d31f8d47bee5c4e2ba537355ae8ab25cc9ed3511ff5053
+
+Count = 81
+Adata = 1583138aa307401dddc40804ac0f414d338fc3ffb2946f09aaaa7079426fc1ee
+Payload = 2c4ba9ce52e01645
+CT = bcfd881238d5f8f1781a9e359804831f31a1efb1ae1cb71d
+
+Count = 82
+Adata = 78d3dda40e433bba7a330ca3e5bd5170f0895f2e3e438402344ced79fcb0c719
+Payload = 5eb2d054a0e58c62
+CT = ce04f188cad062d62dcc77c4e1fe2bafd477598977835f0c
+
+Count = 83
+Adata = dfc762466fa84c27326e0ee4320aa71103d1e9c8a5cf7d9fab5f27d79df94bd6
+Payload = bbbf7830d04ab907
+CT = 2b0959ecba7f57b308946723baf0dbf613359b6e040f9bd5
+
+Count = 84
+Adata = 7e8ea82d1137c1e233522da12626e90a5f66a988e70664cb014c12790d2ab520
+Payload = 10c654c78a9e3c06
+CT = 8070751be0abd2b2003bd62ca51f74088bbbd33e54ac9dd4
+
+Count = 85
+Adata = 873da112557935b3929f713d80744ed08b4b276b86331dbc386fba361726d565
+Payload = 668d32e322e1da3e
+CT = f63b133f48d4348a67e65e7f2cdedf6ef8cc0ee7a6dcfb02
+
+Count = 86
+Adata = cfba97919f703d864efc11eac5f260a5d920d780c52899e5d76f8fe66936ff82
+Payload = e39f6225e8eab6cc
+CT = 732943f982df58780532f8c6639e5d6c7b755fcf516724e3
+
+Count = 87
+Adata = 01abcfee196f9d74fcaa7b69ae24a275485c25af93cc2306d56e41e1eb7f5702
+Payload = 6021a00f6d0610a4
+CT = f09781d30733fe107fd7a33828413ebc252dd9d015773524
+
+Count = 88
+Adata = ce1c31e7121c071d89afab5a9676c9e96cac3d89dcae83136bbb6f5ca8f81e5d
+Payload = bbaf0ac4e77ee78d
+CT = 2b192b188d4b0939d3d51368799325ad1c8233fa071bade0
+
+Count = 89
+Adata = bb210ca5bc07e3c5b06f1d0084a5a72125f177d3e56c151221115ae020177739
+Payload = 98a2336549a23a76
+CT = 081412b92397d4c25d1ea568637f773174a7f920a51b1fe1
+
+[Plen = 9]
+
+Key = b23255372455c69244a0210e6a9e13b155a5ec9d6d0900e54a8f4d9f7a255e3a
+Nonce = 274846196d78f0af2df5860231
+
+Count = 90
+Adata = 69adcae8a1e9a3f2fe9e62591f7b4c5b19d3b50e769521f67e7ea8d7b58d9fc8
+Payload = 615d724ae94a5daf8d
+CT = f019ae51063239287d896e7127f17d13f98013b420219eb877
+
+Count = 91
+Adata = 162d0033c9ea8d8334d485b29eef727302135a07a934eea5fee6041e9f1f47c1
+Payload = 0d9168eeab3b27ba69
+CT = 9cd5b4f54443433d997cc2cd61da9358b4045fef32f8192cbf
+
+Count = 92
+Adata = 3f4ab57efa32f51a4c00790280e77c0e55b85bbda4f854e242368e9a289b5a81
+Payload = 6287dcffdd5fb97885
+CT = f3c300e43227ddff75d280f0ffdd560fb8915978e3bd6205bb
+
+Count = 93
+Adata = 945d18134c148f164b39fd7c4aef0335045553f6ea690a3b1726418d86f0de00
+Payload = 6e5e01b3fd71d16b9c
+CT = ff1adda81209b5ec6c7dbf90420a1ff2e24bd6303b80cfc199
+
+Count = 94
+Adata = 23af12893431b07c2922ab623aed901c0eaaeb9a24efc55273e96aea4dab7038
+Payload = b51521e689b5247362
+CT = 2451fdfd66cd40f492d741f4329ae7cc77d42bf7e5f2ec5ab6
+
+Count = 95
+Adata = b15a118b3132c20c31e6c9d09acdee0e15fcc59d6f18306442682512d22eb10f
+Payload = 7f973617e710fb76fe
+CT = eed3ea0c08689ff10ec9ffdcc2f36edac14613b1d85baf25a9
+
+Count = 96
+Adata = dcfbeb6490f5fa7eaf917462473a6cec98bebf8f17493fe9b994119a6d5a5457
+Payload = 7e909b6727ac3fd02f
+CT = efd4477cc8d45b57df5a61a28bb10265b26043d7a8dd357713
+
+Count = 97
+Adata = 77e9317294f046f315a0d79e3423f29f7d9ebcd36d6eaa2a3fb2f4500309478c
+Payload = a5075638932b5632f8
+CT = 34438a237c5332b508d321c371ae1fd01bdf3b6c75a597da6e
+
+Count = 98
+Adata = 3aa8f204eb127b547e13873ed0238018394e13686c8734e49e3e629deb352c77
+Payload = c10f15a0de78db8aa3
+CT = 504bc9bb3100bf0d539393d1635bc40ac62405a39155406c47
+
+Count = 99
+Adata = 7f67e6f97c6c258f014d721a4edaaa0ddb3f9f09993276ab7b714ea9356c231d
+Payload = 8294f830cfca42cfbe
+CT = 13d0242b20b226484eff89641e1bd5ad6cc827441b17c45ecf
+
+[Plen = 10]
+
+Key = dbf06366f766e2811ecd5d4384d6d08336adc37e0824d620cf0d9e7fd1e7afa9
+Nonce = b3503ed4e277ed9769b20c10c0
+
+Count = 100
+Adata = 9ae5a04baa9d02c8854e609899c6240851cbc83f81f752bc04c71affa4eed385
+Payload = 2e3cf0af8c96c7b22719
+CT = e317df43ab46eb31be7e76f2730d771d56099a0c8d2703d7a24e
+
+Count = 101
+Adata = da77c6d5627a2aa34911bd1f7cc5f8aa68a2c6546adc96a186b9af8e5baac4cf
+Payload = e081c43a07450ce0dfa2
+CT = 2daaebd62095206346c5bcc7a8260ef361dc39fdb776d041f0d4
+
+Count = 102
+Adata = 134d2d9726400d09dd3521326f96fbef993ddc0c4088770057b0f8d70356456f
+Payload = c381d2ae5e72fc82324a
+CT = 0eaafd4279a2d001ab2d19f0cbb0899f221aac9762f2650f8058
+
+Count = 103
+Adata = 0d065dfde1de1f21784c7869eb566c977f807cfbd53578f4616995b51d7dc045
+Payload = 737f4d00c54ddca80eec
+CT = be5462ece29df02b978b3dc92a9bd26b9653e5917359c331fcff
+
+Count = 104
+Adata = 95c54d187f2415535451cbb9cb35869749b171f7043216ce6886dd77baeecf60
+Payload = 4e9e251ebbbbe5dbc8ff
+CT = 83b50af29c6bc958519891dda72c27d272561e00f7041845d998
+
+Count = 105
+Adata = 0f98039e6a9fe360373b48c7850ce113a0ff7b2ae5ce773dd4c67ca967cd691b
+Payload = 0db72b281ab4046d15a6
+CT = c09c04c43d6428ee8cc1928ac628758ad58fc1b5a768d4722848
+
+Count = 106
+Adata = ad840bc55654762e5eba0e4a9e7998992d990a06d70da1b1ca922ef193dab19a
+Payload = 4f7b4f38ff1ba4df5a59
+CT = 825060d4d8cb885cc33ed11dad4dc8b265a53cf0bdd85c5f15f4
+
+Count = 107
+Adata = 911e9876ea98e1bcf710d8fd05b5bf000ea317d926b41b6015998ee1462ab615
+Payload = 58ce55379ef24b72d6d6
+CT = 95e57adbb92267f14fb18eb659a5a7084be48d099467da4395df
+
+Count = 108
+Adata = 3f68a4fb4043bcf9b6d277c97e11365d949c705bd6679c6f0aaf52e62330ad79
+Payload = a219028a953ce1544835
+CT = 6f322d66b2eccdd7d1523b2b2583fd117cec47b1c84d3863159e
+
+Count = 109
+Adata = 02f32242cba6204319075ea8ce806a57845355ae73e6b875955df510096ebff9
+Payload = 83b0ee9a52252c456105
+CT = 4e9bc17675f500c6f8625456eb2b6a2d35c649a84051f843153c
+
+[Plen = 11]
+
+Key = 4dd555bd3a5253a90b68b5d4d46bd050340ee07ddad3a72048c657b5d76bb207
+Nonce = bdb1b82ba864893c2ee8f7426c
+
+Count = 110
+Adata = 9bcc5848e928ba0068f7a867e79e83a6f93593354a8bfcfc306aeeb9821c1da1
+Payload = 8015c0f07a7acd4b1cbdd2
+CT = 8e9f80c726980b3d42e43a6512a0481255b729a10f9edb5f07c60c
+
+Count = 111
+Adata = c2e75952ab49216f305e3776865791ce877cef8c0229ca97561787093fddf1d8
+Payload = c97b62a719720b44b7779c
+CT = c7f122904590cd32e92e748c514444f00ffdb80a4bb7e9eb651946
+
+Count = 112
+Adata = c76a3ff4e6d1f742dd845be2d74c1a9b08e418909b15077deb20373ef55caf91
+Payload = cb7c17ef62464ecc8008f6
+CT = c5f657d83ea488bade511edb609dfc1929ac1ba5753fc83bf945b7
+
+Count = 113
+Adata = bdb69f99f9a144b9ad88c6cfd8ffb8304c201de9b2818552ce6379e6042c1951
+Payload = 893a690cc5221de597d0e8
+CT = 87b0293b99c0db93c9890053b74283296d0fca83b262915289163c
+
+Count = 114
+Adata = 01815f599d6ba0d1c09f6f673bb6cca4c2a7a74f4e985be4c0f37842c7bbc5a4
+Payload = 80f3e4245c3eab16ef8bf0
+CT = 8e79a41300dc6d60b1d21888a34955893059d66549795b3ac2105c
+
+Count = 115
+Adata = a9db62e9ab53c4a805c43838ce36b587d29b75b43fb34c17a22d3981120f3bc5
+Payload = 641c6914920a79943dca39
+CT = 6a962923cee8bfe26393d1377c4e2f20aaa872a9a0b1d1d7f56df0
+
+Count = 116
+Adata = f0c2cc5a1b4c4cbe839338fa0d7a343514801302aef2403530605cf4f44d2811
+Payload = 2286a1eddd80737a724ca9
+CT = 2c0ce1da8162b50c2c15415545aa0c1dd11551891ae553d3a91908
+
+Count = 117
+Adata = 9842922499ad4d487488b3731f48765efe0b4eb59e7b491ba5f6636f09ed564d
+Payload = d8c63e7d7d332198249c0c
+CT = d64c7e4a21d1e7ee7ac5e4d9e07ec5806360843676ef27d811b246
+
+Count = 118
+Adata = 399b71ecb41f4590abda79045cdf6495f27daaa559c1b34f513b5c4ac105ec10
+Payload = 4b81804d777a59b6a107cf
+CT = 450bc07a2b989fc0ff5e27483b8727c5753ede25e1fab0d86963be
+
+Count = 119
+Adata = 2c186c5c3463a4a8bad771feb71e2973c4f6dede2529827707bf4fa40672660f
+Payload = dfc762466fa84c27326e0e
+CT = d14d2271334a8a516c37e64b5c3c1dc577ee8fcf6ef3ebc0783430
+
+[Plen = 12]
+
+Key = d3ad8cda9a0d91a205c4c05665728bb255d50a83403c9ab9243fcbbe95ae7906
+Nonce = 0b5f69697eb1af24e8e6fcb605
+
+Count = 120
+Adata = ea26ea68facdac3c75ba0cdf7b1ad703c9474af83b3fbfc58e548d776b2529b9
+Payload = a203aeb635e195bc33fd42fa
+CT = 62666297a809c982b50722bd56bc555899345e0404b2938edf33168e
+
+Count = 121
+Adata = 0b32069fc7e676f229f1037d3026c93eef199913e426efd786b524ce1dbde543
+Payload = aac414fbad945a49ae178103
+CT = 6aa1d8da307c067728ede1449b15447c904b671824c2ca24c4fc7ad4
+
+Count = 122
+Adata = 7a8658302e5181552292aa56e8209de63b5d86934167549b0d936202681757e1
+Payload = 7ee0ce371329192618e3cda0
+CT = be8502168ec145189e19ade7ea13850e99ef9300c65f5abc9419d13a
+
+Count = 123
+Adata = 4f05600950664d5190a2ebc29c9edb89c20079a4d3e6bc3b27d75e34e2fa3d02
+Payload = b0a1af969a95025385b251af
+CT = 70c463b7077d5e6d034831e8486c93c31bbedc9e5ffa2f4154bceea9
+
+Count = 124
+Adata = 4530e4dc6a4c3733b8ab7e77e384223cc1a8c179fb66818c08aca47e5c705d89
+Payload = 9f6c6d60110fd3782bdf49b0
+CT = 5f09a1418ce78f46ad2529f7f18b556e7da59fd2549dc57a17bf64f8
+
+Count = 125
+Adata = f179353aef342f0f691caf1fcb811e3f6504e14d6d9381c5439b098ff978b01b
+Payload = 90958d7f458d98c48cbb464c
+CT = 50f0415ed865c4fa0a41260b30aad3a838680cbd313004685a5510c5
+
+Count = 126
+Adata = f6df267e5cbc9d2a67b1c0fd762f891ee3b7c435884cb87d8228091b34aeddae
+Payload = 9f7ae892e5662803408d4d06
+CT = 5f1f24b3788e743dc6772d411d57b89ed0c91251aed37a6ca68a50c7
+
+Count = 127
+Adata = 4372e152b1afd99c7f87c8a51dbc3a5c14c49d04ea1c482a45dfbcda54972912
+Payload = 817074e351455f23cb67883d
+CT = 4115b8c2ccad031d4d9de87ad79a3b0feea16ff5fbca16211ea6fdd9
+
+Count = 128
+Adata = 82b6cd1c6618c42ba74e746075dc28700333578131ca6fde6971d2f0c6e31e6a
+Payload = 1b7da3835e074fdf62f1eb3c
+CT = db186fa2c3ef13e1e40b8b7b49f22737c4b2f9fa0a7e3dd4b067fbaa
+
+Count = 129
+Adata = a5422e53975e43168726677930f6d3e13281bdbd13c67c168340ed67e45d15b0
+Payload = 57473e7a105c806867379194
+CT = 9722f25b8db4dc56e1cdf1d3ef43a48dbea8c1547455ad0197af88a2
+
+[Plen = 13]
+
+Key = e300fc7a5b96806382c35af5b2c2e8e26382751b59010d4b1cfc90a4a9cb06df
+Nonce = 55b59eb434dd1ba3723ee0dc72
+
+Count = 130
+Adata = 9b1d85384cb6f47c0b13514a303d4e1d95af4c6442691f314a401135f07829ec
+Payload = 8714eb9ecf8bdb13e919de40f9
+CT = ba6063824d314aa3cbab14b8c54c6520dac0f073856d9b9010b7857736
+
+Count = 131
+Adata = fa17c693d0997140fbc521d39e042d8e08388106874207ca81c85f45c035d6e6
+Payload = a0837676e091213890dc6e0a34
+CT = 9df7fe6a622bb088b26ea4f20820a423dd30796b6016baff106aaef206
+
+Count = 132
+Adata = 27663597b389b78e96c785ca2f5510c8963a5561d2b0b24c4dcdf8e58562c12c
+Payload = b8a2ce7e051b8d094ec43f2a7f
+CT = 85d6466287a11cb96c76f5d2436032bc79c4aef1f74da25e92b0aa7f8a
+
+Count = 133
+Adata = d8f1a83371487d611ce704e0a6731f97a933c43569690022fce33cb5aecdc0a7
+Payload = 9e4103ab1dfb77ae3494507332
+CT = a3358bb79f41e61e16269a8b0e658123d2e5bb324c7ead8897f8e32b0a
+
+Count = 134
+Adata = 05c57aab99f94b315cf8bdd2d6b54440c097fe33c62a96b98b1568cdee4ce62c
+Payload = fb3e3d1b6394d2daebf121f8ac
+CT = c64ab507e12e436ac943eb0090270758ab09f93fa3ba7d7a2aa8eac789
+
+Count = 135
+Adata = 1c1b0933c508c6a8a20846ebd0d0377e24f4abc0c900d3a92bc409ba14ef1434
+Payload = 549ba26a299391538b56ce4bd7
+CT = 69ef2a76ab2900e3a9e404b3eb2293813f1bcb96564f772e9308e42b2d
+
+Count = 136
+Adata = 9f5cf9149f556124d6bb4e3e243cca1502c02682709392cc2ec7eb262fd4d479
+Payload = 287f31e69880823df7798c7970
+CT = 150bb9fa1a3a138dd5cb46814c81877380d5cf097c2fb5177750f8b53a
+
+Count = 137
+Adata = 1a49aaea6fc6fae01a57d2fc207ef9f623dfd0bc2cf736c4a70aaaa0af5dafd3
+Payload = 040d18b128ae4a1935f9509266
+CT = 397990adaa14dba9174b9a6a5acf42c75787edc62a180568c6ef56545d
+
+Count = 138
+Adata = f29a0b2c602ff2cacb587292db301182e6c76c5110b97ca8b706198f0e1dbc26
+Payload = 92441cbe8d70820870bb01ad63
+CT = af3094a20fca13b85209cb555f56d47a0631f2038103e3904b556ba7a5
+
+Count = 139
+Adata = 01fcf5fef50e36175b0510874ea50a4d2005ad5e40e5889b61417700d827251e
+Payload = f11d814df217de96333dee1cbf
+CT = cc69095170ad4f26118f24e4835be15b7ae24edccd0b0934e3af513ed3
+
+[Plen = 14]
+
+Key = 3ae5be5904bae62609ac525e2d1cad90133447573d7b608975a6a2b16cb2efc0
+Nonce = 61bf06b9fa5a450d094f3ddcb5
+
+Count = 140
+Adata = 0245484bcd987787fe97fda6c8ffb6e7058d7b8f7064f27514afaac4048767fd
+Payload = 959403e0771c21a416bd03f38983
+CT = 37a346bc4909965c5497838251826385a52c68914e9d1f63fd297ee6e7ed
+
+Count = 141
+Adata = 52f6a10a022e5ee57eda3fcf53dcf0d922e9a3785b39fad9498327744f2852e4
+Payload = 23fe445efa5bcb318cc85e2ad1ac
+CT = 81c90102c44e7cc9cee2de5b09ad364b603de6afbc2d96d00510894ccbe7
+
+Count = 142
+Adata = d236e3841b9556b32dbd02886724d053a9b8488c5ad1b466b06482a62b79ebb6
+Payload = 762fdc3e0c30c7ecf2ec8808bb79
+CT = d418996232257014b0c6087963781a4321c2ddbc35ce4864457d611219e9
+
+Count = 143
+Adata = 0d2739cfdac782b61f484fa1a423c478c414397ec420327963d79112b2d70a7e
+Payload = b6813d5fe8afa68d646c197337a2
+CT = 14b67803d6ba117526469902efa3296e55efebb17fe145cdca9b31ea7bcc
+
+Count = 144
+Adata = 7f291aa463c4babc76b4a6faf2e27e9401586b1ac83e4b06a4090e94b3ef5fd4
+Payload = 4ce8b6578537215224eb9398c011
+CT = eedff30bbb2296aa66c113e9181059270a0510e7cc1b599705853af2144d
+
+Count = 145
+Adata = 06bca7ef6f91355d19f90bf25590a44a24e5a782f92bc693c031e6de1e948008
+Payload = 9ebf93643854ea5c97a4f38f50bd
+CT = 3c88d63806415da4d58e73fe88bcb55847573bf21e946ce9bdc5f569e3ff
+
+Count = 146
+Adata = 5a44ff94f817c7c028a8f3db35a4d01364d2598432469f09ded86e5127d42d35
+Payload = da989cc7d375ed5fac4d7f938d74
+CT = 78afd99bed605aa7ee67ffe25575b8a61c5687ea02f0276824b8316b76f1
+
+Count = 147
+Adata = 2a755e362373ef27a911c4d93ca07bc97135645442ad7ad6a8ef98146c71e9d7
+Payload = 6fbab5a0f98e21e4d15904af5948
+CT = cd8df0fcc79b961c937384de8149a07ee02791011129fcacffcfb1bf4145
+
+Count = 148
+Adata = f7988873f45a5de314e5381d3f14d8f8c48c9b649bf3e745ed5dc882d507da58
+Payload = b610349e8b370a7c195598573637
+CT = 142771c2b522bd845b7f1826ee36d34204b1ce23f5f58a8eb7cf1fa8cfa7
+
+Count = 149
+Adata = 95d2c8502e28ab3ee2cac52e975c3e7bccb1a93acc33d9c32786f66d6268d198
+Payload = 1d969fd81dab5ced3e6ee70be3bf
+CT = bfa1da8423beeb157c44677a3bbe9c618bb88bbcefb008a5ea6bed4ff949
+
+[Plen = 15]
+
+Key = fab62b3e5deda7a9c1128663cc81c44b74ab1bfe70bc1c9dec7c7fd08173b80a
+Nonce = a5c1b146c82c34b2e6ebeceb58
+
+Count = 150
+Adata = 5e60b02b26e2d5f752eb55ea5f50bb354a6f01b800cea5c815ff0030b8c7d475
+Payload = 54be71705e453177b53c92bbf2ab13
+CT = 788db949697b8cd9abbc74ed9aa40cd6852dc829469368491149d6bb140071
+
+Count = 151
+Adata = 210c04632341fbfc185bfe3cbf6fe272bbe971104173bcb11419b35ab3aaf200
+Payload = 22197f9ad14591e7a6d5f8b18c969a
+CT = 0e2ab7a3e67b2c49b8551ee7e4998556940dc5a7e44bf10234806d00a012b5
+
+Count = 152
+Adata = d3a205dd017e79a67400a937a20ef049f4c40d73311731f03ab857a3f93bd458
+Payload = 096b2f530933c1273304a6ad423726
+CT = 2558e76a3e0d7c892d8440fb2a38390898f7dbde25b0b70d335df71a06987b
+
+Count = 153
+Adata = 0c9b3ba4faf5fc2f310ad1bab06c4ca13474b714feeffb6ad615c1b850bbd6a3
+Payload = d44fdfd9da3a63c1083afe574e91bf
+CT = f87c17e0ed04de6f16ba1801269ea02fd10d1f21b6b963c05aeda8eb09e272
+
+Count = 154
+Adata = d9bb71ad90152d5c1af358c8501fa89ebd4b17bf4ff43841528cccb79fd791b3
+Payload = 8d836acc13ed83c2b2c706415c9679
+CT = a1b0a2f524d33e6cac47e0173499664491d23d90ff55abca17e9d943b98c7f
+
+Count = 155
+Adata = 69dc21eb6f295b12ba493ee8fe6c40d78af946067ce772db316a3cbf00d3c521
+Payload = 2a68e3fe746f593c1b97cb637079c3
+CT = 065b2bc74351e49205172d351876dc9616886c6b2adc97db5a673846b6662c
+
+Count = 156
+Adata = 095eb52135dc6d9c1f56a2571c1389852482e7aa3edc245a3904a0449db24a70
+Payload = 39799b001ed2c334c269acb0f2328c
+CT = 154a533929ec7e9adce94ae69a3d932441dcae1760db90379bd354fa99164e
+
+Count = 157
+Adata = efd7270e0396392fde8b0ddaab00544cbbd504f4d97d4e90d749d1946de90dcb
+Payload = 42143a2b9e1d0b354df3264d08f7b6
+CT = 6e27f212a923b69b5373c01b60f8a9c7c7deb28bdcf84886ef843216b94449
+
+Count = 158
+Adata = 8bc181ce2e66294e803a8dc3834958b5f173bc2123c0726e31f3fca25b622ed6
+Payload = a3dcf26327059a4245b79a38bb8db6
+CT = 8fef3a5a103b27ec5b377c6ed382a935061ae3cd892ba63c44b809d6d29421
+
+Count = 159
+Adata = c39ec70c2c71633ae0dccc41477ac32e47638c885cf59f34ebd4a096d32f91f9
+Payload = 3d54883449ecca8f153436c25a0a01
+CT = 1167400d7ed277210bb4d09432051e3c9ae69a4c59ff8e251c2fe022d065a9
+
+[Plen = 16]
+
+Key = ee8ce187169779d13e443d6428e38b38b55dfb90f0228a8a4e62f8f535806e62
+Nonce = 121642c4218b391c98e6269c8a
+
+Count = 160
+Adata = 718d13e47522ac4cdf3f828063980b6d452fcdcd6e1a1904bf87f548a5fd5a05
+Payload = d15f98f2c6d670f55c78a06648332bc9
+CT = cc17bf8794c843457d899391898ed22a6f9d28fcb64234e1cd793c4144f1da50
+
+Count = 161
+Adata = a371ca29b92ed676bab5dfc4d78631bb6d9bb23a29f822907084a1f0fe17721f
+Payload = 60d55a8d5ab591a51e87fdf6aaa2ad25
+CT = 7d9d7df808aba2153f76ce016b1f54c68b55bbe42d8c97504b97c34a5f16e6a6
+
+Count = 162
+Adata = 01ec87920b42639d4ba22adb1fbe5138d2849db670a2960fd94a399c1532ed75
+Payload = cbf112e4fb85276c4e09649f3de225b2
+CT = d6b93591a99b14dc6ff85768fc5fdc51017d8706acd676ae99e93d5312a4113c
+
+Count = 163
+Adata = eebd2bbf1e9f6d817cd8062a6a9680e7f10464eefeb50b07cb46b14b9b3fcb2c
+Payload = 865b89aa38ee1b5a3ce56620307e8937
+CT = 9b13aedf6af028ea1d1455d7f1c370d45982f0fe5d951a8c62c87894657301e4
+
+Count = 164
+Adata = 72863362612f146699f6b2f6ec3688f2ca6cb1505af7a309c91c1933e34d516a
+Payload = a8efc37d1b8b51f2a47b21dd14da383d
+CT = b5a7e40849956242858a122ad567c1de5addfddbb59f4985947fb3a9ab56333e
+
+Count = 165
+Adata = 9c9efc6593f96207678db813608f2b8bc33ed1bef974ed77ed7b6e74b621b819
+Payload = d9b0eaaff786165f882f41a98dbc0c35
+CT = c4f8cddaa59825efa9de725e4c01f5d6b651053516673402a57538db1a9ce7e9
+
+Count = 166
+Adata = dc482a051b58d8a3904d3af37c37b51983f634a504451bbba6f77d71337f8e78
+Payload = df49d972b6ebbbb18ee975ac635d847e
+CT = c201fe07e4f58801af18465ba2e07d9d86d772b1a1991b7be6589bbccad36171
+
+Count = 167
+Adata = 51ef065a43caa23faf750b02a41ad6ba701aeb8058f6d8738d6f6b005bec7f60
+Payload = 78318aa5cd16699b77bdcea2fc9d1d20
+CT = 6579add09f085a2b564cfd553d20e4c3569387a1a6bcc826e94012670820576e
+
+Count = 168
+Adata = 88e2a74d2920c89c6a101f5f06d0624a6d5eabd9bdb51395ee3983934c55c73d
+Payload = 8e20d65d02dd9a64379f75b6d8328f2d
+CT = 9368f12850c3a9d4166e4641198f76cee9c788b4aae9b2c6caf0c44aa9bd2ed0
+
+Count = 169
+Adata = ada3ed7db2dabbfbc441ef68a5656e628d6d5bd6c1574369688497179a77601a
+Payload = 97e8d8513af41b97801de98cc4269096
+CT = 8aa0ff2468ea2827a1ecda7b059b6975f1df0f01944641a1b04d753e6ab8d3cc
+
+[Plen = 17]
+
+Key = 7da6ef35ad594a09cb74daf27e50a6b30d6b4160cf0de41ee32bbf2a208b911d
+Nonce = 98a32d7fe606583e2906420297
+
+Count = 170
+Adata = 217d130408a738e6a833931e69f8696960c817407301560bbe5fbd92361488b4
+Payload = b0053d1f490809794250d856062d0aaa92
+CT = a6341ee3d60eb34a8a8bc2806d50dd57a3f628ee49a8c2005c7d07d354bf80994d
+
+Count = 171
+Adata = 4ae414bc888a42141d3060c71c2dbbffd425b6a952806982271a8e756b3c9e24
+Payload = 51eb190c6a9f46e8ec1628b090795470c0
+CT = 47da3af0f599fcdb24cd3266fb04838df13c1c5755a5a240c33b2b890a486aac8b
+
+Count = 172
+Adata = 7b7f78ae1a5ee96fdc49dacd71be1a6ac09a6a162d44dea0172886eca5674e46
+Payload = 25144e807e389bb0e45b6dc25558caf61a
+CT = 33256d7ce13e21832c8077143e251d0b2b4cfca1c19abf447d7bc0898d61885144
+
+Count = 173
+Adata = 03f31c6143b77f6ad44749e2256306b8bf82242f2821fad4075b09b388ba81ca
+Payload = dbe1ee14abfe2ecf4edf6db206cf9886ce
+CT = cdd0cde834f894fc860477646db24f7bff229cc7a390867a245dcb7c434f1db347
+
+Count = 174
+Adata = 030390adb572f2bd2a6a4454fd68236cd1d465574328aa001d553375cc63f8a2
+Payload = db6df31f12bf552f81deff5fa2a373fc22
+CT = cd5cd0e38db9ef1c4905e589c9dea401135361b539f9fe0fb7842907c2326aef63
+
+Count = 175
+Adata = 7294ae94358669f2ada4b64c125b248df7fe86c6715e3b6a7b9bb2bd99392c8a
+Payload = ff2a97b49fcc6a50d4549c979d53ccc51f
+CT = e91bb44800cad0631c8f8641f62e1b382e8ed10943929e7d7bf798b2ae8371aae5
+
+Count = 176
+Adata = 4d1513478fc1fb0a18eb6d2a9324fefbd975ecd1b409025de826bc397462acc1
+Payload = 73ddfa0185200a890b7690a7e3986d8818
+CT = 65ecd9fd1a26b0bac3ad8a7188e5ba7529f92b9e49ab83f113f8949dc9e4a36e0d
+
+Count = 177
+Adata = b26a7ff61bfe94864249af7cc9b4a723627dd4463f5a22f0ca6063769522eab7
+Payload = 5c7604f9ac8fdf30ee5820e5aeb75b65d7
+CT = 4a4727053389650326833a33c5ca8c98e6d0e53223adff22a08e3dddf66fff23e3
+
+Count = 178
+Adata = 960f9a85cfbfb6eab223a4139c72ce926a680ea8e8ecc3088cf123de659ad310
+Payload = d44fdfd9da3a63c1083afe574e91bf01c9
+CT = c27efc25453cd9f2c0e1e48125ec68fcf833f49a42521a7a2367f91bfcc2180b7c
+
+Count = 179
+Adata = 3718467effb5d5dc009aaefce84d8cb4fe8f80eb608f4c678f5d0de02ea11e59
+Payload = bb515dc227abb9acad8fefaa14771bb77b
+CT = ad607e3eb8ad039f6554f57c7f0acc4a4ac08bd395c6807223311070659f550934
+
+[Plen = 18]
+
+Key = 0786706f680c27b792d054faa63f499a8e6b5ddb90502946235bf74c022d772c
+Nonce = f61ef1c8c10a863efeb4a1de86
+
+Count = 180
+Adata = 67874c808600a27fcab34d6f69cc5c730831ad4589075dd82479823cb9b41dc3
+Payload = 6a26677836d65bd0d35a027d278b2534e7df
+CT = d1c1f3c60603359c7d6a707f05ecb2296f8e52f2210b7a798ad5c778ee7cfd7fe6e0
+
+Count = 181
+Adata = e0c27cddf919d3092d9a34766c89a5ae6dcf39fe954d1e6f1a70ddf96805def4
+Payload = 4021ff104ff1dbd91e46db249fd82198b0a1
+CT = fbc66bae7f24b595b076a926bdbfb68538f00923bb5a347af13df12f234fca5f03ef
+
+Count = 182
+Adata = 7ae9eca03f616ab39ebb3be26b848842b4aa584e5c8e5695065ad5af34951175
+Payload = 6a681f164efce199a787bccff223b8ae1a98
+CT = d18f8ba87e298fd509b7cecdd0442fb392c9d03ed7bffac83e890caceb6903d9cab5
+
+Count = 183
+Adata = b47c9bc4eb01c74f5db2e6a293bef80db18c58cf06feef7ee0f8a7a9a51c22bb
+Payload = 7861dac338ba3f8274dca04c8c6f92b6d44c
+CT = c3864e7d086f51cedaecd24eae0805ab5c1d4dd8f30870025b2bd1e2a2511574d3e7
+
+Count = 184
+Adata = f6afd661f218c7426b92ee53e65d14898cd0c78a7e594fcc6ac0e3fb5cab1c9c
+Payload = a3f0473c620d2739d5ba4f7156f88d0fb669
+CT = 1817d38252d849757b8a3d73749f1a123e386046d17f337f3cb49884d94995edbdc9
+
+Count = 185
+Adata = d3802911e341577046cfc61d9043b4af059fb4bef3c6a2ff46ccdcb05670af37
+Payload = 07c535d9456a6ff1e41321150d16dae3f7a3
+CT = bc22a16775bf01bd4a2353172f714dfe7ff25fdc77b43bca254d6459263cdfed8fbb
+
+Count = 186
+Adata = db60720db67a60ca286fe744d46173c231fbcc7deb4c9b0d87d52a2247e06b74
+Payload = 5ee220720a896249efdab2ce418318bb5ebf
+CT = e505b4cc3a5c0c0541eac0cc63e48fa6d6eedd1a1d36c8164c55d55dbf0ff1e9517a
+
+Count = 187
+Adata = 57f70ba5493265b30491decc726354e2065e7971a2efd56db9cf0f79b1d76859
+Payload = 98e4eb0361c8bf40bcbe0539b0850e4c35ff
+CT = 23037fbd511dd10c128e773b92e29951bdaeb476e2ca48fd52bec0539b00744a8a07
+
+Count = 188
+Adata = 4a29b9ad548964942f87f28ba267ec0d0e8f72c73b3823ee57693dd63c2605c1
+Payload = 7f0745bea62479c0080ecec52e37c1e32d72
+CT = c4e0d10096f1178ca63ebcc70c5056fea523fad68c62b81d62f2d490ae74f5bb1465
+
+Count = 189
+Adata = acbd2e9911b3218a230d9db5086d91dccac3fc93fc64b0f4a15d56954906b2b7
+Payload = e99ed2ac6c38e033061b5d85f3e77dd72518
+CT = 527946125ced8e7fa82b2f87d180eacaad4913b15d8000266c61ba5aec898eb35b52
+
+[Plen = 19]
+
+Key = bac55f9847d93325bf5071c220c0a3dfeb38f214292d47b4acb7b0a597fe056f
+Nonce = 05b50c458adbba16c55fcc454d
+
+Count = 190
+Adata = 89ad6ae1e550975eaa916a62615e6b6a66366a17a7e06380a95ea5cdcc1d3302
+Payload = c1a994dc198f5676ea85801cd27cc8f47267ec
+CT = 7c9b138177590edaafec4728c4663e77458ffbe3243faec177de4a2e4a293952073e43
+
+Count = 191
+Adata = dfddb719d00398bf48a6cefd27736389e654a93b8595cd5ac446af1996e0f161
+Payload = 791e232bfb42fb18197adc1967da1a83f70168
+CT = c42ca4769594a3b45c131b2d71c0ec00c0e97f8422f736fc435687634d42254b22fd99
+
+Count = 192
+Adata = 58ef310997dcaf067dd217274921504da6dbf0428a2b48a65fe8a02c616ac306
+Payload = 3d4127942459bb8682e662dfc862467582fa68
+CT = 8073a0c94a8fe32ac78fa5ebde78b0f6b5127f38a96e68ef7dbaef1b460cc0980eacd4
+
+Count = 193
+Adata = 511e5d5e100b595f6b20e791830bca37e23f7b785e482a58405bffe7a632a5b8
+Payload = 0e71863c2962244c7d1a28fc755f0c73e5cbd6
+CT = b343016147b47ce03873efc86345faf0d223c15c5c702a82d468929227502e4e35796f
+
+Count = 194
+Adata = e48dfaa53b6807ea6f01d8dca67960b9f321f7851f324459a9bf61fe0be73abb
+Payload = e0f1cd013e6aea4fa484fc3fa35d348b1a2399
+CT = 5dc34a5c50bcb2e3e1ed3b0bb547c2082dcb8e89188c0940182dd99a902d158c5b0810
+
+Count = 195
+Adata = c12c0423fe36e4c88775dd00b4af267b85b7dd2a37a742a3156923c8917c97a3
+Payload = b1cc1946b4fc1dbd033254cdf536f61e9f9cd7
+CT = 0cfe9e1bda2a4511465b93f9e32c009da874c015849acbb7af1892790300bb84fb0558
+
+Count = 196
+Adata = 4255f8af18df7237e0abe98421aec9634443561752d893aaffe76380e829ef32
+Payload = 87284658928208e3bddca83e3ceb13708d88d4
+CT = 3a1ac105fc54504ff8b56f0a2af1e5f3ba60c3e75aaf3077ac6dfb5454851ec3910de6
+
+Count = 197
+Adata = ab83567833d2f3461b5fbecc0e366694bb5ea00933b2b3e792ec3aefe20325df
+Payload = bdb79f931ef3035a33bdd1b032fd9de8f6b2ba
+CT = 008518ce70255bf676d4168424e76b6bc15aade70f42e3e1f2b5bb58433bd11f5dea1f
+
+Count = 198
+Adata = bd1446ba3185d1c16551730947c22142142caa8cc1c540e89ab734ec297401bc
+Payload = 1f9c3a8eb8bc59f3869e10f73883aa8f8990cb
+CT = a2aebdd3d66a015fc3f7d7c32e995c0cbe78dc564f6248cefe5fc7cfb547c90a558925
+
+Count = 199
+Adata = b87577755d2d9489194f6f7cfabf267dc3433a9c91954e81beb72c5e06870922
+Payload = 5f28809181f9a889894da8d6fe1fde6cce354a
+CT = e21a07ccef2ff025cc246fe2e80528eff9dd5db52249d812f7f235afa0732e984e91b2
+
+[Plen = 20]
+
+Key = 8beedeb85d42c2a7fa6f7237b05acb197dd8e1672471ac878064fe5319eab876
+Nonce = 8479bdfad28ebe781e9c01a3f6
+
+Count = 200
+Adata = 7aebdfd955d6e8a19a701d387447a4bdd59a9382156ab0c0dcd37b89419d6eff
+Payload = 7b125c3b9612a8b554913d0384f4795c90cd387c
+CT = 6cc611d816b18c6847b348e46a4119465104254a04e2dfeeeac9c3255f6227704848d5b2
+
+Count = 201
+Adata = d119f300fbd74e754a200ea2c3f9fabc1466d02078c84245db693eef3f5672a6
+Payload = 8b013f5782d5d1af8dbd451a4202866095dac975
+CT = 9cd572b40276f5729e9f30fdacb7e67a5413d44338d48329997c5981d678b5e24a6f01b0
+
+Count = 202
+Adata = d6204303b86acf62d5ab860ca70161288ede56e3cf017c08dca56fd2d6f8f6fe
+Payload = b2b1d82a5523b72ea366a680922ed3a4624536c4
+CT = a56595c9d58093f3b044d3677c9bb3bea38c2bf2a77e3ab68e0a73519591a33ed098b758
+
+Count = 203
+Adata = 8557e22eb4529b43f16b1f8ae47c714ac8a2c827c1408a47704778b4c5b52601
+Payload = f8c4eb4285d3d7744da52775bb44ca436a3154f7
+CT = ef10a6a10570f3a95e87529255f1aa59abf849c1cff6c24251c2fb7b8604dfa10c60ef4a
+
+Count = 204
+Adata = 8c1a4187efbb3d38332f608f2c8bbe64247d9afa2281ced56c586ecb4ab7a85e
+Payload = 6e7fe35fa39c937a0e6b3a8c072e218650f42b8d
+CT = 79abaebc233fb7a71d494f6be99b419c913d36bb6c3c39f915d081d34559179869b32d81
+
+Count = 205
+Adata = a41bb1f256228302cd0548ae2148ff42774d18c2d6d3e38b36bc4938da13bac3
+Payload = 917b467d841850fc6e648f1bc298a7f9f1ee38ca
+CT = 86af0b9e04bb74217d46fafc2c2dc7e3302725fc9389a6a6a74c6eb0e1f87562469f2082
+
+Count = 206
+Adata = b0b024e20c4f75a6dad54c21a9edbce846792e957878b1c8ed2d916c757e2b3c
+Payload = 2b4314fe1a6bfa786b7cfc13fbee861b348efbf6
+CT = 3c97591d9ac8dea5785e89f4155be601f547e6c03bed3a2f5dfdbfcc0d7ac26c88d1962c
+
+Count = 207
+Adata = 42153925c46fc9d5d328312d62f59bb99fdc4ac479a3386d5f88fefd4b32f577
+Payload = e19fa7f83c79920cbff45c41a9dee8fc99e97396
+CT = f64bea1bbcdab6d1acd629a6476b88e658206ea035ea1d99be344fa1467ee91c73bbca67
+
+Count = 208
+Adata = 37ab2a0b7b69942278e21032fc83eba6cdc34f5285a8b711a08da6acd42299fe
+Payload = 53e0475cf492b3d39dad600f5c58eb0bd0021554
+CT = 44340abf7431970e8e8f15e8b2ed8b1111cb08627936ec10a81b36768b606e9a38b2f4c5
+
+Count = 209
+Adata = 4a17522da707b4b2587a0ae367a2cd2831bb593a18ef442a7977eda6de045878
+Payload = c119a383d9a3d4bff4270a1d22076b346db5f61c
+CT = d6cdee605900f062e7057ffaccb20b2eac7ceb2a11575ae03ea8a57bbe4a67c060367b74
+
+[Plen = 21]
+
+Key = c3a0c126cad581012151c25cf85a44472c23f83b6095b6004f4f32cd60ec2db2
+Nonce = 94ab51ce75db8b046d6ab92830
+
+Count = 210
+Adata = 2a243246bfe5b5ab05f51bf5f401af52d5bbaa2549cf57a18e197597fe15dd8c
+Payload = 73b09d18554471309141aa33b687f9248b50fe3154
+CT = b7e8264ca70fd2a4fb76f20a8ad5da3c37f5893fb12abeeaef1187f815ca481ed8ddd3dd37
+
+Count = 211
+Adata = 0595306eb7441622a49800edee0134492d82320707fceba902af2e0c95fe634a
+Payload = b64d00f3a4df754fa4ee6376922fb67ccce0c6209f
+CT = 7215bba75694d6dbced93b4fae7d95647045b12e7accc2b55011dbe92ce7619e0ad48b4ccf
+
+Count = 212
+Adata = bd439dbefec589e120fb4f9825b315bf86523b85c61791cd4da4c8d474ba2714
+Payload = 2b11d1ac74ffe701ec733d32085b1054132726e622
+CT = ef496af886b444958644650b3409334caf8251e8c71e8b1f4d70d8f4c7df4f22847d36b394
+
+Count = 213
+Adata = cfebe1cf82267394065bcecfada6709c6c35a3ac835644f560d4c9a8c1848364
+Payload = a88f22424643a523aa3d7d88f4364f1290f49dd0a2
+CT = 6cd79916b40806b7c00a25b1c8646c0a2c51eade47a85e76a9d07b7b361ca56d53c34cda50
+
+Count = 214
+Adata = 7a37255b682766a0bfecf78e5162528885a339174c2a49325739d2bd8877e64f
+Payload = c81427bc84c6a3cfefd4c4cb210fe82212977e1947
+CT = 0c4c9ce8768d005b85e39cf21d5dcb3aae320917a2fddb010e7508ad03ad287068ecee6020
+
+Count = 215
+Adata = 619f2ae80070e278615466a3fd6c9acb7b510c5679bed7038889c77e78d8bd32
+Payload = 28c4d6de3e2ce51b849b135d9cfd3084f0e3155447
+CT = ec9c6d8acc67468feeac4b64a0af139c4c46625aa2ddea785e6c470c52c4fdf432fd78b66e
+
+Count = 216
+Adata = b2571e56f66a857daffbdc99370ceddd4a7bed3867d600cc797000a3b7b57a9d
+Payload = 4c88151cafef75832bacef43a06e862349d56b67ee
+CT = 88d0ae485da4d617419bb77a9c3ca53bf5701c690b91232cfbd7ffff252498b35274fb2995
+
+Count = 217
+Adata = db409636e3e3bcd606a91aeb7592009896f9ad2c4cc6b7f578e6ad59c0f8fa22
+Payload = 572855e22ce89bc2bcf09cb15a1765d99973449d61
+CT = 9370eeb6dea33856d6c7c488664546c125d633938472b2c50e5e391ad104f9ee33b94f2872
+
+Count = 218
+Adata = 62c89a835721207a182968c516dc8be45774ec846e8dcab9ab8611888f2a76a8
+Payload = 89ce46b3de3afaf2518d419b1a2ac24cabca269a96
+CT = 4d96fde72c7159663bba19a22678e154176f5194732d69c5d6db1b130102af3dae0690673b
+
+Count = 219
+Adata = 33f30ddd83002eea50fd4a8fae39d0980a04160a22ac88b755ac050f1d1f8639
+Payload = edf1682a626e9fbf3d57bb260e0876c6f92ba5b114
+CT = 29a9d37e90253c2b5760e31f325a55de458ed2bff1489903365970c2673c9fd457e1077aad
+
+[Plen = 22]
+
+Key = 9cdebaeee8690b68751070691f49593668a6de12d3a948b38ddbd3f75218b2d4
+Nonce = af1a97d43151f5ea9c48ad36a3
+
+Count = 220
+Adata = f5353fb6bfc8f09d556158132d6cbb97d9045eacdc71f782bcef62d258b1950a
+Payload = 3cbb08f133270e4454bcaaa0f20f6d63c38b6572e766
+CT = 3966930a2ae8fdd8f40e7007f3fde0bd6eb48a46e6d26eef83da9f6384b1a2bda10790dadb3f
+
+Count = 221
+Adata = e3a1555ffe5f34bb43c4a2dae9019b19f1e44a45fb577d495d2a57097612448d
+Payload = 946e86795c332031e2d1ee09d3d4a101fb6800d00911
+CT = 91b31d8245fcd3ad426334aed2262cdf5657efe408a5587bdd120a7d08cd3841cb117af444fb
+
+Count = 222
+Adata = 9c5d43c1a1269cde199509a1eff67cc83a1759b71c9e7a6ee99f76b98c6e23a6
+Payload = b76ce2ab0065ba1c0a754494991c8c452cb416f18ab1
+CT = b2b1795019aa4980aac79e3398ee019b818bf9c58b0545b32f81dcf03e2bcc2aaf62ad366e97
+
+Count = 223
+Adata = b07452a7900a289b91b2771dfdd5108852536659aa259def7b41e38f80bd03ab
+Payload = a3e0d8d0784155bfc45769c52711d4fa68e8bc390c20
+CT = a63d432b618ea62364e5b36226e35924c5d7530d0d94fea17d78533bc9e022dbfb460afdf499
+
+Count = 224
+Adata = 6b30f55c3101540523a92380390f3f84632f42962061b2724cde78ac39809397
+Payload = 6e6a88abbb52a709b47365ad6aa8016fa9a03a9bd834
+CT = 6bb71350a29d549514c1bf0a6b5a8cb1049fd5afd98056defc6dcaeec80b1c639350ab6f1fde
+
+Count = 225
+Adata = 9fc62d14f8b7a6026509275cff80312ff1ade2b5d9c274cb72a506a571439fc1
+Payload = eba1810d537041821121aeff8e0914ac26a550072c8c
+CT = ee7c1af64abfb21eb19374588ffb99728b9abf332d389d37b7251fb8c0ef2b37c36d51219d0f
+
+Count = 226
+Adata = 6b9389cc42113d639fd2b40cbc732ae0dc7c14513b88b36b45a6ea5a06fe4d2b
+Payload = dfc6692cd2442e5ff1f918c8812a27f81d107d16a12f
+CT = da1bf2d7cb8bddc3514bc26f80d8aa26b02f9222a09bd279d9da4437c8a2a252436508134c56
+
+Count = 227
+Adata = db72d98d63fc10acff7dceec0e2691a80ecee50a0e957ad166c77952a50318bd
+Payload = 9ad338cbfd1b52e6ae4178f05e00062274f8b0b25eae
+CT = 9f0ea330e4d4a17a0ef3a2575ff28bfcd9c75f865f1a63943543bc1c5f5991ecc5964a288f79
+
+Count = 228
+Adata = e98b710c47a4d12a73cd8aa2613fc2910c16f4195ea7f15650132493521d19be
+Payload = 9f5a05db89e0e336da066ce81b79ad9be1d0ec4fb7b8
+CT = 9a879e20902f10aa7ab4b64f1a8b20454cef037bb60c0a49ee2b7ceddcbd28abb24b77d5edee
+
+Count = 229
+Adata = 527817316fc48b105f8ab178dd2db1fefa09c50461aa9d8bdf3c03482343bbf9
+Payload = 58f31e5770070a5d4031fb795dc2d298561d3559960d
+CT = 5d2e85ac69c8f9c1e08321de5c305f46fb22da6d97b9b099a68cfa3572d974e03232e09f37fb
+
+[Plen = 23]
+
+Key = d34264a12c35cdd67ac105e2826b071e46f8131d1e325f8e0ae80a6447375135
+Nonce = 3891e308b9f44c5b5a8b59004a
+
+Count = 230
+Adata = 0cda000ed754456a844c9ed61843deea9dadf5e723ea1448057712996d660f8c
+Payload = 79ac1a6a9eca5e07ce635bfd666ef72b16f3f2e140d56c
+CT = 1abcc9b1649deaa0bfa7dcd23508282d9c50ca7fee72486950608d7bcb39dcf03a2cab01587f61
+
+Count = 231
+Adata = 3fb6ddb76809b8e6d703347664ef00a365955124c603900d5c8d4ff476138252
+Payload = 76d12e3c4c5d990bf563c60aa4999e52998d887f97477f
+CT = 15c1fde7b60a2dac84a74125f7ff4154132eb0e139e05b1c4fb40e5c8bc37152a173d4bbb18c3e
+
+Count = 232
+Adata = d9fc295082e8f48569eb073ac1b9566246728fc62ccaab4a5667c472c98b2626
+Payload = a027c28fbe22111fd4c8a226cfe8531c16d7790d561eca
+CT = c33711544475a5b8a50c25099c8e8c1a9c744193f8b9ee019c359008adae3070b5a543ead0effb
+
+Count = 233
+Adata = 7a459aadb48f1a528edae71fcf698b84ed64dc0e18cc23f27ab47eeabeaf833f
+Payload = fa597e37c26c38694abdcf450f9edc529160fa0d651979
+CT = 9949adec383b8cce3b79486a5cf803541bc3c293cbbe5dbd099ab134756b90746762a92a4a9f7f
+
+Count = 234
+Adata = 484207909dec4c35929ebe82fcacf20d2af6d850bd69364ebac9557adeadfbd4
+Payload = 9e4c8aa9b58a8eabc5586892f5541000b43f17d9a051a0
+CT = fd5c59724fdd3a0cb49cefbda632cf063e9c2f470ef684fa4f6adfec85d055310107ba89198afa
+
+Count = 235
+Adata = 88b5448372548e6aab1b262630a28a471d285514703f1bdb10c695850e18fe6d
+Payload = 7d9582cf9e3bb9ee34dce965f56b08e716589486b0641c
+CT = 1e855114646c0d4945186e4aa60dd7e19cfbac181ec338915d23eb2e952afcc89fbddb567d9d75
+
+Count = 236
+Adata = 0e71863c2962244c7d1a28fc755f0c73e5cbd630a8dbdeb38842d7795d830d2e
+Payload = 5a387e7cc22491fc556fe6a0c060b4911d01f0c11f801e
+CT = 3928ada73873255b24ab618f93066b9797a2c85fb1273aaad6c31828314e24198f005955ca8f5e
+
+Count = 237
+Adata = 2aa7a28da38c42fda2e578d9d6340cd8e80b9b32047c3db296d0640d517b0872
+Payload = 87946e910059cbaf48df63b220f397049c65ca10cd1920
+CT = e484bd4afa0e7f08391be49d7395480216c6f28e63be04e531ebbadccfe47182b41904bbfebcfe
+
+Count = 238
+Adata = 3382051c268891da04e6ca73adcead4029f6a1593be4acfe3968e7351a6a2fb5
+Payload = c62f67d208f1c8ffd5d57df9de15ef54f97fbc07d1630a
+CT = a53fb409f2a67c58a411fad68d73305273dc84997fc42e7c582414154236c09ee704cf4a5de411
+
+Count = 239
+Adata = c352828b1920e53bbb60f2ea6a5f15639659e6f3243405c26f6e48628d5519a9
+Payload = 697e73eaaf562d31bdbf7ce9e78c7426fe1c87e421def9
+CT = 0a6ea03155019996cc7bfbc6b4eaab2074bfbf7a8f79dd57c9990029c89d1b37988745fa5737a3
+
+[Plen = 24]
+
+Key = 4ad98dbef0fb2a188b6c49a859c920967214b998435a00b93d931b5acecaf976
+Nonce = 00d772b07788536b688ff2b84a
+
+Count = 240
+Adata = 5f8b1400920891e8057639618183c9c847821c1aae79f2a90d75f114db21e975
+Payload = 9cea3b061e5c402d48497ea4948d75b8af7746d4e570c848
+CT = f28ec535c2d834963c85814ec4173c0b8983dff8dc4a2d4e0f73bfb28ad42aa8f75f549a93594dd4
+
+Count = 241
+Adata = 1ae8108f216defea65d9426da8f8746a3ae408e563d62203063d49bf7e0d6bdf
+Payload = 2b223932fb2fd8433e4b1af9e8234a824569a141f6c96a69
+CT = 4546c70127abacf84a87e513b8b90331639d386dcff38f6f4de907a59c5e4d3f21e1348d7cdf92b6
+
+Count = 242
+Adata = 460f08114b1015fe8b7a9b5dd1b9e6a3d28367c4bd15f29b13c02a8cb9a53968
+Payload = 4d57cbe4a7e780d4ed17267d5ebc91750c2f0209e0444bd2
+CT = 233335d77b63f46f99dbd9970e26d8c62adb9b25d97eaed4ff4239544e2f354d6c6837cd9c23b884
+
+Count = 243
+Adata = 860f4428259d9c5b17698cc95363db6cfee603258582e3a3e8feb886599d4ac4
+Payload = fda8665f87c618646a89c7abdca275fd10c31453ad4b9c99
+CT = 93cc986c5b426cdf1e4538418c383c4e36378d7f9471799f3f6c6f7cc494201069344e2d6d41bd9b
+
+Count = 244
+Adata = 1b43c482f83780c21583f88e5afcf6938edd20f21b74d895161b60c27a6a42f0
+Payload = 98104fd3f3413ad1f57ef4912cb50097dca379a58c47b0d2
+CT = f674b1e02fc54e6a81b20b7b7c2f4924fa57e089b57d55d43787a15352cfceb028202c8730beaa7a
+
+Count = 245
+Adata = b082ccd964617c27a5607b7324faad237ee53acfc18c35502dbf7c1937a9dfcb
+Payload = b46b343e64d2d70e0bd909dbb3f6bedf7e4adc74321be526
+CT = da0fca0db856a3b57f15f631e36cf76c58be45580b210020f3a0ca3da647eb31893e867956097983
+
+Count = 246
+Adata = b8539ba93ef17254ec1d8d62e8f4eae4d41ee1e75345bf90c9cbb26c63bce501
+Payload = 8e12620bb575e6b167b085255b2b5631ff28e04cbef8826d
+CT = e0769c3869f1920a137c7acf0bb11f82d9dc796087c2676be663fbbebbc251b9f1760afa49e89e71
+
+Count = 247
+Adata = b6b09463b5ef5ead1f17f4021693a0d8452e98dcbb8e7590f9fde6394970a6f8
+Payload = 792aaa23b923d1b53173fe19853b9aa402a301d48529873e
+CT = 174e541065a7a50e45bf01f3d5a1d317245798f8bc136238da90cd87e9d9ca5d85430a150e682752
+
+Count = 248
+Adata = 390f6de14d5e1f2f78dbe757c00b89209d0cf8bc48cbbea035779f93de357905
+Payload = ddc5b4e48970ebd72869be6998e9103c014475e8ae6ea29c
+CT = b3a14ad755f49f6c5ca54183c873598f27b0ecc49754479afc0cc4601afb61efa7059cfe49ec9dde
+
+Count = 249
+Adata = 1d75c9e7acb09932db332498d30f82e4009025cb1827047c59a8f97812b568a4
+Payload = d2b66096c475a77648c27235e6972ba8f18761330d3c6adf
+CT = bcd29ea518f1d3cd3c0e8ddfb60d621bd773f81f34068fd9cf7474962c3602dcfcb50039f43e3d6f
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT128.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT128.rsp
new file mode 100644
index 0000000000..0e56a03d42
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT128.rsp
@@ -0,0 +1,1589 @@
+# CAVS 11.0
+# "CCM-DVPT" information
+# AES Keylen: 128
+# Generated on Tue Mar 15 08:09:25 2011
+
+
+[Alen = 0, Plen = 0, Nlen = 7, Tlen = 4]
+
+Key = 4ae701103c63deca5b5a3939d7d05992
+
+Count = 0
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = 02209f55
+Result = Pass
+Payload = 00
+
+Count = 1
+Nonce = 3796cf51b87266
+Adata = 00
+CT = 9a04c241
+Result = Fail
+
+Count = 2
+Nonce = 89ca5a64050f9f
+Adata = 00
+CT = f5f915df
+Result = Fail
+
+Count = 3
+Nonce = ec9d8edff25645
+Adata = 00
+CT = 7a3c3499
+Result = Fail
+
+Count = 4
+Nonce = 05e16f0f42a6f4
+Adata = 00
+CT = f09c2986
+Result = Pass
+Payload = 00
+
+Count = 5
+Nonce = 2e504b694f8df5
+Adata = 00
+CT = 4ae97e71
+Result = Fail
+
+Count = 6
+Nonce = 06d102a9328863
+Adata = 00
+CT = ecb38c8b
+Result = Fail
+
+Count = 7
+Nonce = c288b810fb5334
+Adata = 00
+CT = 9c4dc530
+Result = Fail
+
+Count = 8
+Nonce = 08a166d9eb6610
+Adata = 00
+CT = 67299ef6
+Result = Fail
+
+Count = 9
+Nonce = 4a5810b121c91b
+Adata = 00
+CT = b0538d02
+Result = Fail
+
+Count = 10
+Nonce = 44077341139bf9
+Adata = 00
+CT = 88200ea8
+Result = Fail
+
+Count = 11
+Nonce = a9df4f37847e1f
+Adata = 00
+CT = 19867aa5
+Result = Pass
+Payload = 00
+
+Count = 12
+Nonce = 11df57fcd131e9
+Adata = 00
+CT = 3b392a52
+Result = Pass
+Payload = 00
+
+Count = 13
+Nonce = 890fff56d10dc0
+Adata = 00
+CT = 1c5e47e0
+Result = Pass
+Payload = 00
+
+Count = 14
+Nonce = 9dc18698731b27
+Adata = 00
+CT = 97a56b8b
+Result = Fail
+
+[Alen = 0, Plen = 0, Nlen = 7, Tlen = 16]
+
+Key = 4bb3c4a4f893ad8c9bdc833c325d62b3
+
+Count = 15
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = 75d582db43ce9b13ab4b6f7f14341330
+Result = Pass
+Payload = 00
+
+Count = 16
+Nonce = 3796cf51b87266
+Adata = 00
+CT = 3a65e03af37b81d05acc7ec1bc39deb0
+Result = Fail
+
+Count = 17
+Nonce = 89ca5a64050f9f
+Adata = 00
+CT = efc5721e0b9e4c3c90deab0e1d5c11bd
+Result = Fail
+
+Count = 18
+Nonce = ec9d8edff25645
+Adata = 00
+CT = 91b4b779823f4f0e3979ced93b99736c
+Result = Fail
+
+Count = 19
+Nonce = 05e16f0f42a6f4
+Adata = 00
+CT = e2e87ca82523ccfeb416b42af9d9aadc
+Result = Pass
+Payload = 00
+
+Count = 20
+Nonce = 2e504b694f8df5
+Adata = 00
+CT = 7b85fd105cc960df86ad86846d178274
+Result = Fail
+
+Count = 21
+Nonce = 06d102a9328863
+Adata = 00
+CT = ffa140be27b25f307a6efd9697d66c9b
+Result = Fail
+
+Count = 22
+Nonce = c288b810fb5334
+Adata = 00
+CT = ed356542e0a804a724bfaa422e98a970
+Result = Fail
+
+Count = 23
+Nonce = 08a166d9eb6610
+Adata = 00
+CT = e31dd8dc920fe7900e1b1817fe845c7d
+Result = Fail
+
+Count = 24
+Nonce = 4a5810b121c91b
+Adata = 00
+CT = ae5a0777f03bbf541f305d00acff0396
+Result = Fail
+
+Count = 25
+Nonce = 44077341139bf9
+Adata = 00
+CT = 957dca58616c1cbe99f94fd8f7c257d9
+Result = Fail
+
+Count = 26
+Nonce = a9df4f37847e1f
+Adata = 00
+CT = 0e150af422f6da238bb476810b2d5bc2
+Result = Pass
+Payload = 00
+
+Count = 27
+Nonce = 11df57fcd131e9
+Adata = 00
+CT = 8e1150756ff3a733a1274470f072b74c
+Result = Pass
+Payload = 00
+
+Count = 28
+Nonce = 890fff56d10dc0
+Adata = 00
+CT = a1f70df3fa9cfeb95f869b3fe08466e0
+Result = Pass
+Payload = 00
+
+Count = 29
+Nonce = 9dc18698731b27
+Adata = 00
+CT = fdf3f6c177aa1d71fe3474a5a2eb6bb1
+Result = Fail
+
+[Alen = 0, Plen = 0, Nlen = 13, Tlen = 4]
+
+Key = 4bb3c4a4f893ad8c9bdc833c325d62b3
+
+Count = 30
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = 90156f3f
+Result = Pass
+Payload = 00
+
+Count = 31
+Nonce = a16a2e741f1cd9717285b6d882
+Adata = 00
+CT = 88909016
+Result = Fail
+
+Count = 32
+Nonce = 368f3b8180fd4b851b7b272cb1
+Adata = 00
+CT = de547d03
+Result = Fail
+
+Count = 33
+Nonce = 7bb2bc00c0cafce65b5299ae64
+Adata = 00
+CT = ea4bad52
+Result = Fail
+
+Count = 34
+Nonce = 935c1ef3d4032ff090f91141f3
+Adata = 00
+CT = 1bc82b3d
+Result = Pass
+Payload = 00
+
+Count = 35
+Nonce = 2640b14f10b116411d1b5c1ad1
+Adata = 00
+CT = 92e72250
+Result = Fail
+
+Count = 36
+Nonce = b229c173a13b2d83af91ec45b0
+Adata = 00
+CT = e81f0647
+Result = Fail
+
+Count = 37
+Nonce = 37ca0dc2d6efd9efde69f14f03
+Adata = 00
+CT = 7cb906ec
+Result = Fail
+
+Count = 38
+Nonce = 6b6238aed86d677ba2b3e2622c
+Adata = 00
+CT = d60f815b
+Result = Fail
+
+Count = 39
+Nonce = d6cb2ac67bb13b8f6d31fad64a
+Adata = 00
+CT = d3d4f3b0
+Result = Fail
+
+Count = 40
+Nonce = 32a7cd361ef00e65f5778fdfd4
+Adata = 00
+CT = a9df97ad
+Result = Fail
+
+Count = 41
+Nonce = d0a1508fdefcf5be30a459b813
+Adata = 00
+CT = 36a37a59
+Result = Pass
+Payload = 00
+
+Count = 42
+Nonce = 5381a61b449dc6a42aa4c79b95
+Adata = 00
+CT = dba02a36
+Result = Pass
+Payload = 00
+
+Count = 43
+Nonce = c55430f2da0687ea40313884ab
+Adata = 00
+CT = 25dcb3c5
+Result = Pass
+Payload = 00
+
+Count = 44
+Nonce = ec76d1850acc0979a1f11906fb
+Adata = 00
+CT = 1d2832d0
+Result = Fail
+
+[Alen = 0, Plen = 0, Nlen = 13, Tlen = 16]
+
+Key = 19ebfde2d5468ba0a3031bde629b11fd
+
+Count = 45
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = fb04dc5a44c6bb000f2440f5154364b4
+Result = Pass
+Payload = 00
+
+Count = 46
+Nonce = a16a2e741f1cd9717285b6d882
+Adata = 00
+CT = 5447075bf42a59b91f08064738b015ab
+Result = Fail
+
+Count = 47
+Nonce = 368f3b8180fd4b851b7b272cb1
+Adata = 00
+CT = fdc992847f0815fac67aa935b35208ed
+Result = Fail
+
+Count = 48
+Nonce = 7bb2bc00c0cafce65b5299ae64
+Adata = 00
+CT = 2cabd690a45e59854b7587b26dd77f8e
+Result = Fail
+
+Count = 49
+Nonce = 935c1ef3d4032ff090f91141f3
+Adata = 00
+CT = 3dacc71169f6da77ec91ff1d2f649ed1
+Result = Pass
+Payload = 00
+
+Count = 50
+Nonce = 2640b14f10b116411d1b5c1ad1
+Adata = 00
+CT = 97a2eb170ef03fa12124f1315e3b694f
+Result = Fail
+
+Count = 51
+Nonce = b229c173a13b2d83af91ec45b0
+Adata = 00
+CT = 94d85a83169d8dc76f58baf4d63ecfee
+Result = Fail
+
+Count = 52
+Nonce = 37ca0dc2d6efd9efde69f14f03
+Adata = 00
+CT = d3903c6289ca3684b8ce1174c23153a4
+Result = Fail
+
+Count = 53
+Nonce = 6b6238aed86d677ba2b3e2622c
+Adata = 00
+CT = 5cbac5c418374a68bd7085454c4b0c13
+Result = Fail
+
+Count = 54
+Nonce = d6cb2ac67bb13b8f6d31fad64a
+Adata = 00
+CT = 26317f6b8b0130097441ed04b8009aef
+Result = Fail
+
+Count = 55
+Nonce = 32a7cd361ef00e65f5778fdfd4
+Adata = 00
+CT = b82ab6f3bbf59b6caafc54f05570f74e
+Result = Fail
+
+Count = 56
+Nonce = d0a1508fdefcf5be30a459b813
+Adata = 00
+CT = 1ae34207e74c8c78890ae17e320e84bd
+Result = Pass
+Payload = 00
+
+Count = 57
+Nonce = 5381a61b449dc6a42aa4c79b95
+Adata = 00
+CT = 5c5fa254c0be503b02caffade6b85259
+Result = Pass
+Payload = 00
+
+Count = 58
+Nonce = c55430f2da0687ea40313884ab
+Adata = 00
+CT = 9340266730ea36207bb734819d3553e9
+Result = Pass
+Payload = 00
+
+Count = 59
+Nonce = ec76d1850acc0979a1f11906fb
+Adata = 00
+CT = ec17cccf33bd9a0d4ce7aa20690c1333
+Result = Fail
+
+[Alen = 0, Plen = 24, Nlen = 7, Tlen = 4]
+
+Key = 19ebfde2d5468ba0a3031bde629b11fd
+
+Count = 60
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = a90e8ea44085ced791b2fdb7fd44b5cf0bd7d27718029bb703e1fa6b
+Result = Pass
+Payload = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22
+
+Count = 61
+Nonce = 31f8fa25827d48
+Adata = 00
+CT = 50aafe0578c115c4a8e126ff7b3ccb64dce8ccaa8ceda69f23e5d81c
+Result = Fail
+
+Count = 62
+Nonce = 5340ed7752c9ff
+Adata = 00
+CT = 512ed208bf10d57406537e94d20a5b6e2e9ab0683dfdc685869a97f0
+Result = Fail
+
+Count = 63
+Nonce = 9cbce402511b89
+Adata = 00
+CT = af72db9cd9d6f46607d6f9542ca69988dd15255c5c91171c838e7f95
+Result = Fail
+
+Count = 64
+Nonce = 123a0beace4e39
+Adata = 00
+CT = 47d71409a03c330be9451b3f92c9d21c584391ad1010e9d609b89801
+Result = Pass
+Payload = 9d033e3b66efed1467868f382417c80594877a28bc97f406
+
+Count = 65
+Nonce = 8ea1594a58fe4a
+Adata = 00
+CT = e562c7af0384ea16431ca20934a293a058d722cbfc3186c8eaf5f825
+Result = Fail
+
+Count = 66
+Nonce = 5a7743e59e82da
+Adata = 00
+CT = 004d9d89c401aa79919c2805fcd5de69316e191df56426c05ec1aa6a
+Result = Fail
+
+Count = 67
+Nonce = f477f754d7ee76
+Adata = 00
+CT = d623673d7f6d57c208bde112ca858561f3af5cc2bf5de926f3586c6f
+Result = Fail
+
+Count = 68
+Nonce = 040a257dede70e
+Adata = 00
+CT = fd4733d158b5630f4f6c03ab26b11bff0cbe0d5d3df99a735fa40618
+Result = Fail
+
+Count = 69
+Nonce = dd51b8e91683d1
+Adata = 00
+CT = d352cb996c3075ff367a8dcacbbae46a12fbef08aa96ec835bf4f930
+Result = Fail
+
+Count = 70
+Nonce = ab3cb86cca6fb2
+Adata = 00
+CT = 31730fac20e21eca0aef591faa9fa90b3c058e32af1ce48a66f0496e
+Result = Fail
+
+Count = 71
+Nonce = f67b98efd39b55
+Adata = 00
+CT = dd175905a7ea3aef9fce068e6cb78e9cc60519755a178c77b753181c
+Result = Pass
+Payload = f2e944e1ae47ad5873bf391f1b0cc07f6151eb4c50bb45b2
+
+Count = 72
+Nonce = e60e2c002d1c99
+Adata = 00
+CT = 8ad6b76f54392ee0f2834f09142545bcde9bf03d04d64aa10876f2da
+Result = Pass
+Payload = 70f48dc1d76e5028da07e29852801375a9edb2214a5ea4c0
+
+Count = 73
+Nonce = 098e053fa08043
+Adata = 00
+CT = 808eb3e04c39abde64674f0f7716dde11699cff8dd367c4cd4f7fc07
+Result = Pass
+Payload = bd81680e3dc0b35431c92598dcaa26ef09ca0da5e77193de
+
+Count = 74
+Nonce = 4bf48328725514
+Adata = 00
+CT = e074d13aad43f7b2364d47db0a02326641ca3b2ad61a1c49973a2712
+Result = Fail
+
+[Alen = 0, Plen = 24, Nlen = 7, Tlen = 16]
+
+Key = 197afb02ffbd8f699dacae87094d5243
+
+Count = 75
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = 24ab9eeb0e5508cae80074f1070ee188a637171860881f1f2d9a3fbc210595b7b8b1b41523111a8e
+Result = Pass
+Payload = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22
+
+Count = 76
+Nonce = 31f8fa25827d48
+Adata = 00
+CT = 7ebfda6fa5da1dbffd82dc29b875798fbcef8ba0084fbd2463af747cc88a001fa94e060290f209c4
+Result = Fail
+
+Count = 77
+Nonce = 5340ed7752c9ff
+Adata = 00
+CT = cbf133643851f91ddc7a1e19a0c21990459f2b7728da58f5cf3b8e6c8aeb5eeb0a5efb3700be45a2
+Result = Fail
+
+Count = 78
+Nonce = 9cbce402511b89
+Adata = 00
+CT = 0de7567a945c0af4a2291a651de411e8d0438508f2d4da80f7bd61a0158accbca28913e39fe80906
+Result = Fail
+
+Count = 79
+Nonce = 123a0beace4e39
+Adata = 00
+CT = d43035cdb5a1868aa430e8b41a1dc57a639087238e38bd628feeda2e8f249dd93a8358def7639875
+Result = Pass
+Payload = 9d033e3b66efed1467868f382417c80594877a28bc97f406
+
+Count = 80
+Nonce = 8ea1594a58fe4a
+Adata = 00
+CT = 389547260b354a6cbc909de057d367677049e80613877f6fbf19f89da977e56f308373c616299ad4
+Result = Fail
+
+Count = 81
+Nonce = 5a7743e59e82da
+Adata = 00
+CT = a95aa33483ed3711470025394616bf98fe624fbca8aa6fbc21366b9da457ede2a673351475b53d41
+Result = Fail
+
+Count = 82
+Nonce = f477f754d7ee76
+Adata = 00
+CT = 3d53b6ab8925f429ae14a0065cd203d4f9deddd402a79ac6d889a7cae55efd71b369cd6d43ef363b
+Result = Fail
+
+Count = 83
+Nonce = 040a257dede70e
+Adata = 00
+CT = d5e6e82cb5f8034a89e58adf8298476253f18981bcb3b0364be7f19463dd330a4b9f3cbb30b88fa5
+Result = Fail
+
+Count = 84
+Nonce = dd51b8e91683d1
+Adata = 00
+CT = 02f69107d62ff77145c7d57684c70ba671d55f1c63bb2ad8c2df063f7fdbae27f0736a37fd065fb4
+Result = Fail
+
+Count = 85
+Nonce = ab3cb86cca6fb2
+Adata = 00
+CT = 64ec2f321111da9c5389e8255bfe69876d4f548f94cacd529b45d54cc24cff1b1d8aa1df32fbd81a
+Result = Fail
+
+Count = 86
+Nonce = f67b98efd39b55
+Adata = 00
+CT = 37d63c2bbf44d2eb155ecc1a844841d5c33f1a6d443419330217a4f1f4fb302257b0de7c9da2e750
+Result = Pass
+Payload = f2e944e1ae47ad5873bf391f1b0cc07f6151eb4c50bb45b2
+
+Count = 87
+Nonce = e60e2c002d1c99
+Adata = 00
+CT = 33e0dce4410e51bed5323ea49490207084ac91732bae429236a305d520a1a24930a70a311aa3695d
+Result = Pass
+Payload = 70f48dc1d76e5028da07e29852801375a9edb2214a5ea4c0
+
+Count = 88
+Nonce = 098e053fa08043
+Adata = 00
+CT = 1d732c334319bd775e7cf93dbdc4204bbdb58192be08280481e3d64ed546b6b70ee088a693f55fbb
+Result = Pass
+Payload = bd81680e3dc0b35431c92598dcaa26ef09ca0da5e77193de
+
+Count = 89
+Nonce = 4bf48328725514
+Adata = 00
+CT = c92fc2f0d24593f67d9c09d326158a8138237c4096093f0d737719dd84ccfb397a4f61b70c85262a
+Result = Fail
+
+[Alen = 0, Plen = 24, Nlen = 13, Tlen = 4]
+
+Key = 197afb02ffbd8f699dacae87094d5243
+
+Count = 90
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = 4a550134f94455979ec4bf89ad2bd80d25a77ae94e456134a3e138b9
+Result = Pass
+Payload = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697
+
+Count = 91
+Nonce = 49004912fdd7269279b1f06a89
+Adata = 00
+CT = 118ec53dd1bfbe52d5b9fe5dfebecf2ee674ec983eada654091a5ae9
+Result = Fail
+
+Count = 92
+Nonce = efeb82c8c68d6600b24dd6d8ee
+Adata = 00
+CT = 6b0fea26e4dfe902b5e876c7ba92afbad8aa52d3c1d00ae578b6bcc4
+Result = Fail
+
+Count = 93
+Nonce = 7b93d368dc551640b00ba3cbb5
+Adata = 00
+CT = 640c740e2b8af851712a05948ecee055b25b145ccb82ca58ac542b09
+Result = Fail
+
+Count = 94
+Nonce = 24b7a65391f88bea38fcd54a9a
+Adata = 00
+CT = 05f20b2ae70fcb0ea79aa1845c15b899a799ca60f51e6c296413020a
+Result = Pass
+Payload = 43419715cef9a48dc7280bc035082a6581afd1d82bee9d1a
+
+Count = 95
+Nonce = 6aa3f731522fce7e366ba59945
+Adata = 00
+CT = 9fa576a8a5c72468afa372338cbbc33fef81ad5a873eb38a142d5636
+Result = Fail
+
+Count = 96
+Nonce = a11cf5bed0041ee3cb1fef4b43
+Adata = 00
+CT = 8d26582c74b2b4d960ee9e417c6395daafaebb3aff45d477f3757b6a
+Result = Fail
+
+Count = 97
+Nonce = 273cc5013785baeb5abc79c8bd
+Adata = 00
+CT = cb62a13e38e17cc6635e409c922956ece38f593189a51b99a7001a16
+Result = Fail
+
+Count = 98
+Nonce = d2d4482ea8e98c1cf309671895
+Adata = 00
+CT = f3e29b792423c7fbe743a3b2f890a2bff29519f3636a6232050e9225
+Result = Fail
+
+Count = 99
+Nonce = a8849b44adb48d271979656930
+Adata = 00
+CT = 136e60d6714d906d1f4c02b7bdbb5f3ccdd2165306912dec850ec9f0
+Result = Fail
+
+Count = 100
+Nonce = a632ba0d00511122abcd6227ff
+Adata = 00
+CT = 49b6d0b6eeff74af0de70072d9ccdc68a0ee36a5ddbf098b4eb95533
+Result = Fail
+
+Count = 101
+Nonce = c47af80cd26d047630c1fdf0d1
+Adata = 00
+CT = a2a59041c3f78f6e10c3045118e8a475945e24c85b02abc40f8fb949
+Result = Pass
+Payload = d8306c9c4ea6c69c6e2ad0fc0e49b1e0126b01078d6419ff
+
+Count = 102
+Nonce = 70e132023acae1f88c7a237b68
+Adata = 00
+CT = 19b4ad222795326cb031cfdb07b652dbf64ca5db5ff5d6d569d8ab41
+Result = Pass
+Payload = d0b2bef5ed1a87d9c73d4a459cb05c11799c4f51ad640b1e
+
+Count = 103
+Nonce = 8010d3a2a14f72f5585defc940
+Adata = 00
+CT = 76b66b908657f4df8a329c34ccdde50ae7fc71c4a718b712f00fe764
+Result = Pass
+Payload = 4faba05569bf7ac656780c16995e9122e565fe9984be8a68
+
+Count = 104
+Nonce = a98c2f0e0a7b68942853905191
+Adata = 00
+CT = 20df4662ce6c8c4ce49b14fa791e41ff8598ec93d8a825e879f9eb72
+Result = Fail
+
+[Alen = 0, Plen = 24, Nlen = 13, Tlen = 16]
+
+Key = 90929a4b0ac65b350ad1591611fe4829
+
+Count = 105
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = 4bfe4e35784f0a65b545477e5e2f4bae0e1e6fa717eaf2cb6a9a970b9beb2ac1bd4fd62168f8378a
+Result = Pass
+Payload = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697
+
+Count = 106
+Nonce = 49004912fdd7269279b1f06a89
+Adata = 00
+CT = 0c56a503aa2c12e87450d45a7b714db980fd348f327c0065a65666144994bad0c8195bcb4ade1337
+Result = Fail
+
+Count = 107
+Nonce = efeb82c8c68d6600b24dd6d8ee
+Adata = 00
+CT = 5f69d6c21f771eb98dc724f891f530b1c045f49a054de103a85f868739404b64a7cbdd61b577c388
+Result = Fail
+
+Count = 108
+Nonce = 7b93d368dc551640b00ba3cbb5
+Adata = 00
+CT = d335ba572520c336f711edf27ea738ba5e6b0d772ea443b8b2b164f3c255b699cbf75330d96c3c13
+Result = Fail
+
+Count = 109
+Nonce = 24b7a65391f88bea38fcd54a9a
+Adata = 00
+CT = 9fa846ef8d198c538f84f856bab8f7f9c3bed90b53acb6a32658e077687315eaf11458bdf6e3c36a
+Result = Pass
+Payload = 43419715cef9a48dc7280bc035082a6581afd1d82bee9d1a
+
+Count = 110
+Nonce = 6aa3f731522fce7e366ba59945
+Adata = 00
+CT = b7095030acdc5fbb8fea2c24717c1c236231f9737bcc78f463db3756abba1feef626a956794d7e56
+Result = Fail
+
+Count = 111
+Nonce = a11cf5bed0041ee3cb1fef4b43
+Adata = 00
+CT = d6911d5831163c8ebad0916af1833051b885aae822f9f6657d6fee1de626bc7c93f2caa27a3ecaa0
+Result = Fail
+
+Count = 112
+Nonce = 273cc5013785baeb5abc79c8bd
+Adata = 00
+CT = 6b10a098c96c2bbf9aeb5c9adcf91e4812838dff319f8be989e2d235192f33ba0f357492112d98f4
+Result = Fail
+
+Count = 113
+Nonce = d2d4482ea8e98c1cf309671895
+Adata = 00
+CT = aecd11cbac04e1f79b0fd24052c8cedf393dce9df350d24f800b81e834ea5dd2bdc2c688d9505359
+Result = Fail
+
+Count = 114
+Nonce = a8849b44adb48d271979656930
+Adata = 00
+CT = d3a7a25f71b1988482dc852ed713d55abdcc4bb1129ddcae430889cd5c97343cc0dedfbd62e6b6eb
+Result = Fail
+
+Count = 115
+Nonce = a632ba0d00511122abcd6227ff
+Adata = 00
+CT = 368e1574a433d78d0276ce4a1cacfba834a216693536c00b15acded53c41010554e1c1fe937a7605
+Result = Fail
+
+Count = 116
+Nonce = c47af80cd26d047630c1fdf0d1
+Adata = 00
+CT = 99e40b3c67aca95dd4462c20cbd6b2741e7033fc4f41a975c9390fbdb9ec416267096ccbf2c148e5
+Result = Pass
+Payload = d8306c9c4ea6c69c6e2ad0fc0e49b1e0126b01078d6419ff
+
+Count = 117
+Nonce = 70e132023acae1f88c7a237b68
+Adata = 00
+CT = de079418c25ba67e5fda009998e3fce61bfdc3b7787cf06655c18ae38b7ee7f00f96cfca4fe9a2ef
+Result = Pass
+Payload = d0b2bef5ed1a87d9c73d4a459cb05c11799c4f51ad640b1e
+
+Count = 118
+Nonce = 8010d3a2a14f72f5585defc940
+Adata = 00
+CT = fbab64d8dd8b6e33c7cc6124cd65f004d7247277fe98d5d3b35357a35ff9e58e18d6d80df9fc335d
+Result = Pass
+Payload = 4faba05569bf7ac656780c16995e9122e565fe9984be8a68
+
+Count = 119
+Nonce = a98c2f0e0a7b68942853905191
+Adata = 00
+CT = 372b9af0655df2d0c830b4949a2d2faa8db251ee922a3bff9aba89639f4033be9ba9f3c101acc1bd
+Result = Fail
+
+[Alen = 32, Plen = 0, Nlen = 7, Tlen = 4]
+
+Key = 90929a4b0ac65b350ad1591611fe4829
+
+Count = 120
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = 782e4318
+Result = Pass
+Payload = 00
+
+Count = 121
+Nonce = a265480ca88d5f
+Adata = a2248a882ecbf850daf91933a389e78e81623d233dfd47bf8321361a38f138fe
+CT = a04f270a
+Result = Fail
+
+Count = 122
+Nonce = 87ec7423f1ebfc
+Adata = 2bed1ec06c1ca149d9ffbaf048c474ea2de000eb7950f18d6c25acf6ab3f19b5
+CT = 97dfd257
+Result = Fail
+
+Count = 123
+Nonce = b8b04f90616082
+Adata = 4898731e143fcc677c7cf1a8f2b3c4039fb5e57028e33b05e097d1763cbfe4d8
+CT = 6c202a1c
+Result = Fail
+
+Count = 124
+Nonce = 8c687b4318813a
+Adata = fcad52a88544325bb31eb5de4a41dbff6a96f69d0993b969a01792ee23953acf
+CT = 1be535a0
+Result = Pass
+Payload = 00
+
+Count = 125
+Nonce = 29b810eed8fc92
+Adata = 40d1d320eb63a25d7a2b3141563a552114275ddda56beb62cc0c0273d5795faa
+CT = 4fb6617d
+Result = Fail
+
+Count = 126
+Nonce = 62452462c53934
+Adata = 1eb8863ea100babc1713654afcf54f21f8bff754223ad70269ace9d034f26a96
+CT = c056bd3e
+Result = Fail
+
+Count = 127
+Nonce = 4cceba0e7aee97
+Adata = f33e184c967165eb62542999afaca4e3e319840e439b5bb509544fb4b6901445
+CT = 87048576
+Result = Fail
+
+Count = 128
+Nonce = b5151b0601c683
+Adata = 73d27303ec91f28c79b278882034d11eb6a5266746f37edbb77f8409a8738b8c
+CT = ea8c0407
+Result = Fail
+
+Count = 129
+Nonce = 4e5d6d7ac9e71e
+Adata = a01b6e152fe232b6c10b5d89900961c445f4c46833df242c826678b68c869811
+CT = 41c12dc5
+Result = Fail
+
+Count = 130
+Nonce = dc88e989951a3f
+Adata = fdcacfaff46585406cc45a2da364e67e132a91c98900a8f9d7bfb14ec951fca5
+CT = de84cf5c
+Result = Fail
+
+Count = 131
+Nonce = a1aeda4b4cb8dd
+Adata = db3022ef4cd68ae22b501599448ffe2dda15cfd2e259315c6f6d03036edea963
+CT = e617e006
+Result = Pass
+Payload = 00
+
+Count = 132
+Nonce = f248e5225e3d9a
+Adata = fdc64ef76a3bfd0a15d0bc8e8bacaf64346796a3e35afcf2ac1ab136f63f7b6e
+CT = b7909395
+Result = Pass
+Payload = 00
+
+Count = 133
+Nonce = e68228f5c65b73
+Adata = 614efdf89ce2a9fcbd38bdc0b4cece54dfd7532880e0b4ce6eb3a4010b7cb1e7
+CT = 8a05d2ea
+Result = Pass
+Payload = 00
+
+Count = 134
+Nonce = ea167cfd1101d9
+Adata = 28130f938c45a1a92b02dbeadbd8df816b6d934e87cca2dfdbfdc49c7cd84041
+CT = 8643ba47
+Result = Fail
+
+[Alen = 32, Plen = 0, Nlen = 7, Tlen = 16]
+
+Key = 6a798d7c5e1a72b43e20ad5c7b08567b
+
+Count = 135
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = 41b476013f45e4a781f253a6f3b1e530
+Result = Pass
+Payload = 00
+
+Count = 136
+Nonce = a265480ca88d5f
+Adata = a2248a882ecbf850daf91933a389e78e81623d233dfd47bf8321361a38f138fe
+CT = f9f018fcd125822616083fffebc4c8e6
+Result = Fail
+
+Count = 137
+Nonce = 87ec7423f1ebfc
+Adata = 2bed1ec06c1ca149d9ffbaf048c474ea2de000eb7950f18d6c25acf6ab3f19b5
+CT = 534cc67c44c877c9c908071ee1082f4c
+Result = Fail
+
+Count = 138
+Nonce = b8b04f90616082
+Adata = 4898731e143fcc677c7cf1a8f2b3c4039fb5e57028e33b05e097d1763cbfe4d8
+CT = 201c0ef2ddaa51b645911b5c37d76e95
+Result = Fail
+
+Count = 139
+Nonce = 8c687b4318813a
+Adata = fcad52a88544325bb31eb5de4a41dbff6a96f69d0993b969a01792ee23953acf
+CT = ec774d9000763bba3a5ac307418827b2
+Result = Pass
+Payload = 00
+
+Count = 140
+Nonce = 29b810eed8fc92
+Adata = 40d1d320eb63a25d7a2b3141563a552114275ddda56beb62cc0c0273d5795faa
+CT = 75798c3fe5202f0e33c9183c837aeaf5
+Result = Fail
+
+Count = 141
+Nonce = 62452462c53934
+Adata = 1eb8863ea100babc1713654afcf54f21f8bff754223ad70269ace9d034f26a96
+CT = 32601de5960c11c925444b5c47d42289
+Result = Fail
+
+Count = 142
+Nonce = 4cceba0e7aee97
+Adata = f33e184c967165eb62542999afaca4e3e319840e439b5bb509544fb4b6901445
+CT = 4c1cd6a774c8e6f4e261db1f73b0aa20
+Result = Fail
+
+Count = 143
+Nonce = b5151b0601c683
+Adata = 73d27303ec91f28c79b278882034d11eb6a5266746f37edbb77f8409a8738b8c
+CT = 8bd9c00ff23310216bbd24981c1e2cf7
+Result = Fail
+
+Count = 144
+Nonce = 4e5d6d7ac9e71e
+Adata = a01b6e152fe232b6c10b5d89900961c445f4c46833df242c826678b68c869811
+CT = 174efd089409f9932b8e631965e762a6
+Result = Fail
+
+Count = 145
+Nonce = dc88e989951a3f
+Adata = fdcacfaff46585406cc45a2da364e67e132a91c98900a8f9d7bfb14ec951fca5
+CT = 8de80f620bd41eee6a58925dc8404bfa
+Result = Fail
+
+Count = 146
+Nonce = a1aeda4b4cb8dd
+Adata = db3022ef4cd68ae22b501599448ffe2dda15cfd2e259315c6f6d03036edea963
+CT = 0b9d79e8e33ec45532af5515a99f05df
+Result = Pass
+Payload = 00
+
+Count = 147
+Nonce = f248e5225e3d9a
+Adata = fdc64ef76a3bfd0a15d0bc8e8bacaf64346796a3e35afcf2ac1ab136f63f7b6e
+CT = 1583e1e5a86001bbcec62292ccfd4d48
+Result = Pass
+Payload = 00
+
+Count = 148
+Nonce = e68228f5c65b73
+Adata = 614efdf89ce2a9fcbd38bdc0b4cece54dfd7532880e0b4ce6eb3a4010b7cb1e7
+CT = b72caac6362e68e445f69f605f21e0a2
+Result = Pass
+Payload = 00
+
+Count = 149
+Nonce = ea167cfd1101d9
+Adata = 28130f938c45a1a92b02dbeadbd8df816b6d934e87cca2dfdbfdc49c7cd84041
+CT = 352769a19ac75b8a116be031b33d6449
+Result = Fail
+
+[Alen = 32, Plen = 0, Nlen = 13, Tlen = 4]
+
+Key = 6a798d7c5e1a72b43e20ad5c7b08567b
+
+Count = 150
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = 9f69f24f
+Result = Pass
+Payload = 00
+
+Count = 151
+Nonce = 8739b4bea1a099fe547499cbc6
+Adata = f6107696edb332b2ea059d8860fee26be42e5e12e1a4f79a8d0eafce1b2278a7
+CT = e17afaa4
+Result = Fail
+
+Count = 152
+Nonce = 0f98fdbde2b04387f27b3401dd
+Adata = 02010329660fa716556193eb4870ee84bd934296a5c52d92bba859cc13caaddc
+CT = 07155b7e
+Result = Fail
+
+Count = 153
+Nonce = 4eed58f381e500902ba5c56864
+Adata = 96056d9ebd7c553c22cc2d9d816b61123750d96c1b08c4b661079424bf3c4946
+CT = d538cf2f
+Result = Fail
+
+Count = 154
+Nonce = 1e7e51f0fa9a33ed618c26f5e3
+Adata = da9b8ffb0f3c2aee2e386cc9f035ec1eb3e629bd1544c11dc21be4fd8ac9074a
+CT = c283466f
+Result = Pass
+Payload = 00
+
+Count = 155
+Nonce = f012f94f5988c79aa179d7fdfc
+Adata = 612b2ef2683109d99452f95099417641d0c2be3f8ab4cbb2a44e83355ba9303c
+CT = aa8d8098
+Result = Fail
+
+Count = 156
+Nonce = 715acf92cfb69ad56036c49e70
+Adata = 960667b85be07304634124b9324be12a1c11451f1fa9db82c683265b4cf8e5ff
+CT = a44b69b0
+Result = Fail
+
+Count = 157
+Nonce = 141be3601e38185a9fa1596d2e
+Adata = 606452c62290b43559a588bb03356f846cecb0ccaf0bdaf67a18abd811d4315a
+CT = f395733f
+Result = Fail
+
+Count = 158
+Nonce = fcdda3c5f0e80843b03d8788da
+Adata = 03f22247a55461a293d253c77483859fdac1b87c2480e208a3df767cfbfde512
+CT = 1e9e9237
+Result = Fail
+
+Count = 159
+Nonce = ca660ed3b917c0aca140dcd3fb
+Adata = 254a86f5b20d344ad86fd5523d08f1864737be57731440c29aa6b42574572f51
+CT = e9d2a722
+Result = Fail
+
+Count = 160
+Nonce = 642ae3466661ce1f51783deece
+Adata = 4432a1cec5976cc13b8fb78341d426c2248f091b597123d263ffafc7f82da5a5
+CT = a90fc438
+Result = Fail
+
+Count = 161
+Nonce = 7864c717ec93db38b10679be47
+Adata = 679aad1ad1e57029e3362b325572fc71cac53184b0f1546867e665a4a59466c4
+CT = 48f3a1ec
+Result = Pass
+Payload = 00
+
+Count = 162
+Nonce = c3bf9dfe9d6c26f543188fb457
+Adata = e301f69ad3a7e08a3d02462f0aa584449eb0449b0e3c50aa8dfaa4472816c8b0
+CT = 24763def
+Result = Pass
+Payload = 00
+
+Count = 163
+Nonce = 1527657d2fd98f7deca55cc649
+Adata = f4c723433b7cafe3cda9bb4940a21a89a8382d13018b622ccd1ffb9ffd3211af
+CT = 63394bee
+Result = Pass
+Payload = 00
+
+Count = 164
+Nonce = b8432d3d5525a0dadbbaa6b6b8
+Adata = 86ee6e37b4a2d9a0b52ec95643b4e8297e237721e15ce8bf7593a98644f83eba
+CT = d79b1686
+Result = Fail
+
+[Alen = 32, Plen = 0, Nlen = 13, Tlen = 16]
+
+Key = f9fdca4ac64fe7f014de0f43039c7571
+
+Count = 165
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = 1859ac36a40a6b28b34266253627797a
+Result = Pass
+Payload = 00
+
+Count = 166
+Nonce = 8739b4bea1a099fe547499cbc6
+Adata = f6107696edb332b2ea059d8860fee26be42e5e12e1a4f79a8d0eafce1b2278a7
+CT = edf8b46eb69ac0044116019dec183072
+Result = Fail
+
+Count = 167
+Nonce = 0f98fdbde2b04387f27b3401dd
+Adata = 02010329660fa716556193eb4870ee84bd934296a5c52d92bba859cc13caaddc
+CT = 66622ac26c7227a0329739612012737c
+Result = Fail
+
+Count = 168
+Nonce = 4eed58f381e500902ba5c56864
+Adata = 96056d9ebd7c553c22cc2d9d816b61123750d96c1b08c4b661079424bf3c4946
+CT = e4c9e86493ee78b1cbf6e55e94731b63
+Result = Fail
+
+Count = 169
+Nonce = 1e7e51f0fa9a33ed618c26f5e3
+Adata = da9b8ffb0f3c2aee2e386cc9f035ec1eb3e629bd1544c11dc21be4fd8ac9074a
+CT = 8b5bfe6b5b5552007300bae71172612f
+Result = Pass
+Payload = 00
+
+Count = 170
+Nonce = f012f94f5988c79aa179d7fdfc
+Adata = 612b2ef2683109d99452f95099417641d0c2be3f8ab4cbb2a44e83355ba9303c
+CT = 1848be3cb7665ac68874c617a75d8bd2
+Result = Fail
+
+Count = 171
+Nonce = 715acf92cfb69ad56036c49e70
+Adata = 960667b85be07304634124b9324be12a1c11451f1fa9db82c683265b4cf8e5ff
+CT = 65a23b7b5ee78af9c7d0113447f78ab9
+Result = Fail
+
+Count = 172
+Nonce = 141be3601e38185a9fa1596d2e
+Adata = 606452c62290b43559a588bb03356f846cecb0ccaf0bdaf67a18abd811d4315a
+CT = 90a420b6d2252392e161dcf4fb953d7e
+Result = Fail
+
+Count = 173
+Nonce = fcdda3c5f0e80843b03d8788da
+Adata = 03f22247a55461a293d253c77483859fdac1b87c2480e208a3df767cfbfde512
+CT = 004cbe11292887e246de7704a4a1a05f
+Result = Fail
+
+Count = 174
+Nonce = ca660ed3b917c0aca140dcd3fb
+Adata = 254a86f5b20d344ad86fd5523d08f1864737be57731440c29aa6b42574572f51
+CT = ad7af41e39ea0c0cd072263e826f3cf0
+Result = Fail
+
+Count = 175
+Nonce = 642ae3466661ce1f51783deece
+Adata = 4432a1cec5976cc13b8fb78341d426c2248f091b597123d263ffafc7f82da5a5
+CT = 16b1a4fadbadc906a949592d6ef319a3
+Result = Fail
+
+Count = 176
+Nonce = 7864c717ec93db38b10679be47
+Adata = 679aad1ad1e57029e3362b325572fc71cac53184b0f1546867e665a4a59466c4
+CT = e9cfb1069380434f221db4229a083a76
+Result = Pass
+Payload = 00
+
+Count = 177
+Nonce = c3bf9dfe9d6c26f543188fb457
+Adata = e301f69ad3a7e08a3d02462f0aa584449eb0449b0e3c50aa8dfaa4472816c8b0
+CT = 380cb57fd531bb1dcf22350518bbf8af
+Result = Pass
+Payload = 00
+
+Count = 178
+Nonce = 1527657d2fd98f7deca55cc649
+Adata = f4c723433b7cafe3cda9bb4940a21a89a8382d13018b622ccd1ffb9ffd3211af
+CT = fbf2becc35b5024078bfcfc1f831b669
+Result = Pass
+Payload = 00
+
+Count = 179
+Nonce = b8432d3d5525a0dadbbaa6b6b8
+Adata = 86ee6e37b4a2d9a0b52ec95643b4e8297e237721e15ce8bf7593a98644f83eba
+CT = 080203eb842b3f98a730abbbf98f493e
+Result = Fail
+
+[Alen = 32, Plen = 24, Nlen = 7, Tlen = 4]
+
+Key = f9fdca4ac64fe7f014de0f43039c7571
+
+Count = 180
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = 6be31860ca271ef448de8f8d8b39346daf4b81d7e92d65b338f125fa
+Result = Pass
+Payload = a265480ca88d5f536db0dc6abc40faf0d05be7a966977768
+
+Count = 181
+Nonce = fdd2d6f503c915
+Adata = 5b92394f21ddc3ad49d9b0881b829a5935cb3a4d23e292a62fb66b5e7ab7020e
+CT = 4cc57a9927a6bc401441870d3193bf89ebd163f5c01501c728a66b69
+Result = Fail
+
+Count = 182
+Nonce = 27d73d58100054
+Adata = f6468542923be79b4b06dfe70920d57d1da73a9c16f9c9a12d810d7de0d12467
+CT = 1f16c6d370fff40c011a243356076b67e905d4672ae2f38fee2de18c
+Result = Fail
+
+Count = 183
+Nonce = dd16e0ce1250e3
+Adata = bc65cfd65e9863c8b7457d58afa6bdb48a84170d8aa97ba5b397b52ad17a9242
+CT = 46edb001d58a01dce1bcf064cfc9a04accc82c42b33ba16524537a81
+Result = Fail
+
+Count = 184
+Nonce = ccee19d037cf4a
+Adata = c026696e6425e6c33f45b4145febf1137e7ac26383c9f5aa4cd4e5e8abb19e07
+CT = 9b61335f96fc5b31274cc1fb275f29c1105d68c67b70654f9405edb1
+Result = Pass
+Payload = 0df202431ee7f251a38aaf6aa8cd313782bd293af9114005
+
+Count = 185
+Nonce = 6c8ba94f09cbe6
+Adata = 774ad1a88f8bb063951486d4aec5bf82d5fc535bd0b952f86200c123c37fa496
+CT = 97b5eb2d55847f5d5d9f8c762dace481d8efb19ccfd72265548effe3
+Result = Fail
+
+Count = 186
+Nonce = 1f670302fcdcc8
+Adata = 1a9ff9698cfc96b581d7115c822e4363d7355ec5daed2eae5bf89ee944ac7d9c
+CT = f5cc8198dce8e890587b62572b07413a915bfb55628c901c03459b29
+Result = Fail
+
+Count = 187
+Nonce = 5d05f658c729a2
+Adata = dd9564c1431ed490b17ef69f6115805e54ef156ef4e10e58f7d57a7e86626352
+CT = 50c0b1f6c5e4c86a0c938ecbc762eeaf99b9fe04c2820a43963b04f3
+Result = Fail
+
+Count = 188
+Nonce = 22a77db9fcbc95
+Adata = 86bf1739c10f63df734ee3e60ac40ff5636c49f68ca4c16ece289609eb413e7a
+CT = 1fdbe91189da01c5098cf1538addd85b1cfef0abd0797c141330f633
+Result = Fail
+
+Count = 189
+Nonce = 491e32b0bbfa4c
+Adata = 75bef075c79d6cfd7fc73aefd67b2d215be0648937477ba606b1fe1be591239e
+CT = 462e7cdf9a6a553bca37d4d93bed4986b715d0349238613e10c1f6d7
+Result = Fail
+
+Count = 190
+Nonce = bc4b7d3a380be0
+Adata = 353dbb41e2d525a9f4fcd858d0f0aa1b1e86ac0f936d5c09c6b61c343f94e3fc
+CT = 7d142f26aa6c9d55850c5c9f58ab36a66670d47c515bf93cd37e5543
+Result = Fail
+
+Count = 191
+Nonce = a840e98df72ae9
+Adata = 22c6607732ef1bdc7fcf6197e037cdadd7ee17c008552dd9f04b8564d34fb17c
+CT = f7122cbcec93d53fc7e3fc629ea15d28363cad1c83a23bb3cc5e0c4a
+Result = Pass
+Payload = a2f53385618b41301f4e3ea4c597f411103dac2b37abf5da
+
+Count = 192
+Nonce = 39d93c3cf31a6f
+Adata = 937dfac5cded938438f4e97aabd9beb50dba40f824198260a89729479cfe6869
+CT = e1cad7f946b20c373323218c8a89e56edf3030662e50d459fc12a512
+Result = Pass
+Payload = c1bdef96dc868446be48491b160504546f2a40dd581f9582
+
+Count = 193
+Nonce = 0bbc177019321e
+Adata = f6e02678820f5ccbede6cbded02d6dd58d486166d7b18ee975a688af421fb795
+CT = d4741814466a23e26107d773f103a4c83db9d772dbd5fdc1c2eaf895
+Result = Pass
+Payload = 72a70954d22ad722fc32756afce67b344b2f3c55fe1d9eed
+
+Count = 194
+Nonce = ad048eb2ad7526
+Adata = 0d2739cfdac782b61f484fa1a423c478c414397ec420327963d79112b2d70a7e
+CT = ed35ff66bc7f6d8ec7acf896f994d79f5792cf6d22d6691ff92fa2f7
+Result = Fail
+
+[Alen = 32, Plen = 24, Nlen = 7, Tlen = 16]
+
+Key = a7aa635ea51b0bb20a092bd5573e728c
+
+Count = 195
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = b351ab96b2e45515254558d5212673ee6c776d42dbca3b512cf3a20b7fd7c49e6e79bef475c2906f
+Result = Pass
+Payload = a265480ca88d5f536db0dc6abc40faf0d05be7a966977768
+
+Count = 196
+Nonce = fdd2d6f503c915
+Adata = 5b92394f21ddc3ad49d9b0881b829a5935cb3a4d23e292a62fb66b5e7ab7020e
+CT = df1a5285caa41b4bb47f6e5ceceba4e82721828d68427a3081d18ca149d6766bfaccec88f194eb5b
+Result = Fail
+
+Count = 197
+Nonce = 27d73d58100054
+Adata = f6468542923be79b4b06dfe70920d57d1da73a9c16f9c9a12d810d7de0d12467
+CT = 04a29fc109dfc626e8297e0f586d0bfaf31260017d95f62d5eb4f0875dda5ccd9b94026ba49fb34e
+Result = Fail
+
+Count = 198
+Nonce = dd16e0ce1250e3
+Adata = bc65cfd65e9863c8b7457d58afa6bdb48a84170d8aa97ba5b397b52ad17a9242
+CT = 77e4cd5d319353ecb6b89e2de14bcfee4fbf738b61df14f3920843994def41aed3103995d3392eed
+Result = Fail
+
+Count = 199
+Nonce = ccee19d037cf4a
+Adata = c026696e6425e6c33f45b4145febf1137e7ac26383c9f5aa4cd4e5e8abb19e07
+CT = e676f5dfde8ad810d9e729d142670eef77f2878369a28797d57603d5c45606c68be5535c671d5432
+Result = Pass
+Payload = 0df202431ee7f251a38aaf6aa8cd313782bd293af9114005
+
+Count = 200
+Nonce = 6c8ba94f09cbe6
+Adata = 774ad1a88f8bb063951486d4aec5bf82d5fc535bd0b952f86200c123c37fa496
+CT = 60c51e5c3fe4197454d64fa14017639bcfd1423b9d74e506a0bfd54fb786208e1e49c6d0e645d9fb
+Result = Fail
+
+Count = 201
+Nonce = 1f670302fcdcc8
+Adata = 1a9ff9698cfc96b581d7115c822e4363d7355ec5daed2eae5bf89ee944ac7d9c
+CT = 64d1160365062eca1027cc7036862b027bdda3a9abdf794daf8a9b7a5c50b0be4596290a4d405e79
+Result = Fail
+
+Count = 202
+Nonce = 5d05f658c729a2
+Adata = dd9564c1431ed490b17ef69f6115805e54ef156ef4e10e58f7d57a7e86626352
+CT = 968ca115583c645710d2b47fb196cf55f6ef33f2b01400e22ce9c776932ecf7fddd849be58096b88
+Result = Fail
+
+Count = 203
+Nonce = 22a77db9fcbc95
+Adata = 86bf1739c10f63df734ee3e60ac40ff5636c49f68ca4c16ece289609eb413e7a
+CT = 4985821b16ff6d4d3416573e2fba4d53186d912f0b023a99915d0020da92f483a5a7914cba14b1e7
+Result = Fail
+
+Count = 204
+Nonce = 491e32b0bbfa4c
+Adata = 75bef075c79d6cfd7fc73aefd67b2d215be0648937477ba606b1fe1be591239e
+CT = c7345b031ef85bde766226a7603adaa7dcb07a7b2a8be1b571420e036ea48dddd671be622d372c5b
+Result = Fail
+
+Count = 205
+Nonce = bc4b7d3a380be0
+Adata = 353dbb41e2d525a9f4fcd858d0f0aa1b1e86ac0f936d5c09c6b61c343f94e3fc
+CT = 11460b9acccc13001be236814da6b73f2c8e0467574f151bb619a331f8d67d70c3f3a59b3fab53a5
+Result = Fail
+
+Count = 206
+Nonce = a840e98df72ae9
+Adata = 22c6607732ef1bdc7fcf6197e037cdadd7ee17c008552dd9f04b8564d34fb17c
+CT = 1bcff940a2d9d48e93bbfd13aed5947237485983e6ae04b8b944bb46306a9b1e783f3e54c92d5f5e
+Result = Pass
+Payload = a2f53385618b41301f4e3ea4c597f411103dac2b37abf5da
+
+Count = 207
+Nonce = 39d93c3cf31a6f
+Adata = 937dfac5cded938438f4e97aabd9beb50dba40f824198260a89729479cfe6869
+CT = 3b6c1570c85f297079be14cd66d335251c7b52e131a636f148608963f3037763843b70c35d7011f8
+Result = Pass
+Payload = c1bdef96dc868446be48491b160504546f2a40dd581f9582
+
+Count = 208
+Nonce = 0bbc177019321e
+Adata = f6e02678820f5ccbede6cbded02d6dd58d486166d7b18ee975a688af421fb795
+CT = b540cd8cbe733e0ca2ba2112ea785596d2c1d707f41608514ba2d0944c68cc36d4125b3ef9071d69
+Result = Pass
+Payload = 72a70954d22ad722fc32756afce67b344b2f3c55fe1d9eed
+
+Count = 209
+Nonce = ad048eb2ad7526
+Adata = 0d2739cfdac782b61f484fa1a423c478c414397ec420327963d79112b2d70a7e
+CT = 3c9c1481f1428acf202b510dca67e5e6b2abc5dd71a954da51387922af7182b7d46a33c703e6e7a8
+Result = Fail
+
+[Alen = 32, Plen = 24, Nlen = 13, Tlen = 4]
+
+Key = a7aa635ea51b0bb20a092bd5573e728c
+
+Count = 210
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = 934f893824e880f743d196b22d1f340a52608155087bd28ac25e5329
+Result = Pass
+Payload = 8739b4bea1a099fe547499cbc6d1b13d849b8084c9b6acc5
+
+Count = 211
+Nonce = 0812757ad0cc4d17c4cfe7a642
+Adata = ec6c44a7e94e51a3ca6dee229098391575ec7213c85267fbf7492fdbeee61b10
+CT = f43ba9d834ad85dfab3f1c0c27c3441fe4e411a38a261a6559b3b3ee
+Result = Fail
+
+Count = 212
+Nonce = eff510acc1b85f35029cf7dc00
+Adata = 0923b927b8295c5dfaf67da55e5014293bc8c708fda50af06c1e8aef31cccc86
+CT = c686eac859a7bae3cce97d0b6527a0a7c8c2b24ece35f4370bf6688e
+Result = Fail
+
+Count = 213
+Nonce = 3d13d09057190366c63c8750e9
+Adata = 77e27aa9a7bf30e130c862a3296a1cd7a10195ed1d940f2c97bfff47c6f06e32
+CT = 2b28355ecf7246ddb08d65c464dcaa90af85f434ff95267280ed869c
+Result = Fail
+
+Count = 214
+Nonce = e3c03ef7e1d31961ee0b97bd99
+Adata = 8a3676dd640821b58fb0f0329855fd5882c376ea166b958b7aaad223054e5784
+CT = ecde42091baa1f5c17b79746e21c3de5c78984570748021ccd399507
+Result = Pass
+Payload = 92973ce707733a73118c8ce6b5e3fc77a17f448310c0197f
+
+Count = 215
+Nonce = 5d165ddd4e599387af5967cae6
+Adata = e374f875ce829b62c98fbd67bcf128b5647f25fff9a643300eb95559b889baed
+CT = 5c338435ed4f148342604c9aed63e907c100453d719fda2a3da37b66
+Result = Fail
+
+Count = 216
+Nonce = fcec171162a27a96066181fab2
+Adata = cf431cc3671ec468ea86f6cc09842fcf3a84b3ef0fa1c7b20b232145b4469d62
+CT = 30eac1042015eb82729673edd9939bf9995b2575da4d6c4c7e75dded
+Result = Fail
+
+Count = 217
+Nonce = 2fa8120398d1a946f391367cf6
+Adata = 92558a239c8e13230754f23aec67b153db29fdfc7daf641778185dd2931d89da
+CT = ebd3ce55b40e4bbd8172033948c6c78049161ee8f949eb50722b9c87
+Result = Fail
+
+Count = 218
+Nonce = 88e0ae338bbca9d4299b294354
+Adata = 5db5c388dbadc9f175a5cd5a1472a458d25acd7fb9c951c0cd45edf64da473bb
+CT = 20f79b36ca83baac97600fd8a6dad22c2cd0f9b7e770576048c042e5
+Result = Fail
+
+Count = 219
+Nonce = 4862e36296d6afc9399a95bbb4
+Adata = 36d82ebd0e0f5fe3b12946d041ae5aee16e6d17025406dd776f499bbd8e8b4c8
+CT = 77b76f249f936fb19bd47fe28ad4dbb7725dec365a1cb23a885ba975
+Result = Fail
+
+Count = 220
+Nonce = 2f360a4715074e942244ab7f9b
+Adata = f0087b0086a081c1071481f033a8be8e940c36763084329bb8461b9102238f4f
+CT = cf6763a23c2eab730845d1eb79bbba9f54ee899fe3d70570aa799e79
+Result = Fail
+
+Count = 221
+Nonce = 93e08854560edb096e5d654086
+Adata = bdc60dff08bfd5d44320b75c61e456fd4333c9c3d0294d4a48d936dfd5922ce2
+CT = 1f8086a43c1b2dea557952db88e0dbbdb96aafdb345eddae6c0b0104
+Result = Pass
+Payload = 569e4aec88dd51ca519c0a00c922ee33d3559b98a32d7906
+
+Count = 222
+Nonce = e3f37b68ff508cfe295441d9e3
+Adata = b2b6c5782e4f128467c589d2a6cf55ef12877adb771bbb6245c5bba9dcfd6208
+CT = c0c5f92285b114e0a0777e1bc22b810e7cc4f68c28cd5ce047a28dd8
+Result = Pass
+Payload = 02b5511204bd55f7c37973e26f6df5883c0a530f07c7f8c2
+
+Count = 223
+Nonce = ea98ec44f5a86715014783172e
+Adata = e4692b9f06b666c7451b146c8aeb07a6e30c629d28065c3dde5940325b14b810
+CT = 56327f4db9c18f72bbefc3f316d31f9795dd77f493385ab7b7543552
+Result = Pass
+Payload = 4da40b80579c1d9a5309f7efecb7c059a2f914511ca5fc10
+
+Count = 224
+Nonce = 5a16a8902bd70fa06cfe184c57
+Adata = 399d6b0652836457ec4f701f0dc0e5aed73d16585d61cb1bb5b7ee824fc287c8
+CT = 37d5b17995fac8c94302ec9ba20a36d97678e85199b677f8ee39867e
+Result = Fail
+
+[Alen = 32, Plen = 24, Nlen = 13, Tlen = 16]
+
+Key = 26511fb51fcfa75cb4b44da75a6e5a0e
+
+Count = 225
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = 50038b5fdd364ee747b70d00bd36840ece4ea19998123375c0a458bfcafa3b2609afe0f825cbf503
+Result = Pass
+Payload = 8739b4bea1a099fe547499cbc6d1b13d849b8084c9b6acc5
+
+Count = 226
+Nonce = 0812757ad0cc4d17c4cfe7a642
+Adata = ec6c44a7e94e51a3ca6dee229098391575ec7213c85267fbf7492fdbeee61b10
+CT = 78ed8ff6b5a1255d0fbd0a719a9c27b059ff5f83d0c4962c390042ba8bb5f6798dab01c5afad7306
+Result = Fail
+
+Count = 227
+Nonce = eff510acc1b85f35029cf7dc00
+Adata = 0923b927b8295c5dfaf67da55e5014293bc8c708fda50af06c1e8aef31cccc86
+CT = 4b91d8e616d3f60452fd3a576bd7c265b7f549523ed4a5d7a3463394cf3c25bef8af8f244d0c0b00
+Result = Fail
+
+Count = 228
+Nonce = 3d13d09057190366c63c8750e9
+Adata = 77e27aa9a7bf30e130c862a3296a1cd7a10195ed1d940f2c97bfff47c6f06e32
+CT = ab8cf8891ab62924c0c6f49dd253cfa0c3d6260d0ee4d9ba88caf8ae59d9d1131626da0dddf8722d
+Result = Fail
+
+Count = 229
+Nonce = e3c03ef7e1d31961ee0b97bd99
+Adata = 8a3676dd640821b58fb0f0329855fd5882c376ea166b958b7aaad223054e5784
+CT = c6b7680f321132a8bd00e8e92f785d0b828b100af6392a04d1292373a76970eda77a8194f6276262
+Result = Pass
+Payload = 92973ce707733a73118c8ce6b5e3fc77a17f448310c0197f
+
+Count = 230
+Nonce = 5d165ddd4e599387af5967cae6
+Adata = e374f875ce829b62c98fbd67bcf128b5647f25fff9a643300eb95559b889baed
+CT = aea98867d3d707c43a963c1d7fdcfc953cbd707803b2b5f0a97af19d0b7bf7c7ce398cb0b44d73af
+Result = Fail
+
+Count = 231
+Nonce = fcec171162a27a96066181fab2
+Adata = cf431cc3671ec468ea86f6cc09842fcf3a84b3ef0fa1c7b20b232145b4469d62
+CT = c55e17ba7886eb58126d50bde8c5c211cc1aafd71a3d9e5b343065b4bdd973ee072dbf5160d310f3
+Result = Fail
+
+Count = 232
+Nonce = 2fa8120398d1a946f391367cf6
+Adata = 92558a239c8e13230754f23aec67b153db29fdfc7daf641778185dd2931d89da
+CT = 791a62d5fb39ff9735ad94507e1afe2647714d5cc56b6ff4233ec600bca1d31f704807494fb0f18d
+Result = Fail
+
+Count = 233
+Nonce = 88e0ae338bbca9d4299b294354
+Adata = 5db5c388dbadc9f175a5cd5a1472a458d25acd7fb9c951c0cd45edf64da473bb
+CT = f98a081998e29500f15ebd8978a95423aed4e8e78e0279d17ec183db0e2a33ebb147d0e2363fbb01
+Result = Fail
+
+Count = 234
+Nonce = 4862e36296d6afc9399a95bbb4
+Adata = 36d82ebd0e0f5fe3b12946d041ae5aee16e6d17025406dd776f499bbd8e8b4c8
+CT = 7779814dc295a23b4100ca94bec0ad4ce2f6be6fb75a0c217e67ea2577ade5836c26a89760e0959b
+Result = Fail
+
+Count = 235
+Nonce = 2f360a4715074e942244ab7f9b
+Adata = f0087b0086a081c1071481f033a8be8e940c36763084329bb8461b9102238f4f
+CT = 55640eed12c7595a36ab423da8d8241905b6ff1e906db9624978a7865df8369635269411b3aaeb32
+Result = Fail
+
+Count = 236
+Nonce = 93e08854560edb096e5d654086
+Adata = bdc60dff08bfd5d44320b75c61e456fd4333c9c3d0294d4a48d936dfd5922ce2
+CT = 7fcdce0ba567b9a708d54fdb16125de71dce952f4741684f4f9d302e4f1d2a2aedf2768d7b29163f
+Result = Pass
+Payload = 569e4aec88dd51ca519c0a00c922ee33d3559b98a32d7906
+
+Count = 237
+Nonce = e3f37b68ff508cfe295441d9e3
+Adata = b2b6c5782e4f128467c589d2a6cf55ef12877adb771bbb6245c5bba9dcfd6208
+CT = d42111ba22987eac1ead5cc6cb8548bcda190d118dcd5461a50036af67fadab163e9daa8bd8e9030
+Result = Pass
+Payload = 02b5511204bd55f7c37973e26f6df5883c0a530f07c7f8c2
+
+Count = 238
+Nonce = ea98ec44f5a86715014783172e
+Adata = e4692b9f06b666c7451b146c8aeb07a6e30c629d28065c3dde5940325b14b810
+CT = 1bf0ba0ebb20d8edba59f29a9371750c9c714078f73c335d2f1322ac69b848b001476323aed84c47
+Result = Pass
+Payload = 4da40b80579c1d9a5309f7efecb7c059a2f914511ca5fc10
+
+Count = 239
+Nonce = 5a16a8902bd70fa06cfe184c57
+Adata = 399d6b0652836457ec4f701f0dc0e5aed73d16585d61cb1bb5b7ee824fc287c8
+CT = 9d993b945476ace0b9ca932963ac8835e1bd02e8065da2d816786c4d8cf14c03b031ff723311b3c4
+Result = Fail
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT128.txt b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT128.txt
new file mode 100644
index 0000000000..1606dcb21e
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT128.txt
@@ -0,0 +1,1589 @@
+# CAVS 11.0
+# "CCM-DVPT" information
+# AES Keylen: 128
+# Generated on Tue Mar 15 08:09:25 2011
+
+
+[Alen = 0, Plen = 0, Nlen = 7, Tlen = 4]
+
+Key = 4ae701103c63deca5b5a3939d7d05992
+
+Count = 0
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = 02209f55
+Result = Pass (0)
+Payload = 00
+
+Count = 1
+Nonce = 3796cf51b87266
+Adata = 00
+CT = 9a04c241
+Result = Fail (2 - CT changed)
+
+Count = 2
+Nonce = 89ca5a64050f9f
+Adata = 00
+CT = f5f915df
+Result = Fail (1 - Adata changed)
+
+Count = 3
+Nonce = ec9d8edff25645
+Adata = 00
+CT = 7a3c3499
+Result = Fail (1 - Adata changed)
+
+Count = 4
+Nonce = 05e16f0f42a6f4
+Adata = 00
+CT = f09c2986
+Result = Pass (0)
+Payload = 00
+
+Count = 5
+Nonce = 2e504b694f8df5
+Adata = 00
+CT = 4ae97e71
+Result = Fail (2 - CT changed)
+
+Count = 6
+Nonce = 06d102a9328863
+Adata = 00
+CT = ecb38c8b
+Result = Fail (1 - Adata changed)
+
+Count = 7
+Nonce = c288b810fb5334
+Adata = 00
+CT = 9c4dc530
+Result = Fail (2 - CT changed)
+
+Count = 8
+Nonce = 08a166d9eb6610
+Adata = 00
+CT = 67299ef6
+Result = Fail (2 - CT changed)
+
+Count = 9
+Nonce = 4a5810b121c91b
+Adata = 00
+CT = b0538d02
+Result = Fail (1 - Adata changed)
+
+Count = 10
+Nonce = 44077341139bf9
+Adata = 00
+CT = 88200ea8
+Result = Fail (1 - Adata changed)
+
+Count = 11
+Nonce = a9df4f37847e1f
+Adata = 00
+CT = 19867aa5
+Result = Pass (0)
+Payload = 00
+
+Count = 12
+Nonce = 11df57fcd131e9
+Adata = 00
+CT = 3b392a52
+Result = Pass (0)
+Payload = 00
+
+Count = 13
+Nonce = 890fff56d10dc0
+Adata = 00
+CT = 1c5e47e0
+Result = Pass (0)
+Payload = 00
+
+Count = 14
+Nonce = 9dc18698731b27
+Adata = 00
+CT = 97a56b8b
+Result = Fail (2 - CT changed)
+
+[Alen = 0, Plen = 0, Nlen = 7, Tlen = 16]
+
+Key = 4bb3c4a4f893ad8c9bdc833c325d62b3
+
+Count = 15
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = 75d582db43ce9b13ab4b6f7f14341330
+Result = Pass (0)
+Payload = 00
+
+Count = 16
+Nonce = 3796cf51b87266
+Adata = 00
+CT = 3a65e03af37b81d05acc7ec1bc39deb0
+Result = Fail (2 - CT changed)
+
+Count = 17
+Nonce = 89ca5a64050f9f
+Adata = 00
+CT = efc5721e0b9e4c3c90deab0e1d5c11bd
+Result = Fail (1 - Adata changed)
+
+Count = 18
+Nonce = ec9d8edff25645
+Adata = 00
+CT = 91b4b779823f4f0e3979ced93b99736c
+Result = Fail (1 - Adata changed)
+
+Count = 19
+Nonce = 05e16f0f42a6f4
+Adata = 00
+CT = e2e87ca82523ccfeb416b42af9d9aadc
+Result = Pass (0)
+Payload = 00
+
+Count = 20
+Nonce = 2e504b694f8df5
+Adata = 00
+CT = 7b85fd105cc960df86ad86846d178274
+Result = Fail (2 - CT changed)
+
+Count = 21
+Nonce = 06d102a9328863
+Adata = 00
+CT = ffa140be27b25f307a6efd9697d66c9b
+Result = Fail (1 - Adata changed)
+
+Count = 22
+Nonce = c288b810fb5334
+Adata = 00
+CT = ed356542e0a804a724bfaa422e98a970
+Result = Fail (2 - CT changed)
+
+Count = 23
+Nonce = 08a166d9eb6610
+Adata = 00
+CT = e31dd8dc920fe7900e1b1817fe845c7d
+Result = Fail (2 - CT changed)
+
+Count = 24
+Nonce = 4a5810b121c91b
+Adata = 00
+CT = ae5a0777f03bbf541f305d00acff0396
+Result = Fail (1 - Adata changed)
+
+Count = 25
+Nonce = 44077341139bf9
+Adata = 00
+CT = 957dca58616c1cbe99f94fd8f7c257d9
+Result = Fail (1 - Adata changed)
+
+Count = 26
+Nonce = a9df4f37847e1f
+Adata = 00
+CT = 0e150af422f6da238bb476810b2d5bc2
+Result = Pass (0)
+Payload = 00
+
+Count = 27
+Nonce = 11df57fcd131e9
+Adata = 00
+CT = 8e1150756ff3a733a1274470f072b74c
+Result = Pass (0)
+Payload = 00
+
+Count = 28
+Nonce = 890fff56d10dc0
+Adata = 00
+CT = a1f70df3fa9cfeb95f869b3fe08466e0
+Result = Pass (0)
+Payload = 00
+
+Count = 29
+Nonce = 9dc18698731b27
+Adata = 00
+CT = fdf3f6c177aa1d71fe3474a5a2eb6bb1
+Result = Fail (2 - CT changed)
+
+[Alen = 0, Plen = 0, Nlen = 13, Tlen = 4]
+
+Key = 4bb3c4a4f893ad8c9bdc833c325d62b3
+
+Count = 30
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = 90156f3f
+Result = Pass (0)
+Payload = 00
+
+Count = 31
+Nonce = a16a2e741f1cd9717285b6d882
+Adata = 00
+CT = 88909016
+Result = Fail (2 - CT changed)
+
+Count = 32
+Nonce = 368f3b8180fd4b851b7b272cb1
+Adata = 00
+CT = de547d03
+Result = Fail (1 - Adata changed)
+
+Count = 33
+Nonce = 7bb2bc00c0cafce65b5299ae64
+Adata = 00
+CT = ea4bad52
+Result = Fail (1 - Adata changed)
+
+Count = 34
+Nonce = 935c1ef3d4032ff090f91141f3
+Adata = 00
+CT = 1bc82b3d
+Result = Pass (0)
+Payload = 00
+
+Count = 35
+Nonce = 2640b14f10b116411d1b5c1ad1
+Adata = 00
+CT = 92e72250
+Result = Fail (2 - CT changed)
+
+Count = 36
+Nonce = b229c173a13b2d83af91ec45b0
+Adata = 00
+CT = e81f0647
+Result = Fail (1 - Adata changed)
+
+Count = 37
+Nonce = 37ca0dc2d6efd9efde69f14f03
+Adata = 00
+CT = 7cb906ec
+Result = Fail (2 - CT changed)
+
+Count = 38
+Nonce = 6b6238aed86d677ba2b3e2622c
+Adata = 00
+CT = d60f815b
+Result = Fail (2 - CT changed)
+
+Count = 39
+Nonce = d6cb2ac67bb13b8f6d31fad64a
+Adata = 00
+CT = d3d4f3b0
+Result = Fail (1 - Adata changed)
+
+Count = 40
+Nonce = 32a7cd361ef00e65f5778fdfd4
+Adata = 00
+CT = a9df97ad
+Result = Fail (1 - Adata changed)
+
+Count = 41
+Nonce = d0a1508fdefcf5be30a459b813
+Adata = 00
+CT = 36a37a59
+Result = Pass (0)
+Payload = 00
+
+Count = 42
+Nonce = 5381a61b449dc6a42aa4c79b95
+Adata = 00
+CT = dba02a36
+Result = Pass (0)
+Payload = 00
+
+Count = 43
+Nonce = c55430f2da0687ea40313884ab
+Adata = 00
+CT = 25dcb3c5
+Result = Pass (0)
+Payload = 00
+
+Count = 44
+Nonce = ec76d1850acc0979a1f11906fb
+Adata = 00
+CT = 1d2832d0
+Result = Fail (2 - CT changed)
+
+[Alen = 0, Plen = 0, Nlen = 13, Tlen = 16]
+
+Key = 19ebfde2d5468ba0a3031bde629b11fd
+
+Count = 45
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = fb04dc5a44c6bb000f2440f5154364b4
+Result = Pass (0)
+Payload = 00
+
+Count = 46
+Nonce = a16a2e741f1cd9717285b6d882
+Adata = 00
+CT = 5447075bf42a59b91f08064738b015ab
+Result = Fail (2 - CT changed)
+
+Count = 47
+Nonce = 368f3b8180fd4b851b7b272cb1
+Adata = 00
+CT = fdc992847f0815fac67aa935b35208ed
+Result = Fail (1 - Adata changed)
+
+Count = 48
+Nonce = 7bb2bc00c0cafce65b5299ae64
+Adata = 00
+CT = 2cabd690a45e59854b7587b26dd77f8e
+Result = Fail (1 - Adata changed)
+
+Count = 49
+Nonce = 935c1ef3d4032ff090f91141f3
+Adata = 00
+CT = 3dacc71169f6da77ec91ff1d2f649ed1
+Result = Pass (0)
+Payload = 00
+
+Count = 50
+Nonce = 2640b14f10b116411d1b5c1ad1
+Adata = 00
+CT = 97a2eb170ef03fa12124f1315e3b694f
+Result = Fail (2 - CT changed)
+
+Count = 51
+Nonce = b229c173a13b2d83af91ec45b0
+Adata = 00
+CT = 94d85a83169d8dc76f58baf4d63ecfee
+Result = Fail (1 - Adata changed)
+
+Count = 52
+Nonce = 37ca0dc2d6efd9efde69f14f03
+Adata = 00
+CT = d3903c6289ca3684b8ce1174c23153a4
+Result = Fail (2 - CT changed)
+
+Count = 53
+Nonce = 6b6238aed86d677ba2b3e2622c
+Adata = 00
+CT = 5cbac5c418374a68bd7085454c4b0c13
+Result = Fail (2 - CT changed)
+
+Count = 54
+Nonce = d6cb2ac67bb13b8f6d31fad64a
+Adata = 00
+CT = 26317f6b8b0130097441ed04b8009aef
+Result = Fail (1 - Adata changed)
+
+Count = 55
+Nonce = 32a7cd361ef00e65f5778fdfd4
+Adata = 00
+CT = b82ab6f3bbf59b6caafc54f05570f74e
+Result = Fail (1 - Adata changed)
+
+Count = 56
+Nonce = d0a1508fdefcf5be30a459b813
+Adata = 00
+CT = 1ae34207e74c8c78890ae17e320e84bd
+Result = Pass (0)
+Payload = 00
+
+Count = 57
+Nonce = 5381a61b449dc6a42aa4c79b95
+Adata = 00
+CT = 5c5fa254c0be503b02caffade6b85259
+Result = Pass (0)
+Payload = 00
+
+Count = 58
+Nonce = c55430f2da0687ea40313884ab
+Adata = 00
+CT = 9340266730ea36207bb734819d3553e9
+Result = Pass (0)
+Payload = 00
+
+Count = 59
+Nonce = ec76d1850acc0979a1f11906fb
+Adata = 00
+CT = ec17cccf33bd9a0d4ce7aa20690c1333
+Result = Fail (2 - CT changed)
+
+[Alen = 0, Plen = 24, Nlen = 7, Tlen = 4]
+
+Key = 19ebfde2d5468ba0a3031bde629b11fd
+
+Count = 60
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = a90e8ea44085ced791b2fdb7fd44b5cf0bd7d27718029bb703e1fa6b
+Result = Pass (0)
+Payload = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22
+
+Count = 61
+Nonce = 31f8fa25827d48
+Adata = 00
+CT = 50aafe0578c115c4a8e126ff7b3ccb64dce8ccaa8ceda69f23e5d81c
+Result = Fail (2 - CT changed)
+
+Count = 62
+Nonce = 5340ed7752c9ff
+Adata = 00
+CT = 512ed208bf10d57406537e94d20a5b6e2e9ab0683dfdc685869a97f0
+Result = Fail (1 - Adata changed)
+
+Count = 63
+Nonce = 9cbce402511b89
+Adata = 00
+CT = af72db9cd9d6f46607d6f9542ca69988dd15255c5c91171c838e7f95
+Result = Fail (1 - Adata changed)
+
+Count = 64
+Nonce = 123a0beace4e39
+Adata = 00
+CT = 47d71409a03c330be9451b3f92c9d21c584391ad1010e9d609b89801
+Result = Pass (0)
+Payload = 9d033e3b66efed1467868f382417c80594877a28bc97f406
+
+Count = 65
+Nonce = 8ea1594a58fe4a
+Adata = 00
+CT = e562c7af0384ea16431ca20934a293a058d722cbfc3186c8eaf5f825
+Result = Fail (2 - CT changed)
+
+Count = 66
+Nonce = 5a7743e59e82da
+Adata = 00
+CT = 004d9d89c401aa79919c2805fcd5de69316e191df56426c05ec1aa6a
+Result = Fail (1 - Adata changed)
+
+Count = 67
+Nonce = f477f754d7ee76
+Adata = 00
+CT = d623673d7f6d57c208bde112ca858561f3af5cc2bf5de926f3586c6f
+Result = Fail (2 - CT changed)
+
+Count = 68
+Nonce = 040a257dede70e
+Adata = 00
+CT = fd4733d158b5630f4f6c03ab26b11bff0cbe0d5d3df99a735fa40618
+Result = Fail (2 - CT changed)
+
+Count = 69
+Nonce = dd51b8e91683d1
+Adata = 00
+CT = d352cb996c3075ff367a8dcacbbae46a12fbef08aa96ec835bf4f930
+Result = Fail (1 - Adata changed)
+
+Count = 70
+Nonce = ab3cb86cca6fb2
+Adata = 00
+CT = 31730fac20e21eca0aef591faa9fa90b3c058e32af1ce48a66f0496e
+Result = Fail (1 - Adata changed)
+
+Count = 71
+Nonce = f67b98efd39b55
+Adata = 00
+CT = dd175905a7ea3aef9fce068e6cb78e9cc60519755a178c77b753181c
+Result = Pass (0)
+Payload = f2e944e1ae47ad5873bf391f1b0cc07f6151eb4c50bb45b2
+
+Count = 72
+Nonce = e60e2c002d1c99
+Adata = 00
+CT = 8ad6b76f54392ee0f2834f09142545bcde9bf03d04d64aa10876f2da
+Result = Pass (0)
+Payload = 70f48dc1d76e5028da07e29852801375a9edb2214a5ea4c0
+
+Count = 73
+Nonce = 098e053fa08043
+Adata = 00
+CT = 808eb3e04c39abde64674f0f7716dde11699cff8dd367c4cd4f7fc07
+Result = Pass (0)
+Payload = bd81680e3dc0b35431c92598dcaa26ef09ca0da5e77193de
+
+Count = 74
+Nonce = 4bf48328725514
+Adata = 00
+CT = e074d13aad43f7b2364d47db0a02326641ca3b2ad61a1c49973a2712
+Result = Fail (2 - CT changed)
+
+[Alen = 0, Plen = 24, Nlen = 7, Tlen = 16]
+
+Key = 197afb02ffbd8f699dacae87094d5243
+
+Count = 75
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = 24ab9eeb0e5508cae80074f1070ee188a637171860881f1f2d9a3fbc210595b7b8b1b41523111a8e
+Result = Pass (0)
+Payload = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22
+
+Count = 76
+Nonce = 31f8fa25827d48
+Adata = 00
+CT = 7ebfda6fa5da1dbffd82dc29b875798fbcef8ba0084fbd2463af747cc88a001fa94e060290f209c4
+Result = Fail (2 - CT changed)
+
+Count = 77
+Nonce = 5340ed7752c9ff
+Adata = 00
+CT = cbf133643851f91ddc7a1e19a0c21990459f2b7728da58f5cf3b8e6c8aeb5eeb0a5efb3700be45a2
+Result = Fail (1 - Adata changed)
+
+Count = 78
+Nonce = 9cbce402511b89
+Adata = 00
+CT = 0de7567a945c0af4a2291a651de411e8d0438508f2d4da80f7bd61a0158accbca28913e39fe80906
+Result = Fail (1 - Adata changed)
+
+Count = 79
+Nonce = 123a0beace4e39
+Adata = 00
+CT = d43035cdb5a1868aa430e8b41a1dc57a639087238e38bd628feeda2e8f249dd93a8358def7639875
+Result = Pass (0)
+Payload = 9d033e3b66efed1467868f382417c80594877a28bc97f406
+
+Count = 80
+Nonce = 8ea1594a58fe4a
+Adata = 00
+CT = 389547260b354a6cbc909de057d367677049e80613877f6fbf19f89da977e56f308373c616299ad4
+Result = Fail (2 - CT changed)
+
+Count = 81
+Nonce = 5a7743e59e82da
+Adata = 00
+CT = a95aa33483ed3711470025394616bf98fe624fbca8aa6fbc21366b9da457ede2a673351475b53d41
+Result = Fail (1 - Adata changed)
+
+Count = 82
+Nonce = f477f754d7ee76
+Adata = 00
+CT = 3d53b6ab8925f429ae14a0065cd203d4f9deddd402a79ac6d889a7cae55efd71b369cd6d43ef363b
+Result = Fail (2 - CT changed)
+
+Count = 83
+Nonce = 040a257dede70e
+Adata = 00
+CT = d5e6e82cb5f8034a89e58adf8298476253f18981bcb3b0364be7f19463dd330a4b9f3cbb30b88fa5
+Result = Fail (2 - CT changed)
+
+Count = 84
+Nonce = dd51b8e91683d1
+Adata = 00
+CT = 02f69107d62ff77145c7d57684c70ba671d55f1c63bb2ad8c2df063f7fdbae27f0736a37fd065fb4
+Result = Fail (1 - Adata changed)
+
+Count = 85
+Nonce = ab3cb86cca6fb2
+Adata = 00
+CT = 64ec2f321111da9c5389e8255bfe69876d4f548f94cacd529b45d54cc24cff1b1d8aa1df32fbd81a
+Result = Fail (1 - Adata changed)
+
+Count = 86
+Nonce = f67b98efd39b55
+Adata = 00
+CT = 37d63c2bbf44d2eb155ecc1a844841d5c33f1a6d443419330217a4f1f4fb302257b0de7c9da2e750
+Result = Pass (0)
+Payload = f2e944e1ae47ad5873bf391f1b0cc07f6151eb4c50bb45b2
+
+Count = 87
+Nonce = e60e2c002d1c99
+Adata = 00
+CT = 33e0dce4410e51bed5323ea49490207084ac91732bae429236a305d520a1a24930a70a311aa3695d
+Result = Pass (0)
+Payload = 70f48dc1d76e5028da07e29852801375a9edb2214a5ea4c0
+
+Count = 88
+Nonce = 098e053fa08043
+Adata = 00
+CT = 1d732c334319bd775e7cf93dbdc4204bbdb58192be08280481e3d64ed546b6b70ee088a693f55fbb
+Result = Pass (0)
+Payload = bd81680e3dc0b35431c92598dcaa26ef09ca0da5e77193de
+
+Count = 89
+Nonce = 4bf48328725514
+Adata = 00
+CT = c92fc2f0d24593f67d9c09d326158a8138237c4096093f0d737719dd84ccfb397a4f61b70c85262a
+Result = Fail (2 - CT changed)
+
+[Alen = 0, Plen = 24, Nlen = 13, Tlen = 4]
+
+Key = 197afb02ffbd8f699dacae87094d5243
+
+Count = 90
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = 4a550134f94455979ec4bf89ad2bd80d25a77ae94e456134a3e138b9
+Result = Pass (0)
+Payload = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697
+
+Count = 91
+Nonce = 49004912fdd7269279b1f06a89
+Adata = 00
+CT = 118ec53dd1bfbe52d5b9fe5dfebecf2ee674ec983eada654091a5ae9
+Result = Fail (2 - CT changed)
+
+Count = 92
+Nonce = efeb82c8c68d6600b24dd6d8ee
+Adata = 00
+CT = 6b0fea26e4dfe902b5e876c7ba92afbad8aa52d3c1d00ae578b6bcc4
+Result = Fail (1 - Adata changed)
+
+Count = 93
+Nonce = 7b93d368dc551640b00ba3cbb5
+Adata = 00
+CT = 640c740e2b8af851712a05948ecee055b25b145ccb82ca58ac542b09
+Result = Fail (1 - Adata changed)
+
+Count = 94
+Nonce = 24b7a65391f88bea38fcd54a9a
+Adata = 00
+CT = 05f20b2ae70fcb0ea79aa1845c15b899a799ca60f51e6c296413020a
+Result = Pass (0)
+Payload = 43419715cef9a48dc7280bc035082a6581afd1d82bee9d1a
+
+Count = 95
+Nonce = 6aa3f731522fce7e366ba59945
+Adata = 00
+CT = 9fa576a8a5c72468afa372338cbbc33fef81ad5a873eb38a142d5636
+Result = Fail (2 - CT changed)
+
+Count = 96
+Nonce = a11cf5bed0041ee3cb1fef4b43
+Adata = 00
+CT = 8d26582c74b2b4d960ee9e417c6395daafaebb3aff45d477f3757b6a
+Result = Fail (1 - Adata changed)
+
+Count = 97
+Nonce = 273cc5013785baeb5abc79c8bd
+Adata = 00
+CT = cb62a13e38e17cc6635e409c922956ece38f593189a51b99a7001a16
+Result = Fail (2 - CT changed)
+
+Count = 98
+Nonce = d2d4482ea8e98c1cf309671895
+Adata = 00
+CT = f3e29b792423c7fbe743a3b2f890a2bff29519f3636a6232050e9225
+Result = Fail (2 - CT changed)
+
+Count = 99
+Nonce = a8849b44adb48d271979656930
+Adata = 00
+CT = 136e60d6714d906d1f4c02b7bdbb5f3ccdd2165306912dec850ec9f0
+Result = Fail (1 - Adata changed)
+
+Count = 100
+Nonce = a632ba0d00511122abcd6227ff
+Adata = 00
+CT = 49b6d0b6eeff74af0de70072d9ccdc68a0ee36a5ddbf098b4eb95533
+Result = Fail (1 - Adata changed)
+
+Count = 101
+Nonce = c47af80cd26d047630c1fdf0d1
+Adata = 00
+CT = a2a59041c3f78f6e10c3045118e8a475945e24c85b02abc40f8fb949
+Result = Pass (0)
+Payload = d8306c9c4ea6c69c6e2ad0fc0e49b1e0126b01078d6419ff
+
+Count = 102
+Nonce = 70e132023acae1f88c7a237b68
+Adata = 00
+CT = 19b4ad222795326cb031cfdb07b652dbf64ca5db5ff5d6d569d8ab41
+Result = Pass (0)
+Payload = d0b2bef5ed1a87d9c73d4a459cb05c11799c4f51ad640b1e
+
+Count = 103
+Nonce = 8010d3a2a14f72f5585defc940
+Adata = 00
+CT = 76b66b908657f4df8a329c34ccdde50ae7fc71c4a718b712f00fe764
+Result = Pass (0)
+Payload = 4faba05569bf7ac656780c16995e9122e565fe9984be8a68
+
+Count = 104
+Nonce = a98c2f0e0a7b68942853905191
+Adata = 00
+CT = 20df4662ce6c8c4ce49b14fa791e41ff8598ec93d8a825e879f9eb72
+Result = Fail (2 - CT changed)
+
+[Alen = 0, Plen = 24, Nlen = 13, Tlen = 16]
+
+Key = 90929a4b0ac65b350ad1591611fe4829
+
+Count = 105
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = 4bfe4e35784f0a65b545477e5e2f4bae0e1e6fa717eaf2cb6a9a970b9beb2ac1bd4fd62168f8378a
+Result = Pass (0)
+Payload = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697
+
+Count = 106
+Nonce = 49004912fdd7269279b1f06a89
+Adata = 00
+CT = 0c56a503aa2c12e87450d45a7b714db980fd348f327c0065a65666144994bad0c8195bcb4ade1337
+Result = Fail (2 - CT changed)
+
+Count = 107
+Nonce = efeb82c8c68d6600b24dd6d8ee
+Adata = 00
+CT = 5f69d6c21f771eb98dc724f891f530b1c045f49a054de103a85f868739404b64a7cbdd61b577c388
+Result = Fail (1 - Adata changed)
+
+Count = 108
+Nonce = 7b93d368dc551640b00ba3cbb5
+Adata = 00
+CT = d335ba572520c336f711edf27ea738ba5e6b0d772ea443b8b2b164f3c255b699cbf75330d96c3c13
+Result = Fail (1 - Adata changed)
+
+Count = 109
+Nonce = 24b7a65391f88bea38fcd54a9a
+Adata = 00
+CT = 9fa846ef8d198c538f84f856bab8f7f9c3bed90b53acb6a32658e077687315eaf11458bdf6e3c36a
+Result = Pass (0)
+Payload = 43419715cef9a48dc7280bc035082a6581afd1d82bee9d1a
+
+Count = 110
+Nonce = 6aa3f731522fce7e366ba59945
+Adata = 00
+CT = b7095030acdc5fbb8fea2c24717c1c236231f9737bcc78f463db3756abba1feef626a956794d7e56
+Result = Fail (2 - CT changed)
+
+Count = 111
+Nonce = a11cf5bed0041ee3cb1fef4b43
+Adata = 00
+CT = d6911d5831163c8ebad0916af1833051b885aae822f9f6657d6fee1de626bc7c93f2caa27a3ecaa0
+Result = Fail (1 - Adata changed)
+
+Count = 112
+Nonce = 273cc5013785baeb5abc79c8bd
+Adata = 00
+CT = 6b10a098c96c2bbf9aeb5c9adcf91e4812838dff319f8be989e2d235192f33ba0f357492112d98f4
+Result = Fail (2 - CT changed)
+
+Count = 113
+Nonce = d2d4482ea8e98c1cf309671895
+Adata = 00
+CT = aecd11cbac04e1f79b0fd24052c8cedf393dce9df350d24f800b81e834ea5dd2bdc2c688d9505359
+Result = Fail (2 - CT changed)
+
+Count = 114
+Nonce = a8849b44adb48d271979656930
+Adata = 00
+CT = d3a7a25f71b1988482dc852ed713d55abdcc4bb1129ddcae430889cd5c97343cc0dedfbd62e6b6eb
+Result = Fail (1 - Adata changed)
+
+Count = 115
+Nonce = a632ba0d00511122abcd6227ff
+Adata = 00
+CT = 368e1574a433d78d0276ce4a1cacfba834a216693536c00b15acded53c41010554e1c1fe937a7605
+Result = Fail (1 - Adata changed)
+
+Count = 116
+Nonce = c47af80cd26d047630c1fdf0d1
+Adata = 00
+CT = 99e40b3c67aca95dd4462c20cbd6b2741e7033fc4f41a975c9390fbdb9ec416267096ccbf2c148e5
+Result = Pass (0)
+Payload = d8306c9c4ea6c69c6e2ad0fc0e49b1e0126b01078d6419ff
+
+Count = 117
+Nonce = 70e132023acae1f88c7a237b68
+Adata = 00
+CT = de079418c25ba67e5fda009998e3fce61bfdc3b7787cf06655c18ae38b7ee7f00f96cfca4fe9a2ef
+Result = Pass (0)
+Payload = d0b2bef5ed1a87d9c73d4a459cb05c11799c4f51ad640b1e
+
+Count = 118
+Nonce = 8010d3a2a14f72f5585defc940
+Adata = 00
+CT = fbab64d8dd8b6e33c7cc6124cd65f004d7247277fe98d5d3b35357a35ff9e58e18d6d80df9fc335d
+Result = Pass (0)
+Payload = 4faba05569bf7ac656780c16995e9122e565fe9984be8a68
+
+Count = 119
+Nonce = a98c2f0e0a7b68942853905191
+Adata = 00
+CT = 372b9af0655df2d0c830b4949a2d2faa8db251ee922a3bff9aba89639f4033be9ba9f3c101acc1bd
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 0, Nlen = 7, Tlen = 4]
+
+Key = 90929a4b0ac65b350ad1591611fe4829
+
+Count = 120
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = 782e4318
+Result = Pass (0)
+Payload = 00
+
+Count = 121
+Nonce = a265480ca88d5f
+Adata = a2248a882ecbf850daf91933a389e78e81623d233dfd47bf8321361a38f138fe
+CT = a04f270a
+Result = Fail (2 - CT changed)
+
+Count = 122
+Nonce = 87ec7423f1ebfc
+Adata = 2bed1ec06c1ca149d9ffbaf048c474ea2de000eb7950f18d6c25acf6ab3f19b5
+CT = 97dfd257
+Result = Fail (1 - Adata changed)
+
+Count = 123
+Nonce = b8b04f90616082
+Adata = 4898731e143fcc677c7cf1a8f2b3c4039fb5e57028e33b05e097d1763cbfe4d8
+CT = 6c202a1c
+Result = Fail (1 - Adata changed)
+
+Count = 124
+Nonce = 8c687b4318813a
+Adata = fcad52a88544325bb31eb5de4a41dbff6a96f69d0993b969a01792ee23953acf
+CT = 1be535a0
+Result = Pass (0)
+Payload = 00
+
+Count = 125
+Nonce = 29b810eed8fc92
+Adata = 40d1d320eb63a25d7a2b3141563a552114275ddda56beb62cc0c0273d5795faa
+CT = 4fb6617d
+Result = Fail (2 - CT changed)
+
+Count = 126
+Nonce = 62452462c53934
+Adata = 1eb8863ea100babc1713654afcf54f21f8bff754223ad70269ace9d034f26a96
+CT = c056bd3e
+Result = Fail (1 - Adata changed)
+
+Count = 127
+Nonce = 4cceba0e7aee97
+Adata = f33e184c967165eb62542999afaca4e3e319840e439b5bb509544fb4b6901445
+CT = 87048576
+Result = Fail (2 - CT changed)
+
+Count = 128
+Nonce = b5151b0601c683
+Adata = 73d27303ec91f28c79b278882034d11eb6a5266746f37edbb77f8409a8738b8c
+CT = ea8c0407
+Result = Fail (2 - CT changed)
+
+Count = 129
+Nonce = 4e5d6d7ac9e71e
+Adata = a01b6e152fe232b6c10b5d89900961c445f4c46833df242c826678b68c869811
+CT = 41c12dc5
+Result = Fail (1 - Adata changed)
+
+Count = 130
+Nonce = dc88e989951a3f
+Adata = fdcacfaff46585406cc45a2da364e67e132a91c98900a8f9d7bfb14ec951fca5
+CT = de84cf5c
+Result = Fail (1 - Adata changed)
+
+Count = 131
+Nonce = a1aeda4b4cb8dd
+Adata = db3022ef4cd68ae22b501599448ffe2dda15cfd2e259315c6f6d03036edea963
+CT = e617e006
+Result = Pass (0)
+Payload = 00
+
+Count = 132
+Nonce = f248e5225e3d9a
+Adata = fdc64ef76a3bfd0a15d0bc8e8bacaf64346796a3e35afcf2ac1ab136f63f7b6e
+CT = b7909395
+Result = Pass (0)
+Payload = 00
+
+Count = 133
+Nonce = e68228f5c65b73
+Adata = 614efdf89ce2a9fcbd38bdc0b4cece54dfd7532880e0b4ce6eb3a4010b7cb1e7
+CT = 8a05d2ea
+Result = Pass (0)
+Payload = 00
+
+Count = 134
+Nonce = ea167cfd1101d9
+Adata = 28130f938c45a1a92b02dbeadbd8df816b6d934e87cca2dfdbfdc49c7cd84041
+CT = 8643ba47
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 0, Nlen = 7, Tlen = 16]
+
+Key = 6a798d7c5e1a72b43e20ad5c7b08567b
+
+Count = 135
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = 41b476013f45e4a781f253a6f3b1e530
+Result = Pass (0)
+Payload = 00
+
+Count = 136
+Nonce = a265480ca88d5f
+Adata = a2248a882ecbf850daf91933a389e78e81623d233dfd47bf8321361a38f138fe
+CT = f9f018fcd125822616083fffebc4c8e6
+Result = Fail (2 - CT changed)
+
+Count = 137
+Nonce = 87ec7423f1ebfc
+Adata = 2bed1ec06c1ca149d9ffbaf048c474ea2de000eb7950f18d6c25acf6ab3f19b5
+CT = 534cc67c44c877c9c908071ee1082f4c
+Result = Fail (1 - Adata changed)
+
+Count = 138
+Nonce = b8b04f90616082
+Adata = 4898731e143fcc677c7cf1a8f2b3c4039fb5e57028e33b05e097d1763cbfe4d8
+CT = 201c0ef2ddaa51b645911b5c37d76e95
+Result = Fail (1 - Adata changed)
+
+Count = 139
+Nonce = 8c687b4318813a
+Adata = fcad52a88544325bb31eb5de4a41dbff6a96f69d0993b969a01792ee23953acf
+CT = ec774d9000763bba3a5ac307418827b2
+Result = Pass (0)
+Payload = 00
+
+Count = 140
+Nonce = 29b810eed8fc92
+Adata = 40d1d320eb63a25d7a2b3141563a552114275ddda56beb62cc0c0273d5795faa
+CT = 75798c3fe5202f0e33c9183c837aeaf5
+Result = Fail (2 - CT changed)
+
+Count = 141
+Nonce = 62452462c53934
+Adata = 1eb8863ea100babc1713654afcf54f21f8bff754223ad70269ace9d034f26a96
+CT = 32601de5960c11c925444b5c47d42289
+Result = Fail (1 - Adata changed)
+
+Count = 142
+Nonce = 4cceba0e7aee97
+Adata = f33e184c967165eb62542999afaca4e3e319840e439b5bb509544fb4b6901445
+CT = 4c1cd6a774c8e6f4e261db1f73b0aa20
+Result = Fail (2 - CT changed)
+
+Count = 143
+Nonce = b5151b0601c683
+Adata = 73d27303ec91f28c79b278882034d11eb6a5266746f37edbb77f8409a8738b8c
+CT = 8bd9c00ff23310216bbd24981c1e2cf7
+Result = Fail (2 - CT changed)
+
+Count = 144
+Nonce = 4e5d6d7ac9e71e
+Adata = a01b6e152fe232b6c10b5d89900961c445f4c46833df242c826678b68c869811
+CT = 174efd089409f9932b8e631965e762a6
+Result = Fail (1 - Adata changed)
+
+Count = 145
+Nonce = dc88e989951a3f
+Adata = fdcacfaff46585406cc45a2da364e67e132a91c98900a8f9d7bfb14ec951fca5
+CT = 8de80f620bd41eee6a58925dc8404bfa
+Result = Fail (1 - Adata changed)
+
+Count = 146
+Nonce = a1aeda4b4cb8dd
+Adata = db3022ef4cd68ae22b501599448ffe2dda15cfd2e259315c6f6d03036edea963
+CT = 0b9d79e8e33ec45532af5515a99f05df
+Result = Pass (0)
+Payload = 00
+
+Count = 147
+Nonce = f248e5225e3d9a
+Adata = fdc64ef76a3bfd0a15d0bc8e8bacaf64346796a3e35afcf2ac1ab136f63f7b6e
+CT = 1583e1e5a86001bbcec62292ccfd4d48
+Result = Pass (0)
+Payload = 00
+
+Count = 148
+Nonce = e68228f5c65b73
+Adata = 614efdf89ce2a9fcbd38bdc0b4cece54dfd7532880e0b4ce6eb3a4010b7cb1e7
+CT = b72caac6362e68e445f69f605f21e0a2
+Result = Pass (0)
+Payload = 00
+
+Count = 149
+Nonce = ea167cfd1101d9
+Adata = 28130f938c45a1a92b02dbeadbd8df816b6d934e87cca2dfdbfdc49c7cd84041
+CT = 352769a19ac75b8a116be031b33d6449
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 0, Nlen = 13, Tlen = 4]
+
+Key = 6a798d7c5e1a72b43e20ad5c7b08567b
+
+Count = 150
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = 9f69f24f
+Result = Pass (0)
+Payload = 00
+
+Count = 151
+Nonce = 8739b4bea1a099fe547499cbc6
+Adata = f6107696edb332b2ea059d8860fee26be42e5e12e1a4f79a8d0eafce1b2278a7
+CT = e17afaa4
+Result = Fail (2 - CT changed)
+
+Count = 152
+Nonce = 0f98fdbde2b04387f27b3401dd
+Adata = 02010329660fa716556193eb4870ee84bd934296a5c52d92bba859cc13caaddc
+CT = 07155b7e
+Result = Fail (1 - Adata changed)
+
+Count = 153
+Nonce = 4eed58f381e500902ba5c56864
+Adata = 96056d9ebd7c553c22cc2d9d816b61123750d96c1b08c4b661079424bf3c4946
+CT = d538cf2f
+Result = Fail (1 - Adata changed)
+
+Count = 154
+Nonce = 1e7e51f0fa9a33ed618c26f5e3
+Adata = da9b8ffb0f3c2aee2e386cc9f035ec1eb3e629bd1544c11dc21be4fd8ac9074a
+CT = c283466f
+Result = Pass (0)
+Payload = 00
+
+Count = 155
+Nonce = f012f94f5988c79aa179d7fdfc
+Adata = 612b2ef2683109d99452f95099417641d0c2be3f8ab4cbb2a44e83355ba9303c
+CT = aa8d8098
+Result = Fail (2 - CT changed)
+
+Count = 156
+Nonce = 715acf92cfb69ad56036c49e70
+Adata = 960667b85be07304634124b9324be12a1c11451f1fa9db82c683265b4cf8e5ff
+CT = a44b69b0
+Result = Fail (1 - Adata changed)
+
+Count = 157
+Nonce = 141be3601e38185a9fa1596d2e
+Adata = 606452c62290b43559a588bb03356f846cecb0ccaf0bdaf67a18abd811d4315a
+CT = f395733f
+Result = Fail (2 - CT changed)
+
+Count = 158
+Nonce = fcdda3c5f0e80843b03d8788da
+Adata = 03f22247a55461a293d253c77483859fdac1b87c2480e208a3df767cfbfde512
+CT = 1e9e9237
+Result = Fail (2 - CT changed)
+
+Count = 159
+Nonce = ca660ed3b917c0aca140dcd3fb
+Adata = 254a86f5b20d344ad86fd5523d08f1864737be57731440c29aa6b42574572f51
+CT = e9d2a722
+Result = Fail (1 - Adata changed)
+
+Count = 160
+Nonce = 642ae3466661ce1f51783deece
+Adata = 4432a1cec5976cc13b8fb78341d426c2248f091b597123d263ffafc7f82da5a5
+CT = a90fc438
+Result = Fail (1 - Adata changed)
+
+Count = 161
+Nonce = 7864c717ec93db38b10679be47
+Adata = 679aad1ad1e57029e3362b325572fc71cac53184b0f1546867e665a4a59466c4
+CT = 48f3a1ec
+Result = Pass (0)
+Payload = 00
+
+Count = 162
+Nonce = c3bf9dfe9d6c26f543188fb457
+Adata = e301f69ad3a7e08a3d02462f0aa584449eb0449b0e3c50aa8dfaa4472816c8b0
+CT = 24763def
+Result = Pass (0)
+Payload = 00
+
+Count = 163
+Nonce = 1527657d2fd98f7deca55cc649
+Adata = f4c723433b7cafe3cda9bb4940a21a89a8382d13018b622ccd1ffb9ffd3211af
+CT = 63394bee
+Result = Pass (0)
+Payload = 00
+
+Count = 164
+Nonce = b8432d3d5525a0dadbbaa6b6b8
+Adata = 86ee6e37b4a2d9a0b52ec95643b4e8297e237721e15ce8bf7593a98644f83eba
+CT = d79b1686
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 0, Nlen = 13, Tlen = 16]
+
+Key = f9fdca4ac64fe7f014de0f43039c7571
+
+Count = 165
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = 1859ac36a40a6b28b34266253627797a
+Result = Pass (0)
+Payload = 00
+
+Count = 166
+Nonce = 8739b4bea1a099fe547499cbc6
+Adata = f6107696edb332b2ea059d8860fee26be42e5e12e1a4f79a8d0eafce1b2278a7
+CT = edf8b46eb69ac0044116019dec183072
+Result = Fail (2 - CT changed)
+
+Count = 167
+Nonce = 0f98fdbde2b04387f27b3401dd
+Adata = 02010329660fa716556193eb4870ee84bd934296a5c52d92bba859cc13caaddc
+CT = 66622ac26c7227a0329739612012737c
+Result = Fail (1 - Adata changed)
+
+Count = 168
+Nonce = 4eed58f381e500902ba5c56864
+Adata = 96056d9ebd7c553c22cc2d9d816b61123750d96c1b08c4b661079424bf3c4946
+CT = e4c9e86493ee78b1cbf6e55e94731b63
+Result = Fail (1 - Adata changed)
+
+Count = 169
+Nonce = 1e7e51f0fa9a33ed618c26f5e3
+Adata = da9b8ffb0f3c2aee2e386cc9f035ec1eb3e629bd1544c11dc21be4fd8ac9074a
+CT = 8b5bfe6b5b5552007300bae71172612f
+Result = Pass (0)
+Payload = 00
+
+Count = 170
+Nonce = f012f94f5988c79aa179d7fdfc
+Adata = 612b2ef2683109d99452f95099417641d0c2be3f8ab4cbb2a44e83355ba9303c
+CT = 1848be3cb7665ac68874c617a75d8bd2
+Result = Fail (2 - CT changed)
+
+Count = 171
+Nonce = 715acf92cfb69ad56036c49e70
+Adata = 960667b85be07304634124b9324be12a1c11451f1fa9db82c683265b4cf8e5ff
+CT = 65a23b7b5ee78af9c7d0113447f78ab9
+Result = Fail (1 - Adata changed)
+
+Count = 172
+Nonce = 141be3601e38185a9fa1596d2e
+Adata = 606452c62290b43559a588bb03356f846cecb0ccaf0bdaf67a18abd811d4315a
+CT = 90a420b6d2252392e161dcf4fb953d7e
+Result = Fail (2 - CT changed)
+
+Count = 173
+Nonce = fcdda3c5f0e80843b03d8788da
+Adata = 03f22247a55461a293d253c77483859fdac1b87c2480e208a3df767cfbfde512
+CT = 004cbe11292887e246de7704a4a1a05f
+Result = Fail (2 - CT changed)
+
+Count = 174
+Nonce = ca660ed3b917c0aca140dcd3fb
+Adata = 254a86f5b20d344ad86fd5523d08f1864737be57731440c29aa6b42574572f51
+CT = ad7af41e39ea0c0cd072263e826f3cf0
+Result = Fail (1 - Adata changed)
+
+Count = 175
+Nonce = 642ae3466661ce1f51783deece
+Adata = 4432a1cec5976cc13b8fb78341d426c2248f091b597123d263ffafc7f82da5a5
+CT = 16b1a4fadbadc906a949592d6ef319a3
+Result = Fail (1 - Adata changed)
+
+Count = 176
+Nonce = 7864c717ec93db38b10679be47
+Adata = 679aad1ad1e57029e3362b325572fc71cac53184b0f1546867e665a4a59466c4
+CT = e9cfb1069380434f221db4229a083a76
+Result = Pass (0)
+Payload = 00
+
+Count = 177
+Nonce = c3bf9dfe9d6c26f543188fb457
+Adata = e301f69ad3a7e08a3d02462f0aa584449eb0449b0e3c50aa8dfaa4472816c8b0
+CT = 380cb57fd531bb1dcf22350518bbf8af
+Result = Pass (0)
+Payload = 00
+
+Count = 178
+Nonce = 1527657d2fd98f7deca55cc649
+Adata = f4c723433b7cafe3cda9bb4940a21a89a8382d13018b622ccd1ffb9ffd3211af
+CT = fbf2becc35b5024078bfcfc1f831b669
+Result = Pass (0)
+Payload = 00
+
+Count = 179
+Nonce = b8432d3d5525a0dadbbaa6b6b8
+Adata = 86ee6e37b4a2d9a0b52ec95643b4e8297e237721e15ce8bf7593a98644f83eba
+CT = 080203eb842b3f98a730abbbf98f493e
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 24, Nlen = 7, Tlen = 4]
+
+Key = f9fdca4ac64fe7f014de0f43039c7571
+
+Count = 180
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = 6be31860ca271ef448de8f8d8b39346daf4b81d7e92d65b338f125fa
+Result = Pass (0)
+Payload = a265480ca88d5f536db0dc6abc40faf0d05be7a966977768
+
+Count = 181
+Nonce = fdd2d6f503c915
+Adata = 5b92394f21ddc3ad49d9b0881b829a5935cb3a4d23e292a62fb66b5e7ab7020e
+CT = 4cc57a9927a6bc401441870d3193bf89ebd163f5c01501c728a66b69
+Result = Fail (2 - CT changed)
+
+Count = 182
+Nonce = 27d73d58100054
+Adata = f6468542923be79b4b06dfe70920d57d1da73a9c16f9c9a12d810d7de0d12467
+CT = 1f16c6d370fff40c011a243356076b67e905d4672ae2f38fee2de18c
+Result = Fail (1 - Adata changed)
+
+Count = 183
+Nonce = dd16e0ce1250e3
+Adata = bc65cfd65e9863c8b7457d58afa6bdb48a84170d8aa97ba5b397b52ad17a9242
+CT = 46edb001d58a01dce1bcf064cfc9a04accc82c42b33ba16524537a81
+Result = Fail (1 - Adata changed)
+
+Count = 184
+Nonce = ccee19d037cf4a
+Adata = c026696e6425e6c33f45b4145febf1137e7ac26383c9f5aa4cd4e5e8abb19e07
+CT = 9b61335f96fc5b31274cc1fb275f29c1105d68c67b70654f9405edb1
+Result = Pass (0)
+Payload = 0df202431ee7f251a38aaf6aa8cd313782bd293af9114005
+
+Count = 185
+Nonce = 6c8ba94f09cbe6
+Adata = 774ad1a88f8bb063951486d4aec5bf82d5fc535bd0b952f86200c123c37fa496
+CT = 97b5eb2d55847f5d5d9f8c762dace481d8efb19ccfd72265548effe3
+Result = Fail (2 - CT changed)
+
+Count = 186
+Nonce = 1f670302fcdcc8
+Adata = 1a9ff9698cfc96b581d7115c822e4363d7355ec5daed2eae5bf89ee944ac7d9c
+CT = f5cc8198dce8e890587b62572b07413a915bfb55628c901c03459b29
+Result = Fail (1 - Adata changed)
+
+Count = 187
+Nonce = 5d05f658c729a2
+Adata = dd9564c1431ed490b17ef69f6115805e54ef156ef4e10e58f7d57a7e86626352
+CT = 50c0b1f6c5e4c86a0c938ecbc762eeaf99b9fe04c2820a43963b04f3
+Result = Fail (2 - CT changed)
+
+Count = 188
+Nonce = 22a77db9fcbc95
+Adata = 86bf1739c10f63df734ee3e60ac40ff5636c49f68ca4c16ece289609eb413e7a
+CT = 1fdbe91189da01c5098cf1538addd85b1cfef0abd0797c141330f633
+Result = Fail (2 - CT changed)
+
+Count = 189
+Nonce = 491e32b0bbfa4c
+Adata = 75bef075c79d6cfd7fc73aefd67b2d215be0648937477ba606b1fe1be591239e
+CT = 462e7cdf9a6a553bca37d4d93bed4986b715d0349238613e10c1f6d7
+Result = Fail (1 - Adata changed)
+
+Count = 190
+Nonce = bc4b7d3a380be0
+Adata = 353dbb41e2d525a9f4fcd858d0f0aa1b1e86ac0f936d5c09c6b61c343f94e3fc
+CT = 7d142f26aa6c9d55850c5c9f58ab36a66670d47c515bf93cd37e5543
+Result = Fail (1 - Adata changed)
+
+Count = 191
+Nonce = a840e98df72ae9
+Adata = 22c6607732ef1bdc7fcf6197e037cdadd7ee17c008552dd9f04b8564d34fb17c
+CT = f7122cbcec93d53fc7e3fc629ea15d28363cad1c83a23bb3cc5e0c4a
+Result = Pass (0)
+Payload = a2f53385618b41301f4e3ea4c597f411103dac2b37abf5da
+
+Count = 192
+Nonce = 39d93c3cf31a6f
+Adata = 937dfac5cded938438f4e97aabd9beb50dba40f824198260a89729479cfe6869
+CT = e1cad7f946b20c373323218c8a89e56edf3030662e50d459fc12a512
+Result = Pass (0)
+Payload = c1bdef96dc868446be48491b160504546f2a40dd581f9582
+
+Count = 193
+Nonce = 0bbc177019321e
+Adata = f6e02678820f5ccbede6cbded02d6dd58d486166d7b18ee975a688af421fb795
+CT = d4741814466a23e26107d773f103a4c83db9d772dbd5fdc1c2eaf895
+Result = Pass (0)
+Payload = 72a70954d22ad722fc32756afce67b344b2f3c55fe1d9eed
+
+Count = 194
+Nonce = ad048eb2ad7526
+Adata = 0d2739cfdac782b61f484fa1a423c478c414397ec420327963d79112b2d70a7e
+CT = ed35ff66bc7f6d8ec7acf896f994d79f5792cf6d22d6691ff92fa2f7
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 24, Nlen = 7, Tlen = 16]
+
+Key = a7aa635ea51b0bb20a092bd5573e728c
+
+Count = 195
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = b351ab96b2e45515254558d5212673ee6c776d42dbca3b512cf3a20b7fd7c49e6e79bef475c2906f
+Result = Pass (0)
+Payload = a265480ca88d5f536db0dc6abc40faf0d05be7a966977768
+
+Count = 196
+Nonce = fdd2d6f503c915
+Adata = 5b92394f21ddc3ad49d9b0881b829a5935cb3a4d23e292a62fb66b5e7ab7020e
+CT = df1a5285caa41b4bb47f6e5ceceba4e82721828d68427a3081d18ca149d6766bfaccec88f194eb5b
+Result = Fail (2 - CT changed)
+
+Count = 197
+Nonce = 27d73d58100054
+Adata = f6468542923be79b4b06dfe70920d57d1da73a9c16f9c9a12d810d7de0d12467
+CT = 04a29fc109dfc626e8297e0f586d0bfaf31260017d95f62d5eb4f0875dda5ccd9b94026ba49fb34e
+Result = Fail (1 - Adata changed)
+
+Count = 198
+Nonce = dd16e0ce1250e3
+Adata = bc65cfd65e9863c8b7457d58afa6bdb48a84170d8aa97ba5b397b52ad17a9242
+CT = 77e4cd5d319353ecb6b89e2de14bcfee4fbf738b61df14f3920843994def41aed3103995d3392eed
+Result = Fail (1 - Adata changed)
+
+Count = 199
+Nonce = ccee19d037cf4a
+Adata = c026696e6425e6c33f45b4145febf1137e7ac26383c9f5aa4cd4e5e8abb19e07
+CT = e676f5dfde8ad810d9e729d142670eef77f2878369a28797d57603d5c45606c68be5535c671d5432
+Result = Pass (0)
+Payload = 0df202431ee7f251a38aaf6aa8cd313782bd293af9114005
+
+Count = 200
+Nonce = 6c8ba94f09cbe6
+Adata = 774ad1a88f8bb063951486d4aec5bf82d5fc535bd0b952f86200c123c37fa496
+CT = 60c51e5c3fe4197454d64fa14017639bcfd1423b9d74e506a0bfd54fb786208e1e49c6d0e645d9fb
+Result = Fail (2 - CT changed)
+
+Count = 201
+Nonce = 1f670302fcdcc8
+Adata = 1a9ff9698cfc96b581d7115c822e4363d7355ec5daed2eae5bf89ee944ac7d9c
+CT = 64d1160365062eca1027cc7036862b027bdda3a9abdf794daf8a9b7a5c50b0be4596290a4d405e79
+Result = Fail (1 - Adata changed)
+
+Count = 202
+Nonce = 5d05f658c729a2
+Adata = dd9564c1431ed490b17ef69f6115805e54ef156ef4e10e58f7d57a7e86626352
+CT = 968ca115583c645710d2b47fb196cf55f6ef33f2b01400e22ce9c776932ecf7fddd849be58096b88
+Result = Fail (2 - CT changed)
+
+Count = 203
+Nonce = 22a77db9fcbc95
+Adata = 86bf1739c10f63df734ee3e60ac40ff5636c49f68ca4c16ece289609eb413e7a
+CT = 4985821b16ff6d4d3416573e2fba4d53186d912f0b023a99915d0020da92f483a5a7914cba14b1e7
+Result = Fail (2 - CT changed)
+
+Count = 204
+Nonce = 491e32b0bbfa4c
+Adata = 75bef075c79d6cfd7fc73aefd67b2d215be0648937477ba606b1fe1be591239e
+CT = c7345b031ef85bde766226a7603adaa7dcb07a7b2a8be1b571420e036ea48dddd671be622d372c5b
+Result = Fail (1 - Adata changed)
+
+Count = 205
+Nonce = bc4b7d3a380be0
+Adata = 353dbb41e2d525a9f4fcd858d0f0aa1b1e86ac0f936d5c09c6b61c343f94e3fc
+CT = 11460b9acccc13001be236814da6b73f2c8e0467574f151bb619a331f8d67d70c3f3a59b3fab53a5
+Result = Fail (1 - Adata changed)
+
+Count = 206
+Nonce = a840e98df72ae9
+Adata = 22c6607732ef1bdc7fcf6197e037cdadd7ee17c008552dd9f04b8564d34fb17c
+CT = 1bcff940a2d9d48e93bbfd13aed5947237485983e6ae04b8b944bb46306a9b1e783f3e54c92d5f5e
+Result = Pass (0)
+Payload = a2f53385618b41301f4e3ea4c597f411103dac2b37abf5da
+
+Count = 207
+Nonce = 39d93c3cf31a6f
+Adata = 937dfac5cded938438f4e97aabd9beb50dba40f824198260a89729479cfe6869
+CT = 3b6c1570c85f297079be14cd66d335251c7b52e131a636f148608963f3037763843b70c35d7011f8
+Result = Pass (0)
+Payload = c1bdef96dc868446be48491b160504546f2a40dd581f9582
+
+Count = 208
+Nonce = 0bbc177019321e
+Adata = f6e02678820f5ccbede6cbded02d6dd58d486166d7b18ee975a688af421fb795
+CT = b540cd8cbe733e0ca2ba2112ea785596d2c1d707f41608514ba2d0944c68cc36d4125b3ef9071d69
+Result = Pass (0)
+Payload = 72a70954d22ad722fc32756afce67b344b2f3c55fe1d9eed
+
+Count = 209
+Nonce = ad048eb2ad7526
+Adata = 0d2739cfdac782b61f484fa1a423c478c414397ec420327963d79112b2d70a7e
+CT = 3c9c1481f1428acf202b510dca67e5e6b2abc5dd71a954da51387922af7182b7d46a33c703e6e7a8
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 24, Nlen = 13, Tlen = 4]
+
+Key = a7aa635ea51b0bb20a092bd5573e728c
+
+Count = 210
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = 934f893824e880f743d196b22d1f340a52608155087bd28ac25e5329
+Result = Pass (0)
+Payload = 8739b4bea1a099fe547499cbc6d1b13d849b8084c9b6acc5
+
+Count = 211
+Nonce = 0812757ad0cc4d17c4cfe7a642
+Adata = ec6c44a7e94e51a3ca6dee229098391575ec7213c85267fbf7492fdbeee61b10
+CT = f43ba9d834ad85dfab3f1c0c27c3441fe4e411a38a261a6559b3b3ee
+Result = Fail (2 - CT changed)
+
+Count = 212
+Nonce = eff510acc1b85f35029cf7dc00
+Adata = 0923b927b8295c5dfaf67da55e5014293bc8c708fda50af06c1e8aef31cccc86
+CT = c686eac859a7bae3cce97d0b6527a0a7c8c2b24ece35f4370bf6688e
+Result = Fail (1 - Adata changed)
+
+Count = 213
+Nonce = 3d13d09057190366c63c8750e9
+Adata = 77e27aa9a7bf30e130c862a3296a1cd7a10195ed1d940f2c97bfff47c6f06e32
+CT = 2b28355ecf7246ddb08d65c464dcaa90af85f434ff95267280ed869c
+Result = Fail (1 - Adata changed)
+
+Count = 214
+Nonce = e3c03ef7e1d31961ee0b97bd99
+Adata = 8a3676dd640821b58fb0f0329855fd5882c376ea166b958b7aaad223054e5784
+CT = ecde42091baa1f5c17b79746e21c3de5c78984570748021ccd399507
+Result = Pass (0)
+Payload = 92973ce707733a73118c8ce6b5e3fc77a17f448310c0197f
+
+Count = 215
+Nonce = 5d165ddd4e599387af5967cae6
+Adata = e374f875ce829b62c98fbd67bcf128b5647f25fff9a643300eb95559b889baed
+CT = 5c338435ed4f148342604c9aed63e907c100453d719fda2a3da37b66
+Result = Fail (2 - CT changed)
+
+Count = 216
+Nonce = fcec171162a27a96066181fab2
+Adata = cf431cc3671ec468ea86f6cc09842fcf3a84b3ef0fa1c7b20b232145b4469d62
+CT = 30eac1042015eb82729673edd9939bf9995b2575da4d6c4c7e75dded
+Result = Fail (1 - Adata changed)
+
+Count = 217
+Nonce = 2fa8120398d1a946f391367cf6
+Adata = 92558a239c8e13230754f23aec67b153db29fdfc7daf641778185dd2931d89da
+CT = ebd3ce55b40e4bbd8172033948c6c78049161ee8f949eb50722b9c87
+Result = Fail (2 - CT changed)
+
+Count = 218
+Nonce = 88e0ae338bbca9d4299b294354
+Adata = 5db5c388dbadc9f175a5cd5a1472a458d25acd7fb9c951c0cd45edf64da473bb
+CT = 20f79b36ca83baac97600fd8a6dad22c2cd0f9b7e770576048c042e5
+Result = Fail (2 - CT changed)
+
+Count = 219
+Nonce = 4862e36296d6afc9399a95bbb4
+Adata = 36d82ebd0e0f5fe3b12946d041ae5aee16e6d17025406dd776f499bbd8e8b4c8
+CT = 77b76f249f936fb19bd47fe28ad4dbb7725dec365a1cb23a885ba975
+Result = Fail (1 - Adata changed)
+
+Count = 220
+Nonce = 2f360a4715074e942244ab7f9b
+Adata = f0087b0086a081c1071481f033a8be8e940c36763084329bb8461b9102238f4f
+CT = cf6763a23c2eab730845d1eb79bbba9f54ee899fe3d70570aa799e79
+Result = Fail (1 - Adata changed)
+
+Count = 221
+Nonce = 93e08854560edb096e5d654086
+Adata = bdc60dff08bfd5d44320b75c61e456fd4333c9c3d0294d4a48d936dfd5922ce2
+CT = 1f8086a43c1b2dea557952db88e0dbbdb96aafdb345eddae6c0b0104
+Result = Pass (0)
+Payload = 569e4aec88dd51ca519c0a00c922ee33d3559b98a32d7906
+
+Count = 222
+Nonce = e3f37b68ff508cfe295441d9e3
+Adata = b2b6c5782e4f128467c589d2a6cf55ef12877adb771bbb6245c5bba9dcfd6208
+CT = c0c5f92285b114e0a0777e1bc22b810e7cc4f68c28cd5ce047a28dd8
+Result = Pass (0)
+Payload = 02b5511204bd55f7c37973e26f6df5883c0a530f07c7f8c2
+
+Count = 223
+Nonce = ea98ec44f5a86715014783172e
+Adata = e4692b9f06b666c7451b146c8aeb07a6e30c629d28065c3dde5940325b14b810
+CT = 56327f4db9c18f72bbefc3f316d31f9795dd77f493385ab7b7543552
+Result = Pass (0)
+Payload = 4da40b80579c1d9a5309f7efecb7c059a2f914511ca5fc10
+
+Count = 224
+Nonce = 5a16a8902bd70fa06cfe184c57
+Adata = 399d6b0652836457ec4f701f0dc0e5aed73d16585d61cb1bb5b7ee824fc287c8
+CT = 37d5b17995fac8c94302ec9ba20a36d97678e85199b677f8ee39867e
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 24, Nlen = 13, Tlen = 16]
+
+Key = 26511fb51fcfa75cb4b44da75a6e5a0e
+
+Count = 225
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = 50038b5fdd364ee747b70d00bd36840ece4ea19998123375c0a458bfcafa3b2609afe0f825cbf503
+Result = Pass (0)
+Payload = 8739b4bea1a099fe547499cbc6d1b13d849b8084c9b6acc5
+
+Count = 226
+Nonce = 0812757ad0cc4d17c4cfe7a642
+Adata = ec6c44a7e94e51a3ca6dee229098391575ec7213c85267fbf7492fdbeee61b10
+CT = 78ed8ff6b5a1255d0fbd0a719a9c27b059ff5f83d0c4962c390042ba8bb5f6798dab01c5afad7306
+Result = Fail (2 - CT changed)
+
+Count = 227
+Nonce = eff510acc1b85f35029cf7dc00
+Adata = 0923b927b8295c5dfaf67da55e5014293bc8c708fda50af06c1e8aef31cccc86
+CT = 4b91d8e616d3f60452fd3a576bd7c265b7f549523ed4a5d7a3463394cf3c25bef8af8f244d0c0b00
+Result = Fail (1 - Adata changed)
+
+Count = 228
+Nonce = 3d13d09057190366c63c8750e9
+Adata = 77e27aa9a7bf30e130c862a3296a1cd7a10195ed1d940f2c97bfff47c6f06e32
+CT = ab8cf8891ab62924c0c6f49dd253cfa0c3d6260d0ee4d9ba88caf8ae59d9d1131626da0dddf8722d
+Result = Fail (1 - Adata changed)
+
+Count = 229
+Nonce = e3c03ef7e1d31961ee0b97bd99
+Adata = 8a3676dd640821b58fb0f0329855fd5882c376ea166b958b7aaad223054e5784
+CT = c6b7680f321132a8bd00e8e92f785d0b828b100af6392a04d1292373a76970eda77a8194f6276262
+Result = Pass (0)
+Payload = 92973ce707733a73118c8ce6b5e3fc77a17f448310c0197f
+
+Count = 230
+Nonce = 5d165ddd4e599387af5967cae6
+Adata = e374f875ce829b62c98fbd67bcf128b5647f25fff9a643300eb95559b889baed
+CT = aea98867d3d707c43a963c1d7fdcfc953cbd707803b2b5f0a97af19d0b7bf7c7ce398cb0b44d73af
+Result = Fail (2 - CT changed)
+
+Count = 231
+Nonce = fcec171162a27a96066181fab2
+Adata = cf431cc3671ec468ea86f6cc09842fcf3a84b3ef0fa1c7b20b232145b4469d62
+CT = c55e17ba7886eb58126d50bde8c5c211cc1aafd71a3d9e5b343065b4bdd973ee072dbf5160d310f3
+Result = Fail (1 - Adata changed)
+
+Count = 232
+Nonce = 2fa8120398d1a946f391367cf6
+Adata = 92558a239c8e13230754f23aec67b153db29fdfc7daf641778185dd2931d89da
+CT = 791a62d5fb39ff9735ad94507e1afe2647714d5cc56b6ff4233ec600bca1d31f704807494fb0f18d
+Result = Fail (2 - CT changed)
+
+Count = 233
+Nonce = 88e0ae338bbca9d4299b294354
+Adata = 5db5c388dbadc9f175a5cd5a1472a458d25acd7fb9c951c0cd45edf64da473bb
+CT = f98a081998e29500f15ebd8978a95423aed4e8e78e0279d17ec183db0e2a33ebb147d0e2363fbb01
+Result = Fail (2 - CT changed)
+
+Count = 234
+Nonce = 4862e36296d6afc9399a95bbb4
+Adata = 36d82ebd0e0f5fe3b12946d041ae5aee16e6d17025406dd776f499bbd8e8b4c8
+CT = 7779814dc295a23b4100ca94bec0ad4ce2f6be6fb75a0c217e67ea2577ade5836c26a89760e0959b
+Result = Fail (1 - Adata changed)
+
+Count = 235
+Nonce = 2f360a4715074e942244ab7f9b
+Adata = f0087b0086a081c1071481f033a8be8e940c36763084329bb8461b9102238f4f
+CT = 55640eed12c7595a36ab423da8d8241905b6ff1e906db9624978a7865df8369635269411b3aaeb32
+Result = Fail (1 - Adata changed)
+
+Count = 236
+Nonce = 93e08854560edb096e5d654086
+Adata = bdc60dff08bfd5d44320b75c61e456fd4333c9c3d0294d4a48d936dfd5922ce2
+CT = 7fcdce0ba567b9a708d54fdb16125de71dce952f4741684f4f9d302e4f1d2a2aedf2768d7b29163f
+Result = Pass (0)
+Payload = 569e4aec88dd51ca519c0a00c922ee33d3559b98a32d7906
+
+Count = 237
+Nonce = e3f37b68ff508cfe295441d9e3
+Adata = b2b6c5782e4f128467c589d2a6cf55ef12877adb771bbb6245c5bba9dcfd6208
+CT = d42111ba22987eac1ead5cc6cb8548bcda190d118dcd5461a50036af67fadab163e9daa8bd8e9030
+Result = Pass (0)
+Payload = 02b5511204bd55f7c37973e26f6df5883c0a530f07c7f8c2
+
+Count = 238
+Nonce = ea98ec44f5a86715014783172e
+Adata = e4692b9f06b666c7451b146c8aeb07a6e30c629d28065c3dde5940325b14b810
+CT = 1bf0ba0ebb20d8edba59f29a9371750c9c714078f73c335d2f1322ac69b848b001476323aed84c47
+Result = Pass (0)
+Payload = 4da40b80579c1d9a5309f7efecb7c059a2f914511ca5fc10
+
+Count = 239
+Nonce = 5a16a8902bd70fa06cfe184c57
+Adata = 399d6b0652836457ec4f701f0dc0e5aed73d16585d61cb1bb5b7ee824fc287c8
+CT = 9d993b945476ace0b9ca932963ac8835e1bd02e8065da2d816786c4d8cf14c03b031ff723311b3c4
+Result = Fail (2 - CT changed)
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT192.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT192.rsp
new file mode 100644
index 0000000000..e0978a99ac
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT192.rsp
@@ -0,0 +1,1589 @@
+# CAVS 11.0
+# "CCM-DVPT" information
+# AES Keylen: 192
+# Generated on Tue Mar 15 08:09:25 2011
+
+
+[Alen = 0, Plen = 0, Nlen = 7, Tlen = 4]
+
+Key = c98ad7f38b2c7e970c9b965ec87a08208384718f78206c6c
+
+Count = 0
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = 9d4b7f3b
+Result = Pass
+Payload = 00
+
+Count = 1
+Nonce = 3796cf51b87266
+Adata = 00
+CT = 80745de9
+Result = Fail
+
+Count = 2
+Nonce = 89ca5a64050f9f
+Adata = 00
+CT = 2f6fa823
+Result = Fail
+
+Count = 3
+Nonce = ec9d8edff25645
+Adata = 00
+CT = 3cc132c6
+Result = Fail
+
+Count = 4
+Nonce = 05e16f0f42a6f4
+Adata = 00
+CT = c79d5557
+Result = Pass
+Payload = 00
+
+Count = 5
+Nonce = 2e504b694f8df5
+Adata = 00
+CT = 41e0eea0
+Result = Fail
+
+Count = 6
+Nonce = 06d102a9328863
+Adata = 00
+CT = 1f129266
+Result = Fail
+
+Count = 7
+Nonce = c288b810fb5334
+Adata = 00
+CT = 41b0e4e2
+Result = Fail
+
+Count = 8
+Nonce = 08a166d9eb6610
+Adata = 00
+CT = 5082e06a
+Result = Fail
+
+Count = 9
+Nonce = 4a5810b121c91b
+Adata = 00
+CT = 70587cce
+Result = Fail
+
+Count = 10
+Nonce = 44077341139bf9
+Adata = 00
+CT = 6aaa0acd
+Result = Fail
+
+Count = 11
+Nonce = a9df4f37847e1f
+Adata = 00
+CT = 22976e42
+Result = Pass
+Payload = 00
+
+Count = 12
+Nonce = 11df57fcd131e9
+Adata = 00
+CT = f440ea1d
+Result = Pass
+Payload = 00
+
+Count = 13
+Nonce = 890fff56d10dc0
+Adata = 00
+CT = 88903fb9
+Result = Pass
+Payload = 00
+
+Count = 14
+Nonce = 9dc18698731b27
+Adata = 00
+CT = 3ff345c3
+Result = Fail
+
+[Alen = 0, Plen = 0, Nlen = 7, Tlen = 16]
+
+Key = 4bb3c4a4f893ad8c9bdc833c325d62b3d3ad1bccf9282a65
+
+Count = 15
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = 17223038fa99d53681ca1beabe78d1b4
+Result = Pass
+Payload = 00
+
+Count = 16
+Nonce = 3796cf51b87266
+Adata = 00
+CT = d0e1eeef4d2a264536bb1c2c1bde7c35
+Result = Fail
+
+Count = 17
+Nonce = 89ca5a64050f9f
+Adata = 00
+CT = 81d587f8673fd514c23172af7fb7523d
+Result = Fail
+
+Count = 18
+Nonce = ec9d8edff25645
+Adata = 00
+CT = 500142447e535207899ab1499994daea
+Result = Fail
+
+Count = 19
+Nonce = 05e16f0f42a6f4
+Adata = 00
+CT = fdfdbb38bf161785114f9ee2018e892f
+Result = Pass
+Payload = 00
+
+Count = 20
+Nonce = 2e504b694f8df5
+Adata = 00
+CT = 38fe9622eaa2a50152cf57e393dd3063
+Result = Fail
+
+Count = 21
+Nonce = 06d102a9328863
+Adata = 00
+CT = 73af4b87c167572e1400a0ee28209aff
+Result = Fail
+
+Count = 22
+Nonce = c288b810fb5334
+Adata = 00
+CT = ace2248b9f23efa813449c82217e4a4a
+Result = Fail
+
+Count = 23
+Nonce = 08a166d9eb6610
+Adata = 00
+CT = a9bb0e469829d9cf09ad765c5b0b58bf
+Result = Fail
+
+Count = 24
+Nonce = 4a5810b121c91b
+Adata = 00
+CT = a5977f0826926ec0d32541b2bd4e2b1e
+Result = Fail
+
+Count = 25
+Nonce = 44077341139bf9
+Adata = 00
+CT = 6938fb5afec1a84e4abb062e1a943c20
+Result = Fail
+
+Count = 26
+Nonce = a9df4f37847e1f
+Adata = 00
+CT = 7e3bbe0eb13988a93972f2fbcd35659e
+Result = Pass
+Payload = 00
+
+Count = 27
+Nonce = 11df57fcd131e9
+Adata = 00
+CT = 48d7a15cf4f5808eb45d1ad817470554
+Result = Pass
+Payload = 00
+
+Count = 28
+Nonce = 890fff56d10dc0
+Adata = 00
+CT = 97185ce68af1e6ab718c8c4b83ec04cd
+Result = Pass
+Payload = 00
+
+Count = 29
+Nonce = 9dc18698731b27
+Adata = 00
+CT = a81bc8f5a18293ffe19505a3687ce3f3
+Result = Fail
+
+[Alen = 0, Plen = 0, Nlen = 13, Tlen = 4]
+
+Key = 4bb3c4a4f893ad8c9bdc833c325d62b3d3ad1bccf9282a65
+
+Count = 30
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = fe69ed84
+Result = Pass
+Payload = 00
+
+Count = 31
+Nonce = a16a2e741f1cd9717285b6d882
+Adata = 00
+CT = db7ffc82
+Result = Fail
+
+Count = 32
+Nonce = 368f3b8180fd4b851b7b272cb1
+Adata = 00
+CT = 7a677329
+Result = Fail
+
+Count = 33
+Nonce = 7bb2bc00c0cafce65b5299ae64
+Adata = 00
+CT = d903d8f7
+Result = Fail
+
+Count = 34
+Nonce = 935c1ef3d4032ff090f91141f3
+Adata = 00
+CT = 215e0bf2
+Result = Pass
+Payload = 00
+
+Count = 35
+Nonce = 2640b14f10b116411d1b5c1ad1
+Adata = 00
+CT = 0d38100f
+Result = Fail
+
+Count = 36
+Nonce = b229c173a13b2d83af91ec45b0
+Adata = 00
+CT = 9f8ab5f7
+Result = Fail
+
+Count = 37
+Nonce = 37ca0dc2d6efd9efde69f14f03
+Adata = 00
+CT = 7d811d50
+Result = Fail
+
+Count = 38
+Nonce = 6b6238aed86d677ba2b3e2622c
+Adata = 00
+CT = c2e18439
+Result = Fail
+
+Count = 39
+Nonce = d6cb2ac67bb13b8f6d31fad64a
+Adata = 00
+CT = d8b5817b
+Result = Fail
+
+Count = 40
+Nonce = 32a7cd361ef00e65f5778fdfd4
+Adata = 00
+CT = 28cd70ff
+Result = Fail
+
+Count = 41
+Nonce = d0a1508fdefcf5be30a459b813
+Adata = 00
+CT = 790b2624
+Result = Pass
+Payload = 00
+
+Count = 42
+Nonce = 5381a61b449dc6a42aa4c79b95
+Adata = 00
+CT = 9e46632d
+Result = Pass
+Payload = 00
+
+Count = 43
+Nonce = c55430f2da0687ea40313884ab
+Adata = 00
+CT = 39b82901
+Result = Pass
+Payload = 00
+
+Count = 44
+Nonce = ec76d1850acc0979a1f11906fb
+Adata = 00
+CT = 4c0cf71f
+Result = Fail
+
+[Alen = 0, Plen = 0, Nlen = 13, Tlen = 16]
+
+Key = 19ebfde2d5468ba0a3031bde629b11fd4094afcb205393fa
+
+Count = 45
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = 0c66a8e547ed4f8c2c9a9a1eb5d455b9
+Result = Pass
+Payload = 00
+
+Count = 46
+Nonce = a16a2e741f1cd9717285b6d882
+Adata = 00
+CT = 38757b3a61a4dc97ca3ab88bf1240695
+Result = Fail
+
+Count = 47
+Nonce = 368f3b8180fd4b851b7b272cb1
+Adata = 00
+CT = 11875da4445d92391d0fab5f3625497b
+Result = Fail
+
+Count = 48
+Nonce = 7bb2bc00c0cafce65b5299ae64
+Adata = 00
+CT = 64477bcd4316e5c5789e1a678fdef943
+Result = Fail
+
+Count = 49
+Nonce = 935c1ef3d4032ff090f91141f3
+Adata = 00
+CT = 87da5dbc04e39fc468f43675d4e7df33
+Result = Pass
+Payload = 00
+
+Count = 50
+Nonce = 2640b14f10b116411d1b5c1ad1
+Adata = 00
+CT = bf0d53ee529d8cafc5ad7a8f2d85e7a2
+Result = Fail
+
+Count = 51
+Nonce = b229c173a13b2d83af91ec45b0
+Adata = 00
+CT = 676370637ad78c705d43fce066dc909f
+Result = Fail
+
+Count = 52
+Nonce = 37ca0dc2d6efd9efde69f14f03
+Adata = 00
+CT = 289936db0f9f148a3c9e2d28f7d7de51
+Result = Fail
+
+Count = 53
+Nonce = 6b6238aed86d677ba2b3e2622c
+Adata = 00
+CT = 58a283641627669d5514f2af559b6c14
+Result = Fail
+
+Count = 54
+Nonce = d6cb2ac67bb13b8f6d31fad64a
+Adata = 00
+CT = a6b058540ed905d6e3499a13ea1f3d83
+Result = Fail
+
+Count = 55
+Nonce = 32a7cd361ef00e65f5778fdfd4
+Adata = 00
+CT = 7a19b3377384f09915d0e1ae93a9f16c
+Result = Fail
+
+Count = 56
+Nonce = d0a1508fdefcf5be30a459b813
+Adata = 00
+CT = a0d047a1f9940d325e474da54aa13897
+Result = Pass
+Payload = 00
+
+Count = 57
+Nonce = 5381a61b449dc6a42aa4c79b95
+Adata = 00
+CT = 8a4768a2093694b6bcb7083c0bb6331c
+Result = Pass
+Payload = 00
+
+Count = 58
+Nonce = c55430f2da0687ea40313884ab
+Adata = 00
+CT = a7cafd6f68dc1f15a3603da654ce27bc
+Result = Pass
+Payload = 00
+
+Count = 59
+Nonce = ec76d1850acc0979a1f11906fb
+Adata = 00
+CT = c49845f2ea3c9981ad7e9b942f615b8d
+Result = Fail
+
+[Alen = 0, Plen = 24, Nlen = 7, Tlen = 4]
+
+Key = 19ebfde2d5468ba0a3031bde629b11fd4094afcb205393fa
+
+Count = 60
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = 411986d04d6463100bff03f7d0bde7ea2c3488784378138cddc93a54
+Result = Pass
+Payload = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22
+
+Count = 61
+Nonce = 31f8fa25827d48
+Adata = 00
+CT = 32b649ab56162e55d4148a1292d6a225a988eb1308298273b6889036
+Result = Fail
+
+Count = 62
+Nonce = 5340ed7752c9ff
+Adata = 00
+CT = a963c3568ab413b174cd95cc1e3ca61ee181292bebdb28179b4de35f
+Result = Fail
+
+Count = 63
+Nonce = 9cbce402511b89
+Adata = 00
+CT = 0396e6c8db43e5fac205f4c576fd577368adcb688cf3d7e76df9ffc5
+Result = Fail
+
+Count = 64
+Nonce = 123a0beace4e39
+Adata = 00
+CT = b41bfba94edcafc41b4c144269b9126a6d47b19e83b15772b28c8e38
+Result = Pass
+Payload = 9d033e3b66efed1467868f382417c80594877a28bc97f406
+
+Count = 65
+Nonce = 8ea1594a58fe4a
+Adata = 00
+CT = 01e3bb938e16d0284d1d0fee049d80fb97356ae4d84127cf7336a30a
+Result = Fail
+
+Count = 66
+Nonce = 5a7743e59e82da
+Adata = 00
+CT = abd7551c5e84e9bef5fbfad3e24d13f02864410eae9177ad0c40cc72
+Result = Fail
+
+Count = 67
+Nonce = f477f754d7ee76
+Adata = 00
+CT = 3b5ae49e0974f41826152432b46f1a85ab4995afefbbccddfc9fd290
+Result = Fail
+
+Count = 68
+Nonce = 040a257dede70e
+Adata = 00
+CT = 21fb4324de4ba1e2762b3041ce26e43a3d191458a046d489e485910b
+Result = Fail
+
+Count = 69
+Nonce = dd51b8e91683d1
+Adata = 00
+CT = 99ca8f542fd06481e23719214c9892442f393d72899deea08695053f
+Result = Fail
+
+Count = 70
+Nonce = ab3cb86cca6fb2
+Adata = 00
+CT = 5fcc05342cdc27f66b324ae7387205bfb4ab6302bfe0af09050d2054
+Result = Fail
+
+Count = 71
+Nonce = f67b98efd39b55
+Adata = 00
+CT = 0a7fe63046daf8a979935b897088c64acc1b47a5a9b86fdd6def28ab
+Result = Pass
+Payload = f2e944e1ae47ad5873bf391f1b0cc07f6151eb4c50bb45b2
+
+Count = 72
+Nonce = e60e2c002d1c99
+Adata = 00
+CT = daf7d7dfa512ceb1d7d3435634d9a70b3ef6c6dc38f409e068941fce
+Result = Pass
+Payload = 70f48dc1d76e5028da07e29852801375a9edb2214a5ea4c0
+
+Count = 73
+Nonce = 098e053fa08043
+Adata = 00
+CT = cdb417dff6502208775f21e35cdb8e3e1199308d1a94229051a1ec4a
+Result = Pass
+Payload = bd81680e3dc0b35431c92598dcaa26ef09ca0da5e77193de
+
+Count = 74
+Nonce = 4bf48328725514
+Adata = 00
+CT = e75441093c8ccba6eac5913dc246ce96de4784a01051498298eaddaf
+Result = Fail
+
+[Alen = 0, Plen = 24, Nlen = 7, Tlen = 16]
+
+Key = 197afb02ffbd8f699dacae87094d524324576b99844f75e1
+
+Count = 75
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = cba4b4aeb85f0492fd8d905c4a6d8233139833373ef188a8c5a5ebecf7ac8607fe412189e83d9d20
+Result = Pass
+Payload = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22
+
+Count = 76
+Nonce = 31f8fa25827d48
+Adata = 00
+CT = ca62713728b5c9d652504b0ae8fd4fee5d297ee6a8d19cb6e699f15f14d34dcaf9ba8ed4b877c97d
+Result = Fail
+
+Count = 77
+Nonce = 5340ed7752c9ff
+Adata = 00
+CT = 93012c0a5f6f1025b8c4a5d897d3eea0b1c77be8000c9e59f3b8899459788c58794f177cfd838f35
+Result = Fail
+
+Count = 78
+Nonce = 9cbce402511b89
+Adata = 00
+CT = b8eb95f72f643c2c51ad74775cc203d215c86626e903eb013ad22e8fa4d2f9725ce4f212a8844855
+Result = Fail
+
+Count = 79
+Nonce = 123a0beace4e39
+Adata = 00
+CT = 71f17cf21c44267c676657db9e55bee33273787474e77b17b5eab45d7d096577643815e6d467312d
+Result = Pass
+Payload = 9d033e3b66efed1467868f382417c80594877a28bc97f406
+
+Count = 80
+Nonce = 8ea1594a58fe4a
+Adata = 00
+CT = d6737f642260c4ee3b19cb78cc2ef1767213416b82c71e918b1a5ecca7354af824fea617b9b69031
+Result = Fail
+
+Count = 81
+Nonce = 5a7743e59e82da
+Adata = 00
+CT = cbe60d633399daa6ee66418be6d16e292ea47a93c291fce2c54c98f8007ed55a21759f5452559538
+Result = Fail
+
+Count = 82
+Nonce = f477f754d7ee76
+Adata = 00
+CT = 2a78a7beb8df4bf5d35ff0b2853bc51ce127163d2f56e00ea555aa972e1c2e3f439f85663ae25889
+Result = Fail
+
+Count = 83
+Nonce = 040a257dede70e
+Adata = 00
+CT = ee78ddbea9c3aede9f88af0e82464d9d1afe81de16aa18c49aeb326578fa615e86969348d9bbfb7f
+Result = Fail
+
+Count = 84
+Nonce = dd51b8e91683d1
+Adata = 00
+CT = cdf7cb74d978e7ea738e288ed79edfccf10b553c09d1856e2efbff1da769af3b72099cbda3cbf091
+Result = Fail
+
+Count = 85
+Nonce = ab3cb86cca6fb2
+Adata = 00
+CT = 90b990a1ea254592f2c226c969b332fc7bfe5f808729c2d83291a566e6641a965ffdabe097050dc5
+Result = Fail
+
+Count = 86
+Nonce = f67b98efd39b55
+Adata = 00
+CT = 44a6aa954c3508b3c9264c20c272e80c0e95d50ddec2849084b47504dced5b70c302cc93502cc37e
+Result = Pass
+Payload = f2e944e1ae47ad5873bf391f1b0cc07f6151eb4c50bb45b2
+
+Count = 87
+Nonce = e60e2c002d1c99
+Adata = 00
+CT = 9d4ff7a44cdb9b14f586efc3d6be02d069b425c06bec4eed37109739a3676f03adfd740dbaa4940d
+Result = Pass
+Payload = 70f48dc1d76e5028da07e29852801375a9edb2214a5ea4c0
+
+Count = 88
+Nonce = 098e053fa08043
+Adata = 00
+CT = 23da95e102c7921a51b19b5733ea5776ab6c287f6057c00ec4bfacbb2f246b570efd93d98e99be49
+Result = Pass
+Payload = bd81680e3dc0b35431c92598dcaa26ef09ca0da5e77193de
+
+Count = 89
+Nonce = 4bf48328725514
+Adata = 00
+CT = 53d00d5839d0a1e695916151f9450b7311982917edcbd7c66496912db41761a1d2aecfda04fb2cfa
+Result = Fail
+
+[Alen = 0, Plen = 24, Nlen = 13, Tlen = 4]
+
+Key = 197afb02ffbd8f699dacae87094d524324576b99844f75e1
+
+Count = 90
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = 042653c674ef2a90f7fb11d30848e530ae59478f1051633a34fad277
+Result = Pass
+Payload = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697
+
+Count = 91
+Nonce = 49004912fdd7269279b1f06a89
+Adata = 00
+CT = 1902d9769a7ba3d3268e1257395c8c2e5f98eef295dcbfa5a35df775
+Result = Fail
+
+Count = 92
+Nonce = efeb82c8c68d6600b24dd6d8ee
+Adata = 00
+CT = ebacb8e78c0ad9d3ed99f1821b0b0085beac351f88a79ef71faaf310
+Result = Fail
+
+Count = 93
+Nonce = 7b93d368dc551640b00ba3cbb5
+Adata = 00
+CT = efc1d5b6f0a48e4ce3e821d743d34206b28c69485c410fa94d5e6103
+Result = Fail
+
+Count = 94
+Nonce = 24b7a65391f88bea38fcd54a9a
+Adata = 00
+CT = 3c1836e5d0f0473dab7bfd7a95ba69575f7f841970ac6c6769ac966a
+Result = Pass
+Payload = 43419715cef9a48dc7280bc035082a6581afd1d82bee9d1a
+
+Count = 95
+Nonce = 6aa3f731522fce7e366ba59945
+Adata = 00
+CT = 2c583e54d75a02948c7f6dcd12cba32a65e8d605fba7ec10c47e9a8e
+Result = Fail
+
+Count = 96
+Nonce = a11cf5bed0041ee3cb1fef4b43
+Adata = 00
+CT = a8632dee22f34315b05c40135c6dd471c63b09438da834dc1f3f537f
+Result = Fail
+
+Count = 97
+Nonce = 273cc5013785baeb5abc79c8bd
+Adata = 00
+CT = 0f03ea1b2561951d79062e19a85d98293c8c2846936c724c26421940
+Result = Fail
+
+Count = 98
+Nonce = d2d4482ea8e98c1cf309671895
+Adata = 00
+CT = f9764405e54d827ac433fd624506b92e123463a5b01f21ffa3a22ac7
+Result = Fail
+
+Count = 99
+Nonce = a8849b44adb48d271979656930
+Adata = 00
+CT = a326e0cf3f97adff3249944880ddfb8d616cd18a086e046289429246
+Result = Fail
+
+Count = 100
+Nonce = a632ba0d00511122abcd6227ff
+Adata = 00
+CT = f188bc1a72e81b34d75b402e4f8ef3d638d2f56a409eab064c9649b7
+Result = Fail
+
+Count = 101
+Nonce = c47af80cd26d047630c1fdf0d1
+Adata = 00
+CT = 341df3a273e85cf387ab823bdf9c34a1ae2c86940cb4bfcde2e93f29
+Result = Pass
+Payload = d8306c9c4ea6c69c6e2ad0fc0e49b1e0126b01078d6419ff
+
+Count = 102
+Nonce = 70e132023acae1f88c7a237b68
+Adata = 00
+CT = a0e7997fd67ea66b6274d719b84da92433fdf7d512b160da35c7081d
+Result = Pass
+Payload = d0b2bef5ed1a87d9c73d4a459cb05c11799c4f51ad640b1e
+
+Count = 103
+Nonce = 8010d3a2a14f72f5585defc940
+Adata = 00
+CT = dd8fd11e1c0746e7273fdd2e7dfa1ee4fc8ad835ca3141c0f83a9ad7
+Result = Pass
+Payload = 4faba05569bf7ac656780c16995e9122e565fe9984be8a68
+
+Count = 104
+Nonce = a98c2f0e0a7b68942853905191
+Adata = 00
+CT = 39b0d3603f1289b5885ac244953275d28491952e7e57d93c7ff1eb5d
+Result = Fail
+
+[Alen = 0, Plen = 24, Nlen = 13, Tlen = 16]
+
+Key = 90929a4b0ac65b350ad1591611fe48297e03956f6083e451
+
+Count = 105
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = a5b7d8cca2069908d1ed88e6a9fe2c9bede3131dad54671ea7ade30a07d185692ab0ebdf4c78cf7a
+Result = Pass
+Payload = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697
+
+Count = 106
+Nonce = 49004912fdd7269279b1f06a89
+Adata = 00
+CT = 9a98617fb97a0dfe466be692272dcdaec1c5443a3b51312ef042c86363cc05afb98c66e16be8a445
+Result = Fail
+
+Count = 107
+Nonce = efeb82c8c68d6600b24dd6d8ee
+Adata = 00
+CT = d3068ae815c3605d7670058abb9384f4c15b75150eb7910041a8f6ac697430627826bd76b19da027
+Result = Fail
+
+Count = 108
+Nonce = 7b93d368dc551640b00ba3cbb5
+Adata = 00
+CT = 388a289bb85533b667b141a78d0c79acdeb9fbf72886d5ab980581017fefef92c2b50ae20b93c81c
+Result = Fail
+
+Count = 109
+Nonce = 24b7a65391f88bea38fcd54a9a
+Adata = 00
+CT = 71f68480a8801d4966c84807c5ff6139d83ba0a5b902bee3327f5f91763c0a0bec43264c27cd237f
+Result = Pass
+Payload = 43419715cef9a48dc7280bc035082a6581afd1d82bee9d1a
+
+Count = 110
+Nonce = 6aa3f731522fce7e366ba59945
+Adata = 00
+CT = 8627bf1e3edafc69f1328c393dd8e7bd1c182d021e6d3a3652c4b7fd911ca77950ff2d035e47b7ec
+Result = Fail
+
+Count = 111
+Nonce = a11cf5bed0041ee3cb1fef4b43
+Adata = 00
+CT = b10ea86a384432a45f50b3c2e482595b46c81c61ca39bc0f4ffcb29bde8b9a81945d671b0f619045
+Result = Fail
+
+Count = 112
+Nonce = 273cc5013785baeb5abc79c8bd
+Adata = 00
+CT = 3ace8b7e03a0c1fa9e97f46975ab0a4924446e791540e225578cc14aa558e18d5f777ab6e16dcfee
+Result = Fail
+
+Count = 113
+Nonce = d2d4482ea8e98c1cf309671895
+Adata = 00
+CT = 8190abe4c21e320e10825e269190bb10a354691958e2436275433c4ae28757c8544c86f1f74ea6a5
+Result = Fail
+
+Count = 114
+Nonce = a8849b44adb48d271979656930
+Adata = 00
+CT = 1d7e308c34cdca7b7b222f4ebc92afd8055bff542c0b76d3d7752ebe9c5dbf00ee8ad60ac34dd7d0
+Result = Fail
+
+Count = 115
+Nonce = a632ba0d00511122abcd6227ff
+Adata = 00
+CT = 9c2609f7af5b634a16e58f2e9cc7a9ef7812a12d209847000a4432b35d3b884e4169c28d287499ff
+Result = Fail
+
+Count = 116
+Nonce = c47af80cd26d047630c1fdf0d1
+Adata = 00
+CT = 5b0b5e6690d648e1b92c12cfddb431d6d3dfe689d01db8199256ace490c2f0afb93ba32be58fd1de
+Result = Pass
+Payload = d8306c9c4ea6c69c6e2ad0fc0e49b1e0126b01078d6419ff
+
+Count = 117
+Nonce = 70e132023acae1f88c7a237b68
+Adata = 00
+CT = 8722fca71fdf750ec5d62fc6d7ba079aef19210da764067aefd8535dd6b7fa701c9ca8c8b635c30b
+Result = Pass
+Payload = d0b2bef5ed1a87d9c73d4a459cb05c11799c4f51ad640b1e
+
+Count = 118
+Nonce = 8010d3a2a14f72f5585defc940
+Adata = 00
+CT = 91ac457f5e53492301e72d9d495277ed17edb30e8c7a48d21b5d2cd4d5b6d2ef48413245a6b27b67
+Result = Pass
+Payload = 4faba05569bf7ac656780c16995e9122e565fe9984be8a68
+
+Count = 119
+Nonce = a98c2f0e0a7b68942853905191
+Adata = 00
+CT = d2fe5293b7d53ed46ddf02a5618039adbae22845ce72e434fdc83ea4863c3e84a5456f7f853a1ea6
+Result = Fail
+
+[Alen = 32, Plen = 0, Nlen = 7, Tlen = 4]
+
+Key = 90929a4b0ac65b350ad1591611fe48297e03956f6083e451
+
+Count = 120
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = 1d089a5f
+Result = Pass
+Payload = 00
+
+Count = 121
+Nonce = a265480ca88d5f
+Adata = a2248a882ecbf850daf91933a389e78e81623d233dfd47bf8321361a38f138fe
+CT = 2f46022a
+Result = Fail
+
+Count = 122
+Nonce = 87ec7423f1ebfc
+Adata = 2bed1ec06c1ca149d9ffbaf048c474ea2de000eb7950f18d6c25acf6ab3f19b5
+CT = 67dc4693
+Result = Fail
+
+Count = 123
+Nonce = b8b04f90616082
+Adata = 4898731e143fcc677c7cf1a8f2b3c4039fb5e57028e33b05e097d1763cbfe4d8
+CT = 7027a849
+Result = Fail
+
+Count = 124
+Nonce = 8c687b4318813a
+Adata = fcad52a88544325bb31eb5de4a41dbff6a96f69d0993b969a01792ee23953acf
+CT = 5c6a4de2
+Result = Pass
+Payload = 00
+
+Count = 125
+Nonce = 29b810eed8fc92
+Adata = 40d1d320eb63a25d7a2b3141563a552114275ddda56beb62cc0c0273d5795faa
+CT = 1d855f5d
+Result = Fail
+
+Count = 126
+Nonce = 62452462c53934
+Adata = 1eb8863ea100babc1713654afcf54f21f8bff754223ad70269ace9d034f26a96
+CT = 1b318980
+Result = Fail
+
+Count = 127
+Nonce = 4cceba0e7aee97
+Adata = f33e184c967165eb62542999afaca4e3e319840e439b5bb509544fb4b6901445
+CT = cf871f91
+Result = Fail
+
+Count = 128
+Nonce = b5151b0601c683
+Adata = 73d27303ec91f28c79b278882034d11eb6a5266746f37edbb77f8409a8738b8c
+CT = 4f0e04bc
+Result = Fail
+
+Count = 129
+Nonce = 4e5d6d7ac9e71e
+Adata = a01b6e152fe232b6c10b5d89900961c445f4c46833df242c826678b68c869811
+CT = fc9013df
+Result = Fail
+
+Count = 130
+Nonce = dc88e989951a3f
+Adata = fdcacfaff46585406cc45a2da364e67e132a91c98900a8f9d7bfb14ec951fca5
+CT = 5134def3
+Result = Fail
+
+Count = 131
+Nonce = a1aeda4b4cb8dd
+Adata = db3022ef4cd68ae22b501599448ffe2dda15cfd2e259315c6f6d03036edea963
+CT = 5814103a
+Result = Pass
+Payload = 00
+
+Count = 132
+Nonce = f248e5225e3d9a
+Adata = fdc64ef76a3bfd0a15d0bc8e8bacaf64346796a3e35afcf2ac1ab136f63f7b6e
+CT = 74c75c4a
+Result = Pass
+Payload = 00
+
+Count = 133
+Nonce = e68228f5c65b73
+Adata = 614efdf89ce2a9fcbd38bdc0b4cece54dfd7532880e0b4ce6eb3a4010b7cb1e7
+CT = 9884898b
+Result = Pass
+Payload = 00
+
+Count = 134
+Nonce = ea167cfd1101d9
+Adata = 28130f938c45a1a92b02dbeadbd8df816b6d934e87cca2dfdbfdc49c7cd84041
+CT = 0b1cbfb1
+Result = Fail
+
+[Alen = 32, Plen = 0, Nlen = 7, Tlen = 16]
+
+Key = 6a798d7c5e1a72b43e20ad5c7b08567b12ab744b61c070e2
+
+Count = 135
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = 5280a2137fee3deefcfe9b63a1199fb3
+Result = Pass
+Payload = 00
+
+Count = 136
+Nonce = a265480ca88d5f
+Adata = a2248a882ecbf850daf91933a389e78e81623d233dfd47bf8321361a38f138fe
+CT = d40a7318c5f2d82f838c0beeefe0d598
+Result = Fail
+
+Count = 137
+Nonce = 87ec7423f1ebfc
+Adata = 2bed1ec06c1ca149d9ffbaf048c474ea2de000eb7950f18d6c25acf6ab3f19b5
+CT = 7551978bc9592bf9e294b4984c5862bb
+Result = Fail
+
+Count = 138
+Nonce = b8b04f90616082
+Adata = 4898731e143fcc677c7cf1a8f2b3c4039fb5e57028e33b05e097d1763cbfe4d8
+CT = 859cf444f89225b32a55a1645bd24979
+Result = Fail
+
+Count = 139
+Nonce = 8c687b4318813a
+Adata = fcad52a88544325bb31eb5de4a41dbff6a96f69d0993b969a01792ee23953acf
+CT = 29e967a0245607c36cf3eaf00fdae566
+Result = Pass
+Payload = 00
+
+Count = 140
+Nonce = 29b810eed8fc92
+Adata = 40d1d320eb63a25d7a2b3141563a552114275ddda56beb62cc0c0273d5795faa
+CT = 9daa0e1c4df5f2bf507b1a57a1135b86
+Result = Fail
+
+Count = 141
+Nonce = 62452462c53934
+Adata = 1eb8863ea100babc1713654afcf54f21f8bff754223ad70269ace9d034f26a96
+CT = 18caec79720a5d67d7457e9b7c7a153c
+Result = Fail
+
+Count = 142
+Nonce = 4cceba0e7aee97
+Adata = f33e184c967165eb62542999afaca4e3e319840e439b5bb509544fb4b6901445
+CT = 5f2c455546c56f514a0f69f05345c2c4
+Result = Fail
+
+Count = 143
+Nonce = b5151b0601c683
+Adata = 73d27303ec91f28c79b278882034d11eb6a5266746f37edbb77f8409a8738b8c
+CT = b7e4846ff30b7c3673a962a2701c0387
+Result = Fail
+
+Count = 144
+Nonce = 4e5d6d7ac9e71e
+Adata = a01b6e152fe232b6c10b5d89900961c445f4c46833df242c826678b68c869811
+CT = 7b5fa0d42a616ab05ac2c58c904ce92f
+Result = Fail
+
+Count = 145
+Nonce = dc88e989951a3f
+Adata = fdcacfaff46585406cc45a2da364e67e132a91c98900a8f9d7bfb14ec951fca5
+CT = c8c67f558b5844b149dd47824c8cb9d8
+Result = Fail
+
+Count = 146
+Nonce = a1aeda4b4cb8dd
+Adata = db3022ef4cd68ae22b501599448ffe2dda15cfd2e259315c6f6d03036edea963
+CT = 70a09aaf22ac316124a169f6b0a83ffe
+Result = Pass
+Payload = 00
+
+Count = 147
+Nonce = f248e5225e3d9a
+Adata = fdc64ef76a3bfd0a15d0bc8e8bacaf64346796a3e35afcf2ac1ab136f63f7b6e
+CT = 5bc85ed5521a91b9eb42b437950f0e06
+Result = Pass
+Payload = 00
+
+Count = 148
+Nonce = e68228f5c65b73
+Adata = 614efdf89ce2a9fcbd38bdc0b4cece54dfd7532880e0b4ce6eb3a4010b7cb1e7
+CT = 989ec0e7b192ea010dd61d3fb64e8de0
+Result = Pass
+Payload = 00
+
+Count = 149
+Nonce = ea167cfd1101d9
+Adata = 28130f938c45a1a92b02dbeadbd8df816b6d934e87cca2dfdbfdc49c7cd84041
+CT = 15c2dbe7fa307654d8ca7c0f8d6d2f14
+Result = Fail
+
+[Alen = 32, Plen = 0, Nlen = 13, Tlen = 4]
+
+Key = 6a798d7c5e1a72b43e20ad5c7b08567b12ab744b61c070e2
+
+Count = 150
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = 5e0eaebd
+Result = Pass
+Payload = 00
+
+Count = 151
+Nonce = 8739b4bea1a099fe547499cbc6
+Adata = f6107696edb332b2ea059d8860fee26be42e5e12e1a4f79a8d0eafce1b2278a7
+CT = 71b7fc33
+Result = Fail
+
+Count = 152
+Nonce = 0f98fdbde2b04387f27b3401dd
+Adata = 02010329660fa716556193eb4870ee84bd934296a5c52d92bba859cc13caaddc
+CT = 93227bd4
+Result = Fail
+
+Count = 153
+Nonce = 4eed58f381e500902ba5c56864
+Adata = 96056d9ebd7c553c22cc2d9d816b61123750d96c1b08c4b661079424bf3c4946
+CT = ced654e2
+Result = Fail
+
+Count = 154
+Nonce = 1e7e51f0fa9a33ed618c26f5e3
+Adata = da9b8ffb0f3c2aee2e386cc9f035ec1eb3e629bd1544c11dc21be4fd8ac9074a
+CT = bf7a8e0c
+Result = Pass
+Payload = 00
+
+Count = 155
+Nonce = f012f94f5988c79aa179d7fdfc
+Adata = 612b2ef2683109d99452f95099417641d0c2be3f8ab4cbb2a44e83355ba9303c
+CT = 840caa3e
+Result = Fail
+
+Count = 156
+Nonce = 715acf92cfb69ad56036c49e70
+Adata = 960667b85be07304634124b9324be12a1c11451f1fa9db82c683265b4cf8e5ff
+CT = 1e22fc41
+Result = Fail
+
+Count = 157
+Nonce = 141be3601e38185a9fa1596d2e
+Adata = 606452c62290b43559a588bb03356f846cecb0ccaf0bdaf67a18abd811d4315a
+CT = 968ccbbf
+Result = Fail
+
+Count = 158
+Nonce = fcdda3c5f0e80843b03d8788da
+Adata = 03f22247a55461a293d253c77483859fdac1b87c2480e208a3df767cfbfde512
+CT = 0a31cc96
+Result = Fail
+
+Count = 159
+Nonce = ca660ed3b917c0aca140dcd3fb
+Adata = 254a86f5b20d344ad86fd5523d08f1864737be57731440c29aa6b42574572f51
+CT = a456c3da
+Result = Fail
+
+Count = 160
+Nonce = 642ae3466661ce1f51783deece
+Adata = 4432a1cec5976cc13b8fb78341d426c2248f091b597123d263ffafc7f82da5a5
+CT = 29746eea
+Result = Fail
+
+Count = 161
+Nonce = 7864c717ec93db38b10679be47
+Adata = 679aad1ad1e57029e3362b325572fc71cac53184b0f1546867e665a4a59466c4
+CT = df7f63ca
+Result = Pass
+Payload = 00
+
+Count = 162
+Nonce = c3bf9dfe9d6c26f543188fb457
+Adata = e301f69ad3a7e08a3d02462f0aa584449eb0449b0e3c50aa8dfaa4472816c8b0
+CT = bf0b1445
+Result = Pass
+Payload = 00
+
+Count = 163
+Nonce = 1527657d2fd98f7deca55cc649
+Adata = f4c723433b7cafe3cda9bb4940a21a89a8382d13018b622ccd1ffb9ffd3211af
+CT = ae8533f5
+Result = Pass
+Payload = 00
+
+Count = 164
+Nonce = b8432d3d5525a0dadbbaa6b6b8
+Adata = 86ee6e37b4a2d9a0b52ec95643b4e8297e237721e15ce8bf7593a98644f83eba
+CT = 9426cf89
+Result = Fail
+
+[Alen = 32, Plen = 0, Nlen = 13, Tlen = 16]
+
+Key = f9fdca4ac64fe7f014de0f43039c757194d544ce5d15eed4
+
+Count = 165
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = d07ccf9fdc3d33aa94cda3d230da707c
+Result = Pass
+Payload = 00
+
+Count = 166
+Nonce = 8739b4bea1a099fe547499cbc6
+Adata = f6107696edb332b2ea059d8860fee26be42e5e12e1a4f79a8d0eafce1b2278a7
+CT = 65fe32b649dc328c9f531584897e85b3
+Result = Fail
+
+Count = 167
+Nonce = 0f98fdbde2b04387f27b3401dd
+Adata = 02010329660fa716556193eb4870ee84bd934296a5c52d92bba859cc13caaddc
+CT = ec31fb6b41c2dae87cf395fc1fe3a080
+Result = Fail
+
+Count = 168
+Nonce = 4eed58f381e500902ba5c56864
+Adata = 96056d9ebd7c553c22cc2d9d816b61123750d96c1b08c4b661079424bf3c4946
+CT = 33c2f2312dd5bfcadbb05f8d0a33fd4a
+Result = Fail
+
+Count = 169
+Nonce = 1e7e51f0fa9a33ed618c26f5e3
+Adata = da9b8ffb0f3c2aee2e386cc9f035ec1eb3e629bd1544c11dc21be4fd8ac9074a
+CT = a9e81afd1030d195c679e2c837aeb736
+Result = Pass
+Payload = 00
+
+Count = 170
+Nonce = f012f94f5988c79aa179d7fdfc
+Adata = 612b2ef2683109d99452f95099417641d0c2be3f8ab4cbb2a44e83355ba9303c
+CT = 1db000f0e7d3a03718293fc118678427
+Result = Fail
+
+Count = 171
+Nonce = 715acf92cfb69ad56036c49e70
+Adata = 960667b85be07304634124b9324be12a1c11451f1fa9db82c683265b4cf8e5ff
+CT = ea37900f049db8fc5cbf46edb5fcac2c
+Result = Fail
+
+Count = 172
+Nonce = 141be3601e38185a9fa1596d2e
+Adata = 606452c62290b43559a588bb03356f846cecb0ccaf0bdaf67a18abd811d4315a
+CT = d1097ebd7ad0a41f61ba32a44dc15305
+Result = Fail
+
+Count = 173
+Nonce = fcdda3c5f0e80843b03d8788da
+Adata = 03f22247a55461a293d253c77483859fdac1b87c2480e208a3df767cfbfde512
+CT = 0979729272d8b42f2e3dc0eb181a1217
+Result = Fail
+
+Count = 174
+Nonce = ca660ed3b917c0aca140dcd3fb
+Adata = 254a86f5b20d344ad86fd5523d08f1864737be57731440c29aa6b42574572f51
+CT = 4457200916a20116b096225606f1a9e2
+Result = Fail
+
+Count = 175
+Nonce = 642ae3466661ce1f51783deece
+Adata = 4432a1cec5976cc13b8fb78341d426c2248f091b597123d263ffafc7f82da5a5
+CT = cc6b51f39a3dcfb54abbb89f4df21114
+Result = Fail
+
+Count = 176
+Nonce = 7864c717ec93db38b10679be47
+Adata = 679aad1ad1e57029e3362b325572fc71cac53184b0f1546867e665a4a59466c4
+CT = aac09cef9697927331251f028d24c31f
+Result = Pass
+Payload = 00
+
+Count = 177
+Nonce = c3bf9dfe9d6c26f543188fb457
+Adata = e301f69ad3a7e08a3d02462f0aa584449eb0449b0e3c50aa8dfaa4472816c8b0
+CT = 56c00070eae0db329894a045d866bbaf
+Result = Pass
+Payload = 00
+
+Count = 178
+Nonce = 1527657d2fd98f7deca55cc649
+Adata = f4c723433b7cafe3cda9bb4940a21a89a8382d13018b622ccd1ffb9ffd3211af
+CT = 090016bb96aeaabbf66fd34fc97591a4
+Result = Pass
+Payload = 00
+
+Count = 179
+Nonce = b8432d3d5525a0dadbbaa6b6b8
+Adata = 86ee6e37b4a2d9a0b52ec95643b4e8297e237721e15ce8bf7593a98644f83eba
+CT = 264407dfe796bf7f6eb1f26c1f8504ef
+Result = Fail
+
+[Alen = 32, Plen = 24, Nlen = 7, Tlen = 4]
+
+Key = f9fdca4ac64fe7f014de0f43039c757194d544ce5d15eed4
+
+Count = 180
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = 9f6ca4af9b159148c889a6584d1183ea26e2614874b0504575dea8d1
+Result = Pass
+Payload = a265480ca88d5f536db0dc6abc40faf0d05be7a966977768
+
+Count = 181
+Nonce = fdd2d6f503c915
+Adata = 5b92394f21ddc3ad49d9b0881b829a5935cb3a4d23e292a62fb66b5e7ab7020e
+CT = 84d8212e9cfc2121252baa3b065b1edcf50497b9594db1ebd7965825
+Result = Fail
+
+Count = 182
+Nonce = 27d73d58100054
+Adata = f6468542923be79b4b06dfe70920d57d1da73a9c16f9c9a12d810d7de0d12467
+CT = 5f60a8f867a33b2077ecc69863b295c3c6aeae7d7cade7f8f7f796fe
+Result = Fail
+
+Count = 183
+Nonce = dd16e0ce1250e3
+Adata = bc65cfd65e9863c8b7457d58afa6bdb48a84170d8aa97ba5b397b52ad17a9242
+CT = 1353b3fa1bb1d57ffb139017885c02e26c90231a24b5a615b8f1f2ae
+Result = Fail
+
+Count = 184
+Nonce = ccee19d037cf4a
+Adata = c026696e6425e6c33f45b4145febf1137e7ac26383c9f5aa4cd4e5e8abb19e07
+CT = c3116d9040e1ed4f7c9464d270fb302bd3f1561c25c5b95b8b4b53f6
+Result = Pass
+Payload = 0df202431ee7f251a38aaf6aa8cd313782bd293af9114005
+
+Count = 185
+Nonce = 6c8ba94f09cbe6
+Adata = 774ad1a88f8bb063951486d4aec5bf82d5fc535bd0b952f86200c123c37fa496
+CT = 0ca17e8f89bea67db48a8f132ef6c6df7a292914d401299af6bf3800
+Result = Fail
+
+Count = 186
+Nonce = 1f670302fcdcc8
+Adata = 1a9ff9698cfc96b581d7115c822e4363d7355ec5daed2eae5bf89ee944ac7d9c
+CT = 0ce543569e8187f3cec70399ff922e4903cb1d12f990f05613244cf6
+Result = Fail
+
+Count = 187
+Nonce = 5d05f658c729a2
+Adata = dd9564c1431ed490b17ef69f6115805e54ef156ef4e10e58f7d57a7e86626352
+CT = 3acdbc163a350f312791b152a41e57627b1cc8bf3e41c8aea5876de8
+Result = Fail
+
+Count = 188
+Nonce = 22a77db9fcbc95
+Adata = 86bf1739c10f63df734ee3e60ac40ff5636c49f68ca4c16ece289609eb413e7a
+CT = 604518e436edf7a0561d5e284f3915839a6d28cb06ef792a1970ed17
+Result = Fail
+
+Count = 189
+Nonce = 491e32b0bbfa4c
+Adata = 75bef075c79d6cfd7fc73aefd67b2d215be0648937477ba606b1fe1be591239e
+CT = fc79b520d67da891e63654d7927db6c8012c96985a0059d5f68d8da4
+Result = Fail
+
+Count = 190
+Nonce = bc4b7d3a380be0
+Adata = 353dbb41e2d525a9f4fcd858d0f0aa1b1e86ac0f936d5c09c6b61c343f94e3fc
+CT = d86bb51a98770098d0feb39170bd979199a8f741041df13790ee4c14
+Result = Fail
+
+Count = 191
+Nonce = a840e98df72ae9
+Adata = 22c6607732ef1bdc7fcf6197e037cdadd7ee17c008552dd9f04b8564d34fb17c
+CT = 51b6b928bdd1cc0bd0a0aed2cda302472d618ffaa60e179029c87855
+Result = Pass
+Payload = a2f53385618b41301f4e3ea4c597f411103dac2b37abf5da
+
+Count = 192
+Nonce = 39d93c3cf31a6f
+Adata = 937dfac5cded938438f4e97aabd9beb50dba40f824198260a89729479cfe6869
+CT = d0abab9b8e9d6c11bb9c15bea8a486704bed32c57297055b4de8ed8d
+Result = Pass
+Payload = c1bdef96dc868446be48491b160504546f2a40dd581f9582
+
+Count = 193
+Nonce = 0bbc177019321e
+Adata = f6e02678820f5ccbede6cbded02d6dd58d486166d7b18ee975a688af421fb795
+CT = 92fd519a966c0fbdd7087ff5a1bd946cd663502db378383531d69947
+Result = Pass
+Payload = 72a70954d22ad722fc32756afce67b344b2f3c55fe1d9eed
+
+Count = 194
+Nonce = ad048eb2ad7526
+Adata = 0d2739cfdac782b61f484fa1a423c478c414397ec420327963d79112b2d70a7e
+CT = 7f239b1916830161f3b52b7ab13542a5a0a97a17f30ca5fa30768d4d
+Result = Fail
+
+[Alen = 32, Plen = 24, Nlen = 7, Tlen = 16]
+
+Key = a7aa635ea51b0bb20a092bd5573e728ccd4b3e8cdd2ab33d
+
+Count = 195
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = 6aab64c4787599d8f213446beadb16e08dba60e97f56dbd14d1d980d6fe0fb44b421992662b97975
+Result = Pass
+Payload = a265480ca88d5f536db0dc6abc40faf0d05be7a966977768
+
+Count = 196
+Nonce = fdd2d6f503c915
+Adata = 5b92394f21ddc3ad49d9b0881b829a5935cb3a4d23e292a62fb66b5e7ab7020e
+CT = 4980b2ee49b1aaf393175f5ab9bae95ec7904557dfa206603c51d36c826f01384100886198a7f6a3
+Result = Fail
+
+Count = 197
+Nonce = 27d73d58100054
+Adata = f6468542923be79b4b06dfe70920d57d1da73a9c16f9c9a12d810d7de0d12467
+CT = 86a02bdd6ae733eee26f8eab898b336105978b5bbd6df781758a111aae4f735b7dd4d9802f2a8406
+Result = Fail
+
+Count = 198
+Nonce = dd16e0ce1250e3
+Adata = bc65cfd65e9863c8b7457d58afa6bdb48a84170d8aa97ba5b397b52ad17a9242
+CT = 59cfab8956813c48e09332a2bb8a30dbcdf5afb2529532ab8cef14ebc2951069739d5d657d82addb
+Result = Fail
+
+Count = 199
+Nonce = ccee19d037cf4a
+Adata = c026696e6425e6c33f45b4145febf1137e7ac26383c9f5aa4cd4e5e8abb19e07
+CT = 67d989ea935b9ce190e3a7f3b645305e1e308a7fe617f80f170a2b9c309de6c2326115a76efbdf98
+Result = Pass
+Payload = 0df202431ee7f251a38aaf6aa8cd313782bd293af9114005
+
+Count = 200
+Nonce = 6c8ba94f09cbe6
+Adata = 774ad1a88f8bb063951486d4aec5bf82d5fc535bd0b952f86200c123c37fa496
+CT = 2522a5e4d157193ef2c264cfe877db8ac75b3cc5aab08a814bcd14af0205af716f2b864f0c397f65
+Result = Fail
+
+Count = 201
+Nonce = 1f670302fcdcc8
+Adata = 1a9ff9698cfc96b581d7115c822e4363d7355ec5daed2eae5bf89ee944ac7d9c
+CT = 4536422bbad220079ee09e700e103efdaac832d016a20813762d5d8adafe75a191310a2618930c48
+Result = Fail
+
+Count = 202
+Nonce = 5d05f658c729a2
+Adata = dd9564c1431ed490b17ef69f6115805e54ef156ef4e10e58f7d57a7e86626352
+CT = d6711a78adf54f4effe647d531c4618cf32e3037eb700580206f80080dfa3e66e6371c0cde6cd205
+Result = Fail
+
+Count = 203
+Nonce = 22a77db9fcbc95
+Adata = 86bf1739c10f63df734ee3e60ac40ff5636c49f68ca4c16ece289609eb413e7a
+CT = e44034a397778e1c6babab27f5a50fa4aac0e83d6b3eb25db1b5b2b35c8a8125efccd1f4102f3e82
+Result = Fail
+
+Count = 204
+Nonce = 491e32b0bbfa4c
+Adata = 75bef075c79d6cfd7fc73aefd67b2d215be0648937477ba606b1fe1be591239e
+CT = b8e31c5910623e405f2ebf65821963e5b8814043612395feca36f53b01943f03cb8b69b5af53e505
+Result = Fail
+
+Count = 205
+Nonce = bc4b7d3a380be0
+Adata = 353dbb41e2d525a9f4fcd858d0f0aa1b1e86ac0f936d5c09c6b61c343f94e3fc
+CT = 4000faf8558f2f4e01e45e90796cd236e5211d1704270f31c3bfc6851049d32105fd16bd45b29f29
+Result = Fail
+
+Count = 206
+Nonce = a840e98df72ae9
+Adata = 22c6607732ef1bdc7fcf6197e037cdadd7ee17c008552dd9f04b8564d34fb17c
+CT = 53bb608f6236798839af35888cb0fa4797b599271084cc13847b022733ca5a5e3c4d472332484b7f
+Result = Pass
+Payload = a2f53385618b41301f4e3ea4c597f411103dac2b37abf5da
+
+Count = 207
+Nonce = 39d93c3cf31a6f
+Adata = 937dfac5cded938438f4e97aabd9beb50dba40f824198260a89729479cfe6869
+CT = be54551d1d2f1b3eb60ffe3b165524ff90ca09fb252bf21c1c79edbf38c50e0f240a2d70f65aa79f
+Result = Pass
+Payload = c1bdef96dc868446be48491b160504546f2a40dd581f9582
+
+Count = 208
+Nonce = 0bbc177019321e
+Adata = f6e02678820f5ccbede6cbded02d6dd58d486166d7b18ee975a688af421fb795
+CT = f07c1072d8f8e077dfbb3ad86dd92d32b41f29e647dcd7e3a82cd3ebaf6c2d3e21749bdf570ad28d
+Result = Pass
+Payload = 72a70954d22ad722fc32756afce67b344b2f3c55fe1d9eed
+
+Count = 209
+Nonce = ad048eb2ad7526
+Adata = 0d2739cfdac782b61f484fa1a423c478c414397ec420327963d79112b2d70a7e
+CT = 7f7cf7f4d0645934cb0a5e67b4227a909aa55dba09b2c39cef93a8759845326683a0d9c22151f486
+Result = Fail
+
+[Alen = 32, Plen = 24, Nlen = 13, Tlen = 4]
+
+Key = a7aa635ea51b0bb20a092bd5573e728ccd4b3e8cdd2ab33d
+
+Count = 210
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = 16e543d0e20615ff0df15acd9927ddfe40668a54bb854cccc25e9fce
+Result = Pass
+Payload = 8739b4bea1a099fe547499cbc6d1b13d849b8084c9b6acc5
+
+Count = 211
+Nonce = 0812757ad0cc4d17c4cfe7a642
+Adata = ec6c44a7e94e51a3ca6dee229098391575ec7213c85267fbf7492fdbeee61b10
+CT = df35b109caf690656ae278bbd8f8bba687a2ce11b105dae98ecedb3e
+Result = Fail
+
+Count = 212
+Nonce = eff510acc1b85f35029cf7dc00
+Adata = 0923b927b8295c5dfaf67da55e5014293bc8c708fda50af06c1e8aef31cccc86
+CT = 7075da2291e2cb527eb926ed08d8020c5f8f0f2d4a6a4745728da544
+Result = Fail
+
+Count = 213
+Nonce = 3d13d09057190366c63c8750e9
+Adata = 77e27aa9a7bf30e130c862a3296a1cd7a10195ed1d940f2c97bfff47c6f06e32
+CT = 18a77a66457b53286b1aea0845304cac8e66a02d5c642e4c02a9b9bc
+Result = Fail
+
+Count = 214
+Nonce = e3c03ef7e1d31961ee0b97bd99
+Adata = 8a3676dd640821b58fb0f0329855fd5882c376ea166b958b7aaad223054e5784
+CT = 24e1d3820101412d8f4d57118cab8f7e489d5cac78802dd5ccf8ecf0
+Result = Pass
+Payload = 92973ce707733a73118c8ce6b5e3fc77a17f448310c0197f
+
+Count = 215
+Nonce = 5d165ddd4e599387af5967cae6
+Adata = e374f875ce829b62c98fbd67bcf128b5647f25fff9a643300eb95559b889baed
+CT = b5929bc9648e24a553c5cd953ecb9d67ee508d2d4ac7b46e661181d5
+Result = Fail
+
+Count = 216
+Nonce = fcec171162a27a96066181fab2
+Adata = cf431cc3671ec468ea86f6cc09842fcf3a84b3ef0fa1c7b20b232145b4469d62
+CT = 54aa018dc7fdf8a54809e1393d18031bab4aa5ca35c201907d74517d
+Result = Fail
+
+Count = 217
+Nonce = 2fa8120398d1a946f391367cf6
+Adata = 92558a239c8e13230754f23aec67b153db29fdfc7daf641778185dd2931d89da
+CT = 69bcc300a459862b3cd284c15dd4af53dc7e95f3067bb8254a8edd83
+Result = Fail
+
+Count = 218
+Nonce = 88e0ae338bbca9d4299b294354
+Adata = 5db5c388dbadc9f175a5cd5a1472a458d25acd7fb9c951c0cd45edf64da473bb
+CT = 5c2d2df0d8aade3e5ae0f8d8b4b4d7c565817a31b2865dc270ad39a6
+Result = Fail
+
+Count = 219
+Nonce = 4862e36296d6afc9399a95bbb4
+Adata = 36d82ebd0e0f5fe3b12946d041ae5aee16e6d17025406dd776f499bbd8e8b4c8
+CT = df1b3f98b6b0060191e7eb817f5908ddc0bc6f83860349e8ae423997
+Result = Fail
+
+Count = 220
+Nonce = 2f360a4715074e942244ab7f9b
+Adata = f0087b0086a081c1071481f033a8be8e940c36763084329bb8461b9102238f4f
+CT = 16e59dd38395c7be7f580371edabb1e9bf21270de270aa283309108e
+Result = Fail
+
+Count = 221
+Nonce = 93e08854560edb096e5d654086
+Adata = bdc60dff08bfd5d44320b75c61e456fd4333c9c3d0294d4a48d936dfd5922ce2
+CT = 0ef8981dd37c055a3c3e14786fc662b2a11065964911d35ebcc87096
+Result = Pass
+Payload = 569e4aec88dd51ca519c0a00c922ee33d3559b98a32d7906
+
+Count = 222
+Nonce = e3f37b68ff508cfe295441d9e3
+Adata = b2b6c5782e4f128467c589d2a6cf55ef12877adb771bbb6245c5bba9dcfd6208
+CT = fc1870cfc440f74f73f40e682cf4713d027c297b9426c3efe981e935
+Result = Pass
+Payload = 02b5511204bd55f7c37973e26f6df5883c0a530f07c7f8c2
+
+Count = 223
+Nonce = ea98ec44f5a86715014783172e
+Adata = e4692b9f06b666c7451b146c8aeb07a6e30c629d28065c3dde5940325b14b810
+CT = 9fc2c462dff1ba9756772d73de5c4e822b5ea0bc88845a323b98de4f
+Result = Pass
+Payload = 4da40b80579c1d9a5309f7efecb7c059a2f914511ca5fc10
+
+Count = 224
+Nonce = 5a16a8902bd70fa06cfe184c57
+Adata = 399d6b0652836457ec4f701f0dc0e5aed73d16585d61cb1bb5b7ee824fc287c8
+CT = 05fc586d5c780b8e06f618b5bb85f591665a54390eba4e14af3b74e1
+Result = Fail
+
+[Alen = 32, Plen = 24, Nlen = 13, Tlen = 16]
+
+Key = 26511fb51fcfa75cb4b44da75a6e5a0eb8d9c8f3b906f886
+
+Count = 225
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = c5b0b2ef17498c5570eb335df4588032958ba3d69bf6f3178464a6f7fa2b76744e8e8d95691cecb8
+Result = Pass
+Payload = 8739b4bea1a099fe547499cbc6d1b13d849b8084c9b6acc5
+
+Count = 226
+Nonce = 0812757ad0cc4d17c4cfe7a642
+Adata = ec6c44a7e94e51a3ca6dee229098391575ec7213c85267fbf7492fdbeee61b10
+CT = d1f0518929f4ae2f0543de2a7dfe4bb0110bb3057e524a1c06bd6dc2e6bcc3436cffb969ae900388
+Result = Fail
+
+Count = 227
+Nonce = eff510acc1b85f35029cf7dc00
+Adata = 0923b927b8295c5dfaf67da55e5014293bc8c708fda50af06c1e8aef31cccc86
+CT = 1aa7dfa3a9818142c4971cbf4f64d4cbdbd354c6958ef474bb56d90669c726d866fe2206b8828727
+Result = Fail
+
+Count = 228
+Nonce = 3d13d09057190366c63c8750e9
+Adata = 77e27aa9a7bf30e130c862a3296a1cd7a10195ed1d940f2c97bfff47c6f06e32
+CT = 90352a5ec92d4fa52a96ae28251a57933728b2a3670e2ecd9953fec4e091b3573214e1ecac1ac00c
+Result = Fail
+
+Count = 229
+Nonce = e3c03ef7e1d31961ee0b97bd99
+Adata = 8a3676dd640821b58fb0f0329855fd5882c376ea166b958b7aaad223054e5784
+CT = eaa995946ed91d6a08ade14b260ac752cbd1081d5a7cad90783618374f6d03df28ee57a1a5aa38d8
+Result = Pass
+Payload = 92973ce707733a73118c8ce6b5e3fc77a17f448310c0197f
+
+Count = 230
+Nonce = 5d165ddd4e599387af5967cae6
+Adata = e374f875ce829b62c98fbd67bcf128b5647f25fff9a643300eb95559b889baed
+CT = 0e320c4ece6ef0305a431a07a5a34d463ec4a37fc513c4b947bb3f30d6e674d10a496806c1c8933e
+Result = Fail
+
+Count = 231
+Nonce = fcec171162a27a96066181fab2
+Adata = cf431cc3671ec468ea86f6cc09842fcf3a84b3ef0fa1c7b20b232145b4469d62
+CT = 10685888091597c50acc54b2fb65150b83a7115351d6f8bd7dd7ee3f75cfb47fa72433644f9cf62e
+Result = Fail
+
+Count = 232
+Nonce = 2fa8120398d1a946f391367cf6
+Adata = 92558a239c8e13230754f23aec67b153db29fdfc7daf641778185dd2931d89da
+CT = e456abf9ee83e0a68fbdb09c4a7afaba0efb0aa6d74a17c443314076072a0ebd253fe1ab4883ebea
+Result = Fail
+
+Count = 233
+Nonce = 88e0ae338bbca9d4299b294354
+Adata = 5db5c388dbadc9f175a5cd5a1472a458d25acd7fb9c951c0cd45edf64da473bb
+CT = 5adadfd296edaf4bea92c8245983dc31b11335f682fb222c16a72444f0949868f0e71907acbb29f4
+Result = Fail
+
+Count = 234
+Nonce = 4862e36296d6afc9399a95bbb4
+Adata = 36d82ebd0e0f5fe3b12946d041ae5aee16e6d17025406dd776f499bbd8e8b4c8
+CT = c2bb4d5a830646b3f8bf84044851c3b676c4ec02e43dcbf1ab2025208191d73041c038cf2562bb8c
+Result = Fail
+
+Count = 235
+Nonce = 2f360a4715074e942244ab7f9b
+Adata = f0087b0086a081c1071481f033a8be8e940c36763084329bb8461b9102238f4f
+CT = 9589b8abcb47e54e6e8fad3e64fec7ed4f70ac435bb3e548b7e6d183efa1f51b7ff31eaa52ed59ba
+Result = Fail
+
+Count = 236
+Nonce = 93e08854560edb096e5d654086
+Adata = bdc60dff08bfd5d44320b75c61e456fd4333c9c3d0294d4a48d936dfd5922ce2
+CT = af63f27e2a9e70f106477493dc141d16a1d059dd7a8a7810d990b642039f24755790332b3cc47c49
+Result = Pass
+Payload = 569e4aec88dd51ca519c0a00c922ee33d3559b98a32d7906
+
+Count = 237
+Nonce = e3f37b68ff508cfe295441d9e3
+Adata = b2b6c5782e4f128467c589d2a6cf55ef12877adb771bbb6245c5bba9dcfd6208
+CT = 1d2ae88c878684a0b404986252b3a7583e1a5a51163ddc606d3968fdceaae5138c411a29d0d333ee
+Result = Pass
+Payload = 02b5511204bd55f7c37973e26f6df5883c0a530f07c7f8c2
+
+Count = 238
+Nonce = ea98ec44f5a86715014783172e
+Adata = e4692b9f06b666c7451b146c8aeb07a6e30c629d28065c3dde5940325b14b810
+CT = 30c154c616946eccc2e241d336ad33720953e449a0e6b0f0dbf8e9464909bdf337e48093c082a10b
+Result = Pass
+Payload = 4da40b80579c1d9a5309f7efecb7c059a2f914511ca5fc10
+
+Count = 239
+Nonce = 5a16a8902bd70fa06cfe184c57
+Adata = 399d6b0652836457ec4f701f0dc0e5aed73d16585d61cb1bb5b7ee824fc287c8
+CT = 0c95b692b07b39039b40c80cf52ff71608ae87c973ac9ccb88bba8f204bb98b17cb3c8644e472b1e
+Result = Fail
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT192.txt b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT192.txt
new file mode 100644
index 0000000000..27671e1a0a
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT192.txt
@@ -0,0 +1,1589 @@
+# CAVS 11.0
+# "CCM-DVPT" information
+# AES Keylen: 192
+# Generated on Tue Mar 15 08:09:25 2011
+
+
+[Alen = 0, Plen = 0, Nlen = 7, Tlen = 4]
+
+Key = c98ad7f38b2c7e970c9b965ec87a08208384718f78206c6c
+
+Count = 0
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = 9d4b7f3b
+Result = Pass (0)
+Payload = 00
+
+Count = 1
+Nonce = 3796cf51b87266
+Adata = 00
+CT = 80745de9
+Result = Fail (2 - CT changed)
+
+Count = 2
+Nonce = 89ca5a64050f9f
+Adata = 00
+CT = 2f6fa823
+Result = Fail (1 - Adata changed)
+
+Count = 3
+Nonce = ec9d8edff25645
+Adata = 00
+CT = 3cc132c6
+Result = Fail (1 - Adata changed)
+
+Count = 4
+Nonce = 05e16f0f42a6f4
+Adata = 00
+CT = c79d5557
+Result = Pass (0)
+Payload = 00
+
+Count = 5
+Nonce = 2e504b694f8df5
+Adata = 00
+CT = 41e0eea0
+Result = Fail (2 - CT changed)
+
+Count = 6
+Nonce = 06d102a9328863
+Adata = 00
+CT = 1f129266
+Result = Fail (1 - Adata changed)
+
+Count = 7
+Nonce = c288b810fb5334
+Adata = 00
+CT = 41b0e4e2
+Result = Fail (2 - CT changed)
+
+Count = 8
+Nonce = 08a166d9eb6610
+Adata = 00
+CT = 5082e06a
+Result = Fail (2 - CT changed)
+
+Count = 9
+Nonce = 4a5810b121c91b
+Adata = 00
+CT = 70587cce
+Result = Fail (1 - Adata changed)
+
+Count = 10
+Nonce = 44077341139bf9
+Adata = 00
+CT = 6aaa0acd
+Result = Fail (1 - Adata changed)
+
+Count = 11
+Nonce = a9df4f37847e1f
+Adata = 00
+CT = 22976e42
+Result = Pass (0)
+Payload = 00
+
+Count = 12
+Nonce = 11df57fcd131e9
+Adata = 00
+CT = f440ea1d
+Result = Pass (0)
+Payload = 00
+
+Count = 13
+Nonce = 890fff56d10dc0
+Adata = 00
+CT = 88903fb9
+Result = Pass (0)
+Payload = 00
+
+Count = 14
+Nonce = 9dc18698731b27
+Adata = 00
+CT = 3ff345c3
+Result = Fail (2 - CT changed)
+
+[Alen = 0, Plen = 0, Nlen = 7, Tlen = 16]
+
+Key = 4bb3c4a4f893ad8c9bdc833c325d62b3d3ad1bccf9282a65
+
+Count = 15
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = 17223038fa99d53681ca1beabe78d1b4
+Result = Pass (0)
+Payload = 00
+
+Count = 16
+Nonce = 3796cf51b87266
+Adata = 00
+CT = d0e1eeef4d2a264536bb1c2c1bde7c35
+Result = Fail (2 - CT changed)
+
+Count = 17
+Nonce = 89ca5a64050f9f
+Adata = 00
+CT = 81d587f8673fd514c23172af7fb7523d
+Result = Fail (1 - Adata changed)
+
+Count = 18
+Nonce = ec9d8edff25645
+Adata = 00
+CT = 500142447e535207899ab1499994daea
+Result = Fail (1 - Adata changed)
+
+Count = 19
+Nonce = 05e16f0f42a6f4
+Adata = 00
+CT = fdfdbb38bf161785114f9ee2018e892f
+Result = Pass (0)
+Payload = 00
+
+Count = 20
+Nonce = 2e504b694f8df5
+Adata = 00
+CT = 38fe9622eaa2a50152cf57e393dd3063
+Result = Fail (2 - CT changed)
+
+Count = 21
+Nonce = 06d102a9328863
+Adata = 00
+CT = 73af4b87c167572e1400a0ee28209aff
+Result = Fail (1 - Adata changed)
+
+Count = 22
+Nonce = c288b810fb5334
+Adata = 00
+CT = ace2248b9f23efa813449c82217e4a4a
+Result = Fail (2 - CT changed)
+
+Count = 23
+Nonce = 08a166d9eb6610
+Adata = 00
+CT = a9bb0e469829d9cf09ad765c5b0b58bf
+Result = Fail (2 - CT changed)
+
+Count = 24
+Nonce = 4a5810b121c91b
+Adata = 00
+CT = a5977f0826926ec0d32541b2bd4e2b1e
+Result = Fail (1 - Adata changed)
+
+Count = 25
+Nonce = 44077341139bf9
+Adata = 00
+CT = 6938fb5afec1a84e4abb062e1a943c20
+Result = Fail (1 - Adata changed)
+
+Count = 26
+Nonce = a9df4f37847e1f
+Adata = 00
+CT = 7e3bbe0eb13988a93972f2fbcd35659e
+Result = Pass (0)
+Payload = 00
+
+Count = 27
+Nonce = 11df57fcd131e9
+Adata = 00
+CT = 48d7a15cf4f5808eb45d1ad817470554
+Result = Pass (0)
+Payload = 00
+
+Count = 28
+Nonce = 890fff56d10dc0
+Adata = 00
+CT = 97185ce68af1e6ab718c8c4b83ec04cd
+Result = Pass (0)
+Payload = 00
+
+Count = 29
+Nonce = 9dc18698731b27
+Adata = 00
+CT = a81bc8f5a18293ffe19505a3687ce3f3
+Result = Fail (2 - CT changed)
+
+[Alen = 0, Plen = 0, Nlen = 13, Tlen = 4]
+
+Key = 4bb3c4a4f893ad8c9bdc833c325d62b3d3ad1bccf9282a65
+
+Count = 30
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = fe69ed84
+Result = Pass (0)
+Payload = 00
+
+Count = 31
+Nonce = a16a2e741f1cd9717285b6d882
+Adata = 00
+CT = db7ffc82
+Result = Fail (2 - CT changed)
+
+Count = 32
+Nonce = 368f3b8180fd4b851b7b272cb1
+Adata = 00
+CT = 7a677329
+Result = Fail (1 - Adata changed)
+
+Count = 33
+Nonce = 7bb2bc00c0cafce65b5299ae64
+Adata = 00
+CT = d903d8f7
+Result = Fail (1 - Adata changed)
+
+Count = 34
+Nonce = 935c1ef3d4032ff090f91141f3
+Adata = 00
+CT = 215e0bf2
+Result = Pass (0)
+Payload = 00
+
+Count = 35
+Nonce = 2640b14f10b116411d1b5c1ad1
+Adata = 00
+CT = 0d38100f
+Result = Fail (2 - CT changed)
+
+Count = 36
+Nonce = b229c173a13b2d83af91ec45b0
+Adata = 00
+CT = 9f8ab5f7
+Result = Fail (1 - Adata changed)
+
+Count = 37
+Nonce = 37ca0dc2d6efd9efde69f14f03
+Adata = 00
+CT = 7d811d50
+Result = Fail (2 - CT changed)
+
+Count = 38
+Nonce = 6b6238aed86d677ba2b3e2622c
+Adata = 00
+CT = c2e18439
+Result = Fail (2 - CT changed)
+
+Count = 39
+Nonce = d6cb2ac67bb13b8f6d31fad64a
+Adata = 00
+CT = d8b5817b
+Result = Fail (1 - Adata changed)
+
+Count = 40
+Nonce = 32a7cd361ef00e65f5778fdfd4
+Adata = 00
+CT = 28cd70ff
+Result = Fail (1 - Adata changed)
+
+Count = 41
+Nonce = d0a1508fdefcf5be30a459b813
+Adata = 00
+CT = 790b2624
+Result = Pass (0)
+Payload = 00
+
+Count = 42
+Nonce = 5381a61b449dc6a42aa4c79b95
+Adata = 00
+CT = 9e46632d
+Result = Pass (0)
+Payload = 00
+
+Count = 43
+Nonce = c55430f2da0687ea40313884ab
+Adata = 00
+CT = 39b82901
+Result = Pass (0)
+Payload = 00
+
+Count = 44
+Nonce = ec76d1850acc0979a1f11906fb
+Adata = 00
+CT = 4c0cf71f
+Result = Fail (2 - CT changed)
+
+[Alen = 0, Plen = 0, Nlen = 13, Tlen = 16]
+
+Key = 19ebfde2d5468ba0a3031bde629b11fd4094afcb205393fa
+
+Count = 45
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = 0c66a8e547ed4f8c2c9a9a1eb5d455b9
+Result = Pass (0)
+Payload = 00
+
+Count = 46
+Nonce = a16a2e741f1cd9717285b6d882
+Adata = 00
+CT = 38757b3a61a4dc97ca3ab88bf1240695
+Result = Fail (2 - CT changed)
+
+Count = 47
+Nonce = 368f3b8180fd4b851b7b272cb1
+Adata = 00
+CT = 11875da4445d92391d0fab5f3625497b
+Result = Fail (1 - Adata changed)
+
+Count = 48
+Nonce = 7bb2bc00c0cafce65b5299ae64
+Adata = 00
+CT = 64477bcd4316e5c5789e1a678fdef943
+Result = Fail (1 - Adata changed)
+
+Count = 49
+Nonce = 935c1ef3d4032ff090f91141f3
+Adata = 00
+CT = 87da5dbc04e39fc468f43675d4e7df33
+Result = Pass (0)
+Payload = 00
+
+Count = 50
+Nonce = 2640b14f10b116411d1b5c1ad1
+Adata = 00
+CT = bf0d53ee529d8cafc5ad7a8f2d85e7a2
+Result = Fail (2 - CT changed)
+
+Count = 51
+Nonce = b229c173a13b2d83af91ec45b0
+Adata = 00
+CT = 676370637ad78c705d43fce066dc909f
+Result = Fail (1 - Adata changed)
+
+Count = 52
+Nonce = 37ca0dc2d6efd9efde69f14f03
+Adata = 00
+CT = 289936db0f9f148a3c9e2d28f7d7de51
+Result = Fail (2 - CT changed)
+
+Count = 53
+Nonce = 6b6238aed86d677ba2b3e2622c
+Adata = 00
+CT = 58a283641627669d5514f2af559b6c14
+Result = Fail (2 - CT changed)
+
+Count = 54
+Nonce = d6cb2ac67bb13b8f6d31fad64a
+Adata = 00
+CT = a6b058540ed905d6e3499a13ea1f3d83
+Result = Fail (1 - Adata changed)
+
+Count = 55
+Nonce = 32a7cd361ef00e65f5778fdfd4
+Adata = 00
+CT = 7a19b3377384f09915d0e1ae93a9f16c
+Result = Fail (1 - Adata changed)
+
+Count = 56
+Nonce = d0a1508fdefcf5be30a459b813
+Adata = 00
+CT = a0d047a1f9940d325e474da54aa13897
+Result = Pass (0)
+Payload = 00
+
+Count = 57
+Nonce = 5381a61b449dc6a42aa4c79b95
+Adata = 00
+CT = 8a4768a2093694b6bcb7083c0bb6331c
+Result = Pass (0)
+Payload = 00
+
+Count = 58
+Nonce = c55430f2da0687ea40313884ab
+Adata = 00
+CT = a7cafd6f68dc1f15a3603da654ce27bc
+Result = Pass (0)
+Payload = 00
+
+Count = 59
+Nonce = ec76d1850acc0979a1f11906fb
+Adata = 00
+CT = c49845f2ea3c9981ad7e9b942f615b8d
+Result = Fail (2 - CT changed)
+
+[Alen = 0, Plen = 24, Nlen = 7, Tlen = 4]
+
+Key = 19ebfde2d5468ba0a3031bde629b11fd4094afcb205393fa
+
+Count = 60
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = 411986d04d6463100bff03f7d0bde7ea2c3488784378138cddc93a54
+Result = Pass (0)
+Payload = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22
+
+Count = 61
+Nonce = 31f8fa25827d48
+Adata = 00
+CT = 32b649ab56162e55d4148a1292d6a225a988eb1308298273b6889036
+Result = Fail (2 - CT changed)
+
+Count = 62
+Nonce = 5340ed7752c9ff
+Adata = 00
+CT = a963c3568ab413b174cd95cc1e3ca61ee181292bebdb28179b4de35f
+Result = Fail (1 - Adata changed)
+
+Count = 63
+Nonce = 9cbce402511b89
+Adata = 00
+CT = 0396e6c8db43e5fac205f4c576fd577368adcb688cf3d7e76df9ffc5
+Result = Fail (1 - Adata changed)
+
+Count = 64
+Nonce = 123a0beace4e39
+Adata = 00
+CT = b41bfba94edcafc41b4c144269b9126a6d47b19e83b15772b28c8e38
+Result = Pass (0)
+Payload = 9d033e3b66efed1467868f382417c80594877a28bc97f406
+
+Count = 65
+Nonce = 8ea1594a58fe4a
+Adata = 00
+CT = 01e3bb938e16d0284d1d0fee049d80fb97356ae4d84127cf7336a30a
+Result = Fail (2 - CT changed)
+
+Count = 66
+Nonce = 5a7743e59e82da
+Adata = 00
+CT = abd7551c5e84e9bef5fbfad3e24d13f02864410eae9177ad0c40cc72
+Result = Fail (1 - Adata changed)
+
+Count = 67
+Nonce = f477f754d7ee76
+Adata = 00
+CT = 3b5ae49e0974f41826152432b46f1a85ab4995afefbbccddfc9fd290
+Result = Fail (2 - CT changed)
+
+Count = 68
+Nonce = 040a257dede70e
+Adata = 00
+CT = 21fb4324de4ba1e2762b3041ce26e43a3d191458a046d489e485910b
+Result = Fail (2 - CT changed)
+
+Count = 69
+Nonce = dd51b8e91683d1
+Adata = 00
+CT = 99ca8f542fd06481e23719214c9892442f393d72899deea08695053f
+Result = Fail (1 - Adata changed)
+
+Count = 70
+Nonce = ab3cb86cca6fb2
+Adata = 00
+CT = 5fcc05342cdc27f66b324ae7387205bfb4ab6302bfe0af09050d2054
+Result = Fail (1 - Adata changed)
+
+Count = 71
+Nonce = f67b98efd39b55
+Adata = 00
+CT = 0a7fe63046daf8a979935b897088c64acc1b47a5a9b86fdd6def28ab
+Result = Pass (0)
+Payload = f2e944e1ae47ad5873bf391f1b0cc07f6151eb4c50bb45b2
+
+Count = 72
+Nonce = e60e2c002d1c99
+Adata = 00
+CT = daf7d7dfa512ceb1d7d3435634d9a70b3ef6c6dc38f409e068941fce
+Result = Pass (0)
+Payload = 70f48dc1d76e5028da07e29852801375a9edb2214a5ea4c0
+
+Count = 73
+Nonce = 098e053fa08043
+Adata = 00
+CT = cdb417dff6502208775f21e35cdb8e3e1199308d1a94229051a1ec4a
+Result = Pass (0)
+Payload = bd81680e3dc0b35431c92598dcaa26ef09ca0da5e77193de
+
+Count = 74
+Nonce = 4bf48328725514
+Adata = 00
+CT = e75441093c8ccba6eac5913dc246ce96de4784a01051498298eaddaf
+Result = Fail (2 - CT changed)
+
+[Alen = 0, Plen = 24, Nlen = 7, Tlen = 16]
+
+Key = 197afb02ffbd8f699dacae87094d524324576b99844f75e1
+
+Count = 75
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = cba4b4aeb85f0492fd8d905c4a6d8233139833373ef188a8c5a5ebecf7ac8607fe412189e83d9d20
+Result = Pass (0)
+Payload = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22
+
+Count = 76
+Nonce = 31f8fa25827d48
+Adata = 00
+CT = ca62713728b5c9d652504b0ae8fd4fee5d297ee6a8d19cb6e699f15f14d34dcaf9ba8ed4b877c97d
+Result = Fail (2 - CT changed)
+
+Count = 77
+Nonce = 5340ed7752c9ff
+Adata = 00
+CT = 93012c0a5f6f1025b8c4a5d897d3eea0b1c77be8000c9e59f3b8899459788c58794f177cfd838f35
+Result = Fail (1 - Adata changed)
+
+Count = 78
+Nonce = 9cbce402511b89
+Adata = 00
+CT = b8eb95f72f643c2c51ad74775cc203d215c86626e903eb013ad22e8fa4d2f9725ce4f212a8844855
+Result = Fail (1 - Adata changed)
+
+Count = 79
+Nonce = 123a0beace4e39
+Adata = 00
+CT = 71f17cf21c44267c676657db9e55bee33273787474e77b17b5eab45d7d096577643815e6d467312d
+Result = Pass (0)
+Payload = 9d033e3b66efed1467868f382417c80594877a28bc97f406
+
+Count = 80
+Nonce = 8ea1594a58fe4a
+Adata = 00
+CT = d6737f642260c4ee3b19cb78cc2ef1767213416b82c71e918b1a5ecca7354af824fea617b9b69031
+Result = Fail (2 - CT changed)
+
+Count = 81
+Nonce = 5a7743e59e82da
+Adata = 00
+CT = cbe60d633399daa6ee66418be6d16e292ea47a93c291fce2c54c98f8007ed55a21759f5452559538
+Result = Fail (1 - Adata changed)
+
+Count = 82
+Nonce = f477f754d7ee76
+Adata = 00
+CT = 2a78a7beb8df4bf5d35ff0b2853bc51ce127163d2f56e00ea555aa972e1c2e3f439f85663ae25889
+Result = Fail (2 - CT changed)
+
+Count = 83
+Nonce = 040a257dede70e
+Adata = 00
+CT = ee78ddbea9c3aede9f88af0e82464d9d1afe81de16aa18c49aeb326578fa615e86969348d9bbfb7f
+Result = Fail (2 - CT changed)
+
+Count = 84
+Nonce = dd51b8e91683d1
+Adata = 00
+CT = cdf7cb74d978e7ea738e288ed79edfccf10b553c09d1856e2efbff1da769af3b72099cbda3cbf091
+Result = Fail (1 - Adata changed)
+
+Count = 85
+Nonce = ab3cb86cca6fb2
+Adata = 00
+CT = 90b990a1ea254592f2c226c969b332fc7bfe5f808729c2d83291a566e6641a965ffdabe097050dc5
+Result = Fail (1 - Adata changed)
+
+Count = 86
+Nonce = f67b98efd39b55
+Adata = 00
+CT = 44a6aa954c3508b3c9264c20c272e80c0e95d50ddec2849084b47504dced5b70c302cc93502cc37e
+Result = Pass (0)
+Payload = f2e944e1ae47ad5873bf391f1b0cc07f6151eb4c50bb45b2
+
+Count = 87
+Nonce = e60e2c002d1c99
+Adata = 00
+CT = 9d4ff7a44cdb9b14f586efc3d6be02d069b425c06bec4eed37109739a3676f03adfd740dbaa4940d
+Result = Pass (0)
+Payload = 70f48dc1d76e5028da07e29852801375a9edb2214a5ea4c0
+
+Count = 88
+Nonce = 098e053fa08043
+Adata = 00
+CT = 23da95e102c7921a51b19b5733ea5776ab6c287f6057c00ec4bfacbb2f246b570efd93d98e99be49
+Result = Pass (0)
+Payload = bd81680e3dc0b35431c92598dcaa26ef09ca0da5e77193de
+
+Count = 89
+Nonce = 4bf48328725514
+Adata = 00
+CT = 53d00d5839d0a1e695916151f9450b7311982917edcbd7c66496912db41761a1d2aecfda04fb2cfa
+Result = Fail (2 - CT changed)
+
+[Alen = 0, Plen = 24, Nlen = 13, Tlen = 4]
+
+Key = 197afb02ffbd8f699dacae87094d524324576b99844f75e1
+
+Count = 90
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = 042653c674ef2a90f7fb11d30848e530ae59478f1051633a34fad277
+Result = Pass (0)
+Payload = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697
+
+Count = 91
+Nonce = 49004912fdd7269279b1f06a89
+Adata = 00
+CT = 1902d9769a7ba3d3268e1257395c8c2e5f98eef295dcbfa5a35df775
+Result = Fail (2 - CT changed)
+
+Count = 92
+Nonce = efeb82c8c68d6600b24dd6d8ee
+Adata = 00
+CT = ebacb8e78c0ad9d3ed99f1821b0b0085beac351f88a79ef71faaf310
+Result = Fail (1 - Adata changed)
+
+Count = 93
+Nonce = 7b93d368dc551640b00ba3cbb5
+Adata = 00
+CT = efc1d5b6f0a48e4ce3e821d743d34206b28c69485c410fa94d5e6103
+Result = Fail (1 - Adata changed)
+
+Count = 94
+Nonce = 24b7a65391f88bea38fcd54a9a
+Adata = 00
+CT = 3c1836e5d0f0473dab7bfd7a95ba69575f7f841970ac6c6769ac966a
+Result = Pass (0)
+Payload = 43419715cef9a48dc7280bc035082a6581afd1d82bee9d1a
+
+Count = 95
+Nonce = 6aa3f731522fce7e366ba59945
+Adata = 00
+CT = 2c583e54d75a02948c7f6dcd12cba32a65e8d605fba7ec10c47e9a8e
+Result = Fail (2 - CT changed)
+
+Count = 96
+Nonce = a11cf5bed0041ee3cb1fef4b43
+Adata = 00
+CT = a8632dee22f34315b05c40135c6dd471c63b09438da834dc1f3f537f
+Result = Fail (1 - Adata changed)
+
+Count = 97
+Nonce = 273cc5013785baeb5abc79c8bd
+Adata = 00
+CT = 0f03ea1b2561951d79062e19a85d98293c8c2846936c724c26421940
+Result = Fail (2 - CT changed)
+
+Count = 98
+Nonce = d2d4482ea8e98c1cf309671895
+Adata = 00
+CT = f9764405e54d827ac433fd624506b92e123463a5b01f21ffa3a22ac7
+Result = Fail (2 - CT changed)
+
+Count = 99
+Nonce = a8849b44adb48d271979656930
+Adata = 00
+CT = a326e0cf3f97adff3249944880ddfb8d616cd18a086e046289429246
+Result = Fail (1 - Adata changed)
+
+Count = 100
+Nonce = a632ba0d00511122abcd6227ff
+Adata = 00
+CT = f188bc1a72e81b34d75b402e4f8ef3d638d2f56a409eab064c9649b7
+Result = Fail (1 - Adata changed)
+
+Count = 101
+Nonce = c47af80cd26d047630c1fdf0d1
+Adata = 00
+CT = 341df3a273e85cf387ab823bdf9c34a1ae2c86940cb4bfcde2e93f29
+Result = Pass (0)
+Payload = d8306c9c4ea6c69c6e2ad0fc0e49b1e0126b01078d6419ff
+
+Count = 102
+Nonce = 70e132023acae1f88c7a237b68
+Adata = 00
+CT = a0e7997fd67ea66b6274d719b84da92433fdf7d512b160da35c7081d
+Result = Pass (0)
+Payload = d0b2bef5ed1a87d9c73d4a459cb05c11799c4f51ad640b1e
+
+Count = 103
+Nonce = 8010d3a2a14f72f5585defc940
+Adata = 00
+CT = dd8fd11e1c0746e7273fdd2e7dfa1ee4fc8ad835ca3141c0f83a9ad7
+Result = Pass (0)
+Payload = 4faba05569bf7ac656780c16995e9122e565fe9984be8a68
+
+Count = 104
+Nonce = a98c2f0e0a7b68942853905191
+Adata = 00
+CT = 39b0d3603f1289b5885ac244953275d28491952e7e57d93c7ff1eb5d
+Result = Fail (2 - CT changed)
+
+[Alen = 0, Plen = 24, Nlen = 13, Tlen = 16]
+
+Key = 90929a4b0ac65b350ad1591611fe48297e03956f6083e451
+
+Count = 105
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = a5b7d8cca2069908d1ed88e6a9fe2c9bede3131dad54671ea7ade30a07d185692ab0ebdf4c78cf7a
+Result = Pass (0)
+Payload = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697
+
+Count = 106
+Nonce = 49004912fdd7269279b1f06a89
+Adata = 00
+CT = 9a98617fb97a0dfe466be692272dcdaec1c5443a3b51312ef042c86363cc05afb98c66e16be8a445
+Result = Fail (2 - CT changed)
+
+Count = 107
+Nonce = efeb82c8c68d6600b24dd6d8ee
+Adata = 00
+CT = d3068ae815c3605d7670058abb9384f4c15b75150eb7910041a8f6ac697430627826bd76b19da027
+Result = Fail (1 - Adata changed)
+
+Count = 108
+Nonce = 7b93d368dc551640b00ba3cbb5
+Adata = 00
+CT = 388a289bb85533b667b141a78d0c79acdeb9fbf72886d5ab980581017fefef92c2b50ae20b93c81c
+Result = Fail (1 - Adata changed)
+
+Count = 109
+Nonce = 24b7a65391f88bea38fcd54a9a
+Adata = 00
+CT = 71f68480a8801d4966c84807c5ff6139d83ba0a5b902bee3327f5f91763c0a0bec43264c27cd237f
+Result = Pass (0)
+Payload = 43419715cef9a48dc7280bc035082a6581afd1d82bee9d1a
+
+Count = 110
+Nonce = 6aa3f731522fce7e366ba59945
+Adata = 00
+CT = 8627bf1e3edafc69f1328c393dd8e7bd1c182d021e6d3a3652c4b7fd911ca77950ff2d035e47b7ec
+Result = Fail (2 - CT changed)
+
+Count = 111
+Nonce = a11cf5bed0041ee3cb1fef4b43
+Adata = 00
+CT = b10ea86a384432a45f50b3c2e482595b46c81c61ca39bc0f4ffcb29bde8b9a81945d671b0f619045
+Result = Fail (1 - Adata changed)
+
+Count = 112
+Nonce = 273cc5013785baeb5abc79c8bd
+Adata = 00
+CT = 3ace8b7e03a0c1fa9e97f46975ab0a4924446e791540e225578cc14aa558e18d5f777ab6e16dcfee
+Result = Fail (2 - CT changed)
+
+Count = 113
+Nonce = d2d4482ea8e98c1cf309671895
+Adata = 00
+CT = 8190abe4c21e320e10825e269190bb10a354691958e2436275433c4ae28757c8544c86f1f74ea6a5
+Result = Fail (2 - CT changed)
+
+Count = 114
+Nonce = a8849b44adb48d271979656930
+Adata = 00
+CT = 1d7e308c34cdca7b7b222f4ebc92afd8055bff542c0b76d3d7752ebe9c5dbf00ee8ad60ac34dd7d0
+Result = Fail (1 - Adata changed)
+
+Count = 115
+Nonce = a632ba0d00511122abcd6227ff
+Adata = 00
+CT = 9c2609f7af5b634a16e58f2e9cc7a9ef7812a12d209847000a4432b35d3b884e4169c28d287499ff
+Result = Fail (1 - Adata changed)
+
+Count = 116
+Nonce = c47af80cd26d047630c1fdf0d1
+Adata = 00
+CT = 5b0b5e6690d648e1b92c12cfddb431d6d3dfe689d01db8199256ace490c2f0afb93ba32be58fd1de
+Result = Pass (0)
+Payload = d8306c9c4ea6c69c6e2ad0fc0e49b1e0126b01078d6419ff
+
+Count = 117
+Nonce = 70e132023acae1f88c7a237b68
+Adata = 00
+CT = 8722fca71fdf750ec5d62fc6d7ba079aef19210da764067aefd8535dd6b7fa701c9ca8c8b635c30b
+Result = Pass (0)
+Payload = d0b2bef5ed1a87d9c73d4a459cb05c11799c4f51ad640b1e
+
+Count = 118
+Nonce = 8010d3a2a14f72f5585defc940
+Adata = 00
+CT = 91ac457f5e53492301e72d9d495277ed17edb30e8c7a48d21b5d2cd4d5b6d2ef48413245a6b27b67
+Result = Pass (0)
+Payload = 4faba05569bf7ac656780c16995e9122e565fe9984be8a68
+
+Count = 119
+Nonce = a98c2f0e0a7b68942853905191
+Adata = 00
+CT = d2fe5293b7d53ed46ddf02a5618039adbae22845ce72e434fdc83ea4863c3e84a5456f7f853a1ea6
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 0, Nlen = 7, Tlen = 4]
+
+Key = 90929a4b0ac65b350ad1591611fe48297e03956f6083e451
+
+Count = 120
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = 1d089a5f
+Result = Pass (0)
+Payload = 00
+
+Count = 121
+Nonce = a265480ca88d5f
+Adata = a2248a882ecbf850daf91933a389e78e81623d233dfd47bf8321361a38f138fe
+CT = 2f46022a
+Result = Fail (2 - CT changed)
+
+Count = 122
+Nonce = 87ec7423f1ebfc
+Adata = 2bed1ec06c1ca149d9ffbaf048c474ea2de000eb7950f18d6c25acf6ab3f19b5
+CT = 67dc4693
+Result = Fail (1 - Adata changed)
+
+Count = 123
+Nonce = b8b04f90616082
+Adata = 4898731e143fcc677c7cf1a8f2b3c4039fb5e57028e33b05e097d1763cbfe4d8
+CT = 7027a849
+Result = Fail (1 - Adata changed)
+
+Count = 124
+Nonce = 8c687b4318813a
+Adata = fcad52a88544325bb31eb5de4a41dbff6a96f69d0993b969a01792ee23953acf
+CT = 5c6a4de2
+Result = Pass (0)
+Payload = 00
+
+Count = 125
+Nonce = 29b810eed8fc92
+Adata = 40d1d320eb63a25d7a2b3141563a552114275ddda56beb62cc0c0273d5795faa
+CT = 1d855f5d
+Result = Fail (2 - CT changed)
+
+Count = 126
+Nonce = 62452462c53934
+Adata = 1eb8863ea100babc1713654afcf54f21f8bff754223ad70269ace9d034f26a96
+CT = 1b318980
+Result = Fail (1 - Adata changed)
+
+Count = 127
+Nonce = 4cceba0e7aee97
+Adata = f33e184c967165eb62542999afaca4e3e319840e439b5bb509544fb4b6901445
+CT = cf871f91
+Result = Fail (2 - CT changed)
+
+Count = 128
+Nonce = b5151b0601c683
+Adata = 73d27303ec91f28c79b278882034d11eb6a5266746f37edbb77f8409a8738b8c
+CT = 4f0e04bc
+Result = Fail (2 - CT changed)
+
+Count = 129
+Nonce = 4e5d6d7ac9e71e
+Adata = a01b6e152fe232b6c10b5d89900961c445f4c46833df242c826678b68c869811
+CT = fc9013df
+Result = Fail (1 - Adata changed)
+
+Count = 130
+Nonce = dc88e989951a3f
+Adata = fdcacfaff46585406cc45a2da364e67e132a91c98900a8f9d7bfb14ec951fca5
+CT = 5134def3
+Result = Fail (1 - Adata changed)
+
+Count = 131
+Nonce = a1aeda4b4cb8dd
+Adata = db3022ef4cd68ae22b501599448ffe2dda15cfd2e259315c6f6d03036edea963
+CT = 5814103a
+Result = Pass (0)
+Payload = 00
+
+Count = 132
+Nonce = f248e5225e3d9a
+Adata = fdc64ef76a3bfd0a15d0bc8e8bacaf64346796a3e35afcf2ac1ab136f63f7b6e
+CT = 74c75c4a
+Result = Pass (0)
+Payload = 00
+
+Count = 133
+Nonce = e68228f5c65b73
+Adata = 614efdf89ce2a9fcbd38bdc0b4cece54dfd7532880e0b4ce6eb3a4010b7cb1e7
+CT = 9884898b
+Result = Pass (0)
+Payload = 00
+
+Count = 134
+Nonce = ea167cfd1101d9
+Adata = 28130f938c45a1a92b02dbeadbd8df816b6d934e87cca2dfdbfdc49c7cd84041
+CT = 0b1cbfb1
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 0, Nlen = 7, Tlen = 16]
+
+Key = 6a798d7c5e1a72b43e20ad5c7b08567b12ab744b61c070e2
+
+Count = 135
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = 5280a2137fee3deefcfe9b63a1199fb3
+Result = Pass (0)
+Payload = 00
+
+Count = 136
+Nonce = a265480ca88d5f
+Adata = a2248a882ecbf850daf91933a389e78e81623d233dfd47bf8321361a38f138fe
+CT = d40a7318c5f2d82f838c0beeefe0d598
+Result = Fail (2 - CT changed)
+
+Count = 137
+Nonce = 87ec7423f1ebfc
+Adata = 2bed1ec06c1ca149d9ffbaf048c474ea2de000eb7950f18d6c25acf6ab3f19b5
+CT = 7551978bc9592bf9e294b4984c5862bb
+Result = Fail (1 - Adata changed)
+
+Count = 138
+Nonce = b8b04f90616082
+Adata = 4898731e143fcc677c7cf1a8f2b3c4039fb5e57028e33b05e097d1763cbfe4d8
+CT = 859cf444f89225b32a55a1645bd24979
+Result = Fail (1 - Adata changed)
+
+Count = 139
+Nonce = 8c687b4318813a
+Adata = fcad52a88544325bb31eb5de4a41dbff6a96f69d0993b969a01792ee23953acf
+CT = 29e967a0245607c36cf3eaf00fdae566
+Result = Pass (0)
+Payload = 00
+
+Count = 140
+Nonce = 29b810eed8fc92
+Adata = 40d1d320eb63a25d7a2b3141563a552114275ddda56beb62cc0c0273d5795faa
+CT = 9daa0e1c4df5f2bf507b1a57a1135b86
+Result = Fail (2 - CT changed)
+
+Count = 141
+Nonce = 62452462c53934
+Adata = 1eb8863ea100babc1713654afcf54f21f8bff754223ad70269ace9d034f26a96
+CT = 18caec79720a5d67d7457e9b7c7a153c
+Result = Fail (1 - Adata changed)
+
+Count = 142
+Nonce = 4cceba0e7aee97
+Adata = f33e184c967165eb62542999afaca4e3e319840e439b5bb509544fb4b6901445
+CT = 5f2c455546c56f514a0f69f05345c2c4
+Result = Fail (2 - CT changed)
+
+Count = 143
+Nonce = b5151b0601c683
+Adata = 73d27303ec91f28c79b278882034d11eb6a5266746f37edbb77f8409a8738b8c
+CT = b7e4846ff30b7c3673a962a2701c0387
+Result = Fail (2 - CT changed)
+
+Count = 144
+Nonce = 4e5d6d7ac9e71e
+Adata = a01b6e152fe232b6c10b5d89900961c445f4c46833df242c826678b68c869811
+CT = 7b5fa0d42a616ab05ac2c58c904ce92f
+Result = Fail (1 - Adata changed)
+
+Count = 145
+Nonce = dc88e989951a3f
+Adata = fdcacfaff46585406cc45a2da364e67e132a91c98900a8f9d7bfb14ec951fca5
+CT = c8c67f558b5844b149dd47824c8cb9d8
+Result = Fail (1 - Adata changed)
+
+Count = 146
+Nonce = a1aeda4b4cb8dd
+Adata = db3022ef4cd68ae22b501599448ffe2dda15cfd2e259315c6f6d03036edea963
+CT = 70a09aaf22ac316124a169f6b0a83ffe
+Result = Pass (0)
+Payload = 00
+
+Count = 147
+Nonce = f248e5225e3d9a
+Adata = fdc64ef76a3bfd0a15d0bc8e8bacaf64346796a3e35afcf2ac1ab136f63f7b6e
+CT = 5bc85ed5521a91b9eb42b437950f0e06
+Result = Pass (0)
+Payload = 00
+
+Count = 148
+Nonce = e68228f5c65b73
+Adata = 614efdf89ce2a9fcbd38bdc0b4cece54dfd7532880e0b4ce6eb3a4010b7cb1e7
+CT = 989ec0e7b192ea010dd61d3fb64e8de0
+Result = Pass (0)
+Payload = 00
+
+Count = 149
+Nonce = ea167cfd1101d9
+Adata = 28130f938c45a1a92b02dbeadbd8df816b6d934e87cca2dfdbfdc49c7cd84041
+CT = 15c2dbe7fa307654d8ca7c0f8d6d2f14
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 0, Nlen = 13, Tlen = 4]
+
+Key = 6a798d7c5e1a72b43e20ad5c7b08567b12ab744b61c070e2
+
+Count = 150
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = 5e0eaebd
+Result = Pass (0)
+Payload = 00
+
+Count = 151
+Nonce = 8739b4bea1a099fe547499cbc6
+Adata = f6107696edb332b2ea059d8860fee26be42e5e12e1a4f79a8d0eafce1b2278a7
+CT = 71b7fc33
+Result = Fail (2 - CT changed)
+
+Count = 152
+Nonce = 0f98fdbde2b04387f27b3401dd
+Adata = 02010329660fa716556193eb4870ee84bd934296a5c52d92bba859cc13caaddc
+CT = 93227bd4
+Result = Fail (1 - Adata changed)
+
+Count = 153
+Nonce = 4eed58f381e500902ba5c56864
+Adata = 96056d9ebd7c553c22cc2d9d816b61123750d96c1b08c4b661079424bf3c4946
+CT = ced654e2
+Result = Fail (1 - Adata changed)
+
+Count = 154
+Nonce = 1e7e51f0fa9a33ed618c26f5e3
+Adata = da9b8ffb0f3c2aee2e386cc9f035ec1eb3e629bd1544c11dc21be4fd8ac9074a
+CT = bf7a8e0c
+Result = Pass (0)
+Payload = 00
+
+Count = 155
+Nonce = f012f94f5988c79aa179d7fdfc
+Adata = 612b2ef2683109d99452f95099417641d0c2be3f8ab4cbb2a44e83355ba9303c
+CT = 840caa3e
+Result = Fail (2 - CT changed)
+
+Count = 156
+Nonce = 715acf92cfb69ad56036c49e70
+Adata = 960667b85be07304634124b9324be12a1c11451f1fa9db82c683265b4cf8e5ff
+CT = 1e22fc41
+Result = Fail (1 - Adata changed)
+
+Count = 157
+Nonce = 141be3601e38185a9fa1596d2e
+Adata = 606452c62290b43559a588bb03356f846cecb0ccaf0bdaf67a18abd811d4315a
+CT = 968ccbbf
+Result = Fail (2 - CT changed)
+
+Count = 158
+Nonce = fcdda3c5f0e80843b03d8788da
+Adata = 03f22247a55461a293d253c77483859fdac1b87c2480e208a3df767cfbfde512
+CT = 0a31cc96
+Result = Fail (2 - CT changed)
+
+Count = 159
+Nonce = ca660ed3b917c0aca140dcd3fb
+Adata = 254a86f5b20d344ad86fd5523d08f1864737be57731440c29aa6b42574572f51
+CT = a456c3da
+Result = Fail (1 - Adata changed)
+
+Count = 160
+Nonce = 642ae3466661ce1f51783deece
+Adata = 4432a1cec5976cc13b8fb78341d426c2248f091b597123d263ffafc7f82da5a5
+CT = 29746eea
+Result = Fail (1 - Adata changed)
+
+Count = 161
+Nonce = 7864c717ec93db38b10679be47
+Adata = 679aad1ad1e57029e3362b325572fc71cac53184b0f1546867e665a4a59466c4
+CT = df7f63ca
+Result = Pass (0)
+Payload = 00
+
+Count = 162
+Nonce = c3bf9dfe9d6c26f543188fb457
+Adata = e301f69ad3a7e08a3d02462f0aa584449eb0449b0e3c50aa8dfaa4472816c8b0
+CT = bf0b1445
+Result = Pass (0)
+Payload = 00
+
+Count = 163
+Nonce = 1527657d2fd98f7deca55cc649
+Adata = f4c723433b7cafe3cda9bb4940a21a89a8382d13018b622ccd1ffb9ffd3211af
+CT = ae8533f5
+Result = Pass (0)
+Payload = 00
+
+Count = 164
+Nonce = b8432d3d5525a0dadbbaa6b6b8
+Adata = 86ee6e37b4a2d9a0b52ec95643b4e8297e237721e15ce8bf7593a98644f83eba
+CT = 9426cf89
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 0, Nlen = 13, Tlen = 16]
+
+Key = f9fdca4ac64fe7f014de0f43039c757194d544ce5d15eed4
+
+Count = 165
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = d07ccf9fdc3d33aa94cda3d230da707c
+Result = Pass (0)
+Payload = 00
+
+Count = 166
+Nonce = 8739b4bea1a099fe547499cbc6
+Adata = f6107696edb332b2ea059d8860fee26be42e5e12e1a4f79a8d0eafce1b2278a7
+CT = 65fe32b649dc328c9f531584897e85b3
+Result = Fail (2 - CT changed)
+
+Count = 167
+Nonce = 0f98fdbde2b04387f27b3401dd
+Adata = 02010329660fa716556193eb4870ee84bd934296a5c52d92bba859cc13caaddc
+CT = ec31fb6b41c2dae87cf395fc1fe3a080
+Result = Fail (1 - Adata changed)
+
+Count = 168
+Nonce = 4eed58f381e500902ba5c56864
+Adata = 96056d9ebd7c553c22cc2d9d816b61123750d96c1b08c4b661079424bf3c4946
+CT = 33c2f2312dd5bfcadbb05f8d0a33fd4a
+Result = Fail (1 - Adata changed)
+
+Count = 169
+Nonce = 1e7e51f0fa9a33ed618c26f5e3
+Adata = da9b8ffb0f3c2aee2e386cc9f035ec1eb3e629bd1544c11dc21be4fd8ac9074a
+CT = a9e81afd1030d195c679e2c837aeb736
+Result = Pass (0)
+Payload = 00
+
+Count = 170
+Nonce = f012f94f5988c79aa179d7fdfc
+Adata = 612b2ef2683109d99452f95099417641d0c2be3f8ab4cbb2a44e83355ba9303c
+CT = 1db000f0e7d3a03718293fc118678427
+Result = Fail (2 - CT changed)
+
+Count = 171
+Nonce = 715acf92cfb69ad56036c49e70
+Adata = 960667b85be07304634124b9324be12a1c11451f1fa9db82c683265b4cf8e5ff
+CT = ea37900f049db8fc5cbf46edb5fcac2c
+Result = Fail (1 - Adata changed)
+
+Count = 172
+Nonce = 141be3601e38185a9fa1596d2e
+Adata = 606452c62290b43559a588bb03356f846cecb0ccaf0bdaf67a18abd811d4315a
+CT = d1097ebd7ad0a41f61ba32a44dc15305
+Result = Fail (2 - CT changed)
+
+Count = 173
+Nonce = fcdda3c5f0e80843b03d8788da
+Adata = 03f22247a55461a293d253c77483859fdac1b87c2480e208a3df767cfbfde512
+CT = 0979729272d8b42f2e3dc0eb181a1217
+Result = Fail (2 - CT changed)
+
+Count = 174
+Nonce = ca660ed3b917c0aca140dcd3fb
+Adata = 254a86f5b20d344ad86fd5523d08f1864737be57731440c29aa6b42574572f51
+CT = 4457200916a20116b096225606f1a9e2
+Result = Fail (1 - Adata changed)
+
+Count = 175
+Nonce = 642ae3466661ce1f51783deece
+Adata = 4432a1cec5976cc13b8fb78341d426c2248f091b597123d263ffafc7f82da5a5
+CT = cc6b51f39a3dcfb54abbb89f4df21114
+Result = Fail (1 - Adata changed)
+
+Count = 176
+Nonce = 7864c717ec93db38b10679be47
+Adata = 679aad1ad1e57029e3362b325572fc71cac53184b0f1546867e665a4a59466c4
+CT = aac09cef9697927331251f028d24c31f
+Result = Pass (0)
+Payload = 00
+
+Count = 177
+Nonce = c3bf9dfe9d6c26f543188fb457
+Adata = e301f69ad3a7e08a3d02462f0aa584449eb0449b0e3c50aa8dfaa4472816c8b0
+CT = 56c00070eae0db329894a045d866bbaf
+Result = Pass (0)
+Payload = 00
+
+Count = 178
+Nonce = 1527657d2fd98f7deca55cc649
+Adata = f4c723433b7cafe3cda9bb4940a21a89a8382d13018b622ccd1ffb9ffd3211af
+CT = 090016bb96aeaabbf66fd34fc97591a4
+Result = Pass (0)
+Payload = 00
+
+Count = 179
+Nonce = b8432d3d5525a0dadbbaa6b6b8
+Adata = 86ee6e37b4a2d9a0b52ec95643b4e8297e237721e15ce8bf7593a98644f83eba
+CT = 264407dfe796bf7f6eb1f26c1f8504ef
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 24, Nlen = 7, Tlen = 4]
+
+Key = f9fdca4ac64fe7f014de0f43039c757194d544ce5d15eed4
+
+Count = 180
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = 9f6ca4af9b159148c889a6584d1183ea26e2614874b0504575dea8d1
+Result = Pass (0)
+Payload = a265480ca88d5f536db0dc6abc40faf0d05be7a966977768
+
+Count = 181
+Nonce = fdd2d6f503c915
+Adata = 5b92394f21ddc3ad49d9b0881b829a5935cb3a4d23e292a62fb66b5e7ab7020e
+CT = 84d8212e9cfc2121252baa3b065b1edcf50497b9594db1ebd7965825
+Result = Fail (2 - CT changed)
+
+Count = 182
+Nonce = 27d73d58100054
+Adata = f6468542923be79b4b06dfe70920d57d1da73a9c16f9c9a12d810d7de0d12467
+CT = 5f60a8f867a33b2077ecc69863b295c3c6aeae7d7cade7f8f7f796fe
+Result = Fail (1 - Adata changed)
+
+Count = 183
+Nonce = dd16e0ce1250e3
+Adata = bc65cfd65e9863c8b7457d58afa6bdb48a84170d8aa97ba5b397b52ad17a9242
+CT = 1353b3fa1bb1d57ffb139017885c02e26c90231a24b5a615b8f1f2ae
+Result = Fail (1 - Adata changed)
+
+Count = 184
+Nonce = ccee19d037cf4a
+Adata = c026696e6425e6c33f45b4145febf1137e7ac26383c9f5aa4cd4e5e8abb19e07
+CT = c3116d9040e1ed4f7c9464d270fb302bd3f1561c25c5b95b8b4b53f6
+Result = Pass (0)
+Payload = 0df202431ee7f251a38aaf6aa8cd313782bd293af9114005
+
+Count = 185
+Nonce = 6c8ba94f09cbe6
+Adata = 774ad1a88f8bb063951486d4aec5bf82d5fc535bd0b952f86200c123c37fa496
+CT = 0ca17e8f89bea67db48a8f132ef6c6df7a292914d401299af6bf3800
+Result = Fail (2 - CT changed)
+
+Count = 186
+Nonce = 1f670302fcdcc8
+Adata = 1a9ff9698cfc96b581d7115c822e4363d7355ec5daed2eae5bf89ee944ac7d9c
+CT = 0ce543569e8187f3cec70399ff922e4903cb1d12f990f05613244cf6
+Result = Fail (1 - Adata changed)
+
+Count = 187
+Nonce = 5d05f658c729a2
+Adata = dd9564c1431ed490b17ef69f6115805e54ef156ef4e10e58f7d57a7e86626352
+CT = 3acdbc163a350f312791b152a41e57627b1cc8bf3e41c8aea5876de8
+Result = Fail (2 - CT changed)
+
+Count = 188
+Nonce = 22a77db9fcbc95
+Adata = 86bf1739c10f63df734ee3e60ac40ff5636c49f68ca4c16ece289609eb413e7a
+CT = 604518e436edf7a0561d5e284f3915839a6d28cb06ef792a1970ed17
+Result = Fail (2 - CT changed)
+
+Count = 189
+Nonce = 491e32b0bbfa4c
+Adata = 75bef075c79d6cfd7fc73aefd67b2d215be0648937477ba606b1fe1be591239e
+CT = fc79b520d67da891e63654d7927db6c8012c96985a0059d5f68d8da4
+Result = Fail (1 - Adata changed)
+
+Count = 190
+Nonce = bc4b7d3a380be0
+Adata = 353dbb41e2d525a9f4fcd858d0f0aa1b1e86ac0f936d5c09c6b61c343f94e3fc
+CT = d86bb51a98770098d0feb39170bd979199a8f741041df13790ee4c14
+Result = Fail (1 - Adata changed)
+
+Count = 191
+Nonce = a840e98df72ae9
+Adata = 22c6607732ef1bdc7fcf6197e037cdadd7ee17c008552dd9f04b8564d34fb17c
+CT = 51b6b928bdd1cc0bd0a0aed2cda302472d618ffaa60e179029c87855
+Result = Pass (0)
+Payload = a2f53385618b41301f4e3ea4c597f411103dac2b37abf5da
+
+Count = 192
+Nonce = 39d93c3cf31a6f
+Adata = 937dfac5cded938438f4e97aabd9beb50dba40f824198260a89729479cfe6869
+CT = d0abab9b8e9d6c11bb9c15bea8a486704bed32c57297055b4de8ed8d
+Result = Pass (0)
+Payload = c1bdef96dc868446be48491b160504546f2a40dd581f9582
+
+Count = 193
+Nonce = 0bbc177019321e
+Adata = f6e02678820f5ccbede6cbded02d6dd58d486166d7b18ee975a688af421fb795
+CT = 92fd519a966c0fbdd7087ff5a1bd946cd663502db378383531d69947
+Result = Pass (0)
+Payload = 72a70954d22ad722fc32756afce67b344b2f3c55fe1d9eed
+
+Count = 194
+Nonce = ad048eb2ad7526
+Adata = 0d2739cfdac782b61f484fa1a423c478c414397ec420327963d79112b2d70a7e
+CT = 7f239b1916830161f3b52b7ab13542a5a0a97a17f30ca5fa30768d4d
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 24, Nlen = 7, Tlen = 16]
+
+Key = a7aa635ea51b0bb20a092bd5573e728ccd4b3e8cdd2ab33d
+
+Count = 195
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = 6aab64c4787599d8f213446beadb16e08dba60e97f56dbd14d1d980d6fe0fb44b421992662b97975
+Result = Pass (0)
+Payload = a265480ca88d5f536db0dc6abc40faf0d05be7a966977768
+
+Count = 196
+Nonce = fdd2d6f503c915
+Adata = 5b92394f21ddc3ad49d9b0881b829a5935cb3a4d23e292a62fb66b5e7ab7020e
+CT = 4980b2ee49b1aaf393175f5ab9bae95ec7904557dfa206603c51d36c826f01384100886198a7f6a3
+Result = Fail (2 - CT changed)
+
+Count = 197
+Nonce = 27d73d58100054
+Adata = f6468542923be79b4b06dfe70920d57d1da73a9c16f9c9a12d810d7de0d12467
+CT = 86a02bdd6ae733eee26f8eab898b336105978b5bbd6df781758a111aae4f735b7dd4d9802f2a8406
+Result = Fail (1 - Adata changed)
+
+Count = 198
+Nonce = dd16e0ce1250e3
+Adata = bc65cfd65e9863c8b7457d58afa6bdb48a84170d8aa97ba5b397b52ad17a9242
+CT = 59cfab8956813c48e09332a2bb8a30dbcdf5afb2529532ab8cef14ebc2951069739d5d657d82addb
+Result = Fail (1 - Adata changed)
+
+Count = 199
+Nonce = ccee19d037cf4a
+Adata = c026696e6425e6c33f45b4145febf1137e7ac26383c9f5aa4cd4e5e8abb19e07
+CT = 67d989ea935b9ce190e3a7f3b645305e1e308a7fe617f80f170a2b9c309de6c2326115a76efbdf98
+Result = Pass (0)
+Payload = 0df202431ee7f251a38aaf6aa8cd313782bd293af9114005
+
+Count = 200
+Nonce = 6c8ba94f09cbe6
+Adata = 774ad1a88f8bb063951486d4aec5bf82d5fc535bd0b952f86200c123c37fa496
+CT = 2522a5e4d157193ef2c264cfe877db8ac75b3cc5aab08a814bcd14af0205af716f2b864f0c397f65
+Result = Fail (2 - CT changed)
+
+Count = 201
+Nonce = 1f670302fcdcc8
+Adata = 1a9ff9698cfc96b581d7115c822e4363d7355ec5daed2eae5bf89ee944ac7d9c
+CT = 4536422bbad220079ee09e700e103efdaac832d016a20813762d5d8adafe75a191310a2618930c48
+Result = Fail (1 - Adata changed)
+
+Count = 202
+Nonce = 5d05f658c729a2
+Adata = dd9564c1431ed490b17ef69f6115805e54ef156ef4e10e58f7d57a7e86626352
+CT = d6711a78adf54f4effe647d531c4618cf32e3037eb700580206f80080dfa3e66e6371c0cde6cd205
+Result = Fail (2 - CT changed)
+
+Count = 203
+Nonce = 22a77db9fcbc95
+Adata = 86bf1739c10f63df734ee3e60ac40ff5636c49f68ca4c16ece289609eb413e7a
+CT = e44034a397778e1c6babab27f5a50fa4aac0e83d6b3eb25db1b5b2b35c8a8125efccd1f4102f3e82
+Result = Fail (2 - CT changed)
+
+Count = 204
+Nonce = 491e32b0bbfa4c
+Adata = 75bef075c79d6cfd7fc73aefd67b2d215be0648937477ba606b1fe1be591239e
+CT = b8e31c5910623e405f2ebf65821963e5b8814043612395feca36f53b01943f03cb8b69b5af53e505
+Result = Fail (1 - Adata changed)
+
+Count = 205
+Nonce = bc4b7d3a380be0
+Adata = 353dbb41e2d525a9f4fcd858d0f0aa1b1e86ac0f936d5c09c6b61c343f94e3fc
+CT = 4000faf8558f2f4e01e45e90796cd236e5211d1704270f31c3bfc6851049d32105fd16bd45b29f29
+Result = Fail (1 - Adata changed)
+
+Count = 206
+Nonce = a840e98df72ae9
+Adata = 22c6607732ef1bdc7fcf6197e037cdadd7ee17c008552dd9f04b8564d34fb17c
+CT = 53bb608f6236798839af35888cb0fa4797b599271084cc13847b022733ca5a5e3c4d472332484b7f
+Result = Pass (0)
+Payload = a2f53385618b41301f4e3ea4c597f411103dac2b37abf5da
+
+Count = 207
+Nonce = 39d93c3cf31a6f
+Adata = 937dfac5cded938438f4e97aabd9beb50dba40f824198260a89729479cfe6869
+CT = be54551d1d2f1b3eb60ffe3b165524ff90ca09fb252bf21c1c79edbf38c50e0f240a2d70f65aa79f
+Result = Pass (0)
+Payload = c1bdef96dc868446be48491b160504546f2a40dd581f9582
+
+Count = 208
+Nonce = 0bbc177019321e
+Adata = f6e02678820f5ccbede6cbded02d6dd58d486166d7b18ee975a688af421fb795
+CT = f07c1072d8f8e077dfbb3ad86dd92d32b41f29e647dcd7e3a82cd3ebaf6c2d3e21749bdf570ad28d
+Result = Pass (0)
+Payload = 72a70954d22ad722fc32756afce67b344b2f3c55fe1d9eed
+
+Count = 209
+Nonce = ad048eb2ad7526
+Adata = 0d2739cfdac782b61f484fa1a423c478c414397ec420327963d79112b2d70a7e
+CT = 7f7cf7f4d0645934cb0a5e67b4227a909aa55dba09b2c39cef93a8759845326683a0d9c22151f486
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 24, Nlen = 13, Tlen = 4]
+
+Key = a7aa635ea51b0bb20a092bd5573e728ccd4b3e8cdd2ab33d
+
+Count = 210
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = 16e543d0e20615ff0df15acd9927ddfe40668a54bb854cccc25e9fce
+Result = Pass (0)
+Payload = 8739b4bea1a099fe547499cbc6d1b13d849b8084c9b6acc5
+
+Count = 211
+Nonce = 0812757ad0cc4d17c4cfe7a642
+Adata = ec6c44a7e94e51a3ca6dee229098391575ec7213c85267fbf7492fdbeee61b10
+CT = df35b109caf690656ae278bbd8f8bba687a2ce11b105dae98ecedb3e
+Result = Fail (2 - CT changed)
+
+Count = 212
+Nonce = eff510acc1b85f35029cf7dc00
+Adata = 0923b927b8295c5dfaf67da55e5014293bc8c708fda50af06c1e8aef31cccc86
+CT = 7075da2291e2cb527eb926ed08d8020c5f8f0f2d4a6a4745728da544
+Result = Fail (1 - Adata changed)
+
+Count = 213
+Nonce = 3d13d09057190366c63c8750e9
+Adata = 77e27aa9a7bf30e130c862a3296a1cd7a10195ed1d940f2c97bfff47c6f06e32
+CT = 18a77a66457b53286b1aea0845304cac8e66a02d5c642e4c02a9b9bc
+Result = Fail (1 - Adata changed)
+
+Count = 214
+Nonce = e3c03ef7e1d31961ee0b97bd99
+Adata = 8a3676dd640821b58fb0f0329855fd5882c376ea166b958b7aaad223054e5784
+CT = 24e1d3820101412d8f4d57118cab8f7e489d5cac78802dd5ccf8ecf0
+Result = Pass (0)
+Payload = 92973ce707733a73118c8ce6b5e3fc77a17f448310c0197f
+
+Count = 215
+Nonce = 5d165ddd4e599387af5967cae6
+Adata = e374f875ce829b62c98fbd67bcf128b5647f25fff9a643300eb95559b889baed
+CT = b5929bc9648e24a553c5cd953ecb9d67ee508d2d4ac7b46e661181d5
+Result = Fail (2 - CT changed)
+
+Count = 216
+Nonce = fcec171162a27a96066181fab2
+Adata = cf431cc3671ec468ea86f6cc09842fcf3a84b3ef0fa1c7b20b232145b4469d62
+CT = 54aa018dc7fdf8a54809e1393d18031bab4aa5ca35c201907d74517d
+Result = Fail (1 - Adata changed)
+
+Count = 217
+Nonce = 2fa8120398d1a946f391367cf6
+Adata = 92558a239c8e13230754f23aec67b153db29fdfc7daf641778185dd2931d89da
+CT = 69bcc300a459862b3cd284c15dd4af53dc7e95f3067bb8254a8edd83
+Result = Fail (2 - CT changed)
+
+Count = 218
+Nonce = 88e0ae338bbca9d4299b294354
+Adata = 5db5c388dbadc9f175a5cd5a1472a458d25acd7fb9c951c0cd45edf64da473bb
+CT = 5c2d2df0d8aade3e5ae0f8d8b4b4d7c565817a31b2865dc270ad39a6
+Result = Fail (2 - CT changed)
+
+Count = 219
+Nonce = 4862e36296d6afc9399a95bbb4
+Adata = 36d82ebd0e0f5fe3b12946d041ae5aee16e6d17025406dd776f499bbd8e8b4c8
+CT = df1b3f98b6b0060191e7eb817f5908ddc0bc6f83860349e8ae423997
+Result = Fail (1 - Adata changed)
+
+Count = 220
+Nonce = 2f360a4715074e942244ab7f9b
+Adata = f0087b0086a081c1071481f033a8be8e940c36763084329bb8461b9102238f4f
+CT = 16e59dd38395c7be7f580371edabb1e9bf21270de270aa283309108e
+Result = Fail (1 - Adata changed)
+
+Count = 221
+Nonce = 93e08854560edb096e5d654086
+Adata = bdc60dff08bfd5d44320b75c61e456fd4333c9c3d0294d4a48d936dfd5922ce2
+CT = 0ef8981dd37c055a3c3e14786fc662b2a11065964911d35ebcc87096
+Result = Pass (0)
+Payload = 569e4aec88dd51ca519c0a00c922ee33d3559b98a32d7906
+
+Count = 222
+Nonce = e3f37b68ff508cfe295441d9e3
+Adata = b2b6c5782e4f128467c589d2a6cf55ef12877adb771bbb6245c5bba9dcfd6208
+CT = fc1870cfc440f74f73f40e682cf4713d027c297b9426c3efe981e935
+Result = Pass (0)
+Payload = 02b5511204bd55f7c37973e26f6df5883c0a530f07c7f8c2
+
+Count = 223
+Nonce = ea98ec44f5a86715014783172e
+Adata = e4692b9f06b666c7451b146c8aeb07a6e30c629d28065c3dde5940325b14b810
+CT = 9fc2c462dff1ba9756772d73de5c4e822b5ea0bc88845a323b98de4f
+Result = Pass (0)
+Payload = 4da40b80579c1d9a5309f7efecb7c059a2f914511ca5fc10
+
+Count = 224
+Nonce = 5a16a8902bd70fa06cfe184c57
+Adata = 399d6b0652836457ec4f701f0dc0e5aed73d16585d61cb1bb5b7ee824fc287c8
+CT = 05fc586d5c780b8e06f618b5bb85f591665a54390eba4e14af3b74e1
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 24, Nlen = 13, Tlen = 16]
+
+Key = 26511fb51fcfa75cb4b44da75a6e5a0eb8d9c8f3b906f886
+
+Count = 225
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = c5b0b2ef17498c5570eb335df4588032958ba3d69bf6f3178464a6f7fa2b76744e8e8d95691cecb8
+Result = Pass (0)
+Payload = 8739b4bea1a099fe547499cbc6d1b13d849b8084c9b6acc5
+
+Count = 226
+Nonce = 0812757ad0cc4d17c4cfe7a642
+Adata = ec6c44a7e94e51a3ca6dee229098391575ec7213c85267fbf7492fdbeee61b10
+CT = d1f0518929f4ae2f0543de2a7dfe4bb0110bb3057e524a1c06bd6dc2e6bcc3436cffb969ae900388
+Result = Fail (2 - CT changed)
+
+Count = 227
+Nonce = eff510acc1b85f35029cf7dc00
+Adata = 0923b927b8295c5dfaf67da55e5014293bc8c708fda50af06c1e8aef31cccc86
+CT = 1aa7dfa3a9818142c4971cbf4f64d4cbdbd354c6958ef474bb56d90669c726d866fe2206b8828727
+Result = Fail (1 - Adata changed)
+
+Count = 228
+Nonce = 3d13d09057190366c63c8750e9
+Adata = 77e27aa9a7bf30e130c862a3296a1cd7a10195ed1d940f2c97bfff47c6f06e32
+CT = 90352a5ec92d4fa52a96ae28251a57933728b2a3670e2ecd9953fec4e091b3573214e1ecac1ac00c
+Result = Fail (1 - Adata changed)
+
+Count = 229
+Nonce = e3c03ef7e1d31961ee0b97bd99
+Adata = 8a3676dd640821b58fb0f0329855fd5882c376ea166b958b7aaad223054e5784
+CT = eaa995946ed91d6a08ade14b260ac752cbd1081d5a7cad90783618374f6d03df28ee57a1a5aa38d8
+Result = Pass (0)
+Payload = 92973ce707733a73118c8ce6b5e3fc77a17f448310c0197f
+
+Count = 230
+Nonce = 5d165ddd4e599387af5967cae6
+Adata = e374f875ce829b62c98fbd67bcf128b5647f25fff9a643300eb95559b889baed
+CT = 0e320c4ece6ef0305a431a07a5a34d463ec4a37fc513c4b947bb3f30d6e674d10a496806c1c8933e
+Result = Fail (2 - CT changed)
+
+Count = 231
+Nonce = fcec171162a27a96066181fab2
+Adata = cf431cc3671ec468ea86f6cc09842fcf3a84b3ef0fa1c7b20b232145b4469d62
+CT = 10685888091597c50acc54b2fb65150b83a7115351d6f8bd7dd7ee3f75cfb47fa72433644f9cf62e
+Result = Fail (1 - Adata changed)
+
+Count = 232
+Nonce = 2fa8120398d1a946f391367cf6
+Adata = 92558a239c8e13230754f23aec67b153db29fdfc7daf641778185dd2931d89da
+CT = e456abf9ee83e0a68fbdb09c4a7afaba0efb0aa6d74a17c443314076072a0ebd253fe1ab4883ebea
+Result = Fail (2 - CT changed)
+
+Count = 233
+Nonce = 88e0ae338bbca9d4299b294354
+Adata = 5db5c388dbadc9f175a5cd5a1472a458d25acd7fb9c951c0cd45edf64da473bb
+CT = 5adadfd296edaf4bea92c8245983dc31b11335f682fb222c16a72444f0949868f0e71907acbb29f4
+Result = Fail (2 - CT changed)
+
+Count = 234
+Nonce = 4862e36296d6afc9399a95bbb4
+Adata = 36d82ebd0e0f5fe3b12946d041ae5aee16e6d17025406dd776f499bbd8e8b4c8
+CT = c2bb4d5a830646b3f8bf84044851c3b676c4ec02e43dcbf1ab2025208191d73041c038cf2562bb8c
+Result = Fail (1 - Adata changed)
+
+Count = 235
+Nonce = 2f360a4715074e942244ab7f9b
+Adata = f0087b0086a081c1071481f033a8be8e940c36763084329bb8461b9102238f4f
+CT = 9589b8abcb47e54e6e8fad3e64fec7ed4f70ac435bb3e548b7e6d183efa1f51b7ff31eaa52ed59ba
+Result = Fail (1 - Adata changed)
+
+Count = 236
+Nonce = 93e08854560edb096e5d654086
+Adata = bdc60dff08bfd5d44320b75c61e456fd4333c9c3d0294d4a48d936dfd5922ce2
+CT = af63f27e2a9e70f106477493dc141d16a1d059dd7a8a7810d990b642039f24755790332b3cc47c49
+Result = Pass (0)
+Payload = 569e4aec88dd51ca519c0a00c922ee33d3559b98a32d7906
+
+Count = 237
+Nonce = e3f37b68ff508cfe295441d9e3
+Adata = b2b6c5782e4f128467c589d2a6cf55ef12877adb771bbb6245c5bba9dcfd6208
+CT = 1d2ae88c878684a0b404986252b3a7583e1a5a51163ddc606d3968fdceaae5138c411a29d0d333ee
+Result = Pass (0)
+Payload = 02b5511204bd55f7c37973e26f6df5883c0a530f07c7f8c2
+
+Count = 238
+Nonce = ea98ec44f5a86715014783172e
+Adata = e4692b9f06b666c7451b146c8aeb07a6e30c629d28065c3dde5940325b14b810
+CT = 30c154c616946eccc2e241d336ad33720953e449a0e6b0f0dbf8e9464909bdf337e48093c082a10b
+Result = Pass (0)
+Payload = 4da40b80579c1d9a5309f7efecb7c059a2f914511ca5fc10
+
+Count = 239
+Nonce = 5a16a8902bd70fa06cfe184c57
+Adata = 399d6b0652836457ec4f701f0dc0e5aed73d16585d61cb1bb5b7ee824fc287c8
+CT = 0c95b692b07b39039b40c80cf52ff71608ae87c973ac9ccb88bba8f204bb98b17cb3c8644e472b1e
+Result = Fail (2 - CT changed)
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT256.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT256.rsp
new file mode 100644
index 0000000000..b8045d8291
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT256.rsp
@@ -0,0 +1,1589 @@
+# CAVS 11.0
+# "CCM-DVPT" information
+# AES Keylen: 256
+# Generated on Tue Mar 15 08:09:26 2011
+
+
+[Alen = 0, Plen = 0, Nlen = 7, Tlen = 4]
+
+Key = eda32f751456e33195f1f499cf2dc7c97ea127b6d488f211ccc5126fbb24afa6
+
+Count = 0
+Nonce = a544218dadd3c1
+Adata = 00
+CT = 469c90bb
+Result = Pass
+Payload = 00
+
+Count = 1
+Nonce = d3d5424e20fbec
+Adata = 00
+CT = 46a908ed
+Result = Fail
+
+Count = 2
+Nonce = e776620a3bd961
+Adata = 00
+CT = fdd35c4d
+Result = Fail
+
+Count = 3
+Nonce = 6c7a3be9f9ad55
+Adata = 00
+CT = 869ce60e
+Result = Fail
+
+Count = 4
+Nonce = dbb3923156cfd6
+Adata = 00
+CT = 1302d515
+Result = Pass
+Payload = 00
+
+Count = 5
+Nonce = b390f67eaef8f5
+Adata = 00
+CT = 156416ee
+Result = Fail
+
+Count = 6
+Nonce = a259c114eaac89
+Adata = 00
+CT = 4fe06e92
+Result = Pass
+Payload = 00
+
+Count = 7
+Nonce = 7fc8804fef18ef
+Adata = 00
+CT = 611091aa
+Result = Fail
+
+Count = 8
+Nonce = fbaf4cbc49fa0f
+Adata = 00
+CT = 696e9371
+Result = Fail
+
+Count = 9
+Nonce = 2ed0c8761dbf04
+Adata = 00
+CT = a0e0a2cb
+Result = Fail
+
+Count = 10
+Nonce = 346bb04ea0db86
+Adata = 00
+CT = 43cc0375
+Result = Fail
+
+Count = 11
+Nonce = e1be89af98ffd7
+Adata = 00
+CT = e5417f6b
+Result = Pass
+Payload = 00
+
+Count = 12
+Nonce = a6a0d57aaaf012
+Adata = 00
+CT = fff8a068
+Result = Fail
+
+Count = 13
+Nonce = 1aa758eb2f9a28
+Adata = 00
+CT = f8fa8e71
+Result = Pass
+Payload = 00
+
+Count = 14
+Nonce = 2911167fc98fc3
+Adata = 00
+CT = 0bfa2d9d
+Result = Fail
+
+[Alen = 0, Plen = 0, Nlen = 7, Tlen = 16]
+
+Key = e1b8a927a95efe94656677b692662000278b441c79e879dd5c0ddc758bdc9ee8
+
+Count = 15
+Nonce = a544218dadd3c1
+Adata = 00
+CT = 8207eb14d33855a52acceed17dbcbf6e
+Result = Pass
+Payload = 00
+
+Count = 16
+Nonce = d3d5424e20fbec
+Adata = 00
+CT = 60f8e127cb4d30db6df0622158cd931d
+Result = Fail
+
+Count = 17
+Nonce = e776620a3bd961
+Adata = 00
+CT = 4239f29871651e9a26b8b06ffc5b3748
+Result = Fail
+
+Count = 18
+Nonce = 6c7a3be9f9ad55
+Adata = 00
+CT = 5d35364c621fe8959dfe70ab44700fbe
+Result = Fail
+
+Count = 19
+Nonce = dbb3923156cfd6
+Adata = 00
+CT = e4dc5e03aacea691262ee69cee8ffbbe
+Result = Pass
+Payload = 00
+
+Count = 20
+Nonce = b390f67eaef8f5
+Adata = 00
+CT = c8eb7643b4ed3c796c3873e8c6624e0d
+Result = Fail
+
+Count = 21
+Nonce = a259c114eaac89
+Adata = 00
+CT = f79c53fd5e69835b7e70496ea999718b
+Result = Pass
+Payload = 00
+
+Count = 22
+Nonce = 7fc8804fef18ef
+Adata = 00
+CT = 687e00723a419fa81c0923b8b8e245ae
+Result = Fail
+
+Count = 23
+Nonce = fbaf4cbc49fa0f
+Adata = 00
+CT = 499ab350309ad6091ec4aaf6bf0cbd00
+Result = Fail
+
+Count = 24
+Nonce = 2ed0c8761dbf04
+Adata = 00
+CT = c27b9f14787dc5375f59d0c561a23446
+Result = Fail
+
+Count = 25
+Nonce = 346bb04ea0db86
+Adata = 00
+CT = 655c737722c78ac96582a883d407b2bb
+Result = Fail
+
+Count = 26
+Nonce = e1be89af98ffd7
+Adata = 00
+CT = 10d3f6fe08280d45e67e58fe41a7f036
+Result = Pass
+Payload = 00
+
+Count = 27
+Nonce = a6a0d57aaaf012
+Adata = 00
+CT = b4e425e43edb92c606f7cb2de8a06932
+Result = Fail
+
+Count = 28
+Nonce = 1aa758eb2f9a28
+Adata = 00
+CT = 2590df2453cb94c304ba0a2bff3f3c71
+Result = Pass
+Payload = 00
+
+Count = 29
+Nonce = 2911167fc98fc3
+Adata = 00
+CT = 1f344e30dfa95b2319e274caa5780e60
+Result = Fail
+
+[Alen = 0, Plen = 0, Nlen = 13, Tlen = 4]
+
+Key = e1b8a927a95efe94656677b692662000278b441c79e879dd5c0ddc758bdc9ee8
+
+Count = 30
+Nonce = a544218dadd3c10583db49cf39
+Adata = 00
+CT = 8a19a133
+Result = Pass
+Payload = 00
+
+Count = 31
+Nonce = 3c0e2815d37d844f7ac240ba9d
+Adata = 00
+CT = 2e317f1b
+Result = Fail
+
+Count = 32
+Nonce = 75549e7e5657e5fe19872fcee0
+Adata = 00
+CT = 979bdcfe
+Result = Fail
+
+Count = 33
+Nonce = d071ff72735820d73485870e83
+Adata = 00
+CT = 8ef89acf
+Result = Fail
+
+Count = 34
+Nonce = 79ac204a26b9fee1132370c20f
+Adata = 00
+CT = 154024b2
+Result = Pass
+Payload = 00
+
+Count = 35
+Nonce = a64bbc3d6d377dab513f7d9ce8
+Adata = 00
+CT = 8dbcc439
+Result = Fail
+
+Count = 36
+Nonce = 0545fd9ecbc73ccdbbbd4244fd
+Adata = 00
+CT = 5c349fb2
+Result = Pass
+Payload = 00
+
+Count = 37
+Nonce = 182fb47a12becf0bfe65df1287
+Adata = 00
+CT = 79df3e02
+Result = Fail
+
+Count = 38
+Nonce = f342059a6f9dc14226b40debc4
+Adata = 00
+CT = fbc2c500
+Result = Fail
+
+Count = 39
+Nonce = 6cbfe6bb4c9b171b93d28e9f8f
+Adata = 00
+CT = 2fac1bca
+Result = Fail
+
+Count = 40
+Nonce = 82877df921c6ade43064ad963e
+Adata = 00
+CT = 99948f6e
+Result = Fail
+
+Count = 41
+Nonce = 0a37f2e7c66490e97285f1b09e
+Adata = 00
+CT = c59bf14c
+Result = Pass
+Payload = 00
+
+Count = 42
+Nonce = d7b9c346ce2f8bad9623122e10
+Adata = 00
+CT = b764c393
+Result = Fail
+
+Count = 43
+Nonce = c1ad812bf2bbb2cdaee4636ee7
+Adata = 00
+CT = 5b96f41d
+Result = Pass
+Payload = 00
+
+Count = 44
+Nonce = b6ce7d00731184b24428df046b
+Adata = 00
+CT = f7e12df1
+Result = Fail
+
+[Alen = 0, Plen = 0, Nlen = 13, Tlen = 16]
+
+Key = af063639e66c284083c5cf72b70d8bc277f5978e80d9322d99f2fdc718cda569
+
+Count = 45
+Nonce = a544218dadd3c10583db49cf39
+Adata = 00
+CT = 97e1a8dd4259ccd2e431e057b0397fcf
+Result = Pass
+Payload = 00
+
+Count = 46
+Nonce = 3c0e2815d37d844f7ac240ba9d
+Adata = 00
+CT = 5a9596c511ea6a8671adefc4f2157d8b
+Result = Fail
+
+Count = 47
+Nonce = 75549e7e5657e5fe19872fcee0
+Adata = 00
+CT = 66f5c53efbc74fa02dedc303fd95133a
+Result = Fail
+
+Count = 48
+Nonce = d071ff72735820d73485870e83
+Adata = 00
+CT = 2dfd3c852f68eace45acf433a6aa9c05
+Result = Fail
+
+Count = 49
+Nonce = 79ac204a26b9fee1132370c20f
+Adata = 00
+CT = 5c8c9a5b97be8c7bc01ca8d693b809f9
+Result = Pass
+Payload = 00
+
+Count = 50
+Nonce = a64bbc3d6d377dab513f7d9ce8
+Adata = 00
+CT = ec093121bdcd589285f2262be8db5c4e
+Result = Fail
+
+Count = 51
+Nonce = 0545fd9ecbc73ccdbbbd4244fd
+Adata = 00
+CT = 84201662b213c7a1ff0c1b3c25e4ec45
+Result = Pass
+Payload = 00
+
+Count = 52
+Nonce = 182fb47a12becf0bfe65df1287
+Adata = 00
+CT = bbe746d6d31e8e9745faed4095ab8d5d
+Result = Fail
+
+Count = 53
+Nonce = f342059a6f9dc14226b40debc4
+Adata = 00
+CT = 646c1258dc4aa6fc380818e70e5f4328
+Result = Fail
+
+Count = 54
+Nonce = 6cbfe6bb4c9b171b93d28e9f8f
+Adata = 00
+CT = 15fa37ca7f2883a4642c1ed41b8f6293
+Result = Fail
+
+Count = 55
+Nonce = 82877df921c6ade43064ad963e
+Adata = 00
+CT = c6acf5e5ded4efb2c314370ebb9e9cde
+Result = Fail
+
+Count = 56
+Nonce = 0a37f2e7c66490e97285f1b09e
+Adata = 00
+CT = 586e728193ce6db9a926b03b2d77dd6e
+Result = Pass
+Payload = 00
+
+Count = 57
+Nonce = d7b9c346ce2f8bad9623122e10
+Adata = 00
+CT = 642a187e71feff5989e28184aded0199
+Result = Fail
+
+Count = 58
+Nonce = c1ad812bf2bbb2cdaee4636ee7
+Adata = 00
+CT = 64864d21b6ee3fca13f07fc0486e232d
+Result = Pass
+Payload = 00
+
+Count = 59
+Nonce = b6ce7d00731184b24428df046b
+Adata = 00
+CT = 58c63ce68f132d30d177c5834344cc5d
+Result = Fail
+
+[Alen = 0, Plen = 24, Nlen = 7, Tlen = 4]
+
+Key = af063639e66c284083c5cf72b70d8bc277f5978e80d9322d99f2fdc718cda569
+
+Count = 60
+Nonce = a544218dadd3c1
+Adata = 00
+CT = 64a1341679972dc5869fcf69b19d5c5ea50aa0b5e985f5b722aa8d59
+Result = Pass
+Payload = d3d5424e20fbec43ae495353ed830271515ab104f8860c98
+
+Count = 61
+Nonce = bfcda8b5a2d0d2
+Adata = 00
+CT = c5b7f802bffc498c1626e3774f1d9f94045dfd8e1a10a20277d00a75
+Result = Fail
+
+Count = 62
+Nonce = 6bae7f35c56b27
+Adata = 00
+CT = bf432e246b7fa4aff8b3ada738432b51f6872ed92284db9d28588021
+Result = Fail
+
+Count = 63
+Nonce = c5e4214b1bf209
+Adata = 00
+CT = 0d5760ad0e156e401120a1ebd1b139248784c88e10e3425437921120
+Result = Fail
+
+Count = 64
+Nonce = 9d773a31fe2ec7
+Adata = 00
+CT = 5acfbe5e488976d8b9b77e69a736e8c919053f9415551209dce2d25e
+Result = Pass
+Payload = 839d8cfa2c921c3cceb7d1f46bd2eaad706e53f64523d8c0
+
+Count = 65
+Nonce = f42cb0cce9efb6
+Adata = 00
+CT = be8be6046ac58411a00c131dd4a72d565f98d87a2c89124b1ef530d0
+Result = Fail
+
+Count = 66
+Nonce = 24b7a65391f88b
+Adata = 00
+CT = f00628e10e8e0115b4a4532a1212a23aade4090832c1972d750125f3
+Result = Pass
+Payload = 3bed52236182c19418867d468dbf47c8aac46c02445f99bb
+
+Count = 67
+Nonce = d2a7eb45780df3
+Adata = 00
+CT = 9078151f674d5f7b56e2451b0316156f776459f17d277e0108aaaf93
+Result = Fail
+
+Count = 68
+Nonce = 046cbfd26093d8
+Adata = 00
+CT = 921cbecce3b06f3d655a5a0a4d212320d4f147575079fd23bd95e677
+Result = Fail
+
+Count = 69
+Nonce = 51b13b0b04d077
+Adata = 00
+CT = 8cab1ff22d474e9863c153e84680e2a66981f036051360477e2ebb1d
+Result = Fail
+
+Count = 70
+Nonce = ce2e9967bf9eb7
+Adata = 00
+CT = 15f476b5aefe072548a54f59506d9c3b9ce29025340214be662f8684
+Result = Fail
+
+Count = 71
+Nonce = b672c91376f533
+Adata = 00
+CT = 758aa03dc72c362c43b5f85bfaa3db4a74860887a8c29e47d5642830
+Result = Pass
+Payload = 4f7a561e61b7861719e4445057ac9b74a9be953b772b09ec
+
+Count = 72
+Nonce = 62f6f1872462d8
+Adata = 00
+CT = ec645769b22161567e6a7e23aa06575bc767a34aa54d3cba01472fe1
+Result = Fail
+
+Count = 73
+Nonce = a6d01fb88ca547
+Adata = 00
+CT = 615cbeabbe163ba8bc9c073df9ad40833fcf3f424644ccc37aa999d7
+Result = Pass
+Payload = a36155de477364236591e453008114075b4872120ef17264
+
+Count = 74
+Nonce = 46ad6ebbd8644a
+Adata = 00
+CT = 0ed6cc6451de57ca672d56dee45d4548a810d5c49dfe442dd27b7cf2
+Result = Fail
+
+[Alen = 0, Plen = 24, Nlen = 7, Tlen = 16]
+
+Key = f7079dfa3b5c7b056347d7e437bcded683abd6e2c9e069d333284082cbb5d453
+
+Count = 75
+Nonce = a544218dadd3c1
+Adata = 00
+CT = bc51c3925a960e7732533e4ef3a4f69ee6826de952bcb0fd374f3bb6db8377ebfc79674858c4f305
+Result = Pass
+Payload = d3d5424e20fbec43ae495353ed830271515ab104f8860c98
+
+Count = 76
+Nonce = bfcda8b5a2d0d2
+Adata = 00
+CT = afa1fa8e8a70e26b02161150556d604101fdf423f332c3363275f2a4907d51b734fe7238cebbd48f
+Result = Fail
+
+Count = 77
+Nonce = 6bae7f35c56b27
+Adata = 00
+CT = 72bc8ef21a847047091b673ccf231d35ecf6f4049741703be672f1f22cbe4a5305f19aaa6967237b
+Result = Fail
+
+Count = 78
+Nonce = c5e4214b1bf209
+Adata = 00
+CT = b719f6555fc4e5424273f5903d5672af460413110278707f400b152113c3976be63dcd9e7a84ddac
+Result = Fail
+
+Count = 79
+Nonce = 9d773a31fe2ec7
+Adata = 00
+CT = 4539bb13382b034ddb16a3329148f9243a4eee998fe444aff2870ce198af11f4fb698a67af6c89ad
+Result = Pass
+Payload = 839d8cfa2c921c3cceb7d1f46bd2eaad706e53f64523d8c0
+
+Count = 80
+Nonce = f42cb0cce9efb6
+Adata = 00
+CT = 47cbb909cb12fa0a4b0f1aefd54c52d1edd1533290f76b8ccc98b3f5758972bf08ea9e88dc6e54ed
+Result = Fail
+
+Count = 81
+Nonce = 24b7a65391f88b
+Adata = 00
+CT = 6d0f928352a17d63aca1899cbd305e1f831f1638d27c1e24432704eff9b6830476db3d30d4c103e4
+Result = Pass
+Payload = 3bed52236182c19418867d468dbf47c8aac46c02445f99bb
+
+Count = 82
+Nonce = d2a7eb45780df3
+Adata = 00
+CT = e0e686d917f78b3b0058fed7b084976244789073a6305ff571256981db86f1e768170a104ebfb81d
+Result = Fail
+
+Count = 83
+Nonce = 046cbfd26093d8
+Adata = 00
+CT = 960c573f5d6934a4cac49d06998f827b3d665cf02c998fe55efbbae6a346863a93d52e0321cef8b2
+Result = Fail
+
+Count = 84
+Nonce = 51b13b0b04d077
+Adata = 00
+CT = 7cf8f4806848e34aa7d3bd7e2cb9f5d9ff21395ff6d34826ac2fdc3cc683f6120e405f446a10e0f3
+Result = Fail
+
+Count = 85
+Nonce = ce2e9967bf9eb7
+Adata = 00
+CT = e4f6445ca36e7ee3323f11f6a5ca8ded0c85871e092aa687d254f7765b6155054a5efde28dd38750
+Result = Fail
+
+Count = 86
+Nonce = b672c91376f533
+Adata = 00
+CT = f23ac1426cb1130c9a0913b347d8efafb6ed125913aa678a9dc42d22a5436bc12eff5505edb25e19
+Result = Pass
+Payload = 4f7a561e61b7861719e4445057ac9b74a9be953b772b09ec
+
+Count = 87
+Nonce = 62f6f1872462d8
+Adata = 00
+CT = ac9f131389181b1023f1ee47633aa433fc5d93a87d9ece962db05feb368ab772d977fd97b35262fa
+Result = Fail
+
+Count = 88
+Nonce = a6d01fb88ca547
+Adata = 00
+CT = 773b8eea2e9830297ac11d3c1f6ea4008c96040e83d76d55789d2043179fdd8fdcbd52313b7b15cb
+Result = Pass
+Payload = a36155de477364236591e453008114075b4872120ef17264
+
+Count = 89
+Nonce = 46ad6ebbd8644a
+Adata = 00
+CT = d3fae92043c419fe8ac0d7491ca8041ad089559d895103cf079a2bac0ab4bc249bbdb330181cdd16
+Result = Fail
+
+[Alen = 0, Plen = 24, Nlen = 13, Tlen = 4]
+
+Key = f7079dfa3b5c7b056347d7e437bcded683abd6e2c9e069d333284082cbb5d453
+
+Count = 90
+Nonce = a544218dadd3c10583db49cf39
+Adata = 00
+CT = 63e00d30e4b08fd2a1cc8d70fab327b2368e77a93be4f4123d14fb3f
+Result = Pass
+Payload = 3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e
+
+Count = 91
+Nonce = 894dcaa61008eb8fb052c60d41
+Adata = 00
+CT = bb5425b3869b76856ec58e39886fb6f6f2ac13fe44cb132d8d0c0099
+Result = Fail
+
+Count = 92
+Nonce = 8feba0d720aa4a5e35abc99e82
+Adata = 00
+CT = 2ca3be419d5be5ed682f8954d2c20efd9e6d360814735daeefd4365c
+Result = Fail
+
+Count = 93
+Nonce = ed04c9ca8702aec8d0a58e09a0
+Adata = 00
+CT = 3d34bda62db39d6118d6fd5cd38f1a3820ca69ce584b94a2a4ccbef1
+Result = Fail
+
+Count = 94
+Nonce = 1501a243bf60b2cb40d5aa20ca
+Adata = 00
+CT = 377b2f1e7bd9e3d1077038e084f61950761361095f7eeebbf1a72afc
+Result = Pass
+Payload = f5730a05fec31a11662e2e14e362ccc75c7c30cdfccbf994
+
+Count = 95
+Nonce = c6edaf35f0cb433500a8c3a613
+Adata = 00
+CT = 9cef6c889ff51666df9dd1dd2215c15f4b2078a29373c106be4f5f9a
+Result = Fail
+
+Count = 96
+Nonce = d65e0e53f765f9d5e6795c0c5e
+Adata = 00
+CT = 6cab3060bf3b33b163b933c2ed0ba51406810b54d0edcf5c9d0ef4f7
+Result = Pass
+Payload = 20e394c7cc90bdfa6186fc1ba6fff158dfc690e24ba4c9fb
+
+Count = 97
+Nonce = 2b0163418a341588db0f5786d8
+Adata = 00
+CT = f9543a659e9a8b7d75dd859df923817452735f5051726422c08a9e85
+Result = Fail
+
+Count = 98
+Nonce = f16bba081bddda83546eabc9a5
+Adata = 00
+CT = 0d20bf6a9d02da72091d94cdb38743bfea2473d3ab62dcad75dd819a
+Result = Fail
+
+Count = 99
+Nonce = ace99268a32b9c1b5ccd8b0d84
+Adata = 00
+CT = 8bca01e6ebd7ebcdfe52b88e314670ffeb35882fc05394b386e205f9
+Result = Fail
+
+Count = 100
+Nonce = 24570517bbb0df1b3fbd32f57a
+Adata = 00
+CT = 7061c84e2e1d9d58013543ff82666055a1f055c1296c42c8f73a8bf0
+Result = Fail
+
+Count = 101
+Nonce = a6b2371acf8321864c08ddb4d8
+Adata = 00
+CT = c5aa500d1f7c09a590e9d15d6860c4433684e04dd6bc5c8f94f223f0
+Result = Pass
+Payload = 1a43ca628026219c5a430c54021a5a3152ae517167399635
+
+Count = 102
+Nonce = f8e2d4e043f5fe7a72b6117811
+Adata = 00
+CT = e3efa7971e27ba1245ee9491ebdbb28ad9b24b325da5760417af8b14
+Result = Fail
+
+Count = 103
+Nonce = c2b60f14c894ec6178fe79919f
+Adata = 00
+CT = 852cca903d7fdf899807bd14642057534c8a0ccacb8c7b8fb4d35d44
+Result = Pass
+Payload = 3e707d98f19972a63d913e6ea7533af2f41ff98aee2b2a36
+
+Count = 104
+Nonce = 4de4c909ac0cc5fc608baf45ac
+Adata = 00
+CT = e04fd4f5b60833021ed57c98de300bb68d0d892b2bf68e080bc044b1
+Result = Fail
+
+[Alen = 0, Plen = 24, Nlen = 13, Tlen = 16]
+
+Key = 1b0e8df63c57f05d9ac457575ea764524b8610ae5164e6215f426f5a7ae6ede4
+
+Count = 105
+Nonce = a544218dadd3c10583db49cf39
+Adata = 00
+CT = f0050ad16392021a3f40207bed3521fb1e9f808f49830c423a578d179902f912f9ea1afbce1120b3
+Result = Pass
+Payload = 3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e
+
+Count = 106
+Nonce = 894dcaa61008eb8fb052c60d41
+Adata = 00
+CT = c408190d0fbf5034f83b24a8ed9657331a7ce141de4fae769084607b83bd06e6442eac8dacf583cc
+Result = Fail
+
+Count = 107
+Nonce = 8feba0d720aa4a5e35abc99e82
+Adata = 00
+CT = 52b3d31d02d1b92b38cbae8c510204dde6bf9588e994296c9002a46cfb734290924a15e9c3d99924
+Result = Fail
+
+Count = 108
+Nonce = ed04c9ca8702aec8d0a58e09a0
+Adata = 00
+CT = f80190470212ce1e64bf4c64ca0133d90469abf87a8233c2b238e316c3f9adccce95e8c8b9c7e8d2
+Result = Fail
+
+Count = 109
+Nonce = 1501a243bf60b2cb40d5aa20ca
+Adata = 00
+CT = 254b847d4175bbb44a82b4e805514fa444c224710933f3ec8aaa3f0133234c0cd91609982adc034b
+Result = Pass
+Payload = f5730a05fec31a11662e2e14e362ccc75c7c30cdfccbf994
+
+Count = 110
+Nonce = c6edaf35f0cb433500a8c3a613
+Adata = 00
+CT = 7a5c7bc02aa69efc5a159d653f3993399f69e20752c3b00633255731cd88345860da913bc696fdc1
+Result = Fail
+
+Count = 111
+Nonce = d65e0e53f765f9d5e6795c0c5e
+Adata = 00
+CT = c3618c991b15de641d291419ff6957e8b9ae5046dd8c6f08fafb76adf12f36740347e3edae62bca4
+Result = Pass
+Payload = 20e394c7cc90bdfa6186fc1ba6fff158dfc690e24ba4c9fb
+
+Count = 112
+Nonce = 2b0163418a341588db0f5786d8
+Adata = 00
+CT = 240927bfd671a92aef0311395ad55ae42233ecee53873da4066f55f23d4e55bcbbbf2312ea2d8071
+Result = Fail
+
+Count = 113
+Nonce = f16bba081bddda83546eabc9a5
+Adata = 00
+CT = 4731a7e690c77cd47582ce54a1cec23d94c856b93a9fc767004753689cc84810b8414f1464c0c5b9
+Result = Fail
+
+Count = 114
+Nonce = ace99268a32b9c1b5ccd8b0d84
+Adata = 00
+CT = f0ea12eaff20c3a50674aa1546aaae3bd5c9249108535b21504da83478ede24026ec91fb12769e4b
+Result = Fail
+
+Count = 115
+Nonce = 24570517bbb0df1b3fbd32f57a
+Adata = 00
+CT = 5b164d9752ad6c497a7ab2d0bf8be68fea084ea5839b07b7c9fcf9b9fd5e99767a7b1679b57ea961
+Result = Fail
+
+Count = 116
+Nonce = a6b2371acf8321864c08ddb4d8
+Adata = 00
+CT = bd37326da18e5ac79a1a9512f724bb539530868576b79c67acb5a51d10a58d6584fbe73f1063c31b
+Result = Pass
+Payload = 1a43ca628026219c5a430c54021a5a3152ae517167399635
+
+Count = 117
+Nonce = f8e2d4e043f5fe7a72b6117811
+Adata = 00
+CT = 0455b4dd1069281e10531c0dc180ced9a5ef5d3fe0007470ce54cd7623a80a176f29a01b3abb642e
+Result = Fail
+
+Count = 118
+Nonce = c2b60f14c894ec6178fe79919f
+Adata = 00
+CT = ecd337640022635ce1ed273756d02b7feeb2515614c1fadc95c66d3f411b478853886afd177d88c3
+Result = Pass
+Payload = 3e707d98f19972a63d913e6ea7533af2f41ff98aee2b2a36
+
+Count = 119
+Nonce = 4de4c909ac0cc5fc608baf45ac
+Adata = 00
+CT = e25d7c9fb388596b13a13b885d5b24e31579a3494ad256da830b2b6317716b3975e2b101aebdd920
+Result = Fail
+
+[Alen = 32, Plen = 0, Nlen = 7, Tlen = 4]
+
+Key = 1b0e8df63c57f05d9ac457575ea764524b8610ae5164e6215f426f5a7ae6ede4
+
+Count = 120
+Nonce = a544218dadd3c1
+Adata = d3d5424e20fbec43ae495353ed830271515ab104f8860c988d15b6d36c038eab
+CT = 92d00fbe
+Result = Pass
+Payload = 00
+
+Count = 121
+Nonce = 78c46e3249ca28
+Adata = 232e957c65ffa11988e830d4617d500f1c4a35c1221f396c41ab214f074ca2dc
+CT = 9143e5c4
+Result = Fail
+
+Count = 122
+Nonce = c18d9e7971e2ae
+Adata = 0d40324aa758dbbb5391b5e6edb8a2310c94a4ae51d4fba8a7458d7cc8488baa
+CT = 54337466
+Result = Fail
+
+Count = 123
+Nonce = 162d061351d82d
+Adata = 106d1fb32d948b0d8884f178ad2332a599445fae0f6f71f9ebe53a60b2df9b8e
+CT = bf0bf84c
+Result = Fail
+
+Count = 124
+Nonce = 3fcb328bc96404
+Adata = 10b2ffed4f95af0f98ed4f77c677b5786ad01b31c095bbc6e1c99cf13977abba
+CT = 11250056
+Result = Pass
+Payload = 00
+
+Count = 125
+Nonce = b3fd1eb1422277
+Adata = fa5398cf4cddbe4b45e9f5d7491cd9eefc5e494255961ba3f4b40d22b5f5fe76
+CT = 13de5339
+Result = Fail
+
+Count = 126
+Nonce = c42ac63de6f12a
+Adata = 7ff8d06c5abcc50d3820de34b03089e6c5b202bcbaabca892825553d4d30020a
+CT = 4eed80fd
+Result = Pass
+Payload = 00
+
+Count = 127
+Nonce = d4a7a672237e17
+Adata = d1cdad7fe886d07625a4334be6de4df0645d2a8b4008a8d35f04e6bcf87bfa56
+CT = 4bc2e450
+Result = Fail
+
+Count = 128
+Nonce = b23255372455c6
+Adata = d2e2c3607c40e0a807b86c6ebbc502ab42bdb7f85ab26299cd963bbba3a3a8fa
+CT = b30e6bbd
+Result = Fail
+
+Count = 129
+Nonce = 92272d40475fbb
+Adata = 2f3af695ee33a9ebe6a48ed1b00e337261857110bb104191a54fd13bd960d8bc
+CT = f7c11fe2
+Result = Fail
+
+Count = 130
+Nonce = c4a756f6024a9d
+Adata = 2317b324b6420ada9ea7bf52b71c5faf2485528da5f56b42c517be6355cdb28b
+CT = 76673751
+Result = Fail
+
+Count = 131
+Nonce = 3a1701b185d33a
+Adata = e5d54df8ed9f89b98c5ebb1bc5d5279c2e182784ff4cd9c869ae152e29d7a2b2
+CT = 9a5382c3
+Result = Pass
+Payload = 00
+
+Count = 132
+Nonce = e4db2e80dc3f63
+Adata = 7616bdf5737d01f936072b6576fa76556dfa072f7e2d7de16b9dc96ac8de409c
+CT = 9e632f56
+Result = Fail
+
+Count = 133
+Nonce = 4f490ce07e0150
+Adata = 3e12d09632c644c540077c6f90726d4167423a679322b2000a3f19cfcea02b33
+CT = e1842c46
+Result = Pass
+Payload = 00
+
+Count = 134
+Nonce = b4aaf9ad1bde60
+Adata = 8c96c891456ddec29fe04299506723db2079a6667f96db5d198bf085acf2a4ef
+CT = 9f644671
+Result = Fail
+
+[Alen = 32, Plen = 0, Nlen = 7, Tlen = 16]
+
+Key = a4bc10b1a62c96d459fbaf3a5aa3face7313bb9e1253e696f96a7a8e36801088
+
+Count = 135
+Nonce = a544218dadd3c1
+Adata = d3d5424e20fbec43ae495353ed830271515ab104f8860c988d15b6d36c038eab
+CT = 93af11a08379eb37a16aa2837f09d69d
+Result = Pass
+Payload = 00
+
+Count = 136
+Nonce = 78c46e3249ca28
+Adata = 232e957c65ffa11988e830d4617d500f1c4a35c1221f396c41ab214f074ca2dc
+CT = d19b0c14ec686a7961ca7c386d125a65
+Result = Fail
+
+Count = 137
+Nonce = c18d9e7971e2ae
+Adata = 0d40324aa758dbbb5391b5e6edb8a2310c94a4ae51d4fba8a7458d7cc8488baa
+CT = 02ea916d60e2ceec6d9dc9b1185569b3
+Result = Fail
+
+Count = 138
+Nonce = 162d061351d82d
+Adata = 106d1fb32d948b0d8884f178ad2332a599445fae0f6f71f9ebe53a60b2df9b8e
+CT = fabd2d0c422b47d363ea9936ff4a311b
+Result = Fail
+
+Count = 139
+Nonce = 3fcb328bc96404
+Adata = 10b2ffed4f95af0f98ed4f77c677b5786ad01b31c095bbc6e1c99cf13977abba
+CT = b3884b69d117146cfa5529901753ddc0
+Result = Pass
+Payload = 00
+
+Count = 140
+Nonce = b3fd1eb1422277
+Adata = fa5398cf4cddbe4b45e9f5d7491cd9eefc5e494255961ba3f4b40d22b5f5fe76
+CT = 7162026b6306e74fe32ece8433801bc2
+Result = Fail
+
+Count = 141
+Nonce = c42ac63de6f12a
+Adata = 7ff8d06c5abcc50d3820de34b03089e6c5b202bcbaabca892825553d4d30020a
+CT = b53d93cbfd3d5cf3720cef5080bc7224
+Result = Pass
+Payload = 00
+
+Count = 142
+Nonce = d4a7a672237e17
+Adata = d1cdad7fe886d07625a4334be6de4df0645d2a8b4008a8d35f04e6bcf87bfa56
+CT = c8bbecf69ecf8d10f0863bb4b7cbed51
+Result = Fail
+
+Count = 143
+Nonce = b23255372455c6
+Adata = d2e2c3607c40e0a807b86c6ebbc502ab42bdb7f85ab26299cd963bbba3a3a8fa
+CT = 6037145cc23a175760ae4b573907c80c
+Result = Fail
+
+Count = 144
+Nonce = 92272d40475fbb
+Adata = 2f3af695ee33a9ebe6a48ed1b00e337261857110bb104191a54fd13bd960d8bc
+CT = df7ea77425d631f652ffe096a8157f71
+Result = Fail
+
+Count = 145
+Nonce = c4a756f6024a9d
+Adata = 2317b324b6420ada9ea7bf52b71c5faf2485528da5f56b42c517be6355cdb28b
+CT = 7182b25ef5b113c13fa8f6769e74f1e2
+Result = Fail
+
+Count = 146
+Nonce = 3a1701b185d33a
+Adata = e5d54df8ed9f89b98c5ebb1bc5d5279c2e182784ff4cd9c869ae152e29d7a2b2
+CT = 0a5d1bc02c5fe096a8b9d94d1267c49a
+Result = Pass
+Payload = 00
+
+Count = 147
+Nonce = e4db2e80dc3f63
+Adata = 7616bdf5737d01f936072b6576fa76556dfa072f7e2d7de16b9dc96ac8de409c
+CT = 9eb6d9757ec7c56cc8c79461e0017486
+Result = Fail
+
+Count = 148
+Nonce = 4f490ce07e0150
+Adata = 3e12d09632c644c540077c6f90726d4167423a679322b2000a3f19cfcea02b33
+CT = 1eda43bf07f2bf003107f3a0ba3a4c18
+Result = Pass
+Payload = 00
+
+Count = 149
+Nonce = b4aaf9ad1bde60
+Adata = 8c96c891456ddec29fe04299506723db2079a6667f96db5d198bf085acf2a4ef
+CT = 5287cc160c5dd3a0f9c1986aac2a621c
+Result = Fail
+
+[Alen = 32, Plen = 0, Nlen = 13, Tlen = 4]
+
+Key = a4bc10b1a62c96d459fbaf3a5aa3face7313bb9e1253e696f96a7a8e36801088
+
+Count = 150
+Nonce = a544218dadd3c10583db49cf39
+Adata = 3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e09a1005e024f6907
+CT = 866d4227
+Result = Pass
+Payload = 00
+
+Count = 151
+Nonce = e8de970f6ee8e80ede933581b5
+Adata = 89f8b068d34f56bc49d839d8e47b347e6dae737b903b278632447e6c0485d26a
+CT = 94cb1127
+Result = Fail
+
+Count = 152
+Nonce = 6de75d3c05e83755083399a5f7
+Adata = 504b08cf34cbe17acf631ef219ae01437ebb6a980ab2f00121bb3073701b6511
+CT = 82c2b67a
+Result = Fail
+
+Count = 153
+Nonce = 58d43b9f1581c590daab1a5c56
+Adata = 749f149ef306c70a5d006d9777adbbf7c0de453898c2978ef7c281535ea9b24c
+CT = 8c8283f9
+Result = Fail
+
+Count = 154
+Nonce = dfdcbdff329f7af70731d8e276
+Adata = 2ae56ddde2876d70b3b34eda8c2b1d096c836d5225d53ec460b724b6e16aa5a3
+CT = c4ac0952
+Result = Pass
+Payload = 00
+
+Count = 155
+Nonce = 199ec321d1d24d5408076912d6
+Adata = a77526f3614cd974498a76d8b3cb7bacc623fdc9c85503289c462df888b199ed
+CT = c59aa931
+Result = Fail
+
+Count = 156
+Nonce = 60f2490ba0c658848859fcbea8
+Adata = 3ad743283064929bf4fe4e0807f710f5e6a273e22614c728c3280a27b6c614a0
+CT = 27c3953d
+Result = Pass
+Payload = 00
+
+Count = 157
+Nonce = 6f29ca274190400720bba27651
+Adata = c0850aaf141bd3f1b24f4d882590f58682b41f874748f29f8925b4914f444842
+CT = cb1ac8eb
+Result = Fail
+
+Count = 158
+Nonce = f1dfb6fdb31cb423226f181c09
+Adata = ac6b08900fc1c9463e7dfdb60eee444c4989d7b200e675f3220ba1e14eed0ab4
+CT = 4dcc55cc
+Result = Fail
+
+Count = 159
+Nonce = 0d45226c98eaa9bb445a3aa4f9
+Adata = b9cb3e1a5bcccb0b0599414c9822275b66fa0f913d51bdb0a2228cbb5aad0e0a
+CT = 727d8f5e
+Result = Fail
+
+Count = 160
+Nonce = 39cdbb24bd273a3fe96f42ca9d
+Adata = ddfe6c22f4cdc3128050072005f5bd4ecdef1d836e891683f1ba921d33fafba7
+CT = 5aa56a54
+Result = Fail
+
+Count = 161
+Nonce = db113f38f0504615c5c9347c3d
+Adata = 3b71bc84e48c6dadf6ead14621d22468a3d4c9c103ac96970269730bcfce239b
+CT = c38fbdff
+Result = Pass
+Payload = 00
+
+Count = 162
+Nonce = d16a20ef5f6587f1ee3cb7850b
+Adata = b1133e1cd369617a9f937e9a1eb86a0979ee30b5b7b0b6ff838d9e11301d6b72
+CT = 6be30c42
+Result = Fail
+
+Count = 163
+Nonce = d35f531f714694b5e49303a980
+Adata = 55b791ee495299916ff3c2327b4990952bebd0a2da9acfc553c6c996e354a4b5
+CT = d34e90bb
+Result = Pass
+Payload = 00
+
+Count = 164
+Nonce = 220624db34a022b758473994a2
+Adata = 5b3b2ae87b0d6759f38a858423227f8687f35478a8f565409b741eadcac4d8c4
+CT = 4a5d14bc
+Result = Fail
+
+[Alen = 32, Plen = 0, Nlen = 13, Tlen = 16]
+
+Key = 8c5cf3457ff22228c39c051c4e05ed4093657eb303f859a9d4b0f8be0127d88a
+
+Count = 165
+Nonce = a544218dadd3c10583db49cf39
+Adata = 3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e09a1005e024f6907
+CT = 867b0d87cf6e0f718200a97b4f6d5ad5
+Result = Pass
+Payload = 00
+
+Count = 166
+Nonce = e8de970f6ee8e80ede933581b5
+Adata = 89f8b068d34f56bc49d839d8e47b347e6dae737b903b278632447e6c0485d26a
+CT = 677a040d46ee3f2b7838273bdad14f16
+Result = Fail
+
+Count = 167
+Nonce = 6de75d3c05e83755083399a5f7
+Adata = 504b08cf34cbe17acf631ef219ae01437ebb6a980ab2f00121bb3073701b6511
+CT = f650d46ade2cbabbc68ead6df1ea0c37
+Result = Fail
+
+Count = 168
+Nonce = 58d43b9f1581c590daab1a5c56
+Adata = 749f149ef306c70a5d006d9777adbbf7c0de453898c2978ef7c281535ea9b24c
+CT = 11b8fe8c139ee38f77fd8fa552cbff67
+Result = Fail
+
+Count = 169
+Nonce = dfdcbdff329f7af70731d8e276
+Adata = 2ae56ddde2876d70b3b34eda8c2b1d096c836d5225d53ec460b724b6e16aa5a3
+CT = ad879c64425e6c1ec4841bbb0f99aa8b
+Result = Pass
+Payload = 00
+
+Count = 170
+Nonce = 199ec321d1d24d5408076912d6
+Adata = a77526f3614cd974498a76d8b3cb7bacc623fdc9c85503289c462df888b199ed
+CT = 3c64f8731930ae000162c10654531066
+Result = Fail
+
+Count = 171
+Nonce = 60f2490ba0c658848859fcbea8
+Adata = 3ad743283064929bf4fe4e0807f710f5e6a273e22614c728c3280a27b6c614a0
+CT = e2751f153fc76c0dec5e0cf2d30c1a28
+Result = Pass
+Payload = 00
+
+Count = 172
+Nonce = 6f29ca274190400720bba27651
+Adata = c0850aaf141bd3f1b24f4d882590f58682b41f874748f29f8925b4914f444842
+CT = 76127bf891141e73854752ed10c02bd0
+Result = Fail
+
+Count = 173
+Nonce = f1dfb6fdb31cb423226f181c09
+Adata = ac6b08900fc1c9463e7dfdb60eee444c4989d7b200e675f3220ba1e14eed0ab4
+CT = 4bd833f9da0496e5f6a08a05d02df385
+Result = Fail
+
+Count = 174
+Nonce = 0d45226c98eaa9bb445a3aa4f9
+Adata = b9cb3e1a5bcccb0b0599414c9822275b66fa0f913d51bdb0a2228cbb5aad0e0a
+CT = 05f166328a67a8c58b10a7348f3df612
+Result = Fail
+
+Count = 175
+Nonce = 39cdbb24bd273a3fe96f42ca9d
+Adata = ddfe6c22f4cdc3128050072005f5bd4ecdef1d836e891683f1ba921d33fafba7
+CT = 42499bcd949a5163855a9794f11f917e
+Result = Fail
+
+Count = 176
+Nonce = db113f38f0504615c5c9347c3d
+Adata = 3b71bc84e48c6dadf6ead14621d22468a3d4c9c103ac96970269730bcfce239b
+CT = fc85464a81fe372c12c9e4f0f3bf9c37
+Result = Pass
+Payload = 00
+
+Count = 177
+Nonce = d16a20ef5f6587f1ee3cb7850b
+Adata = b1133e1cd369617a9f937e9a1eb86a0979ee30b5b7b0b6ff838d9e11301d6b72
+CT = 8c7501f423647dee77668858c5e350bb
+Result = Fail
+
+Count = 178
+Nonce = d35f531f714694b5e49303a980
+Adata = 55b791ee495299916ff3c2327b4990952bebd0a2da9acfc553c6c996e354a4b5
+CT = b1c09b093788da19e33c5a6e82ed9627
+Result = Pass
+Payload = 00
+
+Count = 179
+Nonce = 220624db34a022b758473994a2
+Adata = 5b3b2ae87b0d6759f38a858423227f8687f35478a8f565409b741eadcac4d8c4
+CT = d2231ee1455b0bc337c4f8173fb8647c
+Result = Fail
+
+[Alen = 32, Plen = 24, Nlen = 7, Tlen = 4]
+
+Key = 8c5cf3457ff22228c39c051c4e05ed4093657eb303f859a9d4b0f8be0127d88a
+
+Count = 180
+Nonce = a544218dadd3c1
+Adata = d3d5424e20fbec43ae495353ed830271515ab104f8860c988d15b6d36c038eab
+CT = c2fe12658139f5d0dd22cadf2e901695b579302a72fc56083ebc7720
+Result = Pass
+Payload = 78c46e3249ca28e1ef0531d80fd37c124d9aecb7be6668e3
+
+Count = 181
+Nonce = 6ba004fd176791
+Adata = 5a053b2a1bb87e85d56527bfcdcd3ecafb991bb10e4c862bb0751c700a29f54b
+CT = 94748ba81229e53c38583a8564b23ebbafc6f6efdf4c2a81c44db2c9
+Result = Fail
+
+Count = 182
+Nonce = 45c5c284836414
+Adata = 8f01a61eb17366d4e70942ab69b4f4bcf8ff6a97f5972ee5780a264c9dcf7d93
+CT = 1d670ccf3e9ba59186c48da2e5bd0ab21973eee2ea2985bf83a09067
+Result = Fail
+
+Count = 183
+Nonce = c69f7679c80546
+Adata = 5d6c04a5b422b46065a79a889e30ac8d1b53b65d230d4c88190903a24e1fe1ea
+CT = 2c8c80ff10fac1bf6c9c83533c1514ee032c0983730b0657392ae25d
+Result = Fail
+
+Count = 184
+Nonce = 57b940550a383b
+Adata = 33c2c3a57bf8393b126982c96d87daeacd5eadad1519073ad8c84cb9b760296f
+CT = e1b4ec4279bb62902c12521e6b874171695c5da46c647cc03b91ff03
+Result = Pass
+Payload = 6fb5ce32a851676753ba3523edc5ca82af1843ffc08f1ef0
+
+Count = 185
+Nonce = 11edd12ea5873d
+Adata = e32e5384038379e2b7382ba337b6f7a72a1569e110ee89c4dd6aa6f7e69f5250
+CT = b5dda89fe879d6a665b99285b6d937fd5877ebef4de049fb64b837fb
+Result = Fail
+
+Count = 186
+Nonce = f32222e9eec4bd
+Adata = 684595e36eda1db5f586941c9f34c9f8d477970d5ccc14632d1f0cec8190ae68
+CT = 224db21beb8cd0069007660e783c3f85706b014128368aab2a4e56a7
+Result = Pass
+Payload = 2c29d4e2bb9294e90cb04ec697e663a1f7385a39f90c8ccf
+
+Count = 187
+Nonce = e0a0a7f262cb51
+Adata = 1d93b2856ad2bf3700440f9a281bd8947ba209e9ffd18e69921ed0678c957c6c
+CT = ba1ce3a799e1173178b6788723005566f9269d5828c85d28e960a769
+Result = Fail
+
+Count = 188
+Nonce = 40316e7b38bdad
+Adata = 6e49acd9c26944740c778e74b1dbaa8d640c7e18e949a1661f8a77543db69e1f
+CT = 79d59e4bb251988c019c4eaaee2a2513f9cb0521334018fded14a5a5
+Result = Fail
+
+Count = 189
+Nonce = 33008ef5baf263
+Adata = a726f31d9a22bfc0e7e4c3111b0d304e106ab04ed318f8bfe6ec9cb3a811285b
+CT = af4350795f24087aa05070d6d5f55ebb12d7ad3141066866d7d6c61d
+Result = Fail
+
+Count = 190
+Nonce = b48a16fb9a065d
+Adata = be05e9c934c1dcba45223d47c6646a2d13c3b93265e354ae4970484b5101d809
+CT = 22d2da531be1f0d1da4bc21f984d29bf56bed2e92da6bf42d0605b84
+Result = Fail
+
+Count = 191
+Nonce = 14c9bd561c47c1
+Adata = 141ae365f8e65ab9196c4e8cd4e62189b304d67de38f2117e84ec0ec8f260ebd
+CT = 61b46c9024eed3989064a52df90349c18e14e4b552779d3f8f9d6814
+Result = Pass
+Payload = c22524a1ea444be3412b0d773d4ea2ff0af4c1ad2383cba8
+
+Count = 192
+Nonce = 5fb871eac2e52a
+Adata = ff23906e9067da8999842318f2a867759ca2d171395c2ff31fa5a4e2ab349c45
+CT = 539799c2b22a33dd648fc4497d12f9455beaf932f1eaaff4d930f5ce
+Result = Fail
+
+Count = 193
+Nonce = 1ccec9923aa6e8
+Adata = 88a6d037009a1c1756f72bb4589d6d940bd514ed55386baefacc6ac3ca6f8795
+CT = 52f8205534447d722be2b9377f7395938cc88af081a11ccb0d83fa19
+Result = Pass
+Payload = 518a7fb11c463bf23798982118f3cfe4d7ddde9184f37d4f
+
+Count = 194
+Nonce = 68a5351e4422c8
+Adata = 303c767468f48ac9f6e331bbad535b06aa00ab593327320799e17eff63afd3fe
+CT = d11c892ae155098f5e4b5fe60c7afd74fb2dbcc4db956556f243e273
+Result = Fail
+
+[Alen = 32, Plen = 24, Nlen = 7, Tlen = 16]
+
+Key = 705334e30f53dd2f92d190d2c1437c8772f940c55aa35e562214ed45bd458ffe
+
+Count = 195
+Nonce = a544218dadd3c1
+Adata = d3d5424e20fbec43ae495353ed830271515ab104f8860c988d15b6d36c038eab
+CT = 3341168eb8c48468c414347fb08f71d2086f7c2d1bd581ce1ac68bd42f5ec7fa7e068cc0ecd79c2a
+Result = Pass
+Payload = 78c46e3249ca28e1ef0531d80fd37c124d9aecb7be6668e3
+
+Count = 196
+Nonce = 6ba004fd176791
+Adata = 5a053b2a1bb87e85d56527bfcdcd3ecafb991bb10e4c862bb0751c700a29f54b
+CT = d543acda712b898cbb27b8f598b2e4438ce587a836e2785147c3338a2400809e739b63ba8227d2f9
+Result = Fail
+
+Count = 197
+Nonce = 45c5c284836414
+Adata = 8f01a61eb17366d4e70942ab69b4f4bcf8ff6a97f5972ee5780a264c9dcf7d93
+CT = 39a8af5c976b995ea8049e55b68bc65503592ab00915638646288ce9dd1c7088c752e35947fdca98
+Result = Fail
+
+Count = 198
+Nonce = c69f7679c80546
+Adata = 5d6c04a5b422b46065a79a889e30ac8d1b53b65d230d4c88190903a24e1fe1ea
+CT = 950fbf6445f6ffb68178f52f5079d0c6081a48ae1f267a0b7fd89caef9388fbb82361b8d53d9edc6
+Result = Fail
+
+Count = 199
+Nonce = 57b940550a383b
+Adata = 33c2c3a57bf8393b126982c96d87daeacd5eadad1519073ad8c84cb9b760296f
+CT = fbfed2c94f50ca10466da9903ef85833ad48ca00556e66d14d8b30df941f3536ffb42083ef0e1c30
+Result = Pass
+Payload = 6fb5ce32a851676753ba3523edc5ca82af1843ffc08f1ef0
+
+Count = 200
+Nonce = 11edd12ea5873d
+Adata = e32e5384038379e2b7382ba337b6f7a72a1569e110ee89c4dd6aa6f7e69f5250
+CT = 2ebfeb7a843618b37025352df3538526517ed320adfb486c04cf3426e8f975125a7eed00e5f33b6c
+Result = Fail
+
+Count = 201
+Nonce = f32222e9eec4bd
+Adata = 684595e36eda1db5f586941c9f34c9f8d477970d5ccc14632d1f0cec8190ae68
+CT = dae13e6967c8b1ee0dd2d5ba1dd1de69f22c95da39528f9ef78e9e5e9faa058112af57f4ac78db2c
+Result = Pass
+Payload = 2c29d4e2bb9294e90cb04ec697e663a1f7385a39f90c8ccf
+
+Count = 202
+Nonce = e0a0a7f262cb51
+Adata = 1d93b2856ad2bf3700440f9a281bd8947ba209e9ffd18e69921ed0678c957c6c
+CT = e683040a0bcf04c1748e7746400d6ef0f7cd8e77a29517790c63959ce534a0f87fb42a9b000dec84
+Result = Fail
+
+Count = 203
+Nonce = 40316e7b38bdad
+Adata = 6e49acd9c26944740c778e74b1dbaa8d640c7e18e949a1661f8a77543db69e1f
+CT = 829e50e8c09e727a58287e6eb7d38edeb8ab39db279c06397d1a2111dc21aec79ef73193b306d31f
+Result = Fail
+
+Count = 204
+Nonce = 33008ef5baf263
+Adata = a726f31d9a22bfc0e7e4c3111b0d304e106ab04ed318f8bfe6ec9cb3a811285b
+CT = 873c91e76dca0062ae66325aefb84ece3e98928f8dbc5fee7c516d2d1a8318893923f398ca249401
+Result = Fail
+
+Count = 205
+Nonce = b48a16fb9a065d
+Adata = be05e9c934c1dcba45223d47c6646a2d13c3b93265e354ae4970484b5101d809
+CT = 343f6c86f2b852ac388a096faec4472107a924aba56d0cb88055e777bb57eb49497cd2e233ee06fd
+Result = Fail
+
+Count = 206
+Nonce = 14c9bd561c47c1
+Adata = 141ae365f8e65ab9196c4e8cd4e62189b304d67de38f2117e84ec0ec8f260ebd
+CT = a654238fb8b05e293dba07f9d68d75a7f0fbf40fe20edaeba1586bf922412e73ce338e372615c3bc
+Result = Pass
+Payload = c22524a1ea444be3412b0d773d4ea2ff0af4c1ad2383cba8
+
+Count = 207
+Nonce = 5fb871eac2e52a
+Adata = ff23906e9067da8999842318f2a867759ca2d171395c2ff31fa5a4e2ab349c45
+CT = 4846816923ed9f0254bdd0be01028f75061d3594ad3a45bd03538d108df6ecd6f39acfe076ba5fb8
+Result = Fail
+
+Count = 208
+Nonce = 1ccec9923aa6e8
+Adata = 88a6d037009a1c1756f72bb4589d6d940bd514ed55386baefacc6ac3ca6f8795
+CT = 765067ef768908d91ee4c3923943e0c7be70e2e06db99a4b3e3f51ee37fdcc5d81dd85d9e9d4f44e
+Result = Pass
+Payload = 518a7fb11c463bf23798982118f3cfe4d7ddde9184f37d4f
+
+Count = 209
+Nonce = 68a5351e4422c8
+Adata = 303c767468f48ac9f6e331bbad535b06aa00ab593327320799e17eff63afd3fe
+CT = e58ea6c1522e5a3e93a85edd05ae80d6cf5c4dd6d604a8f8d8a906488f79ad5d2234d72458dcfcd4
+Result = Fail
+
+[Alen = 32, Plen = 24, Nlen = 13, Tlen = 4]
+
+Key = 705334e30f53dd2f92d190d2c1437c8772f940c55aa35e562214ed45bd458ffe
+
+Count = 210
+Nonce = a544218dadd3c10583db49cf39
+Adata = 3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e09a1005e024f6907
+CT = c0ea400b599561e7905b99262b4565d5c3dc49fad84d7c69ef891339
+Result = Pass
+Payload = e8de970f6ee8e80ede933581b5bcf4d837e2b72baa8b00c3
+
+Count = 211
+Nonce = 8fa501c5dd9ac9b868144c9fa5
+Adata = 5bb40e3bb72b4509324a7edc852f72535f1f6283156e63f6959ffaf39dcde800
+CT = 60871e03ea0eb968536c99f926ea24ef43d41272ad9fb7f63d488623
+Result = Fail
+
+Count = 212
+Nonce = 9bc0d1502a47e46350fe8667ca
+Adata = 07203674260208d5bd4d39506836f7e76ffc58e938799f21aff7bb4dea4410d2
+CT = 81d7859dcbe51dcc94fe2591cd3b0540003d49a8c4dccbf4527e5ed0
+Result = Fail
+
+Count = 213
+Nonce = 611cb4c66e88f6acf96fea1919
+Adata = 327ee3657e49d4d988362fabae303ccea6638e5cb45993d9d56269bc3d3af32b
+CT = bef380ad725b65fb5fceeabf09c665bc35089f434ec831494d20d5fa
+Result = Fail
+
+Count = 214
+Nonce = 0dd613c0fe28e913c0edbb8404
+Adata = 2ad306575b577c2f61da7212ab63e3db3941f1f751f2356c7443531a90b9d141
+CT = fabe11c9629e598228f5209f3dbcc641fe4b1a22cadb0821d2898c3b
+Result = Pass
+Payload = 9522fb1f1aa58493cba682d788186d902cfc93e80fd6b998
+
+Count = 215
+Nonce = 68806dfe720d0a9a84697de5f2
+Adata = c6b0e4dfd723d7637510f887b7852f60ecdf72e0d33396560fed6534d5b7f015
+CT = b7eb87f84951640de731d4093f1a4ed5f831138a27465d3941e92090
+Result = Fail
+
+Count = 216
+Nonce = 3e0fe3427eeda80f02dda4fed5
+Adata = ae0d1c9c834d60ff0ecfb3c0d78c72ddb789e58adfc166c81d5fc6395b31ec33
+CT = d88f8fcd772125212ce09c2a6e5b5693dd35073f992004f0d18fc889
+Result = Pass
+Payload = 38333ce78110bf53a2c2abc7db99e133ad218ca43ff7a7bc
+
+Count = 217
+Nonce = 7c0c76d9f9316ff6c98758b464
+Adata = 31a0338c3839931fa1dd5131cb796c4c6cfde9fb336d8a80ac35dec463be7a94
+CT = d2d7d52b11304fc1d15b8c20e296ba7c63d99f4ce86cc8ae0f39ecea
+Result = Fail
+
+Count = 218
+Nonce = 07c728135bdfede0e0c8036b17
+Adata = 25a152850b4b80b19d8f0b504b2a8a241824b3a1fca8d85c8713b2c0c84b5e02
+CT = ae1d9f82efb464d5dc2018cffa309634c09b34d1122c4bd994b1d516
+Result = Fail
+
+Count = 219
+Nonce = 710c96d7a6f09de83f0507f28a
+Adata = 2d64acfdbfc582cd9a933790eb1b739fb02e53f511255e49f421bb7acc98a130
+CT = 477c985d92ad1b69d22315235a29e3d3a5991487cbdc8d11d394d047
+Result = Fail
+
+Count = 220
+Nonce = 977bbcdeb6a7d9dcf8664bc2d8
+Adata = 135786125258a49475338ac1961d2718433b9e84cf64f63ca52913e8dd12e505
+CT = d1c085c75d808dc6db493b8a0b4d884e0700d2844a1b4b46bd3d22eb
+Result = Fail
+
+Count = 221
+Nonce = 60122cbd219e5cf17415e8bc09
+Adata = 895a45ddbe0c80793eccbf820de13a233b6aa7045cfd5313388e7184c392b216
+CT = 76bdd9a7b34bf14ae121a87fdfa144f71b848744af6a2f0b1c0d067c
+Result = Pass
+Payload = 794e734966e6d0001699aec3f8ab8f194de7653d3091b1b9
+
+Count = 222
+Nonce = 83a07f2e685959cb50a1bd2bce
+Adata = 02afe300ec0cf0acb59108b2f70e069300294e34f40bb032cb59907599664408
+CT = 413e2e8df9d65b4e5d3b63a738258aaee643f364be9a01b974192744
+Result = Fail
+
+Count = 223
+Nonce = 3542fbe0f59a6d5f3abf619b7d
+Adata = dd4531f158a2fa3bc8a339f770595048f4a42bc1b03f2e824efc6ba4985119d8
+CT = 617d8036e2039d516709062379e0550cbd71ebb90fea967c79018ad5
+Result = Pass
+Payload = c5b3d71312ea14f2f8fae5bd1a453192b6604a45db75c5ed
+
+Count = 224
+Nonce = 48f2d4c0b17072e0a9c300d90b
+Adata = c56175e2cfe0d37454d989afcc36686fb34c015439601567506a4d0003182be7
+CT = 40e609c739e409750a6c41d9c6ea64ce36f70711b4ca3e365c916f91
+Result = Fail
+
+[Alen = 32, Plen = 24, Nlen = 13, Tlen = 16]
+
+Key = 314a202f836f9f257e22d8c11757832ae5131d357a72df88f3eff0ffcee0da4e
+
+Count = 225
+Nonce = a544218dadd3c10583db49cf39
+Adata = 3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e09a1005e024f6907
+CT = 8d34cdca37ce77be68f65baf3382e31efa693e63f914a781367f30f2eaad8c063ca50795acd90203
+Result = Pass
+Payload = e8de970f6ee8e80ede933581b5bcf4d837e2b72baa8b00c3
+
+Count = 226
+Nonce = 8fa501c5dd9ac9b868144c9fa5
+Adata = 5bb40e3bb72b4509324a7edc852f72535f1f6283156e63f6959ffaf39dcde800
+CT = 516c0095cc3d85fd55e48da17c592e0c7014b9daafb82bdc4b41096dfdbe9cc1ab610f8f3e038d16
+Result = Fail
+
+Count = 227
+Nonce = 9bc0d1502a47e46350fe8667ca
+Adata = 07203674260208d5bd4d39506836f7e76ffc58e938799f21aff7bb4dea4410d2
+CT = 0293eae9f8d8bd7ad45357f733fc7b5d990d894783e18501d81ec96df41b8fa8262ed2db880b5e85
+Result = Fail
+
+Count = 228
+Nonce = 611cb4c66e88f6acf96fea1919
+Adata = 327ee3657e49d4d988362fabae303ccea6638e5cb45993d9d56269bc3d3af32b
+CT = 256bad8295e67d8d450f5ecc8276920ec23b1156c57be7c96ee80f60f72db2cbf25b2f8c6af8749c
+Result = Fail
+
+Count = 229
+Nonce = 0dd613c0fe28e913c0edbb8404
+Adata = 2ad306575b577c2f61da7212ab63e3db3941f1f751f2356c7443531a90b9d141
+CT = 6df09613ea986c2d91a57a45a0942cbf20e0dfca12fbda8c945ee6db24aea5f5098952f1203339ce
+Result = Pass
+Payload = 9522fb1f1aa58493cba682d788186d902cfc93e80fd6b998
+
+Count = 230
+Nonce = 68806dfe720d0a9a84697de5f2
+Adata = c6b0e4dfd723d7637510f887b7852f60ecdf72e0d33396560fed6534d5b7f015
+CT = c5b64577d3c34e50f7da5072db5bda1d1d2c6db1a4f1183e2cc4c90ac3f798957cb09a05868a8ad5
+Result = Fail
+
+Count = 231
+Nonce = 3e0fe3427eeda80f02dda4fed5
+Adata = ae0d1c9c834d60ff0ecfb3c0d78c72ddb789e58adfc166c81d5fc6395b31ec33
+CT = 2bfe51f1f43b982d47f76ea8206ddbf585d6f30cec0d4ef16b1556631d3b52bf24154afec1448ef6
+Result = Pass
+Payload = 38333ce78110bf53a2c2abc7db99e133ad218ca43ff7a7bc
+
+Count = 232
+Nonce = 7c0c76d9f9316ff6c98758b464
+Adata = 31a0338c3839931fa1dd5131cb796c4c6cfde9fb336d8a80ac35dec463be7a94
+CT = 1622ae109073f44a4596722d9943fea774dfc2a1f939fc0914f42ec81e3af71c9a5de7e0ac16ca69
+Result = Fail
+
+Count = 233
+Nonce = 07c728135bdfede0e0c8036b17
+Adata = 25a152850b4b80b19d8f0b504b2a8a241824b3a1fca8d85c8713b2c0c84b5e02
+CT = 4c0b361a766d366d983c41e793d75635e17f6eab2eadcf9743d67d90850c4c76a43df1f95170b29b
+Result = Fail
+
+Count = 234
+Nonce = 710c96d7a6f09de83f0507f28a
+Adata = 2d64acfdbfc582cd9a933790eb1b739fb02e53f511255e49f421bb7acc98a130
+CT = 5b02347f30213df7f1506d7dca41b838c92aea0f190c5dba7bd5d5c8c098299394333b34fae9a110
+Result = Fail
+
+Count = 235
+Nonce = 977bbcdeb6a7d9dcf8664bc2d8
+Adata = 135786125258a49475338ac1961d2718433b9e84cf64f63ca52913e8dd12e505
+CT = c77283ca15484d82469ce7249d1fb8e5f4c3bc8245fb4d97e26149d4a9711be81b4f69aa9fabd7f6
+Result = Fail
+
+Count = 236
+Nonce = 60122cbd219e5cf17415e8bc09
+Adata = 895a45ddbe0c80793eccbf820de13a233b6aa7045cfd5313388e7184c392b216
+CT = bf0d219bb50fcc1d51f654bb0fd8b44efa25aef39e2f11afe47d00f2eebb544e6ba7559ac2f34edb
+Result = Pass
+Payload = 794e734966e6d0001699aec3f8ab8f194de7653d3091b1b9
+
+Count = 237
+Nonce = 83a07f2e685959cb50a1bd2bce
+Adata = 02afe300ec0cf0acb59108b2f70e069300294e34f40bb032cb59907599664408
+CT = 1609f8de59da4f50ce034977d132d4f9881a9b85ffa5bb886fa3fddc87690a359fe55f8fa12ba749
+Result = Fail
+
+Count = 238
+Nonce = 3542fbe0f59a6d5f3abf619b7d
+Adata = dd4531f158a2fa3bc8a339f770595048f4a42bc1b03f2e824efc6ba4985119d8
+CT = 39c2e8f6edfe663b90963b98eb79e2d4f7f28a5053ae8881567a6b4426f1667136bed4a5e32a2bc1
+Result = Pass
+Payload = c5b3d71312ea14f2f8fae5bd1a453192b6604a45db75c5ed
+
+Count = 239
+Nonce = 48f2d4c0b17072e0a9c300d90b
+Adata = c56175e2cfe0d37454d989afcc36686fb34c015439601567506a4d0003182be7
+CT = 27c575be0b99af9b106f53f471c31cac4d54ea0bcb602a33fb67bb6092cd579f722ae9b680da083d
+Result = Fail
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT256.txt b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT256.txt
new file mode 100644
index 0000000000..6d9a3eadcb
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT256.txt
@@ -0,0 +1,1589 @@
+# CAVS 11.0
+# "CCM-DVPT" information
+# AES Keylen: 256
+# Generated on Tue Mar 15 08:09:26 2011
+
+
+[Alen = 0, Plen = 0, Nlen = 7, Tlen = 4]
+
+Key = eda32f751456e33195f1f499cf2dc7c97ea127b6d488f211ccc5126fbb24afa6
+
+Count = 0
+Nonce = a544218dadd3c1
+Adata = 00
+CT = 469c90bb
+Result = Pass (0)
+Payload = 00
+
+Count = 1
+Nonce = d3d5424e20fbec
+Adata = 00
+CT = 46a908ed
+Result = Fail (2 - CT changed)
+
+Count = 2
+Nonce = e776620a3bd961
+Adata = 00
+CT = fdd35c4d
+Result = Fail (1 - Adata changed)
+
+Count = 3
+Nonce = 6c7a3be9f9ad55
+Adata = 00
+CT = 869ce60e
+Result = Fail (1 - Adata changed)
+
+Count = 4
+Nonce = dbb3923156cfd6
+Adata = 00
+CT = 1302d515
+Result = Pass (0)
+Payload = 00
+
+Count = 5
+Nonce = b390f67eaef8f5
+Adata = 00
+CT = 156416ee
+Result = Fail (2 - CT changed)
+
+Count = 6
+Nonce = a259c114eaac89
+Adata = 00
+CT = 4fe06e92
+Result = Pass (0)
+Payload = 00
+
+Count = 7
+Nonce = 7fc8804fef18ef
+Adata = 00
+CT = 611091aa
+Result = Fail (2 - CT changed)
+
+Count = 8
+Nonce = fbaf4cbc49fa0f
+Adata = 00
+CT = 696e9371
+Result = Fail (2 - CT changed)
+
+Count = 9
+Nonce = 2ed0c8761dbf04
+Adata = 00
+CT = a0e0a2cb
+Result = Fail (2 - CT changed)
+
+Count = 10
+Nonce = 346bb04ea0db86
+Adata = 00
+CT = 43cc0375
+Result = Fail (1 - Adata changed)
+
+Count = 11
+Nonce = e1be89af98ffd7
+Adata = 00
+CT = e5417f6b
+Result = Pass (0)
+Payload = 00
+
+Count = 12
+Nonce = a6a0d57aaaf012
+Adata = 00
+CT = fff8a068
+Result = Fail (1 - Adata changed)
+
+Count = 13
+Nonce = 1aa758eb2f9a28
+Adata = 00
+CT = f8fa8e71
+Result = Pass (0)
+Payload = 00
+
+Count = 14
+Nonce = 2911167fc98fc3
+Adata = 00
+CT = 0bfa2d9d
+Result = Fail (1 - Adata changed)
+
+[Alen = 0, Plen = 0, Nlen = 7, Tlen = 16]
+
+Key = e1b8a927a95efe94656677b692662000278b441c79e879dd5c0ddc758bdc9ee8
+
+Count = 15
+Nonce = a544218dadd3c1
+Adata = 00
+CT = 8207eb14d33855a52acceed17dbcbf6e
+Result = Pass (0)
+Payload = 00
+
+Count = 16
+Nonce = d3d5424e20fbec
+Adata = 00
+CT = 60f8e127cb4d30db6df0622158cd931d
+Result = Fail (2 - CT changed)
+
+Count = 17
+Nonce = e776620a3bd961
+Adata = 00
+CT = 4239f29871651e9a26b8b06ffc5b3748
+Result = Fail (1 - Adata changed)
+
+Count = 18
+Nonce = 6c7a3be9f9ad55
+Adata = 00
+CT = 5d35364c621fe8959dfe70ab44700fbe
+Result = Fail (1 - Adata changed)
+
+Count = 19
+Nonce = dbb3923156cfd6
+Adata = 00
+CT = e4dc5e03aacea691262ee69cee8ffbbe
+Result = Pass (0)
+Payload = 00
+
+Count = 20
+Nonce = b390f67eaef8f5
+Adata = 00
+CT = c8eb7643b4ed3c796c3873e8c6624e0d
+Result = Fail (2 - CT changed)
+
+Count = 21
+Nonce = a259c114eaac89
+Adata = 00
+CT = f79c53fd5e69835b7e70496ea999718b
+Result = Pass (0)
+Payload = 00
+
+Count = 22
+Nonce = 7fc8804fef18ef
+Adata = 00
+CT = 687e00723a419fa81c0923b8b8e245ae
+Result = Fail (2 - CT changed)
+
+Count = 23
+Nonce = fbaf4cbc49fa0f
+Adata = 00
+CT = 499ab350309ad6091ec4aaf6bf0cbd00
+Result = Fail (2 - CT changed)
+
+Count = 24
+Nonce = 2ed0c8761dbf04
+Adata = 00
+CT = c27b9f14787dc5375f59d0c561a23446
+Result = Fail (2 - CT changed)
+
+Count = 25
+Nonce = 346bb04ea0db86
+Adata = 00
+CT = 655c737722c78ac96582a883d407b2bb
+Result = Fail (1 - Adata changed)
+
+Count = 26
+Nonce = e1be89af98ffd7
+Adata = 00
+CT = 10d3f6fe08280d45e67e58fe41a7f036
+Result = Pass (0)
+Payload = 00
+
+Count = 27
+Nonce = a6a0d57aaaf012
+Adata = 00
+CT = b4e425e43edb92c606f7cb2de8a06932
+Result = Fail (1 - Adata changed)
+
+Count = 28
+Nonce = 1aa758eb2f9a28
+Adata = 00
+CT = 2590df2453cb94c304ba0a2bff3f3c71
+Result = Pass (0)
+Payload = 00
+
+Count = 29
+Nonce = 2911167fc98fc3
+Adata = 00
+CT = 1f344e30dfa95b2319e274caa5780e60
+Result = Fail (1 - Adata changed)
+
+[Alen = 0, Plen = 0, Nlen = 13, Tlen = 4]
+
+Key = e1b8a927a95efe94656677b692662000278b441c79e879dd5c0ddc758bdc9ee8
+
+Count = 30
+Nonce = a544218dadd3c10583db49cf39
+Adata = 00
+CT = 8a19a133
+Result = Pass (0)
+Payload = 00
+
+Count = 31
+Nonce = 3c0e2815d37d844f7ac240ba9d
+Adata = 00
+CT = 2e317f1b
+Result = Fail (2 - CT changed)
+
+Count = 32
+Nonce = 75549e7e5657e5fe19872fcee0
+Adata = 00
+CT = 979bdcfe
+Result = Fail (1 - Adata changed)
+
+Count = 33
+Nonce = d071ff72735820d73485870e83
+Adata = 00
+CT = 8ef89acf
+Result = Fail (1 - Adata changed)
+
+Count = 34
+Nonce = 79ac204a26b9fee1132370c20f
+Adata = 00
+CT = 154024b2
+Result = Pass (0)
+Payload = 00
+
+Count = 35
+Nonce = a64bbc3d6d377dab513f7d9ce8
+Adata = 00
+CT = 8dbcc439
+Result = Fail (2 - CT changed)
+
+Count = 36
+Nonce = 0545fd9ecbc73ccdbbbd4244fd
+Adata = 00
+CT = 5c349fb2
+Result = Pass (0)
+Payload = 00
+
+Count = 37
+Nonce = 182fb47a12becf0bfe65df1287
+Adata = 00
+CT = 79df3e02
+Result = Fail (2 - CT changed)
+
+Count = 38
+Nonce = f342059a6f9dc14226b40debc4
+Adata = 00
+CT = fbc2c500
+Result = Fail (2 - CT changed)
+
+Count = 39
+Nonce = 6cbfe6bb4c9b171b93d28e9f8f
+Adata = 00
+CT = 2fac1bca
+Result = Fail (2 - CT changed)
+
+Count = 40
+Nonce = 82877df921c6ade43064ad963e
+Adata = 00
+CT = 99948f6e
+Result = Fail (1 - Adata changed)
+
+Count = 41
+Nonce = 0a37f2e7c66490e97285f1b09e
+Adata = 00
+CT = c59bf14c
+Result = Pass (0)
+Payload = 00
+
+Count = 42
+Nonce = d7b9c346ce2f8bad9623122e10
+Adata = 00
+CT = b764c393
+Result = Fail (1 - Adata changed)
+
+Count = 43
+Nonce = c1ad812bf2bbb2cdaee4636ee7
+Adata = 00
+CT = 5b96f41d
+Result = Pass (0)
+Payload = 00
+
+Count = 44
+Nonce = b6ce7d00731184b24428df046b
+Adata = 00
+CT = f7e12df1
+Result = Fail (1 - Adata changed)
+
+[Alen = 0, Plen = 0, Nlen = 13, Tlen = 16]
+
+Key = af063639e66c284083c5cf72b70d8bc277f5978e80d9322d99f2fdc718cda569
+
+Count = 45
+Nonce = a544218dadd3c10583db49cf39
+Adata = 00
+CT = 97e1a8dd4259ccd2e431e057b0397fcf
+Result = Pass (0)
+Payload = 00
+
+Count = 46
+Nonce = 3c0e2815d37d844f7ac240ba9d
+Adata = 00
+CT = 5a9596c511ea6a8671adefc4f2157d8b
+Result = Fail (2 - CT changed)
+
+Count = 47
+Nonce = 75549e7e5657e5fe19872fcee0
+Adata = 00
+CT = 66f5c53efbc74fa02dedc303fd95133a
+Result = Fail (1 - Adata changed)
+
+Count = 48
+Nonce = d071ff72735820d73485870e83
+Adata = 00
+CT = 2dfd3c852f68eace45acf433a6aa9c05
+Result = Fail (1 - Adata changed)
+
+Count = 49
+Nonce = 79ac204a26b9fee1132370c20f
+Adata = 00
+CT = 5c8c9a5b97be8c7bc01ca8d693b809f9
+Result = Pass (0)
+Payload = 00
+
+Count = 50
+Nonce = a64bbc3d6d377dab513f7d9ce8
+Adata = 00
+CT = ec093121bdcd589285f2262be8db5c4e
+Result = Fail (2 - CT changed)
+
+Count = 51
+Nonce = 0545fd9ecbc73ccdbbbd4244fd
+Adata = 00
+CT = 84201662b213c7a1ff0c1b3c25e4ec45
+Result = Pass (0)
+Payload = 00
+
+Count = 52
+Nonce = 182fb47a12becf0bfe65df1287
+Adata = 00
+CT = bbe746d6d31e8e9745faed4095ab8d5d
+Result = Fail (2 - CT changed)
+
+Count = 53
+Nonce = f342059a6f9dc14226b40debc4
+Adata = 00
+CT = 646c1258dc4aa6fc380818e70e5f4328
+Result = Fail (2 - CT changed)
+
+Count = 54
+Nonce = 6cbfe6bb4c9b171b93d28e9f8f
+Adata = 00
+CT = 15fa37ca7f2883a4642c1ed41b8f6293
+Result = Fail (2 - CT changed)
+
+Count = 55
+Nonce = 82877df921c6ade43064ad963e
+Adata = 00
+CT = c6acf5e5ded4efb2c314370ebb9e9cde
+Result = Fail (1 - Adata changed)
+
+Count = 56
+Nonce = 0a37f2e7c66490e97285f1b09e
+Adata = 00
+CT = 586e728193ce6db9a926b03b2d77dd6e
+Result = Pass (0)
+Payload = 00
+
+Count = 57
+Nonce = d7b9c346ce2f8bad9623122e10
+Adata = 00
+CT = 642a187e71feff5989e28184aded0199
+Result = Fail (1 - Adata changed)
+
+Count = 58
+Nonce = c1ad812bf2bbb2cdaee4636ee7
+Adata = 00
+CT = 64864d21b6ee3fca13f07fc0486e232d
+Result = Pass (0)
+Payload = 00
+
+Count = 59
+Nonce = b6ce7d00731184b24428df046b
+Adata = 00
+CT = 58c63ce68f132d30d177c5834344cc5d
+Result = Fail (1 - Adata changed)
+
+[Alen = 0, Plen = 24, Nlen = 7, Tlen = 4]
+
+Key = af063639e66c284083c5cf72b70d8bc277f5978e80d9322d99f2fdc718cda569
+
+Count = 60
+Nonce = a544218dadd3c1
+Adata = 00
+CT = 64a1341679972dc5869fcf69b19d5c5ea50aa0b5e985f5b722aa8d59
+Result = Pass (0)
+Payload = d3d5424e20fbec43ae495353ed830271515ab104f8860c98
+
+Count = 61
+Nonce = bfcda8b5a2d0d2
+Adata = 00
+CT = c5b7f802bffc498c1626e3774f1d9f94045dfd8e1a10a20277d00a75
+Result = Fail (2 - CT changed)
+
+Count = 62
+Nonce = 6bae7f35c56b27
+Adata = 00
+CT = bf432e246b7fa4aff8b3ada738432b51f6872ed92284db9d28588021
+Result = Fail (1 - Adata changed)
+
+Count = 63
+Nonce = c5e4214b1bf209
+Adata = 00
+CT = 0d5760ad0e156e401120a1ebd1b139248784c88e10e3425437921120
+Result = Fail (1 - Adata changed)
+
+Count = 64
+Nonce = 9d773a31fe2ec7
+Adata = 00
+CT = 5acfbe5e488976d8b9b77e69a736e8c919053f9415551209dce2d25e
+Result = Pass (0)
+Payload = 839d8cfa2c921c3cceb7d1f46bd2eaad706e53f64523d8c0
+
+Count = 65
+Nonce = f42cb0cce9efb6
+Adata = 00
+CT = be8be6046ac58411a00c131dd4a72d565f98d87a2c89124b1ef530d0
+Result = Fail (2 - CT changed)
+
+Count = 66
+Nonce = 24b7a65391f88b
+Adata = 00
+CT = f00628e10e8e0115b4a4532a1212a23aade4090832c1972d750125f3
+Result = Pass (0)
+Payload = 3bed52236182c19418867d468dbf47c8aac46c02445f99bb
+
+Count = 67
+Nonce = d2a7eb45780df3
+Adata = 00
+CT = 9078151f674d5f7b56e2451b0316156f776459f17d277e0108aaaf93
+Result = Fail (2 - CT changed)
+
+Count = 68
+Nonce = 046cbfd26093d8
+Adata = 00
+CT = 921cbecce3b06f3d655a5a0a4d212320d4f147575079fd23bd95e677
+Result = Fail (2 - CT changed)
+
+Count = 69
+Nonce = 51b13b0b04d077
+Adata = 00
+CT = 8cab1ff22d474e9863c153e84680e2a66981f036051360477e2ebb1d
+Result = Fail (2 - CT changed)
+
+Count = 70
+Nonce = ce2e9967bf9eb7
+Adata = 00
+CT = 15f476b5aefe072548a54f59506d9c3b9ce29025340214be662f8684
+Result = Fail (1 - Adata changed)
+
+Count = 71
+Nonce = b672c91376f533
+Adata = 00
+CT = 758aa03dc72c362c43b5f85bfaa3db4a74860887a8c29e47d5642830
+Result = Pass (0)
+Payload = 4f7a561e61b7861719e4445057ac9b74a9be953b772b09ec
+
+Count = 72
+Nonce = 62f6f1872462d8
+Adata = 00
+CT = ec645769b22161567e6a7e23aa06575bc767a34aa54d3cba01472fe1
+Result = Fail (1 - Adata changed)
+
+Count = 73
+Nonce = a6d01fb88ca547
+Adata = 00
+CT = 615cbeabbe163ba8bc9c073df9ad40833fcf3f424644ccc37aa999d7
+Result = Pass (0)
+Payload = a36155de477364236591e453008114075b4872120ef17264
+
+Count = 74
+Nonce = 46ad6ebbd8644a
+Adata = 00
+CT = 0ed6cc6451de57ca672d56dee45d4548a810d5c49dfe442dd27b7cf2
+Result = Fail (1 - Adata changed)
+
+[Alen = 0, Plen = 24, Nlen = 7, Tlen = 16]
+
+Key = f7079dfa3b5c7b056347d7e437bcded683abd6e2c9e069d333284082cbb5d453
+
+Count = 75
+Nonce = a544218dadd3c1
+Adata = 00
+CT = bc51c3925a960e7732533e4ef3a4f69ee6826de952bcb0fd374f3bb6db8377ebfc79674858c4f305
+Result = Pass (0)
+Payload = d3d5424e20fbec43ae495353ed830271515ab104f8860c98
+
+Count = 76
+Nonce = bfcda8b5a2d0d2
+Adata = 00
+CT = afa1fa8e8a70e26b02161150556d604101fdf423f332c3363275f2a4907d51b734fe7238cebbd48f
+Result = Fail (2 - CT changed)
+
+Count = 77
+Nonce = 6bae7f35c56b27
+Adata = 00
+CT = 72bc8ef21a847047091b673ccf231d35ecf6f4049741703be672f1f22cbe4a5305f19aaa6967237b
+Result = Fail (1 - Adata changed)
+
+Count = 78
+Nonce = c5e4214b1bf209
+Adata = 00
+CT = b719f6555fc4e5424273f5903d5672af460413110278707f400b152113c3976be63dcd9e7a84ddac
+Result = Fail (1 - Adata changed)
+
+Count = 79
+Nonce = 9d773a31fe2ec7
+Adata = 00
+CT = 4539bb13382b034ddb16a3329148f9243a4eee998fe444aff2870ce198af11f4fb698a67af6c89ad
+Result = Pass (0)
+Payload = 839d8cfa2c921c3cceb7d1f46bd2eaad706e53f64523d8c0
+
+Count = 80
+Nonce = f42cb0cce9efb6
+Adata = 00
+CT = 47cbb909cb12fa0a4b0f1aefd54c52d1edd1533290f76b8ccc98b3f5758972bf08ea9e88dc6e54ed
+Result = Fail (2 - CT changed)
+
+Count = 81
+Nonce = 24b7a65391f88b
+Adata = 00
+CT = 6d0f928352a17d63aca1899cbd305e1f831f1638d27c1e24432704eff9b6830476db3d30d4c103e4
+Result = Pass (0)
+Payload = 3bed52236182c19418867d468dbf47c8aac46c02445f99bb
+
+Count = 82
+Nonce = d2a7eb45780df3
+Adata = 00
+CT = e0e686d917f78b3b0058fed7b084976244789073a6305ff571256981db86f1e768170a104ebfb81d
+Result = Fail (2 - CT changed)
+
+Count = 83
+Nonce = 046cbfd26093d8
+Adata = 00
+CT = 960c573f5d6934a4cac49d06998f827b3d665cf02c998fe55efbbae6a346863a93d52e0321cef8b2
+Result = Fail (2 - CT changed)
+
+Count = 84
+Nonce = 51b13b0b04d077
+Adata = 00
+CT = 7cf8f4806848e34aa7d3bd7e2cb9f5d9ff21395ff6d34826ac2fdc3cc683f6120e405f446a10e0f3
+Result = Fail (2 - CT changed)
+
+Count = 85
+Nonce = ce2e9967bf9eb7
+Adata = 00
+CT = e4f6445ca36e7ee3323f11f6a5ca8ded0c85871e092aa687d254f7765b6155054a5efde28dd38750
+Result = Fail (1 - Adata changed)
+
+Count = 86
+Nonce = b672c91376f533
+Adata = 00
+CT = f23ac1426cb1130c9a0913b347d8efafb6ed125913aa678a9dc42d22a5436bc12eff5505edb25e19
+Result = Pass (0)
+Payload = 4f7a561e61b7861719e4445057ac9b74a9be953b772b09ec
+
+Count = 87
+Nonce = 62f6f1872462d8
+Adata = 00
+CT = ac9f131389181b1023f1ee47633aa433fc5d93a87d9ece962db05feb368ab772d977fd97b35262fa
+Result = Fail (1 - Adata changed)
+
+Count = 88
+Nonce = a6d01fb88ca547
+Adata = 00
+CT = 773b8eea2e9830297ac11d3c1f6ea4008c96040e83d76d55789d2043179fdd8fdcbd52313b7b15cb
+Result = Pass (0)
+Payload = a36155de477364236591e453008114075b4872120ef17264
+
+Count = 89
+Nonce = 46ad6ebbd8644a
+Adata = 00
+CT = d3fae92043c419fe8ac0d7491ca8041ad089559d895103cf079a2bac0ab4bc249bbdb330181cdd16
+Result = Fail (1 - Adata changed)
+
+[Alen = 0, Plen = 24, Nlen = 13, Tlen = 4]
+
+Key = f7079dfa3b5c7b056347d7e437bcded683abd6e2c9e069d333284082cbb5d453
+
+Count = 90
+Nonce = a544218dadd3c10583db49cf39
+Adata = 00
+CT = 63e00d30e4b08fd2a1cc8d70fab327b2368e77a93be4f4123d14fb3f
+Result = Pass (0)
+Payload = 3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e
+
+Count = 91
+Nonce = 894dcaa61008eb8fb052c60d41
+Adata = 00
+CT = bb5425b3869b76856ec58e39886fb6f6f2ac13fe44cb132d8d0c0099
+Result = Fail (2 - CT changed)
+
+Count = 92
+Nonce = 8feba0d720aa4a5e35abc99e82
+Adata = 00
+CT = 2ca3be419d5be5ed682f8954d2c20efd9e6d360814735daeefd4365c
+Result = Fail (1 - Adata changed)
+
+Count = 93
+Nonce = ed04c9ca8702aec8d0a58e09a0
+Adata = 00
+CT = 3d34bda62db39d6118d6fd5cd38f1a3820ca69ce584b94a2a4ccbef1
+Result = Fail (1 - Adata changed)
+
+Count = 94
+Nonce = 1501a243bf60b2cb40d5aa20ca
+Adata = 00
+CT = 377b2f1e7bd9e3d1077038e084f61950761361095f7eeebbf1a72afc
+Result = Pass (0)
+Payload = f5730a05fec31a11662e2e14e362ccc75c7c30cdfccbf994
+
+Count = 95
+Nonce = c6edaf35f0cb433500a8c3a613
+Adata = 00
+CT = 9cef6c889ff51666df9dd1dd2215c15f4b2078a29373c106be4f5f9a
+Result = Fail (2 - CT changed)
+
+Count = 96
+Nonce = d65e0e53f765f9d5e6795c0c5e
+Adata = 00
+CT = 6cab3060bf3b33b163b933c2ed0ba51406810b54d0edcf5c9d0ef4f7
+Result = Pass (0)
+Payload = 20e394c7cc90bdfa6186fc1ba6fff158dfc690e24ba4c9fb
+
+Count = 97
+Nonce = 2b0163418a341588db0f5786d8
+Adata = 00
+CT = f9543a659e9a8b7d75dd859df923817452735f5051726422c08a9e85
+Result = Fail (2 - CT changed)
+
+Count = 98
+Nonce = f16bba081bddda83546eabc9a5
+Adata = 00
+CT = 0d20bf6a9d02da72091d94cdb38743bfea2473d3ab62dcad75dd819a
+Result = Fail (2 - CT changed)
+
+Count = 99
+Nonce = ace99268a32b9c1b5ccd8b0d84
+Adata = 00
+CT = 8bca01e6ebd7ebcdfe52b88e314670ffeb35882fc05394b386e205f9
+Result = Fail (2 - CT changed)
+
+Count = 100
+Nonce = 24570517bbb0df1b3fbd32f57a
+Adata = 00
+CT = 7061c84e2e1d9d58013543ff82666055a1f055c1296c42c8f73a8bf0
+Result = Fail (1 - Adata changed)
+
+Count = 101
+Nonce = a6b2371acf8321864c08ddb4d8
+Adata = 00
+CT = c5aa500d1f7c09a590e9d15d6860c4433684e04dd6bc5c8f94f223f0
+Result = Pass (0)
+Payload = 1a43ca628026219c5a430c54021a5a3152ae517167399635
+
+Count = 102
+Nonce = f8e2d4e043f5fe7a72b6117811
+Adata = 00
+CT = e3efa7971e27ba1245ee9491ebdbb28ad9b24b325da5760417af8b14
+Result = Fail (1 - Adata changed)
+
+Count = 103
+Nonce = c2b60f14c894ec6178fe79919f
+Adata = 00
+CT = 852cca903d7fdf899807bd14642057534c8a0ccacb8c7b8fb4d35d44
+Result = Pass (0)
+Payload = 3e707d98f19972a63d913e6ea7533af2f41ff98aee2b2a36
+
+Count = 104
+Nonce = 4de4c909ac0cc5fc608baf45ac
+Adata = 00
+CT = e04fd4f5b60833021ed57c98de300bb68d0d892b2bf68e080bc044b1
+Result = Fail (1 - Adata changed)
+
+[Alen = 0, Plen = 24, Nlen = 13, Tlen = 16]
+
+Key = 1b0e8df63c57f05d9ac457575ea764524b8610ae5164e6215f426f5a7ae6ede4
+
+Count = 105
+Nonce = a544218dadd3c10583db49cf39
+Adata = 00
+CT = f0050ad16392021a3f40207bed3521fb1e9f808f49830c423a578d179902f912f9ea1afbce1120b3
+Result = Pass (0)
+Payload = 3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e
+
+Count = 106
+Nonce = 894dcaa61008eb8fb052c60d41
+Adata = 00
+CT = c408190d0fbf5034f83b24a8ed9657331a7ce141de4fae769084607b83bd06e6442eac8dacf583cc
+Result = Fail (2 - CT changed)
+
+Count = 107
+Nonce = 8feba0d720aa4a5e35abc99e82
+Adata = 00
+CT = 52b3d31d02d1b92b38cbae8c510204dde6bf9588e994296c9002a46cfb734290924a15e9c3d99924
+Result = Fail (1 - Adata changed)
+
+Count = 108
+Nonce = ed04c9ca8702aec8d0a58e09a0
+Adata = 00
+CT = f80190470212ce1e64bf4c64ca0133d90469abf87a8233c2b238e316c3f9adccce95e8c8b9c7e8d2
+Result = Fail (1 - Adata changed)
+
+Count = 109
+Nonce = 1501a243bf60b2cb40d5aa20ca
+Adata = 00
+CT = 254b847d4175bbb44a82b4e805514fa444c224710933f3ec8aaa3f0133234c0cd91609982adc034b
+Result = Pass (0)
+Payload = f5730a05fec31a11662e2e14e362ccc75c7c30cdfccbf994
+
+Count = 110
+Nonce = c6edaf35f0cb433500a8c3a613
+Adata = 00
+CT = 7a5c7bc02aa69efc5a159d653f3993399f69e20752c3b00633255731cd88345860da913bc696fdc1
+Result = Fail (2 - CT changed)
+
+Count = 111
+Nonce = d65e0e53f765f9d5e6795c0c5e
+Adata = 00
+CT = c3618c991b15de641d291419ff6957e8b9ae5046dd8c6f08fafb76adf12f36740347e3edae62bca4
+Result = Pass (0)
+Payload = 20e394c7cc90bdfa6186fc1ba6fff158dfc690e24ba4c9fb
+
+Count = 112
+Nonce = 2b0163418a341588db0f5786d8
+Adata = 00
+CT = 240927bfd671a92aef0311395ad55ae42233ecee53873da4066f55f23d4e55bcbbbf2312ea2d8071
+Result = Fail (2 - CT changed)
+
+Count = 113
+Nonce = f16bba081bddda83546eabc9a5
+Adata = 00
+CT = 4731a7e690c77cd47582ce54a1cec23d94c856b93a9fc767004753689cc84810b8414f1464c0c5b9
+Result = Fail (2 - CT changed)
+
+Count = 114
+Nonce = ace99268a32b9c1b5ccd8b0d84
+Adata = 00
+CT = f0ea12eaff20c3a50674aa1546aaae3bd5c9249108535b21504da83478ede24026ec91fb12769e4b
+Result = Fail (2 - CT changed)
+
+Count = 115
+Nonce = 24570517bbb0df1b3fbd32f57a
+Adata = 00
+CT = 5b164d9752ad6c497a7ab2d0bf8be68fea084ea5839b07b7c9fcf9b9fd5e99767a7b1679b57ea961
+Result = Fail (1 - Adata changed)
+
+Count = 116
+Nonce = a6b2371acf8321864c08ddb4d8
+Adata = 00
+CT = bd37326da18e5ac79a1a9512f724bb539530868576b79c67acb5a51d10a58d6584fbe73f1063c31b
+Result = Pass (0)
+Payload = 1a43ca628026219c5a430c54021a5a3152ae517167399635
+
+Count = 117
+Nonce = f8e2d4e043f5fe7a72b6117811
+Adata = 00
+CT = 0455b4dd1069281e10531c0dc180ced9a5ef5d3fe0007470ce54cd7623a80a176f29a01b3abb642e
+Result = Fail (1 - Adata changed)
+
+Count = 118
+Nonce = c2b60f14c894ec6178fe79919f
+Adata = 00
+CT = ecd337640022635ce1ed273756d02b7feeb2515614c1fadc95c66d3f411b478853886afd177d88c3
+Result = Pass (0)
+Payload = 3e707d98f19972a63d913e6ea7533af2f41ff98aee2b2a36
+
+Count = 119
+Nonce = 4de4c909ac0cc5fc608baf45ac
+Adata = 00
+CT = e25d7c9fb388596b13a13b885d5b24e31579a3494ad256da830b2b6317716b3975e2b101aebdd920
+Result = Fail (1 - Adata changed)
+
+[Alen = 32, Plen = 0, Nlen = 7, Tlen = 4]
+
+Key = 1b0e8df63c57f05d9ac457575ea764524b8610ae5164e6215f426f5a7ae6ede4
+
+Count = 120
+Nonce = a544218dadd3c1
+Adata = d3d5424e20fbec43ae495353ed830271515ab104f8860c988d15b6d36c038eab
+CT = 92d00fbe
+Result = Pass (0)
+Payload = 00
+
+Count = 121
+Nonce = 78c46e3249ca28
+Adata = 232e957c65ffa11988e830d4617d500f1c4a35c1221f396c41ab214f074ca2dc
+CT = 9143e5c4
+Result = Fail (2 - CT changed)
+
+Count = 122
+Nonce = c18d9e7971e2ae
+Adata = 0d40324aa758dbbb5391b5e6edb8a2310c94a4ae51d4fba8a7458d7cc8488baa
+CT = 54337466
+Result = Fail (1 - Adata changed)
+
+Count = 123
+Nonce = 162d061351d82d
+Adata = 106d1fb32d948b0d8884f178ad2332a599445fae0f6f71f9ebe53a60b2df9b8e
+CT = bf0bf84c
+Result = Fail (1 - Adata changed)
+
+Count = 124
+Nonce = 3fcb328bc96404
+Adata = 10b2ffed4f95af0f98ed4f77c677b5786ad01b31c095bbc6e1c99cf13977abba
+CT = 11250056
+Result = Pass (0)
+Payload = 00
+
+Count = 125
+Nonce = b3fd1eb1422277
+Adata = fa5398cf4cddbe4b45e9f5d7491cd9eefc5e494255961ba3f4b40d22b5f5fe76
+CT = 13de5339
+Result = Fail (2 - CT changed)
+
+Count = 126
+Nonce = c42ac63de6f12a
+Adata = 7ff8d06c5abcc50d3820de34b03089e6c5b202bcbaabca892825553d4d30020a
+CT = 4eed80fd
+Result = Pass (0)
+Payload = 00
+
+Count = 127
+Nonce = d4a7a672237e17
+Adata = d1cdad7fe886d07625a4334be6de4df0645d2a8b4008a8d35f04e6bcf87bfa56
+CT = 4bc2e450
+Result = Fail (2 - CT changed)
+
+Count = 128
+Nonce = b23255372455c6
+Adata = d2e2c3607c40e0a807b86c6ebbc502ab42bdb7f85ab26299cd963bbba3a3a8fa
+CT = b30e6bbd
+Result = Fail (2 - CT changed)
+
+Count = 129
+Nonce = 92272d40475fbb
+Adata = 2f3af695ee33a9ebe6a48ed1b00e337261857110bb104191a54fd13bd960d8bc
+CT = f7c11fe2
+Result = Fail (2 - CT changed)
+
+Count = 130
+Nonce = c4a756f6024a9d
+Adata = 2317b324b6420ada9ea7bf52b71c5faf2485528da5f56b42c517be6355cdb28b
+CT = 76673751
+Result = Fail (1 - Adata changed)
+
+Count = 131
+Nonce = 3a1701b185d33a
+Adata = e5d54df8ed9f89b98c5ebb1bc5d5279c2e182784ff4cd9c869ae152e29d7a2b2
+CT = 9a5382c3
+Result = Pass (0)
+Payload = 00
+
+Count = 132
+Nonce = e4db2e80dc3f63
+Adata = 7616bdf5737d01f936072b6576fa76556dfa072f7e2d7de16b9dc96ac8de409c
+CT = 9e632f56
+Result = Fail (1 - Adata changed)
+
+Count = 133
+Nonce = 4f490ce07e0150
+Adata = 3e12d09632c644c540077c6f90726d4167423a679322b2000a3f19cfcea02b33
+CT = e1842c46
+Result = Pass (0)
+Payload = 00
+
+Count = 134
+Nonce = b4aaf9ad1bde60
+Adata = 8c96c891456ddec29fe04299506723db2079a6667f96db5d198bf085acf2a4ef
+CT = 9f644671
+Result = Fail (1 - Adata changed)
+
+[Alen = 32, Plen = 0, Nlen = 7, Tlen = 16]
+
+Key = a4bc10b1a62c96d459fbaf3a5aa3face7313bb9e1253e696f96a7a8e36801088
+
+Count = 135
+Nonce = a544218dadd3c1
+Adata = d3d5424e20fbec43ae495353ed830271515ab104f8860c988d15b6d36c038eab
+CT = 93af11a08379eb37a16aa2837f09d69d
+Result = Pass (0)
+Payload = 00
+
+Count = 136
+Nonce = 78c46e3249ca28
+Adata = 232e957c65ffa11988e830d4617d500f1c4a35c1221f396c41ab214f074ca2dc
+CT = d19b0c14ec686a7961ca7c386d125a65
+Result = Fail (2 - CT changed)
+
+Count = 137
+Nonce = c18d9e7971e2ae
+Adata = 0d40324aa758dbbb5391b5e6edb8a2310c94a4ae51d4fba8a7458d7cc8488baa
+CT = 02ea916d60e2ceec6d9dc9b1185569b3
+Result = Fail (1 - Adata changed)
+
+Count = 138
+Nonce = 162d061351d82d
+Adata = 106d1fb32d948b0d8884f178ad2332a599445fae0f6f71f9ebe53a60b2df9b8e
+CT = fabd2d0c422b47d363ea9936ff4a311b
+Result = Fail (1 - Adata changed)
+
+Count = 139
+Nonce = 3fcb328bc96404
+Adata = 10b2ffed4f95af0f98ed4f77c677b5786ad01b31c095bbc6e1c99cf13977abba
+CT = b3884b69d117146cfa5529901753ddc0
+Result = Pass (0)
+Payload = 00
+
+Count = 140
+Nonce = b3fd1eb1422277
+Adata = fa5398cf4cddbe4b45e9f5d7491cd9eefc5e494255961ba3f4b40d22b5f5fe76
+CT = 7162026b6306e74fe32ece8433801bc2
+Result = Fail (2 - CT changed)
+
+Count = 141
+Nonce = c42ac63de6f12a
+Adata = 7ff8d06c5abcc50d3820de34b03089e6c5b202bcbaabca892825553d4d30020a
+CT = b53d93cbfd3d5cf3720cef5080bc7224
+Result = Pass (0)
+Payload = 00
+
+Count = 142
+Nonce = d4a7a672237e17
+Adata = d1cdad7fe886d07625a4334be6de4df0645d2a8b4008a8d35f04e6bcf87bfa56
+CT = c8bbecf69ecf8d10f0863bb4b7cbed51
+Result = Fail (2 - CT changed)
+
+Count = 143
+Nonce = b23255372455c6
+Adata = d2e2c3607c40e0a807b86c6ebbc502ab42bdb7f85ab26299cd963bbba3a3a8fa
+CT = 6037145cc23a175760ae4b573907c80c
+Result = Fail (2 - CT changed)
+
+Count = 144
+Nonce = 92272d40475fbb
+Adata = 2f3af695ee33a9ebe6a48ed1b00e337261857110bb104191a54fd13bd960d8bc
+CT = df7ea77425d631f652ffe096a8157f71
+Result = Fail (2 - CT changed)
+
+Count = 145
+Nonce = c4a756f6024a9d
+Adata = 2317b324b6420ada9ea7bf52b71c5faf2485528da5f56b42c517be6355cdb28b
+CT = 7182b25ef5b113c13fa8f6769e74f1e2
+Result = Fail (1 - Adata changed)
+
+Count = 146
+Nonce = 3a1701b185d33a
+Adata = e5d54df8ed9f89b98c5ebb1bc5d5279c2e182784ff4cd9c869ae152e29d7a2b2
+CT = 0a5d1bc02c5fe096a8b9d94d1267c49a
+Result = Pass (0)
+Payload = 00
+
+Count = 147
+Nonce = e4db2e80dc3f63
+Adata = 7616bdf5737d01f936072b6576fa76556dfa072f7e2d7de16b9dc96ac8de409c
+CT = 9eb6d9757ec7c56cc8c79461e0017486
+Result = Fail (1 - Adata changed)
+
+Count = 148
+Nonce = 4f490ce07e0150
+Adata = 3e12d09632c644c540077c6f90726d4167423a679322b2000a3f19cfcea02b33
+CT = 1eda43bf07f2bf003107f3a0ba3a4c18
+Result = Pass (0)
+Payload = 00
+
+Count = 149
+Nonce = b4aaf9ad1bde60
+Adata = 8c96c891456ddec29fe04299506723db2079a6667f96db5d198bf085acf2a4ef
+CT = 5287cc160c5dd3a0f9c1986aac2a621c
+Result = Fail (1 - Adata changed)
+
+[Alen = 32, Plen = 0, Nlen = 13, Tlen = 4]
+
+Key = a4bc10b1a62c96d459fbaf3a5aa3face7313bb9e1253e696f96a7a8e36801088
+
+Count = 150
+Nonce = a544218dadd3c10583db49cf39
+Adata = 3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e09a1005e024f6907
+CT = 866d4227
+Result = Pass (0)
+Payload = 00
+
+Count = 151
+Nonce = e8de970f6ee8e80ede933581b5
+Adata = 89f8b068d34f56bc49d839d8e47b347e6dae737b903b278632447e6c0485d26a
+CT = 94cb1127
+Result = Fail (2 - CT changed)
+
+Count = 152
+Nonce = 6de75d3c05e83755083399a5f7
+Adata = 504b08cf34cbe17acf631ef219ae01437ebb6a980ab2f00121bb3073701b6511
+CT = 82c2b67a
+Result = Fail (1 - Adata changed)
+
+Count = 153
+Nonce = 58d43b9f1581c590daab1a5c56
+Adata = 749f149ef306c70a5d006d9777adbbf7c0de453898c2978ef7c281535ea9b24c
+CT = 8c8283f9
+Result = Fail (1 - Adata changed)
+
+Count = 154
+Nonce = dfdcbdff329f7af70731d8e276
+Adata = 2ae56ddde2876d70b3b34eda8c2b1d096c836d5225d53ec460b724b6e16aa5a3
+CT = c4ac0952
+Result = Pass (0)
+Payload = 00
+
+Count = 155
+Nonce = 199ec321d1d24d5408076912d6
+Adata = a77526f3614cd974498a76d8b3cb7bacc623fdc9c85503289c462df888b199ed
+CT = c59aa931
+Result = Fail (2 - CT changed)
+
+Count = 156
+Nonce = 60f2490ba0c658848859fcbea8
+Adata = 3ad743283064929bf4fe4e0807f710f5e6a273e22614c728c3280a27b6c614a0
+CT = 27c3953d
+Result = Pass (0)
+Payload = 00
+
+Count = 157
+Nonce = 6f29ca274190400720bba27651
+Adata = c0850aaf141bd3f1b24f4d882590f58682b41f874748f29f8925b4914f444842
+CT = cb1ac8eb
+Result = Fail (2 - CT changed)
+
+Count = 158
+Nonce = f1dfb6fdb31cb423226f181c09
+Adata = ac6b08900fc1c9463e7dfdb60eee444c4989d7b200e675f3220ba1e14eed0ab4
+CT = 4dcc55cc
+Result = Fail (2 - CT changed)
+
+Count = 159
+Nonce = 0d45226c98eaa9bb445a3aa4f9
+Adata = b9cb3e1a5bcccb0b0599414c9822275b66fa0f913d51bdb0a2228cbb5aad0e0a
+CT = 727d8f5e
+Result = Fail (2 - CT changed)
+
+Count = 160
+Nonce = 39cdbb24bd273a3fe96f42ca9d
+Adata = ddfe6c22f4cdc3128050072005f5bd4ecdef1d836e891683f1ba921d33fafba7
+CT = 5aa56a54
+Result = Fail (1 - Adata changed)
+
+Count = 161
+Nonce = db113f38f0504615c5c9347c3d
+Adata = 3b71bc84e48c6dadf6ead14621d22468a3d4c9c103ac96970269730bcfce239b
+CT = c38fbdff
+Result = Pass (0)
+Payload = 00
+
+Count = 162
+Nonce = d16a20ef5f6587f1ee3cb7850b
+Adata = b1133e1cd369617a9f937e9a1eb86a0979ee30b5b7b0b6ff838d9e11301d6b72
+CT = 6be30c42
+Result = Fail (1 - Adata changed)
+
+Count = 163
+Nonce = d35f531f714694b5e49303a980
+Adata = 55b791ee495299916ff3c2327b4990952bebd0a2da9acfc553c6c996e354a4b5
+CT = d34e90bb
+Result = Pass (0)
+Payload = 00
+
+Count = 164
+Nonce = 220624db34a022b758473994a2
+Adata = 5b3b2ae87b0d6759f38a858423227f8687f35478a8f565409b741eadcac4d8c4
+CT = 4a5d14bc
+Result = Fail (1 - Adata changed)
+
+[Alen = 32, Plen = 0, Nlen = 13, Tlen = 16]
+
+Key = 8c5cf3457ff22228c39c051c4e05ed4093657eb303f859a9d4b0f8be0127d88a
+
+Count = 165
+Nonce = a544218dadd3c10583db49cf39
+Adata = 3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e09a1005e024f6907
+CT = 867b0d87cf6e0f718200a97b4f6d5ad5
+Result = Pass (0)
+Payload = 00
+
+Count = 166
+Nonce = e8de970f6ee8e80ede933581b5
+Adata = 89f8b068d34f56bc49d839d8e47b347e6dae737b903b278632447e6c0485d26a
+CT = 677a040d46ee3f2b7838273bdad14f16
+Result = Fail (2 - CT changed)
+
+Count = 167
+Nonce = 6de75d3c05e83755083399a5f7
+Adata = 504b08cf34cbe17acf631ef219ae01437ebb6a980ab2f00121bb3073701b6511
+CT = f650d46ade2cbabbc68ead6df1ea0c37
+Result = Fail (1 - Adata changed)
+
+Count = 168
+Nonce = 58d43b9f1581c590daab1a5c56
+Adata = 749f149ef306c70a5d006d9777adbbf7c0de453898c2978ef7c281535ea9b24c
+CT = 11b8fe8c139ee38f77fd8fa552cbff67
+Result = Fail (1 - Adata changed)
+
+Count = 169
+Nonce = dfdcbdff329f7af70731d8e276
+Adata = 2ae56ddde2876d70b3b34eda8c2b1d096c836d5225d53ec460b724b6e16aa5a3
+CT = ad879c64425e6c1ec4841bbb0f99aa8b
+Result = Pass (0)
+Payload = 00
+
+Count = 170
+Nonce = 199ec321d1d24d5408076912d6
+Adata = a77526f3614cd974498a76d8b3cb7bacc623fdc9c85503289c462df888b199ed
+CT = 3c64f8731930ae000162c10654531066
+Result = Fail (2 - CT changed)
+
+Count = 171
+Nonce = 60f2490ba0c658848859fcbea8
+Adata = 3ad743283064929bf4fe4e0807f710f5e6a273e22614c728c3280a27b6c614a0
+CT = e2751f153fc76c0dec5e0cf2d30c1a28
+Result = Pass (0)
+Payload = 00
+
+Count = 172
+Nonce = 6f29ca274190400720bba27651
+Adata = c0850aaf141bd3f1b24f4d882590f58682b41f874748f29f8925b4914f444842
+CT = 76127bf891141e73854752ed10c02bd0
+Result = Fail (2 - CT changed)
+
+Count = 173
+Nonce = f1dfb6fdb31cb423226f181c09
+Adata = ac6b08900fc1c9463e7dfdb60eee444c4989d7b200e675f3220ba1e14eed0ab4
+CT = 4bd833f9da0496e5f6a08a05d02df385
+Result = Fail (2 - CT changed)
+
+Count = 174
+Nonce = 0d45226c98eaa9bb445a3aa4f9
+Adata = b9cb3e1a5bcccb0b0599414c9822275b66fa0f913d51bdb0a2228cbb5aad0e0a
+CT = 05f166328a67a8c58b10a7348f3df612
+Result = Fail (2 - CT changed)
+
+Count = 175
+Nonce = 39cdbb24bd273a3fe96f42ca9d
+Adata = ddfe6c22f4cdc3128050072005f5bd4ecdef1d836e891683f1ba921d33fafba7
+CT = 42499bcd949a5163855a9794f11f917e
+Result = Fail (1 - Adata changed)
+
+Count = 176
+Nonce = db113f38f0504615c5c9347c3d
+Adata = 3b71bc84e48c6dadf6ead14621d22468a3d4c9c103ac96970269730bcfce239b
+CT = fc85464a81fe372c12c9e4f0f3bf9c37
+Result = Pass (0)
+Payload = 00
+
+Count = 177
+Nonce = d16a20ef5f6587f1ee3cb7850b
+Adata = b1133e1cd369617a9f937e9a1eb86a0979ee30b5b7b0b6ff838d9e11301d6b72
+CT = 8c7501f423647dee77668858c5e350bb
+Result = Fail (1 - Adata changed)
+
+Count = 178
+Nonce = d35f531f714694b5e49303a980
+Adata = 55b791ee495299916ff3c2327b4990952bebd0a2da9acfc553c6c996e354a4b5
+CT = b1c09b093788da19e33c5a6e82ed9627
+Result = Pass (0)
+Payload = 00
+
+Count = 179
+Nonce = 220624db34a022b758473994a2
+Adata = 5b3b2ae87b0d6759f38a858423227f8687f35478a8f565409b741eadcac4d8c4
+CT = d2231ee1455b0bc337c4f8173fb8647c
+Result = Fail (1 - Adata changed)
+
+[Alen = 32, Plen = 24, Nlen = 7, Tlen = 4]
+
+Key = 8c5cf3457ff22228c39c051c4e05ed4093657eb303f859a9d4b0f8be0127d88a
+
+Count = 180
+Nonce = a544218dadd3c1
+Adata = d3d5424e20fbec43ae495353ed830271515ab104f8860c988d15b6d36c038eab
+CT = c2fe12658139f5d0dd22cadf2e901695b579302a72fc56083ebc7720
+Result = Pass (0)
+Payload = 78c46e3249ca28e1ef0531d80fd37c124d9aecb7be6668e3
+
+Count = 181
+Nonce = 6ba004fd176791
+Adata = 5a053b2a1bb87e85d56527bfcdcd3ecafb991bb10e4c862bb0751c700a29f54b
+CT = 94748ba81229e53c38583a8564b23ebbafc6f6efdf4c2a81c44db2c9
+Result = Fail (2 - CT changed)
+
+Count = 182
+Nonce = 45c5c284836414
+Adata = 8f01a61eb17366d4e70942ab69b4f4bcf8ff6a97f5972ee5780a264c9dcf7d93
+CT = 1d670ccf3e9ba59186c48da2e5bd0ab21973eee2ea2985bf83a09067
+Result = Fail (1 - Adata changed)
+
+Count = 183
+Nonce = c69f7679c80546
+Adata = 5d6c04a5b422b46065a79a889e30ac8d1b53b65d230d4c88190903a24e1fe1ea
+CT = 2c8c80ff10fac1bf6c9c83533c1514ee032c0983730b0657392ae25d
+Result = Fail (1 - Adata changed)
+
+Count = 184
+Nonce = 57b940550a383b
+Adata = 33c2c3a57bf8393b126982c96d87daeacd5eadad1519073ad8c84cb9b760296f
+CT = e1b4ec4279bb62902c12521e6b874171695c5da46c647cc03b91ff03
+Result = Pass (0)
+Payload = 6fb5ce32a851676753ba3523edc5ca82af1843ffc08f1ef0
+
+Count = 185
+Nonce = 11edd12ea5873d
+Adata = e32e5384038379e2b7382ba337b6f7a72a1569e110ee89c4dd6aa6f7e69f5250
+CT = b5dda89fe879d6a665b99285b6d937fd5877ebef4de049fb64b837fb
+Result = Fail (2 - CT changed)
+
+Count = 186
+Nonce = f32222e9eec4bd
+Adata = 684595e36eda1db5f586941c9f34c9f8d477970d5ccc14632d1f0cec8190ae68
+CT = 224db21beb8cd0069007660e783c3f85706b014128368aab2a4e56a7
+Result = Pass (0)
+Payload = 2c29d4e2bb9294e90cb04ec697e663a1f7385a39f90c8ccf
+
+Count = 187
+Nonce = e0a0a7f262cb51
+Adata = 1d93b2856ad2bf3700440f9a281bd8947ba209e9ffd18e69921ed0678c957c6c
+CT = ba1ce3a799e1173178b6788723005566f9269d5828c85d28e960a769
+Result = Fail (2 - CT changed)
+
+Count = 188
+Nonce = 40316e7b38bdad
+Adata = 6e49acd9c26944740c778e74b1dbaa8d640c7e18e949a1661f8a77543db69e1f
+CT = 79d59e4bb251988c019c4eaaee2a2513f9cb0521334018fded14a5a5
+Result = Fail (2 - CT changed)
+
+Count = 189
+Nonce = 33008ef5baf263
+Adata = a726f31d9a22bfc0e7e4c3111b0d304e106ab04ed318f8bfe6ec9cb3a811285b
+CT = af4350795f24087aa05070d6d5f55ebb12d7ad3141066866d7d6c61d
+Result = Fail (2 - CT changed)
+
+Count = 190
+Nonce = b48a16fb9a065d
+Adata = be05e9c934c1dcba45223d47c6646a2d13c3b93265e354ae4970484b5101d809
+CT = 22d2da531be1f0d1da4bc21f984d29bf56bed2e92da6bf42d0605b84
+Result = Fail (1 - Adata changed)
+
+Count = 191
+Nonce = 14c9bd561c47c1
+Adata = 141ae365f8e65ab9196c4e8cd4e62189b304d67de38f2117e84ec0ec8f260ebd
+CT = 61b46c9024eed3989064a52df90349c18e14e4b552779d3f8f9d6814
+Result = Pass (0)
+Payload = c22524a1ea444be3412b0d773d4ea2ff0af4c1ad2383cba8
+
+Count = 192
+Nonce = 5fb871eac2e52a
+Adata = ff23906e9067da8999842318f2a867759ca2d171395c2ff31fa5a4e2ab349c45
+CT = 539799c2b22a33dd648fc4497d12f9455beaf932f1eaaff4d930f5ce
+Result = Fail (1 - Adata changed)
+
+Count = 193
+Nonce = 1ccec9923aa6e8
+Adata = 88a6d037009a1c1756f72bb4589d6d940bd514ed55386baefacc6ac3ca6f8795
+CT = 52f8205534447d722be2b9377f7395938cc88af081a11ccb0d83fa19
+Result = Pass (0)
+Payload = 518a7fb11c463bf23798982118f3cfe4d7ddde9184f37d4f
+
+Count = 194
+Nonce = 68a5351e4422c8
+Adata = 303c767468f48ac9f6e331bbad535b06aa00ab593327320799e17eff63afd3fe
+CT = d11c892ae155098f5e4b5fe60c7afd74fb2dbcc4db956556f243e273
+Result = Fail (1 - Adata changed)
+
+[Alen = 32, Plen = 24, Nlen = 7, Tlen = 16]
+
+Key = 705334e30f53dd2f92d190d2c1437c8772f940c55aa35e562214ed45bd458ffe
+
+Count = 195
+Nonce = a544218dadd3c1
+Adata = d3d5424e20fbec43ae495353ed830271515ab104f8860c988d15b6d36c038eab
+CT = 3341168eb8c48468c414347fb08f71d2086f7c2d1bd581ce1ac68bd42f5ec7fa7e068cc0ecd79c2a
+Result = Pass (0)
+Payload = 78c46e3249ca28e1ef0531d80fd37c124d9aecb7be6668e3
+
+Count = 196
+Nonce = 6ba004fd176791
+Adata = 5a053b2a1bb87e85d56527bfcdcd3ecafb991bb10e4c862bb0751c700a29f54b
+CT = d543acda712b898cbb27b8f598b2e4438ce587a836e2785147c3338a2400809e739b63ba8227d2f9
+Result = Fail (2 - CT changed)
+
+Count = 197
+Nonce = 45c5c284836414
+Adata = 8f01a61eb17366d4e70942ab69b4f4bcf8ff6a97f5972ee5780a264c9dcf7d93
+CT = 39a8af5c976b995ea8049e55b68bc65503592ab00915638646288ce9dd1c7088c752e35947fdca98
+Result = Fail (1 - Adata changed)
+
+Count = 198
+Nonce = c69f7679c80546
+Adata = 5d6c04a5b422b46065a79a889e30ac8d1b53b65d230d4c88190903a24e1fe1ea
+CT = 950fbf6445f6ffb68178f52f5079d0c6081a48ae1f267a0b7fd89caef9388fbb82361b8d53d9edc6
+Result = Fail (1 - Adata changed)
+
+Count = 199
+Nonce = 57b940550a383b
+Adata = 33c2c3a57bf8393b126982c96d87daeacd5eadad1519073ad8c84cb9b760296f
+CT = fbfed2c94f50ca10466da9903ef85833ad48ca00556e66d14d8b30df941f3536ffb42083ef0e1c30
+Result = Pass (0)
+Payload = 6fb5ce32a851676753ba3523edc5ca82af1843ffc08f1ef0
+
+Count = 200
+Nonce = 11edd12ea5873d
+Adata = e32e5384038379e2b7382ba337b6f7a72a1569e110ee89c4dd6aa6f7e69f5250
+CT = 2ebfeb7a843618b37025352df3538526517ed320adfb486c04cf3426e8f975125a7eed00e5f33b6c
+Result = Fail (2 - CT changed)
+
+Count = 201
+Nonce = f32222e9eec4bd
+Adata = 684595e36eda1db5f586941c9f34c9f8d477970d5ccc14632d1f0cec8190ae68
+CT = dae13e6967c8b1ee0dd2d5ba1dd1de69f22c95da39528f9ef78e9e5e9faa058112af57f4ac78db2c
+Result = Pass (0)
+Payload = 2c29d4e2bb9294e90cb04ec697e663a1f7385a39f90c8ccf
+
+Count = 202
+Nonce = e0a0a7f262cb51
+Adata = 1d93b2856ad2bf3700440f9a281bd8947ba209e9ffd18e69921ed0678c957c6c
+CT = e683040a0bcf04c1748e7746400d6ef0f7cd8e77a29517790c63959ce534a0f87fb42a9b000dec84
+Result = Fail (2 - CT changed)
+
+Count = 203
+Nonce = 40316e7b38bdad
+Adata = 6e49acd9c26944740c778e74b1dbaa8d640c7e18e949a1661f8a77543db69e1f
+CT = 829e50e8c09e727a58287e6eb7d38edeb8ab39db279c06397d1a2111dc21aec79ef73193b306d31f
+Result = Fail (2 - CT changed)
+
+Count = 204
+Nonce = 33008ef5baf263
+Adata = a726f31d9a22bfc0e7e4c3111b0d304e106ab04ed318f8bfe6ec9cb3a811285b
+CT = 873c91e76dca0062ae66325aefb84ece3e98928f8dbc5fee7c516d2d1a8318893923f398ca249401
+Result = Fail (2 - CT changed)
+
+Count = 205
+Nonce = b48a16fb9a065d
+Adata = be05e9c934c1dcba45223d47c6646a2d13c3b93265e354ae4970484b5101d809
+CT = 343f6c86f2b852ac388a096faec4472107a924aba56d0cb88055e777bb57eb49497cd2e233ee06fd
+Result = Fail (1 - Adata changed)
+
+Count = 206
+Nonce = 14c9bd561c47c1
+Adata = 141ae365f8e65ab9196c4e8cd4e62189b304d67de38f2117e84ec0ec8f260ebd
+CT = a654238fb8b05e293dba07f9d68d75a7f0fbf40fe20edaeba1586bf922412e73ce338e372615c3bc
+Result = Pass (0)
+Payload = c22524a1ea444be3412b0d773d4ea2ff0af4c1ad2383cba8
+
+Count = 207
+Nonce = 5fb871eac2e52a
+Adata = ff23906e9067da8999842318f2a867759ca2d171395c2ff31fa5a4e2ab349c45
+CT = 4846816923ed9f0254bdd0be01028f75061d3594ad3a45bd03538d108df6ecd6f39acfe076ba5fb8
+Result = Fail (1 - Adata changed)
+
+Count = 208
+Nonce = 1ccec9923aa6e8
+Adata = 88a6d037009a1c1756f72bb4589d6d940bd514ed55386baefacc6ac3ca6f8795
+CT = 765067ef768908d91ee4c3923943e0c7be70e2e06db99a4b3e3f51ee37fdcc5d81dd85d9e9d4f44e
+Result = Pass (0)
+Payload = 518a7fb11c463bf23798982118f3cfe4d7ddde9184f37d4f
+
+Count = 209
+Nonce = 68a5351e4422c8
+Adata = 303c767468f48ac9f6e331bbad535b06aa00ab593327320799e17eff63afd3fe
+CT = e58ea6c1522e5a3e93a85edd05ae80d6cf5c4dd6d604a8f8d8a906488f79ad5d2234d72458dcfcd4
+Result = Fail (1 - Adata changed)
+
+[Alen = 32, Plen = 24, Nlen = 13, Tlen = 4]
+
+Key = 705334e30f53dd2f92d190d2c1437c8772f940c55aa35e562214ed45bd458ffe
+
+Count = 210
+Nonce = a544218dadd3c10583db49cf39
+Adata = 3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e09a1005e024f6907
+CT = c0ea400b599561e7905b99262b4565d5c3dc49fad84d7c69ef891339
+Result = Pass (0)
+Payload = e8de970f6ee8e80ede933581b5bcf4d837e2b72baa8b00c3
+
+Count = 211
+Nonce = 8fa501c5dd9ac9b868144c9fa5
+Adata = 5bb40e3bb72b4509324a7edc852f72535f1f6283156e63f6959ffaf39dcde800
+CT = 60871e03ea0eb968536c99f926ea24ef43d41272ad9fb7f63d488623
+Result = Fail (2 - CT changed)
+
+Count = 212
+Nonce = 9bc0d1502a47e46350fe8667ca
+Adata = 07203674260208d5bd4d39506836f7e76ffc58e938799f21aff7bb4dea4410d2
+CT = 81d7859dcbe51dcc94fe2591cd3b0540003d49a8c4dccbf4527e5ed0
+Result = Fail (1 - Adata changed)
+
+Count = 213
+Nonce = 611cb4c66e88f6acf96fea1919
+Adata = 327ee3657e49d4d988362fabae303ccea6638e5cb45993d9d56269bc3d3af32b
+CT = bef380ad725b65fb5fceeabf09c665bc35089f434ec831494d20d5fa
+Result = Fail (1 - Adata changed)
+
+Count = 214
+Nonce = 0dd613c0fe28e913c0edbb8404
+Adata = 2ad306575b577c2f61da7212ab63e3db3941f1f751f2356c7443531a90b9d141
+CT = fabe11c9629e598228f5209f3dbcc641fe4b1a22cadb0821d2898c3b
+Result = Pass (0)
+Payload = 9522fb1f1aa58493cba682d788186d902cfc93e80fd6b998
+
+Count = 215
+Nonce = 68806dfe720d0a9a84697de5f2
+Adata = c6b0e4dfd723d7637510f887b7852f60ecdf72e0d33396560fed6534d5b7f015
+CT = b7eb87f84951640de731d4093f1a4ed5f831138a27465d3941e92090
+Result = Fail (2 - CT changed)
+
+Count = 216
+Nonce = 3e0fe3427eeda80f02dda4fed5
+Adata = ae0d1c9c834d60ff0ecfb3c0d78c72ddb789e58adfc166c81d5fc6395b31ec33
+CT = d88f8fcd772125212ce09c2a6e5b5693dd35073f992004f0d18fc889
+Result = Pass (0)
+Payload = 38333ce78110bf53a2c2abc7db99e133ad218ca43ff7a7bc
+
+Count = 217
+Nonce = 7c0c76d9f9316ff6c98758b464
+Adata = 31a0338c3839931fa1dd5131cb796c4c6cfde9fb336d8a80ac35dec463be7a94
+CT = d2d7d52b11304fc1d15b8c20e296ba7c63d99f4ce86cc8ae0f39ecea
+Result = Fail (2 - CT changed)
+
+Count = 218
+Nonce = 07c728135bdfede0e0c8036b17
+Adata = 25a152850b4b80b19d8f0b504b2a8a241824b3a1fca8d85c8713b2c0c84b5e02
+CT = ae1d9f82efb464d5dc2018cffa309634c09b34d1122c4bd994b1d516
+Result = Fail (2 - CT changed)
+
+Count = 219
+Nonce = 710c96d7a6f09de83f0507f28a
+Adata = 2d64acfdbfc582cd9a933790eb1b739fb02e53f511255e49f421bb7acc98a130
+CT = 477c985d92ad1b69d22315235a29e3d3a5991487cbdc8d11d394d047
+Result = Fail (2 - CT changed)
+
+Count = 220
+Nonce = 977bbcdeb6a7d9dcf8664bc2d8
+Adata = 135786125258a49475338ac1961d2718433b9e84cf64f63ca52913e8dd12e505
+CT = d1c085c75d808dc6db493b8a0b4d884e0700d2844a1b4b46bd3d22eb
+Result = Fail (1 - Adata changed)
+
+Count = 221
+Nonce = 60122cbd219e5cf17415e8bc09
+Adata = 895a45ddbe0c80793eccbf820de13a233b6aa7045cfd5313388e7184c392b216
+CT = 76bdd9a7b34bf14ae121a87fdfa144f71b848744af6a2f0b1c0d067c
+Result = Pass (0)
+Payload = 794e734966e6d0001699aec3f8ab8f194de7653d3091b1b9
+
+Count = 222
+Nonce = 83a07f2e685959cb50a1bd2bce
+Adata = 02afe300ec0cf0acb59108b2f70e069300294e34f40bb032cb59907599664408
+CT = 413e2e8df9d65b4e5d3b63a738258aaee643f364be9a01b974192744
+Result = Fail (1 - Adata changed)
+
+Count = 223
+Nonce = 3542fbe0f59a6d5f3abf619b7d
+Adata = dd4531f158a2fa3bc8a339f770595048f4a42bc1b03f2e824efc6ba4985119d8
+CT = 617d8036e2039d516709062379e0550cbd71ebb90fea967c79018ad5
+Result = Pass (0)
+Payload = c5b3d71312ea14f2f8fae5bd1a453192b6604a45db75c5ed
+
+Count = 224
+Nonce = 48f2d4c0b17072e0a9c300d90b
+Adata = c56175e2cfe0d37454d989afcc36686fb34c015439601567506a4d0003182be7
+CT = 40e609c739e409750a6c41d9c6ea64ce36f70711b4ca3e365c916f91
+Result = Fail (1 - Adata changed)
+
+[Alen = 32, Plen = 24, Nlen = 13, Tlen = 16]
+
+Key = 314a202f836f9f257e22d8c11757832ae5131d357a72df88f3eff0ffcee0da4e
+
+Count = 225
+Nonce = a544218dadd3c10583db49cf39
+Adata = 3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e09a1005e024f6907
+CT = 8d34cdca37ce77be68f65baf3382e31efa693e63f914a781367f30f2eaad8c063ca50795acd90203
+Result = Pass (0)
+Payload = e8de970f6ee8e80ede933581b5bcf4d837e2b72baa8b00c3
+
+Count = 226
+Nonce = 8fa501c5dd9ac9b868144c9fa5
+Adata = 5bb40e3bb72b4509324a7edc852f72535f1f6283156e63f6959ffaf39dcde800
+CT = 516c0095cc3d85fd55e48da17c592e0c7014b9daafb82bdc4b41096dfdbe9cc1ab610f8f3e038d16
+Result = Fail (2 - CT changed)
+
+Count = 227
+Nonce = 9bc0d1502a47e46350fe8667ca
+Adata = 07203674260208d5bd4d39506836f7e76ffc58e938799f21aff7bb4dea4410d2
+CT = 0293eae9f8d8bd7ad45357f733fc7b5d990d894783e18501d81ec96df41b8fa8262ed2db880b5e85
+Result = Fail (1 - Adata changed)
+
+Count = 228
+Nonce = 611cb4c66e88f6acf96fea1919
+Adata = 327ee3657e49d4d988362fabae303ccea6638e5cb45993d9d56269bc3d3af32b
+CT = 256bad8295e67d8d450f5ecc8276920ec23b1156c57be7c96ee80f60f72db2cbf25b2f8c6af8749c
+Result = Fail (1 - Adata changed)
+
+Count = 229
+Nonce = 0dd613c0fe28e913c0edbb8404
+Adata = 2ad306575b577c2f61da7212ab63e3db3941f1f751f2356c7443531a90b9d141
+CT = 6df09613ea986c2d91a57a45a0942cbf20e0dfca12fbda8c945ee6db24aea5f5098952f1203339ce
+Result = Pass (0)
+Payload = 9522fb1f1aa58493cba682d788186d902cfc93e80fd6b998
+
+Count = 230
+Nonce = 68806dfe720d0a9a84697de5f2
+Adata = c6b0e4dfd723d7637510f887b7852f60ecdf72e0d33396560fed6534d5b7f015
+CT = c5b64577d3c34e50f7da5072db5bda1d1d2c6db1a4f1183e2cc4c90ac3f798957cb09a05868a8ad5
+Result = Fail (2 - CT changed)
+
+Count = 231
+Nonce = 3e0fe3427eeda80f02dda4fed5
+Adata = ae0d1c9c834d60ff0ecfb3c0d78c72ddb789e58adfc166c81d5fc6395b31ec33
+CT = 2bfe51f1f43b982d47f76ea8206ddbf585d6f30cec0d4ef16b1556631d3b52bf24154afec1448ef6
+Result = Pass (0)
+Payload = 38333ce78110bf53a2c2abc7db99e133ad218ca43ff7a7bc
+
+Count = 232
+Nonce = 7c0c76d9f9316ff6c98758b464
+Adata = 31a0338c3839931fa1dd5131cb796c4c6cfde9fb336d8a80ac35dec463be7a94
+CT = 1622ae109073f44a4596722d9943fea774dfc2a1f939fc0914f42ec81e3af71c9a5de7e0ac16ca69
+Result = Fail (2 - CT changed)
+
+Count = 233
+Nonce = 07c728135bdfede0e0c8036b17
+Adata = 25a152850b4b80b19d8f0b504b2a8a241824b3a1fca8d85c8713b2c0c84b5e02
+CT = 4c0b361a766d366d983c41e793d75635e17f6eab2eadcf9743d67d90850c4c76a43df1f95170b29b
+Result = Fail (2 - CT changed)
+
+Count = 234
+Nonce = 710c96d7a6f09de83f0507f28a
+Adata = 2d64acfdbfc582cd9a933790eb1b739fb02e53f511255e49f421bb7acc98a130
+CT = 5b02347f30213df7f1506d7dca41b838c92aea0f190c5dba7bd5d5c8c098299394333b34fae9a110
+Result = Fail (2 - CT changed)
+
+Count = 235
+Nonce = 977bbcdeb6a7d9dcf8664bc2d8
+Adata = 135786125258a49475338ac1961d2718433b9e84cf64f63ca52913e8dd12e505
+CT = c77283ca15484d82469ce7249d1fb8e5f4c3bc8245fb4d97e26149d4a9711be81b4f69aa9fabd7f6
+Result = Fail (1 - Adata changed)
+
+Count = 236
+Nonce = 60122cbd219e5cf17415e8bc09
+Adata = 895a45ddbe0c80793eccbf820de13a233b6aa7045cfd5313388e7184c392b216
+CT = bf0d219bb50fcc1d51f654bb0fd8b44efa25aef39e2f11afe47d00f2eebb544e6ba7559ac2f34edb
+Result = Pass (0)
+Payload = 794e734966e6d0001699aec3f8ab8f194de7653d3091b1b9
+
+Count = 237
+Nonce = 83a07f2e685959cb50a1bd2bce
+Adata = 02afe300ec0cf0acb59108b2f70e069300294e34f40bb032cb59907599664408
+CT = 1609f8de59da4f50ce034977d132d4f9881a9b85ffa5bb886fa3fddc87690a359fe55f8fa12ba749
+Result = Fail (1 - Adata changed)
+
+Count = 238
+Nonce = 3542fbe0f59a6d5f3abf619b7d
+Adata = dd4531f158a2fa3bc8a339f770595048f4a42bc1b03f2e824efc6ba4985119d8
+CT = 39c2e8f6edfe663b90963b98eb79e2d4f7f28a5053ae8881567a6b4426f1667136bed4a5e32a2bc1
+Result = Pass (0)
+Payload = c5b3d71312ea14f2f8fae5bd1a453192b6604a45db75c5ed
+
+Count = 239
+Nonce = 48f2d4c0b17072e0a9c300d90b
+Adata = c56175e2cfe0d37454d989afcc36686fb34c015439601567506a4d0003182be7
+CT = 27c575be0b99af9b106f53f471c31cac4d54ea0bcb602a33fb67bb6092cd579f722ae9b680da083d
+Result = Fail (1 - Adata changed)
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/Readme.txt b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/Readme.txt
new file mode 100644
index 0000000000..88bdc95fd0
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/Readme.txt
@@ -0,0 +1,9 @@
+There are two sets of CCM example files:
+
+1. The response (.rsp) files contain properly formatted CAVS response files.
+
+2. The three DVPT{128/192/256}.txt files contain the same values as the
+ DVPT{128/192/256}.rsp files but have additional information. For the cases
+ that fail, the reason for failure is in parentheses following the result:
+ e.g., Result = Fail (2 - CT changed)
+ This additional information is not in properly formatted response files.
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VADT128.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VADT128.rsp
new file mode 100644
index 0000000000..a4fe9130a0
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VADT128.rsp
@@ -0,0 +1,1823 @@
+# CAVS 11.0
+# "CCM-VADT" information
+# AES Keylen: 128
+# Generated on Tue Mar 15 08:09:24 2011
+
+Plen = 24
+Nlen = 13
+Tlen = 16
+
+[Alen = 0]
+
+Key = d24a3d3dde8c84830280cb87abad0bb3
+Nonce = f1100035bb24a8d26004e0e24b
+
+Count = 0
+Adata = 00
+Payload = 7c86135ed9c2a515aaae0e9a208133897269220f30870006
+CT = 1faeb0ee2ca2cd52f0aa3966578344f24e69b742c4ab37ab1123301219c70599b7c373ad4b3ad67b
+
+Count = 1
+Adata = 00
+Payload = 48df73208cdc63d716752df7794807b1b2a80794a2433455
+CT = 2bf7d09079bc0b904c711a0b0e4a70ca8ea892d9566f03f8b77a140819f39ef045103e785e1df8c2
+
+Count = 2
+Adata = 00
+Payload = b99de8168e8c13ea4aef66bdb93133dff5d57e9837ff6ccb
+CT = dab54ba67bec7bad10eb5141ce3344a4c9d5ebd5c3d35b664b01098842a618390619b86e00850b2e
+
+Count = 3
+Adata = 00
+Payload = 09fc21ac4a1f43de29621cacf3ad84e055c6b220721af7ce
+CT = 6ad4821cbf7f2b9973662b5084aff39b69c6276d8636c0638bd518724ab84fb814fe7b5570769f7f
+
+Count = 4
+Adata = 00
+Payload = cb43320d7488dfd6eed9efd88f440ea3f6f77a0df09d0727
+CT = a86b91bd81e8b791b4ddd824f84679d8caf7ef4004b1308a7229cbcecef221570cee8345b38cd6ec
+
+Count = 5
+Adata = 00
+Payload = a350ed58c04473e113b9088b1fb9dad92807f6b63b0d690c
+CT = c0784ee835241ba649bd3f7768bbada2140763fbcf215ea1fee47fec27d7764e5e2819c850088bac
+
+Count = 6
+Adata = 00
+Payload = 0709e691faf41383fab5d1848a8eee77101d1c99e526a264
+CT = 642145210f947bc4a0b1e678fd8c990c2c1d89d4110a95c954d610bc1ab4bc9a8a28c7306f7c539e
+
+Count = 7
+Adata = 00
+Payload = e7b913c2f0630562eb1c16b3b1ed84090c011a15c09e5471
+CT = 8491b07205036d25b118214fc6eff37230018f5834b263dc2e31657ecc51f5ec8590482fc053230d
+
+Count = 8
+Adata = 00
+Payload = 6b909697074900d41ce8c7d559b229af11fb3cec334784d4
+CT = 08b83527f229689346ecf0292eb05ed42dfba9a1c76bb379d500827f2081b00397102f90fc9ccd88
+
+Count = 9
+Adata = 00
+Payload = 495ff03335bcb39a317b9ea3f8bb6306fa771f3c55adebce
+CT = 2a775383c0dcdbdd6b7fa95f8fb9147dc6778a71a181dc63e2e7997803029476598c0e8d4fc63857
+
+[Alen = 1]
+
+Key = 08b0da255d2083808a1b4d367090bacc
+Nonce = 777828b13679a9e2ca89568233
+
+Count = 10
+Adata = dd
+Payload = 1b156d7e2bf7c9a25ad91cff7b0b02161cb78ff9162286b0
+CT = e8b80af4960d5417c15726406e345c5c46831192b03432eed16b6282283e16602331bcca9d51ce76
+
+Count = 11
+Adata = c5
+Payload = 032fee9dbffccc751e6a1ee6d07bb218b3a7ec6bf5740ead
+CT = f0828917020651c085e42459c544ec52e99372005362baf308ebeed45f67ef8733737c9c6f82daad
+
+Count = 12
+Adata = 68
+Payload = 9c4cd65b92070bc382fd18146611defb4204acddfdf6b276
+CT = 6fe1b1d12ffd9676197322ab732e80b1183032b65be00628f9b477e3a23bfdfdb619c7bc531fbcce
+
+Count = 13
+Adata = be
+Payload = 2ff93ef2fc5fe2c297ace05f3f7585aed75ef90ade3acf89
+CT = dc54597841a57f770c22dae02a4adbe48d6a6761782c7bd7aa82130f5a86c0cd0433585e5c208cf7
+
+Count = 14
+Adata = 7a
+Payload = 62766e9acd41285eeed9b4007340dbb611699624274ad117
+CT = 91db091070bbb5eb75578ebf667f85fc4b5d084f815c65499d60012a2f25463e036ceecea57b3c97
+
+Count = 15
+Adata = 13
+Payload = ea689c268a04912d0527b16d9d9406df38302fb11cb64a99
+CT = 19c5fbac37fe0c989ea98bd288ab58956204b1dabaa0fec7e337897c90eb260729a729aed1c8a244
+
+Count = 16
+Adata = e5
+Payload = f31e35953beb211efcce487ba8c0cd1a8446343d5851b9fd
+CT = 00b3521f8611bcab674072c4bdff9350de72aa56fe470da373dc2911c75b37cd995481d42b04524a
+
+Count = 17
+Adata = e3
+Payload = c4ac3c645387584c2a95b1f16b8317730592924dd831a388
+CT = 37015beeee7dc5f9b11b8b4e7ebc49395fa60c267e2717d684f76ecf3dc5f3307ce982f185321248
+
+Count = 18
+Adata = d5
+Payload = 81af394c2ea3a85e1ea954596e3772f01635d007794c0b19
+CT = 72025ec6935935eb85276ee67b082cba4c014e6cdf5abf472c38d0fe4e4eba054c1420c39a3dcc61
+
+Count = 19
+Adata = ed
+Payload = e013a2edd5b86bab8df5c9940d0a0c864478c1ad42668304
+CT = 13bec5676842f61e167bf32b183552cc1e4c5fc6e470375a7cfa6c9945f5aee3c799eee37b0605db
+
+[Alen = 2]
+
+Key = 1538cc03b60880bf3e7d388e29f27739
+Nonce = 9e734de325026b5d7128193973
+
+Count = 20
+Adata = c93c
+Payload = e7b819a853ffe79baaa72097ff0d04f02640ae62bcfd3da5
+CT = 1d8f42f9730424fa27240bd6277f4882604f440324b11b003ca01d874439b4e1f79a26d8c6dc433a
+
+Count = 21
+Adata = 4cf9
+Payload = dc6cf325ed6d968efba9f57e48a58f4578cc3540fe121ba2
+CT = 265ba874cd9655ef762ade3f90d7c3373ec3df21665e3d07b40653cd23afc7cc7a31fa13ba8f4e49
+
+Count = 22
+Adata = b469
+Payload = 22ab6a0daf953165dda864cceeeb782e275c0b072aedd284
+CT = d89c315c8f6ef204502b4f8d3699345c6153e166b2a1f421c8c10aaf90b1116be216f912c82ca96a
+
+Count = 23
+Adata = cf6b
+Payload = a35f62a431fee63468dc02fdf7bef78d3a5937de56151939
+CT = 596839f511052555e55f29bc2fccbbff7c56ddbfce593f9c2f568ef41324189fb3644edcd76dc19c
+
+Count = 24
+Adata = af7c
+Payload = 548840cb0400824af809fb68447500b77e977128200d3b81
+CT = aebf1b9a24fb412b758ad0299c074cc538989b49b8411d242548c244a875d3681d715db3da19962f
+
+Count = 25
+Adata = 61dc
+Payload = 440b6095c77495e73fff54c785b7ceb5eb358731c213ffcd
+CT = be3c3bc4e78f5686b27c7f865dc582c7ad3a6d505a5fd968b599bc8927ad8d43067807f4b858f854
+
+Count = 26
+Adata = b97e
+Payload = 50c59ca54eb64575b82b13c6dac96488af369e9f5f86cdf2
+CT = aaf2c7f46e4d861435a8388702bb28fae93974fec7caeb577454774ee78f76e555cf743df340381e
+
+Count = 27
+Adata = 57ab
+Payload = 21b8eb1f0bda26ca36167ce7bc2e796818bf11fc8c192885
+CT = db8fb04e2b21e5abbb9557a6645c351a5eb0fb9d14550e20e0a22a5ee031978271c7dd2a0d4e7018
+
+Count = 28
+Adata = 5f9c
+Payload = b4d84fb1e81e18c89391a7a59fc05fedaf160e0d0d027a7c
+CT = 4eef14e0c8e5dba91e128ce447b2139fe919e46c954e5cd99a242ebae5c6da57ee38e5c227c46b32
+
+Count = 29
+Adata = e0c4
+Payload = 54dc5a0e1b67577cda4e7dbd48b769c120c1d13dd567cfad
+CT = aeeb015f3b9c941d57cd56fc90c525b366ce3b5c4d2be908a5f8a92f4201c4658289307167cee810
+
+[Alen = 3]
+
+Key = f149e41d848f59276cfddd743bafa9a9
+Nonce = 14b756d66fc51134e203d1c6f9
+
+Count = 30
+Adata = f5827e
+Payload = 9759e6f21f5a588010f57e6d6eae178d8b20ab59cda66f42
+CT = f634bf00f1f9f1f93f41049d7f3797b05e805f0b14850f4e78e2a23411147a6187da6818506232ee
+
+Count = 31
+Adata = e9699b
+Payload = 1555bc87d6c688fd221a2c75cd1e4dd1c1693207ac421d24
+CT = 7438e575386521840dae5685dc87cdec14c9c65575617d28f10835db9897b7528e3204fe3a81424f
+
+Count = 32
+Adata = 972896
+Payload = b72b2a080d92f3f3bb7d96222982de82a28c9eebaddba247
+CT = d64673fae3315a8a94c9ecd2381b5ebf772c6ab974f8c24b3efa05ba4a73ec2234461d459f54acd2
+
+Count = 33
+Adata = 3053f3
+Payload = b5417ed6933ffe2b57ea601d77e97eb12fa1fb8fdc06c86f
+CT = d42c27247d9c5752785e1aed6670fe8cfa010fdd0525a863b557537c6525e827750917a1ed49602f
+
+Count = 34
+Adata = 24db75
+Payload = 4e7f42666035a00e62783283c54b027603917685d27326bc
+CT = 2f121b948e9609774dcc4873d4d2824bd63182d70b5046b0dfd06b037e9094f120eb3d8649d48918
+
+Count = 35
+Adata = ff27a4
+Payload = 7bf180699c294421ad9565cacc27227a4b3a7cf9637290c6
+CT = 1a9cd99b728aed5882211f3addbea2479e9a88abba51f0cabfa8cfabbd79b3e3210482e6f3822fee
+
+Count = 36
+Adata = 77ec24
+Payload = 3d47071c13f994cb42fb2887e5c6e53a542be7ddad9779e0
+CT = 5c2a5eeefd5a3db26d4f5277f45f6507818b138f74b419ec3b9575e347051e98d0c8646ad46318e6
+
+Count = 37
+Adata = 6d7748
+Payload = 317d5da0a2ec12c3b96c83dd61cc955242a9c1c640e2b92f
+CT = 501004524c4fbbba96d8f92d7055156f9709359499c1d92378e7af65eb0388ae7a52f58f6ba32109
+
+Count = 38
+Adata = 029674
+Payload = c9bb21306ee1b4a6c4fa5443af2e181716993cbb374e177c
+CT = a8d678c280421ddfeb4e2eb3beb7982ac339c8e9ee6d77708019fa97ff70d4d21c0bd83caa434b3a
+
+Count = 39
+Adata = 60dfe8
+Payload = 44eb7edd6bee501ad97873aa7ecbf7ed8b613760d7c95e15
+CT = 2586272f854df963f6cc095a6f5277d05ec1c3320eea3e191814ed48a21d97ea02e86d7e6e8834cb
+
+[Alen = 4]
+
+Key = 9a57a22c7f26feff8ca6cceff214e4c2
+Nonce = 88f30fd2b04fb8ddbce8fc26e6
+
+Count = 40
+Adata = a95bdff6
+Payload = 035c516776c706a7dd5f181fa6aa891b04dd423042ea0667
+CT = b92f7ec2ebecebdbd2977b3874e61bf496a382153b2529fc9b6443a35f329b2068916fb6ab8227eb
+
+Count = 41
+Adata = d2672cbb
+Payload = 3ba306bcec94615c347f990b62841a16df7b321f113f1714
+CT = 81d0291971bf8c203bb7fa2cb0c888f94d05f23a68f0388f19e2aa492ce9ddfb6de0ab7a447f5351
+
+Count = 42
+Adata = 737f4d00
+Payload = 68313a29ace3efe521c3ca1e5bac8e98d6b4434c80a7dc74
+CT = d242158c31c802992e0ba93989e01c7744ca8369f968f3ef2bf683b1209f104e82ba39f7c62cd666
+
+Count = 43
+Adata = 3610b1ae
+Payload = 963bfe556138317bebe3936b18a2c1dd100dc73be6fde556
+CT = 2c48d1f0fc13dc07e42bf04ccaee53328273071e9f32cacd4fc7d5cac043f182edbe5c2658f73092
+
+Count = 44
+Adata = f1aa7f72
+Payload = 52d5c53ee4f23cb050a95db54112b44033c34ac31de96be8
+CT = e8a6ea9b79d9d1cc5f613e92935e26afa1bd8ae664264473b8234f3fbaca3dc2c497418219151b05
+
+Count = 45
+Adata = 6b1013aa
+Payload = a302aebc0f8fd61badc8371991beacf5933de46effacb8ce
+CT = 1971811992a43b67a200543e43f23e1a0143244b866397558fa5f9539e0500f139016e4a4337d86b
+
+Count = 46
+Adata = 33028129
+Payload = f7d653c23254875625b20e1ef60ae92847046d84bb4ce857
+CT = 4da57c67af7f6a2a2a7a6d3924467bc7d57aada1c283c7ccfa2379fde155e64b5b84e336056445c3
+
+Count = 47
+Adata = 2cab4a09
+Payload = 872a3f7230e626abff519e5aeecc93897249405daeaffc98
+CT = 3d5910d7adcdcbd7f099fd7d3c800166e0378078d760d30358208335cb81e4fb10923fca4ddb9ff9
+
+Count = 48
+Adata = 73142ba7
+Payload = 766f94e7d9b1ce74bbaf2c99d215350f060122767fc1953f
+CT = cc1cbb42449a2308b4674fbe0059a7e0947fe253060ebaa42d6ecfb49ac8983415503efef1e21950
+
+Count = 49
+Adata = bc9f967e
+Payload = 5f089ed9267363bc23c6c7b8f73208a36f61fa8ea8084ff7
+CT = e57bb17cbb588ec02c0ea49f257e9a4cfd1f3aabd1c7606c1978a62d15430fc20b87940292b49641
+
+[Alen = 5]
+
+Key = 54caf96ef6d448734700aadab50faf7a
+Nonce = a3803e752ae849c910d8da36af
+
+Count = 50
+Adata = 5f476348dd
+Payload = c69f7c5a50f3e72123371bbfd6bdf532b99ef78500508dfe
+CT = 20c43ad83610880249f1632dd418ec9a5ed333b50e996d1a4e5a32fbe7961b832b722bc07a18595b
+
+Count = 51
+Adata = 07db8aada5
+Payload = 9cf8b638f2b295b85cf782fabab11153dc091b4afcd761a9
+CT = 7aa3f0ba9451fa9b3631fa68b81408fb3b44df7af21e814d401a2222443696021b5faa520129b563
+
+Count = 52
+Adata = 31ef6561ff
+Payload = 62b8263dc015ef873cd16272e4da89799b910f2b04204420
+CT = 84e360bfa6f680a456171ae0e67f90d17cdccb1b0ae9a4c4f842681d2e90da5718234ed893197662
+
+Count = 53
+Adata = e97dfcbafb
+Payload = 810bed3a2bc0f9d75389155b7a39d9d014c08646814f9718
+CT = 6750abb84d2396f4394f6dc9789cc078f38d42768f8677fc33a08eb30ee154f71279682ab02eff27
+
+Count = 54
+Adata = 4981c51fcc
+Payload = 063d23fc3ec344c1ba3486802e01e55617455d5cfbfb5279
+CT = e066657e58202be2d0f2fe122ca4fcfef008996cf532b29d8d3071c79f0cf86fe4148cb5e8ace0ce
+
+Count = 55
+Adata = c8437dba76
+Payload = 41db5b245ea0fab985b93e7fc0a00cd3cca5bdbb642b7ebf
+CT = a7801da63843959aef7f46edc205157b2be8798b6ae29e5b842700619dc1599603f3f3f6cfdf5e0b
+
+Count = 56
+Adata = 6f65a24344
+Payload = b0e36734b2ba871d59df0b029c7f32af68e003a689ac4911
+CT = 56b821b6d459e83e331973909eda2b078fadc7968765a9f539a0cd8d8bbf211b907f34411f868c79
+
+Count = 57
+Adata = cd62d6d203
+Payload = 747e53e627eabde0cd77d78d1bd720bea518f8a2f76e57a2
+CT = 922515644109d2c3a7b1af1f1972391642553c92f9a7b746c4a90e5fc11266bab77eea1d24fbdbb9
+
+Count = 58
+Adata = 9663b3c8e6
+Payload = c70c92ec4c518802662fa4c41a6a33a22599f79f8f7264b3
+CT = 2157d46e2ab2e7210ce9dc5618cf2a0ac2d433af81bb8457b3c1246f7dd6462ce757db82db45f36e
+
+Count = 59
+Adata = 35c4720d3c
+Payload = a26835605b66fc08abdbb5dc77e39783d60b8e8f2314e95f
+CT = 443373e23d85932bc11dcd4e75468e2b31464abf2ddd09bbd472c06a5f4c04f97d06ec401d3e7fd9
+
+[Alen = 6]
+
+Key = cc0c084d7de011e2f031616a302e7a31
+Nonce = f0b4522847f6f8336fe534a4e7
+
+Count = 60
+Adata = da853a27aee2
+Payload = 15b369889699b6de1fa3ee73e5fe19814e46f129074c965b
+CT = f39755d160a64611368a8eccf6fcbc45ef7f1f56240eb19a2e3ca4ec3c776ab58843f617d605fd72
+
+Count = 61
+Adata = d4ed4584678e
+Payload = a18c0460b56a5bcd5bf6842cec6ed44d90b2bfa968a6a7e7
+CT = 47a838394355ab0272dfe493ff6c7189318b51d64be48026327804c44c8f17a4446a3d5ba85f9c7f
+
+Count = 62
+Adata = 590a27721a36
+Payload = 41cee0ecaf9c65cef740440af37954ef49a585779d2abbca
+CT = a7eadcb559a39501de6924b5e07bf12be89c6b08be689c0bbcd00e9cb726d75e4283820ee81d933a
+
+Count = 63
+Adata = 58830fb0b1f3
+Payload = dce983e4e3734a9bd8848dba0d744d07bbeba602f4006025
+CT = 3acdbfbd154cba54f1aded051e76e8c31ad2487dd74247e4d5d71a1f0f1b6518c35f0632a30931fd
+
+Count = 64
+Adata = eedd0d767a25
+Payload = 4653b3e879ab18b65c5c3706a5139698262cb830a22d943b
+CT = a0778fb18f94e879757557b9b611335c8715564f816fb3fa3ad112899e9ba442660eb5dfe33b2f96
+
+Count = 65
+Adata = 618bcf2e3e79
+Payload = 8586383281925363ac15fb19c26d64c639c75920c792dc2c
+CT = 63a2046b77ada3ac853c9ba6d16fc10298feb75fe4d0fbed54fba446028919342b2fe86ee67efcc7
+
+Count = 66
+Adata = 549c9b84c7f7
+Payload = 95c25ae4445cd8c4d267df82687484667e309992fcf1e737
+CT = 73e666bdb263280bfb4ebf3d7b7621a2df0977eddfb3c0f69fc23013142f62881ccfa3037067e1ef
+
+Count = 67
+Adata = 92d7fa6a8135
+Payload = e58034bbb0e6f5e724e32ee56896dadae25c2a3efb8c6f2f
+CT = 03a408e246d905280dca4e5a7b947f1e4365c441d8ce48ee8263568d56fae8bf35b2f2cdecbffe0a
+
+Count = 68
+Adata = f43e126c0f83
+Payload = d98f0dddfe9cb3cae1336970d5efb55316a65e2c51e316f4
+CT = 3fab318408a34305c81a09cfc6ed1097b79fb05372a13135de2c2fbfdddc7dd6672714af174c5121
+
+Count = 69
+Adata = f02074812dde
+Payload = 548747b1669c6383b793054d93957f9e99d605761c6c23b5
+CT = b2a37be890a3934c9eba65f28097da5a38efeb093f2e04743704560ff23ce0000fba8812c45940ad
+
+[Alen = 7]
+
+Key = d7572ed0e37261efa02f8c83e695efdc
+Nonce = f4f96d7b4384a3930b3d830f82
+
+Count = 70
+Adata = 922340ec94861f
+Payload = 1edef80c57d17f969f8bde10ab38a1a8811a124de72c526e
+CT = de14558cc686e1836f1f121ea1b941a9ebd4f0fb916dc870fd541b988a801cb5751c7faaf5b0c164
+
+Count = 71
+Adata = 4eb379f21b1531
+Payload = ddd5282a207c1dcb03c1c3bbc9eb12a7bd28534118db2735
+CT = 1d1f85aab12b83def3550fb5c36af2a6d7e6b1f76e9abd2bc068bd1b1c309dfbd52d9a24be07c630
+
+Count = 72
+Adata = 7fa89e9d6e3fec
+Payload = c5b7c462eb166f48bb59c8102ee7b3dc67a28e5de7570c51
+CT = 057d69e27a41f15d4bcd041e246653dd0d6c6ceb9116964f2d114d6ab082738d05d60acca8e8ccfb
+
+Count = 73
+Adata = fda8665f87c618
+Payload = af793815e147e3180f5146aa6a582e343dc479f26b4226b2
+CT = 6fb3959570107d0dffc58aa460d9ce35570a9b441d03bcac1cc84bd77fe00e1a13433f2c10e3b799
+
+Count = 74
+Adata = 46bde207491ebd
+Payload = 47c76a0bbd5b1616b278089d41a050c509c7a1c280574bf7
+CT = 870dc78b2c0c880342ecc4934b21b0c463094374f616d1e9990c81f1bae32c953bf02ddbde047632
+
+Count = 75
+Adata = a799f5f895fd7a
+Payload = d554806ffc3900a0952a3c094c745808950697a6e5d62c1d
+CT = 159e2def6d6e9eb565bef00746f5b809ffc875109397b6031af19f1f080dd1dd2da799059755e49f
+
+Count = 76
+Adata = 20225831a9ee06
+Payload = ba45e1859efae362a44a0116a14e488ba369da6c76c3913b
+CT = 7a8f4c050fad7d7754decd18abcfa88ac9a738da00820b2523d3b9a0060834ac4860dae0eac570ef
+
+Count = 77
+Adata = 785360916464eb
+Payload = 57bc338946ff78cf76adf5021e2e44e34e687fb68ad703f3
+CT = 97769e09d7a8e6da8639390c14afa4e224a69d00fc9699edff96e7cf841a66c50bbb6fb2bac7ef51
+
+Count = 78
+Adata = 57b946369226db
+Payload = 9ac5be9929c4fe5a9992749a38dc69874866db3d4747da97
+CT = 5a0f1319b893604f6906b894325d898622a8398b3106408986e1c33a45f9d52755c374650635bef6
+
+Count = 79
+Adata = 73e4da8973c1e3
+Payload = 5a05410aa3a71f5f1a253b8576eba269c06a4c30591144cc
+CT = 9acfec8a32f0814aeab1f78b7c6a4268aaa4ae862f50ded2d78592c2d89c15edc5bb7486aa93f896
+
+[Alen = 8]
+
+Key = 98a42d7a0c5917deaf3b4de3f0cbe0a1
+Nonce = 03d33ab0c2df7bfce88b5ee4c4
+
+Count = 80
+Adata = 2d5438b728b950d9
+Payload = 9aa9c8358117564371366beeec923051ef433252197aaad5
+CT = 9ff942baa60f440c17a78e9581216b9a947a67f04d54911feecfff971fdfaa856310b014aa59c978
+
+Count = 81
+Adata = 6e430b497a16e7f5
+Payload = 5758a500978c71a9b90f6e5beae9d96ef05a41486b10ea2e
+CT = 52082f8fb09463e6df9e8b20875a82a58b6314ea3f3ed1e46a4d7b4b4df6c831ee32116ee4dad98c
+
+Count = 82
+Adata = e12f98507d6514c3
+Payload = 49efe18c76a8355127d914a3a830c1c6ff2a163d728526e1
+CT = 4cbf6b0351b0271e4148f1d8c5839a0d8413439f26ab1d2b3243fc75cd1624e152f451678edcac87
+
+Count = 83
+Adata = eecf8d641ee0bee9
+Payload = 49ae2309fbe6ce4e9421516b8f79ae64b1316cb849eaf638
+CT = 4cfea986dcfedc01f2b0b410e2caf5afca08391a1dc4cdf2dd6d8ca57da1880e1baff43736b3da34
+
+Count = 84
+Adata = 9066367c784de0a4
+Payload = b1bda5fa4242aa6aad0f5a5b1d31d86b8d4a97588b3e315d
+CT = b4ed2f75655ab825cb9ebf20708283a0f673c2fadf100a97f05439a661001513a96b896de46b7081
+
+Count = 85
+Adata = edf848b2510f7803
+Payload = eaa8608f6763d968576a7e89056b9828a1686c8441b06377
+CT = eff8ea00407bcb2731fb9bf268d8c3e3da513926159e58bdcf20709b2dc2ff9946094190b5ea09d1
+
+Count = 86
+Adata = 0f49cae81c8628d2
+Payload = f32029cf51609f0df9832ad1b283ea94a5356f70112c1328
+CT = f670a34076788d429f12cfaadf30b15fde0c3ad2450228e2a5bb6b4f87b9b198665203e4fdf9e7f7
+
+Count = 87
+Adata = b0c47e9cce46a276
+Payload = 7a550ef9254a8da6e4fee290a76ea838ffb61d3533d4d31f
+CT = 7f05847602529fe9826f07ebcaddf3f3848f489767fae8d529f416f89f1a34bbbf2ce40d943c6d8b
+
+Count = 88
+Adata = a6fe7c9ce2d49f85
+Payload = e67c486dd7ba9a9061844b9354f55890321ae626efaa28cc
+CT = e32cc2e2f0a288df0715aee83946035b4923b384bb8413067eb95550b91b955d5c2d72d5c189b704
+
+Count = 89
+Adata = eb1d11cc4876f58f
+Payload = 35f2c810091e930a52e4a3f28c9c8184967f1554c2675eb5
+CT = 30a2429f2e06814534754689e12fda4fed4640f69649657f0e8e8a5a7e0ea6860bab4a4320f03ae5
+
+[Alen = 9]
+
+Key = 2a68e3fe746f593c1b97cb637079c3e5
+Nonce = cd62d0f27b7f4864dc7c343acd
+
+Count = 90
+Adata = abe4f1d3812bfe3ccf
+Payload = 13b4a874888db0e5d8fd814b5e7e04f7fdfbc1601ccc02bc
+CT = 032835a3dbf688d09cf2a32a92b101959d33ff47500f92f4fd49840440f866d1a22b0854996111d8
+
+Count = 91
+Adata = 2e21f466814d3d6340
+Payload = 08b5c773364cded74d7b308984313c17ff90eed496a27a2b
+CT = 18295aa46537e6e2097412e848fe39759f58d0f3da61ea63de2f5c335df537fbbc6ae59cd562732f
+
+Count = 92
+Adata = dba22aabcea0e694fc
+Payload = bbac1790abb7aafe272ec472c897e6363e335b3c4126c762
+CT = ab308a47f8cc92cb6321e6130458e3545efb651b0de5572acc5ed6e4a907ff4742ab6c835a427f92
+
+Count = 93
+Adata = 97e9d16bd757395ec1
+Payload = 7249612dc09809bbca9dd311e720f7da2cb54ce33e3eb9c3
+CT = 62d5fcfa93e3318e8e92f1702beff2b84c7d72c472fd298b1714b5a3df454f3bc35869da75adc882
+
+Count = 94
+Adata = 866cf710470cac74d3
+Payload = 060ae0ab9857324a3b2ac79f3b6e6f90f5de884ce9c7b930
+CT = 16967d7ccb2c0a7f7f25e5fef7a16af29516b66ba5042978aa33dffe2596832f98a9c8413bd898b9
+
+Count = 95
+Adata = 2dd7a7f832b29ccce2
+Payload = f77a9fd5363836deefd34e1bea0882484a7ab746b4495d59
+CT = e7e6020265430eebabdc6c7a26c7872a2ab28961f88acd11dd5049f7c53d6a7fe5d7f959689ee960
+
+Count = 96
+Adata = 502349a60e897356b5
+Payload = 96118dbfe53434d8aed88769a535eb0c8b5849dca1c81c34
+CT = 868d1068b64f0cedead7a50869faee6eeb9077fbed0b8c7ced9c3a0d0de8788471c5f6c2f9638b7c
+
+Count = 97
+Adata = debed45c9acf129268
+Payload = df5a47d3eb5c0b6cabb6711a45400602d205b82ecae9e849
+CT = cfc6da04b8273359efb9537b898f0360b2cd8609862a7801d49b4b9bead1b7de2021cff280d6f93b
+
+Count = 98
+Adata = 2726702dd62a6e5344
+Payload = 5a7649cb001fbb6f653cbca17756c5c1a078c2e240d92085
+CT = 4aead41c5364835a21339ec0bb99c0a3c0b0fcc50c1ab0cd69df31aba209d87ee22bd6a1dcadb168
+
+Count = 99
+Adata = e8006cfb0536696ac7
+Payload = 95186d41f927cdbef42157f21d966e88061b6558b5ec932f
+CT = 8584f096aa5cf58bb02e7593d1596bea66d35b7ff92f03677cc5b60c881fe834a789d28447d8fb54
+
+[Alen = 10]
+
+Key = 46b067cf9b1a28cf187002e90b14e130
+Nonce = bad8c03292bf01cfd8d34f860c
+
+Count = 100
+Adata = 8d65880eddb9fd96d276
+Payload = cc0915194218d4536e467433cd6d79ff1d9eb9ff160ab684
+CT = bd56edc015692c6ab9bec493a9893863598414a3d11a6a0f27ecdcb257d0d30491e5bf1aa8f90958
+
+Count = 101
+Adata = 8a65cde13149d9d54a5b
+Payload = 28257133b1d8b0b2be4faecd6e819ac783707a5c5f50c302
+CT = 597a89eae6a9488b69b71e6d0a65db5bc76ad70098401f89b10f9fc201e4128696dcd899dd2e24ea
+
+Count = 102
+Adata = e999ec3e1bfb25b5877c
+Payload = 96ab0cfc204bafc4f5851d6c682d631d0c5ad03ac925a943
+CT = e7f4f425773a57fd227dadcc0cc9228148407d660e3575c8c522e5ba5adbc6a639cbd06f103ebc9e
+
+Count = 103
+Adata = a8554441e073d6065dce
+Payload = 50925853a84a33ff392154e4e737efc18dcfc98f4d5235a9
+CT = 21cda08aff3bcbc6eed9e44483d3ae5dc9d564d38a42e922e1a4e0f7ebc3cff3915d27971cce7e91
+
+Count = 104
+Adata = 838f0be8d04d28d77549
+Payload = d0700658d5f4010ff21091f3d119c99645e339198029c3a9
+CT = a12ffe818285f93625e82153b5fd880a01f9944547391f22c215c88d80bffc881aff10ba40f11976
+
+Count = 105
+Adata = 20f014d928d5b25fbaf4
+Payload = 4bdf28748a0c281dd49c7294ae8e55fe7a52d45ff6384db3
+CT = 3a80d0addd7dd0240364c234ca6a14623e487903312891382cc9391bc06aa6ca9d486a4e2a218c54
+
+Count = 106
+Adata = 56c026b8a71974ff7ecd
+Payload = f75db057f0276fff85014f54ecdec8f90b96a2a982db14cb
+CT = 8602488ea75697c652f9fff4883a89654f8c0ff545cbc840778b05c6c582a0bb7d1d9dcf6a46b9f6
+
+Count = 107
+Adata = 75c3b9e52648a4f9aca9
+Payload = c15c554169dbb9b08494afaa44819a10dc9ddad54199ab54
+CT = b003ad983eaa4189536c1f0a2065db8c98877789868977dff47d9ebbd3cff14623b10cecc94b53d6
+
+Count = 108
+Adata = 1c76c3014a14b7fa1ca8
+Payload = 19eef6f798fc68086aad1cda6d7976cdcfe6b8af74598032
+CT = 68b10e2ecf8d9031bd55ac7a099d37518bfc15f3b3495cb9d2b74b84dc170c00dce85b56e346a976
+
+Count = 109
+Adata = a4eb60d4eb7ead1bd0e6
+Payload = e06e5dba5ac35cfd07949e5cc12ad70507d4a86a952ecca3
+CT = 9131a5630db2a4c4d06c2efca5ce969943ce0536523e1028d92e19fd8b5c1fcbff36adaa5e47ae84
+
+[Alen = 11]
+
+Key = e94dac9c90984790a7c0c867536615ff
+Nonce = c19f06f91e645d4199365f18c0
+
+Count = 110
+Adata = 537038b5357e358a930bd6
+Payload = 4d64461c55eb16bf7b9120f22be349598f2f394da8460dc6
+CT = e9fc5004c2359724e1e4411ae6f834ef6bea046d549753c88790c1648f461a31c84e62ea8592a074
+
+Count = 111
+Adata = 7e3d7b3eada988668f3784
+Payload = eab7d5dbd91d4cbbac8d79fadd70b5dcb3baadac5cb713a3
+CT = 4e2fc3c34ec3cd2036f81812106bc86a577f908ca0664dadacb1d1c9231d2c22ecfeed622792dfd0
+
+Count = 112
+Adata = 78b107b29c4878ff18f749
+Payload = 3c6ae2e2578875a1f5611582528e058aece2ddc33a4dde3d
+CT = 98f2f4fac056f43a6f14746a9f95783c0827e0e3c69c8033fffe60299768f048e7098033cde046b0
+
+Count = 113
+Adata = d293908bb516c5f3a411b9
+Payload = d7a46e726ed43f1580eb52141a93390982cc809dc833e3f0
+CT = 733c786af90abe8e1a9e33fcd78844bf6609bdbd34e2bdfe4ee6ebc0d90a0de05b428495c93e1801
+
+Count = 114
+Adata = 33ef208faad4d2948c9e67
+Payload = b1fe5d9d34157193fc0608cd8ecb872e17720f5f6814a466
+CT = 15664b85a3cbf0086673692543d0fa98f3b7327f94c5fa687e7e64cc0fcd6a92c79ceb6ce2abd8ee
+
+Count = 115
+Adata = b7f7ed9ccac3c2b4fbfee0
+Payload = de6bb539fb7a9c87414f62a7cf25a4cfca176509e991af41
+CT = 7af3a3216ca41d1cdb3a034f023ed9792ed258291540f14fb02b53bc779e0976b634b0d1b88fc0a9
+
+Count = 116
+Adata = a6e287383927f76e4927af
+Payload = 8719d20c20c8959068b8adcd65e6f6bc7b3693828f0735a0
+CT = 2381c414b716140bf2cdcc25a8fd8b0a9ff3aea273d66bae3c37fa936243b393f07fcccb0fc13e41
+
+Count = 117
+Adata = 70828be6dd93954f4e7b6b
+Payload = 30b39426831f61c8ba5f2ef5b71f0c4b2f916e3b5a578110
+CT = 942b823e14c1e053202a4f1d7a0471fdcb54531ba686df1e0d7534a489e6d242966ebea4455f8f79
+
+Count = 118
+Adata = 506015fc2831df293f4da0
+Payload = 818d5d810f678629f078723f5c6c3657271077533bfb7c29
+CT = 25154b9998b907b26a0d13d791774be1c3d54a73c72a2227ccbf64f04e95b180d09e843847d22104
+
+Count = 119
+Adata = e9394b0245b379e68e3dea
+Payload = f0613205a7a0822849df9e8a3cf6caf281f3adfa966c5507
+CT = 54f9241d307e03b3d3aaff62f1edb744653690da6abd0b0927b546ef8cd717073832584fb25a0645
+
+[Alen = 12]
+
+Key = f6bb5d59b0fa9de0828b115303bf94aa
+Nonce = 05358f33e1fc6a53ab5a5c98ce
+
+Count = 120
+Adata = 040b25771239cc2a39446e3c
+Payload = 011fc50329bfd63a85ebd4f7693363602f1a4147371270b7
+CT = 4432d7eb42980734d34f19c50cf8abf71ac1b19ed75a727854e5d050a405f755047d09cb0f49546a
+
+Count = 121
+Adata = 50a1d37fa2f3462bd304631b
+Payload = c90e40540d372ab1eb00ea5d5b8de5bf7c94ce4e376d6949
+CT = 8c2352bc6610fbbfbda4276f3e462d28494f3e97d7256b862abee8547ee3f24cfa677468ecc1d121
+
+Count = 122
+Adata = ac3bb872a41df35e415d2b0c
+Payload = 9e7be78c0ab9e6a4c6c257e77c63681bea35d951f168b0c5
+CT = db56f564619e37aa90669ad519a8a08cdfee29881120b20a61cef865ce4080e7c7abfc43f62c03a3
+
+Count = 123
+Adata = e3106ae6456153dd922640a1
+Payload = 00df0c5a5d3eceb2bd293066529799544f846672a9a1d31b
+CT = 45f21eb236191fbceb8dfd54375c51c37a5f96ab49e9d1d4e1d19c321a1e0852adba939b447220ab
+
+Count = 124
+Adata = 297b4498bf5427e6341aa927
+Payload = 14967a0476dbaea03b07fa8d40d344eabaf479be2443243a
+CT = 51bb68ec1dfc7fae6da337bf25188c7d8f2f8967c40b26f579ea5fb65018abdcde1a39f6859ecb56
+
+Count = 125
+Adata = 5de60dc0e3b5bda0b33a9520
+Payload = 2da3716d76d10b6766a1f9cbf9f420316fd5f396e7b9a2ba
+CT = 688e63851df6da69300534f99c3fe8a65a0e034f07f1a075c2629ff871ee15745fd8c1ddbdae4c29
+
+Count = 126
+Adata = 1c9b8541943ad50b4243c179
+Payload = 8c1b3ba18d1f5cff74a457aadd6b3e7d093d06ad2622e6a0
+CT = c9362949e6388df122009a98b8a0f6ea3ce6f674c66ae46f04e198ad16ad1106d3ba6172f4a13a8f
+
+Count = 127
+Adata = 51e926d2542ac8faef61465a
+Payload = 88936e97db070c0ec2aa58d1c6f5b34df3d32ddf7db34a8b
+CT = cdbe7c7fb020dd00940e95e3a33e7bdac608dd069dfb484475981131e3934ec6d41e00d502729799
+
+Count = 128
+Adata = ebefbac97b363e6f32526aac
+Payload = c20742e4b410c5b661da373a905fb0ed55b20e0e879eff5c
+CT = 872a500cdf3714b8377efa08f594787a6069fed767d6fd93e2c005b5bebe07ff578b1b4bc51971cd
+
+Count = 129
+Adata = 1ef059ac7d648e9e32d9b1f2
+Payload = 65c55ca21a89a8325365bf2be861d700559de2eabb41b37f
+CT = 20e84e4a71ae793c05c172198daa1f97604612335b09b1b021a25f15b5b4229a872a9199972c85b3
+
+[Alen = 13]
+
+Key = d1da2e961e78063af8de41865b226873
+Nonce = 03739f5474857006340cce554d
+
+Count = 130
+Adata = e3afd091d2b588465872a6300f
+Payload = 8e5fa1a6662a8378cda15697e926841594f2f394fa5a34ab
+CT = ca0d95e3ff186ad6b88d45fc4079e6b7b4a615e7e8dd5f4742d522cc9dc19c47a4fa0b1528069cf8
+
+Count = 131
+Adata = ce3186bb737753b59ee76b748c
+Payload = 311ebc5ff2f625944562ea699b2690df3e6e64a17c62bd3a
+CT = 754c881a6bc4cc3a304ef9023279f27d1e3a82d26ee5d6d659b26510b8f25610799e011d7c850ecd
+
+Count = 132
+Adata = bfd636989dfbcb0edc9f014cc8
+Payload = c96cee5ba7b799f16254a17b1870cdb85fe0ef3f42110c13
+CT = 8d3eda1e3e85705f1778b210b12faf1a7fb4094c509667ff52942aa0d39649f3d9ed535bebc2b603
+
+Count = 133
+Adata = 4812b092aa59d57451bfd812c3
+Payload = 13b1b4404dc5735655139414fcbd02c5327ae9fb148bd324
+CT = 57e38005d4f79af8203f877f55e26067122e0f88060cb8c8c1e61efb9c1d84ddac2d24f43531f569
+
+Count = 134
+Adata = f6ef9ac4f4c9ce1e4309c64fa8
+Payload = 6c5b59319e2710f5d63407f85b424d1860425ef8ce0cfe53
+CT = 28096d740715f95ba3181493f21d2fba4016b88bdc8b95bf13350de0ef34df12fb945b0ae0a0d9bd
+
+Count = 135
+Adata = 9bf12168bb3d79ebd25262f2b4
+Payload = 968e1d78008da78611e82985c4028e86770858cfe61c3723
+CT = d2dc293d99bf4e2864c43aee6d5dec24575cbebcf49b5ccfa0734563638598d8c4bf1fcd94009925
+
+Count = 136
+Adata = 7d870d7e52d3053c65eefad477
+Payload = 6a1306d911434cc7400d2f9a95e36aedceddca2b3d583f51
+CT = 2e41329c8871a56935213cf13cbc084fee892c582fdf54bda1f5fc53b08aca82bccfba6fbcb27e69
+
+Count = 137
+Adata = e95099f04371e445e5eaa1d80e
+Payload = b9197eb50c8168d16b8a12bd261d553ffcc521d979b26fee
+CT = fd4b4af095b3817f1ea601d68f42379ddc91c7aa6b3504027d1a922953facbd630d7fea6b63594ec
+
+Count = 138
+Adata = 3e80eb03db6545204ef4241ad6
+Payload = 95f59e36eac8eb3b51709d635b07fa2da0976ea20e25807f
+CT = d1a7aa7373fa0295245c8e08f258988f80c388d11ca2eb9383fa000d10078256b71249d9d1f1846c
+
+Count = 139
+Adata = 9748798c0f3cc766795c8ce0e4
+Payload = a48db9add9ecdeb49e51d3ab7bb2075202ed2aa50c0195b1
+CT = e0df8de840de371aeb7dc0c0d2ed65f022b9ccd61e86fe5d2773c2f55b752477c489facee812c614
+
+[Alen = 14]
+
+Key = 1eee667267ef10b03624cf9c341e3f75
+Nonce = 0630a3eae27e505c61c56e6560
+
+Count = 140
+Adata = d24651ef0561282d3e20e834960c
+Payload = 798e31cce0a83702a95171fb1162a17b9ce00ec3592ce262
+CT = f3c3e52f1a1ff528a8d3783ee4e75f114e3e6416334815d2d9236d5c5c9319092078411b72c51ba8
+
+Count = 141
+Adata = c527d309ab29ee91c5fc53117e71
+Payload = d79cd4c8891ec4ce2c51136712d23b32266b2b73768aeb1e
+CT = 5dd1002b73a906e42dd31aa2e757c558f4b541a61cee1caed8ad2a48cb734e3f93e602c15c7c775e
+
+Count = 142
+Adata = a93dfc3944514ddfc5acdd89fab7
+Payload = d7fa81c949f1f2af29dbd56529b307e3b348e996d0936455
+CT = 5db7552ab34630852859dca0dc36f98961968343baf793e5f34b297f3f106a9cdae255f7634fbd0f
+
+Count = 143
+Adata = e502abe21c7b22120693a08ef3e6
+Payload = 6330caaeddf0473d564d175b9408c6f12e6d3cd4ee2c423f
+CT = e97d1e4d2747851757cf1e9e618d389bfcb356018448b58f4f5d9c3dbfe3e2fe03a002e55039ebe6
+
+Count = 144
+Adata = a49b34dfad43333fb2ffd701a2d6
+Payload = 45671482c390e65f75de15ca91b93596e9bf3d6fc9178bcb
+CT = cf2ac06139272475745c1c0f643ccbfc3b6157baa3737c7b6f7bb0749c99d75740f2d193fef36c60
+
+Count = 145
+Adata = 9e4d8aa3dbdc4d4b4b8d72734f52
+Payload = c8f34bea8bdc403a48d8ed9268429141cd03c29558050ef4
+CT = 42be9f09716b8210495ae4579dc76f2b1fdda8403261f944ceec82fc674da9efa6926e8641729ed8
+
+Count = 146
+Adata = 052327ad59cc791259817fd0ed96
+Payload = d8d1c57b16c23894b66023c29f8648ce4a6074647e1f5f69
+CT = 529c1198ec75fabeb7e22a076a03b6a498be1eb1147ba8d92ff19e93f60c8f3a511300fddc38ee59
+
+Count = 147
+Adata = 14bc3c44c001ccb261a2a0526523
+Payload = 71c14a7031033db15bfe23b75fed9daf8886dd11392a0b78
+CT = fb8c9e93cbb4ff9b5a7c2a72aa6863c55a58b7c4534efcc87fa00fb244eda0d77cf6c05c8fd590af
+
+Count = 148
+Adata = 3477384c396a9e9efb3e169722cb
+Payload = afa795f836763a1210bb36fef167864f73ba3b6abc593537
+CT = 25ea411bccc1f83811393f3b04e27825a16451bfd63dc287bae19612657c87d3bb73cfb8cee7c8a8
+
+Count = 149
+Adata = 0c3b9a6924ad506038cb2d6590c9
+Payload = ca4a186f116a179579e3d327aec3f5be358bc7094f853bc3
+CT = 4007cc8cebddd5bf7861dae25b460bd4e755addc25e1cc733d9713d2e916c23ac3039de34c295fc4
+
+[Alen = 15]
+
+Key = dbbd26f5d9e970e4e384b2273961be5a
+Nonce = 0b1eabe504ef4822542e397fec
+
+Count = 150
+Adata = 477937301c83ba02d50760b603e0ea
+Payload = 553714e17a208a2eceb847a4a2d95088388b1ac8d8ca43e0
+CT = 1c80213268bad5402c4dc9b5d836ab7499810d0d8a974716df9a0e986ab2890736423bb3772cec3e
+
+Count = 151
+Adata = c91eb5a07ff19c044023e5cf339203
+Payload = c94d0b9e728413c58202cb3f6b82dba7aa9e3ca0a72c40c7
+CT = 80fa3e4d601e4cab60f7452e116d205b0b942b65f571443139f907a92cb01215e3cda84ae13af48b
+
+Count = 152
+Adata = 38c71a8e9b279c605c7f0418a0afc1
+Payload = b4e8c4fd5ad98a1be8b5a11677c57ca1c1694e3528092aa9
+CT = fd5ff12e4843d5750a402f070d2a875d606359f07a542e5f3dbd8dbf7485106cdf9ea0e7088a5650
+
+Count = 153
+Adata = f2c76ef617fa2bfc8a4d6bcbb15fe8
+Payload = 578ce26cdb5ba2e8798e23588e5cd04ef782820b80e49a42
+CT = 1e3bd7bfc9c1fd869b7bad49f4b32bb2568895ced2b99eb4853fde6f4dca88ff11bbce20ed9e5012
+
+Count = 154
+Adata = 36004342dd74e7966692a848b2c11e
+Payload = 78733c635d4d4e8b0729732f1e174dfcec4e020a7ac3870d
+CT = 31c409b04fd711e5e5dcfd3e64f8b6004d4415cf289e83fbd94e979108fcecbd32f6bdf72f0ccb4d
+
+Count = 155
+Adata = db92bc3fe5d4141aeb39baea6f114c
+Payload = c7aafe7760945e45703c1e19f1032dfd56ddc216c3b03826
+CT = 8e1dcba4720e012b92c990088becd601f7d7d5d391ed3cd0229c8f9d4e39fc16cbdb44236ef125c7
+
+Count = 156
+Adata = 34ec2d5b6f0d950509b47a0637d74c
+Payload = 2345e36a63be0b78df95e60907c78da0e48e61e70685a1f3
+CT = 6af2d6b9712454163d6068187d28765c4584762254d8a5051c9ab7cb0a779c3fa78c9ee12603802b
+
+Count = 157
+Adata = 6ab658d177c2dd87c9b8787cd70182
+Payload = b0725f735543eb0c0ec88ae69b140f5787d28ef4a2e36d57
+CT = f9c56aa047d9b462ec3d04f7e1fbf4ab26d89931f0be69a1648c6307ec5ea304045a7cdc93f36b9d
+
+Count = 158
+Adata = 483f135c61250fa610b4d14b99ecf0
+Payload = 315a947bf5291278d446d332ee5ca0def7655d5c957a8fb4
+CT = 78eda1a8e7b34d1636b35d2394b35b22566f4a99c7278b42364ff3b1ad915347b1c7f062b10d3da4
+
+Count = 159
+Adata = bb022aed60819ef84ae83ce27db9d0
+Payload = f78d00755bcb45e6822121fe7cb03c8e627c9f548ccd7e7c
+CT = be3a35a649511a8860d4afef065fc772c3768891de907a8a7569808dab58d42181543b2e2d05992c
+
+[Alen = 16]
+
+Key = 10a7720f2e18f739c26924925af6b670
+Nonce = 8c4e7813ab9bce9dafee01c628
+
+Count = 160
+Adata = a209941fab710fda38d11c68b13d930f
+Payload = e59782a9aea45f467b90e51a0fdf166baba05663def2d8b6
+CT = e357b1ccdaca6f3506dc45279c2e4c59f5307a5fd6a99cd72341ea8c0785569973f90ee9ee645acc
+
+Count = 161
+Adata = 2e2f6f9755a492ee54df77b2ecab9808
+Payload = 042a072f6ebf11f79fcb4f5a64f7946dc837d9d2355785ea
+CT = 02ea344a1ad12184e287ef67f706ce5f96a7f5ee3d0cc18b703eb81224cdb1fd2e1cfb2fbfe1e402
+
+Count = 162
+Adata = 99e98c9983c85d1f49ae43ebad67a652
+Payload = 5db6bda27910e7b8b61ac476c6532570b71b3932bd6a698c
+CT = 5b768ec70d7ed7cbcb56644b55a27f42e98b150eb5312ded64c4aea7f17f18f068897557c93ffaaa
+
+Count = 163
+Adata = 37a837d73fa15793f6f823fb99c2ea74
+Payload = 8cac261a461c3ddd2642b8e4e5c3389e491fcb2ff8356412
+CT = 8a6c157f32720dae5b0e18d9763262ac178fe713f06e20736f3b2e70e6e2dc7acc74a823a7f49722
+
+Count = 164
+Adata = 11119a4e779cfb64c736d425e4ff554d
+Payload = 3429f9b088b501d7944c462694d0799568282e7ce07d3e61
+CT = 32e9cad5fcdb31a4e900e61b072123a736b80240e8267a000dc3b57096f0df1d4eb5328c416921bc
+
+Count = 165
+Adata = 962d7d4305f23d1692747b504960c0a4
+Payload = a46ae4c71d4c9eb72fabfa76b8074aa02e07653eca10eef5
+CT = a2aad7a26922aec452e75a4b2bf6109270974902c24baa94f62ed804e9f2ac0f7001d0f35ea9f3c1
+
+Count = 166
+Adata = bbb1fdfefcf3657ba6cd93ff341a04e1
+Payload = 92f5e3083f57c77ac9553a2024a66489698bd2261f05d415
+CT = 9435d06d4b39f709b4199a1db7573ebb371bfe1a175e9074907dcd7ac1e0bb248d46c3036c39fb02
+
+Count = 167
+Adata = 74be126f7c596642dafa8fe3da904e69
+Payload = 41ecc3aae5cfebfad7921a47a0684601ffe73816380f8716
+CT = 472cf0cf91a1db89aadeba7a33991c33a177142a3054c37787cbb80fd21127feca7e76fd6947d5b7
+
+Count = 168
+Adata = d72cc521c90a468522af8966c24799f3
+Payload = 8850bdda4bd0271e333db344a47b837183eb48269c3dc0b6
+CT = 8e908ebf3fbe176d4e711379378ad943dd7b641a946684d7cdb5d1243b6e73b8e380d8ca041647db
+
+Count = 169
+Adata = 28f427fba8d0bb0380bbe5072ccfa519
+Payload = fdd3ca2f193f93f5a349b50357d26748b767cde6ab5cbfe7
+CT = fb13f94a6d51a386de05153ec4233d7ae9f7e1daa307fb864a0ae8604b103f882f17db893ed5c576
+
+[Alen = 17]
+
+Key = 6bffab1f4f4c1ff66b4a669b515b2f8d
+Nonce = ddb34d5e0140fb96d690e1a2b7
+
+Count = 170
+Adata = 5cbba9ea778e01af00afb2a934f28c7211
+Payload = d91b12e8655dd92b1332fc1d71c391c96a17111562d90ba3
+CT = d302e5b2d5d90433186b804cd7717e2db2f22cdc34fb2942ab30780a2c4f12af8f35350d65284c59
+
+Count = 171
+Adata = 1583138aa307401dddc40804ac0f414d33
+Payload = eeafb08d4a4819f5682a01d44371e34cc5729079e74e73a6
+CT = e4b647d7faccc4ed63737d85e5c30ca81d97adb0b16c514746577901b7f6feb88b8e2b8562f9cb5f
+
+Count = 172
+Adata = 23931c258c84086500c6a3b6eda457e6b5
+Payload = b8737d5bbfc976c2d8d9786148dea664dd83cee98df537b5
+CT = b26a8a010f4dabdad3800430ee6c49800566f320dbd715548735a59390ba7a892741694f3a89b0bf
+
+Count = 173
+Adata = e12f98507d6514c3b551d240595346bc9e
+Payload = eb021b63c61c0b194bd44870608d7ef0b932b6104412d7a9
+CT = e11bec397698d601408d3421c63f911461d78bd91230f548f4f81ed18cc1820375a7bec2318cde1e
+
+Count = 174
+Adata = e14b87d49d231c0199eec627fd7f1b5332
+Payload = 93b42584c4956078359d77e80aef52281b9228a1f66aa36b
+CT = 99add2de7411bd603ec40bb9ac5dbdccc3771568a048818a187b430caa60d98dc3e2aeefe6249b44
+
+Count = 175
+Adata = ca095aec96a8b093e62b10f0950ce35ce7
+Payload = 6a788d8238c7b313b8eba27b210a71c36819d719115b9b76
+CT = 60617ad888436e0bb3b2de2a87b89e27b0fcead04779b9970a77372b727408e1bf5a70790b9eba3a
+
+Count = 176
+Adata = d1cac02b34ad33c0e77a5bda2c3baf5e5d
+Payload = 3bc1ee54d0094603dfc68eee118e547d031fb36e464e776d
+CT = 31d8190e608d9b1bd49ff2bfb73cbb99dbfa8ea7106c558cdc1f5cb4d4fa2204e82eedcb3784443d
+
+Count = 177
+Adata = 065c06b49a49898e20bb679e35edbb1f76
+Payload = 8a12adb8b746216baa8a418725e608e4377f13816a036a10
+CT = 800b5ae207c2fc73a1d33dd68354e700ef9a2e483c2148f12413f9496592a75a1d6e42ee3a258607
+
+Count = 178
+Adata = 98a42d7a0c5917deaf3b4de3f0cbe0a191
+Payload = 30a226c07401d0ae24c73d682e3a6e7e377ec1613bafba17
+CT = 3abbd19ac4850db62f9e41398888819aef9bfca86d8d98f6b571a3150887df1ac5f813676b2eb24f
+
+Count = 179
+Adata = e245a7528931841b52a5f59d861d98d7b7
+Payload = 3d17bcdf30445ebd8a9b6aa2fe11d443c1161bb1ee69ced0
+CT = 370e4b8580c083a581c216f358a33ba719f32678b84bec3131aa5e4657c92e31c69ab18d447d3578
+
+[Alen = 18]
+
+Key = ae6136df9ab43631ef143515dacedbe7
+Nonce = c5c445792208a50c8e93d64aa3
+
+Count = 180
+Adata = e04006b68c83a5dd4ceac3cde238e48895ae
+Payload = 6a493c5ef3769ccc4101dbb2eb36e1e5bbc577a057ce0731
+CT = c7584c0203c2535c5702c6ae93b7cbfb066f4a055c627a180d6d676d11fce907b5c93fa1ed7bff2b
+
+Count = 181
+Adata = 5da64e368f45153ea5b7ddca966b6c5b699a
+Payload = 15e0c672c6764f3699d9d3e7120f8ce5daab166f08fdd074
+CT = b8f1b62e36c280a68fdacefb6a8ea6fb67012bca0351ad5d2cd45f211b1a1364c91ad07959bf0ee5
+
+Count = 182
+Adata = 1b315d024bb5d1e03d7510e61f37d8adb10a
+Payload = de907d58cd8f5a72acaa1d329b937dfbbfed65a4e45eb029
+CT = 73810d043d3b95e2baa9002ee31257e502475801eff2cd0018f021a98b2edfb0b7500363099c2a1a
+
+Count = 183
+Adata = 8691ba4f9232ca86f919fe72ddb39c91d707
+Payload = c7fa314d27be79f9d3e2d1e188c1785b0c970f91b8ed4290
+CT = 6aeb4111d70ab669c5e1ccfdf0405245b13d3234b3413fb92ac9aeb018c48f3902276ac759710b6d
+
+Count = 184
+Adata = ff0baf1cbb5884a9290ea7b5ee49915efb4b
+Payload = 33b05b20f3c849fac091a5028cbfa0bc9a1c32514136fee3
+CT = 9ea12b7c037c866ad692b81ef43e8aa227b60ff44a9a83ca7dac49f606dadb9f7034e0a1860d519b
+
+Count = 185
+Adata = 2d118cda20700bc2748ea1753fbca6f74933
+Payload = f43832e420e2eccd5d80502bea2ba1804e17d4433318fc86
+CT = 592942b8d056235d4b834d3792aa8b9ef3bde9e638b481af623ccbab19c1442806e21c5a820945da
+
+Count = 186
+Adata = 0c7a5fd2010c999a8a0efa81f89ff5bfefe0
+Payload = ceb203c842a962183f22e602644fc66e4290b3d5be445fb4
+CT = 63a37394b21dad882921fb1e1cceec70ff3a8e70b5e8229ddbcd18947ac1800856c9c92eb0388c70
+
+Count = 187
+Adata = 73fdddb9e0a64f5671fd70c4ea8443507789
+Payload = d6015b6bd5f5eabb2a649129f8f727c06a3ad59499f21caf
+CT = 7b102b372541252b3c678c3580760dded790e831925e618639c29ea73b0c5aa130d8b14f7b9926a9
+
+Count = 188
+Adata = 82c4484e3a6e18b6bbfd78b69b00c40b30c5
+Payload = c288b810fb533441bd549d02c0b28d5b834293683eaacda2
+CT = 6f99c84c0be7fbd1ab57801eb833a7453ee8aecd3506b08bf0a0f148ae138c2ea02538c8fd7ac76c
+
+Count = 189
+Adata = 267d8385b14721eded743cffd69e4d595f7e
+Payload = 667cc47d13c34923be2441300066a6c150b24d66c947ca7b
+CT = cb6db421e37786b3a8275c2c78e78cdfed1870c3c2ebb75285eb537e7583f04e040a0ddc41106213
+
+[Alen = 19]
+
+Key = f1908328edf2996ebfc9655472ca5ad0
+Nonce = 4c693364546930b6c5250e2699
+
+Count = 190
+Adata = 4a3634e5028df97fbe00eb016e8ea4f1918faa
+Payload = eede01b08f9a303cdf14c99d7a45732972c6eff2a1db06eb
+CT = 90c850790b0b380f5aeb2488fdf43c9d5ef1759861e86f6e52570e769629dcc2e568737ba53a1195
+
+Count = 191
+Adata = 041b93e3fc059fa44aa755e88df277b9b6e499
+Payload = e61ca7310172eec16745a73e34516f65844eecd0dbc5566a
+CT = 980af6f885e3e6f2e2ba4a2bb3e020d1a87976ba1bf63feff1d82ec19a2e3ec43bbdb34e10999d90
+
+Count = 192
+Adata = d1be393376cb5d23cf8139da0fd92f3d520ae9
+Payload = ea887edee68ad5fa6bae928aa480dda898037f820700ec52
+CT = 949e2f17621bddc9ee517f9f2331921cb434e5e8c73385d7f2abb0ce4de9eeb5e8af9cdf3391d3cc
+
+Count = 193
+Adata = f3e551b34d2db1286a9f41085e4dda95ec3f75
+Payload = 71fe1ba5d299495d2a56039c64032ec6263d437f55e3f5be
+CT = 0fe84a6c5608416eafa9ee89e3b261720a0ad91595d09c3b239c73b01ba49a8498b5ff4833851069
+
+Count = 194
+Adata = a69ddc66e63a3415f21009d53adcf26bc1a9a5
+Payload = bd04d854216740a6ceb9827cbddd83761d19feb2a21d78ef
+CT = c312899da5f648954b466f693a6cccc2312e64d8622e116a2248dacd3903c26a2dc5ae649566ad67
+
+Count = 195
+Adata = 5735d6f5882d8f27155eb4cc285a65138ad64a
+Payload = 33b44873a7a1e5b0fdbb7e7347623e4fa1ccd937feb26fda
+CT = 4da219ba2330ed8378449366c0d371fb8dfb435d3e81065fd4156cf7d97b2e744351b6960a807cf8
+
+Count = 196
+Adata = 5d94ed976ab2063512690ae704c3b115519742
+Payload = d3909d577a4e89642227cc6fc146b61bc18392175e342898
+CT = ad86cc9efedf8157a7d8217a46f7f9afedb4087d9e07411d5a50086b6711ac72533c3c5717f6892c
+
+Count = 197
+Adata = db20b384620ab8691aed2fed14a745188d94c0
+Payload = ba0716355fffb8ef947d2a15eb58375a1ff1084c56699029
+CT = c41147fcdb6eb0dc1182c7006ce978ee33c69226965af9ac54fb74ecb9a5163b01b9dbf97ff2f999
+
+Count = 198
+Adata = 94897cdd04e0c8480b2ef7b5201dda37558ba9
+Payload = 5f4b4f97b6aa48adb3336c451aac377fde4adf47897fd9cc
+CT = 215d1e5e323b409e36cc81509d1d78cbf27d452d494cb049d2a81702f665ff5c54f586defd268c94
+
+Count = 199
+Adata = 95c44e1e5ad256b3ce1cc1d87137a1e09f1fd4
+Payload = 598e91d39c414496fd5e69f2cf80826b4e7d59ba28e0a0d8
+CT = 2798c01a18d04ca578a184e74831cddf624ac3d0e8d3c95dfa641889723e163825ab65727e8a5343
+
+[Alen = 20]
+
+Key = 61cb8eb792e95d099a1455fb789d8d16
+Nonce = 1f37b3e59137f2a60dc09d16ac
+
+Count = 200
+Adata = 09db3efac9473f713da630ae92c2c8604c61c51e
+Payload = 6ad541695a37c32d73ff6d5f870abd5b0f362a8968c4fce0
+CT = e65fcc975865c1499b088b58ba163283085d8ca68dc3b235d89756e5d78753ef22c012ae34b39a20
+
+Count = 201
+Adata = b6d07035aed9c141c713cc3bce60f7ba8ac2545f
+Payload = 9cce4c82fe9d38ef64ac8abdf0619f201a25ce6903675627
+CT = 1044c17cfccf3a8b8c5b6cbacd7d10f81d4e6846e66018f2fc78ebae9c143a7283b0641e1f83f5a0
+
+Count = 202
+Adata = 80a5ab693378af29cd5a33555cb3579f9ae540aa
+Payload = 7295a7aed3e987baef19ad68c33ba5a5dcbff27875ff5236
+CT = fe1f2a50d1bb85de07ee4b6ffe272a7ddbd4545790f81ce35a7e44348d2b3085348f787128a4e96a
+
+Count = 203
+Adata = 220817144a15a0a654fc1beaabce60270aa72df8
+Payload = eb21fe20fc4f92452b261eac0d7b70016f7469afdff7a3f5
+CT = 67ab73defe1d9021c3d1f8ab3067ffd9681fcf803af0ed2024dfc096cd8a09d2d81f6146fb54082a
+
+Count = 204
+Adata = 5a2423c2ff2d642c80ac1ca27dd779321f3e9c01
+Payload = 23bf80f51dfd83f63986910e69d54a315c2bfb43f432b7de
+CT = af350d0b1faf8192d171770954c9c5e95b405d6c1135f90b5da82204f4dd8f535cb2fec2f133d882
+
+Count = 205
+Adata = f2c76ef617fa2bfc8a4d6bcbb15fe88436fdc216
+Payload = fc3a50cc8a68778327923ea697f5388da4c814381e29c5e4
+CT = 70b0dd32883a75e7cf65d8a1aae9b755a3a3b217fb2e8b31108630135498ba409f4b6c8caee8a85b
+
+Count = 206
+Adata = b40c8c1d2cee490653105ca2443356cdb63e4fd0
+Payload = 465e41c69928d08c33e063ea119595a04d0de6bffd17bba5
+CT = cad4cc389b7ad2e8db1785ed2c891a784a6640901810f570f89c515837d129ba41f9c24b0229ddcf
+
+Count = 207
+Adata = 6ebfa1e8f80b3cdb1bedf2e3c7e74f30f55c38e1
+Payload = 3f98ee3922f8f1086e3135ae66c5465426b13c8794954880
+CT = b31263c720aaf36c86c6d3a95bd9c98c21da9aa871920655a352fa6b9c4e40733ddcd3fcdaf9ae63
+
+Count = 208
+Adata = 6d0159861031c1a5f01aab35927fe2ab28154d19
+Payload = 5b43067a5ab3a9f9e633fdc084c44ffa7f11edd12ea5873d
+CT = d7c98b8458e1ab9d0ec41bc7b9d8c022787a4bfecba2c9e82c1aa13f062c0f1f5008e27ff2191942
+
+Count = 209
+Adata = 15e5ade017b30ab41878a2747e93aa91c61c2908
+Payload = e40b7e9e46e339e64891526e730b3bf6562fa37acefce307
+CT = 6881f36044b13b82a066b4694e17b42e514405552bfbadd2e149dd02bc7face0c4dfe4e501c2ac2a
+
+[Alen = 21]
+
+Key = be1ed49e2cb0caf6b6a0940c58453b93
+Nonce = b78ad129457681fa7346435b97
+
+Count = 210
+Adata = 161d92c7df1ebb0924719e066e08b95eb4914a5eda
+Payload = a9eec383f63892521e4616fcbadc5485942ffaf4669c43a7
+CT = 949be340720c4fdc4adc05cb777dd81a2549628d33fba07e62d2b338a7b34ebd9d85c244c952d681
+
+Count = 211
+Adata = 6b1d94bc0c6e45fc905c509ea667853e4b2c5a8848
+Payload = 7b44a093162bfc8b4d65f1031d890a6b08a3705b142c0c26
+CT = 46318050921f210519ffe234d02886f4b9c5e822414befff8a4defafeb3d61dad8c007b68d8fb9b3
+
+Count = 212
+Adata = 868dd3e241f60f097a7a2fe571307ee5eb961218ca
+Payload = 28c4d6de3e2ce51b849b135d9cfd3084f0e3155447cad9d5
+CT = 15b1f61dba183895d001006a515cbc1b41858d2d12ad3a0c57cbab553b511d68a4f41db211d0a2fc
+
+Count = 213
+Adata = 3776f37fbf8803bdfd246ffaff2e59658a6c3f0ebb
+Payload = 16d345606a315ad2406abbcb43cd8cabe948107ba6d17a72
+CT = 2ba665a3ee05875c14f0a8fc8e6c0034582e8802f3b699ab0290fd7dbf0afa3e597274e3c9fe170b
+
+Count = 214
+Adata = d0f2769eba9b8e618f00eed6b34c261c59322a253b
+Payload = fcbbcdd9599a86e7c8ccb9347065789a9728ca1220fa51ca
+CT = c1ceed1addae5b699c56aa03bdc4f405264e526b759db2139c7dec3960e6aba3174d793b4e08f449
+
+Count = 215
+Adata = 2be180892faed0bb75887668d187807666d3c66c68
+Payload = 8d145b1f792cc31a2e5b86216609bb018e7aea3012ff70a5
+CT = b0617bdcfd181e947ac19516aba8379e3f1c72494798937c7057b9e2d844e86ee5c3ecfb3270804e
+
+Count = 216
+Adata = 52859849a5b7c1d432c3bfb35271cd8141db2ec774
+Payload = 741db990b43ef34993c33d1c4953b67b128b9299dfe86d74
+CT = 49689953300a2ec7c7592e2b84f23ae4a3ed0ae08a8f8ead1150fa899152eef7a30ae0f20986818e
+
+Count = 217
+Adata = aa192759625f4e42d1d1fa73dc0f62199142155615
+Payload = 51dca5c0f8e5d49596f32d3eb87437bcae866640310ce1e3
+CT = 6ca985037cd1091bc2693e0975d5bb231fe0fe39646b023aba7ff9203608089558698ec29472dda7
+
+Count = 218
+Adata = 6de564226884188ec7bea3894535a875cff2a42fdb
+Payload = dfaa7aa8b28626210d5c24e2ddfe516189be05aabe26f3b2
+CT = e2df5a6b36b2fbaf59c637d5105fddfe38d89dd3eb41106b85bd0a5074ef852575baf5f12c22663e
+
+Count = 219
+Adata = f245f2ee23755df863dee55d7ef0c3c09a0b6f0b0c
+Payload = eedf00aab5edefdd6549d37ed44358e11c588c24f141dc57
+CT = d3aa206931d9325331d3c04919e2d47ead3e145da4263f8e9eb617436bae012331daf020fce24e47
+
+[Alen = 22]
+
+Key = 34ab6fd7f54a2e0276fcb7cf1e203aba
+Nonce = 6091afb62c1a8eed4da5624dd7
+
+Count = 220
+Adata = 1ab5cc3d7b01dc74e6cf838bb565fea3187d33d552a2
+Payload = 8d164f598ea141082b1069776fccd87baf6a2563cbdbc9d1
+CT = 0d30ab07153b5153637969e6bd3539448c541e42b3d432fd7ef14622a9b621d1721b944c60f7fd67
+
+Count = 221
+Adata = 1f1ac4674b272bc7a4ee9f4eae33e969b16fa90a69ba
+Payload = 14e99a2ef0de650adbd785c692342cdb765e6d20d5fca09a
+CT = 94cf7e706b44755193be855740cdcde455605601adf35bb6dfa4ec2c92671c64ee07946527be67f0
+
+Count = 222
+Adata = 43ee77f12ea42e82a02275a68aa95cbd1bb440442bcf
+Payload = 383242c709fe5f2ce782bf8c83b645d171f2bd238abc655d
+CT = b814a69992644f77afebbf1d514fa4ee52cc8602f2b39e71173572fbf3d9495760aae4347397b110
+
+Count = 223
+Adata = ae2ff288199be25bf640811541394ad7e1dd0dc0d24d
+Payload = 9c16a5b638c35c97c5c981c1b8dbcba11aec30e72e45a936
+CT = 1c3041e8a3594ccc8da081506a222a9e39d20bc6564a521a4d2327956e030b9df753e063b5b71201
+
+Count = 224
+Adata = 4ccfb4281852b5ca7e787723d689384a68ff9437db31
+Payload = ec9d8edff25645520801b6e8d14a2fc3b193db70d5e5e878
+CT = 6cbb6a8169cc55094068b67903b3cefc92ade051adea1354e4dac0c9130f5641afd035dd884b6271
+
+Count = 225
+Adata = d3a2fffc798fd9cc2f409471faf18caa2ff3dcf4e652
+Payload = 0db33eda4188a9165147e24e40f79fee1985eb68d5162728
+CT = 8d95da84da12b94d192ee2df920e7ed13abbd049ad19dc0448807dd50a9cf41651083c49c7493ceb
+
+Count = 226
+Adata = 7b5121aa4d1e314f209ffe3e92cd26ee4f74d91e27f2
+Payload = e0d3ea4308376423c4322503f56e427a64e2e6d8b4f5e668
+CT = 60f50e1d93ad74788c5b25922797a34547dcddf9ccfa1d448ea0da53046733f522ded40a09c6d7a6
+
+Count = 227
+Adata = 6e12c112720ef346bbbe7d1c19483721b1c52c438dad
+Payload = 491f2bca585d6b5fdf38d18890e4d1bc923fe26930b3d2f1
+CT = c939cf94c3c77b049751d119421d3083b101d94848bc29dd345cb5a968f39654b994686699d532c2
+
+Count = 228
+Adata = 20433402a2d869c95ac4a070c7a3da838c928a385f89
+Payload = f45908d691ddaf89c0bc129ffada94c3ceda5f47d63ef76a
+CT = 747fec880a47bfd288d5120e282375fcede46466ae310c46cce85eb55339b886b7121b306fccc0b2
+
+Count = 229
+Adata = 42f944c21cc221beaacb288115ac628346b8a1d94bd5
+Payload = e300fc7a5b96806382c35af5b2c2e8e26382751b59010d4b
+CT = 63261824c00c9038caaa5a64603b09dd40bc4e3a210ef667a37ca5ce12aa6f0659467642deb8bfcd
+
+[Alen = 23]
+
+Key = ea96f90fbae12a857f5c97e0cba57943
+Nonce = 21cc46d9ced1539b0ad946e600
+
+Count = 230
+Adata = 105258d2f25f62675aee975cfdb668aff833f05b61eb2a
+Payload = 49db80f22bc267a70e5636dfbc8a21c83d9691fe4b9c3051
+CT = d2fcc8b7809b5fc07e44083e437d8180157f1782a9ce9f65c7fa9ee2e7cdc1b755258f2212a8a8f4
+
+Count = 231
+Adata = 0f5938540651fa4ca03867e67518eb2b73f60dd8750fa0
+Payload = 26618e21099a79d6c517335389551323065ad89c8848ea12
+CT = bd46c664a2c341b1b5050db276a2b36b2eb35ee06a1a4526bfdb9bfcd3b969fb2e41221eb92b0147
+
+Count = 232
+Adata = d6b228960fcbcf07c7bede616139db62b3808718a5b511
+Payload = 4de1d6d57144896ddea1c30f49afecd27bdf4840ed9928b5
+CT = d6c69e90da1db10aaeb3fdeeb6584c9a5336ce3c0fcb8781f8beea22cba93203c912209c78c03aa1
+
+Count = 233
+Adata = 75f8f071e229355e286882917ce5dd4f1db591fee51b6c
+Payload = 785359b1dc754a1e1b6d8731bd2d917ce3e91507401310e8
+CT = e37411f4772c72796b7fb9d042da3134cb00937ba241bfdc69a2e3ea4a40f7c491912c1a0778ebde
+
+Count = 234
+Adata = 4afb62aa8648ac7474dd16fcc376f8909c69e1ce36e6d1
+Payload = ab627aac1496d011ed2edcb2fc6b2afbcc394654f56124f6
+CT = 304532e9bfcfe8769d3ce253039c8ab3e4d0c02817338bc2a75c7ba2a769c27903e99b72639b0841
+
+Count = 235
+Adata = 736fdf94db820a2efe89e7fc9dcfe7c23d5754ac2bcc7c
+Payload = 40722cffb37f1455c2618408e777ed0f4b1bd039952730cc
+CT = db5564ba18262c32b273bae918804d4763f2564577759ff8f84f4ca4a69fde75d7207e50494819b6
+
+Count = 236
+Adata = 8a9a0367137c28db4c4e78d9cd9a68cde0d1b4583532ae
+Payload = dcaabf7a061502618541c09ea59dbbbd52b2692fd0064747
+CT = 478df73fad4c3a06f553fe7f5a6a1bf57a5bef533254e873a0c34a24d3ee0946034c71fba4dbb333
+
+Count = 237
+Adata = 34dbbff560ef04ea731b8979aef2ae50972f4db3efe14a
+Payload = dd641a893b16e0e173ea2eda20638bb01849ac11e64e8ddb
+CT = 464352cc904fd88603f8103bdf942bf830a02a6d041c22ef0f5e24a435a39a716c39f43dabdc4281
+
+Count = 238
+Adata = f3d1fcd912252431db9d8ccfc3e203d5b34d537468b4c6
+Payload = 9aa3e8ad92777dfeb121a646ce2e918d1e12b30754bc0947
+CT = 0184a0e8392e4599c13398a731d931c536fb357bb6eea673f623d59f66764d859a772bb50ec91fc3
+
+Count = 239
+Adata = 513b4cdc551c203ed5f1e659813584862023911590b672
+Payload = c8f44ae4b02fffdbce0df773c24075f877945fc7a86be460
+CT = 53d302a11b76c7bcbe1fc9923db7d5b05f7dd9bb4a394b543b6549eb16fba96318afb3df51f4675f
+
+[Alen = 24]
+
+Key = 35b403a15212097085d6e2b77ec3d4f2
+Nonce = daa423bf9256c3fcc347a293aa
+
+Count = 240
+Adata = d3c0ed74e5f25e4c1e479e1a51182bb018698ec267269149
+Payload = 7dd7396db6613eb80909a3b8c0029b624912aabedda0659b
+CT = 5b00cf8a66baa7fe22502ed6f4861af71fa64b550d643f95eee82c19ecba34280604b58d92dacd3f
+
+Count = 241
+Adata = 62f4fe53e99a9b0c51e9561d910d7e2ffe19a5176c9dec06
+Payload = 897f0dfd90213f64a9277a0eda4f134f303fa89f56ca54fb
+CT = afa8fb1a40faa622827ef760eecb92da668b4974860e0ef5ab4999e9689d52b8afeb87923efa3b48
+
+Count = 242
+Adata = 191c4dfa653c20292657f7694c6b6a4a410c49a879abd217
+Payload = 2b7cf9e6e2d6abcd7775f8a6eb6294e822041c4c45f09c3c
+CT = 0dab0f01320d328b5c2c75c8dfe6157d74b0fda79534c632cdc71e556c34fd4e1b5ebc50d38da8b3
+
+Count = 243
+Adata = ba34741f8edb51470eb20f891869aabeab562d92571ac943
+Payload = dccb9a4625512496b372a2b8b768f75741d8c2e30e57d638
+CT = fa1c6ca1f58abdd0982b2fd683ec76c2176c2308de938c3646223d381090661c2ee2370d29a572a9
+
+Count = 244
+Adata = 8b922aca6125722ec490b134a45864397f4e2c281d6e2089
+Payload = e0e452c990665465160b02cad6367ca89723613488d8efbf
+CT = c633a42e40bdcd233d528fa4e2b2fd3dc19780df581cb5b1f78af50466646b7c7e652f787afe5357
+
+Count = 245
+Adata = afb9fd78e3f8eaf4e8c91da62b2da534508e54f7dfa214fc
+Payload = b536fdb8839f87080ae65ec35da347e792622ffe18a61d46
+CT = 93e10b5f53441e4e21bfd3ad6927c672c4d6ce15c8624748cc9d9a1270f78648a6b66cb8c0f2471b
+
+Count = 246
+Adata = ecf942ccee7396cb3ee177eadd4d96a4af1d90afdce97376
+Payload = c81233826e5125e1f31fe275184ccba8f1a743e58e146e4d
+CT = eec5c565be8abca7d8466f1b2cc84a3da713a20e5ed03443b17d3d6f1fc4f530841b749d9f3a0a7a
+
+Count = 247
+Adata = 16fea92ffcaad563792aa924bffe7ef690edc90ea4e29cc0
+Payload = 24ab253b5b06552665c3c810254c0ed15e68a783180d7eee
+CT = 027cd3dc8bddcc604e9a457e11c88f4408dc4668c8c924e05852ed48cf88d9ab2326aa46b6541b60
+
+Count = 248
+Adata = 76f110eecd369d79e21fb208058359d3a2f37581d1f7f691
+Payload = 7f596bc7a815d103ed9f6dc428b60e72aeadcb9382ccde4a
+CT = 598e9d2078ce4845c6c6e0aa1c328fe7f8192a7852088444c62dff6bcade5ac2edb8ec9797ce433e
+
+Count = 249
+Adata = 8834c776a3237f060ae0ab9857324a3b2ac79f3b6e6f90f5
+Payload = 11cbfb3d348c7abef99f562607e289de34a2bb379a5dfe50
+CT = 371c0ddae457e3f8d2c6db483366084b62165adc4a99a45eb936ac4764575f85352c24ab23209d42
+
+[Alen = 25]
+
+Key = 7a459aadb48f1a528edae71fcf698b84
+Nonce = fa4616b715ea898772b0e89dd4
+
+Count = 250
+Adata = 0c0b4a45df5c3919c1e1669c5af5d398d9545e44307d95c481
+Payload = 0b3d947de8632dc8ff752f619ba7c84716fac7a23e101641
+CT = 7db9f3f7dc26fc2adf58d4525d26d5601e977de5a7c33911a1138cff7b624f9908b5b4d7e90a824a
+
+Count = 251
+Adata = aa27a28a36b5a2cee57ffeca0233feb4bdd4eacb2cae28e98f
+Payload = e6dedce2c278c44e5678d13e7d5b5d3501d61bb0bb6b5558
+CT = 905abb68f63d15ac76552a0dbbda401209bba1f722b87a08e23f92b598f7a248a894e6b8f5691bee
+
+Count = 252
+Adata = 66220aa9b40a1772caba7749a544bff938e804dbc6e556498f
+Payload = a276b0922fbd5094bf89b9329d07341e039d6204397b81c0
+CT = d4f2d7181bf881769fa442015b8629390bf0d843a0a8ae90e94043c0d80fd651469232fe9d47a81f
+
+Count = 253
+Adata = 3d765d20e03a4cebfda50316c4b7d8b6c55078d5b3e9cbc567
+Payload = b99afbc2dbb377350cc58d4bfe8e954cef25d7b27b82fad4
+CT = cf1e9c48eff6a6d72ce87678380f886be7486df5e251d58425088b522fc0731097e729448236b317
+
+Count = 254
+Adata = e91b6265879153e1692b00a112b4205111c8eb1a7b7f2c6898
+Payload = 56114cc783b80ca2dd2881387b6d92a59a237dfc8e976d8b
+CT = 20952b4db7fddd40fd057a0bbdec8f82924ec7bb174442db2208cf07574cc4f3f83ed6301b904404
+
+Count = 255
+Adata = 340b16f352817babb4fb70e9e6e18784b3e67bdd449872158c
+Payload = eb21fe20fc4f92452b261eac0d7b70016f7469afdff7a3f5
+CT = 9da599aac80a43a70b0be59fcbfa6d266719d3e846248ca514b0a900068e55cd24c92bbb78c521ad
+
+Count = 256
+Adata = 5a2423c2ff2d642c80ac1ca27dd779321f3e9c01445be684dc
+Payload = b15083a73607c9d7e197a8cc884ad3be98ac343f6493df67
+CT = c7d4e42d02421835c1ba53ff4ecbce9990c18e78fd40f0373f8ba66d74321c80c057f010078d2f28
+
+Count = 257
+Adata = 5fe8bb27a59a5f4e370adbba96484c2365fc0d8c6e58d7d3e6
+Payload = 07542d18e8f2d3e199fca0f90cabb78b169525fdce81666a
+CT = 71d04a92dcb70203b9d15bcaca2aaaac1ef89fba5752493a0a189319e4f06d53c1405d37b06cc8eb
+
+Count = 258
+Adata = 23e5422e8d7560a9e65642b5e723a47536c16791f3a0cf918d
+Payload = cd574ed56bdfd1408f7831e0b24b4345ee979ac906a7aa22
+CT = bbd3295f5f9a00a2af55cad374ca5e62e6fa208e9f748572dd72f48ae03670249d74f8460b63b1ae
+
+Count = 259
+Adata = fcc9422ba5023a9997baa9c4ee6cb196ffe96e08eb9c2b8a75
+Payload = 8c9abe94beed4c9bd46adb1d04fbfe7016dd50d324525abb
+CT = fa1ed91e8aa89d79f447202ec27ae3571eb0ea94bd8175eb1717c00c93d36a77141b723d573c8c65
+
+[Alen = 26]
+
+Key = ca748225057f735f712ecc64791367f0
+Nonce = 1341a6998eb1f50d4b710a13ac
+
+Count = 260
+Adata = 5fb96b045f494808c02014f06074bd45b8a8ad12b4cb448ec162
+Payload = e92cd0cb97afe4fb00c4f12e9b9abe1d08db98f49a27f461
+CT = 82b666694232e86e82295beae66ae67d56aceb5d6b1484ceb4a6843ec16078038c10afedc41f5362
+
+Count = 261
+Adata = 87db0d9d69bc0cf69cabeb92570e482bbc8ff3e1ba72f12f3225
+Payload = a6dbad96ad23ff61479df39b99f0673a09f2a7eaebbd34b9
+CT = cd411b3478bef3f4c570595fe4003f5a5785d4431a8e4416a7c6566d0b8ff97f946d7c7773a845f2
+
+Count = 262
+Adata = a061a09024f1e03b223695d4703ee202e90e07156b95859a22e3
+Payload = b1dd81cc3b2b0efe540a3194d6fe304cd2de53db7929ebe1
+CT = da47376eeeb6026bd6e79b50ab0e682c8ca92072881a9b4ee1d66a4728b67b42602e23c8500b0115
+
+Count = 263
+Adata = 0dd513c5d8d62b723ab8b0a3aaa477e843d9149dc8a2f878e585
+Payload = fb30c2e98f3d7e4ed7431da285711d3d287884db13a474e7
+CT = 90aa744b5aa072db55aeb766f881455d760ff772e297044803c51e8c59ed13b3e5d9b489d4ea2ccf
+
+Count = 264
+Adata = 3ff59c40bd796048e586eccc23a82e4d09fc5e779f38eb4afbed
+Payload = 886f9f91a6566ceb99c39462ab675a3ae3be98f68787626f
+CT = e3f5293373cb607e1b2e3ea6d697025abdc9eb5f76b412c0f1ec270b43fc5a9811b56ccf033789c6
+
+Count = 265
+Adata = 0df7ef91f7124da867e992bcbc6fb38232ff6d5205f38768da72
+Payload = ed370d1c2d6dc03e4fae4deb9343a7d4339562cffd427587
+CT = 86adbbbef8f0ccabcd43e72feeb3ffb46de211660c710528bb4ed25940d58cba64271fe1d2e8013d
+
+Count = 266
+Adata = 6777de159c34d005b94f67c33ae4a35ebab09d9cb9c56b4c9c81
+Payload = 2f77c2eb07db14bd713c5af10c0760ea3a6ca5ff8d046d36
+CT = 44ed7449d2461828f3d1f03571f7388a641bd6567c371d99392636a5e373c1354ea9b969abb4932a
+
+Count = 267
+Adata = 75559898f4ba03c55afc25ea91aa61a93c2f8270a5fa51b6f6dc
+Payload = 360fb89429dc9b48358097d930c8561b2bd18dc0a470d1d6
+CT = 5d950e36fc4197ddb76d3d1d4d380e7b75a6fe695543a17959a7e8bc0570f19159f91fc14ac6532a
+
+Count = 268
+Adata = 5e03fc430473c5de96d68907fa506f9da353ae48a965445e1f24
+Payload = f2d8d67b9f291c3edc264893922622b2693f3e7231137eba
+CT = 994260d94ab410ab5ecbe257efd67ad237484ddbc0200e1507e559568c27a30b5676f98cc66f57d6
+
+Count = 269
+Adata = 7eee4869e77f6db12c91d1f647cad2340d33a3defaeb362d311d
+Payload = 7fd6fb81c36e44b150af10e04683b1ec9b5dda87c71ff939
+CT = 144c4d2316f34824d242ba243b73e98cc52aa92e362c89964910615920f6f3c3421a9c2bec1bec7e
+
+[Alen = 27]
+
+Key = fdf2b2c7fcb3789b4e90abe607dca2af
+Nonce = a69ddc66e63a3415f21009d53a
+
+Count = 270
+Adata = c76846da496ed87b9c0f65c6266c9a822224acde9775efb186a4a5
+Payload = d7aa4efa5d75195a400018bd38f7d8cd53fdffe88df1837f
+CT = 150d9a8b78d9c04239d66207a1f95021bbb1b7c70d7c354825d05e5a2e76a90f6fe489fd74cab2a3
+
+Count = 271
+Adata = 4efbd225553b541c3f53cabe8a1ac03845b0e846c8616b3ea2cc7d
+Payload = 5f94a2e48d348a1d56c55a659306e319c3d2ad78b9fe43a7
+CT = 9d337695a89853052f1320df0a086bf52b9ee5573973f590be6af49ce97d5e0e77c7fd5d9cc6d932
+
+Count = 272
+Adata = 7631cf7822a545daefa16a5ec43c877d475a82d5aa2d51cec7fbb4
+Payload = a44b010fc1c659eac9241a58b11a73d7ce33156ddfc54c3c
+CT = 66ecd57ee46a80f2b0f260e22814fb3b267f5d425f48fa0b924b268cab915f999aea3e1cc3a88ccd
+
+Count = 273
+Adata = e4da34663edc44370bfd8aa8315945471a893a1cc069628a071ee0
+Payload = 28d157f5741f1be057d5219711414c0638b47d165a905a6a
+CT = ea76838451b3c2f82e035b2d884fc4ead0f83539da1dec5dc368f5af8e311e67209e02dfa2613377
+
+Count = 274
+Adata = 077509eae1dc367540f87832c5780f6c5b29e180bc6c1fee38e826
+Payload = ba7432a8e34bfaa91b35c8dfd822d86850be39e63150257f
+CT = 78d3e6d9c6e723b162e3b265412c5084b8f271c9b1dd9348ad175fcad35d29396380b79a28784cff
+
+Count = 275
+Adata = a513d750ca1e8bf6cb7b8cea5204e064c15c2dc40d742b31cf5459
+Payload = 3f5830b0ce8849a660af7d58a60c19a9824a3033bb5fed43
+CT = fdffe4c1eb2490be197907e23f0291456a06781c3bd25b7493b4b3e33d325359c9c651290ce73bed
+
+Count = 276
+Adata = e439db829c1291df49fc42c2fa1a92118c2665f11e13f28dc6f11a
+Payload = e69b2a243340df5dc70b2cb05be12e5992ee36f7d9f4ca84
+CT = 243cfe5516ec0645bedd560ac2efa6b57aa27ed859797cb371f88ca5857c6d801e726a01c621a0c3
+
+Count = 277
+Adata = a12c690568114fd7a677f49d74e84fc1a6b7f7d2a08693266c0a91
+Payload = 9de35b840a69a84701ffae1b1d2bf13c34b42a57d14c524d
+CT = 5f448ff52fc5715f7829d4a1842579d0dcf8627851c1e47a0592d360fc6a46aa18c4ce5d74fa4532
+
+Count = 278
+Adata = 1813bf176a1127f4d508d7663ae750f9c4bcb84a6e26811ac60d46
+Payload = 9e2fa20bf76768a5a1467d90a048bb503a2c33bbbaa71653
+CT = 5c88767ad2cbb1bdd890072a394633bcd2607b943a2aa0648b772cef893495cf0a94e8ebf06e920b
+
+Count = 279
+Adata = cc6e9cc2699d3ba0e624e715599480d6b7dbc6eeea0d12a9236444
+Payload = 6681b1cbeceea57a828324831407280b00f4917ed52a10df
+CT = a42665bac9427c62fb555e398d09a0e7e8b8d95155a7a6e8b1851d571a1ef8aed565b784dcaaac4e
+
+[Alen = 28]
+
+Key = 7d870d7e52d3053c65eefad47764cfeb
+Nonce = 37d888f4aa452d7bf217f5a529
+
+Count = 280
+Adata = 9610949f6d23d5b1f3989b2f4e524fab4f297a5bec8ddad4f16cb616
+Payload = 109317556c21c969eda65a94176d7a11462c9ae18a865b6d
+CT = 4e6b967b1571c6d7b9e118b112b7ac949a4a175650316a242dd579cb0d201d22c86bbc7fbe47bd0d
+
+Count = 281
+Adata = 96118dbfe53434d8aed88769a535eb0c8b5849dca1c81c34626ac9b9
+Payload = 3e6c914a196e175079315b1c92b2b8a844deb472e249e3d3
+CT = 60941064603e18ee2d76193997686e2d98b839c538fed29af0dd7aef4a609f3587652173446ebd82
+
+Count = 282
+Adata = 21fc96f73975298207f818909088295d6d6861677130ca258c2174f6
+Payload = e0014147d5771b4380dc0192d45f36f7d60776d1ba47374d
+CT = bef9c069ac2714fdd49b43b7d185e0720a61fb6660f0060463e4405d45caf4836467edbf35089d87
+
+Count = 283
+Adata = 72a5151abcb55933ff7c9314f3235eba2a400121454144c2670e8359
+Payload = 0f1c6dffeda98f7a159f9cc61820bfb29910d8eaa41b751a
+CT = 51e4ecd194f980c441d8dee31dfa69374576555d7eac44537441c813e90fac775eddb7290df059d9
+
+Count = 284
+Adata = dbbf192914b1ad73666e9f5e9c22c08ca398f7524af62b1046a863bd
+Payload = c1ddd14e380cc91324cf2a381df1da1ccffd90ae436a373a
+CT = 9f255060415cc6ad7088681d182b0c99139b1d1999dd067334d9316f1f1c3142c1c9b26e5c220a32
+
+Count = 285
+Adata = 28e4b88fbf04e9897057ff5bfde7eb04fa480256817a50fa281030b4
+Payload = d4dae9c4cae92afb80f9a5c99383ff16e23a2ec942eed4d2
+CT = 8a2268eab3b92545d4bee7ec965929933e5ca37e9859e59bc0b188e33bfab29b237d6c6920ce3418
+
+Count = 286
+Adata = d9ebc1cbfab9034317132a72e0f11c341331146a59e7a2f26bf4f3d7
+Payload = 8a188d40a6e6fbb06a9f06304349a7a808b092cc2fc10b9e
+CT = d4e00c6edfb6f40e3ed844154693712dd4d61f7bf5763ad7fdde04d21b876468bd9184101b5f32d0
+
+Count = 287
+Adata = 34ad69f192ae4dcab771aeeacf01bbd32609bcbbea8ff9df31ded719
+Payload = 590c1aac30ab166b1caff748452fc146765c372e226ffc26
+CT = 07f49b8249fb19d548e8b56d40f517c3aa3aba99f8d8cd6f068c65e9d0e5f1b81c86393900e64c19
+
+Count = 288
+Adata = f5e50ce1f99ed5e9f2baa54b96ae7039234b1131e734ec190695d28d
+Payload = 16d0522b2e691e42bd80ce95e00c8a7a1fc738169e904bdb
+CT = 4828d305573911fce9c78cb0e5d65cffc3a1b5a144277a9206ab3b72c56c8df4a12dba89a2f21276
+
+Count = 289
+Adata = 9b1e7e52ea1a12444d884866e11dcf367b70b816460936fdaebba36d
+Payload = 0bddf342121b82f906368b0d7b04df1c682ecd4c2b2b43df
+CT = 5525726c6b4b8d475271c9287ede0999b44840fbf19c72960170ca7b16d23537eeb3034105334699
+
+[Alen = 29]
+
+Key = 8fcac40527c0e7ca8eaff265ca12c053
+Nonce = ae9f012fd9af60a400e20b1690
+
+Count = 290
+Adata = 9ce65598cd1f86afc9aaaf172809570cc306333c25523f863c6d0e0154
+Payload = 78d1e96af8cebdcc7e7e2a4ddcfa34f6cf9a24fb85672ad7
+CT = 9adb9a95a9379ad795d8d3ffd4e37a045160d6d727f974a6cb3b5151f327e65447e52c7525562c91
+
+Count = 291
+Adata = e7c78ef4c4b959ee00cb1a09d71221a43892ef8ad705edd27ed85d03a3
+Payload = bc59f18c8473941abc681a92741ab5ee13679829f542b8f4
+CT = 5e538273d58ab30157cee3207c03fb1c8d9d6a0557dce68534e5b08e27d8f5eeef0f064ff620652a
+
+Count = 292
+Adata = f1bce6f2a4bdd3a07ebf5f8d47f931d27e7e63389d70e1059f701216be
+Payload = 5575d950312c14c89ac609dfb0b2fd1af732bb6aae5e8651
+CT = b77faaaf60d533d37160f06db8abb3e869c849460cc0d82044c0a96baae318f4714f0206812516b5
+
+Count = 293
+Adata = 3da3bb091016e54477dae88af1c84c1a51b59c1bb49a05deb6f32064e6
+Payload = df5947d8c6094ccc25816639ec42214b28731bfd7b8312dc
+CT = 3d53342797f06bd7ce279f8be45b6fb9b689e9d1d91d4cad4e7bdce2dc6aae24178aab6984f31028
+
+Count = 294
+Adata = c4cd183071c37a8157c6930a7d4d530cf4b7eb021682327810bd48209e
+Payload = 2fbb6dc235761875411ef59ae06110df8f15f66b721b0fd6
+CT = cdb11e3d648f3f6eaab80c28e8785e2d11ef0447d08551a7f18ece8260bd56ecdee768022d0dd8d1
+
+Count = 295
+Adata = 0e0fece7b6b659b642668e8ba3dca330523e70279155f485f3f6f8041e
+Payload = cd149d17dba7ec50000b8c5390d114697fafb61025301f4e
+CT = 2f1eeee88a5ecb4bebad75e198c85a9be155443c87ae413f6f0fb3b7440b84ddc3cc53819c2e93be
+
+Count = 296
+Adata = a35c6f70f637a9a5e6f215c694fdf65b6fd85f794ed3eaa1bc19abe592
+Payload = 030390adb572f2bd2a6a4454fd68236cd1d465574328aa00
+CT = e109e352e48bd5a6c1ccbde6f5716d9e4f2e977be1b6f47129ca778c51f9320f121dd803ece8d5da
+
+Count = 297
+Adata = c2992096828325820e2d7acaa17ac789b6830ec3128dd7f904398afbec
+Payload = f2d9cf953c8d3a051d9b3eae4307a3cb4fffaa2435b49586
+CT = 10d3bc6a6d741d1ef63dc71c4b1eed39d1055808972acbf79c223a5ad65120bfca4a5992e5ebc6fc
+
+Count = 298
+Adata = c023763a285ea934bc5bc7ddfc2aefe2b3f9eafe7b87c61383dcc07990
+Payload = 4b92e8d2ffaa4af8f3e0ac037a900bd18e195f490a3d71e1
+CT = a9989b2dae536de3184655b17289452310e3ad65a8a32f905c3bc4f618ffb3a159f4e2d0622cea6e
+
+Count = 299
+Adata = 0a39ec0163c7aeb1b4fbe7cb4fa5b0592fade70f430e23730a23ed4160
+Payload = 7c0e6a0d35f8ac854c7245ebc73693731bbbc3e6fab64446
+CT = 9e0419f264018b9ea7d4bc59cf2fdd81854131ca58281a376f099dce6e18435fba4d26c1e93bda0c
+
+[Alen = 30]
+
+Key = ddf9f150cc3f1c15e8e773663c5b061c
+Nonce = 98c5036b7d54da9a1177105600
+
+Count = 300
+Adata = 20c5ab290e6d97f53c74121951f39ba865b3acc465fa3f0fb8a591622277
+Payload = 79d8841ab83279724ce35e1a8abd4e158168dcf388ab4c3d
+CT = d00d29396ffa9e691290d746527777bf96a851f306d4da0b1816df1e0e82bb7bc8105930ad6a2232
+
+Count = 301
+Adata = 0e205a4dc5d5ead0d9ff7f182dc140fc49511c01b0fdbc7e6d6cb5fdf027
+Payload = 88b2572fbe7cf2b46df04db476ffedb41778ae2eb3c3aae4
+CT = 2167fa0c69b415af3383c4e8ae35d41e00b8232e3dbc3cd2df823c8ccd466807f2bd1c4032f0cfeb
+
+Count = 302
+Adata = 48043560d60381e83c11d4bc9d997d3ee2add6b0524b779c62dfaa73ce0a
+Payload = d44bf28b010e076b45db1b053af03db718b60748da51db1f
+CT = 7d9e5fa8d6c6e0701ba89259e23a041d0f768a48542e4d2931f5be8c9965345c760c72cc1b7908d1
+
+Count = 303
+Adata = f0729a8a2fd073699ab87b521cbe0420b43529556a505f5f87874d1a053c
+Payload = eab8cffb512eabe267cd64353552513defe97c2d10f35503
+CT = 436d62d886e64cf939beed69ed986897f829f12d9e8cc335381d94a828a95872ebdfda8a4c6a196b
+
+Count = 304
+Adata = fc2cd69bb61223f713e33a5071d09bf2783640c307c22d836dd94952dd37
+Payload = 001056926546c261fbbdf92b94498e038c2bcfd0b6345497
+CT = a9c5fbb1b28e257aa5ce70774c83b7a99beb42d0384bc2a163931808533f4f70d7a78242ced110eb
+
+Count = 305
+Adata = 8f653c5c003c807d16d17f833eebb97c9c2f0e5aae3780a52ce53a6c33f7
+Payload = 29ffaef9415fd300127ffd26ef324083a9d90e0f60e2ab4f
+CT = 802a03da9697341b4c0c747a37f87929be19830fee9d3d79f34553198f8e40fde6473f9cf04f1de6
+
+Count = 306
+Adata = 8d05e7d3077151c6d9378cb08e049e4d7c28a908f7f7c079c46ff92cd01b
+Payload = 9874dc5ca1b541f7b21c7b3860fa6b0c3ab1b712ab0fca98
+CT = 31a1717f767da6ecec6ff264b83052a62d713a1225705cae0fac20e8d45d2b0771d140b5e4a47c87
+
+Count = 307
+Adata = d4feb3ea76ac2945651f557406f3f38a2d7e9232ed55ff4eaf1201dd8255
+Payload = 1e01c7128c821fb9c971a27fc7c6f9bb902fa735de583b8a
+CT = b7d46a315b4af8a297022b231f0cc01187ef2a355027adbcd3cacfe4281e52d79e60eeb38319bc3a
+
+Count = 308
+Adata = 7cbb4ae995a3367a256cafd11cd6c6cab5bf3252fa97f27a8a1434ca9a27
+Payload = 51cd306fac7d20e3c7043eae3a6dfec046c5c24a666a0723
+CT = f8189d4c7bb5c7f89977b7f2e2a7c76a51054f4ae81591158f0d7646a799b14288bb2f354b5d8847
+
+Count = 309
+Adata = bd40b06a4beded2be3d176266b10772c7fa2949f0a9b20d613af90c2daf5
+Payload = fc5b26befc633a3e8ace011aa7a42bd0258a9f3dc14fc1c8
+CT = 558e8b9d2babdd25d4bd88467f6e127a324a123d4f3057fefd7f95e1d331e700aa9ef83f09b689fd
+
+[Alen = 31]
+
+Key = b1dc81d116d94f5eced526b37c004b95
+Nonce = 97c8f69fb91b17299461fd8d63
+
+Count = 310
+Adata = f8b08aa83bed09ca342249b2cf9e2b45a89dcfb8711a120395e455921af481
+Payload = 54390715b6e7c7bd51a234db059a51ba030cf22ee00b7277
+CT = cb629994c3418a662a8cde1b5f4d99aa7df66e24c53dc6df11297930fd44c63675b7cca70671ef4d
+
+Count = 311
+Adata = 0351c969dd38eeaa4b9b0000e346eeb1a2cd462033c59d9e6e3331822045cd
+Payload = 65b5e856a8cf35dffd42c5ba105cba4c434aa1c2a0390352
+CT = faee76d7dd697804866c2f7a4a8b725c3db03dc8850fb7fa7e77f5566ca2fd9293835bceb461dbaa
+
+Count = 312
+Adata = 5db8b6bc16740680f78fba917733a6899cdba5e4c10a8058963d1265681eaa
+Payload = 9a7685e3daac43ccf22cad0df900ba8acddc5d420846118d
+CT = 052d1b62af0a0e17890247cda3d7729ab326c1482d70a525ec2cf9f5d35521c1c000685e49d2ed42
+
+Count = 313
+Adata = e7d6024611210da0cfb90a9955195aa0a0539280a3a7c792a1540930daae2d
+Payload = c18d9e7971e2ae5fc128777086338fbe194443324e2d2cd1
+CT = 5ed600f80444e384ba069db0dce447ae67bedf386b1b987966f33dfb44ae413283b238616c6b99fb
+
+Count = 314
+Adata = 77a878c9c76f3e6a4ddd330d1d8828949d08e0fedffe0d8e2e557b29e7c78c
+Payload = fcf8982f7342f1b953658453cd5ea413700eff00f1ee7d6f
+CT = 63a306ae06e4bc62284b6e9397896c030ef4630ad4d8c9c731df6fc6b4cf0b6332936ed7cfe9455e
+
+Count = 315
+Adata = aa540554ee80dbffa475f702d862d6b60e0a4090792420a26d02926517723e
+Payload = 0d5690d2a7083ad6daf22b308314b8f5363aca77ca72835e
+CT = 920d0e53d2ae770da1dcc1f0d9c370e548c0567def4437f67c8162a815f2809601ad02595e2e0ff4
+
+Count = 316
+Adata = fae86f95dd06fb7fbae63a646615555aec8153dc328bdf79da5d4cc9677ed6
+Payload = f6e313cc35e8f8812b10a44f8ad00b6893f8084d942effe0
+CT = 69b88d4d404eb55a503e4e8fd007c378ed029447b1184b487fcaa11bdeab86f60f9cd0a2b45cee1a
+
+Count = 317
+Adata = fd525302d2fb246a47cf4e3a27808bda89d8488cf450f1a1c7df6eedd810ee
+Payload = 91e961ea2eb750577c5137c609602dbfcc4c07955ba429ec
+CT = 0eb2ff6b5b111d8c077fdd0653b7e5afb2b69b9f7e929d440a86a810881bd969744ad80f579400f1
+
+Count = 318
+Adata = 767b1bdf9793a512d3a84e99ef77b43011a3bcb8de4cd375dfe47a79293e01
+Payload = 98438c4411bead6f30c89ead762a12bf39391d3652b78b7a
+CT = 071812c56418e0b44be6746d2cfddaaf47c3813c77813fd2250ca00d3231819ecdf501ad39c864f3
+
+Count = 319
+Adata = aac7014f606df6feec415a75e29015891007f07518c955875fbf5619262ff2
+Payload = 540cb00c0eface3d1b2d632d80a642f53c78ff672a1ff6ff
+CT = cb572e8d7b5c83e6600389edda718ae54282636d0f2942571224d1d0294d46981d7dc39114a693d2
+
+[Alen = 32]
+
+Key = 5a33980e71e7d67fd6cf171454dc96e5
+Nonce = 33ae68ebb8010c6b3da6b9cb29
+
+Count = 320
+Adata = eca622a37570df619e10ebb18bebadb2f2b49c4d2b2ff715873bb672e30fc0ff
+Payload = a34dfa24847c365291ce1b54bcf8d9a75d861e5133cc3a74
+CT = 7a60fa7ee8859e283cce378fb6b95522ab8b70efcdb0265f7c4b4fa597666b86dd1353e400f28864
+
+Count = 321
+Adata = 55a62968c222a8501d1ae56a9a815667f8a9554607b7c56e6753f8fa92a4d054
+Payload = 764dbefb42644d18d23e5e4568685d14dbacfa418d36c4ef
+CT = af60bea12e9de5627f3e729e6229d1912da194ff734ad8c4423862a715dda2f63a4197f894515803
+
+Count = 322
+Adata = f8436e35b7a1c810ac6aabe8e2d48a3678d19e1e96337dada514ee5fc075fce4
+Payload = cecef24b62676a5623bedae8087b9b05d7e22b41a14dd2d5
+CT = 17e3f2110e9ec22c8ebef633023a178021ef45ff5f31cefec200f190bd700f6108f9959f6d12f0f0
+
+Count = 323
+Adata = 548e2152f3a15b8fb81dc01062d99f7b4fc8f074e5cbdc1030c97f8ccc02ec3f
+Payload = 53c164a4990c6e0637267ff2556c1542712fc584f6ff7458
+CT = 8aec64fef5f5c67c9a2653295f2d99c78722ab3a088368733a66ebc4e0777a6fc140a51e04a10f86
+
+Count = 324
+Adata = d100f1d08ef1e3eda4aef22cd970c2b785c4ff9b523c401b4064324aecf7f2d9
+Payload = 15681d2121ac56a63b9d0a38b9c4eccf84fdb746d32c14b4
+CT = cc451d7b4d55fedc969d26e3b385604a72f0d9f82d50089fb810cdc08db0a9966dffeb43ba26446e
+
+Count = 325
+Adata = eece934a807c9f21487cd810f15fd55d7bb4421882333ff2c43b0353de7fc5a6
+Payload = 412a8ef924ca156de860f147575e5731825f0a3759688928
+CT = 98078ea34833bd174560dd9c5d1fdbb474526489a7149503cfc5b397578f8d02a0b936ffac29b99a
+
+Count = 326
+Adata = 86311ff444d9be90459b6ee3652e1705ed0b5cdac3d27293ddea3378fb686ee5
+Payload = 54ba8a020d0876fa369dc32e8627f565ba3dda862ea0bcfe
+CT = 8d978a5861f1de809b9deff58c6679e04c30b438d0dca0d52c3fcd6d618c260d51724126f257534a
+
+Count = 327
+Adata = ab6efbc44a8906d5c067eaed71af467e130aaf170827a58beb03c55069674125
+Payload = 7a15506fd1dae444d77b2a3ae7b57a8d5b4f10e25a9f78e2
+CT = a3385035bd234c3e7a7b06e1edf4f608ad427e5ca4e364c9bf8b2821920640b992b00cd1c9618025
+
+Count = 328
+Adata = ddb640923d083725587aced81ae1d7409983d1f1e3ccc8dcf94376dc1bbcae8b
+Payload = b18a61a89cd698f32e059b7a2a9f62a46be2c248790a9915
+CT = 68a761f2f02f30898305b7a120deee219defacf68776853e4cd52d41a968284af8907ccbb4588cc0
+
+Count = 329
+Adata = d95ec4a6f594be1ba39fa1aa933dc0a5dafff5ce44509577ebb3a3e8084c4401
+Payload = 16ee3bc9ec8b4448e292b8973618e02a99da1c348539d5c7
+CT = cfc33b938072ec324f92944c3c596caf6fd7728a7b45c9ec47449a5cb4943ff2846c589b7c98ef49
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VADT192.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VADT192.rsp
new file mode 100644
index 0000000000..1a7a5875fe
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VADT192.rsp
@@ -0,0 +1,1823 @@
+# CAVS 11.0
+# "CCM-VADT" information
+# AES Keylen: 192
+# Generated on Tue Mar 15 08:09:25 2011
+
+Plen = 24
+Nlen = 13
+Tlen = 16
+
+[Alen = 0]
+
+Key = 26511fb51fcfa75cb4b44da75a6e5a0eb8d9c8f3b906f886
+Nonce = 15b369889699b6de1fa3ee73e5
+
+Count = 0
+Adata = 00
+Payload = 39f08a2af1d8da6212550639b91fb2573e39a8eb5d801de8
+CT = 6342b8700edec97a960eb16e7cb1eb4412fb4e263ddd2206b090155d34a76c8324e5550c3ef426ed
+
+Count = 1
+Adata = 00
+Payload = 296fbda0017351491c2187273fbde2c3a427170e430a703c
+CT = 73dd8ffafe754251987a3070fa13bbd088e5f1c323574fd2167ee33e75d05023a7d63c770cfef2ea
+
+Count = 2
+Adata = 00
+Payload = eb61c284fe009921039ef6a9ce50e702823e44b35357923f
+CT = b1d3f0de01068a3987c541fe0bfebe11aefca27e330aadd170647420f79c0d91cbbd69b806fe96a5
+
+Count = 3
+Adata = 00
+Payload = ffeccc6460d23fdcc387c697e75dbb959b78013a8282eaa4
+CT = a55efe3e9fd42cc447dc71c022f3e286b7bae7f7e2dfd54a8a3ef2324754539ac774872282534386
+
+Count = 4
+Adata = 00
+Payload = 90958d7f458d98c48cbb464c74bf495a49846dd468c514e9
+CT = ca27bf25ba8b8bdc08e0f11bb111104965468b1908982b07e292cd0e32535a848e327bc53cdae94c
+
+Count = 5
+Adata = 00
+Payload = a4fad5205d38206e25097075687ca86032b95b3fe7e82a07
+CT = fe48e77aa23e3376a152c722add2f1731e7bbdf287b515e9bb21701af36936be5f62d02b84df87c3
+
+Count = 6
+Adata = 00
+Payload = b37114c65372b052cbeecf83d05a5da44f7b5bbff7d986b5
+CT = e9c3269cac74a34a4fb578d415f404b763b9bd729784b95b7da7f975367be24341e4af51b8bb156a
+
+Count = 7
+Adata = 00
+Payload = 9c0f0426f171ff18b2a4392f61fb4ee4a44c476fe03dc930
+CT = c6bd367c0e77ec0036ff8e78a45517f7888ea1a28060f6de360c6d50a96f316eda0b216cbb6380ef
+
+Count = 8
+Adata = 00
+Payload = 7b6e0a480a40585545b0e940e8d97c9ec987bd3c0e9c16a8
+CT = 21dc3812f5464b4dc1eb5e172d77258de5455bf16ec1294634cd1bd98e8137b578a174e39efe09b8
+
+Count = 9
+Adata = 00
+Payload = 34dac6dbc28be62332a6935efc122e37b26ee100eb4033f8
+CT = 6e68f4813d8df53bb6fd240939bc77249eac07cd8b1d0c16909a895a3b08b63d7a2a1e75d25e7861
+
+[Alen = 1]
+
+Key = 9748798c0f3cc766795c8ce0e4c979c1930dfe7faefea84a
+Nonce = cdf4ba655acfe8e2134fa0542f
+
+Count = 10
+Adata = 67
+Payload = 100fa71462277d76ca81f2cfdb3d39d3894b0ca28074a0f0
+CT = 36e2415b4f888a6072f260d7e786d803be16f8b9cbee112d7ff74e3b05b7d7c13284573bd3e7e481
+
+Count = 11
+Adata = 17
+Payload = 0217eb6778691f8dfe2d0e5241f05fcbcf97b9171f4de3f0
+CT = 24fa0d2855c6e89b465e9c4a7d4bbe1bf8ca4d0c54d7522d3ee7ce845f85dfc770d96dee9ca54ccd
+
+Count = 12
+Adata = dc
+Payload = a78b7bc6c1a7250c5fc236f2a8343725a9a7bd3ca81b53e4
+CT = 81669d89ec08d21ae7b1a4ea948fd6f59efa4927e381e239dc14ddd8ae0aa5d810040a8d1d4da1e9
+
+Count = 13
+Adata = 0c
+Payload = 390c808d998582793bb10ee60568eb8d975c51d68b4e4da9
+CT = 1fe166c2b42a756f83c29cfe39d30a5da001a5cdc0d4fc746b40dec7e647720f1f5e8474bf570c2f
+
+Count = 14
+Adata = 3e
+Payload = bcd9747fb54184b61b2e9e049caa75e22006e250f3722c0e
+CT = 9a34923098ee73a0a35d0c1ca0119432175b164bb8e89dd3c10c4aac45d90119cce490cc8681a49f
+
+Count = 15
+Adata = 7e
+Payload = d0342e3cd2c1142b642da7297ee3b9978cec405e6810f12f
+CT = f6d9c873ff6ee33ddc5e353142585847bbb1b445238a40f2f9a95091d2cab7d3d9fa3e10d3e67ac9
+
+Count = 16
+Adata = e3
+Payload = 7fab91d1aa072947d22f0dc322355a022fe7f0747f4a184b
+CT = 5946779e87a8de516a5c9fdb1e8ebbd218ba046f34d0a996180f7818c373e89f7ff3003f53260060
+
+Count = 17
+Adata = 3e
+Payload = e487143dc4d98dcc6a2dfe6ee0f85d565d1f46bb0fafe62a
+CT = c26af272e9767adad25e6c76dc43bc866a42b2a0443557f71905f581585e59e3c8c038b5bf966559
+
+Count = 18
+Adata = 3b
+Payload = 976b489244ed6789a34251500057d1d4a3229367a42b9066
+CT = b186aedd6942909f1b31c3483cec3004947f677cefb121bbea56569c34f8d9eea23e85fec18cfc51
+
+Count = 19
+Adata = a5
+Payload = 71efa75961dfd60ad533082a8cfe111214eb02573adc4591
+CT = 570241164c70211c6d409a32b045f0c223b6f64c7146f44c212da23548f2ca4e9a8a07962be6422c
+
+[Alen = 2]
+
+Key = 393dcac5a28d77297946d7ab471ae03bd303ba3499e2ce26
+Nonce = fe7329f343f6e726a90b11ae37
+
+Count = 20
+Adata = 1c8b
+Payload = 262f4ac988812500cb437f52f0c182148e85a0bec67a2736
+CT = e6d43f822ad168aa9c2e29c07f4592d7bbeb0203f418f3020ecdbc200be353112faf20e2be711908
+
+Count = 21
+Adata = 9db5
+Payload = d5982c462ad40458660cd7b120ce07fce9afe812caedcebd
+CT = 1563590d888449f231618123af4a173fdcc14aaff88f1a89015e5cd97b7dd3d981321ae0b2d99e1a
+
+Count = 22
+Adata = 69cf
+Payload = 1a95f06b821879df3fd3ac52fc99a7c1d3e9775263b7d036
+CT = da6e85202048347568befac0731db702e687d5ef51d50402bf3e75863c7acd2699caba3cc301f4b2
+
+Count = 23
+Adata = 6c6e
+Payload = 373c157e59b934a1afb57d4c5dd9ca7fb736b206a6210bef
+CT = f7c76035fbe9790bf8d82bded25ddabc825810bb9443dfdb5d6a8f7a9f52a8038aa9dc1bdc9ed876
+
+Count = 24
+Adata = dafa
+Payload = 26e10a2ed8cc883a6552aee162c5542ff8bb8e758a1975f8
+CT = e61a7f657a9cc590323ff873ed4144eccdd52cc8b87ba1cc8a15603f10cbfdb041f8b2b12cc8f037
+
+Count = 25
+Adata = c8b1
+Payload = dd235b05c15479dfe0326ba206ac784eca50038bbeb35d32
+CT = 1dd82e4e63043475b75f3d308928688dff3ea1368cd189061278bf62ba6a4819513d49fdcdb45480
+
+Count = 26
+Adata = af48
+Payload = a0818342a5cae4a90ef281d3d1289d83f273f418a545fcbf
+CT = 607af609079aa903599fd7415eac8d40c71d56a59727288b8b4d00309b50f9ea72f8105c94475b52
+
+Count = 27
+Adata = b1cd
+Payload = 33c0d06b6583bb4d15b4a07364c4be70ac6e72795c3dae0f
+CT = f33ba520c7d3f6e742d9f6e1eb40aeb39900d0c46e5f7a3b220ba58e97936612c4183ba86705b2f9
+
+Count = 28
+Adata = 649a
+Payload = 3ba11282d61fe36e38cab7b559c2fd9cbe8bf7eb5863bde9
+CT = fb5a67c9744faec46fa7e127d646ed5f8be555566a0169dd87d602dc85bb260fb3df1221e2fbd10c
+
+Count = 29
+Adata = 593c
+Payload = a97faefcae36732fcfe47736c2334ea7d411bf7638b0c019
+CT = 6984dbb70c663e85988921a44db75e64e17f1dcb0ad2142deb3835b7eecad6dac9785ad1d370ede4
+
+[Alen = 3]
+
+Key = a74abc4347e4be0acb0a73bb8f7d25c35bae13b77f80233a
+Nonce = 6a850e94940da8781159ba97ef
+
+Count = 30
+Adata = a4490e
+Payload = 6372824bf416cd072a7ad0ae5f9f596c6127520c1b688ab4
+CT = b14a07bdc119d87611342c4c6935c5786ff1f9ae2eb49e6191c88a3cb4fbafcb8a4a157d587d7e39
+
+Count = 31
+Adata = 5cad2e
+Payload = 295f4f3417a77fcf0bbda17b0fd629ad57a6086573c87eb1
+CT = fb67cac222a86abe30f35d99397cb5b95970a3c746146a64235c34d1390bba5b008c3fb29c2df958
+
+Count = 32
+Adata = ebdf4c
+Payload = 86f354a505de941d34cd98e3af3706d56a938ab9a2797182
+CT = 54cbd15330d1816c0f836401999d9ac16445211b97a565575a733bba0a6992d0664dc77d2b5d194c
+
+Count = 33
+Adata = 7c0d70
+Payload = 88c3bfb546abe2f6bfc92a7c56c627e24ab92a8a87a6b43c
+CT = 5afb3a4373a4f7878487d69e606cbbf6446f8128b27aa0e90902a31b15eed99c2dc4ed1bf11cad96
+
+Count = 34
+Adata = 8fa501
+Payload = 75d4216bad77943bfe82be216157843b0da0fd16eeee8471
+CT = a7eca49d9878814ac5cc42c357fd182f037656b4db3290a42f25595ae00103d4eb20288158132e7d
+
+Count = 35
+Adata = b7aca7
+Payload = bf1401e8dcf6f681ed6dd74c7e23b7e54b384608b0e5ec52
+CT = 6d2c841ee9f9e3f0d6232bae48892bf145eeedaa8539f88760e67693b509ea4795b7da32c5c5d17f
+
+Count = 36
+Adata = 1f283f
+Payload = 7e623e7ef7d0a678b5d22a8402d89220f4f1bf759e3084dd
+CT = ac5abb88c2dfb3098e9cd66634720e34fa2714d7abec900880ef8ea380a1a0a38b2c20288e637a9f
+
+Count = 37
+Adata = e93f31
+Payload = 14f80e7a6298d85d31fb80376a394a8f88b0ae47f00450c7
+CT = c6c08b8c5797cd2c0ab57cd55c93d69b866605e5c5d84412d553aafe8536385d34c412c14d3a1563
+
+Count = 38
+Adata = 27e9a5
+Payload = 3330df12249639961f562a74b34f60b0a8bc7c783f6572fd
+CT = e1085ae411992ce72418d69685e5fca4a66ad7da0ab96628f594d366c8fc826ce58309e9053c27f7
+
+Count = 39
+Adata = 72d566
+Payload = 1a1860ac8c11c5d262f8141738cae8ff91ca05906dc98bb4
+CT = c820e55ab91ed0a359b6e8f50e6074eb9f1cae3258159f61cdd6ac6c42cd3d11e0344a9c1001e253
+
+[Alen = 4]
+
+Key = df052e95aea3769a433ce4e4e800b8418649bbe8c6297eb0
+Nonce = ba356d392c3f700f4f2706a4ca
+
+Count = 40
+Adata = 8ffc0e3d
+Payload = e8c1a89228d8212f75c136bab7923a89f9fea18e781cb836
+CT = 66b5d782323925e1bd0a8413a9a5a881356453d5df2cbeb199b2e1e803550dcdde55fd66ecb45edd
+
+Count = 41
+Adata = 2b4f9cfc
+Payload = a12c6324e022affd61b7e0d8cccbeb23e2e6c65355c1d586
+CT = 2f581c34fac3ab33a97c5271d2fc792b2e7c3408f2f1d3019e8fbc507244ba234a0581dc69962a66
+
+Count = 42
+Adata = b4de3039
+Payload = 7cccb26f1dd227bc77458b99fd9e00f8e801adaece7bfcd1
+CT = f2b8cd7f07332372bf8e3930e3a992f0249b5ff5694bfa5628a2857099af20a4ae08e687bdb02c75
+
+Count = 43
+Adata = bc59f18c
+Payload = 692b53c1355475c71ceff0b0952a8b3541b2938270247d44
+CT = e75f2cd12fb57109d42442198b1d193d8d2861d9d7147bc3e33a6416e387d9e571a1954471ec9cc7
+
+Count = 44
+Adata = 4fd9fd39
+Payload = 7e3e755e25bbe78d4a7770f9356ab9f4ff1bbfdba46383f5
+CT = f04a0a4e3f5ae34382bcc2502b5d2bfc33814d8003538572180f9735f994c8335e593f30b331a920
+
+Count = 45
+Adata = 296cd04c
+Payload = 997b712cd9295dc43cc19b40679f218c27af3e8c638d2e5d
+CT = 170f0e3cc3c8590af40a29e979a8b384eb35ccd7c4bd28da91990fa537d2657d01f66872ba9af22f
+
+Count = 46
+Adata = 88037d3e
+Payload = 577981ccb6c893dfe6405075fcb41507de7f9bfda860791f
+CT = d90dfedcac2997112e8be2dce283870f12e569a60f507f984915cb93e84028c7aedce1a2dadbb6bb
+
+Count = 47
+Adata = fc4bb852
+Payload = 37ba9f57ec230675ce060ba3d388095adf15907aa0b0673d
+CT = b9cee047f6c202bb06cdb90acdbf9b52138f6221078061ba25baa6385af8d7b807a2d2ab19aa4999
+
+Count = 48
+Adata = f40ec14f
+Payload = 401e0cdc132a9e4a9b5ceeed3c181f67e5203ea69508deff
+CT = ce6a73cc09cb9a8453975c44222f8d6f29baccfd3238d8786adcdb44870e1105b7318d8bad0af957
+
+Count = 49
+Adata = 90e2c63b
+Payload = 0234dae5bd7ae66c67ff0c1a3f1a191a0d7bceb451bc2b7d
+CT = 8c40a5f5a79be2a2af34beb3212d8b12c1e13ceff68c2dfa8b079fb71d45bd985bffd343c3362653
+
+[Alen = 5]
+
+Key = 16d345606a315ad2406abbcb43cd8cabe948107ba6d17a72
+Nonce = d4ef3e9e04f1b7f20ffc5a022e
+
+Count = 50
+Adata = a468f08d07
+Payload = d3bef460223c81e4579c9d1d463ac5e0881685de1420a411
+CT = abb85db49a9b1c8724ecbc734cc8373bd20083cfa4007b1cfe4d3a3bb25f89f692884be230c6035c
+
+Count = 51
+Adata = 4497649a54
+Payload = 81ad3f386bedcbf656ff535c63580d1f87e3c72326461ee1
+CT = f9ab96ecd34a5695258f723269aaffc4ddf5c1329666c1ecd05ae56511a230627e02d066c52a919e
+
+Count = 52
+Adata = c30ddd994e
+Payload = 84b88264afec06b370dfcebf5e1d3e2c1f005faf248b3215
+CT = fcbe2bb0174b9bd003afefd154efccf7451659be94abed188ef92fc17dca026f1ac1eaf78a05017c
+
+Count = 53
+Adata = 9573270f7e
+Payload = 9e4c8aa9b58a8eabc5586892f5541000b43f17d9a051a040
+CT = e64a237d0d2d13c8b62849fcffa6e2dbee2911c810717f4d38eddff1e60e2d9ae74a936364b8df21
+
+Count = 54
+Adata = 40336790fc
+Payload = 260f67122dfbe03365bc9e35e9d4ac4b2eb150eddb30857d
+CT = 5e09cec6955c7d5016ccbf5be3265e9074a756fc6b105a70aa3d464ad89cae59b474d019a5a7605c
+
+Count = 55
+Adata = 0b310c8529
+Payload = 1d55e7352bd895c4ef77389a7225c664f72b38c8de778d57
+CT = 65534ee1937f08a79c0719f478d734bfad3d3ed96e57525abeab0c520e64939c6950c0fa406eafb1
+
+Count = 56
+Adata = 5756b2c681
+Payload = fbd315e1f5bd0f0e60ee6684c88f3543452c62ea0701d11d
+CT = 83d5bc354d1a926d139e47eac27dc7981f3a64fbb7210e10d22d339c382343bf39c239fd64c2a64f
+
+Count = 57
+Adata = 3b919e3665
+Payload = d68d6556c5a5b1f5a123389b3ce966d5837cb8fcf5accfff
+CT = ae8bcc827d022c96d25319f5361b940ed96abeed458c10f2fcd6b562a1b6aa10be92a81f99ed540c
+
+Count = 58
+Adata = 58749b643f
+Payload = 062cb6962fa5b3a6239b95f3a51b478a1f32b081dc538a80
+CT = 7e2a1f4297022ec550ebb49dafe9b5514524b6906c73558d4b853022237d94d253b375bf2150e699
+
+Count = 59
+Adata = a5d50c008b
+Payload = 08c62ff9bd7bcf189f530d5065f8764532d2692f69858483
+CT = 70c0862d05dc527bec232c3e6f0a849e68c46f3ed9a55b8ee7aee0d403b2cf6f8b993eebd6b93615
+
+[Alen = 6]
+
+Key = 1c476cfd7dd300d961fd3f24a6fe0e80742b00851676ca63
+Nonce = e300fc7a5b96806382c35af5b2
+
+Count = 60
+Adata = 28130f938c45
+Payload = 6f3938932b5c1280311e892280d8a822a828a0be7fdb1bcd
+CT = df48662fe134e75a85abc2cece2c3b6236c88a70fa792e9beadc9601adf9fbdf4e3e94b395b0a332
+
+Count = 61
+Adata = f600024a7bf9
+Payload = 0af7345e71f4e8886503395ade0b0296a5856e086638b06a
+CT = ba866ae2bb9c1d52d1b672b690ff91d63b6544c6e39a853c0692a40a6aba8d7c5addae21de90fea9
+
+Count = 62
+Adata = 4eef510d1f48
+Payload = 37f57772f056f45a5ce9f46d27be1858980c8935b9c839b7
+CT = 878429ce3a3e0180e85cbf81694a8b1806eca3fb3c6a0ce122f64becb581070411957e632e19bb8f
+
+Count = 63
+Adata = 4c9c76b6fad5
+Payload = 8bb10c82bcabb7fb2b169252ab443b01df217cf908b8c241
+CT = 3bc0523e76c342219fa3d9bee5b0a84141c156378d1af71708c59f83aa97d069b6d83d9387051f43
+
+Count = 64
+Adata = 5572ecfc7e53
+Payload = d1ccb4654a22b1afe32f3d3035fdccd87e9cbed83c679007
+CT = 61bdead9804a4475579a76dc7b095f98e07c9416b9c5a551f04686ee1d7b985d903f1de6cf78f8f4
+
+Count = 65
+Adata = bffdf9d20d74
+Payload = f990a8f6ba14065d48665db36eb470c49f38e2b6376a9bde
+CT = 49e1f64a707cf387fcd3165f2040e38401d8c878b2c8ae88f8118f1b9f39b51965ae9ef1bdb40111
+
+Count = 66
+Adata = 3f27e678c580
+Payload = f8c7d89639ab742a8bcfffe776e868d671e1fbdd55807a8a
+CT = 48b6862af3c381f03f7ab40b381cfb96ef01d113d0224fdca3236d02f33f49759f281315e449bfef
+
+Count = 67
+Adata = 1294cb9db5f5
+Payload = 8601cfd7d935e8a8487b9c39d55ca27096255f2eb9e009e3
+CT = 3670916b135d1d72fcced7d59ba8313008c575e03c423cb5e74770a07c242c3854ceb242dadc1976
+
+Count = 68
+Adata = cec271332b75
+Payload = 77c85b8022f58337b364142a2474fe5cfddb31cfca48af46
+CT = c7b9053ce89d76ed07d15fc66a806d1c633b1b014fea9a10d6c65f19175cfa49898655ccdddb864a
+
+Count = 69
+Adata = da06bd140502
+Payload = b0f2db802475fa70af02057373844f637a3244cda4b4f93d
+CT = 0083853cee1d0faa1bb74e9f3d70dc23e4d26e032116cc6b458822e49e69031431b3eea872a72eb7
+
+[Alen = 7]
+
+Key = 79d1e38a70df1cf239be168833dcd0570bc8f37b3aa26c37
+Nonce = 8229d6d7e9e21fdc789bff5dcf
+
+Count = 70
+Adata = 076887d2abe900
+Payload = 83c24f3a77b83b4ef45277ba90225f3ba1722312f52b1a07
+CT = 19d880f1d959a68f162de243d4a45747ace704613359b27218d1531a066de60a95d2924a6910e990
+
+Count = 71
+Adata = 7535bcc6fbd1a0
+Payload = 24f85ef683cc521387f484bc0b2ad9172f61884c09a9718c
+CT = bee2913d2d2dcfd2658b11454facd16b22f4af3fcfdbd9f96dbf58406020e6df7b312b6825127f9a
+
+Count = 72
+Adata = f4f96d7b4384a3
+Payload = 212bedfa06b5e1a2c3a2f31f6f791dd9df8ef26077821c0a
+CT = bb312231a8547c6321dd66e62bff15a5d21bd513b1f0b47f64dd755177efc87f8b1daf1fd88e51a6
+
+Count = 73
+Adata = 3b7e3d9c1a7fa2
+Payload = 8b9036914bb0f440c8dbcfde9b9547be5e5ef1f56492c75e
+CT = 118af95ae55169812aa45a27df134fc253cbd686a2e06f2b0be31cab31f1a20805d5c07dc516d707
+
+Count = 74
+Adata = a8c35fae8912d6
+Payload = 50f3f3a91bf6fd9573d5ef54b9bb5805205b2f9865d81fd7
+CT = cae93c62b517605491aa7aadfd3d50792dce08eba3aab7a2399df9a45ad153c0dfb3fec3b9d6f7c5
+
+Count = 75
+Adata = db636541f2429d
+Payload = 6fbda8d435555e735443f1e6bc09e96065092efd89edd64a
+CT = f5a7671f9bb4c3b2b63c641ff88fe11c689c098e4f9f7e3fe20b7da94eac8c7ef8478671165e0d82
+
+Count = 76
+Adata = a8de55170c6dc0
+Payload = 640ef4c246a2c6e16ddc49072a5aeef70319149ffba071ef
+CT = fe143b09e8435b208fa3dcfe6edce68b0e8c33ec3dd2d99a4979c35bdbf9538666b6fa57f0f915d8
+
+Count = 77
+Adata = f8d64ce2aa66e6
+Payload = a14e3910766f31594a28ad2c3678c31d0c3aee88484ca6d6
+CT = 3b54f6dbd88eac98a85738d572fecb6101afc9fb8e3e0ea3752824a691da2e99374ae6c031d74ffb
+
+Count = 78
+Adata = b3c340afdc53a8
+Payload = 1b8e0a09e6364020b4cac704dc19bfa79455295604cf9c9a
+CT = 8194c5c248d7dde156b552fd989fb7db99c00e25c2bd34ef04159a68706faa2e8c3376b4dbeb423a
+
+Count = 79
+Adata = 73824034001519
+Payload = 52c84a0735eea6c5c230644075ebfc5db0c3128056e7a8f4
+CT = c8d285cc9b0f3b04204ff1b9316df421bd5635f390950081e5adc7564721ead2af75cb98e61148b4
+
+[Alen = 8]
+
+Key = 72e6cebdaf88205c4e74428664bc0d7eb4687a272217b7ca
+Nonce = 3820db475c7cb04a0f74d8e449
+
+Count = 80
+Adata = f427c47e10c45bb3
+Payload = 54bc7e3c227df4e83252a5848fea12dfdb2d14b9e67c1629
+CT = 91e7baff2b42af63e26c87ce6991af22422c1f82906858b1721961de5c768f4d19bd3034f44f08d2
+
+Count = 81
+Adata = ca25504f3f5559aa
+Payload = ff4493fea916f49fbb3cae2838bc84e293531092cc0904ab
+CT = 3a1f573da029af146b028c62dec7391f0a521ba9ba1d4a3342968c638ecb8a2b358e8eaefd931efb
+
+Count = 82
+Adata = 8215753d9efc5132
+Payload = af16ab8558269a93d8e8c9e38f12a8768947d8b69be0e259
+CT = 6a4d6f465119c11808d6eba96969158b1046d38dedf4acc1f8ac11752fe51e354f3f8a68815539aa
+
+Count = 83
+Adata = 9e7cdbc6202e6492
+Payload = 744a167ae31a8ca20df82290766429de9ef0b7dfe199a78d
+CT = b111d2b9ea25d729ddc600da901f942307f1bce4978de915489de8e241dcab16bdcbf1a1ff4d8d10
+
+Count = 84
+Adata = b8d511d0ab86a07f
+Payload = eeb39de1fe21b5aba654da45fe1481decb22365fa4cbe49d
+CT = 2be85922f71eee20766af80f186f3c2352233d64d2dfaa053fab212a1b6dc7b953e2bc211be194ae
+
+Count = 85
+Adata = c74a5d4265f9f3d5
+Payload = e95c20e80153bae3fde3c3d82b6b33b35fc1959fa31a5d11
+CT = 2c07e42b086ce1682ddde192cd108e4ec6c09ea4d50e138973918ab70fe048d6c5b63a01725eddfb
+
+Count = 86
+Adata = fd849d3ada03181a
+Payload = 6d00606c72cea3deaea5b51ae09e61924355e167058ef42c
+CT = a85ba4af7bf1f8557e9b975006e5dc6fda54ea5c739abab487089bc20867f474c1127aa1320f0000
+
+Count = 87
+Adata = 56825a68681f498c
+Payload = c47705d897a6c7e7aed710b96e2d8532c23b82090e21b114
+CT = 012cc11b9e999c6c7ee932f3885638cf5b3a89327835ff8c34a23b0b6ac4d297dd7832a5e2102272
+
+Count = 88
+Adata = 72e4da839913a26e
+Payload = c822a1ee581cf85b0482c821473385bd3f28528e5e5760d9
+CT = 0d79652d5123a3d0d4bcea6ba1483840a62959b528432e41dd665766c7af21ff890bd40178f1c660
+
+Count = 89
+Adata = 138457571ee8dafd
+Payload = 3ffb82a83308da66e95ac63ae92931b09ffe0e42afbb4979
+CT = faa0466b3a3781ed3964e4700f528c4d06ff0579d9af07e16a6a58bb772c79481dc26861ffbd68c6
+
+[Alen = 9]
+
+Key = 39c03a0c8634047b1635348f284d3dc1e752ab40548eb337
+Nonce = 9e2ea8eb7f56087ee506925648
+
+Count = 90
+Adata = 28d157f09a71da80dd
+Payload = 0662e63c88e963d3e0cf2c4653515ae4474a2c78ab0394c0
+CT = 01dcd4dd3b8c1369518136ce45e8bb9df565b0ad231a887b02ada34addf0aa2f4744ed2e07995491
+
+Count = 91
+Adata = c17d311362c41d442b
+Payload = d6df8b60c697093987b3d89a3667b36504b6ddddf12b0900
+CT = d161b98175f2798336fdc21220de521cb6994108793215bb38a27466b8741bffce44ef04b23af321
+
+Count = 92
+Adata = 006669ef1a11b65b1d
+Payload = 49ad29ef5e82b08752ac5a50dd982e4bcb700005454ade6c
+CT = 4e131b0eede7c03de3e240d8cb21cf32795f9cd0cd53c2d77d11372fb0dab1c99b159e5fe9f91118
+
+Count = 93
+Adata = 8eafce9ba466fd53eb
+Payload = 385f9fb139dbf88561b7a500b0c7b835fe57e2698c6d9f76
+CT = 3fe1ad508abe883fd0f9bf88a67e594c4c787ebc047483cd09e4898a4046f6ec9f40e412915007e4
+
+Count = 94
+Adata = 796e55fbe7bed46d02
+Payload = 4ebb149b01cbacba32d11168ca61928ea149dcf2ee2c1001
+CT = 4905267ab2aedc00839f0be0dcd873f71366402766350cba5d40a9902481bfac7ff33d08fb4b3d31
+
+Count = 95
+Adata = 8f958d796be0566512
+Payload = 0d974e5621caa1d86eaaee689ccbca57843373fcf20db407
+CT = 0a297cb792afd162dfe4f4e08a722b2e361cef297a14a8bcd972d09a17172161eb68a30b593b1bd6
+
+Count = 96
+Adata = cc879ff2d583a7288c
+Payload = f8e0dac6a691dfb231411b5c5f70a0daff83cc637b0c7bb3
+CT = ff5ee82715f4af08800f01d449c941a34dac50b6f3156708119cc26a80c152c253fbc36cb886e0fc
+
+Count = 97
+Adata = 4765d696d19dec58bc
+Payload = 096a36396ccfa260f28fb0919157a5076b53506c51a2a4ef
+CT = 0ed404d8dfaad2da43c1aa1987ee447ed97cccb9d9bbb8549de06cc5c3bc4ad75076c774576843fb
+
+Count = 98
+Adata = a004f283afc3309c31
+Payload = 5b943269be41e2758a4ea6a3cc621b711a8ba6002783aa72
+CT = 5c2a00880d2492cf3b00bc2bdadbfa08a8a43ad5af9ab6c9135493b44f79a5774df6b2943b0bec67
+
+Count = 99
+Adata = cdd5d8aefe49a315ad
+Payload = 5f27867109e74862ce0dbc9ba73c420b93067bdede17ae51
+CT = 5899b490ba8238d87f43a613b185a3722129e70b560eb2ea7a5da4a29a9012d78b6de6f1b3e8c9ed
+
+[Alen = 10]
+
+Key = e2a92ffbb0b5eb68cb82687f12449fae5167d375131b0b10
+Nonce = 441ad5e1382e083a95224f395d
+
+Count = 100
+Adata = 2352648299b0413cb2ce
+Payload = 048c9ba4597c3bb595bfd5048e5e9a1296f30e5c0118b177
+CT = 25247a258e4ac0a988d8def60cc174a9d4578cd5346fb5150c96e8ab8774baa421f39c64a386c418
+
+Count = 101
+Adata = ce003c836a6f5f066053
+Payload = 02ea8e7e488c863584f828df13dfeb68433294d11d9ca9d7
+CT = 23426fff9fba7d29999f232d914005d30196165828ebadb5d453036cdc6bad0c5e770a6249a52e74
+
+Count = 102
+Adata = d11be73a104ccc6346d5
+Payload = 6d5573c9279897d7d1602d8a95c04bb5ca3fad2dbe89a024
+CT = 4cfd9248f0ae6ccbcc072678175fa50e889b2fa48bfea4464627ad75bbfe17f3f5ddfd3dbc1045f3
+
+Count = 103
+Adata = 6a7b80b6738ff0a23ad5
+Payload = 97a813e75d95d25c2edb1c705c4ffe4d7c08c756761fbc0b
+CT = b600f2668aa3294033bc1782ded010f63eac45df4368b869af8943f74706cc3394a170fd49f7011a
+
+Count = 104
+Adata = a391acdb3a06dae4a671
+Payload = a78981ac244307451e4d3fd7f654b70cc4e6518aa47a3c18
+CT = 8621602df375fc59032a342574cb59b78642d303910d387af22597f63074ca3533bb5e107860481f
+
+Count = 105
+Adata = 0b9f28f2d3215785f569
+Payload = 5d649d79ff0e304e164a383c74f13d7ffab145d00cb0ec2c
+CT = 7ccc7cf82838cb520b2d33cef66ed3c4b815c75939c7e84e905b5609f593c6ea9281f66cd2e646dd
+
+Count = 106
+Adata = 7928b1091cbfb2eef0fe
+Payload = 83a273687dced7b94d569f81d75508595cde668f06406183
+CT = a20a92e9aaf82ca55031947355cae6e21e7ae406333765e1428195355618ea0cf87260ad20b6d7b9
+
+Count = 107
+Adata = 3b74afb81f54a93c79d5
+Payload = b4dc3c059cf7b47dd0bb7f165a63fc80b5c6b5f3ca7eeb73
+CT = 9574dd844bc14f61cddc74e4d8fc123bf762377aff09ef1155019659f41a5f0430695b4ada9d8b8d
+
+Count = 108
+Adata = a46ae4c71d4c9eb72fab
+Payload = 7e919581c5105d98717d0613e1ca869c6516506ea482d5c2
+CT = 5f3974001226a6846c1a0de16355682727b2d2e791f5d1a01514b252f33dc870c42260e48c4fa9fd
+
+Count = 109
+Adata = a1ace61711f0a09ac17d
+Payload = 3a4558b55214f21cbd2ae2eda5a2321cfc2f102e059b744a
+CT = 1bedb93485220900a04de91f273ddca7be8b92a730ec7028c263c667d7ed58907452c092905d0b31
+
+[Alen = 11]
+
+Key = ef1ad3eb0bde7d4728389da2255d1f8a66ecb72e6f2f1ac4
+Nonce = 8e7d8a44244daa7df2b340993e
+
+Count = 110
+Adata = 521583c25eb4a3b2e46120
+Payload = 9f580cc6c62a05ce125c6bec109a48ca527ee26a64b14b68
+CT = ff0ff95bcb0bccd5e4aadd77ac6770f5013654eb3c6386fded2c87135861b43a99f258b6938f66e3
+
+Count = 111
+Adata = 31adb39e947f8883fa4b69
+Payload = f16bba081bddda83546eabc9a55c81a439720dd8562ce964
+CT = 913c4f9516fc1398a2981d5219a1b99b6a3abb590efe24f132b87476d66a1bd405f484ef9ac8ab7e
+
+Count = 112
+Adata = f05f39eb0a3d6460076aa8
+Payload = 6baf784f63cf45a1836fa8f3609fff7870ce8cbd1e91268c
+CT = 0bf88dd26eee8cba75991e68dc62c74723863a3c4643eb19a120b455b366cb104fd8b6dc2c80471e
+
+Count = 113
+Adata = 74c7a633ff73ff507009c5
+Payload = d8176a6de1c15a14c8b8b58725c179dc84c9308268d718d5
+CT = b8409ff0ece0930f3e4e031c993c41e3d78186033005d5400c8ca09f4bf06b1c27e75abf15112e49
+
+Count = 114
+Adata = ab322a88cf44b9ca774415
+Payload = 3706e4d8ff748574f382e5f9b0a3b6258f1f360fd87001b0
+CT = 57511145f2554c6f057453620c5e8e1adc57808e80a2cc25b3159274a7de3550baf759f7fae53dbc
+
+Count = 115
+Adata = d6fe6e17221d4e06ed3ab9
+Payload = e02217394772deffe218c405e40f2a3a56ca01d55d6d3330
+CT = 8075e2a44a5317e414ee729e58f212050582b75405bffea516fba8d193e133e6f78daa39681cb262
+
+Count = 116
+Adata = 2739d2cdfcbe7d5cd7d28c
+Payload = bb713f74a884bd1a994adba87561d637853c6181290ef5e8
+CT = db26cae9a5a574016fbc6d33c99cee08d674d70071dc387d65f92db3b3d1c2de04c69c5d06b0e001
+
+Count = 117
+Adata = 5841571299cd064a6262b7
+Payload = 9641dedd50d80ac0abf7591436065fa2e23e4687abbb86e4
+CT = f6162b405df9c3db5d01ef8f8afb679db176f006f3694b716e4d20ab5ffad6f71155f6839dfdbb25
+
+Count = 118
+Adata = dc5d7fd97bb3243ba585fa
+Payload = aefda8501193edacb8abb94fff875529a537a462c4b9b69c
+CT = ceaa5dcd1cb224b74e5d0fd4437a6d16f67f12e39c6b7b090ebc3af2de52b8bee3d130fa973f716b
+
+Count = 119
+Adata = 8789e0b3e0dc13d9725b37
+Payload = 65e53f549b62aca03f21ab2a494b93805e02cfecf4f12aa4
+CT = 05b2cac9964365bbc9d71db1f5b6abbf0d4a796dac23e731b5cd5a004a0ef28e30383bdaed8f93c7
+
+[Alen = 12]
+
+Key = 44cba20b7204ed85327c9c71c6fea00b47ce7bdde9dea490
+Nonce = f3329154d8908f4e4a5b079992
+
+Count = 120
+Adata = f1e0af185180d2eb63e50e37
+Payload = 6333bde218b784ccd8370492f7c8c722f8ef143af66d71d7
+CT = b9401a4927b34dc15e9193db00212f85f0c319781ec90e3b4484d93cb422cb564acc63d3d18e169c
+
+Count = 121
+Adata = ea74231e49e667ca1c21d46d
+Payload = 3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e
+CT = e67d8fbeec794d42fc64d7f36a87d2ac22aafa440021ea72c4c151d9927e6a9f19d47ff7d79ca6f6
+
+Count = 122
+Adata = 7f5871a8300471dc325f8289
+Payload = c642c9722d84d708682350dc70bdaa9a1181a415a9e72b93
+CT = 1c316ed912801e05ee85c7958754423d19ada9574143547f959eee29be1415ab03444de0fa42707d
+
+Count = 123
+Adata = ee7e6075ba52846de5d62549
+Payload = 2286a1eddd80737a724ca941217e9f0232870b6c2f20d29c
+CT = f8f50646e284ba77f4ea3e08d69777a53aab062ec784ad70ce97c1c8aea70de04580d7b37f8c014d
+
+Count = 124
+Adata = a30f2fd445820cdf80014554
+Payload = 92577d5db20391110309d490f52acecdfc18382f368bbe42
+CT = 4824daf68d07581c85af43d902c3266af434356dde2fc1ae23b536f993381e525a14599dd5c02e80
+
+Count = 125
+Adata = 0cfec933831644b468724e80
+Payload = 6803dc3f7c06568ca78ee5aa2e9b1b354a4f1e067ff6a25b
+CT = b2707b9443029f81212872e3d972f392426313449752ddb7d6ea722fdd82ede2c7b8832dde3cbe80
+
+Count = 126
+Adata = 6bd14e3bf91dc7fd6be07647
+Payload = 5580672e52aacb9d714a34c31c33fc221e13e8f90849adba
+CT = 8ff3c0856dae0290f7eca38aebda1485163fe5bbe0edd2565c2994b2b469ad977564d83db1ebfe38
+
+Count = 127
+Adata = 6c6ad35e97d023217018162f
+Payload = 1bd1bcc6766d251144376d91ff93ef83033d0e0ee546266f
+CT = c1a21b6d4969ec1cc291fad8087a07240b11034c0de25983ac31ebf9e255eecf3c69ddf198760556
+
+Count = 128
+Adata = 52c35db85cc34b6efed180ee
+Payload = 28f71a2fe498f89203a5d23e8f8fa64b124aea6459fe721d
+CT = f284bd84db9c319f8503457778664eec1a66e726b15a0df13424079e3de87fa59c3d10fd62380a90
+
+Count = 129
+Adata = a96e4776270683ee7d0c9b6e
+Payload = 5be078ead1926074afca81f9a97dc93dcb954c955e4343e4
+CT = 8193df41ee96a979296c16b05e94219ac3b941d7b6e73c082258e1f3fc3eb7e976c86c8a21bd6569
+
+[Alen = 13]
+
+Key = b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731
+Nonce = 13501aebda19a9bf1b5ffaa42a
+
+Count = 130
+Adata = ead4c45ff9db54f9902a6de181
+Payload = 3726c1aaf85ee8099a7ebd3268700e07d4b3f292c65bba34
+CT = fd80e88f07dad09eed5569a4f9bb65c42ef426dda40450119503d811701642143013f28ce384d912
+
+Count = 131
+Adata = e63b89e95df8338ecdcc885c3b
+Payload = 37f86aa62b1e31e9ded3e1a38a7e1a8a638d619ac109694f
+CT = fd5e4383d49a097ea9f835351bb5714999cab5d5a356836ac6d3f9c7b9f25e09ce164a11370b8b05
+
+Count = 132
+Adata = a2161536e263459e0b0a29a225
+Payload = 1749f5977197359a5d318d5fea38aba95b3603f1d7011e66
+CT = ddefdcb28e130d0d2a1a59c97bf3c06aa171d7beb55ef443e02b848b006c28803303fd97bdc35476
+
+Count = 133
+Adata = 8ac95a6ae0bce0fb07f85368ab
+Payload = 0842bfb8b38283257c2ea58b29c8350775f1dbf15f73c905
+CT = c2e4969d4c06bbb20b05711db8035ec48fb60fbe3d2c2320431de2bc45b2b726bfda92939a11f68b
+
+Count = 134
+Adata = 44cc9b2510680c4d73f1938c77
+Payload = 68d09fce5e89e4ef6d453b8ee326090cedb97b75b886c7b3
+CT = a276b6eba10ddc781a6eef1872ed62cf17feaf3adad92d96786add8c2619f0782ca12312a1d64266
+
+Count = 135
+Adata = d8a662ab8449bd037da0346a24
+Payload = 45245de4ac6a6196a0b15b77c622a21bb50627379ddb4256
+CT = 8f8274c153ee5901d79a8fe157e9c9d84f41f378ff84a873b6bd4a09f9b4aa2864d39ff1a03e0ff7
+
+Count = 136
+Adata = 8ed39da1d9179e77156eb909f3
+Payload = e928e37dbe8389a53c650edc86f83cd3589a53dc8e45adfd
+CT = 238eca584107b1324b4eda4a17335710a2dd8793ec1a47d819b6935778ffbc0953974de0a9d87a31
+
+Count = 137
+Adata = 423515f7bd592d6a7a2408661a
+Payload = 4c3bdc6186297896097b3297ba90bcde78dc8a9efe3bd8b1
+CT = 869df54479ad40017e50e6012b5bd71d829b5ed19c64329400a3da0d3ce34a272b51582a998f461e
+
+Count = 138
+Adata = 5a6bc2cd6890a473d478a582b4
+Payload = 1c5ebaeb7b926a39b8aaf65a4c484b113d6f2caafadc33ea
+CT = d6f893ce841652aecf8122ccdd8320d2c728f8e59883d9cf4ef28c338f497a40f550f2945734ad1a
+
+Count = 139
+Adata = 7bdc26b5b4df58af539d91eb2e
+Payload = be5c9fee6babf569c66e6a0d0f3c4dc314f40c0aeca493f7
+CT = 74fab6cb942fcdfeb145be9b9ef72600eeb3d8458efb79d2e07f1998e57ba9b611568632dc5cb9fe
+
+[Alen = 14]
+
+Key = 13f179aa2a23bc90a85660306394940e9bb226ce3885ec01
+Nonce = aaa52c63ca1f74a203d08c2078
+
+Count = 140
+Adata = 5cc924222692979a8e28ab1e0018
+Payload = d3b36c6289ad6ae7c5d885fe83d62a76270689ce05fa3b48
+CT = bc4fcef401c2e1d1c335734ff23ea52c3474d2e6f31648a7f58649400ac9e825b038d67f0c2a6f1c
+
+Count = 141
+Adata = 21fb9cdd9b110bbbc6832275dfa7
+Payload = a7742dd9c3e8bbad08157fbd01ebfb94e1639117c4b4eb5d
+CT = c8888f4f4b87309b0ef8890c700374cef211ca3f325898b23fa5ad4142e0b4650fa5cc8f7ef70d62
+
+Count = 142
+Adata = 9919ddb6ee6c330646cd15953d39
+Payload = 297b4498bf5427e6341aa9275c1f62e3b0c9b150a195ae72
+CT = 4687e60e373bacd032f75f962df7edb9a3bbea785779dd9dfec551d11b8647432cc4320173939600
+
+Count = 143
+Adata = f94cfd1f8c7902a57784c10b9a5a
+Payload = 2218868033e17220655f0196dab6193c58293ca105d467d9
+CT = 4de42416bb8ef91663b2f727ab5e96664b5b6789f3381436a79a075ec2cacee1482b8328b697a3b2
+
+Count = 144
+Adata = 63f3fe58c348dc6bcbb44c3c370f
+Payload = 4a9bc26fb10000a57b9e73a8a3d30f66ef9de8782201ffa8
+CT = 256760f9396f8b937d738519d23b803cfcefb350d4ed8c4739cbe17b4edd64a3dcd2b8ae3352c04a
+
+Count = 145
+Adata = dec0ce763833305aa9c9efdc2c65
+Payload = 1b61b3ff3e4847a17f55f7565826b0e2ccc1368f4de32022
+CT = 749d1169b627cc9779b801e729ce3fb8dfb36da7bb0f53cdf54665c476d0741164685b0d81caca31
+
+Count = 146
+Adata = 592ef6784ee839a049e0d96257fa
+Payload = 32e5998b37987a38800f5bfe3132979ca1447314570aaef7
+CT = 5d193b1dbff7f10e86e2ad4f40da18c6b236283ca1e6dd18500d93b11fecc8b4560320878ba53550
+
+Count = 147
+Adata = 4a47a82b999a2a739959f153a091
+Payload = 84acfb6cf10b301558e5acbf41bbbe0b145dc66dc600f4df
+CT = eb5059fa7964bb235e085a0e30533151072f9d4530ec87303c2a41443578adaf31483bbb6b9f10b0
+
+Count = 148
+Adata = 4ceba98cc0ff5de1a7d580cf23d2
+Payload = d7c73d77a286df38aad116843620911c92e11486be5fcb0c
+CT = b83b9fe12ae9540eac3ce03547c81e4681934fae48b3b8e32232a856c07999e99a4701988b486ef2
+
+Count = 149
+Adata = 15e3b3c5794fececd703ac58ccb2
+Payload = 140882c5d3534bb0861e7ba9423e67439a02ee6f0b0b00f3
+CT = 7bf420535b3cc08680f38d1833d6e8198970b547fde7731cb3a6d50a92f3183c0c5090edc3c7f822
+
+[Alen = 15]
+
+Key = c1dfc48273d406a3a7b9176f80b2dc4e9a7f68134bab66d2
+Nonce = 1ac53ba965cdaeeef7326a37e4
+
+Count = 150
+Adata = 39ba54a410a58a5d11615a2163cc3b
+Payload = 67d9728a88f1fac3af43ed6d634ba902896bd226858697d9
+CT = 360f0fc714994e3b59448b50cdd61d511b4f09e0e5fb5ac826a51fe5b9b598a17eb3da10f936813b
+
+Count = 151
+Adata = 38b0cca09d69320105d24ee3f96684
+Payload = a8365ba9fcfff060b28895f7a2d786c5991a8f7758962caa
+CT = f9e026e460974498448ff3ca0c4a32960b3e54b138ebe1bbba673a94f4280e84724f4a2510165e9a
+
+Count = 152
+Adata = 76718dfb9c68acdd82592d96def39a
+Payload = 497be597dd695cb159d8a64f44049c3b549ac927837b1b90
+CT = 18ad98da4101e849afdfc072ea992868c6be12e1e306d68118865ab37be6f015316e0d177b6c2e91
+
+Count = 153
+Adata = dd719ba1710916a546233c1494a7a7
+Payload = ca452c21383ebc3fb584f0d59a227374854983f243a3f460
+CT = 9b93516ca45608c7438396e834bfc727176d583423de39713d903f67ad0d72fb8ffea2035216b769
+
+Count = 154
+Adata = d893fa2bd7c70e21a5934dc2e99037
+Payload = 3dd118ed65453d3d7844d8de78d7a43587ac5e9305b11464
+CT = 6c0765a0f92d89c58e43bee3d64a10661588855565ccd9750b885e3e054f519d0355db1bd589bb35
+
+Count = 155
+Adata = 97c60265a3a6993b97ac1b375a79b8
+Payload = a7375ba32251af0138bd9fd8fcd56a7c43ab2ca9a7fc0117
+CT = f6e126eebe391bf9cebaf9e55248de2fd18ff76fc781cc064a950e4bed4137e38787839e39924821
+
+Count = 156
+Adata = acfdf302ed116ac4755069d1704423
+Payload = d39d188f28521e4fb0a0c5e48e6d6efe4383c95b2535ea8d
+CT = 824b65c2b43aaab746a7a3d920f0daadd1a7129d4548279cca94dd97fd2a5d50eb7dd6234b40c525
+
+Count = 157
+Adata = d449f97164aae9a3046624e98810bc
+Payload = 758102470e221e30d87d2807b5f8b793a7a56c83eecf32a4
+CT = 24577f0a924aaac82e7a4e3a1b6503c03581b7458eb2ffb596f11450d5d2ba55ffb4a6cf7eab847a
+
+Count = 158
+Adata = 3e6c914a196e175079315b1c92b2b8
+Payload = 1db875c4b4f9dd4926dfb5604d6c4d21aba7d905aed9d1b0
+CT = 4c6e0889289169b1d0d8d35de3f1f972398302c3cea41ca164894e9218ecacd143fb62df69a13d33
+
+Count = 159
+Adata = e2b7b00d0cfbdfcc24f1819ae1869f
+Payload = d7a75bc621addccbbe162b86d536d69c887c278384af54e7
+CT = 8671268bbdc5683348114dbb7bab62cf1a58fc45e4d299f685a7c19bc9c2f8e36ed95015ebb679ae
+
+[Alen = 16]
+
+Key = d8a662ab8449bd037da0346a24565683a3bbbbd1800e3c1c
+Nonce = 166fb8d0e110124c09013e0568
+
+Count = 160
+Adata = 1c1c082eeb5b8548283d50cc2ace1c35
+Payload = 61fdd10938557080191d13dd6c3002dd445d9af988029199
+CT = 23c05927502a4ee6e61e4e10552d49b020643eab476eeacc867601fe79a122a7817819655183283e
+
+Count = 161
+Adata = cae884fa25adedd883ef4e7c855def19
+Payload = 8c7ae2c3c503e9072d6e04e44c2ea78fd24994503567a136
+CT = ce476aedad7cd761d26d59297533ece2b6703002fa0bda63160bb976ab072aec8fcea8eab3dc5aff
+
+Count = 162
+Adata = a350ed58c04473e113b9088b1fb9dad9
+Payload = 863f9a26182f131c594972398b52b3a01a9d314fd9390bf4
+CT = c402120870502d7aa64a2ff4b24ff8cd7ea4951d165570a1291b2c13a3f5e49ce35b9047ee1e8627
+
+Count = 163
+Adata = cb7090f7a465782f680fd44cbc558107
+Payload = bd94c9ad6253c25dc417f87b6e52e03621ccf4b3bff5b402
+CT = ffa941830a2cfc3b3b14a5b6574fab5b45f550e17099cf57fdd9fd1d469a9042b80e6458d25292b4
+
+Count = 164
+Adata = 914cf55a3fc739b5f87ac7518cc4171b
+Payload = c313bd213dc29c00691e25ce028884192e21a820003aece4
+CT = 812e350f55bda266961d78033b95cf744a180c72cf5697b1a8b8e82175ff30c69ea71d2cfb814ada
+
+Count = 165
+Adata = adc8b69d84ef7ae62f9ca9f371d3488e
+Payload = 85e4e053b976e06a64dfa8523130cdd802d3e7c3d6d797c2
+CT = c7d9687dd109de0c9bdcf59f082d86b566ea439119bbec9776fa36db27b2f84d1b8ab55e2fc89ab8
+
+Count = 166
+Adata = 29ed477994dd231d3a71157eb56d219d
+Payload = c77aae5fd09dc9bceee7428e0734d4b0556528396a58f909
+CT = 85472671b8e2f7da11e41f433e299fdd315c8c6ba534825c0e32058ea939036805a735198934a072
+
+Count = 167
+Adata = 494c8f931029a4919e2dcbc16512a8bf
+Payload = 1f47273103f265f963e498878361c06c01a5ffcfb630a161
+CT = 5d7aaf1f6b8d5b9f9ce7c54aba7c8b01659c5b9d795cda3437098c81475f8a1d8f3b0e63d499d387
+
+Count = 168
+Adata = 53200bc5d1f1fb0eeff02d2bc42f7d54
+Payload = a38231af405dc7b70c8dbc8cb84e6be8a0dc2e95fddc2ce8
+CT = e1bfb9812822f9d1f38ee14181532085c4e58ac732b057bd9d7317973878957e8fc1fa57a025a3e9
+
+Count = 169
+Adata = 61e0e28bf344a9a1b04b15156e06498e
+Payload = a0d3a94ba6bb3bedf38220d1cba7e91273ad19f9a1c436c0
+CT = e2ee2165cec4058b0c817d1cf2baa27f1794bdab6ea84d95b0aa1befae96e71b9d221673844b1cb7
+
+[Alen = 17]
+
+Key = 116f4855121d6aa53e8b8b43a2e23d468c8568c744f49de5
+Nonce = 924322a3ef0c64412f460a91b2
+
+Count = 170
+Adata = 03c2d22a3bb08bbb96b2811ce4b1110a83
+Payload = 1bd3b5db392402790be16e8d0a715453928f17f3384c13a7
+CT = ad736402626df0f9393fe4491eb812725ad39d6facf20b5b2f9340b0d48a17ae1cc71d7515e61ee9
+
+Count = 171
+Adata = f390387610741d560325b5d2010d8cd4a0
+Payload = c93aaa04279e451b6880ed7b7fdb3ca9e80ab76180434937
+CT = 7f9a7bdd7cd7b79b5a5e67bf6b127a8820563dfd14fd51cb717bae4c040561bcfcf80fd842ae8dd8
+
+Count = 172
+Adata = 891d7988a56415a7b433f463b1e80eaa62
+Payload = 2611612ccb5ffefaa73195509bb52c641472bca0dfd09d49
+CT = 90b1b0f590160c7a95ef1f948f7c6a45dc2e363c4b6e85b5bc9fb15d874feccb6b5f581fa470734f
+
+Count = 173
+Adata = 831c0fed5e600dd82d7d55669262a9a17d
+Payload = 08136e946e306cde0544ddc2f3f4a529c89c7b77a5e635c1
+CT = beb3bf4d35799e5e379a5706e73de30800c0f1eb31582d3da72589ee50d23f925f7998ab3ccac37f
+
+Count = 174
+Adata = 32ca9d412d4ef0e89928496e96c9de7f2e
+Payload = 695aaac402942de7d899cc3f741c7fb2b2d8247a7676cf29
+CT = dffa7b1d59dddf67ea4746fb60d539937a84aee6e2c8d7d555c0b608f331dca47c65f5c879f2d532
+
+Count = 175
+Adata = 0746b2e6149c7f55854e9ca3e6861bf0e9
+Payload = 8f958d796be0566512f0512dcebd2e12f3160b05b72ae955
+CT = 39355ca030a9a4e5202edbe9da7468333b4a81992394f1a9b039bd916e923e2fc1f7c60eb59916fd
+
+Count = 176
+Adata = 0e4cbd1c574d656112bf6e70a8f23347f0
+Payload = 367ecd1b71dfb96a84e2369f28705dfaebf0c73ed35d5364
+CT = 80de1cc22a964beab63cbc5b3cb91bdb23ac4da247e34b98ac07f2c0847069fe5be26e623033f532
+
+Count = 177
+Adata = 1a05ff12412bf728497536534c234901ce
+Payload = a9ccee975feb10f635d548a8502f7c8b6adbd2be74117257
+CT = 1f6c3f4e04a2e276070bc26c44e63aaaa2875822e0af6aabf4e66a2b210e5a03bb10ff2926ed8a48
+
+Count = 178
+Adata = 3bd063a51c71fab5aeb47e7f8f958d796b
+Payload = 7df6220599d6235eb450989b6f0cd6c96db62b0d13afc4f4
+CT = cb56f3dcc29fd1de868e125f7bc590e8a5eaa1918711dc08ec90169d0c5c11fff8f255fedb13a99a
+
+Count = 179
+Adata = f0d334e0a27c3d00d56b15c2ee426e6347
+Payload = 6f65a24344c32debaf9f8c3fa426fe0b139e8ad1c8b1fbbb
+CT = d9c5739a1f8adf6b9d4106fbb0efb82adbc2004d5c0fe347170141cf3f207c4f0fc1b0238477cfad
+
+[Alen = 18]
+
+Key = e67f3ba11282d61fe36e38cab7b559c2fd9cbe8bf7eb5863
+Nonce = a727ed373886dd872859b92ccd
+
+Count = 180
+Adata = 68d199e8fced02b7aeba31aa94068a25d27a
+Payload = d7a954dae563b93385c02c82e0143b6c17ce3067d8b54120
+CT = c6cfaa1f54d041089bd81f89197e57a53b2880cefc3f9d877e30b2bcc3f1ea9ec2b8f28bf0af4ecf
+
+Count = 181
+Adata = fc4bbe329a86089ebe2a2f3320dad55a9bda
+Payload = a206a1eb70a9d24bb5e72f314e7d91de074f59055653bdd2
+CT = b3605f2ec11a2a70abff1c3ab717fd172ba9e9ac72d961753a6e6844102d6bb86986c030765d3393
+
+Count = 182
+Adata = d8741e540330692d83cc806a8ac1c4742be6
+Payload = 56ef76dbec6b8b46f5b7b4e311c0baaa6fcf54c69c0b9c3b
+CT = 4789881e5dd8737debaf87e8e8aad6634329e46fb881409c3f92a80b1d82f8c1dc32bfe64adca12a
+
+Count = 183
+Adata = c8b1992dfba55b4ab86b480546c861655e1a
+Payload = 2729636112f2abe2c76ea5e52a3f80b0f882f0f3b6f7c806
+CT = 364f9da4a34153d9d97696eed355ec79d464405a927d14a12fb48ad162b0c0678674d79d26a6b5ef
+
+Count = 184
+Adata = 347e12eec56e95aafcc7d25bf10fc756b4e4
+Payload = dd433eb7422c7c4dccee57a1679633ced3b5f08df763d457
+CT = cc25c072f39f8476d2f664aa9efc5f07ff534024d3e908f081c7cd81c974d985bf24b7fe9542141a
+
+Count = 185
+Adata = 45b35a04d6e2645e9a5aef206ed4e36199c9
+Payload = 70523bc397417e09d791a4976960e02636ca7144a5681cf7
+CT = 6134c50626f28632c989979c900a8cef1a2cc1ed81e2c050a7f6a5c04e59896074e1594706ab27e9
+
+Count = 186
+Adata = 378b48531fe34f55125b2f14f59715dd6ef0
+Payload = 514cb462dd4b117f26cac22062fcbeb353650c71649a7b3d
+CT = 402a4aa76cf8e94438d2f12b9b96d27a7f83bcd84010a79aa9d16c3ab79276cff345444511940a9d
+
+Count = 187
+Adata = 73ed686d6fecdc031cd97653137f269d6537
+Payload = 7f0c2b261db3f3de0ce3a733f4b8c446c374567d96d00379
+CT = 6e6ad5e3ac000be512fb94380dd2a88fef92e6d4b25adfdef92bf8aa6facbe6f9607ea02b54a1bf0
+
+Count = 188
+Adata = 5b0441107e5560be94f030a41cedbdb116d9
+Payload = ebb3e2ad7803508ba46e81e220b1cff33ea8381504110e9f
+CT = fad51c68c9b0a8b0ba76b2e9d9dba33a124e88bc209bd238e4936ee93b5c7a302913292df33c1700
+
+Count = 189
+Adata = feedcc5f8524fe7d49bcd178415b9f4c450a
+Payload = 3216dce3b8b1ce0e79e40fffcac728ab191aaaf319d971d3
+CT = 237022260902363567fc3cf433ad446235fc1a5a3d53ad7493426b6193afe765a76b3dec00266e69
+
+[Alen = 19]
+
+Key = e0a29a2c7840cf9b41de49780b9ee92d646a4bfc5b9da74a
+Nonce = fc9fd876b1edded09f70b18824
+
+Count = 190
+Adata = 36e15baafa0002efbb4bb26503b7e3b79f6c68
+Payload = 344dc8b6bd66a1fbbe330a95af5dd2a8783dc264d6a9267d
+CT = 43b3b96aa5a54378f3bb573ffda3e154aa7f425fc3008175b60a77b9d38740356b544b1c0f259086
+
+Count = 191
+Adata = 712b788f0276e2b5a58be80f9114a12ab2a268
+Payload = 6d0546d4e95d1cfcb37a8f88a62064f5d95791311511535b
+CT = 1afb3708f19efe7ffef2d222f4de57090b15110a00b8f4535f750bb4cd42db3038e2c1622b72cea8
+
+Count = 192
+Adata = 07f77f114d7264a122a7e9db4fc8d091334a03
+Payload = 05024ce13b9057dd2c509db7dbcbd5585e4e64a1e2e380ff
+CT = 72fc3d3d2353b55e61d8c01d8935e6a48c0ce49af74a27f761e77b59ef7eeeae35bb53bb9543b64a
+
+Count = 193
+Adata = 899b036138cee77cd28382ba27984d858a6351
+Payload = 77b8e735b13b10e45e411ab94c6fe1a9eb89f0a7af40ff1a
+CT = 004696e9a9f8f26713c947131e91d25539cb709cbae9581244a60fdb473098a11b2176d37b2c4643
+
+Count = 194
+Adata = 4b000440a8484a5201cd54aec058919769772e
+Payload = 6b21800ae599a15254bb33f0bb080788fb6e9fa054bfd8b2
+CT = 1cdff1d6fd5a43d119336e5ae9f63474292c1f9b41167fba58d4afc30a7f672ea34e05ec1843d848
+
+Count = 195
+Adata = 73a222e681ed1ca47d92a6dd90625d895fbf29
+Payload = bfa9d9af6e1f32b6626a1cd89b1c32513b5b50a18ddab028
+CT = c857a87376dcd0352fe24172c9e201ade919d09a987317204ef270e0f3b5e3ca0b8440af65c76e85
+
+Count = 196
+Adata = 7109a3a36b286059bc1a1abb2767c92f884e3f
+Payload = c68b1bc0050e19780ab53efbea175634f70a7245d966966e
+CT = b1756a1c1dcdfbfb473d6351b8e965c82548f27ecccf3166ffb66991b38a0345fbbff5f2362f87de
+
+Count = 197
+Adata = cd15973753b94b77bb4b778de8b3b0cabbde85
+Payload = 4256f1c9b64390fe2120df9fd38e497c2903c2ca5679ab75
+CT = 35a88015ae80727d6ca8823581707a80fb4142f143d00c7dd033a087c44c2e44adbeb333aa9ded10
+
+Count = 198
+Adata = 6e5e0793855f7145e13a5872f563e5ec61cfd2
+Payload = bb0036b34b0c20094d335a8c74f6b3dea42eeccf4145192e
+CT = ccfe476f53cfc28a00bb072626088022766c6cf454ecbe26ff9c8713422fe38d5bbf2dedccbffe10
+
+Count = 199
+Adata = f844684f5404e7d8eedfa20394b40b4f5d910a
+Payload = 86afa9cdd743916563ebfd3adbdd56e015ea3a4ebc61cfe2
+CT = f151d811cf8073e62e63a0908923651cc7a8ba75a9c868eae75de56eabcf8e02c1a27705adef2732
+
+[Alen = 20]
+
+Key = 26d0a3a8509d97f81379d21981fe1a02c579121ab7356ca0
+Nonce = 8015c0f07a7acd4b1cbdd21b54
+
+Count = 200
+Adata = 093ed26ada5628cfb8cfc1391526b3bcc4af97d9
+Payload = 37ab2a0b7b69942278e21032fc83eba6cdc34f5285a8b711
+CT = a3a60b422eb070b499cf6da0a404b13a05cedda549c6b93e6ca0e07e04674f21a46df2659a5905fb
+
+Count = 201
+Adata = 7df13c9d2247aa40af7bbe2da98bd366d8b47b43
+Payload = 93925579b6367ff592ecbd59495fdeccb50f31ea4fa390bc
+CT = 079f7430e3ef9b6373c1c0cb11d884507d02a31d83cd9e93836597806f5da1d176c745d95c4fa46a
+
+Count = 202
+Adata = 7f369bbc99b6f08049eeb43566269a174829d4dd
+Payload = 8363aef9c7c34e1f8149de46c97d5ac79d38c6ed31ab1d12
+CT = 176e8fb0921aaa896064a3d491fa005b5535541afdc5133df826dda99111691993027628c70ff6ae
+
+Count = 203
+Adata = 04aa8442179f62babad0c006e36af0c21105f27a
+Payload = 17281acb525b13653000ab45d86e70106c10a93c99b18f76
+CT = 83253b820782f7f3d12dd6d780e92a8ca41d3bcb55df8159d074b018143a7ea1b5369b7f80eae20d
+
+Count = 204
+Adata = 997e646014f19a53beab8877ca6022bef23016f1
+Payload = 5d48a71557608736eded309027a80349a18e9ce5dee2bc6a
+CT = c945865c02b963a00cc04d027f2f59d569830e12128cb2455db17d3f75214c3cf39858617cfee57a
+
+Count = 205
+Adata = 60ffcb23d6b88e485b920af81d1083f6291d06ac
+Payload = 6c9d11cfb64d96bfab61c04a25d9e19294fb7330fb4847c8
+CT = f8903086e39472294a4cbdd87d5ebb0e5cf6e1c7372649e79550998376e61e11a5a69e9f8fe1c329
+
+Count = 206
+Adata = d574632658bf456dfbb11c2653602ed0f4dae777
+Payload = 7d41688c86d5e3bc53966810f2299fdd732e3471fb0a88f9
+CT = e94c49c5d30c072ab2bb1582aaaec541bb23a686376486d6a1b0d05a7ebc657c3235479893bf7e5d
+
+Count = 207
+Adata = d896ed60128f4bb0277d3af94c5138cf91697aa9
+Payload = 8c7ae2c3c503e9072d6e04e44c2ea78fd24994503567a136
+CT = 1877c38a90da0d91cc43797614a9fd131a4406a7f909af1980c98c8959c158ce209aebcbd554f250
+
+Count = 208
+Adata = a350ed58c04473e113b9088b1fb9dad92807f6b6
+Payload = 49bc9d3bcf3c22daa8cf55c1b59d4bffddc2412d60518e98
+CT = ddb1bc729ae5c64c49e22853ed1a116315cfd3daac3f80b7573175f9105cd16ee384465ebb232200
+
+Count = 209
+Adata = 1db5887001204194e8b5dcee92c8af8fa5f7321f
+Payload = 25f3788e0d3dd8f5821faa4e45a9d6b3995fd881f927135c
+CT = b1fe59c758e43c636332d7dc1d2e8c2f51524a7635491d732b67e993384f2e7229d1838efd040d99
+
+[Alen = 21]
+
+Key = aac60835c309d837aacc635931af95702a4784c214283ebb
+Nonce = 0e20602d4dc38baa1ebf94ded5
+
+Count = 210
+Adata = 796e55fbe7bed46d025599c258964a99574c523f6a
+Payload = e8610756528f75607b83926597ef515f4b32a8386437e6d4
+CT = e0a3d5f43e688ce104f4ae1a4fcd85500aa6b8fdbcd1b8d3003c0c3b7369e79339433e1754c0937f
+
+Count = 211
+Adata = 5170836711fcb1a350b087907d8a17c7637aa1595b
+Payload = c61b0c1845fa9b2e0013b3fa9a8cb4f4fbbc6846f63ed180
+CT = ced9deba291d62af7f648f8542ae60fbba2878832ed88f87120a7f18d021833b167bf330c4858239
+
+Count = 212
+Adata = 2a68e3fe746f593c1b97cb637079c3e5ee352c107a
+Payload = 10c654c78a9e3c0628f004b061e28c39a3c23e7250f53615
+CT = 18048665e679c587578738cfb9c05836e2562eb788136812ca9698d9a88e892c364e57dd35c2f17a
+
+Count = 213
+Adata = bf38ca0e89b8f5ccd29387f7f193ab5a967caa715b
+Payload = fa3a959fdff853c39f76da626094a1ea6dbc78bd2f091a79
+CT = f2f8473db31faa42e001e61db8b675e52c286878f7ef447ef3839d6f7e20a2e343f4c4da9eb9be13
+
+Count = 214
+Adata = bee00f2f75a4415ce993d2d14a6d8e01d1d59a48f6
+Payload = 76d12e3c4c5d990bf563c60aa4999e52998d887f97477f6d
+CT = 7e13fc9e20ba608a8a14fa757cbb4a5dd81998ba4fa1216a6630bfb7a2a2441e020efdf36274b72f
+
+Count = 215
+Adata = d5b614e4e8f72a5d8b1ec2b375da5dac64c2cc30b1
+Payload = 693fae7af84aa397f0b2baaed9b3c7953f75e7424c49b634
+CT = 61fd7cd894ad5a168fc586d10191139a7ee1f78794afe833866bcee343ec5aae61f9effa19b99d3b
+
+Count = 216
+Adata = 33f11aa36d8ab0fc53486839a576b31ee915dbd769
+Payload = 56ce9a09f38127b14dbbdcaa59f363c92a3b9843ad20e2b7
+CT = 5e0c48ab9f66de3032cce0d581d1b7c66baf888675c6bcb00331b60eb252f744a06b4a95aa9f4e7c
+
+Count = 217
+Adata = f40bce1a6817b29b9e8b56f214fcca7dfde17e7ee6
+Payload = 5cd8986e974d09ede34ba68fd81d6109a64092e7fbbaf87d
+CT = 541a4accfbaaf06c9c3c9af0003fb506e7d48222235ca67a4153778a644cb2469cef3ad125e257bc
+
+Count = 218
+Adata = 53c457d8d4d4ab95ba116c28b82c16743cb09de9fe
+Payload = 9c3c610f204d98702dd91ea28e0cc14830b26bb5e2ee0349
+CT = 94feb3ad4caa61f152ae22dd562e154771267b703a085d4e7013e1c34dbc5efc7bcd4f8e52797644
+
+Count = 219
+Adata = c7acf1b17609dc336df1006ffac6497777cdfd497c
+Payload = 90c5dd9db0316dac89db18f70491bdf0a06a6a7f72b77d9a
+CT = 98070f3fdcd6942df6ac2488dcb369ffe1fe7abaaa51239d66aed667c761b7dea44822e30cff671f
+
+[Alen = 22]
+
+Key = 671544bf2988056f7f9ccd526861391a27233793a23f811f
+Nonce = 0a259148a1d081e0df381ecd0c
+
+Count = 220
+Adata = 61dafc237cb52f83ab773ba8a885462b6f77d4924611
+Payload = 576b069ae2713f53d2924c1fd68f786cb2eec68892f9e1be
+CT = ce06b3d09b02921f290544032a081a7766612940048867281bb089af0245792c16e6320cf5ffa19e
+
+Count = 221
+Adata = 87e49b8164e7052becfa0c966991637b38df833fc5f7
+Payload = d7eb0d7dd737805cd3b8dbf451aeea2fa1f6a96eb58cb428
+CT = 4e86b837ae442d10282fd3e8ad298834757946a623fd32be3cec29bd5df92363d6bb75456f5cd32b
+
+Count = 222
+Adata = d302a518d7c625756d3e4c8cc2b1d973a19107c945fc
+Payload = 77d8c9e6321314524afd05b7ad599c29f4eedda9e9f0763f
+CT = eeb57cac4b60b91eb16a0dab51defe32206132617f81f0a901ca82cddb78a2fe3904d1d8bf6fe5b2
+
+Count = 223
+Adata = 6566bb616a94bb03df5c26b722bcd38d516285c5f6c1
+Payload = abbf28b3ae164051648293d0b94e11f5af8468450005c7c0
+CT = 32d29df9d765ed1d9f159bcc45c973ee7b0b878d96744156d095ad121f0f76f07b715cad996def52
+
+Count = 224
+Adata = 141be3601e38185a9fa1596d2ee406415c9673af32f5
+Payload = b67d50110f844b36a00d352123012a1123c7c3cba959dc48
+CT = 2f10e55b76f7e67a5b9a3d3ddf86480af7482c033f285ade8529ec8f477462dc2409482c3479756d
+
+Count = 225
+Adata = a2969243b0955402ab45a430fef2ef9e0c025006732b
+Payload = 2a63f7b09b43fee65738e8115bd8419b3ef3e8f86eca707f
+CT = b30e42fae23053aaacafe00da75f2380ea7c0730f8bbf6e9b14fe8dbb3c361ea61d7b44e689a1c48
+
+Count = 226
+Adata = 87faef55c54250c30232ccaf5efa1ff41b6243b2a5bc
+Payload = 59dad755af92c29522da4348ab9b3037fe87004f5fa1394a
+CT = c0b7621fd6e16fd9d94d4b54571c522c2a08ef87c9d0bfdc54f0659fae291f943f2f3b33688602cb
+
+Count = 227
+Adata = 5d895fb949344e603ce5de029842b20d2bb614ecbbb8
+Payload = 64d8bd3c646f76dc6ce89defd40777fe17316729e22ba90f
+CT = fdb508761d1cdb90977f95f3288015e5c3be88e1745a2f993af4e3a7a20390a8da264299712a34e3
+
+Count = 228
+Adata = 74cc8da150b0bacdefa8943900b4ea047611d96be70a
+Payload = 0c3c9a634a000f00be003846eac7482e303a5bef3a70fe75
+CT = 95512f293373a24c4597305a16402a35e4b5b427ac0178e3a7f79d2b5a9bde5bd453bc8a03e971d8
+
+Count = 229
+Adata = 65f6adbaaa803dbad5ba9cb6d231314d55147cc61399
+Payload = 712c788928c8a1562bc1f3f0eb1286e15c3405f6a6fa0443
+CT = e841cdc351bb0c1ad056fbec1795e4fa88bbea3e308b82d5ffccebfb8c833833db40e98a1950fb70
+
+[Alen = 23]
+
+Key = 90e2c63b6e5394b1aeec03f95a9d13a01a7d4e9d58610786
+Nonce = dada5465eb9b7229807a39e557
+
+Count = 230
+Adata = f5629ca0eea589f6cf963d875a7d2efb656983f2dd2231
+Payload = 44dd098b1f869d670a8a841900c4bef023a1946a0c278354
+CT = 6b38ca85450e05e7b9362ed7e6e291a130ff233b5a561cdef7ec84dd992fdf98514f845dac8f656e
+
+Count = 231
+Adata = d43d7753530a7280b76221906dca85d396b6cf05125018
+Payload = cea19562328bd1fea889f575db6a28a14b7d06fb9f9c98bb
+CT = e144566c6803497e1b355fbb3d4c07f05823b1aac9ed07313613ed15d527d9dc58ab6893e723db58
+
+Count = 232
+Adata = 75650ce366757618af20205b69af7e5d4e82c398c00101
+Payload = f0641f595b791edd860977fcf699688587a354e053e9c7fe
+CT = df81dc5701f1865d35b5dd3210bf47d494fde3b105985874ef8728d1bf3a2d93db3266bafadb7c26
+
+Count = 233
+Adata = c00f1b8066677c63e898fddfb8a1b482b536963da0628d
+Payload = c7486a084f8475e6f5138e8d6e9f42a1de90f05aa88a362d
+CT = e8ada906150ced6646af244388b96df0cdce470bfefba9a7a5bce94d7564d297fe87730f1a36acf4
+
+Count = 234
+Adata = 5a89ab6b26b2ca78f98a8f8409fe8008b97ba9ef185d41
+Payload = 091ef698e16dc43a11d3ea005d5a5cdb7f1bdb5665a6c81e
+CT = 26fb3596bbe55cbaa26f40cebb7c738a6c456c0733d75794cd971b07fc14c512b8df6dd964b129d0
+
+Count = 235
+Adata = 5d24d80f22afe713c4076c200c1bab36917907fde7b6d3
+Payload = 62f204394b367c4410746001e02dfd171858396568fdd43b
+CT = 4d17c73711bee4c4a3c8cacf060bd2460b068e343e8c4bb1a192b781dc94448d4a0f6a439a716339
+
+Count = 236
+Adata = 4a47a82b999a2a739959f153a091a65c4d7387646da66b
+Payload = ac1cd5ba4997af91dbd74aee7730f9ee92cf8a360ca96a8a
+CT = 83f916b4131f3711686be0209116d6bf81913d675ad8f500cade9533b272e0a3edeba68362b057b4
+
+Count = 237
+Adata = d9fc295082e8f48569eb073ac1b9566246728fc62ccaab
+Payload = d0a249a97b5f1486721a50d4c4ab3f5d674a0e29925d5bf2
+CT = ff478aa721d78c06c1a6fa1a228d100c7414b978c42cc4785d68df8ff28345be4d83541a72071059
+
+Count = 238
+Adata = 720a9dc3e33ac080775a06f67f4a6591c37d0e101944a0
+Payload = 77fb98f24172f5d5edadbf466ee910855a71d46090b789ee
+CT = 581e5bfc1bfa6d555e11158888cf3fd4492f6331c6c61664caa7ec8892be6a18458c663665495035
+
+Count = 239
+Adata = 13cdaaa4f5721c6d7e709cc048063cfb8b9d92e6425903
+Payload = 77fb98f24172f5d5edadbf466ee910855a71d46090b789ee
+CT = 581e5bfc1bfa6d555e11158888cf3fd4492f6331c6c61664862fda880e45e891a3a50da7e14344c8
+
+[Alen = 24]
+
+Key = 13cdaaa4f5721c6d7e709cc048063cfb8b9d92e6425903e6
+Nonce = f97b532259babac5322e9d9a79
+
+Count = 240
+Adata = ad6622279832502839a82348486d42e9b38626e8f06317c4
+Payload = d7c837971b973f5f651102bf8d032e7dcd10e306739a0d6c
+CT = 4709600418f2839841e6d126359f6982bdb53acc7ff209635623d15b24184481eadc63bb8c878fc4
+
+Count = 241
+Adata = ad4833aa53218949cfd724814a43889a74a2114bbef4cf37
+Payload = 7d672bccd0fb01ce79320ed61779146aa432038daa13cb41
+CT = eda67c5fd39ebd095dc5dd4fafe55395d497da47a67bcf4e614c3e546273f0aeef207bd3f4d32fca
+
+Count = 242
+Adata = 54a723826086c7175e8fdc854b62d780de6ac1f90b57dd3a
+Payload = 0e1b73df74982f535a5fb08bc13d22515ee10969efe033bb
+CT = 9eda244c77fd93947ea8631279a165ae2e44d0a3e38837b413c6395ce9aee2e22ac0606beb140185
+
+Count = 243
+Adata = bec02d7df4cc3deefdd7e7d3ea82d381c870ad46bc06d64f
+Payload = 9a55aff269b180118ff0ea99e851c7474d19d23e641f16a9
+CT = 0a94f8616ad43cd6ab07390050cd80b83dbc0bf4687712a661e4f02150bedd86dfa49f52b214239d
+
+Count = 244
+Adata = 1b8090d712e0ec95a01bc3aeb6f5230c67c355e0ed68043a
+Payload = ff19294e8faed8353dbcab0b146e2ef928dd2680833424bd
+CT = 6fd87edd8ccb64f2194b7892acf269065878ff4a8f5c20b2f0e82b9f04bfc0cc0ba432b5135450c2
+
+Count = 245
+Adata = 5ed0b9f25d07b26717cdcb2507bef9d681ecd9389831ac15
+Payload = db1eba6ac4a79aa1d97838d263c7c4ffa7d354770e762805
+CT = 4bdfedf9c7c22666fd8feb4bdb5b8300d7768dbd021e2c0a2e64c82b60880c5c7506321a1060a481
+
+Count = 246
+Adata = 55f16fefaf2168aebc61b5e01d9e1f7bfe215eaaef118974
+Payload = 012d45168505ca9fde5aed123875639a207d473b993dc7b8
+CT = 91ec128586607658faad3e8b80e9246550d89ef19555c3b77152f64dc993b36ad9d5d12bb52b1ad5
+
+Count = 247
+Adata = 9893bf14fd3a86c418a35c5667e642d5998507e396596c50
+Payload = b205f26d6c8a8d6085ab28d595703cae046f96d82093082b
+CT = 22c4a5fe6fef31a7a15cfb4c2dec7b5174ca4f122cfb0c243e5c69256b6326ebb7ee6e677d396765
+
+Count = 248
+Adata = 244b840085bda9576c8424bb05a925a6b09cad2d0528ab8d
+Payload = 549ba26a299391538b56ce4bd71dbbfd96995836f8915ca5
+CT = c45af5f92af62d94afa11dd26f81fc02e63c81fcf4f958aa2083dac565c7a63908f0022e2867bb68
+
+Count = 249
+Adata = 9e8d492c304cf6ad59102bca0e0b23620338c15fc9ecd1e9
+Payload = 9e9dbd78a1066800ae33253be6104015158a0187e4f38116
+CT = 0e5ceaeba263d4c78ac4f6a25e8c07ea652fd84de89b851968242fe32958ea32e670ae1b3543974f
+
+[Alen = 25]
+
+Key = 90851933d4d3257137984cdb9cba2ca737322dac4dbd64bc
+Nonce = be02df3a840322df8d448c600c
+
+Count = 250
+Adata = 69a9dd9ac8be489c3a3f7f070bdaca10699171f66ab3da9351
+Payload = ba1785a149cb8b69a4e011c11a3ff06f6d7218f525ac81b5
+CT = 89ab2efefa8406336d9e2245199fbc9454f0ef650b9ed0f446c7246bd3130803bf8d703ef5bdf15c
+
+Count = 251
+Adata = 0c39a72f0f38d2713c164b0f870646fc65b9838a322ecfddd0
+Payload = 263dc4fb5cd8798ce0f183a816e51fafba167533dde1bf96
+CT = 15816fa4ef97f4d6298fb02c15455354839482a3f3d3eed7096a6a4422e582c5d02973952ac80e5f
+
+Count = 252
+Adata = 911d9f5c4c34c2f4b69be1e253d43fe729e2ab2622130394b1
+Payload = 7b5da2c283116713f3d80c7907114270964541e03ab80d50
+CT = 48e1099d305eea493aa63ffd04b10e8bafc7b670148a5c115965f6df4332fe7a2cdc4d1b80e28a34
+
+Count = 253
+Adata = 8a961df9c23f6d5ecdafa94c61164a22f460a1bf7415258d39
+Payload = 541a2b3ee25022c92fdc6783a6cbde90680ad3dc41868e5f
+CT = 67a68061511faf93e6a25407a56b926b5188244c6fb4df1e18bed174081b2170ffc6ab53b54c9ddb
+
+Count = 254
+Adata = cac7a248a4d4e96a9733627e247234995d6aa57e491498118a
+Payload = ebb2e893da9f32c363f98bc76fd14eda59e7cc620070f6d3
+CT = d80e43cc69d0bf99aa87b8436c71022160653bf22e42a792bac3d3a2b9ef6d4c8715f9a5c6fe8245
+
+Count = 255
+Adata = 41eacf70d05a6d0cdbdd38f197a52987def8fde37f332eebd9
+Payload = 199cca0d0e1c70ec405d6816cbddc69f8ada624f2c168891
+CT = 2a206152bd53fdb689235b92c87d8a64b35895df0224d9d07f9610c82fe9a7c78e8f1980e886b446
+
+Count = 256
+Adata = 78b6ed20ed85337c969618bd41917cd85c37e7c35c3a12e25f
+Payload = ca481f557306f9ce386edd0cfde375a550cb5b574be524f7
+CT = f9f4b40ac0497494f110ee88fe43395e6949acc765d775b6aab366637ec41d0bf557f578be424a8b
+
+Count = 257
+Adata = 87faef55c54250c30232ccaf5efa1ff41b6243b2a5bc93e7cf
+Payload = 6f1b4ff66d3aec7b0c0d9e202acc52722e15bca0983291e0
+CT = 5ca7e4a9de756121c573ada4296c1e8917974b30b600c0a1e57a5b3ae26469d229425f887ad5a2a1
+
+Count = 258
+Adata = 7f19ac3e53a629a2df1cb56d68fde0c80a46be40a996830e2a
+Payload = 7533c88ce55c2243b64b6c5bd01aed4dd6ac8bb9fd333e06
+CT = 468f63d35613af197f355fdfd3baa1b6ef2e7c29d3016f476ce4fe492062f74bff4c3c0e9ea849a4
+
+Count = 259
+Adata = 0516a69bfd8785ad001367b51e5410b75c11b761be08b9eea5
+Payload = 19ea09a9bfd10db2a74e398859d8f4831fa5749767773acf
+CT = 2a56a2f60c9e80e86e300a0c5a78b8782627830749456b8ead47ffc17b871f530f62b9f9aec98509
+
+[Alen = 26]
+
+Key = 5c5d02c93faa74a848e5046fc52f236049e28cd8096dcac6
+Nonce = 54cbf2889437673b8875a0f567
+
+Count = 260
+Adata = 09fc21ac4a1f43de29621cacf3ad84e055c6b220721af7ce33bb
+Payload = b4da43ebfe9396b68f4689fba8837c68d0064841c6ddd4a7
+CT = d40725397229021a18f3481e3a85f70445557bb2a85e4ae8101a34c777e918e16186fda05a386572
+
+Count = 261
+Adata = 10f0c45d06a138a964fb11b2d450620a2977bcd2952afe371cad
+Payload = 7b628930d44e22907277db057395601b82b65479fbd59613
+CT = 1bbfefe258f4b63ce5c21ae0e193eb7717e5678a9556085cc1e79234882846d916dabae40b1bd055
+
+Count = 262
+Adata = 64dbb170a037b36beed28a2637c87830e2b23f8eea6cd9a7331c
+Payload = 9db30b669fc5d25f05e0dc708d597da6ddce2dacc85ae99c
+CT = fd6e6db4137f46f392551d951f5ff6ca489d1e5fa6d977d3e35499e3c09dc384eb41344ee8be3769
+
+Count = 263
+Adata = c47de6608546a02c6eebd6628c9123f6936c0154d3df52a367e5
+Payload = 62036cbed3666d85624d3dc9c1f437454b9ab5c03ce0de92
+CT = 02de0a6c5fdcf929f5f8fc2c53f2bc29dec98633526340ddd605189608ce40b237dde7bed6fde487
+
+Count = 264
+Adata = bab7e36098d59d3a31d7784d549aebfc6938bbd0612c85c0edb7
+Payload = 5c9bc739f6b6fe4214f3c6aad307d1f208892d79de010e37
+CT = 3c46a1eb7a0c6aee8346074f41015a9e9dda1e8ab0829078c31f69c847440be20bd08cfef330002f
+
+Count = 265
+Adata = 8a9716135fa38c250e249f6712f7cb3ad9210d7278b53d599df9
+Payload = 0df109298083d3896214b84ff6edb11e9cfdbd88f5702839
+CT = 6d2c6ffb0c394725f5a179aa64eb3a7209ae8e7b9bf3b676ca83622b127fa50fc9637998c0ddd44d
+
+Count = 266
+Adata = 2d52447d1244d2ebc28650e7b05654bad35b3a68eedc7f851530
+Payload = 518f651f6d82f670b63767ad8476ed8fc24df12a45110611
+CT = 315203cde13862dc2182a648167066e3571ec2d92b92985e81e738b9e4b0dc7b7a39eb7d03adc64a
+
+Count = 267
+Adata = 3cba0fd2bb16ae1d997cbe659a2dd101885c97f2322b0172b5d6
+Payload = e91a694bea2d351928b6098660d49f382c087f6777de159c
+CT = 89c70f996697a1b5bf03c863f2d21454b95b4c94195d8bd3d298c05b1d2e597f44f8621ecd11ed16
+
+Count = 268
+Adata = c7f93152016bba584dadc6002ec493a46305726068886d2340da
+Payload = 2d14792ed349a878b2b879e7fa5f438a50e36947ce827e73
+CT = 4dc91ffc5ff33cd4250db8026859c8e6c5b05ab4a001e03c5fd5221fceecbf0dc7211a1aec06793a
+
+Count = 269
+Adata = 799cac048eaccded37ca6a70dd89595e1ee04606212da5572679
+Payload = 315b8d95938d304015bbc94ea03c21f6dc25c90f991ba680
+CT = 5186eb471f37a4ec820e08ab323aaa9a4976fafcf79838cf5c25f00b862b49fcfe8447949f39787c
+
+[Alen = 27]
+
+Key = 0234dae5bd7ae66c67ff0c1a3f1a191a0d7bceb451bc2b7d
+Nonce = 16d345606a315ad2406abbcb43
+
+Count = 270
+Adata = c37fdf7449fd7e943595d75e977089c623be0a3926e63fdbbfdf4a
+Payload = 0f960a89a7e806f8709047cb7a2e7c4211ad724692c88a05
+CT = 3907880d25f910eab12dd14e704d1b33ea7c453634d54da2a461f44dac1112ae3f9c65671a931d3e
+
+Count = 271
+Adata = 85f647d940a6d1acb6b7851912f807063515631eaabaa019dcfb99
+Payload = ab40a4baa39b0e568bf2193fecbc36b84c76bb50523b2912
+CT = 9dd1263e218a18444a4f8fbae6df51c9b7a78c20f426eeb5ed15db6e142ee07b59eb5b0ad3a59194
+
+Count = 272
+Adata = 79ae14843b2e7ccf0fd85218184f7844fbb35e934476841b056b3a
+Payload = b74c06d9077c568762796d5be14f3563e7205a6e9bc65bcb
+CT = 81dd845d856d4095a3c4fbdeeb2c52121cf16d1e3ddb9c6c203f11f66b74366caeca8dbded2bf17a
+
+Count = 273
+Adata = 542d86fd7ff591f97e6926a090553538bc3b8a6bcd45f2e29c7d9f
+Payload = f2179beb5635a6d8a8340acea0ffcf4428e5de1306a8c12b
+CT = c486196fd424b0ca69899c4baa9ca835d334e963a0b5068ced925fb9a4cf6b6bf17f72ab044653d1
+
+Count = 274
+Adata = 4392c3043287dd096b43b4a37ea7f5dc1d298b0623ccbf4fd650a4
+Payload = d1a9e4593bc3d02c407e84a1736e587c1819c72195a07d57
+CT = e73866ddb9d2c63e81c31224790d3f0de3c8f05133bdbaf0d1f677deca1bfda83c1b9223aaaedbfc
+
+Count = 275
+Adata = 966954582e78e99ba68d6ffaf794b55a82325834ec4f373b2bd227
+Payload = 15b94910853a8f23dfb8b31c0262b8461f777075cc0937e9
+CT = 2328cb94072b99311e0525990801df37e4a647056a14f04e12937871932a7ca3e1e27a90a7f73694
+
+Count = 276
+Adata = b7aca715dcc402565cb711b001f21e8e95ec54c4afab2e2dcc8a2f
+Payload = fd1681cc306518bf77766f55226afac3eb21e31ed897075c
+CT = cb870348b2740eadb6cbf9d028099db210f0d46e7e8ac0fba0464ff4ddeccbd523a5ed3b32337f7c
+
+Count = 277
+Adata = 290a36f7daeeeafca4431446b396dbec0bea0a1f6f081418811656
+Payload = 0804fa48fc76f98bb021e3501bef8875b64a3b508adf8594
+CT = 3e9578cc7e67ef99719c75d5118cef044d9b0c202cc242332f68ed5e44a71c5ba8bade07b7bf5495
+
+Count = 278
+Adata = f0739a855422310a21ed863376bce9d75dc7c687b9b535cb7a05cc
+Payload = 4f5c6d80a3955f12f4d2594e02a045c42fabb11d90817fff
+CT = 79cdef0421844900356fcfcb08c322b5d47a866d369cb8583b5dc1fbe32743e257b7c1c9d624adc8
+
+Count = 279
+Adata = ffac0edb0b62977bb5040e4128a48deaf711f5e6a84d8f677341f3
+Payload = 5c29c458212d010a0d9c5a547aba1138eb4ce94742fef01e
+CT = 6ab846dca33c1718cc21ccd170d97649109dde37e4e337b9e53b654de1976294897cae0476ac6248
+
+[Alen = 28]
+
+Key = 6351a67fd6daabd2fd49ee944dd41dd37301f958dd17fcc3
+Nonce = b8d517b033754058128d13d11a
+
+Count = 280
+Adata = 511c6924fa96db716f6b053b7a48aebdc1504145a56cd02d6be2590d
+Payload = 0c0663dd69ccbffbbd0c8c2e9473d0354451ae7a20fa3695
+CT = 19f2745df5007619c79c84d174e4521b942776478a0601d982c560fede4741e2fd3b54b3a48f3e38
+
+Count = 281
+Adata = d9ccd93317441e9d6ccc358f31e7e2ccef8c921b23d742993eff9d53
+Payload = 34a882834172924d39d2df5d637d9d273a99a9222971701c
+CT = 215c9503ddbe5baf4342d7a283ea1f09eaef711f838d4750ee82d927a2aa678e792acdeb615409f8
+
+Count = 282
+Adata = c268d65f7a7b30d3d198b2045fc8d1db7adda56604fa567d8855d1a5
+Payload = 5b7450b73d68de079e92bba56c7860f11126b8fdedd3334d
+CT = 4e804737a1a417e5e402b35a8cefe2dfc15060c0472f04017a48226389d24ed3ec3da2da1a9bdf7c
+
+Count = 283
+Adata = 4c2b6815156f0643b4573825e28b9f2a668a4976e3342884f48bc310
+Payload = 140c6933248f052e05bd4a36aec185ee86730108cc2989b6
+CT = 01f87eb3b843cccc7f2d42c94e5607c05605d93566d5befa16fe6bd83993ccbdd50e1ca061f4845f
+
+Count = 284
+Adata = f11c873354b3c0cff2c8f8010e9e364582b9c05c62efdefbdcc2e1c0
+Payload = 2a083de317380d94dd991349a7b8761c7c98013b1b0227e0
+CT = 3ffc2a638bf4c476a7091bb6472ff432aceed906b1fe10ac577c5893cb3896400012e48f5b190b73
+
+Count = 285
+Adata = d0a056754098d7f7ef2f639d61ea3d2b9cc936c48a1b2c5a9e96d169
+Payload = 02769283d5a06c363c2cc66c09b1ac954134e3ec7df773f2
+CT = 17828503496ca5d446bcce93e9262ebb91423bd1d70b44be80c80101fdfe6dc4cfce080bf921582e
+
+Count = 286
+Adata = 56de0e55653b9a04a3ded71c31f8807c3c8dd96bc82892e4acccef30
+Payload = 4890404bc5b24822b4cf7a2fe28abc52fbefb919ae0629ec
+CT = 5d6457cb597e81c0ce5f72d0021d3e7c2b99612404fa1ea0122dfc20e3088dcd33b6706a0c1fdfa8
+
+Count = 287
+Adata = 794a86f5b20d344ad86fd5523d08f1864737be57731440c29aa6b425
+Payload = 161f8501f59338f72026815c77cad6d8d581859192cd5644
+CT = 03eb9281695ff1155ab689a3975d54f605f75dac3831610828f0a78ce798448529afe26eec875aa6
+
+Count = 288
+Adata = b1eafc03ea2fa3e9e3842a09a225e83055de8a1f412badd6fc9ead12
+Payload = b3f38aedbf08dd7ead9d402c5aaa1ec9279c7e4bfd4a2967
+CT = a6079d6d23c4149cd70d48d3ba3d9ce7f7eaa67657b61e2ba48856a266c0d404474316f418f8f4e4
+
+Count = 289
+Adata = 8fec99f1be0e69267620c0b934bf984d60c1437f74c6ac19610fe188
+Payload = 5c09e2a6a055fe9c21e06e5519cf56b8e2e7fb44094e79f9
+CT = 49fdf5263c99377e5b7066aaf958d49632912379a3b24eb56412292d8015285efaa6f1154580eb57
+
+[Alen = 29]
+
+Key = 9a5a9560baed3b8e0e90b92655d4e5f33889e5d7253d9f6c
+Nonce = c0049382cdd8646756d4e6bff5
+
+Count = 290
+Adata = c95a86d52088a8b0107cc5b437a8938b2c9e74e46e2e03bb9bceecdbe3
+Payload = 5bbe9c1fb2563e3e82999fe097b28da4dc6ff2e020f3b4f3
+CT = 6d5401db42b5c48b79203b6ad82806d7460ac4c82ad0809b811020480e834f6fe55900a162a4e61a
+
+Count = 291
+Adata = 1dd56442fa09a42890b1b4274b950770ea8beea2e048193dfa755a5943
+Payload = 8a85a9b32a323c6af156a3fa2f1448b6387cc3660aa8a0f4
+CT = bc6f3477dad1c6df0aef0770608ec3c5a219f54e008b949cba9827513c7f1de970d316b6f81c109d
+
+Count = 292
+Adata = c834096e059ea73ddc90b0c982f9a3a31bfc6b1b81a03f9d41c9c741e7
+Payload = 1e02c13104937fe084b18eba1ea8951dcc5e75b692937dea
+CT = 28e85cf5f47085557f082a3051321e6e563b439e98b04982c9d79dd3255a8323f8229ac1c6d76ae4
+
+Count = 293
+Adata = 9249022bdead3d86ef5bd03acf053132d08663ba1f2426e19c126b22e9
+Payload = 3225570fb15ae13a13c71e364ae9a9fef03d1c9a7fa5dfa0
+CT = 04cfcacb41b91b8fe87ebabc0573228d6a582ab27586ebc8425dc81f93257ae8399fc2d48b4a7685
+
+Count = 294
+Adata = 3c3a92c4ece49fb9f84243d7c1bc91f595fce118305a758c83985c34b4
+Payload = fa0a458174537ddba25708b8d0c22d5517d57b122517b0c9
+CT = cce0d84584b0876e59eeac329f58a6268db04d3a2f3484a1b595003c58e69600c2a3b9ec45c0e15a
+
+Count = 295
+Adata = b49b845ccf76acf508f9db8543c73375d530d91f3b0e4ed70decfd2c2d
+Payload = b7fbdaeaa3ee1d0bbf5ec47898b069ec4ba6a140a3e83996
+CT = 8111472e530de7be44e760f2d72ae29fd1c39768a9cb0dfe0da009261c43c6640303696655e2981f
+
+Count = 296
+Adata = 3aabdf589eeb1709bb3d60b08bc71eaa3ffeba4e2903a5dbd8339aae85
+Payload = 9aea86b9fbd9bd4504ee2e25054942b33d3cdbd84215db7e
+CT = ac001b7d0b3a47f0ff578aaf4ad3c9c0a759edf04836ef16dfdcdbd4ad711c493d3176f032a02af0
+
+Count = 297
+Adata = 6a79879cd62bd1dbf9609897d2ebf2dc4dda43cc15fcb241aaa0deb4b3
+Payload = 3a861638ccd6591e51e2a525be59447e4a28bab32e36a5f3
+CT = 0c6c8bfc3c35a3abaa5b01aff1c3cf0dd04d8c9b2415919bfd59b45c05873c670f5f8bb47732d59f
+
+Count = 298
+Adata = c5b6ca474eb251817ae4d2f47c0632c381e222aae3b6f585a0dcae120a
+Payload = c7da4e9ba6e5758be726e6e227d7bddb0332228f7e3ecb6b
+CT = f130d35f56068f3e1c9f4268684d36a8995714a7741dff031572a24bc00b40a6b4b172b3648142e7
+
+Count = 299
+Adata = 64a96d191f1d5f95f5fed6259e33e7206adc07b0279e16cb453a9c6438
+Payload = 2b9347d3e195152dce22afdb92acd179eb484872285704c3
+CT = 1d79da171176ef98359b0b51dd365a0a712d7e5a227430ab828bc33396179ac39ce0027a1d62e0fe
+
+[Alen = 30]
+
+Key = 3e61094c80df0053e86d43fccf4e1d3ee2cdb862d3237b0a
+Nonce = 63f00b2488809fdc49ca5f05d5
+
+Count = 300
+Adata = a08763ca936abdeece06467bef8c3c47c3a473636a039d4db540c867d3e3
+Payload = 1fada8f4c7daea0d1c370184c169485b80a278708ed41451
+CT = 680dd22f16a1290bde42c9792dfa997aed24d5bd2265b6e095aa6b99d3f894d3790c2aa2dae1ba2c
+
+Count = 301
+Adata = 19508a6c83b992c660a1a28597e07c729ea2ed39401aadbf9d7586b5720d
+Payload = e9f1f2cf0b8d563e2d20f39f9f464a808b136dba364a6446
+CT = 9e518814daf69538ef553b6273d59ba1e695c0779afbc6f72d9d77109f4597e9c4c8cf7023dc5f3b
+
+Count = 302
+Adata = e5929c3b5d68a4c9fcf1168ea35bf8c0bf3043cb1ed54ff301578b3b7266
+Payload = 07a74c3b874849ecbf013713b80a84337c90b690cea0b837
+CT = 700736e056338aea7d74ffee5499551211161b5d62111a86b2544ecc3c7d5accd22ac075e7b44d5a
+
+Count = 303
+Adata = caa5cc5d0d87680eafc29429bac55c9e33167d485789c7c124b5c57a1ba8
+Payload = 4255f2cf90f0d15e9bead4be799165c57f7225980713d609
+CT = 35f58814418b1258599f1c439502b4e412f48855aba274b8f1a8a1db25de0fab7cabb11a18497584
+
+Count = 304
+Adata = f61cf7ae23a66777bd3fabc3d542feed2b00c6d4f46a772fda11b5214551
+Payload = 70b1e2e4cf260b108f5a52d0d8234838ffd6ffe7b4acd78d
+CT = 0711983f1e5dc8164d2f9a2d34b099199250522a181d753c5a9718ed0257a50e38de86154054fc3a
+
+Count = 305
+Adata = 85f647d940a6d1acb6b7851912f807063515631eaabaa019dcfb993e86f4
+Payload = af4be10b3a59ea99dadc75fbe5651f6f7630852bb556aa39
+CT = d8eb9bd0eb22299f18a9bd0609f6ce4e1bb628e619e70888550d1acca34c28ba8a3b890bb0542b23
+
+Count = 306
+Adata = 296cd04c4d9ab493def7aeb6841a45309e777028868efe45166235c56b2d
+Payload = 72d5663727592f1bfc9c65be83f4d3508126fecc4e34ae72
+CT = 05751cecf622ec1d3ee9ad436f670271eca05301e2850cc3a268dc1596a7855639c63fa76ad8479b
+
+Count = 307
+Adata = f380ca0a26a94adcf2c1ce26d226d3bf520268c72412e58a71acd9a66d00
+Payload = 3e2ccce03c10ce1527ef8e002adb265edba5779fbd4fcaf6
+CT = 498cb63bed6b0d13e59a46fdc648f77fb623da5211fe6847e3416c75fc28924a21cc123e62a7894c
+
+Count = 308
+Adata = 8825532a31680cb3b5bdb027802d2d8718755e135367e0c8c88e21288311
+Payload = a18dfe7f2d7bbaf316366f67445170afcbe18e2a1de1e947
+CT = d62d84a4fc0079f5d443a79aa8c2a18ea66723e7b1504bf6ff1a47f23d08485951aab18b393584ef
+
+Count = 309
+Adata = f768375589b687fb17c56673af4263626da69eb991007d94d4f5a163fd05
+Payload = 17ca72a440c944fefd6c08ecc3a8ecb54d96b9cad9d2aa4c
+CT = 606a087f91b287f83f19c0112f3b3d9420101407756308fd7d024456bcb69a4f77008773a3f48805
+
+[Alen = 31]
+
+Key = b5664dd6ed435df006052f6ded74bb7ce9482ca9229886f7
+Nonce = 7a1649896f3e030c18f0205599
+
+Count = 310
+Adata = c5f1a26351e53e6509c8bbbed03c42c23ad81c65fccec7ffa1cb494c7f1fc4
+Payload = 0b6de49b530703affc94010c2b793ddc6de0c44d48037ff2
+CT = 56b02fea595cc24e798691ae905be3d466ca68ca744005dba260b5ea3b047020b73b5bafa17e5084
+
+Count = 311
+Adata = 89899be18b4c389afa769b11ecd22e9fad8f38fd614ea5f8eb7a066c0ed8d8
+Payload = 2f1821aa57e5278ffd33c17d46615b77363149dbc9847041
+CT = 72c5eadb5dbee66e782151dffd43857f3d1be55cf5c70a685e4bd97b9dc83134867c00c2acea0aaf
+
+Count = 312
+Adata = d43b841f174335f1347834590b0984a2cb35f7a00a0ee993157d2d4f848748
+Payload = c7da4e95cb38342c6d5bf0c381d5a192adc3bfc1cda3a1d7
+CT = 9a0785e4c163f5cde84960613af77f9aa6e91346f1e0dbfe55202ba34bb9918fe915776de65947c0
+
+Count = 313
+Adata = c1093518efd80245e3c42371f220b21f2034e6738fe02ef43e828190f01aef
+Payload = 414a70aba5a219dbd41cdc46b84812b28cc4f7399218004d
+CT = 1c97bbdaaff9d83a510e4ce4036accba87ee5bbeae5b7a642fdf807b5a6880f2d4c36d558b40eb90
+
+Count = 314
+Adata = 90f627d5b939625bc76fe1bd4643b39edc11d3dc7f4bfe16e61bc26c3d49d8
+Payload = 58b260d3f645a35bad7a3842440bc03608248bd46e725e60
+CT = 056faba2fc1e62ba2868a8e0ff291e3e030e2753523124495a9307ca4239380a45bb7f87e41c4cf7
+
+Count = 315
+Adata = 2f360a4715074e942244ab7f9b6db127b0442df9af2efa2e78db1a94312905
+Payload = 5505caa97218957e90247fde60275bdafce4b16bcb36c263
+CT = 08d801d87843549f1536ef7cdb0585d2f7ce1decf775b84af3aeadff9dd60468aef2a8e2c56dda7d
+
+Count = 316
+Adata = 7db564811f14bc5c2098d5635655c3671fbd8288ea14944af925eaec653408
+Payload = b93e40f556a786e39126b8834a6ecacd2dc9f0f528bab135
+CT = e4e38b845cfc470214342821f14c14c526e35c7214f9cb1c8335f2e31a0468b830c5009cd02dbd5f
+
+Count = 317
+Adata = 36be91854d3d02a5d62503bb9047ef4354280510f7576c4272fd757240b621
+Payload = 543a070fdb3a855dd7d83fbc5f983671ad9e905f307148e4
+CT = 09e7cc7ed16144bc52caaf1ee4bae879a6b43cd80c3232cd5d772a599e91504e022b9dbfb124b71a
+
+Count = 318
+Adata = 6aa6ea668df60b0db85592d0a819c9df9e1099916272aafb8813ccc2f2dd96
+Payload = 86ef67572cb339c6706eb5909b96848aba5246a196972a1e
+CT = db32ac2626e8f827f57c253220b45a82b178ea26aad450379846cd12430f7adc910d1f0c51d80636
+
+Count = 319
+Adata = 3a64414c3588d7c26871d7d054ac6c8420d4917e3baad4a343685916265321
+Payload = cecef24b62676a5623bedae8087b9b05d7e22b41a14dd2d5
+CT = 9313393a683cabb7a6ac4a4ab359450ddcc887c69d0ea8fcd9ee65ac3a8fae1b00a4f1dfe2577293
+
+[Alen = 32]
+
+Key = 50925853a84a33ff392154e4e737efc18dcfc98f4d5235a9
+Nonce = 809343e986f6ff47f54d4cac22
+
+Count = 320
+Adata = d70aef3532bdc5293a3ebb11589ac1f801c9f93ea0d656e1d04068facf9f768b
+Payload = 718f061e8b972a3adcf465d66c5b28e8661f080127f6722f
+CT = bad3b0e6772e9c4c9c631c095e259d99692292932efb72b8966e91a19617bb748f3495aa433585bb
+
+Count = 321
+Adata = 1ee0eb409398bc252175cb460ef9a2da4c9beab2ef6d8206e4fcce74df785246
+Payload = 72e6cebdaf88205c4e74428664bc0d7eb4687a272217b7ca
+CT = b9ba78455331962a0ee33b5956c2b80fbb55e0b52b1ab75dc8f70aa565a12ca3545e68110968040f
+
+Count = 322
+Adata = 3820db475c7cb04a0f74d8e449f026ec951fa59667738698b0ed5c8cb09a8c96
+Payload = d959dd38a458039e2400d21d27b9a2faee8fe23683330cb5
+CT = 12056bc058e1b5e86497abc215c7178be1b278a48a3e0c22daf38076c810e14a7843444a02f010e0
+
+Count = 323
+Adata = f555216840a1f40b411d44128e567617e2694caf16216ea74c604a8d6ec01e72
+Payload = 337f12e8ebc0544b82fcdd3c4a0dab0e5e75c9f433a27d66
+CT = f823a4101779e23dc26ba4e378731e7f514853663aaf7df1594aebf9b8318877bdec2900a22df858
+
+Count = 324
+Adata = 2311a6fe1feeda3a1f16310d635496c0dd662024f0b0f1de79325e030cb850e5
+Payload = 463c65fa7becae5605af80d1feca59075ee88c0abfc72cb4
+CT = 8d60d302875518204538f90eccb4ec7651d51698b6ca2c231d9872d1c10a6594b5c349b84f710d64
+
+Count = 325
+Adata = b2c633e3181ae5fe7828707ed5b70e0460088a84465eadeecdbcfa0e9ff19bb1
+Payload = 23c1732959c4bf85bc707e45cc964b6227acd3a8fc73e675
+CT = e89dc5d1a57d09f3fce7079afee8fe132891493af57ee6e2a9db7c4bcaf6087e158c1a5d4eb1c2cc
+
+Count = 326
+Adata = 791f23252094b9b99fafe7fac1d8ff3ba09305c476041e75afb245ac438b4069
+Payload = 02f60f967e7fbcf957313619882407ea8a03fc943062296c
+CT = c9aab96e82c60a8f17a64fc6ba5ab29b853e6606396f29fb5e1c87d9e1c1f3b7d30fdc2f0ccac783
+
+Count = 327
+Adata = 22197f9ad14591e7a6d5f8b18c969a553de9a85309757fa5d319cc505c24f438
+Payload = 6c1aa088d1a6086d0e72636744a6840c80ab8223409c61b7
+CT = a74616702d1fbe1b4ee51ab876d8317d8f9618b1499161201514b449a741e07f9287f7e9090fa54b
+
+Count = 328
+Adata = 0bb18f7280a30767cd769cb5ffd3edd1c18914b92d1b2192e27ac88f57135616
+Payload = 57275bc3b4d63b9b01b0b0760235c9785d45761cace23f1e
+CT = 9c7bed3b486f8ded4127c9a9304b7c095278ec8ea5ef3f892c889b610157e16e9f31558c669298a7
+
+Count = 329
+Adata = 3e5f0f32e27be18ca6f84de11e6e9c25fc0c4cb0cf83633eea1f033aa1373f3c
+Payload = eba27a27f0d4604a5296a41b3fe995c50c66bcba302d0447
+CT = 20feccdf0c6dd63c1201ddc40d9720b4035b2628392004d0fbe19321dc22c748a17aa5eda29d8cf3
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VADT256.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VADT256.rsp
new file mode 100644
index 0000000000..af4f5c1df7
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VADT256.rsp
@@ -0,0 +1,1823 @@
+# CAVS 11.0
+# "CCM-VADT" information
+# AES Keylen: 256
+# Generated on Tue Mar 15 08:09:25 2011
+
+Plen = 24
+Nlen = 13
+Tlen = 16
+
+[Alen = 0]
+
+Key = 26511fb51fcfa75cb4b44da75a6e5a0eb8d9c8f3b906f886df3ba3e6da3a1389
+Nonce = 72a60f345a1978fb40f28a2fa4
+
+Count = 0
+Adata = 00
+Payload = 30d56ff2a25b83fee791110fcaea48e41db7c7f098a81000
+CT = 55f068c0bbba8b598013dd1841fd740fda2902322148ab5e935753e601b79db4ae730b6ae3500731
+
+Count = 1
+Adata = 00
+Payload = e44b4307234281209bd41f89dbe2cc3fbf68e14df2f7fce4
+CT = 816e44353aa38987fc56d39e50f5f0d478f6248f4b1747ba003abc6a4b020625adc8b6cd7bafbd42
+
+Count = 2
+Adata = 00
+Payload = 8db7a73856bcb4007346bb3e00096f69e75e97c0bb960f3b
+CT = e892a00a4f5dbca714c477298b1e538220c052020276b465e7cfa7a208a8b3e6b6377236045df17d
+
+Count = 3
+Adata = 00
+Payload = 48f3ceda4fd390a7eb38f7f5bcd14310af6b5a557e676d44
+CT = 2dd6c9e8563298008cba3be237c67ffb68f59f97c787d61a81b39a0c55822e32042b4f8981021090
+
+Count = 4
+Adata = 00
+Payload = 7cdb2c9b167b3ae811289acf7dc1814bbe241f553447699f
+CT = 19fe2ba90f9a324f76aa56d8f6d6bda079bada978da7d2c1091117e2ad77db510d902038743b5a98
+
+Count = 5
+Adata = 00
+Payload = 41eacf70d05a6d0cdbdd38f197a52987def8fde37f332eeb
+CT = 24cfc842c9bb65abbc5ff4e61cb2156c19663821c6d395b5ac7379b8e51592b98e4874f4592278a8
+
+Count = 6
+Adata = 00
+Payload = bde9e3eb9f0c57302c9185b1cb912ef76d88f2f9c3b51e9a
+CT = d8cce4d986ed5f974b1349a64086121caa16373b7a55a5c4d08c1c902c4c2f078452dd6943b85028
+
+Count = 7
+Adata = 00
+Payload = 6f9ccc033c6bfbdfad4719ad033c927e2175727a9a021dc6
+CT = 0ab9cb31258af378cac5d5ba882bae95e6ebb7b823e2a69832fefb87445f1ca42811899acc0cdf68
+
+Count = 8
+Adata = 00
+Payload = cc67bc3b7afd625b2610226d3b30e111e6aa47a3254f711a
+CT = a942bb09631c6afc4192ee7ab027ddfa213482619cafca4481d605a1019c8e9778b8928b4636053e
+
+Count = 9
+Adata = 00
+Payload = a10c81725f49ab9075fbf4d96be030a2d881d8501b115d61
+CT = c429864046a8a337127938cee0f70c491f1f1d92a2f1e63f96a82e8411e5b04426dc608298c6408d
+
+[Alen = 1]
+
+Key = a4490ed6ab51dbfccd6f3702a857575dad44da3a27eaf31178abc97da60d1e4b
+Nonce = 26ceaf6e3b28190a17c4f0c378
+
+Count = 10
+Adata = 9e
+Payload = 1b5cc6b1651dec4bbbf5130343852e971c7ff1774100d9be
+CT = 789bce069a725a96c484e64a9e54dcb7a7c268c85df47815a462ff2dd8ba44a381e1f6edab12b5a9
+
+Count = 11
+Adata = 4e
+Payload = e7ab98901c0cb1d7d76e125d8ac8e86edf6f469fa937bc10
+CT = 846c9027e363070aa81fe71457191a4e64d2df20b5c31dbb6b0789c5866b7e3312ad992e228d6d20
+
+Count = 12
+Adata = cc
+Payload = 53bc7e3648d0b389b887b065e9e8f79685beb2eb36e2eb95
+CT = 307b7681b7bf0554c7f6452c343905b63e032b542a164a3e39b1b1a480fdd268c1c75b131cde798b
+
+Count = 13
+Adata = 45
+Payload = 6d7262476da95db63b322c5193ea05030923c3cbf0f8e8b1
+CT = 0eb56af092c6eb6b4443d9184e3bf723b29e5a74ec0c491a32060fea35c3e9528fd18994fae9fce8
+
+Count = 14
+Adata = 2c
+Payload = 8246bf7b81b287411777df7ecb53a1795e54b150ff3dd584
+CT = e181b7cc7edd319c68062a3716825359e5e928efe3c9742fb4e0a604ab30a764e8c98a9cafbca8d4
+
+Count = 15
+Adata = a9
+Payload = 2596ca8772bc69b50bcbf33088c6efbab614b691ed836f92
+CT = 4651c2308dd3df6874ba067955171d9a0da92f2ef177ce397ca72f1acf6dfd078b6f4eb82fa01e9b
+
+Count = 16
+Adata = 85
+Payload = 703065d701f4fcadee20d64300b3082c0c76490eb2dc4ba7
+CT = 13f76d60fe9b4a709151230add62fa0cb7cbd0b1ae28ea0c2a85c9252ee62612dc29cffa7289b2ca
+
+Count = 17
+Adata = dc
+Payload = a1aeda4b4cb8dd2943675181561bac48ba07e8de5b327837
+CT = c269d2fcb3d76bf43c16a4c88bca5e6801ba716147c6d99c9fbdac729413152c089d3939e30b8602
+
+Count = 18
+Adata = ce
+Payload = aa17341f4cead054d41c171dd34c459f7052da225c6c365d
+CT = c9d03ca8b3856689ab6de2540e9db7bfcbef439d409897f6f86266c273f8184e901b50c04845b8ab
+
+Count = 19
+Adata = a6
+Payload = 448cdd9cbbf863eb666fda36b825f3798827da3c1349611f
+CT = 274bd52b4497d536191e2f7f65f40159339a43830fbdc0b4ddd02d5c9ae2bbac47a7a076edb1d207
+
+[Alen = 2]
+
+Key = df594db94ef8eca56a417afe946085eaed444c7cc648d07d58132e6cb5bc2bc3
+Nonce = c1ad812bf2bbb2cdaee4636ee7
+
+Count = 20
+Adata = c0c3
+Payload = f4d7978fad36223623ccb5bb18a7373cba8a6e3b1c921259
+CT = bea778540a90033b2c0d087e3cc447711ea25f7eea96855506ec97f23bd6ea97834f92f7263c3195
+
+Count = 21
+Adata = 34b9
+Payload = f6c043c70136585d012ae0df6f42b25584e374649d0116c5
+CT = bcb0ac1ca69079500eeb5d1a4b21c21820cb45216b0581c9f3230df0b52b5cb7ac907dcadcb662ca
+
+Count = 22
+Adata = d4ab
+Payload = dec0c896b04490816409da1783478ef2510231d0a28c5b39
+CT = 94b0274d17e2b18c6bc867d2a724febff52a00955488cc35a99c3165ce83102891ef3885088ed6eb
+
+Count = 23
+Adata = 2a3a
+Payload = cbfd94fc31785d30214271dab2264134805fee6e52aa0b5c
+CT = 818d7b2796de7c3d2e83cc1f964531792477df2ba4ae9c50c9d8078607994ae5dff0de6526fb53d1
+
+Count = 24
+Adata = 4eb1
+Payload = 134d2d9726400d09dd3521326f96fbef993ddc0c40887700
+CT = 593dc24c81e62c04d2f49cf74bf58ba23d15ed49b68ce00c7e84da7d2564533e7ad55390ec3a6ff9
+
+Count = 25
+Adata = 0a79
+Payload = 1ccdcf789d42caba80d7893feaf26d3853fbcaf7d964df0b
+CT = 56bd20a33ae4ebb78f1634face911d75f7d3fbb22f604807520849295a56191367a696999ffef8e9
+
+Count = 26
+Adata = 865f
+Payload = 4042dbe148db3e6dc542b25d57a5787af535d38e8c34c71b
+CT = 0a32343aef7d1f60ca830f9873c60837511de2cb7a305017bc4aceed1a10309b6402b9e9420b33a3
+
+Count = 27
+Adata = f4ae
+Payload = 85b6894fec36294aa934cdc3523fd95c90ad56cbd18545dd
+CT = cfc666944b900847a6f57006765ca9113485678e2781d2d176c180d2e299ccf0b8781ba6de8a72ce
+
+Count = 28
+Adata = 10bf
+Payload = 0f27f4fc8538a676a763b3e5db845a1bfb20d5fab340dee3
+CT = 45571b27229e877ba8a20e20ffe72a565f08e4bf454449ef98d91c68d94873a5d6557611a5402a0a
+
+Count = 29
+Adata = b92e
+Payload = 1b5ec0cb03810a12fc6a0a1ff565afb001405d2a45a1f18a
+CT = 512e2f10a4272b1ff3abb7dad106dffda5686c6fb3a566865321cedf1122354636e130acbd69718b
+
+[Alen = 3]
+
+Key = d98193ab2a465e3fcd85651aaeca18b8e91489b73b7c7e93b518c4b5b81fc6ac
+Nonce = 2247dc7e2674e9e0a63fe70613
+
+Count = 30
+Adata = 4dc2f4
+Payload = edba7d6312144e90ec9eaace7576045a46e553dcb8ee5a98
+CT = 44b9ea727c847336fd739ad11f4b906b292edb810462f06ef59626ad5cdac2e4d4cb07b538a1fd8f
+
+Count = 31
+Adata = 2f3bf0
+Payload = 52a9626f5279c11e17e96f5dc5e1c1f58c1e913020d8499b
+CT = fbaaf57e3ce9fcb806045f42afdc55c4e3d5196d9c54e36ded0d53402253453e494ad350994ca77a
+
+Count = 32
+Adata = 95d2cf
+Payload = 87b6447d97a74d0b315031078aa06fffc7b9f246bfa5f147
+CT = 2eb5d36cf93770ad20bd0118e09dfbcea8727a1b03295bb196dbc3bff865a1d94b164df23d708e8e
+
+Count = 33
+Adata = 0caba9
+Payload = 1852848046706f2e274ba381a2bee1422df4f61d93219af7
+CT = b151139128e0528836a6939ec8837573423f7e402fad3001791b4469fe50d45f8efb81217cd68580
+
+Count = 34
+Adata = f8d459
+Payload = 99aac82fa66a15e4f76b76cf4590150999d5cf8468df7f42
+CT = 30a95f3ec8fa2842e68646d02fad8138f61e47d9d453d5b4587106da25012f92f01cc2db8d11ac29
+
+Count = 35
+Adata = e883dd
+Payload = 4e2f0f91990b855a00d27fbb2e8db7184cd82909de361b52
+CT = e72c9880f79bb8fc113f4fa444b023292313a15462bab1a464148536847290e4fdda7966fe6d5e3b
+
+Count = 36
+Adata = e45da4
+Payload = e558be3fd246170b294d18ffa708842242681890baf8bed9
+CT = 4c5b292ebcd62aad38a028e0cd3510132da390cd0674142fcc4cb33472825363940e2b26424b7802
+
+Count = 37
+Adata = 3b6fc8
+Payload = f8b284c2d851289275973fcd807fac5d8e5e3b6a75ba2ace
+CT = 51b113d3b6c11534647a0fd2ea42386ce195b337c9368038a99dd8dbe89b3ecf663eda1b0f92be7f
+
+Count = 38
+Adata = 043d68
+Payload = 8edf1eb90f0ad33be8a7c6446899e06addc10b3badc4ea25
+CT = 27dc89a8619aee9df94af65b02a4745bb20a8366114840d3dc4894c8fa0a1e1aa760acf9360042f5
+
+Count = 39
+Adata = e89257
+Payload = 8fe9a6bd82462c97f436d382d1ff971c95406b1a6c847d81
+CT = 26ea31acecd61131e5dbe39dbbc2032dfa8be347d008d777cdad1590fd8bf2d7ea919e60d0316566
+
+[Alen = 4]
+
+Key = 45c8afd7373cb0f6b092af3a633d9fd97c4ca378e19d75f9b74d089429726c29
+Nonce = fdb1fa230ae0b172ff98fc7496
+
+Count = 40
+Adata = 270981af
+Payload = 0b92adbb251dc29a67f0bb97f8e7160862b6c4e843d07fd9
+CT = 274e2faea3271ea6fa0494c1951f115b5491a893056c3ee4c76fc350e585277e373e9119bf9595cb
+
+Count = 41
+Adata = 633f3efa
+Payload = 1f88dfd4f5c52c22b1db47f9f4fb6e2f8bcd78d593061369
+CT = 33545dc173fff01e2c2f68af9903697cbdea14aed5ba52540fa7e55dc54e80488a05ee7f1fc96e9d
+
+Count = 42
+Adata = aad86fb5
+Payload = b2b4cb5e90ebf4bd265093b7f5efd4d62dc60e29737aa496
+CT = 9e68494b16d12881bba4bce19817d3851be1625235c6e5ab18151c17d9e3f97244000a3b2d3c2f95
+
+Count = 43
+Adata = ed42941a
+Payload = f312b47d05f8eb5a29943b41347cb1983c75cb7a458a3868
+CT = dfce366883c23766b46014175984b6cb0a52a7010336795562d521c4b5c7a6f2c5ac65f2fd15b066
+
+Count = 44
+Adata = e5b085d8
+Payload = e9fb86938ea7f04cc230296859e7c96fcc352f968c9473e4
+CT = c5270486089d2c705fc4063e341fce3cfa1243edca2832d9e491a31218f688744098851672a09a64
+
+Count = 45
+Adata = 3776f37f
+Payload = 8af6b7540f997954812e38dbd99ccfaedd5c69963c353a4e
+CT = a62a354189a3a5681cda178db464c8fdeb7b05ed7a897b730ece28347d7ebf8291d7eb66b7651b4e
+
+Count = 46
+Adata = 4eb08c9e
+Payload = b90cfd9dd58e320d98510483b1d939bdb5f3b81666ecee59
+CT = 95d07f8853b4ee3105a52bd5dc213eee83d4d46d2050af64cbd25fb40480d15c039878b5d2f25afb
+
+Count = 47
+Adata = c7f93152
+Payload = 02caabc6ed0641681e7148c10cf3159fe35e44013252071e
+CT = 2e1629d36b3c9d5483856797610b12ccd579287a74ee4623fbfd98c8567b78d4b9c3a49a4641908e
+
+Count = 48
+Adata = 57957630
+Payload = 2f29882fdf1418d04f0b9d44272995a56973c4369c687a99
+CT = 03f50a3a592ec4ecd2ffb2124ad192f65f54a84ddad43ba4655c1abcb3ed1a175f12721a407c5d00
+
+Count = 49
+Adata = 19da955d
+Payload = 4e427130be9e94639320529ec135715e65da1117b5ba3c76
+CT = 629ef32538a4485f0ed47dc8accd760d53fd7d6cf3067d4b90621a5e5683df421a0dc52341485d1b
+
+[Alen = 5]
+
+Key = a2e6bf39efd1ceddc92b4333ed92d65efeea6c031ca345adb93a7770a8039bcd
+Nonce = 693cbb46bc8366086ec7cd7776
+
+Count = 50
+Adata = 3ba11282d6
+Payload = d822f84b023f12ea9e3ce16b904278e4aaab5e11c2c23f3f
+CT = 9f91fd2f6472e33b02b1eabb9d6655729d44c44dad6b3883fe0667bcc5806b225224b04ade8b21c1
+
+Count = 51
+Adata = 3f3a4718ea
+Payload = af87b347b59e37a424004a00907dcbcf6a554e6782a9be12
+CT = e834b623d3d3c675b88d41d09d59e6595dbad43bed00b9aea6750fffa5a487540ce65770cd836e99
+
+Count = 52
+Adata = ff79ca8965
+Payload = 82b7cd168b6a82cb2d837f41ceda0c27adc5f5b28030454b
+CT = c504c872ed27731ab10e7491c3fe21b19a2a6feeef9942f7e7cfafe32bd71ea9813607c5df446c9d
+
+Count = 53
+Adata = 0021be18ed
+Payload = 1c1a0f144df76781e7c85ab178ed9b1ce8c6dc3f15c59149
+CT = 5ba90a702bba96507b45516175c9b68adf2946637a6c96f576716fe674c33ad3b9d3e54cc86bfccf
+
+Count = 54
+Adata = 9ae7996547
+Payload = d9bb71ad90152d5c1af358c8501fa89ebd4b17bf4ff43841
+CT = 9e0874c9f658dc8d867e53185d3b85088aa48de3205d3ffdab55dbee34f1bab555bbb196095fb5fd
+
+Count = 55
+Adata = fa292d1958
+Payload = fc7d028a1aa05c74b7ffe333ba6f676913b0f9f1ffa050b8
+CT = bbce07ee7cedada52b72e8e3b74b4aff245f63ad9009570476a4e9e759d5bb79c187a157099e3d12
+
+Count = 56
+Adata = 88800df7b6
+Payload = c9ea772e61742a6706da3ab3e81df14b31506ae58b063ece
+CT = 8e59724a0739dbb69a573163e539dcdd06bff0b9e4af39729f0f3699c9743ad6c9f09dc00ea10487
+
+Count = 57
+Adata = 715041afd4
+Payload = 70d2b8d64121ceccf1961444e8d33b7b7f998aeb58d3d270
+CT = 3761bdb2276c3f1d6d1b1f94e5f716ed487610b7377ad5cc560d78cba6d9f50e9c2677a710f92155
+
+Count = 58
+Adata = 14682301a9
+Payload = 1013946815001a2c08acca4196e0d6668ffbb3883cf111e7
+CT = 57a0910c734debfd9421c1919bc4fbf0b81429d45358165b95ffb6e29172a283d47e4478e2e1f7c4
+
+Count = 59
+Adata = e44c3c21c1
+Payload = f40dc834067bd163e0004d0ec5dd4b96e2a1ea31ea431c98
+CT = b3becd50603620b27c8d46dec8f96600d54e706d85ea1b24ccf233caf0bad9f68f71d78ee58512ec
+
+[Alen = 6]
+
+Key = c5a850167a5bfdf56636ce9e56e2952855504e35cc4f5d24ee5e168853be82d8
+Nonce = c45b165477e8bfa9ca3a1cd3ca
+
+Count = 60
+Adata = 4759557e9bab
+Payload = e758796d7db73bccb1697c42df691ac57974b40ca9186a43
+CT = 93ad58bd5f4f77ac4f92b0ae16c62489e4074c7f152e2ed8a88179e0d32f4928eff13b4ce2873338
+
+Count = 61
+Adata = 2ea07d393a0a
+Payload = ce60ddbe40b70bd55a9147036ad079dec1558ef4c2c625b3
+CT = ba95fc6e624f47b5a46a8befa37f47925c2676877ef06128b7d812c4d69f1f53ee9158382e56625b
+
+Count = 62
+Adata = aa6667faedc1
+Payload = 89eb3056770a6157f06921bc153834447c4b6d862d10d185
+CT = fd1e118655f22d370e92ed50dc970a08e13895f59126951e26fdbed62b228db008a1b14bd7942e12
+
+Count = 63
+Adata = 9e2127d92311
+Payload = 132f3e19e12f462a7463226b716c41a05a59c76f0e1a2f72
+CT = 67da1fc9c3d70a4a8a98ee87b8c37fecc72a3f1cb22c6be9124e1eb78de01b8af83b684baf3e43ad
+
+Count = 64
+Adata = 2f191bc9cff6
+Payload = b8611cbb9a3667b9458ca57eb636eb1dc580e7dbb5701692
+CT = cc943d6bb8ce2bd9bb7769927f99d55158f31fa809465209cb0f79736d1a810d06a776094f9fb67f
+
+Count = 65
+Adata = ad739d5f4736
+Payload = 112f89ccbdadc2433008d3ede2290f9ce81e5c736abf42a8
+CT = 65daa81c9f558e23cef31f012b8631d0756da400d6890633bfba2348f629471c232c9ff7e5f6f85a
+
+Count = 66
+Adata = 01acc909b7d3
+Payload = d47f2ff745de39a9055ad002de6334971fde480bef268b33
+CT = a08a0e27672675c9fba11cee17cc0adb82adb0785310cfa8c0f694d03ffed043787343827ea2603f
+
+Count = 67
+Adata = ce003c836a6f
+Payload = 13be365884b8a91a284ca24f70011e48794b51be275153b9
+CT = 674b1788a640e57ad6b76ea3b9ae2004e438a9cd9b671722279b553998a6fee0a86e177a448573a4
+
+Count = 68
+Adata = 6a759a4efd00
+Payload = d5c87c649579da3f632ba95cb0a07c924095e4bdd4e0376e
+CT = a13d5db4b781965f9dd065b0790f42dedde61cce68d673f54eeb434cca3ea719827417e94d6ed564
+
+Count = 69
+Adata = 02b84a26c773
+Payload = b7bc1580c68fd5d06c1bf75c31dad7a3e26d636d7eee20b9
+CT = c3493450e47799b092e03bb0f875e9ef7f1e9b1ec2d86422a74b5e4e2edb91fbbe722bfaf1500db4
+
+[Alen = 7]
+
+Key = ae8f93c3efe38e2af07e256961dd33028faa0716e5320a7ab319a10d2f4c5548
+Nonce = 6333bde218b784ccd8370492f7
+
+Count = 70
+Adata = 0b1fabdf2a4107
+Payload = bc9ca92a9c9919e39095d3e53fb148694620ae61227e0069
+CT = 45811b0c8f754bf03950e520cd4afc81c2e3eb8a11f4fd386d5a6e4b1fbee15d35939c721004502e
+
+Count = 71
+Adata = 2fc7f5c0ce052f
+Payload = f25a4ca20bbf4969bed6b93c1c77e3d7415f60fe3784216b
+CT = 0b47fe8418531b7a17138ff9ee8c573fc59c2515040edc3a24a68f98716190fb55f743a8bf62a085
+
+Count = 72
+Adata = 8a74412da3034b
+Payload = 3237bf953989d17c65a0fafd2bb1e32c237f98f55389e8f8
+CT = cb2a0db32a65836fcc65cc38d94a57c4a7bcdd1e600315a923afef7b4955d7d1e8f1abef9933bf9f
+
+Count = 73
+Adata = 7139f3c1d6cc36
+Payload = 55d86dc0423cfc2616ef996a3316e776707f8d25c985884a
+CT = acc5dfe651d0ae35bf2aafafc1ed539ef4bcc8cefa0f751b8e824c62632dff5cbc103d3060fbd174
+
+Count = 74
+Adata = af7a380f079aa1
+Payload = ac48398adb10292314973946f261ec39397442ca09b98dd8
+CT = 55558bacc8fc7b30bd520f83009a58d1bdb707213a33708980202d518ca871c9544f4a8c55fd8d20
+
+Count = 75
+Adata = e602abe8f72964
+Payload = 2fb78654e4395df8c37f260d74def234a3a4e3d2b1fe8614
+CT = d6aa3472f7d50feb6aba10c8862546dc2767a63982747b454b33ea6e4344033f74f513d1e41b82ae
+
+Count = 76
+Adata = 82741c5fd6e1df
+Payload = d488bdda400932de56a9f105f0e74ee79c2ed869faaadc31
+CT = 2d950ffc53e560cdff6cc7c0021cfa0f18ed9d82c920216073ccf18c7ea7dce79d0be1204c593234
+
+Count = 77
+Adata = 78f0cc22535402
+Payload = b22aba8d3e9f4b4bf006e26062de15daf94597731a600912
+CT = 4b3708ab2d73195859c3d4a59025a1327d86d29829eaf443b81b8af57b85093778690266e20e2fbb
+
+Count = 78
+Adata = 18e468139dd16f
+Payload = bd864f7b8efd6ed2b068f425482d449bf53a203ea88e1ca1
+CT = 449bfd5d9d113cc119adc2e0bad6f07371f965d59b04e1f09b94a857e7a0423ef6c9cbebde1f9c40
+
+Count = 79
+Adata = a6dab47c0fbfe1
+Payload = 47d9d18b6addc5f88986f0457b666faae59aba4fa3a02abb
+CT = bec463ad793197eb2043c680899ddb426159ffa4902ad7ea64718820065a739fbd3ba560a416895c
+
+[Alen = 8]
+
+Key = 548c2d1eb7d91e003633d4d9ff199e4a8447180edd89ac7867d25a1db288b5ce
+Nonce = 23b205bd6ff8ed0bab0c98999c
+
+Count = 80
+Adata = a6601111cd92c943
+Payload = 49fd5cbe4aff89dc3b8718f9ce545d612cbbebb289ecbf42
+CT = 3cfc6211e359ae322802fc9566f377b0dfe17d1dfe0878ebf2a9047e37cc0be1fab0006af8db8dc4
+
+Count = 81
+Adata = 96f0b7cd7439721d
+Payload = 94a95e945f660d1571b4d7d22709b000b45ff98b2129a4ae
+CT = e1a8603bf6c02afb623133be8fae9ad147056f2456cd6307106a430b04938e97f2e4cda81108ad3e
+
+Count = 82
+Adata = 2ee135dc2ddd9501
+Payload = aeed3aea01755c912213c8c276a2b75dad24f888a611efa3
+CT = dbec0445a8d37b7f31962caede059d8c5e7e6e27d1f5280ab2ab219c6c4952d52505cd9f904b0e04
+
+Count = 83
+Adata = 10c361934fd6ff77
+Payload = be1fcebea4c22a1d71e08047b028d7f4ccab0a6b8085d344
+CT = cb1ef0110d640df36265642b188ffd253ff19cc4f76114edfc1f7b2fe314faea28ab0dae349feb9c
+
+Count = 84
+Adata = 3f6c8a69917f7776
+Payload = 87680ac26fe1511e0f1f745aa4c2a5b9f6c0117dcf08feaa
+CT = f269346dc64776f01c9a90360c658f68059a87d2b8ec390308e529d64e786a29661cccddc0366f3b
+
+Count = 85
+Adata = 0f7a1426ff3b5ee1
+Payload = 9e004b072a27b085e59ca201c157c7d3c906a2c3b455c56e
+CT = eb0175a88381976bf619466d69f0ed023a5c346cc3b102c797c6510b85dfd097f3eac276aff00ba2
+
+Count = 86
+Adata = faa5bed84dcf168e
+Payload = a1bf47b15cd66e43daff420edf014a14b11994b97ada4030
+CT = d4be791ef57049adc97aa66277a660c5424302160d3e87998e522b6f13f99ecb553b6de845940907
+
+Count = 87
+Adata = 2851dae3cb3fcb1c
+Payload = 2d15734871adc63ff32d7002ab40c4a235a4d5fad223953f
+CT = 58144de7d80be1d1e0a8946e03e7ee73c6fe4355a5c752967a9ca39566189ee96c86462bfea78af5
+
+Count = 88
+Adata = 35a29c1bcbe2182f
+Payload = 5a84c4fdd47510fb7aebc0f79d7b625ccd0a96575740b8e6
+CT = 2f85fa527dd33715696e249b35dc488d3e5000f820a47f4fa613b5fbbe73a2df6c630a00ff4b1b92
+
+Count = 89
+Adata = 45820ae66c3e8e77
+Payload = 2052a94e1392dc1db0e89be19ea8f7379ee4cb607a914c89
+CT = 555397e1ba34fbf3a36d7f8d360fdde66dbe5dcf0d758b20d19feb067e9f6225376da21b4899d296
+
+[Alen = 9]
+
+Key = aab793e377a12484dbdd74c9b3a85c74c286e1cc498663fbd7c718b5633bb91a
+Nonce = 10022cddb323e88b3c08f95a0f
+
+Count = 90
+Adata = 82b8c736037ce2f2e8
+Payload = 7c0889854658d3408c5d8043aad2f4ae4a89449a36f8a3b8
+CT = 1044250f58857c69f72b5d3454d43949e5c02b3822970b280de1a3f7fc5d06cc30f06075f5504ed7
+
+Count = 91
+Adata = 8f2777ec4930f7e349
+Payload = bd845561f099500a6ff3fd09964dc3820f7ab48ba4ed04d5
+CT = d1c8f9ebee44ff231485207e684b0e65a033db29b082ac45835840df6fa96f5c972ac09d94148cbc
+
+Count = 92
+Adata = 5cab3b846870709569
+Payload = a6e09404fe60badfc63dc228057485e6f563ba82acdabd7c
+CT = caac388ee0bd15f6bd4b1f5ffb7248015a2ad520b8b515ec2f83ef84b299cfdb61d2b5039d536c3f
+
+Count = 93
+Adata = 0938f2e2ebb64f8af8
+Payload = 33404d7e0e620c1030b91020e33619c5f53d8b210fa86489
+CT = 5f0ce1f410bfa3394bcfcd571d30d4225a74e4831bc7cc19db04e655cbe22b9ea508d2a03757b97c
+
+Count = 94
+Adata = 82f78ca0e0da2b2d3a
+Payload = 617868ae91f705c6b583b5fd7e1e4086a1bb9f087a50bf50
+CT = 0d34c4248f2aaaefcef5688a80188d610ef2f0aa6e3f17c04bd88dc6985f819004c2b634c5303ed8
+
+Count = 95
+Adata = 401191aa3fd34abe87
+Payload = 949cdd7c2973d7519e7bca98b2c5947e6d8e91c90e632319
+CT = f8d071f637ae7878e50d17ef4cc35999c2c7fe6b1a0c8b894ff3572e4ebf78473760d8cb4b0366b4
+
+Count = 96
+Adata = 4df4377596d8987671
+Payload = f6720a0bd8705c70e0f923338965e810b3ea939bad652327
+CT = 9a3ea681c6adf3599b8ffe44776325f71ca3fc39b90a8bb7de95ec3eee17753e60fb3c0661bdd098
+
+Count = 97
+Adata = 6593194b9970545c5a
+Payload = de9b0556661e726f3e6e34515ff7196420fe61b4f38419f2
+CT = b2d7a9dc78c3dd464518e926a1f1d4838fb70e16e7ebb162b8590ff04f967e51fbd1be84f01b4dcb
+
+Count = 98
+Adata = ab2d432058b540ac72
+Payload = 6cad7f3b9f196839bbc5a7f755c09aa8e17c83d9cb8b3954
+CT = 00e1d3b181c4c710c0b37a80abc6574f4e35ec7bdfe491c471d67b75b2da855a12ffb24ddd64a048
+
+Count = 99
+Adata = 5dc631eeeacb5a0b0b
+Payload = 70a55aec1144357377612fd0bbc2c817f33465a656219957
+CT = 1ce9f6660f999a5a0c17f2a745c405f05c7d0a04424e31c71fc798dd16c1fadef607a9297cbfbfef
+
+[Alen = 10]
+
+Key = 06ac39896073a44283611a66ccab067e2dd2faa8da82ff9a45bb29e54d2e6e77
+Nonce = 6c7942c9819cf69b817bfcdb0a
+
+Count = 100
+Adata = 215e2a6c24325340fdec
+Payload = 3216dce3b8b1ce0e79e40fffcac728ab191aaaf319d971d3
+CT = c5b3b50ed8a7b7b96b02ba9464b6a2ff80e90548605699a63d70e6dffb31a376a1eb7f94526dca48
+
+Count = 101
+Adata = e0a29a2c7840cf9b41de
+Payload = 7e5e5710a693ebfa36335cf7965574740880acdddd13fb1a
+CT = 89fb3efdc685924d24d5e99c3824fe2091730366a49c136fcbf516608fe20e06bbff931e84683545
+
+Count = 102
+Adata = b8026fbada6339d84802
+Payload = 08c342a50aa23362622934dfab55d9b22c22c249ad08138c
+CT = ff662b486ab44ad570cf81b4052453e6b5d16df2d487fbf9d70eb14f3fa0229906b9e0360be3d3f9
+
+Count = 103
+Adata = 65f4b3a00c1c1ef39445
+Payload = e085aba85882c75d5e41559167731496cf17d3907894352a
+CT = 1720c2453894beea4ca7e0fac9029ec256e47c2b011bdd5f4184771199a427861bf17cd8401e794e
+
+Count = 104
+Adata = 96118dbfe53434d8aed8
+Payload = 710f890be2b8da77c1eff429ede9cc931d50f059748cbcb6
+CT = 86aae0e682aea3c0d3094142439846c784a35fe20d0354c34e20b2db52fde68f88bfb886fdcb2c47
+
+Count = 105
+Adata = cdf4b485d2e04709cf8f
+Payload = cda96efee4e188ab3048bc1904ac2c36ab018f2ab7602682
+CT = 3a0c071384f7f11c22ae0972aadda66232f22091ceefcef782ee3df38ddea8e269eb47e39900345e
+
+Count = 106
+Adata = 50e57e57cf8e49e3a4e6
+Payload = 3dc596d52e520779a50bcba3049388b340dbf6d0f2eb94cf
+CT = ca60ff384e447eceb7ed7ec8aae202e7d928596b8b647cba44aaac4ed86f687cfc031f22827725f1
+
+Count = 107
+Adata = 48c670f11ff7f74e7003
+Payload = a33105c0dccf8e3b687212a870af9f710462756705fe09b3
+CT = 54946c2dbcd9f78c7a94a7c3dede15259d91dadc7c71e1c6d75255006ac037d6a4d048f1fc338012
+
+Count = 108
+Adata = 465e3be6113a2fb2ee20
+Payload = 573ac2436158eb7dd9be981e3cfbe75d3a188ea9cf2b1ee2
+CT = a09fabae014e92cacb582d75928a6d09a3eb2112b6a4f6976c1da33a80bc8157cece1acf9400b2bb
+
+Count = 109
+Adata = ee4e10574faeae85e9b6
+Payload = ca35bdb54e73eac5a5200a296b3aba5f37c87349746102d4
+CT = 3d90d4582e659372b7c6bf42c54b300bae3bdcf20deeeaa165c1cb98da4a1a920ca1ed9a7b6ec514
+
+[Alen = 11]
+
+Key = 50412c6444bcf9829506ab019e98234af1541061557412740bc120b456052763
+Nonce = 85684f94c3702c5d870310166d
+
+Count = 110
+Adata = f706a3e09df95d3e21d2e0
+Payload = 6cdbd63f6d591f59776f828533b28e2453a214d1d0dd8a39
+CT = 8c8b4ae854a5d5c265b25e3b54bded9444cc454b3e0e6a24d6c05eaf406a5ebd578e19edd5227380
+
+Count = 111
+Adata = e46b25b9a41a858e87900a
+Payload = 100132c315bfc9c4fb93023f5d3500d7208a68acb4d2c630
+CT = f051ae142c43035fe94ede813a3a636737e439365a01262d5088446e42591c0ede68e82334d97cfa
+
+Count = 112
+Adata = 28d34b29afe6586fd9bf0e
+Payload = d5460c1db0d24dedc63c4c78ce6d1f0b2d46f3b01934525c
+CT = 351690ca892e8776d4e190c6a9627cbb3a28a22af7e7b2413eaaef2823f5ac3f313f560bd774d10e
+
+Count = 113
+Adata = 2852d4fd68a3e9e47d44a7
+Payload = d2d73b62e3b1c9ab75f3544ff8616741e0adbae84b8cf9d0
+CT = 3287a7b5da4d0330672e88f19f6e04f1f7c3eb72a55f19cd62d30d99bb7dadec34e2891c156a1f5d
+
+Count = 114
+Adata = ec1c17b2ab13d7c8ac874f
+Payload = 74796d78d6ad03634ed80800af530212baa7e5093651cedf
+CT = 9429f1afef51c9f85c05d4bec85c61a2adc9b493d8822ec241c9a05ebf9ed27792bbced83b5dc582
+
+Count = 115
+Adata = 4f1ab5ddb1c199e9a5daab
+Payload = fb432488b5d08d576a90f085181ad883407a6ce9ea29950a
+CT = 1b13b85f8c2c47cc784d2c3b7f15bb3357143d7304fa75171ffc24020e86b1314724104e6b57b3ce
+
+Count = 116
+Adata = 864e0e728aea856fae6c6d
+Payload = 2b82d96ed1778412378abe4e09c633acf3359b9709ae3dcb
+CT = cbd245b9e88b4e89255762f06ec9501ce45bca0de77dddd6539bbb0af8ecf77b4508533247b3501a
+
+Count = 117
+Adata = 21ee21a5ed0d75d0380a28
+Payload = 85143071241bb65261fe7afcc102416e59b9e46ee0c90073
+CT = 6544aca61de77cc97323a642a60d22de4ed7b5f40e1ae06ef8981ec6ce7c4687b178f2103fa8c8be
+
+Count = 118
+Adata = 2b63f7b676f13f45d103dd
+Payload = 185577b48237acbdaa3590b8057fe374f875ce829b62c98f
+CT = f805eb63bbcb6626b8e84c06627080c4ef1b9f1875b1299265d9d899c6b71c0ab3049ea1dbfaf6a9
+
+Count = 119
+Adata = a33e86d813c2c4ff3bab20
+Payload = f051beb936e60fd4f3bca31964f1ad3e6fa16dd27b65a6db
+CT = 1001226e0f1ac54fe1617fa703fece8e78cf3c4895b646c6b246474c4e79822f5fd55f2fb0067a40
+
+[Alen = 12]
+
+Key = 8a56588fe5e125237b6cdc30f940b8d88b2863ec501a0cb00b1abade1b5ce0ed
+Nonce = d80210b9f9776ea36dc0e0a787
+
+Count = 120
+Adata = e4296d1c8cf4ffc4b2635135
+Payload = c825952293e434ea866db558aaf486ef09a92bf366988f71
+CT = b8b3b15fdf6a4a0b5abc313afc769e4e8413bd887552583ede3ed995d1b70561c8e28a7b1a7e3dc8
+
+Count = 121
+Adata = d18bfcc1584eeb8695388ebe
+Payload = a1e0248355bfd1d881fb1a4798cda2f6f6ad513c69c5f9b4
+CT = d17600fe1931af395d2a9e25ce4fba577b17c7477a0f2efb561575f6743c5759494be59afa0c3e11
+
+Count = 122
+Adata = 14682301a99bf680805d1ffe
+Payload = ded135fcbf62219bfba2cba40c2d2cbe4815ddaac1342231
+CT = ae471181f3ec5f7a27734fc65aaf341fc5af4bd1d2fef57e34f689367228cbaf3cd76fb407109cf6
+
+Count = 123
+Adata = 8853aa2dfea9c4d370678bb6
+Payload = 12d3900c6c01968b8344762e0e883e5e219f42b052dc6215
+CT = 6245b471208fe86a5f95f24c580a26ffac25d4cb4116b55a2cacb7fc3856abcf759feb8dc0998ab1
+
+Count = 124
+Adata = c5d3b9c593c3185fe4b6d1bc
+Payload = 8c3c1193fe1a1ebad7e01a1eed1a32c08a0091b1c948e184
+CT = fcaa35eeb294605b0b319e7cbb982a6107ba07cada8236cb42a740cd3262424a2c3d77849ead6149
+
+Count = 125
+Adata = dfb9e8149b51f89b1ec00a8e
+Payload = 8219618b7728ac89237705ecf84012cc7c80293c4cf171d8
+CT = f28f45f63ba6d268ffa6818eaec20a6df13abf475f3ba69747d4dbe0f9415d40843070e1e93059eb
+
+Count = 126
+Adata = 08a4590d262e4dbcb7e23ffc
+Payload = b344b7dc239617fa51b9ea10a349e940c3163779f5284c9c
+CT = c3d293a16f18691b8d686e72f5cbf1e14eaca102e6e29bd31215b3dccba4ca5de64be7fab8a7a22c
+
+Count = 127
+Adata = 74aab7b5b96238710637c6e5
+Payload = 740d4b25ca7221d0826057701a6bfd66c50a82f010a57be8
+CT = 049b6f5886fc5f315eb1d3124ce9e5c748b0148b036faca734e09945ee44c95c7923d8b9249ade7b
+
+Count = 128
+Adata = 420aac47a3f212fffca40549
+Payload = 5d9000489186abdf4f0a2794f0222fcaa156fe6309c10f79
+CT = 2d062435dd08d53e93dba3f6a6a0376b2cec68181a0bd8360a568dd779526a0058d522af1dafde30
+
+Count = 129
+Adata = 6e80dd7f1badf3a1c9ab25c7
+Payload = ac2c44263363810bec3a309aa618b303e05099dfdbeb5c16
+CT = dcba605b7fedffea30ebb4f8f09aaba26dea0fa4c8218b59279442c88d612ed1a39ae0005f88155d
+
+[Alen = 13]
+
+Key = a4cc7e1c90f8684e6a5f95e6898ab4e3c194cb46e196d8228062b9f3fa744930
+Nonce = cdc2712e51c7f333d6bad78eee
+
+Count = 130
+Adata = 569c56b27268d3db54e728aac0
+Payload = 10d4cff95ef490923c9e0906880729d4d05412e7675cce76
+CT = be3ce3e9dc72499839a98ae52abb17415e8547687e8a3c7b8aaaac20d4c9276f2851cbba2b04d185
+
+Count = 131
+Adata = d75635b6450e43285fba966835
+Payload = c9db03e2efbab713b0b640421018d3971ffe2abd70fe8fa1
+CT = 67332ff26d3c6e19b581c3a1b2a4ed02912f7f3269287dacc121ff83891335dd1214ea6fc25f6a68
+
+Count = 132
+Adata = 70750acea6a05f8b7b425d262b
+Payload = add631ce5846ce71434aad4998f8e429aed430e7d38bdbb2
+CT = 033e1ddedac0177b467d2eaa3a44dabc20056568ca5d29bf549e71ec517cd65150f42b3cb53f936e
+
+Count = 133
+Adata = 2a567c7ec7edaa5a438ae3bb35
+Payload = a514d170422feb1d87bb7725a9e77cc6fc8afb45c2af6d90
+CT = 0bfcfd60c0a93217828cf4c60b5b4253725baecadb799f9d0e432ec394ddbb65205dc40a5a8e90a4
+
+Count = 134
+Adata = 0f8795385b805246a0a2573afc
+Payload = 79d8841ab83279724ce35e1a8abd4e158168dcf388ab4c3d
+CT = d730a80a3ab4a07849d4ddf9280170800fb9897c917dbe30926b0d977107a3918717f79b63f36b0a
+
+Count = 135
+Adata = 111d224c102b136159fbeb44a7
+Payload = 2edd498e54b23aab6f4fd7b3f22c4c787e3a4f1fb06c9ec7
+CT = 8035659ed634e3a16a785450509072edf0eb1a90a9ba6ccac2cd61599bb93db3dd3dabc12aa90932
+
+Count = 136
+Adata = df0821c9ea6ab329c626d11b4b
+Payload = 6e3e25db29da2c787bb37755ee770e2402fb8208da23389d
+CT = c0d609cbab5cf5727e84f4b64ccb30b18c2ad787c3f5ca90bd027ecd00cc6dc5ffd5d746d92281e9
+
+Count = 137
+Adata = aacaf4839c35338d6e2b47ac45
+Payload = d4ed4584678e982ace8664e77d0e55be356be558cead3755
+CT = 7a056994e5084120cbb1e704dfb26b2bbbbab0d7d77bc5583c01354a450eda2588be7578530e38c0
+
+Count = 138
+Adata = dc6eed3f8bd1b5563c1eeb9afa
+Payload = 4ebf00eadaf70711f630f5badf0214d8518a200afb0e5765
+CT = e0572cfa5871de1bf30776597dbe2a4ddf5b7585e2d8a5688d7a1d546e25ba026cd46556eb2c4b7e
+
+Count = 139
+Adata = fbfe7e910f242a78dd6e69a2ec
+Payload = 2729636112f2abe2c76ea5e52a3f80b0f882f0f3b6f7c806
+CT = 89c14f71907472e8c25926068883be257653a57caf213a0b0e951aee790239e7067ef37f497b4bf4
+
+[Alen = 14]
+
+Key = 347e12eec56e95aafcc7d25bf10fc756b4e42bc2e43da7f97df24331f27f1f5c
+Nonce = b8d517b033754058128d13d11a
+
+Count = 140
+Adata = 511c6924fa96db716f6b053b7a48
+Payload = ca88dddfc876a12f45f19562bc9ca250f43267ab251a7f34
+CT = eeedcfa8f5b5b48c1d7e277526eecb7294213b9f5785167ae949b93003dfe63c95c1d49edfb4de3f
+
+Count = 141
+Adata = 10c26d5939618189a9503623f55f
+Payload = de0c0d17c3950e7f8985b56d60623cbd010cd765da4df5ab
+CT = fa691f60fe561bdcd10a077afa10559f611f8b51a8d29ce585c32a90d77fed97eb0ac164ed616e1c
+
+Count = 142
+Adata = bc09c59d20e55a9e184d70af2c7c
+Payload = 2f35102d78a32fcde1cfb563ea8d310ecb83c146ab8de362
+CT = 0b50025a45603a6eb940077470ff582cab909d72d9128a2c180fdf5f63045f326057cf74fd4cee6b
+
+Count = 143
+Adata = b75887f13d6e8c4b35b27b965693
+Payload = a3fcce3420effdd6edb37271735a0d30c10c65233aee173f
+CT = 8799dc431d2ce875b53cc066e9286412a11f391748717e7134959a180fc2cf2ba99af21cc1bc8e5c
+
+Count = 144
+Adata = 603401a9b8ecde4d5c86b6107363
+Payload = 4ac918727e41b8c536484e3781c403e260c278712853508d
+CT = 6eac0a054382ad666ec7fc201bb66ac000d124455acc39c32ca2e5195dbd44f0a119538c95788510
+
+Count = 145
+Adata = 7206b06f306124ca3a302e84c5a6
+Payload = 97d770cbb2c42a552e450cc4e35e5668b2ff89cec735cc91
+CT = b3b262bc8f073ff676cabed3792c3f4ad2ecd5fab5aaa5df74a4e1198878a76291594b9826d4b563
+
+Count = 146
+Adata = b15efed90a5d1d62f545ac22af6e
+Payload = 86bb2ae50e36c72936240a74502172625cbca210cf285077
+CT = a2de389233f5d28a6eabb863ca531b403caffe24bdb73939ff5f993dcfbd048274da7439c0f9ef5a
+
+Count = 147
+Adata = c9eb714ed9858a8dc11a26ee3f00
+Payload = 0dc79993047fd6e7260aac4d847fdb4d16483f28b13b5f17
+CT = 29a28be439bcc3447e851e5a1e0db26f765b631cc3a436590e87710559a375ece6ef2953b6aa2542
+
+Count = 148
+Adata = 07ca22271e95cb48a872046822b7
+Payload = f950e96d65a55efb3be3a55daffb421afad1d5625e3440a1
+CT = dd35fb1a58664b58636c174a35892b389ac289562cab29ef998035c81716e2d1ed4b4d56ff18af5d
+
+Count = 149
+Adata = b65f6773516124317cfb4b1fcdf5
+Payload = e160e28e601a49d16db18f25410756b330b036c42e615fd6
+CT = c505f0f95dd95c72353e3d32db753f9150a36af05cfe36981ae73a9b6896d8fc1b8c0d772d632983
+
+[Alen = 15]
+
+Key = 520902aa27c16dee112812b2e685aa203aeb8b8633bd1bfc99728a482d96c1fe
+Nonce = ddf50502f414c1bf24888f1328
+
+Count = 150
+Adata = 22b4f8f1aac02a9b2ef785d0ff6f93
+Payload = 533fee7d2c7740db55770e48cb1b541d990ea3f8f08ed1a6
+CT = fc867b319e0e4ab45ec518a1b5dcec4f29982173f3abfd4d8a8f8d14d2bdac84c3737cfbd75b7c0b
+
+Count = 151
+Adata = d0a43de391d492746ecf322acd6e5b
+Payload = cced20b59a6b2c3c45ea6c87802440c9c47b1015e83d86c3
+CT = 6354b5f9281226534e587a6efee3f89b74ed929eeb18aa28fce59f5e6e3cee284b4cc747ff5ee13f
+
+Count = 152
+Adata = 3a789c06f87f05933c34a1cf9834a8
+Payload = 90939a4530181ad6900664f66bfc2ce0289432a0afe9babe
+CT = 3f2a0f09826110b99bb4721f153b94b29802b02baccc9655ddaef56d8255125f7c316c6c59ce779f
+
+Count = 153
+Adata = 785260973f112c56d9f891160c4c11
+Payload = 86cd926b9565b76a88fde73c31e9ac908ffd1e6ca30b59ce
+CT = 29740727271cbd05834ff1d54f2e14c23f6b9ce7a02e752555810cbcdf48f05d0a7808673c82d08d
+
+Count = 154
+Adata = bf6a144591c0ea7b10274fbd3345a1
+Payload = 6ecd1c1acc6290672f9cf639ed0cebcb21ed0c56f35a5ce3
+CT = c17489567e1b9a08242ee0d093cb5399917b8eddf07f700849e41e5d34a698ae1d96f16bc68da944
+
+Count = 155
+Adata = 7d9488b500d89a27f367f34a448a87
+Payload = b01e3f4fb5ee7501e8c2f4ccefb542ae20d7fd61a2c41c8b
+CT = 1fa7aa0307977f6ee370e2259172fafc90417feaa1e130601bc54e546d1a6fcf6187169feb1ea533
+
+Count = 156
+Adata = 060fc718e994edc7bac9962ca7f28d
+Payload = 22ab6a0daf953165dda864cceeeb782e275c0b072aedd284
+CT = 8d12ff411dec3b0ad61a7225902cc07c97ca898c29c8fe6ff2eb6c0ab42acf42985c721bfd576e71
+
+Count = 157
+Adata = cb6f96dd06015967279ade310a7401
+Payload = f96ed20b23c784015ff58f5f040798ca75e3b98045deca8e
+CT = 56d7474791be8e6e544799b67ac02098c5753b0b46fbe665ac502b8e65cc1329b6895afdd354f5db
+
+Count = 158
+Adata = 9aa6d501455019b4ef4c7fb789d22f
+Payload = 648a84813ca97aef4ab7e143ee29acb946388660f18eb671
+CT = cb3311cd8ed070804105f7aa90ee14ebf6ae04ebf2ab9a9a87e5f8a8148f21adf721477c36bd99ca
+
+Count = 159
+Adata = ebd1d12bbd14176a0d4080aa1edb89
+Payload = 32d71e59634126ac6c6156a80a0dfa0175b29e9f40a31696
+CT = 9d6e8b15d1382cc367d3404174ca4253c5241c1443863a7dda9ea0427522dbeaa509a11755434760
+
+[Alen = 16]
+
+Key = 57da1c2704219ed59abfdf04743a9a93c87a63d471818de0f1564b2db6421562
+Nonce = 4b60a47b7e90f622fa0bf803e1
+
+Count = 160
+Adata = 0ae8c012ff39753510df3ee80707e4e2
+Payload = ddc3c1aa73fb6de92bb4db138e26f3c2e0543ab4f5924871
+CT = daa8256d4753fdf9cfef876295badaba89b45cc497f54d220ec2c6fb687753bca4580adc6aa2f296
+
+Count = 161
+Adata = d5b22e7697ba70e00c7ef32709563f01
+Payload = 34270576724083e9989764d08a0d5c1b4738f34927a1e436
+CT = 334ce1b146e813f97ccc38a1919175632ed8953945c6e1658f30b9c8e380c98bb939a4e8a85af758
+
+Count = 162
+Adata = 6b4edef415763aabcef01863e8197aec
+Payload = 904fe88e7a8e76447a64b488ef84184d0f1ab1b67f0c5a7d
+CT = 97240c494e26e6549e3fe8f9f418313566fad7c61d6b5f2e53e80d8ccc687fd303f4cdef44b6e8b9
+
+Count = 163
+Adata = 4c099809061024c010a77e9621fc2bcf
+Payload = 51fe7bac8f3255f17f64fb9322210fb7d8da8e762498b233
+CT = 56959f6bbb9ac5e19b3fa7e239bd26cfb13ae80646ffb7600c635dac5b70338dac3f33ce16a99145
+
+Count = 164
+Adata = 9d329439588164d5a96675a85c07a039
+Payload = eab6dbc13bb92df36b1882df2b8f34c3cefa41f95717fbd7
+CT = eddd3f060f11bde38f43deae30131dbba71a27893570fe84f996e8163affb1494bb3c12eeadf16b6
+
+Count = 165
+Adata = b768fc3daf29ff9e8bd575072d986e99
+Payload = c44c9c287d3eac7c30570d9c4adf2e4857c598f7c54cd126
+CT = c32778ef49963c6cd40c51ed514307303e25fe87a72bd47598b4206a9622d5631751a497dfb1f662
+
+Count = 166
+Adata = 3efc7cc2d16bf82d2bcfbc559a09b2c9
+Payload = c11b9c9d7607f387359c0038d3e8ec4d527562ce63c3384c
+CT = c670785a42af6397d1c75c49c874c5353b9504be01a43d1f7dd300167d267ad700dea37fb475ecdd
+
+Count = 167
+Adata = 0ff89eff92a530b66684cd75a39481e7
+Payload = cc17904b166f28df82f57889f391159a4a308e752d714ee5
+CT = cb7c748c22c7b8cf66ae24f8e80d3ce223d0e8054f164bb6303e9c9bd0d8e4aac42894ca03d6ab06
+
+Count = 168
+Adata = fbd11bc75759f0461e796f6917aeb42b
+Payload = 6f97e595ea2f40612ea84a2097b974d235055fe1dae59403
+CT = 68fc0152de87d071caf316518c255daa5ce53991b88291500953f46e0e9cf1369e9eb018a4df3c09
+
+Count = 169
+Adata = b79940952f42537484aa2907c72dffa9
+Payload = a48cbf933b88c0ec5ddcdd8fcad186391c2cbef308607de5
+CT = a3e75b540f2050fcb98781fed14daf4175ccd8836a0778b68a1702dfa0cd9c290c5ff9c35cc83705
+
+[Alen = 17]
+
+Key = 9267ebc99ccf648b146cba3c251187e24a9947d806ceb0ced6894211641a1e0d
+Nonce = 9b7298950280e8762ecdc9bbe4
+
+Count = 170
+Adata = 5824689453bc406bf891b85e4576e38fe8
+Payload = 967daf12f16f166b7b5038f83a1cf0b980f5abf4c7746f2a
+CT = 7cfe2a7a54306eb8d8a63d3d1ae86794f9a2c22198b2cb4f10ca926f1a430c08c12e23db3d913e93
+
+Count = 171
+Adata = cd15973753b94b77bb4b778de8b3b0cabb
+Payload = c4a756f6024a9dceabf6e264fffff9c719217fb418141ac5
+CT = 2e24d39ea715e51d0800e7a1df0b6eea6076166147d2bea05d5b674fd15410cc235dba6d8c8d82a8
+
+Count = 172
+Adata = ed8540f7ce451c522c1ff5d2d1030d7b3f
+Payload = e0d5de7d1eace211c0e70859ff315ff485d1200c6dd13f93
+CT = 0a565b15bbf39ac263110d9cdfc5c8d9fc8649d932179bf688750b5f36c86e7eda9015e960a7471a
+
+Count = 173
+Adata = cbbecf92551a15f5cf00a5be4a50b0eb17
+Payload = 05a4a4ba28fe8876f9bcfa5ec60651fd3fd4732f22049bd5
+CT = ef2721d28da1f0a55a4aff9be6f2c6d046831afa7dc23fb0d5fa842209dbbc04c87965f78500fec1
+
+Count = 174
+Adata = 873ba7f8b71517ec50297b21cf94cdb7a5
+Payload = 9cdebaeee8690b68751070691f49593668a6de12d3a948b3
+CT = 765d3f864d3673bbd6e675ac3fbdce1b11f1b7c78c6fecd67d147edbe114bfdb3f3b9b37d5719ef5
+
+Count = 175
+Adata = ac087420feb1e1e8c2546c2a8b8a5af0d0
+Payload = 5672e61cf664d73918dc1ca84df1fce82db0e305a61d57b9
+CT = bcf16374533bafeabb2a196d6d056bc554e78ad0f9dbf3dc57b4c2bbc377937d15b3b89543e29d0e
+
+Count = 176
+Adata = a12c690568114fd7a677f49d74e84fc1a6
+Payload = 0f5452e6b51540cf219998590995cd7f8785fa40b4f217fc
+CT = e5d7d78e104a381c826f9d9c29615a52fed29395eb34b3992e6ca774074b47b59adabeaf8835582d
+
+Count = 177
+Adata = 7a78ddfe5afb2dc90ee4a600c2fc014b0f
+Payload = 9ad338cbfd1b52e6ae4178f05e00062274f8b0b25eae72f7
+CT = 7050bda358442a350db77d357ef4910f0dafd9670168d692bd320f48a7221537e3cbed5ac4154a56
+
+Count = 178
+Adata = 6053e466ed1f647a3cd88c4d2052ec00cb
+Payload = d17b8d556e83190c84d4a812957c64ffa7f336298f4e2c72
+CT = 3bf8083dcbdc61df2722add7b588f3d2dea45ffcd088881740574e201f9a26932a87c8d822505814
+
+Count = 179
+Adata = f7673e3beb526834d6507058fe62e34987
+Payload = 2eaef86b0f602364f86510eabc58bc9ad1e6f0a6f6df0b83
+CT = c42d7d03aa3f5bb75b93152f9cac2bb7a8b19973a919afe6837dfa3fdef2f012b6609de2ac5dd9d6
+
+[Alen = 18]
+
+Key = 7a855e1690ee638de01db43b37401dcd569c1ae03dc73dd0a917d0cadb5abc29
+Nonce = 8f160a873a1166c8b32bccbba7
+
+Count = 180
+Adata = 72674aca7eba2fc0eeafbd143c2c4d8aa6c8
+Payload = 33ae68ebb8010c6b3da6b9cb29fe9f8bd09b59ec39f4ce4b
+CT = b22afdf4f12c43ec23e01ac1215a3f5286059211207e957057e9a9203da74387a9468f8af5e27547
+
+Count = 181
+Adata = f7da3f100b80e2ade812f1700aab6b72f746
+Payload = dbb29817b86cb80e0d008742cedfbf52b236f15ee8cad50e
+CT = 5a360d08f141f78913462448c67b1f8be4a83aa3f1408e35a3985f12a49eac424a35c94645917e91
+
+Count = 182
+Adata = 4b05eaadf98505d0806c233b2cdcaf4254e8
+Payload = 145aa8cfd544a2f46bae1aa83cbdb3d21c3d1350078a3af4
+CT = 95de3dd09c69ed7375e8b9a23419130b4aa3d8ad1e0061cf4ab089a8724b87a1167180963d44ec65
+
+Count = 183
+Adata = 05a3aaa08b9a6aaeb84704431425d0e45a14
+Payload = 6b32e8906dc89194a69410b79cd041b62eb01afb28a3e10a
+CT = eab67d8f24e5de13b8d2b3bd9474e16f782ed1063129ba310a7d1520141892e140448292185c41c7
+
+Count = 184
+Adata = 74db01edc26a2d2044cb8eaad8b907b78863
+Payload = 545ed03588fd85a8bbfeee66d2082ae6f8e2f3c9dbd8725f
+CT = d5da452ac1d0ca2fa5b84d6cdaac8a3fae7c3834c252296472d3eee219d94bd788f62df4add5ec40
+
+Count = 185
+Adata = 5f2c6ddf5a2403e04dac8b2813c060b67e76
+Payload = 66dd5fd8611c551973a3d0c078ec2b4d39ad163d9168de3c
+CT = e759cac728311a9e6de573ca70488b946f33ddc088e28507c600496f4f8b1b7da118ee36d8cd57f8
+
+Count = 186
+Adata = a650a2a5e3c6f7c95614570aaefd0cdd9a42
+Payload = 6f364b3f778376cbf3f4b0b0c5350a8fa278f9d8c25faad6
+CT = eeb2de203eae394cedb213bacd91aa56f4e63225dbd5f1ed4710004d06ce7a7efbd19da4e3ce3cf7
+
+Count = 187
+Adata = 477c2484cf5c56b813313927be8387b1024f
+Payload = 3de4798d8ad84c460b92abc10b7f5e7c9fae46a1dd353687
+CT = bc60ec92c3f503c115d408cb03dbfea5c9308d5cc4bf6dbc304099641c4ec3dc2c54fdf4f48dbef2
+
+Count = 188
+Adata = 564e1df74aa2d7ee33b66cfeda810774e16c
+Payload = 7769b45fea11f530fb9a67f1b5b1964a34cfa32bbb03f4b1
+CT = f6ed2140a33cbab7e5dcc4fbbd153693625168d6a289af8a905c1b05e8945685f8688faea777eb43
+
+Count = 189
+Adata = d5e66502529b0045883d935e05acd242baa8
+Payload = 0c0a502b42f81b51806c7080a8155280f493f2922cdc7df8
+CT = 8d8ec5340bd554d69e2ad38aa0b1f259a20d396f355626c3ea5a3b6a8bafde4006b993cfb3b13557
+
+[Alen = 19]
+
+Key = 0ebdc6ddb4c502725dd6ee8da95d56a0d1044b4694d6ba8475a4434f23a8474f
+Nonce = fb717a8c82114477253acc14f6
+
+Count = 190
+Adata = 41e9d65632f74f449a6842d5e6c4a86ef83791
+Payload = c7360282c85484a5a33ab1c68dd70873ab4e74ffd4a62cd5
+CT = 2e961b3a2fa1609a4e6fd04bff6ac5e306ae2638706f997b42be2e2ba05c54b619850db5c9d684fe
+
+Count = 191
+Adata = 555304659bde926cb2553b8a4605251fcddd92
+Payload = 1332314d1cf783b9f64e0fa2d42d43d225da9fd5165b5f0a
+CT = fa9228f5fb0267861b1b6e2fa6908e42883acd12b292eaa4bbdee2605bc69601b1e83d1e7a0b400d
+
+Count = 192
+Adata = 69ea953dbb910ec589372d797c7379d3f3b9e9
+Payload = f264da8606ea429e0e25da3f2efafe28beaff05b42097369
+CT = 1bc4c33ee11fa6a1e370bbb25c4733b8134fa29ce6c0c6c7304611baf530932da7954f714514d228
+
+Count = 193
+Adata = d7186a67061319b44eedc0677ebf5d932d5bce
+Payload = c9ee6482144dc61c43041324a2c18ede370011cb4882b0c5
+CT = 204e7d3af3b82223ae5172a9d07c434e9ae0430cec4b056b6d1d44e26404b7324767f0b3f7486f8b
+
+Count = 194
+Adata = 38f37d5e2da017f1953ff3701be0b38809ba80
+Payload = 40524a4d32a711e7d5a59809878c318f42b6e2375b77b8a7
+CT = a9f253f5d552f5d838f0f984f531fc1fef56b0f0ffbe0d095453724d2db19f606c85d00e49b0bb38
+
+Count = 195
+Adata = b3b2d249cd3517555fa692bbe9116f069e7405
+Payload = 961c15bd7dc34cd5409c9e8869988676ec6845ecb0ee85fd
+CT = 7fbc0c059a36a8eaadc9ff051b254be64188172b142730536db1e4112fcd650e8c0f0f6fbf2d07e1
+
+Count = 196
+Adata = f5b5bcc38efaff01f69bd3a106dcfca3cc6414
+Payload = 879568ab9ebdea768a5459ced1d3181d822536c3d1ba38c3
+CT = 6e35711379480e4967013843a36ed58d2fc5640475738d6d1cedb29e68322e47ff9997f859257d98
+
+Count = 197
+Adata = a2098e3e23826e01f31107a208202f710eff00
+Payload = 47cb57599686716c75d7ecef5541d20fb908e6d98c39925a
+CT = ae6b4ee17173955398828d6227fc1f9f14e8b41e28f027f41c12bf2a3571ed672592b27e986e9058
+
+Count = 198
+Adata = 20a3d53e77201599540344c4e746c3ae3a5f84
+Payload = 4a8667b5ee09d3d4a6dca9a95f4ad406f1da94b846dcc6b8
+CT = a3267e0d09fc37eb4b89c8242df719965c3ac67fe2157316f12b2be8f5966d96602111c28f87b104
+
+Count = 199
+Adata = 92c592ead4b3f193cc36687593d4f0f412a5d5
+Payload = 1dc9e32ac4176f64bd78a6edd651ebeea3ba85dfcd8298a8
+CT = f469fa9223e28b5b502dc760a4ec267e0e5ad718694b2d06776df0a0cf048892e65bd8ad77cb2255
+
+[Alen = 20]
+
+Key = 2ff64bbec197a63315c2f328dcb4837d0cdc21a5d6f89ff1d97cb51195330cd8
+Nonce = a235f8ee3de9896b71910ac02c
+
+Count = 200
+Adata = 2b411bea57b51d10a4d2fb17ef0f204aa53cf112
+Payload = 4a17522da707b4b2587a0ae367a2cd2831bb593a18ef442a
+CT = 1bf122798bd8ee8e73391d589bd046a294d1615794e69cb9e6f3ba30143acbc3a1c1c6ec74333107
+
+Count = 201
+Adata = 0248359f8071143c3cc1d61882a3547a0b3d2175
+Payload = 4a6a7151465c2abd7e7fa1fd13019ad098b6ebcd190e96f7
+CT = 1b8c01056a837081553cb646ef73115a3ddcd3a095074e6436cb510c13a039f4df8cc26a942f9911
+
+Count = 202
+Adata = cca77bc4cf6c0abd3393dac3fbe90fbc8a1154f7
+Payload = a94f5ede43929d48d2c5a58c3262d9127d2ac3cb2fbd5768
+CT = f8a92e8a6f4dc774f986b237ce105298d840fba6a3b48ffb7fe0dedc2899dff81a251cff16bf5897
+
+Count = 203
+Adata = 9c082a84646c070bb11b7d6b92b62f06ee5b5b71
+Payload = 7303bd41cf47289a3111366d08e8e21548baf293052029eb
+CT = 22e5cd15e39872a61a5221d6f49a699fedd0cafe8929f17886c43ac23800de60a1fd2caef0f03261
+
+Count = 204
+Adata = 1c3ede1982a807a410ae1e21947bf430f8db7027
+Payload = fa9743a67978c20316cb91801d7789e350079aae3aadbd43
+CT = ab7133f255a7983f3d88863be1050269f56da2c3b6a465d026f7907e235c09d3322c4092d2e88f88
+
+Count = 205
+Adata = deb05a30a026ff66ce71e98afa62f0255aef84f5
+Payload = 99599b4042dcdb685350cdecfdf24992fd5b165670025d0c
+CT = c8bfeb146e0381547813da570180c21858312e3bfc0b859f6bb44a28c145d49f49f2821d4044e4b6
+
+Count = 206
+Adata = 93dd9b00a3353e5331338dcfcb7ca7e0bb873a4e
+Payload = 451101250ec6f26652249d59dc974b7361d571a8101cdfd3
+CT = 14f771712219a85a79678ae220e5c0f9c4bf49c59c1507400f7d20aa3d792d6a3ebc5ee0df2fd89c
+
+Count = 207
+Adata = 0855263860043207543c8c34648d53ec51c4f47e
+Payload = b2db87b7787531968d603098cb20ca7c438b4af72623fea9
+CT = e33df7e354aa6baaa6232723375241f6e6e1729aaa2a263a7ca4733f0208668b0a7879305e861d71
+
+Count = 208
+Adata = ee2d3a66deb3ebca867a902bb9202226ed516ded
+Payload = ca18ce38086223e63b4f0b616d110010f9e45eac42f2ba46
+CT = 9bfebe6c24bd79da100c1cda91638b9a5c8e66c1cefb62d5d76b482ff20429da8f60f0f863e1af50
+
+Count = 209
+Adata = 8e531aaea849addab6a83497cbc504f489505952
+Payload = 5717ed5da5b8aa806a18bfe979502bab6632c9428d3a7725
+CT = 06f19d098967f0bc415ba8528522a021c358f12f0133afb6aab66e1ac2346ef97850a4985c64b737
+
+[Alen = 21]
+
+Key = 24e9f08a9a007f9976919e10dc432002e2e078a339677f00105c72ed35633a3f
+Nonce = 15977424eeec0ec7f647e6c798
+
+Count = 210
+Adata = 2d838eb51a4bc69a001a18adf2084a680f02a3c5fc
+Payload = d3416a81b4246eb0bf8119a72a886bbc0ac9449c69f71d2f
+CT = e001a8fae390dc5d672cdd18f86a1f728158ec83a002050def9af5679edbcbb7db20ab6af30698db
+
+Count = 211
+Adata = d83ee7ce22fd1a2882d8d552346e4d7b3efdd67da4
+Payload = 22b6f10b482448626f6c7bebb14f1497896d071738133b4d
+CT = 11f633701f90fa8fb7c1bf5463ad605902fcaf08f1e6236fd435a5a38f84387f63b13407f65ec86c
+
+Count = 212
+Adata = 2d5537b24d0b0f7a45703c1e131656ec9edc12cdf7
+Payload = d60edc830be8207ffd9e9f646d3b4343b10b3d56acb89d44
+CT = e54e1ef85c5c929225335bdbbfd9378d3a9a9549654d85662ede8a705f8c988f55459542bd631b1c
+
+Count = 213
+Adata = 1a750eb326923412d94ccb35f5acd0f87415268178
+Payload = 716d3132f449a9def383978102ae50ed3ccae0cb346ba1df
+CT = 422df349a3fd1b332b2e533ed04c2423b75b48d4fd9eb9fd986de774a612230ce6c71449d26732ce
+
+Count = 214
+Adata = b10fc523bc4562d44edfe5956f93c15c4ab38bba3c
+Payload = 063c2ae2a15f26f979bf90657d20643e3184f1a9f75a3aad
+CT = 357ce899f6eb9414a11254daafc210f0ba1559b63eaf228fe710431005264fa7d3fc04bac50fc1ec
+
+Count = 215
+Adata = fe4f60ce9634e7dbc5e56204c4bf8aa9be577027ec
+Payload = bdc513e56a5bb70c02abc041af04d6e45e735d10cc88357f
+CT = 8e85d19e3def05e1da0604fe7de6a22ad5e2f50f057d2d5d5c13bea6ad0cad724e6cd02c89517ffc
+
+Count = 216
+Adata = 48f3ceda4fd390a7eb38f7f5bcd14310af6b5a557e
+Payload = 7dc5d8cd90ce2faf76bbd0d52e5ae11b310fc2b0051c4377
+CT = 4e851ab6c77a9d42ae16146afcb895d5ba9e6aafcce95b55d2a5531655aae01e249f213e0e04af0d
+
+Count = 217
+Adata = 199ec321d1d24d5408076912d6bb2b6f192d6b347f
+Payload = 66c2696edec26ba3d07bd3f485a0d6ce8a1b0a85b20083e7
+CT = 5582ab158976d94e08d6174b5742a200018aa29a7bf59bc52a127ef341345f9641b26e91265e1482
+
+Count = 218
+Adata = 8b013f5782d5d1af8dbd451a4202866095dac975fc
+Payload = f4da8ac3e8fe5ec6a5b6a2f27b68396e850b46a024d441f0
+CT = c79a48b8bf4aec2b7d1b664da98a4da00e9aeebfed2159d2a005ca13c4bf715c3b7b2782f799b23a
+
+Count = 219
+Adata = e320df32b71cc530e8493b12b9afbeabc255c5eb44
+Payload = 244891cb4af66cc8e99a3784a2e82475e51bd5c7fde67cf5
+CT = 170853b01d42de253137f33b700a50bb6e8a7dd8341364d704642aff9cb9288d49f0e567dd837e05
+
+[Alen = 22]
+
+Key = 0ec1b22b8df05dc92135d2dfbefed8ea81458f5ea1b801e8a218faf6cbdf1a79
+Nonce = 97ebcb8575bb58260208d5c227
+
+Count = 220
+Adata = a2f6337f86dd00d1a58448851e95d8c9bace4a5c8710
+Payload = 2f59d94d4ab8eeb84c2a6fefb7fb0a3ac059c1e1a65ae34a
+CT = 7ca0b1dbe34b0391e524b868b0af08b3e096917664d6aa2cabc1f9d0132394149c9062b74b82f04b
+
+Count = 221
+Adata = abf26b05558252c8e38c52b1ace087bbd1eb3d561239
+Payload = c25381853f73a3dc4195fdcbc45dfa1a40eb8324749adb2e
+CT = 91aae91396804ef5e89b2a4cc309f8936024d3b3b61692486d7df57c6a792f6f6b24cb5f87e92123
+
+Count = 222
+Adata = a13ade56b47803897666e42ef2ef88be0e779ac86c28
+Payload = 8dc5226a2a13088c87f4bf94262e0c0413f06b35d2fda79b
+CT = de3c4afc83e0e5a52efa6813217a0e8d333f3ba21071eefd4ac19b0b74cd9d5e100598b96c9f1f2e
+
+Count = 223
+Adata = 3c5b68b65edf62755b7e064bd26c843816bf6c1cd481
+Payload = ee4b23039cd512cfab8c7a2d0f2c78d66764520bc88759e1
+CT = bdb24b953526ffe60282adaa08787a5f47ab029c0a0b1087a77a27eabfc79f192c0ac491280af8d0
+
+Count = 224
+Adata = 0213fe13c49083d7c00335e1864dc139c9e7123162d1
+Payload = 30b48d4021838090fbd5251069ff8c631452daee5ef899db
+CT = 634de5d688706db952dbf2976eab8eea349d8a799c74d0bd39935f91c1e29fc1e4c5c5427ca9da79
+
+Count = 225
+Adata = a32291746b151be8134e183798aa82bef210343feaf6
+Payload = 2286a1eddd80737a724ca941217e9f0232870b6c2f20d29c
+CT = 717fc97b74739e53db427ec6262a9d8b12485bfbedac9bfaaeaec90ada2a1ffef64c3873af645a40
+
+Count = 226
+Adata = a30f2fd445820cdf800145540602c877da0e4c311272
+Payload = fe703ca0901e4a706ce1393c7d8ce18a03eb2caadbfa7b8e
+CT = ad89543639eda759c5efeebb7ad8e30323247c3d197632e87932952831d0ba25c77c18fe154d8ed8
+
+Count = 227
+Adata = ed438e393e0e37629cb25044ae89de9fd0d42d60c1a3
+Payload = 7043c67726870bb5816da925925bc2722478311c8a606cca
+CT = 23baaee18f74e69c28637ea2950fc0fb04b7618b48ec25ac234fd0241d00f3890a23ccd0bf16dcbf
+
+Count = 228
+Adata = 1013946815001a2c08acca4196e0d6668ffbb3883cf1
+Payload = 695e9712dbbf883e9bf8af9188bd01fc631968928258168d
+CT = 3aa7ff84724c651732f678168fe9037543d6380540d45febaf43498b0c3f70c119f82d5812db940f
+
+Count = 229
+Adata = 44cc9b2510680c4d73f1938c77de21242c8ee790ed7f
+Payload = 67ba90d22c6bb5f649bc0c505c5ed23a299882559a3bf520
+CT = 3443f844859858dfe0b2dbd75b0ad0b30957d2c258b7bc46db66dbb03a4c943ac089ed11eb214bbb
+
+[Alen = 23]
+
+Key = 0875020959ed969cfb38636d1d5aabce9658b00171a7614ea9e5395331c7659c
+Nonce = 451101250ec6f26652249d59dc
+
+Count = 230
+Adata = 7cc9c51b69f98a06391ab32742fb6365e15106c811fe8a
+Payload = 065ef9eeafbe077c1c7049f43eb0d8999708e8609f214d5c
+CT = 990065322a438e136860f7b019807e9feff52a642bf3d44a9163fa7a867f04cab6f52dc250070f31
+
+Count = 231
+Adata = 7bb1bc069a783d45d51d8ecd0a53ab7a386fa1f5ef12a1
+Payload = 69b2b056f2265e707d3e31e68bff6a060544c8a737b2a9b9
+CT = f6ec2c8a77dbd71f092e8fa2accfcc007db90aa3836030affd33dd9155619fb040dcd6038c7b7367
+
+Count = 232
+Adata = 0dd220919d0eeee3b7cec36c47e376b778583b38bf61c8
+Payload = b98d79aaa4c04171398c7f1189497acaa7546ef068bc7a3f
+CT = 26d3e576213dc81e4d9cc155ae79dcccdfa9acf4dc6ee3294fcba5a886b1f33cf1cf44618d28f01f
+
+Count = 233
+Adata = 1c1915fab09348b9a5536495c70d1a040305708c112479
+Payload = eeaeb773ade5fb2d27b50bb892916333e0b123c6e3ae5bdb
+CT = 71f02baf2818724253a5b5fcb5a1c535984ce1c2577cc2cdeafe2c670eac203d5e90b9d520e7a618
+
+Count = 234
+Adata = 614b0ac4611b6c6d3b4ed089510dcd2215567bc3789f85
+Payload = f2198e1f91fde2672a1ef60403c0d175f366b6780ee9f1c2
+CT = 6d4712c314006b085e0e484024f077738b9b747cba3b68d4f0388746438e83b731b5588fef53f1f3
+
+Count = 235
+Adata = 866fea4483d4e903566844e31c24283571832dfae32c74
+Payload = ba37617342b4eefd4bdce8fad30c4751b206d47814973b3a
+CT = 2569fdafc74967923fcc56bef43ce157cafb167ca045a22cfca81f8b36d16698a600fd701f2c6424
+
+Count = 236
+Adata = 9d7546f7e8b949c539d21a357f81d0151e278d0bf2c5a5
+Payload = 69adcae8a1e9a3f2fe9e62591f7b4c5b19d3b50e769521f6
+CT = f6f3563424142a9d8a8edc1d384bea5d612e770ac247b8e04c15a6d292c7ed2f31cf9512435ec7d2
+
+Count = 237
+Adata = 42b692048c8b3cce1b5e83f4f33232a7d7d0bc20695e7e
+Payload = e0753d4248643642c7a96404de8d76c9d80527b659ec6d31
+CT = 7f2ba19ecd99bf2db3b9da40f9bdd0cfa0f8e5b2ed3ef427a2ad73179d0314b5fe52dd7217518cb8
+
+Count = 238
+Adata = f1dfb6fdb31cb423226f181c0988a52ee4015aef4536f4
+Payload = 79ba959c7221b293e2115f538d9394c64284c756563c04b0
+CT = e6e40940f7dc3bfc9601e117aaa332c03a790552e2ee9da69ccc5ba1caf933b80bfc6f281109688f
+
+Count = 239
+Adata = 8eafce9ba466fd53eb87f499d7c76bd486db0e90a3d281
+Payload = e1590206717a708cad9cca7d23a3b8ee5f7fb7786aa3be47
+CT = 7e079edaf487f9e3d98c743904931ee82782757cde71275173271ec36d92fff34609169f579c8f1d
+
+[Alen = 24]
+
+Key = ef4c1d2314e671f666cc6667660f1438a293208c7cc29b412d81277f0a635c91
+Nonce = 50b23b052922366c25dd40e348
+
+Count = 240
+Adata = cd0522ebe1fed82465277d1c10ae9316a98b4469be63b180
+Payload = c99c3e79125b6fd95e737326a842424eb6c6ecea4c0475c4
+CT = 76df4be4ec8373864399acda11294b220b9f7c3a7d2b3660b25764e40ac6a171e7e6bab4fdee4288
+
+Count = 241
+Adata = ce5bf070678cb07e963263b1562ff79311144addb6e4de4f
+Payload = eede01b08f9a303cdf14c99d7a45732972c6eff2a1db06eb
+CT = 519d742d71422c63c2fe1661c32e7a45cf9f7f2290f4454ffca49758d17f2073066b82667eae6ce3
+
+Count = 242
+Adata = 07175be2475cc735c9a3c1140895277378debf8fb1c87c24
+Payload = 6d5579aaaf8737b01620424f3ddeaf538f10dfad094e5ec4
+CT = d2160c37515f2bef0bca9db384b5a63f32494f7d38611d607c1d64d7e9de47a6ad7878283da9d870
+
+Count = 243
+Adata = c821a8d4bab9d993c20dd206955304a55968e6db5ab6480d
+Payload = d0628b2027f06c246497977d05f211b2c2e302d5b82700b5
+CT = 6f21febdd928707b797d4881bc9918de7fba920589084311adc2bb471862d25cfe25e66fedb8e28c
+
+Count = 244
+Adata = 68439bc9d176feeeb4119d00ed5449dfefb72b5a582bfd97
+Payload = 6cc9749f48c61050e421afa3a10ad3dd3aa02cc3f8586915
+CT = d38a0102b61e0c0ff9cb705f1861dab187f9bc13c9772ab1319a493abc947945f1312395ea98d937
+
+Count = 245
+Adata = adb262c924942e4e1964e9d97c6a8c159fbf9bfedc5ff296
+Payload = 92d50736466e64e6225962e76bd90da824f716a3301a1a90
+CT = 2d9672abb8b678b93fb3bd1bd2b204c499ae86730135593421d0602d29447ba6b24a67509eaee1e8
+
+Count = 246
+Adata = fc7b08707d3c3dac7689ec18088ee6502ef08d3ffbff38ed
+Payload = 87c7ac031fd63e4c83280dce6b68a92dfafb6ea19388fa9f
+CT = 3884d99ee10e22139ec2d232d203a04147a2fe71a2a7b93be52a2eeacb1f023e849161b6306b6cfa
+
+Count = 247
+Adata = fd43dfb66041b117f2ac54c94f7b6e2677860864d9494175
+Payload = 6b53c46266b2f4284d8fe7f0549c98977344d67e178e9a8e
+CT = d410b1ff986ae8775065380cedf791fbce1d46ae26a1d92a0d8c5b1e96b21460e0b5414639abeb0b
+
+Count = 248
+Adata = ef1ad3eb0bde7d4728389da2255d1f8a66ecb72e6f2f1ac4
+Payload = 8e7d8a44244daa7df2b340993e32dac50e05d7b2e103be98
+CT = 313effd9da95b622ef599f658759d3a9b35c4762d02cfd3c1c97260d20797d374c595cbc2ff080bc
+
+Count = 249
+Adata = 9895b24d12b004b215583eac70a95f4fba7442164f35c57b
+Payload = cec07df916ffb7a453d0eb588b7462096f22874bd5abf814
+CT = 71830864e827abfb4e3a34a4321f6b65d27b179be484bbb06cd287afcbdbc5531f11246080b22677
+
+[Alen = 25]
+
+Key = 8544808e8fbf8c3a5e1d4ca751d4b603af9fe119eabc6923205815e0e748b7e7
+Nonce = b44a58724596b4d8dea827c1a0
+
+Count = 250
+Adata = f5b2c88f5232c37273b1e66aa31cfa7201e33c21d60054d025
+Payload = 617d54fc6a23601c79e3984f93bfc2d151fde420863206b3
+CT = 57b3414db48982c6567265e1e0173bf38fdfaffe4461fbebc1411af83237c0f9eb0bfe8ed914da66
+
+Count = 251
+Adata = 8fabe14dcb3aa2fd28281147c326e98ad699ca7997f03a105d
+Payload = 337290d0b4ce1e87afc3cf01d6c98f8c17a4603120dcfcd1
+CT = 05bc85616a64fc5d805232afa56176aec9862befe28f01897ed6e23720b60ffe54bbb9f7ff371008
+
+Count = 252
+Adata = cf193eb3d755cb8e06c5be2334b5c8b7a22b6524d46d547ba3
+Payload = 01ef7ac6470aa02ccd8c1712827e52699d05751b78e4c5a6
+CT = 37216f7799a042f6e21deabcf1d6ab4b43273ec5bab738feb6aa6b284e7720acbd027a50317f816a
+
+Count = 253
+Adata = b4cadb5f9cb66415c3a3b71421b926f147566a174160a0bcc0
+Payload = 64fb9322210fb7d8da8e762498b233b0eb172c91231c50cb
+CT = 52358693ffa55502f51f8b8aeb1aca923535674fe14fad937058e9c0164ca079668097fde19e5302
+
+Count = 254
+Adata = 48400d76ff882d6d5129c8674acc71f445356c9db9c91f8256
+Payload = 291aa463c4babc76b4a6faf2e27e9401586b1ac83e4b06a4
+CT = 1fd4b1d21a105eac9b37075c91d66d2386495116fc18fbfcf988611d5ce0f65b217bb4787bf59bbc
+
+Count = 255
+Adata = 749d369d837002ad33feb8aa22c3f68705eb4872e1b8f85a7f
+Payload = 141cdd7f964a78815be144a785c6a2a298c54230e73039e2
+CT = 22d2c8ce48e09a5b7470b909f66e5b8046e709ee2563c4bad6251a5fd375a48583a6d0f8eb75cbb4
+
+Count = 256
+Adata = 80214108b16d030feff6e056c9a07a00a1d5e3ebb07abd3f4a
+Payload = fa2441cb7f9d072b8a3f1a496b2be6728a38b94a4f44c9be
+CT = ccea547aa137e5f1a5aee7e718831f50541af2948d1734e6af1dab0f105414293cb130bea285fd6a
+
+Count = 257
+Adata = 8b9fabe29718a8f297c9bf6f199c80bbc71f94eb3034a11ecb
+Payload = c8ce88ab40b62229223d46cc44f21bb39cfef27aa9fdccad
+CT = fe009d1a9e1cc0f30dacbb62375ae29142dcb9a46bae31f51cc3f7640a42460be877fb7059a3ed61
+
+Count = 258
+Adata = 8812f28a0cd5fdaa226fdd44ed857241007377057be3bea577
+Payload = cf59f75ca4d6d216cf8862b44b5192c382c140f862def117
+CT = f997e2ed7a7c30cce0199f1a38f96be15ce30b26a08d0c4fbbe0ddd2e7f4aa2024b3fec9281b6cac
+
+Count = 259
+Adata = c8f05e96d703a4850bae1421ae9ff3aec7531baf9b899dfd75
+Payload = 4eed58f381e500902ba5c56864f6249d191e14d1b1fad3dd
+CT = 78234d425f4fe24a043438c6175eddbfc73c5f0f73a92e85e5df1e5e96bb84f730fcb253d468278f
+
+[Alen = 26]
+
+Key = e19eaddd9f1574447e7e6525f7fd67e3b42807e44fbb60e75d8c3e98abc18361
+Nonce = a8c459ce0223358826fb1ec0f0
+
+Count = 260
+Adata = ef88f4393d6c1e7b7be55a12144209ee051bb779e440432721ef
+Payload = b3b0de10b7c0996662f1b064e04e528b7d85ca1166985d33
+CT = d63e6082c95c6c5ff2bc0771321a4f883ef61cff7b99e0ea8a20a1abe7c842ebc08c8c81a2743c81
+
+Count = 261
+Adata = a4c891c9dd1fcc982c35bc74cfe71651bae424602519672b466d
+Payload = 4f0b40913f07269550b7b06ab9027a4d9331f8ef98a45dca
+CT = 2a85fe03419bd3acc0fa077f6b56674ed0422e0185a5e013845e2d6de83ab729dd200a21088a1ec3
+
+Count = 262
+Adata = 4db5730cb9794f3b1facc9d6738115d02ba9f27ba02330fbb856
+Payload = 841e032773d58bc72a3237bc9b24c61b9efdd850fc2ea605
+CT = e190bdb50d497efeba7f80a94970db18dd8e0ebee12f1bdc10ed272c732247a696a608ef67510f9c
+
+Count = 263
+Adata = 471a900ee49f2cfa1d3eb37c951d810c349364d4cc3b5b64fc47
+Payload = b4db42e523e65557157b93dc0281601f7997e6731543a914
+CT = d155fc775d7aa06e853624c9d0d57d1c3ae4309d084214cd15f0df52e392c37ec15f7458469dae84
+
+Count = 264
+Adata = 7b40b3443d00a0348a060db109e8882157612c43084ac5c3e9c5
+Payload = 73e0ed35c0e847188e607cde46586eb9e237fbdc5d59163c
+CT = 166e53a7be74b2211e2dcbcb940c73baa1442d324058abe5421433dafea2b5484ba87b5050e1fb49
+
+Count = 265
+Adata = d563f5c048a1b45265182b99ca7b9004fdc73a9cb07806dd44fc
+Payload = 4f7669caaedee961dbba6bde9d09fee1a20eee55baaf98f5
+CT = 2af8d758d0421c584bf7dccb4f5de3e2e17d38bba7ae252cdf91749fe3cd52a9431d9a847a8c2a9a
+
+Count = 266
+Adata = d301a61eb17366d4e70942ab69b4f4bcf8ff6a97f5972ee5780a
+Payload = 154454fb74e9565c56775a8e4654f75a38b954dd28c4e939
+CT = 70caea690a75a365c63aed9b9400ea597bca823335c554e07563d37846f5185bb44d71be1ea6a73c
+
+Count = 267
+Adata = f74b48d168f77fbd3429728c0b168ecbd854264eaef70b74fffb
+Payload = 716b371857e68a17b20ea06651cdcfd4560a741830ca8a13
+CT = 14e5898a297a7f2e224317738399d2d71579a2f62dcb37ca55e93bc2d3f05d7016747690fb920e12
+
+Count = 268
+Adata = 3a257ce3592a8f88162f0bb4ecd5db3bb79b54ab17b0bbc61506
+Payload = cfdb7363985aa01af6f8e8237dbfb7871eb39303b4135269
+CT = aa55cdf1e6c6552366b55f36afebaa845dc045eda912efb01c46822f839f09c41b7aa6dc06035c93
+
+Count = 269
+Adata = 21916ebeca9e66b77cf55d1cac80a4c85d8b6b014f268ffa73ca
+Payload = b4b67ac551d1966caa20d951351387f384c2e5d81a76a92c
+CT = d138c4572f4d63553a6d6e44e7479af0c7b13336077714f54f8e77600c5bbc6d028fa25ba61a1719
+
+[Alen = 27]
+
+Key = 9498f02e50487cfbda1ce6459e241233bd4c4cb10281dcb51915dbc7fb6545c0
+Nonce = e3bd4bc3a60cddd26c20aa8636
+
+Count = 270
+Adata = 70cfcb828d483216b46c3cd22e2f9ee879e9e3059b566179b6e16c
+Payload = 0d16cc69caa9f19b88b05e151b3d26accd018ca4a5786a80
+CT = f1c4bedb8d6f91676881daa37656a7e6402f472735b04a0f1f8332f4236437737438e7aa1b5100c7
+
+Count = 271
+Adata = e7e5779282db80f424dc050b2c1e7754b2a5d3a8beae77beb74e34
+Payload = 148de640f3c11591a6f8c5c48632c5fb79d3b7e1cef9159c
+CT = e85f94f2b407756d46c94172eb5944b1f4fd7c625e3135138be2f6f356c2eb401468be15104e7763
+
+Count = 272
+Adata = d17e8189a94a559b07be9549f73d653172740e8e978f5b0a38ad43
+Payload = 00a23b25bca7c206edd051814d81083db1cd00048ce8ead5
+CT = fc704997fb61a2fa0de1d53720ea89773ce3cb871c20ca5a9646f2b6c2455603f1a6f20ea5a4611a
+
+Count = 273
+Adata = fda37ff136895de7ebeaf81e701e5751245201baed2e13d7e1b591
+Payload = a89409b0977f60a029dc4c1560ba6dbe7c65b068633acf74
+CT = 54467b02d0b9005cc9edc8a30dd1ecf4f14b7bebf3f2effb303fa5d8321241b1c9e18a5909d6e428
+
+Count = 274
+Adata = 9c179fd0d6277a5e073e77dd6abb4cba00ad9c9932e6c002b951c7
+Payload = e16c69861efc206e85aab1255e69d6d33c52cf058dec9d0b
+CT = 1dbe1b34593a4092659b359333025799b17c04861d24bd849e8cb01db1da077502814db1610662ce
+
+Count = 275
+Adata = cf5703228e615428d3d3805e428e754961d205c5aa0297ecdea71d
+Payload = 62036cbed3666d85624d3dc9c1f437454b9ab5c03ce0de92
+CT = 9ed11e0c94a00d79827cb97fac9fb60fc6b47e43ac28fe1d40a02a49857d7b280330b8105efac854
+
+Count = 276
+Adata = bab7e36098d59d3a31d7784d549aebfc6938bbd0612c85c0edb796
+Payload = 790ac86c5e9d8ce8cbec1dfb7e4fc4dca3d0b1039adfe585
+CT = 85d8bade195bec142bdd994d132445962efe7a800a17c50a5ecfa9dd03e2db70aa212ee7dcb573fd
+
+Count = 277
+Adata = 96f0b7cd7439721d4c9cc4f69585f8c90a95bed8fea22150efffba
+Payload = 3cfacd61ea3398de20ca6bdb00e81af482320614bdfb8642
+CT = c028bfd3adf5f822c0fbef6d6d839bbe0f1ccd972d33a6cde17a7a0cd162945a3616892e101e3e93
+
+Count = 278
+Adata = ee71e53d0b4eef82575c2bd38d7bd21b41fabe58c6f571954fe159
+Payload = d75c153e34ae1c6d1fcf5b1052190d8882041e1f9c5490e2
+CT = 2b8e678c73687c91fffedfa63f728cc20f2ad59c0c9cb06d15fadc2d79841d230cd55c04379f22b4
+
+Count = 279
+Adata = 18a4aa894861c7720ddb43809c3d2ed2af2f1bfe8f9fd4f872c14c
+Payload = 0e728056c7c64214be8f1f1727408d8cca8c42e2ac7bf67e
+CT = f2a0f2e4800022e85ebe9ba14a2b0cc647a289613cb3d6f1b229b9bae4634eea6b723f432e19ae55
+
+[Alen = 28]
+
+Key = 3ac7d5bc4698c021e49a685cd71057e09821633957d1d59c3c30cbc3f2d1dbf8
+Nonce = 54c8ff5459702aac058bb3be04
+
+Count = 280
+Adata = ecbd7091732e49c0f4bda2e63235ea43bbf8c8730f955f9c049dd1ec
+Payload = 89198d3acc39b950f0d411119c478c60b2422ffe7e26e00b
+CT = 7717b8e4447afcea1eeebf3e39ffdab2f52828e7931ef27e475acd27900478f09fec1f479ab3a7c8
+
+Count = 281
+Adata = 9a04820205234795ecd540b6a0b2fbd0b19f18106c42f374a2b98425
+Payload = c0f61950f98110db4226e269cf197c7e2794c5b87ad68cf9
+CT = 3ef82c8e71c25561ac1c4c466aa12aac60fec2a197ee9e8cf7b7ed6e8ede6ef5a73b484bf13b3424
+
+Count = 282
+Adata = 0e4dbd167da0240298f4795102ef18ff9a8772c6fd73b3374cdfa30a
+Payload = 7960dbc9136880e2eea7956c3271adfe2aba7dca53da917d
+CT = 876eee179b2bc558009d3b4397c9fb2c6dd07ad3bee28308e47d08ea0788f7ca0ecd846689c8027a
+
+Count = 283
+Adata = 2de4291068a5d290b599a73c6a8ecff4f9fd6c9cc48f14c233e18581
+Payload = 0c5d7055bbfbd2bc213cfbbafa763b71b1fde6f4de96fa59
+CT = f253458b33b89706cf0655955fce6da3f697e1ed33aee82cd081f66b1c7b70718dc50367c3da6792
+
+Count = 284
+Adata = dedeb714f555575fcedbd9de8171484090e6466dd4fba3c6b7c42eae
+Payload = b5654edcc8f09e4f80d0258c9376d7c53fb68f78d333b18b
+CT = 4b6b7b0240b3dbf56eea8ba336ce811778dc88613e0ba3fece672883438da186741e6c542b3f805d
+
+Count = 285
+Adata = 03d340904ace1cd52d4b72a96d96afd77aee68ac3936415005ed0d56
+Payload = d796f3409a7eeb896c3d4ebef46e9c6e553aab28b1cc4a90
+CT = 2998c69e123dae338207e09151d6cabc1250ac315cf458e5cf58d4a5552bc8ed1b1dda46703a256e
+
+Count = 286
+Adata = c67f9aa8cf1be3b4377c30c175d33ab2af390982c6a015d99209acdd
+Payload = e4dd279a79a381c68de777df941a4779e50a1381c8aa9122
+CT = 1ad31244f1e0c47c63ddd9f031a211aba260149825928357f95cf2b57e06de4d01bbb6c0e39f37e1
+
+Count = 287
+Adata = fef1b2ccd661b9fac85ba005addebdf8317ab104920549d3a490a21a
+Payload = bbf0c267d952aeb6f810601b9cf1962a92dcaba7273e6902
+CT = 45fef7b95111eb0c162ace343949c0f8d5b6acbeca067b777589cd12984286af98908db88920323c
+
+Count = 288
+Adata = 693fae7af84aa397f0b2baaed9b3c7953f75e7424c49b6349c2fc20f
+Payload = e8b13a263e0c4fb5645e500e88ab8074ab7d92e5a8dac6aa
+CT = 16bf0ff8b64f0a0f8a64fe212d13d6a6ec1795fc45e2d4dfee8fc441da990dd92c0caeac9d956699
+
+Count = 289
+Adata = 85e5df4ddec99f0bea14b3338b2eb190ab6584f5253c6c2ee3064637
+Payload = 067de2869333ed22c7b63ed7eeba1301bbac69b0d430adb5
+CT = f873d7581b70a898298c90f84b0245d3fcc66ea93908bfc0d502f5434bea8c3c13ad5422ff90e218
+
+[Alen = 29]
+
+Key = 948882c3667caa81c9b900996e3d591e6fcb3d08333eeb29911e9c6338710c17
+Nonce = 43b0aca2f0a9030f90559fa6d3
+
+Count = 290
+Adata = a516ca8405e5c8854e667921b5c5e1968bdd052915b55ac9984b7eefb3
+Payload = 8b9130b0c3c15366831bbb19f377e3209a8dbf7619cd09bd
+CT = 4646b2acdeb11174171da23999cd54e297daa32bbc13d30512e57c576b315f48c11877178389aaa0
+
+Count = 291
+Adata = db3121ea71294983b185207a9d8de3e484a66c0431bf07c962eb82977c
+Payload = 7f369bbc99b6f08049eeb43566269a174829d4dddb05cb9b
+CT = b2e119a084c6b292dde8ad150c9c2dd5457ec8807edb112366775e693f93af6575dccc7903538065
+
+Count = 292
+Adata = 1651cf38fd9b2da65ebb4922b97dcb861128eeefa060d6c1c94b25eb4e
+Payload = fd0900b5fa72e2fba43d611bad25de40a3507a5cc5d186c7
+CT = 30de82a9e702a0e9303b783bc79f6982ae076601600f5c7fb70d8de40c2068de96a274d3b5086b5a
+
+Count = 293
+Adata = af87b347b59e37a424004a00907dcbcf6a554e6782a9be12cb3047625e
+Payload = 36318d80c02a1da41ef1652d9a752e155526b5f597fba226
+CT = fbe60f9cdd5a5fb68af77c0df0cf99d75871a9a83225789ee7da096d2fb28f20f64a000fe93e96e2
+
+Count = 294
+Adata = 0680d5bacefa2ab14aa12b0e517a1432862d4215dc72dc4d5ac6b96c1c
+Payload = 7a29aa2994d11215ab3ef3382b3db6ed581164a235c4b1d1
+CT = b7fe283589a150073f38ea184187012f554678ff901a6b69b88748a2de31261534cdb2237565bf8a
+
+Count = 295
+Adata = 9af701f0a9de52309267289bd170fb97c03c131c0a169d736137ff3d74
+Payload = 3542fbe0f59a6d5f3abf619b7d58b199f7caff0205093f8b
+CT = f89579fce8ea2f4daeb978bb17e2065bfa9de35fa0d7e5330c003eb65ceedc98ae4e38ef341ee47d
+
+Count = 296
+Adata = dab7845fb7ead205569475753c7e26540c09d3a74312f2de25181511f8
+Payload = 83c15520d9541c86b3dd809ede42de22bbb2b75ff18a023b
+CT = 4e16d73cc4245e9427db99beb4f869e0b6e5ab025454d8835c2fb596d8ff6a863604cd224fa3be42
+
+Count = 297
+Adata = a844d6dbd05545ecc736994dc9fc2260c5ab63ed6ffdc40b915f8744a1
+Payload = 793a188fa3efa32f41d6e4c5b42353b95024117d546c79ca
+CT = b4ed9a93be9fe13dd5d0fde5de99e47b5d730d20f1b2a3722ac782e2cd8ecb06172eef2cb9b0e331
+
+Count = 298
+Adata = f9112503884615c0e8a1d8414724b0d19298988f393a27c436b2b6734c
+Payload = 6b237444fb0e1f4150701546c4cb24021c5edad30d9b31dd
+CT = a6f4f658e67e5d53c4760c66ae7193c01109c68ea845eb65f814492b42571033f4dffc0282ea2f51
+
+Count = 299
+Adata = d633a5a3defdde6a68f959ef39a91c6ea6e13ef1a7859d2c2c94d3a5b4
+Payload = 6342312e8a72f71f2e5afe04cfcde4d60a41556111752103
+CT = ae95b3329702b50dba5ce724a57753140716493cb4abfbbb75999099df2de6e436bd99f0341423f4
+
+[Alen = 30]
+
+Key = 3bf52cc5ee86b9a0190f390a5c0366a560b557000dbe5115fd9ee11630a62769
+Nonce = f9fbd02f28ecc929d369182752
+
+Count = 300
+Adata = ebf0b3e3199a5c3773c761c725c7600add5f9d8321c9f8e5e5fd1c7a5d2f
+Payload = 094b538110495e938b08cf748a6bcf3e0c80ff9c66570237
+CT = 4d8b53016fc8bc9677184c0fa15bbd3d671b9366d82ecb67f8562eadcdcbcdbad1299bea1523f5d2
+
+Count = 301
+Adata = a865b88d512e485ab3f2844c29e6dde0cf1151efa9ad3b3021d06fffb74b
+Payload = 23edddd8732cdbf03af08162f0e4a24c9222bdbb4549c663
+CT = 672ddd580cad39f5c6e00219dbd4d04ff9b9d141fb300f3359ff77cf0962455b3539dbf91f3077cc
+
+Count = 302
+Adata = 16918dbc785d94a8f1720c5ad234dde860219874c9fb076a5c290903f85b
+Payload = 1798286c37c1504fc0d7402681f6f70711ef506dcc3e29d0
+CT = 535828ec4840b24a3cc7c35daac685047a743c977247e0806dbed76d94c90595b49d50c84c3efc76
+
+Count = 303
+Adata = a2969243b0955402ab45a430fef2ef9e0c025006732bf8e592e3d3884918
+Payload = 0d02778f90a164a4f9ada9dc7fd24eeb941069621418ef32
+CT = 49c2770fef2086a105bd2aa754e23ce8ff8b0598aa61266248fbe60c146056e5cb01268403e4b9f5
+
+Count = 304
+Adata = 2de5222a0609f058f60e9e581b6e4f0ddebed84fc8302c8e985d17b89241
+Payload = b0c3858231e284af6d231f043b95772f5e7b16a34ffcd2ec
+CT = f40385024e6366aa91339c7f10a5052c35e07a59f1851bbcacff35df1ec942b43eef5aef980cb038
+
+Count = 305
+Adata = 3fc7453df038a92829dc103d44b63ad097d7cd7f9ae7996547012090c7c4
+Payload = 319f396cc02834f8e69d65f77496d0eb31ce1a7b7e324820
+CT = 755f39ecbfa9d6fd1a8de68c5fa6a2e85a557681c04b817091a93f5fc28e5f4f351cfb888da763dc
+
+Count = 306
+Adata = 18f1e92bd3c4a597ed970911d03a78ff9a6790147c9bb0ca5f23b70cce7a
+Payload = 25550c03f8fa02b3781330f96e0fdc58681b0c0bc5e83fe9
+CT = 61950c83877be0b68403b382453fae5b038060f17b91f6b92c6a90ef2e9a969ec0576fae1d126a85
+
+Count = 307
+Adata = 09ecb2406054716418ff3600c3c5cacb0845a377a2d80542abc36ec81bb1
+Payload = 210ff7975e08388b9a46eb732230e3a3856a497549b5eb49
+CT = 65cff7172189da8e66566808090091a0eef1258ff7cc221959fd6aeb047200907911621e8756b45f
+
+Count = 308
+Adata = 62d515bb0525b565a6a3613ae20343c8da7424c8368e8cad6a862b7d37a5
+Payload = 5d867265965bb2aafebb0691de9e157a24066d06fe3cbd7c
+CT = 194672e5e9da50af02ab85eaf5ae67794f9d01fc4045742cc4db6d5fd910c83fd77aefba3f7665d8
+
+Count = 309
+Adata = 00617ca141e55b045a188e4934caf6db63d4577f634db92c22010e1cbf1e
+Payload = 396b27afd16a1081f37bbc1f742b549f5f68df799b93083f
+CT = 7dab272faeebf2840f6b3f645f1b269c34f3b38325eac16fdf5f21f32cbe5d272004f1c104cbcae9
+
+[Alen = 31]
+
+Key = e45bb1730d0d539aab3805350ac986540de9f0f6c239ee70395c291397b70309
+Nonce = d5c7824af715bb7822b6b340fe
+
+Count = 310
+Adata = 860f4a09ad8b3d345c2aa18ffb803f0bc3b734a4d047a1437701a5e3d95288
+Payload = bc8b3bc48c7a88c9fafde258b6ccaa9d4f0d018703d63871
+CT = 95f083ad6bbaee6ab540fe023858f8baf25e333fd3e89c00e678a392d228b210dc5c991905dacf3f
+
+Count = 311
+Adata = 8a84b57915bdbe7bf5a1c1a426512b3c178d883251cc46c95a8bbc8ed9e56b
+Payload = 9499ea48edab9bc21b91dd614f04934ca20db8630622f481
+CT = bde252210a6bfd61542cc13bc190c16b1f5e8adbd61c50f010fbdd3b305522dae6b652322d89d9ac
+
+Count = 312
+Adata = ed8540f7ce451c522c1ff5d2d1030d7b3fbd1219a21aaa84044c4f23c08f5d
+Payload = 73843a4e9e7937fed24bb1fae15822213b1aa86c07f1b5d1
+CT = 5aff822779b9515d9df6ada06fcc700686499ad4d7cf11a08b6b08548e794eaf85ad9f5de80b1c00
+
+Count = 313
+Adata = 61bb196b212feab645f05a8aa1986f6210a384c15bc749245d840b3565fb36
+Payload = a8e24266e5981b2ed14213a29f961cbbf7f02f63a33c987e
+CT = 8199fa0f02587d8d9eff0ff811024e9c4aa31ddb73023c0fcc73643a7ee9291e15137d7046a92f3f
+
+Count = 314
+Adata = a49c2df94ba65107f375ce1c53b72406143f6bcd270945de5b7811682fe361
+Payload = 3e3c402caeca41687d12897102e04312edf7b8c7d8567a22
+CT = 1747f845490a27cb32af952b8c74113550a48a7f0868de53204438662ea82f423a69c6e4e3c0623a
+
+Count = 315
+Adata = 7c48480e9bc87ba299e03899698b2259eef150ee0f2efff40a5583b80ab484
+Payload = cfa9292b9052ac6bb863205d3c0dc2d9e20d2ba6a680d2ed
+CT = e6d291427792cac8f7de3c07b29990fe5f5e191e76be769c6ea00b9cd881e3f4b1e838dfa31f6560
+
+Count = 316
+Adata = 5cf9744090366d828b477dc890eab8ebebd44f6aeaa5b101291bf67d12867e
+Payload = e0fe4e139ab0deb4fdf2145b719f35c50b869e6cb20608b5
+CT = c985f67a7d70b817b24f0801ff0b67e2b6d5acd46238acc4c59b3b87d722a58cd1de58f3963d12b3
+
+Count = 317
+Adata = 761d74be5fae170a1bdfa16081b44c1e49972e15ce0818df1390bf7204f619
+Payload = 665fdcdf55a1231e9912562eaa5a5011d69f6948e29e3f8f
+CT = 4f2464b6b26145bdd6af4a7424ce02366bcc5bf032a09bfe158759886124f1f0ce8147c94f4e7114
+
+Count = 318
+Adata = 9815353b69d0b4effa52cefff13703fa71a6296f9cca0f02568661be4b64cb
+Payload = 7b2d52a5186d912cf6b83ace7740ceda3f5f443530c5a49f
+CT = 5256eaccffadf78fb9052694f9d49cfd820c768de0fb00ee6310a79c9932456dbc00515b264f3168
+
+Count = 319
+Adata = 69dd1a050c8d79dafbbe3403af4dc1f070b9b2b980888aa796e6cff68d9060
+Payload = 3cea5ff50167c5641066852fd00061df35b1f66bedb894b7
+CT = 1591e79ce6a7a3c75fdb99755e9433f888e2c4d33d8630c6da7e97f9984a7db3b93aefb4316d9acb
+
+[Alen = 32]
+
+Key = 2e6e34070caf1b8820ed39edfa83459abe1c15a1827f1c39f7ac316c4c27910f
+Nonce = c49ccef869bb86d21932cb443b
+
+Count = 320
+Adata = d37e35d7cdccd9824a1ae4c787819735e4af798a3beb49d4705336d6496853ad
+Payload = 771a7baa9cf83aa253349f6475d5e74dba4525307b022ba7
+CT = eebac2475004970071dfa2cfb855c4e78b1add8dcbccfc0bd6b14027324b657a56263df148665393
+
+Count = 321
+Adata = ab22bc22bf2628b0e0ab245c3db2fc5128d13a011c2cc9b9fea05a79a3410704
+Payload = dad95a4b4d3754613f0542caa62cfe4e375dfbdd369ec32e
+CT = 4379e3a681cbf9c31dee7f616bacdde40602036086501482a8c810b6944815fd2e434193520b1d5b
+
+Count = 322
+Adata = c48c5aacf701137fc40fd0d3649641aaa5be427ceee702cf7ddf6408f458a581
+Payload = 3f28df9263e473be648fabad163aa4142b633388b16d8392
+CT = a688667faf18de1c46649606dbba87be1a3ccb3501a3543e8aa447b79284c588bef50b423de97908
+
+Count = 323
+Adata = 477c2484cf5c56b813313927be8387b1024f995e98fc87f1029091c01424bdc2
+Payload = f83107b50a1f192ed45cc43fa80e6b519bfd859173ea9ee9
+CT = 6191be58c6e3b48cf6b7f994658e48fbaaa27d2cc3244945d4f4a413eb3ac2c474134995d4db9a16
+
+Count = 324
+Adata = 143bc037f1d0bd4ec16825c58cb3796bf8989200d27bda9beabbbc49247f59f7
+Payload = dfeb324ba459ec4a5c54d2534e98002412e67db19cfc66bb
+CT = 464b8ba668a541e87ebfeff88318238e23b9850c2c32b11756a3fb2e06734b28fbd57942a609d914
+
+Count = 325
+Adata = ffc416f1dae4e43c1a01339a604c44d6a0f25ab9ca3978c6aacb6d270d510ee6
+Payload = 0765949e6f22c422ebd47dc1ed73f1b849d7a058a1656fc2
+CT = 9ec52d73a3de6980c93f406a20f3d212788858e511abb86edb94280d3c4a1cd8cb00705f60ae36f2
+
+Count = 326
+Adata = 6090b596b4082ec6926576137f6561cf13916860ad1cfc43650d1b5142a12041
+Payload = 6db320cbe76bc5b8cee9ef89aca11765571c6c501993195a
+CT = f41399262b97681aec02d222612134cf664394eda95dcef612caca26cc3bbb289da3be0616b3445f
+
+Count = 327
+Adata = 178ba75adb7c5bea6769270bb3b4f6ce208d4a786913d3ced7bb4090b5f65544
+Payload = 0875020959ed969cfb38636d1d5aabce9658b00171a7614e
+CT = 91d5bbe495113b3ed9d35ec6d0da8864a70748bcc169b6e26cc8c665289d907628eb0e299c2d411e
+
+Count = 328
+Adata = 90f0474dca998916075b1b1428df14d90be05491bb8d5d88e32e65ec890ba9d3
+Payload = 4f89ca6ad371f86a6e073ec12fb1b928bb10d6639233b918
+CT = d62973871f8d55c84cec036ae2319a828a4f2ede22fd6eb4f7e481607a2a0529f9cda1d5903325b7
+
+Count = 329
+Adata = 5ad8dd40ecdce52d5b30424ca0bccb666f34f66b0c9a4c1260051ac04ca06aab
+Payload = fe2009d0a4a1711b83057b948cd0b174a3a042fd97579ab8
+CT = 6780b03d685ddcb9a1ee463f415092de92ffba4027994d140a1b9ba2bfe5bf778b859f0ff0c29a67
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VNT128.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VNT128.rsp
new file mode 100644
index 0000000000..b796541cf5
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VNT128.rsp
@@ -0,0 +1,456 @@
+# CAVS 11.0
+# "CCM-VNT" information
+# AES Keylen: 128
+# Generated on Tue Mar 15 08:09:25 2011
+
+Alen = 32
+Plen = 24
+Tlen = 16
+
+[Nlen = 7]
+
+Key = c0425ed20cd28fda67a2bcc0ab342a49
+
+Count = 0
+Nonce = 37667f334dce90
+Adata = 0b3e8d9785c74c8f41ea257d4d87495ffbbb335542b12e0d62bb177ec7a164d9
+Payload = 4f065a23eeca6b18d118e1de4d7e5ca1a7c0e556d786d407
+CT = 768fccdf4898bca099e33c3d40565497dec22dd6e33dcf4384d71be8565c21a455db45816da8158c
+
+Count = 1
+Nonce = f7a5098b2a4d92
+Adata = bc498326755503ff25d02805eb3517221b54eb4fd79af0fcdf9312b2a9ad95f7
+Payload = 3e2144e2a381b718962a77e167778bf579957a8fae29612c
+CT = 98ce91033fabaa8fe853d347be6cbe5de102fdccf042e7be697b41c9a69acaf8386140ee6e36f406
+
+Count = 2
+Nonce = 732d2dd64b4a25
+Adata = 495b03df82e317e4f351c5323d17c673f4c77856983179d7c7cb75c2b0573c72
+Payload = 4bb0d170bdcc70fd18f19605cf9c6181082c4367f1e6fbce
+CT = 9bd9304259962448fa8487bc15d950303621213afd88f1e32d442ff663242fa269c4a742a220edc5
+
+Count = 3
+Nonce = fefd3ac595428f
+Adata = 91ffb6be8e129cef9189f7e0fec8e937afcfc6083b6a79a778a724bb3e8d0794
+Payload = 9e8c4f1292e8d7e5179b34ae5d2ba2491d7754acc54bb91d
+CT = a5d012b3062cc93b831860d76539169c88854b85550c67fc564a2f1cb7d77e0223287740d5ff9003
+
+Count = 4
+Nonce = e14d81ee3b873a
+Adata = ecdc5249ceb48e8d5a4483043921c00c1acb1843fae00155a28f3a127150b1c4
+Payload = f99e23288e6b5ae85c14610994d90d5fcbcab62b4ed1333e
+CT = cc4ee711d0202deb58664e00cf0cf70b737f48ddadcefd6cd217fb611daeb66fa2d8e1bd43cb2131
+
+Count = 5
+Nonce = 2cbeaba94dbbd1
+Adata = d129674c6c91c1c89f4408139afe187026b8114893d0f172f16469b183fee97e
+Payload = 1b42cb685bd462fbd40e0273a81c767aa81cb43f17d3c0c9
+CT = 1a1b1c7130aa63098dea17ffbb2216d1d276cb10145b0762a45116736e95d823e579d73dc31dc487
+
+Count = 6
+Nonce = 8a961df9c23f6d
+Adata = 07185502bf6d275c84e3ac4f5f77c3d4b30d8e106603be84410c11849a3c18ea
+Payload = 434e182d04ecda519a6119fbaa4c45e8c9803a9a3eb51dae
+CT = 3f603939c6226d8208b2b0e675b82557609ceaeeee4032c7837ed517dbd7e6fe34ea42b01c69d370
+
+Count = 7
+Nonce = d3604d390faab3
+Adata = c95e7329d36145664da69d25f24b301d334e1bca2baa74b2d5c325ed7d04fae4
+Payload = ee104be898a225eb1da99163bbf768d8ae6d5850af6f8767
+CT = 3e6a7683d9d804f791f77d2b69996102ba82477ec4557747ef2e0b322f51abb366a1e8e37f4fe4ee
+
+Count = 8
+Nonce = db5004a1cdae8e
+Adata = 1370fc9d5bf1ad2d071be5a28b235402a85270f536b5601c221519a3b329c71a
+Payload = 59bee7d18fd4ba573f3e4f61076f5b9f6a3487e47d98c729
+CT = 6db54d6f5c3f3efa6da67aea1234d46e8b679a5c257c66d82e4ef944778281ed186b4a8099b47fff
+
+Count = 9
+Nonce = 783477f981ef05
+Adata = 04bbf2a826bdf3d55069b1936c4f8e8e08189f54066a035c950c7347604b1b65
+Payload = 6150f132b25727ebbaed9f16bd91ebce00c68e5b39bc0ef9
+CT = 36f78cef22cacaf9f3d4464821737f7fbacd79be517b4727bc5c098625c51ac7fdd15da2cc9ef4b6
+
+[Nlen = 8]
+
+Key = 0b6256bd328a4cda2510d527c0f73ed4
+
+Count = 10
+Nonce = 21fd9011d6d9484a
+Adata = 66ff35c4f86ad7755b149e14e299034763023e7384f4af8c35277d2c7e1a7de2
+Payload = 78a292662b8e05abc2d44fbefd0840795e7493028015d9f2
+CT = 5a0be834c57b59d47a4590d8d19a1206d3c06e937a9b57f74034d9fdb43c3f48932aa72177b23bf6
+
+Count = 11
+Nonce = 97f940d7c1230bd8
+Adata = 78337ddfe38be7897372b0f805603a9a9e55598452285764641c3bb7aeb54a3c
+Payload = 772aeff60eb3adf5a9589ad54dda0401cc9765589609dbd3
+CT = ef5c408dc6d0b501925a47def54d8deb9880a07a3e6380bca20a3995cf25c5a7b9477d8916adff73
+
+Count = 12
+Nonce = acfdf302ed116ac4
+Adata = fe9d9989bffae3c9e6161eb0aa9d54ee8f5051f0dcabb5a750c5478c11798ce1
+Payload = 99ffe16de323a9b65fe60305a2d062cae490ccca6d9fe9da
+CT = 1bbc2c7877d845591660636cb6ccf4edcd4c156996a26a707d0e2fe322f203c08f44d7f9bd7258c3
+
+Count = 13
+Nonce = c8d36e13b7459c47
+Adata = 3f3c3a4c26dba18f385274ac5ac3df73282686488d91bc8190b7f61071b07f62
+Payload = 316ee95430329f706348886b8ac7779e3056809e25da0a03
+CT = fd2db9611a26a3e90f4861467df60edcc595f442332b089905fdd72307c3355b19ea66d4a16ef17d
+
+Count = 14
+Nonce = 5822755a3e47c27d
+Adata = 1d72d6b371e85ca359483761704f80b3360f4d6610e6d5e490b0d509f73c3233
+Payload = af4ae8f19cf6cbd199677fe033859f56906f1979b1b5926d
+CT = d5ed6f8d5c42f4f3ea527094173b278724a2ba787e416ad759124db19ab1373a5376f46ec7095ef4
+
+Count = 15
+Nonce = 6c1c94c2e71b865b
+Adata = 298cac1e4684182786f386ef3de79c11e30b2dab7579b8ca18d0312200860403
+Payload = 6e4d992d7541e02a4aa167e56c7e47206abc25fea6c5125d
+CT = 560cd43a502a6e8b1af478a3b640a68937d1a83057110d38eaa52d69ab9790edc384b9a5d8c91dbf
+
+Count = 16
+Nonce = ce7ec65cfeda31da
+Adata = 13c1298cbf7fe6a9ab378f86d3c2207944cc2a232f9383513ceb3b202086d365
+Payload = 196c80d02b663bdd89fdaa31e329b5a8f7c596236ee8dd80
+CT = 00174dd83a7f8edc71afbe5da095160336be9184f693db3db1f45de395e021c6fb1b2991c91bd643
+
+Count = 17
+Nonce = ddb739acda6c56ec
+Adata = 7f89bbe513b9a7ebe9be3f6eb88782080593c83e8cbe47fbe15bdc3e5782090f
+Payload = e95e142217c838d1f998a52e342e4f2d80b1cfd35cf6b73d
+CT = 819d73dadaf095652cf39729b2e2cad7fc7783887a5acc15713d941b845d96a5bf65e9f80ae7f923
+
+Count = 18
+Nonce = d9bb71ad90152d5c
+Adata = 20bfcba120cdbeb07c5f4d70338ffce493822d78a03c9e80b5b934e16e39f70e
+Payload = f1fe98b50ea2f9f088f6f93910757cf744d5aabf3081966d
+CT = 36decda8ade6ab104a201c6d370412b907a559738eef59665e99761cb1ac77d772b9cce9345d9a75
+
+Count = 19
+Nonce = 2c9ec9f1f1358c50
+Adata = 96f0b1edec4ad14407dcaf30ed68942b46c48d58b2dd63af60fccd5bdd48e560
+Payload = d74badb8ad7f2c2bcdf67e497151d35a4fc2a3c4c871868a
+CT = 0e9066270da6e03cb4307c43adc71b4b596213a63fc8032085ce60506ac3bd97327904ad2e072a6a
+
+[Nlen = 9]
+
+Key = afdccc84f257cb768b7ad735edbd1990
+
+Count = 20
+Nonce = b7776aa998f4d1189b
+Adata = 9f9ac464de508b98e789243fdb32db458538f8a291ed93ddf8aeaacfbfc371aa
+Payload = 56d0942490e546798f30d3c60ad4e3e110fc04f5b1c1fa83
+CT = 96f124c74fd737819008ddef440320f4a3733d0062c83c893e259aecf12ba08f2a2e966a3341d6d4
+
+Count = 21
+Nonce = 278cf1f09b13f467fe
+Adata = af9627922758a9f7792345716782e8837ca78e8f9db16e3fe12a7124a3d4e99d
+Payload = aa9b9e80cef47b6db3816b1d665f233e696337e21bb8333a
+CT = 5eba7e3b3ecab78121b0d56acb9dbfc6756c1255b42f145d11751638ed36c1fd3c7268b71633c1cf
+
+Count = 22
+Nonce = 4ae701103c63deca5b
+Adata = 5872a1507c833c581ac2750b2b54add4b92be14e45d72db7679f8fa2b4d1eeeb
+Payload = e832b053854fbd40c0d8b6d6b8fd5de2da0c173f5fe594ef
+CT = 3b2b964c3a90d51c0ace186db79818b4d0f7b81236d36017d3635aa1d8167087600b01643b0a5ce5
+
+Count = 23
+Nonce = cfb5b12928e1c36849
+Adata = febe755bb8e4475d8d12f5e96269abd0d4e40d73cb966e2c523343e9a6d2d71a
+Payload = f46d6970dcc37d32d93ff062e68034c1906ee487fd28eefa
+CT = 0d5332a42fc583f4f81744b899cdf2a64cad1e78d577112fee6f8c4b252e10b42fbaf8c7af1e9f3e
+
+Count = 24
+Nonce = 68d5863cafc69e6ceb
+Adata = 048ba28abb191ded5449dfe9dc7d19f9b132a2a9fd779aab7da44d2887485954
+Payload = dd4438d7ba3edc73872e42dbbf78cf300fe4bf0eac9e16b6
+CT = 874d3ef7f916db2c2799b6892ef4bfbeb4729ecbf26ac4983a8639f21f8548fae45dc76de57bcee0
+
+Count = 25
+Nonce = ea09fbe5da0fa4fe91
+Adata = 63ee18eb720b21ee4c157dafcb8c7bcc6817f54d5c1b8dd7058c37228a03f8ad
+Payload = c1811d613bf0789beeef693611ef733cd173da703b66ab3c
+CT = cbe5c799952b28fadf414607a6cf8194e9f41194abace4541d3853a52971b0ab46cc0a3eded435c1
+
+Count = 26
+Nonce = 0021be18ed76b3a34c
+Adata = bb5eded483f0ae1106fd08c5e2b91cf06d3a7a73518ad4c479fb05e631ba5399
+Payload = 2d5531d1c51c6ea100b028596bf9f24dd90be14eab58f07b
+CT = 7af0449f7359b7f3e5f6c1e7bc264c7724037f4f16077fd0a2a8e3cfb827c7e6edabb34f7bbafd01
+
+Count = 27
+Nonce = 449b51ee0760179e35
+Adata = e99bdf783070a3a48431704e90277ca65a9704c12eeae2e2d70b62f816115267
+Payload = c4896d58442877c986e4f862a9f3a3179f0e9b96316a90d8
+CT = af7531c073df01077fd5c8ea9a5530c2fe1688d529e5c2f24aa8feae6a500919a336dbba1d9fb7e9
+
+Count = 28
+Nonce = 232114642e0c6b55b5
+Adata = da288d2014616f16a2abf5923dea49aded1748592adbcd97415c33ebfa57150d
+Payload = 11fd3f94b5a5ce94f2740a27a0771aeeac77f3155d2bc12c
+CT = f0c174a7927da0bb88e92917af8ae1df4ffc3527004e9e2d0b25cea7ed6e4fe9069a2ce49875230d
+
+Count = 29
+Nonce = 660cb6d654afcbdab4
+Adata = bd96c3c225099fc58cc1f97779304606b11efe9712fba13abf74fc1d7d44a900
+Payload = 793c0bc3deb6e0bec4c1d1fc17e455eb1aa5e9e25cada861
+CT = fa4b14a381ee41fec7b7279e58f0d06a3beec26d645f81336218635754d5563f2cd48bdbb267e5ca
+
+[Nlen = 10]
+
+Key = 6ccb68d3838d4ddf660b9cd904cad40f
+
+Count = 30
+Nonce = c4fb7519a19f13d9d1fc
+Adata = 092e64fef08b5655a86cdb8de63ffaa7772e8730844e9016141af8bad2216246
+Payload = 5ea35c082e2b190e9d98e6b2daad8672f587b4f2968072fc
+CT = cda5fe3d15d00150b99120c7f206b88a4c2c4a39ca9143425603ab284a73a38cc916f8b653c92ab4
+
+Count = 31
+Nonce = 45927852550961f1ae9e
+Adata = 53ae030474795ffda4d9ac0fc3c45afb592ddd761f7b5335c13a6747e21075a7
+Payload = 6c5f468077536b4c9a94ea4a6fe3cf621083a210daee45b6
+CT = 694847b6429cbc3902d9cb7049625aef1e97b569e1e3169035bb811491d142cf1b26350f8451bd14
+
+Count = 32
+Nonce = d8c54463dfcf02d0e327
+Adata = ff95c0ed0da32d1b5f57570b815a50592ecdc9c1c4e727e0f6dfd93fc10ce88d
+Payload = 7321a6de8d694ea05623206f5df438c5c2cdd6b1eccab4d8
+CT = 9cf8ef119aa5cf3d6305d50b2b520a0b10bcd240e27276749c68e8e641b0120f7dd66e8f0cfa4205
+
+Count = 33
+Nonce = f690f3a996928275050b
+Adata = 41c05fda535770699ed22cef253753b658437f833afe65c9c393581d835f0fea
+Payload = 56520a4bfd7b73a471e0446f9524a407e81c2681b7329e35
+CT = 14aa15f9f64c4c64f6e88094e012ecb24193249f044c033dda44a62f97c0fead3f65b28928bfbcc3
+
+Count = 34
+Nonce = 26eb9ef25be62148fa61
+Adata = 8f45608a07521de86ed5a84a851e629b579b51d7bf4cc7202a773e0f9e9d8748
+Payload = c68094c26c7f017b79f126dc26b3bbcb95f97535ca412da5
+CT = 7ba8a0c2fe2b230768d1c1874085ddff8926931961bc4558f0d5444466bcc631bef8e58fe5818af7
+
+Count = 35
+Nonce = fad21bc27dabafe7a4ae
+Adata = dc5d7fd97bb3243ba585fa0d71a07191667af418e30a6b76bedd05b32c673403
+Payload = c247fa8d8091cd3f299cdacba7fb7af93549e9e3160f9cf8
+CT = 3097d2ec0f8bf00b22504ab03a75e740d3e59c269c3ee3f00b5419293a67eb008aef0f9f675201df
+
+Count = 36
+Nonce = c911348848fe67406dea
+Adata = 50d50a0b5ed4d6904ec3045263af0255a6494b7a7e2e95ea806c4bb788423dc1
+Payload = d846c170ae0111348362901503b26d58f5efc17b6d296aba
+CT = 5d72562f7dfb47bf34b90ee4ea11ff9f726c915b07f4d843dec5a554f4bbecbf6943ffdab8d8a26a
+
+Count = 37
+Nonce = bb921b46a16d20ae4046
+Adata = 7d17f8f60ad1e61a168b5b0e7fbbc90cee79b612b6d6c0d7ff6ede042341e8a1
+Payload = 71bb6ae84262646c9be95e0f4289ffeab7555ec6746c6ae9
+CT = bac123320888b553666249756e6d63b3498760791cbe9e34e5b1162b7489a59a50c0f0f3618e6c2e
+
+Count = 38
+Nonce = 61a8b8cbfc9bdbadb2a3
+Adata = 51cf2a8949e13eaa087a34c9ec4d7fd92b862efd6a0b1fef8b016fa2c6933426
+Payload = 362f9a46aab59fb6213c83d791b2129b34367ac2de2048fb
+CT = b8a57e8714d8789f4ef2af29e0efec21b1ef67fdabc7cdf0ed5505f1f0ff77723771338585c456b7
+
+Count = 39
+Nonce = 6bc4cd23c32a913998a7
+Adata = 92fbc970b5e64198ce2a138de92767edff8d82f12f8832444b346d159657356b
+Payload = fa442383da234cf8f0c5fb667218bc3bea0c091b3a8e6b77
+CT = cdfe3e83aba43a9804c5a1832e0e47a9a153359cc32db907714025f485c7f40256049f16f859b859
+
+[Nlen = 11]
+
+Key = e6ab9e70a4fb51b01c2e262233e64c0d
+
+Count = 40
+Nonce = 74e689eb5af9441dd690a6
+Adata = 42f6518ee0fbe42f28e13b4bb2eb60517b37c9744394d9143393a879c3e107c7
+Payload = ba15916733550d7aa82b2f6b117cd3f54c83ddc16cd0288a
+CT = dcc151443288f35d39ed8fae6f0ce1d1eb656f4f7fd65c0b16f322ce85d7c54e71ac560fd4da9651
+
+Count = 41
+Nonce = eb118fb41284bfcb1bc338
+Adata = b5a6067fbac46578cfc8d3fe04108588c9de077eb009249374f205553bba9d02
+Payload = 863da00c7accf45418d47c1eda72338734dcc49cd599f328
+CT = d64de7a56146b971e21bf5784d67bab32dd837cfb81591da4a0177883346dc896eb39e8a32bc1393
+
+Count = 42
+Nonce = caba2716d07e95de83855e
+Adata = 0e0ff2c73ea5fa8f8726a3514cf906ce1610a1a6dc19b22682f9e4619f762d82
+Payload = 2af6d5636ab65db2058b2ba16df257369fc4e8aef8b9481c
+CT = 3c9e006c7d8eff5f448b0cc9c27c964713241aa7fed3665d775ea25fb272981de8b8aa0a637498fb
+
+Count = 43
+Nonce = 314c136999e41d137bd7ba
+Adata = 366c659bc45d0a88acd54ef7eeaa3e140e1cafb1b01474a065a9d460c5e83bfd
+Payload = 217b19ea6a431a1f66bd9d02b718e8507a08ab8e6f603e3f
+CT = 33d7b672b23e8b03a39ff3fd1e7b0f2be67163e3e3bae072f2aaa211dec623947a50b1252bc5aad3
+
+Count = 44
+Nonce = 6fe51f5013f53d4e4fd907
+Adata = ff182f2e179d790e827cbfd0bd8b9297ecae57ffcef9e25ef114474a22e4ec5b
+Payload = c6bf582b49dd4ab6cb33f3f88e8a4d14fe32b308ee3b4682
+CT = 26cd5dc5eac2acda283ca03354260ad57af79e20c5e92f5775ed171bb0fbaa6f431c5411cf9b536d
+
+Count = 45
+Nonce = 24bc8dc1e2354667b79ba4
+Adata = d0d48d01fc79685c6bee04d45e40d06cdf1f4607542b1ece556fc2d1bb2b03f1
+Payload = 90f52ebb1bd5439386faeaa194623285f750672a7baae64b
+CT = a7f43f56c50705a1a101044b954414fdfbe32b518e934d38f391749ea3acd624c01e4583ab1506b7
+
+Count = 46
+Nonce = 89ce46b3de3afaf2518d41
+Adata = 5767202c913584d653f37d926a0c5ac1c67db3efd1dc58fbff998778a6856254
+Payload = b2ab379a0dd15baf91415eee3a4e56e7eca54d4c1c3094f8
+CT = 9f530e455a54b86835eacd8801b34c884a3b2ac819ba38f894e43a6b1cf73cb2d6a1dd8331549520
+
+Count = 47
+Nonce = d3208eb695e84c7a925037
+Adata = 91d8fa65a6885f162a795afe2898f391990a8b3a87c11f94734dcbddf5f58da8
+Payload = f15e39f0e4eaa5bf81359d8e30186522f1a1a415436668cf
+CT = 7f1d9fcd9e5cce3a81e3495bfecec817fd7180d8bbfe0abab27fb6425fcc3537ce471425a5b17dcf
+
+Count = 48
+Nonce = 067de2869333ed22c7b63e
+Adata = c31e441fd551b3fdfbe23ceec5ec1f838f31a5300f6055ad2a936a9d0c1c856e
+Payload = 1536d9c9a09302d142c85638202f5bbf0c287f68115d51d8
+CT = b1a5c7a7fd23228dc7ea26885802daa0719f6a23681e1d65dfb879c21b46f3307ef22f1da579303f
+
+Count = 49
+Nonce = 15f61b4526d19bceae1093
+Adata = b97b122af73e928e617e98684f845be4cb80566345739b7a884c6a3eec5102bf
+Payload = 37c81988c07a5b01e2b40ff9f9ada5f50ca764efb717ff9e
+CT = 0d93a5c77482d573b7f1b8c5e283f2571efc9f54216a4c01900504a73c8817ff2b55618b2602bf38
+
+[Nlen = 12]
+
+Key = 005e8f4d8e0cbf4e1ceeb5d87a275848
+
+Count = 50
+Nonce = 0ec3ac452b547b9062aac8fa
+Adata = 2f1821aa57e5278ffd33c17d46615b77363149dbc98470413f6543a6b749f2ca
+Payload = b6f345204526439daf84998f380dcfb4b4167c959c04ff65
+CT = 9575e16f35da3c88a19c26a7b762044f4d7bbbafeff05d754829e2a7752fa3a14890972884b511d8
+
+Count = 51
+Nonce = 472711261a9262bef077c0b7
+Adata = 17c87889a2652636bcf712d111c86b9d68d64d18d531928030a5ec97c59931a4
+Payload = 9d63df773b3799e361c5328d44bbb12f4154747ecf7cc667
+CT = 53323b82d7a754d82cebf0d4bc930ef06d11e162c5c027c4715a641834bbb75bb6572ca5a45c3183
+
+Count = 52
+Nonce = 6a7b80b6738ff0a23ad58fb2
+Adata = 26c12e5cdfe225a5be56d7a8aaf9fd4eb327d2f29c2ebc7396022f884f33ce54
+Payload = ba1978d58492c7f827cafef87d00f1a137f3f05a2dedb14d
+CT = aa1d9eacabdcdd0f54681653ac44042a3dd47e338d15604e86a0e926daf21d17b359253d0d5d5d00
+
+Count = 53
+Nonce = d8e133e7ff8e0a0ec6c4096e
+Adata = ef9e432c15d8c93a4b5c0666608e61c824cd466d7940d642acd3dc33057c0395
+Payload = 2836de99c0f641cd55e89f5af76638947b8227377ef88bfb
+CT = 5edb056d85dafeaaf74bdf4caa47339d6a75bf1ee998565e9f9cdf6ab825f6e026f5be2ad895033e
+
+Count = 54
+Nonce = 2fa8120398d1a946f391367c
+Adata = 377cd407ad28dc02bd3835a31d92f8295c9dbe597f56662ceda112c588dc73a5
+Payload = 7a37255b682766a0bfecf78e5162528885a339174c2a4932
+CT = 701f5f506fc7e9ea4a27a4db5cb890f7be3b4f6bcb20f97ed3021f6ad620648b8196ab1693710398
+
+Count = 55
+Nonce = 8d638ef43f56dece910139e9
+Adata = 87ea7b095388de70ac0ed23e86f502400910028a8ab5e3bbb91d05821c0d2d61
+Payload = 7370d9b453936955b9c9d336f4b283237986232de007bf41
+CT = be2f03f6ce1731418a5f53b6f6e467b73992a0c8102d8ffc2d236162688096d80b8733d2afbcd244
+
+Count = 56
+Nonce = f479ea8812b6b2f6ac78fe9d
+Adata = 20c2b8f5d3a65a66ba8a25e2ee339a779a32d45f5db91077efae6cf308feef50
+Payload = 59ff9f7581a781808d36fed378080963f35c00ea5a6e3932
+CT = d127c956349c16e2186f55b72254c677f03c61f1c4ada9e661bb9415b32d6a58f5f7647ed41de685
+
+Count = 57
+Nonce = 423515f7bd592d6a7a240866
+Adata = 19eef6f798fc68086aad1cda6d7976cdcfe6b8af74598032972c939db300d8c1
+Payload = 3c379f90b11c622a765756a15efc8fc3ca7b08b3281945f5
+CT = 15792e01fc17f5294c3405484291082c00a8f46dd9af8ca230ba95c4058501234a1b97543c998e9d
+
+Count = 58
+Nonce = c3f3da69e13c5733039744b1
+Adata = eedf00aab5edefdd6549d37ed44358e11c588c24f141dc5731303fe0bd56b11e
+Payload = 9db6fe9adb8c0fee87cac9a7f01a7ed8a84f0512d09b1834
+CT = 9b6b829ca1dc4e90d4402188632ea3377cbec2ba60f0f072afca1b08b6dd589a17a32d49b6f7135b
+
+Count = 59
+Nonce = 0a57d59f21ead5b6d80cd2ce
+Adata = de5f2d413c98c6ea2a5640a7b1c424aebe75cbc78b06710b5bff8bec6afb5a76
+Payload = 0b5f6389f7c20f4ba326e8f05d373ca27b7ebe59e6d729f0
+CT = 0b704e14bc7d2977d89e0b2e7ed7fe3c9e0f2ea80d2d6165f344f2f1b2218d9b4283fe640a6d315b
+
+[Nlen = 13]
+
+Key = ac87fef3b76e725d66d905625a387e82
+
+Count = 60
+Nonce = 61bf06b9fa5a450d094f3ddcb5
+Adata = 0245484bcd987787fe97fda6c8ffb6e7058d7b8f7064f27514afaac4048767fd
+Payload = 959403e0771c21a416bd03f3898390e90d0a0899f69f9552
+CT = cabf8aa613d5357aa3e70173d43f1f202b628a61d18e8b572eb66bb8213a515aa61e5f0945cd57f4
+
+Count = 61
+Nonce = 2a27257bfaadf23a87df082c57
+Adata = 0001dc666c9daf3560daeaf514270db0b5075d295068e6caf231c1de0e1a9300
+Payload = 6cbbfa6d736fbcc4cf73ab4d7be537420e0e574ee1f2d1b5
+CT = 72d525e6bb312bf2c20b91f41108779789c25720797ebffa4cd9d735f51430275387c565cf1a69bc
+
+Count = 62
+Nonce = b94ac8ed14895c80a91fda8367
+Adata = e1eaf35fb266f243a3fa407cd41815ae6432ad79877bfa59d8f196cbf19bfbb2
+Payload = e6ec561496ce18d96b26d594a47ffad02d68ef25d2d2edb9
+CT = c63500445239bbdf71a8dfe3f8c01061d659cfeb038b825dc89fb5f507f5aeefaa9365f0b18dcb3c
+
+Count = 63
+Nonce = bbae10aa491ac9c668a3ba8d7a
+Adata = 981fc31e64fbad244ba1ef0303ba1e4beef5bacca74f60ffdb9142a25a1ad5a3
+Payload = b9bec3e2adc83620772048d6cbfb6f78e4fad74d754ffbbb
+CT = 9c629c375f014e162895cfc25a972c29839f97407e7c7cca83d0a61d453d596fbc5c2e315d9780bf
+
+Count = 64
+Nonce = e0b10e78e9fb41ee970143e9e3
+Adata = 399b71ecb41f4590abda79045cdf6495f27daaa559c1b34f513b5c4ac105ec10
+Payload = 4b81804d777a59b6a107cf3c99c9d1a35bd8e4ed36596789
+CT = 867799b30558697d6efb4afcfe458cfad8da21139a0b43128e8f8e13b7896b244d0c9aa52ed31a95
+
+Count = 65
+Nonce = 17b61109f5e37754e4e92a28d7
+Adata = 0bc2fdd890c19882640f8d4188b88b9db99cc1934cc3e98a5df08589287968a6
+Payload = 347c1eb4aff917bc0012f005e74caadc93f4f18f2b614ece
+CT = ee19f3120991b67b2389e6f36543d99590f2e6d785c9c8ecc40eb85585cc3b7520a940a4e993327d
+
+Count = 66
+Nonce = db3ca9e80ab761804349379961
+Adata = ce01369d08d37dcda2c899c9fc0d11ccf94a0051b2816a1d6c3ad07fc8dd02d7
+Payload = f0e1af1276d2918be91a191814660bfe735463d3983de1ed
+CT = 0f1b1228729b181772d7cf55ad257fbcb19cd46f7b31a885401358c7b44aea27617b429583103a1a
+
+Count = 67
+Nonce = 1f57959cecbd377374477e33b3
+Adata = de1c7c83ac61e1f99ae99b198f4af5d24f8de60ea98fe637f3a801fab38b2a4b
+Payload = 42a42b84df098ceb43519c4cb86c14c2fafca39346159e13
+CT = 12425453de653d0fe8103013fde1ebf4a8fe18f76f0c9d60e93525fe8048c3b2147a149f12eaecd3
+
+Count = 68
+Nonce = c9db03e2efbab713b0b6404210
+Adata = a2969243b0955402ab45a430fef2ef9e0c025006732bf8e592e3d3884918696a
+Payload = d633a5a3defdde6a68f959ef39a91c6ea6e13ef1a7859d2c
+CT = 5cdc183c32b4c1878eb83e8473a17c55c88e2ad6b944ab1f64ddee42614aa737231207636c114575
+
+Count = 69
+Nonce = 89ed296a3ac03fbfb71422b921
+Adata = 1ffbe1aff0a1e7fa3e68be31a74612a1519b59397e7007ef61fc015f316d55b5
+Payload = bff42516e30c92ed46710013c656600406a48a84c1fa32ce
+CT = e08c1ab4ae7edb5184c30ffb3e74689ea855f50b0e890392f26b130720f75c422fdf66fb174383b5
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VNT192.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VNT192.rsp
new file mode 100644
index 0000000000..06e9ff5655
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VNT192.rsp
@@ -0,0 +1,456 @@
+# CAVS 11.0
+# "CCM-VNT" information
+# AES Keylen: 192
+# Generated on Tue Mar 15 08:09:25 2011
+
+Alen = 32
+Plen = 24
+Tlen = 16
+
+[Nlen = 7]
+
+Key = ceb009aea4454451feadf0e6b36f45555dd04723baa448e8
+
+Count = 0
+Nonce = 764043c49460b7
+Adata = 6e80dd7f1badf3a1c9ab25c75f10bde78c23fa0eb8f9aaa53adefbf4cbf78fe4
+Payload = c8d275f919e17d7fe69c2a1f58939dfe4d403791b5df1310
+CT = 8a0f3d8229e48e7487fd95a28ad392c80b3681d4fbc7bbfd2dd6ef1c45d4ccb723dc074414db506d
+
+Count = 1
+Nonce = 026a0b8b17be95
+Adata = 44caa8ecfaf38e5e773cb0366e1b04aa0b9fac5c34a362310f471960c4a1e1c9
+Payload = 0e52a384cedcdf7f179348de6e7336aa86f8855fbd903cfa
+CT = 3417044bad5fddd9455579123dda4fd342c273a57ff6333dfedf191496d88cbe17c6271b65096e66
+
+Count = 2
+Nonce = ea09fbe5da0fa4
+Adata = 1d9799f2bb0f7ab57fe3de27949ff64066131c81bfee172b308f9bb0b3171067
+Payload = 469ff9698cfc96b581d7115c822e4363d7355ec5daed2eae
+CT = 1dae7cc16f1b469290902cfad47b959784b4d6f48a79e690d47e30b635d10d1663477d61d7ffb55d
+
+Count = 3
+Nonce = 8d27bcbf9ebfd3
+Adata = a7070b85b7add9193c9dcd2e6c03f6e7ecc52ffe9e099866baf7472f20c03aab
+Payload = 225651d072dc9d93762dd79691ac2b6ddba00ec1252d69eb
+CT = 5da819adefbf794612eb458519debcd524c283763eb3d7252eca8766bdf0db6bb2dcc793e1749c21
+
+Count = 4
+Nonce = 13f560187b6077
+Adata = c4ab4244db75f8256e55c5b613a07b11c963c3cc24f66128aad4ba8b7ca99331
+Payload = a38231af405dc7b70c8dbc8cb84e6be8a0dc2e95fddc2ce8
+CT = 3aedcf8347aa23fd3325ce08b6b00462536baed69968a753feab6761c55431bb5668e1f5b7505e89
+
+Count = 5
+Nonce = 61e0e28bf344a9
+Adata = 5f998952de70449ad46428f2ff8a01c5af43c0107a1bcc6930f19d4112598666
+Payload = db21b37e875d7709a02239ce6ea529cf37255d5b617c153d
+CT = b8f5fed39c723d7643d6dcf2efd3bbd1ba0da1ec901305fd64b2302ace4f66216ca8b4d776197692
+
+Count = 6
+Nonce = f6be4aad63d33a
+Adata = 18339be863fb8a887d04ae9ff3b4a7db095075cd5d113a9ec87b41fe85ea405e
+Payload = e53101e6eabcda32c13d7b1dd1d88e7c2ca3ddc2064f64c6
+CT = b758858ab60e1630a0883d4d330119a593729a3015c42525effb985b9c2dd9ec954bd25d9c464c67
+
+Count = 7
+Nonce = 2c1c59aa0d8eff
+Adata = d44af86b89fda8448a9b2fcae20ea156dd8738c8251699c02b785811c830bf72
+Payload = 1fd7188a43dee7b059420e8634d71d2c0658f6d0d308dc73
+CT = d046f845a67800a5a58f461e5a8641e8fc9b4c53b32e61d172adafffbacb297d67f6b5c02b982e04
+
+Count = 8
+Nonce = 48e4598edd191e
+Adata = 61588bdc980ea2310e87dec4c651e9a55c27e3858b6505cbf3bf85e51931badc
+Payload = c25868f390af5e59c035cb5830e018c62c5b96bd35b764f1
+CT = 0ece161bd77b7f969b3b20c818769a98c178d84524544664500ff4cfe66ade1832babc019778acc3
+
+Count = 9
+Nonce = 6d576ce3c5fcb5
+Adata = 92c598cb5ca2926c11f67c3b3cf25493d77606fa60d7290430e0e975091644a6
+Payload = bcd97479db934357a163a9e5f5a85999ca987f8243d8017b
+CT = bee185e11b3d42bac846b9d92c70a078aebfa630ab763840391031b3a22b2adeb9791ee35765c8cc
+
+[Nlen = 8]
+
+Key = 1dd56442fa09a42890b1b4274b950770ea8beea2e048193d
+
+Count = 10
+Nonce = ad749d596d88a4b4
+Adata = c67219909828adef64422286008e1e306867a1c0b3da95444507a68b45c953e4
+Payload = bd92d6744cde446fc8621625658fc4bc00dcb97f06195ad7
+CT = 076cffd0ca978fe2bad411ced45a090abafb22a99896f6a75a1969276aa2b0cdb37ccaf2845dbf6e
+
+Count = 11
+Nonce = b1dc81d116d94f5e
+Adata = aa4b71906b6642f10f66c2391ec157c7cde97eb322db10045af4c5248807f691
+Payload = 9aa6dbe1cd3eb98d330c937d31ef93bee8938b6c5cfd38de
+CT = 720f6876ac91665f20147483f0655fdbe21963a01e36f1daa67e36d7cc8d54cfec0762514475127b
+
+Count = 12
+Nonce = e758738df5c89af3
+Adata = 5715fa238f432c926e62dd93708d0e3145428e0ed45e1efa8148d2c4ab6cba50
+Payload = ce80b99039a16e69018d1e3c239dd1bf06e94a78b0b1df37
+CT = acdf7ba3edca1563727ed85cabf085c2f0c8f27556c3c064ef50d85bc3ade6a773d956b2660ac367
+
+Count = 13
+Nonce = d586c4c67d535476
+Adata = 1e8dc63c6c54a540b6b02067ba7c719221cf289fa3897299722c9a2bd6eed05b
+Payload = 2f88305117f9a5d807d54b7e95ecfeb7327e52d9acac352f
+CT = e42b86e619be1a38973c934babeb4688243a9012c85d643d81e024aaf0a62b353f9bed36681288d2
+
+Count = 14
+Nonce = 77e83758f68d272b
+Adata = 25c80edef3d5bd8b049fa731215b80ca2ee9ee6fb051326e8c6d0b9e11e3d7ef
+Payload = 92e47b82b728d639777d5d5843de2a5c364956cb4b21cabd
+CT = 1b9177f5b76403cb8c690b39c3dd22b55da35cebccb9b64e05fe32f796f0b4a75a459fce6c7d740c
+
+Count = 15
+Nonce = 311dc245549206cd
+Adata = 87767f13bb4904d0df0d64eb22c9ddb65e81b5739baad86ad5e2c239ffde9f6c
+Payload = 8691c0301a216a5f3ed9123886d100309bd85630d6b845f5
+CT = f39fe3620a03b37a4bf457909e0770447b498ad2a2f0f9d7b75f9e4239e43bbf93066897e60f6fbe
+
+Count = 16
+Nonce = 2a17b70f10e120c0
+Adata = 981fc31e64fbad244ba1ef0303ba1e4beef5bacca74f60ffdb9142a25a1ad5a3
+Payload = b9bec3e2adc83620772048d6cbfb6f78e4fad74d754ffbbb
+CT = 92187955ee1ae702ef01a385537119b2bd4545402e8b2384a0c069a2439a2d8843302c6a9999e658
+
+Count = 17
+Nonce = e0b10e78e9fb41ee
+Adata = 9d072b8a3f1a496b2be6728a38b94a4f44c9be40c8793b69afd81d01696a6b4a
+Payload = cea28e7cd0eff0c5eafeec908d4aa8ba303e72ada33db087
+CT = c605e48f2e66e8e0a92471e466981ae5e31db3e4ad80b09f5005b06d15f63f2f015cfe447828da09
+
+Count = 18
+Nonce = 02d72dde23f9772c
+Adata = 2dc44c39940e2d9c94d2dbe40bbf5cca5efb4d4b250a31aa24f208b87e9c2453
+Payload = 809343e986f6ff47f54d4cac22ed39babd12271d4c7edb58
+CT = 0bb59581f22f6b15de76c0066645495a5c19e44381c349263ed92ebb789c314a89c83542b15ed694
+
+Count = 19
+Nonce = 28c4d6de3e2ce51b
+Adata = 913a8eda924589d3206ce0a951fef93668c6c0c454824b217997bff6b3026d54
+Payload = a19f65ffdafd6ad5ee43570f7e168f94a8b4a7b7402ac80b
+CT = f0c91a29f1222b906550ef5c7c0944c5c4236cb6c31122cfada8e796f2ce7f9449f42de504873868
+
+[Nlen = 9]
+
+Key = 8cc622645065c72d0d2aca75802cf1bbbd81096721627c08
+
+Count = 20
+Nonce = cd84acbe9abb6a990a
+Adata = 447b6f36acdad2d1cfd6e9a92f4055ad90142e61f4a19927caea9dbe634d3208
+Payload = 597b3614ff9cd567afd1aad4e5f52cc3fa4ca32b9b213c55
+CT = 2d7fb83e6621eed9073e0386d032c6941bef37b2cf36a4c6c5e36222d17c6fb0631c3f560a3ce4a4
+
+Count = 21
+Nonce = 1fc7a43ed124745d04
+Adata = c892b095173076a40e24522297be27fd3a765c8d417f24c71a9f03b3fe3d8e20
+Payload = 415cd8312dd20a1c26f4b90d98104cdfbe06739466fc0aa5
+CT = 7bebd6f55f15ae57ab73f92f7be6ff37ddd99740e988f01a7a2a13c22df4a156e6d6063235452c85
+
+Count = 22
+Nonce = 19ff5e7c1f2c594abc
+Adata = effcea4e4dbc57410426b39fcf51c9daecd9d310888590d77827973a29c4ebff
+Payload = 97fd2c259a4e672e9555a9a5b98f4c0ec8c4c49c7ade26a4
+CT = a460674c2f358762e97dfc958d90973e1e419dbc6a832e987579b2c4a6bcf0356f48cf8959cfa54a
+
+Count = 23
+Nonce = 64d9bd368ac2357cf2
+Adata = 62c5a16f946b4312517f67c80afe2614c822e3a01b87dc81538c00bbf3fc0108
+Payload = b6ada12f7a28211e9d2c07cbb3d39fa77aadc077b34c46f9
+CT = 8fb5e0954388b9b58519482962487e9b0768f0cee08afe9a92be2b06a0ecd2d00877abded7d9634c
+
+Count = 24
+Nonce = b4aaf2cd93efc0ce93
+Adata = 79d8841ab83279724ce35e1a8abd4e158168dcf388ab4c3d1ae70413e4e43d14
+Payload = dd42449da4c95e858b796085b6b5b3b5eef484dbf3c2bc8b
+CT = 893f86e29972928c1f3c3e25c73947c8d677814bca7fff2cf8d301ceace678f9bf91fc361dff5812
+
+Count = 25
+Nonce = 132f3e19e12f462a74
+Adata = 176cc5a280f6171d00e247edacc81f05c1b9faa87fc831163ac9d76aae59a6c3
+Payload = 8ea05a5033ab8b009664fa2800c24e217488ce6888cad147
+CT = 4771d210ea678dbfab96e320e9c44b68f47cb05b01826ccf42ca4f4ccf986eb6a6b85b99db2fcd93
+
+Count = 26
+Nonce = de709ba64cb75704c0
+Adata = 0cf8e9ab95766b6fa85e88d86e4f349a17c0d90509939e343eede988e7462255
+Payload = 51dd9fda9549f25dd868245a6a54b8d59346d2f336adf9af
+CT = fccc3e44afa6bd2fbcfc5c834db63dc9d152c04c0dc0b43d393162252ae91ca46fb8e8338cbeb75d
+
+Count = 27
+Nonce = b11b4c1b7a26387265
+Adata = 14ed867cc909c0619f366918a7d5ae25279fb137e1dee7fd98ddbe3bd19d841d
+Payload = e35ea4a16e274fcab457fd4dc7886c3d81fc668c19e0f374
+CT = dcca8aa2eab8ac3f5db9cd9560ae0758d7df40d7d868d1f71f498ea6ec8251a6d149c7ca38b25fe4
+
+Count = 28
+Nonce = 20d03227a7fcaef1ce
+Adata = c5c15245e641687d0ca9e913406acd2de3f21fbaf2dc5e4e8963222da61d02a6
+Payload = 6775e5faffd0b13e78da70a789042245d5ef31eab5245380
+CT = 4bb8ed2207f36f40f62d3a2c90f8e3bd8f589059b69037118ce3ab864545ea81943ef0ea9489d223
+
+Count = 29
+Nonce = 267f76b9ec0f5e7c6f
+Adata = 2b421be47d07dcb12a0706f7490d05024fce8f433079e18ec78f4c8678f5f155
+Payload = 9330bb23428ab45f573923e977db74882282cbe1371da68e
+CT = c6ae24f82ac5cf9c18a2d98e610027eb2566a1ccfcf99945655e14c7bc8be97ea47388cb7b18bcf0
+
+[Nlen = 10]
+
+Key = ab72eef2aba30205c986e2052d6e2c67881d24ae5fceaa8f
+
+Count = 30
+Nonce = d7a46e726ed43f1580eb
+Adata = baa86f14271b2be7dbb37ddc7c95ce4857e57aa94624d594d7bd6ceeaada8d5f
+Payload = 2a794b84fc9e4a7e6d70a82b5141fd132177a86b4e8fc13a
+CT = 2d7f76464417613bb61d3657481346b74fc9d6abc6a3babd39365dce86859cd82395d11bfc8cf188
+
+Count = 31
+Nonce = d0afcbc1b2524a4a4553
+Adata = 7c267223047af946b06f6a45ffde4a5ec49c28b81ca22da4a36bf523e89e9da8
+Payload = bfc5ce1316ccdbcd8ac62484e7656c87947ff98cbba8e1e9
+CT = 4772c121367d0e8d3edade883342395f3ea065fe7dd7be8c8355b915ca2633fd557ca7ed41e00926
+
+Count = 32
+Nonce = 6eecffd227e8d5349523
+Adata = df7736560b1a13aa8e536500ea6cdb9a6757309aadf25a6a9189055a309c3f8b
+Payload = 19eef017100dc82f26ed0815c55c122e0b1587302894c391
+CT = e2864c6e12ac089daaa1e94af4b2ed04060d7ef65d2f72f0e7d017514d498f1f3c07d650afde8293
+
+Count = 33
+Nonce = a67c0675753f725a8fd4
+Adata = 7dd546397a9a0129861fb6815d419a307f90d259d55f3503961754126cd1b776
+Payload = 80f1f1ea46c92d28f2d60eab39ce056a4aefe63fa688538e
+CT = 882c687c03eaaad9d7f591649e736f0c1c78f95e40d40cd77499a8544bc2a8fe95f55fefc7316f8d
+
+Count = 34
+Nonce = eb83928f0d5f7aa3a74f
+Adata = 060cd3e4aecdb03837dfa9f544318c0a16cdc37fa2a3135be7888ac67e7eb26b
+Payload = 81e9174e9472777b6b184707108c01d6ea6b5d108ec3c6c8
+CT = 243cfa0a0a36a4c20333968910e6f52acc04c6f74e704180623f3a13fc13db958cbac49f7421d6af
+
+Count = 35
+Nonce = 5757abe01f7a1183fdcf
+Adata = 744629263041f0eccfce4a1ebcc18c4c984010f9241d35966263a8b2f72ee26b
+Payload = 991049f26b529af8b0bee0cc83989cf817d248254182f332
+CT = b20469b5f33f0996e8de869ad10ce09924a0bdd7b67a89a09c447a3132fbe5213133650000d50b06
+
+Count = 36
+Nonce = d9adfc5b44ad7aa94b05
+Adata = aa6a5448c6ec87be75eca35725ad2e902dbccf840d25b2bdf7e62e4a8fa4a511
+Payload = 14682301a99bf680805d1ffe62e1506d48cee8c51ef1d255
+CT = 9b44efa185b0c10325bb4c3c0815e6a6e46eea366b9a416b5ae554cb440eadd875657fd5cecc214a
+
+Count = 37
+Nonce = dc3ca30782c9c0a7fe89
+Adata = e788c98ae85b11b3ae884eed6f3b8f5bcf5ab1b7b20ad3f44f760b2287cc5793
+Payload = f9cb86f24536931a1b095b426a07e4621c000cf09b472bf8
+CT = 463f9124d1cc387a0f8b971d1e2da448f0efffc3956ebb2af8312986315522081f0989838ef0429b
+
+Count = 38
+Nonce = 9523f53f92b6e4ba86e5
+Adata = c3b123ccc916d26a2e6a8b5e30041ad69a944217e9b402b7acc0170c31e8c2e4
+Payload = b9bdcac80f64175836ab51bb1a1bee5ffe3a6b9b71afe3ef
+CT = c356b5a78cebd123808fb740754dc47a8ec7c9448bfacf39768e94f062e86129cc9210dfcd3e6128
+
+Count = 39
+Nonce = 16bdf18c09d60f3a2a32
+Adata = eedd0796f23612749e9fd282c864f3118d0683409d3bef1fda352e1422273c7e
+Payload = cc96133e473d197be1bafdfc1a21d58e57d0d89b2ba1c3ff
+CT = f9d78e9e3a41b3bcbfe756385a3715776eb84bb7d8d15432978757883f07802b25e9a5b15c43b451
+
+[Nlen = 11]
+
+Key = af84c6f302c59aeee6d5728ed5da2e3c64a5a781c52c4d1b
+
+Count = 40
+Nonce = df990c42a268950677c433
+Adata = a6ab5d78427f297a4b7e21f1091ff3a5b20caa3fe1cbcb09459d9df596a6c8e1
+Payload = 6db41aeb5f7c24df8929dbc30483b3c7934b3bd1cdce5bb9
+CT = 8c9328258bf71970d33e23a3ff81cc1c9cbe196a1294264bfd6a7255e4801963bb30a63de3fc5b82
+
+Count = 41
+Nonce = b7ea72641bbe2dca6d85e7
+Adata = 4e0f2ddf183281ec131693bdcea3fc9743733c07a486a42d5737735b3f6e3fdf
+Payload = 726844e41b1e4d883024b32fee0dcea38c889cb328885b7c
+CT = 9a133e4582c2ebc445862a9c6f2f4e39223c84081e322c8f262de30da6ef505fe640c53d765f672c
+
+Count = 42
+Nonce = 446fee1e75e79c0dfc9ddc
+Adata = 42b598eaee271e06d9e98dd94152b28ef10f506d65bd660b2fb8b1be9a2d7254
+Payload = 0cdcf348ecc9c3588001802c2106fb64be9c301adcc66e73
+CT = 0c2657b0482b6ca92e1b1c8fdf75eae3b0cd3af205e9bca396ecb1e46beb16000d585e1d9559ee22
+
+Count = 43
+Nonce = 2e6e34070caf1b8820ed39
+Adata = 8bd1ef3a1831fcc8919d736fb23111ca3ef4cccaf20264fab8eb3b071e56667f
+Payload = ca0860cc1e96506c2beb25b53d2947fbab634f0372afc8ba
+CT = 19e4774030e43e6853ab5bf176ba9c4b59f29f285977e3c15198cbe3e34c884c3f56a732974aa1d6
+
+Count = 44
+Nonce = 428542ecfb94a745980aa6
+Adata = 8efe01716b9018084e2ea7616f85b7333d945c0c970f8cdd400130b98db67cda
+Payload = bc6b59120ba2845b0e41f65a55e2ef1c45a81485c926c14c
+CT = cb48b0af6fad251d409d14ce0fbfae9cd9c40bf4a0c1e2b7e7cec415030997e1ac5db974b617b5a7
+
+Count = 45
+Nonce = eff703e6d72ddd23ff52d9
+Adata = d7fc74035e66709d2590b7bb3276245dd43824c9896fbd801ec1d07018b39b6b
+Payload = 1a5432e8085511ddac1be91be3e2945f85f0cdcc3a1c9f8d
+CT = c0a00cbaec65b7ca525fb26e80ee0cd18c7ef47c39c704833e59bfecf263bfdb24686627fd95e120
+
+Count = 46
+Nonce = 6a652ce21334a40a259dcf
+Adata = 5d24d80f22afe713c4076c200c1bab36917907fde7b6d34e141066f543526db6
+Payload = eb8f1988cb405041bf48d138ad41da7ef364d4ac59a9e324
+CT = d4f23166c09a15466c7e0e2b30627ee5a84f22d7e6135b4a0652b67d559a84b4a915ca6a420fd300
+
+Count = 47
+Nonce = 9382e12d447c0ca23cc9c3
+Adata = 239129eb760f8a770410c160e4e13a6b9497077c3e463b65397393fcd3cb5c70
+Payload = b40e80564263c7f450c53ef84df67247d72e8a04dbb284bc
+CT = 6de2ba26caa80874814816154784912c55e3d6da83488e7250f5a52f82211542b4e2661cf870c80c
+
+Count = 48
+Nonce = 2c3a4148cbb02504a2483f
+Adata = 33c3bdbf185b580353de79e51e675b03b31e195f19ba1f063d44def0441dc528
+Payload = 60a31736d99c3dcf25b349f6110e1c152b93506e85a01e67
+CT = 4d5e705d08f3ed1ca6f1caa74b46e4b1eee18a0783686f207de16aaa41d06bc071657dacf14da754
+
+Count = 49
+Nonce = 691cdf6fe9ecc2154d0101
+Adata = dc096596644c4e09c44078b86e5e0887c45094042eb0d74a6a13aa2524463076
+Payload = 77e6441ee017a93dd876ff2c7980540c77ee15edb0f23933
+CT = 24cecc81c8ac7ca9906372dc5263f2220b4dd162f1e08283f07f23e65475a20fd96e45c6c695cd83
+
+[Nlen = 12]
+
+Key = d49b255aed8be1c02eb6d8ae2bac6dcd7901f1f61df3bbf5
+
+Count = 50
+Nonce = 1af29e721c98e81fb6286370
+Adata = 64f8a0eee5487a4958a489ed35f1327e2096542c1bdb2134fb942ca91804c274
+Payload = 062eafb0cd09d26e65108c0f56fcc7a305f31c34e0f3a24c
+CT = 721344e2fd05d2ee50713531052d75e4071103ab0436f65f0af2a663da51bac626c9f4128ba5ec0b
+
+Count = 51
+Nonce = ca650ed993c4010c1b0bd1f2
+Adata = 4efbd225553b541c3f53cabe8a1ac03845b0e846c8616b3ea2cc7d50d344340c
+Payload = fc375d984fa13af4a5a7516f3434365cd9473cd316e8964c
+CT = 5b300c718d5a64f537f6cbb4d212d0f903b547ab4b21af56ef7662525021c5777c2d74ea239a4c44
+
+Count = 52
+Nonce = 318adeb8d8df47878ca59117
+Adata = feccf08d8c3a9be9a2c0f93f888e486b0076e2e9e2fd068c04b2db735cbeb23a
+Payload = 610a52216f47a544ec562117e0741e5f8b2e02bc9bc9122e
+CT = 83f14f6ba09a6e6b50f0d94d7d79376561f891f9a6162d0f8925c37cc35c1c8530b0be4817814a8e
+
+Count = 53
+Nonce = b4cadb5f9cb66415c3a3b714
+Adata = c4384069e09a3d4de2c94e7e6055d8a00394e268398d6ea32914097aec37a1f4
+Payload = 22bade59214fa4b933cb5e3dc5f096e239af4c2f44f582b0
+CT = 2296e3f8a2245224d274f1b90ed1287cbeeb464c70a89ee475ecb546efb8872a3f8b0281b3901752
+
+Count = 54
+Nonce = 72e6cebdaf88205c4e744286
+Adata = feaf010f462ad40a38eefb788b648e1cc292cd4bb08ebeff3c39182862296042
+Payload = 30655a6b5a5965db992e7248d24141055e988d726abb8e72
+CT = 69b27f2bbaa61c4f24e1c25e0779147fef79ec1582486b4651cffa571570618e2ada3376bd9f3e5f
+
+Count = 55
+Nonce = d8030fb31eca2c43f3f5eb88
+Adata = 66704365ddd0145febeb33f68b228a3f09e1e5a4b68149e6e06d886301841295
+Payload = 9d014a02507a6f266bd1ace21b55ab8b73983ff503bb9adb
+CT = 233a883650538ab8c0da30b90527f880fcad5b16bd435e762beeeea7a638c717e63764b3a5118a0c
+
+Count = 56
+Nonce = 58038cc35ad3dcd75195e125
+Adata = 3da7a757e942409a3b39ccdc0669ce6401f7e133c07c4c42e366d70a8e9bdd49
+Payload = eccfd817fa5e3a0146967fae13fc2471ee3944cee37969f4
+CT = 415a36872a04f5b4b5372f63394ab9fb353e0eb9b430450133a87fa29e5fbfa9bc0430b0cac00b7e
+
+Count = 57
+Nonce = acd82ae31bfcabd90af5af45
+Adata = ce22126f01bde16249c47102b4da68ad3edebcd4a16c24a16ea7ccdd5d364d10
+Payload = 9d2126d34963d3ba12cd841bd321036cb82cfb78f2a6535f
+CT = 88a5b889e6fd74fc15336e23374b430988416c7e6b6e7248b336cbbeb64fbebf2e7076a98ecf5bbe
+
+Count = 58
+Nonce = d24457d567fd0a65fdabf219
+Adata = 0091d39f3478d2c59bf874b96db9ce0f7e8b85a9b805e07dc96b219819d51663
+Payload = 6da3ac85505e93c4f391ea367a9e15fa9b388ef7ae2693c1
+CT = 7039a8a49cfa6402b4ba3b840e69200c13ac4a3eb1c709a30ea909047af4998c660afbaf346ed65b
+
+Count = 59
+Nonce = 50c59ca54eb64575b82b13c6
+Adata = 5e4e42cbf172853c351d597c7d6d38b1a9cbb7ac92c00863a80ac4a2d9f0e7fd
+Payload = 25b2ba0a937b71f3ee68e7172cf2c4524b662efcd08ce2b3
+CT = e95fc44287ce39c5ad6b91c88582563fa68a9e304094deb8b193dd767f17783f0b51ac0fb7323301
+
+[Nlen = 13]
+
+Key = 36ad1e3fb630d1b1fbccfd685f44edd8984427b78deae7a9
+
+Count = 60
+Nonce = 3af625df8be9d7685a842f260e
+Adata = 308443033ecd4a814475672b814b7c6d813d0ec2a0caeecbcaba18a2840cdb6c
+Payload = 8b9db1c8f9b4892a5654c85467bcffa2e15e28392c938952
+CT = 6bc6890fee299c712fb8d9df9c141f24ee1572b8f15112c2f8c99ccf2d82788cf613a61d60dae458
+
+Count = 61
+Nonce = 24eaeaa437649e61b706942b8d
+Adata = fff75462f96157d9554bddb6aac156fefd88fd4a90a8536dfc28cc577f19c83a
+Payload = 49ff4ff85f7407ca383cfa4fd7177adb4dab26e642c8186d
+CT = 3647fae50c588d792442f43a20125e77ab5db3c469391d24d0a421bbbc002eb9ac9ad01f625f824b
+
+Count = 62
+Nonce = 7325932d6694aaf61a8204c172
+Adata = be20ceb8ca14e9bef7158b280a26bcac763da79cd0eba9b1833ea808c5e7a66a
+Payload = 2861494eb40b9d964d339797c1b6aac63c6674187768957c
+CT = 286dc74001e2a6000a23db164f4b2912de4afcf1df8c3aa5ee32a7ffd4e7bc303d3482fbac431828
+
+Count = 63
+Nonce = 61c9949df5853e42599e5ee0c7
+Adata = 243d09ceb16755cb58d62065df84890b840ad9b7eec1132c6427cd7c3d843fcc
+Payload = 943a49073db6ae94a88844ed895f8fd99ed25c3f42a2f78c
+CT = d3c56bd265a2cb0811dd218f248800ceade4f02b5403b9635eb30cbec49cbb51c41cd5032b7fd759
+
+Count = 64
+Nonce = 07b6c18dd3b0fd9e8ff026a436
+Adata = e85f141c3d1af7727fcdb00f8e2c34e42a436d04ac5b8ca9f321a178a2056806
+Payload = a18b0a4618063c0519818d113b8e5435aaf153f664058f1b
+CT = 69f933a2a5e774e8d013cbf78c6ab0b73e6ca323d0c52691acb5cf2631987d3d963349b035324aac
+
+Count = 65
+Nonce = 0c075df70630dec2fe81834945
+Adata = f3f5c5ffbfe8247bc0c33c793652f749fe91b6dd141cf0db56e71cef8a2fd266
+Payload = ddc4bac4115e8cb06d29d22e400674dbc615a667f933603d
+CT = 26bdd25c9f204fc7520d26c161464c28fb35e395b295b3db4e239d33283d18415b54c2aad4bde354
+
+Count = 66
+Nonce = 0c2d20375057fcd4241d290f6a
+Adata = 70ff1b9ff8ec08fdb18b0e7dbe01127ed0cfe0b0a449ca2ace4992b7b6248b71
+Payload = dacbdf1979e000d52b573e74800761b30acc26681f372acd
+CT = 6a642c389433a3464fc64783ae6a14a9a45f0998b56a5b9162d7e0320dc930df3640a786d7ea9ae4
+
+Count = 67
+Nonce = ea0801cb3dab853750a922dd25
+Adata = d83360d0896e022bf014bd33710ab212ddedda6d95a54996f33db304e5f12f01
+Payload = 46cc5653bbd8300dfb0df6d0af3fb7c7639a830bdc9f68c7
+CT = f1b0728920351d9edfdbe7df360b21f6cc5b628dcf43a3f10d06b4a545609a2128a95d4d73471559
+
+Count = 68
+Nonce = 97e6de379c90fccf3fa8f27013
+Adata = 539f8eb802bfecaa4fb5b19debbf3d4847db9c4e0473a308ab3f3c859e68fecf
+Payload = 8b013f52a828905013f250fb9c006a173f6c66a64b5ba317
+CT = 556a439bc979dac1cfea8c5b64aa78547f52a62896c19893f3512baf72cd79ba9301194be204bcc0
+
+Count = 69
+Nonce = e832b6330d3e5e190598cb9c61
+Adata = 093be516277e8b197ba5e9c85a831529befff0f3971510ab611dfe0dfb50a2ad
+Payload = 635d2d7894bb816f154210946a369df37ea492993ba23af9
+CT = d8e19c67e5aa7f14a16ecaaac414a2b15a15bb5f966932e6b0bfe9a5857fd36df94aeadda7f83a79
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VNT256.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VNT256.rsp
new file mode 100644
index 0000000000..2817684910
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VNT256.rsp
@@ -0,0 +1,456 @@
+# CAVS 11.0
+# "CCM-VNT" information
+# AES Keylen: 256
+# Generated on Tue Mar 15 08:09:25 2011
+
+Alen = 32
+Plen = 24
+Tlen = 16
+
+[Nlen = 7]
+
+Key = 553521a765ab0c3fd203654e9916330e189bdf951feee9b44b10da208fee7acf
+
+Count = 0
+Nonce = aaa23f101647d8
+Adata = a355d4c611812e5f9258d7188b3df8851477094ffc2af2cf0c8670db903fbbe0
+Payload = 644eb34b9a126e437b5e015eea141ca1a88020f2d5d6cc2c
+CT = 27ed90668174ebf8241a3c74b35e1246b6617e4123578f153bdb67062a13ef4e986f5bb3d0bb4307
+
+Count = 1
+Nonce = 195c0b84baacc8
+Adata = c7d9557b2ed415652ce6faa8cff5217ac803530ec902890b31eaaf3eeb0aa98b
+Payload = fe012718481b2c4e1d7f9a7685e3daac43ccf22cad0df900
+CT = 893af0f130f1317de9f217234274b0c04fcc202cea9a0df882c00b5b463654adbf82888099a7d258
+
+Count = 2
+Nonce = 363e0e921c6f11
+Adata = 805678936d4e94746ab4818dc5f50c41e32cf32e7a8aafb300fb91af6406108c
+Payload = 7e7e33e1a07d4e8fde2f33304f21cb564d146860ccfeb49f
+CT = 645cdd11a1c232815ce1e07ca3ea83f372eba46cedafddd980adf2762a1617adfd4d8356bb48aa8a
+
+Count = 3
+Nonce = e323cc866af462
+Adata = 163c747f3ba4ffd68af87f2475f48f2714659a2ec43b9ed115e02fe0e3c8be99
+Payload = 2bfc76f3b108ba3118b07433c4d3d5f41564d22547c12822
+CT = 0db04c6b068e73e3c4d71059bdeee3d27622f99dfd07d868fb9c02753c57fec7e1a5fa8f3860501b
+
+Count = 4
+Nonce = 03ae777078b95d
+Adata = f1dacf9062dff9a6a3d0498f9d058782f891475684196bf2d8e7e905393acff7
+Payload = 38c4275a5f605fd1d99517e13deebf0c9794ef586070fa9a
+CT = df8f524872b5f06f3f219ba76524990b466409894930d7e0d104990e598eabd88cc8342ac16424b5
+
+Count = 5
+Nonce = 1c6c351d4fe9be
+Adata = 14285e97cc3cae452e1a52e2fa0bbe24df96abf2faf6b9779acc59764612eadd
+Payload = 9e2220f3c17532e1ce0d6f562b049fcef35bcaf9a7e196be
+CT = c274b28228a6b13b670c325080f88d188d40d78d385481eae004894b1861db5d2d8ae98ed8926c1e
+
+Count = 6
+Nonce = a121dc27479397
+Adata = 359421e9f78cc4a31f4f019977d7fd29780524e20288798c50002a682a6368b9
+Payload = d42b16b32e77637724144eaddb21ca8d7db4e7f73acbf707
+CT = 56e3e3e59e978161355e7d8573dc0657db400ca0b083dae8ed2ac2cb63e1b9d7dc598634198fe4fc
+
+Count = 7
+Nonce = b1f0e26b60bf1d
+Adata = 2ab4239fffd13762fb5391f5a4760d12d96ea12666a793b4d651e9f4891c22c1
+Payload = 9a2851083ad4e7b915bb0526bb4054e4c0b4adf8626edc90
+CT = 5b2e0215523ff37f0df46e84f996fc9fc779986c766fa51595b8a23ee377d5c2850f4ed95a385253
+
+Count = 8
+Nonce = 50412c6444bcf9
+Adata = 09cdcaa87ddf8bbe6db8411d14bb9064e4a121286cc8a6e97fce1844935f436b
+Payload = b28a5bc814e7f71ae94586b58281ff05a71191c92e45db74
+CT = 05cbc32a6ca797684636dedd16ce65a1eed69bcab1b1bdbd514ef5cbf9991a919fb4974d55506ce1
+
+Count = 9
+Nonce = 225557b0faca3d
+Adata = 21611da060fa90cf7fd68b721caf303307a56e56453326495b628c7dc93cd175
+Payload = e831b739e8eb9f787f63c0bb071ddcc9f44cab8d5b447d23
+CT = a97e0879407eb3b7f93118ca73f17eb34e9f4baf43b07be2e8a3f7b848054cb235e1b58d6a12c5cb
+
+[Nlen = 8]
+
+Key = 472bf7946bce1d3c6f168f4475e5bb3a67d5df2fa01e64bce8bb6e43a6c8b177
+
+Count = 10
+Nonce = 790134a8db83f2da
+Adata = a7a86a4407b7ecebc89434baa65ef173e88bd2dad9899b717ca578867c2d916f
+Payload = 59eb45bbbeb054b0b97334d53580ce03f699ac2a7e490143
+CT = db4961070f528ccd1a5a0681ee4d0ce3515fb890bccedc2dbc00b1d8b2bc393a8d09e87af7811f55
+
+Count = 11
+Nonce = fb2441d1594a488a
+Adata = 0875020959ed969cfb38636d1d5aabce9658b00171a7614ea9e5395331c7659c
+Payload = 451101250ec6f26652249d59dc974b7361d571a8101cdfd3
+CT = 1bca7b0d35a68c0ffc568ffc8221cca738b67b95e3ab26efee21c5738d1f7fddf3030d004a702704
+
+Count = 12
+Nonce = 0855263860043207
+Adata = c7fc24863c33f7e8cf97b337918495d52d864ac570c99cbb09d151758d6b504e
+Payload = 61fcd7ef9bf151b9d8a81dc1ba4f82c45e9c2e4784627acd
+CT = 9b939b6b188e1d0fe016f366fb01eb79a99ef7b1b57c6f7ab223454c57c714d96681cd4d55615afd
+
+Count = 13
+Nonce = 415cd251a5e36943
+Adata = 1a393c7e85fb286709f4eb50f09640e1d65ec1135cb4443820136b3cec69772a
+Payload = 66ae08d494dc9df9b7f8f53199fa37d0c88885458b168c57
+CT = 1731e260ae31b8068ad1099313b167d9e6cbe49f471da61a9af96d3ce4ea94213b60cb69d92050e6
+
+Count = 14
+Nonce = d95bd65242bb2265
+Adata = d0e20e1358be5cc1c45c1cf02c82d0a6d0824cfcb65774cf95f047b9f2cc1d3f
+Payload = 312c3791c64d79205a11eebfc14b2d7a6b00391793c9559b
+CT = c3fbe558ff9ea83ed86b7d66503ee38eee94e4a41fd53f0f627a352d056712e0d44404c61712e2ab
+
+Count = 15
+Nonce = 3f0bf0141dd3ace0
+Adata = 9dd4ed18209dd6cdf19cc76fee443827e7331aaf020960c15d7bbed0f6a3b1f7
+Payload = 08354480047eee3beeb5ab165da17d23f2f1a4ad98720611
+CT = 2db9d2c54134d37ebefcecb9e2076034b975677fde58ef6032645a322fa9bc8aace600f942a84db4
+
+Count = 16
+Nonce = 3fd8b3a3ff563a42
+Adata = e58327efebad3276a7cd1b1ccb56db0caddd02a303cd9fc7ea5c607a2ebefaae
+Payload = d1abd89351384e1a3c3366f77c3175f6390801554d7cd783
+CT = be284dcb357ae99ada7cc891730320ebb32ca627eb8c80623957a2a5b6164218fc83e12c42d5c532
+
+Count = 17
+Nonce = 14db1ffc1c87117f
+Adata = 6c2b091433833a0ed915354dcb70d982095b614dc51a95a22cec417184d8e786
+Payload = 0594307491f157821e63f50c94034f9284f095d5b897153c
+CT = a114c84a10071e359bba2b2ba4ea67f893e27e6ea880aa4b2cf16ce68a93f8839245baebb2278300
+
+Count = 18
+Nonce = 40b0f74ff27a3fc8
+Adata = 3b9e1f4e9b57a6dfb5e0ca7ef601fc6af30a1f8650228e51e0dc61180d0bec6b
+Payload = fc8b7dbceef6b0ffcbade789e09303044042cd671607e819
+CT = d00ef56074a8213740af8b8f974f778db560ac365d6ce916b8d191130e864bcfcd1dec94a1aaeaef
+
+Count = 19
+Nonce = 96cbe9cd19351359
+Adata = cf498fd042f9a07503e490cec4873d4df91162cfde60bd2cbb2b710c6681a9fd
+Payload = 315e81c9ce556dcf97a5b68503fd2228a7a6a174a15cd618
+CT = 7383c2de08bce3f0b7e504dc03d062f44396bcedd2180fd954e6ec9f6ae1e0976ecf04dbee6463c2
+
+[Nlen = 9]
+
+Key = 58ae7965a508e8dd2eda69b5d888a28a1cb3783bad55d59d5b0da87137b72e93
+
+Count = 20
+Nonce = caa3d928d2bf2b7f2c
+Adata = 304678b3ffd3200e33a8912bcb556b3cfec53ca17f70ecba00d359f9f51d3e3b
+Payload = e61bad17640ecff926d0b0238271ee4c9f8e801dd7243e9e
+CT = 7bb1137c14cb4d324a4a8f1115c619ebf74927f0bed60a8d5a9140ff50dc4da375c7d2de80de097f
+
+Count = 21
+Nonce = cf09ca67659a583bb1
+Adata = 5507c4c3107cb446d19975f91207dbf3e2a51d1dcfd7da2f082159dbc3f41547
+Payload = 1887bb0c02500093a30a44b99e137483704b06615d308c6b
+CT = 834d3b2e5f0915c2348c706b4d2ff2717983ab4490edcc63971f02b7122d1e4f78de9c3376520f5a
+
+Count = 22
+Nonce = 97f940d7c1230bd8d2
+Adata = 56be2c9e09b555373d58f6fe2a0ca9b4ddba899addddf12b0fda860ad791773a
+Payload = 5ac67c9bec9b95c54e187a4a6812f5d701c4ac8f847c005b
+CT = 9f372ba1c87a115847cd708aaf5b8a143b6981ffc2c61cefd30ece13481609809b218de04c4e5ed0
+
+Count = 23
+Nonce = 147c7ebb6c92245054
+Adata = f95d64a513a9f3e6c95c9ed27b22fafd7dd10da52636029523142149116aff53
+Payload = 08f199a8d7e3ea821dd3106e8947cd2e9d485342b25a6471
+CT = c438aa6d187643d030dfe4d6b5b578f84838f4dc5c396d700c0986ecd7dab44e5e97db37392a485a
+
+Count = 24
+Nonce = b9bad794d49cdac9b3
+Adata = de9ff2a43f49cdc502cd17a373989bafd13fa6ccff6660557ce05b6295186d47
+Payload = 40d1cd4063750184356a1d7cae1cf1824f552c5d59a62dc1
+CT = 9952b25f4f4f375440cd958456184fe61610381ba92ca48f38dd977042c4d97da84e4effa650799a
+
+Count = 25
+Nonce = bbe054fbef86db3ce7
+Adata = dcec76181e3b872a5a6e79f070354e38866c7f67fc428fbca29ae6d929b1dd7f
+Payload = 5f29808ba74b672a0f82b3b7581dc32478c6e790e2b8c61c
+CT = 4d176f48b09b772dde8adbdaef720aba128a8d38a902847ebf22c81a5d824b4916660be6f9b513e6
+
+Count = 26
+Nonce = 6a35e1a4307f6efc6d
+Adata = af28120505a84a75b0f6b18cc9d8c75c661bf143be29c11d8ede78b9bb98c98a
+Payload = 5e2f601395ec406fcf96785f768162e849f867dca77667ab
+CT = 4e305e26d34711c6aa775f490939cc6560d3cb6905f5b0f5588ace6fc303600abc8e5825cbaedc7c
+
+Count = 27
+Nonce = f6c237fb3cfe95ec84
+Adata = 038f8ed89444784417a9c23bf11e9b436174e6c10959e00faa1704ce2f7f2c7e
+Payload = dfd9cacbf7d73d688447ebab13d2e13f3613652379b386f6
+CT = fb16c17a6b22a8658f446203ad46a48b34808083b271cabb015a1f78abc287bd2a63381ead07c558
+
+Count = 28
+Nonce = 50d024a3e7455d7249
+Adata = 8513365786b7988b208984e11022c15573f978bbdc29e8a7a4745c8a81885a1d
+Payload = 400317786b7df63373ffe541efcee6318cfc95bb673aad3e
+CT = d33b3141fea3a9ebdeb80d1da32dae42680be78471fb3023721f714120162514555b60560afa4256
+
+Count = 29
+Nonce = 02769283d5a06c363c
+Adata = 292c0be3713c6c588cb4e29a1c43b3e6353e33556194e568e800e4e44e8281e0
+Payload = 12ba8eddff1c2a03ddd25bb924ff065a93fd712b2c4f61eb
+CT = b15b1789c323a68568f86f35483bd7e204beff8f318ae14351f5e62b3b923a937e6c307af202fab3
+
+[Nlen = 10]
+
+Key = aecc5e18088bf9fd7b17f089bdd5607b69903b04b726361f8a81e221b1c91891
+
+Count = 30
+Nonce = c527d309ab29ee91c5fc
+Adata = 8f9a73e7bc1c11e2919020ba3a404cbddf861e9e78477218e3be2cd4337b278d
+Payload = d4291c99901345afe29f58912a414a7498f37b44362bdf3c
+CT = 392784a9e0b14bcd37639ec5409d6ead3e75f855e5a92c33ffc040ef3977e0035ce6ea6d157c18d3
+
+Count = 31
+Nonce = eebc31a5813b4fb93b63
+Adata = 9c87ad77953bf8a811e001ddb946eefafbfaa598150e85f0701853fa307d77d6
+Payload = ebcfd71120b0f9a2cccb898e6dfa082998cbe10032de3e61
+CT = e38eaad1e2df77e85e7129a8ce0f82cfc32b0aef79ab651bade65aa17e4dfb0aafe18cf71a72b180
+
+Count = 32
+Nonce = 231b33dc406c9210f59a
+Adata = 38be46d271bf868c198052391f8a2147c663700d9bb25a0caaa36974f18dacea
+Payload = 9032f910347daf661092b5c1f15b5ffed1369b194d9e12f0
+CT = 868b85288828501cf1d06610fec25e8b8a4b437e2e4f5563b7f3b898a2356909784598f8a8916f5a
+
+Count = 33
+Nonce = f2a88c3ebc74e62f24c7
+Adata = 5f495c5da035cabeb77e8aef10e91a05bd5aa414d1a37fa1099af959b26e5403
+Payload = cfe8ee9b475e36058471e2984ae66f6ba1b3cb477b15155e
+CT = 22c16333ac651cd9c183e78aba3e9312fb3b77dd6f9199502788860aae5534cf84979e30c3327d37
+
+Count = 34
+Nonce = 9cbaf1c83ba60b1e90ea
+Adata = 7ef136bd9a5809676abbaa68016d6fc713e34ac4b768a8246b1198c959f43085
+Payload = c3bcb0aaea93893f05eeb6439c8619dec17670a6439e2921
+CT = ebd9fb86563aa8f10062624441336f982c161ce5717d990a599ca6ec1c61a14c37b5902389e47aee
+
+Count = 35
+Nonce = e25322845d87d8a76753
+Adata = 2a89b9f0e56a1cf87dd38ed78028b6286ef8b7141dd2b3c65c5a8e1ed79bf4aa
+Payload = ae622ff9381854f831892c318bae5c003e74b15199bc12c0
+CT = 144c920f0fe278f353d0b053563d907c7589e4f1479d7a93a0604deb3fd9cea2d89987833ff5c2f1
+
+Count = 36
+Nonce = f4d7978fad36223623cc
+Adata = 8671de7e994967f2521d263925e745af9273682d9c08ced07d4a98fc985f68a0
+Payload = ef9b4ff8da108cabc972192ffecd5f96594c6d0871ffa6aa
+CT = ae4948b3bc1e50beb9f5d005871fc0d3dbde295de1c9ec3cbc866ab47bea7a4d0070e52b492fb8f6
+
+Count = 37
+Nonce = 6597ffb9eaad0fd9d830
+Adata = d2967ddf69ef62a9e23c9118dfaa55df92b4116322f1c9275131e3875dc92faa
+Payload = 5015c894b2437ff15c46bca9236830ff4bb057cd5764f027
+CT = 0b1dcb3cb0b4c32f398f3c43eccfe8f4242f33c99a2a2283efcb3dacac25bed0304f227fd5b77b8f
+
+Count = 38
+Nonce = 80e376b87272d99cde28
+Adata = c9cc8f967dff45c05b9345d03813b6e30dace99556f7df75b7120bb6e5f55827
+Payload = 615f657e24129a3e0f119988959608821219ce8354c4be26
+CT = d3e8b8f7ff8faa666ffe2509187fa7befc7412fd4e3bdb06cd2f7494b1fb0a0c6a2184e5c4787fea
+
+Count = 39
+Nonce = 344cce96455541d403f3
+Adata = 748cce18fb40126ce125dbe341fbbc59d2aacc170ed5ef0293b15713c9184a07
+Payload = 828b6a4cd49f499a6e8e8508f9ab35255d8e9fed33ba4d91
+CT = b67e582a74d7f022a16ada2de7ec18caafdefa6b104baf4ed93b6f8c8a1bf72be75976e4ebe6dd1f
+
+[Nlen = 11]
+
+Key = 97bc7482a87ba005475dfa3448f59d4b3f9c4c969d08b39b1b21ef965c0f5125
+
+Count = 40
+Nonce = 0bcf78103ec52d6df28887
+Adata = 049c10f0cb37ae08eae2d0766563b7c5a8454f841c2061a4f71a0a2158ae6ce5
+Payload = b99bf4dc781795fc4d3a8467b06e1665d4e543657f23129f
+CT = 0d3891fa0caac1f7ebe41b480920ffd34d4155064c24f3b17a483163dd8f228d1f20cd4f86cf38fd
+
+Count = 41
+Nonce = ab6374c6b2faefd92fa3d3
+Adata = f19c044023e5cf339203738ee70e76527519763664c06ae00e002a5ba94c32c6
+Payload = a2e5c51f516db01688b64c173bb25645182a005018022ee1
+CT = f70c598df3c64d3527ebb7fc8408b7de2cfaa1da7984ec361f1ad61758d828b70d4881b7d6ae8cd0
+
+Count = 42
+Nonce = cfb89e7ddcba601e875110
+Adata = 052714010da516c896ac5842a839ae845324643cddb080e6206148432d0d0407
+Payload = 037f206cab78a6ca0745dc8fc137e22e14f3d7183917ef83
+CT = ccd675862502a2e2520a33250150b8b7b220e84db854888c316dd62075fc761e2bc80edc5c564bdf
+
+Count = 43
+Nonce = 967cb6f8530bf8a43adb42
+Adata = cf391a84d03e2e22aec1965cec821f99e7bf21a7c3580dffa531464b22d83225
+Payload = caa3d928d2bf2b7f2cd8a7f357055b6d6895a5e34f47972a
+CT = 4f4f509debe6e52eae4af8b1740dde0a5338f78711a3b4ebfc8b5aca6d606222d6af7cfea0d1f4e1
+
+Count = 44
+Nonce = f5b7b5dd2b5e1ec93710c9
+Adata = e7a6b228a67d37b9d29a38efc547e50b4a6d95d599b45ee189ece21101ac6b5b
+Payload = 4a74ff35418723f2cecec1012484b52114067b2b2393e7f4
+CT = 25b140922a9d4f2ce153a4ff86596a49d7de6a6184e931e8b2ff27a98029b23484e00c2a5d291887
+
+Count = 45
+Nonce = 713de00faff892977d99d0
+Adata = 14ea93488d4284d21d4c7ce14414adf45c1ed9d2d99db866d0e59accb6234dac
+Payload = 3820db475c7cb04a0f74d8e449f026ec951fa59667738698
+CT = e4d92ab8d1ffb0976670d891cc8338da12f86d5d79b334103d2ae816edf857c810b6fdc7f2c71f1d
+
+Count = 46
+Nonce = ba87934808de09b2ae829b
+Adata = 30e2ea2a505f19e8760a0a84961000c7a0b7fe3460a9d3f5a38f54149be2e9ee
+Payload = 0e52a384cedcdf7f179348de6e7336aa86f8855fbd903cfa
+CT = 6df893eed2be958e5f542f8cb4adb392b34786cb4ce821ec93fc57997b977948d55bdb026db5bc48
+
+Count = 47
+Nonce = ea09fbe5da0fa4fe911e18
+Adata = 237dc8512b29bccdeb8ee39cf83b9b6dd203823d175c44d5f605b194e7ec136e
+Payload = 41cee0ecaf9c65cef740440af37954ef49a585779d2abbca
+CT = 2f204ebcf549ee2a800d870e6341b9a89a41ab4ae91b6902ff704a2bcfb8becd0226f76d68fbb08b
+
+Count = 48
+Nonce = 5b80d7affc4ab4a4b68bdd
+Adata = 3a38dd7da30f5c312fb1e978d87b7a39792fd9ea3e9ab1565874e99df587327c
+Payload = 5ff92f6d3ca791421363e10cc84b4e8e21e0ebe5d8c55d6c
+CT = 05472db7875d59f8bed45606f355a516de93740aa2baeba18df9400df42baee6b9a0d75b45840104
+
+Count = 49
+Nonce = 514bba483fe7f2b7e555cc
+Adata = ac8beb419099cdb42a39e9b46fd900cc52eec4b43a96ed18b37b899b63fb931c
+Payload = b0b11dfca9b3936d1b4a423c5acd3d012b399a487c19c994
+CT = fa20629d514c4ce7bf727629bca5aa1c0c7e7851fc1bfc5c847729a70d7b4cff5281aece37006015
+
+[Nlen = 12]
+
+Key = d6ff67379a2ead2ca87aa4f29536258f9fb9fc2e91b0ed18e7b9f5df332dd1dc
+
+Count = 50
+Nonce = 2f1d0717a822e20c7cd28f0a
+Adata = d50741d34c8564d92f396b97be782923ff3c855ea9757bde419f632c83997630
+Payload = 98626ffc6c44f13c964e7fcb7d16e988990d6d063d012d33
+CT = 50e22db70ac2bab6d6af7059c90d00fbf0fb52eee5eb650e08aca7dec636170f481dcb9fefb85c05
+
+Count = 51
+Nonce = 819ecbe71f851743871163cc
+Adata = 48e06c3b2940819e58eb24122a2988c997697347a6e34c21267d76049febdcf8
+Payload = 8d164f598ea141082b1069776fccd87baf6a2563cbdbc9d1
+CT = 70fd9d3c7d9e8af610edb3d329f371cf3052d820e79775a932d42f9954f9d35d989a09e4292949fc
+
+Count = 52
+Nonce = 22168c66967d545823ea0b7a
+Adata = 7f596bc7a815d103ed9f6dc428b60e72aeadcb9382ccde4ac9f3b61e7e8047fd
+Payload = b28a5bc814e7f71ae94586b58281ff05a71191c92e45db74
+CT = 30254fe7c249c0125c56c90bad3983c7f852df91fa4e828b7522efcd96cd4de4cf41e9b67c708f9f
+
+Count = 53
+Nonce = 225557b0faca3d6cbaedec5c
+Adata = c7aafe7d3b419fa4ea06143897054846ac4b25e4744b62ba8a809cc19253a94b
+Payload = 0e71863c2962244c7d1a28fc755f0c73e5cbd630a8dbdeb3
+CT = 2369b56f21336aba9ac3e9ba428e0d648842a7971182d5ffac57f6ae1080efab4ed93f8b4ce1d355
+
+Count = 54
+Nonce = 78912be1a35e156a70fb72f7
+Adata = 12ba8eddff1c2a03ddd25bb924ff065a93fd712b2c4f61eb80d77fab2c4900e0
+Payload = 113efd182f683596862ccd5eba2e2d4ffa709d9b85c6f1d5
+CT = 835a22eb8d718c0ee1531a2d1bb95f58215c997c612908eeed3ccaeb7a814f69d3ec1fbf2ee9792d
+
+Count = 55
+Nonce = 91ad90b58d2044abacf957e1
+Adata = 4fc795b9126c23dd7fd514c2e5a8ca583e88a783b28cbb2a5df09f8b520ba0d1
+Payload = ed55f6b9eb8fe74474c037ede94ffd84ada846ede4ecff74
+CT = ecb595276fd5d412a7cc3f5cfe960f47a0d0e2df0b08a11ac257d67143722a976c9d7f44b09a767d
+
+Count = 56
+Nonce = 4bbe4ca29122c4892ca09b5b
+Adata = 367ecd1b71dfb96a84e2369f28705dfaebf0c73ed35d5364449b2391230be846
+Payload = 8dd497bb777bbc3e56e3af25a43545007bb00f2b9e9f815c
+CT = 563d61fc0a5b82804a580a7d752a8e61d3342fb39372b39b6843a685bde3175695796f6e64f35901
+
+Count = 57
+Nonce = 218e7b8a8fd62927f90b70e5
+Adata = 01815f599d6ba0d1c09f6f673bb6cca4c2a7a74f4e985be4c0f37842c7bbc5a4
+Payload = 80f3e4245c3eab16ef8bf001429122e46bde21735f63adba
+CT = aaceb16589b9de253c99d0d32409a631db71e8df8a7644bfd027e3466e8220144cb0552f9b2800e6
+
+Count = 58
+Nonce = eecc9f106a0721334cc7f5ba
+Adata = bf38d0ee11a796a517539bbc9ab00ff85a4ddbf0a612d46e2bc635180ad34c50
+Payload = 36cefa10af1a3446a2c8d4a1171144b9ddd8e33a7cd5a02d
+CT = 9bf3b2df93cf5b587ecc96f45fc75e6eb066cb286cb06f284c9027fc41bb8c848025fcf9d092a873
+
+Count = 59
+Nonce = e41af8ca408c4c12e37561a4
+Adata = e0b20892875f60b5d8763a04958487fa5b7cf8d67a456e430475b337245d671c
+Payload = 32a4da08bdd51336ed5798c7177b853a534bc98f2e6f7d4e
+CT = 95ffdc68f721cf2294d0d88002e3814167306fd906dbebdb7e6e0e5dc0a03826e51bd94269d7a41d
+
+[Nlen = 13]
+
+Key = 4a75ff2f66dae2935403cce27e829ad8be98185c73f8bc61d3ce950a83007e11
+
+Count = 60
+Nonce = 46eb390b175e75da6193d7edb6
+Adata = 282f05f734f249c0535ee396282218b7c4913c39b59ad2a03ffaf5b0e9b0f780
+Payload = 205f2a664a8512e18321a91c13ec13b9e6b633228c57cc1e
+CT = 58f1584f761983bef4d0060746b5d5ee610ecfda31101a7f5460e9b7856d60a5ad9803c0762f8176
+
+Count = 61
+Nonce = 8a56588fe5e125237b6cdc30f9
+Adata = b3aee5fbf409bcfe9b46ae68d570edbbed32c12d13926ffb5ddc60ff0bdb7f85
+Payload = eca81bbd12d3fd28df85e2cc3dcc2ecbd87408002fd00fe1
+CT = 9aad62a5443550d11f9efdab2de0eba74d47ae4f7d16adf4276664f6567f2f978bd4be4d80cd07be
+
+Count = 62
+Nonce = d908b04840caca2280e5293ade
+Adata = 314a202f836f9f257e22d8c11757832ae5131d357a72df88f3eff0ffcee0da4e
+Payload = ad1109ea5c79bb55d22e9713eb2df42767cb29a2eba3ad2c
+CT = 61fdcebb158cd03151697ae7871c0a998802997e0672e5886e5a9df1b1d6284ef657cde6f74734bb
+
+Count = 63
+Nonce = 6df8c5c28d1728975a0b766cd7
+Adata = 080f82469505118842e5fa70df5323de175a37609904ee5e76288f94ca84b3c5
+Payload = 1a95f06b821879df3fd3ac52fc99a7c1d3e9775263b7d036
+CT = 704f60f9cc3ef7bc00b4f7a271ca70a89f4d5605387b3e2f8cc80aa08572b90e9598d0a73712b720
+
+Count = 64
+Nonce = 6c6ebacce80dde9fefb7e5bb47
+Adata = 93f0fca0c8c84d5cc48160b25e246226d489225c0f8275e52856da592c715aa6
+Payload = 46820aec46ebd0d61706129584058a1498514928a87fe620
+CT = 00f6cccf45f046da1e6266afe61eed61c60c28515b2e1ab386b2c952055899184f0d95ffe3959f89
+
+Count = 65
+Nonce = b94bc20d8c9abca7645fc6bebf
+Adata = e1c083c93663f5a066ef337a61aa3fddde7c301a42463137c375cc2dcdd76954
+Payload = f1fca581d3dbbc61060c0c02adb47bc57954d25a283f66d6
+CT = 90c65d23e0e1786cebb95f9b1306d001b2e503842cdedb75e37a53d77b9e38605febdd7b2b666f98
+
+Count = 66
+Nonce = a4974791d417d7e9eea0f4ae8d
+Adata = 33602f308f3a0f7e1c75fc1e4321d545ffa278234958dbadd37f59a0f85349c3
+Payload = 41712c058d2d56b43b2c79278e790858a289320746c15a60
+CT = aab5656a1ef060c9b1ef7e2f3cc0bda40ff067900401182563ceb824708a20724c99c83f1caacd70
+
+Count = 67
+Nonce = 6003b771afe4e99e1ef1ed4a31
+Adata = f60d8362b2ebf523681bb051fd3ee13919ad86acd963c703c4178a5f01a84236
+Payload = b766022311c5e1d74a607fec7cb8ee805b8397a6c5f374c1
+CT = f73b2a6dbf8f798d4bfb489a6578c9c79152e42aa3b81b64a84e7af3116a18f7ce44ae93f420270b
+
+Count = 68
+Nonce = 27861168ac731a223dc35c03e8
+Adata = b7ba1c66282cb6092ba601407ff9578afdadf7ba7a4d08edef06dbbfd87171bf
+Payload = 0822e3e6ba982091d532cd5271fbde25305d1f6e71880f81
+CT = 5ab3e5296cd1f08704c82f6b42939702515b7733853d723d4009312bdae46958d844eca502bcb005
+
+Count = 69
+Nonce = ef284d1ddf35d1d23de6a2f84b
+Adata = 0b90b3a087b9a4d3267bc57c470695ef7cf658353f2f680ee00ccc32c2ba0bdc
+Payload = bf35ddbad5e059169468ae8537f00ec790cc038b9ed0a5d7
+CT = b702ad593b4169fd7011f0288e4e62620543095186b32c122389523b5ccc33c6b41b139108a99442
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VPT128.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VPT128.rsp
new file mode 100644
index 0000000000..f79db90b4d
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VPT128.rsp
@@ -0,0 +1,1383 @@
+# CAVS 11.0
+# "CCM-VPT" information
+# AES Keylen: 128
+# Generated on Tue Mar 15 08:09:24 2011
+
+Alen = 32
+Nlen = 13
+Tlen = 16
+
+[Plen = 0]
+
+Key = 2ebf60f0969013a54a3dedb19d20f6c8
+Nonce = 1de8c5e21f9db33123ff870add
+
+Count = 0
+Adata = e1de6c6119d7db471136285d10b47a450221b16978569190ef6a22b055295603
+Payload = 00
+CT = 0ead29ef205fbb86d11abe5ed704b880
+
+Count = 1
+Adata = 98d477b7ef0e4ded679b0bc8d880f09823ad80e9732fde59c3a87da6a1fcf70b
+Payload = 00
+CT = 5b85d144bb51d4927074d3536a2db83a
+
+Count = 2
+Adata = 28f32de10b6c9d3c3f46efec7aee24006208a54c4d1c2bba4b8cdce166cab7d9
+Payload = 00
+CT = 01045de4a09486eea5efa33ecc6cd299
+
+Count = 3
+Adata = af397a8b8dd73ab702ce8e53aa9f0189995c6c9e920dcb75795149550b499deb
+Payload = 00
+CT = dfd75400b59c3ad387bc86dfbbfb52ac
+
+Count = 4
+Adata = 3fa956bfaa27e249bf0a1276468d808259f3b8e2687851d780885d44cc2f04bd
+Payload = 00
+CT = 2b11d2549b4e2f0a81c07ee90af4d081
+
+Count = 5
+Adata = babbd1b44cae3af06e0150bf0e3d898f6fe862b71ea9f6b727accfc18848fc79
+Payload = 00
+CT = 10f76ab445f4ec158ccc1f7c6fee3ede
+
+Count = 6
+Adata = 7fba0bfda3b03c736c121cf9a257db55060b621be5168619ec4182f13ef6a408
+Payload = 00
+CT = 59e02d6a6aa3fb2692b04e65a0e735da
+
+Count = 7
+Adata = 057354a29808f4ed77671ed3dc36f8b03f5cd952caac5cb80dc3b319f3333e29
+Payload = 00
+CT = 367a2ade4087964dcb0ca2984d44657e
+
+Count = 8
+Adata = ec08b618602d091e9304715cb552b357c16fd1d7f7f023a28d84a98ba21ca0ab
+Payload = 00
+CT = 47cb92cd40bc89328d4dd44fbd727032
+
+Count = 9
+Adata = 45622834ea658b09b17f32777d18b34b387ef957bd344468f68e7178417a7c24
+Payload = 00
+CT = f5185afb8359b5ef995483c0bc4192c3
+
+[Plen = 1]
+
+Key = 6ae7a8e907b8720f4b0d5507c1d0dc41
+Nonce = 7f18ad442e536a0159e7aa8c0f
+
+Count = 10
+Adata = 9c9b0f11e020c6512a63dfa1a5ec8df8bd8e2ad83cf87b80b38635621c5dc0d7
+Payload = 0e
+CT = 4c201784bdab19e255787fecd02000c49d
+
+Count = 11
+Adata = 73616a428f1a567b2e9af86b1fc8aec6d597b1b55f2aa2219b3b662fa6bd3407
+Payload = 30
+CT = 72f14519f06b63fac3d5b2d9bbfa0cb758
+
+Count = 12
+Adata = 6d62f4e15e8bcc9ba4993bc50a046737121016f0d15020b90068250551167b1c
+Payload = 34
+CT = 7676b581a28ca0a0ba5178eba7fe028da6
+
+Count = 13
+Adata = 8f0b8289a1834ecc2167b59ce3c9d3b58465c4cfaad50c728d04360cb7e5bc41
+Payload = ec
+CT = aed99b805c0a4785ff2913cab3e50f6205
+
+Count = 14
+Adata = 477b2a6932f838f0d1bc420c0ca306981d8e2dab945b6f259e15fe888667220a
+Payload = ec
+CT = aeb50e41cd7af84a8fdb6aee144e904616
+
+Count = 15
+Adata = d6518d409b1f05708d0b44f18fb5721f20f3220f8d2f2718650aa9932e4579e0
+Payload = d1
+CT = 9312639c863974f077fe8236c943b464c4
+
+Count = 16
+Adata = 865e7cde73b558e9bfd05356923f8a697970811fc484acad2d5b3528baf1f986
+Payload = 24
+CT = 66d7265cde50bc7a3989458437baf06db5
+
+Count = 17
+Adata = f0c3c67a935eace53ed32435655dd0974fafe283622e8294a15d70977398eae2
+Payload = c5
+CT = 87063144b25d2268063815d1b42ebbac34
+
+Count = 18
+Adata = 341e71b2ef26e9db03882e06d06cde2c0617326cd157d5984d22f6f3407a9c39
+Payload = 34
+CT = 767da45c10d0d6498716bcf3f13ca7e26c
+
+Count = 19
+Adata = 31fce6735ba9a3385df11c153179b8e4141a3c6b8ad6eceaa211f3f17bfd0474
+Payload = 7d
+CT = 3fcb0a6f562974cfb3fb7c8d5cafd50f2b
+
+[Plen = 2]
+
+Key = 3d746ae6cac5cefd01f021c0bbf4bc3c
+Nonce = 597b3614ff9cd567afd1aad4e5
+
+Count = 20
+Adata = 90446190e1ff5e48e8a09d692b217de3ad0ab4a670e7f1b437f9c07a902cad60
+Payload = 4360
+CT = e38fdb77c1f8bbac2903a2ec7bc0f9c5654d
+
+Count = 21
+Adata = 6bc3d30925c67371573271f1a4273ad76e91e07dfab65f7bce0b241b5e4cd00e
+Payload = 17c6
+CT = b72955210d62e1393e4fda647c2b2e59a47d
+
+Count = 22
+Adata = d1bb4cdfc3f2c16d92576068543692aa4b5a427d688387af0f1583e91a0e8b3c
+Payload = 6575
+CT = c59ad54fd88a47b9f6e39cb4606af86d13e8
+
+Count = 23
+Adata = ae6136df9ab43631ef143515dacedbe759b3459e951bfaf4712a21c86352f1c0
+Payload = b1dd
+CT = 11326de841af64b55bb7ebe3fd30ba493c7d
+
+Count = 24
+Adata = ffead34ac26e21158212d07c367c3a7cb6b795887ee2d3d8ae25c60556ea88d3
+Payload = cd16
+CT = 6df93a206339de534271f6469edfa5ed07d3
+
+Count = 25
+Adata = e768e7d867820d46c1cc62ee0e51d4dac6f5c4b5785b5ccfbf05236871bdce2a
+Payload = 12f5
+CT = b21aa8f65144f2ec5809e2ccb38c8760f7bc
+
+Count = 26
+Adata = 402e802885e4119df17fe85f141c3d1af7727fcdb00f8e2c34e42a436d04ac5b
+Payload = 39c0
+CT = 992f9af825957abe7d89e175b6e8c0b84b5f
+
+Count = 27
+Adata = 8a3a622b3d347c0c5210d484adf77fa33205ba02224ddceea71d89c9ad8429ae
+Payload = 912f
+CT = 31c025d6a12e91e84e355934547f6b5dceb8
+
+Count = 28
+Adata = 636114e5e5f83cec94e1df21d6babb9f6a14a532fcbfc3bcf649fbd79ac1abbb
+Payload = cb6d
+CT = 6b826db959a21e9e4ebf25ca4f98501b560d
+
+Count = 29
+Adata = 04e84f9156998c2eca9e96079a6001f2947dc49a081b3d75e47d75f71ed4a606
+Payload = 5bd2
+CT = fb3d2006ff22ff231a6646ae561923818a21
+
+[Plen = 3]
+
+Key = 3e4fa1c6f8b00f1296956735ee86e310
+Nonce = c6a170936568651020edfe15df
+
+Count = 30
+Adata = 00d57896da2435a4271afb9c98f61a650e63a4955357c47d073c5165dd4ea318
+Payload = 3a6734
+CT = 384be657bfc5f385b179be7333eb3f57df546b
+
+Count = 31
+Adata = 50f6e6dd57bd3a24f6bfdc8b1c7b5a36ebdd07fd6d194e6e82da47151d9c88fb
+Payload = 4ffad3
+CT = 4dd601b8ca97bda492546d82dccdebef441f8b
+
+Count = 32
+Adata = 70e132023acae1f88c7a237b68f5bdce56bcfc92be9f403d95d3bcc93b4477a9
+Payload = 8a594b
+CT = 887599fa0f3e397d9a580aa39c7028e1a508c9
+
+Count = 33
+Adata = 08d2b011f36e05dc728c1a8bda3d92c779a3d2f27c4b041810bd6222c852b14d
+Payload = 1f89df
+CT = 1da50d593460d335e2f7a6d40b8fe305b0f690
+
+Count = 34
+Adata = b207eb870aeeab27c6201ef04650bdc7ea30028a243420f7d198f1c9c9a43023
+Payload = 72e9c1
+CT = 70c513a2d49e1a113767ea4219107819d88b65
+
+Count = 35
+Adata = 74294088721fc9e7aabd5f1c66b5369b1e2d2cdb3e73abaa28ecd1c37d4ecea2
+Payload = 016083
+CT = 034c51dab1c819778be8453db163c882063af8
+
+Count = 36
+Adata = abbd347999a1c26368cdb17ab08bf57a8e942d1248296e952f5f42f2cabbf0e6
+Payload = 25f665
+CT = 27dab7537eb435df8d0e48c3f7e0bd1877c866
+
+Count = 37
+Adata = 231b33dc406c9210f59a5df1cfd595c803474db34b9b1848f0bcbe7b28df33c2
+Payload = 158606
+CT = 17aad4da549fc63d55b5910bbbf64435b95220
+
+Count = 38
+Adata = 69b851e63a78baef90637978e3dfe8c47be4b21e85bb89bf67051cf251004376
+Payload = b07452
+CT = b25880d5ee29fb2af47f8040fad585921057f5
+
+Count = 39
+Adata = 9b1f786c887d310b8efd3e8192fe504f603024c94aaa4ec9123736a40bf1605d
+Payload = 65187c
+CT = 6734aebc3ee43e10205f83143e0d3794a6734c
+
+[Plen = 4]
+
+Key = 7ccbb8557f6e08f436d0957d4bbe7fdf
+Nonce = bb8e2ef2ed9484f9021cda7073
+
+Count = 40
+Adata = fba1d18a74a3bb38671ab2842ffaa434cd572a0b45320e4145930b3008d8d350
+Payload = 4cabeb02
+CT = 32501f4235c4dd96e83d5ab4c3c31c523453c317
+
+Count = 41
+Adata = 78b3faecb2bdf6ed14ac2b86ded07aa791b60f5d54f9e24a965a8453f5131898
+Payload = 5ff73653
+CT = 210cc2137907d6a03e66403a7d9330d30d934a8d
+
+Count = 42
+Adata = db1239528eb464dd063e2a97ee83a87d6002ebb4fbafa77036f72c14f3fe959b
+Payload = 062fa9ca
+CT = 78d45d8a44f4bc78fbb969935076134437df82b4
+
+Count = 43
+Adata = 0071f1edb3a0ce57af3c88bb0ccf138f752697a77e55695838fb39de04c78dfb
+Payload = cad710b4
+CT = b42ce4f459692911fea2e0034d06c3b2e89af3d1
+
+Count = 44
+Adata = 7381471a62b1fa6f5061c4c37e9721f07099d007ffaf8639aa2ae3f82da5a559
+Payload = 7ac716b4
+CT = 043ce2f468484e22381923bfcaed16e0cb85b0f8
+
+Count = 45
+Adata = 19bea6d92d5892216e8e4a30dda802387800bb046a6717817fc46c7edafe17b0
+Payload = 362da02c
+CT = 48d6546cd081de39c247df309c4b56c31c03690d
+
+Count = 46
+Adata = 8503c8eb9cebc6110f259e35e03a0740267768130ce6f61b1c7d1d25be942274
+Payload = de52b209
+CT = a0a94649c6c6bd7b3a9d7c4dfa2738847ea3cb33
+
+Count = 47
+Adata = d2445db6efecaa3f426b06de8d496ceed54a1d0171384cc762e21b31e265c6d5
+Payload = 8fe8b383
+CT = f11347c32ca874d18d0b790856837555f4d4699a
+
+Count = 48
+Adata = 8cda7d1e135cf5fde1ec9473c4b42c1bbb445c27fd87b5f73df61ceb2d0b6f75
+Payload = d8d6b2c9
+CT = a62d4689932c2f8d78e322aaffc90846025190f1
+
+Count = 49
+Adata = b506a6ba900c1147c806775324b36eb376aa01d4c3eef6f5a4c25393ecbf2025
+Payload = 6a029e53
+CT = 14f96a13c346a4084918081b4bbe53b50d896788
+
+[Plen = 5]
+
+Key = 3725c7905bfaca415908c617b78f8dee
+Nonce = c98ec4473e051a4d4ac56fd082
+
+Count = 50
+Adata = 11bc87f1c2d2076ba47c5cb530dd6c2a224f7a0f7f554e23d7d29077c7787680
+Payload = f5499a7082
+CT = e378b776242066751af249d521c6eaebdff40b2642
+
+Count = 51
+Adata = d54219ef4fb851bebd1c546011ae3922b8337e19c28d4d58428efd66f80edcf0
+Payload = 513c46fcce
+CT = 470d6bfa68e7258df363e0e9af67a543c86db3c994
+
+Count = 52
+Adata = a92e88edd297da8c7089e21822b3e6cffd6837c78b975c8413fd6cca1b99bcb0
+Payload = 9d62e557c3
+CT = 8b53c8516572b7573e5b27a1d0e15cdb7b06c8857f
+
+Count = 53
+Adata = 77d9c306aa257379053cf1f2043c388a301dac2a9e2bb89eb8bab6eb3f150fe3
+Payload = 7a05db235f
+CT = 6c34f625f9de691a412ad54bbdb6ceac45ed45902b
+
+Count = 54
+Adata = 081568ae0b948aa647b9d4dda5d42641ad5de72aa9874d8d0717d872007720a8
+Payload = 30a22ca0fc
+CT = 269301a65a8a1bb8ba3d6763dcb1bdd3400e3459f7
+
+Count = 55
+Adata = 695ba4dea0f84baf190ec25a25fc00cb9898902d7a17e6f5ff2df323b974f7c4
+Payload = 35e25aa51f
+CT = 23d377a3b9403897d496cabcd5bd9de3282199a8ed
+
+Count = 56
+Adata = 1f3ba0336a634efdd11f8168c0fe25039f9403bfa70b3898f4dbe577dbd52957
+Payload = 8bde704c74
+CT = 9def5d4ad270a81f7cb0ab7ab2b495f51d66abeee5
+
+Count = 57
+Adata = 097b9ebff3ff93a143678d59721fdf359e95cbc82585ae47727a773317925d38
+Payload = 428542ecfb
+CT = 54b46fea5dce68e9b01a4462a2221bd2f3cadf64c0
+
+Count = 58
+Adata = 76d0341dd44c39e43a23dbcf4cb602f15d5fb9fee20c3d0d262d539c3fd1dfd5
+Payload = bd6866ded0
+CT = ab594bd876f2545964ef3978cad3387d61104bab84
+
+Count = 59
+Adata = 7e7c40ad64b511005b4546f9ec61ca24829390fbc4bd8507225bc348ae0807d7
+Payload = 5822755a3e
+CT = 4e13585c98002c41938a935d51905b2a708a2c5194
+
+[Plen = 6]
+
+Key = 80bead98a05d1bb173cd4fca463b8fa3
+Nonce = 8a14a6d255aa4032ebff37a3d7
+
+Count = 60
+Adata = bb4e706e73d21df66f64173859d47e247527cd9832e20dccff8548ed5f554108
+Payload = e479990bf082
+CT = 89c9246238878427f36b1f6c633e4542f32b50ca8edb
+
+Count = 61
+Adata = 9db2182c8a4f5471082bfa1a8496602cbcdef2790f7e8f71f791303bd48dcb05
+Payload = 017a7fd1aecb
+CT = 6ccac2b866ced76fe54da69af5edf8309c7f013bb07e
+
+Count = 62
+Adata = bf483f59fb73681f27b68168c998c90ea8ceea997654c6fab2bd737dcdc884f9
+Payload = 512fc5e4973a
+CT = 3c9f788d5f3f662f53d17f7cb6673415bb2324ca0666
+
+Count = 63
+Adata = b91e641d8210e1ef705fec2beb9f58a391c7d1a38935cd1d13f2c00363388ff5
+Payload = 06212e989616
+CT = 6b9193f15e1340c86156b1065b64af1e4d6c89b32603
+
+Count = 64
+Adata = 5cebf908e232d797fcce8453c4c3000868d4172622a4ee0d6a1bdd876a0b7c96
+Payload = c45629069ebc
+CT = a9e6946f56b9c07ef5349903b928e39e99e2e32625de
+
+Count = 65
+Adata = ab92cbc97f3aa6f9ea4dae5d8c3d9e91231f43ffff548da7b668e61c183ac2cf
+Payload = b949ced37725
+CT = d4f973babf205e40654ea16e83cc6faeaad668c416f3
+
+Count = 66
+Adata = 2c3d2f9c7e89c2b9e07317c4db6e9f00f5faadfad531c5bea79d164ac24d4543
+Payload = 517ff7b383b7
+CT = 3ccf4ada4bb23102a502dbba0c280e1d5fc627fe3a9e
+
+Count = 67
+Adata = d798e77ab0f3697768f23014fd31b9e8762ae65b6aa8a4bbc17ecb8cbe78461f
+Payload = b40d863ca4ff
+CT = d9bd3b556cfa6745fd4c954396e696697731e1f9a262
+
+Count = 68
+Adata = 45b44e3dec57e24d960fd1767797ffdbbab81e38bab37e6974df262c3d932327
+Payload = 56e00289a003
+CT = 3b50bfe06806bdf2b2dd47077c98234eae5d47c3b594
+
+Count = 69
+Adata = 645d27970ccce096d082fccfc1183955bad2611af0dd7c58c9d54430f28bd992
+Payload = aa22bb1de579
+CT = c79206742d7cea66649ad7e204a344d3234125aa324b
+
+[Plen = 7]
+
+Key = dc8ec91184ba18eae31ac2d3b252673f
+Nonce = 0da4c988f521f5648259f2bec2
+
+Count = 70
+Adata = 6d5573c9279897d7d1602d8a95c04bb5ca3fad2dbe89a024b3651eb227e73bb5
+Payload = 2a5775986551c8
+CT = 4f259f2a718faea852a7c4358dfa9f5467357638acac90
+
+Count = 71
+Adata = ff0ab5021ef466e2e898b0993d691145168be558682c74914c172f2b5e863754
+Payload = 8db3c1ca0580f9
+CT = e8c12b78115e9f8767c76e707d48a2144e090812e0192d
+
+Count = 72
+Adata = 2ee03cc28f79773af139c4ea55ec4daa48bb2885b8adcd5f066eceda5c4ec27b
+Payload = 3c69e2e83236b6
+CT = 591b085a26e8d05486df740083c959fb62ef7e2e221602
+
+Count = 73
+Adata = f041504d4c1b3d5be358bd6d350af42921205d29ab22b44ffe221358adef5bb4
+Payload = 777828ab5ccb68
+CT = 120ac21948150ebdc4d2b86b2528f75db4a7f5423f4395
+
+Count = 74
+Adata = 81ea116832d69542ac8d3d22c16c82eecf2ccac39264dd933c4f9c13c8d0f1d4
+Payload = af556fef3584e3
+CT = ca27855d215a85a7b06d1b710baa15daef19069ecf46f0
+
+Count = 75
+Adata = 8a0a120ed290a62456f002da1c250a0ddb1ebd57185a733d8fb562aad482679d
+Payload = 98f26635351f14
+CT = fd808c8721c1723811129add52e1406d50cbff4aa82802
+
+Count = 76
+Adata = 12b5a76faedf6f855e328c2cb87be8aea78c5e926b32d828e167b46205c86de5
+Payload = bd22c1ec05dc26
+CT = d8502b5e1102401563d3da8a6cabb7515f642e42fb4b2e
+
+Count = 77
+Adata = 8dc32f35ef4bcbfd040ad25dc36d0bd2486f93d0cabb7704cd1582dc99f65449
+Payload = 2a87c0d64806fe
+CT = 4ff52a645cd89817609a21f703253e5e56beef4ac71759
+
+Count = 78
+Adata = 83ced632359a11eb0c4c99baad84df5cac15bc5453b6593d9ffb4c5e8c84037f
+Payload = f05f39eb0a3d64
+CT = 952dd3591ee302236c72f98da859b54be7c598d85c37eb
+
+Count = 79
+Adata = 771a818a24e7da7b98f4b4291ef34bec7e1656b0c6c6e9474a989a04ea7de385
+Payload = 59dad755af92c2
+CT = 3ca83de7bb4ca464c8cd38cbcc46e7f09bf3e1c6590c71
+
+[Plen = 8]
+
+Key = 19f97ef5318b8005fc7133fa31dd1236
+Nonce = 01ce9814c6329dbee1d02b1321
+
+Count = 80
+Adata = 85853f120981f33cf1d50fde6b8bc865fe988a9f12579acdb336f9f992b08b89
+Payload = 6d972a673fbe1ca1
+CT = 2f12a7e7acecae5d2563309efc19368cdee8266538ca89d3
+
+Count = 81
+Adata = a4ec5aee89e2cce2115b6c1f42570bc5062887cad08192a682d0b4508fcd936a
+Payload = 68b1b6367a15fe49
+CT = 2a343bb6e9474cb528096a5fec5e5359c369833eac3b7efb
+
+Count = 82
+Adata = f5499a7082bf1e6e2923211271f5f7f6d7c7b26db7963071705a58ddc4dca0dd
+Payload = 707023615563a40e
+CT = 32f5aee1c63116f2754a65863efb60c98dbb536e2b5a69d8
+
+Count = 83
+Adata = 765f267befe6fcfaaa4b46eda32e7bfab87f12ceb07fa3b37be74965bb664a21
+Payload = b56454bc50df3e28
+CT = f7e1d93cc38d8cd40b6e9b7f3b3541ffee66a1f668f67d28
+
+Count = 84
+Adata = 9ce65598cd1f86afc9aaaf172809570cc306333c25523f863c6d0e0154c55e40
+Payload = 962f765da3565bde
+CT = d4aafbdd3004e9227018c9db8baf6be349d93d4eef7d7c9d
+
+Count = 85
+Adata = d0125e30c36232a8c07cee9abc53453b276849a7c04ade80ad586ed8cbcede51
+Payload = 4f18bcc8ee0bbb80
+CT = 0d9d31487d59097c501b28887f05fd66f050525943d101f8
+
+Count = 86
+Adata = 90dfd9e7bb7bf8fb70c22a879ffa760d14cda7b79ce4968f69b8a7f2b7a59642
+Payload = ca293c9e1780b401
+CT = 88acb11e84d206fdda53dde2e1aef96b3658a7635ee54188
+
+Count = 87
+Adata = 58f518710e6b282482a7f1950fa353b13bdda10c9aaea6d5f0d7ea0a965d31e8
+Payload = b9df9fb4a6b299b4
+CT = fb5a123435e02b48b62a5ec234f1efd1b52c8fad1cf09890
+
+Count = 88
+Adata = df052e95aea3769a433ce4e4e800b8418649bbe8c6297eb07545e6802de7e807
+Payload = fb2441d1594a488a
+CT = b9a1cc51ca18fa76bc051ede6f37cf67543a7252d7d9b203
+
+Count = 89
+Adata = 0875020959ed969cfb38636d1d5aabce9658b00171a7614ea9e5395331c7659c
+Payload = 451101250ec6f266
+CT = 07948ca59d94409a5be4be6bc6b18104fac167b6e3fc15f7
+
+[Plen = 9]
+
+Key = c17944bfaeeb808eed66ae7242ab545f
+Nonce = 910b3db64df3728ca98219e01b
+
+Count = 90
+Adata = edf64f98b3ab593cbcf68ab37a8c9472e49cb849d4a744deae925a5a43faf262
+Payload = 7caae2640e734539d3
+CT = 0dae8b3ccf0b439f6ff8ee4a233dfb7753f6bfe321b3e26959
+
+Count = 91
+Adata = 29ac8fd6a20a5df4ec79660c44d373da42de7d7c5fc35982b6c29b480723b484
+Payload = e574b3a37af3bf2251
+CT = 9470dafbbb8bb984ed63b1477d9506a51ae23abbac179d8b02
+
+Count = 92
+Adata = 9ae5a04baa9d02c8854e609899c6240851cbc83f81f752bc04c71affa4eed385
+Payload = 2e3cf0af8c96c7b227
+CT = 5f3899f74deec1149bdb0986198bce2e486581c041029a81d9
+
+Count = 93
+Adata = cc8e789462879e348d20be4e1161d7b7fc6f8371d8f8cb2d25d13f0e07de47b0
+Payload = 16f22817c5b79f9fa6
+CT = 67f6414f04cf99391a0cbb2df2079a6eb964c3469f4f326122
+
+Count = 94
+Adata = c63061f2800228269015693336f78bb535ae8b88869e4ccf4ead2f3b0ea4e48a
+Payload = 64fe8076d4e8538e18
+CT = 15fae92e15905528a4a40ca7622acf7266b7c24cf0c3202e4c
+
+Count = 95
+Adata = 71c14a7031033db15bfe23b75fed9daf8886dd11392a0b787660e7b1a581af11
+Payload = 4814aaac48bdf43c92
+CT = 3910c3f489c5f29a2e7de20e98586cd5d684bf015a7abbe82c
+
+Count = 96
+Adata = 8f4947f8588ed866ed7477d7f1a28046430c6470806a50e3c9e80958c61f1b42
+Payload = 392a692b57a8a97f60
+CT = 482e007396d0afd9dc8d503f5d87818f7c0e173b857cef4288
+
+Count = 97
+Adata = 9d44f6df58c2b43db67e3daa95b176c81daff32e996d670e86405e15eae72e93
+Payload = cba1e00e345b0cb7eb
+CT = baa58956f5230a1157c85e2283d9e80700268a6459d1451d00
+
+Count = 98
+Adata = b6ada12f7a28211e9d2c07cbb3d39fa77aadc077b34c46f93006c1ca2ff66f87
+Payload = 22f5b6752582919dc1
+CT = 53f1df2de4fa973b7d1056aea3d3e4f7a5219170aaa52465e1
+
+Count = 99
+Adata = d6411fd5b25433f67ca75e4560ceb809d3721266beec358dde126b2f6a514137
+Payload = 6e1b55d6f5288c5451
+CT = 1f1f3c8e34508af2edfbfcf8200a8a3f8d995f50284a7280c8
+
+[Plen = 10]
+
+Key = 0fb9df6f638847f5de371f003dd938f4
+Nonce = c9ddf61c052f3502ad6b229819
+
+Count = 100
+Adata = 4f9938d5bc3dcbe47f6b256d5e99723d0891e50c6175aba41b011e4686113c49
+Payload = e10cc36bc1c5d3c646ab
+CT = 7f797367de50be6dc04e4cf0d8c24189affd35060cb7ca3dd136
+
+Count = 101
+Adata = e013a2edd5b86bab8df5c9940d0a0c864478c1ad42668304a643141855adac10
+Payload = 15841284c959febe63f9
+CT = 8bf1a288d6cc9315e51c4148ef85caab151488c1a6b3df540d21
+
+Count = 102
+Adata = 147d77d509f642189594df17574a0ce62b52a838feb62310e11533995ba4c851
+Payload = a8b4e5829069c335d1d8
+CT = 36c1558e8ffcae9e573ddaaa1e7c22b3efa8362abb3d31ee8884
+
+Count = 103
+Adata = 0bb09658e23fe8a08c01a6994ef36cb8dcc9a806297a09c67efe3558ca56bb5d
+Payload = 1bb2da0f1ae7e044deb0
+CT = 85c76a0305728def5855317b141383ad38dd78569d5f846f2520
+
+Count = 104
+Adata = 34eb2e6149bad764837f6f25ddd96865e5b05d5cbf233c4f6cc2aa654dfea3b7
+Payload = 63af538196add9b3fad2
+CT = fddae38d8938b4187c374e6432971aecf6bf7cf5244d21f7f173
+
+Count = 105
+Adata = b69f26fda6d1cd92897e03758cae020c4e1beb019ce5ad987f872940780a9468
+Payload = 6ef2df5a1688ae795537
+CT = f0876f56091dc3d2d3d2e4d0ffc0f0add38a80c7ffe6b4701e54
+
+Count = 106
+Adata = a7375ba32251af0138bd9fd8fcd56a7c43ab2ca9a7fc0117d25f6d4ef9c2fcbc
+Payload = 3f46c83021069ac488a1
+CT = a133783c3e93f76f0e4447fdd0b2f29f39094ba5a7375e278349
+
+Count = 107
+Adata = f9b91f7298b4e43843fc739a2f41c57c3f2cf36378fe4c34b574a43f9cedee7b
+Payload = 86c10a6dfdd6a06ef638
+CT = 18b4ba61e243cdc570dd57500f913ee3f46801e1bba9d4db7ecf
+
+Count = 108
+Adata = 9d35876d9449a1642b5062dfbfc7a26a7ac080b7198f4aeff2c79e463565cfd2
+Payload = 196c80d02b663bdd89fd
+CT = 871930dc34f356760f1856a6b87519b4807a2114ced587f72189
+
+Count = 109
+Adata = f2d5e927eb507f889efc6f21d783851f638f978c74960cc347f89f2703476114
+Payload = bd27ae3ade0781a33d5f
+CT = 23521e36c192ec08bbba2101012808adefe9b8166e04685bd537
+
+[Plen = 11]
+
+Key = 006ff7d3153caf906ec7929f5aef9276
+Nonce = 57db1541a185bd9cdc34d62025
+
+Count = 110
+Adata = 7d9681cac38e778fba11f4464f69ed9ebfea31b7ffcaf2925b3381c65d975974
+Payload = 31be1b241cae79c54c2446
+CT = 9dd8a4244fbdb30b624578a625c43233476bbb959acd9edebe2883
+
+Count = 111
+Adata = 1b0012c468009bd2851653013782c7b71ef43c393afd4dc0aec4d6d0c3fa11c5
+Payload = 8802831e22092b30110cf7
+CT = 24643c1e711ae1fe3f6dc9d477ca066ec2befa854a1faef018ea8b
+
+Count = 112
+Adata = 48b216375c00ca7e9c4048834b37944d2543e24fa091fb3c7290e11c53a6b6a0
+Payload = 3b3f782d637319d7fd161d
+CT = 9759c72d3060d319d37723eb6be9a78dfbd9e16181679b782969ad
+
+Count = 113
+Adata = f3e06a45fcf1f6abeb00727bf2c9bcea00ce621d38f7b7eba17c27e51f04c793
+Payload = e98f5e5a20d02c80372d6d
+CT = 45e9e15a73c3e64e194c533d9574d95b821a5170e9b61d8e6b2ff3
+
+Count = 114
+Adata = b36e27729f9a139d8ec4f61215b7bf1149cbb4d93a5c14bebd7cfb7c6fe585cb
+Payload = ceeed4fde3406ec40f7ac6
+CT = 62886bfdb053a40a211bf8aa193d257907be1330abaa56bc4f431a
+
+Count = 115
+Adata = 8886ed7fa414d74aef704a9751b197cbab02c41c6aedcaf65cda019dc2d2d815
+Payload = b38f03449883773135c0cd
+CT = 1fe9bc44cb90bdff1ba1f31d92029a6428748664b5c815f15ca1b7
+
+Count = 116
+Adata = 816d81af167d2294497d9b06a39fdf75e37cbacf4d10c3a444068c891b361bba
+Payload = 8efb141db7b77c521003cf
+CT = 229dab1de4a4b69c3e62f1386e4ad7c72ce0081a85d4cfd34254c7
+
+Count = 117
+Adata = f427c47e10c45bb3c7e75e9e604503b3560427691470358efdef48ddaf3794d2
+Payload = 6dc38e37d1379732df4dd5
+CT = c1a5313782245dfcf12ceb98eeb05bc376a1042735569d5b63f8fa
+
+Count = 118
+Adata = f3df712b5e8dd8e4aa8b7c5f41e93bd11b0df66a3456a01f3d0094ad91482cdb
+Payload = e0e358aff203369dd5960c
+CT = 4c85e7afa110fc53fbf732065b03ebeb68a9153cb4ed152ce0d64c
+
+Count = 119
+Adata = 264f2c7b095a296eb8ff6b5151ab3d9497ea8dc0002a9e5b09c2fd0ccd32b6ff
+Payload = 57b940550a383b40f3c308
+CT = fbdfff55592bf18edda236fcd16c8360a408e2787f930ed275bf3f
+
+[Plen = 12]
+
+Key = 026331e98aba9e8c23a9e8a91d0b0c97
+Nonce = bccfe69bba168b81cbdf7d018a
+
+Count = 120
+Adata = 26e011143a686a7224ddb8c5b1e5d31713fa22c386785e2c34f498ae56d07ed5
+Payload = a82200ef3a08c390dec5cbf9
+CT = adf4fc6f9be113066c09248fcb56a9c1a1c3bb16fbb9fbaedacdb12b
+
+Count = 121
+Adata = 97a720ae4720546e31263a1a538ce1d35c198c23bd4362e0023a67536328ab9a
+Payload = 7fc58d1bb450b396b9161f53
+CT = 7a13719b15b963000bdaf025002120b619a391fbd23402e5edd4949e
+
+Count = 122
+Adata = aff6c8cefda055c67262e9c68825d1ad2a7488e5b09640a111fabf6254d96cc0
+Payload = e9ea182d7f895f312b9738db
+CT = ec3ce4adde608fa7995bd7ad48b6e9a8de0099a28cebbf5c2bad42ff
+
+Count = 123
+Adata = 35a3963b43f47855ef3df12af5de3626e0c5c8d9cd2a534c737cd695609b05a9
+Payload = cfbc8bcbb5e5bb744bb1f340
+CT = ca6a774b140c6be2f97d1c36df80fd62e751757bb0a32a987980afe6
+
+Count = 124
+Adata = 46a2e6bd3fd5336abf02eace3cd1e1f6dde505ab976a9fa596edd6fbde7175de
+Payload = a334f8f41897cbcaeb5cffdf
+CT = a6e20474b97e1b5c599010a93b211350c70adf9bab5c01081bdc6a99
+
+Count = 125
+Adata = d110651c00ac5540f9d1ed9eb175e06b97163fc36d43f048565e5d0c30a069b1
+Payload = 3f781267290e8e73c6355e75
+CT = 3aaeeee788e75ee574f9b103d7f65690d9a2fb6759d658c9bdfdfc37
+
+Count = 126
+Adata = 978644dc4e36f1d98a2a63e19bbf8af11785d09fce58a95c00cc6bf6cecf6161
+Payload = 3dc39dbb91efe8b16396d488
+CT = 3815613b30063827d15a3bfe0d5df472f49e7f713cd1373293810906
+
+Count = 127
+Adata = 5ae7528c5e965880b1533cbd78c1e81a8187379327a2fc3f76ff45829049e183
+Payload = 6caa8c0764512baa39dabac0
+CT = 697c7087c5b8fb3c8b1655b64bfca9ef00b0f2bbb03c1a3f7a0862e7
+
+Count = 128
+Adata = afe754828be6e3731d3eee54b021b4fa182247bd958e9074fb0094a11030f5e8
+Payload = b19bc92e2305883580dd7742
+CT = b44d35ae82ec58a332119834a03be1d1d262b03c0ab425d533fe4ec1
+
+Count = 129
+Adata = 0650859c635654ca4d815963c0a99f9d2f47456ad37f739c425e924d4360bd7e
+Payload = dab87e79544df1cc98096b91
+CT = df6e82f9f5a4215a2ac584e7da61ca8461925996880e2874393232d6
+
+[Plen = 13]
+
+Key = d32088d50df9aba14d9022c870a0cb85
+Nonce = e16c69861efc206e85aab1255e
+
+Count = 130
+Adata = 0eff7d7bcceb873c3203a8df74f4e91b04bd607ec11202f96cfeb99f5bcdb7aa
+Payload = 4b10788c1a03bca656f04f1f98
+CT = 89f15b1cb665a8851da03b874ca6f73242f2f227350c0277e4e72cdaa6
+
+Count = 131
+Adata = a533b3279db530eaed425842b0d3528f5c5e4c16acfa0f49de43d6491f0060a9
+Payload = de6ea86d3641d916c4394fdd31
+CT = 1c8f8bfd9a27cd358f693b45e594271cc06f81d510075728cfeb89222c
+
+Count = 132
+Adata = 8e6c1cde142e18635c1b4f0cb54d3cf817f22ad7c25bf6a022501682f6a7da1c
+Payload = 6f3b32adc8c0314872947f3d31
+CT = adda113d64a6256b39c40ba5e5ab1aefed75400a41447b2bd8f0605542
+
+Count = 133
+Adata = 248a4389da2d51b87907dc11c46253515503ba80de5d06c9b505cb89906614a6
+Payload = 0cc992a8c736b44fedb4ad498f
+CT = ce28b1386b50a06ca6e4d9d15b46b3a6463876f1a43a287748f339e913
+
+Count = 134
+Adata = 2e2c8244a2cbf53816b59e413207fb75f9c5ce1af06e67d182d3250ea3283bcb
+Payload = 98104fd3f3413ad1f57ef4912c
+CT = 5af16c435f272ef2be2e8009f8f625786bdc58af24b17c1ba34fa87baa
+
+Count = 135
+Adata = 4ada86d88d5f49dfcde13fc30ba9a1af58d5254b47fb1885a20fad915c87952e
+Payload = 3b4fec79d52d8b2a533917b75f
+CT = f9aecfe9794b9f091869632f8bd4a918290cf97208232c76908514b07a
+
+Count = 136
+Adata = 9e3b23232e5a9e69747f8bcb148cd6d282fd9b7ecd6d97e8bb5cdc261b2fc86f
+Payload = f10c19c76ae7ed55e1651155df
+CT = 33ed3a57c681f976aa3565cd0b01d6306bb91c315bb4a23fe23d496d09
+
+Count = 137
+Adata = ccea2c815ea4efadc3007f511d633e98f9fa38b0e0fb572b282ed6a610adf7a9
+Payload = fa34af376868d9a49aa200f59a
+CT = 38d58ca7c40ecd87d1f2746d4e620d9d3004587c5d510e2a857fc857ea
+
+Count = 138
+Adata = f7277fb296e2c0d2c9ceb7013ea8b59fe37e26b3b42a0b8cd01aaaa8d35283d4
+Payload = abe2fd996bb6804ed3286c057d
+CT = 6903de09c7d0946d9878189da982d2438a5138977bde5f514e2335c28c
+
+Count = 139
+Adata = 14dd1810df3eeee78ed3836c77edf510d91ea28f119bf57111e580d70da94b74
+Payload = 395ea6979b77dabd2042aee4ff
+CT = fbbf85073711ce9e6b12da7c2b78100a05448fa6e74bd3ed16c3bd364e
+
+[Plen = 14]
+
+Key = 7301c907b9d2aaac355c5416ff25c59b
+Nonce = 7304b65b6dab466273862c88b9
+
+Count = 140
+Adata = 2c5d114eff62c527cc2e03c33c595a80fe609bfc0fe13ce3380efe05d85cceac
+Payload = 484300aa3a506afcd313b49ead8d
+CT = 928ca58b0d373dc50c52afac787ce8eeb5d5b493661259a9d91ea31a5f7e
+
+Count = 141
+Adata = d9ebc1cbfab9034317132a72e0f11c341331146a59e7a2f26bf4f3d778da52c4
+Payload = 8b318f75ed79a7978adc17c4d2d4
+CT = 51fe2a54da1ef0ae559d0cf60725552193439abfedda67d765d030cef30b
+
+Count = 142
+Adata = 9aea86b9fbd9bd4504ee2e25054942b33d3cdbd84215db7ea337e548cb706780
+Payload = 0256b0d154c768c85070da6ea8c7
+CT = d89915f063a03ff18f31c15c7d3615013c2bc9338868fad0d2fac11df019
+
+Count = 143
+Adata = 08afe10bbfbd65b948a6561bbeaf3ab46a8e3d0a861f1cfc46584156197f30a3
+Payload = 89ed296a3ac03fbfb71422b92117
+CT = 53228c4b0da768866855398bf4e66c3c4cb8c50891d6523245e4c619aa99
+
+Count = 144
+Adata = 7d653792bb8683e07c7d2c800db6f7f08343c85af2377115df4fc86ff7d8fcaa
+Payload = 414b6acb1db479028f5cc8800f2b
+CT = 9b84cfea2ad32e3b501dd3b2dada792d2cb93e45811a4c897ae9d907c9cf
+
+Count = 145
+Adata = 4d73c1484f9429eb15742f29ab05cbab6552abf40e127b93427d649d195ed25a
+Payload = 163f67b3766c3c650ce26c5bd8b5
+CT = ccf0c292410b6b5cd3a377690d441983a87812eaa7b66c5a0e54a01cb882
+
+Count = 146
+Adata = 2fba7a881f019a8745691343d79ef3656e25bb37b93fb5ab7311889f92010a5f
+Payload = 9c5b4aa703c27d16d82013853e16
+CT = 4694ef8634a52a2f076108b7ebe7b0afabd23b33765a63753cad66b0e6db
+
+Count = 147
+Adata = a640343fd4a866aec07b667d25176e11a32fb4d8bfc08fde2c46dc9b492fa010
+Payload = 99eb86b3202c7ce68a2339065f47
+CT = 43242392174b2bdf556222348ab639b8d0f97540373a7b9061aa3b2f7044
+
+Count = 148
+Adata = 9efd58d3ef5f74f663b2b5ca5e96c5a2fe85ca5eac1495d7f1751c7d8b412b3e
+Payload = 3f5c1d038161e65c9ed955c961af
+CT = e593b822b606b16541984efbb45e312c803e29f7be7c5eb236401037a320
+
+Count = 149
+Adata = a7d7ba684c0903323f7efc83dc32815195df325394162fb5a18f201047be7999
+Payload = be8dea2b4e602a787ecd28f2f7f0
+CT = 64424f0a79077d41a18c33c02201fd929c717d75388387dc25bfcf90b707
+
+[Plen = 15]
+
+Key = 38be46d271bf868c198052391f8a2147
+Nonce = 6758f67db9bfea5f0e0972e08b
+
+Count = 150
+Adata = c6de3be97f11d0e2ab85c9353b783f25b37366a78a2012cecf5b7a87138b3c86
+Payload = 61bd1385be92097e866550a55278f0
+CT = 7c9fa8d99b38f825315ece6a2613f55e902f296dcce870263ae50cda4fadae
+
+Count = 151
+Adata = 7c8cf9c650511f33af82e807e60336ec086bd2d9400a5f35652b8c3fcf968ead
+Payload = 7e5e51301fa44a21f2734731ee3710
+CT = 637cea6c3a0ebb7a4548d9fe9a5c15cae8a9e4b606f5fbeac2b829b42a150a
+
+Count = 152
+Adata = 5f8b1400920891e8057639618183c9c847821c1aae79f2a90d75f114db21e975
+Payload = 9cea3b061e5c402d48497ea4948d75
+CT = 81c8805a3bf6b176ff72e06be0e670f5419c6085e5434f056162cf80f6729d
+
+Count = 153
+Adata = 238d3c9d9de32f2040b1dd0dd040b921e456c3653263f4020cffdc552b948a46
+Payload = 20660408d6890aed84aa65dfe23032
+CT = 3d44bf54f323fbb63391fb10965b377fedcc743389a9d48e6b871dc0dd63b2
+
+Count = 154
+Adata = 3b5d61ca21953fdd22280747dd4ae908a511750127875da84dfe7d0063a318c9
+Payload = 9ab83c81f2d2c896c6596660c3974d
+CT = 879a87ddd77839cd7162f8afb7fc488137e0a856d3d911af9f420b68d8110d
+
+Count = 155
+Adata = 78c1751e86144a78285a30dc04f51742bd47e3d36b607bab48d91cddabfff4b7
+Payload = c1ec469aa9c73b677af225a9f5f6f8
+CT = dccefdc68c6dca3ccdc9bb66819dfd5644448fa8445b6cd185bdf9b3718033
+
+Count = 156
+Adata = add33e9a1d7e91e2c160c1123537e3f7e3535881cb4aac1a80ecbe367379212c
+Payload = 9df1d6b6debffdd316aeb27143508e
+CT = 80d36deafb150c88a1952cbe373b8bbd38e4dc44f768cef0c51344e3a7f7b8
+
+Count = 157
+Adata = df7736560b1a13aa8e536500ea6cdb9a6757309aadf25a6a9189055a309c3f8b
+Payload = 19eef017100dc82f26ed0815c55c12
+CT = 04cc4b4b35a7397491d696dab137172e7f2ec918099898b843a34c385f2a57
+
+Count = 158
+Adata = b40c8d22069b8a65cddb51c1ea3571160cacb19fd371552436b19c7122b28d08
+Payload = 2af5db43f2a5fe8b494b40661510bb
+CT = 37d7601fd70f0fd0fe70dea9617bbe94c2709685b0827cc42f3a25b579db28
+
+Count = 159
+Adata = 9de5559ea8ccc70f4375a436ce0b72551a75960ad5ed6a1949ee8f6c47548558
+Payload = 5de41a8ca8ed8011304fa9e9f36498
+CT = 40c6a1d08d47714a87743726870f9d63bf4b40ce7e672587816fdcda16efbe
+
+[Plen = 16]
+
+Key = 70010ed90e6186ecad41f0d3c7c42ff8
+Nonce = a5f4f4986e98472965f5abcc4b
+
+Count = 160
+Adata = 3fec0e5cc24d67139437cbc8112414fc8daccd1a94b49a4c76e2d39303547317
+Payload = be322f58efa7f8c68a635e0b9cce77f2
+CT = 8e4425ae573974f0f0693a188b525812eef08e3fb15f4227e0d989a4d587a8cf
+
+Count = 161
+Adata = b6fecd1edeb55a9a4148b1aefb716a1e162779a5ab2a682e4adce4479c527bd2
+Payload = 0e6118d0409751d36cb642504678535e
+CT = 3e171226f809dde516bc264351e47cbedf7f186e8d3d7c21c549c41ebcc7f505
+
+Count = 162
+Adata = 5c3933c30bf9d4841eff4000aaa1cb4d39cdf8ef1240e2aabbf9da95bdee5270
+Payload = 5c8a5fb36f860d00c21ae9e3f24097c4
+CT = 6cfc5545d7188136b8108df0e5dcb824810a68be1814f53c09aca4066527fef8
+
+Count = 163
+Adata = 7ca7ef30d3ac08aa51a9e5d3d84e8b6bb7fdde921e72b98ad6a93ebf2efc6b04
+Payload = ebd1cb4b35257790c9806be476bd25a3
+CT = dba7c1bd8dbbfba6b38a0ff761210a43cc30245a6e64625c4f6531d7497fb144
+
+Count = 164
+Adata = 90f1416768fca7dd48d01230dabf95f2f1a0c044bf2d755448aaf72316c8448c
+Payload = 842b7e5f22d921b2b8ab3131684b7eff
+CT = b45d74a99a47ad84c2a155227fd7511f10d85725dacc274034669acf7f34fed7
+
+Count = 165
+Adata = adc5c36849283d57acb2bcbc0e12465cb7c1830cb4e314b9ce6e25acbd8d460c
+Payload = f0c2cc5a1b4c4cbe839338fa0d7a3435
+CT = c0b4c6aca3d2c088f9995ce91ae61bd5f731b465eb59c4989e42020d86102a59
+
+Count = 166
+Adata = 80a7a483d1dbcdf00ed02a700e93d8b87fa6ac5c7368d1e81bd1b32cd1621cd7
+Payload = 2c1a5f906f2ae0373cc25e3519df2ba4
+CT = 1c6c5566d7b46c0146c83a260e43044484bcd2775448447ed801b3b0ff071c19
+
+Count = 167
+Adata = 13c02992992d2708250184a579c43bc29a3a8cf1e02dade4496cbd8b1214f97d
+Payload = 1da5190517546f1ad852f64263e1f679
+CT = 2dd313f3afcae32ca2589251747dd99901d1919f1451ad16f115cde863f15303
+
+Count = 168
+Adata = f6f18dfe093e4c0c3fbfa8a5b1f4a703c08addc2ab959741611a594b93d08bf7
+Payload = 13ccb08a580efea53dfba6a59626bbe2
+CT = 23baba7ce090729347f1c2b681ba9402ccae4f6ec07bf73d6f086cf09e2e14ed
+
+Count = 169
+Adata = 63708e12dfa14f192ec5ee5856dc3cf2403817d9628c31899b4613f65e1e61c2
+Payload = e0b5fbc6c2269d445a60273bf844892b
+CT = d0c3f1307ab81172206a4328efd8a6cb2bad8bf67d32a855c3940ac908397a5f
+
+[Plen = 17]
+
+Key = 79eae5baddc5887bdf3031fd1d65085b
+Nonce = 9da59614535d1fad35f2ece00f
+
+Count = 170
+Adata = 46603500af9e4e7a2f9545411a58b21a6efd21f2b5f315d02d964c09270145b3
+Payload = 001343e6191f5f1738e7d19d4eec2b9592
+CT = 2162e27bfbf1d00f2404754a254665fd9270f0edb415993588b2535e2e0e4fd086
+
+Count = 171
+Adata = 278afebc604bb7d87bed3574a2c5053de17eb8ca7e18ddc7892f2c54b38104a8
+Payload = ba47d5bfb36f6150a100e36caa116405c4
+CT = 9b3674225181ee48bde347bbc1bb2a6dc4778e3c4a11f3f9dc42554d45796379ef
+
+Count = 172
+Adata = 3239b2ce4efe4f6a6255dc53347400a6446ed3280c65422386fab471ef09eed6
+Payload = 96eccb7f9b0e16c6883de0a381e4767f5a
+CT = b79d6ae279e099de94de4474ea4e38175aab5540cc01d867f641c9b196fa159291
+
+Count = 173
+Adata = e2a5488d5f7930ea4ce399f2a6c0810265f7c0dc52fe824d19a0fa0d9ffd55e6
+Payload = d68f5990da1a2fe39ed81af145ab834fa4
+CT = f7fef80d38f4a0fb823bbe262e01cd27a46366fbe302e142dcf6aa16337d98550f
+
+Count = 174
+Adata = 0071f1edb3a0ce57af3c88bb0ccf138f752697a77e55695838fb39de04c78dfb
+Payload = cdd4d8b3d8f6e4742793b456cefc9e686d
+CT = eca5792e3a186b6c3b701081a556d0006df88c07797267bf5a49b3d0f601a225ce
+
+Count = 175
+Adata = f5d6989587e463969d97aadabea9538511f8d109cc2d3cecf09ba7cc346aaea0
+Payload = e7d7fc60ae852b68102e01b506f9dab986
+CT = c6a65dfd4c6ba4700ccda5626d5394d1865c9fbf69d81cef238ac513562d4a0dd5
+
+Count = 176
+Adata = e0b5fbc6c2269d445a60273bf844892b26fed03b82869edacd6dd7a63fd69e8d
+Payload = be9f51abfbe2da5a56db0f9a31b67c9f83
+CT = 9feef036190c55424a38ab4d5a1c32f783e2c748c8c9e3190de095de8eb0650203
+
+Count = 177
+Adata = e6bd0010c98e60b9af7cf905c58e0653bc425e2ccc809bd4f9cd7b1f95c18786
+Payload = 81b9c73029cea1936ef8755c80ba8d4093
+CT = a0c866adcb202e8b721bd18beb10c3289305cf563c5b4ba4ebd5bf107f2ad3555b
+
+Count = 178
+Adata = b1688cbc058816974694cd26c0f28ba9418e9912867fc8c5f4e7bd9c891a8d2e
+Payload = 618dc26853ee339689467ffbc2a77be69e
+CT = 40fc63f5b100bc8e95a5db2ca90d358e9e60dbbd8f46343c8442b03a472da4e23f
+
+Count = 179
+Adata = 469e004fee9878ed40621b41d04ec34af175f213d64d16e2f77d0bb2b6efe2e3
+Payload = 4f18bcc8ee0bbb80de30a9e08629323116
+CT = 6e691d550ce53498c2d30d37ed837c591643352e46995e8c1aee43dbdb26b46c30
+
+[Plen = 18]
+
+Key = c14eda0f958465246fe6ab541e5dfd75
+Nonce = 32b63ca7e269223f80a56baaaa
+
+Count = 180
+Adata = 733f8e7670de3446016916510dfe722ce671570121d91331a64feb3d03f210e6
+Payload = 617868ae91f705c6b583b5fd7e1e4086a1bb
+CT = b2dc1e548b3d3f225a34082f4391980a0788b4cc36852fd64a423fb8e872252b248e
+
+Count = 181
+Adata = b6ec659856866959ef6fd4e71ba930f0e3e5fd49d7465fd65f6813ab4ca1a770
+Payload = b8b342c49c28bffc2a1c457db0b537ad46bb
+CT = 6b17343e86e28518c5abf8af8d3aef21e08895a66eb5b902bb23a1a8584249409fda
+
+Count = 182
+Adata = 89eb3636fff80230352a3582be5698e3401c9e0579d48f2680c6e5e24d99f74b
+Payload = 37d694ba94d0af8df662134f20d142903839
+CT = e472e2408e1a956919d5ae9d1d5e9a1c9e0a7fa792fb7246218f7d56d5fa4a5476bd
+
+Count = 183
+Adata = 03434f3709e19a1e37edfcaabc215116763b71ab1c5e053dbdb599f86959f25d
+Payload = 90e4c0550cb7b279ef61f9140b7d94b8003d
+CT = 4340b6af167d889d00d644c636f24c34a60ea83dc3f0012ae6da32a15fd1684835ef
+
+Count = 184
+Adata = 0e2ddb65fcc72094ac388d53a1055c7e902285c4c3c33c13bb6fbb4f1956414a
+Payload = 69b851e63a78baef90637978e3dfe8c47be4
+CT = ba1c271c20b2800b7fd4c4aade503048ddd7f09d38d3dba01995e36bd685c8ea3371
+
+Count = 185
+Adata = a42b2538ee2fb5f6a85d4d00524b01ad3331f61c404069243f35f28e2c2d0a82
+Payload = b7dbf8382115199dd2a2d87938c6ae6c4241
+CT = 647f8ec23bdf23793d1565ab054976e0e472c89becf8d2bb935cb17f44b950df3ef5
+
+Count = 186
+Adata = 09bc5c426dc1faa4d71f50908bd6f297ec8e754d4d20def005585b4bc1fa31da
+Payload = d53698d719c51bf9eae346269c6a1da07162
+CT = 0692ee2d030f211d0554fbf4a1e5c52cd75196e28badf0202097e80561451796194d
+
+Count = 187
+Adata = 2ac87e59c2c86532cf165af3e8ff4871d730f5e742cccca38bbcdffff4472c93
+Payload = cfdb7363985aa01af6f8e8237dbfb7871eb3
+CT = 1c7f059982909afe194f55f140306f0bb880710d4d7f66660891ac655d6eca4a3f3e
+
+Count = 188
+Adata = 05d2fbc3d0ec81f52f31cb0c4bf960c2076867f6d9f0174ed9176e20177b2693
+Payload = 56fdf10dc0c1dfd10965b83938e557459c61
+CT = 855987f7da0be535e6d205eb056a8fc93a52f90ab18925fea6964490f364a975a473
+
+Count = 189
+Adata = c2c3902cfe8622254b3787cc13e79c5a3c388c2357c29f1c1ab5539a10bfae5c
+Payload = e7c9812eda2ed7dcfc80fc5fe0d43e1e5982
+CT = 346df7d4c0e4ed381337418ddd5be692ffb168a00e5e7a39b371024927d3ac98fe43
+
+[Plen = 19]
+
+Key = c5e7147f56ba4530b8799ababeb82772
+Nonce = bdd38e173fb20b981659c597d6
+
+Count = 190
+Adata = 3a069a2bfda44abbb0a82a97e5e9047258c803da2c66190d77149e0f010b3af9
+Payload = 2f3bf0b566440912a1e47a0c07f1cfd39cb440
+CT = bd6265dcba9e14c59e515e395dc60bd053345fa6d7568c738e3a7fdf142d8f2d1562c0
+
+Count = 191
+Adata = 7709132415c94960025cc39c950ead208703a9d5a71e224fd022dc0a1817d0f4
+Payload = 7c880d787726c4ddeb2304b5d161b4a257298e
+CT = eed19811abfcd90ad49620808b5670a198a991f22337efa5cb7db7240e7518b67ffbb1
+
+Count = 192
+Adata = aad77595f87a27f2c7995fc7149317f4cbebcece8336db2068380070784a4283
+Payload = 08c43bbfa706512aa39e2bfa5c365aca11e22e
+CT = 9a9daed67bdc4cfd9c2b0fcf06019ec9de623140bac6094528f02eeda093312fcf716f
+
+Count = 193
+Adata = bdb1b82ba864893c2ee8f7426c7b9a8460b00a50f164fc8f2ff2ae9cddab8657
+Payload = a531c0ed8840b2fcf08d76eca71036153b6e11
+CT = 37685584549aaf2bcf3852d9fd27f216f4ee0e0c041d86dd483c1d6da366e91bd826dd
+
+Count = 194
+Adata = 38b3b9f45041ceb743fc2655b409213fa081427e41c833a2321a09fbd566c80c
+Payload = 177946b4dc3b0b825a505f097a0a203eb21c00
+CT = 8520d3dd00e1165565e57b3c203de43d7d9c1ffde45ca2a83dec2f930bb652a6fcdc5f
+
+Count = 195
+Adata = ec9d8edff25645520801b6e8d14a2fc3b193db70d5e5e878742de83154a578da
+Payload = a2634ef20a2a418b2c3be64f0b5f79d7ea9b7b
+CT = 303adb9bd6f05c5c138ec27a5168bdd4251b648b89aa22cd7d0170a975565cd3a33dc1
+
+Count = 196
+Adata = 8f6c1de4efdc5ac2d6e5452b5b4f58416d618da672f521332fd297ede8350134
+Payload = 40e52edaad5acf2d4eedfb3f9ac2908112e9b1
+CT = d2bcbbb37180d2fa7158df0ac0f55482dd69aed960b33c3df5cd38a82980dc0950ada4
+
+Count = 197
+Adata = b0f1dc85fe223bcf29cdfa9319866bacd0a0a79c554e24d1f10889279e31c0af
+Payload = bf97780f498c23adcf1c49f60873780a235969
+CT = 2dceed6695563e7af0a96dc35244bc09ecd97638fa273c4102b5ca050b23044ac2064f
+
+Count = 198
+Adata = 7d02a323aa769a8201549bf48a520d940bf6f69ed6106f1ce68856c22a594216
+Payload = 58bfe1eb2d38d91f80b3467db94fdcb84ff5f3
+CT = cae67482f1e2c4c8bf066248e37818bb8075ecc15438af1bafac3eac61e1c24ed00ab7
+
+Count = 199
+Adata = d4b90ef8abad08c552c8c3b080b8c37df314d514049d45e27ec4527cb06cdf85
+Payload = a206a1eb70a9d24bb5e72f314e7d91de074f59
+CT = 305f3482ac73cf9c8a520b04144a55ddc8cf464422d9e2f4f84fde49e9701296294d5a
+
+[Plen = 20]
+
+Key = 78c46e3249ca28e1ef0531d80fd37c12
+Nonce = 5de41a86ce3f3fb1b685b3ca4d
+
+Count = 200
+Adata = e98a77f2a941b36232589486b05f4278275588665a06d98aec98915cc5607e06
+Payload = 4802422c9b3b4459ba26e7863ad87b0c172cfe4b
+CT = daea2234ea433533bf0716abe1aa3844b6d3c51e9d5ca3d8ec5065630d2de0717cdeb7d5
+
+Count = 201
+Adata = 5970a836de1f1e91d94d7eef79742cbbd46a759c413715eb0224fd6a27145333
+Payload = 796a69ad0e9379173ef6b66f44f5c84fa70a0e28
+CT = eb8209b57feb087d3bd747429f878b0706f5357d0ff0648ddb07f42f815b38bfc95688b1
+
+Count = 202
+Adata = e3f08834c4894f6fa66a55a280c0e677a79e97c1ef9488b21384e74e57b1b51f
+Payload = 98e1f8cf250183b13ad418024dc40c1a6a7ee8ac
+CT = 0a0998d75479f2db3ff5e92f96b64f52cb81d3f93ddd9a6977ea8e7adf5c5234346e560f
+
+Count = 203
+Adata = 18349be2894d49290339b97f4db28c92b3e112ffac77100abbf9c093935b1a46
+Payload = 4a856d9b50a5b40d6566b38eae6a53ed0c192805
+CT = d86d0d8321ddc567604742a3751810a5ade61350bdee05328a7ea8cc6c2e42bf3faeeda0
+
+Count = 204
+Adata = 7355e34ad13880de17a1d66b02672ea5c9f51774019f64ecbe36747ffcd9b671
+Payload = ad048eb2ad75266b43b59d9d1f073c44e4cbf25e
+CT = 3feceeaadc0d570146946cb0c4757f0c4534c90bafb1435cf929db35ec5986aabaf4a7d1
+
+Count = 205
+Adata = 4be21ba2eb26234ddcbb6aac6b4c3be7ef644af64edf51b7c29ffc3ddd80036b
+Payload = 5b527ac6cc6d1b4c3c56f8315bc96dae91632df9
+CT = c9ba1adebd156a263977091c80bb2ee6309c16ac736be6563cf9f5bce97486b7cc6f1c18
+
+Count = 206
+Adata = 266e0e3365e06d3b1e864c6e5897145df7bdde90eb744013a7b36632d4cf6580
+Payload = cee059cb0fe91a39faccc2914340baeab4b644ce
+CT = 5c0839d37e916b53ffed33bc9832f9a215497f9b2e90335fcea56b969b4fce65442768dd
+
+Count = 207
+Adata = 55a723883a340877d85ad1a5f264f2c834d824c7bbf207cdd8500c9d11ef9225
+Payload = 85321fef6a2b7d31cbd079c4bf2bfbbc979df90b
+CT = 17da7ff71b530c5bcef188e96459b8f43662c25eacd6afdb3578ebc75e8a408d32758931
+
+Count = 208
+Adata = 773864475a1a60a778468a66cbe13dfe3458094e62abb593f50c8495e3a8b81e
+Payload = e227b8d44320bd3ce9d3f7d688f3de887947b1e9
+CT = 70cfd8cc3258cc56ecf206fb53819dc0d8b88abca19fb73fc0488d9f29a09c1b47e3e066
+
+Count = 209
+Adata = f64f3b00c9117aed3c486aa4c8d574b44d679be4069e1078bb7100af38cdb190
+Payload = 206e9eb2bc3f8534d844a38debf1306df808744a
+CT = b286feaacd47f45edd6552a03083732559f74f1fce2c5ef8cdce76b358739e2a1b173fb3
+
+[Plen = 21]
+
+Key = 8883002bf13b3a94b2467225970df938
+Nonce = 818a702d5c8ee973b34e9acda1
+
+Count = 210
+Adata = 545aeac737c0ca2a3d5e1fd966840c3a0d71e0301abbe99c7af18d24cc7e9633
+Payload = d516bbff452e7706c91c7ace3e9baa76d65ff7050f
+CT = b85242fdc06344f2bd9a97b408902ebcd22aece3d42f2da4dd4d817c9fa2d44bc02163a0a9
+
+Count = 211
+Adata = f032db01da60ca078d35c3fb5d05d6750fce1c01911a0422e827e8976946e4dc
+Payload = 590d1aa655fed50ca2e402299f2da6fe20eed56071
+CT = 3449e3a4d0b3e6f8d662ef53a9262234249bce86aa180f41bccbcd47c8b7890754c032269b
+
+Count = 212
+Adata = 71ecb4252518997b53491cf42a3e0fe1496a2af2329a16f9fcd9c4f249900341
+Payload = ecd86cdb7d78d310dca5b477cd9da2612f5a05ab39
+CT = 819c95d9f835e0e4a823590dfb9626ab2b2f1e4de21d6ba58cc2eb474401851bf9502c3413
+
+Count = 213
+Adata = ec7abed9bda4a52fdf1bf278b6bdd6b0a27d4688deb9ff5ca9c8c865a4d2f730
+Payload = 0024b14c283df032cf80c22ad8d2c96289ee229092
+CT = 6d60484ead70c3c6bb062f50eed94da88d9b3976499b94d4b7a2044696c72322e850537b6d
+
+Count = 214
+Adata = c2c77d7ad7b27d7c0f976a1e28881ea4ec7ad03b63a4e67f47280a40b8f58086
+Payload = bc6965d8f62d066d118c14044c1fd2a224b9d95110
+CT = d12d9cda73603599650af97e7a14566820ccc2b7cb9d8da8e718570caf8bed7909fbff3ec6
+
+Count = 215
+Adata = 28929286bd1391468ac75f5c03689f74780ddd7585fc16f9a9bf7b00357a72e5
+Payload = da4a630cabaff0728a1cc3e6a79721a7176b708f1d
+CT = b70e9a0e2ee2c386fe9a2e9c919ca56d131e6b69c6e671012690c61fe3c9abd50a78eb4736
+
+Count = 216
+Adata = ed360d22081b019dc979420a3a45c21c8903c59daedd9f1b4ef2bfdedff0ec1d
+Payload = a95058f8e1f6bc0f143a9ca7e4425a2a63eb2f7e33
+CT = c414a1fa64bb8ffb60bc71ddd249dee0679e3498e8e657e2250427130acef7032454cde7b6
+
+Count = 217
+Adata = 2b4022d0b951fe48635d04fb3e2fa032c07c855fdd73f45670953bb9ddc77cb4
+Payload = fcbbc7f9d1ace60e830ca56ec84814fbd2579993d4
+CT = 91ff3efb54e1d5faf78a4814fe439031d62282750faac6ff0a264b8199550d93c1f06063da
+
+Count = 218
+Adata = 48e553a87a7d3c1bd68af39f96aca67583da86e06701d5e4c4ed404dc66d70f3
+Payload = b95d298d391c6b893c6cad66f9780534516e71455e
+CT = d419d08fbc51587d48ea401ccf7381fe551b6aa3857e68bf636e81c332f72063dc0d6fc2b6
+
+Count = 219
+Adata = e8e2835e47144365a2f218d4c95d7522e824fb43b66d4727ee570f8303dd6dd3
+Payload = bc79d444dff9d9e722effab07b068cb7723ae8fae0
+CT = d13d2d465ab4ea13566917ca4d0d087d764ff31c3bdf3af9e9c4e04bad261dc17cf00a00dd
+
+[Plen = 22]
+
+Key = 5cea00ee44cfb9cfbb598d3812e380ef
+Nonce = 948788a9c8188cb988430a7ebd
+
+Count = 220
+Adata = 50422c5e6a0fb8231b3bb6e2f89607019be6ad92a4dae8e0fe3f9e486476004b
+Payload = 33bfd0713f30fcac8f7f95920ac6d9b803ddd5480dd8
+CT = b168747dea3ae0fbede4402af9a3dc3185d6d162f859d828101682de32923788c70262b84814
+
+Count = 221
+Adata = bb0036b34b0c20094d335a8c74f6b3dea42eeccf4145192eada64ae00c726b2e
+Payload = 5576d94b577ed26820fb13c00ab0e2d1a1c3589bfdc4
+CT = d7a17d478274ce3f4260c678f9d5e75827c85cb10845bafc4ae4d31907def6f648b081174e2a
+
+Count = 222
+Adata = 5140324aa758dbbb5391b5e6edb8a2310c94a4ae51d4fba8a7458d7cc8488baa
+Payload = 13303e14068205cbfa992d4ccb6a265804ea64a15d7f
+CT = 91e79a18d388199c9802f8f4380f23d182e1608ba8fe314e378e9ed6e725a14c07632b02bdbd
+
+Count = 223
+Adata = 74da07d324060e590356988f27d9879fa3a3ade0fe71e2a0e49054211cfa1fe1
+Payload = 567e6d14b446add630d53ea86a537c0938537c4604a8
+CT = d4a9c918614cb181524eeb1099367980be58786cf1295bc2f2f9331536f7f70be09c41bda0ad
+
+Count = 224
+Adata = 0e403cff47adee3ec5bb6b178dabfc7d53b60a04eaad33a2fedd9db705358a4c
+Payload = 9f3d165d44cf1c5770346d211d4ff34ca2ecd6b28549
+CT = 1deab25191c5000012afb899ee2af6c524e7d29870c86b59cc9c3c008bc5876ef86327859cbe
+
+Count = 225
+Adata = 211e6ce3d0c3abdef069e6e4fa35015797bd8a9d64bc9b75f20b028b12cca04a
+Payload = d726e599db6a6d40629bc4bda5e3fa2e5aeda229cea4
+CT = 55f141950e607117000011055686ffa7dce6a6033b25135e6d59a5385a78658d60d254f99962
+
+Count = 226
+Adata = 3c5c67b083322115e1b3112c2b6968efc050094e23e646dce982eac9d6e67d10
+Payload = 42646cfb8a99e48a35cee3f5f9b3e6175695973f6de0
+CT = c0b3c8f75f93f8dd5755364d0ad6e39ed09e93159861e234e83d9a0570dbf2b2fa59ce3cdbd9
+
+Count = 227
+Adata = 37a931f1dd05755b376d1a164aa36b8de802e39f8108a0453c1114754665fe46
+Payload = e814c7b5c72d973a9bc7ccd463f107325ffa3321783b
+CT = 6ac363b912278b6df95c196c909402bbd9f1370b8dba2084e352b1b157267228576dd056c1a3
+
+Count = 228
+Adata = f1ddc2c49da7363526ba36c600c589b4c3121fbb8c5b9a8aa0de0e7453b30568
+Payload = 4f7a5618870945b89f194e31b1aa802c5350326dc691
+CT = cdadf214520359effd829b8942cf85a5d55b36473310bf88ad35ee338e489e55bb49732447cf
+
+Count = 229
+Adata = d14b3d3803df432488b5d66704abef6a500d397e855bc2c2574df746a515cf70
+Payload = f555216840a1f40b411d44128e567617e2694caf1621
+CT = 7782856495abe85c238691aa7d33739e64624885e3a07ab67f9397a81371ef6ebc775cb7007b
+
+[Plen = 23]
+
+Key = cb83f77751e72711401cbbf4f61aa0ed
+Nonce = c0b461b2e15b8b116ef9281704
+
+Count = 230
+Adata = 2bd112231f903fa0dff085db48a2e2a96ec0199249b005d5ab4c2eab753f9ad0
+Payload = eede01b08f9a303cdf14c99d7a45732972c6eff2a1db06
+CT = feb114b7bd3b43497b62454a675a632c3546d2802462c6af57647efda119c59862cd5dd3904efc
+
+Count = 231
+Adata = 864e0e728aea856fae6c6daa6357d1542cef7177f441ba21a563f6c4f6fdc1dd
+Payload = 8a56588fe5e125237b6cdc30f940b8d88b2863ec501a0c
+CT = 9a394d88d7405656df1a50e7e45fa8ddcca85e9ed5a3cc2af4027ca5824b41c7bb238d3e8eeebf
+
+Count = 232
+Adata = dac7f3cba0b5a47f67f85b226b66df695a8ae2501355e36aad105375bb95f732
+Payload = 66e34540d7accf377877aa2d3e6d2db0cfafc608a1eb3d
+CT = 768c5047e50dbc42dc0126fa23723db5882ffb7a2452fdf7fbd7044ce1d7b266bdf545247a3c2b
+
+Count = 233
+Adata = 07f48cdc12aa27119fbdfda4ec07ce6068c92ba7ba9c930905aadd156b1dd56e
+Payload = a9ebd04fba7155c39b5c29c5571b5354c9ae228f5e5b13
+CT = b984c54888d026b63f2aa5124a0443518e2e1ffddbe2d3afabc559b552cf7c7730c7dca25bc3ed
+
+Count = 234
+Adata = 2d24e79abd157af2c21b60932947fd9f9d6478f09ec56fffd341ea04a17b8e5f
+Payload = f179353aef342f0f691caf1fcb811e3f6504e14d6d9381
+CT = e116203ddd955c7acd6a23c8d69e0e3a2284dc3fe82a41488ca99e0f85ac388f981ce25560b8f9
+
+Count = 235
+Adata = fea280f710379e4665b5ed3d1620729a7bc164899dc83e6aee3612d538fa20db
+Payload = 6c19a18eab544acc883c5886eaa89f54d61ae5f1f1368c
+CT = 7c76b48999f539b92c4ad451f7b78f51919ad883748f4c9156faae3d8860bed216e8d497a75962
+
+Count = 236
+Adata = 18f2e3457127c35f2e0cff2d821af8178028fcc7803bc795c49f4a435b37abeb
+Payload = d0df1bdf1df6203241722fb9c9c1cf7405017497ae1545
+CT = c0b00ed82f575347e504a36ed4dedf71428149e52bac8588cd7791c544d1098b2de49d04b1e0c1
+
+Count = 237
+Adata = 35221f0efcb109cb93c38a62c58b5ab8b236437e171e8507cf417a569af1767c
+Payload = 479526b33c42c240b9a4549ca70cbfb691f16ae3be8888
+CT = 57fa33b40ee3b1351dd2d84bba13afb3d67157913b3148c523fd8a2524717f63dac75c22268fa6
+
+Count = 238
+Adata = 95f2ab02af01aeacce86b02cf846f9fbd516963d06e350e8b7f6df2778765a01
+Payload = aa6761148b254a2ff202b620c2ec2c5e623bf61f05e483
+CT = ba087413b984395a56743af7dff33c5b25bbcb6d805d4392904f05dc2397596543df73de5aa708
+
+Count = 239
+Adata = 3746a36154e42dd600049d506f5ce4d034864263b1a65cecd24c8e25fb9c82e1
+Payload = 2f298f106703b8a994cbb20acf47f9442e44f6b5e82c38
+CT = 3f469a1755a2cbdc30bd3eddd258e94169c4cbc76d95f8c3cbfecfa3f75fb111ef0011222b7948
+
+[Plen = 24]
+
+Key = 43c1142877d9f450e12d7b6db47a85ba
+Nonce = 76becd9d27ca8a026215f32712
+
+Count = 240
+Adata = 6a59aacadd416e465264c15e1a1e9bfa084687492710f9bda832e2571e468224
+Payload = b506a6ba900c1147c806775324b36eb376aa01d4c3eef6f5
+CT = 14b14fe5b317411392861638ec383ae40ba95fefe34255dc2ec067887114bc370281de6f00836ce4
+
+Count = 241
+Adata = e82fc3ffd276218a82aede65fe5abf4fd35c7059a26923f8dbb97a59c903a7f4
+Payload = eab8cef576816a82ed036f158e5036f5987b195e60582a6f
+CT = 4b0f27aa559a3ad6b7830e7e46db62a2e578476540f489460d2d30268e9f1ce0e7c762993297d828
+
+Count = 242
+Adata = 776aae7f62225556b6da522c0c9432ac70fe72ac6f3f361071ef3deb4a6715e8
+Payload = 566ef9ce1d397be2547c385639507a9e7d6f9eed9a3b1055
+CT = f7d910913e222bb60efc593df1db2ec9006cc0d6ba97b37c0939e56f0b7200d1b1409f3f8e8179cc
+
+Count = 243
+Adata = d9aef0955922f89747ba4a8ddcdb8c1c7579aefd3c2eb8ad0589c66576a8504c
+Payload = 8c28b6d93b23f1ea031d5020aa92f6608c3d3df0ee24a895
+CT = 2d9f5f861838a1be599d314b6219a237f13e63cbce880bbc138e3b817023993608be06fe92efca8b
+
+Count = 244
+Adata = 13c222a65ce30570ecac85a185a2a0922a8c96d633339a1ca067ce57ae426e1d
+Payload = f0c1cd60f5fa8d1efd5e2e1ab37c4f7e6aef76d15e8d6ac8
+CT = 5176243fd6e1dd4aa7de4f717bf71b2917ec28ea7e21c9e1f3ca13b4ab7fd0d4badf158972570c06
+
+Count = 245
+Adata = ce40fb0cbfdf07676ed55b040ae6be5db8f0a0f28816ae8ea71da3cbd71661d8
+Payload = 570d5f79aa8db14b1ac99ee567cc105ae9e238e482b52628
+CT = f6bab6268996e11f4049ff8eaf47440d94e166dfa21985010a79fa4e8b27a31ff360a1b6c05ff844
+
+Count = 246
+Adata = 446b01d09cbc41b6393ef81ca65ab7e099018187d5f9d22f5074dfc491e72077
+Payload = 7c267223047af946b06f6a45ffde4a5ec49c28b81ca22da4
+CT = dd919b7c2761a912eaef0b2e37551e09b99f76833c0e8e8d5d34ef0ca0b47d6a2ec7442cbb739504
+
+Count = 247
+Adata = 01ec87920b42639d4ba22adb1fbe5138d2849db670a2960fd94a399c1532ed75
+Payload = cbf112e4fb85276c4e09649f3de225b2398e86ac3fe48bc7
+CT = 6a46fbbbd89e7738148905f4f56971e5448dd8971f4828ee8f607d154393e35fd1efc1ae8cb244e4
+
+Count = 248
+Adata = 5032b818d202872f3fe2b08fc7940696df02cf393a6d6247f5c6f5f2125cb08b
+Payload = 4324a89788e8ddae5d560cf937df701743cbbc3bf980558c
+CT = e29341c8abf38dfa07d66d92ff5424403ec8e200d92cf6a5617d9cebea38591a00c9fba4ef9c8e71
+
+Count = 249
+Adata = 27b661861717f00a3ae22ead78f4dc3f32b40e8fcb8ed58167a31a61f2becd77
+Payload = db72d98d63fc10acff7dceec0e2691a80ecee50a0e957ad1
+CT = 7ac530d240e740f8a5fdaf87c6adc5ff73cdbb312e39d9f897062a1ec759a515b938780f902fa7c2
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VPT192.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VPT192.rsp
new file mode 100644
index 0000000000..abf1775dd1
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VPT192.rsp
@@ -0,0 +1,1383 @@
+# CAVS 11.0
+# "CCM-VPT" information
+# AES Keylen: 192
+# Generated on Tue Mar 15 08:09:25 2011
+
+Alen = 32
+Nlen = 13
+Tlen = 16
+
+[Plen = 0]
+
+Key = 086e2967cde99e90faaea8a94e168bf0e066c503a849a9f3
+Nonce = 929542cd690f1babcf1696cb03
+
+Count = 0
+Adata = 58f70bab24e0a6137e5cd3eb18656f2b5ccddc3f538a0000c65190e4a3668e71
+Payload = 00
+CT = 3bf9d93af6ffac9ac84cd3202d4e0cc8
+
+Count = 1
+Adata = 760d065275e345900a7bbab451cc9309fb161e6cfec526538b98800e4102e14d
+Payload = 00
+CT = b0078a769ab68db44e723993da382abc
+
+Count = 2
+Adata = ffedc67efd355ea404fcbcb3993d3bae81386ded86230270771deb747163bf44
+Payload = 00
+CT = 31fbff2d715a2eb9af54e8320a8e42e1
+
+Count = 3
+Adata = 55153ff5e4d208d2e647794f382c788e0e36f293e63e7290ba9ff2657ae0f167
+Payload = 00
+CT = 945839d62c9d1b899f6dcd0ca9517e68
+
+Count = 4
+Adata = f8813985f59bf284bd3882e899ca9b67fb496f3eb78d7ebe6ffbad084f639915
+Payload = 00
+CT = 903f90d23321a6882d6c4c1955b14847
+
+Count = 5
+Adata = 7b95cd827ab93507f1819ae76627d6e2a31d29890c092e5c300f0e2f9e4ef4d2
+Payload = 00
+CT = 652ec5ab43088eb568186d0d9887b30f
+
+Count = 6
+Adata = bd144c9bb974729aaa1188ceefdf85e1d9fddc0b0c8afe8828ba204aa9293feb
+Payload = 00
+CT = e6c1455d1117eec49338c96f51007309
+
+Count = 7
+Adata = 92b911cdc3137a6f7f32651b788eb82975660aea52b2c03b4759755a6da4a0f8
+Payload = 00
+CT = 1cf3c32fb229dac209523eaa517bb59a
+
+Count = 8
+Adata = a8200dbbfe4086015cdbdec2fc8e4934d0d663527430c424627ed44065ade091
+Payload = 00
+CT = ee10bfeb1cf9b3cd5a0faebd4d8f3fe1
+
+Count = 9
+Adata = 3b7f37b6b8e3c1390a99d59c47f7c102cf659d361a132ef8b4e70b9585bafebb
+Payload = 00
+CT = c51ed994253adb9bb5b9a8c34a27f225
+
+[Plen = 1]
+
+Key = 992d38768b11a236945bd4b327c3728fac24c091238b6553
+Nonce = b248a90b84b0122a5ad8e12760
+
+Count = 10
+Adata = 27cabc40da0e1eda0ea5f8abbb7c179e30776250a7b30d711b0e106c5ee9d84a
+Payload = 1c
+CT = 1a96f58c3f38c44d1a345f3e2da6679f20
+
+Count = 11
+Adata = dc2e28d5ae726c1beadb1e7e92ae7d14f5546320deb81a910bf170cbe0210eaa
+Payload = e9
+CT = ef0579aee7c17482691f3f832d867ffea7
+
+Count = 12
+Adata = c579f912ac1b45d5aa8cf20f78f0a1ace32abd3dc7fd0b3f3a7182a008795c7f
+Payload = 97
+CT = 913452d8ece38ffa1d4107d6a053acd8c8
+
+Count = 13
+Adata = 69ea953dbb910ec589372d797c7379d3f3b9e9fd48894c9b55e6e8eb360a6211
+Payload = f4
+CT = f20d760b9fe29530738157db0ba2d253f0
+
+Count = 14
+Adata = 622835dea57b2c70cca8f7548d6210714070b55b36adde7a4c547269c07aba9c
+Payload = 9f
+CT = 996fc21f24dee7b52f51d69eea30819f4a
+
+Count = 15
+Adata = 67ebda0a3573a9a58751d4169e10c7e8663febb3a8cf769d81bc872113f0720f
+Payload = 43
+CT = 4594c5b8db0064426a77dc536814c56147
+
+Count = 16
+Adata = 255412e380e9a28cbcd345be172c40f72dec3e8a10adfd8a9ab147e9022524e1
+Payload = c1
+CT = c76d36c0b0d699a22da3116dfb8f453181
+
+Count = 17
+Adata = c7c8e7151eb6844a954d091b460f83add0f0a634aa5ac213b774f2451aa497fb
+Payload = 31
+CT = 370c3a1690acc3f0eb09c9cfd3396c7fa9
+
+Count = 18
+Adata = 63f00b2488809fdc49ca5f05d54e98468906308115f7e702da05ddfd970b5537
+Payload = a7
+CT = a1ad45070fe4c61270c13cc52247fee411
+
+Count = 19
+Adata = 8e2c5e55c0bf70014e9897b6f6940e4e738b1e84e8269b6382f0b1fe59b0e162
+Payload = 40
+CT = 46b2a2a8b283ff7eeff5c2670f77b8809d
+
+[Plen = 2]
+
+Key = 5012db40ff6ae23c1e1ce43768c5936c4400b0e79ae77f30
+Nonce = b67e500b35d60ad7264240027c
+
+Count = 20
+Adata = 40affd355416200191ba64edec8d7d27ead235a7b2e01a12662273deb36379b8
+Payload = 0c6c
+CT = c996ef3d6ef9f981557506ecc8797bbaaaa7
+
+Count = 21
+Adata = c5e12e17e02bcc12b3a4c14cf837250e2886db3ee1c717d28bd11e8a3b764ddf
+Payload = 23df
+CT = e6254405257a837c5343b59d5689d6de5269
+
+Count = 22
+Adata = 213b5b6015d472bd593be5acf85ebba6d6a09f3a962be302ba83c6d70c61f241
+Payload = 0dc2
+CT = c838e93e67d37d2367bb1f27f71b54b29317
+
+Count = 23
+Adata = fc1b6e152fe232b6c10b5d89900961c445f4c46833df242c826678b68c869811
+Payload = dc88
+CT = 1972ca3744a4ab375af9060621a9dc4f4c32
+
+Count = 24
+Adata = 5b2eb1a6fa585d61d1fb3da68f5b93829c8e2d5e4fe03782617553d7a130ecf1
+Payload = 8179
+CT = 4483172626e930d24052bc056d8609c4175f
+
+Count = 25
+Adata = e2b3c3bf33cf847660929e48cce51d9d9289945169651aaecb1e939756e93105
+Payload = 01fd
+CT = c407852310207be8d3417de800b372700da2
+
+Count = 26
+Adata = 6051f12cd8aae68b4023aaf7178fd086aa582b8d8821e36637abc97025f5e858
+Payload = ca18
+CT = 0fe228553bc037954dbf4ce5db99792c2c7a
+
+Count = 27
+Adata = 2d3555faf285caaddfe95c010c2a7f233e09c2fc0cd30d644035269280527ad7
+Payload = a855
+CT = 6daf904725668634d6345bd8f90a3831b452
+
+Count = 28
+Adata = 4fca820dc545bf93bdffed33a04b67eb45384e696f092c2197e5d79cecd09913
+Payload = 5555
+CT = 90afdf6098cb3135c3045a54ffce88efaceb
+
+Count = 29
+Adata = 1789ae403e183d2225f431f001d475b53bccdec66572bb027340ae592839ba8b
+Payload = 11dd
+CT = d4278568e8c08ff5ee5ea0a608589c2fc029
+
+[Plen = 3]
+
+Key = fa15cc7f0de294d7341b1fd79326c8be78e67822343c1992
+Nonce = e5257aed2bda0495aa44591db4
+
+Count = 30
+Adata = 31a0338c3839931fa1dd5131cb796c4c6cfde9fb336d8a80ac35dec463be7a94
+Payload = bcb898
+CT = 68f08298d9a2147776dca9c1a42382bce323b2
+
+Count = 31
+Adata = 4863dd810ee70ef0f5da81f60c5ce550abb96454619032322e34657af25207de
+Payload = d1da2e
+CT = 059234a9a77755b324f3a557217752ade14ed7
+
+Count = 32
+Adata = 173594fc26b167f044aeaf9bfe920cab99a27eb2b01827d61f7553cb2018b5fe
+Payload = 394f31
+CT = ed072ba4441a79a90e228a28069fe109d5d876
+
+Count = 33
+Adata = 71cdd16eca9255aeedc23bd623513918ea97da21485074415fe75bcc42f454c0
+Payload = 868bda
+CT = 52c3c065f272f44c5210b5bcc571e819580910
+
+Count = 34
+Adata = e84418d332d16d2298e69e7ff3c37bc7b6e030cc822e73b3f4a0029bc2ea4d80
+Payload = 52d6bf
+CT = 869ea559c5f7f73a1b5f419c9f63ca401894a8
+
+Count = 35
+Adata = 42d962109bea1d50be0f3d83b4c2a6033d53b3d7112591866b1ae52dc84cb5d0
+Payload = 6f8d58
+CT = bbc542220b828cf5365137fb3f1df67cc8d2a1
+
+Count = 36
+Adata = 943b4327b5c70dba63c82f27e0412b3ada012bc0f7dd39ebb13db2f864daf80e
+Payload = fda286
+CT = 29ea9c422b0f41075ac79a0afa2d1047cbbfb5
+
+Count = 37
+Adata = 6076b94caabfa476ab7e6482e4fda9b29f2e2b2883efe44d668c7c74628505bb
+Payload = 8651fb
+CT = 5219e1ae68cd6d6815ecbfd01293d160d4d38a
+
+Count = 38
+Adata = 3e4bb5781f84b4bbd23583e3dae561c6ff4af8eff35e2a4f35b50d2f360d3469
+Payload = c3e179
+CT = 17a963fbaa81cfdbcaee476860cd5102f556e4
+
+Count = 39
+Adata = 364008acbad330d0b8d574641a97b0682c49279cfdc80ff309b7514514d18a44
+Payload = 4a97d5
+CT = 9edfcf7ad1520564b68824a3a939371c21a336
+
+[Plen = 4]
+
+Key = b5330a8447d74a7987fb718cfae246b5c7e057991064eeaf
+Nonce = 2ef29d62b40d8643848797cde8
+
+Count = 40
+Adata = 1225b036e6044df52314016760e92750de0936120395de750a2c54a7fa0cea82
+Payload = b46b343e
+CT = c2c39d6f9344e2de064f269d065a2a6108605916
+
+Count = 41
+Adata = aaa6257d6783936a4445833c2ac3bea8cb7334f22ade9c035d515bbc91d6a78a
+Payload = cb216301
+CT = bd89ca50693d90b8297b90bc41c231d08b0204fb
+
+Count = 42
+Adata = 1c1915fab09348b9a5536495c70d1a040305708c1124797e564b63e008e7b8ab
+Payload = 697a8696
+CT = 1fd22fc79d0146fe373437c529fb2eeb169e4bd7
+
+Count = 43
+Adata = 864d0f786497c7ce283762ca0959ec9c825ed445a5dbe5b4b2e5772fe88ce7f5
+Payload = 6bee3db9
+CT = 1d4694e8e389c549bfc4ede936d7896e544b23ad
+
+Count = 44
+Adata = d5388b0b548c58886dcd335dff2b1ed23ce3eebbb708fb5bbd831c83e959d3fa
+Payload = 85d95855
+CT = f371f10495177a9fe6d9329a585c8737c92a4d29
+
+Count = 45
+Adata = 83cddd189736f224cad6a29efba45e43c75450a14f1541713b7fb926ffc768c6
+Payload = e8b23340
+CT = 9e1a9a113914431a10b1f94a2b99b9e442f3dca4
+
+Count = 46
+Adata = 8fccbd1fc5240691cf24e8807bf3416c1b2d87fc86dbf3955fa2e52b9a3a8457
+Payload = 595c4d7c
+CT = 2ff4e42d383d8dc98b22010dd93cd0cbb396d9e3
+
+Count = 47
+Adata = 513d45f6f37f3f051667dc743215059e06e4fdc8945789b16d50556a2e839368
+Payload = 314e0c7d
+CT = 47e6a52c40c513bfc92d1a7db5ed7cab2d8212b0
+
+Count = 48
+Adata = 70828be102e554f0d4b07641fa3254bc8db06eefaf5b85a7c97e01c217fc8f3f
+Payload = 35753e32
+CT = 43dd9763ea98f4ac6b3eabd483f1e6ab92f3b83c
+
+Count = 49
+Adata = 343d5a4ad39acf81adcf24e9807618932abcb3bc076734f179174c77c8cb89e9
+Payload = a531c0ed
+CT = d39969bcf99fb67b1e2aba2d232db2445e6aec2a
+
+[Plen = 5]
+
+Key = 30419145ae966591b408c29e5fd14d9112542909be5363f7
+Nonce = 27e6b2a482bbc6f13702005708
+
+Count = 50
+Adata = e04e81e860daf9696098c723085d8023c240ebe7a643131e35359ab04bd650fe
+Payload = 8ceaeb89fd
+CT = ec9d5ed36243ddf77b33d8cf2963ba76fd4e19f3c5
+
+Count = 51
+Adata = 6217cd581d4b3b2f7bcf1b8dad9ad6430e2e3a0063cad52260e0a1cd6fc9e73a
+Payload = 7e51d6f870
+CT = 1e2663a2ef6b73fe9e638e205b27f78ed1bb9b0ed0
+
+Count = 52
+Adata = 8aa7847e496f5e9f1f87851442de844f27a21c1b48f82fe525f0dd5a88b8ec38
+Payload = e0023b674d
+CT = 80758e3dd25936115e23158aff1916edec241fad56
+
+Count = 53
+Adata = 3612abc865a4d8d7b86a84109388584df6526525adb1006ec6c8d00048d725bc
+Payload = e2b5b6f36e
+CT = 82c203a9f1f15aae4b70dbee244be1daa74475d7e2
+
+Count = 54
+Adata = 849a99c6f1cae0ad4bcde4bd0811e87ca5ed7b913de1a8285a206e980b4b7043
+Payload = 9a17e4a22a
+CT = fa6051f8b5bbff424487848385f8501ab5a77f327c
+
+Count = 55
+Adata = 9066367c784de0a4d1116bbe95ce55ded85edddb6273c2049ee24e0fb3429352
+Payload = d4e765fc78
+CT = b490d0a6e772d8d5da6f593a8d9956731b42645aa9
+
+Count = 56
+Adata = e7aa9f767fa8920f96f91c41d9e86755faaedaeda596a444b65f99b7a9e23e85
+Payload = 1074349e10
+CT = 700381c48fe3eca12b835dcfd08166ac8831585626
+
+Count = 57
+Adata = bc0db1ebf910b6f4dcad5401401d6bc2272e23130947dc236ca664d5b5ed6d66
+Payload = a46dd7fb58
+CT = c41a62a1c72bcce66018e9e552d2c8a229301361df
+
+Count = 58
+Adata = fcbeba2d0d73239d05f691a52b08152c9dd871f8dc76c2c18b8a638a74460d31
+Payload = 2e0ca09221
+CT = 4e7b15c8be3e41a50a28ea3be14baadf12964a37c4
+
+Count = 59
+Adata = dcdefce64ae4339f46c0759a4a10b29d59daaaf1e5dbf75cf11b4e4f73c5025f
+Payload = 2e108ce0fa
+CT = 4e6739ba65bee2ab25bfafa76dc3e54832b2f76864
+
+[Plen = 6]
+
+Key = 748ad503388a34041a7bdae6361d57894357c333bacf02ca
+Nonce = 518b79d194579b19f2d8845b70
+
+Count = 60
+Adata = 691dd98f61fd213b0840ec5a6f06ef9a1420be0d59bde5e43546347a2a865a94
+Payload = 24d6880aed7e
+CT = 270120f9634ec15536e21d961c675070ec4cff9037bc
+
+Count = 61
+Adata = d1fd047cdb18463766841abb1fcd25257f1458b595bfcf24066ff9385232fa97
+Payload = 2298028d0213
+CT = 214faa7e8c239b303af0b098f902dc24e66fe56adc6e
+
+Count = 62
+Adata = 65a480d120a0459dab69e8f23094801e10092666cc56f9fb2549662982bda6d0
+Payload = f248e5225e3d
+CT = f19f4dd1d00d1b657925a9740d6828bd85cd12205764
+
+Count = 63
+Adata = b738a53fbc9689dd49f68f97f5a99665258cd52e74dc653b594cffec045508aa
+Payload = 611dade00cec
+CT = 62ca051382dc395a1c49129ef6cce0ad5f6ef378aa1c
+
+Count = 64
+Adata = 7006f54184f0ff0ab215ca408d46325b86c1cbae6da7838435b1826ff81f55dd
+Payload = 5871a8300471
+CT = 5ba600c38a415e68468d1b2b516be3d688567d84ab80
+
+Count = 65
+Adata = 9e6e6675d4c6b1e0f3894aac071f4c99a364708edea12f319cbc27b40fabc0f1
+Payload = 3ca8a7520e94
+CT = 3f7f0fa180a40ba1af163049d16817021665d183bc9e
+
+Count = 66
+Adata = 10ceef716f54b74d7c8a435d6aa38a10ff23939ca29e2de7b6c3e0a8269a23c9
+Payload = 9c2a0070fbba
+CT = 9ffda883758a670f35869da9821b6ff1fab3e6062ad4
+
+Count = 67
+Adata = 3ee0865f29be50160273b4a94ec078932b9cd10a858e31838d5b607867e1ce69
+Payload = 436179c74fd2
+CT = 40b6d134c1e208f395250fd79087c858b83755411114
+
+Count = 68
+Adata = ec2b8bfe1ccd491b02aa4a9178fd6f099556963e39e2ca5fe6ecb6b5d2a46085
+Payload = ecfa41c614c5
+CT = ef2de9359af5afcbd9af2d584a0f638d066f2496d9be
+
+Count = 69
+Adata = 5b6f6369643d83b1db33d75257d7dea761e574e6e1f1ecead64e5e354a2f4235
+Payload = b48c10105dbc
+CT = b75bb8e3d38c17861882b8930296fd51d969a1e9489e
+
+[Plen = 7]
+
+Key = b930cca30a3fd230c237c8f3cc6792d0c4084dff5c18d775
+Nonce = 7574802fd82fe96c05431acd40
+
+Count = 70
+Adata = 1cf83928b6a9e525fe578c5c0f40c322be71b3092239bff954dd6883738d6d71
+Payload = 2a755e362373ef
+CT = f06238b0450fd1f4b6cab1383adb420c4724aa7bdfefb7
+
+Count = 71
+Adata = bb5450f66273f63b2f79dce177381ce846584ce4f7a0ad5a0171a56e149370bb
+Payload = fab43224bf8989
+CT = 20a354a2d9f5b7a1f99175d3dff5a73f0053a95c36fd8d
+
+Count = 72
+Adata = 3e5e1037bd2922eb20c34200c470b76e537baf7e7f1d8dd2f7a184a593c66554
+Payload = e3aed6715aa429
+CT = 39b9b0f73cd81734b4ad0e41117940abf530093dac648e
+
+Count = 73
+Adata = 3cc88a096a1a440827f5b7da675389e50b5cce35fa2cc36674d6bfc5a3a966b2
+Payload = e78db0f83997cb
+CT = 3d9ad67e5febf5663a8324014550430c7eaeffbd8568f7
+
+Count = 74
+Adata = 2cca33a10b9da7ba99a6b552d1405f2df3fdfd15358d8fdab5e15296b38f9135
+Payload = 726557906845b1
+CT = a87231160e398f34ab635c4eb5b38b86e71da8af3840ae
+
+Count = 75
+Adata = 2fe5dd58b17914187e29029c53cfe5b015ca74cab750d8f95e05f818c3cdf947
+Payload = 043a759b578be4
+CT = de2d131d31f7dabd9961766e03eaa7e8888227c98d1f42
+
+Count = 76
+Adata = 8b8e3d7c88fa16d70130cee290b7e2eecf0ce711118cd9265093b11467e63554
+Payload = f31f2fb4b3fd80
+CT = 29084932d581be637842d96d13c4aab97e296458745a9d
+
+Count = 77
+Adata = 6341370e126097f9721a13c977eb4875cf1286e15c3adfa4e7597e0e13d93b6a
+Payload = 7e3c8224104669
+CT = a42be4a2763a57a51ac46611366c666cab6bfd3d1baaa5
+
+Count = 78
+Adata = 227926b62f7cdd90e4d3b0cb5457e71fb087d329671f0fa891ec06eb8edeb58a
+Payload = 26a0528ae6f9c1
+CT = fcb7340c8085ff8c7d7e5aec14845f844ad38544a2f11d
+
+Count = 79
+Adata = 05b50c40b02e79b74b94d726a7ce8b2b7216ef8af6e7a42d041d2a692a58ad83
+Payload = 61dcf53d1a184e
+CT = bbcb93bb7c6470f1605ab8a2332012b759ccd2eedbed24
+
+[Plen = 8]
+
+Key = 314c136999e41d137bd7ba17201a9fa406025868334e39b3
+Nonce = 65f7a0f4c0f5bba9d26f7e0ddb
+
+Count = 80
+Adata = 5c7ce4819b30b975ae6ce58dcc1bfa29a8b6dda8f4b76c7e23516487745e829c
+Payload = 4d54d8b06b204445
+CT = 2baf90c490b11f9607482362ab3f157c42d0e9c6c5cffcf0
+
+Count = 81
+Adata = 90257ed88679197b8219bc4c2434a71a4e3664d5859c4ffb9a075654898ffedf
+Payload = b2a35df881cd63a2
+CT = d458158c7a5c38715389509b5b6f2df1faf7e8c39203970f
+
+Count = 82
+Adata = dff8ad83525d8235eacdccc91abeb80795e6b5f463fd28af35c46199f646ceb8
+Payload = e98f5e5a20d02c80
+CT = 8f74162edb41775395328747ca544e987df28883d0377b35
+
+Count = 83
+Adata = cde159c5343cd9d98001cd719d3e9ea25e47e1ff13fc87055d4a53b741f59285
+Payload = 90c3e48313cd4fe4
+CT = f638acf7e85c1437a4ba841883a0d7aeda398c043161966f
+
+Count = 84
+Adata = fa88cf5a08be4fb0c1a7960f45726c303eb559861fa60d17aa8dfe8bb5795382
+Payload = 8ad6d5a28ec075e6
+CT = ec2d9dd675512e3509195efe66c5faf413e0f68df8cb647d
+
+Count = 85
+Adata = fe9e93a9370b43efa1560aeb017ff04fca7f207191e6f707c1c35b2e90c44eb2
+Payload = eb83928f0d5f7aa3
+CT = 8d78dafbf6ce2170b51af067ad69ad96009e50ead3d03f02
+
+Count = 86
+Adata = 35792c854fdf1c8cf7f3f8ed2b8ec4f31fe17bf8d4ba49caec03f954bd8bb17a
+Payload = 4cd74ed2fd083011
+CT = 2a2c06a606996bc26b1cb03ee76587f84364825f7c1fcbe9
+
+Count = 87
+Adata = c084108f9c0a74cbf70f614dceae592546865006930db0401828a0eecff98671
+Payload = 52365f94579e0646
+CT = 34cd17e0ac0f5d958fa70c5e195f1f955d64892f532b7683
+
+Count = 88
+Adata = e8045949de61c5c18a63e628330a4d1d12782379a8f9187755409d1825f453c5
+Payload = 8fb85c857a3e38e7
+CT = e94314f181af63342ddf297bdad58083645a052815d29a83
+
+Count = 89
+Adata = 53cfdfd66d63c2924bd583487b90b1dd9ec199f90d660cb9c3a763a4776abfe1
+Payload = 43d2828e86f7856b
+CT = 2529cafa7d66deb81ad3b2be41dbc39df4c0145dcbae3e76
+
+[Plen = 9]
+
+Key = a19f6be062ec0aaf33046bd52734f3336c85d8368bef86ab
+Nonce = 7f2d07f8169c5672b4df7f6cac
+
+Count = 90
+Adata = d68d5f763db6111c5d6324d694cb0236beab877daae8115ecb75d60530777b58
+Payload = 13511ae5ff6c6860a1
+CT = b3859b757802ebd048467fd8e139eb9ee8fcdca45ed87dc1c8
+
+Count = 91
+Adata = f6e219b29884dab9ea9bad34d9ef8a50ae389c9a908de7154a1f2e894f27141f
+Payload = 7e7e33e1a07d4e8fde
+CT = deaab2712713cd3f3789d0ee8323ea2ee7a68aaaa9c49b98df
+
+Count = 92
+Adata = bcca002d69d9d1044c40ae741ea33ce6b8463f5a28d0514e044fdae2fe7d3c3b
+Payload = cc88980c73e6c5f0cd
+CT = 6c5c199cf48846402437c9fe3d9feb0485e6d7c04423b77a53
+
+Count = 93
+Adata = 39cac8f0825ffdb0668455933ad1581263a23b9e5f1305340528f0320d4b1269
+Payload = 34cb528f50d073cfdc
+CT = 941fd31fd7bef07f35b87e90a71ffe6c30bee1771078a701ab
+
+Count = 94
+Adata = 510a02a44d142c8e975d1d933f828fd7e47d28b88223f1698cf009dc3b079be6
+Payload = cbce3df86438a61065
+CT = 6b1abc68e35625a08c9e9c5be0657649448c38692e8d703d30
+
+Count = 95
+Adata = 40e0418cd52f74d78a8e18ed86210e3661a86d8574aedcee540340d8996d9852
+Payload = 80a2b835f8b0729a4b
+CT = 207639a57fdef12aa213e5f2bfd33101597cfae7cf334a8528
+
+Count = 96
+Adata = 1f2938b3bde19e1af91299c08638061dc3c1ea3284c259d415e996477cb37b0e
+Payload = dd04794e65ce34127a
+CT = 7dd0f8dee2a0b7a293516a7310fbd4ceb90d8db9a86cb6311b
+
+Count = 97
+Adata = cbae5b46e35fa2a279dcaa4c724b923805d4707412a84252b64228c91cedd019
+Payload = 00c4101052f54462d5
+CT = a0109180d59bc7d23cef6165af65f3522dfbfed0293db39ecd
+
+Count = 98
+Adata = d0f27c7f42892f3ad4c0029c5b698abb1d035ba5869a665b1de8861db6c055e8
+Payload = d0865445d3b26b6f49
+CT = 7052d5d554dce8dfa00726434c1349e3e874a2d6bf598d05fc
+
+Count = 99
+Adata = ab0f5a829a9319a74d5d5179aa0a410a0fcf52f344a7a896aeb1f7a6c5d398ea
+Payload = 7c7c8580b944ed3fd3
+CT = dca804103e2a6e8f3aab491e60fc97b3cb5248291e4866dcab
+
+[Plen = 10]
+
+Key = de1c8263345081d2dfa9afdf37675971135e178df554a4d8
+Nonce = a301bb82f91a582db01355c388
+
+Count = 100
+Adata = 9ad52c041390d0d4aaf65a4667c3239c95e7eae6178acc23fb4e70a852d483c6
+Payload = f777aba1fa70f94e6de9
+CT = 9d8bff6d2dcde77104ac6aba025abc01416a7ca9f096ab2529cb
+
+Count = 101
+Adata = b49c7e7b47870c1cc339c7c09aaacfd6115fa8a0f04990367eea10cfacb9d23c
+Payload = 349feebfbe58f93ea3c3
+CT = 5e63ba7369e5e701ca864acb200e85a0d4753a8ba226aca72f98
+
+Count = 102
+Adata = e61ca7310172eec16745a73e34516f65844eecd0dbc5566ac5213626b9096ef1
+Payload = 678a40b4c2c7df0e4c9d
+CT = 0d761478157ac13125d87869784e3321183d8c044657a020e9b9
+
+Count = 103
+Adata = 690f5e5d8da6cdb0f492e80449e152ffe88fea9742564d8383c79cef739a7f74
+Payload = 2b81e0533313664bf615
+CT = 417db49fe4ae78749f5070634d00b1facf0e9e9979ca257a71e2
+
+Count = 104
+Adata = 78e34b0a1d61ccd411cbfd306ea2ef3ce89c0b085deb4cfbaec2ab72ce16daa9
+Payload = 1ac63aa38a206d8e7d68
+CT = 703a6e6f5d9d73b1142d994630ed92e2973b22773f229b45bdad
+
+Count = 105
+Adata = 51bacfcf87ea11da34b76acba8c444792ec3db3c8ee6e600d69679975a682a54
+Payload = 027a7fd7897808ec7a56
+CT = 68862b1b5ec516d3131304571b015bb6b4651f1eb9f6fb3a7b74
+
+Count = 106
+Adata = 5159357a133e4743f903d05bd641da369a3675337760fcd2424a99221ba70b78
+Payload = 1086953d352e94a51a6d
+CT = 7a7ac1f1e2938a9a7328bb0e11ac4608081fd0702a137da0aea3
+
+Count = 107
+Adata = f567820865340314d46a17f520ff315efb6b33bdeda590ca9c4fad604c2d8e8d
+Payload = b8b148aafec4a035e9a7
+CT = d24d1c662979be0a80e252c9ec1317ce30dffeb4c9bf3fd0bbdd
+
+Count = 108
+Adata = 0cfec933831644b468724e808bb3d25fe8f15850ce513fc341da46089c845208
+Payload = 884242a87779d3921f8e
+CT = e2be1664a0c4cdad76cb691e32be3cdd9721a13aabad26dba58c
+
+Count = 109
+Adata = 8edc2b85d44297ac66bdd90d05d8df38124033d6a583bb8dda18a2246ba096e8
+Payload = 25c32770a299020d8500
+CT = 4f3f73bc75241c32ec45333a381be77800654aac335bf9220ac9
+
+[Plen = 11]
+
+Key = 248d36bd15f58e47fcf1c948272355821f8492e6e69f3661
+Nonce = 9e8d492c304cf6ad59102bca0e
+
+Count = 110
+Adata = 9ec08c7ed6b70823d819e9ab019e9929249f966fdb2069311a0ddc680ac468f5
+Payload = 33709d9c7906e2f82dd9e2
+CT = 9114d36b79b1918b2720f40cddce66df9b4802f737bea4bd8f5378
+
+Count = 111
+Adata = ba13974d95f2eeb367b63850609c53dc66c2710f682f10bef0142d48f851b430
+Payload = 84172985e7d194ba28a87c
+CT = 26736772e766e7c922516a12c94615be2bd81bd598f3022f5775a4
+
+Count = 112
+Adata = 5f16180bfac9b7483774cb0e1d57a43e9bf3cf03bf6fe758293aadcbbef25b80
+Payload = 9a34d32070c71d7de8f512
+CT = 38509dd770706e0ee20c042758e936750e335702542bc598e211c4
+
+Count = 113
+Adata = 4352057bdd1735a85dc0fc4dbeedc73279c27eb24a97641236f03f11cdafb8c0
+Payload = 2054a268b1f6fae4f15d91
+CT = 8230ec9fb1418997fba4870762bb2a7d04ba2ad251d595d0619dc4
+
+Count = 114
+Adata = ddf118ae403b2509e75eb7a26d17e73e527acbacfbe49a56fa3210169030144b
+Payload = f71afe9a60f08a0ef694aa
+CT = 557eb06d6047f97dfc6dbc27d85594da3fd35bd8498d7e389ee7cd
+
+Count = 115
+Adata = 973904409e8154132439926f0dc45c0d81bbbd5793f7f81e20eb818bfa374d58
+Payload = cdf5b47ff73306aa55c496
+CT = 6f91fa88f78475d95f3d80055936db383a8ad10b152046d721d3f7
+
+Count = 116
+Adata = 06bca7ef6f91355d19f90bf25590a44a24e5a782f92bc693c031e6de1e948008
+Payload = 9ebf93643854ea5c97a4f3
+CT = 3cdbdd9338e3992f9d5de5d57e228369e24fe955fd8924526af6e5
+
+Count = 117
+Adata = 8321f65baf9dc856ac1c24f3fee5c74d697eb0b50470d59d8f4a14b506e86c53
+Payload = 685116faa5cc527ac8bfa1
+CT = ca35580da57b2109c246b76c23abfb3b4eb39deb8da2064390dfa8
+
+Count = 118
+Adata = a4e7738038a5116592bb9d92d6d4ed191ab774310f6409e4e45fe907674c006f
+Payload = 9e8c4f1292e8d7e5179b34
+CT = 3ce801e5925fa4961d6222b4272c0639e8e6a1d356fb4fea86762c
+
+Count = 119
+Adata = 0df202431ee7f251a38aaf6aa8cd313782bd293af9114005adfe9faab253b572
+Payload = 3ecc2ba566c723462eb0ea
+CT = 9ca86552667050352449fc0633a0f9cdc9490231ec2dd69f6e35db
+
+[Plen = 12]
+
+Key = 77a67fb504b961028633321111aac2c30eb6d71a8cf72056
+Nonce = acadc0330194906f8c75ac287f
+
+Count = 120
+Adata = 8c18486d52571f70f2ba6a747aaa3d4b3ebc2e481ee1b70907dddb94bdfa0ca6
+Payload = 10554c062d269ff6dcd98493
+CT = 7f8b0cad79b545e5addf0b04ff4b0f2b2a5067283210aba8630d0306
+
+Count = 121
+Adata = 4e0b4771c7f6c66f9577c430611fdeec5702296ee3691b6bb8c6a81217edabe4
+Payload = 1c9e7875cf02129ac52daeb0
+CT = 734038de9b91c889b42b21275b16dbdf0b9be3c8c82ac652992d630d
+
+Count = 122
+Adata = 4a687e1d0a95ed2efb95b4c6b040999fcd35136811cd665f934d10224b6064c2
+Payload = 34575694dde459d195b7357a
+CT = 5b89163f897783c2e4b1baede629274d654ef5a4480e24f6bef3bc8c
+
+Count = 123
+Adata = b5330a8447d74a7987fb718cfae246b5c7e057991064eeaf823641a12bfce9f5
+Payload = ab20c8e8aab1aac1e4f64206
+CT = c4fe8843fe2270d295f0cd9142ab5407a08b648ce24e9955e28fe47e
+
+Count = 124
+Adata = 4f19bbc3135d7a216465b4c1df2616e8bfc3cc64af0bf52bdc42543f4d2448d4
+Payload = e556ca05bcd1991d2c9836a9
+CT = 8a888aaee842430e5d9eb93e151e94d311c7cd2c1b9048575076ceac
+
+Count = 125
+Adata = b6ffc7387b19786282bda7caad52eb37fbe7e557afcb80faaf57767e2a0f178a
+Payload = e5b665600a2aa413e117c538
+CT = 8a6825cb5eb97e0090114aaf61b71330d72506050368186a5619f180
+
+Count = 126
+Adata = 6a493c5ef3769ccc4101dbb2eb36e1e5bbc577a057ce0731203ba3f25b52497b
+Payload = 870864a611aa0475d120bc40
+CT = e8d6240d4539de66a02633d7ea21e36f99e5aab6ffa85994d13d5bb0
+
+Count = 127
+Adata = 8215753d9efc51325f182199e39f9082cc3fe524400f2a7434c68df7eb2b06d4
+Payload = 71afe8d00c6f2ea8c8b050d4
+CT = 1e71a87b58fcf4bbb9b6df437cc93a50dea11c5e0b19f14b9c8f16bd
+
+Count = 128
+Adata = eb8f198da6ee92a03913c6575343f6c749d2377a09430eb751b13c041e6edbea
+Payload = 7021f18b8f398a5999fcdcd1
+CT = 1fffb120dbaa504ae8fa534699cbfd1beafa2d2942f6812b8dfc88e6
+
+Count = 129
+Adata = de2ee30359e390db72f682c2ca0f14b72b60ff9bccd8c6fbd19a512b12add794
+Payload = affca856eb412f0b3276ae6e
+CT = c022e8fdbfd2f518437021f9337405235dce6161441caa25cc6007c6
+
+[Plen = 13]
+
+Key = 0d423519e4110c06063061323f8c7c95387776b6ee4e4b6e
+Nonce = 39abe53826d9b8e300fe747533
+
+Count = 130
+Adata = cdd9bf1b4f865e922c678ec4947ea0cb02e78bd5c1538f33aeb818ad3f47e519
+Payload = 4021ff104ff1dbd91e46db249f
+CT = 7953d3cd66d093785d123f65ba37f16761dd6aedbfc789ad96edf1490d
+
+Count = 131
+Adata = 342de5fe61e05c2e58ac2978a871fbdf186a7294ec5f85c4631c21b584231211
+Payload = 95050ca1d494bdb561d4840f8a
+CT = ac77207cfdb5f5142280604eaf8f8e855ae975a1fc64bcce3e7492e9d6
+
+Count = 132
+Adata = 7871482948d8d09d0a7491d915543082cb5fc7d6c1e82ee2218279f54c15c154
+Payload = c45823203b20821a48502f9c67
+CT = fd2a0ffd1201cabb0b04cbdd42017a6515156691b3161b747576078da4
+
+Count = 133
+Adata = 65781d018f27ca0c72a9fa9ab4648ed369646dd3ce45d7ad3a54f6b051f1b6e9
+Payload = e901661b7d47c9918244ee1077
+CT = d0734ac654668130c1100a515225cec7d2566a07cd78181ae94577befe
+
+Count = 134
+Adata = 05556b04dae5cde8525633d1862aa200c54af534e302d2cbd34ddc2b78532a60
+Payload = 5556f799d6a6cffb343f28c1a9
+CT = 6c24db44ff87875a776bcc808c133f51dac00f973fd42e0948fab70ea9
+
+Count = 135
+Adata = 151304e3e4f3c2d4d3227e035d849e0d3841ba00cf6cab1cf2e3e4d6cc760623
+Payload = 56bf26be81c7b55ef898e23981
+CT = 6fcd0a63a8e6fdffbbcc0678a4fe78bdeaa8d408ffe8fe64811aa87742
+
+Count = 136
+Adata = f870cc1fe67d6169279f905b0fe5fd9a0436c36498e4b7c6f584f00f7efe8784
+Payload = 36b304a72dbf4acfffa1d7d624
+CT = 0fc1287a049e026ebcf533970197228d155dda2bc814ff33ebeb9a7ffd
+
+Count = 137
+Adata = 5692c9d452ea1c067e62fdc554ddd2b18c8433d59067f971316797fd9853ae6a
+Payload = fb529eb5ae79a0830474ffbc98
+CT = c220b2688758e82247201bfdbde7ba03e144e34a4ab34791a372a2b8ab
+
+Count = 138
+Adata = dcf7fe16b7ca9e27ec3291103398eaa2e77c7b770b67f8858c215af4c523822d
+Payload = 6218c778955d9a56360f06c704
+CT = 5b6aeba5bc7cd2f7755be2862103c2eb5ef0657306d12b753a0694efcc
+
+Count = 139
+Adata = b0f1e2668611dca86e8d0f58c2a4cf4a9472d81ba013e271800b75841fe5ffde
+Payload = bf6b143fb713a81c965c5a9d8d
+CT = 861938e29e32e0bdd508bedca87cc6119151393461ecf65bfe06e0163b
+
+[Plen = 14]
+
+Key = a60cf7ceb62bf3118532bc61daa25ce946991047f951b536
+Nonce = 7499494faa44a7576f9ed5580d
+
+Count = 140
+Adata = baa482c64eefd09118549a8968f44cfea7a436913a428e30aa4ab44802a4ba35
+Payload = d64f9426febce6a84c954dd5ded5
+CT = f7580f17266d68237747bf57c7ed8242ac1a1979c5a9e7bc67d7698c7efa
+
+Count = 141
+Adata = 2ad8ecc5ac9437ace079419f17e6018625b10490120fbe2f12b41e64b73b653c
+Payload = fcd9b67717bcadeceddea336c671
+CT = ddce2d46cf6d2367d60c51b4df4918abced491c063d8bfd0e7341febddc3
+
+Count = 142
+Adata = 7585ee95e74d7a869bdc0b59ca9939dd57e7b09afab179079d467bfe0668416c
+Payload = 18232d7c792fb80e6ca1c8f2c3cc
+CT = 3934b64da1fe368557733a70daf4659ecbb3dbfbcdb0f913abedf8afab05
+
+Count = 143
+Adata = 41be6ca6188f34da1ce83fb8c27652848dc2a71e32bd3631fb9b33ae69e5d879
+Payload = 764dbefb42644d18d23e5e456868
+CT = 575a25ca9ab5c393e9ecacc77150a220d5ec0b5397d6b4e323b5dc7d1b63
+
+Count = 144
+Adata = 197cee3b15320d57996191dd13106fbd4546a5cc3d2bcf0c886af52ea3d9a855
+Payload = 8003586af34bdd0acae4f5547394
+CT = a114c35b2b9a5381f13607d66aac3a5f713f5d0793b732c6e114805cc9b3
+
+Count = 145
+Adata = ee0b647a47656a6e9e09c2d64f734a2cc3fd45b7ee52fea51c24af59ee22a006
+Payload = da143266516a4145cde92c93f961
+CT = fb03a95789bbcfcef63bde11e059ed90e8650bc16f590789dcc625b9e63d
+
+Count = 146
+Adata = 9f5bfffa01f1425d95465723735b49fc1dffbad06cf37a00ca4b59efa21739c1
+Payload = 3842b033f3ca31a6f8e5a638b39e
+CT = 19552b022b1bbf2dc33754baaaa6bda183dda1aef021d92210e27cdd7c5e
+
+Count = 147
+Adata = 64e92ba2748d07f602808f7c5ded15cb0e43140400d37107e59a01e7d45b4c9c
+Payload = cedf60b17185fc71b957cb759260
+CT = efc8fb80a95472fa828539f78b585e4087fb314f893937e95383e66745c0
+
+Count = 148
+Adata = 6ebcaeb4bd44ff4c990305ac64264dfe2ada5f7cd4b294eb9f492865cd28905c
+Payload = 035f449bb28f43365f4a0556096a
+CT = 2248dfaa6a5ecdbd6498f7d410520a71ce5813c578532b742d704fa92276
+
+Count = 149
+Adata = db617207dccd1f6baea5f2242d5e577adb8d69af3bb1707a7a53a8b75452455c
+Payload = 9a2a45424f4965a71270e77cc403
+CT = bb3dde739798eb2c29a215fedd3bb7fc45d15d6939668065d2282fc589c7
+
+[Plen = 15]
+
+Key = 82d4bc9aac298b09112073277205e1bf42176d1e6339b76c
+Nonce = 70325ef19e581b743095cd5eb1
+
+Count = 150
+Adata = 6d14bb2635c5d0ae83687f1824279cf141173527e1b32d1baf8a27f7fe34a542
+Payload = 25a53fd3e476dc0860eeeea25fcb0c
+CT = 4a1cfd0023557a184b929965b0a445cb3993ca35acf354cb2b4254ff672e7f
+
+Count = 151
+Adata = 9f8a56fecf32fa7d50f033b2524c3d798e254bc87245cce57e38edd6ee5d5f1a
+Payload = 797dca47597947c057789433309b67
+CT = 16c408949e5ae1d07c04e3f4dff42ea25b5eb103bac224cad66ec0f100875c
+
+Count = 152
+Adata = 86f15b8b677b7655f358a2c7fd5785bc84d31e079ed859b6af88e198debd36fc
+Payload = e61f9a663d3a2b50ea2f9475971270
+CT = 89a658b5fa198d40c153e3b2787d39b598cc6ec2295c586e7ae270a01846d1
+
+Count = 153
+Adata = 4de6bd43c28143ea5d40919cb5330a7e674f5bd8aeb7b178343a2851281c8668
+Payload = df990c42a268950677c433555319b3
+CT = b020ce91654b33165cb84492bc76fa97ff732093f7d0a96b30d8cdfd1bd583
+
+Count = 154
+Adata = a5c3a480dea1b2a1e3a0ce416148b04f60104217c9d24a5b267b4aa6aa07a4dd
+Payload = a7e72fb4bec3768594a2f6f5b4379e
+CT = c85eed6779e0d095bfde81325b58d7ad98e32a9156e125ff021ef6951b0c40
+
+Count = 155
+Adata = 51b041f1666c59045d333fe63d43457107e1adad34fcbf965e0d191f3e414776
+Payload = d3d1550047cf90eceaea7000d8e280
+CT = bc6897d380ec36fcc19607c7378dc9390f10df08a84c21031626861b201fbd
+
+Count = 156
+Adata = 22f8a3c9d85b2d53ffd92078d3c94373f855ecd01a8ac521d1abd0f2c7cba9ff
+Payload = 756412c4ee6416f2f4e0342011cde2
+CT = 1addd0172947b0e2df9c43e7fea2abdd5d840bb8c4348a9a548482e6b93043
+
+Count = 157
+Adata = da08b14e1b770b81faaf1e59851df1cba8838cd63bef141340ee378e65fdcbd4
+Payload = 666e4a4b3f6cf598aa763cdada4109
+CT = 09d78898f84f5388810a4b1d352e403f0d49927cd6103e3705ba201e8f73c6
+
+Count = 158
+Adata = 2db3ded385ef9c82fd39ea5782d9befe66e8a070066269b2aa7c4bbfac3711c3
+Payload = eb9013a74352b0677a88bd73052477
+CT = 8429d1748471167751f4cab4ea4b3e2d97f7c2b3b42bf570cce79bf30ccc50
+
+Count = 159
+Adata = 194c9e1eaa8e376f9c41bf33823efa28ee60a9213438665b7002cf0fcad7e644
+Payload = e3126400e3c571a4d39b37bc938a22
+CT = 8caba6d324e6d7b4f8e7407b7ce56bd3c2a4fc45d014a0c54edab2930a5bdc
+
+[Plen = 16]
+
+Key = 6873f1c6c30975aff6f08470264321130a6e5984ade324e9
+Nonce = 7c4d2f7cec04361f187f0726d5
+
+Count = 160
+Adata = 77743b5d83a00d2c8d5f7e10781531b496e09f3bc9295d7ae9799e64668ef8c5
+Payload = 5051a0b0b6766cd6ea29a672769d40fe
+CT = 0ce5ac8d6b256fb7580bf6acc76426af40bce58fd4cd6548df90a0337c842004
+
+Count = 161
+Adata = e883dd42e9ddf7bc64f460ba019c28597587d06e57c3b7242f84d5e7d124ab81
+Payload = b31dfa833b0cda20eaa84d2ecd18f49a
+CT = efa9f6bee65fd941588a1df07ce192cb8707b1a4d9ce3def33703e19eaab6dda
+
+Count = 162
+Adata = 409401eb49cd96b1aad2525c5124c509766ff86f88b2011c67a1d501d3485e31
+Payload = 24bc8dc1e2354667b79ba4d7061448ff
+CT = 780881fc3f66450605b9f409b7ed2eaefd9041ddce37d88e79fba28e385b2327
+
+Count = 163
+Adata = 83bf5c063bf1febf71688a832d615e09d6f14badedeaeb6ffbfe343fc7274e78
+Payload = d41d95a1d2326e12cba636910ddfca53
+CT = 88a9999c0f616d737984664fbc26ac0291d971893543868bd8c69078fc2bdb24
+
+Count = 164
+Adata = 8cdd70524e24318c64d681aa27752d4c86c5348c05c9e48f06ed41594785a6e6
+Payload = e8a4b80e081919f1912542d3136764f2
+CT = b410b433d54a1a902307120da29e02a3866b23e4c991f4007e56a1ee9265c6cf
+
+Count = 165
+Adata = 615985f63571c0f94ffcd4df77326abd41e84f388f061d97573a181da7ee5695
+Payload = 7fca7388058d6d1438b6eee0292131cb
+CT = 237e7fb5d8de6e758a94be3e98d8579a2abbea637996b954027efa9464ced6b9
+
+Count = 166
+Adata = 17aa90f2bff0419011b01dee62be31354431cbc89f22332704b096143d4743f4
+Payload = aa540554ee80dbffa475f702d862d6b6
+CT = f6e0096933d3d89e1657a7dc699bb0e757bc8d48d82ebefc76f17323c518ecc2
+
+Count = 167
+Adata = 85288b2be612e42335c144fb058a7dcd567c382fbcee3962bd5be4cc7a7000a8
+Payload = 6d745581831edba437e70ea89cad217d
+CT = 31c059bc5e4dd8c585c55e762d54472c65470c81e487a26cdc26830f2b51bd1c
+
+Count = 168
+Adata = 288f9f52824b54b608dd7226a0a89d43ae8c05107dbae761e1c756911a003b74
+Payload = 811a61869c7a6b2aa9ac0fcc523ef784
+CT = ddae6dbb4129684b1b8e5f12e3c791d5a3043722be9448c3ef144f2288066f75
+
+Count = 169
+Adata = 51dbaba180d4746edbb3420461919b5b735797bf7dd19f84d80475f5efc2748d
+Payload = 378a4e39817f308ed1e639f943b694c4
+CT = 6b3e42045c2c33ef63c46927f24ff29549aba95e04e11cf18ddf73773d395c1a
+
+[Plen = 17]
+
+Key = 3cf8da27d5be1af024158985f725fd7a6242cbe0041f2c17
+Nonce = 07f77f114d7264a122a7e9db4f
+
+Count = 170
+Adata = 30457e99616f0247f1339b101974ea231904d0ef7bd0d5ee9b57c6c16761a282
+Payload = f6dd2c64bf597e63263ccae1c54e0805fe
+CT = ce3031c3a70600e9340b2ddfe56aa72cffdc5e53e68c51ee55b276eb3f85d2cf63
+
+Count = 171
+Adata = 42370f115bbd4b31bb99fe82cca273b3c93072f96b2e09bdc6718d926d48db69
+Payload = f45fee3e086c28a7c590ec0cc05b972664
+CT = ccb2f3991033562dd7a70b32e07f380f65c6328a7476db2c10ec7bca3f6bd3df42
+
+Count = 172
+Adata = e2d692c5678124998a7862b8e87276b0a19e293a609103c99583b36305bcb2b0
+Payload = 4ad69a8ab433ed8909825c71f6081f64a7
+CT = 723b872dac6c93031bb5bb4fd62cb04da68080f0d51d3b8841683eff361984f7e4
+
+Count = 173
+Adata = b5b38791160959dd2836ec1ad25286c1ba410d7212347a95b5738a3d725bb651
+Payload = 3d47071c13f994cb42fb2887e5c6e53a54
+CT = 05aa1abb0ba6ea4150cccfb9c5e24a1355c1428ef5d40bc9e363817f219af2ed56
+
+Count = 174
+Adata = 02691171795a77d1e3bdad513b6fab5b50d1def81bcc1df15012de3433a6aa78
+Payload = e8a4b80e081919f1912542d3136764f264
+CT = d049a5a91046677b8312a5ed3343cbdb65fdfb37dfd1236198035c8461b304152b
+
+Count = 175
+Adata = 7371d8ae79e628f53ffede174eb068db2318c05e2f6d94ad2233a59369b16db0
+Payload = 549aa84bb182312dd016e3107f3b1f9c5b
+CT = 6c77b5eca9dd4fa7c221042e5f1fb0b55acefde0e84a3ce0cb702ceb73ca1dd9a5
+
+Count = 176
+Adata = bb1e1f51082e470f7245458ec902098e1e41d0ed28efa31be71d21ce86527ff7
+Payload = 31a12ca6d69db2e6e252474d7d59ed6552
+CT = 094c3101cec2cc6cf065a0735d7d424c53f8441d46dc5456a587b765e1a820c11c
+
+Count = 177
+Adata = 7584f57b49e95bbf5a67153e18b9b8c4722644e8f611613c39cbe8c679aba5b4
+Payload = 5bb121e70452a954f420a56aca8cd5c059
+CT = 635c3c401c0dd7dee6174254eaa87ae958d0daddcfcc92349ef059149c54a25cd0
+
+Count = 178
+Adata = 505687182c06e6f4effe7fe03c1f436199a9015380ff21d0b2aa9453cfa10b1d
+Payload = 5b80d1cf745b14cb71cbc8dfe0bc7c7358
+CT = 636dcc686c046a4163fc2fe1c098d35a5948c1242b89490c6ee69dedc1e91286ee
+
+Count = 179
+Adata = 7ebb051741145a3bad87131553375c6debcbcecee9b79ee451bd1429cbb33fc1
+Payload = 79ac204a26b9fee1132370c20f8c5bcada
+CT = 41413ded3ee6806b011497fc2fa8f4e3dba2ddd54e509bca0a45dcf2fd514e1496
+
+[Plen = 18]
+
+Key = b46a3a24c66eb846ca6413c001153dc6998970c12e7acd5a
+Nonce = b79c33c96a0a90030694163e2a
+
+Count = 180
+Adata = ea9405d6a46cac9783a7b48ac2e25cc9a3a519c4658b2a8770a37240d41587fb
+Payload = 56d18d3e2e496440d0a5c9e1bcb464faf5bc
+CT = 01baba2e0d5b49d600d03a7ed84ee878926c0ca478f40a6fbde01f584d938a1c91bf
+
+Count = 181
+Adata = 72340d595f3dbd23b46513f8f2b73b6249328c705e7968084bcb647fe734a967
+Payload = 7a76eac44486afdb112fc4aab939e4d1eedb
+CT = 2d1dddd46794824dc15a3735ddc36853890be4646492b6f4cb169383c075756073b6
+
+Count = 182
+Adata = d5c87c649579da3f632ba95cb0a07c924095e4bdd4e0376e06bb90e07460172e
+Payload = 48348c5ec996f7a97ef0ba2cd6885572fe64
+CT = 1f5fbb4eea84da3fae8549b3b272d9f099b4f584289f560cbf76606942fe1a92dd63
+
+Count = 183
+Adata = ffa6277395d31d5db13034d362228a87610e441c98ca3038e252a9db12bdbcef
+Payload = d5c58f10e1a03d8a2501d1eaf5fcdfff3ae5
+CT = 82aeb800c2b2101cf57422759106537d5d355964f5f5532d7cddd7207f0e9a6aace9
+
+Count = 184
+Adata = daf83d02a9bd992ea58c23e7ad18d41796314bae20e864e729f40ccc215454fc
+Payload = da2a863ab1c58ddde320ecadeecac9c5d2d8
+CT = 8d41b12a92d7a04b33551f328a304547b50890ae047e35aecfc38ffdc07e7d8f5705
+
+Count = 185
+Adata = 21ddad5f550044dc5cb123ade17eeef549c4e0173b216bcc602c1e736764cca8
+Payload = 4573969afa831c244817230406fe51183091
+CT = 1218a18ad99131b29862d09b6204dd9a5741b2bdf539ceaa35015712dd15265ca476
+
+Count = 186
+Adata = 9228265ae5c3daf1485ff8011738da508bf2a73731396c5d9aa56fc554e0c00b
+Payload = edf5557e15473b747a819398c9ac1459ffdb
+CT = ba9e626e365516e2aaf46007ad5698db980b241412124ae20b84c13b0c3671d305c9
+
+Count = 187
+Adata = c0a2ff0de21b3ba961e06015ccd71374856a65a4c57cf8cde0a1643aca8ed868
+Payload = e139263478900df806a0f3446bd6600c1aeb
+CT = b65211245b82206ed6d500db0f2cec8e7d3bee9803747bf9fa63412bfc4e10aea89e
+
+Count = 188
+Adata = b54378f031a31cf3985f573829c9ffca14616742e0a7e03b0a2d7f05eff0219e
+Payload = 660eaff0f113eaa2f5f7ad4b62bb849a3a25
+CT = 316598e0d201c73425825ed4064108185df55afdf430b57845dcf622d4f25cdeb2a3
+
+Count = 189
+Adata = e67f35c18a9336469eae23040f98f52338ca8d0cab269ac32fe6bc7605d3ea56
+Payload = 0f89897271f5d0349d57399005ea60c0cadc
+CT = 58e2be6252e7fda24d22ca0f6110ec42ad0c7ed4c04c4b4dd585891ecfddeab8cc87
+
+[Plen = 19]
+
+Key = 7b71045ccef735bd0c5bea3cf3b7e16e58d9c62061a204e0
+Nonce = 2b9ecfd179242c295fe6c6fa55
+
+Count = 190
+Adata = b89166f97deb9cc7fdeb63639eeafb145895b307749ec1a293b27115f3aa8232
+Payload = 890d05420d57e3b3d8dbef117fe60c3fa6a095
+CT = f842ff6662684de8785af275fa2d82d587de0687ebe35e883cbd53b82f2a4624c03894
+
+Count = 191
+Adata = 4392c3043287dd096b43b4a37ea7f5dc1d298b0623ccbf4fd650a49569a5b27b
+Payload = 6b425cdcdf8304e7fbb70b2973d55e6940025b
+CT = 1a0da6f8b0bcaabc5b36164df61ed083617cc807d4824f0a98db2d87365a42ca3b80e1
+
+Count = 192
+Adata = 9b4fc98fcdcf485205e7054bc9d1e02d0d8584420537e20d3821de2fd6824787
+Payload = c8bf145fcffbafd6cd1a4c5b6cedfe008aacb2
+CT = b9f0ee7ba0c4018d6d9b513fe92670eaabd221404e631735c544edeeb4c0105c55bf0b
+
+Count = 193
+Adata = 45622e1472542be2f63f463d253617eafd4f2ad609f9020884905dd5c22fba53
+Payload = 12b5a76faedf6f855e328c2cb87be8aea78c5e
+CT = 63fa5d4bc1e0c1defeb391483db0664486f2cdc16a4cf37e8e96eed1217d21133e83d1
+
+Count = 194
+Adata = 958689aea3c6cd19020eff9d635ef44ee0793424df38fdf13a238b969d429777
+Payload = f0927c3cb0a876d7877466507da8bfa0bd9a16
+CT = 81dd8618df97d88c27f57b34f863314a9ce4859facf81a636351f6e67d6ec12636ae0b
+
+Count = 195
+Adata = c22911efc36fa739048af0c951ef2449bb3605c52f65120c4d71fe5976026032
+Payload = d2c5d4e2362f19c99de66da7bd9c495c03d9a1
+CT = a38a2ec65910b7923d6770c33857c7b622a7327ce73a7e2db69d30441f89a03fd0e84e
+
+Count = 196
+Adata = 799da61e2c10ebb4783f618b8f69da7704a1b2b925cebc228af57d7ceebb9825
+Payload = 1c9d7f5b329ef4d384b8b7955a20f8a3fc15cd
+CT = 6dd2857f5da15a882439aaf1dfeb7649dd6b5e8d787a9d06b8533ca96fb1db8aecc8e5
+
+Count = 197
+Adata = 14a8e18afe0b9fe18ddfd754219a7e18ed36f419f8262d91678e10daffb31c81
+Payload = 3a64414c3588d7c26871d7d054ac6c8420d491
+CT = 4b2bbb685ab77999c8f0cab4d167e26e01aa028ff5f819d552c08054b5ac02063e102a
+
+Count = 198
+Adata = 7294a8b4ad97c81969e4a2876a3dc0ee322d554726997dc9ed98c5601985ee5b
+Payload = 545dd71bea9967e07a89f84a2027aacd132187
+CT = 25122d3f85a6c9bbda08e52ea5ec2427325f141cde5af8fada67c47cbb5787a6b2d9c9
+
+Count = 199
+Adata = 99294b22d73805805630fb416d20d4fca67419ab660ff45cd19a3729e81b9f69
+Payload = ec1b17b885c018272652453f47fa6e9ed972b9
+CT = 9d54ed9ceaffb67c86d3585bc231e074f80c2a7412640b179bd3e8a417dc38462c16e8
+
+[Plen = 20]
+
+Key = dc7c67715f2709e150cceff020aaacf88a1e7568191acbcf
+Nonce = da56ea046990c70fa216e5e6c4
+
+Count = 200
+Adata = f799818d91be7bab555a2e39f1f45810a94d07179f94fe1151d95ab963c47611
+Payload = f383bd3e6270876b74abbb5d35e7d4f11d83412c
+CT = 377b5df263c5c74f63603692cbb61ea37b6d686c743f71e15490ca41d245768988719ede
+
+Count = 201
+Adata = 69adcae8a1e9a3f2fe9e62591f7b4c5b19d3b50e769521f67e7ea8d7b58d9fc8
+Payload = 615d724ae94a5daf8d27ad5132d507504898f61e
+CT = a5a59286e8ff1d8b9aec209ecc84cd022e76df5ea9bc8cfaf2a1734a792076618c4b9690
+
+Count = 202
+Adata = 4586f73a1f162b2cdb65f6e798a60b5f48938d40b4612d84c1f39244f14efdce
+Payload = 6e923e1f404002aa5cf8f8aaf1b9772da425e21c
+CT = aa6aded341f5428e4b3375650fe8bd7fc2cbcb5cc5122df904b052e4d5580fdeddf5297c
+
+Count = 203
+Adata = 9f7ae892e5662803408d4d062265846441a43c1fa202da59f640ae722a692671
+Payload = 68115771505daa18bb3ce90054bfb7d077e1f37c
+CT = ace9b7bd51e8ea3cacf764cfaaee7d82110fda3ce0ba1bb1af18e15ade3316c21d6b41fb
+
+Count = 204
+Adata = 1f0769a7ae82bd985661e031c4a892c15d3ef37bdcfb45243d02f40fdb51d34b
+Payload = 681fd2a324b3fea4cfebed567ae4546ba373c8f1
+CT = ace7326f2506be80d820609984b59e39c59de1b1dc71e342fbc44289ef7e53e28edf3839
+
+Count = 205
+Adata = bf957ef5ab2805e58ea752da5793f7f23d98fce1b2b67738929e5de8a15f9801
+Payload = a7b9d2d069941e8b943706a02d2847ea713bb103
+CT = 6341321c68215eaf83fc8b6fd3798db817d59843ced1fb4a2a3e349aa590aabbfc3d13bc
+
+Count = 206
+Adata = 833264c1bebb597043b4158087cb651960915d9023189c9509c0d2aed84e7fe4
+Payload = 9b946e8198ce69d2173e970f4e0c103a47ee4160
+CT = 5f6c8e4d997b29f600f51ac0b05dda68210068205079f6c2739e2b789b6e3d3c60389374
+
+Count = 207
+Adata = 94c8414cbbec52e2d73bb8f02ef687c91432495c0c744666317d02e6d46706d2
+Payload = 81ac4618f3db6bcf9bbf67220b7671be4bb4f8a2
+CT = 4554a6d4f26e2beb8c74eaedf527bbec2d5ad1e22a02f287db7217148317d897f65f6a0c
+
+Count = 208
+Adata = fced1131dab3dabdc1a16d3409fa09a90ffe02f0e2c814a63f77f771c08c3389
+Payload = 90851933d4d3257137984cdb9cba2ca737322dac
+CT = 547df9ffd56665552053c11462ebe6f551dc04ec362df9f8b41b1dd4821f8f14e9e633d7
+
+Count = 209
+Adata = 495dfcf91f4735ab35c6bc4deef8468bd988e4099cd291a32b4707f93e13d82b
+Payload = c14ce6d57f0fe7367331c9fe159ae1fb8f1ccb2c
+CT = 05b406197ebaa71264fa4431ebcb2ba9e9f2e26cf61ffb51e56497ca9f39c6665fcbdfa8
+
+[Plen = 21]
+
+Key = f41e369a1599627e76983e9a4fc2e963dab4960b09ebe390
+Nonce = 68ef8285b90f28bcd3cb1bacea
+
+Count = 210
+Adata = dbe3e82e49624d968f5463ceb8af189fb3ad8b3b4122142b110d848a286dae71
+Payload = 81ad3f386bedcbf656ff535c63580d1f87e3c72326
+CT = 9f6028153e06d14d30b862a99a35413413c04a49dc6f68a03a11cf00d58f062a7b36465d13
+
+Count = 211
+Adata = d9acfd611e5bbb08c5d05d56791b8aebabf8d69734ec89153c91a1f65b2e1adb
+Payload = 35f6bb3f6a388f3a5a039b0a495b676d0b928aeb19
+CT = 2b3bac123fd395813c44aaffb0362b469fb10781e3ca1fb470b666523a19f83481f16481ed
+
+Count = 212
+Adata = 6003b771afe4e99e1ef1ed4a31b10540d95f4ac49885f0c8e5cdcb63d213127e
+Payload = 6aa7e3802b5a29d4f9ca88eb59f94af783d1054466
+CT = 746af4ad7eb1336f9f8db91ea09406dc17f2882e9c53cb05bfcd64da2b45c2e9a89a380b49
+
+Count = 213
+Adata = c371644275a6290821e7d308714bec2bf62d36c30f7fa77a0d60b28894f1c82a
+Payload = 13332b67ba5ba18137c306bd860dc3eb0a9a0b871a
+CT = 0dfe3c4aefb0bb3a518437487f608fc09eb986ede048f70fbc680cf7092b3dd90b943fc6e5
+
+Count = 214
+Adata = 8eceb15300ec4220510ed5b7deb3429de6ae5f618e1c222c28990a9ab4b4bac8
+Payload = 05981dc26a1db2d8e2c3d85ea9a4d1dc3432d9edc4
+CT = 1b550aef3ff6a8638484e9ab50c99df7a01154873ee386f33c0b8da8d0c5934e617dd618e5
+
+Count = 215
+Adata = 96d1cf3690c48c77a155ce13e67bbd62e6f03d88c893c1f7c30a6435d5ab36e0
+Payload = 60249343a8cd4d33c6edc583ea7e5c221ef3064787
+CT = 7ee9846efd265788a0aaf476131310098ad08b2d7d3d2db1360fb1121893f4d197731bce4f
+
+Count = 216
+Adata = 379bbc9f919dc2a8687f2a86cc9c3291804240a9b566c58519956848102e6155
+Payload = 79003a8d3d20d412f468f11712cec4d37cee847440
+CT = 67cd2da068cbcea9922fc0e2eba388f8e8cd091eba335ce1bfafc0948f2523e75f2aad86f9
+
+Count = 217
+Adata = 9bff9c9a8f94cd77e7016748da31f86d1b9c68465cbf954511c93a4776981524
+Payload = 7d078a8b200514a00628756250d410f7a0f8a769e6
+CT = 63ca9da675ee0e1b606f4497a9b95cdc34db2a031c7dc265e281307f0f4c38cddc556ac725
+
+Count = 218
+Adata = 25125a4668c31dc2e8a68b6c4c95ad7cf9322852e371b415a357d09acb01b587
+Payload = d9b0eaaff786165f882f41a98dbc0c355b3a1aaf40
+CT = c77dfd82a26d0ce4ee68705c74d1401ecf1997c5ba61c78a2f85a447c3e62b6197d65b9065
+
+Count = 219
+Adata = ad34d8f0902a5b79fb145b8206bb4d3b77e0bd8ae2d0964815389eacb33b4007
+Payload = 17b517ef577f588da374340d2522cc9ea642c8d8ae
+CT = 097800c202944236c53305f8dc4f80b5326145b2540312d067c08a9b4400e1df8bb7ed671a
+
+[Plen = 22]
+
+Key = 3289e59e3a7b29bf4a309afc253030bba4b9bdd64f0722f9
+Nonce = 30259ce106e9bd7a8bacbaf212
+
+Count = 220
+Adata = 2870bd9a26c510e9a256920899bbc77a4eb9b53f927045a943d5ed6b13638cf3
+Payload = 53911a67b65738f87fc7c20d6db8044bde1af95838d1
+CT = 70cf37d4b6f7e707376b1574ce17c040b5143da47abb2fe9afafc2fccd98ccf63b0fdec30eac
+
+Count = 221
+Adata = 611032a95ee87f89ad6be7c0fed8bd245c5f81076087b3bda4cde5587b8d14b6
+Payload = 46917e38b8a542296d290d065b0aa7c8aaa38950c386
+CT = 65cf538bb8059dd62585da7ff8a563c3c1ad4dac81ec102dfd8c231d6a355f079c213ce6858e
+
+Count = 222
+Adata = 2e7ea26d1cceaca3b7862a7a8469e366b52ec27ca127e3317222ee651d8da4a0
+Payload = b527828c89f674dc6f024f8cdd80c694bb3ebd57b2d9
+CT = 9679af3f8956ab2327ae98f57e2f029fd03079abf0b36df11febe34dd568da12c374674b9ac4
+
+Count = 223
+Adata = 0bf4413010daec585de34142224d1cad3072f9720f91ac664ad152820e838741
+Payload = 78230f73f9c0150f630eca4cd679818551d449db82e6
+CT = 5b7d22c0f960caf02ba21d3575d6458e3ada8d27c08cb2916540d9439b832aa44236a7e187ac
+
+Count = 224
+Adata = 2e7cae3306582eb5bad148247aa6c6ec943f8748e84b8a069ca9488b11844716
+Payload = 847bb12e0e56fa07a086eeda5907ae148148fa4107d2
+CT = a7259c9d0ef625f8e82a39a3faa86a1fea463ebd45b80d0768a18dead55700901408aa3f901a
+
+Count = 225
+Adata = 63036dc4ad13aee5dc1832e867f7538da108188fec7b08262af440d07579c451
+Payload = ec59e208c4bb429a371f1b3ffdf07fce5dea8a05f0ce
+CT = cf07cfbbc41b9d657fb3cc465e5fbbc536e44ef9b2a45f2073605d2a441805b6ff89d8beb68c
+
+Count = 226
+Adata = f9ec5ce4b63156d57e451eb67ab6d7a59cc397f43f6d26dc07d1036f0fb4a8cf
+Payload = fb12d94bd21b5748b23132a03065c78dae65a0bd2cfb
+CT = d84cf4f8d2bb88b7fa9de5d993ca0386c56b64416e91dcabef6907811c6b7df4e74c7a63d83b
+
+Count = 227
+Adata = e13a204e16f42bbf4716e95f1cb7e125ffac66a87f591c8ef2c7b8485ff707fd
+Payload = 239fa31d4a65de0318bfc5b60a06d706c129dcf255ac
+CT = 00c18eae4ac501fc501312cfa9a9130daa27180e17c626aa8aa37e858cd990f5593d9ef35f2a
+
+Count = 228
+Adata = c4591c3ad984a1e189c526b719212f8248289eeb277827272b8205d78191eb2d
+Payload = 57caadbb1a56cc5b8a5cf9584552e17e7af9542ba13e
+CT = 749480081af613a4c2f02e21e6fd257511f790d7e354d81e424d6b4528901ae46fb35f8b3106
+
+Count = 229
+Adata = cf4795bc7f43c30d3c3a8fd1b8a9d77d69bf59eb8b59d0f464315f40cb52335d
+Payload = a68c74e05f0a44d4a0372c0e5915b83d8e6729efacbb
+CT = 85d259535faa9b2be89bfb77faba7c36e569ed13eed1f25a4bfda35e1390f3f16f638dcd4047
+
+[Plen = 23]
+
+Key = 40f1aff2e44d05f12126097a0f07ac0359ba1a609356a4e6
+Nonce = 0df3fc6396f851785fca9aa5ff
+
+Count = 230
+Adata = e9699b20b0574fce8b5cbc4ef792eb96e2c1cce36b1b1f06ea2a95fe300633cc
+Payload = 8d98c580fb366f330dbfda20f91d99a0878b47efd14c6d
+CT = 579cdf9da62a2df471e03450516adb4ce99ae0f70b1776a39c3b429a1f922fac0b59e29a122e43
+
+Count = 231
+Adata = bd94c9ad6253c25dc417f87b6e52e03621ccf4b3bff5b402677aeb51e216335f
+Payload = 7391ba60fabe2c632bbaca16af9a235b2c7dae61691c0b
+CT = a995a07da7a26ea457e5246607ed61b7426c0979b3471067bf538e40f9366adf8758968f06ce8a
+
+Count = 232
+Adata = 4f263cda4a50b0e5379ec2fb546b326a07943527c1d175c029455a917753883b
+Payload = 7e1e93a6ca35a2c0e4f08fdb2e7ee22b9f486f0ab919e2
+CT = a41a89bb9729e00798af61ab8609a0c7f159c8126342f964a1199251b54f419720a30de83161de
+
+Count = 233
+Adata = 4d43702be4f0530319555d7f1a3356160f6cae48051f12e22a153d7e405c1149
+Payload = f94ff053c7413f34f96eae41fd1ac101151069af5a9428
+CT = 234bea4e9a5d7df385314031556d83ed7b01ceb780cf33b417e4cceb8dcf45ef33cc0007755bbc
+
+Count = 234
+Adata = f4d7978fad36223623ccb5bb18a7373cba8a6e3b1c921259e319266042db8887
+Payload = ba0716355fffb8ef947d2a15eb58375a1ff1084c566990
+CT = 60030c2802e3fa28e822c465432f75b671e0af548c328bd35aed57f49dcfecf248cf9d246ac024
+
+Count = 235
+Adata = 12e4fe727b1f27a619dd67bb976ddc2b18b2ef8b7184290d9553494a500d933e
+Payload = 872940780a94680a791c937994ceafd2c8b7a22b5f4927
+CT = 5d2d5a6557882acd05437d093cb9ed3ea6a6053385123c97cda0e04d2ff65c2e06a8276bdf6f97
+
+Count = 236
+Adata = 2c16724296ff85e079627be3053ea95adf35722c21886baba343bd6c79b5cb57
+Payload = d71864877f2578db092daba2d6a1f9f4698a9c356c7830
+CT = 0d1c7e9a22393a1c757245d27ed6bb18079b3b2db6232b3494dd2ee0a0fe5bfc9f69234c8142ed
+
+Count = 237
+Adata = cefc4f2fb796c2502329ca3d8f8af3200dd9edb8f164e15acec90536a15b6fdc
+Payload = cda681aa3109ebf5f21ee3a849098ea3a551e844fae4b4
+CT = 17a29bb76c15a9328e410dd8e17ecc4fcb404f5c20bfaf9008ead8e923997508eebf5e776198dc
+
+Count = 238
+Adata = 94fc7eb8febb832097ba6eecd2697da91b5a8a1f2248f67a7659e0ac55a09a0d
+Payload = d4f8d262870b5000a40b8fcce88f55c65c4d12e729975e
+CT = 0efcc87fda1712c7d85461bc40f8172a325cb5fff3cc45f136cc6ea1b0fdb554e0803053875b89
+
+Count = 239
+Adata = 459085184094e302b2e921cc04270b676e75bbcf0e4b53ed387df2bd0e75e0ac
+Payload = 732f211061c0a32c6ad124c58418d560ef5eab2602314c
+CT = a92b3b0d3cdce1eb168ecab52c6f978c814f0c3ed86a575da8ceccae093888daaf92c95817fc3d
+
+[Plen = 24]
+
+Key = 91f9d636a071c3aad1743137e0644a73de9e47bd76acd919
+Nonce = 1bf491ac320d660eb2dd45c6c3
+
+Count = 240
+Adata = 3bdfd7f18d2b6d0804d779f0679aaa2d7d32978c2df8015ae4b758d337be81dd
+Payload = 4eaf9384cad976f65f98042d561d760b5a787330dc658f6c
+CT = 635530cab14e3d0a135bb6eebb5829412676e6dd4995f99cb7e17f235bd660e7e17b2c65320e9fd4
+
+Count = 241
+Adata = 9de45b7e30bb67e88735b8fb7729d6f3de46c78921b228bad8f17cc9c709c387
+Payload = 59bee7d18fd4ba573f3e4f61076f5b9f6a3487e47d98c729
+CT = 7444449ff443f1ab73fdfda2ea2a04d5163a1209e868b1d99f40890c7d650afccda40fb2a4cd603b
+
+Count = 242
+Adata = 783477f981ef0551b5e7a714b640bbb38316c53756c96e30c898cdee3b72e6f4
+Payload = 4e7f3c86d846ff351db81dbe1d2e9ed73ec0450587ae681b
+CT = 63859fc8a3d1b4c9517baf7df06bc19d42ced0e8125e1eeb50236cf1a12a9e3542a4051788f9775a
+
+Count = 243
+Adata = 2851d40243512a43f70f9c25e9b18c122a1433f05c61e65017e197e88b129e43
+Payload = 2db7cb2739c839383b64c2c93c7d5c906d984756c3dedaa9
+CT = 004d6869425f72c477a7700ad13803da1196d2bb562eac59b1bbad9861192df356c6678b2f561ea3
+
+Count = 244
+Adata = 1cfa2d62cc1f6313fb0c6eb21803e09cdf61ee3ddb15192529560e5d8096cafb
+Payload = 2f2b82497c78369890809460d80a16be4f3330e8a0089165
+CT = 02d1210707ef7d64dc4326a3354f49f4333da50535f8e7951da4211d4c28d2d91568117fc99fd911
+
+Count = 245
+Adata = 5a14b556156191b2704936f64df0bf1dd2bd8d587418f4f85472338fcf86aa52
+Payload = 7cfefca725da1b6bb5d9545e3e50f5a624a8160bdb0e7d4e
+CT = 51045fe95e4d5097f91ae69dd315aaec58a683e64efe0bbeda99be0e054bb881a25a74b547d3ed5e
+
+Count = 246
+Adata = 148de640f3c11591a6f8c5c48632c5fb79d3b7e1cef9159c680d71fd1f9801fa
+Payload = 5205165c4e9612974dc92f60d1e328d68aa9466e27dbd499
+CT = 7fffb5123501596b010a9da33ca6779cf6a7d383b22ba2694c1fedb47fa30ff2ead6bf382431b2de
+
+Count = 247
+Adata = f852e38703097cc37c589b7860dbc333e091411462d5576dc9909a8cf6ac99d4
+Payload = f968f2833427abbc9fe1cab7e7a3f905a3b23a35802029ff
+CT = d49251cd4fb0e040d32278740ae6a64fdfbcafd815d05f0f338762a4e4299615c67130a28b56a383
+
+Count = 248
+Adata = 43df03a0e23c7ad0d13485150ca224c0b3f39d4e5f2d718db6308e003d3dc683
+Payload = 67da6ca42655188af0b8e389152b2a1b6e2c3ed88926afa5
+CT = 4a20cfea5dc25376bc7b514af86e75511222ab351cd6d9559dbdf61387294812f483aad76d48d899
+
+Count = 249
+Adata = b297dce04ada2ddebc7e94eff7c51b87eee2f98c410c5c0919d0652653ab7458
+Payload = 9777cf90dd7c7e863506686fc3ba6d3d05328f78b350f92f
+CT = ba8d6cdea6eb357a79c5daac2eff3277793c1a9526a08fdf078177541e19b11dfec995f40c99af70
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VPT256.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VPT256.rsp
new file mode 100644
index 0000000000..e9cd7eefe9
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VPT256.rsp
@@ -0,0 +1,1383 @@
+# CAVS 11.0
+# "CCM-VPT" information
+# AES Keylen: 256
+# Generated on Tue Mar 15 08:09:25 2011
+
+Alen = 32
+Nlen = 13
+Tlen = 16
+
+[Plen = 0]
+
+Key = c6c14c655e52c8a4c7e8d54e974d698e1f21ee3ba717a0adfa6136d02668c476
+Nonce = 291e91b19de518cd7806de44f6
+
+Count = 0
+Adata = b4f8326944a45d95f91887c2a6ac36b60eea5edef84c1c358146a666b6878335
+Payload = 00
+CT = ca482c674b599046cc7d7ee0d00eec1e
+
+Count = 1
+Adata = 36c17fd901169e5b144fdb2c4bea8cd65ad8acf7b4d3dd39acf2ad83da7b1971
+Payload = 00
+CT = 67747defe5da5fecc00b9bf3b249f434
+
+Count = 2
+Adata = 9a37c654ab8e5a0c6bdfff9793457197d206ed207d768cbc8318cfb39f077b89
+Payload = 00
+CT = c57ef5d0faf49149c311707493a4cfd4
+
+Count = 3
+Adata = 5ab80169184541393a6975f442ee583cd432d71a6d1568fa51159df7c5b8f959
+Payload = 00
+CT = bc2fb5571a7563bb90689a229d2f63a7
+
+Count = 4
+Adata = c78a22a667aafab0c94047e03837d51b11490693d5c57ea27b901ff80b6a38f9
+Payload = 00
+CT = 428888c6420c56806f465b415a66e65a
+
+Count = 5
+Adata = e11e30cbf63623816379f578788b0c8e6b59ee3c9c50aa6e1dcd749172d48fed
+Payload = 00
+CT = 9f1b7520025e1075731adc946b80121d
+
+Count = 6
+Adata = 05716168829276ff7ab23b7dd373db361e6d9e1f11d0028d374a0d3fe62be19f
+Payload = 00
+CT = bd36b053b6a90f19e3b6622cba93105d
+
+Count = 7
+Adata = 3e915389639435629fcc01e1b7022d3574e2848e9151261ad801d03387425dd7
+Payload = 00
+CT = 458595a3413b965b189de46703760aa0
+
+Count = 8
+Adata = 2f496be73a9a5d9db5927e622e166c6ec946150687b21c51c8ca7e680f9775ac
+Payload = 00
+CT = 8b259b84a6ee5669e175affca8ba3b1a
+
+Count = 9
+Adata = 0a8725bd8c8eab9ed52ca47835837b9f00a6c8d834ab17105b01eb4eb30402e7
+Payload = 00
+CT = c5f35fdf2b63e77a18d154f0ddcfedbf
+
+[Plen = 1]
+
+Key = cc49d4a397887cb57bc92c8a8c26a7aac205c653ef4011c1f48390ad35f5df14
+Nonce = 6df8c5c28d1728975a0b766cd7
+
+Count = 10
+Adata = 080f82469505118842e5fa70df5323de175a37609904ee5e76288f94ca84b3c5
+Payload = 1a
+CT = a5f24e87a11a95374d4c190945bf08ef2f
+
+Count = 11
+Adata = f6cfb81373f1cbb0574dda514747d0099635b48cb809c6f1fa30cbb671baa505
+Payload = 40
+CT = ffd43c5f39be92778fdce3c832d2d3a019
+
+Count = 12
+Adata = 5a88b14bada16b513d4aa349b11ce4a77d4cda6f6322ff4939ad77d8ecb63748
+Payload = 41
+CT = fe753b7b661f1aad57c24c889b1c4fe513
+
+Count = 13
+Adata = a92b95b997cf9efded9ff5e1bff2e49d32e65f6283552ded4b05485b011f853f
+Payload = 06
+CT = b91c5ac66e89bf2769ef5f38a3f1738b24
+
+Count = 14
+Adata = a206a1eb70a9d24bb5e72f314e7d91de074f59055653bdd24aab5f2bbe112436
+Payload = c8
+CT = 773fe64379cea1a8ae3627418dd3e489a2
+
+Count = 15
+Adata = d3029f384fd7859c287e38c61a9475d5ddbfd64af93746b1dc86b8842a8c194c
+Payload = e2
+CT = 5dabc529442ff93005551b7689bcb748f7
+
+Count = 16
+Adata = 51ca3d3b70b5e354451a5177d7acfd8e7b44eae55e29d88b5e8eb8fc1e5c62fc
+Payload = 1a
+CT = a5ee68e416617ac974b3d1af7320cd51f6
+
+Count = 17
+Adata = 8c6c6791f1ac957b18bf008e260a0af4a5b7bfdb1e0008d6eaaa227f45cf4f62
+Payload = dd
+CT = 6243883d93d7066991e0fac453400b4fbf
+
+Count = 18
+Adata = b0a1af969a95025385b251afd1e89f353426ed6e5d71019cd73366aa31d5b464
+Payload = 4c
+CT = f3b940d416f3435812f9d1b18f441b7721
+
+Count = 19
+Adata = 7e72b2ca698a18cb0bf625f5daddb0d40643009db938340a9e4fe164a052fee1
+Payload = 88
+CT = 371d27e9a32feea28a6a7e7da2d27e1cc4
+
+[Plen = 2]
+
+Key = 36b0175379e7ae19c277fe656a2252a82796309be0f0d4e1c07fdde88aca4510
+Nonce = 021bd8b551947be4c18cf1a455
+
+Count = 20
+Adata = b5c6e8313b9c68e6bb84bffd65fa4108d243f580eab99bb80563ed1050c8266b
+Payload = be80
+CT = ecacc3152e43d9efea26e16c1d1793e2a8c4
+
+Count = 21
+Adata = 38e5032c5949c2668191ef1af5bb17eddc28abdb4e5bb41eaffec2523b2525d6
+Payload = 82c9
+CT = d0e5d06bf4b50ccce0b2acfd16ce90a8854d
+
+Count = 22
+Adata = 0b50f5173249fb7118f80d25874d6745d88e4ce265fa0dd141ad67ae26c31122
+Payload = 8239
+CT = d0158d784f486c1dc4a2bafd5b02ca1e1c05
+
+Count = 23
+Adata = 0296743a3125b103a2b2a78a109e825ea10834bd684215ab2e85cc4172e37348
+Payload = 16c1
+CT = 44eda3377002a48f9fe306d157358e6df37d
+
+Count = 24
+Adata = a94e64becb803e211785ba51db7f3db042fbf44a7a821509156a6828b0f207e9
+Payload = 2801
+CT = 7a2df6c09bf1dcb1c82bd98c6e2c13a8d7a5
+
+Count = 25
+Adata = 105358cc17b12107e023a23d57b44c66a2c58d8db05100311575e1ea152fc350
+Payload = 65e7
+CT = 37cb2ea363c0d8864363056467570959ba03
+
+Count = 26
+Adata = 669f9a63cf638a202dca1965c4116273249813ce0b39703887d89bdf5b3b12d6
+Payload = 819d
+CT = d3b16519377e6d0252b5f80cdf3d0253eccf
+
+Count = 27
+Adata = e288590a3eba28ac6847a50b0294ab6bd0a548716ff5102c44a5b656b2d9ddd6
+Payload = 761e
+CT = 24329a4dee6ca2cde473f08f76f779856c3c
+
+Count = 28
+Adata = 5b222aae3c7786c3b9021ba672f9136190ec931cf055f84c85706127f74c6d5b
+Payload = 56de
+CT = 04f29e65c0f01e644e74092253b470cd5511
+
+Count = 29
+Adata = 2082f96c7e36b204ad076d8b2f796cccf5cbc80b8384b53a504e07706b07f596
+Payload = b275
+CT = e059809fa107f379957b52ac29fe0bc8a1e2
+
+[Plen = 3]
+
+Key = ddb739acda6c56ec9aefc4f4cbc258587f443da4e76ddfa85dbe0813a8784944
+Nonce = 0bddf342121b82f906368b0d7b
+
+Count = 30
+Adata = 887486fff7922768186363ef17eb78e5cf2fab8f47a4eb327de8b16d63b02acb
+Payload = db457c
+CT = 54473c3f65d6be431e79700378049ac06f2599
+
+Count = 31
+Adata = 0683c20e82d3c66787cb047f0b1eb1c58cdde9fb99ee4e4494bbf27eb62777d1
+Payload = 62a6c5
+CT = eda4853b186edc15c22ba24e470eb5a072da9f
+
+Count = 32
+Adata = 413074619b598f8bed34cab51ddf59941861ba0169ebe7570a5ed01d790c08e5
+Payload = cc67bc
+CT = 4365fc52a1fb5a58bd51931230c1a7dfb1a8c1
+
+Count = 33
+Adata = 2d65a5175c29a095dc082dab9cfcf4b895efbfa715c57614589d4db159543ce9
+Payload = 33800b
+CT = bc824b7d3810f59176cb108c7e969da51d4d79
+
+Count = 34
+Adata = 6a831b6059456be98e6fce608d8c71cb8efb04a96b45c2dfbdaeabf5420a1482
+Payload = b2c826
+CT = 3dca6646ffea832595c9c86e6517215541ddbd
+
+Count = 35
+Adata = 3a04a01160402bf36f33337c340883597207972728c5014213980cd7744e9e41
+Payload = d7e620
+CT = 58e460e89a6725f0fc35622d89d2f3e34be90a
+
+Count = 36
+Adata = 64d8bd3c646f76dc6ce89defd40777fe17316729e22ba90f6a2443ee03f6390b
+Payload = 795af4
+CT = f658b4b1bd7ad5d81686aeb44caa6025d488bd
+
+Count = 37
+Adata = 7bef8d35616108922aab78936967204980b8a4945b31602f5ef2feec9b144841
+Payload = 66efcd
+CT = e9ed8d0553c801f37c2b6f82861a3cd68a75e3
+
+Count = 38
+Adata = 92f7dc22dcbbe6420aca303bd586e5a24f4c3ed923a6ebe01ec1b66eee216341
+Payload = 78b00d
+CT = f7b24de3eeb8ea6c08b466baf246b3667feb3f
+
+Count = 39
+Adata = 71bf573cf63b0022d8143780fc2d9c7dbd0505ac31e9dce0ad68c2428b0878a0
+Payload = 9dd5e1
+CT = 12d7a11db811640c533794bfec6eeb977233ec
+
+[Plen = 4]
+
+Key = 62b82637e567ad27c3066d533ed76e314522ac5c53851a8c958ce6c64b82ffd0
+Nonce = 5bc2896d8b81999546f88232ab
+
+Count = 40
+Adata = fffb40b0d18cb23018aac109bf62d849adca42629d8a9ad1299b83fe274f9a63
+Payload = 87294078
+CT = 2bc22735ab21dfdcfe95bd83592fb6b4168d9a23
+
+Count = 41
+Adata = 75c3b3059e59032067e9cd94d872e66f168e503bcf46bc78d82a4d4a15a29f6e
+Payload = 0f28ee1c
+CT = a3c38951b5de3331078aa13bd3742b59df4f661a
+
+Count = 42
+Adata = 8fb9569f18a256aff71601d8412d22863e5a6e6f639214d180b095fa3b18d60e
+Payload = d41c9c87
+CT = 78f7fbcae52afe7326a12a9aaf22255a38d4bd0d
+
+Count = 43
+Adata = 8b62d9adf6819c46c870df8a1486f0a329672f7d137bb7d8659f419c361a466c
+Payload = 046bc0d8
+CT = a880a7957543692a72f0d599de48b5e5f5a9413f
+
+Count = 44
+Adata = fd98f8f39dfa46ea5926e0ffacbabbe8c34205aade08aa0df82e1d4eaaf95515
+Payload = 39bd4db8
+CT = 95562af530fc357f5482b9004d466bf858586acb
+
+Count = 45
+Adata = 09bf4f77a9883733590a3cc7ee97f3c9b70f4db255620e88cd5080badc73684c
+Payload = b43cdd3a
+CT = 18d7ba77a9e8db046fdd548b52d40375c1e9a448
+
+Count = 46
+Adata = 40326d765e0f6cf4b4deccb128bebf65a7b3c3e5bcf1d58f6158e1e9153b7e85
+Payload = e0052e9b
+CT = 4cee49d64efbdd4ad8d3e863172d9372fca07c20
+
+Count = 47
+Adata = aa5ae6dcdc21b5446489bdabf5c6747bdf3bbfdb3de2c03170efefe5ccb06d69
+Payload = 696825f6
+CT = c58342bb95bd661b32bc18025808f8b4035acad6
+
+Count = 48
+Adata = d3d34f140a856e55b29471fde4c0e5f7306b76d03faab26db79c10f95ffb3122
+Payload = 7eb07739
+CT = d25b1074ac05b072264e31a4b2801a6d790512d7
+
+Count = 49
+Adata = 648a84813ca97aef4ab7e143ee29acb946388660f18eb671194646e0b0136432
+Payload = 9cad70b1
+CT = 304617fcc00514d260e1d211de361c254369e93a
+
+[Plen = 5]
+
+Key = bc29a16e19cfbe32bf4948e8e4484159bc819b7eec504e4441a1a98ca210e576
+Nonce = 4f18bcc8ee0bbb80de30a9e086
+
+Count = 50
+Adata = 574931ae4b24bdf7e9217eca6ce2a07287999e529f6e106e3721c42dacf00f5d
+Payload = 3e8c6d1b12
+CT = 45f3795fcf9c66e1a43103d9a18f5fba5fab83f994
+
+Count = 51
+Adata = 99cd9d15630a55e166114f04093bd1bb6dbb94ecaad126fe5c408dee5f012d9f
+Payload = 76fc98ec66
+CT = 0d838ca8bb6f3cd579294f706213ed0f0bf32f00c5
+
+Count = 52
+Adata = 1516fdf7a7a99f3c9acc7fff686203dec794c3e52272985449ddf5a268a47bc3
+Payload = 6564c247cc
+CT = 1e1bd603117d38e026f706c9273dbcb6dc982751d0
+
+Count = 53
+Adata = 0c9c35be98591bf6737fc8d5624dcdba1a3523c6029013363b9153f0de77725b
+Payload = c11b9c9d76
+CT = ba6488d9abc3e46166767c6ad2aeffb347168b1b55
+
+Count = 54
+Adata = e74afe3ba960e6409dba78ecb9457e2a4ce2e09792b1d2e3858f4c79f7ddba62
+Payload = 45a4e0d7dd
+CT = 3edbf4930033a7dca78bcbf4d75d651ee5fadff31b
+
+Count = 55
+Adata = 96cbe9cd193513599c81f5a520fabaff51ee8cbdb81063c8311b1a57a0b8c8fd
+Payload = e5861b2327
+CT = 9ef90f67fa11585167c83105ee16828a574c84ac86
+
+Count = 56
+Adata = 2e7ea84da4bc4d7cfb463e3f2c8647057afff3fbececa1d20024dac29e41e2cf
+Payload = f5b5bcc38e
+CT = 8ecaa88753ffaba456f78e431f4baa5665f14e1845
+
+Count = 57
+Adata = be125386f5be9532e36786d2e4011f1149abd227b9841150d1c00f7d0efbca4a
+Payload = b6cc89c75d
+CT = cdb39d838034714731f9503993df357954ecb19cd3
+
+Count = 58
+Adata = 3fa8628594b2645bc35530203dca640838037daeaf9cf8acaa0fb76abf27a733
+Payload = 3802f2aa9e
+CT = 437de6ee436c1b008b7572752f04362b2bfdc296bb
+
+Count = 59
+Adata = 642ae3466661ce1f51783deece86c38e986b8c0adea9e410e976f8a2fe0fe10f
+Payload = e082b8741c
+CT = 9bfdac30c1a3f7c3c29dc312c1f51a675400500e32
+
+[Plen = 6]
+
+Key = 5f4b4f97b6aa48adb3336c451aac377fde4adf47897fd9ccdf139f33be76b18c
+Nonce = 7a76eac44486afdb112fc4aab9
+
+Count = 60
+Adata = a66c980f6621e03ff93b55d5a148615c4ad36d6cbdd0b22b173b4b1479fb8ff7
+Payload = 1b62ad19dcac
+CT = 4ad1fcf57c12b14e0e659a6305b4aeffae82f8a66c94
+
+Count = 61
+Adata = c13f65bd491cb172a0f7bbc4a056c579484b62695e90383358d605307d5be0a5
+Payload = 3ef0faaa9b79
+CT = 6f43ab463bc779fa7932d365e2da9b05c00a7318384a
+
+Count = 62
+Adata = 59dcca8fc50740831f8f259eb55d4db11f763a83187d93758d78d166f4d73cd5
+Payload = 1a98ddbf35f1
+CT = 4b2b8c53954f813229912137b7a4945dc07cea24a974
+
+Count = 63
+Adata = 578509ca4f57aadb78056794bf18b0714090970db786e2e838105e672165761c
+Payload = f46a7b1c28ea
+CT = a5d92af088546e045f19f737a24c8addf832ed3f7a42
+
+Count = 64
+Adata = 696c0c6427273cf06be79f2206c43af9cbda0b884efaf04deba0c4bf0a25cb26
+Payload = e98f5e5a20d0
+CT = b83c0fb6806edaae8a7dcd3b0fbb59438f88743ec6e8
+
+Count = 65
+Adata = 95a66b60249ed086eecaeb9bc449afcee9de212619e87516ca947351b25120df
+Payload = 06319c0480e2
+CT = 5782cde8205cd9cb636ca6543c4e35964f47341f2814
+
+Count = 66
+Adata = 2b411bea57b51d10a4d2fb17ef0f204aa53cf112e1130c21d411cdf16a84176d
+Payload = f4c723433b7c
+CT = a57472af9bc2ec82eadf4eb1f055da1a92a82052ab8b
+
+Count = 67
+Adata = ff3bff3a26fc5a91252d795f7e1b06f352314eb676bff50dc9fbe881c446941e
+Payload = 02f809b01ce3
+CT = 534b585cbc5d01b10a7ae24a4ca2bfb07ea2a3b31a97
+
+Count = 68
+Adata = f6be4aad63d33a96c0b5e9c4be62323c9e2308b29961fff980ba0dbda0549274
+Payload = 2b6004823a29
+CT = 7ad3556e9a97231323a4b88af5d7d0b07c0e73ddce1d
+
+Count = 69
+Adata = c3706a28d7420b41e072dcecc06b6b13116cca110bde8faea8e51f5107352d71
+Payload = 236c60cba4fa
+CT = 72df31270444db30eb33d2ede33abbe22f37704fe68b
+
+[Plen = 7]
+
+Key = f7aaeff3a1dc0cc5ecf220c67ad9f6dda060b4f1be3cc609cb4f18b2342a88a2
+Nonce = d0d6871b9adc8623ac63faf00f
+
+Count = 70
+Adata = e97175c23c5b47da8ce67811c6d60a7499b3b7e1347ad860519285b67201fe38
+Payload = d48daa2919348d
+CT = eb32ab153a8e092fa325bafc176a07c31e6cc0a852d288
+
+Count = 71
+Adata = ba45e1859efae362a44a0116a14e488ba369da6c76c3913b6df8e69e5e1111fa
+Payload = f95b716bfe3475
+CT = c6e47057dd8ef1a24840f4f40a7963becde3a85968b29c
+
+Count = 72
+Adata = efcaa6f6cda3036b0b52ff9f36bc38ca74049c32c6b7cdfb8a46ca4144bacd64
+Payload = 4862e3677083f0
+CT = 77dde25b5339748f2a4a5c276727e0a210fc2efb5aeabe
+
+Count = 73
+Adata = 360bcb407603fe92f856bf677625b9882521e6dae8f35fdfc3dc737f9398f609
+Payload = 7f1ca0728f6d65
+CT = 40a3a14eacd7e1051734fc31232ab2ab63474020ab4dc9
+
+Count = 74
+Adata = f12ee9d37946cfd88516cbe4a046f08c9bbba76a3973ff1e2cb14493405bd384
+Payload = 67478ef73290fa
+CT = 58f88fcb112a7ec715244f307609ffa253e4e3659b0ece
+
+Count = 75
+Adata = 5833dde0c577b2be4eb4b3d01d7b0042fa8441ad7043ea462bbbbd56a59790ea
+Payload = 36bb9e511276c5
+CT = 09049f6d31cc41f11047da612d2987fa2e50ada5ae7f9d
+
+Count = 76
+Adata = 1e103c63d8ead36b985f921044cd32b8f9f04a2ba9fa154a09e676ffaa093970
+Payload = d68d6556c5a5b1
+CT = e932646ae61f35382f7648718127ebae7eb7443ebd2c2c
+
+Count = 77
+Adata = a1cfb61d45a140bdea6329ba0fe80429ff9aa4624a1d31bc752f7c97f1d390a0
+Payload = 0568cca4ff79dc
+CT = 3ad7cd98dcc358cc40a5e7fffb1fb9a5dd9d6ba91bede1
+
+Count = 78
+Adata = 116b5b015e44ceef0061b2d2e73fa0b386d5c1e187782beebdfc6efb5a1c6935
+Payload = bd93d08eea4263
+CT = 822cd1b2c9f8e7468d2b70c311732f11ed72b57d83e500
+
+Count = 79
+Adata = 3d55882e6f3f89309b6940a3b408e573458eedd10fc3d0e1f3170eb313367475
+Payload = 4fb62753024e92
+CT = 7009266f21f416b41a70f548e359add30c0e5746fbeb2b
+
+[Plen = 8]
+
+Key = 493e14623cd250058a7fc66a3fee0c24b6e363b966c2314aff53b276b6c2ea7b
+Nonce = fe2d8ae8da94a6df563f89ce00
+
+Count = 80
+Adata = 579a637e37a0974cd2fc3b735d9ed088e8e488ffe210f043e0f9d2079a015ad6
+Payload = e5653e512d8b0b70
+CT = 75d31f8d47bee5c4e2ba537355ae8ab25cc9ed3511ff5053
+
+Count = 81
+Adata = 1583138aa307401dddc40804ac0f414d338fc3ffb2946f09aaaa7079426fc1ee
+Payload = 2c4ba9ce52e01645
+CT = bcfd881238d5f8f1781a9e359804831f31a1efb1ae1cb71d
+
+Count = 82
+Adata = 78d3dda40e433bba7a330ca3e5bd5170f0895f2e3e438402344ced79fcb0c719
+Payload = 5eb2d054a0e58c62
+CT = ce04f188cad062d62dcc77c4e1fe2bafd477598977835f0c
+
+Count = 83
+Adata = dfc762466fa84c27326e0ee4320aa71103d1e9c8a5cf7d9fab5f27d79df94bd6
+Payload = bbbf7830d04ab907
+CT = 2b0959ecba7f57b308946723baf0dbf613359b6e040f9bd5
+
+Count = 84
+Adata = 7e8ea82d1137c1e233522da12626e90a5f66a988e70664cb014c12790d2ab520
+Payload = 10c654c78a9e3c06
+CT = 8070751be0abd2b2003bd62ca51f74088bbbd33e54ac9dd4
+
+Count = 85
+Adata = 873da112557935b3929f713d80744ed08b4b276b86331dbc386fba361726d565
+Payload = 668d32e322e1da3e
+CT = f63b133f48d4348a67e65e7f2cdedf6ef8cc0ee7a6dcfb02
+
+Count = 86
+Adata = cfba97919f703d864efc11eac5f260a5d920d780c52899e5d76f8fe66936ff82
+Payload = e39f6225e8eab6cc
+CT = 732943f982df58780532f8c6639e5d6c7b755fcf516724e3
+
+Count = 87
+Adata = 01abcfee196f9d74fcaa7b69ae24a275485c25af93cc2306d56e41e1eb7f5702
+Payload = 6021a00f6d0610a4
+CT = f09781d30733fe107fd7a33828413ebc252dd9d015773524
+
+Count = 88
+Adata = ce1c31e7121c071d89afab5a9676c9e96cac3d89dcae83136bbb6f5ca8f81e5d
+Payload = bbaf0ac4e77ee78d
+CT = 2b192b188d4b0939d3d51368799325ad1c8233fa071bade0
+
+Count = 89
+Adata = bb210ca5bc07e3c5b06f1d0084a5a72125f177d3e56c151221115ae020177739
+Payload = 98a2336549a23a76
+CT = 081412b92397d4c25d1ea568637f773174a7f920a51b1fe1
+
+[Plen = 9]
+
+Key = b23255372455c69244a0210e6a9e13b155a5ec9d6d0900e54a8f4d9f7a255e3a
+Nonce = 274846196d78f0af2df5860231
+
+Count = 90
+Adata = 69adcae8a1e9a3f2fe9e62591f7b4c5b19d3b50e769521f67e7ea8d7b58d9fc8
+Payload = 615d724ae94a5daf8d
+CT = f019ae51063239287d896e7127f17d13f98013b420219eb877
+
+Count = 91
+Adata = 162d0033c9ea8d8334d485b29eef727302135a07a934eea5fee6041e9f1f47c1
+Payload = 0d9168eeab3b27ba69
+CT = 9cd5b4f54443433d997cc2cd61da9358b4045fef32f8192cbf
+
+Count = 92
+Adata = 3f4ab57efa32f51a4c00790280e77c0e55b85bbda4f854e242368e9a289b5a81
+Payload = 6287dcffdd5fb97885
+CT = f3c300e43227ddff75d280f0ffdd560fb8915978e3bd6205bb
+
+Count = 93
+Adata = 945d18134c148f164b39fd7c4aef0335045553f6ea690a3b1726418d86f0de00
+Payload = 6e5e01b3fd71d16b9c
+CT = ff1adda81209b5ec6c7dbf90420a1ff2e24bd6303b80cfc199
+
+Count = 94
+Adata = 23af12893431b07c2922ab623aed901c0eaaeb9a24efc55273e96aea4dab7038
+Payload = b51521e689b5247362
+CT = 2451fdfd66cd40f492d741f4329ae7cc77d42bf7e5f2ec5ab6
+
+Count = 95
+Adata = b15a118b3132c20c31e6c9d09acdee0e15fcc59d6f18306442682512d22eb10f
+Payload = 7f973617e710fb76fe
+CT = eed3ea0c08689ff10ec9ffdcc2f36edac14613b1d85baf25a9
+
+Count = 96
+Adata = dcfbeb6490f5fa7eaf917462473a6cec98bebf8f17493fe9b994119a6d5a5457
+Payload = 7e909b6727ac3fd02f
+CT = efd4477cc8d45b57df5a61a28bb10265b26043d7a8dd357713
+
+Count = 97
+Adata = 77e9317294f046f315a0d79e3423f29f7d9ebcd36d6eaa2a3fb2f4500309478c
+Payload = a5075638932b5632f8
+CT = 34438a237c5332b508d321c371ae1fd01bdf3b6c75a597da6e
+
+Count = 98
+Adata = 3aa8f204eb127b547e13873ed0238018394e13686c8734e49e3e629deb352c77
+Payload = c10f15a0de78db8aa3
+CT = 504bc9bb3100bf0d539393d1635bc40ac62405a39155406c47
+
+Count = 99
+Adata = 7f67e6f97c6c258f014d721a4edaaa0ddb3f9f09993276ab7b714ea9356c231d
+Payload = 8294f830cfca42cfbe
+CT = 13d0242b20b226484eff89641e1bd5ad6cc827441b17c45ecf
+
+[Plen = 10]
+
+Key = dbf06366f766e2811ecd5d4384d6d08336adc37e0824d620cf0d9e7fd1e7afa9
+Nonce = b3503ed4e277ed9769b20c10c0
+
+Count = 100
+Adata = 9ae5a04baa9d02c8854e609899c6240851cbc83f81f752bc04c71affa4eed385
+Payload = 2e3cf0af8c96c7b22719
+CT = e317df43ab46eb31be7e76f2730d771d56099a0c8d2703d7a24e
+
+Count = 101
+Adata = da77c6d5627a2aa34911bd1f7cc5f8aa68a2c6546adc96a186b9af8e5baac4cf
+Payload = e081c43a07450ce0dfa2
+CT = 2daaebd62095206346c5bcc7a8260ef361dc39fdb776d041f0d4
+
+Count = 102
+Adata = 134d2d9726400d09dd3521326f96fbef993ddc0c4088770057b0f8d70356456f
+Payload = c381d2ae5e72fc82324a
+CT = 0eaafd4279a2d001ab2d19f0cbb0899f221aac9762f2650f8058
+
+Count = 103
+Adata = 0d065dfde1de1f21784c7869eb566c977f807cfbd53578f4616995b51d7dc045
+Payload = 737f4d00c54ddca80eec
+CT = be5462ece29df02b978b3dc92a9bd26b9653e5917359c331fcff
+
+Count = 104
+Adata = 95c54d187f2415535451cbb9cb35869749b171f7043216ce6886dd77baeecf60
+Payload = 4e9e251ebbbbe5dbc8ff
+CT = 83b50af29c6bc958519891dda72c27d272561e00f7041845d998
+
+Count = 105
+Adata = 0f98039e6a9fe360373b48c7850ce113a0ff7b2ae5ce773dd4c67ca967cd691b
+Payload = 0db72b281ab4046d15a6
+CT = c09c04c43d6428ee8cc1928ac628758ad58fc1b5a768d4722848
+
+Count = 106
+Adata = ad840bc55654762e5eba0e4a9e7998992d990a06d70da1b1ca922ef193dab19a
+Payload = 4f7b4f38ff1ba4df5a59
+CT = 825060d4d8cb885cc33ed11dad4dc8b265a53cf0bdd85c5f15f4
+
+Count = 107
+Adata = 911e9876ea98e1bcf710d8fd05b5bf000ea317d926b41b6015998ee1462ab615
+Payload = 58ce55379ef24b72d6d6
+CT = 95e57adbb92267f14fb18eb659a5a7084be48d099467da4395df
+
+Count = 108
+Adata = 3f68a4fb4043bcf9b6d277c97e11365d949c705bd6679c6f0aaf52e62330ad79
+Payload = a219028a953ce1544835
+CT = 6f322d66b2eccdd7d1523b2b2583fd117cec47b1c84d3863159e
+
+Count = 109
+Adata = 02f32242cba6204319075ea8ce806a57845355ae73e6b875955df510096ebff9
+Payload = 83b0ee9a52252c456105
+CT = 4e9bc17675f500c6f8625456eb2b6a2d35c649a84051f843153c
+
+[Plen = 11]
+
+Key = 4dd555bd3a5253a90b68b5d4d46bd050340ee07ddad3a72048c657b5d76bb207
+Nonce = bdb1b82ba864893c2ee8f7426c
+
+Count = 110
+Adata = 9bcc5848e928ba0068f7a867e79e83a6f93593354a8bfcfc306aeeb9821c1da1
+Payload = 8015c0f07a7acd4b1cbdd2
+CT = 8e9f80c726980b3d42e43a6512a0481255b729a10f9edb5f07c60c
+
+Count = 111
+Adata = c2e75952ab49216f305e3776865791ce877cef8c0229ca97561787093fddf1d8
+Payload = c97b62a719720b44b7779c
+CT = c7f122904590cd32e92e748c514444f00ffdb80a4bb7e9eb651946
+
+Count = 112
+Adata = c76a3ff4e6d1f742dd845be2d74c1a9b08e418909b15077deb20373ef55caf91
+Payload = cb7c17ef62464ecc8008f6
+CT = c5f657d83ea488bade511edb609dfc1929ac1ba5753fc83bf945b7
+
+Count = 113
+Adata = bdb69f99f9a144b9ad88c6cfd8ffb8304c201de9b2818552ce6379e6042c1951
+Payload = 893a690cc5221de597d0e8
+CT = 87b0293b99c0db93c9890053b74283296d0fca83b262915289163c
+
+Count = 114
+Adata = 01815f599d6ba0d1c09f6f673bb6cca4c2a7a74f4e985be4c0f37842c7bbc5a4
+Payload = 80f3e4245c3eab16ef8bf0
+CT = 8e79a41300dc6d60b1d21888a34955893059d66549795b3ac2105c
+
+Count = 115
+Adata = a9db62e9ab53c4a805c43838ce36b587d29b75b43fb34c17a22d3981120f3bc5
+Payload = 641c6914920a79943dca39
+CT = 6a962923cee8bfe26393d1377c4e2f20aaa872a9a0b1d1d7f56df0
+
+Count = 116
+Adata = f0c2cc5a1b4c4cbe839338fa0d7a343514801302aef2403530605cf4f44d2811
+Payload = 2286a1eddd80737a724ca9
+CT = 2c0ce1da8162b50c2c15415545aa0c1dd11551891ae553d3a91908
+
+Count = 117
+Adata = 9842922499ad4d487488b3731f48765efe0b4eb59e7b491ba5f6636f09ed564d
+Payload = d8c63e7d7d332198249c0c
+CT = d64c7e4a21d1e7ee7ac5e4d9e07ec5806360843676ef27d811b246
+
+Count = 118
+Adata = 399b71ecb41f4590abda79045cdf6495f27daaa559c1b34f513b5c4ac105ec10
+Payload = 4b81804d777a59b6a107cf
+CT = 450bc07a2b989fc0ff5e27483b8727c5753ede25e1fab0d86963be
+
+Count = 119
+Adata = 2c186c5c3463a4a8bad771feb71e2973c4f6dede2529827707bf4fa40672660f
+Payload = dfc762466fa84c27326e0e
+CT = d14d2271334a8a516c37e64b5c3c1dc577ee8fcf6ef3ebc0783430
+
+[Plen = 12]
+
+Key = d3ad8cda9a0d91a205c4c05665728bb255d50a83403c9ab9243fcbbe95ae7906
+Nonce = 0b5f69697eb1af24e8e6fcb605
+
+Count = 120
+Adata = ea26ea68facdac3c75ba0cdf7b1ad703c9474af83b3fbfc58e548d776b2529b9
+Payload = a203aeb635e195bc33fd42fa
+CT = 62666297a809c982b50722bd56bc555899345e0404b2938edf33168e
+
+Count = 121
+Adata = 0b32069fc7e676f229f1037d3026c93eef199913e426efd786b524ce1dbde543
+Payload = aac414fbad945a49ae178103
+CT = 6aa1d8da307c067728ede1449b15447c904b671824c2ca24c4fc7ad4
+
+Count = 122
+Adata = 7a8658302e5181552292aa56e8209de63b5d86934167549b0d936202681757e1
+Payload = 7ee0ce371329192618e3cda0
+CT = be8502168ec145189e19ade7ea13850e99ef9300c65f5abc9419d13a
+
+Count = 123
+Adata = 4f05600950664d5190a2ebc29c9edb89c20079a4d3e6bc3b27d75e34e2fa3d02
+Payload = b0a1af969a95025385b251af
+CT = 70c463b7077d5e6d034831e8486c93c31bbedc9e5ffa2f4154bceea9
+
+Count = 124
+Adata = 4530e4dc6a4c3733b8ab7e77e384223cc1a8c179fb66818c08aca47e5c705d89
+Payload = 9f6c6d60110fd3782bdf49b0
+CT = 5f09a1418ce78f46ad2529f7f18b556e7da59fd2549dc57a17bf64f8
+
+Count = 125
+Adata = f179353aef342f0f691caf1fcb811e3f6504e14d6d9381c5439b098ff978b01b
+Payload = 90958d7f458d98c48cbb464c
+CT = 50f0415ed865c4fa0a41260b30aad3a838680cbd313004685a5510c5
+
+Count = 126
+Adata = f6df267e5cbc9d2a67b1c0fd762f891ee3b7c435884cb87d8228091b34aeddae
+Payload = 9f7ae892e5662803408d4d06
+CT = 5f1f24b3788e743dc6772d411d57b89ed0c91251aed37a6ca68a50c7
+
+Count = 127
+Adata = 4372e152b1afd99c7f87c8a51dbc3a5c14c49d04ea1c482a45dfbcda54972912
+Payload = 817074e351455f23cb67883d
+CT = 4115b8c2ccad031d4d9de87ad79a3b0feea16ff5fbca16211ea6fdd9
+
+Count = 128
+Adata = 82b6cd1c6618c42ba74e746075dc28700333578131ca6fde6971d2f0c6e31e6a
+Payload = 1b7da3835e074fdf62f1eb3c
+CT = db186fa2c3ef13e1e40b8b7b49f22737c4b2f9fa0a7e3dd4b067fbaa
+
+Count = 129
+Adata = a5422e53975e43168726677930f6d3e13281bdbd13c67c168340ed67e45d15b0
+Payload = 57473e7a105c806867379194
+CT = 9722f25b8db4dc56e1cdf1d3ef43a48dbea8c1547455ad0197af88a2
+
+[Plen = 13]
+
+Key = e300fc7a5b96806382c35af5b2c2e8e26382751b59010d4b1cfc90a4a9cb06df
+Nonce = 55b59eb434dd1ba3723ee0dc72
+
+Count = 130
+Adata = 9b1d85384cb6f47c0b13514a303d4e1d95af4c6442691f314a401135f07829ec
+Payload = 8714eb9ecf8bdb13e919de40f9
+CT = ba6063824d314aa3cbab14b8c54c6520dac0f073856d9b9010b7857736
+
+Count = 131
+Adata = fa17c693d0997140fbc521d39e042d8e08388106874207ca81c85f45c035d6e6
+Payload = a0837676e091213890dc6e0a34
+CT = 9df7fe6a622bb088b26ea4f20820a423dd30796b6016baff106aaef206
+
+Count = 132
+Adata = 27663597b389b78e96c785ca2f5510c8963a5561d2b0b24c4dcdf8e58562c12c
+Payload = b8a2ce7e051b8d094ec43f2a7f
+CT = 85d6466287a11cb96c76f5d2436032bc79c4aef1f74da25e92b0aa7f8a
+
+Count = 133
+Adata = d8f1a83371487d611ce704e0a6731f97a933c43569690022fce33cb5aecdc0a7
+Payload = 9e4103ab1dfb77ae3494507332
+CT = a3358bb79f41e61e16269a8b0e658123d2e5bb324c7ead8897f8e32b0a
+
+Count = 134
+Adata = 05c57aab99f94b315cf8bdd2d6b54440c097fe33c62a96b98b1568cdee4ce62c
+Payload = fb3e3d1b6394d2daebf121f8ac
+CT = c64ab507e12e436ac943eb0090270758ab09f93fa3ba7d7a2aa8eac789
+
+Count = 135
+Adata = 1c1b0933c508c6a8a20846ebd0d0377e24f4abc0c900d3a92bc409ba14ef1434
+Payload = 549ba26a299391538b56ce4bd7
+CT = 69ef2a76ab2900e3a9e404b3eb2293813f1bcb96564f772e9308e42b2d
+
+Count = 136
+Adata = 9f5cf9149f556124d6bb4e3e243cca1502c02682709392cc2ec7eb262fd4d479
+Payload = 287f31e69880823df7798c7970
+CT = 150bb9fa1a3a138dd5cb46814c81877380d5cf097c2fb5177750f8b53a
+
+Count = 137
+Adata = 1a49aaea6fc6fae01a57d2fc207ef9f623dfd0bc2cf736c4a70aaaa0af5dafd3
+Payload = 040d18b128ae4a1935f9509266
+CT = 397990adaa14dba9174b9a6a5acf42c75787edc62a180568c6ef56545d
+
+Count = 138
+Adata = f29a0b2c602ff2cacb587292db301182e6c76c5110b97ca8b706198f0e1dbc26
+Payload = 92441cbe8d70820870bb01ad63
+CT = af3094a20fca13b85209cb555f56d47a0631f2038103e3904b556ba7a5
+
+Count = 139
+Adata = 01fcf5fef50e36175b0510874ea50a4d2005ad5e40e5889b61417700d827251e
+Payload = f11d814df217de96333dee1cbf
+CT = cc69095170ad4f26118f24e4835be15b7ae24edccd0b0934e3af513ed3
+
+[Plen = 14]
+
+Key = 3ae5be5904bae62609ac525e2d1cad90133447573d7b608975a6a2b16cb2efc0
+Nonce = 61bf06b9fa5a450d094f3ddcb5
+
+Count = 140
+Adata = 0245484bcd987787fe97fda6c8ffb6e7058d7b8f7064f27514afaac4048767fd
+Payload = 959403e0771c21a416bd03f38983
+CT = 37a346bc4909965c5497838251826385a52c68914e9d1f63fd297ee6e7ed
+
+Count = 141
+Adata = 52f6a10a022e5ee57eda3fcf53dcf0d922e9a3785b39fad9498327744f2852e4
+Payload = 23fe445efa5bcb318cc85e2ad1ac
+CT = 81c90102c44e7cc9cee2de5b09ad364b603de6afbc2d96d00510894ccbe7
+
+Count = 142
+Adata = d236e3841b9556b32dbd02886724d053a9b8488c5ad1b466b06482a62b79ebb6
+Payload = 762fdc3e0c30c7ecf2ec8808bb79
+CT = d418996232257014b0c6087963781a4321c2ddbc35ce4864457d611219e9
+
+Count = 143
+Adata = 0d2739cfdac782b61f484fa1a423c478c414397ec420327963d79112b2d70a7e
+Payload = b6813d5fe8afa68d646c197337a2
+CT = 14b67803d6ba117526469902efa3296e55efebb17fe145cdca9b31ea7bcc
+
+Count = 144
+Adata = 7f291aa463c4babc76b4a6faf2e27e9401586b1ac83e4b06a4090e94b3ef5fd4
+Payload = 4ce8b6578537215224eb9398c011
+CT = eedff30bbb2296aa66c113e9181059270a0510e7cc1b599705853af2144d
+
+Count = 145
+Adata = 06bca7ef6f91355d19f90bf25590a44a24e5a782f92bc693c031e6de1e948008
+Payload = 9ebf93643854ea5c97a4f38f50bd
+CT = 3c88d63806415da4d58e73fe88bcb55847573bf21e946ce9bdc5f569e3ff
+
+Count = 146
+Adata = 5a44ff94f817c7c028a8f3db35a4d01364d2598432469f09ded86e5127d42d35
+Payload = da989cc7d375ed5fac4d7f938d74
+CT = 78afd99bed605aa7ee67ffe25575b8a61c5687ea02f0276824b8316b76f1
+
+Count = 147
+Adata = 2a755e362373ef27a911c4d93ca07bc97135645442ad7ad6a8ef98146c71e9d7
+Payload = 6fbab5a0f98e21e4d15904af5948
+CT = cd8df0fcc79b961c937384de8149a07ee02791011129fcacffcfb1bf4145
+
+Count = 148
+Adata = f7988873f45a5de314e5381d3f14d8f8c48c9b649bf3e745ed5dc882d507da58
+Payload = b610349e8b370a7c195598573637
+CT = 142771c2b522bd845b7f1826ee36d34204b1ce23f5f58a8eb7cf1fa8cfa7
+
+Count = 149
+Adata = 95d2c8502e28ab3ee2cac52e975c3e7bccb1a93acc33d9c32786f66d6268d198
+Payload = 1d969fd81dab5ced3e6ee70be3bf
+CT = bfa1da8423beeb157c44677a3bbe9c618bb88bbcefb008a5ea6bed4ff949
+
+[Plen = 15]
+
+Key = fab62b3e5deda7a9c1128663cc81c44b74ab1bfe70bc1c9dec7c7fd08173b80a
+Nonce = a5c1b146c82c34b2e6ebeceb58
+
+Count = 150
+Adata = 5e60b02b26e2d5f752eb55ea5f50bb354a6f01b800cea5c815ff0030b8c7d475
+Payload = 54be71705e453177b53c92bbf2ab13
+CT = 788db949697b8cd9abbc74ed9aa40cd6852dc829469368491149d6bb140071
+
+Count = 151
+Adata = 210c04632341fbfc185bfe3cbf6fe272bbe971104173bcb11419b35ab3aaf200
+Payload = 22197f9ad14591e7a6d5f8b18c969a
+CT = 0e2ab7a3e67b2c49b8551ee7e4998556940dc5a7e44bf10234806d00a012b5
+
+Count = 152
+Adata = d3a205dd017e79a67400a937a20ef049f4c40d73311731f03ab857a3f93bd458
+Payload = 096b2f530933c1273304a6ad423726
+CT = 2558e76a3e0d7c892d8440fb2a38390898f7dbde25b0b70d335df71a06987b
+
+Count = 153
+Adata = 0c9b3ba4faf5fc2f310ad1bab06c4ca13474b714feeffb6ad615c1b850bbd6a3
+Payload = d44fdfd9da3a63c1083afe574e91bf
+CT = f87c17e0ed04de6f16ba1801269ea02fd10d1f21b6b963c05aeda8eb09e272
+
+Count = 154
+Adata = d9bb71ad90152d5c1af358c8501fa89ebd4b17bf4ff43841528cccb79fd791b3
+Payload = 8d836acc13ed83c2b2c706415c9679
+CT = a1b0a2f524d33e6cac47e0173499664491d23d90ff55abca17e9d943b98c7f
+
+Count = 155
+Adata = 69dc21eb6f295b12ba493ee8fe6c40d78af946067ce772db316a3cbf00d3c521
+Payload = 2a68e3fe746f593c1b97cb637079c3
+CT = 065b2bc74351e49205172d351876dc9616886c6b2adc97db5a673846b6662c
+
+Count = 156
+Adata = 095eb52135dc6d9c1f56a2571c1389852482e7aa3edc245a3904a0449db24a70
+Payload = 39799b001ed2c334c269acb0f2328c
+CT = 154a533929ec7e9adce94ae69a3d932441dcae1760db90379bd354fa99164e
+
+Count = 157
+Adata = efd7270e0396392fde8b0ddaab00544cbbd504f4d97d4e90d749d1946de90dcb
+Payload = 42143a2b9e1d0b354df3264d08f7b6
+CT = 6e27f212a923b69b5373c01b60f8a9c7c7deb28bdcf84886ef843216b94449
+
+Count = 158
+Adata = 8bc181ce2e66294e803a8dc3834958b5f173bc2123c0726e31f3fca25b622ed6
+Payload = a3dcf26327059a4245b79a38bb8db6
+CT = 8fef3a5a103b27ec5b377c6ed382a935061ae3cd892ba63c44b809d6d29421
+
+Count = 159
+Adata = c39ec70c2c71633ae0dccc41477ac32e47638c885cf59f34ebd4a096d32f91f9
+Payload = 3d54883449ecca8f153436c25a0a01
+CT = 1167400d7ed277210bb4d09432051e3c9ae69a4c59ff8e251c2fe022d065a9
+
+[Plen = 16]
+
+Key = ee8ce187169779d13e443d6428e38b38b55dfb90f0228a8a4e62f8f535806e62
+Nonce = 121642c4218b391c98e6269c8a
+
+Count = 160
+Adata = 718d13e47522ac4cdf3f828063980b6d452fcdcd6e1a1904bf87f548a5fd5a05
+Payload = d15f98f2c6d670f55c78a06648332bc9
+CT = cc17bf8794c843457d899391898ed22a6f9d28fcb64234e1cd793c4144f1da50
+
+Count = 161
+Adata = a371ca29b92ed676bab5dfc4d78631bb6d9bb23a29f822907084a1f0fe17721f
+Payload = 60d55a8d5ab591a51e87fdf6aaa2ad25
+CT = 7d9d7df808aba2153f76ce016b1f54c68b55bbe42d8c97504b97c34a5f16e6a6
+
+Count = 162
+Adata = 01ec87920b42639d4ba22adb1fbe5138d2849db670a2960fd94a399c1532ed75
+Payload = cbf112e4fb85276c4e09649f3de225b2
+CT = d6b93591a99b14dc6ff85768fc5fdc51017d8706acd676ae99e93d5312a4113c
+
+Count = 163
+Adata = eebd2bbf1e9f6d817cd8062a6a9680e7f10464eefeb50b07cb46b14b9b3fcb2c
+Payload = 865b89aa38ee1b5a3ce56620307e8937
+CT = 9b13aedf6af028ea1d1455d7f1c370d45982f0fe5d951a8c62c87894657301e4
+
+Count = 164
+Adata = 72863362612f146699f6b2f6ec3688f2ca6cb1505af7a309c91c1933e34d516a
+Payload = a8efc37d1b8b51f2a47b21dd14da383d
+CT = b5a7e40849956242858a122ad567c1de5addfddbb59f4985947fb3a9ab56333e
+
+Count = 165
+Adata = 9c9efc6593f96207678db813608f2b8bc33ed1bef974ed77ed7b6e74b621b819
+Payload = d9b0eaaff786165f882f41a98dbc0c35
+CT = c4f8cddaa59825efa9de725e4c01f5d6b651053516673402a57538db1a9ce7e9
+
+Count = 166
+Adata = dc482a051b58d8a3904d3af37c37b51983f634a504451bbba6f77d71337f8e78
+Payload = df49d972b6ebbbb18ee975ac635d847e
+CT = c201fe07e4f58801af18465ba2e07d9d86d772b1a1991b7be6589bbccad36171
+
+Count = 167
+Adata = 51ef065a43caa23faf750b02a41ad6ba701aeb8058f6d8738d6f6b005bec7f60
+Payload = 78318aa5cd16699b77bdcea2fc9d1d20
+CT = 6579add09f085a2b564cfd553d20e4c3569387a1a6bcc826e94012670820576e
+
+Count = 168
+Adata = 88e2a74d2920c89c6a101f5f06d0624a6d5eabd9bdb51395ee3983934c55c73d
+Payload = 8e20d65d02dd9a64379f75b6d8328f2d
+CT = 9368f12850c3a9d4166e4641198f76cee9c788b4aae9b2c6caf0c44aa9bd2ed0
+
+Count = 169
+Adata = ada3ed7db2dabbfbc441ef68a5656e628d6d5bd6c1574369688497179a77601a
+Payload = 97e8d8513af41b97801de98cc4269096
+CT = 8aa0ff2468ea2827a1ecda7b059b6975f1df0f01944641a1b04d753e6ab8d3cc
+
+[Plen = 17]
+
+Key = 7da6ef35ad594a09cb74daf27e50a6b30d6b4160cf0de41ee32bbf2a208b911d
+Nonce = 98a32d7fe606583e2906420297
+
+Count = 170
+Adata = 217d130408a738e6a833931e69f8696960c817407301560bbe5fbd92361488b4
+Payload = b0053d1f490809794250d856062d0aaa92
+CT = a6341ee3d60eb34a8a8bc2806d50dd57a3f628ee49a8c2005c7d07d354bf80994d
+
+Count = 171
+Adata = 4ae414bc888a42141d3060c71c2dbbffd425b6a952806982271a8e756b3c9e24
+Payload = 51eb190c6a9f46e8ec1628b090795470c0
+CT = 47da3af0f599fcdb24cd3266fb04838df13c1c5755a5a240c33b2b890a486aac8b
+
+Count = 172
+Adata = 7b7f78ae1a5ee96fdc49dacd71be1a6ac09a6a162d44dea0172886eca5674e46
+Payload = 25144e807e389bb0e45b6dc25558caf61a
+CT = 33256d7ce13e21832c8077143e251d0b2b4cfca1c19abf447d7bc0898d61885144
+
+Count = 173
+Adata = 03f31c6143b77f6ad44749e2256306b8bf82242f2821fad4075b09b388ba81ca
+Payload = dbe1ee14abfe2ecf4edf6db206cf9886ce
+CT = cdd0cde834f894fc860477646db24f7bff229cc7a390867a245dcb7c434f1db347
+
+Count = 174
+Adata = 030390adb572f2bd2a6a4454fd68236cd1d465574328aa001d553375cc63f8a2
+Payload = db6df31f12bf552f81deff5fa2a373fc22
+CT = cd5cd0e38db9ef1c4905e589c9dea401135361b539f9fe0fb7842907c2326aef63
+
+Count = 175
+Adata = 7294ae94358669f2ada4b64c125b248df7fe86c6715e3b6a7b9bb2bd99392c8a
+Payload = ff2a97b49fcc6a50d4549c979d53ccc51f
+CT = e91bb44800cad0631c8f8641f62e1b382e8ed10943929e7d7bf798b2ae8371aae5
+
+Count = 176
+Adata = 4d1513478fc1fb0a18eb6d2a9324fefbd975ecd1b409025de826bc397462acc1
+Payload = 73ddfa0185200a890b7690a7e3986d8818
+CT = 65ecd9fd1a26b0bac3ad8a7188e5ba7529f92b9e49ab83f113f8949dc9e4a36e0d
+
+Count = 177
+Adata = b26a7ff61bfe94864249af7cc9b4a723627dd4463f5a22f0ca6063769522eab7
+Payload = 5c7604f9ac8fdf30ee5820e5aeb75b65d7
+CT = 4a4727053389650326833a33c5ca8c98e6d0e53223adff22a08e3dddf66fff23e3
+
+Count = 178
+Adata = 960f9a85cfbfb6eab223a4139c72ce926a680ea8e8ecc3088cf123de659ad310
+Payload = d44fdfd9da3a63c1083afe574e91bf01c9
+CT = c27efc25453cd9f2c0e1e48125ec68fcf833f49a42521a7a2367f91bfcc2180b7c
+
+Count = 179
+Adata = 3718467effb5d5dc009aaefce84d8cb4fe8f80eb608f4c678f5d0de02ea11e59
+Payload = bb515dc227abb9acad8fefaa14771bb77b
+CT = ad607e3eb8ad039f6554f57c7f0acc4a4ac08bd395c6807223311070659f550934
+
+[Plen = 18]
+
+Key = 0786706f680c27b792d054faa63f499a8e6b5ddb90502946235bf74c022d772c
+Nonce = f61ef1c8c10a863efeb4a1de86
+
+Count = 180
+Adata = 67874c808600a27fcab34d6f69cc5c730831ad4589075dd82479823cb9b41dc3
+Payload = 6a26677836d65bd0d35a027d278b2534e7df
+CT = d1c1f3c60603359c7d6a707f05ecb2296f8e52f2210b7a798ad5c778ee7cfd7fe6e0
+
+Count = 181
+Adata = e0c27cddf919d3092d9a34766c89a5ae6dcf39fe954d1e6f1a70ddf96805def4
+Payload = 4021ff104ff1dbd91e46db249fd82198b0a1
+CT = fbc66bae7f24b595b076a926bdbfb68538f00923bb5a347af13df12f234fca5f03ef
+
+Count = 182
+Adata = 7ae9eca03f616ab39ebb3be26b848842b4aa584e5c8e5695065ad5af34951175
+Payload = 6a681f164efce199a787bccff223b8ae1a98
+CT = d18f8ba87e298fd509b7cecdd0442fb392c9d03ed7bffac83e890caceb6903d9cab5
+
+Count = 183
+Adata = b47c9bc4eb01c74f5db2e6a293bef80db18c58cf06feef7ee0f8a7a9a51c22bb
+Payload = 7861dac338ba3f8274dca04c8c6f92b6d44c
+CT = c3864e7d086f51cedaecd24eae0805ab5c1d4dd8f30870025b2bd1e2a2511574d3e7
+
+Count = 184
+Adata = f6afd661f218c7426b92ee53e65d14898cd0c78a7e594fcc6ac0e3fb5cab1c9c
+Payload = a3f0473c620d2739d5ba4f7156f88d0fb669
+CT = 1817d38252d849757b8a3d73749f1a123e386046d17f337f3cb49884d94995edbdc9
+
+Count = 185
+Adata = d3802911e341577046cfc61d9043b4af059fb4bef3c6a2ff46ccdcb05670af37
+Payload = 07c535d9456a6ff1e41321150d16dae3f7a3
+CT = bc22a16775bf01bd4a2353172f714dfe7ff25fdc77b43bca254d6459263cdfed8fbb
+
+Count = 186
+Adata = db60720db67a60ca286fe744d46173c231fbcc7deb4c9b0d87d52a2247e06b74
+Payload = 5ee220720a896249efdab2ce418318bb5ebf
+CT = e505b4cc3a5c0c0541eac0cc63e48fa6d6eedd1a1d36c8164c55d55dbf0ff1e9517a
+
+Count = 187
+Adata = 57f70ba5493265b30491decc726354e2065e7971a2efd56db9cf0f79b1d76859
+Payload = 98e4eb0361c8bf40bcbe0539b0850e4c35ff
+CT = 23037fbd511dd10c128e773b92e29951bdaeb476e2ca48fd52bec0539b00744a8a07
+
+Count = 188
+Adata = 4a29b9ad548964942f87f28ba267ec0d0e8f72c73b3823ee57693dd63c2605c1
+Payload = 7f0745bea62479c0080ecec52e37c1e32d72
+CT = c4e0d10096f1178ca63ebcc70c5056fea523fad68c62b81d62f2d490ae74f5bb1465
+
+Count = 189
+Adata = acbd2e9911b3218a230d9db5086d91dccac3fc93fc64b0f4a15d56954906b2b7
+Payload = e99ed2ac6c38e033061b5d85f3e77dd72518
+CT = 527946125ced8e7fa82b2f87d180eacaad4913b15d8000266c61ba5aec898eb35b52
+
+[Plen = 19]
+
+Key = bac55f9847d93325bf5071c220c0a3dfeb38f214292d47b4acb7b0a597fe056f
+Nonce = 05b50c458adbba16c55fcc454d
+
+Count = 190
+Adata = 89ad6ae1e550975eaa916a62615e6b6a66366a17a7e06380a95ea5cdcc1d3302
+Payload = c1a994dc198f5676ea85801cd27cc8f47267ec
+CT = 7c9b138177590edaafec4728c4663e77458ffbe3243faec177de4a2e4a293952073e43
+
+Count = 191
+Adata = dfddb719d00398bf48a6cefd27736389e654a93b8595cd5ac446af1996e0f161
+Payload = 791e232bfb42fb18197adc1967da1a83f70168
+CT = c42ca4769594a3b45c131b2d71c0ec00c0e97f8422f736fc435687634d42254b22fd99
+
+Count = 192
+Adata = 58ef310997dcaf067dd217274921504da6dbf0428a2b48a65fe8a02c616ac306
+Payload = 3d4127942459bb8682e662dfc862467582fa68
+CT = 8073a0c94a8fe32ac78fa5ebde78b0f6b5127f38a96e68ef7dbaef1b460cc0980eacd4
+
+Count = 193
+Adata = 511e5d5e100b595f6b20e791830bca37e23f7b785e482a58405bffe7a632a5b8
+Payload = 0e71863c2962244c7d1a28fc755f0c73e5cbd6
+CT = b343016147b47ce03873efc86345faf0d223c15c5c702a82d468929227502e4e35796f
+
+Count = 194
+Adata = e48dfaa53b6807ea6f01d8dca67960b9f321f7851f324459a9bf61fe0be73abb
+Payload = e0f1cd013e6aea4fa484fc3fa35d348b1a2399
+CT = 5dc34a5c50bcb2e3e1ed3b0bb547c2082dcb8e89188c0940182dd99a902d158c5b0810
+
+Count = 195
+Adata = c12c0423fe36e4c88775dd00b4af267b85b7dd2a37a742a3156923c8917c97a3
+Payload = b1cc1946b4fc1dbd033254cdf536f61e9f9cd7
+CT = 0cfe9e1bda2a4511465b93f9e32c009da874c015849acbb7af1892790300bb84fb0558
+
+Count = 196
+Adata = 4255f8af18df7237e0abe98421aec9634443561752d893aaffe76380e829ef32
+Payload = 87284658928208e3bddca83e3ceb13708d88d4
+CT = 3a1ac105fc54504ff8b56f0a2af1e5f3ba60c3e75aaf3077ac6dfb5454851ec3910de6
+
+Count = 197
+Adata = ab83567833d2f3461b5fbecc0e366694bb5ea00933b2b3e792ec3aefe20325df
+Payload = bdb79f931ef3035a33bdd1b032fd9de8f6b2ba
+CT = 008518ce70255bf676d4168424e76b6bc15aade70f42e3e1f2b5bb58433bd11f5dea1f
+
+Count = 198
+Adata = bd1446ba3185d1c16551730947c22142142caa8cc1c540e89ab734ec297401bc
+Payload = 1f9c3a8eb8bc59f3869e10f73883aa8f8990cb
+CT = a2aebdd3d66a015fc3f7d7c32e995c0cbe78dc564f6248cefe5fc7cfb547c90a558925
+
+Count = 199
+Adata = b87577755d2d9489194f6f7cfabf267dc3433a9c91954e81beb72c5e06870922
+Payload = 5f28809181f9a889894da8d6fe1fde6cce354a
+CT = e21a07ccef2ff025cc246fe2e80528eff9dd5db52249d812f7f235afa0732e984e91b2
+
+[Plen = 20]
+
+Key = 8beedeb85d42c2a7fa6f7237b05acb197dd8e1672471ac878064fe5319eab876
+Nonce = 8479bdfad28ebe781e9c01a3f6
+
+Count = 200
+Adata = 7aebdfd955d6e8a19a701d387447a4bdd59a9382156ab0c0dcd37b89419d6eff
+Payload = 7b125c3b9612a8b554913d0384f4795c90cd387c
+CT = 6cc611d816b18c6847b348e46a4119465104254a04e2dfeeeac9c3255f6227704848d5b2
+
+Count = 201
+Adata = d119f300fbd74e754a200ea2c3f9fabc1466d02078c84245db693eef3f5672a6
+Payload = 8b013f5782d5d1af8dbd451a4202866095dac975
+CT = 9cd572b40276f5729e9f30fdacb7e67a5413d44338d48329997c5981d678b5e24a6f01b0
+
+Count = 202
+Adata = d6204303b86acf62d5ab860ca70161288ede56e3cf017c08dca56fd2d6f8f6fe
+Payload = b2b1d82a5523b72ea366a680922ed3a4624536c4
+CT = a56595c9d58093f3b044d3677c9bb3bea38c2bf2a77e3ab68e0a73519591a33ed098b758
+
+Count = 203
+Adata = 8557e22eb4529b43f16b1f8ae47c714ac8a2c827c1408a47704778b4c5b52601
+Payload = f8c4eb4285d3d7744da52775bb44ca436a3154f7
+CT = ef10a6a10570f3a95e87529255f1aa59abf849c1cff6c24251c2fb7b8604dfa10c60ef4a
+
+Count = 204
+Adata = 8c1a4187efbb3d38332f608f2c8bbe64247d9afa2281ced56c586ecb4ab7a85e
+Payload = 6e7fe35fa39c937a0e6b3a8c072e218650f42b8d
+CT = 79abaebc233fb7a71d494f6be99b419c913d36bb6c3c39f915d081d34559179869b32d81
+
+Count = 205
+Adata = a41bb1f256228302cd0548ae2148ff42774d18c2d6d3e38b36bc4938da13bac3
+Payload = 917b467d841850fc6e648f1bc298a7f9f1ee38ca
+CT = 86af0b9e04bb74217d46fafc2c2dc7e3302725fc9389a6a6a74c6eb0e1f87562469f2082
+
+Count = 206
+Adata = b0b024e20c4f75a6dad54c21a9edbce846792e957878b1c8ed2d916c757e2b3c
+Payload = 2b4314fe1a6bfa786b7cfc13fbee861b348efbf6
+CT = 3c97591d9ac8dea5785e89f4155be601f547e6c03bed3a2f5dfdbfcc0d7ac26c88d1962c
+
+Count = 207
+Adata = 42153925c46fc9d5d328312d62f59bb99fdc4ac479a3386d5f88fefd4b32f577
+Payload = e19fa7f83c79920cbff45c41a9dee8fc99e97396
+CT = f64bea1bbcdab6d1acd629a6476b88e658206ea035ea1d99be344fa1467ee91c73bbca67
+
+Count = 208
+Adata = 37ab2a0b7b69942278e21032fc83eba6cdc34f5285a8b711a08da6acd42299fe
+Payload = 53e0475cf492b3d39dad600f5c58eb0bd0021554
+CT = 44340abf7431970e8e8f15e8b2ed8b1111cb08627936ec10a81b36768b606e9a38b2f4c5
+
+Count = 209
+Adata = 4a17522da707b4b2587a0ae367a2cd2831bb593a18ef442a7977eda6de045878
+Payload = c119a383d9a3d4bff4270a1d22076b346db5f61c
+CT = d6cdee605900f062e7057ffaccb20b2eac7ceb2a11575ae03ea8a57bbe4a67c060367b74
+
+[Plen = 21]
+
+Key = c3a0c126cad581012151c25cf85a44472c23f83b6095b6004f4f32cd60ec2db2
+Nonce = 94ab51ce75db8b046d6ab92830
+
+Count = 210
+Adata = 2a243246bfe5b5ab05f51bf5f401af52d5bbaa2549cf57a18e197597fe15dd8c
+Payload = 73b09d18554471309141aa33b687f9248b50fe3154
+CT = b7e8264ca70fd2a4fb76f20a8ad5da3c37f5893fb12abeeaef1187f815ca481ed8ddd3dd37
+
+Count = 211
+Adata = 0595306eb7441622a49800edee0134492d82320707fceba902af2e0c95fe634a
+Payload = b64d00f3a4df754fa4ee6376922fb67ccce0c6209f
+CT = 7215bba75694d6dbced93b4fae7d95647045b12e7accc2b55011dbe92ce7619e0ad48b4ccf
+
+Count = 212
+Adata = bd439dbefec589e120fb4f9825b315bf86523b85c61791cd4da4c8d474ba2714
+Payload = 2b11d1ac74ffe701ec733d32085b1054132726e622
+CT = ef496af886b444958644650b3409334caf8251e8c71e8b1f4d70d8f4c7df4f22847d36b394
+
+Count = 213
+Adata = cfebe1cf82267394065bcecfada6709c6c35a3ac835644f560d4c9a8c1848364
+Payload = a88f22424643a523aa3d7d88f4364f1290f49dd0a2
+CT = 6cd79916b40806b7c00a25b1c8646c0a2c51eade47a85e76a9d07b7b361ca56d53c34cda50
+
+Count = 214
+Adata = 7a37255b682766a0bfecf78e5162528885a339174c2a49325739d2bd8877e64f
+Payload = c81427bc84c6a3cfefd4c4cb210fe82212977e1947
+CT = 0c4c9ce8768d005b85e39cf21d5dcb3aae320917a2fddb010e7508ad03ad287068ecee6020
+
+Count = 215
+Adata = 619f2ae80070e278615466a3fd6c9acb7b510c5679bed7038889c77e78d8bd32
+Payload = 28c4d6de3e2ce51b849b135d9cfd3084f0e3155447
+CT = ec9c6d8acc67468feeac4b64a0af139c4c46625aa2ddea785e6c470c52c4fdf432fd78b66e
+
+Count = 216
+Adata = b2571e56f66a857daffbdc99370ceddd4a7bed3867d600cc797000a3b7b57a9d
+Payload = 4c88151cafef75832bacef43a06e862349d56b67ee
+CT = 88d0ae485da4d617419bb77a9c3ca53bf5701c690b91232cfbd7ffff252498b35274fb2995
+
+Count = 217
+Adata = db409636e3e3bcd606a91aeb7592009896f9ad2c4cc6b7f578e6ad59c0f8fa22
+Payload = 572855e22ce89bc2bcf09cb15a1765d99973449d61
+CT = 9370eeb6dea33856d6c7c488664546c125d633938472b2c50e5e391ad104f9ee33b94f2872
+
+Count = 218
+Adata = 62c89a835721207a182968c516dc8be45774ec846e8dcab9ab8611888f2a76a8
+Payload = 89ce46b3de3afaf2518d419b1a2ac24cabca269a96
+CT = 4d96fde72c7159663bba19a22678e154176f5194732d69c5d6db1b130102af3dae0690673b
+
+Count = 219
+Adata = 33f30ddd83002eea50fd4a8fae39d0980a04160a22ac88b755ac050f1d1f8639
+Payload = edf1682a626e9fbf3d57bb260e0876c6f92ba5b114
+CT = 29a9d37e90253c2b5760e31f325a55de458ed2bff1489903365970c2673c9fd457e1077aad
+
+[Plen = 22]
+
+Key = 9cdebaeee8690b68751070691f49593668a6de12d3a948b38ddbd3f75218b2d4
+Nonce = af1a97d43151f5ea9c48ad36a3
+
+Count = 220
+Adata = f5353fb6bfc8f09d556158132d6cbb97d9045eacdc71f782bcef62d258b1950a
+Payload = 3cbb08f133270e4454bcaaa0f20f6d63c38b6572e766
+CT = 3966930a2ae8fdd8f40e7007f3fde0bd6eb48a46e6d26eef83da9f6384b1a2bda10790dadb3f
+
+Count = 221
+Adata = e3a1555ffe5f34bb43c4a2dae9019b19f1e44a45fb577d495d2a57097612448d
+Payload = 946e86795c332031e2d1ee09d3d4a101fb6800d00911
+CT = 91b31d8245fcd3ad426334aed2262cdf5657efe408a5587bdd120a7d08cd3841cb117af444fb
+
+Count = 222
+Adata = 9c5d43c1a1269cde199509a1eff67cc83a1759b71c9e7a6ee99f76b98c6e23a6
+Payload = b76ce2ab0065ba1c0a754494991c8c452cb416f18ab1
+CT = b2b1795019aa4980aac79e3398ee019b818bf9c58b0545b32f81dcf03e2bcc2aaf62ad366e97
+
+Count = 223
+Adata = b07452a7900a289b91b2771dfdd5108852536659aa259def7b41e38f80bd03ab
+Payload = a3e0d8d0784155bfc45769c52711d4fa68e8bc390c20
+CT = a63d432b618ea62364e5b36226e35924c5d7530d0d94fea17d78533bc9e022dbfb460afdf499
+
+Count = 224
+Adata = 6b30f55c3101540523a92380390f3f84632f42962061b2724cde78ac39809397
+Payload = 6e6a88abbb52a709b47365ad6aa8016fa9a03a9bd834
+CT = 6bb71350a29d549514c1bf0a6b5a8cb1049fd5afd98056defc6dcaeec80b1c639350ab6f1fde
+
+Count = 225
+Adata = 9fc62d14f8b7a6026509275cff80312ff1ade2b5d9c274cb72a506a571439fc1
+Payload = eba1810d537041821121aeff8e0914ac26a550072c8c
+CT = ee7c1af64abfb21eb19374588ffb99728b9abf332d389d37b7251fb8c0ef2b37c36d51219d0f
+
+Count = 226
+Adata = 6b9389cc42113d639fd2b40cbc732ae0dc7c14513b88b36b45a6ea5a06fe4d2b
+Payload = dfc6692cd2442e5ff1f918c8812a27f81d107d16a12f
+CT = da1bf2d7cb8bddc3514bc26f80d8aa26b02f9222a09bd279d9da4437c8a2a252436508134c56
+
+Count = 227
+Adata = db72d98d63fc10acff7dceec0e2691a80ecee50a0e957ad166c77952a50318bd
+Payload = 9ad338cbfd1b52e6ae4178f05e00062274f8b0b25eae
+CT = 9f0ea330e4d4a17a0ef3a2575ff28bfcd9c75f865f1a63943543bc1c5f5991ecc5964a288f79
+
+Count = 228
+Adata = e98b710c47a4d12a73cd8aa2613fc2910c16f4195ea7f15650132493521d19be
+Payload = 9f5a05db89e0e336da066ce81b79ad9be1d0ec4fb7b8
+CT = 9a879e20902f10aa7ab4b64f1a8b20454cef037bb60c0a49ee2b7ceddcbd28abb24b77d5edee
+
+Count = 229
+Adata = 527817316fc48b105f8ab178dd2db1fefa09c50461aa9d8bdf3c03482343bbf9
+Payload = 58f31e5770070a5d4031fb795dc2d298561d3559960d
+CT = 5d2e85ac69c8f9c1e08321de5c305f46fb22da6d97b9b099a68cfa3572d974e03232e09f37fb
+
+[Plen = 23]
+
+Key = d34264a12c35cdd67ac105e2826b071e46f8131d1e325f8e0ae80a6447375135
+Nonce = 3891e308b9f44c5b5a8b59004a
+
+Count = 230
+Adata = 0cda000ed754456a844c9ed61843deea9dadf5e723ea1448057712996d660f8c
+Payload = 79ac1a6a9eca5e07ce635bfd666ef72b16f3f2e140d56c
+CT = 1abcc9b1649deaa0bfa7dcd23508282d9c50ca7fee72486950608d7bcb39dcf03a2cab01587f61
+
+Count = 231
+Adata = 3fb6ddb76809b8e6d703347664ef00a365955124c603900d5c8d4ff476138252
+Payload = 76d12e3c4c5d990bf563c60aa4999e52998d887f97477f
+CT = 15c1fde7b60a2dac84a74125f7ff4154132eb0e139e05b1c4fb40e5c8bc37152a173d4bbb18c3e
+
+Count = 232
+Adata = d9fc295082e8f48569eb073ac1b9566246728fc62ccaab4a5667c472c98b2626
+Payload = a027c28fbe22111fd4c8a226cfe8531c16d7790d561eca
+CT = c33711544475a5b8a50c25099c8e8c1a9c744193f8b9ee019c359008adae3070b5a543ead0effb
+
+Count = 233
+Adata = 7a459aadb48f1a528edae71fcf698b84ed64dc0e18cc23f27ab47eeabeaf833f
+Payload = fa597e37c26c38694abdcf450f9edc529160fa0d651979
+CT = 9949adec383b8cce3b79486a5cf803541bc3c293cbbe5dbd099ab134756b90746762a92a4a9f7f
+
+Count = 234
+Adata = 484207909dec4c35929ebe82fcacf20d2af6d850bd69364ebac9557adeadfbd4
+Payload = 9e4c8aa9b58a8eabc5586892f5541000b43f17d9a051a0
+CT = fd5c59724fdd3a0cb49cefbda632cf063e9c2f470ef684fa4f6adfec85d055310107ba89198afa
+
+Count = 235
+Adata = 88b5448372548e6aab1b262630a28a471d285514703f1bdb10c695850e18fe6d
+Payload = 7d9582cf9e3bb9ee34dce965f56b08e716589486b0641c
+CT = 1e855114646c0d4945186e4aa60dd7e19cfbac181ec338915d23eb2e952afcc89fbddb567d9d75
+
+Count = 236
+Adata = 0e71863c2962244c7d1a28fc755f0c73e5cbd630a8dbdeb38842d7795d830d2e
+Payload = 5a387e7cc22491fc556fe6a0c060b4911d01f0c11f801e
+CT = 3928ada73873255b24ab618f93066b9797a2c85fb1273aaad6c31828314e24198f005955ca8f5e
+
+Count = 237
+Adata = 2aa7a28da38c42fda2e578d9d6340cd8e80b9b32047c3db296d0640d517b0872
+Payload = 87946e910059cbaf48df63b220f397049c65ca10cd1920
+CT = e484bd4afa0e7f08391be49d7395480216c6f28e63be04e531ebbadccfe47182b41904bbfebcfe
+
+Count = 238
+Adata = 3382051c268891da04e6ca73adcead4029f6a1593be4acfe3968e7351a6a2fb5
+Payload = c62f67d208f1c8ffd5d57df9de15ef54f97fbc07d1630a
+CT = a53fb409f2a67c58a411fad68d73305273dc84997fc42e7c582414154236c09ee704cf4a5de411
+
+Count = 239
+Adata = c352828b1920e53bbb60f2ea6a5f15639659e6f3243405c26f6e48628d5519a9
+Payload = 697e73eaaf562d31bdbf7ce9e78c7426fe1c87e421def9
+CT = 0a6ea03155019996cc7bfbc6b4eaab2074bfbf7a8f79dd57c9990029c89d1b37988745fa5737a3
+
+[Plen = 24]
+
+Key = 4ad98dbef0fb2a188b6c49a859c920967214b998435a00b93d931b5acecaf976
+Nonce = 00d772b07788536b688ff2b84a
+
+Count = 240
+Adata = 5f8b1400920891e8057639618183c9c847821c1aae79f2a90d75f114db21e975
+Payload = 9cea3b061e5c402d48497ea4948d75b8af7746d4e570c848
+CT = f28ec535c2d834963c85814ec4173c0b8983dff8dc4a2d4e0f73bfb28ad42aa8f75f549a93594dd4
+
+Count = 241
+Adata = 1ae8108f216defea65d9426da8f8746a3ae408e563d62203063d49bf7e0d6bdf
+Payload = 2b223932fb2fd8433e4b1af9e8234a824569a141f6c96a69
+CT = 4546c70127abacf84a87e513b8b90331639d386dcff38f6f4de907a59c5e4d3f21e1348d7cdf92b6
+
+Count = 242
+Adata = 460f08114b1015fe8b7a9b5dd1b9e6a3d28367c4bd15f29b13c02a8cb9a53968
+Payload = 4d57cbe4a7e780d4ed17267d5ebc91750c2f0209e0444bd2
+CT = 233335d77b63f46f99dbd9970e26d8c62adb9b25d97eaed4ff4239544e2f354d6c6837cd9c23b884
+
+Count = 243
+Adata = 860f4428259d9c5b17698cc95363db6cfee603258582e3a3e8feb886599d4ac4
+Payload = fda8665f87c618646a89c7abdca275fd10c31453ad4b9c99
+CT = 93cc986c5b426cdf1e4538418c383c4e36378d7f9471799f3f6c6f7cc494201069344e2d6d41bd9b
+
+Count = 244
+Adata = 1b43c482f83780c21583f88e5afcf6938edd20f21b74d895161b60c27a6a42f0
+Payload = 98104fd3f3413ad1f57ef4912cb50097dca379a58c47b0d2
+CT = f674b1e02fc54e6a81b20b7b7c2f4924fa57e089b57d55d43787a15352cfceb028202c8730beaa7a
+
+Count = 245
+Adata = b082ccd964617c27a5607b7324faad237ee53acfc18c35502dbf7c1937a9dfcb
+Payload = b46b343e64d2d70e0bd909dbb3f6bedf7e4adc74321be526
+CT = da0fca0db856a3b57f15f631e36cf76c58be45580b210020f3a0ca3da647eb31893e867956097983
+
+Count = 246
+Adata = b8539ba93ef17254ec1d8d62e8f4eae4d41ee1e75345bf90c9cbb26c63bce501
+Payload = 8e12620bb575e6b167b085255b2b5631ff28e04cbef8826d
+CT = e0769c3869f1920a137c7acf0bb11f82d9dc796087c2676be663fbbebbc251b9f1760afa49e89e71
+
+Count = 247
+Adata = b6b09463b5ef5ead1f17f4021693a0d8452e98dcbb8e7590f9fde6394970a6f8
+Payload = 792aaa23b923d1b53173fe19853b9aa402a301d48529873e
+CT = 174e541065a7a50e45bf01f3d5a1d317245798f8bc136238da90cd87e9d9ca5d85430a150e682752
+
+Count = 248
+Adata = 390f6de14d5e1f2f78dbe757c00b89209d0cf8bc48cbbea035779f93de357905
+Payload = ddc5b4e48970ebd72869be6998e9103c014475e8ae6ea29c
+CT = b3a14ad755f49f6c5ca54183c873598f27b0ecc49754479afc0cc4601afb61efa7059cfe49ec9dde
+
+Count = 249
+Adata = 1d75c9e7acb09932db332498d30f82e4009025cb1827047c59a8f97812b568a4
+Payload = d2b66096c475a77648c27235e6972ba8f18761330d3c6adf
+CT = bcd29ea518f1d3cd3c0e8ddfb60d621bd773f81f34068fd9cf7474962c3602dcfcb50039f43e3d6f
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VTT128.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VTT128.rsp
new file mode 100644
index 0000000000..a05492b485
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VTT128.rsp
@@ -0,0 +1,393 @@
+# CAVS 11.0
+# "CCM-VTT" information
+# AES Keylen: 128
+# Generated on Tue Mar 15 08:09:25 2011
+
+Alen = 32
+Plen = 24
+Nlen = 13
+
+[Tlen = 4]
+
+Key = 43b1a6bc8d0d22d6d1ca95c18593cca5
+Nonce = 9882578e750b9682c6ca7f8f86
+
+Count = 0
+Adata = 2084f3861c9ad0ccee7c63a7e05aece5db8b34bd8724cc06b4ca99a7f9c4914f
+Payload = a2b381c7d1545c408fe29817a21dc435a154c87256346b05
+CT = cc69ed76985e0ed4c8365a72775e5a19bfccc71aeb116c85a8c74677
+
+Count = 1
+Adata = 79db716e6b0b1627890d378c4560eba7871883d94527be3454dc3c257ea93556
+Payload = 47f4cdd574264f48716d02d616cf27c759fdf787cdcd43b1
+CT = 292ea1643d2c1ddc36b9c0b3c38cb9eb4765f8ef70e84431676e2df1
+
+Count = 2
+Adata = 0d02778f90a164a4f9ada9dc7fd24eeb941069621418ef32c3f9ca6bf6fb2c4a
+Payload = 5eadeaec29561244ede706b6eb30a1c371d74450a105c3f9
+CT = 3077865d605c40d0aa33c4d33e733fef6f4f4b381c20c479eb1321a1
+
+Count = 3
+Adata = 02e5a1306f612bdec098458cff3e691d93f050ba11ba627355dc7029d2cea5ab
+Payload = aac9fb69fed114c62db65090947096a2f5c85c271c6a6d53
+CT = c41397d8b7db46526a6292f54133088eeb50534fa14f6ad3dd8cb4ca
+
+Count = 4
+Adata = 25144e807e389bb0e45b6dc25558caf61a2263869c4d0e4079d07674d7091110
+Payload = fb6e8d38ce38a8c1e710f3a33c682e6dabf055fb33fe75f8
+CT = 95b4e1898732fa55a0c431c6e92bb041b5685a938edb7278b659a844
+
+Count = 5
+Adata = be303c1ed9327ad88dae7cb5930b5a786d4f5477ef9370a9fdb56501964cb8fa
+Payload = 87d81389a6062e8ed501ea964c2fe35b2d3de9fd676c04f7
+CT = e9027f38ef0c7c1a92d528f3996c7d7733a5e695da490377e9e5e005
+
+Count = 6
+Adata = 46dfb8f3e06c3f168e5ac9b341e7710d7b9c6a19b32389eafb58036de0a27756
+Payload = e1bd9095fa9bb811e4054643feea3eac13fb57b43a0502a0
+CT = 8f67fc24b391ea85a3d184262ba9a0800d6358dc87200520c9fc48e0
+
+Count = 7
+Adata = 19eb03c35c352b79e8c32fa40bb9759b0565e04a6c18519ace346e2e9987a250
+Payload = 92f7dc22dcbbe6420aca303bd586e5a24f4c3ed923a6ebe0
+CT = fc2db09395b1b4d64d1ef25e00c57b8e51d431b19e83ec60ac73022c
+
+Count = 8
+Adata = efa6ddd6fb8e4480a0f64414694e5f9e7f2e9b97cbe9cd145b65173d072ab001
+Payload = cecdf831c4044c8fe149e4cd579a1aecf222bf8e9dadba09
+CT = a01794808d0e1e1ba69d26a882d984c0ecbab0e62088bd895dc8d581
+
+Count = 9
+Adata = 1b156d7e2bf7c9a25ad91cff7b0b02161cb78ff9162286b0622fccda2e251c97
+Payload = 7cfb0973ea13dedc33ef6728db90f47559273ea6d3cd4db6
+CT = 122165c2a3198c48743ba54d0ed36a5947bf31ce6ee84a36b941b65b
+
+[Tlen = 6]
+
+Key = 44e89189b815b4649c4e9b38c4275a5a
+Nonce = 374c83e94384061ac01963f88d
+
+Count = 10
+Adata = cd149d17dba7ec50000b8c5390d114697fafb61025301f4e3eaa9f4535718a08
+Payload = 8db6ae1eb959963931d1c5224f29ef50019d2b0db7f5f76f
+CT = df952dce0f843374d33da94c969eff07b7bc2418ca9ee01e32bc2ffa8600
+
+Count = 11
+Adata = 463c65fa7becae5605af80d1feca59075ee88c0abfc72cb463312b3c772ec308
+Payload = bde3fc83287ddd1227bdab4305102c94d885412eb332bf6b
+CT = efc07f539ea0785fc551c72ddca73cc36ea44e3bce59a81a8b847d3a0c98
+
+Count = 12
+Adata = ab153b0a8933f2eb0d721621c86de0cfe100d13e09654824b09d54277912c79d
+Payload = 82176e573c6070faa08d18b5957f119bb1ff51d744b04240
+CT = d034ed878abdd5b7426174db4cc801cc07de5ec239db5531fb4f9d559a8e
+
+Count = 13
+Adata = b22aba8d3e9f4b4bf006e26062de15daf94597731a6009129bfd12957877b1ce
+Payload = bcfc4485eaf225d945146374b737cdf5301c7738ea9f142a
+CT = eedfc7555c2f8094a7f80f1a6e80dda2863d782d97f4035b1e09ff3d6a6c
+
+Count = 14
+Adata = eb80a43c5986deee6925d7c6d53cbdcbe11194843ea133f72d3590d8e8363efa
+Payload = aa182e3ec4fb2f7a905c03582b2ee100ab81a9a311a778bc
+CT = f83badee72268a3772b06f36f299f1571da0a6b66ccc6fcdb60ba1175f1b
+
+Count = 15
+Adata = 3ee186594f110fb788a8bf8aa8be5d4ad52d6e3bd5f406f080d9df0d7553a851
+Payload = 8ad6db8216af16bfda3261a220d078cc98c8ad134e4a80ca
+CT = d8f55852a072b3f238de0dccf967689b2ee9a206332197bb4a75860f3dd6
+
+Count = 16
+Adata = d36fc18b5b12662ff5f6ea55af7c7a82d25d386220e399a85a590b1505c0dcd5
+Payload = a65d24bd1ab92d8d294d654423412860e113c976f12ed76b
+CT = f47ea76dac6488c0cba1092afaf638375732c6638c45c01a00cf106d70a4
+
+Count = 17
+Adata = f0028503e7cd54474c56dc8b2416fe41f416eed73c63ddd141bdd51a0f8fe49c
+Payload = 6e9dc61dd9cf19a6eebc10c9b51c13970636de2c9ea33592
+CT = 3cbe45cd6f12bceb0c507ca76cab03c0b017d139e3c822e3c0193a87ddfb
+
+Count = 18
+Adata = 9a58a226a578bda012dbd7d04b11c879179aaaa36c6145418586cb103360c6c2
+Payload = b526896c11e514b5b4c26351859e2a33800fefd6fd9e6d1a
+CT = e7050abca738b1f8562e0f3f5c293a64362ee0c380f57a6b444d9b63ffab
+
+Count = 19
+Adata = c015fb08540755a8a8adc387d60553478667158964202eb2d25e28efd94c8c76
+Payload = 88907b639f3fd07f40bf6b9b6334b11b2852557975721bf3
+CT = dab3f8b329e27532a25307f5ba83a14c9e735a6c08190c82c339ba21fcf7
+
+[Tlen = 8]
+
+Key = 368f35a1f80eaaacd6bb136609389727
+Nonce = 842a8445847502ea77363a16b6
+
+Count = 20
+Adata = 34396dfcfa6f742aea7040976bd596497a7a6fa4fb85ee8e4ca394d02095b7bf
+Payload = 1cccd55825316a94c5979e049310d1d717cdfb7624289dac
+CT = 1a58094f0e8c6035a5584bfa8d1009c5f78fd2ca487ff222f6d1d897d6051618
+
+Count = 21
+Adata = 25865c1b89f1973bfa680d8458df35a56993a7e81e407e061794004068e481ab
+Payload = 36004342dd74e7966692a848b2c11e1fc311eac9d9cef616
+CT = 30949f55f6c9ed37065d7db6acc1c60d2353c375b5999998ceca422687f41550
+
+Count = 22
+Adata = e6209480da9e49172ba58a9048f2f1b0349030e8e7a79dcdf295eecd613f401a
+Payload = e81f4fb360bcae372d8be3f32655a29bc10a2f31876173cc
+CT = ee8b93a44b01a4964d44360d38557a892148068deb361c42d2b981fc741f2591
+
+Count = 23
+Adata = 112c969882e685b4ae1ee6b67f680e6a1d9d840e627d12118f991c1a3d71314c
+Payload = 27d6443e729d35d7a0690fcb7fe0b20892875f60b5d8763a
+CT = 2142982959203f76c0a6da3561e06a1a72c576dcd98f19b4a1fd47cd41fcf013
+
+Count = 24
+Adata = 73ef62870c50faca5d4e6c6ec45fa7b54bf79ed229fcf1fc8c79c9c09596039b
+Payload = 6c17ad5496dfccde8b877630e1e582dab52aaabe385a321f
+CT = 6a837143bd62c67feb48a3ceffe55ac855688302540d5d9143eb86ffa6958d71
+
+Count = 25
+Adata = b537f0f2981405f6069b401966656461b3516a32d181777121a60cea537e7cef
+Payload = dc4a1e39561f14321238272adff8b74a4e770c0a0c864a52
+CT = dadec22e7da21e9372f7f2d4c1f86f58ae3525b660d125dc1dfc38975c948d29
+
+Count = 26
+Adata = 96bd747ccdcd5fa6cd920514a2f38203e82ee9c7ec6e88080e9f6e2a6a812b0d
+Payload = c51958d7d7d39906b14d4ebb574db881355ec3e6b41838dd
+CT = c38d84c0fc6e93a7d1829b45494d6093d51cea5ad84f575320a48ee3845d9e7a
+
+Count = 27
+Adata = 690d6a2377314fc2f7dd06ae401e3585c79faf648a7af358ae4ef615669222eb
+Payload = 9eaf24f84e8818e286410de321d65ffbf25d1a14073c60da
+CT = 983bf8ef65351243e68ed81d3fd687e9121f33a86b6b0f54884188f946c9a317
+
+Count = 28
+Adata = 748dc83299a43033239ad2fef2dc3d72b76a38ca127607cef72de94a56d5e5c0
+Payload = 71c8eb0079559a306e236c49b7ce1b6cfe26c7888733eb7e
+CT = 775c371752e890910eecb9b7a9cec37e1e64ee34eb6484f00ae2dd33327f8459
+
+Count = 29
+Adata = 35a49535684637f67573fb0b4fdc1bdd8a57650a1d8f29b866fa552a6e0cdf91
+Payload = f09569906381138cc49e3fc2384c5d33c34abd3d617c487b
+CT = f601b587483c192da451ea3c264c8521230894810d2b27f5c50821a48b93d0ca
+
+[Tlen = 10]
+
+Key = 996a09a652fa6c82eae8be7886d7e75e
+Nonce = a8b3eb68f205a46d8f632c3367
+
+Count = 30
+Adata = c71620d0477c8137b77ec5c72ced4df3a1e987fd9af6b5b10853f0526d876cd5
+Payload = 84cdd7380f47524b86168ed95386faa402831f22045183d0
+CT = a7fbf9dd1b099ed3acf6bcbd0b6f7cae57bee99f9d084f826d86e69c07f053d1a607
+
+Count = 31
+Adata = 7b40b3443d00a0348a060db109e8882157612c43084ac5c3e9c5350c88bc165d
+Payload = 7ebb051741145a3bad87131553375c6debcbcecee9b79ee4
+CT = 5d8d2bf2555a96a3876721710bdeda67bef6387370ee52b694af9359a96acfb31a4a
+
+Count = 32
+Adata = 5cab3b84687070956916c11cab0ceea61adb6ea1f909be63d73df96fbfa3a9f4
+Payload = 35a29c1bcbe2182f34fe05f09dfb9ac4a496f95819ef11ec
+CT = 1694b2fedfacd4b71e1e3794c5121ccef1ab0fe580b6ddbe36d3920d1012bf093a5c
+
+Count = 33
+Adata = 6d440b44a069a6967f8750c3b4f8118798fe32d2eaa696ccc7f24e16d6366753
+Payload = a0e21d971876ae4048a61b43a3ac07c685005a20bccbe6ec
+CT = 83d433720c3862d862462927fb4581ccd03dac9d25922abec23025c1776811647f99
+
+Count = 34
+Adata = 06904325b8c6fc2b5a0412ba8062cd48d3af51beacb5ced9e2bdf8d0e056b738
+Payload = 8d333ed7d4b208e794e1673f6df692caee4e3a00fc49115e
+CT = ae051032c0fcc47fbe01555b351f14c0bb73ccbd6510dd0c6efeeaed29e65f1a8908
+
+Count = 35
+Adata = e5049e1c32f0a000024882e4fca9b77adb6c87fdbad96d0c8e97bdb8f46789dc
+Payload = 4189351b5caea375a0299e81c621bf434b6b97da68ad44be
+CT = 62bf1bfe48e06fed8ac9ace59ec839491e566167f1f488ec70d42f84a5411dfa43f9
+
+Count = 36
+Adata = 6f0be1905d1b5b607574ad93a1e7b4a536020fc6798acae862253916a0562707
+Payload = 5a063a24410b3d265c9a32a027cb2382a52bb8e35db15b98
+CT = 793014c15545f1be767a00c47f22a588f0164e5ec4e897caadd2256112d1f7d04934
+
+Count = 37
+Adata = a90f9f55ef22f5e6c542ed3573a9ab67d9c3b6775587fc2be70817479347ce00
+Payload = 0b72cb09a444be2d7b34cf9997fc5b885851d7e6092008b4
+CT = 2844e5ecb00a72b551d4fdfdcf15dd820d6c215b9079c4e6e187f5f37e8a5029ca4e
+
+Count = 38
+Adata = 4dd64fd7d8b571704cddabef854c51691ace4c30de74bfecad42eaed65284ebf
+Payload = ce2d996c9a4cf85edb888822773e03179feeb9e4b0928d6a
+CT = ed1bb7898e0234c6f168ba462fd7851dcad34f5929cb4138fbbb92009435f9ab6691
+
+Count = 39
+Adata = 75f4031d2e5098a9ea3eaa20c2423fbc1705ea18289efb96e311f3fefc153b67
+Payload = aa182e3ec4fb2f7a905c03582b2ee100ab81a9a311a778bc
+CT = 892e00dbd0b5e3e2babc313c73c7670afebc5f1e88feb4ee3cae38db7cc9d577b0ed
+
+[Tlen = 12]
+
+Key = 3ee186594f110fb788a8bf8aa8be5d4a
+Nonce = 44f705d52acf27b7f17196aa9b
+
+Count = 40
+Adata = 2c16724296ff85e079627be3053ea95adf35722c21886baba343bd6c79b5cb57
+Payload = d71864877f2578db092daba2d6a1f9f4698a9c356c7830a1
+CT = b4dd74e7a0cc51aea45dfb401a41d5822c96901a83247ea0d6965f5aa6e31302a9cc2b36
+
+Count = 41
+Adata = 78230f73f9c0150f630eca4cd679818551d449db82e665d8dc25fc53ebc11293
+Payload = 048ba28abb191ded5449dfe9dc7d19f9b132a2a9fd779aab
+CT = 674eb2ea64f03498f9398f0b109d358ff42eae86122bd4aa6356e2548a22e7cbee3b89d4
+
+Count = 42
+Adata = c09191a7d2fca98fca486f8843f275a78d57b8c9a6d330d5652ba641f928c6d8
+Payload = adf51386b3cc133ea9d18e679fe4bbf10ea780b7bed57d6a
+CT = ce3003e66c253a4b04a1de85530497874bbb8c985189336b35516f170a2aada38d1d94eb
+
+Count = 43
+Adata = ea46cc1a7ba5afaa6176f8dedc049283d2ac38fa74ef37ea1fc575328033b222
+Payload = f660a28551416b2f8e21466ba99daee280a91740d98219cf
+CT = 95a5b2e58ea8425a23511689657d8294c5b51b6f36de57ceea2d3237788a02ff15258351
+
+Count = 44
+Adata = 3093b74eb088bdd59999629d59509920938f4feabbd29df8e0b44364c8b55244
+Payload = b9a96f0e4c6dea8861e888bdd693b300017718da958aaa00
+CT = da6c7f6e9384c3fdcc98d85f1a739f76446b14f57ad6e40165fb6719509987930d350890
+
+Count = 45
+Adata = 5580672e52aacb9d714a34c31c33fc221e13e8f90849adbad3f6b3bec8571838
+Payload = cc4acdbd34ec9b7cbc3e23a53e0627c2a7c63206f3e0298d
+CT = af8fddddeb05b209114e7347f2e60bb4e2da3e291cbc678c8ecdf173444c334cfda5b22b
+
+Count = 46
+Adata = c7acf1b17609dc336df1006ffac6497777cdfd497c8c91525377c130accce0bc
+Payload = ed75d28be4794ad81bbc0f26a11c5466f23c0270d2d7b8f8
+CT = 8eb0c2eb3b9063adb6cc5fc46dfc7810b7200e5f3d8bf6f92221c860022d92b0f961c3e6
+
+Count = 47
+Adata = ac1adca686e1d129142c49f26b52941d037d8052b8a27d5215b7ffcfd2202481
+Payload = b8234b8bd34d9c6ceffebbb85722764e7d37e43c495256e0
+CT = dbe65beb0ca4b519428eeb5a9bc25a38382be813a60e18e11c73d6a695afc704228ed7a1
+
+Count = 48
+Adata = 472bf7946bce1d3c6f168f4475e5bb3a67d5df2fa01e64bce8bb6e43a6c8b177
+Payload = 790134a8db83f2da35dde832c3ae45ec62aff0274495d6e7
+CT = 1ac424c8046adbaf98adb8d00f4e699a27b3fc08abc998e6bf1e81950e44c63183a679d7
+
+Count = 49
+Adata = 1340ac7ff04dd7450afc13f8fa52df6d526c744a2dc2f76b0aadf284da270508
+Payload = 21ea2f778cf37aa02fea30e855c20a77909548da4ee7eb61
+CT = 422f3f17531a53d5829a600a99222601d58944f5a1bba560c2c3a1876e49a47a9b44b737
+
+[Tlen = 14]
+
+Key = 7b2d52a5186d912cf6b83ace7740ceda
+Nonce = f47be3a2b019d1beededf5b80c
+
+Count = 50
+Adata = 76cf3522aff97a44b4edd0eef3b81e3ab3cd1ccc93a767a133afd508315f05ed
+Payload = ea384b081f60bb450808e0c20dc2914ae14a320612c3e1e8
+CT = 79070f33114a980dfd48215051e224dfd01471ac293242afddb36e37da1ee8a88a77d7f12cc6
+
+Count = 51
+Adata = 41aa11ec55980609482575b97eee172590ff545d5798fd4246313da3fdbbcda6
+Payload = 811d54bad842a8b92b96fc03b4fff8b5f1939fd3a49876dc
+CT = 12221081d6688bf1ded63d91e8df4d20c0cddc799f69d59ba850b0116f3269b5e44e57de7166
+
+Count = 52
+Adata = dedfb02e93b975270f50cffa3351c85975a7b21fd89bbb921c40c1e5310e6702
+Payload = 8bbf87b490020b863fc596a8d169d79c0cb3506e1f1f5aa2
+CT = 1880c38f9e2828ceca85573a8d4962093ded13c424eef9e50f053627bd0c90714820c4fbe5ec
+
+Count = 53
+Adata = a727ed3d13331ee6a224ae4b73f0ccb04b997fcf88533a1f57e9b055275de92b
+Payload = 7294ae94358669f2ada4b64c125b248df7fe86c6715e3b6a
+CT = e1abeaaf3bac4aba58e477de4e7b9118c6a0c56c4aaf982df865a77d66f1232cd7e36af3d1be
+
+Count = 54
+Adata = 6704dc39a259152d2dc3f08b8799ffecf4e1bc38ce5b77c71cc293c6664ef2dd
+Payload = 48033c46389f6221fb9cdda1ecb8fc25fdec6afe4eaa5fd0
+CT = db3c787d36b541690edc1c33b09849b0ccb22954755bfc97e1fba154f6b166549d0d6bb9b573
+
+Count = 55
+Adata = 6cba004dfb5e5d9e1433bf1223039ae1d2df89cd2db68f550327a22c8f946ae9
+Payload = 01acc909b7d3bb3b3e1f72845f05238d2e1d9162976d3bd2
+CT = 92938d32b9f99873cb5fb316032596181f43d2c8ac9c9895c485e9e28ae33959f8acbb640fbf
+
+Count = 56
+Adata = dd5799710523aa1da0b1209fab1e6f2ed177444ed3880d462deebbd5f774c621
+Payload = 3706def87786e49baec2d13407865286cb4e05908cac430f
+CT = a4399ac379acc7d35b8210a65ba6e713fa10463ab75de0488ef976fa9bda9544ed94ef266ed2
+
+Count = 57
+Adata = 5d7505ff863d218f6822150455b977ad2df3c02be094f6832ee68872b1ae7a01
+Payload = f38d4b225d9b80a0c5fadc61476aef419ad3d18937d8661f
+CT = 60b20f1953b1a3e830ba1df31b4a5ad4ab8d92230c29c5580caadf1dbd07515e3bfb6992e2cd
+
+Count = 58
+Adata = 796b62c7abf797de7f6bad8bf5d549688ccb7ada62fff9469c14b08208b07a8a
+Payload = 993bb3a85f67f6c1a809d8094ee80e2ad9b694063af2fdb3
+CT = 0a04f793514dd5895d49199b12c8bbbfe8e8d7ac01035ef4733ad369e4a067b7976c9d6d0456
+
+Count = 59
+Adata = 84fd27557aeb283282366083e3586f3a59691ccd0d43ec81c4e5f4e85715eba8
+Payload = 1286506be19fb865a288b09dda8af4323567cd9a66e08643
+CT = 81b91450efb59b2d57c8710f86aa41a704398e305d11250439860d66891f32ce0a09788f5899
+
+[Tlen = 16]
+
+Key = 4189351b5caea375a0299e81c621bf43
+Nonce = 48c0906930561e0ab0ef4cd972
+
+Count = 60
+Adata = 40a27c1d1e23ea3dbe8056b2774861a4a201cce49f19997d19206d8c8a343951
+Payload = 4535d12b4377928a7c0a61c9f825a48671ea05910748c8ef
+CT = 26c56961c035a7e452cce61bc6ee220d77b3f94d18fd10b6d80e8bf80f4a46cab06d4313f0db9be9
+
+Count = 61
+Adata = ac8dde7ba60e4ba226eecb0a789b1c4673ddffe8f371464389f52f767004f0a6
+Payload = 7c0889854658d3408c5d8043aad2f4ae4a89449a36f8a3b8
+CT = 1ff831cfc51ae62ea29b0791941972254cd0b846294d7be196363d27b9e11fee55111b273399f5ff
+
+Count = 62
+Adata = 8f2777ec4930f7e349c3bd4830120cebdd896db9d8a33d34f101672024bd737f
+Payload = c641cf589020b94026ae5ac0bfdc29822cc13862a54614c7
+CT = a5b1771213628c2e0868dd128117af092a98c4bebaf3cc9ef741e15ad9b2f5ab864ad94d3f9de562
+
+Count = 63
+Adata = a87426f83bf91bd3c3556bf859cd97f51c92609879f02dbca9c7ae637a3fbf05
+Payload = d204994c128d6204ef2939c22572daa56c12df2e4d3e33e9
+CT = b1f4210691cf576ac1efbe101bb95c2e6a4b23f2528bebb0652a083ea1b43b7da026692c7aa796d7
+
+Count = 64
+Adata = 7ff9ca86f820e4d57995d450611009ffaa726e6fbe4ce1558ca1e775daed9ec2
+Payload = aff9bb0238689255f54cd5fdebe6d3dff5f5604ab8d77038
+CT = cc090348bb2aa73bdb8a522fd52d5554f3ac9c96a762a861057e0faa2711cfa1e3da5499f9a1ee0b
+
+Count = 65
+Adata = faa6b7f8c6e076b5e5b981119b7ec2e0b9c73da4064f9704e303d5792f59674b
+Payload = 95d2cf30b6174b17278ad9f44079a2199082dab917f89763
+CT = f622777a35557e79094c5e267eb2249296db2665084d4f3a90b39704d8913391ebd3424117b93b68
+
+Count = 66
+Adata = b553e65640c1ad0d2ff748c5b2af9d970c74131cff4fa73384a33dfec056332e
+Payload = aaa53244520e157c4890a0e62100a12daa84f9be710242d7
+CT = c9558a0ed14c2012665627341fcb27a6acdd05626eb79a8ed0a6cb58733be0a3b608afdf78eaa70c
+
+Count = 67
+Adata = a9be73668b94bc6a212744522a0adff03d49fd495daadaf6cd32f4ca25ebc2b5
+Payload = 1066b96c3c44301073717520ea5c07adbac7759b88d52154
+CT = 73960126bf06057e5db7f2f2d4978126bc9e89479760f90daf20ce64e6a821e39ca96aded43f0875
+
+Count = 68
+Adata = 8b516c47e6630b2c31d8eefd8ba152d7315582a3f4d3f0e0eb2984a365b434db
+Payload = b5969813d0f892febe64ed52d429cc737b5df8d5e0c63207
+CT = d666205953baa79090a26a80eae24af87d040409ff73ea5ecf4699d23f5fc6742bffebbd16858f6e
+
+Count = 69
+Adata = 8ad3e84edbe7d9305848746cbd0f769bce47d5ae4609513210e54cd3b984db1f
+Payload = daa90a2de3937e7942e6711f165a89b9e077fe322cab597d
+CT = b959b26760d14b176c20f6cd28910f32e62e02ee331e81243713601bb16dc91af84ac19ebd43a1ec
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VTT192.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VTT192.rsp
new file mode 100644
index 0000000000..75b0c429f6
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VTT192.rsp
@@ -0,0 +1,393 @@
+# CAVS 11.0
+# "CCM-VTT" information
+# AES Keylen: 192
+# Generated on Tue Mar 15 08:09:25 2011
+
+Alen = 32
+Plen = 24
+Nlen = 13
+
+[Tlen = 4]
+
+Key = 11fd45743d946e6d37341fec49947e8c70482494a8f07fcc
+Nonce = c6aeebcb146cfafaae66f78aab
+
+Count = 0
+Adata = 7dc8c52144a7cb65b3e5a846e8fd7eae37bf6996c299b56e49144ebf43a1770f
+Payload = ee7e6075ba52846de5d6254959a18affc4faf59c8ef63489
+CT = 137d9da59baf5cbfd46620c5f298fc766de10ac68e774edf1f2c5bad
+
+Count = 1
+Adata = edb8834974b02fc9ab29b4b3c49683426124e729b44e43cde4ab9bb1b30b5531
+Payload = d05410f42d4759f8cab3884785cf8f60ecbf902e525b92e8
+CT = 2d57ed240cba812afb038dcb2ef6f9e945a46f7452dae8be24285996
+
+Count = 2
+Adata = 8baf194e81e47a6ca82ca51b488339d014a0a494007793aa5201ac72fc3f808d
+Payload = db3022ef4cd68ae22b501599448ffe2dda15cfd2e259315c
+CT = 2633df3f6d2b52301ae01015efb688a4730e3088e2d84b0a6c510570
+
+Count = 3
+Adata = c0b55acc7fbfa9d9af6e1f32b6626a1cd89b1c32513b5b50a18ddab028470953
+Payload = 7f0745bea62479c0080ecec52e37c1e32d72a6b3864da44a
+CT = 8204b86e87d9a11239becb49850eb76a846959e986ccde1cb418cfd2
+
+Count = 4
+Adata = 9dc672e64c468242ddeec318c71f9b8cbaa14639eba3c861acfc26463fb7d5d7
+Payload = 263dbe1bd5e9d9b29b316fe36ec8bb10f64543b4921c01f6
+CT = db3e43cbf4140160aa816a6fc5f1cd995f5ebcee929d7ba03e5b5794
+
+Count = 5
+Adata = 1798286c37c1504fc0d7402681f6f70711ef506dcc3e29d0183dc578ed976f92
+Payload = 22dbba2b1a39074ddac736767ebdedc37e4208b233e03b34
+CT = dfd847fb3bc4df9feb7733fad5849b4ad759f7e833614162f63b4847
+
+Count = 6
+Adata = ed2898d0bcb34eebf98b5279bc3e8a20214321a7e23bc55b2b7613b1a9b94f2c
+Payload = f0f1235ee88d04de3f3d1489ec6b28b285a6a4fbb344911a
+CT = 0df2de8ec970dc0c0e8d110547525e3b2cbd5ba1b3c5eb4c7ab29a40
+
+Count = 7
+Adata = 50c4a285d6a4e64efceb288b82e7c8277307cf1eaa4b8b9294f97a1c38926a60
+Payload = 0e50aa6a3079c0b8d61e51c3bd93b592a03719acb9f0252e
+CT = f35357ba1184186ae7ae544f16aac31b092ce6f6b9715f7868f40ff6
+
+Count = 8
+Adata = b48a16fb9a065d3aeb2bdf1860e4b0f1348c8f13cd00b1729ff8c19e4e9724f3
+Payload = 82f39f5207afcfd677a7544579f2b888a1eabdee4e835924
+CT = 7ff0628226521704461751c9d2cbce0108f142b44e022372ceeff92c
+
+Count = 9
+Adata = d92b80544f29aba52496e2c9a0aa4adeb89820be321cfd2f0a53585a15d04c7f
+Payload = bc3b08eec6506d1497572f901f0e5f3e9854b40b0f992d08
+CT = 4138f53ee7adb5c6a6e72a1cb43729b7314f4b510f18575e619c1124
+
+[Tlen = 6]
+
+Key = 146a163bbf10746e7c1201546ba46de769be23f9d7cc2c80
+Nonce = f5827e51707d8d64bb522985bb
+
+Count = 10
+Adata = 599b12ebd3347a5ad098772c44c49eed954ec27c3ba6206d899ddaabca23a762
+Payload = 473b6600559aefb67f7976f0a5cc744fb456efd86f615648
+CT = 26d2be30e171439d54a0fec291c6024d1de09d61b44f53258ba1360406f9
+
+Count = 11
+Adata = 3a8423feb661db30542dc3cfb596280429397f80755a4bc8d4d941d03b61aacc
+Payload = 7edfce3dedd65a8592aec2bfc7a751e2360f3137941fc960
+CT = 1f36160d593df6aeb9774a8df3ad27e09fb9438e4f31cc0db5e5938e8c75
+
+Count = 12
+Adata = 0dc79993047fd6e7260aac4d847fdb4d16483f28b13b5f17330744d401d2875b
+Payload = a9fb3ebba43c273cacbf0f7187030c69172f31382e9e059b
+CT = c812e68b10d78b1787668743b3097a6bbe994381f5b000f694f534b76f0b
+
+Count = 13
+Adata = 6546d9a90e0e763679d5469a1bcffcc4f18f35f50c7714d14c7329b76ce7984e
+Payload = a7573e5b7dd7f4ce9e4480f603c14145a27f7c7a9246a3cf
+CT = c6bee66bc93c58e5b59d08c437cb37470bc90ec34968a6a23c6c025faa1b
+
+Count = 14
+Adata = 7f398ff0d47e2c0fccd8a16cc9e79b4813abac42e346fa33ba033956f798d6ac
+Payload = 84370557e0bbf74fd0a4533185adfe202d9fa9d622bba72f
+CT = e5dedd6754505b64fb7ddb03b1a788228429db6ff995a242ae0f88d836be
+
+Count = 15
+Adata = d0f46fb37d516cc957aaefd3be2a8bede885330a8edb96f3e5e0ab8cd03a8c59
+Payload = 029575400bd3f2621c7d9ca9b6a09ea6f776968b19dc3f3e
+CT = 637cad70bf385e4937a4149b82aae8a45ec0e432c2f23a5366d09f64b4c2
+
+Count = 16
+Adata = 4abaa4260c864572e12553c5aabfe62e4e7038490d4ba160119fc5d646780cc6
+Payload = 448be3821d94452425fae41a06457260a2666e890fa94954
+CT = 25623bb2a97fe90f0e236c28324f04620bd01c30d4874c39677fd479c852
+
+Count = 17
+Adata = 686e0578eadd19583291a01e11a29fc95a2c156da100dd85429ad58ba65440c6
+Payload = aebfe3e15a876412ec9df714f1afa898e69004c1ef25732b
+CT = cf563bd1ee6cc839c7447f26c5a5de9a4f267678340b7646bbc332573774
+
+Count = 18
+Adata = e3d29f970667286a81586aa02bb490c72d8bb3a308eafec5da0d105fddd1a157
+Payload = 08b2ce5f7296016e86d02f8c7952d746703ee4f0429b8df3
+CT = 695b166fc67dad45ad09a7be4d58a144d988964999b5889e33171a8ccec1
+
+Count = 19
+Adata = 9e2ea8eb7f56087ee506925648661eeefffd643a056cd4f4fc5cc23172b5c637
+Payload = e73d7d23736db17cca816ab2440062a8051177d47feb514e
+CT = 86d4a513c7861d57e158e280700a14aaaca7056da4c55423bc8299cc9f95
+
+[Tlen = 8]
+
+Key = bdf277af2226f03ec1a0ba7a8532ade6aea9b3d519fe2d38
+Nonce = cc3c596be884e7caed503315c0
+
+Count = 20
+Adata = 4d6546167b3ed55f01c62bd384e02e1039c0d67ef7abe33291fecb136272f73b
+Payload = 0ff89eff92a530b66684cd75a39481e7e069a7d05e89b692
+CT = 6ef66a52c866bd5df20ec5096de92167ad83cab0e095ad0c778a299f1224f10c
+
+Count = 21
+Adata = 95722ef5e0cf9f482e4c359f1fd6b9efe2b6e0630413c40285b8958c31188ca4
+Payload = b1ea02e3721e44c327443fcf4b424cce19afbb9e8cf06b76
+CT = d0e4f64e28ddc928b3ce37b3853fec4e5445d6fe32ec70e8a5c2c6b097a04d50
+
+Count = 22
+Adata = f7b76a2a4fe0a1b07a6b193b4600aec02360eb35853d88fe8a4f31a8dda48ad9
+Payload = c1f9c7b2e0ba712b4d2b32e4693b145228213999703767fc
+CT = a0f7331fba79fcc0d9a13a98a746b4d265cb54f9ce2b7c62f62e74c2312f9243
+
+Count = 23
+Adata = 406f39cb77b8d8c63f7797d184b6ebde819af7d48de5003538c022fe96b841ce
+Payload = ebf3a717546199c6f6b14efe8888613ca7e075e8290b277c
+CT = 8afd53ba0ea2142d623b468246f5c1bcea0a188897173ce2f1cb228ffd2ff8e6
+
+Count = 24
+Adata = 3dd3110703a95b05b9b9cff92ab7244e6c6dcb4509522c305d5d33e03f1b0b60
+Payload = a0e317b790870e6703e6077dfb8ea327c12e29a17107284c
+CT = c1ede31aca44838c976c0f0135f303a78cc444c1cf1b33d21f38e2d280a8f3ff
+
+Count = 25
+Adata = 044ae4064156b6ebc0921cb2c3c607976339f824d4dc6902eac66910dce086b2
+Payload = 8a16990690717dc16eea24da39878a2ee7c1579976e5b173
+CT = eb186dabcab2f02afa602ca6f7fa2aaeaa2b3af9c8f9aaedafbcf46b4e75bb11
+
+Count = 26
+Adata = 5479cc7f92460ff7a3e500f76d70e3036c44300005058b5517e3f64ad41b46b3
+Payload = 1e7e51f0fa9a33ed618c26f5e37754df0f7de7778882c26c
+CT = 7f70a55da059be06f5062e892d0af45f42978a17369ed9f2fac11c84d08e918e
+
+Count = 27
+Adata = f950e96d65a55efb3be3a55daffb421afad1d5625e3440a16414085469effe1c
+Payload = 3ef1f4c438dce131990ba536d7a6166022ae7de4a436f87c
+CT = 5fff0069621f6cda0d81ad4a19dbb6e06f4410841a2ae3e2b50cb871173d9bb8
+
+Count = 28
+Adata = 52742be3969830ba9c2bce26c98c2fb44ac881ec55c85627b2c94ba17b0de8cf
+Payload = 3c7b4a68dfb766e24739f14932563fb81f24591f0e31e895
+CT = 5d75bec58574eb09d3b3f935fc2b9f3852ce347fb02df30b4ce29627efbc3523
+
+Count = 29
+Adata = e16e5dc034719e5d815f937b672cf34d5d420a3945c8f73645241779d2bec150
+Payload = 03038acd2d8351e4e5aa308e554abfcd0d0334d8f864ec60
+CT = 620d7e607740dc0f712038f29b371f4d40e959b84678f7fe095168ed90827db2
+
+[Tlen = 10]
+
+Key = 62f8eba1c2c5f66215493a6fa6ae007aae5be92f7880336a
+Nonce = 15769753f503aa324f4b0e8ee0
+
+Count = 30
+Adata = 1bc05440ee3e34d0f25e90ca1ecbb555d0fb92b311621d171be6f2b719923d23
+Payload = f5522e3405d9b77cbf3257db2b9675e618e8744a0ee03f0f
+CT = b9103942dbbb93e15086751c9bb0a3d33112b55f95b7d4f32ff0bb90a8879812683f
+
+Count = 31
+Adata = 25c32770a299020d8500d8a4b5d7621e4379dbd6ef34a9aceefd4055ea6144f5
+Payload = c8bf145fcffbafd6cd1a4c5b6cedfe008aacb2528ef51c80
+CT = 84fd032911998b4b22ae6e9cdccb2835a356734715a2f77c6982d0796e1bd1cc9879
+
+Count = 32
+Adata = cba0e0140f094e17652ea6f64c26f69dd9429bfefb41aaf104c38f3f6501f4f9
+Payload = f8813985f59bf284bd3882e899ca9b67fb496f3eb78d7ebe
+CT = b4c32ef32bf9d619528ca02f29ec4d52d2b3ae2b2cda9542fe08edf50e05d4d85faf
+
+Count = 33
+Adata = a846d0f56eb963b308ab8f697adca378ab6ccf9f739edcd7f5db197b2ffa99ac
+Payload = 72862d82d940748d54369e3143192453069b80d10f32e569
+CT = 3ec43af407225010bb82bcf6f33ff2662f6141c494650e95800ae2523c5f161ed96f
+
+Count = 34
+Adata = 1dc5f6d6103ed2ae7f4ecd7b1bae4d5b9c0adef9100527b1737e1cf57f1175ef
+Payload = 46f2199305ff4e1f21a89d96d3902c54939f52278ba7aa0e
+CT = 0ab00ee5db9d6a82ce1cbf5163b6fa61ba65933210f041f234a29547607846bc9834
+
+Count = 35
+Adata = 8c28bcb9c31191c347dd64e552af5aff500e6e6f39e866351dd7065501a2837d
+Payload = 18c38c41a4e70c3f7362249ea329059b0e026bce7ae976b0
+CT = 54819b377a8528a29cd60659130fd3ae27f8aadbe1be9d4c95f73957e86152df56bd
+
+Count = 36
+Adata = 1081afd5bf9f1a87169973ebdca85c2b69598154673d7ca9d6e2f63d52030fc1
+Payload = c89e388dd6124c41251e7422b420a71e4618f5cf9f0a63fc
+CT = 84dc2ffb087068dccaaa56e50406712b6fe234da045d8800b2b028cd785f4f964069
+
+Count = 37
+Adata = 079bc543c966734fa70814139ba8051271ee1c4f701579013c427f8efb141db7
+Payload = 68449bc3f6c8bd8f3a46a8e147522d979948c88ca791d204
+CT = 24068cb528aa9912d5f28a26f774fba2b0b209993cc639f8fd3ef357e5e69f504c95
+
+Count = 38
+Adata = e7094697b78d20174ec3c97a48abcf67c2ba6790b4db5fda82b454becd2a25ef
+Payload = 330088153204c3d5de7744047b60887c8c044e4eeaae4bab
+CT = 7f429f63ec66e74831c366c3cb465e49a5fe8f5b71f9a057e092ed15d1a074306a9e
+
+Count = 39
+Adata = f8d64ce2aa66e67de0f2fa584dec858983333b0570882ab628419bcee541395a
+Payload = 893c5c45db989bd39485caa05ed700bb17c526b426edf4ba
+CT = c57e4b3305fabf4e7b31e867eef1d68e3e3fe7a1bdba1f46afaad39e9183b2970027
+
+[Tlen = 12]
+
+Key = 5a5667197f46b8027980d0a3166c0a419713d4df0629a860
+Nonce = 6236b01079d180fce156fbaab4
+
+Count = 40
+Adata = 29bdf65b29394d363d5243d4249bad087520f8d733a763daa1356be458d487e5
+Payload = d0e4024d6e33daafc011fe463545ed20f172872f6f33cefa
+CT = 479f3d408bfa00d1cd1c8bf11a167ce7ae4bcdb011f04e38733013b8ebe5e92b1917640c
+
+Count = 41
+Adata = 314f069dd4ac5aa3fdc2a74e83daa1d5d18330cd3b90684a9260bb48f5626d49
+Payload = 9ebd994a9af0cb94552ffd749fdd97f75a1ebd0ad3de3a9a
+CT = 09c6a6477f3911ea582288c3b08e06300527f795ad1dba58425a1bad4381dc84fee903e3
+
+Count = 42
+Adata = 3aa7f30ac5bfbcb3f8de7c5e76269c608fbc76361d215e78abc0e308ddc3528f
+Payload = 590a27721a36987d1ffa15f23c6ca5cc556dfcfa6993a2fb
+CT = ce71187fffff420312f76045133f340b0a54b66517502239efcb43c6aaec88b51d0a378b
+
+Count = 43
+Adata = 5630345f662df248886f771b2b77cc0cbdc8fe4cc4a6cde52b1ea4e5d946cebe
+Payload = 65f4b3a00c1c1ef39445a69b2150b034705410140ff9dad0
+CT = f28f8cade9d5c48d9948d32c0e0321f32f6d5a8b713a5a12b9a60374d9304316e2fc50d9
+
+Count = 44
+Adata = 38ee97f0dc635c7416a024e3af5c95dd1d496db8a5a5c3bcc20b9093ca906dfb
+Payload = 0edea2afaeaf650704d2c6c6622aad82169807c983c17309
+CT = 99a59da24b66bf7909dfb3714d793c4549a14d56fd02f3cb07611163d6b0f1734292ed8c
+
+Count = 45
+Adata = ea3b3f3c5b28f7d48af2ccf97083937baccb0a6b1a041080a73b15b9640ccf44
+Payload = b80175a03dff1b10078ded64ed759e5453e3bc0657c68590
+CT = 2f7a4aadd836c16e0a8098d3c2260f930cdaf69929050552edefbcbb51d9d607b7b2e8f8
+
+Count = 46
+Adata = 287f31e69880823df7798c7970c0e42e600bf567ad78f5d559d0182d570c03cb
+Payload = 531c1e721e185f58b2c654b9098ce0c1338bab4149c7bef7
+CT = c467217ffbd18526bfcb210e26df71066cb2e1de37043e35f2b6d4dc8afae25ff400d73d
+
+Count = 47
+Adata = 1d4579c9410cc34ade1352ed433e0d4faaaa28200e359bcb4140d35939b3a792
+Payload = cead1c5af16ca89bc0821775f8cba8c25620a03dfd27d6f1
+CT = 59d6235714a572e5cd8f62c2d79839050919eaa283e4563319cd80c1ce0f9ed40f1e9dec
+
+Count = 48
+Adata = 3fec0e5cc24d67139437cbc8112414fc8daccd1a94b49a4c76e2d39303547317
+Payload = be322f58efa7f8c68a635e0b9cce77f28e3f8faaa76fcad4
+CT = 294910550a6e22b8876e2bbcb39de635d106c535d9ac4a16e53d5aeccfb4a6837b79a625
+
+Count = 49
+Adata = ec6857533675b5ed8d4315b0d5f59c826f3ccb2d0bd6f604bd54f7c9542123ce
+Payload = c222374d366baf2d0301340582aa056c04441ac766065ab1
+CT = 55590840d3a275530e0c41b2adf994ab5b7d505818c5da73385e080bf29ae097c328789a
+
+[Tlen = 14]
+
+Key = d2d4482ea8e98c1cf309671895a16610152ce283434bca38
+Nonce = 6ee177d48f59bd37045ec03731
+
+Count = 50
+Adata = 9ef2d0d556d05cf9d1ee9dab9b322a389c75cd4e9dee2c0d08eea961efce8690
+Payload = 78168e5cc3cddf4b90d5bc11613465030903e0196f1fe443
+CT = e2324a6d5643dfc8aea8c08cbbc245494a3dcbcb800c797c3abcdb0563978785bf7fd71c6c1f
+
+Count = 51
+Adata = 6f99d9ce00a4be502a5d2c76a07b914d56f49a1592c1ee2e46e11b3c9da0d083
+Payload = 3c3992cac792e019720d38f768beac3deb6a43e7e1f59f20
+CT = a61d56fb521ce09a4c70446ab2488c77a85468350ee6021fcb0e8ec0879db8ffa59125eac239
+
+Count = 52
+Adata = deae66f68bb18178d1bc0734f19fd3ab390049c2ca083a159f5c078fcb4f0a38
+Payload = 8eaae72e532943d66ce8250c6b434d299b6afbf8e2b4f8b1
+CT = 148e231fc6a7435552955991b1b56d63d854d02a0da7658e664a2d992f7cf821e19bb7d4dff8
+
+Count = 53
+Adata = e2d592cb412e65f9044257d78e7491f9f80c8b08102c2d5da20535cef74ad8c8
+Payload = 1b8096b79ace8c6ee5dbd8735f1287aa2c94865f382dc2da
+CT = 81a452860f408ceddba6a4ee85e4a7e06faaad8dd73e5fe546a4a816b709a55db450ac249c5c
+
+Count = 54
+Adata = 78a292662b8e05abc2d44fbefd0840795e7493028015d9f2aae7b3b7a4634437
+Payload = 014f15219463ac22820ba6a1fa04d7f686003ef24004da67
+CT = 9b6bd11001edaca1bc76da3c20f2f7bcc53e1520af174758fbebbdb2e35ebf682f7fe30996bc
+
+Count = 55
+Adata = de6ea86d3641d916c4394fdd31e6a50194993d6ef1d3dfd9fffca20b2f58107d
+Payload = cc8c855a4c122046916bdcf8089eba3ddb80483e201c7102
+CT = 56a8416bd99c20c5af16a065d2689a7798be63eccf0fec3deee137bb5b1e7385aa1bd5d69831
+
+Count = 56
+Adata = 87b937b1d36e8a9ab33a1d3eed617030923acaabc7e620dfcb3c388936030fc6
+Payload = 3fb7d1f17e7e36d5d4b816cc6db11d1d85848c577fdfe938
+CT = a59315c0ebf03656eac56a51b7473d57c6baa78590cc74079b13b729c70e1fa89c43a05a544b
+
+Count = 57
+Adata = 116f4855121d6aa53e8b8b43a2e23d468c8568c744f49de5f7f1a60cf4e16278
+Payload = 268fe424d6db30f680c10fe2684707a0778069958e9a3bf7
+CT = bcab201543553075bebc737fb2b127ea34be42476189a6c82d900340d90dc4f09a7171d331d6
+
+Count = 58
+Adata = e13e0c9cef1f86160a75ccb131586370b0edabbf8b3b63f21f3a6fee072dd926
+Payload = 9d64de7161895884e7fa3d6e9eb996e7ebe511b01fe19cd4
+CT = 07401a40f4075807d98741f3444fb6ada8db3a62f0f201ebe4ad0d90322ed2813a3343029e93
+
+Count = 59
+Adata = d4cd69b26ea43596278b8caec441fedcf0d729d4e0c27ed1332f48871c96e958
+Payload = e4abe343f98a2df09413c3defb85b56a6d34dba305dcce46
+CT = 7e8f27726c042d73aa6ebf43217395202e0af071eacf53790065601bb59972c35b580852e684
+
+[Tlen = 16]
+
+Key = a7177fd129674c6c91c1c89f4408139afe187026b8114893
+Nonce = 31bb28f0e1e63c36ca3959dd18
+
+Count = 60
+Adata = 2529a834668187213f5342a1f3deea0dc2765478c7d71c9c21b9eb1351a5f6cb
+Payload = 2cea0f7304860a4f40a28c8b890db60f3891b9982478495e
+CT = 5bb7aa6ab9c02a5712d62343fbe61f774e598d6b87545612380ea23dcffc9574f672bca92e306411
+
+Count = 61
+Adata = a4dbf26802b2dba1bf828f57618fd197d3e60b6efc9d884f965ce3b43e1dc008
+Payload = 2baf3d378942bd44f67fb787def50aaf446bf15c56243484
+CT = 5cf2982e34049d5ca40b184fac1ea3d732a3c5aff5082bc8b93605b46a8a6a9c7e02cb8feac67af4
+
+Count = 62
+Adata = cbd1302c9fffe29fe882838236f64fe9d9ba35db5499e90f0faa35f34c7490f2
+Payload = a0639aa4e7a8bda4e9e096d17c1c47d3786010fabe9c72d2
+CT = d73e3fbd5aee9dbcbb9439190ef7eeab0ea824091db06d9e82e411c052c0a025ab15767b0242ebf7
+
+Count = 63
+Adata = b6112eb8299b28445aca8f72e7170a1cd8bbfee4d2145fbe8d49c6af8831c4d4
+Payload = e2d78ce5df9284c045b84df33f551211ddccf7bb14cd4529
+CT = 958a29fc62d4a4d817cce23b4dbebb69ab04c348b7e15a65ab58a892f7142414d3f7cf10925a403a
+
+Count = 64
+Adata = c70a9fb811894b73e445b78db7a931705a181f3a8730341cbb50eaff43572c6e
+Payload = c3f1e735a6741aa481ad577a98dbac1f03cc80ea0dae1b94
+CT = b4ac422c1b323abcd3d9f8b2ea3005677504b419ae8204d8b5b3ce6bae6ecb060289508d6e9212fe
+
+Count = 65
+Adata = c7cbda495a7dc1d91837f652a9d084df9b717e99b29bf1ab7f6c17b3341ecd6c
+Payload = db8cd5d76e459afce765e07da98f4ac58231224238c293c7
+CT = acd170ced303bae4b5114fb5db64e3bdf4f916b19bee8c8ba16229a91a2298ffe104f9c032720abb
+
+Count = 66
+Adata = 4bd3a656796cb1fa87976f3a93471e33dd1209ce33d7a28aaca4d17c99d78c94
+Payload = fd66aebc94f2513b1b9218396b08c63a869b9c4dd0752a91
+CT = 8a3b0ba529b4712349e6b7f119e36f42f053a8be735935ddb9cacc4fdb44402971a0eee7f1ad90d7
+
+Count = 67
+Adata = 448cdd9cbbf863eb666fda36b825f3798827da3c1349611f45605ab734b24498
+Payload = 5831e9a6af0234d051ffd17a14b8e3c8da95067ab767901b
+CT = 2f6c4cbf124414c8038b7eb266534ab0ac5d3289144b8f5713306e7f0a61d4b3da372db669321143
+
+Count = 68
+Adata = f8f04f12174b5205866515ce3775bd8e11d50d8b96142be0c347a773379fb928
+Payload = 248a4969621cf291bec7f0d76d80b7f019d4eb002a22c46a
+CT = 53d7ec70df5ad289ecb35f1f1f6b1e886f1cdff3890edb2609726d3a3d04005dc13629658624d05b
+
+Count = 69
+Adata = 4ecd7c2188fb9cfc84a9ee2fab29ccbbd48a574ec20f1959eedfe96887fe0eb3
+Payload = 68f36fd96de8c57210f6f41da5b67d68533d722c604dda62
+CT = 1faecac0d0aee56a42825bd5d75dd41025f546dfc361c52e8631fb934e918210097f3cefc7f3b0ee
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VTT256.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VTT256.rsp
new file mode 100644
index 0000000000..dbe86fbb71
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VTT256.rsp
@@ -0,0 +1,393 @@
+# CAVS 11.0
+# "CCM-VTT" information
+# AES Keylen: 256
+# Generated on Tue Mar 15 08:09:25 2011
+
+Alen = 32
+Plen = 24
+Nlen = 13
+
+[Tlen = 4]
+
+Key = 9074b1ae4ca3342fe5bf6f14bcf2f27904f0b15179d95a654f61e699692e6f71
+Nonce = 2e1e0132468500d4bd47862563
+
+Count = 0
+Adata = 3c5f5404370abdcb1edde99de60d0682c600b034e063b7d3237723da70ab7552
+Payload = 239029f150bccbd67edbb67f8ae456b4ea066a4beee065f9
+CT = 9c8d5dd227fd9f81237601830afee4f0115636c8e5d5fd743cb9afed
+
+Count = 1
+Adata = ab91d1aa072947d22f0dc322355a022fe7f0747f4a184b48446bd27999ef01fe
+Payload = 25a43fd8bf241d67dab9e3c106cd27b71fd45a87b9254a53
+CT = 9ab94bfbc86549308714543d86d795f3e4840604b210d2de169d7775
+
+Count = 2
+Adata = 4c3bdc6186297896097b3297ba90bcde78dc8a9efe3bd8b10a85eed1bf63a30c
+Payload = e63d8303fa5c51550e417e77ec1ec647c9e2a853cab00fee
+CT = 5920f7208d1d050253ecc98b6c04740332b2f4d0c1859763b9c2e299
+
+Count = 3
+Adata = 8587324c1ff6712aed8af134744de5df1f88c5d2cb33f4f888af9fd39eb8e813
+Payload = f27548ec1608d3b8a5bdcbccb7e09cf4b5c29d3661b13a61
+CT = 4d683ccf614987eff8107c3037fa2eb04e92c1b56a84a2ec02f73205
+
+Count = 4
+Adata = 58820fb68ba1cd73b05a6698b4394ba1b13e8e296480f5afe1154d9b8536007c
+Payload = ecbd7091732e49c0f4bda2e63235ea43bbf8c8730f955f9c
+CT = 53a004b2046f1d97a910151ab22f580740a894f004a0c7114e1dd81b
+
+Count = 5
+Adata = f3034031933e7807d47140cf5c7794e42a228a522a83883b0765b57a411bad85
+Payload = 3002c6fb49497c7d1d06e1bd4edd57a9e54bbbb74e948c79
+CT = 8f1fb2d83e08282a40ab5641cec7e5ed1e1be73445a114f446525bc4
+
+Count = 6
+Adata = 05981dc26a1db2d8e2c3d85ea9a4d1dc3432d9edc4795ca03ca4661d2fc35b8c
+Payload = 214acfb2613b266f2929d43c7666f3a23e61423061cdbec3
+CT = 9e57bb91167a7238748463c0f67c41e6c5311eb36af8264e651844a3
+
+Count = 7
+Adata = 968a302a27624c304e894633af600c3cc7c614b7da3af0bf2d3f239c7605338a
+Payload = 9c575d592a9622c014c1303329757a65a414a9ed0c1b1b3f
+CT = 234a297a5dd77697496c87cfa96fc8215f44f56e072e83b249fd550d
+
+Count = 8
+Adata = 9011231ec382ecaaae57f34de1ac6bbb50741014a978160ce59c60491e64f30d
+Payload = 426a4c83793abdcff5e2a99e161785dc27c6168a329ee465
+CT = fd7738a00e7be998a84f1e62960d3798dc964a0939ab7ce84137defa
+
+Count = 9
+Adata = 96f0b1edec4ad14407dcaf30ed68942b46c48d58b2dd63af60fccd5bdd48e560
+Payload = e04006b68c83a5dd4ceac3cde238e48895ae17728fdc7bbe
+CT = 5f5d7295fbc2f18a11477431622256cc6efe4bf184e9e33356a4953f
+
+[Tlen = 6]
+
+Key = 8596a69890b0e47d43aeeca54b52029331da06fae63aa3249faaca94e2605feb
+Nonce = 20442e1c3f3c88919c39978b78
+
+Count = 10
+Adata = 4e0d3aa502bd03fe1761b167c4e0df1d228301d3ebaa4a0281becd813266e255
+Payload = f0b065da6ecb9ddcab855152d3b4155037adfa758ba96070
+CT = d6a0f377f7c1b14dcdba729cae5271b027e71cc7850173ec265867a29eb3
+
+Count = 11
+Adata = aeef2d1e3d3c9920a4fdb5f9d963b88e78a5d0edae531e3b55e702ed609d9a3c
+Payload = f2a8855e34854656df0776e80255ad1d125841c727201509
+CT = d4b813f3ad8f6ac7b93855267fb3c9fd0212a7752988069566e89a72dc0e
+
+Count = 12
+Adata = 3051ffb19862370bc46ca94a8eb906a660d539b18e965583e95acc149190e3e9
+Payload = 20955a0ca3c9c10d4055406ec12226130ecdaf195b08d65e
+CT = 0685cca13ac3ed9c266a63a0bcc442f31e8749ab55a0c5c2dff4f6257e06
+
+Count = 13
+Adata = aafa45a107d909756b4a1956d5228b50316fc5852afdeecf401fa2a71aabea46
+Payload = 246b60d17ea70deb1380fbf4bd767d88f53069b0f4136511
+CT = 027bf67ce7ad217a75bfd83ac0901968e57a8f02fabb768def0017c9acc1
+
+Count = 14
+Adata = ccdeab6a28b1b9e9f0c67116a91f2215b229d0edcd35d696db2bcf54e77db743
+Payload = 5b735697c5577ee0e352cf6a1495c490d6f7e97c3898f0ee
+CT = 7d63c03a5c5d5271856deca46973a070c6bd0fce3630e372c73969437912
+
+Count = 15
+Adata = 33a1e7d4820ed6a76a6dab90b4ba830888caf12a262e4eb6d75a505b2207de36
+Payload = 1170416faf81896c7f00815f53c2be5f7246d4794895b4b1
+CT = 3760d7c2368ba5fd193fa2912e24dabf620c32cb463da72dd7cb3721fcdd
+
+Count = 16
+Adata = 3df3edd9fc93be9960b5a632e2847b30b10187c8f83de5b45fcb2e3ed475569a
+Payload = 556765ffe5c46015cbd8194e32abc41e8f711773e2bcac90
+CT = 7377f3527cce4c84ade73a804f4da0fe9f3bf1c1ec14bf0c82183448e643
+
+Count = 17
+Adata = 4cb8663a1a934b6b27cbc1ed3040fbb99fbb6812f8ca35ff73cc13feeb483af7
+Payload = 3070e269f3e87cd82af3896895a5dd6fbfa9898279e0f73b
+CT = 166074c46ae250494cccaaa6e843b98fafe36f307748e4a76069901b5e3a
+
+Count = 18
+Adata = 876df130c01d0b9b8ebe43e71046c365e13124169026876d50d7e155f0299676
+Payload = dd18d40728c561e24e6e54834348dde5683f067baf8df469
+CT = fb0842aab1cf4d732851774d3eaeb9057875e0c9a125e7f56d65c2b005d4
+
+Count = 19
+Adata = da08b14e1b770b81faaf1e59851df1cba8838cd63bef141340ee378e65fdcbd4
+Payload = 7064a2491f716f4a2969815e4a281a54690ced9f794b264e
+CT = 567434e4867b43db4f56a29037ce7eb479460b2d77e335d275b37e9fb9e9
+
+[Tlen = 8]
+
+Key = bae73483de27b581a7c13f178a6d7bda168c1b4a1cb9180512a13e3ab914eb61
+Nonce = daf54faef6e4fc7867624b76f2
+
+Count = 20
+Adata = 7022eaa52c9da821da72d2edd98f6b91dfe474999b75b34699aeb38465f70c1c
+Payload = 28ef408d57930086011b167ac04b866e5b58fe6690a0b9c3
+CT = 356367c6cee4453658418d9517f7c6faddcd7c65aef460138cf050f48c505151
+
+Count = 21
+Adata = a61b6c1f0293a7c35520abf158a995e5ae59b43ec5f38ff6fd6529970c9f83ac
+Payload = 1c5ad37d2a55afbc390b27cde0c42d6651fe191239bfaa27
+CT = 01d6f436b322ea0c6051bc2237786df2d76b9b1107eb73f76bca352f92f383e1
+
+Count = 22
+Adata = 0f1c6dffeda98f7a159f9cc61820bfb29910d8eaa41b751a41f9fe5648f02fba
+Payload = 6efe6652d46a84166d30befe2fbee0795e9475b401eedd60
+CT = 737241194d1dc1a6346a2511f802a0edd801f7b73fba04b014fd7c84052208d9
+
+Count = 23
+Adata = 151110a9ce7e44e5d76d9cad53c1819317527fcd169051f01c6a3efcc06ea999
+Payload = 55b791ee495299916ff3c2327b4990952bebd0a2da9acfc5
+CT = 483bb6a5d025dc2136a959ddacf5d001ad7e52a1e4ce1615c3ebc7214b9eef31
+
+Count = 24
+Adata = 0ba1210696d735eebc13b609d0ec33bc740805105dd82f065b82892b931f1e6d
+Payload = 794a86f5b20d344ad86fd5523d08f1864737be57731440c2
+CT = 64c6a1be2b7a71fa81354ebdeab4b112c1a23c544d409912eff08182f8a00f13
+
+Count = 25
+Adata = 5a3b71b0fdecce8bd759d3d72321b5c3e882c82627c14e0b59cc8c6d191f243f
+Payload = efa6ddd6fb8e4480a0f64414694e5f9e7f2e9b97cbe9cd14
+CT = f22afa9d62f90130f9acdffbbef21f0af9bb1994f5bd14c46894be1f8fa14538
+
+Count = 26
+Adata = 5d344c5b94695a66192b6692e420c8eaa3cb482502be837b2a0a91b787fbe48e
+Payload = 561dd3bf419ae33ff521a43898cf12c6a5c6163eec22abc1
+CT = 4b91f4f4d8eda68fac7b3fd74f7352522353943dd2767211f4393bca514c3336
+
+Count = 27
+Adata = 08344486df2b2f9a6880a03503a3986c485f067c480c31a51607553b875f91fa
+Payload = 6d3596f25401f2e3b099613236f1d88a2f3d8edc1f04bc0c
+CT = 70b9b1b9cd76b753e9c3fadde14d981ea9a80cdf215065dcb708ffd04c8c2da0
+
+Count = 28
+Adata = 9d0824a4dc7e67326c5b68a6ea99cb68298a2af2cc1952351454b038f6270603
+Payload = c563a43e4cc0f93d955432f68287e63400a7fdcae738ba84
+CT = d8ef8375d5b7bc8dcc0ea919553ba6a086327fc9d96c63541511d7d684d58762
+
+Count = 29
+Adata = c4384069e09a3d4de2c94e7e6055d8a00394e268398d6ea32914097aec37a1f4
+Payload = 18c5865b414b2a06b4d71ab9550985b4f3c3d7817e8a8d7c
+CT = 0549a110d83c6fb6ed8d815682b5c5207556558240de54acef0919c5f5daf093
+
+[Tlen = 10]
+
+Key = d5b321b0ac2fedce0933d57d12195c7b9941f4caa95529125ed21c41fac43374
+Nonce = b35fb2262edfa14938a0fba03e
+
+Count = 30
+Adata = ba762bbda601d711e2dfc9dbe3003d39df1043ca845612b8e9dc9ff5c5d06ec4
+Payload = 6aa6ea668df60b0db85592d0a819c9df9e1099916272aafb
+CT = 97027de5effd82c58f8dbfb909d7696fbe2d54916262912001a4d765bc1c95c90a95
+
+Count = 31
+Adata = 77a685958ca801dbcbf346d6bac72662d3870899d7bcdef6665d57bacd4e558f
+Payload = c2992096828325820e2d7acaa17ac789b6830ec3128dd7f9
+CT = 3f3db715e088ac4a39f557a300b4673996bec3c3129dec22288aecb4c38c2391c21d
+
+Count = 32
+Adata = 3a54d3e14bbd0549570ef12425c4b36fd25382d56b68e217bc711ab1625fe9bb
+Payload = e5151262cafdd2f4dea187372dacb9e5975065572446f2a5
+CT = 18b185e1a8f65b3ce979aa5e8c621955b76da8572456c97edb4bd2cb1f1222e0d64f
+
+Count = 33
+Adata = 5c7604f9ac8fdf30ee5820e5aeb75b65d7855e5d2ff9ccf021640707bf1f53e8
+Payload = 1fe786f52daab92a6aa5f43263bed74153d90579a34bceff
+CT = e24311764fa130e25d7dd95bc27077f173e4c879a35bf5249283c1a61e9113462325
+
+Count = 34
+Adata = 42b8863ea100babc1713654afcf54f21f8bff754223ad70269ace9d034f26a96
+Payload = 56c3130c5af210b5bcf7c58b968fc75fc92b9c339efb7aee
+CT = ab67848f38f9997d8b2fe8e2374167efe91651339eeb4135bd3ffe1b1051ec3206db
+
+Count = 35
+Adata = c5a369a8291f4278e797ff11ea5e777d69df3b9c0c32d46150ed4b3e2c3defdd
+Payload = daa716f3cd1e008b46318ec90d976c3fbf88c3ff73cf0052
+CT = 27038170af15894371e9a3a0ac59cc8f9fb50eff73df3b8910d5d255f193b29eb961
+
+Count = 36
+Adata = 63bdceb36a032d3e0e81b4e98ad9861e2c708cef4e870c5b88a87ecc24449be3
+Payload = 42477d7d44881dabccfce52efb8a2cc917b182a23b71fb49
+CT = bfe3eafe26839463fb24c8475a448c79378c4fa23b61c0924e524729fb06212508e6
+
+Count = 37
+Adata = b7f8e7b66726e07c3c73d74135f068bb8025c9da9ba70affb9ed9a69675f0eef
+Payload = 07f48cdc12aa27119fbdfda4ec07ce6068c92ba7ba9c9309
+CT = fa501b5f70a1aed9a865d0cd4dc96ed048f4e6a7ba8ca8d2222af86d91fb6a2b09d3
+
+Count = 38
+Adata = 09891ed14f4488069cd6a5744061e06f8ff8d1bc87b10448b3fbfc1a4e327787
+Payload = e2e7002b769fb5b4201053457158147d99b0d5147f3acac2
+CT = 1f4397a814943c7c17c87e2cd096b4cdb98d18147f2af1194cddcb65a76c40698017
+
+Count = 39
+Adata = 8f9786940943752c536548497f9dae2bd8d677b8bbcb0121a9c9f3c399b62e4b
+Payload = 86be1d1949fe03b8b80ef7abb3e27394273d7b76d7697f0e
+CT = 7b1a8a9a2bf58a708fd6dac2122cd3240700b676d77944d5ddb42d504b6fc47d6575
+
+[Tlen = 12]
+
+Key = 7f4af6765cad1d511db07e33aaafd57646ec279db629048aa6770af24849aa0d
+Nonce = dde2a362ce81b2b6913abc3095
+
+Count = 40
+Adata = 404f5df97ece7431987bc098cce994fc3c063b519ffa47b0365226a0015ef695
+Payload = 7ebef26bf4ecf6f0ebb2eb860edbf900f27b75b4a6340fdb
+CT = 353022db9c568bd7183a13c40b1ba30fcc768c54264aa2cd2927a053c9244d3217a7ad05
+
+Count = 41
+Adata = e9ed05813262fbe769c1104d8ba5c836dbd229a22a681de3565d17ac1129f96b
+Payload = fdf5a5fb377bb52ad07a971c6a9da3e1a68d279be9ac4ed7
+CT = b67b754b5fc1c80d23f26f5e6f5df9ee9880de7b69d2e3c11c000c9d88f047ca198c4e65
+
+Count = 42
+Adata = f246f1e948c81c98ea13f03dd8eea878449d0c3d5b5fe87c633bbe0106fcb899
+Payload = e5e6b57e74ce7afbde3697e2a69d61ca615aa3dfd32fe31f
+CT = ae6865ce1c7407dc2dbe6fa0a35d3bc55f575a3f53514e095c09878f1a963b795b29f4dd
+
+Count = 43
+Adata = e4683285695348ff04a61d51d90b868dfe4cf6ea246544727adeaeface571d57
+Payload = ef2c3a6bb8602d290045854a5f223e6f43bfd0bb9278fa88
+CT = a4a2eadbd0da500ef3cd7d085ae264607db2295b1206579e807d196d2628df1c384816f7
+
+Count = 44
+Adata = 42695369dbd69f07b46db282653704c34106aad82efdcc99b452598b5353f904
+Payload = beda29c7fe15c73ee5bef96485eb8c9e3cd3ea7ee633ef45
+CT = f554f97796afba1916360126802bd69102de139e664d4253961c666279394e1e28cf1b02
+
+Count = 45
+Adata = 58c3ce3906633475441229cfcdf05e02ff3738ae8d1b255974f431b3309ed41e
+Payload = 419c96ba8142b27e3377716358c97a8a636d7fe8403165e1
+CT = 0a12460ae9f8cf59c0ff89215d0920855d608608c04fc8f764efe624dd6c6f8b8cdc76e3
+
+Count = 46
+Adata = a9c06d8029f8da31629c3a6ddceb6009220a69fc614af1c231ae8702b3a85d6e
+Payload = 69bb441a7640f77e124d66af45a0e9f646658a838dfcb957
+CT = 223594aa1efa8a59e1c59eed4060b3f9786873630d8214410ef4b71970b9f80087533cf7
+
+Count = 47
+Adata = a92e88edd297da8c7089e21822b3e6cffd6837c78b975c8413fd6cca1b99bcb0
+Payload = a45b755658d38bdea57d1faae21d75428a17f2c74a33d2d5
+CT = efd5a5e63069f6f956f5e7e8e7dd2f4db41a0b27ca4d7fc36e27dfbf1ff7f08d1b213848
+
+Count = 48
+Adata = 421533453c8129fc8e681c68b9d7371adb0a19442ede7accd185129fcb7db648
+Payload = 2c3e28b61cede08121e80ee08c4f1f19dabb19add9d2dc8a
+CT = 67b0f80674579da6d260f6a2898f4516e4b6e04d59ac719ca48d1a0b815139fa28652d94
+
+Count = 49
+Adata = 55351bc7ddbc6b668d435088f1f9cf6f53caae16d4292b14bc0deec20f393ba0
+Payload = 81fa7fd41ba267bcbdf024cef1543b041cadd96b62a7cf1f
+CT = ca74af6473181a9b4e78dc8cf494610b22a0208be2d962091301c87a2a94df147c8cce4c
+
+[Tlen = 14]
+
+Key = 5c8b59d3e7986c277d5ad51e4a2233251076809ebf59463f47cd10b4aa951f8c
+Nonce = 21ff892b743d661189e205c7f3
+
+Count = 50
+Adata = f1e0af185180d2eb63e50e37ba692647cac2c6a149d70c81dbd34685ed78feaa
+Payload = 138ee53b1914d3322c2dd0a4e02faab2236555131d5eea08
+CT = 5b2f3026f30fdd50accc40ddd093b7997f23d7c6d3c8bc425f82c828413643b8794494cb5236
+
+Count = 51
+Adata = 45c5c284836414407268d7c8a89a0146759cfc92242004027d58d0828fad74e7
+Payload = fe3df84ee9b237f9edd77a5b8af96bc3e184579ac9c6e246
+CT = b69c2d5303a9399b6d36ea22ba4576e8bdc2d54f0750b40c6db5c92de5fb3aafba9537795e17
+
+Count = 52
+Adata = a41ea42692eac0914fef35e58409007342cef027de141223ffb46da7f58df034
+Payload = e0f5c02f9f84e57fada3f3575f1b1a748f360e0ea781b7b8
+CT = a8541532759feb1d2d42632e6fa7075fd3708cdb6917e1f21af6cf931ac943fd3affa6ad6fd1
+
+Count = 53
+Adata = 17dae00f2a9417780ecfef98f290a5ca9b17c873a9149cd81c18bd33164a0405
+Payload = 3a77a2ec5a1be6cbfbbfaab3e65427cb38d6798b132ff5c7
+CT = 72d677f1b000e8a97b5e3acad6e83ae06490fb5eddb9a38d38a3f09c56ae653be49b355fb938
+
+Count = 54
+Adata = 33b44873a7a1e5b0fdbb7e7347623e4fa1ccd937feb26fda2749b42f00744e50
+Payload = d0628b26019dad84de628d9dabf42cfb195165a369c22b49
+CT = 98c35e3beb86a3e65e831de49b4831d04517e776a7547d03974deec7ce2e1f296890bee795cb
+
+Count = 55
+Adata = f4fc5acff75d404849675b813cf7adcaeb8f3d56cb9a54a083f8ec07feb666bb
+Payload = 10b5ec41036e4bc5d61728e8811b520b7080c2177c122cbd
+CT = 5814395ce97545a756f6b891b1a74f202cc640c2b2847af798a3bc56f900bee7e8271c6dab22
+
+Count = 56
+Adata = ba051d1bc19b9a27520834fa3977b6413a319c9a52c8785e3e9594bd4265d911
+Payload = 648a84813ca97aef4ab7e143ee29acb946388660f18eb671
+CT = 2c2b519cd6b2748dca56713ade95b1921a7e04b53f18e03be6623d80c677633a9e4f999bb885
+
+Count = 57
+Adata = f5c629299d18901c8c34c42e8fc29a70c377c160fdea4a6068a36867707575f7
+Payload = 3ead49ed0b41de79c829098d034b666bce052d79bf1f56db
+CT = 760c9cf0e15ad01b48c899f433f77b409243afac71890091c65b88ff4fdd9b8187f7d71ba04b
+
+Count = 58
+Adata = da486fd2953a72838e67e1909ed4042df67c355b648a45bcd2cc1ba610659e76
+Payload = 4543457c8fdf463c4bf8515a762cdc83d9aaa887d3eaa2af
+CT = 0de2906165c4485ecb19c1234690c1a885ec2a521d7cf4e5727c3404564ed41528973d389c7c
+
+Count = 59
+Adata = a0b1d3600f6eba910a11537d61fa12184959f1c3ae386570cbbc9106f7a7ba07
+Payload = 22071ef5d204417f99bc2faf53ecc4c6cf795e77805633ee
+CT = 6aa6cbe8381f4f1d195dbfd66350d9ed933fdca24ec065a446ecb536703a7a97928f80fcc7cf
+
+[Tlen = 16]
+
+Key = 60823b64e0b2da3a7eb772bd5941c534e6ff94ea96b564e2b38f82c78bb54522
+Nonce = 48526f1bffc97dd65e42906983
+
+Count = 60
+Adata = fab62b3e5deda7a9c1128663cc81c44b74ab1bfe70bc1c9dec7c7fd08173b80a
+Payload = a8be794613835c4366e75817d228438f011a2ec8a86f9797
+CT = cc3efe04d84a4ec5cb6a6c28dc2c2d386a359d9550dbdec963ddd56464aed6d0613159d1aa181dcb
+
+Count = 61
+Adata = b3ff11e57eeab41bc597622c770c9eea333e178d5bd5689c6a30011187a965b8
+Payload = 7590769380dc91832da023798dfdd447b9f7adaa09d7e2d0
+CT = 1110f1d14b158305802d174683f9baf0d2d81ef7f163ab8e7c1273765bc5bfdeca429cc8ebd8aca2
+
+Count = 62
+Adata = 2a953a081c5d52bc500c9c12f56cd2aab5c920d73098335baa5d947100cb3411
+Payload = 30e4de5e8c275677f8f4f7bbf9d101f96b38d79968ea028c
+CT = 5464591c47ee44f15579c384f7d56f4e001764c4905e4bd2886229c09b986bee3a8a3025c150d3a3
+
+Count = 63
+Adata = 99cc9d1b3db79640dfdc4423af3ded03c329f7ba5b6b509269c10e59519053b8
+Payload = 852698f6ab4aa794b3d657c4a2ca7b9c8bfb5fc9b4ad0aca
+CT = e1a61fb46083b5121e5b63fbacce152be0d4ec944c19439480cd04041918c4071ea5ac263f36c544
+
+Count = 64
+Adata = b76aef71eaf03c2d0dc0623e90596fcb0bc4dbbed1d5bb24c8af37d778863e5b
+Payload = cd337fcf362d301d66916c7097bdeb31df8206e00f7ac106
+CT = a9b3f88dfde4229bcb1c584f99b98586b4adb5bdf7ce8858f001d6002eafaec49c472acdfaedf1de
+
+Count = 65
+Adata = 42a718d892e229a1807b74bd730fb15500ac4a790392100aef362cd7628d5806
+Payload = 0041a0cf48fcf870b21db6107cfd9ef91e409afc7562ffa7
+CT = 64c1278d8335eaf61f90822f72f9f04e756f29a18dd6b6f975d86cde91b6610496c3bb5276238741
+
+Count = 66
+Adata = e788c98ae85b11b3ae884eed6f3b8f5bcf5ab1b7b20ad3f44f760b2287cc5793
+Payload = fcc74ef1908dbcab9b05c76ee5a9941cdef933d433c0d25f
+CT = 9847c9b35b44ae2d3688f351ebadfaabb5d68089cb749b01db7d9f10e75d1b213beae0e0230dd82b
+
+Count = 67
+Adata = d330fc1ca406dd9528e9281aa1a3cdf013b698c14a4e55371e7539c9f6867dd4
+Payload = 611dade00cec14743be4e035cafe7507df5fb94b278875b1
+CT = 059d2aa2c72506f29669d40ac4fa1bb0b4700a16df3c3cefc63ba64291e73e6349ed089a53564291
+
+Count = 68
+Adata = 06bbadd5d22d1796d88415d7a4b024313f243bd0f58aafc75bb554a691d7e54f
+Payload = b67b5dd7f90ecd48a45853cb193e0d9702d78898f07e831d
+CT = d2fbda9532c7dfce09d567f4173a632069f83bc508caca43ac4d7bd964a2f9e2303df688dd0513da
+
+Count = 69
+Adata = 54da66d406f2d98edd999b673ef44d46ffd196091c8b7582ac2ed6bf13dc648f
+Payload = d092dc436c41836bdb815e473bc6a1906f37624e73b494f9
+CT = b4125b01a78891ed760c6a7835c2cf270418d1138b00dda7b4cd237cd9a7c9d93b9cc0f171818dae
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/ccmtestvectors.zip b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/ccmtestvectors.zip
new file mode 100644
index 0000000000..34bb67b1ac
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/ccmtestvectors.zip
Binary files differ
diff --git a/lib/crypto/test/crypto_bench.spec b/lib/crypto/test/crypto_bench.spec
new file mode 100644
index 0000000000..b9a26d94db
--- /dev/null
+++ b/lib/crypto/test/crypto_bench.spec
@@ -0,0 +1,3 @@
+{suites, "../crypto_test", [
+ crypto_bench_SUITE
+ ]}.
diff --git a/lib/crypto/test/crypto_bench_SUITE.erl b/lib/crypto/test/crypto_bench_SUITE.erl
new file mode 100644
index 0000000000..c66a27f0c8
--- /dev/null
+++ b/lib/crypto/test/crypto_bench_SUITE.erl
@@ -0,0 +1,400 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+-module(crypto_bench_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct_event.hrl").
+-include_lib("common_test/include/ct.hrl").
+
+suite() -> [%%{ct_hooks,[{ts_install_cth,[{nodenames,2}]}]},
+ {timetrap,{minutes,2}}
+ ].
+
+all() ->
+ [
+ {group, textblock_256}
+ ].
+
+groups() ->
+ [
+ {textblock_256, [], [
+ {group, ciphers_128},
+ {group, ciphers_256}
+ ]},
+
+ {ciphers_128, [{repeat, 5}], [
+ block,
+ stream
+ ]},
+
+ {ciphers_256, [{repeat, 5}], [
+ block,
+ stream,
+ chacha
+ ]}
+ ].
+
+%%%----------------------------------------------------------------
+%%%
+init_per_suite(Config0) ->
+ try crypto:start() of
+ _ ->
+ [{_,_,Info}] = crypto:info_lib(),
+ ct:comment("~s",[Info]),
+ ct:pal("Crypto version: ~p~n~n~p",[Info,crypto:supports()]),
+ Config1 = measure_openssl_aes_cbc([128,256], Config0),
+ calibrate([{sec_goal,10} | Config1])
+
+ catch _:_ ->
+ {fail, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ application:stop(crypto).
+
+%%%----------------------------------------------------------------
+%%%
+init_per_group(Group, Config) ->
+ case atom_to_list(Group) of
+ "ciphers_"++KeySizeStr ->
+ KeySize = list_to_integer(KeySizeStr),
+ [{key_size,KeySize} | Config];
+
+ "textblock_"++BlockSizeStr ->
+ BlockSize = list_to_integer(BlockSizeStr),
+ [{block_size,BlockSize} | Config];
+
+ _ ->
+ Config
+ end.
+
+end_per_group(_Group, Config) ->
+ Config.
+
+
+measure_openssl_aes_cbc(KeySizes, Config) ->
+ BLno_acc = [baseline(aes_cbc, KeySize, false) || KeySize <- KeySizes],
+ ct:pal("Non-accelerated baseline encryption time [µs/block]:~n~p", [BLno_acc]),
+ BLacc = [baseline(aes_cbc, KeySize, true) || KeySize <- KeySizes],
+ ct:pal("Possibly accelerated baseline encryption time [µs/block]:~n~p", [BLacc]),
+ [{acc,BLacc},
+ {no_acc,BLno_acc} | Config].
+
+calibrate(Config) ->
+ Secs = proplists:get_value(sec_goal, Config, 10),
+ {_,Empty} = data(empty, 0, 0),
+ {Ne,Te} = run1(Secs*3000, Empty),
+ report(["Overhead"], Te/Ne),
+ [{overhead,Te/Ne} | Config].
+
+%%%================================================================
+%%%
+%%%
+block(Config) ->
+ run_cryptos([aes_cbc, aes_gcm, aes_ccm],
+ Config).
+
+stream(Config) ->
+ run_cryptos([aes_ctr],
+ Config).
+
+chacha(Config) ->
+ run_cryptos([chacha20, chacha20_poly1305],
+ Config).
+
+
+%%%================================================================
+%%%
+%%%
+
+run_cryptos(Cryptos, Config) ->
+ KeySize = proplists:get_value(key_size, Config),
+ BlockSize = proplists:get_value(block_size, Config),
+ MilliSecGoal = 1000*proplists:get_value(sec_goal,Config),
+ OverHead = proplists:get_value(overhead, Config, 0),
+ [try
+ TimePerOpBrutto = run(Crypto,KeySize,BlockSize,MilliSecGoal),
+ %% ct:pal("Brutto: ~p Overhead: ~p (~.2f %) Netto: ~p",
+ %% [TimePerOpBrutto, OverHead, 100*OverHead/TimePerOpBrutto,TimePerOpBrutto - OverHead]),
+ TimePerOpBrutto - OverHead
+ of
+ TimePerOp -> % µs
+ %% First, Report speed of encrypting blocks of 1000. [blocks/sec]
+ ReportUnit = 1000,
+ Label = [fmt(Crypto)," key:",KeySize," block:",BlockSize],
+ report(Label,
+ (BlockSize/ReportUnit)*1000000/TimePerOp
+ ),
+
+ EffCrypto = case Crypto of
+ X -> X
+ end,
+ %% Percent of accelerated speed
+ case find_value([acc,{EffCrypto,KeySize},BlockSize], Config) of
+ undefined ->
+ ok;
+ TimePerOpBaseAcc ->
+ report(["Percent of acc OpenSSL "|Label],
+ 100*TimePerOpBaseAcc/TimePerOp % Percent of base *speed*
+ )
+ end,
+
+ %% Percent of non-accelerated speed
+ case find_value([no_acc,{EffCrypto,KeySize},BlockSize], Config) of
+ undefined ->
+ ok;
+ TimePerOpBaseNoAcc ->
+ report(["Percent of noacc OpenSSL "|Label],
+ 100*TimePerOpBaseNoAcc/TimePerOp % Percent of base *speed*
+ )
+ end
+ catch
+ _:_ ->
+ ct:pal("~p unsupported",[{Crypto,KeySize,BlockSize}])
+ end
+ || Crypto <- Cryptos,
+ supported(Crypto)
+ ].
+
+
+run(Crypto, KeySize, BlockSize, MilliSecGoal) ->
+ {_Type, Funs} = data(Crypto, KeySize, BlockSize),
+ {Nc,Tc} = run1(MilliSecGoal, Funs),
+ Tc/Nc.
+
+fmt(X) -> X.
+
+
+find_value(KeyPath, PropList, Default) ->
+ try find_value(KeyPath, PropList)
+ of
+ undefined -> Default
+ catch
+ error:function_clause -> Default
+ end.
+
+find_value(KeyPath, PropList) ->
+ lists:foldl(fun(K, L) when is_list(L) -> proplists:get_value(K,L);
+ (_, _) -> undefined
+ end, PropList, KeyPath).
+
+%%%================================================================
+%%%
+%%%
+funs({block, {Type, Key, IV, Block}}) ->
+ {fun() -> ok end,
+ fun(_) -> crypto:block_encrypt(Type, Key, IV, Block) end,
+ fun(_) -> ok end};
+
+funs({stream, {Type, Key, IV, Block}}) ->
+ {fun() -> {crypto:stream_init(Type, Key, IV),ok} end,
+ fun({Ctx,_}) -> crypto:stream_encrypt(Ctx, Block) end,
+ fun(_) -> ok end}.
+
+
+data(aes_cbc, KeySize, BlockSize) ->
+ Type = case KeySize of
+ 128 -> aes_cbc128;
+ 256 -> aes_cbc256
+ end,
+ Key = mk_bin(KeySize div 8),
+ IV = mk_bin(16),
+ Block = mk_bin(BlockSize),
+ {Type, funs({block, {Type, Key, IV, Block}})};
+
+data(aes_gcm, KeySize, BlockSize) ->
+ Type = aes_gcm,
+ Key = mk_bin(KeySize div 8),
+ IV = mk_bin(12),
+ Block = mk_bin(BlockSize),
+ AAD = <<01,02,03,04>>,
+ {Type, funs({block, {Type, Key, IV, {AAD,Block,16}}})};
+
+data(aes_ccm, KeySize, BlockSize) ->
+ Type = aes_ccm,
+ Key = mk_bin(KeySize div 8),
+ IV = mk_bin(12),
+ Block = mk_bin(BlockSize),
+ AAD = <<01,02,03,04>>,
+ {Type, funs({block, {Type, Key, IV, {AAD,Block,12}}})};
+
+data(aes_ctr, KeySize, BlockSize) ->
+ Type = aes_ctr,
+ Key = mk_bin(KeySize div 8),
+ IV = mk_bin(16),
+ Block = mk_bin(BlockSize),
+ {Type, funs({stream, {Type, Key, IV, Block}})};
+
+data(chacha20_poly1305, 256=KeySize, BlockSize) ->
+ Type = chacha20_poly1305,
+ Key = mk_bin(KeySize div 8),
+ IV = mk_bin(16),
+ AAD = <<01,02,03,04>>,
+ Block = mk_bin(BlockSize),
+ {Type, funs({block, {Type, Key, IV, {AAD,Block}}})};
+
+data(chacha20, 256=KeySize, BlockSize) ->
+ Type = chacha20,
+ Key = mk_bin(KeySize div 8),
+ IV = mk_bin(16),
+ Block = mk_bin(BlockSize),
+ {Type, funs({stream, {Type, Key, IV, Block}})};
+
+data(empty, 0, 0) ->
+ {undefined,
+ {fun() -> ok end,
+ fun(X) -> X end,
+ fun(_) -> ok end}}.
+
+%%%================================================================
+%%%
+%%%
+run1(MilliSecGoal, Funs) ->
+ Parent = self(),
+ Pid = spawn(fun() ->
+ {Fi,Fu,Ff} = Funs,
+ Ctx0 = Fi(),
+ erlang:garbage_collect(),
+ T0 = start_time(),
+ {N,Ctx} = loop(Fu, Ctx0, 0),
+ T = elapsed_time(T0),
+ Ff(Ctx),
+ Parent ! {result,N,microseconds(T)}
+ end),
+ Pid ! go,
+ receive
+ after MilliSecGoal ->
+ Pid ! stop
+ end,
+ receive
+ {result,N,MicroSecs} ->
+ {N,MicroSecs}
+ end.
+
+
+loop(F, Ctx, N) ->
+ receive
+ stop ->
+ {N, Ctx}
+ after 0 ->
+ loop(F, F(Ctx), N+1)
+ end.
+
+%%%----------------------------------------------------------------
+report(LabelList, Value) ->
+ Label = report_chars(lists:concat(LabelList)),
+ ct:pal("ct_event:notify ~p: ~p", [Label, Value]),
+ ct_event:notify(
+ #event{name = benchmark_data,
+ data = [{name, Label},
+ {value,Value}]}).
+
+report_chars(Cs) ->
+ [case C of
+ $- -> $_;
+ _ -> C
+ end || C <- Cs].
+
+%%%----------------------------------------------------------------
+supported(Algorithm) ->
+ lists:member(Algorithm,
+ [A || {_,As} <- crypto:supports(), A <- As]
+ ).
+
+%%%----------------------------------------------------------------
+start_time() ->
+ erlang:system_time().
+
+elapsed_time(StartTime) ->
+ erlang:system_time() - StartTime.
+
+microseconds(Time) ->
+ erlang:convert_time_unit(Time, native, microsecond).
+
+%%%----------------------------------------------------------------
+
+%% Example output:
+%% +DT:aes-128-cbc:3:16
+%% +R:135704772:aes-128-cbc:2.980000
+%% +DT:aes-128-cbc:3:64
+%% +R:36835089:aes-128-cbc:3.000000
+%% +DT:aes-128-cbc:3:256
+%% +R:9398616:aes-128-cbc:3.000000
+%% +DT:aes-128-cbc:3:1024
+%% +R:2355683:aes-128-cbc:2.990000
+%% +DT:aes-128-cbc:3:8192
+%% +R:294508:aes-128-cbc:2.990000
+%% +H:16:64:256:1024:8192
+%% +F:22:aes-128-cbc:728616225.50:785815232.00:802015232.00:806762338.46:806892821.40
+
+baseline(Crypto, KeySize, EVP) ->
+ Spec=
+ case {Crypto,KeySize} of
+ {aes_cbc, 128} -> "aes-128-cbc";
+ {aes_cbc, 256} -> "aes-256-cbc"
+ end,
+ {{Crypto,KeySize}, baseline(Spec, EVP)}.
+
+baseline(Spec, EVP) ->
+ Cmd =
+ case EVP of
+ true -> "openssl speed -mr -evp " ++ Spec;
+ false-> "openssl speed -mr " ++ Spec
+ end,
+ get_base_values(string:tokens(os:cmd(Cmd),"\n"), Spec, []).
+
+
+get_base_values(["+DT:"++Sdt,
+ "+R:"++Sr
+ |T], Crypto, Acc) ->
+ [Crypto0,_GoalSecs0,BlockSize0] = string:tokens(Sdt, ":"),
+ [Nblocks0,Crypto0,RealSecs0] = string:tokens(Sr, ":"),
+ Crypto = fix_possible_space_bug(Crypto0),
+ RealSecs = list_to_float(RealSecs0),
+ BlockSize = list_to_integer(BlockSize0),
+ Nblocks = list_to_integer(Nblocks0),
+ get_base_values(T, Crypto, [{BlockSize, 1000000*RealSecs/Nblocks} | Acc]);
+
+get_base_values([_|T], Crypto, Acc) ->
+ get_base_values(T, Crypto, Acc);
+
+get_base_values([], _, Acc) ->
+ lists:sort(Acc).
+
+fix_possible_space_bug(S) -> lists:concat(lists:join("-",string:tokens(S,"- "))).
+
+%%%----------------------------------------------------------------
+mk_bin(Size) when Size =< 256 ->
+ list_to_binary(lists:seq(0,Size-1));
+
+mk_bin(Size) when 1024 =< Size ->
+ B = mk_bin(Size div 4),
+ Brest = mk_bin(Size rem 4),
+ <<B/binary, B/binary, B/binary, B/binary, Brest/binary>>;
+
+mk_bin(Size) when 256 < Size ->
+ B = mk_bin(Size div 2),
+ Brest = mk_bin(Size rem 2),
+ <<B/binary, B/binary, Brest/binary>>.
+
diff --git a/lib/crypto/test/engine_SUITE.erl b/lib/crypto/test/engine_SUITE.erl
index f410542f72..41cd132734 100644
--- a/lib/crypto/test/engine_SUITE.erl
+++ b/lib/crypto/test/engine_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2017-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -39,6 +39,10 @@ all() ->
get_all_possible_methods,
engine_load_all_methods,
engine_load_some_methods,
+ multiple_engine_load,
+ engine_list,
+ get_id_and_name,
+ engine_by_id,
bad_arguments,
unknown_engine,
pre_command_fail_bad_value,
@@ -46,12 +50,15 @@ all() ->
failed_engine_init,
ctrl_cmd_string,
ctrl_cmd_string_optional,
- {group, engine_stored_key}
+ ensure_load,
+ {group, engine_stored_key},
+ {group, engine_fakes_rsa}
].
groups() ->
[{engine_stored_key, [],
- [sign_verify_rsa,
+ [
+ sign_verify_rsa,
sign_verify_dsa,
sign_verify_ecdsa,
sign_verify_rsa_pwd,
@@ -66,58 +73,96 @@ groups() ->
get_pub_from_priv_key_rsa_pwd_bad_pwd,
get_pub_from_priv_key_dsa,
get_pub_from_priv_key_ecdsa
- ]}].
+ ]},
+ {engine_fakes_rsa, [], [sign_verify_rsa_fake
+ ]}
+ ].
init_per_suite(Config) ->
- try crypto:start() of
- ok ->
- case crypto:info_lib() of
- [{_,_, <<"OpenSSL 1.0.1s-freebsd 1 Mar 2016">>}] ->
- {skip, "Problem with engine on OpenSSL 1.0.1s-freebsd"};
- _ ->
+ case {os:type(), crypto:info_lib()} of
+ {_, [{_,_, <<"OpenSSL 1.0.1s-freebsd 1 Mar 2016">>}]} ->
+ {skip, "Problem with engine on OpenSSL 1.0.1s-freebsd"};
+
+ {{unix,darwin}, _} ->
+ {skip, "Engine unsupported on Darwin"};
+
+ {{win32,_}, _} ->
+ {skip, "Engine unsupported on Windows"};
+
+ {OS, Res} ->
+ ct:log("crypto:info_lib() -> ~p\nos:type() -> ~p", [Res,OS]),
+ try crypto:start() of
+ ok ->
+ Config;
+ {error,{already_started,crypto}} ->
Config
- end;
- {error,{already_started,crypto}} ->
- Config
- catch _:_ ->
- {skip, "Crypto did not start"}
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end
end.
+
end_per_suite(_Config) ->
ok.
%%--------------------------------------------------------------------
init_per_group(engine_stored_key, Config) ->
- case load_storage_engine(Config) of
+ group_load_engine(Config, [engine_method_rsa]);
+init_per_group(engine_fakes_rsa, Config) ->
+ case crypto:info_lib() of
+ [{<<"OpenSSL">>,LibVer,_}] when is_integer(LibVer), LibVer >= 16#10100000 ->
+ group_load_engine(Config, []);
+ _ ->
+ {skip, "Too low OpenSSL cryptolib version"}
+ end;
+init_per_group(_Group, Config0) ->
+ Config0.
+
+
+group_load_engine(Config, ExcludeMthds) ->
+ case load_storage_engine(Config, ExcludeMthds) of
{ok, E} ->
KeyDir = key_dir(Config),
[{storage_engine,E}, {storage_dir,KeyDir} | Config];
{error, notexist} ->
{skip, "OTP Test engine not found"};
{error, notsup} ->
- {skip, "Engine not supported on this OpenSSL version"};
+ {skip, "Engine not supported on this SSL version"};
{error, bad_engine_id} ->
{skip, "Dynamic Engine not supported"};
Other ->
ct:log("Engine load failed: ~p",[Other]),
{fail, "Engine load failed"}
- end;
-init_per_group(_Group, Config0) ->
- Config0.
+ end.
+
+
-end_per_group(engine_stored_key, Config) ->
+
+
+end_per_group(_, Config) ->
case proplists:get_value(storage_engine, Config) of
undefined ->
ok;
E ->
ok = crypto:engine_unload(E)
- end;
-end_per_group(_, _) ->
- ok.
+ end.
%%--------------------------------------------------------------------
-init_per_testcase(_Case, Config) ->
- Config.
+init_per_testcase(Case, Config) ->
+ case string:tokens(atom_to_list(Case),"_") of
+ ["sign","verify",Type|_] ->
+ skip_if_unsup(list_to_atom(Type), Config);
+
+ ["priv","encrypt","pub","decrypt",Type|_] ->
+ skip_if_unsup(list_to_atom(Type), Config);
+
+ ["get","pub","from","priv","key",Type|_] ->
+ skip_if_unsup(list_to_atom(Type), Config);
+
+ _ ->
+ Config
+ end.
+
end_per_testcase(_Case, _Config) ->
ok.
@@ -130,11 +175,12 @@ get_all_possible_methods() ->
get_all_possible_methods(Config) when is_list(Config) ->
try
List = crypto:engine_get_all_methods(),
+ true = erlang:is_list(List),
ct:log("crypto:engine_get_all_methods() -> ~p\n", [List]),
ok
catch
error:notsup ->
- {skip, "Engine not supported on this OpenSSL version"}
+ {skip, "Engine not supported on this SSL version"}
end.
engine_load_all_methods()->
@@ -147,13 +193,12 @@ engine_load_all_methods(Config) when is_list(Config) ->
{error, notexist} ->
{skip, "OTP Test engine not found"};
{ok, Engine} ->
- try
+ try
Md5Hash1 = <<106,30,3,246,166,222,229,158,244,217,241,179,50,232,107,109>>,
Md5Hash1 = crypto:hash(md5, "Don't panic"),
Md5Hash2 = <<0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>,
case crypto:engine_load(<<"dynamic">>,
[{<<"SO_PATH">>, Engine},
- {<<"ID">>, <<"MD5">>},
<<"LOAD">>],
[]) of
{ok, E} ->
@@ -179,7 +224,7 @@ engine_load_all_methods(Config) when is_list(Config) ->
end
catch
error:notsup ->
- {skip, "Engine not supported on this OpenSSL version"}
+ {skip, "Engine not supported on this SSL version"}
end
end.
@@ -193,21 +238,20 @@ engine_load_some_methods(Config) when is_list(Config) ->
{error, notexist} ->
{skip, "OTP Test engine not found"};
{ok, Engine} ->
- try
+ try
Md5Hash1 = <<106,30,3,246,166,222,229,158,244,217,241,179,50,232,107,109>>,
Md5Hash1 = crypto:hash(md5, "Don't panic"),
Md5Hash2 = <<0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>,
EngineMethods = crypto:engine_get_all_methods() --
- [engine_method_dh,engine_method_rand,
+ [engine_method_dh, engine_method_rand,
engine_method_ciphers, engine_method_store,
engine_method_pkey_meths, engine_method_pkey_asn1_meths],
case crypto:engine_load(<<"dynamic">>,
[{<<"SO_PATH">>, Engine},
- {<<"ID">>, <<"MD5">>},
<<"LOAD">>],
[],
EngineMethods) of
- {ok, E} ->
+ {ok, E} ->
case crypto:hash(md5, "Don't panic") of
Md5Hash1 ->
ct:fail(fail_to_load_engine_still_original);
@@ -230,7 +274,168 @@ engine_load_some_methods(Config) when is_list(Config) ->
end
catch
error:notsup ->
- {skip, "Engine not supported on this OpenSSL version"}
+ {skip, "Engine not supported on this SSL version"}
+ end
+ end.
+
+multiple_engine_load()->
+ [{doc, "Use a dummy md5 engine that does not implement md5"
+ "but rather returns a static binary to test that crypto:engine_load "
+ "functions works when called multiple times."}].
+
+multiple_engine_load(Config) when is_list(Config) ->
+ case crypto:get_test_engine() of
+ {error, notexist} ->
+ {skip, "OTP Test engine not found"};
+ {ok, Engine} ->
+ try
+ Md5Hash1 = <<106,30,3,246,166,222,229,158,244,217,241,179,50,232,107,109>>,
+ Md5Hash1 = crypto:hash(md5, "Don't panic"),
+ Md5Hash2 = <<0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>,
+ case crypto:engine_load(<<"dynamic">>,
+ [{<<"SO_PATH">>, Engine},
+ <<"LOAD">>],
+ []) of
+ {ok, E} ->
+ {ok, E1} = crypto:engine_load(<<"dynamic">>,
+ [{<<"SO_PATH">>, Engine},
+ <<"LOAD">>],
+ []),
+ {ok, E2} = crypto:engine_load(<<"dynamic">>,
+ [{<<"SO_PATH">>, Engine},
+ <<"LOAD">>],
+ []),
+ case crypto:hash(md5, "Don't panic") of
+ Md5Hash1 ->
+ ct:fail(fail_to_load_still_original_engine);
+ Md5Hash2 ->
+ ok;
+ _ ->
+ ct:fail(fail_to_load_engine)
+ end,
+ ok = crypto:engine_unload(E2),
+ case crypto:hash(md5, "Don't panic") of
+ Md5Hash1 ->
+ ct:fail(fail_to_load_still_original_engine);
+ Md5Hash2 ->
+ ok;
+ _ ->
+ ct:fail(fail_to_load_engine)
+ end,
+ ok = crypto:engine_unload(E),
+ case crypto:hash(md5, "Don't panic") of
+ Md5Hash1 ->
+ ct:fail(fail_to_load_still_original_engine);
+ Md5Hash2 ->
+ ok;
+ _ ->
+ ct:fail(fail_to_load_engine)
+ end,
+ ok = crypto:engine_unload(E1),
+ case crypto:hash(md5, "Don't panic") of
+ Md5Hash2 ->
+ ct:fail(fail_to_unload_still_test_engine);
+ Md5Hash1 ->
+ ok;
+ _ ->
+ ct:fail(fail_to_unload_engine)
+ end;
+ {error, bad_engine_id} ->
+ {skip, "Dynamic Engine not supported"}
+ end
+ catch
+ error:notsup ->
+ {skip, "Engine not supported on this SSL version"}
+ end
+ end.
+
+engine_list()->
+ [{doc, "Test add and remove engine ID to the SSL internal engine list."}].
+
+engine_list(Config) when is_list(Config) ->
+ case crypto:get_test_engine() of
+ {error, notexist} ->
+ {skip, "OTP Test engine not found"};
+ {ok, Engine} ->
+ try
+ case crypto:engine_load(<<"dynamic">>,
+ [{<<"SO_PATH">>, Engine},
+ <<"LOAD">>],
+ []) of
+ {ok, E} ->
+ EngineList0 = crypto:engine_list(),
+ false = lists:member(<<"MD5">>, EngineList0),
+ ok = crypto:engine_add(E),
+ [<<"MD5">>] = lists:subtract(crypto:engine_list(), EngineList0),
+ ok = crypto:engine_remove(E),
+ EngineList0 = crypto:engine_list(),
+ ok = crypto:engine_unload(E);
+ {error, bad_engine_id} ->
+ {skip, "Dynamic Engine not supported"}
+ end
+ catch
+ error:notsup ->
+ {skip, "Engine not supported on this SSL version"}
+ end
+ end.
+
+get_id_and_name()->
+ [{doc, "Test fetching id and name from an engine."}].
+
+get_id_and_name(Config) when is_list(Config) ->
+ case crypto:get_test_engine() of
+ {error, notexist} ->
+ {skip, "OTP Test engine not found"};
+ {ok, Engine} ->
+ try
+ case crypto:engine_load(<<"dynamic">>,
+ [{<<"SO_PATH">>, Engine},
+ <<"LOAD">>],
+ []) of
+ {ok, E} ->
+ <<"MD5">> = crypto:engine_get_id(E),
+ <<"MD5 test engine">> = crypto:engine_get_name(E),
+ ok = crypto:engine_unload(E);
+ {error, bad_engine_id} ->
+ {skip, "Dynamic Engine not supported"}
+ end
+ catch
+ error:notsup ->
+ {skip, "Engine not supported on this SSL version"}
+ end
+ end.
+
+engine_by_id()->
+ [{doc, "Test fetching a new reference the the engine when the"
+ "engine id is added to the SSL engine list."}].
+
+engine_by_id(Config) when is_list(Config) ->
+ case crypto:get_test_engine() of
+ {error, notexist} ->
+ {skip, "OTP Test engine not found"};
+ {ok, Engine} ->
+ try
+ case crypto:engine_load(<<"dynamic">>,
+ [{<<"SO_PATH">>, Engine},
+ <<"LOAD">>],
+ []) of
+ {ok, E} ->
+ case crypto:engine_by_id(<<"MD5">>) of
+ {error,bad_engine_id} ->
+ ok;
+ {ok, _} ->
+ ct:fail(fail_engine_found)
+ end,
+ ok = crypto:engine_add(E),
+ {ok, _E1} = crypto:engine_by_id(<<"MD5">>),
+ ok = crypto:engine_remove(E),
+ ok = crypto:engine_unload(E);
+ {error, bad_engine_id} ->
+ {skip, "Dynamic Engine not supported"}
+ end
+ catch
+ error:notsup ->
+ {skip, "Engine not supported on this SSL version"}
end
end.
@@ -244,9 +449,12 @@ bad_arguments(Config) when is_list(Config) ->
{error, notexist} ->
{skip, "OTP Test engine not found"};
{ok, Engine} ->
- try
+ try
try
crypto:engine_load(fail_engine, [], [])
+ of
+ X1 ->
+ ct:fail("1 Got ~p",[X1])
catch
error:badarg ->
ok
@@ -258,6 +466,11 @@ bad_arguments(Config) when is_list(Config) ->
{<<"ID">>, <<"MD5">>},
<<"LOAD">>],
[])
+ of
+ {error,bad_engine_id} ->
+ throw(dynamic_engine_unsupported);
+ X2 ->
+ ct:fail("2 Got ~p",[X2])
catch
error:badarg ->
ok
@@ -268,13 +481,20 @@ bad_arguments(Config) when is_list(Config) ->
{'ID', <<"MD5">>},
<<"LOAD">>],
[])
+ of
+ {error,bad_engine_id} -> % should have happend in the previous try...catch end!
+ throw(dynamic_engine_unsupported);
+ X3 ->
+ ct:fail("3 Got ~p",[X3])
catch
error:badarg ->
ok
end
catch
error:notsup ->
- {skip, "Engine not supported on this OpenSSL version"}
+ {skip, "Engine not supported on this SSL version"};
+ throw:dynamic_engine_unsupported ->
+ {skip, "Dynamic Engine not supported"}
end
end.
@@ -287,7 +507,7 @@ unknown_engine(Config) when is_list(Config) ->
ok
catch
error:notsup ->
- {skip, "Engine not supported on this OpenSSL version"}
+ {skip, "Engine not supported on this SSL version"}
end.
pre_command_fail_bad_value() ->
@@ -309,7 +529,7 @@ pre_command_fail_bad_value(Config) when is_list(Config) ->
end
catch
error:notsup ->
- {skip, "Engine not supported on this OpenSSL version"}
+ {skip, "Engine not supported on this SSL version"}
end.
pre_command_fail_bad_key() ->
@@ -332,9 +552,9 @@ pre_command_fail_bad_key(Config) when is_list(Config) ->
{skip, "Dynamic Engine not supported"}
end
end
- catch
+ catch
error:notsup ->
- {skip, "Engine not supported on this OpenSSL version"}
+ {skip, "Engine not supported on this SSL version"}
end.
failed_engine_init()->
@@ -350,18 +570,20 @@ failed_engine_init(Config) when is_list(Config) ->
[{<<"SO_PATH">>, Engine},
{<<"ID">>, <<"MD5">>}],
[]) of
- {error, add_engine_failed} ->
+ {error, engine_init_failed} ->
ok;
{error, bad_engine_id} ->
{skip, "Dynamic Engine not supported"}
end
end
- catch
+ catch
error:notsup ->
- {skip, "Engine not supported on this OpenSSL version"}
+ {skip, "Engine not supported on this SSL version"}
end.
+%%-------------------------------------------------------------------------
+%% Test the optional flag in ctrl comands
ctrl_cmd_string()->
[{doc, "Test that a not known optional ctrl comand do not fail"}].
ctrl_cmd_string(Config) when is_list(Config) ->
@@ -375,22 +597,22 @@ ctrl_cmd_string(Config) when is_list(Config) ->
{<<"ID">>, <<"MD5">>},
<<"LOAD">>],
[]) of
- {ok, E} ->
+ {ok, E} ->
case crypto:engine_ctrl_cmd_string(E, <<"TEST">>, <<"17">>) of
ok ->
+ ok = crypto:engine_unload(E),
ct:fail(fail_ctrl_cmd_should_fail);
- {error,ctrl_cmd_failed} ->
- ok
- end,
- ok = crypto:engine_unload(E);
+ {error,ctrl_cmd_failed} ->
+ ok = crypto:engine_unload(E)
+ end;
{error, bad_engine_id} ->
{skip, "Dynamic Engine not supported"}
end
end
- catch
+ catch
error:notsup ->
- {skip, "Engine not supported on this OpenSSL version"}
- end.
+ {skip, "Engine not supported on this SSL version"}
+ end.
ctrl_cmd_string_optional()->
[{doc, "Test that a not known optional ctrl comand do not fail"}].
@@ -405,25 +627,67 @@ ctrl_cmd_string_optional(Config) when is_list(Config) ->
{<<"ID">>, <<"MD5">>},
<<"LOAD">>],
[]) of
- {ok, E} ->
+ {ok, E} ->
case crypto:engine_ctrl_cmd_string(E, <<"TEST">>, <<"17">>, true) of
ok ->
- ok;
- _ ->
+ ok = crypto:engine_unload(E);
+ Err ->
+ ct:log("Error: ~p",[Err]),
+ ok = crypto:engine_unload(E),
ct:fail(fail_ctrl_cmd_string)
- end,
- ok = crypto:engine_unload(E);
+ end;
{error, bad_engine_id} ->
{skip, "Dynamic Engine not supported"}
end
end
- catch
+ catch
error:notsup ->
- {skip, "Engine not supported on this OpenSSL version"}
- end.
+ {skip, "Engine not supported on this SSL version"}
+ end.
+
+ensure_load()->
+ [{doc, "Test the special ensure load function."}].
+
+ensure_load(Config) when is_list(Config) ->
+ case crypto:get_test_engine() of
+ {error, notexist} ->
+ {skip, "OTP Test engine not found"};
+ {ok, Engine} ->
+ try
+ Md5Hash1 = <<106,30,3,246,166,222,229,158,244,217,241,179,50,232,107,109>>,
+ Md5Hash1 = crypto:hash(md5, "Don't panic"),
+ Md5Hash2 = <<0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>,
+ case crypto:ensure_engine_loaded(<<"MD5">>, Engine) of
+ {ok, E} ->
+ {ok, _E1} = crypto:ensure_engine_loaded(<<"MD5">>, Engine),
+ case crypto:hash(md5, "Don't panic") of
+ Md5Hash1 ->
+ ct:fail(fail_to_load_still_original_engine);
+ Md5Hash2 ->
+ ok;
+ _ ->
+ ct:fail(fail_to_load_engine)
+ end,
+ ok = crypto:ensure_engine_unloaded(E),
+ case crypto:hash(md5, "Don't panic") of
+ Md5Hash2 ->
+ ct:fail(fail_to_unload_still_test_engine);
+ Md5Hash1 ->
+ ok;
+ _ ->
+ ct:fail(fail_to_unload_engine)
+ end;
+ {error, bad_engine_id} ->
+ {skip, "Dynamic Engine not supported"}
+ end
+ catch
+ error:notsup ->
+ {skip, "Engine not supported on this SSL version"}
+ end
+ end.
%%%----------------------------------------------------------------
-%%% Pub/priv key storage tests. Thoose are for testing the crypto.erl
+%%% Pub/priv key storage tests. Those are for testing the crypto.erl
%%% support for using priv/pub keys stored in an engine.
sign_verify_rsa(Config) ->
@@ -433,6 +697,14 @@ sign_verify_rsa(Config) ->
key_id => key_id(Config, "rsa_public_key.pem")},
sign_verify(rsa, sha, Priv, Pub).
+sign_verify_rsa_fake(Config) ->
+ %% Use fake engine rsa implementation
+ Priv = #{engine => engine_ref(Config),
+ key_id => key_id(Config, "rsa_private_key.pem")},
+ Pub = #{engine => engine_ref(Config),
+ key_id => key_id(Config, "rsa_public_key.pem")},
+ sign_verify_fake(rsa, sha256, Priv, Pub).
+
sign_verify_dsa(Config) ->
Priv = #{engine => engine_ref(Config),
key_id => key_id(Config, "dsa_private_key.pem")},
@@ -465,7 +737,7 @@ sign_verify_rsa_pwd_bad_pwd(Config) ->
_ -> {fail, "PWD prot pubkey sign succeded with no pwd!"}
catch
error:badarg -> ok
- end.
+ end.
priv_encrypt_pub_decrypt_rsa(Config) ->
Priv = #{engine => engine_ref(Config),
@@ -538,7 +810,7 @@ get_pub_from_priv_key_rsa_pwd_no_pwd(Config) ->
{skip, "RSA not supported"};
{error, Error} ->
{fail, {wrong_error,Error}};
- Pub ->
+ Pub ->
ct:log("rsa Pub = ~p",[Pub]),
{fail, "PWD prot pubkey fetch succeded although no pwd!"}
end.
@@ -554,7 +826,7 @@ get_pub_from_priv_key_rsa_pwd_bad_pwd(Config) ->
{skip, "RSA not supported"};
{error, Error} ->
{fail, {wrong_error,Error}};
- Pub ->
+ Pub ->
ct:log("rsa Pub = ~p",[Pub]),
{fail, "PWD prot pubkey fetch succeded with bad pwd!"}
end.
@@ -588,17 +860,35 @@ get_pub_from_priv_key_ecdsa(Config) ->
ct:log("ecdsa Pub = ~p",[Pub]),
sign_verify(ecdsa, sha, Priv, Pub)
end.
-
+
%%%================================================================
%%% Help for engine_stored_pub_priv_keys* test cases
%%%
-load_storage_engine(_Config) ->
+skip_if_unsup(Type, Config) ->
+ case pkey_supported(Type) of
+ false ->
+ {skip, "Unsupported in this cryptolib"};
+ true ->
+ Config
+ end.
+
+
+pkey_supported(Type) ->
+ lists:member(Type, proplists:get_value(public_keys, crypto:supports(), [])).
+
+
+load_storage_engine(Config) ->
+ load_storage_engine(Config, []).
+
+load_storage_engine(_Config, ExcludeMthds) ->
case crypto:get_test_engine() of
{ok, Engine} ->
try crypto:engine_load(<<"dynamic">>,
[{<<"SO_PATH">>, Engine},
<<"LOAD">>],
- [])
+ [],
+ crypto:engine_get_all_methods() -- ExcludeMthds
+ )
catch
error:notsup ->
{error, notsup}
@@ -656,10 +946,47 @@ sign_verify(Alg, Sha, KeySign, KeyVerify) ->
true ->
PlainText = <<"Hej på dig">>,
Signature = crypto:sign(Alg, Sha, PlainText, KeySign),
- case crypto:verify(Alg, Sha, PlainText, Signature, KeyVerify) of
- true -> ok;
- _ -> {fail, "Sign-verify error"}
+ case is_fake(Signature) of
+ true ->
+ ct:pal("SIG ~p ~p size ~p~n~p",[Alg,Sha,size(Signature),Signature]),
+ {fail, "Faked RSA impl used!!"};
+ false ->
+ case crypto:verify(Alg, Sha, PlainText, Signature, KeyVerify) of
+ true -> ok;
+ _ -> {fail, "Sign-verify error"}
+ end
end;
false ->
{skip, lists:concat([Alg," is not supported by cryptolib"])}
end.
+
+
+%%% Use fake engine rsa implementation
+sign_verify_fake(Alg, Sha, KeySign, KeyVerify) ->
+ case pubkey_alg_supported(Alg) of
+ true ->
+ PlainText = <<"Fake me!">>,
+ Signature = crypto:sign(Alg, Sha, PlainText, KeySign),
+ case is_fake(Signature) of
+ true ->
+ case crypto:verify(Alg, Sha, PlainText, Signature, KeyVerify) of
+ true -> ok;
+ _ -> {fail, "Sign-verify error"}
+ end;
+ false ->
+ ct:pal("SIG ~p ~p size ~p~n~p",[Alg,Sha,size(Signature),Signature]),
+ {fail, "Faked impl not used"}
+ end;
+ false ->
+ {skip, lists:concat([Alg," is not supported by cryptolib"])}
+ end.
+
+
+is_fake(Sig) -> is_fake(Sig, 0).
+
+is_fake(<<>>, _) -> true;
+is_fake(<<B,Rest/binary>>, B) -> is_fake(Rest, B+1);
+is_fake(_, _) -> false.
+
+
+
diff --git a/lib/crypto/vsn.mk b/lib/crypto/vsn.mk
index 3432f00836..72a51bfec9 100644
--- a/lib/crypto/vsn.mk
+++ b/lib/crypto/vsn.mk
@@ -1 +1 @@
-CRYPTO_VSN = 4.2.1
+CRYPTO_VSN = 4.5
diff --git a/lib/debugger/doc/src/Makefile b/lib/debugger/doc/src/Makefile
index cc0b8861d3..49b5a4be57 100644
--- a/lib/debugger/doc/src/Makefile
+++ b/lib/debugger/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -99,6 +99,7 @@ gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
@@ -113,8 +114,7 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
$(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
$(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
- $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
- ($(CP) -rf $(HTMLDIR) "$(RELSYSDIR)/doc")
+ $(INSTALL_DIR_DATA) $(HTMLDIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
$(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
$(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
diff --git a/lib/debugger/doc/src/debugger.xml b/lib/debugger/doc/src/debugger.xml
index 1ecdbcd064..77285095e7 100644
--- a/lib/debugger/doc/src/debugger.xml
+++ b/lib/debugger/doc/src/debugger.xml
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>debugger</module>
+ <module since="">debugger</module>
<modulesummary>Erlang Debugger.</modulesummary>
<description>
<p>Erlang Debugger for debugging and testing of Erlang programs.</p>
@@ -36,10 +36,10 @@
<funcs>
<func>
- <name>start()</name>
- <name>start(File)</name>
- <name>start(Mode)</name>
- <name>start(Mode, File)</name>
+ <name since="">start()</name>
+ <name since="">start(File)</name>
+ <name since="">start(Mode)</name>
+ <name since="">start(Mode, File)</name>
<fsummary>Start Debugger.</fsummary>
<type>
<v>Mode = local | global</v>
@@ -60,7 +60,7 @@
</func>
<func>
- <name>quick(Module, Name, Args)</name>
+ <name since="">quick(Module, Name, Args)</name>
<fsummary>Debug a process.</fsummary>
<type>
<v>Module = Name = atom()</v>
diff --git a/lib/debugger/doc/src/i.xml b/lib/debugger/doc/src/i.xml
index 628b91e9e4..06b0eb876a 100644
--- a/lib/debugger/doc/src/i.xml
+++ b/lib/debugger/doc/src/i.xml
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>i</module>
+ <module since="">i</module>
<modulesummary>Debugger/Interpreter Interface.</modulesummary>
<description>
<p>The <c>i</c> module provides short forms for some of
@@ -51,7 +51,7 @@
<funcs>
<func>
- <name>im() -> pid()</name>
+ <name since="">im() -> pid()</name>
<fsummary>Start a graphical monitor.</fsummary>
<desc>
<p>Starts a new graphical monitor. This is the Monitor window,
@@ -63,10 +63,10 @@
</func>
<func>
- <name>ii(AbsModules) -> ok</name>
- <name>ii(AbsModule) -> {module, Module} | error</name>
- <name>ini(AbsModules) -> ok</name>
- <name>ini(AbsModule) -> {module, Module} | error</name>
+ <name since="">ii(AbsModules) -> ok</name>
+ <name since="">ii(AbsModule) -> {module, Module} | error</name>
+ <name since="">ini(AbsModules) -> ok</name>
+ <name since="">ini(AbsModule) -> {module, Module} | error</name>
<fsummary>Interpret a module.</fsummary>
<type>
<v>AbsModules = [AbsModule]</v>
@@ -84,8 +84,8 @@
</func>
<func>
- <name>iq(AbsModule) -> ok</name>
- <name>inq(AbsModule) -> ok</name>
+ <name since="">iq(AbsModule) -> ok</name>
+ <name since="">inq(AbsModule) -> ok</name>
<fsummary>Stop interpreting a module.</fsummary>
<type>
<v>AbsModule = Module | File</v>
@@ -100,7 +100,7 @@
</func>
<func>
- <name>il() -> ok</name>
+ <name since="">il() -> ok</name>
<fsummary>Make a printout of all interpreted modules</fsummary>
<desc>
<p>Makes a printout of all interpreted modules.
@@ -110,7 +110,7 @@
</func>
<func>
- <name>ip() -> ok</name>
+ <name since="">ip() -> ok</name>
<fsummary>Print the current status of all interpreted
processes.</fsummary>
<desc>
@@ -119,7 +119,7 @@
</func>
<func>
- <name>ic() -> ok</name>
+ <name since="">ic() -> ok</name>
<fsummary>Clear information about processes executing interpreted
code.</fsummary>
<desc>
@@ -129,8 +129,8 @@
</func>
<func>
- <name>iaa(Flags) -> true</name>
- <name>iaa(Flags, Function) -> true</name>
+ <name since="">iaa(Flags) -> true</name>
+ <name since="">iaa(Flags, Function) -> true</name>
<fsummary>Set when and how to attach to a process.</fsummary>
<type>
<v>Flags = [init | break | exit]</v>
@@ -148,7 +148,7 @@
</func>
<func>
- <name>ist(Flag) -> true</name>
+ <name since="">ist(Flag) -> true</name>
<fsummary>Set how to save call frames.</fsummary>
<type>
<v>Flag = all | no_tail | false</v>
@@ -160,7 +160,7 @@
</func>
<func>
- <name>ia(Pid) -> ok | no_proc</name>
+ <name since="">ia(Pid) -> ok | no_proc</name>
<fsummary>Attache to a process.</fsummary>
<type>
<v>Pid = pid()</v>
@@ -172,7 +172,7 @@
</func>
<func>
- <name>ia(X,Y,Z) -> ok | no_proc</name>
+ <name since="">ia(X,Y,Z) -> ok | no_proc</name>
<fsummary>Attache to a process.</fsummary>
<type>
<v>X = Y = Z = int()</v>
@@ -184,7 +184,7 @@
</func>
<func>
- <name>ia(Pid, Function) -> ok | no_proc</name>
+ <name since="">ia(Pid, Function) -> ok | no_proc</name>
<fsummary>Attache to a process.</fsummary>
<type>
<v>Pid = pid()</v>
@@ -199,7 +199,7 @@
</func>
<func>
- <name>ia(X,Y,Z, Function) -> ok | no_proc</name>
+ <name since="">ia(X,Y,Z, Function) -> ok | no_proc</name>
<fsummary>Attache to a process.</fsummary>
<type>
<v>X = Y = Z = int()</v>
@@ -217,7 +217,7 @@
</func>
<func>
- <name>ib(Module, Line) -> ok | {error, break_exists}</name>
+ <name since="">ib(Module, Line) -> ok | {error, break_exists}</name>
<fsummary>Create a breakpoint.</fsummary>
<type>
<v>Module = atom()</v>
@@ -229,7 +229,7 @@
</func>
<func>
- <name>ib(Module, Name, Arity) -> ok | {error, function_not_found}
+ <name since="">ib(Module, Name, Arity) -> ok | {error, function_not_found}
</name>
<fsummary>Create breakpoints in the specified function.</fsummary>
<type>
@@ -243,7 +243,7 @@
</func>
<func>
- <name>ir() -> ok</name>
+ <name since="">ir() -> ok</name>
<fsummary>Delete all breakpoints.</fsummary>
<desc>
<p>Deletes all breakpoints.</p>
@@ -251,7 +251,7 @@
</func>
<func>
- <name>ir(Module) -> ok</name>
+ <name since="">ir(Module) -> ok</name>
<fsummary>Delete all breakpoints in a module.</fsummary>
<type>
<v>Module = atom()</v>
@@ -262,7 +262,7 @@
</func>
<func>
- <name>ir(Module, Line) -> ok</name>
+ <name since="">ir(Module, Line) -> ok</name>
<fsummary>Delete a breakpoint.</fsummary>
<type>
<v>Module = atom()</v>
@@ -274,7 +274,7 @@
</func>
<func>
- <name>ir(Module, Name, Arity) -> ok | {error, function_not_found}
+ <name since="">ir(Module, Name, Arity) -> ok | {error, function_not_found}
</name>
<fsummary>Delete breakpoints from the specified function.</fsummary>
<type>
@@ -288,7 +288,7 @@
</func>
<func>
- <name>ibd(Module, Line) -> ok</name>
+ <name since="">ibd(Module, Line) -> ok</name>
<fsummary>Make a breakpoint inactive.</fsummary>
<type>
<v>Module = atom()</v>
@@ -300,7 +300,7 @@
</func>
<func>
- <name>ibe(Module, Line) -> ok</name>
+ <name since="">ibe(Module, Line) -> ok</name>
<fsummary>Make a breakpoint active.</fsummary>
<type>
<v>Module = atom()</v>
@@ -312,7 +312,7 @@
</func>
<func>
- <name>iba(Module, Line, Action) -> ok</name>
+ <name since="">iba(Module, Line, Action) -> ok</name>
<fsummary>Set the trigger action of a breakpoint.</fsummary>
<type>
<v>Module = atom()</v>
@@ -326,7 +326,7 @@
</func>
<func>
- <name>ibc(Module, Line, Function) -> ok</name>
+ <name since="">ibc(Module, Line, Function) -> ok</name>
<fsummary>Set the conditional test of a breakpoint.</fsummary>
<type>
<v>Module = atom()</v>
@@ -348,7 +348,7 @@
</func>
<func>
- <name>ipb() -> ok</name>
+ <name since="">ipb() -> ok</name>
<fsummary>Print all existing breakpoints.</fsummary>
<desc>
<p>Prints all existing breakpoints.</p>
@@ -356,7 +356,7 @@
</func>
<func>
- <name>ipb(Module) -> ok</name>
+ <name since="">ipb(Module) -> ok</name>
<fsummary>Print all existing breakpoints in a module.</fsummary>
<type>
<v>Module = atom()</v>
@@ -367,7 +367,7 @@
</func>
<func>
- <name>iv() -> atom()</name>
+ <name since="">iv() -> atom()</name>
<fsummary>Return the current version number of the interpreter.
</fsummary>
<desc>
@@ -377,7 +377,7 @@
</func>
<func>
- <name>help() -> ok</name>
+ <name since="">help() -> ok</name>
<fsummary>Print help text.</fsummary>
<desc>
<p>Prints help text.</p>
diff --git a/lib/debugger/doc/src/int.xml b/lib/debugger/doc/src/int.xml
index 31e9dfe923..a0078714e6 100644
--- a/lib/debugger/doc/src/int.xml
+++ b/lib/debugger/doc/src/int.xml
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>int</module>
+ <module since="">int</module>
<modulesummary>Interpreter Interface.</modulesummary>
<description>
<p>The Erlang interpreter provides mechanisms for breakpoints and
@@ -94,10 +94,10 @@
<funcs>
<func>
- <name>i(AbsModule) -> {module,Module} | error</name>
- <name>i(AbsModules) -> ok</name>
- <name>ni(AbsModule) -> {module,Module} | error</name>
- <name>ni(AbsModules) -> ok</name>
+ <name since="">i(AbsModule) -> {module,Module} | error</name>
+ <name since="">i(AbsModules) -> ok</name>
+ <name since="">ni(AbsModule) -> {module,Module} | error</name>
+ <name since="">ni(AbsModules) -> ok</name>
<fsummary>Interpret a module.</fsummary>
<type>
<v>AbsModules = [AbsModule]</v>
@@ -144,8 +144,8 @@
</func>
<func>
- <name>n(AbsModule) -> ok</name>
- <name>nn(AbsModule) -> ok</name>
+ <name since="">n(AbsModule) -> ok</name>
+ <name since="">nn(AbsModule) -> ok</name>
<fsummary>Stop interpreting a module.</fsummary>
<type>
<v>AbsModule = Module | File | [Module | File]</v>
@@ -163,7 +163,7 @@
</func>
<func>
- <name>interpreted() -> [Module]</name>
+ <name since="">interpreted() -> [Module]</name>
<fsummary>Get all interpreted modules.</fsummary>
<type>
<v>Module = atom()</v>
@@ -174,7 +174,7 @@
</func>
<func>
- <name>file(Module) -> File | {error,not_loaded}</name>
+ <name since="">file(Module) -> File | {error,not_loaded}</name>
<fsummary>Get the filename for an interpreted module.</fsummary>
<type>
<v>Module = atom()</v>
@@ -187,7 +187,7 @@
</func>
<func>
- <name>interpretable(AbsModule) -> true | {error,Reason}</name>
+ <name since="">interpretable(AbsModule) -> true | {error,Reason}</name>
<fsummary>Check if a module can be interpreted.</fsummary>
<type>
<v>AbsModule = Module | File</v>
@@ -255,9 +255,9 @@
</func>
<func>
- <name>auto_attach() -> false | {Flags,Function}</name>
- <name>auto_attach(false)</name>
- <name>auto_attach(Flags, Function)</name>
+ <name since="">auto_attach() -> false | {Flags,Function}</name>
+ <name since="">auto_attach(false)</name>
+ <name since="">auto_attach(Flags, Function)</name>
<fsummary>Get and set when and how to attach to a process.</fsummary>
<type>
<v>Flags = [init | break | exit]</v>
@@ -290,8 +290,8 @@ spawn(Module, Name, [Pid | Args])</pre>
</func>
<func>
- <name>stack_trace() -> Flag</name>
- <name>stack_trace(Flag)</name>
+ <name since="">stack_trace() -> Flag</name>
+ <name since="">stack_trace(Flag)</name>
<fsummary>Get and set if and how to save call frames.</fsummary>
<type>
<v>Flag = all | no_tail | false</v>
@@ -322,7 +322,7 @@ spawn(Module, Name, [Pid | Args])</pre>
</func>
<func>
- <name>break(Module, Line) -> ok | {error,break_exists}</name>
+ <name since="">break(Module, Line) -> ok | {error,break_exists}</name>
<fsummary>Create a breakpoint.</fsummary>
<type>
<v>Module = atom()</v>
@@ -334,7 +334,7 @@ spawn(Module, Name, [Pid | Args])</pre>
</func>
<func>
- <name>delete_break(Module, Line) -> ok</name>
+ <name since="">delete_break(Module, Line) -> ok</name>
<fsummary>Delete a breakpoint.</fsummary>
<type>
<v>Module = atom()</v>
@@ -346,7 +346,7 @@ spawn(Module, Name, [Pid | Args])</pre>
</func>
<func>
- <name>break_in(Module, Name, Arity) -> ok
+ <name since="">break_in(Module, Name, Arity) -> ok
| {error,function_not_found}</name>
<fsummary>Create breakpoints in the specified function.</fsummary>
<type>
@@ -360,7 +360,7 @@ spawn(Module, Name, [Pid | Args])</pre>
</func>
<func>
- <name>del_break_in(Module, Name, Arity) -> ok
+ <name since="">del_break_in(Module, Name, Arity) -> ok
| {error,function_not_found}</name>
<fsummary>Delete breakpoints from the specified function.</fsummary>
<type>
@@ -374,8 +374,8 @@ spawn(Module, Name, [Pid | Args])</pre>
</func>
<func>
- <name>no_break() -> ok</name>
- <name>no_break(Module) -> ok</name>
+ <name since="">no_break() -> ok</name>
+ <name since="">no_break(Module) -> ok</name>
<fsummary>Delete all breakpoints.</fsummary>
<desc>
<p>Deletes all breakpoints, or all breakpoints in <c>Module</c>.</p>
@@ -383,7 +383,7 @@ spawn(Module, Name, [Pid | Args])</pre>
</func>
<func>
- <name>disable_break(Module, Line) -> ok</name>
+ <name since="">disable_break(Module, Line) -> ok</name>
<fsummary>Make a breakpoint inactive.</fsummary>
<type>
<v>Module = atom()</v>
@@ -395,7 +395,7 @@ spawn(Module, Name, [Pid | Args])</pre>
</func>
<func>
- <name>enable_break(Module, Line) -> ok</name>
+ <name since="">enable_break(Module, Line) -> ok</name>
<fsummary>Make a breakpoint active.</fsummary>
<type>
<v>Module = atom()</v>
@@ -407,7 +407,7 @@ spawn(Module, Name, [Pid | Args])</pre>
</func>
<func>
- <name>action_at_break(Module, Line, Action) -> ok</name>
+ <name since="">action_at_break(Module, Line, Action) -> ok</name>
<fsummary>Set the trigger action of a breakpoint.</fsummary>
<type>
<v>Module = atom()</v>
@@ -421,7 +421,7 @@ spawn(Module, Name, [Pid | Args])</pre>
</func>
<func>
- <name>test_at_break(Module, Line, Function) -> ok</name>
+ <name since="">test_at_break(Module, Line, Function) -> ok</name>
<fsummary>Set the conditional test of a breakpoint.</fsummary>
<type>
<v>Module = atom()</v>
@@ -438,7 +438,7 @@ spawn(Module, Name, [Pid | Args])</pre>
</func>
<func>
- <name>get_binding(Var, Bindings) -> {value,Value} | unbound</name>
+ <name since="">get_binding(Var, Bindings) -> {value,Value} | unbound</name>
<fsummary>Retrieve a variable binding.</fsummary>
<type>
<v>Var = atom()</v>
@@ -453,8 +453,8 @@ spawn(Module, Name, [Pid | Args])</pre>
</func>
<func>
- <name>all_breaks() -> [Break]</name>
- <name>all_breaks(Module) -> [Break]</name>
+ <name since="">all_breaks() -> [Break]</name>
+ <name since="">all_breaks(Module) -> [Break]</name>
<fsummary>Get all breakpoints.</fsummary>
<type>
<v>Break = {Point,Options}</v>
@@ -474,7 +474,7 @@ spawn(Module, Name, [Pid | Args])</pre>
</func>
<func>
- <name>snapshot() -> [Snapshot]</name>
+ <name since="">snapshot() -> [Snapshot]</name>
<fsummary>Get information about all processes executing interpreted
code.</fsummary>
<type>
@@ -519,7 +519,7 @@ spawn(Module, Name, [Pid | Args])</pre>
</func>
<func>
- <name>clear() -> ok</name>
+ <name since="">clear() -> ok</name>
<fsummary>Clear information about processes executing interpreted
code.</fsummary>
<desc>
@@ -529,8 +529,8 @@ spawn(Module, Name, [Pid | Args])</pre>
</func>
<func>
- <name>continue(Pid) -> ok | {error,not_interpreted}</name>
- <name>continue(X,Y,Z) -> ok | {error,not_interpreted}</name>
+ <name since="">continue(Pid) -> ok | {error,not_interpreted}</name>
+ <name since="">continue(X,Y,Z) -> ok | {error,not_interpreted}</name>
<fsummary>Resume process execution.</fsummary>
<type>
<v>Pid = pid()</v>
diff --git a/lib/debugger/doc/src/notes.xml b/lib/debugger/doc/src/notes.xml
index e71746e30d..795b46d467 100644
--- a/lib/debugger/doc/src/notes.xml
+++ b/lib/debugger/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -33,6 +33,53 @@
<p>This document describes the changes made to the Debugger
application.</p>
+<section><title>Debugger 4.2.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ All incorrect (that is, all) uses of "can not" has been
+ corrected to "cannot" in source code comments,
+ documentation, examples, and so on.</p>
+ <p>
+ Own Id: OTP-14282 Aux Id: PR-1891 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Debugger 4.2.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Debugger 4.2.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Fix a bug where calling a fun inside a binary would
+ crash the Debugger. </p>
+ <p>
+ Own Id: OTP-14957 Aux Id: PR-1741 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Debugger 4.2.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/debugger/src/dbg_debugged.erl b/lib/debugger/src/dbg_debugged.erl
index e142af4ae0..5296b8d892 100644
--- a/lib/debugger/src/dbg_debugged.erl
+++ b/lib/debugger/src/dbg_debugged.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -31,32 +31,25 @@
%% Called via the error handler.
%%--------------------------------------------------------------------
eval(Mod, Func, Args) ->
- SaveStacktrace = erlang:get_stacktrace(),
Meta = dbg_ieval:eval(Mod, Func, Args),
Mref = erlang:monitor(process, Meta),
- msg_loop(Meta, Mref, SaveStacktrace).
+ msg_loop(Meta, Mref).
%%====================================================================
%% Internal functions
%%====================================================================
-msg_loop(Meta, Mref, SaveStacktrace) ->
+msg_loop(Meta, Mref) ->
receive
%% Evaluated function has returned a value
{sys, Meta, {ready, Val}} ->
erlang:demonitor(Mref, [flush]),
-
- %% Restore original stacktrace and return the value
- try erlang:raise(throw, stack, SaveStacktrace)
- catch
- throw:stack ->
- case Val of
- {dbg_apply,M,F,A} ->
- apply(M, F, A);
- _ ->
- Val
- end
+ case Val of
+ {dbg_apply,M,F,A} ->
+ apply(M, F, A);
+ _ ->
+ Val
end;
%% Evaluated function raised an (uncaught) exception
@@ -74,32 +67,25 @@ msg_loop(Meta, Mref, SaveStacktrace) ->
Meta ! {self(), rec_acked},
ok
end,
- msg_loop(Meta, Mref, SaveStacktrace);
+ msg_loop(Meta, Mref);
%% Meta needs something evaluated within context of real process
{sys, Meta, {command,Command}} ->
Reply = handle_command(Command),
Meta ! {sys, self(), Reply},
- msg_loop(Meta, Mref, SaveStacktrace);
+ msg_loop(Meta, Mref);
%% Meta has terminated
%% Must be due to int:stop() (or -heaven forbid- a debugger bug)
{'DOWN', Mref, _, _, Reason} ->
-
- %% Restore original stacktrace and return a dummy value
- try erlang:raise(throw, stack, SaveStacktrace)
- catch
- throw:stack ->
- {interpreter_terminated, Reason}
- end
+ {interpreter_terminated, Reason}
end.
handle_command(Command) ->
try
reply(Command)
- catch Class:Reason ->
- Stacktrace = stacktrace_f(erlang:get_stacktrace()),
- {exception,{Class,Reason,Stacktrace}}
+ catch Class:Reason:Stacktrace ->
+ {exception,{Class,Reason,stacktrace_f(Stacktrace)}}
end.
reply({apply,M,F,As}) ->
diff --git a/lib/debugger/src/dbg_icmd.erl b/lib/debugger/src/dbg_icmd.erl
index 4cd3dce670..0eb258567f 100644
--- a/lib/debugger/src/dbg_icmd.erl
+++ b/lib/debugger/src/dbg_icmd.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -248,7 +248,7 @@ handle_int_msg({attached, AttPid}, Status, _Bs,
tell_attached({attached, M, Line, get(trace)}),
%% Give info about status and call level as well
- %% In this case, Status can not be exit_at
+ %% In this case, Status cannot be exit_at
Msg = case Status of
idle -> {func_at,M,Line,Le};
break -> {break_at,M,Line,Le};
@@ -467,7 +467,7 @@ mark_break(Cm, LineNo, Le) ->
parse_cmd(Cmd, LineNo) ->
{ok,Tokens,_} = erl_scan:string(Cmd, LineNo, [text]),
- {ok,Forms,Bs} = lib:extended_parse_exprs(Tokens),
+ {ok,Forms,Bs} = erl_eval:extended_parse_exprs(Tokens),
{Forms, Bs}.
%%====================================================================
diff --git a/lib/debugger/src/dbg_ieval.erl b/lib/debugger/src/dbg_ieval.erl
index 8009d62629..b6703d5d9e 100644
--- a/lib/debugger/src/dbg_ieval.erl
+++ b/lib/debugger/src/dbg_ieval.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -924,8 +924,7 @@ expr({dbg,Line,raise,As0}, Bs0, #ieval{level=Le}=Ieval0) ->
trace(return, {Le,Error}),
{value,Error,Bs}
catch
- _:_ ->
- Stk = erlang:get_stacktrace(), %Possibly truncated.
+ _:_:Stk -> %Possibly truncated.
StkFun = fun(_) -> Stk end,
do_exception(Class, Reason, StkFun, Bs, Ieval)
end;
@@ -1034,7 +1033,7 @@ expr({send,Line,To0,Msg0}, Bs0, Ieval0) ->
%% Binary
expr({bin,Line,Fs}, Bs0, Ieval0) ->
- Ieval = Ieval0#ieval{line=Line},
+ Ieval = Ieval0#ieval{line=Line,top=false},
try
eval_bits:expr_grp(Fs, Bs0,
fun (E, B) -> expr(E, B, Ieval) end,
diff --git a/lib/debugger/src/dbg_wx_mon.erl b/lib/debugger/src/dbg_wx_mon.erl
index a32a6894b8..08b20d3f69 100644
--- a/lib/debugger/src/dbg_wx_mon.erl
+++ b/lib/debugger/src/dbg_wx_mon.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -119,9 +119,9 @@ init(CallingPid, Mode, SFile) ->
init2(CallingPid, Mode, SFile, GS)
catch
exit:stop -> stop;
- Error:Reason ->
+ Error:Reason:Stacktrace ->
io:format("~p: Crashed {~p,~p} in~n ~p",
- [?MODULE, Error, Reason, erlang:get_stacktrace()])
+ [?MODULE, Error, Reason, Stacktrace])
end
end.
diff --git a/lib/debugger/src/dbg_wx_trace.erl b/lib/debugger/src/dbg_wx_trace.erl
index b1e0e03b4c..25f32ca7e7 100644
--- a/lib/debugger/src/dbg_wx_trace.erl
+++ b/lib/debugger/src/dbg_wx_trace.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -95,9 +95,9 @@ start(Pid, Env, Parent, TraceWin, BackTrace, Strings) ->
catch
_:stop ->
exit(stop);
- E:R ->
+ E:R:S ->
io:format("TraceWin Crashed ~p~n",[E]),
- io:format(" ~p in ~p~n",[R, erlang:get_stacktrace()]),
+ io:format(" ~p in ~p~n",[R, S]),
exit(R)
end;
error ->
@@ -518,8 +518,8 @@ gui_cmd({user_command, Cmd}, State) ->
gui_cmd({edit, {Var, Value}}, State) ->
Window = dbg_wx_trace_win:get_window(State#state.win),
Val = case State#state.strings of
- [] -> dbg_wx_win:to_string("~999999lp",[Value]);
- [str_on] -> dbg_wx_win:to_string("~999999tp",[Value])
+ [] -> dbg_wx_win:to_string("~0lp",[Value]);
+ [str_on] -> dbg_wx_win:to_string("~0tp",[Value])
end,
case dbg_wx_win:entry(Window, "Edit variable", Var, {term, Val}) of
cancel ->
diff --git a/lib/debugger/src/dbg_wx_win.erl b/lib/debugger/src/dbg_wx_win.erl
index f1298154ab..4391ad1598 100644
--- a/lib/debugger/src/dbg_wx_win.erl
+++ b/lib/debugger/src/dbg_wx_win.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -275,7 +275,7 @@ entry(Parent, Title, Prompt, {Type, Value}) ->
verify(Type, Str) ->
case erl_scan:string(Str, 1, [text]) of
{ok, Tokens, _EndLine} when Type==term ->
- case lib:extended_parse_term(Tokens++[{dot, erl_anno:new(1)}]) of
+ case erl_eval:extended_parse_term(Tokens++[{dot, erl_anno:new(1)}]) of
{ok, Value} -> {edit, Value};
_Error ->
ignore
diff --git a/lib/debugger/src/debugger.app.src b/lib/debugger/src/debugger.app.src
index 37a41c1a56..c8a8b0fd43 100644
--- a/lib/debugger/src/debugger.app.src
+++ b/lib/debugger/src/debugger.app.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/debugger/src/i.erl b/lib/debugger/src/i.erl
index 62ce8d0e20..853fa529a0 100644
--- a/lib/debugger/src/i.erl
+++ b/lib/debugger/src/i.erl
@@ -30,7 +30,7 @@
-import(lists, [sort/1,foreach/2]).
iv() ->
- Vsn = string:substr(filename:basename(code:lib_dir(debugger)), 10),
+ Vsn = string:slice(filename:basename(code:lib_dir(debugger)), 9),
list_to_atom(Vsn).
%% -------------------------------------------
diff --git a/lib/debugger/test/guard_SUITE.erl b/lib/debugger/test/guard_SUITE.erl
index f7874f79df..02a1bbd66b 100644
--- a/lib/debugger/test/guard_SUITE.erl
+++ b/lib/debugger/test/guard_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -390,7 +390,7 @@ all_types() ->
{atom, xxxx},
{ref, make_ref()},
{pid, self()},
- {port, open_port({spawn, efile}, [])},
+ {port, make_port()},
{function, fun(X) -> X+1, "" end},
{binary, list_to_binary([])}].
@@ -435,6 +435,9 @@ type_test(binary, X) when binary(X) ->
type_test(function, X) when function(X) ->
function.
+make_port() ->
+ hd(erlang:ports()).
+
const_guard(Config) when is_list(Config) ->
if
(0 == 0) and ((0 == 0) or (0 == 0)) ->
diff --git a/lib/debugger/test/int_eval_SUITE.erl b/lib/debugger/test/int_eval_SUITE.erl
index 27ca4852b5..324a44bad8 100644
--- a/lib/debugger/test/int_eval_SUITE.erl
+++ b/lib/debugger/test/int_eval_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,7 +29,8 @@
bifs_outside_erlang/1, spawning/1, applying/1,
catch_and_throw/1, external_call/1, test_module_info/1,
apply_interpreted_fun/1, apply_uninterpreted_fun/1,
- interpreted_exit/1, otp_8310/1, stacktrace/1, maps/1]).
+ interpreted_exit/1, otp_8310/1, stacktrace/1, maps/1,
+ call_inside_binary/1]).
%% Helpers.
-export([applier/3]).
@@ -45,7 +46,8 @@ all() ->
[bifs_outside_erlang, spawning, applying,
catch_and_throw, external_call, test_module_info,
apply_interpreted_fun, apply_uninterpreted_fun,
- interpreted_exit, otp_8310, stacktrace, maps].
+ interpreted_exit, otp_8310, stacktrace, maps,
+ call_inside_binary].
groups() ->
[].
@@ -275,12 +277,18 @@ maps(Config) when is_list(Config) ->
[#{hello := 0, price := 0}] = spawn_eval(fun () -> ?IM:update_in_fun() end),
ok.
+call_inside_binary(Config) when is_list(Config) ->
+ <<"1">> = ?IM:call_inside_binary(fun erlang:integer_to_binary/1),
+ ok.
do_eval(Config, Mod) ->
DataDir = proplists:get_value(data_dir, Config),
ok = file:set_cwd(DataDir),
- {ok,Mod} = compile:file(Mod, [report,debug_info]),
+ %% Turn off type-based optimizations across function calls, as it
+ %% would turn many body-recursive calls into tail-recursive calls,
+ %% which would change the stacktrace.
+ {ok,Mod} = compile:file(Mod, [no_module_opt,report,debug_info]),
{module,Mod} = code:load_file(Mod),
CompiledRes = Mod:Mod(),
ok = io:format("Compiled:\n~p", [CompiledRes]),
diff --git a/lib/debugger/test/int_eval_SUITE_data/my_int_eval_module.erl b/lib/debugger/test/int_eval_SUITE_data/my_int_eval_module.erl
index ca7929c10b..aa26a44686 100644
--- a/lib/debugger/test/int_eval_SUITE_data/my_int_eval_module.erl
+++ b/lib/debugger/test/int_eval_SUITE_data/my_int_eval_module.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@
-export([f/1, f_try/1, f_catch/1]).
-export([otp_5837/1, otp_8310/0]).
-export([empty_map_update/1, update_in_fun/0]).
+-export([call_inside_binary/1]).
%% Internal exports.
-export([echo/2,my_subtract/2,catch_a_ball/0,throw_a_ball/0]).
@@ -248,3 +249,6 @@ empty_map_update(Map) -> Map#{}.
update_in_fun() ->
lists:map(fun (X) -> X#{price := 0} end, [#{hello => 0, price => nil}]).
+
+call_inside_binary(Fun) ->
+ <<(Fun(1))/binary>>.
diff --git a/lib/debugger/vsn.mk b/lib/debugger/vsn.mk
index 57da7e5618..daecc7594c 100644
--- a/lib/debugger/vsn.mk
+++ b/lib/debugger/vsn.mk
@@ -1 +1 @@
-DEBUGGER_VSN = 4.2.4
+DEBUGGER_VSN = 4.2.7
diff --git a/lib/dialyzer/doc/src/Makefile b/lib/dialyzer/doc/src/Makefile
index 3463b589e6..3ce777392b 100644
--- a/lib/dialyzer/doc/src/Makefile
+++ b/lib/dialyzer/doc/src/Makefile
@@ -91,6 +91,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/lib/dialyzer/doc/src/dialyzer.xml b/lib/dialyzer/doc/src/dialyzer.xml
index e34ffd6def..443de7b0dd 100644
--- a/lib/dialyzer/doc/src/dialyzer.xml
+++ b/lib/dialyzer/doc/src/dialyzer.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2006</year><year>2017</year>
+ <year>2006</year><year>2019</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -29,7 +29,7 @@
<rev></rev>
<file>dialyzer.xml</file>
</header>
- <module>dialyzer</module>
+ <module since="">dialyzer</module>
<modulesummary>Dialyzer, a DIscrepancy AnaLYZer for ERlang programs.
</modulesummary>
<description>
@@ -85,7 +85,7 @@ dialyzer --help</code>
dialyzer [--add_to_plt] [--apps applications] [--build_plt]
[--check_plt] [-Ddefine]* [-Dname] [--dump_callgraph file]
[files_or_dirs] [--fullpath] [--get_warnings] [--gui] [--help]
- [-I include_dir]* [--no_check_plt] [--no_native]
+ [-I include_dir]* [--no_check_plt] [--no_indentation] [--no_native]
[--no_native_cache] [-o outfile] [--output_plt file] [-pa dir]*
[--plt plt] [--plt_info] [--plts plt*] [--quiet] [-r dirs]
[--raw] [--remove_from_plt] [--shell] [--src] [--statistics]
@@ -181,6 +181,11 @@ dialyzer --apps inets ssl ./ebin ../other_lib/ebin/my_module.beam</code>
<p>Skip the PLT check when running Dialyzer. This is useful when
working with installed PLTs that never change.</p>
</item>
+ <tag><c>--no_indentation</c></tag>
+ <item>
+ <p>Do not insert line breaks in types, contracts, and Erlang
+ Code when formatting warnings.</p>
+ </item>
<tag><c>--no_native</c> (or <c>-nn</c>)</tag>
<item>
<p>Bypass the native code compilation of some key files that
@@ -472,21 +477,38 @@ dialyzer --plts plt_1 ... plt_n -- files_to_analyze</code>
<funcs>
<func>
- <name>format_warning(Msg) -> string()</name>
+ <name since="">format_warning(Msg) -> string()</name>
+ <fsummary>Get the string version of a warning message.</fsummary>
+ <type>
+ <v>Msg = {Tag, Id, msg()}</v>
+ <d>See <c>run/1</c>.</d>
+ </type>
+ <desc>
+ <p>Get a string from warnings as returned by
+ <seealso marker="#run/1"><c>run/1</c></seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">format_warning(Msg, Options) -> string()</name>
<fsummary>Get the string version of a warning message.</fsummary>
<type>
<v>Msg = {Tag, Id, msg()}</v>
<d>See <c>run/1</c>.</d>
+ <v>Options = [{indent_opt, boolean()}]</v>
</type>
<desc>
<p>Get a string from warnings as returned by
<seealso marker="#run/1"><c>run/1</c></seealso>.</p>
+ <p>If <c>indent_opt</c> is set to <c>true</c> (default),
+ line breaks are inserted in types, contracts, and Erlang
+ code to improve readability.</p>
</desc>
</func>
<func>
- <name>gui() -> ok | {error, Msg}</name>
- <name>gui(OptList) -> ok | {error, Msg}</name>
+ <name since="">gui() -> ok | {error, Msg}</name>
+ <name since="">gui(OptList) -> ok | {error, Msg}</name>
<fsummary>Dialyzer GUI version.</fsummary>
<type>
<v>OptList</v>
@@ -539,7 +561,7 @@ WarnOpts :: error_handling
</func>
<func>
- <name>plt_info(string()) -> {'ok', [{atom(), any()}]} | {'error', atom()}</name>
+ <name since="">plt_info(string()) -> {'ok', [{atom(), any()}]} | {'error', atom()}</name>
<fsummary>Return information about the specified PLT.</fsummary>
<desc>
<p>Returns information about the specified PLT.</p>
@@ -547,7 +569,7 @@ WarnOpts :: error_handling
</func>
<func>
- <name>run(OptList) -> Warnings</name>
+ <name since="">run(OptList) -> Warnings</name>
<fsummary>Dialyzer command-line version.</fsummary>
<type>
<v>OptList</v>
diff --git a/lib/dialyzer/doc/src/notes.xml b/lib/dialyzer/doc/src/notes.xml
index 8d11252bff..dd0a2bfd7d 100644
--- a/lib/dialyzer/doc/src/notes.xml
+++ b/lib/dialyzer/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2006</year><year>2017</year>
+ <year>2006</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,6 +32,151 @@
<p>This document describes the changes made to the Dialyzer
application.</p>
+<section><title>Dialyzer 4.0</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ All incorrect (that is, all) uses of "can not" has been
+ corrected to "cannot" in source code comments,
+ documentation, examples, and so on.</p>
+ <p>
+ Own Id: OTP-14282 Aux Id: PR-1891 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> By default Dialyzer inserts line breaks in types,
+ contracts, and Erlang Code when formatting results. Use
+ the new <c>--no_indentation</c> option to get the old
+ behavior of not inserting line breaks. </p>
+ <p>
+ Own Id: OTP-15135</p>
+ </item>
+ <item>
+ <p> Use bit syntax in warnings instead of Core Erlang
+ syntax, for readability. </p>
+ <p>
+ Own Id: OTP-15752</p>
+ </item>
+ <item>
+ <p> The format of the raw analysis result tagged with
+ <c>fun_app_args</c> is changed to <c>{fun_app_args,
+ [ArgNs, Args, Type]}</c>. </p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15779</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Dialyzer 3.3.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Fix a bug that caused Dialyzer to crash when
+ analyzing a contract with a module name differing from
+ the analyzed module's name. The bug was introduced in
+ Erlang/OTP 18. </p>
+ <p>
+ Own Id: OTP-15562 Aux Id: ERL-845 </p>
+ </item>
+ <item>
+ <p> Fix a bug in the handling of the <c>Key</c> argument
+ of <c>lists:{keysearch, keyfind, keymember}</c>. </p>
+ <p>
+ Own Id: OTP-15570</p>
+ </item>
+ <item>
+ <p>Optimize (again) Dialyzer's handling of
+ left-associative use of <c>andalso</c> and <c>orelse</c>
+ in guards.</p>
+ <p>
+ Own Id: OTP-15577 Aux Id: ERL-851, PR-2141, PR-1944 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Dialyzer 3.3.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> Optimize Dialyzer's handling of left-associative use
+ of <c>andalso</c> and <c>orelse</c> in guards. </p>
+ <p>
+ Own Id: OTP-15268 Aux Id: ERL-680 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Dialyzer 3.3</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>Changed the default behaviour of <c>.erlang</c>
+ loading: <c>.erlang</c> is no longer loaded from the
+ current directory. <c>c:erlangrc(PathList)</c> can be
+ used to search and load an <c>.erlang</c> file from user
+ specified directories.</p> <p><c>escript</c>,
+ <c>erlc</c>, <c>dialyzer</c> and <c>typer</c> no longer
+ load an <c>.erlang</c> at all.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14439</p>
+ </item>
+ <item>
+ <p> Dialyzer can no longer read BEAM files created with
+ OTP 19 or earlier. </p>
+ <p>
+ Own Id: OTP-14493 Aux Id: PR-1434 </p>
+ </item>
+ <item>
+ <p> Speed up the computation of MD5 sums. </p>
+ <p>
+ Own Id: OTP-14937 Aux Id: PR-1719 </p>
+ </item>
+ <item>
+ <p> Fix a situation where Dialyzer unnecessarily
+ discarded contract information, resulting in missed
+ warnings. </p>
+ <p>
+ Own Id: OTP-14970 Aux Id: PR-1722 </p>
+ </item>
+ <item>
+ <p> The (not recommended) option <c>-Woverspecs</c> is
+ somewhat refined, and generates warnings in a few more
+ cases. </p>
+ <p>
+ Own Id: OTP-14982 Aux Id: OTP-14970, PR-1722 </p>
+ </item>
+ <item>
+ <p> Do not emit warnings for fun expressions residing in
+ code that cannot be run. This is consistent with how
+ Dialyzer treats other code that cannot be run. </p>
+ <p>
+ Own Id: OTP-15079 Aux Id: ERL-593 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Dialyzer 3.2.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/dialyzer/src/Makefile b/lib/dialyzer/src/Makefile
index fc08e7ca2f..bddd761705 100644
--- a/lib/dialyzer/src/Makefile
+++ b/lib/dialyzer/src/Makefile
@@ -90,8 +90,10 @@ APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
ifeq ($(NATIVE_LIBS_ENABLED),yes)
ERL_COMPILE_FLAGS += +native
+else
+ERL_COMPILE_FLAGS += -Werror
endif
-ERL_COMPILE_FLAGS += +warn_export_vars +warn_unused_import +warn_untyped_record +warn_missing_spec +warnings_as_errors
+ERL_COMPILE_FLAGS += +warn_export_vars +warn_unused_import +warn_untyped_record +warn_missing_spec
# ----------------------------------------------------
# Targets
diff --git a/lib/dialyzer/src/dialyzer.erl b/lib/dialyzer/src/dialyzer.erl
index 1538174d4a..cfe5fa9b3f 100644
--- a/lib/dialyzer/src/dialyzer.erl
+++ b/lib/dialyzer/src/dialyzer.erl
@@ -280,20 +280,23 @@ cl_check_log(Output) ->
format_warning(W) ->
format_warning(W, basename).
--spec format_warning(raw_warning() | dial_warning(), fopt()) -> string().
-
-format_warning({Tag, {File, Line, _MFA}, Msg}, FOpt) ->
- format_warning({Tag, {File, Line}, Msg}, FOpt);
-format_warning({_Tag, {File, Line}, Msg}, FOpt) when is_list(File),
+-spec format_warning(raw_warning() | dial_warning(),
+ fopt() | proplists:proplist()) -> string().
+
+format_warning(RawWarning, FOpt) when is_atom(FOpt) ->
+ format_warning(RawWarning, [{filename_opt, FOpt}]);
+format_warning({Tag, {File, Line, _MFA}, Msg}, Opts) ->
+ format_warning({Tag, {File, Line}, Msg}, Opts);
+format_warning({_Tag, {File, Line}, Msg}, Opts) when is_list(File),
is_integer(Line) ->
- F = case FOpt of
+ F = case proplists:get_value(filename_opt, Opts, basename) of
fullpath -> File;
basename -> filename:basename(File)
end,
- String = lists:flatten(message_to_string(Msg)),
+ Indent = proplists:get_value(indent_opt, Opts, ?INDENT_OPT),
+ String = message_to_string(Msg, Indent),
lists:flatten(io_lib:format("~ts:~w: ~ts", [F, Line, String])).
-
%%-----------------------------------------------------------------------------
%% Message classification and pretty-printing below. Messages appear in
%% categories and in more or less alphabetical ordering within each category.
@@ -301,52 +304,60 @@ format_warning({_Tag, {File, Line}, Msg}, FOpt) when is_list(File),
%%----- Warnings for general discrepancies ----------------
message_to_string({apply, [Args, ArgNs, FailReason,
- SigArgs, SigRet, Contract]}) ->
- io_lib:format("Fun application with arguments ~ts ", [Args]) ++
- call_or_apply_to_string(ArgNs, FailReason, SigArgs, SigRet, Contract);
-message_to_string({app_call, [M, F, Args, Culprit, ExpectedType, FoundType]}) ->
+ SigArgs, SigRet, Contract]}, I) ->
+ io_lib:format("Fun application with arguments ~ts ", [a(Args, I)]) ++
+ call_or_apply_to_string(ArgNs, FailReason, SigArgs, SigRet, Contract, I);
+message_to_string({app_call, [M, F, Args, Culprit, ExpectedType, FoundType]},
+ I) ->
io_lib:format("The call ~s:~ts~ts requires that ~ts is of type ~ts not ~ts\n",
- [M, F, Args, Culprit, ExpectedType, FoundType]);
-message_to_string({bin_construction, [Culprit, Size, Seg, Type]}) ->
+ [M, F, a(Args, I), c(Culprit, I),
+ t(ExpectedType, I), t(FoundType, I)]);
+message_to_string({bin_construction, [Culprit, Size, Seg, Type]}, I) ->
io_lib:format("Binary construction will fail since the ~s field ~s in"
- " segment ~s has type ~s\n", [Culprit, Size, Seg, Type]);
+ " segment ~s has type ~s\n",
+ [Culprit, c(Size, I), c(Seg, I), t(Type, I)]);
message_to_string({call, [M, F, Args, ArgNs, FailReason,
- SigArgs, SigRet, Contract]}) ->
- io_lib:format("The call ~w:~tw~ts ", [M, F, Args]) ++
- call_or_apply_to_string(ArgNs, FailReason, SigArgs, SigRet, Contract);
-message_to_string({call_to_missing, [M, F, A]}) ->
+ SigArgs, SigRet, Contract]}, I) ->
+ io_lib:format("The call ~w:~tw~ts ", [M, F, a(Args, I)]) ++
+ call_or_apply_to_string(ArgNs, FailReason, SigArgs, SigRet, Contract, I);
+message_to_string({call_to_missing, [M, F, A]}, _I) ->
io_lib:format("Call to missing or unexported function ~w:~tw/~w\n",
[M, F, A]);
-message_to_string({exact_eq, [Type1, Op, Type2]}) ->
+message_to_string({exact_eq, [Type1, Op, Type2]}, I) ->
io_lib:format("The test ~ts ~s ~ts can never evaluate to 'true'\n",
- [Type1, Op, Type2]);
-message_to_string({fun_app_args, [Args, Type]}) ->
+ [t(Type1, I), Op, t(Type2, I)]);
+message_to_string({fun_app_args, [ArgNs, Args, Type]}, I) ->
+ PositionString = form_position_string(ArgNs),
io_lib:format("Fun application with arguments ~ts will fail"
- " since the function has type ~ts\n", [Args, Type]);
-message_to_string({fun_app_no_fun, [Op, Type, Arity]}) ->
+ " since the function has type ~ts,"
+ " which differs in the ~s argument\n",
+ [a(Args, I), t(Type, I), PositionString]);
+message_to_string({fun_app_no_fun, [Op, Type, Arity]}, I) ->
io_lib:format("Fun application will fail since ~ts :: ~ts"
- " is not a function of arity ~w\n", [Op, Type, Arity]);
-message_to_string({guard_fail, []}) ->
+ " is not a function of arity ~w\n", [Op, t(Type, I), Arity]);
+message_to_string({guard_fail, []}, _I) ->
"Clause guard cannot succeed.\n";
-message_to_string({guard_fail, [Arg1, Infix, Arg2]}) ->
- io_lib:format("Guard test ~ts ~s ~ts can never succeed\n", [Arg1, Infix, Arg2]);
-message_to_string({map_update, [Type, Key]}) ->
+message_to_string({guard_fail, [Arg1, Infix, Arg2]}, I) ->
+ io_lib:format("Guard test ~ts ~s ~ts can never succeed\n",
+ [a(Arg1, I), Infix, a(Arg2, I)]); % a/2 rather than c/2
+message_to_string({map_update, [Type, Key]}, I) ->
io_lib:format("A key of type ~ts cannot exist "
- "in a map of type ~ts\n", [Key, Type]);
-message_to_string({neg_guard_fail, [Arg1, Infix, Arg2]}) ->
+ "in a map of type ~ts\n", [t(Key, I), t(Type, I)]);
+message_to_string({neg_guard_fail, [Arg1, Infix, Arg2]}, I) ->
io_lib:format("Guard test not(~ts ~s ~ts) can never succeed\n",
- [Arg1, Infix, Arg2]);
-message_to_string({guard_fail, [Guard, Args]}) ->
- io_lib:format("Guard test ~w~ts can never succeed\n", [Guard, Args]);
-message_to_string({neg_guard_fail, [Guard, Args]}) ->
- io_lib:format("Guard test not(~w~ts) can never succeed\n", [Guard, Args]);
-message_to_string({guard_fail_pat, [Pat, Type]}) ->
+ [a(Arg1, I), Infix, a(Arg2, I)]); % a/2 rather than c/2
+message_to_string({guard_fail, [Guard, Args]}, I) ->
+ io_lib:format("Guard test ~s~ts can never succeed\n", [Guard, a(Args, I)]);
+message_to_string({neg_guard_fail, [Guard, Args]}, I) ->
+ io_lib:format("Guard test not(~s~ts) can never succeed\n",
+ [Guard, a(Args, I)]);
+message_to_string({guard_fail_pat, [Pat, Type]}, I) ->
io_lib:format("Clause guard cannot succeed. The ~ts was matched"
- " against the type ~ts\n", [Pat, Type]);
-message_to_string({improper_list_constr, [TlType]}) ->
+ " against the type ~ts\n", [ps(Pat, I), t(Type, I)]);
+message_to_string({improper_list_constr, [TlType]}, I) ->
io_lib:format("Cons will produce an improper list"
- " since its 2nd argument is ~ts\n", [TlType]);
-message_to_string({no_return, [Type|Name]}) ->
+ " since its 2nd argument is ~ts\n", [t(TlType, I)]);
+message_to_string({no_return, [Type|Name]}, _I) ->
NameString =
case Name of
[] -> "The created fun ";
@@ -358,131 +369,150 @@ message_to_string({no_return, [Type|Name]}) ->
only_normal -> NameString ++ "has no local return\n";
both -> NameString ++ "has no local return\n"
end;
-message_to_string({record_constr, [RecConstr, FieldDiffs]}) ->
+message_to_string({record_constr, [RecConstr, FieldDiffs]}, I) ->
io_lib:format("Record construction ~ts violates the"
- " declared type of field ~ts\n", [RecConstr, FieldDiffs]);
-message_to_string({record_constr, [Name, Field, Type]}) ->
+ " declared type of field ~ts\n",
+ [t(RecConstr, I), field_diffs(FieldDiffs, I)]);
+message_to_string({record_constr, [Name, Field, Type]}, I) ->
io_lib:format("Record construction violates the declared type for #~tw{}"
- " since ~ts cannot be of type ~ts\n", [Name, Field, Type]);
-message_to_string({record_matching, [String, Name]}) ->
+ " since ~ts cannot be of type ~ts\n",
+ [Name, ps(Field, I), t(Type, I)]);
+message_to_string({record_matching, [String, Name]}, I) ->
io_lib:format("The ~ts violates the"
- " declared type for #~tw{}\n", [String, Name]);
-message_to_string({record_match, [Pat, Type]}) ->
+ " declared type for #~tw{}\n", [rec_type(String, I), Name]);
+message_to_string({record_match, [Pat, Type]}, I) ->
io_lib:format("Matching of ~ts tagged with a record name violates"
- " the declared type of ~ts\n", [Pat, Type]);
-message_to_string({pattern_match, [Pat, Type]}) ->
- io_lib:format("The ~ts can never match the type ~ts\n", [Pat, Type]);
-message_to_string({pattern_match_cov, [Pat, Type]}) ->
+ " the declared type of ~ts\n", [ps(Pat, I), t(Type, I)]);
+message_to_string({pattern_match, [Pat, Type]}, I) ->
+ io_lib:format("The ~ts can never match the type ~ts\n",
+ [ps(Pat, I), t(Type, I)]);
+message_to_string({pattern_match_cov, [Pat, Type]}, I) ->
io_lib:format("The ~ts can never match since previous"
" clauses completely covered the type ~ts\n",
- [Pat, Type]);
-message_to_string({unmatched_return, [Type]}) ->
+ [ps(Pat, I), t(Type, I)]);
+message_to_string({unmatched_return, [Type]}, I) ->
io_lib:format("Expression produces a value of type ~ts,"
- " but this value is unmatched\n", [Type]);
-message_to_string({unused_fun, [F, A]}) ->
+ " but this value is unmatched\n", [t(Type, I)]);
+message_to_string({unused_fun, [F, A]}, _I) ->
io_lib:format("Function ~tw/~w will never be called\n", [F, A]);
%%----- Warnings for specs and contracts -------------------
-message_to_string({contract_diff, [M, F, _A, Contract, Sig]}) ->
- io_lib:format("Type specification ~w:~tw~ts"
- " is not equal to the success typing: ~w:~tw~ts\n",
- [M, F, Contract, M, F, Sig]);
-message_to_string({contract_subtype, [M, F, _A, Contract, Sig]}) ->
- io_lib:format("Type specification ~w:~tw~ts"
- " is a subtype of the success typing: ~w:~tw~ts\n",
- [M, F, Contract, M, F, Sig]);
-message_to_string({contract_supertype, [M, F, _A, Contract, Sig]}) ->
- io_lib:format("Type specification ~w:~tw~ts"
- " is a supertype of the success typing: ~w:~tw~ts\n",
- [M, F, Contract, M, F, Sig]);
-message_to_string({contract_range, [Contract, M, F, ArgStrings, Line, CRet]}) ->
- io_lib:format("The contract ~w:~tw~ts cannot be right because the inferred"
+message_to_string({contract_diff, [M, F, _A, Contract, Sig]}, I) ->
+ io_lib:format("Type specification ~ts"
+ " is not equal to the success typing: ~ts\n",
+ [con(M, F, Contract, I), con(M, F, Sig, I)]);
+message_to_string({contract_subtype, [M, F, _A, Contract, Sig]}, I) ->
+ io_lib:format("Type specification ~ts"
+ " is a subtype of the success typing: ~ts\n",
+ [con(M, F, Contract, I), con(M, F, Sig, I)]);
+message_to_string({contract_supertype, [M, F, _A, Contract, Sig]}, I) ->
+ io_lib:format("Type specification ~ts"
+ " is a supertype of the success typing: ~ts\n",
+ [con(M, F, Contract, I), con(M, F, Sig, I)]);
+message_to_string({contract_range, [Contract, M, F, ArgStrings, Line, CRet]},
+ I) ->
+ io_lib:format("The contract ~ts cannot be right because the inferred"
" return for ~tw~ts on line ~w is ~ts\n",
- [M, F, Contract, F, ArgStrings, Line, CRet]);
-message_to_string({invalid_contract, [M, F, A, Sig]}) ->
+ [con(M, F, Contract, I), F, a(ArgStrings, I), Line, t(CRet, I)]);
+message_to_string({invalid_contract, [M, F, A, Sig]}, I) ->
io_lib:format("Invalid type specification for function ~w:~tw/~w."
- " The success typing is ~ts\n", [M, F, A, Sig]);
-message_to_string({contract_with_opaque, [M, F, A, OpaqueType, SigType]}) ->
+ " The success typing is ~ts\n", [M, F, A, sig(Sig, I)]);
+message_to_string({contract_with_opaque, [M, F, A, OpaqueType, SigType]},
+ I) ->
io_lib:format("The specification for ~w:~tw/~w"
" has an opaque subtype ~ts which is violated by the"
- " success typing ~ts\n", [M, F, A, OpaqueType, SigType]);
-message_to_string({extra_range, [M, F, A, ExtraRanges, SigRange]}) ->
+ " success typing ~ts\n",
+ [M, F, A, t(OpaqueType, I), sig(SigType, I)]);
+message_to_string({extra_range, [M, F, A, ExtraRanges, SigRange]}, I) ->
io_lib:format("The specification for ~w:~tw/~w states that the function"
" might also return ~ts but the inferred return is ~ts\n",
- [M, F, A, ExtraRanges, SigRange]);
-message_to_string({overlapping_contract, [M, F, A]}) ->
+ [M, F, A, t(ExtraRanges, I), t(SigRange, I)]);
+message_to_string({missing_range, [M, F, A, ExtraRanges, ContrRange]}, I) ->
+ io_lib:format("The success typing for ~w:~tw/~w implies that the function"
+ " might also return ~ts but the specification return is ~ts\n",
+ [M, F, A, t(ExtraRanges, I), t(ContrRange, I)]);
+message_to_string({overlapping_contract, [M, F, A]}, _I) ->
io_lib:format("Overloaded contract for ~w:~tw/~w has overlapping domains;"
" such contracts are currently unsupported and are simply ignored\n",
[M, F, A]);
-message_to_string({spec_missing_fun, [M, F, A]}) ->
+message_to_string({spec_missing_fun, [M, F, A]}, _I) ->
io_lib:format("Contract for function that does not exist: ~w:~tw/~w\n",
[M, F, A]);
%%----- Warnings for opaque type violations -------------------
-message_to_string({call_with_opaque, [M, F, Args, ArgNs, ExpArgs]}) ->
+message_to_string({call_with_opaque, [M, F, Args, ArgNs, ExpArgs]}, I) ->
io_lib:format("The call ~w:~tw~ts contains ~ts when ~ts\n",
- [M, F, Args, form_positions(ArgNs), form_expected(ExpArgs)]);
-message_to_string({call_without_opaque, [M, F, Args, ExpectedTriples]}) ->
+ [M, F, a(Args, I), form_positions(ArgNs),
+ form_expected(ExpArgs, I)]);
+message_to_string({call_without_opaque, [M, F, Args, ExpectedTriples]}, I) ->
io_lib:format("The call ~w:~tw~ts does not have ~ts\n",
- [M, F, Args, form_expected_without_opaque(ExpectedTriples)]);
-message_to_string({opaque_eq, [Type, _Op, OpaqueType]}) ->
+ [M, F, a(Args, I),
+ form_expected_without_opaque(ExpectedTriples, I)]);
+message_to_string({opaque_eq, [Type, _Op, OpaqueType]}, I) ->
io_lib:format("Attempt to test for equality between a term of type ~ts"
- " and a term of opaque type ~ts\n", [Type, OpaqueType]);
-message_to_string({opaque_guard, [Arg1, Infix, Arg2, ArgNs]}) ->
+ " and a term of opaque type ~ts\n",
+ [t(Type, I), t(OpaqueType, I)]);
+message_to_string({opaque_guard, [Arg1, Infix, Arg2, ArgNs]}, I) ->
io_lib:format("Guard test ~ts ~s ~ts contains ~s\n",
- [Arg1, Infix, Arg2, form_positions(ArgNs)]);
-message_to_string({opaque_guard, [Guard, Args]}) ->
+ [a(Arg1, I), Infix, a(Arg2, I), form_positions(ArgNs)]);
+message_to_string({opaque_guard, [Guard, Args]}, I) ->
io_lib:format("Guard test ~w~ts breaks the opacity of its argument\n",
- [Guard, Args]);
-message_to_string({opaque_match, [Pat, OpaqueType, OpaqueTerm]}) ->
+ [Guard, a(Args, I)]);
+message_to_string({opaque_match, [Pat, OpaqueType, OpaqueTerm]}, I) ->
Term = if OpaqueType =:= OpaqueTerm -> "the term";
- true -> OpaqueTerm
+ true -> t(OpaqueTerm, I)
end,
- io_lib:format("The attempt to match a term of type ~s against the ~ts"
- " breaks the opacity of ~ts\n", [OpaqueType, Pat, Term]);
-message_to_string({opaque_neq, [Type, _Op, OpaqueType]}) ->
+ io_lib:format("The attempt to match a term of type ~ts against the ~ts"
+ " breaks the opacity of ~ts\n",
+ [t(OpaqueType, I), ps(Pat, I), Term]);
+message_to_string({opaque_neq, [Type, _Op, OpaqueType]}, I) ->
io_lib:format("Attempt to test for inequality between a term of type ~ts"
- " and a term of opaque type ~ts\n", [Type, OpaqueType]);
-message_to_string({opaque_type_test, [Fun, Args, Arg, ArgType]}) ->
+ " and a term of opaque type ~ts\n",
+ [t(Type, I), t(OpaqueType, I)]);
+message_to_string({opaque_type_test, [Fun, Args, Arg, ArgType]}, I) ->
io_lib:format("The type test ~ts~ts breaks the opacity of the term ~ts~ts\n",
- [Fun, Args, Arg, ArgType]);
-message_to_string({opaque_size, [SizeType, Size]}) ->
+ [Fun, a(Args, I), Arg, t(ArgType, I)]);
+message_to_string({opaque_size, [SizeType, Size]}, I) ->
io_lib:format("The size ~ts breaks the opacity of ~ts\n",
- [SizeType, Size]);
-message_to_string({opaque_call, [M, F, Args, Culprit, OpaqueType]}) ->
+ [t(SizeType, I), c(Size, I)]);
+message_to_string({opaque_call, [M, F, Args, Culprit, OpaqueType]}, I) ->
io_lib:format("The call ~s:~ts~ts breaks the opacity of the term ~ts :: ~ts\n",
- [M, F, Args, Culprit, OpaqueType]);
+ [M, F, a(Args, I), c(Culprit, I), t(OpaqueType, I)]);
%%----- Warnings for concurrency errors --------------------
-message_to_string({race_condition, [M, F, Args, Reason]}) ->
- io_lib:format("The call ~w:~tw~ts ~ts\n", [M, F, Args, Reason]);
+message_to_string({race_condition, [M, F, Args, Reason]}, I) ->
+ %% There is a possibly huge type in Reason.
+ io_lib:format("The call ~w:~tw~ts ~ts\n", [M, F, a(Args, I), Reason]);
%%----- Warnings for behaviour errors --------------------
-message_to_string({callback_type_mismatch, [B, F, A, ST, CT]}) ->
- io_lib:format("The inferred return type of ~tw/~w (~ts) has nothing in"
+message_to_string({callback_type_mismatch, [B, F, A, ST, CT]}, I) ->
+ io_lib:format("The inferred return type of ~tw/~w ~ts has nothing in"
" common with ~ts, which is the expected return type for"
- " the callback of the ~w behaviour\n", [F, A, ST, CT, B]);
-message_to_string({callback_arg_type_mismatch, [B, F, A, N, ST, CT]}) ->
+ " the callback of the ~w behaviour\n",
+ [F, A, t("("++ST++")", I), t(CT, I), B]);
+message_to_string({callback_arg_type_mismatch, [B, F, A, N, ST, CT]}, I) ->
io_lib:format("The inferred type for the ~s argument of ~tw/~w (~ts) is"
" not a supertype of ~ts, which is expected type for this"
" argument in the callback of the ~w behaviour\n",
- [ordinal(N), F, A, ST, CT, B]);
-message_to_string({callback_spec_type_mismatch, [B, F, A, ST, CT]}) ->
+ [ordinal(N), F, A, t(ST, I), t(CT, I), B]);
+message_to_string({callback_spec_type_mismatch, [B, F, A, ST, CT]}, I) ->
io_lib:format("The return type ~ts in the specification of ~tw/~w is not a"
" subtype of ~ts, which is the expected return type for the"
- " callback of the ~w behaviour\n", [ST, F, A, CT, B]);
-message_to_string({callback_spec_arg_type_mismatch, [B, F, A, N, ST, CT]}) ->
+ " callback of the ~w behaviour\n",
+ [t(ST, I), F, A, t(CT, I), B]);
+message_to_string({callback_spec_arg_type_mismatch, [B, F, A, N, ST, CT]},
+ I) ->
io_lib:format("The specified type for the ~ts argument of ~tw/~w (~ts) is"
" not a supertype of ~ts, which is expected type for this"
" argument in the callback of the ~w behaviour\n",
- [ordinal(N), F, A, ST, CT, B]);
-message_to_string({callback_missing, [B, F, A]}) ->
+ [ordinal(N), F, A, t(ST, I), t(CT, I), B]);
+message_to_string({callback_missing, [B, F, A]}, _I) ->
io_lib:format("Undefined callback function ~tw/~w (behaviour ~w)\n",
[F, A, B]);
-message_to_string({callback_info_missing, [B]}) ->
+message_to_string({callback_info_missing, [B]}, _I) ->
io_lib:format("Callback info about the ~w behaviour is not available\n", [B]);
%%----- Warnings for unknown functions, types, and behaviours -------------
-message_to_string({unknown_type, {M, F, A}}) ->
+message_to_string({unknown_type, {M, F, A}}, _I) ->
io_lib:format("Unknown type ~w:~tw/~w", [M, F, A]);
-message_to_string({unknown_function, {M, F, A}}) ->
+message_to_string({unknown_function, {M, F, A}}, _I) ->
io_lib:format("Unknown function ~w:~tw/~w", [M, F, A]);
-message_to_string({unknown_behaviour, B}) ->
+message_to_string({unknown_behaviour, B}, _I) ->
io_lib:format("Unknown behaviour ~w", [B]).
%%-----------------------------------------------------------------------------
@@ -490,7 +520,7 @@ message_to_string({unknown_behaviour, B}) ->
%%-----------------------------------------------------------------------------
call_or_apply_to_string(ArgNs, FailReason, SigArgs, SigRet,
- {IsOverloaded, Contract}) ->
+ {IsOverloaded, Contract}, I) ->
PositionString = form_position_string(ArgNs),
case FailReason of
only_sig ->
@@ -498,24 +528,25 @@ call_or_apply_to_string(ArgNs, FailReason, SigArgs, SigRet,
true ->
%% We do not know which argument(s) caused the failure
io_lib:format("will never return since the success typing arguments"
- " are ~ts\n", [SigArgs]);
+ " are ~ts\n", [t(SigArgs, I)]);
false ->
io_lib:format("will never return since it differs in the ~s argument"
" from the success typing arguments: ~ts\n",
- [PositionString, SigArgs])
+ [PositionString, t(SigArgs, I)])
end;
only_contract ->
case (ArgNs =:= []) orelse IsOverloaded of
true ->
%% We do not know which arguments caused the failure
- io_lib:format("breaks the contract ~ts\n", [Contract]);
+ io_lib:format("breaks the contract ~ts\n", [sig(Contract, I)]);
false ->
io_lib:format("breaks the contract ~ts in the ~s argument\n",
- [Contract, PositionString])
+ [sig(Contract, I), PositionString])
end;
both ->
io_lib:format("will never return since the success typing is ~ts -> ~ts"
- " and the contract is ~ts\n", [SigArgs, SigRet, Contract])
+ " and the contract is ~ts\n",
+ [t(SigArgs, I), t(SigRet, I), sig(Contract, I)])
end.
form_positions(ArgNs) ->
@@ -530,24 +561,27 @@ form_positions(ArgNs) ->
%% We know which positions N are to blame;
%% the list of triples will never be empty.
-form_expected_without_opaque([{N, T, TStr}]) ->
+form_expected_without_opaque([{N, T, TStr}], I) ->
case erl_types:t_is_opaque(T) of
true ->
- io_lib:format("an opaque term of type ~ts as ", [TStr]);
+ io_lib:format("an opaque term of type ~ts as ", [t(TStr, I)]);
false ->
- io_lib:format("a term of type ~ts (with opaque subterms) as ", [TStr])
+ io_lib:format("a term of type ~ts (with opaque subterms) as ",
+ [t(TStr, I)])
end ++ form_position_string([N]) ++ " argument";
-form_expected_without_opaque(ExpectedTriples) -> %% TODO: can do much better here
+form_expected_without_opaque(ExpectedTriples, _I) -> %% TODO: can do much better here
{ArgNs, _Ts, _TStrs} = lists:unzip3(ExpectedTriples),
"opaque terms as " ++ form_position_string(ArgNs) ++ " arguments".
-form_expected(ExpectedArgs) ->
+form_expected(ExpectedArgs, I) ->
case ExpectedArgs of
[T] ->
TS = erl_types:t_to_string(T),
case erl_types:t_is_opaque(T) of
- true -> io_lib:format("an opaque term of type ~ts is expected", [TS]);
- false -> io_lib:format("a structured term of type ~ts is expected", [TS])
+ true -> io_lib:format("an opaque term of type ~ts is expected",
+ [t(TS, I)]);
+ false -> io_lib:format("a structured term of type ~ts is expected",
+ [t(TS, I)])
end;
[_,_|_] -> "terms of different types are expected in these positions"
end.
@@ -567,3 +601,161 @@ ordinal(1) -> "1st";
ordinal(2) -> "2nd";
ordinal(3) -> "3rd";
ordinal(N) when is_integer(N) -> io_lib:format("~wth", [N]).
+
+%% Functions that parse type strings, literal strings, and contract
+%% strings. Return strings formatted by erl_pp.
+
+%% If lib/hipe/cerl/erl_types.erl is compiled with DEBUG=true,
+%% the contents of opaque types are showed inside brackets.
+%% Since erl_parse:parse_form() cannot handle the bracket syntax,
+%% no indentation is done.
+%%-define(DEBUG , true).
+
+-define(IND, 10).
+
+con(M, F, Src, I) ->
+ S = sig(Src, I),
+ io_lib:format("~w:~tw~ts", [M, F, S]).
+
+sig(Src, false) ->
+ Src;
+sig(Src, true) ->
+ Str = lists:flatten(io_lib:format("-spec ~w:~tw~ts.", [a, b, Src])),
+ {ok, Tokens, _EndLocation} = erl_scan:string(Str),
+ exec(fun() ->
+ {ok, {attribute, _, spec, {_MFA, Types}}} =
+ erl_parse:parse_form(Tokens),
+ indentation(?IND) ++ pp_spec(Types)
+ end, Src).
+
+%% Argument(list)s are a mix of types and Erlang code. Note: sometimes
+%% (contract_range, call_without_opaque, opaque_type_test), the initial
+%% newline is a bit out of place.
+a(""=Args, _I) ->
+ Args;
+a(Args, I) ->
+ t(Args, I).
+
+c(Cerl, _I) ->
+ Cerl.
+
+field_diffs(Src, false) ->
+ Src;
+field_diffs(Src, true) ->
+ Fields = string:split(Src, " and "),
+ lists:join(" and ", [field_diff(Field) || Field <- Fields]).
+
+field_diff(Field) ->
+ [F | Ts] = string:split(Field, "::"),
+ F ++ " ::" ++ t(lists:flatten(lists:join("::", Ts)), true).
+
+rec_type("record "++Src, I) ->
+ "record " ++ t(Src, I).
+
+%% "variable"/"pattern" ++ cerl
+ps("pattern "++Src, I) ->
+ "pattern " ++ t(Src, I);
+ps("variable "++_=Src, _I) ->
+ Src;
+ps("record field"++Rest, I) ->
+ [S, TypeStr] = string:split(Rest, "of type "),
+ "record field" ++ S ++ "of type " ++ t(TypeStr, I).
+
+%% Scan and parse a type or a literal, and pretty-print it using erl_pp.
+t(Src, false) ->
+ Src;
+t("("++_=Src, true) ->
+ ts(Src);
+t(Src, true) ->
+ %% Binary types and products both start with a $<.
+ try parse_type_or_literal(Src) of
+ TypeOrLiteral ->
+ indentation(?IND) ++ pp_type(TypeOrLiteral)
+ catch
+ _:_ ->
+ ts(Src)
+ end.
+
+ts(Src) ->
+ Ind = indentation(?IND),
+ [C1|Src1] = Src, % $< (product) or $( (arglist)
+ [C2|RevSrc2] = lists:reverse(Src1),
+ Src2 = lists:reverse(RevSrc2),
+ exec(fun() ->
+ Types = parse_types_and_literals(Src2),
+ CommaInd = [$, | Ind],
+ (indentation(?IND-1) ++
+ [C1 | lists:join(CommaInd, [pp_type(Type) || Type <- Types])] ++
+ [C2])
+ end, Src).
+
+-ifdef(DEBUG).
+exec(F, R) ->
+ try F() catch _:_ -> R end.
+-else.
+exec(F, _) ->
+ F().
+-endif.
+
+indentation(I) ->
+ [$\n | lists:duplicate(I, $\s)].
+
+pp_type(Type) ->
+ Form = {attribute, erl_anno:new(0), type, {t, Type, []}},
+ TypeDef = erl_pp:form(Form, [{quote_singleton_atom_types, true}]),
+ {match, [S]} = re:run(TypeDef, <<"::\\s*(.*)\\.\\n*">>,
+ [{capture, all_but_first, list}, dotall]),
+ S.
+
+pp_spec(Spec) ->
+ Form = {attribute, erl_anno:new(0), spec, {{a,b,0}, Spec}},
+ Sig = erl_pp:form(Form, [{quote_singleton_atom_types, true}]),
+ {match, [S]} = re:run(Sig, <<"-spec a:b\\s*(.*)\\.\\n*">>,
+ [{capture, all_but_first, list}, dotall]),
+ S.
+
+parse_types_and_literals(Src) ->
+ {ok, Tokens, _EndLocation} = erl_scan:string(Src),
+ [parse_a_type_or_literal(Ts) || Ts <- types(Tokens)].
+
+parse_type_or_literal(Src) ->
+ {ok, Tokens, _EndLocation} = erl_scan:string(Src),
+ parse_a_type_or_literal(Tokens).
+
+parse_a_type_or_literal(Ts0) ->
+ L = erl_anno:new(1),
+ Ts = Ts0 ++ [{dot,L}],
+ Tokens = [{'-',L}, {atom,L,type}, {atom,L,t}, {'(',L}, {')',L},
+ {'::',L}] ++ Ts,
+ case erl_parse:parse_form(Tokens) of
+ {ok, {attribute, _, type, {t, Type, []}}} ->
+ Type;
+ {error, _} ->
+ %% literal
+ {ok, [T]} = erl_parse:parse_exprs(Ts),
+ T
+ end.
+
+types([]) -> [];
+types(Ts) ->
+ {Ts0, Ts1} = one_type(Ts, [], []),
+ [Ts0 | types(Ts1)].
+
+one_type([], [], Ts) ->
+ {lists:reverse(Ts), []};
+one_type([{',', _Lc}|Toks], [], Ts0) ->
+ {lists:reverse(Ts0), Toks};
+one_type([{')', Lrp}|Toks], [], Ts0) ->
+ {lists:reverse(Ts0), [{')', Lrp}|Toks]};
+one_type([{'(', Llp}|Toks], E, Ts0) ->
+ one_type(Toks, [')'|E], [{'(', Llp}|Ts0]);
+one_type([{'<<', Lls}|Toks], E, Ts0) ->
+ one_type(Toks, ['>>'|E], [{'<<', Lls}|Ts0]);
+one_type([{'[', Lls}|Toks], E, Ts0) ->
+ one_type(Toks, [']'|E], [{'[', Lls}|Ts0]);
+one_type([{'{', Llc}|Toks], E, Ts0) ->
+ one_type(Toks, ['}'|E], [{'{', Llc}|Ts0]);
+one_type([{Rb, Lrb}|Toks], [Rb|E], Ts0) ->
+ one_type(Toks, E, [{Rb, Lrb}|Ts0]);
+one_type([T|Toks], E, Ts0) ->
+ one_type(Toks, E, [T|Ts0]).
diff --git a/lib/dialyzer/src/dialyzer.hrl b/lib/dialyzer/src/dialyzer.hrl
index e7cf2860b7..4a12b9b671 100644
--- a/lib/dialyzer/src/dialyzer.hrl
+++ b/lib/dialyzer/src/dialyzer.hrl
@@ -108,6 +108,7 @@
-type dial_options() :: [dial_option()].
-type fopt() :: 'basename' | 'fullpath'.
-type format() :: 'formatted' | 'raw'.
+-type iopt() :: boolean().
-type label() :: non_neg_integer().
-type dial_warn_tags():: ordsets:ordset(dial_warn_tag()).
-type rep_mode() :: 'quiet' | 'normal' | 'verbose'.
@@ -119,6 +120,8 @@
%% Record declarations used by various files
%%--------------------------------------------------------------------
+-define(INDENT_OPT, true).
+
-type doc_plt() :: 'undefined' | dialyzer_plt:plt().
-record(analysis, {analysis_pid :: pid() | 'undefined',
@@ -154,6 +157,7 @@
output_file = none :: 'none' | file:filename(),
output_format = formatted :: format(),
filename_opt = basename :: fopt(),
+ indent_opt = ?INDENT_OPT :: iopt(),
callgraph_file = "" :: file:filename(),
check_plt = true :: boolean(),
solvers = [] :: [solver()]}).
diff --git a/lib/dialyzer/src/dialyzer_cl.erl b/lib/dialyzer/src/dialyzer_cl.erl
index 0617be6435..f887f661bd 100644
--- a/lib/dialyzer/src/dialyzer_cl.erl
+++ b/lib/dialyzer/src/dialyzer_cl.erl
@@ -40,6 +40,7 @@
output = standard_io :: io:device(),
output_format = formatted :: format(),
filename_opt = basename :: fopt(),
+ indent_opt = ?INDENT_OPT :: iopt(),
output_plt = none :: 'none' | file:filename(),
plt_info = none :: 'none' | dialyzer_plt:plt_info(),
report_mode = normal :: rep_mode(),
@@ -588,8 +589,11 @@ new_state() ->
init_output(State0, #options{output_file = OutFile,
output_format = OutFormat,
- filename_opt = FOpt}) ->
- State = State0#cl_state{output_format = OutFormat, filename_opt = FOpt},
+ filename_opt = FOpt,
+ indent_opt = IOpt}) ->
+ State = State0#cl_state{output_format = OutFormat,
+ filename_opt = FOpt,
+ indent_opt = IOpt},
case OutFile =:= none of
true ->
State;
@@ -672,7 +676,7 @@ failed_anal_msg(Reason, LogCache) ->
%%
format_log_cache(LogCache) ->
Str = lists:append(lists:reverse(LogCache)),
- string:join(string:tokens(Str, "\n"), "\n ").
+ lists:join("\n ", string:lexemes(Str, "\n")).
-spec store_warnings(#cl_state{}, [raw_warning()]) -> #cl_state{}.
@@ -818,6 +822,7 @@ print_warnings(#cl_state{stored_warnings = []}) ->
print_warnings(#cl_state{output = Output,
output_format = Format,
filename_opt = FOpt,
+ indent_opt = IOpt,
stored_warnings = Warnings}) ->
PrWarnings = process_warnings(Warnings),
case PrWarnings of
@@ -825,7 +830,8 @@ print_warnings(#cl_state{output = Output,
[_|_] ->
S = case Format of
formatted ->
- [dialyzer:format_warning(W, FOpt) || W <- PrWarnings];
+ Opts = [{filename_opt, FOpt}, {indent_opt, IOpt}],
+ [dialyzer:format_warning(W, Opts) || W <- PrWarnings];
raw ->
[io_lib:format("~tp. \n",
[W]) || W <- set_warning_id(PrWarnings)]
diff --git a/lib/dialyzer/src/dialyzer_cl_parse.erl b/lib/dialyzer/src/dialyzer_cl_parse.erl
index 80c10183cf..280cae81d5 100644
--- a/lib/dialyzer/src/dialyzer_cl_parse.erl
+++ b/lib/dialyzer/src/dialyzer_cl_parse.erl
@@ -41,8 +41,8 @@ start() ->
Ret
catch
throw:{dialyzer_cl_parse_error, Msg} -> {error, Msg};
- _:R ->
- Msg = io_lib:format("~tp\n~tp\n", [R, erlang:get_stacktrace()]),
+ _:R:S ->
+ Msg = io_lib:format("~tp\n~tp\n", [R, S]),
{error, lists:flatten(Msg)}
end.
@@ -134,6 +134,9 @@ cl(["--raw"|T]) ->
cl(["--fullpath"|T]) ->
put(dialyzer_filename_opt, fullpath),
cl(T);
+cl(["--no_indentation"|T]) ->
+ put(dialyzer_indent_opt, false),
+ cl(T);
cl(["-pa", Path|T]) ->
case code:add_patha(Path) of
true -> cl(T);
@@ -254,6 +257,7 @@ init() ->
put(dialyzer_options_files, DefaultOpts#options.files),
put(dialyzer_output_format, formatted),
put(dialyzer_filename_opt, basename),
+ put(dialyzer_indent_opt, ?INDENT_OPT),
put(dialyzer_options_check_plt, DefaultOpts#options.check_plt),
put(dialyzer_timing, DefaultOpts#options.timing),
put(dialyzer_solvers, DefaultOpts#options.solvers),
@@ -295,6 +299,7 @@ cl_options() ->
{output_file, get(dialyzer_output)},
{output_format, get(dialyzer_output_format)},
{filename_opt, get(dialyzer_filename_opt)},
+ {indent_opt, get(dialyzer_indent_opt)},
{analysis_type, get(dialyzer_options_analysis_type)},
{get_warnings, get(dialyzer_options_get_warnings)},
{timing, get(dialyzer_timing)},
@@ -361,7 +366,7 @@ help_message() ->
[--build_plt] [--add_to_plt] [--remove_from_plt]
[--check_plt] [--no_check_plt] [--plt_info] [--get_warnings]
[--dump_callgraph file] [--no_native] [--fullpath]
- [--statistics] [--no_native_cache]
+ [--no_indentation] [--statistics] [--no_native_cache]
Options:
files_or_dirs (for backwards compatibility also as: -c files_or_dirs)
Use Dialyzer from the command line to detect defects in the
@@ -473,6 +478,9 @@ Options:
caching.
--fullpath
Display the full path names of files for which warnings are emitted.
+ --no_indentation
+ Do not indent contracts and success typings. Note that this option has
+ no effect when combined with the --raw option.
--gui
Use the GUI.
diff --git a/lib/dialyzer/src/dialyzer_codeserver.erl b/lib/dialyzer/src/dialyzer_codeserver.erl
index 5587cf2bdf..c4e3c322e5 100644
--- a/lib/dialyzer/src/dialyzer_codeserver.erl
+++ b/lib/dialyzer/src/dialyzer_codeserver.erl
@@ -347,13 +347,11 @@ get_file_contract(Key, ContDict) ->
lookup_mfa_contract(MFA, #codeserver{contracts = ContDict}) ->
ets_dict_find(MFA, ContDict).
--spec lookup_meta_info(module() | mfa(), codeserver()) -> meta_info().
+-spec lookup_meta_info(module() | mfa(), codeserver()) ->
+ {'ok', meta_info()} | 'error'.
lookup_meta_info(MorMFA, #codeserver{fun_meta_info = FunMetaInfo}) ->
- case ets_dict_find(MorMFA, FunMetaInfo) of
- error -> [];
- {ok, PropList} -> PropList
- end.
+ ets_dict_find(MorMFA, FunMetaInfo).
-spec get_contracts(codeserver()) ->
dict:dict(mfa(), dialyzer_contracts:file_contract()).
diff --git a/lib/dialyzer/src/dialyzer_contracts.erl b/lib/dialyzer/src/dialyzer_contracts.erl
index e72c1aecfc..17b2168852 100644
--- a/lib/dialyzer/src/dialyzer_contracts.erl
+++ b/lib/dialyzer/src/dialyzer_contracts.erl
@@ -25,7 +25,7 @@
%% get_contract_signature/1,
is_overloaded/1,
process_contract_remote_types/1,
- store_tmp_contract/5]).
+ store_tmp_contract/6]).
-export_type([file_contract/0, plt_contracts/0]).
@@ -146,18 +146,18 @@ process_contract_remote_types(CodeServer) ->
Mods = dialyzer_codeserver:all_temp_modules(CodeServer),
RecordTable = dialyzer_codeserver:get_records_table(CodeServer),
ExpTypes = dialyzer_codeserver:get_exported_types(CodeServer),
- ContractFun =
- fun({{_M, _F, _A}=MFA, {File, TmpContract, Xtra}}, C0) ->
- #tmp_contract{contract_funs = CFuns, forms = Forms} = TmpContract,
- {NewCs, C2} = lists:mapfoldl(fun(CFun, C1) ->
- CFun(ExpTypes, RecordTable, C1)
- end, C0, CFuns),
- Args = general_domain(NewCs),
- Contract = #contract{contracts = NewCs, args = Args, forms = Forms},
- {{MFA, {File, Contract, Xtra}}, C2}
- end,
ModuleFun =
fun(ModuleName) ->
+ ContractFun =
+ fun({MFA, {File, TmpContract, Xtra}}, C0) ->
+ #tmp_contract{contract_funs = CFuns, forms = Forms} = TmpContract,
+ {NewCs, C2} = lists:mapfoldl(fun(CFun, C1) ->
+ CFun(ExpTypes, RecordTable, C1)
+ end, C0, CFuns),
+ Args = general_domain(NewCs),
+ Contract = #contract{contracts = NewCs, args = Args, forms = Forms},
+ {{MFA, {File, Contract, Xtra}}, C2}
+ end,
Cache = erl_types:cache__new(),
{ContractMap, CallbackMap} =
dialyzer_codeserver:get_temp_contracts(ModuleName, CodeServer),
@@ -197,6 +197,12 @@ check_contracts(Contracts, Callgraph, FunTypes, ModOpaques) ->
false ->
[{MFA, Contract}|NewContracts]
end;
+ {range_warnings, _} ->
+ %% do not treat extra range, either in contract or
+ %% in success typing, as an error in this check
+ %% since that prevents discovering other actual
+ %% errors
+ [{MFA, Contract}|NewContracts];
{error, _Error} -> NewContracts
end;
error -> NewContracts
@@ -206,14 +212,26 @@ check_contracts(Contracts, Callgraph, FunTypes, ModOpaques) ->
end,
orddict:from_list(lists:foldl(FoldFun, [], orddict:to_list(FunTypes))).
+-type check_contract_return() ::
+ 'ok'
+ | {'error',
+ 'invalid_contract'
+ | {'opaque_mismatch', erl_types:erl_type()}
+ | {'overlapping_contract', [module() | atom() | byte()]}
+ | string()}
+ | {'range_warnings',
+ [{'error', {'extra_range' | 'missing_range',
+ erl_types:erl_type(),
+ erl_types:erl_type()}}]}.
+
%% Checks all components of a contract
--spec check_contract(#contract{}, erl_types:erl_type()) -> 'ok' | {'error', term()}.
+-spec check_contract(#contract{}, erl_types:erl_type()) -> check_contract_return().
check_contract(Contract, SuccType) ->
check_contract(Contract, SuccType, 'universe').
-spec check_contract(#contract{}, erl_types:erl_type(), erl_types:opaques()) ->
- 'ok' | {'error', term()}.
+ check_contract_return().
check_contract(#contract{contracts = Contracts}, SuccType, Opaques) ->
try
@@ -286,15 +304,23 @@ check_contract_inf_list([], _SuccType, _Opaques, OM) ->
check_extraneous([], _SuccType) -> ok;
check_extraneous([C|Cs], SuccType) ->
case check_extraneous_1(C, SuccType) of
- ok -> check_extraneous(Cs, SuccType);
- Error -> Error
+ {error, invalid_contract} = Error ->
+ Error;
+ {error, {extra_range, _, _}} = Error ->
+ {range_warnings, [Error | check_missing(C, SuccType)]};
+ ok ->
+ case check_missing(C, SuccType) of
+ [] -> check_extraneous(Cs, SuccType);
+ ErrorL -> {range_warnings, ErrorL}
+ end
end.
check_extraneous_1(Contract, SuccType) ->
CRng = erl_types:t_fun_range(Contract),
CRngs = erl_types:t_elements(CRng),
STRng = erl_types:t_fun_range(SuccType),
- ?debug("CR = ~tp\nSR = ~tp\n", [CRngs, STRng]),
+ ?debug("\nCR = ~ts\nSR = ~ts\n", [erl_types:t_to_string(CRng),
+ erl_types:t_to_string(STRng)]),
case [CR || CR <- CRngs,
erl_types:t_is_none(erl_types:t_inf(CR, STRng))] of
[] ->
@@ -337,6 +363,18 @@ map_part(Type) ->
is_empty_map(Type) ->
erl_types:t_is_equal(Type, erl_types:t_from_term(#{})).
+check_missing(Contract, SuccType) ->
+ CRng = erl_types:t_fun_range(Contract),
+ STRng = erl_types:t_fun_range(SuccType),
+ STRngs = erl_types:t_elements(STRng),
+ ?debug("\nCR = ~ts\nSR = ~ts\n", [erl_types:t_to_string(CRng),
+ erl_types:t_to_string(STRng)]),
+ case [STR || STR <- STRngs,
+ erl_types:t_is_none(erl_types:t_inf(STR, CRng))] of
+ [] -> [];
+ STRs -> [{error, {missing_range, erl_types:t_sup(STRs), CRng}}]
+ end.
+
%% This is the heart of the "range function"
-spec process_contracts([contract_pair()], [erl_types:erl_type()]) ->
erl_types:erl_type().
@@ -436,26 +474,29 @@ insert_constraints([], Map) -> Map.
-type spec_data() :: {TypeSpec :: [_], Xtra:: [_]}.
--spec store_tmp_contract(mfa(), file_line(), spec_data(), contracts(), types()) ->
- contracts().
+-spec store_tmp_contract(module(), mfa(), file_line(), spec_data(),
+ contracts(), types()) -> contracts().
-store_tmp_contract(MFA, FileLine, {TypeSpec, Xtra}, SpecMap, RecordsDict) ->
+store_tmp_contract(Module, MFA, FileLine, {TypeSpec, Xtra}, SpecMap,
+ RecordsDict) ->
%% io:format("contract from form: ~tp\n", [TypeSpec]),
- TmpContract = contract_from_form(TypeSpec, MFA, RecordsDict, FileLine),
+ TmpContract = contract_from_form(TypeSpec, Module, MFA, RecordsDict, FileLine),
%% io:format("contract: ~tp\n", [TmpContract]),
maps:put(MFA, {FileLine, TmpContract, Xtra}, SpecMap).
-contract_from_form(Forms, MFA, RecDict, FileLine) ->
- {CFuns, Forms1} = contract_from_form(Forms, MFA, RecDict, FileLine, [], []),
+contract_from_form(Forms, Module, MFA, RecDict, FileLine) ->
+ {CFuns, Forms1} =
+ contract_from_form(Forms, Module, MFA, RecDict, FileLine, [], []),
#tmp_contract{contract_funs = CFuns, forms = Forms1}.
-contract_from_form([{type, _, 'fun', [_, _]} = Form | Left], MFA, RecDict,
- FileLine, TypeAcc, FormAcc) ->
+contract_from_form([{type, _, 'fun', [_, _]} = Form | Left], Module, MFA,
+ RecDict, FileLine, TypeAcc, FormAcc) ->
TypeFun =
fun(ExpTypes, RecordTable, Cache) ->
{NewType, NewCache} =
try
- from_form_with_check(Form, ExpTypes, MFA, RecordTable, Cache)
+ from_form_with_check(Form, ExpTypes, Module, MFA, RecordTable,
+ Cache)
catch
throw:{error, Msg} ->
{File, Line} = FileLine,
@@ -468,68 +509,74 @@ contract_from_form([{type, _, 'fun', [_, _]} = Form | Left], MFA, RecDict,
end,
NewTypeAcc = [TypeFun | TypeAcc],
NewFormAcc = [{Form, []} | FormAcc],
- contract_from_form(Left, MFA, RecDict, FileLine, NewTypeAcc, NewFormAcc);
+ contract_from_form(Left, Module, MFA, RecDict, FileLine, NewTypeAcc,
+ NewFormAcc);
contract_from_form([{type, _L1, bounded_fun,
[{type, _L2, 'fun', [_, _]} = Form, Constr]}| Left],
- MFA, RecDict, FileLine, TypeAcc, FormAcc) ->
+ Module, MFA, RecDict, FileLine, TypeAcc, FormAcc) ->
TypeFun =
fun(ExpTypes, RecordTable, Cache) ->
{Constr1, VarTable, Cache1} =
- process_constraints(Constr, MFA, RecDict, ExpTypes, RecordTable,
- Cache),
+ process_constraints(Constr, Module, MFA, RecDict, ExpTypes,
+ RecordTable, Cache),
{NewType, NewCache} =
- from_form_with_check(Form, ExpTypes, MFA, RecordTable,
+ from_form_with_check(Form, ExpTypes, Module, MFA, RecordTable,
VarTable, Cache1),
NewTypeNoVars = erl_types:subst_all_vars_to_any(NewType),
{{NewTypeNoVars, Constr1}, NewCache}
end,
NewTypeAcc = [TypeFun | TypeAcc],
NewFormAcc = [{Form, Constr} | FormAcc],
- contract_from_form(Left, MFA, RecDict, FileLine, NewTypeAcc, NewFormAcc);
-contract_from_form([], _MFA, _RecDict, _FileLine, TypeAcc, FormAcc) ->
+ contract_from_form(Left, Module, MFA, RecDict, FileLine, NewTypeAcc,
+ NewFormAcc);
+contract_from_form([], _Mod, _MFA, _RecDict, _FileLine, TypeAcc, FormAcc) ->
{lists:reverse(TypeAcc), lists:reverse(FormAcc)}.
-process_constraints(Constrs, MFA, RecDict, ExpTypes, RecordTable, Cache) ->
- {Init0, NewCache} = initialize_constraints(Constrs, MFA, RecDict, ExpTypes,
- RecordTable, Cache),
+process_constraints(Constrs, Module, MFA, RecDict, ExpTypes, RecordTable,
+ Cache) ->
+ {Init0, NewCache} = initialize_constraints(Constrs, Module, MFA, RecDict,
+ ExpTypes, RecordTable, Cache),
Init = remove_cycles(Init0),
- constraints_fixpoint(Init, MFA, RecDict, ExpTypes, RecordTable, NewCache).
+ constraints_fixpoint(Init, Module, MFA, RecDict, ExpTypes, RecordTable,
+ NewCache).
-initialize_constraints(Constrs, MFA, RecDict, ExpTypes, RecordTable, Cache) ->
- initialize_constraints(Constrs, MFA, RecDict, ExpTypes, RecordTable,
+initialize_constraints(Constrs, Module, MFA, RecDict, ExpTypes, RecordTable,
+ Cache) ->
+ initialize_constraints(Constrs, Module, MFA, RecDict, ExpTypes, RecordTable,
Cache, []).
-initialize_constraints([], _MFA, _RecDict, _ExpTypes, _RecordTable,
+initialize_constraints([], _Module, _MFA, _RecDict, _ExpTypes, _RecordTable,
Cache, Acc) ->
{Acc, Cache};
-initialize_constraints([Constr|Rest], MFA, RecDict, ExpTypes, RecordTable,
- Cache, Acc) ->
+initialize_constraints([Constr|Rest], Module, MFA, RecDict, ExpTypes,
+ RecordTable, Cache, Acc) ->
case Constr of
{type, _, constraint, [{atom, _, is_subtype}, [Type1, Type2]]} ->
VarTable = erl_types:var_table__new(),
{T1, NewCache} =
- final_form(Type1, ExpTypes, MFA, RecordTable, VarTable, Cache),
+ final_form(Type1, ExpTypes, Module, MFA, RecordTable, VarTable, Cache),
Entry = {T1, Type2},
- initialize_constraints(Rest, MFA, RecDict, ExpTypes, RecordTable,
- NewCache, [Entry|Acc]);
+ initialize_constraints(Rest, Module, MFA, RecDict, ExpTypes,
+ RecordTable, NewCache, [Entry|Acc]);
{type, _, constraint, [{atom,_,Name}, List]} ->
N = length(List),
throw({error,
io_lib:format("Unsupported type guard ~tw/~w\n", [Name, N])})
end.
-constraints_fixpoint(Constrs, MFA, RecDict, ExpTypes, RecordTable, Cache) ->
+constraints_fixpoint(Constrs, Module, MFA, RecDict, ExpTypes, RecordTable,
+ Cache) ->
VarTable = erl_types:var_table__new(),
{VarTab, NewCache} =
- constraints_to_dict(Constrs, MFA, RecDict, ExpTypes, RecordTable,
+ constraints_to_dict(Constrs, Module, MFA, RecDict, ExpTypes, RecordTable,
VarTable, Cache),
- constraints_fixpoint(VarTab, MFA, Constrs, RecDict, ExpTypes,
+ constraints_fixpoint(VarTab, Module, MFA, Constrs, RecDict, ExpTypes,
RecordTable, NewCache).
-constraints_fixpoint(OldVarTab, MFA, Constrs, RecDict, ExpTypes,
+constraints_fixpoint(OldVarTab, Module, MFA, Constrs, RecDict, ExpTypes,
RecordTable, Cache) ->
{NewVarTab, NewCache} =
- constraints_to_dict(Constrs, MFA, RecDict, ExpTypes, RecordTable,
+ constraints_to_dict(Constrs, Module, MFA, RecDict, ExpTypes, RecordTable,
OldVarTab, Cache),
case NewVarTab of
OldVarTab ->
@@ -540,19 +587,23 @@ constraints_fixpoint(OldVarTab, MFA, Constrs, RecDict, ExpTypes,
FinalConstrs = maps:fold(Fun, [], NewVarTab),
{FinalConstrs, NewVarTab, NewCache};
_Other ->
- constraints_fixpoint(NewVarTab, MFA, Constrs, RecDict, ExpTypes,
+ constraints_fixpoint(NewVarTab, Module, MFA, Constrs, RecDict, ExpTypes,
RecordTable, NewCache)
end.
-final_form(Form, ExpTypes, MFA, RecordTable, VarTable, Cache) ->
- from_form_with_check(Form, ExpTypes, MFA, RecordTable, VarTable, Cache).
+final_form(Form, ExpTypes, Module, MFA, RecordTable, VarTable, Cache) ->
+ from_form_with_check(Form, ExpTypes, Module, MFA, RecordTable, VarTable,
+ Cache).
-from_form_with_check(Form, ExpTypes, MFA, RecordTable, Cache) ->
+from_form_with_check(Form, ExpTypes, Module, MFA, RecordTable, Cache) ->
VarTable = erl_types:var_table__new(),
- from_form_with_check(Form, ExpTypes, MFA, RecordTable, VarTable, Cache).
+ from_form_with_check(Form, ExpTypes, Module, MFA, RecordTable, VarTable,
+ Cache).
-from_form_with_check(Form, ExpTypes, MFA, RecordTable, VarTable, Cache) ->
- Site = {spec, MFA},
+from_form_with_check(Form, ExpTypes, Module, MFA, RecordTable, VarTable,
+ Cache) ->
+ {_, F, A} = MFA,
+ Site = {spec, {Module, F, A}},
C1 = erl_types:t_check_record_fields(Form, ExpTypes, Site, RecordTable,
VarTable, Cache),
%% The check costs some time, and with the assumption that contracts
@@ -560,22 +611,22 @@ from_form_with_check(Form, ExpTypes, MFA, RecordTable, VarTable, Cache) ->
%% erl_types:t_from_form_check_remote(Form, ExpTypes, MFA, RecordTable),
erl_types:t_from_form(Form, ExpTypes, Site, RecordTable, VarTable, C1).
-constraints_to_dict(Constrs, MFA, RecDict, ExpTypes, RecordTable,
+constraints_to_dict(Constrs, Module, MFA, RecDict, ExpTypes, RecordTable,
VarTab, Cache) ->
{Subtypes, NewCache} =
- constraints_to_subs(Constrs, MFA, RecDict, ExpTypes, RecordTable,
+ constraints_to_subs(Constrs, Module, MFA, RecDict, ExpTypes, RecordTable,
VarTab, Cache, []),
{insert_constraints(Subtypes), NewCache}.
-constraints_to_subs([], _MFA, _RecDict, _ExpTypes, _RecordTable,
+constraints_to_subs([], _Module, _MFA, _RecDict, _ExpTypes, _RecordTable,
_VarTab, Cache, Acc) ->
{Acc, Cache};
-constraints_to_subs([{T1, Form2}|Rest], MFA, RecDict, ExpTypes, RecordTable,
- VarTab, Cache, Acc) ->
+constraints_to_subs([{T1, Form2}|Rest], Module, MFA, RecDict, ExpTypes,
+ RecordTable, VarTab, Cache, Acc) ->
{T2, NewCache} =
- final_form(Form2, ExpTypes, MFA, RecordTable, VarTab, Cache),
+ final_form(Form2, ExpTypes, Module, MFA, RecordTable, VarTab, Cache),
NewAcc = [{subtype, T1, T2}|Acc],
- constraints_to_subs(Rest, MFA, RecDict, ExpTypes, RecordTable,
+ constraints_to_subs(Rest, Module, MFA, RecDict, ExpTypes, RecordTable,
VarTab, NewCache, NewAcc).
%% Replaces variables with '_' when necessary to break up cycles among
@@ -708,22 +759,30 @@ get_invalid_contract_warnings_funs([{MFA, {FileLine, Contract, _Xtra}}|Left],
[W|Acc];
{error, {overlapping_contract, []}} ->
[overlapping_contract_warning(MFA, WarningInfo)|Acc];
- {error, {extra_range, ExtraRanges, STRange}} ->
- Warn =
- case t_from_forms_without_remote(Contract#contract.forms,
- MFA, RecDict) of
- {ok, NoRemoteType} ->
- CRet = erl_types:t_fun_range(NoRemoteType),
- erl_types:t_is_subtype(ExtraRanges, CRet);
- unsupported ->
- true
- end,
- case Warn of
- true ->
- [extra_range_warning(MFA, WarningInfo, ExtraRanges, STRange)|Acc];
- false ->
- Acc
- end;
+ {range_warnings, Errors} ->
+ Fun =
+ fun({error, {extra_range, ExtraRanges, STRange}}, Acc0) ->
+ Warn =
+ case t_from_forms_without_remote(Contract#contract.forms,
+ MFA, RecDict) of
+ {ok, NoRemoteType} ->
+ CRet = erl_types:t_fun_range(NoRemoteType),
+ erl_types:t_is_subtype(ExtraRanges, CRet);
+ unsupported ->
+ true
+ end,
+ case Warn of
+ true ->
+ [extra_range_warning(MFA, WarningInfo,
+ ExtraRanges, STRange)|Acc0];
+ false ->
+ Acc0
+ end;
+ ({error, {missing_range, ExtraRanges, CRange}}, Acc0) ->
+ [missing_range_warning(MFA, WarningInfo,
+ ExtraRanges, CRange)|Acc0]
+ end,
+ lists:foldl(Fun, Acc, Errors);
{error, Msg} ->
[{?WARN_CONTRACT_SYNTAX, WarningInfo, Msg}|Acc];
ok ->
@@ -741,6 +800,9 @@ get_invalid_contract_warnings_funs([{MFA, {FileLine, Contract, _Xtra}}|Left],
{error, _} ->
[invalid_contract_warning(MFA, WarningInfo, BifSig, RecDict)
|Acc];
+ {range_warnings, _} ->
+ picky_contract_check(CSig, BifSig, MFA, WarningInfo,
+ Contract, RecDict, Acc);
ok ->
picky_contract_check(CSig, BifSig, MFA, WarningInfo,
Contract, RecDict, Acc)
@@ -774,6 +836,12 @@ extra_range_warning({M, F, A}, WarningInfo, ExtraRanges, STRange) ->
{?WARN_CONTRACT_SUPERTYPE, WarningInfo,
{extra_range, [M, F, A, ERangesStr, STRangeStr]}}.
+missing_range_warning({M, F, A}, WarningInfo, ExtraRanges, CRange) ->
+ ERangesStr = erl_types:t_to_string(ExtraRanges),
+ CRangeStr = erl_types:t_to_string(CRange),
+ {?WARN_CONTRACT_SUBTYPE, WarningInfo,
+ {missing_range, [M, F, A, ERangesStr, CRangeStr]}}.
+
picky_contract_check(CSig0, Sig0, MFA, WarningInfo, Contract, RecDict, Acc) ->
CSig = erl_types:t_abstract_records(CSig0, RecDict),
Sig = erl_types:t_abstract_records(Sig0, RecDict),
diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl
index ea3523a965..55c77814f8 100644
--- a/lib/dialyzer/src/dialyzer_dataflow.erl
+++ b/lib/dialyzer/src/dialyzer_dataflow.erl
@@ -102,6 +102,8 @@
| 'undefined', % race
fun_homes :: dict:dict(label(), mfa())
| 'undefined', % race
+ reachable_funs :: sets:set(label())
+ | 'undefined', % race
plt :: dialyzer_plt:plt()
| 'undefined', % race
opaques :: [type()]
@@ -269,9 +271,11 @@ traverse(Tree, Map, State) ->
case state__warning_mode(State) of
true -> {State, Map, Type};
false ->
- State2 = state__add_work(get_label(Tree), State),
+ FunLbl = get_label(Tree),
+ State2 = state__add_work(FunLbl, State),
State3 = state__update_fun_env(Tree, Map, State2),
- {State3, Map, Type}
+ State4 = state__add_reachable(FunLbl, State3),
+ {State4, Map, Type}
end;
'let' ->
handle_let(Tree, Map, State);
@@ -299,6 +303,7 @@ traverse(Tree, Map, State) ->
match_fail -> t_none();
raise -> t_none();
bs_init_writable -> t_from_term(<<>>);
+ build_stacktrace -> erl_bif_types:type(erlang, build_stacktrace, 0);
Other -> erlang:error({'Unsupported primop', Other})
end,
{State, Map, Type};
@@ -400,8 +405,13 @@ handle_apply(Tree, Map, State) ->
t_fun_args(OpType1, 'universe')),
case any_none(NewArgs) of
true ->
+ EnumNewArgs = lists:zip(lists:seq(1, length(NewArgs)),
+ NewArgs),
+ ArgNs = [Arg ||
+ {Arg, Type} <- EnumNewArgs, t_is_none(Type)],
Msg = {fun_app_args,
- [format_args(Args, ArgTypes, State),
+ [ArgNs,
+ format_args(Args, ArgTypes, State),
format_type(OpType, State)]},
State3 = state__add_warning(State2, ?WARN_FAILING_CALL,
Tree, Msg),
@@ -3038,25 +3048,35 @@ state__new(Callgraph, Codeserver, Tree, Plt, Module, Records) ->
{TreeMap, FunHomes} = build_tree_map(Tree, Callgraph),
Funs = dict:fetch_keys(TreeMap),
FunTab = init_fun_tab(Funs, dict:new(), TreeMap, Callgraph, Plt),
- ExportedFuns =
- [Fun || Fun <- Funs--[top], dialyzer_callgraph:is_escaping(Fun, Callgraph)],
- Work = init_work(ExportedFuns),
+ ExportedFunctions =
+ [Fun ||
+ Fun <- Funs--[top],
+ dialyzer_callgraph:is_escaping(Fun, Callgraph),
+ dialyzer_callgraph:lookup_name(Fun, Callgraph) =/= error
+ ],
+ Work = init_work(ExportedFunctions),
Env = lists:foldl(fun(Fun, Env) -> dict:store(Fun, map__new(), Env) end,
dict:new(), Funs),
#state{callgraph = Callgraph, codeserver = Codeserver,
envs = Env, fun_tab = FunTab, fun_homes = FunHomes, opaques = Opaques,
plt = Plt, races = dialyzer_races:new(), records = Records,
warning_mode = false, warnings = [], work = Work, tree_map = TreeMap,
- module = Module}.
+ module = Module, reachable_funs = sets:new()}.
state__warning_mode(#state{warning_mode = WM}) ->
WM.
state__set_warning_mode(#state{tree_map = TreeMap, fun_tab = FunTab,
- races = Races} = State) ->
+ races = Races, callgraph = Callgraph,
+ reachable_funs = ReachableFuns} = State) ->
?debug("==========\nStarting warning pass\n==========\n", []),
Funs = dict:fetch_keys(TreeMap),
- State#state{work = init_work([top|Funs--[top]]),
+ Work =
+ [Fun ||
+ Fun <- Funs--[top],
+ dialyzer_callgraph:lookup_name(Fun, Callgraph) =/= error orelse
+ sets:is_element(Fun, ReachableFuns)],
+ State#state{work = init_work(Work),
fun_tab = FunTab, warning_mode = true,
races = dialyzer_races:put_race_analysis(true, Races)}.
@@ -3148,7 +3168,8 @@ state__get_race_warnings(#state{races = Races} = State) ->
State1#state{races = Races1}.
state__get_warnings(#state{tree_map = TreeMap, fun_tab = FunTab,
- callgraph = Callgraph, plt = Plt} = State) ->
+ callgraph = Callgraph, plt = Plt,
+ reachable_funs = ReachableFuns} = State) ->
FoldFun =
fun({top, _}, AccState) -> AccState;
({FunLbl, Fun}, AccState) ->
@@ -3183,7 +3204,12 @@ state__get_warnings(#state{tree_map = TreeMap, fun_tab = FunTab,
GenRet = dialyzer_contracts:get_contract_return(C),
not t_is_unit(GenRet)
end,
- case Warn of
+ %% Do not output warnings for unreachable funs.
+ case
+ Warn andalso
+ (dialyzer_callgraph:lookup_name(FunLbl, Callgraph) =/= error
+ orelse sets:is_element(FunLbl, ReachableFuns))
+ of
true ->
case classify_returns(Fun) of
no_match ->
@@ -3254,6 +3280,10 @@ state__get_args_and_status(Tree, #state{fun_tab = FunTab}) ->
{ok, {ArgTypes, _}} -> {ArgTypes, true}
end.
+state__add_reachable(FunLbl, #state{reachable_funs = ReachableFuns}=State) ->
+ NewReachableFuns = sets:add_element(FunLbl, ReachableFuns),
+ State#state{reachable_funs = NewReachableFuns}.
+
build_tree_map(Tree, Callgraph) ->
Fun =
fun(T, {Dict, Homes, FunLbls} = Acc) ->
@@ -3614,14 +3644,15 @@ format_args(ArgList0, TypeList, State) ->
"(" ++ format_args_1(ArgList, TypeList, State) ++ ")".
format_args_1([Arg], [Type], State) ->
- format_arg(Arg) ++ format_type(Type, State);
+ format_arg_1(Arg, Type, State);
format_args_1([Arg|Args], [Type|Types], State) ->
- String =
- case cerl:is_literal(Arg) of
- true -> format_cerl(Arg);
- false -> format_arg(Arg) ++ format_type(Type, State)
- end,
- String ++ "," ++ format_args_1(Args, Types, State).
+ format_arg_1(Arg, Type, State) ++ "," ++ format_args_1(Args, Types, State).
+
+format_arg_1(Arg, Type, State) ->
+ case cerl:is_literal(Arg) of
+ true -> format_cerl(Arg);
+ false -> format_arg(Arg) ++ format_type(Type, State)
+ end.
format_arg(Arg) ->
Default = "",
diff --git a/lib/dialyzer/src/dialyzer_gui_wx.erl b/lib/dialyzer/src/dialyzer_gui_wx.erl
index b4b1872c12..f47d90b91f 100644
--- a/lib/dialyzer/src/dialyzer_gui_wx.erl
+++ b/lib/dialyzer/src/dialyzer_gui_wx.erl
@@ -475,7 +475,7 @@ gui_loop(#gui_state{backend_pid = BackendPid, doc_plt = DocPlt,
gui_loop(State);
{BackendPid, ext_types, ExtTypes} ->
Map = fun({M,F,A}) -> io_lib:format("~tp:~tp/~p",[M,F,A]) end,
- ExtTypeString = string:join(lists:map(Map, ExtTypes), "\n"),
+ ExtTypeString = lists:join("\n", lists:map(Map, ExtTypes)),
Msg = io_lib:format("The following remote types are being used "
"but information about them is not available.\n"
"The analysis might get more precise by including "
@@ -638,7 +638,7 @@ output_sms(#gui_state{frame = Frame}, Title, Message, Type) ->
free_editor(#gui_state{gui = Wx, frame = Frame}, Title, Contents0) ->
Contents = lists:flatten(Contents0),
- Tokens = string:tokens(Contents, "\n"),
+ Tokens = string:lexemes(Contents, "\n"),
NofLines = length(Tokens),
LongestLine = lists:max([length(X) || X <- Tokens]),
Height0 = NofLines * 25 + 80,
@@ -1135,7 +1135,9 @@ handle_help(State, Title, Txt) ->
add_warnings(#gui_state{warnings_box = WarnBox,
rawWarnings = RawWarns} = State, Warnings) ->
NewRawWarns = RawWarns ++ Warnings,
- WarnList = [dialyzer:format_warning(W) -- "\n" || W <- NewRawWarns],
+ %% The indentation cannot be turned off.
+ WarnList = [string:trim(dialyzer:format_warning(W), trailing) ||
+ W <- NewRawWarns],
wxListBox:set(WarnBox, WarnList),
State#gui_state{rawWarnings = NewRawWarns}.
diff --git a/lib/dialyzer/src/dialyzer_options.erl b/lib/dialyzer/src/dialyzer_options.erl
index 03040f8e38..3b30036c1c 100644
--- a/lib/dialyzer/src/dialyzer_options.erl
+++ b/lib/dialyzer/src/dialyzer_options.erl
@@ -177,6 +177,8 @@ build_options([{OptionName, Value} = Term|Rest], Options) ->
filename_opt ->
assert_filename_opt(Value),
build_options(Rest, Options#options{filename_opt = Value});
+ indent_opt ->
+ build_options(Rest, Options#options{indent_opt = Value});
output_plt ->
assert_filename(Value),
build_options(Rest, Options#options{output_plt = Value});
diff --git a/lib/dialyzer/src/dialyzer_plt.erl b/lib/dialyzer/src/dialyzer_plt.erl
index 95c8b5ebce..2af4534396 100644
--- a/lib/dialyzer/src/dialyzer_plt.erl
+++ b/lib/dialyzer/src/dialyzer_plt.erl
@@ -531,17 +531,19 @@ compute_md5_from_files(Files) ->
lists:keysort(1, [{F, compute_md5_from_file(F)} || F <- Files]).
compute_md5_from_file(File) ->
- case filelib:is_regular(File) of
- false ->
+ case beam_lib:all_chunks(File) of
+ {ok, _, Chunks} ->
+ %% We cannot use beam_lib:md5 because it does not consider
+ %% the debug_info chunk, where typespecs are likely stored.
+ %% So we consider almost all chunks except the useless ones.
+ Filtered = [[ID, Chunk] || {ID, Chunk} <- Chunks, ID =/= "CInf", ID =/= "Docs"],
+ erlang:md5(lists:sort(Filtered));
+ {error, beam_lib, {file_error, _, enoent}} ->
Msg = io_lib:format("Not a regular file: ~ts\n", [File]),
throw({dialyzer_error, Msg});
- true ->
- case dialyzer_utils:get_core_from_beam(File) of
- {error, Error} ->
- throw({dialyzer_error, Error});
- {ok, Core} ->
- erlang:md5(term_to_binary(Core))
- end
+ {error, beam_lib, _} ->
+ Msg = io_lib:format("Could not compute MD5 for .beam: ~ts\n", [File]),
+ throw({dialyzer_error, Msg})
end.
init_diff_list(RemoveFiles, AddFiles) ->
diff --git a/lib/dialyzer/src/dialyzer_races.erl b/lib/dialyzer/src/dialyzer_races.erl
index 7fe64c3e11..7602faa21d 100644
--- a/lib/dialyzer/src/dialyzer_races.erl
+++ b/lib/dialyzer/src/dialyzer_races.erl
@@ -1270,8 +1270,8 @@ filter_named_tables(NamesList) ->
[] -> [];
[Head|Tail] ->
NewHead =
- case string:rstr(Head, "()") of
- 0 -> [Head];
+ case string:find(Head, "()", trailing) of
+ nomatch -> [Head];
_Other -> []
end,
NewHead ++ filter_named_tables(Tail)
@@ -1558,8 +1558,8 @@ any_args(StrList) ->
case StrList of
[] -> false;
[Head|Tail] ->
- case string:rstr(Head, "()") of
- 0 -> any_args(Tail);
+ case string:find(Head, "()", trailing) of
+ nomatch -> any_args(Tail);
_Other -> true
end
end.
@@ -1765,10 +1765,8 @@ ets_list_args(MaybeList) ->
end.
ets_list_argtypes(ListStr) ->
- ListStr1 = string:strip(ListStr, left, $[),
- ListStr2 = string:strip(ListStr1, right, $]),
- ListStr3 = string:strip(ListStr2, right, $.),
- string:strip(ListStr3, right, $,).
+ ListStr1 = string:trim(ListStr, leading, "$["),
+ string:trim(ListStr1, trailing, "$]$.$,").
ets_tuple_args(MaybeTuple) ->
case is_tuple(MaybeTuple) of
@@ -1810,7 +1808,7 @@ ets_tuple_argtypes2_helper(TupleStr, ElemStr, NestingLevel) ->
{[H|ElemStr], NestingLevel, false}
end,
case Return of
- true -> string:tokens(NewElemStr, " |");
+ true -> string:lexemes(NewElemStr, " |");
false ->
ets_tuple_argtypes2_helper(T, NewElemStr, NewNestingLevel)
end
@@ -1889,44 +1887,44 @@ format_args_2(StrArgList, Call) ->
case Call of
whereis ->
lists_key_replace(2, StrArgList,
- string:tokens(lists:nth(2, StrArgList), " |"));
+ string:lexemes(lists:nth(2, StrArgList), " |"));
register ->
lists_key_replace(2, StrArgList,
- string:tokens(lists:nth(2, StrArgList), " |"));
+ string:lexemes(lists:nth(2, StrArgList), " |"));
unregister ->
lists_key_replace(2, StrArgList,
- string:tokens(lists:nth(2, StrArgList), " |"));
+ string:lexemes(lists:nth(2, StrArgList), " |"));
ets_new ->
StrArgList1 = lists_key_replace(2, StrArgList,
- string:tokens(lists:nth(2, StrArgList), " |")),
+ string:lexemes(lists:nth(2, StrArgList), " |")),
lists_key_replace(4, StrArgList1,
- string:tokens(ets_list_argtypes(lists:nth(4, StrArgList1)), " |"));
+ string:lexemes(ets_list_argtypes(lists:nth(4, StrArgList1)), " |"));
ets_lookup ->
StrArgList1 = lists_key_replace(2, StrArgList,
- string:tokens(lists:nth(2, StrArgList), " |")),
+ string:lexemes(lists:nth(2, StrArgList), " |")),
lists_key_replace(4, StrArgList1,
- string:tokens(lists:nth(4, StrArgList1), " |"));
+ string:lexemes(lists:nth(4, StrArgList1), " |"));
ets_insert ->
StrArgList1 = lists_key_replace(2, StrArgList,
- string:tokens(lists:nth(2, StrArgList), " |")),
+ string:lexemes(lists:nth(2, StrArgList), " |")),
lists_key_replace(4, StrArgList1,
ets_tuple_argtypes2(
ets_tuple_argtypes1(lists:nth(4, StrArgList1), [], [], 0),
[]));
mnesia_dirty_read1 ->
lists_key_replace(2, StrArgList,
- [mnesia_tuple_argtypes(T) || T <- string:tokens(
+ [mnesia_tuple_argtypes(T) || T <- string:lexemes(
lists:nth(2, StrArgList), " |")]);
mnesia_dirty_read2 ->
lists_key_replace(2, StrArgList,
- string:tokens(lists:nth(2, StrArgList), " |"));
+ string:lexemes(lists:nth(2, StrArgList), " |"));
mnesia_dirty_write1 ->
lists_key_replace(2, StrArgList,
- [mnesia_record_tab(R) || R <- string:tokens(
+ [mnesia_record_tab(R) || R <- string:lexemes(
lists:nth(2, StrArgList), " |")]);
mnesia_dirty_write2 ->
lists_key_replace(2, StrArgList,
- string:tokens(lists:nth(2, StrArgList), " |"));
+ string:lexemes(lists:nth(2, StrArgList), " |"));
function_call -> StrArgList
end.
@@ -1943,18 +1941,16 @@ format_type(Type, State) ->
erl_types:t_to_string(Type, R).
mnesia_record_tab(RecordStr) ->
- case string:str(RecordStr, "#") =:= 1 of
- true ->
- "'" ++
- string:sub_string(RecordStr, 2, string:str(RecordStr, "{") - 1) ++
- "'";
- false -> RecordStr
+ case erl_scan:string(RecordStr) of
+ {ok, [{'#', _}, {atom, _, Name}|_], _} ->
+ io_lib:write_string(atom_to_list(Name), $');
+ _ -> RecordStr
end.
mnesia_tuple_argtypes(TupleStr) ->
- TupleStr1 = string:strip(TupleStr, left, ${),
- [TupleStr2|_T] = string:tokens(TupleStr1, " ,"),
- lists:flatten(string:tokens(TupleStr2, " |")).
+ TupleStr1 = string:trim(TupleStr, leading, "${"),
+ [TupleStr2|_T] = string:lexemes(TupleStr1, " ,"),
+ lists:flatten(string:lexemes(TupleStr2, " |")).
-spec race_var_map(var_to_map1(), var_to_map2(), dict:dict(), op()) ->
dict:dict().
@@ -2237,7 +2233,7 @@ var_type_analysis(FunDefArgs, FunCallTypes, WarnVarArgs, RaceWarnTag,
case lists_key_member_lists(Vars, FunVarArgs) of
0 -> [Vars, WVA2, WVA3, WVA4];
N when is_integer(N) ->
- NewWVA2 = string:tokens(lists:nth(N + 1, FunVarArgs), " |"),
+ NewWVA2 = string:lexemes(lists:nth(N + 1, FunVarArgs), " |"),
[Vars, NewWVA2, WVA3, WVA4]
end;
?WARN_WHEREIS_UNREGISTER ->
@@ -2246,7 +2242,7 @@ var_type_analysis(FunDefArgs, FunCallTypes, WarnVarArgs, RaceWarnTag,
case lists_key_member_lists(Vars, FunVarArgs) of
0 -> [Vars, WVA2];
N when is_integer(N) ->
- NewWVA2 = string:tokens(lists:nth(N + 1, FunVarArgs), " |"),
+ NewWVA2 = string:lexemes(lists:nth(N + 1, FunVarArgs), " |"),
[Vars, NewWVA2]
end;
?WARN_ETS_LOOKUP_INSERT ->
@@ -2256,7 +2252,7 @@ var_type_analysis(FunDefArgs, FunCallTypes, WarnVarArgs, RaceWarnTag,
case lists_key_member_lists(Vars1, FunVarArgs) of
0 -> [Vars1, WVA2];
N1 when is_integer(N1) ->
- NewWVA2 = string:tokens(lists:nth(N1 + 1, FunVarArgs), " |"),
+ NewWVA2 = string:lexemes(lists:nth(N1 + 1, FunVarArgs), " |"),
[Vars1, NewWVA2]
end,
Vars2 =
@@ -2286,10 +2282,10 @@ var_type_analysis(FunDefArgs, FunCallTypes, WarnVarArgs, RaceWarnTag,
NewWVA2 =
case Arity of
1 ->
- [mnesia_record_tab(R) || R <- string:tokens(
+ [mnesia_record_tab(R) || R <- string:lexemes(
lists:nth(2, FunVarArgs), " |")];
2 ->
- string:tokens(lists:nth(N + 1, FunVarArgs), " |")
+ string:lexemes(lists:nth(N + 1, FunVarArgs), " |")
end,
[Vars, NewWVA2|T]
end
diff --git a/lib/dialyzer/src/dialyzer_typesig.erl b/lib/dialyzer/src/dialyzer_typesig.erl
index d03326ec97..dede475f98 100644
--- a/lib/dialyzer/src/dialyzer_typesig.erl
+++ b/lib/dialyzer/src/dialyzer_typesig.erl
@@ -418,6 +418,11 @@ traverse(Tree, DefinedVars, State) ->
match_fail -> throw(error);
raise -> throw(error);
bs_init_writable -> {State, t_from_term(<<>>)};
+ build_stacktrace ->
+ V = mk_var(Tree),
+ Type = erl_bif_types:type(erlang, build_stacktrace, 0),
+ State1 = state__store_conj(V, sub, Type, State),
+ {State1, V};
Other -> erlang:error({'Unsupported primop', Other})
end;
'receive' ->
@@ -1895,9 +1900,8 @@ solver(Solver, SolveFun) ->
?debug("Solver ~w returned unexpected result:\n ~P\n",
[Solver, _R, 60]),
throw(error)
- catch E:R ->
- io:format("Solver ~w failed: ~w:~p\n ~tp\n",
- [Solver, E, R, erlang:get_stacktrace()]),
+ catch E:R:S ->
+ io:format("Solver ~w failed: ~w:~p\n ~tp\n", [Solver, E, R, S]),
throw(error)
end.
diff --git a/lib/dialyzer/src/dialyzer_utils.erl b/lib/dialyzer/src/dialyzer_utils.erl
index 9b8fbc67eb..245c099fef 100644
--- a/lib/dialyzer/src/dialyzer_utils.erl
+++ b/lib/dialyzer/src/dialyzer_utils.erl
@@ -46,6 +46,7 @@
]).
-include("dialyzer.hrl").
+-include("../../compiler/src/core_parse.hrl").
%%-define(DEBUG, true).
@@ -120,92 +121,10 @@ get_core_from_beam(File, Opts) ->
{error, " Could not get Core Erlang code for: " ++ File ++ "\n"}
end;
_ ->
- deprecated_get_core_from_beam(File, Opts)
+ {error, " Could not get Core Erlang code for: " ++ File ++ "\n" ++
+ " Recompile with +debug_info or analyze starting from source code"}
end.
-deprecated_get_core_from_beam(File, Opts) ->
- case get_abstract_code_from_beam(File) of
- error ->
- {error, " Could not get abstract code for: " ++ File ++ "\n" ++
- " Recompile with +debug_info or analyze starting from source code"};
- {ok, AbstrCode} ->
- case get_compile_options_from_beam(File) of
- error ->
- {error, " Could not get compile options for: " ++ File ++ "\n" ++
- " Recompile or analyze starting from source code"};
- {ok, CompOpts} ->
- case get_core_from_abstract_code(AbstrCode, Opts ++ CompOpts) of
- error ->
- {error, " Could not get core Erlang code for: " ++ File};
- {ok, _} = Core ->
- Core
- end
- end
- end.
-
-get_abstract_code_from_beam(File) ->
- case beam_lib:chunks(File, [abstract_code]) of
- {ok, {_, List}} ->
- case lists:keyfind(abstract_code, 1, List) of
- {abstract_code, {raw_abstract_v1, Abstr}} -> {ok, Abstr};
- _ -> error
- end;
- _ ->
- %% No or unsuitable abstract code.
- error
- end.
-
-get_compile_options_from_beam(File) ->
- case beam_lib:chunks(File, [compile_info]) of
- {ok, {_, List}} ->
- case lists:keyfind(compile_info, 1, List) of
- {compile_info, CompInfo} -> compile_info_to_options(CompInfo);
- _ -> error
- end;
- _ ->
- %% No or unsuitable compile info.
- error
- end.
-
-compile_info_to_options(CompInfo) ->
- case lists:keyfind(options, 1, CompInfo) of
- {options, CompOpts} -> {ok, CompOpts};
- _ -> error
- end.
-
-get_core_from_abstract_code(AbstrCode, Opts) ->
- %% We do not want the parse_transforms around since we already
- %% performed them. In some cases we end up in trouble when
- %% performing them again.
- AbstrCode1 = cleanup_parse_transforms(AbstrCode),
- %% Remove parse_transforms (and other options) from compile options.
- Opts2 = cleanup_compile_options(Opts),
- try compile:noenv_forms(AbstrCode1, Opts2 ++ src_compiler_opts()) of
- {ok, _, Core} -> {ok, Core};
- _What -> error
- catch
- error:_ -> error
- end.
-
-cleanup_parse_transforms([{attribute, _, compile, {parse_transform, _}}|Left]) ->
- cleanup_parse_transforms(Left);
-cleanup_parse_transforms([Other|Left]) ->
- [Other|cleanup_parse_transforms(Left)];
-cleanup_parse_transforms([]) ->
- [].
-
-cleanup_compile_options(Opts) ->
- lists:filter(fun keep_compile_option/1, Opts).
-
-%% Using abstract, not asm or core.
-keep_compile_option(from_asm) -> false;
-keep_compile_option(from_core) -> false;
-%% The parse transform will already have been applied, may cause
-%% problems if it is re-applied.
-keep_compile_option({parse_transform, _}) -> false;
-keep_compile_option(warnings_as_errors) -> false;
-keep_compile_option(_) -> true.
-
%% ============================================================================
%%
%% Typed Records
@@ -532,8 +451,9 @@ get_spec_info([{Contract, Ln, [{Id, TypeSpec}]}|Left],
error ->
SpecData = {TypeSpec, Xtra},
NewActiveMap =
- dialyzer_contracts:store_tmp_contract(MFA, {File, Ln}, SpecData,
- ActiveMap, RecordsMap),
+ dialyzer_contracts:store_tmp_contract(ModName, MFA, {File, Ln},
+ SpecData, ActiveMap,
+ RecordsMap),
{NewSpecMap, NewCallbackMap} =
case Contract of
spec -> {NewActiveMap, CallbackMap};
@@ -681,24 +601,32 @@ collect_attribute([], _Tag, _File) ->
-spec is_suppressed_fun(mfa(), codeserver()) -> boolean().
is_suppressed_fun(MFA, CodeServer) ->
- lookup_fun_property(MFA, nowarn_function, CodeServer).
+ lookup_fun_property(MFA, nowarn_function, CodeServer, false).
-spec is_suppressed_tag(mfa() | module(), dial_warn_tag(), codeserver()) ->
boolean().
is_suppressed_tag(MorMFA, Tag, Codeserver) ->
- not lookup_fun_property(MorMFA, Tag, Codeserver).
-
-lookup_fun_property({M, _F, _A}=MFA, Property, CodeServer) ->
- MFAPropList = dialyzer_codeserver:lookup_meta_info(MFA, CodeServer),
- case proplists:get_value(Property, MFAPropList, no) of
- mod -> false; % suppressed in function
- func -> true; % requested in function
- no -> lookup_fun_property(M, Property, CodeServer)
+ not lookup_fun_property(MorMFA, Tag, Codeserver, true).
+
+lookup_fun_property({M, _F, _A}=MFA, Property, CodeServer, NoInfoReturn) ->
+ case dialyzer_codeserver:lookup_meta_info(MFA, CodeServer) of
+ error ->
+ lookup_fun_property(M, Property, CodeServer, NoInfoReturn);
+ {ok, MFAPropList} ->
+ case proplists:get_value(Property, MFAPropList, no) of
+ mod -> false; % suppressed in function
+ func -> true; % requested in function
+ no -> lookup_fun_property(M, Property, CodeServer, NoInfoReturn)
+ end
end;
-lookup_fun_property(M, Property, CodeServer) when is_atom(M) ->
- MPropList = dialyzer_codeserver:lookup_meta_info(M, CodeServer),
- proplists:is_defined(Property, MPropList).
+lookup_fun_property(M, Property, CodeServer, NoInfoReturn) when is_atom(M) ->
+ case dialyzer_codeserver:lookup_meta_info(M, CodeServer) of
+ error ->
+ NoInfoReturn;
+ {ok, MPropList} ->
+ proplists:is_defined(Property, MPropList)
+ end.
%% ============================================================================
%%
@@ -725,7 +653,7 @@ sets_filter([Mod|Mods], ExpTypes) ->
src_compiler_opts() ->
[no_copt, to_core, binary, return_errors,
no_inline, strict_record_tests, strict_record_updates,
- dialyzer].
+ dialyzer, no_spawn_compiler_process].
-spec format_errors([{module(), string()}]) -> [string()].
@@ -824,9 +752,13 @@ pp_hook(Node, Ctxt, Cont) ->
map ->
pp_map(Node, Ctxt, Cont);
literal ->
- case is_map(cerl:concrete(Node)) of
- true -> pp_map(Node, Ctxt, Cont);
- false -> Cont(Node, Ctxt)
+ case cerl:concrete(Node) of
+ Map when is_map(Map) ->
+ pp_map(Node, Ctxt, Cont);
+ Bitstr when is_bitstring(Bitstr) ->
+ pp_binary(Node, Ctxt, Cont);
+ _ ->
+ Cont(Node, Ctxt)
end;
_ ->
Cont(Node, Ctxt)
@@ -834,7 +766,7 @@ pp_hook(Node, Ctxt, Cont) ->
pp_binary(Node, Ctxt, Cont) ->
prettypr:beside(prettypr:text("<<"),
- prettypr:beside(pp_segments(cerl:binary_segments(Node),
+ prettypr:beside(pp_segments(cerl_binary_segments(Node),
Ctxt, Cont),
prettypr:text(">>"))).
@@ -853,10 +785,29 @@ pp_segment(Node, Ctxt, Cont) ->
Unit = cerl:bitstr_unit(Node),
Type = cerl:bitstr_type(Node),
Flags = cerl:bitstr_flags(Node),
- prettypr:beside(Cont(Val, Ctxt),
- prettypr:beside(pp_size(Size, Ctxt, Cont),
- prettypr:beside(pp_opts(Type, Flags),
- pp_unit(Unit, Ctxt, Cont)))).
+ RestPP =
+ case {concrete(Unit), concrete(Type), concrete(Flags)} of
+ {1, integer, [unsigned, big]} -> % Simplify common cases.
+ case concrete(Size) of
+ 8 -> prettypr:text("");
+ _ -> pp_size(Size, Ctxt, Cont)
+ end;
+ {8, binary, [unsigned, big]} ->
+ SizePP = pp_size(Size, Ctxt, Cont),
+ prettypr:beside(SizePP,
+ prettypr:beside(prettypr:text("/"), pp_atom(Type)));
+ _What ->
+ SizePP = pp_size(Size, Ctxt, Cont),
+ UnitPP = pp_unit(Unit, Ctxt, Cont),
+ OptsPP = pp_opts(Type, Flags),
+ prettypr:beside(SizePP, prettypr:beside(OptsPP, UnitPP))
+ end,
+ prettypr:beside(Cont(Val, Ctxt), RestPP).
+
+concrete(Cerl) ->
+ try cerl:concrete(Cerl)
+ catch _:_ -> anything_unexpected
+ end.
pp_size(Size, Ctxt, Cont) ->
case cerl:is_c_atom(Size) of
@@ -932,6 +883,31 @@ seq([H | T], Separator, Ctxt, Fun) ->
seq([], _, _, _) ->
[prettypr:empty()].
+cerl_binary_segments(#c_literal{val = B}) when is_bitstring(B) ->
+ segs_from_bitstring(B);
+cerl_binary_segments(CBinary) ->
+ cerl:binary_segments(CBinary).
+
+%% Copied from core_pp. The function cerl:binary_segments/2 should/could
+%% be extended to handle literals, but then the cerl module cannot be
+%% HiPE-compiled as of Erlang/OTP 22.0 (due to <<I:N>>).
+segs_from_bitstring(<<H,T/bitstring>>) ->
+ [#c_bitstr{val=#c_literal{val=H},
+ size=#c_literal{val=8},
+ unit=#c_literal{val=1},
+ type=#c_literal{val=integer},
+ flags=#c_literal{val=[unsigned,big]}}|segs_from_bitstring(T)];
+segs_from_bitstring(<<>>) ->
+ [];
+segs_from_bitstring(Bitstring) ->
+ N = bit_size(Bitstring),
+ <<I:N>> = Bitstring,
+ [#c_bitstr{val=#c_literal{val=I},
+ size=#c_literal{val=N},
+ unit=#c_literal{val=1},
+ type=#c_literal{val=integer},
+ flags=#c_literal{val=[unsigned,big]}}].
+
%%------------------------------------------------------------------------------
-spec refold_pattern(cerl:cerl()) -> cerl:cerl().
diff --git a/lib/dialyzer/src/typer.erl b/lib/dialyzer/src/typer.erl
index 16b9c8a94a..5a1b8619c9 100644
--- a/lib/dialyzer/src/typer.erl
+++ b/lib/dialyzer/src/typer.erl
@@ -164,9 +164,9 @@ get_type_info(#analysis{callgraph = CallGraph,
CodeServer),
Analysis#analysis{callgraph = StrippedCallGraph, trust_plt = NewPlt}
catch
- error:What ->
+ error:What:Stacktrace ->
fatal_error(io_lib:format("Analysis failed with message: ~tp",
- [{What, erlang:get_stacktrace()}]));
+ [{What, Stacktrace}]));
throw:{dialyzer_succ_typing_error, Msg} ->
fatal_error(io_lib:format("Analysis failed with message: ~ts", [Msg]))
end.
@@ -401,7 +401,7 @@ get_type({{M, F, A} = MFA, Range, Arg}, CodeServer, Records) ->
Sig = erl_types:t_fun(Arg, Range),
case dialyzer_contracts:check_contract(Contract, Sig) of
ok -> {{F, A}, {contract, Contract}};
- {error, {extra_range, _, _}} ->
+ {range_warnings, _} ->
{{F, A}, {contract, Contract}};
{error, {overlapping_contract, []}} ->
{{F, A}, {contract, Contract}};
@@ -980,7 +980,7 @@ fatal_error(Slogan) ->
mode_error(OldMode, NewMode) ->
Msg = io_lib:format("Mode was previously set to '~s'; "
- "can not set it to '~s' now",
+ "cannot set it to '~s' now",
[OldMode, NewMode]),
fatal_error(Msg).
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/dialyzer_options b/lib/dialyzer/test/behaviour_SUITE_data/dialyzer_options
index 365b4798c5..83d4a0ec35 100644
--- a/lib/dialyzer/test/behaviour_SUITE_data/dialyzer_options
+++ b/lib/dialyzer/test/behaviour_SUITE_data/dialyzer_options
@@ -1,2 +1,2 @@
-{dialyzer_options, []}.
+{dialyzer_options, [{indent_opt, false}]}.
{time_limit, 5}.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_incorrect_args b/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_incorrect_args
index 1eb8cd455b..1be0ce0d8c 100644
--- a/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_incorrect_args
+++ b/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_incorrect_args
@@ -1,5 +1,5 @@
gen_server_incorrect_args.erl:3: Undefined callback function handle_cast/2 (behaviour gen_server)
gen_server_incorrect_args.erl:3: Undefined callback function init/1 (behaviour gen_server)
-gen_server_incorrect_args.erl:7: The inferred return type of handle_call/3 ({'no'} | {'ok'}) has nothing in common with {'noreply',_} | {'noreply',_,'hibernate' | 'infinity' | non_neg_integer()} | {'reply',_,_} | {'stop',_,_} | {'reply',_,_,'hibernate' | 'infinity' | non_neg_integer()} | {'stop',_,_,_}, which is the expected return type for the callback of the gen_server behaviour
+gen_server_incorrect_args.erl:7: The inferred return type of handle_call/3 ({'no'} | {'ok'}) has nothing in common with {'noreply',_} | {'noreply',_,'hibernate' | 'infinity' | non_neg_integer() | {'continue',_}} | {'reply',_,_} | {'stop',_,_} | {'reply',_,_,'hibernate' | 'infinity' | non_neg_integer() | {'continue',_}} | {'stop',_,_,_}, which is the expected return type for the callback of the gen_server behaviour
gen_server_incorrect_args.erl:7: The inferred type for the 2nd argument of handle_call/3 ('boo' | 'foo') is not a supertype of {pid(),_}, which is expected type for this argument in the callback of the gen_server behaviour
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/proper/proper_typeserver.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/proper/proper_typeserver.erl
index b16075763f..12f6532c0c 100644
--- a/lib/dialyzer/test/behaviour_SUITE_data/src/proper/proper_typeserver.erl
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/proper/proper_typeserver.erl
@@ -539,7 +539,7 @@ apply_spec_test({Mod,Fun,_Arity}=MFA, {_Domain,Range}, SpecTimeout, FalsePositiv
try apply(Mod, Fun, Args) of
X -> {ok, X}
catch
- X:Y -> {X, Y}
+ X:Y:S -> {{X, Y}, S}
end,
case Result of
{ok, Z} ->
@@ -551,15 +551,15 @@ apply_spec_test({Mod,Fun,_Arity}=MFA, {_Domain,Range}, SpecTimeout, FalsePositiv
false ->
false
end;
- Exception when is_function(FalsePositiveMFAs) ->
+ {Exception, S2} when is_function(FalsePositiveMFAs) ->
case FalsePositiveMFAs(MFA, Args, Exception) of
true ->
true;
false ->
- error(Exception, erlang:get_stacktrace())
+ error(Exception, S2)
end;
- Exception ->
- error(Exception, erlang:get_stacktrace())
+ {Exception, S3} ->
+ error(Exception, S3)
end
end).
diff --git a/lib/dialyzer/test/callgraph_SUITE_data/dialyzer_options b/lib/dialyzer/test/callgraph_SUITE_data/dialyzer_options
index 50991c9bc5..8413436b67 100644
--- a/lib/dialyzer/test/callgraph_SUITE_data/dialyzer_options
+++ b/lib/dialyzer/test/callgraph_SUITE_data/dialyzer_options
@@ -1 +1 @@
-{dialyzer_options, []}.
+{dialyzer_options, [{indent_opt, false}]}.
diff --git a/lib/dialyzer/test/dialyzer_common.erl b/lib/dialyzer/test/dialyzer_common.erl
index 48083a2731..beaf126344 100644
--- a/lib/dialyzer/test/dialyzer_common.erl
+++ b/lib/dialyzer/test/dialyzer_common.erl
@@ -147,7 +147,8 @@ check(TestCase, Opts, Dir, OutDir) ->
try dialyzer:run([{files, Files},{from, src_code},{init_plt, PltFilename},
{check_plt, false}|ProperOpts]) of
RawWarns ->
- Warns = lists:sort([dialyzer:format_warning(W) || W <- RawWarns]),
+ Warns = lists:sort([dialyzer:format_warning(W, ProperOpts) ||
+ W <- RawWarns]),
case Warns of
[] -> ok;
_ ->
@@ -221,13 +222,9 @@ get_suites(Dir) ->
end.
suffix(String, Suffix) ->
- case string:rstr(String, Suffix) of
- 0 -> no;
- Index ->
- case string:substr(String, Index) =:= Suffix of
- true -> {yes, string:sub_string(String,1,Index-1)};
- false -> no
- end
+ case string:split(String, Suffix, trailing) of
+ [Prefix,[]] -> {yes, Prefix};
+ _ -> no
end.
-spec create_suite(string()) -> 'ok'.
diff --git a/lib/dialyzer/test/indent2_SUITE_data/dialyzer_options b/lib/dialyzer/test/indent2_SUITE_data/dialyzer_options
new file mode 100644
index 0000000000..ee07090337
--- /dev/null
+++ b/lib/dialyzer/test/indent2_SUITE_data/dialyzer_options
@@ -0,0 +1 @@
+{dialyzer_options, [{warnings, [no_unused, no_return, specdiffs]}]}.
diff --git a/lib/dialyzer/test/indent2_SUITE_data/results/arr b/lib/dialyzer/test/indent2_SUITE_data/results/arr
new file mode 100644
index 0000000000..77e67f0cab
--- /dev/null
+++ b/lib/dialyzer/test/indent2_SUITE_data/results/arr
@@ -0,0 +1,15 @@
+
+arr.erl:14: Type specification arr:test2
+ (array:array(T), non_neg_integer(), T) -> array:array(T) is a supertype of the success typing: arr:test2
+ (array:array(_), pos_integer(), _) -> array:array(_)
+arr.erl:24: Type specification arr:test4
+ (array:array(T), non_neg_integer(), _) -> array:array(T) is a supertype of the success typing: arr:test4
+ (array:array(_), pos_integer(), _) -> array:array(_)
+arr.erl:29: Type specification arr:test5
+ (array:array(T), non_neg_integer(), T) -> array:array(T) is a supertype of the success typing: arr:test5
+ (array:array(_), non_neg_integer(), integer()) ->
+ array:array(_)
+arr.erl:37: Type specification arr:test6
+ (array:array(integer()), non_neg_integer(), integer()) ->
+ array:array(any()) is not equal to the success typing: arr:test6
+ (array:array(_), non_neg_integer(), _) -> array:array(_)
diff --git a/lib/dialyzer/test/indent2_SUITE_data/results/iodata b/lib/dialyzer/test/indent2_SUITE_data/results/iodata
new file mode 100644
index 0000000000..d95551d330
--- /dev/null
+++ b/lib/dialyzer/test/indent2_SUITE_data/results/iodata
@@ -0,0 +1,24 @@
+
+iodata.erl:7: The specification for iodata:encode/2 states that the function might also return
+ binary() but the inferred return is
+ nonempty_maybe_improper_list(<<_:8, _:_*8>> |
+ nonempty_maybe_improper_list(<<_:8,
+ _:_*8>> |
+ nonempty_maybe_improper_list(any(),
+ <<_:8,
+ _:_*8>> |
+ []) |
+ byte(),
+ <<_:8,
+ _:_*8>> |
+ []) |
+ integer(),
+ <<_:8, _:_*8>> | []) |
+ integer()
+iodata.erl:7: The success typing for iodata:encode/2 implies that the function might also return
+ integer() but the specification return is
+ binary() |
+ maybe_improper_list(binary() |
+ maybe_improper_list(any(), binary() | []) |
+ byte(),
+ binary() | [])
diff --git a/lib/dialyzer/test/indent2_SUITE_data/results/remote b/lib/dialyzer/test/indent2_SUITE_data/results/remote
new file mode 100644
index 0000000000..6decec6c6a
--- /dev/null
+++ b/lib/dialyzer/test/indent2_SUITE_data/results/remote
@@ -0,0 +1,25 @@
+
+remotes1.erl:17: The specification for remotes1:foo5/1 states that the function might also return
+ 'ko' but the inferred return is
+ 'ok'
+remotes1.erl:20: Type specification remotes1:foo6
+ ('ok' | 'ko') -> 'ok' is a supertype of the success typing: remotes1:foo6
+ ('ok') -> 'ok'
+remotes1.erl:25: The specification for remotes1:foo7/1 states that the function might also return
+ 'ko' but the inferred return is
+ 'ok'
+remotes1.erl:28: Type specification remotes1:foo8
+ (local_type_42()) -> 'ok' is a supertype of the success typing: remotes1:foo8
+ ('ok') -> 'ok'
+remotes1.erl:33: The specification for remotes1:foo9/1 states that the function might also return
+ 'ko' but the inferred return is
+ 'ok'
+remotes1.erl:36: Type specification remotes1:foo10
+ (local_and_known_remote_type_42()) -> 'ok' is a supertype of the success typing: remotes1:foo10
+ ('ok') -> 'ok'
+remotes1.erl:49: Type specification remotes1:foo13
+ ('ok') -> local_and_unknown_remote_type_42() is a supertype of the success typing: remotes1:foo13
+ ('ok') -> 'ok'
+remotes1.erl:52: Type specification remotes1:foo14
+ (local_and_unknown_remote_type_42()) -> 'ok' is a supertype of the success typing: remotes1:foo14
+ ('ok') -> 'ok'
diff --git a/lib/dialyzer/test/indent2_SUITE_data/src/arr.erl b/lib/dialyzer/test/indent2_SUITE_data/src/arr.erl
new file mode 100644
index 0000000000..3b265ccec2
--- /dev/null
+++ b/lib/dialyzer/test/indent2_SUITE_data/src/arr.erl
@@ -0,0 +1,41 @@
+-module(arr).
+
+%% http://erlang.org/pipermail/erlang-questions/2014-August/080445.html
+
+-define(A, array).
+
+-export([test/3, test2/3, test3/3, test4/3, test5/3, test6/3]).
+
+-spec test(?A:array(T), non_neg_integer(), T) -> ?A:array(T).
+
+test(Array, N, Value) ->
+ ?A:set(N, Value, Array).
+
+-spec test2(?A:array(T), non_neg_integer(), T) -> ?A:array(T).
+
+test2(Array, N, Value) when N > 0 ->
+ ?A:set(N, Value, Array).
+
+-spec test3(?A:array(T), non_neg_integer(), _) -> ?A:array(T).
+
+test3(Array, N, Value) ->
+ ?A:set(N, Value, Array).
+
+-spec test4(?A:array(T), non_neg_integer(), _) -> ?A:array(T).
+
+test4(Array, N, Value) when N > 0 ->
+ ?A:set(N, Value, Array).
+
+-spec test5(?A:array(T), non_neg_integer(), T) -> ?A:array(T).
+
+test5(Array, N, Value) when is_integer(Value) ->
+ ?A:set(N, Value, Array).
+
+%% One would ideally want a warning also for test6(), but the current
+%% analysis of parametrized opaque types is not strong enough to
+%% discover this.
+-spec test6(?A:array(integer()), non_neg_integer(), integer()) ->
+ ?A:array(any()).
+
+test6(Array, N, Value) ->
+ ?A:set(N, Value, Array).
diff --git a/lib/dialyzer/test/indent2_SUITE_data/src/iodata.erl b/lib/dialyzer/test/indent2_SUITE_data/src/iodata.erl
new file mode 100644
index 0000000000..caa44f6c91
--- /dev/null
+++ b/lib/dialyzer/test/indent2_SUITE_data/src/iodata.erl
@@ -0,0 +1,41 @@
+-module(iodata).
+
+%% A small part of beam_asm.
+
+-export([encode/2]).
+
+-spec encode(non_neg_integer(), integer()) -> iodata(). % extra range binary()
+
+encode(Tag, N) when Tag >= 0, N < 0 ->
+ encode1(Tag, negative_to_bytes(N));
+encode(Tag, N) when Tag >= 0, N < 16 ->
+ (N bsl 4) bor Tag; % not in the specification
+encode(Tag, N) when Tag >= 0, N < 16#800 ->
+ [((N bsr 3) band 2#11100000) bor Tag bor 2#00001000, N band 16#ff];
+encode(Tag, N) when Tag >= 0 ->
+ encode1(Tag, to_bytes(N)).
+
+encode1(Tag, Bytes) ->
+ case iolist_size(Bytes) of
+ Num when 2 =< Num, Num =< 8 ->
+ [((Num-2) bsl 5) bor 2#00011000 bor Tag| Bytes];
+ Num when 8 < Num ->
+ [2#11111000 bor Tag, encode(0, Num-9)| Bytes]
+ end.
+
+to_bytes(N) ->
+ Bin = binary:encode_unsigned(N),
+ case Bin of
+ <<0:1,_/bits>> -> Bin;
+ <<1:1,_/bits>> -> [0,Bin]
+ end.
+
+negative_to_bytes(N) when N >= -16#8000 ->
+ <<N:16>>;
+negative_to_bytes(N) ->
+ Bytes = byte_size(binary:encode_unsigned(-N)),
+ Bin = <<N:Bytes/unit:8>>,
+ case Bin of
+ <<0:1,_/bits>> -> [16#ff,Bin];
+ <<1:1,_/bits>> -> Bin
+ end.
diff --git a/lib/dialyzer/test/indent2_SUITE_data/src/remote/remotes1.erl b/lib/dialyzer/test/indent2_SUITE_data/src/remote/remotes1.erl
new file mode 100644
index 0000000000..b722495095
--- /dev/null
+++ b/lib/dialyzer/test/indent2_SUITE_data/src/remote/remotes1.erl
@@ -0,0 +1,61 @@
+-module(remotes1).
+
+-compile(export_all).
+
+-spec foo1(some_unknown_remote:type42()) -> ok.
+foo1(ok) -> ok.
+
+-spec foo2(ok) -> some_unknown_remote:type42().
+foo2(ok) -> ok.
+
+-spec foo3(some_known_remote:type42()) -> ok.
+foo3(ok) -> ok.
+
+-spec foo4(ok) -> some_known_remote:type42().
+foo4(ok) -> ok.
+
+-spec foo5(ok|ko) -> ok|ko.
+foo5(ok) -> ok.
+
+-spec foo6(ok|ko) -> ok.
+foo6(ok) -> ok.
+
+-type local_type_42() :: ok | ko.
+
+-spec foo7(ok) -> local_type_42().
+foo7(ok) -> ok.
+
+-spec foo8(local_type_42()) -> ok.
+foo8(ok) -> ok.
+
+-type local_and_known_remote_type_42() :: some_known_remote:type42() | ok | ko.
+
+-spec foo9(ok) -> local_and_known_remote_type_42().
+foo9(ok) -> ok.
+
+-spec foo10(local_and_known_remote_type_42()) -> ok.
+foo10(ok) -> ok.
+
+-type local_and_ok_known_remote_type_42() :: some_known_remote:type42() | ok.
+
+-spec foo11(ok) -> local_and_ok_known_remote_type_42().
+foo11(ok) -> ok.
+
+-spec foo12(local_and_ok_known_remote_type_42()) -> ok.
+foo12(ok) -> ok.
+
+-type local_and_unknown_remote_type_42() :: some_unknown_remote:type42() | ok | ko.
+
+-spec foo13(ok) -> local_and_unknown_remote_type_42().
+foo13(ok) -> ok.
+
+-spec foo14(local_and_unknown_remote_type_42()) -> ok.
+foo14(ok) -> ok.
+
+-type local_and_ok_unknown_remote_type_42() :: some_unknown_remote:type42() | ok.
+
+-spec foo15(ok) -> local_and_ok_unknown_remote_type_42().
+foo15(ok) -> ok.
+
+-spec foo16(local_and_ok_unknown_remote_type_42()) -> ok.
+foo16(ok) -> ok.
diff --git a/lib/dialyzer/test/indent2_SUITE_data/src/remote/some_known_remote.erl b/lib/dialyzer/test/indent2_SUITE_data/src/remote/some_known_remote.erl
new file mode 100644
index 0000000000..437f1e7826
--- /dev/null
+++ b/lib/dialyzer/test/indent2_SUITE_data/src/remote/some_known_remote.erl
@@ -0,0 +1,5 @@
+-module(some_known_remote).
+
+-export_type([type42/0]).
+
+-type type42() :: ok | ko.
diff --git a/lib/dialyzer/test/indent_SUITE_data/dialyzer_options b/lib/dialyzer/test/indent_SUITE_data/dialyzer_options
new file mode 100644
index 0000000000..7c088f9a65
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/dialyzer_options
@@ -0,0 +1 @@
+{dialyzer_options, [{warnings, [no_unused, no_return, race_conditions]}]}.
diff --git a/lib/dialyzer/test/indent_SUITE_data/results/abs b/lib/dialyzer/test/indent_SUITE_data/results/abs
new file mode 100644
index 0000000000..ac663a4e80
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/abs
@@ -0,0 +1,13 @@
+
+abs.erl:16: The pattern
+ 'true' can never match the type
+ 'false'
+abs.erl:27: The pattern
+ 'true' can never match the type
+ 'false'
+abs.erl:37: The pattern
+ 'true' can never match the type
+ 'false'
+abs.erl:49: The pattern
+ 'true' can never match the type
+ 'false'
diff --git a/lib/dialyzer/test/indent_SUITE_data/results/app_call b/lib/dialyzer/test/indent_SUITE_data/results/app_call
new file mode 100644
index 0000000000..729587b5c6
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/app_call
@@ -0,0 +1,9 @@
+
+app_call.erl:6: The call M:'foo'
+ () requires that M is of type
+ atom() not
+ 42
+app_call.erl:9: The call 'mod':F
+ () requires that F is of type
+ atom() not
+ {'gazonk', []}
diff --git a/lib/dialyzer/test/indent_SUITE_data/results/arr b/lib/dialyzer/test/indent_SUITE_data/results/arr
new file mode 100644
index 0000000000..9497d12eec
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/arr
@@ -0,0 +1,4 @@
+
+arr.erl:14: Type specification arr:test2(array:array(T),non_neg_integer(),T) -> array:array(T) is a supertype of the success typing: arr:test2(array:array(_),pos_integer(),_) -> array:array(_)
+arr.erl:24: Type specification arr:test4(array:array(T),non_neg_integer(),_) -> array:array(T) is a supertype of the success typing: arr:test4(array:array(_),pos_integer(),_) -> array:array(_)
+arr.erl:29: Type specification arr:test5(array:array(T),non_neg_integer(),T) -> array:array(T) is a supertype of the success typing: arr:test5(array:array(_),non_neg_integer(),integer()) -> array:array(_)
diff --git a/lib/dialyzer/test/indent_SUITE_data/results/blame_contract_range b/lib/dialyzer/test/indent_SUITE_data/results/blame_contract_range
new file mode 100644
index 0000000000..287d23d91f
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/blame_contract_range
@@ -0,0 +1,8 @@
+
+blame_contract_range.erl:14: The contract blame_contract_range:bar
+ (atom()) -> 'a' cannot be right because the inferred return for bar
+ ('b') on line 12 is
+ 'b'
+blame_contract_range.erl:15: The pattern
+ 'a' can never match the type
+ 'b'
diff --git a/lib/dialyzer/test/indent_SUITE_data/results/bs_fail_constr b/lib/dialyzer/test/indent_SUITE_data/results/bs_fail_constr
new file mode 100644
index 0000000000..86f1329bf3
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/bs_fail_constr
@@ -0,0 +1,9 @@
+
+bs_fail_constr.erl:12: Binary construction will fail since the size field S in segment 42:S has type
+ neg_integer()
+bs_fail_constr.erl:15: Binary construction will fail since the value field V in segment V/utf32 has type
+ float()
+bs_fail_constr.erl:6: Binary construction will fail since the value field V in segment V has type
+ float()
+bs_fail_constr.erl:9: Binary construction will fail since the value field V in segment V/binary has type
+ atom()
diff --git a/lib/dialyzer/test/indent_SUITE_data/results/callbacks_and_specs b/lib/dialyzer/test/indent_SUITE_data/results/callbacks_and_specs
new file mode 100644
index 0000000000..dd9d3397d2
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/callbacks_and_specs
@@ -0,0 +1,23 @@
+
+my_callbacks_wrong.erl:26: The return type
+ #state{parent :: pid(),
+ status :: 'closed' | 'init' | 'open',
+ subscribe :: [{pid(), integer()}],
+ counter :: integer()} in the specification of callback_init/1 is not a subtype of
+ {'ok', _}, which is the expected return type for the callback of the my_behaviour behaviour
+my_callbacks_wrong.erl:28: The inferred return type of callback_init/1
+ (#state{parent :: pid(),
+ status :: 'init',
+ subscribe :: [],
+ counter :: 1}) has nothing in common with
+ {'ok', _}, which is the expected return type for the callback of the my_behaviour behaviour
+my_callbacks_wrong.erl:30: The return type
+ {'reply',
+ #state{parent :: pid(),
+ status :: 'closed' | 'init' | 'open',
+ subscribe :: [{pid(), integer()}],
+ counter :: integer()}} in the specification of callback_cast/3 is not a subtype of
+ {'noreply', _}, which is the expected return type for the callback of the my_behaviour behaviour
+my_callbacks_wrong.erl:39: The specified type for the 2nd argument of callback_call/3 (
+ atom()) is not a supertype of
+ pid(), which is expected type for this argument in the callback of the my_behaviour behaviour
diff --git a/lib/dialyzer/test/indent_SUITE_data/results/contract3 b/lib/dialyzer/test/indent_SUITE_data/results/contract3
new file mode 100644
index 0000000000..6e111f87d9
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/contract3
@@ -0,0 +1,3 @@
+
+contract3.erl:17: Overloaded contract for contract3:t1/1 has overlapping domains; such contracts are currently unsupported and are simply ignored
+contract3.erl:29: Overloaded contract for contract3:t3/3 has overlapping domains; such contracts are currently unsupported and are simply ignored
diff --git a/lib/dialyzer/test/indent_SUITE_data/results/contracts_with_subtypes b/lib/dialyzer/test/indent_SUITE_data/results/contracts_with_subtypes
new file mode 100644
index 0000000000..737959a49d
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/contracts_with_subtypes
@@ -0,0 +1,142 @@
+
+contracts_with_subtypes.erl:106: The call contracts_with_subtypes:rec_arg
+ ({'a', 'b'}) breaks the contract
+ (Arg) -> 'ok'
+ when
+ Arg :: {'a', A} | {'b', B},
+ A :: 'a' | {'b', B},
+ B :: 'b' | {'a', A}
+contracts_with_subtypes.erl:107: The call contracts_with_subtypes:rec_arg
+ ({'b', 'a'}) breaks the contract
+ (Arg) -> 'ok'
+ when
+ Arg :: {'a', A} | {'b', B},
+ A :: 'a' | {'b', B},
+ B :: 'b' | {'a', A}
+contracts_with_subtypes.erl:109: The call contracts_with_subtypes:rec_arg
+ ({'b', {'a', 'b'}}) breaks the contract
+ (Arg) -> 'ok'
+ when
+ Arg :: {'a', A} | {'b', B},
+ A :: 'a' | {'b', B},
+ B :: 'b' | {'a', A}
+contracts_with_subtypes.erl:135: The call contracts_with_subtypes:rec2
+ ({'a', 'b'}) breaks the contract
+ (Arg) -> 'ok' when Arg :: ab()
+contracts_with_subtypes.erl:136: The call contracts_with_subtypes:rec2
+ ({'b', 'a'}) breaks the contract
+ (Arg) -> 'ok' when Arg :: ab()
+contracts_with_subtypes.erl:137: The call contracts_with_subtypes:rec2
+ ({'a', {'b', 'a'}}) breaks the contract
+ (Arg) -> 'ok' when Arg :: ab()
+contracts_with_subtypes.erl:138: The call contracts_with_subtypes:rec2
+ ({'b', {'a', 'b'}}) breaks the contract
+ (Arg) -> 'ok' when Arg :: ab()
+contracts_with_subtypes.erl:139: The call contracts_with_subtypes:rec2
+ ({'a', {'b', {'a', 'b'}}}) breaks the contract
+ (Arg) -> 'ok' when Arg :: ab()
+contracts_with_subtypes.erl:140: The call contracts_with_subtypes:rec2
+ ({'b', {'a', {'b', 'a'}}}) breaks the contract
+ (Arg) -> 'ok' when Arg :: ab()
+contracts_with_subtypes.erl:141: The call contracts_with_subtypes:rec2
+ ({'a', {'b', {'a', {'b', 'a'}}}}) breaks the contract
+ (Arg) -> 'ok' when Arg :: ab()
+contracts_with_subtypes.erl:142: The call contracts_with_subtypes:rec2
+ ({'b', {'a', {'b', {'a', 'b'}}}}) breaks the contract
+ (Arg) -> 'ok' when Arg :: ab()
+contracts_with_subtypes.erl:175: The pattern
+ 1 can never match the type
+ string()
+contracts_with_subtypes.erl:178: The pattern
+ 'alpha' can never match the type
+ {'ok', _} | {'ok', _, string()}
+contracts_with_subtypes.erl:180: The pattern
+ 42 can never match the type
+ {'ok', _} | {'ok', _, string()}
+contracts_with_subtypes.erl:196: The pattern
+ 'alpha' can never match the type
+ {'ok', _}
+contracts_with_subtypes.erl:198: The pattern
+ 42 can never match the type
+ {'ok', _}
+contracts_with_subtypes.erl:216: The pattern
+ 'alpha' can never match the type
+ {'ok', _}
+contracts_with_subtypes.erl:218: The pattern
+ 42 can never match the type
+ {'ok', _}
+contracts_with_subtypes.erl:235: The pattern
+ 1 can never match the type
+ string()
+contracts_with_subtypes.erl:238: The pattern
+ {'ok', _} can never match the type
+ {'ok', _, string()}
+contracts_with_subtypes.erl:239: The pattern
+ 'alpha' can never match the type
+ {'ok', _, string()}
+contracts_with_subtypes.erl:23: Invalid type specification for function contracts_with_subtypes:extract2/0. The success typing is
+ () -> 'something'
+contracts_with_subtypes.erl:240: The pattern
+ {'ok', 42} can never match the type
+ {'ok', _, string()}
+contracts_with_subtypes.erl:241: The pattern
+ 42 can never match the type
+ {'ok', _, string()}
+contracts_with_subtypes.erl:268: The call contracts_with_subtypes:flat_ets_new
+ (12,
+ []) breaks the contract
+ (Name, Options) -> atom()
+ when
+ Name :: atom(),
+ Options :: [Option],
+ Option ::
+ 'set' | 'ordered_set' | 'bag' | 'duplicate_bag' |
+ 'public' | 'protected' | 'private' |
+ 'named_table' |
+ {'keypos', integer()} |
+ {'heir', pid(), term()} |
+ {'heir', 'none'} |
+ {'write_concurrency', boolean()} |
+ {'read_concurrency', boolean()} |
+ 'compressed'
+contracts_with_subtypes.erl:295: The call contracts_with_subtypes:factored_ets_new
+ (12,
+ []) breaks the contract
+ (Name, Options) -> atom()
+ when
+ Name :: atom(),
+ Options :: [Option],
+ Option ::
+ Type | Access | 'named_table' |
+ {'keypos', Pos} |
+ {'heir', Pid :: pid(), HeirData} |
+ {'heir', 'none'} |
+ Tweaks,
+ Type :: type(),
+ Access :: access(),
+ Tweaks ::
+ {'write_concurrency', boolean()} |
+ {'read_concurrency', boolean()} |
+ 'compressed',
+ Pos :: pos_integer(),
+ HeirData :: term()
+contracts_with_subtypes.erl:77: The call contracts_with_subtypes:foo1
+ (5) breaks the contract
+ (Arg1) -> Res when Arg1 :: atom(), Res :: atom()
+contracts_with_subtypes.erl:78: The call contracts_with_subtypes:foo2
+ (5) breaks the contract
+ (Arg1) -> Res when Arg1 :: Arg2, Arg2 :: atom(), Res :: atom()
+contracts_with_subtypes.erl:79: The call contracts_with_subtypes:foo3
+ (5) breaks the contract
+ (Arg1) -> Res when Arg2 :: atom(), Arg1 :: Arg2, Res :: atom()
+contracts_with_subtypes.erl:7: Invalid type specification for function contracts_with_subtypes:extract/0. The success typing is
+ () -> 'something'
+contracts_with_subtypes.erl:80: The call contracts_with_subtypes:foo4
+ (5) breaks the contract
+ (Type) -> Type when Type :: atom()
+contracts_with_subtypes.erl:81: The call contracts_with_subtypes:foo5
+ (5) breaks the contract
+ (Type :: atom()) -> Type :: atom()
+contracts_with_subtypes.erl:82: The call contracts_with_subtypes:foo6
+ (5) breaks the contract
+ (Type) -> Type when Type :: atom()
diff --git a/lib/dialyzer/test/indent_SUITE_data/results/dict_use b/lib/dialyzer/test/indent_SUITE_data/results/dict_use
new file mode 100644
index 0000000000..c6863d057e
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/dict_use
@@ -0,0 +1,48 @@
+
+dict_use.erl:41: The attempt to match a term of type
+ dict:dict(_, _) against the pattern
+ 'gazonk' breaks the opacity of the term
+dict_use.erl:45: The attempt to match a term of type
+ dict:dict(_, _) against the pattern
+ [] breaks the opacity of the term
+dict_use.erl:46: The attempt to match a term of type
+ dict:dict(_, _) against the pattern
+ 42 breaks the opacity of the term
+dict_use.erl:51: The attempt to match a term of type
+ dict:dict(_, _) against the pattern
+ [] breaks the opacity of the term
+dict_use.erl:52: The attempt to match a term of type
+ dict:dict(_, _) against the pattern
+ 42 breaks the opacity of the term
+dict_use.erl:58: Attempt to test for equality between a term of type
+ maybe_improper_list() and a term of opaque type
+ dict:dict(_, _)
+dict_use.erl:60: Attempt to test for inequality between a term of type
+ atom() and a term of opaque type
+ dict:dict(_, _)
+dict_use.erl:64: Guard test length
+ (D :: dict:dict(_, _)) breaks the opacity of its argument
+dict_use.erl:65: Guard test is_atom
+ (D :: dict:dict(_, _)) breaks the opacity of its argument
+dict_use.erl:66: Guard test is_list
+ (D :: dict:dict(_, _)) breaks the opacity of its argument
+dict_use.erl:70: The type test is_list
+ (dict:dict(_, _)) breaks the opacity of the term
+ dict:dict(_, _)
+dict_use.erl:73: The call dict:fetch
+ ('foo',
+ [1, 2, 3]) does not have an opaque term of type
+ dict:dict(_, _) as 2nd argument
+dict_use.erl:76: The call dict:merge
+ (Fun :: any(),
+ 42,
+ [1, 2]) does not have opaque terms as 2nd and 3rd arguments
+dict_use.erl:79: The call dict:store
+ (42,
+ 'elli',
+ {'dict', 0, 16, 16, 8, 80, 48,
+ {[], [], [], [], [], [], [], [], [], [], [], [], [], [], [],
+ []},
+ {{[], [], [], [], [], [], [], [], [], [], [], [], [], [], [],
+ []}}}) does not have an opaque term of type
+ dict:dict(_, _) as 3rd argument
diff --git a/lib/dialyzer/test/indent_SUITE_data/results/fun_app b/lib/dialyzer/test/indent_SUITE_data/results/fun_app
new file mode 100644
index 0000000000..d4a3caf749
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/fun_app
@@ -0,0 +1,7 @@
+
+fun_app.erl:37: Fun application will fail since F ::
+ fun((_, _, _) -> 'ok' | 'true') is not a function of arity 1
+fun_app.erl:38: Fun application will fail since F ::
+ fun((_, _, _) -> 'ok' | 'true') is not a function of arity 2
+fun_app.erl:40: Fun application will fail since F ::
+ fun((_, _, _) -> 'ok' | 'true') is not a function of arity 4
diff --git a/lib/dialyzer/test/indent_SUITE_data/results/fun_app_args b/lib/dialyzer/test/indent_SUITE_data/results/fun_app_args
new file mode 100644
index 0000000000..ac1bbb62b8
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/fun_app_args
@@ -0,0 +1,5 @@
+
+fun_app_args.erl:12: Fun application with arguments
+ ('b',
+ []) will fail since the function has type
+ 'c' | fun(('a', []) -> any()), which differs in the 1st argument
diff --git a/lib/dialyzer/test/indent_SUITE_data/results/guard_update b/lib/dialyzer/test/indent_SUITE_data/results/guard_update
new file mode 100644
index 0000000000..bd0e8cd5dd
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/guard_update
@@ -0,0 +1,6 @@
+
+guard_update.erl:6: The call guard_update:f
+ (#{'a' => 2}) will never return since it differs in the 1st argument from the success typing arguments:
+ (#{'b' := _, _ => _})
+guard_update.erl:8: Clause guard cannot succeed. The variable M was matched against the type
+ #{'a' := 2}
diff --git a/lib/dialyzer/test/indent_SUITE_data/results/guard_warnings b/lib/dialyzer/test/indent_SUITE_data/results/guard_warnings
new file mode 100644
index 0000000000..a6cb54ff9c
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/guard_warnings
@@ -0,0 +1,134 @@
+
+guard_warnings.erl:100: Guard test not
+ ('true') can never succeed
+guard_warnings.erl:102: Guard test
+ X :: 'true' =:=
+ 'false' can never succeed
+guard_warnings.erl:104: Guard test
+ X :: 'true' ==
+ 'false' can never succeed
+guard_warnings.erl:106: Guard test
+ X :: 'true' =/=
+ 'true' can never succeed
+guard_warnings.erl:12: Guard test
+ X :: 'true' =:=
+ 'false' can never succeed
+guard_warnings.erl:14: Guard test
+ X :: 'false' =:=
+ 'true' can never succeed
+guard_warnings.erl:16: Guard test not
+ (X :: 'true') can never succeed
+guard_warnings.erl:18: Guard test and
+ ('true',
+ X :: none()) can never succeed
+guard_warnings.erl:20: Guard test not
+ (X :: 'true') can never succeed
+guard_warnings.erl:22: Guard test and
+ ('true',
+ X :: none()) can never succeed
+guard_warnings.erl:28: Guard test not(not
+ (X :: 'false')) can never succeed
+guard_warnings.erl:30: Guard test not(or
+ ('false',
+ X :: none())) can never succeed
+guard_warnings.erl:32: Guard test not(not
+ (X :: 'false')) can never succeed
+guard_warnings.erl:34: Guard test not(or
+ ('false',
+ X :: none())) can never succeed
+guard_warnings.erl:36: Guard test and
+ ('true',
+ 'false') can never succeed
+guard_warnings.erl:38: Guard test and
+ ('false',
+ any()) can never succeed
+guard_warnings.erl:40: Guard test and
+ (X :: 'true',
+ 'false') can never succeed
+guard_warnings.erl:42: Guard test and
+ ('false',
+ X :: any()) can never succeed
+guard_warnings.erl:44: Guard test and
+ (X :: 'true',
+ 'false') can never succeed
+guard_warnings.erl:46: Guard test and
+ ('false',
+ X :: any()) can never succeed
+guard_warnings.erl:48: Guard test not(or
+ ('true',
+ any())) can never succeed
+guard_warnings.erl:50: Guard test not(or
+ ('false',
+ 'true')) can never succeed
+guard_warnings.erl:52: Guard test not(or
+ ('true',
+ X :: any())) can never succeed
+guard_warnings.erl:54: Guard test not(or
+ (X :: 'false',
+ 'true')) can never succeed
+guard_warnings.erl:56: Guard test not(or
+ ('true',
+ X :: any())) can never succeed
+guard_warnings.erl:58: Guard test not(or
+ (X :: 'false',
+ 'true')) can never succeed
+guard_warnings.erl:60: Guard test and
+ ('false',
+ any()) can never succeed
+guard_warnings.erl:62: Guard test and
+ ('true',
+ 'false') can never succeed
+guard_warnings.erl:64: Guard test and
+ ('false',
+ X :: any()) can never succeed
+guard_warnings.erl:66: Guard test and
+ (X :: 'true',
+ 'false') can never succeed
+guard_warnings.erl:68: Guard test and
+ ('false',
+ X :: any()) can never succeed
+guard_warnings.erl:70: Guard test and
+ (X :: 'true',
+ 'false') can never succeed
+guard_warnings.erl:72: Guard test and
+ ('false',
+ 'false') can never succeed
+guard_warnings.erl:74: Guard test and
+ ('false',
+ 'false') can never succeed
+guard_warnings.erl:76: Guard test not(and
+ ('true',
+ 'true')) can never succeed
+guard_warnings.erl:78: Guard test and
+ ('false',
+ 'false') can never succeed
+guard_warnings.erl:80: Guard test not(and
+ ('true',
+ 'true')) can never succeed
+guard_warnings.erl:82: Guard test or
+ ('false',
+ 'false') can never succeed
+guard_warnings.erl:84: Guard test or
+ ('false',
+ 'false') can never succeed
+guard_warnings.erl:86: Guard test or
+ ('false',
+ 'false') can never succeed
+guard_warnings.erl:88: Guard test or
+ ('false',
+ 'false') can never succeed
+guard_warnings.erl:90: Guard test or
+ ('false',
+ 'false') can never succeed
+guard_warnings.erl:92: Guard test
+ 'true' =:=
+ 'false' can never succeed
+guard_warnings.erl:94: Guard test
+ 'true' ==
+ 'false' can never succeed
+guard_warnings.erl:96: Guard test
+ 'true' =:=
+ 'false' can never succeed
+guard_warnings.erl:98: Guard test not(
+ 'true' ==
+ 'true') can never succeed
diff --git a/lib/dialyzer/test/indent_SUITE_data/results/map_galore b/lib/dialyzer/test/indent_SUITE_data/results/map_galore
new file mode 100644
index 0000000000..1b63e28ace
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/map_galore
@@ -0,0 +1,713 @@
+
+map_galore.erl:1000: A key of type
+ 42 cannot exist in a map of type
+ #{1 := 'a',
+ 2 := 'b',
+ 4 := 'd',
+ 5 := 'e',
+ float() => 'c' | 'v'}
+map_galore.erl:1080: A key of type
+ 'nonexisting' cannot exist in a map of type
+ #{10 := 'a0',
+ 11 := 'a1',
+ 12 := 'a2',
+ 13 := 'a3',
+ 14 := 'a4',
+ 15 := 'a5',
+ 16 := 'a6',
+ 17 := 'a7',
+ 18 := 'a8',
+ 19 := 'a9',
+ 20 := 'b0',
+ 21 := 'b1',
+ 22 := 'b2',
+ 23 := 'b3',
+ 24 := 'b4',
+ 25 := 'b5',
+ 26 := 'b6',
+ 27 := 'b7',
+ 28 := 'b8',
+ 29 := 'b9',
+ 30 := [48 | 99, ...],
+ 31 := [49 | 99, ...],
+ 32 := [50 | 99, ...],
+ 33 := [51 | 99, ...],
+ 34 := [52 | 99, ...],
+ 35 := [53 | 99, ...],
+ 36 := [54 | 99, ...],
+ 37 := [55 | 99, ...],
+ 38 := [56 | 99, ...],
+ 39 := [57 | 99, ...],
+ <<_:16>> |
+ [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57, ...] |
+ float() |
+ {[[48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57, ...],
+ ...]} |
+ #{'k16' => 'a6',
+ 'k26' => 'b6',
+ 'k36' => [54 | 99, ...],
+ 'map' => 'key',
+ 'one' => 'small',
+ 'second' => 'small',
+ 'third' => 'small',
+ 10 => 'a0',
+ 11 => 'a1',
+ 12 => 'a2',
+ 13 => 'a3',
+ 14 => 'a4',
+ 15 => 'a5',
+ 16 => 'a6',
+ 17 => 'a7',
+ 18 => 'a8',
+ 19 => 'a9',
+ 20 => 'b0',
+ 21 => 'b1',
+ 22 => 'b2',
+ 23 => 'b3',
+ 24 => 'b4',
+ 25 => 'b5',
+ 26 => 'b6',
+ 27 => 'b7',
+ 28 => 'b8',
+ 29 => 'b9',
+ 30 => [48 | 99, ...],
+ 31 => [49 | 99, ...],
+ 32 => [50 | 99, ...],
+ 33 => [51 | 99, ...],
+ 34 => [52 | 99, ...],
+ 35 => [53 | 99, ...],
+ 36 => [54 | 99, ...],
+ 37 => [55 | 99, ...],
+ 38 => [56 | 99, ...],
+ 39 => [57 | 99, ...],
+ <<_:16>> |
+ [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57, ...] |
+ {[[48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57, ...],
+ ...]} =>
+ [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 |
+ 100 | 101,
+ ...]} =>
+ atom() | [1..255, ...]}
+map_galore.erl:1082: A key of type
+ 42 cannot exist in a map of type
+ #{10 := 'a0',
+ 11 := 'a1',
+ 12 := 'a2',
+ 13 := 'a3',
+ 14 := 'a4',
+ 15 := 'a5',
+ 16 := 'a6',
+ 17 := 'a7',
+ 18 := 'a8',
+ 19 := 'a9',
+ 20 := 'b0',
+ 21 := 'b1',
+ 22 := 'b2',
+ 23 := 'b3',
+ 24 := 'b4',
+ 25 := 'b5',
+ 26 := 'b6',
+ 27 := 'b7',
+ 28 := 'b8',
+ 29 := 'b9',
+ 30 := [48 | 99, ...],
+ 31 := [49 | 99, ...],
+ 32 := [50 | 99, ...],
+ 33 := [51 | 99, ...],
+ 34 := [52 | 99, ...],
+ 35 := [53 | 99, ...],
+ 36 := [54 | 99, ...],
+ 37 := [55 | 99, ...],
+ 38 := [56 | 99, ...],
+ 39 := [57 | 99, ...],
+ <<_:16>> |
+ [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57, ...] |
+ float() |
+ {[[48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57, ...],
+ ...]} |
+ #{'k16' => 'a6',
+ 'k26' => 'b6',
+ 'k36' => [54 | 99, ...],
+ 'map' => 'key',
+ 'one' => 'small',
+ 'second' => 'small',
+ 'third' => 'small',
+ 10 => 'a0',
+ 11 => 'a1',
+ 12 => 'a2',
+ 13 => 'a3',
+ 14 => 'a4',
+ 15 => 'a5',
+ 16 => 'a6',
+ 17 => 'a7',
+ 18 => 'a8',
+ 19 => 'a9',
+ 20 => 'b0',
+ 21 => 'b1',
+ 22 => 'b2',
+ 23 => 'b3',
+ 24 => 'b4',
+ 25 => 'b5',
+ 26 => 'b6',
+ 27 => 'b7',
+ 28 => 'b8',
+ 29 => 'b9',
+ 30 => [48 | 99, ...],
+ 31 => [49 | 99, ...],
+ 32 => [50 | 99, ...],
+ 33 => [51 | 99, ...],
+ 34 => [52 | 99, ...],
+ 35 => [53 | 99, ...],
+ 36 => [54 | 99, ...],
+ 37 => [55 | 99, ...],
+ 38 => [56 | 99, ...],
+ 39 => [57 | 99, ...],
+ <<_:16>> |
+ [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57, ...] |
+ {[[48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57, ...],
+ ...]} =>
+ [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 |
+ 100 | 101,
+ ...]} =>
+ atom() | [1..255, ...]}
+map_galore.erl:1140: The call map_galore:map_guard_sequence_1
+ (#{seq => 6, val => "e"}) will never return since it differs in the 1st argument from the success typing arguments:
+ (#{'seq' := 1 | 2 | 3 | 4 | 5,
+ 'val' := [97 | 98 | 99 | 100 | 101, ...],
+ 10 => 'a0',
+ 11 => 'a1',
+ 12 => 'a2',
+ 13 => 'a3',
+ 14 => 'a4',
+ 15 => 'a5',
+ 16 => 'a6',
+ 17 => 'a7',
+ 18 => 'a8',
+ 19 => 'a9',
+ 20 => 'b0',
+ 21 => 'b1',
+ 22 => 'b2',
+ 23 => 'b3',
+ 24 => 'b4',
+ 25 => 'b5',
+ 26 => 'b6',
+ 27 => 'b7',
+ 28 => 'b8',
+ 29 => 'b9',
+ 30 => [48 | 99, ...],
+ 31 => [49 | 99, ...],
+ 32 => [50 | 99, ...],
+ 33 => [51 | 99, ...],
+ 34 => [52 | 99, ...],
+ 35 => [53 | 99, ...],
+ 36 => [54 | 99, ...],
+ 37 => [55 | 99, ...],
+ 38 => [56 | 99, ...],
+ 39 => [57 | 99, ...],
+ <<_:16>> |
+ [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57, ...] |
+ float() |
+ {[any(), ...]} |
+ #{'k16' => 'a6',
+ 'k26' => 'b6',
+ 'k36' => [any(), ...],
+ 'map' => 'key',
+ 'one' => 'small',
+ 'second' => 'small',
+ 'third' => 'small',
+ 10 => 'a0',
+ 11 => 'a1',
+ 12 => 'a2',
+ 13 => 'a3',
+ 14 => 'a4',
+ 15 => 'a5',
+ 16 => 'a6',
+ 17 => 'a7',
+ 18 => 'a8',
+ 19 => 'a9',
+ 20 => 'b0',
+ 21 => 'b1',
+ 22 => 'b2',
+ 23 => 'b3',
+ 24 => 'b4',
+ 25 => 'b5',
+ 26 => 'b6',
+ 27 => 'b7',
+ 28 => 'b8',
+ 29 => 'b9',
+ 30 => [any(), ...],
+ 31 => [any(), ...],
+ 32 => [any(), ...],
+ 33 => [any(), ...],
+ 34 => [any(), ...],
+ 35 => [any(), ...],
+ 36 => [any(), ...],
+ 37 => [any(), ...],
+ 38 => [any(), ...],
+ 39 => [any(), ...],
+ <<_:16>> | [any(), ...] | {_} => [any(), ...]} =>
+ atom() | [1..255, ...]})
+map_galore.erl:1141: The call map_galore:map_guard_sequence_2
+ (#{'b' => 5}) will never return since it differs in the 1st argument from the success typing arguments:
+ (#{'a' := 'gg' | 'kk' | 'sc' | 3 | 4,
+ 'b' => 'other' | 3 | 4 | 5,
+ 'c' => 'sc2',
+ 10 => 'a0',
+ 11 => 'a1',
+ 12 => 'a2',
+ 13 => 'a3',
+ 14 => 'a4',
+ 15 => 'a5',
+ 16 => 'a6',
+ 17 => 'a7',
+ 18 => 'a8',
+ 19 => 'a9',
+ 20 => 'b0',
+ 21 => 'b1',
+ 22 => 'b2',
+ 23 => 'b3',
+ 24 => 'b4',
+ 25 => 'b5',
+ 26 => 'b6',
+ 27 => 'b7',
+ 28 => 'b8',
+ 29 => 'b9',
+ 30 => [48 | 99, ...],
+ 31 => [49 | 99, ...],
+ 32 => [50 | 99, ...],
+ 33 => [51 | 99, ...],
+ 34 => [52 | 99, ...],
+ 35 => [53 | 99, ...],
+ 36 => [54 | 99, ...],
+ 37 => [55 | 99, ...],
+ 38 => [56 | 99, ...],
+ 39 => [57 | 99, ...],
+ <<_:16>> |
+ [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57, ...] |
+ float() |
+ {[any(), ...]} |
+ #{'k16' => 'a6',
+ 'k26' => 'b6',
+ 'k36' => [any(), ...],
+ 'map' => 'key',
+ 'one' => 'small',
+ 'second' => 'small',
+ 'third' => 'small',
+ 10 => 'a0',
+ 11 => 'a1',
+ 12 => 'a2',
+ 13 => 'a3',
+ 14 => 'a4',
+ 15 => 'a5',
+ 16 => 'a6',
+ 17 => 'a7',
+ 18 => 'a8',
+ 19 => 'a9',
+ 20 => 'b0',
+ 21 => 'b1',
+ 22 => 'b2',
+ 23 => 'b3',
+ 24 => 'b4',
+ 25 => 'b5',
+ 26 => 'b6',
+ 27 => 'b7',
+ 28 => 'b8',
+ 29 => 'b9',
+ 30 => [any(), ...],
+ 31 => [any(), ...],
+ 32 => [any(), ...],
+ 33 => [any(), ...],
+ 34 => [any(), ...],
+ 35 => [any(), ...],
+ 36 => [any(), ...],
+ 37 => [any(), ...],
+ 38 => [any(), ...],
+ 39 => [any(), ...],
+ <<_:16>> | [any(), ...] | {_} => [any(), ...]} =>
+ atom() | [1..255, ...]})
+map_galore.erl:1209: The call map_galore:map_guard_sequence_1
+ (#{'seq' := 6,
+ 'val' := [101, ...],
+ 10 := 'a0',
+ 11 := 'a1',
+ 12 := 'a2',
+ 13 := 'a3',
+ 14 := 'a4',
+ 15 := 'a5',
+ 16 := 'a6',
+ 17 := 'a7',
+ 18 := 'a8',
+ 19 := 'a9',
+ 20 := 'b0',
+ 21 := 'b1',
+ 22 := 'b2',
+ 23 := 'b3',
+ 24 := 'b4',
+ 25 := 'b5',
+ 26 := 'b6',
+ 27 := 'b7',
+ 28 := 'b8',
+ 29 := 'b9',
+ 30 := [48 | 99, ...],
+ 31 := [49 | 99, ...],
+ 32 := [50 | 99, ...],
+ 33 := [51 | 99, ...],
+ 34 := [52 | 99, ...],
+ 35 := [53 | 99, ...],
+ 36 := [54 | 99, ...],
+ 37 := [55 | 99, ...],
+ 38 := [56 | 99, ...],
+ 39 := [57 | 99, ...],
+ <<_:16>> |
+ [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57, ...] |
+ float() |
+ {[[48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57, ...] | 3,
+ ...]} |
+ #{'k16' => 'a6',
+ 'k26' => 'b6',
+ 'k36' => [54 | 99, ...],
+ 'map' => 'key',
+ 'one' => 'small',
+ 'second' => 'small',
+ 'third' => 'small',
+ 10 => 'a0',
+ 11 => 'a1',
+ 12 => 'a2',
+ 13 => 'a3',
+ 14 => 'a4',
+ 15 => 'a5',
+ 16 => 'a6',
+ 17 => 'a7',
+ 18 => 'a8',
+ 19 => 'a9',
+ 20 => 'b0',
+ 21 => 'b1',
+ 22 => 'b2',
+ 23 => 'b3',
+ 24 => 'b4',
+ 25 => 'b5',
+ 26 => 'b6',
+ 27 => 'b7',
+ 28 => 'b8',
+ 29 => 'b9',
+ 30 => [48 | 99, ...],
+ 31 => [49 | 99, ...],
+ 32 => [50 | 99, ...],
+ 33 => [51 | 99, ...],
+ 34 => [52 | 99, ...],
+ 35 => [53 | 99, ...],
+ 36 => [54 | 99, ...],
+ 37 => [55 | 99, ...],
+ 38 => [56 | 99, ...],
+ 39 => [57 | 99, ...],
+ <<_:16>> |
+ [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57, ...] |
+ {[[48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57, ...],
+ ...]} =>
+ [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 |
+ 100 | 101,
+ ...]} =>
+ atom() | [1..255, ...]}) will never return since it differs in the 1st argument from the success typing arguments:
+ (#{'seq' := 1 | 2 | 3 | 4 | 5,
+ 'val' := [97 | 98 | 99 | 100 | 101, ...],
+ 10 => 'a0',
+ 11 => 'a1',
+ 12 => 'a2',
+ 13 => 'a3',
+ 14 => 'a4',
+ 15 => 'a5',
+ 16 => 'a6',
+ 17 => 'a7',
+ 18 => 'a8',
+ 19 => 'a9',
+ 20 => 'b0',
+ 21 => 'b1',
+ 22 => 'b2',
+ 23 => 'b3',
+ 24 => 'b4',
+ 25 => 'b5',
+ 26 => 'b6',
+ 27 => 'b7',
+ 28 => 'b8',
+ 29 => 'b9',
+ 30 => [48 | 99, ...],
+ 31 => [49 | 99, ...],
+ 32 => [50 | 99, ...],
+ 33 => [51 | 99, ...],
+ 34 => [52 | 99, ...],
+ 35 => [53 | 99, ...],
+ 36 => [54 | 99, ...],
+ 37 => [55 | 99, ...],
+ 38 => [56 | 99, ...],
+ 39 => [57 | 99, ...],
+ <<_:16>> |
+ [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57, ...] |
+ float() |
+ {[any(), ...]} |
+ #{'k16' => 'a6',
+ 'k26' => 'b6',
+ 'k36' => [any(), ...],
+ 'map' => 'key',
+ 'one' => 'small',
+ 'second' => 'small',
+ 'third' => 'small',
+ 10 => 'a0',
+ 11 => 'a1',
+ 12 => 'a2',
+ 13 => 'a3',
+ 14 => 'a4',
+ 15 => 'a5',
+ 16 => 'a6',
+ 17 => 'a7',
+ 18 => 'a8',
+ 19 => 'a9',
+ 20 => 'b0',
+ 21 => 'b1',
+ 22 => 'b2',
+ 23 => 'b3',
+ 24 => 'b4',
+ 25 => 'b5',
+ 26 => 'b6',
+ 27 => 'b7',
+ 28 => 'b8',
+ 29 => 'b9',
+ 30 => [any(), ...],
+ 31 => [any(), ...],
+ 32 => [any(), ...],
+ 33 => [any(), ...],
+ 34 => [any(), ...],
+ 35 => [any(), ...],
+ 36 => [any(), ...],
+ 37 => [any(), ...],
+ 38 => [any(), ...],
+ 39 => [any(), ...],
+ <<_:16>> | [any(), ...] | {_} => [any(), ...]} =>
+ atom() | [1..255, ...]})
+map_galore.erl:1210: The call map_galore:map_guard_sequence_2
+ (#{'b' := 5,
+ 10 := 'a0',
+ 11 := 'a1',
+ 12 := 'a2',
+ 13 := 'a3',
+ 14 := 'a4',
+ 15 := 'a5',
+ 16 := 'a6',
+ 17 := 'a7',
+ 18 := 'a8',
+ 19 := 'a9',
+ 20 := 'b0',
+ 21 := 'b1',
+ 22 := 'b2',
+ 23 := 'b3',
+ 24 := 'b4',
+ 25 := 'b5',
+ 26 := 'b6',
+ 27 := 'b7',
+ 28 := 'b8',
+ 29 := 'b9',
+ 30 := [48 | 99, ...],
+ 31 := [49 | 99, ...],
+ 32 := [50 | 99, ...],
+ 33 := [51 | 99, ...],
+ 34 := [52 | 99, ...],
+ 35 := [53 | 99, ...],
+ 36 := [54 | 99, ...],
+ 37 := [55 | 99, ...],
+ 38 := [56 | 99, ...],
+ 39 := [57 | 99, ...],
+ <<_:16>> |
+ [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57, ...] |
+ float() |
+ {[[48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57, ...] | 3,
+ ...]} |
+ #{'k16' => 'a6',
+ 'k26' => 'b6',
+ 'k36' => [54 | 99, ...],
+ 'map' => 'key',
+ 'one' => 'small',
+ 'second' => 'small',
+ 'third' => 'small',
+ 10 => 'a0',
+ 11 => 'a1',
+ 12 => 'a2',
+ 13 => 'a3',
+ 14 => 'a4',
+ 15 => 'a5',
+ 16 => 'a6',
+ 17 => 'a7',
+ 18 => 'a8',
+ 19 => 'a9',
+ 20 => 'b0',
+ 21 => 'b1',
+ 22 => 'b2',
+ 23 => 'b3',
+ 24 => 'b4',
+ 25 => 'b5',
+ 26 => 'b6',
+ 27 => 'b7',
+ 28 => 'b8',
+ 29 => 'b9',
+ 30 => [48 | 99, ...],
+ 31 => [49 | 99, ...],
+ 32 => [50 | 99, ...],
+ 33 => [51 | 99, ...],
+ 34 => [52 | 99, ...],
+ 35 => [53 | 99, ...],
+ 36 => [54 | 99, ...],
+ 37 => [55 | 99, ...],
+ 38 => [56 | 99, ...],
+ 39 => [57 | 99, ...],
+ <<_:16>> |
+ [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57, ...] |
+ {[[48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57, ...],
+ ...]} =>
+ [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 |
+ 100 | 101,
+ ...]} =>
+ atom() | [1..255, ...]}) will never return since it differs in the 1st argument from the success typing arguments:
+ (#{'a' := 'gg' | 'kk' | 'sc' | 3 | 4,
+ 'b' => 'other' | 3 | 4 | 5,
+ 'c' => 'sc2',
+ 10 => 'a0',
+ 11 => 'a1',
+ 12 => 'a2',
+ 13 => 'a3',
+ 14 => 'a4',
+ 15 => 'a5',
+ 16 => 'a6',
+ 17 => 'a7',
+ 18 => 'a8',
+ 19 => 'a9',
+ 20 => 'b0',
+ 21 => 'b1',
+ 22 => 'b2',
+ 23 => 'b3',
+ 24 => 'b4',
+ 25 => 'b5',
+ 26 => 'b6',
+ 27 => 'b7',
+ 28 => 'b8',
+ 29 => 'b9',
+ 30 => [48 | 99, ...],
+ 31 => [49 | 99, ...],
+ 32 => [50 | 99, ...],
+ 33 => [51 | 99, ...],
+ 34 => [52 | 99, ...],
+ 35 => [53 | 99, ...],
+ 36 => [54 | 99, ...],
+ 37 => [55 | 99, ...],
+ 38 => [56 | 99, ...],
+ 39 => [57 | 99, ...],
+ <<_:16>> |
+ [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57, ...] |
+ float() |
+ {[any(), ...]} |
+ #{'k16' => 'a6',
+ 'k26' => 'b6',
+ 'k36' => [any(), ...],
+ 'map' => 'key',
+ 'one' => 'small',
+ 'second' => 'small',
+ 'third' => 'small',
+ 10 => 'a0',
+ 11 => 'a1',
+ 12 => 'a2',
+ 13 => 'a3',
+ 14 => 'a4',
+ 15 => 'a5',
+ 16 => 'a6',
+ 17 => 'a7',
+ 18 => 'a8',
+ 19 => 'a9',
+ 20 => 'b0',
+ 21 => 'b1',
+ 22 => 'b2',
+ 23 => 'b3',
+ 24 => 'b4',
+ 25 => 'b5',
+ 26 => 'b6',
+ 27 => 'b7',
+ 28 => 'b8',
+ 29 => 'b9',
+ 30 => [any(), ...],
+ 31 => [any(), ...],
+ 32 => [any(), ...],
+ 33 => [any(), ...],
+ 34 => [any(), ...],
+ 35 => [any(), ...],
+ 36 => [any(), ...],
+ 37 => [any(), ...],
+ 38 => [any(), ...],
+ 39 => [any(), ...],
+ <<_:16>> | [any(), ...] | {_} => [any(), ...]} =>
+ atom() | [1..255, ...]})
+map_galore.erl:1418: Fun application with arguments
+ (#{'s' => 'none', 'v' => 'none'}) will never return since it differs in the 1st argument from the success typing arguments:
+ (#{'s' := 'l' | 't' | 'v',
+ 'v' :=
+ 'none' |
+ <<_:16>> |
+ [<<_:16>>, ...] |
+ {<<_:16>>, <<_:16>>}})
+map_galore.erl:1491: The test
+ #{} =:=
+ #{'a' := 1} can never evaluate to 'true'
+map_galore.erl:1492: The test
+ #{'a' := 1} =:=
+ #{} can never evaluate to 'true'
+map_galore.erl:1495: The test
+ #{'a' := 1} =:=
+ #{'a' := 2} can never evaluate to 'true'
+map_galore.erl:1496: The test
+ #{'a' := 2} =:=
+ #{'a' := 1} can never evaluate to 'true'
+map_galore.erl:1497: The test
+ #{'a' := 2, 'b' := 1} =:=
+ #{'a' := 1, 'b' := 3} can never evaluate to 'true'
+map_galore.erl:1498: The test
+ #{'a' := 1, 'b' := 1} =:=
+ #{'a' := 1, 'b' := 3} can never evaluate to 'true'
+map_galore.erl:1762: The call maps:get
+ ({1, 1},
+ #{{1, float()} => [101 | 108 | 112 | 116 | 117, ...]}) will never return since the success typing arguments are
+ (any(),
+ map())
+map_galore.erl:1763: The call maps:get
+ ('a',
+ #{}) will never return since the success typing arguments are
+ (any(),
+ map())
+map_galore.erl:1765: The call maps:get
+ ('a',
+ #{'b' => 1, 'c' => 2}) will never return since the success typing arguments are
+ (any(),
+ map())
+map_galore.erl:186: The pattern
+ #{'x' := 2} can never match the type
+ #{'x' := 3}
+map_galore.erl:187: The pattern
+ #{'x' := 3} can never match the type
+ {'a', 'b', 'c'}
+map_galore.erl:188: The pattern
+ #{'x' := 3} can never match the type
+ #{'y' := 3}
+map_galore.erl:189: The pattern
+ #{'x' := 3} can never match the type
+ #{'x' := [101 | 104 | 114 | 116, ...]}
+map_galore.erl:2280: Cons will produce an improper list since its 2nd argument is
+ {'b', 'a'}
+map_galore.erl:2280: The call maps:from_list
+ ([{'a', 'b'} | {'b', 'a'}]) will never return since it differs in the 1st argument from the success typing arguments:
+ ([{_, _}])
+map_galore.erl:2281: The call maps:from_list
+ ('a') will never return since it differs in the 1st argument from the success typing arguments:
+ ([{_, _}])
+map_galore.erl:2282: The call maps:from_list
+ (42) will never return since it differs in the 1st argument from the success typing arguments:
+ ([{_, _}])
+map_galore.erl:997: A key of type
+ 'nonexisting' cannot exist in a map of type
+ #{}
+map_galore.erl:998: A key of type
+ 'nonexisting' cannot exist in a map of type
+ #{1 := 'a', 2 := 'b', 4 := 'd', 5 := 'e', float() => 'c'}
diff --git a/lib/dialyzer/test/indent_SUITE_data/results/order b/lib/dialyzer/test/indent_SUITE_data/results/order
new file mode 100644
index 0000000000..5b0030d7b1
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/order
@@ -0,0 +1,23 @@
+
+order.erl:14: Guard test is_integer
+ (Int :: 'b') can never succeed
+order.erl:16: The variable _Else can never match since previous clauses completely covered the type
+ 'b'
+order.erl:21: Guard test is_integer
+ (Int :: 'b') can never succeed
+order.erl:23: The variable _Else can never match since previous clauses completely covered the type
+ 'b'
+order.erl:30: The variable _Else can never match since previous clauses completely covered the type
+ 'b' | 1
+order.erl:36: The variable Atom can never match since previous clauses completely covered the type
+ 1
+order.erl:37: The variable _Else can never match since previous clauses completely covered the type
+ 1
+order.erl:42: Guard test is_integer
+ (Int :: 'b') can never succeed
+order.erl:44: The variable _Else can never match since previous clauses completely covered the type
+ 'b'
+order.erl:7: Guard test is_integer
+ (Int :: 'b') can never succeed
+order.erl:9: The variable _Else can never match since previous clauses completely covered the type
+ 'b'
diff --git a/lib/dialyzer/test/indent_SUITE_data/results/queue_use b/lib/dialyzer/test/indent_SUITE_data/results/queue_use
new file mode 100644
index 0000000000..b6604e5320
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/queue_use
@@ -0,0 +1,34 @@
+
+queue_use.erl:18: The call queue:is_empty
+ ({[], []}) does not have an opaque term of type
+ queue:queue(_) as 1st argument
+queue_use.erl:22: The call queue:in
+ (42,
+ Q0 :: {[], []}) does not have an opaque term of type
+ queue:queue(_) as 2nd argument
+queue_use.erl:27: The attempt to match a term of type
+ queue:queue(_) against the pattern
+ {"*", Q2} breaks the opacity of the term
+queue_use.erl:33: Attempt to test for equality between a term of type
+ {[42, ...], []} and a term of opaque type
+ queue:queue(_)
+queue_use.erl:36: The attempt to match a term of type
+ queue:queue(_) against the pattern
+ {F, _R} breaks the opacity of the term
+queue_use.erl:40: The call queue:out
+ ({"*", []}) does not have an opaque term of type
+ queue:queue(_) as 1st argument
+queue_use.erl:51: The call queue_use:is_in_queue
+ (E :: 42,
+ DB :: #db{p :: [], q :: queue:queue(_)}) contains an opaque term as 2nd argument when terms of different types are expected in these positions
+queue_use.erl:56: The attempt to match a term of type
+ #db{p :: [], q :: queue:queue(_)} against the pattern
+ {'db', _, {L1, L2}} breaks the opacity of
+ queue:queue(_)
+queue_use.erl:62: The call queue_use:tuple_queue
+ ({42, 'gazonk'}) does not have a term of type
+ {_, queue:queue(_)} (with opaque subterms) as 1st argument
+queue_use.erl:65: The call queue:in
+ (F :: 42,
+ Q :: 'gazonk') does not have an opaque term of type
+ queue:queue(_) as 2nd argument
diff --git a/lib/dialyzer/test/indent_SUITE_data/results/rec b/lib/dialyzer/test/indent_SUITE_data/results/rec
new file mode 100644
index 0000000000..5938b18be0
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/rec
@@ -0,0 +1,15 @@
+
+rec_use.erl:17: The attempt to match a term of type
+ rec_adt:rec() against the pattern
+ {'rec', _, 42} breaks the opacity of the term
+rec_use.erl:18: Guard test tuple_size
+ (R :: rec_adt:rec()) breaks the opacity of its argument
+rec_use.erl:23: The call rec_adt:get_a
+ (R :: tuple()) does not have an opaque term of type
+ rec_adt:rec() as 1st argument
+rec_use.erl:27: Attempt to test for equality between a term of type
+ {'rec', 'gazonk', 42} and a term of opaque type
+ rec_adt:rec()
+rec_use.erl:30: The call erlang:tuple_size
+ (rec_adt:rec()) contains an opaque term as 1st argument when a structured term of type
+ tuple() is expected
diff --git a/lib/dialyzer/test/indent_SUITE_data/results/record_construct b/lib/dialyzer/test/indent_SUITE_data/results/record_construct
new file mode 100644
index 0000000000..a1268de690
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/record_construct
@@ -0,0 +1,11 @@
+
+record_construct.erl:16: Record construction
+ #r_opa{b :: gb_sets:set(_), c :: 42, e :: 'false'} violates the declared type of field c ::
+ boolean()
+record_construct.erl:21: Record construction
+ #r_rem{a :: 'gazonk'} violates the declared type of field a ::
+ string()
+record_construct.erl:7: Record construction
+ #r_loc{a :: 'gazonk', b :: 42} violates the declared type of field a ::
+ integer() and b ::
+ atom()
diff --git a/lib/dialyzer/test/indent_SUITE_data/results/record_creation_diffs b/lib/dialyzer/test/indent_SUITE_data/results/record_creation_diffs
new file mode 100644
index 0000000000..9b5f9489db
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/record_creation_diffs
@@ -0,0 +1,4 @@
+
+record_creation_diffs.erl:11: Record construction
+ #bar{some_list :: {'this', 'is', 'a', 'tuple'}} violates the declared type of field some_list ::
+ [any()]
diff --git a/lib/dialyzer/test/indent_SUITE_data/results/record_match b/lib/dialyzer/test/indent_SUITE_data/results/record_match
new file mode 100644
index 0000000000..4738a4b0c9
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/record_match
@@ -0,0 +1,4 @@
+
+record_match.erl:17: Matching of pattern
+ {'b_literal', 'undefined'} tagged with a record name violates the declared type of
+ #b_local{} | #b_remote{}
diff --git a/lib/dialyzer/test/indent_SUITE_data/results/record_pat b/lib/dialyzer/test/indent_SUITE_data/results/record_pat
new file mode 100644
index 0000000000..cf9247d5a8
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/record_pat
@@ -0,0 +1,4 @@
+
+record_pat.erl:14: Matching of pattern
+ {'foo', 'baz'} tagged with a record name violates the declared type of
+ #foo{bar :: integer()}
diff --git a/lib/dialyzer/test/indent_SUITE_data/results/record_send_test b/lib/dialyzer/test/indent_SUITE_data/results/record_send_test
new file mode 100644
index 0000000000..51d8e1a852
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/record_send_test
@@ -0,0 +1,6 @@
+
+record_send_test.erl:30: The call erlang:'!'
+ (Rec1 :: #rec1{a :: 'a', b :: 'b', c :: 'c'},
+ 'hello_again') will never return since it differs in the 1st argument from the success typing arguments:
+ (atom() | pid() | port() | {atom(), atom()},
+ any())
diff --git a/lib/dialyzer/test/indent_SUITE_data/results/record_test b/lib/dialyzer/test/indent_SUITE_data/results/record_test
new file mode 100644
index 0000000000..1574459578
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/record_test
@@ -0,0 +1,6 @@
+
+record_test.erl:19: Matching of pattern
+ {'foo', _} tagged with a record name violates the declared type of
+ 'foo'
+record_test.erl:21: The variable _ can never match since previous clauses completely covered the type
+ 'foo'
diff --git a/lib/dialyzer/test/indent_SUITE_data/results/record_update b/lib/dialyzer/test/indent_SUITE_data/results/record_update
new file mode 100644
index 0000000000..6e4124552e
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/record_update
@@ -0,0 +1,3 @@
+
+record_update.erl:7: Invalid type specification for function record_update:quux/2. The success typing is
+ (#foo{bar :: atom()}, atom()) -> #foo{bar :: atom()}
diff --git a/lib/dialyzer/test/indent_SUITE_data/results/sample_behaviour b/lib/dialyzer/test/indent_SUITE_data/results/sample_behaviour
new file mode 100644
index 0000000000..f0e41d024a
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/sample_behaviour
@@ -0,0 +1,23 @@
+
+sample_callback_wrong.erl:16: The inferred return type of sample_callback_2/0
+ (42) has nothing in common with
+ atom(), which is the expected return type for the callback of the sample_behaviour behaviour
+sample_callback_wrong.erl:17: The inferred return type of sample_callback_3/0
+ ('fair') has nothing in common with
+ 'fail' | {'ok', 1..255}, which is the expected return type for the callback of the sample_behaviour behaviour
+sample_callback_wrong.erl:18: The inferred return type of sample_callback_4/1
+ ('fail') has nothing in common with
+ 'ok', which is the expected return type for the callback of the sample_behaviour behaviour
+sample_callback_wrong.erl:20: The inferred return type of sample_callback_5/1
+ (string()) has nothing in common with
+ 'fail' | 'ok', which is the expected return type for the callback of the sample_behaviour behaviour
+sample_callback_wrong.erl:20: The inferred type for the 1st argument of sample_callback_5/1 (
+ atom()) is not a supertype of
+ 1..255, which is expected type for this argument in the callback of the sample_behaviour behaviour
+sample_callback_wrong.erl:22: The inferred return type of sample_callback_6/3
+ ({'okk', number()}) has nothing in common with
+ 'fail' | {'ok', 1..255}, which is the expected return type for the callback of the sample_behaviour behaviour
+sample_callback_wrong.erl:22: The inferred type for the 3rd argument of sample_callback_6/3 (
+ atom()) is not a supertype of
+ string(), which is expected type for this argument in the callback of the sample_behaviour behaviour
+sample_callback_wrong.erl:4: Undefined callback function sample_callback_1/0 (behaviour sample_behaviour)
diff --git a/lib/dialyzer/test/indent_SUITE_data/results/simple b/lib/dialyzer/test/indent_SUITE_data/results/simple
new file mode 100644
index 0000000000..bafe334405
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/simple
@@ -0,0 +1,289 @@
+
+exact_api.erl:17: The call exact_api:set_type
+ (A ::
+ #digraph{vtab :: 'notable',
+ etab :: 'notable',
+ ntab :: 'notable',
+ cyclic :: 'true'}) does not have an opaque term of type
+ digraph:graph() as 1st argument
+exact_api.erl:23: The call digraph:delete
+ (G ::
+ #digraph{vtab :: 'notable',
+ etab :: 'notable',
+ ntab :: 'notable',
+ cyclic :: 'true'}) does not have an opaque term of type
+ digraph:graph() as 1st argument
+exact_api.erl:55: The attempt to match a term of type
+ exact_adt:exact_adt() against the pattern
+ {'exact_adt'} breaks the opacity of the term
+exact_api.erl:59: The call exact_adt:exact_adt_set_type2
+ (A :: #exact_adt{}) does not have an opaque term of type
+ exact_adt:exact_adt() as 1st argument
+is_rec.erl:10: The call erlang:is_record
+ (simple1_adt:d1(),
+ 'r',
+ 2) contains an opaque term as 1st argument when terms of different types are expected in these positions
+is_rec.erl:15: The call erlang:is_record
+ (A :: simple1_adt:d1(),
+ 'r',
+ I :: 1 | 2 | 3) contains an opaque term as 1st argument when terms of different types are expected in these positions
+is_rec.erl:19: Guard test is_record
+ (A :: simple1_adt:d1(),
+ 'r',
+ 2) breaks the opacity of its argument
+is_rec.erl:23: Guard test is_record
+ ({simple1_adt:d1(), 1},
+ 'r',
+ 2) breaks the opacity of its argument
+is_rec.erl:41: The call erlang:is_record
+ (A :: simple1_adt:d1(),
+ R :: 'a') contains an opaque term as 1st argument when terms of different types are expected in these positions
+is_rec.erl:45: The call erlang:is_record
+ (A :: simple1_adt:d1(),
+ A :: simple1_adt:d1(),
+ 1) contains an opaque term as 2nd argument when terms of different types are expected in these positions
+is_rec.erl:49: The call erlang:is_record
+ (A :: simple1_adt:d1(),
+ any(),
+ 1) contains an opaque term as 1st argument when terms of different types are expected in these positions
+is_rec.erl:53: The call erlang:is_record
+ (A :: simple1_adt:d1(),
+ A :: simple1_adt:d1(),
+ any()) contains an opaque term as 2nd argument when terms of different types are expected in these positions
+is_rec.erl:57: Guard test is_record
+ (A :: simple1_adt:d1(),
+ 'r',
+ 2) breaks the opacity of its argument
+is_rec.erl:61: The record
+ #r{f1 :: simple1_adt:d1()} violates the declared type for #r{}
+is_rec.erl:65: The call erlang:is_record
+ ({simple1_adt:d1(), 1},
+ 'r',
+ 2) contains an opaque term as 1st argument when terms of different types are expected in these positions
+rec_api.erl:104: Matching of pattern
+ {'r2', 10} tagged with a record name violates the declared type of
+ #r2{f1 :: 10}
+rec_api.erl:113: The attempt to match a term of type
+ #r3{f1 :: queue:queue(_)} against the pattern
+ {'r3', 'a'} breaks the opacity of
+ queue:queue(_)
+rec_api.erl:118: Record construction
+ #r3{f1 :: 10} violates the declared type of field f1 ::
+ queue:queue(_)
+rec_api.erl:123: The attempt to match a term of type
+ #r3{f1 :: 10} against the pattern
+ {'r3', 10} breaks the opacity of
+ queue:queue(_)
+rec_api.erl:24: Record construction
+ #r1{f1 :: 10} violates the declared type of field f1 ::
+ rec_api:a()
+rec_api.erl:29: Matching of pattern
+ {'r1', 10} tagged with a record name violates the declared type of
+ #r1{f1 :: 10}
+rec_api.erl:33: The attempt to match a term of type
+ rec_adt:r1() against the pattern
+ {'r1', 'a'} breaks the opacity of the term
+rec_api.erl:35: Invalid type specification for function rec_api:adt_t1/1. The success typing is
+ (#r1{f1 :: 'a'}) -> #r1{f1 :: 'a'}
+rec_api.erl:40: The specification for rec_api:adt_r1/0 has an opaque subtype
+ rec_adt:r1() which is violated by the success typing
+ () -> #r1{f1 :: 'a'}
+rec_api.erl:85: The attempt to match a term of type
+ rec_adt:f() against the record field 'f' declared to be of type
+ rec_api:f() breaks the opacity of the term
+rec_api.erl:99: Record construction
+ #r2{f1 :: 10} violates the declared type of field f1 ::
+ rec_api:a()
+simple1_api.erl:113: The test
+ simple1_api:d1() =:=
+ simple1_api:d2() can never evaluate to 'true'
+simple1_api.erl:118: Guard test
+ simple1_api:d2() =:=
+ A :: simple1_api:d1() can never succeed
+simple1_api.erl:142: Attempt to test for equality between a term of type
+ simple1_adt:o2() and a term of opaque type
+ simple1_adt:o1()
+simple1_api.erl:148: Guard test
+ simple1_adt:o2() =:=
+ A :: simple1_adt:o1() contains opaque terms as 1st and 2nd arguments
+simple1_api.erl:154: Attempt to test for inequality between a term of type
+ simple1_adt:o2() and a term of opaque type
+ simple1_adt:o1()
+simple1_api.erl:160: Attempt to test for inequality between a term of type
+ simple1_adt:o2() and a term of opaque type
+ simple1_adt:o1()
+simple1_api.erl:165: Attempt to test for equality between a term of type
+ simple1_adt:c2() and a term of opaque type
+ simple1_adt:c1()
+simple1_api.erl:181: Guard test
+ A :: simple1_adt:d1() =<
+ B :: simple1_adt:d2() contains opaque terms as 1st and 2nd arguments
+simple1_api.erl:185: Guard test
+ 'a' =<
+ B :: simple1_adt:d2() contains an opaque term as 2nd argument
+simple1_api.erl:189: Guard test
+ A :: simple1_adt:d1() =<
+ 'd' contains an opaque term as 1st argument
+simple1_api.erl:197: The type test is_integer
+ (A :: simple1_adt:d1()) breaks the opacity of the term A::
+ simple1_adt:d1()
+simple1_api.erl:221: Guard test
+ A :: simple1_api:i1() >
+ 3 can never succeed
+simple1_api.erl:225: Guard test
+ A :: simple1_adt:i1() >
+ 3 contains an opaque term as 1st argument
+simple1_api.erl:233: Guard test
+ A :: simple1_adt:i1() <
+ 3 contains an opaque term as 1st argument
+simple1_api.erl:239: Guard test
+ A :: 1 >
+ 3 can never succeed
+simple1_api.erl:243: Guard test
+ A :: 1 >
+ 3 can never succeed
+simple1_api.erl:257: Guard test is_function
+ (T :: simple1_api:o1()) can never succeed
+simple1_api.erl:265: Guard test is_function
+ (T :: simple1_adt:o1()) breaks the opacity of its argument
+simple1_api.erl:269: The type test is_function
+ (T :: simple1_adt:o1()) breaks the opacity of the term T::
+ simple1_adt:o1()
+simple1_api.erl:274: Guard test is_function
+ (T :: simple1_api:o1(),
+ A :: simple1_api:i1()) can never succeed
+simple1_api.erl:284: Guard test is_function
+ (T :: simple1_adt:o1(),
+ A :: simple1_adt:i1()) breaks the opacity of its argument
+simple1_api.erl:289: The type test is_function
+ (T :: simple1_adt:o1(),
+ A :: simple1_adt:i1()) breaks the opacity of the term T::
+ simple1_adt:o1()
+simple1_api.erl:294: The call erlang:is_function
+ (T :: simple1_api:o1(),
+ A :: simple1_adt:i1()) contains an opaque term as 2nd argument when terms of different types are expected in these positions
+simple1_api.erl:300: The type test is_function
+ (T :: simple1_adt:o1(),
+ A :: simple1_api:i1()) breaks the opacity of the term T::
+ simple1_adt:o1()
+simple1_api.erl:306: Guard test
+ B :: simple1_api:b2() =:=
+ 'true' can never succeed
+simple1_api.erl:315: Guard test
+ A :: simple1_api:b1() =:=
+ 'false' can never succeed
+simple1_api.erl:319: Guard test not(and
+ ('true',
+ 'true')) can never succeed
+simple1_api.erl:337: Clause guard cannot succeed.
+simple1_api.erl:342: Guard test
+ B :: simple1_adt:b2() =:=
+ 'true' contains an opaque term as 1st argument
+simple1_api.erl:347: Guard test
+ A :: simple1_adt:b1() =:=
+ 'true' contains an opaque term as 1st argument
+simple1_api.erl:355: Invalid type specification for function simple1_api:bool_adt_t6/1. The success typing is
+ ('true') -> 1
+simple1_api.erl:365: Clause guard cannot succeed.
+simple1_api.erl:368: Invalid type specification for function simple1_api:bool_adt_t8/2. The success typing is
+ (boolean(), boolean()) -> 1
+simple1_api.erl:378: Clause guard cannot succeed.
+simple1_api.erl:381: Invalid type specification for function simple1_api:bool_adt_t9/2. The success typing is
+ ('false', 'false') -> 1
+simple1_api.erl:407: The size
+ simple1_adt:i1() breaks the opacity of A
+simple1_api.erl:418: The attempt to match a term of type
+ non_neg_integer() against the variable A breaks the opacity of
+ simple1_adt:i1()
+simple1_api.erl:425: The attempt to match a term of type
+ non_neg_integer() against the variable B breaks the opacity of
+ simple1_adt:i1()
+simple1_api.erl:432: The pattern
+ <<_:B>> can never match the type
+ any()
+simple1_api.erl:448: The attempt to match a term of type
+ non_neg_integer() against the variable Sz breaks the opacity of
+ simple1_adt:i1()
+simple1_api.erl:460: The attempt to match a term of type
+ simple1_adt:bit1() against the pattern
+ <<_/binary>> breaks the opacity of the term
+simple1_api.erl:478: The call 'foo':A
+ (A :: simple1_adt:a()) breaks the opacity of the term A ::
+ simple1_adt:a()
+simple1_api.erl:486: The call A:'foo'
+ (A :: simple1_adt:a()) breaks the opacity of the term A ::
+ simple1_adt:a()
+simple1_api.erl:499: The call 'foo':A
+ (A :: simple1_api:i()) requires that A is of type
+ atom() not
+ simple1_api:i()
+simple1_api.erl:503: The call 'foo':A
+ (A :: simple1_adt:i()) requires that A is of type
+ atom() not
+ simple1_adt:i()
+simple1_api.erl:507: The call A:'foo'
+ (A :: simple1_api:i()) requires that A is of type
+ atom() not
+ simple1_api:i()
+simple1_api.erl:511: The call A:'foo'
+ (A :: simple1_adt:i()) requires that A is of type
+ atom() not
+ simple1_adt:i()
+simple1_api.erl:519: Guard test
+ A :: simple1_adt:d2() ==
+ B :: simple1_adt:d1() contains opaque terms as 1st and 2nd arguments
+simple1_api.erl:534: Guard test
+ A :: simple1_adt:d1() >=
+ 3 contains an opaque term as 1st argument
+simple1_api.erl:536: Guard test
+ A :: simple1_adt:d1() ==
+ 3 contains an opaque term as 1st argument
+simple1_api.erl:538: Guard test
+ A :: simple1_adt:d1() =:=
+ 3 contains an opaque term as 1st argument
+simple1_api.erl:548: The call erlang:'<'
+ (A :: simple1_adt:d1(),
+ 3) contains an opaque term as 1st argument when terms of different types are expected in these positions
+simple1_api.erl:558: The call erlang:'=<'
+ (A :: simple1_adt:d1(),
+ B :: simple1_adt:d2()) contains opaque terms as 1st and 2nd arguments when terms of different types are expected in these positions
+simple1_api.erl:565: Guard test
+ {digraph:graph(), 3} >
+ {digraph:graph(), atom() | ets:tid()} contains an opaque term as 2nd argument
+simple1_api.erl:91: The specification for simple1_api:tup/0 has an opaque subtype
+ simple1_adt:tuple1() which is violated by the success typing
+ () -> {'a', 'b'}
+simple2_api.erl:100: The call lists:flatten
+ (A :: simple1_adt:tuple1()) contains an opaque term as 1st argument when a structured term of type
+ [any()] is expected
+simple2_api.erl:116: The call lists:flatten
+ ({simple1_adt:tuple1()}) will never return since it differs in the 1st argument from the success typing arguments:
+ ([any()])
+simple2_api.erl:121: Guard test
+ {simple1_adt:d1(), 3} >
+ {simple1_adt:d1(), simple1_adt:tuple1()} contains an opaque term as 2nd argument
+simple2_api.erl:125: The call erlang:tuple_to_list
+ (B :: simple1_adt:tuple1()) contains an opaque term as 1st argument when a structured term of type
+ tuple() is expected
+simple2_api.erl:31: The call erlang:'!'
+ (A :: simple1_adt:d1(),
+ 'foo') contains an opaque term as 1st argument when terms of different types are expected in these positions
+simple2_api.erl:35: The call erlang:send
+ (A :: simple1_adt:d1(),
+ 'foo') contains an opaque term as 1st argument when terms of different types are expected in these positions
+simple2_api.erl:51: The call erlang:'<'
+ (A :: simple1_adt:d1(),
+ 3) contains an opaque term as 1st argument when terms of different types are expected in these positions
+simple2_api.erl:59: The call lists:keysearch
+ (1,
+ A :: simple1_adt:d1(),
+ []) contains an opaque term as 2nd argument when terms of different types are expected in these positions
+simple2_api.erl:67: The call lists:keysearch
+ ('key',
+ 1,
+ A :: simple1_adt:tuple1()) contains an opaque term as 3rd argument when terms of different types are expected in these positions
+simple2_api.erl:96: The call lists:keyreplace
+ ('a',
+ 1,
+ [{1, 2}],
+ A :: simple1_adt:tuple1()) contains an opaque term as 4th argument when terms of different types are expected in these positions
diff --git a/lib/dialyzer/test/indent_SUITE_data/results/suppress_request b/lib/dialyzer/test/indent_SUITE_data/results/suppress_request
new file mode 100644
index 0000000000..c08f1798c1
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/suppress_request
@@ -0,0 +1,11 @@
+
+suppress_request.erl:21: Expression produces a value of type
+ {'a', 'b'}, but this value is unmatched
+suppress_request.erl:25: Expression produces a value of type
+ {'a', 'b'}, but this value is unmatched
+suppress_request.erl:39: Guard test
+ 2 =:=
+ A :: fun((none()) -> no_return()) can never succeed
+suppress_request.erl:7: Type specification suppress_request:test1
+ ('a' | 'b') -> 'ok' is a subtype of the success typing: suppress_request:test1
+ ('a' | 'b' | 'c') -> 'ok'
diff --git a/lib/dialyzer/test/indent_SUITE_data/results/trec b/lib/dialyzer/test/indent_SUITE_data/results/trec
new file mode 100644
index 0000000000..f19f728750
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/trec
@@ -0,0 +1,10 @@
+
+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:32: Record construction violates the declared type for #foo{} since variable A cannot be of type
+ atom()
+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/indent_SUITE_data/results/whereis_control_flow1 b/lib/dialyzer/test/indent_SUITE_data/results/whereis_control_flow1
new file mode 100644
index 0000000000..0e733fced6
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/results/whereis_control_flow1
@@ -0,0 +1,4 @@
+
+whereis_control_flow1.erl:13: The call erlang:register
+ (AnAtom :: atom(),
+ Pid :: pid()) might fail due to a possible race condition caused by its combination with the erlang:whereis(AnAtom::any()) call in whereis_control_flow1.erl on line 8
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/abs.erl b/lib/dialyzer/test/indent_SUITE_data/src/abs.erl
new file mode 100644
index 0000000000..0e38c3dbb7
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/abs.erl
@@ -0,0 +1,78 @@
+-module(abs).
+
+%% OTP-12948. erlang:abs/1 bug fix.
+
+-export([t/0]).
+
+t() ->
+ Fs = [fun i1/0, fun i2/0, fun i3/0, fun i4/0, fun f1/0, fun erl_551/0],
+ _ = [catch F() || F <- Fs],
+ ok.
+
+i1() ->
+ A = int(),
+ I1 = i1(A),
+ true = I1 < 2,
+ true = I1 < 1. % can never match
+
+-spec i1(neg_integer()) -> non_neg_integer().
+
+i1(A) when is_integer(A), A < 0 ->
+ abs(A).
+
+i2() ->
+ A = int(),
+ I2 = i2(A),
+ true = I2 < 1,
+ true = I2 < 0. % can never match
+
+-spec i2(non_neg_integer()) -> non_neg_integer().
+
+i2(A) when is_integer(A), A >= 0 ->
+ abs(A).
+
+i3() ->
+ A = int(),
+ I3 = i3(A),
+ true = I3 < -1,
+ true = I3 < 0. % can never match
+
+-spec i3(integer()) -> non_neg_integer().
+
+i3(A) when is_integer(A) ->
+ abs(A).
+
+i4() ->
+ A = int(),
+ I4 = i4(A),
+ true = I4 =:= 0 orelse I4 =:= 1,
+ true = I4 < 0 orelse I4 > 1. % can never match
+
+-spec i4(integer()) -> number().
+
+i4(A) when A =:= -1; A =:= 0; A =:= 1 ->
+ abs(A).
+
+f1() ->
+ F1 = f1(float()),
+ math:sqrt(F1).
+
+f1(A) ->
+ abs(A).
+
+erl_551() ->
+ accept(9),
+ accept(-3).
+
+accept(Number) when abs(Number) >= 8 -> first;
+accept(_Number) -> second.
+
+-spec int() -> integer().
+
+int() ->
+ foo:bar().
+
+-spec float() -> float().
+
+float() ->
+ math:sqrt(1.0).
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/app_call.erl b/lib/dialyzer/test/indent_SUITE_data/src/app_call.erl
new file mode 100644
index 0000000000..54d178d29a
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/app_call.erl
@@ -0,0 +1,17 @@
+-module(app_call).
+-export([test/1]).
+
+test(m) ->
+ M = get_mod(),
+ M:foo();
+test(f) ->
+ F = get_fun(),
+ mod:F();
+test(_) ->
+ ok.
+
+get_mod() ->
+ 42.
+
+get_fun() ->
+ {gazonk, []}.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/blame_contract_range.erl b/lib/dialyzer/test/indent_SUITE_data/src/blame_contract_range.erl
new file mode 100644
index 0000000000..efd3332b44
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/blame_contract_range.erl
@@ -0,0 +1,16 @@
+%%-----------------------------------------------------------------------
+%% A test where the contract is wrongly specified by the programmer;
+%% however, this is found only by refinement.
+%% Dialyzer in R14B01 and prior gave a confusing (if not bogus) warning
+%% for this case. Corrected in R14B02.
+%%-----------------------------------------------------------------------
+-module(blame_contract_range).
+
+-export([foo/0]).
+
+foo() ->
+ bar(b).
+
+-spec bar(atom()) -> a.
+bar(a) -> a;
+bar(b) -> b.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/bs_fail_constr.erl b/lib/dialyzer/test/indent_SUITE_data/src/bs_fail_constr.erl
new file mode 100644
index 0000000000..8c1f8c009a
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/bs_fail_constr.erl
@@ -0,0 +1,15 @@
+-module(bs_fail_constr).
+
+-export([w1/1, w2/1, w3/1, w4/1]).
+
+w1(V) when is_float(V) ->
+ <<V/integer>>.
+
+w2(V) when is_atom(V) ->
+ <<V/binary>>.
+
+w3(S) when is_integer(S), S < 0 ->
+ <<42:S/integer>>.
+
+w4(V) when is_float(V) ->
+ <<V/utf32>>.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/callbacks_and_specs/my_behaviour.erl b/lib/dialyzer/test/indent_SUITE_data/src/callbacks_and_specs/my_behaviour.erl
new file mode 100644
index 0000000000..c4e5203448
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/callbacks_and_specs/my_behaviour.erl
@@ -0,0 +1,11 @@
+-module(my_behaviour).
+
+-callback callback_init(Parent :: pid()) -> {'ok', State::term()}.
+
+-callback callback_cast(State::term(), From::pid(), Msg::term()) ->
+ {'noreply', NewState::term()}.
+
+-callback callback_call(State::term(), From::pid(), Msg::term()) ->
+ {'reply', NewState::term(), Reply::term()}.
+
+-callback callback_exit(State::term()) -> 'ok'.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/callbacks_and_specs/my_callbacks_correct.erl b/lib/dialyzer/test/indent_SUITE_data/src/callbacks_and_specs/my_callbacks_correct.erl
new file mode 100644
index 0000000000..041b4ac56c
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/callbacks_and_specs/my_callbacks_correct.erl
@@ -0,0 +1,59 @@
+-module(my_callbacks_correct).
+
+-export([
+ callback_init/1
+ , callback_call/3
+ , callback_cast/3
+ , callback_exit/1
+ ]).
+
+-record(state, {
+ parent :: pid(),
+ status = init :: 'init' | 'open' | 'closed',
+ subscribe = [] :: list({pid(), integer()}),
+ counter = 1 :: integer()
+ }).
+
+-type state() :: #state{}.
+
+-type cast_message() :: 'open' | 'closed'.
+
+-type call_message() :: 'subscribe' | 'unsubscribe'.
+-type call_reply() :: 'accepted' | 'rejected'.
+
+-spec callback_init(Parent::pid()) -> {'ok', state()}.
+
+callback_init(Parent) ->
+ {ok, #state{parent = Parent}}.
+
+-spec callback_cast(state(), pid(), cast_message()) -> {'noreply', state()}.
+
+callback_cast(#state{parent = Pid} = State, Pid, Message)
+ when Message =:= 'open'; Message =:= 'close' ->
+ {noreply, State#state{status = Message}};
+callback_cast(State, _Pid, _Message) ->
+ {noreply, State}.
+
+-spec callback_call(state(), pid(), call_message()) ->
+ {'reply', state(), call_reply()}.
+
+callback_call(#state{status = open, subscribe = Subscribers} = State,
+ Pid, Message)
+ when Message =:= 'subscribe';
+ Message =:= 'unsubscribe' ->
+ NewState =
+ case Message of
+ subscribe ->
+ N = State#state.counter,
+ State#state{subscribe = [{Pid, N}|Subscribers], counter = N+1};
+ unsubscribe ->
+ State#state{subscribe = lists:keydelete(Pid, 1, Subscribers)}
+ end,
+ {reply, NewState, accepted};
+callback_call(State, _Pid, _Message) ->
+ {reply, State, rejected}.
+
+-spec callback_exit(state()) -> 'ok'.
+
+callback_exit(_State) ->
+ ok.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/callbacks_and_specs/my_callbacks_wrong.erl b/lib/dialyzer/test/indent_SUITE_data/src/callbacks_and_specs/my_callbacks_wrong.erl
new file mode 100644
index 0000000000..0459622dc1
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/callbacks_and_specs/my_callbacks_wrong.erl
@@ -0,0 +1,61 @@
+-module(my_callbacks_wrong).
+
+-export([
+ callback_init/1
+ , callback_call/3
+ , callback_cast/3
+ , callback_exit/1
+ ]).
+
+-behaviour(my_behaviour).
+
+-record(state, {
+ parent :: pid(),
+ status = init :: 'init' | 'open' | 'closed',
+ subscribe = [] :: list({pid(), integer()}),
+ counter = 1 :: integer()
+ }).
+
+-type state() :: #state{}.
+
+-type cast_message() :: 'open' | 'closed'.
+
+-type call_message() :: 'subscribe' | 'unsubscribe'.
+-type call_reply() :: 'accepted' | 'rejected'.
+
+-spec callback_init(Parent::pid()) -> state(). %% Wrong return spec
+
+callback_init(Parent) -> #state{parent = Parent}. %% Wrong return
+
+-spec callback_cast(state(), pid() | atom(), cast_message()) ->
+ {'noreply' | 'reply', state()}. %% More generic spec
+
+callback_cast(#state{parent = Pid} = State, Pid, Message)
+ when Message =:= 'open'; Message =:= 'close' ->
+ {noreply, State#state{status = Message}};
+callback_cast(State, _Pid, _Message) ->
+ {noreply, State}.
+
+-spec callback_call(state(), atom(), call_message()) -> %% Wrong arg spec
+ {'reply', state(), call_reply()}.
+
+callback_call(#state{status = open, subscribe = Subscribers} = State,
+ Pid, Message)
+ when Message =:= 'subscribe';
+ Message =:= 'unsubscribe' ->
+ NewState =
+ case Message of
+ subscribe ->
+ N = State#state.counter,
+ State#state{subscribe = [{Pid, N}|Subscribers], counter = N+1};
+ unsubscribe ->
+ State#state{subscribe = lists:keydelete(Pid, 1, Subscribers)}
+ end,
+ {reply, NewState, accepted};
+callback_call(State, _Pid, _Message) ->
+ {reply, State, rejected}.
+
+-spec callback_exit(state()) -> ok.
+
+callback_exit(_State) ->
+ ok.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/contract3.erl b/lib/dialyzer/test/indent_SUITE_data/src/contract3.erl
new file mode 100644
index 0000000000..a6ce91882e
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/contract3.erl
@@ -0,0 +1,40 @@
+%%%-------------------------------------------------------------------
+%%% File : contract3.erl
+%%% Author : Tobias Lindahl <[email protected]>
+%%% Description : Check overloaded domains
+%%%
+%%% Created : 2 Nov 2007 by Tobias Lindahl <[email protected]>
+%%%-------------------------------------------------------------------
+-module(contract3).
+
+-export([t/3]).
+
+t(X, Y, Z) ->
+ t1(X),
+ t2(X, Y),
+ t3(X, Y, Z).
+
+-spec t1(atom()|integer()) -> integer();
+ (atom()|list()) -> atom().
+
+t1(X) ->
+ f(X).
+
+-spec t2(atom(), integer()) -> integer();
+ (atom(), list()) -> atom().
+
+t2(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/indent_SUITE_data/src/contracts_with_subtypes.erl b/lib/dialyzer/test/indent_SUITE_data/src/contracts_with_subtypes.erl
new file mode 100644
index 0000000000..dbabd904c2
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/contracts_with_subtypes.erl
@@ -0,0 +1,300 @@
+-module(contracts_with_subtypes).
+
+-compile(export_all).
+
+%===============================================================================
+
+-spec extract() -> 'ok'.
+
+extract() ->
+ case dz_extract() of
+ {ok, Val} -> Val;
+ error -> exit(boom)
+ end.
+
+-spec dz_extract() -> RetValue when
+ FileList :: something,
+ RetValue :: {ok, FileList} | error.
+
+dz_extract() -> get(foo).
+
+%-------------------------------------------------------------------------------
+
+-spec extract2() -> 'ok'.
+
+extract2() ->
+ case dz_extract2() of
+ {ok, Val} -> Val;
+ error -> exit(boom)
+ end.
+
+-spec dz_extract2() -> RetValue when
+ RetValue :: {ok, FileList} | error,
+ FileList :: something.
+
+dz_extract2() -> get(foo).
+
+%===============================================================================
+
+-spec foo1(Arg1) -> Res when
+ Arg1 :: atom(),
+ Res :: atom().
+
+foo1(X) -> X.
+
+-spec foo2(Arg1) -> Res when
+ Arg1 :: Arg2,
+ Arg2 :: atom(),
+ Res :: atom().
+
+foo2(X) -> X.
+
+-spec foo3(Arg1) -> Res when
+ Arg2 :: atom(),
+ Arg1 :: Arg2,
+ Res :: atom().
+
+foo3(X) -> X.
+
+-spec foo4(Type) -> Type when is_subtype(Type, atom()).
+
+foo4(X) -> X.
+
+-spec foo5(Type :: atom()) -> Type :: atom().
+
+foo5(X) -> X.
+
+-spec foo6(Type) -> Type when Type :: atom().
+
+foo6(X) -> X.
+
+-spec foo7(Type) -> Type.
+
+foo7(X) -> X.
+
+%-------------------------------------------------------------------------------
+
+bar(1) -> foo1(5);
+bar(2) -> foo2(5);
+bar(3) -> foo3(5);
+bar(4) -> foo4(5);
+bar(5) -> foo5(5);
+bar(6) -> foo6(5);
+bar(7) -> foo7(5).
+
+wrong_foo6() ->
+ b = foo6(a).
+
+%===============================================================================
+
+-spec rec_arg(Arg) -> ok when
+ Arg :: {a, A} | {b, B},
+ A :: a | {b, B},
+ B :: b | {a, A}.
+
+rec_arg(X) -> get(X).
+
+c(aa) -> rec_arg({a, a});
+c(bb) -> rec_arg({b, b});
+c(abb) -> rec_arg({a, {b, b}});
+c(baa) -> rec_arg({b, {a, a}});
+c(abaa) -> rec_arg({a, {b, {a, a}}});
+c(babb) -> rec_arg({b, {a, {b, b}}});
+c(ababb) -> rec_arg({a, {b, {a, {b, b}}}});
+c(babaa) -> rec_arg({b, {a, {b, {a, a}}}}).
+
+w(ab) -> rec_arg({a, b}); % breaks the contract
+w(ba) -> rec_arg({b, a}); % breaks the contract
+w(aba) -> rec_arg({a, {b, a}}); % no longer breaks the contract
+w(bab) -> rec_arg({b, {a, b}}); % breaks the contract
+w(abab) -> rec_arg({a, {b, {a, b}}}); % no longer breaks the contract
+w(baba) -> rec_arg({b, {a, {b, a}}}); % no longer breaks the contract
+w(ababa) -> rec_arg({a, {b, {a, {b, a}}}});
+w(babab) -> rec_arg({b, {a, {b, {a, b}}}}).
+
+%% For comparison: the same thing with types
+
+-type ab() :: {a, a()} | {b, b()}.
+-type a() :: a | {b, b()}.
+-type b() :: b | {a, a()}.
+
+-spec rec2(Arg) -> ok when
+ Arg :: ab().
+
+rec2(X) -> get(X).
+
+d(aa) -> rec2({a, a});
+d(bb) -> rec2({b, b});
+d(abb) -> rec2({a, {b, b}});
+d(baa) -> rec2({b, {a, a}});
+d(abaa) -> rec2({a, {b, {a, a}}});
+d(babb) -> rec2({b, {a, {b, b}}});
+d(ababb) -> rec2({a, {b, {a, {b, b}}}});
+d(babaa) -> rec2({b, {a, {b, {a, a}}}}).
+
+q(ab) -> rec2({a, b}); % breaks the contract
+q(ba) -> rec2({b, a}); % breaks the contract
+q(aba) -> rec2({a, {b, a}}); % breaks the contract
+q(bab) -> rec2({b, {a, b}}); % breaks the contract
+q(abab) -> rec2({a, {b, {a, b}}}); % breaks the contract
+q(baba) -> rec2({b, {a, {b, a}}}); % breaks the contract
+q(ababa) -> rec2({a, {b, {a, {b, a}}}}); % breaks the contract
+q(babab) -> rec2({b, {a, {b, {a, b}}}}); % breaks the contract
+q(ababab) -> rec2({a, {b, {a, {b, {a, b}}}}});
+q(bababa) -> rec2({b, {a, {b, {a, {b, a}}}}});
+q(abababa) -> rec2({a, {b, {a, {b, {a, {b, a}}}}}});
+q(bababab) -> rec2({b, {a, {b, {a, {b, {a, b}}}}}}).
+
+%===============================================================================
+
+-type dublo(X) :: {X, X}.
+
+-type weird(X,Y) :: {X, Y, X, X}.
+
+-spec forfun(dublo(Var)) -> ok when Var :: atom().
+
+forfun(_) -> ok.
+
+-spec forfun2(weird(Var, Var)) -> ok when Var :: atom().
+
+forfun2(_) -> ok.
+
+%===============================================================================
+
+-spec shallow(X) -> {ok, X} | {ok, X, file:filename()} | err1 | err2.
+
+shallow(X) -> get(X).
+
+st(X) when is_atom(X) ->
+ case shallow(X) of
+ err1 -> ok;
+ err2 -> ok;
+ {ok, X} -> ok;
+ {ok, X, Res} ->
+ case Res of
+ 1 -> bad;
+ _Other -> ok
+ end;
+ alpha -> bad;
+ {ok, 42} -> ok;
+ 42 -> bad
+ end.
+
+%-------------------------------------------------------------------------------
+
+-spec deep(X) -> Ret when
+ Ret :: {ok, X} | Err,
+ Err :: err1 | err2.
+
+deep(X) -> get(X).
+
+dt(X) when is_atom(X) ->
+ case deep(X) of
+ err1 -> ok;
+ err2 -> ok;
+ {ok, X} -> ok;
+ alpha -> bad;
+ {ok, 42} -> ok;
+ 42 -> bad
+ end.
+
+%-------------------------------------------------------------------------------
+
+-type local_errors() :: err1 | err2.
+
+-spec deep2(X) -> Ret when
+ Ret :: {ok, X} | Err,
+ Err :: local_errors().
+
+deep2(X) -> get(X).
+
+dt2(X) when is_atom(X) ->
+ case deep2(X) of
+ err1 -> ok;
+ err2 -> ok;
+ {ok, X} -> ok;
+ alpha -> bad;
+ {ok, 42} -> ok;
+ 42 -> bad
+ end.
+
+%-------------------------------------------------------------------------------
+
+-spec deep3(X) -> Ret when
+ Ret :: {ok, X, file:filename()} | Err,
+ Err :: local_errors().
+
+deep3(X) -> get(X).
+
+dt3(X) when is_atom(X) ->
+ case deep3(X) of
+ err1 -> ok;
+ err2 -> ok;
+ {ok, X, Res} ->
+ case Res of
+ 1 -> bad;
+ _Other -> ok
+ end;
+ {ok, X} -> bad;
+ alpha -> bad;
+ {ok, 42} -> bad;
+ 42 -> bad
+ end.
+
+%===============================================================================
+
+-spec flat_ets_new(Name, Options) -> atom() when
+ Name :: atom(),
+ Options :: [Option],
+ Option :: set
+ | ordered_set
+ | bag
+ | duplicate_bag
+ | public
+ | protected
+ | private
+ | named_table
+ | {keypos, integer()}
+ | {heir, pid(), term()}
+ | {heir, none}
+ | {write_concurrency, boolean()}
+ | {read_concurrency, boolean()}
+ | compressed.
+
+flat_ets_new(Name, Options) ->
+ get({Name, Options}).
+
+flat_ets_new_t() ->
+ flat_ets_new(12,[]),
+ flat_ets_new({a,b},[]),
+ flat_ets_new(name,[foo]),
+ flat_ets_new(name,{bag}),
+ flat_ets_new(name,bag),
+ ok.
+
+-type access() :: public | protected | private.
+-type type() :: set | ordered_set | bag | duplicate_bag.
+
+-spec factored_ets_new(Name, Options) -> atom() when
+ Name :: atom(),
+ Options :: [Option],
+ Option :: Type | Access | named_table | {keypos,Pos}
+ | {heir, Pid :: pid(), HeirData} | {heir, none} | Tweaks,
+ Type :: type(),
+ Access :: access(),
+ Tweaks :: {write_concurrency, boolean()}
+ | {read_concurrency, boolean()}
+ | compressed,
+ Pos :: pos_integer(),
+ HeirData :: term().
+
+factored_ets_new(Name, Options) ->
+ get({Name, Options}).
+
+factored_ets_new_t() ->
+ factored_ets_new(12,[]),
+ factored_ets_new({a,b},[]),
+ factored_ets_new(name,[foo]),
+ factored_ets_new(name,{bag}),
+ factored_ets_new(name,bag),
+ ok.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/dict_use.erl b/lib/dialyzer/test/indent_SUITE_data/src/dict_use.erl
new file mode 100644
index 0000000000..2527f166f2
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/dict_use.erl
@@ -0,0 +1,82 @@
+-module(dict_use).
+
+-export([ok1/0, ok2/0, ok3/0, ok4/0, ok5/0, ok6/0]).
+-export([middle/0]).
+-export([w1/0, w2/0, w3/0, w4/1, w5/0, w6/0, w7/0, w8/1, w9/0]).
+
+-define(DICT, dict).
+
+%%---------------------------------------------------------------------
+%% Cases that are OK
+%%---------------------------------------------------------------------
+
+ok1() ->
+ dict:new().
+
+ok2() ->
+ case dict:new() of X -> X end.
+
+ok3() ->
+ Dict1 = dict:new(),
+ Dict2 = dict:new(),
+ Dict1 =:= Dict2.
+
+ok4() ->
+ dict:fetch(foo, dict:new()).
+
+ok5() -> % this is OK since some_mod:new/0 might be returning a dict:dict()
+ dict:fetch(foo, some_mod:new()).
+
+ok6() ->
+ dict:store(42, elli, dict:new()).
+
+middle() ->
+ {w1(), w2()}.
+
+%%---------------------------------------------------------------------
+%% Cases that are problematic w.r.t. opacity of types
+%%---------------------------------------------------------------------
+
+w1() ->
+ gazonk = dict:new().
+
+w2() ->
+ case dict:new() of
+ [] -> nil;
+ 42 -> weird
+ end.
+
+w3() ->
+ try dict:new() of
+ [] -> nil;
+ 42 -> weird
+ catch
+ _:_ -> exception
+ end.
+
+w4(Dict) when is_list(Dict) ->
+ Dict =:= dict:new();
+w4(Dict) when is_atom(Dict) ->
+ Dict =/= dict:new().
+
+w5() ->
+ case dict:new() of
+ D when length(D) =/= 42 -> weird;
+ D when is_atom(D) -> weirder;
+ D when is_list(D) -> gazonk
+ end.
+
+w6() ->
+ is_list(dict:new()).
+
+w7() ->
+ dict:fetch(foo, [1,2,3]).
+
+w8(Fun) ->
+ dict:merge(Fun, 42, [1,2]).
+
+w9() ->
+ dict:store(42, elli,
+ {dict,0,16,16,8,80,48,
+ {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},
+ {{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]}}}).
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/fun_app.erl b/lib/dialyzer/test/indent_SUITE_data/src/fun_app.erl
new file mode 100644
index 0000000000..20b6138d26
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/fun_app.erl
@@ -0,0 +1,41 @@
+%% This is taken from the code of distel.
+
+-module(fun_app).
+-export([html_index/2]). % , lines/3, curry/2]).
+
+html_index(file,Dir) ->
+ fold_file(curry(fun lines/3,Dir),[],filename:join([Dir,"doc","man_index.html"])).
+
+fold_file(Fun,Acc0,File) ->
+ {ok, FD} = file:open(File, [read]),
+ Acc = fold_file_lines(FD,Fun,Acc0),
+ file:close(FD),
+ Acc.
+
+fold_file_lines(FD,Fun,Acc) ->
+ case io:get_line(FD, "") of
+ eof -> Acc;
+ Line -> fold_file_lines(FD,Fun,Fun(trim_nl(Line),Acc))
+ end.
+
+trim_nl(Str) -> lists:reverse(tl(lists:reverse(Str))).
+
+lines(Line,_,Dir) ->
+ case string:tokens(Line, "<> \"") of
+ ["TD", "A", "HREF=", "../"++Href, M|_] ->
+ case filename:basename(Href, ".html") of
+ "index" -> ok;
+ M -> e_set({file,M}, filename:join([Dir,Href]))
+ end;
+ _ -> ok
+ end.
+
+e_set(Key,Val) -> ets:insert(?MODULE, {Key,Val}).
+
+curry(F, Arg) ->
+ case erlang:fun_info(F,arity) of
+ {_,1} -> fun() -> F(Arg) end;
+ {_,2} -> fun(A) -> F(A,Arg) end;
+ {_,3} -> fun(A,B) -> F(A,B,Arg) end;
+ {_,4} -> fun(A,B,C) -> F(A,B,C,Arg) end
+ end.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/fun_app_args.erl b/lib/dialyzer/test/indent_SUITE_data/src/fun_app_args.erl
new file mode 100644
index 0000000000..b4409bc550
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/fun_app_args.erl
@@ -0,0 +1,12 @@
+-module(fun_app_args).
+
+-export([t/1]).
+
+-type ft() :: fun((a, []) -> any()).
+
+-record(r, {
+ h = c :: c | ft()
+}).
+
+t(#r{h = H}) ->
+ fun(_) -> (H)(b, []) end.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/guard_update.erl b/lib/dialyzer/test/indent_SUITE_data/src/guard_update.erl
new file mode 100644
index 0000000000..19d0089401
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/guard_update.erl
@@ -0,0 +1,18 @@
+-module(guard_update).
+
+-export([t/0, t2/0]).
+
+t() ->
+ f(#{a=>2}). %% Illegal
+
+f(M)
+ when M#{b := 7} =/= q
+ -> ok.
+
+t2() ->
+ f2(#{a=>2}). %% Legal!
+
+f2(M)
+ when M#{b := 7} =/= q;
+ M =/= p
+ -> ok.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/guard_warnings.erl b/lib/dialyzer/test/indent_SUITE_data/src/guard_warnings.erl
new file mode 100644
index 0000000000..6ab13eef9a
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/guard_warnings.erl
@@ -0,0 +1,118 @@
+%%
+%% A couple of tests for booleans in guards.
+%% Tests with suffix w have incomplete results due to weak dataflow.
+%% Tests with suffix ww have incomplete results due to weak dialyzer.
+%% Tests with suffix x should not give warnings.
+%%
+
+-module(and_bug).
+
+-compile(export_all).
+
+test1(X) when X and not X -> never.
+
+test2(X) when not X and X -> never.
+
+test3(X) when (X and not X) =:= true -> never.
+
+test4(X) when (not X and X) =:= true -> never.
+
+test5(X) when (X and not X) == true -> never.
+
+test6(X) when (not X and X) == true -> never.
+
+test7_w(X) when not (X or not X) -> never.
+
+test8_w(X) when not (not X or X) -> never.
+
+test9(X) when (X or not X) =:= false -> never.
+
+test10(X) when (not X or X) =:= false -> never.
+
+test11(X) when (X or not X) == false -> never.
+
+test12(X) when (not X or X) == false -> never.
+
+test13(X) when X and false -> never.
+
+test14(X) when false and X -> never.
+
+test15(X) when (X and false) =:= true -> never.
+
+test16(X) when (false and X) =:= true -> never.
+
+test17(X) when (X and false) == true -> never.
+
+test18(X) when (false and X) == true -> never.
+
+test19(X) when not (true or X) -> never.
+
+test20(X) when not (X or true) -> never.
+
+test21(X) when (true or X) =:= false -> never.
+
+test22(X) when (X or true) =:= false -> never.
+
+test23(X) when (true or X) == false -> never.
+
+test24(X) when (X or true) == false -> never.
+
+test25(X) when (false and X) -> never.
+
+test26(X) when (X and false) -> never.
+
+test27(X) when (false and X) =:= true -> never.
+
+test28(X) when (X and false) =:= true -> never.
+
+test29(X) when (false and X) == true -> never.
+
+test30(X) when (X and false) == true -> never.
+
+test31() when false and false -> never.
+
+test32() when (false and false) =:= true -> never.
+
+test33() when not (true and true) =:= true -> never.
+
+test34() when (false and false) == true -> never.
+
+test35() when not (true and true) == true -> never.
+
+test36() when false or false -> never.
+
+test37() when (false or false) =:= true -> never.
+
+test38() when not (false or false) =:= false -> never.
+
+test39() when (false or false) == true -> never.
+
+test40() when not (false or false) == false -> never.
+
+test41() when true =:= false -> never.
+
+test42() when true == false -> never.
+
+test43() when not (true =:= true) -> never.
+
+test44() when not (true == true) -> never.
+
+test45() when not (not (not (not (not (not (not true)))))) -> never.
+
+test46(X) when (X =:= true) and (X =:= false) -> never.
+
+test47(X) when (X == true) and (X == false) -> never.
+
+test48(X) when is_boolean(X) and (X =:= true) and (X =/= true) -> never.
+
+test49_x(X) when not (X or X) -> maybe.
+
+test50_x(X) when not (X and X) -> maybe.
+
+test51_x(X) when not (not X) -> maybe.
+
+test52_w(X) when is_boolean(X) and (X =/= true) and (X =:= true) -> never.
+
+test53_ww(X) when is_boolean(X) and (X =/= true) and (X =/= false) -> never.
+
+test54_w(X) when is_boolean(X) and not ((X =:= true) or (X =:= false)) -> never.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/map_galore.erl b/lib/dialyzer/test/indent_SUITE_data/src/map_galore.erl
new file mode 100644
index 0000000000..99eb73a5f6
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/map_galore.erl
@@ -0,0 +1,2800 @@
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(map_galore).
+-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
+ init_per_group/2,end_per_group/2
+ ]).
+
+-export([
+ t_build_and_match_literals/1, t_build_and_match_literals_large/1,
+ t_update_literals/1, t_update_literals_large/1,
+ t_match_and_update_literals/1, t_match_and_update_literals_large/1,
+ t_update_map_expressions/1,
+ t_update_assoc/1, t_update_assoc_large/1,
+ t_update_exact/1, t_update_exact_large/1,
+ t_guard_bifs/1,
+ t_guard_sequence/1, t_guard_sequence_large/1,
+ t_guard_update/1, t_guard_update_large/1,
+ t_guard_receive/1, t_guard_receive_large/1,
+ t_guard_fun/1,
+ t_update_deep/1,
+ t_list_comprehension/1,
+ t_map_sort_literals/1,
+ t_map_equal/1,
+ t_map_compare/1,
+ t_map_size/1,
+ t_is_map/1,
+
+ %% Specific Map BIFs
+ t_bif_map_get/1,
+ t_bif_map_find/1,
+ t_bif_map_is_key/1,
+ t_bif_map_keys/1,
+ t_bif_map_merge/1,
+ t_bif_map_new/1,
+ t_bif_map_put/1,
+ t_bif_map_remove/1,
+ t_bif_map_update/1,
+ t_bif_map_values/1,
+ t_bif_map_to_list/1,
+ t_bif_map_from_list/1,
+
+ %% erlang
+ t_erlang_hash/1,
+ t_map_encode_decode/1,
+
+ %% non specific BIF related
+ t_bif_build_and_check/1,
+ t_bif_merge_and_check/1,
+
+ %% maps module not bifs
+ t_maps_fold/1,
+ t_maps_map/1,
+ t_maps_size/1,
+ t_maps_without/1,
+
+ %% misc
+ t_erts_internal_order/1,
+ t_erts_internal_hash/1,
+ t_pdict/1,
+ t_ets/1,
+ t_dets/1,
+ t_tracing/1,
+
+ %% instruction-level tests
+ t_has_map_fields/1,
+ y_regs/1
+ ]).
+
+-include_lib("stdlib/include/ms_transform.hrl").
+
+-define(CHECK(Cond,Term),
+ case (catch (Cond)) of
+ true -> true;
+ _ -> io:format("###### CHECK FAILED ######~nINPUT: ~p~n", [Term]),
+ exit(Term)
+ end).
+
+suite() -> [].
+
+all() -> [
+ t_build_and_match_literals, t_build_and_match_literals_large,
+ t_update_literals, t_update_literals_large,
+ t_match_and_update_literals, t_match_and_update_literals_large,
+ t_update_map_expressions,
+ t_update_assoc, t_update_assoc_large,
+ t_update_exact, t_update_exact_large,
+ t_guard_bifs,
+ t_guard_sequence, t_guard_sequence_large,
+ t_guard_update, t_guard_update_large,
+ t_guard_receive, t_guard_receive_large,
+ t_guard_fun, t_list_comprehension,
+ t_update_deep,
+ t_map_equal, t_map_compare,
+ t_map_sort_literals,
+
+ %% Specific Map BIFs
+ t_bif_map_get,t_bif_map_find,t_bif_map_is_key,
+ t_bif_map_keys, t_bif_map_merge, t_bif_map_new,
+ t_bif_map_put,
+ t_bif_map_remove, t_bif_map_update,
+ t_bif_map_values,
+ t_bif_map_to_list, t_bif_map_from_list,
+
+ %% erlang
+ t_erlang_hash, t_map_encode_decode,
+ t_map_size, t_is_map,
+
+ %% non specific BIF related
+ t_bif_build_and_check,
+ t_bif_merge_and_check,
+
+ %% maps module
+ t_maps_fold, t_maps_map,
+ t_maps_size, t_maps_without,
+
+
+ %% Other functions
+ t_erts_internal_order,
+ t_erts_internal_hash,
+ t_pdict,
+ t_ets,
+ t_tracing,
+
+ %% instruction-level tests
+ t_has_map_fields,
+ y_regs
+ ].
+
+groups() -> [].
+
+init_per_suite(Config) -> Config.
+end_per_suite(_Config) -> ok.
+
+init_per_group(_GroupName, Config) -> Config.
+end_per_group(_GroupName, Config) -> Config.
+
+%% tests
+
+t_build_and_match_literals(Config) when is_list(Config) ->
+ #{} = #{},
+ #{1:=a} = #{1=>a},
+ #{1:=a,2:=b} = #{1=>a,2=>b},
+ #{1:=a,2:=b,3:="c"} = #{1=>a,2=>b,3=>"c"},
+ #{1:=a,2:=b,3:="c","4":="d"} = #{1=>a,2=>b,3=>"c","4"=>"d"},
+ #{1:=a,2:=b,3:="c","4":="d",<<"5">>:=<<"e">>} =
+ #{1=>a,2=>b,3=>"c","4"=>"d",<<"5">>=><<"e">>},
+ #{1:=a,2:=b,3:="c","4":="d",<<"5">>:=<<"e">>,{"6",7}:="f"} =
+ #{1=>a,2=>b,3=>"c","4"=>"d",<<"5">>=><<"e">>,{"6",7}=>"f"},
+ #{1:=a,2:=b,3:="c","4":="d",<<"5">>:=<<"e">>,{"6",7}:="f",8:=g} =
+ #{1=>a,2=>b,3=>"c","4"=>"d",<<"5">>=><<"e">>,{"6",7}=>"f",8=>g},
+
+ #{[]:=a,42.0:=b,x:={x,y},[a,b]:=list} =
+ #{[]=>a,42.0=>b,x=>{x,y},[a,b]=>list},
+
+ #{<<"hi all">> := 1} = #{<<"hi",32,"all">> => 1},
+
+ #{a:=X,a:=X=3,b:=4} = #{a=>3,b=>4}, % weird but ok =)
+
+ #{ a:=#{ b:=#{c := third, b:=second}}, b:=first} =
+ #{ b=>first, a=>#{ b=>#{c => third, b=> second}}},
+
+ M = #{ map_1=>#{ map_2=>#{value_3 => third}, value_2=> second}, value_1=>first},
+ M = #{ map_1:=#{ map_2:=#{value_3 := third}, value_2:= second}, value_1:=first} =
+ #{ map_1=>#{ map_2=>#{value_3 => third}, value_2=> second}, value_1=>first},
+
+ %% error case
+ %V = 32,
+ %{'EXIT',{{badmatch,_},_}} = (catch (#{<<"hi all">> => 1} = #{<<"hi",V,"all">> => 1})),
+ {'EXIT',{{badmatch,_},_}} = (catch (#{x:=3,x:=2} = #{x=>3})),
+ {'EXIT',{{badmatch,_},_}} = (catch (#{x:=2} = #{x=>3})),
+ {'EXIT',{{badmatch,_},_}} = (catch (#{x:=3} = {a,b,c})),
+ {'EXIT',{{badmatch,_},_}} = (catch (#{x:=3} = #{y=>3})),
+ {'EXIT',{{badmatch,_},_}} = (catch (#{x:=3} = #{x=>"three"})),
+ ok.
+
+t_build_and_match_literals_large(Config) when is_list(Config) ->
+ % normal non-repeating
+ M0 = #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ 16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" },
+
+ #{10:=a0,20:=b0,30:="c0","40":="d0",<<"50">>:="e0",{["00"]}:="10"} = M0,
+ #{11:=a1,21:=b1,31:="c1","41":="d1",<<"51">>:="e1",{["01"]}:="11"} = M0,
+ #{12:=a2,22:=b2,32:="c2","42":="d2",<<"52">>:="e2",{["02"]}:="12"} = M0,
+ #{13:=a3,23:=b3,33:="c3","43":="d3",<<"53">>:="e3",{["03"]}:="13"} = M0,
+ #{14:=a4,24:=b4,34:="c4","44":="d4",<<"54">>:="e4",{["04"]}:="14"} = M0,
+
+ #{15:=a5,25:=b5,35:="c5","45":="d5",<<"55">>:="e5",{["05"]}:="15"} = M0,
+ #{16:=a6,26:=b6,36:="c6","46":="d6",<<"56">>:="e6",{["06"]}:="16"} = M0,
+ #{17:=a7,27:=b7,37:="c7","47":="d7",<<"57">>:="e7",{["07"]}:="17"} = M0,
+ #{18:=a8,28:=b8,38:="c8","48":="d8",<<"58">>:="e8",{["08"]}:="18"} = M0,
+ #{19:=a9,29:=b9,39:="c9","49":="d9",<<"59">>:="e9",{["09"]}:="19"} = M0,
+
+ 60 = map_size(M0),
+ 60 = maps:size(M0),
+
+ % with repeating
+ M1 = #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 10=>na0,20=>nb0,30=>"nc0","40"=>"nd0",<<"50">>=>"ne0",{["00"]}=>"n10",
+ 11=>na1,21=>nb1,31=>"nc1","41"=>"nd1",<<"51">>=>"ne1",{["01"]}=>"n11",
+ 12=>na2,22=>nb2,32=>"nc2","42"=>"nd2",<<"52">>=>"ne2",{["02"]}=>"n12",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ 16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+
+ 13=>na3,23=>nb3,33=>"nc3","43"=>"nd3",<<"53">>=>"ne3",{["03"]}=>"n13",
+ 14=>na4,24=>nb4,34=>"nc4","44"=>"nd4",<<"54">>=>"ne4",{["04"]}=>"n14",
+
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" },
+
+ #{10:=na0,20:=nb0,30:="nc0","40":="nd0",<<"50">>:="ne0",{["00"]}:="n10"} = M1,
+ #{11:=na1,21:=nb1,31:="nc1","41":="nd1",<<"51">>:="ne1",{["01"]}:="n11"} = M1,
+ #{12:=na2,22:=nb2,32:="nc2","42":="nd2",<<"52">>:="ne2",{["02"]}:="n12"} = M1,
+ #{13:=na3,23:=nb3,33:="nc3","43":="nd3",<<"53">>:="ne3",{["03"]}:="n13"} = M1,
+ #{14:=na4,24:=nb4,34:="nc4","44":="nd4",<<"54">>:="ne4",{["04"]}:="n14"} = M1,
+
+ #{15:=a5,25:=b5,35:="c5","45":="d5",<<"55">>:="e5",{["05"]}:="15"} = M1,
+ #{16:=a6,26:=b6,36:="c6","46":="d6",<<"56">>:="e6",{["06"]}:="16"} = M1,
+ #{17:=a7,27:=b7,37:="c7","47":="d7",<<"57">>:="e7",{["07"]}:="17"} = M1,
+ #{18:=a8,28:=b8,38:="c8","48":="d8",<<"58">>:="e8",{["08"]}:="18"} = M1,
+ #{19:=a9,29:=b9,39:="c9","49":="d9",<<"59">>:="e9",{["09"]}:="19"} = M1,
+
+ 60 = map_size(M1),
+ 60 = maps:size(M1),
+
+ % with floats
+
+ M2 = #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ 16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19",
+
+ 10.0=>fa0,20.0=>fb0,30.0=>"fc0",
+ 11.0=>fa1,21.0=>fb1,31.0=>"fc1",
+ 12.0=>fa2,22.0=>fb2,32.0=>"fc2",
+ 13.0=>fa3,23.0=>fb3,33.0=>"fc3",
+ 14.0=>fa4,24.0=>fb4,34.0=>"fc4",
+
+ 15.0=>fa5,25.0=>fb5,35.0=>"fc5",
+ 16.0=>fa6,26.0=>fb6,36.0=>"fc6",
+ 17.0=>fa7,27.0=>fb7,37.0=>"fc7",
+ 18.0=>fa8,28.0=>fb8,38.0=>"fc8",
+ 19.0=>fa9,29.0=>fb9,39.0=>"fc9"},
+
+ #{10:=a0,20:=b0,30:="c0","40":="d0",<<"50">>:="e0",{["00"]}:="10"} = M2,
+ #{11:=a1,21:=b1,31:="c1","41":="d1",<<"51">>:="e1",{["01"]}:="11"} = M2,
+ #{12:=a2,22:=b2,32:="c2","42":="d2",<<"52">>:="e2",{["02"]}:="12"} = M2,
+ #{13:=a3,23:=b3,33:="c3","43":="d3",<<"53">>:="e3",{["03"]}:="13"} = M2,
+ #{14:=a4,24:=b4,34:="c4","44":="d4",<<"54">>:="e4",{["04"]}:="14"} = M2,
+
+ #{15:=a5,25:=b5,35:="c5","45":="d5",<<"55">>:="e5",{["05"]}:="15"} = M2,
+ #{16:=a6,26:=b6,36:="c6","46":="d6",<<"56">>:="e6",{["06"]}:="16"} = M2,
+ #{17:=a7,27:=b7,37:="c7","47":="d7",<<"57">>:="e7",{["07"]}:="17"} = M2,
+ #{18:=a8,28:=b8,38:="c8","48":="d8",<<"58">>:="e8",{["08"]}:="18"} = M2,
+ #{19:=a9,29:=b9,39:="c9","49":="d9",<<"59">>:="e9",{["09"]}:="19"} = M2,
+
+ #{10.0:=fa0,20.0:=fb0,30.0:="fc0","40":="d0",<<"50">>:="e0",{["00"]}:="10"} = M2,
+ #{11.0:=fa1,21.0:=fb1,31.0:="fc1","41":="d1",<<"51">>:="e1",{["01"]}:="11"} = M2,
+ #{12.0:=fa2,22.0:=fb2,32.0:="fc2","42":="d2",<<"52">>:="e2",{["02"]}:="12"} = M2,
+ #{13.0:=fa3,23.0:=fb3,33.0:="fc3","43":="d3",<<"53">>:="e3",{["03"]}:="13"} = M2,
+ #{14.0:=fa4,24.0:=fb4,34.0:="fc4","44":="d4",<<"54">>:="e4",{["04"]}:="14"} = M2,
+
+ #{15.0:=fa5,25.0:=fb5,35.0:="fc5","45":="d5",<<"55">>:="e5",{["05"]}:="15"} = M2,
+ #{16.0:=fa6,26.0:=fb6,36.0:="fc6","46":="d6",<<"56">>:="e6",{["06"]}:="16"} = M2,
+ #{17.0:=fa7,27.0:=fb7,37.0:="fc7","47":="d7",<<"57">>:="e7",{["07"]}:="17"} = M2,
+ #{18.0:=fa8,28.0:=fb8,38.0:="fc8","48":="d8",<<"58">>:="e8",{["08"]}:="18"} = M2,
+ #{19.0:=fa9,29.0:=fb9,39.0:="fc9","49":="d9",<<"59">>:="e9",{["09"]}:="19"} = M2,
+
+ 90 = map_size(M2),
+ 90 = maps:size(M2),
+
+ % with bignums
+ M3 = #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ 16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19",
+
+ 10.0=>fa0,20.0=>fb0,30.0=>"fc0",
+ 11.0=>fa1,21.0=>fb1,31.0=>"fc1",
+ 12.0=>fa2,22.0=>fb2,32.0=>"fc2",
+ 13.0=>fa3,23.0=>fb3,33.0=>"fc3",
+ 14.0=>fa4,24.0=>fb4,34.0=>"fc4",
+
+ 15.0=>fa5,25.0=>fb5,35.0=>"fc5",
+ 16.0=>fa6,26.0=>fb6,36.0=>"fc6",
+ 17.0=>fa7,27.0=>fb7,37.0=>"fc7",
+ 18.0=>fa8,28.0=>fb8,38.0=>"fc8",
+ 19.0=>fa9,29.0=>fb9,39.0=>"fc9",
+
+ 36893488147419103232=>big1, 73786976294838206464=>big2,
+ 147573952589676412928=>big3, 18446744073709551616=>big4,
+ 4294967296=>big5, 8589934592=>big6,
+ 4294967295=>big7, 67108863=>big8
+ },
+
+ #{10:=a0,20:=b0,30:="c0","40":="d0",<<"50">>:="e0",{["00"]}:="10"} = M3,
+ #{11:=a1,21:=b1,31:="c1","41":="d1",<<"51">>:="e1",{["01"]}:="11"} = M3,
+ #{12:=a2,22:=b2,32:="c2","42":="d2",<<"52">>:="e2",{["02"]}:="12"} = M3,
+ #{13:=a3,23:=b3,33:="c3","43":="d3",<<"53">>:="e3",{["03"]}:="13"} = M3,
+ #{14:=a4,24:=b4,34:="c4","44":="d4",<<"54">>:="e4",{["04"]}:="14"} = M3,
+
+ #{15:=a5,25:=b5,35:="c5","45":="d5",<<"55">>:="e5",{["05"]}:="15"} = M3,
+ #{16:=a6,26:=b6,36:="c6","46":="d6",<<"56">>:="e6",{["06"]}:="16"} = M3,
+ #{17:=a7,27:=b7,37:="c7","47":="d7",<<"57">>:="e7",{["07"]}:="17"} = M3,
+ #{18:=a8,28:=b8,38:="c8","48":="d8",<<"58">>:="e8",{["08"]}:="18"} = M3,
+ #{19:=a9,29:=b9,39:="c9","49":="d9",<<"59">>:="e9",{["09"]}:="19"} = M3,
+
+ #{10.0:=fa0,20.0:=fb0,30.0:="fc0","40":="d0",<<"50">>:="e0",{["00"]}:="10"} = M3,
+ #{11.0:=fa1,21.0:=fb1,31.0:="fc1","41":="d1",<<"51">>:="e1",{["01"]}:="11"} = M3,
+ #{12.0:=fa2,22.0:=fb2,32.0:="fc2","42":="d2",<<"52">>:="e2",{["02"]}:="12"} = M3,
+ #{13.0:=fa3,23.0:=fb3,33.0:="fc3","43":="d3",<<"53">>:="e3",{["03"]}:="13"} = M3,
+ #{14.0:=fa4,24.0:=fb4,34.0:="fc4","44":="d4",<<"54">>:="e4",{["04"]}:="14"} = M3,
+
+ #{15.0:=fa5,25.0:=fb5,35.0:="fc5","45":="d5",<<"55">>:="e5",{["05"]}:="15"} = M3,
+ #{16.0:=fa6,26.0:=fb6,36.0:="fc6","46":="d6",<<"56">>:="e6",{["06"]}:="16"} = M3,
+ #{17.0:=fa7,27.0:=fb7,37.0:="fc7","47":="d7",<<"57">>:="e7",{["07"]}:="17"} = M3,
+ #{18.0:=fa8,28.0:=fb8,38.0:="fc8","48":="d8",<<"58">>:="e8",{["08"]}:="18"} = M3,
+ #{19.0:=fa9,29.0:=fb9,39.0:="fc9","49":="d9",<<"59">>:="e9",{["09"]}:="19"} = M3,
+
+ #{36893488147419103232:=big1,67108863:=big8,"45":="d5",<<"55">>:="e5",{["05"]}:="15"} = M3,
+ #{147573952589676412928:=big3,8589934592:=big6,"46":="d6",<<"56">>:="e6",{["06"]}:="16"} = M3,
+ #{4294967296:=big5,18446744073709551616:=big4,"47":="d7",<<"57">>:="e7",{["07"]}:="17"} = M3,
+ #{4294967295:=big7,73786976294838206464:=big2,"48":="d8",<<"58">>:="e8",{["08"]}:="18"} = M3,
+
+ 98 = map_size(M3),
+ 98 = maps:size(M3),
+
+ %% with maps
+
+ M4 = #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ 16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19",
+
+ 10.0=>fa0,20.0=>fb0,30.0=>"fc0",
+ 11.0=>fa1,21.0=>fb1,31.0=>"fc1",
+ 12.0=>fa2,22.0=>fb2,32.0=>"fc2",
+ 13.0=>fa3,23.0=>fb3,33.0=>"fc3",
+ 14.0=>fa4,24.0=>fb4,34.0=>"fc4",
+
+ 15.0=>fa5,25.0=>fb5,35.0=>"fc5",
+ 16.0=>fa6,26.0=>fb6,36.0=>"fc6",
+ 17.0=>fa7,27.0=>fb7,37.0=>"fc7",
+ 18.0=>fa8,28.0=>fb8,38.0=>"fc8",
+ 19.0=>fa9,29.0=>fb9,39.0=>"fc9",
+
+ #{ one => small, map => key } => "small map key 1",
+ #{ second => small, map => key } => "small map key 2",
+ #{ third => small, map => key } => "small map key 3",
+
+ #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ 16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 1",
+
+ #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ k16=>a6,k26=>b6,k36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 2" },
+
+ #{10:=a0,20:=b0,30:="c0","40":="d0",<<"50">>:="e0",{["00"]}:="10"} = M4,
+ #{11:=a1,21:=b1,31:="c1","41":="d1",<<"51">>:="e1",{["01"]}:="11"} = M4,
+ #{12:=a2,22:=b2,32:="c2","42":="d2",<<"52">>:="e2",{["02"]}:="12"} = M4,
+ #{13:=a3,23:=b3,33:="c3","43":="d3",<<"53">>:="e3",{["03"]}:="13"} = M4,
+ #{14:=a4,24:=b4,34:="c4","44":="d4",<<"54">>:="e4",{["04"]}:="14"} = M4,
+
+ #{15:=a5,25:=b5,35:="c5","45":="d5",<<"55">>:="e5",{["05"]}:="15"} = M4,
+ #{16:=a6,26:=b6,36:="c6","46":="d6",<<"56">>:="e6",{["06"]}:="16"} = M4,
+ #{17:=a7,27:=b7,37:="c7","47":="d7",<<"57">>:="e7",{["07"]}:="17"} = M4,
+ #{18:=a8,28:=b8,38:="c8","48":="d8",<<"58">>:="e8",{["08"]}:="18"} = M4,
+ #{19:=a9,29:=b9,39:="c9","49":="d9",<<"59">>:="e9",{["09"]}:="19"} = M4,
+
+ #{ #{ one => small, map => key } := "small map key 1",
+ #{ second => small, map => key } := "small map key 2",
+ #{ third => small, map => key } := "small map key 3" } = M4,
+
+ #{ #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ 16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } := "large map key 1",
+
+ #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ k16=>a6,k26=>b6,k36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } := "large map key 2" } = M4,
+
+
+ #{ 15:=V1,25:=b5,35:=V2,"45":="d5",<<"55">>:=V3,{["05"]}:="15",
+ #{ one => small, map => key } := "small map key 1",
+ #{ second => small, map => key } := V4,
+ #{ third => small, map => key } := "small map key 3",
+ #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ 16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } := V5 } = M4,
+
+ a5 = V1,
+ "c5" = V2,
+ "e5" = V3,
+ "small map key 2" = V4,
+ "large map key 1" = V5,
+
+ 95 = map_size(M4),
+ 95 = maps:size(M4),
+
+ % call for value
+
+ M5 = #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ 16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19",
+
+ 10.0=>fa0,20.0=>fb0,30.0=>"fc0",
+ 11.0=>fa1,21.0=>fb1,31.0=>"fc1",
+ 12.0=>fa2,22.0=>fb2,32.0=>"fc2",
+ 13.0=>fa3,23.0=>fb3,33.0=>"fc3",
+ 14.0=>fa4,24.0=>fb4,34.0=>"fc4",
+
+ 15.0=>fa5,25.0=>fb5,35.0=>"fc5",
+ 16.0=>fa6,26.0=>fb6,36.0=>"fc6",
+ 17.0=>fa7,27.0=>fb7,37.0=>"fc7",
+ 18.0=>fa8,28.0=>fb8,38.0=>"fc8",
+ 19.0=>fa9,29.0=>fb9,39.0=>"fc9",
+
+ #{ one => small, map => key } => "small map key 1",
+ #{ second => small, map => key } => "small map key 2",
+ #{ third => small, map => key } => "small map key 3",
+
+ #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ 16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 1",
+
+ #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ k16=>a6,k26=>b6,k36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 2" },
+
+ #{10:=a0,20:=b0,30:="c0","40":="d0",<<"50">>:="e0",{["00"]}:="10"} = M5,
+ #{11:=a1,21:=b1,31:="c1","41":="d1",<<"51">>:="e1",{["01"]}:="11"} = M5,
+ #{12:=a2,22:=b2,32:="c2","42":="d2",<<"52">>:="e2",{["02"]}:="12"} = M5,
+ #{13:=a3,23:=b3,33:="c3","43":="d3",<<"53">>:="e3",{["03"]}:="13"} = M5,
+ #{14:=a4,24:=b4,34:="c4","44":="d4",<<"54">>:="e4",{["04"]}:="14"} = M5,
+
+ #{15:=a5,25:=b5,35:="c5","45":="d5",<<"55">>:="e5",{["05"]}:="15"} = M5,
+ #{16:=a6,26:=b6,36:="c6","46":="d6",<<"56">>:="e6",{["06"]}:="16"} = M5,
+ #{17:=a7,27:=b7,37:="c7","47":="d7",<<"57">>:="e7",{["07"]}:="17"} = M5,
+ #{18:=a8,28:=b8,38:="c8","48":="d8",<<"58">>:="e8",{["08"]}:="18"} = M5,
+ #{19:=a9,29:=b9,39:="c9","49":="d9",<<"59">>:="e9",{["09"]}:="19"} = M5,
+
+ #{ #{ one => small, map => key } := "small map key 1",
+ #{ second => small, map => key } := "small map key 2",
+ #{ third => small, map => key } := "small map key 3" } = M5,
+
+ #{ #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ 16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } := "large map key 1",
+
+ #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ k16=>a6,k26=>b6,k36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } := "large map key 2" } = M5,
+
+ 95 = map_size(M5),
+ 95 = maps:size(M5),
+
+ %% remember
+
+ #{10:=a0,20:=b0,30:="c0","40":="d0",<<"50">>:="e0",{["00"]}:="10"} = M0,
+ #{11:=a1,21:=b1,31:="c1","41":="d1",<<"51">>:="e1",{["01"]}:="11"} = M0,
+ #{12:=a2,22:=b2,32:="c2","42":="d2",<<"52">>:="e2",{["02"]}:="12"} = M0,
+ #{13:=a3,23:=b3,33:="c3","43":="d3",<<"53">>:="e3",{["03"]}:="13"} = M0,
+ #{14:=a4,24:=b4,34:="c4","44":="d4",<<"54">>:="e4",{["04"]}:="14"} = M0,
+
+ #{10:=na0,20:=nb0,30:="nc0","40":="nd0",<<"50">>:="ne0",{["00"]}:="n10"} = M1,
+ #{11:=na1,21:=nb1,31:="nc1","41":="nd1",<<"51">>:="ne1",{["01"]}:="n11"} = M1,
+ #{12:=na2,22:=nb2,32:="nc2","42":="nd2",<<"52">>:="ne2",{["02"]}:="n12"} = M1,
+ #{13:=na3,23:=nb3,33:="nc3","43":="nd3",<<"53">>:="ne3",{["03"]}:="n13"} = M1,
+ #{14:=na4,24:=nb4,34:="nc4","44":="nd4",<<"54">>:="ne4",{["04"]}:="n14"} = M1,
+
+ #{15:=a5,25:=b5,35:="c5","45":="d5",<<"55">>:="e5",{["05"]}:="15"} = M1,
+ #{16:=a6,26:=b6,36:="c6","46":="d6",<<"56">>:="e6",{["06"]}:="16"} = M1,
+ #{17:=a7,27:=b7,37:="c7","47":="d7",<<"57">>:="e7",{["07"]}:="17"} = M1,
+ #{18:=a8,28:=b8,38:="c8","48":="d8",<<"58">>:="e8",{["08"]}:="18"} = M1,
+ #{19:=a9,29:=b9,39:="c9","49":="d9",<<"59">>:="e9",{["09"]}:="19"} = M1,
+
+ #{15:=a5,25:=b5,35:="c5","45":="d5",<<"55">>:="e5",{["05"]}:="15"} = M2,
+ #{16:=a6,26:=b6,36:="c6","46":="d6",<<"56">>:="e6",{["06"]}:="16"} = M2,
+ #{17:=a7,27:=b7,37:="c7","47":="d7",<<"57">>:="e7",{["07"]}:="17"} = M2,
+ #{18:=a8,28:=b8,38:="c8","48":="d8",<<"58">>:="e8",{["08"]}:="18"} = M2,
+ #{19:=a9,29:=b9,39:="c9","49":="d9",<<"59">>:="e9",{["09"]}:="19"} = M2,
+
+ #{10.0:=fa0,20.0:=fb0,30.0:="fc0","40":="d0",<<"50">>:="e0",{["00"]}:="10"} = M2,
+ #{11.0:=fa1,21.0:=fb1,31.0:="fc1","41":="d1",<<"51">>:="e1",{["01"]}:="11"} = M2,
+ #{12.0:=fa2,22.0:=fb2,32.0:="fc2","42":="d2",<<"52">>:="e2",{["02"]}:="12"} = M2,
+ #{13.0:=fa3,23.0:=fb3,33.0:="fc3","43":="d3",<<"53">>:="e3",{["03"]}:="13"} = M2,
+ #{14.0:=fa4,24.0:=fb4,34.0:="fc4","44":="d4",<<"54">>:="e4",{["04"]}:="14"} = M2,
+
+ #{15:=a5,25:=b5,35:="c5","45":="d5",<<"55">>:="e5",{["05"]}:="15"} = M3,
+ #{16:=a6,26:=b6,36:="c6","46":="d6",<<"56">>:="e6",{["06"]}:="16"} = M3,
+ #{17:=a7,27:=b7,37:="c7","47":="d7",<<"57">>:="e7",{["07"]}:="17"} = M3,
+ #{18:=a8,28:=b8,38:="c8","48":="d8",<<"58">>:="e8",{["08"]}:="18"} = M3,
+ #{19:=a9,29:=b9,39:="c9","49":="d9",<<"59">>:="e9",{["09"]}:="19"} = M3,
+
+ #{10.0:=fa0,20.0:=fb0,30.0:="fc0","40":="d0",<<"50">>:="e0",{["00"]}:="10"} = M3,
+ #{11.0:=fa1,21.0:=fb1,31.0:="fc1","41":="d1",<<"51">>:="e1",{["01"]}:="11"} = M3,
+ #{12.0:=fa2,22.0:=fb2,32.0:="fc2","42":="d2",<<"52">>:="e2",{["02"]}:="12"} = M3,
+ #{13.0:=fa3,23.0:=fb3,33.0:="fc3","43":="d3",<<"53">>:="e3",{["03"]}:="13"} = M3,
+ #{14.0:=fa4,24.0:=fb4,34.0:="fc4","44":="d4",<<"54">>:="e4",{["04"]}:="14"} = M3,
+
+ #{15.0:=fa5,25.0:=fb5,35.0:="fc5","45":="d5",<<"55">>:="e5",{["05"]}:="15"} = M3,
+ #{16.0:=fa6,26.0:=fb6,36.0:="fc6","46":="d6",<<"56">>:="e6",{["06"]}:="16"} = M3,
+ #{17.0:=fa7,27.0:=fb7,37.0:="fc7","47":="d7",<<"57">>:="e7",{["07"]}:="17"} = M3,
+ #{18.0:=fa8,28.0:=fb8,38.0:="fc8","48":="d8",<<"58">>:="e8",{["08"]}:="18"} = M3,
+ #{19.0:=fa9,29.0:=fb9,39.0:="fc9","49":="d9",<<"59">>:="e9",{["09"]}:="19"} = M3,
+
+ #{36893488147419103232:=big1,67108863:=big8,"45":="d5",<<"55">>:="e5",{["05"]}:="15"} = M3,
+ #{147573952589676412928:=big3,8589934592:=big6,"46":="d6",<<"56">>:="e6",{["06"]}:="16"} = M3,
+ #{4294967296:=big5,18446744073709551616:=big4,"47":="d7",<<"57">>:="e7",{["07"]}:="17"} = M3,
+ #{4294967295:=big7,73786976294838206464:=big2,"48":="d8",<<"58">>:="e8",{["08"]}:="18"} = M3,
+
+ ok.
+
+
+t_map_size(Config) when is_list(Config) ->
+ 0 = map_size(#{}),
+ 1 = map_size(#{a=>1}),
+ 1 = map_size(#{a=>"wat"}),
+ 2 = map_size(#{a=>1, b=>2}),
+ 3 = map_size(#{a=>1, b=>2, b=>"3","33"=><<"n">>}),
+
+ true = map_is_size(#{a=>1}, 1),
+ true = map_is_size(#{a=>1, a=>2}, 1),
+ M = #{ "a" => 1, "b" => 2},
+ true = map_is_size(M, 2),
+ false = map_is_size(M, 3),
+ true = map_is_size(M#{ "a" => 2}, 2),
+ false = map_is_size(M#{ "c" => 2}, 2),
+
+ Ks = [build_key(fun(K) -> <<1,K:32,1>> end,I)||I<-lists:seq(1,100)],
+ ok = build_and_check_size(Ks,0,#{}),
+
+ %% try deep collisions
+ %% statistically we get another subtree at 50k -> 100k elements
+ %% Try to be nice and don't use too much memory in the testcase,
+
+ N = 500000,
+ Is = lists:seq(1,N),
+ N = map_size(maps:from_list([{I,I}||I<-Is])),
+ N = map_size(maps:from_list([{<<I:32>>,I}||I<-Is])),
+ N = map_size(maps:from_list([{integer_to_list(I),I}||I<-Is])),
+ N = map_size(maps:from_list([{float(I),I}||I<-Is])),
+
+ %% Error cases.
+ do_badmap(fun(T) ->
+ {'EXIT',{{badmap,T},_}} =
+ (catch map_size(T))
+ end),
+ ok.
+
+build_and_check_size([K|Ks],N,M0) ->
+ N = map_size(M0),
+ M1 = M0#{ K => K },
+ build_and_check_size(Ks,N + 1,M1);
+build_and_check_size([],N,M) ->
+ N = map_size(M),
+ ok.
+
+map_is_size(M,N) when map_size(M) =:= N -> true;
+map_is_size(_,_) -> false.
+
+t_is_map(Config) when is_list(Config) ->
+ true = is_map(#{}),
+ true = is_map(#{a=>1}),
+ false = is_map({a,b}),
+ false = is_map(x),
+ if is_map(#{}) -> ok end,
+ if is_map(#{b=>1}) -> ok end,
+ if not is_map([1,2,3]) -> ok end,
+ if not is_map(x) -> ok end,
+ ok.
+
+% test map updates without matching
+t_update_literals_large(Config) when is_list(Config) ->
+ Map = #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ 16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19",
+
+ 10.0=>fa0,20.0=>fb0,30.0=>"fc0",
+ 11.0=>fa1,21.0=>fb1,31.0=>"fc1",
+ 12.0=>fa2,22.0=>fb2,32.0=>"fc2",
+ 13.0=>fa3,23.0=>fb3,33.0=>"fc3",
+ 14.0=>fa4,24.0=>fb4,34.0=>"fc4",
+
+ 15.0=>fa5,25.0=>fb5,35.0=>"fc5",
+ 16.0=>fa6,26.0=>fb6,36.0=>"fc6",
+ 17.0=>fa7,27.0=>fb7,37.0=>"fc7",
+ 18.0=>fa8,28.0=>fb8,38.0=>"fc8",
+ 19.0=>fa9,29.0=>fb9,39.0=>"fc9",
+
+ #{ one => small, map => key } => "small map key 1",
+ #{ second => small, map => key } => "small map key 2",
+ #{ third => small, map => key } => "small map key 3",
+
+ #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ 16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 1",
+
+ #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ k16=>a6,k26=>b6,k36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 2" },
+
+ #{x:="d",q:="4"} = loop_update_literals_x_q(Map, [
+ {"a","1"},{"b","2"},{"c","3"},{"d","4"}
+ ]),
+ ok.
+
+t_update_literals(Config) when is_list(Config) ->
+ Map = #{x=>1,y=>2,z=>3,q=>4},
+ #{x:="d",q:="4"} = loop_update_literals_x_q(Map, [
+ {"a","1"},{"b","2"},{"c","3"},{"d","4"}
+ ]),
+ ok.
+
+
+loop_update_literals_x_q(Map, []) -> Map;
+loop_update_literals_x_q(Map, [{X,Q}|Vs]) ->
+ loop_update_literals_x_q(Map#{q=>Q,x=>X},Vs).
+
+% test map updates with matching
+t_match_and_update_literals(Config) when is_list(Config) ->
+ Map = #{ x=>0,y=>"untouched",z=>"also untouched",q=>1,
+ #{ "one" => small, map => key } => "small map key 1" },
+ #{x:=16,q:=21,y:="untouched",z:="also untouched"} = loop_match_and_update_literals_x_q(Map, [
+ {1,2},{3,4},{5,6},{7,8}
+ ]),
+ M0 = #{ "hi" => "hello", int => 3, <<"key">> => <<"value">>,
+ 4 => number, 18446744073709551629 => wat},
+ M1 = #{},
+ M2 = M1#{ "hi" => "hello", int => 3, <<"key">> => <<"value">>,
+ 4 => number, 18446744073709551629 => wat},
+ M0 = M2,
+
+ #{ 4 := another_number, int := 3 } = M2#{ 4 => another_number },
+ ok.
+
+t_match_and_update_literals_large(Config) when is_list(Config) ->
+ Map = #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ 16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19",
+
+ 10.0=>fa0,20.0=>fb0,30.0=>"fc0",
+ 11.0=>fa1,21.0=>fb1,31.0=>"fc1",
+ 12.0=>fa2,22.0=>fb2,32.0=>"fc2",
+ 13.0=>fa3,23.0=>fb3,33.0=>"fc3",
+ 14.0=>fa4,24.0=>fb4,34.0=>"fc4",
+
+ 15.0=>fa5,25.0=>fb5,35.0=>"fc5",
+ 16.0=>fa6,26.0=>fb6,36.0=>"fc6",
+ 17.0=>fa7,27.0=>fb7,37.0=>"fc7",
+ 18.0=>fa8,28.0=>fb8,38.0=>"fc8",
+ 19.0=>fa9,29.0=>fb9,39.0=>"fc9",
+
+ x=>0,y=>"untouched",z=>"also untouched",q=>1,
+
+ #{ "one" => small, map => key } => "small map key 1",
+ #{ second => small, map => key } => "small map key 2",
+ #{ third => small, map => key } => "small map key 3",
+
+ #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ 16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 1",
+
+ #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ k16=>a6,k26=>b6,k36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 2" },
+
+ #{x:=16,q:=21,y:="untouched",z:="also untouched"} = loop_match_and_update_literals_x_q(Map, [
+ {1,2},{3,4},{5,6},{7,8}
+ ]),
+ M0 = Map#{ "hi" => "hello", int => 3, <<"key">> => <<"value">>,
+ 4 => number, 18446744073709551629 => wat},
+ M1 = Map#{},
+ M2 = M1#{ "hi" => "hello", int => 3, <<"key">> => <<"value">>,
+ 4 => number, 18446744073709551629 => wat},
+ M0 = M2,
+
+ #{ 4 := another_number, int := 3 } = M2#{ 4 => another_number },
+ ok.
+
+
+loop_match_and_update_literals_x_q(Map, []) -> Map;
+loop_match_and_update_literals_x_q(#{ q:=Q0, x:=X0,
+ #{ "one" => small, map => key } := "small map key 1" } = Map, [{X,Q}|Vs]) ->
+ loop_match_and_update_literals_x_q(Map#{q=>Q0+Q,x=>X0+X},Vs).
+
+
+t_update_map_expressions(Config) when is_list(Config) ->
+ M = maps:new(),
+ #{ a := 1 } = M#{a => 1},
+
+ #{ b := 2 } = (maps:new())#{ b => 2 },
+
+ #{ a :=42, b:=42, c:=42 } = (maps:from_list([{a,1},{b,2},{c,3}]))#{ a := 42, b := 42, c := 42 },
+ #{ "a" :=1, "b":=42, "c":=42 } = (maps:from_list([{"a",1},{"b",2}]))#{ "b" := 42, "c" => 42 },
+ Ks = lists:seq($a,$z),
+ #{ "aa" := {$a,$a}, "ac":=41, "dc":=42 } =
+ (maps:from_list([{[K1,K2],{K1,K2}}|| K1 <- Ks, K2 <- Ks]))#{ "ac" := 41, "dc" => 42 },
+
+ %% Error cases.
+ do_badmap(fun(T) ->
+ {'EXIT',{{badmap,T},_}} =
+ (catch (T)#{a:=42,b=>2})
+ end),
+ ok.
+
+t_update_assoc(Config) when is_list(Config) ->
+ M0 = #{1=>a,2=>b,3.0=>c,4=>d,5=>e},
+
+ M1 = M0#{1=>42,2=>100,4=>[a,b,c]},
+ #{1:=42,2:=100,3.0:=c,4:=[a,b,c],5:=e} = M1,
+ #{1:=42,2:=b,4:=d,5:=e,2.0:=100,3.0:=c,4.0:=[a,b,c]} = M0#{1.0=>float,1:=42,2.0=>wrong,2.0=>100,4.0=>[a,b,c]},
+
+ M2 = M0#{3.0=>new},
+ #{1:=a,2:=b,3.0:=new,4:=d,5:=e} = M2,
+ M2 = M0#{3.0:=wrong,3.0=>new},
+
+ %% Errors cases.
+ do_badmap(fun(T) ->
+ {'EXIT',{{badmap,T},_}} =
+ (catch T#{nonexisting=>val})
+ end),
+ ok.
+
+
+t_update_assoc_large(Config) when is_list(Config) ->
+ M0 = #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ 16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19",
+
+ 10.0=>fa0,20.0=>fb0,30.0=>"fc0",
+ 11.0=>fa1,21.0=>fb1,31.0=>"fc1",
+ 12.0=>fa2,22.0=>fb2,32.0=>"fc2",
+ 13.0=>fa3,23.0=>fb3,33.0=>"fc3",
+ 14.0=>fa4,24.0=>fb4,34.0=>"fc4",
+
+ 15.0=>fa5,25.0=>fb5,35.0=>"fc5",
+ 16.0=>fa6,26.0=>fb6,36.0=>"fc6",
+ 17.0=>fa7,27.0=>fb7,37.0=>"fc7",
+ 18.0=>fa8,28.0=>fb8,38.0=>"fc8",
+ 19.0=>fa9,29.0=>fb9,39.0=>"fc9",
+
+ #{ one => small, map => key } => "small map key 1",
+ #{ second => small, map => key } => "small map key 2",
+ #{ third => small, map => key } => "small map key 3",
+
+ #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ 16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 1",
+
+ #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ k16=>a6,k26=>b6,k36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 2" },
+
+
+ M1 = M0#{1=>42,2=>100,4=>[a,b,c]},
+ #{1:=42,2:=100,10.0:=fa0,4:=[a,b,c],25:=b5} = M1,
+ #{ 10:=43, 24:=b4, 15:=a5, 35:="c5", 2.0:=100, 13.0:=fa3, 4.0:=[a,b,c]} =
+ M0#{1.0=>float,10:=43,2.0=>wrong,2.0=>100,4.0=>[a,b,c]},
+
+ M2 = M0#{13.0=>new},
+ #{10:=a0,20:=b0,13.0:=new,"40":="d0",<<"50">>:="e0"} = M2,
+ M2 = M0#{13.0:=wrong,13.0=>new},
+
+ ok.
+
+t_update_exact(Config) when is_list(Config) ->
+ M0 = #{1=>a,2=>b,3.0=>c,4=>d,5=>e},
+
+ M1 = M0#{1:=42,2:=100,4:=[a,b,c]},
+ #{1:=42,2:=100,3.0:=c,4:=[a,b,c],5:=e} = M1,
+ M1 = M0#{1:=wrong,1=>42,2=>wrong,2:=100,4:=[a,b,c]},
+
+ M2 = M0#{3.0:=new},
+ #{1:=a,2:=b,3.0:=new,4:=d,5:=e} = M2,
+ M2 = M0#{3.0=>wrong,3.0:=new},
+ true = M2 =/= M0#{3=>right,3.0:=new},
+ #{ 3 := right, 3.0 := new } = M0#{3=>right,3.0:=new},
+
+ M3 = #{ 1 => val},
+ #{1 := update2,1.0 := new_val4} = M3#{
+ 1.0 => new_val1, 1 := update, 1=> update3,
+ 1 := update2, 1.0 := new_val2, 1.0 => new_val3,
+ 1.0 => new_val4 },
+
+ %% Errors cases.
+ do_badmap(fun(T) ->
+ {'EXIT',{{badmap,T},_}} =
+ (catch T#{nonexisting=>val})
+ end),
+ Empty = #{},
+ {'EXIT',{{badkey,nonexisting},_}} = (catch Empty#{nonexisting:=val}),
+ {'EXIT',{{badkey,nonexisting},_}} = (catch M0#{nonexisting:=val}),
+ {'EXIT',{{badkey,1.0},_}} = (catch M0#{1.0:=v,1.0=>v2}),
+ {'EXIT',{{badkey,42},_}} = (catch M0#{42.0:=v,42:=v2}),
+ {'EXIT',{{badkey,42.0},_}} = (catch M0#{42=>v1,42.0:=v2,42:=v3}),
+
+ ok.
+
+t_update_exact_large(Config) when is_list(Config) ->
+ M0 = #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ 16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19",
+
+ 10.0=>fa0,20.0=>fb0,30.0=>"fc0",
+ 11.0=>fa1,21.0=>fb1,31.0=>"fc1",
+ 12.0=>fa2,22.0=>fb2,32.0=>"fc2",
+ 13.0=>fa3,23.0=>fb3,33.0=>"fc3",
+ 14.0=>fa4,24.0=>fb4,34.0=>"fc4",
+
+ 15.0=>fa5,25.0=>fb5,35.0=>"fc5",
+ 16.0=>fa6,26.0=>fb6,36.0=>"fc6",
+ 17.0=>fa7,27.0=>fb7,37.0=>"fc7",
+ 18.0=>fa8,28.0=>fb8,38.0=>"fc8",
+ 19.0=>fa9,29.0=>fb9,39.0=>"fc9",
+
+ #{ one => small, map => key } => "small map key 1",
+ #{ second => small, map => key } => "small map key 2",
+ #{ third => small, map => key } => "small map key 3",
+
+ #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ 16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 1",
+
+ #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ k16=>a6,k26=>b6,k36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 2" },
+
+
+ M1 = M0#{10:=42,<<"55">>:=100,10.0:=[a,b,c]},
+ #{ 10:=42,<<"55">>:=100,{["05"]}:="15",10.0:=[a,b,c],
+ #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ 16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } := "large map key 1" } = M1,
+
+ M1 = M0#{10:=wrong,10=>42,<<"55">>=>wrong,<<"55">>:=100,10.0:=[a,b,c]},
+
+ M2 = M0#{13.0:=new},
+ #{10:=a0,20:=b0,13.0:=new} = M2,
+ M2 = M0#{13.0=>wrong,13.0:=new},
+
+ %% Errors cases.
+ {'EXIT',{{badkey,nonexisting},_}} = (catch M0#{nonexisting:=val}),
+ {'EXIT',{{badkey,1.0},_}} = (catch M0#{1.0:=v,1.0=>v2}),
+ {'EXIT',{{badkey,42},_}} = (catch M0#{42.0:=v,42:=v2}),
+ {'EXIT',{{badkey,42.0},_}} = (catch M0#{42=>v1,42.0:=v2,42:=v3}),
+
+ ok.
+
+t_update_deep(Config) when is_list(Config) ->
+ N = 250000,
+ M0 = maps:from_list([{integer_to_list(I),a}||I<-lists:seq(1,N)]),
+ #{ "1" := a, "10" := a, "100" := a, "1000" := a, "10000" := a } = M0,
+
+ M1 = M0#{ "1" := b, "10" := b, "100" := b, "1000" := b, "10000" := b },
+ #{ "1" := a, "10" := a, "100" := a, "1000" := a, "10000" := a } = M0,
+ #{ "1" := b, "10" := b, "100" := b, "1000" := b, "10000" := b } = M1,
+
+ M2 = M0#{ "1" => c, "10" => c, "100" => c, "1000" => c, "10000" => c },
+ #{ "1" := a, "10" := a, "100" := a, "1000" := a, "10000" := a } = M0,
+ #{ "1" := b, "10" := b, "100" := b, "1000" := b, "10000" := b } = M1,
+ #{ "1" := c, "10" := c, "100" := c, "1000" := c, "10000" := c } = M2,
+
+ M3 = M2#{ "n1" => d, "n10" => d, "n100" => d, "n1000" => d, "n10000" => d },
+ #{ "1" := a, "10" := a, "100" := a, "1000" := a, "10000" := a } = M0,
+ #{ "1" := b, "10" := b, "100" := b, "1000" := b, "10000" := b } = M1,
+ #{ "1" := c, "10" := c, "100" := c, "1000" := c, "10000" := c } = M2,
+ #{ "1" := c, "10" := c, "100" := c, "1000" := c, "10000" := c } = M3,
+ #{ "n1" := d, "n10" := d, "n100" := d, "n1000" := d, "n10000" := d } = M3,
+ ok.
+
+t_guard_bifs(Config) when is_list(Config) ->
+ true = map_guard_head(#{a=>1}),
+ false = map_guard_head([]),
+ true = map_guard_body(#{a=>1}),
+ false = map_guard_body({}),
+ true = map_guard_pattern(#{a=>1, <<"hi">> => "hi" }),
+ false = map_guard_pattern("list"),
+ ok.
+
+map_guard_head(M) when is_map(M) -> true;
+map_guard_head(_) -> false.
+
+map_guard_body(M) -> is_map(M).
+
+map_guard_pattern(#{}) -> true;
+map_guard_pattern(_) -> false.
+
+t_guard_sequence(Config) when is_list(Config) ->
+ {1, "a"} = map_guard_sequence_1(#{seq=>1,val=>"a"}),
+ {2, "b"} = map_guard_sequence_1(#{seq=>2,val=>"b"}),
+ {3, "c"} = map_guard_sequence_1(#{seq=>3,val=>"c"}),
+ {4, "d"} = map_guard_sequence_1(#{seq=>4,val=>"d"}),
+ {5, "e"} = map_guard_sequence_1(#{seq=>5,val=>"e"}),
+
+ {1,M1} = map_guard_sequence_2(M1 = #{a=>3}),
+ {2,M2} = map_guard_sequence_2(M2 = #{a=>4, b=>4}),
+ {3,gg,M3} = map_guard_sequence_2(M3 = #{a=>gg, b=>4}),
+ {4,sc,sc,M4} = map_guard_sequence_2(M4 = #{a=>sc, b=>3, c=>sc2}),
+ {5,kk,kk,M5} = map_guard_sequence_2(M5 = #{a=>kk, b=>other, c=>sc2}),
+
+ %% error case
+ {'EXIT',{function_clause,_}} = (catch map_guard_sequence_1(#{seq=>6,val=>"e"})),
+ {'EXIT',{function_clause,_}} = (catch map_guard_sequence_2(#{b=>5})),
+ ok.
+
+t_guard_sequence_large(Config) when is_list(Config) ->
+ M0 = #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00",03]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01",03]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02",03]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03",03]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04",03]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05",03]}=>"15",
+ 16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06",03]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07",03]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08",03]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09",03]}=>"19",
+
+ 10.0=>fa0,20.0=>fb0,30.0=>"fc0",
+ 11.0=>fa1,21.0=>fb1,31.0=>"fc1",
+ 12.0=>fa2,22.0=>fb2,32.0=>"fc2",
+ 13.0=>fa3,23.0=>fb3,33.0=>"fc3",
+ 14.0=>fa4,24.0=>fb4,34.0=>"fc4",
+
+ 15.0=>fa5,25.0=>fb5,35.0=>"fc5",
+ 16.0=>fa6,26.0=>fb6,36.0=>"fc6",
+ 17.0=>fa7,27.0=>fb7,37.0=>"fc7",
+ 18.0=>fa8,28.0=>fb8,38.0=>"fc8",
+ 19.0=>fa9,29.0=>fb9,39.0=>"fc9",
+
+ #{ one => small, map => key } => "small map key 1",
+ #{ second => small, map => key } => "small map key 2",
+ #{ third => small, map => key } => "small map key 3",
+
+ #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ 16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 1",
+
+ #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ k16=>a6,k26=>b6,k36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 2" },
+
+ {1, "a"} = map_guard_sequence_1(M0#{seq=>1,val=>"a"}),
+ {2, "b"} = map_guard_sequence_1(M0#{seq=>2,val=>"b"}),
+ {3, "c"} = map_guard_sequence_1(M0#{seq=>3,val=>"c"}),
+ {4, "d"} = map_guard_sequence_1(M0#{seq=>4,val=>"d"}),
+ {5, "e"} = map_guard_sequence_1(M0#{seq=>5,val=>"e"}),
+
+ {1,M1} = map_guard_sequence_2(M1 = M0#{a=>3}),
+ {2,M2} = map_guard_sequence_2(M2 = M0#{a=>4, b=>4}),
+ {3,gg,M3} = map_guard_sequence_2(M3 = M0#{a=>gg, b=>4}),
+ {4,sc,sc,M4} = map_guard_sequence_2(M4 = M0#{a=>sc, b=>3, c=>sc2}),
+ {5,kk,kk,M5} = map_guard_sequence_2(M5 = M0#{a=>kk, b=>other, c=>sc2}),
+
+ {'EXIT',{function_clause,_}} = (catch map_guard_sequence_1(M0#{seq=>6,val=>"e"})),
+ {'EXIT',{function_clause,_}} = (catch map_guard_sequence_2(M0#{b=>5})),
+ ok.
+
+
+map_guard_sequence_1(#{seq:=1=Seq, val:=Val}) -> {Seq,Val};
+map_guard_sequence_1(#{seq:=2=Seq, val:=Val}) -> {Seq,Val};
+map_guard_sequence_1(#{seq:=3=Seq, val:=Val}) -> {Seq,Val};
+map_guard_sequence_1(#{seq:=4=Seq, val:=Val}) -> {Seq,Val};
+map_guard_sequence_1(#{seq:=5=Seq, val:=Val}) -> {Seq,Val}.
+
+map_guard_sequence_2(#{ a:=3 }=M) -> {1, M};
+map_guard_sequence_2(#{ a:=4 }=M) -> {2, M};
+map_guard_sequence_2(#{ a:=X, a:=X, b:=4 }=M) -> {3,X,M};
+map_guard_sequence_2(#{ a:=X, a:=Y, b:=3 }=M) when X =:= Y -> {4,X,Y,M};
+map_guard_sequence_2(#{ a:=X, a:=Y }=M) when X =:= Y -> {5,X,Y,M}.
+
+
+t_guard_update(Config) when is_list(Config) ->
+ error = map_guard_update(#{},#{}),
+ first = map_guard_update(#{}, #{x=>first}),
+ second = map_guard_update(#{y=>old}, #{x=>second,y=>old}),
+ ok.
+
+t_guard_update_large(Config) when is_list(Config) ->
+ M0 = #{ 70=>a0,80=>b0,90=>"c0","40"=>"d0",<<"50">>=>"e0",{["00",03]}=>"10",
+ 71=>a1,81=>b1,91=>"c1","41"=>"d1",<<"51">>=>"e1",{["01",03]}=>"11",
+ 72=>a2,82=>b2,92=>"c2","42"=>"d2",<<"52">>=>"e2",{["02",03]}=>"12",
+ 73=>a3,83=>b3,93=>"c3","43"=>"d3",<<"53">>=>"e3",{["03",03]}=>"13",
+ 74=>a4,84=>b4,94=>"c4","44"=>"d4",<<"54">>=>"e4",{["04",03]}=>"14",
+
+ 75=>a5,85=>b5,95=>"c5","45"=>"d5",<<"55">>=>"e5",{["05",03]}=>"15",
+ 76=>a6,86=>b6,96=>"c6","46"=>"d6",<<"56">>=>"e6",{["06",03]}=>"16",
+ 77=>a7,87=>b7,97=>"c7","47"=>"d7",<<"57">>=>"e7",{["07",03]}=>"17",
+ 78=>a8,88=>b8,98=>"c8","48"=>"d8",<<"58">>=>"e8",{["08",03]}=>"18",
+ 79=>a9,89=>b9,99=>"c9","49"=>"d9",<<"59">>=>"e9",{["09",03]}=>"19",
+
+ 70.0=>fa0,80.0=>fb0,90.0=>"fc0",
+ 71.0=>fa1,81.0=>fb1,91.0=>"fc1",
+ 72.0=>fa2,82.0=>fb2,92.0=>"fc2",
+ 73.0=>fa3,83.0=>fb3,93.0=>"fc3",
+ 74.0=>fa4,84.0=>fb4,94.0=>"fc4",
+
+ 75.0=>fa5,85.0=>fb5,95.0=>"fc5",
+ 76.0=>fa6,86.0=>fb6,96.0=>"fc6",
+ 77.0=>fa7,87.0=>fb7,97.0=>"fc7",
+ 78.0=>fa8,88.0=>fb8,98.0=>"fc8",
+ 79.0=>fa9,89.0=>fb9,99.0=>"fc9",
+
+ #{ one => small, map => key } => "small map key 1",
+ #{ second => small, map => key } => "small map key 2",
+ #{ third => small, map => key } => "small map key 3",
+
+ #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ 16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 1",
+
+ #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
+ 11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
+ 12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
+ 13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
+ 14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
+
+ 15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
+ k16=>a6,k26=>b6,k36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
+ 17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
+ 18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
+ 19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 2" },
+
+
+ error = map_guard_update(M0#{},M0#{}),
+ first = map_guard_update(M0#{},M0#{x=>first}),
+ second = map_guard_update(M0#{y=>old}, M0#{x=>second,y=>old}),
+ ok.
+
+
+map_guard_update(M1, M2) when M1#{x=>first} =:= M2 -> first;
+map_guard_update(M1, M2) when M1#{x=>second} =:= M2 -> second;
+map_guard_update(_, _) -> error.
+
+t_guard_receive(Config) when is_list(Config) ->
+ M0 = #{ id => 0 },
+ Pid = spawn_link(fun() -> guard_receive_loop() end),
+ Big = 36893488147419103229,
+ B1 = <<"some text">>,
+ B2 = <<"was appended">>,
+ B3 = <<B1/binary, B2/binary>>,
+
+ #{id:=1, res:=Big} = M1 = call(Pid, M0#{op=>sub,in=>{1 bsl 65, 3}}),
+ #{id:=2, res:=26} = M2 = call(Pid, M1#{op=>idiv,in=>{53,2}}),
+ #{id:=3, res:=832} = M3 = call(Pid, M2#{op=>imul,in=>{26,32}}),
+ #{id:=4, res:=4} = M4 = call(Pid, M3#{op=>add,in=>{1,3}}),
+ #{id:=5, res:=Big} = M5 = call(Pid, M4#{op=>sub,in=>{1 bsl 65, 3}}),
+ #{id:=6, res:=B3} = M6 = call(Pid, M5#{op=>"append",in=>{B1,B2}}),
+ #{id:=7, res:=4} = _ = call(Pid, M6#{op=>add,in=>{1,3}}),
+
+
+ %% update old maps and check id update
+ #{id:=2, res:=B3} = call(Pid, M1#{op=>"append",in=>{B1,B2}}),
+ #{id:=5, res:=99} = call(Pid, M4#{op=>add,in=>{33, 66}}),
+
+ %% cleanup
+ done = call(Pid, done),
+ ok.
+
+-define(t_guard_receive_large_procs, 1500).
+
+t_guard_receive_large(Config) when is_list(Config) ->
+ M = lists:foldl(fun(_,#{procs := Ps } = M) ->
+ M#{ procs := Ps#{ spawn_link(fun() -> grecv_loop() end) => 0 }}
+ end, #{procs => #{}, done => 0}, lists:seq(1,?t_guard_receive_large_procs)),
+ lists:foreach(fun(Pid) ->
+ Pid ! {self(), hello}
+ end, maps:keys(maps:get(procs,M))),
+ ok = guard_receive_large_loop(M),
+ ok.
+
+guard_receive_large_loop(#{done := ?t_guard_receive_large_procs}) ->
+ ok;
+guard_receive_large_loop(M) ->
+ receive
+ #{pid := Pid, msg := hello} ->
+ case M of
+ #{done := Count, procs := #{Pid := 150}} ->
+ Pid ! {self(), done},
+ guard_receive_large_loop(M#{done := Count + 1});
+ #{procs := #{Pid := Count} = Ps} ->
+ Pid ! {self(), hello},
+ guard_receive_large_loop(M#{procs := Ps#{Pid := Count + 1}})
+ end
+ end.
+
+grecv_loop() ->
+ receive
+ {_, done} ->
+ ok;
+ {Pid, hello} ->
+ Pid ! #{pid=>self(), msg=>hello},
+ grecv_loop()
+ end.
+
+call(Pid, M) ->
+ Pid ! {self(), M}, receive {Pid, Res} -> Res end.
+
+guard_receive_loop() ->
+ receive
+ {Pid, #{ id:=Id, op:="append", in:={X,Y}}=M} when is_binary(X), is_binary(Y) ->
+ Pid ! {self(), M#{ id=>Id+1, res=><<X/binary,Y/binary>>}},
+ guard_receive_loop();
+ {Pid, #{ id:=Id, op:=add, in:={X,Y}}} ->
+ Pid ! {self(), #{ id=>Id+1, res=>X+Y}},
+ guard_receive_loop();
+ {Pid, #{ id:=Id, op:=sub, in:={X,Y}}=M} ->
+ Pid ! {self(), M#{ id=>Id+1, res=>X-Y}},
+ guard_receive_loop();
+ {Pid, #{ id:=Id, op:=idiv, in:={X,Y}}=M} ->
+ Pid ! {self(), M#{ id=>Id+1, res=>X div Y}},
+ guard_receive_loop();
+ {Pid, #{ id:=Id, op:=imul, in:={X,Y}}=M} ->
+ Pid ! {self(), M#{ id=>Id+1, res=>X * Y}},
+ guard_receive_loop();
+ {Pid, done} ->
+ Pid ! {self(), done};
+ {Pid, Other} ->
+ Pid ! {error, Other},
+ guard_receive_loop()
+ end.
+
+
+t_list_comprehension(Config) when is_list(Config) ->
+ [#{k:=1},#{k:=2},#{k:=3}] = [#{k=>I} || I <- [1,2,3]],
+
+ Ks = lists:seq($a,$z),
+ Ms = [#{[K1,K2]=>{K1,K2}} || K1 <- Ks, K2 <- Ks],
+ [#{"aa" := {$a,$a}},#{"ab":={$a,$b}}|_] = Ms,
+ [#{"zz" := {$z,$z}},#{"zy":={$z,$y}}|_] = lists:reverse(Ms),
+ ok.
+
+t_guard_fun(Config) when is_list(Config) ->
+ F1 = fun
+ (#{s:=v,v:=V}) -> {v,V};
+ (#{s:=t,v:={V,V}}) -> {t,V};
+ (#{s:=l,v:=[V,V]}) -> {l,V}
+ end,
+
+ F2 = fun
+ (#{s:=T,v:={V,V}}) -> {T,V};
+ (#{s:=T,v:=[V,V]}) -> {T,V};
+ (#{s:=T,v:=V}) -> {T,V}
+ end,
+ V = <<"hi">>,
+
+ {v,V} = F1(#{s=>v,v=>V}),
+ {t,V} = F1(#{s=>t,v=>{V,V}}),
+ {l,V} = F1(#{s=>l,v=>[V,V]}),
+
+ {v,V} = F2(#{s=>v,v=>V}),
+ {t,V} = F2(#{s=>t,v=>{V,V}}),
+ {l,V} = F2(#{s=>l,v=>[V,V]}),
+
+ %% error case
+ {'EXIT', {function_clause,[{?MODULE,_,[#{s:=none,v:=none}],_}|_]}} = (catch F1(#{s=>none,v=>none})),
+ ok.
+
+
+t_map_sort_literals(Config) when is_list(Config) ->
+ % test relation
+
+ %% size order
+ true = #{ a => 1, b => 2} < #{ a => 1, b => 1, c => 1},
+ true = #{ b => 1, a => 1} < #{ c => 1, a => 1, b => 1},
+ false = #{ c => 1, b => 1, a => 1} < #{ c => 1, a => 1},
+
+ %% key order
+ true = #{ a => 1 } < #{ b => 1},
+ false = #{ b => 1 } < #{ a => 1},
+ true = #{ a => 1, b => 1, c => 1 } < #{ b => 1, c => 1, d => 1},
+ true = #{ b => 1, c => 1, d => 1 } > #{ a => 1, b => 1, c => 1},
+ true = #{ c => 1, b => 1, a => 1 } < #{ b => 1, c => 1, d => 1},
+ true = #{ "a" => 1 } < #{ <<"a">> => 1},
+ false = #{ <<"a">> => 1 } < #{ "a" => 1},
+ true = #{ 1 => 1 } < #{ 1.0 => 1},
+ false = #{ 1.0 => 1 } < #{ 1 => 1},
+
+ %% value order
+ true = #{ a => 1 } < #{ a => 2},
+ false = #{ a => 2 } < #{ a => 1},
+ false = #{ a => 2, b => 1 } < #{ a => 1, b => 3},
+ true = #{ a => 1, b => 1 } < #{ a => 1, b => 3},
+ false = #{ a => 1 } < #{ a => 1.0},
+ false = #{ a => 1.0 } < #{ a => 1},
+
+ true = #{ "a" => "hi", b => 134 } == #{ b => 134,"a" => "hi"},
+
+ %% large maps
+
+ M = maps:from_list([{I,I}||I <- lists:seq(1,500)]),
+
+ %% size order
+ true = M#{ a => 1, b => 2} < M#{ a => 1, b => 1, c => 1},
+ true = M#{ b => 1, a => 1} < M#{ c => 1, a => 1, b => 1},
+ false = M#{ c => 1, b => 1, a => 1} < M#{ c => 1, a => 1},
+
+ %% key order
+ true = M#{ a => 1 } < M#{ b => 1},
+ false = M#{ b => 1 } < M#{ a => 1},
+ true = M#{ a => 1, b => 1, c => 1 } < M#{ b => 1, c => 1, d => 1},
+ true = M#{ b => 1, c => 1, d => 1 } > M#{ a => 1, b => 1, c => 1},
+ true = M#{ c => 1, b => 1, a => 1 } < M#{ b => 1, c => 1, d => 1},
+ true = M#{ "a" => 1 } < M#{ <<"a">> => 1},
+ false = M#{ <<"a">> => 1 } < #{ "a" => 1},
+ true = M#{ 1 => 1 } < maps:remove(1,M#{ 1.0 => 1}),
+ false = M#{ 1.0 => 1 } < M#{ 1 => 1},
+
+ %% value order
+ true = M#{ a => 1 } < M#{ a => 2},
+ false = M#{ a => 2 } < M#{ a => 1},
+ false = M#{ a => 2, b => 1 } < M#{ a => 1, b => 3},
+ true = M#{ a => 1, b => 1 } < M#{ a => 1, b => 3},
+ false = M#{ a => 1 } < M#{ a => 1.0},
+ false = M#{ a => 1.0 } < M#{ a => 1},
+
+ true = M#{ "a" => "hi", b => 134 } == M#{ b => 134,"a" => "hi"},
+
+ %% lists:sort
+
+ SortVs = [#{"a"=>1},#{a=>2},#{1=>3},#{<<"a">>=>4}],
+ [#{1:=ok},#{a:=ok},#{"a":=ok},#{<<"a">>:=ok}] = lists:sort([#{"a"=>ok},#{a=>ok},#{1=>ok},#{<<"a">>=>ok}]),
+ [#{1:=3},#{a:=2},#{"a":=1},#{<<"a">>:=4}] = lists:sort(SortVs),
+ [#{1:=3},#{a:=2},#{"a":=1},#{<<"a">>:=4}] = lists:sort(lists:reverse(SortVs)),
+ ok.
+
+t_map_equal(Config) when is_list(Config) ->
+ true = #{} =:= #{},
+ false = #{} =:= #{a=>1},
+ false = #{a=>1} =:= #{},
+ true = #{ "a" => "hi", b => 134 } =:= #{ b => 134,"a" => "hi"},
+
+ false = #{ a => 1 } =:= #{ a => 2},
+ false = #{ a => 2 } =:= #{ a => 1},
+ false = #{ a => 2, b => 1 } =:= #{ a => 1, b => 3},
+ false = #{ a => 1, b => 1 } =:= #{ a => 1, b => 3},
+
+ true = #{ a => 1 } =:= #{ a => 1},
+ true = #{ "a" => 2 } =:= #{ "a" => 2},
+ true = #{ "a" => 2, b => 3 } =:= #{ "a" => 2, b => 3},
+ true = #{ a => 1, b => 3, c => <<"wat">> } =:= #{ a => 1, b => 3, c=><<"wat">>},
+ ok.
+
+
+t_map_compare(Config) when is_list(Config) ->
+ Seed = {erlang:monotonic_time(),
+ erlang:time_offset(),
+ erlang:unique_integer()},
+ io:format("seed = ~p\n", [Seed]),
+ random:seed(Seed),
+ repeat(100, fun(_) -> float_int_compare() end, []),
+ repeat(100, fun(_) -> recursive_compare() end, []),
+ ok.
+
+float_int_compare() ->
+ Terms = numeric_keys(3),
+ %%io:format("Keys to use: ~p\n", [Terms]),
+ Pairs = lists:map(fun(K) -> list_to_tuple([{K,V} || V <- Terms]) end, Terms),
+ lists:foreach(fun(Size) ->
+ MapGen = fun() -> map_gen(list_to_tuple(Pairs), Size) end,
+ repeat(100, fun do_compare/1, [MapGen, MapGen])
+ end,
+ lists:seq(1,length(Terms))),
+ ok.
+
+numeric_keys(N) ->
+ lists:foldl(fun(_,Acc) ->
+ Int = random:uniform(N*4) - N*2,
+ Float = float(Int),
+ [Int, Float, Float * 0.99, Float * 1.01 | Acc]
+ end,
+ [],
+ lists:seq(1,N)).
+
+
+repeat(0, _, _) ->
+ ok;
+repeat(N, Fun, Arg) ->
+ Fun(Arg),
+ repeat(N-1, Fun, Arg).
+
+copy_term(T) ->
+ Papa = self(),
+ P = spawn_link(fun() -> receive Msg -> Papa ! Msg end end),
+ P ! T,
+ receive R -> R end.
+
+do_compare([Gen1, Gen2]) ->
+ M1 = Gen1(),
+ M2 = Gen2(),
+ %%io:format("Maps to compare: ~p AND ~p\n", [M1, M2]),
+ C = (M1 < M2),
+ Erlang = maps_lessthan(M1, M2),
+ C = Erlang,
+ ?CHECK(M1==M1, M1),
+
+ %% Change one key from int to float (or vice versa) and check compare
+ ML1 = maps:to_list(M1),
+ {K1,V1} = lists:nth(random:uniform(length(ML1)), ML1),
+ case K1 of
+ I when is_integer(I) ->
+ case maps:find(float(I),M1) of
+ error ->
+ M1f = maps:remove(I, maps:put(float(I), V1, M1)),
+ ?CHECK(M1f > M1, [M1f, M1]);
+ _ -> ok
+ end;
+
+ F when is_float(F), round(F) == F ->
+ case maps:find(round(F),M1) of
+ error ->
+ M1i = maps:remove(F, maps:put(round(F), V1, M1)),
+ ?CHECK(M1i < M1, [M1i, M1]);
+ _ -> ok
+ end;
+
+ _ -> ok % skip floats with decimals
+ end,
+
+ ?CHECK(M2 == M2, [M2]).
+
+
+maps_lessthan(M1, M2) ->
+ case {maps:size(M1),maps:size(M2)} of
+ {_S,_S} ->
+ {K1,V1} = lists:unzip(term_sort(maps:to_list(M1))),
+ {K2,V2} = lists:unzip(term_sort(maps:to_list(M2))),
+
+ case erts_internal:cmp_term(K1,K2) of
+ -1 -> true;
+ 0 -> (V1 < V2);
+ 1 -> false
+ end;
+
+ {S1, S2} ->
+ S1 < S2
+ end.
+
+term_sort(L) ->
+ lists:sort(fun(A,B) -> erts_internal:cmp_term(A,B) =< 0 end,
+ L).
+
+
+cmp(T1, T2, Exact) when is_tuple(T1) and is_tuple(T2) ->
+ case {size(T1),size(T2)} of
+ {_S,_S} -> cmp(tuple_to_list(T1), tuple_to_list(T2), Exact);
+ {S1,S2} when S1 < S2 -> -1;
+ {S1,S2} when S1 > S2 -> 1
+ end;
+
+cmp([H1|T1], [H2|T2], Exact) ->
+ case cmp(H1,H2, Exact) of
+ 0 -> cmp(T1,T2, Exact);
+ C -> C
+ end;
+
+cmp(M1, M2, Exact) when is_map(M1) andalso is_map(M2) ->
+ cmp_maps(M1,M2,Exact);
+cmp(M1, M2, Exact) ->
+ cmp_others(M1, M2, Exact).
+
+cmp_maps(M1, M2, Exact) ->
+ case {maps:size(M1),maps:size(M2)} of
+ {_S,_S} ->
+ {K1,V1} = lists:unzip(term_sort(maps:to_list(M1))),
+ {K2,V2} = lists:unzip(term_sort(maps:to_list(M2))),
+
+ case cmp(K1, K2, true) of
+ 0 -> cmp(V1, V2, Exact);
+ C -> C
+ end;
+
+ {S1,S2} when S1 < S2 -> -1;
+ {S1,S2} when S1 > S2 -> 1
+ end.
+
+cmp_others(I, F, true) when is_integer(I), is_float(F) ->
+ -1;
+cmp_others(F, I, true) when is_float(F), is_integer(I) ->
+ 1;
+cmp_others(T1, T2, _) ->
+ case {T1<T2, T1==T2} of
+ {true,false} -> -1;
+ {false,true} -> 0;
+ {false,false} -> 1
+ end.
+
+map_gen(Pairs, Size) ->
+ {_,L} = lists:foldl(fun(_, {Keys, Acc}) ->
+ KI = random:uniform(size(Keys)),
+ K = element(KI,Keys),
+ KV = element(random:uniform(size(K)), K),
+ {erlang:delete_element(KI,Keys), [KV | Acc]}
+ end,
+ {Pairs, []},
+ lists:seq(1,Size)),
+
+ maps:from_list(L).
+
+
+recursive_compare() ->
+ Leafs = {atom, 17, 16.9, 17.1, [], self(), spawn(fun() -> ok end), make_ref(), make_ref()},
+ {A, B} = term_gen_recursive(Leafs, 0, 0),
+ %%io:format("Recursive term A = ~p\n", [A]),
+ %%io:format("Recursive term B = ~p\n", [B]),
+
+ ?CHECK({true,false} =:= case do_cmp(A, B, false) of
+ -1 -> {A<B, A>=B};
+ 0 -> {A==B, A/=B};
+ 1 -> {A>B, A=<B}
+ end,
+ {A,B}),
+ A2 = copy_term(A),
+ ?CHECK(A == A2, {A,A2}),
+ ?CHECK(0 =:= cmp(A, A2, false), {A,A2}),
+
+ B2 = copy_term(B),
+ ?CHECK(B == B2, {B,B2}),
+ ?CHECK(0 =:= cmp(B, B2, false), {B,B2}),
+ ok.
+
+do_cmp(A, B, Exact) ->
+ C = cmp(A, B, Exact),
+ C.
+
+%% Generate two terms {A,B} that may only differ
+%% at float vs integer types.
+term_gen_recursive(Leafs, Flags, Depth) ->
+ MaxDepth = 10,
+ Rnd = case {Flags, Depth} of
+ {_, MaxDepth} -> % Only leafs
+ random:uniform(size(Leafs)) + 3;
+ {0, 0} -> % Only containers
+ random:uniform(3);
+ {0,_} -> % Anything
+ random:uniform(size(Leafs)+3)
+ end,
+ case Rnd of
+ 1 -> % Make map
+ Size = random:uniform(size(Leafs)),
+ lists:foldl(fun(_, {Acc1,Acc2}) ->
+ {K1,K2} = term_gen_recursive(Leafs, Flags,
+ Depth+1),
+ {V1,V2} = term_gen_recursive(Leafs, Flags, Depth+1),
+ {maps:put(K1,V1, Acc1), maps:put(K2,V2, Acc2)}
+ end,
+ {maps:new(), maps:new()},
+ lists:seq(1,Size));
+ 2 -> % Make cons
+ {Car1,Car2} = term_gen_recursive(Leafs, Flags, Depth+1),
+ {Cdr1,Cdr2} = term_gen_recursive(Leafs, Flags, Depth+1),
+ {[Car1 | Cdr1], [Car2 | Cdr2]};
+ 3 -> % Make tuple
+ Size = random:uniform(size(Leafs)),
+ L = lists:map(fun(_) -> term_gen_recursive(Leafs, Flags, Depth+1) end,
+ lists:seq(1,Size)),
+ {L1, L2} = lists:unzip(L),
+ {list_to_tuple(L1), list_to_tuple(L2)};
+
+ N -> % Make leaf
+ case element(N-3, Leafs) of
+ I when is_integer(I) ->
+ case random:uniform(4) of
+ 1 -> {I, float(I)};
+ 2 -> {float(I), I};
+ _ -> {I,I}
+ end;
+ T -> {T,T}
+ end
+ end.
+
+%% BIFs
+t_bif_map_get(Config) when is_list(Config) ->
+ %% small map
+ 1 = maps:get(a, #{ a=> 1}),
+ 2 = maps:get(b, #{ a=> 1, b => 2}),
+ "hi" = maps:get("hello", #{ a=>1, "hello" => "hi"}),
+ "tuple hi" = maps:get({1,1.0}, #{ a=>a, {1,1.0} => "tuple hi"}),
+
+ M0 = #{ k1=>"v1", <<"k2">> => <<"v3">> },
+ "v4" = maps:get(<<"k2">>, M0#{<<"k2">> => "v4"}),
+
+ %% large map
+ M1 = maps:from_list([{I,I}||I<-lists:seq(1,100)] ++
+ [{a,1},{b,2},{"hello","hi"},{{1,1.0},"tuple hi"},
+ {k1,"v1"},{<<"k2">>,"v3"}]),
+ 1 = maps:get(a, M1),
+ 2 = maps:get(b, M1),
+ "hi" = maps:get("hello", M1),
+ "tuple hi" = maps:get({1,1.0}, M1),
+ "v3" = maps:get(<<"k2">>, M1),
+
+ %% error cases
+ do_badmap(fun(T) ->
+ {'EXIT',{{badmap,T},[{maps,get,_,_}|_]}} =
+ (catch maps:get(a, T))
+ end),
+
+ {'EXIT',{{badkey,{1,1}},[{maps,get,_,_}|_]}} =
+ (catch maps:get({1,1}, #{{1,1.0} => "tuple"})),
+ {'EXIT',{{badkey,a},[{maps,get,_,_}|_]}} = (catch maps:get(a, #{})),
+ {'EXIT',{{badkey,a},[{maps,get,_,_}|_]}} =
+ (catch maps:get(a, #{b=>1, c=>2})),
+ ok.
+
+t_bif_map_find(Config) when is_list(Config) ->
+ %% small map
+ {ok, 1} = maps:find(a, #{ a=> 1}),
+ {ok, 2} = maps:find(b, #{ a=> 1, b => 2}),
+ {ok, "int"} = maps:find(1, #{ 1 => "int"}),
+ {ok, "float"} = maps:find(1.0, #{ 1.0=> "float"}),
+
+ {ok, "hi"} = maps:find("hello", #{ a=>1, "hello" => "hi"}),
+ {ok, "tuple hi"} = maps:find({1,1.0}, #{ a=>a, {1,1.0} => "tuple hi"}),
+
+ M0 = #{ k1=>"v1", <<"k2">> => <<"v3">> },
+ {ok, "v4"} = maps:find(<<"k2">>, M0#{ <<"k2">> => "v4" }),
+
+ %% large map
+ M1 = maps:from_list([{I,I}||I<-lists:seq(1,100)] ++
+ [{a,1},{b,2},{"hello","hi"},{{1,1.0},"tuple hi"},
+ {k1,"v1"},{<<"k2">>,"v3"}]),
+ {ok, 1} = maps:find(a, M1),
+ {ok, 2} = maps:find(b, M1),
+ {ok, "hi"} = maps:find("hello", M1),
+ {ok, "tuple hi"} = maps:find({1,1.0}, M1),
+ {ok, "v3"} = maps:find(<<"k2">>, M1),
+
+ %% error case
+ error = maps:find(a,#{}),
+ error = maps:find(a,#{b=>1, c=>2}),
+ error = maps:find(1.0, #{ 1 => "int"}),
+ error = maps:find(1, #{ 1.0 => "float"}),
+ error = maps:find({1.0,1}, #{ a=>a, {1,1.0} => "tuple hi"}), % reverse types in tuple key
+
+ do_badmap(fun(T) ->
+ {'EXIT',{{badmap,T},[{maps,find,_,_}|_]}} =
+ (catch maps:find(a, T))
+ end),
+ ok.
+
+
+t_bif_map_is_key(Config) when is_list(Config) ->
+ M1 = #{ "hi" => "hello", int => 3, <<"key">> => <<"value">>, 4 => number},
+
+ true = maps:is_key("hi", M1),
+ true = maps:is_key(int, M1),
+ true = maps:is_key(<<"key">>, M1),
+ true = maps:is_key(4, M1),
+
+ false = maps:is_key(5, M1),
+ false = maps:is_key(<<"key2">>, M1),
+ false = maps:is_key("h", M1),
+ false = maps:is_key("hello", M1),
+ false = maps:is_key(atom, M1),
+ false = maps:is_key(any, #{}),
+
+ false = maps:is_key("hi", maps:remove("hi", M1)),
+ true = maps:is_key("hi", M1),
+ true = maps:is_key(1, maps:put(1, "number", M1)),
+ false = maps:is_key(1.0, maps:put(1, "number", M1)),
+
+ %% error case
+ do_badmap(fun(T) ->
+ {'EXIT',{{badmap,T},[{maps,is_key,_,_}|_]}} =
+ (catch maps:is_key(a, T))
+ end),
+ ok.
+
+t_bif_map_keys(Config) when is_list(Config) ->
+ [] = maps:keys(#{}),
+
+ [1,2,3,4,5] = lists:sort(maps:keys(#{ 1 => a, 2 => b, 3 => c, 4 => d, 5 => e})),
+ [1,2,3,4,5] = lists:sort(maps:keys(#{ 4 => d, 5 => e, 1 => a, 2 => b, 3 => c})),
+
+ % values in key order: [4,int,"hi",<<"key">>]
+ M1 = #{ "hi" => "hello", int => 3, <<"key">> => <<"value">>, 4 => number},
+ [4,int,"hi",<<"key">>] = lists:sort(maps:keys(M1)),
+
+ %% error case
+ do_badmap(fun(T) ->
+ {'EXIT',{{badmap,T},[{maps,keys,_,_}|_]}} =
+ (catch maps:keys(T))
+ end),
+ ok.
+
+t_bif_map_new(Config) when is_list(Config) ->
+ #{} = maps:new(),
+ 0 = erlang:map_size(maps:new()),
+ ok.
+
+t_bif_map_merge(Config) when is_list(Config) ->
+ 0 = erlang:map_size(maps:merge(#{},#{})),
+
+ M0 = #{ "hi" => "hello", int => 3, <<"key">> => <<"value">>,
+ 4 => number, 18446744073709551629 => wat},
+
+ #{ "hi" := "hello", int := 3, <<"key">> := <<"value">>,
+ 4 := number, 18446744073709551629 := wat} = maps:merge(#{}, M0),
+
+ #{ "hi" := "hello", int := 3, <<"key">> := <<"value">>,
+ 4 := number, 18446744073709551629 := wat} = maps:merge(M0, #{}),
+
+ M1 = #{ "hi" => "hello again", float => 3.3, {1,2} => "tuple", 4 => integer },
+
+ #{4 := number, 18446744073709551629 := wat, float := 3.3, int := 3,
+ {1,2} := "tuple", "hi" := "hello", <<"key">> := <<"value">>} = maps:merge(M1,M0),
+
+ #{4 := integer, 18446744073709551629 := wat, float := 3.3, int := 3,
+ {1,2} := "tuple", "hi" := "hello again", <<"key">> := <<"value">>} = maps:merge(M0,M1),
+
+ %% try deep collisions
+ N = 150000,
+ Is = lists:seq(1,N),
+ M2 = maps:from_list([{I,I}||I<-Is]),
+ 150000 = maps:size(M2),
+ M3 = maps:from_list([{<<I:32>>,I}||I<-Is]),
+ 150000 = maps:size(M3),
+ M4 = maps:merge(M2,M3),
+ 300000 = maps:size(M4),
+ M5 = maps:from_list([{integer_to_list(I),I}||I<-Is]),
+ 150000 = maps:size(M5),
+ M6 = maps:merge(M4,M5),
+ 450000 = maps:size(M6),
+ M7 = maps:from_list([{float(I),I}||I<-Is]),
+ 150000 = maps:size(M7),
+ M8 = maps:merge(M7,M6),
+ 600000 = maps:size(M8),
+
+ #{ 1 := 1, "1" := 1, <<1:32>> := 1 } = M8,
+ #{ 10 := 10, "10" := 10, <<10:32>> := 10 } = M8,
+ #{ 100 := 100, "100" := 100, <<100:32>> := 100 } = M8,
+ #{ 1000 := 1000, "1000" := 1000, <<1000:32>> := 1000 } = M8,
+ #{ 10000 := 10000, "10000" := 10000, <<10000:32>> := 10000 } = M8,
+ #{ 100000 := 100000, "100000" := 100000, <<100000:32>> := 100000 } = M8,
+
+ %% overlapping
+ M8 = maps:merge(M2,M8),
+ M8 = maps:merge(M3,M8),
+ M8 = maps:merge(M4,M8),
+ M8 = maps:merge(M5,M8),
+ M8 = maps:merge(M6,M8),
+ M8 = maps:merge(M7,M8),
+ M8 = maps:merge(M8,M8),
+
+ %% maps:merge/2 and mixed
+
+ Ks1 = [764492191,2361333849], %% deep collision
+ Ks2 = lists:seq(1,33),
+ M9 = maps:from_list([{K,K}||K <- Ks1]),
+ M10 = maps:from_list([{K,K}||K <- Ks2]),
+ M11 = maps:merge(M9,M10),
+ ok = check_keys_exist(Ks1 ++ Ks2, M11),
+
+ %% error case
+ do_badmap(fun(T) ->
+ {'EXIT',{{badmap,T},[{maps,merge,_,_}|_]}} =
+ (catch maps:merge(#{}, T)),
+ {'EXIT',{{badmap,T},[{maps,merge,_,_}|_]}} =
+ (catch maps:merge(T, #{})),
+ {'EXIT',{{badmap,T},[{maps,merge,_,_}|_]}} =
+ (catch maps:merge(T, T))
+ end),
+ ok.
+
+
+t_bif_map_put(Config) when is_list(Config) ->
+ M0 = #{ "hi" => "hello", int => 3, <<"key">> => <<"value">>,
+ 4 => number, 18446744073709551629 => wat},
+
+ M1 = #{ "hi" := "hello"} = maps:put("hi", "hello", #{}),
+
+ true = is_members(["hi"],maps:keys(M1)),
+ true = is_members(["hello"],maps:values(M1)),
+
+ M2 = #{ int := 3 } = maps:put(int, 3, M1),
+
+ true = is_members([int,"hi"],maps:keys(M2)),
+ true = is_members([3,"hello"],maps:values(M2)),
+
+ M3 = #{ <<"key">> := <<"value">> } = maps:put(<<"key">>, <<"value">>, M2),
+
+ true = is_members([int,"hi",<<"key">>],maps:keys(M3)),
+ true = is_members([3,"hello",<<"value">>],maps:values(M3)),
+
+ M4 = #{ 18446744073709551629 := wat } = maps:put(18446744073709551629, wat, M3),
+
+ true = is_members([18446744073709551629,int,"hi",<<"key">>],maps:keys(M4)),
+ true = is_members([wat,3,"hello",<<"value">>],maps:values(M4)),
+
+ M0 = #{ 4 := number } = M5 = maps:put(4, number, M4),
+
+ true = is_members([4,18446744073709551629,int,"hi",<<"key">>],maps:keys(M5)),
+ true = is_members([number,wat,3,"hello",<<"value">>],maps:values(M5)),
+
+ M6 = #{ <<"key">> := <<"other value">> } = maps:put(<<"key">>, <<"other value">>, M5),
+
+ true = is_members([4,18446744073709551629,int,"hi",<<"key">>],maps:keys(M6)),
+ true = is_members([number,wat,3,"hello",<<"other value">>],maps:values(M6)),
+
+ %% error case
+ do_badmap(fun(T) ->
+ {'EXIT',{{badmap,T},[{maps,put,_,_}|_]}} =
+ (catch maps:put(1, a, T))
+ end),
+ ok.
+
+is_members(Ks,Ls) when length(Ks) =/= length(Ls) -> false;
+is_members(Ks,Ls) -> is_members_do(Ks,Ls).
+
+is_members_do([],[]) -> true;
+is_members_do([],_) -> false;
+is_members_do([K|Ks],Ls) ->
+ is_members_do(Ks, lists:delete(K,Ls)).
+
+t_bif_map_remove(Config) when is_list(Config) ->
+ 0 = erlang:map_size(maps:remove(some_key, #{})),
+
+ M0 = #{ "hi" => "hello", int => 3, <<"key">> => <<"value">>,
+ 4 => number, 18446744073709551629 => wat},
+
+ M1 = maps:remove("hi", M0),
+ true = is_members([4,18446744073709551629,int,<<"key">>],maps:keys(M1)),
+ true = is_members([number,wat,3,<<"value">>],maps:values(M1)),
+
+ M2 = maps:remove(int, M1),
+ true = is_members([4,18446744073709551629,<<"key">>],maps:keys(M2)),
+ true = is_members([number,wat,<<"value">>],maps:values(M2)),
+
+ M3 = maps:remove(<<"key">>, M2),
+ true = is_members([4,18446744073709551629],maps:keys(M3)),
+ true = is_members([number,wat],maps:values(M3)),
+
+ M4 = maps:remove(18446744073709551629, M3),
+ true = is_members([4],maps:keys(M4)),
+ true = is_members([number],maps:values(M4)),
+
+ M5 = maps:remove(4, M4),
+ [] = maps:keys(M5),
+ [] = maps:values(M5),
+
+ M0 = maps:remove(5,M0),
+ M0 = maps:remove("hi there",M0),
+
+ #{ "hi" := "hello", int := 3, 4 := number} = maps:remove(18446744073709551629,maps:remove(<<"key">>,M0)),
+
+ %% error case
+ do_badmap(fun(T) ->
+ {'EXIT',{{badmap,T},[{maps,remove,_,_}|_]}} =
+ (catch maps:remove(a, T))
+ end),
+ ok.
+
+t_bif_map_update(Config) when is_list(Config) ->
+ M0 = #{ "hi" => "hello", int => 3, <<"key">> => <<"value">>,
+ 4 => number, 18446744073709551629 => wat},
+
+ #{ "hi" := "hello again", int := 3, <<"key">> := <<"value">>,
+ 4 := number, 18446744073709551629 := wat} = maps:update("hi", "hello again", M0),
+
+ #{ "hi" := "hello", int := 1337, <<"key">> := <<"value">>,
+ 4 := number, 18446744073709551629 := wat} = maps:update(int, 1337, M0),
+
+ #{ "hi" := "hello", int := 3, <<"key">> := <<"new value">>,
+ 4 := number, 18446744073709551629 := wat} = maps:update(<<"key">>, <<"new value">>, M0),
+
+ #{ "hi" := "hello", int := 3, <<"key">> := <<"value">>,
+ 4 := integer, 18446744073709551629 := wat} = maps:update(4, integer, M0),
+
+ #{ "hi" := "hello", int := 3, <<"key">> := <<"value">>,
+ 4 := number, 18446744073709551629 := wazzup} = maps:update(18446744073709551629, wazzup, M0),
+
+ %% error case
+ do_badmap(fun(T) ->
+ {'EXIT',{{badmap,T},[{maps,update,_,_}|_]}} =
+ (catch maps:update(1, none, T))
+ end),
+ ok.
+
+
+
+t_bif_map_values(Config) when is_list(Config) ->
+
+ [] = maps:values(#{}),
+ [1] = maps:values(#{a=>1}),
+
+ true = is_members([a,b,c,d,e],maps:values(#{ 1 => a, 2 => b, 3 => c, 4 => d, 5 => e})),
+ true = is_members([a,b,c,d,e],maps:values(#{ 4 => d, 5 => e, 1 => a, 2 => b, 3 => c})),
+
+ M1 = #{ "hi" => "hello", int => 3, <<"key">> => <<"value">>, 4 => number},
+ M2 = M1#{ "hi" => "hello2", <<"key">> => <<"value2">> },
+ true = is_members([number,3,"hello2",<<"value2">>],maps:values(M2)),
+ true = is_members([number,3,"hello",<<"value">>],maps:values(M1)),
+
+ Vs = lists:seq(1000,20000),
+ M3 = maps:from_list([{K,K}||K<-Vs]),
+ M4 = maps:merge(M1,M3),
+ M5 = maps:merge(M2,M3),
+ true = is_members(Vs,maps:values(M3)),
+ true = is_members([number,3,"hello",<<"value">>]++Vs,maps:values(M4)),
+ true = is_members([number,3,"hello2",<<"value2">>]++Vs,maps:values(M5)),
+
+ %% error case
+ do_badmap(fun(T) ->
+ {'EXIT',{{badmap,T},[{maps,values,_,_}|_]}} =
+ (catch maps:values(T))
+ end),
+ ok.
+
+t_erlang_hash(Config) when is_list(Config) ->
+ ok = t_bif_erlang_phash2(),
+ ok = t_bif_erlang_phash(),
+ ok.
+
+t_bif_erlang_phash2() ->
+
+ 39679005 = erlang:phash2(#{}),
+ 33667975 = erlang:phash2(#{ a => 1, "a" => 2, <<"a">> => 3, {a,b} => 4 }), % 78942764
+ 95332690 = erlang:phash2(#{ 1 => a, 2 => "a", 3 => <<"a">>, 4 => {a,b} }), % 37338230
+ 108954384 = erlang:phash2(#{ 1 => a }), % 14363616
+ 59617982 = erlang:phash2(#{ a => 1 }), % 51612236
+
+ 42770201 = erlang:phash2(#{{} => <<>>}), % 37468437
+ 71687700 = erlang:phash2(#{<<>> => {}}), % 44049159
+
+ M0 = #{ a => 1, "key" => <<"value">> },
+ M1 = maps:remove("key",M0),
+ M2 = M1#{ "key" => <<"value">> },
+
+ 70249457 = erlang:phash2(M0), % 118679416
+ 59617982 = erlang:phash2(M1), % 51612236
+ 70249457 = erlang:phash2(M2), % 118679416
+ ok.
+
+t_bif_erlang_phash() ->
+ Sz = 1 bsl 32,
+ 1113425985 = erlang:phash(#{},Sz), % 268440612
+ 1510068139 = erlang:phash(#{ a => 1, "a" => 2, <<"a">> => 3, {a,b} => 4 },Sz), % 1196461908
+ 3182345590 = erlang:phash(#{ 1 => a, 2 => "a", 3 => <<"a">>, 4 => {a,b} },Sz), % 3944426064
+ 2927531828 = erlang:phash(#{ 1 => a },Sz), % 1394238263
+ 1670235874 = erlang:phash(#{ a => 1 },Sz), % 4066388227
+
+ 3935089469 = erlang:phash(#{{} => <<>>},Sz), % 1578050717
+ 71692856 = erlang:phash(#{<<>> => {}},Sz), % 1578050717
+
+ M0 = #{ a => 1, "key" => <<"value">> },
+ M1 = maps:remove("key",M0),
+ M2 = M1#{ "key" => <<"value">> },
+
+ 2620391445 = erlang:phash(M0,Sz), % 3590546636
+ 1670235874 = erlang:phash(M1,Sz), % 4066388227
+ 2620391445 = erlang:phash(M2,Sz), % 3590546636
+ ok.
+
+t_map_encode_decode(Config) when is_list(Config) ->
+ <<131,116,0,0,0,0>> = erlang:term_to_binary(#{}),
+ Pairs = [
+ {a,b},{"key","values"},{<<"key">>,<<"value">>},
+ {1,b},{[atom,1],{<<"wat">>,1,2,3}},
+ {aa,"values"},
+ {1 bsl 64 + (1 bsl 50 - 1), sc1},
+ {99, sc2},
+ {1 bsl 65 + (1 bsl 51 - 1), sc3},
+ {88, sc4},
+ {1 bsl 66 + (1 bsl 52 - 1), sc5},
+ {77, sc6},
+ {1 bsl 67 + (1 bsl 53 - 1), sc3},
+ {75, sc6}, {-10,sc8},
+ {<<>>, sc9}, {3.14158, sc10},
+ {[3.14158], sc11}, {more_atoms, sc12},
+ {{more_tuples}, sc13}, {self(), sc14},
+ {{},{}},{[],[]}
+ ],
+ ok = map_encode_decode_and_match(Pairs,[],#{}),
+
+ %% check sorting
+
+ %% literally #{ b=>2, a=>1 } in the internal order
+ #{ a:=1, b:=2 } =
+ erlang:binary_to_term(<<131,116,0,0,0,2,100,0,1,98,97,2,100,0,1,97,97,1>>),
+
+
+ %% literally #{ "hi" => "value", a=>33, b=>55 } in the internal order
+ #{ a:=33, b:=55, "hi" := "value"} = erlang:binary_to_term(<<131,116,0,0,0,3,
+ 107,0,2,104,105, % "hi" :: list()
+ 107,0,5,118,97,108,117,101, % "value" :: list()
+ 100,0,1,97, % a :: atom()
+ 97,33, % 33 :: integer()
+ 100,0,1,98, % b :: atom()
+ 97,55 % 55 :: integer()
+ >>),
+
+ %% Maps of different sizes
+ lists:foldl(fun(Key, M0) ->
+ M1 = M0#{Key => Key},
+ case Key rem 17 of
+ 0 ->
+ M1 = binary_to_term(term_to_binary(M1));
+ _ ->
+ ok
+ end,
+ M1
+ end,
+ #{},
+ lists:seq(1,10000)),
+
+ %% many maps in same binary
+ MapList = lists:foldl(fun(K, [M|_]=Acc) -> [M#{K => K} | Acc] end,
+ [#{}],
+ lists:seq(1,100)),
+ MapList = binary_to_term(term_to_binary(MapList)),
+ MapListR = lists:reverse(MapList),
+ MapListR = binary_to_term(term_to_binary(MapListR)),
+
+ %% error cases
+ %% template: <<131,116,0,0,0,2,100,0,1,97,100,0,1,98,97,1,97,1>>
+ %% which is: #{ a=>1, b=>1 }
+
+ %% uniqueness violation
+ %% literally #{ a=>1, "hi"=>"value", a=>2 }
+ {'EXIT',{badarg,[{_,_,_,_}|_]}} = (catch
+ erlang:binary_to_term(<<131,116,0,0,0,3,
+ 100,0,1,97,
+ 97,1,
+ 107,0,2,104,105,
+ 107,0,5,118,97,108,117,101,
+ 100,0,1,97,
+ 97,2>>)),
+
+ %% bad size (too large)
+ {'EXIT',{badarg,[{_,_,_,_}|_]}} = (catch
+ erlang:binary_to_term(<<131,116,0,0,0,12,100,0,1,97,97,1,100,0,1,98,97,1>>)),
+
+ %% bad size (too small) .. should fail just truncate it .. weird.
+ %% possibly change external format so truncated will be #{a:=1}
+ #{ a:=b } =
+ erlang:binary_to_term(<<131,116,0,0,0,1,100,0,1,97,100,0,1,98,97,1,97,1>>),
+
+ ok.
+
+map_encode_decode_and_match([{K,V}|Pairs], EncodedPairs, M0) ->
+ M1 = maps:put(K,V,M0),
+ B0 = erlang:term_to_binary(M1),
+ Ls = [{erlang:term_to_binary(K), erlang:term_to_binary(V)}|EncodedPairs],
+ ok = match_encoded_map(B0, length(Ls), Ls),
+ %% decode and match it
+ M1 = erlang:binary_to_term(B0),
+ map_encode_decode_and_match(Pairs,Ls,M1);
+map_encode_decode_and_match([],_,_) -> ok.
+
+match_encoded_map(<<131,116,Size:32,Encoded/binary>>,Size,Items) ->
+ match_encoded_map_stripped_size(Encoded,Items,Items);
+match_encoded_map(_,_,_) -> no_match_size.
+
+match_encoded_map_stripped_size(<<>>,_,_) -> ok;
+match_encoded_map_stripped_size(B0,[{<<131,K/binary>>,<<131,V/binary>>}|Items],Ls) ->
+ Ksz = byte_size(K),
+ Vsz = byte_size(V),
+ case B0 of
+ <<K:Ksz/binary,V:Vsz/binary,B1/binary>> ->
+ match_encoded_map_stripped_size(B1,Ls,Ls);
+ _ ->
+ match_encoded_map_stripped_size(B0,Items,Ls)
+ end;
+match_encoded_map_stripped_size(_,[],_) -> fail.
+
+
+t_bif_map_to_list(Config) when is_list(Config) ->
+ [] = maps:to_list(#{}),
+ [{a,1},{b,2}] = lists:sort(maps:to_list(#{a=>1,b=>2})),
+ [{a,1},{b,2},{c,3}] = lists:sort(maps:to_list(#{c=>3,a=>1,b=>2})),
+ [{a,1},{b,2},{g,3}] = lists:sort(maps:to_list(#{g=>3,a=>1,b=>2})),
+ [{a,1},{b,2},{g,3},{"c",4}] = lists:sort(maps:to_list(#{g=>3,a=>1,b=>2,"c"=>4})),
+ [{3,v2},{hi,v4},{{hi,3},v5},{"hi",v3},{<<"hi">>,v1}] =
+ lists:sort(maps:to_list(#{<<"hi">>=>v1,3=>v2,"hi"=>v3,hi=>v4,{hi,3}=>v5})),
+
+ [{3,v7},{hi,v9},{{hi,3},v10},{"hi",v8},{<<"hi">>,v6}] =
+ lists:sort(maps:to_list(#{<<"hi">>=>v1,3=>v2,"hi"=>v3,hi=>v4,{hi,3}=>v5,
+ <<"hi">>=>v6,3=>v7,"hi"=>v8,hi=>v9,{hi,3}=>v10})),
+
+ %% error cases
+ do_badmap(fun(T) ->
+ {'EXIT', {{badmap,T},_}} =
+ (catch maps:to_list(T))
+ end),
+ ok.
+
+
+t_bif_map_from_list(Config) when is_list(Config) ->
+ #{} = maps:from_list([]),
+ A = maps:from_list([]),
+ 0 = erlang:map_size(A),
+
+ #{a:=1,b:=2} = maps:from_list([{a,1},{b,2}]),
+ #{c:=3,a:=1,b:=2} = maps:from_list([{a,1},{b,2},{c,3}]),
+ #{g:=3,a:=1,b:=2} = maps:from_list([{a,1},{b,2},{g,3}]),
+
+ #{a:=2} = maps:from_list([{a,1},{a,3},{a,2}]),
+
+ #{ <<"hi">>:=v1,3:=v3,"hi":=v6,hi:=v4,{hi,3}:=v5} =
+ maps:from_list([{3,v3},{"hi",v6},{hi,v4},{{hi,3},v5},{<<"hi">>,v1}]),
+
+ #{<<"hi">>:=v6,3:=v8,"hi":=v11,hi:=v9,{hi,3}:=v10} =
+ maps:from_list([ {{hi,3},v3}, {"hi",v0},{3,v1}, {<<"hi">>,v4}, {hi,v2},
+ {<<"hi">>,v6}, {{hi,3},v10},{"hi",v11}, {hi,v9}, {3,v8}]),
+
+ %% repeated keys (large -> small)
+ Ps1 = [{a,I}|| I <- lists:seq(1,32)],
+ Ps2 = [{a,I}|| I <- lists:seq(33,64)],
+
+ M = maps:from_list(Ps1 ++ [{b,1},{c,1}] ++ Ps2),
+ #{ a := 64, b := 1, c := 1 } = M,
+
+ %% error cases
+ {'EXIT', {badarg,_}} = (catch maps:from_list([{a,b},b])),
+ {'EXIT', {badarg,_}} = (catch maps:from_list([{a,b},{b,b,3}])),
+ {'EXIT', {badarg,_}} = (catch maps:from_list([{a,b},<<>>])),
+ {'EXIT', {badarg,_}} = (catch maps:from_list([{a,b}|{b,a}])),
+ {'EXIT', {badarg,_}} = (catch maps:from_list(a)),
+ {'EXIT', {badarg,_}} = (catch maps:from_list(42)),
+ ok.
+
+t_bif_build_and_check(Config) when is_list(Config) ->
+ ok = check_build_and_remove(750,[
+ fun(K) -> [K,K] end,
+ fun(K) -> [float(K),K] end,
+ fun(K) -> K end,
+ fun(K) -> {1,K} end,
+ fun(K) -> {K} end,
+ fun(K) -> [K|K] end,
+ fun(K) -> [K,1,2,3,4] end,
+ fun(K) -> {K,atom} end,
+ fun(K) -> float(K) end,
+ fun(K) -> integer_to_list(K) end,
+ fun(K) -> list_to_atom(integer_to_list(K)) end,
+ fun(K) -> [K,{K,[K,{K,[K]}]}] end,
+ fun(K) -> <<K:32>> end
+ ]),
+
+ ok.
+
+check_build_and_remove(_,[]) -> ok;
+check_build_and_remove(N,[F|Fs]) ->
+ {M,Ks} = build_and_check(N, maps:new(), F, []),
+ ok = remove_and_check(Ks,M),
+ check_build_and_remove(N,Fs).
+
+build_and_check(0, M0, _, Ks) -> {M0, Ks};
+build_and_check(N, M0, F, Ks) ->
+ K = build_key(F,N),
+ M1 = maps:put(K,K,M0),
+ ok = check_keys_exist([I||{I,_} <- [{K,M1}|Ks]], M1),
+ M2 = maps:update(K,v,M1),
+ v = maps:get(K,M2),
+ build_and_check(N-1,M1,F,[{K,M1}|Ks]).
+
+remove_and_check([],_) -> ok;
+remove_and_check([{K,Mc}|Ks], M0) ->
+ K = maps:get(K,M0),
+ true = maps:is_key(K,M0),
+ true = Mc =:= M0,
+ true = M0 == Mc,
+ M1 = maps:remove(K,M0),
+ false = M1 =:= Mc,
+ false = Mc == M1,
+ false = maps:is_key(K,M1),
+ true = maps:is_key(K,M0),
+ ok = check_keys_exist([I||{I,_} <- Ks],M1),
+ error = maps:find(K,M1),
+ remove_and_check(Ks, M1).
+
+build_key(F,N) when N rem 3 =:= 0 -> F(N);
+build_key(F,N) when N rem 3 =:= 1 -> K = F(N), {K,K};
+build_key(F,N) when N rem 3 =:= 2 -> K = F(N), [K,K].
+
+check_keys_exist([], _) -> ok;
+check_keys_exist([K|Ks],M) ->
+ true = maps:is_key(K,M),
+ check_keys_exist(Ks,M).
+
+t_bif_merge_and_check(Config) when is_list(Config) ->
+
+ io:format("rand:export_seed() -> ~p\n",[rand:export_seed()]),
+
+ %% simple disjunct ones
+ %% make sure all keys are unique
+ Kss = [[a,b,c,d],
+ [1,2,3,4],
+ [],
+ ["hi"],
+ [e],
+ [build_key(fun(K) -> {small,K} end, I) || I <- lists:seq(1,32)],
+ lists:seq(5, 28),
+ lists:seq(29, 59),
+ [build_key(fun(K) -> integer_to_list(K) end, I) || I <- lists:seq(2000,10000)],
+ [build_key(fun(K) -> <<K:32>> end, I) || I <- lists:seq(1,80)],
+ [build_key(fun(K) -> {<<K:32>>} end, I) || I <- lists:seq(100,1000)]],
+
+
+ KsMs = build_keys_map_pairs(Kss),
+ Cs = [{CKs1,CM1,CKs2,CM2} || {CKs1,CM1} <- KsMs, {CKs2,CM2} <- KsMs],
+ ok = merge_and_check_combo(Cs),
+
+ %% overlapping ones
+
+ KVs1 = [{a,1},{b,2},{c,3}],
+ KVs2 = [{b,3},{c,4},{d,5}],
+ KVs = [{I,I} || I <- lists:seq(1,32)],
+ KVs3 = KVs1 ++ KVs,
+ KVs4 = KVs2 ++ KVs,
+
+ M1 = maps:from_list(KVs1),
+ M2 = maps:from_list(KVs2),
+ M3 = maps:from_list(KVs3),
+ M4 = maps:from_list(KVs4),
+
+ M12 = maps:merge(M1,M2),
+ ok = check_key_values(KVs2 ++ [{a,1}], M12),
+ M21 = maps:merge(M2,M1),
+ ok = check_key_values(KVs1 ++ [{d,5}], M21),
+
+ M34 = maps:merge(M3,M4),
+ ok = check_key_values(KVs4 ++ [{a,1}], M34),
+ M43 = maps:merge(M4,M3),
+ ok = check_key_values(KVs3 ++ [{d,5}], M43),
+
+ M14 = maps:merge(M1,M4),
+ ok = check_key_values(KVs4 ++ [{a,1}], M14),
+ M41 = maps:merge(M4,M1),
+ ok = check_key_values(KVs1 ++ [{d,5}] ++ KVs, M41),
+
+ [begin Ma = random_map(SzA, a),
+ Mb = random_map(SzB, b),
+ ok = merge_maps(Ma, Mb)
+ end || SzA <- [3,10,20,100,200,1000], SzB <- [3,10,20,100,200,1000]],
+
+ ok.
+
+% Generate random map with an average of Sz number of pairs: K -> {V,K}
+random_map(Sz, V) ->
+ random_map_insert(#{}, 0, V, Sz*2).
+
+random_map_insert(M0, K0, _, Sz) when K0 > Sz ->
+ M0;
+random_map_insert(M0, K0, V, Sz) ->
+ Key = K0 + rand:uniform(3),
+ random_map_insert(M0#{Key => {V,Key}}, Key, V, Sz).
+
+
+merge_maps(A, B) ->
+ AB = maps:merge(A, B),
+ %%io:format("A=~p\nB=~p\n",[A,B]),
+ maps_foreach(fun(K,VB) -> VB = maps:get(K, AB)
+ end, B),
+ maps_foreach(fun(K,VA) ->
+ case {maps:get(K, AB),maps:find(K, B)} of
+ {VA, error} -> ok;
+ {VB, {ok, VB}} -> ok
+ end
+ end, A),
+
+ maps_foreach(fun(K,V) ->
+ case {maps:find(K, A),maps:find(K, B)} of
+ {{ok, V}, error} -> ok;
+ {error, {ok, V}} -> ok;
+ {{ok,_}, {ok, V}} -> ok
+ end
+ end, AB),
+ ok.
+
+maps_foreach(Fun, Map) ->
+ maps:fold(fun(K,V,_) -> Fun(K,V) end, void, Map).
+
+
+check_key_values([],_) -> ok;
+check_key_values([{K,V}|KVs],M) ->
+ V = maps:get(K,M),
+ check_key_values(KVs,M).
+
+merge_and_check_combo([]) -> ok;
+merge_and_check_combo([{Ks1,M1,Ks2,M2}|Cs]) ->
+ M12 = maps:merge(M1,M2),
+ ok = check_keys_exist(Ks1 ++ Ks2, M12),
+ M21 = maps:merge(M2,M1),
+ ok = check_keys_exist(Ks1 ++ Ks2, M21),
+
+ true = M12 =:= M21,
+ M12 = M21,
+
+ merge_and_check_combo(Cs).
+
+build_keys_map_pairs([]) -> [];
+build_keys_map_pairs([Ks|Kss]) ->
+ M = maps:from_list(keys_to_pairs(Ks)),
+ ok = check_keys_exist(Ks, M),
+ [{Ks,M}|build_keys_map_pairs(Kss)].
+
+keys_to_pairs(Ks) -> [{K,K} || K <- Ks].
+
+
+%% Maps module, not BIFs
+t_maps_fold(_Config) ->
+ Vs = lists:seq(1,100),
+ M = maps:from_list([{{k,I},{v,I}}||I<-Vs]),
+
+ %% fold
+ 5050 = maps:fold(fun({k,_},{v,V},A) -> V + A end, 0, M),
+
+ ok.
+
+t_maps_map(_Config) ->
+ Vs = lists:seq(1,100),
+ M1 = maps:from_list([{I,I}||I<-Vs]),
+ M2 = maps:from_list([{I,{token,I}}||I<-Vs]),
+
+ M2 = maps:map(fun(_K,V) -> {token,V} end, M1),
+ ok.
+
+t_maps_size(_Config) ->
+ Vs = lists:seq(1,100),
+ lists:foldl(fun(I,M) ->
+ M1 = maps:put(I,I,M),
+ I = maps:size(M1),
+ M1
+ end, #{}, Vs),
+ ok.
+
+
+t_maps_without(_Config) ->
+ Ki = [11,22,33,44,55,66,77,88,99],
+ M0 = maps:from_list([{{k,I},{v,I}}||I<-lists:seq(1,100)]),
+ M1 = maps:from_list([{{k,I},{v,I}}||I<-lists:seq(1,100) -- Ki]),
+ M1 = maps:without([{k,I}||I <- Ki],M0),
+ ok.
+
+t_erts_internal_order(_Config) when is_list(_Config) ->
+ M = #{0 => 0,2147483648 => 0},
+ true = M =:= binary_to_term(term_to_binary(M)),
+
+ F1 = fun(_, _) -> 0 end,
+ F2 = fun(_, _) -> 1 end,
+ M0 = maps:from_list( [{-2147483649, 0}, {0,0}, {97, 0}, {false, 0}, {flower, 0}, {F1, 0}, {F2, 0}, {<<>>, 0}]),
+ M1 = maps:merge(M0, #{0 => 1}),
+ 8 = maps:size(M1),
+ 1 = maps:get(0,M1),
+ ok.
+
+t_erts_internal_hash(_Config) when is_list(_Config) ->
+ K1 = 0.0,
+ K2 = 0.0/-1,
+ M = maps:from_list([{I,I}||I<-lists:seq(1,32)]),
+
+ M1 = M#{ K1 => a, K2 => b },
+ b = maps:get(K2,M1),
+
+ M2 = M#{ K2 => a, K1 => b },
+ b = maps:get(K1,M2),
+
+ %% test previously faulty hash list optimization
+
+ M3 = M#{[0] => a, [0,0] => b, [0,0,0] => c, [0,0,0,0] => d},
+ a = maps:get([0],M3),
+ b = maps:get([0,0],M3),
+ c = maps:get([0,0,0],M3),
+ d = maps:get([0,0,0,0],M3),
+
+ M4 = M#{{[0]} => a, {[0,0]} => b, {[0,0,0]} => c, {[0,0,0,0]} => d},
+ a = maps:get({[0]},M4),
+ b = maps:get({[0,0]},M4),
+ c = maps:get({[0,0,0]},M4),
+ d = maps:get({[0,0,0,0]},M4),
+
+ M5 = M3#{[0,0,0] => e, [0,0,0,0] => f, [0,0,0,0,0] => g,
+ [0,0,0,0,0,0] => h, [0,0,0,0,0,0,0] => i,
+ [0,0,0,0,0,0,0,0] => j, [0,0,0,0,0,0,0,0,0] => k},
+
+ a = maps:get([0],M5),
+ b = maps:get([0,0],M5),
+ e = maps:get([0,0,0],M5),
+ f = maps:get([0,0,0,0],M5),
+ g = maps:get([0,0,0,0,0],M5),
+ h = maps:get([0,0,0,0,0,0],M5),
+ i = maps:get([0,0,0,0,0,0,0],M5),
+ j = maps:get([0,0,0,0,0,0,0,0],M5),
+ k = maps:get([0,0,0,0,0,0,0,0,0],M5),
+
+ M6 = M4#{{[0,0,0]} => e, {[0,0,0,0]} => f, {[0,0,0,0,0]} => g,
+ {[0,0,0,0,0,0]} => h, {[0,0,0,0,0,0,0]} => i,
+ {[0,0,0,0,0,0,0,0]} => j, {[0,0,0,0,0,0,0,0,0]} => k},
+
+ a = maps:get({[0]},M6),
+ b = maps:get({[0,0]},M6),
+ e = maps:get({[0,0,0]},M6),
+ f = maps:get({[0,0,0,0]},M6),
+ g = maps:get({[0,0,0,0,0]},M6),
+ h = maps:get({[0,0,0,0,0,0]},M6),
+ i = maps:get({[0,0,0,0,0,0,0]},M6),
+ j = maps:get({[0,0,0,0,0,0,0,0]},M6),
+ k = maps:get({[0,0,0,0,0,0,0,0,0]},M6),
+
+ M7 = maps:merge(M5,M6),
+
+ a = maps:get([0],M7),
+ b = maps:get([0,0],M7),
+ e = maps:get([0,0,0],M7),
+ f = maps:get([0,0,0,0],M7),
+ g = maps:get([0,0,0,0,0],M7),
+ h = maps:get([0,0,0,0,0,0],M7),
+ i = maps:get([0,0,0,0,0,0,0],M7),
+ j = maps:get([0,0,0,0,0,0,0,0],M7),
+ k = maps:get([0,0,0,0,0,0,0,0,0],M7),
+ a = maps:get({[0]},M7),
+ b = maps:get({[0,0]},M7),
+ e = maps:get({[0,0,0]},M7),
+ f = maps:get({[0,0,0,0]},M7),
+ g = maps:get({[0,0,0,0,0]},M7),
+ h = maps:get({[0,0,0,0,0,0]},M7),
+ i = maps:get({[0,0,0,0,0,0,0]},M7),
+ j = maps:get({[0,0,0,0,0,0,0,0]},M7),
+ k = maps:get({[0,0,0,0,0,0,0,0,0]},M7),
+ ok.
+
+t_pdict(_Config) ->
+
+ put(#{ a => b, b => a},#{ c => d}),
+ put(get(#{ a => b, b => a}),1),
+ 1 = get(#{ c => d}),
+ #{ c := d } = get(#{ a => b, b => a}).
+
+t_ets(_Config) ->
+
+ Tid = ets:new(map_table,[]),
+
+ [ets:insert(Tid,{maps:from_list([{I,-I}]),I}) || I <- lists:seq(1,100)],
+
+
+ [{#{ 2 := -2},2}] = ets:lookup(Tid,#{ 2 => -2 }),
+
+ %% Test equal
+ [3,4] = lists:sort(
+ ets:select(Tid,[{{'$1','$2'},
+ [{'or',{'==','$1',#{ 3 => -3 }},
+ {'==','$1',#{ 4 => -4 }}}],
+ ['$2']}])),
+ %% Test match
+ [30,50] = lists:sort(
+ ets:select(Tid,
+ [{{#{ 30 => -30}, '$1'},[],['$1']},
+ {{#{ 50 => -50}, '$1'},[],['$1']}]
+ )),
+
+ ets:insert(Tid,{#{ a => b, b => c, c => a},transitivity}),
+
+ %% Test equal with map of different size
+ [] = ets:select(Tid,[{{'$1','_'},[{'==','$1',#{ b => c }}],['$_']}]),
+
+ %% Test match with map of different size
+ %[{#{ a := b },_}] = ets:select(Tid,[{{#{ b => c },'_'},[],['$_']}]),
+
+ %%% Test match with don't care value
+ %[{#{ a := b },_}] = ets:select(Tid,[{{#{ b => '_' },'_'},[],['$_']}]),
+
+ %% Test is_map bif
+ 101 = length(ets:select(Tid,[{'$1',[{is_map,{element,1,'$1'}}],['$1']}])),
+ ets:insert(Tid,{not_a_map,2}),
+ 101 = length(ets:select(Tid,[{'$1',[{is_map,{element,1,'$1'}}],['$1']}])),
+ ets:insert(Tid,{{nope,a,tuple},2}),
+ 101 = length(ets:select(Tid,[{'$1',[{is_map,{element,1,'$1'}}],['$1']}])),
+
+ %% Test map_size bif
+ [3] = ets:select(Tid,[{{'$1','_'},[{'==',{map_size,'$1'},3}],
+ [{map_size,'$1'}]}]),
+
+ true = ets:delete(Tid,#{50 => -50}),
+ [] = ets:lookup(Tid,#{50 => -50}),
+
+ ets:delete(Tid),
+ ok.
+
+t_dets(_Config) ->
+ ok.
+
+t_tracing(_Config) ->
+
+ dbg:stop_clear(),
+ {ok,Tracer} = dbg:tracer(process,{fun trace_collector/2, self()}),
+ dbg:p(self(),c),
+
+ %% Test basic map call
+ {ok,_} = dbg:tpl(?MODULE,id,x),
+ #{ a => b },
+ {trace,_,call,{?MODULE,id,[#{ a := b }]}} = getmsg(Tracer),
+ {trace,_,return_from,{?MODULE,id,1},#{ a := b }} = getmsg(Tracer),
+ dbg:ctpl(),
+
+ %% Test equals in argument list
+ {ok,_} = dbg:tpl(?MODULE,id,[{['$1'],[{'==','$1',#{ b => c}}],
+ [{return_trace}]}]),
+ #{ a => b },
+ #{ b => c },
+ {trace,_,call,{?MODULE,id,[#{ b := c }]}} = getmsg(Tracer),
+ {trace,_,return_from,{?MODULE,id,1},#{ b := c }} = getmsg(Tracer),
+ dbg:ctpl(),
+
+ %% Test match in head
+ {ok,_} = dbg:tpl(?MODULE,id,[{[#{b => c}],[],[]}]),
+ #{ a => b },
+ #{ b => c },
+ {trace,_,call,{?MODULE,id,[#{ b := c }]}} = getmsg(Tracer),
+ dbg:ctpl(),
+
+ % Test map guard bifs
+ {ok,_} = dbg:tpl(?MODULE,id,[{['$1'],[{is_map,{element,1,'$1'}}],[]}]),
+ #{ a => b },
+ {1,2},
+ {#{ a => b},2},
+ {trace,_,call,{?MODULE,id,[{#{ a := b },2}]}} = getmsg(Tracer),
+ dbg:ctpl(),
+
+ {ok,_} = dbg:tpl(?MODULE,id,[{['$1'],[{'==',{map_size,{element,1,'$1'}},2}],[]}]),
+ #{ a => b },
+ {1,2},
+ {#{ a => b},2},
+ {#{ a => b, b => c},atom},
+ {trace,_,call,{?MODULE,id,[{#{ a := b, b := c },atom}]}} = getmsg(Tracer),
+ dbg:ctpl(),
+
+ %MS = dbg:fun2ms(fun([A]) when A == #{ a => b} -> ok end),
+ %dbg:tpl(?MODULE,id,MS),
+ %#{ a => b },
+ %#{ b => c },
+ %{trace,_,call,{?MODULE,id,[#{ a := b }]}} = getmsg(Tracer),
+ %dbg:ctpl(),
+
+ %% Check to extra messages
+ timeout = getmsg(Tracer),
+
+ dbg:stop_clear(),
+ ok.
+
+getmsg(_Tracer) ->
+ receive V -> V after 100 -> timeout end.
+
+trace_collector(Msg,Parent) ->
+ io:format("~p~n",[Msg]),
+ Parent ! Msg,
+ Parent.
+
+t_has_map_fields(Config) when is_list(Config) ->
+ true = has_map_fields_1(#{one=>1}),
+ true = has_map_fields_1(#{one=>1,two=>2}),
+ false = has_map_fields_1(#{two=>2}),
+ false = has_map_fields_1(#{}),
+
+ true = has_map_fields_2(#{c=>1,b=>2,a=>3}),
+ true = has_map_fields_2(#{c=>1,b=>2,a=>3,x=>42}),
+ false = has_map_fields_2(#{b=>2,c=>1}),
+ false = has_map_fields_2(#{x=>y}),
+ false = has_map_fields_2(#{}),
+
+ true = has_map_fields_3(#{c=>1,b=>2,a=>3}),
+ true = has_map_fields_3(#{c=>1,b=>2,a=>3,[]=>42}),
+ true = has_map_fields_3(#{b=>2,a=>3,[]=>42,42.0=>43}),
+ true = has_map_fields_3(#{a=>3,[]=>42,42.0=>43}),
+ true = has_map_fields_3(#{[]=>42,42.0=>43}),
+ false = has_map_fields_3(#{b=>2,c=>1}),
+ false = has_map_fields_3(#{[]=>y}),
+ false = has_map_fields_3(#{42.0=>x,a=>99}),
+ false = has_map_fields_3(#{}),
+
+ ok.
+
+has_map_fields_1(#{one:=_}) -> true;
+has_map_fields_1(#{}) -> false.
+
+has_map_fields_2(#{a:=_,b:=_,c:=_}) -> true;
+has_map_fields_2(#{}) -> false.
+
+has_map_fields_3(#{a:=_,b:=_}) -> true;
+has_map_fields_3(#{[]:=_,42.0:=_}) -> true;
+has_map_fields_3(#{}) -> false.
+
+y_regs(Config) when is_list(Config) ->
+ Val = [length(Config)],
+ Map0 = y_regs_update(#{}, Val),
+ Map2 = y_regs_update(Map0, Val),
+
+ Map3 = maps:from_list([{I,I*I} || I <- lists:seq(1, 100)]),
+ Map4 = y_regs_update(Map3, Val),
+
+ true = is_map(Map2) andalso is_map(Map4),
+
+ ok.
+
+y_regs_update(Map0, Val0) ->
+ Val1 = {t,Val0},
+ K1 = {key,1},
+ K2 = {key,2},
+ Map1 = Map0#{K1=>K1,
+ a=>Val0,b=>Val0,c=>Val0,d=>Val0,e=>Val0,
+ f=>Val0,g=>Val0,h=>Val0,i=>Val0,j=>Val0,
+ k=>Val0,l=>Val0,m=>Val0,n=>Val0,o=>Val0,
+ p=>Val0,q=>Val0,r=>Val0,s=>Val0,t=>Val0,
+ u=>Val0,v=>Val0,w=>Val0,x=>Val0,y=>Val0,
+ z=>Val0,
+ aa=>Val0,ab=>Val0,ac=>Val0,ad=>Val0,ae=>Val0,
+ af=>Val0,ag=>Val0,ah=>Val0,ai=>Val0,aj=>Val0,
+ ak=>Val0,al=>Val0,am=>Val0,an=>Val0,ao=>Val0,
+ ap=>Val0,aq=>Val0,ar=>Val0,as=>Val0,at=>Val0,
+ au=>Val0,av=>Val0,aw=>Val0,ax=>Val0,ay=>Val0,
+ az=>Val0,
+ K2=>[a,b,c]},
+ Map2 = Map1#{K1=>K1,
+ a:=Val1,b:=Val1,c:=Val1,d:=Val1,e:=Val1,
+ f:=Val1,g:=Val1,h:=Val1,i:=Val1,j:=Val1,
+ k:=Val1,l:=Val1,m:=Val1,n:=Val1,o:=Val1,
+ p:=Val1,q:=Val1,r:=Val1,s:=Val1,t:=Val1,
+ u:=Val1,v:=Val1,w:=Val1,x:=Val1,y:=Val1,
+ z:=Val1,
+ aa:=Val1,ab:=Val1,ac:=Val1,ad:=Val1,ae:=Val1,
+ af:=Val1,ag:=Val1,ah:=Val1,ai:=Val1,aj:=Val1,
+ ak:=Val1,al:=Val1,am:=Val1,an:=Val1,ao:=Val1,
+ ap:=Val1,aq:=Val1,ar:=Val1,as:=Val1,at:=Val1,
+ au:=Val1,av:=Val1,aw:=Val1,ax:=Val1,ay:=Val1,
+ az:=Val1,
+ K2=>[a,b,c]},
+
+ %% Traverse the maps to validate them.
+ _ = erlang:phash2({Map1,Map2}, 100000),
+
+ _ = {K1,K2,Val0,Val1}, %Force use of Y registers.
+ Map2.
+
+do_badmap(Test) ->
+ Terms = [Test,fun erlang:abs/1,make_ref(),self(),0.0/-1,
+ <<0:1024>>,<<1:1>>,<<>>,<<1,2,3>>,
+ [],{a,b,c},[a,b],atom,10.0,42,(1 bsl 65) + 3],
+ [Test(T) || T <- Terms].
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/order.erl b/lib/dialyzer/test/indent_SUITE_data/src/order.erl
new file mode 100644
index 0000000000..51868d7e94
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/order.erl
@@ -0,0 +1,56 @@
+-module(order).
+
+-export([t1/0, t2/0, t3/0, t4/0, t5/0, t6/0]).
+
+t1() ->
+ case maps:get(a, #{a=>1, a=>b}) of
+ Int when is_integer(Int) -> fail;
+ Atom when is_atom(Atom) -> error(ok);
+ _Else -> fail
+ end.
+
+t2() ->
+ case maps:get(a, #{a=>id_1(1), a=>id_b(b)}) of
+ Int when is_integer(Int) -> fail;
+ Atom when is_atom(Atom) -> error(ok);
+ _Else -> fail
+ end.
+
+t3() ->
+ case maps:get(a, #{a=>id_1(1), id_a(a)=>id_b(b)}) of
+ Int when is_integer(Int) -> fail;
+ Atom when is_atom(Atom) -> error(ok);
+ _Else -> fail
+ end.
+
+t4() ->
+ case maps:get(a, #{a=>id_1(1), a_or_b()=>id_b(b)}) of
+ Int when is_integer(Int) -> ok;
+ Atom when is_atom(Atom) -> ok;
+ _Else -> fail
+ end.
+
+t5() ->
+ case maps:get(c, #{c=>id_1(1), a_or_b()=>id_b(b)}) of
+ Int when is_integer(Int) -> error(ok);
+ Atom when is_atom(Atom) -> fail;
+ _Else -> fail
+ end.
+
+t6() ->
+ case maps:get(a, #{a_or_b()=>id_1(1), id_a(a)=>id_b(b)}) of
+ Int when is_integer(Int) -> fail;
+ Atom when is_atom(Atom) -> error(ok);
+ _Else -> fail
+ end.
+
+id_1(X) -> X.
+
+id_a(X) -> X.
+
+id_b(X) -> X.
+
+any() -> binary_to_term(<<>>).
+
+-spec a_or_b() -> a | b.
+a_or_b() -> any().
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/queue_use.erl b/lib/dialyzer/test/indent_SUITE_data/src/queue_use.erl
new file mode 100644
index 0000000000..8d46bdb989
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/queue_use.erl
@@ -0,0 +1,65 @@
+-module(queue_use).
+
+-export([ok1/0, ok2/0]).
+-export([wrong1/0, wrong2/0, wrong3/0, wrong4/0, wrong5/0, wrong6/0, wrong7/0, wrong8/0]).
+
+ok1() ->
+ queue:is_empty(queue:new()).
+
+ok2() ->
+ Q0 = queue:new(),
+ Q1 = queue:in(42, Q0),
+ {{value, 42}, Q2} = queue:out(Q1),
+ queue:is_empty(Q2).
+
+%%--------------------------------------------------
+
+wrong1() ->
+ queue:is_empty({[],[]}).
+
+wrong2() ->
+ Q0 = {[],[]},
+ queue:in(42, Q0).
+
+wrong3() ->
+ Q0 = queue:new(),
+ Q1 = queue:in(42, Q0),
+ {[42],Q2} = Q1,
+ Q2.
+
+wrong4() ->
+ Q0 = queue:new(),
+ Q1 = queue:in(42, Q0),
+ Q1 =:= {[42],[]}.
+
+wrong5() ->
+ {F, _R} = queue:new(),
+ F.
+
+wrong6() ->
+ {{value, 42}, Q2} = queue:out({[42],[]}),
+ Q2.
+
+%%--------------------------------------------------
+
+-record(db, {p, q}).
+
+wrong7() ->
+ add_unique(42, #db{p = [], q = queue:new()}).
+
+add_unique(E, DB) ->
+ case is_in_queue(E, DB) of
+ true -> DB;
+ false -> DB#db{q = queue:in(E, DB#db.q)}
+ end.
+
+is_in_queue(P, #db{q = {L1,L2}}) ->
+ lists:member(P, L1) orelse lists:member(P, L2).
+
+%%--------------------------------------------------
+
+wrong8() ->
+ tuple_queue({42, gazonk}).
+
+tuple_queue({F, Q}) ->
+ queue:in(F, Q).
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/rec/rec_adt.erl b/lib/dialyzer/test/indent_SUITE_data/src/rec/rec_adt.erl
new file mode 100644
index 0000000000..f01cc5e519
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/rec/rec_adt.erl
@@ -0,0 +1,22 @@
+-module(rec_adt).
+
+-export([new/0, get_a/1, get_b/1, set_a/2, set_b/2]).
+
+-record(rec, {a :: atom(), b = 0 :: integer()}).
+
+-opaque rec() :: #rec{}.
+
+-spec new() -> rec().
+new() -> #rec{a = gazonk, b = 42}.
+
+-spec get_a(rec()) -> atom().
+get_a(#rec{a = A}) -> A.
+
+-spec get_b(rec()) -> integer().
+get_b(#rec{b = B}) -> B.
+
+-spec set_a(rec(), atom()) -> rec().
+set_a(R, A) -> R#rec{a = A}.
+
+-spec set_b(rec(), integer()) -> rec().
+set_b(R, B) -> R#rec{b = B}.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/rec/rec_use.erl b/lib/dialyzer/test/indent_SUITE_data/src/rec/rec_use.erl
new file mode 100644
index 0000000000..358e9f918c
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/rec/rec_use.erl
@@ -0,0 +1,30 @@
+-module(rec_use).
+
+-export([ok1/0, ok2/0, wrong1/0, wrong2/0, wrong3/0, wrong4/0]).
+
+ok1() ->
+ rec_adt:set_a(rec_adt:new(), foo).
+
+ok2() ->
+ R1 = rec_adt:new(),
+ B1 = rec_adt:get_b(R1),
+ R2 = rec_adt:set_b(R1, 42),
+ B2 = rec_adt:get_b(R2),
+ B1 =:= B2.
+
+wrong1() ->
+ case rec_adt:new() of
+ {rec, _, 42} -> weird1;
+ R when tuple_size(R) =:= 3 -> weird2
+ end.
+
+wrong2() ->
+ R = list_to_tuple([rec, a, 42]),
+ rec_adt:get_a(R).
+
+wrong3() ->
+ R = rec_adt:new(),
+ R =:= {rec, gazonk, 42}.
+
+wrong4() ->
+ tuple_size(rec_adt:new()).
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/record_construct.erl b/lib/dialyzer/test/indent_SUITE_data/src/record_construct.erl
new file mode 100644
index 0000000000..b250c6ee65
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/record_construct.erl
@@ -0,0 +1,21 @@
+-module(record_construct).
+-export([t_loc/0, t_opa/0, t_rem/0]).
+
+-record(r_loc, {a = gazonk :: integer(), b = 42 :: atom()}).
+
+t_loc() ->
+ #r_loc{}.
+
+-record(r_opa, {a :: atom(),
+ b = gb_sets:new() :: gb_sets:set(),
+ c = 42 :: boolean(),
+ d, % untyped on purpose
+ e = false :: boolean()}).
+
+t_opa() ->
+ #r_opa{}.
+
+-record(r_rem, {a = gazonk :: string()}).
+
+t_rem() ->
+ #r_rem{}.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/record_creation_diffs.erl b/lib/dialyzer/test/indent_SUITE_data/src/record_creation_diffs.erl
new file mode 100644
index 0000000000..e813459f8e
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/record_creation_diffs.erl
@@ -0,0 +1,11 @@
+-module(record_creation_diffs).
+
+-export([foo/1]).
+
+-record(bar, {
+ some_atom :: atom(),
+ some_list :: list()
+ }).
+
+foo(Input) ->
+ #bar{some_atom = Input, some_list = {this,is,a,tuple}}.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/record_match.erl b/lib/dialyzer/test/indent_SUITE_data/src/record_match.erl
new file mode 100644
index 0000000000..8e9b91937f
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/record_match.erl
@@ -0,0 +1,17 @@
+-module(record_match).
+
+-export([select/0]).
+
+-record(b_literal, {val}).
+-record(b_remote, {mod,name,arity}).
+-record(b_local, {name,arity}).
+
+-type b_remote() :: #b_remote{}.
+-type b_local() :: #b_local{}.
+
+-type argument() :: b_remote() | b_local().
+
+-record(b_set, {args=[] :: [argument()]}).
+
+select() ->
+ #b_set{args=[#b_remote{},#b_literal{}]}.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/record_pat.erl b/lib/dialyzer/test/indent_SUITE_data/src/record_pat.erl
new file mode 100644
index 0000000000..3308641571
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/record_pat.erl
@@ -0,0 +1,15 @@
+%%%-------------------------------------------------------------------
+%%% File : record_pat.erl
+%%% Author : Tobias Lindahl <>
+%%% Description : Emit warning if a pattern violates the record type
+%%%
+%%% Created : 21 Oct 2008 by Tobias Lindahl <>
+%%%-------------------------------------------------------------------
+-module(record_pat).
+
+-export([t/1]).
+
+-record(foo, {bar :: integer()}).
+
+t(#foo{bar=baz}) -> no_way;
+t(#foo{bar=1}) -> ok.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/record_send_test.erl b/lib/dialyzer/test/indent_SUITE_data/src/record_send_test.erl
new file mode 100644
index 0000000000..87cd97bd85
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/record_send_test.erl
@@ -0,0 +1,32 @@
+%%-------------------------------------------------------------------
+%% File : record_send_test.erl
+%% Author : Kostis Sagonas <[email protected]>
+%% Description : A test inspired by a post of Mkcael Remond to the
+%% Erlang mailing list suggesting thst Dialyzer should
+%% be reporting sends to records rather than to pids.
+%% Dialyzer v1.3.0 indeed reports one of the dicrepancies
+%% (the one with the 4-tuple) but not the one where the
+%% message is sent to a pair which is a record.
+%% This should be fixed.
+%%
+%% Created : 10 Apr 2005 by Kostis Sagonas <[email protected]>
+%%-------------------------------------------------------------------
+-module(record_send_test).
+
+-export([t/0]).
+
+-record(rec1, {a=a, b=b, c=c}).
+-record(rec2, {a}).
+
+t() ->
+ t(#rec1{}).
+
+t(Rec1 = #rec1{b=B}) ->
+ Rec2 = some_mod:some_function(),
+ if
+ is_record(Rec2, rec2) ->
+ Rec2 ! hello; %% currently this one is not found
+ true ->
+ Rec1 ! hello_again
+ end,
+ B.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/record_test.erl b/lib/dialyzer/test/indent_SUITE_data/src/record_test.erl
new file mode 100644
index 0000000000..48a00b172e
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/record_test.erl
@@ -0,0 +1,22 @@
+%%%-------------------------------------------------------------------
+%%% File : record_test.erl
+%%% Author : Tobias Lindahl <[email protected]>
+%%% Description :
+%%%
+%%% Created : 22 Oct 2004 by Tobias Lindahl <[email protected]>
+%%%-------------------------------------------------------------------
+-module(record_test).
+
+-export([t/0]).
+
+-record(foo, {bar}).
+
+t() ->
+ doit(foo).
+
+doit(X) ->
+ case X of
+ #foo{} -> error1;
+ foo -> ok;
+ _ -> error2
+ end.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/record_update.erl b/lib/dialyzer/test/indent_SUITE_data/src/record_update.erl
new file mode 100644
index 0000000000..bad7a0a929
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/record_update.erl
@@ -0,0 +1,10 @@
+-module(record_update).
+
+-export([quux/2]).
+
+-record(foo, {bar :: atom()}).
+
+-spec quux(#foo{}, string()) -> #foo{}.
+
+quux(Foo, NotBar) ->
+ Foo#foo{ bar = NotBar }.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/sample_behaviour/sample_behaviour.erl b/lib/dialyzer/test/indent_SUITE_data/src/sample_behaviour/sample_behaviour.erl
new file mode 100644
index 0000000000..116980986b
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/sample_behaviour/sample_behaviour.erl
@@ -0,0 +1,13 @@
+-module(sample_behaviour).
+
+-type custom() :: 1..42.
+
+-callback sample_callback_1() -> term().
+-callback sample_callback_2() -> atom().
+-callback sample_callback_3() -> {'ok', custom()} | 'fail'.
+
+-callback sample_callback_4(term()) -> 'ok'.
+-callback sample_callback_5(custom()) -> 'ok' | 'fail'.
+
+-callback sample_callback_6(custom(), custom(), string()) ->
+ {'ok', custom()} | 'fail'.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/sample_behaviour/sample_callback_correct.erl b/lib/dialyzer/test/indent_SUITE_data/src/sample_behaviour/sample_callback_correct.erl
new file mode 100644
index 0000000000..ab0378e6f0
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/sample_behaviour/sample_callback_correct.erl
@@ -0,0 +1,32 @@
+-module(sample_callback_correct).
+
+-behaviour(sample_behaviour).
+
+-export([
+ sample_callback_1/0,
+ sample_callback_2/0,
+ sample_callback_3/0,
+ sample_callback_4/1,
+ sample_callback_5/1,
+ sample_callback_6/3
+ ]).
+
+sample_callback_1() -> 42. % This is a valid return.
+sample_callback_2() -> foo. % This is a valid return.
+sample_callback_3() -> {ok, 17}. % This is a valid return.
+sample_callback_4(Input) ->
+ put(mine, Input+1), % This is valid handling of the input
+ ok. % This is a valid return.
+sample_callback_5(Input) ->
+ case Input - 1 < 22 of % This is valid handling of the input
+ true -> ok; % This is a valid return.
+ false -> fail % This is a valid return.
+ end.
+sample_callback_6(OldNr, NewNr, Reason) ->
+ Diff = NewNr - OldNr, % This is valid handling of the input
+ Msg = string:join(["Reason: ", Reason], ","), % This is valid handling of the input
+ case Diff > 0 of
+ true -> put(mine, {NewNr, Msg}),
+ {ok, NewNr}; % This is a valid return.
+ false -> fail % This is a valid return.
+ end.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/sample_behaviour/sample_callback_correct_2.erl b/lib/dialyzer/test/indent_SUITE_data/src/sample_behaviour/sample_callback_correct_2.erl
new file mode 100644
index 0000000000..c218174e58
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/sample_behaviour/sample_callback_correct_2.erl
@@ -0,0 +1,38 @@
+-module(sample_callback_correct_2).
+
+-behaviour(sample_behaviour).
+
+-export([
+ sample_callback_1/0,
+ sample_callback_2/0,
+ sample_callback_3/0,
+ sample_callback_4/1,
+ sample_callback_5/1,
+ sample_callback_6/3,
+ common_infrastructure/1
+ ]).
+
+sample_callback_1() -> 42. % This is a valid return.
+sample_callback_2() -> halt(). % Crashes are also allowed.
+sample_callback_3() -> {ok, 17}. % This is a valid return.
+sample_callback_4(Input) ->
+ case Input of
+ 1 -> common_infrastructure(Input); % This is 'correct' input for
+ _ -> ok % common_infrastructure.
+ end.
+sample_callback_5(Input) ->
+ case get(Input) of % This is valid handling of a more generic input
+ true -> ok; % This is a valid return.
+ false -> fail % This is a valid return.
+ end.
+sample_callback_6(OldNr, NewNr, Reason) ->
+ Diff = NewNr - OldNr, % This is valid handling of the input
+ Msg = string:join(["Reason: ", Reason], ","), % This is valid handling of the input
+ case Diff > 0 of
+ true -> put(mine, {NewNr, Msg}),
+ {ok, NewNr}; % This is a valid return.
+ false -> fail % This is a valid return.
+ end.
+
+common_infrastructure( 1) -> 'ok';
+common_infrastructure(42) -> 'fail'.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/sample_behaviour/sample_callback_wrong.erl b/lib/dialyzer/test/indent_SUITE_data/src/sample_behaviour/sample_callback_wrong.erl
new file mode 100644
index 0000000000..430494c48c
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/sample_behaviour/sample_callback_wrong.erl
@@ -0,0 +1,26 @@
+-module(sample_callback_wrong).
+
+%% This attribute uses the american spelling of 'behaviour'.
+-behavior(sample_behaviour).
+
+-export([
+% sample_callback_1/0,
+ sample_callback_2/0,
+ sample_callback_3/0,
+ sample_callback_4/1,
+ sample_callback_5/1,
+ sample_callback_6/3
+ ]).
+
+% sample_callback_1() -> 41. % We can't really break this contract so: missing!
+sample_callback_2() -> 42. % This is not an atom().
+sample_callback_3() -> fair. % This is probably a typo.
+sample_callback_4(_) -> % We cannot break the input.
+ fail. % We can definitely return a wrong value however. :)
+sample_callback_5(Input) -> % Input is treated as an atom, result is a list.
+ atom_to_list(Input). % Both violate the contract.
+sample_callback_6(OldNr, NewNr, Reason) ->
+ Diff = NewNr - OldNr, % This is valid handling of the input
+ %% Reason should have been treated as a string.
+ Msg = string:join(["Reason: ", atom_to_list(Reason)], ","),
+ {okk, NewNr}. %% This, too, is a typo.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/simple/exact_adt.erl b/lib/dialyzer/test/indent_SUITE_data/src/simple/exact_adt.erl
new file mode 100644
index 0000000000..7103847ae7
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/simple/exact_adt.erl
@@ -0,0 +1,17 @@
+-module(exact_adt).
+
+-export([exact_adt_set_type/1, exact_adt_set_type2/1]).
+
+-export_type([exact_adt/0]).
+
+-record(exact_adt, {}).
+
+-opaque exact_adt() :: #exact_adt{}.
+
+-spec exact_adt_set_type(_) -> exact_adt().
+
+exact_adt_set_type(G) -> G.
+
+-spec exact_adt_set_type2(exact_adt()) -> exact_adt().
+
+exact_adt_set_type2(G) -> G.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/simple/exact_api.erl b/lib/dialyzer/test/indent_SUITE_data/src/simple/exact_api.erl
new file mode 100644
index 0000000000..597460ce77
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/simple/exact_api.erl
@@ -0,0 +1,60 @@
+-module(exact_api).
+
+-export([new/0, exact_api_test/1, exact_api_new/1,
+ exact_adt_test/1, exact_adt_new/1]).
+
+-export_type([exact_api/0]).
+
+-record(digraph, {vtab = notable :: ets:tab(),
+ etab = notable :: ets:tab(),
+ ntab = notable :: ets:tab(),
+ cyclic = true :: boolean()}).
+
+-spec new() -> digraph:graph().
+
+new() ->
+ A = #digraph{},
+ set_type(A), % does not have an opaque term as 1st argument
+ A.
+
+-spec set_type(digraph:graph()) -> true.
+
+set_type(G) ->
+ digraph:delete(G).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%% The derived spec of exact_api_new() is
+%%% -spec exact_api_new(exact_api:exact_api()) -> exact_api:exact_api().
+%%% This won't happen unless dialyzer_typesig uses
+%%% t_is_exactly_equal() rather than t_is_equal().
+%%% [As of R17B the latter considers two types equal if nothing but
+%%% their ?opaque tags differ.]
+
+-record(exact_api, {}).
+
+-opaque exact_api() :: #exact_api{}.
+
+exact_api_test(X) ->
+ #exact_api{} = exact_api_set_type(X). % OK
+
+exact_api_new(A) ->
+ A = #exact_api{},
+ _ = exact_api_set_type(A), % OK (the opaque type is local)
+ A.
+
+-spec exact_api_set_type(exact_api()) -> exact_api().
+
+exact_api_set_type(#exact_api{}=E) -> E.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-record(exact_adt, {}).
+
+exact_adt_test(X) ->
+ #exact_adt{} = exact_adt:exact_adt_set_type(X). % breaks the opacity
+
+exact_adt_new(A) ->
+ A = #exact_adt{},
+ _ = exact_adt:exact_adt_set_type2(A), % does not have an opaque term as 1st argument
+ A.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/simple/is_rec.erl b/lib/dialyzer/test/indent_SUITE_data/src/simple/is_rec.erl
new file mode 100644
index 0000000000..b906431b44
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/simple/is_rec.erl
@@ -0,0 +1,65 @@
+-module(is_rec).
+
+-export([ri1/0, ri11/0, ri13/0, ri14/0, ri2/0, ri3/0, ri4/0, ri5/0,
+ ri6/0, ri7/0, ri8/0]).
+
+-record(r, {f1 :: integer()}).
+
+ri1() ->
+ A = simple1_adt:d1(),
+ is_record(A, r). % opaque term 1
+
+ri11() ->
+ A = simple1_adt:d1(),
+ I = '1-3'(),
+ is_record(A, r, I). % opaque term 1
+
+ri13() ->
+ A = simple1_adt:d1(),
+ if is_record(A, r) -> true end. % breaks the opacity
+
+ri14() ->
+ A = simple1_adt:d1(),
+ if is_record({A, 1}, r) -> true end. % breaks the opacity
+
+-type '1-3-t'() :: 1..3.
+
+-spec '1-3'() -> '1-3-t'().
+
+'1-3'() ->
+ random:uniform(3).
+
+
+-spec 'Atom'() -> atom().
+
+'Atom'() ->
+ a.
+
+ri2() ->
+ A = simple1_adt:d1(),
+ R = 'Atom'(),
+ is_record(A, R). % opaque term 1
+
+ri3() ->
+ A = simple1_adt:d1(),
+ is_record(A, A, 1). % opaque term 2
+
+ri4() ->
+ A = simple1_adt:d1(),
+ is_record(A, hipp:hopp(), 1). % opaque term 1
+
+ri5() ->
+ A = simple1_adt:d1(),
+ is_record(A, A, hipp:hopp()). % opaque term 2
+
+ri6() ->
+ A = simple1_adt:d1(),
+ if is_record(A, r) -> true end. % breaks opacity
+
+ri7() ->
+ A = simple1_adt:d1(),
+ if is_record({r, A}, r) -> true end. % A violates #r{}
+
+ri8() ->
+ A = simple1_adt:d1(),
+ is_record({A, 1}, r). % opaque term 1
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/simple/rec_adt.erl b/lib/dialyzer/test/indent_SUITE_data/src/simple/rec_adt.erl
new file mode 100644
index 0000000000..ff80d6e99b
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/simple/rec_adt.erl
@@ -0,0 +1,28 @@
+-module(rec_adt).
+
+-export([f/0, r1/0]).
+
+-export_type([r1/0]).
+
+-export_type([f/0, op_t/0, a/0]).
+
+-opaque a() :: a | b.
+
+-record(r1,
+ {f1 :: a()}).
+
+-opaque r1() :: #r1{}.
+
+-opaque f() :: fun((_) -> _).
+
+-opaque op_t() :: integer().
+
+-spec f() -> f().
+
+f() ->
+ fun(_) -> 3 end.
+
+-spec r1() -> r1().
+
+r1() ->
+ #r1{f1 = a}.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/simple/rec_api.erl b/lib/dialyzer/test/indent_SUITE_data/src/simple/rec_api.erl
new file mode 100644
index 0000000000..59b9e0fec4
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/simple/rec_api.erl
@@ -0,0 +1,123 @@
+-module(rec_api).
+
+-export([t1/0, t2/0, t3/0, adt_t1/0, adt_t1/1, adt_r1/0,
+ t/1, t_adt/0, r/0, r_adt/0, u1/0, u2/0, u3/0, v1/0, v2/0, v3/0]).
+
+-export_type([{a,0},{r1,0}, r2/0, r3/0]).
+
+-export_type([f/0, op_t/0, r/0, tup/0]).
+
+-opaque a() :: a | b.
+
+-record(r1,
+ {f1 :: a()}).
+
+-opaque r1() :: #r1{}.
+
+t1() ->
+ A = #r1{f1 = a},
+ {r1, a} = A.
+
+t2() ->
+ A = {r1, 10},
+ {r1, 10} = A,
+ A = #r1{f1 = 10}, % violates the type of field f1
+ #r1{f1 = 10} = A.
+
+t3() ->
+ A = {r1, 10},
+ #r1{f1 = 10} = A. % violates the type of #r1{}
+
+adt_t1() ->
+ R = rec_adt:r1(),
+ {r1, a} = R. % breaks the opacity
+
+-spec adt_t1(rec_adt:r1()) -> rec_adt:r1(). % invalid type spec
+
+adt_t1(R) ->
+ {r1, a} = R.
+
+-spec adt_r1() -> rec_adt:r1(). % invalid type spec
+
+adt_r1() ->
+ #r1{f1 = a}.
+
+-opaque f() :: fun((_) -> _).
+
+-opaque op_t() :: integer().
+
+-spec t(f()) -> _.
+
+t(A) ->
+ T = term(),
+ %% 3(T), % cannot test this: dialyzer_dep deliberately crashes
+ A(T).
+
+-spec term() -> op_t().
+
+term() ->
+ 3.
+
+t_adt() ->
+ A = rec_adt:f(),
+ T = term(),
+ A(T).
+
+-record(r, {f = fun(_) -> 3 end :: f(), o = 1 :: op_t()}).
+
+-opaque r() :: #r{}.
+
+-opaque tup() :: {'r', f(), op_t()}.
+
+-spec r() -> _.
+
+r() ->
+ {{r, f(), 2},
+ #r{f = f(), o = 2}}. % OK, f() is a local opaque type
+
+-spec f() -> f().
+
+f() ->
+ fun(_) -> 3 end.
+
+r_adt() ->
+ {{r, rec_adt:f(), 2},
+ #r{f = rec_adt:f(), o = 2}}. % breaks the opacity
+
+-record(r2, % like #r1{}, but with initial value
+ {f1 = a :: a()}).
+
+-opaque r2() :: #r2{}.
+
+u1() ->
+ A = #r2{f1 = a},
+ {r2, a} = A.
+
+u2() ->
+ A = {r2, 10},
+ {r2, 10} = A,
+ A = #r2{f1 = 10}, % violates the type of field f1
+ #r2{f1 = 10} = A.
+
+u3() ->
+ A = {r2, 10},
+ #r2{f1 = 10} = A. % violates the type of #r2{}
+
+-record(r3, % like #r1{}, but an opaque type
+ {f1 = queue:new():: queue:queue()}).
+
+-opaque r3() :: #r3{}.
+
+v1() ->
+ A = #r3{f1 = queue:new()},
+ {r3, a} = A. % breaks the opacity
+
+v2() ->
+ A = {r3, 10},
+ {r3, 10} = A,
+ A = #r3{f1 = 10}, % violates the type of field f1
+ #r3{f1 = 10} = A.
+
+v3() ->
+ A = {r3, 10},
+ #r3{f1 = 10} = A. % breaks the opacity
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/simple/simple1_adt.erl b/lib/dialyzer/test/indent_SUITE_data/src/simple/simple1_adt.erl
new file mode 100644
index 0000000000..21a277c1e9
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/simple/simple1_adt.erl
@@ -0,0 +1,138 @@
+-module(simple1_adt).
+
+-export([d1/0, d2/0, i/0, n1/0, n2/0, o1/0, o2/0,
+ c1/0, c2/0, bit1/0, a/0, i1/0, tuple/0,
+ b1/0, b2/0, ty_i1/0]).
+
+-export_type([o1/0, o2/0, d1/0, d2/0]).
+
+-export_type([i1/0, i2/0, di1/0, di2/0]).
+
+-export_type([ty_i1/0, c1/0, c2/0]).
+
+-export_type([b1/0, b2/0]).
+
+-export_type([bit1/0]).
+
+-export_type([tuple1/0, a/0, i/0]).
+
+%% Equal:
+
+-opaque o1() :: a | b | c.
+
+-opaque o2() :: a | b | c.
+
+%% Disjoint:
+
+-opaque d1() :: a | b | c.
+
+-opaque d2() :: d | e | f.
+
+%% One common element:
+
+-opaque c1() :: a | b | c.
+
+-opaque c2() :: c | e | f.
+
+%% Equal integer range:
+
+-opaque i1() :: 1 | 2.
+
+-opaque i2() :: 1 | 2.
+
+%% Disjoint integer range:
+
+-opaque di1() :: 1 | 2.
+
+-opaque di2() :: 3 | 4.
+
+
+-type ty_i1() :: 1 | 2.
+
+%% Boolean types
+
+-opaque b1() :: boolean().
+
+-opaque b2() :: boolean().
+
+%% Binary types
+
+-opaque bit1() :: binary().
+
+%% Tuple types
+
+-opaque tuple1() :: tuple().
+
+%% Atom type
+
+-opaque a() :: atom().
+
+-opaque i() :: integer().
+
+-spec d1() -> d1().
+
+d1() -> a.
+
+-spec d2() -> d2().
+
+d2() -> d.
+
+-spec i() -> i().
+
+i() ->
+ 1.
+
+-spec n1() -> o1().
+
+n1() -> a.
+
+-spec n2() -> o2().
+
+n2() -> a.
+
+-spec o1() -> o1().
+
+o1() -> a.
+
+-spec o2() -> o2().
+
+o2() -> a.
+
+-spec c1() -> c1().
+
+c1() -> a.
+
+-spec c2() -> c2().
+
+c2() -> e.
+
+-spec bit1() -> bit1().
+
+bit1() ->
+ <<"hej">>.
+
+-spec a() -> a().
+
+a() ->
+ e.
+
+-spec i1() -> i1().
+
+i1() -> 1.
+
+-spec tuple() -> tuple1().
+
+tuple() -> {1,2}.
+
+-spec b1() -> b1().
+
+b1() -> true.
+
+-spec b2() -> b2().
+
+b2() -> false.
+
+-spec ty_i1() -> ty_i1().
+
+ty_i1() ->
+ 1.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/simple/simple1_api.erl b/lib/dialyzer/test/indent_SUITE_data/src/simple/simple1_api.erl
new file mode 100644
index 0000000000..d67aa913d8
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/simple/simple1_api.erl
@@ -0,0 +1,571 @@
+-module(simple1_api).
+
+-export([t1/1, adt_t1/1, t2/1, adt_t2/1, tup/0, t3/0, t4/0, t5/0, t6/0, t7/0,
+ t8/0, adt_t3/0, adt_t4/0, adt_t7/0, adt_t8/0, adt_t5/0,
+ c1/2, c2/2, c2/0, c3/0, c4/0, tt1/0, tt2/0,
+ cmp1/0, cmp2/0, cmp3/0, cmp4/0,
+ ty_cmp1/0, ty_cmp2/0, ty_cmp3/0, ty_cmp4/0,
+ f1/0, f2/0, adt_f1/0, adt_f2/0, f3/0, f4/0, adt_f3/0, adt_f4/0,
+ adt_f4_a/0, adt_f4_b/0,
+ bool_t1/0, bool_t2/0, bool_t3/0, bool_t4/0, bool_t5/1, bool_t6/1,
+ bool_t7/0, bool_adt_t1/0, bool_adt_t2/0, bool_adt_t5/1,
+ bool_adt_t6/1, bool_t8/0, bool_adt_t8/2, bool_t9/0, bool_adt_t9/2,
+ bit_t1/0, bit_adt_t1/0, bit_t3/1, bit_adt_t2/0, bit_adt_t3/1,
+ bit_t5/1, bit_t4/1, bit_adt_t4/1, bit_t5/0, bit_adt_t5/0,
+ call_f/1, call_f_adt/1, call_m_adt/1, call_m/1, call_f_i/1,
+ call_m_i/1, call_m_adt_i/1, call_f_adt_i/1,
+ eq1/0, eq2/0, c5/0, c6/2, c7/2, c8/0]).
+
+%%% Equal opaque types
+
+-export_type([o1/0, o2/0]).
+
+-export_type([d1/0, d2/0]).
+
+-opaque o1() :: a | b | c.
+
+-opaque o2() :: a | b | c.
+
+-export_type([i1/0, i2/0, di1/0, di2/0]).
+
+-export_type([b1/0, b2/0]).
+
+-export_type([bit1/0]).
+
+-export_type([a/0, i/0]).
+
+%% The derived spec is
+%% -spec t1('a' | 'b') -> simple1_api:o1('a') | simple1_api:o2('a').
+%% but that is not tested...
+
+t1(a) ->
+ o1();
+t1(b) ->
+ o2().
+
+-spec o1() -> o1().
+
+o1() -> a.
+
+-spec o2() -> o2().
+
+o2() -> a.
+
+%% The derived spec is
+%% -spec adt_t1('a' | 'b') -> simple1_adt:o1('a') | simple1_adt:o2('a').
+%% but that is not tested...
+
+adt_t1(a) ->
+ simple1_adt:o1();
+adt_t1(b) ->
+ simple1_adt:o2().
+
+%%% Disjunct opaque types
+
+-opaque d1() :: a | b | c.
+
+-opaque d2() :: d | e | f.
+
+%% -spec t2('a' | 'b') -> simple1_api:d1('a') | simple1_api:d2('d').
+
+t2(a) ->
+ d1();
+t2(b) ->
+ d2().
+
+-spec d1() -> d1().
+
+d1() -> a.
+
+-spec d2() -> d2().
+
+d2() -> d.
+
+%% -spec adt_t2('a' | 'b') -> simple1_adt:d1('a') | simple1_adt:d2('d').
+
+adt_t2(a) ->
+ simple1_adt:d1();
+adt_t2(b) ->
+ simple1_adt:d2().
+
+-spec tup() -> simple1_adt:tuple1(). % invalid type spec
+
+tup() ->
+ {a, b}.
+
+%%% Matching equal opaque types with different names
+
+t3() ->
+ A = n1(),
+ B = n2(),
+ A = A, % OK, of course
+ A = B. % OK since o1() and o2() are local opaque types
+
+t4() ->
+ A = n1(),
+ B = n2(),
+ true = A =:= A, % OK, of course
+ A =:= B. % OK since o1() and o2() are local opaque types
+
+t5() ->
+ A = d1(),
+ B = d2(),
+ A =:= B. % can never evaluate to true
+
+t6() ->
+ A = d1(),
+ B = d2(),
+ A = B. % can never succeed
+
+t7() ->
+ A = d1(),
+ B = d2(),
+ A =/= B. % OK (always true?)
+
+t8() ->
+ A = d1(),
+ B = d2(),
+ A /= B. % OK (always true?)
+
+-spec n1() -> o1().
+
+n1() -> a.
+
+-spec n2() -> o2().
+
+n2() -> a.
+
+adt_t3() ->
+ A = simple1_adt:n1(),
+ B = simple1_adt:n2(),
+ true = A =:= A, % OK.
+ A =:= B. % opaque test, not OK
+
+adt_t4() ->
+ A = simple1_adt:n1(),
+ B = simple1_adt:n2(),
+ A = A, % OK
+ A = B. % opaque terms
+
+adt_t7() ->
+ A = simple1_adt:n1(),
+ B = simple1_adt:n2(),
+ false = A =/= A, % OK
+ A =/= B. % opaque test, not OK
+
+adt_t8() ->
+ A = simple1_adt:n1(),
+ B = simple1_adt:n2(),
+ false = A /= A, % OK
+ A /= B. % opaque test, not OK
+
+adt_t5() ->
+ A = simple1_adt:c1(),
+ B = simple1_adt:c2(),
+ A =:= B. % opaque test, not OK
+
+%% Comparison in guard
+
+-spec c1(simple1_adt:d1(), simple1_adt:d2()) -> boolean().
+
+c1(A, B) when A =< B -> true. % succ type of A and B is any() (type spec is OK)
+
+-spec c2(simple1_adt:d1(), simple1_adt:d2()) -> boolean().
+
+c2(A, B) ->
+ if A =< B -> true end. % succ type of A and B is any() (type spec is OK)
+
+c2() ->
+ A = simple1_adt:d1(),
+ B = simple1_adt:d2(),
+ if A =< B -> ok end. % opaque terms
+
+c3() ->
+ B = simple1_adt:d2(),
+ if a =< B -> ok end. % opaque term
+
+c4() ->
+ A = simple1_adt:d1(),
+ if A =< d -> ok end. % opaque term
+
+tt1() ->
+ A = o1(),
+ is_integer(A). % OK
+
+tt2() ->
+ A = simple1_adt:d1(),
+ is_integer(A). % breaks the opacity
+
+%% Comparison with integers
+
+-opaque i1() :: 1 | 2.
+
+-opaque i2() :: 1 | 2.
+
+-opaque di1() :: 1 | 2.
+
+-opaque di2() :: 3 | 4.
+
+-spec i1() -> i1().
+
+i1() -> 1.
+
+-type ty_i1() :: 1 | 2.
+
+-spec ty_i1() -> ty_i1().
+
+ty_i1() -> 1.
+
+cmp1() ->
+ A = i1(),
+ if A > 3 -> ok end. % can never succeed
+
+cmp2() ->
+ A = simple1_adt:i1(),
+ if A > 3 -> ok end. % opaque term
+
+cmp3() ->
+ A = i1(),
+ if A < 3 -> ok end.
+
+cmp4() ->
+ A = simple1_adt:i1(),
+ if A < 3 -> ok end. % opaque term
+
+%% -type
+
+ty_cmp1() ->
+ A = ty_i1(),
+ if A > 3 -> ok end. % can never succeed
+
+ty_cmp2() ->
+ A = simple1_adt:ty_i1(),
+ if A > 3 -> ok end. % can never succeed
+
+ty_cmp3() ->
+ A = ty_i1(),
+ if A < 3 -> ok end.
+
+ty_cmp4() ->
+ A = simple1_adt:ty_i1(),
+ if A < 3 -> ok end.
+
+%% is_function
+
+f1() ->
+ T = n1(),
+ if is_function(T) -> ok end. % can never succeed
+
+f2() ->
+ T = n1(),
+ is_function(T). % ok
+
+adt_f1() ->
+ T = simple1_adt:n1(),
+ if is_function(T) -> ok end. % breaks the opacity
+
+adt_f2() ->
+ T = simple1_adt:n1(),
+ is_function(T). % breaks the opacity
+
+f3() ->
+ A = i1(),
+ T = n1(),
+ if is_function(T, A) -> ok end. % can never succeed
+
+f4() ->
+ A = i1(),
+ T = n1(),
+ is_function(T, A). % ok
+
+adt_f3() ->
+ A = simple1_adt:i1(),
+ T = simple1_adt:n1(),
+ if is_function(T, A) -> ok end. % breaks the opacity
+
+adt_f4() ->
+ A = simple1_adt:i1(),
+ T = simple1_adt:n1(),
+ is_function(T, A). % breaks the opacity
+
+adt_f4_a() ->
+ A = simple1_adt:i1(),
+ T = n1(),
+ is_function(T, A). % opaque term
+
+
+adt_f4_b() ->
+ A = i1(),
+ T = simple1_adt:n1(),
+ is_function(T, A). % breaks the opacity
+
+%% A few Boolean examples
+
+bool_t1() ->
+ B = b2(),
+ if B -> ok end. % B =:= true can never succeed
+
+bool_t2() ->
+ A = b1(),
+ B = b2(),
+ if A and not B -> ok end.
+
+bool_t3() ->
+ A = b1(),
+ if not A -> ok end. % can never succeed
+
+bool_t4() ->
+ A = n1(),
+ if not ((A >= 1) and not (A < 1)) -> ok end. % can never succeed
+
+-spec bool_t5(i1()) -> integer().
+
+bool_t5(A) ->
+ if [not (A > 1)] =:=
+ [false]-> 1 end.
+
+-spec bool_t6(b1()) -> integer().
+
+bool_t6(A) ->
+ if [not A] =:=
+ [false]-> 1 end.
+
+-spec bool_t7() -> integer().
+
+bool_t7() ->
+ A = i1(),
+ if [not A] =:= % cannot succeed
+ [false]-> 1 end.
+
+bool_adt_t1() ->
+ B = simple1_adt:b2(),
+ if B -> ok end. % opaque term
+
+bool_adt_t2() ->
+ A = simple1_adt:b1(),
+ B = simple1_adt:b2(),
+ if A and not B -> ok end. % opaque term
+
+-spec bool_adt_t5(simple1_adt:i1()) -> integer().
+
+bool_adt_t5(A) ->
+ if [not (A > 1)] =:= % succ type of A is any() (type spec is OK)
+ [false]-> 1 end.
+
+-spec bool_adt_t6(simple1_adt:b1()) -> integer(). % invalid type spec
+
+bool_adt_t6(A) ->
+ if [not A] =:= % succ type of A is 'true'
+ [false]-> 1 end.
+
+-spec bool_t8() -> integer().
+
+bool_t8() ->
+ A = i1(),
+ if [A and A] =:= % cannot succeed
+ [false]-> 1 end.
+
+-spec bool_adt_t8(simple1_adt:b1(), simple1_adt:b2()) -> integer(). % invalid
+
+bool_adt_t8(A, B) ->
+ if [A and B] =:=
+ [false]-> 1 end.
+
+-spec bool_t9() -> integer().
+
+bool_t9() ->
+ A = i1(),
+ if [A or A] =:= % cannot succeed
+ [false]-> 1 end.
+
+-spec bool_adt_t9(simple1_adt:b1(), simple1_adt:b2()) -> integer(). % invalid
+
+bool_adt_t9(A, B) ->
+ if [A or B] =:=
+ [false]-> 1 end.
+
+-opaque b1() :: boolean().
+
+-opaque b2() :: boolean().
+
+-spec b1() -> b1().
+
+b1() -> true.
+
+-spec b2() -> b2().
+
+b2() -> false.
+
+%% Few (very few...) examples with bit syntax
+
+bit_t1() ->
+ A = i1(),
+ <<100:(A)>>.
+
+bit_adt_t1() ->
+ A = simple1_adt:i1(),
+ <<100:(A)>>. % breaks the opacity
+
+bit_t3(A) ->
+ B = i1(),
+ case none:none() of
+ <<A:B>> -> 1
+ end.
+
+bit_adt_t2() ->
+ A = simple1_adt:i1(),
+ case <<"hej">> of
+ <<_:A>> -> ok % breaks the opacity (but the message is strange)
+ end.
+
+
+bit_adt_t3(A) ->
+ B = simple1_adt:i1(),
+ case none:none() of
+ <<A: % breaks the opacity (the message is less than perfect)
+ B>> -> 1
+ end.
+
+bit_t5(A) ->
+ B = o1(),
+ case none:none() of % the type is any(); should fix that XXX
+ <<A:B>> -> 1 % can never match (local opaque type is OK)
+ end.
+
+-spec bit_t4(<<_:1>>) -> integer().
+
+bit_t4(A) ->
+ Sz = i1(),
+ case A of
+ <<_:Sz>> -> 1
+ end.
+
+-spec bit_adt_t4(<<_:1>>) -> integer().
+
+bit_adt_t4(A) ->
+ Sz = simple1_adt:i1(),
+ case A of
+ <<_:Sz>> -> 1 % breaks the opacity
+ end.
+
+bit_t5() ->
+ A = bit1(),
+ case A of
+ <<_/binary>> -> 1
+ end.
+
+bit_adt_t5() ->
+ A = simple1_adt:bit1(),
+ case A of
+ <<_/binary>> -> 1 % breaks the opacity
+ end.
+
+-opaque bit1() :: binary().
+
+-spec bit1() -> bit1().
+
+bit1() ->
+ <<"hej">>.
+
+%% Calls with variable module or function
+
+call_f(A) ->
+ A = a(),
+ foo:A(A).
+
+call_f_adt(A) ->
+ A = simple1_adt:a(),
+ foo:A(A). % breaks the opacity
+
+call_m(A) ->
+ A = a(),
+ A:foo(A).
+
+call_m_adt(A) ->
+ A = simple1_adt:a(),
+ A:foo(A). % breaks the opacity
+
+-opaque a() :: atom().
+
+-opaque i() :: integer().
+
+-spec a() -> a().
+
+a() ->
+ e.
+
+call_f_i(A) ->
+ A = i(),
+ foo:A(A). % A is not atom() but i()
+
+call_f_adt_i(A) ->
+ A = simple1_adt:i(),
+ foo:A(A). % A is not atom() but simple1_adt:i()
+
+call_m_i(A) ->
+ A = i(),
+ A:foo(A). % A is not atom() but i()
+
+call_m_adt_i(A) ->
+ A = simple1_adt:i(),
+ A:foo(A). % A is not atom() but simple1_adt:i()
+
+-spec eq1() -> integer().
+
+eq1() ->
+ A = simple1_adt:d2(),
+ B = simple1_adt:d1(),
+ if
+ A == B -> % opaque terms
+ 0;
+ A == A ->
+ 1;
+ A =:= A -> % compiler finds this one cannot match
+ 2;
+ true -> % compiler finds this one cannot match
+ 3
+ end.
+
+eq2() ->
+ A = simple1_adt:d1(),
+ if
+ {A} >= {A} ->
+ 1;
+ A >= 3 -> % opaque term
+ 2;
+ A == 3 -> % opaque term
+ 3;
+ A =:= 3 -> % opaque term
+ 4;
+ A == A ->
+ 5;
+ A =:= A -> % compiler finds this one cannot match
+ 6
+ end.
+
+c5() ->
+ A = simple1_adt:d1(),
+ A < 3. % opaque term
+
+c6(A, B) ->
+ A = simple1_adt:d1(),
+ B = simple1_adt:d1(),
+ A =< B. % same type - no warning
+
+c7(A, B) ->
+ A = simple1_adt:d1(),
+ B = simple1_adt:d2(),
+ A =< B. % opaque terms
+
+c8() ->
+ D = digraph:new(),
+ E = ets:new(foo, []),
+ if {D, a} > {D, E} -> true; % OK
+ {1.0, 2} > {{D}, {E}} -> true; % OK
+ {D, 3} > {D, E} -> true % opaque term 2
+ end.
+
+-spec i() -> i().
+
+i() ->
+ 1.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/simple/simple2_api.erl b/lib/dialyzer/test/indent_SUITE_data/src/simple/simple2_api.erl
new file mode 100644
index 0000000000..c86f6fd0b5
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/simple/simple2_api.erl
@@ -0,0 +1,125 @@
+-module(simple2_api).
+
+-export([c1/2, c2/0, c3/0, c4/1, c5/1, c6/0, c6_b/0, c7/0, c7_b/0,
+ c7_c/0, c8/0, c9/0, c10/0, c11/0, c12/0, c13/0, c14/0, c15/0,
+ c16/0, c17/0, c18/0, c19/0, c20/0, c21/0, c22/0, c23/0,
+ c24/0, c25/0, c26/0]).
+
+-spec c1(simple1_adt:d1(), simple1_adt:d2()) -> boolean().
+
+c1(A, B) ->
+ {A} =< {B}. % succ type of A and B is any()
+
+c2() ->
+ A = simple1_adt:d1(),
+ erlang:make_tuple(1, A). % ok
+
+c3() ->
+ A = simple1_adt:d1(),
+ setelement(1, {A}, A). % ok
+
+c4(_) ->
+ A = simple1_adt:d1(),
+ halt(A). % ok (BIF fails...)
+
+c5(_) ->
+ A = simple1_adt:d1(),
+ [A] -- [A]. % ok
+
+c6() ->
+ A = simple1_adt:d1(),
+ A ! foo. % opaque term
+
+c6_b() ->
+ A = simple1_adt:d1(),
+ erlang:send(A, foo). % opaque term
+
+c7() ->
+ A = simple1_adt:d1(),
+ foo ! A. % ok
+
+c7_b() ->
+ A = simple1_adt:d1(),
+ erlang:send(foo, A). % ok
+
+c7_c() ->
+ A = simple1_adt:d1(),
+ erlang:send(foo, A, []). % ok
+
+c8() ->
+ A = simple1_adt:d1(),
+ A < 3. % opaque term
+
+c9() ->
+ A = simple1_adt:d1(),
+ lists:keysearch(A, 1, []). % ok
+
+c10() ->
+ A = simple1_adt:d1(),
+ lists:keysearch(1, A, []). % opaque term 2
+
+c11() ->
+ A = simple1_adt:tuple(),
+ lists:keysearch(key, 1, [A]). % ok
+
+c12() ->
+ A = simple1_adt:tuple(),
+ lists:keysearch(key, 1, A). % opaque term 3
+
+c13() ->
+ A = simple1_adt:tuple(),
+ lists:keysearch(key, 1, [{A,2}]). % ok
+
+c14() ->
+ A = simple1_adt:tuple(),
+ lists:keysearch(key, 1, [{2,A}]). % ok
+
+c15() ->
+ A = simple1_adt:d1(),
+ lists:keysearch(key, 1, [A]). % ok
+
+c16() ->
+ A = simple1_adt:tuple(),
+ erlang:send(foo, A). % ok
+
+c17() ->
+ A = simple1_adt:tuple(),
+ lists:reverse([A]). % ok
+
+c18() ->
+ A = simple1_adt:tuple(),
+ lists:keyreplace(a, 1, [A], {1,2}). % ok
+
+c19() ->
+ A = simple1_adt:tuple(),
+ %% Problem. The spec says argument 4 is a tuple(). Fix that!
+ lists:keyreplace(a, 1, [{1,2}], A). % opaque term 4
+
+c20() ->
+ A = simple1_adt:tuple(),
+ lists:flatten(A). % opaque term 1
+
+c21() ->
+ A = simple1_adt:tuple(),
+ lists:flatten([[{A}]]). % ok
+
+c22() ->
+ A = simple1_adt:tuple(),
+ lists:flatten([[A]]). % ok
+
+c23() ->
+ A = simple1_adt:tuple(),
+ lists:flatten([A]). % ok
+
+c24() ->
+ A = simple1_adt:tuple(),
+ lists:flatten({A}). % will never return
+
+c25() ->
+ A = simple1_adt:d1(),
+ B = simple1_adt:tuple(),
+ if {A,3} > {A,B} -> true end. % opaque 2nd argument
+
+c26() ->
+ B = simple1_adt:tuple(),
+ tuple_to_list(B). % opaque term 1
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/suppress_request.erl b/lib/dialyzer/test/indent_SUITE_data/src/suppress_request.erl
new file mode 100644
index 0000000000..c4275fa110
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/suppress_request.erl
@@ -0,0 +1,50 @@
+-module(suppress_request).
+
+-export([test1/1, test1_b/1, test2/0, test2_b/0,
+ test3/0, test3_b/0, test4/0, test4_b/0]).
+
+-dialyzer({[specdiffs], test1/1}).
+-spec test1(a | b) -> ok. % spec is subtype
+test1(A) ->
+ ok = test1_1(A).
+
+-spec test1_b(a | b) -> ok. % spec is subtype (suppressed by default)
+test1_b(A) ->
+ ok = test1_1(A).
+
+-spec test1_1(a | b | c) -> ok.
+test1_1(_) ->
+ ok.
+
+-dialyzer(unmatched_returns).
+test2() ->
+ tuple(), % unmatched
+ ok.
+
+test2_b() ->
+ tuple(), % unmatched
+ ok.
+
+-dialyzer({[no_return, no_match], [test3/0]}).
+test3() -> % no local return (suppressed)
+ A = fun(_) ->
+ 1
+ end,
+ A = 2. % can never succeed (suppressed)
+
+test3_b() -> % no local return (requested by default)
+ A = fun(_) ->
+ 1
+ end,
+ A = 2. % can never succeed (requested by default)
+
+-dialyzer(no_improper_lists).
+test4() ->
+ [1 | 2]. % improper list (suppressed)
+
+-dialyzer({no_improper_lists, test4_b/0}).
+test4_b() ->
+ [1 | 2]. % improper list (suppressed)
+
+tuple() ->
+ {a, b}.
diff --git a/lib/dialyzer/test/indent_SUITE_data/src/trec.erl b/lib/dialyzer/test/indent_SUITE_data/src/trec.erl
new file mode 100644
index 0000000000..516358f7c6
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/trec.erl
@@ -0,0 +1,39 @@
+%%
+%% The current treatment of typed records leaves much to be desired.
+%% These are not made up examples; I have cases like that the branch
+%% of the HiPE compiler with types in records. I get very confusing
+%% warnings which require a lot of effort to find their cause and why
+%% a function has no local return.
+%%
+-module(trec).
+-export([test/0, mk_foo_exp/2]).
+
+-record(foo, {a :: integer() | 'undefined', b :: [atom()]}).
+
+%%
+%% For these functions we currently get the following warnings:
+%% 1. Function test/0 has no local return
+%% 2. The call trec:mk_foo_loc(42,any()) will fail since it differs
+%% in argument position 1 from the success typing arguments:
+%% ('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 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, some_mod:some_function()).
+
+mk_foo_loc(A, B) ->
+ #foo{a = A, b = [A,B]}.
+
+%%
+%% 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/dialyzer/test/indent_SUITE_data/src/whereis_control_flow1.erl b/lib/dialyzer/test/indent_SUITE_data/src/whereis_control_flow1.erl
new file mode 100644
index 0000000000..e65f6c3e23
--- /dev/null
+++ b/lib/dialyzer/test/indent_SUITE_data/src/whereis_control_flow1.erl
@@ -0,0 +1,17 @@
+%% This tests the presence of possible races due to a whereis/register
+%% combination. It takes into account control flow that might exist.
+
+-module(whereis_control_flow1).
+-export([start/2]).
+
+start(AnAtom, Fun) ->
+ case whereis(AnAtom) of
+ undefined ->
+ Pid = spawn(Fun),
+ case Pid =:= self() of
+ true -> ok;
+ false -> register(AnAtom, Pid)
+ end;
+ P when is_pid(P) ->
+ ok
+ end.
diff --git a/lib/dialyzer/test/map_SUITE_data/dialyzer_options b/lib/dialyzer/test/map_SUITE_data/dialyzer_options
index 02425c33f2..1ddeb02c27 100644
--- a/lib/dialyzer/test/map_SUITE_data/dialyzer_options
+++ b/lib/dialyzer/test/map_SUITE_data/dialyzer_options
@@ -1,2 +1,2 @@
-{dialyzer_options, []}.
+{dialyzer_options, [{indent_opt, false}]}.
{time_limit, 30}.
diff --git a/lib/dialyzer/test/map_SUITE_data/results/contract b/lib/dialyzer/test/map_SUITE_data/results/contract
index 0f6e1d0c65..620ec8e6b1 100644
--- a/lib/dialyzer/test/map_SUITE_data/results/contract
+++ b/lib/dialyzer/test/map_SUITE_data/results/contract
@@ -1,7 +1,7 @@
contract.erl:10: Function t2/0 has no local return
-contract.erl:10: The call missing:f(#{'a':=1, 'c':=4}) breaks the contract (#{'a':=1,'b'=>2,'c'=>3}) -> 'ok'
+contract.erl:10: The call missing:f(#{'a'=>1, 'c'=>4}) breaks the contract (#{'a':=1,'b'=>2,'c'=>3}) -> 'ok'
contract.erl:12: Function t3/0 has no local return
-contract.erl:12: The call missing:f(#{'a':=1, 'b':=2, 'e':=3}) breaks the contract (#{'a':=1,'b'=>2,'c'=>3}) -> 'ok'
+contract.erl:12: The call missing:f(#{'a'=>1, 'b'=>2, 'e'=>3}) breaks the contract (#{'a':=1,'b'=>2,'c'=>3}) -> 'ok'
contract.erl:8: Function t1/0 has no local return
-contract.erl:8: The call missing:f(#{'b':=2}) breaks the contract (#{'a':=1,'b'=>2,'c'=>3}) -> 'ok'
+contract.erl:8: The call missing:f(#{'b'=>2}) breaks the contract (#{'a':=1,'b'=>2,'c'=>3}) -> 'ok'
diff --git a/lib/dialyzer/test/map_SUITE_data/results/guard_update b/lib/dialyzer/test/map_SUITE_data/results/guard_update
index 98df23907f..f6de2158fc 100644
--- a/lib/dialyzer/test/map_SUITE_data/results/guard_update
+++ b/lib/dialyzer/test/map_SUITE_data/results/guard_update
@@ -1,5 +1,5 @@
guard_update.erl:5: Function t/0 has no local return
-guard_update.erl:6: The call guard_update:f(#{'a':=2}) will never return since it differs in the 1st argument from the success typing arguments: (#{'b':=_, _=>_})
+guard_update.erl:6: The call guard_update:f(#{'a'=>2}) will never return since it differs in the 1st argument from the success typing arguments: (#{'b':=_, _=>_})
guard_update.erl:8: Clause guard cannot succeed. The variable M was matched against the type #{'a':=2}
guard_update.erl:8: Function f/1 has no local return
diff --git a/lib/dialyzer/test/map_SUITE_data/results/map_galore b/lib/dialyzer/test/map_SUITE_data/results/map_galore
index 9a140de255..6d1f4ff2bf 100644
--- a/lib/dialyzer/test/map_SUITE_data/results/map_galore
+++ b/lib/dialyzer/test/map_SUITE_data/results/map_galore
@@ -2,11 +2,11 @@
map_galore.erl:1000: A key of type 42 cannot exist in a map of type #{1:='a', 2:='b', 4:='d', 5:='e', float()=>'c' | 'v'}
map_galore.erl:1080: A key of type 'nonexisting' cannot exist in a map of type #{10:='a0', 11:='a1', 12:='a2', 13:='a3', 14:='a4', 15:='a5', 16:='a6', 17:='a7', 18:='a8', 19:='a9', 20:='b0', 21:='b1', 22:='b2', 23:='b3', 24:='b4', 25:='b5', 26:='b6', 27:='b7', 28:='b8', 29:='b9', 30:=[48 | 99,...], 31:=[49 | 99,...], 32:=[50 | 99,...], 33:=[51 | 99,...], 34:=[52 | 99,...], 35:=[53 | 99,...], 36:=[54 | 99,...], 37:=[55 | 99,...], 38:=[56 | 99,...], 39:=[57 | 99,...], <<_:16>> | [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57,...] | float() | {[[48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57,...],...]} | #{'k16'=>'a6', 'k26'=>'b6', 'k36'=>[54 | 99,...], 'map'=>'key', 'one'=>'small', 'second'=>'small', 'third'=>'small', 10=>'a0', 11=>'a1', 12=>'a2', 13=>'a3', 14=>'a4', 15=>'a5', 16=>'a6', 17=>'a7', 18=>'a8', 19=>'a9', 20=>'b0', 21=>'b1', 22=>'b2', 23=>'b3', 24=>'b4', 25=>'b5', 26=>'b6', 27=>'b7', 28=>'b8', 29=>'b9', 30=>[48 | 99,...], 31=>[49 | 99,...], 32=>[50 | 99,...], 33=>[51 | 99,...], 34=>[52 | 99,...], 35=>[53 | 99,...], 36=>[54 | 99,...], 37=>[55 | 99,...], 38=>[56 | 99,...], 39=>[57 | 99,...], <<_:16>> | [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57,...] | {[[48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57,...],...]}=>[48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 100 | 101,...]}=>atom() | [1..255,...]}
map_galore.erl:1082: A key of type 42 cannot exist in a map of type #{10:='a0', 11:='a1', 12:='a2', 13:='a3', 14:='a4', 15:='a5', 16:='a6', 17:='a7', 18:='a8', 19:='a9', 20:='b0', 21:='b1', 22:='b2', 23:='b3', 24:='b4', 25:='b5', 26:='b6', 27:='b7', 28:='b8', 29:='b9', 30:=[48 | 99,...], 31:=[49 | 99,...], 32:=[50 | 99,...], 33:=[51 | 99,...], 34:=[52 | 99,...], 35:=[53 | 99,...], 36:=[54 | 99,...], 37:=[55 | 99,...], 38:=[56 | 99,...], 39:=[57 | 99,...], <<_:16>> | [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57,...] | float() | {[[48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57,...],...]} | #{'k16'=>'a6', 'k26'=>'b6', 'k36'=>[54 | 99,...], 'map'=>'key', 'one'=>'small', 'second'=>'small', 'third'=>'small', 10=>'a0', 11=>'a1', 12=>'a2', 13=>'a3', 14=>'a4', 15=>'a5', 16=>'a6', 17=>'a7', 18=>'a8', 19=>'a9', 20=>'b0', 21=>'b1', 22=>'b2', 23=>'b3', 24=>'b4', 25=>'b5', 26=>'b6', 27=>'b7', 28=>'b8', 29=>'b9', 30=>[48 | 99,...], 31=>[49 | 99,...], 32=>[50 | 99,...], 33=>[51 | 99,...], 34=>[52 | 99,...], 35=>[53 | 99,...], 36=>[54 | 99,...], 37=>[55 | 99,...], 38=>[56 | 99,...], 39=>[57 | 99,...], <<_:16>> | [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57,...] | {[[48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57,...],...]}=>[48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 100 | 101,...]}=>atom() | [1..255,...]}
-map_galore.erl:1140: The call map_galore:map_guard_sequence_1(#{'seq':=6, 'val':=[101,...]}) will never return since it differs in the 1st argument from the success typing arguments: (#{'seq':=1 | 2 | 3 | 4 | 5, 'val':=[97 | 98 | 99 | 100 | 101,...], 10=>'a0', 11=>'a1', 12=>'a2', 13=>'a3', 14=>'a4', 15=>'a5', 16=>'a6', 17=>'a7', 18=>'a8', 19=>'a9', 20=>'b0', 21=>'b1', 22=>'b2', 23=>'b3', 24=>'b4', 25=>'b5', 26=>'b6', 27=>'b7', 28=>'b8', 29=>'b9', 30=>[48 | 99,...], 31=>[49 | 99,...], 32=>[50 | 99,...], 33=>[51 | 99,...], 34=>[52 | 99,...], 35=>[53 | 99,...], 36=>[54 | 99,...], 37=>[55 | 99,...], 38=>[56 | 99,...], 39=>[57 | 99,...], <<_:16>> | [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57,...] | float() | {[any(),...]} | #{'k16'=>'a6', 'k26'=>'b6', 'k36'=>[any(),...], 'map'=>'key', 'one'=>'small', 'second'=>'small', 'third'=>'small', 10=>'a0', 11=>'a1', 12=>'a2', 13=>'a3', 14=>'a4', 15=>'a5', 16=>'a6', 17=>'a7', 18=>'a8', 19=>'a9', 20=>'b0', 21=>'b1', 22=>'b2', 23=>'b3', 24=>'b4', 25=>'b5', 26=>'b6', 27=>'b7', 28=>'b8', 29=>'b9', 30=>[any(),...], 31=>[any(),...], 32=>[any(),...], 33=>[any(),...], 34=>[any(),...], 35=>[any(),...], 36=>[any(),...], 37=>[any(),...], 38=>[any(),...], 39=>[any(),...], <<_:16>> | [any(),...] | {_}=>[any(),...]}=>atom() | [1..255,...]})
-map_galore.erl:1141: The call map_galore:map_guard_sequence_2(#{'b':=5}) will never return since it differs in the 1st argument from the success typing arguments: (#{'a':='gg' | 'kk' | 'sc' | 3 | 4, 'b'=>'other' | 3 | 4 | 5, 'c'=>'sc2', 10=>'a0', 11=>'a1', 12=>'a2', 13=>'a3', 14=>'a4', 15=>'a5', 16=>'a6', 17=>'a7', 18=>'a8', 19=>'a9', 20=>'b0', 21=>'b1', 22=>'b2', 23=>'b3', 24=>'b4', 25=>'b5', 26=>'b6', 27=>'b7', 28=>'b8', 29=>'b9', 30=>[48 | 99,...], 31=>[49 | 99,...], 32=>[50 | 99,...], 33=>[51 | 99,...], 34=>[52 | 99,...], 35=>[53 | 99,...], 36=>[54 | 99,...], 37=>[55 | 99,...], 38=>[56 | 99,...], 39=>[57 | 99,...], <<_:16>> | [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57,...] | float() | {[any(),...]} | #{'k16'=>'a6', 'k26'=>'b6', 'k36'=>[any(),...], 'map'=>'key', 'one'=>'small', 'second'=>'small', 'third'=>'small', 10=>'a0', 11=>'a1', 12=>'a2', 13=>'a3', 14=>'a4', 15=>'a5', 16=>'a6', 17=>'a7', 18=>'a8', 19=>'a9', 20=>'b0', 21=>'b1', 22=>'b2', 23=>'b3', 24=>'b4', 25=>'b5', 26=>'b6', 27=>'b7', 28=>'b8', 29=>'b9', 30=>[any(),...], 31=>[any(),...], 32=>[any(),...], 33=>[any(),...], 34=>[any(),...], 35=>[any(),...], 36=>[any(),...], 37=>[any(),...], 38=>[any(),...], 39=>[any(),...], <<_:16>> | [any(),...] | {_}=>[any(),...]}=>atom() | [1..255,...]})
+map_galore.erl:1140: The call map_galore:map_guard_sequence_1(#{'seq'=>6, 'val'=>"e"}) will never return since it differs in the 1st argument from the success typing arguments: (#{'seq':=1 | 2 | 3 | 4 | 5, 'val':=[97 | 98 | 99 | 100 | 101,...], 10=>'a0', 11=>'a1', 12=>'a2', 13=>'a3', 14=>'a4', 15=>'a5', 16=>'a6', 17=>'a7', 18=>'a8', 19=>'a9', 20=>'b0', 21=>'b1', 22=>'b2', 23=>'b3', 24=>'b4', 25=>'b5', 26=>'b6', 27=>'b7', 28=>'b8', 29=>'b9', 30=>[48 | 99,...], 31=>[49 | 99,...], 32=>[50 | 99,...], 33=>[51 | 99,...], 34=>[52 | 99,...], 35=>[53 | 99,...], 36=>[54 | 99,...], 37=>[55 | 99,...], 38=>[56 | 99,...], 39=>[57 | 99,...], <<_:16>> | [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57,...] | float() | {[any(),...]} | #{'k16'=>'a6', 'k26'=>'b6', 'k36'=>[any(),...], 'map'=>'key', 'one'=>'small', 'second'=>'small', 'third'=>'small', 10=>'a0', 11=>'a1', 12=>'a2', 13=>'a3', 14=>'a4', 15=>'a5', 16=>'a6', 17=>'a7', 18=>'a8', 19=>'a9', 20=>'b0', 21=>'b1', 22=>'b2', 23=>'b3', 24=>'b4', 25=>'b5', 26=>'b6', 27=>'b7', 28=>'b8', 29=>'b9', 30=>[any(),...], 31=>[any(),...], 32=>[any(),...], 33=>[any(),...], 34=>[any(),...], 35=>[any(),...], 36=>[any(),...], 37=>[any(),...], 38=>[any(),...], 39=>[any(),...], <<_:16>> | [any(),...] | {_}=>[any(),...]}=>atom() | [1..255,...]})
+map_galore.erl:1141: The call map_galore:map_guard_sequence_2(#{'b'=>5}) will never return since it differs in the 1st argument from the success typing arguments: (#{'a':='gg' | 'kk' | 'sc' | 3 | 4, 'b'=>'other' | 3 | 4 | 5, 'c'=>'sc2', 10=>'a0', 11=>'a1', 12=>'a2', 13=>'a3', 14=>'a4', 15=>'a5', 16=>'a6', 17=>'a7', 18=>'a8', 19=>'a9', 20=>'b0', 21=>'b1', 22=>'b2', 23=>'b3', 24=>'b4', 25=>'b5', 26=>'b6', 27=>'b7', 28=>'b8', 29=>'b9', 30=>[48 | 99,...], 31=>[49 | 99,...], 32=>[50 | 99,...], 33=>[51 | 99,...], 34=>[52 | 99,...], 35=>[53 | 99,...], 36=>[54 | 99,...], 37=>[55 | 99,...], 38=>[56 | 99,...], 39=>[57 | 99,...], <<_:16>> | [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57,...] | float() | {[any(),...]} | #{'k16'=>'a6', 'k26'=>'b6', 'k36'=>[any(),...], 'map'=>'key', 'one'=>'small', 'second'=>'small', 'third'=>'small', 10=>'a0', 11=>'a1', 12=>'a2', 13=>'a3', 14=>'a4', 15=>'a5', 16=>'a6', 17=>'a7', 18=>'a8', 19=>'a9', 20=>'b0', 21=>'b1', 22=>'b2', 23=>'b3', 24=>'b4', 25=>'b5', 26=>'b6', 27=>'b7', 28=>'b8', 29=>'b9', 30=>[any(),...], 31=>[any(),...], 32=>[any(),...], 33=>[any(),...], 34=>[any(),...], 35=>[any(),...], 36=>[any(),...], 37=>[any(),...], 38=>[any(),...], 39=>[any(),...], <<_:16>> | [any(),...] | {_}=>[any(),...]}=>atom() | [1..255,...]})
map_galore.erl:1209: The call map_galore:map_guard_sequence_1(#{'seq':=6, 'val':=[101,...], 10:='a0', 11:='a1', 12:='a2', 13:='a3', 14:='a4', 15:='a5', 16:='a6', 17:='a7', 18:='a8', 19:='a9', 20:='b0', 21:='b1', 22:='b2', 23:='b3', 24:='b4', 25:='b5', 26:='b6', 27:='b7', 28:='b8', 29:='b9', 30:=[48 | 99,...], 31:=[49 | 99,...], 32:=[50 | 99,...], 33:=[51 | 99,...], 34:=[52 | 99,...], 35:=[53 | 99,...], 36:=[54 | 99,...], 37:=[55 | 99,...], 38:=[56 | 99,...], 39:=[57 | 99,...], <<_:16>> | [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57,...] | float() | {[[48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57,...] | 3,...]} | #{'k16'=>'a6', 'k26'=>'b6', 'k36'=>[54 | 99,...], 'map'=>'key', 'one'=>'small', 'second'=>'small', 'third'=>'small', 10=>'a0', 11=>'a1', 12=>'a2', 13=>'a3', 14=>'a4', 15=>'a5', 16=>'a6', 17=>'a7', 18=>'a8', 19=>'a9', 20=>'b0', 21=>'b1', 22=>'b2', 23=>'b3', 24=>'b4', 25=>'b5', 26=>'b6', 27=>'b7', 28=>'b8', 29=>'b9', 30=>[48 | 99,...], 31=>[49 | 99,...], 32=>[50 | 99,...], 33=>[51 | 99,...], 34=>[52 | 99,...], 35=>[53 | 99,...], 36=>[54 | 99,...], 37=>[55 | 99,...], 38=>[56 | 99,...], 39=>[57 | 99,...], <<_:16>> | [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57,...] | {[[48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57,...],...]}=>[48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 100 | 101,...]}=>atom() | [1..255,...]}) will never return since it differs in the 1st argument from the success typing arguments: (#{'seq':=1 | 2 | 3 | 4 | 5, 'val':=[97 | 98 | 99 | 100 | 101,...], 10=>'a0', 11=>'a1', 12=>'a2', 13=>'a3', 14=>'a4', 15=>'a5', 16=>'a6', 17=>'a7', 18=>'a8', 19=>'a9', 20=>'b0', 21=>'b1', 22=>'b2', 23=>'b3', 24=>'b4', 25=>'b5', 26=>'b6', 27=>'b7', 28=>'b8', 29=>'b9', 30=>[48 | 99,...], 31=>[49 | 99,...], 32=>[50 | 99,...], 33=>[51 | 99,...], 34=>[52 | 99,...], 35=>[53 | 99,...], 36=>[54 | 99,...], 37=>[55 | 99,...], 38=>[56 | 99,...], 39=>[57 | 99,...], <<_:16>> | [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57,...] | float() | {[any(),...]} | #{'k16'=>'a6', 'k26'=>'b6', 'k36'=>[any(),...], 'map'=>'key', 'one'=>'small', 'second'=>'small', 'third'=>'small', 10=>'a0', 11=>'a1', 12=>'a2', 13=>'a3', 14=>'a4', 15=>'a5', 16=>'a6', 17=>'a7', 18=>'a8', 19=>'a9', 20=>'b0', 21=>'b1', 22=>'b2', 23=>'b3', 24=>'b4', 25=>'b5', 26=>'b6', 27=>'b7', 28=>'b8', 29=>'b9', 30=>[any(),...], 31=>[any(),...], 32=>[any(),...], 33=>[any(),...], 34=>[any(),...], 35=>[any(),...], 36=>[any(),...], 37=>[any(),...], 38=>[any(),...], 39=>[any(),...], <<_:16>> | [any(),...] | {_}=>[any(),...]}=>atom() | [1..255,...]})
map_galore.erl:1210: The call map_galore:map_guard_sequence_2(#{'b':=5, 10:='a0', 11:='a1', 12:='a2', 13:='a3', 14:='a4', 15:='a5', 16:='a6', 17:='a7', 18:='a8', 19:='a9', 20:='b0', 21:='b1', 22:='b2', 23:='b3', 24:='b4', 25:='b5', 26:='b6', 27:='b7', 28:='b8', 29:='b9', 30:=[48 | 99,...], 31:=[49 | 99,...], 32:=[50 | 99,...], 33:=[51 | 99,...], 34:=[52 | 99,...], 35:=[53 | 99,...], 36:=[54 | 99,...], 37:=[55 | 99,...], 38:=[56 | 99,...], 39:=[57 | 99,...], <<_:16>> | [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57,...] | float() | {[[48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57,...] | 3,...]} | #{'k16'=>'a6', 'k26'=>'b6', 'k36'=>[54 | 99,...], 'map'=>'key', 'one'=>'small', 'second'=>'small', 'third'=>'small', 10=>'a0', 11=>'a1', 12=>'a2', 13=>'a3', 14=>'a4', 15=>'a5', 16=>'a6', 17=>'a7', 18=>'a8', 19=>'a9', 20=>'b0', 21=>'b1', 22=>'b2', 23=>'b3', 24=>'b4', 25=>'b5', 26=>'b6', 27=>'b7', 28=>'b8', 29=>'b9', 30=>[48 | 99,...], 31=>[49 | 99,...], 32=>[50 | 99,...], 33=>[51 | 99,...], 34=>[52 | 99,...], 35=>[53 | 99,...], 36=>[54 | 99,...], 37=>[55 | 99,...], 38=>[56 | 99,...], 39=>[57 | 99,...], <<_:16>> | [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57,...] | {[[48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57,...],...]}=>[48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 100 | 101,...]}=>atom() | [1..255,...]}) will never return since it differs in the 1st argument from the success typing arguments: (#{'a':='gg' | 'kk' | 'sc' | 3 | 4, 'b'=>'other' | 3 | 4 | 5, 'c'=>'sc2', 10=>'a0', 11=>'a1', 12=>'a2', 13=>'a3', 14=>'a4', 15=>'a5', 16=>'a6', 17=>'a7', 18=>'a8', 19=>'a9', 20=>'b0', 21=>'b1', 22=>'b2', 23=>'b3', 24=>'b4', 25=>'b5', 26=>'b6', 27=>'b7', 28=>'b8', 29=>'b9', 30=>[48 | 99,...], 31=>[49 | 99,...], 32=>[50 | 99,...], 33=>[51 | 99,...], 34=>[52 | 99,...], 35=>[53 | 99,...], 36=>[54 | 99,...], 37=>[55 | 99,...], 38=>[56 | 99,...], 39=>[57 | 99,...], <<_:16>> | [48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57,...] | float() | {[any(),...]} | #{'k16'=>'a6', 'k26'=>'b6', 'k36'=>[any(),...], 'map'=>'key', 'one'=>'small', 'second'=>'small', 'third'=>'small', 10=>'a0', 11=>'a1', 12=>'a2', 13=>'a3', 14=>'a4', 15=>'a5', 16=>'a6', 17=>'a7', 18=>'a8', 19=>'a9', 20=>'b0', 21=>'b1', 22=>'b2', 23=>'b3', 24=>'b4', 25=>'b5', 26=>'b6', 27=>'b7', 28=>'b8', 29=>'b9', 30=>[any(),...], 31=>[any(),...], 32=>[any(),...], 33=>[any(),...], 34=>[any(),...], 35=>[any(),...], 36=>[any(),...], 37=>[any(),...], 38=>[any(),...], 39=>[any(),...], <<_:16>> | [any(),...] | {_}=>[any(),...]}=>atom() | [1..255,...]})
-map_galore.erl:1418: Fun application with arguments (#{'s':='none', 'v':='none'}) will never return since it differs in the 1st argument from the success typing arguments: (#{'s':='l' | 't' | 'v', 'v':='none' | <<_:16>> | [<<_:16>>,...] | {<<_:16>>,<<_:16>>}})
+map_galore.erl:1418: Fun application with arguments (#{'s'=>'none', 'v'=>'none'}) will never return since it differs in the 1st argument from the success typing arguments: (#{'s':='l' | 't' | 'v', 'v':='none' | <<_:16>> | [<<_:16>>,...] | {<<_:16>>,<<_:16>>}})
map_galore.erl:1491: The test #{} =:= #{'a':=1} can never evaluate to 'true'
map_galore.erl:1492: The test #{'a':=1} =:= #{} can never evaluate to 'true'
map_galore.erl:1495: The test #{'a':=1} =:= #{'a':=2} can never evaluate to 'true'
@@ -15,13 +15,13 @@ map_galore.erl:1497: The test #{'a':=2, 'b':=1} =:= #{'a':=1, 'b':=3} can never
map_galore.erl:1498: The test #{'a':=1, 'b':=1} =:= #{'a':=1, 'b':=3} can never evaluate to 'true'
map_galore.erl:1762: The call maps:get({1, 1},#{{1,float()}=>[101 | 108 | 112 | 116 | 117,...]}) will never return since the success typing arguments are (any(),map())
map_galore.erl:1763: The call maps:get('a',#{}) will never return since the success typing arguments are (any(),map())
-map_galore.erl:1765: The call maps:get('a',#{'b':=1, 'c':=2}) will never return since the success typing arguments are (any(),map())
+map_galore.erl:1765: The call maps:get('a',#{'b'=>1, 'c'=>2}) will never return since the success typing arguments are (any(),map())
map_galore.erl:186: The pattern #{'x':=2} can never match the type #{'x':=3}
map_galore.erl:187: The pattern #{'x':=3} can never match the type {'a','b','c'}
map_galore.erl:188: The pattern #{'x':=3} can never match the type #{'y':=3}
map_galore.erl:189: The pattern #{'x':=3} can never match the type #{'x':=[101 | 104 | 114 | 116,...]}
map_galore.erl:2280: Cons will produce an improper list since its 2nd argument is {'b','a'}
-map_galore.erl:2280: The call maps:from_list(nonempty_improper_list({'a','b'},{'b','a'})) will never return since it differs in the 1st argument from the success typing arguments: ([{_,_}])
+map_galore.erl:2280: The call maps:from_list([{'a', 'b'} | {'b', 'a'}]) will never return since it differs in the 1st argument from the success typing arguments: ([{_,_}])
map_galore.erl:2281: The call maps:from_list('a') will never return since it differs in the 1st argument from the success typing arguments: ([{_,_}])
map_galore.erl:2282: The call maps:from_list(42) will never return since it differs in the 1st argument from the success typing arguments: ([{_,_}])
map_galore.erl:997: A key of type 'nonexisting' cannot exist in a map of type #{}
diff --git a/lib/dialyzer/test/map_SUITE_data/results/typesig b/lib/dialyzer/test/map_SUITE_data/results/typesig
index fb2f851a7d..6a79fe35f1 100644
--- a/lib/dialyzer/test/map_SUITE_data/results/typesig
+++ b/lib/dialyzer/test/map_SUITE_data/results/typesig
@@ -1,5 +1,5 @@
typesig.erl:5: Function t1/0 has no local return
-typesig.erl:5: The call typesig:test(#{'a':=1}) will never return since it differs in the 1st argument from the success typing arguments: (#{'a':={number()}, _=>_})
+typesig.erl:5: The call typesig:test(#{'a'=>1}) will never return since it differs in the 1st argument from the success typing arguments: (#{'a':={number()}, _=>_})
typesig.erl:6: Function t2/0 has no local return
typesig.erl:6: The call typesig:test(#{'a':={'b'}}) will never return since it differs in the 1st argument from the success typing arguments: (#{'a':={number()}, _=>_})
diff --git a/lib/dialyzer/test/opaque_SUITE_data/dialyzer_options b/lib/dialyzer/test/opaque_SUITE_data/dialyzer_options
index cb301ff6a1..8551a47541 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/dialyzer_options
+++ b/lib/dialyzer/test/opaque_SUITE_data/dialyzer_options
@@ -1,2 +1,2 @@
-{dialyzer_options, [{warnings, [no_unused, no_return]}]}.
+{dialyzer_options, [{indent_opt, false}, {warnings, [no_unused, no_return]}]}.
{time_limit, 40}.
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/dict b/lib/dialyzer/test/opaque_SUITE_data/results/dict
index 3f8242c72d..bda9bfc09f 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/dict
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/dict
@@ -10,6 +10,6 @@ dict_use.erl:64: Guard test length(D::dict:dict(_,_)) breaks the opacity of its
dict_use.erl:65: Guard test is_atom(D::dict:dict(_,_)) breaks the opacity of its argument
dict_use.erl:66: Guard test is_list(D::dict:dict(_,_)) breaks the opacity of its argument
dict_use.erl:70: The type test is_list(dict:dict(_,_)) breaks the opacity of the term dict:dict(_,_)
-dict_use.erl:73: The call dict:fetch('foo',[1 | 2 | 3,...]) does not have an opaque term of type dict:dict(_,_) as 2nd argument
-dict_use.erl:76: The call dict:merge(Fun::any(),42,[1 | 2,...]) does not have opaque terms as 2nd and 3rd arguments
-dict_use.erl:79: The call dict:store(42,'elli',{'dict',0,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]}}}) does not have an opaque term of type dict:dict(_,_) as 3rd argument
+dict_use.erl:73: The call dict:fetch('foo',[1, 2, 3]) does not have an opaque term of type dict:dict(_,_) as 2nd argument
+dict_use.erl:76: The call dict:merge(Fun::any(),42,[1, 2]) does not have opaque terms as 2nd and 3rd arguments
+dict_use.erl:79: The call dict:store(42,'elli',{'dict', 0, 16, 16, 8, 80, 48, {[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], []}, {{[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], []}}}) does not have an opaque term of type dict:dict(_,_) as 3rd argument
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/para b/lib/dialyzer/test/opaque_SUITE_data/results/para
index 37b5b7b44e..eca445315c 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/para
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/para
@@ -29,5 +29,6 @@ para4.erl:74: Attempt to test for equality between a term of type para4_adt:int(
para4.erl:79: Attempt to test for equality between a term of type para4_adt:int(2 | 3 | 4) and a term of opaque type para4_adt:int(5 | 6 | 7)
para4.erl:84: Attempt to test for equality between a term of type para4_adt:un(3 | 4) and a term of opaque type para4_adt:un(1 | 2)
para4.erl:89: Attempt to test for equality between a term of type para4_adt:tup({_,_}) and a term of opaque type para4_adt:tup(tuple())
+para4.erl:94: Attempt to test for equality between a term of type para4_adt:t(#{1=>'a'}) and a term of opaque type para4_adt:t(#{2=>'b'})
para5.erl:13: Attempt to test for inequality between a term of type para5_adt:dd(atom()) and a term of opaque type para5_adt:d()
para5.erl:8: The test para5_adt:d() =:= para5_adt:d() can never evaluate to 'true'
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/queue b/lib/dialyzer/test/opaque_SUITE_data/results/queue
index 9822b7168f..8f9373e8e4 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/queue
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/queue
@@ -1,11 +1,11 @@
-queue_use.erl:18: The call queue:is_empty({[],[]}) does not have an opaque term of type queue:queue(_) as 1st argument
+queue_use.erl:18: The call queue:is_empty({[], []}) does not have an opaque term of type queue:queue(_) as 1st argument
queue_use.erl:22: The call queue:in(42,Q0::{[],[]}) does not have an opaque term of type queue:queue(_) as 2nd argument
queue_use.erl:27: The attempt to match a term of type queue:queue(_) against the pattern {"*", Q2} breaks the opacity of the term
queue_use.erl:33: Attempt to test for equality between a term of type {[42,...],[]} and a term of opaque type queue:queue(_)
queue_use.erl:36: The attempt to match a term of type queue:queue(_) against the pattern {F, _R} breaks the opacity of the term
-queue_use.erl:40: The call queue:out({[42,...],[]}) does not have an opaque term of type queue:queue(_) as 1st argument
+queue_use.erl:40: The call queue:out({"*", []}) does not have an opaque term of type queue:queue(_) as 1st argument
queue_use.erl:51: The call queue_use:is_in_queue(E::42,DB::#db{p::[],q::queue:queue(_)}) contains an opaque term as 2nd argument when terms of different types are expected in these positions
queue_use.erl:56: The attempt to match a term of type #db{p::[],q::queue:queue(_)} against the pattern {'db', _, {L1, L2}} breaks the opacity of queue:queue(_)
-queue_use.erl:62: The call queue_use:tuple_queue({42,'gazonk'}) does not have a term of type {_,queue:queue(_)} (with opaque subterms) as 1st argument
+queue_use.erl:62: The call queue_use:tuple_queue({42, 'gazonk'}) does not have a term of type {_,queue:queue(_)} (with opaque subterms) as 1st argument
queue_use.erl:65: The call queue:in(F::42,Q::'gazonk') does not have an opaque term of type queue:queue(_) as 2nd argument
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/simple b/lib/dialyzer/test/opaque_SUITE_data/results/simple
index 5cd8916aee..5d13b56970 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/simple
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/simple
@@ -51,7 +51,7 @@ simple1_api.erl:294: The call erlang:is_function(T::simple1_api:o1(),A::simple1_
simple1_api.erl:300: The type test is_function(T::simple1_adt:o1(),A::simple1_api:i1()) breaks the opacity of the term T::simple1_adt:o1()
simple1_api.erl:306: Guard test B::simple1_api:b2() =:= 'true' can never succeed
simple1_api.erl:315: Guard test A::simple1_api:b1() =:= 'false' can never succeed
-simple1_api.erl:319: Guard test not('and'('true','true')) can never succeed
+simple1_api.erl:319: Guard test not(and('true','true')) can never succeed
simple1_api.erl:337: Clause guard cannot succeed.
simple1_api.erl:342: Guard test B::simple1_adt:b2() =:= 'true' contains an opaque term as 1st argument
simple1_api.erl:347: Guard test A::simple1_adt:b1() =:= 'true' contains an opaque term as 1st argument
@@ -63,9 +63,9 @@ simple1_api.erl:381: Invalid type specification for function simple1_api:bool_ad
simple1_api.erl:407: The size simple1_adt:i1() breaks the opacity of A
simple1_api.erl:418: The attempt to match a term of type non_neg_integer() against the variable A breaks the opacity of simple1_adt:i1()
simple1_api.erl:425: The attempt to match a term of type non_neg_integer() against the variable B breaks the opacity of simple1_adt:i1()
-simple1_api.erl:432: The pattern <<_:B/integer-unit:1>> can never match the type any()
+simple1_api.erl:432: The pattern <<_:B>> can never match the type any()
simple1_api.erl:448: The attempt to match a term of type non_neg_integer() against the variable Sz breaks the opacity of simple1_adt:i1()
-simple1_api.erl:460: The attempt to match a term of type simple1_adt:bit1() against the pattern <<_/binary-unit:8>> breaks the opacity of the term
+simple1_api.erl:460: The attempt to match a term of type simple1_adt:bit1() against the pattern <<_/binary>> breaks the opacity of the term
simple1_api.erl:478: The call 'foo':A(A::simple1_adt:a()) breaks the opacity of the term A :: simple1_adt:a()
simple1_api.erl:486: The call A:'foo'(A::simple1_adt:a()) breaks the opacity of the term A :: simple1_adt:a()
simple1_api.erl:499: The call 'foo':A(A::simple1_api:i()) requires that A is of type atom() not simple1_api:i()
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/para/para4.erl b/lib/dialyzer/test/opaque_SUITE_data/src/para/para4.erl
index b9794672a9..8cd049169d 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/src/para/para4.erl
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/para/para4.erl
@@ -88,6 +88,11 @@ adt_tt13() ->
I2 = adt_tup2(),
I1 =:= I2. % opaque attempt
+adt_tt14() ->
+ I1 = adt_map(),
+ I2 = adt_map2(),
+ I1 =:= I2.
+
y3() ->
{a, 3}.
@@ -132,3 +137,9 @@ adt_tup() ->
adt_tup2() ->
para4_adt:tup2().
+
+adt_map() ->
+ para4_adt:map().
+
+adt_map2() ->
+ para4_adt:map2().
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/para/para4_adt.erl b/lib/dialyzer/test/opaque_SUITE_data/src/para/para4_adt.erl
index 407dd198a7..06a6c22677 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/src/para/para4_adt.erl
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/para/para4_adt.erl
@@ -8,6 +8,8 @@
-export([tup/0, tup2/0]).
+-export([map/0, map2/0]).
+
-export_type([t/1, y/1, int/1, tup/1, un/1]).
-type ai() :: atom() | integer().
@@ -106,3 +108,13 @@ tup() ->
tup2() ->
foo:tup2().
+
+-spec map() -> t(#{2 => b}).
+
+map() ->
+ foo:map().
+
+-spec map2() -> t(#{1 => a}).
+
+map2() ->
+ foo:map2().
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/proper/proper_typeserver.erl b/lib/dialyzer/test/opaque_SUITE_data/src/proper/proper_typeserver.erl
index 1677b4efb8..529f9fba72 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/src/proper/proper_typeserver.erl
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/proper/proper_typeserver.erl
@@ -533,7 +533,7 @@ apply_spec_test({Mod,Fun,_Arity}=MFA, {_Domain,Range}, SpecTimeout, FalsePositiv
try apply(Mod,Fun,Args) of
X -> {ok, X}
catch
- X:Y -> {X, Y}
+ X:Y:S -> {{X, Y}, S}
end,
case Result of
{ok, Z} ->
@@ -545,15 +545,15 @@ apply_spec_test({Mod,Fun,_Arity}=MFA, {_Domain,Range}, SpecTimeout, FalsePositiv
false ->
false
end;
- Exception when is_function(FalsePositiveMFAs) ->
+ {Exception, S2} when is_function(FalsePositiveMFAs) ->
case FalsePositiveMFAs(MFA, Args, Exception) of
true ->
true;
false ->
- error(Exception, erlang:get_stacktrace())
+ error(Exception, S2)
end;
- Exception ->
- error(Exception, erlang:get_stacktrace())
+ {Exception, S3} ->
+ error(Exception, S3)
end
end).
diff --git a/lib/dialyzer/test/options1_SUITE_data/dialyzer_options b/lib/dialyzer/test/options1_SUITE_data/dialyzer_options
index c612e77d3e..ef5887a1eb 100644
--- a/lib/dialyzer/test/options1_SUITE_data/dialyzer_options
+++ b/lib/dialyzer/test/options1_SUITE_data/dialyzer_options
@@ -1,2 +1,2 @@
-{dialyzer_options, [{include_dirs, ["my_include"]}, {defines, [{'COMPILER_VSN', 42}]}, {warnings, [no_improper_lists]}]}.
+{dialyzer_options, [{indent_opt, false}, {include_dirs, ["my_include"]}, {defines, [{'COMPILER_VSN', 42}]}, {warnings, [no_improper_lists]}]}.
{time_limit, 30}.
diff --git a/lib/dialyzer/test/options1_SUITE_data/results/compiler b/lib/dialyzer/test/options1_SUITE_data/results/compiler
index cbb5115c91..121163d7ca 100644
--- a/lib/dialyzer/test/options1_SUITE_data/results/compiler
+++ b/lib/dialyzer/test/options1_SUITE_data/results/compiler
@@ -6,8 +6,8 @@ beam_disasm.erl:537: The variable X can never match since previous clauses compl
beam_type.erl:284: The pattern <'pi', 0> can never match the type <_,1 | 2>
beam_validator.erl:396: Matching of pattern {'vst', 'none', _} tagged with a record name violates the declared type of #vst{current::#st{ct::[]}}
beam_validator.erl:690: The pattern <'term', OldT> can never match the type <{'tuple',[any(),...]},_>
-beam_validator.erl:693: Guard test 'or'('false','false') can never succeed
-beam_validator.erl:700: Guard test 'or'('false','false') can never succeed
+beam_validator.erl:693: Guard test or('false','false') can never succeed
+beam_validator.erl:700: Guard test or('false','false') can never succeed
beam_validator.erl:702: The pattern <'number', OldT = {Type, _}> can never match the type <{'tuple',[any(),...]},_>
beam_validator.erl:705: The pattern <'bool', {'atom', A}> can never match the type <{'tuple',[any(),...]},_>
beam_validator.erl:707: The pattern <{'atom', A}, 'bool'> can never match the type <{'tuple',[any(),...]},_>
@@ -28,7 +28,7 @@ cerl_inline.erl:2750: The pattern <{[], L, D}, Vs> can never match the type <[1.
cerl_inline.erl:2752: The pattern <{[], _L, D}, Vs> can never match the type <[1..255,...],[any()]>
cerl_inline.erl:2754: The pattern <{F, L, D}, Vs> can never match the type <[1..255,...],[any()]>
cerl_inline.erl:2756: The pattern <{F, _L, D}, Vs> can never match the type <[1..255,...],[any()]>
-compile.erl:788: The pattern {'error', Es} can never match the type {'ok',<<_:64,_:_*8>>}
+compile.erl:792: The pattern {'error', Es} can never match the type {'ok',<<_:64,_:_*8>>}
core_lint.erl:473: The pattern <{'c_atom', _, 'all'}, 'binary', _Def, St> can never match the type <_,#c_nil{} | {'c_atom' | 'c_char' | 'c_float' | 'c_int' | 'c_string' | 'c_tuple',_,_} | #c_cons{hd::#c_nil{} | {'c_atom' | 'c_char' | 'c_float' | 'c_int' | 'c_string' | 'c_tuple',_,_} | #c_cons{hd::{_,_} | {_,_,_} | {_,_,_,_},tl::{_,_} | {_,_,_} | {_,_,_,_}},tl::#c_nil{} | {'c_atom' | 'c_char' | 'c_float' | 'c_int' | 'c_string' | 'c_tuple',_,_} | #c_cons{hd::{_,_} | {_,_,_} | {_,_,_,_},tl::{_,_} | {_,_,_} | {_,_,_,_}}},[any()],_>
core_lint.erl:505: The pattern <_Req, 'unknown', St> can never match the type <non_neg_integer(),non_neg_integer(),_>
sys_pre_expand.erl:625: Call to missing or unexported function erlang:hash/2
diff --git a/lib/dialyzer/test/options1_SUITE_data/src/compiler/beam_validator.erl b/lib/dialyzer/test/options1_SUITE_data/src/compiler/beam_validator.erl
index 8fe43163f6..3606b21932 100644
--- a/lib/dialyzer/test/options1_SUITE_data/src/compiler/beam_validator.erl
+++ b/lib/dialyzer/test/options1_SUITE_data/src/compiler/beam_validator.erl
@@ -174,7 +174,7 @@ validate_error(Error, Name, Ar) ->
-endif.
validate_error_1(Error, Name, Ar) ->
{{'_',Name,Ar},
- {internal_error,'_',{Error,erlang:get_stacktrace()}}}.
+ {internal_error,'_',{Error,[]}}}.
-record(st, %Emulation state
{x=init_regs(0, term), %x register info.
@@ -272,7 +272,7 @@ valfun_1(if_end, Vst) ->
valfun_1({try_case_end,Src}, Vst) ->
assert_term(Src, Vst),
kill_state(Vst);
-%% Instructions that can not cause exceptions
+%% Instructions that cannot cause exceptions
valfun_1({move,Src,Dst}, Vst) ->
Type = get_term_type(Src, Vst),
set_type_reg(Type, Dst, Vst);
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 7e5ccde2fd..6838cf6734 100644
--- a/lib/dialyzer/test/options1_SUITE_data/src/compiler/compile.erl
+++ b/lib/dialyzer/test/options1_SUITE_data/src/compiler/compile.erl
@@ -228,11 +228,15 @@ os_process_size() ->
case os:type() of
{unix, sunos} ->
Size = os:cmd("ps -o vsz -p " ++ os:getpid() ++ " | tail -1"),
- list_to_integer(lib:nonl(Size));
+ list_to_integer(nonl(Size));
_ ->
0
end.
+nonl([$\n]) -> [];
+nonl([]) -> [];
+nonl([H|T]) -> [H|nonl(T)].
+
run_tc({Name,Fun}, St) ->
Before0 = statistics(runtime),
Val = (catch Fun(St)),
diff --git a/lib/dialyzer/test/options2_SUITE_data/dialyzer_options b/lib/dialyzer/test/options2_SUITE_data/dialyzer_options
index be57e2de72..6492098d01 100644
--- a/lib/dialyzer/test/options2_SUITE_data/dialyzer_options
+++ b/lib/dialyzer/test/options2_SUITE_data/dialyzer_options
@@ -1 +1 @@
-{dialyzer_options, [{defines, [{'vsn', 4}]}, {warnings, [unknown, no_return]}]}.
+{dialyzer_options, [{indent_opt, false}, {defines, [{'vsn', 4}]}, {warnings, [unknown, no_return]}]}.
diff --git a/lib/dialyzer/test/overspecs_SUITE_data/dialyzer_options b/lib/dialyzer/test/overspecs_SUITE_data/dialyzer_options
new file mode 100644
index 0000000000..f581ad6607
--- /dev/null
+++ b/lib/dialyzer/test/overspecs_SUITE_data/dialyzer_options
@@ -0,0 +1 @@
+{dialyzer_options, [{indent_opt, false}, {warnings, [overspecs]}]}.
diff --git a/lib/dialyzer/test/overspecs_SUITE_data/results/iodata b/lib/dialyzer/test/overspecs_SUITE_data/results/iodata
new file mode 100644
index 0000000000..d9c70330ec
--- /dev/null
+++ b/lib/dialyzer/test/overspecs_SUITE_data/results/iodata
@@ -0,0 +1,2 @@
+
+iodata.erl:7: The success typing for iodata:encode/2 implies that the function might also return integer() but the specification return is binary() | maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | byte(),binary() | [])
diff --git a/lib/dialyzer/test/overspecs_SUITE_data/results/iolist b/lib/dialyzer/test/overspecs_SUITE_data/results/iolist
new file mode 100644
index 0000000000..ca556f017c
--- /dev/null
+++ b/lib/dialyzer/test/overspecs_SUITE_data/results/iolist
@@ -0,0 +1,2 @@
+
+iolist.erl:7: The success typing for iolist:encode/2 implies that the function might also return integer() but the specification return is maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | byte(),binary() | [])
diff --git a/lib/dialyzer/test/overspecs_SUITE_data/src/iodata.erl b/lib/dialyzer/test/overspecs_SUITE_data/src/iodata.erl
new file mode 100644
index 0000000000..caa44f6c91
--- /dev/null
+++ b/lib/dialyzer/test/overspecs_SUITE_data/src/iodata.erl
@@ -0,0 +1,41 @@
+-module(iodata).
+
+%% A small part of beam_asm.
+
+-export([encode/2]).
+
+-spec encode(non_neg_integer(), integer()) -> iodata(). % extra range binary()
+
+encode(Tag, N) when Tag >= 0, N < 0 ->
+ encode1(Tag, negative_to_bytes(N));
+encode(Tag, N) when Tag >= 0, N < 16 ->
+ (N bsl 4) bor Tag; % not in the specification
+encode(Tag, N) when Tag >= 0, N < 16#800 ->
+ [((N bsr 3) band 2#11100000) bor Tag bor 2#00001000, N band 16#ff];
+encode(Tag, N) when Tag >= 0 ->
+ encode1(Tag, to_bytes(N)).
+
+encode1(Tag, Bytes) ->
+ case iolist_size(Bytes) of
+ Num when 2 =< Num, Num =< 8 ->
+ [((Num-2) bsl 5) bor 2#00011000 bor Tag| Bytes];
+ Num when 8 < Num ->
+ [2#11111000 bor Tag, encode(0, Num-9)| Bytes]
+ end.
+
+to_bytes(N) ->
+ Bin = binary:encode_unsigned(N),
+ case Bin of
+ <<0:1,_/bits>> -> Bin;
+ <<1:1,_/bits>> -> [0,Bin]
+ end.
+
+negative_to_bytes(N) when N >= -16#8000 ->
+ <<N:16>>;
+negative_to_bytes(N) ->
+ Bytes = byte_size(binary:encode_unsigned(-N)),
+ Bin = <<N:Bytes/unit:8>>,
+ case Bin of
+ <<0:1,_/bits>> -> [16#ff,Bin];
+ <<1:1,_/bits>> -> Bin
+ end.
diff --git a/lib/dialyzer/test/overspecs_SUITE_data/src/iolist.erl b/lib/dialyzer/test/overspecs_SUITE_data/src/iolist.erl
new file mode 100644
index 0000000000..7cceeda24e
--- /dev/null
+++ b/lib/dialyzer/test/overspecs_SUITE_data/src/iolist.erl
@@ -0,0 +1,41 @@
+-module(iolist).
+
+%% A small part of beam_asm.
+
+-export([encode/2]).
+
+-spec encode(non_neg_integer(), integer()) -> iolist().
+
+encode(Tag, N) when Tag >= 0, N < 0 ->
+ encode1(Tag, negative_to_bytes(N));
+encode(Tag, N) when Tag >= 0, N < 16 ->
+ (N bsl 4) bor Tag; % not in the specification
+encode(Tag, N) when Tag >= 0, N < 16#800 ->
+ [((N bsr 3) band 2#11100000) bor Tag bor 2#00001000, N band 16#ff];
+encode(Tag, N) when Tag >= 0 ->
+ encode1(Tag, to_bytes(N)).
+
+encode1(Tag, Bytes) ->
+ case iolist_size(Bytes) of
+ Num when 2 =< Num, Num =< 8 ->
+ [((Num-2) bsl 5) bor 2#00011000 bor Tag| Bytes];
+ Num when 8 < Num ->
+ [2#11111000 bor Tag, encode(0, Num-9)| Bytes]
+ end.
+
+to_bytes(N) ->
+ Bin = binary:encode_unsigned(N),
+ case Bin of
+ <<0:1,_/bits>> -> Bin;
+ <<1:1,_/bits>> -> [0,Bin]
+ end.
+
+negative_to_bytes(N) when N >= -16#8000 ->
+ <<N:16>>;
+negative_to_bytes(N) ->
+ Bytes = byte_size(binary:encode_unsigned(-N)),
+ Bin = <<N:Bytes/unit:8>>,
+ case Bin of
+ <<0:1,_/bits>> -> [16#ff,Bin];
+ <<1:1,_/bits>> -> Bin
+ end.
diff --git a/lib/dialyzer/test/r9c_SUITE_data/dialyzer_options b/lib/dialyzer/test/r9c_SUITE_data/dialyzer_options
index e00e23bb66..ab6c9439ad 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/dialyzer_options
+++ b/lib/dialyzer/test/r9c_SUITE_data/dialyzer_options
@@ -1,2 +1,2 @@
-{dialyzer_options, [{defines, [{vsn, 42}]}]}.
+{dialyzer_options, [{indent_opt, false}, {defines, [{vsn, 42}]}]}.
{time_limit, 20}.
diff --git a/lib/dialyzer/test/r9c_SUITE_data/results/asn1 b/lib/dialyzer/test/r9c_SUITE_data/results/asn1
index 1cf03346ee..6e51b972af 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/results/asn1
+++ b/lib/dialyzer/test/r9c_SUITE_data/results/asn1
@@ -87,7 +87,7 @@ asn1rt_per_bin.erl:2127: Cons will produce an improper list since its 2nd argume
asn1rt_per_bin.erl:2129: Cons will produce an improper list since its 2nd argument is integer()
asn1rt_per_bin.erl:446: The variable _ can never match since previous clauses completely covered the type integer()
asn1rt_per_bin.erl:467: The variable _ can never match since previous clauses completely covered the type integer()
-asn1rt_per_bin.erl:474: The pattern <{_N, <<_:8/integer-unit:1,Bs/binary-unit:8>>}, C> can never match since previous clauses completely covered the type <{0,_},integer()>
+asn1rt_per_bin.erl:474: The pattern <{_N, <<_,Bs/binary>>}, C> can never match since previous clauses completely covered the type <{0,_},integer()>
asn1rt_per_bin.erl:487: The variable _ can never match since previous clauses completely covered the type integer()
asn1rt_per_bin.erl:498: The variable _ can never match since previous clauses completely covered the type integer()
asn1rt_per_bin_rt2ct.erl:152: The call asn1rt_per_bin_rt2ct:getbit({0,maybe_improper_list()}) will never return since it differs in the 1st argument from the success typing arguments: (<<_:8,_:_*8>> | {non_neg_integer(),<<_:1,_:_*1>>})
@@ -95,7 +95,7 @@ asn1rt_per_bin_rt2ct.erl:1533: The pattern {'BMPString', {'octets', Ol}} can nev
asn1rt_per_bin_rt2ct.erl:1875: The pattern {Name, Val} can never match since previous clauses completely covered the type any()
asn1rt_per_bin_rt2ct.erl:443: The variable _ can never match since previous clauses completely covered the type integer()
asn1rt_per_bin_rt2ct.erl:464: The variable _ can never match since previous clauses completely covered the type integer()
-asn1rt_per_bin_rt2ct.erl:471: The pattern <{_N, <<_B:8/integer-unit:1,Bs/binary-unit:8>>}, C> can never match since previous clauses completely covered the type <{0,_},integer()>
+asn1rt_per_bin_rt2ct.erl:471: The pattern <{_N, <<_B,Bs/binary>>}, C> can never match since previous clauses completely covered the type <{0,_},integer()>
asn1rt_per_bin_rt2ct.erl:484: The variable _ can never match since previous clauses completely covered the type integer()
asn1rt_per_bin_rt2ct.erl:495: The variable _ can never match since previous clauses completely covered the type integer()
asn1rt_per_v1.erl:1209: The pattern <_, 'true', _> can never match the type <_,'false',_>
diff --git a/lib/dialyzer/test/r9c_SUITE_data/results/inets b/lib/dialyzer/test/r9c_SUITE_data/results/inets
index d377f34978..31e9f031ce 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/results/inets
+++ b/lib/dialyzer/test/r9c_SUITE_data/results/inets
@@ -21,9 +21,9 @@ httpd_manager.erl:885: The pattern {'EXIT', Reason} can never match since previo
httpd_manager.erl:919: Function auth_status/1 will never be called
httpd_manager.erl:926: Function sec_status/1 will never be called
httpd_manager.erl:933: Function acceptor_status/1 will never be called
-httpd_request_handler.erl:374: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 66 | 98 | 100 | 103 | 105 | 111 | 116 | 121,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any())
-httpd_request_handler.erl:378: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 77 | 97 | 100 | 101 | 104 | 108 | 110 | 111 | 116 | 119,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any())
-httpd_request_handler.erl:401: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 77 | 97 | 100 | 101 | 104 | 108 | 110 | 111 | 116 | 119,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any())
+httpd_request_handler.erl:374: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,"Body to big") will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any())
+httpd_request_handler.erl:378: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,"Method not allowed") will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any())
+httpd_request_handler.erl:401: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,"Method not allowed") will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any())
httpd_request_handler.erl:649: Guard test [{_,_}] =:= Trailers::nonempty_string() can never succeed
httpd_sup.erl:63: The variable Else can never match since previous clauses completely covered the type {'error',_} | {'ok',[any()],_,_}
httpd_sup.erl:88: The pattern {'error', Reason} can never match the type {'ok',_,_}
diff --git a/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber.erl b/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber.erl
index 1d065b3723..88b464a721 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber.erl
+++ b/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber.erl
@@ -300,7 +300,7 @@ gen_encode_prim(_Erules,D,DoTag,Value) when record(D,type) ->
'ASN1_OPEN_TYPE' ->
emit_encode_func('open_type', Value,DoTag);
XX ->
- exit({'can not encode' ,XX})
+ exit({'cannot encode' ,XX})
end.
@@ -562,7 +562,7 @@ gen_dec_prim(Erules,Att,BytesVar,DoTag,TagIn,Length,_Form,OptOrMand) ->
BytesVar,","]),
false;
Other ->
- exit({'can not decode' ,Other})
+ exit({'cannot decode' ,Other})
end,
NewLength = case DoLength of
diff --git a/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber_bin_v2.erl b/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber_bin_v2.erl
index 9164ec6551..573bb15c92 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber_bin_v2.erl
+++ b/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber_bin_v2.erl
@@ -290,7 +290,7 @@ gen_encode_prim(_Erules,D,DoTag,Value) when record(D,type) ->
'ASN1_OPEN_TYPE' ->
emit_encode_func('open_type', Value,DoTag);
XX ->
- exit({'can not encode' ,XX})
+ exit({'cannot encode' ,XX})
end.
@@ -602,7 +602,7 @@ gen_dec_prim(_Erules,Att,BytesVar,DoTag,_TagIn,_Form,_OptOrMand) ->
BytesVar,","]),
add_func({decode_open_type_as_binary,2});
Other ->
- exit({'can not decode' ,Other})
+ exit({'cannot decode' ,Other})
end,
case {DoTag,NewTypeName} of
diff --git a/lib/dialyzer/test/r9c_SUITE_data/src/inets/mod_esi.erl b/lib/dialyzer/test/r9c_SUITE_data/src/inets/mod_esi.erl
index a48f73274b..52db2d9096 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/src/inets/mod_esi.erl
+++ b/lib/dialyzer/test/r9c_SUITE_data/src/inets/mod_esi.erl
@@ -285,7 +285,7 @@ eval(Info,"GET",CGIBody,Modules) ->
"~n Modules: ~p",[Modules]),
case auth(CGIBody,Modules) of
true ->
- case lib:eval_str(string:concat(CGIBody,". ")) of
+ case erl_eval:eval_str(string:concat(CGIBody,". ")) of
{error,Reason} ->
?vlog("eval -> error:"
"~n Reason: ~p",[Reason]),
diff --git a/lib/dialyzer/test/r9c_SUITE_data/src/inets/mod_responsecontrol.erl b/lib/dialyzer/test/r9c_SUITE_data/src/inets/mod_responsecontrol.erl
index a997db6880..53eeedc29f 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/src/inets/mod_responsecontrol.erl
+++ b/lib/dialyzer/test/r9c_SUITE_data/src/inets/mod_responsecontrol.erl
@@ -71,7 +71,7 @@ do_responsecontrol(Info) ->
%% If a client sends more then one of the if-XXXX fields in a request
-%% The standard says it does not specify the behaviuor so I specified it :-)
+%% The standard says it does not specify the behaviour so I specified it :-)
%% The priority between the fields is
%% 1.If-modified
%% 2.If-Unmodified
diff --git a/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_lib.erl b/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_lib.erl
index 4008f8d789..9e0cdac2dc 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_lib.erl
+++ b/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_lib.erl
@@ -779,7 +779,7 @@ error_desc(no_transaction) -> "Operation not allowed outside transactions";
error_desc(combine_error) -> "Table options were ilegally combined";
error_desc(bad_index) -> "Index already exists or was out of bounds";
error_desc(already_exists) -> "Some schema option we try to set is already on";
-error_desc(index_exists)-> "Some ops can not be performed on tabs with index";
+error_desc(index_exists)-> "Some ops cannot be performed on tabs with index";
error_desc(no_exists)-> "Tried to perform op on non-existing (non alive) item";
error_desc(system_limit) -> "Some system_limit was exhausted";
error_desc(mnesia_down) -> "A transaction involving objects at some remote "
diff --git a/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_tm.erl b/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_tm.erl
index 09e310530d..b4e9edb7ce 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_tm.erl
+++ b/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_tm.erl
@@ -1529,7 +1529,7 @@ commit_participant(Coord, Tid, Bin, C0, DiscNs, _RamNs) ->
?eval_debug_fun({?MODULE, commit_participant, pre}, [{tid, Tid}]),
case catch mnesia_schema:prepare_commit(Tid, C0, {part, Coord}) of
{Modified, C, DumperMode} when record(C, commit) ->
- %% If we can not find any local unclear decision
+ %% If we cannot find any local unclear decision
%% we should presume abort at startup recovery
case lists:member(node(), DiscNs) of
false ->
@@ -2051,7 +2051,7 @@ display_pid_info(Pid) ->
Other
end,
Reds = fetch(reductions, Info),
- LM = length(fetch(messages, Info)),
+ LM = fetch(message_queue_len, Info),
pformat(io_lib:format("~p", [Pid]),
io_lib:format("~p", [Call]),
io_lib:format("~p", [Curr]), Reds, LM)
diff --git a/lib/dialyzer/test/race_SUITE_data/dialyzer_options b/lib/dialyzer/test/race_SUITE_data/dialyzer_options
index 44e1720715..2be2f47dda 100644
--- a/lib/dialyzer/test/race_SUITE_data/dialyzer_options
+++ b/lib/dialyzer/test/race_SUITE_data/dialyzer_options
@@ -1 +1 @@
-{dialyzer_options, [{warnings, [race_conditions]}]}.
+{dialyzer_options, [{indent_opt, false}, {warnings, [race_conditions]}]}.
diff --git a/lib/dialyzer/test/race_SUITE_data/results/ets_insert_double1 b/lib/dialyzer/test/race_SUITE_data/results/ets_insert_double1
index b640b91271..2473bf5d01 100644
--- a/lib/dialyzer/test/race_SUITE_data/results/ets_insert_double1
+++ b/lib/dialyzer/test/race_SUITE_data/results/ets_insert_double1
@@ -1,4 +1,4 @@
ets_insert_double1.erl:15: The call ets:insert('foo',[{'pass',[number()]} | {'random',integer()},...]) might have an unintended effect due to a possible race condition caused by its combination with the ets:lookup('foo','random') call in ets_insert_double1.erl on line 10, the ets:lookup('foo','pass') call in ets_insert_double1.erl on line 27
ets_insert_double1.erl:19: The call ets:insert('foo',[{'pass',[number()]} | {'random',integer()},...]) might have an unintended effect due to a possible race condition caused by its combination with the ets:lookup('foo','random') call in ets_insert_double1.erl on line 10, the ets:lookup('foo','pass') call in ets_insert_double1.erl on line 27
-ets_insert_double1.erl:24: The call ets:insert('foo',{'pass','empty'}) might have an unintended effect due to a possible race condition caused by its combination with the ets:lookup('foo','pass') call in ets_insert_double1.erl on line 22
+ets_insert_double1.erl:24: The call ets:insert('foo',{'pass', 'empty'}) might have an unintended effect due to a possible race condition caused by its combination with the ets:lookup('foo','pass') call in ets_insert_double1.erl on line 22
diff --git a/lib/dialyzer/test/small_SUITE_data/dialyzer_options b/lib/dialyzer/test/small_SUITE_data/dialyzer_options
index 50991c9bc5..8413436b67 100644
--- a/lib/dialyzer/test/small_SUITE_data/dialyzer_options
+++ b/lib/dialyzer/test/small_SUITE_data/dialyzer_options
@@ -1 +1 @@
-{dialyzer_options, []}.
+{dialyzer_options, [{indent_opt, false}]}.
diff --git a/lib/dialyzer/test/small_SUITE_data/results/bs_fail_constr b/lib/dialyzer/test/small_SUITE_data/results/bs_fail_constr
index dbc8241971..797f83956d 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/bs_fail_constr
+++ b/lib/dialyzer/test/small_SUITE_data/results/bs_fail_constr
@@ -1,9 +1,9 @@
bs_fail_constr.erl:11: Function w3/1 has no local return
-bs_fail_constr.erl:12: Binary construction will fail since the size field S in segment 42:S/integer-unit:1 has type neg_integer()
+bs_fail_constr.erl:12: Binary construction will fail since the size field S in segment 42:S has type neg_integer()
bs_fail_constr.erl:14: Function w4/1 has no local return
bs_fail_constr.erl:15: Binary construction will fail since the value field V in segment V/utf32 has type float()
bs_fail_constr.erl:5: Function w1/1 has no local return
-bs_fail_constr.erl:6: Binary construction will fail since the value field V in segment V:8/integer-unit:1 has type float()
+bs_fail_constr.erl:6: Binary construction will fail since the value field V in segment V has type float()
bs_fail_constr.erl:8: Function w2/1 has no local return
-bs_fail_constr.erl:9: Binary construction will fail since the value field V in segment V/binary-unit:8 has type atom()
+bs_fail_constr.erl:9: Binary construction will fail since the value field V in segment V/binary has type atom()
diff --git a/lib/dialyzer/test/small_SUITE_data/results/chars b/lib/dialyzer/test/small_SUITE_data/results/chars
index 2c1f8f8d17..02797f2a59 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/chars
+++ b/lib/dialyzer/test/small_SUITE_data/results/chars
@@ -1,4 +1,4 @@
-chars.erl:29: Invalid type specification for function chars:f/1. The success typing is (#{'b':=50}) -> 'ok'
-chars.erl:32: Function t1/0 has no local return
-chars.erl:32: The call chars:f(#{'b':=50}) breaks the contract (#{'a':=49,'b'=>50,'c'=>51}) -> 'ok'
+chars.erl:37: Invalid type specification for function chars:f/1. The success typing is (#{'b':=50}) -> 'ok'
+chars.erl:40: Function t1/0 has no local return
+chars.erl:40: The call chars:f(#{'b'=>50}) breaks the contract (#{'a':=49,'b'=>50,'c'=>51}) -> 'ok'
diff --git a/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes b/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes
index d2a3ebb766..04336f43aa 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes
+++ b/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes
@@ -1,15 +1,15 @@
-contracts_with_subtypes.erl:106: The call contracts_with_subtypes:rec_arg({'a','b'}) breaks the contract (Arg) -> 'ok' when Arg :: {'a',A} | {'b',B}, A :: 'a' | {'b',B}, B :: 'b' | {'a',A}
-contracts_with_subtypes.erl:107: The call contracts_with_subtypes:rec_arg({'b','a'}) breaks the contract (Arg) -> 'ok' when Arg :: {'a',A} | {'b',B}, A :: 'a' | {'b',B}, B :: 'b' | {'a',A}
-contracts_with_subtypes.erl:109: The call contracts_with_subtypes:rec_arg({'b',{'a','b'}}) breaks the contract (Arg) -> 'ok' when Arg :: {'a',A} | {'b',B}, A :: 'a' | {'b',B}, B :: 'b' | {'a',A}
-contracts_with_subtypes.erl:135: The call contracts_with_subtypes:rec2({'a','b'}) breaks the contract (Arg) -> 'ok' when Arg :: ab()
-contracts_with_subtypes.erl:136: The call contracts_with_subtypes:rec2({'b','a'}) breaks the contract (Arg) -> 'ok' when Arg :: ab()
-contracts_with_subtypes.erl:137: The call contracts_with_subtypes:rec2({'a',{'b','a'}}) breaks the contract (Arg) -> 'ok' when Arg :: ab()
-contracts_with_subtypes.erl:138: The call contracts_with_subtypes:rec2({'b',{'a','b'}}) breaks the contract (Arg) -> 'ok' when Arg :: ab()
-contracts_with_subtypes.erl:139: The call contracts_with_subtypes:rec2({'a',{'b',{'a','b'}}}) breaks the contract (Arg) -> 'ok' when Arg :: ab()
-contracts_with_subtypes.erl:140: The call contracts_with_subtypes:rec2({'b',{'a',{'b','a'}}}) breaks the contract (Arg) -> 'ok' when Arg :: ab()
-contracts_with_subtypes.erl:141: The call contracts_with_subtypes:rec2({'a',{'b',{'a',{'b','a'}}}}) breaks the contract (Arg) -> 'ok' when Arg :: ab()
-contracts_with_subtypes.erl:142: The call contracts_with_subtypes:rec2({'b',{'a',{'b',{'a','b'}}}}) breaks the contract (Arg) -> 'ok' when Arg :: ab()
+contracts_with_subtypes.erl:106: The call contracts_with_subtypes:rec_arg({'a', 'b'}) breaks the contract (Arg) -> 'ok' when Arg :: {'a',A} | {'b',B}, A :: 'a' | {'b',B}, B :: 'b' | {'a',A}
+contracts_with_subtypes.erl:107: The call contracts_with_subtypes:rec_arg({'b', 'a'}) breaks the contract (Arg) -> 'ok' when Arg :: {'a',A} | {'b',B}, A :: 'a' | {'b',B}, B :: 'b' | {'a',A}
+contracts_with_subtypes.erl:109: The call contracts_with_subtypes:rec_arg({'b', {'a', 'b'}}) breaks the contract (Arg) -> 'ok' when Arg :: {'a',A} | {'b',B}, A :: 'a' | {'b',B}, B :: 'b' | {'a',A}
+contracts_with_subtypes.erl:135: The call contracts_with_subtypes:rec2({'a', 'b'}) breaks the contract (Arg) -> 'ok' when Arg :: ab()
+contracts_with_subtypes.erl:136: The call contracts_with_subtypes:rec2({'b', 'a'}) breaks the contract (Arg) -> 'ok' when Arg :: ab()
+contracts_with_subtypes.erl:137: The call contracts_with_subtypes:rec2({'a', {'b', 'a'}}) breaks the contract (Arg) -> 'ok' when Arg :: ab()
+contracts_with_subtypes.erl:138: The call contracts_with_subtypes:rec2({'b', {'a', 'b'}}) breaks the contract (Arg) -> 'ok' when Arg :: ab()
+contracts_with_subtypes.erl:139: The call contracts_with_subtypes:rec2({'a', {'b', {'a', 'b'}}}) breaks the contract (Arg) -> 'ok' when Arg :: ab()
+contracts_with_subtypes.erl:140: The call contracts_with_subtypes:rec2({'b', {'a', {'b', 'a'}}}) breaks the contract (Arg) -> 'ok' when Arg :: ab()
+contracts_with_subtypes.erl:141: The call contracts_with_subtypes:rec2({'a', {'b', {'a', {'b', 'a'}}}}) breaks the contract (Arg) -> 'ok' when Arg :: ab()
+contracts_with_subtypes.erl:142: The call contracts_with_subtypes:rec2({'b', {'a', {'b', {'a', 'b'}}}}) breaks the contract (Arg) -> 'ok' when Arg :: ab()
contracts_with_subtypes.erl:175: The pattern 1 can never match the type string()
contracts_with_subtypes.erl:178: The pattern 'alpha' can never match the type {'ok',_} | {'ok',_,string()}
contracts_with_subtypes.erl:180: The pattern 42 can never match the type {'ok',_} | {'ok',_,string()}
diff --git a/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes2 b/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes2
index 1a8aeb13d0..6d611db568 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes2
+++ b/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes2
@@ -1,3 +1,3 @@
contracts_with_subtypes2.erl:18: Function t/0 has no local return
-contracts_with_subtypes2.erl:19: The call contracts_with_subtypes2:t({'a',{'b',{'c',{'d',{'e',{'g',3}}}}}}) breaks the contract (Arg) -> 'ok' when Arg :: {'a',A}, A :: {'b',B}, B :: {'c',C}, C :: {'d',D}, D :: {'e',E}, E :: {'f',_}
+contracts_with_subtypes2.erl:19: The call contracts_with_subtypes2:t({'a', {'b', {'c', {'d', {'e', {'g', 3}}}}}}) breaks the contract (Arg) -> 'ok' when Arg :: {'a',A}, A :: {'b',B}, B :: {'c',C}, C :: {'d',D}, D :: {'e',E}, E :: {'f',_}
diff --git a/lib/dialyzer/test/small_SUITE_data/results/extra_range b/lib/dialyzer/test/small_SUITE_data/results/extra_range
new file mode 100644
index 0000000000..ec50c95c4e
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/extra_range
@@ -0,0 +1,4 @@
+
+extra_range.erl:29: The pattern 'ok' can never match the type 'error'
+extra_range.erl:43: The pattern 'no' can never match the type 'maybe' | 'yes'
+extra_range.erl:58: The pattern 'maybe' can never match the type 'no' | 'yes'
diff --git a/lib/dialyzer/test/small_SUITE_data/results/failing_guard1 b/lib/dialyzer/test/small_SUITE_data/results/failing_guard1
index 5bdd13093a..09fe076a6f 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/failing_guard1
+++ b/lib/dialyzer/test/small_SUITE_data/results/failing_guard1
@@ -1,4 +1,4 @@
failing_guard1.erl:12: Guard test float() =:= 2 can never succeed
-failing_guard1.erl:13: Guard test integer() =:= float() can never succeed
-failing_guard1.erl:14: Guard test -2 | -1 | 0 | 1 | 2 =:= float() can never succeed
+failing_guard1.erl:13: Guard test integer() =:= 2.0 can never succeed
+failing_guard1.erl:14: Guard test -2 | -1 | 0 | 1 | 2 =:= 2.0 can never succeed
diff --git a/lib/dialyzer/test/small_SUITE_data/results/fun_app_args b/lib/dialyzer/test/small_SUITE_data/results/fun_app_args
new file mode 100644
index 0000000000..ac153a6fb2
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/fun_app_args
@@ -0,0 +1,3 @@
+
+fun_app_args.erl:12: Fun application with arguments ('b',[]) will fail since the function has type 'c' | fun(('a',[]) -> any()), which differs in the 1st argument
+fun_app_args.erl:12: The created fun has no local return
diff --git a/lib/dialyzer/test/small_SUITE_data/results/fun_arity b/lib/dialyzer/test/small_SUITE_data/results/fun_arity
index e916b2483f..8b7a538758 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/fun_arity
+++ b/lib/dialyzer/test/small_SUITE_data/results/fun_arity
@@ -1,37 +1,37 @@
-fun_arity.erl:100: Fun application will fail since _@c1 :: fun(() -> any()) is not a function of arity 1
+fun_arity.erl:100: Fun application will fail since _1 :: fun(() -> any()) is not a function of arity 1
fun_arity.erl:100: Function 'Mfa_0_ko'/1 has no local return
-fun_arity.erl:104: Fun application will fail since _@c1 :: fun((_) -> any()) is not a function of arity 0
+fun_arity.erl:104: Fun application will fail since _1 :: fun((_) -> any()) is not a function of arity 0
fun_arity.erl:104: Function 'Mfa_1_ko'/1 has no local return
-fun_arity.erl:111: Fun application will fail since _@c1 :: fun(() -> any()) is not a function of arity 1
+fun_arity.erl:111: Fun application will fail since _1 :: fun(() -> any()) is not a function of arity 1
fun_arity.erl:111: Function mFa_0_ko/1 has no local return
-fun_arity.erl:115: Fun application will fail since _@c1 :: fun((_) -> any()) is not a function of arity 0
+fun_arity.erl:115: Fun application will fail since _1 :: fun((_) -> any()) is not a function of arity 0
fun_arity.erl:115: Function mFa_1_ko/1 has no local return
-fun_arity.erl:122: Fun application will fail since _@c2 :: fun(() -> any()) is not a function of arity 1
+fun_arity.erl:122: Fun application will fail since _2 :: fun(() -> any()) is not a function of arity 1
fun_arity.erl:122: Function 'MFa_0_ko'/2 has no local return
-fun_arity.erl:126: Fun application will fail since _@c2 :: fun((_) -> any()) is not a function of arity 0
+fun_arity.erl:126: Fun application will fail since _2 :: fun((_) -> any()) is not a function of arity 0
fun_arity.erl:126: Function 'MFa_1_ko'/2 has no local return
-fun_arity.erl:35: Fun application will fail since _@c0 :: fun(() -> 'ok') is not a function of arity 1
+fun_arity.erl:35: Fun application will fail since _0 :: fun(() -> 'ok') is not a function of arity 1
fun_arity.erl:35: Function f_0_ko/0 has no local return
-fun_arity.erl:39: Fun application will fail since _@c0 :: fun((_) -> 'ok') is not a function of arity 0
+fun_arity.erl:39: Fun application will fail since _0 :: fun((_) -> 'ok') is not a function of arity 0
fun_arity.erl:39: Function f_1_ko/0 has no local return
-fun_arity.erl:48: Fun application will fail since _@c0 :: fun(() -> 'ok') is not a function of arity 1
+fun_arity.erl:48: Fun application will fail since _0 :: fun(() -> 'ok') is not a function of arity 1
fun_arity.erl:48: Function fa_0_ko/0 has no local return
-fun_arity.erl:53: Fun application will fail since _@c0 :: fun((_) -> 'ok') is not a function of arity 0
+fun_arity.erl:53: Fun application will fail since _0 :: fun((_) -> 'ok') is not a function of arity 0
fun_arity.erl:53: Function fa_1_ko/0 has no local return
-fun_arity.erl:63: Fun application will fail since _@c0 :: fun(() -> any()) is not a function of arity 1
+fun_arity.erl:63: Fun application will fail since _0 :: fun(() -> any()) is not a function of arity 1
fun_arity.erl:63: Function mfa_0_ko/0 has no local return
-fun_arity.erl:68: Fun application will fail since _@c0 :: fun((_) -> any()) is not a function of arity 0
+fun_arity.erl:68: Fun application will fail since _0 :: fun((_) -> any()) is not a function of arity 0
fun_arity.erl:68: Function mfa_1_ko/0 has no local return
-fun_arity.erl:76: Fun application will fail since _@c0 :: fun(() -> any()) is not a function of arity 1
+fun_arity.erl:76: Fun application will fail since _0 :: fun(() -> any()) is not a function of arity 1
fun_arity.erl:76: Function mfa_ne_0_ko/0 has no local return
fun_arity.erl:78: Function mf_ne/0 will never be called
-fun_arity.erl:81: Fun application will fail since _@c0 :: fun((_) -> any()) is not a function of arity 0
+fun_arity.erl:81: Fun application will fail since _0 :: fun((_) -> any()) is not a function of arity 0
fun_arity.erl:81: Function mfa_ne_1_ko/0 has no local return
fun_arity.erl:83: Function mf_ne/1 will never be called
-fun_arity.erl:89: Fun application will fail since _@c0 :: fun(() -> any()) is not a function of arity 1
+fun_arity.erl:89: Fun application will fail since _0 :: fun(() -> any()) is not a function of arity 1
fun_arity.erl:89: Function mfa_nd_0_ko/0 has no local return
fun_arity.erl:90: Call to missing or unexported function fun_arity:mf_nd/0
-fun_arity.erl:93: Fun application will fail since _@c0 :: fun((_) -> any()) is not a function of arity 0
+fun_arity.erl:93: Fun application will fail since _0 :: fun((_) -> any()) is not a function of arity 0
fun_arity.erl:93: Function mfa_nd_1_ko/0 has no local return
fun_arity.erl:94: Call to missing or unexported function fun_arity:mf_nd/1
diff --git a/lib/dialyzer/test/small_SUITE_data/results/guard_warnings b/lib/dialyzer/test/small_SUITE_data/results/guard_warnings
index 0ff998bf50..14b7a9052c 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/guard_warnings
+++ b/lib/dialyzer/test/small_SUITE_data/results/guard_warnings
@@ -1,6 +1,6 @@
guard_warnings.erl:100: Function test45/0 has no local return
-guard_warnings.erl:100: Guard test 'not'('true') can never succeed
+guard_warnings.erl:100: Guard test not('true') can never succeed
guard_warnings.erl:102: Function test46/1 has no local return
guard_warnings.erl:102: Guard test X::'true' =:= 'false' can never succeed
guard_warnings.erl:104: Function test47/1 has no local return
@@ -14,79 +14,79 @@ guard_warnings.erl:12: Guard test X::'true' =:= 'false' can never succeed
guard_warnings.erl:14: Function test2/1 has no local return
guard_warnings.erl:14: Guard test X::'false' =:= 'true' can never succeed
guard_warnings.erl:16: Function test3/1 has no local return
-guard_warnings.erl:16: Guard test 'not'(X::'true') can never succeed
+guard_warnings.erl:16: Guard test not(X::'true') can never succeed
guard_warnings.erl:18: Function test4/1 has no local return
-guard_warnings.erl:18: Guard test 'and'('true',X::none()) can never succeed
+guard_warnings.erl:18: Guard test and('true',X::none()) can never succeed
guard_warnings.erl:20: Function test5/1 has no local return
-guard_warnings.erl:20: Guard test 'not'(X::'true') can never succeed
+guard_warnings.erl:20: Guard test not(X::'true') can never succeed
guard_warnings.erl:22: Function test6/1 has no local return
-guard_warnings.erl:22: Guard test 'and'('true',X::none()) can never succeed
+guard_warnings.erl:22: Guard test and('true',X::none()) can never succeed
guard_warnings.erl:24: Function test7_w/1 has no local return
guard_warnings.erl:26: Function test8_w/1 has no local return
guard_warnings.erl:28: Function test9/1 has no local return
-guard_warnings.erl:28: Guard test not('not'(X::'false')) can never succeed
+guard_warnings.erl:28: Guard test not(not(X::'false')) can never succeed
guard_warnings.erl:30: Function test10/1 has no local return
-guard_warnings.erl:30: Guard test not('or'('false',X::none())) can never succeed
+guard_warnings.erl:30: Guard test not(or('false',X::none())) can never succeed
guard_warnings.erl:32: Function test11/1 has no local return
-guard_warnings.erl:32: Guard test not('not'(X::'false')) can never succeed
+guard_warnings.erl:32: Guard test not(not(X::'false')) can never succeed
guard_warnings.erl:34: Function test12/1 has no local return
-guard_warnings.erl:34: Guard test not('or'('false',X::none())) can never succeed
+guard_warnings.erl:34: Guard test not(or('false',X::none())) can never succeed
guard_warnings.erl:36: Function test13/1 has no local return
-guard_warnings.erl:36: Guard test 'and'('true','false') can never succeed
+guard_warnings.erl:36: Guard test and('true','false') can never succeed
guard_warnings.erl:38: Function test14/1 has no local return
-guard_warnings.erl:38: Guard test 'and'('false',any()) can never succeed
+guard_warnings.erl:38: Guard test and('false',any()) can never succeed
guard_warnings.erl:40: Function test15/1 has no local return
-guard_warnings.erl:40: Guard test 'and'(X::'true','false') can never succeed
+guard_warnings.erl:40: Guard test and(X::'true','false') can never succeed
guard_warnings.erl:42: Function test16/1 has no local return
-guard_warnings.erl:42: Guard test 'and'('false',X::any()) can never succeed
+guard_warnings.erl:42: Guard test and('false',X::any()) can never succeed
guard_warnings.erl:44: Function test17/1 has no local return
-guard_warnings.erl:44: Guard test 'and'(X::'true','false') can never succeed
+guard_warnings.erl:44: Guard test and(X::'true','false') can never succeed
guard_warnings.erl:46: Function test18/1 has no local return
-guard_warnings.erl:46: Guard test 'and'('false',X::any()) can never succeed
+guard_warnings.erl:46: Guard test and('false',X::any()) can never succeed
guard_warnings.erl:48: Function test19/1 has no local return
-guard_warnings.erl:48: Guard test not('or'('true',any())) can never succeed
+guard_warnings.erl:48: Guard test not(or('true',any())) can never succeed
guard_warnings.erl:50: Function test20/1 has no local return
-guard_warnings.erl:50: Guard test not('or'('false','true')) can never succeed
+guard_warnings.erl:50: Guard test not(or('false','true')) can never succeed
guard_warnings.erl:52: Function test21/1 has no local return
-guard_warnings.erl:52: Guard test not('or'('true',X::any())) can never succeed
+guard_warnings.erl:52: Guard test not(or('true',X::any())) can never succeed
guard_warnings.erl:54: Function test22/1 has no local return
-guard_warnings.erl:54: Guard test not('or'(X::'false','true')) can never succeed
+guard_warnings.erl:54: Guard test not(or(X::'false','true')) can never succeed
guard_warnings.erl:56: Function test23/1 has no local return
-guard_warnings.erl:56: Guard test not('or'('true',X::any())) can never succeed
+guard_warnings.erl:56: Guard test not(or('true',X::any())) can never succeed
guard_warnings.erl:58: Function test24/1 has no local return
-guard_warnings.erl:58: Guard test not('or'(X::'false','true')) can never succeed
+guard_warnings.erl:58: Guard test not(or(X::'false','true')) can never succeed
guard_warnings.erl:60: Function test25/1 has no local return
-guard_warnings.erl:60: Guard test 'and'('false',any()) can never succeed
+guard_warnings.erl:60: Guard test and('false',any()) can never succeed
guard_warnings.erl:62: Function test26/1 has no local return
-guard_warnings.erl:62: Guard test 'and'('true','false') can never succeed
+guard_warnings.erl:62: Guard test and('true','false') can never succeed
guard_warnings.erl:64: Function test27/1 has no local return
-guard_warnings.erl:64: Guard test 'and'('false',X::any()) can never succeed
+guard_warnings.erl:64: Guard test and('false',X::any()) can never succeed
guard_warnings.erl:66: Function test28/1 has no local return
-guard_warnings.erl:66: Guard test 'and'(X::'true','false') can never succeed
+guard_warnings.erl:66: Guard test and(X::'true','false') can never succeed
guard_warnings.erl:68: Function test29/1 has no local return
-guard_warnings.erl:68: Guard test 'and'('false',X::any()) can never succeed
+guard_warnings.erl:68: Guard test and('false',X::any()) can never succeed
guard_warnings.erl:70: Function test30/1 has no local return
-guard_warnings.erl:70: Guard test 'and'(X::'true','false') can never succeed
+guard_warnings.erl:70: Guard test and(X::'true','false') can never succeed
guard_warnings.erl:72: Function test31/0 has no local return
-guard_warnings.erl:72: Guard test 'and'('false',any()) can never succeed
+guard_warnings.erl:72: Guard test and('false','false') can never succeed
guard_warnings.erl:74: Function test32/0 has no local return
-guard_warnings.erl:74: Guard test 'and'('false',any()) can never succeed
+guard_warnings.erl:74: Guard test and('false','false') can never succeed
guard_warnings.erl:76: Function test33/0 has no local return
-guard_warnings.erl:76: Guard test not('and'('true','true')) can never succeed
+guard_warnings.erl:76: Guard test not(and('true','true')) can never succeed
guard_warnings.erl:78: Function test34/0 has no local return
-guard_warnings.erl:78: Guard test 'and'('false',any()) can never succeed
+guard_warnings.erl:78: Guard test and('false','false') can never succeed
guard_warnings.erl:80: Function test35/0 has no local return
-guard_warnings.erl:80: Guard test not('and'('true','true')) can never succeed
+guard_warnings.erl:80: Guard test not(and('true','true')) can never succeed
guard_warnings.erl:82: Function test36/0 has no local return
-guard_warnings.erl:82: Guard test 'or'('false','false') can never succeed
+guard_warnings.erl:82: Guard test or('false','false') can never succeed
guard_warnings.erl:84: Function test37/0 has no local return
-guard_warnings.erl:84: Guard test 'or'('false','false') can never succeed
+guard_warnings.erl:84: Guard test or('false','false') can never succeed
guard_warnings.erl:86: Function test38/0 has no local return
-guard_warnings.erl:86: Guard test 'or'('false','false') can never succeed
+guard_warnings.erl:86: Guard test or('false','false') can never succeed
guard_warnings.erl:88: Function test39/0 has no local return
-guard_warnings.erl:88: Guard test 'or'('false','false') can never succeed
+guard_warnings.erl:88: Guard test or('false','false') can never succeed
guard_warnings.erl:90: Function test40/0 has no local return
-guard_warnings.erl:90: Guard test 'or'('false','false') can never succeed
+guard_warnings.erl:90: Guard test or('false','false') can never succeed
guard_warnings.erl:92: Function test41/0 has no local return
guard_warnings.erl:92: Guard test 'true' =:= 'false' can never succeed
guard_warnings.erl:94: Function test42/0 has no local return
diff --git a/lib/dialyzer/test/small_SUITE_data/results/left_assoc b/lib/dialyzer/test/small_SUITE_data/results/left_assoc
new file mode 100644
index 0000000000..58cdad29de
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/left_assoc
@@ -0,0 +1,2 @@
+
+left_assoc.erl:93: The variable __@2 can never match since previous clauses completely covered the type binary()
diff --git a/lib/dialyzer/test/small_SUITE_data/results/maps_sum b/lib/dialyzer/test/small_SUITE_data/results/maps_sum
index bd192bdb93..daa099e490 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/maps_sum
+++ b/lib/dialyzer/test/small_SUITE_data/results/maps_sum
@@ -1,4 +1,4 @@
-maps_sum.erl:15: Invalid type specification for function maps_sum:wrong1/1. The success typing is (map()) -> any()
+maps_sum.erl:15: Invalid type specification for function maps_sum:wrong1/1. The success typing is (maps:iterator(_,_) | map()) -> any()
maps_sum.erl:26: Function wrong2/1 has no local return
maps_sum.erl:27: The call lists:foldl(fun((_,_,_) -> any()),0,Data::any()) will never return since it differs in the 1st argument from the success typing arguments: (fun((_,_) -> any()),any(),[any()])
diff --git a/lib/dialyzer/test/small_SUITE_data/results/pretty_bitstring b/lib/dialyzer/test/small_SUITE_data/results/pretty_bitstring
index e148e5cf22..dc3620fcf0 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/pretty_bitstring
+++ b/lib/dialyzer/test/small_SUITE_data/results/pretty_bitstring
@@ -1,3 +1,3 @@
pretty_bitstring.erl:7: Function t/0 has no local return
-pretty_bitstring.erl:8: The call binary:copy(#{#<1>(8, 1, 'integer', ['unsigned', 'big']), #<2>(8, 1, 'integer', ['unsigned', 'big']), #<3>(3, 1, 'integer', ['unsigned', 'big'])}#,2) breaks the contract (Subject,N) -> binary() when Subject :: binary(), N :: non_neg_integer()
+pretty_bitstring.erl:8: The call binary:copy(<<1,2,3:3>>,2) breaks the contract (Subject,N) -> binary() when Subject :: binary(), N :: non_neg_integer()
diff --git a/lib/dialyzer/test/small_SUITE_data/results/stacktrace b/lib/dialyzer/test/small_SUITE_data/results/stacktrace
new file mode 100644
index 0000000000..fd60881953
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/stacktrace
@@ -0,0 +1,5 @@
+
+stacktrace.erl:11: The pattern {'a', 'b'} can never match the type [{atom(),atom(),[any()] | byte(),[{'file',string()} | {'line',pos_integer()}]}]
+stacktrace.erl:19: The pattern ['a', 'b'] can never match the type [{atom(),atom(),[any()] | byte(),[{'file',string()} | {'line',pos_integer()}]}]
+stacktrace.erl:44: The pattern {'a', 'b'} can never match the type [{atom(),atom(),[any()] | byte(),[{'file',string()} | {'line',pos_integer()}]}]
+stacktrace.erl:53: The pattern ['a', 'b'] can never match the type [{atom(),atom(),[any()] | byte(),[{'file',string()} | {'line',pos_integer()}]}]
diff --git a/lib/dialyzer/test/small_SUITE_data/results/tuple_set_crash b/lib/dialyzer/test/small_SUITE_data/results/tuple_set_crash
index 8c9df56a4b..7fd1f304cb 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/tuple_set_crash
+++ b/lib/dialyzer/test/small_SUITE_data/results/tuple_set_crash
@@ -3,12 +3,12 @@ tuple_set_crash.erl:103: Invalid type specification for function tuple_set_crash
tuple_set_crash.erl:123: Invalid type specification for function tuple_set_crash:parse_video_target_info/1. The success typing is (<<_:48>>) -> [{'status',byte()} | {'target_id',non_neg_integer()},...]
tuple_set_crash.erl:127: Invalid type specification for function tuple_set_crash:parse_audio_target_info/1. The success typing is (<<_:48>>) -> [{'master_volume',char()} | {'status',byte()} | {'target_id',non_neg_integer()},...]
tuple_set_crash.erl:138: Invalid type specification for function tuple_set_crash:parse_av_device_info/1. The success typing is (<<_:48>>) -> [{'address',byte()} | {'device_id',non_neg_integer()} | {'model',binary()} | {'status',byte()},...]
-tuple_set_crash.erl:143: The pattern <<TargetId:32/integer-little-unit:1,Rest1/binary-unit:8>> can never match the type <<_:8>>
+tuple_set_crash.erl:143: The pattern <<TargetId:32/integer-little-unit:1,Rest1/binary>> can never match the type <<_:8>>
tuple_set_crash.erl:155: Invalid type specification for function tuple_set_crash:parse_video_output_info/1. The success typing is (<<_:48>>) -> [{'audio_volume',char()} | {'display_type',binary()} | {'output_id',non_neg_integer()},...]
-tuple_set_crash.erl:160: The pattern <<DeviceId:32/integer-little-unit:1,Rest1/binary-unit:8>> can never match the type <<_:8>>
+tuple_set_crash.erl:160: The pattern <<DeviceId:32/integer-little-unit:1,Rest1/binary>> can never match the type <<_:8>>
tuple_set_crash.erl:171: Invalid type specification for function tuple_set_crash:parse_audio_output_info/1. The success typing is (<<_:48>>) -> [{'output_id',non_neg_integer()},...]
-tuple_set_crash.erl:176: The pattern <<DeviceId:32/integer-little-unit:1,Rest1/binary-unit:8>> can never match the type <<_:8>>
-tuple_set_crash.erl:179: The pattern <<AudioVolume:16/integer-little-unit:1,Rest2/binary-unit:8>> can never match the type <<_:8>>
-tuple_set_crash.erl:182: The pattern <<Delay:16/integer-little-unit:1,_Padding/binary-unit:8>> can never match the type <<_:8>>
+tuple_set_crash.erl:176: The pattern <<DeviceId:32/integer-little-unit:1,Rest1/binary>> can never match the type <<_:8>>
+tuple_set_crash.erl:179: The pattern <<AudioVolume:16/integer-little-unit:1,Rest2/binary>> can never match the type <<_:8>>
+tuple_set_crash.erl:182: The pattern <<Delay:16/integer-little-unit:1,_Padding/binary>> can never match the type <<_:8>>
tuple_set_crash.erl:62: The pattern {'play_list', _Playlist} can never match the type 'ok' | {'device_properties',[{atom(),_}]} | {'error',[{atom(),_}]}
tuple_set_crash.erl:64: The pattern {'error', 17} can never match the type 'ok' | {'device_properties',[{atom(),_}]} | {'error',[{atom(),_}]}
diff --git a/lib/dialyzer/test/small_SUITE_data/results/union_paren b/lib/dialyzer/test/small_SUITE_data/results/union_paren
new file mode 100644
index 0000000000..3a3526df89
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/union_paren
@@ -0,0 +1,7 @@
+
+union_paren.erl:12: Function t2/0 has no local return
+union_paren.erl:13: The call union_paren:t2(3.14) breaks the contract (integer() | atom()) -> integer()
+union_paren.erl:19: Function t3/0 has no local return
+union_paren.erl:20: The pattern 3.14 can never match the type atom() | integer()
+union_paren.erl:5: Function t1/0 has no local return
+union_paren.erl:6: The call union_paren:t1(3.14) breaks the contract ((A::integer()) | (B::atom())) -> integer()
diff --git a/lib/dialyzer/test/small_SUITE_data/results/unused_funs b/lib/dialyzer/test/small_SUITE_data/results/unused_funs
new file mode 100644
index 0000000000..c468457ead
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/unused_funs
@@ -0,0 +1,5 @@
+
+unused_funs.erl:10: The pattern 'error' can never match the type 'other_error'
+unused_funs.erl:15: Function not_used/0 will never be called
+unused_funs.erl:19: Function foo/1 will never be called
+unused_funs.erl:7: Function test/0 has no local return
diff --git a/lib/dialyzer/test/small_SUITE_data/src/chars.erl b/lib/dialyzer/test/small_SUITE_data/src/chars.erl
index 1e9c8ab6b9..62b90cf54d 100644
--- a/lib/dialyzer/test/small_SUITE_data/src/chars.erl
+++ b/lib/dialyzer/test/small_SUITE_data/src/chars.erl
@@ -12,17 +12,25 @@
-spec t() -> $0-$0..$9-$0| $?.
t() ->
- c(#r{f = $z - 3}),
+ r(#r{f = $z - 3}),
+ r(#r{f = 97}),
+ c($/),
c($z - 3),
c($B).
-spec c(cs()) -> $3-$0..$9-$0.
-
-c($A + 1) -> 2;
+c($A + 1) -> $9-$0;
c(C) ->
case C of
- $z - 3 -> 3;
- #r{f = $z - 3} -> 7
+ $z - 3 -> $3-$0;
+ _ -> $7-$0
+ end.
+
+-spec r(#r{f :: $a..$z}) -> ok | error.
+r(R) ->
+ case R of
+ #r{f = $z - 3} -> error;
+ _ -> ok
end.
%% Display contract with character in warning:
diff --git a/lib/dialyzer/test/small_SUITE_data/src/extra_range.erl b/lib/dialyzer/test/small_SUITE_data/src/extra_range.erl
new file mode 100644
index 0000000000..9d6ba89c95
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/extra_range.erl
@@ -0,0 +1,59 @@
+%% Test that a spec containing more items than actually returned
+%% (whether by accident or by benign overspeccing) does not prevent
+%% detection of impossible matches.
+
+-module(extra_range).
+
+-export([t1/2, t2/2, t3/2, t4/2]).
+
+-dialyzer([no_return]).
+
+%% this spec matches the behaviour of the code
+-spec normal(integer()) -> ok | error.
+normal(1) -> ok;
+normal(2) -> error.
+
+t1(X, Y) when is_integer(X), is_integer(Y) ->
+ ok = normal(X),
+ error = normal(Y),
+ ok.
+
+
+%% this spec has a typo, which should cause anyone trying to match on
+%% `ok = typo(X)' to get a warning, because `ok' is not in the spec
+-spec typo(integer()) -> ook | error.
+typo(1) -> ok;
+typo(2) -> error.
+
+t2(X, Y) when is_integer(X), is_integer(Y) ->
+ ok = typo(X), % warning expected - not allowed according to spec
+ error = typo(Y),
+ ok.
+
+
+%% this is overspecified, and should cause a warning for trying
+%% to match on `no = over(X)', because it cannot succeed and either
+%% the spec should be updated or the code should be extended
+-spec over(integer()) -> yes | no | maybe.
+over(1) -> yes;
+over(_) -> maybe.
+
+t3(X, Y) when is_integer(X), is_integer(Y) ->
+ yes = over(X),
+ no = over(Y), % warning expected - spec or code needs fixing
+ maybe = over(X + Y),
+ ok.
+
+
+%% this is underspecified, which should cause anyone trying to match on
+%% `maybe = under(X)' to get a warning, because `maybe' is not in the spec
+-spec under(integer()) -> yes | no.
+under(1) -> yes;
+under(2) -> no;
+under(_) -> maybe.
+
+t4(X, Y) when is_integer(X), is_integer(Y) ->
+ yes = under(X),
+ no = under(Y),
+ maybe = under(X + Y), % warning expected - not in spec
+ ok.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/fun_app_args.erl b/lib/dialyzer/test/small_SUITE_data/src/fun_app_args.erl
new file mode 100644
index 0000000000..b4409bc550
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/fun_app_args.erl
@@ -0,0 +1,12 @@
+-module(fun_app_args).
+
+-export([t/1]).
+
+-type ft() :: fun((a, []) -> any()).
+
+-record(r, {
+ h = c :: c | ft()
+}).
+
+t(#r{h = H}) ->
+ fun(_) -> (H)(b, []) end.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/left_assoc.erl b/lib/dialyzer/test/small_SUITE_data/src/left_assoc.erl
new file mode 100644
index 0000000000..0250e4ab49
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/left_assoc.erl
@@ -0,0 +1,96 @@
+-module(left_assoc).
+
+%% As pointed out in ERL-680, analyzing guards with short circuit
+%% operators becomes very slow as the number of left associations
+%% grows.
+
+-spec from_iso8601('Elixir.String':t(), 'Elixir.Calendar':calendar()) ->
+ {ok, t()} | {error, atom()}.
+
+-export_type([t/0]).
+
+-type t() ::
+ #{'__struct__' := 'Elixir.Date',
+ calendar := 'Elixir.Calendar':calendar(),
+ day := 'Elixir.Calendar':day(),
+ month := 'Elixir.Calendar':month(),
+ year := 'Elixir.Calendar':year()}.
+
+-export([from_iso8601/1,
+ from_iso8601/2]).
+
+from_iso8601(__@1) ->
+ from_iso8601(__@1, 'Elixir.Calendar.ISO').
+
+from_iso8601(<<45/integer,_rest@1/binary>>, _calendar@1) ->
+ case raw_from_iso8601(_rest@1, _calendar@1) of
+ {ok,#{year := _year@1} = _date@1} ->
+ {ok,_date@1#{year := - _year@1}};
+ __@1 ->
+ __@1
+ end;
+from_iso8601(<<_rest@1/binary>>, _calendar@1) ->
+ raw_from_iso8601(_rest@1, _calendar@1).
+
+raw_from_iso8601(_string@1, _calendar@1) ->
+ case _string@1 of
+ <<_y1@1/integer,
+ _y2@1/integer,
+ _y3@1/integer,
+ _y4@1/integer,
+ 45/integer,
+ _m1@1/integer,
+ _m2@1/integer,
+ 45/integer,
+ _d1@1/integer,
+ _d2@1/integer>>
+ when
+ ((((((((((((((_y1@1 >= 48
+ andalso
+ _y1@1 =< 57)
+ andalso
+ _y2@1 >= 48)
+ andalso
+ _y2@1 =< 57)
+ andalso
+ _y3@1 >= 48)
+ andalso
+ _y3@1 =< 57)
+ andalso
+ _y4@1 >= 48)
+ andalso
+ _y4@1 =< 57)
+ andalso
+ _m1@1 >= 48)
+ andalso
+ _m1@1 =< 57)
+ andalso
+ _m2@1 >= 48)
+ andalso
+ _m2@1 =< 57)
+ andalso
+ _d1@1 >= 48)
+ andalso
+ _d1@1 =< 57)
+ andalso
+ _d2@1 >= 48)
+ andalso
+ _d2@1 =< 57 ->
+ {ok,
+ #{year => (_y1@1 - 48) * 1000 + (_y2@1 - 48) * 100
+ +
+ (_y3@1 - 48) * 10
+ +
+ (_y4@1 - 48),
+ month => (_m1@1 - 48) * 10 + (_m2@1 - 48),
+ day => (_d1@1 - 48) * 10 + (_d2@1 - 48),
+ calendar => _calendar@1,
+ '__struct__' => 'Elixir.Date'}};
+ __@1 ->
+ case __@1 of
+ _ ->
+ {error,invalid_format};
+ __@2 ->
+ error({with_clause,__@2})
+ end
+ end.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/lists_key_bug.erl b/lib/dialyzer/test/small_SUITE_data/src/lists_key_bug.erl
new file mode 100644
index 0000000000..ad5cf3c503
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/lists_key_bug.erl
@@ -0,0 +1,75 @@
+-module(lists_key_bug).
+
+%% OTP-15570
+
+-export([is_1/1, is_2/1, i/1, t1/0, t2/0, im/0]).
+
+%% int_set([3])
+is_1(V) ->
+ K = ikey(V),
+ case lists:keyfind(K, 1, [{<<"foo">>, bar}]) of
+ false ->
+ a;
+ {_, _} ->
+ b
+ end.
+
+ikey(1) ->
+ 3;
+ikey(2) ->
+ <<"foo">>.
+
+%% int_set([3, 5])
+is_2(V) ->
+ K = iskey(V),
+ case lists:keyfind(K, 1, [{<<"foo">>, bar}]) of
+ false ->
+ a;
+ {_, _} ->
+ b
+ end.
+
+iskey(1) ->
+ 12;
+iskey(2) ->
+ 14;
+iskey(3) ->
+ <<"foo">>.
+
+%% integer()
+i(V) ->
+ K = intkey(V),
+ case lists:keyfind(K, 1, [{9.0, foo}]) of
+ false ->
+ a;
+ {_, _} ->
+ b
+ end.
+
+intkey(K) when is_integer(K) ->
+ K + 9999.
+
+t1() ->
+ case lists:keyfind({17}, 1, [{{17.0}, true}]) of
+ false ->
+ a;
+ {_, _} ->
+ b
+ end.
+
+t2() ->
+ case lists:keyfind({17.0}, 1, [{{17}, true}]) of
+ false ->
+ a;
+ {_, _} ->
+ b
+ end.
+
+%% Note: #{1.0 => a} =/= #{1 => a}.
+im() ->
+ case lists:keyfind(#{1.0 => a}, 1, [{#{1 => a}, foo}]) of
+ false ->
+ a;
+ {_, _} ->
+ b
+ end.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/stacktrace.erl b/lib/dialyzer/test/small_SUITE_data/src/stacktrace.erl
new file mode 100644
index 0000000000..de79e710e9
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/stacktrace.erl
@@ -0,0 +1,73 @@
+-module(stacktrace).
+
+%% Check the stacktrace variable introduced in Erlang/OTP 21.0
+
+-export([t1/0, t2/0, t3/0, t4/0, s1/0, s2/0, s3/0, s4/0]).
+
+t1() ->
+ try foo:bar()
+ catch
+ E:P:S ->
+ {a,b} = S, % can never match
+ {E, P}
+ end.
+
+t2() ->
+ try foo:bar()
+ catch
+ E:P:S ->
+ [a,b] = S, % can never match
+ {E, P}
+ end.
+
+t3() ->
+ try foo:bar()
+ catch
+ E:P:S ->
+ [{m,f,[],[]}] = S,
+ {E, P}
+ end.
+
+t4() ->
+ try foo:bar()
+ catch
+ E:P:S ->
+ [{m,f,1,[{file,"tjo"},{line,95}]}] = S,
+ {E, P}
+ end.
+
+s1() ->
+ try foo:bar()
+ catch
+ E:P ->
+ S = erlang:get_stacktrace(),
+ {a,b} = S, % can never match
+ {E, P}
+ end.
+
+s2() ->
+ try foo:bar()
+ catch
+ E:P ->
+ S = erlang:get_stacktrace(),
+ [a,b] = S, % can never match
+ {E, P}
+ end.
+
+s3() ->
+ try foo:bar()
+ catch
+ E:P ->
+ S = erlang:get_stacktrace(),
+ [{m,f,[],[]}] = S,
+ {E, P}
+ end.
+
+s4() ->
+ try foo:bar()
+ catch
+ E:P ->
+ S = erlang:get_stacktrace(),
+ [{m,f,1,[{file,"tjo"},{line,95}]}] = S,
+ {E, P}
+ end.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/union_paren.erl b/lib/dialyzer/test/small_SUITE_data/src/union_paren.erl
new file mode 100644
index 0000000000..4691a57d98
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/union_paren.erl
@@ -0,0 +1,24 @@
+-module(union_paren).
+
+-compile(export_all).
+
+t1() ->
+ t1(3.14).
+
+-spec t1((A :: integer()) | (B :: atom())) -> integer().
+t1(A) ->
+ fy:bar(A).
+
+t2() ->
+ t2(3.14).
+
+-spec t2(integer() | atom()) -> integer().
+t2(A) ->
+ fy:bar(A).
+
+t3() ->
+ 3.14 = t3(foo).
+
+-spec t3(_) -> (I :: integer()) | (A :: atom()).
+t3(A) when is_atom(A) -> A;
+t3(I) when is_integer(I) -> I.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/unused_funs.erl b/lib/dialyzer/test/small_SUITE_data/src/unused_funs.erl
new file mode 100644
index 0000000000..c24cf3ea81
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/unused_funs.erl
@@ -0,0 +1,21 @@
+%% See also ERL-593.
+
+-module(unused_funs).
+
+-export([test/0]).
+
+test() -> % "has no local return"
+ Var = outer_scope,
+ case other_error of
+ error -> % "can never match"
+ %% No warnings "no local return" and "_ = 1 can never match 0" (!)
+ foo(fun() -> {Var, 1 = 0} end)
+ end.
+
+not_used() -> % "will never be called"
+ %% No warnings "no local return" and "1 can never match 0".
+ foo(fun() -> 1 = 0 end).
+
+foo(Fun) -> % "will never be called"
+ 1 = 0, % No pattern match warning (foo/1 is not traversed at all).
+ Fun().
diff --git a/lib/dialyzer/test/specdiffs_SUITE_data/dialyzer_options b/lib/dialyzer/test/specdiffs_SUITE_data/dialyzer_options
new file mode 100644
index 0000000000..f7076e34da
--- /dev/null
+++ b/lib/dialyzer/test/specdiffs_SUITE_data/dialyzer_options
@@ -0,0 +1 @@
+{dialyzer_options, [{indent_opt, false}, {warnings, [specdiffs]}]}.
diff --git a/lib/dialyzer/test/specdiffs_SUITE_data/results/iodata b/lib/dialyzer/test/specdiffs_SUITE_data/results/iodata
new file mode 100644
index 0000000000..3fb12fe000
--- /dev/null
+++ b/lib/dialyzer/test/specdiffs_SUITE_data/results/iodata
@@ -0,0 +1,3 @@
+
+iodata.erl:7: The specification for iodata:encode/2 states that the function might also return binary() but the inferred return is nonempty_maybe_improper_list(<<_:8,_:_*8>> | nonempty_maybe_improper_list(<<_:8,_:_*8>> | nonempty_maybe_improper_list(any(),<<_:8,_:_*8>> | []) | byte(),<<_:8,_:_*8>> | []) | integer(),<<_:8,_:_*8>> | []) | integer()
+iodata.erl:7: The success typing for iodata:encode/2 implies that the function might also return integer() but the specification return is binary() | maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | byte(),binary() | [])
diff --git a/lib/dialyzer/test/specdiffs_SUITE_data/results/iolist b/lib/dialyzer/test/specdiffs_SUITE_data/results/iolist
new file mode 100644
index 0000000000..ca556f017c
--- /dev/null
+++ b/lib/dialyzer/test/specdiffs_SUITE_data/results/iolist
@@ -0,0 +1,2 @@
+
+iolist.erl:7: The success typing for iolist:encode/2 implies that the function might also return integer() but the specification return is maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | byte(),binary() | [])
diff --git a/lib/dialyzer/test/specdiffs_SUITE_data/src/iodata.erl b/lib/dialyzer/test/specdiffs_SUITE_data/src/iodata.erl
new file mode 100644
index 0000000000..caa44f6c91
--- /dev/null
+++ b/lib/dialyzer/test/specdiffs_SUITE_data/src/iodata.erl
@@ -0,0 +1,41 @@
+-module(iodata).
+
+%% A small part of beam_asm.
+
+-export([encode/2]).
+
+-spec encode(non_neg_integer(), integer()) -> iodata(). % extra range binary()
+
+encode(Tag, N) when Tag >= 0, N < 0 ->
+ encode1(Tag, negative_to_bytes(N));
+encode(Tag, N) when Tag >= 0, N < 16 ->
+ (N bsl 4) bor Tag; % not in the specification
+encode(Tag, N) when Tag >= 0, N < 16#800 ->
+ [((N bsr 3) band 2#11100000) bor Tag bor 2#00001000, N band 16#ff];
+encode(Tag, N) when Tag >= 0 ->
+ encode1(Tag, to_bytes(N)).
+
+encode1(Tag, Bytes) ->
+ case iolist_size(Bytes) of
+ Num when 2 =< Num, Num =< 8 ->
+ [((Num-2) bsl 5) bor 2#00011000 bor Tag| Bytes];
+ Num when 8 < Num ->
+ [2#11111000 bor Tag, encode(0, Num-9)| Bytes]
+ end.
+
+to_bytes(N) ->
+ Bin = binary:encode_unsigned(N),
+ case Bin of
+ <<0:1,_/bits>> -> Bin;
+ <<1:1,_/bits>> -> [0,Bin]
+ end.
+
+negative_to_bytes(N) when N >= -16#8000 ->
+ <<N:16>>;
+negative_to_bytes(N) ->
+ Bytes = byte_size(binary:encode_unsigned(-N)),
+ Bin = <<N:Bytes/unit:8>>,
+ case Bin of
+ <<0:1,_/bits>> -> [16#ff,Bin];
+ <<1:1,_/bits>> -> Bin
+ end.
diff --git a/lib/dialyzer/test/specdiffs_SUITE_data/src/iolist.erl b/lib/dialyzer/test/specdiffs_SUITE_data/src/iolist.erl
new file mode 100644
index 0000000000..7cceeda24e
--- /dev/null
+++ b/lib/dialyzer/test/specdiffs_SUITE_data/src/iolist.erl
@@ -0,0 +1,41 @@
+-module(iolist).
+
+%% A small part of beam_asm.
+
+-export([encode/2]).
+
+-spec encode(non_neg_integer(), integer()) -> iolist().
+
+encode(Tag, N) when Tag >= 0, N < 0 ->
+ encode1(Tag, negative_to_bytes(N));
+encode(Tag, N) when Tag >= 0, N < 16 ->
+ (N bsl 4) bor Tag; % not in the specification
+encode(Tag, N) when Tag >= 0, N < 16#800 ->
+ [((N bsr 3) band 2#11100000) bor Tag bor 2#00001000, N band 16#ff];
+encode(Tag, N) when Tag >= 0 ->
+ encode1(Tag, to_bytes(N)).
+
+encode1(Tag, Bytes) ->
+ case iolist_size(Bytes) of
+ Num when 2 =< Num, Num =< 8 ->
+ [((Num-2) bsl 5) bor 2#00011000 bor Tag| Bytes];
+ Num when 8 < Num ->
+ [2#11111000 bor Tag, encode(0, Num-9)| Bytes]
+ end.
+
+to_bytes(N) ->
+ Bin = binary:encode_unsigned(N),
+ case Bin of
+ <<0:1,_/bits>> -> Bin;
+ <<1:1,_/bits>> -> [0,Bin]
+ end.
+
+negative_to_bytes(N) when N >= -16#8000 ->
+ <<N:16>>;
+negative_to_bytes(N) ->
+ Bytes = byte_size(binary:encode_unsigned(-N)),
+ Bin = <<N:Bytes/unit:8>>,
+ case Bin of
+ <<0:1,_/bits>> -> [16#ff,Bin];
+ <<1:1,_/bits>> -> Bin
+ end.
diff --git a/lib/dialyzer/test/underspecs_SUITE_data/dialyzer_options b/lib/dialyzer/test/underspecs_SUITE_data/dialyzer_options
index f7197ac30f..1a9734deb2 100644
--- a/lib/dialyzer/test/underspecs_SUITE_data/dialyzer_options
+++ b/lib/dialyzer/test/underspecs_SUITE_data/dialyzer_options
@@ -1 +1 @@
-{dialyzer_options, [{warnings, [underspecs]}]}.
+{dialyzer_options, [{indent_opt, false}, {warnings, [underspecs]}]}.
diff --git a/lib/dialyzer/test/unmatched_returns_SUITE_data/dialyzer_options b/lib/dialyzer/test/unmatched_returns_SUITE_data/dialyzer_options
index 49ac917f61..7de9d6f962 100644
--- a/lib/dialyzer/test/unmatched_returns_SUITE_data/dialyzer_options
+++ b/lib/dialyzer/test/unmatched_returns_SUITE_data/dialyzer_options
@@ -1 +1 @@
-{dialyzer_options, [{warnings, [unmatched_returns]}]}.
+{dialyzer_options, [{indent_opt, false}, {warnings, [unmatched_returns]}]}.
diff --git a/lib/dialyzer/test/user_SUITE_data/dialyzer_options b/lib/dialyzer/test/user_SUITE_data/dialyzer_options
index 513ed7752b..0a944966f0 100644
--- a/lib/dialyzer/test/user_SUITE_data/dialyzer_options
+++ b/lib/dialyzer/test/user_SUITE_data/dialyzer_options
@@ -1,2 +1,2 @@
-{dialyzer_options, []}.
+{dialyzer_options, [{indent_opt, false}]}.
{time_limit, 3}. \ No newline at end of file
diff --git a/lib/dialyzer/vsn.mk b/lib/dialyzer/vsn.mk
index fa58adc2db..95984c7c85 100644
--- a/lib/dialyzer/vsn.mk
+++ b/lib/dialyzer/vsn.mk
@@ -1 +1 @@
-DIALYZER_VSN = 3.2.4
+DIALYZER_VSN = 4.0
diff --git a/lib/diameter/bin/diameterc b/lib/diameter/bin/diameterc
index 3dbd238c19..4d415ece78 100755
--- a/lib/diameter/bin/diameterc
+++ b/lib/diameter/bin/diameterc
@@ -4,7 +4,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -78,8 +78,8 @@ compile(#argv{file = File, options = Opts, output = Out}) ->
error_msg(diameter_make:format_error(Reason), []),
1
catch
- error: Reason ->
- error_msg("ERROR: ~p~n ~p", [Reason, erlang:get_stacktrace()]),
+ error: Reason: Stack ->
+ error_msg("ERROR: ~p~n ~p", [Reason, Stack]),
2
end.
diff --git a/lib/diameter/doc/src/Makefile b/lib/diameter/doc/src/Makefile
index 7a7546fc4d..7c7fbeafef 100644
--- a/lib/diameter/doc/src/Makefile
+++ b/lib/diameter/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2010-2016. All Rights Reserved.
+# Copyright Ericsson AB 2010-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -77,6 +77,7 @@ clean_man:
clean_html:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml
index 6bc7d147c0..85522c99b2 100644
--- a/lib/diameter/doc/src/diameter.xml
+++ b/lib/diameter/doc/src/diameter.xml
@@ -1,7 +1,9 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd" [
- <!ENTITY spawn_opt
+ <!ENTITY spawn_opt2
'<seealso marker="erts:erlang#spawn_opt-2">erlang:spawn_opt/2</seealso>'>
+ <!ENTITY spawn_opt5
+ '<seealso marker="erts:erlang#spawn_opt-5">erlang:spawn_opt/5</seealso>'>
<!ENTITY nodes
'<seealso marker="erts:erlang#nodes-0">erlang:nodes/0</seealso>'>
<!ENTITY make_ref
@@ -21,7 +23,7 @@
<copyright>
<year>2011</year>
-<year>2017</year>
+<year>2019</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -55,7 +57,7 @@ limitations under the License.
<!-- ===================================================================== -->
<!-- ===================================================================== -->
-<module>diameter</module>
+<module since="OTP R14B03">diameter</module>
<modulesummary>Main API of the diameter application.</modulesummary>
<description>
@@ -135,7 +137,7 @@ along with any
extra arguments to be appended to those documented.
Note that extra arguments specific to an outgoing request can be
specified to &call;, in which case
-those are are appended to any module-specific extra arguments.</p>
+those are appended to any module-specific extra arguments.</p>
<p>
Specifying a <c>#diameter_callback{}</c> record allows individual
@@ -150,7 +152,7 @@ See <c>diameter_callback.erl</c> for details.</p>
<p>
Options defining a Diameter application.
-Has one the following types.</p>
+Has one of the following types.</p>
<taglist>
@@ -1384,12 +1386,22 @@ the same peer.</p>
</item>
<tag>
-<marker id="spawn_opt"/><c>{spawn_opt, [term()]}</c></tag>
+<marker id="spawn_opt"/><c>{spawn_opt, [term()] | {M,F,A}}</c></tag>
<item>
<p>
-Options passed to &spawn_opt; when spawning a process for an
-incoming Diameter request.
-Options <c>monitor</c> and <c>link</c> are ignored.</p>
+An options list passed to &spawn_opt2; to spawn a handler process for an
+incoming Diameter request on the local node, or an MFA that returns
+the pid of a handler process.</p>
+
+<p>
+Options <c>monitor</c> and <c>link</c> are ignored in the list-valued
+case.
+An MFA is applied with an additional term prepended to its argument
+list, and should return either the pid of the handler process that
+invokes <c>diameter_traffic:request/1</c> on the term in order to
+process the request, or the atom <c>discard</c>.
+The handler process need not be local, but diameter must be started on
+the remote node.</p>
<p>
Defaults to the empty list.</p>
@@ -1574,7 +1586,7 @@ identifies the configuration.</p>
<!-- ===================================================================== -->
<func>
-<name>add_transport(SvcName, {connect|listen, [Opt]})
+<name since="OTP R14B03">add_transport(SvcName, {connect|listen, [Opt]})
-> {ok, Ref} | {error, Reason}</name>
<fsummary>Add transport capability to a service.</fsummary>
<type>
@@ -1624,7 +1636,7 @@ its transports.</p>
<!-- ===================================================================== -->
<func>
-<name>call(SvcName, App, Request, [Opt]) -> Answer | ok | {error, Reason}</name>
+<name since="OTP R14B03">call(SvcName, App, Request, [Opt]) -> Answer | ok | {error, Reason}</name>
<fsummary>Send a Diameter request message.</fsummary>
<type>
<v>SvcName = &service_name;</v>
@@ -1730,7 +1742,7 @@ transport connection.</p>
<!-- ===================================================================== -->
<func>
-<name>origin_state_id() -> &dict_Unsigned32;</name>
+<name since="OTP R14B03">origin_state_id() -> &dict_Unsigned32;</name>
<fsummary>Returns a reasonable Origin-State-Id.</fsummary>
<desc>
<p>
@@ -1748,7 +1760,7 @@ at the time the diameter application was started.</p>
<!-- ===================================================================== -->
<func>
-<name>remove_transport(SvcName, Pred) -> ok | {error, Reason}</name>
+<name since="OTP R14B03">remove_transport(SvcName, Pred) -> ok | {error, Reason}</name>
<fsummary>Remove previously added transports.</fsummary>
<type>
<v>SvcName = &service_name;</v>
@@ -1795,7 +1807,7 @@ configured on the transport.</p>
<!-- ===================================================================== -->
<func>
-<name>service_info(SvcName, Info) -> term()</name>
+<name since="OTP R14B03">service_info(SvcName, Info) -> term()</name>
<fsummary>Return information about a started service.</fsummary>
<type>
<v>SvcName = &service_name;</v>
@@ -2114,7 +2126,7 @@ For example:</p>
<!-- ===================================================================== -->
<func>
-<name>services() -> [SvcName]</name>
+<name since="OTP R14B03">services() -> [SvcName]</name>
<fsummary>Return the list of started services.</fsummary>
<type>
<v>SvcName = &service_name;</v>
@@ -2129,7 +2141,7 @@ Return the list of started services.</p>
<!-- ===================================================================== -->
<func>
-<name>session_id(Ident) -> &dict_OctetString;</name>
+<name since="OTP R14B03">session_id(Ident) -> &dict_OctetString;</name>
<fsummary>Return a value for a Session-Id AVP.</fsummary>
<type>
<v>Ident = &dict_DiameterIdentity;</v>
@@ -2148,7 +2160,7 @@ the message containing the returned value will be sent.</p>
<!-- ===================================================================== -->
<func>
-<name>start() -> ok | {error, Reason}</name>
+<name since="OTP R14B03">start() -> ok | {error, Reason}</name>
<fsummary>Start the diameter application.</fsummary>
<desc>
<p>
@@ -2164,7 +2176,7 @@ file, not by calling <c>start/0</c> explicitly.</p>
<!-- ===================================================================== -->
<func>
-<name>start_service(SvcName, Options) -> ok | {error, Reason}</name>
+<name since="OTP R14B03">start_service(SvcName, Options) -> ok | {error, Reason}</name>
<fsummary>Start a Diameter service.</fsummary>
<type>
<v>SvcName = &service_name;</v>
@@ -2194,7 +2206,7 @@ necessarily the case.</p>
<!-- ===================================================================== -->
<func>
-<name>stop() -> ok | {error, Reason}</name>
+<name since="OTP R14B03">stop() -> ok | {error, Reason}</name>
<fsummary>Stop the diameter application.</fsummary>
<desc>
<p>
@@ -2208,7 +2220,7 @@ Stop the diameter application.</p>
<!-- ===================================================================== -->
<func>
-<name>stop_service(SvcName) -> ok | {error, Reason}</name>
+<name since="OTP R14B03">stop_service(SvcName) -> ok | {error, Reason}</name>
<fsummary>Stop a Diameter service.</fsummary>
<type>
<v>SvcName = &service_name;</v>
@@ -2221,7 +2233,7 @@ Stop a diameter service.</p>
<p>
Stopping a service causes all associated transport connections to be
broken.
-A DPR message with be sent as in the case of &remove_transport;.</p>
+A DPR message will be sent as in the case of &remove_transport;.</p>
<note>
<p>
@@ -2236,7 +2248,7 @@ be called to remove transport configuration.</p>
<!-- ===================================================================== -->
<func>
-<name>subscribe(SvcName) -> true</name>
+<name since="OTP R14B03">subscribe(SvcName) -> true</name>
<fsummary>Subscribe to event messages.</fsummary>
<type>
<v>SvcName = &service_name;</v>
@@ -2258,7 +2270,7 @@ reception of all transport-related events.</p>
<!-- ===================================================================== -->
<func>
-<name>unsubscribe(SvcName) -> true</name>
+<name since="OTP R14B03">unsubscribe(SvcName) -> true</name>
<fsummary>Unsubscribe to event messages.</fsummary>
<type>
<v>SvcName = &service_name;</v>
diff --git a/lib/diameter/doc/src/diameter_app.xml b/lib/diameter/doc/src/diameter_app.xml
index aa334beb21..82e3d449ef 100644
--- a/lib/diameter/doc/src/diameter_app.xml
+++ b/lib/diameter/doc/src/diameter_app.xml
@@ -44,7 +44,7 @@ limitations under the License.
</header>
-<module>diameter_app</module>
+<module since="OTP R14B03">diameter_app</module>
<modulesummary>
Callback module of a Diameter application.</modulesummary>
@@ -180,7 +180,7 @@ process.</p>
<funcs>
<func>
-<name>Mod:peer_up(SvcName, Peer, State) -> NewState</name>
+<name since="OTP R14B03">Mod:peer_up(SvcName, Peer, State) -> NewState</name>
<fsummary>Invoked when a transport connection has been established</fsummary>
<type>
<v>SvcName = &mod_service_name;</v>
@@ -215,7 +215,7 @@ handled independently of &peer_up; and &peer_down;.</p>
</func>
<func>
-<name>Mod:peer_down(SvcName, Peer, State) -> NewState</name>
+<name since="OTP R14B03">Mod:peer_down(SvcName, Peer, State) -> NewState</name>
<fsummary>Invoked when a transport connection has been lost.</fsummary>
<type>
<v>SvcName = &mod_service_name;</v>
@@ -234,7 +234,7 @@ candidate in &pick_peer; callbacks.</p>
</func>
<func>
-<name>Mod:pick_peer(LocalCandidates, RemoteCandidates, SvcName, State)
+<name since="OTP R14B03">Mod:pick_peer(LocalCandidates, RemoteCandidates, SvcName, State)
-> Selection | false</name>
<fsummary>Select a target peer for an outgoing request.</fsummary>
<type>
@@ -311,7 +311,7 @@ or &peer_down; callback.</p>
</func>
<func>
-<name>Mod:prepare_request(Packet, SvcName, Peer) -> Action</name>
+<name since="OTP R14B03">Mod:prepare_request(Packet, SvcName, Peer) -> Action</name>
<fsummary>Return a request for encoding and transport.</fsummary>
<type>
<v>Packet = &packet;</v>
@@ -363,7 +363,7 @@ discarded}</c>.</p>
</func>
<func>
-<name>Mod:prepare_retransmit(Packet, SvcName, Peer) -> Action</name>
+<name since="OTP R14B03">Mod:prepare_retransmit(Packet, SvcName, Peer) -> Action</name>
<fsummary>Return a request for encoding and retransmission.</fsummary>
<type>
<v>Packet = &packet;</v>
@@ -393,7 +393,7 @@ discarded}</c>.</p>
</func>
<func>
-<name>Mod:handle_answer(Packet, Request, SvcName, Peer) -> Result</name>
+<name since="OTP R14B03">Mod:handle_answer(Packet, Request, SvcName, Peer) -> Result</name>
<fsummary>Receive an answer message from a peer.</fsummary>
<type>
<v>Packet = &packet;</v>
@@ -437,7 +437,7 @@ The &mod_application_opt;
</func>
<func>
-<name>Mod:handle_error(Reason, Request, SvcName, Peer) -> Result</name>
+<name since="OTP R14B03">Mod:handle_error(Reason, Request, SvcName, Peer) -> Result</name>
<fsummary>Return an error from a outgoing request.</fsummary>
<type>
<v>Reason = timeout | failover | term()</v>
@@ -465,7 +465,7 @@ not selected.</p>
</func>
<func>
-<name>Mod:handle_request(Packet, SvcName, Peer) -> Action</name>
+<name since="OTP R14B03">Mod:handle_request(Packet, SvcName, Peer) -> Action</name>
<fsummary>Receive an incoming request.</fsummary>
<type>
<v>Packet = &packet;</v>
diff --git a/lib/diameter/doc/src/diameter_codec.xml b/lib/diameter/doc/src/diameter_codec.xml
index 5124b49484..0384ad2913 100644
--- a/lib/diameter/doc/src/diameter_codec.xml
+++ b/lib/diameter/doc/src/diameter_codec.xml
@@ -46,7 +46,7 @@ limitations under the License.
<file>diameter_codec.xml</file>
</header>
-<module>diameter_codec</module>
+<module since="OTP R15B03">diameter_codec</module>
<modulesummary>Decode and encode of Diameter messages.</modulesummary>
<description>
@@ -255,7 +255,7 @@ Another list-valued representation allows a message to be specified
as a list whose head is a &header; and whose tail is an &avp; list.
This representation is used by diameter itself when relaying requests
as directed by the return value of a &app_handle_request; callback.
-It differs from the other other two in that it bypasses the checks for
+It differs from the other two in that it bypasses the checks for
messages that do not agree with their definitions in the dictionary in
question: messages are sent exactly as specified.</p>
@@ -346,7 +346,7 @@ question, as documented in &man_transport;.</p>
<funcs>
<func>
-<name>decode(Mod, Bin) -> Pkt</name>
+<name since="OTP R15B03">decode(Mod, Bin) -> Pkt</name>
<fsummary>Decode a Diameter message.</fsummary>
<type>
<v>Mod = &dictionary;</v>
@@ -362,7 +362,7 @@ Decode a Diameter message.</p>
</func>
<func>
-<name>encode(Mod, Msg) -> Pkt</name>
+<name since="OTP R15B03">encode(Mod, Msg) -> Pkt</name>
<fsummary>Encode a Diameter message.</fsummary>
<type>
<v>Mod = &dictionary;</v>
diff --git a/lib/diameter/doc/src/diameter_dict.xml b/lib/diameter/doc/src/diameter_dict.xml
index 94016d9466..37d30b709b 100644
--- a/lib/diameter/doc/src/diameter_dict.xml
+++ b/lib/diameter/doc/src/diameter_dict.xml
@@ -486,9 +486,9 @@ will result in the following record definition given an empty
prefix.</p>
<pre>
--record('SIP-Deregistration-Reason' {'SIP-Reason-Code',
- 'SIP-Reason-Info',
- 'AVP'}).
+-record('SIP-Deregistration-Reason', {'SIP-Reason-Code',
+ 'SIP-Reason-Info',
+ 'AVP'}).
</pre>
<p>
diff --git a/lib/diameter/doc/src/diameter_make.xml b/lib/diameter/doc/src/diameter_make.xml
index 112355816f..57e83bbca1 100644
--- a/lib/diameter/doc/src/diameter_make.xml
+++ b/lib/diameter/doc/src/diameter_make.xml
@@ -45,7 +45,7 @@ limitations under the License.
<file>diameter_make.xml</file>
</header>
-<module>diameter_make</module>
+<module since="OTP R14B03">diameter_make</module>
<modulesummary>Diameter dictionary compilation.</modulesummary>
<description>
@@ -67,7 +67,7 @@ interface.</p>
<funcs>
<func>
-<name>codec(File :: iolist() | binary(), [Opt]) -> ok
+<name since="OTP R15B">codec(File :: iolist() | binary(), [Opt]) -> ok
| {ok, [Out]}
| {error, Reason}</name>
<fsummary>Compile a dictionary file into Erlang source.</fsummary>
@@ -186,7 +186,7 @@ A returned error reason can be converted into a readable string using
<!-- ===================================================================== -->
<func>
-<name>format(Parsed) -> iolist()</name>
+<name since="OTP R16B03">format(Parsed) -> iolist()</name>
<fsummary>Format a parsed dictionary.</fsummary>
<desc>
<p>
@@ -198,7 +198,7 @@ dictionary format.</p>
<!-- ===================================================================== -->
<func>
-<name>flatten(Parsed) -> term()</name>
+<name since="OTP R16B03">flatten(Parsed) -> term()</name>
<fsummary>Flatten a parsed dictionary.</fsummary>
<desc>
@@ -214,7 +214,7 @@ The return value is also a parsed dictionary.</p>
<!-- ===================================================================== -->
<func>
-<name>format_error(Reason) -> string()</name>
+<name since="OTP 17.0">format_error(Reason) -> string()</name>
<fsummary>Turn an error reason into a readable string.</fsummary>
<desc>
diff --git a/lib/diameter/doc/src/diameter_sctp.xml b/lib/diameter/doc/src/diameter_sctp.xml
index 62e958870e..2cf924ee6b 100644
--- a/lib/diameter/doc/src/diameter_sctp.xml
+++ b/lib/diameter/doc/src/diameter_sctp.xml
@@ -47,7 +47,7 @@ limitations under the License.
<file>diameter_sctp.xml</file>
</header>
-<module>diameter_sctp</module>
+<module since="OTP R14B03">diameter_sctp</module>
<modulesummary>Diameter transport over SCTP.</modulesummary>
<description>
@@ -67,7 +67,7 @@ and implements the behaviour documented in
<funcs>
<func>
-<name>start({Type, Ref}, Svc, [Opt])
+<name since="OTP R14B03">start({Type, Ref}, Svc, [Opt])
-> {ok, Pid, [LAddr]} | {error, Reason}</name>
<fsummary>Start a transport process.</fsummary>
<type>
diff --git a/lib/diameter/doc/src/diameter_soc.xml b/lib/diameter/doc/src/diameter_soc.xml
index 28e01ff1be..2d2d66a243 100644
--- a/lib/diameter/doc/src/diameter_soc.xml
+++ b/lib/diameter/doc/src/diameter_soc.xml
@@ -137,7 +137,7 @@ Capitalized <em>Diameter</em> refers to the protocol, lowercase
<cell>Creating New AVPs</cell>
<cell>&NA;</cell>
<cell>New AVPs can be defined using the dictionary interface.
- Both both RFC data formats and extensions are supported.</cell>
+ Both RFC data formats and extensions are supported.</cell>
</row>
<row>
<cell>1.3.3</cell>
diff --git a/lib/diameter/doc/src/diameter_tcp.xml b/lib/diameter/doc/src/diameter_tcp.xml
index 9f84eeb9fd..fe0cb2d067 100644
--- a/lib/diameter/doc/src/diameter_tcp.xml
+++ b/lib/diameter/doc/src/diameter_tcp.xml
@@ -57,7 +57,7 @@ limitations under the License.
<file>diameter_tcp.xml</file>
</header>
-<module>diameter_tcp</module>
+<module since="OTP R14B03">diameter_tcp</module>
<modulesummary>Diameter transport over TCP.</modulesummary>
<description>
@@ -83,7 +83,7 @@ before configuring TLS capability on diameter transports.</p>
<funcs>
<func>
-<name>start({Type, Ref}, Svc, [Opt])
+<name since="OTP R14B03">start({Type, Ref}, Svc, [Opt])
-> {ok, Pid}
| {ok, Pid, [LAddr]}
| {error, Reason}</name>
diff --git a/lib/diameter/doc/src/diameter_transport.xml b/lib/diameter/doc/src/diameter_transport.xml
index 294e8a8864..0a8ef321c6 100644
--- a/lib/diameter/doc/src/diameter_transport.xml
+++ b/lib/diameter/doc/src/diameter_transport.xml
@@ -14,7 +14,8 @@
<erlref>
<header>
<copyright>
-<year>2011</year><year>2016</year>
+<year>2011</year>
+<year>2019</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -43,7 +44,7 @@ limitations under the License.
<file>diameter_transport.xml</file>
</header>
-<module>diameter_transport</module>
+<module since="OTP R14B03">diameter_transport</module>
<modulesummary>Diameter transport interface.</modulesummary>
<description>
@@ -94,7 +95,7 @@ and has the binary() to send in its <c>bin</c> field.</p>
<funcs>
<func>
-<name>Mod:start({Type, Ref}, Svc, Config)
+<name since="OTP R14B03">Mod:start({Type, Ref}, Svc, Config)
-> {ok, Pid}
| {ok, Pid, LAddrs}
| {error, Reason}</name>
@@ -174,10 +175,13 @@ its parent.</p>
<taglist>
-<tag><c>{diameter, {send, &message;}}</c></tag>
+<tag><c>{diameter, {send, &message; | false}}</c></tag>
<item>
<p>
-An outbound Diameter message.</p>
+An outbound Diameter message.
+The atom <c>false</c> can only be received when request
+acknowledgements have been requests: see the <c>ack</c> message
+below.</p>
</item>
<tag><c>{diameter, {close, Pid}}</c></tag>
@@ -246,6 +250,27 @@ A <c>LocalAddr</c> list has the same semantics as one returned from
&start;.</p>
</item>
+<tag><c>{diameter, ack}</c></tag>
+<item>
+<p>
+Request acknowledgements of unanswered requests.
+A transport process should send this once before passing incoming
+Diameter messages into diameter.
+As a result, every Diameter request passed into diameter with a
+<c>recv</c> message (below) will be answered with a
+<c>send</c> message (above), either a &message; for the transport
+process to send or the atom <c>false</c> if the request has been
+discarded or otherwise not answered.</p>
+
+<p>
+This is to allow a transport process to keep count of the number
+of incoming request messages that have not yet been answered or
+discarded, to allow it to regulate the amount of incoming traffic.
+Both diameter_tcp and diameter_sctp request acknowledgements when a
+<c>message_cb</c> is configured, turning send/recv message into
+callbacks that can be used to regulate traffic.</p>
+</item>
+
<tag><c>{diameter, {recv, &message;}}</c></tag>
<item>
<p>
diff --git a/lib/diameter/doc/src/notes.xml b/lib/diameter/doc/src/notes.xml
index fa1be39b5b..8dcba93273 100644
--- a/lib/diameter/doc/src/notes.xml
+++ b/lib/diameter/doc/src/notes.xml
@@ -11,7 +11,7 @@
<header>
<copyright>
<year>2011</year>
-<year>2017</year>
+<year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -43,6 +43,111 @@ first.</p>
<!-- ===================================================================== -->
+<section><title>diameter 2.2.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix inadvertently broad monitor that resulted in
+ gen_server cast messages to hidden nodes from module
+ diameter_dist.</p>
+ <p>
+ Own Id: OTP-15768</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>diameter 2.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix failure of incoming answer message with faulty
+ Experimental-Result-Code. Failure to decode the AVP
+ resulted in an uncaught exception, with no no
+ handle_answer/error callback as a consequence.</p>
+ <p>
+ Own Id: OTP-15569 Aux Id: ERIERL-302 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Add spawn_opt MFA configuration to allow a callback to
+ spawn a handler process for an incoming Diameter request
+ on an an arbitrary node. Module diameter_dist provides a
+ route_session/2 that can be used to distribute requests
+ based on Session-Id, although this module is currently
+ only documented in the module itself and may change.</p>
+ <p>
+ Own Id: OTP-15398</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>diameter 2.1.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix function_clause when sending an outgoing request
+ after DPA has been sent in response to an incoming DPR.
+ The caused the diameter_peer_fsm gen_server associated
+ with the peer connection to fail, which could then result
+ in the transport connection being reset before the peer
+ closed it upon reception of DPA.</p>
+ <p>
+ Own Id: OTP-15198 Aux Id: ERIERL-213 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>diameter 2.1.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix documentation typos.</p>
+ <p>
+ Own Id: OTP-15045</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>diameter 2.1.4.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix failure of incoming answer message with faulty
+ Experimental-Result-Code. Failure to decode the AVP
+ resulted in an uncaught exception, with no no
+ handle_answer/error callback as a consequence.</p>
+ <p>
+ Own Id: OTP-15569 Aux Id: ERIERL-302 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>diameter 2.1.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -75,7 +180,7 @@ first.</p>
<list>
<item>
<p>
- Fix documentation typo: peer_down/3 was written where
+ Fix documentation typo: peer_up/3 was written where
peer_down/3 was intended.</p>
<p>
Own Id: OTP-14805</p>
diff --git a/lib/diameter/examples/code/node.erl b/lib/diameter/examples/code/node.erl
index fc5830f8e2..77810bf893 100644
--- a/lib/diameter/examples/code/node.erl
+++ b/lib/diameter/examples/code/node.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/diameter/src/Makefile b/lib/diameter/src/Makefile
index 3af856f63e..98636ed6e2 100644
--- a/lib/diameter/src/Makefile
+++ b/lib/diameter/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2010-2017. All Rights Reserved.
+# Copyright Ericsson AB 2010-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -149,7 +149,7 @@ gen/$(DICT_YRL).erl: compiler/$(DICT_YRL).yrl
$(ERLC) -Werror -o $(@D) $<
# Generate the app file.
-$(APP_TARGET): $(APP_SRC) ../vsn.mk modules.mk app.sed
+$(APP_TARGET): $(APP_SRC) ../vsn.mk modules.mk
$(gen_verbose) \
M=`echo $(notdir $(APP_MODULES)) | tr ' ' ,`; \
C=`echo $(COMPILER_MODULES) | tr ' ' ,`; \
@@ -160,8 +160,7 @@ $(APP_TARGET): $(APP_SRC) ../vsn.mk modules.mk app.sed
-e "s;%COMPILER%;$$C;" \
-e "s;%INFO%;$$I;" \
-e "s;%REGISTERED%;$$R;" \
- $< \
- | sed -f app.sed > $@
+ $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
$(vsn_verbose) \
diff --git a/lib/diameter/src/app.sed b/lib/diameter/src/app.sed
deleted file mode 100644
index dd3806f5f1..0000000000
--- a/lib/diameter/src/app.sed
+++ /dev/null
@@ -1,41 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2014-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-
-#
-# Generate runtime_dependencies from applications to avoid having to
-# specify the same application more than once.
-#
-
-/{runtime_dependencies,/b v
-/{[-a-z]*, "[0-9.]*"}/!b
-/{vsn,/b
-
-/%%/!H
-s/{\([^,]*\)[^}]*}/\1/g
-s/%%/%,/
-b
-
-:v
-
-p
-x
-s/\n//
-s/%//g
-s/\n */ /g
-s/{\([^,]*\), "\([^"]*"\)}/"\1-\2/g
diff --git a/lib/diameter/src/base/diameter.erl b/lib/diameter/src/base/diameter.erl
index b90b794611..7f172e1fa1 100644
--- a/lib/diameter/src/base/diameter.erl
+++ b/lib/diameter/src/base/diameter.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -365,7 +365,7 @@ call(SvcName, App, Message) ->
| {connect_timer, 'Unsigned32'()}
| {watchdog_timer, 'Unsigned32'() | {module(), atom(), list()}}
| {watchdog_config, [{okay|suspect, non_neg_integer()}]}
- | {spawn_opt, list()}.
+ | {spawn_opt, list() | mfa()}.
%% Options passed to start_service/2
diff --git a/lib/diameter/src/base/diameter_callback.erl b/lib/diameter/src/base/diameter_callback.erl
index d04a416bef..3bcf550cd8 100644
--- a/lib/diameter/src/base/diameter_callback.erl
+++ b/lib/diameter/src/base/diameter_callback.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -70,7 +70,7 @@
-module(diameter_callback).
-%% Default callbacks when no aleternate is specified.
+%% Default callbacks when no alternate is specified.
-export([peer_up/3,
peer_down/3,
pick_peer/4,
diff --git a/lib/diameter/src/base/diameter_codec.erl b/lib/diameter/src/base/diameter_codec.erl
index 2dd2c906a2..493a6ab1e3 100644
--- a/lib/diameter/src/base/diameter_codec.erl
+++ b/lib/diameter/src/base/diameter_codec.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -92,8 +92,8 @@ encode(Mod, Opts, #diameter_packet{} = Pkt) ->
%% count encode errors.
?LOG(encode_error, {Reason, Stack, H}),
exit({?MODULE, encode, T});
- error: Reason ->
- T = {Reason, diameter_lib:get_stacktrace()},
+ error: Reason: Stack ->
+ T = {Reason, diameter_lib:stacktrace(Stack)},
?LOG(encode_error, T),
exit({?MODULE, encode, T})
end;
@@ -134,8 +134,8 @@ enc(_, Opts, #diameter_packet{msg = [#diameter_header{} = Hdr | As]}
Eid:32,
Bin/binary>>}
catch
- error: Reason ->
- exit({Reason, diameter_lib:get_stacktrace(), Hdr})
+ error: Reason: Stack ->
+ exit({Reason, diameter_lib:stacktrace(Stack), Hdr})
end;
enc(Mod, Opts, #diameter_packet{header = Hdr0, msg = Msg} = Pkt) ->
@@ -179,14 +179,14 @@ enc(Mod, Opts, #diameter_packet{header = Hdr0, msg = Msg} = Pkt) ->
Eid:32,
Bin/binary>>}
catch
- error: Reason ->
+ error: Reason: Stack ->
Hdr = Hdr0#diameter_header{cmd_code = Code,
application_id = Aid,
is_request = RB,
is_proxiable = PB,
is_error = EB,
is_retransmitted = TB},
- exit({Reason, diameter_lib:get_stacktrace(), Hdr})
+ exit({Reason, diameter_lib:stacktrace(Stack), Hdr})
end.
%% values/1
diff --git a/lib/diameter/src/base/diameter_config.erl b/lib/diameter/src/base/diameter_config.erl
index 90a9282349..36ae4c2276 100644
--- a/lib/diameter/src/base/diameter_config.erl
+++ b/lib/diameter/src/base/diameter_config.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -633,8 +633,8 @@ opt(service, {K, F})
Nodes ->
is_list(Nodes) orelse {error, Nodes}
catch
- E:R ->
- {error, {E, R, ?STACK}}
+ E:R:Stack ->
+ {error, {E, R, Stack}}
end;
opt(service, {sequence, {H,N}}) ->
@@ -651,8 +651,8 @@ opt(service = S, {sequence = K, F}) ->
V ->
{error, V}
catch
- E:R ->
- {error, {E, R, ?STACK}}
+ E:R:Stack ->
+ {error, {E, R, Stack}}
end;
opt(transport, {transport_module, M}) ->
@@ -932,8 +932,8 @@ cb(M,F) ->
try M:F() of
V -> V
catch
- E: Reason ->
- ?THROW({callback, E, Reason, ?STACK})
+ E: Reason: Stack ->
+ ?THROW({callback, E, Reason, Stack})
end.
%% call/1
diff --git a/lib/diameter/src/base/diameter_dist.erl b/lib/diameter/src/base/diameter_dist.erl
new file mode 100644
index 0000000000..ed23152b8b
--- /dev/null
+++ b/lib/diameter/src/base/diameter_dist.erl
@@ -0,0 +1,535 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(diameter_dist).
+
+-behaviour(gen_server).
+
+%%
+%% Implements callbacks that can be configured as a spawn_opt
+%% transport configuration, to be able to distribute incoming Diameter
+%% requests to handler processes (local or remote) in various ways.
+%%
+
+%% spawn_opt callbacks
+-export([spawn_local/2,
+ spawn_local/1,
+ route_session/2,
+ route_session/1]).
+
+%% signal availability for handling incoming requests to route_sesssion/2
+-export([attach/1,
+ detach/1]).
+
+%% consistent hashing
+-export([hash/3, %% for use as default MFA in route_session/2 options map
+ hash/2]). %% arbitrary key/values
+
+-include_lib("diameter/include/diameter.hrl").
+
+%% server start
+-export([start_link/0]).
+
+%% gen_server callbacks
+-export([init/1,
+ handle_info/2,
+ handle_cast/2,
+ handle_call/3,
+ code_change/3,
+ terminate/2]).
+
+-type request() :: tuple(). %% callback argument from diameter_traffic
+
+-define(SERVER, ?MODULE). %% server monitoring node connections
+
+%% Maps a node name binary to the corresponding atom. Used by
+%% route_session/2 to map the optional value of a Session-Id to
+%% node().
+-define(NODE_TABLE, diameter_dist_node).
+
+%% Maps a diameter:service_name() to a node() that has called attach/1
+%% to declare its willingness to handle incoming requests for the
+%% service. Use by route_session/2 in case the optional value mapping
+%% has failed.
+-define(SERVICE_TABLE, diameter_dist_service).
+
+-define(B(A), atom_to_binary(A, utf8)).
+-define(ORCOND(List), list_to_tuple(['orelse', false | List])).
+-define(HASH(T), erlang:phash2(T, 16#100000000)).
+
+%% spawn_local/2
+%%
+%% Callback that is equivalent to an options list. That is, the
+%% following are equivalent when passed as options to
+%% diameter:add_transport/2.
+%%
+%% {spawn_opt, Opts}
+%% {spawn_opt, {diameter_dist, spawn_local, [Opts]}}
+
+-spec spawn_local(ReqT :: request(), Opts :: list())
+ -> pid().
+
+spawn_local(ReqT, Opts) ->
+ spawn_opt(diameter_traffic, request, [ReqT], Opts).
+
+%% spawn_local/1
+
+spawn_local(ReqT) ->
+ spawn_local(ReqT, []).
+
+%% route_session/2
+%%
+%% Callback that maps the Session-Id of an incoming request to a
+%% handler node.
+%%
+%% With an options list, maps an id whose optional value is the name
+%% of a connected node to the same node, to handle the case that the
+%% session id has been returned from diameter:session_id/1; otherwise
+%% to a node that has called diameter_dist:attach/1 using the
+%% consistent hashing provided by hash/3, or to the local node() if a
+%% session id could not be extracted or there are no attached nodes. A
+%% handler process is spawned on the selected node using
+%% erlang:spawn_opt/4.
+%%
+%% Different behaviour can be configured by supplying an options map
+%% of the following form:
+%%
+%% #{search => non_neg_integer(),
+%% id => [binary()],
+%% default => discard | local | mfa(),
+%% dispatch => list() | mfa()}
+%%
+%% The search member limits the number of AVPs that are examined in
+%% the message (from the front), to avoid searching entire message in
+%% case it's known that peers follow RFC 6733's recommendation that
+%% Session-Id be placed at the head of a message. The default is to
+%% search the entire message.
+%%
+%% The id member restricts the optional value mapping to session ids
+%% whose DiamterIdentity is one of those specified. Set this to the
+%% list of Diameter identities advertised by the service in question
+%% (typically one) to ensure that only locally generated session ids
+%% are mapped; or to the empty list to disable the mapping.
+%%
+%% The default member determines where to handle a message whose
+%% Session-Id isn't found or whose optional value isn't mapped to the
+%% name of a connected node. The atom local says the local node, an
+%% MFA is invoked on Session-Id | false, the name of the diameter
+%% service, and the message binary, and should return either a node()
+%% or false to discard the message. Defaults to {diameter_dist, hash, []}.
+%%
+%% The dispatch member determines how the pid() of the request handler
+%% process is retrieved. An MFA is applied to a previously selected
+%% node(), and the module, function, and arguments list to apply in
+%% the handler process to handle the request, the MFA being supplied
+%% by diameter, and returns pid() | discard. A list is equivalent to
+%% {erlang, spawn_opt, []}. Defaults to [].
+%%
+%% This can be used with search = 0 to route on something other than
+%% Session-Id, but this is probably no simpler than just implementing
+%% an own spawn_opt callback. (Except with the default dispatch possibly.)
+%%
+%% Note that if the peer is also implemented with OTP diameter and
+%% generating session ids with diameter:session_id/1 then
+%% route_session/2 can map an optional value to a local node that
+%% happens to have the same name as one of the peer's nodes. This
+%% could lead to an uneven distribution; for example, if the peer
+%% nodes are a subset of the local nodes. In practice, it's typically
+%% known if it's peers or the local node originating sessions; if the
+%% former then setting id = [] disables the optional value mapping, if
+%% the latter then setting default = local disables the hashing.
+-spec route_session(ReqT :: request(), Opts)
+ -> discard
+ | pid()
+ when Opts :: pos_integer() %% aka #{search => N}
+ | list() %% aka #{dispatch => Opts}
+ | #{search => non_neg_integer(), %% limit number of examined AVPs
+ id => [binary()], %% restrict optional value map on DiamIdent
+ default => local %% handle locally
+ | discard
+ | mfa(), %% return node() | false
+ dispatch => list() %% spawn options
+ | mfa()}. %% (Node, M, F, A) -> pid() | discard
+
+route_session(ReqT, Opts) ->
+ {_, Bin} = Info = diameter_traffic:request_info(ReqT),
+ Sid = session_id(avps(Bin), search(Opts)),
+ Node = default(node_of_session_id(Sid, Opts), Sid, Opts, Info),
+ dispatch(Node, ReqT, dispatch(Opts)).
+
+%% avps/1
+
+avps(<<_:20/binary, Bin/binary>>) ->
+ Bin;
+
+avps(_) ->
+ false.
+
+%% dispatch/3
+
+dispatch(false, _, _) ->
+ discard;
+
+dispatch(Node, ReqT, {M,F,A}) ->
+ apply(M, F, [Node, diameter_traffic, request, [ReqT] | A]);
+
+dispatch(Node, ReqT, Opts) ->
+ spawn_opt(Node, diameter_traffic, request, [ReqT], Opts).
+
+%% route_session/1
+
+route_session(ReqT) ->
+ route_session(ReqT, []).
+
+%% node_of_session_id/2
+%%
+%% Return the node name encoded as optional value in a Session-Id,
+%% assuming the id has been created with diameter:session_id/0. Lookup
+%% the node name to ensure we don't convert arbitrary binaries to
+%% atom.
+
+node_of_session_id([Id, _, _, Bin], #{id := Ids}) ->
+ lists:member(Id, Ids) andalso nodemap(Bin);
+
+node_of_session_id([_, _, _, Bin], _) ->
+ nodemap(Bin);
+
+node_of_session_id(_, _) ->
+ false.
+
+%% nodemap/1
+
+nodemap(Bin) ->
+ try
+ ets:lookup_element(?NODE_TABLE, Bin, 2)
+ catch
+ error: badarg -> false
+ end.
+
+%% session_id/2
+
+session_id(_, 0) -> %% give up
+ false;
+
+%% Session-Id = Command Code 263, V-bit = 0.
+session_id(<<263:32, 0:1, _:7, Len:24, _/binary>> = Bin, _) ->
+ case Bin of
+ <<Avp:Len/binary, _/binary>> ->
+ <<_:8/binary, Sid/binary>> = Avp,
+ split(Sid);
+ _ ->
+ false
+ end;
+
+%% Jump to the next AVP. This is potentially costly for a message with
+%% many AVPs and no Session-Id, which an attacker is prone to send.
+%% 8.8 or RFC 6733 says that Session-Id SHOULD (but not MUST) appear
+%% immediately following the Diameter Header, so there is no
+%% guarantee.
+session_id(<<_:40, Len:24, _/binary>> = Bin, N) ->
+ Pad = (4 - (Len rem 4)) rem 4,
+ case Bin of
+ <<_:Len/binary, _:Pad/binary, Rest/binary>> ->
+ session_id(Rest, if N == infinity -> N; true -> N-1 end);
+ _ ->
+ false
+ end;
+
+session_id(_, _) ->
+ false.
+
+%% split/1
+%%
+%% Split a Session-Id at no more than three semicolons: the optional
+%% value (if any) follows the third. binary:split/2 does better than
+%% matching character by character, especially when the pattern is
+%% compiled.
+
+split(Bin) ->
+ split(3, Bin, pattern()).
+
+%% split/3
+
+split(0, Bin, _) ->
+ [Bin];
+
+split(N, Bin, Pattern) ->
+ [H|T] = binary:split(Bin, Pattern),
+ [H | case T of
+ [] ->
+ T;
+ [Rest] ->
+ split(N-1, Rest, Pattern)
+ end].
+
+%% pattern/0
+%%
+%% Since this is being called in a watchdog process, compile the
+%% pattern once and maintain it in the process dictionary.
+
+pattern() ->
+ case get(?MODULE) of
+ undefined ->
+ CP = binary:compile_pattern(<<$;>>), %% tuple
+ put(?MODULE, CP),
+ CP;
+ CP ->
+ CP
+ end.
+
+%% dispatch/1
+
+dispatch(#{} = Opts) ->
+ maps:get(dispatch, Opts, []);
+
+dispatch(Opts)
+ when is_list(Opts) ->
+ Opts;
+
+dispatch(_) ->
+ [].
+
+%% search/1
+%%
+%% Bound number of AVPs examined when looking for Session-Id.
+
+search(#{search := N})
+ when is_integer(N), 0 =< N ->
+ N;
+
+search(N)
+ when is_integer(N), 0 =< N ->
+ N;
+
+search(_) ->
+ infinity.
+
+%% default/3
+%%
+%% Choose a node when Session-Id lookup has failed.
+
+default(false, _, #{default := discard}, _) ->
+ false;
+
+default(false, _, #{default := local}, _) ->
+ node();
+
+default(false, Sid, #{default := {M,F,A}}, Info) ->
+ {ServiceName, Bin} = Info,
+ apply(M, F, [Sid, ServiceName, Bin | A]); %% node() | false
+
+default(false, Sid, _, Info) -> %% aka {?MODULE, hash, []}
+ {ServiceName, Bin} = Info,
+ hash(Sid, ServiceName, Bin);
+
+default(Node, _, _, _) ->
+ Node.
+
+%% ===========================================================================
+
+%% hash/3
+%%
+%% Consistent hashing of Session-Id to an attached node, or the local
+%% node if Session-Id = false or no attached nodes.
+
+hash(Sid, ServiceName, _) ->
+ case false /= Sid andalso attached(ServiceName) of
+ [_|_] = Nodes ->
+ hash(Sid, Nodes);
+ _ ->
+ node()
+ end.
+
+%% hash/2
+%%
+%% Consistent hashing on arbitrary key/values. Returns false if the
+%% list is empty.
+
+%% No key or no values.
+hash(_, []) ->
+ false;
+
+%% Not much choice.
+hash(_, [Value]) ->
+ Value;
+
+%% Hash on a circle and choose the closest predecessor.
+hash(Key, Values) ->
+ Hash = ?HASH(Key),
+ tl(lists:foldl(fun(V,A) ->
+ choose(Hash, [?HASH({Key, V}) | V], A)
+ end,
+ false, %% < list()
+ Values)).
+
+%% choose/3
+
+choose(Hash, [Hash1 | _] = T, [Hash2 | _])
+ when Hash1 =< Hash, Hash < Hash2 ->
+ T;
+
+choose(Hash, [Hash1 | _], [Hash2 | _] = T)
+ when Hash2 =< Hash, Hash < Hash1 ->
+ T;
+
+choose(_, T1, T2) ->
+ max(T1, T2).
+
+%% ===========================================================================
+
+%% attach/1
+%%
+%% Register the local node as a handler of incoming requests for the
+%% specified services when using the route_session/2 spawn_opt
+%% callback.
+
+attach(ServiceNames) ->
+ abcast({attach, node(), ServiceNames}).
+
+%% detach/1
+%%
+%% Deregister the local node as a handler of incoming requests.
+
+detach(ServiceNames) ->
+ abcast({detach, node(), ServiceNames}).
+
+%% abcast/1
+
+abcast(T) ->
+ gen_server:abcast([node() | nodes()], ?SERVER, T),
+ ok.
+
+%% attached/1
+
+attached(ServiceName) ->
+ try
+ ets:lookup_element(?SERVICE_TABLE, ServiceName, 2)
+ catch
+ error: badarg -> []
+ end.
+
+%% cast/2
+
+cast(Node, T) ->
+ gen_server:cast({?SERVER, Node}, T).
+
+%% attach/2
+
+attach(Node, S) ->
+ case sets:to_list(S) of
+ [] ->
+ ok;
+ Services ->
+ cast(Node, {attach, node(), Services})
+ end.
+
+%% ===========================================================================
+
+start_link() ->
+ gen_server:start_link({local, ?SERVER}, ?MODULE, _Args = [], _Opts = []).
+
+%% init/1
+%%
+%% Maintain [node() | nodes()] in a table that maps from binary-valued
+%% names, so we can lookup the corresponding atoms rather than convert
+%% binaries that aren't necessarily node names.
+
+init([]) ->
+ ets:new(?NODE_TABLE, [set, named_table]),
+ ets:new(?SERVICE_TABLE, [bag, named_table]),
+ ok = net_kernel:monitor_nodes(true, [{node_type, visible},
+ nodedown_reason]),
+ ets:insert(?NODE_TABLE, [{?B(N), N} || N <- [node() | nodes()]]),
+ abcast({attach, node()}),
+ {ok, sets:new()}.
+
+%% handle_call/3
+
+handle_call(_, _From, S) ->
+ {reply, nok, S}.
+
+%% handle_cast/2
+
+%% Remote node is asking which services the local node wants to handle.
+handle_cast({attach, Node}, S)
+ when Node /= node() ->
+ attach(Node, S),
+ {noreply, S};
+
+%% Node wants to handle incoming requests ...
+handle_cast({attach, Node, ServiceNames}, S) ->
+ ets:insert(?SERVICE_TABLE, [{N, Node} || N <- ServiceNames]),
+ {noreply, case node() of
+ Node ->
+ sets:union(S, sets:from_list(ServiceNames));
+ _ ->
+ S
+ end};
+
+%% ... or not.
+handle_cast({detach, Node, ServiceNames}, S) ->
+ ets:select_delete(?SERVICE_TABLE, [{{'$1', Node},
+ [?ORCOND([{'==', '$1', {const, N}}
+ || N <- ServiceNames])],
+ [true]}]),
+ {noreply, case node() of
+ Node ->
+ sets:subtract(S, sets:from_list(ServiceNames));
+ _ ->
+ S
+ end};
+
+handle_cast(_, S) ->
+ {noreply, S}.
+
+%% handle_info/2
+
+handle_info({nodeup, Node, _}, S) ->
+ ets:insert(?NODE_TABLE, {?B(Node), Node}),
+ cast(Node, {attach, node()}), %% ask which services remote node handles
+ attach(Node, S), %% say which service local node handles
+ {noreply, S};
+
+handle_info({nodedown, Node, _}, S) ->
+ ets:delete(?NODE_TABLE, ?B(Node)),
+ ets:select_delete(?SERVICE_TABLE, [{{'_', Node}, [], [true]}]),
+ {noreply, S};
+
+handle_info(_, S) ->
+ {noreply, S}.
+
+%% terminate/2
+
+terminate(_, _) ->
+ ok.
+
+%% code_change/3
+
+%% Old code inadvertently monitored all nodes: start a new
+%% subscription and remove the old one.
+code_change(_OldVsn, State, "2.2") ->
+ ok = net_kernel:monitor_nodes(true, [{node_type, visible},
+ nodedown_reason]),
+ ok = net_kernel:monitor_nodes(false, [{node_type, all},
+ nodedown_reason]),
+ {ok, State};
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
diff --git a/lib/diameter/src/base/diameter_gen.erl b/lib/diameter/src/base/diameter_gen.erl
index 93ebe57685..564448de48 100644
--- a/lib/diameter/src/base/diameter_gen.erl
+++ b/lib/diameter/src/base/diameter_gen.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -76,8 +76,7 @@ encode_avps(Name, Vals, #{module := Mod} = Opts) ->
?LINE,
{Reason, Name, Vals, Mod}),
erlang:error(list_to_tuple(Reason ++ [Name]));
- error: Reason ->
- Stack = erlang:get_stacktrace(),
+ error: Reason: Stack ->
diameter_lib:log({encode, failure},
?MODULE,
?LINE,
@@ -555,8 +554,8 @@ dec(Data, Name, AvpName, Type, Mod, Dict, Fmt, Failed, Opts, Avp) ->
catch
throw: {?MODULE, T} ->
decode_error(Failed, Fmt, T, Avp);
- error: Reason ->
- decode_error(Failed, Reason, Name, Mod, Opts, Avp)
+ error: Reason: Stack ->
+ decode_error(Failed, Reason, Stack, Name, Mod, Opts, Avp)
end.
%% dec_AVP/7
@@ -623,19 +622,19 @@ set(none, Avp, _Name) ->
set(_, Avp, Rec) ->
Avp#diameter_avp{value = Rec}.
-%% decode_error/6
+%% decode_error/7
%%
%% Error when decoding a non-grouped AVP.
-decode_error(true, _, _, _, _, Avp) ->
+decode_error(true, _, _, _, _, _, Avp) ->
Avp;
-decode_error(false, Reason, Name, Mod, Opts, Avp) ->
- Stack = diameter_lib:get_stacktrace(),
+decode_error(false, Reason, Stack, Name, Mod, Opts, Avp) ->
+ Z = diameter_lib:stacktrace(Stack),
diameter_lib:log(decode_error,
?MODULE,
?LINE,
- {Reason, Name, Avp#diameter_avp.name, Mod, Stack}),
+ {Reason, Name, Avp#diameter_avp.name, Mod, Z}),
case Reason of
{'DIAMETER', 5014 = RC, _} ->
%% Length error communicated from diameter_types or a
diff --git a/lib/diameter/src/base/diameter_internal.hrl b/lib/diameter/src/base/diameter_internal.hrl
index a0f4a8567d..4a678643c2 100644
--- a/lib/diameter/src/base/diameter_internal.hrl
+++ b/lib/diameter/src/base/diameter_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -35,9 +35,6 @@
%% A corresponding error when failure is the best option.
-define(ERROR(T), erlang:error({T, ?MODULE, ?LINE})).
-%% Failure reports always get a stack trace.
--define(STACK, erlang:get_stacktrace()).
-
%% Warning report for unexpected messages in various processes.
-define(UNEXPECTED(F,A),
diameter_lib:warning_report(unexpected, {?MODULE, F, A})).
diff --git a/lib/diameter/src/base/diameter_lib.erl b/lib/diameter/src/base/diameter_lib.erl
index 1c1ea42cb5..edd9d5a4ce 100644
--- a/lib/diameter/src/base/diameter_lib.erl
+++ b/lib/diameter/src/base/diameter_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -33,7 +33,7 @@
time/1,
eval/1,
eval_name/1,
- get_stacktrace/0,
+ stacktrace/1,
ipaddr/1,
spawn_opts/2,
wait/1,
@@ -42,16 +42,13 @@
log/4]).
%% ---------------------------------------------------------------------------
-%% # get_stacktrace/0
+%% # stacktrace/1
%% ---------------------------------------------------------------------------
%% Return a stacktrace with a leading, potentially large, argument
-%% list replaced by an arity. Trace on stacktrace/0 to see the
+%% list replaced by an arity. Trace on stacktrace/1 to see the
%% original.
-get_stacktrace() ->
- stacktrace(erlang:get_stacktrace()).
-
stacktrace([{M,F,A,L} | T]) when is_list(A) ->
[{M, F, length(A), L} | T];
stacktrace(L) ->
@@ -268,8 +265,8 @@ ipaddr(Addr) ->
try
ip(Addr)
catch
- error: _ ->
- erlang:error({invalid_address, erlang:get_stacktrace()})
+ error: _: Stack ->
+ erlang:error({invalid_address, Stack})
end.
%% Already a tuple: ensure non-negative integers of the right size.
diff --git a/lib/diameter/src/base/diameter_misc_sup.erl b/lib/diameter/src/base/diameter_misc_sup.erl
index 343688be23..fec5a41b5c 100644
--- a/lib/diameter/src/base/diameter_misc_sup.erl
+++ b/lib/diameter/src/base/diameter_misc_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -35,6 +35,7 @@
diameter_stats, %% statistics counter management
diameter_reg, %% service/property publishing
diameter_peer, %% remote peer manager
+ diameter_dist, %% request distribution
diameter_config]). %% configuration/restart
%% start_link/0
diff --git a/lib/diameter/src/base/diameter_peer_fsm.erl b/lib/diameter/src/base/diameter_peer_fsm.erl
index d99f11a697..cf5e7f21d3 100644
--- a/lib/diameter/src/base/diameter_peer_fsm.erl
+++ b/lib/diameter/src/base/diameter_peer_fsm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -901,7 +901,7 @@ outgoing(#diameter_packet{header = #diameter_header{is_request = false}}
ok;
%% Outgoing request: discard.
-outgoing(Msg, #state{dpr = {_,_,_}}) ->
+outgoing(Msg, #state{}) ->
invalid(false, send_after_dpr, header(Msg)).
header(#diameter_packet{header = H}) ->
diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl
index cbe66ef27a..77d184cfc7 100644
--- a/lib/diameter/src/base/diameter_service.erl
+++ b/lib/diameter/src/base/diameter_service.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -808,8 +808,8 @@ remotes(F) ->
error_report(invalid_return, share_peers, F),
[]
catch
- E:R ->
- ?LOG(failure, {E, R, F, diameter_lib:get_stacktrace()}),
+ E:R:S ->
+ ?LOG(failure, {E, R, F, diameter_lib:stacktrace(S)}),
error_report(failure, share_peers, F),
[]
end.
@@ -1146,11 +1146,11 @@ peer_cb(App, F, A) ->
mod_state(App#diameter_app.alias, ModS),
true
catch
- E:R ->
+ E:R:S ->
%% Don't include arguments since a #diameter_caps{} strings
%% from the peer, which could be anything (especially, large).
[Mod|X] = App#diameter_app.module,
- ?LOG(failure, {E, R, Mod, F, diameter_lib:get_stacktrace()}),
+ ?LOG(failure, {E, R, Mod, F, diameter_lib:stacktrace(S)}),
error_report(failure, F, {Mod, F, A ++ X}),
false
end.
@@ -1376,9 +1376,9 @@ cm([#diameter_app{alias = Alias} = App], Req, From, Svc) ->
?LOG(invalid_return, {ModX, handle_call, Args, T}),
invalid
catch
- E: Reason ->
+ E: Reason: S ->
ModX = App#diameter_app.module,
- Stack = diameter_lib:get_stacktrace(),
+ Stack = diameter_lib:stacktrace(S),
?LOG(failure, {E, Reason, ModX, handle_call, Stack}),
failure
end;
@@ -1585,10 +1585,10 @@ pick_peer(Local,
?LOG(invalid_return, {ModX, pick_peer, T}),
false
catch
- E: Reason when M ->
+ E: Reason: Stack when M ->
ModX = App#diameter_app.module,
- Stack = diameter_lib:get_stacktrace(),
- ?LOG(failure, {E, Reason, ModX, pick_peer, Stack}),
+ Z = diameter_lib:stacktrace(Stack),
+ ?LOG(failure, {E, Reason, ModX, pick_peer, Z}),
false
end.
diff --git a/lib/diameter/src/base/diameter_traffic.erl b/lib/diameter/src/base/diameter_traffic.erl
index d2856ae530..8423e30269 100644
--- a/lib/diameter/src/base/diameter_traffic.erl
+++ b/lib/diameter/src/base/diameter_traffic.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -42,8 +42,12 @@
peer_up/1,
peer_down/1]).
+%% towards diameter_dist
+-export([request_info/1]).
+
%% internal
-export([send/1, %% send from remote node
+ request/1, %% process request in handler process
init/1]). %% monitor process start
-include_lib("diameter/include/diameter.hrl").
@@ -232,7 +236,7 @@ incr_rc(Dir, Pkt, TPid, MsgDict, AppDict, Dict0) ->
-spec receive_message(pid(), Route, #diameter_packet{}, module(), RecvData)
-> pid() %% request handler
| boolean() %% answer, known request or not
- | discard %% request discarded by MFA
+ | discard %% request discarded
when Route :: {Handler, RequestRef, TPid}
| Ack,
RecvData :: {[SpawnOpt], #recvdata{}},
@@ -252,7 +256,8 @@ receive_message(TPid, Route, Pkt, Dict0, RecvData) ->
recv(true, Ack, TPid, Pkt, Dict0, T)
when is_boolean(Ack) ->
{Opts, RecvData} = T,
- spawn_request(Ack, TPid, Pkt, Dict0, RecvData, Opts);
+ AppT = find_app(TPid, Pkt, RecvData),
+ ack(Ack, TPid, spawn_request(AppT, Opts, Ack, TPid, Pkt, Dict0, RecvData));
%% ... answer to known request ...
recv(false, {Pid, Ref, TPid}, _, Pkt, Dict0, _) ->
@@ -274,58 +279,73 @@ recv(false, false, TPid, Pkt, _, _) ->
incr(TPid, {{unknown, 0}, recv, discarded}),
false.
-%% spawn_request/6
+%% spawn_request/7
+
+spawn_request(false, _, _, _, _, _, _) -> %% no transport
+ discard;
-%% An MFA should return a pid() or the atom 'discard'. The latter
-%% results in an acknowledgment back to the transport process when
-%% appropriate, to ensure that send/recv callbacks can count
-%% outstanding requests. Acknowledgement is implicit if the
+%% An MFA should return the pid() of a process in which the argument
+%% fun in applied, or the atom 'discard' if the fun is not applied.
+%% The latter results in an acknowledgment back to the transport
+%% process when appropriate, to ensure that send/recv callbacks can
+%% count outstanding requests. Acknowledgement is implicit if the
%% handler process dies (in a handle_request callback for example).
-spawn_request(Ack, TPid, Pkt, Dict0, RecvData, {M,F,A}) ->
- ReqF = fun() ->
- ack(Ack, TPid, recv_request(Ack, TPid, Pkt, Dict0, RecvData))
- end,
- ack(Ack, TPid, apply(M, F, [ReqF | A]));
+spawn_request(AppT, {M,F,A}, Ack, TPid, Pkt, Dict0, RecvData) ->
+ %% Term to pass to request/1 in an appropriate process. Module
+ %% diameter_dist implements callbacks.
+ ReqT = {Pkt, AppT, Ack, TPid, Dict0, RecvData},
+ apply(M, F, [ReqT | A]);
%% A spawned process acks implicitly when it dies, so there's no need
%% to handle 'discard'.
-spawn_request(Ack, TPid, Pkt, Dict0, RecvData, Opts) ->
+spawn_request(AppT, Opts, Ack, TPid, Pkt, Dict0, RecvData) ->
spawn_opt(fun() ->
- recv_request(Ack, TPid, Pkt, Dict0, RecvData)
+ recv_request(Ack, TPid, Pkt, Dict0, RecvData, AppT)
end,
Opts).
+%% request_info/1
+%%
+%% Limited request information for diameter_dist.
+
+request_info({Pkt, _AppT, _Ack, _TPid, _Dict0, RecvData} = _ReqT) ->
+ {RecvData#recvdata.service_name, Pkt#diameter_packet.bin}.
+
+%% request/1
+%%
+%% Called from a handler process chosen by a transport spawn_opt MFA
+%% to process an incoming request.
+
+request({Pkt, AppT, Ack, TPid, Dict0, RecvData} = _ReqT) ->
+ ack(Ack, TPid, recv_request(Ack, TPid, Pkt, Dict0, RecvData, AppT)).
+
%% ack/3
ack(Ack, TPid, RC) ->
- RC == discard andalso Ack andalso (TPid ! {send, false}),
+ RC == discard
+ andalso Ack
+ andalso (TPid ! {send, false}),
RC.
%% ---------------------------------------------------------------------------
-%% recv_request/5
+%% recv_request/6
%% ---------------------------------------------------------------------------
-spec recv_request(Ack :: boolean(),
TPid :: pid(),
#diameter_packet{},
Dict0 :: module(),
- #recvdata{})
+ #recvdata{},
+ AppT :: {#diameter_app{}, #diameter_caps{}}
+ | #diameter_caps{}) %% no suitable app
-> ok %% answer was sent
- | discard %% or not
- | false. %% no transport
-
-recv_request(Ack,
- TPid,
- #diameter_packet{header = #diameter_header{application_id = Id}}
- = Pkt,
- Dict0,
- #recvdata{peerT = PeerT,
- apps = Apps,
- counters = Count}
- = RecvData) ->
+ | discard. %% or not
+
+recv_request(Ack, TPid, Pkt, Dict0, RecvData, AppT) ->
Ack andalso (TPid ! {handler, self()}),
- case diameter_service:find_incoming_app(PeerT, TPid, Id, Apps) of
+ case AppT of
{#diameter_app{id = Aid, dictionary = AppDict} = App, Caps} ->
+ Count = RecvData#recvdata.counters,
Count andalso incr(recv, Pkt, TPid, AppDict),
DecPkt = decode(Aid, AppDict, RecvData, Pkt),
Count andalso incr_error(recv, DecPkt, TPid, AppDict),
@@ -349,11 +369,20 @@ recv_request(Ack,
Dict0,
RecvData,
DecPkt,
- [[]]);
- false = No -> %% transport has gone down
- No
+ [[]])
end.
+%% find_app/3
+%%
+%% Lookup the application of a received Diameter request on the node
+%% on which it's received.
+
+find_app(TPid,
+ #diameter_packet{header = #diameter_header{application_id = Id}},
+ #recvdata{peerT = PeerT,
+ apps = Apps}) ->
+ diameter_service:find_incoming_app(PeerT, TPid, Id, Apps).
+
%% decode/4
decode(Id, Dict, #recvdata{codec = Opts}, Pkt) ->
@@ -1925,6 +1954,8 @@ get_avp(Dict, Name, [#diameter_header{} | Avps]) ->
A = find_avp(Code, Vid, Avps),
avp_decode(Dict, Name, ungroup(A))
catch
+ {diameter_gen, _} -> %% faulty Grouped AVP
+ undefined;
error: _ ->
undefined
end;
diff --git a/lib/diameter/src/compiler/diameter_exprecs.erl b/lib/diameter/src/compiler/diameter_exprecs.erl
index 143dede037..ded07f2353 100644
--- a/lib/diameter/src/compiler/diameter_exprecs.erl
+++ b/lib/diameter/src/compiler/diameter_exprecs.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/diameter/src/compiler/diameter_make.erl b/lib/diameter/src/compiler/diameter_make.erl
index eae40dbafd..03cfc03edc 100644
--- a/lib/diameter/src/compiler/diameter_make.erl
+++ b/lib/diameter/src/compiler/diameter_make.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -271,6 +271,6 @@ make(File, Opts, Dict, Mode) ->
try
diameter_codegen:from_dict(File, Dict, Opts, Mode)
catch
- error: Reason ->
- erlang:error({Reason, Mode, erlang:get_stacktrace()})
+ error: Reason: Stack ->
+ erlang:error({Reason, Mode, Stack})
end.
diff --git a/lib/diameter/src/diameter.app.src b/lib/diameter/src/diameter.app.src
index 9a6e47006b..18202f033e 100644
--- a/lib/diameter/src/diameter.app.src
+++ b/lib/diameter/src/diameter.app.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -28,14 +28,21 @@
]},
{registered, [%REGISTERED%]},
{applications, [
- {stdlib, "2.4"}, {kernel, "3.2"}%, {erts, "6.4"}
- %% {syntax-tools, "1.6,18"}
- %% {runtime-tools, "1.8.16"}
- %, {ssl, "6.0"}
+ stdlib,
+ kernel
+ %, ssl
+ %, syntax-tools
+ %, runtime-tools
]},
{env, []},
{mod, {diameter_app, []}},
{runtime_dependencies, [
+ "erts-10.0",
+ "stdlib-2.4",
+ "kernel-3.2",
+ "ssl-9.0"
+ %, "syntax-tools-1.6.18"
+ %, "runtime-tools-1.8.16"
]}
%%
%% Note that ssl is only required if configured on TCP transports,
diff --git a/lib/diameter/src/diameter.appup.src b/lib/diameter/src/diameter.appup.src
index 05a8c9378e..bb2a4a8e92 100644
--- a/lib/diameter/src/diameter.appup.src
+++ b/lib/diameter/src/diameter.appup.src
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -57,7 +57,12 @@
{"2.1", [{restart_application, diameter}]}, %% 20.1
{"2.1.1", [{restart_application, diameter}]}, %% 20.1.2
{"2.1.2", [{restart_application, diameter}]}, %% 20.1.3
- {"2.1.3", [{restart_application, diameter}]} %% 20.2
+ {"2.1.3", [{restart_application, diameter}]}, %% 20.2
+ {"2.1.4", [{restart_application, diameter}]}, %% 20.3
+ {"2.1.4.1", [{restart_application, diameter}]}, %% 20.3.8.19
+ {"2.1.5", [{restart_application, diameter}]}, %% 21.0
+ {"2.1.6", [{restart_application, diameter}]}, %% 21.1
+ {"2.2", [{update, diameter_dist, {advanced, "2.2"}}]} %% 21.3
],
[
{"0.9", [{restart_application, diameter}]},
@@ -96,6 +101,11 @@
{"2.1", [{restart_application, diameter}]},
{"2.1.1", [{restart_application, diameter}]},
{"2.1.2", [{restart_application, diameter}]},
- {"2.1.3", [{restart_application, diameter}]}
+ {"2.1.3", [{restart_application, diameter}]},
+ {"2.1.4", [{restart_application, diameter}]},
+ {"2.1.4.1", [{restart_application, diameter}]},
+ {"2.1.5", [{restart_application, diameter}]},
+ {"2.1.6", [{restart_application, diameter}]},
+ {"2.2", [{restart_application, diameter}]}
]
}.
diff --git a/lib/diameter/src/modules.mk b/lib/diameter/src/modules.mk
index bb86de016a..d16292bb88 100644
--- a/lib/diameter/src/modules.mk
+++ b/lib/diameter/src/modules.mk
@@ -1,7 +1,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2010-2017. All Rights Reserved.
+# Copyright Ericsson AB 2010-2019. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -40,6 +40,7 @@ RT_MODULES = \
base/diameter_config \
base/diameter_config_sup \
base/diameter_codec \
+ base/diameter_dist \
base/diameter_gen \
base/diameter_lib \
base/diameter_misc_sup \
diff --git a/lib/diameter/src/transport/diameter_tcp.erl b/lib/diameter/src/transport/diameter_tcp.erl
index a8639baa11..e5e766d2a0 100644
--- a/lib/diameter/src/transport/diameter_tcp.erl
+++ b/lib/diameter/src/transport/diameter_tcp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -92,9 +92,9 @@
-type connect_option() :: {raddr, inet:ip_address()}
| {rport, pos_integer()}
- | {ssl_options, true | [ssl:connect_option()]}
+ | {ssl_options, true | [ssl:tls_client_option()]}
| option()
- | ssl:connect_option()
+ | ssl:tls_client_option()
| gen_tcp:connect_option().
-type match() :: inet:ip_address()
@@ -102,9 +102,9 @@
| [match()].
-type listen_option() :: {accept, match()}
- | {ssl_options, true | [ssl:listen_option()]}
+ | {ssl_options, true | [ssl:tls_server_option()]}
| option()
- | ssl:listen_option()
+ | ssl:tls_server_option()
| gen_tcp:listen_option().
-type option() :: {port, non_neg_integer()}
@@ -716,7 +716,7 @@ tls_handshake(_, false, S) ->
tls(connect, Sock, Opts) ->
ssl:connect(Sock, Opts);
tls(accept, Sock, Opts) ->
- ssl:ssl_accept(Sock, Opts).
+ ssl:handshake(Sock, Opts). %% assume no handshake option
%% recv/2
%%
@@ -839,7 +839,7 @@ start_fragment_timer(#transport{timeout = Tmo} = S) ->
accept(ssl, LSock) ->
case ssl:transport_accept(LSock) of
{ok, Sock} ->
- {ssl:ssl_accept(Sock), Sock};
+ ssl:handshake(Sock);
{error, _} = No ->
No
end;
diff --git a/lib/diameter/test/diameter_app_SUITE.erl b/lib/diameter/test/diameter_app_SUITE.erl
index 71256020f5..ef4a28d3f4 100644
--- a/lib/diameter/test/diameter_app_SUITE.erl
+++ b/lib/diameter/test/diameter_app_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -208,9 +208,9 @@ xref(Config) ->
CTmods = CTmods -- Mods,
%% Ensure that runtime modules only call other runtime modules, or
- %% applications declared as in runtime_dependencies in the app
- %% file. Note that the declared application versions are ignored
- %% since we only know what we can see now.
+ %% applications declared in runtime_dependencies in the app file.
+ %% The declared application versions are ignored since we only
+ %% know what we see now.
[] = lists:filter(fun(M) -> not lists:member(app(M), Deps) end,
RTdeps -- Mods).
@@ -261,8 +261,12 @@ app(Mod) ->
case code:which(Mod) of
preloaded ->
"erts";
+ Reason when is_atom(Reason) ->
+ error({Reason, Mod});
Path ->
- unversion(lists:nth(3, lists:reverse(filename:split(Path))))
+ %% match to identify an unexpectedly short path
+ {_, _, [_,_,_|_] = Split} = {Mod, Path, filename:split(Path)},
+ unversion(lists:nth(3, lists:reverse(Split)))
end.
add_application(XRef, App) ->
diff --git a/lib/diameter/test/diameter_dist_SUITE.erl b/lib/diameter/test/diameter_dist_SUITE.erl
new file mode 100644
index 0000000000..b2e4c35b9a
--- /dev/null
+++ b/lib/diameter/test/diameter_dist_SUITE.erl
@@ -0,0 +1,332 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%% Tests of traffic between two Diameter nodes, the server being
+%% spread across three Erlang nodes.
+%%
+
+-module(diameter_dist_SUITE).
+
+-export([suite/0,
+ all/0]).
+
+%% testcases
+-export([enslave/1, enslave/0,
+ ping/1,
+ start/1,
+ connect/1,
+ send/1,
+ stop/1, stop/0]).
+
+%% diameter callbacks
+-export([peer_up/3,
+ peer_down/3,
+ pick_peer/4,
+ prepare_request/3,
+ prepare_retransmit/3,
+ handle_answer/4,
+ handle_error/4,
+ handle_request/3]).
+
+-export([call/1]).
+
+-include("diameter.hrl").
+-include("diameter_gen_base_rfc6733.hrl").
+
+%% ===========================================================================
+
+-define(util, diameter_util).
+
+-define(CLIENT, 'CLIENT').
+-define(SERVER, 'SERVER').
+-define(REALM, "erlang.org").
+-define(DICT, diameter_gen_base_rfc6733).
+-define(ADDR, {127,0,0,1}).
+
+%% Config for diameter:start_service/2.
+-define(SERVICE(Host),
+ [{'Origin-Host', Host ++ [$.|?REALM]},
+ {'Origin-Realm', ?REALM},
+ {'Host-IP-Address', [?ADDR]},
+ {'Vendor-Id', 12345},
+ {'Product-Name', "OTP/diameter"},
+ {'Auth-Application-Id', [?DICT:id()]},
+ {'Origin-State-Id', origin()},
+ {spawn_opt, {diameter_dist, route_session, [#{id => []}]}},
+ {sequence, fun sequence/0},
+ {string_decode, false},
+ {application, [{dictionary, ?DICT},
+ {module, ?MODULE},
+ {request_errors, callback},
+ {answer_errors, callback}]}]).
+
+-define(SUCCESS, 2001).
+-define(BUSY, 3004).
+-define(LOGOUT, ?'DIAMETER_BASE_TERMINATION-CAUSE_LOGOUT').
+-define(MOVED, ?'DIAMETER_BASE_TERMINATION-CAUSE_USER_MOVED').
+-define(TIMEOUT, ?'DIAMETER_BASE_TERMINATION-CAUSE_SESSION_TIMEOUT').
+
+-define(L, atom_to_list).
+-define(A, list_to_atom).
+
+%% The order here is significant and causes the server to listen
+%% before the clients connect. The server listens on the first node,
+%% and distributes requests to the other two.
+-define(NODES, [{server0, ?SERVER},
+ {server1, ?SERVER},
+ {server2, ?SERVER},
+ {client, ?CLIENT}]).
+
+%% Options to ct_slave:start/2.
+-define(TIMEOUTS, [{T, 15000} || T <- [boot_timeout,
+ init_timeout,
+ start_timeout]]).
+
+%% ===========================================================================
+
+suite() ->
+ [{timetrap, {seconds, 60}}].
+
+all() ->
+ [enslave,
+ ping,
+ start,
+ connect,
+ send,
+ stop].
+
+%% ===========================================================================
+%% start/stop testcases
+
+%% enslave/1
+%%
+%% Start four slave nodes, three to implement a Diameter server,
+%% one to implement a client.
+
+enslave() ->
+ [{timetrap, {seconds, 30*length(?NODES)}}].
+
+enslave(Config) ->
+ Here = filename:dirname(code:which(?MODULE)),
+ Ebin = filename:join([Here, "..", "ebin"]),
+ Dirs = [Here, Ebin],
+ Nodes = [{N,S} || {M,S} <- ?NODES, N <- [slave(M, Dirs)]],
+ ?util:write_priv(Config, nodes, [{N,S} || {{N,ok},S} <- Nodes]),
+ [] = [{T,S} || {{_,E} = T, S} <- Nodes, E /= ok].
+
+slave(Name, Dirs) ->
+ add_pathsa(Dirs, ct_slave:start(Name, ?TIMEOUTS)).
+
+add_pathsa(Dirs, {ok, Node}) ->
+ {Node, rpc:call(Node, code, add_pathsa, [Dirs])};
+add_pathsa(_, No) ->
+ {No, error}.
+
+%% ping/1
+%%
+%% Ensure the server nodes are connected so that diameter_dist can attach.
+
+ping({S, Nodes}) ->
+ ?SERVER = S,
+ [N || {N,_} <- Nodes,
+ node() /= N,
+ pang <- [net_adm:ping(N)]];
+
+ping(Config) ->
+ Nodes = lists:droplast(?util:read_priv(Config, nodes)),
+ [] = [{N,RC} || {N,S} <- Nodes,
+ RC <- [rpc:call(N, ?MODULE, ping, [{S,Nodes}])],
+ RC /= []].
+
+%% start/1
+%%
+%% Start diameter services.
+
+start(SvcName)
+ when is_atom(SvcName) ->
+ ok = diameter:start(),
+ ok = diameter:start_service(SvcName, ?SERVICE((?L(SvcName))));
+
+start(Config) ->
+ Nodes = ?util:read_priv(Config, nodes),
+ [] = [{N,RC} || {N,S} <- Nodes,
+ RC <- [rpc:call(N, ?MODULE, start, [S])],
+ RC /= ok].
+
+sequence() ->
+ sequence(sname()).
+
+sequence(client) ->
+ {0,32};
+sequence(Server) ->
+ "server" ++ N = ?L(Server),
+ {list_to_integer(N), 30}.
+
+origin() ->
+ origin(sname()).
+
+origin(client) ->
+ 99;
+origin(Server) ->
+ "server" ++ N = ?L(Server),
+ list_to_integer(N).
+
+%% connect/1
+%%
+%% Establish one connection from the client, terminated on the first
+%% server node, the others handling requests.
+
+connect({?SERVER, Config, [{Node, _} | _]}) ->
+ if Node == node() -> %% server0
+ ?util:write_priv(Config, lref, {Node, ?util:listen(?SERVER, tcp)});
+ true ->
+ diameter_dist:attach([?SERVER])
+ end,
+ ok;
+
+connect({?CLIENT, Config, _}) ->
+ ?util:connect(?CLIENT, tcp, ?util:read_priv(Config, lref)),
+ ok;
+
+connect(Config) ->
+ Nodes = ?util:read_priv(Config, nodes),
+ [] = [{N,RC} || {N,S} <- Nodes,
+ RC <- [rpc:call(N, ?MODULE, connect, [{S, Config, Nodes}])],
+ RC /= ok].
+
+%% stop/1
+%%
+%% Stop the slave nodes.
+
+stop() ->
+ [{timetrap, {seconds, 30*length(?NODES)}}].
+
+stop(_Config) ->
+ [] = [{N,E} || {N,_} <- ?NODES,
+ {error, _, _} = E <- [ct_slave:stop(N)]].
+
+%% ===========================================================================
+%% traffic testcases
+
+%% send/1
+%%
+%% Send 100 requests and ensure the node name sent as User-Name isn't
+%% the node terminating transport.
+
+send(Config) ->
+ send(Config, 100, dict:new()).
+
+%% send/2
+
+send(Config, 0, Dict) ->
+ [{Server0, _} | _] = ?util:read_priv(Config, nodes) ,
+ Node = atom_to_binary(Server0, utf8),
+ {false, _} = {dict:is_key(Node, Dict), dict:to_list(Dict)};
+
+send(Config, N, Dict) ->
+ #diameter_base_STA{'Result-Code' = ?SUCCESS,
+ 'User-Name' = [ServerNode]}
+ = send(Config, str(?LOGOUT)),
+ true = is_binary(ServerNode),
+ send(Config, N-1, dict:update_counter(ServerNode, 1, Dict)).
+
+%% ===========================================================================
+
+str(Cause) ->
+ #diameter_base_STR{'Destination-Realm' = ?REALM,
+ 'Auth-Application-Id' = ?DICT:id(),
+ 'Termination-Cause' = Cause}.
+
+%% send/2
+
+send(Config, Req) ->
+ {Node, _} = lists:last(?util:read_priv(Config, nodes)),
+ rpc:call(Node, ?MODULE, call, [Req]).
+
+%% call/1
+
+call(Req) ->
+ diameter:call(?CLIENT, ?DICT, Req, []).
+
+%% sname/0
+
+sname() ->
+ ?A(hd(string:tokens(?L(node()), "@"))).
+
+%% ===========================================================================
+%% diameter callbacks
+
+%% peer_up/3
+
+peer_up(_SvcName, _Peer, State) ->
+ State.
+
+%% peer_down/3
+
+peer_down(_SvcName, _Peer, State) ->
+ State.
+
+%% pick_peer/4
+
+pick_peer([Peer], [], ?CLIENT, _State) ->
+ {ok, Peer}.
+
+%% prepare_request/3
+
+prepare_request(Pkt, ?CLIENT, {_Ref, Caps}) ->
+ #diameter_packet{msg = Req}
+ = Pkt,
+ #diameter_caps{origin_host = {OH, _},
+ origin_realm = {OR, _}}
+ = Caps,
+ {send, Req#diameter_base_STR{'Origin-Host' = OH,
+ 'Origin-Realm' = OR,
+ 'Session-Id' = diameter:session_id(OH)}}.
+
+%% prepare_retransmit/3
+
+prepare_retransmit(_, ?CLIENT, _) ->
+ discard.
+
+%% handle_answer/5
+
+handle_answer(Pkt, _Req, ?CLIENT, _Peer) ->
+ #diameter_packet{msg = Rec, errors = []} = Pkt,
+ Rec.
+
+%% handle_error/5
+
+handle_error(Reason, _Req, ?CLIENT, _Peer) ->
+ {error, Reason}.
+
+%% handle_request/3
+
+handle_request(Pkt, ?SERVER, {_, Caps}) ->
+ #diameter_packet{msg = #diameter_base_STR{'Session-Id' = SId}}
+ = Pkt,
+ #diameter_caps{origin_host = {OH, _},
+ origin_realm = {OR, _}}
+ = Caps,
+ {reply, #diameter_base_STA{'Result-Code' = ?SUCCESS,
+ 'Session-Id' = SId,
+ 'Origin-Host' = OH,
+ 'Origin-Realm' = OR,
+ 'User-Name' = [atom_to_binary(node(), utf8)]}}.
diff --git a/lib/diameter/test/diameter_distribution_SUITE.erl b/lib/diameter/test/diameter_distribution_SUITE.erl
index 5146f68ff1..5fe02284ae 100644
--- a/lib/diameter/test/diameter_distribution_SUITE.erl
+++ b/lib/diameter/test/diameter_distribution_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -76,6 +76,7 @@
{share_peers, peers()},
{use_shared_peers, peers()},
{restrict_connections, false},
+ {spawn_opt, {diameter_dist, spawn_local, []}},
{sequence, fun sequence/0},
{application, [{dictionary, ?DICT},
{module, ?MODULE},
@@ -125,7 +126,7 @@ all() ->
%% enslave/1
%%
%% Start four slave nodes, one to implement a Diameter server,
-%% two three to implement a client.
+%% three to implement a client.
enslave() ->
[{timetrap, {seconds, 30*length(?NODES)}}].
@@ -331,6 +332,8 @@ prepare_request(Pkt, ?CLIENT, {_Ref, Caps}, {_, client0}) ->
'Origin-Realm' = OR,
'Session-Id' = diameter:session_id(OH)}}.
+%% prepare_retransmit/4
+
prepare_retransmit(Pkt, ?CLIENT, _, {_, client0}) ->
#diameter_packet{msg = #diameter_base_STR{'Termination-Cause' = ?MOVED}}
= Pkt, %% assert
diff --git a/lib/diameter/test/diameter_pool_SUITE.erl b/lib/diameter/test/diameter_pool_SUITE.erl
index 97c16940ff..a36a4fa17a 100644
--- a/lib/diameter/test/diameter_pool_SUITE.erl
+++ b/lib/diameter/test/diameter_pool_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -51,6 +51,7 @@
{'Auth-Application-Id', [0]}, %% common
{'Acct-Application-Id', [3]}, %% accounting
{restrict_connections, false},
+ {spawn_opt, {diameter_dist, route_session, []}},
{application, [{alias, common},
{dictionary, diameter_gen_base_rfc6733},
{module, diameter_callback}]},
diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl
index c224f9a27e..47b00c25a2 100644
--- a/lib/diameter/test/diameter_traffic_SUITE.erl
+++ b/lib/diameter/test/diameter_traffic_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -539,8 +539,7 @@ add_transports(Config) ->
++ [{unordered, unordered()} || T == sctp],
[{capabilities_cb, fun capx/2},
{pool_size, 8}
- | server_apps()]
- ++ [{spawn_opt, {erlang, spawn, []}} || CS]),
+ | server_apps()]),
Cs = [?util:connect(CN,
[T, {sender, CS} | client_opts(T)],
LRef,
@@ -1924,8 +1923,8 @@ compile_and_load() ->
{module, nas4005} = code:load_binary(nas4005, "nas4005", Bin),
true
catch
- E:R ->
- {E, R, erlang:get_stacktrace()}
+ E:R:Stack ->
+ {E, R, Stack}
end.
here() ->
diff --git a/lib/diameter/test/diameter_watchdog_SUITE.erl b/lib/diameter/test/diameter_watchdog_SUITE.erl
index 39c4f051a5..f3f168e671 100644
--- a/lib/diameter/test/diameter_watchdog_SUITE.erl
+++ b/lib/diameter/test/diameter_watchdog_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -638,10 +638,9 @@ run1([F|A]) ->
apply(?MODULE, F, A),
ok
catch
- E:R ->
- S = erlang:get_stacktrace(),
- ?WARN("~p", [{A, E, R, S}]),
- S
+ E:R:Stack ->
+ ?WARN("~p", [{A, E, R, Stack}]),
+ Stack
end.
%% jitter/2
diff --git a/lib/diameter/test/modules.mk b/lib/diameter/test/modules.mk
index 0c73adca12..90b0a25d5f 100644
--- a/lib/diameter/test/modules.mk
+++ b/lib/diameter/test/modules.mk
@@ -1,7 +1,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2010-2017. All Rights Reserved.
+# Copyright Ericsson AB 2010-2019. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@ MODULES = \
diameter_codec_test \
diameter_config_SUITE \
diameter_compiler_SUITE \
+ diameter_dist_SUITE \
diameter_distribution_SUITE \
diameter_dpr_SUITE \
diameter_event_SUITE \
diff --git a/lib/diameter/vsn.mk b/lib/diameter/vsn.mk
index b0fb4ada28..a8fbca5bc8 100644
--- a/lib/diameter/vsn.mk
+++ b/lib/diameter/vsn.mk
@@ -17,5 +17,5 @@
# %CopyrightEnd%
APPLICATION = diameter
-DIAMETER_VSN = 2.1.4
+DIAMETER_VSN = 2.2.1
APP_VSN = $(APPLICATION)-$(DIAMETER_VSN)$(PRE_VSN)
diff --git a/lib/edoc/doc/edoc.dtd b/lib/edoc/doc/edoc.dtd
new file mode 120000
index 0000000000..43f4b27db6
--- /dev/null
+++ b/lib/edoc/doc/edoc.dtd
@@ -0,0 +1 @@
+../priv/edoc.dtd \ No newline at end of file
diff --git a/lib/edoc/doc/edoc_doclet.hrl b/lib/edoc/doc/edoc_doclet.hrl
new file mode 120000
index 0000000000..4623b18bb4
--- /dev/null
+++ b/lib/edoc/doc/edoc_doclet.hrl
@@ -0,0 +1 @@
+../include/edoc_doclet.hrl \ No newline at end of file
diff --git a/lib/edoc/doc/src/Makefile b/lib/edoc/doc/src/Makefile
index ca9ea66e3c..3e53e75c75 100644
--- a/lib/edoc/doc/src/Makefile
+++ b/lib/edoc/doc/src/Makefile
@@ -54,9 +54,10 @@ XML_NOTES_FILES = notes.xml
BOOK_FILES = book.xml
XML_FILES=\
- $(BOOK_FILES) $(XML_CHAPTER_FILES) \
- $(XML_PART_FILES) $(XML_REF3_FILES) $(XML_APPLICATION_FILES) \
- $(XML_NOTES_FILES)
+ $(BOOK_FILES) $(XML_APPLICATION_FILES) \
+ $(XML_PART_FILES) $(XML_NOTES_FILES)
+
+XML_GEN_FILES=$(XML_REF3_FILES:%=$(XMLDIR)/%) $(XML_CHAPTER_FILES:%=$(XMLDIR)/%)
# ----------------------------------------------------
INFO_FILE = ../../info
@@ -78,6 +79,11 @@ HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
+INCLUDES_DIR = ../../include
+INCLUDES = $(INCLUDES_DIR)/edoc_doclet.hrl
+
+DTDS_DIR = ../../priv
+DTDS = $(DTDS_DIR)/edoc.dtd
# ----------------------------------------------------
# FLAGS
@@ -101,11 +107,11 @@ html: gifs $(HTML_REF_MAN_FILE)
man: $(MAN3_FILES)
-$(XML_REF3_FILES):
- escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(EDOC_VSN) -i $(ERL_TOP)/lib/edoc/include $(SRC_DIR)/$(@:%.xml=%.erl)
+$(XML_REF3_FILES:%=$(XMLDIR)/%):
+ $(gen_verbose)escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(EDOC_VSN) -i $(ERL_TOP)/lib/edoc/include -dir $(XMLDIR) $(SRC_DIR)/$(@:$(XMLDIR)/%.xml=%.erl)
-$(XML_CHAPTER_FILES): ../overview.edoc
- escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(EDOC_VSN) -chapter ../overview.edoc
+$(XML_CHAPTER_FILES:%=$(XMLDIR)/%): ../overview.edoc
+ $(gen_verbose)escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(EDOC_VSN) -chapter -dir $(XMLDIR) $<
gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
@@ -113,6 +119,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(XML_REF3_FILES) $(XML_CHAPTER_FILES) *.html
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
@@ -133,5 +140,6 @@ release_docs_spec: docs
$(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
$(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
$(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(INCLUDES) $(DTDS) "$(RELSYSDIR)/doc/html"
release_spec:
diff --git a/lib/edoc/doc/src/notes.xml b/lib/edoc/doc/src/notes.xml
index 240789e876..48bc5d9c74 100644
--- a/lib/edoc/doc/src/notes.xml
+++ b/lib/edoc/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2007</year><year>2017</year>
+ <year>2007</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,6 +32,78 @@
<p>This document describes the changes made to the EDoc
application.</p>
+<section><title>Edoc 0.11</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> Correct links in the documentation. </p>
+ <p>
+ Own Id: OTP-15761</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Edoc 0.10</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> Print a helpful message explaining that adding
+ <c>{preprocess, true}</c> can help if reading a source
+ file fails. </p>
+ <p>
+ Own Id: OTP-15605 Aux Id: ERL-841 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Edoc 0.9.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Edoc 0.9.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Types and function specifications including the
+ <c>map()</c> type are pretty-printed correctly. </p>
+ <p>
+ Own Id: OTP-15117</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Update to use the new string api instead of the old.</p>
+ <p>
+ Own Id: OTP-15036</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Edoc 0.9.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/edoc/include/edoc_doclet.hrl b/lib/edoc/include/edoc_doclet.hrl
index 1429ee5971..a05a9cb2bc 100644
--- a/lib/edoc/include/edoc_doclet.hrl
+++ b/lib/edoc/include/edoc_doclet.hrl
@@ -43,7 +43,7 @@
%% @type no_app().
%% A value used to mark absence of an Erlang application
%% context. Use the macro `NO_APP' defined in
-%% <a href="../include/edoc_doclet.hrl">`edoc_doclet.hrl'</a>
+%% <a href="edoc_doclet.hrl">`edoc_doclet.hrl'</a>
%% to produce this value.
%% @type doclet_gen() = #doclet_gen{sources = [string()],
diff --git a/lib/edoc/src/edoc.erl b/lib/edoc/src/edoc.erl
index b641118c5d..62483602aa 100644
--- a/lib/edoc/src/edoc.erl
+++ b/lib/edoc/src/edoc.erl
@@ -578,7 +578,7 @@ read_source(Name, Opts0) ->
Opts = expand_opts(Opts0),
case read_source_1(Name, Opts) of
{ok, Forms} ->
- check_forms(Forms, Name),
+ check_forms(Forms, Name, Opts),
Forms;
{error, R} ->
edoc_report:error({"error reading file '~ts'.",
@@ -692,13 +692,19 @@ fll([T | L], LastLine, Ts) ->
fll(L, _LastLine, Ts) ->
lists:reverse(L, Ts).
-check_forms(Fs, Name) ->
+check_forms(Fs, Name, Opts) ->
Fun = fun (F) ->
case erl_syntax:type(F) of
error_marker ->
case erl_syntax:error_marker_info(F) of
{L, M, D} ->
- edoc_report:error(L, Name, {format_error, M, D});
+ edoc_report:error(L, Name, {format_error, M, D}),
+ case proplists:get_bool(preprocess, Opts) of
+ true ->
+ ok;
+ false ->
+ helpful_message(Name)
+ end;
Other ->
edoc_report:report(Name, "unknown error in "
"source code: ~w.", [Other])
@@ -710,6 +716,11 @@ check_forms(Fs, Name) ->
end,
lists:foreach(Fun, Fs).
+helpful_message(Name) ->
+ Ms = ["If the error is caused by too exotic macro",
+ "definitions or uses of macros, adding option",
+ "{preprocess, true} can help. See also edoc(3)."],
+ lists:foreach(fun(M) -> edoc_report:report(Name, M, []) end, Ms).
%% @spec get_doc(File::filename()) -> {ModuleName, edoc_module()}
%% @equiv get_doc(File, [])
@@ -723,7 +734,7 @@ get_doc(File) ->
%%
%% @type edoc_module(). The EDoc documentation data for a module,
%% expressed as an XML document in {@link //xmerl. XMerL} format. See
-%% the file <a href="../priv/edoc.dtd">`edoc.dtd'</a> for details.
+%% the file <a href="edoc.dtd">`edoc.dtd'</a> for details.
%%
%% @doc Reads a source code file and extracts EDoc documentation data.
%% Note that without an environment parameter (see {@link get_doc/3}),
diff --git a/lib/edoc/src/edoc_data.erl b/lib/edoc/src/edoc_data.erl
index 7c077d3acd..a8373d6536 100644
--- a/lib/edoc/src/edoc_data.erl
+++ b/lib/edoc/src/edoc_data.erl
@@ -345,6 +345,8 @@ deprecated(Repl, Env) ->
deprecated(Desc) ->
[{deprecated, description(Desc)}].
+-dialyzer({no_match, replacement_function/2}).
+
replacement_function(M0, {M,F,A}) when is_list(A) ->
%% refer to the largest listed arity - the most general version
replacement_function(M0, {M,F,lists:last(lists:sort(A))});
diff --git a/lib/edoc/src/edoc_doclet.erl b/lib/edoc/src/edoc_doclet.erl
index 0e084e619e..604291374a 100644
--- a/lib/edoc/src/edoc_doclet.erl
+++ b/lib/edoc/src/edoc_doclet.erl
@@ -40,7 +40,7 @@
-import(edoc_report, [report/2, warning/2]).
-%% @headerfile "edoc_doclet.hrl"
+%% @headerfile "../include/edoc_doclet.hrl"
-include("../include/edoc_doclet.hrl").
-define(EDOC_APP, edoc).
@@ -62,7 +62,7 @@
%% @spec (Command::doclet_gen() | doclet_toc(), edoc_context()) -> ok
%% @doc Main doclet entry point. See the file <a
-%% href="../include/edoc_doclet.hrl">`edoc_doclet.hrl'</a> for the data
+%% href="edoc_doclet.hrl">`edoc_doclet.hrl'</a> for the data
%% structures used for passing parameters.
%%
%% Also see {@link edoc:layout/2} for layout-related options, and
@@ -255,7 +255,7 @@ modules_frame(Dir, Ms, Title, CSS) ->
?NL,
{table, [{width, "100%"}, {border, 0},
{summary, "list of modules"}],
- lists:concat(
+ lists:append(
[[?NL,
{tr, [{td, [],
[{a, [{href, module_ref(M)},
@@ -448,7 +448,7 @@ application_frame(Dir, Apps, Title, CSS) ->
{h2, ["Applications"]},
?NL,
{table, [{width, "100%"}, {border, 0}],
- lists:concat(
+ lists:append(
[[{tr, [{td, [], [{a, [{href,app_ref(Path,App)},
{target,"_top"}],
[App]}]}]}]
diff --git a/lib/edoc/src/edoc_layout.erl b/lib/edoc/src/edoc_layout.erl
index eafab0588e..47ff7b21fc 100644
--- a/lib/edoc/src/edoc_layout.erl
+++ b/lib/edoc/src/edoc_layout.erl
@@ -608,7 +608,7 @@ etypef([Cs | L], St, O, R, Opts) ->
app_fix(L, Opts) ->
try
{"//" ++ R1,L2} = app_fix1(L, 1),
- [App, Mod] = string:tokens(R1, "/"),
+ [App, Mod] = string:lexemes(R1, "/"),
"//" ++ atom(App, Opts) ++ "/" ++ atom(Mod, Opts) ++ L2
catch _:_ -> L
end.
@@ -1120,13 +1120,13 @@ ot_integer(E) ->
{integer,0,list_to_integer(get_attrval(value, E))}.
ot_range(E) ->
- [I1, I2] = string:tokens(get_attrval(value, E), "."),
+ [I1, I2] = string:lexemes(get_attrval(value, E), "."),
{type,0,range,[{integer,0,list_to_integer(I1)},
{integer,0,list_to_integer(I2)}]}.
ot_binary(E) ->
{Base, Unit} =
- case string:tokens(get_attrval(value, E), ",:*><") of
+ case string:lexemes(get_attrval(value, E), ",:*><") of
[] ->
{0, 0};
["_",B] ->
@@ -1193,6 +1193,8 @@ ot_name(Es, T) ->
{atom,0,list_to_atom(Atom)},T]};
"tuple" when T =:= [] ->
{type,0,tuple,any};
+ "map" when T =:= [] ->
+ {type,0,map,any};
Atom ->
{type,0,list_to_atom(Atom),T}
end.
diff --git a/lib/edoc/src/edoc_specs.erl b/lib/edoc/src/edoc_specs.erl
index 4e45e42f20..7b451c43f8 100644
--- a/lib/edoc/src/edoc_specs.erl
+++ b/lib/edoc/src/edoc_specs.erl
@@ -83,7 +83,7 @@ spec(Form, Clause) ->
%% the given Erlang spec and an empty list of arguments.
dummy_spec(Form) ->
{#t_name{name = Name}, Arity, TypeSpecs} = get_spec(Form),
- As = string:join(lists:duplicate(Arity, "_X"), ","),
+ As = lists:join(",", lists:duplicate(Arity, "_X")),
S = lists:flatten(io_lib:format("~p(~s) -> true\n", [Name, As])),
#tag{name = spec, line = get_line(element(2, hd(TypeSpecs))),
origin = code, data = S}.
diff --git a/lib/edoc/vsn.mk b/lib/edoc/vsn.mk
index 2f6d469536..3510fdfccf 100644
--- a/lib/edoc/vsn.mk
+++ b/lib/edoc/vsn.mk
@@ -1 +1 @@
-EDOC_VSN = 0.9.2
+EDOC_VSN = 0.11
diff --git a/lib/eldap/README b/lib/eldap/README
index e1bde9d658..238f140e93 100644
--- a/lib/eldap/README
+++ b/lib/eldap/README
@@ -23,7 +23,7 @@ system has been configured with SSL.
In the test directory there are some hints and examples
on how to test the code and how to setup and populate
an OpenLDAP server. The 'eldap' code has been tested
-agains OpenLDAP, IPlanet and ActiveDirectory servers.
+against OpenLDAP, IPlanet and ActiveDirectory servers.
If you plan to incorporate this code into your system
I suggest that you build a server/supervisor harnesk
diff --git a/lib/eldap/doc/src/Makefile b/lib/eldap/doc/src/Makefile
index aff1da4a9a..bf1eca267a 100644
--- a/lib/eldap/doc/src/Makefile
+++ b/lib/eldap/doc/src/Makefile
@@ -89,6 +89,7 @@ debug opt valgrind:
clean clean_docs clean_tex:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(MAN6DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
diff --git a/lib/eldap/doc/src/eldap.xml b/lib/eldap/doc/src/eldap.xml
index f2c7889e58..790a2f4e26 100644
--- a/lib/eldap/doc/src/eldap.xml
+++ b/lib/eldap/doc/src/eldap.xml
@@ -28,7 +28,7 @@
<date>2000-06-20</date>
<rev>B</rev>
</header>
- <module>eldap</module>
+ <module since="OTP R15B01">eldap</module>
<modulesummary>LDAP Client</modulesummary>
<description>
<p>This module provides a client api to the Lightweight Directory Access Protocol (LDAP).
@@ -103,7 +103,7 @@
<funcs>
<func>
- <name>open([Host]) -> {ok, Handle} | {error, Reason}</name>
+ <name since="OTP R15B01">open([Host]) -> {ok, Handle} | {error, Reason}</name>
<fsummary>Open a connection to an LDAP server.</fsummary>
<type>
<v>Handle = handle()</v>
@@ -113,7 +113,7 @@
</desc>
</func>
<func>
- <name>open([Host], [Option]) -> {ok, Handle} | {error, Reason}</name>
+ <name since="OTP R15B01">open([Host], [Option]) -> {ok, Handle} | {error, Reason}</name>
<fsummary>Open a connection to an LDAP server.</fsummary>
<type>
<v>Handle = handle()</v>
@@ -129,7 +129,7 @@
</desc>
</func>
<func>
- <name>close(Handle) -> ok</name>
+ <name since="OTP R15B01">close(Handle) -> ok</name>
<fsummary>Shutdown the connection.</fsummary>
<type>
<v>Handle = handle()</v>
@@ -140,14 +140,14 @@
</desc>
</func>
<func>
- <name>start_tls(Handle, Options) -> return_value()</name>
+ <name since="OTP R16B03">start_tls(Handle, Options) -> return_value()</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) -> return_value()</name>
+ <name since="OTP R16B03">start_tls(Handle, Options, Timeout) -> return_value()</name>
<fsummary>Upgrade a connection to TLS.</fsummary>
<type>
<v>Handle = handle()</v>
@@ -176,7 +176,7 @@
</desc>
</func>
<func>
- <name>simple_bind(Handle, Dn, Password) -> return_value()</name>
+ <name since="OTP R15B01">simple_bind(Handle, Dn, Password) -> return_value()</name>
<fsummary>Authenticate the connection.</fsummary>
<type>
<v>Handle = handle()</v>
@@ -188,7 +188,7 @@
</desc>
</func>
<func>
- <name>add(Handle, Dn, [Attribute]) -> return_value()</name>
+ <name since="OTP R15B01">add(Handle, Dn, [Attribute]) -> return_value()</name>
<fsummary>Add an entry.</fsummary>
<type>
<v>Handle = handle()</v>
@@ -209,7 +209,7 @@
</desc>
</func>
<func>
- <name>delete(Handle, Dn) -> return_value()</name>
+ <name since="OTP R15B01">delete(Handle, Dn) -> return_value()</name>
<fsummary>Delete an entry.</fsummary>
<type>
<v>Dn = string()</v>
@@ -223,7 +223,7 @@
</func>
<func>
- <name>mod_add(Type, [Value]) -> modify_op()</name>
+ <name since="OTP R15B01">mod_add(Type, [Value]) -> modify_op()</name>
<fsummary>Create a modification operation.</fsummary>
<type>
<v>Type = string()</v>
@@ -232,7 +232,7 @@
<desc> <p> Create an add modification operation.</p> </desc>
</func>
<func>
- <name>mod_delete(Type, [Value]) -> modify_op()</name>
+ <name since="OTP R15B01">mod_delete(Type, [Value]) -> modify_op()</name>
<fsummary>Create a modification operation.</fsummary>
<type>
<v>Type = string()</v>
@@ -241,7 +241,7 @@
<desc> <p> Create a delete modification operation.</p> </desc>
</func>
<func>
- <name>mod_replace(Type, [Value]) -> modify_op()</name>
+ <name since="OTP R15B01">mod_replace(Type, [Value]) -> modify_op()</name>
<fsummary>Create a modification operation.</fsummary>
<type>
<v>Type = string()</v>
@@ -251,7 +251,7 @@
</func>
<func>
- <name>modify(Handle, Dn, [ModifyOp]) -> return_value()</name>
+ <name since="OTP R15B01">modify(Handle, Dn, [ModifyOp]) -> return_value()</name>
<fsummary>Modify an entry.</fsummary>
<type>
<v>Dn = string()</v>
@@ -267,7 +267,7 @@
</desc>
</func>
<func>
- <name>modify_password(Handle, Dn, NewPasswd) -> return_value() | {ok, GenPasswd}</name>
+ <name since="OTP 18.0">modify_password(Handle, Dn, NewPasswd) -> return_value() | {ok, GenPasswd}</name>
<fsummary>Modify the password of a user.</fsummary>
<type>
<v>Dn = string()</v>
@@ -278,7 +278,7 @@
</desc>
</func>
<func>
- <name>modify_password(Handle, Dn, NewPasswd, OldPasswd) -> return_value() | {ok, GenPasswd}</name>
+ <name since="OTP 18.0">modify_password(Handle, Dn, NewPasswd, OldPasswd) -> return_value() | {ok, GenPasswd}</name>
<fsummary>Modify the password of a user.</fsummary>
<type>
<v>Dn = string()</v>
@@ -307,7 +307,7 @@
</desc>
</func>
<func>
- <name>modify_dn(Handle, Dn, NewRDN, DeleteOldRDN, NewSupDN) -> return_value()</name>
+ <name since="OTP R15B01">modify_dn(Handle, Dn, NewRDN, DeleteOldRDN, NewSupDN) -> return_value()</name>
<fsummary>Modify the DN of an entry.</fsummary>
<type>
<v>Dn = string()</v>
@@ -327,7 +327,7 @@
</desc>
</func>
<func>
- <name>search(Handle, SearchOptions) -> {ok, #eldap_search_result{}} | {ok, {referral,referrals()}} | {error, Reason}</name>
+ <name since="OTP R15B01">search(Handle, SearchOptions) -> {ok, #eldap_search_result{}} | {ok, {referral,referrals()}} | {error, Reason}</name>
<fsummary>Search the Directory</fsummary>
<type>
<v>SearchOptions = #eldap_search{} | [SearchOption]</v>
@@ -354,44 +354,44 @@
</func>
<func>
- <name>baseObject() -> scope()</name>
+ <name since="OTP R15B01">baseObject() -> scope()</name>
<fsummary>Create search scope.</fsummary>
<desc> <p> Search baseobject only.</p> </desc>
</func>
<func>
- <name>singleLevel() -> scope()</name>
+ <name since="OTP R15B01">singleLevel() -> scope()</name>
<fsummary>Create search scope.</fsummary>
<desc> <p> Search the specified level only, i.e. do not recurse.</p> </desc>
</func>
<func>
- <name>wholeSubtree() -> scope()</name>
+ <name since="OTP R15B01">wholeSubtree() -> scope()</name>
<fsummary>Create search scope.</fsummary>
<desc> <p> Search the entire subtree.</p> </desc>
</func>
<func>
- <name>neverDerefAliases() -> dereference()</name>
+ <name since="OTP R15B01">neverDerefAliases() -> dereference()</name>
<fsummary>Create search option.</fsummary>
<desc> <p>Never derefrence aliases, treat aliases as entries.</p> </desc>
</func>
<func>
- <name>derefAlways() -> dereference()</name>
+ <name since="OTP R15B01">derefAlways() -> dereference()</name>
<fsummary>Create search option.</fsummary>
<desc> <p>Always derefrence aliases.</p> </desc>
</func>
<func>
- <name>derefInSearching() -> dereference()</name>
+ <name since="OTP R15B01">derefInSearching() -> dereference()</name>
<fsummary>Create search option.</fsummary>
<desc> <p>Derefrence aliases only when searching.</p> </desc>
</func>
<func>
- <name>derefFindingBaseObj() -> dereference()</name>
+ <name since="OTP R15B01">derefFindingBaseObj() -> dereference()</name>
<fsummary>Create search option.</fsummary>
<desc> <p>Derefrence aliases only in finding the base.</p> </desc>
</func>
<func>
- <name>present(Type) -> filter()</name>
+ <name since="OTP R15B01">present(Type) -> filter()</name>
<fsummary>Create search filter option.</fsummary>
<type>
<v>Type = string()</v>
@@ -399,7 +399,7 @@
<desc> <p>Create a filter which filters on attribute type presence.</p> </desc>
</func>
<func>
- <name>substrings(Type, [SubString]) -> filter()</name>
+ <name since="OTP R15B01">substrings(Type, [SubString]) -> filter()</name>
<fsummary>Create search filter option.</fsummary>
<type>
<v>Type = string()</v>
@@ -409,7 +409,7 @@
<desc> <p>Create a filter which filters on substrings.</p> </desc>
</func>
<func>
- <name>equalityMatch(Type, Value) -> filter()</name>
+ <name since="OTP R15B01">equalityMatch(Type, Value) -> filter()</name>
<fsummary>Create search filter option.</fsummary>
<type>
<v>Type = string()</v>
@@ -418,7 +418,7 @@
<desc> <p>Create a equality filter.</p> </desc>
</func>
<func>
- <name>greaterOrEqual(Type, Value) -> filter()</name>
+ <name since="OTP R15B01">greaterOrEqual(Type, Value) -> filter()</name>
<fsummary>Create search filter option.</fsummary>
<type>
<v>Type = string()</v>
@@ -427,7 +427,7 @@
<desc> <p>Create a greater or equal filter.</p> </desc>
</func>
<func>
- <name>lessOrEqual(Type, Value) -> filter()</name>
+ <name since="OTP R15B01">lessOrEqual(Type, Value) -> filter()</name>
<fsummary>Create search filter option.</fsummary>
<type>
<v>Type = string()</v>
@@ -436,7 +436,7 @@
<desc> <p>Create a less or equal filter.</p> </desc>
</func>
<func>
- <name>approxMatch(Type, Value) -> filter()</name>
+ <name since="OTP R15B01">approxMatch(Type, Value) -> filter()</name>
<fsummary>Create search filter option.</fsummary>
<type>
<v>Type = string()</v>
@@ -445,7 +445,7 @@
<desc> <p>Create a approximation match filter.</p> </desc>
</func>
<func>
- <name>extensibleMatch(MatchValue, OptionalAttrs) -> filter()</name>
+ <name since="OTP 17.4">extensibleMatch(MatchValue, OptionalAttrs) -> filter()</name>
<fsummary>Create search filter option.</fsummary>
<type>
<v>MatchValue = string()</v>
@@ -459,7 +459,7 @@
<p>creates a filter which performs a <c>caseExactMatch</c> on the attribute <c>sn</c> and matches with the value <c>"Bar"</c>. The default value of <c>dnAttributes</c> is <c>false</c>.</p> </desc>
</func>
<func>
- <name>'and'([Filter]) -> filter()</name>
+ <name since="OTP R15B01">'and'([Filter]) -> filter()</name>
<fsummary>Create search filter option.</fsummary>
<type>
<v>Filter = filter()</v>
@@ -467,7 +467,7 @@
<desc> <p>Creates a filter where all <c>Filter</c> must be true.</p> </desc>
</func>
<func>
- <name>'or'([Filter]) -> filter()</name>
+ <name since="OTP R15B01">'or'([Filter]) -> filter()</name>
<fsummary>Create search filter option.</fsummary>
<type>
<v>Filter = filter()</v>
@@ -475,7 +475,7 @@
<desc> <p>Create a filter where at least one of the <c>Filter</c> must be true.</p> </desc>
</func>
<func>
- <name>'not'(Filter) -> filter()</name>
+ <name since="OTP R15B01">'not'(Filter) -> filter()</name>
<fsummary>Create search filter option.</fsummary>
<type>
<v>Filter = filter()</v>
diff --git a/lib/eldap/doc/src/notes.xml b/lib/eldap/doc/src/notes.xml
index 8b066671ee..946db5b93d 100644
--- a/lib/eldap/doc/src/notes.xml
+++ b/lib/eldap/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2012</year><year>2016</year>
+ <year>2012</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,6 +31,104 @@
</header>
<p>This document describes the changes made to the Eldap application.</p>
+<section><title>Eldap 1.2.8</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix dialyzer warnings in eldap when not matching the
+ return value of ssl:close/1.</p>
+ <p>
+ Own Id: OTP-15775</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Eldap 1.2.7</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Back port of bug fix ERL-893 from OTP-22 and document
+ enhancements that will solve dialyzer warnings for users
+ of the ssl application.</p>
+ <p>
+ This change also affects public_key, eldap (and inet
+ doc).</p>
+ <p>
+ Own Id: OTP-15785 Aux Id: ERL-929, ERL-893, PR-2215 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Eldap 1.2.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A race condition at close could cause the eldap client to
+ exit with a badarg message as cause.</p>
+ <p>
+ Own Id: OTP-15342 Aux Id: ERIERL-242 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Eldap 1.2.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Eldap 1.2.4</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Update to use the new string api instead of the old.</p>
+ <p>
+ Own Id: OTP-15036</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Eldap 1.2.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A race condition at close could cause the eldap client to
+ exit with a badarg message as cause.</p>
+ <p>
+ Own Id: OTP-15342 Aux Id: ERIERL-242 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Eldap 1.2.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -46,6 +144,22 @@
</section>
+<section><title>Eldap 1.2.2.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A race condition at close could cause the eldap client to
+ exit with a badarg message as cause.</p>
+ <p>
+ Own Id: OTP-15342 Aux Id: ERIERL-242 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Eldap 1.2.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -322,4 +436,3 @@
<p>New application. </p>
</section>
</chapter>
-
diff --git a/lib/eldap/src/eldap.erl b/lib/eldap/src/eldap.erl
index 625309271b..9b7e254dfe 100644
--- a/lib/eldap/src/eldap.erl
+++ b/lib/eldap/src/eldap.erl
@@ -957,11 +957,20 @@ do_modify_dn_0(Data, Entry, NewRDN, DelOldRDN, NewSup, Controls) ->
do_unbind(Data) ->
Req = "",
log2(Data, "unbind request = ~p (has no reply)~n", [Req]),
- send_request(Data#eldap.fd, Data, Data#eldap.id, {unbindRequest, Req}),
- case Data#eldap.using_tls of
- true -> ssl:close(Data#eldap.fd);
- false -> gen_tcp:close(Data#eldap.fd)
- end,
+ _ = case Data#eldap.using_tls of
+ true ->
+ send_request(Data#eldap.fd, Data, Data#eldap.id, {unbindRequest, Req}),
+ ssl:close(Data#eldap.fd);
+ false ->
+ OldTrapExit = process_flag(trap_exit, true),
+ catch send_request(Data#eldap.fd, Data, Data#eldap.id, {unbindRequest, Req}),
+ catch gen_tcp:close(Data#eldap.fd),
+ receive
+ {'EXIT', _From, _Reason} -> ok
+ after 0 -> ok
+ end,
+ process_flag(trap_exit, OldTrapExit)
+ end,
{no_reply, Data#eldap{binddn = (#eldap{})#eldap.binddn,
passwd = (#eldap{})#eldap.passwd,
fd = (#eldap{})#eldap.fd,
@@ -1121,7 +1130,7 @@ 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, _} ->
- ssl:close(Data#eldap.fd),
+ _ = ssl:close(Data#eldap.fd),
{error, ldap_closed};
{ok, _} ->
{error, Emsg};
@@ -1368,9 +1377,9 @@ rm_leading_slash(Tail) -> Tail.
parse_attributes([$?|Tail]) ->
case split_string(Tail,$?) of
{[],Attributes} ->
- {[],{attributes,string:tokens(Attributes,",")}};
+ {[],{attributes,string:lexemes(Attributes,",")}};
{Attributes,Rest} ->
- {Rest,{attributes,string:tokens(Attributes,",")}}
+ {Rest,{attributes,string:lexemes(Attributes,",")}}
end.
parse_hostport(Str) ->
diff --git a/lib/eldap/test/eldap_basic_SUITE.erl b/lib/eldap/test/eldap_basic_SUITE.erl
index 4bfb0dd291..b871eda19c 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-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/eldap/test/make_certs.erl b/lib/eldap/test/make_certs.erl
index cfa43289e1..e8a13ae113 100644
--- a/lib/eldap/test/make_certs.erl
+++ b/lib/eldap/test/make_certs.erl
@@ -348,7 +348,7 @@ req_cnf(C) ->
"default_bits = ", integer_to_list(C#config.default_bits), "\n"
"RANDFILE = $ROOTDIR/RAND\n"
"encrypt_key = no\n"
- "default_md = md5\n"
+ "default_md = sha1\n"
"#string_mask = pkix\n"
"x509_extensions = ca_ext\n"
"prompt = no\n"
@@ -394,7 +394,7 @@ ca_cnf(C) ->
["crl_extensions = crl_ext\n" || C#config.v2_crls],
"unique_subject = no\n"
"default_days = 3600\n"
- "default_md = md5\n"
+ "default_md = sha1\n"
"preserve = no\n"
"policy = policy_match\n"
"\n"
diff --git a/lib/eldap/vsn.mk b/lib/eldap/vsn.mk
index 1636b6bb6d..8f969e6945 100644
--- a/lib/eldap/vsn.mk
+++ b/lib/eldap/vsn.mk
@@ -1 +1 @@
-ELDAP_VSN = 1.2.3
+ELDAP_VSN = 1.2.8
diff --git a/lib/erl_docgen/doc/src/Makefile b/lib/erl_docgen/doc/src/Makefile
index a9110e4635..d6d2550425 100644
--- a/lib/erl_docgen/doc/src/Makefile
+++ b/lib/erl_docgen/doc/src/Makefile
@@ -106,6 +106,7 @@ html: gifs examples $(HTML_REF_MAN_FILE)
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN6DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/lib/erl_docgen/doc/src/doc-build.xml b/lib/erl_docgen/doc/src/doc-build.xml
index 3ea8798639..17e13bff81 100644
--- a/lib/erl_docgen/doc/src/doc-build.xml
+++ b/lib/erl_docgen/doc/src/doc-build.xml
@@ -178,7 +178,7 @@
</section>
<section>
- <title>Upcomming changes</title>
+ <title>Upcoming changes</title>
<p>
The output from the <c>erl_docgen</c> documentation build process is now just the OTP style.
But in a near future we will for example add the possibility to change logo, color in the PDF and
diff --git a/lib/erl_docgen/doc/src/docgen_xml_check.xml b/lib/erl_docgen/doc/src/docgen_xml_check.xml
index 68253edef7..8d6dceef43 100644
--- a/lib/erl_docgen/doc/src/docgen_xml_check.xml
+++ b/lib/erl_docgen/doc/src/docgen_xml_check.xml
@@ -30,7 +30,7 @@
<date></date>
<rev></rev>
</header>
- <module>docgen_xml_check</module>
+ <module since="OTP R15B">docgen_xml_check</module>
<modulesummary>Validate XML documentation source code</modulesummary>
<description>
<p><c>docgen_xml_check</c> contains functions for validating XML
@@ -39,7 +39,7 @@
<funcs>
<func>
- <name>validate(File) -> ok | error | {error, badfile}</name>
+ <name since="OTP R15B">validate(File) -> ok | error | {error, badfile}</name>
<fsummary>Validate XML source code.</fsummary>
<type>
<v>File = string()</v>
diff --git a/lib/erl_docgen/doc/src/notes.xml b/lib/erl_docgen/doc/src/notes.xml
index 2652b4b0c8..f25361a202 100644
--- a/lib/erl_docgen/doc/src/notes.xml
+++ b/lib/erl_docgen/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,7 +31,100 @@
</header>
<p>This document describes the changes made to the <em>erl_docgen</em> application.</p>
- <section><title>Erl_Docgen 0.7.2</title>
+ <section><title>Erl_Docgen 0.9.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ All incorrect (that is, all) uses of "can not" has been
+ corrected to "cannot" in source code comments,
+ documentation, examples, and so on.</p>
+ <p>
+ Own Id: OTP-14282 Aux Id: PR-1891 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Docgen 0.9</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The HTML reference documentation shows the OTP version
+ where modules and functions were first introduced.
+ Versions older than R13B04 are not shown.</p>
+ <p>
+ Own Id: OTP-15460</p>
+ </item>
+ <item>
+ <p>
+ Make html documentation of C functions with many
+ arguments more readable.</p>
+ <p>
+ Own Id: OTP-15637 Aux Id: PR-2160 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Docgen 0.8.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Indexing for the online search function has been
+ corrected for CREF documents.</p>
+ <p>
+ Own Id: OTP-14406</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Docgen 0.8</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Add a hoverable element to the titles in the html
+ documentation with a link to github where the
+ documentation can be edited.</p>
+ <p>
+ Make the anchors in the html User's Guide and system
+ documentation use the title of the sections instead of a
+ generated id.</p>
+ <p>
+ Own Id: OTP-14979</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Docgen 0.7.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Update makefile so db_funcs.xsl is a part of the
+ installed application. </p>
+ <p>
+ Own Id: OTP-15091</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Docgen 0.7.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/erl_docgen/priv/bin/codeline_preprocessing.escript b/lib/erl_docgen/priv/bin/codeline_preprocessing.escript
index 8e1e35bcdd..ce9303f86e 100755
--- a/lib/erl_docgen/priv/bin/codeline_preprocessing.escript
+++ b/lib/erl_docgen/priv/bin/codeline_preprocessing.escript
@@ -2,7 +2,7 @@
%% -*- erlang -*-
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -30,7 +30,7 @@
%% Function: main/1
%% Description:
%%----------------------------------------------------------------------
-main([InFile, OutFile]) ->
+main([CPath, InFile, OutFile]) ->
InDev =
case file:open(InFile, [read]) of
{ok,ID} ->
@@ -38,7 +38,6 @@ main([InFile, OutFile]) ->
_ ->
halt(5)
end,
- CPath=filename:dirname(InFile),
OutDev =
case file:open(OutFile, [write]) of
{ok,OD} ->
diff --git a/lib/erl_docgen/priv/bin/github_link.escript b/lib/erl_docgen/priv/bin/github_link.escript
new file mode 100755
index 0000000000..e0f5a2f471
--- /dev/null
+++ b/lib/erl_docgen/priv/bin/github_link.escript
@@ -0,0 +1,51 @@
+#!/usr/bin/env escript
+%% -*- erlang -*-
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%----------------------------------------------------------------------
+%% File : github_link.escript
+%%
+%% Created : 12 Dec 2017 by Lukas Larsson
+%%----------------------------------------------------------------------
+
+main([In, Filename, Sha, Out]) ->
+ {ok, Bin} = file:read_file(In),
+
+ TagsToAnnotate = ["description", "func", "datatype", "section"],
+
+ Subs = subs(TagsToAnnotate, Filename, Sha, re:split(Bin,[$\n])),
+
+ file:write_file(Out, Subs).
+
+subs([], _, _, Bin) ->
+ lists:join("\n", Bin);
+subs([Pat|Pats], Fn, Sha, Bin) ->
+ subs(Pats, Fn, Sha, sub(Bin, Pat, Fn, Sha)).
+
+sub(Bin, Pat, Fn, Sha) ->
+ sub(Bin, Pat, Fn, Sha, 1).
+sub([], _Pat, _Fn, _Sha, _Cnt) ->
+ [];
+sub([H|T], Pat, Fn, Sha, Cnt) ->
+ %% We use the maint branch here, it is not as exact as the tag,
+ %% but it is the best we can do as github does not allow doing
+ %% pullrequests on anything but branches.
+ [re:replace(H,["<",Pat,">"],
+ ["<",Pat," ghlink=\"maint/",Fn,"#L",
+ integer_to_list(Cnt),"\">"],[{return,list}]) |
+ sub(T, Pat, Fn, Sha, Cnt+1)].
diff --git a/lib/erl_docgen/priv/bin/xml_from_edoc.escript b/lib/erl_docgen/priv/bin/xml_from_edoc.escript
index b930ae3818..38e4f2d923 100755
--- a/lib/erl_docgen/priv/bin/xml_from_edoc.escript
+++ b/lib/erl_docgen/priv/bin/xml_from_edoc.escript
@@ -2,7 +2,7 @@
%% -*- erlang -*-
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -28,6 +28,7 @@
%% Records
%%======================================================================
-record(args, {suffix=".xml",
+ dir=".",
layout=docgen_edoc_xml_cb,
def=[],
includes=[],
@@ -85,7 +86,7 @@ module(File, Args) ->
{app_default, "OTPROOT"},
{file_suffix, Args#args.suffix},
- {dir, "."},
+ {dir, Args#args.dir},
{layout, Args#args.layout}],
edoc:file(File, Opts);
false ->
@@ -118,7 +119,7 @@ users_guide(File, Args) ->
Text = edoc_lib:run_layout(F, Opts),
OutFile = "chapter" ++ Args#args.suffix,
- edoc_lib:write_file(Text, ".", OutFile, Encoding);
+ edoc_lib:write_file(Text, Args#args.dir, OutFile, Encoding);
false ->
io:format("~s: not a regular file\n", [File]),
usage()
@@ -139,6 +140,8 @@ parse(["-def", Key, Val |RawOpts], Type, Args) ->
parse(["-i", Dir |RawOpts], Type, Args) ->
Args2 = Args#args{includes=Args#args.includes++[Dir]},
parse(RawOpts, Type, Args2);
+parse(["-dir", Dir |RawOpts], Type, Args) ->
+ parse(RawOpts, Type, Args#args{dir=Dir});
parse(["-preprocess", Bool |RawOpts], Type, Args) when Bool == "true";
Bool == "false" ->
parse(RawOpts, Type, Args#args{preprocess=list_to_atom(Bool)});
diff --git a/lib/erl_docgen/priv/css/otp_doc.css b/lib/erl_docgen/priv/css/otp_doc.css
index 844aad2945..17d9f8dd56 100644
--- a/lib/erl_docgen/priv/css/otp_doc.css
+++ b/lib/erl_docgen/priv/css/otp_doc.css
@@ -71,6 +71,39 @@ a:visited { color: #1b6ec2; text-decoration: none }
}
.bold_code { font-family: mono, Courier, monospace; font-weight: bold }
+
+/* Invisible table for function specs,
+ * just to get since-version out in right margin */
+.func-table, .func-tr, .func-td, .cfunc-td, .func-since-td {
+ width: 200%;
+ border: 0;
+ padding: 0;
+ margin: 0;
+}
+
+.func-tr:nth-child(n) {
+ background: inherit /* turn off zebra striped rows */
+}
+
+.func-td {
+ width: 50%;
+}
+
+.cfunc-td {
+ width: 50%;
+ padding-left: 100px;
+ text-indent: -100px;
+}
+
+.func-since-td {
+ width: 50%;
+ padding-left: 1em
+}
+
+.func-td:hover {
+ background-color: #f5f5f5;
+}
+
.code {
font-family: mono, Courier, monospace;
font-weight: normal;
@@ -242,8 +275,25 @@ th {
font-size: small;
}
-h3>a{
- color: #1a1a1a !important;
+.title_link {
+ color: #1a1a1a !important;
+ outline: none;
+}
+
+.ghlink {
+ margin-left: -2.7em; /* .pencil.font-size + .pencil.padding.left + .pencil.padding.right = 2.7 */
+ visibility: hidden;
+}
+
+.pencil:before {
+ transform: rotateZ(90deg);
+ content: "\270E";
+ color: #1a1a1a !important;
+ font-weight: bold;
+ font-size: 1.5em;
+ padding: .3em .6em .6em;
+ line-height: 1em;
+ font-family: mono;
}
hr{
@@ -266,3 +316,9 @@ a > .code {
.func-types-title{
font-size: 1em;
}
+
+.since{
+ color: gray;
+ font-weight: normal;
+ font-size: small;
+} \ No newline at end of file
diff --git a/lib/erl_docgen/priv/dtd/book.dtd b/lib/erl_docgen/priv/dtd/book.dtd
index aa07d38658..326bf3369a 100644
--- a/lib/erl_docgen/priv/dtd/book.dtd
+++ b/lib/erl_docgen/priv/dtd/book.dtd
@@ -30,7 +30,7 @@
insidecover?,
pagetext,
preamble,
- (applications|parts|headline|pagetext)+,
+ (applications|parts|internals|headline|pagetext)+,
(listoffigures?,
listoftables?,
listofterms?,
@@ -56,6 +56,7 @@
<!ELEMENT applications (include)* >
<!ELEMENT parts (title?,description?,(include|onepart)*) >
<!ATTLIST parts lift (yes|no) "no" >
+<!ELEMENT internals (include)* >
<!ELEMENT headline (#PCDATA) >
<!ELEMENT index EMPTY >
<!ELEMENT listoffigures EMPTY >
diff --git a/lib/erl_docgen/priv/dtd/chapter.dtd b/lib/erl_docgen/priv/dtd/chapter.dtd
index 8d940b90f7..3e9113d798 100644
--- a/lib/erl_docgen/priv/dtd/chapter.dtd
+++ b/lib/erl_docgen/priv/dtd/chapter.dtd
@@ -35,3 +35,4 @@
<!ELEMENT section (marker*,title,
(%block;|quote|warning|note|dont|do|br|image|marker|
table|section)*) >
+<!ATTLIST section ghlink CDATA #IMPLIED>
diff --git a/lib/erl_docgen/priv/dtd/common.dtd b/lib/erl_docgen/priv/dtd/common.dtd
index b1578ad9d4..0ccd52068b 100644
--- a/lib/erl_docgen/priv/dtd/common.dtd
+++ b/lib/erl_docgen/priv/dtd/common.dtd
@@ -25,7 +25,7 @@
<!ENTITY % block "p|pre|code|list|taglist|codeinclude|
erleval" >
<!ENTITY % inline "#PCDATA|c|i|em|strong|term|cite|br|path|seealso|
- url|marker|anno" >
+ url|marker|anno|image" >
<!-- XXX -->
<!ELEMENT p (%inline;)* >
<!ELEMENT pre (#PCDATA|seealso|url|input|anno)* >
diff --git a/lib/erl_docgen/priv/dtd/common.image.dtd b/lib/erl_docgen/priv/dtd/common.image.dtd
index d97057590e..138da3609b 100644
--- a/lib/erl_docgen/priv/dtd/common.image.dtd
+++ b/lib/erl_docgen/priv/dtd/common.image.dtd
@@ -18,5 +18,7 @@
$Id$
-->
<!ELEMENT image (icaption) >
-<!ATTLIST image file CDATA #REQUIRED >
+<!ATTLIST image
+ file CDATA #REQUIRED
+ width CDATA #IMPLIED >
<!ELEMENT icaption (#PCDATA) >
diff --git a/lib/erl_docgen/priv/dtd/common.refs.dtd b/lib/erl_docgen/priv/dtd/common.refs.dtd
index 4f87007a09..07c876a17f 100644
--- a/lib/erl_docgen/priv/dtd/common.refs.dtd
+++ b/lib/erl_docgen/priv/dtd/common.refs.dtd
@@ -26,8 +26,10 @@
%common.header;
<!ELEMENT description (%block;|quote|br|marker|warning|note|dont|do)* >
+<!ATTLIST description ghlink CDATA #IMPLIED>
<!ELEMENT funcs (func)+ >
<!ELEMENT func (name+,fsummary,(type|type_desc)*,desc?) >
+<!ATTLIST func ghlink CDATA #IMPLIED>
<!-- ELEMENT name is defined in each ref dtd -->
<!ELEMENT fsummary (#PCDATA|c|i|em|anno)* >
<!ELEMENT type (v,d?)* >
@@ -42,8 +44,11 @@
<!ELEMENT email (#PCDATA) >
<!ELEMENT section (marker*,title,(%block;|quote|br|marker|
warning|note|dont|do|section)*) >
-<!ELEMENT datatypes (datatype)+ >
+<!ATTLIST section ghlink CDATA #IMPLIED>
+<!ELEMENT datatypes (datatype_title?,datatype)+ >
+<!ELEMENT datatype_title (#PCDATA) >
<!ELEMENT datatype (name+,desc?) >
+<!ATTLIST datatype ghlink CDATA #IMPLIED>
<!ELEMENT type_desc (#PCDATA|anno|c|seealso)* >
<!ATTLIST type_desc variable CDATA #IMPLIED
name CDATA #IMPLIED>
diff --git a/lib/erl_docgen/priv/dtd/cref.dtd b/lib/erl_docgen/priv/dtd/cref.dtd
index 5ccd98ed89..d392081807 100644
--- a/lib/erl_docgen/priv/dtd/cref.dtd
+++ b/lib/erl_docgen/priv/dtd/cref.dtd
@@ -30,6 +30,8 @@
<!-- `name' is used in common.refs.dtd and must therefore
be defined in each *ref. dtd -->
<!ELEMENT name (ret,nametext) >
+<!ATTLIST name since CDATA #IMPLIED>
+
<!ELEMENT ret (#PCDATA) >
<!ELEMENT nametext (#PCDATA) >
diff --git a/lib/erl_docgen/priv/dtd/erlref.dtd b/lib/erl_docgen/priv/dtd/erlref.dtd
index 615b88b61a..8202ea5a4d 100644
--- a/lib/erl_docgen/priv/dtd/erlref.dtd
+++ b/lib/erl_docgen/priv/dtd/erlref.dtd
@@ -25,6 +25,7 @@
<!ELEMENT erlref (header,module,modulesummary,description,
(section|funcs|datatypes)*,authors?) >
<!ELEMENT module (#PCDATA) >
+<!ATTLIST module since CDATA #IMPLIED>
<!ELEMENT modulesummary (#PCDATA) >
<!-- `name' is used in common.refs.dtd and must therefore
@@ -33,4 +34,6 @@
<!ATTLIST name name CDATA #IMPLIED
arity CDATA #IMPLIED
clause_i CDATA #IMPLIED
+ anchor CDATA #IMPLIED
+ since CDATA #IMPLIED
n_vars CDATA #IMPLIED>
diff --git a/lib/erl_docgen/priv/xsl/Makefile b/lib/erl_docgen/priv/xsl/Makefile
index d0dd227169..d381bd4cf7 100644
--- a/lib/erl_docgen/priv/xsl/Makefile
+++ b/lib/erl_docgen/priv/xsl/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2009-2016. All Rights Reserved.
+# Copyright Ericsson AB 2009-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -44,7 +44,8 @@ XSL_FILES = \
db_html.xsl \
db_html_params.xsl \
db_man.xsl \
- db_eix.xsl
+ db_eix.xsl \
+ db_funcs.xsl
# ----------------------------------------------------
diff --git a/lib/erl_docgen/priv/xsl/db_eix.xsl b/lib/erl_docgen/priv/xsl/db_eix.xsl
index b496614854..6bce577f08 100644
--- a/lib/erl_docgen/priv/xsl/db_eix.xsl
+++ b/lib/erl_docgen/priv/xsl/db_eix.xsl
@@ -3,7 +3,7 @@
#
# %CopyrightBegin%
#
- # Copyright Ericsson AB 2009-2016. All Rights Reserved.
+ # Copyright Ericsson AB 2009-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -199,11 +199,34 @@
<xsl:template name="name">
<xsl:param name="lastfuncsblock"/>
+ <xsl:variable name="signature">
+ <xsl:variable name="signature1">
+ <xsl:choose>
+ <xsl:when test="ancestor::cref">
+ <xsl:value-of
+ select="normalize-space(nametext)"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of
+ select="normalize-space(substring-before(., '->'))"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test="string-length($signature1) > 0">
+ <xsl:value-of select="$signature1"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="normalize-space(.)"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
<xsl:variable name="tmpstring">
- <xsl:value-of select="substring-before(substring-after(., '('), '->')"/>
+ <xsl:value-of select="substring-after($signature, '(')"/>
</xsl:variable>
- <xsl:variable name="ustring">
+ <xsl:variable name="argstring">
<xsl:choose>
<xsl:when test="string-length($tmpstring) > 0">
<xsl:call-template name="remove-paren">
@@ -219,10 +242,19 @@
</xsl:variable>
<xsl:variable name="arity">
- <xsl:call-template name="calc-arity">
- <xsl:with-param name="string" select="substring-before($ustring, ')')"/>
- <xsl:with-param name="no-of-pars" select="0"/>
- </xsl:call-template>
+ <xsl:choose>
+ <xsl:when
+ test="string-length(substring-before(., '->')) > 0">
+ <xsl:call-template name="calc-arity">
+ <xsl:with-param
+ name="string"
+ select="substring-before($argstring, ')')"/>
+ <xsl:with-param name="no-of-pars" select="0"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise/>
+ </xsl:choose>
+
</xsl:variable>
<xsl:variable name="fname">
@@ -250,10 +282,18 @@
</xsl:variable>
<xsl:text> {"</xsl:text><xsl:value-of select="$fname"/>
+ <xsl:text>", "</xsl:text>
+ <xsl:call-template name="escape-doublequotes">
+ <xsl:with-param name="string" select="$signature"/>
+ </xsl:call-template>
<xsl:text>", "</xsl:text><xsl:value-of select="$fname"/>
- <xsl:text>(</xsl:text><xsl:value-of select="normalize-space($tmpstring)"/>
- <xsl:text>", "</xsl:text><xsl:value-of select="$fname"/>
- <xsl:text>-</xsl:text><xsl:value-of select="$arity"/><xsl:text>"}</xsl:text>
+ <xsl:choose>
+ <xsl:when test="string-length($arity) > 0">
+ <xsl:text>-</xsl:text><xsl:value-of select="$arity"/>
+ </xsl:when>
+ <xsl:otherwise/>
+ </xsl:choose>
+ <xsl:text>"}</xsl:text>
<xsl:choose>
<xsl:when test="($lastfuncsblock = 'true') and (position() = last())">
@@ -345,6 +385,27 @@
</xsl:template>
+ <xsl:template name="escape-doublequotes">
+ <xsl:param name="string"/>
+ <xsl:param name="pPat">"</xsl:param>
+ <xsl:param name="pRep">\"</xsl:param>
+
+ <xsl:choose>
+ <xsl:when test="not(contains($string, $pPat))">
+ <xsl:copy-of select="$string"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:copy-of select="substring-before($string, $pPat)"/>
+ <xsl:copy-of select="$pRep"/>
+ <xsl:call-template name="escape-doublequotes">
+ <xsl:with-param
+ name="string"
+ select="substring-after($string, $pPat)"/>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
<!-- default content handling -->
<xsl:template match="text()"/>
diff --git a/lib/erl_docgen/priv/xsl/db_html.xsl b/lib/erl_docgen/priv/xsl/db_html.xsl
index 75614392fb..18bc8cd1cf 100644
--- a/lib/erl_docgen/priv/xsl/db_html.xsl
+++ b/lib/erl_docgen/priv/xsl/db_html.xsl
@@ -3,7 +3,7 @@
#
# %CopyrightBegin%
#
- # Copyright Ericsson AB 2009-2017. All Rights Reserved.
+ # Copyright Ericsson AB 2009-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -54,6 +54,24 @@
<func:result select="$result"/>
</func:function>
+ <func:function name="erl:lower-case">
+ <xsl:param name="str"/>
+
+ <xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
+ <xsl:variable name="lowercase" select="'abcdefghijklmnopqrstuvwxyz'"/>
+
+ <xsl:variable name="result">
+ <xsl:value-of select="translate($str, $uppercase, $lowercase)"/>
+ </xsl:variable>
+
+ <func:result select="$result"/>
+ </func:function>
+
+ <func:function name="erl:to-link">
+ <xsl:param name="text"/>
+ <func:result select="translate(erl:lower-case($text),'?: /()&quot;&#10;','--------')"/>
+ </func:function>
+
<!-- Used from template menu.funcs to sort a module's functions for the lefthand index list,
from the module's .xml file. Returns a value on which to sort the entity in question
(a <name> element).
@@ -172,6 +190,8 @@
<xsl:template name="spec_name">
<xsl:variable name="name" select="@name"/>
<xsl:variable name="arity" select="@arity"/>
+ <xsl:variable name="anchor" select="@anchor"/>
+ <xsl:variable name="since" select="@since"/>
<xsl:variable name="spec0">
<xsl:call-template name="find_spec"/>
</xsl:variable>
@@ -198,26 +218,54 @@
</xsl:otherwise>
</xsl:choose>
+ <!-- Insert an anchor for "anchor" attribute -->
+ <xsl:if test="string-length($anchor) > 0">
+ <a name="{$anchor}"></a>
+ </xsl:if>
+
<xsl:variable name="global_types" select="ancestor::erlref/datatypes"/>
<xsl:variable name="local_types"
select="../type[string-length(@name) > 0]"/>
- <xsl:apply-templates select="$spec/contract/clause/head">
+ <xsl:apply-templates select="$spec/contract/clause/head">
+ <xsl:with-param name="ghlink" select="ancestor-or-self::*[@ghlink]/@ghlink"/>
<xsl:with-param name="local_types" select="$local_types"/>
<xsl:with-param name="global_types" select="$global_types"/>
- </xsl:apply-templates>
+ <xsl:with-param name="since" select="$since"/>
+ </xsl:apply-templates>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="head">
+ <xsl:param name="ghlink"/>
<xsl:param name="local_types"/>
<xsl:param name="global_types"/>
- <div class="bold_code func-head">
- <xsl:apply-templates mode="local_type">
- <xsl:with-param name="local_types" select="$local_types"/>
- <xsl:with-param name="global_types" select="$global_types"/>
- </xsl:apply-templates>
- </div>
+ <xsl:param name="since"/>
+ <xsl:variable name="id" select="concat(concat(concat(concat(../../../name,'-'),../../../arity),'-'),generate-id(.))"/>
+ <table class="func-table">
+ <tr class="func-tr">
+ <td class="func-td">
+ <div class="bold_code func-head"
+ onMouseOver="document.getElementById('ghlink-{$id}').style.visibility = 'visible';"
+ onMouseOut="document.getElementById('ghlink-{$id}').style.visibility = 'hidden';">
+ <xsl:call-template name="ghlink">
+ <xsl:with-param name="ghlink" select="$ghlink"/>
+ <xsl:with-param name="id" select="$id"/>
+ </xsl:call-template>
+ <xsl:apply-templates mode="local_type">
+ <xsl:with-param name="local_types" select="$local_types"/>
+ <xsl:with-param name="global_types" select="$global_types"/>
+ </xsl:apply-templates>
+ </div>
+ </td>
+ <td class="func-since-td">
+ <xsl:if test="string-length($since) > 0">
+ <span class="since"><xsl:value-of select="$since"/>
+ </span>
+ </xsl:if>
+ </td>
+ </tr>
+ </table>
</xsl:template>
<!-- The *last* <name name="..." arity=".."/> -->
@@ -397,18 +445,37 @@
<!-- Datatypes -->
<xsl:template match="datatypes">
- <h3>
- <a name="data-types" href="#data-types"><xsl:text>Data Types</xsl:text></a>
- </h3>
- <div class="data-types-body">
- <xsl:apply-templates/>
- </div>
+ <xsl:call-template name="h3_title_link">
+ <xsl:with-param name="title">Data Types</xsl:with-param>
+ </xsl:call-template>
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <!-- Datatype Title, is the really needed? not used by anything -->
+ <xsl:template match="datatype_title">
+ <xsl:variable name="title" select="."/>
+ <h4>
+ <xsl:call-template name="title_link">
+ <xsl:with-param name="title"><xsl:apply-templates/></xsl:with-param>
+ <xsl:with-param name="link" select="$title"/>
+ </xsl:call-template>
+ </h4>
</xsl:template>
<!-- Datatype -->
<xsl:template match="datatype">
- <div class="data-type-name"><xsl:apply-templates select="name"/></div>
- <div class="data-type-desc"><xsl:apply-templates select="desc"/></div>
+ <xsl:variable name="id" select="concat('type-',name/@name)"/>
+ <div class="data-types-body">
+ <div class="data-type-name"
+ onMouseOver="document.getElementById('ghlink-{$id}').style.visibility = 'visible';"
+ onMouseOut="document.getElementById('ghlink-{$id}').style.visibility = 'hidden';">
+ <xsl:call-template name="ghlink">
+ <xsl:with-param name="id" select="$id"/>
+ </xsl:call-template>
+ <xsl:apply-templates select="name"/>
+ </div>
+ <div class="data-type-desc"><xsl:apply-templates select="desc"/></div>
+ </div>
</xsl:template>
<!-- The "mode" attribute of apply has been used to separate the case
@@ -769,6 +836,10 @@
<!-- .../part -->
<xsl:call-template name="part.content" />
</xsl:if>
+ <xsl:if test="$lname = 'internal'">
+ <!-- .../internals -->
+ <xsl:call-template name="internal.content" />
+ </xsl:if>
<xsl:if test="$lname = 'chapter'">
<!-- .../part/chapter -->
<xsl:call-template name="chapter.content">
@@ -792,12 +863,24 @@
<xsl:param name="chapnum"/>
<xsl:param name="curModule"/>
<xsl:if test="(local-name() = 'part') or ((local-name() = 'chapter') and ancestor::part)">
- <!-- .../part or.../part/chapter -->
+ <!-- .../part or .../part/chapter -->
<xsl:call-template name="menu.ug">
<xsl:with-param name="chapnum" select="$chapnum"/>
</xsl:call-template>
</xsl:if>
- <xsl:if test="(local-name() = 'application') or (local-name() = 'erlref')or (local-name() = 'comref')or (local-name() = 'cref')or (local-name() = 'fileref')or (local-name() = 'appref')">
+ <xsl:if test="(local-name() = 'internal' and descendant::chapter) or ((local-name() = 'chapter') and ancestor::internal)">
+ <!-- .../internal or .../internal/chapter -->
+ <xsl:call-template name="menu.internal.ug">
+ <xsl:with-param name="chapnum" select="$chapnum"/>
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:if test="(local-name() = 'internal' and descendant::erlref) or (((local-name() = 'erlref') or (local-name() = 'comref') or (local-name() = 'cref') or (local-name() = 'fileref') or (local-name() = 'appref')) and ancestor::internal)">
+ <!-- .../internal,.../internal/erlref, .../internal/comref or .../internal/cref or .../internal/fileref or .../internal/appref -->
+ <xsl:call-template name="menu.internal.ref">
+ <xsl:with-param name="curModule" select="$curModule"/>
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:if test="(local-name() = 'application') or (((local-name() = 'erlref') or (local-name() = 'comref') or (local-name() = 'cref') or (local-name() = 'fileref') or (local-name() = 'appref')) and ancestor::application)">
<!-- .../application,.../application/erlref, .../application/comref or .../application/cref or .../application/fileref or .../application/appref -->
<xsl:call-template name="menu.ref">
<xsl:with-param name="curModule" select="$curModule"/>
@@ -835,6 +918,9 @@
<xsl:if test="boolean(/book/applications)">
<li><a href="index.html">Reference Manual</a></li>
</xsl:if>
+ <xsl:if test="boolean(/book/internals)">
+ <li><a href="internal_docs.html">Internal Documentation</a></li>
+ </xsl:if>
<xsl:if test="boolean(/book/releasenotes)">
<li><a href="release_notes.html">Release Notes</a></li>
</xsl:if>
@@ -875,6 +961,7 @@
<xsl:template match="/book">
<xsl:apply-templates select="parts"/>
<xsl:apply-templates select="applications"/>
+ <xsl:apply-templates select="internals"/>
<xsl:apply-templates select="releasenotes"/>
</xsl:template>
@@ -888,9 +975,14 @@
<xsl:apply-templates select="application"/>
</xsl:template>
+ <!-- Internals -->
+ <xsl:template match="internals">
+ <xsl:apply-templates select="internal"/>
+ </xsl:template>
+
<!-- Header -->
<xsl:template match="header"/>
-
+
<!-- Section/Title -->
<xsl:template match="section/title"/>
@@ -903,10 +995,12 @@
<xsl:for-each select="marker">
<xsl:call-template name="marker-before-title"/>
</xsl:for-each>
- <a name="{generate-id(title)}">
- <xsl:value-of select="$chapnum"/>.<xsl:number/>&#160;
- <xsl:value-of select="title"/>
- </a>
+ <xsl:call-template name="title_link">
+ <xsl:with-param name="title">
+ <xsl:value-of select="$chapnum"/>.<xsl:number/>&#160;
+ <xsl:value-of select="title"/>
+ </xsl:with-param>
+ </xsl:call-template>
</h3>
<xsl:apply-templates>
<xsl:with-param name="chapnum" select="$chapnum"/>
@@ -923,7 +1017,9 @@
<xsl:call-template name="marker-before-title"/>
</xsl:for-each>
<!-- xsl:value-of select="$partnum"/>.<xsl:value-of select="$chapnum"/>.<xsl:value-of select="$sectnum"/>.<xsl:number/ -->
- <xsl:value-of select="title"/>
+ <xsl:call-template name="title_link">
+ <xsl:with-param name="title" select="title"/>
+ </xsl:call-template>
</h4>
<xsl:apply-templates>
<xsl:with-param name="chapnum" select="$chapnum"/>
@@ -953,9 +1049,9 @@
<xsl:for-each select="marker">
<xsl:call-template name="marker-before-title"/>
</xsl:for-each>
- <a name="{generate-id(title)}">
- <xsl:value-of select="title"/>
- </a>
+ <xsl:call-template name="title_link">
+ <xsl:with-param name="title" select="title"/>
+ </xsl:call-template>
</h3>
<div class="REFBODY rb-3">
<xsl:apply-templates>
@@ -1208,7 +1304,14 @@
</xsl:variable>
<div class="doc-image-wrapper">
- <img alt="IMAGE MISSING" src="{@file}" class="doc-image"/>
+ <xsl:choose>
+ <xsl:when test="@width">
+ <img alt="IMAGE MISSING" width="{@width}" src="{@file}" class="doc-image"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <img alt="IMAGE MISSING" src="{@file}" class="doc-image"/>
+ </xsl:otherwise>
+ </xsl:choose>
<xsl:apply-templates>
<xsl:with-param name="chapnum" select="$chapnum"/>
@@ -1233,6 +1336,90 @@
</xsl:template>
+ <!-- Internal Docs -->
+
+ <!-- Part -->
+ <xsl:template match="internal">
+
+ <xsl:document href="{$outdir}/internal_docs.html" method="html" encoding="UTF-8" indent="yes" doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN">
+ <xsl:call-template name="pagelayout"/>
+ </xsl:document>
+ </xsl:template>
+
+
+ <!-- Part content-->
+ <xsl:template name="internal.content">
+ <div class="frontpage"/>
+
+ <center><h1><xsl:value-of select="/book/header/title"/> Internal Docs</h1></center>
+
+ <center><h4>Version <xsl:value-of select="$appver"/></h4></center>
+ <center><h4><xsl:value-of select="$gendate"/></h4></center>
+ <div class="extrafrontpageinfo">
+ <center><xsl:value-of select="$extra_front_page_info"/></center>
+ </div>
+
+ <xsl:apply-templates select="chapter|erlref"/>
+
+ </xsl:template>
+
+ <!-- Menu.internal.chapter -->
+ <xsl:template name="menu.internal.ug">
+ <xsl:param name="chapnum"/>
+
+ <div id="leftnav">
+ <div class="innertube">
+
+ <xsl:call-template name="erlang_logo"/>
+
+ <p class="section-title"><xsl:value-of select="/book/header/title"/></p>
+ <p class="section-subtitle">Internal Documentation</p>
+ <p class="section-version">Version <xsl:value-of select="$appver"/></p>
+
+ <xsl:call-template name="menu_top"/>
+
+ <xsl:call-template name="menu_middle"/>
+
+ <h3>Chapters</h3>
+
+ <ul class="flipMenu" imagepath="{$topdocdir}/js/flipmenu">
+ <xsl:call-template name="menu.chapter">
+ <xsl:with-param name="entries" select="/book/internals/internal/chapter[header/title]"/>
+ <xsl:with-param name="chapnum" select="$chapnum"/>
+ </xsl:call-template>
+ </ul>
+ </div>
+ </div>
+ </xsl:template>
+
+ <!-- Menu.internal.ref -->
+ <xsl:template name="menu.internal.ref">
+ <xsl:param name="curModule"/>
+ <div id="leftnav">
+ <div class="innertube">
+
+ <xsl:call-template name="erlang_logo"/>
+
+ <p class="section-title"><xsl:value-of select="/book/header/title"/></p>
+ <p class="section-subtitle">Reference Manual</p>
+ <p class="section-version">Version <xsl:value-of select="$appver"/></p>
+
+ <xsl:call-template name="menu_top"/>
+
+ <xsl:call-template name="menu_middle"/>
+
+ <h3>Table of Contents</h3>
+
+ <ul class="flipMenu">
+ <xsl:call-template name="menu.ref2">
+ <xsl:with-param name="entries" select="/book/internals/internal/erlref[module]|/book/internals/internal/cref[lib]|/book/internals/internal/comref[com]|/book/internals/internal/fileref[file]|/book/internals/internal/appref[app]"/>
+ <!--xsl:with-param name="genFuncMenu" select="true"/-->
+ <xsl:with-param name="curModule" select="$curModule"/>
+ </xsl:call-template>
+ </ul>
+ </div>
+ </div>
+ </xsl:template>
<!--Users Guide -->
@@ -1345,7 +1532,7 @@
<xsl:param name="chapter_file"/>
<xsl:for-each select="$entries">
<li title="{title}">
- <a href="{$chapter_file}.html#{generate-id(title)}">
+ <a href="{$chapter_file}.html#{erl:to-link(title)}">
<xsl:value-of select="title"/>
</a>
</li>
@@ -1799,7 +1986,9 @@
<!-- Module -->
<xsl:template match="module">
<xsl:param name="partnum"/>
- <h3><a name="module" href="#module">Module</a></h3>
+ <xsl:call-template name="h3_title_link">
+ <xsl:with-param name="title">Module</xsl:with-param>
+ </xsl:call-template>
<div class="REFBODY module-body">
<xsl:apply-templates>
<xsl:with-param name="partnum" select="$partnum"/>
@@ -1811,18 +2000,32 @@
<!-- Modulesummary -->
<xsl:template match="modulesummary">
<xsl:param name="partnum"/>
- <h3><a name="module-summary" href="#module-summary">Module Summary</a></h3>
+ <xsl:call-template name="h3_title_link">
+ <xsl:with-param name="title">Module Summary</xsl:with-param>
+ </xsl:call-template>
<div class="REFBODY module-summary-body">
<xsl:apply-templates>
<xsl:with-param name="partnum" select="$partnum"/>
</xsl:apply-templates>
</div>
+ <!-- Since -->
+ <xsl:if test="string-length(../module/@since) > 0">
+ <xsl:call-template name="h3_title_link">
+ <xsl:with-param name="title">Since</xsl:with-param>
+ </xsl:call-template>
+ <div class="REFBODY module-since">
+ Module <xsl:value-of select="../module"/> was introduced in
+ <xsl:value-of select="../module/@since"/>.
+ </div>
+ </xsl:if>
</xsl:template>
<!-- Lib -->
<xsl:template match="lib">
<xsl:param name="partnum"/>
- <h3><a name="c-library" href="#c-library">C Library</a></h3>
+ <xsl:call-template name="h3_title_link">
+ <xsl:with-param name="title">C Library</xsl:with-param>
+ </xsl:call-template>
<div class="REFBODY c-library-body">
<xsl:apply-templates>
<xsl:with-param name="partnum" select="$partnum"/>
@@ -1834,7 +2037,9 @@
<!-- Libsummary -->
<xsl:template match="libsummary">
<xsl:param name="partnum"/>
- <h3><a name="library-summary" href="#library-summary">Library Summary</a></h3>
+ <xsl:call-template name="h3_title_link">
+ <xsl:with-param name="title">Library Summary</xsl:with-param>
+ </xsl:call-template>
<div class="REFBODY library-summary-body">
<xsl:apply-templates>
<xsl:with-param name="partnum" select="$partnum"/>
@@ -1845,7 +2050,9 @@
<!-- Com -->
<xsl:template match="com">
<xsl:param name="partnum"/>
- <h3><a name="command" href="#command">Command</a></h3>
+ <xsl:call-template name="h3_title_link">
+ <xsl:with-param name="title">Command</xsl:with-param>
+ </xsl:call-template>
<div class="REFBODY command-body">
<xsl:apply-templates>
<xsl:with-param name="partnum" select="$partnum"/>
@@ -1857,7 +2064,9 @@
<!-- Comsummary -->
<xsl:template match="comsummary">
<xsl:param name="partnum"/>
- <h3><a name="command-summary" href="#command-summary">Command Summary</a></h3>
+ <xsl:call-template name="h3_title_link">
+ <xsl:with-param name="title">Command Summary</xsl:with-param>
+ </xsl:call-template>
<div class="REFBODY command-summary-body">
<xsl:apply-templates>
<xsl:with-param name="partnum" select="$partnum"/>
@@ -1868,7 +2077,9 @@
<!-- File -->
<xsl:template match="file">
<xsl:param name="partnum"/>
- <h3><a name="file" href="#file">File</a></h3>
+ <xsl:call-template name="h3_title_link">
+ <xsl:with-param name="title">File</xsl:with-param>
+ </xsl:call-template>
<div class="REFBODY file-body">
<xsl:apply-templates>
<xsl:with-param name="partnum" select="$partnum"/>
@@ -1880,7 +2091,9 @@
<!-- Filesummary -->
<xsl:template match="filesummary">
<xsl:param name="partnum"/>
- <h3><a name="file-summary" href="#file-summary">File Summary</a></h3>
+ <xsl:call-template name="h3_title_link">
+ <xsl:with-param name="title">File Summary</xsl:with-param>
+ </xsl:call-template>
<div class="REFBODY file-summary-body">
<xsl:apply-templates>
<xsl:with-param name="partnum" select="$partnum"/>
@@ -1892,7 +2105,9 @@
<!-- App -->
<xsl:template match="app">
<xsl:param name="partnum"/>
- <h3><a name="application" href="#application">Application</a></h3>
+ <xsl:call-template name="h3_title_link">
+ <xsl:with-param name="title">Application</xsl:with-param>
+ </xsl:call-template>
<div class="REFBODY application-body">
<xsl:apply-templates>
<xsl:with-param name="partnum" select="$partnum"/>
@@ -1904,7 +2119,9 @@
<!-- Appsummary -->
<xsl:template match="appsummary">
<xsl:param name="partnum"/>
- <h3><a name="application-summary" href="#application-summary">Application Summary</a></h3>
+ <xsl:call-template name="h3_title_link">
+ <xsl:with-param name="title">Application Summary</xsl:with-param>
+ </xsl:call-template>
<div class="REFBODY application-summary-body">
<xsl:apply-templates>
<xsl:with-param name="partnum" select="$partnum"/>
@@ -1915,7 +2132,9 @@
<!-- Description -->
<xsl:template match="description">
<xsl:param name="partnum"/>
- <h3><a name="description" href="#description">Description</a></h3>
+ <xsl:call-template name="h3_title_link">
+ <xsl:with-param name="title">Description</xsl:with-param>
+ </xsl:call-template>
<div class="REFBODY description-body">
<p>
<xsl:apply-templates>
@@ -1929,7 +2148,9 @@
<xsl:template match="funcs">
<xsl:param name="partnum"/>
- <h3><a name="exports" href="#exports"><xsl:text>Exports</xsl:text></a></h3>
+ <xsl:call-template name="h3_title_link">
+ <xsl:with-param name="title">Exports</xsl:with-param>
+ </xsl:call-template>
<div class="exports-body">
<xsl:apply-templates>
@@ -1943,10 +2164,10 @@
<xsl:template match="func">
<xsl:param name="partnum"/>
- <p><xsl:apply-templates select="name"/>
- <xsl:apply-templates
- select="name[string-length(@arity) > 0 and position()=last()]"
- mode="types"/></p>
+ <xsl:apply-templates select="name"/>
+ <xsl:apply-templates
+ select="name[string-length(@arity) > 0 and position()=last()]"
+ mode="types"/>
<xsl:apply-templates select="fsummary|type|desc">
<xsl:with-param name="partnum" select="$partnum"/>
@@ -2005,14 +2226,22 @@
<xsl:choose>
<xsl:when test="ancestor::cref">
- <a name="{substring-before(nametext, '(')}">
- <span class="bold_code bc-7">
- <xsl:value-of select="ret"/>
- <xsl:call-template name="maybe-space-after-ret">
- <xsl:with-param name="s" select="ret"/>
- </xsl:call-template>
- <xsl:value-of select="nametext"/>
- </span></a><br/>
+ <table class="func-table">
+ <tr class="func-tr">
+ <td class="cfunc-td">
+ <span class="bold_code bc-7">
+ <xsl:call-template name="title_link">
+ <xsl:with-param name="link" select="substring-before(nametext, '(')"/>
+ </xsl:call-template>
+ </span>
+ </td>
+ <td class="func-since-td">
+ <xsl:if test="string-length(@since) > 0">
+ <span class="since"><xsl:value-of select="@since"/></span>
+ </xsl:if>
+ </td>
+ </tr>
+ </table>
</xsl:when>
<xsl:when test="ancestor::erlref">
<xsl:variable name="fname">
@@ -2033,32 +2262,45 @@
</xsl:variable>
<xsl:choose>
<xsl:when test="ancestor::datatype">
- <a name="type-{$fname}"></a><span class="bold_code bc-8"><xsl:apply-templates/></span><br/>
+ <div class="bold_code bc-8">
+ <xsl:call-template name="title_link">
+ <xsl:with-param name="link" select="concat('type-',$fname)"/>
+ <xsl:with-param name="title">
+ <xsl:apply-templates/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </div>
</xsl:when>
<xsl:otherwise>
- <a name="{$fname}-{$arity}"></a><span class="bold_code fun-type"><xsl:apply-templates/></span><br/>
+ <table class="func-table">
+ <tr class="func-tr">
+ <td class="func-td">
+ <div class="bold_code fun-type">
+ <xsl:call-template name="title_link">
+ <xsl:with-param name="link" select="concat(concat($fname,'-'),$arity)"/>
+ <xsl:with-param name="title">
+ <xsl:apply-templates/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </div>
+ </td>
+ <td class="func-since-td">
+ <xsl:if test="string-length(@since) > 0">
+ <span class="since"><xsl:value-of select="@since"/></span>
+ </xsl:if>
+ </td>
+ </tr>
+ </table>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
- <span class="bold_code bc-10"><xsl:value-of select="."/></span>
+ <div class="bold_code bc-10"><xsl:value-of select="."/></div>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
- <xsl:template name="maybe-space-after-ret">
- <xsl:param name="s"/>
- <xsl:variable name="last_char"
- select="substring($s, string-length($s), 1)"/>
- <xsl:choose>
- <xsl:when test="$last_char != '*'">
- <xsl:text> </xsl:text>
- </xsl:when>
- </xsl:choose>
- </xsl:template>
-
-
<!-- Type -->
<xsl:template match="type">
<xsl:param name="partnum"/>
@@ -2101,6 +2343,58 @@
</div>
</xsl:template>
+ <xsl:template name="h3_title_link">
+ <xsl:param name="title"/>
+ <h3>
+ <xsl:call-template name="title_link">
+ <xsl:with-param name="title" select="$title"/>
+ <xsl:with-param name="link" select="erl:to-link($title)"/>
+ </xsl:call-template>
+ </h3>
+ </xsl:template>
+
+ <xsl:template name="title_link">
+ <xsl:param name="title" select="'APPLY'"/>
+ <xsl:param name="link" select="erl:to-link(title)"/>
+ <xsl:param name="ghlink" select="ancestor-or-self::*[@ghlink][position() = 1]/@ghlink"/>
+ <xsl:variable name="id" select="concat(concat($link,'-'), generate-id(.))"/>
+ <span onMouseOver="document.getElementById('ghlink-{$id}').style.visibility = 'visible';"
+ onMouseOut="document.getElementById('ghlink-{$id}').style.visibility = 'hidden';">
+ <xsl:call-template name="ghlink">
+ <xsl:with-param name="id" select="$id"/>
+ <xsl:with-param name="ghlink" select="$ghlink"/>
+ </xsl:call-template>
+ <a class="title_link" name="{$link}" href="#{$link}">
+ <xsl:choose>
+ <xsl:when test="$title = 'APPLY'">
+ <xsl:apply-templates/> <!-- like <ret> and <nametext> -->
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$title"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </a>
+ </span>
+ </xsl:template>
+
+ <xsl:template name="ghlink">
+ <xsl:param name="id"/>
+ <xsl:param name="ghlink" select="ancestor-or-self::*[@ghlink][position() = 1]/@ghlink"/>
+ <xsl:choose>
+ <xsl:when test="string-length($ghlink) > 0">
+ <span id="ghlink-{$id}" class="ghlink">
+ <a href="https://github.com/erlang/otp/edit/{$ghlink}"
+ title="Found an issue with the documentation? Fix it by clicking here!">
+ <span class="pencil"/>
+ </a>
+ </span>
+ </xsl:when>
+ <xsl:otherwise>
+ <span id="ghlink-{$id}"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
<!-- Desc -->
<xsl:template match="desc">
<xsl:param name="partnum"/>
@@ -2509,4 +2803,46 @@
<xsl:value-of select="normalize-space(.)"/>
</xsl:template>
+ <xsl:template match="ret">
+ <xsl:value-of select="."/>
+ <xsl:variable name="last_char" select="substring(., string-length(.), 1)"/>
+ <xsl:if test="$last_char != '*'">
+ <xsl:text> </xsl:text>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template match="nametext">
+ <xsl:value-of select="substring-before(.,'(')"/>
+ <xsl:text>(</xsl:text>
+ <xsl:variable name="arglist" select="substring-after(.,'(')"/>
+ <xsl:choose>
+ <xsl:when test="$arglist = ')' or $arglist = 'void)'">
+ <xsl:value-of select="$arglist"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <br/>
+ <xsl:call-template name="cfunc-arglist">
+ <xsl:with-param name="text" select="$arglist"/>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <!-- Format C function argument list with <br> after comma -->
+ <xsl:template name="cfunc-arglist">
+ <xsl:param name="text"/>
+ <xsl:variable name="line" select="normalize-space($text)"/>
+ <xsl:choose>
+ <xsl:when test="contains($line,',')">
+ <xsl:value-of select="substring-before($line,',')"/>,<br/>
+ <xsl:call-template name="cfunc-arglist">
+ <xsl:with-param name="text" select="substring-after($line,',')"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$line"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
</xsl:stylesheet>
diff --git a/lib/erl_docgen/priv/xsl/db_man.xsl b/lib/erl_docgen/priv/xsl/db_man.xsl
index 03b6b0691d..27b2bd4066 100644
--- a/lib/erl_docgen/priv/xsl/db_man.xsl
+++ b/lib/erl_docgen/priv/xsl/db_man.xsl
@@ -3,7 +3,7 @@
#
# %CopyrightBegin%
#
- # Copyright Ericsson AB 2009-2016. All Rights Reserved.
+ # Copyright Ericsson AB 2009-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -271,6 +271,12 @@
<xsl:apply-templates/>
</xsl:template>
+ <!-- Datatype Title-->
+ <xsl:template match="datatype_title">
+ <xsl:text>&#10;.SS </xsl:text>
+ <xsl:apply-templates/>
+ </xsl:template>
+
<!-- Datatype -->
<xsl:template match="datatype">
<xsl:apply-templates/>
diff --git a/lib/erl_docgen/priv/xsl/db_pdf.xsl b/lib/erl_docgen/priv/xsl/db_pdf.xsl
index 46de66bcd8..1b91d768e3 100644
--- a/lib/erl_docgen/priv/xsl/db_pdf.xsl
+++ b/lib/erl_docgen/priv/xsl/db_pdf.xsl
@@ -3,7 +3,7 @@
#
# %CopyrightBegin%
#
- # Copyright Ericsson AB 2009-2016. All Rights Reserved.
+ # Copyright Ericsson AB 2009-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -299,6 +299,13 @@
<xsl:apply-templates/>
</xsl:template>
+ <!-- Datatype Title-->
+ <xsl:template match="datatype_title">
+ <fo:block xsl:use-attribute-sets="h4">
+ <xsl:apply-templates/>
+ </fo:block>
+ </xsl:template>
+
<!-- Datatype -->
<xsl:template match="datatype">
<fo:block xsl:use-attribute-sets="function-name">
@@ -1649,8 +1656,14 @@
</xsl:variable>
<fo:block xsl:use-attribute-sets="image">
- <fo:external-graphic content-width="scale-down-to-fit" inline-progression-dimension.maximum="100%" src="{@file}"/>
-
+ <xsl:choose>
+ <xsl:when test="@width">
+ <fo:external-graphic content-width="scale-to-fit" width="{@width}" inline-progression-dimension.maximum="100%" src="{@file}"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <fo:external-graphic content-width="scale-down-to-fit" inline-progression-dimension.maximum="100%" src="{@file}"/>
+ </xsl:otherwise>
+ </xsl:choose>
<xsl:apply-templates>
<xsl:with-param name="chapnum" select="$chapnum"/>
<xsl:with-param name="fignum" select="$fignum"/>
diff --git a/lib/erl_docgen/priv/xsl/db_pdf_params.xsl b/lib/erl_docgen/priv/xsl/db_pdf_params.xsl
index 99da29c2ac..9bfa991b54 100644
--- a/lib/erl_docgen/priv/xsl/db_pdf_params.xsl
+++ b/lib/erl_docgen/priv/xsl/db_pdf_params.xsl
@@ -3,7 +3,7 @@
#
# %CopyrightBegin%
#
- # Copyright Ericsson AB 2009-2017. All Rights Reserved.
+ # Copyright Ericsson AB 2009-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -139,6 +139,7 @@
<xsl:attribute-set name="image">
<xsl:attribute name="space-after">0.5em</xsl:attribute>
<xsl:attribute name="space-before">0.5em</xsl:attribute>
+ <xsl:attribute name="text-align">center</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="listblock">
diff --git a/lib/erl_docgen/src/docgen_edoc_xml_cb.erl b/lib/erl_docgen/src/docgen_edoc_xml_cb.erl
index 91422c8910..5342d02947 100644
--- a/lib/erl_docgen/src/docgen_edoc_xml_cb.erl
+++ b/lib/erl_docgen/src/docgen_edoc_xml_cb.erl
@@ -11,7 +11,7 @@
%% limitations under the License.
%%
%% Copyright (c) 2001-2016 Richard Carlsson. Parts written by Ericsson
-%% are Copyright (c) Ericsson AB 2001-2012. All Rights Reserved.
+%% are Copyright (c) Ericsson AB 2001-2017. All Rights Reserved.
%%
-module(docgen_edoc_xml_cb).
@@ -113,7 +113,7 @@ root_attributes(Element, Opts) ->
%% epp:default_encoding/0 returns 'utf8'
reformat_encoding(utf8) -> "UTF-8";
reformat_encoding(List) when is_list(List) ->
- case string:to_lower(List) of
+ case string:lowercase(List) of
"utf8" -> "UTF-8";
_ -> List
end;
@@ -182,7 +182,7 @@ chapter_title(#xmlElement{content=Es}) -> % name = h3 | h4
%% otp_xmlify(Es1) -> Es2
%% Es1 = Es2 = [#xmlElement{} | #xmlText{}]
%% Fix things that are allowed in XHTML but not in chapter/erlref DTDs.
-%% 1) lists (<ul>, <ol>, <dl>) and code snippets (<pre>) can not occur
+%% 1) lists (<ul>, <ol>, <dl>) and code snippets (<pre>) cannot occur
%% within a <p>, such a <p> must be splitted into a sequence of <p>,
%% <ul>, <ol>, <dl> and <pre>.
%% 2) <a> must only have either a href attribute (corresponds to a
@@ -1260,11 +1260,14 @@ get_text(#xmlElement{content=[E]}) ->
%% text_and_name_only(Es) -> {N, Ts}
text_and_a_name_only(Es) ->
- [Name|_] = [Name ||
- #xmlElement{
- name = a,
- attributes = [#xmlAttribute{name=name}]}=Name <- Es],
- {Name#xmlElement{content = []}, text_only(Es)}.
+ case [Name || #xmlElement{
+ name = a,
+ attributes = [#xmlAttribute{name=name}]}=Name <- Es] of
+ [Name|_] ->
+ {Name#xmlElement{content = []}, text_only(Es)};
+ [] ->
+ {"", text_only(Es)}
+ end.
%% text_only(Es) -> Ts
%% Takes a list of xmlElement and xmlText and return a lists of xmlText.
diff --git a/lib/erl_docgen/src/docgen_otp_specs.erl b/lib/erl_docgen/src/docgen_otp_specs.erl
index 126229ecc9..311ec1471a 100644
--- a/lib/erl_docgen/src/docgen_otp_specs.erl
+++ b/lib/erl_docgen/src/docgen_otp_specs.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -297,7 +297,7 @@ indent(L) ->
app_fix(L) ->
try
{"//" ++ R1,L2} = app_fix(L, 1),
- [App, Mod] = string:tokens(R1, "/"),
+ [App, Mod] = string:lexemes(R1, "/"),
"//" ++ atom(App) ++ "/" ++ atom(Mod) ++ L2
catch _:_ -> L
end.
@@ -585,13 +585,13 @@ ot_integer(E) ->
{integer,0,list_to_integer(get_attrval(value, E))}.
ot_range(E) ->
- [I1, I2] = string:tokens(get_attrval(value, E), "."),
+ [I1, I2] = string:lexemes(get_attrval(value, E), "."),
{type,0,range,[{integer,0,list_to_integer(I1)},
{integer,0,list_to_integer(I2)}]}.
ot_binary(E) ->
{Base, Unit} =
- case string:tokens(get_attrval(value, E), ",:*><") of
+ case string:lexemes(get_attrval(value, E), ",:*><") of
[] ->
{0, 0};
["_",B] ->
@@ -658,6 +658,8 @@ ot_name(Es, T) ->
{atom,0,list_to_atom(Atom)},T]};
"tuple" when T =:= [] ->
{type,0,tuple,any};
+ "map" when T =:= [] ->
+ {type,0,map,any};
Atom ->
{type,0,list_to_atom(Atom),T}
end.
diff --git a/lib/erl_docgen/src/docgen_xmerl_xml_cb.erl b/lib/erl_docgen/src/docgen_xmerl_xml_cb.erl
index 59d4dccfb7..9d69143c3c 100644
--- a/lib/erl_docgen/src/docgen_xmerl_xml_cb.erl
+++ b/lib/erl_docgen/src/docgen_xmerl_xml_cb.erl
@@ -87,6 +87,7 @@ convert_tag(underline, Attrs) -> {em, Attrs};
convert_tag(Tag, Attrs) -> {Tag, Attrs}.
is_url("http:"++_) -> true;
+is_url("https:"++_) -> true;
is_url("../"++_) -> true;
is_url(FileRef) ->
case filename:extension(FileRef) of
diff --git a/lib/erl_docgen/vsn.mk b/lib/erl_docgen/vsn.mk
index 95b2329ac5..fece2456c1 100644
--- a/lib/erl_docgen/vsn.mk
+++ b/lib/erl_docgen/vsn.mk
@@ -1 +1 @@
-ERL_DOCGEN_VSN = 0.7.2
+ERL_DOCGEN_VSN = 0.9.1
diff --git a/lib/erl_interface/configure.in b/lib/erl_interface/configure.in
index 0a8fbf513c..f0e9b2eb3f 100644
--- a/lib/erl_interface/configure.in
+++ b/lib/erl_interface/configure.in
@@ -1,7 +1,7 @@
# -*- Autoconf -*-
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2000-2016. All Rights Reserved.
+# Copyright Ericsson AB 2000-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -29,11 +29,6 @@ dnl m4_define(EI_VERSION,regexp(m4_include(VERSION),[version \([-.0-9A-Za-z]+\)]
AC_INIT()
-if test "x$no_recursion" != "xyes" -a "x$OVERRIDE_CONFIG_CACHE" = "x"; then
- # We do not want to use a common cache!
- cache_file=/dev/null
-fi
-
dnl How to set srcdir absolute is taken from the GNU Emacs distribution
#### Make srcdir absolute, if it isn't already. It's important to
#### avoid running the path through pwd unnecessary, since pwd can
@@ -82,6 +77,15 @@ AC_ARG_ENABLE(threads,
esac ],
[ threads_disabled=maybe ])
+AC_ARG_ENABLE(mask-real-errno,
+[ --disable-mask-real-errno do not mask real 'errno'],
+[ case "$enableval" in
+ no) mask_real_errno=no ;;
+ *) mask_real_errno=yes ;;
+ esac ],
+[ mask_real_errno=yes ])
+
+
dnl ----------------------------------------------------------------------
dnl Checks for programs
dnl ----------------------------------------------------------------------
@@ -100,12 +104,29 @@ AC_CHECK_SIZEOF(long)
AC_CHECK_SIZEOF(void *)
AC_CHECK_SIZEOF(long long)
+if test $mask_real_errno = yes; then
+ AC_DEFINE(EI_HIDE_REAL_ERRNO, 1, [Define if 'errno' should not be exposed as is in 'erl_errno'])
+fi
+
dnl We set EI_64BIT mode when long is 8 bytes, this makes things
dnl work on windows and unix correctly
if test $ac_cv_sizeof_long = 8; then
CFLAGS="$CFLAGS -DEI_64BIT"
fi
+LM_HARDWARE_ARCH
+
+AC_MSG_CHECKING(for unaligned word access)
+case "$ARCH" in
+ x86|amd64)
+ AC_MSG_RESULT(yes: x86 or amd64)
+ AC_DEFINE(HAVE_UNALIGNED_WORD_ACCESS, 1, [Define if hw supports unaligned word access])
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+esac
+
AC_CHECK_TOOL(AR, ar, false)
if test "$AR" = false; then
AC_MSG_ERROR([No 'ar' command found in PATH])
@@ -145,7 +166,7 @@ AC_CHECK_LIB([socket], [getpeername])
# Checks for header files.
AC_HEADER_STDC
AC_HEADER_SYS_WAIT
-AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h malloc.h netdb.h netinet/in.h stddef.h stdlib.h string.h sys/param.h sys/socket.h sys/select.h sys/time.h unistd.h sys/types.h])
+AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h malloc.h netdb.h netinet/in.h stddef.h stdlib.h string.h sys/param.h sys/socket.h sys/select.h sys/time.h unistd.h sys/types.h sys/uio.h])
# Checks for typedefs, structures, and compiler characteristics.
# fixme AC_C_CONST & AC_C_VOLATILE needed for Windows?
@@ -180,7 +201,7 @@ AC_CHECK_FUNCS([dup2 gethostbyaddr gethostbyname \
gethostbyaddr_r \
gethostbyname_r gethostname writev \
gethrtime gettimeofday inet_ntoa memchr memmove memset select \
- socket strchr strerror strrchr strstr uname])
+ socket strchr strerror strrchr strstr uname sysconf])
AC_CHECK_FUNC(res_gethostbyname, [],
AC_CHECK_LIB(resolv, res_gethostbyname)
)
@@ -242,6 +263,7 @@ AC_SUBST(EI_THREADS)
case "$threads_disabled" in
no|maybe)
LM_CHECK_THR_LIB
+ ETHR_CHK_GCC_ATOMIC_OPS([])
case "$THR_LIB_NAME" in
"")
@@ -255,7 +277,7 @@ case "$threads_disabled" in
EI_THREADS="true"
THR_DEFS="$THR_DEFS -D_WIN32_WINNT=0x0600 -DWINVER=0x0600"
;;
- pthread)
+ pthread)
EI_THREADS="true"
;;
*)
@@ -338,6 +360,7 @@ LDFLAGS="$LDFLAGS $sanitizers"
# XXX
# ---------------------------------------------------------------------------
+
AC_OUTPUT(
src/$host/Makefile:src/Makefile.in
src/$host/eidefs.mk:src/eidefs.mk.in
diff --git a/lib/erl_interface/doc/src/Makefile b/lib/erl_interface/doc/src/Makefile
index 8ef7e9648c..507a84a453 100644
--- a/lib/erl_interface/doc/src/Makefile
+++ b/lib/erl_interface/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1998-2017. All Rights Reserved.
+# Copyright Ericsson AB 1998-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -100,6 +100,7 @@ debug opt:
clean clean_docs clean_tex:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN1DIR)/*
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
diff --git a/lib/erl_interface/doc/src/ei.xml b/lib/erl_interface/doc/src/ei.xml
index 9502fb1ee7..70af5642da 100644
--- a/lib/erl_interface/doc/src/ei.xml
+++ b/lib/erl_interface/doc/src/ei.xml
@@ -35,6 +35,9 @@
<lib>ei</lib>
<libsummary>Routines for handling the Erlang binary term format.</libsummary>
<description>
+ <note><p>The support for VxWorks is deprecated as of OTP 22, and
+ will be removed in OTP 23.</p></note>
+
<p>The library <c>ei</c> contains macros and functions to encode
and decode the Erlang binary term format.</p>
@@ -124,7 +127,7 @@ typedef enum {
<funcs>
<func>
- <name><ret>int</ret><nametext>ei_decode_atom(const char *buf, int *index, char *p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_decode_atom(const char *buf, int *index, char *p)</nametext></name>
<fsummary>Decode an atom.</fsummary>
<desc>
<p>Decodes an atom from the binary format. The <c>NULL</c>-terminated
@@ -134,7 +137,7 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_decode_atom_as(const char *buf, int *index, char *p, int plen, erlang_char_encoding want, erlang_char_encoding* was, erlang_char_encoding* result)</nametext></name>
+ <name since="OTP R16B"><ret>int</ret><nametext>ei_decode_atom_as(const char *buf, int *index, char *p, int plen, erlang_char_encoding want, erlang_char_encoding* was, erlang_char_encoding* result)</nametext></name>
<fsummary>Decode an atom.</fsummary>
<desc>
<p>Decodes an atom from the binary format. The <c>NULL</c>-terminated
@@ -158,7 +161,7 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_decode_bignum(const char *buf, int *index, mpz_t obj)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_decode_bignum(const char *buf, int *index, mpz_t obj)</nametext></name>
<fsummary>Decode a GMP arbitrary precision integer.</fsummary>
<desc>
<p>Decodes an integer in the binary format to a GMP
@@ -168,7 +171,7 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_decode_binary(const char *buf, int *index, void *p, long *len)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_decode_binary(const char *buf, int *index, void *p, long *len)</nametext></name>
<fsummary>Decode a binary.</fsummary>
<desc>
<p>Decodes a binary from the binary format. Parameter
@@ -180,7 +183,44 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_decode_boolean(const char *buf, int *index, int *p)</nametext></name>
+ <name since="OTP 22.0"><ret>int</ret><nametext>ei_decode_bitstring(const char *buf, int *index, const char **pp, unsigned int *bitoffsp, size_t *nbitsp)</nametext></name>
+ <fsummary>Decode a bitstring.</fsummary>
+ <desc>
+ <p>Decodes a bit string from the binary format.</p>
+ <taglist>
+ <tag><c>pp</c></tag>
+ <item><p>Either <c>NULL</c> or <c>*pp</c> returns a pointer to
+ the first byte of the bit string. The returned bit string is
+ readable as long as the buffer pointed to by <c>buf</c> is
+ readable and not written to.</p>
+ </item>
+ <tag><c>bitoffsp</c></tag>
+ <item><p>Either <c>NULL</c> or <c>*bitoffsp</c> returns the
+ number of unused bits in the first byte pointed to by
+ <c>*pp</c>. The value of <c>*bitoffsp</c> is between 0 and 7.
+ Unused bits in the first byte are the most significant bits.</p>
+ </item>
+ <tag><c>nbitsp</c></tag>
+ <item><p>Either <c>NULL</c> or <c>*nbitsp</c> returns the length
+ of the bit string in <em>bits</em>.</p>
+ </item>
+ </taglist>
+ <p>Returns <c>0</c> if it was a bit string term.</p>
+ <p>The number of <em>bytes</em> pointed to by <c>*pp</c>, which are
+ part of the bit string, is <c>(*bitoffsp + *nbitsp + 7)/8</c>. If
+ <c>(*bitoffsp + *bitsp)%8 > 0</c> then only <c>(*bitoffsp +
+ *bitsp)%8</c> bits of the last byte are used. Unused bits in
+ the last byte are the least significant bits.</p>
+ <p>The values of unused bits in the first and last byte are undefined
+ and cannot be relied on.</p>
+ <p>Number of bits may be divisible by 8, which means a binary
+ decodable by <c>ei_decode_binary</c> is also decodable by
+ <c>ei_decode_bitstring</c>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since=""><ret>int</ret><nametext>ei_decode_boolean(const char *buf, int *index, int *p)</nametext></name>
<fsummary>Decode a boolean.</fsummary>
<desc>
<p>Decodes a boolean value from the binary format.
@@ -190,7 +230,7 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_decode_char(const char *buf, int *index, char *p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_decode_char(const char *buf, int *index, char *p)</nametext></name>
<fsummary>Decode an 8-bit integer between 0-255.</fsummary>
<desc>
<p>Decodes a char (8-bit) integer between 0-255 from the binary format.
@@ -203,7 +243,7 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_decode_double(const char *buf, int *index, double *p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_decode_double(const char *buf, int *index, double *p)</nametext></name>
<fsummary>Decode a double.</fsummary>
<desc>
<p>Decodes a double-precision (64-bit) floating
@@ -212,7 +252,7 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_decode_ei_term(const char* buf, int* index, ei_term* term)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_decode_ei_term(const char* buf, int* index, ei_term* term)</nametext></name>
<fsummary>Decode a term, without previous knowledge of type.</fsummary>
<desc>
<p>Decodes any term, or at least tries to. If the term
@@ -233,8 +273,8 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_decode_fun(const char *buf, int *index, erlang_fun *p)</nametext></name>
- <name><ret>void</ret><nametext>free_fun(erlang_fun* f)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_decode_fun(const char *buf, int *index, erlang_fun *p)</nametext></name>
+ <name since=""><ret>void</ret><nametext>free_fun(erlang_fun* f)</nametext></name>
<fsummary>Decode a fun.</fsummary>
<desc>
<p>Decodes a fun from the binary format. Parameter
@@ -248,7 +288,7 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_decode_list_header(const char *buf, int *index, int *arity)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_decode_list_header(const char *buf, int *index, int *arity)</nametext></name>
<fsummary>Decode a list.</fsummary>
<desc>
<p>Decodes a list header from the binary
@@ -265,7 +305,7 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_decode_long(const char *buf, int *index, long *p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_decode_long(const char *buf, int *index, long *p)</nametext></name>
<fsummary>Decode integer.</fsummary>
<desc>
<p>Decodes a long integer from the binary format.
@@ -275,7 +315,7 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_decode_longlong(const char *buf, int *index, long long *p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_decode_longlong(const char *buf, int *index, long long *p)</nametext></name>
<fsummary>Decode integer.</fsummary>
<desc>
<p>Decodes a GCC <c>long long</c> or Visual C++
@@ -286,7 +326,7 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_decode_map_header(const char *buf, int *index, int *arity)</nametext></name>
+ <name since="OTP 17.0"><ret>int</ret><nametext>ei_decode_map_header(const char *buf, int *index, int *arity)</nametext></name>
<fsummary>Decode a map.</fsummary>
<desc>
<p>Decodes a map header from the binary
@@ -299,7 +339,7 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_decode_pid(const char *buf, int *index, erlang_pid *p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_decode_pid(const char *buf, int *index, erlang_pid *p)</nametext></name>
<fsummary>Decode a <c>pid</c>.</fsummary>
<desc>
<p>Decodes a process identifier (pid) from the binary format.</p>
@@ -307,7 +347,7 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_decode_port(const char *buf, int *index, erlang_port *p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_decode_port(const char *buf, int *index, erlang_port *p)</nametext></name>
<fsummary>Decode a port.</fsummary>
<desc>
<p>Decodes a port identifier from the binary format.</p>
@@ -315,7 +355,7 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_decode_ref(const char *buf, int *index, erlang_ref *p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_decode_ref(const char *buf, int *index, erlang_ref *p)</nametext></name>
<fsummary>Decode a reference.</fsummary>
<desc>
<p>Decodes a reference from the binary format.</p>
@@ -323,7 +363,7 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_decode_string(const char *buf, int *index, char *p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_decode_string(const char *buf, int *index, char *p)</nametext></name>
<fsummary>Decode a string.</fsummary>
<desc>
<p>Decodes a string from the binary format. A
@@ -338,7 +378,7 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_decode_term(const char *buf, int *index, void *t)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_decode_term(const char *buf, int *index, void *t)</nametext></name>
<fsummary>Decode a <c>ETERM</c>.</fsummary>
<desc>
<p>Decodes a term from the binary format. The term
@@ -346,13 +386,15 @@ typedef enum {
<c>t</c> is actually an <c>ETERM**</c> (see
<seealso marker="erl_eterm"><c>erl_eterm</c></seealso>).
The term is later to be deallocated.</p>
- <p>Notice that this function is located in the <c>Erl_Interface</c>
- library.</p>
+ <note><p>This function is deprecated as of OTP 22 and will be removed in
+ OTP 23 together with the old legacy <c>erl_interface</c> library (functions
+ with prefix <c>erl_</c>).</p>
+ </note>
</desc>
</func>
<func>
- <name><ret>int</ret><nametext>ei_decode_trace(const char *buf, int *index, erlang_trace *p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_decode_trace(const char *buf, int *index, erlang_trace *p)</nametext></name>
<fsummary>Decode a trace token.</fsummary>
<desc>
<p>Decodes an Erlang trace token from the binary format.</p>
@@ -360,7 +402,7 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_decode_tuple_header(const char *buf, int *index, int *arity)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_decode_tuple_header(const char *buf, int *index, int *arity)</nametext></name>
<fsummary>Decode a tuple.</fsummary>
<desc>
<p>Decodes a tuple header, the number of elements
@@ -370,7 +412,7 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_decode_ulong(const char *buf, int *index, unsigned long *p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_decode_ulong(const char *buf, int *index, unsigned long *p)</nametext></name>
<fsummary>Decode unsigned integer.</fsummary>
<desc>
<p>Decodes an unsigned long integer from the binary format.
@@ -380,7 +422,7 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_decode_ulonglong(const char *buf, int *index, unsigned long long *p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_decode_ulonglong(const char *buf, int *index, unsigned long long *p)</nametext></name>
<fsummary>Decode unsigned integer.</fsummary>
<desc>
<p>Decodes a GCC <c>unsigned long long</c> or Visual C++
@@ -390,7 +432,7 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_decode_version(const char *buf, int *index, int *version)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_decode_version(const char *buf, int *index, int *version)</nametext></name>
<fsummary>Decode an empty list (<c>nil</c>).</fsummary>
<desc>
<p>Decodes the version magic number for the
@@ -400,10 +442,10 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_encode_atom(char *buf, int *index, const char *p)</nametext></name>
- <name><ret>int</ret><nametext>ei_encode_atom_len(char *buf, int *index, const char *p, int len)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_atom(ei_x_buff* x, const char *p)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_atom_len(ei_x_buff* x, const char *p, int len)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_encode_atom(char *buf, int *index, const char *p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_encode_atom_len(char *buf, int *index, const char *p, int len)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_encode_atom(ei_x_buff* x, const char *p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_encode_atom_len(ei_x_buff* x, const char *p, int len)</nametext></name>
<fsummary>Encode an atom.</fsummary>
<desc>
<p>Encodes an atom in the binary format. Parameter <c>p</c>
@@ -415,10 +457,10 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_encode_atom_as(char *buf, int *index, const char *p, erlang_char_encoding from_enc, erlang_char_encoding to_enc)</nametext></name>
- <name><ret>int</ret><nametext>ei_encode_atom_len_as(char *buf, int *index, const char *p, int len, erlang_char_encoding from_enc, erlang_char_encoding to_enc)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_atom_as(ei_x_buff* x, const char *p, erlang_char_encoding from_enc, erlang_char_encoding to_enc)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_atom_len_as(ei_x_buff* x, const char *p, int len, erlang_char_encoding from_enc, erlang_char_encoding to_enc)</nametext></name>
+ <name since="OTP R16B"><ret>int</ret><nametext>ei_encode_atom_as(char *buf, int *index, const char *p, erlang_char_encoding from_enc, erlang_char_encoding to_enc)</nametext></name>
+ <name since="OTP R16B"><ret>int</ret><nametext>ei_encode_atom_len_as(char *buf, int *index, const char *p, int len, erlang_char_encoding from_enc, erlang_char_encoding to_enc)</nametext></name>
+ <name since="OTP R16B"><ret>int</ret><nametext>ei_x_encode_atom_as(ei_x_buff* x, const char *p, erlang_char_encoding from_enc, erlang_char_encoding to_enc)</nametext></name>
+ <name since="OTP R16B"><ret>int</ret><nametext>ei_x_encode_atom_len_as(ei_x_buff* x, const char *p, int len, erlang_char_encoding from_enc, erlang_char_encoding to_enc)</nametext></name>
<fsummary>Encode an atom.</fsummary>
<desc>
<p>Encodes an atom in the binary format. Parameter <c>p</c> is the name of the atom with
@@ -435,8 +477,8 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_encode_bignum(char *buf, int *index, mpz_t obj)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_bignum(ei_x_buff *x, mpz_t obj)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_encode_bignum(char *buf, int *index, mpz_t obj)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_encode_bignum(ei_x_buff *x, mpz_t obj)</nametext></name>
<fsummary>Encode an arbitrary precision integer.</fsummary>
<desc>
<p>Encodes a GMP <c>mpz_t</c> integer to binary format.
@@ -446,8 +488,8 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_encode_binary(char *buf, int *index, const void *p, long len)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_binary(ei_x_buff* x, const void *p, long len)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_encode_binary(char *buf, int *index, const void *p, long len)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_encode_binary(ei_x_buff* x, const void *p, long len)</nametext></name>
<fsummary>Encode a binary.</fsummary>
<desc>
<p>Encodes a binary in the binary format. The data is at
@@ -456,8 +498,30 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_encode_boolean(char *buf, int *index, int p)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_boolean(ei_x_buff* x, int p)</nametext></name>
+ <name since="OTP 22.0"><ret>int</ret>
+ <nametext>ei_encode_bitstring(char *buf, int *index, const char *p, size_t bitoffs, size_t nbits)</nametext></name>
+ <name since="OTP 22.0"><ret>int</ret>
+ <nametext>ei_x_encode_bitstring(ei_x_buff* x, const char *p, size_t bitoffs, size_t nbits)</nametext></name>
+ <fsummary>Encode a bitstring.</fsummary>
+ <desc>
+ <p>Encodes a bit string in the binary format.</p>
+ <p>The data is at <c>p</c>. The length of the bit string is <c>nbits</c>
+ bits. The first <c>bitoffs</c> bits of the data at <c>p</c> are unused.
+ The first byte which is part of the bit string is
+ <c>p[bitoffs/8]</c>. The <c>bitoffs%8</c> most significant bits of
+ the first byte <c>p[bitoffs/8]</c> are unused.</p>
+ <p>The number of bytes which is part of the bit string is <c>(bitoffs +
+ nbits + 7)/8</c>. If <c>(bitoffs + nbits)%8 > 0</c> then only <c>(bitoffs +
+ nbits)%8</c> bits of the last byte are used. Unused bits in
+ the last byte are the least significant bits.</p>
+ <p>The values of unused bits are disregarded and does not need to be
+ cleared.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since=""><ret>int</ret><nametext>ei_encode_boolean(char *buf, int *index, int p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_encode_boolean(ei_x_buff* x, int p)</nametext></name>
<fsummary>Encode a boolean.</fsummary>
<desc>
<p>Encodes a boolean value as the atom <c>true</c> if
@@ -467,8 +531,8 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_encode_char(char *buf, int *index, char p)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_char(ei_x_buff* x, char p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_encode_char(char *buf, int *index, char p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_encode_char(ei_x_buff* x, char p)</nametext></name>
<fsummary>Encode an 8-bit integer between 0-255.</fsummary>
<desc>
<p>Encodes a char (8-bit) as an integer between 0-255 in the binary
@@ -481,8 +545,8 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_encode_double(char *buf, int *index, double p)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_double(ei_x_buff* x, double p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_encode_double(char *buf, int *index, double p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_encode_double(ei_x_buff* x, double p)</nametext></name>
<fsummary>Encode a double float.</fsummary>
<desc>
<p>Encodes a double-precision (64-bit) floating point number in
@@ -493,8 +557,8 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_encode_empty_list(char* buf, int* index)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_empty_list(ei_x_buff* x)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_encode_empty_list(char* buf, int* index)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_encode_empty_list(ei_x_buff* x)</nametext></name>
<fsummary>Encode an empty list (<c>nil</c>).</fsummary>
<desc>
<p>Encodes an empty list. It is often used at the tail of a list.</p>
@@ -502,8 +566,8 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_encode_fun(char *buf, int *index, const erlang_fun *p)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_fun(ei_x_buff* x, const erlang_fun* fun)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_encode_fun(char *buf, int *index, const erlang_fun *p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_encode_fun(ei_x_buff* x, const erlang_fun* fun)</nametext></name>
<fsummary>Encode a fun.</fsummary>
<desc>
<p>Encodes a fun in the binary format. Parameter <c>p</c>
@@ -515,8 +579,8 @@ typedef enum {
</func>
<func>
- <name><ret>int</ret><nametext>ei_encode_list_header(char *buf, int *index, int arity)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_list_header(ei_x_buff* x, int arity)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_encode_list_header(char *buf, int *index, int arity)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_encode_list_header(ei_x_buff* x, int arity)</nametext></name>
<fsummary>Encode a list.</fsummary>
<desc>
<p>Encodes a list header, with a specified
@@ -552,8 +616,8 @@ ei_x_encode_empty_list(&amp;x);</pre>
</func>
<func>
- <name><ret>int</ret><nametext>ei_encode_long(char *buf, int *index, long p)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_long(ei_x_buff* x, long p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_encode_long(char *buf, int *index, long p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_encode_long(ei_x_buff* x, long p)</nametext></name>
<fsummary>Encode integer.</fsummary>
<desc>
<p>Encodes a long integer in the binary format.
@@ -563,8 +627,8 @@ ei_x_encode_empty_list(&amp;x);</pre>
</func>
<func>
- <name><ret>int</ret><nametext>ei_encode_longlong(char *buf, int *index, long long p)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_longlong(ei_x_buff* x, long long p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_encode_longlong(char *buf, int *index, long long p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_encode_longlong(ei_x_buff* x, long long p)</nametext></name>
<fsummary>Encode integer.</fsummary>
<desc>
<p>Encodes a GCC <c>long long</c> or Visual C++
@@ -574,8 +638,8 @@ ei_x_encode_empty_list(&amp;x);</pre>
</func>
<func>
- <name><ret>int</ret><nametext>ei_encode_map_header(char *buf, int *index, int arity)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_map_header(ei_x_buff* x, int arity)</nametext></name>
+ <name since="OTP 17.0"><ret>int</ret><nametext>ei_encode_map_header(char *buf, int *index, int arity)</nametext></name>
+ <name since="OTP 17.0"><ret>int</ret><nametext>ei_x_encode_map_header(ei_x_buff* x, int arity)</nametext></name>
<fsummary>Encode a map.</fsummary>
<desc>
<p>Encodes a map header, with a specified arity. The next
@@ -595,8 +659,8 @@ ei_x_encode_string(&amp;x, "Banana");</pre>
</func>
<func>
- <name><ret>int</ret><nametext>ei_encode_pid(char *buf, int *index, const erlang_pid *p)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_pid(ei_x_buff* x, const erlang_pid *p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_encode_pid(char *buf, int *index, const erlang_pid *p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_encode_pid(ei_x_buff* x, const erlang_pid *p)</nametext></name>
<fsummary>Encode a pid.</fsummary>
<desc>
<p>Encodes an Erlang process identifier (pid) in the binary
@@ -607,8 +671,8 @@ ei_x_encode_string(&amp;x, "Banana");</pre>
</func>
<func>
- <name><ret>int</ret><nametext>ei_encode_port(char *buf, int *index, const erlang_port *p)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_port(ei_x_buff* x, const erlang_port *p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_encode_port(char *buf, int *index, const erlang_port *p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_encode_port(ei_x_buff* x, const erlang_port *p)</nametext></name>
<fsummary>Encode a port.</fsummary>
<desc>
<p>Encodes an Erlang port in the binary format. Parameter
@@ -619,8 +683,8 @@ ei_x_encode_string(&amp;x, "Banana");</pre>
</func>
<func>
- <name><ret>int</ret><nametext>ei_encode_ref(char *buf, int *index, const erlang_ref *p)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_ref(ei_x_buff* x, const erlang_ref *p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_encode_ref(char *buf, int *index, const erlang_ref *p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_encode_ref(ei_x_buff* x, const erlang_ref *p)</nametext></name>
<fsummary>Encode a ref.</fsummary>
<desc>
<p>Encodes an Erlang reference in the binary format. Parameter
@@ -631,10 +695,10 @@ ei_x_encode_string(&amp;x, "Banana");</pre>
</func>
<func>
- <name><ret>int</ret><nametext>ei_encode_string(char *buf, int *index, const char *p)</nametext></name>
- <name><ret>int</ret><nametext>ei_encode_string_len(char *buf, int *index, const char *p, int len)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_string(ei_x_buff* x, const char *p)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_string_len(ei_x_buff* x, const char* s, int len)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_encode_string(char *buf, int *index, const char *p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_encode_string_len(char *buf, int *index, const char *p, int len)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_encode_string(ei_x_buff* x, const char *p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_encode_string_len(ei_x_buff* x, const char* s, int len)</nametext></name>
<fsummary>Encode a string.</fsummary>
<desc>
<p>Encodes a string in the binary format. (A string in Erlang
@@ -645,19 +709,23 @@ ei_x_encode_string(&amp;x, "Banana");</pre>
</func>
<func>
- <name><ret>int</ret><nametext>ei_encode_term(char *buf, int *index, void *t)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_term(ei_x_buff* x, void *t)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_encode_term(char *buf, int *index, void *t)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_encode_term(ei_x_buff* x, void *t)</nametext></name>
<fsummary>Encode an <c>erl_interface</c> term.</fsummary>
<desc>
<p>Encodes an <c>ETERM</c>, as obtained from
<c>erl_interface</c>. Parameter <c>t</c> is
actually an <c>ETERM</c> pointer. This function
does not free the <c>ETERM</c>.</p>
+ <note><p>These functions are deprecated as of OTP 22 and will be removed in
+ OTP 23 together with the old legacy <c>erl_interface</c> library
+ (functions with prefix <c>erl_</c>).</p>
+ </note>
</desc>
</func>
<func>
- <name><ret>int</ret><nametext>ei_encode_trace(char *buf, int *index, const erlang_trace *p)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_trace(ei_x_buff* x, const erlang_trace *p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_encode_trace(char *buf, int *index, const erlang_trace *p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_encode_trace(ei_x_buff* x, const erlang_trace *p)</nametext></name>
<fsummary>Encode a trace token.</fsummary>
<desc>
<p>Encodes an Erlang trace token in the binary format.
@@ -668,8 +736,8 @@ ei_x_encode_string(&amp;x, "Banana");</pre>
</func>
<func>
- <name><ret>int</ret><nametext>ei_encode_tuple_header(char *buf, int *index, int arity)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_tuple_header(ei_x_buff* x, int arity)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_encode_tuple_header(char *buf, int *index, int arity)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_encode_tuple_header(ei_x_buff* x, int arity)</nametext></name>
<fsummary>Encode a tuple.</fsummary>
<desc>
<p>Encodes a tuple header, with a specified
@@ -687,8 +755,8 @@ ei_encode_tuple_header(buf, &amp;i, 0);</pre>
</func>
<func>
- <name><ret>int</ret><nametext>ei_encode_ulong(char *buf, int *index, unsigned long p)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_ulong(ei_x_buff* x, unsigned long p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_encode_ulong(char *buf, int *index, unsigned long p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_encode_ulong(ei_x_buff* x, unsigned long p)</nametext></name>
<fsummary>Encode unsigned integer.</fsummary>
<desc>
<p>Encodes an unsigned long integer in the binary format.
@@ -698,8 +766,8 @@ ei_encode_tuple_header(buf, &amp;i, 0);</pre>
</func>
<func>
- <name><ret>int</ret><nametext>ei_encode_ulonglong(char *buf, int *index, unsigned long long p)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_ulonglong(ei_x_buff* x, unsigned long long p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_encode_ulonglong(char *buf, int *index, unsigned long long p)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_encode_ulonglong(ei_x_buff* x, unsigned long long p)</nametext></name>
<fsummary>Encode unsigned integer.</fsummary>
<desc>
<p>Encodes a GCC <c>unsigned long long</c> or Visual C++
@@ -709,8 +777,8 @@ ei_encode_tuple_header(buf, &amp;i, 0);</pre>
</func>
<func>
- <name><ret>int</ret><nametext>ei_encode_version(char *buf, int *index)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_encode_version(ei_x_buff* x)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_encode_version(char *buf, int *index)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_encode_version(ei_x_buff* x)</nametext></name>
<fsummary>Encode version.</fsummary>
<desc>
<p>Encodes a version magic number for the binary format. Must
@@ -719,22 +787,37 @@ ei_encode_tuple_header(buf, &amp;i, 0);</pre>
</func>
<func>
- <name><ret>int</ret><nametext>ei_get_type(const char *buf, const int *index, int *type, int *size)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_get_type(const char *buf, const int *index, int *type, int *size)</nametext></name>
<fsummary>Fetch the type and size of an encoded term.</fsummary>
<desc>
- <p>Returns the type in <c>type</c> and size in
- <c>size</c> of the encoded term. For strings and atoms,
+ <p>Returns the type in <c>*type</c> and size in
+ <c>*size</c> of the encoded term. For strings and atoms,
size is the number of characters <em>not</em> including the
- terminating <c>NULL</c>. For binaries, <c>size</c> is the number of
- bytes. For lists and tuples, <c>size</c> is the arity of
- the object. For other types, <c>size</c> is 0. In all
+ terminating <c>NULL</c>. For binaries and bitstrings, <c>*size</c> is
+ the number of bytes. For lists, tuples and maps, <c>*size</c> is the
+ arity of the object. For other types, <c>*size</c> is 0. In all
cases, <c>index</c> is left unchanged.</p>
</desc>
</func>
<func>
- <name><ret>int</ret><nametext>ei_print_term(FILE* fp, const char* buf, int* index)</nametext></name>
- <name><ret>int</ret><nametext>ei_s_print_term(char** s, const char* buf, int* index)</nametext></name>
+ <name since="OTP 21.3"><ret>int</ret><nametext>ei_init(void)</nametext></name>
+ <fsummary>Initialize the ei library.</fsummary>
+ <desc>
+ <p>Initialize the <c>ei</c> library. This function should be called once
+ (and only once) before calling any other functionality in the <c>ei</c>
+ library. However, note the exception below.</p>
+ <p>If the <c>ei</c> library is used together with the <c>erl_interface</c>
+ library, this function should <em>not</em> be called directly. It will be
+ called by the <c>erl_init()</c> function which should be used to initialize
+ the combination of the two libraries instead.</p>
+ <p>On success zero is returned. On failure a posix error code is returned.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since=""><ret>int</ret><nametext>ei_print_term(FILE* fp, const char* buf, int* index)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_s_print_term(char** s, const char* buf, int* index)</nametext></name>
<fsummary>Print a term in clear text.</fsummary>
<desc>
<p>Prints a term, in clear text, to the file
@@ -759,42 +842,60 @@ ei_encode_tuple_header(buf, &amp;i, 0);</pre>
</func>
<func>
- <name><ret>void</ret><nametext>ei_set_compat_rel(release_number)</nametext></name>
+ <name since=""><ret>void</ret><nametext>ei_set_compat_rel(release_number)</nametext></name>
<fsummary>Set the ei library in compatibility mode.</fsummary>
<type>
<v>unsigned release_number;</v>
</type>
<desc>
<marker id="ei_set_compat_rel"></marker>
- <p>By default, the <c>ei</c> library is only guaranteed
- to be compatible with other Erlang/OTP components from the same
- release as the <c>ei</c> library itself. For example,
- <c>ei</c> from
- Erlang/OTP R10 is not compatible with an Erlang emulator
- from Erlang/OTP R9 by default.</p>
- <p>A call to <c>ei_set_compat_rel(release_number)</c> sets
- the <c>ei</c> library in compatibility mode of release
- <c>release_number</c>. Valid range of
- <c>release_number</c>
- is <c>[7, current release]</c>. This makes it possible to
- communicate with Erlang/OTP components from earlier releases.</p>
+ <p>In general, the <c>ei</c> library is guaranteed
+ to be compatible with other Erlang/OTP components that are 2 major
+ releases older or newer than the <c>ei</c> library itself.</p>
+ <p>Sometimes an exception to the above rule has to be made to make new
+ features (or even bug fixes) possible. A call to
+ <c>ei_set_compat_rel(release_number)</c> sets
+ the <c>ei</c> library in compatibility mode of OTP release
+ <c>release_number</c>.</p>
+ <p>The only useful value for <c>release_number</c> is currently
+ <c>21</c>. This will only be useful and have an effect if <em>bit
+ strings</em> or <em>export funs</em> are received from a connected
+ node. Before OTP 22, bit strings and export funs were not supported by
+ <c>ei</c>. They were instead encoded using an undocumented fallback
+ tuple format when sent from the emulator to <c>ei</c>:</p>
+ <taglist>
+ <tag><c>Bit string</c></tag>
+ <item><p>The term <c>&lt;&lt;42, 1:1>></c> was encoded as
+ <c>{&lt;&lt;42, 128>>, 1}</c>. The first element of the tuple is a
+ binary and the second element denotes how many bits of the last bytes
+ are part of the bit string. In this example only the most significant
+ bit of the last byte (128) is part of the bit string.</p>
+ </item>
+ <tag><c>Export fun</c></tag>
+ <item><p>The term <c>fun lists:map/2</c> was encoded as
+ <c>{lists,map}</c>. A tuple with the module, function and a missing
+ arity.</p>
+ </item>
+ </taglist>
+ <p>If <c>ei_set_compat_rel(21)</c> is <em>not</em> called then a connected
+ emulator will send bit strings and export funs correctly encoded. The
+ functions <seealso marker="#ei_decode_bitstring"><c>ei_decode_bitstring</c></seealso>
+ and <seealso marker="#ei_decode_fun"><c>ei_decode_fun</c></seealso>
+ has to be used to decode such terms. Calling
+ <c>ei_set_compat_rel(21)</c> should only be done as a workaround to
+ keep an old implementation alive, which expects to receive the
+ undocumented tuple formats for bit strings and/or export funs.
+ </p>
<note>
<p>If this function is called, it can only be called once
and must be called before any other functions in the
<c>ei</c> library are called.</p>
</note>
- <warning>
- <p>You can run into trouble if this feature is used
- carelessly. Always ensure that all communicating
- components are either from the same Erlang/OTP release, or
- from release X and release Y where all components
- from release Y are in compatibility mode of release X.</p>
- </warning>
</desc>
</func>
<func>
- <name><ret>int</ret><nametext>ei_skip_term(const char* buf, int* index)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_skip_term(const char* buf, int* index)</nametext></name>
<fsummary>Skip a term.</fsummary>
<desc>
<p>Skips a term in the specified buffer;
@@ -815,8 +916,8 @@ ei_encode_tuple_header(buf, &amp;i, 0);</pre>
</func>
<func>
- <name><ret>int</ret><nametext>ei_x_append(ei_x_buff* x, const ei_x_buff* x2)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_append_buf(ei_x_buff* x, const char* buf, int len)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_append(ei_x_buff* x, const ei_x_buff* x2)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_append_buf(ei_x_buff* x, const char* buf, int len)</nametext></name>
<fsummary>Append a buffer at the end.</fsummary>
<desc>
<p>Appends data at the end of buffer <c>x</c>.</p>
@@ -824,8 +925,8 @@ ei_encode_tuple_header(buf, &amp;i, 0);</pre>
</func>
<func>
- <name><ret>int</ret><nametext>ei_x_format(ei_x_buff* x, const char* fmt, ...)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_format_wo_ver(ei_x_buff* x, const char *fmt, ... )</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_format(ei_x_buff* x, const char* fmt, ...)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_format_wo_ver(ei_x_buff* x, const char *fmt, ... )</nametext></name>
<fsummary>Format a term from a format string and parameters.</fsummary>
<desc>
<p>Formats a term, given as a string, to a buffer.
@@ -853,7 +954,7 @@ encodes the tuple {numbers,12,3.14159}</pre>
</func>
<func>
- <name><ret>int</ret><nametext>ei_x_free(ei_x_buff* x)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_free(ei_x_buff* x)</nametext></name>
<fsummary>Free a buffer.</fsummary>
<desc>
<p>Frees an <c>ei_x_buff</c> buffer.
@@ -862,8 +963,8 @@ encodes the tuple {numbers,12,3.14159}</pre>
</func>
<func>
- <name><ret>int</ret><nametext>ei_x_new(ei_x_buff* x)</nametext></name>
- <name><ret>int</ret><nametext>ei_x_new_with_version(ei_x_buff* x)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_new(ei_x_buff* x)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_x_new_with_version(ei_x_buff* x)</nametext></name>
<fsummary>Allocate a new buffer.</fsummary>
<desc>
<p>Allocates a new <c>ei_x_buff</c> buffer. The
diff --git a/lib/erl_interface/doc/src/ei_connect.xml b/lib/erl_interface/doc/src/ei_connect.xml
index 607a7cbff4..795f1249b3 100644
--- a/lib/erl_interface/doc/src/ei_connect.xml
+++ b/lib/erl_interface/doc/src/ei_connect.xml
@@ -34,6 +34,9 @@
<lib>ei_connect</lib>
<libsummary>Communicate with distributed Erlang.</libsummary>
<description>
+ <note><p>The support for VxWorks is deprecated as of OTP 22, and
+ will be removed in OTP 23.</p></note>
+
<p>This module enables C-programs to communicate with Erlang nodes,
using the Erlang distribution over TCP/IP.</p>
@@ -85,20 +88,288 @@
the <c>_tmo</c> suffix.</p>
</section>
+ <section>
+ <marker id="ussi"/>
+ <title>User Supplied Socket Implementation</title>
+ <p>By default <c>ei</c> supplies a TCP/IPv4 socket interface
+ that is used when communicating. The user can however plug in
+ his/her own IPv4 socket implementation. This, for example, in order
+ to communicate over TLS. A user supplied socket implementation
+ is plugged in by passing a
+ <seealso marker="#ei_socket_callbacks">callback structure</seealso>
+ to either
+ <seealso marker="#ei_connect_init"><c>ei_connect_init_ussi()</c></seealso>
+ or
+ <seealso marker="#ei_connect_init"><c>ei_connect_xinit_ussi()</c></seealso>.</p>
+
+ <p>All callbacks in the <c>ei_socket_callbacks</c> structure
+ <em>should</em> return zero on success; and a posix error
+ code on failure.</p>
+
+ <p>The <c>addr</c> argument of the <c>listen</c>, <c>accept</c>,
+ and <c>connect</c> callbacks refer to appropriate address
+ structure for currently used protocol. Currently <c>ei</c>
+ only supports IPv4. That is, at this time <c>addr</c> always
+ points to a <c>struct sockaddr_in</c> structure.</p>
+
+ <p>The <c>ei_socket_callbacks</c> structure may be enlarged in
+ the future. All fields not set, <em>needs</em> to be zeroed out.</p>
+
+ <marker id="ei_socket_callbacks"/>
+ <code type="none"><![CDATA[
+typedef struct {
+ int flags;
+ int (*socket)(void **ctx, void *setup_ctx);
+ int (*close)(void *ctx);
+ int (*listen)(void *ctx, void *addr, int *len, int backlog);
+ int (*accept)(void **ctx, void *addr, int *len, unsigned tmo);
+ int (*connect)(void *ctx, void *addr, int len, unsigned tmo);
+ int (*writev)(void *ctx, const void *iov, int iovcnt, ssize_t *len, unsigned tmo);
+ int (*write)(void *ctx, const char *buf, ssize_t *len, unsigned tmo);
+ int (*read)(void *ctx, char *buf, ssize_t *len, unsigned tmo);
+ int (*handshake_packet_header_size)(void *ctx, int *sz);
+ int (*connect_handshake_complete)(void *ctx);
+ int (*accept_handshake_complete)(void *ctx);
+ int (*get_fd)(void *ctx, int *fd);
+} ei_socket_callbacks;
+ ]]></code>
+
+ <taglist>
+
+ <tag><c>flags</c></tag>
+ <item>
+ <p>Flags informing <c>ei</c> about the behaviour of the
+ callbacks. Flags should be bitwise or:ed together. If no flag,
+ is set, the <c>flags</c> field should contain <c>0</c>. Currently,
+ supported flags:</p>
+ <taglist>
+ <tag><c>EI_SCLBK_FLG_FULL_IMPL</c></tag>
+ <item>
+ <p>
+ If set, the <c>accept()</c>, <c>connect()</c>,
+ <c>writev()</c>, <c>write()</c>, and <c>read()</c> callbacks
+ implements timeouts. The timeout is passed in the <c>tmo</c>
+ argument and is given in milli seconds. Note that the
+ <c>tmo</c> argument to these callbacks differ from the
+ timeout arguments in the <c>ei</c> API. Zero means a zero
+ timeout. That is, poll and timeout immediately unless the
+ operation is successful. <c>EI_SCLBK_INF_TMO</c>
+ (max <c>unsigned</c>) means infinite timeout. The file
+ descriptor is in blocking mode when a callback is called,
+ and it must be in blocking mode when the callback returns.
+ </p>
+ <p>
+ If not set, <c>ei</c> will implement the timeout using
+ <c>select()</c> in order to determine when to call the
+ callbacks and when to time out. The <c>tmo</c> arguments
+ of the <c>accept()</c>, <c>connect()</c>, <c>writev()</c>,
+ <c>write()</c>, and <c>read()</c> callbacks should be
+ ignored. The callbacks may be called in non-blocking mode.
+ The callbacks are not allowed to change between blocking
+ and non-blocking mode. In order for this to work,
+ <c>select()</c> needs to interact with the socket primitives
+ used the same way as it interacts with the ordinary socket
+ primitives. If this is not the case, the callbacks
+ <em>need</em> to implement timeouts and this flag should
+ be set.
+ </p>
+ </item>
+ </taglist>
+ <p>More flags may be introduced in the future.</p>
+ </item>
+
+ <tag><c>int (*socket)(void **ctx, void *setup_ctx)</c></tag>
+ <item>
+ <p>Create a socket and a context for the socket.</p>
+
+ <p>On success it should set <c>*ctx</c> to point to a context for
+ the created socket. This context will be passed to all other
+ socket callbacks. This function will be passed the same
+ <c>setup_context</c> as passed to the preceeding
+ <seealso marker="#ei_connect_init"><c>ei_connect_init_ussi()</c></seealso>
+ or
+ <seealso marker="#ei_connect_init"><c>ei_connect_xinit_ussi()</c></seealso>
+ call.</p>
+
+ <note><p>During the lifetime of a socket, the pointer <c>*ctx</c>
+ <em>has</em> to remain the same. That is, it cannot later be
+ relocated.</p></note>
+
+ <p>This callback is mandatory.</p>
+ </item>
+
+ <tag><c>int (*close)(void *ctx)</c></tag>
+ <item>
+ <p>Close the socket identified by <c>ctx</c> and destroy the context.</p>
+
+ <p>This callback is mandatory.</p>
+ </item>
+
+ <tag><c>int (*listen)(void *ctx, void *addr, int *len, int backlog)</c></tag>
+ <item>
+ <p>Bind the socket identified by <c>ctx</c> to a local interface
+ and then listen on it.</p>
+
+ <p>The <c>addr</c> and <c>len</c> arguments are both input and output
+ arguments. When called <c>addr</c> points to an address structure of
+ lenght <c>*len</c> containing information on how to bind the socket.
+ Uppon return this callback should have updated the structure referred
+ by <c>addr</c> with information on how the socket actually was bound.
+ <c>*len</c> should be updated to reflect the size of <c>*addr</c>
+ updated. <c>backlog</c> identifies the size of the backlog for the
+ listen socket.</p>
+
+ <p>This callback is mandatory.</p>
+ </item>
+
+ <tag><c>int (*accept)(void **ctx, void *addr, int *len, unsigned tmo)</c></tag>
+ <item>
+ <p>Accept connections on the listen socket identified by
+ <c>*ctx</c>.</p>
+
+ <p>When a connection is accepted, a new context for the accepted
+ connection should be created and <c>*ctx</c> should be updated
+ to point to the new context for the accepted connection. When
+ called <c>addr</c> points to an uninitialized address structure
+ of lenght <c>*len</c>. Uppon return this callback should have
+ updated this structure with information about the client address.
+ <c>*len</c> should be updated to reflect the size of <c>*addr</c>
+ updated.
+ </p>
+
+ <p>If the <c>EI_SCLBK_FLG_FULL_IMPL</c> flag has been set,
+ <c>tmo</c> contains timeout time in milliseconds.</p>
+
+ <note><p>During the lifetime of a socket, the pointer <c>*ctx</c>
+ <em>has</em> to remain the same. That is, it cannot later be
+ relocated.</p></note>
+
+ <p>This callback is mandatory.</p>
+ </item>
+
+ <tag><c>int (*connect)(void *ctx, void *addr, int len, unsigned tmo)</c></tag>
+ <item>
+ <p>Connect the socket identified by <c>ctx</c> to the address
+ identified by <c>addr</c>.</p>
+
+ <p>When called <c>addr</c> points to an address structure of
+ lenght <c>len</c> containing information on where to connect.</p>
+
+ <p>If the <c>EI_SCLBK_FLG_FULL_IMPL</c> flag has been set,
+ <c>tmo</c> contains timeout time in milliseconds.</p>
+
+ <p>This callback is mandatory.</p>
+ </item>
+
+ <tag><c>int (*writev)(void *ctx, const void *iov, long iovcnt, ssize_t *len, unsigned tmo)</c></tag>
+ <item>
+ <p>Write data on the connected socket identified by <c>ctx</c>.</p>
+
+ <p><c>iov</c> points to an array of <c>struct iovec</c> structures of
+ length <c>iovcnt</c> containing data to write to the socket. On success,
+ this callback should set <c>*len</c> to the amount of bytes successfully
+ written on the socket.</p>
+
+ <p>If the <c>EI_SCLBK_FLG_FULL_IMPL</c> flag has been set,
+ <c>tmo</c> contains timeout time in milliseconds.</p>
+
+ <p>This callback is optional. Set the <c>writev</c> field
+ in the the <c>ei_socket_callbacks</c> structure to <c>NULL</c> if not
+ implemented.</p>
+ </item>
+
+ <tag><c>int (*write)(void *ctx, const char *buf, ssize_t *len, unsigned tmo)</c></tag>
+ <item>
+ <p>Write data on the connected socket identified by <c>ctx</c>.</p>
+
+ <p>When called <c>buf</c> points to a buffer of length <c>*len</c>
+ containing the data to write on the socket. On success, this callback
+ should set <c>*len</c> to the amount of bytes successfully written on
+ the socket.</p>
+
+ <p>If the <c>EI_SCLBK_FLG_FULL_IMPL</c> flag has been set,
+ <c>tmo</c> contains timeout time in milliseconds.</p>
+
+ <p>This callback is mandatory.</p>
+ </item>
+
+ <tag><c>int (*read)(void *ctx, char *buf, ssize_t *len, unsigned tmo)</c></tag>
+ <item>
+ <p>Read data on the connected socket identified by <c>ctx</c>.</p>
+
+ <p><c>buf</c> points to a buffer of length <c>*len</c> where the
+ read data should be placed. On success, this callback should update
+ <c>*len</c> to the amount of bytes successfully read on the socket.</p>
+
+ <p>If the <c>EI_SCLBK_FLG_FULL_IMPL</c> flag has been set,
+ <c>tmo</c> contains timeout time in milliseconds.</p>
+
+ <p>This callback is mandatory.</p>
+ </item>
+
+ <tag><c>int (*handshake_packet_header_size)(void *ctx, int *sz)</c></tag>
+ <item>
+ <p>Inform about handshake packet header size to use during the Erlang
+ distribution handshake.</p>
+
+ <p>On success, <c>*sz</c> should be set to the handshake packet header
+ size to use. Valid values are <c>2</c> and <c>4</c>. Erlang TCP
+ distribution use a handshake packet size of <c>2</c> and Erlang TLS
+ distribution use a handshake packet size of <c>4</c>.</p>
+
+ <p>This callback is mandatory.</p>
+ </item>
+
+ <tag><c>int (*connect_handshake_complete)(void *ctx)</c></tag>
+ <item>
+ <p>Called when a locally started handshake has completed successfully.</p>
+
+ <p>This callback is optional. Set the <c>connect_handshake_complete</c> field
+ in the <c>ei_socket_callbacks</c> structure to <c>NULL</c> if not implemented.</p>
+ </item>
+
+ <tag><c>int (*accept_handshake_complete)(void *ctx)</c></tag>
+ <item>
+ <p>Called when a remotely started handshake has completed successfully.</p>
+
+ <p>This callback is optional. Set the <c>accept_handshake_complete</c> field in
+ the <c>ei_socket_callbacks</c> structure to <c>NULL</c> if not implemented.</p>
+ </item>
+
+ <tag><c>int (*get_fd)(void *ctx, int *fd)</c></tag>
+ <item>
+ <p>Inform about file descriptor used by the socket which is identified
+ by <c>ctx</c>.</p>
+
+ <note><p>During the lifetime of a socket, the file descriptor
+ <em>has</em> to remain the same. That is, repeated calls to this
+ callback with the same context <c>should</c> always report the same
+ file descriptor.</p>
+ <p>The file descriptor <em>has</em> to be a real file descriptor.
+ That is, no other operation should be able to get the same file
+ descriptor until it has been released by the <c>close()</c>
+ callback.</p>
+ </note>
+
+ <p>This callback is mandatory.</p>
+ </item>
+ </taglist>
+ </section>
<funcs>
<func>
- <name><ret>struct hostent</ret><nametext>*ei_gethostbyaddr(const char *addr, int len, int type)</nametext></name>
- <name><ret>struct hostent</ret><nametext>*ei_gethostbyaddr_r(const char *addr, int length, int type, struct hostent *hostp, char *buffer, int buflen, int *h_errnop)</nametext></name>
- <name><ret>struct hostent</ret><nametext>*ei_gethostbyname(const char *name)</nametext></name>
- <name><ret>struct hostent</ret><nametext>*ei_gethostbyname_r(const char *name, struct hostent *hostp, char *buffer, int buflen, int *h_errnop)</nametext></name>
+ <name since=""><ret>struct hostent *</ret><nametext>ei_gethostbyaddr(const char *addr, int len, int type)</nametext></name>
+ <name since=""><ret>struct hostent *</ret><nametext>ei_gethostbyaddr_r(const char *addr, int length, int type, struct hostent *hostp, char *buffer, int buflen, int *h_errnop)</nametext></name>
+ <name since=""><ret>struct hostent *</ret><nametext>ei_gethostbyname(const char *name)</nametext></name>
+ <name since=""><ret>struct hostent *</ret><nametext>ei_gethostbyname_r(const char *name, struct hostent *hostp, char *buffer, int buflen, int *h_errnop)</nametext></name>
<fsummary>Name lookup functions.</fsummary>
<desc>
<p>Convenience functions for some common name lookup functions.</p>
</desc>
</func>
+
<func>
- <name><ret>int</ret><nametext>ei_accept(ei_cnode *ec, int listensock, ErlConnect *conp)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_accept(ei_cnode *ec, int listensock, ErlConnect *conp)</nametext></name>
<fsummary>Accept a connection from another node.</fsummary>
<desc>
<p>Used by a server process to accept a
@@ -130,7 +401,7 @@ typedef struct {
</func>
<func>
- <name><ret>int</ret><nametext>ei_accept_tmo(ei_cnode *ec, int listensock, ErlConnect *conp, unsigned timeout_ms)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_accept_tmo(ei_cnode *ec, int listensock, ErlConnect *conp, unsigned timeout_ms)</nametext></name>
<fsummary>Accept a connection from another node with optional
time-out.</fsummary>
<desc>
@@ -141,8 +412,16 @@ typedef struct {
</func>
<func>
- <name><ret>int</ret><nametext>ei_connect(ei_cnode* ec, char *nodename)</nametext></name>
- <name><ret>int</ret><nametext>ei_xconnect(ei_cnode* ec, Erl_IpAddr adr, char *alivename)</nametext></name>
+ <name since="OTP 21.3"><ret>int</ret><nametext>ei_close_connection(int fd)</nametext></name>
+ <fsummary>Close a connection.</fsummary>
+ <desc>
+ <p>Closes a previously opened connection or listen socket.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since=""><ret>int</ret><nametext>ei_connect(ei_cnode* ec, char *nodename)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_xconnect(ei_cnode* ec, Erl_IpAddr adr, char *alivename)</nametext></name>
<fsummary>Establish a connection to an Erlang node.</fsummary>
<desc>
<p>Sets up a connection to an Erlang node.</p>
@@ -192,8 +471,10 @@ fd = ei_xconnect(&ec, &addr, ALIVE);
</func>
<func>
- <name><ret>int</ret><nametext>ei_connect_init(ei_cnode* ec, const char* this_node_name, const char *cookie, short creation)</nametext></name>
- <name><ret>int</ret><nametext>ei_connect_xinit(ei_cnode* ec, const char *thishostname, const char *thisalivename, const char *thisnodename, Erl_IpAddr thisipaddr, const char *cookie, short creation)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_connect_init(ei_cnode* ec, const char* this_node_name, const char *cookie, short creation)</nametext></name>
+ <name since="OTP 21.3"><ret>int</ret><nametext>ei_connect_init_ussi(ei_cnode* ec, const char* this_node_name, const char *cookie, short creation, ei_socket_callbacks *cbs, int cbs_sz, void *setup_context)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_connect_xinit(ei_cnode* ec, const char *thishostname, const char *thisalivename, const char *thisnodename, Erl_IpAddr thisipaddr, const char *cookie, short creation)</nametext></name>
+ <name since="OTP 21.3"><ret>int</ret><nametext>ei_connect_xinit_ussi(ei_cnode* ec, const char *thishostname, const char *thisalivename, const char *thisnodename, Erl_IpAddr thisipaddr, const char *cookie, short creation, ei_socket_callbacks *cbs, int cbs_sz, void *setup_context)</nametext></name>
<fsummary>Initialize for a connection.</fsummary>
<desc>
<p>Initializes the <c>ec</c> structure, to
@@ -236,6 +517,21 @@ fd = ei_xconnect(&ec, &addr, ALIVE);
<item>
<p><c>thispaddr</c> if the IP address of the host.</p>
</item>
+ <item>
+ <p><c>cbs</c> is a pointer to a
+ <seealso marker="#ei_socket_callbacks">callback structure</seealso>
+ implementing and alternative socket interface.</p>
+ </item>
+ <item>
+ <p><c>cbs_sz</c> is the size of the structure
+ pointed to by <c>cbs</c>.</p>
+ </item>
+ <item>
+ <p><c>setup_context</c> is a pointer to a structure that
+ will be passed as second argument to the <c>socket</c> callback
+ in the <c>cbs</c> structure.</p>
+ </item>
+
</list>
<p>A C-node acting as a server is assigned a creation
number when it calls <c>ei_publish()</c>.</p>
@@ -273,8 +569,8 @@ if (ei_connect_init(&ec, "madonna", "cookie...", n++) < 0) {
</func>
<func>
- <name><ret>int</ret><nametext>ei_connect_tmo(ei_cnode* ec, char *nodename, unsigned timeout_ms)</nametext></name>
- <name><ret>int</ret><nametext>ei_xconnect_tmo(ei_cnode* ec, Erl_IpAddr adr, char *alivename, unsigned timeout_ms)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_connect_tmo(ei_cnode* ec, char *nodename, unsigned timeout_ms)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_xconnect_tmo(ei_cnode* ec, Erl_IpAddr adr, char *alivename, unsigned timeout_ms)</nametext></name>
<fsummary>Establish a connection to an Erlang node with optional
time-out.</fsummary>
<desc>
@@ -286,8 +582,8 @@ if (ei_connect_init(&ec, "madonna", "cookie...", n++) < 0) {
</func>
<func>
- <name><ret>int</ret><nametext>ei_get_tracelevel(void)</nametext></name>
- <name><ret>void</ret><nametext>ei_set_tracelevel(int level)</nametext></name>
+ <name since="OTP R13B04"><ret>int</ret><nametext>ei_get_tracelevel(void)</nametext></name>
+ <name since="OTP R13B04"><ret>void</ret><nametext>ei_set_tracelevel(int level)</nametext></name>
<fsummary>Get and set functions for tracing.</fsummary>
<desc>
<p>Used to set tracing on the distribution. The levels are different
@@ -299,7 +595,46 @@ if (ei_connect_init(&ec, "madonna", "cookie...", n++) < 0) {
</func>
<func>
- <name><ret>int</ret><nametext>ei_publish(ei_cnode *ec, int port)</nametext></name>
+ <name since="OTP 21.3"><ret>int</ret><nametext>ei_listen(ei_cnode *ec, int *port, int backlog)</nametext></name>
+ <name since="OTP 21.3"><ret>int</ret><nametext>ei_xlisten(ei_cnode *ec, Erl_IpAddr adr, int *port, int backlog)</nametext></name>
+ <fsummary>Create a listen socket.</fsummary>
+ <desc>
+ <p>Used by a server process to setup a listen socket which
+ later can be used for accepting connections from client processes.
+ </p>
+ <list type="bulleted">
+ <item>
+ <p><c>ec</c> is the C-node structure.</p>
+ </item>
+ <item>
+ <p><c>adr</c> is local interface to bind to.</p>
+ </item>
+ <item>
+ <p><c>port</c> is a pointer to an integer containing the
+ port number to bind to. If <c>*port</c> equals <c>0</c>
+ when calling <c>ei_listen()</c>, the socket will be bound to
+ an ephemeral port. On success, <c>ei_listen()</c> will update
+ the value of <c>*port</c> to the port actually bound to.
+ </p>
+ </item>
+ <item>
+ <p><c>backlog</c> is maximum backlog of pending connections.</p>
+ </item>
+ </list>
+ <p><c>ei_listen</c> will create a socket, bind to a port on the
+ local interface identified by <c>adr</c> (or all local interfaces if
+ <c>ei_listen()</c> is called), and mark the socket as a passive socket
+ (that is, a socket that will be used for accepting incoming connections).
+ </p>
+ <p>
+ On success, a file descriptor is returned which can be used in a call to
+ <c>ei_accept()</c>. On failure, <c>ERL_ERROR</c> is returned and
+ <c>erl_errno</c> is set to <c>EIO</c>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since=""><ret>int</ret><nametext>ei_publish(ei_cnode *ec, int port)</nametext></name>
<fsummary>Publish a node name.</fsummary>
<desc>
<p>Used by a server process to register
@@ -336,7 +671,7 @@ if (ei_connect_init(&ec, "madonna", "cookie...", n++) < 0) {
</func>
<func>
- <name><ret>int</ret><nametext>ei_publish_tmo(ei_cnode *ec, int port, unsigned timeout_ms)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_publish_tmo(ei_cnode *ec, int port, unsigned timeout_ms)</nametext></name>
<fsummary>Publish a node name with optional time-out.</fsummary>
<desc>
<p>Equivalent to
@@ -346,7 +681,7 @@ if (ei_connect_init(&ec, "madonna", "cookie...", n++) < 0) {
</func>
<func>
- <name><ret>int</ret><nametext>ei_receive(int fd, unsigned char* bufp, int bufsize)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_receive(int fd, unsigned char* bufp, int bufsize)</nametext></name>
<fsummary>Receive a message.</fsummary>
<desc>
<p>Receives a message consisting of a sequence
@@ -387,7 +722,7 @@ if (ei_connect_init(&ec, "madonna", "cookie...", n++) < 0) {
</func>
<func>
- <name><ret>int</ret><nametext>ei_receive_encoded(int fd, char **mbufp, int *bufsz, erlang_msg *msg, int *msglen)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_receive_encoded(int fd, char **mbufp, int *bufsz, erlang_msg *msg, int *msglen)</nametext></name>
<fsummary>Obsolete function for receiving a message.</fsummary>
<desc>
<p>This function is retained for compatibility with code
@@ -417,7 +752,7 @@ if (ei_connect_init(&ec, "madonna", "cookie...", n++) < 0) {
</func>
<func>
- <name><ret>int</ret><nametext>ei_receive_encoded_tmo(int fd, char **mbufp, int *bufsz, erlang_msg *msg, int *msglen, unsigned timeout_ms)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_receive_encoded_tmo(int fd, char **mbufp, int *bufsz, erlang_msg *msg, int *msglen, unsigned timeout_ms)</nametext></name>
<fsummary>Obsolete function for receiving a message with time-out.
</fsummary>
<desc>
@@ -428,8 +763,8 @@ if (ei_connect_init(&ec, "madonna", "cookie...", n++) < 0) {
</func>
<func>
- <name><ret>int</ret><nametext>ei_receive_msg(int fd, erlang_msg* msg, ei_x_buff* x)</nametext></name>
- <name><ret>int</ret><nametext>ei_xreceive_msg(int fd, erlang_msg* msg, ei_x_buff* x)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_receive_msg(int fd, erlang_msg* msg, ei_x_buff* x)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_xreceive_msg(int fd, erlang_msg* msg, ei_x_buff* x)</nametext></name>
<fsummary>Receive a message.</fsummary>
<desc>
<p>Receives a message to the buffer in <c>x</c>.
@@ -493,8 +828,8 @@ typedef struct {
</func>
<func>
- <name><ret>int</ret><nametext>ei_receive_msg_tmo(int fd, erlang_msg* msg, ei_x_buff* x, unsigned imeout_ms)</nametext></name>
- <name><ret>int</ret><nametext>ei_xreceive_msg_tmo(int fd, erlang_msg* msg, ei_x_buff* x, unsigned timeout_ms)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_receive_msg_tmo(int fd, erlang_msg* msg, ei_x_buff* x, unsigned imeout_ms)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_xreceive_msg_tmo(int fd, erlang_msg* msg, ei_x_buff* x, unsigned timeout_ms)</nametext></name>
<fsummary>Receive a message with optional time-out.</fsummary>
<desc>
<p>Equivalent to <c>ei_receive_msg</c> and <c>ei_xreceive_msg</c>
@@ -504,7 +839,7 @@ typedef struct {
</func>
<func>
- <name><ret>int</ret><nametext>ei_receive_tmo(int fd, unsigned char* bufp, int bufsize, unsigned timeout_ms)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_receive_tmo(int fd, unsigned char* bufp, int bufsize, unsigned timeout_ms)</nametext></name>
<fsummary>Receive a message with optional time-out.</fsummary>
<desc>
<p>Equivalent to
@@ -514,7 +849,7 @@ typedef struct {
</func>
<func>
- <name><ret>int</ret><nametext>ei_reg_send(ei_cnode* ec, int fd, char* server_name, char* buf, int len)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_reg_send(ei_cnode* ec, int fd, char* server_name, char* buf, int len)</nametext></name>
<fsummary>Send a message to a registered name.</fsummary>
<desc>
<p>Sends an Erlang term to a registered process.</p>
@@ -546,7 +881,7 @@ if (ei_reg_send(&ec, fd, x.buff, x.index) < 0)
</func>
<func>
- <name><ret>int</ret><nametext>ei_reg_send_tmo(ei_cnode* ec, int fd, char* server_name, char* buf, int len, unsigned timeout_ms)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_reg_send_tmo(ei_cnode* ec, int fd, char* server_name, char* buf, int len, unsigned timeout_ms)</nametext></name>
<fsummary>Send a message to a registered name with optional time-out
</fsummary>
<desc>
@@ -557,9 +892,9 @@ if (ei_reg_send(&ec, fd, x.buff, x.index) < 0)
</func>
<func>
- <name><ret>int</ret><nametext>ei_rpc(ei_cnode *ec, int fd, char *mod, char *fun, const char *argbuf, int argbuflen, ei_x_buff *x)</nametext></name>
- <name><ret>int</ret><nametext>ei_rpc_to(ei_cnode *ec, int fd, char *mod, char *fun, const char *argbuf, int argbuflen)</nametext></name>
- <name><ret>int</ret><nametext>ei_rpc_from(ei_cnode *ec, int fd, int timeout, erlang_msg *msg, ei_x_buff *x)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_rpc(ei_cnode *ec, int fd, char *mod, char *fun, const char *argbuf, int argbuflen, ei_x_buff *x)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_rpc_to(ei_cnode *ec, int fd, char *mod, char *fun, const char *argbuf, int argbuflen)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_rpc_from(ei_cnode *ec, int fd, int timeout, erlang_msg *msg, ei_x_buff *x)</nametext></name>
<fsummary>Remote Procedure Call from C to Erlang.</fsummary>
<desc>
<p>Supports calling Erlang functions on remote nodes.
@@ -658,7 +993,7 @@ if (ei_decode_version(result.buff, &index) < 0
</func>
<func>
- <name><ret>erlang_pid *</ret><nametext>ei_self(ei_cnode *ec)</nametext></name>
+ <name since=""><ret>erlang_pid *</ret><nametext>ei_self(ei_cnode *ec)</nametext></name>
<fsummary>Retrieve the pid of the C-node.</fsummary>
<desc>
<p>Retrieves the pid of the C-node. Every C-node
@@ -671,7 +1006,7 @@ if (ei_decode_version(result.buff, &index) < 0
</func>
<func>
- <name><ret>int</ret><nametext>ei_send(int fd, erlang_pid* to, char* buf, int len)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_send(int fd, erlang_pid* to, char* buf, int len)</nametext></name>
<fsummary>Send a message.</fsummary>
<desc>
<p>Sends an Erlang term to a process.</p>
@@ -692,7 +1027,7 @@ if (ei_decode_version(result.buff, &index) < 0
</func>
<func>
- <name><ret>int</ret><nametext>ei_send_encoded(int fd, erlang_pid* to, char* buf, int len)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_send_encoded(int fd, erlang_pid* to, char* buf, int len)</nametext></name>
<fsummary>Obsolete function to send a message.</fsummary>
<desc>
<p>Works exactly as <c>ei_send</c>, the alternative name is retained for
@@ -702,7 +1037,7 @@ if (ei_decode_version(result.buff, &index) < 0
</func>
<func>
- <name><ret>int</ret><nametext>ei_send_encoded_tmo(int fd, erlang_pid* to, char* buf, int len, unsigned timeout_ms)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_send_encoded_tmo(int fd, erlang_pid* to, char* buf, int len, unsigned timeout_ms)</nametext></name>
<fsummary>Obsolete function to send a message with optional time-out.
</fsummary>
<desc>
@@ -713,7 +1048,7 @@ if (ei_decode_version(result.buff, &index) < 0
</func>
<func>
- <name><ret>int</ret><nametext>ei_send_reg_encoded(int fd, const erlang_pid *from, const char *to, const char *buf, int len)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_send_reg_encoded(int fd, const erlang_pid *from, const char *to, const char *buf, int len)</nametext></name>
<fsummary>Obsolete function to send a message to a registered name.
</fsummary>
<desc>
@@ -741,7 +1076,7 @@ self->num = fd;
</func>
<func>
- <name><ret>int</ret><nametext>ei_send_reg_encoded_tmo(int fd, const erlang_pid *from, const char *to, const char *buf, int len)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_send_reg_encoded_tmo(int fd, const erlang_pid *from, const char *to, const char *buf, int len)</nametext></name>
<fsummary>Obsolete function to send a message to a registered name with
time-out.</fsummary>
<desc>
@@ -752,7 +1087,7 @@ self->num = fd;
</func>
<func>
- <name><ret>int</ret><nametext>ei_send_tmo(int fd, erlang_pid* to, char* buf, int len, unsigned timeout_ms)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_send_tmo(int fd, erlang_pid* to, char* buf, int len, unsigned timeout_ms)</nametext></name>
<fsummary>Send a message with optional time-out.</fsummary>
<desc>
<p>Equivalent to
@@ -762,9 +1097,9 @@ self->num = fd;
</func>
<func>
- <name><ret>const char *</ret><nametext>ei_thisnodename(ei_cnode *ec)</nametext></name>
- <name><ret>const char *</ret><nametext>ei_thishostname(ei_cnode *ec)</nametext></name>
- <name><ret>const char *</ret><nametext>ei_thisalivename(ei_cnode *ec)</nametext></name>
+ <name since=""><ret>const char *</ret><nametext>ei_thisnodename(ei_cnode *ec)</nametext></name>
+ <name since=""><ret>const char *</ret><nametext>ei_thishostname(ei_cnode *ec)</nametext></name>
+ <name since=""><ret>const char *</ret><nametext>ei_thisalivename(ei_cnode *ec)</nametext></name>
<fsummary>Retrieve some values.</fsummary>
<desc>
<p>Can be used to retrieve information about
@@ -779,7 +1114,7 @@ self->num = fd;
</func>
<func>
- <name><ret>int</ret><nametext>ei_unpublish(ei_cnode *ec)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_unpublish(ei_cnode *ec)</nametext></name>
<fsummary>Forcefully unpublish a node name.</fsummary>
<desc>
<p>Can be called by a process to unregister a
@@ -802,7 +1137,7 @@ self->num = fd;
</func>
<func>
- <name><ret>int</ret><nametext>ei_unpublish_tmo(ei_cnode *ec, unsigned timeout_ms)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_unpublish_tmo(ei_cnode *ec, unsigned timeout_ms)</nametext></name>
<fsummary>Unpublish a node name with optional time-out.</fsummary>
<desc>
<p>Equivalent to
diff --git a/lib/erl_interface/doc/src/ei_users_guide.xml b/lib/erl_interface/doc/src/ei_users_guide.xml
index 0eed50b50b..7ca10d1a99 100644
--- a/lib/erl_interface/doc/src/ei_users_guide.xml
+++ b/lib/erl_interface/doc/src/ei_users_guide.xml
@@ -34,6 +34,18 @@
</header>
<section>
+ <title>Deprecation and Removal</title>
+ <note><p>The support for VxWorks is deprecated as of OTP 22, and
+ will be removed in OTP 23.</p></note>
+ <note><p>The old legacy <c>erl_interface</c> library (functions
+ with prefix <c>erl_</c>) is deprecated as of OTP 22, and will be
+ removed in OTP 23. This does not apply to the <c>ei</c>
+ library. Reasonably new <c>gcc</c> compilers will issue deprecation
+ warnings. In order to disable these warnings, define the macro
+ <c>EI_NO_DEPR_WARN</c>.</p></note>
+ </section>
+
+ <section>
<title>Introduction</title>
<p>The <c>Erl_Interface</c> library contains functions that help you
integrate programs written in C and Erlang. The functions in
@@ -162,12 +174,20 @@ $ ld -L/usr/local/otp/lib/erl_interface-3.2.3/
</section>
<section>
- <title>Initializing the Erl_Interface Library</title>
- <p>Before calling any of the other <c>Erl_Interface</c> functions, call
- <c>erl_init()</c> exactly once to initialize the library.
+ <title>Initializing the Libraries</title>
+ <p>
+ Before calling any of the other functions in the <c>erl_interface</c>
+ and <c>ei</c> libraries, call <c>erl_init()</c> exactly once to initialize
+ both libraries.
<c>erl_init()</c> takes two arguments. However, the arguments
- are no longer used by <c>Erl_Interface</c> and are therefore to be
- specified as <c>erl_init(NULL,0)</c>.</p>
+ are no longer used by <c>erl_interface</c> and are therefore to be
+ specified as <c>erl_init(NULL,0)</c>.
+ </p>
+ <p>
+ If you only use the <c>ei</c> library, instead initialize it by calling
+ <c>ei_init()</c> exactly once before calling any other functions in
+ the <c>ei</c> library.
+ </p>
</section>
<section>
diff --git a/lib/erl_interface/doc/src/erl_connect.xml b/lib/erl_interface/doc/src/erl_connect.xml
index 76ef6588c2..9492a82864 100644
--- a/lib/erl_interface/doc/src/erl_connect.xml
+++ b/lib/erl_interface/doc/src/erl_connect.xml
@@ -35,6 +35,15 @@
<lib>erl_connect</lib>
<libsummary>Communicate with distributed Erlang.</libsummary>
<description>
+ <note><p>The support for VxWorks is deprecated as of OTP 22, and
+ will be removed in OTP 23.</p></note>
+ <note><p>The old legacy <c>erl_interface</c> library (functions
+ with prefix <c>erl_</c>) is deprecated as of OTP 22, and will be
+ removed in OTP 23. This does not apply to the <c>ei</c>
+ library. Reasonably new <c>gcc</c> compilers will issue deprecation
+ warnings. In order to disable these warnings, define the macro
+ <c>EI_NO_DEPR_WARN</c>.</p></note>
+
<p>This module provides support for communication between distributed
Erlang nodes and C-nodes, in a manner that is transparent to Erlang
processes.</p>
@@ -49,7 +58,7 @@
<funcs>
<func>
- <name><ret>int</ret><nametext>erl_accept(listensock, conp)</nametext></name>
+ <name since=""><ret>int</ret><nametext>erl_accept(listensock, conp)</nametext></name>
<fsummary>Accept a connection.</fsummary>
<type>
<v>int listensock;</v>
@@ -78,7 +87,7 @@ typedef struct {
</func>
<func>
- <name><ret>int</ret><nametext>erl_close_connection(fd)</nametext></name>
+ <name since=""><ret>int</ret><nametext>erl_close_connection(fd)</nametext></name>
<fsummary>Close a connection to an Erlang node.</fsummary>
<type>
<v>int fd;</v>
@@ -95,8 +104,8 @@ typedef struct {
</func>
<func>
- <name><ret>int</ret><nametext>erl_connect(node)</nametext></name>
- <name><ret>int</ret><nametext>erl_xconnect(addr, alive)</nametext></name>
+ <name since=""><ret>int</ret><nametext>erl_connect(node)</nametext></name>
+ <name since=""><ret>int</ret><nametext>erl_xconnect(addr, alive)</nametext></name>
<fsummary>Establish a connection to an Erlang node.</fsummary>
<type>
<v>char *node, *alive;</v>
@@ -149,8 +158,8 @@ erl_xconnect( &addr , ALIVE );
</func>
<func>
- <name><ret>int</ret><nametext>erl_connect_init(number, cookie, creation)</nametext></name>
- <name><ret>int</ret><nametext>erl_connect_xinit(host, alive, node, addr, cookie, creation)</nametext></name>
+ <name since=""><ret>int</ret><nametext>erl_connect_init(number, cookie, creation)</nametext></name>
+ <name since=""><ret>int</ret><nametext>erl_connect_xinit(host, alive, node, addr, cookie, creation)</nametext></name>
<fsummary>Initialize communication.</fsummary>
<type>
<v>int number;</v>
@@ -246,7 +255,7 @@ if (!erl_connect_init(17, "samplecookiestring...", 0))
</func>
<func>
- <name><ret>int</ret><nametext>erl_publish(port)</nametext></name>
+ <name since=""><ret>int</ret><nametext>erl_publish(port)</nametext></name>
<fsummary>Publish a node name.</fsummary>
<type>
<v>int port;</v>
@@ -277,7 +286,7 @@ if (!erl_connect_init(17, "samplecookiestring...", 0))
</func>
<func>
- <name><ret>int</ret><nametext>erl_receive(fd, bufp, bufsize)</nametext></name>
+ <name since=""><ret>int</ret><nametext>erl_receive(fd, bufp, bufsize)</nametext></name>
<fsummary>Receive a message.</fsummary>
<type>
<v>int fd;</v>
@@ -316,7 +325,7 @@ if (!erl_connect_init(17, "samplecookiestring...", 0))
</func>
<func>
- <name><ret>int</ret><nametext>erl_receive_msg(fd, bufp, bufsize, emsg)</nametext></name>
+ <name since=""><ret>int</ret><nametext>erl_receive_msg(fd, bufp, bufsize, emsg)</nametext></name>
<fsummary>Receive and decode a message.</fsummary>
<type>
<v>int fd;</v>
@@ -411,7 +420,7 @@ typedef struct {
</func>
<func>
- <name><ret>int</ret><nametext>erl_reg_send(fd, to, msg)</nametext></name>
+ <name since=""><ret>int</ret><nametext>erl_reg_send(fd, to, msg)</nametext></name>
<fsummary>Send a message to a registered name.</fsummary>
<type>
<v>int fd;</v>
@@ -439,9 +448,9 @@ typedef struct {
</func>
<func>
- <name><ret>ETERM *</ret><nametext>erl_rpc(fd, mod, fun, args)</nametext></name>
- <name><ret>int</ret><nametext>erl_rpc_from(fd, timeout, emsg)</nametext></name>
- <name><ret>int</ret><nametext>erl_rpc_to(fd, mod, fun, args)</nametext></name>
+ <name since=""><ret>ETERM *</ret><nametext>erl_rpc(fd, mod, fun, args)</nametext></name>
+ <name since=""><ret>int</ret><nametext>erl_rpc_from(fd, timeout, emsg)</nametext></name>
+ <name since=""><ret>int</ret><nametext>erl_rpc_to(fd, mod, fun, args)</nametext></name>
<fsummary>Remote Procedure Call.</fsummary>
<type>
<v>int fd, timeout;</v>
@@ -511,7 +520,7 @@ typedef struct {
</func>
<func>
- <name><ret>int</ret><nametext>erl_send(fd, to, msg)</nametext></name>
+ <name since=""><ret>int</ret><nametext>erl_send(fd, to, msg)</nametext></name>
<fsummary>Send a message.</fsummary>
<type>
<v>int fd;</v>
@@ -541,11 +550,11 @@ typedef struct {
</func>
<func>
- <name><ret>const char *</ret><nametext>erl_thisalivename()</nametext></name>
- <name><ret>const char *</ret><nametext>erl_thiscookie()</nametext></name>
- <name><ret>short</ret><nametext>erl_thiscreation()</nametext></name>
- <name><ret>const char *</ret><nametext>erl_thishostname()</nametext></name>
- <name><ret>const char *</ret><nametext>erl_thisnodename()</nametext></name>
+ <name since=""><ret>const char *</ret><nametext>erl_thisalivename()</nametext></name>
+ <name since=""><ret>const char *</ret><nametext>erl_thiscookie()</nametext></name>
+ <name since=""><ret>short</ret><nametext>erl_thiscreation()</nametext></name>
+ <name since=""><ret>const char *</ret><nametext>erl_thishostname()</nametext></name>
+ <name since=""><ret>const char *</ret><nametext>erl_thisnodename()</nametext></name>
<fsummary>Retrieve some values.</fsummary>
<desc>
<p>Retrieves information about
@@ -556,7 +565,7 @@ typedef struct {
</func>
<func>
- <name><ret>int</ret><nametext>erl_unpublish(alive)</nametext></name>
+ <name since=""><ret>int</ret><nametext>erl_unpublish(alive)</nametext></name>
<fsummary>Forcefully unpublish a node name.</fsummary>
<type>
<v>char *alive;</v>
@@ -583,7 +592,7 @@ typedef struct {
</func>
<func>
- <name><ret>int</ret><nametext>erl_xreceive_msg(fd, bufpp, bufsizep, emsg)</nametext></name>
+ <name since=""><ret>int</ret><nametext>erl_xreceive_msg(fd, bufpp, bufsizep, emsg)</nametext></name>
<fsummary>Receive and decode a message.</fsummary>
<type>
<v>int fd;</v>
@@ -616,10 +625,10 @@ typedef struct {
</func>
<func>
- <name><ret>struct hostent</ret><nametext>*erl_gethostbyaddr(addr, length, type)</nametext></name>
- <name><ret>struct hostent</ret><nametext>*erl_gethostbyaddr_r(addr, length, type, hostp, buffer, buflen, h_errnop)</nametext></name>
- <name><ret>struct hostent</ret><nametext>*erl_gethostbyname(name)</nametext></name>
- <name><ret>struct hostent</ret><nametext>*erl_gethostbyname_r(name, hostp, buffer, buflen, h_errnop)</nametext></name>
+ <name since=""><ret>struct hostent *</ret><nametext>erl_gethostbyaddr(addr, length, type)</nametext></name>
+ <name since=""><ret>struct hostent *</ret><nametext>erl_gethostbyaddr_r(addr, length, type, hostp, buffer, buflen, h_errnop)</nametext></name>
+ <name since=""><ret>struct hostent *</ret><nametext>erl_gethostbyname(name)</nametext></name>
+ <name since=""><ret>struct hostent *</ret><nametext>erl_gethostbyname_r(name, hostp, buffer, buflen, h_errnop)</nametext></name>
<fsummary>Name lookup functions.</fsummary>
<type>
diff --git a/lib/erl_interface/doc/src/erl_error.xml b/lib/erl_interface/doc/src/erl_error.xml
index 8139c9b343..6fac94e442 100644
--- a/lib/erl_interface/doc/src/erl_error.xml
+++ b/lib/erl_interface/doc/src/erl_error.xml
@@ -47,7 +47,7 @@
<funcs>
<func>
- <name><ret>void</ret><nametext>erl_err_msg(FormatStr, ... )</nametext></name>
+ <name since=""><ret>void</ret><nametext>erl_err_msg(FormatStr, ... )</nametext></name>
<fsummary>Non-fatal error, and not system call error.</fsummary>
<type>
<v>const char *FormatStr;</v>
@@ -59,7 +59,7 @@
</func>
<func>
- <name><ret>void</ret><nametext>erl_err_quit(FormatStr, ... )</nametext></name>
+ <name since=""><ret>void</ret><nametext>erl_err_quit(FormatStr, ... )</nametext></name>
<fsummary>Fatal error, but not system call error.</fsummary>
<type>
<v>const char *FormatStr;</v>
@@ -73,7 +73,7 @@
</func>
<func>
- <name><ret>void</ret><nametext>erl_err_ret(FormatStr, ... )</nametext></name>
+ <name since=""><ret>void</ret><nametext>erl_err_ret(FormatStr, ... )</nametext></name>
<fsummary>Non-fatal system call error.</fsummary>
<type>
<v>const char *FormatStr;</v>
@@ -86,7 +86,7 @@
</func>
<func>
- <name><ret>void</ret><nametext>erl_err_sys(FormatStr, ... )</nametext></name>
+ <name since=""><ret>void</ret><nametext>erl_err_sys(FormatStr, ... )</nametext></name>
<fsummary>Fatal system call error.</fsummary>
<type>
<v>const char *FormatStr;</v>
@@ -113,7 +113,7 @@
<funcs>
<func>
- <name><ret>volatile int</ret><nametext>erl_errno</nametext></name>
+ <name since=""><ret>volatile int</ret><nametext>erl_errno</nametext></name>
<fsummary>Variable <c>erl_errno</c> contains the
Erl_Interface error number. You can change the value if you wish.
</fsummary>
diff --git a/lib/erl_interface/doc/src/erl_eterm.xml b/lib/erl_interface/doc/src/erl_eterm.xml
index 9a05196a70..295760b4e6 100644
--- a/lib/erl_interface/doc/src/erl_eterm.xml
+++ b/lib/erl_interface/doc/src/erl_eterm.xml
@@ -35,6 +35,15 @@
<lib>erl_eterm</lib>
<libsummary>Functions for Erlang term construction.</libsummary>
<description>
+ <note><p>The support for VxWorks is deprecated as of OTP 22, and
+ will be removed in OTP 23.</p></note>
+ <note><p>The old legacy <c>erl_interface</c> library (functions
+ with prefix <c>erl_</c>) is deprecated as of OTP 22, and will be
+ removed in OTP 23. This does not apply to the <c>ei</c>
+ library. Reasonably new <c>gcc</c> compilers will issue deprecation
+ warnings. In order to disable these warnings, define the macro
+ <c>EI_NO_DEPR_WARN</c>.</p></note>
+
<p>This module provides functions for creating and manipulating
Erlang terms.</p>
@@ -142,7 +151,7 @@
<funcs>
<func>
- <name><ret>ETERM *</ret><nametext>erl_cons(head, tail)</nametext></name>
+ <name since=""><ret>ETERM *</ret><nametext>erl_cons(head, tail)</nametext></name>
<fsummary>Prepend a term to the head of a list.</fsummary>
<type>
<v>ETERM *head;</v>
@@ -181,7 +190,7 @@ erl_free_compound(list);
</func>
<func>
- <name><ret>ETERM *</ret><nametext>erl_copy_term(term)</nametext></name>
+ <name since=""><ret>ETERM *</ret><nametext>erl_copy_term(term)</nametext></name>
<fsummary>Create a copy of an Erlang term.</fsummary>
<type>
<v>ETERM *term;</v>
@@ -193,7 +202,7 @@ erl_free_compound(list);
</func>
<func>
- <name><ret>ETERM *</ret><nametext>erl_element(position, tuple)</nametext></name>
+ <name since=""><ret>ETERM *</ret><nametext>erl_element(position, tuple)</nametext></name>
<fsummary>Extract an element from an Erlang tuple.</fsummary>
<type>
<v>int position;</v>
@@ -215,7 +224,7 @@ erl_free_compound(list);
</func>
<func>
- <name><ret>ETERM *</ret><nametext>erl_hd(list)</nametext></name>
+ <name since=""><ret>ETERM *</ret><nametext>erl_hd(list)</nametext></name>
<fsummary>Extract the first element from a list.</fsummary>
<type>
<v>ETERM *list;</v>
@@ -230,7 +239,7 @@ erl_free_compound(list);
</func>
<func>
- <name><ret>void</ret><nametext>erl_init(NULL, 0)</nametext></name>
+ <name since=""><ret>void</ret><nametext>erl_init(NULL, 0)</nametext></name>
<fsummary>Initialization routine.</fsummary>
<type>
<v>void *NULL;</v>
@@ -245,7 +254,7 @@ erl_free_compound(list);
</func>
<func>
- <name><ret>int</ret><nametext>erl_iolist_length(list)</nametext></name>
+ <name since=""><ret>int</ret><nametext>erl_iolist_length(list)</nametext></name>
<fsummary>Return the length of an I/O list.</fsummary>
<type>
<v>ETERM *list;</v>
@@ -262,7 +271,7 @@ erl_free_compound(list);
</func>
<func>
- <name><ret>ETERM *</ret><nametext>erl_iolist_to_binary(term)</nametext></name>
+ <name since=""><ret>ETERM *</ret><nametext>erl_iolist_to_binary(term)</nametext></name>
<fsummary>Convert an I/O list to a binary.</fsummary>
<type>
<v>ETERM *list;</v>
@@ -289,7 +298,7 @@ iohead ::= Binary
</func>
<func>
- <name><ret>char *</ret><nametext>erl_iolist_to_string(list)</nametext></name>
+ <name since=""><ret>char *</ret><nametext>erl_iolist_to_string(list)</nametext></name>
<fsummary>Convert an I/O list to a <c>NULL</c>-terminated string.</fsummary>
<type>
<v>ETERM *list;</v>
@@ -312,7 +321,7 @@ iohead ::= Binary
</func>
<func>
- <name><ret>int</ret><nametext>erl_length(list)</nametext></name>
+ <name since=""><ret>int</ret><nametext>erl_length(list)</nametext></name>
<fsummary>Determine the length of a list.</fsummary>
<type>
<v>ETERM *list;</v>
@@ -328,7 +337,7 @@ iohead ::= Binary
</func>
<func>
- <name><ret>ETERM *</ret><nametext>erl_mk_atom(string)</nametext></name>
+ <name since=""><ret>ETERM *</ret><nametext>erl_mk_atom(string)</nametext></name>
<fsummary>Create an atom.</fsummary>
<type>
<v>const char *string;</v>
@@ -355,7 +364,7 @@ iohead ::= Binary
</func>
<func>
- <name><ret>ETERM *</ret><nametext>erl_mk_binary(bptr, size)</nametext></name>
+ <name since=""><ret>ETERM *</ret><nametext>erl_mk_binary(bptr, size)</nametext></name>
<fsummary>Create a binary object.</fsummary>
<type>
<v>char *bptr;</v>
@@ -378,7 +387,7 @@ iohead ::= Binary
</func>
<func>
- <name><ret>ETERM *</ret><nametext>erl_mk_empty_list()</nametext></name>
+ <name since=""><ret>ETERM *</ret><nametext>erl_mk_empty_list()</nametext></name>
<fsummary>Create an empty Erlang list.</fsummary>
<desc>
<p>Creates and returns an empty Erlang list.
@@ -388,7 +397,7 @@ iohead ::= Binary
</func>
<func>
- <name><ret>ETERM *</ret><nametext>erl_mk_estring(string, len)</nametext></name>
+ <name since=""><ret>ETERM *</ret><nametext>erl_mk_estring(string, len)</nametext></name>
<fsummary>Create an Erlang string.</fsummary>
<type>
<v>char *string;</v>
@@ -408,7 +417,7 @@ iohead ::= Binary
</func>
<func>
- <name><ret>ETERM *</ret><nametext>erl_mk_float(f)</nametext></name>
+ <name since=""><ret>ETERM *</ret><nametext>erl_mk_float(f)</nametext></name>
<fsummary>Create an Erlang float.</fsummary>
<type>
<v>double f;</v>
@@ -426,7 +435,7 @@ iohead ::= Binary
</func>
<func>
- <name><ret>ETERM *</ret><nametext>erl_mk_int(n)</nametext></name>
+ <name since=""><ret>ETERM *</ret><nametext>erl_mk_int(n)</nametext></name>
<fsummary>Create an Erlang integer.</fsummary>
<type>
<v>int n;</v>
@@ -443,7 +452,7 @@ iohead ::= Binary
</func>
<func>
- <name><ret>ETERM *</ret><nametext>erl_mk_list(array, arrsize)</nametext></name>
+ <name since=""><ret>ETERM *</ret><nametext>erl_mk_list(array, arrsize)</nametext></name>
<fsummary>Create a list from an array.</fsummary>
<type>
<v>ETERM **array;</v>
@@ -465,7 +474,7 @@ iohead ::= Binary
</func>
<func>
- <name><ret>ETERM *</ret><nametext>erl_mk_long_ref(node, n1, n2, n3, creation)</nametext></name>
+ <name since=""><ret>ETERM *</ret><nametext>erl_mk_long_ref(node, n1, n2, n3, creation)</nametext></name>
<fsummary>Create an Erlang reference.</fsummary>
<type>
<v>const char *node;</v>
@@ -495,7 +504,7 @@ iohead ::= Binary
</func>
<func>
- <name><ret>ETERM *</ret><nametext>erl_mk_pid(node, number, serial, creation)</nametext></name>
+ <name since=""><ret>ETERM *</ret><nametext>erl_mk_pid(node, number, serial, creation)</nametext></name>
<fsummary>Create a process identifier.</fsummary>
<type>
<v>const char *node;</v>
@@ -525,7 +534,7 @@ iohead ::= Binary
</func>
<func>
- <name><ret>ETERM *</ret><nametext>erl_mk_port(node, number, creation)</nametext></name>
+ <name since=""><ret>ETERM *</ret><nametext>erl_mk_port(node, number, creation)</nametext></name>
<fsummary>Create a port identifier.</fsummary>
<type>
<v>const char *node;</v>
@@ -550,7 +559,7 @@ iohead ::= Binary
</func>
<func>
- <name><ret>ETERM *</ret><nametext>erl_mk_ref(node, number, creation)</nametext></name>
+ <name since=""><ret>ETERM *</ret><nametext>erl_mk_ref(node, number, creation)</nametext></name>
<fsummary>Create an old Erlang reference.</fsummary>
<type>
<v>const char *node;</v>
@@ -578,7 +587,7 @@ iohead ::= Binary
</func>
<func>
- <name><ret>ETERM *</ret><nametext>erl_mk_string(string)</nametext></name>
+ <name since=""><ret>ETERM *</ret><nametext>erl_mk_string(string)</nametext></name>
<fsummary>Create a string.</fsummary>
<type>
<v>char *string;</v>
@@ -593,7 +602,7 @@ iohead ::= Binary
</func>
<func>
- <name><ret>ETERM *</ret><nametext>erl_mk_tuple(array, arrsize)</nametext></name>
+ <name since=""><ret>ETERM *</ret><nametext>erl_mk_tuple(array, arrsize)</nametext></name>
<fsummary>Create an Erlang tuple from an array.</fsummary>
<type>
<v>ETERM **array;</v>
@@ -621,7 +630,7 @@ iohead ::= Binary
</func>
<func>
- <name><ret>ETERM *</ret><nametext>erl_mk_uint(n)</nametext></name>
+ <name since=""><ret>ETERM *</ret><nametext>erl_mk_uint(n)</nametext></name>
<fsummary>Create an unsigned integer.</fsummary>
<type>
<v>unsigned int n;</v>
@@ -638,7 +647,7 @@ iohead ::= Binary
</func>
<func>
- <name><ret>ETERM *</ret><nametext>erl_mk_var(name)</nametext></name>
+ <name since=""><ret>ETERM *</ret><nametext>erl_mk_var(name)</nametext></name>
<fsummary>Create an Erlang variable.</fsummary>
<type>
<v>char *name;</v>
@@ -653,7 +662,7 @@ iohead ::= Binary
</func>
<func>
- <name><ret>int</ret><nametext>erl_print_term(stream, term)</nametext></name>
+ <name since=""><ret>int</ret><nametext>erl_print_term(stream, term)</nametext></name>
<fsummary>Print an Erlang term.</fsummary>
<type>
<v>FILE *stream;</v>
@@ -672,7 +681,7 @@ iohead ::= Binary
</func>
<func>
- <name><ret>void</ret><nametext>erl_set_compat_rel(release_number)</nametext></name>
+ <name since=""><ret>void</ret><nametext>erl_set_compat_rel(release_number)</nametext></name>
<fsummary>Set the Erl_Interface library in compatibility mode.</fsummary>
<type>
<v>unsigned release_number;</v>
@@ -706,7 +715,7 @@ iohead ::= Binary
</func>
<func>
- <name><ret>int</ret><nametext>erl_size(term)</nametext></name>
+ <name since=""><ret>int</ret><nametext>erl_size(term)</nametext></name>
<fsummary>Return the arity of a tuple or binary.</fsummary>
<type>
<v>ETERM *term;</v>
@@ -723,7 +732,7 @@ iohead ::= Binary
</func>
<func>
- <name><ret>ETERM *</ret><nametext>erl_tl(list)</nametext></name>
+ <name since=""><ret>ETERM *</ret><nametext>erl_tl(list)</nametext></name>
<fsummary>Extract the tail from a list.</fsummary>
<type>
<v>ETERM *list;</v>
@@ -738,7 +747,7 @@ iohead ::= Binary
</func>
<func>
- <name><ret>ETERM *</ret><nametext>erl_var_content(term, name)</nametext></name>
+ <name since=""><ret>ETERM *</ret><nametext>erl_var_content(term, name)</nametext></name>
<fsummary>Extract the content of a variable.</fsummary>
<type>
<v>ETERM *term;</v>
diff --git a/lib/erl_interface/doc/src/erl_format.xml b/lib/erl_interface/doc/src/erl_format.xml
index 5b8b7b5e78..b5e895c720 100644
--- a/lib/erl_interface/doc/src/erl_format.xml
+++ b/lib/erl_interface/doc/src/erl_format.xml
@@ -41,7 +41,7 @@
<funcs>
<func>
- <name><ret>ETERM *</ret><nametext>erl_format(FormatStr, ...)</nametext></name>
+ <name since=""><ret>ETERM *</ret><nametext>erl_format(FormatStr, ...)</nametext></name>
<fsummary>Create an Erlang term.</fsummary>
<type>
<v>char *FormatStr;</v>
@@ -81,7 +81,7 @@ erl_format("[{name,~a},{age,~i},{data,~w}]",
</func>
<func>
- <name><ret>int</ret><nametext>erl_match(Pattern, Term)</nametext></name>
+ <name since=""><ret>int</ret><nametext>erl_match(Pattern, Term)</nametext></name>
<fsummary>Perform pattern matching.</fsummary>
<type>
<v>ETERM *Pattern,*Term;</v>
diff --git a/lib/erl_interface/doc/src/erl_global.xml b/lib/erl_interface/doc/src/erl_global.xml
index 2fa0045adf..39085b46f0 100644
--- a/lib/erl_interface/doc/src/erl_global.xml
+++ b/lib/erl_interface/doc/src/erl_global.xml
@@ -35,6 +35,15 @@
<lib>erl_global</lib>
<libsummary>Access globally registered names.</libsummary>
<description>
+ <note><p>The support for VxWorks is deprecated as of OTP 22, and
+ will be removed in OTP 23.</p></note>
+ <note><p>The old legacy <c>erl_interface</c> library (functions
+ with prefix <c>erl_</c>) is deprecated as of OTP 22, and will be
+ removed in OTP 23. This does not apply to the <c>ei</c>
+ library. Reasonably new <c>gcc</c> compilers will issue deprecation
+ warnings. In order to disable these warnings, define the macro
+ <c>EI_NO_DEPR_WARN</c>.</p></note>
+
<p>This module provides support for registering, looking
up, and unregistering names in the <c>global</c> module.
For more information, see
@@ -48,7 +57,7 @@
<funcs>
<func>
- <name><ret>char **</ret><nametext>erl_global_names(fd,count)</nametext></name>
+ <name since=""><ret>char **</ret><nametext>erl_global_names(fd,count)</nametext></name>
<fsummary>Obtain list of global names.</fsummary>
<type>
<v>int fd;</v>
@@ -79,7 +88,7 @@
</func>
<func>
- <name><ret>int</ret><nametext>erl_global_register(fd,name,pid)</nametext></name>
+ <name since=""><ret>int</ret><nametext>erl_global_register(fd,name,pid)</nametext></name>
<fsummary>Register a name in global.</fsummary>
<type>
<v>int fd;</v>
@@ -103,7 +112,7 @@
</func>
<func>
- <name><ret>int</ret><nametext>erl_global_unregister(fd,name)</nametext></name>
+ <name since=""><ret>int</ret><nametext>erl_global_unregister(fd,name)</nametext></name>
<fsummary>Unregister a name from global.</fsummary>
<type>
<v>int fd;</v>
@@ -122,7 +131,7 @@
</func>
<func>
- <name><ret>ETERM *</ret><nametext>erl_global_whereis(fd,name,node)</nametext></name>
+ <name since=""><ret>ETERM *</ret><nametext>erl_global_whereis(fd,name,node)</nametext></name>
<fsummary>Look up a name in global.</fsummary>
<type>
<v>int fd;</v>
diff --git a/lib/erl_interface/doc/src/erl_interface.xml b/lib/erl_interface/doc/src/erl_interface.xml
index 4e66655b39..decd66046a 100644
--- a/lib/erl_interface/doc/src/erl_interface.xml
+++ b/lib/erl_interface/doc/src/erl_interface.xml
@@ -58,6 +58,18 @@
</list>
<section>
+ <title>Deprecation and Removal</title>
+ <note><p>The support for VxWorks is deprecated as of OTP 22, and
+ will be removed in OTP 23.</p></note>
+ <note><p>The old legacy <c>erl_interface</c> library (functions
+ with prefix <c>erl_</c>) is deprecated as of OTP 22, and will be
+ removed in OTP 23. This does not apply to the <c>ei</c>
+ library. Reasonably new <c>gcc</c> compilers will issue deprecation
+ warnings. In order to disable these warnings, define the macro
+ <c>EI_NO_DEPR_WARN</c>.</p></note>
+ </section>
+
+ <section>
<title>Compiling and Linking Your Code</title>
<p>In order to use any of the Erl_Interface functions, include the
following lines in your code:</p>
diff --git a/lib/erl_interface/doc/src/erl_malloc.xml b/lib/erl_interface/doc/src/erl_malloc.xml
index c0eebc29e9..6650620064 100644
--- a/lib/erl_interface/doc/src/erl_malloc.xml
+++ b/lib/erl_interface/doc/src/erl_malloc.xml
@@ -35,13 +35,21 @@
<lib>erl_malloc</lib>
<libsummary>Memory allocation functions.</libsummary>
<description>
+ <note><p>The support for VxWorks is deprecated as of OTP 22, and
+ will be removed in OTP 23.</p></note>
+ <note><p>The old legacy <c>erl_interface</c> library (functions
+ with prefix <c>erl_</c>) is deprecated as of OTP 22, and will be
+ removed in OTP 23. This does not apply to the <c>ei</c>
+ library. Reasonably new <c>gcc</c> compilers will issue deprecation
+ warnings. In order to disable these warnings, define the macro
+ <c>EI_NO_DEPR_WARN</c>.</p></note>
<p>This module provides functions for allocating and deallocating
memory.</p>
</description>
<funcs>
<func>
- <name><ret>ETERM *</ret><nametext>erl_alloc_eterm(etype)</nametext></name>
+ <name since=""><ret>ETERM *</ret><nametext>erl_alloc_eterm(etype)</nametext></name>
<fsummary>Allocate an ETERM structure.</fsummary>
<type>
<v>unsigned char etype;</v>
@@ -89,7 +97,7 @@
</func>
<func>
- <name><ret>void</ret><nametext>erl_eterm_release(void)</nametext></name>
+ <name since=""><ret>void</ret><nametext>erl_eterm_release(void)</nametext></name>
<fsummary>Clear the ETERM freelist.</fsummary>
<desc>
<p>Clears the freelist, where blocks are placed when they are
@@ -99,7 +107,7 @@
</func>
<func>
- <name><ret>void</ret><nametext>erl_eterm_statistics(allocated, freed)</nametext></name>
+ <name since=""><ret>void</ret><nametext>erl_eterm_statistics(allocated, freed)</nametext></name>
<fsummary>Report term allocation statistics.</fsummary>
<type>
<v>long *allocated;</v>
@@ -127,7 +135,7 @@
</func>
<func>
- <name><ret>void</ret><nametext>erl_free(ptr)</nametext></name>
+ <name since=""><ret>void</ret><nametext>erl_free(ptr)</nametext></name>
<fsummary>Free some memory.</fsummary>
<type>
<v>void *ptr;</v>
@@ -139,7 +147,7 @@
</func>
<func>
- <name><ret>void</ret><nametext>erl_free_array(array, size)</nametext></name>
+ <name since=""><ret>void</ret><nametext>erl_free_array(array, size)</nametext></name>
<fsummary>Free an array of ETERM structures.</fsummary>
<type>
<v>ETERM **array;</v>
@@ -156,7 +164,7 @@
</func>
<func>
- <name><ret>void</ret><nametext>erl_free_compound(t)</nametext></name>
+ <name since=""><ret>void</ret><nametext>erl_free_compound(t)</nametext></name>
<fsummary>Free an array of ETERM structures.</fsummary>
<type>
<v>ETERM *t;</v>
@@ -179,7 +187,7 @@
</func>
<func>
- <name><ret>void</ret><nametext>erl_free_term(t)</nametext></name>
+ <name since=""><ret>void</ret><nametext>erl_free_term(t)</nametext></name>
<fsummary>Free an ETERM structure.</fsummary>
<type>
<v>ETERM *t;</v>
@@ -190,7 +198,7 @@
</func>
<func>
- <name><ret>void</ret><nametext>erl_malloc(size)</nametext></name>
+ <name since=""><ret>void</ret><nametext>erl_malloc(size)</nametext></name>
<fsummary>Allocate some memory.</fsummary>
<type>
<v>long size;</v>
diff --git a/lib/erl_interface/doc/src/erl_marshal.xml b/lib/erl_interface/doc/src/erl_marshal.xml
index 2ad658f78b..33d359d871 100644
--- a/lib/erl_interface/doc/src/erl_marshal.xml
+++ b/lib/erl_interface/doc/src/erl_marshal.xml
@@ -35,6 +35,14 @@
<lib>erl_marshal</lib>
<libsummary>Encoding and decoding of Erlang terms.</libsummary>
<description>
+ <note><p>The support for VxWorks is deprecated as of OTP 22, and
+ will be removed in OTP 23.</p></note>
+ <note><p>The old legacy <c>erl_interface</c> library (functions
+ with prefix <c>erl_</c>) is deprecated as of OTP 22, and will be
+ removed in OTP 23. This does not apply to the <c>ei</c>
+ library. Reasonably new <c>gcc</c> compilers will issue deprecation
+ warnings. In order to disable these warnings, define the macro
+ <c>EI_NO_DEPR_WARN</c>.</p></note>
<p>This module contains functions for encoding Erlang terms into
a sequence of bytes, and for decoding Erlang terms from a
sequence of bytes.</p>
@@ -42,7 +50,7 @@
<funcs>
<func>
- <name><ret>int</ret><nametext>erl_compare_ext(bufp1, bufp2)</nametext></name>
+ <name since=""><ret>int</ret><nametext>erl_compare_ext(bufp1, bufp2)</nametext></name>
<fsummary>Compare encoded byte sequences.</fsummary>
<type>
<v>unsigned char *bufp1,*bufp2;</v>
@@ -62,8 +70,8 @@
</func>
<func>
- <name><ret>ETERM *</ret><nametext>erl_decode(bufp)</nametext></name>
- <name><ret>ETERM *</ret><nametext>erl_decode_buf(bufpp)</nametext></name>
+ <name since=""><ret>ETERM *</ret><nametext>erl_decode(bufp)</nametext></name>
+ <name since=""><ret>ETERM *</ret><nametext>erl_decode_buf(bufpp)</nametext></name>
<fsummary>Convert a term from Erlang external format.</fsummary>
<type>
<v>unsigned char *bufp;</v>
@@ -102,8 +110,8 @@
</func>
<func>
- <name><ret>int</ret><nametext>erl_encode(term, bufp)</nametext></name>
- <name><ret>int</ret><nametext>erl_encode_buf(term, bufpp)</nametext></name>
+ <name since=""><ret>int</ret><nametext>erl_encode(term, bufp)</nametext></name>
+ <name since=""><ret>int</ret><nametext>erl_encode_buf(term, bufpp)</nametext></name>
<fsummary>Convert a term into Erlang external format.</fsummary>
<type>
<v>ETERM *term;</v>
@@ -179,7 +187,7 @@
</func>
<func>
- <name><ret>int</ret><nametext>erl_ext_size(bufp)</nametext></name>
+ <name since=""><ret>int</ret><nametext>erl_ext_size(bufp)</nametext></name>
<fsummary>Count elements in encoded term.</fsummary>
<type>
<v>unsigned char *bufp;</v>
@@ -190,7 +198,7 @@
</func>
<func>
- <name><ret>unsigned char</ret><nametext>erl_ext_type(bufp)</nametext></name>
+ <name since=""><ret>unsigned char</ret><nametext>erl_ext_type(bufp)</nametext></name>
<fsummary>Determine type of an encoded byte sequence.</fsummary>
<type>
<v>unsigned char *bufp;</v>
@@ -228,7 +236,7 @@
</func>
<func>
- <name><ret>unsigned char *</ret><nametext>erl_peek_ext(bufp, pos)</nametext></name>
+ <name since=""><ret>unsigned char *</ret><nametext>erl_peek_ext(bufp, pos)</nametext></name>
<fsummary>Step over encoded term.</fsummary>
<type>
<v>unsigned char *bufp;</v>
@@ -252,7 +260,7 @@
</func>
<func>
- <name><ret>int</ret><nametext>erl_term_len(t)</nametext></name>
+ <name since=""><ret>int</ret><nametext>erl_term_len(t)</nametext></name>
<fsummary>Determine encoded size of term.</fsummary>
<type>
<v>ETERM *t;</v>
diff --git a/lib/erl_interface/doc/src/notes.xml b/lib/erl_interface/doc/src/notes.xml
index 641a3de13f..c47f0d2bd1 100644
--- a/lib/erl_interface/doc/src/notes.xml
+++ b/lib/erl_interface/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,6 +31,343 @@
</header>
<p>This document describes the changes made to the Erl_interface application.</p>
+<section><title>Erl_Interface 3.12</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The vxworks configure has been updated to respect the
+ environment CFLAGS.</p>
+ <p>
+ Own Id: OTP-15773</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Minor adjustments made to build system for parallel
+ configure.</p>
+ <p>
+ Own Id: OTP-15340 Aux Id: OTP-14625 </p>
+ </item>
+ <item>
+ <p>
+ The limited support for VxWorks is deprecated as of OTP
+ 22, and will be removed in OTP 23.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15621</p>
+ </item>
+ <item>
+ <p>The old legacy <c>erl_interface</c> library (functions
+ with prefix <c>erl_</c>) is deprecated as of OTP 22, and
+ will be removed in OTP 23. This does not apply to the
+ <c>ei</c> library. Reasonably new <c>gcc</c> compilers
+ will issue deprecation warnings. In order to disable
+ these warnings, define the macro
+ <c>EI_NO_DEPR_WARN</c>.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15622</p>
+ </item>
+ <item>
+ <p>Added support to receive, decode, encode and send both
+ bit strings and export funs (<c>fun M:F/A</c>).</p>
+ <p>New functions <c>ei_decode_bitstring</c> and
+ <c>ei_encode_bitstring</c> have been added in order to
+ decode and encode bit strings where the number of bits is
+ not necessary divisible by 8 (a whole number of bytes).
+ The existing functions <c>ei_decode_fun</c> and
+ <c>ei_encode_fun</c> can now also handle export funs.</p>
+ <p>Before this change, bit strings and export funs sent
+ to an erl_interface c-node were encoded using an
+ undocumented fallback tuple format. For bit strings
+ <c>{Binary,BitsInLastByte}</c> and for export funs
+ <c>{M,F}</c>. Existing c-node implementations expecting
+ these tuples must be changed to instead use
+ <c>ei_decode_bitstring</c> and <c>ei_decode_fun</c>. As a
+ temporary solution you can also build erl_interface with
+ macro <c>EI_COMPAT=21</c> or call
+ <c>ei_set_compat_rel(21)</c> to receive the old fallback
+ tuples.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15712 Aux Id: OTP-15774 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Interface 3.11.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ <c>erl_interface</c>/<c>ei</c> refused to use node names
+ with an alive name (the part of the node name preceding
+ the @ sign) longer than 63 characters and a host name
+ longer than 64 characters. The total amount of characters
+ allowed in a node name (alivename@hostname) was thus
+ limited to 128 characters. These limits applied both to
+ the own node name as well as node names of other nodes.
+ Ordinary Erlang nodes limit the node name length to 256
+ characters, which meant that you could not communicate
+ with certain Erlang nodes due to their node name used.</p>
+ <p>
+ <c>erl_interface</c>/<c>ei</c> now allow the total amount
+ of characters in a node name to be up to 256 characters.
+ These characters may be distributed between alive name
+ and host name in whatever way needed. That is, the
+ maximum amount of characters in the alive name may be 254
+ and the maximum amount of characters in the host name may
+ be 254, but in total the node name must not exceed 256
+ characters.</p>
+ <p>
+ Own Id: OTP-15781 Aux Id: ERIERL-356 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Interface 3.11.2.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ <c>erl_interface</c>/<c>ei</c> refused to use node names
+ with an alive name (the part of the node name preceding
+ the @ sign) longer than 63 characters and a host name
+ longer than 64 characters. The total amount of characters
+ allowed in a node name (alivename@hostname) was thus
+ limited to 128 characters. These limits applied both to
+ the own node name as well as node names of other nodes.
+ Ordinary Erlang nodes limit the node name length to 256
+ characters, which meant that you could not communicate
+ with certain Erlang nodes due to their node name used.</p>
+ <p>
+ <c>erl_interface</c>/<c>ei</c> now allow the total amount
+ of characters in a node name to be up to 256 characters.
+ These characters may be distributed between alive name
+ and host name in whatever way needed. That is, the
+ maximum amount of characters in the alive name may be 254
+ and the maximum amount of characters in the host name may
+ be 254, but in total the node name must not exceed 256
+ characters.</p>
+ <p>
+ Own Id: OTP-15781 Aux Id: ERIERL-356 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Interface 3.11.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix handling of Makefile dependencies so that parallel
+ make works properly.</p>
+ <p>
+ Own Id: OTP-15757</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Interface 3.11.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed two bugs in the <c>erl_call</c> program. A missing
+ initialization (introduced in <c>erl_interface-3.11</c>)
+ which either caused a crash or failure to connect to or
+ start a node, and an incorrectly calculated timeout which
+ could cause failure to start an erlang node. These bugs
+ only caused failures on some platforms.</p>
+ <p>
+ Own Id: OTP-15676 Aux Id: OTP-15442, ERL-881 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Interface 3.11</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Support for plugin of a <seealso
+ marker="ei_connect#ussi">user supplied socket
+ implementation</seealso> has been added.</p>
+ <p>
+ Own Id: OTP-15442 Aux Id: ERIERL-258 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Interface 3.10.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Make <c>ei_connect</c> and friends also accept state
+ <c>ok_simultaneous</c> during handshake, which means the
+ other node has initiated a connection setup that will be
+ cancelled in favor of this connection.</p>
+ <p>
+ Own Id: OTP-15161 Aux Id: ERIERL-191 </p>
+ </item>
+ <item>
+ <p>
+ Fixed bug in <c>ei_receive_msg</c>,
+ <c>ei_xreceive_msg</c>, <c>ei_receive_msg_tmo</c> and
+ <c>ei_xreceive_msg_tmo</c>. The <c>x-&gt;index</c> was
+ set to entire buffer size instead of the number of bytes
+ actually received.</p>
+ <p>
+ Own Id: OTP-15171</p>
+ </item>
+ <item>
+ <p>
+ Fixed bug in <c>ei_connect_init</c> which could be
+ provoked if called by concurrent threads.
+ <c>ei_connect_init</c> called posix interface
+ <c>gethostbyname</c> which is documented as not thread
+ safe.</p>
+ <p>
+ Own Id: OTP-15191</p>
+ </item>
+ <item>
+ <p>
+ Fixed bug in erl_compare_ext() ignoring the tail of lists
+ of otherwise equal content. Example: <c>[a | b]</c> and
+ <c>[a | c]</c> compared equal and <c>{[a], b}</c> and
+ <c>{[a], c}</c> compared equal.</p>
+ <p>
+ Own Id: OTP-15277 Aux Id: PR-1929 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Interface 3.10.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix bug where calling erl_init on certain platforms could
+ result in a buffer overflow bug.</p>
+ <p>
+ Own Id: OTP-15033</p>
+ </item>
+ <item>
+ <p>
+ Fixed <c>erl_call -m</c> to not deallocate module source
+ binary before it has been read.</p>
+ <p>
+ Own Id: OTP-15105 Aux Id: ERL-629 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> The program <c>erl_call</c> calls
+ <c>erl_eval:eval_str/1</c> when it used to call
+ <c>lib:eval_str/1</c>. This means that <c>erl_call</c>
+ will fail when trying interact with an Erlang node
+ running Erlang/OTP 20 or earlier. </p>
+ <p>
+ Own Id: OTP-15114 Aux Id: OTP-15072, ERL-634 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Interface 3.10.2.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix handling of Makefile dependencies so that parallel
+ make works properly.</p>
+ <p>
+ Own Id: OTP-15757</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Interface 3.10.2.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Make <c>ei_connect</c> and friends also accept state
+ <c>ok_simultaneous</c> during handshake, which means the
+ other node has initiated a connection setup that will be
+ cancelled in favor of this connection.</p>
+ <p>
+ Own Id: OTP-15161 Aux Id: ERIERL-191 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Interface 3.10.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix bug in <c>ei_connect</c> functions that may cause
+ failure due to insufficient buffer space for
+ gethostbyname_r.</p>
+ <p>
+ Own Id: OTP-15022 Aux Id: ERIERL-163 </p>
+ </item>
+ <item>
+ <p>
+ Optimize encoding/decoding for pure 7-bit ascii atoms.</p>
+ <p>
+ Own Id: OTP-15023 Aux Id: ERIERL-150 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erl_Interface 3.10.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -1440,4 +1777,3 @@
</section>
</section>
</chapter>
-
diff --git a/lib/erl_interface/doc/src/ref_man.xml b/lib/erl_interface/doc/src/ref_man.xml
index 1e20637cb7..a4f947c79f 100644
--- a/lib/erl_interface/doc/src/ref_man.xml
+++ b/lib/erl_interface/doc/src/ref_man.xml
@@ -29,6 +29,14 @@
<file>ref_man.xml</file>
</header>
<description>
+ <note><p>The support for VxWorks is deprecated as of OTP 22, and
+ will be removed in OTP 23.</p></note>
+ <note><p>The old legacy <c>erl_interface</c> library (functions
+ with prefix <c>erl_</c>) is deprecated as of OTP 22, and will be
+ removed in OTP 23. This does not apply to the <c>ei</c>
+ library. Reasonably new <c>gcc</c> compilers will issue deprecation
+ warnings. In order to disable these warnings, define the macro
+ <c>EI_NO_DEPR_WARN</c>.</p></note>
</description>
<xi:include href="ei.xml"/>
<xi:include href="ei_connect.xml"/>
diff --git a/lib/erl_interface/doc/src/ref_man_ei.xml b/lib/erl_interface/doc/src/ref_man_ei.xml
index 92ff9ed328..d8d1deaea1 100644
--- a/lib/erl_interface/doc/src/ref_man_ei.xml
+++ b/lib/erl_interface/doc/src/ref_man_ei.xml
@@ -30,8 +30,14 @@
<file>ref_man_ei.xml</file>
</header>
<description>
- <p>The <c>ei</c> library is a <c>C</c> interface library for
- communication with <c>Erlang</c>.</p>
+ <note><p>The support for VxWorks is deprecated as of OTP 22, and
+ will be removed in OTP 23.</p></note>
+ <note><p>The old legacy <c>erl_interface</c> library (functions
+ with prefix <c>erl_</c>) is deprecated as of OTP 22, and will be
+ removed in OTP 23. This does not apply to the <c>ei</c>
+ library. Reasonably new <c>gcc</c> compilers will issue deprecation
+ warnings. In order to disable these warnings, define the macro
+ <c>EI_NO_DEPR_WARN</c>.</p></note>
<note>
<p>By default, the <c>ei</c> library is only guaranteed
to be compatible with other Erlang/OTP components from the same
diff --git a/lib/erl_interface/doc/src/ref_man_erl_interface.xml b/lib/erl_interface/doc/src/ref_man_erl_interface.xml
index 4b1d0e9981..2b69d0fa74 100644
--- a/lib/erl_interface/doc/src/ref_man_erl_interface.xml
+++ b/lib/erl_interface/doc/src/ref_man_erl_interface.xml
@@ -30,6 +30,14 @@
<file>ref_man_erl_interface.xml</file>
</header>
<description>
+ <note><p>The support for VxWorks is deprecated as of OTP 22, and
+ will be removed in OTP 23.</p></note>
+ <note><p>The old legacy <c>erl_interface</c> library (functions
+ with prefix <c>erl_</c>) is deprecated as of OTP 22, and will be
+ removed in OTP 23. This does not apply to the <c>ei</c>
+ library. Reasonably new <c>gcc</c> compilers will issue deprecation
+ warnings. In order to disable these warnings, define the macro
+ <c>EI_NO_DEPR_WARN</c>.</p></note>
<p>The <c>erl_interface</c> library is a <c>C</c> interface library
for communication with <c>Erlang</c>.</p>
<note>
diff --git a/lib/erl_interface/doc/src/registry.xml b/lib/erl_interface/doc/src/registry.xml
index 6d70fb3475..1c90c5c9dd 100644
--- a/lib/erl_interface/doc/src/registry.xml
+++ b/lib/erl_interface/doc/src/registry.xml
@@ -44,7 +44,7 @@
<funcs>
<func>
- <name><ret>int</ret><nametext>ei_reg_close(reg)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_reg_close(reg)</nametext></name>
<fsummary>Close a registry.</fsummary>
<type>
<v>ei_reg *reg;</v>
@@ -59,7 +59,7 @@
</func>
<func>
- <name><ret>int</ret><nametext>ei_reg_delete(reg,key)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_reg_delete(reg,key)</nametext></name>
<fsummary>Delete an object from the registry.</fsummary>
<type>
<v>ei_reg *reg;</v>
@@ -85,7 +85,7 @@
</func>
<func>
- <name><ret>int</ret><nametext>ei_reg_dump(fd,reg,mntab,flags)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_reg_dump(fd,reg,mntab,flags)</nametext></name>
<fsummary>Back up a registry to Mnesia.</fsummary>
<type>
<v>int fd;</v>
@@ -125,7 +125,7 @@
</func>
<func>
- <name><ret>double</ret><nametext>ei_reg_getfval(reg,key)</nametext></name>
+ <name since=""><ret>double</ret><nametext>ei_reg_getfval(reg,key)</nametext></name>
<fsummary>Get a floating point object.</fsummary>
<type>
<v>ei_reg *reg;</v>
@@ -151,7 +151,7 @@
</func>
<func>
- <name><ret>int</ret><nametext>ei_reg_getival(reg,key)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_reg_getival(reg,key)</nametext></name>
<fsummary>Get an integer object.</fsummary>
<type>
<v>ei_reg *reg;</v>
@@ -177,7 +177,7 @@
</func>
<func>
- <name><ret>const void *</ret><nametext>ei_reg_getpval(reg,key,size)</nametext></name>
+ <name since=""><ret>const void *</ret><nametext>ei_reg_getpval(reg,key,size)</nametext></name>
<fsummary>Get a binary object.</fsummary>
<type>
<v>ei_reg *reg;</v>
@@ -207,7 +207,7 @@
</func>
<func>
- <name><ret>const char *</ret><nametext>ei_reg_getsval(reg,key)</nametext></name>
+ <name since=""><ret>const char *</ret><nametext>ei_reg_getsval(reg,key)</nametext></name>
<fsummary>Get a string object.</fsummary>
<type>
<v>ei_reg *reg;</v>
@@ -232,7 +232,7 @@
</func>
<func>
- <name><ret>int</ret><nametext>ei_reg_getval(reg,key,flags,v,...)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_reg_getval(reg,key,flags,v,...)</nametext></name>
<fsummary>Get any object.</fsummary>
<type>
<v>ei_reg *reg;</v>
@@ -278,7 +278,7 @@
</func>
<func>
- <name><ret>int</ret><nametext>ei_reg_markdirty(reg,key)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_reg_markdirty(reg,key)</nametext></name>
<fsummary>Mark an object as dirty.</fsummary>
<type>
<v>ei_reg *reg;</v>
@@ -305,7 +305,7 @@
</func>
<func>
- <name><ret>ei_reg *</ret><nametext>ei_reg_open(size)</nametext></name>
+ <name since=""><ret>ei_reg *</ret><nametext>ei_reg_open(size)</nametext></name>
<fsummary>Create and open a registry.</fsummary>
<type>
<v>int size;</v>
@@ -326,7 +326,7 @@
</func>
<func>
- <name><ret>int</ret><nametext>ei_reg_purge(reg)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_reg_purge(reg)</nametext></name>
<fsummary>Remove deleted objects.</fsummary>
<type>
<v>ei_reg *reg;</v>
@@ -346,7 +346,7 @@
</func>
<func>
- <name><ret>int</ret><nametext>ei_reg_resize(reg,newsize)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_reg_resize(reg,newsize)</nametext></name>
<fsummary>Resize a registry.</fsummary>
<type>
<v>ei_reg *reg;</v>
@@ -363,7 +363,7 @@
</func>
<func>
- <name><ret>int</ret><nametext>ei_reg_restore(fd,reg,mntab)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_reg_restore(fd,reg,mntab)</nametext></name>
<fsummary>Restore a registry from Mnesia.</fsummary>
<type>
<v>int fd;</v>
@@ -399,7 +399,7 @@
</func>
<func>
- <name><ret>int</ret><nametext>ei_reg_setfval(reg,key,f)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_reg_setfval(reg,key,f)</nametext></name>
<fsummary>Assign a floating point object.</fsummary>
<type>
<v>ei_reg *reg;</v>
@@ -424,7 +424,7 @@
</func>
<func>
- <name><ret>int</ret><nametext>ei_reg_setival(reg,key,i)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_reg_setival(reg,key,i)</nametext></name>
<fsummary>Assign an integer object.</fsummary>
<type>
<v>ei_reg *reg;</v>
@@ -448,7 +448,7 @@
</func>
<func>
- <name><ret>int</ret><nametext>ei_reg_setpval(reg,key,p,size)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_reg_setpval(reg,key,p,size)</nametext></name>
<fsummary>Assign a binary object.</fsummary>
<type>
<v>ei_reg *reg;</v>
@@ -479,7 +479,7 @@
</func>
<func>
- <name><ret>int</ret><nametext>ei_reg_setsval(reg,key,s)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_reg_setsval(reg,key,s)</nametext></name>
<fsummary>Assign a string object.</fsummary>
<type>
<v>ei_reg *reg;</v>
@@ -507,7 +507,7 @@
</func>
<func>
- <name><ret>int</ret><nametext>ei_reg_setval(reg,key,flags,v,...)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_reg_setval(reg,key,flags,v,...)</nametext></name>
<fsummary>Assign a value to any object type.</fsummary>
<type>
<v>ei_reg *reg;</v>
@@ -552,7 +552,7 @@
</func>
<func>
- <name><ret>int</ret><nametext>ei_reg_stat(reg,key,obuf)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_reg_stat(reg,key,obuf)</nametext></name>
<fsummary>Get object information.</fsummary>
<type>
<v>ei_reg *reg;</v>
@@ -590,7 +590,7 @@ struct ei_reg_stat {
</func>
<func>
- <name><ret>int</ret><nametext>ei_reg_tabstat(reg,obuf)</nametext></name>
+ <name since=""><ret>int</ret><nametext>ei_reg_tabstat(reg,obuf)</nametext></name>
<fsummary>Get registry information.</fsummary>
<type>
<v>ei_reg *reg;</v>
diff --git a/lib/erl_interface/include/ei.h b/lib/erl_interface/include/ei.h
index 948f89be85..b138118f04 100644
--- a/lib/erl_interface/include/ei.h
+++ b/lib/erl_interface/include/ei.h
@@ -35,6 +35,9 @@
#include <winsock2.h>
#include <windows.h>
#include <winbase.h>
+typedef LONG_PTR ssize_t; /* Sigh... */
+#else
+#include <sys/types.h> /* ssize_t */
#endif
#include <stdio.h> /* Need type FILE */
@@ -44,6 +47,25 @@
# include <netdb.h>
#endif
+#ifdef __has_attribute
+#if __has_attribute(deprecated)
+#define EI_HAVE_DEPRECATED_ATTR__ 1
+#else
+#undef EI_HAVE_DEPRECATED_ATTR__
+#endif
+#endif
+
+#ifdef EI_NO_DEPR_WARN
+#undef EI_HAVE_DEPRECATED_ATTR__
+#endif
+
+#ifdef EI_HAVE_DEPRECATED_ATTR__
+#define EI_DEPRECATED_ATTR_NAME deprecated
+#define EI_DEPRECATED_ATTR __attribute__((EI_DEPRECATED_ATTR_NAME))
+#else
+#define EI_DEPRECATED_ATTR_NAME
+#define EI_DEPRECATED_ATTR
+#endif
/* -------------------------------------------------------------------- */
/* Defines part of API */
@@ -132,11 +154,14 @@
#define ERL_STRING_EXT 'k'
#define ERL_LIST_EXT 'l'
#define ERL_BINARY_EXT 'm'
+#define ERL_BIT_BINARY_EXT 'M'
#define ERL_SMALL_BIG_EXT 'n'
#define ERL_LARGE_BIG_EXT 'o'
#define ERL_NEW_FUN_EXT 'p'
#define ERL_MAP_EXT 't'
#define ERL_FUN_EXT 'u'
+#define ERL_EXPORT_EXT 'q'
+
#define ERL_NEW_CACHE 'N' /* c nodes don't know these two */
#define ERL_CACHED_ATOM 'C'
@@ -188,12 +213,12 @@ extern volatile int __erl_errno;
* library and when using the library we set a value that we use
*/
-#define EI_MAXHOSTNAMELEN 64
-#define EI_MAXALIVELEN 63
#define EI_MAX_COOKIE_SIZE 512
#define MAXATOMLEN (255 + 1)
#define MAXATOMLEN_UTF8 (255*4 + 1)
-#define MAXNODELEN EI_MAXALIVELEN+1+EI_MAXHOSTNAMELEN
+#define EI_MAXHOSTNAMELEN (MAXATOMLEN - 2)
+#define EI_MAXALIVELEN (MAXATOMLEN - 2)
+#define MAXNODELEN MAXATOMLEN
typedef enum {
ERLANG_ASCII = 1,
@@ -247,15 +272,23 @@ typedef struct {
typedef struct {
long arity;
char module[MAXATOMLEN_UTF8];
- erlang_char_encoding module_org_enc;
- char md5[16];
- long index;
- long old_index;
- long uniq;
- long n_free_vars;
- erlang_pid pid;
- long free_var_len;
- char* free_vars;
+ enum { EI_FUN_CLOSURE, EI_FUN_EXPORT } type;
+ union {
+ struct {
+ char md5[16];
+ long index;
+ long old_index;
+ long uniq;
+ long n_free_vars;
+ erlang_pid pid;
+ long free_var_len;
+ char* free_vars;
+ } closure;
+ struct {
+ char* func;
+ int func_allocated;
+ } exprt;
+ } u;
} erlang_fun;
/* a big */
@@ -286,6 +319,31 @@ typedef struct {
char nodename[MAXNODELEN+1];
} ErlConnect;
+#define EI_SCLBK_INF_TMO (~((unsigned) 0))
+
+#define EI_SCLBK_FLG_FULL_IMPL (1 << 0)
+
+typedef struct {
+ int flags;
+
+ int (*socket)(void **ctx, void *setup_ctx);
+ int (*close)(void *ctx);
+ int (*listen)(void *ctx, void *addr, int *len, int backlog);
+ int (*accept)(void **ctx, void *addr, int *len, unsigned tmo);
+ int (*connect)(void *ctx, void *addr, int len, unsigned tmo);
+ int (*writev)(void *ctx, const void *iov, int iovcnt, ssize_t *len, unsigned tmo);
+ int (*write)(void *ctx, const char *buf, ssize_t *len, unsigned tmo);
+ int (*read)(void *ctx, char *buf, ssize_t *len, unsigned tmo);
+
+ int (*handshake_packet_header_size)(void *ctx, int *sz);
+ int (*connect_handshake_complete)(void *ctx);
+ int (*accept_handshake_complete)(void *ctx);
+ int (*get_fd)(void *ctx, int *fd);
+
+ /* end of version 1 */
+
+} ei_socket_callbacks;
+
typedef struct ei_cnode_s {
char thishostname[EI_MAXHOSTNAMELEN+1];
char thisnodename[MAXNODELEN+1];
@@ -295,6 +353,8 @@ typedef struct ei_cnode_s {
char ei_connect_cookie[EI_MAX_COOKIE_SIZE+1];
short creation;
erlang_pid self;
+ ei_socket_callbacks *cbs;
+ void *setup_context;
} ei_cnode;
typedef struct in_addr *Erl_IpAddr;
@@ -308,7 +368,6 @@ typedef struct ei_x_buff_TAG {
int index;
} ei_x_buff;
-
/* -------------------------------------------------------------------- */
/* Function definitions (listed in same order as documentation) */
/* -------------------------------------------------------------------- */
@@ -322,6 +381,16 @@ int ei_connect_xinit (ei_cnode* ec, const char *thishostname,
Erl_IpAddr thisipaddr, const char *cookie,
const short creation);
+int ei_connect_init_ussi(ei_cnode* ec, const char* this_node_name,
+ const char *cookie, short creation,
+ ei_socket_callbacks *cbs, int cbs_sz,
+ void *setup_context);
+int ei_connect_xinit_ussi(ei_cnode* ec, const char *thishostname,
+ const char *thisalivename, const char *thisnodename,
+ Erl_IpAddr thisipaddr, const char *cookie,
+ const short creation, ei_socket_callbacks *cbs,
+ int cbs_sz, void *setup_context);
+
int ei_connect(ei_cnode* ec, char *nodename);
int ei_connect_tmo(ei_cnode* ec, char *nodename, unsigned ms);
int ei_xconnect(ei_cnode* ec, Erl_IpAddr adr, char *alivename);
@@ -348,11 +417,15 @@ int ei_rpc_from(ei_cnode* ec, int fd, int timeout, erlang_msg* msg,
int ei_publish(ei_cnode* ec, int port);
int ei_publish_tmo(ei_cnode* ec, int port, unsigned ms);
+int ei_listen(ei_cnode *ec, int *port, int backlog);
+int ei_xlisten(ei_cnode *ec, Erl_IpAddr adr, int *port, int backlog);
int ei_accept(ei_cnode* ec, int lfd, ErlConnect *conp);
int ei_accept_tmo(ei_cnode* ec, int lfd, ErlConnect *conp, unsigned ms);
int ei_unpublish(ei_cnode* ec);
int ei_unpublish_tmo(const char *alive, unsigned ms);
+int ei_close_connection(int fd);
+
const char *ei_thisnodename(const ei_cnode* ec);
const char *ei_thishostname(const ei_cnode* ec);
const char *ei_thisalivename(const ei_cnode* ec);
@@ -453,7 +526,9 @@ int ei_x_encode_atom_len(ei_x_buff* x, const char* s, int len);
int ei_x_encode_atom_len_as(ei_x_buff* x, const char* s, int len,
erlang_char_encoding from, erlang_char_encoding to);
int ei_encode_binary(char *buf, int *index, const void *p, long len);
+int ei_encode_bitstring(char *buf, int *index, const char *p, size_t bitoffs, size_t bits);
int ei_x_encode_binary(ei_x_buff* x, const void* s, int len);
+int ei_x_encode_bitstring(ei_x_buff* x, const char* p, size_t bitoffs, size_t bits);
int ei_encode_pid(char *buf, int *index, const erlang_pid *p);
int ei_x_encode_pid(ei_x_buff* x, const erlang_pid* pid);
int ei_encode_fun(char* buf, int* index, const erlang_fun* p);
@@ -462,8 +537,8 @@ int ei_encode_port(char *buf, int *index, const erlang_port *p);
int ei_x_encode_port(ei_x_buff* x, const erlang_port *p);
int ei_encode_ref(char *buf, int *index, const erlang_ref *p);
int ei_x_encode_ref(ei_x_buff* x, const erlang_ref *p);
-int ei_encode_term(char *buf, int *index, void *t); /* ETERM* actually */
-int ei_x_encode_term(ei_x_buff* x, void* t);
+int ei_encode_term(char *buf, int *index, void *t) EI_DEPRECATED_ATTR;
+int ei_x_encode_term(ei_x_buff* x, void* t) EI_DEPRECATED_ATTR;
int ei_encode_trace(char *buf, int *index, const erlang_trace *p);
int ei_x_encode_trace(ei_x_buff* x, const erlang_trace *p);
int ei_encode_tuple_header(char *buf, int *index, int arity);
@@ -485,8 +560,6 @@ int ei_x_encode_map_header(ei_x_buff* x, long n);
*/
int ei_get_type(const char *buf, const int *index, int *type, int *size);
-int ei_get_type_internal(const char *buf, const int *index, int *type,
- int *size);
/* Step through buffer, decoding the given type into the buffer
* provided. On success, 0 is returned and index is updated to point
@@ -505,12 +578,15 @@ int ei_decode_string(const char *buf, int *index, char *p);
int ei_decode_atom(const char *buf, int *index, char *p);
int ei_decode_atom_as(const char *buf, int *index, char *p, int destlen, erlang_char_encoding want, erlang_char_encoding* was, erlang_char_encoding* result);
int ei_decode_binary(const char *buf, int *index, void *p, long *len);
+int ei_decode_bitstring(const char *buf, int *index, const char** pp,
+ unsigned int* bitoffsp, size_t *nbitsp);
+
int ei_decode_fun(const char* buf, int* index, erlang_fun* p);
void free_fun(erlang_fun* f);
int ei_decode_pid(const char *buf, int *index, erlang_pid *p);
int ei_decode_port(const char *buf, int *index, erlang_port *p);
int ei_decode_ref(const char *buf, int *index, erlang_ref *p);
-int ei_decode_term(const char *buf, int *index, void *t); /* ETERM** actually */
+int ei_decode_term(const char *buf, int *index, void *t) EI_DEPRECATED_ATTR;
int ei_decode_trace(const char *buf, int *index, erlang_trace *p);
int ei_decode_tuple_header(const char *buf, int *index, int *arity);
int ei_decode_list_header(const char *buf, int *index, int *arity);
@@ -626,6 +702,8 @@ struct ei_reg_tabstat {
};
+int ei_init(void);
+
/* -------------------------------------------------------------------- */
/* XXXXXXXXXXX */
/* -------------------------------------------------------------------- */
diff --git a/lib/erl_interface/include/erl_interface.h b/lib/erl_interface/include/erl_interface.h
index c22f21af2b..7c87223a38 100644
--- a/lib/erl_interface/include/erl_interface.h
+++ b/lib/erl_interface/include/erl_interface.h
@@ -25,8 +25,6 @@
/* Note: the 'ei' interface is the prefered C API. */
/************************************************************************/
-/* FIXME only include if needed? */
-
#include "ei.h" /* ei is the base */
/* -------------------------------------------------------------------- */
@@ -195,11 +193,11 @@ typedef struct {
int lenL;
} Erl_Atom_data;
-char* erl_atom_ptr_latin1(Erl_Atom_data*);
-char* erl_atom_ptr_utf8(Erl_Atom_data*);
-int erl_atom_size_latin1(Erl_Atom_data*);
-int erl_atom_size_utf8(Erl_Atom_data*);
-char* erl_atom_init_latin1(Erl_Atom_data*, const char*);
+char* erl_atom_ptr_latin1(Erl_Atom_data*) EI_DEPRECATED_ATTR;
+char* erl_atom_ptr_utf8(Erl_Atom_data*) EI_DEPRECATED_ATTR;
+int erl_atom_size_latin1(Erl_Atom_data*) EI_DEPRECATED_ATTR;
+int erl_atom_size_utf8(Erl_Atom_data*) EI_DEPRECATED_ATTR;
+char* erl_atom_init_latin1(Erl_Atom_data*, const char*) EI_DEPRECATED_ATTR;
typedef struct {
Erl_Header h;
@@ -324,110 +322,117 @@ typedef unsigned char Erl_Heap;
/* The functions */
/* -------------------------------------------------------------------- */
-void erl_init(void *x, long y);
-void erl_set_compat_rel(unsigned);
-int erl_connect_init(int, char*,short);
-int erl_connect_xinit(char*,char*,char*,struct in_addr*,char*,short);
-int erl_connect(char*);
-int erl_xconnect(struct in_addr*,char *);
-int erl_close_connection(int);
-int erl_receive(int, unsigned char*, int);
-int erl_receive_msg(int, unsigned char*, int, ErlMessage*);
-int erl_xreceive_msg(int, unsigned char**, int*, ErlMessage*);
-int erl_send(int, ETERM*, ETERM*);
-int erl_reg_send(int, char*, ETERM*);
-ETERM *erl_rpc(int,char*,char*,ETERM*);
-int erl_rpc_to(int,char*,char*,ETERM*);
-int erl_rpc_from(int,int,ErlMessage*);
+void erl_init(void *x, long y) EI_DEPRECATED_ATTR;
+void erl_set_compat_rel(unsigned) EI_DEPRECATED_ATTR;
+int erl_connect_init(int, char*,short) EI_DEPRECATED_ATTR;
+int erl_connect_xinit(char*,char*,char*,struct in_addr*,char*,short) EI_DEPRECATED_ATTR;
+int erl_connect(char*) EI_DEPRECATED_ATTR;
+int erl_xconnect(struct in_addr*,char *) EI_DEPRECATED_ATTR;
+int erl_close_connection(int) EI_DEPRECATED_ATTR;
+int erl_receive(int, unsigned char*, int) EI_DEPRECATED_ATTR;
+int erl_receive_msg(int, unsigned char*, int, ErlMessage*) EI_DEPRECATED_ATTR;
+int erl_xreceive_msg(int, unsigned char**, int*, ErlMessage*) EI_DEPRECATED_ATTR;
+int erl_send(int, ETERM*, ETERM*) EI_DEPRECATED_ATTR;
+int erl_reg_send(int, char*, ETERM*) EI_DEPRECATED_ATTR;
+ETERM *erl_rpc(int,char*,char*,ETERM*) EI_DEPRECATED_ATTR;
+int erl_rpc_to(int,char*,char*,ETERM*) EI_DEPRECATED_ATTR;
+int erl_rpc_from(int,int,ErlMessage*) EI_DEPRECATED_ATTR;
/* erl_publish returns open descriptor on success, or -1 */
-int erl_publish(int port);
-int erl_accept(int,ErlConnect*);
+int erl_publish(int port) EI_DEPRECATED_ATTR;
+int erl_accept(int,ErlConnect*) EI_DEPRECATED_ATTR;
-const char *erl_thiscookie(void);
-const char *erl_thisnodename(void);
-const char *erl_thishostname(void);
-const char *erl_thisalivename(void);
-short erl_thiscreation(void);
+const char *erl_thiscookie(void) EI_DEPRECATED_ATTR;
+const char *erl_thisnodename(void) EI_DEPRECATED_ATTR;
+const char *erl_thishostname(void) EI_DEPRECATED_ATTR;
+const char *erl_thisalivename(void) EI_DEPRECATED_ATTR;
+short erl_thiscreation(void) EI_DEPRECATED_ATTR;
/* returns 0 on success, -1 if node not known to epmd or epmd not reached */
-int erl_unpublish(const char *alive);
+int erl_unpublish(const char *alive) EI_DEPRECATED_ATTR;
+
+#ifdef EI_HAVE_DEPRECATED_ATTR__
+#define EI_DEPR_ATTR_EXTRA , EI_DEPRECATED_ATTR_NAME
+#else
+#define EI_DEPR_ATTR_EXTRA
+#endif
+
/* Report generic error to stderr. */
void erl_err_msg(const char * __template, ...)
- __attribute__ ((__format__ (printf, 1, 2)));
+ __attribute__ ((__format__ (printf, 1, 2) EI_DEPR_ATTR_EXTRA)) ;
/* Report generic error to stderr and die. */
void erl_err_quit(const char * __template, ...)
- __attribute__ ((__format__ (printf, 1, 2), __noreturn__));
+ __attribute__ ((__format__ (printf, 1, 2), __noreturn__ EI_DEPR_ATTR_EXTRA));
/* Report system/libc error to stderr. */
void erl_err_ret(const char * __template, ...)
- __attribute__ ((__format__ (printf, 1, 2)));
+ __attribute__ ((__format__ (printf, 1, 2) EI_DEPR_ATTR_EXTRA));
/* Report system/libc error to stderr and die. */
void erl_err_sys(const char * __template, ...)
- __attribute__ ((__format__ (printf, 1, 2), __noreturn__));
-
-ETERM *erl_cons(ETERM*,ETERM*);
-ETERM *erl_copy_term(const ETERM*);
-ETERM *erl_element(int,const ETERM*);
-
-ETERM *erl_hd(const ETERM*);
-ETERM* erl_iolist_to_binary(const ETERM* term);
-char* erl_iolist_to_string(const ETERM* term);
-int erl_iolist_length(const ETERM*);
-int erl_length(const ETERM*);
-ETERM *erl_mk_atom(const char*);
-ETERM *erl_mk_binary(const char*,int);
-ETERM *erl_mk_empty_list(void);
-ETERM *erl_mk_estring(const char*, int);
-ETERM *erl_mk_float(double);
-ETERM *erl_mk_int(int);
-ETERM *erl_mk_longlong(long long);
-ETERM *erl_mk_list(ETERM**,int);
-ETERM *erl_mk_pid(const char*,unsigned int,unsigned int,unsigned char);
-ETERM *erl_mk_port(const char*,unsigned int,unsigned char);
-ETERM *erl_mk_ref(const char*,unsigned int,unsigned char);
+ __attribute__ ((__format__ (printf, 1, 2), __noreturn__ EI_DEPR_ATTR_EXTRA));
+
+ETERM *erl_cons(ETERM*,ETERM*) EI_DEPRECATED_ATTR;
+ETERM *erl_copy_term(const ETERM*) EI_DEPRECATED_ATTR;
+ETERM *erl_element(int,const ETERM*) EI_DEPRECATED_ATTR;
+
+ETERM *erl_hd(const ETERM*) EI_DEPRECATED_ATTR;
+ETERM* erl_iolist_to_binary(const ETERM* term) EI_DEPRECATED_ATTR;
+char* erl_iolist_to_string(const ETERM* term) EI_DEPRECATED_ATTR;
+int erl_iolist_length(const ETERM*) EI_DEPRECATED_ATTR;
+int erl_length(const ETERM*) EI_DEPRECATED_ATTR;
+ETERM *erl_mk_atom(const char*) EI_DEPRECATED_ATTR;
+ETERM *erl_mk_binary(const char*,int) EI_DEPRECATED_ATTR;
+ETERM *erl_mk_empty_list(void) EI_DEPRECATED_ATTR;
+ETERM *erl_mk_estring(const char*, int) EI_DEPRECATED_ATTR;
+ETERM *erl_mk_float(double) EI_DEPRECATED_ATTR;
+ETERM *erl_mk_int(int) EI_DEPRECATED_ATTR;
+ETERM *erl_mk_longlong(long long) EI_DEPRECATED_ATTR;
+ETERM *erl_mk_list(ETERM**,int) EI_DEPRECATED_ATTR;
+ETERM *erl_mk_pid(const char*,unsigned int,unsigned int,unsigned char) EI_DEPRECATED_ATTR;
+ETERM *erl_mk_port(const char*,unsigned int,unsigned char) EI_DEPRECATED_ATTR;
+ETERM *erl_mk_ref(const char*,unsigned int,unsigned char) EI_DEPRECATED_ATTR;
ETERM *erl_mk_long_ref(const char*,unsigned int,unsigned int,
- unsigned int,unsigned char);
-ETERM *erl_mk_string(const char*);
-ETERM *erl_mk_tuple(ETERM**,int);
-ETERM *erl_mk_uint(unsigned int);
-ETERM *erl_mk_ulonglong(unsigned long long);
-ETERM *erl_mk_var(const char*);
-int erl_print_term(FILE*,const ETERM*);
-/* int erl_sprint_term(char*,const ETERM*); */
-int erl_size(const ETERM*);
-ETERM *erl_tl(const ETERM*);
-ETERM *erl_var_content(const ETERM*, const char*);
-
-ETERM *erl_format(char*, ... );
-int erl_match(ETERM*, ETERM*);
-
-char **erl_global_names(int fd, int *count);
-int erl_global_register(int fd, const char *name, ETERM *pid);
-int erl_global_unregister(int fd, const char *name);
-ETERM *erl_global_whereis(int fd, const char *name, char *node);
-
-void erl_init_malloc(Erl_Heap*,long);
-ETERM *erl_alloc_eterm(unsigned char);
-void erl_eterm_release(void);
-void erl_eterm_statistics(unsigned long*,unsigned long*);
-void erl_free_array(ETERM**,int);
-void erl_free_term(ETERM*);
-void erl_free_compound(ETERM*);
-void *erl_malloc(long);
-void erl_free(void*);
-
-int erl_compare_ext(unsigned char*, unsigned char*);
-ETERM *erl_decode(unsigned char*);
-ETERM *erl_decode_buf(unsigned char**);
-int erl_encode(ETERM*,unsigned char*t);
-int erl_encode_buf(ETERM*,unsigned char**);
-int erl_ext_size(unsigned char*);
-unsigned char erl_ext_type(unsigned char*); /* Note: returned 'char' before R9C */
-unsigned char *erl_peek_ext(unsigned char*,int);
-int erl_term_len(ETERM*);
-
-int cmp_latin1_vs_utf8(const char* sL, int lenL, const char* sU, int lenU);
+ unsigned int,unsigned char) EI_DEPRECATED_ATTR;
+ETERM *erl_mk_string(const char*) EI_DEPRECATED_ATTR;
+ETERM *erl_mk_tuple(ETERM**,int) EI_DEPRECATED_ATTR;
+ETERM *erl_mk_uint(unsigned int) EI_DEPRECATED_ATTR;
+ETERM *erl_mk_ulonglong(unsigned long long) EI_DEPRECATED_ATTR;
+ETERM *erl_mk_var(const char*) EI_DEPRECATED_ATTR;
+int erl_print_term(FILE*,const ETERM*) EI_DEPRECATED_ATTR;
+/* int erl_sprint_term(char*,const ETERM*) EI_DEPRECATED_ATTR; */
+int erl_size(const ETERM*) EI_DEPRECATED_ATTR;
+ETERM *erl_tl(const ETERM*) EI_DEPRECATED_ATTR;
+ETERM *erl_var_content(const ETERM*, const char*) EI_DEPRECATED_ATTR;
+
+ETERM *erl_format(char*, ... ) EI_DEPRECATED_ATTR;
+int erl_match(ETERM*, ETERM*) EI_DEPRECATED_ATTR;
+
+char **erl_global_names(int fd, int *count) EI_DEPRECATED_ATTR;
+int erl_global_register(int fd, const char *name, ETERM *pid) EI_DEPRECATED_ATTR;
+int erl_global_unregister(int fd, const char *name) EI_DEPRECATED_ATTR;
+ETERM *erl_global_whereis(int fd, const char *name, char *node) EI_DEPRECATED_ATTR;
+
+void erl_init_malloc(Erl_Heap*,long) EI_DEPRECATED_ATTR;
+ETERM *erl_alloc_eterm(unsigned char) EI_DEPRECATED_ATTR;
+void erl_eterm_release(void) EI_DEPRECATED_ATTR;
+void erl_eterm_statistics(unsigned long*,unsigned long*) EI_DEPRECATED_ATTR;
+void erl_free_array(ETERM**,int) EI_DEPRECATED_ATTR;
+void erl_free_term(ETERM*) EI_DEPRECATED_ATTR;
+void erl_free_compound(ETERM*) EI_DEPRECATED_ATTR;
+void *erl_malloc(long) EI_DEPRECATED_ATTR;
+void erl_free(void*) EI_DEPRECATED_ATTR;
+
+int erl_compare_ext(unsigned char*, unsigned char*) EI_DEPRECATED_ATTR;
+ETERM *erl_decode(unsigned char*) EI_DEPRECATED_ATTR;
+ETERM *erl_decode_buf(unsigned char**) EI_DEPRECATED_ATTR;
+int erl_encode(ETERM*,unsigned char*t) EI_DEPRECATED_ATTR;
+int erl_encode_buf(ETERM*,unsigned char**) EI_DEPRECATED_ATTR;
+int erl_ext_size(unsigned char*) EI_DEPRECATED_ATTR;
+unsigned char erl_ext_type(unsigned char*) EI_DEPRECATED_ATTR; /* Note: returned 'char' before R9C */
+unsigned char *erl_peek_ext(unsigned char*,int) EI_DEPRECATED_ATTR;
+int erl_term_len(ETERM*) EI_DEPRECATED_ATTR;
+
+int cmp_latin1_vs_utf8(const char* sL, int lenL, const char* sU, int lenU) EI_DEPRECATED_ATTR;
/* -------------------------------------------------------------------- */
/* Wrappers around ei functions */
@@ -437,29 +442,29 @@ int cmp_latin1_vs_utf8(const char* sL, int lenL, const char* sU, int lenU);
* Undocumented before R9C, included for compatibility with old code
*/
-struct hostent *erl_gethostbyname(const char *name);
-struct hostent *erl_gethostbyaddr(const char *addr, int len, int type);
+struct hostent *erl_gethostbyname(const char *name) EI_DEPRECATED_ATTR;
+struct hostent *erl_gethostbyaddr(const char *addr, int len, int type) EI_DEPRECATED_ATTR;
struct hostent *erl_gethostbyname_r(const char *name,
struct hostent *hostp,
char *buffer,
int buflen,
- int *h_errnop);
+ int *h_errnop) EI_DEPRECATED_ATTR;
struct hostent *erl_gethostbyaddr_r(const char *addr,
int length,
int type,
struct hostent *hostp,
char *buffer,
int buflen,
- int *h_errnop);
+ int *h_errnop) EI_DEPRECATED_ATTR;
/*
* Undocumented, included for compatibility with old code
*/
-void erl_init_resolve(void);
-int erl_distversion(int fd);
-int erl_epmd_connect(struct in_addr *inaddr);
-int erl_epmd_port(struct in_addr *inaddr, const char *alive, int *dist);
+void erl_init_resolve(void) EI_DEPRECATED_ATTR;
+int erl_distversion(int fd) EI_DEPRECATED_ATTR;
+int erl_epmd_connect(struct in_addr *inaddr) EI_DEPRECATED_ATTR;
+int erl_epmd_port(struct in_addr *inaddr, const char *alive, int *dist) EI_DEPRECATED_ATTR;
#ifdef __cplusplus
}
diff --git a/lib/erl_interface/src/INSTALL b/lib/erl_interface/src/INSTALL
index b42a17ac46..bf3ca8b6a5 100644
--- a/lib/erl_interface/src/INSTALL
+++ b/lib/erl_interface/src/INSTALL
@@ -122,10 +122,10 @@ you can use the `configure' options `--x-includes=DIR' and
Specifying the System Type
==========================
- There may be some features `configure' can not figure out
+ There may be some features `configure' cannot figure out
automatically, but needs to determine by the type of host the package
will run on. Usually `configure' can figure that out, but if it prints
-a message saying it can not guess the host type, give it the
+a message saying it cannot guess the host type, give it the
`--host=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name with three fields:
CPU-COMPANY-SYSTEM
diff --git a/lib/erl_interface/src/Makefile b/lib/erl_interface/src/Makefile
index 135522397b..00c49f1622 100644
--- a/lib/erl_interface/src/Makefile
+++ b/lib/erl_interface/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2016. All Rights Reserved.
+# Copyright Ericsson AB 1996-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -27,7 +27,9 @@ include $(ERL_TOP)/make/output.mk
include $(ERL_TOP)/make/target.mk
debug opt shared purify quantify purecov gcov:
+ifndef TERTIARY_BOOTSTRAP
$(make_verbose)$(MAKE) -f $(TARGET)/Makefile TYPE=$@
+endif
clean depend docs release release_docs tests release_tests check xmllint:
$(make_verbose)$(MAKE) -f $(TARGET)/Makefile $@
diff --git a/lib/erl_interface/src/Makefile.in b/lib/erl_interface/src/Makefile.in
index 69b5b6003d..6e0d3476c7 100644
--- a/lib/erl_interface/src/Makefile.in
+++ b/lib/erl_interface/src/Makefile.in
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -31,12 +31,13 @@
.PHONY : debug opt release clean distclean depend
-TARGET = @TARGET@
+include $(ERL_TOP)/make/target.mk
# ----------------------------------------------------
# Application version and release dir specification
# ----------------------------------------------------
include ../vsn.mk
+include $(ERL_TOP)/make/target.mk
include $(TARGET)/eidefs.mk
include $(ERL_TOP)/make/output.mk
@@ -126,6 +127,8 @@ else
WARNFLAGS = @WFLAGS@
endif
+WARNFLAGS += -DEI_NO_DEPR_WARN
+
CFLAGS = @LIB_CFLAGS@ $(WARNFLAGS) $(INCFLAGS) $(TYPE_FLAGS)
PROG_CFLAGS = @CFLAGS@ $(WARNFLAGS) $(INCFLAGS) $(TYPE_FLAGS) -Ilegacy
@@ -417,7 +420,8 @@ MISCSRC = \
misc/eimd5.c \
misc/get_type.c \
misc/show_msg.c \
- misc/ei_compat.c
+ misc/ei_compat.c \
+ misc/ei_init.c
REGISTRYSRC = \
registry/hash_dohash.c \
@@ -780,29 +784,31 @@ $(MDD_OBJDIR)/ei_fake_prog_mdd_cxx$(EXE): prog/ei_fake_prog.c $(MDD_EILIB)
# Create dependency file using gcc -MM
###########################################################################
-depend:
+depend: $(TARGET)/depend.mk
+
+$(TARGET)/depend.mk: $(TARGET)/config.h
$(gen_verbose)
- $(V_colon)@echo "Generating dependency file depend.mk..."
- @echo "# Generated dependency rules" > depend.mk; \
- $(V_CC) $(CFLAGS) -MM $(SOURCES) | \
+ $(V_colon)echo "Generating dependency file depend.mk..."
+ @echo "# Generated dependency rules" > $@
+ $(V_CC) $(CFLAGS) -MM $(SOURCES) | \
sed 's&$(TARGET)&\$$\(TARGET\)&g' | \
- sed 's/^.*:/\$$\(ST_OBJDIR\)\/&/' >> depend.mk; \
- echo >> depend.mk; \
- $(CC) $(CFLAGS) -MM $(SOURCES) | \
+ sed 's/^.*:/\$$\(ST_OBJDIR\)\/&/' >> $@
+ @echo >> $@
+ $(V_CC) $(CFLAGS) -MM $(SOURCES) | \
sed 's&$(TARGET)&\$$\(TARGET\)&g' | \
- sed 's/^.*:/\$$\(MT_OBJDIR\)\/&/' >> depend.mk; \
- echo >> depend.mk; \
- $(CC) $(CFLAGS) -MM $(SOURCES) | \
+ sed 's/^.*:/\$$\(MT_OBJDIR\)\/&/' >> $@
+ @echo >> $@
+ $(V_CC) $(CFLAGS) -MM $(SOURCES) | \
sed 's&$(TARGET)&\$$\(TARGET\)&g' | \
- sed 's/^.*:/\$$\(MD_OBJDIR\)\/&/' >> depend.mk; \
- echo >> depend.mk; \
- $(CC) $(CFLAGS) -MM $(SOURCES) | \
+ sed 's/^.*:/\$$\(MD_OBJDIR\)\/&/' >> $@
+ @echo >> $@
+ $(V_CC) $(CFLAGS) -MM $(SOURCES) | \
sed 's&$(TARGET)&\$$\(TARGET\)&g' | \
- sed 's/^.*:/\$$\(MDD_OBJDIR\)\/&/' >> depend.mk; \
- echo >> depend.mk
+ sed 's/^.*:/\$$\(MDD_OBJDIR\)\/&/' >> $@
+ @echo >> $@
# For some reason this has to be after 'opt' target
-include depend.mk
+-include $(TARGET)/depend.mk
# ----------------------------------------------------
# Release Target
diff --git a/lib/erl_interface/src/README.internal b/lib/erl_interface/src/README.internal
index c1f2d6863f..42c45b46a9 100644
--- a/lib/erl_interface/src/README.internal
+++ b/lib/erl_interface/src/README.internal
@@ -167,12 +167,12 @@ NOTE!!!! Sending a "char" to macros like isupper(), isalpha() where
the character is > 127 will cause serios problems on some
machines/OS. The reason is that
- 'char' may be unsigned, i.e. the Swedish char '�' will
+ 'char' may be unsigned, i.e. the Swedish char 'ä' will
as a number be negativ.
The implementation of isupper() and others will on some
machines use an array that is indexed with the incoming
- character code. The Swedish '�' will then create an access
+ character code. The Swedish 'ä' will then create an access
on memory outside the array!
This may give a random value as a result or a segmentation
@@ -219,7 +219,7 @@ There are some functions in the 'ei' library that uses the GCC and
VC++ "long long" type. Unfortunately this can lead to some trouble.
When user code is linked with the "libei.a" the linker will extract
-all objects files needed for resolving all symbol referenses
+all objects files needed for resolving all symbol references
found. This means that you want to follow the rule that
* To reduce executable code size we use resonably small C source
@@ -252,7 +252,7 @@ example is that in plain R9C the ei_x_encode_longlong() function is
located in the file "ei_x_encode.c". So if any "long long" ei_x
function is used we have an unessesary dependency on
"ei_encode_longlong.o" and then need to link with GNU ld on with the
-user code or explicitely link with "libgcc.a". The situation can be
+user code or explicitly link with "libgcc.a". The situation can be
visible in in plain R9C using
% nm -A erl_interface-3.4/lib/libei.a | \
diff --git a/lib/erl_interface/src/connect/ei_connect.c b/lib/erl_interface/src/connect/ei_connect.c
index ea9ecb31d5..1b1479d2e9 100644
--- a/lib/erl_interface/src/connect/ei_connect.c
+++ b/lib/erl_interface/src/connect/ei_connect.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2000-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2000-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -42,10 +42,8 @@
#include <inetLib.h>
#include <unistd.h>
-#include <sys/types.h>
#include <sys/times.h>
#include <unistd.h>
-#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
@@ -55,7 +53,6 @@
#else /* some other unix */
#include <unistd.h>
-#include <sys/types.h>
#include <sys/times.h>
#if TIME_WITH_SYS_TIME
@@ -84,6 +81,7 @@
#include <string.h>
#include <errno.h>
#include <ctype.h>
+#include <stddef.h>
#include "eiext.h"
#include "ei_portio.h"
@@ -98,11 +96,16 @@
#include "ei_epmd.h"
#include "ei_internal.h"
+static int ei_connect_initialized = 0;
int ei_tracelevel = 0;
#define COOKIE_FILE "/.erlang.cookie"
#define EI_MAX_HOME_PATH 1024
+#define EI_SOCKET_CALLBACKS_SZ_V1 \
+ (offsetof(ei_socket_callbacks, get_fd) \
+ + sizeof(int (*)(void *)))
+
/* FIXME why not macro? */
static char *null_cookie = "";
@@ -113,30 +116,51 @@ static int get_home(char *buf, int size);
static unsigned gen_challenge(void);
static void gen_digest(unsigned challenge, char cookie[],
unsigned char digest[16]);
-static int send_status(int fd, char *status, unsigned ms);
-static int recv_status(int fd, unsigned ms);
-static int send_challenge(int fd, char *nodename,
- unsigned challenge, unsigned version, unsigned ms);
-static int recv_challenge(int fd, unsigned *challenge,
- unsigned *version,
- unsigned *flags, ErlConnect *namebuf, unsigned ms);
-static int send_challenge_reply(int fd, unsigned char digest[16],
+static int send_status(ei_socket_callbacks *cbs, void *ctx,
+ int pkt_sz, char *status, unsigned ms);
+static int recv_status(ei_socket_callbacks *cbs, void *ctx,
+ int pkt_sz, unsigned ms);
+static int send_challenge(ei_socket_callbacks *cbs, void *ctx, int pkt_sz,
+ char *nodename, unsigned challenge,
+ unsigned version, unsigned ms);
+static int recv_challenge(ei_socket_callbacks *cbs, void *ctx, int pkt_sz,
+ unsigned *challenge, unsigned *version,
+ unsigned *flags, char *namebuf, unsigned ms);
+static int send_challenge_reply(ei_socket_callbacks *cbs, void *ctx,
+ int pkt_sz, unsigned char digest[16],
unsigned challenge, unsigned ms);
-static int recv_challenge_reply(int fd,
- unsigned our_challenge,
+static int recv_challenge_reply(ei_socket_callbacks *cbs, void *ctx,
+ int pkt_sz, unsigned our_challenge,
char cookie[],
unsigned *her_challenge, unsigned ms);
-static int send_challenge_ack(int fd, unsigned char digest[16], unsigned ms);
-static int recv_challenge_ack(int fd,
- unsigned our_challenge,
+static int send_challenge_ack(ei_socket_callbacks *cbs, void *ctx,
+ int pkt_sz, unsigned char digest[16],
+ unsigned ms);
+static int recv_challenge_ack(ei_socket_callbacks *cbs, void *ctx,
+ int pkt_sz, unsigned our_challenge,
char cookie[], unsigned ms);
-static int send_name(int fd, char *nodename,
- unsigned version, unsigned ms);
+static int send_name(ei_socket_callbacks *cbs, void *ctx, int pkt_sz,
+ char *nodename, unsigned version, unsigned ms);
+
+static int recv_name(ei_socket_callbacks *cbs, void *ctx, int pkt_sz,
+ unsigned *version, unsigned *flags, char *namebuf,
+ unsigned ms);
-/* Common for both handshake types */
-static int recv_name(int fd,
- unsigned *version,
- unsigned *flags, ErlConnect *namebuf, unsigned ms);
+static struct hostent*
+dyn_gethostbyname_r(const char *name, struct hostent *hostp, char **buffer_p,
+ int buflen, int *h_errnop);
+
+static void abort_connection(ei_socket_callbacks *cbs, void *ctx);
+static int close_connection(ei_socket_callbacks *cbs, void *ctx, int fd);
+
+static char *
+estr(int e)
+{
+ char *str = strerror(e);
+ if (!str)
+ return "unknown error";
+ return str;
+}
/***************************************************************************
@@ -149,25 +173,208 @@ static int recv_name(int fd,
typedef struct ei_socket_info_s {
int socket;
+ ei_socket_callbacks *cbs;
+ void *ctx;
int dist_version;
ei_cnode cnode; /* A copy, not a pointer. We don't know when freed */
char cookie[EI_MAX_COOKIE_SIZE+1];
} ei_socket_info;
+/***************************************************************************
+ *
+ * XXX
+ *
+ ***************************************************************************/
+
+#ifndef ETHR_HAVE___atomic_compare_exchange_n
+# define ETHR_HAVE___atomic_compare_exchange_n 0
+#endif
+#ifndef ETHR_HAVE___atomic_load_n
+# define ETHR_HAVE___atomic_load_n 0
+#endif
+#ifndef ETHR_HAVE___atomic_store_n
+# define ETHR_HAVE___atomic_store_n 0
+#endif
+
+#if defined(_REENTRANT) \
+ && (!(ETHR_HAVE___atomic_compare_exchange_n & SIZEOF_VOID_P) \
+ || !(ETHR_HAVE___atomic_load_n & SIZEOF_VOID_P) \
+ || !(ETHR_HAVE___atomic_store_n & SIZEOF_VOID_P))
+# undef EI_DISABLE_SEQ_SOCKET_INFO
+# define EI_DISABLE_SEQ_SOCKET_INFO
+#endif
+
+#ifdef __WIN32__
+# undef EI_DISABLE_SEQ_SOCKET_INFO
+# define EI_DISABLE_SEQ_SOCKET_INFO
+#endif
+
+#ifndef EI_DISABLE_SEQ_SOCKET_INFO
+
+#ifdef _REENTRANT
+
+#define EI_ATOMIC_CMPXCHG_ACQ_REL(VARP, XCHGP, NEW) \
+ __atomic_compare_exchange_n((VARP), (XCHGP), (NEW), 0, \
+ __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)
+#define EI_ATOMIC_LOAD_ACQ(VARP) \
+ __atomic_load_n((VARP), __ATOMIC_ACQUIRE)
+#define EI_ATOMIC_STORE_REL(VARP, NEW) \
+ __atomic_store_n((VARP), (NEW), __ATOMIC_RELEASE)
+
+#else /* ! _REENTRANT */
+
+#define EI_ATOMIC_CMPXCHG_ACQ_REL(VARP, XCHGP, NEW) \
+ (*(VARP) == *(XCHGP) \
+ ? ((*(VARP) = (NEW)), !0) \
+ : ((*(XCHGP) = *(VARP)), 0))
+#define EI_ATOMIC_LOAD_ACQ(VARP) (*(VARP))
+#define EI_ATOMIC_STORE_REL(VARP, NEW) (*(VARP) = (NEW))
+
+#endif /* ! _REENTRANT */
+
+#define EI_SOCKET_INFO_SEG_BITS 5
+#define EI_SOCKET_INFO_SEG_SIZE (1 << EI_SOCKET_INFO_SEG_BITS)
+#define EI_SOCKET_INFO_SEG_MASK (EI_SOCKET_INFO_SEG_SIZE - 1)
+
+typedef struct {
+ int max_fds;
+ ei_socket_info *segments[1]; /* Larger in reality... */
+} ei_socket_info_data__;
+
+static ei_socket_info_data__ *socket_info_data = NULL;
+
+static int init_socket_info(int late)
+{
+ int max_fds;
+ int i;
+ size_t segments_len;
+ ei_socket_info_data__ *info_data, *xchg;
+
+ if (EI_ATOMIC_LOAD_ACQ(&socket_info_data) != NULL)
+ return 0; /* Already initialized... */
+
+#if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
+ max_fds = sysconf(_SC_OPEN_MAX);
+#else
+ max_fds = 1024;
+#endif
+
+ if (max_fds < 0)
+ return EIO;
+
+ segments_len = ((max_fds-1)/EI_SOCKET_INFO_SEG_SIZE + 1);
+
+ info_data = malloc(sizeof(ei_socket_info_data__)
+ + (sizeof(ei_socket_info *)*(segments_len-1)));
+ if (!info_data)
+ return ENOMEM;
+
+ info_data->max_fds = max_fds;
+ for (i = 0; i < segments_len; i++)
+ info_data->segments[i] = NULL;
+
+ xchg = NULL;
+ if (!EI_ATOMIC_CMPXCHG_ACQ_REL(&socket_info_data, &xchg, info_data))
+ free(info_data); /* Already initialized... */
+
+ return 0;
+}
+
+static int put_ei_socket_info(int fd, int dist_version, char* cookie, ei_cnode *ec,
+ ei_socket_callbacks *cbs, void *ctx)
+{
+ int six;
+ ei_socket_info *seg, *si;
+ int socket;
+
+ if (fd < 0 || socket_info_data->max_fds <= fd)
+ return -1;
+
+ socket = fd;
+ six = fd >> EI_SOCKET_INFO_SEG_BITS;
+ seg = EI_ATOMIC_LOAD_ACQ(&socket_info_data->segments[six]);
+
+ if (!seg) {
+ ei_socket_info *xchg;
+ int i;
+ seg = malloc(sizeof(ei_socket_info)*EI_SOCKET_INFO_SEG_SIZE);
+ if (!seg)
+ return -1;
+ for (i = 0; i < EI_SOCKET_INFO_SEG_SIZE; i++) {
+ seg[i].socket = -1;
+ }
+
+ xchg = NULL;
+ if (!EI_ATOMIC_CMPXCHG_ACQ_REL(&socket_info_data->segments[six], &xchg, seg)) {
+ free(seg);
+ seg = xchg;
+ }
+ }
+
+ si = &seg[fd & EI_SOCKET_INFO_SEG_MASK];
+
+ if (dist_version < 0) {
+ socket = -1;
+ si->cbs = NULL;
+ si->ctx = NULL;
+ }
+ else {
+ si->dist_version = dist_version;
+ si->cnode = *ec;
+ si->cbs = cbs;
+ si->ctx = ctx;
+ strcpy(si->cookie, cookie);
+ }
+
+ EI_ATOMIC_STORE_REL(&si->socket, socket);
+
+ return 0;
+}
+
+static ei_socket_info* get_ei_socket_info(int fd)
+{
+ int six, socket;
+ ei_socket_info *seg, *si;
+
+ if (fd < 0 || socket_info_data->max_fds <= fd)
+ return NULL;
+
+ six = fd >> EI_SOCKET_INFO_SEG_BITS;
+ seg = EI_ATOMIC_LOAD_ACQ(&socket_info_data->segments[six]);
+
+ if (!seg)
+ return NULL;
+
+ si = &seg[fd & EI_SOCKET_INFO_SEG_MASK];
+ socket = EI_ATOMIC_LOAD_ACQ(&si->socket);
+ if (socket != fd)
+ return NULL;
+ return si;
+}
+
+#else /* EI_DISABLE_SEQ_SOCKET_INFO */
+
int ei_n_sockets = 0, ei_sz_sockets = 0;
ei_socket_info *ei_sockets = NULL;
+
#ifdef _REENTRANT
ei_mutex_t* ei_sockets_lock = NULL;
#endif /* _REENTRANT */
+static int init_socket_info(int late)
+{
+#ifdef _REENTRANT
+ if (late)
+ return ENOTSUP; /* Refuse doing unsafe initialization... */
+ ei_sockets_lock = ei_mutex_create();
+ if (!ei_sockets_lock)
+ return ENOMEM;
+#endif /* _REENTRANT */
+ return 0;
+}
-/***************************************************************************
- *
- * XXX
- *
- ***************************************************************************/
-
-static int put_ei_socket_info(int fd, int dist_version, char* cookie, ei_cnode *ec)
+static int put_ei_socket_info(int fd, int dist_version, char* cookie, ei_cnode *ec,
+ ei_socket_callbacks *cbs, void *ctx)
{
int i;
@@ -177,11 +384,13 @@ static int put_ei_socket_info(int fd, int dist_version, char* cookie, ei_cnode *
for (i = 0; i < ei_n_sockets; ++i) {
if (ei_sockets[i].socket == fd) {
if (dist_version == -1) {
- memmove(&ei_sockets[i], &ei_sockets[i+1],
+ memmove(&ei_sockets[i], &ei_sockets[i+1],
sizeof(ei_sockets[0])*(ei_n_sockets-i-1));
} else {
ei_sockets[i].dist_version = dist_version;
/* Copy the content, see ei_socket_info */
+ ei_sockets[i].cbs = cbs;
+ ei_sockets[i].ctx = ctx;
ei_sockets[i].cnode = *ec;
strcpy(ei_sockets[i].cookie, cookie);
}
@@ -204,7 +413,9 @@ static int put_ei_socket_info(int fd, int dist_version, char* cookie, ei_cnode *
}
ei_sockets[ei_n_sockets].socket = fd;
ei_sockets[ei_n_sockets].dist_version = dist_version;
- ei_sockets[i].cnode = *ec;
+ ei_sockets[ei_n_sockets].cnode = *ec;
+ ei_sockets[ei_n_sockets].cbs = cbs;
+ ei_sockets[ei_n_sockets].ctx = ctx;
strcpy(ei_sockets[ei_n_sockets].cookie, cookie);
++ei_n_sockets;
}
@@ -214,14 +425,6 @@ static int put_ei_socket_info(int fd, int dist_version, char* cookie, ei_cnode *
return 0;
}
-#if 0
-/* FIXME not used ?! */
-static int remove_ei_socket_info(int fd, int dist_version, char* cookie)
-{
- return put_ei_socket_info(fd, -1, NULL);
-}
-#endif
-
static ei_socket_info* get_ei_socket_info(int fd)
{
int i;
@@ -243,6 +446,13 @@ static ei_socket_info* get_ei_socket_info(int fd)
return NULL;
}
+#endif /* EI_DISABLE_SEQ_SOCKET_INFO */
+
+static int remove_ei_socket_info(int fd)
+{
+ return put_ei_socket_info(fd, -1, NULL, NULL, NULL, NULL);
+}
+
ei_cnode *ei_fd_to_cnode(int fd)
{
ei_socket_info *sockinfo = get_ei_socket_info(fd);
@@ -250,6 +460,19 @@ ei_cnode *ei_fd_to_cnode(int fd)
return &sockinfo->cnode;
}
+int ei_get_cbs_ctx__(ei_socket_callbacks **cbs, void **ctx, int fd)
+{
+ ei_socket_info *sockinfo = get_ei_socket_info(fd);
+ if (sockinfo) {
+ *cbs = sockinfo->cbs;
+ *ctx = sockinfo->ctx;
+ return 0;
+ }
+
+ *cbs = NULL;
+ *ctx = NULL;
+ return EBADF;
+}
/***************************************************************************
* Get/Set tracelevel
@@ -328,21 +551,6 @@ const char *ei_getfdcookie(int fd)
return r;
}
-/* call with cookie to set value to use on descriptor fd,
-* or specify NULL to use default
-*/
-/* FIXME why defined but not used? */
-#if 0
-static int ei_setfdcookie(ei_cnode* ec, int fd, char *cookie)
-{
- int dist_version = ei_distversion(fd);
-
- if (cookie == NULL)
- cookie = ec->ei_connect_cookie;
- return put_ei_socket_info(fd, dist_version, cookie);
-}
-#endif
-
static int get_int32(unsigned char *s)
{
return ((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | (s[3] ));
@@ -395,34 +603,62 @@ static int initWinSock(void)
}
#endif
+static int init_connect(int late)
+{
+ int error;
+
+ /*
+ * 'late' is non-zero when not called via ei_init(). Such a
+ * call is not supported, but we for now save the day if
+ * it easy to do so; otherwise, return ENOTSUP.
+ */
+
+#ifdef __WIN32__
+ if (!initWinSock()) {
+ EI_TRACE_ERR0("ei_init_connect","can't initiate winsock");
+ return EIO;
+ }
+#endif /* win32 */
+
+ error = init_socket_info(late);
+ if (error) {
+ EI_TRACE_ERR0("ei_init_connect","can't initiate socket info");
+ return error;
+ }
+
+ ei_connect_initialized = !0;
+ return 0;
+}
+
+int ei_init_connect(void)
+{
+ return init_connect(0);
+}
+
/*
* Perhaps run this routine instead of ei_connect_init/2 ?
* Initailize by setting:
* thishostname, thisalivename, thisnodename and thisipaddr
*/
-int ei_connect_xinit(ei_cnode* ec, const char *thishostname,
- const char *thisalivename, const char *thisnodename,
- Erl_IpAddr thisipaddr, const char *cookie,
- const short creation)
+int ei_connect_xinit_ussi(ei_cnode* ec, const char *thishostname,
+ const char *thisalivename, const char *thisnodename,
+ Erl_IpAddr thisipaddr, const char *cookie,
+ const short creation, ei_socket_callbacks *cbs,
+ int cbs_sz, void *setup_context)
{
char *dbglevel;
-
-/* FIXME this code was enabled for 'erl'_connect_xinit(), why not here? */
-#if 0
-#ifdef __WIN32__
- if (!initWinSock()) {
- EI_TRACE_ERR0("ei_connect_xinit","can't initiate winsock");
- return ERL_ERROR;
- }
-#endif
-#endif
-#ifdef _REENTRANT
- if (ei_sockets_lock == NULL) {
- ei_sockets_lock = ei_mutex_create();
- }
-#endif /* _REENTRANT */
+ if (!ei_connect_initialized)
+ init_connect(!0);
+ if (cbs != &ei_default_socket_callbacks)
+ EI_SET_HAVE_PLUGIN_SOCKET_IMPL__;
+
+ if (cbs_sz < EI_SOCKET_CALLBACKS_SZ_V1) {
+ EI_TRACE_ERR0("ei_connect_xinit","invalid size of ei_socket_callbacks struct");
+ return ERL_ERROR;
+ }
+
ec->creation = creation & 0x3; /* 2 bits */
if (cookie) {
@@ -464,6 +700,9 @@ int ei_connect_xinit(ei_cnode* ec, const char *thishostname,
ec->self.serial = 0;
ec->self.creation = creation & 0x3; /* 2 bits */
+ ec->cbs = cbs;
+ ec->setup_context = setup_context;
+
if ((dbglevel = getenv("EI_TRACELEVEL")) != NULL ||
(dbglevel = getenv("ERL_DEBUG_DIST")) != NULL)
ei_tracelevel = atoi(dbglevel);
@@ -471,31 +710,39 @@ int ei_connect_xinit(ei_cnode* ec, const char *thishostname,
return 0;
}
+int ei_connect_xinit(ei_cnode* ec, const char *thishostname,
+ const char *thisalivename, const char *thisnodename,
+ Erl_IpAddr thisipaddr, const char *cookie,
+ const short creation)
+{
+ return ei_connect_xinit_ussi(ec, thishostname, thisalivename, thisnodename,
+ thisipaddr, cookie, creation,
+ &ei_default_socket_callbacks,
+ sizeof(ei_default_socket_callbacks),
+ NULL);
+}
/*
* Initialize by set: thishostname, thisalivename,
* thisnodename and thisipaddr. At success return 0,
* otherwise return -1.
*/
-int ei_connect_init(ei_cnode* ec, const char* this_node_name,
- const char *cookie, short creation)
+int ei_connect_init_ussi(ei_cnode* ec, const char* this_node_name,
+ const char *cookie, short creation,
+ ei_socket_callbacks *cbs, int cbs_sz,
+ void *setup_context)
{
- struct hostent *hp;
char thishostname[EI_MAXHOSTNAMELEN+1];
char thisnodename[MAXNODELEN+1];
char thisalivename[EI_MAXALIVELEN+1];
+ struct hostent host, *hp;
+ char buffer[1024];
+ char *buf = buffer;
+ int ei_h_errno;
+ int res;
-#ifdef __WIN32__
- if (!initWinSock()) {
- EI_TRACE_ERR0("ei_connect_xinit","can't initiate winsock");
- return ERL_ERROR;
- }
-#endif /* win32 */
-#ifdef _REENTRANT
- if (ei_sockets_lock == NULL) {
- ei_sockets_lock = ei_mutex_create();
- }
-#endif /* _REENTRANT */
+ if (!ei_connect_initialized)
+ init_connect(!0);
/* gethostname requires len to be max(hostname) + 1 */
if (gethostname(thishostname, EI_MAXHOSTNAMELEN+1) == -1) {
@@ -517,10 +764,13 @@ int ei_connect_init(ei_cnode* ec, const char* this_node_name,
strcpy(thisalivename, this_node_name);
}
- if ((hp = ei_gethostbyname(thishostname)) == 0) {
+ hp = dyn_gethostbyname_r(thishostname,&host,&buf,sizeof(buffer),&ei_h_errno);
+ if (hp == NULL) {
/* Looking up IP given hostname fails. We must be on a standalone
host so let's use loopback for communication instead. */
- if ((hp = ei_gethostbyname("localhost")) == 0) {
+ hp = dyn_gethostbyname_r("localhost", &host, &buf, sizeof(buffer),
+ &ei_h_errno);
+ if (hp == NULL) {
#ifdef __WIN32__
char reason[1024];
@@ -541,47 +791,88 @@ int ei_connect_init(ei_cnode* ec, const char* this_node_name,
if (strcmp(hp->h_name, "localhost") == 0) {
/* We use a short node name */
if ((ct = strchr(thishostname, '.')) != NULL) *ct = '\0';
- sprintf(thisnodename, "%s@%s", this_node_name, thishostname);
} else {
/* We use a short node name */
if ((ct = strchr(hp->h_name, '.')) != NULL) *ct = '\0';
strcpy(thishostname, hp->h_name);
- sprintf(thisnodename, "%s@%s", this_node_name, hp->h_name);
}
}
- return ei_connect_xinit(ec, thishostname, thisalivename, thisnodename,
- (struct in_addr *)*hp->h_addr_list, cookie, creation);
+ if (strlen(this_node_name) + 1 + strlen(thishostname) > MAXNODELEN) {
+ EI_TRACE_ERR0("ei_connect_init_ussi","this node name is too long");
+ return ERL_ERROR;
+ }
+ sprintf(thisnodename, "%s@%s", this_node_name, thishostname);
+ res = ei_connect_xinit_ussi(ec, thishostname, thisalivename, thisnodename,
+ (struct in_addr *)*hp->h_addr_list, cookie, creation,
+ cbs, cbs_sz, setup_context);
+ if (buf != buffer)
+ free(buf);
+ return res;
}
+int ei_connect_init(ei_cnode* ec, const char* this_node_name,
+ const char *cookie, short creation)
+{
+ return ei_connect_init_ussi(ec, this_node_name, cookie, creation,
+ &ei_default_socket_callbacks,
+ sizeof(ei_default_socket_callbacks),
+ NULL);
+}
-/* connects to port at ip-address ip_addr
-* and returns fd to socket
-* port has to be in host byte order
-*/
-static int cnct(uint16 port, struct in_addr *ip_addr, int addr_len, unsigned ms)
+/*
+ * Same as ei_gethostbyname_r, but also handles ERANGE error
+ * and may allocate larger buffer with malloc.
+ */
+static
+struct hostent *dyn_gethostbyname_r(const char *name,
+ struct hostent *hostp,
+ char **buffer_p,
+ int buflen,
+ int *h_errnop)
{
- int s, res;
- struct sockaddr_in iserv_addr;
-
- if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- erl_errno = errno;
- return ERL_ERROR;
- }
-
- memset((char*)&iserv_addr, 0, sizeof(struct sockaddr_in));
- memcpy((char*)&iserv_addr.sin_addr, (char*)ip_addr, addr_len);
- iserv_addr.sin_family = AF_INET;
- iserv_addr.sin_port = htons(port);
-
- if ((res = ei_connect_t(s, (struct sockaddr*)&iserv_addr,
- sizeof(iserv_addr),ms)) < 0) {
- erl_errno = (res == -2) ? ETIMEDOUT : EIO;
- closesocket(s);
- return ERL_ERROR;
- }
-
- return s;
-} /* cnct */
+#ifdef __WIN32__
+ /*
+ * Apparently ei_gethostbyname_r not implemented for Windows (?)
+ * Fall back on ei_gethostbyname like before.
+ */
+ return ei_gethostbyname(name);
+#else
+ char* buf = *buffer_p;
+ struct hostent *hp;
+
+ while (1) {
+ hp = ei_gethostbyname_r(name, hostp, buf, buflen, h_errnop);
+ if (hp) {
+ *buffer_p = buf;
+ break;
+ }
+
+ if (*h_errnop != ERANGE) {
+ if (buf != *buffer_p)
+ free(buf);
+ break;
+ }
+
+ buflen *= 2;
+ if (buf == *buffer_p)
+ buf = malloc(buflen);
+ else {
+ char* buf2 = realloc(buf, buflen);
+ if (buf2)
+ buf = buf2;
+ else {
+ free(buf);
+ buf = NULL;
+ }
+ }
+ if (!buf) {
+ *h_errnop = ENOMEM;
+ break;
+ }
+ }
+ return hp;
+#endif
+}
/*
* Set up a connection to a given Node, and
@@ -597,8 +888,15 @@ int ei_connect_tmo(ei_cnode* ec, char *nodename, unsigned ms)
/* these are needed for the call to gethostbyname_r */
struct hostent host;
char buffer[1024];
+ char *buf = buffer;
int ei_h_errno;
#endif /* !win32 */
+ int res;
+
+ if (strlen(nodename) > MAXNODELEN) {
+ EI_TRACE_ERR0("ei_connect","Too long nodename");
+ return ERL_ERROR;
+ }
/* extract the host and alive parts from nodename */
if (!(hostname = strchr(nodename,'@'))) {
@@ -611,7 +909,7 @@ int ei_connect_tmo(ei_cnode* ec, char *nodename, unsigned ms)
}
#ifndef __WIN32__
- hp = ei_gethostbyname_r(hostname,&host,buffer,1024,&ei_h_errno);
+ hp = dyn_gethostbyname_r(hostname,&host,&buf,sizeof(buffer),&ei_h_errno);
if (hp == NULL) {
char thishostname[EI_MAXHOSTNAMELEN+1];
/* gethostname requies len to be max(hostname) + 1*/
@@ -627,7 +925,7 @@ int ei_connect_tmo(ei_cnode* ec, char *nodename, unsigned ms)
}
if (strcmp(hostname,thishostname) == 0)
/* Both nodes on same standalone host, use loopback */
- hp = ei_gethostbyname_r("localhost",&host,buffer,1024,&ei_h_errno);
+ hp = dyn_gethostbyname_r("localhost",&host,&buf,sizeof(buffer),&ei_h_errno);
if (hp == NULL) {
EI_TRACE_ERR2("ei_connect",
"Can't find host for %s: %d\n",nodename,ei_h_errno);
@@ -663,7 +961,14 @@ int ei_connect_tmo(ei_cnode* ec, char *nodename, unsigned ms)
}
}
#endif /* win32 */
- return ei_xconnect_tmo(ec, (Erl_IpAddr) *hp->h_addr_list, alivename, ms);
+
+ res = ei_xconnect_tmo(ec, (Erl_IpAddr) *hp->h_addr_list, alivename, ms);
+
+#ifndef __WIN32__
+ if (buf != buffer)
+ free(buf);
+#endif
+ return res;
} /* ei_connect */
int ei_connect(ei_cnode* ec, char *nodename)
@@ -678,91 +983,218 @@ int ei_connect(ei_cnode* ec, char *nodename)
* the node through epmd at that host
*
*/
-int ei_xconnect_tmo(ei_cnode* ec, Erl_IpAddr adr, char *alivename, unsigned ms)
+int ei_xconnect_tmo(ei_cnode* ec, Erl_IpAddr ip_addr, char *alivename, unsigned ms)
{
- struct in_addr *ip_addr=(struct in_addr *) adr;
+ ei_socket_callbacks *cbs = ec->cbs;
+ void *ctx;
int rport = 0; /*uint16 rport = 0;*/
int sockd;
- int one = 1;
int dist = 0;
- ErlConnect her_name;
unsigned her_flags, her_version;
-
+ unsigned our_challenge, her_challenge;
+ unsigned char our_digest[16];
+ int err;
+ int pkt_sz;
+ struct sockaddr_in addr;
+ unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms;
+
erl_errno = EIO; /* Default error code */
EI_TRACE_CONN1("ei_xconnect","-> CONNECT attempt to connect to %s",
alivename);
- if ((rport = ei_epmd_port_tmo(ip_addr,alivename,&dist, ms)) < 0) {
+ if ((rport = ei_epmd_port_tmo(ip_addr,alivename,&dist, tmo)) < 0) {
EI_TRACE_ERR0("ei_xconnect","-> CONNECT can't get remote port");
/* ei_epmd_port_tmo() has set erl_errno */
return ERL_NO_PORT;
}
-
- /* we now have port number to enode, try to connect */
- if((sockd = cnct((uint16)rport, ip_addr, sizeof(struct in_addr),ms)) < 0) {
- EI_TRACE_ERR0("ei_xconnect","-> CONNECT socket connect failed");
- /* cnct() has set erl_errno */
- return ERL_CONNECT_FAIL;
- }
-
- EI_TRACE_CONN0("ei_xconnect","-> CONNECT connected to remote");
- /* FIXME why connect before checking 'dist' output from ei_epmd_port() ?! */
if (dist <= 4) {
EI_TRACE_ERR0("ei_xconnect","-> CONNECT remote version not compatible");
- goto error;
+ return ERL_ERROR;
}
- else {
- unsigned our_challenge, her_challenge;
- unsigned char our_digest[16];
-
- if (send_name(sockd, ec->thisnodename, (unsigned) dist, ms))
- goto error;
- if (recv_status(sockd, ms))
- goto error;
- if (recv_challenge(sockd, &her_challenge, &her_version,
- &her_flags, &her_name, ms))
- goto error;
- our_challenge = gen_challenge();
- gen_digest(her_challenge, ec->ei_connect_cookie, our_digest);
- if (send_challenge_reply(sockd, our_digest, our_challenge, ms))
- goto error;
- if (recv_challenge_ack(sockd, our_challenge,
- ec->ei_connect_cookie, ms))
- goto error;
- put_ei_socket_info(sockd, dist, null_cookie, ec); /* FIXME check == 0 */
+
+ err = ei_socket_ctx__(cbs, &ctx, ec->setup_context);
+ if (err) {
+ EI_TRACE_ERR2("ei_xconnect","-> SOCKET failed: %s (%d)",
+ estr(err), err);
+ erl_errno = err;
+ return ERL_CONNECT_FAIL;
+ }
+
+ memset((void *) &addr, 0, sizeof(struct sockaddr_in));
+ memcpy((void *) &addr.sin_addr, (void *) ip_addr, sizeof(addr.sin_addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(rport);
+
+ err = ei_connect_ctx_t__(cbs, ctx, (void *) &addr, sizeof(addr), tmo);
+ if (err) {
+ EI_TRACE_ERR2("ei_xconnect","-> CONNECT socket connect failed: %s (%d)",
+ estr(err), err);
+ abort_connection(cbs, ctx);
+ erl_errno = err;
+ return ERL_CONNECT_FAIL;
}
- setsockopt(sockd, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one));
- setsockopt(sockd, SOL_SOCKET, SO_KEEPALIVE, (char *)&one, sizeof(one));
+ EI_TRACE_CONN0("ei_xconnect","-> CONNECT connected to remote");
- EI_TRACE_CONN1("ei_xconnect","-> CONNECT (ok) remote = %s",alivename);
+ err = EI_GET_FD__(cbs, ctx, &sockd);
+ if (err) {
+ EI_CONN_SAVE_ERRNO__(err);
+ goto error;
+ }
+
+ err = cbs->handshake_packet_header_size(ctx, &pkt_sz);
+ if (err) {
+ EI_CONN_SAVE_ERRNO__(err);
+ goto error;
+ }
+
+ if (send_name(cbs, ctx, pkt_sz, ec->thisnodename, (unsigned) dist, tmo))
+ goto error;
+ if (recv_status(cbs, ctx, pkt_sz, tmo))
+ goto error;
+ if (recv_challenge(cbs, ctx, pkt_sz, &her_challenge,
+ &her_version, &her_flags, NULL, tmo))
+ goto error;
+ our_challenge = gen_challenge();
+ gen_digest(her_challenge, ec->ei_connect_cookie, our_digest);
+ if (send_challenge_reply(cbs, ctx, pkt_sz, our_digest, our_challenge, tmo))
+ goto error;
+ if (recv_challenge_ack(cbs, ctx, pkt_sz, our_challenge,
+ ec->ei_connect_cookie, tmo))
+ goto error;
+ if (put_ei_socket_info(sockd, dist, null_cookie, ec, cbs, ctx) != 0)
+ goto error;
+
+ if (cbs->connect_handshake_complete) {
+ err = cbs->connect_handshake_complete(ctx);
+ if (err) {
+ EI_TRACE_ERR2("ei_xconnect","-> CONNECT failed: %s (%d)",
+ estr(err), err);
+ close_connection(cbs, ctx, sockd);
+ EI_CONN_SAVE_ERRNO__(err);
+ return ERL_ERROR;
+ }
+ }
+ EI_TRACE_CONN1("ei_xconnect","-> CONNECT (ok) remote = %s",alivename);
+
erl_errno = 0;
return sockd;
error:
EI_TRACE_ERR0("ei_xconnect","-> CONNECT failed");
- closesocket(sockd);
+ abort_connection(cbs, ctx);
return ERL_ERROR;
} /* ei_xconnect */
-int ei_xconnect(ei_cnode* ec, Erl_IpAddr adr, char *alivename)
+int ei_xconnect(ei_cnode* ec, Erl_IpAddr ip_addr, char *alivename)
{
- return ei_xconnect_tmo(ec, adr, alivename, 0);
+ return ei_xconnect_tmo(ec, ip_addr, alivename, 0);
}
+int ei_listen(ei_cnode *ec, int *port, int backlog)
+{
+ struct in_addr ip_addr;
+ ip_addr.s_addr = htonl(INADDR_ANY);
+ return ei_xlisten(ec, &ip_addr, port, backlog);
+}
+
+int ei_xlisten(ei_cnode *ec, struct in_addr *ip_addr, int *port, int backlog)
+{
+ ei_socket_callbacks *cbs = ec->cbs;
+ struct sockaddr_in sock_addr;
+ void *ctx;
+ int fd, err, len;
+
+ err = ei_socket_ctx__(cbs, &ctx, ec->setup_context);
+ if (err) {
+ EI_TRACE_ERR2("ei_xlisten","-> SOCKET failed: %s (%d)",
+ estr(err), err);
+ erl_errno = err;
+ return ERL_ERROR;
+ }
+
+ memset((void *) &sock_addr, 0, sizeof(struct sockaddr_in));
+ memcpy((void *) &sock_addr.sin_addr, (void *) ip_addr, sizeof(*ip_addr));
+ sock_addr.sin_family = AF_INET;
+ sock_addr.sin_port = htons((short) *port);
+
+ len = sizeof(sock_addr);
+ err = ei_listen_ctx__(cbs, ctx, (void *) &sock_addr, &len, backlog);
+ if (err) {
+ EI_TRACE_ERR2("ei_xlisten","-> listen failed: %s (%d)",
+ estr(err), err);
+ erl_errno = err;
+ goto error;
+ }
+
+ if (len != sizeof(sock_addr)) {
+ if (len < offsetof(struct sockaddr_in, sin_addr) + sizeof(sock_addr.sin_addr)
+ || len < offsetof(struct sockaddr_in, sin_port) + sizeof(sock_addr.sin_port)) {
+ erl_errno = EIO;
+ EI_TRACE_ERR0("ei_xlisten","-> get info failed");
+ goto error;
+ }
+ }
+
+ memcpy((void *) ip_addr, (void *) &sock_addr.sin_addr, sizeof(*ip_addr));
+ *port = (int) ntohs(sock_addr.sin_port);
+
+ err = EI_GET_FD__(cbs, ctx, &fd);
+ if (err) {
+ erl_errno = err;
+ goto error;
+ }
+
+ if (put_ei_socket_info(fd, 0, null_cookie, ec, cbs, ctx) != 0) {
+ EI_TRACE_ERR0("ei_xlisten","-> save socket info failed");
+ erl_errno = EIO;
+ goto error;
+ }
+
+ erl_errno = 0;
+
+ return fd;
+
+error:
+ abort_connection(cbs, ctx);
+ return ERL_ERROR;
+}
+
+static int close_connection(ei_socket_callbacks *cbs, void *ctx, int fd)
+{
+ int err;
+ remove_ei_socket_info(fd);
+ err = ei_close_ctx__(cbs, ctx);
+ if (err) {
+ erl_errno = err;
+ return ERL_ERROR;
+ }
+ return 0;
+}
- /*
- * For symmetry reasons
-*/
-#if 0
int ei_close_connection(int fd)
{
- return closesocket(fd);
+ ei_socket_callbacks *cbs;
+ void *ctx;
+ int err = EI_GET_CBS_CTX__(&cbs, &ctx, fd);
+ if (err)
+ erl_errno = err;
+ else {
+ if (close_connection(cbs, ctx, fd) == 0)
+ return 0;
+ }
+ EI_TRACE_ERR2("ei_close_connection","<- CLOSE socket close failed: %s (%d)",
+ estr(erl_errno), erl_errno);
+ return ERL_ERROR;
} /* ei_close_connection */
-#endif
+
+static void abort_connection(ei_socket_callbacks *cbs, void *ctx)
+{
+ (void) ei_close_ctx__(cbs, ctx);
+}
/*
* Accept and initiate a connection from another
@@ -777,25 +1209,71 @@ int ei_accept(ei_cnode* ec, int lfd, ErlConnect *conp)
int ei_accept_tmo(ei_cnode* ec, int lfd, ErlConnect *conp, unsigned ms)
{
int fd;
- struct sockaddr_in cli_addr;
- int cli_addr_len=sizeof(struct sockaddr_in);
unsigned her_version, her_flags;
- ErlConnect her_name;
+ char tmp_nodename[MAXNODELEN+1];
+ char *her_name;
+ int pkt_sz, err;
+ struct sockaddr_in addr;
+ int addr_len = sizeof(struct sockaddr_in);
+ ei_socket_callbacks *cbs;
+ void *ctx;
+ unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms;
erl_errno = EIO; /* Default error code */
+
+ err = EI_GET_CBS_CTX__(&cbs, &ctx, lfd);
+ if (err) {
+ EI_CONN_SAVE_ERRNO__(err);
+ return ERL_ERROR;
+ }
+
EI_TRACE_CONN0("ei_accept","<- ACCEPT waiting for connection");
+
+ if (conp) {
+ her_name = &conp->nodename[0];
+ }
+ else {
+ her_name = &tmp_nodename[0];
+ }
- if ((fd = ei_accept_t(lfd, (struct sockaddr*) &cli_addr,
- &cli_addr_len, ms )) < 0) {
- EI_TRACE_ERR0("ei_accept","<- ACCEPT socket accept failed");
- erl_errno = (fd == -2) ? ETIMEDOUT : EIO;
- goto error;
+ /*
+ * ei_accept_ctx_t__() replaces the pointer to the listen context
+ * with a pointer to the accepted connection context on success.
+ */
+ err = ei_accept_ctx_t__(cbs, &ctx, (void *) &addr, &addr_len, tmo);
+ if (err) {
+ EI_TRACE_ERR2("ei_accept","<- ACCEPT socket accept failed: %s (%d)",
+ estr(err), err);
+ EI_CONN_SAVE_ERRNO__(err);
+ return ERL_ERROR;
+ }
+
+ err = EI_GET_FD__(cbs, ctx, &fd);
+ if (err) {
+ EI_TRACE_ERR2("ei_accept","<- ACCEPT get fd failed: %s (%d)",
+ estr(err), err);
+ EI_CONN_SAVE_ERRNO__(err);
+ }
+
+ if (addr_len != sizeof(struct sockaddr_in)) {
+ if (addr_len < (offsetof(struct sockaddr_in, sin_addr)
+ + sizeof(addr.sin_addr))) {
+ EI_TRACE_ERR0("ei_accept","<- ACCEPT get addr failed");
+ goto error;
+ }
+ }
+
+ err = cbs->handshake_packet_header_size(ctx, &pkt_sz);
+ if (err) {
+ EI_TRACE_ERR2("ei_accept","<- ACCEPT get packet size failed: %s (%d)",
+ estr(err), err);
+ EI_CONN_SAVE_ERRNO__(err);
}
EI_TRACE_CONN0("ei_accept","<- ACCEPT connected to remote");
- if (recv_name(fd, &her_version, &her_flags, &her_name, ms)) {
+ if (recv_name(cbs, ctx, pkt_sz, &her_version, &her_flags, her_name, tmo)) {
EI_TRACE_ERR0("ei_accept","<- ACCEPT initial ident failed");
goto error;
}
@@ -808,34 +1286,45 @@ int ei_accept_tmo(ei_cnode* ec, int lfd, ErlConnect *conp, unsigned ms)
unsigned our_challenge;
unsigned her_challenge;
unsigned char our_digest[16];
-
- if (send_status(fd,"ok", ms))
+
+ if (send_status(cbs, ctx, pkt_sz, "ok", tmo))
goto error;
our_challenge = gen_challenge();
- if (send_challenge(fd, ec->thisnodename,
- our_challenge, her_version, ms))
+ if (send_challenge(cbs, ctx, pkt_sz, ec->thisnodename,
+ our_challenge, her_version, tmo))
goto error;
- if (recv_challenge_reply(fd, our_challenge,
- ec->ei_connect_cookie,
- &her_challenge, ms))
+ if (recv_challenge_reply(cbs, ctx, pkt_sz, our_challenge,
+ ec->ei_connect_cookie, &her_challenge, tmo))
goto error;
gen_digest(her_challenge, ec->ei_connect_cookie, our_digest);
- if (send_challenge_ack(fd, our_digest, ms))
+ if (send_challenge_ack(cbs, ctx, pkt_sz, our_digest, tmo))
goto error;
- put_ei_socket_info(fd, her_version, null_cookie, ec);
+ if (put_ei_socket_info(fd, her_version, null_cookie, ec, cbs, ctx) != 0)
+ goto error;
+ }
+ if (conp) {
+ memcpy((void *) conp->ipadr, (void *) &addr.sin_addr, sizeof(conp->ipadr));
+ }
+
+ if (cbs->accept_handshake_complete) {
+ err = cbs->accept_handshake_complete(ctx);
+ if (err) {
+ EI_TRACE_ERR2("ei_xconnect","-> ACCEPT handshake failed: %s (%d)",
+ estr(err), err);
+ close_connection(cbs, ctx, fd);
+ EI_CONN_SAVE_ERRNO__(err);
+ return ERL_ERROR;
+ }
}
- if (conp)
- *conp = her_name;
- EI_TRACE_CONN1("ei_accept","<- ACCEPT (ok) remote = %s",her_name.nodename);
+ EI_TRACE_CONN1("ei_accept","<- ACCEPT (ok) remote = %s",her_name);
erl_errno = 0; /* No error */
return fd;
error:
EI_TRACE_ERR0("ei_accept","<- ACCEPT failed");
- if (fd>=0)
- closesocket(fd);
+ abort_connection(cbs, ctx);
return ERL_ERROR;
} /* ei_accept */
@@ -847,36 +1336,57 @@ error:
*/
int ei_receive_tmo(int fd, unsigned char *bufp, int bufsize, unsigned ms)
{
- int len;
+ ssize_t len;
unsigned char fourbyte[4]={0,0,0,0};
- int res;
-
- if ((res = ei_read_fill_t(fd, (char *) bufp, 4, ms)) != 4) {
- erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ int err;
+ ei_socket_callbacks *cbs;
+ void *ctx;
+ unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms;
+
+ err = EI_GET_CBS_CTX__(&cbs, &ctx, fd);
+ if (err) {
+ EI_CONN_SAVE_ERRNO__(err);
+ return ERL_ERROR;
+ }
+
+ len = (ssize_t) 4;
+ err = ei_read_fill_ctx_t__(cbs, ctx, (char *) bufp, &len, tmo);
+ if (!err && len != (ssize_t) 4)
+ err = EIO;
+ if (err) {
+ EI_CONN_SAVE_ERRNO__(err);
return ERL_ERROR;
}
/* Tick handling */
- if ((len = get_int32(bufp)) == ERL_TICK)
- {
- ei_write_fill_t(fd, (char *) fourbyte, 4, ms);
+ len = get_int32(bufp);
+ if (len == ERL_TICK) {
+ len = 4;
+ ei_write_fill_ctx_t__(cbs, ctx, (char *) fourbyte, &len, tmo);
/* FIXME ok to ignore error or timeout? */
erl_errno = EAGAIN;
return ERL_TICK;
}
- else if (len > bufsize)
- {
+
+ if (len > bufsize) {
/* FIXME: We should drain the message. */
erl_errno = EMSGSIZE;
return ERL_ERROR;
}
- else if ((res = ei_read_fill_t(fd, (char *) bufp, len, ms)) != len)
- {
- erl_errno = (res == -2) ? ETIMEDOUT : EIO;
- return ERL_ERROR;
+ else {
+ ssize_t need = len;
+ err = ei_read_fill_ctx_t__(cbs, ctx, (char *) bufp, &len, tmo);
+ if (err) {
+ EI_CONN_SAVE_ERRNO__(err);
+ return ERL_ERROR;
+ }
+ if (len != need) {
+ erl_errno = EIO;
+ return ERL_ERROR;
+ }
}
- return len;
+ return (int) len;
}
@@ -942,7 +1452,7 @@ int ei_do_receive_msg(int fd, int staticbuffer_p,
erl_errno = EMSGSIZE;
return ERL_ERROR;
}
- x->index = x->buffsz;
+ x->index = msglen;
switch (msg->msgtype) { /* FIXME does not handle trace tokens and monitors */
case ERL_SEND:
case ERL_REG_SEND:
@@ -1032,36 +1542,11 @@ int ei_rpc_to(ei_cnode *ec, int fd, char *mod, char *fun,
int ei_rpc_from(ei_cnode *ec, int fd, int timeout, erlang_msg *msg,
ei_x_buff *x)
{
- fd_set readmask;
- struct timeval tv;
- struct timeval *t = NULL;
-
- if (timeout >= 0) {
- tv.tv_sec = timeout / 1000;
- tv.tv_usec = (timeout % 1000) * 1000;
- t = &tv;
- }
-
- FD_ZERO(&readmask);
- FD_SET(fd,&readmask);
-
- switch (select(fd+1, &readmask, NULL, NULL, t)) {
- case -1:
- erl_errno = EIO;
- return ERL_ERROR;
-
- case 0:
- erl_errno = ETIMEDOUT;
- return ERL_TIMEOUT;
-
- default:
- if (FD_ISSET(fd, &readmask)) {
- return ei_xreceive_msg(fd, msg, x);
- } else {
- erl_errno = EIO;
- return ERL_ERROR;
- }
- }
+ unsigned tmo = timeout < 0 ? EI_SCLBK_INF_TMO : (unsigned) timeout;
+ int res = ei_xreceive_msg_tmo(fd, msg, x, tmo);
+ if (res < 0 && erl_errno == ETIMEDOUT)
+ return ERL_TIMEOUT;
+ return res;
} /* rpc_from */
/*
@@ -1215,19 +1700,34 @@ static char *hex(char digest[16], char buff[33])
return buff;
}
-static int read_2byte_package(int fd, char **buf, int *buflen,
- int *is_static, unsigned ms)
+static int read_hs_package(ei_socket_callbacks *cbs, void *ctx,
+ int pkt_sz, char **buf, int *buflen,
+ int *is_static, unsigned ms)
{
- unsigned char nbuf[2];
+ unsigned char nbuf[4];
unsigned char *x = nbuf;
- unsigned len;
- int res;
-
- if((res = ei_read_fill_t(fd, (char *)nbuf, 2, ms)) != 2) {
- erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ ssize_t len, need;
+ int err;
+
+ len = (ssize_t) pkt_sz;
+ err = ei_read_fill_ctx_t__(cbs, ctx, (char *)nbuf, &len, ms);
+ if (!err && len != (ssize_t) pkt_sz)
+ err = EIO;
+ if (err) {
+ EI_CONN_SAVE_ERRNO__(err);
return -1;
}
- len = get16be(x);
+
+ switch (pkt_sz) {
+ case 2:
+ len = get16be(x);
+ break;
+ case 4:
+ len = get32be(x);
+ break;
+ default:
+ return -1;
+ }
if (len > *buflen) {
if (*is_static) {
@@ -1249,20 +1749,26 @@ static int read_2byte_package(int fd, char **buf, int *buflen,
*buflen = len;
}
}
- if ((res = ei_read_fill_t(fd, *buf, len, ms)) != len) {
- erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ need = len;
+ err = ei_read_fill_ctx_t__(cbs, ctx, *buf, &len, ms);
+ if (!err && len != need)
+ err = EIO;
+ if (err) {
+ EI_CONN_SAVE_ERRNO__(err);
return -1;
}
return len;
}
-static int send_status(int fd, char *status, unsigned ms)
+static int send_status(ei_socket_callbacks *cbs, void *ctx,
+ int pkt_sz, char *status, unsigned ms)
{
char *buf, *s;
char dbuf[DEFBUF_SIZ];
- int siz = strlen(status) + 1 + 2;
- int res;
+ int siz = strlen(status) + 1 + pkt_sz;
+ int err;
+ ssize_t len;
buf = (siz > DEFBUF_SIZ) ? malloc(siz) : dbuf;
if (!buf) {
@@ -1270,14 +1776,28 @@ static int send_status(int fd, char *status, unsigned ms)
return -1;
}
s = buf;
- put16be(s,siz - 2);
+ switch (pkt_sz) {
+ case 2:
+ put16be(s,siz - 2);
+ break;
+ case 4:
+ put32be(s,siz - 4);
+ break;
+ default:
+ return -1;
+ }
put8(s, 's');
memcpy(s, status, strlen(status));
- if ((res = ei_write_fill_t(fd, buf, siz, ms)) != siz) {
- EI_TRACE_ERR0("send_status","-> SEND_STATUS socket write failed");
+ len = (ssize_t) siz;
+ err = ei_write_fill_ctx_t__(cbs, ctx, buf, &len, ms);
+ if (!err && len != (ssize_t) siz)
+ err = EIO;
+ if (err) {
+ EI_TRACE_ERR2("send_status","-> SEND_STATUS socket write failed: %s (%d)",
+ estr(err), err);
if (buf != dbuf)
- free(buf);
- erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ free(buf);
+ EI_CONN_SAVE_ERRNO__(err);
return -1;
}
EI_TRACE_CONN1("send_status","-> SEND_STATUS (%s)",status);
@@ -1287,7 +1807,8 @@ static int send_status(int fd, char *status, unsigned ms)
return 0;
}
-static int recv_status(int fd, unsigned ms)
+static int recv_status(ei_socket_callbacks *cbs, void *ctx,
+ int pkt_sz, unsigned ms)
{
char dbuf[DEFBUF_SIZ];
char *buf = dbuf;
@@ -1295,16 +1816,20 @@ static int recv_status(int fd, unsigned ms)
int buflen = DEFBUF_SIZ;
int rlen;
- if ((rlen = read_2byte_package(fd, &buf, &buflen, &is_static, ms)) <= 0) {
+ if ((rlen = read_hs_package(cbs, ctx, pkt_sz,
+ &buf, &buflen, &is_static, ms)) <= 0) {
EI_TRACE_ERR1("recv_status",
"<- RECV_STATUS socket read failed (%d)", rlen);
goto error;
}
- if (rlen == 3 && buf[0] == 's' && buf[1] == 'o' &&
- buf[2] == 'k') {
+
+ EI_TRACE_CONN2("recv_status",
+ "<- RECV_STATUS (%.*s)", (rlen>20 ? 20 : rlen), buf);
+
+ if (rlen >= 3 && buf[0] == 's' && buf[1] == 'o' && buf[2] == 'k') {
+ /* Expecting "sok" or "sok_simultaneous" */
if (!is_static)
free(buf);
- EI_TRACE_CONN0("recv_status","<- RECV_STATUS (ok)");
return 0;
}
error:
@@ -1313,7 +1838,10 @@ error:
return -1;
}
-static int send_name_or_challenge(int fd, char *nodename,
+static int send_name_or_challenge(ei_socket_callbacks *cbs,
+ void *ctx,
+ int pkt_sz,
+ char *nodename,
int f_chall,
unsigned challenge,
unsigned version,
@@ -1322,9 +1850,11 @@ static int send_name_or_challenge(int fd, char *nodename,
char *buf;
unsigned char *s;
char dbuf[DEFBUF_SIZ];
- int siz = 2 + 1 + 2 + 4 + strlen(nodename);
+ int siz = pkt_sz + 1 + 2 + 4 + strlen(nodename);
const char* function[] = {"SEND_NAME", "SEND_CHALLENGE"};
- int res;
+ int err;
+ ssize_t len;
+ unsigned int flags;
if (f_chall)
siz += 4;
@@ -1334,10 +1864,19 @@ static int send_name_or_challenge(int fd, char *nodename,
return -1;
}
s = (unsigned char *)buf;
- put16be(s,siz - 2);
+ switch (pkt_sz) {
+ case 2:
+ put16be(s,siz - 2);
+ break;
+ case 4:
+ put32be(s,siz - 4);
+ break;
+ default:
+ return -1;
+ }
put8(s, 'n');
put16be(s, version);
- put32be(s, (DFLAG_EXTENDED_REFERENCES
+ flags = (DFLAG_EXTENDED_REFERENCES
| DFLAG_DIST_MONITOR
| DFLAG_EXTENDED_PIDS_PORTS
| DFLAG_FUN_TAGS
@@ -1346,17 +1885,27 @@ static int send_name_or_challenge(int fd, char *nodename,
| DFLAG_SMALL_ATOM_TAGS
| DFLAG_UTF8_ATOMS
| DFLAG_MAP_TAG
- | DFLAG_BIG_CREATION));
+ | DFLAG_BIG_CREATION
+ | DFLAG_EXPORT_PTR_TAG
+ | DFLAG_BIT_BINARIES);
+ if (ei_internal_use_21_bitstr_expfun()) {
+ flags &= ~(DFLAG_EXPORT_PTR_TAG
+ | DFLAG_BIT_BINARIES);
+ }
+ put32be(s, flags);
if (f_chall)
put32be(s, challenge);
memcpy(s, nodename, strlen(nodename));
-
- if ((res = ei_write_fill_t(fd, buf, siz, ms)) != siz) {
+ len = (ssize_t) siz;
+ err = ei_write_fill_ctx_t__(cbs, ctx, buf, &len, ms);
+ if (!err && len != (ssize_t) siz)
+ err = EIO;
+ if (err) {
EI_TRACE_ERR1("send_name_or_challenge",
"-> %s socket write failed", function[f_chall]);
if (buf != dbuf)
free(buf);
- erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ EI_CONN_SAVE_ERRNO__(err);
return -1;
}
@@ -1365,9 +1914,9 @@ static int send_name_or_challenge(int fd, char *nodename,
return 0;
}
-static int recv_challenge(int fd, unsigned *challenge,
- unsigned *version,
- unsigned *flags, ErlConnect *namebuf, unsigned ms)
+static int recv_challenge(ei_socket_callbacks *cbs, void *ctx,
+ int pkt_sz, unsigned *challenge, unsigned *version,
+ unsigned *flags, char *namebuf, unsigned ms)
{
char dbuf[DEFBUF_SIZ];
char *buf = dbuf;
@@ -1375,13 +1924,13 @@ static int recv_challenge(int fd, unsigned *challenge,
int buflen = DEFBUF_SIZ;
int rlen;
char *s;
- struct sockaddr_in sin;
- socklen_t sin_len = sizeof(sin);
char tag;
-
+ char tmp_nodename[MAXNODELEN+1];
+
erl_errno = EIO; /* Default */
- if ((rlen = read_2byte_package(fd, &buf, &buflen, &is_static, ms)) <= 0) {
+ if ((rlen = read_hs_package(cbs, ctx, pkt_sz, &buf, &buflen,
+ &is_static, ms)) <= 0) {
EI_TRACE_ERR1("recv_challenge",
"<- RECV_CHALLENGE socket read failed (%d)",rlen);
goto error;
@@ -1408,8 +1957,7 @@ static int recv_challenge(int fd, unsigned *challenge,
goto error;
}
- if (!(*flags & DFLAG_EXTENDED_PIDS_PORTS)
- && !ei_internal_use_r9_pids_ports()) {
+ if (!(*flags & DFLAG_EXTENDED_PIDS_PORTS)) {
EI_TRACE_ERR0("recv_challenge","<- RECV_CHALLENGE peer cannot "
"handle extended pids and ports");
erl_errno = EIO;
@@ -1422,22 +1970,19 @@ static int recv_challenge(int fd, unsigned *challenge,
goto error;
}
- if (getpeername(fd, (struct sockaddr *) &sin, &sin_len) < 0) {
- EI_TRACE_ERR0("recv_challenge","<- RECV_CHALLENGE can't get peername");
- erl_errno = errno;
- goto error;
- }
- memcpy(namebuf->ipadr, &(sin.sin_addr.s_addr),
- sizeof(sin.sin_addr.s_addr));
- memcpy(namebuf->nodename, s, rlen - 11);
- namebuf->nodename[rlen - 11] = '\0';
+ if (!namebuf)
+ namebuf = &tmp_nodename[0];
+
+ memcpy(namebuf, s, rlen - 11);
+ namebuf[rlen - 11] = '\0';
+
if (!is_static)
free(buf);
EI_TRACE_CONN4("recv_challenge","<- RECV_CHALLENGE (ok) node = %s, "
"version = %u, "
"flags = %u, "
"challenge = %d",
- namebuf->nodename,
+ namebuf,
*version,
*flags,
*challenge
@@ -1450,24 +1995,40 @@ error:
return -1;
}
-static int send_challenge_reply(int fd, unsigned char digest[16],
+static int send_challenge_reply(ei_socket_callbacks *cbs, void *ctx,
+ int pkt_sz, unsigned char digest[16],
unsigned challenge, unsigned ms)
{
char *s;
char buf[DEFBUF_SIZ];
- int siz = 2 + 1 + 4 + 16;
- int res;
+ int siz = pkt_sz + 1 + 4 + 16;
+ int err;
+ ssize_t len;
s = buf;
- put16be(s,siz - 2);
+ switch (pkt_sz) {
+ case 2:
+ put16be(s,siz - 2);
+ break;
+ case 4:
+ put32be(s,siz - 4);
+ break;
+ default:
+ return -1;
+ }
put8(s, 'r');
put32be(s, challenge);
memcpy(s, digest, 16);
-
- if ((res = ei_write_fill_t(fd, buf, siz, ms)) != siz) {
- EI_TRACE_ERR0("send_challenge_reply",
- "-> SEND_CHALLENGE_REPLY socket write failed");
- erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+
+ len = (ssize_t) siz;
+ err = ei_write_fill_ctx_t__(cbs, ctx, buf, &len, ms);
+ if (!err && len != (ssize_t) siz)
+ err = EIO;
+ if (err) {
+ EI_TRACE_ERR2("send_challenge_reply",
+ "-> SEND_CHALLENGE_REPLY socket write failed: %s (%d)",
+ estr(err), err);
+ EI_CONN_SAVE_ERRNO__(err);
return -1;
}
@@ -1480,11 +2041,13 @@ static int send_challenge_reply(int fd, unsigned char digest[16],
return 0;
}
-static int recv_challenge_reply (int fd,
- unsigned our_challenge,
- char cookie[],
- unsigned *her_challenge,
- unsigned ms)
+static int recv_challenge_reply(ei_socket_callbacks *cbs,
+ void *ctx,
+ int pkt_sz,
+ unsigned our_challenge,
+ char cookie[],
+ unsigned *her_challenge,
+ unsigned ms)
{
char dbuf[DEFBUF_SIZ];
char *buf = dbuf;
@@ -1497,7 +2060,7 @@ static int recv_challenge_reply (int fd,
erl_errno = EIO; /* Default */
- if ((rlen = read_2byte_package(fd, &buf, &buflen, &is_static, ms)) != 21) {
+ if ((rlen = read_hs_package(cbs, ctx, pkt_sz, &buf, &buflen, &is_static, ms)) != 21) {
EI_TRACE_ERR1("recv_challenge_reply",
"<- RECV_CHALLENGE_REPLY socket read failed (%d)",rlen);
goto error;
@@ -1537,23 +2100,38 @@ error:
return -1;
}
-static int send_challenge_ack(int fd, unsigned char digest[16], unsigned ms)
+static int send_challenge_ack(ei_socket_callbacks *cbs, void *ctx, int pkt_sz,
+ unsigned char digest[16], unsigned ms)
{
char *s;
char buf[DEFBUF_SIZ];
- int siz = 2 + 1 + 16;
- int res;
+ int siz = pkt_sz + 1 + 16;
+ int err;
+ ssize_t len;
s = buf;
-
- put16be(s,siz - 2);
+ switch (pkt_sz) {
+ case 2:
+ put16be(s,siz - 2);
+ break;
+ case 4:
+ put32be(s,siz - 4);
+ break;
+ default:
+ return -1;
+ }
put8(s, 'a');
memcpy(s, digest, 16);
- if ((res = ei_write_fill_t(fd, buf, siz, ms)) != siz) {
- EI_TRACE_ERR0("recv_challenge_reply",
- "-> SEND_CHALLENGE_ACK socket write failed");
- erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ len = (ssize_t) siz;
+ err = ei_write_fill_ctx_t__(cbs, ctx, buf, &len, ms);
+ if (!err && len != (ssize_t) siz)
+ err = EIO;
+ if (err) {
+ EI_TRACE_ERR2("recv_challenge_reply",
+ "-> SEND_CHALLENGE_ACK socket write failed: %s (%d)",
+ estr(err), err);
+ EI_CONN_SAVE_ERRNO__(err);
return -1;
}
@@ -1566,8 +2144,8 @@ static int send_challenge_ack(int fd, unsigned char digest[16], unsigned ms)
return 0;
}
-static int recv_challenge_ack(int fd,
- unsigned our_challenge,
+static int recv_challenge_ack(ei_socket_callbacks *cbs, void *ctx,
+ int pkt_sz, unsigned our_challenge,
char cookie[], unsigned ms)
{
char dbuf[DEFBUF_SIZ];
@@ -1581,7 +2159,7 @@ static int recv_challenge_ack(int fd,
erl_errno = EIO; /* Default */
- if ((rlen = read_2byte_package(fd, &buf, &buflen, &is_static, ms)) != 17) {
+ if ((rlen = read_hs_package(cbs, ctx, pkt_sz, &buf, &buflen, &is_static, ms)) != 17) {
EI_TRACE_ERR1("recv_challenge_ack",
"<- RECV_CHALLENGE_ACK socket read failed (%d)",rlen);
goto error;
@@ -1618,20 +2196,24 @@ error:
return -1;
}
-static int send_name(int fd, char *nodename, unsigned version, unsigned ms)
+static int send_name(ei_socket_callbacks *cbs, void *ctx, int pkt_sz,
+ char *nodename, unsigned version, unsigned ms)
{
- return send_name_or_challenge(fd, nodename, 0, 0, version, ms);
+ return send_name_or_challenge(cbs, ctx, pkt_sz, nodename, 0,
+ 0, version, ms);
}
-static int send_challenge(int fd, char *nodename,
- unsigned challenge, unsigned version, unsigned ms)
+static int send_challenge(ei_socket_callbacks *cbs, void *ctx, int pkt_sz,
+ char *nodename, unsigned challenge, unsigned version,
+ unsigned ms)
{
- return send_name_or_challenge(fd, nodename, 1, challenge, version, ms);
+ return send_name_or_challenge(cbs, ctx, pkt_sz, nodename, 1,
+ challenge, version, ms);
}
-static int recv_name(int fd,
- unsigned *version,
- unsigned *flags, ErlConnect *namebuf, unsigned ms)
+static int recv_name(ei_socket_callbacks *cbs, void *ctx,
+ int pkt_sz, unsigned *version,
+ unsigned *flags, char *namebuf, unsigned ms)
{
char dbuf[DEFBUF_SIZ];
char *buf = dbuf;
@@ -1639,13 +2221,13 @@ static int recv_name(int fd,
int buflen = DEFBUF_SIZ;
int rlen;
char *s;
- struct sockaddr_in sin;
- socklen_t sin_len = sizeof(sin);
+ char tmp_nodename[MAXNODELEN+1];
char tag;
erl_errno = EIO; /* Default */
- if ((rlen = read_2byte_package(fd, &buf, &buflen, &is_static, ms)) <= 0) {
+ if ((rlen = read_hs_package(cbs, ctx, pkt_sz, &buf, &buflen,
+ &is_static, ms)) <= 0) {
EI_TRACE_ERR1("recv_name","<- RECV_NAME socket read failed (%d)",rlen);
goto error;
}
@@ -1669,28 +2251,24 @@ static int recv_name(int fd,
goto error;
}
- if (!(*flags & DFLAG_EXTENDED_PIDS_PORTS)
- && !ei_internal_use_r9_pids_ports()) {
+ if (!(*flags & DFLAG_EXTENDED_PIDS_PORTS)) {
EI_TRACE_ERR0("recv_name","<- RECV_NAME peer cannot "
"handle extended pids and ports");
erl_errno = EIO;
goto error;
}
-
- if (getpeername(fd, (struct sockaddr *) &sin, &sin_len) < 0) {
- EI_TRACE_ERR0("recv_name","<- RECV_NAME can't get peername");
- erl_errno = errno;
- goto error;
- }
- memcpy(namebuf->ipadr, &(sin.sin_addr.s_addr),
- sizeof(sin.sin_addr.s_addr));
- memcpy(namebuf->nodename, s, rlen - 7);
- namebuf->nodename[rlen - 7] = '\0';
+
+ if (!namebuf)
+ namebuf = &tmp_nodename[0];
+
+ memcpy(namebuf, s, rlen - 7);
+ namebuf[rlen - 7] = '\0';
+
if (!is_static)
free(buf);
EI_TRACE_CONN3("recv_name",
"<- RECV_NAME (ok) node = %s, version = %u, flags = %u",
- namebuf->nodename,*version,*flags);
+ namebuf,*version,*flags);
erl_errno = 0;
return 0;
@@ -1784,3 +2362,4 @@ static int get_cookie(char *buf, int bufsize)
return 1; /* Success! */
}
+
diff --git a/lib/erl_interface/src/connect/ei_connect_int.h b/lib/erl_interface/src/connect/ei_connect_int.h
index 0bcccaa84b..b41a5f2b23 100644
--- a/lib/erl_interface/src/connect/ei_connect_int.h
+++ b/lib/erl_interface/src/connect/ei_connect_int.h
@@ -102,6 +102,8 @@ extern int h_errno;
#define DFLAG_FUN_TAGS 16
#define DFLAG_NEW_FUN_TAGS 0x80
#define DFLAG_EXTENDED_PIDS_PORTS 0x100
+#define DFLAG_EXPORT_PTR_TAG 0x200
+#define DFLAG_BIT_BINARIES 0x400
#define DFLAG_NEW_FLOATS 0x800
#define DFLAG_SMALL_ATOM_TAGS 0x4000
#define DFLAG_UTF8_ATOMS 0x10000
diff --git a/lib/erl_interface/src/connect/ei_resolve.c b/lib/erl_interface/src/connect/ei_resolve.c
index fd0c659373..225fddc784 100644
--- a/lib/erl_interface/src/connect/ei_resolve.c
+++ b/lib/erl_interface/src/connect/ei_resolve.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2016. All Rights Reserved.
+ * Copyright Ericsson AB 1997-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -57,9 +57,9 @@
#ifdef HAVE_GETHOSTBYNAME_R
-void ei_init_resolve(void)
+int ei_init_resolve(void)
{
- return; /* Do nothing */
+ return 0; /* Do nothing */
}
#else /* !HAVE_GETHOSTBYNAME_R */
@@ -103,7 +103,7 @@ static int verify_dns_configuration(void);
* our own, which are just wrappers around hostGetByName() and
* hostGetByAddr(). Here we look up the functions.
*/
-void ei_init_resolve(void)
+int ei_init_resolve(void)
{
#ifdef VXWORKS
@@ -134,9 +134,12 @@ void ei_init_resolve(void)
#ifdef _REENTRANT
ei_gethost_sem = ei_mutex_create();
+ if (!ei_gethost_sem)
+ return ENOMEM;
#endif /* _REENTRANT */
ei_resolve_initialized = 1;
+ return 0;
}
#ifdef VXWORKS
@@ -312,9 +315,11 @@ static struct hostent *my_gethostbyname_r(const char *name,
struct hostent *src;
struct hostent *rval = NULL;
- /* FIXME this should have been done in 'erl'_init()? */
- if (!ei_resolve_initialized) ei_init_resolve();
-
+ if (!ei_resolve_initialized) {
+ *h_errnop = NO_RECOVERY;
+ return NULL;
+ }
+
#ifdef _REENTRANT
/* === BEGIN critical section === */
if (ei_mutex_lock(ei_gethost_sem,0) != 0) {
@@ -377,7 +382,10 @@ static struct hostent *my_gethostbyaddr_r(const char *addr,
struct hostent *rval = NULL;
/* FIXME this should have been done in 'erl'_init()? */
- if (!ei_resolve_initialized) ei_init_resolve();
+ if (!ei_resolve_initialized) {
+ *h_errnop = NO_RECOVERY;
+ return NULL;
+ }
#ifdef _REENTRANT
/* === BEGIN critical section === */
@@ -645,8 +653,11 @@ struct hostent *ei_gethostbyname_r(const char *name,
#else
#if (defined(__GLIBC__) || defined(__linux__) || (__FreeBSD_version >= 602000) || defined(__DragonFly__) || defined(__ANDROID__))
struct hostent *result;
+ int err;
- gethostbyname_r(name, hostp, buffer, buflen, &result, h_errnop);
+ err = gethostbyname_r(name, hostp, buffer, buflen, &result, h_errnop);
+ if (err == ERANGE)
+ *h_errnop = err;
return result;
#else
diff --git a/lib/erl_interface/src/connect/ei_resolve.h b/lib/erl_interface/src/connect/ei_resolve.h
index 10a49ffbc6..5711d7da76 100644
--- a/lib/erl_interface/src/connect/ei_resolve.h
+++ b/lib/erl_interface/src/connect/ei_resolve.h
@@ -20,6 +20,6 @@
#ifndef _EI_RESOLVE_H
#define _EI_RESOLVE_H
-void ei_init_resolve(void);
+int ei_init_resolve(void);
#endif /* _EI_RESOLVE_H */
diff --git a/lib/erl_interface/src/connect/eirecv.c b/lib/erl_interface/src/connect/eirecv.c
index 7b9dbfc387..47eea06ced 100644
--- a/lib/erl_interface/src/connect/eirecv.c
+++ b/lib/erl_interface/src/connect/eirecv.c
@@ -60,22 +60,36 @@ ei_recv_internal (int fd,
int arity;
int version;
int index = 0;
- int i = 0;
- int res;
+ int err;
int show_this_msg = 0;
+ ei_socket_callbacks *cbs;
+ void *ctx;
+ ssize_t rlen;
+ unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms;
+
+ err = EI_GET_CBS_CTX__(&cbs, &ctx, fd);
+ if (err) {
+ EI_CONN_SAVE_ERRNO__(err);
+ return -1;
+ }
/* get length field */
- if ((res = ei_read_fill_t(fd, header, 4, ms)) != 4)
- {
- erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ rlen = 4;
+ err = ei_read_fill_ctx_t__(cbs, ctx, header, &rlen, tmo);
+ if (!err && rlen != 4)
+ err = EIO;
+ if (err) {
+ EI_CONN_SAVE_ERRNO__(err);
return -1;
}
+
len = get32be(s);
/* got tick - respond and return */
if (!len) {
char tock[] = {0,0,0,0};
- ei_write_fill_t(fd, tock, sizeof(tock), ms); /* Failure no problem */
+ ssize_t wlen = sizeof(tock);
+ ei_write_fill_ctx_t__(cbs, ctx, tock, &wlen, tmo); /* Failure no problem */
*msglenp = 0;
return 0; /* maybe flag ERL_EAGAIN [sverkerw] */
}
@@ -86,9 +100,12 @@ ei_recv_internal (int fd,
ei_trace(-1,NULL);
/* read enough to get at least entire header */
- bytesread = (len > EIRECVBUF ? EIRECVBUF : len);
- if ((i = ei_read_fill_t(fd,header,bytesread,ms)) != bytesread) {
- erl_errno = (i == -2) ? ETIMEDOUT : EIO;
+ rlen = bytesread = (len > EIRECVBUF ? EIRECVBUF : len);
+ err = ei_read_fill_ctx_t__(cbs, ctx, header, &rlen, tmo);
+ if (!err && rlen != bytesread)
+ err = EIO;
+ if (err) {
+ EI_CONN_SAVE_ERRNO__(err);
return -1;
}
@@ -212,12 +229,17 @@ ei_recv_internal (int fd,
*/
if (msglen > *bufsz) {
if (staticbufp) {
- int sz = EIRECVBUF;
/* flush in rest of packet */
while (remain > 0) {
- if (remain < sz) sz = remain;
- if ((i=ei_read_fill_t(fd,header,sz,ms)) <= 0) break;
- remain -= i;
+ rlen = remain > EIRECVBUF ? EIRECVBUF : remain;
+ err = ei_read_fill_ctx_t__(cbs, ctx, header, &rlen, tmo);
+ if (err) {
+ EI_CONN_SAVE_ERRNO__(err);
+ return -1;
+ }
+ if (rlen == 0)
+ break;
+ remain -= rlen;
}
erl_errno = EMSGSIZE;
return -1;
@@ -247,11 +269,15 @@ ei_recv_internal (int fd,
/* read the rest of the message into callers buffer */
if (remain > 0) {
- if ((i = ei_read_fill_t(fd,mbuf+bytesread-index,remain,ms)) != remain) {
- *msglenp = bytesread-index+1; /* actual bytes in users buffer */
- erl_errno = (i == -2) ? ETIMEDOUT : EIO;
- return -1;
- }
+ rlen = remain;
+ err = ei_read_fill_ctx_t__(cbs, ctx, mbuf+bytesread-index, &rlen, tmo);
+ if (!err && rlen != remain)
+ err = EIO;
+ if (err) {
+ *msglenp = bytesread-index+1; /* actual bytes in users buffer */
+ EI_CONN_SAVE_ERRNO__(err);
+ return -1;
+ }
}
if (show_this_msg)
diff --git a/lib/erl_interface/src/connect/send.c b/lib/erl_interface/src/connect/send.c
index 37d7db6d68..d97532d123 100644
--- a/lib/erl_interface/src/connect/send.c
+++ b/lib/erl_interface/src/connect/send.c
@@ -58,10 +58,17 @@ int ei_send_encoded_tmo(int fd, const erlang_pid *to,
char *s, header[1200]; /* see size calculation below */
erlang_trace *token = NULL;
int index = 5; /* reserve 5 bytes for control message */
- int res;
-#ifdef HAVE_WRITEV
- struct iovec v[2];
-#endif
+ int err;
+ ei_socket_callbacks *cbs;
+ void *ctx;
+ ssize_t len, tot_len;
+ unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms;
+
+ err = EI_GET_CBS_CTX__(&cbs, &ctx, fd);
+ if (err) {
+ EI_CONN_SAVE_ERRNO__(err);
+ return ERL_ERROR;
+ }
/* are we tracing? */
/* check that he can receive trace tokens first */
@@ -91,30 +98,47 @@ int ei_send_encoded_tmo(int fd, const erlang_pid *to,
if (ei_tracelevel >= 4)
ei_show_sendmsg(stderr,header,msg);
-#ifdef HAVE_WRITEV
-
- v[0].iov_base = (char *)header;
- v[0].iov_len = index;
- v[1].iov_base = (char *)msg;
- v[1].iov_len = msglen;
-
- if ((res = ei_writev_fill_t(fd,v,2,ms)) != index+msglen) {
- erl_errno = (res == -2) ? ETIMEDOUT : EIO;
- return -1;
- }
-
-#else /* !HAVE_WRITEV */
-
- if ((res = ei_write_fill_t(fd,header,index,ms)) != index) {
- erl_errno = (res == -2) ? ETIMEDOUT : EIO;
- return -1;
+
+#ifdef EI_HAVE_STRUCT_IOVEC__
+ if (ei_socket_callbacks_have_writev__(cbs)) {
+ struct iovec v[2];
+
+ v[0].iov_base = (char *)header;
+ v[0].iov_len = index;
+ v[1].iov_base = (char *)msg;
+ v[1].iov_len = msglen;
+
+ len = tot_len = (ssize_t) index+msglen;
+ err = ei_writev_fill_ctx_t__(cbs, ctx, v, 2, &len, tmo);
+ if (!err && len != tot_len)
+ err = EIO;
+ if (err) {
+ EI_CONN_SAVE_ERRNO__(err);
+ return -1;
+ }
+
+ return 0;
}
- if ((res = ei_write_fill_t(fd,msg,msglen,ms)) != msglen) {
- erl_errno = (res == -2) ? ETIMEDOUT : EIO;
- return -1;
+#endif /* EI_HAVE_STRUCT_IOVEC__ */
+
+ /* no writev() */
+ len = tot_len = (ssize_t) index;
+ err = ei_write_fill_ctx_t__(cbs, ctx, header, &len, tmo);
+ if (!err && len != tot_len)
+ err = EIO;
+ if (err) {
+ EI_CONN_SAVE_ERRNO__(err);
+ return -1;
}
-#endif /* !HAVE_WRITEV */
+ len = tot_len = (ssize_t) msglen;
+ err = ei_write_fill_ctx_t__(cbs, ctx, msg, &len, tmo);
+ if (!err && len != tot_len)
+ err = EIO;
+ if (err) {
+ EI_CONN_SAVE_ERRNO__(err);
+ return -1;
+ }
return 0;
}
diff --git a/lib/erl_interface/src/connect/send_exit.c b/lib/erl_interface/src/connect/send_exit.c
index 2e298e3221..b4f7e14c7f 100644
--- a/lib/erl_interface/src/connect/send_exit.c
+++ b/lib/erl_interface/src/connect/send_exit.c
@@ -55,6 +55,17 @@ int ei_send_exit_tmo(int fd, const erlang_pid *from, const erlang_pid *to,
char *s;
int index = 0;
int len = strlen(reason) + 1080; /* see below */
+ ei_socket_callbacks *cbs;
+ void *ctx;
+ int err;
+ ssize_t wlen;
+ unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms;
+
+ err = EI_GET_CBS_CTX__(&cbs, &ctx, fd);
+ if (err) {
+ EI_CONN_SAVE_ERRNO__(err);
+ return ERL_ERROR;
+ }
if (len > EISMALLBUF)
if (!(dbuf = malloc(len)))
@@ -92,10 +103,16 @@ int ei_send_exit_tmo(int fd, const erlang_pid *from, const erlang_pid *to,
if (ei_tracelevel >= 4)
ei_show_sendmsg(stderr,msgbuf,NULL);
- ei_write_fill_t(fd,msgbuf,index,ms);
- /* FIXME ignore timeout etc? erl_errno?! */
-
- if (dbuf) free(dbuf);
+ wlen = (ssize_t) index;
+ err = ei_write_fill_ctx_t__(cbs, ctx, msgbuf, &wlen, tmo);
+ if (!err && wlen != (ssize_t) index)
+ err = EIO;
+ if (dbuf)
+ free(dbuf);
+ if (err) {
+ EI_CONN_SAVE_ERRNO__(err);
+ return ERL_ERROR;
+ }
return 0;
}
diff --git a/lib/erl_interface/src/connect/send_reg.c b/lib/erl_interface/src/connect/send_reg.c
index 62478f042d..80d61e57b5 100644
--- a/lib/erl_interface/src/connect/send_reg.c
+++ b/lib/erl_interface/src/connect/send_reg.c
@@ -51,11 +51,17 @@ int ei_send_reg_encoded_tmo(int fd, const erlang_pid *from,
char *s, header[1400]; /* see size calculation below */
erlang_trace *token = NULL;
int index = 5; /* reserve 5 bytes for control message */
- int res;
+ int err;
+ ei_socket_callbacks *cbs;
+ void *ctx;
+ ssize_t len, tot_len;
+ unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms;
-#ifdef HAVE_WRITEV
- struct iovec v[2];
-#endif
+ err = EI_GET_CBS_CTX__(&cbs, &ctx, fd);
+ if (err) {
+ EI_CONN_SAVE_ERRNO__(err);
+ return ERL_ERROR;
+ }
/* are we tracing? */
/* check that he can receive trace tokens first */
@@ -86,29 +92,45 @@ int ei_send_reg_encoded_tmo(int fd, const erlang_pid *from,
if (ei_tracelevel >= 4)
ei_show_sendmsg(stderr,header,msg);
-#ifdef HAVE_WRITEV
+#ifdef EI_HAVE_STRUCT_IOVEC__
+ if (ei_socket_callbacks_have_writev__(cbs)) {
+ struct iovec v[2];
- v[0].iov_base = (char *)header;
- v[0].iov_len = index;
- v[1].iov_base = (char *)msg;
- v[1].iov_len = msglen;
+ v[0].iov_base = (char *)header;
+ v[0].iov_len = index;
+ v[1].iov_base = (char *)msg;
+ v[1].iov_len = msglen;
- if ((res = ei_writev_fill_t(fd,v,2,ms)) != index+msglen) {
- erl_errno = (res == -2) ? ETIMEDOUT : EIO;
- return -1;
+ len = tot_len = (ssize_t) index+msglen;
+ err = ei_writev_fill_ctx_t__(cbs, ctx, v, 2, &len, tmo);
+ if (!err && len != tot_len)
+ err = EIO;
+ if (err) {
+ EI_CONN_SAVE_ERRNO__(err);
+ return -1;
+ }
+ return 0;
}
-#else
-
+#endif /* EI_HAVE_STRUCT_IOVEC__ */
+
/* no writev() */
- if ((res = ei_write_fill_t(fd,header,index,ms)) != index) {
- erl_errno = (res == -2) ? ETIMEDOUT : EIO;
- return -1;
+ len = tot_len = (ssize_t) index;
+ err = ei_write_fill_ctx_t__(cbs, ctx, header, &len, tmo);
+ if (!err && len != tot_len)
+ err = EIO;
+ if (err) {
+ EI_CONN_SAVE_ERRNO__(err);
+ return -1;
}
- if ((res = ei_write_fill_t(fd,msg,msglen,ms)) != msglen) {
- erl_errno = (res == -2) ? ETIMEDOUT : EIO;
- return -1;
+
+ len = tot_len = (ssize_t) msglen;
+ err = ei_write_fill_ctx_t__(cbs, ctx, msg, &len, tmo);
+ if (!err && len != tot_len)
+ err = EIO;
+ if (err) {
+ EI_CONN_SAVE_ERRNO__(err);
+ return -1;
}
-#endif
return 0;
}
diff --git a/lib/erl_interface/src/decode/decode_atom.c b/lib/erl_interface/src/decode/decode_atom.c
index b3bba82434..2bf8ab0552 100644
--- a/lib/erl_interface/src/decode/decode_atom.c
+++ b/lib/erl_interface/src/decode/decode_atom.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2016. All Rights Reserved.
+ * Copyright Ericsson AB 1998-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -92,6 +92,51 @@ int ei_decode_atom_as(const char *buf, int *index, char* p, int destlen,
}
+
+#ifdef HAVE_UNALIGNED_WORD_ACCESS
+
+#if SIZEOF_VOID_P == SIZEOF_LONG
+typedef unsigned long AsciiWord;
+#elif SIZEOF_VOID_P == SIZEOF_LONG_LONG
+typedef unsigned long long AsciiWord;
+#else
+# error "Uknown word type"
+#endif
+
+#if SIZEOF_VOID_P == 4
+# define ASCII_CHECK_MASK ((AsciiWord)0x80808080U)
+#elif SIZEOF_VOID_P == 8
+# define ASCII_CHECK_MASK ((AsciiWord)0x8080808080808080U)
+#endif
+
+static int ascii_fast_track(char* dst, const char* src, int slen, int destlen)
+{
+ const AsciiWord* src_word = (AsciiWord*) src;
+ const AsciiWord* const src_word_end = src_word + (slen / sizeof(AsciiWord));
+
+ if (destlen < slen)
+ return 0;
+
+ if (dst) {
+ AsciiWord* dst_word = (AsciiWord*)dst;
+
+ while (src_word < src_word_end) {
+ if ((*src_word & ASCII_CHECK_MASK) != 0)
+ break;
+ *dst_word++ = *src_word++;
+ }
+ }
+ else {
+ while (src_word < src_word_end) {
+ if ((*src_word & ASCII_CHECK_MASK) != 0)
+ break;
+ src_word++;
+ }
+ }
+ return (char*)src_word - src;
+}
+#endif /* HAVE_UNALIGNED_WORD_ACCESS */
+
int utf8_to_latin1(char* dst, const char* src, int slen, int destlen,
erlang_char_encoding* res_encp)
{
@@ -99,6 +144,15 @@ int utf8_to_latin1(char* dst, const char* src, int slen, int destlen,
const char* const dst_end = dst + destlen;
int found_non_ascii = 0;
+#ifdef HAVE_UNALIGNED_WORD_ACCESS
+ {
+ int aft = ascii_fast_track(dst, src, slen, destlen);
+ src += aft;
+ slen -= aft;
+ dst += aft;
+ }
+#endif
+
while (slen > 0) {
if (dst >= dst_end) return -1;
if ((src[0] & 0x80) == 0) {
@@ -136,6 +190,14 @@ int latin1_to_utf8(char* dst, const char* src, int slen, int destlen,
const char* const dst_end = dst + destlen;
int found_non_ascii = 0;
+#ifdef HAVE_UNALIGNED_WORD_ACCESS
+ {
+ int aft = ascii_fast_track(dst, src, slen, destlen);
+ dst += aft;
+ src += aft;
+ }
+#endif
+
while (src < src_end) {
if (dst >= dst_end) return -1;
if ((src[0] & 0x80) == 0) {
diff --git a/lib/erl_interface/src/decode/decode_binary.c b/lib/erl_interface/src/decode/decode_binary.c
index 5b8d234984..0d28c67230 100644
--- a/lib/erl_interface/src/decode/decode_binary.c
+++ b/lib/erl_interface/src/decode/decode_binary.c
@@ -40,4 +40,41 @@ int ei_decode_binary(const char *buf, int *index, void *p, long *lenp)
return 0;
}
+int ei_decode_bitstring(const char *buf, int *index,
+ const char** pp,
+ unsigned int* bitoffsp,
+ size_t *nbitsp)
+{
+ const char *s = buf + *index;
+ const char *s0 = s;
+ unsigned char last_bits;
+ const unsigned char tag = get8(s);
+ size_t len = get32be(s);
+
+ switch(tag) {
+ case ERL_BINARY_EXT:
+ if (nbitsp)
+ *nbitsp = len * 8;
+ break;
+ case ERL_BIT_BINARY_EXT:
+ last_bits = get8(s);
+ if (((last_bits==0) != (len==0)) || last_bits > 8)
+ return -1;
+
+ if (nbitsp)
+ *nbitsp = (len == 0) ? 0 : ((len-1) * 8) + last_bits;
+ break;
+ default:
+ return -1;
+ }
+
+ if (pp)
+ *pp = s;
+ if (bitoffsp)
+ *bitoffsp = 0;
+
+ s += len;
+ *index += s-s0;
+ return 0;
+}
diff --git a/lib/erl_interface/src/decode/decode_fun.c b/lib/erl_interface/src/decode/decode_fun.c
index f944c028af..3a7a2b01c1 100644
--- a/lib/erl_interface/src/decode/decode_fun.c
+++ b/lib/erl_interface/src/decode/decode_fun.c
@@ -33,22 +33,20 @@ int ei_decode_fun(const char *buf, int *index, erlang_fun *p)
int i, ix, ix0, n;
erlang_pid* p_pid;
char* p_module;
- erlang_char_encoding* p_module_org_enc;
long* p_index;
long* p_uniq;
long* p_old_index;
if (p != NULL) {
- p_pid = &p->pid;
+ p_pid = &p->u.closure.pid;
p_module = &p->module[0];
- p_module_org_enc = &p->module_org_enc;
- p_index = &p->index;
- p_uniq = &p->uniq;
- p_old_index = &p->old_index;
+ p_index = &p->u.closure.index;
+ p_uniq = &p->u.closure.uniq;
+ p_old_index = &p->u.closure.old_index;
}
else {
- p_pid = NULL; p_module = NULL; p_module_org_enc = NULL;
p_index = NULL; p_uniq = NULL; p_old_index = NULL;
+ p_pid = NULL; p_module = NULL;
}
switch (get8(s)) {
@@ -63,7 +61,7 @@ int ei_decode_fun(const char *buf, int *index, erlang_fun *p)
return -1;
/* then the module (atom) */
if (ei_decode_atom_as(s, &ix, p_module, MAXATOMLEN_UTF8, ERLANG_UTF8,
- p_module_org_enc, NULL) < 0)
+ NULL, NULL) < 0)
return -1;
/* then the index */
if (ei_decode_long(s, &ix, p_index) < 0)
@@ -78,11 +76,11 @@ int ei_decode_fun(const char *buf, int *index, erlang_fun *p)
return -1;
}
if (p != NULL) {
- p->n_free_vars = n;
- p->free_var_len = ix - ix0;
- p->free_vars = ei_malloc(ix - ix0);
- if (!(p->free_vars)) return -1;
- memcpy(p->free_vars, s + ix0, ix - ix0);
+ p->u.closure.n_free_vars = n;
+ p->u.closure.free_var_len = ix - ix0;
+ p->u.closure.free_vars = ei_malloc(ix - ix0);
+ if (!(p->u.closure.free_vars)) return -1;
+ memcpy(p->u.closure.free_vars, s + ix0, ix - ix0);
}
s += ix;
*index += s-s0;
@@ -93,20 +91,23 @@ int ei_decode_fun(const char *buf, int *index, erlang_fun *p)
n = get32be(s);
/* then the arity */
i = get8(s);
- if (p != NULL) p->arity = i;
- /* then md5 */
- if (p != NULL) memcpy(p->md5, s, 16);
+ if (p != NULL) {
+ p->type = EI_FUN_CLOSURE;
+ p->arity = i;
+ /* then md5 */
+ memcpy(p->u.closure.md5, s, 16);
+ }
s += 16;
/* then index */
i = get32be(s);
- if (p != NULL) p->index = i;
+ if (p != NULL) p->u.closure.index = i;
/* then the number of free vars (environment) */
i = get32be(s);
- if (p != NULL) p->n_free_vars = i;
+ if (p != NULL) p->u.closure.n_free_vars = i;
/* then the module (atom) */
ix = 0;
if (ei_decode_atom_as(s, &ix, p_module, MAXATOMLEN_UTF8, ERLANG_UTF8,
- p_module_org_enc, NULL) < 0)
+ NULL, NULL) < 0)
return -1;
/* then the old_index */
if (ei_decode_long(s, &ix, p_old_index) < 0)
@@ -122,17 +123,56 @@ int ei_decode_fun(const char *buf, int *index, erlang_fun *p)
n = n - (s - s0) + 1;
if (n < 0) return -1;
if (p != NULL) {
- p->free_var_len = n;
+ p->u.closure.free_var_len = n;
if (n > 0) {
- p->free_vars = malloc(n);
- if (!(p->free_vars)) return -1;
- memcpy(p->free_vars, s, n);
+ p->u.closure.free_vars = malloc(n);
+ if (!(p->u.closure.free_vars)) return -1;
+ memcpy(p->u.closure.free_vars, s, n);
}
}
s += n;
*index += s-s0;
return 0;
break;
+ case ERL_EXPORT_EXT: {
+ char* p_func;
+ long* p_arity;
+ int used;
+
+ if (p) {
+ p->type = EI_FUN_EXPORT;
+ p_arity = &p->arity;
+ }
+ else {
+ p_arity = NULL;
+ }
+ if (ei_decode_atom_as(s, &ix, p_module, MAXATOMLEN_UTF8, ERLANG_UTF8,
+ NULL, NULL) < 0)
+ return -1;
+ if (p) {
+ /* try use module buffer for function name */
+ used = strlen(p->module) + 1;
+ p_func = p->module + used;
+ p->u.exprt.func = p_func;
+ p->u.exprt.func_allocated = 0;
+ }
+ else {
+ used = 0;
+ p_func = NULL;
+ }
+ while (ei_decode_atom_as(s, &ix, p_func, MAXATOMLEN_UTF8-used,
+ ERLANG_UTF8, NULL, NULL) < 0) {
+ if (!used)
+ return -1;
+ p_func = malloc(MAXATOMLEN_UTF8);
+ p->u.exprt.func = p_func;
+ p->u.exprt.func_allocated = 1;
+ used = 0;
+ }
+ if (ei_decode_long(s, &ix, p_arity) < 0)
+ return -1;
+ return 0;
+ }
default:
return -1;
}
@@ -140,6 +180,14 @@ int ei_decode_fun(const char *buf, int *index, erlang_fun *p)
void free_fun(erlang_fun* f)
{
- if (f->free_var_len > 0)
- ei_free(f->free_vars);
+ switch (f->type) {
+ case EI_FUN_CLOSURE:
+ if (f->u.closure.free_var_len > 0)
+ ei_free(f->u.closure.free_vars);
+ break;
+ case EI_FUN_EXPORT:
+ if (f->u.exprt.func_allocated)
+ ei_free(f->u.exprt.func);
+ break;
+ }
}
diff --git a/lib/erl_interface/src/decode/decode_skip.c b/lib/erl_interface/src/decode/decode_skip.c
index 0db315f09b..736c00e074 100644
--- a/lib/erl_interface/src/decode/decode_skip.c
+++ b/lib/erl_interface/src/decode/decode_skip.c
@@ -27,7 +27,7 @@ int ei_skip_term(const char* buf, int* index)
/* ASSERT(ep != NULL); */
- ei_get_type_internal(buf, index, &ty, &n);
+ ei_get_type(buf, index, &ty, &n);
switch (ty) {
case ERL_ATOM_EXT:
/* FIXME: what if some weird locale is in use? */
@@ -54,7 +54,7 @@ int ei_skip_term(const char* buf, int* index)
if (ei_decode_list_header(buf, index, &n) < 0) return -1;
for (i = 0; i < n; ++i)
ei_skip_term(buf, index);
- if (ei_get_type_internal(buf, index, &ty, &n) < 0) return -1;
+ if (ei_get_type(buf, index, &ty, &n) < 0) return -1;
if (ty != ERL_NIL_EXT)
ei_skip_term(buf, index);
else
@@ -79,6 +79,10 @@ int ei_skip_term(const char* buf, int* index)
if (ei_decode_binary(buf, index, NULL, NULL) < 0)
return -1;
break;
+ case ERL_BIT_BINARY_EXT:
+ if (ei_decode_bitstring(buf, index, NULL, NULL, NULL) < 0)
+ return -1;
+ break;
case ERL_SMALL_INTEGER_EXT:
case ERL_INTEGER_EXT:
if (ei_decode_long(buf, index, NULL) < 0) return -1;
diff --git a/lib/erl_interface/src/depend.mk b/lib/erl_interface/src/depend.mk
deleted file mode 100644
index af753046e5..0000000000
--- a/lib/erl_interface/src/depend.mk
+++ /dev/null
@@ -1,1133 +0,0 @@
-# Generated dependency rules
-$(ST_OBJDIR)/ei_connect.o: connect/ei_connect.c $(TARGET)/config.h \
- misc/eidef.h ../include/ei.h misc/eiext.h misc/ei_portio.h \
- misc/ei_internal.h connect/ei_connect_int.h misc/ei_locking.h \
- connect/eisend.h connect/eirecv.h misc/eimd5.h misc/putget.h \
- connect/ei_resolve.h epmd/ei_epmd.h
-$(ST_OBJDIR)/ei_resolve.o: connect/ei_resolve.c $(TARGET)/config.h \
- misc/eidef.h ../include/ei.h connect/ei_resolve.h misc/ei_locking.h
-$(ST_OBJDIR)/eirecv.o: connect/eirecv.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eirecv.h misc/ei_portio.h \
- misc/ei_internal.h misc/putget.h misc/ei_trace.h misc/show_msg.h
-$(ST_OBJDIR)/send.o: connect/send.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
- connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
- misc/show_msg.h
-$(ST_OBJDIR)/send_exit.o: connect/send_exit.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/ei_connect_int.h misc/ei_trace.h \
- misc/ei_internal.h misc/putget.h misc/show_msg.h
-$(ST_OBJDIR)/send_reg.o: connect/send_reg.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
- connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
- misc/show_msg.h
-$(ST_OBJDIR)/decode_atom.o: decode/decode_atom.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_big.o: decode/decode_big.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_bignum.o: decode/decode_bignum.c $(TARGET)/config.h
-$(ST_OBJDIR)/decode_binary.o: decode/decode_binary.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_boolean.o: decode/decode_boolean.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_char.o: decode/decode_char.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_double.o: decode/decode_double.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_fun.o: decode/decode_fun.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_malloc.h decode/decode_skip.h misc/putget.h
-$(ST_OBJDIR)/decode_intlist.o: decode/decode_intlist.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_list_header.o: decode/decode_list_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_long.o: decode/decode_long.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_pid.o: decode/decode_pid.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_port.o: decode/decode_port.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_ref.o: decode/decode_ref.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_skip.o: decode/decode_skip.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- decode/decode_skip.h
-$(ST_OBJDIR)/decode_string.o: decode/decode_string.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_trace.o: decode/decode_trace.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/putget.h
-$(ST_OBJDIR)/decode_tuple_header.o: decode/decode_tuple_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_ulong.o: decode/decode_ulong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_version.o: decode/decode_version.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_longlong.o: decode/decode_longlong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/decode_ulonglong.o: decode/decode_ulonglong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_atom.o: encode/encode_atom.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_bignum.o: encode/encode_bignum.c $(TARGET)/config.h
-$(ST_OBJDIR)/encode_binary.o: encode/encode_binary.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_boolean.o: encode/encode_boolean.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_char.o: encode/encode_char.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_double.o: encode/encode_double.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_fun.o: encode/encode_fun.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_list_header.o: encode/encode_list_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_long.o: encode/encode_long.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_pid.o: encode/encode_pid.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_port.o: encode/encode_port.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_ref.o: encode/encode_ref.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_string.o: encode/encode_string.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_trace.o: encode/encode_trace.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/putget.h
-$(ST_OBJDIR)/encode_tuple_header.o: encode/encode_tuple_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_ulong.o: encode/encode_ulong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_version.o: encode/encode_version.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(ST_OBJDIR)/encode_longlong.o: encode/encode_longlong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h
-$(ST_OBJDIR)/encode_ulonglong.o: encode/encode_ulonglong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h
-$(ST_OBJDIR)/epmd_port.o: epmd/epmd_port.c misc/ei_internal.h epmd/ei_epmd.h \
- misc/putget.h
-$(ST_OBJDIR)/epmd_publish.o: epmd/epmd_publish.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
- misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
-$(ST_OBJDIR)/epmd_unpublish.o: epmd/epmd_unpublish.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
- misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
-$(ST_OBJDIR)/ei_decode_term.o: misc/ei_decode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_decode_term.h misc/putget.h
-$(ST_OBJDIR)/ei_format.o: misc/ei_format.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/ei_malloc.h misc/ei_format.h
-$(ST_OBJDIR)/ei_locking.o: misc/ei_locking.c $(TARGET)/config.h \
- misc/ei_malloc.h misc/ei_locking.h
-$(ST_OBJDIR)/ei_malloc.o: misc/ei_malloc.c misc/ei_malloc.h
-$(ST_OBJDIR)/ei_portio.o: misc/ei_portio.c misc/ei_portio.h misc/ei_internal.h
-$(ST_OBJDIR)/ei_printterm.o: misc/ei_printterm.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_printterm.h misc/ei_malloc.h
-$(ST_OBJDIR)/ei_pthreads.o: misc/ei_pthreads.c $(TARGET)/config.h \
- ../include/ei.h misc/ei_locking.h
-$(ST_OBJDIR)/ei_trace.o: misc/ei_trace.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/ei_trace.h
-$(ST_OBJDIR)/ei_x_encode.o: misc/ei_x_encode.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_x_encode.h \
- misc/ei_malloc.h
-$(ST_OBJDIR)/eimd5.o: misc/eimd5.c misc/eimd5.h
-$(ST_OBJDIR)/get_type.o: misc/get_type.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h misc/putget.h
-$(ST_OBJDIR)/show_msg.o: misc/show_msg.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h misc/putget.h misc/ei_printterm.h \
- misc/ei_internal.h misc/show_msg.h
-$(ST_OBJDIR)/ei_compat.o: misc/ei_compat.c ../include/ei.h misc/ei_internal.h
-$(ST_OBJDIR)/hash_dohash.o: registry/hash_dohash.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/hash_foreach.o: registry/hash_foreach.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/hash_freetab.o: registry/hash_freetab.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/hash_insert.o: registry/hash_insert.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/hash_isprime.o: registry/hash_isprime.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/hash_lookup.o: registry/hash_lookup.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/hash_newtab.o: registry/hash_newtab.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/hash_remove.o: registry/hash_remove.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/hash_resize.o: registry/hash_resize.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/hash_rlookup.o: registry/hash_rlookup.c registry/hash.h ../include/ei.h
-$(ST_OBJDIR)/reg_close.o: registry/reg_close.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_delete.o: registry/reg_delete.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_dirty.o: registry/reg_dirty.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_dump.o: registry/reg_dump.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
- connect/ei_connect_int.h
-$(ST_OBJDIR)/reg_free.o: registry/reg_free.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_get.o: registry/reg_get.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_getf.o: registry/reg_getf.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_geti.o: registry/reg_geti.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_getp.o: registry/reg_getp.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_gets.o: registry/reg_gets.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_make.o: registry/reg_make.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_open.o: registry/reg_open.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_purge.o: registry/reg_purge.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_resize.o: registry/reg_resize.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_restore.o: registry/reg_restore.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
- connect/ei_connect_int.h
-$(ST_OBJDIR)/reg_set.o: registry/reg_set.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_setf.o: registry/reg_setf.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_seti.o: registry/reg_seti.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_setp.o: registry/reg_setp.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_sets.o: registry/reg_sets.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_stat.o: registry/reg_stat.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/reg_tabstat.o: registry/reg_tabstat.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(ST_OBJDIR)/decode_term.o: legacy/decode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h ../include/erl_interface.h
-$(ST_OBJDIR)/encode_term.o: legacy/encode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h ../include/erl_interface.h \
- legacy/erl_marshal.h legacy/erl_eterm.h legacy/portability.h
-$(ST_OBJDIR)/erl_connect.o: legacy/erl_connect.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_config.h \
- legacy/erl_connect.h legacy/erl_eterm.h legacy/portability.h \
- legacy/erl_malloc.h misc/putget.h connect/ei_connect_int.h \
- misc/ei_locking.h epmd/ei_epmd.h misc/ei_internal.h
-$(ST_OBJDIR)/erl_error.o: legacy/erl_error.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_error.h
-$(ST_OBJDIR)/erl_eterm.o: legacy/erl_eterm.c misc/ei_locking.h \
- $(TARGET)/config.h connect/ei_resolve.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_eterm.h \
- legacy/portability.h legacy/erl_malloc.h legacy/erl_marshal.h \
- legacy/erl_error.h legacy/erl_internal.h misc/ei_internal.h
-$(ST_OBJDIR)/erl_fix_alloc.o: legacy/erl_fix_alloc.c $(TARGET)/config.h \
- misc/ei_locking.h ../include/erl_interface.h ../include/ei.h \
- legacy/erl_error.h legacy/erl_malloc.h legacy/erl_fix_alloc.h \
- legacy/erl_eterm.h legacy/portability.h
-$(ST_OBJDIR)/erl_format.o: legacy/erl_format.c ../include/erl_interface.h \
- ../include/ei.h legacy/erl_eterm.h legacy/portability.h \
- legacy/erl_malloc.h legacy/erl_error.h legacy/erl_internal.h
-$(ST_OBJDIR)/erl_malloc.o: legacy/erl_malloc.c ../include/erl_interface.h \
- ../include/ei.h legacy/erl_fix_alloc.h legacy/erl_malloc.h \
- legacy/erl_internal.h legacy/erl_eterm.h legacy/portability.h \
- misc/ei_malloc.h
-$(ST_OBJDIR)/erl_marshal.o: legacy/erl_marshal.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_marshal.h \
- legacy/erl_eterm.h legacy/portability.h legacy/erl_malloc.h \
- legacy/erl_error.h legacy/erl_internal.h misc/eiext.h misc/putget.h
-$(ST_OBJDIR)/erl_timeout.o: legacy/erl_timeout.c $(TARGET)/config.h \
- legacy/erl_timeout.h
-$(ST_OBJDIR)/global_names.o: legacy/global_names.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-$(ST_OBJDIR)/global_register.o: legacy/global_register.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h ../include/erl_interface.h
-$(ST_OBJDIR)/global_unregister.o: legacy/global_unregister.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-$(ST_OBJDIR)/global_whereis.o: legacy/global_whereis.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-
-$(MT_OBJDIR)/ei_connect.o: connect/ei_connect.c $(TARGET)/config.h \
- misc/eidef.h ../include/ei.h misc/eiext.h misc/ei_portio.h \
- misc/ei_internal.h connect/ei_connect_int.h misc/ei_locking.h \
- connect/eisend.h connect/eirecv.h misc/eimd5.h misc/putget.h \
- connect/ei_resolve.h epmd/ei_epmd.h
-$(MT_OBJDIR)/ei_resolve.o: connect/ei_resolve.c $(TARGET)/config.h \
- misc/eidef.h ../include/ei.h connect/ei_resolve.h misc/ei_locking.h
-$(MT_OBJDIR)/eirecv.o: connect/eirecv.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eirecv.h misc/ei_portio.h \
- misc/ei_internal.h misc/putget.h misc/ei_trace.h misc/show_msg.h
-$(MT_OBJDIR)/send.o: connect/send.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
- connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
- misc/show_msg.h
-$(MT_OBJDIR)/send_exit.o: connect/send_exit.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/ei_connect_int.h misc/ei_trace.h \
- misc/ei_internal.h misc/putget.h misc/show_msg.h
-$(MT_OBJDIR)/send_reg.o: connect/send_reg.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
- connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
- misc/show_msg.h
-$(MT_OBJDIR)/decode_atom.o: decode/decode_atom.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_big.o: decode/decode_big.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_bignum.o: decode/decode_bignum.c $(TARGET)/config.h
-$(MT_OBJDIR)/decode_binary.o: decode/decode_binary.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_boolean.o: decode/decode_boolean.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_char.o: decode/decode_char.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_double.o: decode/decode_double.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_fun.o: decode/decode_fun.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_malloc.h decode/decode_skip.h misc/putget.h
-$(MT_OBJDIR)/decode_intlist.o: decode/decode_intlist.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_list_header.o: decode/decode_list_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_long.o: decode/decode_long.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_pid.o: decode/decode_pid.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_port.o: decode/decode_port.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_ref.o: decode/decode_ref.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_skip.o: decode/decode_skip.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- decode/decode_skip.h
-$(MT_OBJDIR)/decode_string.o: decode/decode_string.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_trace.o: decode/decode_trace.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/putget.h
-$(MT_OBJDIR)/decode_tuple_header.o: decode/decode_tuple_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_ulong.o: decode/decode_ulong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_version.o: decode/decode_version.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_longlong.o: decode/decode_longlong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/decode_ulonglong.o: decode/decode_ulonglong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_atom.o: encode/encode_atom.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_bignum.o: encode/encode_bignum.c $(TARGET)/config.h
-$(MT_OBJDIR)/encode_binary.o: encode/encode_binary.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_boolean.o: encode/encode_boolean.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_char.o: encode/encode_char.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_double.o: encode/encode_double.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_fun.o: encode/encode_fun.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_list_header.o: encode/encode_list_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_long.o: encode/encode_long.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_pid.o: encode/encode_pid.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_port.o: encode/encode_port.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_ref.o: encode/encode_ref.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_string.o: encode/encode_string.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_trace.o: encode/encode_trace.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/putget.h
-$(MT_OBJDIR)/encode_tuple_header.o: encode/encode_tuple_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_ulong.o: encode/encode_ulong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_version.o: encode/encode_version.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MT_OBJDIR)/encode_longlong.o: encode/encode_longlong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h
-$(MT_OBJDIR)/encode_ulonglong.o: encode/encode_ulonglong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h
-$(MT_OBJDIR)/epmd_port.o: epmd/epmd_port.c misc/ei_internal.h epmd/ei_epmd.h \
- misc/putget.h
-$(MT_OBJDIR)/epmd_publish.o: epmd/epmd_publish.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
- misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
-$(MT_OBJDIR)/epmd_unpublish.o: epmd/epmd_unpublish.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
- misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
-$(MT_OBJDIR)/ei_decode_term.o: misc/ei_decode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_decode_term.h misc/putget.h
-$(MT_OBJDIR)/ei_format.o: misc/ei_format.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/ei_malloc.h misc/ei_format.h
-$(MT_OBJDIR)/ei_locking.o: misc/ei_locking.c $(TARGET)/config.h \
- misc/ei_malloc.h misc/ei_locking.h
-$(MT_OBJDIR)/ei_malloc.o: misc/ei_malloc.c misc/ei_malloc.h
-$(MT_OBJDIR)/ei_portio.o: misc/ei_portio.c misc/ei_portio.h misc/ei_internal.h
-$(MT_OBJDIR)/ei_printterm.o: misc/ei_printterm.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_printterm.h misc/ei_malloc.h
-$(MT_OBJDIR)/ei_pthreads.o: misc/ei_pthreads.c $(TARGET)/config.h \
- ../include/ei.h misc/ei_locking.h
-$(MT_OBJDIR)/ei_trace.o: misc/ei_trace.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/ei_trace.h
-$(MT_OBJDIR)/ei_x_encode.o: misc/ei_x_encode.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_x_encode.h \
- misc/ei_malloc.h
-$(MT_OBJDIR)/eimd5.o: misc/eimd5.c misc/eimd5.h
-$(MT_OBJDIR)/get_type.o: misc/get_type.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h misc/putget.h
-$(MT_OBJDIR)/show_msg.o: misc/show_msg.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h misc/putget.h misc/ei_printterm.h \
- misc/ei_internal.h misc/show_msg.h
-$(MT_OBJDIR)/ei_compat.o: misc/ei_compat.c ../include/ei.h misc/ei_internal.h
-$(MT_OBJDIR)/hash_dohash.o: registry/hash_dohash.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/hash_foreach.o: registry/hash_foreach.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/hash_freetab.o: registry/hash_freetab.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/hash_insert.o: registry/hash_insert.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/hash_isprime.o: registry/hash_isprime.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/hash_lookup.o: registry/hash_lookup.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/hash_newtab.o: registry/hash_newtab.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/hash_remove.o: registry/hash_remove.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/hash_resize.o: registry/hash_resize.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/hash_rlookup.o: registry/hash_rlookup.c registry/hash.h ../include/ei.h
-$(MT_OBJDIR)/reg_close.o: registry/reg_close.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_delete.o: registry/reg_delete.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_dirty.o: registry/reg_dirty.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_dump.o: registry/reg_dump.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
- connect/ei_connect_int.h
-$(MT_OBJDIR)/reg_free.o: registry/reg_free.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_get.o: registry/reg_get.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_getf.o: registry/reg_getf.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_geti.o: registry/reg_geti.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_getp.o: registry/reg_getp.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_gets.o: registry/reg_gets.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_make.o: registry/reg_make.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_open.o: registry/reg_open.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_purge.o: registry/reg_purge.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_resize.o: registry/reg_resize.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_restore.o: registry/reg_restore.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
- connect/ei_connect_int.h
-$(MT_OBJDIR)/reg_set.o: registry/reg_set.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_setf.o: registry/reg_setf.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_seti.o: registry/reg_seti.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_setp.o: registry/reg_setp.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_sets.o: registry/reg_sets.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_stat.o: registry/reg_stat.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/reg_tabstat.o: registry/reg_tabstat.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MT_OBJDIR)/decode_term.o: legacy/decode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h ../include/erl_interface.h
-$(MT_OBJDIR)/encode_term.o: legacy/encode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h ../include/erl_interface.h \
- legacy/erl_marshal.h legacy/erl_eterm.h legacy/portability.h
-$(MT_OBJDIR)/erl_connect.o: legacy/erl_connect.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_config.h \
- legacy/erl_connect.h legacy/erl_eterm.h legacy/portability.h \
- legacy/erl_malloc.h misc/putget.h connect/ei_connect_int.h \
- misc/ei_locking.h epmd/ei_epmd.h misc/ei_internal.h
-$(MT_OBJDIR)/erl_error.o: legacy/erl_error.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_error.h
-$(MT_OBJDIR)/erl_eterm.o: legacy/erl_eterm.c misc/ei_locking.h \
- $(TARGET)/config.h connect/ei_resolve.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_eterm.h \
- legacy/portability.h legacy/erl_malloc.h legacy/erl_marshal.h \
- legacy/erl_error.h legacy/erl_internal.h misc/ei_internal.h
-$(MT_OBJDIR)/erl_fix_alloc.o: legacy/erl_fix_alloc.c $(TARGET)/config.h \
- misc/ei_locking.h ../include/erl_interface.h ../include/ei.h \
- legacy/erl_error.h legacy/erl_malloc.h legacy/erl_fix_alloc.h \
- legacy/erl_eterm.h legacy/portability.h
-$(MT_OBJDIR)/erl_format.o: legacy/erl_format.c ../include/erl_interface.h \
- ../include/ei.h legacy/erl_eterm.h legacy/portability.h \
- legacy/erl_malloc.h legacy/erl_error.h legacy/erl_internal.h
-$(MT_OBJDIR)/erl_malloc.o: legacy/erl_malloc.c ../include/erl_interface.h \
- ../include/ei.h legacy/erl_fix_alloc.h legacy/erl_malloc.h \
- legacy/erl_internal.h legacy/erl_eterm.h legacy/portability.h \
- misc/ei_malloc.h
-$(MT_OBJDIR)/erl_marshal.o: legacy/erl_marshal.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_marshal.h \
- legacy/erl_eterm.h legacy/portability.h legacy/erl_malloc.h \
- legacy/erl_error.h legacy/erl_internal.h misc/eiext.h misc/putget.h
-$(MT_OBJDIR)/erl_timeout.o: legacy/erl_timeout.c $(TARGET)/config.h \
- legacy/erl_timeout.h
-$(MT_OBJDIR)/global_names.o: legacy/global_names.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-$(MT_OBJDIR)/global_register.o: legacy/global_register.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h ../include/erl_interface.h
-$(MT_OBJDIR)/global_unregister.o: legacy/global_unregister.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-$(MT_OBJDIR)/global_whereis.o: legacy/global_whereis.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-
-$(MD_OBJDIR)/ei_connect.o: connect/ei_connect.c $(TARGET)/config.h \
- misc/eidef.h ../include/ei.h misc/eiext.h misc/ei_portio.h \
- misc/ei_internal.h connect/ei_connect_int.h misc/ei_locking.h \
- connect/eisend.h connect/eirecv.h misc/eimd5.h misc/putget.h \
- connect/ei_resolve.h epmd/ei_epmd.h
-$(MD_OBJDIR)/ei_resolve.o: connect/ei_resolve.c $(TARGET)/config.h \
- misc/eidef.h ../include/ei.h connect/ei_resolve.h misc/ei_locking.h
-$(MD_OBJDIR)/eirecv.o: connect/eirecv.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eirecv.h misc/ei_portio.h \
- misc/ei_internal.h misc/putget.h misc/ei_trace.h misc/show_msg.h
-$(MD_OBJDIR)/send.o: connect/send.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
- connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
- misc/show_msg.h
-$(MD_OBJDIR)/send_exit.o: connect/send_exit.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/ei_connect_int.h misc/ei_trace.h \
- misc/ei_internal.h misc/putget.h misc/show_msg.h
-$(MD_OBJDIR)/send_reg.o: connect/send_reg.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
- connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
- misc/show_msg.h
-$(MD_OBJDIR)/decode_atom.o: decode/decode_atom.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_big.o: decode/decode_big.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_bignum.o: decode/decode_bignum.c $(TARGET)/config.h
-$(MD_OBJDIR)/decode_binary.o: decode/decode_binary.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_boolean.o: decode/decode_boolean.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_char.o: decode/decode_char.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_double.o: decode/decode_double.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_fun.o: decode/decode_fun.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_malloc.h decode/decode_skip.h misc/putget.h
-$(MD_OBJDIR)/decode_intlist.o: decode/decode_intlist.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_list_header.o: decode/decode_list_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_long.o: decode/decode_long.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_pid.o: decode/decode_pid.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_port.o: decode/decode_port.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_ref.o: decode/decode_ref.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_skip.o: decode/decode_skip.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- decode/decode_skip.h
-$(MD_OBJDIR)/decode_string.o: decode/decode_string.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_trace.o: decode/decode_trace.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/putget.h
-$(MD_OBJDIR)/decode_tuple_header.o: decode/decode_tuple_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_ulong.o: decode/decode_ulong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_version.o: decode/decode_version.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_longlong.o: decode/decode_longlong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/decode_ulonglong.o: decode/decode_ulonglong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_atom.o: encode/encode_atom.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_bignum.o: encode/encode_bignum.c $(TARGET)/config.h
-$(MD_OBJDIR)/encode_binary.o: encode/encode_binary.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_boolean.o: encode/encode_boolean.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_char.o: encode/encode_char.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_double.o: encode/encode_double.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_fun.o: encode/encode_fun.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_list_header.o: encode/encode_list_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_long.o: encode/encode_long.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_pid.o: encode/encode_pid.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_port.o: encode/encode_port.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_ref.o: encode/encode_ref.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_string.o: encode/encode_string.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_trace.o: encode/encode_trace.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/putget.h
-$(MD_OBJDIR)/encode_tuple_header.o: encode/encode_tuple_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_ulong.o: encode/encode_ulong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_version.o: encode/encode_version.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MD_OBJDIR)/encode_longlong.o: encode/encode_longlong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h
-$(MD_OBJDIR)/encode_ulonglong.o: encode/encode_ulonglong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h
-$(MD_OBJDIR)/epmd_port.o: epmd/epmd_port.c misc/ei_internal.h epmd/ei_epmd.h \
- misc/putget.h
-$(MD_OBJDIR)/epmd_publish.o: epmd/epmd_publish.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
- misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
-$(MD_OBJDIR)/epmd_unpublish.o: epmd/epmd_unpublish.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
- misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
-$(MD_OBJDIR)/ei_decode_term.o: misc/ei_decode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_decode_term.h misc/putget.h
-$(MD_OBJDIR)/ei_format.o: misc/ei_format.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/ei_malloc.h misc/ei_format.h
-$(MD_OBJDIR)/ei_locking.o: misc/ei_locking.c $(TARGET)/config.h \
- misc/ei_malloc.h misc/ei_locking.h
-$(MD_OBJDIR)/ei_malloc.o: misc/ei_malloc.c misc/ei_malloc.h
-$(MD_OBJDIR)/ei_portio.o: misc/ei_portio.c misc/ei_portio.h misc/ei_internal.h
-$(MD_OBJDIR)/ei_printterm.o: misc/ei_printterm.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_printterm.h misc/ei_malloc.h
-$(MD_OBJDIR)/ei_pthreads.o: misc/ei_pthreads.c $(TARGET)/config.h \
- ../include/ei.h misc/ei_locking.h
-$(MD_OBJDIR)/ei_trace.o: misc/ei_trace.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/ei_trace.h
-$(MD_OBJDIR)/ei_x_encode.o: misc/ei_x_encode.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_x_encode.h \
- misc/ei_malloc.h
-$(MD_OBJDIR)/eimd5.o: misc/eimd5.c misc/eimd5.h
-$(MD_OBJDIR)/get_type.o: misc/get_type.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h misc/putget.h
-$(MD_OBJDIR)/show_msg.o: misc/show_msg.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h misc/putget.h misc/ei_printterm.h \
- misc/ei_internal.h misc/show_msg.h
-$(MD_OBJDIR)/ei_compat.o: misc/ei_compat.c ../include/ei.h misc/ei_internal.h
-$(MD_OBJDIR)/hash_dohash.o: registry/hash_dohash.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/hash_foreach.o: registry/hash_foreach.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/hash_freetab.o: registry/hash_freetab.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/hash_insert.o: registry/hash_insert.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/hash_isprime.o: registry/hash_isprime.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/hash_lookup.o: registry/hash_lookup.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/hash_newtab.o: registry/hash_newtab.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/hash_remove.o: registry/hash_remove.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/hash_resize.o: registry/hash_resize.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/hash_rlookup.o: registry/hash_rlookup.c registry/hash.h ../include/ei.h
-$(MD_OBJDIR)/reg_close.o: registry/reg_close.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_delete.o: registry/reg_delete.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_dirty.o: registry/reg_dirty.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_dump.o: registry/reg_dump.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
- connect/ei_connect_int.h
-$(MD_OBJDIR)/reg_free.o: registry/reg_free.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_get.o: registry/reg_get.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_getf.o: registry/reg_getf.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_geti.o: registry/reg_geti.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_getp.o: registry/reg_getp.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_gets.o: registry/reg_gets.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_make.o: registry/reg_make.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_open.o: registry/reg_open.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_purge.o: registry/reg_purge.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_resize.o: registry/reg_resize.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_restore.o: registry/reg_restore.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
- connect/ei_connect_int.h
-$(MD_OBJDIR)/reg_set.o: registry/reg_set.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_setf.o: registry/reg_setf.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_seti.o: registry/reg_seti.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_setp.o: registry/reg_setp.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_sets.o: registry/reg_sets.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_stat.o: registry/reg_stat.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/reg_tabstat.o: registry/reg_tabstat.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MD_OBJDIR)/decode_term.o: legacy/decode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h ../include/erl_interface.h
-$(MD_OBJDIR)/encode_term.o: legacy/encode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h ../include/erl_interface.h \
- legacy/erl_marshal.h legacy/erl_eterm.h legacy/portability.h
-$(MD_OBJDIR)/erl_connect.o: legacy/erl_connect.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_config.h \
- legacy/erl_connect.h legacy/erl_eterm.h legacy/portability.h \
- legacy/erl_malloc.h misc/putget.h connect/ei_connect_int.h \
- misc/ei_locking.h epmd/ei_epmd.h misc/ei_internal.h
-$(MD_OBJDIR)/erl_error.o: legacy/erl_error.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_error.h
-$(MD_OBJDIR)/erl_eterm.o: legacy/erl_eterm.c misc/ei_locking.h \
- $(TARGET)/config.h connect/ei_resolve.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_eterm.h \
- legacy/portability.h legacy/erl_malloc.h legacy/erl_marshal.h \
- legacy/erl_error.h legacy/erl_internal.h misc/ei_internal.h
-$(MD_OBJDIR)/erl_fix_alloc.o: legacy/erl_fix_alloc.c $(TARGET)/config.h \
- misc/ei_locking.h ../include/erl_interface.h ../include/ei.h \
- legacy/erl_error.h legacy/erl_malloc.h legacy/erl_fix_alloc.h \
- legacy/erl_eterm.h legacy/portability.h
-$(MD_OBJDIR)/erl_format.o: legacy/erl_format.c ../include/erl_interface.h \
- ../include/ei.h legacy/erl_eterm.h legacy/portability.h \
- legacy/erl_malloc.h legacy/erl_error.h legacy/erl_internal.h
-$(MD_OBJDIR)/erl_malloc.o: legacy/erl_malloc.c ../include/erl_interface.h \
- ../include/ei.h legacy/erl_fix_alloc.h legacy/erl_malloc.h \
- legacy/erl_internal.h legacy/erl_eterm.h legacy/portability.h \
- misc/ei_malloc.h
-$(MD_OBJDIR)/erl_marshal.o: legacy/erl_marshal.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_marshal.h \
- legacy/erl_eterm.h legacy/portability.h legacy/erl_malloc.h \
- legacy/erl_error.h legacy/erl_internal.h misc/eiext.h misc/putget.h
-$(MD_OBJDIR)/erl_timeout.o: legacy/erl_timeout.c $(TARGET)/config.h \
- legacy/erl_timeout.h
-$(MD_OBJDIR)/global_names.o: legacy/global_names.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-$(MD_OBJDIR)/global_register.o: legacy/global_register.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h ../include/erl_interface.h
-$(MD_OBJDIR)/global_unregister.o: legacy/global_unregister.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-$(MD_OBJDIR)/global_whereis.o: legacy/global_whereis.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-
-$(MDD_OBJDIR)/ei_connect.o: connect/ei_connect.c $(TARGET)/config.h \
- misc/eidef.h ../include/ei.h misc/eiext.h misc/ei_portio.h \
- misc/ei_internal.h connect/ei_connect_int.h misc/ei_locking.h \
- connect/eisend.h connect/eirecv.h misc/eimd5.h misc/putget.h \
- connect/ei_resolve.h epmd/ei_epmd.h
-$(MDD_OBJDIR)/ei_resolve.o: connect/ei_resolve.c $(TARGET)/config.h \
- misc/eidef.h ../include/ei.h connect/ei_resolve.h misc/ei_locking.h
-$(MDD_OBJDIR)/eirecv.o: connect/eirecv.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eirecv.h misc/ei_portio.h \
- misc/ei_internal.h misc/putget.h misc/ei_trace.h misc/show_msg.h
-$(MDD_OBJDIR)/send.o: connect/send.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
- connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
- misc/show_msg.h
-$(MDD_OBJDIR)/send_exit.o: connect/send_exit.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/ei_connect_int.h misc/ei_trace.h \
- misc/ei_internal.h misc/putget.h misc/show_msg.h
-$(MDD_OBJDIR)/send_reg.o: connect/send_reg.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
- connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
- misc/show_msg.h
-$(MDD_OBJDIR)/decode_atom.o: decode/decode_atom.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_big.o: decode/decode_big.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_bignum.o: decode/decode_bignum.c $(TARGET)/config.h
-$(MDD_OBJDIR)/decode_binary.o: decode/decode_binary.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_boolean.o: decode/decode_boolean.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_char.o: decode/decode_char.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_double.o: decode/decode_double.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_fun.o: decode/decode_fun.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_malloc.h decode/decode_skip.h misc/putget.h
-$(MDD_OBJDIR)/decode_intlist.o: decode/decode_intlist.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_list_header.o: decode/decode_list_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_long.o: decode/decode_long.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_pid.o: decode/decode_pid.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_port.o: decode/decode_port.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_ref.o: decode/decode_ref.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_skip.o: decode/decode_skip.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- decode/decode_skip.h
-$(MDD_OBJDIR)/decode_string.o: decode/decode_string.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_trace.o: decode/decode_trace.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/putget.h
-$(MDD_OBJDIR)/decode_tuple_header.o: decode/decode_tuple_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_ulong.o: decode/decode_ulong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_version.o: decode/decode_version.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_longlong.o: decode/decode_longlong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/decode_ulonglong.o: decode/decode_ulonglong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_atom.o: encode/encode_atom.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_bignum.o: encode/encode_bignum.c $(TARGET)/config.h
-$(MDD_OBJDIR)/encode_binary.o: encode/encode_binary.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_boolean.o: encode/encode_boolean.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_char.o: encode/encode_char.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_double.o: encode/encode_double.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_fun.o: encode/encode_fun.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_list_header.o: encode/encode_list_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_long.o: encode/encode_long.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_pid.o: encode/encode_pid.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_port.o: encode/encode_port.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_ref.o: encode/encode_ref.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_string.o: encode/encode_string.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_trace.o: encode/encode_trace.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/putget.h
-$(MDD_OBJDIR)/encode_tuple_header.o: encode/encode_tuple_header.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_ulong.o: encode/encode_ulong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_version.o: encode/encode_version.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h
-$(MDD_OBJDIR)/encode_longlong.o: encode/encode_longlong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h
-$(MDD_OBJDIR)/encode_ulonglong.o: encode/encode_ulonglong.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h
-$(MDD_OBJDIR)/epmd_port.o: epmd/epmd_port.c misc/ei_internal.h epmd/ei_epmd.h \
- misc/putget.h
-$(MDD_OBJDIR)/epmd_publish.o: epmd/epmd_publish.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
- misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
-$(MDD_OBJDIR)/epmd_unpublish.o: epmd/epmd_unpublish.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
- misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
-$(MDD_OBJDIR)/ei_decode_term.o: misc/ei_decode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_decode_term.h misc/putget.h
-$(MDD_OBJDIR)/ei_format.o: misc/ei_format.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/ei_malloc.h misc/ei_format.h
-$(MDD_OBJDIR)/ei_locking.o: misc/ei_locking.c $(TARGET)/config.h \
- misc/ei_malloc.h misc/ei_locking.h
-$(MDD_OBJDIR)/ei_malloc.o: misc/ei_malloc.c misc/ei_malloc.h
-$(MDD_OBJDIR)/ei_portio.o: misc/ei_portio.c misc/ei_portio.h misc/ei_internal.h
-$(MDD_OBJDIR)/ei_printterm.o: misc/ei_printterm.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/ei_printterm.h misc/ei_malloc.h
-$(MDD_OBJDIR)/ei_pthreads.o: misc/ei_pthreads.c $(TARGET)/config.h \
- ../include/ei.h misc/ei_locking.h
-$(MDD_OBJDIR)/ei_trace.o: misc/ei_trace.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/ei_trace.h
-$(MDD_OBJDIR)/ei_x_encode.o: misc/ei_x_encode.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/ei_x_encode.h \
- misc/ei_malloc.h
-$(MDD_OBJDIR)/eimd5.o: misc/eimd5.c misc/eimd5.h
-$(MDD_OBJDIR)/get_type.o: misc/get_type.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h misc/putget.h
-$(MDD_OBJDIR)/show_msg.o: misc/show_msg.c misc/eidef.h $(TARGET)/config.h \
- ../include/ei.h misc/eiext.h misc/putget.h misc/ei_printterm.h \
- misc/ei_internal.h misc/show_msg.h
-$(MDD_OBJDIR)/ei_compat.o: misc/ei_compat.c ../include/ei.h misc/ei_internal.h
-$(MDD_OBJDIR)/hash_dohash.o: registry/hash_dohash.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/hash_foreach.o: registry/hash_foreach.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/hash_freetab.o: registry/hash_freetab.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/hash_insert.o: registry/hash_insert.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/hash_isprime.o: registry/hash_isprime.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/hash_lookup.o: registry/hash_lookup.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/hash_newtab.o: registry/hash_newtab.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/hash_remove.o: registry/hash_remove.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/hash_resize.o: registry/hash_resize.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/hash_rlookup.o: registry/hash_rlookup.c registry/hash.h ../include/ei.h
-$(MDD_OBJDIR)/reg_close.o: registry/reg_close.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_delete.o: registry/reg_delete.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_dirty.o: registry/reg_dirty.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_dump.o: registry/reg_dump.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
- connect/ei_connect_int.h
-$(MDD_OBJDIR)/reg_free.o: registry/reg_free.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_get.o: registry/reg_get.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_getf.o: registry/reg_getf.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_geti.o: registry/reg_geti.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_getp.o: registry/reg_getp.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_gets.o: registry/reg_gets.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_make.o: registry/reg_make.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_open.o: registry/reg_open.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_purge.o: registry/reg_purge.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_resize.o: registry/reg_resize.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_restore.o: registry/reg_restore.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
- connect/ei_connect_int.h
-$(MDD_OBJDIR)/reg_set.o: registry/reg_set.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_setf.o: registry/reg_setf.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_seti.o: registry/reg_seti.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_setp.o: registry/reg_setp.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_sets.o: registry/reg_sets.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_stat.o: registry/reg_stat.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/reg_tabstat.o: registry/reg_tabstat.c registry/reg.h ../include/ei.h \
- registry/hash.h
-$(MDD_OBJDIR)/decode_term.o: legacy/decode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h ../include/erl_interface.h
-$(MDD_OBJDIR)/encode_term.o: legacy/encode_term.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- misc/putget.h misc/ei_x_encode.h ../include/erl_interface.h \
- legacy/erl_marshal.h legacy/erl_eterm.h legacy/portability.h
-$(MDD_OBJDIR)/erl_connect.o: legacy/erl_connect.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_config.h \
- legacy/erl_connect.h legacy/erl_eterm.h legacy/portability.h \
- legacy/erl_malloc.h misc/putget.h connect/ei_connect_int.h \
- misc/ei_locking.h epmd/ei_epmd.h misc/ei_internal.h
-$(MDD_OBJDIR)/erl_error.o: legacy/erl_error.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_error.h
-$(MDD_OBJDIR)/erl_eterm.o: legacy/erl_eterm.c misc/ei_locking.h \
- $(TARGET)/config.h connect/ei_resolve.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_eterm.h \
- legacy/portability.h legacy/erl_malloc.h legacy/erl_marshal.h \
- legacy/erl_error.h legacy/erl_internal.h misc/ei_internal.h
-$(MDD_OBJDIR)/erl_fix_alloc.o: legacy/erl_fix_alloc.c $(TARGET)/config.h \
- misc/ei_locking.h ../include/erl_interface.h ../include/ei.h \
- legacy/erl_error.h legacy/erl_malloc.h legacy/erl_fix_alloc.h \
- legacy/erl_eterm.h legacy/portability.h
-$(MDD_OBJDIR)/erl_format.o: legacy/erl_format.c ../include/erl_interface.h \
- ../include/ei.h legacy/erl_eterm.h legacy/portability.h \
- legacy/erl_malloc.h legacy/erl_error.h legacy/erl_internal.h
-$(MDD_OBJDIR)/erl_malloc.o: legacy/erl_malloc.c ../include/erl_interface.h \
- ../include/ei.h legacy/erl_fix_alloc.h legacy/erl_malloc.h \
- legacy/erl_internal.h legacy/erl_eterm.h legacy/portability.h \
- misc/ei_malloc.h
-$(MDD_OBJDIR)/erl_marshal.o: legacy/erl_marshal.c $(TARGET)/config.h \
- ../include/erl_interface.h ../include/ei.h legacy/erl_marshal.h \
- legacy/erl_eterm.h legacy/portability.h legacy/erl_malloc.h \
- legacy/erl_error.h legacy/erl_internal.h misc/eiext.h misc/putget.h
-$(MDD_OBJDIR)/erl_timeout.o: legacy/erl_timeout.c $(TARGET)/config.h \
- legacy/erl_timeout.h
-$(MDD_OBJDIR)/global_names.o: legacy/global_names.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-$(MDD_OBJDIR)/global_register.o: legacy/global_register.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h ../include/erl_interface.h
-$(MDD_OBJDIR)/global_unregister.o: legacy/global_unregister.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-$(MDD_OBJDIR)/global_whereis.o: legacy/global_whereis.c misc/eidef.h \
- $(TARGET)/config.h ../include/ei.h misc/eiext.h \
- connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
- ../include/erl_interface.h legacy/erl_connect.h
-
diff --git a/lib/erl_interface/src/encode/encode_binary.c b/lib/erl_interface/src/encode/encode_binary.c
index 4471c51769..0562979417 100644
--- a/lib/erl_interface/src/encode/encode_binary.c
+++ b/lib/erl_interface/src/encode/encode_binary.c
@@ -22,6 +22,10 @@
#include "eiext.h"
#include "putget.h"
+static void copy_bits(const unsigned char* src, size_t soffs,
+ unsigned char* dst, size_t n);
+
+
int ei_encode_binary(char *buf, int *index, const void *p, long len)
{
char *s = buf + *index;
@@ -40,3 +44,106 @@ int ei_encode_binary(char *buf, int *index, const void *p, long len)
return 0;
}
+int ei_encode_bitstring(char *buf, int *index,
+ const char *p,
+ size_t bitoffs,
+ size_t bits)
+{
+ char *s = buf + *index;
+ char *s0 = s;
+ size_t bytes = (bits + 7) / 8;
+ char last_bits = bits % 8;
+
+ if (!buf) s += last_bits ? 6 : 5;
+ else {
+ char* tagp = s++;
+ put32be(s, bytes);
+ if (last_bits) {
+ *tagp = ERL_BIT_BINARY_EXT;
+ put8(s, last_bits);
+ }
+ else
+ *tagp = ERL_BINARY_EXT;
+
+ copy_bits((const unsigned char*)p, bitoffs, (unsigned char*)s, bits);
+ }
+ s += bytes;
+
+ *index += s-s0;
+
+ return 0;
+}
+
+
+/*
+ * MAKE_MASK(n) constructs a mask with n bits.
+ * Example: MAKE_MASK(3) returns the binary number 00000111.
+ */
+#define MAKE_MASK(n) ((((unsigned) 1) << (n))-1)
+
+
+static
+void copy_bits(const unsigned char* src, /* Base pointer to source. */
+ size_t soffs, /* Bit offset for source relative to src. */
+ unsigned char* dst, /* Destination. */
+ size_t n) /* Number of bits to copy. */
+{
+ unsigned rmask;
+ unsigned count;
+ unsigned deoffs;
+ unsigned bits;
+ unsigned bits1;
+ unsigned rshift;
+
+ if (n == 0)
+ return;
+
+ deoffs = n & 7;
+ rmask = deoffs ? (MAKE_MASK(deoffs) << (8-deoffs)) : 0;
+
+ if (soffs == 0) {
+ unsigned nbytes = (n + 7) / 8;
+ memcpy(dst, src, nbytes);
+ if (rmask)
+ dst[nbytes-1] &= rmask;
+ return;
+ }
+
+ src += soffs / 8;
+ soffs &= 7;
+
+ if (n < 8) { /* Less than one byte */
+ bits = (*src << soffs);
+ if (soffs+n > 8) {
+ src++;
+ bits |= (*src >> (8 - soffs));
+ }
+ *dst = bits & rmask;
+ return;
+ }
+
+ count = n >> 3;
+
+ rshift = 8 - soffs;
+ bits = *src;
+ if (soffs + n > 8) {
+ src++;
+ }
+
+ while (count--) {
+ bits1 = bits << soffs;
+ bits = *src;
+ src++;
+ *dst = bits1 | (bits >> rshift);
+ dst++;
+ }
+
+ if (rmask) {
+ bits1 = bits << soffs;
+ if ((rmask << rshift) & 0xff) {
+ bits = *src;
+ bits1 |= (bits >> rshift);
+ }
+ *dst = bits1 & rmask;
+ }
+}
diff --git a/lib/erl_interface/src/encode/encode_fun.c b/lib/erl_interface/src/encode/encode_fun.c
index 3bfc7530d1..e29424f9f4 100644
--- a/lib/erl_interface/src/encode/encode_fun.c
+++ b/lib/erl_interface/src/encode/encode_fun.c
@@ -26,56 +26,72 @@ int ei_encode_fun(char *buf, int *index, const erlang_fun *p)
{
int ix = *index;
- if (p->arity == -1) {
- /* ERL_FUN_EXT */
- if (buf != NULL) {
- char* s = buf + ix;
- put8(s, ERL_FUN_EXT);
- put32be(s, p->n_free_vars);
- }
- ix += sizeof(char) + 4;
- if (ei_encode_pid(buf, &ix, &p->pid) < 0)
- return -1;
- if (ei_encode_atom_as(buf, &ix, p->module, ERLANG_UTF8, p->module_org_enc) < 0)
- return -1;
- if (ei_encode_long(buf, &ix, p->index) < 0)
- return -1;
- if (ei_encode_long(buf, &ix, p->uniq) < 0)
- return -1;
- if (buf != NULL)
- memcpy(buf + ix, p->free_vars, p->free_var_len);
- ix += p->free_var_len;
- } else {
- char *size_p;
- /* ERL_NEW_FUN_EXT */
- if (buf != NULL) {
- char* s = buf + ix;
- put8(s, ERL_NEW_FUN_EXT);
- size_p = s;
- s += 4;
- put8(s, p->arity);
- memcpy(s, p->md5, sizeof(p->md5));
- s += sizeof(p->md5);
- put32be(s, p->index);
- put32be(s, p->n_free_vars);
- } else
- size_p = NULL;
- ix += 1 + 4 + 1 + sizeof(p->md5) + 4 + 4;
- if (ei_encode_atom_as(buf, &ix, p->module, ERLANG_UTF8, p->module_org_enc) < 0)
- return -1;
- if (ei_encode_long(buf, &ix, p->old_index) < 0)
- return -1;
- if (ei_encode_long(buf, &ix, p->uniq) < 0)
- return -1;
- if (ei_encode_pid(buf, &ix, &p->pid) < 0)
- return -1;
- if (buf != NULL)
- memcpy(buf + ix, p->free_vars, p->free_var_len);
- ix += p->free_var_len;
- if (size_p != NULL) {
- int sz = buf + ix - size_p;
- put32be(size_p, sz);
+ switch (p->type) {
+ case EI_FUN_CLOSURE:
+ if (p->arity == -1) {
+ /* ERL_FUN_EXT */
+ if (buf != NULL) {
+ char* s = buf + ix;
+ put8(s, ERL_FUN_EXT);
+ put32be(s, p->u.closure.n_free_vars);
+ }
+ ix += sizeof(char) + 4;
+ if (ei_encode_pid(buf, &ix, &p->u.closure.pid) < 0)
+ return -1;
+ if (ei_encode_atom_as(buf, &ix, p->module, ERLANG_UTF8, ERLANG_UTF8) < 0)
+ return -1;
+ if (ei_encode_long(buf, &ix, p->u.closure.index) < 0)
+ return -1;
+ if (ei_encode_long(buf, &ix, p->u.closure.uniq) < 0)
+ return -1;
+ if (buf != NULL)
+ memcpy(buf + ix, p->u.closure.free_vars, p->u.closure.free_var_len);
+ ix += p->u.closure.free_var_len;
+ } else {
+ char *size_p;
+ if (buf != NULL) {
+ char* s = buf + ix;
+ put8(s, ERL_NEW_FUN_EXT);
+ size_p = s;
+ s += 4;
+ put8(s, p->arity);
+ memcpy(s, p->u.closure.md5, sizeof(p->u.closure.md5));
+ s += sizeof(p->u.closure.md5);
+ put32be(s, p->u.closure.index);
+ put32be(s, p->u.closure.n_free_vars);
+ } else
+ size_p = NULL;
+ ix += 1 + 4 + 1 + sizeof(p->u.closure.md5) + 4 + 4;
+ if (ei_encode_atom_as(buf, &ix, p->module, ERLANG_UTF8, ERLANG_UTF8) < 0)
+ return -1;
+ if (ei_encode_long(buf, &ix, p->u.closure.old_index) < 0)
+ return -1;
+ if (ei_encode_long(buf, &ix, p->u.closure.uniq) < 0)
+ return -1;
+ if (ei_encode_pid(buf, &ix, &p->u.closure.pid) < 0)
+ return -1;
+ if (buf != NULL)
+ memcpy(buf + ix, p->u.closure.free_vars, p->u.closure.free_var_len);
+ ix += p->u.closure.free_var_len;
+ if (size_p != NULL) {
+ int sz = buf + ix - size_p;
+ put32be(size_p, sz);
+ }
}
+ break;
+ case EI_FUN_EXPORT:
+ if (buf != NULL) {
+ char* s = buf + ix;
+ put8(s, ERL_EXPORT_EXT);
+ }
+ ix++;
+ if (ei_encode_atom_as(buf, &ix, p->module, ERLANG_UTF8, ERLANG_UTF8) < 0)
+ return -1;
+ if (ei_encode_atom_as(buf, &ix, p->u.exprt.func, ERLANG_UTF8, ERLANG_UTF8) < 0)
+ return -1;
+ if (ei_encode_long(buf, &ix, p->arity) < 0)
+ return -1;
+ break;
}
*index = ix;
return 0;
diff --git a/lib/erl_interface/src/epmd/epmd_port.c b/lib/erl_interface/src/epmd/epmd_port.c
index 2ec418b24a..492c3fb3aa 100644
--- a/lib/erl_interface/src/epmd/epmd_port.c
+++ b/lib/erl_interface/src/epmd/epmd_port.c
@@ -62,31 +62,38 @@
int ei_epmd_connect_tmo(struct in_addr *inaddr, unsigned ms)
{
static unsigned int epmd_port = 0;
- struct sockaddr_in saddr;
- int sd;
- int res;
+ int port, sd, err;
+ struct in_addr ip_addr;
+ struct sockaddr_in addr;
+ unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms;
+
+ err = ei_socket__(&sd);
+ if (err) {
+ erl_errno = err;
+ return -1;
+ }
if (epmd_port == 0) {
char* port_str = getenv("ERL_EPMD_PORT");
epmd_port = (port_str != NULL) ? atoi(port_str) : EPMD_PORT;
}
- memset(&saddr, 0, sizeof(saddr));
- saddr.sin_port = htons(epmd_port);
- saddr.sin_family = AF_INET;
- if (!inaddr) saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- else memmove(&saddr.sin_addr,inaddr,sizeof(saddr.sin_addr));
+ port = (int) epmd_port;
- if (((sd = socket(PF_INET, SOCK_STREAM, 0)) < 0))
- {
- erl_errno = errno;
- return -1;
+ if (!inaddr) {
+ ip_addr.s_addr = htonl(INADDR_LOOPBACK);
+ inaddr = &ip_addr;
}
+
+ memset((void *) &addr, 0, sizeof(struct sockaddr_in));
+ memcpy((void *) &addr.sin_addr, (void *) inaddr, sizeof(addr.sin_addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
- if ((res = ei_connect_t(sd,(struct sockaddr *)&saddr,sizeof(saddr),ms)) < 0)
- {
- erl_errno = (res == -2) ? ETIMEDOUT : errno;
- closesocket(sd);
+ err = ei_connect_t__(sd, (void *) &addr, sizeof(addr), tmo);
+ if (err) {
+ erl_errno = err;
+ ei_close__(sd);
return -1;
}
@@ -104,6 +111,9 @@ static int ei_epmd_r4_port (struct in_addr *addr, const char *alive,
int port;
int dist_high, dist_low, proto;
int res;
+ int err;
+ ssize_t dlen;
+ unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms;
#if defined(VXWORKS)
char ntoabuf[32];
#endif
@@ -124,10 +134,14 @@ static int ei_epmd_r4_port (struct in_addr *addr, const char *alive,
return -1;
}
- if ((res = ei_write_fill_t(fd, buf, len+2, ms)) != len+2) {
- closesocket(fd);
- erl_errno = (res == -2) ? ETIMEDOUT : EIO;
- return -1;
+ dlen = len + 2;
+ err = ei_write_fill_t__(fd, buf, &dlen, tmo);
+ if (!err && dlen != (ssize_t) len + 2)
+ erl_errno = EIO;
+ if (err) {
+ ei_close__(fd);
+ EI_CONN_SAVE_ERRNO__(err);
+ return -1;
}
#ifdef VXWORKS
@@ -142,12 +156,15 @@ static int ei_epmd_r4_port (struct in_addr *addr, const char *alive,
"-> PORT2_REQ alive=%s ip=%s",alive,inet_ntoa(*addr));
#endif
- /* read first two bytes (response type, response) */
- if ((res = ei_read_fill_t(fd, buf, 2, ms)) != 2) {
- EI_TRACE_ERR0("ei_epmd_r4_port","<- CLOSE");
- erl_errno = (res == -2) ? ETIMEDOUT : EIO;
- closesocket(fd);
- return -2; /* version mismatch */
+ dlen = (ssize_t) 2;
+ err = ei_read_fill_t__(fd, buf, &dlen, tmo);
+ if (!err && dlen != (ssize_t) 2)
+ erl_errno = EIO;
+ if (err) {
+ EI_TRACE_ERR0("ei_epmd_r4_port","<- CLOSE");
+ ei_close__(fd);
+ EI_CONN_SAVE_ERRNO__(err);
+ return -2;
}
s = buf;
@@ -156,7 +173,7 @@ static int ei_epmd_r4_port (struct in_addr *addr, const char *alive,
if (res != EI_EPMD_PORT2_RESP) { /* response type */
EI_TRACE_ERR1("ei_epmd_r4_port","<- unknown (%d)",res);
EI_TRACE_ERR0("ei_epmd_r4_port","-> CLOSE");
- closesocket(fd);
+ ei_close__(fd);
erl_errno = EIO;
return -1;
}
@@ -167,7 +184,7 @@ static int ei_epmd_r4_port (struct in_addr *addr, const char *alive,
if ((res = get8(s))) {
/* got negative response */
EI_TRACE_ERR1("ei_epmd_r4_port","<- PORT2_RESP result=%d (failure)",res);
- closesocket(fd);
+ ei_close__(fd);
erl_errno = EIO;
return -1;
}
@@ -175,14 +192,18 @@ static int ei_epmd_r4_port (struct in_addr *addr, const char *alive,
EI_TRACE_CONN1("ei_epmd_r4_port","<- PORT2_RESP result=%d (ok)",res);
/* expecting remaining 8 bytes */
- if ((res = ei_read_fill_t(fd,buf,8,ms)) != 8) {
+ dlen = (ssize_t) 8;
+ err = ei_read_fill_t__(fd, buf, &dlen, tmo);
+ if (!err && dlen != (ssize_t) 8)
+ err = EIO;
+ if (err) {
EI_TRACE_ERR0("ei_epmd_r4_port","<- CLOSE");
- erl_errno = (res == -2) ? ETIMEDOUT : EIO;
- closesocket(fd);
+ ei_close__(fd);
+ EI_CONN_SAVE_ERRNO__(err);
return -1;
}
- closesocket(fd);
+ ei_close__(fd);
s = buf;
port = get16be(s);
diff --git a/lib/erl_interface/src/epmd/epmd_publish.c b/lib/erl_interface/src/epmd/epmd_publish.c
index 47d68a6db0..20b8e867e8 100644
--- a/lib/erl_interface/src/epmd/epmd_publish.c
+++ b/lib/erl_interface/src/epmd/epmd_publish.c
@@ -68,8 +68,10 @@ static int ei_epmd_r4_publish (int port, const char *alive, unsigned ms)
int nlen = strlen(alive);
int len = elen + nlen + 13; /* hard coded: be careful! */
int n;
- int res, creation;
-
+ int err, res, creation;
+ ssize_t dlen;
+ unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms;
+
if (len > sizeof(buf)-2)
{
erl_errno = ERANGE;
@@ -93,29 +95,39 @@ static int ei_epmd_r4_publish (int port, const char *alive, unsigned ms)
if ((fd = ei_epmd_connect_tmo(NULL,ms)) < 0) return fd;
- if ((res = ei_write_fill_t(fd, buf, len+2, ms)) != len+2) {
- closesocket(fd);
- erl_errno = (res == -2) ? ETIMEDOUT : EIO;
- return -1;
+ dlen = (ssize_t) len+2;
+ err = ei_write_fill_t__(fd, buf, &dlen, tmo);
+ if (!err && dlen != (ssize_t) len + 2)
+ erl_errno = EIO;
+ if (err) {
+ ei_close__(fd);
+ EI_CONN_SAVE_ERRNO__(err);
+ return -1;
}
EI_TRACE_CONN6("ei_epmd_r4_publish",
"-> ALIVE2_REQ alive=%s port=%d ntype=%d "
"proto=%d dist-high=%d dist-low=%d",
alive,port,'H',EI_MYPROTO,EI_DIST_HIGH,EI_DIST_LOW);
-
- if ((n = ei_read_fill_t(fd, buf, 4, ms)) != 4) {
+
+ dlen = (ssize_t) 4;
+ err = ei_read_fill_t__(fd, buf, &dlen, tmo);
+ n = (int) dlen;
+ if (!err && n != 4)
+ err = EIO;
+ if (err) {
EI_TRACE_ERR0("ei_epmd_r4_publish","<- CLOSE");
- closesocket(fd);
- erl_errno = (n == -2) ? ETIMEDOUT : EIO;
+ ei_close__(fd);
+ EI_CONN_SAVE_ERRNO__(err);
return -2; /* version mismatch */
}
+
/* Don't close fd here! It keeps us registered with epmd */
s = buf;
if (((res=get8(s)) != EI_EPMD_ALIVE2_RESP)) { /* response */
EI_TRACE_ERR1("ei_epmd_r4_publish","<- unknown (%d)",res);
EI_TRACE_ERR0("ei_epmd_r4_publish","-> CLOSE");
- closesocket(fd);
+ ei_close__(fd);
erl_errno = EIO;
return -1;
}
@@ -124,7 +136,7 @@ static int ei_epmd_r4_publish (int port, const char *alive, unsigned ms)
if (((res=get8(s)) != 0)) { /* 0 == success */
EI_TRACE_ERR1("ei_epmd_r4_publish"," result=%d (fail)",res);
- closesocket(fd);
+ ei_close__(fd);
erl_errno = EIO;
return -1;
}
diff --git a/lib/erl_interface/src/epmd/epmd_unpublish.c b/lib/erl_interface/src/epmd/epmd_unpublish.c
index 255d0ffb59..c112f74147 100644
--- a/lib/erl_interface/src/epmd/epmd_unpublish.c
+++ b/lib/erl_interface/src/epmd/epmd_unpublish.c
@@ -58,7 +58,9 @@ int ei_unpublish_tmo(const char *alive, unsigned ms)
char buf[EPMDBUF];
char *s = (char*)buf;
int len = 1 + strlen(alive);
- int fd, res;
+ int fd, err;
+ ssize_t dlen;
+ unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms;
if (len > sizeof(buf)-3) {
erl_errno = ERANGE;
@@ -72,20 +74,29 @@ int ei_unpublish_tmo(const char *alive, unsigned ms)
/* FIXME can't connect, return success?! At least commen whats up */
if ((fd = ei_epmd_connect_tmo(NULL,ms)) < 0) return fd;
- if ((res = ei_write_fill_t(fd, buf, len+2,ms)) != len+2) {
- closesocket(fd);
- erl_errno = (res == -2) ? ETIMEDOUT : EIO;
- return -1;
+ dlen = (ssize_t) len+2;
+ err = ei_write_fill_t__(fd, buf, &dlen, tmo);
+ if (!err && dlen != (ssize_t) len + 2)
+ erl_errno = EIO;
+ if (err) {
+ ei_close__(fd);
+ EI_CONN_SAVE_ERRNO__(err);
+ return -1;
}
EI_TRACE_CONN1("ei_unpublish_tmo","-> STOP %s",alive);
-
- if ((res = ei_read_fill_t(fd, buf, 7, ms)) != 7) {
- closesocket(fd);
- erl_errno = (res == -2) ? ETIMEDOUT : EIO;
- return -1;
+
+ dlen = (ssize_t) 7;
+ err = ei_read_fill_t__(fd, buf, &dlen, tmo);
+ if (!err && dlen != (ssize_t) 7)
+ erl_errno = EIO;
+ if (err) {
+ ei_close__(fd);
+ EI_CONN_SAVE_ERRNO__(err);
+ return -1;
}
- closesocket(fd);
+
+ ei_close__(fd);
buf[7]=(char)0; /* terminate the string */
if (!strcmp("STOPPED",(char *)buf)) {
diff --git a/lib/erl_interface/src/legacy/erl_connect.c b/lib/erl_interface/src/legacy/erl_connect.c
index 7ffd545d3e..e2fd4611c0 100644
--- a/lib/erl_interface/src/legacy/erl_connect.c
+++ b/lib/erl_interface/src/legacy/erl_connect.c
@@ -179,15 +179,13 @@ int erl_xconnect(Erl_IpAddr addr, char *alivename)
*
* API: erl_close_connection()
*
- * Close a connection. FIXME call ei_close_connection() later.
- *
* Returns 0 on success and -1 on failure.
*
***************************************************************************/
int erl_close_connection(int fd)
{
- return closesocket(fd);
+ return ei_close_connection(fd);
}
/*
@@ -220,7 +218,10 @@ int erl_reg_send(int fd, char *server_name, ETERM *msg)
ei_x_buff x;
int r;
- ei_x_new_with_version(&x);
+ if (ei_x_new_with_version(&x) < 0) {
+ erl_errno = ENOMEM;
+ return 0;
+ }
if (ei_x_encode_term(&x, msg) < 0) {
erl_errno = EINVAL;
r = 0;
diff --git a/lib/erl_interface/src/legacy/erl_eterm.c b/lib/erl_interface/src/legacy/erl_eterm.c
index 9ad92121f4..7ecea83b1a 100644
--- a/lib/erl_interface/src/legacy/erl_eterm.c
+++ b/lib/erl_interface/src/legacy/erl_eterm.c
@@ -65,7 +65,7 @@ void erl_init(void *hp,long heap_size)
{
erl_init_malloc(hp, heap_size);
erl_init_marshal();
- ei_init_resolve();
+ (void) ei_init();
}
void erl_set_compat_rel(unsigned rel)
@@ -299,12 +299,7 @@ void erl_mk_pid_helper(ETERM *ep, unsigned int number,
unsigned int serial, unsigned int creation)
{
ERL_PID_NUMBER(ep) = number & 0x7fff; /* 15 bits */
- if (ei_internal_use_r9_pids_ports()) {
- ERL_PID_SERIAL(ep) = serial & 0x07; /* 3 bits */
- }
- else {
- ERL_PID_SERIAL(ep) = serial & 0x1fff; /* 13 bits */
- }
+ ERL_PID_SERIAL(ep) = serial & 0x1fff; /* 13 bits */
ERL_PID_CREATION(ep) = creation; /* 32 bits */
}
@@ -334,12 +329,7 @@ ETERM *erl_mk_port(const char *node,
void erl_mk_port_helper(ETERM* ep, unsigned number, unsigned int creation)
{
- if (ei_internal_use_r9_pids_ports()) {
- ERL_PORT_NUMBER(ep) = number & 0x3ffff; /* 18 bits */
- }
- else {
- ERL_PORT_NUMBER(ep) = number & 0x0fffffff; /* 18 bits */
- }
+ ERL_PORT_NUMBER(ep) = number & 0x0fffffff; /* 18 bits */
ERL_PORT_CREATION(ep) = creation; /* 32 bits */
}
diff --git a/lib/erl_interface/src/legacy/erl_marshal.c b/lib/erl_interface/src/legacy/erl_marshal.c
index caa171858d..932bba43bf 100644
--- a/lib/erl_interface/src/legacy/erl_marshal.c
+++ b/lib/erl_interface/src/legacy/erl_marshal.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -107,7 +107,7 @@ static int init_cmp_num_class_p=1; /* initialize array, the first time */
void erl_init_marshal(void)
{
if (init_cmp_array_p) {
- memset(cmp_array, 0, CMP_ARRAY_SIZE);
+ memset(cmp_array, 0, sizeof cmp_array);
cmp_array[ERL_SMALL_INTEGER_EXT] = ERL_NUM_CMP;
cmp_array[ERL_INTEGER_EXT] = ERL_NUM_CMP;
cmp_array[ERL_FLOAT_EXT] = ERL_NUM_CMP;
@@ -1803,7 +1803,7 @@ static int cmp_exe2(unsigned char **e1, unsigned char **e2)
k = 0;
while (1) {
if (k++ == min){
- if (i == j) return 0;
+ if (i == j) return compare_top_ext(e1 , e2);
if (i < j) return -1;
return 1;
}
diff --git a/lib/erl_interface/src/misc/ei_compat.c b/lib/erl_interface/src/misc/ei_compat.c
index 93d7dbfb83..787895992e 100644
--- a/lib/erl_interface/src/misc/ei_compat.c
+++ b/lib/erl_interface/src/misc/ei_compat.c
@@ -22,19 +22,22 @@
#include "ei.h"
#include "ei_internal.h"
-#define EI_COMPAT_NO_REL (~((unsigned) 0))
+#include <limits.h>
-static unsigned compat_rel = EI_COMPAT_NO_REL;
+#ifndef EI_COMPAT
+# define EI_COMPAT UINT_MAX
+#endif
+
+static unsigned compat_rel = EI_COMPAT;
void
ei_set_compat_rel(unsigned rel)
{
- if (compat_rel == EI_COMPAT_NO_REL)
- compat_rel = rel;
+ compat_rel = rel;
}
-int
-ei_internal_use_r9_pids_ports(void)
+int ei_internal_use_21_bitstr_expfun(void)
{
- return compat_rel < 10;
+ return compat_rel < 22;
}
+
diff --git a/lib/erl_interface/src/misc/ei_decode_term.c b/lib/erl_interface/src/misc/ei_decode_term.c
index 63a7034508..8a4f7cc30d 100644
--- a/lib/erl_interface/src/misc/ei_decode_term.c
+++ b/lib/erl_interface/src/misc/ei_decode_term.c
@@ -87,6 +87,14 @@ int ei_decode_ei_term(const char* buf, int* index, ei_term* term)
case ERL_BINARY_EXT:
term->size = get32be(s);
return 0;
+ case ERL_BIT_BINARY_EXT: {
+ int bytes = get32be(s);
+ int last_bits = get8(s);
+ if (((last_bits==0) != (bytes==0)) || last_bits > 8)
+ return -1;
+ term->size = bytes;
+ return 0;
+ }
case ERL_SMALL_BIG_EXT:
if ((term->arity = get8(s)) != 4) return -1;
sign = get8(s);
diff --git a/lib/erl_interface/src/misc/ei_init.c b/lib/erl_interface/src/misc/ei_init.c
new file mode 100644
index 0000000000..5357968657
--- /dev/null
+++ b/lib/erl_interface/src/misc/ei_init.c
@@ -0,0 +1,32 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2019. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "ei.h"
+#include "ei_resolve.h"
+#include "ei_internal.h"
+
+int
+ei_init(void)
+{
+ int error = ei_init_connect();
+ if (error)
+ return error;
+ return ei_init_resolve();
+}
diff --git a/lib/erl_interface/src/misc/ei_internal.h b/lib/erl_interface/src/misc/ei_internal.h
index aa6aacd703..ab12597c86 100644
--- a/lib/erl_interface/src/misc/ei_internal.h
+++ b/lib/erl_interface/src/misc/ei_internal.h
@@ -22,19 +22,20 @@
#ifndef _EI_INTERNAL_H
#define _EI_INTERNAL_H
+#ifdef EI_HIDE_REAL_ERRNO
+# define EI_CONN_SAVE_ERRNO__(E) \
+ ((E) == ETIMEDOUT ? (erl_errno = ETIMEDOUT) : (erl_errno = EIO))
+#else
+# define EI_CONN_SAVE_ERRNO__(E) \
+ (erl_errno = (E))
+#endif
+
/*
* Some useful stuff not to be exported to users.
*/
#ifdef __WIN32__
#define MAXPATHLEN 256
-#define writesocket(sock,buf,nbyte) send(sock,buf,nbyte,0)
-#define readsocket(sock,buf,nbyte) recv(sock,buf,nbyte,0)
-#else /* not __WIN32__ */
-#define writesocket write
-#define readsocket read
-#define closesocket close
-#define ioctlsocket ioctl
#endif
/*
@@ -152,7 +153,12 @@
extern int ei_tracelevel;
+int ei_init_connect(void);
+
void ei_trace_printf(const char *name, int level, const char *format, ...);
-int ei_internal_use_r9_pids_ports(void);
+int ei_internal_use_21_bitstr_expfun(void);
+
+int ei_get_cbs_ctx__(ei_socket_callbacks **cbs, void **ctx, int fd);
+
#endif /* _EI_INTERNAL_H */
diff --git a/lib/erl_interface/src/misc/ei_portio.c b/lib/erl_interface/src/misc/ei_portio.c
index 8cd35bf2e5..bccc86c1b1 100644
--- a/lib/erl_interface/src/misc/ei_portio.c
+++ b/lib/erl_interface/src/misc/ei_portio.c
@@ -19,9 +19,13 @@
*
*/
+
+#include "eidef.h"
+
#ifdef __WIN32__
#include <winsock2.h>
#include <windows.h>
+#include <winbase.h>
#include <process.h>
#include <stdio.h>
#include <stdlib.h>
@@ -35,10 +39,6 @@ static unsigned long param_one = 1;
#define SET_BLOCKING(Sock) ioctlsocket((Sock),FIONBIO,&param_zero)
#define SET_NONBLOCKING(Sock) ioctlsocket((Sock),FIONBIO,&param_one)
-#define ERROR_WOULDBLOCK WSAEWOULDBLOCK
-#define ERROR_TIMEDOUT WSAETIMEDOUT
-#define ERROR_INPROGRESS WSAEINPROGRESS
-#define GET_SOCKET_ERROR() WSAGetLastError()
#define MEANS_SOCKET_ERROR(Ret) ((Ret == SOCKET_ERROR))
#define IS_INVALID_SOCKET(Sock) ((Sock) == INVALID_SOCKET)
@@ -50,125 +50,414 @@ static unsigned long param_one = 1;
#include <taskLib.h>
#include <inetLib.h>
#include <selectLib.h>
-#include <sys/types.h>
#include <ioLib.h>
#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <timers.h>
static unsigned long param_zero = 0;
static unsigned long param_one = 1;
#define SET_BLOCKING(Sock) ioctl((Sock),FIONBIO,(int)&param_zero)
#define SET_NONBLOCKING(Sock) ioctl((Sock),FIONBIO,(int)&param_one)
-#define ERROR_WOULDBLOCK EWOULDBLOCK
-#define ERROR_TIMEDOUT ETIMEDOUT
-#define ERROR_INPROGRESS EINPROGRESS
-#define GET_SOCKET_ERROR() (errno)
#define MEANS_SOCKET_ERROR(Ret) ((Ret) == ERROR)
#define IS_INVALID_SOCKET(Sock) ((Sock) < 0)
#else /* other unix */
#include <stdlib.h>
-#include <sys/types.h>
#include <sys/socket.h>
-#include <sys/uio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
-#ifndef EWOULDBLOCK
-#define ERROR_WOULDBLOCK EAGAIN
-#else
-#define ERROR_WOULDBLOCK EWOULDBLOCK
-#endif
#define SET_BLOCKING(fd) fcntl((fd), F_SETFL, \
fcntl((fd), F_GETFL, 0) & ~O_NONBLOCK)
#define SET_NONBLOCKING(fd) fcntl((fd), F_SETFL, \
fcntl((fd), F_GETFL, 0) | O_NONBLOCK)
-#define ERROR_TIMEDOUT ETIMEDOUT
-#define ERROR_INPROGRESS EINPROGRESS
-#define GET_SOCKET_ERROR() (errno)
#define MEANS_SOCKET_ERROR(Ret) ((Ret) < 0)
#define IS_INVALID_SOCKET(Sock) ((Sock) < 0)
#endif
/* common includes */
-#include "eidef.h"
+#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include "ei_portio.h"
-#include "ei_internal.h"
-
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#else
#include <time.h>
#endif
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#include "ei_portio.h"
+#include "ei_internal.h"
+
+#ifdef __WIN32__
-#ifdef HAVE_WRITEV
-static int ei_writev_t(int fd, struct iovec *iov, int iovcnt, unsigned ms)
+#define writesocket(sock,buf,nbyte) send(sock,buf,nbyte,0)
+#define readsocket(sock,buf,nbyte) recv(sock,buf,nbyte,0)
+
+static int get_error(void)
{
- int res;
- if (ms != 0) {
- fd_set writemask;
- struct timeval tv;
- tv.tv_sec = (time_t) (ms / 1000U);
- ms %= 1000U;
- tv.tv_usec = (time_t) (ms * 1000U);
- FD_ZERO(&writemask);
- FD_SET(fd,&writemask);
- switch (select(fd+1, NULL, &writemask, NULL, &tv)) {
- case -1 :
- return -1; /* i/o error */
- case 0:
- return -2; /* timeout */
- default:
- if (!FD_ISSET(fd, &writemask)) {
- return -1; /* Other error */
- }
- }
+ switch (WSAGetLastError()) {
+ case WSAEWOULDBLOCK: return EWOULDBLOCK;
+ case WSAETIMEDOUT: return ETIMEDOUT;
+ case WSAEINPROGRESS: return EINPROGRESS;
+ case WSA_NOT_ENOUGH_MEMORY: return ENOMEM;
+ case WSA_INVALID_PARAMETER: return EINVAL;
+ case WSAEBADF: return EBADF;
+ case WSAEINVAL: return EINVAL;
+ case WSAEADDRINUSE: return EADDRINUSE;
+ case WSAENETUNREACH: return ENETUNREACH;
+ case WSAECONNABORTED: return ECONNABORTED;
+ case WSAECONNRESET: return ECONNRESET;
+ case WSAECONNREFUSED: return ECONNREFUSED;
+ case WSAEHOSTUNREACH: return EHOSTUNREACH;
+ case WSAEMFILE: return EMFILE;
+ case WSAEALREADY: return EALREADY;
+ default: return EIO;
}
+}
+
+#else /* not __WIN32__ */
+
+#define writesocket write
+#define readsocket read
+#define closesocket close
+#define ioctlsocket ioctl
+
+static int get_error(void)
+{
+ int err = errno;
+ if (err == 0)
+ return EIO; /* Make sure never to return 0 as error code... */
+ return err;
+}
+
+#endif
+
+int ei_plugin_socket_impl__ = 0;
+
+/*
+ * Callbacks for communication over TCP/IPv4
+ */
+
+static int tcp_get_fd(void *ctx, int *fd)
+{
+ return EI_DFLT_CTX_TO_FD__(ctx, fd);
+}
+
+static int tcp_hs_packet_header_size(void *ctx, int *sz)
+{
+ int fd;
+ *sz = 2;
+ return EI_DFLT_CTX_TO_FD__(ctx, &fd);
+}
+
+static int tcp_handshake_complete(void *ctx)
+{
+ int res, fd, one = 1;
+
+ res = EI_DFLT_CTX_TO_FD__(ctx, &fd);
+ if (res)
+ return res;
+
+ res = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one));
+ if (MEANS_SOCKET_ERROR(res))
+ return get_error();
+
+ res = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&one, sizeof(one));
+ if (MEANS_SOCKET_ERROR(res))
+ return get_error();
+
+ return 0;
+}
+
+static int tcp_socket(void **ctx, void *setup_ctx)
+{
+ int fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (MEANS_SOCKET_ERROR(fd))
+ return get_error();
+
+ *ctx = EI_FD_AS_CTX__(fd);
+ return 0;
+}
+
+static int tcp_close(void *ctx)
+{
+ int fd, res;
+
+ res = EI_DFLT_CTX_TO_FD__(ctx, &fd);
+ if (res)
+ return res;
+
+ res = closesocket(fd);
+ if (MEANS_SOCKET_ERROR(res))
+ return get_error();
+
+ return 0;
+}
+
+static int tcp_listen(void *ctx, void *addr, int *len, int backlog)
+{
+ int res, fd;
+ socklen_t sz = (socklen_t) *len;
+ int on = 1;
+
+ res = EI_DFLT_CTX_TO_FD__(ctx, &fd);
+ if (res)
+ return res;
+
+ res = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on));
+ if (MEANS_SOCKET_ERROR(res))
+ return get_error();
+
+ res = bind(fd, (struct sockaddr *) addr, sz);
+ if (MEANS_SOCKET_ERROR(res))
+ return get_error();
+
+ res = getsockname(fd, (struct sockaddr *) addr, (socklen_t *) &sz);
+ if (MEANS_SOCKET_ERROR(res))
+ return get_error();
+ *len = (int) sz;
+
+ res = listen(fd, backlog);
+ if (MEANS_SOCKET_ERROR(res))
+ return get_error();
+
+ return 0;
+}
+
+static int tcp_accept(void **ctx, void *addr, int *len, unsigned unused)
+{
+ int fd, res;
+ socklen_t addr_len = (socklen_t) *len;
+
+ if (!ctx)
+ return EINVAL;
+
+ res = EI_DFLT_CTX_TO_FD__(*ctx, &fd);
+ if (res)
+ return res;
+
+ res = accept(fd, (struct sockaddr*) addr, &addr_len);
+ if (MEANS_SOCKET_ERROR(res))
+ return get_error();
+
+ *len = (int) addr_len;
+
+ *ctx = EI_FD_AS_CTX__(res);
+ return 0;
+}
+
+static int tcp_connect(void *ctx, void *addr, int len, unsigned unused)
+{
+ int res, fd;
+
+ res = EI_DFLT_CTX_TO_FD__(ctx, &fd);
+ if (res)
+ return res;
+
+ res = connect(fd, (struct sockaddr *) addr, len);
+ if (MEANS_SOCKET_ERROR(res))
+ return get_error();
+
+ return 0;
+}
+
+#if defined(EI_HAVE_STRUCT_IOVEC__) && defined(HAVE_WRITEV)
+
+static int tcp_writev(void *ctx, const void *viov, int iovcnt, ssize_t *len, unsigned unused)
+{
+ const struct iovec *iov = (const struct iovec *) viov;
+ int fd, error;
+ ssize_t res;
+
+ error = EI_DFLT_CTX_TO_FD__(ctx, &fd);
+ if (error)
+ return error;
+
res = writev(fd, iov, iovcnt);
- return (res < 0) ? -1 : res;
+ if (MEANS_SOCKET_ERROR(res))
+ return get_error();
+ *len = res;
+ return 0;
+}
+
+#endif
+
+static int tcp_write(void *ctx, const char* buf, ssize_t *len, unsigned unused)
+{
+ int error, fd;
+ ssize_t res;
+
+ error = EI_DFLT_CTX_TO_FD__(ctx, &fd);
+ if (error)
+ return error;
+
+ res = writesocket(fd, buf, *len);
+ if (MEANS_SOCKET_ERROR(res))
+ return get_error();
+ *len = res;
+ return 0;
+}
+
+static int tcp_read(void *ctx, char* buf, ssize_t *len, unsigned unused)
+{
+ int error, fd;
+ ssize_t res;
+
+ error = EI_DFLT_CTX_TO_FD__(ctx, &fd);
+ if (error)
+ return error;
+
+ res = readsocket(fd, buf, *len);
+ if (MEANS_SOCKET_ERROR(res))
+ return get_error();
+ *len = res;
+ return 0;
+}
+
+ei_socket_callbacks ei_default_socket_callbacks = {
+ 0, /* flags */
+ tcp_socket,
+ tcp_close,
+ tcp_listen,
+ tcp_accept,
+ tcp_connect,
+#if defined(EI_HAVE_STRUCT_IOVEC__) && defined(HAVE_WRITEV)
+ tcp_writev,
+#else
+ NULL,
+#endif
+ tcp_write,
+ tcp_read,
+
+ tcp_hs_packet_header_size,
+ tcp_handshake_complete,
+ tcp_handshake_complete,
+ tcp_get_fd
+
+};
+
+
+/*
+ *
+ */
+
+#if defined(EI_HAVE_STRUCT_IOVEC__)
+
+int ei_socket_callbacks_have_writev__(ei_socket_callbacks *cbs)
+{
+ return !!cbs->writev;
}
-int ei_writev_fill_t(int fd, const struct iovec *iov, int iovcnt, unsigned ms)
+static int writev_ctx_t__(ei_socket_callbacks *cbs, void *ctx,
+ const struct iovec *iov, int iovcnt,
+ ssize_t *len,
+ unsigned ms)
{
- int i;
- int done;
+ int error;
+
+ if (!(cbs->flags & EI_SCLBK_FLG_FULL_IMPL) && ms != EI_SCLBK_INF_TMO) {
+ int fd;
+
+ error = EI_GET_FD__(cbs, ctx, &fd);
+ if (error)
+ return error;
+
+ do {
+ fd_set writemask;
+ struct timeval tv;
+
+ tv.tv_sec = (time_t) (ms / 1000U);
+ ms %= 1000U;
+ tv.tv_usec = (time_t) (ms * 1000U);
+ FD_ZERO(&writemask);
+ FD_SET(fd,&writemask);
+ switch (select(fd+1, NULL, &writemask, NULL, &tv)) {
+ case -1 :
+ error = get_error();
+ if (error != EINTR)
+ return error;
+ break;
+ case 0:
+ return ETIMEDOUT; /* timeout */
+ default:
+ if (!FD_ISSET(fd, &writemask)) {
+ return EIO; /* Other error */
+ }
+ error = 0;
+ break;
+ }
+ } while (error == EINTR);
+ }
+ do {
+ error = cbs->writev(ctx, (const void *) iov, iovcnt, len, ms);
+ } while (error == EINTR);
+ return error;
+}
+
+int ei_writev_fill_ctx_t__(ei_socket_callbacks *cbs, void *ctx,
+ const struct iovec *iov, int iovcnt,
+ ssize_t *len,
+ unsigned ms)
+{
+ ssize_t i, done, sum;
struct iovec *iov_base = NULL;
struct iovec *current_iov;
int current_iovcnt;
- int sum;
+ int fd, error;
+ int basic;
+
+ if (!cbs->writev)
+ return ENOTSUP;
+
+ error = EI_GET_FD__(cbs, ctx, &fd);
+ if (error)
+ return error;
+ basic = !(cbs->flags & EI_SCLBK_FLG_FULL_IMPL);
+
for (sum = 0, i = 0; i < iovcnt; ++i) {
sum += iov[i].iov_len;
}
- if (ms != 0U) {
+ if (basic && ms != 0U) {
SET_NONBLOCKING(fd);
}
current_iovcnt = iovcnt;
current_iov = (struct iovec *) iov;
done = 0;
for (;;) {
- i = ei_writev_t(fd, current_iov, current_iovcnt, ms);
- if (i <= 0) { /* ei_writev_t should always return at least 1 */
+
+ error = writev_ctx_t__(cbs, ctx, current_iov, current_iovcnt, &i, ms);
+ if (error) {
+ *len = done;
if (ms != 0U) {
SET_BLOCKING(fd);
}
if (iov_base != NULL) {
free(iov_base);
}
- return (i);
- }
+ return error;
+ }
done += i;
if (done < sum) {
if (iov_base == NULL) {
iov_base = malloc(sizeof(struct iovec) * iovcnt);
if (iov_base == NULL) {
- return -1;
+ *len = done;
+ return ENOMEM;
}
memcpy(iov_base, iov, sizeof(struct iovec) * iovcnt);
current_iov = iov_base;
@@ -189,195 +478,383 @@ int ei_writev_fill_t(int fd, const struct iovec *iov, int iovcnt, unsigned
break;
}
}
- if (ms != 0U) {
+ if (basic && ms != 0U) {
SET_BLOCKING(fd);
}
if (iov_base != NULL) {
free(iov_base);
}
- return (sum);
+ *len = done;
+ return 0;
}
+#endif /* defined(EI_HAVE_STRUCT_IOVEC__) */
-#endif
-
-int ei_connect_t(int fd, void *sinp, int sin_siz, unsigned ms)
+int ei_socket_ctx__(ei_socket_callbacks *cbs, void **ctx, void *setup_ctx)
{
int res;
- int error;
- int s_res;
- struct timeval tv;
- fd_set writefds;
- fd_set exceptfds;
-
- if (ms == 0) {
- res = connect(fd, sinp, sin_siz);
- return (res < 0) ? -1 : res;
- } else {
- SET_NONBLOCKING(fd);
- res = connect(fd, sinp, sin_siz);
- error = GET_SOCKET_ERROR();
- SET_BLOCKING(fd);
- if (!MEANS_SOCKET_ERROR(res)) {
- return (res < 0) ? -1 : res;
- } else {
- if (error != ERROR_WOULDBLOCK &&
- error != ERROR_INPROGRESS) {
- return -1;
- } else {
- tv.tv_sec = (long) (ms/1000U);
- ms %= 1000U;
- tv.tv_usec = (long) (ms * 1000U);
- FD_ZERO(&writefds);
- FD_SET(fd,&writefds);
- FD_ZERO(&exceptfds);
- FD_SET(fd,&exceptfds);
- s_res = select(fd + 1, NULL, &writefds, &exceptfds, &tv);
- switch (s_res) {
- case 0:
- return -2;
- case 1:
- if (FD_ISSET(fd, &exceptfds)) {
- return -1;
- } else {
- return 0; /* Connect completed */
- }
- default:
- return -1;
- }
- }
- }
- }
+
+ do {
+ res = cbs->socket(ctx, setup_ctx);
+ } while (res == EINTR);
+
+ return res;
}
-int ei_accept_t(int fd, void *addr, void *addrlen, unsigned ms)
+int ei_close_ctx__(ei_socket_callbacks *cbs, void *ctx)
{
- int res;
- if (ms != 0) {
- fd_set readmask;
- struct timeval tv;
- tv.tv_sec = (time_t) (ms / 1000U);
- ms %= 1000U;
- tv.tv_usec = (time_t) (ms * 1000U);
- FD_ZERO(&readmask);
- FD_SET(fd,&readmask);
- switch (select(fd+1, &readmask, NULL, NULL, &tv)) {
- case -1 :
- return -1; /* i/o error */
- case 0:
- return -2; /* timeout */
- default:
- if (!FD_ISSET(fd, &readmask)) {
- return -1; /* Other error */
- }
- }
- }
- res = (int) accept(fd,addr,addrlen);
- return (res < 0) ? -1 : res;
+ return cbs->close(ctx);
}
+
+int ei_connect_ctx_t__(ei_socket_callbacks *cbs, void *ctx,
+ void *addr, int len, unsigned ms)
+{
+ int res, fd;
+
+ if ((cbs->flags & EI_SCLBK_FLG_FULL_IMPL) || ms == EI_SCLBK_INF_TMO) {
+ do {
+ res = cbs->connect(ctx, addr, len, ms);
+ } while (res == EINTR);
+ return res;
+ }
+
+ res = EI_GET_FD__(cbs, ctx, &fd);
+ if (res)
+ return res;
+ SET_NONBLOCKING(fd);
+ do {
+ res = cbs->connect(ctx, addr, len, 0);
+ } while (res == EINTR);
+ SET_BLOCKING(fd);
+ switch (res) {
+ case EINPROGRESS:
+ case EAGAIN:
+#ifdef EWOULDBLOCK
+#if EWOULDBLOCK != EAGAIN
+ case EWOULDBLOCK:
+#endif
+#endif
+ break;
+ default:
+ return res;
+ }
-static int ei_read_t(int fd, char* buf, int len, unsigned ms)
+ while (1) {
+ struct timeval tv;
+ fd_set writefds;
+ fd_set exceptfds;
+
+ tv.tv_sec = (long) (ms/1000U);
+ ms %= 1000U;
+ tv.tv_usec = (long) (ms * 1000U);
+ FD_ZERO(&writefds);
+ FD_SET(fd,&writefds);
+ FD_ZERO(&exceptfds);
+ FD_SET(fd,&exceptfds);
+ res = select(fd + 1, NULL, &writefds, &exceptfds, &tv);
+ switch (res) {
+ case -1:
+ res = get_error();
+ if (res != EINTR)
+ return res;
+ break;
+ case 0:
+ return ETIMEDOUT;
+ case 1:
+ if (!FD_ISSET(fd, &exceptfds))
+ return 0; /* Connect completed */
+ /* fall through... */
+ default:
+ return EIO;
+ }
+ }
+}
+
+int ei_listen_ctx__(ei_socket_callbacks *cbs, void *ctx,
+ void *adr, int *len, int backlog)
{
int res;
- if (ms != 0) {
- fd_set readmask;
- struct timeval tv;
- tv.tv_sec = (time_t) (ms / 1000U);
- ms %= 1000U;
- tv.tv_usec = (time_t) (ms * 1000U);
- FD_ZERO(&readmask);
- FD_SET(fd,&readmask);
- switch (select(fd+1, &readmask, NULL, NULL, &tv)) {
- case -1 :
- return -1; /* i/o error */
- case 0:
- return -2; /* timeout */
- default:
- if (!FD_ISSET(fd, &readmask)) {
- return -1; /* Other error */
- }
- }
+
+ do {
+ res = cbs->listen(ctx, adr, len, backlog);
+ } while (res == EINTR);
+ return res;
+}
+
+int ei_accept_ctx_t__(ei_socket_callbacks *cbs, void **ctx,
+ void *addr, int *len, unsigned ms)
+{
+ int error;
+
+ if (!(cbs->flags & EI_SCLBK_FLG_FULL_IMPL) && ms != EI_SCLBK_INF_TMO) {
+ int fd;
+
+ error = EI_GET_FD__(cbs, *ctx, &fd);
+ if (error)
+ return error;
+
+ do {
+ fd_set readmask;
+ struct timeval tv;
+
+ tv.tv_sec = (time_t) (ms / 1000U);
+ ms %= 1000U;
+ tv.tv_usec = (time_t) (ms * 1000U);
+ FD_ZERO(&readmask);
+ FD_SET(fd,&readmask);
+ switch (select(fd+1, &readmask, NULL, NULL, &tv)) {
+ case -1 :
+ error = get_error();
+ if (error != EINTR)
+ return error;
+ break;
+ case 0:
+ return ETIMEDOUT; /* timeout */
+ default:
+ if (!FD_ISSET(fd, &readmask)) {
+ return EIO; /* Other error */
+ }
+ error = 0;
+ break;
+ }
+ } while (error == EINTR);
}
- res = readsocket(fd, buf, len);
- return (res < 0) ? -1 : res;
+ do {
+ error = cbs->accept(ctx, addr, len, ms);
+ } while (error == EINTR);
+ return error;
}
-static int ei_write_t(int fd, const char* buf, int len, unsigned ms)
+static int read_ctx_t__(ei_socket_callbacks *cbs, void *ctx,
+ char* buf, ssize_t *len, unsigned ms)
{
- int res;
- if (ms != 0) {
- fd_set writemask;
- struct timeval tv;
- tv.tv_sec = (time_t) (ms / 1000U);
- ms %= 1000U;
- tv.tv_usec = (time_t) (ms * 1000U);
- FD_ZERO(&writemask);
- FD_SET(fd,&writemask);
- switch (select(fd+1, NULL, &writemask, NULL, &tv)) {
- case -1 :
- return -1; /* i/o error */
- case 0:
- return -2; /* timeout */
- default:
- if (!FD_ISSET(fd, &writemask)) {
- return -1; /* Other error */
- }
- }
+ int error;
+
+ if (!(cbs->flags & EI_SCLBK_FLG_FULL_IMPL) && ms != EI_SCLBK_INF_TMO) {
+ int fd;
+
+ error = EI_GET_FD__(cbs, ctx, &fd);
+ if (error)
+ return error;
+
+ do {
+ fd_set readmask;
+ struct timeval tv;
+
+ tv.tv_sec = (time_t) (ms / 1000U);
+ ms %= 1000U;
+ tv.tv_usec = (time_t) (ms * 1000U);
+ FD_ZERO(&readmask);
+ FD_SET(fd,&readmask);
+ switch (select(fd+1, &readmask, NULL, NULL, &tv)) {
+ case -1 :
+ error = get_error();
+ if (error != EINTR)
+ return error;
+ break;
+ case 0:
+ return ETIMEDOUT; /* timeout */
+ default:
+ if (!FD_ISSET(fd, &readmask)) {
+ return EIO; /* Other error */
+ }
+ error = 0;
+ break;
+ }
+ } while (error == EINTR);
+ }
+ do {
+ error = cbs->read(ctx, buf, len, ms);
+ } while (error == EINTR);
+ return error;
+}
+
+static int write_ctx_t__(ei_socket_callbacks *cbs, void *ctx, const char* buf, ssize_t *len, unsigned ms)
+{
+ int error;
+
+ if (!(cbs->flags & EI_SCLBK_FLG_FULL_IMPL) && ms != EI_SCLBK_INF_TMO) {
+ int fd;
+
+ error = EI_GET_FD__(cbs, ctx, &fd);
+ if (error)
+ return error;
+
+ do {
+ fd_set writemask;
+ struct timeval tv;
+
+ tv.tv_sec = (time_t) (ms / 1000U);
+ ms %= 1000U;
+ tv.tv_usec = (time_t) (ms * 1000U);
+ FD_ZERO(&writemask);
+ FD_SET(fd,&writemask);
+ switch (select(fd+1, NULL, &writemask, NULL, &tv)) {
+ case -1 :
+ error = get_error();
+ if (error != EINTR)
+ return error;
+ break;
+ case 0:
+ return ETIMEDOUT; /* timeout */
+ default:
+ if (!FD_ISSET(fd, &writemask)) {
+ return EIO; /* Other error */
+ }
+ error = 0;
+ break;
+ }
+ } while (error == EINTR);
}
- res = writesocket(fd, buf, len);
- return (res < 0) ? -1 : res;
+ do {
+ error = cbs->write(ctx, buf, len, ms);
+ } while (error == EINTR);
+ return error;
}
/*
* Fill buffer, return buffer length, 0 for EOF, < 0 (and sets errno)
* for error. */
-int ei_read_fill_t(int fd, char* buf, int len, unsigned ms)
+int ei_read_fill_ctx_t__(ei_socket_callbacks *cbs, void *ctx, char* buf, ssize_t *len, unsigned ms)
{
- int i,got=0;
+ ssize_t got = 0;
+ ssize_t want = *len;
do {
- i = ei_read_t(fd, buf+got, len-got, ms);
- if (i <= 0)
- return (i);
- got += i;
- } while (got < len);
- return (len);
-
+ ssize_t read_len = want-got;
+ int error;
+
+ do {
+ error = read_ctx_t__(cbs, ctx, buf+got, &read_len, ms);
+ } while (error == EINTR);
+ if (error)
+ return error;
+ if (read_len == 0) {
+ *len = got;
+ return 0;
+ }
+ got += read_len;
+ } while (got < want);
+
+ *len = got;
+ return 0;
} /* read_fill */
-int ei_read_fill(int fd, char* buf, int len)
+int ei_read_fill_ctx__(ei_socket_callbacks *cbs, void *ctx, char* buf, ssize_t *len)
{
- return ei_read_fill_t(fd, buf, len, 0);
+ return ei_read_fill_ctx_t__(cbs, ctx, buf, len, 0);
}
/* write entire buffer on fd or fail (setting errno)
*/
-int ei_write_fill_t(int fd, const char *buf, int len, unsigned ms)
+int ei_write_fill_ctx_t__(ei_socket_callbacks *cbs, void *ctx, const char *buf, ssize_t *len, unsigned ms)
{
- int i,done=0;
- if (ms != 0U) {
+ ssize_t tot = *len, done = 0;
+ int error, fd = -1, basic = !(cbs->flags & EI_SCLBK_FLG_FULL_IMPL);
+
+ if (basic && ms != 0U) {
+ error = EI_GET_FD__(cbs, ctx, &fd);
+ if (error)
+ return error;
SET_NONBLOCKING(fd);
}
do {
- i = ei_write_t(fd, buf+done, len-done, ms);
- if (i <= 0) {
- if (ms != 0U) {
+ ssize_t write_len = tot-done;
+ error = write_ctx_t__(cbs, ctx, buf+done, &write_len, ms);
+ if (error) {
+ *len = done;
+ if (basic && ms != 0U) {
SET_BLOCKING(fd);
}
- return (i);
+ return error;
}
- done += i;
- } while (done < len);
- if (ms != 0U) {
+ done += write_len;
+ } while (done < tot);
+ if (basic && ms != 0U) {
SET_BLOCKING(fd);
}
- return (len);
+ *len = done;
+ return 0;
+}
+
+int ei_write_fill_ctx__(ei_socket_callbacks *cbs, void *ctx, const char *buf, ssize_t *len)
+{
+ return ei_write_fill_ctx_t__(cbs, ctx, buf, len, 0);
+}
+
+/*
+ * Internal API for TCP/IPv4
+ */
+
+int ei_connect_t__(int fd, void *addr, int len, unsigned ms)
+{
+ return ei_connect_ctx_t__(&ei_default_socket_callbacks, EI_FD_AS_CTX__(fd),
+ addr, len, ms);
}
-int ei_write_fill(int fd, const char *buf, int len)
+int ei_socket__(int *fd)
{
- return ei_write_fill_t(fd, buf, len, 0);
+ void *ctx;
+ int error = ei_socket_ctx__(&ei_default_socket_callbacks, &ctx, NULL);
+ if (error)
+ return error;
+ return EI_GET_FD__(&ei_default_socket_callbacks, ctx, fd);
}
+int ei_close__(int fd)
+{
+ return ei_close_ctx__(&ei_default_socket_callbacks, EI_FD_AS_CTX__(fd));
+}
+
+int ei_listen__(int fd, void *adr, int *len, int backlog)
+{
+ return ei_listen_ctx__(&ei_default_socket_callbacks, EI_FD_AS_CTX__(fd),
+ adr, len, backlog);
+}
+
+int ei_accept_t__(int *fd, void *addr, int *len, unsigned ms)
+{
+ void *ctx = EI_FD_AS_CTX__(*fd);
+ int error = ei_accept_ctx_t__(&ei_default_socket_callbacks, &ctx,
+ addr, len, ms);
+ if (error)
+ return error;
+ return EI_GET_FD__(&ei_default_socket_callbacks, ctx, fd);
+}
+
+int ei_read_fill_t__(int fd, char* buf, ssize_t *len, unsigned ms)
+{
+ return ei_read_fill_ctx_t__(&ei_default_socket_callbacks, EI_FD_AS_CTX__(fd),
+ buf, len, ms);
+}
+
+int ei_read_fill__(int fd, char* buf, ssize_t *len)
+{
+ return ei_read_fill_ctx_t__(&ei_default_socket_callbacks, EI_FD_AS_CTX__(fd),
+ buf, len, 0);
+}
+
+int ei_write_fill_t__(int fd, const char *buf, ssize_t *len, unsigned ms)
+{
+ return ei_write_fill_ctx_t__(&ei_default_socket_callbacks, EI_FD_AS_CTX__(fd),
+ buf, len, ms);
+}
+
+int ei_write_fill__(int fd, const char *buf, ssize_t *len)
+{
+ return ei_write_fill_ctx_t__(&ei_default_socket_callbacks, EI_FD_AS_CTX__(fd),
+ buf, len, 0);
+}
+
+#if defined(EI_HAVE_STRUCT_IOVEC__) && defined(HAVE_WRITEV)
+
+int ei_writev_fill_t__(int fd, const struct iovec *iov, int iovcnt, ssize_t *len, unsigned ms)
+{
+ return ei_writev_fill_ctx_t__(&ei_default_socket_callbacks, EI_FD_AS_CTX__(fd),
+ iov, iovcnt, len, ms);
+}
+
+#endif
+
diff --git a/lib/erl_interface/src/misc/ei_portio.h b/lib/erl_interface/src/misc/ei_portio.h
index bded811a35..a84b5ca09c 100644
--- a/lib/erl_interface/src/misc/ei_portio.h
+++ b/lib/erl_interface/src/misc/ei_portio.h
@@ -21,21 +21,94 @@
*/
#ifndef _EI_PORTIO_H
#define _EI_PORTIO_H
-#if !defined(__WIN32__) && !defined(VXWORKS)
-#ifdef HAVE_WRITEV
+
+#undef EI_HAVE_STRUCT_IOVEC__
+#if !defined(__WIN32__) && !defined(VXWORKS) && defined(HAVE_SYS_UIO_H)
/* Declaration of struct iovec *iov should be visible in this scope. */
-#include <sys/uio.h>
+# include <sys/uio.h>
+# define EI_HAVE_STRUCT_IOVEC__
#endif
+
+/*
+ * Internal API. Should not be used outside of the erl_interface application...
+ */
+
+int ei_socket_ctx__(ei_socket_callbacks *cbs, void **ctx, void *setup);
+int ei_close_ctx__(ei_socket_callbacks *cbs, void *ctx);
+int ei_listen_ctx__(ei_socket_callbacks *cbs, void *ctx, void *adr, int *len, int backlog);
+int ei_accept_ctx_t__(ei_socket_callbacks *cbs, void **ctx, void *addr, int *len, unsigned ms);
+int ei_connect_ctx_t__(ei_socket_callbacks *cbs, void *ctx, void *addr, int len, unsigned ms);
+int ei_read_fill_ctx__(ei_socket_callbacks *cbs, void *ctx, char* buf, ssize_t *len);
+int ei_write_fill_ctx__(ei_socket_callbacks *cbs, void *ctx, const char *buf, ssize_t *len);
+int ei_read_fill_ctx_t__(ei_socket_callbacks *cbs, void *ctx, char* buf, ssize_t *len, unsigned ms);
+int ei_write_fill_ctx_t__(ei_socket_callbacks *cbs, void *ctx, const char *buf, ssize_t *len, unsigned ms);
+#if defined(EI_HAVE_STRUCT_IOVEC__)
+int ei_writev_fill_ctx_t__(ei_socket_callbacks *cbs, void *ctx, const struct iovec *iov, int iovcnt, ssize_t *len, unsigned ms);
+int ei_socket_callbacks_have_writev__(ei_socket_callbacks *cbs);
#endif
-int ei_accept_t(int fd, void *addr, void *addrlen, unsigned ms);
-int ei_connect_t(int fd, void *sinp, int sin_siz, unsigned ms);
-int ei_read_fill(int fd, char* buf, int len);
-int ei_write_fill(int fd, const char *buf, int len);
-int ei_read_fill_t(int fd, char* buf, int len, unsigned ms);
-int ei_write_fill_t(int fd, const char *buf, int len, unsigned ms);
-#ifdef HAVE_WRITEV
-int ei_writev_fill_t(int fd, const struct iovec *iov, int iovcnt, unsigned ms);
+ei_socket_callbacks ei_default_socket_callbacks;
+
+#define EI_FD_AS_CTX__(FD) \
+ ((void *) (long) (FD))
+
+#define EI_DFLT_CTX_TO_FD__(CTX, FD) \
+ ((int) (long) (CTX) < 0 \
+ ? EBADF \
+ : (*(FD) = (int) (long) (CTX), 0))
+
+#define EI_GET_FD__(CBS, CTX, FD) \
+ ((CBS) == &ei_default_socket_callbacks \
+ ? EI_DFLT_CTX_TO_FD__((CTX), FD) \
+ : (CBS)->get_fd((CTX), (FD)))
+
+extern int ei_plugin_socket_impl__;
+
+#if !defined(_REENTRANT)
+
+#define EI_HAVE_PLUGIN_SOCKET_IMPL__ \
+ ei_plugin_socket_impl__
+#define EI_SET_HAVE_PLUGIN_SOCKET_IMPL__ \
+ ei_plugin_socket_impl__ = 1
+
+#elif ((ETHR_HAVE___atomic_load_n & SIZEOF_INT) \
+ && (ETHR_HAVE___atomic_store_n & SIZEOF_INT))
+
+#define EI_HAVE_PLUGIN_SOCKET_IMPL__ \
+ __atomic_load_n(&ei_plugin_socket_impl__, __ATOMIC_ACQUIRE)
+#define EI_SET_HAVE_PLUGIN_SOCKET_IMPL__ \
+ __atomic_store_n(&ei_plugin_socket_impl__, 1, __ATOMIC_RELEASE)
+
+#else
+
+/* No gcc atomics; always lookup using ei_get_cbs_ctx()... */
+#define EI_HAVE_PLUGIN_SOCKET_IMPL__ 0
+#define EI_SET_HAVE_PLUGIN_SOCKET_IMPL__ (void) 0
+
+#endif
+
+#define EI_GET_CBS_CTX__(CBS, CTX, FD) \
+ (EI_HAVE_PLUGIN_SOCKET_IMPL__ \
+ ? ei_get_cbs_ctx__((CBS), (CTX), (FD)) \
+ : ((FD) < 0 \
+ ? EBADF \
+ : (*(CBS) = &ei_default_socket_callbacks, \
+ *(CTX) = EI_FD_AS_CTX__((FD)), \
+ 0)))
+/*
+ * The following uses our own TCP/IPv4 socket implementation...
+ */
+int ei_socket__(int *fd);
+int ei_close__(int fd);
+int ei_listen__(int fd, void *adr, int *len, int backlog);
+int ei_accept_t__(int *fd, void *addr, int *len, unsigned ms);
+int ei_connect_t__(int fd, void *addr, int len, unsigned ms);
+int ei_read_fill__(int fd, char* buf, ssize_t *len);
+int ei_write_fill__(int fd, const char *buf, ssize_t *len);
+int ei_read_fill_t__(int fd, char* buf, ssize_t *len, unsigned ms);
+int ei_write_fill_t__(int fd, const char *buf, ssize_t *len, unsigned ms);
+#if defined(EI_HAVE_STRUCT_IOVEC__) && defined(HAVE_WRITEV)
+int ei_writev_fill_t__(int fd, const struct iovec *iov, int iovcnt, ssize_t *len, unsigned ms);
#endif
#endif /* _EI_PORTIO_H */
diff --git a/lib/erl_interface/src/misc/ei_printterm.c b/lib/erl_interface/src/misc/ei_printterm.c
index 058de00de5..5c40fb7747 100644
--- a/lib/erl_interface/src/misc/ei_printterm.c
+++ b/lib/erl_interface/src/misc/ei_printterm.c
@@ -131,7 +131,7 @@ static int print_term(FILE* fp, ei_x_buff* x,
if (fp == NULL && x == NULL) return -1;
doquote = 0;
- ei_get_type_internal(buf, index, &ty, &n);
+ ei_get_type(buf, index, &ty, &n);
switch (ty) {
case ERL_ATOM_EXT:
case ERL_ATOM_UTF8_EXT:
@@ -189,7 +189,7 @@ static int print_term(FILE* fp, ei_x_buff* x,
xputs(", ", fp, x); ch_written += 2;
}
}
- if (ei_get_type_internal(buf, &tindex, &ty, &n) < 0) goto err;
+ if (ei_get_type(buf, &tindex, &ty, &n) < 0) goto err;
if (ty != ERL_NIL_EXT) {
xputs(" | ", fp, x); ch_written += 3;
r = print_term(fp, x, buf, &tindex);
@@ -249,6 +249,34 @@ static int print_term(FILE* fp, ei_x_buff* x,
xputc('>', fp, x); ++ch_written;
ei_free(p);
break;
+ case ERL_BIT_BINARY_EXT: {
+ const char* cp;
+ size_t bits;
+ unsigned int bitoffs;
+ int trunc = 0;
+
+ if (ei_decode_bitstring(buf, index, &cp, &bitoffs, &bits) < 0
+ || bitoffs != 0) {
+ goto err;
+ }
+ ch_written += xprintf(fp, x, "#Bits<");
+ m = (bits+7) / 8;
+ if (m > BINPRINTSIZE) {
+ m = BINPRINTSIZE;
+ trunc = 1;
+ }
+ --m;
+ for (i = 0; i < m; ++i) {
+ ch_written += xprintf(fp, x, "%d,", cp[i]);
+ }
+ ch_written += xprintf(fp, x, "%d", cp[i]);
+ if (trunc)
+ ch_written += xprintf(fp, x, ",...");
+ else if (bits % 8 != 0)
+ ch_written += xprintf(fp, x, ":%u", (unsigned)(bits % 8));
+ xputc('>', fp, x); ++ch_written;
+ break;
+ }
case ERL_SMALL_INTEGER_EXT:
case ERL_INTEGER_EXT:
if (ei_decode_long(buf, index, &l) < 0) goto err;
diff --git a/lib/erl_interface/src/misc/ei_pthreads.c b/lib/erl_interface/src/misc/ei_pthreads.c
index 25608edeec..c6d07a9a0a 100644
--- a/lib/erl_interface/src/misc/ei_pthreads.c
+++ b/lib/erl_interface/src/misc/ei_pthreads.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2001-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -78,7 +78,7 @@ static void tls_init_once(void)
errno_tls_index = TlsAlloc();
if (errno_tls_index == TLS_OUT_OF_INDEXES) {
fprintf(stderr,
- "FATAL ERROR: can not allocate TLS index for "
+ "FATAL ERROR: cannot allocate TLS index for "
"erl_errno (error code = %d)!\n",GetLastError());
exit(1);
}
@@ -206,6 +206,7 @@ volatile int *__erl_errno_place(void)
use_fallback = 1;
return &fallback_errno;
}
+ *erl_errno_p = 0;
if (pthread_setspecific(erl_errno_key, erl_errno_p) != 0 ||
(erl_errno_p = pthread_getspecific(erl_errno_key)) == NULL) {
diff --git a/lib/erl_interface/src/misc/ei_x_encode.c b/lib/erl_interface/src/misc/ei_x_encode.c
index 4ff5974663..8e77679d2a 100644
--- a/lib/erl_interface/src/misc/ei_x_encode.c
+++ b/lib/erl_interface/src/misc/ei_x_encode.c
@@ -117,6 +117,16 @@ int ei_x_encode_binary(ei_x_buff* x, const void* p, int len)
return ei_encode_binary(x->buff, &x->index, p, len);
}
+int ei_x_encode_bitstring(ei_x_buff* x, const char* p, size_t bitoffs, size_t bits)
+{
+ int i = x->index;
+ if (ei_encode_bitstring(NULL, &i, p, bitoffs, bits) == -1)
+ return -1;
+ if (!x_fix_buff(x, i))
+ return -1;
+ return ei_encode_bitstring(x->buff, &x->index, p, bitoffs, bits);
+}
+
int ei_x_encode_long(ei_x_buff* x, long n)
{
int i = x->index;
diff --git a/lib/erl_interface/src/misc/get_type.c b/lib/erl_interface/src/misc/get_type.c
index aa69cd4d60..eef58a9363 100644
--- a/lib/erl_interface/src/misc/get_type.c
+++ b/lib/erl_interface/src/misc/get_type.c
@@ -27,17 +27,8 @@
/* for types with meaningful length attributes, return the length too.
In other cases, return length 0 */
-/* FIXME working on this one.... */
-
int ei_get_type(const char *buf, const int *index, int *type, int *len)
{
- return ei_get_type_internal(buf, index, type, len);
-}
-
-
-int ei_get_type_internal(const char *buf, const int *index,
- int *type, int *len)
-{
const char *s = buf + *index;
*type = get8(s);
@@ -64,7 +55,9 @@ int ei_get_type_internal(const char *buf, const int *index,
case ERL_LARGE_TUPLE_EXT:
case ERL_LIST_EXT:
+ case ERL_MAP_EXT:
case ERL_BINARY_EXT:
+ case ERL_BIT_BINARY_EXT:
*len = get32be(s);
break;
diff --git a/lib/erl_interface/src/misc/show_msg.c b/lib/erl_interface/src/misc/show_msg.c
index 5868cccba6..805d69e9b3 100644
--- a/lib/erl_interface/src/misc/show_msg.c
+++ b/lib/erl_interface/src/misc/show_msg.c
@@ -342,7 +342,7 @@ static void show_term(const char *termbuf, int *index, FILE *stream)
int i, len;
char *s;
- ei_get_type_internal(termbuf,index,&type,&len);
+ ei_get_type(termbuf,index,&type,&len);
switch (type) {
case ERL_VERSION_MAGIC:
@@ -455,6 +455,12 @@ static void show_term(const char *termbuf, int *index, FILE *stream)
fprintf(stream,"#Bin<%ld>",num);
break;
+ case ERL_BIT_BINARY_EXT: {
+ size_t bits;
+ ei_decode_bitstring(termbuf, index, NULL, NULL, &bits);
+ fprintf(stream, "#Bits<%lu>", (unsigned long)bits);
+ break;
+ }
case ERL_LARGE_BIG_EXT:
/* doesn't actually decode - just skip over it */
/* FIXME if GMP, what to do here?? */
diff --git a/lib/erl_interface/src/not_used/send_link.c b/lib/erl_interface/src/not_used/send_link.c
index 7be476fd93..38fae27df4 100644
--- a/lib/erl_interface/src/not_used/send_link.c
+++ b/lib/erl_interface/src/not_used/send_link.c
@@ -50,6 +50,7 @@ static int link_unlink(int fd, const erlang_pid *from, const erlang_pid *to,
char *s;
int index = 0;
int n;
+ unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms;
index = 5; /* max sizes: */
ei_encode_version(msgbuf,&index); /* 1 */
@@ -69,7 +70,7 @@ static int link_unlink(int fd, const erlang_pid *from, const erlang_pid *to,
if (ei_trace_distribution > 1) ei_show_sendmsg(stderr,msgbuf,NULL);
#endif
- n = ei_write_fill_t(fd,msgbuf,index,ms);
+ n = ei_write_fill_t__(fd,msgbuf,index,tmo);
return (n==index ? 0 : -1);
}
diff --git a/lib/erl_interface/src/prog/ei_fake_prog.c b/lib/erl_interface/src/prog/ei_fake_prog.c
index c7a16dc7c4..6f58c9833d 100644
--- a/lib/erl_interface/src/prog/ei_fake_prog.c
+++ b/lib/erl_interface/src/prog/ei_fake_prog.c
@@ -98,11 +98,18 @@ int main(void)
EI_ULONGLONG ulonglongx = 0;
#endif
erlang_char_encoding enc;
+ ei_socket_callbacks cbs;
intx = erl_errno;
+ ei_init();
+
+ ei_close_connection(intx);
+
ei_connect_init(&xec, charp, charp, creation);
+ ei_connect_init_ussi(&xec, charp, charp, creation, &cbs, sizeof(cbs), NULL);
ei_connect_xinit (&xec, charp, charp, charp, thisipaddr, charp, creation);
+ ei_connect_xinit_ussi(&xec, charp, charp, charp, thisipaddr, charp, creation, &cbs, sizeof(cbs), NULL);
ei_connect(&xec, charp);
ei_xconnect (&xec, thisipaddr, charp);
@@ -121,6 +128,8 @@ int main(void)
ei_publish(&xec, intx);
ei_accept(&xec, intx, &conp);
ei_unpublish(&xec);
+ ei_listen(&xec, intp, intx);
+ ei_xlisten(&xec, thisipaddr, intp, intx);
ei_thisnodename(&xec);
ei_thishostname(&xec);
@@ -177,7 +186,6 @@ int main(void)
ei_x_encode_empty_list(&eix);
ei_get_type(charp, intp, intp, intp);
- ei_get_type_internal(charp, intp, intp, intp);
ei_decode_version(charp, intp, intp);
ei_decode_long(charp, intp, longp);
@@ -187,7 +195,7 @@ int main(void)
ei_decode_char(charp, intp, charp);
ei_decode_string(charp, intp, charp);
ei_decode_atom(charp, intp, charp);
- ei_decode_atom_as(charp, intp, charp, MAXATOMLEN_UTF8, ERLANG_WHATEVER, &enc, &enc);
+ ei_decode_atom_as(charp, intp, charp, MAXATOMLEN_UTF8, ERLANG_UTF8, &enc, &enc);
ei_decode_binary(charp, intp, (void *)0, longp);
ei_decode_fun(charp, intp, &efun);
free_fun(&efun);
diff --git a/lib/erl_interface/src/prog/erl_call.c b/lib/erl_interface/src/prog/erl_call.c
index 7577a07a3e..ab91157035 100644
--- a/lib/erl_interface/src/prog/erl_call.c
+++ b/lib/erl_interface/src/prog/erl_call.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -88,10 +88,6 @@
#include "ei_resolve.h"
#include "erl_start.h" /* FIXME remove dependency */
-#ifdef __WIN32__
-static void initWinSock(void);
-#endif
-
/*
* Some nice global variables
* (I don't think "nice" is the right word actually... -gordon)
@@ -157,6 +153,8 @@ int erl_call(int argc, char **argv)
char* progname = argv[0];
ei_cnode ec;
+ ei_init();
+
/* Get the command line options */
while (i < argc) {
if (argv[i][0] != '-') {
@@ -317,14 +315,6 @@ int erl_call(int argc, char **argv)
struct in_addr h_ipadr;
char* ct;
-#ifdef __WIN32__
- /*
- * FIXME Extremly ugly, but needed to get ei_gethostbyname() below
- * to work.
- */
- initWinSock();
-#endif
-
/* gethostname requires len to be max(hostname) + 1 */
if (gethostname(h_hostname, EI_MAXHOSTNAMELEN+1) < 0) {
fprintf(stderr,"erl_call: failed to get host name: %d\n", errno);
@@ -517,6 +507,15 @@ int erl_call(int argc, char **argv)
}
}
+
+ /*
+ * If we loaded any module source code, we can free the buffer
+ * now. This buffer was allocated in read_stdin().
+ */
+ if (module != NULL) {
+ free(module);
+ }
+
/*
* Eval the Erlang functions read from stdin/
*/
@@ -545,7 +544,7 @@ int erl_call(int argc, char **argv)
/* erl_format("[~w]", erl_mk_binary(evalbuf,len))) */
- if (ei_rpc(&ec, fd, "lib", "eval_str", p, i, &reply) < 0) {
+ if (ei_rpc(&ec, fd, "erl_eval", "eval_str", p, i, &reply) < 0) {
fprintf(stderr,"erl_call: evaluating input failed: %s\n",
evalbuf);
free(p);
@@ -795,8 +794,6 @@ static int get_module(char **mbuf, char **mname)
*mname = (char *) ei_chk_calloc(i+1, sizeof(char));
memcpy(*mname, start, i);
}
- if (*mbuf)
- free(*mbuf); /* Allocated in read_stdin() */
return len;
@@ -850,46 +847,6 @@ static void usage(const char *progname) {
exit(0);
}
-
-/***************************************************************************
- *
- * OS specific functions
- *
- ***************************************************************************/
-
-#ifdef __WIN32__
-/*
- * FIXME This should not be here. This is a quick fix to make erl_call
- * work at all on Windows NT.
- */
-static void initWinSock(void)
-{
- WORD wVersionRequested;
- WSADATA wsaData;
- int err;
- static int initialized;
-
- wVersionRequested = MAKEWORD(1, 1);
- if (!initialized) {
- initialized = 1;
- err = WSAStartup(wVersionRequested, &wsaData);
-
- if (err != 0) {
- fprintf(stderr,"erl_call: "
- "Can't initialize windows sockets: %d\n", err);
- }
-
- if ( LOBYTE( wsaData.wVersion ) != 1 ||
- HIBYTE( wsaData.wVersion ) != 1 ) {
- fprintf(stderr,"erl_call: This version of "
- "windows sockets not supported\n");
- WSACleanup();
- }
- }
-}
-#endif
-
-
/***************************************************************************
*
* Utility functions
diff --git a/lib/erl_interface/src/prog/erl_start.c b/lib/erl_interface/src/prog/erl_start.c
index 670a5900c9..b7aa451946 100644
--- a/lib/erl_interface/src/prog/erl_start.c
+++ b/lib/erl_interface/src/prog/erl_start.c
@@ -97,7 +97,7 @@
#endif
#ifndef RSH
-#define RSH "/usr/bin/rsh"
+#define RSH "/usr/bin/ssh"
#endif
#ifndef HAVE_SOCKLEN_T
@@ -657,7 +657,7 @@ static int wait_for_erlang(int sockd, int magic, struct timeval *timeout)
gettimeofday(&now,NULL);
to.tv_sec = stop_time.tv_sec - now.tv_sec;
to.tv_usec = stop_time.tv_usec - now.tv_usec;
- while ((to.tv_usec <= 0) && (to.tv_sec >= 0)) {
+ while ((to.tv_usec < 0) && (to.tv_sec > 0)) {
to.tv_usec += 1000000;
to.tv_sec--;
}
diff --git a/lib/erl_interface/src/registry/reg_dump.c b/lib/erl_interface/src/registry/reg_dump.c
index 43c9824433..da0413e6e6 100644
--- a/lib/erl_interface/src/registry/reg_dump.c
+++ b/lib/erl_interface/src/registry/reg_dump.c
@@ -90,7 +90,7 @@ static int mn_start_dump(int fd, const erlang_pid *self,
|| (arity != 2)
|| ei_decode_atom(buf,&index,tmpbuf)
|| strcmp(tmpbuf,"rex")
- || ei_get_type_internal(buf,&index,&type,&arity)
+ || ei_get_type(buf,&index,&type,&arity)
|| (type != ERL_PID_EXT))
return -1; /* bad response from other side */
diff --git a/lib/erl_interface/test/Makefile b/lib/erl_interface/test/Makefile
index 94f4b422d6..f8f2ef0156 100644
--- a/lib/erl_interface/test/Makefile
+++ b/lib/erl_interface/test/Makefile
@@ -33,6 +33,7 @@ MODULES= \
ei_format_SUITE \
ei_print_SUITE \
ei_tmo_SUITE \
+ erl_call_SUITE \
erl_connect_SUITE \
erl_global_SUITE \
erl_eterm_SUITE \
diff --git a/lib/erl_interface/test/all_SUITE_data/ei_runner.h b/lib/erl_interface/test/all_SUITE_data/ei_runner.h
index 2608661303..7c874ac82e 100644
--- a/lib/erl_interface/test/all_SUITE_data/ei_runner.h
+++ b/lib/erl_interface/test/all_SUITE_data/ei_runner.h
@@ -53,6 +53,7 @@ void free_packet(char*);
#define fail(reason) do_fail(__FILE__, __LINE__, reason)
#define fail1(reason, a1) do_fail(__FILE__, __LINE__, reason, a1)
+#define fail2(reason, a1, a2) do_fail(__FILE__, __LINE__, reason, a1, a2)
#define report(ok) do_report(__FILE__, __LINE__, ok)
void do_report(char* file, int line, int ok);
diff --git a/lib/erl_interface/test/ei_accept_SUITE.erl b/lib/erl_interface/test/ei_accept_SUITE.erl
index e06ee762d7..f40c67375b 100644
--- a/lib/erl_interface/test/ei_accept_SUITE.erl
+++ b/lib/erl_interface/test/ei_accept_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,7 +25,9 @@
-include("ei_accept_SUITE_data/ei_accept_test_cases.hrl").
-export([all/0, suite/0,
- ei_accept/1, ei_threaded_accept/1]).
+ init_per_testcase/2,
+ ei_accept/1, ei_threaded_accept/1,
+ monitor_ei_process/1]).
-import(runner, [get_term/1,send_term/2]).
@@ -34,59 +36,101 @@ suite() ->
{timetrap, {seconds, 30}}].
all() ->
- [ei_accept, ei_threaded_accept].
+ [ei_accept, ei_threaded_accept,
+ monitor_ei_process].
+
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
ei_accept(Config) when is_list(Config) ->
- P = runner:start(?interpret),
- 0 = ei_connect_init(P, 42, erlang:get_cookie(), 0),
+ ei_accept_do(Config, 0), % default
+ ei_accept_do(Config, 21). % ei_set_compat_rel
+
+ei_accept_do(Config, CompatRel) ->
+ P = runner:start(Config, ?interpret),
+ 0 = ei_connect_init(P, 42, erlang:get_cookie(), 0, CompatRel),
Myname = hd(tl(string:tokens(atom_to_list(node()), "@"))),
io:format("Myname ~p ~n", [Myname]),
EINode = list_to_atom("c42@"++Myname),
io:format("EINode ~p ~n", [EINode]),
+
+ %% We take this opportunity to also test export-funs and bit-strings
+ %% with (ugly) tuple fallbacks in OTP 21 and older.
+ %% Test both toward pending connection and established connection.
+ RealTerms = [<<1:1>>, fun lists:map/2],
+ EncTerms = case CompatRel of
+ 0 -> RealTerms;
+ 21 -> [{<<128>>,1}, {lists,map}]
+ end,
+
Self = self(),
- TermToSend= {call, Self, "Test"},
- F= fun() ->
- case waitfornode("c42",20) of
- true ->
- {any, EINode} ! TermToSend,
- Self ! sent_ok;
- false ->
- Self ! never_published
- end,
- ok
- end,
-
- spawn(F),
+ Funny = fun() -> hello end,
+ TermToSend = {call, Self, "Test", Funny, RealTerms},
+ TermToGet = {call, Self, "Test", Funny, EncTerms},
Port = 6543,
- {ok, Fd, _Node} = ei_accept(P, Port),
- TermReceived= ei_receive(P, Fd),
- io:format("Sent ~p received ~p ~n", [TermToSend, TermReceived]),
- TermToSend= TermReceived,
- receive
- sent_ok ->
- ok;
- Unknown ->
- io:format("~p ~n", [Unknown])
- after 1000 ->
- io:format("timeout ~n")
- end,
+ {ok, ListenFd} = ei_publish(P, Port),
+ {any, EINode} ! TermToSend,
+
+ {ok, Fd, _Node} = ei_accept(P, ListenFd),
+ Got1 = ei_receive(P, Fd),
+
+ %% Send again, now without auto-connect
+ {any, EINode} ! TermToSend,
+ Got2 = ei_receive(P, Fd),
+
+ io:format("Sent ~p~nExp. ~p~nGot1 ~p~nGot2 ~p~n", [TermToSend, TermToGet, Got1, Got2]),
+ TermToGet = Got1,
+ TermToGet = Got2,
+
runner:finish(P),
ok.
ei_threaded_accept(Config) when is_list(Config) ->
Einode = filename:join(proplists:get_value(data_dir, Config), "eiaccnode"),
- N = 1, % 3,
+ N = 3,
Host = atom_to_list(node()),
- Port = 6767,
- start_einode(Einode, N, Host, Port),
+ start_einode(Einode, N, Host),
io:format("started eiaccnode"),
- %%spawn_link(fun() -> start_einode(Einode, N, Host, Port) end),
TestServerPid = self(),
[spawn_link(fun() -> send_rec_einode(I, TestServerPid) end) || I <- lists:seq(0, N-1)],
[receive I -> ok end || I <- lists:seq(0, N-1) ],
ok.
+
+%% Test erlang:monitor toward erl_interface "processes"
+monitor_ei_process(Config) when is_list(Config) ->
+ P = runner:start(Config, ?interpret),
+ 0 = ei_connect_init(P, 42, erlang:get_cookie(), 0, 0),
+
+ Myname = hd(tl(string:tokens(atom_to_list(node()), "@"))),
+ io:format("Myname ~p ~n", [Myname]),
+ EINode = list_to_atom("c42@"++Myname),
+ io:format("EINode ~p ~n", [EINode]),
+
+ Port = 6543,
+ {ok, ListenFd} = ei_publish(P, Port),
+ MRef1 = erlang:monitor(process, {any, EINode}),
+ {any, EINode} ! hello,
+
+ {ok, Fd, _Node} = ei_accept(P, ListenFd),
+ hello = ei_receive(P, Fd),
+
+ %% Again, now on an established connection.
+ MRef2 = erlang:monitor(process, {any, EINode}),
+ {any, EINode} ! hello,
+ hello = ei_receive(P, Fd),
+
+ ok = receive M -> M after 0 -> ok end,
+
+ runner:finish(P),
+
+ [{'DOWN', MRef1, process, {any, EINode}, noconnection},
+ {'DOWN', MRef2, process, {any, EINode}, noconnection}
+ ] = lists:sort(flush(2, 1000)),
+
+ ok.
+
waitfornode(String,0) ->
io:format("~s never published itself.~n",[String]),
false;
@@ -120,10 +164,9 @@ send_rec_einode(N, TestServerPid) ->
ct:fail(EINode)
end.
-start_einode(Einode, N, Host, Port) ->
+start_einode(Einode, N, Host) ->
Einodecmd = Einode ++ " " ++ atom_to_list(erlang:get_cookie())
- ++ " " ++ integer_to_list(N) ++ " " ++ Host ++ " "
- ++ integer_to_list(Port) ++ " nothreads",
+ ++ " " ++ integer_to_list(N) ++ " " ++ Host,
io:format("Einodecmd ~p ~n", [Einodecmd]),
open_port({spawn, Einodecmd}, []),
ok.
@@ -131,14 +174,21 @@ start_einode(Einode, N, Host, Port) ->
%%% Interface functions for ei (erl_interface) functions.
-ei_connect_init(P, Num, Cookie, Creation) ->
- send_command(P, ei_connect_init, [Num,Cookie,Creation]),
+ei_connect_init(P, Num, Cookie, Creation, Compat) ->
+ send_command(P, ei_connect_init, [Num,Cookie,Creation,Compat]),
case get_term(P) of
{term,Int} when is_integer(Int) -> Int
end.
-ei_accept(P, PortNo) ->
- send_command(P, ei_accept, [PortNo]),
+ei_publish(P, PortNo) ->
+ send_command(P, ei_publish, [PortNo]),
+ case get_term(P) of
+ {term,{ListenFd, EpmdFd, _}} when ListenFd >= 0, EpmdFd >= 0 -> {ok, ListenFd};
+ {term,{_, _, Errno}} -> {error,Errno}
+ end.
+
+ei_accept(P, ListenFd) ->
+ send_command(P, ei_accept, [ListenFd]),
case get_term(P) of
{term,{Fd, _, Node}} when Fd >= 0 -> {ok, Fd, Node};
{term,{_Fd, Errno, _Node}} -> {error,Errno}
@@ -151,3 +201,12 @@ ei_receive(P, Fd) ->
send_command(P, Name, Args) ->
runner:send_term(P, {Name,list_to_tuple(Args)}).
+
+flush(0, Timeout) ->
+ flush(1, Timeout div 10);
+flush(Expected, Timeout) ->
+ receive M ->
+ [M | flush(Expected-1, Timeout)]
+ after Timeout ->
+ []
+ end.
diff --git a/lib/erl_interface/test/ei_accept_SUITE_data/ei_accept_test.c b/lib/erl_interface/test/ei_accept_SUITE_data/ei_accept_test.c
index 7b81ee5491..09b0b5440b 100644
--- a/lib/erl_interface/test/ei_accept_SUITE_data/ei_accept_test.c
+++ b/lib/erl_interface/test/ei_accept_SUITE_data/ei_accept_test.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2001-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -43,6 +43,7 @@
#include "ei_runner.h"
static void cmd_ei_connect_init(char* buf, int len);
+static void cmd_ei_publish(char* buf, int len);
static void cmd_ei_accept(char* buf, int len);
static void cmd_ei_receive(char* buf, int len);
static void cmd_ei_unpublish(char* buf, int len);
@@ -57,7 +58,8 @@ static struct {
int num_args; /* Number of arguments. */
void (*func)(char* buf, int len);
} commands[] = {
- "ei_connect_init", 3, cmd_ei_connect_init,
+ "ei_connect_init", 4, cmd_ei_connect_init,
+ "ei_publish", 1, cmd_ei_publish,
"ei_accept", 1, cmd_ei_accept,
"ei_receive", 1, cmd_ei_receive,
"ei_unpublish", 0, cmd_ei_unpublish
@@ -72,12 +74,10 @@ TESTCASE(interpret)
int i;
ei_term term;
+ ei_init();
+
ei_x_new(&x);
- for (;;) {
- if (get_bin_term(&x, &term)) {
- report(1);
- return;
- } else {
+ while (get_bin_term(&x, &term) == 0) {
char* buf = x.buff, func[MAXATOMLEN];
int index = x.index, arity;
if (term.ei_type != ERL_SMALL_TUPLE_EXT || term.arity != 2)
@@ -98,78 +98,86 @@ TESTCASE(interpret)
message("\"%d\" \n", func);
fail("bad command");
}
- }
- }
+ }
+ report(1);
+ ei_x_free(&x);
}
static void cmd_ei_connect_init(char* buf, int len)
{
int index = 0, r = 0;
- int type, size;
- long l;
- char b[100];
+ long num, creation;
+ unsigned long compat;
+ char node_name[100];
char cookie[MAXATOMLEN], * cp = cookie;
ei_x_buff res;
- if (ei_decode_long(buf, &index, &l) < 0)
+ if (ei_decode_long(buf, &index, &num) < 0)
fail("expected int");
- sprintf(b, "c%d", l);
- /* FIXME don't use internal and maybe use skip?! */
- ei_get_type_internal(buf, &index, &type, &size);
+ sprintf(node_name, "c%d", num);
if (ei_decode_atom(buf, &index, cookie) < 0)
fail("expected atom (cookie)");
if (cookie[0] == '\0')
cp = NULL;
- r = ei_connect_init(&ec, b, cp, 0);
+ if (ei_decode_long(buf, &index, &creation) < 0)
+ fail("expected int");
+ if (ei_decode_long(buf, &index, &compat) < 0)
+ fail("expected uint");
+ if (compat)
+ ei_set_compat_rel(compat);
+ r = ei_connect_init(&ec, node_name, cp, creation);
ei_x_new_with_version(&res);
ei_x_encode_long(&res, r);
send_bin_term(&res);
ei_x_free(&res);
}
-static int my_listen(int port)
-{
- int listen_fd;
- struct sockaddr_in addr;
- const char *on = "1";
-
- if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
- return -1;
-
- setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, on, sizeof(on));
-
- memset((void*) &addr, 0, (size_t) sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- addr.sin_addr.s_addr = htonl(INADDR_ANY);
-
- if (bind(listen_fd, (struct sockaddr*) &addr, sizeof(addr)) < 0)
- return -1;
-
- listen(listen_fd, 5);
- return listen_fd;
-}
-
-static void cmd_ei_accept(char* buf, int len)
+static void cmd_ei_publish(char* buf, int len)
{
int index = 0;
- int listen, r;
- ErlConnect conn;
- long port;
+ int iport, lfd, r;
+ long lport;
ei_x_buff x;
int i;
/* get port */
- if (ei_decode_long(buf, &index, &port) < 0)
+ if (ei_decode_long(buf, &index, &lport) < 0)
fail("expected int (port)");
/* Make a listen socket */
- if ((listen = my_listen(port)) <= 0)
+
+ iport = (int) lport;
+ lfd = ei_listen(&ec, &iport, 5);
+ if (lfd < 0)
fail("listen");
+ lport = (long) iport;
- if ((i = ei_publish(&ec, port)) == -1)
+ if ((i = ei_publish(&ec, lport)) == -1)
fail("ei_publish");
#ifdef VXWORKS
save_fd(i);
#endif
+ /* send listen-fd, result and errno */
+ ei_x_new_with_version(&x);
+ ei_x_encode_tuple_header(&x, 3);
+ ei_x_encode_long(&x, (long) lfd);
+ ei_x_encode_long(&x, i);
+ ei_x_encode_long(&x, erl_errno);
+ send_bin_term(&x);
+ ei_x_free(&x);
+}
+
+static void cmd_ei_accept(char* buf, int len)
+{
+ int index = 0;
+ int r;
+ ErlConnect conn;
+ long listen;
+ ei_x_buff x;
+ int i;
+
+ /* get port */
+ if (ei_decode_long(buf, &index, &listen) < 0)
+ fail("expected int (listen fd)");
+
r = ei_accept(&ec, listen, &conn);
#ifdef VXWORKS
save_fd(r);
@@ -200,7 +208,7 @@ static void cmd_ei_receive(char* buf, int len)
if (got == ERL_TICK)
continue;
if (got == ERL_ERROR)
- fail("ei_xreceive_msg");
+ fail1("ei_xreceive_msg, got==%d", got);
break;
}
index = 1;
diff --git a/lib/erl_interface/test/ei_accept_SUITE_data/eiaccnode.c b/lib/erl_interface/test/ei_accept_SUITE_data/eiaccnode.c
index 308f843530..90c7a2259f 100644
--- a/lib/erl_interface/test/ei_accept_SUITE_data/eiaccnode.c
+++ b/lib/erl_interface/test/ei_accept_SUITE_data/eiaccnode.c
@@ -47,8 +47,6 @@
#define MAIN main
#endif
-static int my_listen(int port);
-
/*
A small einode.
To be called from the test case ei_accept_SUITE:multi_thread
@@ -64,7 +62,6 @@ static int my_listen(int port);
*/
static const char* cookie, * desthost;
-static int port; /* actually base port */
#ifndef SD_SEND
#ifdef SHUTWR
@@ -74,10 +71,6 @@ static int port; /* actually base port */
#endif
#endif
-#ifndef __WIN32__
-#define closesocket(fd) close(fd)
-#endif
-
#ifdef __WIN32__
static DWORD WINAPI
#else
@@ -86,26 +79,32 @@ static void*
einode_thread(void* num)
{
int n = (int)num;
+ int port;
ei_cnode ec;
- char myname[100], destname[100];
+ char myname[100], destname[100], filename[100];
int r, fd, listen;
ErlConnect conn;
erlang_msg msg;
-/* FILE* f;*/
+ FILE* file;
- sprintf(myname, "eiacc%d", n);
- printf("thread %d (%s) listening\n", n, myname, destname);
+ sprintf(filename, "eiacc%d_trace.txt", n);
+ file = fopen(filename, "w");
+
+ sprintf(myname, "eiacc%d", n); fflush(file);
r = ei_connect_init(&ec, myname, cookie, 0);
- if ((listen = my_listen(port+n)) <= 0) {
- printf("listen err\n");
+ port = 0;
+ listen = ei_listen(&ec, &port, 5);
+ if (listen <= 0) {
+ fprintf(file, "listen err\n"); fflush(file);
exit(7);
}
- if (ei_publish(&ec, port + n) == -1) {
- printf("ei_publish port %d\n", port+n);
+ fprintf(file, "thread %d (%s:%s) listening on port %d\n", n, myname, destname, port);
+ if (ei_publish(&ec, port) == -1) {
+ fprintf(file, "ei_publish port %d\n", port+n); fflush(file);
exit(8);
}
fd = ei_accept(&ec, listen, &conn);
- printf("ei_accept %d\n", fd);
+ fprintf(file, "ei_accept %d\n", fd); fflush(file);
if (fd >= 0) {
ei_x_buff x, xs;
int index, version;
@@ -117,37 +116,38 @@ static void*
if (got == ERL_TICK)
continue;
if (got == ERL_ERROR) {
- printf("receive error %d\n", n);
+ fprintf(file, "receive error %d\n", n); fflush(file);
return 0;
}
- printf("received %d\n", got);
+ fprintf(file, "received %d\n", got); fflush(file);
break;
}
index = 0;
if (ei_decode_version(x.buff, &index, &version) != 0) {
- printf("ei_decode_version %d\n", n);
+ fprintf(file, "ei_decode_version %d\n", n); fflush(file);
return 0;
}
if (ei_decode_pid(x.buff, &index, &pid) != 0) {
- printf("ei_decode_pid %d\n", n);
+ fprintf(file, "ei_decode_pid %d\n", n); fflush(file);
return 0;
}
-/* fprintf(f, "got pid from %s \n", pid.node);*/
+ fprintf(file, "got pid from %s \n", pid.node); fflush(file);
ei_x_new_with_version(&xs);
ei_x_encode_tuple_header(&xs, 2);
ei_x_encode_long(&xs, n);
ei_x_encode_pid(&xs, &pid);
r = ei_send(fd, &pid, xs.buff, xs.index);
-/* fprintf(f, "sent %d bytes %d\n", xs.index, r);*/
+ fprintf(file, "sent %d bytes %d\n", xs.index, r); fflush(file);
shutdown(fd, SD_SEND);
- closesocket(fd);
+ ei_close_connection(fd);
ei_x_free(&x);
ei_x_free(&xs);
} else {
- printf("coudn't connect fd %d r %d\n", fd, r);
+ fprintf(file, "coudn't connect fd %d r %d\n", fd, r); fflush(file);
}
- printf("done thread %d\n", n);
-/* fclose(f);*/
+ ei_close_connection(listen);
+ fprintf(file, "done thread %d\n", n);
+ fclose(file);
return 0;
}
@@ -170,12 +170,16 @@ MAIN(int argc, char *argv[])
if (n > 100)
exit(2);
desthost = argv[3];
- port = atoi(argv[4]);
-#ifndef VXWORKS
- no_threads = argv[5] != NULL && strcmp(argv[5], "nothreads") == 0;
-#else
+ if (argc == 3)
+ no_threads = 0;
+ else
+ no_threads = argv[4] != NULL && strcmp(argv[4], "nothreads") == 0;
+#ifdef VXWORKS
no_threads = 1;
#endif
+
+ ei_init();
+
for (i = 0; i < n; ++i) {
if (!no_threads) {
#ifndef VXWORKS
@@ -209,27 +213,3 @@ MAIN(int argc, char *argv[])
printf("ok\n");
return 0;
}
-
-static int my_listen(int port)
-{
- int listen_fd;
- struct sockaddr_in addr;
- const char *on = "1";
-
- if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
- return -1;
-
- setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, on, sizeof(on));
-
- memset((void*) &addr, 0, (size_t) sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- addr.sin_addr.s_addr = htonl(INADDR_ANY);
-
- if (bind(listen_fd, (struct sockaddr*) &addr, sizeof(addr)) < 0)
- return -1;
-
- listen(listen_fd, 5);
- return listen_fd;
-}
-
diff --git a/lib/erl_interface/test/ei_connect_SUITE.erl b/lib/erl_interface/test/ei_connect_SUITE.erl
index 66498deadc..6184ce801b 100644
--- a/lib/erl_interface/test/ei_connect_SUITE.erl
+++ b/lib/erl_interface/test/ei_connect_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
-include("ei_connect_SUITE_data/ei_connect_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
ei_send/1,
ei_reg_send/1,
ei_format_pid/1,
@@ -44,8 +45,11 @@ all() ->
[ei_send, ei_reg_send, ei_rpc, ei_format_pid, ei_send_funs,
ei_threaded_send, ei_set_get_tracelevel].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
ei_send(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
0 = ei_connect_init(P, 42, erlang:get_cookie(), 0),
{ok,Fd} = ei_connect(P, node()),
@@ -58,7 +62,7 @@ ei_send(Config) when is_list(Config) ->
ei_format_pid(Config) when is_list(Config) ->
S = self(),
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
0 = ei_connect_init(P, 42, erlang:get_cookie(), 0),
{ok,Fd} = ei_connect(P, node()),
@@ -70,14 +74,15 @@ ei_format_pid(Config) when is_list(Config) ->
ok.
ei_send_funs(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
0 = ei_connect_init(P, 42, erlang:get_cookie(), 0),
{ok,Fd} = ei_connect(P, node()),
Fun1 = fun ei_send/1,
- Fun2 = fun(X) -> P, X, Fd, Fun1 end,
+ Fun2 = fun(X) -> {P, X, Fd, Fun1} end,
+ Bits = <<1,2,3:5>>,
- AMsg={Fun1,Fun2},
+ AMsg={Fun1,Fun2,Bits},
%%AMsg={wait_with_funs, new_dist_format},
ok = ei_send_funs(P, Fd, self(), AMsg),
EIMsg = receive M -> M end,
@@ -88,7 +93,7 @@ ei_send_funs(Config) when is_list(Config) ->
ok.
ei_reg_send(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
0 = ei_connect_init(P, 42, erlang:get_cookie(), 0),
{ok,Fd} = ei_connect(P, node()),
@@ -137,7 +142,7 @@ start_einode(Einode, N, Host) ->
ok.
ei_rpc(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
0 = ei_connect_init(P, 42, erlang:get_cookie(), 0),
{ok,Fd} = ei_connect(P, node()),
@@ -150,7 +155,7 @@ ei_rpc(Config) when is_list(Config) ->
ok.
ei_set_get_tracelevel(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
5 = ei_set_get_tracelevel(P, 5),
0 = ei_connect_init(P, 42, erlang:get_cookie(), 0),
{ok,Fd} = ei_connect(P, node()),
diff --git a/lib/erl_interface/test/ei_connect_SUITE_data/ei_connect_test.c b/lib/erl_interface/test/ei_connect_SUITE_data/ei_connect_test.c
index 6a3796dd24..385bcdd422 100644
--- a/lib/erl_interface/test/ei_connect_SUITE_data/ei_connect_test.c
+++ b/lib/erl_interface/test/ei_connect_SUITE_data/ei_connect_test.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2001-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -73,12 +73,10 @@ TESTCASE(interpret)
int i;
ei_term term;
+ ei_init();
+
ei_x_new(&x);
- for (;;) {
- if (get_bin_term(&x, &term)) {
- report(1);
- return;
- } else {
+ while (get_bin_term(&x, &term) == 0) {
char* buf = x.buff, func[MAXATOMLEN];
int index = x.index, arity;
if (term.ei_type != ERL_SMALL_TUPLE_EXT || term.arity != 2)
@@ -99,15 +97,16 @@ TESTCASE(interpret)
message("\"%d\" \n", func);
fail("bad command");
}
- }
- }
+ }
+ report(1);
+ ei_x_free(&x);
+ return;
}
static void cmd_ei_connect_init(char* buf, int len)
{
int index = 0, r = 0;
- int type, size;
long l;
char b[100];
char cookie[MAXATOMLEN], * cp = cookie;
@@ -115,8 +114,6 @@ static void cmd_ei_connect_init(char* buf, int len)
if (ei_decode_long(buf, &index, &l) < 0)
fail("expected int");
sprintf(b, "c%ld", l);
- /* FIXME don't use internal and maybe use skip?! */
- ei_get_type_internal(buf, &index, &type, &size);
if (ei_decode_atom(buf, &index, cookie) < 0)
fail("expected atom (cookie)");
if (cookie[0] == '\0')
@@ -212,6 +209,9 @@ static void cmd_ei_send_funs(char* buf, int len)
erlang_pid pid;
ei_x_buff x;
erlang_fun fun1, fun2;
+ char* bitstring;
+ size_t bits;
+ int bitoffs;
if (ei_decode_long(buf, &index, &fd) < 0)
fail("expected long");
@@ -219,20 +219,24 @@ static void cmd_ei_send_funs(char* buf, int len)
fail("expected pid (node)");
if (ei_decode_tuple_header(buf, &index, &n) < 0)
fail("expected tuple");
- if (n != 2)
+ if (n != 3)
fail("expected tuple");
if (ei_decode_fun(buf, &index, &fun1) < 0)
fail("expected Fun1");
if (ei_decode_fun(buf, &index, &fun2) < 0)
fail("expected Fun2");
+ if (ei_decode_bitstring(buf, &index, &bitstring, &bitoffs, &bits) < 0)
+ fail("expected bitstring");
if (ei_x_new_with_version(&x) < 0)
fail("ei_x_new_with_version");
- if (ei_x_encode_tuple_header(&x, 2) < 0)
+ if (ei_x_encode_tuple_header(&x, 3) < 0)
fail("encode tuple header");
if (ei_x_encode_fun(&x, &fun1) < 0)
fail("encode fun1");
if (ei_x_encode_fun(&x, &fun2) < 0)
fail("encode fun2");
+ if (ei_x_encode_bitstring(&x, bitstring, bitoffs, bits) < 0)
+ fail("encode bitstring");
free_fun(&fun1);
free_fun(&fun2);
send_errno_result(ei_send(fd, &pid, x.buff, x.index));
diff --git a/lib/erl_interface/test/ei_decode_SUITE.erl b/lib/erl_interface/test/ei_decode_SUITE.erl
index 74fb9b8916..e005ec89c7 100644
--- a/lib/erl_interface/test/ei_decode_SUITE.erl
+++ b/lib/erl_interface/test/ei_decode_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
-include("ei_decode_SUITE_data/ei_decode_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
test_ei_decode_long/1,
test_ei_decode_ulong/1,
test_ei_decode_longlong/1,
@@ -42,6 +43,9 @@ all() ->
test_ei_decode_char, test_ei_decode_nonoptimal,
test_ei_decode_misc, test_ei_decode_utf8_atom].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
%% ---------------------------------------------------------------------------
% NOTE: for historical reasons we don't pach as tight as we can,
@@ -51,7 +55,7 @@ all() ->
%% ######################################################################## %%
test_ei_decode_long(Config) when is_list(Config) ->
- P = runner:start(?test_ei_decode_long),
+ P = runner:start(Config, ?test_ei_decode_long),
send_integers(P),
runner:recv_eot(P),
ok.
@@ -60,7 +64,7 @@ test_ei_decode_long(Config) when is_list(Config) ->
%% ######################################################################## %%
test_ei_decode_ulong(Config) when is_list(Config) ->
- P = runner:start(?test_ei_decode_ulong),
+ P = runner:start(Config, ?test_ei_decode_ulong),
send_integers(P),
runner:recv_eot(P),
ok.
@@ -77,7 +81,7 @@ test_ei_decode_longlong(Config) when is_list(Config) ->
vxworks ->
{skip,"Skipped on VxWorks"};
_ ->
- P = runner:start(?test_ei_decode_longlong),
+ P = runner:start(Config, ?test_ei_decode_longlong),
send_integers2(P),
runner:recv_eot(P),
ok
@@ -91,7 +95,7 @@ test_ei_decode_ulonglong(Config) when is_list(Config) ->
vxworks ->
{skip,"Skipped on VxWorks"};
_ ->
- P = runner:start(?test_ei_decode_ulonglong),
+ P = runner:start(Config, ?test_ei_decode_ulonglong),
send_integers2(P),
runner:recv_eot(P),
ok
@@ -104,7 +108,7 @@ test_ei_decode_ulonglong(Config) when is_list(Config) ->
%% FIXME maybe the API should change to use "unsigned char" to be clear?!
test_ei_decode_char(Config) when is_list(Config) ->
- P = runner:start(?test_ei_decode_char),
+ P = runner:start(Config, ?test_ei_decode_char),
send_term_as_binary(P,0),
send_term_as_binary(P,16#7f),
@@ -119,7 +123,7 @@ test_ei_decode_char(Config) when is_list(Config) ->
%% ######################################################################## %%
test_ei_decode_nonoptimal(Config) when is_list(Config) ->
- P = runner:start(?test_ei_decode_nonoptimal),
+ P = runner:start(Config, ?test_ei_decode_nonoptimal),
send_non_optimal_pos(P), % decode_char
send_non_optimal(P), % decode_long
@@ -168,7 +172,7 @@ send_non_optimal_neg(P) ->
%% ######################################################################## %%
test_ei_decode_misc(Config) when is_list(Config) ->
- P = runner:start(?test_ei_decode_misc),
+ P = runner:start(Config, ?test_ei_decode_misc),
send_term_as_binary(P,0.0),
send_term_as_binary(P,-1.0),
@@ -190,6 +194,9 @@ test_ei_decode_misc(Config) when is_list(Config) ->
send_term_as_binary(P,<<>>),
send_term_as_binary(P,<<"ÅÄÖåäö">>),
+ send_term_as_binary(P,<<1, 2, 3:5>>),
+ send_term_as_binary(P,<<1:1>>),
+
% send_term_as_binary(P,{}),
% send_term_as_binary(P,[]),
@@ -199,7 +206,7 @@ test_ei_decode_misc(Config) when is_list(Config) ->
%% ######################################################################## %%
test_ei_decode_utf8_atom(Config) ->
- P = runner:start(?test_ei_decode_utf8_atom),
+ P = runner:start(Config, ?test_ei_decode_utf8_atom),
send_latin1_atom_as_binary(P,"å"),
send_latin1_atom_as_binary(P,"ä"),
diff --git a/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c b/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c
index b7a2c4bb8b..46d6b8f2af 100644
--- a/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c
+++ b/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2004-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -105,6 +105,7 @@ int ei_decode_my_string(const char *buf, int *index, char *to,
fail1("size of encoded data (%d) is incorrect", size1); \
return; \
} \
+ free_packet(buf); \
} \
#define EI_DECODE_2_FAIL(FUNC,SIZE,TYPE,VAL) \
@@ -148,6 +149,7 @@ int ei_decode_my_string(const char *buf, int *index, char *to,
fail("size of encoded data should be 0"); \
return; \
} \
+ free_packet(buf); \
} \
#define dump(arr, num) { \
@@ -205,6 +207,7 @@ int ei_decode_my_string(const char *buf, int *index, char *to,
fail("size of encoded data is incorrect"); \
return; \
} \
+ free_packet(buf); \
} \
#define EI_DECODE_STRING(FUNC,SIZE,VAL) \
@@ -248,74 +251,146 @@ int ei_decode_my_string(const char *buf, int *index, char *to,
fail("size of encoded data should be 0"); \
return; \
} \
+ free_packet(buf); \
} \
//#define EI_DECODE_UTF8_STRING(FUNC,SIZE,VAL)
-#define EI_DECODE_BIN(FUNC,SIZE,VAL,LEN) \
- { \
- char p[1024]; \
- char *buf; \
- long len; \
- int size1 = 0; \
- int size2 = 0; \
- int err; \
- message("ei_" #FUNC " should be " #VAL); \
- buf = read_packet(NULL); \
- err = ei_ ## FUNC(buf+1, &size1, NULL, &len); \
+static void decode_bin(int exp_size, const char* val, int exp_len)
+{
+ char p[1024];
+ char *buf;
+ long len;
+ int size1 = 0;
+ int size2 = 0;
+ int err;
+ message("ei_decode_binary should be %s", val);
+ buf = read_packet(NULL);
+ err = ei_decode_binary(buf+1, &size1, NULL, &len);
message("err = %d, size = %d, len = %d, expected size = %d, expected len = %d\n",\
- err,size1,len,SIZE,LEN); \
- if (err != 0) { \
- if (err != -1) { \
- fail("returned non zero but not -1 if NULL pointer"); \
- } else { \
- fail("returned non zero"); \
- } \
- return; \
- } \
-\
- if (len != LEN) { \
- fail("size is not correct"); \
- return; \
- } \
-\
- err = ei_ ## FUNC(buf+1, &size2, p, &len); \
+ err,size1,len, exp_size, exp_len);
+ if (err != 0) {
+ if (err != -1) {
+ fail("returned non zero but not -1 if NULL pointer");
+ } else {
+ fail("returned non zero");
+ }
+ return;
+ }
+
+ if (len != exp_len) {
+ fail("size is not correct");
+ return;
+ }
+
+ err = ei_decode_binary(buf+1, &size2, p, &len);
message("err = %d, size = %d, len = %d, expected size = %d, expected len = %d\n",\
- err,size2,len,SIZE,LEN); \
- if (err != 0) { \
- if (err != -1) { \
- fail("returned non zero but not -1 if NULL pointer"); \
- } else { \
- fail("returned non zero"); \
- } \
- return; \
- } \
-\
- if (len != LEN) { \
- fail("size is not correct"); \
- return; \
- } \
-\
- if (strncmp(p,VAL,LEN) != 0) { \
- fail("value is not correct"); \
- return; \
- } \
-\
- if (size1 != size2) { \
- fail("size with and without pointer differs"); \
- return; \
- } \
-\
- if (size1 != SIZE) { \
- fail("size of encoded data is incorrect"); \
- return; \
- } \
- } \
+ err,size2,len, exp_size, exp_len);
+ if (err != 0) {
+ if (err != -1) {
+ fail("returned non zero but not -1 if NULL pointer");
+ } else {
+ fail("returned non zero");
+ }
+ return;
+ }
+
+ if (len != exp_len) {
+ fail("size is not correct");
+ return;
+ }
+
+ if (strncmp(p,val,exp_len) != 0) {
+ fail("value is not correct");
+ return;
+ }
+
+ if (size1 != size2) {
+ fail("size with and without pointer differs");
+ return;
+ }
+
+ if (size1 != exp_size) {
+ fail("size of encoded data is incorrect");
+ return;
+ }
+ free_packet(buf);
+}
+
+static void decode_bits(int exp_size, const char* val, size_t exp_bits)
+{
+ const char* p;
+ char *buf;
+ size_t bits;
+ int bitoffs;
+ int size1 = 0;
+ int size2 = 0;
+ int err;
+ message("ei_decode_bitstring should be %d bits", (int)exp_bits);
+ buf = read_packet(NULL);
+ err = ei_decode_bitstring(buf+1, &size1, NULL, &bitoffs, &bits);
+ message("err = %d, size = %d, bitoffs = %d, bits = %d, expected size = %d, expected bits = %d\n",\
+ err,size1, bitoffs, (int)bits, exp_size, (int)exp_bits);
+
+ if (err != 0) {
+ if (err != -1) {
+ fail("returned non zero but not -1 if NULL pointer");
+ } else {
+ fail("returned non zero");
+ }
+ return;
+ }
+
+ if (bits != exp_bits) {
+ fail("number of bits is not correct");
+ return;
+ }
+ if (bitoffs != 0) {
+ fail("non zero bit offset");
+ return;
+ }
+
+ err = ei_decode_bitstring(buf+1, &size2, &p, NULL, &bits);
+ message("err = %d, size = %d, len = %d, expected size = %d, expected len = %d\n",\
+ err,size2, (int)bits, exp_size, (int)exp_bits);
+ if (err != 0) {
+ if (err != -1) {
+ fail("returned non zero but not -1 if NULL pointer");
+ } else {
+ fail("returned non zero");
+ }
+ return;
+ }
+
+ if (bits != exp_bits) {
+ fail("bits is not correct");
+ return;
+ }
+
+ if (memcmp(p, val, (exp_bits+7)/8) != 0) {
+ fail("value is not correct");
+ return;
+ }
+
+ if (size1 != size2) {
+ fail("size with and without pointer differs");
+ return;
+ }
+
+ if (size1 != exp_size) {
+ fail2("size of encoded data is incorrect %d != %d", size1, exp_size);
+ return;
+ }
+ free_packet(buf);
+}
+
/* ******************************************************************** */
TESTCASE(test_ei_decode_long)
{
+ ei_init();
+
EI_DECODE_2 (decode_long, 2, long, 0);
EI_DECODE_2 (decode_long, 2, long, 255);
EI_DECODE_2 (decode_long, 5, long, 256);
@@ -358,6 +433,8 @@ TESTCASE(test_ei_decode_long)
TESTCASE(test_ei_decode_ulong)
{
+ ei_init();
+
EI_DECODE_2 (decode_ulong, 2, unsigned long, 0);
EI_DECODE_2 (decode_ulong, 2, unsigned long, 255);
EI_DECODE_2 (decode_ulong, 5, unsigned long, 256);
@@ -404,6 +481,8 @@ TESTCASE(test_ei_decode_ulong)
TESTCASE(test_ei_decode_longlong)
{
+ ei_init();
+
#ifndef VXWORKS
EI_DECODE_2 (decode_longlong, 2, EI_LONGLONG, 0);
EI_DECODE_2 (decode_longlong, 2, EI_LONGLONG, 255);
@@ -438,6 +517,8 @@ TESTCASE(test_ei_decode_longlong)
TESTCASE(test_ei_decode_ulonglong)
{
+ ei_init();
+
#ifndef VXWORKS
EI_DECODE_2 (decode_ulonglong, 2, EI_ULONGLONG, 0);
EI_DECODE_2 (decode_ulonglong, 2, EI_ULONGLONG, 255);
@@ -473,6 +554,8 @@ TESTCASE(test_ei_decode_ulonglong)
TESTCASE(test_ei_decode_char)
{
+ ei_init();
+
EI_DECODE_2(decode_char, 2, char, 0);
EI_DECODE_2(decode_char, 2, char, 0x7f);
EI_DECODE_2(decode_char, 2, char, 0xff);
@@ -486,6 +569,8 @@ TESTCASE(test_ei_decode_char)
TESTCASE(test_ei_decode_nonoptimal)
{
+ ei_init();
+
EI_DECODE_2(decode_char, 2, char, 42);
EI_DECODE_2(decode_char, 5, char, 42);
EI_DECODE_2(decode_char, 4, char, 42);
@@ -607,6 +692,8 @@ TESTCASE(test_ei_decode_nonoptimal)
TESTCASE(test_ei_decode_misc)
{
+ ei_init();
+
/*
EI_DECODE_0(decode_version);
*/
@@ -625,9 +712,17 @@ TESTCASE(test_ei_decode_misc)
EI_DECODE_STRING(decode_my_string, 1, "");
EI_DECODE_STRING(decode_my_string, 9, "������");
- EI_DECODE_BIN(decode_binary, 8, "foo", 3);
- EI_DECODE_BIN(decode_binary, 5, "", 0);
- EI_DECODE_BIN(decode_binary, 11, "������", 6);
+ decode_bin(8, "foo", 3);
+ decode_bin(5, "", 0);
+ decode_bin(11, "������", 6);
+
+#define LAST_BYTE(V, BITS) ((V) << (8-(BITS)))
+ {
+ unsigned char bits1[] = {1, 2, LAST_BYTE(3,5) };
+ unsigned char bits2[] = {LAST_BYTE(1,1) };
+ decode_bits(9, bits1, 21);
+ decode_bits(7, bits2, 1);
+ }
/* FIXME check \0 in strings and atoms? */
/*
@@ -642,6 +737,7 @@ TESTCASE(test_ei_decode_misc)
TESTCASE(test_ei_decode_utf8_atom)
{
+ ei_init();
EI_DECODE_STRING_4(decode_my_atom_as, 4, P99({229,0}), /* LATIN1 "�" */
P99({ERLANG_ANY,ERLANG_LATIN1,ERLANG_LATIN1}));
diff --git a/lib/erl_interface/test/ei_decode_encode_SUITE.erl b/lib/erl_interface/test/ei_decode_encode_SUITE.erl
index 160720b413..3451d9f503 100644
--- a/lib/erl_interface/test/ei_decode_encode_SUITE.erl
+++ b/lib/erl_interface/test/ei_decode_encode_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
-include("ei_decode_encode_SUITE_data/ei_decode_encode_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
test_ei_decode_encode/1]).
suite() ->
@@ -33,6 +34,9 @@ suite() ->
all() ->
[test_ei_decode_encode].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
%% ---------------------------------------------------------------------------
% NOTE: these types have no meaning on the C side so we pass them
@@ -42,7 +46,7 @@ all() ->
%% ######################################################################## %%
test_ei_decode_encode(Config) when is_list(Config) ->
- P = runner:start(?test_ei_decode_encode),
+ P = runner:start(Config, ?test_ei_decode_encode),
Fun = fun (X) -> {X,true} end,
Pid = self(),
@@ -116,9 +120,31 @@ test_ei_decode_encode(Config) when is_list(Config) ->
send_rec(P, #{key => value}),
send_rec(P, maps:put(Port, Ref, #{key => value, key2 => Pid})),
+ [send_rec(P, <<16#dec0deb175:B/little>>) || B <- lists:seq(0,48)],
+
+ % And last an ugly duckling to test ei_encode_bitstring with bitoffs != 0
+ encode_bitstring(P),
+
runner:recv_eot(P),
ok.
+encode_bitstring(P) ->
+ %% Send one bitstring to c-node
+ Bits = <<16#18f6d4b2907e5c3a1:66>>,
+ P ! {self(), {command, term_to_binary(Bits, [{minor_version, 2}])}},
+
+ %% and then receive and verify a number of different sub-bitstrings
+ receive_sub_bitstring(P, Bits, 0, bit_size(Bits)).
+
+receive_sub_bitstring(_, _, _, NBits) when NBits < 0 ->
+ ok;
+receive_sub_bitstring(P, Bits, BitOffs, NBits) ->
+ <<_:BitOffs, Sub:NBits/bits, _/bits>> = Bits,
+ %%io:format("expecting term_to_binary(~p) = ~p\n", [Sub, term_to_binary(Sub)]),
+ {_B,Sub} = get_buf_and_term(P),
+ receive_sub_bitstring(P, Bits, BitOffs+1, NBits - ((NBits div 20)+1)).
+
+
%% ######################################################################## %%
diff --git a/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c b/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
index 467f789fdb..85ca6c56e9 100644
--- a/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
+++ b/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2004-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -40,6 +40,13 @@ typedef struct
erlang_char_encoding enc;
}my_atom;
+typedef struct
+{
+ const char* bytes;
+ unsigned int bitoffs;
+ size_t nbits;
+}my_bitstring;
+
struct my_obj {
union {
erlang_fun fun;
@@ -49,6 +56,7 @@ struct my_obj {
erlang_trace trace;
erlang_big big;
my_atom atom;
+ my_bitstring bits;
int arity;
}u;
@@ -119,6 +127,26 @@ struct Type my_atom_type = {
(encodeFT*)ei_encode_my_atom, (x_encodeFT*)ei_x_encode_my_atom
};
+int ei_decode_my_bits(const char *buf, int *index, my_bitstring* a)
+{
+ return ei_decode_bitstring(buf, index, (a ? &a->bytes : NULL),
+ (a ? &a->bitoffs : NULL),
+ (a ? &a->nbits : NULL));
+}
+int ei_encode_my_bits(char *buf, int *index, my_bitstring* a)
+{
+ return ei_encode_bitstring(buf, index, a->bytes, a->bitoffs, a->nbits);
+}
+int ei_x_encode_my_bits(ei_x_buff* x, my_bitstring* a)
+{
+ return ei_x_encode_bitstring(x, a->bytes, a->bitoffs, a->nbits);
+}
+
+struct Type my_bitstring_type = {
+ "bits", "my_bitstring", (decodeFT*)ei_decode_my_bits,
+ (encodeFT*)ei_encode_my_bits, (x_encodeFT*)ei_x_encode_my_bits
+};
+
int my_decode_tuple_header(const char *buf, int *index, struct my_obj* obj)
{
@@ -237,11 +265,7 @@ void decode_encode(struct Type** tv, int nobj)
size1 = 0;
err = t->ei_decode_fp(inp, &size1, NULL);
if (err != 0) {
- if (err != -1) {
- fail("decode returned non zero but not -1");
- } else {
- fail1("decode '%s' returned non zero", t->name);
- }
+ fail2("decode '%s' returned non zero %d", t->name, err);
return;
}
if (size1 < 1) {
@@ -466,9 +490,70 @@ void decode_encode_big(struct Type* t)
send_buffer(arg.buff, arg.index);
ei_x_free(&arg);
ei_free_big(p);
+ free_packet(buf);
}
+void encode_bitstring(void)
+{
+ char* packet;
+ char* inp;
+ char out_buf[BUFSZ];
+ int size;
+ int err, i;
+ ei_x_buff arg;
+ const char* p;
+ unsigned int bitoffs;
+ size_t nbits, org_nbits;
+
+ packet = read_packet(NULL);
+ inp = packet+1;
+
+ size = 0;
+ err = ei_decode_bitstring(inp, &size, &p, &bitoffs, &nbits);
+ if (err != 0) {
+ fail1("ei_decode_bitstring returned non zero %d", err);
+ return;
+ }
+
+ /*
+ * Now send a bunch of different sub-bitstrings back
+ * encoded both with ei_encode_ and ei_x_encode_.
+ */
+ org_nbits = nbits;
+ do {
+ size = 0;
+ err = ei_encode_bitstring(out_buf, &size, p, bitoffs, nbits);
+ if (err != 0) {
+ fail1("ei_encode_bitstring returned non zero %d", err);
+ return;
+ }
+
+ ei_x_new(&arg);
+ err = ei_x_encode_bitstring(&arg, p, bitoffs, nbits);
+ if (err != 0) {
+ fail1("ei_x_encode_bitstring returned non zero %d", err);
+ ei_x_free(&arg);
+ return;
+ }
+
+ if (arg.index < 1) {
+ fail("size is < 1");
+ ei_x_free(&arg);
+ return;
+ }
+
+ send_buffer(out_buf, size);
+ send_buffer(arg.buff, arg.index);
+ ei_x_free(&arg);
+
+ bitoffs++;
+ nbits -= (nbits / 20) + 1;
+ } while (nbits < org_nbits);
+
+ free_packet(packet);
+}
+
/* ******************************************************************** */
@@ -476,6 +561,8 @@ TESTCASE(test_ei_decode_encode)
{
int i;
+ ei_init();
+
decode_encode_one(&fun_type);
decode_encode_one(&pid_type);
decode_encode_one(&port_type);
@@ -534,6 +621,12 @@ TESTCASE(test_ei_decode_encode)
decode_encode(map, 7);
}
+ for (i=0; i <= 48; i++) {
+ decode_encode_one(&my_bitstring_type);
+ }
+
+ encode_bitstring();
+
report(1);
}
diff --git a/lib/erl_interface/test/ei_encode_SUITE.erl b/lib/erl_interface/test/ei_encode_SUITE.erl
index 8857b092f3..0267a5126f 100644
--- a/lib/erl_interface/test/ei_encode_SUITE.erl
+++ b/lib/erl_interface/test/ei_encode_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
-include("ei_encode_SUITE_data/ei_encode_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
test_ei_encode_long/1,
test_ei_encode_ulong/1,
test_ei_encode_longlong/1,
@@ -45,6 +46,9 @@ all() ->
test_ei_encode_fails, test_ei_encode_utf8_atom,
test_ei_encode_utf8_atom_len].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
%% ---------------------------------------------------------------------------
@@ -55,7 +59,7 @@ all() ->
%% ######################################################################## %%
test_ei_encode_long(Config) when is_list(Config) ->
- P = runner:start(?test_ei_encode_long),
+ P = runner:start(Config, ?test_ei_encode_long),
{<<97,0>> ,0} = get_buf_and_term(P),
{<<97,255>> ,255} = get_buf_and_term(P),
@@ -77,7 +81,7 @@ test_ei_encode_long(Config) when is_list(Config) ->
%% ######################################################################## %%
test_ei_encode_ulong(Config) when is_list(Config) ->
- P = runner:start(?test_ei_encode_ulong),
+ P = runner:start(Config, ?test_ei_encode_ulong),
{<<97,0>> ,0} = get_buf_and_term(P),
{<<97,255>> ,255} = get_buf_and_term(P),
@@ -101,7 +105,7 @@ test_ei_encode_longlong(Config) when is_list(Config) ->
vxworks ->
{skip,"Skipped on VxWorks"};
_ ->
- P = runner:start(?test_ei_encode_longlong),
+ P = runner:start(Config, ?test_ei_encode_longlong),
{<<97,0>> ,0} = get_buf_and_term(P),
{<<97,255>> ,255} = get_buf_and_term(P),
@@ -132,7 +136,7 @@ test_ei_encode_ulonglong(Config) when is_list(Config) ->
vxworks ->
{skip,"Skipped on VxWorks"};
_ ->
- P = runner:start(?test_ei_encode_ulonglong),
+ P = runner:start(Config, ?test_ei_encode_ulonglong),
{<<97,0>> ,0} = get_buf_and_term(P),
{<<97,255>> ,255} = get_buf_and_term(P),
@@ -158,7 +162,7 @@ test_ei_encode_ulonglong(Config) when is_list(Config) ->
%% FIXME maybe the API should change to use "unsigned char" to be clear?!
test_ei_encode_char(Config) when is_list(Config) ->
- P = runner:start(?test_ei_encode_char),
+ P = runner:start(Config, ?test_ei_encode_char),
{<<97, 0>>,0} = get_buf_and_term(P),
{<<97,127>>,16#7f} = get_buf_and_term(P),
@@ -171,7 +175,7 @@ test_ei_encode_char(Config) when is_list(Config) ->
%% ######################################################################## %%
test_ei_encode_misc(Config) when is_list(Config) ->
- P = runner:start(?test_ei_encode_misc),
+ P = runner:start(Config, ?test_ei_encode_misc),
<<131>> = get_binaries(P),
@@ -217,7 +221,7 @@ test_ei_encode_misc(Config) when is_list(Config) ->
%% ######################################################################## %%
test_ei_encode_fails(Config) when is_list(Config) ->
- P = runner:start(?test_ei_encode_fails),
+ P = runner:start(Config, ?test_ei_encode_fails),
XAtom = list_to_atom(lists:duplicate(255, $x)),
YAtom = list_to_atom(lists:duplicate(255, $y)),
@@ -236,7 +240,7 @@ test_ei_encode_fails(Config) when is_list(Config) ->
%% ######################################################################## %%
test_ei_encode_utf8_atom(Config) ->
- P = runner:start(?test_ei_encode_utf8_atom),
+ P = runner:start(Config, ?test_ei_encode_utf8_atom),
{<<119,2,195,133>>,'Å'} = get_buf_and_term(P),
{<<119,2,195,133>>,'Å'} = get_buf_and_term(P),
@@ -251,7 +255,7 @@ test_ei_encode_utf8_atom(Config) ->
%% ######################################################################## %%
test_ei_encode_utf8_atom_len(Config) ->
- P = runner:start(?test_ei_encode_utf8_atom_len),
+ P = runner:start(Config, ?test_ei_encode_utf8_atom_len),
{<<119,2,195,133>>,'Å'} = get_buf_and_term(P),
{<<119,4,195,133,195,132>>,'ÅÄ'} = get_buf_and_term(P),
diff --git a/lib/erl_interface/test/ei_encode_SUITE_data/ei_encode_test.c b/lib/erl_interface/test/ei_encode_SUITE_data/ei_encode_test.c
index 32811fdf22..6f63cc5d7e 100644
--- a/lib/erl_interface/test/ei_encode_SUITE_data/ei_encode_test.c
+++ b/lib/erl_interface/test/ei_encode_SUITE_data/ei_encode_test.c
@@ -403,6 +403,8 @@
TESTCASE(test_ei_encode_long)
{
+ ei_init();
+
EI_ENCODE_1(encode_long, 0);
EI_ENCODE_1(encode_long, 255);
@@ -430,6 +432,8 @@ TESTCASE(test_ei_encode_long)
TESTCASE(test_ei_encode_ulong)
{
+ ei_init();
+
EI_ENCODE_1(encode_ulong, 0);
EI_ENCODE_1(encode_ulong, 255);
@@ -454,6 +458,7 @@ TESTCASE(test_ei_encode_ulong)
TESTCASE(test_ei_encode_longlong)
{
+ ei_init();
#ifndef VXWORKS
@@ -494,6 +499,7 @@ TESTCASE(test_ei_encode_longlong)
TESTCASE(test_ei_encode_ulonglong)
{
+ ei_init();
#ifndef VXWORKS
@@ -527,6 +533,8 @@ TESTCASE(test_ei_encode_ulonglong)
TESTCASE(test_ei_encode_char)
{
+ ei_init();
+
EI_ENCODE_1(encode_char, 0);
EI_ENCODE_1(encode_char, 0x7f);
@@ -540,6 +548,8 @@ TESTCASE(test_ei_encode_char)
TESTCASE(test_ei_encode_misc)
{
+ ei_init();
+
EI_ENCODE_0(encode_version);
EI_ENCODE_1(encode_double, 0.0);
@@ -594,6 +604,8 @@ TESTCASE(test_ei_encode_fails)
char buf[1024];
int index;
+ ei_init();
+
/* FIXME the ei_x versions are not tested */
index = 0;
@@ -660,6 +672,7 @@ TESTCASE(test_ei_encode_fails)
TESTCASE(test_ei_encode_utf8_atom)
{
+ ei_init();
EI_ENCODE_3(encode_atom_as, "�", ERLANG_LATIN1, ERLANG_UTF8);
EI_ENCODE_3(encode_atom_as, "�", ERLANG_LATIN1, ERLANG_LATIN1);
@@ -686,6 +699,7 @@ TESTCASE(test_ei_encode_utf8_atom)
TESTCASE(test_ei_encode_utf8_atom_len)
{
+ ei_init();
EI_ENCODE_4(encode_atom_len_as, "���", 1, ERLANG_LATIN1, ERLANG_UTF8);
EI_ENCODE_4(encode_atom_len_as, "���", 2, ERLANG_LATIN1, ERLANG_LATIN1);
diff --git a/lib/erl_interface/test/ei_format_SUITE.erl b/lib/erl_interface/test/ei_format_SUITE.erl
index 07ee479b1f..e074c184c1 100644
--- a/lib/erl_interface/test/ei_format_SUITE.erl
+++ b/lib/erl_interface/test/ei_format_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,6 +26,7 @@
-export([format_wo_ver/1,
all/0, suite/0,
+ init_per_testcase/2,
atoms/1,
tuples/1,
lists/1]).
@@ -41,10 +42,13 @@ suite() ->
all() ->
[format_wo_ver, atoms, tuples, lists].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
%% Tests formatting various atoms.
atoms(Config) when is_list(Config) ->
- P = runner:start(?atoms),
+ P = runner:start(Config, ?atoms),
{term, ''} = get_term(P),
{term, 'a'} = get_term(P),
@@ -84,7 +88,7 @@ atoms(Config) when is_list(Config) ->
%% Tests formatting various tuples
tuples(Config) when is_list(Config) ->
- P = runner:start(?tuples),
+ P = runner:start(Config, ?tuples),
{term, {}} = get_term(P),
{term, {a}} = get_term(P),
@@ -105,7 +109,7 @@ tuples(Config) when is_list(Config) ->
%% Tests formatting various lists
lists(Config) when is_list(Config) ->
- P = runner:start(?lists),
+ P = runner:start(Config, ?lists),
{term, []} = get_term(P),
{term, [a]} = get_term(P),
@@ -146,7 +150,7 @@ lists(Config) when is_list(Config) ->
format_wo_ver(Config) when is_list(Config) ->
- P = runner:start(?format_wo_ver),
+ P = runner:start(Config, ?format_wo_ver),
{term, [-1, 2, $c, {a, "b"}, {c, 10}]} = get_term(P),
diff --git a/lib/erl_interface/test/ei_format_SUITE_data/ei_format_test.c b/lib/erl_interface/test/ei_format_SUITE_data/ei_format_test.c
index 8450332b28..1c0443c0f4 100644
--- a/lib/erl_interface/test/ei_format_SUITE_data/ei_format_test.c
+++ b/lib/erl_interface/test/ei_format_SUITE_data/ei_format_test.c
@@ -48,6 +48,8 @@ send_format(char* format)
TESTCASE(atoms)
{
+ ei_init();
+
send_format("''");
send_format("'a'");
send_format("'A'");
@@ -82,6 +84,8 @@ TESTCASE(atoms)
TESTCASE(tuples)
{
+ ei_init();
+
send_format("{}");
send_format("{a}");
send_format("{a, b}");
@@ -108,6 +112,8 @@ TESTCASE(lists)
ei_x_buff x;
static char str[65537];
+ ei_init();
+
send_format("[]");
send_format("[a]");
send_format("[a, b]");
@@ -177,6 +183,8 @@ TESTCASE(format_wo_ver) {
*/
ei_x_buff x;
+ ei_init();
+
ei_x_new (&x);
ei_x_format(&x, "[-1, +2, ~c, {~a,~s},{~a,~i}]", 'c', "a", "b", "c", 10);
send_bin_term(&x);
diff --git a/lib/erl_interface/test/ei_print_SUITE.erl b/lib/erl_interface/test/ei_print_SUITE.erl
index 6d5c341eae..c75ce55a7d 100644
--- a/lib/erl_interface/test/ei_print_SUITE.erl
+++ b/lib/erl_interface/test/ei_print_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
-include("ei_print_SUITE_data/ei_print_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
atoms/1, tuples/1, lists/1, strings/1]).
-import(runner, [get_term/1]).
@@ -38,10 +39,13 @@ suite() ->
all() ->
[atoms, tuples, lists, strings].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
%% Tests formatting various atoms.
atoms(Config) when is_list(Config) ->
- P = runner:start(?atoms),
+ P = runner:start(Config, ?atoms),
{term, "''"} = get_term(P),
{term, "a"} = get_term(P),
@@ -79,7 +83,7 @@ atoms(Config) when is_list(Config) ->
%% Tests formatting various tuples
tuples(Config) when is_list(Config) ->
- P = runner:start(?tuples),
+ P = runner:start(Config, ?tuples),
{term, "{}"} = get_term(P),
{term, "{a}"} = get_term(P),
@@ -100,7 +104,7 @@ tuples(Config) when is_list(Config) ->
%% Tests formatting various lists
lists(Config) when is_list(Config) ->
- P = runner:start(?lists),
+ P = runner:start(Config, ?lists),
{term, "[]"} = get_term(P),
{term, "[a]"} = get_term(P),
@@ -125,7 +129,7 @@ lists(Config) when is_list(Config) ->
ok.
strings(Config) when is_list(Config) ->
- P = runner:start(?strings),
+ P = runner:start(Config, ?strings),
{term, "\"\\n\""} = get_term(P),
{term, "\"\\r\\n\""} = get_term(P),
diff --git a/lib/erl_interface/test/ei_print_SUITE_data/ei_print_test.c b/lib/erl_interface/test/ei_print_SUITE_data/ei_print_test.c
index 15cfbcae34..80be3016e6 100644
--- a/lib/erl_interface/test/ei_print_SUITE_data/ei_print_test.c
+++ b/lib/erl_interface/test/ei_print_SUITE_data/ei_print_test.c
@@ -84,6 +84,8 @@ static void send_printed3f(char* format, float f1, float f2)
TESTCASE(atoms)
{
+ ei_init();
+
send_printed("''");
send_printed("'a'");
send_printed("'A'");
@@ -118,6 +120,8 @@ TESTCASE(atoms)
TESTCASE(tuples)
{
+ ei_init();
+
send_printed("{}");
send_printed("{a}");
send_printed("{a, b}");
@@ -138,6 +142,8 @@ TESTCASE(lists)
{
ei_x_buff x;
+ ei_init();
+
send_printed("[]");
send_printed("[a]");
send_printed("[a, b]");
@@ -164,6 +170,8 @@ TESTCASE(strings)
{
ei_x_buff x;
+ ei_init();
+
send_printed("\"\n\"");
send_printed("\"\r\n\"");
send_printed("\"a\"");
diff --git a/lib/erl_interface/test/ei_tmo_SUITE.erl b/lib/erl_interface/test/ei_tmo_SUITE.erl
index 003fe20594..5b9de80128 100644
--- a/lib/erl_interface/test/ei_tmo_SUITE.erl
+++ b/lib/erl_interface/test/ei_tmo_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -39,14 +39,16 @@ all() ->
[framework_check, ei_accept_tmo, ei_connect_tmo,
ei_send_tmo, ei_recv_tmo].
-init_per_testcase(_Case, Config) ->
+init_per_testcase(Case, Config) ->
+ Config1 = runner:init_per_testcase(?MODULE, Case, Config),
+
% test if platform is vxworks_simso
{_,Host} = split(node()),
Bool = case atom_to_list(Host) of
[$v,$x,$s,$i,$m | _] -> true;
_ -> false
end,
- [{vxsim,Bool}|Config].
+ [{vxsim,Bool} | Config1].
end_per_testcase(_Case, _Config) ->
ok.
@@ -55,7 +57,7 @@ end_per_testcase(_Case, _Config) ->
framework_check(Config) when is_list(Config) ->
%%dbg:tracer(),
%%dbg:p(self()),
- P = runner:start(?framework_check),
+ P = runner:start(Config, ?framework_check),
runner:send_term(P,{hello,world}),
{term, {hello,world}} = runner:get_term(P),
runner:recv_eot(P),
@@ -71,7 +73,7 @@ ei_recv_tmo(Config) when is_list(Config) ->
do_one_recv(Config,CNode) ->
{_,Host} = split(node()),
- P1 = runner:start(?recv_tmo),
+ P1 = runner:start(Config, ?recv_tmo),
runner:send_term(P1,{CNode,
erlang:get_cookie(),
node()}),
@@ -84,7 +86,7 @@ do_one_recv(Config,CNode) ->
runner:recv_eot(P1).
do_one_recv_failure(Config,CNode) ->
- P1 = runner:start(?recv_tmo),
+ P1 = runner:start(Config, ?recv_tmo),
runner:send_term(P1,{CNode,
erlang:get_cookie(),
node()}),
@@ -110,7 +112,7 @@ ei_send_tmo(Config) when is_list(Config) ->
do_one_send(Config,From,CNode) ->
{_,Host} = split(node()),
- P1 = runner:start(?send_tmo),
+ P1 = runner:start(Config, ?send_tmo),
runner:send_term(P1,{CNode,
erlang:get_cookie(),
node()}),
@@ -139,7 +141,7 @@ do_one_send_failure(Config,From,FakeName,CName,VxSim) ->
exit(Else)
end,
EpmdSocket = register(OurName, LSocket, 1, 5),
- P3 = runner:start(?send_tmo),
+ P3 = runner:start(Config, ?send_tmo),
Cookie = kaksmula_som_ingen_bryr_sig_om,
runner:send_term(P3,{CName,
Cookie,
@@ -202,7 +204,7 @@ ei_connect_tmo(Config) when is_list(Config) ->
%dbg:p(self()),
VxSim = proplists:get_value(vxsim, Config),
DummyNode = make_and_check_dummy(),
- P = runner:start(?connect_tmo),
+ P = runner:start(Config, ?connect_tmo),
runner:send_term(P,{c_nod_connect_tmo_1,
kaksmula_som_ingen_bryr_sig_om,
DummyNode}),
@@ -219,7 +221,7 @@ ei_connect_tmo(Config) when is_list(Config) ->
end
end,
runner:recv_eot(P),
- P2 = runner:start(?connect_tmo),
+ P2 = runner:start(Config, ?connect_tmo),
runner:send_term(P2,{c_nod_connect_tmo_2,
erlang:get_cookie(),
node()}),
@@ -237,7 +239,7 @@ ei_connect_tmo(Config) when is_list(Config) ->
exit(Else)
end,
EpmdSocket = register(OurName, LSocket, 1, 5),
- P3 = runner:start(?connect_tmo),
+ P3 = runner:start(Config, ?connect_tmo),
Cookie = kaksmula_som_ingen_bryr_sig_om,
runner:send_term(P3,{c_nod_connect_tmo_3,
Cookie,
@@ -266,12 +268,12 @@ ei_connect_tmo(Config) when is_list(Config) ->
ei_accept_tmo(Config) when is_list(Config) ->
%%dbg:tracer(),
%%dbg:p(self()),
- P = runner:start(?accept_tmo),
+ P = runner:start(Config, ?accept_tmo),
runner:send_term(P,{c_nod_som_ingen_kontaktar_1,
kaksmula_som_ingen_bryr_sig_om}),
{term,{-1,ETimedout,ETimedout}} = runner:get_term(P, 10000),
runner:recv_eot(P),
- P2 = runner:start(?accept_tmo),
+ P2 = runner:start(Config, ?accept_tmo),
runner:send_term(P2,{c_nod_som_vi_kontaktar_1,
erlang:get_cookie()}),
receive after 1000 -> ok end,
@@ -280,7 +282,7 @@ ei_accept_tmo(Config) when is_list(Config) ->
{term, X} = runner:get_term(P2, 10000),
runner:recv_eot(P2),
true = is_integer(X),
- P3 = runner:start(?accept_tmo),
+ P3 = runner:start(Config, ?accept_tmo),
runner:send_term(P3,{c_nod_som_vi_kontaktar_2,
erlang:get_cookie()}),
receive after 1000 -> ok end,
diff --git a/lib/erl_interface/test/ei_tmo_SUITE_data/ei_tmo_test.c b/lib/erl_interface/test/ei_tmo_SUITE_data/ei_tmo_test.c
index 0079ef8c86..693e405f75 100644
--- a/lib/erl_interface/test/ei_tmo_SUITE_data/ei_tmo_test.c
+++ b/lib/erl_interface/test/ei_tmo_SUITE_data/ei_tmo_test.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2003-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
*/
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#ifdef VXWORKS
#include "reclaim.h"
@@ -95,6 +96,8 @@ TESTCASE(framework_check)
int i;
#endif
+ ei_init();
+
OPEN_DEBUGFILE(1);
DEBUGF(("B�rjar... \n"));
@@ -339,6 +342,7 @@ TESTCASE(recv_tmo)
int com_sock = -1;
ei_cnode nodeinfo;
+ ei_init();
OPEN_DEBUGFILE(5);
@@ -449,6 +453,7 @@ TESTCASE(send_tmo)
int com_sock = -1;
ei_cnode nodeinfo;
+ ei_init();
OPEN_DEBUGFILE(4);
@@ -590,7 +595,7 @@ TESTCASE(connect_tmo)
int com_sock = -1;
ei_cnode nodeinfo;
-
+ ei_init();
OPEN_DEBUGFILE(3);
@@ -679,7 +684,7 @@ TESTCASE(accept_tmo)
ErlConnect peer;
ei_cnode nodeinfo;
-
+ ei_init();
OPEN_DEBUGFILE(2);
diff --git a/lib/erl_interface/test/erl_call_SUITE.erl b/lib/erl_interface/test/erl_call_SUITE.erl
new file mode 100644
index 0000000000..9e2b2e4251
--- /dev/null
+++ b/lib/erl_interface/test/erl_call_SUITE.erl
@@ -0,0 +1,96 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+-module(erl_call_SUITE).
+
+-include_lib("common_test/include/ct.hrl").
+
+-export([all/0, smoke/1]).
+
+all() ->
+ [smoke].
+
+smoke(Config) when is_list(Config) ->
+ ErlCall = find_erl_call(),
+ NameSwitch = case net_kernel:longnames() of
+ true ->
+ "-name";
+ false ->
+ "-sname"
+ end,
+ Name = atom_to_list(?MODULE)
+ ++ "-"
+ ++ integer_to_list(erlang:system_time(microsecond)),
+
+ ArgsList = ["-s", "-a", "erlang node", NameSwitch, Name],
+ io:format("erl_call: \"~ts\"\n~nargs list: ~p~n", [ErlCall, ArgsList]),
+ CmdRes = get_smoke_port_res(open_port({spawn_executable, ErlCall},
+ [{args, ArgsList}, eof]), []),
+ io:format("CmdRes: ~p~n", [CmdRes]),
+
+ [_, Hostname] = string:lexemes(atom_to_list(node()), "@"),
+ NodeName = list_to_atom(Name ++ "@" ++ Hostname),
+ io:format("NodeName: ~p~n~n", [NodeName]),
+
+ pong = net_adm:ping(NodeName),
+ rpc:cast(NodeName, erlang, halt, []),
+ NodeName = list_to_atom(string:trim(CmdRes, both, "'")),
+ ok.
+
+%
+% Utility functions...
+%
+
+find_erl_call() ->
+ ErlCallName = case os:type() of
+ {win32, _} -> "erl_call.exe";
+ _ -> "erl_call"
+ end,
+ LibDir = code:lib_dir(erl_interface),
+ InstalledErlCall = filename:join([LibDir, "bin", ErlCallName]),
+ TargetDir = erlang:system_info(system_architecture),
+ TargetErlCall = filename:join([LibDir, "bin", TargetDir, ErlCallName]),
+
+ try
+ lists:foreach(fun (F) ->
+ io:format("Checking: \"~ts\"~n", [F]),
+ case file:read_file_info(F) of
+ {ok, _} ->
+ throw(F);
+ _ ->
+ ok
+ end
+ end,
+ [InstalledErlCall, TargetErlCall]),
+ exit({missing, erl_call})
+ catch
+ throw:ErlCall ->
+ ErlCall
+ end.
+
+get_smoke_port_res(Port, Acc) when is_port(Port) ->
+ receive
+ {Port, {data, Data}} ->
+ get_smoke_port_res(Port, [Acc|Data]);
+ {Port, eof} ->
+ lists:flatten(Acc)
+ end.
+
diff --git a/lib/erl_interface/test/erl_connect_SUITE.erl b/lib/erl_interface/test/erl_connect_SUITE.erl
index cd73f07b8f..782691b8fb 100644
--- a/lib/erl_interface/test/erl_connect_SUITE.erl
+++ b/lib/erl_interface/test/erl_connect_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
-include("erl_connect_SUITE_data/erl_connect_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
erl_send/1, erl_reg_send/1,
erl_send_cookie_file/1]).
@@ -38,8 +39,11 @@ all() ->
[erl_send, erl_reg_send, erl_send_cookie_file].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
erl_send(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
1 = erl_connect_init(P, 42, erlang:get_cookie(), 0),
{ok,Fd} = erl_connect(P, node()),
@@ -56,7 +60,7 @@ erl_send_cookie_file(Config) when is_list(Config) ->
vxworks ->
{skip,"Skipped on VxWorks"};
_ ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
1 = erl_connect_init(P, 42, '', 0),
{ok,Fd} = erl_connect(P, node()),
@@ -70,7 +74,7 @@ erl_send_cookie_file(Config) when is_list(Config) ->
end.
erl_reg_send(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
1 = erl_connect_init(P, 42, erlang:get_cookie(), 0),
{ok,Fd} = erl_connect(P, node()),
diff --git a/lib/erl_interface/test/erl_eterm_SUITE.erl b/lib/erl_interface/test/erl_eterm_SUITE.erl
index 3d1e33081b..77910a9fc7 100644
--- a/lib/erl_interface/test/erl_eterm_SUITE.erl
+++ b/lib/erl_interface/test/erl_eterm_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -35,6 +35,7 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-export([all/0, suite/0,
+ init_per_testcase/2,
build_terms/1, round_trip_conversion/1,
decode_terms/1, decode_float/1,
t_erl_mk_int/1, t_erl_mk_list/1,
@@ -94,6 +95,9 @@ all() ->
high_chaparal, broken_data, cnode_1].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%
%%% 1. B a s i c t e s t s
@@ -104,7 +108,7 @@ all() ->
%% a list and verifies that the result is as expected.
build_terms(Config) when is_list(Config) ->
- P = runner:start(?build_terms),
+ P = runner:start(Config, ?build_terms),
{term, Term} = get_term(P),
io:format("Received: ~p", [Term]),
[ARefLN, ARef, APortLN, APort, APidLN, APid,
@@ -136,7 +140,7 @@ build_terms(Config) when is_list(Config) ->
%% This test is run entirely in C code.
round_trip_conversion(Config) when is_list(Config) ->
- runner:test(?round_trip_conversion),
+ runner:test(Config, ?round_trip_conversion),
ok.
%% This test sends a list of all data types to the C code function,
@@ -156,7 +160,7 @@ decode_terms(Config) when is_list(Config) ->
{element1, 42, 767}, "A string",
1, -1, 0, 3.0, ABinary, 'I am an atom'],
- P = runner:start(?decode_terms),
+ P = runner:start(Config, ?decode_terms),
runner:send_term(P, Terms),
runner:recv_eot(P),
@@ -165,7 +169,7 @@ decode_terms(Config) when is_list(Config) ->
%% Decodes the floating point number 3.1415.
decode_float(Config) when is_list(Config) ->
- P = runner:start(?decode_float),
+ P = runner:start(Config, ?decode_float),
runner:send_term(P, 3.1415),
runner:recv_eot(P),
ok.
@@ -173,7 +177,7 @@ decode_float(Config) when is_list(Config) ->
%% Tests the erl_free_compound() function.
t_erl_free_compound(Config) when is_list(Config) ->
- runner:test(?t_erl_free_compound),
+ runner:test(Config, ?t_erl_free_compound),
ok.
@@ -186,7 +190,7 @@ t_erl_free_compound(Config) when is_list(Config) ->
%% This tests the erl_mk_list() function.
t_erl_mk_list(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_list),
+ P = runner:start(Config, ?t_erl_mk_list),
{term, []} = get_term(P),
{term, [abc]} = get_term(P),
@@ -200,7 +204,7 @@ t_erl_mk_list(Config) when is_list(Config) ->
%% This tests the erl_mk_int() function.
t_erl_mk_int(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_int),
+ P = runner:start(Config, ?t_erl_mk_int),
{term, 0} = get_term(P),
{term, 127} = get_term(P),
@@ -255,14 +259,14 @@ t_erl_mk_int(Config) when is_list(Config) ->
%% Basic test of erl_copy_term().
basic_copy(Config) when is_list(Config) ->
- runner:test(?basic_copy),
+ runner:test(Config, ?basic_copy),
ok.
%% This tests the erl_mk_tuple() function.
t_erl_mk_tuple(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_tuple),
+ P = runner:start(Config, ?t_erl_mk_tuple),
{term, {madonna, 21, 'mad donna', 12}} = get_term(P),
{term, {'Madonna',21,{children,{"Isabella",2}},
@@ -275,7 +279,7 @@ t_erl_mk_tuple(Config) when is_list(Config) ->
%% This tests the erl_mk_atom() function.
t_erl_mk_atom(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_atom),
+ P = runner:start(Config, ?t_erl_mk_atom),
{term, madonna} = (get_term(P)),
{term, 'Madonna'} = (get_term(P)),
@@ -295,7 +299,7 @@ t_erl_mk_atom(Config) when is_list(Config) ->
%% This tests the erl_mk_binary() function.
t_erl_mk_binary(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_binary),
+ P = runner:start(Config, ?t_erl_mk_binary),
{term, Bin} = (get_term(P)),
"{madonna,21,'mad donna',1234.567.890, !#$%&/()=?+-@, \" \\}" = binary_to_list(Bin),
@@ -307,7 +311,7 @@ t_erl_mk_binary(Config) when is_list(Config) ->
%% This tests the erl_mk_empty_list() function.
t_erl_mk_empty_list(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_empty_list),
+ P = runner:start(Config, ?t_erl_mk_empty_list),
{term, []} = get_term(P),
@@ -322,7 +326,7 @@ t_erl_mk_float(Config) when is_list(Config) ->
vxworks ->
{skipped, "Floating point numbers never compare equal on PPC"};
_ ->
- P = runner:start(?t_erl_mk_float),
+ P = runner:start(Config, ?t_erl_mk_float),
{term, {3.1415, 1.999999, 2.000000, 2.000001,
2.000002, 12345.67890}} = get_term(P),
runner:recv_eot(P),
@@ -333,7 +337,7 @@ t_erl_mk_float(Config) when is_list(Config) ->
%% This tests the erl_mk_pid() function.
t_erl_mk_pid(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_pid),
+ P = runner:start(Config, ?t_erl_mk_pid),
{term, A_pid} = (get_term(P)),
{pid, kalle@localhost, 3, 2} = nc2vinfo(A_pid),
@@ -342,7 +346,7 @@ t_erl_mk_pid(Config) when is_list(Config) ->
ok.
t_erl_mk_xpid(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_xpid),
+ P = runner:start(Config, ?t_erl_mk_xpid),
{term, A_pid} = (get_term(P)),
{pid, kalle@localhost, 32767, 8191} = nc2vinfo(A_pid),
@@ -354,7 +358,7 @@ t_erl_mk_xpid(Config) when is_list(Config) ->
%% This tests the erl_mk_port() function.
t_erl_mk_port(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_port),
+ P = runner:start(Config, ?t_erl_mk_port),
{term, A_port} = (get_term(P)),
{port, kalle@localhost, 4} = nc2vinfo(A_port),
@@ -363,7 +367,7 @@ t_erl_mk_port(Config) when is_list(Config) ->
ok.
t_erl_mk_xport(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_xport),
+ P = runner:start(Config, ?t_erl_mk_xport),
{term, A_port} = (get_term(P)),
{port, kalle@localhost, 268435455} = nc2vinfo(A_port),
@@ -375,7 +379,7 @@ t_erl_mk_xport(Config) when is_list(Config) ->
%% This tests the erl_mk_ref() function.
t_erl_mk_ref(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_ref),
+ P = runner:start(Config, ?t_erl_mk_ref),
{term, A_ref} = (get_term(P)),
{ref, kalle@localhost, _Length, [6]} = nc2vinfo(A_ref),
@@ -384,7 +388,7 @@ t_erl_mk_ref(Config) when is_list(Config) ->
ok.
t_erl_mk_long_ref(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_long_ref),
+ P = runner:start(Config, ?t_erl_mk_long_ref),
{term, A_ref} = (get_term(P)),
{ref, kalle@localhost, _Length, [4294967295,4294967295,262143]}
@@ -397,7 +401,7 @@ t_erl_mk_long_ref(Config) when is_list(Config) ->
%% This tests the erl_mk_string() function.
t_erl_mk_string(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_string),
+ P = runner:start(Config, ?t_erl_mk_string),
{term, "madonna"} = (get_term(P)),
{term, "Madonna"} = (get_term(P)),
@@ -417,7 +421,7 @@ t_erl_mk_string(Config) when is_list(Config) ->
%% This tests the erl_mk_estring() function.
t_erl_mk_estring(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_estring),
+ P = runner:start(Config, ?t_erl_mk_estring),
{term, "madonna"} = (get_term(P)),
{term, "Madonna"} = (get_term(P)),
@@ -437,7 +441,7 @@ t_erl_mk_estring(Config) when is_list(Config) ->
%% This tests the erl_mk_uint() function.
t_erl_mk_uint(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_uint),
+ P = runner:start(Config, ?t_erl_mk_uint),
{term, 54321} = (get_term(P)),
{term, 2147483647} = (get_term(P)),
@@ -453,7 +457,7 @@ t_erl_mk_uint(Config) when is_list(Config) ->
%% This tests the erl_mk_var() function.
t_erl_mk_var(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_var),
+ P = runner:start(Config, ?t_erl_mk_var),
{term, 1} = (get_term(P)),
{term, 0} = (get_term(P)),
@@ -470,7 +474,7 @@ t_erl_mk_var(Config) when is_list(Config) ->
%% This tests the erl_cons() function.
t_erl_cons(Config) when is_list(Config) ->
- P = runner:start(?t_erl_cons),
+ P = runner:start(Config, ?t_erl_cons),
{term, [madonna, 21]} = get_term(P),
@@ -490,7 +494,7 @@ t_erl_cons(Config) when is_list(Config) ->
%% Tests the erl_length() function.
t_erl_length(Config) when is_list(Config) ->
- P = runner:start(?t_erl_length),
+ P = runner:start(Config, ?t_erl_length),
0 = erl_length(P, []),
1 = erl_length(P, [a]),
@@ -513,7 +517,7 @@ erl_length(Port, List) ->
%% Tests the erl_hd() function.
t_erl_hd(Config) when is_list(Config) ->
- P = runner:start(?t_erl_hd),
+ P = runner:start(Config, ?t_erl_hd),
'NULL' = erl_hd(P, 42),
'NULL' = erl_hd(P, abc),
@@ -537,7 +541,7 @@ erl_hd(Port, List) ->
%% Tests the erl_tail() function.
t_erl_tl(Config) when is_list(Config) ->
- P = runner:start(?t_erl_tl),
+ P = runner:start(Config, ?t_erl_tl),
'NULL' = erl_tl(P, 42),
'NULL' = erl_tl(P, abc),
@@ -561,20 +565,20 @@ erl_tl(Port, List) ->
%% Tests the type checking macros (done in the C program).
type_checks(Config) when is_list(Config) ->
- runner:test(?type_checks),
+ runner:test(Config, ?type_checks),
ok.
%% Tests the extractor macros (done in the C program).
extractor_macros(Config) when is_list(Config) ->
- runner:test(?extractor_macros),
+ runner:test(Config, ?extractor_macros),
ok.
%% This tests the erl_size() function.
t_erl_size(Config) when is_list(Config) ->
- P = runner:start(?t_erl_size),
+ P = runner:start(Config, ?t_erl_size),
{term, 0} = (get_term(P)),
{term, 4} = (get_term(P)),
@@ -589,7 +593,7 @@ t_erl_size(Config) when is_list(Config) ->
%% This tests the erl_var_content() function.
t_erl_var_content(Config) when is_list(Config) ->
- P = runner:start(?t_erl_var_content),
+ P = runner:start(Config, ?t_erl_var_content),
{term, 17} = (get_term(P)),
{term, "http://www.madonna.com"} = (get_term(P)),
@@ -604,7 +608,7 @@ t_erl_var_content(Config) when is_list(Config) ->
%% This tests the erl_element() function.
t_erl_element(Config) when is_list(Config) ->
- P = runner:start(?t_erl_element),
+ P = runner:start(Config, ?t_erl_element),
{term, madonna} = get_term(P),
{term, 21} = get_term(P),
@@ -630,7 +634,7 @@ t_erl_element(Config) when is_list(Config) ->
%% Tests the erl_iolist_length() function.
t_erl_iolist_length(Config) when is_list(Config) ->
- P = runner:start(?t_erl_iolist_length),
+ P = runner:start(Config, ?t_erl_iolist_length),
%% Flat lists.
@@ -697,7 +701,7 @@ erl_iolist_length(Port, List) ->
%% Tests the erl_iolist_to_binary() function.
t_erl_iolist_to_binary(Config) when is_list(Config) ->
- P = runner:start(?t_erl_iolist_to_binary),
+ P = runner:start(Config, ?t_erl_iolist_to_binary),
%% Flat lists.
@@ -768,7 +772,7 @@ iolist_to_list(Port, Term) ->
%% Tests the erl_iolist_to_string() function.
t_erl_iolist_to_string(Config) when is_list(Config) ->
- P = runner:start(?t_erl_iolist_to_string),
+ P = runner:start(Config, ?t_erl_iolist_to_string),
%% Flat lists.
@@ -947,14 +951,14 @@ collect_line1([C|Rest], Result) ->
%% Test case submitted by Per Lundgren, ERV.
high_chaparal(Config) when is_list(Config) ->
- P = runner:start(?high_chaparal),
+ P = runner:start(Config, ?high_chaparal),
{term, [hello, world]} = get_term(P),
runner:recv_eot(P),
ok.
%% OTP-7448
broken_data(Config) when is_list(Config) ->
- P = runner:start(?broken_data),
+ P = runner:start(Config, ?broken_data),
runner:recv_eot(P),
ok.
diff --git a/lib/erl_interface/test/erl_eterm_SUITE_data/cnode.c b/lib/erl_interface/test/erl_eterm_SUITE_data/cnode.c
index bead0f8413..b87feb9dfc 100644
--- a/lib/erl_interface/test/erl_eterm_SUITE_data/cnode.c
+++ b/lib/erl_interface/test/erl_eterm_SUITE_data/cnode.c
@@ -20,7 +20,7 @@
#include <stdlib.h>
#include <stdio.h>
-
+#include <string.h>
#include "ei.h"
#include "erl_interface.h"
@@ -68,6 +68,7 @@ MAIN(int argc, char **argv)
char host[80];
int number;
ETERM *ref, *ref1, *ref2;
+ FILE *dfile = fopen("cnode_debug_printout", "w");
erl_init(NULL, 0);
@@ -80,28 +81,30 @@ MAIN(int argc, char **argv)
gethostname(host, sizeof(host));
sprintf(node, "c%d@%s", number, host);
- printf("s = %d\n", s);
+ fprintf(dfile, "s = %d\n", s); fflush(dfile);
sprintf(server, "test_server@%s", host);
fd = erl_connect(server);
- printf("fd = %d\n", fd);
+ fprintf(dfile, "fd = %d\n", fd);
-/* printf("dist = %d\n", erl_distversion(fd)); */
+/* fprintf(dfile, "dist = %d\n", erl_distversion(fd)); */
#if 1
ref = erl_mk_long_ref(node, 4711, 113, 98, 0);
#else
ref = erl_mk_ref(node, 4711, 0);
#endif
- printf("ref = %d\n", ref);
+ fprintf(dfile, "ref = %p\n", ref); fflush(dfile);
s = erl_reg_send(fd, "mip", ref);
- printf("s = %d\n", s);
+ fprintf(dfile, "s = %d\n", s); fflush(dfile);
{
ETERM* emsg;
emsg = SELF(fd);
- erl_reg_send(fd,"mip",emsg);
+ fprintf(dfile, "pid = %p\n", emsg); fflush(dfile);
+ s = erl_reg_send(fd,"mip",emsg);
+ fprintf(dfile, "s2 = %d\n", s); fflush(dfile);
erl_free_term(emsg);
}
@@ -116,28 +119,29 @@ MAIN(int argc, char **argv)
#endif
switch (s) {
case ERL_TICK:
- printf("tick\n");
+ fprintf(dfile, "tick\n");
break;
case ERL_ERROR:
- printf("error\n");
+ fprintf(dfile, "error: %s (%d)\n", strerror(erl_errno), erl_errno);
break;
case ERL_MSG:
- printf("msg %d\n", msgsize);
+ fprintf(dfile, "msg %d\n", msgsize);
break;
default:
- printf("unknown result %d\n", s);
+ fprintf(dfile, "unknown result %d\n", s);
break;
}
+ fflush(dfile);
} while (s == ERL_TICK);
s = erl_reg_send(fd, "mip", msg.msg);
- printf("s = %d\n", s);
+ fprintf(dfile, "s = %d\n", s); fflush(dfile);
s = erl_reg_send(fd, "mip", msg.to);
- printf("s = %d\n", s);
+ fprintf(dfile, "s = %d\n", s); fflush(dfile);
#if 0
/* from = NULL! */
s = erl_reg_send(fd, "mip", msg.from);
- printf("s = %d\n", s);
+ fprintf(dfile, "s = %d\n", s); fflush(dfile);
#endif
#if 0
@@ -150,17 +154,19 @@ MAIN(int argc, char **argv)
ref1 = erl_mk_long_ref(node, 4711, 113, 98, 0);
ref2 = erl_mk_ref(node, 4711, 0);
s = erl_encode(ref1, buf1);
- printf("enc1 s = %d\n", s);
+ fprintf(dfile, "enc1 s = %d\n", s); fflush(dfile);
s = erl_encode(ref2, buf2);
- printf("enc2 s = %d\n", s);
+ fprintf(dfile, "enc2 s = %d\n", s); fflush(dfile);
s = erl_compare_ext(buf1, buf2);
- printf("comp s = %d\n", s);
+ fprintf(dfile, "comp s = %d\n", s); fflush(dfile);
/* Compare, in another way */
s = erl_match(ref1, ref2);
- printf("match s = %d\n", s);
+ fprintf(dfile, "match s = %d\n", s); fflush(dfile);
#endif
+ fclose(dfile);
+
erl_close_connection(fd);
return 0;
diff --git a/lib/erl_interface/test/erl_ext_SUITE.erl b/lib/erl_interface/test/erl_ext_SUITE.erl
index afaba1fd93..ff3b495f7b 100644
--- a/lib/erl_interface/test/erl_ext_SUITE.erl
+++ b/lib/erl_interface/test/erl_ext_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
-include("erl_ext_SUITE_data/ext_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
compare_tuple/1,
compare_list/1,
compare_string/1,
@@ -40,28 +41,30 @@ all() ->
[compare_tuple, compare_list, compare_string,
compare_list_string, compare_nc_ext].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
compare_tuple(Config) when is_list(Config) ->
- P = runner:start(?compare_tuple),
+ P = runner:start(Config, ?compare_tuple),
runner:recv_eot(P),
ok.
compare_list(Config) when is_list(Config) ->
- P = runner:start(?compare_list),
+ P = runner:start(Config, ?compare_list),
runner:recv_eot(P),
ok.
compare_string(Config) when is_list(Config) ->
- P = runner:start(?compare_string),
+ P = runner:start(Config, ?compare_string),
runner:recv_eot(P),
ok.
compare_list_string(Config) when is_list(Config) ->
- P = runner:start(?compare_list_string),
+ P = runner:start(Config, ?compare_list_string),
runner:recv_eot(P),
ok.
compare_nc_ext(Config) when is_list(Config) ->
- P = runner:start(?compare_nc_ext),
+ P = runner:start(Config, ?compare_nc_ext),
runner:recv_eot(P),
ok.
diff --git a/lib/erl_interface/test/erl_ext_SUITE_data/ext_test.c b/lib/erl_interface/test/erl_ext_SUITE_data/ext_test.c
index 1e986feacf..6b47c3e510 100644
--- a/lib/erl_interface/test/erl_ext_SUITE_data/ext_test.c
+++ b/lib/erl_interface/test/erl_ext_SUITE_data/ext_test.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2002-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2002-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -88,6 +88,11 @@ TESTCASE(compare_list) {
// erlang:term_to_binary([0, 1000])
unsigned char term4[] = {131,108,0,0,0,2,97,0,98,0,0,3,232,106};
+ // erlang:term_to_binary([a|b])
+ unsigned char term5a[] = {131,108,0,0,0,1,100,0,1,97,100,0,1,98};
+ // erlang:term_to_binary([a|c])
+ unsigned char term5b[] = {131,108,0,0,0,1,100,0,1,97,100,0,1,99};
+
erl_init(NULL, 0);
start_a = term1;
start_b = term2;
@@ -103,6 +108,13 @@ TESTCASE(compare_list) {
test_compare_ext("lists1", start_a, end_a, start_b, end_b, -1);
+ start_a = term5a;
+ start_b = term5b;
+ end_a = term5a + sizeof(term5a);
+ end_b = term5b + sizeof(term5b);
+
+ test_compare_ext("lists5", start_a, end_a, start_b, end_b, -1);
+
report(1);
}
diff --git a/lib/erl_interface/test/erl_format_SUITE.erl b/lib/erl_interface/test/erl_format_SUITE.erl
index c1a7d8377e..69dfdcc4c8 100644
--- a/lib/erl_interface/test/erl_format_SUITE.erl
+++ b/lib/erl_interface/test/erl_format_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
-include("erl_format_SUITE_data/format_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
atoms/1, tuples/1, lists/1]).
-import(runner, [get_term/1]).
@@ -38,10 +39,13 @@ suite() ->
all() ->
[atoms, tuples, lists].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
%% Tests formatting various atoms.
atoms(Config) when is_list(Config) ->
- P = runner:start(?atoms),
+ P = runner:start(Config, ?atoms),
{term, ''} = get_term(P),
{term, 'a'} = get_term(P),
@@ -79,7 +83,7 @@ atoms(Config) when is_list(Config) ->
%% Tests formatting various tuples
tuples(Config) when is_list(Config) ->
- P = runner:start(?tuples),
+ P = runner:start(Config, ?tuples),
{term, {}} = get_term(P),
{term, {a}} = get_term(P),
@@ -100,7 +104,7 @@ tuples(Config) when is_list(Config) ->
%% Tests formatting various lists
lists(Config) when is_list(Config) ->
- P = runner:start(?lists),
+ P = runner:start(Config, ?lists),
{term, []} = get_term(P),
{term, [a]} = get_term(P),
diff --git a/lib/erl_interface/test/erl_global_SUITE.erl b/lib/erl_interface/test/erl_global_SUITE.erl
index ecc6753c7f..6d3a75c8d7 100644
--- a/lib/erl_interface/test/erl_global_SUITE.erl
+++ b/lib/erl_interface/test/erl_global_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
-include("erl_global_SUITE_data/erl_global_test_cases.hrl").
-export([all/0,suite/0,
+ init_per_testcase/2,
erl_global_registration/1,
erl_global_whereis/1, erl_global_names/1]).
@@ -39,9 +40,11 @@ suite() ->
[{ct_hooks,[ts_install_cth]},
{timetrap, {seconds, 30}}].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
erl_global_registration(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
{ok, Fd} = erl_connect(P, node(), 42, erlang:get_cookie(), 0),
ok = erl_global_register(P, Fd, ?GLOBAL_NAME),
@@ -53,7 +56,7 @@ erl_global_registration(Config) when is_list(Config) ->
ok.
erl_global_whereis(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
{ok, Fd} = erl_connect(P, node(), 42, erlang:get_cookie(), 0),
Self = self(),
@@ -66,7 +69,7 @@ erl_global_whereis(Config) when is_list(Config) ->
ok.
erl_global_names(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
{ok, Fd} = erl_connect(P, node(), 42, erlang:get_cookie(), 0),
Self = self(),
diff --git a/lib/erl_interface/test/erl_match_SUITE.erl b/lib/erl_interface/test/erl_match_SUITE.erl
index 5566714092..bb62d6288d 100644
--- a/lib/erl_interface/test/erl_match_SUITE.erl
+++ b/lib/erl_interface/test/erl_match_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
-include("erl_match_SUITE_data/match_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
atoms/1, lists/1, tuples/1, references/1, pids/1, ports/1,
bind/1, integers/1, floats/1, binaries/1, strings/1]).
@@ -40,6 +41,8 @@ all() ->
[atoms, lists, tuples, references, pids, ports, bind,
integers, floats, binaries, strings].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
atoms(Config) when is_list(Config) ->
P = start_matcher(Config),
@@ -239,7 +242,7 @@ bind(Config) when is_list(Config) ->
ok.
start_bind(Config) ->
- runner:start(?erl_match_bind).
+ runner:start(Config, ?erl_match_bind).
bind_ok(Port, Bind, Term) ->
true = erl_bind(Port, Bind, Term).
@@ -258,7 +261,7 @@ erl_bind(Port, Pattern, Term) ->
start_matcher(Config) ->
- runner:start(?erl_match_server).
+ runner:start(Config, ?erl_match_server).
eq(Port, Pattern, Term) ->
true = erl_match(Port, Pattern, Term).
diff --git a/lib/erl_interface/test/port_call_SUITE.erl b/lib/erl_interface/test/port_call_SUITE.erl
index fb10bd895f..5c4f5f3cee 100644
--- a/lib/erl_interface/test/port_call_SUITE.erl
+++ b/lib/erl_interface/test/port_call_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,7 +32,9 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--export([all/0, suite/0, basic/1]).
+-export([all/0, suite/0,
+ init_per_testcase/2,
+ basic/1]).
% Private exports
-include_lib("common_test/include/ct.hrl").
@@ -44,6 +46,8 @@ suite() ->
all() ->
[basic].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
basic(Config) when is_list(Config) ->
case os:type() of
diff --git a/lib/erl_interface/test/runner.erl b/lib/erl_interface/test/runner.erl
index 1084eec2a3..484890006e 100644
--- a/lib/erl_interface/test/runner.erl
+++ b/lib/erl_interface/test/runner.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,8 +21,9 @@
%%
-module(runner).
--export([test/1, test/2,
- start/1, send_term/2, finish/1, send_eot/1, recv_eot/1,
+-export([test/2, test/3,
+ init_per_testcase/3,
+ start/2, send_term/2, finish/1, send_eot/1, recv_eot/1,
get_term/1, get_term/2]).
-define(default_timeout, 5000).
@@ -32,11 +33,11 @@
%% This function is useful for test cases written in C which requires
%% no further input, and only returns a result by calling report().
-test(Tc) ->
- test(Tc, ?default_timeout).
+test(Config, Tc) ->
+ test(Config, Tc, ?default_timeout).
-test(Tc, Timeout) ->
- Port = start(Tc),
+test(Config, Tc, Timeout) ->
+ Port = start(Config, Tc),
case get_term(Port, Timeout) of
eot ->
@@ -54,12 +55,51 @@ test(Tc, Timeout) ->
%%
%% Returns: {ok, Port}
-start({Prog, Tc}) when is_list(Prog), is_integer(Tc) ->
- Port = open_port({spawn, Prog}, [{packet, 4}, exit_status]),
+start(Config, {Prog, Tc}) when is_list(Prog), is_integer(Tc) ->
+ Port = open_port({spawn, prog_cmd(Config, Prog)},
+ [{packet, 4}, exit_status]),
Command = [Tc div 256, Tc rem 256],
Port ! {self(), {command, Command}},
Port.
+prog_cmd(Config, Prog) ->
+ case proplists:get_value(valgrind_cmd_fun, Config) of
+ undefined ->
+ Prog;
+ Fun when is_function(Fun) ->
+ Fun(Prog)
+ end.
+
+init_per_testcase(Suite, Case, Config) ->
+ case os:getenv("VALGRIND_LOG_DIR") of
+ false ->
+ Config;
+ LogDir ->
+ Valgrind = case os:find_executable("valgrind") of
+ false ->
+ ct:fail("VALGRIND_LOG_DIR set, "
+ "but no valgrind executable found");
+ VG -> VG
+ end,
+
+ LogFileOpt = case os:getenv("VALGRIND_LOG_XML") of
+ false ->
+ " --log-file=";
+ "yes" ->
+ " --xml=yes --xml-file="
+ end,
+ Fun = fun(Prog) ->
+ LogFile = io_lib:format("erl_interface-~w.~w-~s.log.%p",
+ [Suite, Case, filename:basename(Prog)]),
+ Valgrind
+ ++ LogFileOpt ++ filename:join(LogDir,LogFile)
+ ++ " " ++ os:getenv("VALGRIND_MISC_FLAGS","")
+ ++ " " ++ Prog
+ end,
+ [{valgrind_cmd_fun, Fun} | Config]
+ end.
+
+
%% Finishes a test case by send an 'eot' message to the C program
%% and waiting for an 'eot'.
%%
@@ -67,7 +107,12 @@ start({Prog, Tc}) when is_list(Prog), is_integer(Tc) ->
finish(Port) when is_port(Port) ->
send_eot(Port),
- recv_eot(Port).
+ ok = recv_eot(Port),
+ 0 = receive
+ {Port,{exit_status,Status}} ->
+ Status
+ end,
+ ok.
%% Sends an Erlang term to a C program.
diff --git a/lib/erl_interface/vsn.mk b/lib/erl_interface/vsn.mk
index d76d110afd..cc72ed639a 100644
--- a/lib/erl_interface/vsn.mk
+++ b/lib/erl_interface/vsn.mk
@@ -1,2 +1,2 @@
-EI_VSN = 3.10.1
+EI_VSN = 3.12
ERL_INTERFACE_VSN = $(EI_VSN)
diff --git a/lib/et/doc/src/Makefile b/lib/et/doc/src/Makefile
index 0257a8f817..93e2f8eeee 100644
--- a/lib/et/doc/src/Makefile
+++ b/lib/et/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2002-2016. All Rights Reserved.
+# Copyright Ericsson AB 2002-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -45,8 +45,11 @@ include files.mk
XML_FILES = $(BOOK_FILES) $(XML_APPLICATION_FILES) $(XML_REF3_FILES) \
$(XML_PART_FILES) $(XML_CHAPTER_FILES)
+XML_GEN_FILES = $(GEN_XML:%=$(XMLDIR)/%)
+
HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \
- $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html)
+ $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html) \
+ $(GEN_XML:%.xml=$(HTMLDIR)/%.html)
INFO_FILE = ../../info
@@ -82,6 +85,7 @@ clean clean_docs:
fi \
done
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/lib/et/doc/src/et.xml b/lib/et/doc/src/et.xml
index 3009b559e1..a362d00b3e 100644
--- a/lib/et/doc/src/et.xml
+++ b/lib/et/doc/src/et.xml
@@ -32,14 +32,14 @@
<rev>%VSN%</rev>
<file>et</file>
</header>
- <module>et</module>
+ <module since="">et</module>
<modulesummary>Main API of the Event Trace (ET) application</modulesummary>
<description>
<p>Interface module for the Event Trace (ET) application</p>
</description>
<funcs>
<func>
- <name>trace_me(DetailLevel, From, To, Label, Contents) -> hopefully_traced</name>
+ <name since="OTP R13B04">trace_me(DetailLevel, From, To, Label, Contents) -> hopefully_traced</name>
<fsummary>A function that is intended to be traced.</fsummary>
<type>
<v>DetailLevel = integer(X) when X =&lt; 0, X >= 100</v>
@@ -70,7 +70,7 @@
</func>
<func>
- <name>trace_me(DetailLevel, FromTo, Label, Contents) -> hopefully_traced</name>
+ <name since="OTP R13B04">trace_me(DetailLevel, FromTo, Label, Contents) -> hopefully_traced</name>
<fsummary>A function that is intended to be traced.</fsummary>
<desc>
<p>Invokes <c>et:trace_me/5</c> with both <c>From</c> and <c>To</c>
@@ -79,8 +79,8 @@
</func>
<func>
- <name>phone_home(DetailLevel, FromTo, Label, Contents) -> hopefully_traced</name>
- <name>phone_home(DetailLevel, From, To, Label, Contents) -> hopefully_traced</name>
+ <name since="">phone_home(DetailLevel, FromTo, Label, Contents) -> hopefully_traced</name>
+ <name since="">phone_home(DetailLevel, From, To, Label, Contents) -> hopefully_traced</name>
<fsummary>Send a signal to the outer space</fsummary>
<desc>
<p>These functions sends a signal to the outer space and the
@@ -90,8 +90,8 @@
</desc>
</func>
<func>
- <name>report_event(DetailLevel, FromTo, Label, Contents) -> hopefully_traced</name>
- <name>report_event(DetailLevel, From, To, Label, Contents) -> hopefully_traced</name>
+ <name since="">report_event(DetailLevel, FromTo, Label, Contents) -> hopefully_traced</name>
+ <name since="">report_event(DetailLevel, From, To, Label, Contents) -> hopefully_traced</name>
<fsummary>Deprecated functions</fsummary>
<desc>
<p>Deprecated functions which for the time being are kept for
diff --git a/lib/et/doc/src/et_collector.xml b/lib/et/doc/src/et_collector.xml
index 6a85b81ec2..f908612797 100644
--- a/lib/et/doc/src/et_collector.xml
+++ b/lib/et/doc/src/et_collector.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2002</year><year>2016</year>
+ <year>2002</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,21 +32,22 @@
<rev>%VSN%</rev>
<file>et_collector.xml</file>
</header>
- <module>et_collector</module>
+ <module since="">et_collector</module>
<modulesummary>Collect trace events and provide a backing storage appropriate for iteration </modulesummary>
<description>
<p>Interface module for the Event Trace (ET) application</p>
</description>
<funcs>
<func>
- <name>start_link(Options) -> {ok, CollectorPid} | {error, Reason}</name>
+ <name since="">start_link(Options) -> {ok, CollectorPid} | {error, Reason}</name>
<fsummary>Start a collector process</fsummary>
<type>
<v>Options = [option()]</v>
<v>option() = {parent_pid, pid()} | {event_order, event_order()} | {dict_insert, {filter, collector}, collector_fun()} | {dict_insert, {filter, event_filter_name()}, event_filter_fun()} | {dict_insert, {subscriber, pid()}, dict_val()} | {dict_insert, dict_key(), dict_val()} | {dict_delete, dict_key()} | {trace_client, trace_client()} | {trace_global, boolean()} | {trace_pattern, trace_pattern()} | {trace_port, integer()} | {trace_max_queue, integer()}</v>
<v>event_order() = trace_ts | event_ts</v>
<v>trace_pattern() = {report_module(), extended_dbg_match_spec()} | undefined</v>
- <v>report_module() = atom() | undefined &lt;v>extended_dbg_match_spec()() = detail_level() | dbg_match_spec()</v>
+ <v>report_module() = atom() | undefined</v>
+ <v>extended_dbg_match_spec() = detail_level() | dbg_match_spec()</v>
<v>detail_level() = min | max | integer(X) when X =&lt; 0, X >= 100</v>
<v>trace_client() = {event_file, file_name()} | {dbg_trace_type(), dbg_trace_parameters()}</v>
<v>file_name() = string()</v>
@@ -104,7 +105,7 @@
</desc>
</func>
<func>
- <name>stop(CollectorPid) -> ok</name>
+ <name since="">stop(CollectorPid) -> ok</name>
<fsummary>Stop a collector process</fsummary>
<type>
<v>CollectorPid = pid()</v>
@@ -114,7 +115,7 @@
</desc>
</func>
<func>
- <name>save_event_file(CollectorPid, FileName, Options) -> ok | {error, Reason}</name>
+ <name since="">save_event_file(CollectorPid, FileName, Options) -> ok | {error, Reason}</name>
<fsummary>Save the events to a file</fsummary>
<type>
<v>CollectorPid = pid()</v>
@@ -138,7 +139,7 @@
</desc>
</func>
<func>
- <name>load_event_file(CollectorPid, FileName) -> {ok, BadBytes} | exit(Reason)</name>
+ <name since="">load_event_file(CollectorPid, FileName) -> {ok, BadBytes} | exit(Reason)</name>
<fsummary>Load the event table from a file</fsummary>
<type>
<v>CollectorPid = pid()</v>
@@ -151,9 +152,9 @@
</desc>
</func>
<func>
- <name>report(Handle, TraceOrEvent) -> {ok, Continuation} | exit(Reason)</name>
- <name>report_event(Handle, DetailLevel, FromTo, Label, Contents) -> {ok, Continuation} | exit(Reason)</name>
- <name>report_event(Handle, DetailLevel, From, To, Label, Contents) -> {ok, Continuation} | exit(Reason)</name>
+ <name since="">report(Handle, TraceOrEvent) -> {ok, Continuation} | exit(Reason)</name>
+ <name since="">report_event(Handle, DetailLevel, FromTo, Label, Contents) -> {ok, Continuation} | exit(Reason)</name>
+ <name since="">report_event(Handle, DetailLevel, From, To, Label, Contents) -> {ok, Continuation} | exit(Reason)</name>
<fsummary>Report an event to the collector</fsummary>
<type>
<v>Handle = Initial | Continuation</v>
@@ -180,7 +181,7 @@
</desc>
</func>
<func>
- <name>make_key(Type, Stuff) -> Key</name>
+ <name since="">make_key(Type, Stuff) -> Key</name>
<fsummary>Make a key out of an event record or an old key</fsummary>
<type>
<v>Type = record(table_handle) | trace_ts | event_ts</v>
@@ -192,7 +193,7 @@
</desc>
</func>
<func>
- <name>get_table_handle(CollectorPid) -> Handle</name>
+ <name since="">get_table_handle(CollectorPid) -> Handle</name>
<fsummary>Return a table handle</fsummary>
<type>
<v>CollectorPid = pid()</v>
@@ -203,7 +204,7 @@
</desc>
</func>
<func>
- <name>get_global_pid() -> CollectorPid | exit(Reason)</name>
+ <name since="">get_global_pid() -> CollectorPid | exit(Reason)</name>
<fsummary>Return a the identity of the globally registered collector if there is any</fsummary>
<type>
<v>CollectorPid = pid()</v>
@@ -215,13 +216,13 @@
</desc>
</func>
<func>
- <name>change_pattern(CollectorPid, RawPattern) -> {old_pattern, TracePattern}</name>
+ <name since="">change_pattern(CollectorPid, RawPattern) -> {old_pattern, TracePattern}</name>
<fsummary>Change active trace pattern globally on all trace nodes</fsummary>
<type>
<v>CollectorPid = pid()</v>
<v>RawPattern = {report_module(), extended_dbg_match_spec()}</v>
<v>report_module() = atom() | undefined</v>
- <v>extended_dbg_match_spec()() = detail_level() | dbg_match_spec()</v>
+ <v>extended_dbg_match_spec() = detail_level() | dbg_match_spec()</v>
<v>RawPattern = detail_level()</v>
<v>detail_level() = min | max | integer(X) when X =&lt; 0, X >= 100</v>
<v>TracePattern = {report_module(), dbg_match_spec_match_spec()}</v>
@@ -231,9 +232,9 @@
</desc>
</func>
<func>
- <name>dict_insert(CollectorPid, {filter, collector}, FilterFun) -> ok</name>
- <name>dict_insert(CollectorPid, {subscriber, SubscriberPid}, Void) -> ok</name>
- <name>dict_insert(CollectorPid, Key, Val) -> ok</name>
+ <name since="">dict_insert(CollectorPid, {filter, collector}, FilterFun) -> ok</name>
+ <name since="">dict_insert(CollectorPid, {subscriber, SubscriberPid}, Void) -> ok</name>
+ <name since="">dict_insert(CollectorPid, Key, Val) -> ok</name>
<fsummary>Insert a dictionary entry and send a {et, {dict_insert, Key, Val}} tuple to all registered subscribers.</fsummary>
<type>
<v>CollectorPid = pid()</v>
@@ -258,7 +259,7 @@
</desc>
</func>
<func>
- <name>dict_lookup(CollectorPid, Key) -> [Val]</name>
+ <name since="">dict_lookup(CollectorPid, Key) -> [Val]</name>
<fsummary>Lookup a dictionary entry and return zero or one value</fsummary>
<type>
<v>CollectorPid = pid()</v>
@@ -272,7 +273,7 @@
</desc>
</func>
<func>
- <name>dict_delete(CollectorPid, Key) -> ok</name>
+ <name since="">dict_delete(CollectorPid, Key) -> ok</name>
<fsummary>Delete a dictionary entry and send a {et, {dict_delete, Key}} tuple to all registered subscribers.</fsummary>
<type>
<v>CollectorPid = pid()</v>
@@ -289,7 +290,7 @@
</desc>
</func>
<func>
- <name>dict_match(CollectorPid, Pattern) -> [Match]</name>
+ <name since="">dict_match(CollectorPid, Pattern) -> [Match]</name>
<fsummary>Match some dictionary entries</fsummary>
<type>
<v>CollectorPid = pid()</v>
@@ -305,7 +306,7 @@
</desc>
</func>
<func>
- <name>multicast(_CollectorPid, Msg) -> ok</name>
+ <name since="">multicast(_CollectorPid, Msg) -> ok</name>
<fsummary>Sends a message to all registered subscribers</fsummary>
<type>
<v>CollectorPid = pid()</v>
@@ -317,7 +318,7 @@
</desc>
</func>
<func>
- <name>start_trace_client(CollectorPid, Type, Parameters) -> file_loaded | {trace_client_pid, pid()} | exit(Reason)</name>
+ <name since="">start_trace_client(CollectorPid, Type, Parameters) -> file_loaded | {trace_client_pid, pid()} | exit(Reason)</name>
<fsummary>Load raw Erlang trace from a file, port or process.</fsummary>
<type>
<v>Type = dbg_trace_client_type()</v>
@@ -329,14 +330,14 @@
</desc>
</func>
<func>
- <name>iterate(Handle, Prev, Limit) -> NewAcc</name>
+ <name since="">iterate(Handle, Prev, Limit) -> NewAcc</name>
<fsummary>Iterates over the currently stored events</fsummary>
<desc>
<p>Short for iterate(Handle, Prev, Limit, undefined, Prev) -&gt; NewAcc</p>
</desc>
</func>
<func>
- <name>iterate(Handle, Prev, Limit, Fun, Acc) -> NewAcc</name>
+ <name since="">iterate(Handle, Prev, Limit, Fun, Acc) -> NewAcc</name>
<fsummary>Iterate over the currently stored events</fsummary>
<type>
<v>Handle = collector_pid() | table_handle()</v>
@@ -348,7 +349,8 @@
<v>done() = 0</v>
<v>forward() = infinity | integer(X) where X > 0</v>
<v>backward() = '-infinity' | integer(X) where X &lt; 0</v>
- <v>Fun = fun(Event, Acc) -> NewAcc &lt;v>Acc = NewAcc = term()</v>
+ <v>Fun = fun(Event, Acc) -> NewAcc</v>
+ <v>Acc = NewAcc = term()</v>
</type>
<desc>
<p>Iterate over the currently stored events.</p>
@@ -359,7 +361,7 @@
</desc>
</func>
<func>
- <name>clear_table(Handle) -> ok</name>
+ <name since="">clear_table(Handle) -> ok</name>
<fsummary>Clear the event table</fsummary>
<type>
<v>Handle = collector_pid() | table_handle()</v>
diff --git a/lib/et/doc/src/et_selector.xml b/lib/et/doc/src/et_selector.xml
index 441a4dd278..3c766cafb7 100644
--- a/lib/et/doc/src/et_selector.xml
+++ b/lib/et/doc/src/et_selector.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2002</year><year>2016</year>
+ <year>2002</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,7 +32,7 @@
<rev>%VSN%</rev>
<file>et_selector.xml</file>
</header>
- <module>et_selector</module>
+ <module since="">et_selector</module>
<modulesummary>Define event transforms and trace patterns</modulesummary>
<description>
<p></p>
@@ -40,7 +40,7 @@
<funcs>
<func>
- <name>make_pattern(RawPattern) -> TracePattern</name>
+ <name since="">make_pattern(RawPattern) -> TracePattern</name>
<fsummary>Makes a trace pattern suitable to feed change_pattern/1</fsummary>
<type>
@@ -61,7 +61,7 @@
</func>
<func>
- <name>change_pattern(Pattern) -> ok</name>
+ <name since="">change_pattern(Pattern) -> ok</name>
<fsummary>Activates/deactivates tracing by changing the current trace pattern</fsummary>
@@ -85,12 +85,14 @@
</desc>
</func>
<func>
- <name>parse_event(Mod, ValidTraceData) -> false | true | {true, Event}</name>
+ <name since="">parse_event(Mod, ValidTraceData) -> false | true | {true, Event}</name>
<fsummary>Transforms trace data and makes an event record out of it</fsummary>
<type>
- <v>Mod = module_name() | undefined &lt;v>module_name() = atom() &lt;v>ValidTraceData = erlang_trace_data() | record(event)</v>
+ <v>Mod = module_name() | undefined</v>
+ <v>module_name() = atom()</v>
+ <v>ValidTraceData = erlang_trace_data() | record(event)</v>
<v>erlang_trace_data() = {trace, Pid, Label, Info} | {trace, Pid, Label, Info, Extra} | {trace_ts, Pid, Label, Info, ReportedTS} | {trace_ts, Pid, Label, Info, Extra, ReportedTS} | {seq_trace, Label, Info} | {seq_trace, Label, Info, ReportedTS} | {drop, NumberOfDroppedItems}</v>
</type>
diff --git a/lib/et/doc/src/et_viewer.xml b/lib/et/doc/src/et_viewer.xml
index e0b39636e9..9d59eef668 100644
--- a/lib/et/doc/src/et_viewer.xml
+++ b/lib/et/doc/src/et_viewer.xml
@@ -32,14 +32,14 @@
<rev>%VSN%</rev>
<file>et_viewer.xml</file>
</header>
- <module>et_viewer</module>
+ <module since="">et_viewer</module>
<modulesummary>Displays a sequence chart for trace events (messages/actions)</modulesummary>
<description>
<p></p>
</description>
<funcs>
<func>
- <name>file(FileName) -> {ok, ViewerPid} | {error, Reason}</name>
+ <name since="">file(FileName) -> {ok, ViewerPid} | {error, Reason}</name>
<fsummary>Start a new event viewer and a corresponding collector and load them with trace events from a trace file.</fsummary>
<type>
<v>FileName() = string()</v>
@@ -52,7 +52,7 @@
</desc>
</func>
<func>
- <name>start() -> ok</name>
+ <name since="">start() -> ok</name>
<fsummary>Simplified start of a sequence chart viewer with global tracing activated.</fsummary>
<desc>
<p>Simplified start of a sequence chart viewer with
@@ -62,7 +62,7 @@
</desc>
</func>
<func>
- <name>start(Options) -> ok</name>
+ <name since="">start(Options) -> ok</name>
<fsummary>Start of a sequence chart viewer without linking to the parent process.</fsummary>
<desc>
<p>Start of a sequence chart viewer without linking
@@ -70,7 +70,7 @@
</desc>
</func>
<func>
- <name>start_link(Options) -> {ok, ViewerPid} | {error, Reason}</name>
+ <name since="">start_link(Options) -> {ok, ViewerPid} | {error, Reason}</name>
<fsummary>Start a sequence chart viewer for trace events (messages/actions)</fsummary>
<type>
<v>Options = [option() | collector_option()]</v>
@@ -125,7 +125,7 @@
</desc>
</func>
<func>
- <name>get_collector_pid(ViewerPid) -> CollectorPid</name>
+ <name since="">get_collector_pid(ViewerPid) -> CollectorPid</name>
<fsummary>Returns the identifier of the collector process</fsummary>
<type>
<v>ViewerPid = pid()</v>
@@ -136,7 +136,7 @@
</desc>
</func>
<func>
- <name>stop(ViewerPid) -> ok</name>
+ <name since="">stop(ViewerPid) -> ok</name>
<fsummary>Stops a viewer</fsummary>
<type>
<v>ViewerPid = pid()</v>
diff --git a/lib/et/doc/src/files.mk b/lib/et/doc/src/files.mk
index e0ea9b0b76..c9041caa81 100644
--- a/lib/et/doc/src/files.mk
+++ b/lib/et/doc/src/files.mk
@@ -1,7 +1,7 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2002-2016. All Rights Reserved.
+# Copyright Ericsson AB 2002-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -31,10 +31,13 @@ XML_PART_FILES = \
XML_CHAPTER_FILES = \
et_intro.xml \
+ notes.xml
+
+GEN_XML = \
et_tutorial.xml \
et_desc.xml \
- et_examples.xml \
- notes.xml
+ et_examples.xml
+
BOOK_FILES = book.xml
diff --git a/lib/et/doc/src/notes.xml b/lib/et/doc/src/notes.xml
index f0995b7c19..e144defb69 100644
--- a/lib/et/doc/src/notes.xml
+++ b/lib/et/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2002</year><year>2016</year>
+ <year>2002</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -37,6 +37,53 @@
one section in this document. The title of each section is the
version number of <c>Event Tracer (ET)</c>.</p>
+<section><title>ET 1.6.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The scroll bar of the et_viewer window could not be
+ dragged all the way to the top of the window. It would
+ always stop at the second event. This is now corrected.</p>
+ <p>
+ Own Id: OTP-15463 Aux Id: ERL-780 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>ET 1.6.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>ET 1.6.2</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> Calls to <c>erlang:get_stacktrace()</c> are removed.
+ </p>
+ <p>
+ Own Id: OTP-14861</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>ET 1.6.1</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/et/src/et.app.src b/lib/et/src/et.app.src
index f4e32f734d..8cea1ba842 100644
--- a/lib/et/src/et.app.src
+++ b/lib/et/src/et.app.src
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/et/src/et_collector.erl b/lib/et/src/et_collector.erl
index b0f016a8ea..3609238509 100644
--- a/lib/et/src/et_collector.erl
+++ b/lib/et/src/et_collector.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -509,7 +509,7 @@ get_global_pid() ->
%% CollectorPid = pid()
%% RawPattern = {report_module(), extended_dbg_match_spec()}
%% report_module() = atom() | undefined
-%% extended_dbg_match_spec()() = detail_level() | dbg_match_spec()
+%% extended_dbg_match_spec() = detail_level() | dbg_match_spec()
%% RawPattern = detail_level()
%% detail_level() = min | max | integer(X) when X =< 0, X >= 100
%% TracePattern = {report_module(), dbg_match_spec_match_spec()}
@@ -1135,7 +1135,7 @@ handle_info(Info, S) ->
noreply(S).
listen_on_trace_port(Node, Port, S) ->
- [_Name, Host] = string:tokens(atom_to_list(Node), [$@]),
+ [_Name, Host] = string:lexemes(atom_to_list(Node), [$@]),
case catch start_trace_client(self(), ip, {Host, Port}) of
{trace_client_pid, RemotePid} ->
rpc:call(Node, et_selector, change_pattern, [S#state.trace_pattern]),
diff --git a/lib/et/src/et_wx_contents_viewer.erl b/lib/et/src/et_wx_contents_viewer.erl
index bca517317e..580c921139 100644
--- a/lib/et/src/et_wx_contents_viewer.erl
+++ b/lib/et/src/et_wx_contents_viewer.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -93,8 +93,8 @@ start_link(Options) ->
end,
{ok, Pid}
catch
- error:Reason ->
- {error, {'EXIT', Reason, erlang:get_stacktrace()}}
+ error:Reason:Stacktrace ->
+ {error, {'EXIT', Reason, Stacktrace}}
end;
{error, Reason} ->
{error, Reason}
diff --git a/lib/et/src/et_wx_viewer.erl b/lib/et/src/et_wx_viewer.erl
index 4dd44e7a4c..041527fec4 100644
--- a/lib/et/src/et_wx_viewer.erl
+++ b/lib/et/src/et_wx_viewer.erl
@@ -793,8 +793,8 @@ handle_info(#wx{event = #wxScroll{type = scroll_changed}} = Wx, S) ->
N = round(S#state.n_events * Pos / Range),
Diff =
case N - event_pos(S) of
- D when D < 0 -> D - 1;
- D -> D + 1
+ D when D < 0 -> D;
+ D -> D
end,
S2 = scroll_changed(S, Diff),
noreply(S2);
@@ -1002,7 +1002,7 @@ scroll_changed(S, Expected) ->
scroll_first(S);
last ->
scroll_last(S)
- end;
+ end;
true ->
%% Down
OldPos = event_pos(S),
@@ -1018,19 +1018,24 @@ scroll_changed(S, Expected) ->
end.
jump_up(S, OldKey, OldPos, NewPos) ->
- Try = NewPos - OldPos,
+ Try = NewPos - OldPos -1,
Order = S#state.event_order,
- Fun = fun(Event, #e{pos = P}) when P >= NewPos ->
- Key = et_collector:make_key(Order, Event),
- #e{event = Event, key = Key, pos = P - 1};
- (_, Acc) ->
- Acc
- end,
- PrevE = et_collector:iterate(S#state.collector_pid,
- OldKey,
- Try,
- Fun,
- #e{key = OldKey, pos = OldPos}),
+ PrevE =
+ if NewPos =:= 0 ->
+ first;
+ true ->
+ Fun = fun(Event, #e{pos = P}) when P >= NewPos ->
+ Key = et_collector:make_key(Order, Event),
+ #e{event = Event, key = Key, pos = P - 1};
+ (_E, Acc) ->
+ Acc
+ end,
+ et_collector:iterate(S#state.collector_pid,
+ OldKey,
+ Try,
+ Fun,
+ #e{key = OldKey, pos = OldPos})
+ end,
case collect_more_events(S, PrevE, S#state.events_per_page) of
{_, []} ->
S;
@@ -2013,7 +2018,7 @@ update_scroll_bar(#state{scroll_bar = ScrollBar,
PixelsPerEvent = Range / EventsPerPage,
Share = EventsPerPage / N,
wxScrollBar:setScrollbar(ScrollBar,
- trunc(EventPos * Share * PixelsPerEvent),
+ trunc(EventPos * Share * PixelsPerEvent),
round(Share * Range),
Range,
round(Share * Range),
diff --git a/lib/et/test/et_test_lib.erl b/lib/et/test/et_test_lib.erl
index fc469f646a..4addcd7ca8 100644
--- a/lib/et/test/et_test_lib.erl
+++ b/lib/et/test/et_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/et/test/ett.erl b/lib/et/test/ett.erl
index 2b276eab1a..dd274ec317 100644
--- a/lib/et/test/ett.erl
+++ b/lib/et/test/ett.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/et/vsn.mk b/lib/et/vsn.mk
index aab63a402e..d5416f1ea9 100644
--- a/lib/et/vsn.mk
+++ b/lib/et/vsn.mk
@@ -1 +1 @@
-ET_VSN = 1.6.1
+ET_VSN = 1.6.4
diff --git a/lib/eunit/doc/src/Makefile b/lib/eunit/doc/src/Makefile
index 610e575af6..117542cb37 100644
--- a/lib/eunit/doc/src/Makefile
+++ b/lib/eunit/doc/src/Makefile
@@ -70,9 +70,10 @@ HTML_STYLESHEET_FILES = \
BOOK_FILES = book.xml
XML_FILES = \
- $(BOOK_FILES) $(XML_CHAPTER_FILES) $(XML_NOTES_FILES) \
- $(XML_PART_FILES) $(XML_REF3_FILES) $(XML_APPLICATION_FILES)
+ $(BOOK_FILES) $(XML_NOTES_FILES) \
+ $(XML_PART_FILES) $(XML_APPLICATION_FILES)
+XML_GEN_FILES = $(XML_REF3_FILES:%=$(XMLDIR)/%) $(XML_CHAPTER_FILES:%=$(XMLDIR)/%)
# ----------------------------------------------------
INFO_FILE = ../../info
@@ -122,11 +123,11 @@ man: $(MAN3_FILES)
gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
-$(XML_REF3_FILES):
- escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(EUNIT_VSN) -i $(EUNIT_INC_DIR) $(EUNIT_DIR)/$(@:%.xml=%.erl)
+$(XML_REF3_FILES:%=$(XMLDIR)/%):
+ $(gen_verbose)escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(EUNIT_VSN) -i $(EUNIT_INC_DIR) -dir $(XMLDIR) $(EUNIT_DIR)/$(@:$(XMLDIR)/%.xml=%.erl)
-$(XML_CHAPTER_FILES):
- escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(EUNIT_VSN) -chapter ../overview.edoc
+$(XML_CHAPTER_FILES:%=$(XMLDIR)/%):
+ $(gen_verbose)escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(EUNIT_VSN) -chapter -dir $(XMLDIR) ../overview.edoc
info:
@echo "XML_PART_FILES: $(XML_PART_FILES)"
@@ -145,6 +146,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(XML_REF3_FILES) $(XML_CHAPTER_FILES) *.html
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
diff --git a/lib/eunit/doc/src/notes.xml b/lib/eunit/doc/src/notes.xml
index b38cb2e70e..67a9ae5fcb 100644
--- a/lib/eunit/doc/src/notes.xml
+++ b/lib/eunit/doc/src/notes.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2008</year>
- <year>2017</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -33,6 +33,36 @@
</header>
<p>This document describes the changes made to the EUnit application.</p>
+<section><title>Eunit 2.3.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Eunit 2.3.6</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> Calls to <c>erlang:get_stacktrace()</c> are removed.
+ </p>
+ <p>
+ Own Id: OTP-14861</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Eunit 2.3.5</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/eunit/src/eunit_lib.erl b/lib/eunit/src/eunit_lib.erl
index e340f50a3c..771541354c 100644
--- a/lib/eunit/src/eunit_lib.erl
+++ b/lib/eunit/src/eunit_lib.erl
@@ -202,13 +202,13 @@ format_exception_test_() ->
"\nymmud:rorre"++_,
lists:reverse(lists:flatten(
format_exception(try erlang:error(dummy)
- catch C:R -> {C, R, erlang:get_stacktrace()}
+ catch C:R:S -> {C, R, S}
end)))),
?_assertMatch(
"\nymmud:rorre"++_,
lists:reverse(lists:flatten(
format_exception(try erlang:error(dummy, [a])
- catch C:R -> {C, R, erlang:get_stacktrace()}
+ catch C:R:S -> {C, R, S}
end))))].
-endif.
@@ -391,7 +391,7 @@ fun_parent(F) ->
-ifdef(TEST).
fun_parent_test() ->
- {?MODULE,fun_parent_test,0} = fun_parent(fun () -> ok end).
+ {?MODULE,fun_parent_test,0} = fun_parent(fun (A) -> {ok,A} end).
-endif.
%% ---------------------------------------------------------------------
diff --git a/lib/eunit/src/eunit_listener.erl b/lib/eunit/src/eunit_listener.erl
index e652c5b2f6..75aa05c543 100644
--- a/lib/eunit/src/eunit_listener.erl
+++ b/lib/eunit/src/eunit_listener.erl
@@ -137,8 +137,7 @@ call(F, As, St) when is_atom(F) ->
try apply(St#state.callback, F, As) of
Substate -> St#state{state = Substate}
catch
- Class:Term ->
- Trace = erlang:get_stacktrace(),
+ Class:Term:Trace ->
if F =/= terminate ->
call(terminate, [{error, {Class, Term, Trace}},
St#state.state], St);
diff --git a/lib/eunit/src/eunit_proc.erl b/lib/eunit/src/eunit_proc.erl
index e075005238..96bdcf88b6 100644
--- a/lib/eunit/src/eunit_proc.erl
+++ b/lib/eunit/src/eunit_proc.erl
@@ -628,7 +628,7 @@ io_request({put_chars, M, F, As}, Buf) ->
try apply(M, F, As) of
Chars -> {ok, [Chars | Buf]}
catch
- C:T -> {{error, {C,T,erlang:get_stacktrace()}}, Buf}
+ C:T:S -> {{error, {C,T,S}}, Buf}
end;
io_request({put_chars, _Enc, Chars}, Buf) ->
io_request({put_chars, Chars}, Buf);
diff --git a/lib/eunit/src/eunit_test.erl b/lib/eunit/src/eunit_test.erl
index 6036537178..6fe85ae70a 100644
--- a/lib/eunit/src/eunit_test.erl
+++ b/lib/eunit/src/eunit_test.erl
@@ -39,11 +39,11 @@
%% somewhat, but you can't have everything.) Note that we assume that
%% this particular module is the boundary between eunit and user code.
-get_stacktrace() ->
- get_stacktrace([]).
+get_stacktrace(Trace) ->
+ get_stacktrace(Trace, []).
-get_stacktrace(Ts) ->
- eunit_lib:uniq(prune_trace(erlang:get_stacktrace(), Ts)).
+get_stacktrace(Trace, Ts) ->
+ eunit_lib:uniq(prune_trace(Trace, Ts)).
-dialyzer({no_match, prune_trace/2}).
prune_trace([{eunit_data, _, _} | Rest], Tail) ->
@@ -75,8 +75,8 @@ run_testfun(F) ->
{eunit_internal, Term} ->
%% Internally generated: re-throw Term (lose the trace)
throw(Term);
- Class:Reason ->
- {error, {Class, Reason, get_stacktrace()}}
+ Class:Reason:Trace ->
+ {error, {Class, Reason, Trace}}
end.
@@ -272,7 +272,7 @@ mf_wrapper(M, F) ->
fun () ->
try M:F()
catch
- error:undef ->
+ error:undef:Trace ->
%% Check if it was M:F/0 that was undefined
case erlang:module_loaded(M) of
false ->
@@ -282,14 +282,14 @@ mf_wrapper(M, F) ->
false ->
fail({no_such_function, {M,F,0}});
true ->
- rethrow(error, undef, [{M,F,0}])
+ rethrow(error, undef, Trace, [{M,F,0}])
end
end
end
end.
-rethrow(Class, Reason, Trace) ->
- erlang:raise(Class, Reason, get_stacktrace(Trace)).
+rethrow(Class, Reason, Trace, Ts) ->
+ erlang:raise(Class, Reason, get_stacktrace(Trace, Ts)).
fail(Term) ->
throw({eunit_internal, Term}).
@@ -332,12 +332,14 @@ enter_context(Setup, Cleanup, Instantiate, Callback) ->
T ->
case eunit_lib:is_not_test(T) of
true ->
- catch throw(error), % generate a stack trace
+ {_, Stacktrace} =
+ erlang:process_info(self(),
+ current_stacktrace),
{module,M} = erlang:fun_info(Instantiate, module),
{name,N} = erlang:fun_info(Instantiate, name),
{arity,A} = erlang:fun_info(Instantiate, arity),
context_error({bad_instantiator, {{M,N,A},T}},
- error, badarg);
+ error, Stacktrace, badarg);
false ->
ok
end,
@@ -346,21 +348,22 @@ enter_context(Setup, Cleanup, Instantiate, Callback) ->
%% Always run cleanup; client may be an idiot
try Cleanup(R)
catch
- Class:Term ->
- context_error(cleanup_failed, Class, Term)
+ Class:Term:Trace ->
+ context_error(cleanup_failed,
+ Class, Trace, Term)
end
end
catch
- Class:Term ->
- context_error(instantiation_failed, Class, Term)
+ Class:Term:Trace ->
+ context_error(instantiation_failed, Class, Trace, Term)
end
catch
- Class:Term ->
- context_error(setup_failed, Class, Term)
+ Class:Term:Trace ->
+ context_error(setup_failed, Class, Trace, Term)
end.
-context_error(Type, Class, Term) ->
- throw({context_error, Type, {Class, Term, get_stacktrace()}}).
+context_error(Type, Class, Trace, Term) ->
+ throw({context_error, Type, {Class, Term, get_stacktrace(Trace)}}).
%% This generates single setup/cleanup functions from a list of tuples
%% on the form {Tag, Setup, Cleanup}, where the setup function always
@@ -378,8 +381,8 @@ multi_setup([{Tag, S, C} | Es], CleanupPrev) ->
try C(R) of
_ -> CleanupPrev(Rs)
catch
- Class:Term ->
- throw({Tag, {Class, Term, get_stacktrace()}})
+ Class:Term:Trace ->
+ throw({Tag, {Class, Term, Trace}})
end
end,
{SetupRest, CleanupAll} = multi_setup(Es, Cleanup),
@@ -388,9 +391,9 @@ multi_setup([{Tag, S, C} | Es], CleanupPrev) ->
R ->
SetupRest([R|Rs])
catch
- Class:Term ->
+ Class:Term:Trace ->
CleanupPrev(Rs),
- throw({Tag, {Class, Term, get_stacktrace()}})
+ throw({Tag, {Class, Term, Trace}})
end
end,
CleanupAll};
diff --git a/lib/eunit/vsn.mk b/lib/eunit/vsn.mk
index 2ed9eaac16..46ef5eea3c 100644
--- a/lib/eunit/vsn.mk
+++ b/lib/eunit/vsn.mk
@@ -1 +1 @@
-EUNIT_VSN = 2.3.5
+EUNIT_VSN = 2.3.7
diff --git a/lib/ftp/AUTHORS b/lib/ftp/AUTHORS
new file mode 100644
index 0000000000..88dcbf602a
--- /dev/null
+++ b/lib/ftp/AUTHORS
@@ -0,0 +1,11 @@
+Original Authors:
+
+Peter Högfeldt - first version of ftp
+
+Contributors:
+
+Ingela Anderton Andin
+Martin Gustafsson
+Johan Blom
+Torbjörn Törnkvist
+Joe Armstrong \ No newline at end of file
diff --git a/lib/ftp/Makefile b/lib/ftp/Makefile
new file mode 100644
index 0000000000..e0c9de42e4
--- /dev/null
+++ b/lib/ftp/Makefile
@@ -0,0 +1,78 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1996-2018. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# %CopyrightEnd%
+#
+#
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Macros
+# ----------------------------------------------------
+
+SUB_DIRECTORIES = src doc/src
+
+include vsn.mk
+VSN = $(FTP_VSN)
+
+SPECIAL_TARGETS =
+
+DIA_PLT = ./priv/plt/$(APPLICATION).plt
+DIA_ANALYSIS = $(basename $(DIA_PLT)).dialyzer_analysis
+
+
+# ----------------------------------------------------
+# Default Subdir Targets
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_subdir.mk
+
+.PHONY: info gclean dialyzer dialyzer_plt dclean
+
+info:
+ @echo "OS: $(OS)"
+ @echo "DOCB: $(DOCB)"
+ @echo ""
+ @echo "FTP_VSN: $(FTP_VSN)"
+ @echo "APP_VSN: $(APP_VSN)"
+ @echo ""
+ @echo "DIA_PLT: $(DIA_PLT)"
+ @echo "DIA_ANALYSIS: $(DIA_ANALYSIS)"
+ @echo ""
+
+gclean:
+ git clean -fXd
+
+dclean:
+ rm -f $(DIA_PLT)
+ rm -f $(DIA_ANALYSIS)
+
+dialyzer_plt: $(DIA_PLT)
+
+$(DIA_PLT):
+ @echo "Building $(APPLICATION) plt file"
+ @dialyzer --build_plt \
+ --output_plt $@ \
+ -r ../$(APPLICATION)/ebin \
+ --output $(DIA_ANALYSIS) \
+ --verbose
+
+dialyzer: $(DIA_PLT)
+ @echo "Running dialyzer on $(APPLICATION)"
+ @dialyzer --plt $< \
+ ../$(APPLICATION)/ebin \
+ --verbose
diff --git a/lib/inets/doc/archive/rfc2428.txt b/lib/ftp/doc/archive/rfc2428.txt
index a6ec3535ed..a6ec3535ed 100644
--- a/lib/inets/doc/archive/rfc2428.txt
+++ b/lib/ftp/doc/archive/rfc2428.txt
diff --git a/lib/inets/doc/archive/rfc2577.txt b/lib/ftp/doc/archive/rfc2577.txt
index 83ba203130..83ba203130 100644
--- a/lib/inets/doc/archive/rfc2577.txt
+++ b/lib/ftp/doc/archive/rfc2577.txt
diff --git a/lib/inets/doc/archive/rfc959.txt b/lib/ftp/doc/archive/rfc959.txt
index 5c9f11af5d..5c9f11af5d 100644
--- a/lib/inets/doc/archive/rfc959.txt
+++ b/lib/ftp/doc/archive/rfc959.txt
diff --git a/lib/cosEvent/doc/html/.gitignore b/lib/ftp/doc/html/.gitignore
index e69de29bb2..e69de29bb2 100644
--- a/lib/cosEvent/doc/html/.gitignore
+++ b/lib/ftp/doc/html/.gitignore
diff --git a/lib/cosEvent/doc/man3/.gitignore b/lib/ftp/doc/man3/.gitignore
index e69de29bb2..e69de29bb2 100644
--- a/lib/cosEvent/doc/man3/.gitignore
+++ b/lib/ftp/doc/man3/.gitignore
diff --git a/lib/cosEvent/doc/man6/.gitignore b/lib/ftp/doc/man6/.gitignore
index e69de29bb2..e69de29bb2 100644
--- a/lib/cosEvent/doc/man6/.gitignore
+++ b/lib/ftp/doc/man6/.gitignore
diff --git a/lib/cosEvent/doc/pdf/.gitignore b/lib/ftp/doc/pdf/.gitignore
index e69de29bb2..e69de29bb2 100644
--- a/lib/cosEvent/doc/pdf/.gitignore
+++ b/lib/ftp/doc/pdf/.gitignore
diff --git a/lib/ftp/doc/src/Makefile b/lib/ftp/doc/src/Makefile
new file mode 100644
index 0000000000..20fbbc73a9
--- /dev/null
+++ b/lib/ftp/doc/src/Makefile
@@ -0,0 +1,155 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# %CopyrightEnd%
+#
+#
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../../vsn.mk
+VSN=$(FTP_VSN)
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
+
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+XML_APPLICATION_FILES = ref_man.xml
+
+XML_CHAPTER_FILES = \
+ introduction.xml \
+ ftp_client.xml \
+ notes.xml
+
+XML_REF3_FILES = \
+ ftp.xml
+
+XML_PART_FILES = \
+ part.xml
+
+BOOK_FILES = book.xml
+
+XML_FILES = \
+ $(BOOK_FILES) \
+ $(XML_CHAPTER_FILES) \
+ $(XML_PART_FILES) \
+ $(XML_REF6_FILES) \
+ $(XML_REF3_FILES) \
+ $(XML_APPLICATION_FILES)
+
+# GIF_FILES = ftp.gif
+
+
+# ----------------------------------------------------
+
+HTML_FILES = \
+ $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \
+ $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html)
+
+INFO_FILE = ../../info
+EXTRA_FILES = \
+ $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html) \
+ $(XML_REF6_FILES:%.xml=$(HTMLDIR)/%.html) \
+ $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html)
+
+MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
+
+HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
+
+TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+XML_FLAGS +=
+DVIPS_FLAGS +=
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+$(HTMLDIR)/%.gif: %.gif
+ $(INSTALL_DATA) $< $@
+
+docs: pdf html man
+
+ldocs: local_docs
+
+$(TOP_PDF_FILE): $(XML_FILES)
+
+pdf: $(TOP_PDF_FILE)
+
+html: gifs $(HTML_REF_MAN_FILE)
+
+clean clean_docs: clean_html clean_man clean_pdf
+ rm -rf $(XMLDIR)
+ rm -f errs core *~
+
+man: $(MAN3_FILES)
+
+gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
+
+debug opt:
+
+clean_pdf:
+ rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
+
+clean_html:
+ rm -rf $(TOP_HTML_FILES) $(HTMLDIR)/*
+
+clean_man:
+ rm -f $(MAN3_FILES)
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_docs_spec: docs
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(HTMLDIR)/* "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
+
+release_spec:
+
+info:
+ @echo "GIF_FILES:\n$(GIF_FILES)"
+ @echo ""
+ @echo "EXTRA_FILES:\n$(EXTRA_FILES)"
+ @echo ""
+ @echo "HTML_FILES:\n$(HTML_FILES)"
+ @echo ""
+ @echo "TOP_HTML_FILES:\n$(TOP_HTML_FILES)"
+ @echo ""
+ @echo "XML_REF3_FILES:\n$(XML_REF3_FILES)"
+ @echo ""
+ @echo "XML_REF6_FILES:\n$(XML_REF6_FILES)"
+ @echo ""
+ @echo "XML_CHAPTER_FILES:\n$(XML_CHAPTER_FILES)"
+ @echo ""
diff --git a/lib/ftp/doc/src/book.xml b/lib/ftp/doc/src/book.xml
new file mode 100644
index 0000000000..1268af64bf
--- /dev/null
+++ b/lib/ftp/doc/src/book.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE book SYSTEM "book.dtd">
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header titlestyle="normal">
+ <copyright>
+ <year>1997</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>FTP</title>
+ <prepared>Péter Dimitrov</prepared>
+ <docno></docno>
+ <date>2018-02-26</date>
+ <rev>1.0</rev>
+ <file>book.sgml</file>
+ </header>
+ <insidecover>
+ </insidecover>
+ <pagetext>FTP</pagetext>
+ <preamble>
+ <contents level="2"></contents>
+ </preamble>
+ <parts lift="no">
+ <xi:include href="part.xml"/>
+ </parts>
+ <applications>
+ <xi:include href="ref_man.xml"/>
+ </applications>
+ <releasenotes>
+ <xi:include href="notes.xml"/>
+ </releasenotes>
+ <listofterms></listofterms>
+ <index></index>
+</book>
diff --git a/lib/ftp/doc/src/ftp.xml b/lib/ftp/doc/src/ftp.xml
new file mode 100644
index 0000000000..9645b03364
--- /dev/null
+++ b/lib/ftp/doc/src/ftp.xml
@@ -0,0 +1,983 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>1997</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>ftp</title>
+ <prepared>Peter H&ouml;gfeldt</prepared>
+ <docno></docno>
+ <date>1997-11-05</date>
+ <rev>B</rev>
+ <file>ftp.xml</file>
+ </header>
+ <module since="">ftp</module>
+ <modulesummary>A File Transfer Protocol client.</modulesummary>
+
+ <description>
+
+ <p>This module implements a client for file transfer
+ according to a subset of the File Transfer Protocol (FTP), see
+ <url href="http://www.ietf.org/rfc/rfc959.txt">RFC 959</url>.</p>
+
+ <p>The FTP client always tries to use passive FTP mode and only resort
+ to active FTP mode if this fails. This default behavior can be
+ changed by start option <seealso marker="#mode">mode</seealso>.</p>
+
+ <marker id="two_start"></marker>
+
+ <p>An FTP client can be started in two ways. One is using the
+ <seealso marker="#service_start">service_start</seealso> function,
+ the other is to start it directly as a standalone process
+ using function <seealso marker="#open">open</seealso>.</p>
+
+ <p>For a simple example of an FTP session, see
+ <seealso marker="ftp_client">FTP User's Guide</seealso>.</p>
+
+ <p>In addition to the ordinary functions for receiving and sending
+ files (see <c>recv/2</c>, <c>recv/3</c>, <c>send/2</c>, and
+ <c>send/3</c>) there are functions for receiving remote files as
+ binaries (see <c>recv_bin/2</c>) and for sending binaries to be
+ stored as remote files (see <c>send_bin/3</c>).</p>
+
+ <p>A set of functions is provvided for sending and receiving
+ contiguous parts of a file to be stored in a remote file. For send,
+ see <c>send_chunk_start/2</c>, <c>send_chunk/2</c>, and
+ <c>send_chunk_end/1</c>. For receive, see
+ <c>recv_chunk_start/2</c> and <c>recv_chunk/</c>).</p>
+
+ <p>The return values of the following functions depend
+ much on the implementation of the FTP server at the remote
+ host. In particular, the results from <c>ls</c> and <c>nlist</c>
+ varies. Often real errors are not reported as errors by <c>ls</c>,
+ even if, for example, a file or directory does not
+ exist. <c>nlist</c> is usually more strict, but some
+ implementations have the peculiar behaviour of responding with an
+ error if the request is a listing of the contents of a directory
+ that exists but is empty.</p>
+
+ <marker id="service_start"></marker>
+ </description>
+
+ <section>
+ <title>FTP CLIENT SERVICE START/STOP</title>
+
+ <p>The FTP client can be started and stopped dynamically in runtime by
+ calling the <c>ftp</c> application API
+ <c>ftp:start_service(ServiceConfig)</c> and
+ <c>ftp:stop_service(Pid)</c>.</p>
+
+ <p>The available configuration options are as follows:</p>
+
+ <taglist>
+ <tag>{host, Host}</tag>
+ <item>
+ <marker id="host"></marker>
+ <p>Host = <c>string() | ip_address()</c></p>
+ </item>
+
+ <tag>{port, Port}</tag>
+ <item>
+ <marker id="port"></marker>
+ <p>Port = <c>integer() > 0</c></p>
+ <p>Default is <c>21</c>.</p>
+ </item>
+
+ <tag>{mode, Mode}</tag>
+ <item>
+ <marker id="mode"></marker>
+ <p>Mode = <c>active | passive</c></p>
+ <p>Default is <c>passive</c>.</p>
+ </item>
+
+ <tag>{verbose, Verbose}</tag>
+ <item>
+ <marker id="verbose"></marker>
+ <p>Verbose = <c>boolean()</c> </p>
+ <p>Determines if the FTP communication is to be
+ verbose or not.</p>
+ <p>Default is <c>false</c>.</p>
+ </item>
+
+ <tag>{debug, Debug}</tag>
+ <item>
+ <marker id="debug"></marker>
+ <p>Debug = <c>trace | debug | disable</c> </p>
+ <p>Debugging using the dbg toolkit. </p>
+ <p>Default is <c>disable</c>.</p>
+ </item>
+
+ <tag>{ipfamily, IpFamily}</tag>
+ <item>
+ <marker id="ipfamily"></marker>
+ <p>IpFamily = <c>inet | inet6 | inet6fb4</c> </p>
+ <p>With <c>inet6fb4</c> the client behaves as before, that is,
+ tries to use IPv6, and only if that does not work it
+ uses IPv4).</p>
+ <p>Default is <c>inet</c> (IPv4).</p>
+ </item>
+
+ <tag>{timeout, Timeout}</tag>
+ <item>
+ <marker id="timeout"></marker>
+ <p>Timeout = <c>non_neg_integer()</c></p>
+ <p>Connection time-out.</p>
+ <p>Default is <c>60000</c> (milliseconds).</p>
+ </item>
+
+ <tag>{dtimeout, DTimeout}</tag>
+ <item>
+ <marker id="dtimeout"></marker>
+ <p>DTimeout = <c>non_neg_integer() | infinity</c> </p>
+ <p>Data connect time-out.
+ The time the client waits for the server to connect to the
+ data socket.</p>
+ <p>Default is <c>infinity</c>. </p>
+ </item>
+
+ <tag>{progress, Progress}</tag>
+ <item>
+ <marker id="progress"></marker>
+ <p>Progress = <c>ignore | {CBModule, CBFunction, InitProgress}</c></p>
+ <p><c>CBModule = atom()</c>, <c>CBFunction = atom()</c></p>
+ <p><c>InitProgress = term()</c></p>
+ <p>Default is <c>ignore</c>.</p>
+ </item>
+
+ </taglist>
+
+ <p>Option <c>progress</c> is intended to be used by applications that
+ want to create some type of progress report, such as a progress bar in
+ a GUI. Default for the progress option is <c>ignore</c>,
+ that is, the option is not used. When the progress option is
+ specified, the following happens when <c>ftp:send/[3,4]</c> or
+ <c>ftp:recv/[3,4]</c> are called:</p>
+
+ <list type="bulleted">
+ <item>
+ <p>Before a file is transferred, the following call is
+ made to indicate the start of the file transfer and how large
+ the file is. The return value of the callback function
+ is to be a new value for the <c>UserProgressTerm</c> that will
+ be used as input the next time the callback function is
+ called.</p>
+ <p><c>
+ CBModule:CBFunction(InitProgress, File, {file_size, FileSize})
+ </c></p>
+ </item>
+
+ <item>
+ <p>Every time a chunk of bytes is transferred the
+ following call is made:</p>
+ <p><c>
+ CBModule:CBFunction(UserProgressTerm, File, {transfer_size, TransferSize})
+ </c></p>
+ </item>
+
+ <item>
+ <p>At the end of the file the following call is
+ made to indicate the end of the transfer:</p>
+ <p><c>
+ CBModule:CBFunction(UserProgressTerm, File, {transfer_size, 0})
+ </c></p>
+ </item>
+ </list>
+
+ <p>The callback function is to be defined as follows:</p>
+
+ <p><c>
+ CBModule:CBFunction(UserProgressTerm, File, Size) -> UserProgressTerm
+ </c></p>
+
+ <p><c>
+ CBModule = CBFunction = atom()
+ </c></p>
+
+ <p><c>
+ UserProgressTerm = term()
+ </c></p>
+
+ <p><c>
+ File = string()
+ </c></p>
+
+ <p><c>
+ Size = {transfer_size, integer()} | {file_size, integer()} | {file_size, unknown}
+ </c></p>
+
+ <p>For remote files, <c>ftp</c> cannot determine the
+ file size in a platform independent way. In this case the size
+ becomes <c>unknown</c> and it is left to the application to
+ determine the size.</p>
+
+ <note>
+ <p>The callback is made by a middleman process, hence the
+ file transfer is not affected by the code in the progress
+ callback function. If the callback crashes, this is
+ detected by the FTP connection process, which then prints an
+ info-report and goes on as if the progress option was set
+ to <c>ignore</c>.</p>
+ </note>
+
+ <p>The file transfer type is set to the default of the FTP server
+ when the session is opened. This is usually ASCCI mode.
+ </p>
+
+ <p>The current local working directory (compare <c>lpwd/1</c>) is set
+ to the value reported by <c>file:get_cwd/1</c>, the wanted
+ local directory.
+ </p>
+
+ <p>The return value <c>Pid</c> is used as a reference to the
+ newly created FTP client in all other functions, and they are to
+ be called by the process that created the connection. The FTP
+ client process monitors the process that created it and
+ terminates if that process terminates.</p>
+ </section>
+
+ <section>
+ <title>DATA TYPES</title>
+ <p>The following type definitions are used by more than one
+ function in the FTP client API:</p>
+ <p><c>pid()</c> = identifier of an FTP connection</p>
+ <p><c>string()</c> = list of ASCII characters</p>
+ <p><c>shortage_reason()</c> = <c>etnospc | epnospc</c></p>
+ <p><c>restriction_reason()</c> = <c>epath | efnamena | elogin | enotbinary</c>
+ - all restrictions are not always relevant to all functions
+ </p>
+ <p><c>common_reason()</c> = <c>econn | eclosed | term()</c>
+ - some explanation of what went wrong</p>
+
+ <marker id="account"></marker>
+ </section>
+
+ <funcs>
+
+ <func>
+ <name since="">account(Pid, Account) -> ok | {error, Reason}</name>
+ <fsummary>Specifies which account to use.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>Account = string()</v>
+ <v>Reason = eacct | common_reason()</v>
+ </type>
+ <desc>
+ <p>Sets the account for an operation, if needed.</p>
+
+ <marker id="append"></marker>
+ <marker id="append2"></marker>
+ <marker id="append3"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">append(Pid, LocalFile) -> </name>
+ <name since="">append(Pid, LocalFile, RemoteFile) -> ok | {error, Reason}</name>
+ <fsummary>Transfers a file to remote server, and appends it to
+ <c>Remotefile</c>.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>LocalFile = RemoteFile = string()</v>
+ <v>Reason = epath | elogin | etnospc | epnospc | efnamena | common_reason</v>
+ </type>
+ <desc>
+ <p>Transfers the file <c>LocalFile</c> to the remote server. If
+ <c>RemoteFile</c> is specified, the name of the remote file that the
+ file is appended to is set to <c>RemoteFile</c>, otherwise
+ to <c>LocalFile</c>. If the file does not exists,
+ it is created.</p>
+
+ <marker id="append_bin"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">append_bin(Pid, Bin, RemoteFile) -> ok | {error, Reason}</name>
+ <fsummary>Transfers a binary into a remote file.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>Bin = binary()</v>
+ <v>RemoteFile = string()</v>
+ <v>Reason = restriction_reason()| shortage_reason() | common_reason()</v>
+ </type>
+ <desc>
+ <p>Transfers the binary <c>Bin</c> to the remote server and appends
+ it to the file <c>RemoteFile</c>. If the file does not exist, it
+ is created.</p>
+
+ <marker id="append_chunk"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">append_chunk(Pid, Bin) -> ok | {error, Reason}</name>
+ <fsummary>Appends a chunk to the remote file.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>Bin = binary()</v>
+ <v>Reason = echunk | restriction_reason() | common_reason()</v>
+ </type>
+ <desc>
+ <p>Transfers the chunk <c>Bin</c> to the remote server, which
+ appends it to the file specified in the call to
+ <c>append_chunk_start/2</c>.</p>
+ <p>For some errors, for example, file system full, it is
+ necessary to call <c>append_chunk_end</c> to get the
+ proper reason.</p>
+
+ <marker id="append_chunk_start"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">append_chunk_start(Pid, File) -> ok | {error, Reason}</name>
+ <fsummary>Starts transfer of file chunks for appending to <c>File</c>.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>File = string()</v>
+ <v>Reason = restriction_reason() | common_reason()</v>
+ </type>
+ <desc>
+ <p>Starts the transfer of chunks for appending to the file
+ <c>File</c> at the remote server. If the file does not exist,
+ it is created.</p>
+
+ <marker id="append_chunk_end"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">append_chunk_end(Pid) -> ok | {error, Reason}</name>
+ <fsummary>Stops transfer of chunks for appending.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>Reason = echunk | restriction_reason() | shortage_reason() </v>
+ </type>
+ <desc>
+ <p>Stops transfer of chunks for appending to the remote server.
+ The file at the remote server, specified in the call to
+ <c>append_chunk_start/2</c>, is closed by the server.</p>
+
+ <marker id="cd"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">cd(Pid, Dir) -> ok | {error, Reason}</name>
+ <fsummary>Changes remote working directory.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>Dir = string()</v>
+ <v>Reason = restriction_reason() | common_reason() </v>
+ </type>
+ <desc>
+ <p>Changes the working directory at the remote server to
+ <c>Dir</c>.</p>
+
+ <marker id="close"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">close(Pid) -> ok</name>
+ <fsummary>Ends the FTP session.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ </type>
+ <desc>
+ <p>Ends an FTP session, created using function
+ <seealso marker="#open">open</seealso>.</p>
+
+ <marker id="delete"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">delete(Pid, File) -> ok | {error, Reason}</name>
+ <fsummary>Deletes a file at the remote server.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>File = string()</v>
+ <v>Reason = restriction_reason() | common_reason()</v>
+ </type>
+ <desc>
+ <p>Deletes the file <c>File</c> at the remote server.</p>
+
+ <marker id="append"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">formaterror(Tag) -> string()</name>
+ <fsummary>Returns error diagnostics.</fsummary>
+ <type>
+ <v>Tag = {error, atom()} | atom()</v>
+ </type>
+ <desc>
+ <p>Given an error return value <c>{error, AtomReason}</c>,
+ this function returns a readable string describing the error.</p>
+
+ <marker id="lcd"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">lcd(Pid, Dir) -> ok | {error, Reason}</name>
+ <fsummary>Changes local working directory.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>Dir = string()</v>
+ <v>Reason = restriction_reason()</v>
+ </type>
+ <desc>
+ <p>Changes the working directory to <c>Dir</c> for the local client.</p>
+
+ <marker id="lpwd"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">lpwd(Pid) -> {ok, Dir}</name>
+ <fsummary>Gets local current working directory.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ </type>
+ <desc>
+ <p>Returns the current working directory at the local client.</p>
+
+ <marker id="ls"></marker>
+ <marker id="ls1"></marker>
+ <marker id="ls2"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">ls(Pid) -> </name>
+ <name since="">ls(Pid, Pathname) -> {ok, Listing} | {error, Reason}</name>
+ <fsummary>List of files.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>Pathname = string()</v>
+ <v>Listing = string()</v>
+ <v>Reason = restriction_reason() | common_reason()</v>
+ </type>
+ <desc>
+ <p>Returns a list of files in long format.</p>
+ <p><c>Pathname</c> can be a directory, a group of files, or
+ a file. The <c>Pathname</c> string can contain wildcards.</p>
+ <p><c>ls/1</c> implies the current remote directory of the user.</p>
+ <p>The format of <c>Listing</c> depends on the operating system.
+ On UNIX, it is typically produced from the output of the
+ <c>ls -l</c> shell command.</p>
+
+ <marker id="mkdir"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">mkdir(Pid, Dir) -> ok | {error, Reason}</name>
+ <fsummary>Creates a remote directory.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>Dir = string()</v>
+ <v>Reason = restriction_reason() | common_reason()</v>
+ </type>
+ <desc>
+ <p>Creates the directory <c>Dir</c> at the remote server.</p>
+
+ <marker id="nlist"></marker>
+ <marker id="nlist1"></marker>
+ <marker id="nlist2"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">nlist(Pid) -> </name>
+ <name since="">nlist(Pid, Pathname) -> {ok, Listing} | {error, Reason}</name>
+ <fsummary>List of files.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>Pathname = string()</v>
+ <v>Listing = string()</v>
+ <v>Reason = restriction_reason() | common_reason()</v>
+ </type>
+ <desc>
+ <p>Returns a list of files in short format.</p>
+ <p><c>Pathname</c> can be a directory, a group of files, or
+ a file. The <c>Pathname</c> string can contain wildcards.</p>
+ <p><c>nlist/1</c> implies the current remote directory of the user.</p>
+ <p>The format of <c>Listing</c> is a stream of
+ filenames where each filename is separated by &lt;CRLF&gt; or
+ &lt;NL&gt;. Contrary to function <c>ls</c>, the purpose of
+ <c>nlist</c> is to enable a program to
+ process filename information automatically.</p>
+
+ <marker id="open"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">open(Host) -> {ok, Pid} | {error, Reason}</name>
+ <name since="">open(Host, Opts) -> {ok, Pid} | {error, Reason}</name>
+ <fsummary>Starts a standalone FTP client.</fsummary>
+ <type>
+ <v>Host = string() | ip_address()</v>
+ <v>Opts = options()</v>
+ <v>options() = [option()]</v>
+ <v>option() = start_option() | open_option()</v>
+ <v>start_option() = {verbose, verbose()} | {debug, debug()}</v>
+ <v>verbose() = boolean() (default is false)</v>
+ <v>debug() = disable | debug | trace (default is disable)</v>
+ <v>open_option() = {ipfamily, ipfamily()} | {port, port()} | {mode, mode()} | {tls, tls_options()} | {timeout, timeout()} | {dtimeout, dtimeout()} | {progress, progress() | {sock_ctrl, sock_opts()} | {sock_data_act, sock_opts()} | {sock_data_pass, sock_opts()} }</v>
+ <v>ipfamily() = inet | inet6 | inet6fb4 (default is inet)</v>
+ <v>port() = integer() > 0 (default is 21)</v>
+ <v>mode() = active | passive (default is passive)</v>
+ <v>tls_options() = [<seealso marker="ssl:ssl#type-tls_option">ssl:tls_option()</seealso>]</v>
+ <v>sock_opts() = [<seealso marker="kernel:gen_tcp#type-option">gen_tcp:option()</seealso> except for ipv6_v6only, active, packet, mode, packet_size and header</v>
+ <v>timeout() = integer() > 0 (default is 60000 milliseconds)</v>
+ <v>dtimeout() = integer() > 0 | infinity (default is infinity)</v>
+ <v>pogress() = ignore | {module(), function(), initial_data()} (default is ignore)</v>
+ <v>module() = atom()</v>
+ <v>function() = atom()</v>
+ <v>initial_data() = term()</v>
+ <v>Reason = ehost | term()</v>
+ </type>
+
+ <desc>
+ <p>Starts a standalone FTP client process
+ (without the <c>ftp</c> service framework) and
+ opens a session with the FTP server at <c>Host</c>. </p>
+
+ <p>If option <c>{tls, tls_options()}</c> is present, the FTP session
+ is transported over <c>tls</c> (<c>ftps</c>, see
+ <url href="http://www.ietf.org/rfc/rfc4217.txt">RFC 4217</url>).
+ The list <c>tls_options()</c> can be empty. The function
+ <seealso marker="ssl:ssl#connect/3"><c>ssl:connect/3</c></seealso>
+ is used for securing both the control connection and the data sessions.
+ </p>
+
+ <p>The options <c>sock_ctrl</c>, <c>sock_data_act</c> and <c>sock_data_pass</c> passes options down to
+ the underlying transport layer (tcp). The default value for <c>sock_ctrl</c> is <c>[]</c>. Both
+ <c>sock_data_act</c> and <c>sock_data_pass</c> uses the value of <c>sock_ctrl</c> as default value.
+ </p>
+
+ <p>A session opened in this way is closed using function
+ <seealso marker="#close">close</seealso>.</p>
+
+ <marker id="pwd"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">pwd(Pid) -> {ok, Dir} | {error, Reason}</name>
+ <fsummary>Gets the remote current working directory.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>Reason = restriction_reason() | common_reason()</v>
+ </type>
+ <desc>
+ <p>Returns the current working directory at the remote server.</p>
+
+ <marker id="recv"></marker>
+ <marker id="recv2"></marker>
+ <marker id="recv3"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">recv(Pid, RemoteFile) -> </name>
+ <name since="">recv(Pid, RemoteFile, LocalFile) -> ok | {error, Reason}</name>
+ <fsummary>Transfers a file from remote server.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>RemoteFile = LocalFile = string()</v>
+ <v>Reason = restriction_reason() | common_reason() | file_write_error_reason() </v>
+ <v>file_write_error_reason() = see file:write/2</v>
+ </type>
+ <desc>
+ <p>Transfers the file <c>RemoteFile</c> from the remote server
+ to the file system of the local client. If
+ <c>LocalFile</c> is specified, the local file will be
+ <c>LocalFile</c>, otherwise
+ <c>RemoteFile</c>.</p>
+ <p>If the file write fails (for example, <c>enospc</c>), the command is
+ aborted and <c>{error, file_write_error_reason()}</c> is returned.
+ However, the file is <em>not</em> removed.</p>
+
+ <marker id="recv_bin"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">recv_bin(Pid, RemoteFile) -> {ok, Bin} | {error, Reason}</name>
+ <fsummary>Transfers a file from remote server as a binary.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>Bin = binary()</v>
+ <v>RemoteFile = string()</v>
+ <v>Reason = restriction_reason() | common_reason()</v>
+ </type>
+ <desc>
+ <p>Transfers the file <c>RemoteFile</c> from the remote server and
+ receives it as a binary.</p>
+
+ <marker id="recv_chunk_start"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">recv_chunk_start(Pid, RemoteFile) -> ok | {error, Reason}</name>
+ <fsummary>Starts chunk-reading of the remote file.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>RemoteFile = string()</v>
+ <v>Reason = restriction_reason() | common_reason()</v>
+ </type>
+ <desc>
+ <p>Starts transfer of the file <c>RemoteFile</c> from the
+ remote server.</p>
+
+ <marker id="recv_chunk"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">recv_chunk(Pid) -> ok | {ok, Bin} | {error, Reason}</name>
+ <fsummary>Receives a chunk of the remote file.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>Bin = binary()</v>
+ <v>Reason = restriction_reason() | common_reason()</v>
+ </type>
+ <desc>
+ <p>Receives a chunk of the remote file (<c>RemoteFile</c> of
+ <c>recv_chunk_start</c>). The return values have the following
+ meaning:</p>
+ <list type="bulleted">
+ <item><c>ok</c> = the transfer is complete.</item>
+ <item><c>{ok, Bin}</c> = just another chunk of the file.</item>
+ <item><c>{error, Reason}</c> = transfer failed.</item>
+ </list>
+
+ <marker id="rename"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">rename(Pid, Old, New) -> ok | {error, Reason}</name>
+ <fsummary>Renames a file at the remote server.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>CurrFile = NewFile = string()</v>
+ <v>Reason = restriction_reason() | common_reason()</v>
+ </type>
+ <desc>
+ <p>Renames <c>Old</c> to <c>New</c> at the remote server.</p>
+
+ <marker id="rmdir"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">rmdir(Pid, Dir) -> ok | {error, Reason}</name>
+ <fsummary>Removes a remote directory.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>Dir = string()</v>
+ <v>Reason = restriction_reason() | common_reason()</v>
+ </type>
+ <desc>
+ <p>Removes directory <c>Dir</c> at the remote server.</p>
+
+ <marker id="send"></marker>
+ <marker id="send2"></marker>
+ <marker id="send3"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">send(Pid, LocalFile) -></name>
+ <name since="">send(Pid, LocalFile, RemoteFile) -> ok | {error, Reason}</name>
+ <fsummary>Transfers a file to the remote server.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>LocalFile = RemoteFile = string()</v>
+ <v>Reason = restriction_reason() | common_reason() | shortage_reason()</v>
+ </type>
+ <desc>
+ <p>Transfers the file <c>LocalFile</c> to the remote server. If
+ <c>RemoteFile</c> is specified, the name of the remote file is set
+ to <c>RemoteFile</c>, otherwise to <c>LocalFile</c>.</p>
+
+ <marker id="send_bin"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">send_bin(Pid, Bin, RemoteFile) -> ok | {error, Reason}</name>
+ <fsummary>Transfers a binary into a remote file.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>Bin = binary()</v>
+ <v>RemoteFile = string()</v>
+ <v>Reason = restriction_reason() | common_reason() | shortage_reason()</v>
+ </type>
+ <desc>
+ <p>Transfers the binary <c>Bin</c> into the file <c>RemoteFile</c>
+ at the remote server.</p>
+
+ <marker id="send_chunk"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">send_chunk(Pid, Bin) -> ok | {error, Reason}</name>
+ <fsummary>Writes a chunk to the remote file.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>Bin = binary()</v>
+ <v>Reason = echunk | restriction_reason() | common_reason()</v>
+ </type>
+ <desc>
+ <p>Transfers the chunk <c>Bin</c> to the remote server, which
+ writes it into the file specified in the call to
+ <c>send_chunk_start/2</c>.</p>
+ <p>For some errors, for example, file system full, it is
+ necessary to to call <c>send_chunk_end</c> to get the
+ proper reason.</p>
+
+ <marker id="send_chunk_start"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">send_chunk_start(Pid, File) -> ok | {error, Reason}</name>
+ <fsummary>Starts transfer of file chunks.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>File = string()</v>
+ <v>Reason = restriction_reason() | common_reason()</v>
+ </type>
+ <desc>
+ <p>Starts transfer of chunks into the file <c>File</c> at the
+ remote server.</p>
+
+ <marker id="send_chunk_end"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">send_chunk_end(Pid) -> ok | {error, Reason}</name>
+ <fsummary>Stops transfer of chunks.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>Reason = restriction_reason() | common_reason() | shortage_reason()</v>
+ </type>
+ <desc>
+ <p>Stops transfer of chunks to the remote server. The file at the
+ remote server, specified in the call to <c>send_chunk_start/2</c>
+ is closed by the server.</p>
+
+ <marker id="type"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0">start_service(ServiceConfig) -> {ok, Pid} | {error, Reason}</name>
+ <fsummary>Dynamically starts an <c>FTP</c>
+ session after the <c>ftp</c> application has been started.</fsummary>
+ <type>
+ <v>ServiceConfig = [{Option, Value}]</v>
+ <v>Option = property()</v>
+ <v>Value = term()</v>
+ </type>
+ <desc>
+ <p>Dynamically starts an <c>FTP</c> session after the <c>ftp</c>
+ application has been started.</p>
+ <note>
+ <p>As long as the <c>ftp</c> application is operational,
+ the FTP sessions are supervised and can be soft code upgraded.</p>
+ </note>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0">stop_service(Reference) -> ok | {error, Reason} </name>
+ <fsummary>Stops an FTP session.</fsummary>
+ <type>
+ <v>Reference = pid() | term() - service-specified reference</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Stops a started FTP session.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">type(Pid, Type) -> ok | {error, Reason}</name>
+ <fsummary>Sets transfer type to <c>ascii</c>or <c>binary</c>.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>Type = ascii | binary</v>
+ <v>Reason = etype | restriction_reason() | common_reason()</v>
+ </type>
+ <desc>
+ <p>Sets the file transfer type to <c>ascii</c> or <c>binary</c>. When
+ an FTP session is opened, the default transfer type of the
+ server is used, most often <c>ascii</c>, which is default
+ according to <url href="http://www.ietf.org/rfc/rfc959.txt">RFC 959</url>.</p>
+ <marker id="user3"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">user(Pid, User, Password) -> ok | {error, Reason}</name>
+ <fsummary>User login.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>User = Password = string()</v>
+ <v>Reason = euser | common_reason()</v>
+ </type>
+ <desc>
+ <p>Performs login of <c>User</c> with <c>Password</c>.</p>
+
+ <marker id="user4"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">user(Pid, User, Password, Account) -> ok | {error, Reason}</name>
+ <fsummary>User login.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>User = Password = string()</v>
+ <v>Reason = euser | common_reason() </v>
+ </type>
+ <desc>
+ <p>Performs login of <c>User</c> with <c>Password</c> to the account
+ specified by <c>Account</c>.</p>
+
+ <marker id="quote"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">quote(Pid, Command) -> [FTPLine]</name>
+ <fsummary>Sends an arbitrary FTP command.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>Command = string()</v>
+ <v>FTPLine = string(</v>
+ </type>
+ <desc><note><p>The telnet end of line characters, from the FTP
+ protocol definition, CRLF, for example, "\\r\\n" has been removed.</p></note>
+ <p>Sends an arbitrary FTP command and returns verbatim a list
+ of the lines sent back by the FTP server. This function is
+ intended to give application accesses to FTP commands
+ that are server-specific or that cannot be provided by
+ this FTP client.</p>
+ <note>
+ <p>FTP commands requiring a data connection cannot be
+ successfully issued with this function.</p>
+ </note>
+ </desc>
+ </func>
+ </funcs>
+
+ <section>
+ <title>ERRORS</title>
+ <p>The possible error reasons and the corresponding diagnostic strings
+ returned by <c>formaterror/1</c> are as follows:
+ </p>
+ <taglist>
+ <tag><c>echunk</c></tag>
+ <item>
+ <p>Synchronization error during chunk sending according to one
+ of the following:
+ </p><list type="bulleted">
+ <item>A call is made to <c>send_chunk/2</c> or <c>send_chunk_end/1</c>
+ before a call to <c>send_chunk_start/2</c>.</item>
+ <item>A call has been made to another transfer function during chunk
+ sending, that is, before a call to <c>send_chunk_end/1</c>.</item>
+ </list>
+ </item>
+ <tag><c>eclosed</c></tag>
+ <item>
+ <p>The session is closed.</p>
+ </item>
+ <tag><c>econn</c></tag>
+ <item>
+ <p>Connection to the remote server is prematurely closed.</p>
+ </item>
+ <tag><c>ehost</c></tag>
+ <item>
+ <p>Host is not found, FTP server is not found, or connection is rejected
+ by FTP server.</p>
+ </item>
+ <tag><c>elogin</c></tag>
+ <item>
+ <p>User is not logged in.</p>
+ </item>
+ <tag><c>enotbinary</c></tag>
+ <item>
+ <p>Term is not a binary.</p>
+ </item>
+ <tag><c>epath</c></tag>
+ <item>
+ <p>No such file or directory, or directory already exists, or
+ permission denied.</p>
+ </item>
+ <tag><c>etype</c></tag>
+ <item>
+ <p>No such type.</p>
+ </item>
+ <tag><c>euser</c></tag>
+ <item>
+ <p>Invalid username or password.</p>
+ </item>
+ <tag><c>etnospc</c></tag>
+ <item>
+ <p>Insufficient storage space in system [452].</p>
+ </item>
+ <tag><c>epnospc</c></tag>
+ <item>
+ <p>Exceeded storage allocation (for current directory or
+ dataset) [552].</p>
+ </item>
+ <tag><c>efnamena</c></tag>
+ <item>
+ <p>Filename not allowed [553].</p>
+ </item>
+ </taglist>
+ </section>
+
+ <section>
+ <title>SEE ALSO</title>
+ <p><seealso marker="kernel:file">file(3)</seealso>
+ <seealso marker="stdlib:filename">filename(3)</seealso>
+ and J. Postel and J. Reynolds: File Transfer Protocol
+ (<url href="http://www.ietf.org/rfc/rfc959.txt">RFC 959</url>).
+ </p>
+ </section>
+
+</erlref>
+
+
diff --git a/lib/ftp/doc/src/ftp_client.xml b/lib/ftp/doc/src/ftp_client.xml
new file mode 100644
index 0000000000..047b055be7
--- /dev/null
+++ b/lib/ftp/doc/src/ftp_client.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2004</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>FTP Client</title>
+ <prepared>Péter Dimitrov</prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>ftp_client.xml</file>
+ </header>
+
+ <section>
+ <title>Getting Started</title>
+
+ <p>FTP clients are considered to be rather temporary. Thus,
+ they are only started and stopped during runtime and cannot
+ be started at application startup.
+ The FTP client API is designed to allow some functions to
+ return intermediate results. This implies that only the process
+ that started the FTP client can access it with
+ preserved sane semantics.
+ If the process that started the FTP session
+ dies, the FTP client process terminates.</p>
+
+ <p>The client supports IPv6 as long as the underlying mechanisms
+ also do so.</p>
+
+ <p>The following is a simple example of an FTP session, where
+ the user <c>guest</c> with password <c>password</c> logs on to
+ the remote host <c>erlang.org</c>:</p>
+ <code type="erl"><![CDATA[
+ 1> ftp:start().
+ ok
+ 2> {ok, Pid} = ftp:start_service([{host, "erlang.org"}]).
+ {ok,<0.22.0>}
+ 3> ftp:user(Pid, "guest", "password").
+ ok
+ 4> ftp:pwd(Pid).
+ {ok, "/home/guest"}
+ 5> ftp:cd(Pid, "appl/examples").
+ ok
+ 6> ftp:lpwd(Pid).
+ {ok, "/home/fred"}.
+ 7> ftp:lcd(Pid, "/home/eproj/examples").
+ ok
+ 8> ftp:recv(Pid, "appl.erl").
+ ok
+ 9> ftp:stop_service(Pid).
+ ok
+ 10> ftp:stop().
+ ok
+ ]]></code>
+ <p> The file
+ <c>appl.erl</c> is transferred from the remote to the local
+ host. When the session is opened, the current directory at
+ the remote host is <c>/home/guest</c>, and <c>/home/fred</c>
+ at the local host. Before transferring the file, the current
+ local directory is changed to <c>/home/eproj/examples</c>, and
+ the remote directory is set to
+ <c>/home/guest/appl/examples</c>.</p>
+ </section>
+</chapter>
diff --git a/lib/ftp/doc/src/introduction.xml b/lib/ftp/doc/src/introduction.xml
new file mode 100644
index 0000000000..cc3673a0fc
--- /dev/null
+++ b/lib/ftp/doc/src/introduction.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>1997</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Introduction</title>
+ <prepared>Péter Dimitrov</prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date>2018-02-26</date>
+ <rev>A</rev>
+ <file>introduction.xml</file>
+ </header>
+
+ <section>
+ <title>Purpose</title>
+ <p>An <c>FTP</c> client.</p>
+ </section>
+
+ <section>
+ <title>Prerequisites</title>
+ <p>It is assumed that the reader is familiar with the Erlang
+ programming language, concepts of OTP, and has a basic
+ understanding of the FTP protocol.</p>
+ </section>
+</chapter>
diff --git a/lib/ftp/doc/src/notes.xml b/lib/ftp/doc/src/notes.xml
new file mode 100644
index 0000000000..61da079900
--- /dev/null
+++ b/lib/ftp/doc/src/notes.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2002</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>FTP Release Notes</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date>2018-02-26</date>
+ <rev>A</rev>
+ <file>notes.xml</file>
+ </header>
+
+ <section><title>Ftp 1.0.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed timing related bug that could make ftp functions
+ behave badly.</p>
+ <p>
+ Own Id: OTP-15659 Aux Id: ERIERL-316 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ftp 1.0.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>FTP 1.0</title>
+
+ <section><title>First released version</title>
+ <list>
+ <item>
+ <p>
+ Inets application was split into multiple smaller protocol specific applications.
+ The FTP application is a standalone FTP client with the same functionality as
+ FTP client in Inets.</p>
+ <p>
+ Own Id: OTP-14113</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+</chapter>
diff --git a/lib/ftp/doc/src/part.xml b/lib/ftp/doc/src/part.xml
new file mode 100644
index 0000000000..ec05f5ac76
--- /dev/null
+++ b/lib/ftp/doc/src/part.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE part SYSTEM "part.dtd">
+
+<part xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header>
+ <copyright>
+ <year>2004</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>FTP User's Guide</title>
+ <prepared>Péter Dimitrov</prepared>
+ <docno></docno>
+ <date>2018-02-26</date>
+ <rev>A</rev>
+ <file>part.sgml</file>
+ </header>
+ <description>
+ <p>The <c>FTP</c> application provides an FTP client.</p>
+ </description>
+ <xi:include href="introduction.xml"/>
+ <xi:include href="ftp_client.xml"/>
+</part>
diff --git a/lib/ftp/doc/src/ref_man.xml b/lib/ftp/doc/src/ref_man.xml
new file mode 100644
index 0000000000..925842610d
--- /dev/null
+++ b/lib/ftp/doc/src/ref_man.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE application SYSTEM "application.dtd">
+
+<application xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header>
+ <copyright>
+ <year>1997</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>FTP Reference Manual</title>
+ <prepared>Péter Dimitrov</prepared>
+ <docno></docno>
+ <date>2018-03-09</date>
+ <rev>1.0</rev>
+ <file>ref_man.xml</file>
+ </header>
+ <description>
+ <p>An <c>FTP</c> client.</p>
+ </description>
+ <xi:include href="ftp.xml"/>
+</application>
diff --git a/lib/cosEvent/ebin/.gitignore b/lib/ftp/ebin/.gitignore
index e69de29bb2..e69de29bb2 100644
--- a/lib/cosEvent/ebin/.gitignore
+++ b/lib/ftp/ebin/.gitignore
diff --git a/lib/ftp/info b/lib/ftp/info
new file mode 100644
index 0000000000..f6c62d19c2
--- /dev/null
+++ b/lib/ftp/info
@@ -0,0 +1,2 @@
+group: comm
+short: FTP client
diff --git a/lib/ftp/src/Makefile b/lib/ftp/src/Makefile
new file mode 100644
index 0000000000..93e3c4a8e5
--- /dev/null
+++ b/lib/ftp/src/Makefile
@@ -0,0 +1,118 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1999-2018. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# %CopyrightEnd%
+#
+
+#
+
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../vsn.mk
+VSN=$(FTP_VSN)
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/ftp-$(VSN)
+
+# ----------------------------------------------------
+# Common Macros
+# ----------------------------------------------------
+
+BEHAVIOUR_MODULES=
+
+MODULES= \
+ ftp \
+ ftp_app \
+ ftp_progress \
+ ftp_response \
+ ftp_sup
+
+
+INTERNAL_HRL_FILES =
+
+ERL_FILES= \
+ $(MODULES:%=%.erl) \
+ $(BEHAVIOUR_MODULES:%=%.erl)
+
+
+TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+BEHAVIOUR_TARGET_FILES= $(BEHAVIOUR_MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+APP_FILE= ftp.app
+APPUP_FILE= ftp.appup
+
+APP_SRC= $(APP_FILE).src
+APP_TARGET= $(EBIN)/$(APP_FILE)
+APPUP_SRC= $(APPUP_FILE).src
+APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+EXTRA_ERLC_FLAGS = +warn_unused_vars
+ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/kernel/src \
+ -pz $(EBIN) \
+ -pz $(ERL_TOP)/lib/public_key/ebin \
+ $(EXTRA_ERLC_FLAGS) -DVSN=\"$(VSN)\"
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+$(TARGET_FILES): $(BEHAVIOUR_TARGET_FILES)
+
+debug opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
+
+clean:
+ rm -f $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(BEHAVIOUR_TARGET_FILES)
+ rm -f errs core *~
+
+$(APP_TARGET): $(APP_SRC) ../vsn.mk
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
+
+$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
+
+docs:
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec: opt
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(BEHAVIOUR_TARGET_FILES) $(TARGET_FILES) $(APP_TARGET) \
+ $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
+
+release_docs_spec:
+
+# ----------------------------------------------------
+# Dependencies
+# ----------------------------------------------------
+
diff --git a/lib/ftp/src/ftp.app.src b/lib/ftp/src/ftp.app.src
new file mode 100644
index 0000000000..66ccace390
--- /dev/null
+++ b/lib/ftp/src/ftp.app.src
@@ -0,0 +1,19 @@
+{application, ftp,
+ [{description, "FTP client"},
+ {vsn, "%VSN%"},
+ {registered, []},
+ {mod, { ftp_app, []}},
+ {applications,
+ [kernel,
+ stdlib
+ ]},
+ {env,[]},
+ {modules, [
+ ftp,
+ ftp_app,
+ ftp_progress,
+ ftp_response,
+ ftp_sup
+ ]},
+ {runtime_dependencies, ["erts-7.0","stdlib-3.5","kernel-6.0"]}
+ ]}.
diff --git a/lib/ftp/src/ftp.appup.src b/lib/ftp/src/ftp.appup.src
new file mode 100644
index 0000000000..d79c7b60ff
--- /dev/null
+++ b/lib/ftp/src/ftp.appup.src
@@ -0,0 +1,26 @@
+%% -*- erlang -*-
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+{"%VSN%",
+ [
+ {<<".*">>,[{restart_application, ftp}]}
+ ],
+ [
+ {<<".*">>,[{restart_application, ftp}]}
+ ]
+}.
diff --git a/lib/ftp/src/ftp.erl b/lib/ftp/src/ftp.erl
new file mode 100644
index 0000000000..18cd8c7524
--- /dev/null
+++ b/lib/ftp/src/ftp.erl
@@ -0,0 +1,2619 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+-module(ftp).
+
+-behaviour(gen_server).
+
+-export([start/0,
+ start_service/1,
+ stop/0,
+ stop_service/1,
+ services/0,
+ service_info/1
+ ]).
+
+%% Added for backward compatibility
+-export([start_standalone/1]).
+
+-export([start_link/1, start_link/2]).
+
+%% API - Client interface
+-export([cd/2, close/1, delete/2, formaterror/1,
+ lcd/2, lpwd/1, ls/1, ls/2,
+ mkdir/2, nlist/1, nlist/2,
+ open/1, open/2,
+ pwd/1, quote/2,
+ recv/2, recv/3, recv_bin/2,
+ recv_chunk_start/2, recv_chunk/1,
+ rename/3, rmdir/2,
+ send/2, send/3, send_bin/3,
+ send_chunk_start/2, send_chunk/2, send_chunk_end/1,
+ type/2, user/3, user/4, account/2,
+ append/3, append/2, append_bin/3,
+ append_chunk/2, append_chunk_end/1, append_chunk_start/2,
+ info/1, latest_ctrl_response/1]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2,
+ handle_info/2, terminate/2, code_change/3]).
+
+-include("ftp_internal.hrl").
+
+%% Constants used in internal state definition
+-define(CONNECTION_TIMEOUT, 60*1000).
+-define(DATA_ACCEPT_TIMEOUT, infinity).
+-define(DEFAULT_MODE, passive).
+-define(PROGRESS_DEFAULT, ignore).
+-define(FTP_EXT_DEFAULT, false).
+
+%% Internal Constants
+-define(FTP_PORT, 21).
+-define(FILE_BUFSIZE, 4096).
+
+
+%%%=========================================================================
+%%% Data Types
+%%%=========================================================================
+
+%% Internal state
+-record(state, {
+ csock = undefined, % socket() - Control connection socket
+ dsock = undefined, % socket() - Data connection socket
+ tls_options = undefined, % list()
+ verbose = false, % boolean()
+ ldir = undefined, % string() - Current local directory
+ type = ftp_server_default, % atom() - binary | ascii
+ chunk = false, % boolean() - Receiving data chunks
+ mode = ?DEFAULT_MODE, % passive | active
+ timeout = ?CONNECTION_TIMEOUT, % integer()
+ %% Data received so far on the data connection
+ data = <<>>, % binary()
+ %% Data received so far on the control connection
+ %% {BinStream, AccLines}. If a binary sequence
+ %% ends with ?CR then keep it in the binary to
+ %% be able to detect if the next received byte is ?LF
+ %% and hence the end of the response is reached!
+ ctrl_data = {<<>>, [], start}, % {binary(), [bytes()], LineStatus}
+ %% pid() - Client pid (note not the same as "From")
+ latest_ctrl_response = "",
+ owner = undefined,
+ client = undefined, % "From" to be used in gen_server:reply/2
+ %% Function that activated a connection and maybe some
+ %% data needed further on.
+ caller = undefined, % term()
+ ipfamily, % inet | inet6 | inet6fb4
+ sockopts_ctrl = [],
+ sockopts_data_passive = [],
+ sockopts_data_active = [],
+ progress = ignore, % ignore | pid()
+ dtimeout = ?DATA_ACCEPT_TIMEOUT, % non_neg_integer() | infinity
+ tls_upgrading_data_connection = false,
+ ftp_extension = ?FTP_EXT_DEFAULT
+ }).
+
+-record(recv_chunk_closing, {
+ dconn_closed = false,
+ pos_compl_received = false,
+ client_called_us = false
+ }).
+
+
+-type shortage_reason() :: 'etnospc' | 'epnospc'.
+-type restriction_reason() :: 'epath' | 'efnamena' | 'elogin' | 'enotbinary'.
+-type common_reason() :: 'econn' | 'eclosed' | term().
+-type file_write_error_reason() :: term(). % See file:write for more info
+
+-define(DBG(F,A), 'n/a').
+%%-define(DBG(F,A), io:format(F,A)).
+%%-define(DBG(F,A), ct:pal("~p:~p " ++ if is_list(F) -> F; is_atom(F) -> atom_to_list(F) end, [?MODULE,?LINE|A])).
+
+
+%%%=========================================================================
+%%% API
+%%%=========================================================================
+
+start() ->
+ application:start(ftp).
+
+start_standalone(Options) ->
+ try
+ {ok, StartOptions} = start_options(Options),
+ {ok, OpenOptions} = open_options(Options),
+ {ok, SocketOptions} = socket_options(Options),
+ case start_link(StartOptions, []) of
+ {ok, Pid} ->
+ call(Pid, {open, ip_comm, OpenOptions, SocketOptions}, plain);
+ Error1 ->
+ Error1
+ end
+ catch
+ throw:Error2 ->
+ Error2
+ end.
+
+start_service(Options) ->
+ try
+ {ok, StartOptions} = start_options(Options),
+ {ok, OpenOptions} = open_options(Options),
+ {ok, SocketOptions} = socket_options(Options),
+ case ftp_sup:start_child([[[{client, self()} | StartOptions], []]]) of
+ {ok, Pid} ->
+ call(Pid, {open, ip_comm, OpenOptions, SocketOptions}, plain);
+ Error1 ->
+ Error1
+ end
+ catch
+ throw:Error2 ->
+ Error2
+ end.
+
+stop() ->
+ application:stop(ftp).
+
+stop_service(Pid) ->
+ close(Pid).
+
+services() ->
+ [{ftpc, Pid} || {_, Pid, _, _} <-
+ supervisor:which_children(ftp_sup)].
+service_info(Pid) ->
+ {ok, Info} = call(Pid, info, list),
+ {ok, [proplists:lookup(mode, Info),
+ proplists:lookup(local_port, Info),
+ proplists:lookup(peer, Info),
+ proplists:lookup(peer_port, Info)]}.
+
+
+%%%=========================================================================
+%%% API - CLIENT FUNCTIONS
+%%%=========================================================================
+
+%%--------------------------------------------------------------------------
+%% open(HostOrOtpList, <Port>, <Flags>) -> {ok, Pid} | {error, ehost}
+%% HostOrOtpList = string() | [{option_list, Options}]
+%% Port = integer(),
+%% Flags = [Flag],
+%% Flag = verbose | debug | trace
+%%
+%% Description: Start an ftp client and connect to a host.
+%%--------------------------------------------------------------------------
+
+-spec open(Host :: string() | inet:ip_address()) ->
+ {'ok', Pid :: pid()} | {'error', Reason :: 'ehost' | term()}.
+
+%% <BACKWARD-COMPATIBILLITY>
+open({option_list, Options}) when is_list(Options) ->
+ try
+ {ok, StartOptions} = start_options(Options),
+ {ok, OpenOptions} = open_options(Options),
+ {ok, SockOpts} = socket_options(Options),
+ case ftp_sup:start_child([[[{client, self()} | StartOptions], []]]) of
+ {ok, Pid} ->
+ call(Pid, {open, ip_comm, OpenOptions, SockOpts}, plain);
+ Error1 ->
+ Error1
+ end
+ catch
+ throw:Error2 ->
+ Error2
+ end;
+%% </BACKWARD-COMPATIBILLITY>
+
+open(Host) ->
+ open(Host, []).
+
+-spec open(Host :: string() | inet:ip_address(), Opts :: list()) ->
+ {'ok', Pid :: pid()} | {'error', Reason :: 'ehost' | term()}.
+
+%% <BACKWARD-COMPATIBILLITY>
+open(Host, Port) when is_integer(Port) ->
+ open(Host, [{port, Port}]);
+%% </BACKWARD-COMPATIBILLITY>
+
+open(Host, Opts) when is_list(Opts) ->
+ try
+ {ok, StartOptions} = start_options(Opts),
+ {ok, OpenOptions} = open_options([{host, Host}|Opts]),
+ {ok, SocketOptions} = socket_options(Opts),
+ case start_link(StartOptions, []) of
+ {ok, Pid} ->
+ do_open(Pid, OpenOptions, SocketOptions, tls_options(Opts));
+ Error1 ->
+ Error1
+ end
+ catch
+ throw:Error2 ->
+ Error2
+ end.
+
+do_open(Pid, OpenOptions, SocketOptions, TLSOpts) ->
+ case call(Pid, {open, ip_comm, OpenOptions, SocketOptions}, plain) of
+ {ok, Pid} ->
+ maybe_tls_upgrade(Pid, TLSOpts);
+ Error ->
+ Error
+ end.
+%%--------------------------------------------------------------------------
+%% user(Pid, User, Pass, <Acc>) -> ok | {error, euser} | {error, econn}
+%% | {error, eacct}
+%% Pid = pid(),
+%% User = Pass = Acc = string()
+%%
+%% Description: Login with or without a supplied account name.
+%%--------------------------------------------------------------------------
+-spec user(Pid :: pid(),
+ User :: string(),
+ Pass :: string()) ->
+ 'ok' | {'error', Reason :: 'euser' | common_reason()}.
+
+user(Pid, User, Pass) ->
+ case {is_name_sane(User), is_name_sane(Pass)} of
+ {true, true} ->
+ call(Pid, {user, User, Pass}, atom);
+ _ ->
+ {error, euser}
+ end.
+
+-spec user(Pid :: pid(),
+ User :: string(),
+ Pass :: string(),
+ Acc :: string()) ->
+ 'ok' | {'error', Reason :: 'euser' | common_reason()}.
+
+user(Pid, User, Pass, Acc) ->
+ case {is_name_sane(User), is_name_sane(Pass), is_name_sane(Acc)} of
+ {true, true, true} ->
+ call(Pid, {user, User, Pass, Acc}, atom);
+ _ ->
+ {error, euser}
+ end.
+
+
+%%--------------------------------------------------------------------------
+%% account(Pid, Acc) -> ok | {error, eacct}
+%% Pid = pid()
+%% Acc= string()
+%%
+%% Description: Set a user Account.
+%%--------------------------------------------------------------------------
+
+-spec account(Pid :: pid(), Acc :: string()) ->
+ 'ok' | {'error', Reason :: 'eacct' | common_reason()}.
+
+account(Pid, Acc) ->
+ case is_name_sane(Acc) of
+ true ->
+ call(Pid, {account, Acc}, atom);
+ _ ->
+ {error, eacct}
+ end.
+
+
+%%--------------------------------------------------------------------------
+%% pwd(Pid) -> {ok, Dir} | {error, elogin} | {error, econn}
+%% Pid = pid()
+%% Dir = string()
+%%
+%% Description: Get the current working directory at remote server.
+%%--------------------------------------------------------------------------
+
+-spec pwd(Pid :: pid()) ->
+ {'ok', Dir :: string()} |
+ {'error', Reason :: restriction_reason() | common_reason()}.
+
+pwd(Pid) ->
+ call(Pid, pwd, ctrl).
+
+
+%%--------------------------------------------------------------------------
+%% lpwd(Pid) -> {ok, Dir}
+%% Pid = pid()
+%% Dir = string()
+%%
+%% Description: Get the current working directory at local server.
+%%--------------------------------------------------------------------------
+
+-spec lpwd(Pid :: pid()) ->
+ {'ok', Dir :: string()}.
+
+lpwd(Pid) ->
+ call(Pid, lpwd, string).
+
+
+%%--------------------------------------------------------------------------
+%% cd(Pid, Dir) -> ok | {error, epath} | {error, elogin} | {error, econn}
+%% Pid = pid()
+%% Dir = string()
+%%
+%% Description: Change current working directory at remote server.
+%%--------------------------------------------------------------------------
+
+-spec cd(Pid :: pid(), Dir :: string()) ->
+ 'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
+
+cd(Pid, Dir) ->
+ case is_name_sane(Dir) of
+ true ->
+ call(Pid, {cd, Dir}, atom);
+ _ ->
+ {error, efnamena}
+ end.
+
+
+%%--------------------------------------------------------------------------
+%% lcd(Pid, Dir) -> ok | {error, epath}
+%% Pid = pid()
+%% Dir = string()
+%%
+%% Description: Change current working directory for the local client.
+%%--------------------------------------------------------------------------
+
+-spec lcd(Pid :: pid(), Dir :: string()) ->
+ 'ok' | {'error', Reason :: restriction_reason()}.
+
+lcd(Pid, Dir) ->
+ call(Pid, {lcd, Dir}, string).
+
+
+%%--------------------------------------------------------------------------
+%% ls(Pid) -> Result
+%% ls(Pid, <Dir>) -> Result
+%%
+%% Pid = pid()
+%% Dir = string()
+%% Result = {ok, Listing} | {error, Reason}
+%% Listing = string()
+%% Reason = epath | elogin | econn
+%%
+%% Description: Returns a list of files in long format.
+%%--------------------------------------------------------------------------
+
+-spec ls(Pid :: pid()) ->
+ {'ok', Listing :: string()} |
+ {'error', Reason :: restriction_reason() | common_reason()}.
+
+ls(Pid) ->
+ ls(Pid, "").
+
+-spec ls(Pid :: pid(), Dir :: string()) ->
+ {'ok', Listing :: string()} |
+ {'error', Reason :: restriction_reason() | common_reason()}.
+
+ls(Pid, Dir) ->
+ case is_name_sane(Dir) of
+ true ->
+ call(Pid, {dir, long, Dir}, string);
+ _ ->
+ {error, efnamena}
+ end.
+
+
+%%--------------------------------------------------------------------------
+%% nlist(Pid) -> Result
+%% nlist(Pid, Pathname) -> Result
+%%
+%% Pid = pid()
+%% Pathname = string()
+%% Result = {ok, Listing} | {error, Reason}
+%% Listing = string()
+%% Reason = epath | elogin | econn
+%%
+%% Description: Returns a list of files in short format
+%%--------------------------------------------------------------------------
+
+-spec nlist(Pid :: pid()) ->
+ {'ok', Listing :: string()} |
+ {'error', Reason :: restriction_reason() | common_reason()}.
+
+nlist(Pid) ->
+ nlist(Pid, "").
+
+-spec nlist(Pid :: pid(), Pathname :: string()) ->
+ {'ok', Listing :: string()} |
+ {'error', Reason :: restriction_reason() | common_reason()}.
+
+nlist(Pid, Dir) ->
+ case is_name_sane(Dir) of
+ true ->
+ call(Pid, {dir, short, Dir}, string);
+ _ ->
+ {error, efnamena}
+ end.
+
+
+%%--------------------------------------------------------------------------
+%% rename(Pid, Old, New) -> ok | {error, epath} | {error, elogin}
+%% | {error, econn}
+%% Pid = pid()
+%% CurrFile = NewFile = string()
+%%
+%% Description: Rename a file at remote server.
+%%--------------------------------------------------------------------------
+
+-spec rename(Pid :: pid(), Old :: string(), New :: string()) ->
+ 'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
+
+rename(Pid, Old, New) ->
+ case {is_name_sane(Old), is_name_sane(New)} of
+ {true, true} ->
+ call(Pid, {rename, Old, New}, string);
+ _ ->
+ {error, efnamena}
+ end.
+
+
+%%--------------------------------------------------------------------------
+%% delete(Pid, File) -> ok | {error, epath} | {error, elogin} |
+%% {error, econn}
+%% Pid = pid()
+%% File = string()
+%%
+%% Description: Remove file at remote server.
+%%--------------------------------------------------------------------------
+
+-spec delete(Pid :: pid(), File :: string()) ->
+ 'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
+
+delete(Pid, File) ->
+ case is_name_sane(File) of
+ true ->
+ call(Pid, {delete, File}, string);
+ _ ->
+ {error, efnamena}
+ end.
+
+
+%%--------------------------------------------------------------------------
+%% mkdir(Pid, Dir) -> ok | {error, epath} | {error, elogin} | {error, econn}
+%% Pid = pid(),
+%% Dir = string()
+%%
+%% Description: Make directory at remote server.
+%%--------------------------------------------------------------------------
+
+-spec mkdir(Pid :: pid(), Dir :: string()) ->
+ 'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
+
+mkdir(Pid, Dir) ->
+ case is_name_sane(Dir) of
+ true ->
+ call(Pid, {mkdir, Dir}, atom);
+ _ ->
+ {error, efnamena}
+ end.
+
+
+%%--------------------------------------------------------------------------
+%% rmdir(Pid, Dir) -> ok | {error, epath} | {error, elogin} | {error, econn}
+%% Pid = pid(),
+%% Dir = string()
+%%
+%% Description: Remove directory at remote server.
+%%--------------------------------------------------------------------------
+
+-spec rmdir(Pid :: pid(), Dir :: string()) ->
+ 'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
+
+rmdir(Pid, Dir) ->
+ case is_name_sane(Dir) of
+ true ->
+ call(Pid, {rmdir, Dir}, atom);
+ _ ->
+ {error, efnamena}
+ end.
+
+
+%%--------------------------------------------------------------------------
+%% type(Pid, Type) -> ok | {error, etype} | {error, elogin} | {error, econn}
+%% Pid = pid()
+%% Type = ascii | binary
+%%
+%% Description: Set transfer type.
+%%--------------------------------------------------------------------------
+
+-spec type(Pid :: pid(), Type :: ascii | binary) ->
+ 'ok' |
+ {'error', Reason :: 'etype' | restriction_reason() | common_reason()}.
+
+type(Pid, Type) ->
+ call(Pid, {type, Type}, atom).
+
+
+%%--------------------------------------------------------------------------
+%% recv(Pid, RemoteFileName [, LocalFileName]) -> ok | {error, epath} |
+%% {error, elogin} | {error, econn}
+%% Pid = pid()
+%% RemoteFileName = LocalFileName = string()
+%%
+%% Description: Transfer file from remote server.
+%%--------------------------------------------------------------------------
+
+-spec recv(Pid :: pid(), RemoteFileName :: string()) ->
+ 'ok' | {'error', Reason :: restriction_reason() |
+ common_reason() |
+ file_write_error_reason()}.
+
+recv(Pid, RemotFileName) ->
+ recv(Pid, RemotFileName, RemotFileName).
+
+-spec recv(Pid :: pid(),
+ RemoteFileName :: string(),
+ LocalFileName :: string()) ->
+ 'ok' | {'error', Reason :: term()}.
+
+recv(Pid, RemotFileName, LocalFileName) ->
+ case is_name_sane(RemotFileName) of
+ true ->
+ call(Pid, {recv, RemotFileName, LocalFileName}, atom);
+ _ ->
+ {error, efnamena}
+ end.
+
+
+%%--------------------------------------------------------------------------
+%% recv_bin(Pid, RemoteFile) -> {ok, Bin} | {error, epath} | {error, elogin}
+%% | {error, econn}
+%% Pid = pid()
+%% RemoteFile = string()
+%% Bin = binary()
+%%
+%% Description: Transfer file from remote server into binary.
+%%--------------------------------------------------------------------------
+
+-spec recv_bin(Pid :: pid(),
+ RemoteFile :: string()) ->
+ {'ok', Bin :: binary()} |
+ {'error', Reason :: restriction_reason() | common_reason()}.
+
+recv_bin(Pid, RemoteFile) ->
+ case is_name_sane(RemoteFile) of
+ true ->
+ call(Pid, {recv_bin, RemoteFile}, bin);
+ _ ->
+ {error, efnamena}
+ end.
+
+
+%%--------------------------------------------------------------------------
+%% recv_chunk_start(Pid, RemoteFile) -> ok | {error, elogin} | {error, epath}
+%% | {error, econn}
+%% Pid = pid()
+%% RemoteFile = string()
+%%
+%% Description: Start receive of chunks of remote file.
+%%--------------------------------------------------------------------------
+
+-spec recv_chunk_start(Pid :: pid(),
+ RemoteFile :: string()) ->
+ 'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
+
+recv_chunk_start(Pid, RemoteFile) ->
+ case is_name_sane(RemoteFile) of
+ true ->
+ call(Pid, {recv_chunk_start, RemoteFile}, atom);
+ _ ->
+ {error, efnamena}
+ end.
+
+
+%%--------------------------------------------------------------------------
+%% recv_chunk(Pid, RemoteFile) -> ok | {ok, Bin} | {error, Reason}
+%% Pid = pid()
+%% RemoteFile = string()
+%%
+%% Description: Transfer file from remote server into binary in chunks
+%%--------------------------------------------------------------------------
+
+-spec recv_chunk(Pid :: pid()) ->
+ 'ok' |
+ {'ok', Bin :: binary()} |
+ {'error', Reason :: restriction_reason() | common_reason()}.
+
+recv_chunk(Pid) ->
+ call(Pid, recv_chunk, atom).
+
+
+%%--------------------------------------------------------------------------
+%% send(Pid, LocalFileName [, RemotFileName]) -> ok | {error, epath}
+%% | {error, elogin}
+%% | {error, econn}
+%% Pid = pid()
+%% LocalFileName = RemotFileName = string()
+%%
+%% Description: Transfer file to remote server.
+%%--------------------------------------------------------------------------
+
+-spec send(Pid :: pid(), LocalFileName :: string()) ->
+ 'ok' |
+ {'error', Reason :: restriction_reason() |
+ common_reason() |
+ shortage_reason()}.
+
+send(Pid, LocalFileName) ->
+ send(Pid, LocalFileName, LocalFileName).
+
+-spec send(Pid :: pid(),
+ LocalFileName :: string(),
+ RemoteFileName :: string()) ->
+ 'ok' |
+ {'error', Reason :: restriction_reason() |
+ common_reason() |
+ shortage_reason()}.
+
+send(Pid, LocalFileName, RemotFileName) ->
+ case is_name_sane(RemotFileName) of
+ true ->
+ call(Pid, {send, LocalFileName, RemotFileName}, atom);
+ _ ->
+ {error, efnamena}
+ end.
+
+
+%%--------------------------------------------------------------------------
+%% send_bin(Pid, Bin, RemoteFile) -> ok | {error, epath} | {error, elogin}
+%% | {error, enotbinary} | {error, econn}
+%% Pid = pid()
+%% Bin = binary()
+%% RemoteFile = string()
+%%
+%% Description: Transfer a binary to a remote file.
+%%--------------------------------------------------------------------------
+
+-spec send_bin(Pid :: pid(), Bin :: binary(), RemoteFile :: string()) ->
+ 'ok' |
+ {'error', Reason :: restriction_reason() |
+ common_reason() |
+ shortage_reason()}.
+
+send_bin(Pid, Bin, RemoteFile) when is_binary(Bin) ->
+ case is_name_sane(RemoteFile) of
+ true ->
+ call(Pid, {send_bin, Bin, RemoteFile}, atom);
+ _ ->
+ {error, efnamena}
+ end;
+send_bin(_Pid, _Bin, _RemoteFile) ->
+ {error, enotbinary}.
+
+
+%%--------------------------------------------------------------------------
+%% send_chunk_start(Pid, RemoteFile) -> ok | {error, elogin} | {error, epath}
+%% | {error, econn}
+%% Pid = pid()
+%% RemoteFile = string()
+%%
+%% Description: Start transfer of chunks to remote file.
+%%--------------------------------------------------------------------------
+
+-spec send_chunk_start(Pid :: pid(), RemoteFile :: string()) ->
+ 'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
+
+send_chunk_start(Pid, RemoteFile) ->
+ case is_name_sane(RemoteFile) of
+ true ->
+ call(Pid, {send_chunk_start, RemoteFile}, atom);
+ _ ->
+ {error, efnamena}
+ end.
+
+
+%%--------------------------------------------------------------------------
+%% append_chunk_start(Pid, RemoteFile) -> ok | {error, elogin} |
+%% {error, epath} | {error, econn}
+%% Pid = pid()
+%% RemoteFile = string()
+%%
+%% Description: Start append chunks of data to remote file.
+%%--------------------------------------------------------------------------
+
+-spec append_chunk_start(Pid :: pid(), RemoteFile :: string()) ->
+ 'ok' | {'error', Reason :: term()}.
+
+append_chunk_start(Pid, RemoteFile) ->
+ case is_name_sane(RemoteFile) of
+ true ->
+ call(Pid, {append_chunk_start, RemoteFile}, atom);
+ _ ->
+ {error, efnamena}
+ end.
+
+
+%%--------------------------------------------------------------------------
+%% send_chunk(Pid, Bin) -> ok | {error, elogin} | {error, enotbinary}
+%% | {error, echunk} | {error, econn}
+%% Pid = pid()
+%% Bin = binary().
+%%
+%% Purpose: Send chunk to remote file.
+%%--------------------------------------------------------------------------
+
+-spec send_chunk(Pid :: pid(), Bin :: binary()) ->
+ 'ok' |
+ {'error', Reason :: 'echunk' |
+ restriction_reason() |
+ common_reason()}.
+
+send_chunk(Pid, Bin) when is_binary(Bin) ->
+ call(Pid, {transfer_chunk, Bin}, atom);
+send_chunk(_Pid, _Bin) ->
+ {error, enotbinary}.
+
+
+%%--------------------------------------------------------------------------
+%% append_chunk(Pid, Bin) -> ok | {error, elogin} | {error, enotbinary}
+%% | {error, echunk} | {error, econn}
+%% Pid = pid()
+%% Bin = binary()
+%%
+%% Description: Append chunk to remote file.
+%%--------------------------------------------------------------------------
+
+-spec append_chunk(Pid :: pid(), Bin :: binary()) ->
+ 'ok' |
+ {'error', Reason :: 'echunk' |
+ restriction_reason() |
+ common_reason()}.
+
+append_chunk(Pid, Bin) when is_binary(Bin) ->
+ call(Pid, {transfer_chunk, Bin}, atom);
+append_chunk(_Pid, _Bin) ->
+ {error, enotbinary}.
+
+
+%%--------------------------------------------------------------------------
+%% send_chunk_end(Pid) -> ok | {error, elogin} | {error, echunk}
+%% | {error, econn}
+%% Pid = pid()
+%%
+%% Description: End sending of chunks to remote file.
+%%--------------------------------------------------------------------------
+
+-spec send_chunk_end(Pid :: pid()) ->
+ 'ok' |
+ {'error', Reason :: restriction_reason() |
+ common_reason() |
+ shortage_reason()}.
+
+send_chunk_end(Pid) ->
+ call(Pid, chunk_end, atom).
+
+
+%%--------------------------------------------------------------------------
+%% append_chunk_end(Pid) -> ok | {error, elogin} | {error, echunk}
+%% | {error, econn}
+%% Pid = pid()
+%%
+%% Description: End appending of chunks to remote file.
+%%--------------------------------------------------------------------------
+
+-spec append_chunk_end(Pid :: pid()) ->
+ 'ok' |
+ {'error', Reason :: restriction_reason() |
+ common_reason() |
+ shortage_reason()}.
+
+append_chunk_end(Pid) ->
+ call(Pid, chunk_end, atom).
+
+
+%%--------------------------------------------------------------------------
+%% append(Pid, LocalFileName [, RemotFileName]) -> ok | {error, epath}
+%% | {error, elogin}
+%% | {error, econn}
+%% Pid = pid()
+%% LocalFileName = RemotFileName = string()
+%%
+%% Description: Append the local file to the remote file
+%%--------------------------------------------------------------------------
+
+-spec append(Pid :: pid(), LocalFileName :: string()) ->
+ 'ok' |
+ {'error', Reason :: 'epath' |
+ 'elogin' |
+ 'etnospc' |
+ 'epnospc' |
+ 'efnamena' | common_reason()}.
+
+append(Pid, LocalFileName) ->
+ append(Pid, LocalFileName, LocalFileName).
+
+-spec append(Pid :: pid(),
+ LocalFileName :: string(),
+ RemoteFileName :: string()) ->
+ 'ok' | {'error', Reason :: term()}.
+
+append(Pid, LocalFileName, RemotFileName) ->
+ case is_name_sane(RemotFileName) of
+ true ->
+ call(Pid, {append, LocalFileName, RemotFileName}, atom);
+ _ ->
+ {error, efnamena}
+ end.
+
+
+%%--------------------------------------------------------------------------
+%% append_bin(Pid, Bin, RemoteFile) -> ok | {error, epath} | {error, elogin}
+%% | {error, enotbinary} | {error, econn}
+%% Pid = pid()
+%% Bin = binary()
+%% RemoteFile = string()
+%%
+%% Purpose: Append a binary to a remote file.
+%%--------------------------------------------------------------------------
+
+-spec append_bin(Pid :: pid(),
+ Bin :: binary(),
+ RemoteFile :: string()) ->
+ 'ok' |
+ {'error', Reason :: restriction_reason() |
+ common_reason() |
+ shortage_reason()}.
+
+append_bin(Pid, Bin, RemoteFile) when is_binary(Bin) ->
+ case is_name_sane(RemoteFile) of
+ true ->
+ call(Pid, {append_bin, Bin, RemoteFile}, atom);
+ _ ->
+ {error, efnamena}
+ end;
+append_bin(_Pid, _Bin, _RemoteFile) ->
+ {error, enotbinary}.
+
+
+%%--------------------------------------------------------------------------
+%% quote(Pid, Cmd) -> list()
+%% Pid = pid()
+%% Cmd = string()
+%%
+%% Description: Send arbitrary ftp command.
+%%--------------------------------------------------------------------------
+
+-spec quote(Pid :: pid(), Cmd :: string()) -> list().
+
+quote(Pid, Cmd) when is_list(Cmd) ->
+ call(Pid, {quote, Cmd}, atom).
+
+
+%%--------------------------------------------------------------------------
+%% close(Pid) -> ok
+%% Pid = pid()
+%%
+%% Description: End the ftp session.
+%%--------------------------------------------------------------------------
+
+-spec close(Pid :: pid()) -> 'ok'.
+
+close(Pid) ->
+ cast(Pid, close),
+ ok.
+
+
+%%--------------------------------------------------------------------------
+%% formaterror(Tag) -> string()
+%% Tag = atom() | {error, atom()}
+%%
+%% Description: Return diagnostics.
+%%--------------------------------------------------------------------------
+
+-spec formaterror(Tag :: term()) -> string().
+
+formaterror(Tag) ->
+ ftp_response:error_string(Tag).
+
+
+info(Pid) ->
+ call(Pid, info, list).
+
+
+%%--------------------------------------------------------------------------
+%% latest_ctrl_response(Pid) -> string()
+%% Pid = pid()
+%%
+%% Description: The latest received response from the server
+%%--------------------------------------------------------------------------
+
+-spec latest_ctrl_response(Pid :: pid()) -> string().
+
+latest_ctrl_response(Pid) ->
+ call(Pid, latest_ctrl_response, string).
+
+
+%%%========================================================================
+%%% gen_server callback functions
+%%%========================================================================
+
+%%-------------------------------------------------------------------------
+%% init(Args) -> {ok, State} | {ok, State, Timeout} | {stop, Reason}
+%% Description: Initiates the erlang process that manages a ftp connection.
+%%-------------------------------------------------------------------------
+init(Options) ->
+ process_flag(trap_exit, true),
+
+ %% Keep track of the client
+ {value, {client, Client}} = lists:keysearch(client, 1, Options),
+ erlang:monitor(process, Client),
+
+ %% Make sure inet is started
+ _ = inet_db:start(),
+
+ %% Where are we
+ {ok, Dir} = file:get_cwd(),
+
+ %% Maybe activate dbg
+ case key_search(debug, Options, disable) of
+ trace ->
+ dbg:tracer(),
+ dbg:p(all, [call]),
+ {ok, _} = dbg:tpl(ftp, [{'_', [], [{return_trace}]}]),
+ {ok, _} = dbg:tpl(ftp_response, [{'_', [], [{return_trace}]}]),
+ {ok, _} = dbg:tpl(ftp_progress, [{'_', [], [{return_trace}]}]),
+ ok;
+ debug ->
+ dbg:tracer(),
+ dbg:p(all, [call]),
+ {ok, _} = dbg:tp(ftp, [{'_', [], [{return_trace}]}]),
+ {ok, _} = dbg:tp(ftp_response, [{'_', [], [{return_trace}]}]),
+ {ok, _} = dbg:tp(ftp_progress, [{'_', [], [{return_trace}]}]),
+ ok;
+ _ ->
+ %% Keep silent
+ ok
+ end,
+
+ %% Verbose?
+ Verbose = key_search(verbose, Options, false),
+
+ %% IpFamily?
+ IpFamily = key_search(ipfamily, Options, inet),
+
+ State = #state{owner = Client,
+ verbose = Verbose,
+ ipfamily = IpFamily,
+ ldir = Dir},
+
+ %% Set process prio
+ Priority = key_search(priority, Options, low),
+ process_flag(priority, Priority),
+
+ %% And we are done
+ {ok, State}.
+
+
+%%--------------------------------------------------------------------------
+%% handle_call(Request, From, State) -> {reply, Reply, State} |
+%% {reply, Reply, State, Timeout} |
+%% {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, Reply, State} |
+%% Description: Handle incoming requests.
+%%-------------------------------------------------------------------------
+
+%% Anyone can ask this question
+handle_call({_, info}, _, #state{verbose = Verbose,
+ mode = Mode,
+ timeout = Timeout,
+ ipfamily = IpFamily,
+ csock = Socket,
+ progress = Progress} = State) ->
+ {ok, {_, LocalPort}} = sockname(Socket),
+ {ok, {Address, Port}} = peername(Socket),
+ Options = [{verbose, Verbose},
+ {ipfamily, IpFamily},
+ {mode, Mode},
+ {peer, Address},
+ {peer_port, Port},
+ {local_port, LocalPort},
+ {timeout, Timeout},
+ {progress, Progress}],
+ {reply, {ok, Options}, State};
+
+handle_call({_,latest_ctrl_response}, _, #state{latest_ctrl_response=Resp} = State) ->
+ {reply, {ok,Resp}, State};
+
+%% But everything else must come from the owner
+handle_call({Pid, _}, _, #state{owner = Owner} = State) when Owner =/= Pid ->
+ {reply, {error, not_connection_owner}, State};
+
+handle_call({_, {open, ip_comm, Opts, {CtrlOpts, DataPassOpts, DataActOpts}}}, From, State) ->
+ case key_search(host, Opts, undefined) of
+ undefined ->
+ {stop, normal, {error, ehost}, State};
+ Host ->
+ Mode = key_search(mode, Opts, ?DEFAULT_MODE),
+ Port = key_search(port, Opts, ?FTP_PORT),
+ Timeout = key_search(timeout, Opts, ?CONNECTION_TIMEOUT),
+ DTimeout = key_search(dtimeout, Opts, ?DATA_ACCEPT_TIMEOUT),
+ Progress = key_search(progress, Opts, ignore),
+ IpFamily = key_search(ipfamily, Opts, inet),
+ FtpExt = key_search(ftp_extension, Opts, ?FTP_EXT_DEFAULT),
+
+ State2 = State#state{client = From,
+ mode = Mode,
+ progress = progress(Progress),
+ ipfamily = IpFamily,
+ sockopts_ctrl = CtrlOpts,
+ sockopts_data_passive = DataPassOpts,
+ sockopts_data_active = DataActOpts,
+ dtimeout = DTimeout,
+ ftp_extension = FtpExt},
+
+ case setup_ctrl_connection(Host, Port, Timeout, State2) of
+ {ok, State3, WaitTimeout} ->
+ {noreply, State3, WaitTimeout};
+ {error, _Reason} ->
+ gen_server:reply(From, {error, ehost}),
+ {stop, normal, State2#state{client = undefined}}
+ end
+ end;
+
+handle_call({_, {open, tls_upgrade, TLSOptions}}, From, State0) ->
+ _ = send_ctrl_message(State0, mk_cmd("AUTH TLS", [])),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{client = From, caller = open, tls_options = TLSOptions}};
+
+handle_call({_, {user, User, Password}}, From,
+ #state{csock = CSock} = State) when (CSock =/= undefined) ->
+ handle_user(User, Password, "", State#state{client = From});
+
+handle_call({_, {user, User, Password, Acc}}, From,
+ #state{csock = CSock} = State) when (CSock =/= undefined) ->
+ handle_user(User, Password, Acc, State#state{client = From});
+
+handle_call({_, {account, Acc}}, From, State)->
+ handle_user_account(Acc, State#state{client = From});
+
+handle_call({_, pwd}, From, #state{chunk = false} = State0) ->
+ _ = send_ctrl_message(State0, mk_cmd("PWD", [])),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{client = From, caller = pwd}};
+
+handle_call({_, lpwd}, From, #state{ldir = LDir} = State) ->
+ {reply, {ok, LDir}, State#state{client = From}};
+
+handle_call({_, {cd, Dir}}, From, #state{chunk = false} = State0) ->
+ _ = send_ctrl_message(State0, mk_cmd("CWD ~s", [Dir])),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{client = From, caller = cd}};
+
+handle_call({_,{lcd, Dir}}, _From, #state{ldir = LDir0} = State) ->
+ LDir = filename:absname(Dir, LDir0),
+ case file:read_file_info(LDir) of %% FIX better check that LDir is a dir.
+ {ok, _ } ->
+ {reply, ok, State#state{ldir = LDir}};
+ _ ->
+ {reply, {error, epath}, State}
+ end;
+
+handle_call({_, {dir, Len, Dir}}, {_Pid, _} = From,
+ #state{chunk = false} = State) ->
+ setup_data_connection(State#state{caller = {dir, Dir, Len},
+ client = From});
+handle_call({_, {rename, CurrFile, NewFile}}, From,
+ #state{chunk = false} = State0) ->
+ _ = send_ctrl_message(State0, mk_cmd("RNFR ~s", [CurrFile])),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{caller = {rename, NewFile}, client = From}};
+
+handle_call({_, {delete, File}}, {_Pid, _} = From,
+ #state{chunk = false} = State0) ->
+ _ = send_ctrl_message(State0, mk_cmd("DELE ~s", [File])),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{client = From}};
+
+handle_call({_, {mkdir, Dir}}, From, #state{chunk = false} = State0) ->
+ _ = send_ctrl_message(State0, mk_cmd("MKD ~s", [Dir])),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{client = From}};
+
+handle_call({_,{rmdir, Dir}}, From, #state{chunk = false} = State0) ->
+ _ = send_ctrl_message(State0, mk_cmd("RMD ~s", [Dir])),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{client = From}};
+
+handle_call({_,{type, Type}}, From, #state{chunk = false} = State0) ->
+ case Type of
+ ascii ->
+ _ = send_ctrl_message(State0, mk_cmd("TYPE A", [])),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{caller = type, type = ascii,
+ client = From}};
+ binary ->
+ _ = send_ctrl_message(State0, mk_cmd("TYPE I", [])),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{caller = type, type = binary,
+ client = From}};
+ _ ->
+ {reply, {error, etype}, State0}
+ end;
+
+handle_call({_,{recv, RemoteFile, LocalFile}}, From,
+ #state{chunk = false, ldir = LocalDir} = State) ->
+ progress_report({remote_file, RemoteFile}, State),
+ NewLocalFile = filename:absname(LocalFile, LocalDir),
+
+ case file_open(NewLocalFile, write) of
+ {ok, Fd} ->
+ setup_data_connection(State#state{client = From,
+ caller =
+ {recv_file,
+ RemoteFile, Fd}});
+ {error, _What} ->
+ {reply, {error, epath}, State}
+ end;
+
+handle_call({_, {recv_bin, RemoteFile}}, From, #state{chunk = false} =
+ State) ->
+ setup_data_connection(State#state{caller = {recv_bin, RemoteFile},
+ client = From});
+
+handle_call({_,{recv_chunk_start, RemoteFile}}, From, #state{chunk = false}
+ = State) ->
+ setup_data_connection(State#state{caller = {start_chunk_transfer,
+ "RETR", RemoteFile},
+ client = From});
+
+handle_call({_, recv_chunk}, _, #state{chunk = false} = State) ->
+ {reply, {error, "ftp:recv_chunk_start/2 not called"}, State};
+
+handle_call({_, recv_chunk}, _From, #state{chunk = true,
+ caller = #recv_chunk_closing{dconn_closed = true,
+ pos_compl_received = true
+ }
+ } = State0) ->
+ %% The ftp:recv_chunk call was the last event we waited for, finnish and clean up
+ ?DBG("recv_chunk_closing ftp:recv_chunk, last event",[]),
+ State = activate_ctrl_connection(State0),
+ {reply, ok, State#state{caller = undefined,
+ chunk = false,
+ client = undefined}};
+
+handle_call({_, recv_chunk}, From, #state{chunk = true,
+ caller = #recv_chunk_closing{} = R
+ } = State) ->
+ %% Waiting for more, don't care what
+ ?DBG("recv_chunk_closing ftp:recv_chunk, get more",[]),
+ {noreply, State#state{client = From, caller = R#recv_chunk_closing{client_called_us=true}}};
+
+handle_call({_, recv_chunk}, From, #state{chunk = true} = State0) ->
+ State = activate_data_connection(State0),
+ {noreply, State#state{client = From, caller = recv_chunk}};
+
+handle_call({_, {send, LocalFile, RemoteFile}}, From,
+ #state{chunk = false, ldir = LocalDir} = State) ->
+ progress_report({local_file, filename:absname(LocalFile, LocalDir)},
+ State),
+ setup_data_connection(State#state{caller = {transfer_file,
+ {"STOR",
+ LocalFile, RemoteFile}},
+ client = From});
+handle_call({_, {append, LocalFile, RemoteFile}}, From,
+ #state{chunk = false} = State) ->
+ setup_data_connection(State#state{caller = {transfer_file,
+ {"APPE",
+ LocalFile, RemoteFile}},
+ client = From});
+handle_call({_, {send_bin, Bin, RemoteFile}}, From,
+ #state{chunk = false} = State) ->
+ setup_data_connection(State#state{caller = {transfer_data,
+ {"STOR", Bin, RemoteFile}},
+ client = From});
+handle_call({_,{append_bin, Bin, RemoteFile}}, From,
+ #state{chunk = false} = State) ->
+ setup_data_connection(State#state{caller = {transfer_data,
+ {"APPE", Bin, RemoteFile}},
+ client = From});
+handle_call({_, {send_chunk_start, RemoteFile}}, From, #state{chunk = false}
+ = State) ->
+ setup_data_connection(State#state{caller = {start_chunk_transfer,
+ "STOR", RemoteFile},
+ client = From});
+handle_call({_, {append_chunk_start, RemoteFile}}, From, #state{chunk = false}
+ = State) ->
+ setup_data_connection(State#state{caller = {start_chunk_transfer,
+ "APPE", RemoteFile},
+ client = From});
+handle_call({_, {transfer_chunk, Bin}}, _, #state{chunk = true} = State) ->
+ send_data_message(State, Bin),
+ {reply, ok, State};
+
+handle_call({_, {transfer_chunk, _}}, _, #state{chunk = false} = State) ->
+ {reply, {error, echunk}, State};
+
+handle_call({_, chunk_end}, From, #state{chunk = true} = State0) ->
+ close_data_connection(State0),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{client = From, dsock = undefined,
+ caller = end_chunk_transfer, chunk = false}};
+
+handle_call({_, chunk_end}, _, #state{chunk = false} = State) ->
+ {reply, {error, echunk}, State};
+
+handle_call({_, {quote, Cmd}}, From, #state{chunk = false} = State0) ->
+ _ = send_ctrl_message(State0, mk_cmd(Cmd, [])),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{client = From, caller = quote}};
+
+handle_call({_, _Req}, _From, #state{csock = CSock} = State)
+ when (CSock =:= undefined) ->
+ {reply, {error, not_connected}, State};
+
+handle_call(_, _, #state{chunk = true} = State) ->
+ {reply, {error, echunk}, State};
+
+%% Catch all - This can only happen if the application programmer writes
+%% really bad code that violates the API.
+handle_call(Request, _Timeout, State) ->
+ {stop, {'API_violation_connection_closed', Request},
+ {error, {connection_terminated, 'API_violation'}}, State}.
+
+%%--------------------------------------------------------------------------
+%% handle_cast(Request, State) -> {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State}
+%% Description: Handles cast messages.
+%%-------------------------------------------------------------------------
+handle_cast({Pid, close}, #state{owner = Pid} = State) ->
+ _ = send_ctrl_message(State, mk_cmd("QUIT", [])),
+ close_ctrl_connection(State),
+ close_data_connection(State),
+ {stop, normal, State#state{csock = undefined, dsock = undefined}};
+
+handle_cast({Pid, close}, State) ->
+ Report = io_lib:format("A none owner process ~p tried to close an "
+ "ftp connection: ~n", [Pid]),
+ error_logger:info_report(Report),
+ {noreply, State};
+
+%% Catch all - This can oly happen if the application programmer writes
+%% really bad code that violates the API.
+handle_cast(Msg, State) ->
+ {stop, {'API_violation_connection_closed', Msg}, State}.
+
+%%--------------------------------------------------------------------------
+%% handle_info(Msg, State) -> {noreply, State} | {noreply, State, Timeout} |
+%% {stop, Reason, State}
+%% Description: Handles tcp messages from the ftp-server.
+%% Note: The order of the function clauses is significant.
+%%--------------------------------------------------------------------------
+
+handle_info(timeout, #state{caller = open} = State) ->
+ {stop, timeout, State};
+
+handle_info(timeout, State) ->
+ {noreply, State};
+
+%%% Data socket messages %%%
+handle_info({Trpt, Socket, Data},
+ #state{dsock = {Trpt,Socket},
+ caller = {recv_file, Fd}} = State0) when Trpt==tcp;Trpt==ssl ->
+ ?DBG('L~p --data ~p ----> ~s~p~n',[?LINE,Socket,Data,State0]),
+ ok = file_write(binary_to_list(Data), Fd),
+ progress_report({binary, Data}, State0),
+ State = activate_data_connection(State0),
+ {noreply, State};
+
+handle_info({Trpt, Socket, Data}, #state{dsock = {Trpt,Socket}, client = From,
+ caller = recv_chunk}
+ = State) when Trpt==tcp;Trpt==ssl ->
+ ?DBG('L~p --data ~p ----> ~s~p~n',[?LINE,Socket,Data,State]),
+ gen_server:reply(From, {ok, Data}),
+ {noreply, State#state{client = undefined, data = <<>>}};
+
+handle_info({Trpt, Socket, Data}, #state{dsock = {Trpt,Socket}} = State0) when Trpt==tcp;Trpt==ssl ->
+ ?DBG('L~p --data ~p ----> ~s~p~n',[?LINE,Socket,Data,State0]),
+ State = activate_data_connection(State0),
+ {noreply, State#state{data = <<(State#state.data)/binary,
+ Data/binary>>}};
+
+handle_info({Cls, Socket}, #state{dsock = {Trpt,Socket},
+ caller = {recv_file, Fd}} = State0)
+ when {Cls,Trpt}=={tcp_closed,tcp} ; {Cls,Trpt}=={ssl_closed,ssl} ->
+ file_close(Fd),
+ progress_report({transfer_size, 0}, State0),
+ State = activate_ctrl_connection(State0),
+ ?DBG("Data channel close",[]),
+ {noreply, State#state{dsock = undefined, data = <<>>}};
+
+handle_info({Cls, Socket}, #state{dsock = {Trpt,Socket},
+ client = Client,
+ caller = recv_chunk} = State0)
+ when {Cls,Trpt}=={tcp_closed,tcp} ; {Cls,Trpt}=={ssl_closed,ssl} ->
+ ?DBG("Data channel close recv_chunk",[]),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{dsock = undefined,
+ caller = #recv_chunk_closing{dconn_closed = true,
+ client_called_us = Client =/= undefined}
+ }};
+
+handle_info({Cls, Socket}, #state{dsock = {Trpt,Socket}, caller = recv_bin,
+ data = Data} = State0)
+ when {Cls,Trpt}=={tcp_closed,tcp} ; {Cls,Trpt}=={ssl_closed,ssl} ->
+ ?DBG("Data channel close",[]),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{dsock = undefined, data = <<>>,
+ caller = {recv_bin, Data}}};
+
+handle_info({Cls, Socket}, #state{dsock = {Trpt,Socket}, data = Data,
+ caller = {handle_dir_result, Dir}}
+ = State0) when {Cls,Trpt}=={tcp_closed,tcp} ; {Cls,Trpt}=={ssl_closed,ssl} ->
+ ?DBG("Data channel close",[]),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{dsock = undefined,
+ caller = {handle_dir_result, Dir, Data},
+% data = <<?CR,?LF>>}};
+ data = <<>>}};
+
+handle_info({Err, Socket, Reason}, #state{dsock = {Trpt,Socket},
+ client = From} = State)
+ when {Err,Trpt}=={tcp_error,tcp} ; {Err,Trpt}=={ssl_error,ssl} ->
+ gen_server:reply(From, {error, Reason}),
+ close_data_connection(State),
+ {noreply, State#state{dsock = undefined, client = undefined,
+ data = <<>>, caller = undefined, chunk = false}};
+
+%%% Ctrl socket messages %%%
+handle_info({Transport, Socket, Data}, #state{csock = {Transport, Socket},
+ verbose = Verbose,
+ caller = Caller,
+ client = From,
+ ctrl_data = {CtrlData, AccLines,
+ LineStatus}}
+ = State0) ->
+ ?DBG('--ctrl ~p ----> ~s~p~n',[Socket,<<CtrlData/binary, Data/binary>>,State]),
+ case ftp_response:parse_lines(<<CtrlData/binary, Data/binary>>,
+ AccLines, LineStatus) of
+ {ok, Lines, NextMsgData} ->
+ verbose(Lines, Verbose, 'receive'),
+ CtrlResult = ftp_response:interpret(Lines),
+ case Caller of
+ quote ->
+ gen_server:reply(From, string:tokens(Lines, [?CR, ?LF])),
+ {noreply, State0#state{client = undefined,
+ caller = undefined,
+ latest_ctrl_response = Lines,
+ ctrl_data = {NextMsgData, [],
+ start}}};
+ _ ->
+ ?DBG(' ...handle_ctrl_result(~p,...) ctrl_data=~p~n',[CtrlResult,{NextMsgData, [], start}]),
+ handle_ctrl_result(CtrlResult,
+ State0#state{latest_ctrl_response = Lines,
+ ctrl_data =
+ {NextMsgData, [], start}})
+ end;
+ {continue, NewCtrlData} ->
+ ?DBG(' ...Continue... ctrl_data=~p~n',[NewCtrlData]),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{ctrl_data = NewCtrlData}}
+ end;
+
+%% If the server closes the control channel it is
+%% the expected behavior that connection process terminates.
+handle_info({Cls, Socket}, #state{csock = {Trpt, Socket}})
+ when {Cls,Trpt}=={tcp_closed,tcp} ; {Cls,Trpt}=={ssl_closed,ssl} ->
+ exit(normal); %% User will get error message from terminate/2
+
+handle_info({Err, Socket, Reason}, _) when Err==tcp_error ; Err==ssl_error ->
+ Report =
+ io_lib:format("~p on socket: ~p for reason: ~p~n",
+ [Err, Socket, Reason]),
+ error_logger:error_report(Report),
+ %% If tcp does not work the only option is to terminate,
+ %% this is the expected behavior under these circumstances.
+ exit(normal); %% User will get error message from terminate/2
+
+%% Monitor messages - if the process owning the ftp connection goes
+%% down there is no point in continuing.
+handle_info({'DOWN', _Ref, _Type, _Process, normal}, State) ->
+ {stop, normal, State#state{client = undefined}};
+
+handle_info({'DOWN', _Ref, _Type, _Process, shutdown}, State) ->
+ {stop, normal, State#state{client = undefined}};
+
+handle_info({'DOWN', _Ref, _Type, _Process, timeout}, State) ->
+ {stop, normal, State#state{client = undefined}};
+
+handle_info({'DOWN', _Ref, _Type, Process, Reason}, State) ->
+ {stop, {stopped, {'EXIT', Process, Reason}},
+ State#state{client = undefined}};
+
+handle_info({'EXIT', Pid, Reason}, #state{progress = Pid} = State) ->
+ Report = io_lib:format("Progress reporting stopped for reason ~p~n",
+ [Reason]),
+ error_logger:info_report(Report),
+ {noreply, State#state{progress = ignore}};
+
+%% Catch all - throws away unknown messages (This could happen by "accident"
+%% so we do not want to crash, but we make a log entry as it is an
+%% unwanted behaviour.)
+handle_info(Info, State) ->
+ Report = io_lib:format("ftp : ~p : Unexpected message: ~p~nState: ~p~n",
+ [self(), Info, State]),
+ error_logger:info_report(Report),
+ {noreply, State}.
+
+%%--------------------------------------------------------------------------
+%% terminate/2 and code_change/3
+%%--------------------------------------------------------------------------
+terminate(normal, State) ->
+ %% If terminate reason =/= normal the progress reporting process will
+ %% be killed by the exit signal.
+ progress_report(stop, State),
+ do_terminate({error, econn}, State);
+terminate(Reason, State) ->
+ Report = io_lib:format("Ftp connection closed due to: ~p~n", [Reason]),
+ error_logger:error_report(Report),
+ do_terminate({error, eclosed}, State).
+
+do_terminate(ErrorMsg, State) ->
+ close_data_connection(State),
+ close_ctrl_connection(State),
+ case State#state.client of
+ undefined ->
+ ok;
+ From ->
+ gen_server:reply(From, ErrorMsg)
+ end,
+ ok.
+
+code_change(_Vsn, State1, upgrade_from_pre_5_12) ->
+ {state, CSock, DSock, Verbose, LDir, Type, Chunk, Mode, Timeout,
+ Data, CtrlData, Owner, Client, Caller, IPv6Disable, Progress} = State1,
+ IpFamily =
+ if
+ (IPv6Disable =:= true) ->
+ inet;
+ true ->
+ inet6fb4
+ end,
+ State2 = #state{csock = CSock,
+ dsock = DSock,
+ verbose = Verbose,
+ ldir = LDir,
+ type = Type,
+ chunk = Chunk,
+ mode = Mode,
+ timeout = Timeout,
+ data = Data,
+ ctrl_data = CtrlData,
+ owner = Owner,
+ client = Client,
+ caller = Caller,
+ ipfamily = IpFamily,
+ progress = Progress},
+ {ok, State2};
+
+code_change(_Vsn, State1, downgrade_to_pre_5_12) ->
+ #state{csock = CSock,
+ dsock = DSock,
+ verbose = Verbose,
+ ldir = LDir,
+ type = Type,
+ chunk = Chunk,
+ mode = Mode,
+ timeout = Timeout,
+ data = Data,
+ ctrl_data = CtrlData,
+ owner = Owner,
+ client = Client,
+ caller = Caller,
+ ipfamily = IpFamily,
+ progress = Progress} = State1,
+ IPv6Disable =
+ if
+ (IpFamily =:= inet) ->
+ true;
+ true ->
+ false
+ end,
+ State2 =
+ {state, CSock, DSock, Verbose, LDir, Type, Chunk, Mode, Timeout,
+ Data, CtrlData, Owner, Client, Caller, IPv6Disable, Progress},
+ {ok, State2};
+
+code_change(_Vsn, State, _Extra) ->
+ {ok, State}.
+
+
+%%%=========================================================================
+%% Start/stop
+%%%=========================================================================
+%%--------------------------------------------------------------------------
+%% start_link([Opts, GenServerOptions]) -> {ok, Pid} | {error, Reason}
+%%
+%% Description: Callback function for the ftp supervisor. It is called
+%% : when start_service/1 calls ftp_sup:start_child/1 to start an
+%% : instance of the ftp process. Also called by start_standalone/1
+%%--------------------------------------------------------------------------
+start_link([Opts, GenServerOptions]) ->
+ start_link(Opts, GenServerOptions).
+
+start_link(Opts, GenServerOptions) ->
+ case lists:keysearch(client, 1, Opts) of
+ {value, _} ->
+ %% Via the supervisor
+ gen_server:start_link(?MODULE, Opts, GenServerOptions);
+ false ->
+ Opts2 = [{client, self()} | Opts],
+ gen_server:start_link(?MODULE, Opts2, GenServerOptions)
+ end.
+
+
+%%% Stop functionality is handled by close/1
+
+%%%========================================================================
+%%% Internal functions
+%%%========================================================================
+
+%%--------------------------------------------------------------------------
+%%% Help functions to handle_call and/or handle_ctrl_result
+%%--------------------------------------------------------------------------
+%% User handling
+handle_user(User, Password, Acc, State0) ->
+ _ = send_ctrl_message(State0, mk_cmd("USER ~s", [User])),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{caller = {handle_user, Password, Acc}}}.
+
+handle_user_passwd(Password, Acc, State0) ->
+ _ = send_ctrl_message(State0, mk_cmd("PASS ~s", [Password])),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{caller = {handle_user_passwd, Acc}}}.
+
+handle_user_account(Acc, State0) ->
+ _ = send_ctrl_message(State0, mk_cmd("ACCT ~s", [Acc])),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{caller = handle_user_account}}.
+
+
+%%--------------------------------------------------------------------------
+%% handle_ctrl_result
+%%--------------------------------------------------------------------------
+handle_ctrl_result({tls_upgrade, _}, #state{csock = {tcp, Socket},
+ tls_options = TLSOptions,
+ timeout = Timeout,
+ caller = open, client = From}
+ = State0) ->
+ ?DBG('<--ctrl ssl:connect(~p, ~p)~n~p~n',[Socket,TLSOptions,State0]),
+ case ssl:connect(Socket, TLSOptions, Timeout) of
+ {ok, TLSSocket} ->
+ State1 = State0#state{csock = {ssl,TLSSocket}},
+ _ = send_ctrl_message(State1, mk_cmd("PBSZ 0", [])),
+ State = activate_ctrl_connection(State1),
+ {noreply, State#state{tls_upgrading_data_connection = {true, pbsz}} };
+ {error, _} = Error ->
+ gen_server:reply(From, {Error, self()}),
+ {stop, normal, State0#state{client = undefined,
+ caller = undefined,
+ tls_upgrading_data_connection = false}}
+ end;
+
+handle_ctrl_result({pos_compl, _}, #state{tls_upgrading_data_connection = {true, pbsz}} = State0) ->
+ _ = send_ctrl_message(State0, mk_cmd("PROT P", [])),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{tls_upgrading_data_connection = {true, prot}}};
+
+handle_ctrl_result({pos_compl, _}, #state{tls_upgrading_data_connection = {true, prot},
+ client = From} = State) ->
+ gen_server:reply(From, {ok, self()}),
+ {noreply, State#state{client = undefined,
+ caller = undefined,
+ tls_upgrading_data_connection = false}};
+
+handle_ctrl_result({pos_compl, _}, #state{caller = open, client = From}
+ = State) ->
+ gen_server:reply(From, {ok, self()}),
+ {noreply, State#state{client = undefined,
+ caller = undefined }};
+handle_ctrl_result({_, Lines}, #state{caller = open} = State) ->
+ ctrl_result_response(econn, State, {error, Lines});
+
+%%--------------------------------------------------------------------------
+%% Data connection setup active mode
+handle_ctrl_result({pos_compl, _Lines},
+ #state{mode = active,
+ caller = {setup_data_connection,
+ {LSock, Caller}}} = State) ->
+ handle_caller(State#state{caller = Caller, dsock = {lsock, LSock}});
+
+handle_ctrl_result({Status, _Lines},
+ #state{mode = active,
+ caller = {setup_data_connection, {LSock, _}}}
+ = State) ->
+ close_connection({tcp,LSock}),
+ ctrl_result_response(Status, State, {error, Status});
+
+%% Data connection setup passive mode
+handle_ctrl_result({pos_compl, Lines},
+ #state{mode = passive,
+ ipfamily = inet6,
+ client = From,
+ caller = {setup_data_connection, Caller},
+ csock = CSock,
+ sockopts_data_passive = SockOpts,
+ timeout = Timeout}
+ = State) ->
+ [_, PortStr | _] = lists:reverse(string:tokens(Lines, "|")),
+ {ok, {IP, _}} = peername(CSock),
+ case connect(IP, list_to_integer(PortStr), SockOpts, Timeout, State) of
+ {ok, _, Socket} ->
+ handle_caller(State#state{caller = Caller, dsock = {tcp, Socket}});
+ {error, _Reason} = Error ->
+ gen_server:reply(From, Error),
+ {noreply, State#state{client = undefined, caller = undefined}}
+ end;
+
+handle_ctrl_result({pos_compl, Lines},
+ #state{mode = passive,
+ ipfamily = inet,
+ client = From,
+ caller = {setup_data_connection, Caller},
+ timeout = Timeout,
+ sockopts_data_passive = SockOpts,
+ ftp_extension = false} = State) ->
+
+ {_, [?LEFT_PAREN | Rest]} =
+ lists:splitwith(fun(?LEFT_PAREN) -> false; (_) -> true end, Lines),
+ {NewPortAddr, _} =
+ lists:splitwith(fun(?RIGHT_PAREN) -> false; (_) -> true end, Rest),
+ [A1, A2, A3, A4, P1, P2] =
+ lists:map(fun(X) -> list_to_integer(X) end,
+ string:tokens(NewPortAddr, [$,])),
+ IP = {A1, A2, A3, A4},
+ Port = (P1 * 256) + P2,
+
+ ?DBG('<--data tcp connect to ~p:~p, Caller=~p~n',[IP,Port,Caller]),
+ case connect(IP, Port, SockOpts, Timeout, State) of
+ {ok, _, Socket} ->
+ handle_caller(State#state{caller = Caller, dsock = {tcp,Socket}});
+ {error, _Reason} = Error ->
+ gen_server:reply(From, Error),
+ {noreply,State#state{client = undefined, caller = undefined}}
+ end;
+
+handle_ctrl_result({pos_compl, Lines},
+ #state{mode = passive,
+ ipfamily = inet,
+ client = From,
+ caller = {setup_data_connection, Caller},
+ csock = CSock,
+ timeout = Timeout,
+ sockopts_data_passive = SockOpts,
+ ftp_extension = true} = State) ->
+
+ [_, PortStr | _] = lists:reverse(string:tokens(Lines, "|")),
+ {ok, {IP, _}} = peername(CSock),
+
+ ?DBG('<--data tcp connect to ~p:~p, Caller=~p~n',[IP,PortStr,Caller]),
+ case connect(IP, list_to_integer(PortStr), SockOpts, Timeout, State) of
+ {ok, _, Socket} ->
+ handle_caller(State#state{caller = Caller, dsock = {tcp, Socket}});
+ {error, _Reason} = Error ->
+ gen_server:reply(From, Error),
+ {noreply, State#state{client = undefined, caller = undefined}}
+ end;
+
+
+%% FTP server does not support passive mode: try to fallback on active mode
+handle_ctrl_result(_,
+ #state{mode = passive,
+ caller = {setup_data_connection, Caller}} = State) ->
+ setup_data_connection(State#state{mode = active, caller = Caller});
+
+
+%%--------------------------------------------------------------------------
+%% User handling
+handle_ctrl_result({pos_interm, _},
+ #state{caller = {handle_user, PassWord, Acc}} = State) ->
+ handle_user_passwd(PassWord, Acc, State);
+handle_ctrl_result({Status, _},
+ #state{caller = {handle_user, _, _}} = State) ->
+ ctrl_result_response(Status, State, {error, euser});
+
+%% Accounts
+handle_ctrl_result({pos_interm_acct, _},
+ #state{caller = {handle_user_passwd, Acc}} = State)
+ when Acc =/= "" ->
+ handle_user_account(Acc, State);
+handle_ctrl_result({Status, _},
+ #state{caller = {handle_user_passwd, _}} = State) ->
+ ctrl_result_response(Status, State, {error, euser});
+
+%%--------------------------------------------------------------------------
+%% Print current working directory
+handle_ctrl_result({pos_compl, Lines},
+ #state{caller = pwd, client = From} = State) ->
+ Dir = pwd_result(Lines),
+ gen_server:reply(From, {ok, Dir}),
+ {noreply, State#state{client = undefined, caller = undefined}};
+
+%%--------------------------------------------------------------------------
+%% Directory listing
+handle_ctrl_result({pos_prel, _}, #state{caller = {dir, Dir}} = State0) ->
+ case accept_data_connection(State0) of
+ {ok, State1} ->
+ State = activate_data_connection(State1),
+ {noreply, State#state{caller = {handle_dir_result, Dir}}};
+ {error, _Reason} = ERROR ->
+ case State0#state.client of
+ undefined ->
+ {stop, ERROR, State0};
+ From ->
+ gen_server:reply(From, ERROR),
+ {stop, normal, State0#state{client = undefined}}
+ end
+ end;
+
+handle_ctrl_result({pos_compl, _}, #state{caller = {handle_dir_result, Dir,
+ Data}, client = From}
+ = State) ->
+ case Dir of
+ "" -> % Current directory
+ gen_server:reply(From, {ok, Data}),
+ {noreply, State#state{client = undefined,
+ caller = undefined}};
+ _ ->
+ %% <WTF>
+ %% Dir cannot be assumed to be a dir. It is a string that
+ %% could be a dir, but could also be a file or even a string
+ %% containing wildcards (*).
+ %%
+ %% %% If there is only one line it might be a directory with one
+ %% %% file but it might be an error message that the directory
+ %% %% was not found. So in this case we have to endure a little
+ %% %% overhead to be able to give a good return value. Alas not
+ %% %% all ftp implementations behave the same and returning
+ %% %% an error string is allowed by the FTP RFC.
+ %% case lists:dropwhile(fun(?CR) -> false;(_) -> true end,
+ %% binary_to_list(Data)) of
+ %% L when (L =:= [?CR, ?LF]) orelse (L =:= []) ->
+ %% send_ctrl_message(State, mk_cmd("PWD", [])),
+ %% activate_ctrl_connection(State),
+ %% {noreply,
+ %% State#state{caller = {handle_dir_data, Dir, Data}}};
+ %% _ ->
+ %% gen_server:reply(From, {ok, Data}),
+ %% {noreply, State#state{client = undefined,
+ %% caller = undefined}}
+ %% end
+ %% </WTF>
+ gen_server:reply(From, {ok, Data}),
+ {noreply, State#state{client = undefined,
+ caller = undefined}}
+ end;
+
+handle_ctrl_result({pos_compl, Lines},
+ #state{caller = {handle_dir_data, Dir, DirData}} =
+ State0) ->
+ OldDir = pwd_result(Lines),
+ _ = send_ctrl_message(State0, mk_cmd("CWD ~s", [Dir])),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{caller = {handle_dir_data_second_phase, OldDir,
+ DirData}}};
+handle_ctrl_result({Status, _},
+ #state{caller = {handle_dir_data, _, _}} = State) ->
+ ctrl_result_response(Status, State, {error, epath});
+
+handle_ctrl_result(S={_Status, _},
+ #state{caller = {handle_dir_result, _, _}} = State) ->
+ %% OTP-5731, macosx
+ ctrl_result_response(S, State, {error, epath});
+
+handle_ctrl_result({pos_compl, _},
+ #state{caller = {handle_dir_data_second_phase, OldDir,
+ DirData}} = State0) ->
+ _ = send_ctrl_message(State0, mk_cmd("CWD ~s", [OldDir])),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{caller = {handle_dir_data_third_phase, DirData}}};
+handle_ctrl_result({Status, _},
+ #state{caller = {handle_dir_data_second_phase, _, _}}
+ = State) ->
+ ctrl_result_response(Status, State, {error, epath});
+handle_ctrl_result(_, #state{caller = {handle_dir_data_third_phase, DirData},
+ client = From} = State) ->
+ gen_server:reply(From, {ok, DirData}),
+ {noreply, State#state{client = undefined, caller = undefined}};
+
+handle_ctrl_result({Status, _}, #state{caller = cd} = State) ->
+ ctrl_result_response(Status, State, {error, Status});
+
+handle_ctrl_result(Status={epath, _}, #state{caller = {dir,_}} = State) ->
+ ctrl_result_response(Status, State, {error, epath});
+
+%%--------------------------------------------------------------------------
+%% File renaming
+handle_ctrl_result({pos_interm, _}, #state{caller = {rename, NewFile}}
+ = State0) ->
+ _ = send_ctrl_message(State0, mk_cmd("RNTO ~s", [NewFile])),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{caller = rename_second_phase}};
+
+handle_ctrl_result({Status, _},
+ #state{caller = {rename, _}} = State) ->
+ ctrl_result_response(Status, State, {error, Status});
+
+handle_ctrl_result({Status, _},
+ #state{caller = rename_second_phase} = State) ->
+ ctrl_result_response(Status, State, {error, Status});
+
+%%--------------------------------------------------------------------------
+%% File handling - recv_bin
+handle_ctrl_result({pos_prel, _}, #state{caller = recv_bin} = State0) ->
+ case accept_data_connection(State0) of
+ {ok, State1} ->
+ State = activate_data_connection(State1),
+ {noreply, State};
+ {error, _Reason} = ERROR ->
+ case State0#state.client of
+ undefined ->
+ {stop, ERROR, State0};
+ From ->
+ gen_server:reply(From, ERROR),
+ {stop, normal, State0#state{client = undefined}}
+ end
+ end;
+
+handle_ctrl_result({pos_compl, _}, #state{caller = {recv_bin, Data},
+ client = From} = State) ->
+ gen_server:reply(From, {ok, Data}),
+ close_data_connection(State),
+ {noreply, State#state{client = undefined, caller = undefined}};
+
+handle_ctrl_result({Status, _}, #state{caller = recv_bin} = State) ->
+ close_data_connection(State),
+ ctrl_result_response(Status, State#state{dsock = undefined},
+ {error, epath});
+
+handle_ctrl_result({Status, _}, #state{caller = {recv_bin, _}} = State) ->
+ close_data_connection(State),
+ ctrl_result_response(Status, State#state{dsock = undefined},
+ {error, epath});
+%%--------------------------------------------------------------------------
+%% File handling - start_chunk_transfer
+handle_ctrl_result({pos_prel, _}, #state{client = From,
+ caller = start_chunk_transfer}
+ = State0) ->
+ case accept_data_connection(State0) of
+ {ok, State1} ->
+ State = start_chunk(State1),
+ {noreply, State};
+ {error, _Reason} = ERROR ->
+ case State0#state.client of
+ undefined ->
+ {stop, ERROR, State0};
+ From ->
+ gen_server:reply(From, ERROR),
+ {stop, normal, State0#state{client = undefined}}
+ end
+ end;
+
+%%--------------------------------------------------------------------------
+%% File handling - chunk_transfer complete
+
+handle_ctrl_result({pos_compl, _}, #state{client = From,
+ caller = #recv_chunk_closing{dconn_closed = true,
+ client_called_us = true,
+ pos_compl_received = false
+ }}
+ = State0) when From =/= undefined ->
+ %% The pos_compl was the last event we waited for, finnish and clean up
+ ?DBG("recv_chunk_closing pos_compl, last event",[]),
+ gen_server:reply(From, ok),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{caller = undefined,
+ chunk = false,
+ client = undefined}};
+
+handle_ctrl_result({pos_compl, _}, #state{caller = #recv_chunk_closing{}=R}
+ = State0) ->
+ %% Waiting for more, don't care what
+ ?DBG("recv_chunk_closing pos_compl, wait more",[]),
+ {noreply, State0#state{caller = R#recv_chunk_closing{pos_compl_received=true}}};
+
+
+%%--------------------------------------------------------------------------
+%% File handling - recv_file
+handle_ctrl_result({pos_prel, _}, #state{caller = {recv_file, _}} = State0) ->
+ case accept_data_connection(State0) of
+ {ok, State1} ->
+ State = activate_data_connection(State1),
+ {noreply, State};
+ {error, _Reason} = ERROR ->
+ case State0#state.client of
+ undefined ->
+ {stop, ERROR, State0};
+ From ->
+ gen_server:reply(From, ERROR),
+ {stop, normal, State0#state{client = undefined}}
+ end
+ end;
+
+handle_ctrl_result({Status, _}, #state{caller = {recv_file, Fd}} = State) ->
+ file_close(Fd),
+ close_data_connection(State),
+ ctrl_result_response(Status, State#state{dsock = undefined},
+ {error, epath});
+%%--------------------------------------------------------------------------
+%% File handling - transfer_*
+handle_ctrl_result({pos_prel, _}, #state{caller = {transfer_file, Fd}}
+ = State0) ->
+ case accept_data_connection(State0) of
+ {ok, State1} ->
+ send_file(State1, Fd);
+ {error, _Reason} = ERROR ->
+ case State0#state.client of
+ undefined ->
+ {stop, ERROR, State0};
+ From ->
+ gen_server:reply(From, ERROR),
+ {stop, normal, State0#state{client = undefined}}
+ end
+ end;
+
+handle_ctrl_result({pos_prel, _}, #state{caller = {transfer_data, Bin}}
+ = State0) ->
+ case accept_data_connection(State0) of
+ {ok, State} ->
+ send_bin(State, Bin);
+ {error, _Reason} = ERROR ->
+ case State0#state.client of
+ undefined ->
+ {stop, ERROR, State0};
+ From ->
+ gen_server:reply(From, ERROR),
+ {stop, normal, State0#state{client = undefined}}
+ end
+ end;
+
+%%--------------------------------------------------------------------------
+%% Default
+handle_ctrl_result({Status, _Lines}, #state{client = From} = State)
+ when From =/= undefined ->
+ ctrl_result_response(Status, State, {error, Status}).
+
+%%--------------------------------------------------------------------------
+%% Help functions to handle_ctrl_result
+%%--------------------------------------------------------------------------
+ctrl_result_response(pos_compl, #state{client = From} = State, _) ->
+ gen_server:reply(From, ok),
+ {noreply, State#state{client = undefined, caller = undefined}};
+
+ctrl_result_response(enofile, #state{client = From} = State, _) ->
+ gen_server:reply(From, {error, enofile}),
+ {noreply, State#state{client = undefined, caller = undefined}};
+
+ctrl_result_response(Status, #state{client = From} = State, _)
+ when (Status =:= etnospc) orelse
+ (Status =:= epnospc) orelse
+ (Status =:= efnamena) orelse
+ (Status =:= econn) ->
+ gen_server:reply(From, {error, Status}),
+%% {stop, normal, {error, Status}, State#state{client = undefined}};
+ {stop, normal, State#state{client = undefined}};
+
+ctrl_result_response(_, #state{client = From} = State, ErrorMsg) ->
+ gen_server:reply(From, ErrorMsg),
+ {noreply, State#state{client = undefined, caller = undefined}}.
+
+%%--------------------------------------------------------------------------
+handle_caller(#state{caller = {dir, Dir, Len}} = State0) ->
+ Cmd = case Len of
+ short -> "NLST";
+ long -> "LIST"
+ end,
+ _ = case Dir of
+ "" ->
+ send_ctrl_message(State0, mk_cmd(Cmd, ""));
+ _ ->
+ send_ctrl_message(State0, mk_cmd(Cmd ++ " ~s", [Dir]))
+ end,
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{caller = {dir, Dir}}};
+
+handle_caller(#state{caller = {recv_bin, RemoteFile}} = State0) ->
+ _ = send_ctrl_message(State0, mk_cmd("RETR ~s", [RemoteFile])),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{caller = recv_bin}};
+
+handle_caller(#state{caller = {start_chunk_transfer, Cmd, RemoteFile}} =
+ State0) ->
+ _ = send_ctrl_message(State0, mk_cmd("~s ~s", [Cmd, RemoteFile])),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{caller = start_chunk_transfer}};
+
+handle_caller(#state{caller = {recv_file, RemoteFile, Fd}} = State0) ->
+ _ = send_ctrl_message(State0, mk_cmd("RETR ~s", [RemoteFile])),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{caller = {recv_file, Fd}}};
+
+handle_caller(#state{caller = {transfer_file, {Cmd, LocalFile, RemoteFile}},
+ ldir = LocalDir, client = From} = State0) ->
+ case file_open(filename:absname(LocalFile, LocalDir), read) of
+ {ok, Fd} ->
+ _ = send_ctrl_message(State0, mk_cmd("~s ~s", [Cmd, RemoteFile])),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{caller = {transfer_file, Fd}}};
+ {error, _} ->
+ gen_server:reply(From, {error, epath}),
+ {noreply, State0#state{client = undefined, caller = undefined,
+ dsock = undefined}}
+ end;
+
+handle_caller(#state{caller = {transfer_data, {Cmd, Bin, RemoteFile}}} =
+ State0) ->
+ _ = send_ctrl_message(State0, mk_cmd("~s ~s", [Cmd, RemoteFile])),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{caller = {transfer_data, Bin}}}.
+
+%% ----------- FTP SERVER COMMUNICATION -------------------------
+
+%% Connect to FTP server at Host (default is TCP port 21)
+%% in order to establish a control connection.
+setup_ctrl_connection(Host, Port, Timeout, #state{sockopts_ctrl = SockOpts} = State0) ->
+ MsTime = erlang:monotonic_time(),
+ case connect(Host, Port, SockOpts, Timeout, State0) of
+ {ok, IpFam, CSock} ->
+ State1 = State0#state{csock = {tcp, CSock}, ipfamily = IpFam},
+ State = activate_ctrl_connection(State1),
+ case Timeout - millisec_passed(MsTime) of
+ Timeout2 when (Timeout2 >= 0) ->
+ {ok, State#state{caller = open}, Timeout2};
+ _ ->
+ %% Oups: Simulate timeout
+ {ok, State#state{caller = open}, 0}
+ end;
+ Error ->
+ Error
+ end.
+
+setup_data_connection(#state{mode = active,
+ caller = Caller,
+ csock = CSock,
+ sockopts_data_active = SockOpts,
+ ftp_extension = FtpExt} = State0) ->
+ case (catch sockname(CSock)) of
+ {ok, {{_, _, _, _, _, _, _, _} = IP0, _}} ->
+ IP = proplists:get_value(ip, SockOpts, IP0),
+ {ok, LSock} =
+ gen_tcp:listen(0, [{ip, IP}, {active, false},
+ inet6, binary, {packet, 0} |
+ lists:keydelete(ip,1,SockOpts)]),
+ {ok, {_, Port}} = sockname({tcp,LSock}),
+ IpAddress = inet_parse:ntoa(IP),
+ Cmd = mk_cmd("EPRT |2|~s|~p|", [IpAddress, Port]),
+ _ = send_ctrl_message(State0, Cmd),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{caller = {setup_data_connection,
+ {LSock, Caller}}}};
+ {ok, {{_,_,_,_} = IP0, _}} ->
+ IP = proplists:get_value(ip, SockOpts, IP0),
+ {ok, LSock} = gen_tcp:listen(0, [{ip, IP}, {active, false},
+ binary, {packet, 0} |
+ lists:keydelete(ip,1,SockOpts)]),
+ {ok, Port} = inet:port(LSock),
+ _ = case FtpExt of
+ false ->
+ {IP1, IP2, IP3, IP4} = IP,
+ {Port1, Port2} = {Port div 256, Port rem 256},
+ send_ctrl_message(State0,
+ mk_cmd("PORT ~w,~w,~w,~w,~w,~w",
+ [IP1, IP2, IP3, IP4, Port1, Port2]));
+ true ->
+ IpAddress = inet_parse:ntoa(IP),
+ Cmd = mk_cmd("EPRT |1|~s|~p|", [IpAddress, Port]),
+ send_ctrl_message(State0, Cmd)
+ end,
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{caller = {setup_data_connection,
+ {LSock, Caller}}}}
+ end;
+
+setup_data_connection(#state{mode = passive, ipfamily = inet6,
+ caller = Caller} = State0) ->
+ _ = send_ctrl_message(State0, mk_cmd("EPSV", [])),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{caller = {setup_data_connection, Caller}}};
+
+setup_data_connection(#state{mode = passive, ipfamily = inet,
+ caller = Caller,
+ ftp_extension = false} = State0) ->
+ _ = send_ctrl_message(State0, mk_cmd("PASV", [])),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{caller = {setup_data_connection, Caller}}};
+
+setup_data_connection(#state{mode = passive, ipfamily = inet,
+ caller = Caller,
+ ftp_extension = true} = State0) ->
+ _ = send_ctrl_message(State0, mk_cmd("EPSV", [])),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{caller = {setup_data_connection, Caller}}}.
+
+connect(Host, Port, SockOpts, Timeout, #state{ipfamily = inet = IpFam}) ->
+ connect2(Host, Port, IpFam, SockOpts, Timeout);
+
+connect(Host, Port, SockOpts, Timeout, #state{ipfamily = inet6 = IpFam}) ->
+ connect2(Host, Port, IpFam, SockOpts, Timeout);
+
+connect(Host, Port, SockOpts, Timeout, #state{ipfamily = inet6fb4}) ->
+ case inet:getaddr(Host, inet6) of
+ {ok, {0, 0, 0, 0, 0, 16#ffff, _, _} = IPv6} ->
+ case inet:getaddr(Host, inet) of
+ {ok, IPv4} ->
+ IpFam = inet,
+ connect2(IPv4, Port, IpFam, SockOpts, Timeout);
+
+ _ ->
+ IpFam = inet6,
+ connect2(IPv6, Port, IpFam, SockOpts, Timeout)
+ end;
+
+ {ok, IPv6} ->
+ IpFam = inet6,
+ connect2(IPv6, Port, IpFam, SockOpts, Timeout);
+
+ _ ->
+ case inet:getaddr(Host, inet) of
+ {ok, IPv4} ->
+ IpFam = inet,
+ connect2(IPv4, Port, IpFam, SockOpts, Timeout);
+ Error ->
+ Error
+ end
+ end.
+
+connect2(Host, Port, IpFam, SockOpts, Timeout) ->
+ Opts = [IpFam, binary, {packet, 0}, {active, false} | SockOpts],
+ case gen_tcp:connect(Host, Port, Opts, Timeout) of
+ {ok, Sock} ->
+ {ok, IpFam, Sock};
+ Error ->
+ Error
+ end.
+
+
+accept_data_connection(#state{mode = active,
+ dtimeout = DTimeout,
+ tls_options = TLSOptions,
+ dsock = {lsock, LSock}} = State0) ->
+ case gen_tcp:accept(LSock, DTimeout) of
+ {ok, Socket} when is_list(TLSOptions) ->
+ gen_tcp:close(LSock),
+ ?DBG('<--data ssl:connect(~p, ~p)~n~p~n',[Socket,TLSOptions,State0]),
+ case ssl:connect(Socket, TLSOptions, DTimeout) of
+ {ok, TLSSocket} ->
+ {ok, State0#state{dsock={ssl,TLSSocket}}};
+ {error, Reason} ->
+ {error, {ssl_connect_failed, Reason}}
+ end;
+ {ok, Socket} ->
+ gen_tcp:close(LSock),
+ {ok, State0#state{dsock={tcp,Socket}}};
+ {error, Reason} ->
+ {error, {data_connect_failed, Reason}}
+ end;
+
+accept_data_connection(#state{mode = passive,
+ dtimeout = DTimeout,
+ dsock = {tcp,Socket},
+ tls_options = TLSOptions} = State) when is_list(TLSOptions) ->
+ ?DBG('<--data ssl:connect(~p, ~p)~n~p~n',[Socket,TLSOptions,State]),
+ case ssl:connect(Socket, TLSOptions, DTimeout) of
+ {ok, TLSSocket} ->
+ {ok, State#state{dsock={ssl,TLSSocket}}};
+ {error, Reason} ->
+ {error, {ssl_connect_failed, Reason}}
+ end;
+accept_data_connection(#state{mode = passive} = State) ->
+ {ok,State}.
+
+
+send_ctrl_message(_S=#state{csock = Socket, verbose = Verbose}, Message) ->
+ verbose(lists:flatten(Message),Verbose,send),
+ ?DBG('<--ctrl ~p ---- ~s~p~n',[Socket,Message,_S]),
+ _ = send_message(Socket, Message).
+
+send_data_message(_S=#state{dsock = Socket}, Message) ->
+ ?DBG('<==data ~p ==== ~s~n~p~n',[Socket,Message,_S]),
+ case send_message(Socket, Message) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ Report = io_lib:format("send/2 for socket ~p failed with "
+ "reason ~p~n", [Socket, Reason]),
+ error_logger:error_report(Report),
+ %% If tcp/ssl does not work the only option is to terminate,
+ %% this is the expected behavior under these circumstances.
+ exit(normal) %% User will get error message from terminate/2
+ end.
+
+send_message({tcp, Socket}, Message) ->
+ gen_tcp:send(Socket, Message);
+send_message({ssl, Socket}, Message) ->
+ ssl:send(Socket, Message).
+
+activate_ctrl_connection(#state{csock = CSock, ctrl_data = {<<>>, _, _}} = State) ->
+ activate_connection(CSock),
+ State;
+activate_ctrl_connection(#state{csock = CSock} = State0) ->
+ activate_connection(CSock),
+ %% We have already received at least part of the next control message,
+ %% that has been saved in ctrl_data, process this first.
+ {noreply, State} = handle_info({socket_type(CSock), unwrap_socket(CSock), <<>>}, State0),
+ State.
+
+activate_data_connection(#state{dsock = DSock} = State) ->
+ activate_connection(DSock),
+ State.
+
+activate_connection(Socket) ->
+ ignore_return_value(
+ case socket_type(Socket) of
+ tcp -> inet:setopts(unwrap_socket(Socket), [{active, once}]);
+ ssl -> ssl:setopts(unwrap_socket(Socket), [{active, once}])
+ end).
+
+
+ignore_return_value(_) -> ok.
+
+unwrap_socket({tcp,Socket}) -> Socket;
+unwrap_socket({ssl,Socket}) -> Socket.
+
+socket_type({tcp,_Socket}) -> tcp;
+socket_type({ssl,_Socket}) -> ssl.
+
+close_ctrl_connection(#state{csock = undefined}) -> ok;
+close_ctrl_connection(#state{csock = Socket}) -> close_connection(Socket).
+
+close_data_connection(#state{dsock = undefined}) -> ok;
+close_data_connection(#state{dsock = Socket}) -> close_connection(Socket).
+
+close_connection({lsock,Socket}) -> ignore_return_value( gen_tcp:close(Socket) );
+close_connection({tcp, Socket}) -> ignore_return_value( gen_tcp:close(Socket) );
+close_connection({ssl, Socket}) -> ignore_return_value( ssl:close(Socket) ).
+
+%% ------------ FILE HANDLING ----------------------------------------
+send_file(#state{tls_upgrading_data_connection = {true, CTRL, _}} = State, Fd) ->
+ {noreply, State#state{tls_upgrading_data_connection = {true, CTRL, ?MODULE, send_file, Fd}}};
+send_file(State0, Fd) ->
+ case file_read(Fd) of
+ {ok, N, Bin} when N > 0 ->
+ send_data_message(State0, Bin),
+ progress_report({binary, Bin}, State0),
+ send_file(State0, Fd);
+ {ok, _, _} ->
+ file_close(Fd),
+ close_data_connection(State0),
+ progress_report({transfer_size, 0}, State0),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{caller = transfer_file_second_phase,
+ dsock = undefined}};
+ {error, Reason} ->
+ gen_server:reply(State0#state.client, {error, Reason}),
+ {stop, normal, State0#state{client = undefined}}
+ end.
+
+file_open(File, Option) ->
+ file:open(File, [raw, binary, Option]).
+
+file_close(Fd) ->
+ ignore_return_value( file:close(Fd) ).
+
+file_read(Fd) ->
+ case file:read(Fd, ?FILE_BUFSIZE) of
+ {ok, Bytes} ->
+ {ok, size(Bytes), Bytes};
+ eof ->
+ {ok, 0, []};
+ Other ->
+ Other
+ end.
+
+file_write(Bytes, Fd) ->
+ file:write(Fd, Bytes).
+
+%% -------------- MISC ----------------------------------------------
+
+call(GenServer, Msg, Format) ->
+ call(GenServer, Msg, Format, infinity).
+call(GenServer, Msg, Format, Timeout) ->
+ Req = {self(), Msg},
+ case (catch gen_server:call(GenServer, Req, Timeout)) of
+ {ok, Bin} when is_binary(Bin) andalso (Format =:= string) ->
+ {ok, binary_to_list(Bin)};
+ {'EXIT', _} ->
+ {error, eclosed};
+ Result ->
+ Result
+ end.
+
+cast(GenServer, Msg) ->
+ gen_server:cast(GenServer, {self(), Msg}).
+
+send_bin(#state{tls_upgrading_data_connection = {true, CTRL, _}} = State, Bin) ->
+ State#state{tls_upgrading_data_connection = {true, CTRL, ?MODULE, send_bin, Bin}};
+send_bin(State0, Bin) ->
+ send_data_message(State0, Bin),
+ close_data_connection(State0),
+ State = activate_ctrl_connection(State0),
+ {noreply, State#state{caller = transfer_data_second_phase,
+ dsock = undefined}}.
+
+mk_cmd(Fmt, Args) ->
+ [io_lib:format(Fmt, Args)| [?CR, ?LF]]. % Deep list ok.
+
+is_name_sane([]) ->
+ true;
+is_name_sane([?CR| _]) ->
+ false;
+is_name_sane([?LF| _]) ->
+ false;
+is_name_sane([_| Rest]) ->
+ is_name_sane(Rest).
+
+pwd_result(Lines) ->
+ {_, [?DOUBLE_QUOTE | Rest]} =
+ lists:splitwith(fun(?DOUBLE_QUOTE) -> false; (_) -> true end, Lines),
+ {Dir, _} =
+ lists:splitwith(fun(?DOUBLE_QUOTE) -> false; (_) -> true end, Rest),
+ Dir.
+
+
+key_search(Key, List, Default) ->
+ case lists:keysearch(Key, 1, List) of
+ {value, {_,Val}} ->
+ Val;
+ false ->
+ Default
+ end.
+
+verbose(Lines, true, Direction) ->
+ DirStr =
+ case Direction of
+ send ->
+ "Sending: ";
+ _ ->
+ "Receiving: "
+ end,
+ Str = string:strip(string:strip(Lines, right, ?LF), right, ?CR),
+ erlang:display(DirStr++Str);
+verbose(_, false,_) ->
+ ok.
+
+progress(Options) ->
+ ftp_progress:start_link(Options).
+
+progress_report(_, #state{progress = ignore}) ->
+ ok;
+progress_report(stop, #state{progress = ProgressPid}) ->
+ ftp_progress:stop(ProgressPid);
+progress_report({binary, Data}, #state{progress = ProgressPid}) ->
+ ftp_progress:report(ProgressPid, {transfer_size, size(Data)});
+progress_report(Report, #state{progress = ProgressPid}) ->
+ ftp_progress:report(ProgressPid, Report).
+
+
+peername({tcp, Socket}) -> inet:peername(Socket);
+peername({ssl, Socket}) -> ssl:peername(Socket).
+
+sockname({tcp, Socket}) -> inet:sockname(Socket);
+sockname({ssl, Socket}) -> ssl:sockname(Socket).
+
+maybe_tls_upgrade(Pid, undefined) ->
+ {ok, Pid};
+maybe_tls_upgrade(Pid, TLSOptions) ->
+ catch ssl:start(),
+ call(Pid, {open, tls_upgrade, TLSOptions}, plain).
+
+start_chunk(#state{tls_upgrading_data_connection = {true, CTRL, _}} = State) ->
+ State#state{tls_upgrading_data_connection = {true, CTRL, ?MODULE, start_chunk, undefined}};
+start_chunk(#state{client = From} = State) ->
+ gen_server:reply(From, ok),
+ State#state{chunk = true,
+ client = undefined,
+ caller = undefined}.
+
+
+%% This function extracts the start options from the
+%% Valid options:
+%% debug,
+%% verbose
+%% ipfamily
+%% priority
+%% flags (for backward compatibillity)
+start_options(Options) ->
+ case lists:keysearch(flags, 1, Options) of
+ {value, {flags, Flags}} ->
+ Verbose = lists:member(verbose, Flags),
+ IsTrace = lists:member(trace, Flags),
+ IsDebug = lists:member(debug, Flags),
+ DebugLevel =
+ if
+ (IsTrace =:= true) ->
+ trace;
+ IsDebug =:= true ->
+ debug;
+ true ->
+ disable
+ end,
+ {ok, [{verbose, Verbose},
+ {debug, DebugLevel},
+ {priority, low}]};
+ false ->
+ ValidateVerbose =
+ fun(true) -> true;
+ (false) -> true;
+ (_) -> false
+ end,
+ ValidateDebug =
+ fun(trace) -> true;
+ (debug) -> true;
+ (disable) -> true;
+ (_) -> false
+ end,
+ ValidatePriority =
+ fun(low) -> true;
+ (normal) -> true;
+ (high) -> true;
+ (_) -> false
+ end,
+ ValidOptions =
+ [{verbose, ValidateVerbose, false, false},
+ {debug, ValidateDebug, false, disable},
+ {priority, ValidatePriority, false, low}],
+ validate_options(Options, ValidOptions, [])
+ end.
+
+
+%% This function extracts and validates the open options from the
+%% Valid options:
+%% mode
+%% host
+%% port
+%% timeout
+%% dtimeout
+%% progress
+%% ftp_extension
+
+open_options(Options) ->
+ ValidateMode =
+ fun(active) -> true;
+ (passive) -> true;
+ (_) -> false
+ end,
+ ValidateHost =
+ fun(Host) when is_list(Host) ->
+ true;
+ (Host) when is_tuple(Host) andalso
+ ((size(Host) =:= 4) orelse (size(Host) =:= 8)) ->
+ true;
+ (_) ->
+ false
+ end,
+ ValidatePort =
+ fun(Port) when is_integer(Port) andalso (Port > 0) -> true;
+ (_) -> false
+ end,
+ ValidateIpFamily =
+ fun(inet) -> true;
+ (inet6) -> true;
+ (inet6fb4) -> true;
+ (_) -> false
+ end,
+ ValidateTimeout =
+ fun(Timeout) when is_integer(Timeout) andalso (Timeout >= 0) -> true;
+ (_) -> false
+ end,
+ ValidateDTimeout =
+ fun(DTimeout) when is_integer(DTimeout) andalso (DTimeout >= 0) -> true;
+ (infinity) -> true;
+ (_) -> false
+ end,
+ ValidateProgress =
+ fun(ignore) ->
+ true;
+ ({Mod, Func, _InitProgress}) when is_atom(Mod) andalso
+ is_atom(Func) ->
+ true;
+ (_) ->
+ false
+ end,
+ ValidateFtpExtension =
+ fun(true) -> true;
+ (false) -> true;
+ (_) -> false
+ end,
+ ValidOptions =
+ [{mode, ValidateMode, false, ?DEFAULT_MODE},
+ {host, ValidateHost, true, ehost},
+ {port, ValidatePort, false, ?FTP_PORT},
+ {ipfamily, ValidateIpFamily, false, inet},
+ {timeout, ValidateTimeout, false, ?CONNECTION_TIMEOUT},
+ {dtimeout, ValidateDTimeout, false, ?DATA_ACCEPT_TIMEOUT},
+ {progress, ValidateProgress, false, ?PROGRESS_DEFAULT},
+ {ftp_extension, ValidateFtpExtension, false, ?FTP_EXT_DEFAULT}],
+ validate_options(Options, ValidOptions, []).
+
+socket_options(Options) ->
+ CtrlOpts = proplists:get_value(sock_ctrl, Options, []),
+ DataActOpts = proplists:get_value(sock_data_act, Options, CtrlOpts),
+ DataPassOpts = proplists:get_value(sock_data_pass, Options, CtrlOpts),
+ case [O || O <- lists:usort(CtrlOpts++DataPassOpts++DataActOpts),
+ not valid_socket_option(O)] of
+ [] ->
+ {ok, {CtrlOpts, DataPassOpts, DataActOpts}};
+ Invalid ->
+ throw({error,{sock_opts,Invalid}})
+ end.
+
+
+valid_socket_option(inet ) -> false;
+valid_socket_option(inet6 ) -> false;
+valid_socket_option({ipv6_v6only, _}) -> false;
+valid_socket_option({active,_} ) -> false;
+valid_socket_option({packet,_} ) -> false;
+valid_socket_option({mode,_} ) -> false;
+valid_socket_option(binary ) -> false;
+valid_socket_option(list ) -> false;
+valid_socket_option({header,_} ) -> false;
+valid_socket_option({packet_size,_} ) -> false;
+valid_socket_option(_) -> true.
+
+
+tls_options(Options) ->
+ %% Options will be validated by ssl application
+ proplists:get_value(tls, Options, undefined).
+
+validate_options([], [], Acc) ->
+ {ok, lists:reverse(Acc)};
+validate_options([], ValidOptions, Acc) ->
+ %% Check if any mandatory options are missing!
+ case [{Key, Reason} || {Key, _, true, Reason} <- ValidOptions] of
+ [] ->
+ Defaults =
+ [{Key, Default} || {Key, _, _, Default} <- ValidOptions],
+ {ok, lists:reverse(Defaults ++ Acc)};
+ [{_, Reason}|_Missing] ->
+ throw({error, Reason})
+ end;
+validate_options([{Key, Value}|Options], ValidOptions, Acc) ->
+ case lists:keysearch(Key, 1, ValidOptions) of
+ {value, {Key, Validate, _, Default}} ->
+ case (catch Validate(Value)) of
+ true ->
+ NewValidOptions = lists:keydelete(Key, 1, ValidOptions),
+ validate_options(Options, NewValidOptions,
+ [{Key, Value} | Acc]);
+ _ ->
+ NewValidOptions = lists:keydelete(Key, 1, ValidOptions),
+ validate_options(Options, NewValidOptions,
+ [{Key, Default} | Acc])
+ end;
+ false ->
+ validate_options(Options, ValidOptions, Acc)
+ end;
+validate_options([_|Options], ValidOptions, Acc) ->
+ validate_options(Options, ValidOptions, Acc).
+
+%% Help function, elapsed milliseconds since T0
+millisec_passed(T0) ->
+ %% OTP 18
+ erlang:convert_time_unit(erlang:monotonic_time() - T0,
+ native,
+ micro_seconds) div 1000.
diff --git a/lib/ftp/src/ftp_app.erl b/lib/ftp/src/ftp_app.erl
new file mode 100644
index 0000000000..d647d9fce3
--- /dev/null
+++ b/lib/ftp/src/ftp_app.erl
@@ -0,0 +1,47 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+%%%-------------------------------------------------------------------
+%% @doc ftp public API
+%% @end
+%%%-------------------------------------------------------------------
+
+-module(ftp_app).
+
+-behaviour(application).
+
+%% Application callbacks
+-export([start/2, stop/1]).
+
+%%====================================================================
+%% API
+%%====================================================================
+
+start(_StartType, _StartArgs) ->
+ ftp_sup:start_link().
+
+%%--------------------------------------------------------------------
+stop(_State) ->
+ ok.
+
+%%====================================================================
+%% Internal functions
+%%====================================================================
diff --git a/lib/ftp/src/ftp_internal.hrl b/lib/ftp/src/ftp_internal.hrl
new file mode 100644
index 0000000000..84f980e8fd
--- /dev/null
+++ b/lib/ftp/src/ftp_internal.hrl
@@ -0,0 +1,35 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+-ifndef(ftp_internal_hrl).
+-define(ftp_internal_hrl, true).
+
+-define(CR, $\r).
+-define(LF, $\n).
+-define(CRLF, [$\r,$\n]).
+-define(SP, $\s).
+-define(TAB, $\t).
+-define(LEFT_PAREN, $().
+-define(RIGHT_PAREN, $)).
+-define(WHITE_SPACE, $ ).
+-define(DOUBLE_QUOTE, $").
+
+-endif. % -ifdef(ftp_internal_hrl).
diff --git a/lib/ftp/src/ftp_progress.erl b/lib/ftp/src/ftp_progress.erl
new file mode 100644
index 0000000000..64c612519d
--- /dev/null
+++ b/lib/ftp/src/ftp_progress.erl
@@ -0,0 +1,136 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+%% Description: This module impements a temporary process that
+%% performes progress reporting during file transfer calling a user
+%% defined callback function. Its life span is as long as the ftp connection
+%% processes that spawned it lives. The purpose of this process is to
+%% shild the ftp connection process from errors and time consuming operations
+%% in the user defined callback function.
+
+-module(ftp_progress).
+
+%% Internal API
+-export([start_link/1, report/2, stop/1]).
+
+%% Spawn export
+-export([init/1]).
+
+-include_lib("kernel/include/file.hrl").
+
+-record(progress, {
+ file :: string() | 'undefined',
+ cb_module :: module(),
+ cb_function :: atom(),
+ init_progress_term :: term(),
+ current_progress_term :: term()
+ }).
+
+%%%=========================================================================
+%%% Internal application API
+%%%=========================================================================
+%%--------------------------------------------------------------------------
+%% start_link(Options) -> ignore | pid()
+%% Options = ignore | {CBModule, CBFunction, InitProgressTerm}
+%%
+%% Description: Starts the progress report process unless progress reporting
+%% should not be performed.
+%%--------------------------------------------------------------------------
+-type options() :: 'ignore' | {module(), atom(), term()}.
+-spec start_link(options()) -> 'ignore' | pid().
+start_link(ignore) ->
+ ignore;
+start_link(Options) ->
+ spawn_link(?MODULE, init, [Options]).
+
+%%--------------------------------------------------------------------------
+%% report_progress(Pid, Report) -> ok
+%% Pid = pid()
+%% Report = {local_file, File} | {remote_file, File} |
+%% {transfer_size, Size}
+%% Size = integer()
+%%
+%% Description: Reports progress to the reporting process that calls the
+%% user defined callback function.
+%%--------------------------------------------------------------------------
+-type report() :: {'local_file', string()} | {'remote_file', string()}
+ | {'transfer_size', non_neg_integer()}.
+-spec report(pid(), report()) -> 'ok'.
+report(Pid, Report) ->
+ Pid ! {progress_report, Report},
+ ok.
+
+%%--------------------------------------------------------------------------
+%% stop(Pid) -> ok
+%% Pid = pid()
+%%
+%% Description:
+%%--------------------------------------------------------------------------
+-spec stop(pid()) -> 'ok'.
+stop(Pid) ->
+ Pid ! stop,
+ ok.
+
+%%%=========================================================================
+%%% Internal functions
+%%%=========================================================================
+init(Options) ->
+ loop(progress(Options)).
+
+loop(Progress) ->
+ receive
+ {progress_report, Report} ->
+ NewProgress = report_progress(Report, Progress),
+ loop(NewProgress);
+ stop ->
+ ok
+ end.
+
+progress({CBModule, CBFunction, InitProgressTerm}) when is_atom(CBModule),
+ is_atom(CBFunction) ->
+ #progress{cb_module = CBModule,
+ cb_function = CBFunction,
+ init_progress_term = InitProgressTerm,
+ current_progress_term = InitProgressTerm}.
+
+report_progress({local_file, File}, Progress) ->
+ {ok, FileInfo} = file:read_file_info(File),
+ report_progress({file_size, FileInfo#file_info.size},
+ Progress#progress{file = File});
+
+report_progress({remote_file, File}, Progress) ->
+ report_progress({file_size, unknown}, Progress#progress{file = File});
+
+report_progress(Size, #progress{file = File,
+ cb_module = CBModule,
+ cb_function = CBFunction,
+ current_progress_term = Term,
+ init_progress_term = InitTerm} = Progress) ->
+
+ NewProgressTerm = CBModule:CBFunction(Term, File, Size),
+
+ case Size of
+ {transfer_size, 0} ->
+ %% Transfer is compleat reset initial values
+ Progress#progress{current_progress_term = InitTerm,
+ file = undefined};
+ _ ->
+ Progress#progress{current_progress_term = NewProgressTerm}
+ end.
diff --git a/lib/ftp/src/ftp_response.erl b/lib/ftp/src/ftp_response.erl
new file mode 100644
index 0000000000..8d00153ba8
--- /dev/null
+++ b/lib/ftp/src/ftp_response.erl
@@ -0,0 +1,203 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+%% Description: This module impements handling of ftp server responses.
+
+-module(ftp_response).
+
+%% Internal API
+-export([parse_lines/3, interpret/1, error_string/1]).
+
+-include("ftp_internal.hrl").
+
+%% First group of reply code digits
+-define(POS_PREL, 1).
+-define(POS_COMPL, 2).
+-define(POS_INTERM, 3).
+-define(TRANS_NEG_COMPL, 4).
+-define(PERM_NEG_COMPL, 5).
+%% Second group of reply code digits
+-define(SYNTAX,0).
+-define(INFORMATION,1).
+-define(CONNECTION,2).
+-define(AUTH_ACC,3).
+-define(UNSPEC,4).
+-define(FILE_SYSTEM,5).
+
+%%%=========================================================================
+%%% INTERNAL API
+%%%=========================================================================
+
+%%--------------------------------------------------------------------------
+%% parse_lines(Data, AccLines, StatusCode) -> {ok, Lines} |
+%% {continue, {Data,
+%% AccLines, StatusCode}}
+%%
+%% Data = binary() - data recived on the control connection from the
+%% ftp-server.
+%% AccLines = [string()]
+%% StatusCode = start | {byte(), byte(), byte()} | finish -
+%% Indicates where in the parsing process we are.
+%% start - (looking for the status code of the message)
+%% {byte(), byte(), byte()} - status code found, now
+%% looking for the last line indication.
+%% finish - now on the last line.
+%% Description: Parses a ftp control response message.
+%% "A reply is defined to contain the 3-digit code, followed by Space
+%% <SP>, followed by one line of text (where some maximum line length
+%% has been specified), and terminated by the Telnet end-of-line
+%% code (CRLF), or a so called multilined reply for example:
+%%
+%% 123-First line
+%% Second line
+%% 234 A line beginning with numbers
+%% 123 The last line
+%%
+%% The user-process then simply needs to search for the second
+%% occurrence of the same reply code, followed by <SP> (Space), at
+%% the beginning of a line, and ignore all intermediary lines. If
+%% an intermediary line begins with a 3-digit number, the Server
+%% will pad the front to avoid confusion.
+%%--------------------------------------------------------------------------
+
+%% Make sure we received the first 4 bytes so we know how to parse
+%% the FTP server response e.i. is the response composed of one
+%% or multiple lines.
+parse_lines(Bin, Lines, start) when size(Bin) < 4 ->
+ {continue, {Bin, Lines, start}};
+%% Multiple lines exist
+parse_lines(<<C1, C2, C3, $-, Rest/binary>>, Lines, start) ->
+ parse_lines(Rest, [$-, C3, C2, C1 | Lines], {C1, C2, C3});
+%% Only one line exists
+parse_lines(<<C1, C2, C3, ?WHITE_SPACE, Bin/binary>>, Lines, start) ->
+ parse_lines(Bin, [?WHITE_SPACE, C3, C2, C1 | Lines], finish);
+
+%% Last line found
+parse_lines(<<?CR, ?LF, C1, C2, C3, ?WHITE_SPACE, Rest/binary>>, Lines, {C1, C2, C3}) ->
+ parse_lines(Rest, [?WHITE_SPACE, C3, C2, C1, ?LF, ?CR | Lines], finish);
+%% Potential end found wait for more data
+parse_lines(<<?CR, ?LF, C1, C2, C3>> = Bin, Lines, {C1, C2, C3}) ->
+ {continue, {Bin, Lines, {C1, C2, C3}}};
+%% Intermidate line begining with status code
+parse_lines(<<?CR, ?LF, C1, C2, C3, Rest/binary>>, Lines, {C1, C2, C3}) ->
+ parse_lines(Rest, [C3, C2, C1, ?LF, ?CR | Lines], {C1, C2, C3});
+
+%% Potential last line wait for more data
+parse_lines(<<?CR, ?LF, C1, C2>> = Data, Lines, {C1, C2, _} = StatusCode) ->
+ {continue, {Data, Lines, StatusCode}};
+parse_lines(<<?CR, ?LF, C1>> = Data, Lines, {C1, _, _} = StatusCode) ->
+ {continue, {Data, Lines, StatusCode}};
+parse_lines(<<?CR, ?LF>> = Data, Lines, {_,_,_} = StatusCode) ->
+ {continue, {Data, Lines, StatusCode}};
+parse_lines(<<?LF>> = Data, Lines, {_,_,_} = StatusCode) ->
+ {continue, {Data, Lines, StatusCode}};
+parse_lines(<<>> = Data, Lines, {_,_,_} = StatusCode) ->
+ {continue, {Data, Lines, StatusCode}};
+%% Part of the multiple lines
+parse_lines(<<Octet, Rest/binary>>, Lines, {_,_, _} = StatusCode) ->
+ parse_lines(Rest, [Octet | Lines], StatusCode);
+
+%% End of FTP server response found
+parse_lines(<<?CR, ?LF>>, Lines, finish) ->
+ {ok, lists:reverse([?LF, ?CR | Lines]), <<>>};
+parse_lines(<<?CR, ?LF, Rest/binary>>, Lines, finish) ->
+ {ok, lists:reverse([?LF, ?CR | Lines]), Rest};
+
+%% Potential end found wait for more data
+parse_lines(<<?CR>> = Data, Lines, finish) ->
+ {continue, {Data, Lines, finish}};
+parse_lines(<<>> = Data, Lines, finish) ->
+ {continue, {Data, Lines, finish}};
+%% Part of last line
+parse_lines(<<Octet, Rest/binary>>, Lines, finish) ->
+ parse_lines(Rest, [Octet | Lines], finish).
+
+%%--------------------------------------------------------------------------
+%% interpret(Lines) -> {Status, Text}
+%% Lines = [byte(), byte(), byte() | Text] - ftp server response as
+%% returned by parse_lines/3
+%% Stauts = atom() (see interpret_status/3)
+%% Text = [string()]
+%%
+%% Description: Create nicer data to match on.
+%%--------------------------------------------------------------------------
+interpret([Didgit1, Didgit2, Didgit3 | Data]) ->
+ Code1 = Didgit1 - $0,
+ Code2 = Didgit2 - $0,
+ Code3 = Didgit3 - $0,
+ {interpret_status(Code1, Code2, Code3), Data}.
+
+%%--------------------------------------------------------------------------
+%% error_string(Error) -> string()
+%% Error = {error, term()} | term()
+%%
+%% Description: Translates error codes into strings intended for
+%% human interpretation.
+%%--------------------------------------------------------------------------
+error_string({error, Reason}) ->
+ error_string(Reason);
+
+error_string(echunk) -> "Synchronisation error during chunk sending.";
+error_string(eclosed) -> "Session has been closed.";
+error_string(econn) -> "Connection to remote server prematurely closed.";
+error_string(eexists) ->"File or directory already exists.";
+error_string(ehost) -> "Host not found, FTP server not found, "
+ "or connection rejected.";
+error_string(elogin) -> "User not logged in.";
+error_string(enotbinary) -> "Term is not a binary.";
+error_string(epath) -> "No such file or directory, already exists, "
+ "or permission denied.";
+error_string(etype) -> "No such type.";
+error_string(euser) -> "User name or password not valid.";
+error_string(etnospc) -> "Insufficient storage space in system.";
+error_string(enofile) -> "No files found or file unavailable";
+error_string(epnospc) -> "Exceeded storage allocation "
+ "(for current directory or dataset).";
+error_string(efnamena) -> "File name not allowed.";
+error_string(Reason) ->
+ lists:flatten(io_lib:format("Unknown error: ~w", [Reason])).
+
+%%%========================================================================
+%%% Internal functions
+%%%========================================================================
+
+%% Positive Preleminary Reply
+interpret_status(?POS_PREL,_,_) -> pos_prel;
+%%FIXME ??? 3??? interpret_status(?POS_COMPL, ?AUTH_ACC, 3) -> tls_upgrade;
+interpret_status(?POS_COMPL, ?AUTH_ACC, 4) -> tls_upgrade;
+%% Positive Completion Reply
+interpret_status(?POS_COMPL,_,_) -> pos_compl;
+%% Positive Intermediate Reply nedd account
+interpret_status(?POS_INTERM,?AUTH_ACC,2) -> pos_interm_acct;
+%% Positive Intermediate Reply
+interpret_status(?POS_INTERM,_,_) -> pos_interm;
+%% No files found or file not available
+interpret_status(?TRANS_NEG_COMPL,?FILE_SYSTEM,0) -> enofile;
+%% No storage area no action taken
+interpret_status(?TRANS_NEG_COMPL,?FILE_SYSTEM,2) -> etnospc;
+%% Temporary Error, no action taken
+interpret_status(?TRANS_NEG_COMPL,_,_) -> trans_neg_compl;
+%% Permanent disk space error, the user shall not try again
+interpret_status(?PERM_NEG_COMPL,?FILE_SYSTEM,0) -> epath;
+interpret_status(?PERM_NEG_COMPL,?FILE_SYSTEM,2) -> epnospc;
+interpret_status(?PERM_NEG_COMPL,?FILE_SYSTEM,3) -> efnamena;
+interpret_status(?PERM_NEG_COMPL,?AUTH_ACC,0) -> elogin;
+interpret_status(?PERM_NEG_COMPL,_,_) -> perm_neg_compl.
+
diff --git a/lib/ftp/src/ftp_sup.erl b/lib/ftp/src/ftp_sup.erl
new file mode 100644
index 0000000000..f30046802f
--- /dev/null
+++ b/lib/ftp/src/ftp_sup.erl
@@ -0,0 +1,68 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+%%%-------------------------------------------------------------------
+%% @doc ftp top level supervisor.
+%% @end
+%%%-------------------------------------------------------------------
+
+-module(ftp_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_child/1, start_link/0]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+-define(SERVER, ?MODULE).
+
+%%====================================================================
+%% API functions
+%%====================================================================
+
+start_link() ->
+ supervisor:start_link({local, ?SERVER}, ?MODULE, []).
+
+start_child(Args) ->
+ supervisor:start_child(?MODULE, Args).
+
+%%====================================================================
+%% Supervisor callbacks
+%%====================================================================
+init(_) ->
+ SupFlags = #{strategy => simple_one_for_one,
+ intensity => 0,
+ period => 3600},
+ {ok, {SupFlags, child_specs()}}.
+
+
+%%====================================================================
+%% Internal functions
+%%====================================================================
+child_specs() ->
+ [#{id => undefined,
+ start => {ftp, start_link, []},
+ restart => temporary,
+ shutdown => 4000,
+ type => worker,
+ modules => [ftp]}].
diff --git a/lib/ftp/test/Makefile b/lib/ftp/test/Makefile
new file mode 100644
index 0000000000..147f8e5dd6
--- /dev/null
+++ b/lib/ftp/test/Makefile
@@ -0,0 +1,251 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# %CopyrightEnd%
+#
+#
+# For an outline of how this all_SUITE_data stuff works, see the
+# make file ../../ssl/test/Makefile.
+#
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../vsn.mk
+VSN = $(FTP_VSN)
+
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
+
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+INCLUDES = -I. \
+ -I$(ERL_TOP)/lib/ftp/src
+
+CP = cp
+
+ifeq ($(TESTROOT_DIR),)
+TESTROOT_DIR = /ldisk/tests/$(USER)/ftp
+endif
+
+ifeq ($(FTP_DATA_DIR),)
+FTP_DATA_DIR = $(TESTROOT_DIR)/data_dir
+endif
+
+ifeq ($(FTP_PRIV_DIR),)
+FTP_PRIV_DIR = $(TESTROOT_DIR)/priv_dir
+endif
+
+FTP_FLAGS = -Dftp__data_dir='"$(FTP_DATA_DIR)"' \
+ -Dftp_priv_dir='"$(FTP_PRIV_DIR)"'
+
+
+###
+### test suite debug flags
+###
+ifeq ($(FTP_DEBUG_CLIENT),)
+ FTP_DEBUG_CLIENT = y
+endif
+
+ifeq ($(FTP_DEBUG_CLIENT),)
+ FTP_FLAGS += -Dftp_debug_client
+endif
+
+ifeq ($(FTP_TRACE_CLIENT),)
+ FTP_DEBUG_CLIENT = y
+endif
+
+ifeq ($(FTP_TRACE_CLIENT),y)
+ FTP_FLAGS += -Dftp_trace_client
+endif
+
+ifneq ($(FTP_DEBUG),)
+ FTP_DEBUG = s
+endif
+
+ifeq ($(FTP_DEBUG),l)
+ FTP_FLAGS += -Dftp_log
+endif
+
+ifeq ($(FTP_DEBUG),d)
+ FTP_FLAGS += -Dftp_debug -Dftp_log
+endif
+
+
+FTP_FLAGS += -pa ../ftp/ebin
+
+FTP_ROOT = ../ftp
+
+MODULES = \
+ erl_make_certs \
+ ftp_SUITE \
+ ftp_format_SUITE \
+ ftp_test_lib
+
+
+EBIN = .
+
+HRL_FILES = \
+ ftp_internal.hrl
+
+ERL_FILES = $(MODULES:%=%.erl)
+
+SOURCE = $(ERL_FILES) $(HRL_FILES)
+
+TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+FTP_SPECS = ftp.spec ftp_bench.spec
+COVER_FILE = ftp.cover
+FTP_FILES = ftp.config $(FTP_SPECS)
+
+
+FTP_DATADIRS = ftp_SUITE_data
+
+DATADIRS = $(FTP_DATADIRS)
+
+EMAKEFILE = Emakefile
+MAKE_EMAKE = $(wildcard $(ERL_TOP)/make/make_emakefile)
+
+ifeq ($(MAKE_EMAKE),)
+BUILDTARGET = $(TARGET_FILES)
+RELTEST_FILES = $(COVER_FILE) $(FTP_SPECS) $(SOURCE)
+else
+BUILDTARGET = emakebuild
+RELTEST_FILES = $(EMAKEFILE) $(COVER_FILE) $(FTP_SPECS) $(SOURCE)
+endif
+
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+
+RELTESTSYSDIR = "$(RELEASE_PATH)/ftp_test"
+RELTESTSYSALLDATADIR = $(RELTESTSYSDIR)/all_SUITE_data
+RELTESTSYSBINDIR = $(RELTESTSYSALLDATADIR)/bin
+
+
+# ----------------------------------------------------
+# FLAGS
+# The path to the test_server ebin dir is needed when
+# running the target "targets".
+# ----------------------------------------------------
+ERL_COMPILE_FLAGS += \
+ $(INCLUDES) \
+ $(FTP_FLAGS)
+
+# ----------------------------------------------------
+# Targets
+# erl -sname kalle -pa ../ebin
+# If you intend to run the test suite locally (private), then
+# there is some requirements:
+# 1) FTP_PRIV_DIR must be created
+# ----------------------------------------------------
+
+tests debug opt: $(BUILDTARGET)
+
+targets: $(TARGET_FILES)
+
+.PHONY: emakebuild
+
+emakebuild: $(EMAKEFILE)
+
+$(EMAKEFILE):
+ $(MAKE_EMAKE) $(ERL_COMPILE_FLAGS) -o$(EBIN) '*_SUITE_make' | grep -v Warning > $(EMAKEFILE)
+ $(MAKE_EMAKE) $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES) | grep -v Warning >> $(EMAKEFILE)
+
+clean:
+ rm -f $(EMAKEFILE)
+ rm -f $(TARGET_FILES)
+ rm -f core *~
+
+docs:
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec: opt
+ $(INSTALL_DIR) "$(RELSYSDIR)/test"
+ $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) "$(RELSYSDIR)/test"
+ $(INSTALL_DATA) $(FTP_FILES) "$(RELSYSDIR)/test"
+ @for d in $(DATADIRS); do \
+ echo "installing data dir $$d"; \
+ if test -f $$d/TAR.exclude; then \
+ echo $$d/TAR.exclude2 > $$d/TAR.exclude2; \
+ cat $$d/TAR.exclude >> $$d/TAR.exclude2; \
+ find $$d -name '*.contrib*' >> $$d/TAR.exclude2; \
+ find $$d -name '*.keep*' >> $$d/TAR.exclude2; \
+ find $$d -name '*.mkelem*' >> $$d/TAR.exclude2; \
+ find $$d -name '*~' >> $$d/TAR.exclude2; \
+ find $$d -name 'erl_crash.dump' >> $$d/TAR.exclude2; \
+ find $$d -name 'core' >> $$d/TAR.exclude2; \
+ find $$d -name '.cmake.state' >> $$d/TAR.exclude2; \
+ tar cfX - $$d/TAR.exclude2 $$d | (cd "$(RELSYSDIR)/test"; tar xf -); \
+ else \
+ tar cf - $$d | (cd "$(RELSYSDIR)/test"; tar xf -); \
+ fi; \
+ done
+
+release_tests_spec: opt
+ $(INSTALL_DIR) $(RELTESTSYSDIR)
+ $(INSTALL_DATA) $(RELTEST_FILES) $(RELTESTSYSDIR)
+ chmod -R u+w $(RELTESTSYSDIR)
+ tar chf - $(DATADIRS) | (cd $(RELTESTSYSDIR); tar xf -)
+ $(INSTALL_DIR) $(RELTESTSYSALLDATADIR)
+ $(INSTALL_DIR) $(RELTESTSYSBINDIR)
+ chmod -R +x $(RELTESTSYSBINDIR)
+ $(INSTALL_DIR) $(RELTESTSYSALLDATADIR)/win32/lib
+
+release_docs_spec:
+
+info:
+ @echo "MAKE_EMAKE = $(MAKE_EMAKE)"
+ @echo "EMAKEFILE = $(EMAKEFILE)"
+ @echo "BUILDTARGET = $(BUILDTARGET)"
+ @echo ""
+ @echo "MODULES = $(MODULES)"
+ @echo "ERL_FILES = $(ERL_FILES)"
+ @echo "SOURCE = $(SOURCE)"
+ @echo "TARGET_FILES = $(TARGET_FILES)"
+ @echo ""
+ @echo "FTP_SPECS = $(FTP_SPECS)"
+ @echo "FTP_FILES = $(FTP_FILES)"
+ @echo ""
+ @echo "RELEASE_PATH = "$(RELEASE_PATH)""
+ @echo "RELSYSDIR = "$(RELSYSDIR)""
+ @echo "RELTESTSYSDIR = $(RELTESTSYSDIR)"
+ @echo "RELTESTSYSALLDATADIR = $(RELTESTSYSALLDATADIR)"
+ @echo "RELTESTSYSBINDIR = $(RELTESTSYSBINDIR)"
+ @echo ""
+ @echo "DATADIRS = $(DATADIRS)"
+ @echo "REL_DATADIRS = $(REL_DATADIRS)"
+ @echo ""
+ @echo "FTP_DATA_DIR = $(FTP_DATA_DIR)"
+ @echo "FTP_PRIV_DIR = $(FTP_PRIV_DIR)"
+ @echo "FTP_ROOT = $(FTP_ROOT)"
+ @echo "FTP_FLAGS = $(FTP_FLAGS)"
+
+
diff --git a/lib/ftp/test/erl_make_certs.erl b/lib/ftp/test/erl_make_certs.erl
new file mode 100644
index 0000000000..e10ecf01f9
--- /dev/null
+++ b/lib/ftp/test/erl_make_certs.erl
@@ -0,0 +1,475 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%% Create test certificates
+
+-module(erl_make_certs).
+-include_lib("public_key/include/public_key.hrl").
+
+-export([make_cert/1, gen_rsa/1, verify_signature/3, write_pem/3]).
+-compile(export_all).
+
+%%--------------------------------------------------------------------
+%% @doc Create and return a der encoded certificate
+%% Option Default
+%% -------------------------------------------------------
+%% digest sha1
+%% validity {date(), date() + week()}
+%% version 3
+%% subject [] list of the following content
+%% {name, Name}
+%% {email, Email}
+%% {city, City}
+%% {state, State}
+%% {org, Org}
+%% {org_unit, OrgUnit}
+%% {country, Country}
+%% {serial, Serial}
+%% {title, Title}
+%% {dnQualifer, DnQ}
+%% issuer = {Issuer, IssuerKey} true (i.e. a ca cert is created)
+%% (obs IssuerKey migth be {Key, Password}
+%% key = KeyFile|KeyBin|rsa|dsa|ec Subject PublicKey rsa, dsa or ec generates key
+%%
+%%
+%% (OBS: The generated keys are for testing only)
+%% @spec ([{::atom(), ::term()}]) -> {Cert::binary(), Key::binary()}
+%% @end
+%%--------------------------------------------------------------------
+
+make_cert(Opts) ->
+ SubjectPrivateKey = get_key(Opts),
+ {TBSCert, IssuerKey} = make_tbs(SubjectPrivateKey, Opts),
+ Cert = public_key:pkix_sign(TBSCert, IssuerKey),
+ true = verify_signature(Cert, IssuerKey, undef), %% verify that the keys where ok
+ {Cert, encode_key(SubjectPrivateKey)}.
+
+%%--------------------------------------------------------------------
+%% @doc Writes pem files in Dir with FileName ++ ".pem" and FileName ++ "_key.pem"
+%% @spec (::string(), ::string(), {Cert,Key}) -> ok
+%% @end
+%%--------------------------------------------------------------------
+write_pem(Dir, FileName, {Cert, Key = {_,_,not_encrypted}}) when is_binary(Cert) ->
+ ok = der_to_pem(filename:join(Dir, FileName ++ ".pem"),
+ [{'Certificate', Cert, not_encrypted}]),
+ ok = der_to_pem(filename:join(Dir, FileName ++ "_key.pem"), [Key]).
+
+%%--------------------------------------------------------------------
+%% @doc Creates a rsa key (OBS: for testing only)
+%% the size are in bytes
+%% @spec (::integer()) -> {::atom(), ::binary(), ::opaque()}
+%% @end
+%%--------------------------------------------------------------------
+gen_rsa(Size) when is_integer(Size) ->
+ Key = gen_rsa2(Size),
+ {Key, encode_key(Key)}.
+
+%%--------------------------------------------------------------------
+%% @doc Creates a dsa key (OBS: for testing only)
+%% the sizes are in bytes
+%% @spec (::integer()) -> {::atom(), ::binary(), ::opaque()}
+%% @end
+%%--------------------------------------------------------------------
+gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) ->
+ Key = gen_dsa2(LSize, NSize),
+ {Key, encode_key(Key)}.
+
+%%--------------------------------------------------------------------
+%% @doc Creates a ec key (OBS: for testing only)
+%% the sizes are in bytes
+%% @spec (::integer()) -> {::atom(), ::binary(), ::opaque()}
+%% @end
+%%--------------------------------------------------------------------
+gen_ec(Curve) when is_atom(Curve) ->
+ Key = gen_ec2(Curve),
+ {Key, encode_key(Key)}.
+
+%%--------------------------------------------------------------------
+%% @doc Verifies cert signatures
+%% @spec (::binary(), ::tuple()) -> ::boolean()
+%% @end
+%%--------------------------------------------------------------------
+verify_signature(DerEncodedCert, DerKey, _KeyParams) ->
+ Key = decode_key(DerKey),
+ case Key of
+ #'RSAPrivateKey'{modulus=Mod, publicExponent=Exp} ->
+ public_key:pkix_verify(DerEncodedCert,
+ #'RSAPublicKey'{modulus=Mod, publicExponent=Exp});
+ #'DSAPrivateKey'{p=P, q=Q, g=G, y=Y} ->
+ public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}});
+ #'ECPrivateKey'{version = _Version, privateKey = _PrivKey,
+ parameters = Params, publicKey = {0, PubKey}} ->
+ public_key:pkix_verify(DerEncodedCert, {#'ECPoint'{point = PubKey}, Params})
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%% Implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+get_key(Opts) ->
+ case proplists:get_value(key, Opts) of
+ undefined -> make_key(rsa, Opts);
+ rsa -> make_key(rsa, Opts);
+ dsa -> make_key(dsa, Opts);
+ ec -> make_key(ec, Opts);
+ Key ->
+ Password = proplists:get_value(password, Opts, no_passwd),
+ decode_key(Key, Password)
+ end.
+
+decode_key({Key, Pw}) ->
+ decode_key(Key, Pw);
+decode_key(Key) ->
+ decode_key(Key, no_passwd).
+
+
+decode_key(#'RSAPublicKey'{} = Key,_) ->
+ Key;
+decode_key(#'RSAPrivateKey'{} = Key,_) ->
+ Key;
+decode_key(#'DSAPrivateKey'{} = Key,_) ->
+ Key;
+decode_key(#'ECPrivateKey'{} = Key,_) ->
+ Key;
+decode_key(PemEntry = {_,_,_}, Pw) ->
+ public_key:pem_entry_decode(PemEntry, Pw);
+decode_key(PemBin, Pw) ->
+ [KeyInfo] = public_key:pem_decode(PemBin),
+ decode_key(KeyInfo, Pw).
+
+encode_key(Key = #'RSAPrivateKey'{}) ->
+ {ok, Der} = 'OTP-PUB-KEY':encode('RSAPrivateKey', Key),
+ {'RSAPrivateKey', Der, not_encrypted};
+encode_key(Key = #'DSAPrivateKey'{}) ->
+ {ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key),
+ {'DSAPrivateKey', Der, not_encrypted};
+encode_key(Key = #'ECPrivateKey'{}) ->
+ {ok, Der} = 'OTP-PUB-KEY':encode('ECPrivateKey', Key),
+ {'ECPrivateKey', Der, not_encrypted}.
+
+make_tbs(SubjectKey, Opts) ->
+ Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))),
+
+ IssuerProp = proplists:get_value(issuer, Opts, true),
+ {Issuer, IssuerKey} = issuer(IssuerProp, Opts, SubjectKey),
+
+ {Algo, Parameters} = sign_algorithm(IssuerKey, Opts),
+
+ SignAlgo = #'SignatureAlgorithm'{algorithm = Algo,
+ parameters = Parameters},
+ Subject = case IssuerProp of
+ true -> %% Is a Root Ca
+ Issuer;
+ _ ->
+ subject(proplists:get_value(subject, Opts),false)
+ end,
+
+ {#'OTPTBSCertificate'{serialNumber = trunc(random:uniform()*100000000)*10000 + 1,
+ signature = SignAlgo,
+ issuer = Issuer,
+ validity = validity(Opts),
+ subject = Subject,
+ subjectPublicKeyInfo = publickey(SubjectKey),
+ version = Version,
+ extensions = extensions(Opts)
+ }, IssuerKey}.
+
+issuer(true, Opts, SubjectKey) ->
+ %% Self signed
+ {subject(proplists:get_value(subject, Opts), true), SubjectKey};
+issuer({Issuer, IssuerKey}, _Opts, _SubjectKey) when is_binary(Issuer) ->
+ {issuer_der(Issuer), decode_key(IssuerKey)};
+issuer({File, IssuerKey}, _Opts, _SubjectKey) when is_list(File) ->
+ {ok, [{cert, Cert, _}|_]} = pem_to_der(File),
+ {issuer_der(Cert), decode_key(IssuerKey)}.
+
+issuer_der(Issuer) ->
+ Decoded = public_key:pkix_decode_cert(Issuer, otp),
+ #'OTPCertificate'{tbsCertificate=Tbs} = Decoded,
+ #'OTPTBSCertificate'{subject=Subject} = Tbs,
+ Subject.
+
+subject(undefined, IsRootCA) ->
+ User = if IsRootCA -> "RootCA"; true -> os:getenv("USER", "test_user") end,
+ Opts = [{email, User ++ "@erlang.org"},
+ {name, User},
+ {city, "Stockholm"},
+ {country, "SE"},
+ {org, "erlang"},
+ {org_unit, "testing dep"}],
+ subject(Opts);
+subject(Opts, _) ->
+ subject(Opts).
+
+subject(SubjectOpts) when is_list(SubjectOpts) ->
+ Encode = fun(Opt) ->
+ {Type,Value} = subject_enc(Opt),
+ [#'AttributeTypeAndValue'{type=Type, value=Value}]
+ end,
+ {rdnSequence, [Encode(Opt) || Opt <- SubjectOpts]}.
+
+%% Fill in the blanks
+subject_enc({name, Name}) -> {?'id-at-commonName', {printableString, Name}};
+subject_enc({email, Email}) -> {?'id-emailAddress', Email};
+subject_enc({city, City}) -> {?'id-at-localityName', {printableString, City}};
+subject_enc({state, State}) -> {?'id-at-stateOrProvinceName', {printableString, State}};
+subject_enc({org, Org}) -> {?'id-at-organizationName', {printableString, Org}};
+subject_enc({org_unit, OrgUnit}) -> {?'id-at-organizationalUnitName', {printableString, OrgUnit}};
+subject_enc({country, Country}) -> {?'id-at-countryName', Country};
+subject_enc({serial, Serial}) -> {?'id-at-serialNumber', Serial};
+subject_enc({title, Title}) -> {?'id-at-title', {printableString, Title}};
+subject_enc({dnQualifer, DnQ}) -> {?'id-at-dnQualifier', DnQ};
+subject_enc(Other) -> Other.
+
+
+extensions(Opts) ->
+ case proplists:get_value(extensions, Opts, []) of
+ false ->
+ asn1_NOVALUE;
+ Exts ->
+ lists:flatten([extension(Ext) || Ext <- default_extensions(Exts)])
+ end.
+
+default_extensions(Exts) ->
+ Def = [{key_usage,undefined},
+ {subject_altname, undefined},
+ {issuer_altname, undefined},
+ {basic_constraints, default},
+ {name_constraints, undefined},
+ {policy_constraints, undefined},
+ {ext_key_usage, undefined},
+ {inhibit_any, undefined},
+ {auth_key_id, undefined},
+ {subject_key_id, undefined},
+ {policy_mapping, undefined}],
+ Filter = fun({Key, _}, D) -> lists:keydelete(Key, 1, D) end,
+ Exts ++ lists:foldl(Filter, Def, Exts).
+
+extension({_, undefined}) -> [];
+extension({basic_constraints, Data}) ->
+ case Data of
+ default ->
+ #'Extension'{extnID = ?'id-ce-basicConstraints',
+ extnValue = #'BasicConstraints'{cA=true},
+ critical=true};
+ false ->
+ [];
+ Len when is_integer(Len) ->
+ #'Extension'{extnID = ?'id-ce-basicConstraints',
+ extnValue = #'BasicConstraints'{cA=true, pathLenConstraint=Len},
+ critical=true};
+ _ ->
+ #'Extension'{extnID = ?'id-ce-basicConstraints',
+ extnValue = Data}
+ end;
+extension({Id, Data, Critical}) ->
+ #'Extension'{extnID = Id, extnValue = Data, critical = Critical}.
+
+
+publickey(#'RSAPrivateKey'{modulus=N, publicExponent=E}) ->
+ Public = #'RSAPublicKey'{modulus=N, publicExponent=E},
+ Algo = #'PublicKeyAlgorithm'{algorithm= ?rsaEncryption, parameters='NULL'},
+ #'OTPSubjectPublicKeyInfo'{algorithm = Algo,
+ subjectPublicKey = Public};
+publickey(#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y}) ->
+ Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-dsa',
+ parameters={params, #'Dss-Parms'{p=P, q=Q, g=G}}},
+ #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y};
+publickey(#'ECPrivateKey'{version = _Version,
+ privateKey = _PrivKey,
+ parameters = Params,
+ publicKey = {0, PubKey}}) ->
+ Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-ecPublicKey', parameters=Params},
+ #'OTPSubjectPublicKeyInfo'{algorithm = Algo,
+ subjectPublicKey = #'ECPoint'{point = PubKey}}.
+
+validity(Opts) ->
+ DefFrom0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())-1),
+ DefTo0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())+7),
+ {DefFrom, DefTo} = proplists:get_value(validity, Opts, {DefFrom0, DefTo0}),
+ Format = fun({Y,M,D}) -> lists:flatten(io_lib:format("~w~2..0w~2..0w000000Z",[Y,M,D])) end,
+ #'Validity'{notBefore={generalTime, Format(DefFrom)},
+ notAfter ={generalTime, Format(DefTo)}}.
+
+sign_algorithm(#'RSAPrivateKey'{}, Opts) ->
+ Type = case proplists:get_value(digest, Opts, sha1) of
+ sha1 -> ?'sha1WithRSAEncryption';
+ sha512 -> ?'sha512WithRSAEncryption';
+ sha384 -> ?'sha384WithRSAEncryption';
+ sha256 -> ?'sha256WithRSAEncryption';
+ md5 -> ?'md5WithRSAEncryption';
+ md2 -> ?'md2WithRSAEncryption'
+ end,
+ {Type, 'NULL'};
+sign_algorithm(#'DSAPrivateKey'{p=P, q=Q, g=G}, _Opts) ->
+ {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}};
+sign_algorithm(#'ECPrivateKey'{}, Opts) ->
+ Type = case proplists:get_value(digest, Opts, sha1) of
+ sha1 -> ?'ecdsa-with-SHA1';
+ sha512 -> ?'ecdsa-with-SHA512';
+ sha384 -> ?'ecdsa-with-SHA384';
+ sha256 -> ?'ecdsa-with-SHA256'
+ end,
+ {Type, 'NULL'}.
+
+make_key(rsa, _Opts) ->
+ %% (OBS: for testing only)
+ gen_rsa2(64);
+make_key(dsa, _Opts) ->
+ gen_dsa2(128, 20); %% Bytes i.e. {1024, 160}
+make_key(ec, _Opts) ->
+ %% (OBS: for testing only)
+ gen_ec2(secp256k1).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% RSA key generation (OBS: for testing only)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-define(SMALL_PRIMES, [65537,97,89,83,79,73,71,67,61,59,53,
+ 47,43,41,37,31,29,23,19,17,13,11,7,5,3]).
+
+gen_rsa2(Size) ->
+ P = prime(Size),
+ Q = prime(Size),
+ N = P*Q,
+ Tot = (P - 1) * (Q - 1),
+ [E|_] = lists:dropwhile(fun(Candidate) -> (Tot rem Candidate) == 0 end, ?SMALL_PRIMES),
+ {D1,D2} = extended_gcd(E, Tot),
+ D = erlang:max(D1,D2),
+ case D < E of
+ true ->
+ gen_rsa2(Size);
+ false ->
+ {Co1,Co2} = extended_gcd(Q, P),
+ Co = erlang:max(Co1,Co2),
+ #'RSAPrivateKey'{version = 'two-prime',
+ modulus = N,
+ publicExponent = E,
+ privateExponent = D,
+ prime1 = P,
+ prime2 = Q,
+ exponent1 = D rem (P-1),
+ exponent2 = D rem (Q-1),
+ coefficient = Co
+ }
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% DSA key generation (OBS: for testing only)
+%% See http://en.wikipedia.org/wiki/Digital_Signature_Algorithm
+%% and the fips_186-3.pdf
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+gen_dsa2(LSize, NSize) ->
+ Q = prime(NSize), %% Choose N-bit prime Q
+ X0 = prime(LSize),
+ P0 = prime((LSize div 2) +1),
+
+ %% Choose L-bit prime modulus P such that p-1 is a multiple of q.
+ case dsa_search(X0 div (2*Q*P0), P0, Q, 1000) of
+ error ->
+ gen_dsa2(LSize, NSize);
+ P ->
+ G = crypto:mod_pow(2, (P-1) div Q, P), % Choose G a number whose multiplicative order modulo p is q.
+ %% such that This may be done by setting g = h^(p-1)/q mod p, commonly h=2 is used.
+
+ X = prime(20), %% Choose x by some random method, where 0 < x < q.
+ Y = crypto:mod_pow(G, X, P), %% Calculate y = g^x mod p.
+
+ #'DSAPrivateKey'{version=0, p = P, q = Q,
+ g = crypto:bytes_to_integer(G), y = crypto:bytes_to_integer(Y), x = X}
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EC key generation (OBS: for testing only)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+gen_ec2(CurveId) ->
+ {PubKey, PrivKey} = crypto:generate_key(ecdh, CurveId),
+
+ #'ECPrivateKey'{version = 1,
+ privateKey = binary_to_list(PrivKey),
+ parameters = {namedCurve, pubkey_cert_records:namedCurves(CurveId)},
+ publicKey = {0, PubKey}}.
+
+%% See fips_186-3.pdf
+dsa_search(T, P0, Q, Iter) when Iter > 0 ->
+ P = 2*T*Q*P0 + 1,
+ case is_prime(P, 50) of
+ true -> P;
+ false -> dsa_search(T+1, P0, Q, Iter-1)
+ end;
+dsa_search(_,_,_,_) ->
+ error.
+
+
+%%%%%%% Crypto Math %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+prime(ByteSize) ->
+ Rand = odd_rand(ByteSize),
+ prime_odd(Rand, 0).
+
+prime_odd(Rand, N) ->
+ case is_prime(Rand, 50) of
+ true ->
+ Rand;
+ false ->
+ prime_odd(Rand+2, N+1)
+ end.
+
+%% see http://en.wikipedia.org/wiki/Fermat_primality_test
+is_prime(_, 0) -> true;
+is_prime(Candidate, Test) ->
+ CoPrime = odd_rand(10000, Candidate),
+ Result = crypto:mod_pow(CoPrime, Candidate, Candidate) ,
+ is_prime(CoPrime, crypto:bytes_to_integer(Result), Candidate, Test).
+
+is_prime(CoPrime, CoPrime, Candidate, Test) ->
+ is_prime(Candidate, Test-1);
+is_prime(_,_,_,_) ->
+ false.
+
+odd_rand(Size) ->
+ Min = 1 bsl (Size*8-1),
+ Max = (1 bsl (Size*8))-1,
+ odd_rand(Min, Max).
+
+odd_rand(Min,Max) ->
+ Rand = crypto:rand_uniform(Min,Max),
+ case Rand rem 2 of
+ 0 ->
+ Rand + 1;
+ _ ->
+ Rand
+ end.
+
+extended_gcd(A, B) ->
+ case A rem B of
+ 0 ->
+ {0, 1};
+ N ->
+ {X, Y} = extended_gcd(B, N),
+ {Y, X-Y*(A div B)}
+ end.
+
+pem_to_der(File) ->
+ {ok, PemBin} = file:read_file(File),
+ public_key:pem_decode(PemBin).
+
+der_to_pem(File, Entries) ->
+ PemBin = public_key:pem_encode(Entries),
+ file:write_file(File, PemBin).
+
diff --git a/lib/ftp/test/ftp.config b/lib/ftp/test/ftp.config
new file mode 100644
index 0000000000..2600237da9
--- /dev/null
+++ b/lib/ftp/test/ftp.config
@@ -0,0 +1 @@
+[]. \ No newline at end of file
diff --git a/lib/ftp/test/ftp.cover b/lib/ftp/test/ftp.cover
new file mode 100644
index 0000000000..5b155991bc
--- /dev/null
+++ b/lib/ftp/test/ftp.cover
@@ -0,0 +1,2 @@
+{incl_app,ftp,details}.
+
diff --git a/lib/ftp/test/ftp.spec b/lib/ftp/test/ftp.spec
new file mode 100644
index 0000000000..faf1e532a8
--- /dev/null
+++ b/lib/ftp/test/ftp.spec
@@ -0,0 +1 @@
+{suites,"../ftp_test", all}.
diff --git a/lib/ftp/test/ftp_SUITE.erl b/lib/ftp/test/ftp_SUITE.erl
new file mode 100644
index 0000000000..0b070ee8cb
--- /dev/null
+++ b/lib/ftp/test/ftp_SUITE.erl
@@ -0,0 +1,1274 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+-module(ftp_SUITE).
+
+-include_lib("kernel/include/file.hrl").
+-include_lib("common_test/include/ct.hrl").
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-define(FTP_USER, "anonymous").
+-define(FTP_PASS(Cmnt), (fun({ok,__H}) -> "ftp_SUITE_"++Cmnt++"@" ++ __H;
+ (_) -> "ftp_SUITE_"++Cmnt++"@localhost"
+ end)(inet:gethostname())
+ ).
+
+-define(BAD_HOST, "badhostname").
+-define(BAD_USER, "baduser").
+-define(BAD_DIR, "baddirectory").
+
+-record(progress, {
+ current = 0,
+ total
+ }).
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+suite() ->
+ [{timetrap,{seconds,20}}].
+
+all() ->
+ [
+ {group, ftp_passive},
+ {group, ftp_active},
+ {group, ftps_passive},
+ {group, ftps_active},
+ {group, ftp_sup},
+ app,
+ appup,
+ error_ehost,
+ clean_shutdown
+ ].
+
+groups() ->
+ [
+ {ftp_passive, [], ftp_tests()},
+ {ftp_active, [], ftp_tests()},
+ {ftps_passive, [], ftp_tests()},
+ {ftps_active, [], ftp_tests()},
+ {ftp_sup, [], ftp_sup_tests()}
+ ].
+
+ftp_tests()->
+ [
+ user,
+ bad_user,
+ pwd,
+ cd,
+ lcd,
+ ls,
+ nlist,
+ rename,
+ delete,
+ mkdir,
+ rmdir,
+ send,
+ send_3,
+ send_bin,
+ send_chunk,
+ append,
+ append_bin,
+ append_chunk,
+ recv,
+ recv_3,
+ recv_bin,
+ recv_bin_twice,
+ recv_chunk,
+ recv_chunk_twice,
+ recv_chunk_three_times,
+ recv_chunk_delay,
+ type,
+ quote,
+ error_elogin,
+ progress_report_send,
+ progress_report_recv,
+ not_owner,
+ unexpected_call,
+ unexpected_cast,
+ unexpected_bang
+ ].
+
+ftp_sup_tests() ->
+ [
+ start_ftp,
+ ftp_worker
+ ].
+
+%%--------------------------------------------------------------------
+
+%%% Config
+%%% key meaning
+%%% ................................................................
+%%% ftpservers list of servers to check if they are available
+%%% The element is:
+%%% {Name, % string(). The os command name
+%%% Path, % string(). The os PATH syntax, e.g "/bin:/usr/bin"
+%%% StartCommand, % fun()->{ok,start_result()} | {error,string()}.
+%%% % The command to start the daemon with.
+%%% ChkUp, % fun(start_result()) -> string(). Os command to check
+%%% % if the server is running. [] if not running.
+%%% % The string in string() is suitable for logging.
+%%% StopCommand, % fun(start_result()) -> void(). The command to stop the daemon with.
+%%% AugmentFun, % fun(config()) -> config() Adds two funs for transforming names of files
+%%% % and directories to the form they are returned from this server
+%%% ServerHost, % string(). Mostly "localhost"
+%%% ServerPort % pos_integer()
+%%% }
+%%%
+
+-define(default_ftp_servers,
+ [{"vsftpd",
+ "/sbin:/usr/sbin:/usr/local/sbin",
+ fun(__CONF__, AbsName) ->
+ DataDir = proplists:get_value(data_dir,__CONF__),
+ ConfFile = filename:join(DataDir, "vsftpd.conf"),
+ PrivDir = proplists:get_value(priv_dir,__CONF__),
+ AnonRoot = PrivDir,
+ Cmd = [AbsName ++" "++filename:join(DataDir,"vsftpd.conf"),
+ " -oftpd_banner=erlang_otp_testing",
+ " -oanon_root=\"",AnonRoot,"\"",
+ " -orsa_cert_file=\"",filename:join(DataDir,"server-cert.pem"),"\"",
+ " -orsa_private_key_file=\"",filename:join(DataDir,"server-key.pem"),"\""
+ ],
+ Result = os:cmd(Cmd),
+ ct:log("Config file:~n~s~n~nServer start command:~n ~s~nResult:~n ~p",
+ [case file:read_file(ConfFile) of
+ {ok,X} -> X;
+ _ -> ""
+ end,
+ Cmd, Result
+ ]),
+ case Result of
+ [] -> {ok,'dont care'};
+ [Msg] -> {error,Msg}
+ end
+ end,
+ fun(_StartResult) -> os:cmd("ps ax | grep erlang_otp_testing | grep -v grep")
+ end,
+ fun(_StartResult) -> os:cmd("kill `ps ax | grep erlang_otp_testing | awk '/vsftpd/{print $1}'`")
+ end,
+ fun(__CONF__) ->
+ AnonRoot = proplists:get_value(priv_dir,__CONF__),
+ [{id2ftp, fun(Id) -> filename:join(AnonRoot,Id) end},
+ {id2ftp_result,fun(Id) -> filename:join(AnonRoot,Id) end} | __CONF__]
+ end,
+ "localhost",
+ 9999
+ }
+ ]
+ ).
+
+
+init_per_suite(Config) ->
+ case find_executable(Config) of
+ false ->
+ {skip, "No ftp server found"};
+ {ok,Data} ->
+ TstDir = filename:join(proplists:get_value(priv_dir,Config), "test"),
+ file:make_dir(TstDir),
+ %% make_cert_files(dsa, rsa, "server-", proplists:get_value(data_dir,Config)),
+ ftp_test_lib:make_cert_files(proplists:get_value(data_dir,Config)),
+ start_ftpd([{test_dir,TstDir},
+ {ftpd_data,Data}
+ | Config])
+ end.
+
+end_per_suite(Config) ->
+ ps_ftpd(Config),
+ stop_ftpd(Config),
+ ps_ftpd(Config),
+ ok.
+
+%%--------------------------------------------------------------------
+init_per_group(Group, Config) when Group == ftps_active,
+ Group == ftps_passive ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ Config
+ catch
+ _:_ ->
+ {skip, "Crypto did not start"}
+ end;
+init_per_group(ftp_sup, Config) ->
+ try ftp:start() of
+ ok ->
+ Config
+ catch
+ _:_ ->
+ {skip, "Ftp did not start"}
+ end;
+init_per_group(_Group, Config) ->
+ Config.
+
+
+end_per_group(ftp_sup, Config) ->
+ ftp:stop(),
+ Config;
+end_per_group(_Group, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+init_per_testcase(T, Config0) when T =:= app; T =:= appup ->
+ Config0;
+init_per_testcase(Case, Config0) ->
+ Group = proplists:get_value(name, proplists:get_value(tc_group_properties,Config0)),
+
+ %% Workaround for interoperability issues with vsftpd =< 3.0.2:
+ %%
+ %% vsftpd =< 3.0.2 does not support ECDHE ciphers and the ssl application
+ %% removed ciphers with RSA key exchange from its default cipher list.
+ %% To allow interoperability with old versions of vsftpd, cipher suites
+ %% with RSA key exchange are appended to the default cipher list.
+ All = ssl:cipher_suites(all, 'tlsv1.2'),
+ Default = ssl:cipher_suites(default, 'tlsv1.2'),
+ RSASuites =
+ ssl:filter_cipher_suites(All, [{key_exchange, fun(rsa) -> true;
+ (_) -> false end}]),
+ Suites = ssl:append_cipher_suites(RSASuites, Default),
+ TLS = [{tls,[{reuse_sessions,true},{ciphers, Suites}]}],
+ ACTIVE = [{mode,active}],
+ PASSIVE = [{mode,passive}],
+ CaseOpts = case Case of
+ progress_report_send -> [{progress, {?MODULE,progress,#progress{}}}];
+ progress_report_recv -> [{progress, {?MODULE,progress,#progress{}}}];
+ _ -> []
+ end,
+ ExtraOpts = [verbose | CaseOpts],
+ Config =
+ case Group of
+ ftp_active -> ftp__open(Config0, ACTIVE ++ ExtraOpts);
+ ftps_active -> ftp__open(Config0, TLS++ ACTIVE ++ ExtraOpts);
+ ftp_passive -> ftp__open(Config0, PASSIVE ++ ExtraOpts);
+ ftps_passive -> ftp__open(Config0, TLS++PASSIVE ++ ExtraOpts);
+ ftp_sup -> ftp_start_service(Config0, ACTIVE ++ ExtraOpts);
+ undefined -> Config0
+ end,
+ case Case of
+ user -> Config;
+ bad_user -> Config;
+ error_elogin -> Config;
+ error_ehost -> Config;
+ clean_shutdown -> Config;
+ _ ->
+ Pid = proplists:get_value(ftp,Config),
+ ok = ftp:user(Pid, ?FTP_USER, ?FTP_PASS(atom_to_list(Group)++"-"++atom_to_list(Case)) ),
+ ok = ftp:cd(Pid, proplists:get_value(priv_dir,Config)),
+ Config
+ end.
+
+end_per_testcase(T, _Config) when T =:= app; T =:= appup -> ok;
+end_per_testcase(user, _Config) -> ok;
+end_per_testcase(bad_user, _Config) -> ok;
+end_per_testcase(error_elogin, _Config) -> ok;
+end_per_testcase(error_ehost, _Config) -> ok;
+end_per_testcase(clean_shutdown, _Config) -> ok;
+end_per_testcase(_Case, Config) ->
+ case proplists:get_value(tc_status,Config) of
+ ok -> ok;
+ _ ->
+ try ftp:latest_ctrl_response(proplists:get_value(ftp,Config))
+ of
+ {ok,S} -> ct:log("***~n*** Latest ctrl channel response:~n*** ~p~n***",[S])
+ catch
+ _:_ -> ok
+ end
+ end,
+ Group = proplists:get_value(name, proplists:get_value(tc_group_properties,Config)),
+ case Group of
+ ftp_sup ->
+ ftp_stop_service(Config);
+ _Else ->
+ ftp__close(Config)
+ end.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+app() ->
+ [{doc, "Test that the ftp app file is ok"}].
+app(Config) when is_list(Config) ->
+ ok = ?t:app_test(ftp).
+
+%%--------------------------------------------------------------------
+appup() ->
+ [{doc, "Test that the ftp appup file is ok"}].
+appup(Config) when is_list(Config) ->
+ ok = ?t:appup_test(ftp).
+
+%%--------------------------------------------------------------------
+
+user() -> [
+ {doc, "Open an ftp connection to a host, and logon as anonymous ftp,"
+ " then logoff"}].
+user(Config) ->
+ Pid = proplists:get_value(ftp, Config),
+ ok = ftp:user(Pid, ?FTP_USER, ?FTP_PASS("")),% logon
+ ok = ftp:close(Pid), % logoff
+ {error,eclosed} = ftp:pwd(Pid), % check logoff result
+ ok.
+
+%%-------------------------------------------------------------------------
+bad_user() ->
+ [{doc, "Open an ftp connection to a host, and logon with bad user."}].
+bad_user(Config) ->
+ Pid = proplists:get_value(ftp, Config),
+ {error, euser} = ftp:user(Pid, ?BAD_USER, ?FTP_PASS("")),
+ ok.
+
+%%-------------------------------------------------------------------------
+pwd() ->
+ [{doc, "Test ftp:pwd/1 & ftp:lpwd/1"}].
+pwd(Config0) ->
+ Config = set_state([reset], Config0),
+ Pid = proplists:get_value(ftp, Config),
+ {ok, PWD} = ftp:pwd(Pid),
+ {ok, PathLpwd} = ftp:lpwd(Pid),
+ PWD = id2ftp_result("", Config),
+ PathLpwd = id2ftp_result("", Config).
+
+%%-------------------------------------------------------------------------
+cd() ->
+ ["Open an ftp connection, log on as anonymous ftp, and cd to a"
+ "directory and to a non-existent directory."].
+cd(Config0) ->
+ Dir = "test",
+ Config = set_state([reset,{mkdir,Dir}], Config0),
+ Pid = proplists:get_value(ftp, Config),
+ ok = ftp:cd(Pid, id2ftp(Dir,Config)),
+ {ok, PWD} = ftp:pwd(Pid),
+ ExpectedPWD = id2ftp_result(Dir, Config),
+ PWD = ExpectedPWD,
+ {error, epath} = ftp:cd(Pid, ?BAD_DIR),
+ ok.
+
+%%-------------------------------------------------------------------------
+lcd() ->
+ [{doc, "Test api function ftp:lcd/2"}].
+lcd(Config0) ->
+ Dir = "test",
+ Config = set_state([reset,{mkdir,Dir}], Config0),
+ Pid = proplists:get_value(ftp, Config),
+ ok = ftp:lcd(Pid, id2ftp(Dir,Config)),
+ {ok, PWD} = ftp:lpwd(Pid),
+ ExpectedPWD = id2ftp_result(Dir, Config),
+ PWD = ExpectedPWD,
+ {error, epath} = ftp:lcd(Pid, ?BAD_DIR).
+
+%%-------------------------------------------------------------------------
+ls() ->
+ [{doc, "Open an ftp connection; ls the current directory, and the "
+ "\"test\" directory. We assume that ls never fails, since "
+ "it's output is meant to be read by humans. "}].
+ls(Config0) ->
+ Config = set_state([reset,{mkdir,"test"}], Config0),
+ Pid = proplists:get_value(ftp, Config),
+ {ok, _R1} = ftp:ls(Pid),
+ {ok, _R2} = ftp:ls(Pid, id2ftp("test",Config)),
+ %% neither nlist nor ls operates on a directory
+ %% they operate on a pathname, which *can* be a
+ %% directory, but can also be a filename or a group
+ %% of files (including wildcards).
+ case proplists:get_value(wildcard_support, Config) of
+ true ->
+ {ok, _R3} = ftp:ls(Pid, id2ftp("te*",Config));
+ _ ->
+ ok
+ end.
+
+%%-------------------------------------------------------------------------
+nlist() ->
+ [{doc,"Open an ftp connection; nlist the current directory, and the "
+ "\"test\" directory. Nlist does not behave consistenly over "
+ "operating systems. On some it is an error to have an empty "
+ "directory."}].
+nlist(Config0) ->
+ Config = set_state([reset,{mkdir,"test"}], Config0),
+ Pid = proplists:get_value(ftp, Config),
+ {ok, _R1} = ftp:nlist(Pid),
+ {ok, _R2} = ftp:nlist(Pid, id2ftp("test",Config)),
+ %% neither nlist nor ls operates on a directory
+ %% they operate on a pathname, which *can* be a
+ %% directory, but can also be a filename or a group
+ %% of files (including wildcards).
+ case proplists:get_value(wildcard_support, Config) of
+ true ->
+ {ok, _R3} = ftp:nlist(Pid, id2ftp("te*",Config));
+ _ ->
+ ok
+ end.
+
+%%-------------------------------------------------------------------------
+rename() ->
+ [{doc, "Rename a file."}].
+rename(Config0) ->
+ Contents = <<"ftp_SUITE test ...">>,
+ OldFile = "old.txt",
+ NewFile = "new.txt",
+ Config = set_state([reset,{mkfile,OldFile,Contents}], Config0),
+ Pid = proplists:get_value(ftp, Config),
+
+ ok = ftp:rename(Pid,
+ id2ftp(OldFile,Config),
+ id2ftp(NewFile,Config)),
+
+ true = (chk_file(NewFile,Contents,Config)
+ and chk_no_file([OldFile],Config)),
+ {error,epath} = ftp:rename(Pid,
+ id2ftp("non_existing_file",Config),
+ id2ftp(NewFile,Config)),
+ ok.
+
+%%-------------------------------------------------------------------------
+send() ->
+ [{doc, "Transfer a file with ftp using send/2."}].
+send(Config0) ->
+ Contents = <<"ftp_SUITE test ...">>,
+ SrcDir = "data",
+ File = "file.txt",
+ Config = set_state([reset,{mkfile,[SrcDir,File],Contents}], Config0),
+ Pid = proplists:get_value(ftp, Config),
+
+ chk_no_file([File],Config),
+ chk_file([SrcDir,File],Contents,Config),
+
+ ok = ftp:lcd(Pid, id2ftp(SrcDir,Config)),
+ ok = ftp:cd(Pid, id2ftp("",Config)),
+ ok = ftp:send(Pid, File),
+ chk_file(File, Contents, Config),
+
+ {error,epath} = ftp:send(Pid, "non_existing_file"),
+ ok.
+
+%%-------------------------------------------------------------------------
+send_3() ->
+ [{doc, "Transfer a file with ftp using send/3."}].
+send_3(Config0) ->
+ Contents = <<"ftp_SUITE test ...">>,
+ Dir = "incoming",
+ File = "file.txt",
+ RemoteFile = "remfile.txt",
+ Config = set_state([reset,{mkfile,File,Contents},{mkdir,Dir}], Config0),
+ Pid = proplists:get_value(ftp, Config),
+
+ ok = ftp:cd(Pid, id2ftp(Dir,Config)),
+ ok = ftp:lcd(Pid, id2ftp("",Config)),
+ ok = ftp:send(Pid, File, RemoteFile),
+ chk_file([Dir,RemoteFile], Contents, Config),
+
+ {error,epath} = ftp:send(Pid, "non_existing_file", RemoteFile),
+ ok.
+
+%%-------------------------------------------------------------------------
+send_bin() ->
+ [{doc, "Send a binary."}].
+send_bin(Config0) ->
+ BinContents = <<"ftp_SUITE test ...">>,
+ File = "file.txt",
+ Config = set_state([reset], Config0),
+ Pid = proplists:get_value(ftp, Config),
+ {error, enotbinary} = ftp:send_bin(Pid, "some string", id2ftp(File,Config)),
+ ok = ftp:send_bin(Pid, BinContents, id2ftp(File,Config)),
+ chk_file(File, BinContents, Config),
+ {error, efnamena} = ftp:send_bin(Pid, BinContents, "/nothere"),
+ ok.
+
+%%-------------------------------------------------------------------------
+send_chunk() ->
+ [{doc, "Send a binary using chunks."}].
+send_chunk(Config0) ->
+ Contents1 = <<"1: ftp_SUITE test ...">>,
+ Contents2 = <<"2: ftp_SUITE test ...">>,
+ File = "file.txt",
+ Config = set_state([reset,{mkdir,"incoming"}], Config0),
+ Pid = proplists:get_value(ftp, Config),
+
+ ok = ftp:send_chunk_start(Pid, id2ftp(File,Config)),
+ {error, echunk} = ftp:send_chunk_start(Pid, id2ftp(File,Config)),
+ {error, echunk} = ftp:cd(Pid, "incoming"),
+ {error, enotbinary} = ftp:send_chunk(Pid, "some string"),
+ ok = ftp:send_chunk(Pid, Contents1),
+ ok = ftp:send_chunk(Pid, Contents2),
+ ok = ftp:send_chunk_end(Pid),
+ chk_file(File, <<Contents1/binary,Contents2/binary>>, Config),
+
+ {error, echunk} = ftp:send_chunk(Pid, Contents1),
+ {error, echunk} = ftp:send_chunk_end(Pid),
+ {error, efnamena} = ftp:send_chunk_start(Pid, "/"),
+ ok.
+
+%%-------------------------------------------------------------------------
+delete() ->
+ [{doc, "Delete a file."}].
+delete(Config0) ->
+ Contents = <<"ftp_SUITE test ...">>,
+ File = "file.txt",
+ Config = set_state([reset,{mkfile,File,Contents}], Config0),
+ Pid = proplists:get_value(ftp, Config),
+ ok = ftp:delete(Pid, id2ftp(File,Config)),
+ chk_no_file([File], Config),
+ {error,epath} = ftp:delete(Pid, id2ftp(File,Config)),
+ ok.
+
+%%-------------------------------------------------------------------------
+mkdir() ->
+ [{doc, "Make a remote directory."}].
+mkdir(Config0) ->
+ NewDir = "new_dir",
+ Config = set_state([reset], Config0),
+ Pid = proplists:get_value(ftp, Config),
+ ok = ftp:mkdir(Pid, id2ftp(NewDir,Config)),
+ chk_dir([NewDir], Config),
+ {error,epath} = ftp:mkdir(Pid, id2ftp(NewDir,Config)),
+ ok.
+
+%%-------------------------------------------------------------------------
+rmdir() ->
+ [{doc, "Remove a directory."}].
+rmdir(Config0) ->
+ Dir = "dir",
+ Config = set_state([reset,{mkdir,Dir}], Config0),
+ Pid = proplists:get_value(ftp, Config),
+ ok = ftp:rmdir(Pid, id2ftp(Dir,Config)),
+ chk_no_dir([Dir], Config),
+ {error,epath} = ftp:rmdir(Pid, id2ftp(Dir,Config)),
+ ok.
+
+%%-------------------------------------------------------------------------
+append() ->
+ [{doc, "Append a local file twice to a remote file"}].
+append(Config0) ->
+ SrcFile = "f_src.txt",
+ DstFile = "f_dst.txt",
+ Contents = <<"ftp_SUITE test ...">>,
+ Config = set_state([reset,{mkfile,SrcFile,Contents}], Config0),
+ Pid = proplists:get_value(ftp, Config),
+ ok = ftp:append(Pid, id2ftp(SrcFile,Config), id2ftp(DstFile,Config)),
+ ok = ftp:append(Pid, id2ftp(SrcFile,Config), id2ftp(DstFile,Config)),
+ chk_file(DstFile, <<Contents/binary,Contents/binary>>, Config),
+ {error,epath} = ftp:append(Pid, id2ftp("non_existing_file",Config), id2ftp(DstFile,Config)),
+ ok.
+
+%%-------------------------------------------------------------------------
+append_bin() ->
+ [{doc, "Append a local file twice to a remote file using append_bin"}].
+append_bin(Config0) ->
+ DstFile = "f_dst.txt",
+ Contents = <<"ftp_SUITE test ...">>,
+ Config = set_state([reset], Config0),
+ Pid = proplists:get_value(ftp, Config),
+ ok = ftp:append_bin(Pid, Contents, id2ftp(DstFile,Config)),
+ ok = ftp:append_bin(Pid, Contents, id2ftp(DstFile,Config)),
+ chk_file(DstFile, <<Contents/binary,Contents/binary>>, Config).
+
+%%-------------------------------------------------------------------------
+append_chunk() ->
+ [{doc, "Append chunks."}].
+append_chunk(Config0) ->
+ File = "f_dst.txt",
+ Contents = [<<"ER">>,<<"LE">>,<<"RL">>],
+ Config = set_state([reset], Config0),
+ Pid = proplists:get_value(ftp, Config),
+ ok = ftp:append_chunk_start(Pid, id2ftp(File,Config)),
+ {error, enotbinary} = ftp:append_chunk(Pid, binary_to_list(lists:nth(1,Contents))),
+ ok = ftp:append_chunk(Pid,lists:nth(1,Contents)),
+ ok = ftp:append_chunk(Pid,lists:nth(2,Contents)),
+ ok = ftp:append_chunk(Pid,lists:nth(3,Contents)),
+ ok = ftp:append_chunk_end(Pid),
+ chk_file(File, <<"ERLERL">>, Config).
+
+%%-------------------------------------------------------------------------
+recv() ->
+ [{doc, "Receive a file using recv/2"}].
+recv(Config0) ->
+ File1 = "f_dst1.txt",
+ File2 = "f_dst2.txt",
+ SrcDir = "a_dir",
+ Contents1 = <<"1 ftp_SUITE test ...">>,
+ Contents2 = <<"2 ftp_SUITE test ...">>,
+ Config = set_state([reset, {mkfile,[SrcDir,File1],Contents1}, {mkfile,[SrcDir,File2],Contents2}], Config0),
+ Pid = proplists:get_value(ftp, Config),
+ ok = ftp:cd(Pid, id2ftp(SrcDir,Config)),
+ ok = ftp:lcd(Pid, id2ftp("",Config)),
+ ok = ftp:recv(Pid, File1),
+ chk_file(File1, Contents1, Config),
+ ok = ftp:recv(Pid, File2),
+ chk_file(File2, Contents2, Config),
+ {error,epath} = ftp:recv(Pid, "non_existing_file"),
+ ok.
+
+%%-------------------------------------------------------------------------
+recv_3() ->
+ [{doc,"Receive a file using recv/3"}].
+recv_3(Config0) ->
+ DstFile = "f_src.txt",
+ SrcFile = "f_dst.txt",
+ Contents = <<"ftp_SUITE test ...">>,
+ Config = set_state([reset, {mkfile,SrcFile,Contents}], Config0),
+ Pid = proplists:get_value(ftp, Config),
+ ok = ftp:cd(Pid, id2ftp("",Config)),
+ ok = ftp:recv(Pid, SrcFile, id2abs(DstFile,Config)),
+ chk_file(DstFile, Contents, Config).
+
+%%-------------------------------------------------------------------------
+recv_bin() ->
+ [{doc, "Receive a file as a binary."}].
+recv_bin(Config0) ->
+ File = "f_dst.txt",
+ Contents = <<"ftp_SUITE test ...">>,
+ Config = set_state([reset, {mkfile,File,Contents}], Config0),
+ Pid = proplists:get_value(ftp, Config),
+ {ok,Received} = ftp:recv_bin(Pid, id2ftp(File,Config)),
+ find_diff(Received, Contents),
+ {error,epath} = ftp:recv_bin(Pid, id2ftp("non_existing_file",Config)),
+ ok.
+
+%%-------------------------------------------------------------------------
+recv_bin_twice() ->
+ [{doc, "Receive two files as a binaries."}].
+recv_bin_twice(Config0) ->
+ File1 = "f_dst1.txt",
+ File2 = "f_dst2.txt",
+ Contents1 = <<"1 ftp_SUITE test ...">>,
+ Contents2 = <<"2 ftp_SUITE test ...">>,
+ Config = set_state([reset, {mkfile,File1,Contents1}, {mkfile,File2,Contents2}], Config0),
+ ct:log("First transfer",[]),
+ Pid = proplists:get_value(ftp, Config),
+ {ok,Received1} = ftp:recv_bin(Pid, id2ftp(File1,Config)),
+ find_diff(Received1, Contents1),
+ ct:log("Second transfer",[]),
+ {ok,Received2} = ftp:recv_bin(Pid, id2ftp(File2,Config)),
+ find_diff(Received2, Contents2),
+ ct:log("Transfers ready!",[]),
+ {error,epath} = ftp:recv_bin(Pid, id2ftp("non_existing_file",Config)),
+ ok.
+%%-------------------------------------------------------------------------
+recv_chunk() ->
+ [{doc, "Receive a file using chunk-wise."}].
+recv_chunk(Config0) ->
+ File = "big_file.txt",
+ Contents = list_to_binary( lists:duplicate(1000, lists:seq(0,255)) ),
+ Config = set_state([reset, {mkfile,File,Contents}], Config0),
+ Pid = proplists:get_value(ftp, Config),
+ {error, "ftp:recv_chunk_start/2 not called"} = do_recv_chunk(Pid),
+ ok = ftp:recv_chunk_start(Pid, id2ftp(File,Config)),
+ {ok, ReceivedContents} = do_recv_chunk(Pid),
+ find_diff(ReceivedContents, Contents).
+
+recv_chunk_twice() ->
+ [{doc, "Receive two files using chunk-wise."}].
+recv_chunk_twice(Config0) ->
+ File1 = "big_file1.txt",
+ File2 = "big_file2.txt",
+ Contents1 = list_to_binary( lists:duplicate(1000, lists:seq(0,255)) ),
+ Contents2 = crypto:strong_rand_bytes(1200),
+ Config = set_state([reset, {mkfile,File1,Contents1}, {mkfile,File2,Contents2}], Config0),
+ Pid = proplists:get_value(ftp, Config),
+ {error, "ftp:recv_chunk_start/2 not called"} = do_recv_chunk(Pid),
+ ok = ftp:recv_chunk_start(Pid, id2ftp(File1,Config)),
+ {ok, ReceivedContents1} = do_recv_chunk(Pid),
+ ok = ftp:recv_chunk_start(Pid, id2ftp(File2,Config)),
+ {ok, ReceivedContents2} = do_recv_chunk(Pid),
+ find_diff(ReceivedContents1, Contents1),
+ find_diff(ReceivedContents2, Contents2).
+
+recv_chunk_three_times() ->
+ [{doc, "Receive two files using chunk-wise."},
+ {timetrap,{seconds,120}}].
+recv_chunk_three_times(Config0) ->
+ File1 = "big_file1.txt",
+ File2 = "big_file2.txt",
+ File3 = "big_file3.txt",
+ Contents1 = list_to_binary( lists:duplicate(1000, lists:seq(0,255)) ),
+ Contents2 = crypto:strong_rand_bytes(1200),
+ Contents3 = list_to_binary( lists:duplicate(1000, lists:seq(255,0,-1)) ),
+
+ Config = set_state([reset, {mkfile,File1,Contents1}, {mkfile,File2,Contents2}, {mkfile,File3,Contents3}], Config0),
+ Pid = proplists:get_value(ftp, Config),
+ {error, "ftp:recv_chunk_start/2 not called"} = do_recv_chunk(Pid),
+
+ ok = ftp:recv_chunk_start(Pid, id2ftp(File3,Config)),
+ {ok, ReceivedContents3} = do_recv_chunk(Pid),
+
+ ok = ftp:recv_chunk_start(Pid, id2ftp(File1,Config)),
+ {ok, ReceivedContents1} = do_recv_chunk(Pid),
+
+ ok = ftp:recv_chunk_start(Pid, id2ftp(File2,Config)),
+ {ok, ReceivedContents2} = do_recv_chunk(Pid),
+
+ find_diff(ReceivedContents1, Contents1),
+ find_diff(ReceivedContents2, Contents2),
+ find_diff(ReceivedContents3, Contents3).
+
+
+do_recv_chunk(Pid) ->
+ recv_chunk(Pid, <<>>).
+recv_chunk(Pid, Acc) ->
+ case ftp:recv_chunk(Pid) of
+ ok ->
+ {ok, Acc};
+ {ok, Bin} ->
+ recv_chunk(Pid, <<Acc/binary, Bin/binary>>);
+ Error ->
+ Error
+ end.
+
+recv_chunk_delay(Config0) when is_list(Config0) ->
+ File1 = "big_file1.txt",
+ Contents = list_to_binary(lists:duplicate(1000, lists:seq(0,255))),
+ Config = set_state([reset, {mkfile,File1,Contents}], Config0),
+ Pid = proplists:get_value(ftp, Config),
+ ok = ftp:recv_chunk_start(Pid, id2ftp(File1,Config)),
+ {ok, ReceivedContents} = delay_recv_chunk(Pid),
+ find_diff(ReceivedContents, Contents).
+
+delay_recv_chunk(Pid) ->
+ delay_recv_chunk(Pid, <<>>).
+delay_recv_chunk(Pid, Acc) ->
+ ct:pal("Recived size ~p", [byte_size(Acc)]),
+ case ftp:recv_chunk(Pid) of
+ ok ->
+ {ok, Acc};
+ {ok, Bin} ->
+ ct:sleep(100),
+ delay_recv_chunk(Pid, <<Acc/binary, Bin/binary>>);
+ Error ->
+ Error
+ end.
+
+%%-------------------------------------------------------------------------
+type() ->
+ [{doc,"Test that we can change btween ASCCI and binary transfer mode"}].
+type(Config) ->
+ Pid = proplists:get_value(ftp, Config),
+ ok = ftp:type(Pid, ascii),
+ ok = ftp:type(Pid, binary),
+ ok = ftp:type(Pid, ascii),
+ {error, etype} = ftp:type(Pid, foobar).
+
+%%-------------------------------------------------------------------------
+quote(Config) ->
+ Pid = proplists:get_value(ftp, Config),
+ ["257 \""++_Rest] = ftp:quote(Pid, "pwd"), %% 257
+ [_| _] = ftp:quote(Pid, "help"),
+ %% This negativ test causes some ftp servers to hang. This test
+ %% is not important for the client, so we skip it for now.
+ %%["425 Can't build data connection: Connection refused."]
+ %% = ftp:quote(Pid, "list"),
+ ok.
+
+%%-------------------------------------------------------------------------
+progress_report_send() ->
+ [{doc, "Test the option progress for ftp:send/[2,3]"}].
+progress_report_send(Config) when is_list(Config) ->
+ ReportPid =
+ spawn_link(?MODULE, progress_report_receiver_init, [self(), 1]),
+ send(Config),
+ receive
+ {ReportPid, ok} ->
+ ok
+ end.
+
+%%-------------------------------------------------------------------------
+progress_report_recv() ->
+ [{doc, "Test the option progress for ftp:recv/[2,3]"}].
+progress_report_recv(Config) when is_list(Config) ->
+ ReportPid =
+ spawn_link(?MODULE, progress_report_receiver_init, [self(), 3]),
+ recv(Config),
+ receive
+ {ReportPid, ok} ->
+ ok
+ end.
+
+%%-------------------------------------------------------------------------
+
+not_owner() ->
+ [{doc, "Test what happens if a process that not owns the connection tries "
+ "to use it"}].
+not_owner(Config) when is_list(Config) ->
+ Pid = proplists:get_value(ftp, Config),
+
+ Parent = self(),
+ OtherPid = spawn_link(
+ fun() ->
+ {error, not_connection_owner} = ftp:pwd(Pid),
+ ftp:close(Pid),
+ Parent ! {self(), ok}
+ end),
+ receive
+ {OtherPid, ok} ->
+ {ok, _} = ftp:pwd(Pid)
+ end.
+
+
+%%-------------------------------------------------------------------------
+
+
+unexpected_call()->
+ [{doc, "Test that behaviour of the ftp process if the api is abused"}].
+unexpected_call(Config) when is_list(Config) ->
+ Flag = process_flag(trap_exit, true),
+ Pid = proplists:get_value(ftp, Config),
+
+ %% Serious programming fault, connetion will be shut down
+ case (catch gen_server:call(Pid, {self(), foobar, 10}, infinity)) of
+ {error, {connection_terminated, 'API_violation'}} ->
+ ok;
+ Unexpected1 ->
+ exit({unexpected_result, Unexpected1})
+ end,
+ ct:sleep(500),
+ undefined = process_info(Pid, status),
+ process_flag(trap_exit, Flag).
+%%-------------------------------------------------------------------------
+
+unexpected_cast()->
+ [{doc, "Test that behaviour of the ftp process if the api is abused"}].
+unexpected_cast(Config) when is_list(Config) ->
+ Flag = process_flag(trap_exit, true),
+ Pid = proplists:get_value(ftp, Config),
+ %% Serious programming fault, connetion will be shut down
+ gen_server:cast(Pid, {self(), foobar, 10}),
+ ct:sleep(500),
+ undefined = process_info(Pid, status),
+ process_flag(trap_exit, Flag).
+%%-------------------------------------------------------------------------
+
+unexpected_bang()->
+ [{doc, "Test that connection ignores unexpected bang"}].
+unexpected_bang(Config) when is_list(Config) ->
+ Flag = process_flag(trap_exit, true),
+ Pid = proplists:get_value(ftp, Config),
+ %% Could be an innocent misstake the connection lives.
+ Pid ! foobar,
+ ct:sleep(500),
+ {status, _} = process_info(Pid, status),
+ process_flag(trap_exit, Flag).
+
+%%-------------------------------------------------------------------------
+
+clean_shutdown() ->
+ [{doc, "Test that owning process that exits with reason "
+ "'shutdown' does not cause an error message. OTP 6035"}].
+
+clean_shutdown(Config) ->
+ Parent = self(),
+ HelperPid = spawn(
+ fun() ->
+ ftp__open(Config, [verbose]),
+ Parent ! ok,
+ receive
+ nothing -> ok
+ end
+ end),
+ receive
+ ok ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ LogFile = filename:join([PrivDir,"ticket_6035.log"]),
+ error_logger:logfile({open, LogFile}),
+ exit(HelperPid, shutdown),
+ timer:sleep(2000),
+ error_logger:logfile(close),
+ case is_error_report_6035(LogFile) of
+ true -> ok;
+ false -> {fail, "Bad logfile"}
+ end
+ end.
+
+%%-------------------------------------------------------------------------
+start_ftp() ->
+ [{doc, "Start/stop of ftp service"}].
+start_ftp(Config) ->
+ Pid0 = proplists:get_value(ftp,Config),
+ Pids0 = [ServicePid || {_, ServicePid} <- ftp:services()],
+ true = lists:member(Pid0, Pids0),
+ {ok, [_|_]} = ftp:service_info(Pid0),
+ ftp:stop_service(Pid0),
+ ct:sleep(100),
+ Pids1 = [ServicePid || {_, ServicePid} <- ftp:services()],
+ false = lists:member(Pid0, Pids1),
+
+ Host = proplists:get_value(ftpd_host,Config),
+ Port = proplists:get_value(ftpd_port,Config),
+
+ {ok, Pid1} = ftp:start_standalone([{host, Host},{port, Port}]),
+ Pids2 = [ServicePid || {_, ServicePid} <- ftp:services()],
+ false = lists:member(Pid1, Pids2).
+
+%%-------------------------------------------------------------------------
+ftp_worker() ->
+ [{doc, "Makes sure the ftp worker processes are added and removed "
+ "appropriatly to/from the supervison tree."}].
+ftp_worker(Config) ->
+ Pid = proplists:get_value(ftp,Config),
+ case supervisor:which_children(ftp_sup) of
+ [{_,_, worker, [ftp]}] ->
+ ftp:stop_service(Pid),
+ ct:sleep(5000),
+ [] = supervisor:which_children(ftp_sup),
+ ok;
+ Children ->
+ ct:fail("Unexpected children: ~p",[Children])
+ end.
+
+
+%%%----------------------------------------------------------------
+%%% Error codes not tested elsewhere
+
+error_elogin(Config0) ->
+ Dir = "test",
+ OldFile = "old.txt",
+ NewFile = "new.txt",
+ SrcDir = "data",
+ File = "file.txt",
+ Config = set_state([reset,
+ {mkdir,Dir},
+ {mkfile,OldFile,<<"Contents..">>},
+ {mkfile,[SrcDir,File],<<"Contents..">>}], Config0),
+
+ Pid = proplists:get_value(ftp, Config),
+ ok = ftp:lcd(Pid, id2ftp(SrcDir,Config)),
+ {error,elogin} = ftp:send(Pid, File),
+ ok = ftp:lcd(Pid, id2ftp("",Config)),
+ {error,elogin} = ftp:pwd(Pid),
+ {error,elogin} = ftp:cd(Pid, id2ftp(Dir,Config)),
+ {error,elogin} = ftp:rename(Pid,
+ id2ftp(OldFile,Config),
+ id2ftp(NewFile,Config)),
+ ok.
+
+error_ehost(_Config) ->
+ {error, ehost} = ftp:open("nohost.nodomain"),
+ ok.
+
+%%--------------------------------------------------------------------
+%% Internal functions -----------------------------------------------
+%%--------------------------------------------------------------------
+
+chk_file(Path=[C|_], ExpectedContents, Config) when 0<C,C=<255 ->
+ chk_file([Path], ExpectedContents, Config);
+
+chk_file(PathList, ExpectedContents, Config) ->
+ Path = filename:join(PathList),
+ AbsPath = id2abs(Path,Config),
+ case file:read_file(AbsPath) of
+ {ok,ExpectedContents} ->
+ true;
+ {ok,ReadContents} ->
+ {error,{diff,Pos,RC,LC}} = find_diff(ReadContents, ExpectedContents, 1),
+ ct:log("Bad contents of ~p.~nGot:~n~p~nExpected:~n~p~nDiff at pos ~p ~nRead: ~p~nExp : ~p",
+ [AbsPath,ReadContents,ExpectedContents,Pos,RC,LC]),
+ ct:fail("Bad contents of ~p", [Path]);
+ {error,Error} ->
+ try begin
+ {ok,CWD} = file:get_cwd(),
+ ct:log("file:get_cwd()=~p~nfiles:~n~p",[CWD,file:list_dir(CWD)])
+ end
+ of _ -> ok
+ catch _:_ ->ok
+ end,
+ ct:fail("Error reading ~p: ~p",[Path,Error])
+ end.
+
+
+chk_no_file(Path=[C|_], Config) when 0<C,C=<255 ->
+ chk_no_file([Path], Config);
+
+chk_no_file(PathList, Config) ->
+ Path = filename:join(PathList),
+ AbsPath = id2abs(Path,Config),
+ case file:read_file(AbsPath) of
+ {error,enoent} ->
+ true;
+ {ok,Contents} ->
+ ct:log("File ~p exists although it shouldn't. Contents:~n~p",
+ [AbsPath,Contents]),
+ ct:fail("File exists: ~p", [Path]);
+ {error,Error} ->
+ ct:fail("Unexpected error reading ~p: ~p",[Path,Error])
+ end.
+
+
+chk_dir(Path=[C|_], Config) when 0<C,C=<255 ->
+ chk_dir([Path], Config);
+
+chk_dir(PathList, Config) ->
+ Path = filename:join(PathList),
+ AbsPath = id2abs(Path,Config),
+ case file:read_file_info(AbsPath) of
+ {ok, #file_info{type=directory}} ->
+ true;
+ {ok, #file_info{type=Type}} ->
+ ct:fail("Expected dir ~p is a ~p",[Path,Type]);
+ {error,Error} ->
+ ct:fail("Expected dir ~p: ~p",[Path,Error])
+ end.
+
+chk_no_dir(PathList, Config) ->
+ Path = filename:join(PathList),
+ AbsPath = id2abs(Path,Config),
+ case file:read_file_info(AbsPath) of
+ {error,enoent} ->
+ true;
+ {ok, #file_info{type=directory}} ->
+ ct:fail("Dir ~p erroneously exists",[Path]);
+ {ok, #file_info{type=Type}} ->
+ ct:fail("~p ~p erroneously exists",[Type,Path]);
+ {error,Error} ->
+ ct:fail("Unexpected error for ~p: ~p",[Path,Error])
+ end.
+
+%%--------------------------------------------------------------------
+find_executable(Config) ->
+ search_executable(proplists:get_value(ftpservers, Config, ?default_ftp_servers)).
+
+
+search_executable([{Name,Paths,_StartCmd,_ChkUp,_StopCommand,_ConfigUpd,_Host,_Port}|Srvrs]) ->
+ case os_find(Name,Paths) of
+ false ->
+ ct:log("~p not found",[Name]),
+ search_executable(Srvrs);
+ AbsName ->
+ ct:comment("Found ~p",[AbsName]),
+ {ok, {AbsName,_StartCmd,_ChkUp,_StopCommand,_ConfigUpd,_Host,_Port}}
+ end;
+search_executable([]) ->
+ false.
+
+
+os_find(Name, Paths) ->
+ case os:find_executable(Name, Paths) of
+ false -> os:find_executable(Name);
+ AbsName -> AbsName
+ end.
+
+%%%----------------------------------------------------------------
+start_ftpd(Config0) ->
+ {AbsName,StartCmd,_ChkUp,_StopCommand,ConfigRewrite,Host,Port} =
+ proplists:get_value(ftpd_data, Config0),
+ case StartCmd(Config0, AbsName) of
+ {ok,StartResult} ->
+ Config = [{ftpd_host,Host},
+ {ftpd_port,Port},
+ {ftpd_start_result,StartResult} | ConfigRewrite(Config0)],
+ try
+ ftp__close(ftp__open(Config,[verbose]))
+ of
+ Config1 when is_list(Config1) ->
+ ct:log("Usuable ftp server ~p started on ~p:~p",[AbsName,Host,Port]),
+ Config
+ catch
+ Class:Exception ->
+ ct:log("Ftp server ~p started on ~p:~p but is unusable:~n~p:~p",
+ [AbsName,Host,Port,Class,Exception]),
+ {skip, [AbsName," started but unusuable"]}
+ end;
+ {error,Msg} ->
+ {skip, [AbsName," not started: ",Msg]}
+ end.
+
+stop_ftpd(Config) ->
+ {_Name,_StartCmd,_ChkUp,StopCommand,_ConfigUpd,_Host,_Port} = proplists:get_value(ftpd_data, Config),
+ StopCommand(proplists:get_value(ftpd_start_result,Config)).
+
+ps_ftpd(Config) ->
+ {_Name,_StartCmd,ChkUp,_StopCommand,_ConfigUpd,_Host,_Port} = proplists:get_value(ftpd_data, Config),
+ ct:log( ChkUp(proplists:get_value(ftpd_start_result,Config)) ).
+
+
+ftpd_running(Config) ->
+ {_Name,_StartCmd,ChkUp,_StopCommand,_ConfigUpd,_Host,_Port} = proplists:get_value(ftpd_data, Config),
+ ChkUp(proplists:get_value(ftpd_start_result,Config)).
+
+ftp__open(Config, Options) ->
+ Host = proplists:get_value(ftpd_host,Config),
+ Port = proplists:get_value(ftpd_port,Config),
+ ct:log("Host=~p, Port=~p",[Host,Port]),
+ {ok,Pid} = ftp:open(Host, [{port,Port} | Options]),
+ [{ftp,Pid}|Config].
+
+ftp__close(Config) ->
+ ok = ftp:close(proplists:get_value(ftp,Config)),
+ Config.
+
+ftp_start_service(Config, Options) ->
+ Host = proplists:get_value(ftpd_host,Config),
+ Port = proplists:get_value(ftpd_port,Config),
+ ct:log("Host=~p, Port=~p",[Host,Port]),
+ {ok,Pid} = ftp:start_service([{host, Host},{port,Port} | Options]),
+ [{ftp,Pid}|Config].
+
+ftp_stop_service(Config) ->
+ ok = ftp:stop_service(proplists:get_value(ftp,Config)),
+ Config.
+
+split(Cs) -> string:tokens(Cs, "\r\n").
+
+find_diff(Bin1, Bin2) ->
+ case find_diff(Bin1, Bin2, 1) of
+ {error, {diff,Pos,RC,LC}} ->
+ ct:log("Contents differ at position ~p.~nOp1: ~p~nOp2: ~p",[Pos,RC,LC]),
+ ct:fail("Contents differ at pos ~p",[Pos]);
+ Other ->
+ Other
+ end.
+
+find_diff(A, A, _) -> true;
+find_diff(<<H,T1/binary>>, <<H,T2/binary>>, Pos) -> find_diff(T1, T2, Pos+1);
+find_diff(RC, LC, Pos) -> {error, {diff, Pos, RC, LC}}.
+
+set_state(Ops, Config) when is_list(Ops) -> lists:foldl(fun set_state/2, Config, Ops);
+
+set_state(reset, Config) ->
+ rm('*', id2abs("",Config)),
+ PrivDir = proplists:get_value(priv_dir,Config),
+ file:set_cwd(PrivDir),
+ ftp:lcd(proplists:get_value(ftp,Config),PrivDir),
+ set_state({mkdir,""},Config);
+set_state({mkdir,Id}, Config) ->
+ Abs = id2abs(Id, Config),
+ mk_path(Abs),
+ file:make_dir(Abs),
+ Config;
+set_state({mkfile,Id,Contents}, Config) ->
+ Abs = id2abs(Id, Config),
+ mk_path(Abs),
+ ok = file:write_file(Abs, Contents),
+ Config.
+
+mk_path(Abs) -> lists:foldl(fun mk_path/2, [], filename:split(filename:dirname(Abs))).
+
+mk_path(F, Pfx) ->
+ case file:read_file_info(AbsName=filename:join(Pfx,F)) of
+ {ok,#file_info{type=directory}} ->
+ AbsName;
+ {error,eexist} ->
+ AbsName;
+ {error,enoent} ->
+ ok = file:make_dir(AbsName),
+ AbsName
+ end.
+
+rm('*', Pfx) ->
+ {ok,Fs} = file:list_dir(Pfx),
+ lists:foreach(fun(F) -> rm(F, Pfx) end, Fs);
+rm(F, Pfx) ->
+ case file:read_file_info(AbsName=filename:join(Pfx,F)) of
+ {ok,#file_info{type=directory}} ->
+ {ok,Fs} = file:list_dir(AbsName),
+ lists:foreach(fun(F1) -> rm(F1,AbsName) end, Fs),
+ ok = file:del_dir(AbsName);
+
+ {ok,#file_info{type=regular}} ->
+ ok = file:delete(AbsName);
+
+ {error,enoent} ->
+ ok
+ end.
+
+id2abs(Id, Conf) -> filename:join(proplists:get_value(priv_dir,Conf),ids(Id)).
+id2ftp(Id, Conf) -> (proplists:get_value(id2ftp,Conf))(ids(Id)).
+id2ftp_result(Id, Conf) -> (proplists:get_value(id2ftp_result,Conf))(ids(Id)).
+
+ids([[_|_]|_]=Ids) -> filename:join(Ids);
+ids(Id) -> Id.
+
+
+is_expected_absName(Id, File, Conf) -> File = (proplists:get_value(id2abs,Conf))(Id).
+is_expected_ftpInName(Id, File, Conf) -> File = (proplists:get_value(id2ftp,Conf))(Id).
+is_expected_ftpOutName(Id, File, Conf) -> File = (proplists:get_value(id2ftp_result,Conf))(Id).
+
+
+%%%----------------------------------------------------------------
+%%% Help functions for the option '{progress,Progress}'
+%%%
+
+%%%----------------
+%%% Callback:
+
+progress(#progress{} = P, _File, {file_size, Total} = M) ->
+ ct:pal("Progress: ~p",[M]),
+ progress_report_receiver ! start,
+ P#progress{total = Total};
+
+progress(#progress{current = Current} = P, _File, {transfer_size, 0} = M) ->
+ ct:pal("Progress: ~p",[M]),
+ progress_report_receiver ! finish,
+ case P#progress.total of
+ unknown -> P;
+ Current -> P;
+ Total -> ct:fail({error, {progress, {total,Total}, {current,Current}}}),
+ P
+ end;
+
+progress(#progress{current = Current} = P, _File, {transfer_size, Size} = M) ->
+ ct:pal("Progress: ~p",[M]),
+ progress_report_receiver ! update,
+ P#progress{current = Current + Size};
+
+progress(P, _File, M) ->
+ ct:pal("Progress **** Strange: ~p",[M]),
+ P.
+
+
+%%%----------------
+%%% Help process that counts the files transferred:
+
+progress_report_receiver_init(Parent, N) ->
+ register(progress_report_receiver, self()),
+ progress_report_receiver_expect_N_files(Parent, N).
+
+progress_report_receiver_expect_N_files(_Parent, 0) ->
+ ct:pal("progress_report got all files!", []);
+progress_report_receiver_expect_N_files(Parent, N) ->
+ ct:pal("progress_report expects ~p more files",[N]),
+ receive
+ start -> ok
+ end,
+ progress_report_receiver_loop(Parent, N-1).
+
+
+progress_report_receiver_loop(Parent, N) ->
+ ct:pal("progress_report expect update | finish. N = ~p",[N]),
+ receive
+ update ->
+ ct:pal("progress_report got update",[]),
+ progress_report_receiver_loop(Parent, N);
+ finish ->
+ ct:pal("progress_report got finish, send ~p to ~p",[{self(),ok}, Parent]),
+ Parent ! {self(), ok},
+ progress_report_receiver_expect_N_files(Parent, N)
+ end.
+
+%%%----------------------------------------------------------------
+%%% Help functions for bug OTP-6035
+
+is_error_report_6035(LogFile) ->
+ case file:read_file(LogFile) of
+ {ok, Bin} ->
+ nomatch =/= binary:match(Bin, <<"=ERROR REPORT====">>);
+ _ ->
+ false
+ end.
+
diff --git a/lib/inets/test/ftp_SUITE_data/ftpd_hosts.skel b/lib/ftp/test/ftp_SUITE_data/ftpd_hosts.skel
index 75096ce687..75096ce687 100644
--- a/lib/inets/test/ftp_SUITE_data/ftpd_hosts.skel
+++ b/lib/ftp/test/ftp_SUITE_data/ftpd_hosts.skel
diff --git a/lib/ftp/test/ftp_SUITE_data/vsftpd.conf b/lib/ftp/test/ftp_SUITE_data/vsftpd.conf
new file mode 100644
index 0000000000..4568fad147
--- /dev/null
+++ b/lib/ftp/test/ftp_SUITE_data/vsftpd.conf
@@ -0,0 +1,33 @@
+
+###
+### Some parameters are given in the vsftpd start command.
+###
+### Typical command-line paramters are such that has a file path
+### component like cert files.
+###
+
+
+listen=YES
+listen_port=9999
+run_as_launching_user=YES
+ssl_enable=YES
+ssl_ciphers=HIGH:!aNULL:!MD5
+allow_anon_ssl=YES
+
+background=YES
+
+write_enable=YES
+anonymous_enable=YES
+anon_upload_enable=YES
+anon_mkdir_write_enable=YES
+anon_other_write_enable=YES
+anon_world_readable_only=NO
+
+### Shouldn't be necessary....
+require_ssl_reuse=NO
+
+### Logging
+#vsftpd_log_file=/devel/otp/vsftpd.log
+#xferlog_enable=YES
+#xferlog_std_format=NO
+#log_ftp_protocol=YES \ No newline at end of file
diff --git a/lib/ftp/test/ftp_bench.spec b/lib/ftp/test/ftp_bench.spec
new file mode 100644
index 0000000000..4d1ecf8891
--- /dev/null
+++ b/lib/ftp/test/ftp_bench.spec
@@ -0,0 +1 @@
+{suites,"../ftp_test",[]}.
diff --git a/lib/ftp/test/ftp_format_SUITE.erl b/lib/ftp/test/ftp_format_SUITE.erl
new file mode 100644
index 0000000000..e1d0de2390
--- /dev/null
+++ b/lib/ftp/test/ftp_format_SUITE.erl
@@ -0,0 +1,328 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+-module(ftp_format_SUITE).
+-author('[email protected]').
+
+-include_lib("common_test/include/ct.hrl").
+-include("ftp_internal.hrl").
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap,{seconds,5}}
+ ].
+
+all() ->
+ [{group, ftp_response}, format_error].
+
+groups() ->
+ [{ftp_response, [],
+ [ftp_150, ftp_200, ftp_220, ftp_226, ftp_257, ftp_331,
+ ftp_425, ftp_other_status_codes, ftp_multiple_lines_status_in_msg,
+ ftp_multiple_lines, ftp_multipel_ctrl_messages]}].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+
+init_per_testcase(_, Config) ->
+ Config.
+end_per_testcase(_, _) ->
+ ok.
+
+%%-------------------------------------------------------------------------
+%% Test cases starts here.
+%%-------------------------------------------------------------------------
+
+ftp_150() ->
+ [{doc, "Especially check that respons can be devided in a random place."}].
+ftp_150(Config) when is_list(Config) ->
+ FtpResponse = ["150 ASCII data conn", "ection for /bin/ls ",
+ "(134.138.177", ".89,50434) (0 bytes).\r\n"],
+
+ "150 ASCII data connection for /bin/ls "
+ "(134.138.177.89,50434) (0 bytes).\r\n" = Msg =
+ parse(ftp_response, parse_lines, [[], start], FtpResponse),
+ {pos_prel, _} = ftp_response:interpret(Msg).
+
+ftp_200() ->
+ [{doc, "Especially check that respons can be devided after the first status "
+ "code character and in the end delimiter."}].
+ftp_200(Config) when is_list(Config) ->
+ FtpResponse = ["2", "00 PORT command successful.", [?CR], [?LF]],
+
+ "200 PORT command successful.\r\n" = Msg =
+ parse(ftp_response, parse_lines, [[], start], FtpResponse),
+ {pos_compl, _} = ftp_response:interpret(Msg),
+ ok.
+
+ftp_220() ->
+ [{doc, "Especially check that respons can be devided after the "
+ "first with space "}].
+ftp_220(Config) when is_list(Config) ->
+ FtpResponse = ["220 ","fingon FTP server (SunOS 5.8) ready.\r\n"],
+
+ "220 fingon FTP server (SunOS 5.8) ready.\r\n" = Msg =
+ parse(ftp_response, parse_lines, [[], start], FtpResponse),
+ {pos_compl, _} = ftp_response:interpret(Msg),
+ ok.
+
+ftp_226() ->
+ [{doc, "Especially check that respons can be devided after second status code"
+ " character and in the end delimiter."}].
+ftp_226(Config) when is_list(Config) ->
+ FtpResponse = ["22" "6 Transfer complete.\r", [?LF]],
+
+ "226 Transfer complete.\r\n" = Msg =
+ parse(ftp_response, parse_lines, [[], start], FtpResponse),
+ {pos_compl, _} = ftp_response:interpret(Msg),
+ ok.
+
+ftp_257() ->
+ [{doc, "Especially check that quoted chars do not cause a problem."}].
+ftp_257(Config) when is_list(Config) ->
+ FtpResponse = ["257 \"/\" is current directory.\r\n"],
+
+ "257 \"/\" is current directory.\r\n" = Msg =
+ parse(ftp_response, parse_lines, [[], start], FtpResponse),
+ {pos_compl, _} = ftp_response:interpret(Msg),
+ ok.
+
+ftp_331() ->
+ [{doc, "Especially check that respons can be devided after the third status "
+ " status code character."}].
+ftp_331(Config) when is_list(Config) ->
+ %% Brake before white space after code
+ FtpResponse =
+ ["331"," Guest login ok, send ient as password.\r\n"],
+
+ "331 Guest login ok, send ient as password.\r\n" = Msg =
+ parse(ftp_response, parse_lines, [[], start], FtpResponse),
+ {pos_interm, _} = ftp_response:interpret(Msg),
+ ok.
+
+ftp_425() ->
+ [{doc, "Especially check a message that was received in only one part."}].
+ftp_425(Config) when is_list(Config) ->
+ FtpResponse =
+ ["425 Can't build data connection: Connection refused.\r\n"],
+
+ "425 Can't build data connection: Connection refused.\r\n"
+ = Msg = parse(ftp_response, parse_lines, [[], start], FtpResponse),
+ {trans_neg_compl, _} = ftp_response:interpret(Msg),
+ ok.
+
+ftp_multiple_lines_status_in_msg() ->
+ [{doc, "check that multiple lines gets parsed correct, even if we have "
+ " the status code within the msg being sent"}].
+ftp_multiple_lines_status_in_msg(Config) when is_list(Config) ->
+ ML = "230-User usr-230 is logged in\r\n" ++
+ "230 OK. Current directory is /\r\n",
+ {ok, ML, <<>>} = ftp_response:parse_lines(list_to_binary(ML), [], start),
+ ok.
+
+ftp_multiple_lines() ->
+ [{doc, "Especially check multiple lines devided in significant places"}].
+ftp_multiple_lines(Config) when is_list(Config) ->
+ FtpResponse = ["21", "4","-The",
+ " following commands are recognized:\r\n"
+ " USER EPRT STRU MAIL* ALLO CWD",
+ " STAT* XRMD \r\n"
+ " PASS LPRT MODE MSND* "
+ " REST* XCWD HELP PWD ", [?CRLF],
+ " ACCT* EPSV RETR MSOM* RNFR LIST "
+ " NOOP XPWD \r\n",
+ " REIN* LPSV STOR MSAM* RNTO NLST "
+ " MKD CDUP \r\n"
+ " QUIT PASV APPE MRSQ* ABOR SITE* "
+ " XMKD XCUP \r\n"
+ " PORT TYPE MLFL* MRCP* DELE SYST "
+ " RMD STOU \r\n"
+ "214 (*'s => unimplemented)", [?CR], [?LF]],
+
+
+ FtpResponse1 = ["214-", "The",
+ " following commands are recognized:\r\n"
+ " USER EPRT STRU MAIL* ALLO CWD",
+ " STAT* XRMD \r\n"
+ " PASS LPRT MODE MSND* "
+ " REST* XCWD HELP PWD ", [?CRLF],
+ " ACCT* EPSV RETR MSOM* RNFR LIST "
+ " NOOP XPWD \r\n",
+ " REIN* LPSV STOR MSAM* RNTO NLST "
+ " MKD CDUP \r\n"
+ " QUIT PASV APPE MRSQ* ABOR SITE* "
+ " XMKD XCUP \r\n"
+ " PORT TYPE MLFL* MRCP* DELE SYST "
+ " RMD STOU \r\n"
+ "2", "14 (*'s => unimplemented)", [?CR], [?LF]],
+
+ FtpResponse2 = ["214-", "The",
+ " following commands are recognized:\r\n"
+ " USER EPRT STRU MAIL* ALLO CWD",
+ " STAT* XRMD \r\n"
+ " PASS LPRT MODE MSND* "
+ " REST* XCWD HELP PWD ", [?CRLF],
+ " ACCT* EPSV RETR MSOM* RNFR LIST "
+ " NOOP XPWD \r\n",
+ " REIN* LPSV STOR MSAM* RNTO NLST "
+ " MKD CDUP \r\n"
+ " QUIT PASV APPE MRSQ* ABOR SITE* "
+ " XMKD XCUP \r\n"
+ " PORT TYPE MLFL* MRCP* DELE SYST "
+ " RMD STOU \r\n"
+ "21", "4"," (*'s => unimplemented)", [?CR], [?LF]],
+
+ MultiLineResultStr =
+ "214-The following commands are recognized:\r\n"
+ " USER EPRT STRU MAIL* ALLO CWD STAT* "
+ "XRMD \r\n"
+ " PASS LPRT MODE MSND* REST* XCWD HELP "
+ "PWD \r\n"
+ " ACCT* EPSV RETR MSOM* RNFR LIST NOOP "
+ "XPWD \r\n"
+ " REIN* LPSV STOR MSAM* RNTO NLST MKD "
+ "CDUP \r\n"
+ " QUIT PASV APPE MRSQ* ABOR SITE* XMKD "
+ "XCUP \r\n"
+ " PORT TYPE MLFL* MRCP* DELE SYST RMD "
+ "STOU \r\n"
+ "214 (*'s => unimplemented)\r\n",
+
+ MultiLineResultStr =
+ parse(ftp_response, parse_lines, [[], start], FtpResponse),
+ {pos_compl, _} = ftp_response:interpret(MultiLineResultStr),
+
+ MultiLineResultStr = parse(ftp_response, parse_lines, [[], start],
+ FtpResponse1),
+
+ MultiLineResultStr = parse(ftp_response, parse_lines, [[], start],
+ FtpResponse2),
+ ok.
+
+ftp_other_status_codes() ->
+ [{doc, "Check that other valid status codes, than the ones above, are handled"
+ "by ftp_response:interpret/1. Note there are som ftp status codes"
+ "that will not be received with the current ftp instruction support,"
+ "they are not included here."}].
+ftp_other_status_codes(Config) when is_list(Config) ->
+
+ %% 1XX
+ {pos_prel, _ } = ftp_response:interpret("120 Foobar\r\n"),
+
+ %% 2XX
+ {pos_compl, _ } = ftp_response:interpret("202 Foobar\r\n"),
+ {pos_compl, _ } = ftp_response:interpret("221 Foobar\r\n"),
+ {pos_compl, _ } = ftp_response:interpret("227 Foobar\r\n"),
+ {pos_compl, _ } = ftp_response:interpret("230 Foobar\r\n"),
+ {pos_compl, _ } = ftp_response:interpret("250 Foobar\r\n"),
+
+ %% 3XX
+ {pos_interm_acct, _ } = ftp_response:interpret("332 Foobar\r\n"),
+ {pos_interm, _ } = ftp_response:interpret("350 Foobar\r\n"),
+
+ %% 4XX
+ {trans_neg_compl, _ } = ftp_response:interpret("421 Foobar\r\n"),
+ {trans_neg_compl, _ } = ftp_response:interpret("426 Foobar\r\n"),
+ {enofile, _ } = ftp_response:interpret("450 Foobar\r\n"),
+ {trans_neg_compl, _ } = ftp_response:interpret("451 Foobar\r\n"),
+ {etnospc, _ } = ftp_response:interpret("452 Foobar\r\n"),
+
+ %% 5XX
+ {perm_neg_compl, _ } = ftp_response:interpret("500 Foobar\r\n"),
+ {perm_neg_compl, _ } = ftp_response:interpret("501 Foobar\r\n"),
+ {perm_neg_compl, _ } = ftp_response:interpret("503 Foobar\r\n"),
+ {perm_neg_compl, _ } = ftp_response:interpret("504 Foobar\r\n"),
+ {elogin, _ } = ftp_response:interpret("530 Foobar\r\n"),
+ {perm_neg_compl, _ } = ftp_response:interpret("532 Foobar\r\n"),
+ {epath, _ } = ftp_response:interpret("550 Foobar\r\n"),
+ {epnospc, _ } = ftp_response:interpret("552 Foobar\r\n"),
+ {efnamena, _ } = ftp_response:interpret("553 Foobar\r\n"),
+ ok.
+
+ftp_multipel_ctrl_messages() ->
+ [{doc, "The ftp server may send more than one control message as a reply,"
+ "check that they are handled one at the time."}].
+ftp_multipel_ctrl_messages(Config) when is_list(Config) ->
+ FtpResponse = ["200 PORT command successful.\r\n200 Foobar\r\n"],
+
+ {"200 PORT command successful.\r\n" = Msg, NextMsg} =
+ parse(ftp_response, parse_lines, [[], start], FtpResponse),
+ {pos_compl, _} = ftp_response:interpret(Msg),
+ NewMsg = parse(ftp_response, parse_lines, [[], start], NextMsg),
+ {pos_compl, _} = ftp_response:interpret(NewMsg),
+ ok.
+
+
+%%-------------------------------------------------------------------------
+format_error(Config) when is_list(Config) ->
+ "Synchronisation error during chunk sending." =
+ ftp:formaterror(echunk),
+ "Session has been closed." = ftp:formaterror(eclosed),
+ "Connection to remote server prematurely closed." =
+ ftp:formaterror(econn),
+ "File or directory already exists." = ftp:formaterror(eexists),
+ "Host not found, FTP server not found, or connection rejected." =
+ ftp:formaterror(ehost),
+ "User not logged in." = ftp:formaterror(elogin),
+ "Term is not a binary." = ftp:formaterror(enotbinary),
+ "No such file or directory, already exists, or permission denied."
+ = ftp:formaterror(epath),
+ "No such type." = ftp:formaterror(etype),
+ "User name or password not valid." = ftp:formaterror(euser),
+ "Insufficient storage space in system." = ftp:formaterror(etnospc),
+ "Exceeded storage allocation (for current directory or dataset)."
+ = ftp:formaterror(epnospc),
+ "File name not allowed." = ftp:formaterror(efnamena),
+ "Unknown error: foobar" = ftp:formaterror({error, foobar}).
+
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
+parse(Module, Function, Args, Bin) when is_binary(Bin) ->
+ parse(Module, Function, Args, [binary_to_list(Bin)]);
+
+parse(Module, Function, [AccLines, StatusCode], [Data | Rest]) ->
+ case Module:Function(list_to_binary(Data), AccLines, StatusCode) of
+ {ok, Result, <<>>} ->
+ Result;
+ {ok, Result, Next} ->
+ {Result, Next};
+ {continue, {NewData, NewAccLines, NewStatusCode}} ->
+ case Rest of
+ [] ->
+ ct:fail({wrong_input, Data, Rest});
+ [_ | _] ->
+ parse(Module, Function, [NewAccLines, NewStatusCode],
+ [binary_to_list(NewData) ++ hd(Rest) | tl(Rest)])
+ end
+ end.
diff --git a/lib/ftp/test/ftp_internal.hrl b/lib/ftp/test/ftp_internal.hrl
new file mode 120000
index 0000000000..2ae5c46460
--- /dev/null
+++ b/lib/ftp/test/ftp_internal.hrl
@@ -0,0 +1 @@
+../src/ftp_internal.hrl \ No newline at end of file
diff --git a/lib/ftp/test/ftp_property_test_SUITE.erl b/lib/ftp/test/ftp_property_test_SUITE.erl
new file mode 100644
index 0000000000..cd43613b9e
--- /dev/null
+++ b/lib/ftp/test/ftp_property_test_SUITE.erl
@@ -0,0 +1,55 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+%%% Run like this:
+%%% ct:run_test([{suite,"ftp_property_test_SUITE"}, {logdir,"/ldisk/OTP/LOG"}]).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%% %%%
+%%% WARNING %%%
+%%% %%%
+%%% This is experimental code which may be changed or removed %%%
+%%% anytime without any warning. %%%
+%%% %%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-module(ftp_property_test_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+all() -> [prop_ftp_case].
+
+
+init_per_suite(Config) ->
+ ftp:start(),
+ ct_property_test:init_per_suite(Config).
+
+end_per_suite(Config) ->
+ Config.
+
+%%%---- test case
+prop_ftp_case(Config) ->
+ ct_property_test:quickcheck(
+ ftp_simple_client_server:prop_ftp(Config),
+ Config
+ ).
diff --git a/lib/ftp/test/ftp_test_lib.erl b/lib/ftp/test/ftp_test_lib.erl
new file mode 100644
index 0000000000..f5fbc39037
--- /dev/null
+++ b/lib/ftp/test/ftp_test_lib.erl
@@ -0,0 +1,126 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+-module(ftp_test_lib).
+
+-include_lib("public_key/include/public_key.hrl").
+
+-export([make_cert_files/1]).
+
+
+make_cert_files(Dir) ->
+ #{server_config := ServerConf,
+ client_config := _} =
+ public_key:pkix_test_data(#{server_chain =>
+ #{root => [{key, hardcode_rsa_key(1)}],
+ intermediates => [[{key, hardcode_rsa_key(2)}]],
+ peer => [{key, hardcode_rsa_key(3)}]},
+ client_chain =>
+ #{root => [{key, hardcode_rsa_key(1)}],
+ intermediates => [[{key, hardcode_rsa_key(3)}]],
+ peer => [{key, hardcode_rsa_key(2)}]}}),
+
+ CaCertFile = filename:join(Dir, "server-cacerts.pem"),
+ CertFile = filename:join(Dir, "server-cert.pem"),
+ KeyFile = filename:join(Dir, "server-key.pem"),
+
+ CAs = proplists:get_value(cacerts, ServerConf),
+ Cert = proplists:get_value(cert, ServerConf),
+ Key = proplists:get_value(key, ServerConf),
+ der_to_pem(CertFile, [cert_entry(Cert)]),
+ der_to_pem(KeyFile, [key_entry(Key)]),
+ der_to_pem(CaCertFile, ca_entries(CAs)).
+
+cert_entry(Cert) ->
+ {'Certificate', Cert, not_encrypted}.
+
+key_entry({'RSAPrivateKey', DERKey}) ->
+ {'RSAPrivateKey', DERKey, not_encrypted};
+key_entry({'DSAPrivateKey', DERKey}) ->
+ {'DSAPrivateKey', DERKey, not_encrypted};
+key_entry({'ECPrivateKey', DERKey}) ->
+ {'ECPrivateKey', DERKey, not_encrypted}.
+
+ca_entries(CAs) ->
+ [{'Certificate', CACert, not_encrypted} || CACert <- CAs].
+
+der_to_pem(File, Entries) ->
+ PemBin = public_key:pem_encode(Entries),
+ file:write_file(File, PemBin).
+
+hardcode_rsa_key(1) ->
+ #'RSAPrivateKey'{
+ version = 'two-prime',
+ modulus =
+23995666614853919027835084074500048897452890537492185072956789802729257783422306095699263934587064480357348855732149402060270996295002843755712064937715826848741191927820899197493902093529581182351132392364214171173881547273475904587683433713767834856230531387991145055273426806331200574039205571401702219159773947658558490957010003143162250693492642996408861265758000254664396313741422909188635443907373976005987612936763564996605457102336549804831742940035613780926178523017685712710473543251580072875247250504243621640157403744718833162626193206685233710319205099867303242759099560438381385658382486042995679707669,
+ publicExponent = 17,
+ privateExponent =
+11292078406990079542510627799764728892919007311761028269626724613049062486316379339152594792746853873109340637991599718616598115903530750002688030558925094987642913848386305504703012749896273497577003478759630198199473669305165131570674557041773098755873191241407597673069847908861741446606684974777271632545629600685952292605647052193819136445675100211504432575554351515262198132231537860917084269870590492135731720141577986787033006338680118008484613510063003323516659048210893001173583018220214626635609151105287049126443102976056146630518124476470236027123782297108342869049542023328584384300970694412006494684657,
+prime1 =
+169371138592582642967021557955633494538845517070305333860805485424261447791289944610138334410987654265476540480228705481960508520379619587635662291973699651583489223555422528867090299996446070521801757353675026048850480903160224210802452555900007597342687137394192939372218903554801584969667104937092080815197,
+ prime2 =
+141675062317286527042995673340952251894209529891636708844197799307963834958115010129693036021381525952081167155681637592199810112261679449166276939178032066869788822014115556349519329537177920752776047051833616197615329017439297361972726138285974555338480581117881706656603857310337984049152655480389797687577,
+ exponent1 =
+119556097830058336212015217380447172615655659108450823901745048534772786676204666783627059584226579481512852103690850928442711896738555003036938088452023283470698275450886490965004917644550167427154181661417665446247398284583687678213495921811770068712485038160606780733330990744565824684470897602653233516609,
+ exponent2 =
+41669135975672507953822256864985956439473391144599032012999352737636422046504414744027363535700448809435637398729893409470532385959317485048904982111185902020526124121798693043976273393287623750816484427009887116945685005129205106462566511260580751570141347387612266663707016855981760014456663376585234613993,
+ coefficient =
+76837684977089699359024365285678488693966186052769523357232308621548155587515525857011429902602352279058920284048929101483304120686557782043616693940283344235057989514310975192908256494992960578961614059245280827077951132083993754797053182279229469590276271658395444955906108899267024101096069475145863928441,
+ otherPrimeInfos = asn1_NOVALUE};
+
+hardcode_rsa_key(2) ->
+ #'RSAPrivateKey'{
+ version = 'two-prime',
+ modulus =
+21343679768589700771839799834197557895311746244621307033143551583788179817796325695589283169969489517156931770973490560582341832744966317712674900833543896521418422508485833901274928542544381247956820115082240721897193055368570146764204557110415281995205343662628196075590438954399631753508888358737971039058298703003743872818150364935790613286541190842600031570570099801682794056444451081563070538409720109449780410837763602317050353477918147758267825417201591905091231778937606362076129350476690460157227101296599527319242747999737801698427160817755293383890373574621116766934110792127739174475029121017282777887777,
+ publicExponent = 17,
+ privateExponent =
+18832658619343853622211588088997845201745658451136447382185486691577805721584993260814073385267196632785528033211903435807948675951440868570007265441362261636545666919252206383477878125774454042314841278013741813438699754736973658909592256273895837054592950290554290654932740253882028017801960316533503857992358685308186680144968293076156011747178275038098868263178095174694099811498968993700538293188879611375604635940554394589807673542938082281934965292051746326331046224291377703201248790910007232374006151098976879987912446997911775904329728563222485791845480864283470332826504617837402078265424772379987120023773,
+ prime1 =
+146807662748886761089048448970170315054939768171908279335181627815919052012991509112344782731265837727551849787333310044397991034789843793140419387740928103541736452627413492093463231242466386868459637115999163097726153692593711599245170083315894262154838974616739452594203727376460632750934355508361223110419,
+ prime2 =
+145385325050081892763917667176962991350872697916072592966410309213561884732628046256782356731057378829876640317801978404203665761131810712267778698468684631707642938779964806354584156202882543264893826268426566901882487709510744074274965029453915224310656287149777603803201831202222853023280023478269485417083,
+ exponent1 =
+51814469205489445090252393754177758254684624060673510353593515699736136004585238510239335081623236845018299924941168250963996835808180162284853901555621683602965806809675350150634081614988136541809283687999704622726877773856604093851236499993845033701707873394143336209718962603456693912094478414715725803677,
+ exponent2 =
+51312467664734785681382706062457526359131540440966797517556579722433606376221663384746714140373192528191755406283051201483646739222992016094510128871300458249756331334105225772206172777487956446433115153562317730076172132768497908567634716277852432109643395464627389577600646306666889302334125933506877206029,
+ coefficient =
+30504662229874176232343608562807118278893368758027179776313787938167236952567905398252901545019583024374163153775359371298239336609182249464886717948407152570850677549297935773605431024166978281486607154204888016179709037883348099374995148481968169438302456074511782717758301581202874062062542434218011141540,
+ otherPrimeInfos = asn1_NOVALUE};
+
+hardcode_rsa_key(3) ->
+ #'RSAPrivateKey'{
+ version = 'two-prime',
+ modulus =
+25089040456112869869472694987833070928503703615633809313972554887193090845137746668197820419383804666271752525807484521370419854590682661809972833718476098189250708650325307850184923546875260207894844301992963978994451844985784504212035958130279304082438876764367292331581532569155681984449177635856426023931875082020262146075451989132180409962870105455517050416234175675478291534563995772675388370042873175344937421148321291640477650173765084699931690748536036544188863178325887393475703801759010864779559318631816411493486934507417755306337476945299570726975433250753415110141783026008347194577506976486290259135429,
+ publicExponent = 17,
+ privateExponent =
+8854955455098659953931539407470495621824836570223697404931489960185796768872145882893348383311931058684147950284994536954265831032005645344696294253579799360912014817761873358888796545955974191021709753644575521998041827642041589721895044045980930852625485916835514940558187965584358347452650930302268008446431977397918214293502821599497633970075862760001650736520566952260001423171553461362588848929781360590057040212831994258783694027013289053834376791974167294527043946669963760259975273650548116897900664646809242902841107022557239712438496384819445301703021164043324282687280801738470244471443835900160721870265,
+ prime1 =
+171641816401041100605063917111691927706183918906535463031548413586331728772311589438043965564336865070070922328258143588739626712299625805650832695450270566547004154065267940032684307994238248203186986569945677705100224518137694769557564475390859269797990555863306972197736879644001860925483629009305104925823,
+ prime2
+=146170909759497809922264016492088453282310383272504533061020897155289106805616042710009332510822455269704884883705830985184223718261139908416790475825625309815234508695722132706422885088219618698987115562577878897003573425367881351537506046253616435685549396767356003663417208105346307649599145759863108910523,
+ exponent1 =
+60579464612132153154728441333538327425711971378777222246428851853999433684345266860486105493295364142377972586444050678378691780811632637288529186629507258781295583787741625893888579292084087601124818789392592131211843947578009918667375697196773859928702549128225990187436545756706539150170692591519448797349,
+ exponent2 =
+137572620950115585809189662580789132500998007785886619351549079675566218169991569609420548245479957900898715184664311515467504676010484619686391036071176762179044243478326713135456833024206699951987873470661533079532774988581535389682358631768109586527575902839864474036157372334443583670210960715165278974609,
+ coefficient =
+15068630434698373319269196003209754243798959461311186548759287649485250508074064775263867418602372588394608558985183294561315208336731894947137343239541687540387209051236354318837334154993136528453613256169847839789803932725339395739618592522865156272771578671216082079933457043120923342632744996962853951612,
+ otherPrimeInfos = asn1_NOVALUE}.
diff --git a/lib/ftp/test/property_test/README b/lib/ftp/test/property_test/README
new file mode 100644
index 0000000000..57602bf719
--- /dev/null
+++ b/lib/ftp/test/property_test/README
@@ -0,0 +1,12 @@
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%% %%%
+%%% WARNING %%%
+%%% %%%
+%%% This is experimental code which may be changed or removed %%%
+%%% anytime without any warning. %%%
+%%% %%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+The test in this directory are written assuming that the user has a QuickCheck license. They are to be run manually. Some may be possible to be run with other tools, e.g. PropEr.
+
diff --git a/lib/ftp/test/property_test/ftp_simple_client_server.erl b/lib/ftp/test/property_test/ftp_simple_client_server.erl
new file mode 100644
index 0000000000..d304478b47
--- /dev/null
+++ b/lib/ftp/test/property_test/ftp_simple_client_server.erl
@@ -0,0 +1,307 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+-module(ftp_simple_client_server).
+
+-compile(export_all).
+
+-ifndef(EQC).
+-ifndef(PROPER).
+-define(EQC,true).
+%%-define(PROPER,true).
+-endif.
+-endif.
+
+
+-ifdef(EQC).
+
+-include_lib("eqc/include/eqc.hrl").
+-include_lib("eqc/include/eqc_statem.hrl").
+-define(MOD_eqc, eqc).
+-define(MOD_eqc_gen, eqc_gen).
+-define(MOD_eqc_statem, eqc_statem).
+
+-else.
+-ifdef(PROPER).
+
+-include_lib("proper/include/proper.hrl").
+-define(MOD_eqc, proper).
+-define(MOD_eqc_gen, proper_gen).
+-define(MOD_eqc_statem, proper_statem).
+
+-endif.
+-endif.
+
+-record(state, {
+ initialized = false,
+ priv_dir,
+ data_dir,
+ servers = [], % [ {IP,Port,Userid,Pwd} ]
+ clients = [], % [ client_ref() ]
+ store = [] % [ {Name,Contents} ]
+ }).
+
+-define(fmt(F,A), io:format(F,A)).
+%%-define(fmt(F,A), ok).
+
+-define(v(K,L), proplists:get_value(K,L)).
+
+%%%================================================================
+%%%
+%%% Properties
+%%%
+
+%% This function is for normal eqc calls:
+prop_ftp() ->
+ {ok,PWD} = file:get_cwd(),
+ prop_ftp(filename:join([PWD,?MODULE_STRING++"_data"]),
+ filename:join([PWD,?MODULE_STRING,"_files"])).
+
+%% This function is for calls from common_test test cases:
+prop_ftp(Config) ->
+ prop_ftp(filename:join([?v(property_dir,Config), ?MODULE_STRING++"_data"]),
+ ?v(priv_dir,Config) ).
+
+
+prop_ftp(DataDir, PrivDir) ->
+ S0 = #state{data_dir = DataDir,
+ priv_dir = PrivDir},
+ ?FORALL(Cmds, more_commands(10,commands(?MODULE,S0)),
+ aggregate(command_names(Cmds),
+ begin {_H,S,Result} = run_commands(?MODULE,Cmds),
+ % io:format('**** Result=~p~n',[Result]),
+ % io:format('**** S=~p~n',[S]),
+ % io:format('**** _H=~p~n',[_H]),
+ % io:format('**** Cmds=~p~n',[Cmds]),
+ [cmnd_stop_server(X) || X <- S#state.servers],
+ [ftp:stop_service(X) || {ok,X} <- S#state.clients],
+ Result==ok
+ end)
+ ).
+
+%%%================================================================
+%%%
+%%% State model
+%%%
+
+%% @doc Returns the state in which each test case starts. (Unless a different
+%% initial state is supplied explicitly to, e.g. commands/2.)
+-spec initial_state() ->?MOD_eqc_statem:symbolic_state().
+initial_state() ->
+ ?fmt("Initial_state()~n",[]),
+ #state{}.
+
+%% @doc Command generator, S is the current state
+-spec command(S :: ?MOD_eqc_statem:symbolic_state()) -> ?MOD_eqc_gen:gen(eqc_statem:call()).
+
+command(#state{initialized=false,
+ priv_dir=PrivDir}) ->
+ {call,?MODULE,cmnd_init,[PrivDir]};
+
+command(#state{servers=[],
+ priv_dir=PrivDir,
+ data_dir=DataDir}) ->
+ {call,?MODULE,cmnd_start_server,[PrivDir,DataDir]};
+
+command(#state{servers=Ss=[_|_],
+ clients=[]}) ->
+ {call,?MODULE,cmnd_start_client,[oneof(Ss)]};
+
+command(#state{servers=Ss=[_|_],
+ clients=Cs=[_|_],
+ store=Store=[_|_]
+ }) ->
+ frequency([
+ { 5, {call,?MODULE,cmnd_start_client,[oneof(Ss)]}},
+ { 5, {call,?MODULE,cmnd_stop_client,[oneof(Cs)]}},
+ {10, {call,?MODULE,cmnd_put,[oneof(Cs),file_path(),file_contents()]}},
+ {20, {call,?MODULE,cmnd_get,[oneof(Cs),oneof(Store)]}},
+ {10, {call,?MODULE,cmnd_delete,[oneof(Cs),oneof(Store)]}}
+ ]);
+
+command(#state{servers=Ss=[_|_],
+ clients=Cs=[_|_],
+ store=[]
+ }) ->
+ frequency([
+ {5, {call,?MODULE,cmnd_start_client,[oneof(Ss)]}},
+ {5, {call,?MODULE,cmnd_stop_client,[oneof(Cs)]}},
+ {10, {call,?MODULE,cmnd_put,[oneof(Cs),file_path(),file_contents()]}}
+ ]).
+
+%% @doc Precondition, checked before command is added to the command sequence.
+-spec precondition(S :: ?MOD_eqc_statem:symbolic_state(), C :: ?MOD_eqc_statem:call()) -> boolean().
+
+precondition(#state{clients=Cs}, {call, _, cmnd_put, [C,_,_]}) -> lists:member(C,Cs);
+
+precondition(#state{clients=Cs, store=Store},
+ {call, _, cmnd_get, [C,X]}) -> lists:member(C,Cs) andalso lists:member(X,Store);
+
+precondition(#state{clients=Cs, store=Store},
+ {call, _, cmnd_delete, [C,X]}) -> lists:member(C,Cs) andalso lists:member(X,Store);
+
+precondition(#state{servers=Ss}, {call, _, cmnd_start_client, _}) -> Ss =/= [];
+
+precondition(#state{clients=Cs}, {call, _, cmnd_stop_client, [C]}) -> lists:member(C,Cs);
+
+precondition(#state{initialized=IsInit}, {call, _, cmnd_init, _}) -> IsInit==false;
+
+precondition(_S, {call, _, _, _}) -> true.
+
+
+%% @doc Postcondition, checked after command has been evaluated
+%% Note: S is the state before next_state(S,_,C)
+-spec postcondition(S :: ?MOD_eqc_statem:dynamic_state(), C :: ?MOD_eqc_statem:call(),
+ Res :: term()) -> boolean().
+
+postcondition(_S, {call, _, cmnd_get, [_,{_Name,Expected}]}, {ok,Value}) ->
+ Value == Expected;
+
+postcondition(S, {call, _, cmnd_delete, [_,{Name,_Expected}]}, ok) ->
+ ?fmt("file:read_file(..) = ~p~n",[file:read_file(filename:join(S#state.priv_dir,Name))]),
+ {error,enoent} == file:read_file(filename:join(S#state.priv_dir,Name));
+
+postcondition(S, {call, _, cmnd_put, [_,Name,Value]}, ok) ->
+ {ok,Bin} = file:read_file(filename:join(S#state.priv_dir,Name)),
+ Bin == unicode:characters_to_binary(Value);
+
+postcondition(_S, {call, _, cmnd_stop_client, _}, ok) -> true;
+
+postcondition(_S, {call, _, cmnd_start_client, _}, {ok,_}) -> true;
+
+postcondition(_S, {call, _, cmnd_init, _}, ok) -> true;
+
+postcondition(_S, {call, _, cmnd_start_server, _}, {ok,_}) -> true.
+
+
+%% @doc Next state transformation, S is the current state. Returns next state.
+-spec next_state(S :: ?MOD_eqc_statem:symbolic_state(),
+ V :: ?MOD_eqc_statem:var(),
+ C :: ?MOD_eqc_statem:call()) -> ?MOD_eqc_statem:symbolic_state().
+
+next_state(S, _V, {call, _, cmnd_put, [_,Name,Val]}) ->
+ S#state{store = [{Name,Val} | lists:keydelete(Name,1,S#state.store)]};
+
+next_state(S, _V, {call, _, cmnd_delete, [_,{Name,_Val}]}) ->
+ S#state{store = lists:keydelete(Name,1,S#state.store)};
+
+next_state(S, V, {call, _, cmnd_start_client, _}) ->
+ S#state{clients = [V | S#state.clients]};
+
+next_state(S, V, {call, _, cmnd_start_server, _}) ->
+ S#state{servers = [V | S#state.servers]};
+
+next_state(S, _V, {call, _, cmnd_stop_client, [C]}) ->
+ S#state{clients = S#state.clients -- [C]};
+
+next_state(S, _V, {call, _, cmnd_init, _}) ->
+ S#state{initialized=true};
+
+next_state(S, _V, {call, _, _, _}) ->
+ S.
+
+%%%================================================================
+%%%
+%%% Data model
+%%%
+
+file_path() -> non_empty(list(alphanum_char())).
+%%file_path() -> non_empty( list(oneof([alphanum_char(), utf8_char()])) ).
+
+%%file_contents() -> list(alphanum_char()).
+file_contents() -> list(oneof([alphanum_char(), utf8_char()])).
+
+alphanum_char() -> oneof(lists:seq($a,$z) ++ lists:seq($A,$Z) ++ lists:seq($0,$9)).
+
+utf8_char() -> oneof("åäöÅÄÖ話话カタカナひらがな").
+
+%%%================================================================
+%%%
+%%% Commands doing something with the System Under Test
+%%%
+
+cmnd_init(PrivDir) ->
+ ?fmt('Call cmnd_init(~p)~n',[PrivDir]),
+ os:cmd("killall vsftpd"),
+ clear_files(PrivDir),
+ ok.
+
+cmnd_start_server(PrivDir, DataDir) ->
+ ?fmt('Call cmnd_start_server(~p, ~p)~n',[PrivDir,DataDir]),
+ Cmnd = ["vsftpd ", filename:join(DataDir,"vsftpd.conf"),
+ " -oftpd_banner=erlang_otp_testing"
+ " -oanon_root=",PrivDir
+ ],
+ ?fmt("Cmnd=~s~n",[Cmnd]),
+ case os:cmd(Cmnd) of
+ [] ->
+ {ok,{"localhost",9999,"ftp","[email protected]"}};
+ Other ->
+ {error,Other}
+ end.
+
+cmnd_stop_server({ok,{_Host,Port,_Usr,_Pwd}}) ->
+ os:cmd("kill `netstat -tpln | grep "++integer_to_list(Port)++" | awk '{print $7}' | awk -F/ '{print $1}'`").
+
+cmnd_start_client({ok,{Host,Port,Usr,Pwd}}) ->
+ ?fmt('Call cmnd_start_client(~p)...',[{Host,Port,Usr,Pwd}]),
+ case ftp:start_service([{host,Host},{port,Port}]) of
+ {ok,Client} ->
+ ?fmt("~p...",[{ok,Client}]),
+ case ftp:user(Client, Usr, Pwd) of
+ ok ->
+ ?fmt("OK!~n",[]),
+ {ok,Client};
+ Other ->
+ ?fmt("Other1=~p~n",[Other]),
+ ftp:stop_service(Client), Other
+ end;
+ Other ->
+ ?fmt("Other2=~p~n",[Other]),
+ Other
+ end.
+
+cmnd_stop_client({ok,Client}) ->
+ ?fmt('Call cmnd_stop_client(~p)~n',[Client]),
+ ftp:stop_service(Client). %% -> ok | Other
+
+cmnd_delete({ok,Client}, {Name,_ExpectedValue}) ->
+ ?fmt('Call cmnd_delete(~p, ~p)~n',[Client,Name]),
+ R=ftp:delete(Client, Name),
+ ?fmt("R=~p~n",[R]),
+ R.
+
+cmnd_put({ok,Client}, Name, Value) ->
+ ?fmt('Call cmnd_put(~p, ~p, ~p)...',[Client, Name, Value]),
+ R = ftp:send_bin(Client, unicode:characters_to_binary(Value), Name), % ok | {error,Error}
+ ?fmt('~p~n',[R]),
+ R.
+
+cmnd_get({ok,Client}, {Name,_ExpectedValue}) ->
+ ?fmt('Call cmnd_get(~p, ~p)~n',[Client,Name]),
+ case ftp:recv_bin(Client, Name) of
+ {ok,Bin} -> {ok, unicode:characters_to_list(Bin)};
+ Other -> Other
+ end.
+
+
+clear_files(Dir) ->
+ os:cmd(["rm -fr ",filename:join(Dir,"*")]).
diff --git a/lib/ftp/test/property_test/ftp_simple_client_server_data/vsftpd.conf b/lib/ftp/test/property_test/ftp_simple_client_server_data/vsftpd.conf
new file mode 100644
index 0000000000..fd48e2abf0
--- /dev/null
+++ b/lib/ftp/test/property_test/ftp_simple_client_server_data/vsftpd.conf
@@ -0,0 +1,26 @@
+
+###
+### Some parameters are given in the vsftpd start command.
+###
+### Typical command-line paramters are such that has a file path
+### component like cert files.
+###
+
+
+listen=YES
+listen_port=9999
+run_as_launching_user=YES
+ssl_enable=NO
+#allow_anon_ssl=YES
+
+background=YES
+
+write_enable=YES
+anonymous_enable=YES
+anon_upload_enable=YES
+anon_mkdir_write_enable=YES
+anon_other_write_enable=YES
+anon_world_readable_only=NO
+
+### Shouldn't be necessary....
+require_ssl_reuse=NO
diff --git a/lib/ftp/vsn.mk b/lib/ftp/vsn.mk
new file mode 100644
index 0000000000..9f14658099
--- /dev/null
+++ b/lib/ftp/vsn.mk
@@ -0,0 +1,24 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2001-2018. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# %CopyrightEnd%
+
+APPLICATION = ftp
+FTP_VSN = 1.0.2
+PRE_VSN =
+APP_VSN = "$(APPLICATION)-$(FTP_VSN)$(PRE_VSN)"
diff --git a/lib/hipe/cerl/Makefile b/lib/hipe/cerl/Makefile
index 9f50d6bf91..5c367b5b77 100644
--- a/lib/hipe/cerl/Makefile
+++ b/lib/hipe/cerl/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2003-2016. All Rights Reserved.
+# Copyright Ericsson AB 2003-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -44,7 +44,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/hipe-$(VSN)
# Target Specs
# ----------------------------------------------------
MODULES = cerl_cconv cerl_closurean cerl_hipeify cerl_lib \
- cerl_messagean cerl_pmatch cerl_prettypr cerl_to_icode \
+ cerl_pmatch cerl_prettypr cerl_to_icode \
cerl_typean erl_bif_types erl_types
HRL_FILES= cerl_hipe_primops.hrl
@@ -66,7 +66,10 @@ DOC_FILES= $(MODULES:%=$(DOCS)/%.html)
include ../native.mk
-ERL_COMPILE_FLAGS += +inline -Werror +warn_export_vars +warn_unused_import +warn_missing_spec #+warn_untyped_record
+ERL_COMPILE_FLAGS += +inline +warn_export_vars +warn_unused_import +warn_missing_spec #+warn_untyped_record
+ifneq ($(NATIVE_LIBS_ENABLED),yes)
+ERL_COMPILE_FLAGS += -Werror
+endif
# ----------------------------------------------------
# Targets
diff --git a/lib/hipe/cerl/cerl_messagean.erl b/lib/hipe/cerl/cerl_messagean.erl
deleted file mode 100644
index c79e045bd0..0000000000
--- a/lib/hipe/cerl/cerl_messagean.erl
+++ /dev/null
@@ -1,1095 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% @copyright 2002 Richard Carlsson
-%% @author Richard Carlsson <[email protected]>
-%% @doc Message analysis of Core Erlang programs.
-
-%% TODO: might need a "top" (`any') element for any-length value lists.
-
--module(cerl_messagean).
-
--export([annotate/1]).
-
--import(cerl, [alias_pat/1, alias_var/1, ann_c_var/2, ann_c_fun/3,
- apply_args/1, apply_op/1, atom_val/1, bitstr_size/1,
- bitstr_val/1, binary_segments/1, c_letrec/2,
- ann_c_tuple/2, c_nil/0, call_args/1, call_module/1,
- call_name/1, case_arg/1, case_clauses/1, catch_body/1,
- clause_body/1, clause_guard/1, clause_pats/1, cons_hd/1,
- cons_tl/1, fun_body/1, fun_vars/1, get_ann/1, int_val/1,
- is_c_atom/1, is_c_int/1, let_arg/1, let_body/1,
- let_vars/1, letrec_body/1, letrec_defs/1, module_defs/1,
- module_defs/1, module_exports/1, pat_vars/1,
- primop_args/1, primop_name/1, receive_action/1,
- receive_clauses/1, receive_timeout/1, seq_arg/1,
- seq_body/1, set_ann/2, try_arg/1, try_body/1, try_vars/1,
- try_evars/1, try_handler/1, tuple_es/1, type/1,
- values_es/1]).
-
--import(cerl_trees, [get_label/1]).
-
--define(DEF_LIMIT, 4).
-
-%% -export([test/1, test1/1, ttest/1]).
-
-%% ttest(F) ->
-%% {T, _} = cerl_trees:label(user_default:read(F)),
-%% {Time0, _} = erlang:statistics(runtime),
-%% analyze(T),
-%% {Time1, _} = erlang:statistics(runtime),
-%% Time1 - Time0.
-
-%% test(F) ->
-%% {T, _} = cerl_trees:label(user_default:read(F)),
-%% {Time0, _} = erlang:statistics(runtime),
-%% {Esc, _Vars} = analyze(T),
-%% {Time1, _} = erlang:statistics(runtime),
-%% io:fwrite("messages: ~p.\n", [Esc]),
-%% Set = sets:from_list(Esc),
-%% H = fun (Node, Ctxt, Cont) ->
-%% Doc = case get_ann(Node) of
-%% [{label, L} | _] ->
-%% B = sets:is_element(L, Set),
-%% bf(Node, Ctxt, Cont, B);
-%% _ ->
-%% bf(Node, Ctxt, Cont, false)
-%% end,
-%% case type(Node) of
-%% cons -> color(Doc);
-%% tuple -> color(Doc);
-%% _ -> Doc
-%% end
-%% end,
-%% {ok, FD} = file:open("out.html",[write]),
-%% Txt = cerl_prettypr:format(T, [{hook, H},{user,false}]),
-%% io:put_chars(FD, "<pre>\n"),
-%% io:put_chars(FD, html(Txt)),
-%% io:put_chars(FD, "</pre>\n"),
-%% file:close(FD),
-%% {ok, Time1 - Time0}.
-
-%% test1(F) ->
-%% {T, _} = cerl_trees:label(user_default:read(F)),
-%% {Time0, _} = erlang:statistics(runtime),
-%% {T1, Esc, Vars} = annotate(T),
-%% {Time1, _} = erlang:statistics(runtime),
-%% io:fwrite("messages: ~p.\n", [Esc]),
-%% %%% io:fwrite("vars: ~p.\n", [[X || X <- dict:to_list(Vars)]]),
-%% T2 = hhl_transform:transform(T1, Vars),
-%% Set = sets:from_list(Esc),
-%% H = fun (Node, Ctxt, Cont) ->
-%% case get_ann(Node) of
-%% [{label, L} | _] ->
-%% B = sets:is_element(L, Set),
-%% bf(Node, Ctxt, Cont, B);
-%% _ ->
-%% bf(Node, Ctxt, Cont, false)
-%% end
-%% end,
-%% {ok, FD} = file:open("out.html",[write]),
-%% Txt = cerl_prettypr:format(T2, [{hook, H},{user,false}]),
-%% io:put_chars(FD, "<pre>\n"),
-%% io:put_chars(FD, html(Txt)),
-%% io:put_chars(FD, "</pre>\n"),
-%% file:close(FD),
-%% {ok, Time1 - Time0}.
-
-%% html(Cs) ->
-%% html(Cs, []).
-
-%% html([$#, $< | Cs], As) ->
-%% html_1(Cs, [$< | As]);
-%% html([$< | Cs], As) ->
-%% html(Cs, ";tl&" ++ As);
-%% html([$> | Cs], As) ->
-%% html(Cs, ";tg&" ++ As);
-%% html([$& | Cs], As) ->
-%% html(Cs, ";pma&" ++ As);
-%% html([C | Cs], As) ->
-%% html(Cs, [C | As]);
-%% html([], As) ->
-%% lists:reverse(As).
-
-%% html_1([$> | Cs], As) ->
-%% html(Cs, [$> | As]);
-%% html_1([C | Cs], As) ->
-%% html_1(Cs, [C | As]).
-
-%% bf(Node, Ctxt, Cont, B) ->
-%% B0 = cerl_prettypr:get_ctxt_user(Ctxt),
-%% if B /= B0 ->
-%% Ctxt1 = cerl_prettypr:set_ctxt_user(Ctxt, B),
-%% Doc = Cont(Node, Ctxt1),
-%% case B of
-%% true ->
-%% Start = "<b>",
-%% End = "</b>";
-%% false ->
-%% Start = "</b>",
-%% End = "<b>"
-%% end,
-%% markup(Doc, Start, End);
-%% true ->
-%% Cont(Node, Ctxt)
-%% end.
-
-%% color(Doc) ->
-%% % Doc.
-%% markup(Doc, "<font color=blue>", "</font>").
-
-%% markup(Doc, Start, End) ->
-%% prettypr:beside(
-%% prettypr:null_text([$# | Start]),
-%% prettypr:beside(Doc,
-%% prettypr:null_text([$# | End]))).
-
-
-%% =====================================================================
-%% annotate(Tree) -> {Tree1, Escapes, Vars}
-%%
-%% Tree = cerl:cerl()
-%%
-%% Analyzes `Tree' (see `analyze') and appends a term 'escapes', to
-%% the annotation list of each constructor expression node and of
-%% `Tree', corresponding to the escape information derived by the
-%% analysis. Any previous such annotations are removed from `Tree'.
-%% `Tree1' is the modified tree; for details on `OutList',
-%% `Outputs' , `Dependencies', `Escapes' and `Parents', see
-%% `analyze'.
-%%
-%% Note: `Tree' must be annotated with labels in order to use this
-%% function; see `analyze' for details.
-
--type label() :: integer() | 'external' | 'top'.
--type ordset(X) :: [X]. % XXX: TAKE ME OUT
-
--spec annotate(cerl:cerl()) -> {cerl:cerl(), ordset(label()), dict:dict()}.
-
-annotate(Tree) ->
- {Esc0, Vars} = analyze(Tree),
- Esc = sets:from_list(Esc0),
- F = fun (T) ->
- case type(T) of
- literal -> T;
-%%% var ->
-%%% L = get_label(T),
-%%% T1 = ann_escape(T, L, Esc),
-%%% X = dict:fetch(L, Vars),
-%%% set_ann(T1, append_ann({s,X}, get_ann(T1)));
- _ ->
- L = get_label(T),
- ann_escape(T, L, Esc)
- end
- end,
- {cerl_trees:map(F, Tree), Esc0, Vars}.
-
-ann_escape(T, L, Esc) ->
- case sets:is_element(L, Esc) of
- true ->
- set_ann(T, append_ann(escapes, get_ann(T)));
- false ->
- T
- end.
-
-append_ann(Tag, [X | Xs]) ->
- if tuple_size(X) >= 1, element(1, X) =:= Tag ->
- append_ann(Tag, Xs);
- true ->
- [X | append_ann(Tag, Xs)]
- end;
-append_ann(Tag, []) ->
- [Tag].
-
-
-%% =====================================================================
-%% analyze(Tree) -> Escapes
-%%
-%% Tree = cerl:cerl()
-%% Escapes = ordset(Label)
-%% Label = integer() | external | top
-%%
-%% Analyzes a module or an expression represented by `Tree'.
-%%
-%% `Escapes' is the set of labels of constructor expressions in
-%% `Tree' such that the created values may be accessed from outside
-%% `Tree'.
-%%
-%% Note: `Tree' must be annotated with labels (as done by the
-%% function `cerl_trees:label/1') in order to use this function.
-%% The label annotation `{label, L}' (where L should be an integer)
-%% must be the first element of the annotation list of each node in
-%% the tree. Instances of variables bound in `Tree' which denote
-%% the same variable must have the same label; apart from this,
-%% labels should be unique. Constant literals do not need to be
-%% labeled.
-
--record(state, {vars, out, dep, work, funs, k}).
-
-%% Note: We assume that all remote calls and primops return a single
-%% value.
-
-%% The analysis determines which objects (identified by the
-%% corresponding "cons-point" labels in the code) are likely to be
-%% passed in a message. (If so, we say that they "escape".) It is always
-%% safe to assume either case, because the send operation will assure
-%% that things are copied if necessary. This analysis tries to
-%% anticipate that copying will be done.
-%%
-%% Rules:
-%% 1) An object passed as message argument (or part of such an
-%% argument) to a known send-operation, will probably be a message.
-%% 2) A received value is always a message (safe).
-%% 3) The external function can return any object (unsafe).
-%% 4) A function called from the external function can receive any
-%% object (unsafe) as argument.
-%% 5) Unknown functions/operations can return any object (unsafe).
-
-%% We wrap the given syntax tree T in a fun-expression labeled `top',
-%% which is initially in the set of escaped labels. `top' will be
-%% visited at least once.
-%%
-%% We create a separate function labeled `external', defined as:
-%% "'external'/1 = fun () -> Any", which will represent any and all
-%% functions outside T, and which returns the 'unsafe' value.
-
-analyze(Tree) ->
- analyze(Tree, ?DEF_LIMIT).
-
-analyze(Tree, Limit) ->
- {_, _, Esc, Dep, _Par} = cerl_closurean:analyze(Tree),
-%%% io:fwrite("dependencies: ~w.\n", [dict:to_list(Dep)]),
- analyze(Tree, Limit, Dep, Esc).
-
-analyze(Tree, Limit, Dep0, Esc0) ->
- %% Note that we use different name spaces for variable labels and
- %% function/call site labels, so we can reuse some names here. We
- %% assume that the labeling of Tree only uses integers, not atoms.
- Any = ann_c_var([{label, any}], 'Any'),
- External = ann_c_var([{label, external}], {external, 1}),
- ExtFun = ann_c_fun([{label, external}], [], Any),
-%%% io:fwrite("external fun:\n~s.\n",
-%%% [cerl_prettypr:format(ExtFun, [noann, {paper, 80}])]),
- Top = ann_c_var([{label, top}], {top, 0}),
- TopFun = ann_c_fun([{label, top}], [], Tree),
-
- %% The "start fun" just makes the initialisation easier. It is not
- %% itself in the call graph.
- StartFun = ann_c_fun([{label, start}], [],
- c_letrec([{External, ExtFun}, {Top, TopFun}],
- c_nil())),
-%%% io:fwrite("start fun:\n~s.\n",
-%%% [cerl_prettypr:format(StartFun, [{paper, 80}])]),
-
- %% Initialise the Any and Escape variables. Gather a database of all
- %% fun-expressions in Tree and initialise their outputs and parameter
- %% variables. All escaping functions can receive any values as
- %% inputs. Bind all module- and letrec-defined variables to their
- %% corresponding labels.
- Esc = sets:from_list(Esc0),
- Unsafe = unsafe(),
- Empty = empty(),
- Funs0 = dict:new(),
- Vars0 = dict:store(escape, empty(),
- dict:store(any, Unsafe, dict:new())),
- Out0 = dict:new(),
- F = fun (T, S = {Fs, Vs, Os}) ->
- case type(T) of
- 'fun' ->
- L = get_label(T),
- As = fun_vars(T),
- X = case sets:is_element(L, Esc) of
- true -> Unsafe;
- false -> Empty
- end,
- {dict:store(L, T, Fs),
- bind_vars_single(As, X, Vs),
- dict:store(L, none, Os)};
- letrec ->
- {Fs, bind_defs(letrec_defs(T), Vs), Os};
- module ->
- {Fs, bind_defs(module_defs(T), Vs), Os};
- _ ->
- S
- end
- end,
- {Funs, Vars, Out} = cerl_trees:fold(F, {Funs0, Vars0, Out0}, StartFun),
-
- %% Add the dependency for the loop in 'external':
- Dep = add_dep(loop, external, Dep0),
-
- %% Enter the fixpoint iteration at the StartFun.
- St = loop(StartFun, start, #state{vars = Vars,
- out = Out,
- dep = Dep,
- work = init_work(),
- funs = Funs,
- k = Limit}),
- Ms = labels(dict:fetch(escape, St#state.vars)),
- {Ms, St#state.vars}.
-
-loop(T, L, St0) ->
-%%% io:fwrite("analyzing: ~w.\n",[L]),
-%%% io:fwrite("work: ~w.\n", [St0#state.work]),
- Xs0 = dict:fetch(L, St0#state.out),
- {Xs1, St1} = visit(fun_body(T), L, St0),
- Xs = limit(Xs1, St1#state.k),
- {W, M} = case equal(Xs0, Xs) of
- true ->
- {St1#state.work, St1#state.out};
- false ->
-%%% io:fwrite("out (~w) changed: ~w <- ~w.\n",
-%%% [L, Xs, Xs0]),
- M1 = dict:store(L, Xs, St1#state.out),
- case dict:find(L, St1#state.dep) of
- {ok, S} ->
- {add_work(set__to_list(S), St1#state.work),
- M1};
- error ->
- {St1#state.work, M1}
- end
- end,
- St2 = St1#state{out = M},
- case take_work(W) of
- {ok, L1, W1} ->
- T1 = dict:fetch(L1, St2#state.funs),
- loop(T1, L1, St2#state{work = W1});
- none ->
- St2
- end.
-
-visit(T, L, St) ->
-%%% io:fwrite("visiting: ~w.\n",[type(T)]),
- case type(T) of
- literal ->
- %% This is (or should be) a constant, even if it's compound,
- %% so it's bugger all whether it is sent or not.
- case cerl:concrete(T) of
- [] -> {[empty()], St};
- X when is_atom(X) -> {[empty()], St};
- X when is_integer(X) -> {[empty()], St};
- X when is_float(X) -> {[empty()], St};
- _ ->
- exit({not_literal, T})
- end;
- var ->
- %% If a variable is not already in the store here, it must
- %% be free in the program.
- L1 = get_label(T),
- Vars = St#state.vars,
- case dict:find(L1, Vars) of
- {ok, X} ->
- {[X], St};
- error ->
-%%% io:fwrite("free var: ~w.\n",[L1]),
- X = unsafe(),
- St1 = St#state{vars = dict:store(L1, X, Vars)},
- {[X], St1}
- end;
- 'fun' ->
- %% Must revisit the fun also, because its environment might
- %% have changed. (We don't keep track of such dependencies.)
- L1 = get_label(T),
- St1 = St#state{work = add_work([L1], St#state.work)},
- %% Currently, lambda expressions can only be locally
- %% allocated, and therefore we have to force copying by
- %% treating them as "unsafe" for now.
- {[unsafe()], St1};
- %% {[singleton(L1)], St1};
- values ->
- visit_list(values_es(T), L, St);
- cons ->
- {[X1, X2], St1} = visit_list([cons_hd(T), cons_tl(T)], L, St),
- L1 = get_label(T),
- X = make_cons(L1, X1, X2),
- %% Also store the values of the elements.
- Hd = get_hd(X),
- Tl = get_tl(X),
- St2 = St1#state{vars = dict:store(L1, [Hd, Tl], St1#state.vars)},
- {[X], St2};
- tuple ->
- {Xs, St1} = visit_list(tuple_es(T), L, St),
- L1 = get_label(T),
- %% Also store the values of the elements.
- St2 = St1#state{vars = dict:store(L1, Xs, St1#state.vars)},
- {[struct(L1, Xs)], St2};
- 'let' ->
- {Xs, St1} = visit(let_arg(T), L, St),
- Vars = bind_vars(let_vars(T), Xs, St1#state.vars),
- visit(let_body(T), L, St1#state{vars = Vars});
- seq ->
- {_, St1} = visit(seq_arg(T), L, St),
- visit(seq_body(T), L, St1);
- apply ->
- {_F, St1} = visit(apply_op(T), L, St),
- {As, St2} = visit_list(apply_args(T), L, St1),
- L1 = get_label(T),
- Ls = get_deps(L1, St#state.dep),
- Out = St2#state.out,
- Xs1 = join_list([dict:fetch(X, Out) || X <- Ls]),
- {Xs1, call_site(Ls, As, St2)};
- call ->
- M = call_module(T),
- F = call_name(T),
- As = call_args(T),
- {_, St1} = visit(M, L, St),
- {_, St2} = visit(F, L, St1),
- {Xs, St3} = visit_list(As, L, St2),
- L1 = get_label(T),
- remote_call(M, F, Xs, As, L1, St3);
- primop ->
- As = primop_args(T),
- {Xs, St1} = visit_list(As, L, St),
- F = atom_val(primop_name(T)),
- primop_call(F, length(Xs), Xs, As, St1);
- 'case' ->
- {Xs, St1} = visit(case_arg(T), L, St),
- visit_clauses(Xs, case_clauses(T), L, St1);
- 'receive' ->
- %% The received value is of course a message, so it
- %% is 'empty()', not 'unsafe()'.
- X = empty(),
- {Xs1, St1} = visit_clauses([X], receive_clauses(T), L, St),
- {_, St2} = visit(receive_timeout(T), L, St1),
- {Xs2, St3} = visit(receive_action(T), L, St2),
- {join(Xs1, Xs2), St3};
- 'try' ->
- {Xs1, St1} = visit(try_arg(T), L, St),
- X = unsafe(),
- Vars = bind_vars(try_vars(T), Xs1, St1#state.vars),
- {Xs2, St2} = visit(try_body(T), L, St1#state{vars = Vars}),
- EVars = bind_vars(try_evars(T), [X, X, X], St2#state.vars),
- {Xs3, St3} = visit(try_handler(T), L, St2#state{vars = EVars}),
- {join(Xs2, Xs3), St3};
- 'catch' ->
- %% If we catch an exception, we can get unsafe data.
- {Xs, St1} = visit(catch_body(T), L, St),
- {join([unsafe()], Xs), St1};
- binary ->
- %% Binaries are heap objects, but we don't have special
- %% shared-heap allocation operators for them at the moment.
- %% They must therefore be treated as unsafe.
- {_, St1} = visit_list(binary_segments(T), L, St),
- {[unsafe()], St1};
- bitstr ->
- %% The other fields are constant literals.
- {_, St1} = visit(bitstr_val(T), L, St),
- {_, St2} = visit(bitstr_size(T), L, St1),
- {none, St2};
- letrec ->
- %% All the bound funs should be revisited, because the
- %% environment might have changed.
- Ls = [get_label(F) || {_, F} <- letrec_defs(T)],
- St1 = St#state{work = add_work(Ls, St#state.work)},
- visit(letrec_body(T), L, St1);
- module ->
- %% We regard a module as a tuple of function variables in
- %% the body of a `letrec'.
- visit(c_letrec(module_defs(T),
- ann_c_tuple([{label, get_label(T)}],
- module_exports(T))),
- L, St)
- end.
-
-visit_clause(T, Xs, L, St) ->
- Vars = bind_pats(clause_pats(T), Xs, St#state.vars),
- {_, St1} = visit(clause_guard(T), L, St#state{vars = Vars}),
- visit(clause_body(T), L, St1).
-
-%% We assume correct value-list typing.
-
-visit_list([T | Ts], L, St) ->
- {Xs, St1} = visit(T, L, St),
- {Xs1, St2} = visit_list(Ts, L, St1),
- X = case Xs of
- [X1] -> X1;
- _ -> empty()
- end,
- {[X | Xs1], St2};
-visit_list([], _L, St) ->
- {[], St}.
-
-visit_clauses(Xs, [T | Ts], L, St) ->
- {Xs1, St1} = visit_clause(T, Xs, L, St),
- {Xs2, St2} = visit_clauses(Xs, Ts, L, St1),
- {join(Xs1, Xs2), St2};
-visit_clauses(_, [], _L, St) ->
- {none, St}.
-
-bind_defs([{V, F} | Ds], Vars) ->
- bind_defs(Ds, dict:store(get_label(V), singleton(get_label(F)), Vars));
-bind_defs([], Vars) ->
- Vars.
-
-bind_pats(Ps, none, Vars) ->
- bind_pats_single(Ps, empty(), Vars);
-bind_pats(Ps, Xs, Vars) ->
- if length(Xs) =:= length(Ps) ->
- bind_pats_list(Ps, Xs, Vars);
- true ->
- bind_pats_single(Ps, empty(), Vars)
- end.
-
-%% The lists might not be of the same length.
-
-bind_pats_list([P | Ps], [X | Xs], Vars) ->
- bind_pats_list(Ps, Xs, bind_pat_vars(P, X, Vars));
-bind_pats_list(Ps, [], Vars) ->
- bind_pats_single(Ps, empty(), Vars);
-bind_pats_list([], _, Vars) ->
- Vars.
-
-bind_pats_single([P | Ps], X, Vars) ->
- bind_pats_single(Ps, X, bind_pat_vars(P, X, Vars));
-bind_pats_single([], _X, Vars) ->
- Vars.
-
-bind_pat_vars(P, X, Vars) ->
- case type(P) of
- var ->
- dict:store(get_label(P), X, Vars);
- literal ->
- Vars;
- cons ->
- bind_pats_list([cons_hd(P), cons_tl(P)],
- [get_hd(X), get_tl(X)], Vars);
- tuple ->
- case elements(X) of
- none ->
- bind_vars_single(pat_vars(P), X, Vars);
- Xs ->
- bind_pats_list(tuple_es(P), Xs, Vars)
- end;
- binary ->
- %% See the handling of binary-expressions.
- bind_pats_single(binary_segments(P), unsafe(), Vars);
- bitstr ->
- %% See the handling of binary-expressions.
- bind_pats_single([bitstr_val(P), bitstr_size(P)],
- unsafe(), Vars);
- alias ->
- P1 = alias_pat(P),
- Vars1 = bind_pat_vars(P1, X, Vars),
- dict:store(get_label(alias_var(P)), X, Vars1)
- end.
-
-%%% %% This is the "exact" version of list representation, which simply
-%%% %% mimics the actual cons, head and tail operations.
-%%% make_cons(L, X1, X2) ->
-%%% struct(L1, [X1, X2]).
-%%% get_hd(X) ->
-%%% case elements(X) of
-%%% none -> X;
-%%% [X1 | _] -> X1;
-%%% _ -> empty()
-%%% end.
-%%% get_tl(X) ->
-%%% case elements(X) of
-%%% none -> X;
-%%% [_, X2 | _] -> X2;
-%%% _ -> empty()
-%%% end.
-
-%% This version does not unnecessarily confuse spine labels with element
-%% labels, and is safe. However, it loses precision if cons cells are
-%% used for other things than proper lists.
-
-make_cons(L, X1, X2) ->
- %% join subtypes and cons locations
- join_single(struct(L, [X1]), X2).
-
-get_hd(X) ->
- case elements(X) of
- none -> X;
- [X1 | _] -> X1; % First element represents list subtype.
- _ -> empty()
- end.
-
-get_tl(X) -> X. % Tail of X has same type as X.
-
-bind_vars(Vs, none, Vars) ->
- bind_vars_single(Vs, empty(), Vars);
-bind_vars(Vs, Xs, Vars) ->
- if length(Vs) =:= length(Xs) ->
- bind_vars_list(Vs, Xs, Vars);
- true ->
- bind_vars_single(Vs, empty(), Vars)
- end.
-
-bind_vars_list([V | Vs], [X | Xs], Vars) ->
- bind_vars_list(Vs, Xs, dict:store(get_label(V), X, Vars));
-bind_vars_list([], [], Vars) ->
- Vars.
-
-bind_vars_single([V | Vs], X, Vars) ->
- bind_vars_single(Vs, X, dict:store(get_label(V), X, Vars));
-bind_vars_single([], _X, Vars) ->
- Vars.
-
-%% This handles a call site, updating parameter variables with respect
-%% to the actual parameters. The 'external' function is handled
-%% specially, since it can get an arbitrary number of arguments. For our
-%% purposes here, calls to the external function can be ignored.
-
-call_site(Ls, Xs, St) ->
-%%% io:fwrite("call site: ~w -> ~w (~w).\n", [L, Ls, Xs]),
- {W, V} = call_site(Ls, Xs, St#state.work, St#state.vars,
- St#state.funs, St#state.k),
- St#state{work = W, vars = V}.
-
-call_site([external | Ls], Xs, W, V, Fs, Limit) ->
- call_site(Ls, Xs, W, V, Fs, Limit);
-call_site([L | Ls], Xs, W, V, Fs, Limit) ->
- Vs = fun_vars(dict:fetch(L, Fs)),
- case bind_args(Vs, Xs, V, Limit) of
- {V1, true} ->
- call_site(Ls, Xs, add_work([L], W), V1, Fs, Limit);
- {V1, false} ->
- call_site(Ls, Xs, W, V1, Fs, Limit)
- end;
-call_site([], _, W, V, _, _) ->
- {W, V}.
-
-add_dep(Source, Target, Deps) ->
- case dict:find(Source, Deps) of
- {ok, X} ->
- case set__is_member(Target, X) of
- true ->
- Deps;
- false ->
-%%% io:fwrite("new dep: ~w <- ~w.\n", [Target, Source]),
- dict:store(Source, set__add(Target, X), Deps)
- end;
- error ->
-%%% io:fwrite("new dep: ~w <- ~w.\n", [Target, Source]),
- dict:store(Source, set__singleton(Target), Deps)
- end.
-
-%% If the arity does not match the call, nothing is done here.
-
-bind_args(Vs, Xs, Vars, Limit) ->
- if length(Vs) =:= length(Xs) ->
- bind_args(Vs, Xs, Vars, Limit, false);
- true ->
- {Vars, false}
- end.
-
-bind_args([V | Vs], [X | Xs], Vars, Limit, Ch) ->
- L = get_label(V),
- {Vars1, Ch1} = bind_arg(L, X, Vars, Limit, Ch),
- bind_args(Vs, Xs, Vars1, Limit, Ch1);
-bind_args([], [], Vars, _Limit, Ch) ->
- {Vars, Ch}.
-
-%% bind_arg(L, X, Vars, Limit) ->
-%% bind_arg(L, X, Vars, Limit, false).
-
-bind_arg(L, X, Vars, Limit, Ch) ->
- X0 = dict:fetch(L, Vars),
- X1 = limit_single(join_single(X, X0), Limit),
- case equal_single(X0, X1) of
- true ->
- {Vars, Ch};
- false ->
-%%% io:fwrite("arg (~w) changed: ~w <- ~w + ~w.\n",
-%%% [L, X1, X0, X]),
- {dict:store(L, X1, Vars), true}
- end.
-
-%% This handles escapes from things like primops and remote calls.
-
-escape(Xs, Ns, St) ->
- escape(Xs, Ns, 1, St).
-
-escape([_ | Xs], Ns=[N1 | _], N, St) when is_integer(N1), N1 > N ->
- escape(Xs, Ns, N + 1, St);
-escape([X | Xs], [N | Ns], N, St) ->
- Vars = St#state.vars,
- X0 = dict:fetch(escape, Vars),
- X1 = join_single(X, X0),
- case equal_single(X0, X1) of
- true ->
- escape(Xs, Ns, N + 1, St);
- false ->
-%%% io:fwrite("escape changed: ~w <- ~w + ~w.\n", [X1, X0, X]),
- Vars1 = dict:store(escape, X1, Vars),
- escape(Xs, Ns, N + 1, St#state{vars = Vars1})
- end;
-escape(Xs, [_ | Ns], N, St) ->
- escape(Xs, Ns, N + 1, St);
-escape(_, _, _, St) ->
- St.
-
-%% Handle primop calls: (At present, we assume that all unknown calls
-%% yield exactly one value. This might have to be changed.)
-
-primop_call(F, A, Xs, _As, St0) ->
- %% St1 = case is_escape_op(F, A) of
- %% [] -> St0;
- %% Ns -> escape(Xs, Ns, St0)
- %% end,
- St1 = St0,
- case is_imm_op(F, A) of
- true ->
- {[empty()], St1};
- false ->
- call_unknown(Xs, St1)
- end.
-
-%% Handle remote-calls: (At present, we assume that all unknown calls
-%% yield exactly one value. This might have to be changed.)
-
-remote_call(M, F, Xs, As, L, St) ->
- case is_c_atom(M) andalso is_c_atom(F) of
- true ->
- remote_call_1(atom_val(M), atom_val(F), length(Xs),
- Xs, As, L, St);
- false ->
- %% Unknown function
- call_unknown(Xs, St)
- end.
-
-%% When calling an unknown function, we assume that the result does
-%% *not* contain any of the constructors in its arguments (but it could
-%% return locally allocated data that we don't know about). Note that
-%% even a "pure" function can still cons up new data.
-
-call_unknown(_Xs, St) ->
- {[unsafe()], St}.
-
-%% We need to handle some important standard functions in order to get
-%% decent precision.
-%% TODO: foldl, map, mapfoldl
-
-remote_call_1(erlang, hd, 1, [X], _As, _L, St) ->
- {[get_hd(X)], St};
-remote_call_1(erlang, tl, 1, [X], _As, _L, St) ->
- {[get_tl(X)], St};
-remote_call_1(erlang, element, 2, [_,X], [N|_], _L, St) ->
- case elements(X) of
- none -> {[X], St};
- Xs ->
- case is_c_int(N) of
- true ->
- N1 = int_val(N),
- if is_integer(N1), 1 =< N1, N1 =< length(Xs) ->
- {[nth(N1, Xs)], St};
- true ->
- {none, St}
- end;
- false ->
- %% Even if we don't know which element is selected,
- %% we know that the top level is never part of the
- %% returned value.
- {[join_single_list(Xs)], St}
- end
- end;
-remote_call_1(erlang, setelement, 3, [_,X, Y], [N|_], L, St) ->
- %% The constructor gets the label of the call operation.
- case elements(X) of
- none -> {[join_single(singleton(L), join_single(X, Y))], St};
- Xs ->
- case is_c_int(N) of
- true ->
- N1 = int_val(N),
- if is_integer(N1), 1 =< N1, N1 =< length(Xs) ->
- Xs1 = set_nth(N1, Y, Xs),
- {[struct(L, Xs1)], St};
- true ->
- {none, St}
- end;
- false ->
- %% Even if we don't know which element is selected,
- %% we know that the top level is never part of the
- %% returned value (a new tuple is always created).
- Xs1 = [join_single(Y, X1) || X1 <- Xs],
- {[struct(L, Xs1)], St}
- end
- end;
-remote_call_1(erlang, '++', 2, [X1,X2], _As, _L, St) ->
- %% Note: this is unsafe for non-proper lists! (See make_cons/3).
- %% No safe version is implemented.
- {[join_single(X1, X2)], St};
-remote_call_1(erlang, '--', 2, [X1,_X2], _As, _L, St) ->
- {[X1], St};
-remote_call_1(lists, append, 2, Xs, As, L, St) ->
- remote_call_1(erlang, '++', 2, Xs, As, L, St);
-remote_call_1(lists, subtract, 2, Xs, As, L, St) ->
- remote_call_1(erlang, '--', 2, Xs, As, L, St);
-remote_call_1(M, F, A, Xs, _As, _L, St0) ->
- St1 = case is_escape_op(M, F, A) of
- [] -> St0;
- Ns -> escape(Xs, Ns, St0)
- end,
- case is_imm_op(M, F, A) of
- true ->
- {[empty()], St1};
- false ->
- call_unknown(Xs, St1)
- end.
-
-%% 1-based n:th-element list selector and update function.
-
-nth(1, [X | _Xs]) -> X;
-nth(N, [_X | Xs]) when N > 1 -> nth(N - 1, Xs).
-
-set_nth(1, Y, [_X | Xs]) -> [Y | Xs];
-set_nth(N, Y, [X | Xs]) when N > 1 -> [X | set_nth(N - 1, Y, Xs)].
-
-%% Domain: none | [V], where V = {S, none} | {S, [V]}, S = set(integer()).
-
-join(none, Xs2) -> Xs2;
-join(Xs1, none) -> Xs1;
-join(Xs1, Xs2) ->
- if length(Xs1) =:= length(Xs2) ->
- join_1(Xs1, Xs2);
- true ->
- none
- end.
-
-join_1([X1 | Xs1], [X2 | Xs2]) ->
- [join_single(X1, X2) | join_1(Xs1, Xs2)];
-join_1([], []) ->
- [].
-
-join_list([Xs | Xss]) ->
- join(Xs, join_list(Xss));
-join_list([]) ->
- none.
-
-empty() -> {set__new(), []}.
-
-singleton(X) -> {set__singleton(X), []}.
-
-struct(X, Xs) -> {set__singleton(X), Xs}.
-
-elements({_, Xs}) -> Xs.
-
-unsafe() -> {set__singleton(unsafe), none}.
-
-equal(none, none) -> true;
-equal(none, _) -> false;
-equal(_, none) -> false;
-equal(X1, X2) -> equal_1(X1, X2).
-
-equal_1([X1 | Xs1], [X2 | Xs2]) ->
- equal_single(X1, X2) andalso equal_1(Xs1, Xs2);
-equal_1([], []) -> true;
-equal_1(_, _) -> false.
-
-equal_single({S1, none}, {S2, none}) ->
- set__equal(S1, S2);
-equal_single({_, none}, _) ->
- false;
-equal_single(_, {_, none}) ->
- false;
-equal_single({S1, Vs1}, {S2, Vs2}) ->
- set__equal(S1, S2) andalso equal_single_lists(Vs1, Vs2).
-
-equal_single_lists([X1 | Xs1], [X2 | Xs2]) ->
- equal_single(X1, X2) andalso equal_single_lists(Xs1, Xs2);
-equal_single_lists([], []) ->
- true;
-equal_single_lists(_, _) ->
- false.
-
-join_single({S, none}, V) ->
- {set__union(S, labels(V)), none};
-join_single(V, {S, none}) ->
- {set__union(S, labels(V)), none};
-join_single({S1, Vs1}, {S2, Vs2}) ->
- {set__union(S1, S2), join_single_lists(Vs1, Vs2)}.
-
-join_single_list([V | Vs]) ->
- join_single(V, join_single_list(Vs));
-join_single_list([]) ->
- empty().
-
-%% If one list has more elements that the other, and N is the length of
-%% the longer list, then the result has N elements.
-
-join_single_lists([V1], [V2]) ->
- [join_single(V1, V2)];
-join_single_lists([V1 | Vs1], [V2 | Vs2]) ->
- [join_single(V1, V2) | join_single_lists(Vs1, Vs2)];
-join_single_lists([], Vs) -> Vs;
-join_single_lists(Vs, []) -> Vs.
-
-collapse(V) ->
- {labels(V), none}.
-
-%% collapse_list([]) ->
-%% empty();
-%% collapse_list(Vs) ->
-%% {labels_list(Vs), none}.
-
-labels({S, none}) -> S;
-labels({S, []}) -> S;
-labels({S, Vs}) -> set__union(S, labels_list(Vs)).
-
-labels_list([V]) ->
- labels(V);
-labels_list([V | Vs]) ->
- set__union(labels(V), labels_list(Vs)).
-
-limit(none, _K) -> none;
-limit(X, K) -> limit_list(X, K).
-
-limit_list([X | Xs], K) ->
- [limit_single(X, K) | limit_list(Xs, K)];
-limit_list([], _) ->
- [].
-
-limit_single({_, none} = V, _K) ->
- V;
-limit_single({_, []} = V, _K) ->
- V;
-limit_single({S, Vs}, K) when K > 0 ->
- {S, limit_list(Vs, K - 1)};
-limit_single(V, _K) ->
- collapse(V).
-
-%% Set abstraction for label sets in the domain.
-
-%% set__is_empty([]) -> true;
-%% set__is_empty(_) -> false.
-
-set__new() -> [].
-
-set__singleton(X) -> [X].
-
-set__to_list(S) -> S.
-
-%% set__from_list(S) -> ordsets:from_list(S).
-
-set__union(X, Y) -> ordsets:union(X, Y).
-
-set__add(X, S) -> ordsets:add_element(X, S).
-
-set__is_member(X, S) -> ordsets:is_element(X, S).
-
-%% set__subtract(X, Y) -> ordsets:subtract(X, Y).
-
-set__equal(X, Y) -> X =:= Y.
-
-%% A simple but efficient functional queue.
-
-queue__new() -> {[], []}.
-
-queue__put(X, {In, Out}) -> {[X | In], Out}.
-
-queue__get({In, [X | Out]}) -> {ok, X, {In, Out}};
-queue__get({[], _}) -> empty;
-queue__get({In, _}) ->
- [X | In1] = lists:reverse(In),
- {ok, X, {[], In1}}.
-
-%% The work list - a queue without repeated elements.
-
-init_work() ->
- {queue__new(), sets:new()}.
-
-add_work(Ls, {Q, Set}) ->
- add_work(Ls, Q, Set).
-
-%% Note that the elements are enqueued in order.
-
-add_work([L | Ls], Q, Set) ->
- case sets:is_element(L, Set) of
- true ->
- add_work(Ls, Q, Set);
- false ->
- add_work(Ls, queue__put(L, Q), sets:add_element(L, Set))
- end;
-add_work([], Q, Set) ->
- {Q, Set}.
-
-take_work({Queue0, Set0}) ->
- case queue__get(Queue0) of
- {ok, L, Queue1} ->
- Set1 = sets:del_element(L, Set0),
- {ok, L, {Queue1, Set1}};
- empty ->
- none
- end.
-
-get_deps(L, Dep) ->
- case dict:find(L, Dep) of
- {ok, Ls} -> Ls;
- error -> []
- end.
-
-%% Escape operators may let their arguments escape. For this analysis,
-%% only send-operations are considered as causing escapement, and only
-%% in specific arguments.
-
-%% is_escape_op(_F, _A) -> [].
-
--spec is_escape_op(atom(), atom(), arity()) -> [arity()].
-
-is_escape_op(erlang, '!', 2) -> [2];
-is_escape_op(erlang, send, 2) -> [2];
-is_escape_op(erlang, spawn, 1) -> [1];
-is_escape_op(erlang, spawn, 3) -> [3];
-is_escape_op(erlang, spawn, 4) -> [4];
-is_escape_op(erlang, spawn_link, 3) -> [3];
-is_escape_op(erlang, spawn_link, 4) -> [4];
-is_escape_op(_M, _F, _A) -> [].
-
-%% "Immediate" operators will never return heap allocated data. This is
-%% of course true for operators that never return, like 'exit/1'. (Note
-%% that floats are always heap allocated objects, and that most integer
-%% arithmetic can return a bignum on the heap.)
-
--spec is_imm_op(atom(), arity()) -> boolean().
-
-is_imm_op(match_fail, 1) -> true;
-is_imm_op(_, _) -> false.
-
--spec is_imm_op(atom(), atom(), arity()) -> boolean().
-
-is_imm_op(erlang, self, 0) -> true;
-is_imm_op(erlang, '=:=', 2) -> true;
-is_imm_op(erlang, '==', 2) -> true;
-is_imm_op(erlang, '=/=', 2) -> true;
-is_imm_op(erlang, '/=', 2) -> true;
-is_imm_op(erlang, '<', 2) -> true;
-is_imm_op(erlang, '=<', 2) -> true;
-is_imm_op(erlang, '>', 2) -> true;
-is_imm_op(erlang, '>=', 2) -> true;
-is_imm_op(erlang, 'and', 2) -> true;
-is_imm_op(erlang, 'or', 2) -> true;
-is_imm_op(erlang, 'xor', 2) -> true;
-is_imm_op(erlang, 'not', 1) -> true;
-is_imm_op(erlang, is_alive, 0) -> true;
-is_imm_op(erlang, is_atom, 1) -> true;
-is_imm_op(erlang, is_binary, 1) -> true;
-is_imm_op(erlang, is_builtin, 3) -> true;
-is_imm_op(erlang, is_float, 1) -> true;
-is_imm_op(erlang, is_function, 1) -> true;
-is_imm_op(erlang, is_integer, 1) -> true;
-is_imm_op(erlang, is_list, 1) -> true;
-is_imm_op(erlang, is_number, 1) -> true;
-is_imm_op(erlang, is_pid, 1) -> true;
-is_imm_op(erlang, is_port, 1) -> true;
-is_imm_op(erlang, is_process_alive, 1) -> true;
-is_imm_op(erlang, is_reference, 1) -> true;
-is_imm_op(erlang, is_tuple, 1) -> true;
-is_imm_op(erlang, length, 1) -> true; % never a bignum
-is_imm_op(erlang, list_to_atom, 1) -> true;
-is_imm_op(erlang, node, 0) -> true;
-is_imm_op(erlang, node, 1) -> true;
-is_imm_op(erlang, throw, 1) -> true;
-is_imm_op(erlang, exit, 1) -> true;
-is_imm_op(erlang, error, 1) -> true;
-is_imm_op(erlang, error, 2) -> true;
-is_imm_op(_M, _F, _A) -> false.
diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl
index 518f67ee1b..8ae1cd4ab7 100644
--- a/lib/hipe/cerl/erl_bif_types.erl
+++ b/lib/hipe/cerl/erl_bif_types.erl
@@ -585,6 +585,13 @@ type(erlang, float, 1, Xs, Opaques) ->
%% Guard bif, needs to be here.
type(erlang, floor, 1, Xs, Opaques) ->
strict(erlang, floor, 1, Xs, fun (_) -> t_integer() end, Opaques);
+%% Primop, needs to be somewhere.
+type(erlang, build_stacktrace, 0, _, _Opaques) ->
+ t_list(t_tuple([t_module(),
+ t_atom(),
+ t_sup([t_arity(),t_list()]),
+ t_list(t_sup([t_tuple([t_atom('file'),t_string()]),
+ t_tuple([t_atom('line'),t_pos_integer()])]))]));
%% Guard bif, needs to be here.
type(erlang, hd, 1, Xs, Opaques) ->
strict(erlang, hd, 1, Xs, fun ([X]) -> t_cons_hd(X) end, Opaques);
@@ -658,6 +665,8 @@ type(erlang, is_map, 1, Xs, Opaques) ->
check_guard(X, fun (Y) -> t_is_map(Y, Opaques) end,
t_map(), Opaques) end,
strict(erlang, is_map, 1, Xs, Fun, Opaques);
+type(erlang, is_map_key, 2, Xs, Opaques) ->
+ type(maps, is_key, 2, Xs, Opaques);
type(erlang, is_number, 1, Xs, Opaques) ->
Fun = fun (X) ->
check_guard(X, fun (Y) -> t_is_number(Y, Opaques) end,
@@ -763,6 +772,9 @@ type(erlang, length, 1, Xs, Opaques) ->
%% Guard bif, needs to be here.
type(erlang, map_size, 1, Xs, Opaques) ->
type(maps, size, 1, Xs, Opaques);
+%% Guard bif, needs to be here.
+type(erlang, map_get, 2, Xs, Opaques) ->
+ type(maps, get, 2, Xs, Opaques);
type(erlang, make_fun, 3, Xs, Opaques) ->
strict(erlang, make_fun, 3, Xs,
fun ([_, _, Arity]) ->
@@ -1701,24 +1713,6 @@ type(maps, size, 1, Xs, Opaques) ->
t_from_range(LowerBound, UpperBound)
end
end, Opaques);
-type(maps, to_list, 1, Xs, Opaques) ->
- strict(maps, to_list, 1, Xs,
- fun ([Map]) ->
- DefK = t_map_def_key(Map, Opaques),
- DefV = t_map_def_val(Map, Opaques),
- Pairs = t_map_entries(Map, Opaques),
- EType = lists:foldl(
- fun({K,_,V},EType0) ->
- case t_is_none(V) of
- true -> t_subtract(EType0, t_tuple([K,t_any()]));
- false -> t_sup(EType0, t_tuple([K,V]))
- end
- end, t_tuple([DefK, DefV]), Pairs),
- case t_is_none(EType) of
- true -> t_nil();
- false -> t_list(EType)
- end
- end, Opaques);
type(maps, update, 3, Xs, Opaques) ->
strict(maps, update, 3, Xs,
fun ([Key, Value, Map]) ->
@@ -2231,10 +2225,7 @@ type_order() ->
t_map(), t_list(), t_bitstr()].
key_comparisons_fail(X0, KeyPos, TupleList, Opaques) ->
- X = case t_is_number(t_inf(X0, t_number(), Opaques), Opaques) of
- false -> X0;
- true -> t_number()
- end,
+ X = erl_types:t_widen_to_number(X0),
lists:all(fun(Tuple) ->
Key = type(erlang, element, 2, [KeyPos, Tuple]),
t_is_none(t_inf(Key, X, Opaques))
@@ -2354,6 +2345,9 @@ arg_types(erlang, float, 1) ->
%% Guard bif, needs to be here.
arg_types(erlang, floor, 1) ->
[t_number()];
+%% Primop, needs to be somewhere.
+arg_types(erlang, build_stacktrace, 0) ->
+ [];
%% Guard bif, needs to be here.
arg_types(erlang, hd, 1) ->
[t_cons()];
@@ -2379,6 +2373,8 @@ arg_types(erlang, is_list, 1) ->
[t_any()];
arg_types(erlang, is_map, 1) ->
[t_any()];
+arg_types(erlang, is_map_key, 2) ->
+ [t_any(), t_map()];
arg_types(erlang, is_number, 1) ->
[t_any()];
arg_types(erlang, is_pid, 1) ->
@@ -2399,6 +2395,9 @@ arg_types(erlang, length, 1) ->
%% Guard bif, needs to be here.
arg_types(erlang, map_size, 1) ->
[t_map()];
+%% Guard bif, needs to be here.
+arg_types(erlang, map_get, 2) ->
+ [t_any(), t_map()];
arg_types(erlang, make_fun, 3) ->
[t_atom(), t_atom(), t_arity()];
arg_types(erlang, make_tuple, 2) ->
@@ -2651,8 +2650,6 @@ arg_types(maps, put, 3) ->
[t_any(), t_any(), t_map()];
arg_types(maps, size, 1) ->
[t_map()];
-arg_types(maps, to_list, 1) ->
- [t_map()];
arg_types(maps, update, 3) ->
[t_any(), t_any(), t_map()];
arg_types(M, F, A) when is_atom(M), is_atom(F),
diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl
index 2b290b2f23..badf58936f 100644
--- a/lib/hipe/cerl/erl_types.erl
+++ b/lib/hipe/cerl/erl_types.erl
@@ -66,7 +66,6 @@
t_find_opaque_mismatch/3,
t_find_unknown_opaque/3,
t_fixnum/0,
- t_map/2,
t_non_neg_fixnum/0,
t_pos_fixnum/0,
t_float/0,
@@ -108,13 +107,14 @@
t_is_bitstr/1, t_is_bitstr/2,
t_is_bitwidth/1,
t_is_boolean/1, t_is_boolean/2,
- %% t_is_byte/1,
- %% t_is_char/1,
+ t_is_byte/1,
+ t_is_char/1,
t_is_cons/1, t_is_cons/2,
t_is_equal/2,
t_is_fixnum/1,
t_is_float/1, t_is_float/2,
t_is_fun/1, t_is_fun/2,
+ t_is_identifier/1,
t_is_instance/2,
t_is_integer/1, t_is_integer/2,
t_is_list/1,
@@ -204,6 +204,7 @@
t_unopaque/1, t_unopaque/2,
t_var/1,
t_var_name/1,
+ t_widen_to_number/1,
%% t_assign_variables_to_subtype/2,
type_is_defined/4,
record_field_diffs_to_string/2,
@@ -216,18 +217,7 @@
cache__new/0
]).
-%%-define(DO_ERL_TYPES_TEST, true).
--compile({no_auto_import,[min/2,max/2]}).
-
--ifdef(DO_ERL_TYPES_TEST).
--export([test/0]).
--else.
--define(NO_UNUSED, true).
--endif.
-
--ifndef(NO_UNUSED).
--export([t_is_identifier/1]).
--endif.
+-compile({no_auto_import,[min/2,max/2,map_get/2]}).
-export_type([erl_type/0, opaques/0, type_table/0,
var_table/0, cache/0]).
@@ -1190,12 +1180,10 @@ is_fun(_) -> false.
t_identifier() ->
?identifier(?any).
--ifdef(DO_ERL_TYPES_TEST).
--spec t_is_identifier(erl_type()) -> erl_type().
+-spec t_is_identifier(erl_type()) -> boolean().
t_is_identifier(?identifier(_)) -> true;
t_is_identifier(_) -> false.
--endif.
%%------------------------------------
@@ -1366,7 +1354,6 @@ is_integer1(_) -> false.
t_byte() ->
?byte.
--ifdef(DO_ERL_TYPES_TEST).
-spec t_is_byte(erl_type()) -> boolean().
t_is_byte(?int_range(neg_inf, _)) -> false;
@@ -1376,7 +1363,6 @@ t_is_byte(?int_range(From, To))
t_is_byte(?int_set(Set)) ->
(set_min(Set) >= 0) andalso (set_max(Set) =< ?MAX_BYTE);
t_is_byte(_) -> false.
--endif.
%%------------------------------------
@@ -1608,6 +1594,50 @@ lift_list_to_pos_empty(?nil) -> ?nil;
lift_list_to_pos_empty(?list(Content, Termination, _)) ->
?list(Content, Termination, ?unknown_qual).
+-spec t_widen_to_number(erl_type()) -> erl_type().
+
+%% Widens integers and floats to t_number().
+%% Used by erl_bif_types:key_comparison_fail().
+
+t_widen_to_number(?any) -> ?any;
+t_widen_to_number(?none) -> ?none;
+t_widen_to_number(?unit) -> ?unit;
+t_widen_to_number(?atom(_Set) = T) -> T;
+t_widen_to_number(?bitstr(_Unit, _Base) = T) -> T;
+t_widen_to_number(?float) -> t_number();
+t_widen_to_number(?function(Domain, Range)) ->
+ ?function(t_widen_to_number(Domain), t_widen_to_number(Range));
+t_widen_to_number(?identifier(_Types) = T) -> T;
+t_widen_to_number(?int_range(_From, _To)) -> t_number();
+t_widen_to_number(?int_set(_Set)) -> t_number();
+t_widen_to_number(?integer(_Types)) -> t_number();
+t_widen_to_number(?list(Type, Tail, Size)) ->
+ ?list(t_widen_to_number(Type), t_widen_to_number(Tail), Size);
+t_widen_to_number(?map(Pairs, DefK, DefV)) ->
+ L = [{t_widen_to_number(K), MNess, t_widen_to_number(V)} ||
+ {K, MNess, V} <- Pairs],
+ t_map(L, t_widen_to_number(DefK), t_widen_to_number(DefV));
+t_widen_to_number(?matchstate(_P, _Slots) = T) -> T;
+t_widen_to_number(?nil) -> ?nil;
+t_widen_to_number(?number(_Set, _Tag)) -> t_number();
+t_widen_to_number(?opaque(Set)) ->
+ L = [Opaque#opaque{struct = t_widen_to_number(S)} ||
+ #opaque{struct = S} = Opaque <- set_to_list(Set)],
+ ?opaque(ordsets:from_list(L));
+t_widen_to_number(?product(Types)) ->
+ ?product(list_widen_to_number(Types));
+t_widen_to_number(?tuple(?any, _, _) = T) -> T;
+t_widen_to_number(?tuple(Types, Arity, Tag)) ->
+ ?tuple(list_widen_to_number(Types), Arity, Tag);
+t_widen_to_number(?tuple_set(_) = Tuples) ->
+ t_sup([t_widen_to_number(T) || T <- t_tuple_subtypes(Tuples)]);
+t_widen_to_number(?union(List)) ->
+ ?union(list_widen_to_number(List));
+t_widen_to_number(?var(_Id)= T) -> T.
+
+list_widen_to_number(List) ->
+ [t_widen_to_number(E) || E <- List].
+
%%-----------------------------------------------------------------------------
%% Maps
%%
@@ -3118,9 +3148,18 @@ is_compat_arg(?list(Contents1, Termination1, Size1),
is_compat_arg(?product(Types1), ?product(Types2)) ->
is_compat_list(Types1, Types2);
is_compat_arg(?map(Pairs1, DefK1, DefV1), ?map(Pairs2, DefK2, DefV2)) ->
- (is_compat_list(Pairs1, Pairs2) andalso
- is_compat_arg(DefK1, DefK2) andalso
- is_compat_arg(DefV1, DefV2));
+ {Ks1, _, Vs1} = lists:unzip3(Pairs1),
+ {Ks2, _, Vs2} = lists:unzip3(Pairs2),
+ Key1 = t_sup([DefK1 | Ks1]),
+ Key2 = t_sup([DefK2 | Ks2]),
+ case is_compat_arg(Key1, Key2) of
+ true ->
+ Value1 = t_sup([DefV1 | Vs1]),
+ Value2 = t_sup([DefV2 | Vs2]),
+ is_compat_arg(Value1, Value2);
+ false ->
+ false
+ end;
is_compat_arg(?tuple(?any, ?any, ?any), ?tuple(_, _, _)) -> false;
is_compat_arg(?tuple(_, _, _), ?tuple(?any, ?any, ?any)) -> false;
is_compat_arg(?tuple(Elements1, Arity, _),
@@ -4170,39 +4209,6 @@ t_abstract_records(?opaque(_)=Type, RecDict) ->
t_abstract_records(T, _RecDict) ->
T.
-%% Map over types. Depth first. Used by the contract checker. ?list is
-%% not fully implemented so take care when changing the type in Termination.
-
--spec t_map(fun((erl_type()) -> erl_type()), erl_type()) -> erl_type().
-
-t_map(Fun, ?list(Contents, Termination, Size)) ->
- Fun(?list(t_map(Fun, Contents), t_map(Fun, Termination), Size));
-t_map(Fun, ?function(Domain, Range)) ->
- Fun(?function(t_map(Fun, Domain), t_map(Fun, Range)));
-t_map(Fun, ?product(Types)) ->
- Fun(?product([t_map(Fun, T) || T <- Types]));
-t_map(Fun, ?union(Types)) ->
- Fun(t_sup([t_map(Fun, T) || T <- Types]));
-t_map(Fun, ?tuple(?any, ?any, ?any) = T) ->
- Fun(T);
-t_map(Fun, ?tuple(Elements, _Arity, _Tag)) ->
- Fun(t_tuple([t_map(Fun, E) || E <- Elements]));
-t_map(Fun, ?tuple_set(_) = Tuples) ->
- Fun(t_sup([t_map(Fun, T) || T <- t_tuple_subtypes(Tuples)]));
-t_map(Fun, ?opaque(Set)) ->
- L = [Opaque#opaque{struct = NewS} ||
- #opaque{struct = S} = Opaque <- set_to_list(Set),
- not t_is_none(NewS = t_map(Fun, S))],
- Fun(case L of
- [] -> ?none;
- _ -> ?opaque(ordsets:from_list(L))
- end);
-t_map(Fun, ?map(Pairs,DefK,DefV)) ->
- %% TODO:
- Fun(t_map(Pairs, Fun(DefK), Fun(DefV)));
-t_map(Fun, T) ->
- Fun(T).
-
%%=============================================================================
%%
%% Prettyprinter
@@ -4257,13 +4263,13 @@ t_to_string(?identifier(Set), _RecDict) ->
case Set of
?any -> "identifier()";
_ ->
- string:join([flat_format("~w()", [T]) || T <- set_to_list(Set)], " | ")
+ flat_join([flat_format("~w()", [T]) || T <- set_to_list(Set)], " | ")
end;
t_to_string(?opaque(Set), RecDict) ->
- string:join([opaque_type(Mod, Name, Args, S, RecDict) ||
- #opaque{mod = Mod, name = Name, struct = S, args = Args}
- <- set_to_list(Set)],
- " | ");
+ flat_join([opaque_type(Mod, Name, Args, S, RecDict) ||
+ #opaque{mod = Mod, name = Name, struct = S, args = Args}
+ <- set_to_list(Set)],
+ " | ");
t_to_string(?matchstate(Pres, Slots), RecDict) ->
flat_format("ms(~ts,~ts)", [t_to_string(Pres, RecDict),
t_to_string(Slots,RecDict)]);
@@ -4354,9 +4360,9 @@ t_to_string(?map(Pairs0,DefK,DefV), RecDict) ->
end end,
StrMand = [{Tos(K),Tos(V)}||{K,?mand,V}<-Pairs],
StrOpt = [{Tos(K),Tos(V)}||{K,?opt,V}<-Pairs],
- "#{" ++ string:join([K ++ ":=" ++ V||{K,V}<-StrMand]
- ++ [K ++ "=>" ++ V||{K,V}<-StrOpt]
- ++ ExtraEl, ", ") ++ "}";
+ "#{" ++ flat_join([K ++ ":=" ++ V||{K,V}<-StrMand]
+ ++ [K ++ "=>" ++ V||{K,V}<-StrOpt]
+ ++ ExtraEl, ", ") ++ "}";
t_to_string(?tuple(?any, ?any, ?any), _RecDict) -> "tuple()";
t_to_string(?tuple(Elements, _Arity, ?any), RecDict) ->
"{" ++ comma_sequence(Elements, RecDict) ++ "}";
@@ -4379,7 +4385,7 @@ t_to_string(?var(Id), _RecDict) when is_integer(Id) ->
record_to_string(Tag, [_|Fields], FieldNames, RecDict) ->
FieldStrings = record_fields_to_string(Fields, FieldNames, RecDict, []),
- "#" ++ atom_to_string(Tag) ++ "{" ++ string:join(FieldStrings, ",") ++ "}".
+ "#" ++ atom_to_string(Tag) ++ "{" ++ flat_join(FieldStrings, ",") ++ "}".
record_fields_to_string([F|Fs], [{FName, _Abstr, DefType}|FDefs],
RecDict, Acc) ->
@@ -4405,7 +4411,7 @@ record_field_diffs_to_string(?tuple([_|Fs], Arity, Tag), RecDict) ->
{ok, FieldNames} = lookup_record(TagAtom, Arity-1, RecDict),
%% io:format("RecCElems = ~p\nRecTypes = ~p\n", [Fs, FieldNames]),
FieldDiffs = field_diffs(Fs, FieldNames, RecDict, []),
- string:join(FieldDiffs, " and ").
+ flat_join(FieldDiffs, " and ").
field_diffs([F|Fs], [{FName, _Abstr, DefType}|FDefs], RecDict, Acc) ->
%% Don't care about opacity for now.
@@ -4425,11 +4431,11 @@ comma_sequence(Types, RecDict) ->
true -> "_";
false -> t_to_string(T, RecDict)
end || T <- Types],
- string:join(List, ",").
+ flat_join(List, ",").
union_sequence(Types, RecDict) ->
List = [t_to_string(T, RecDict) || T <- Types],
- string:join(List, " | ").
+ flat_join(List, " | ").
-ifdef(DEBUG).
opaque_type(Mod, Name, _Args, S, RecDict) ->
@@ -5269,7 +5275,7 @@ t_form_to_string({ann_type, _L, [Var, Type]}) ->
t_form_to_string({paren_type, _L, [Type]}) ->
flat_format("(~ts)", [t_form_to_string(Type)]);
t_form_to_string({remote_type, _L, [{atom, _, Mod}, {atom, _, Name}, Args]}) ->
- ArgString = "(" ++ string:join(t_form_to_string_list(Args), ",") ++ ")",
+ ArgString = "(" ++ flat_join(t_form_to_string_list(Args), ",") ++ ")",
flat_format("~w:~tw", [Mod, Name]) ++ ArgString;
t_form_to_string({type, _L, arity, []}) -> "arity()";
t_form_to_string({type, _L, binary, []}) -> "binary()";
@@ -5292,7 +5298,7 @@ t_form_to_string({type, _L, 'fun', []}) -> "fun()";
t_form_to_string({type, _L, 'fun', [{type, _, any}, Range]}) ->
"fun(...) -> " ++ t_form_to_string(Range);
t_form_to_string({type, _L, 'fun', [{type, _, product, Domain}, Range]}) ->
- "fun((" ++ string:join(t_form_to_string_list(Domain), ",") ++ ") -> "
+ "fun((" ++ flat_join(t_form_to_string_list(Domain), ",") ++ ") -> "
++ t_form_to_string(Range) ++ ")";
t_form_to_string({type, _L, iodata, []}) -> "iodata()";
t_form_to_string({type, _L, iolist, []}) -> "iolist()";
@@ -5300,7 +5306,7 @@ t_form_to_string({type, _L, list, [Type]}) ->
"[" ++ t_form_to_string(Type) ++ "]";
t_form_to_string({type, _L, map, any}) -> "map()";
t_form_to_string({type, _L, map, Args}) ->
- "#{" ++ string:join(t_form_to_string_list(Args), ",") ++ "}";
+ "#{" ++ flat_join(t_form_to_string_list(Args), ",") ++ "}";
t_form_to_string({type, _L, map_field_assoc, [Key, Val]}) ->
t_form_to_string(Key) ++ "=>" ++ t_form_to_string(Val);
t_form_to_string({type, _L, map_field_exact, [Key, Val]}) ->
@@ -5312,7 +5318,7 @@ t_form_to_string({type, _L, nonempty_list, [Type]}) ->
"[" ++ t_form_to_string(Type) ++ ",...]";
t_form_to_string({type, _L, nonempty_string, []}) -> "nonempty_string()";
t_form_to_string({type, _L, product, Elements}) ->
- "<" ++ string:join(t_form_to_string_list(Elements), ",") ++ ">";
+ "<" ++ flat_join(t_form_to_string_list(Elements), ",") ++ ">";
t_form_to_string({type, _L, range, [From, To]} = Type) ->
case {erl_eval:partial_eval(From), erl_eval:partial_eval(To)} of
{{integer, _, FromVal}, {integer, _, ToVal}} ->
@@ -5322,7 +5328,7 @@ t_form_to_string({type, _L, range, [From, To]} = Type) ->
t_form_to_string({type, _L, record, [{atom, _, Name}]}) ->
flat_format("#~tw{}", [Name]);
t_form_to_string({type, _L, record, [{atom, _, Name}|Fields]}) ->
- FieldString = string:join(t_form_to_string_list(Fields), ","),
+ FieldString = flat_join(t_form_to_string_list(Fields), ","),
flat_format("#~tw{~ts}", [Name, FieldString]);
t_form_to_string({type, _L, field_type, [{atom, _, Name}, Type]}) ->
flat_format("~tw::~ts", [Name, t_form_to_string(Type)]);
@@ -5330,9 +5336,17 @@ t_form_to_string({type, _L, term, []}) -> "term()";
t_form_to_string({type, _L, timeout, []}) -> "timeout()";
t_form_to_string({type, _L, tuple, any}) -> "tuple()";
t_form_to_string({type, _L, tuple, Args}) ->
- "{" ++ string:join(t_form_to_string_list(Args), ",") ++ "}";
+ "{" ++ flat_join(t_form_to_string_list(Args), ",") ++ "}";
t_form_to_string({type, _L, union, Args}) ->
- string:join(t_form_to_string_list(Args), " | ");
+ flat_join(lists:map(fun(Arg) ->
+ case Arg of
+ {ann_type, _AL, _} ->
+ "(" ++ t_form_to_string(Arg) ++ ")";
+ _ ->
+ t_form_to_string(Arg)
+ end
+ end, Args),
+ " | ");
t_form_to_string({type, _L, Name, []} = T) ->
try
M = mod,
@@ -5350,7 +5364,7 @@ t_form_to_string({type, _L, Name, []} = T) ->
end;
t_form_to_string({user_type, _L, Name, List}) ->
flat_format("~tw(~ts)",
- [Name, string:join(t_form_to_string_list(List), ",")]);
+ [Name, flat_join(t_form_to_string_list(List), ",")]);
t_form_to_string({type, L, Name, List}) ->
%% Compatibility: modules compiled before Erlang/OTP 18.0.
t_form_to_string({user_type, L, Name, List}).
@@ -5611,7 +5625,7 @@ set_to_string(Set) ->
true -> io_lib:write_string(atom_to_list(X), $'); % stupid emacs '
false -> flat_format("~tw", [X])
end || X <- set_to_list(Set)],
- string:join(L, " | ").
+ flat_join(L, " | ").
set_min([H|_]) -> H.
@@ -5621,6 +5635,9 @@ set_max(Set) ->
flat_format(F, S) ->
lists:flatten(io_lib:format(F, S)).
+flat_join(List, Sep) ->
+ lists:flatten(lists:join(Sep, List)).
+
%%=============================================================================
%%
%% Utilities for the binary type
@@ -5690,173 +5707,3 @@ family(L) ->
var_table__new() ->
maps:new().
-
-%%=============================================================================
-%% Consistency-testing function(s) below
-%%=============================================================================
-
--ifdef(DO_ERL_TYPES_TEST).
-
-test() ->
- Atom1 = t_atom(),
- Atom2 = t_atom(foo),
- Atom3 = t_atom(bar),
- true = t_is_atom(Atom2),
-
- True = t_atom(true),
- False = t_atom(false),
- Bool = t_boolean(),
- true = t_is_boolean(True),
- true = t_is_boolean(Bool),
- false = t_is_boolean(Atom1),
-
- Binary = t_binary(),
- true = t_is_binary(Binary),
-
- Bitstr = t_bitstr(),
- true = t_is_bitstr(Bitstr),
-
- Bitstr1 = t_bitstr(7, 3),
- true = t_is_bitstr(Bitstr1),
- false = t_is_binary(Bitstr1),
-
- Bitstr2 = t_bitstr(16, 8),
- true = t_is_bitstr(Bitstr2),
- true = t_is_binary(Bitstr2),
-
- ?bitstr(8, 16) = t_subtract(t_bitstr(4, 12), t_bitstr(8, 12)),
- ?bitstr(8, 16) = t_subtract(t_bitstr(4, 12), t_bitstr(8, 12)),
-
- Int1 = t_integer(),
- Int2 = t_integer(1),
- Int3 = t_integer(16#ffffffff),
- true = t_is_integer(Int2),
- true = t_is_byte(Int2),
- false = t_is_byte(Int3),
- false = t_is_byte(t_from_range(-1, 1)),
- true = t_is_byte(t_from_range(1, ?MAX_BYTE)),
-
- Tuple1 = t_tuple(),
- Tuple2 = t_tuple(3),
- Tuple3 = t_tuple([Atom1, Int1]),
- Tuple4 = t_tuple([Tuple1, Tuple2]),
- Tuple5 = t_tuple([Tuple3, Tuple4]),
- Tuple6 = t_limit(Tuple5, 2),
- Tuple7 = t_limit(Tuple5, 3),
- true = t_is_tuple(Tuple1),
-
- Port = t_port(),
- Pid = t_pid(),
- Ref = t_reference(),
- Identifier = t_identifier(),
- false = t_is_reference(Port),
- true = t_is_identifier(Port),
-
- Function1 = t_fun(),
- Function2 = t_fun(Pid),
- Function3 = t_fun([], Pid),
- Function4 = t_fun([Port, Pid], Pid),
- Function5 = t_fun([Pid, Atom1], Int2),
- true = t_is_fun(Function3),
-
- List1 = t_list(),
- List2 = t_list(t_boolean()),
- List3 = t_cons(t_boolean(), List2),
- List4 = t_cons(t_boolean(), t_atom()),
- List5 = t_cons(t_boolean(), t_nil()),
- List6 = t_cons_tl(List5),
- List7 = t_sup(List4, List5),
- List8 = t_inf(List7, t_list()),
- List9 = t_cons(),
- List10 = t_cons_tl(List9),
- true = t_is_boolean(t_cons_hd(List5)),
- true = t_is_list(List5),
- false = t_is_list(List4),
-
- Product1 = t_product([Atom1, Atom2]),
- Product2 = t_product([Atom3, Atom1]),
- Product3 = t_product([Atom3, Atom2]),
-
- Union1 = t_sup(Atom2, Atom3),
- Union2 = t_sup(Tuple2, Tuple3),
- Union3 = t_sup(Int2, Atom3),
- Union4 = t_sup(Port, Pid),
- Union5 = t_sup(Union4, Int1),
- Union6 = t_sup(Function1, Function2),
- Union7 = t_sup(Function4, Function5),
- Union8 = t_sup(True, False),
- true = t_is_boolean(Union8),
- Union9 = t_sup(Int2, t_integer(2)),
- true = t_is_byte(Union9),
- Union10 = t_sup(t_tuple([t_atom(true), ?any]),
- t_tuple([t_atom(false), ?any])),
-
- ?any = t_sup(Product3, Function5),
-
- Atom3 = t_inf(Union3, Atom1),
- Union2 = t_inf(Union2, Tuple1),
- Int2 = t_inf(Int1, Union3),
- Union4 = t_inf(Union4, Identifier),
- Port = t_inf(Union5, Port),
- Function4 = t_inf(Union7, Function4),
- ?none = t_inf(Product2, Atom1),
- Product3 = t_inf(Product1, Product2),
- Function5 = t_inf(Union7, Function5),
- true = t_is_byte(t_inf(Union9, t_number())),
- true = t_is_char(t_inf(Union9, t_number())),
-
- io:format("3? ~p ~n", [?int_set([3])]),
-
- RecDict = dict:store({foo, 2}, [bar, baz], dict:new()),
- Record1 = t_from_term({foo, [1,2], {1,2,3}}),
-
- Types = [
- Atom1,
- Atom2,
- Atom3,
- Binary,
- Int1,
- Int2,
- Tuple1,
- Tuple2,
- Tuple3,
- Tuple4,
- Tuple5,
- Tuple6,
- Tuple7,
- Ref,
- Port,
- Pid,
- Identifier,
- List1,
- List2,
- List3,
- List4,
- List5,
- List6,
- List7,
- List8,
- List9,
- List10,
- Function1,
- Function2,
- Function3,
- Function4,
- Function5,
- Product1,
- Product2,
- Record1,
- Union1,
- Union2,
- Union3,
- Union4,
- Union5,
- Union6,
- Union7,
- Union8,
- Union10,
- t_inf(Union10, t_tuple([t_atom(true), t_integer()]))
- ],
- io:format("~p\n", [[t_to_string(X, RecDict) || X <- Types]]).
-
--endif.
diff --git a/lib/hipe/doc/src/Makefile b/lib/hipe/doc/src/Makefile
index 1c774d3357..104c15f2bb 100644
--- a/lib/hipe/doc/src/Makefile
+++ b/lib/hipe/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2006-2017. All Rights Reserved.
+# Copyright Ericsson AB 2006-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -94,6 +94,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/lib/hipe/doc/src/hipe_app.xml b/lib/hipe/doc/src/hipe_app.xml
index 9299c6d73f..61d92fdffe 100644
--- a/lib/hipe/doc/src/hipe_app.xml
+++ b/lib/hipe/doc/src/hipe_app.xml
@@ -4,7 +4,7 @@
<appref>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -35,6 +35,14 @@
<app>HiPE</app>
<appsummary>The HiPE Application</appsummary>
<description>
+ <note>
+ <p>
+ HiPE and execution of HiPE compiled code only have limited support by
+ the OTP team at Ericsson. The OTP team only does limited maintenance
+ of HiPE and does not actively develop HiPE. HiPE is mainly supported
+ by the HiPE team at Uppsala University.
+ </p>
+ </note>
<p>
The normal way to native-compile an Erlang module using HiPE is to include the atom native
in the Erlang compiler options, as in:</p>
@@ -54,6 +62,11 @@
and the runtime system that have limited or no support for HiPE compiled modules.
</p>
<taglist>
+ <tag>Binary matching</tag>
+ <item><p>The HiPE compiler will crash on modules containing binary
+ matching.</p>
+ </item>
+
<tag>Stack traces</tag>
<item><p>Stack traces returned from <seealso marker="erts:erlang#get_stacktrace/0">
<c>erlang:get_stacktrace/0</c></seealso> or as part of <c>'EXIT'</c> terms
@@ -70,12 +83,12 @@
</item>
<tag>NIFs</tag>
- <item><p>Modules compiled with HiPE can not call <seealso marker="erts:erlang#load_nif-2">
+ <item><p>Modules compiled with HiPE cannot call <seealso marker="erts:erlang#load_nif-2">
<c>erlang:load_nif/2</c></seealso> to load NIFs.</p>
</item>
<tag>-on_load</tag>
- <item><p>Modules compiled with HiPE can not use
+ <item><p>Modules compiled with HiPE cannot use
<seealso marker="doc/reference_manual:code_loading#on_load"><c>-on_load()</c></seealso>
directives.</p>
</item>
@@ -100,19 +113,77 @@
</item>
<tag>Optimization for <c>receive</c> with unique references</tag>
- <item><p>The BEAM compiler can do an optimization when
- a <c>receive</c> statement is <em>only</em> waiting for messages
- containing a reference created before the receive. All messages
- that existed in the queue when the reference was created will be
- bypassed, as they cannot possibly contain the reference. HiPE
- does not implement this optimization.</p>
- <p>An example of this is when
- <c>gen_server:call()</c> waits for the reply message.</p>
+ <item>
+ <p>
+ The BEAM compiler can do an optimization when a receive
+ statement is only waiting for messages containing a reference
+ created before the receive. All messages that existed in the
+ queue when the reference was created will be bypassed, as they
+ cannot possibly contain the reference. HiPE currently has an
+ optimization similar this, but it is not guaranteed to
+ bypass all messages. In the worst case scenario, it cannot
+ bypass any messages at all.
+ </p>
+ <p>
+ An example of this is when <c>gen_server:call()</c> waits for
+ the reply message.
+ </p>
+ </item>
+
+ <tag>Garbage collection after BIFs</tag>
+ <item>
+ <p>
+ The condition for determining whether a garbage collection
+ is needed or not has changed in later releases. HiPE has not
+ been updated regarding this which may cause premature garbage
+ collections after BIF calls.
+ </p>
</item>
</taglist>
</section>
<section>
+ <title>Stability Issues</title>
+ <taglist>
+ <tag>Not checking reduction count on function returns</tag>
+ <item>
+ <p>
+ BEAM checks the reduction count and schedules out the executing
+ process if needed both when calling a function and when returning
+ from a function call that was not called using a tail call.
+ HiPE only checks the reduction count when calling a function.
+ </p>
+ <p>
+ The runtime system might need to schedule out a process
+ in order to reclaim memory. If the process isn't scheduled
+ out soon after the process has entered this state, memory
+ consumption will quickly grow. Maintaining this state is also
+ quite expensive performance wise.
+ </p>
+ <p>
+ Processes executing code that performs large recursions and
+ produce data after returning from recursive calls may have to
+ be scheduled out when returning from a function call. Since
+ HiPE does not check reductions on returns, processes executing
+ such HiPE compiled code may cause huge peeks in memory
+ consumption as well as severe performance degradation.
+ </p>
+ </item>
+
+ <tag>Not bumping appropriate amount of reductions in <c>receive</c> statements</tag>
+ <item>
+ <p>
+ The process signaling improvements made in ERTS version
+ 10.0 moved potentially significant amounts of work into the
+ receive statement from other places. In order to account for
+ this work, the reduction count should be bumped on the
+ executing process. Reductions are not bumped when entering
+ the <c>receive</c> statement from HiPE compiled code.
+ </p>
+ </item>
+ </taglist>
+ </section>
+ <section>
<title>SEE ALSO</title>
<p>
<seealso marker="stdlib:c">c(3)</seealso>,
diff --git a/lib/hipe/doc/src/notes.xml b/lib/hipe/doc/src/notes.xml
index c190a89260..a2e0766bb7 100644
--- a/lib/hipe/doc/src/notes.xml
+++ b/lib/hipe/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2006</year><year>2017</year>
+ <year>2006</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,6 +31,143 @@
</header>
<p>This document describes the changes made to HiPE.</p>
+<section><title>Hipe 3.19</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Add function <c>hipe:erllvm_is_supported</c> to check for
+ the presences of a suitable version of the LLVM tool
+ chain as well as supported hardware architecture. The old
+ <c>hipe:llvm_support_available</c> has been removed.</p>
+ <p>
+ Own Id: OTP-15385 Aux Id: PR-1986 </p>
+ </item>
+ <item>
+ <p>
+ Fix hipe LLVM for FreeBSD and other non-linux unix to use
+ /tmp/ instead of /dev/shm/.</p>
+ <p>
+ Own Id: OTP-15386 Aux Id: PR-1963 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>In OTP 22, HiPE (the native code compiler) is not
+ fully functional. The reasons for this are:</p>
+ <p>There are new BEAM instructions for binary matching
+ that the HiPE native code compiler does not support.</p>
+ <p>The new optimizations in the Erlang compiler create
+ new combination of instructions that HiPE currently does
+ not handle correctly.</p>
+ <p>If erlc is invoked with the <c>+native</c> option, and
+ if any of the new binary matching instructions are used,
+ the compiler will issue a warning and produce a BEAM file
+ without native code.</p>
+ <p>
+ Own Id: OTP-15596</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Hipe 3.18.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Fix a bug in the handling of the <c>Key</c> argument
+ of <c>lists:{keysearch, keyfind, keymember}</c>. </p>
+ <p>
+ Own Id: OTP-15570</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Hipe 3.18.2</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>The code was updated to avoid causing a dialyzer
+ warning because of a tightened spec for
+ <c>beam_lib:info/1</c>.</p>
+ <p>
+ Own Id: OTP-15482</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Hipe 3.18.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Hipe 3.18</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Optimize <c>receive</c> statements that are only waiting
+ for messages containing a reference created before the
+ receive. All messages that existed in the queue when the
+ reference was created will be bypassed, as they cannot
+ possibly contain the reference. This optimization has
+ existed for vanilla BEAM since OTP R14.</p>
+ <p>
+ Own Id: OTP-14785 Aux Id: PR-1632 </p>
+ </item>
+ <item>
+ <p>
+ Add validation pass to hipe compiler to detect internal
+ errors causing primop calls that may trigger an unsafe GC
+ at run-time. The pass can be disabled with option
+ <c>no_verify_gcsafe</c>.</p>
+ <p>
+ Own Id: OTP-14900 Aux Id: PR-1685, PR-1621 </p>
+ </item>
+ <item>
+ <p>
+ Make hipe compiled code work on x86_64 (amd64) with OS
+ security feature PIE, where executable code can be loaded
+ into a random location. Old behavior, if hipe was
+ enabled, was to disable PIE build options for the VM.</p>
+ <p>
+ Own Id: OTP-14903</p>
+ </item>
+ <item>
+ <p>
+ Inline more type test BIFs; <c>is_number</c>,
+ <c>is_bitstring</c>, <c>is_map</c>.</p>
+ <p>
+ Own Id: OTP-14941 Aux Id: PR-1718 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Hipe 3.17.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/hipe/icode/hipe_beam_to_icode.erl b/lib/hipe/icode/hipe_beam_to_icode.erl
index 2abecf7f18..8e7e56b6c4 100644
--- a/lib/hipe/icode/hipe_beam_to_icode.erl
+++ b/lib/hipe/icode/hipe_beam_to_icode.erl
@@ -415,11 +415,13 @@ trans_fun([{wait_timeout,{_,Lbl},Reg}|Instructions], Env) ->
SuspTmout = hipe_icode:mk_if(suspend_msg_timeout,[],
map_label(Lbl),hipe_icode:label_name(DoneLbl)),
Movs ++ [SetTmout, SuspTmout, DoneLbl | trans_fun(Instructions,Env1)];
-%%--- recv_mark/1 & recv_set/1 --- XXX: Handle better??
+%%--- recv_mark/1 & recv_set/1 ---
trans_fun([{recv_mark,{f,_}}|Instructions], Env) ->
- trans_fun(Instructions,Env);
+ Mark = hipe_icode:mk_primop([],recv_mark,[]),
+ [Mark | trans_fun(Instructions,Env)];
trans_fun([{recv_set,{f,_}}|Instructions], Env) ->
- trans_fun(Instructions,Env);
+ Set = hipe_icode:mk_primop([],recv_set,[]),
+ [Set | trans_fun(Instructions,Env)];
%%--------------------------------------------------------------------
%%--- Translation of arithmetics {bif,ArithOp, ...} ---
%%--------------------------------------------------------------------
@@ -603,6 +605,16 @@ trans_fun([{get_list,List,Head,Tail}|Instructions], Env) ->
?error_msg("hd and tl regs identical in get_list~n",[]),
erlang:error(not_handled)
end;
+%%--- get_hd ---
+trans_fun([{get_hd,List,Head}|Instructions], Env) ->
+ TransList = [trans_arg(List)],
+ I = hipe_icode:mk_primop([mk_var(Head)],unsafe_hd,TransList),
+ [I | trans_fun(Instructions,Env)];
+%%--- get_tl ---
+trans_fun([{get_tl,List,Tail}|Instructions], Env) ->
+ TransList = [trans_arg(List)],
+ I = hipe_icode:mk_primop([mk_var(Tail)],unsafe_tl,TransList),
+ [I | trans_fun(Instructions,Env)];
%%--- get_tuple_element ---
trans_fun([{get_tuple_element,Xreg,Index,Dst}|Instructions], Env) ->
I = hipe_icode:mk_primop([mk_var(Dst)],
@@ -635,6 +647,13 @@ trans_fun([{put_tuple,_Size,Reg}|Instructions], Env) ->
Primop = hipe_icode:mk_primop(Dest,mktuple,Src),
Moves ++ [Primop | trans_fun(Instructions2,Env2)];
%%--- put --- SHOULD NOT REALLY EXIST HERE; put INSTRUCTIONS ARE HANDLED ABOVE.
+%%--- put_tuple2 ---
+trans_fun([{put_tuple2,Reg,{list,Elements}}|Instructions], Env) ->
+ Dest = [mk_var(Reg)],
+ {Moves,Vars,Env2} = trans_elements(Elements, [], [], Env),
+ Src = lists:reverse(Vars),
+ Primop = hipe_icode:mk_primop(Dest, mktuple, Src),
+ Moves ++ [Primop | trans_fun(Instructions, Env2)];
%%--- badmatch ---
trans_fun([{badmatch,Arg}|Instructions], Env) ->
BadVar = trans_arg(Arg),
@@ -794,7 +813,7 @@ trans_fun([{bs_append,{f,Lbl},Size,W,R,U,Binary,{field_flags,F},Dst}|
SizeArg = trans_arg(Size),
BinArg = trans_arg(Binary),
IcodeDst = mk_var(Dst),
- Offset = mk_var(reg),
+ Offset = mk_var(reg_gcsafe),
Base = mk_var(reg),
trans_bin_call({hipe_bs_primop,{bs_append,W,R,U,F}},Lbl,[SizeArg,BinArg],
[IcodeDst,Base,Offset],
@@ -805,7 +824,7 @@ trans_fun([{bs_private_append,{f,Lbl},Size,U,Binary,{field_flags,F},Dst}|
SizeArg = trans_arg(Size),
BinArg = trans_arg(Binary),
IcodeDst = mk_var(Dst),
- Offset = mk_var(reg),
+ Offset = mk_var(reg_gcsafe),
Base = mk_var(reg),
trans_bin_call({hipe_bs_primop,{bs_private_append,U,F}},
Lbl,[SizeArg,BinArg],
@@ -844,7 +863,7 @@ trans_fun([{bs_init2,{f,Lbl},Size,_Words,_LiveRegs,{field_flags,Flags0},X}|
Instructions], Env) ->
Dst = mk_var(X),
Flags = resolve_native_endianess(Flags0),
- Offset = mk_var(reg),
+ Offset = mk_var(reg_gcsafe),
Base = mk_var(reg),
{Name, Args} =
case Size of
@@ -860,7 +879,7 @@ trans_fun([{bs_init_bits,{f,Lbl},Size,_Words,_LiveRegs,{field_flags,Flags0},X}|
Instructions], Env) ->
Dst = mk_var(X),
Flags = resolve_native_endianess(Flags0),
- Offset = mk_var(reg),
+ Offset = mk_var(reg_gcsafe),
Base = mk_var(reg),
{Name, Args} =
case Size of
@@ -1127,9 +1146,10 @@ trans_fun([{test,has_map_fields,{f,Lbl},Map,{list,Keys}}|Instructions], Env) ->
lists:flatten([[K, {r, 0}] || K <- Keys])),
[MapMove, TestInstructions | trans_fun(Instructions, Env2)];
trans_fun([{get_map_elements,{f,Lbl},Map,{list,KVPs}}|Instructions], Env) ->
+ KVPs1 = overwrite_map_last(Map, KVPs),
{MapMove, MapVar, Env1} = mk_move_and_var(Map, Env),
{TestInstructions, GetInstructions, Env2} =
- trans_map_query(MapVar, map_label(Lbl), Env1, KVPs),
+ trans_map_query(MapVar, map_label(Lbl), Env1, KVPs1),
[MapMove, TestInstructions, GetInstructions | trans_fun(Instructions, Env2)];
%%--- put_map_assoc ---
trans_fun([{put_map_assoc,{f,Lbl},Map,Dst,_N,{list,Pairs}}|Instructions], Env) ->
@@ -1157,6 +1177,32 @@ trans_fun([{put_map_exact,{f,Lbl},Map,Dst,_N,{list,Pairs}}|Instructions], Env) -
gen_put_map_instrs(new, exact, TempMapVar, Dst, new, Pairs, Env1)
end,
[MapMove, TempMapMove, PutInstructions | trans_fun(Instructions, Env2)];
+%%--- build_stacktrace ---
+trans_fun([build_stacktrace|Instructions], Env) ->
+ Vars = [mk_var({x,0})], %{x,0} is implict arg and dst
+ [hipe_icode:mk_primop(Vars,build_stacktrace,Vars),
+ trans_fun(Instructions, Env)];
+%%--- raw_raise ---
+trans_fun([raw_raise|Instructions], Env) ->
+ Vars = [mk_var({x,0}),mk_var({x,1}),mk_var({x,2})],
+ Dst = [mk_var({x,0})],
+ [hipe_icode:mk_primop(Dst,raw_raise,Vars) |
+ trans_fun(Instructions, Env)];
+%%--------------------------------------------------------------------
+%% New binary matching added in OTP 22.
+%%--------------------------------------------------------------------
+%%--- bs_get_tail ---
+trans_fun([{bs_get_tail=Name,_,_,_}|_Instructions], _Env) ->
+ nyi(Name);
+%%--- bs_start_match3 ---
+trans_fun([{bs_start_match3=Name,_,_,_,_}|_Instructions], _Env) ->
+ nyi(Name);
+%%--- bs_get_position ---
+trans_fun([{bs_get_position=Name,_,_,_}|_Instructions], _Env) ->
+ nyi(Name);
+%%--- bs_set_position ---
+trans_fun([{bs_set_position=Name,_,_}|_Instructions], _Env) ->
+ nyi(Name);
%%--------------------------------------------------------------------
%%--- ERROR HANDLING ---
%%--------------------------------------------------------------------
@@ -1165,6 +1211,9 @@ trans_fun([X|_], _) ->
trans_fun([], _) ->
[].
+nyi(Name) ->
+ throw({unimplemented_instruction,Name}).
+
%%--------------------------------------------------------------------
%% trans_call and trans_enter generate correct Icode calls/tail-calls,
%% recognizing explicit fails.
@@ -1505,7 +1554,10 @@ clone_dst(Dest) ->
New =
case hipe_icode:is_reg(Dest) of
true ->
- mk_var(reg);
+ case hipe_icode:reg_is_gcsafe(Dest) of
+ true -> mk_var(reg_gcsafe);
+ false -> mk_var(reg)
+ end;
false ->
true = hipe_icode:is_var(Dest),
mk_var(new)
@@ -1537,6 +1589,21 @@ trans_type_test2(function2, Lbl, Arg, Arity, Env) ->
hipe_icode:label_name(True), map_label(Lbl)),
{[Move1,Move2,I,True],Env2}.
+
+%%
+%% Makes sure that if a get_map_elements instruction will overwrite
+%% the map source, it will be done last.
+%%
+overwrite_map_last(Map, KVPs) ->
+ overwrite_map_last2(Map, KVPs, []).
+
+overwrite_map_last2(Map, [Key,Map|KVPs], _Last) ->
+ overwrite_map_last2(Map, KVPs, [Key,Map]);
+overwrite_map_last2(Map, [Key,Val|KVPs], Last) ->
+ [Key,Val|overwrite_map_last2(Map, KVPs, Last)];
+overwrite_map_last2(_Map, [], Last) ->
+ Last.
+
%%
%% Handles the get_map_elements instruction and the has_map_fields
%% test instruction.
@@ -1657,6 +1724,19 @@ trans_puts([{put,X}|Code], Vars, Moves, Env) ->
trans_puts(Code, Vars, Moves, Env) -> %% No more put operations
{Moves, Code, Vars, Env}.
+trans_elements([X|Code], Vars, Moves, Env) ->
+ case type(X) of
+ var ->
+ Var = mk_var(X),
+ trans_elements(Code, [Var|Vars], Moves, Env);
+ #beam_const{value=C} ->
+ Var = mk_var(new),
+ Move = hipe_icode:mk_move(Var, hipe_icode:mk_const(C)),
+ trans_elements(Code, [Var|Vars], [Move|Moves], Env)
+ end;
+trans_elements([], Vars, Moves, Env) ->
+ {Moves, Vars, Env}.
+
%%-----------------------------------------------------------------------
%% The code for this instruction is a bit large because we are treating
%% different cases differently. We want to use the icode `type'
@@ -2126,7 +2206,12 @@ mk_var(reg) ->
T = hipe_gensym:new_var(icode),
V = (5*T)+4,
hipe_gensym:update_vrange(icode,V),
- hipe_icode:mk_reg(V).
+ hipe_icode:mk_reg(V);
+mk_var(reg_gcsafe) ->
+ T = hipe_gensym:new_var(icode),
+ V = (5*T)+4, % same namespace as 'reg'
+ hipe_gensym:update_vrange(icode,V),
+ hipe_icode:mk_reg_gcsafe(V).
%%-----------------------------------------------------------------------
%% Make an icode label of proper type
@@ -2296,6 +2381,12 @@ split_code([First|Code], Label, Instr) ->
split_code([Instr|Code], Label, Instr, Prev, As) when Prev =:= Label ->
split_code_final(Code, As); % drop both label and instruction
+split_code([{icode_end_try}|_]=Code, Label, {try_case,_}, Prev, As)
+ when Prev =:= Label ->
+ %% The try_case has been replaced with try_end as an optimization.
+ %% Keep this instruction, since it might be the only try_end instruction
+ %% for this try/catch block.
+ split_code_final(Code, As); % drop label
split_code([Other|_Code], Label, Instr, Prev, _As) when Prev =:= Label ->
?EXIT({missing_instr_after_label, Label, Instr, [Other, Prev | _As]});
split_code([Other|Code], Label, Instr, Prev, As) ->
diff --git a/lib/hipe/icode/hipe_icode.erl b/lib/hipe/icode/hipe_icode.erl
index 24b7ac4783..bc3403b0c5 100644
--- a/lib/hipe/icode/hipe_icode.erl
+++ b/lib/hipe/icode/hipe_icode.erl
@@ -515,10 +515,12 @@
annotate_variable/2, %% annotate_var_or_reg(VarOrReg, Type)
unannotate_variable/1,%% unannotate_var_or_reg(VarOrReg)
mk_reg/1, %% mk_reg(Id)
+ mk_reg_gcsafe/1, %% mk_reg_gcsafe(Id)
mk_fvar/1, %% mk_fvar(Id)
mk_new_var/0, %% mk_new_var()
mk_new_fvar/0, %% mk_new_fvar()
mk_new_reg/0, %% mk_new_reg()
+ mk_new_reg_gcsafe/0, %% mk_new_reg_gcsafe()
mk_phi/1, %% mk_phi(Id)
mk_phi/2 %% mk_phi(Id, ArgList)
]).
@@ -1260,14 +1262,22 @@ is_var(_) -> false.
-spec mk_reg(non_neg_integer()) -> #icode_variable{kind::'reg'}.
mk_reg(V) -> #icode_variable{name=V, kind=reg}.
--spec reg_name(#icode_variable{kind::'reg'}) -> non_neg_integer().
-reg_name(#icode_variable{name=Name, kind=reg}) -> Name.
+-spec mk_reg_gcsafe(non_neg_integer()) -> #icode_variable{kind::'reg_gcsafe'}.
+mk_reg_gcsafe(V) -> #icode_variable{name=V, kind=reg_gcsafe}.
--spec reg_is_gcsafe(#icode_variable{kind::'reg'}) -> 'false'.
-reg_is_gcsafe(#icode_variable{kind=reg}) -> false. % for now
+-spec reg_name(#icode_variable{kind::'reg'|'reg_gcsafe'})
+ -> non_neg_integer().
+reg_name(#icode_variable{name=Name, kind=reg}) -> Name;
+reg_name(#icode_variable{name=Name, kind=reg_gcsafe}) -> Name.
+
+-spec reg_is_gcsafe(#icode_variable{kind::'reg'}) -> 'false';
+ (#icode_variable{kind::'reg_gcsafe'}) -> 'true'.
+reg_is_gcsafe(#icode_variable{kind=reg}) -> false;
+reg_is_gcsafe(#icode_variable{kind=reg_gcsafe}) -> true.
-spec is_reg(icode_argument()) -> boolean().
-is_reg(#icode_variable{kind=reg}) -> true;
+is_reg(#icode_variable{kind=reg}) -> true;
+is_reg(#icode_variable{kind=reg_gcsafe}) -> true;
is_reg(_) -> false.
-spec mk_fvar(non_neg_integer()) -> #icode_variable{kind::'fvar'}.
@@ -1676,6 +1686,16 @@ mk_new_reg() ->
mk_reg(hipe_gensym:get_next_var(icode)).
%%
+%% @doc Makes a new gcsafe register; that is, a register that is allowed to be
+%% live over calls and other operations that might cause GCs and thus move heap
+%% data around.
+%%
+
+-spec mk_new_reg_gcsafe() -> icode_reg().
+mk_new_reg_gcsafe() ->
+ mk_reg_gcsafe(hipe_gensym:get_next_var(icode)).
+
+%%
%% @doc Makes a new label.
%%
diff --git a/lib/hipe/icode/hipe_icode.hrl b/lib/hipe/icode/hipe_icode.hrl
index 380ddd8371..7ed80a9ed4 100644
--- a/lib/hipe/icode/hipe_icode.hrl
+++ b/lib/hipe/icode/hipe_icode.hrl
@@ -41,9 +41,9 @@
-type variable_annotation() :: {atom(), any(), fun((any()) -> string())}.
--record(icode_variable, {name :: non_neg_integer(),
- kind :: 'var' | 'reg' | 'fvar',
- annotation = [] :: [] | variable_annotation()}).
+-record(icode_variable, {name :: non_neg_integer(),
+ kind :: 'var' | 'reg' | 'reg_gcsafe' | 'fvar',
+ annotation = [] :: [] | variable_annotation()}).
%%---------------------------------------------------------------------
%% Type declarations for Icode instructions
@@ -66,7 +66,7 @@
-type icode_funcall() :: mfa() | icode_primop().
-type icode_var() :: #icode_variable{kind::'var'}.
--type icode_reg() :: #icode_variable{kind::'reg'}.
+-type icode_reg() :: #icode_variable{kind::'reg'|'reg_gcsafe'}.
-type icode_fvar() :: #icode_variable{kind::'fvar'}.
-type icode_argument() :: #icode_const{} | #icode_variable{}.
-type icode_term_arg() :: icode_var() | #icode_const{}.
diff --git a/lib/hipe/icode/hipe_icode_inline_bifs.erl b/lib/hipe/icode/hipe_icode_inline_bifs.erl
index 7a6947f190..16a95991e7 100644
--- a/lib/hipe/icode/hipe_icode_inline_bifs.erl
+++ b/lib/hipe/icode/hipe_icode_inline_bifs.erl
@@ -24,8 +24,9 @@
%% Currently inlined BIFs:
%% and, or, xor, not, <, >, >=, =<, ==, /=, =/=, =:=
-%% is_atom, is_boolean, is_binary, is_float, is_function,
-%% is_integer, is_list, is_pid, is_port, is_reference, is_tuple
+%% is_atom, is_binary, is_bitstring, is_boolean, is_float,
+%% is_function, is_integer, is_list, is_map, is_number,
+%% is_pid, is_port, is_reference, is_tuple
-module(hipe_icode_inline_bifs).
@@ -116,17 +117,20 @@ try_type_tests(I) -> I.
is_type_test(Name) ->
case Name of
- is_integer -> {true, integer};
+ is_atom -> {true, atom};
+ is_binary -> {true, binary};
+ is_bitstring -> {true, bitstr};
+ is_boolean -> {true, boolean};
is_float -> {true, float};
- is_tuple -> {true, tuple};
- is_binary -> {true, binary};
+ is_function -> {true, function};
+ is_integer -> {true, integer};
is_list -> {true, list};
+ is_map -> {true, map};
+ is_number -> {true, number};
is_pid -> {true, pid};
- is_atom -> {true, atom};
- is_boolean -> {true, boolean};
- is_function -> {true, function};
- is_reference -> {true, reference};
is_port -> {true, port};
+ is_reference -> {true, reference};
+ is_tuple -> {true, tuple};
_ -> false
end.
diff --git a/lib/hipe/icode/hipe_icode_liveness.erl b/lib/hipe/icode/hipe_icode_liveness.erl
index 51e2855108..e61529a1bb 100644
--- a/lib/hipe/icode/hipe_icode_liveness.erl
+++ b/lib/hipe/icode/hipe_icode_liveness.erl
@@ -77,6 +77,7 @@ print_var(#icode_variable{name=V, kind=Kind, annotation=T}) ->
case Kind of
var -> io:format("v~p", [V]);
reg -> io:format("r~p", [V]);
+ reg_gcsafe -> io:format("rs~p", [V]);
fvar -> io:format("fv~p", [V])
end,
case T of
diff --git a/lib/hipe/icode/hipe_icode_pp.erl b/lib/hipe/icode/hipe_icode_pp.erl
index 5b017dca32..33d1e62884 100644
--- a/lib/hipe/icode/hipe_icode_pp.erl
+++ b/lib/hipe/icode/hipe_icode_pp.erl
@@ -230,7 +230,10 @@ pp_arg(Dev, Arg) ->
case hipe_icode:is_reg(Arg) of
true ->
N = hipe_icode:reg_name(Arg),
- io:format(Dev, "r~p", [N]);
+ case hipe_icode:reg_is_gcsafe(Arg) of
+ true -> io:format(Dev, "rs~p", [N]);
+ false -> io:format(Dev, "r~p", [N])
+ end;
false ->
N = hipe_icode:fvar_name(Arg),
io:format(Dev, "fv~p", [N])
diff --git a/lib/hipe/icode/hipe_icode_primops.erl b/lib/hipe/icode/hipe_icode_primops.erl
index 50ece05259..a1f1128124 100644
--- a/lib/hipe/icode/hipe_icode_primops.erl
+++ b/lib/hipe/icode/hipe_icode_primops.erl
@@ -67,6 +67,8 @@ is_safe(fp_mul) -> false;
is_safe(fp_sub) -> false;
is_safe(mktuple) -> true;
is_safe(next_msg) -> false;
+is_safe(recv_mark) -> false;
+is_safe(recv_set) -> false;
is_safe(redtest) -> false;
is_safe(select_msg) -> false;
is_safe(self) -> true;
@@ -130,6 +132,7 @@ is_safe({hipe_bs_primop, {bs_match_string, _, _}}) -> false;
is_safe({hipe_bs_primop, {bs_append, _, _, _, _}}) -> false;
is_safe({hipe_bs_primop, {bs_private_append, _, _}}) -> false;
is_safe({hipe_bs_primop, bs_init_writable}) -> true;
+is_safe(build_stacktrace) -> true;
is_safe(#mkfun{}) -> true;
is_safe(#unsafe_element{}) -> true;
is_safe(#unsafe_update_element{}) -> true;
@@ -165,6 +168,8 @@ fails(fp_mul) -> false;
fails(fp_sub) -> false;
fails(mktuple) -> false;
fails(next_msg) -> false;
+fails(recv_mark) -> false;
+fails(recv_set) -> false;
fails(redtest) -> false;
fails(select_msg) -> false;
fails(self) -> false;
@@ -230,6 +235,8 @@ fails({hipe_bs_primop, bs_final}) -> false;
fails({hipe_bs_primop, {bs_append, _, _, _, _}}) -> true;
fails({hipe_bs_primop, {bs_private_append, _, _}}) -> true;
fails({hipe_bs_primop, bs_init_writable}) -> true;
+fails(build_stacktrace) -> false;
+fails(raw_raise) -> true;
fails(#mkfun{}) -> false;
fails(#unsafe_element{}) -> false;
fails(#unsafe_update_element{}) -> false;
@@ -709,6 +716,10 @@ type(Primop, Args) ->
erl_types:t_any();
next_msg ->
erl_types:t_any();
+ recv_mark ->
+ erl_types:t_any();
+ recv_set ->
+ erl_types:t_any();
select_msg ->
erl_types:t_any();
set_timeout ->
@@ -723,6 +734,10 @@ type(Primop, Args) ->
erl_types:t_any();
debug_native_called ->
erl_types:t_any();
+ build_stacktrace ->
+ erl_types:t_list();
+ raw_raise ->
+ erl_types:t_atom();
{M, F, A} ->
erl_bif_types:type(M, F, A, Args)
end.
@@ -883,6 +898,10 @@ type(Primop) ->
erl_types:t_any();
next_msg ->
erl_types:t_any();
+ recv_mark ->
+ erl_types:t_any();
+ recv_set ->
+ erl_types:t_any();
select_msg ->
erl_types:t_any();
set_timeout ->
@@ -891,6 +910,10 @@ type(Primop) ->
erl_types:t_any();
%%% -----------------------------------------------------
%%% Other
+ build_stacktrace ->
+ erl_types:t_any();
+ raw_raise ->
+ erl_types:t_any();
#closure_element{} ->
erl_types:t_any();
redtest ->
diff --git a/lib/hipe/icode/hipe_icode_range.erl b/lib/hipe/icode/hipe_icode_range.erl
index 287b1c80fe..098a7a8d8c 100644
--- a/lib/hipe/icode/hipe_icode_range.erl
+++ b/lib/hipe/icode/hipe_icode_range.erl
@@ -1160,6 +1160,8 @@ basic_type(#gc_test{}) -> not_analysed;
%% Message handling
basic_type(check_get_msg) -> not_analysed;
basic_type(next_msg) -> not_analysed;
+basic_type(recv_mark) -> not_analysed;
+basic_type(recv_set) -> not_analysed;
basic_type(select_msg) -> not_analysed;
basic_type(suspend_msg) -> not_analysed;
%% Functions
@@ -1184,7 +1186,9 @@ basic_type(unsafe_hd) -> not_analysed;
basic_type(unsafe_tl) -> not_int;
basic_type(#element{}) -> not_analysed;
basic_type(#unsafe_element{}) -> not_analysed;
-basic_type(#unsafe_update_element{}) -> not_analysed.
+basic_type(#unsafe_update_element{}) -> not_analysed;
+basic_type(build_stacktrace) -> not_int;
+basic_type(raw_raise) -> not_int.
-spec analyse_bs_get_integer(integer(), integer(), boolean()) -> range_tuple().
@@ -1629,7 +1633,7 @@ inf_bsl(_, pos_inf) -> neg_inf;
inf_bsl(Number, neg_inf) when is_integer(Number), Number >= 0 -> 0;
inf_bsl(_Number, neg_inf) -> -1;
inf_bsl(Number1, Number2) when is_integer(Number1), is_integer(Number2) ->
- %% We can not shift left with a number which is not a fixnum. We
+ %% We cannot shift left with a number which is not a fixnum. We
%% don't have enough memory.
Bits = ?BITS,
if Number2 > (Bits bsl 1) -> inf_bsl(Number1, pos_inf);
diff --git a/lib/hipe/llvm/Makefile b/lib/hipe/llvm/Makefile
index 817ff67dcd..9f7a2def6d 100644
--- a/lib/hipe/llvm/Makefile
+++ b/lib/hipe/llvm/Makefile
@@ -70,7 +70,10 @@ TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
include ../native.mk
-ERL_COMPILE_FLAGS += -Werror +inline +warn_export_vars #+warn_missing_spec
+ERL_COMPILE_FLAGS += +inline +warn_export_vars #+warn_missing_spec
+ifneq ($(NATIVE_LIBS_ENABLED),yes)
+ERL_COMPILE_FLAGS += -Werror
+endif
# if in 32 bit backend define BIT32 symbol
ifneq ($(BITS64),yes)
diff --git a/lib/hipe/llvm/hipe_llvm.erl b/lib/hipe/llvm/hipe_llvm.erl
index e04b171194..343ca94cb1 100644
--- a/lib/hipe/llvm/hipe_llvm.erl
+++ b/lib/hipe/llvm/hipe_llvm.erl
@@ -1005,11 +1005,12 @@ pp_ins(Dev, Ver, I) ->
write(Dev, [" ", adj_stack_offset(I),")\n"]);
#llvm_meta{} ->
write(Dev, ["!", meta_id(I), " = !{ "]),
- write(Dev, string:join([if is_list(Op) -> ["!\"", Op, "\""];
- is_integer(Op) -> ["i32 ", integer_to_list(Op)];
- is_record(Op, llvm_meta) ->
- ["!", meta_id(Op)]
- end || Op <- meta_operands(I)], ", ")),
+ write(Dev, lists:join(", ",
+ [if is_list(Op) -> ["!\"", Op, "\""];
+ is_integer(Op) -> ["i32 ", integer_to_list(Op)];
+ is_record(Op, llvm_meta) ->
+ ["!", meta_id(Op)]
+ end || Op <- meta_operands(I)])),
write(Dev, " }\n");
Other ->
exit({?MODULE, pp_ins, {"Unknown LLVM instruction", Other}})
diff --git a/lib/hipe/llvm/hipe_llvm_main.erl b/lib/hipe/llvm/hipe_llvm_main.erl
index 4eec0c752b..44f0566379 100644
--- a/lib/hipe/llvm/hipe_llvm_main.erl
+++ b/lib/hipe/llvm/hipe_llvm_main.erl
@@ -154,7 +154,7 @@ compiler_target_opt() ->
%% @doc Join options.
fix_opts(Opts) ->
- string:join(Opts, " ").
+ lists:flatten(lists:join(" ", Opts)).
%% @doc Translate optimization-level flag (default is "O2").
trans_optlev_flag(Tool, Options) ->
@@ -526,8 +526,8 @@ unique_folder(FunName, Arity, Options) ->
case proplists:get_bool(llvm_save_temps, Options) of
true -> %% Store folder in current directory
DirName;
- false -> %% Temporarily store folder in tempfs (/dev/shm/)
- "/dev/shm/" ++ DirName
+ false -> %% Temporarily store folder in tempfs or tmp dir
+ tmpfs_folder() ++ DirName
end,
%% Make sure it does not exist
case dir_exists(Dir) of
@@ -537,6 +537,14 @@ unique_folder(FunName, Arity, Options) ->
Dir
end.
+tmpfs_folder() ->
+ case os:type() of
+ {unix, linux} ->
+ "/dev/shm/";
+ {unix, _} -> %% Fallback to tmp dir. e.g. FreeBSD
+ "/tmp/"
+ end.
+
%% @doc Function that checks that a given Filename is an existing Directory
%% Name (from http://rosettacode.org/wiki/Ensure_that_a_file_exists#Erlang)
dir_exists(Filename) ->
diff --git a/lib/hipe/llvm/hipe_rtl_to_llvm.erl b/lib/hipe/llvm/hipe_rtl_to_llvm.erl
index 79e1bfd381..934717efc1 100644
--- a/lib/hipe/llvm/hipe_rtl_to_llvm.erl
+++ b/lib/hipe/llvm/hipe_rtl_to_llvm.erl
@@ -1537,7 +1537,7 @@ declare_switch_table({Name, {switch, {TableType, Labels, _, _}, _}}, FunName) ->
LabelList = [mk_jump_label(L) || L <- Labels],
Fun1 = fun(X) -> "i8* blockaddress(@" ++ FunName ++ ", " ++ X ++ ")" end,
List2 = lists:map(Fun1, LabelList),
- List3 = string:join(List2, ",\n"),
+ List3 = lists:flatten(lists:join(",\n", List2)),
List4 = "[\n" ++ List3 ++ "\n]\n",
hipe_llvm:mk_const_decl("@" ++ Name, "constant", TableType, List4).
@@ -1553,7 +1553,7 @@ declare_closure_labels(ClosureLabels, Relocs, Fun) ->
Relocs1 = relocs_store("table_closures", {table_closures, ArityList}, Relocs),
List2 =
["i8* blockaddress(@" ++ FunName ++ ", " ++ L ++ ")" || L <- LabelList],
- List3 = string:join(List2, ",\n"),
+ List3 = lists:flatten(lists:join(",\n", List2)),
List4 = "[\n" ++ List3 ++ "\n]\n",
NrLabels = length(LabelList),
ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(?BITS_IN_BYTE)),
diff --git a/lib/hipe/main/hipe.app.src b/lib/hipe/main/hipe.app.src
index eef4b9a34f..4684ab49ea 100644
--- a/lib/hipe/main/hipe.app.src
+++ b/lib/hipe/main/hipe.app.src
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,7 +26,6 @@
cerl_closurean,
cerl_hipeify,
cerl_lib,
- cerl_messagean,
cerl_pmatch,
cerl_prettypr,
cerl_to_icode,
@@ -179,6 +178,7 @@
hipe_rtl_to_sparc,
hipe_rtl_to_x86,
hipe_rtl_varmap,
+ hipe_rtl_verify_gcsafe,
hipe_segment_trees,
hipe_sdi,
hipe_sparc,
diff --git a/lib/hipe/main/hipe.erl b/lib/hipe/main/hipe.erl
index 19b4e8bfe2..094b7bc508 100644
--- a/lib/hipe/main/hipe.erl
+++ b/lib/hipe/main/hipe.erl
@@ -196,7 +196,7 @@
file/1,
file/2,
get_llvm_version/0,
- llvm_support_available/0,
+ erllvm_is_supported/0,
load/1,
help/0,
help_hiper/0,
@@ -218,12 +218,11 @@
%% Basic type declaration for exported functions of the 'hipe' module
%%-------------------------------------------------------------------
--type mod() :: atom().
--type f_unit() :: mod() | binary().
+-type mod() :: module().
+-type file_or_bin() :: file:filename() | binary().
-type ret_rtl() :: [_].
-type c_ret() :: {'ok', mod()} | {'error', term()} |
{'ok', mod(), ret_rtl()}. %% The last for debugging only
--type compile_file() :: atom() | string() | binary().
-type compile_ret() :: {hipe_architecture(), binary()} | list().
%%-------------------------------------------------------------------
@@ -233,26 +232,26 @@
%%-------------------------------------------------------------------
-%% @spec load(Mod) -> {module, Mod} | {error, Reason}
-%% Mod = mod()
+%% @spec load(Module) -> {module, Module} | {error, Reason}
+%% Module = mod()
%% Reason = term()
%%
%% @doc Like load/2, but tries to locate a BEAM file automatically.
%%
%% @see load/2
--spec load(Mod) -> {'module', Mod} | {'error', term()} when Mod :: mod().
+-spec load(Module) -> {'module', Module} | {'error', Reason :: term()}
+ when Module :: mod().
-load(Mod) ->
- load(Mod, beam_file(Mod)).
+load(Module) ->
+ load(Module, beam_file(Module)).
-%% @spec load(Mod, BeamFileName) -> {module, Mod} | {error, Reason}
-%% Mod = mod()
+%% @spec load(Module, BeamFileName) -> {module, Module} | {error, Reason}
+%% Module = mod()
+%% BeamFileName = file:filename()
%% Reason = term()
-%% BeamFileName = string()
-%% filename() = term()
%%
-%% @type mod() = atom(). A module name.
+%% @type mod() = module(). A module name.
%%
%% @doc User interface for loading code into memory. The code can be
%% given as a native code binary or as the file name of a BEAM file
@@ -262,8 +261,8 @@ load(Mod) ->
%%
%% @see load/1
--spec load(Mod, string()) -> {'module', Mod} | {'error', term()}
- when Mod :: mod().
+-spec load(Module, file:filename()) -> {'module', Module} | {'error', term()}
+ when Module :: mod().
load(Mod, BeamFileName) when is_list(BeamFileName) ->
Architecture = erlang:system_info(hipe_architecture),
@@ -273,26 +272,22 @@ load(Mod, BeamFileName) when is_list(BeamFileName) ->
Error -> {error, Error}
end.
-%% @spec c(Name) -> {ok, Name} | {error, Reason}
-%% Name = mod()
+%% @spec c(Mod) -> {ok, Mod} | {error, Reason}
+%% Mod = mod()
%% Reason = term()
%%
-%% @equiv c(Name, [])
+%% @equiv c(Mod, [])
-spec c(mod()) -> c_ret().
-c(Name) ->
- c(Name, []).
+c(Mod) ->
+ c(Mod, []).
-%% @spec c(Name, options()) -> {ok, Name} | {error, Reason}
-%% Name = mod()
+%% @spec c(Module, options()) -> {ok, Module} | {error, Reason}
+%% Module = mod()
%% options() = [option()]
%% option() = term()
%% Reason = term()
-%%
-%% @type fun() = atom(). A function identifier.
-%%
-%% @type arity() = integer(). A function arity; always nonnegative.
%%
%% @doc User-friendly native code compiler interface. Reads BEAM code
%% from the corresponding "Module<code>.beam</code>" file in the
@@ -307,12 +302,12 @@ c(Name) ->
-spec c(mod(), comp_options()) -> c_ret().
-c(Name, Options) ->
- c(Name, beam_file(Name), Options).
+c(Module, Options) ->
+ c(Module, beam_file(Module), Options).
-%% @spec c(Name, File, options()) -> {ok, Name} | {error, Reason}
-%% Name = mod()
-%% File = filename() | binary()
+%% @spec c(Module, File, options()) -> {ok, Module} | {error, Reason}
+%% Module = mod()
+%% File = file:filename() | binary()
%% Reason = term()
%%
%% @doc Like <code>c/2</code>, but reads BEAM code from the specified
@@ -321,32 +316,32 @@ c(Name, Options) ->
%% @see c/2
%% @see f/2
-c(Name, File, Opts) ->
+c(Module, File, Opts) ->
Opts1 = user_compile_opts(Opts),
- case compile(Name, File, Opts1) of
+ case compile(Module, File, Opts1) of
{ok, Res} ->
case proplists:get_bool(to_rtl, Opts1) of
- true -> {ok, Name, Res};
- false -> {ok, Name}
+ true -> {ok, Module, Res};
+ false -> {ok, Module}
end;
Other ->
Other
end.
%% @spec f(File) -> {ok, Name} | {error, Reason}
-%% File = filename() | binary()
+%% File = file:filename() | binary()
%% Name = mod()
%% Reason = term()
%%
%% @equiv f(File, [])
--spec f(f_unit()) -> {'ok', mod()} | {'error', term()}.
+-spec f(file_or_bin()) -> {'ok', mod()} | {'error', term()}.
f(File) ->
f(File, []).
%% @spec f(File, options()) -> {ok, Name} | {error, Reason}
-%% File = filename() | binary()
+%% File = file:filename() | binary()
%% Name = mod()
%% Reason = term()
%%
@@ -355,7 +350,7 @@ f(File) ->
%%
%% @see c/3
--spec f(f_unit(), comp_options()) -> {'ok', mod()} | {'error', term()}.
+-spec f(file_or_bin(), comp_options()) -> {'ok', mod()} | {'error', term()}.
f(File, Opts) ->
case file(File, user_compile_opts(Opts)) of
@@ -371,20 +366,20 @@ user_compile_opts(Opts) ->
Opts ++ ?USER_DEFAULTS.
-%% @spec compile(Name) -> {ok, {Target,Binary}} | {error, Reason}
-%% Name = mod()
+%% @spec compile(Module) -> {ok, {Target,Binary}} | {error, Reason}
+%% Module = mod()
%% Binary = binary()
%% Reason = term()
%%
-%% @equiv compile(Name, [])
+%% @equiv compile(Module, [])
-spec compile(mod()) -> {'ok', compile_ret()} | {'error', term()}.
-compile(Name) ->
- compile(Name, []).
+compile(Module) ->
+ compile(Module, []).
-%% @spec compile(Name, options()) -> {ok, {Target,Binary}} | {error, Reason}
-%% Name = mod()
+%% @spec compile(Module, options()) -> {ok, {Target,Binary}} | {error, Reason}
+%% Module = mod()
%% Binary = binary()
%% Reason = term()
%%
@@ -403,26 +398,26 @@ compile(Name) ->
%% @see file/2
%% @see load/2
--spec compile(mod(), comp_options()) -> {'ok', compile_ret()} | {'error', _}.
+-spec compile(mod(), comp_options()) -> {'ok', compile_ret()} | {'error', term()}.
-compile(Name, Options) ->
- compile(Name, beam_file(Name), Options).
+compile(Module, Options) ->
+ compile(Module, beam_file(Module), Options).
--spec beam_file(mod()) -> string().
+-spec beam_file(mod()) -> file:filename().
beam_file(Module) when is_atom(Module) ->
case code:which(Module) of
non_existing ->
- ?error_msg("Cannot find ~w.beam file.",[Module]),
+ ?error_msg("Cannot find ~w.beam file.", [Module]),
?EXIT({cant_find_beam_file,Module});
- File -> % string()
+ File when is_list(File) ->
File
end.
%% @spec compile(Name, File, options()) ->
%% {ok, {Target, Binary}} | {error, Reason}
%% Name = mod()
-%% File = filename() | binary()
+%% File = file:filename() | binary()
%% Binary = binary()
%% Reason = term()
%%
@@ -431,7 +426,7 @@ beam_file(Module) when is_atom(Module) ->
%%
%% @see compile/2
--spec compile(mod(), compile_file(), comp_options()) ->
+-spec compile(mod(), file_or_bin(), comp_options()) ->
{'ok', compile_ret()} | {'error', term()}.
compile(Name, File, Opts0) when is_atom(Name) ->
@@ -475,18 +470,18 @@ compile(Name, File, Opts0) when is_atom(Name) ->
run_compiler(Name, DisasmFun, IcodeFun, Opts)
end.
--spec compile_core(mod(), cerl:c_module(), compile_file(), comp_options()) ->
+-spec compile_core(mod(), cerl:c_module(), file_or_bin(), comp_options()) ->
{'ok', compile_ret()} | {'error', term()}.
compile_core(Name, Core0, File, Opts) ->
Core = cerl:from_records(Core0),
compile(Name, Core, File, Opts).
-%% @spec compile(Name, Core, File, options()) ->
+%% @spec compile(Module, Core, File, options()) ->
%% {ok, {Target, Binary}} | {error, Reason}
-%% Name = mod()
+%% Module = mod()
%% Core = coreErlang() | []
-%% File = filename() | binary()
+%% File = file:filename() | binary()
%% Binary = binary()
%% Reason = term()
%%
@@ -499,7 +494,7 @@ compile_core(Name, Core0, File, Opts) ->
%%
%% @see compile/3
--spec compile(mod(), cerl:c_module() | [], compile_file(), comp_options()) ->
+-spec compile(mod(), cerl:c_module() | [], file_or_bin(), comp_options()) ->
{'ok', compile_ret()} | {'error', term()}.
compile(Name, [], File, Opts) ->
@@ -511,37 +506,35 @@ compile(Name, Core, File, Opts) when is_atom(Name) ->
end,
run_compiler(Name, DisasmFun, IcodeFun, Opts).
-%% @spec file(File) -> {ok, Name, {Target, Binary}} | {error, Reason}
-%% File = filename() | binary()
-%% Name = mod() | mfa()
+%% @spec file(File) -> {ok, Mod, {Target, Binary}} | {error, Reason}
+%% File = file:filename()
+%% Mod = mod()
%% Binary = binary()
%% Reason = term()
%%
%% @equiv file(File, [])
--spec file(Mod) -> {'ok', Mod, compile_ret()} | {'error', term()}
- when Mod :: mod().
+-spec file(file:filename()) -> {'ok', mod(), compile_ret()} | {'error', term()}.
file(File) ->
file(File, []).
-%% @spec file(File, options()) -> {ok, Name, {Target,Binary}} | {error, Reason}
-%% File = filename()
-%% Name = mod() | mfa()
+%% @spec file(File, options()) -> {ok, Mod, {Target, Binary}} | {error, Reason}
+%% File = file:filename()
+%% Mod = mod()
%% Binary = binary()
%% Reason = term()
%%
%% @doc Like <code>compile/2</code>, but takes the module name from the
-%% specified <code>File</code>. Returns both the name and the final
+%% specified <code>File</code>. Returns both the module name and the final
%% binary if successful.
%%
%% @see file/1
%% @see compile/2
--spec file(Mod, comp_options()) -> {'ok', Mod, compile_ret()}
- | {'error', term()}
- when Mod :: mod().
-file(File, Options) when is_atom(File) ->
+-spec file(file:filename(), comp_options()) -> {'ok', mod(), compile_ret()}
+ | {'error', Reason :: term()}.
+file(File, Options) when is_list(File) ->
case beam_lib:info(File) of
L when is_list(L) ->
{module, Mod} = lists:keyfind(module, 1, L),
@@ -590,9 +583,8 @@ fix_beam_exports([], Exports) ->
Exports.
get_beam_icode(Mod, {BeamCode, Exports}, File, Options) ->
- {ok, Icode} =
- ?option_time((catch {ok, hipe_beam_to_icode:module(BeamCode, Options)}),
- "BEAM-to-Icode", Options),
+ Icode = ?option_time(hipe_beam_to_icode:module(BeamCode, Options),
+ "BEAM-to-Icode", Options),
BeamBin = get_beam_code(File),
{{Mod, Exports, Icode}, BeamBin}.
@@ -653,7 +645,7 @@ run_compiler_1(Name, DisasmFun, IcodeFun, Options) ->
get(hipe_target_arch)),
Opts =
case proplists:get_bool(to_llvm, Opts0) andalso
- not llvm_support_available() of
+ not llvm_version_is_OK() of
true ->
?error_msg("No LLVM version 3.9 or greater "
"found in $PATH; aborting "
@@ -669,9 +661,12 @@ run_compiler_1(Name, DisasmFun, IcodeFun, Options) ->
{Icode, WholeModule} = IcodeFun(Code, Opts),
CompRes = compile_finish(Icode, WholeModule, Opts),
compiler_return(CompRes, Parent)
- catch error:Error ->
- print_crash_message(Name, Error),
- exit(Error)
+ catch
+ error:Error:StackTrace ->
+ print_crash_message(Name, Error, StackTrace),
+ exit(Error);
+ throw:{unimplemented_instruction,_Instruction}=Error ->
+ exit(Error)
end
end),
Timeout = case proplists:get_value(timeout, Options) of
@@ -757,8 +752,8 @@ finalize(OrigList, Mod, Exports, WholeModule, Opts) ->
TargetArch = get(hipe_target_arch),
{ok, {TargetArch,Bin}}
catch
- error:Error ->
- {error,Error,erlang:get_stacktrace()}
+ error:Error:StackTrace ->
+ {error,Error,StackTrace}
end
end.
@@ -843,17 +838,17 @@ finalize_fun_sequential({MFA, Icode}, Opts, Servers) ->
{llvm_binary, Binary} ->
{MFA, Binary}
catch
- error:Error ->
+ error:Error:StackTrace ->
?when_option(verbose, Opts, ?debug_untagged_msg("\n", [])),
- print_crash_message(MFA, Error),
+ print_crash_message(MFA, Error, StackTrace),
exit(Error)
end.
-print_crash_message(What, Error) ->
+print_crash_message(What, Error, StackTrace) ->
StackFun = fun(_,_,_) -> false end,
FormatFun = fun (Term, _) -> io_lib:format("~p", [Term]) end,
- StackTrace = lib:format_stacktrace(1, erlang:get_stacktrace(),
- StackFun, FormatFun),
+ StackTraceS = erl_error:format_stacktrace(1, StackTrace,
+ StackFun, FormatFun),
WhatS = case What of
{M,F,A} -> io_lib:format("~w:~w/~w", [M,F,A]);
Mod -> io_lib:format("~w", [Mod])
@@ -862,7 +857,7 @@ print_crash_message(What, Error) ->
"while compiling ~s~n"
"crash reason: ~p~n"
"~s~n",
- [WhatS, Error, StackTrace]).
+ [WhatS, Error, StackTraceS]).
pp_server_start(Opts) ->
set_architecture(Opts),
@@ -1414,6 +1409,7 @@ opt_keys() ->
use_clusters,
use_jumptable,
verbose,
+ verify_gcsafe,
%% verbose_spills,
x87].
@@ -1510,7 +1506,8 @@ opt_negations() ->
{no_use_callgraph, use_callgraph},
{no_use_clusters, use_clusters},
{no_use_inline_atom_search, use_inline_atom_search},
- {no_use_indexing, use_indexing}].
+ {no_use_indexing, use_indexing},
+ {no_verify_gcsafe, verify_gcsafe}].
%% Don't use negative forms in right-hand sides of aliases and expansions!
%% We only expand negations once, before the other expansions are done.
@@ -1605,9 +1602,15 @@ check_options(Opts) ->
ok
end.
--spec llvm_support_available() -> boolean().
+-spec erllvm_is_supported() -> boolean().
+erllvm_is_supported() ->
+ %% XXX: The test should really check the _target_ architecture,
+ %% (hipe_target_arch), but there's no guarantee it's set.
+ Arch = erlang:system_info(hipe_architecture),
+ lists:member(Arch, [amd64, x86]) andalso llvm_version_is_OK().
-llvm_support_available() ->
+-spec llvm_version_is_OK() -> boolean().
+llvm_version_is_OK() ->
get_llvm_version() >= {3,9}.
-type llvm_version() :: {Major :: integer(), Minor :: integer()}.
@@ -1616,11 +1619,11 @@ llvm_support_available() ->
get_llvm_version() ->
OptStr = os:cmd("opt -version"),
SubStr = "LLVM version ", N = length(SubStr),
- case string:str(OptStr, SubStr) of
- 0 -> % No opt available
+ case string:find(OptStr, SubStr) of
+ nomatch -> % No opt available
{0, 0};
S ->
- case string:tokens(string:sub_string(OptStr, S + N), ".") of
+ case string:lexemes(string:slice(S, N), ".") of
[MajorS, MinorS | _] ->
case {string:to_integer(MajorS), string:to_integer(MinorS)} of
{{Major, ""}, {Minor, _}}
diff --git a/lib/hipe/main/hipe_main.erl b/lib/hipe/main/hipe_main.erl
index dca6fddec3..6e48f0cffd 100644
--- a/lib/hipe/main/hipe_main.erl
+++ b/lib/hipe/main/hipe_main.erl
@@ -410,6 +410,11 @@ icode_to_rtl(MFA, Icode, Options, Servers) ->
hipe_llvm_liveness:analyze(RtlCfg4)
end,
pp(RtlCfg5, MFA, rtl, pp_rtl, Options, Servers),
+ case proplists:get_bool(no_verify_gcsafe, Options) of
+ true -> ok;
+ false ->
+ ok = hipe_rtl_verify_gcsafe:check(RtlCfg5)
+ end,
LinearRTL1 = hipe_rtl_cfg:linearize(RtlCfg5),
LinearRTL2 = hipe_rtl_cleanup_const:cleanup(LinearRTL1),
%% hipe_rtl:pp(standard_io, LinearRTL2),
diff --git a/lib/hipe/opt/hipe_schedule.erl b/lib/hipe/opt/hipe_schedule.erl
deleted file mode 100644
index 0f25940e3d..0000000000
--- a/lib/hipe/opt/hipe_schedule.erl
+++ /dev/null
@@ -1,1483 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% INSTRUCTION SCHEDULER
-%%
-%% This is a basic ILP cycle scheduler:
-%% * set cycle = 0
-%% * while ready[cycle] nonempty do
-%% - take x with greatest priority from ready[cycle]
-%% - try to schedule x;
-%% * if scheduling x was possible,
-%% - reserve resources
-%% - add x to schedule and delete x from dag
-%% - update earliest-time for all successor nodes
-%% as max[earliest[y],cycle+latency[x]]
-%% - if some node y now has no predecessors,
-%% add y to ready[earliest[y]]
-%% * if it was impossible, put x in ready[cycle+1]
-%% (= try again)
-%%
-%% We use the following data structures:
-%% 1. all nodes are numbered and indices used as array keys
-%% 2. priority per node can be computed statically or dynamically
-%% * statically: before scheduling, each node gets a priority value
-%% * dynamically: at each cycle, compute priorities for all ready nodes
-%% 3. earliest: earliest cycle of issue, starts at 0
-%% and is updated as predecessors issue
-%% 4. predecessors: number of predecessors (0 = ready to issue)
-%% 5. successors: list of {Latency,NodeID}
-%% 6. ready: an array indexed by cycle-time (integer), where
-%% ready nodes are kept.
-%% 7. resources: a resource representation (ADT) that answers
-%% certain queries, e.g., "can x be scheduled this cycle"
-%% and "reserve resources for x".
-%% 8. schedule: list of scheduled instructions {Instr,Cycle}
-%% in the order of issue
-%% 9. instructions: maps IDs back to instructions
-%%
-%% Inputs:
-%% - a list of {ID,Node} pairs (where ID is a unique key)
-%% - a dependence list {ID0,Latency,ID1}, which is used to
-%% build the DAG.
-%%
-%% Note that there is some leeway in how things are represented
-%% from here.
-%%
-%% MODIFICATIONS:
-%% - Some basic blocks are not worth scheduling (e.g., GC save/restore code)
-%% yet are pretty voluminous. How do we skip them?
-%% - Scheduling should be done at finalization time: when basic block is
-%% linearized and is definitely at Sparc assembly level, THEN reorder
-%% stuff.
-
--module(hipe_schedule).
--export([cfg/1, est_cfg/1, delete_node/5]).
-
--include("../sparc/hipe_sparc.hrl").
-
-%%-define(debug1,true).
-
--define(debug2(Str,Args),ok).
-%%-define(debug2(Str,Args),io:format(Str,Args)).
-
--define(debug3(Str,Args),ok).
-%%-define(debug3(Str,Args),io:format(Str,Args)).
-
--define(debug4(Str,Args),ok).
-%%-define(debug4(Str,Args),io:format(Str,Args)).
-
--define(debug5(Str,Args),ok).
-%%-define(debug5(Str,Args),io:format(Str,Args)).
-
--define(debug(Str,Args),ok).
-%%-define(debug(Str,Args),io:format(Str,Args)).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : cfg
-%% Argument : CFG - the control flow graph
-%% Returns : CFG - A new cfg with scheduled blocks
-%% Description : Takes each basic block and schedules them one by one.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-cfg(CFG) ->
- ?debug3("CFG: ~n~p", [CFG]),
- update_all( [ {L,
- hipe_bb:mk_bb(
- block(L,hipe_bb:code(hipe_sparc_cfg:bb(CFG,L))) )}
- || L <- hipe_sparc_cfg:labels(CFG) ], CFG).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : update_all
-%% Argument : Blocks - [{Label, Block}] , a list with labels and new code
-%% used for updating the old CFG.
-%% CFG - The old controlflow graph
-%% Returns : An updated controlflow graph.
-%% Description : Just swappes the basic blocks in the CFG to the scheduled one.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-update_all([],CFG) -> CFG;
-update_all([{L,NewB}|Ls],CFG) ->
- update_all(Ls,hipe_sparc_cfg:bb_add(CFG,L,NewB)).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-est_cfg(CFG) ->
- update_all([ {L, hipe_bb:mk_bb(est_block(hipe_bb:code(hipe_sparc_cfg:bb(CFG,L))))}
- || L <- hipe_sparc_cfg:labels(CFG) ], CFG).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Provides an estimation of how quickly a block will execute.
-%% This is done by chaining all instructions in sequential order
-%% by 0-cycle dependences (which means they will never be reordered),
-%% then scheduling the mess.
-
-est_block([]) -> [];
-est_block([I]) -> [I];
-est_block(Blk) ->
- {IxBlk,DAG} = est_deps(Blk),
- Sch = bb(IxBlk,DAG),
- separate_block(Sch,IxBlk).
-
-est_deps(Blk) ->
- IxBlk = indexed_bb(Blk),
- DAG = deps(IxBlk),
- {IxBlk, chain_instrs(IxBlk,DAG)}.
-
-chain_instrs([{N,_}|Xs],DAG) ->
- chain_i(N,Xs,DAG).
-
-chain_i(_,[],DAG) -> DAG;
-chain_i(N,[{M,_}|Xs],DAG) ->
- NewDAG = dep_arc(N,zero_latency(),M,DAG),
- chain_i(M,Xs,NewDAG).
-
-zero_latency() -> 0.
-
-lookup_instr([{N,I}|_], N) -> I;
-lookup_instr([_|Xs], N) -> lookup_instr(Xs, N).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : block
-%% Argument : Instrs - [Instr], list of all the instructions in a basic
-%% block.
-%% Returns : A new scheduled block
-%% Description : Schedule a basic block
-%%
-%% Note: does not consider delay slots!
-%% (another argument for using only annulled delay slots?)
-%% * how do we add delay slots? somewhat tricky to
-%% reconcile with the sort of scheduling we consider.
-%% (as-early-as-possible)
-%% => rewrite scheduler into as-late-as-possible?
-%% (=> just reverse the dependence arcs??)
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%% Don't fire up the scheduler if there's no work to do.
-block(_, []) ->
- [];
-block(_L, [I]) ->
- case hipe_sparc:is_any_branch(I) of
- true -> [hipe_sparc:nop_create(), I];
- false -> [I]
- end;
-block(_L, Blk) ->
- IxBlk = indexed_bb(Blk),
- case IxBlk of
- [{_N, I}] -> % comments and nops may have been removed.
- case hipe_sparc:is_any_branch(I) of
- true -> [hipe_sparc:nop_create(), I];
- false -> [I]
- end;
- _ ->
- Sch = bb(IxBlk, {DAG, _Preds} = deps(IxBlk)),
- {NewSch, NewIxBlk} = fill_delays(Sch, IxBlk, DAG),
- X = finalize_block(NewSch, NewIxBlk),
- debug1_stuff(Blk, DAG, IxBlk, Sch, X),
- X
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : fill_delays
-%% Argument : Sch - List of {{cycle, C}, {node, N}} : C = current cycle
-%% N = node index
-%% IxBlk - Indexed block [{N, Instr}]
-%% DAG - Dependence graph
-%% Returns : {NewSch, NewIxBlk} - vector with new schedule and vector
-%% with {N, Instr}
-%% Description : Goes through the schedule from back to front looking for
-%% branches/jumps. If one is found fill_del tries to find
-%% an instr to fill the delayslot.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-fill_delays(Sch, IxBlk, DAG) ->
- NewIxBlk = hipe_vectors:list_to_vector(IxBlk),
- %% NewSch = hipe_vectors:list_to_vector(Sch),
- NewSch = fill_del(length(Sch), hipe_vectors:list_to_vector(Sch),
- NewIxBlk, DAG),
- {NewSch, NewIxBlk}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : fill_del
-%% Argument : N - current index in the schedule
-%% Sch - schedule
-%% IxBlk - indexed block
-%% DAG - dependence graph
-%% Returns : Sch - New schedule with possibly a delay instr in the last
-%% position.
-%% Description : If a call/jump is found fill_branch_delay/fill_call_delay
-%% is called to find a delay-filler.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-fill_del(N, Sch, _IxBlk, _DAG) when N < 1 -> Sch;
-fill_del(N, Sch, IxBlk, DAG) ->
- Index = get_index(Sch, N),
- ?debug2("Index for ~p: ~p~nInstr: ~p~n",
- [N, Index, get_instr(IxBlk, Index)]),
- NewSch =
- case get_instr(IxBlk, Index) of
- #call_link{} ->
- fill_branch_delay(N - 1, N, Sch, IxBlk, DAG);
- #jmp_link{} ->
- fill_call_delay(N - 1, N, Sch, IxBlk, DAG);
- #jmp{} ->
- fill_call_delay(N - 1, N, Sch, IxBlk, DAG);
- #b{} ->
- fill_branch_delay(N - 1, N, Sch, IxBlk, DAG);
- #br{} ->
- fill_branch_delay(N - 1, N, Sch, IxBlk, DAG);
- #goto{} ->
- fill_branch_delay(N - 1, N, Sch, IxBlk, DAG);
- _Other ->
- Sch
- end,
- NewSch.
- %% fill_del(N - 1, NewSch, IxBlk, DAG).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : fill_call_delay
-%% Argument : Cand - index in schedule of delay-candidate
-%% Call - index in schedule of call
-%% Sch - schedule vector: < {{cycle,Ci},{node,Nj}}, ... >
-%% IxBlk - block vector: < {N, Instr1}, {N+1, Instr2} ... >
-%% DAG - dependence graph
-%% Returns : Sch - new updated schedule.
-%% Description : Searches backwards through the schedule trying to find an
-%% instr without conflicts with the Call-instr.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-fill_call_delay(Cand, _Call, Sch, _IxBlk, _DAG) when Cand < 1 -> Sch;
-fill_call_delay(Cand, Call, Sch, IxBlk, DAG) ->
- CandIndex = get_index(Sch, Cand),
- CallIndex = get_index(Sch, Call),
- CandI = get_instr(IxBlk, CandIndex),
- case move_or_alu(CandI) of
- true ->
- case single_depend(CandIndex, CallIndex, DAG) of
- false -> % Other instrs depends on Cand ...
- fill_call_delay(Cand - 1, Call, Sch, IxBlk, DAG);
-
- true ->
- CallI = get_instr(IxBlk, CallIndex),
-
- CandDefs = ordsets:from_list(hipe_sparc:defines(CandI)),
- %% CandUses = ordsets:from_list(hipe_sparc:uses(CandI)),
- %% CallDefs = ordsets:from_list(hipe_sparc:defines(CallI)),
- CallUses = ordsets:from_list(hipe_sparc:uses(CallI)),
-
- Args = case CallI of
- #jmp_link{} ->
- ordsets:from_list(
- hipe_sparc:jmp_link_args(CallI));
- #jmp{} ->
- ordsets:from_list(hipe_sparc:jmp_args(CallI));
- #call_link{} ->
- ordsets:from_list(
- hipe_sparc:call_link_args(CallI))
- end,
- CallUses2 = ordsets:subtract(CallUses, Args),
- Conflict = ordsets:intersection(CandDefs, CallUses2),
- %% io:format("single_depend -> true:~n ~p~n, ~p~n,~p~n",[CandI,CallI,DAG]),
- %% io:format("Cand = ~p~nCall = ~p~n",[CandI,CallI]),
- %% io:format("CandDefs = ~p~nCallDefs = ~p~n",[CandDefs,CallDefs]),
- %% io:format("CandUses = ~p~nCallUses = ~p~n",[CandUses,CallUses]),
- %% io:format("Args = ~p~nCallUses2 = ~p~n",[Args,CallUses2]),
- %% io:format("Conflict = ~p~n",[Conflict]),
-
- case Conflict of
- [] -> % No conflicts ==> Cand can fill delayslot after Call
- update_schedule(Cand, Call, Sch);
- _ -> % Conflict: try with preceeding instrs
- fill_call_delay(Cand - 1, Call, Sch, IxBlk, DAG)
- end
- end;
- false ->
- fill_call_delay(Cand - 1, Call, Sch, IxBlk, DAG)
- end.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : fill_branch_delay
-%% Argument : Cand - index in schedule of delay-candidate
-%% Branch - index in schedule of branch
-%% Sch - schedule
-%% IxBlk - indexed block
-%% DAG - dependence graph
-%% Returns : Sch - new updated schedule.
-%% Description : Searches backwards through the schedule trying to find an
-%% instr without conflicts with the Branch-instr.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-fill_branch_delay(Cand, _Br, Sch, _IxBlk, _DAG) when Cand < 1 -> Sch;
-fill_branch_delay(Cand, Br, Sch, IxBlk, DAG) ->
- CandIndex = get_index(Sch, Cand),
- BrIndex = get_index(Sch, Br),
- CandI = get_instr(IxBlk, CandIndex),
- case move_or_alu(CandI) of
- true ->
- case single_depend(CandIndex, BrIndex, DAG) of
- false -> % Other instrs depends on Cand ...
- fill_branch_delay(Cand - 1, Br, Sch, IxBlk, DAG);
-
- true ->
- BrI = get_instr(IxBlk, BrIndex),
- CandDefs = ordsets:from_list(hipe_sparc:defines(CandI)),
- %% CandUses = ordsets:from_list(hipe_sparc:uses(CandI)),
- %% BrDefs = ordsets:from_list(hipe_sparc:defines(BrI)),
- BrUses = ordsets:from_list(hipe_sparc:uses(BrI)),
-
- Conflict = ordsets:intersection(CandDefs, BrUses),
- %% io:format("single_depend -> true: ~p~n, ~p~n,~p~n", [CandI, BrI, DAG]),
- %% io:format("Cand = ~p~nBr = ~p~n",[CandI,BrI]),
- %% io:format("CandDefs = ~p~nBrDefs = ~p~n",[CandDefs,BrDefs]),
- %% io:format("CandUses = ~p~nBrUses = ~p~n",[CandUses,BrUses]),
- %% io:format("Conflict = ~p~n",[Conflict]);
-
- case Conflict of
- [] -> % No conflicts ==>
- % Cand can fill delayslot after Branch
- update_schedule(Cand, Br, Sch);
- _ -> % Conflict: try with preceeding instrs
- fill_branch_delay(Cand - 1, Br, Sch, IxBlk, DAG)
- end
- end;
- false ->
- fill_branch_delay(Cand - 1, Br, Sch, IxBlk, DAG)
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : update_schedule
-%% Argument : From - the position from where to switch indexes in Sch
-%% To - the position to where to switch indexes in Sch
-%% Sch - schedule
-%% Returns : Sch - an updated schedule
-%% Description : If From is the delay-filler and To is the Call/jump, the
-%% schedule is updated so From gets index To, To gets index
-%% To - 1, and the nodes between From and To gets old_index - 1.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-update_schedule(To, To, Sch) ->
- {{cycle, C}, {node, _N} = Node} = hipe_vectors:get(Sch, To-1),
- hipe_vectors:set(Sch, To-1, {{cycle, C+1}, Node});
-update_schedule(From, To, Sch) ->
- Temp = hipe_vectors:get(Sch, From-1),
- Sch1 = hipe_vectors:set(Sch, From-1, hipe_vectors:get(Sch, From)),
- update_schedule(From + 1, To, hipe_vectors:set(Sch1, From, Temp)).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : single_depend
-%% Argument : N - Index of the delayslot candidate
-%% M - Index of the node that N possibly has a single
-%% depend to.
-%% DAG - The dependence graph
-%% Returns : true if no other nodes than N os depending on N
-%% Description : Checks that no other nodes than M depends on N and that the
-%% latency between them is zero or 1.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-single_depend(N, M, DAG) ->
- Deps = hipe_vectors:get(DAG, N-1),
- single_depend(M, Deps).
-
-single_depend(_N, []) -> true;
-single_depend(N, [{0, N}]) -> true;
-single_depend(N, [{1, N}]) -> true;
-single_depend(_N, [{_Lat, _}|_]) -> false.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : get_index
-%% Argument : Sch - schedule
-%% N - index in schedule
-%% Returns : Index - index of the node
-%% Description : Returns the index of the node on position N in the schedule.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-get_index(Sch, N) ->
- {{cycle, _C}, {node, Index}} = hipe_vectors:get(Sch,N-1),
- Index.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : get_instr
-%% Argument : IxBlk - indexed block
-%% N - index in block
-%% Returns : Instr
-%% Description : Returns the instr on position N in the indexed block.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-get_instr(IxBlk, N) ->
- {_, Instr} = hipe_vectors:get(IxBlk, N-1),
- Instr.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : get_instr
-%% Argument : Sch - schedule
-%% IxBlk - indexed block
-%% N - index in schedule
-%% Returns : Instr
-%% Description : Returns the instr on position N in the schedule.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-get_instr(Sch, IxBlk, N) ->
- {{cycle, _C}, {node, Index}} = hipe_vectors:get(Sch, N-1),
- {_, Instr} = hipe_vectors:get(IxBlk, Index-1),
- Instr.
-
-separate_block(Sch,IxBlk) ->
- sep_comments([{C,lookup_instr(IxBlk,N)} || {{cycle,C},{node,N}} <- Sch]).
-
-sep_comments([]) -> [];
-sep_comments([{C,I}|Xs]) ->
- [hipe_sparc:comment_create({cycle,C}), I | sep_comments(Xs,C)].
-
-sep_comments([], _) -> [];
-sep_comments([{C1,I}|Xs], C0) ->
- if
- C1 > C0 ->
- [hipe_sparc:comment_create({cycle,C1}),I|sep_comments(Xs,C1)];
- true ->
- [I|sep_comments(Xs, C0)]
- end.
-
-finalize_block(Sch, IxBlk) ->
- ?debug5("Sch: ~p~nIxBlk: ~p~n",[Sch,IxBlk]),
- finalize_block(1, hipe_vectors:size(Sch), 1, Sch, IxBlk, []).
-
-finalize_block(N, End, _C, Sch, IxBlk, _Instrs) when N =:= End - 1 ->
- NextLast = get_instr(Sch, IxBlk, N),
- Last = get_instr(Sch, IxBlk, End),
- ?debug5("NextLast: ~p~nLast: ~p~n",[NextLast,Last]),
- case hipe_sparc:is_any_branch(Last) of
- true -> % Couldn't fill delayslot ==> add NOP
- [NextLast , hipe_sparc:nop_create(), Last];
- false -> % Last is a delayslot-filler ==> change order...
- [Last, NextLast]
- end;
-finalize_block(N, End, C0, Sch, IxBlk, Instrs) ->
- {{cycle, _C1}, {node, _M}} = hipe_vectors:get(Sch, N-1),
- Instr = get_instr(Sch, IxBlk, N),
- ?debug5("Instr: ~p~n~n",[Instr]),
- [Instr | finalize_block(N + 1, End, C0, Sch, IxBlk, Instrs)].
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : bb
-%% Argument : IxBlk - indexed block
-%% DAG - {Dag, Preds} where Dag is dependence graph and
-%% Preds is number of predecessors for each node.
-%% Returns : Sch
-%% Description : Initializes earliest-list, ready-list, priorities, resources
-%% and so on, and calls the cycle_sched which does the scheduling
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-bb(IxBlk,DAG) ->
- bb(length(IxBlk), IxBlk, DAG).
-
-bb(N,IxBlk,{DAG, Preds}) ->
- Earliest = init_earliest(N),
- BigArray = N*10, % "nothing" is this big :-)
- Ready = hipe_schedule_prio:init_ready(BigArray,Preds),
- I_res = init_instr_resources(N, IxBlk),
-
- Prio = hipe_schedule_prio:init_instr_prio(N,DAG),
- Rsrc = init_resources(BigArray),
- ?debug4("I_res: ~n~p~nPrio: ~n~p~nRsrc: ~n~p~n", [I_res,Prio,Rsrc]),
- ?debug('cycle 1~n',[]),
- Sch = empty_schedule(),
- cycle_sched(1,Ready,DAG,Preds,Earliest,Rsrc,I_res,Prio,Sch,N,IxBlk).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : cycle_sched
-%% Argument : - C is current cycle, 1 or more.
-%% - Ready is an array (Cycle -> [Node])
-%% yielding the collection of nodes ready to be
-%% scheduled in a cycle.
-%% - DAG is an array (Instr -> [{Latency,Instr}])
-%% represents the dependence DAG.
-%% - Preds is an array (Instr -> NumPreds)
-%% counts the number of predecessors
-%% (0 preds = ready to be scheduled).
-%% - Earl is an array (Instr -> EarliestCycle)
-%% holds the earliest cycle an instruction can be scheduled.
-%% - Rsrc is a 'resource ADT' that handles scheduler resource
-%% management checks whether instruction can be scheduled
-%% this cycle without a stall.
-%% - I_res is an array (Instr -> Required_resources)
-%% holds the resources required to schedule an instruction.
-%% - Sch is the representation of the schedule current schedule.
-%% - N is the number of nodes remaining to be scheduled
-%% tells us when to stop the scheduler.
-%% - IxBlk is the indexed block with instrs
-%% Returns : present schedule
-%% Description : Scheduler main loop.
-%% Pick next ready node in priority order for cycle C until
-%% none remain.
-%% * check each node if it can be scheduled w/o stalling
-%% * if so, schedule it
-%% * otherwise, bump the node to the next cycle
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-cycle_sched(C,Ready,DAG,Preds,Earl,Rsrc,I_res,Prio,Sch,N,IxBlk) ->
- case hipe_schedule_prio:next_ready(C,Ready,Prio,IxBlk,DAG,Preds,Earl) of
-% case hipe_schedule_prio:next_ready(C,Ready,Prio,IxBlk) of
- {next,I,Ready1} ->
- ?debug('try ~p~n==> ready = ~p~n',[I, Ready1]),
- case resources_available(C,I,Rsrc,I_res) of
- {yes,NewRsrc} ->
- ?debug(' scheduled~n==> Rscrs = ~p~n',[NewRsrc]),
- NewSch = add_to_schedule(I,C,Sch),
- {ReadyNs,NewDAG,NewPreds,NewEarl} =
- delete_node(C,I,DAG,Preds,Earl),
- ?debug("NewPreds : ~p~n",[Preds]),
- ?debug(' ReadyNs: ~p~n',[ReadyNs]),
- NewReady = hipe_schedule_prio:add_ready_nodes(ReadyNs,
- Ready1),
- ?debug(' New ready: ~p~n',[NewReady]),
- cycle_sched(C,NewReady,NewDAG,NewPreds,NewEarl,
- NewRsrc,I_res,Prio,NewSch,N-1, IxBlk);
- no ->
- ?debug(' resource conflict~n',[]),
- NewReady = hipe_schedule_prio:insert_node(C+1,I,Ready1),
- cycle_sched(C,NewReady,DAG,Preds,Earl,Rsrc,
- I_res,Prio,Sch,N,IxBlk)
- end;
- none -> % schedule next cycle if some node remains
- if
- N > 0 ->
- ?debug('cycle ~p~n',[C+1]),
- cycle_sched(C+1,Ready,DAG,Preds,Earl,
- advance_cycle(Rsrc),
- I_res,Prio,Sch,N, IxBlk);
- true ->
- present_schedule(Sch)
- end
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : init_earliest
-%% Argument : N - number of instrs
-%% Returns :
-%% Description :
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-init_earliest(N) ->
- hipe_vectors:new(N,1).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Schedule is kept reversed until the end.
-
--define(present_node(I,Cycle),{{cycle,Cycle},{node,I}}).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : empty_schedule
-%% Description : Returns an empty schedule.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-empty_schedule() -> [].
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : add_to_schedule
-%% Argument : I - instr
-%% Cycle - cycle when I was placed
-%% Sch - schedule
-%% Description : Adds instr to schedule
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-add_to_schedule(I,Cycle,Sch) ->
- [?present_node(I,Cycle)|Sch].
-
-present_schedule(Sch) -> lists:reverse(Sch).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Interface to resource manager:
-%%
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : init_resources
-%% Description : Yields a 'big enough' array mapping (Cycle -> Resources);
-%% this array is called Rsrc below.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-init_resources(S) ->
- hipe_target_machine:init_resources(S).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : init_instr_resources
-%% Argument : Nodes - a list of the instructions
-%% N - is the number of nodes
-%% Description : return a vector (NodeID -> Resource_requirements)
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-init_instr_resources(N,Nodes) ->
- hipe_target_machine:init_instr_resources(N,Nodes).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : resources_available
-%% Argument : Cycle - the current cycle
-%% I - the current instruction (index = NodeID)
-%% Rsrc - a map (Cycle -> Resources)
-%% I_res - maps (NodeID -> Resource_requirements)
-%% Description : returns {yes,NewResTab} | no
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-resources_available(Cycle,I,Rsrc,I_res) ->
- hipe_target_machine:resources_available(Cycle,I,Rsrc,I_res).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : advance_cycle
-%% Argument : Rsrc - resources
-%% Description : Returns an empty resources-state
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-advance_cycle(Rsrc) ->
- hipe_target_machine:advance_cycle(Rsrc).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : delete_node
-%% Argument : Cycle - current cycle
-%% I - index of instr
-%% DAG - dependence dag
-%% Preds - array with number of predecessors for nodes
-%% Earl - array with earliest-times for nodes
-%% Returns : {ReadyNs,NewDAG,NewPreds,NewEarl}
-%% Description : Deletes node I and updates earliest times for the rest.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-delete_node(Cycle,I,DAG,Preds,Earl) ->
- Succ = hipe_vectors:get(DAG,I-1),
- NewDAG = hipe_vectors:set(DAG,I-1,scheduled), % provides debug 'support'
- {ReadyNs,NewPreds,NewEarl} = update_earliest(Succ,Cycle,Preds,Earl,[]),
- ?debug('earliest after ~p: ~p~n',[I,[{Ix+1,V} || {Ix,V} <- hipe_vectors:list(NewEarl)]]),
- {ReadyNs,NewDAG,NewPreds,NewEarl}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : update_earliest
-%% Argument : Succ - successor list
-%% Cycle - current cycle
-%% Preds - predecessors
-%% Earl - earliest times for nodes
-%% Ready - array with readynodes for cycles
-%% Returns : {Ready,Preds,Earl}
-%% Description : Updates the earliest times for nodes and updates number of
-%% predecessors for nodes
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-update_earliest([],_Cycle,Preds,Earl,Ready) ->
- {Ready,Preds,Earl};
-update_earliest([{Lat,N}|Xs],Cycle,Preds,Earl,Ready) ->
- Old_earl = hipe_vectors:get(Earl,N-1),
- New_earl = erlang:max(Old_earl,Cycle+Lat),
- NewEarl = hipe_vectors:set(Earl,N-1,New_earl),
- Num_preds = hipe_vectors:get(Preds,N-1),
- NewPreds = hipe_vectors:set(Preds,N-1,Num_preds-1),
- if
- Num_preds =:= 0 ->
- ?debug('inconsistent DAG~n',[]),
- exit({update_earliest,N});
- Num_preds =:= 1 ->
- NewReady = [{New_earl,N}|Ready],
- NewPreds2 = hipe_vectors:set(NewPreds,N-1,0),
- update_earliest(Xs,Cycle,NewPreds2,NewEarl,NewReady);
- is_integer(Num_preds), Num_preds > 1 ->
- update_earliest(Xs,Cycle,NewPreds,NewEarl,Ready)
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Collect instruction dependences.
-%%
-%% Three forms:
-%% - data/register
-%% * insert RAW, WAR, WAW dependences
-%% - memory
-%% * stores serialize memory references
-%% * alias analysis may allow loads to bypass stores
-%% - control
-%% * unsafe operations are 'trapped' between branches
-%% * branches are ordered
-%%
-%% returns { [{Index,Instr}], DepDAG }
-%% DepDAG is defined below.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : deps
-%% Argument : BB - Basic block
-%% Returns : {IxBB,DAG} - indexed block and dependence graph. DAG consists
-%% of both Dag and Preds, where Preds is number
-%% of predecessors for nodes.
-%% Description : Collect instruction dependences.
-%%
-%% Three forms:
-%% - data/register
-%% * insert RAW, WAR, WAW dependences
-%% - memory
-%% * stores serialize memory references
-%% * alias analysis may allow loads to bypass stores
-%% - control
-%% * unsafe operations are 'trapped' between branches
-%% * branches are ordered
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-deps(IxBB) ->
- N = length(IxBB),
- DAG = empty_dag(N), % The DAG contains both dependence-arcs and
- % number of predeccessors...
- {_DepTab,DAG1} = dd(IxBB, DAG),
- DAG2 = md(IxBB, DAG1),
- cd(IxBB, DAG2).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : empty_dag
-%% Argument : N - number of nodes
-%% Returns : empty DAG
-%% Description : DAG consists of dependence graph and predeccessors
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-empty_dag(N) ->
- {hipe_vectors:new(N, []), hipe_vectors:new(N, 0)}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : indexed_bb
-%% Argument : BB - basic block
-%% Returns : [{N, Instr}]
-%% Description : Puts indexes to all instrs of a block, removes comments.
-%% NOP's are also removed because if both sparc_schedule and
-%% sparc_post_schedule options are used, the first pass will
-%% add nop's before the branch if necessary, and these are
-%% removed before scheduling the second pass.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-indexed_bb(BB) ->
- indexed_bb(BB,1).
-
-indexed_bb([],_N) -> [];
-indexed_bb([X|Xs],N) ->
- case X of
- #comment{} ->
- indexed_bb(Xs,N);
- #nop{} ->
- indexed_bb(Xs,N);
- _Other ->
- [{N,X}|indexed_bb(Xs,N+1)]
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : dep_arc
-%% Argument : N - Current node
-%% Lat - Latency from current node to M
-%% M - The dependent node
-%% DAG - The dependence graph. Consists of both DAG and
-%% predeccessors
-%% Returns : A new DAG with the arc added and number of predeccessors for
-%% M increased.
-%% Description : Adds a new arc to the graph, if an older arc goes from N to M
-%% it will be replaced with a new arc {max(OldLat, NewLat), M}.
-%% Number of predeccessors for node M is increased.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-dep_arc(N, Lat, M, {Dag,Preds}) ->
- OldDeps = hipe_vectors:get(Dag, N-1),
- %% io:format("{OldDeps} = {~p}~n",[OldDeps]),
- {NewDeps, Status} = add_arc(Lat, M, OldDeps),
- %% io:format("{NewDeps, Status} = {~p, ~p}~n",[NewDeps, Status]),
- NewDag = hipe_vectors:set(Dag, N-1, NewDeps),
- NewPreds = case Status of
- added -> % just increase preds if new arc was added
- OldPreds = hipe_vectors:get(Preds, M-1),
- hipe_vectors:set(Preds, M-1, OldPreds + 1);
- non_added ->
- Preds
- end,
- {NewDag, NewPreds}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : add_arc
-%% Argument : Lat - The latency from current node to To.
-%% To - The instr-id of the node which the dependence goes to
-%% Arcs - The dependecies that are already in the dep-graph
-%% Returns : A dependence graph sorted by To.
-%% Description : A new arc that is added is sorted in the right place, and if
-%% there is already an arc between nodes A and B, the one with
-%% the greatest latency is chosen.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-add_arc(Lat,To, []) -> {[{Lat, To}], added};
-add_arc(Lat1, To, [{Lat2, To} | Arcs]) ->
- {[{erlang:max(Lat1, Lat2), To} | Arcs], non_added};
-add_arc(Lat1,To1, [{Lat2, To2} | Arcs]) when To1 < To2 ->
- {[{Lat1, To1}, {Lat2, To2} | Arcs], added};
-add_arc(Lat1 ,To1, [{Lat2, To2} | Arcs]) ->
- {Arcs1, Status} = add_arc(Lat1, To1, Arcs),
- {[{Lat2, To2} | Arcs1], Status}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% The register/data dependence DAG of a block is represented
-%% as a mapping (Variable -> {NextWriter,NextReaders})
-%% where NextWriter is a pair {Ix,Type}
-%% and NextReaders is a list of pairs {Ix,Type}.
-%%
-%% Type is used to determine latencies of operations; on the UltraSparc,
-%% latencies of arcs (n -> m) are determined by both n and m. (E.g., if
-%% n is an integer op and m is a store, then latency is 0; if m is an
-%% integer op, it's 1.)
-
-dd([],DAG) -> { empty_deptab(), DAG };
-dd([{N,I}|Is],DAG0) ->
- {DepTab,DAG1} = dd(Is,DAG0),
- add_deps(N,I,DepTab,DAG1).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : add_deps
-%% Argument : N - current node
-%% Instr - current instr
-%% DepTab - hashtable with {next-writer, next-readers} for reg
-%% DAG - dependence graph
-%% Returns : {DepTab, BlockInfo, DAG} - with new values
-%% Description : Adds dependencies for node N to the graph. The registers that
-%% node N defines and uses are used for computing the
-%% dependencies to the following nodes.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-add_deps(N,Instr,DepTab,DAG) ->
- {Ds,Us} = def_use(Instr),
- Type = dd_type(Instr),
- {DepTab1,DAG1} = add_write_deps(Ds,N,Type,DepTab,DAG),
- add_read_deps(Us,N,Type,DepTab1,DAG1).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Instructions are classified into symbolic categories,
-%% which are subsequently used to determine operation latencies
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-dd_type(Instr) ->
- case Instr of
- #b{} -> branch;
- %% #br{} -> branch;
- #call_link{} -> branch;
- #jmp_link{} -> branch;
- #jmp{} -> branch;
- #goto{} -> branch;
- #load{} -> load;
- #store{} -> store;
- #alu{} -> alu;
- #move{} -> alu;
- #multimove{} ->
- Src = hipe_sparc:multimove_src(Instr),
- Lat = round(length(Src)/2),
- {mmove,Lat};
- #sethi{} -> alu;
- #alu_cc{} -> alu_cc;
- %% #cmov_cc{} -> cmov_cc;
- %% #cmov_r{} -> alu;
- #load_atom{} -> alu;
- #load_address{} -> alu;
- #pseudo_enter{} -> pseudo;
- #pseudo_pop{} -> pseudo;
- #pseudo_return{} -> pseudo;
- #pseudo_spill{} -> pseudo;
- #pseudo_unspill{} -> pseudo
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : add_write_deps
-%% Argument : Defs - registers that node N defines.
-%% N - current node
-%% Ty - the type of current instr
-%% DepTab - Dependence-table
-%% DAG - The dependence graph.
-%% Returns : {DepTab,DAG} - with new values
-%% Description : Adds dependencies to the graph for nodes that depends on the
-%% registers that N defines.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-add_write_deps([],_N,_Ty,DepTab,DAG) -> {DepTab,DAG};
-add_write_deps([D|Ds],N,Ty,DepTab,DAG) ->
- {NewDepTab,NewDAG} = add_write_dep(D,N,Ty,DepTab,DAG),
- add_write_deps(Ds,N,Ty,NewDepTab,NewDAG).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : add_write_dep
-%% Description : Updates the dependence table with N as next writer, and
-%% updates the DAG with the dependencies from N to subsequent
-%% nodes.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-add_write_dep(X,N,Ty,DepTab,DAG) ->
- {NxtWriter,NxtReaders} = lookup(X,DepTab),
- NewDepTab = writer(X,N,Ty,DepTab),
- NewDAG = write_deps(N,Ty,NxtWriter,NxtReaders,DAG),
- {NewDepTab, NewDAG}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : write_deps
-%% Argument : Instr - Current instr
-%% Ty - Type of current instr
-%% NxtWriter - The node that is the next writer of the ragister
-%% that Instr defines.
-%% NxtReaders - The nodes that are subsequent readers of the
-%% register that N defines.
-%% DAG - The dependence graph
-%% Returns : Calls raw_deps that finally returns a new DAG with the new
-%% dependence arcs added.
-%% Description : If a next writer exists a dependence arc for this node is
-%% added, and after this raw_deps is called to compute the
-%% arcs for read-after-write dependencies.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-write_deps(Instr,Ty,NxtWriter,NxtReaders,DAG) ->
- DAG1 = case NxtWriter of
- none ->
- DAG;
- {Instr,_} ->
- DAG;
- {Wr,WrTy} ->
- dep_arc(Instr,
- hipe_target_machine:waw_latency(Ty,WrTy),
- Wr, DAG)
- end,
- raw_deps(Instr,Ty,NxtReaders,DAG1).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : raw_deps
-%% Argument : Instr - current instr
-%% Type - type of instr
-%% Readers - subsequent readers
-%% DAG - dependence graph
-%% Returns : DAG - A new DAG with read-after-write dependencies added
-%% Description : Updates the DAG with the dependence-arcs from Instr to the
-%% subsequent readers, with the appropriate latencies.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-raw_deps(_Instr,_Type,[],DAG) -> DAG;
-raw_deps(Instr,Ty,[{Rd,RdTy}|Xs],DAG) ->
- raw_deps(Instr,Ty,Xs,
- dep_arc(Instr,hipe_target_machine:raw_latency(Ty,RdTy),
- Rd,DAG)).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : add_read_deps
-%% Argument : Uses - The registers that node N uses.
-%% N - Index of the current node.
-%% Ty - Type of current node.
-%% DepTab - Dependence table
-%% DAG - Dependence graph
-%% Returns : {DepTab, DAG} - with updated values.
-%% Description : Adds the read dependencies from node N to subsequent ones,
-%% according to the registers that N uses.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-add_read_deps([],_N,_Ty,DepTab,DAG) -> {DepTab,DAG};
-add_read_deps([U|Us],N,Ty,DepTab,DAG) ->
- {NewDepTab,NewDAG} = add_read_dep(U,N,Ty,DepTab,DAG),
- add_read_deps(Us,N,Ty,NewDepTab,NewDAG).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : add_read_dep
-%% Argument : X - Used register
-%% N - Index of checked instr
-%% Ty - Type of checked instr
-%% DepTab - Hashtable with {next-writer, next-readers}
-%% DAG - Dependence graph
-%% Returns : {DepTab, DAG} - with updated values
-%% Description : Looks up what the next-writer/next-readers are, and adjusts
-%% the table with current node as new reader. Finally
-%% read-dependencies are added to the DAG.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-add_read_dep(X,N,Ty,DepTab,DAG) ->
- {NxtWriter,_NxtReaders} = lookup(X,DepTab),
- NewDepTab = reader(X,N,Ty,DepTab),
- NewDAG = read_deps(N,Ty,NxtWriter,DAG),
- {NewDepTab, NewDAG}.
-
-% If NxtWriter is 'none', then this var is not written subsequently
-% Add WAR from Instr to NxtWriter (if it exists)
-% *** UNFINISHED ***
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : read_deps
-%% Argument : N - Index of current node
-%% Ty - Type of current node
-%% Writer - tuple {NextWriter, WrType} where NextWriter is the
-%% subsequent instr that writes this register next time,
-%% and WrType is the type of that instr.
-%% DAG - The dependence graph
-%% Returns : DAG
-%% Description : Returns a new DAG if a next-writer exists, otherwise the old
-%% DAG is returned.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-read_deps(_Instr,_Ty,none,DAG) ->
- DAG;
-read_deps(_Instr,_Ty,{_Instr,_},DAG) ->
- DAG;
-read_deps(Instr,Ty,{NxtWr,NxtWrTy},DAG) ->
- dep_arc(Instr,hipe_target_machine:war_latency(Ty,NxtWrTy),NxtWr,
- DAG).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : empty_deptab
-%% Description : Creates an empty dependence table (hash-table)
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-empty_deptab() ->
- gb_trees:empty().
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : lookup
-%% Argument : X - key (register)
-%% DepTab - dependence table
-%% Returns : {NextWriter, NextReaders}
-%% Description : Returns next writer and a list of following readers on
-%% register X.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-lookup(X, DepTab) ->
- case gb_trees:lookup(X, DepTab) of
- none ->
- {none, []};
- {value, {W, Rs} = Val} ->
- Val
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : writer
-%% Argument : X - key (register)
-%% N - index of writer
-%% Ty - type of writer
-%% DepTab - dependence table to be updated
-%% Returns : DepTab - new dependence table
-%% Description : Sets N tobe next writer on X
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-writer(X, N, Ty, DepTab) ->
- gb_trees:enter(X, {{N, Ty}, []}, DepTab).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : reader
-%% Argument : X - key (register)
-%% N - index of reader
-%% Ty - type of reader
-%% DepTab - dependence table to be updated
-%% Returns : DepTab - new dependence table
-%% Description : Adds N to the dependence table as a reader.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-reader(X,N,Ty,DepTab) ->
- {W,Rs} = lookup(X,DepTab),
- gb_trees:enter(X,{W,[{N,Ty}|Rs]},DepTab).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% The following version of md/2 separates heap- and stack operations,
-%% which allows for greater reordering.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : md
-%% Argument : IxBB - indexed block
-%% DAG - dependence graph
-%% Returns : DAG - new dependence graph
-%% Description : Adds arcs for load/store dependencies to the DAG.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-md(IxBB, DAG) ->
- md(IxBB,empty_md_state(),DAG).
-
-md([],_,DAG) -> DAG;
-md([{N,I}|Is],St,DAG) ->
- case md_type(I) of
- other ->
- md(Is,St,DAG);
- {st,T} ->
- { WAW_nodes, WAR_nodes, NewSt } = st_overlap(N,T,St),
- md(Is,NewSt,
- md_war_deps(WAR_nodes,N,md_waw_deps(WAW_nodes,N,DAG)));
- {ld,T} ->
- { RAW_nodes, NewSt } = ld_overlap(N,T,St),
- md(Is,NewSt,
- md_raw_deps(RAW_nodes,N,DAG))
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : md_war_deps
-%% Argument : WAR_nodes - write-after-read nodes depending on N
-%% N - index of current instr
-%% DAG - dependence graph
-%% Returns : DAG - updated DAG
-%% Description : Adds arcs for write-after-read dependencies for N
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-md_war_deps([],_,DAG) -> DAG;
-md_war_deps([M|Ms],N,DAG) ->
- md_war_deps(Ms,N,dep_arc(M,hipe_target_machine:m_war_latency(),N,DAG)).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : md_waw_deps
-%% Argument : WAW_nodes - write-after-write nodes depending on N
-%% N - index of current instr
-%% DAG - dependence graph
-%% Returns : DAG - updated DAG
-%% Description : Adds arcs for write-after-write dependencies for N
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-md_waw_deps([],_,DAG) -> DAG;
-md_waw_deps([M|Ms],N,DAG) ->
- md_waw_deps(Ms,N,dep_arc(M,hipe_target_machine:m_waw_latency(),N,DAG)).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : md_raw_deps
-%% Argument : RAW_nodes - read-after-write nodes depending on N
-%% N - index of current instr
-%% DAG - dependence graph
-%% Returns : DAG - updated DAG
-%% Description : Adds arcs for read-after-write dependencies for N
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-md_raw_deps([],_,DAG) -> DAG;
-md_raw_deps([M|Ms],N,DAG) ->
- md_raw_deps(Ms,N,dep_arc(M,hipe_target_machine:m_raw_latency(),N,DAG)).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : empty_md_state
-%% Description : Returns an empty memorydependence state, eg. 4 lists
-%% representing {StackStores, HeapStores, StackLoads, HeapLoads}
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-empty_md_state() -> {[], [], [], []}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : md_type
-%% Argument : I - instr
-%% Description : Maps the instr-type to a simplified type, telling if it's
-%% store/load resp. heap or stack.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-md_type(I) ->
- case I of
- #load{} ->
- Sp = hipe_sparc_registers:stack_pointer(),
- Src = hipe_sparc:load_src(I),
- N = hipe_sparc:reg_nr(Src),
- Off = hipe_sparc:load_off(I),
- if
- N =:= Sp -> % operation on stack
- {ld,{sp,Off}};
- true ->
- {ld,{hp,Src,Off}}
- end;
- #store{} ->
- Sp = hipe_sparc_registers:stack_pointer(),
- Dst = hipe_sparc:store_dest(I),
- N = hipe_sparc:reg_nr(Dst),
- Off = hipe_sparc:store_off(I),
- if
- N =:= Sp ->
- {st,{sp,Off}};
- true ->
- {st,{hp,Dst,Off}}
- end;
- _ ->
- other
- end.
-
-%% Given a memory operation and a 'memory op state',
-%% overlap(N,MemOp,State) returns { Preceding_Dependent_Ops, NewState }.
-%% which are either a tuple { WAW_deps, WAR_deps } or a list RAW_deps.
-%%
-%% NOTES:
-%% Note that Erlang's semantics ("heap stores never overwrite existing data")
-%% means we can be quite free in reordering stores to the heap.
-%% Ld/St to the stack are simply handled by their offsets; since we do not
-%% rename the stack pointer, this is sufficient.
-%% *** We assume all memory ops have uniform size = 4 ***
-%%
-%% NOTES:
-%% The method mentioned above has now been changed because the assumption that
-%% "heap stores never overwrite existing data" caused a bug when the
-%% process-pointer was treated the same way as the heap. We were also told
-%% that the semantics can possibly change in the future, so it would be more
-%% safe to treat the heap store/loads as the stack.
-%% A future improvement can be to do an alias analysis to give more freedom
-%% in reordering stuff...
-%%
-%% Alias state:
-%% { [StackOp], [HeapOp], [StackOp], [HeapOp] }
-%% where StackOp = {InstrID, Offset}
-%% HeapOp = {InstrID, Reg, Offset}
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : st_overlap
-%% Argument : N - Index of current node
-%% Type - {sp,Off} or {hp,Dst,Off}, store on stack or heap
-%% State - { [StackStrs], [HeapStrs], [StackLds], [HeapLds] }
-%% where StackStrs/StackLds = {InstrID, Offset}
-%% and HeapStrs/HeapLds = {InstrID, Reg, Offset}
-%% Returns : { DepStrs, DepLds, State } -
-%% where DepStrs/DepLds = [NodeId]
-%% and State is the new state
-%% Description : Adds dependencies for overlapping stores.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-st_overlap(N, {sp, Off}, {St_Sp, St_Hp, Ld_Sp, Ld_Hp}) ->
- {DepSt, IndepSt_Sp} = st_sp_dep(St_Sp, Off),
- {DepLd, IndepLd_Sp} = ld_sp_dep(Ld_Sp, Off),
- {DepSt, DepLd, {[{N, Off}|IndepSt_Sp], St_Hp, IndepLd_Sp, Ld_Hp}};
-st_overlap(N, {hp, Dst, Off}, {St_Sp, St_Hp, Ld_Sp, Ld_Hp}) ->
- DstOff = {Dst, Off},
- {DepSt,_IndepSt_Hp} = st_hp_dep(St_Hp, DstOff),
- {DepLd, IndepLd_Hp} = ld_hp_dep(Ld_Hp, DstOff),
- {DepSt, DepLd, {St_Sp, [{N, Dst, Off}|St_Hp], Ld_Sp, IndepLd_Hp}}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : ld_overlap
-%% Argument : N - Index of current node
-%% Type - {sp,Off} or {hp,Dst,Off}, store on stack or heap
-%% State - { [StackStrs], [HeapStrs], [StackLds], [HeapLds] }
-%% where StackStrs/StackLds = {InstrID, Offset}
-%% and HeapStrs/HeapLds = {InstrID, Reg, Offset}
-%% Returns : { DepStrs, State }
-%% Description : Adds dependencies for overlapping laods
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-ld_overlap(N, {sp, Off}, {St_Sp, St_Hp, Ld_Sp, Ld_Hp}) ->
- DepSt = sp_dep_only(St_Sp, Off),
- {DepSt, {St_Sp, St_Hp, [{N, Off}|Ld_Sp], Ld_Hp}};
-ld_overlap(N, {hp, Src, Off}, {St_Sp, St_Hp, Ld_Sp, Ld_Hp}) ->
- DepSt = hp_dep_only(St_Hp, Src, Off),
- {DepSt, {St_Sp, St_Hp, Ld_Sp, [{N, Src, Off}|Ld_Hp]}}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : st_sp_dep
-%% Description : Adds dependencies that are depending on a stack store
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-st_sp_dep(Stores, Off) ->
- sp_dep(Stores, Off, [], []).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : ld_sp_dep
-%% Description : Adds dependencies that are depending on a stack load
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-ld_sp_dep(Loads, Off) ->
- sp_dep(Loads, Off, [], []).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : st_hp_dep
-%% Description : Adds dependencies that are depending on a heap store
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-st_hp_dep(Stores, {_Reg, _Off} = RegOff) ->
- hp_dep(Stores, RegOff, [], []).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : ld_hp_dep
-%% Description : Adds dependencies that are depending on a heap load
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-ld_hp_dep(Loads, {_Reg, _Off} = RegOff) ->
- hp_dep(Loads, RegOff, [], []).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : sp_dep
-%% Description : Returns {Dependent, Independent} which are lists of nodes
-%% that depends or not on a stack load/store
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-sp_dep([], _Off, Dep, Indep) -> {Dep, Indep};
-sp_dep([{N,Off}|Xs], Off, Dep, Indep) ->
- sp_dep(Xs, Off, [N|Dep], Indep);
-sp_dep([X|Xs], Off, Dep, Indep) ->
- sp_dep(Xs, Off, Dep, [X|Indep]).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : hp_dep
-%% Description : Returns {Dependent, Independent} which are lists of nodes
-%% that depends or not on a heap load/store
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-hp_dep([], {_Reg,_Off}, Dep, Indep) -> {Dep,Indep};
-hp_dep([{N,Reg,Off1}|Xs], {Reg,Off}, Dep, Indep) when Off1 =/= Off ->
- hp_dep(Xs, {Reg,Off}, Dep, [{N,Reg,Off1}|Indep]);
-hp_dep([{N,_,_}|Xs], {Reg,Off}, Dep, Indep) ->
- hp_dep(Xs, {Reg,Off}, [N|Dep], Indep).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : sp_dep_only
-%% Description : Returns a list of nodes that are depending on a stack store
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-sp_dep_only(Stores, Off) ->
- [N || {N,Off0} <- Stores, Off =:= Off0].
-
-%% Dependences from heap stores to heap loads.
-%% *** UNFINISHED ***
-%% - but works
-%% This is somewhat subtle:
-%% - a heap load can only bypass a heap store if we KNOW it won't
-%% load the stored value
-%% - unfortunately, we do not know the relationships between registers
-%% at this point, so we can't say that store(p+4) is independent of
-%% load(q+0).
-%% (OR CAN WE? A bit closer reasoning might show that it's possible?)
-%% - We can ONLY say that st(p+c) and ld(p+c') are independent when c /= c'
-%%
-%% (As said before, it might be possible to lighten this restriction?)
-
-hp_dep_only([], _Reg, _Off) -> [];
-hp_dep_only([{_N,Reg,Off_1}|Xs], Reg, Off) when Off_1 =/= Off ->
- hp_dep_only(Xs, Reg, Off);
-hp_dep_only([{N,_,_}|Xs], Reg, Off) ->
- [N|hp_dep_only(Xs, Reg, Off)].
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Control dependences:
-%% - add dependences so that
-%% * branches are performed in order
-%% * unsafe operations are 'fenced in' by surrounding branches
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : cd
-%% Argument : IxBB - indexed block
-%% DAG - dependence graph
-%% Returns : DAG - new dependence graph
-%% Description : Adds conditional dependencies to the DAG
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-cd(IxBB,DAG) ->
- cd(IxBB, DAG, none, [], []).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : cd
-%% Argument : IxBB - indexed block
-%% DAG - dependence graph
-%% PrevBr - previous branch
-%% PrevUnsafe - previous unsafe instr (mem-op)
-%% PrevOthers - previous other instrs, used to "fix" preceeding
-%% instrs so they don't bypass a branch.
-%% Returns : DAG - new dependence graph
-%% Description : Adds conditional dependencies to the graph.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-cd([], DAG, _PrevBr, _PrevUnsafe, _PrevOthers) ->
- DAG;
-cd([{N,I}|Xs], DAG, PrevBr, PrevUnsafe, PrevOthers) ->
- case cd_type(I) of
- {branch,Ty} ->
- DAG1 = cd_branch_to_other_deps(N, PrevOthers, DAG),
- NewDAG = cd_branch_deps(PrevBr, PrevUnsafe, N, Ty, DAG1),
- cd(Xs,NewDAG,{N,Ty},[],[]);
- {unsafe,Ty} ->
- NewDAG = cd_unsafe_deps(PrevBr,N,Ty,DAG),
- cd(Xs, NewDAG, PrevBr, [{N,Ty}|PrevUnsafe], PrevOthers);
- {other,_Ty} ->
- cd(Xs, DAG, PrevBr, PrevUnsafe, [N|PrevOthers])
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : cd_branch_to_other_deps
-%% Argument : N - index of branch
-%% Ms - list of indexes of "others" preceding instrs
-%% DAG - dependence graph
-%% Returns : DAG - new graph
-%% Description : Makes preceding instrs fixed so they don't bypass a branch
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-cd_branch_to_other_deps(_, [], DAG) ->
- DAG;
-cd_branch_to_other_deps(N, [M | Ms], DAG) ->
- cd_branch_to_other_deps(N, Ms, dep_arc(M, zero_latency(), N, DAG)).
-
-%% Is the operation a branch, an unspeculable op or something else?
-
-%% Returns
-%% {branch,BranchType}
-%% {unsafe,OpType}
-%% {other,OpType}
-
-%% *** UNFINISHED ***
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : cd_type
-%% Argument : I - instr
-%% Description : Maps instrs to a simpler type.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-cd_type(I) ->
- case I of
- #goto{} ->
- {branch,uncond};
- #br{} ->
- {branch,'cond'};
- #b{} ->
- {branch,'cond'};
- #call_link{} ->
- {branch,call};
- #jmp_link{} ->
- {branch,call};
- #jmp{} ->
- {branch,call};
- #load{} ->
- {unsafe,load};
- #store{} ->
- {unsafe,load};
- T ->
- {other,T}
- end.
-
-%% add dependences to keep order of branches + unspeculable ops:
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : cd_branch_deps
-%% Argument : PrevBr - preceeding branch
-%% PrevUnsafe - preceeding unsafe ops, eg, mem-ops
-%% N - current id.
-%% Ty - type of current instr
-%% DAG - dependence graph
-%% Returns : DAG - new DAG
-%% Description : Adds arcs between branches and calls deps_to_unsafe that adds
-%% arcs between branches and unsafe ops.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-cd_branch_deps(PrevBr, PrevUnsafe, N, Ty, DAG) ->
- DAG1 = case PrevBr of
- none ->
- DAG;
- {Br,BrTy} ->
- dep_arc(Br,
- hipe_target_machine:br_br_latency(BrTy,Ty),
- N, DAG)
- end,
- deps_to_unsafe(PrevUnsafe, N, Ty, DAG1).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : deps_to_unsafe
-%% Description : Adds dependencies between unsafe's and branches
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-deps_to_unsafe([], _, _, DAG) -> DAG;
-deps_to_unsafe([{M,UTy}|Us], N, Ty, DAG) ->
- deps_to_unsafe(Us,N,Ty,
- dep_arc(M, hipe_target_machine:unsafe_to_br_latency(UTy,Ty),
- N, DAG)).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : cd_unsafe_deps
-%% Description : Adds dependencies between branches and unsafe's
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-cd_unsafe_deps(none, _, _, DAG) ->
- DAG;
-cd_unsafe_deps({Br,BrTy}, N, Ty, DAG) ->
- dep_arc(Br, hipe_target_machine:br_to_unsafe_latency(BrTy, Ty), N, DAG).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : def_use
-%% Argument : Instr
-%% Description : Returns the registers that Instr defines resp. uses as 2 lists
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-def_use(Instr) ->
- {hipe_sparc:defines(Instr), hipe_sparc:uses(Instr)}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : move_or_alu
-%% Description : True if the instruction is a move or an alu; false otherwise
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-move_or_alu(#move{}) -> true;
-move_or_alu(#alu{}) -> true;
-move_or_alu(_) -> false.
-
-%% Debugging stuff below %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--ifdef(debug1).
-debug1_stuff(Blk, DAG, IxBlk, Sch, X) ->
- io:format("Blk: ~p~n",[Blk]),
- io:format("DAG: ~n~p~n~p",[DAG,IxBlk]),
- io:format("~n"),
- print_instrs(IxBlk),
- print_sch(Sch, IxBlk),
- print_instrs2(X).
-
-print_instrs([]) ->
- io:format("~n");
-print_instrs([{N,Instr} | Instrs]) ->
- io:format("(~p): ",[N]),
- hipe_sparc_pp:pp_instr(Instr),
- io:format("~p~n",[element(1,Instr)]),
- print_instrs(Instrs).
-
-print_instrs2([]) ->
- io:format("~n");
-print_instrs2([Instr | Instrs]) ->
- hipe_sparc_pp:pp_instr(Instr),
- print_instrs2(Instrs).
-
-print_sch([],_) -> io:format("~n");
-print_sch([{{cycle,Cycle},{node,I}} | Rest], IxBlk) ->
- io:format("{C~p, N~p} ",[Cycle,I]),
- print_node(I, IxBlk),
- print_sch(Rest, IxBlk).
-
-print_node(_, []) ->
- io:format("~n");
-print_node(I, [{I, Instr} | _]) ->
- hipe_sparc_pp:pp_instr(Instr);
-print_node(I, [_ | IxBlk]) ->
- print_node(I, IxBlk).
--else.
-debug1_stuff(_Blk, _DAG, _IxBlk, _Sch, _X) ->
- ok.
--endif.
diff --git a/lib/hipe/opt/hipe_schedule_prio.erl b/lib/hipe/opt/hipe_schedule_prio.erl
deleted file mode 100644
index 339bb82aab..0000000000
--- a/lib/hipe/opt/hipe_schedule_prio.erl
+++ /dev/null
@@ -1,53 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% PRIORITY HANDLING AND PRIORITY CALCULATION
-%%
-%% Handling of ready nodes and priorities.
-%% - at present, all nodes have the same priority and so on.
-%%
-%% *** UNFINISHED ***
-%% - should compute a static priority estimate
-%% - should dynamically modify priorities + possibly insert NOPs
-%% (e.g., to separate branches, etc.)
-%% - thus, ought to be passed the current schedule and/or resources as well
-
--module(hipe_schedule_prio).
--export([init_ready/2,
- init_instr_prio/2,
- %% initial_ready_set/4,
- next_ready/7,
- add_ready_nodes/2,
- insert_node/3
- ]).
-
-init_ready(Size,Preds) ->
- hipe_ultra_prio:init_ready(Size,Preds).
-
-init_instr_prio(N,DAG) ->
- hipe_ultra_prio:init_instr_prio(N,DAG).
-
-%% initial_ready_set(M,N,Preds,Ready) ->
-%% hipe_ultra_prio:initial_ready_set(M,N,Preds,Ready).
-
-next_ready(C,Ready,Prio,Nodes,DAG,Preds,Earl) ->
- hipe_ultra_prio:next_ready(C,Ready,Prio,Nodes,DAG,Preds,Earl).
-
-add_ready_nodes(NodeLst,Ready) ->
- hipe_ultra_prio:add_ready_nodes(NodeLst,Ready).
-
-insert_node(C,I,Ready) ->
- hipe_ultra_prio:insert_node(C,I,Ready).
diff --git a/lib/hipe/opt/hipe_target_machine.erl b/lib/hipe/opt/hipe_target_machine.erl
deleted file mode 100644
index 75993cb95e..0000000000
--- a/lib/hipe/opt/hipe_target_machine.erl
+++ /dev/null
@@ -1,87 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% INTERFACE TO TARGET MACHINE MODEL
-%%
-%% Interfaces the instruction scheduler to the (resource) machine model.
-
--module(hipe_target_machine).
--export([init_resources/1,
- init_instr_resources/2,
- resources_available/4,
- advance_cycle/1
- ]).
--export([raw_latency/2,
- war_latency/2,
- waw_latency/2,
- %% m_raw_latency/2,
- %% m_war_latency/2,
- %% m_waw_latency/2,
- m_raw_latency/0,
- m_war_latency/0,
- m_waw_latency/0,
- br_to_unsafe_latency/2,
- unsafe_to_br_latency/2,
- br_br_latency/2
- ]).
-
--define(target,hipe_ultra_mod2).
-
-init_resources(X) ->
- ?target:init_resources(X).
-
-init_instr_resources(X,Y) ->
- ?target:init_instr_resources(X,Y).
-
-resources_available(X,Y,Z,W) ->
- ?target:resources_available(X,Y,Z,W).
-
-advance_cycle(X) ->
- ?target:advance_cycle(X).
-
-raw_latency(From,To) ->
- ?target:raw_latency(From,To).
-
-war_latency(From,To) ->
- ?target:war_latency(From,To).
-
-waw_latency(From,To) ->
- ?target:waw_latency(From,To).
-
-%% m_raw_latency(From,To) ->
-%% ?target:m_raw_latency(From,To).
-
-%% m_war_latency(From,To) ->
-%% ?target:m_war_latency(From,To).
-
-%% m_waw_latency(From,To) ->
-%% ?target:m_waw_latency(From,To).
-
-m_raw_latency() ->
- ?target:m_raw_latency().
-
-m_war_latency() ->
- ?target:m_war_latency().
-
-m_waw_latency() ->
- ?target:m_waw_latency().
-
-br_to_unsafe_latency(Br,U) ->
- ?target:br_to_unsafe_latency(Br,U).
-
-unsafe_to_br_latency(U,Br) ->
- ?target:unsafe_to_br_latency(U,Br).
-
-br_br_latency(Br1,Br2) ->
- ?target:br_br_latency(Br1,Br2).
diff --git a/lib/hipe/opt/hipe_ultra_mod2.erl b/lib/hipe/opt/hipe_ultra_mod2.erl
deleted file mode 100644
index cec9c56a1e..0000000000
--- a/lib/hipe/opt/hipe_ultra_mod2.erl
+++ /dev/null
@@ -1,233 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% ULTRASPARC MACHINE MODEL
-%%
-%% This module is used by the scheduler.
-%% The following interface is used:
-%% ...
-%%
-%% NOTES:
-%% - the machine model is simple (on the verge of simplistic)
-%% * all FUs are pipelined => model only one cycle at a time
-%% * instruction latencies are mostly 1
-%% * floating point is left for later (I _think_ it works, but ...)
-%% - conservative: instructions that require multiple resources are
-%% modelled as 'single'; instead, they could reserve IEU+BR or whatever
-%% - possibly inefficient: I think machine state model could be turned into
-%% a bitvector.
-
--module(hipe_ultra_mod2).
--export([init_resources/1,
- init_instr_resources/2,
- resources_available/4,
- advance_cycle/1
- ]).
--export([raw_latency/2,
- war_latency/2,
- waw_latency/2,
- %% m_raw_latency/2,
- %% m_war_latency/2,
- %% m_waw_latency/2,
- m_raw_latency/0,
- m_war_latency/0,
- m_waw_latency/0,
- br_to_unsafe_latency/2,
- unsafe_to_br_latency/2,
- br_br_latency/2
- ]).
-
--include("../sparc/hipe_sparc.hrl").
-
--define(debug(Str,Args),ok).
-%-define(debug(Str,Args),io:format(Str,Args)).
-
--define(debug_ultra(Str,Args),ok).
-%-define(debug_ultra(Str,Args),io:format(Str,Args)).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Straightforward and somewhat simplistic model for UltraSparc:
-%% - only one cycle at a time is modelled
-%% - resources are simplified:
-%% * ieu0, ieu1, ieu, mem, br, single
-%% * per-cycle state = done | { I0, I1, NumI, X, Mem, Br }
-%% * unoptimized representation (could be bit vector)
-
-init_resources(_Size) ->
- ?debug_ultra('init res ~p~n',[_Size]),
- empty_state().
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-init_instr_resources(N,Nodes) ->
- ultra_instr_rsrcs(Nodes,hipe_vectors:new(N, '')).
-
-ultra_instr_rsrcs([],I_res) -> I_res;
-ultra_instr_rsrcs([N|Ns],I_res) ->
- ultra_instr_rsrcs(Ns,ultra_instr_type(N,I_res)).
-
-ultra_instr_type({N,I},I_res) ->
- hipe_vectors:set(I_res,N-1,instr_type(I)).
-
-instr_type(I) ->
- case I of
- #move{} ->
- ieu;
- #multimove{} -> %% TODO: expand multimoves before scheduling
- ieu;
- #alu{} ->
- case hipe_sparc:alu_operator(I) of
- '>>' -> ieu0;
- '<<' -> ieu0;
- _ -> ieu
- end;
- #alu_cc{} ->
- ieu1;
- #sethi{} ->
- ieu;
- #load{} ->
- mem;
- #store{} ->
- mem;
- #b{} ->
- br;
- #br{} ->
- br;
- #goto{} ->
- br;
- #jmp_link{} -> % imprecise; should be mem+br?
- single;
- #jmp{} -> % imprecise
- br;
- #call_link{} -> % imprecise; should be mem+br?
- single;
- #cmov_cc{} -> % imprecise
- single;
- #cmov_r{} -> % imprecise
- single;
- #load_atom{} -> % should be resolved to sethi/or
- single;
- #load_address{} -> % should be resolved to sethi/or
- single;
- #load_word_index{} -> % should be resolved to sethi/or
- single;
- %% uncommon types:
- #label{} ->
- none;
- #nop{} ->
- none;
- #comment{} ->
- none;
- _ ->
- exit({ultrasparc_instr_type,{cant_schedule,I}})
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-resources_available(_Cycle, I, Rsrc, I_res) ->
- res_avail(instruction_resource(I_res, I), Rsrc).
-
-instruction_resource(I_res, I) ->
- hipe_vectors:get(I_res, I-1).
-
-%% The following function checks resource availability.
-%% * all function units are assumed to be fully pipelined, so only
-%% one cycle at a time is modelled.
-%% * for IEU0 and IEU1, these must precede all generic IEU instructions
-%% (handled by X bit)
-%% * at most 2 integer instructions can issue in a cycle
-%% * mem is straightforward
-%% * br closes the cycle (= returns done).
-%% * single requires an entirely empty state and closes the cycle
-
-res_avail(ieu0, { free, I1, NumI, free, Mem, Br })
- when is_integer(NumI), NumI < 2 ->
- { yes, { occ, I1, NumI+1, free, Mem, Br }};
-res_avail(ieu1, { _I0, free, NumI, free, Mem, Br })
- when is_integer(NumI), NumI < 2 ->
- { yes, { free, occ, NumI+1, free, Mem, Br }};
-res_avail(ieu, { I0, I1, NumI, _X, Mem, Br })
- when is_integer(NumI), NumI < 2 ->
- { yes, { I0, I1, NumI+1, occ, Mem, Br }};
-res_avail(mem, { I0, I1, NumI, X, free, Br }) ->
- { yes, { I0, I1, NumI, X, occ, Br }};
-res_avail(br, { _I0, _I1, _NumI, _X, _Mem, free }) ->
- { yes, done };
-res_avail(single, { free, free, 0, free, free, free }) ->
- { yes, done };
-res_avail(_, _) ->
- no.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-advance_cycle(_Rsrc) ->
- empty_state().
-
-empty_state() -> { free, free, 0, free, free, free }.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Latencies are taken from UltraSparc hardware manual
-%%
-%% *** UNFINISHED ***
-%% more precisely, they are taken from my memory of the US-manual
-%% at the moment.
-%%
-%% Note: all ld/st are assumed to hit in the L1 cache (D-cache),
-%% which is sort of imprecise.
-
-raw_latency(alu, store) -> 0;
-raw_latency(load, _) -> 2; % only if load is L1 hit
-raw_latency(alu_cc, b) -> 0;
-raw_latency(_I0, _I1) ->
- 1.
-
-war_latency(_I0, _I1) ->
- 0.
-
-waw_latency(_I0, _I1) ->
- 1.
-
-%% *** UNFINISHED ***
-%% At present, all load/stores are assumed to hit in the L1 cache,
-%% which isn't really satisfying.
-
-%% m_raw_latency(_St, _Ld) ->
-%% 1.
-%%
-%% m_war_latency(_Ld, _St) ->
-%% 1.
-%%
-%% m_waw_latency(_St1, _St2) ->
-%% 1.
-
-%% Use these for 'default latencies' = do not permit reordering.
-
-m_raw_latency() ->
- 1.
-
-m_war_latency() ->
- 1.
-
-m_waw_latency() ->
- 1.
-
-br_to_unsafe_latency(_BrTy, _UTy) ->
- 0.
-
-unsafe_to_br_latency(_UTy, _BrTy) ->
- 0.
-
-br_br_latency(_BrTy1, _BrTy2) ->
- 0.
diff --git a/lib/hipe/opt/hipe_ultra_prio.erl b/lib/hipe/opt/hipe_ultra_prio.erl
deleted file mode 100644
index 6dd240a33a..0000000000
--- a/lib/hipe/opt/hipe_ultra_prio.erl
+++ /dev/null
@@ -1,298 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% PRIORITY HANDLING AND PRIORITY CALCULATION
-%%
-%% Handling of ready nodes and priorities.
-%% Priorities are mainly from the critical path. More priorities are added.
-%% * One version is adding priorities just depending on the instr, so
-%% for example loads get higher priority than stores, and ordered
-%% after reg's and offset for better cache performance.
-%% * The other version gives higher priority to a node that adds more new
-%% nodes to the ready list. This one is maybe not so effectively
-%% implemented, but was added too late for smarter solutions.
-%% One version is commented away
-
--module(hipe_ultra_prio).
--export([init_ready/2,
- init_instr_prio/2,
- %% initial_ready_set/4,
- next_ready/7,
- add_ready_nodes/2,
- insert_node/3
- ]).
-
--include("../sparc/hipe_sparc.hrl").
-
-% At first, only nodes with no predecessors are selected.
-% - if R is empty, there is an error (unless BB itself is empty)
-
-%% Arguments : Size - size of ready-array
-%% Preds - array with number of predecessors for each node
-%% Returns : An array with list of ready-nodes for each cycle.
-
-init_ready(Size, Preds) ->
- P = hipe_vectors:size(Preds),
- Ready = hipe_vectors:new(Size, []),
- R = initial_ready_set(1, P, Preds, []),
- hipe_vectors:set(Ready, 0, R).
-
-init_instr_prio(N, DAG) ->
- critical_path(N, DAG).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : initial_ready_set
-%% Argument : M - current node-index
-%% N - where to stop
-%% Preds - array with number of predecessors for each node
-%% Ready - list with ready-nodes
-%% Returns : Ready - list with ready-nodes
-%% Description : Finds all nodes with no predecessors and adds them to ready.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-initial_ready_set(M, N, Preds, Ready) ->
- if
- M > N ->
- Ready;
- true ->
- case hipe_vectors:get(Preds, M-1) of
- 0 ->
- initial_ready_set(M+1, N, Preds, [M|Ready]);
- V when is_integer(V), V > 0 ->
- initial_ready_set(M+1, N, Preds, Ready)
- end
- end.
-
-%% The following handles the nodes ready to schedule:
-%% 1. select the ready queue of given cycle
-%% 2. if queue empty, return none
-%% 3. otherwise, remove entry with highest priority
-%% and return {next,Highest_Prio,NewReady}
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : next_ready
-%% Argument : C - current cycle
-%% Ready - array with ready nodes
-%% Prio - array with cpath-priorities for all nodes
-%% Nodes - indexed list [{N, Instr}]
-%% Returns : none / {next,Highest_Prio,NewReady}
-%% Description : 1. select the ready queue of given cycle
-%% 2. if queue empty, return none
-%% 3. otherwise, remove entry with highest priority
-%% and return {next,Highest_Prio,NewReady} where Highest_Prio
-%% = Id of instr and NewReady = updated ready-array.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-next_ready(C, Ready, Prio, Nodes, DAG, Preds, Earl) ->
- Curr = hipe_vectors:get(Ready, C-1),
- case Curr of
- [] ->
- none;
- Instrs ->
- {BestI,RestIs} =
- get_best_instr(Instrs, Prio, Nodes, DAG, Preds, Earl, C),
- {next,BestI,hipe_vectors:set(Ready,C-1,RestIs)}
- end.
-
-% next_ready(C,Ready,Prio,Nodes) ->
-% Curr = hipe_vectors:get(Ready,C-1),
-% case Curr of
-% [] ->
-% none;
-% Instrs ->
-% {BestInstr,RestInstrs} = get_best_instr(Instrs, Prio, Nodes),
-% {next,BestInstr,hipe_vectors:set(Ready,C-1,RestInstrs)}
-% end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : get_best_instr
-%% Argument : Instrs - list of node-id's
-%% Prio - array with cpath-priorities for the nodes
-%% Nodes - indexed list [{Id, Instr}]
-%% Returns : {BestSoFar, Rest} - Id of best instr and the rest of id's
-%% Description : Returns the id of the instr that is the best choice.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-get_best_instr([Instr|Instrs], Prio, Nodes, DAG, Preds, Earl, C) ->
- get_best_instr(Instrs, [], Instr, Prio, Nodes, DAG, Preds, Earl, C).
-
-get_best_instr([], Rest, BestSoFar, _Prio, _Nodes, _DAG, _Preds, _Earl, _C) ->
- {BestSoFar, Rest};
-get_best_instr([Instr|Instrs], PassedInstrs, BestSoFar, Prio, Nodes,
- DAG, Preds, Earl, C) ->
- case better(Instr, BestSoFar, Prio, Nodes, DAG, Preds, Earl, C) of
- true ->
- get_best_instr(Instrs, [BestSoFar|PassedInstrs],
- Instr, Prio, Nodes, DAG, Preds, Earl, C);
- false ->
- get_best_instr(Instrs, [Instr|PassedInstrs], BestSoFar, Prio,
- Nodes, DAG, Preds, Earl, C)
- end.
-
-% get_best_instr([Instr|Instrs], Prio, Nodes) ->
-% get_best_instr(Instrs, [], Instr, Prio, Nodes).
-
-% get_best_instr([], Rest, BestSoFar, Prio, Nodes) -> {BestSoFar, Rest};
-% get_best_instr([Instr|Instrs], PassedInstrs, BestSoFar, Prio, Nodes) ->
-% case better(Instr, BestSoFar, Prio, Nodes) of
-% true ->
-% get_best_instr(Instrs, [BestSoFar|PassedInstrs],
-% Instr, Prio, Nodes);
-% false ->
-% get_best_instr(Instrs, [Instr|PassedInstrs],BestSoFar, Prio, Nodes)
-% end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : better
-%% Argument : Instr1 - Id of instr 1
-%% Instr2 - Id of instr 2
-%% Prio - array with cpath-priorities for the nodes
-%% Nodes - indexed list [{Id, Instr}]
-%% Returns : true if Instr1 has higher priority than Instr2
-%% Description : Checks if Instr1 is a better choice than Instr2 for scheduling
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-better(Instr1, Instr2, Prio, Nodes, DAG, Preds, Earl, C) ->
- better_hlp(priority(Instr1, Prio, Nodes, DAG, Preds, Earl, C),
- priority(Instr2, Prio, Nodes, DAG, Preds, Earl, C)).
-
-better_hlp([], []) -> false;
-better_hlp([], [_|_]) -> false;
-better_hlp([_|_], []) -> true;
-better_hlp([X|Xs], [Y|Ys]) -> (X > Y) or ((X =:= Y) and better_hlp(Xs,Ys)).
-
-%%
-%% Returns the instr corresponding to id
-%%
-get_instr(InstrId, [{InstrId,Instr}|_]) -> Instr;
-get_instr(InstrId, [_|Xs]) -> get_instr(InstrId, Xs).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : priority
-%% Argument : InstrId - Id
-%% Prio - array with cpath-priorities for the nodes
-%% Nodes - indexed list [{Id, Instr}]
-%% Returns : PrioList - list of priorities [MostSignificant, LessSign, ...]
-%% Description : Returns a list of priorities where the first element is the
-%% cpath-priority and the rest are added depending on what kind
-%% of instr it is. Used to order loads/stores sequentially and
-%% there is possibility to add whatever stuff...
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-priority(InstrId, Prio, Nodes, DAG, Preds, Earl, C) ->
- {ReadyNodes,_,_,_} = hipe_schedule:delete_node(C,InstrId,DAG,Preds,Earl),
- Instr = get_instr(InstrId, Nodes),
- Prio1 = hipe_vectors:get(Prio, InstrId-1),
- Prio2 = length(ReadyNodes),
- PrioRest =
- case Instr of
- #load_atom{} ->
- [3];
- #move{} ->
- [3];
- #load{} ->
- Src = hipe_sparc:load_src(Instr),
- Off = hipe_sparc:load_off(Instr),
- case hipe_sparc:is_reg(Off) of
- false -> [3,
- -(hipe_sparc:reg_nr(Src)),
- -(hipe_sparc:imm_value(Off))];
- true -> [1]
- end;
- #store{} ->
- Src = hipe_sparc:store_dest(Instr),
- Off = hipe_sparc:store_off(Instr),
- case hipe_sparc:is_reg(Off) of
- false -> [2,
- -(hipe_sparc:reg_nr(Src)),
- -(hipe_sparc:imm_value(Off))];
- true -> [1]
- end;
- _ -> [0]
- end,
- [Prio1,Prio2|PrioRest].
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : add_ready_nodes
-%% Argument : Nodes - list of [{Cycle,Id}]
-%% Ready - array of ready nodes for all cycles
-%% Returns : NewReady - updated ready-array
-%% Description : Gets a list of instrs and adds them to the ready-array
-%% to the corresponding cycle.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-add_ready_nodes([], Ready) -> Ready;
-add_ready_nodes([{C,I}|Xs], Ready) ->
- add_ready_nodes(Xs, insert_node(C, I, Ready)).
-
-insert_node(C, I, Ready) ->
- Old = hipe_vectors:get(Ready, C-1),
- hipe_vectors:set(Ready, C-1, [I|Old]).
-
-%%
-%% Computes the latency for the "most expensive" way through the graph
-%% for all nodes. Returns an array of priorities for all nodes.
-%%
-critical_path(N, DAG) ->
- critical_path(1, N, DAG, hipe_vectors:new(N, -1)).
-
-critical_path(M, N, DAG, Prio) ->
- if
- M > N ->
- Prio;
- true ->
- critical_path(M+1, N, DAG, cpath(M, DAG, Prio))
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Function : cpath
-%% Argument : M - current node id
-%% DAG - the dependence graph
-%% Prio - array of priorities for all nodes
-%% Returns : Prio - updated prio array
-%% Description : If node has prio -1, it has not been visited
-%% - otherwise, compute priority as max of priorities of
-%% successors (+ latency)
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-cpath(M, DAG, Prio) ->
- InitPrio = hipe_vectors:get(Prio, M-1),
- if
- InitPrio =:= -1 ->
- cpath_node(M, DAG, Prio);
- true ->
- Prio
- end.
-
-cpath_node(N, DAG, Prio) ->
- SuccL = dag_succ(DAG, N),
- {Max, NewPrio} = cpath_succ(SuccL, DAG, Prio),
- hipe_vectors:set(NewPrio, N-1, Max).
-
-cpath_succ(SuccL, DAG, Prio) ->
- cpath_succ(SuccL, DAG, Prio, 0).
-
-%% performs an unnecessary lookup of priority of Succ, but that might
-%% not be such a big deal
-
-cpath_succ([], _DAG, Prio, NodePrio) -> {NodePrio,Prio};
-cpath_succ([{Lat,Succ}|Xs], DAG, Prio, NodePrio) ->
- NewPrio = cpath(Succ, DAG, Prio),
- NewNodePrio = erlang:max(hipe_vectors:get(NewPrio, Succ - 1) + Lat, NodePrio),
- cpath_succ(Xs, DAG, NewPrio, NewNodePrio).
-
-dag_succ(DAG, N) when is_integer(N) ->
- hipe_vectors:get(DAG, N-1).
-
diff --git a/lib/hipe/rtl/Makefile b/lib/hipe/rtl/Makefile
index 5abc9ec049..0c0f6e24f5 100644
--- a/lib/hipe/rtl/Makefile
+++ b/lib/hipe/rtl/Makefile
@@ -50,7 +50,7 @@ HIPE_MODULES = hipe_rtl hipe_rtl_cfg \
hipe_rtl_ssa hipe_rtl_ssa_const_prop \
hipe_rtl_cleanup_const hipe_rtl_symbolic hipe_rtl_lcm \
hipe_rtl_ssapre hipe_rtl_binary hipe_rtl_ssa_avail_expr \
- hipe_rtl_arch hipe_tagscheme
+ hipe_rtl_arch hipe_tagscheme hipe_rtl_verify_gcsafe
else
HIPE_MODULES =
endif
@@ -75,7 +75,10 @@ TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
include ../native.mk
-ERL_COMPILE_FLAGS += -Werror +inline +warn_unused_import +warn_export_vars
+ERL_COMPILE_FLAGS += +inline +warn_unused_import +warn_export_vars
+ifneq ($(NATIVE_LIBS_ENABLED),yes)
+ERL_COMPILE_FLAGS += -Werror
+endif
# ----------------------------------------------------
# Targets
diff --git a/lib/hipe/rtl/hipe_icode2rtl.erl b/lib/hipe/rtl/hipe_icode2rtl.erl
index 6da8a76d34..1ab41f4deb 100644
--- a/lib/hipe/rtl/hipe_icode2rtl.erl
+++ b/lib/hipe/rtl/hipe_icode2rtl.erl
@@ -215,7 +215,7 @@ gen_enter(I, VarMap, ConstTab) ->
{Code1, ConstTab2} =
case hipe_icode:enter_type(I) of
primop ->
- IsGuard = false, % enter can not happen in a guard
+ IsGuard = false, % enter cannot happen in a guard
hipe_rtl_primops:gen_enter_primop({Fun, Args}, IsGuard, ConstTab1);
Type ->
Call = gen_enter_1(Fun, Args, Type),
diff --git a/lib/hipe/rtl/hipe_rtl.erl b/lib/hipe/rtl/hipe_rtl.erl
index 04c9728d5c..33027f3259 100644
--- a/lib/hipe/rtl/hipe_rtl.erl
+++ b/lib/hipe/rtl/hipe_rtl.erl
@@ -1740,7 +1740,10 @@ pp_reg(Dev, Arg) ->
true ->
pp_hard_reg(Dev, reg_index(Arg));
false ->
- io:format(Dev, "r~w", [reg_index(Arg)])
+ case reg_is_gcsafe(Arg) of
+ true -> io:format(Dev, "rs~w", [reg_index(Arg)]);
+ false -> io:format(Dev, "r~w", [reg_index(Arg)])
+ end
end.
pp_var(Dev, Arg) ->
diff --git a/lib/hipe/rtl/hipe_rtl_arith.inc b/lib/hipe/rtl/hipe_rtl_arith.inc
index c05b7aa160..575f10b542 100644
--- a/lib/hipe/rtl/hipe_rtl_arith.inc
+++ b/lib/hipe/rtl/hipe_rtl_arith.inc
@@ -118,8 +118,8 @@ eval_alu(Op, Arg1, Arg2) ->
%% Björn & Bjarni:
%% We need to be able to do evaluations based only on the bits, since
-%% there are cases where we can evaluate a subset of the bits, but can
-%% not do a full eval-alub call (eg. a + 0 gives no carry)
+%% there are cases where we can evaluate a subset of the bits, but
+%% cannot do a full eval-alub call (eg. a + 0 gives no carry)
%%
-spec eval_cond_bits(hipe_rtl:alub_cond(), boolean(),
boolean(), boolean(), boolean()) -> boolean().
diff --git a/lib/hipe/rtl/hipe_rtl_binary_construct.erl b/lib/hipe/rtl/hipe_rtl_binary_construct.erl
index ec7044a2b9..111dda3d82 100644
--- a/lib/hipe/rtl/hipe_rtl_binary_construct.erl
+++ b/lib/hipe/rtl/hipe_rtl_binary_construct.erl
@@ -363,7 +363,8 @@ not_writable_code(Bin, SizeReg, Dst, Base, Offset, Unit,
allocate_writable(Dst, Base, UsedBytes, TotBytes, TotSize) ->
Zero = hipe_rtl:mk_imm(0),
[NextLbl] = create_lbls(1),
- [EndSubSize, EndSubBitSize, ProcBin] = create_regs(3),
+ [EndSubSize, EndSubBitSize] = create_regs(2),
+ [ProcBin] = create_unsafe_regs(1),
[hipe_rtl:mk_call([Base], bs_allocate, [UsedBytes],
hipe_rtl:label_name(NextLbl), [], not_remote),
NextLbl,
@@ -590,12 +591,12 @@ const_init2(Size, Dst, Base, Offset, TrueLblName) ->
false ->
ByteSize = hipe_rtl:mk_new_reg(),
[hipe_rtl:mk_gctest(?PROC_BIN_WORDSIZE+?SUB_BIN_WORDSIZE),
- hipe_rtl:mk_move(Offset, hipe_rtl:mk_imm(0)),
hipe_rtl:mk_move(ByteSize, hipe_rtl:mk_imm(Size)),
hipe_rtl:mk_call([Base], bs_allocate, [ByteSize],
hipe_rtl:label_name(NextLbl), [], not_remote),
NextLbl,
hipe_tagscheme:create_refc_binary(Base, ByteSize, Dst),
+ hipe_rtl:mk_move(Offset, hipe_rtl:mk_imm(0)),
hipe_rtl:mk_goto(TrueLblName)]
end.
@@ -638,13 +639,12 @@ var_init2(Size, Dst, Base, Offset, TrueLblName, SystemLimitLblName, FalseLblName
Log2WordSize = hipe_rtl_arch:log2_word_size(),
WordSize = hipe_rtl_arch:word_size(),
[ContLbl, HeapLbl, REFCLbl, NextLbl] = create_lbls(4),
- [USize, Tmp] = create_unsafe_regs(2),
+ [USize, Tmp] = create_regs(2),
[get_word_integer(Size, USize, SystemLimitLblName, FalseLblName),
hipe_rtl:mk_branch(USize, leu, hipe_rtl:mk_imm(?MAX_BINSIZE),
hipe_rtl:label_name(ContLbl),
SystemLimitLblName),
ContLbl,
- hipe_rtl:mk_move(Offset, hipe_rtl:mk_imm(0)),
hipe_rtl:mk_branch(USize, leu, hipe_rtl:mk_imm(?MAX_HEAP_BIN_SIZE),
hipe_rtl:label_name(HeapLbl),
hipe_rtl:label_name(REFCLbl)),
@@ -654,6 +654,7 @@ var_init2(Size, Dst, Base, Offset, TrueLblName, SystemLimitLblName, FalseLblName
hipe_rtl:mk_alu(Tmp, Tmp, add, hipe_rtl:mk_imm(?SUB_BIN_WORDSIZE)),
hipe_rtl:mk_gctest(Tmp),
hipe_tagscheme:create_heap_binary(Base, USize, Dst),
+ hipe_rtl:mk_move(Offset, hipe_rtl:mk_imm(0)),
hipe_rtl:mk_goto(TrueLblName),
REFCLbl,
hipe_rtl:mk_gctest(?PROC_BIN_WORDSIZE+?SUB_BIN_WORDSIZE),
@@ -661,6 +662,7 @@ var_init2(Size, Dst, Base, Offset, TrueLblName, SystemLimitLblName, FalseLblName
hipe_rtl:label_name(NextLbl), [], not_remote),
NextLbl,
hipe_tagscheme:create_refc_binary(Base, USize, Dst),
+ hipe_rtl:mk_move(Offset, hipe_rtl:mk_imm(0)),
hipe_rtl:mk_goto(TrueLblName)].
var_init_bits(Size, Dst, Base, Offset, TrueLblName, SystemLimitLblName, FalseLblName) ->
@@ -867,7 +869,7 @@ get_base_offset_size(Binary, SrcBase, SrcOffset, SrcSize, FLName) ->
JoinLbl,
hipe_tagscheme:test_heap_binary(Orig, HeapLblName, REFCLblName),
HeapLbl,
- hipe_rtl:mk_alu(SrcBase, Orig, add, hipe_rtl:mk_imm(?HEAP_BIN_DATA-2)),
+ hipe_tagscheme:get_field_addr_from_term({heap_bin, {data, 0}}, Orig, SrcBase),
hipe_rtl:mk_goto(EndLblName),
REFCLbl,
hipe_tagscheme:get_field_from_term({proc_bin,bytes}, Orig, SrcBase),
@@ -1214,6 +1216,12 @@ is_divisible(Dividend, Divisor, SuccLbl, FailLbl) ->
[hipe_rtl:mk_branch(Dividend, 'and', Mask, eq, SuccLbl, FailLbl, 0.99)];
false ->
%% We need division, fall back to a primop
- [hipe_rtl:mk_call([], is_divisible, [Dividend, hipe_rtl:mk_imm(Divisor)],
- SuccLbl, FailLbl, not_remote)]
+ [Tmp] = create_regs(1),
+ RetLbl = hipe_rtl:mk_new_label(),
+ [hipe_rtl:mk_call([Tmp], is_divisible,
+ [Dividend, hipe_rtl:mk_imm(Divisor)],
+ hipe_rtl:label_name(RetLbl), [], not_remote),
+ RetLbl,
+ hipe_rtl:mk_branch(Tmp, ne, hipe_rtl:mk_imm(0),
+ SuccLbl, FailLbl, 0.99)]
end.
diff --git a/lib/hipe/rtl/hipe_rtl_binary_match.erl b/lib/hipe/rtl/hipe_rtl_binary_match.erl
index 362a52f8fe..4575213838 100644
--- a/lib/hipe/rtl/hipe_rtl_binary_match.erl
+++ b/lib/hipe/rtl/hipe_rtl_binary_match.erl
@@ -730,7 +730,7 @@ get_base(Orig,Base) ->
[hipe_tagscheme:test_heap_binary(Orig, hipe_rtl:label_name(HeapLbl),
hipe_rtl:label_name(REFCLbl)),
HeapLbl,
- hipe_rtl:mk_alu(Base, Orig, 'add', hipe_rtl:mk_imm(?HEAP_BIN_DATA-2)),
+ hipe_tagscheme:get_field_addr_from_term({heap_bin, {data, 0}}, Orig, Base),
hipe_rtl:mk_goto(hipe_rtl:label_name(EndLbl)),
REFCLbl,
get_field_from_term({proc_bin, flags}, Orig, Flags),
@@ -740,7 +740,7 @@ get_base(Orig,Base) ->
WritableLbl,
hipe_rtl:mk_call([], emasculate_binary, [Orig], [], [], 'not_remote'),
NotWritableLbl,
- hipe_rtl:mk_load(Base, Orig, hipe_rtl:mk_imm(?PROC_BIN_BYTES-2)),
+ get_field_from_term({proc_bin, bytes}, Orig, Base),
EndLbl].
extract_matchstate_var(binsize, Ms) ->
@@ -842,12 +842,12 @@ make_dyn_prep(SizeReg, CCode) ->
%%------------------------------------------------------------------------
get_unaligned_int(Dst1, Size, Base, Offset, Shiftr, Type, TrueLblName) ->
- [Reg] = create_regs(1),
+ [Reg] = create_gcsafe_regs(1),
[get_maybe_unaligned_int_to_reg(Reg, Size, Base, Offset, Shiftr, Type),
do_bignum_code(Size, Type, Reg, Dst1, TrueLblName)].
get_maybe_unaligned_int_to_reg(Reg, Size, Base, Offset, Shiftr, Type) ->
- [LowBits] = create_regs(1),
+ [LowBits] = create_gcsafe_regs(1),
[AlignedLbl, UnAlignedLbl, EndLbl] = create_lbls(3),
[hipe_rtl:mk_alub(LowBits, Offset, 'and', hipe_rtl:mk_imm(?LOW_BITS),
eq, hipe_rtl:label_name(AlignedLbl),
@@ -1001,7 +1001,7 @@ do_bignum_code(Size, {Signedness,_}, Src, Dst1, TrueLblName)
end.
signed_bignum(Dst1, Src, TrueLblName) ->
- Tmp1 = hipe_rtl:mk_new_reg(),
+ Tmp1 = hipe_rtl:mk_new_reg_gcsafe(),
BignumLabel = hipe_rtl:mk_new_label(),
[hipe_tagscheme:realtag_fixnum(Dst1, Src),
hipe_tagscheme:realuntag_fixnum(Tmp1, Dst1),
diff --git a/lib/hipe/rtl/hipe_rtl_cleanup_const.erl b/lib/hipe/rtl/hipe_rtl_cleanup_const.erl
index bfa6b9682e..00cc2bcb37 100644
--- a/lib/hipe/rtl/hipe_rtl_cleanup_const.erl
+++ b/lib/hipe/rtl/hipe_rtl_cleanup_const.erl
@@ -69,9 +69,9 @@ cleanup_instr([Const|Left], I, Acc) ->
case I of
X when is_record(X, fp_unop) orelse is_record(X, fp) ->
Fdst = hipe_rtl:mk_new_fpreg(),
- Fconv = hipe_tagscheme:unsafe_untag_float(Fdst, Dst),
+ Fconv = lists:flatten(hipe_tagscheme:unsafe_untag_float(Fdst, Dst)),
NewI = hipe_rtl:subst_uses([{Const, Fdst}], I),
- cleanup_instr(Left, NewI, Fconv ++ [Load|Acc]);
+ cleanup_instr(Left, NewI, lists:reverse(Fconv, [Load|Acc]));
_ ->
NewI = hipe_rtl:subst_uses([{Const, Dst}], I),
cleanup_instr(Left, NewI, [Load|Acc])
diff --git a/lib/hipe/rtl/hipe_rtl_lcm.erl b/lib/hipe/rtl/hipe_rtl_lcm.erl
index 9dcdd05fb1..2c8cc80e56 100644
--- a/lib/hipe/rtl/hipe_rtl_lcm.erl
+++ b/lib/hipe/rtl/hipe_rtl_lcm.erl
@@ -182,42 +182,41 @@ delete_exprs(Code, _, _, []) ->
Code;
delete_exprs(Code, ExprMap, IdMap, [ExprId|Exprs]) ->
Expr = expr_id_map_get_expr(IdMap, ExprId),
- %% Perform a foldl that goes through the code and deletes all
- %% occurences of the expression.
- NewCode =
- lists:reverse
- (lists:foldl(fun(CodeExpr, Acc) ->
- case is_expr(CodeExpr) of
- true ->
- case expr_clear_dst(CodeExpr) =:= Expr of
- true ->
- pp_debug(" Deleting: ", []),
- pp_debug_instr(CodeExpr),
- %% Lookup expression entry.
- Defines =
- case expr_map_lookup(ExprMap, Expr) of
- {value, {_, _, Defs}} ->
- Defs;
- none ->
- exit({?MODULE, expr_map_lookup,
- "expression missing"})
- end,
- MoveCode =
- mk_expr_move_instr(hipe_rtl:defines(CodeExpr),
- Defines),
- pp_debug(" Replacing with: ", []),
- pp_debug_instr(MoveCode),
- [MoveCode|Acc];
- false ->
- [CodeExpr|Acc]
- end;
- false ->
- [CodeExpr|Acc]
- end
- end,
- [], Code)),
+ %% Lookup expression entry.
+ {value, {_, _, Defines}} = expr_map_lookup(ExprMap, Expr),
+ %% Go through the code and deletes all occurences of the expression.
+ NewCode = delete_expr(Code, Expr, Defines, []),
delete_exprs(NewCode, ExprMap, IdMap, Exprs).
+delete_expr([], _Expr, _Defines, Acc) -> lists:reverse(Acc);
+delete_expr([CodeExpr|Code], Expr, Defines, Acc) ->
+ case exp_kill_expr(CodeExpr, [Expr]) of
+ [] -> % Expr was killed; deleting stops here
+ pp_debug(" Stopping before: ", []),
+ pp_debug_instr(CodeExpr),
+ lists:reverse(Acc, [CodeExpr|Code]);
+ [Expr] ->
+ NewCodeExpr =
+ case is_expr(CodeExpr) of
+ true ->
+ case expr_clear_dst(CodeExpr) =:= Expr of
+ true ->
+ pp_debug(" Deleting: ", []),
+ pp_debug_instr(CodeExpr),
+ MoveCode = mk_expr_move_instr(hipe_rtl:defines(CodeExpr),
+ Defines),
+ pp_debug(" Replacing with: ", []),
+ pp_debug_instr(MoveCode),
+ MoveCode;
+ false ->
+ CodeExpr
+ end;
+ false ->
+ CodeExpr
+ end,
+ delete_expr(Code, Expr, Defines, [NewCodeExpr|Acc])
+ end.
+
%%=============================================================================
%% Goes through the given list of expressions and inserts them at
%% appropriate places in the code.
@@ -226,13 +225,12 @@ insert_exprs(CFG, _, _, _, _, BetweenMap, []) ->
insert_exprs(CFG, Pred, Succ, ExprMap, IdMap, BetweenMap, [ExprId|Exprs]) ->
Expr = expr_id_map_get_expr(IdMap, ExprId),
Instr = expr_map_get_instr(ExprMap, Expr),
- case hipe_rtl_cfg:succ(CFG, Pred) of
- [_] ->
+ case try_insert_expr_last(CFG, Pred, Instr) of
+ {ok, NewCFG} ->
pp_debug(" Inserted last: ", []),
pp_debug_instr(Instr),
- NewCFG = insert_expr_last(CFG, Pred, Instr),
insert_exprs(NewCFG, Pred, Succ, ExprMap, IdMap, BetweenMap, Exprs);
- _ ->
+ not_safe ->
case hipe_rtl_cfg:pred(CFG, Succ) of
[_] ->
pp_debug(" Inserted first: ", []),
@@ -252,25 +250,34 @@ insert_exprs(CFG, Pred, Succ, ExprMap, IdMap, BetweenMap, [ExprId|Exprs]) ->
%% Recursively goes through the code in a block and returns a new block
%% with the new code inserted second to last (assuming the last expression
%% is a branch operation).
-insert_expr_last(CFG0, Label, Instr) ->
- Code0 = hipe_bb:code(hipe_rtl_cfg:bb(CFG0, Label)),
- %% FIXME: Use hipe_bb:butlast() instead?
- Code1 = insert_expr_last_work(Label, Instr, Code0),
- hipe_rtl_cfg:bb_add(CFG0, Label, hipe_bb:mk_bb(Code1)).
+try_insert_expr_last(CFG0, Label, Instr) ->
+ case hipe_rtl_cfg:succ(CFG0, Label) of
+ [_] ->
+ Code0 = hipe_bb:code(hipe_rtl_cfg:bb(CFG0, Label)),
+ case insert_expr_last_work(Instr, Code0) of
+ not_safe -> not_safe;
+ Code1 ->
+ {ok, hipe_rtl_cfg:bb_add(CFG0, Label, hipe_bb:mk_bb(Code1))}
+ end;
+ _ -> not_safe
+ end.
%%=============================================================================
%% Recursively goes through the code in a block and returns a new block
%% with the new code inserted second to last (assuming the last expression
%% is a branch operation).
-insert_expr_last_work(_, Instr, []) ->
- %% This case should not happen since this means that block was completely
- %% empty when the function was called. For compatibility we insert it last.
- [Instr];
-insert_expr_last_work(_, Instr, [Code1]) ->
+insert_expr_last_work(_Instr, [#call{}]) ->
+ %% Call instructions clobber all expressions; we must not insert the
+ %% expression before it
+ not_safe;
+insert_expr_last_work(Instr, [Code1]) ->
%% We insert the code next to last.
[Instr, Code1];
-insert_expr_last_work(Label, Instr, [Code|Codes]) ->
- [Code|insert_expr_last_work(Label, Instr, Codes)].
+insert_expr_last_work(Instr, [Code|Codes]) ->
+ case insert_expr_last_work(Instr, Codes) of
+ not_safe -> not_safe;
+ NewCodes -> [Code|NewCodes]
+ end.
%%=============================================================================
%% Inserts expression first in the block for the given label.
@@ -305,7 +312,8 @@ insert_expr_between(CFG0, BetweenMap, Pred, Succ, Instr) ->
{value, Label} ->
pp_debug(" Using existing new bb for edge (~w,~w) with label ~w~n",
[Pred, Succ, Label]),
- {insert_expr_last(CFG0, Label, Instr), BetweenMap}
+ {ok, NewCfg} = try_insert_expr_last(CFG0, Label, Instr),
+ {NewCfg, BetweenMap}
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/hipe/rtl/hipe_rtl_primops.erl b/lib/hipe/rtl/hipe_rtl_primops.erl
index 850a75f71b..ce5433379e 100644
--- a/lib/hipe/rtl/hipe_rtl_primops.erl
+++ b/lib/hipe/rtl/hipe_rtl_primops.erl
@@ -291,6 +291,10 @@ gen_primop({Op,Dst,Args,Cont,Fail}, IsGuard, ConstTab) ->
gen_select_msg(Dst, Cont);
clear_timeout ->
gen_clear_timeout(Dst, GotoCont);
+ recv_mark ->
+ gen_recv_mark(Dst, GotoCont);
+ recv_set ->
+ gen_recv_set(Dst, Cont);
set_timeout ->
%% BIF call: am_set_timeout -> nbif_set_timeout -> hipe_set_timeout
[hipe_rtl:mk_call(Dst, set_timeout, Args, Cont, Fail, not_remote)];
@@ -390,6 +394,10 @@ gen_primop({Op,Dst,Args,Cont,Fail}, IsGuard, ConstTab) ->
end;
debug_native_called ->
[hipe_rtl:mk_call(Dst, Op, Args, Cont, Fail, not_remote)];
+ build_stacktrace ->
+ [hipe_rtl:mk_call(Dst, Op, Args, Cont, Fail, not_remote)];
+ raw_raise ->
+ [hipe_rtl:mk_call(Dst, Op, Args, Cont, Fail, not_remote)];
%% Only names listed above are accepted! MFA:s are not primops!
_ ->
@@ -1064,6 +1072,27 @@ gen_tuple_header(Ptr, Arity) ->
%%%
%%% Receives
+%%% recv_mark is:
+%%% p->msg.saved_last = p->msg.last;
+gen_recv_mark([], GotoCont) ->
+ TmpLast = hipe_rtl:mk_new_reg(),
+ [load_p_field(TmpLast, ?P_MSG_LAST),
+ store_p_field(TmpLast, ?P_MSG_SAVED_LAST),
+ GotoCont].
+
+%%% recv_set is:
+%%% if (p->msg.saved_last)
+%%% p->msg.save = p->msg.saved_last;
+gen_recv_set([], Cont) ->
+ TmpSave = hipe_rtl:mk_new_reg(),
+ TrueLbl = hipe_rtl:mk_new_label(),
+ [load_p_field(TmpSave, ?P_MSG_SAVED_LAST),
+ hipe_rtl:mk_branch(TmpSave, ne, hipe_rtl:mk_imm(0),
+ hipe_rtl:label_name(TrueLbl), Cont),
+ TrueLbl,
+ store_p_field(TmpSave, ?P_MSG_SAVE),
+ hipe_rtl:mk_goto(Cont)].
+
gen_check_get_msg(Dsts, GotoCont, Fail) ->
gen_check_get_msg_outofline(Dsts, GotoCont, Fail).
diff --git a/lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl b/lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl
index cad43e2df5..72373e536d 100644
--- a/lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl
+++ b/lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl
@@ -31,11 +31,11 @@
%%
%% Some things to note:
%%
-%% 1. All precoloured registers are assumed to contain bottom. We can not
+%% 1. All precoloured registers are assumed to contain bottom. We cannot
%% do anything with them since they are not in SSA-form. This might be
%% possible to resolve in some way, but we decided to not go there.
%%
-%% 2. const_labels are assumed to be bottom, we can not find the address
+%% 2. const_labels are assumed to be bottom, we cannot find the address
%% in any nice way (that I know of, maybe someone can help ?). I
%% suppose they don't get a value until linking (or some step that
%% resembles it). They are only affecting bignums and floats (at least
@@ -579,7 +579,7 @@ visit_multimove(Inst, Env) ->
%% Procedure : visit_call/2
%% Purpose : execute a call-instruction. All calls return bottom. We make
%% this assumption since the icode-leel have taken care of BIF's
-%% and we belive that we are left with the things that can not be
+%% and we belive that we are left with the things that cannot be
%% done att compile time.
%% Arguments : Inst - The instruction
%% Env - The environment
diff --git a/lib/hipe/rtl/hipe_rtl_varmap.erl b/lib/hipe/rtl/hipe_rtl_varmap.erl
index 375a8f85c0..f34c66ab85 100644
--- a/lib/hipe/rtl/hipe_rtl_varmap.erl
+++ b/lib/hipe/rtl/hipe_rtl_varmap.erl
@@ -105,7 +105,7 @@ icode_var2rtl_var(Var, Map) ->
{reg, IsGcSafe} ->
NewVar =
case IsGcSafe of
- %% true -> hipe_rtl:mk_new_reg_gcsafe();
+ true -> hipe_rtl:mk_new_reg_gcsafe();
false -> hipe_rtl:mk_new_reg()
end,
{NewVar, insert(Var, NewVar, Map)}
diff --git a/lib/hipe/rtl/hipe_rtl_verify_gcsafe.erl b/lib/hipe/rtl/hipe_rtl_verify_gcsafe.erl
new file mode 100644
index 0000000000..01d7e89ccd
--- /dev/null
+++ b/lib/hipe/rtl/hipe_rtl_verify_gcsafe.erl
@@ -0,0 +1,89 @@
+%% -*- mode: erlang; erlang-indent-level: 2 -*-
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+-module(hipe_rtl_verify_gcsafe).
+
+-export([check/1]).
+
+-include("../flow/cfg.hrl"). %% needed for the specs
+-include("hipe_rtl.hrl").
+
+check(CFG) ->
+ Liveness = hipe_rtl_liveness:analyze(CFG),
+ put({?MODULE, 'fun'}, CFG#cfg.info#cfg_info.'fun'),
+ lists:foreach(
+ fun(Lb) ->
+ put({?MODULE, label}, Lb),
+ Liveout = hipe_rtl_liveness:liveout(Liveness, Lb),
+ BB = hipe_rtl_cfg:bb(CFG, Lb),
+ check_instrs(lists:reverse(hipe_bb:code(BB)), Liveout)
+ end, hipe_rtl_cfg:labels(CFG)),
+ erase({?MODULE, 'fun'}),
+ erase({?MODULE, label}),
+ erase({?MODULE, instr}),
+ ok.
+
+check_instrs([], _Livein) -> ok;
+check_instrs([I|Is], LiveOut) ->
+ Def = ordsets:from_list(hipe_rtl:defines(I)),
+ Use = ordsets:from_list(hipe_rtl:uses(I)),
+ LiveOver = ordsets:subtract(LiveOut, Def),
+ LiveIn = ordsets:union(LiveOver, Use),
+ case (hipe_rtl:is_call(I)
+ andalso not safe_primop(hipe_rtl:call_fun(I)))
+ orelse is_record(I, gctest)
+ of
+ false -> ok;
+ true ->
+ put({?MODULE, instr}, I),
+ lists:foreach(fun verify_live/1, LiveOver)
+ end,
+ check_instrs(Is, LiveIn).
+
+verify_live(T) ->
+ case hipe_rtl:is_reg(T) of
+ false -> ok;
+ true ->
+ case hipe_rtl:reg_is_gcsafe(T) of
+ true -> ok;
+ false ->
+ error({gcunsafe_live_over_call,
+ get({?MODULE, 'fun'}),
+ {label, get({?MODULE, label})},
+ get({?MODULE, instr}),
+ T})
+ end
+ end.
+
+%% Primops that can't gc
+%% Note: This information is essentially duplicated from hipe_bif_list.m4
+safe_primop(is_divisible) -> true;
+safe_primop(is_unicode) -> true;
+safe_primop(cmp_2) -> true;
+safe_primop(eq_2) -> true;
+safe_primop(bs_allocate) -> true;
+safe_primop(bs_reallocate) -> true;
+safe_primop(bs_utf8_size) -> true;
+safe_primop(bs_get_utf8) -> true;
+safe_primop(bs_put_utf8) -> true;
+safe_primop(bs_utf16_size) -> true;
+safe_primop(bs_get_utf16) -> true;
+safe_primop(bs_validate_unicode_retract) -> true;
+safe_primop(bs_put_small_float) -> true;
+safe_primop(bs_put_bits) -> true;
+safe_primop(emasculate_binary) -> true;
+safe_primop(atomic_inc) -> true;
+%% Not noproc but manually verified
+safe_primop(bs_put_big_integer) -> true;
+safe_primop(_) -> false.
diff --git a/lib/hipe/rtl/hipe_tagscheme.erl b/lib/hipe/rtl/hipe_tagscheme.erl
index 68cbe75e85..737f0ec5e3 100644
--- a/lib/hipe/rtl/hipe_tagscheme.erl
+++ b/lib/hipe/rtl/hipe_tagscheme.erl
@@ -53,7 +53,8 @@
-export([test_subbinary/3, test_heap_binary/3]).
-export([create_heap_binary/3, create_refc_binary/3, create_refc_binary/4]).
-export([create_matchstate/6, convert_matchstate/1, compare_matchstate/4]).
--export([get_field_from_term/3, get_field_from_pointer/3,
+-export([get_field_addr_from_term/3,
+ get_field_from_term/3, get_field_from_pointer/3,
set_field_from_term/3, set_field_from_pointer/3,
extract_matchbuffer/2, extract_binary_bytes/2]).
@@ -76,6 +77,10 @@
-define(TAG_PRIMARY_BOXED, 16#2).
-define(TAG_PRIMARY_IMMED1, 16#3).
+%% Only when ?ERTS_USE_LITERAL_TAG =:= 1
+-define(TAG_PTR_MASK__, 16#7).
+-define(TAG_LITERAL_PTR, 16#4).
+
-define(TAG_IMMED1_SIZE, 4).
-define(TAG_IMMED1_MASK, 16#F).
-define(TAG_IMMED1_PID, ((16#0 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_IMMED1)).
@@ -157,6 +162,38 @@ tag_cons(Res, X) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ptr_val(Res, X) ->
+ hipe_rtl:mk_alu(Res, X, 'and', hipe_rtl:mk_imm(bnot ?TAG_PTR_MASK__)).
+
+%% Returns {Base, Offset, Untag}. To be used like, for example:
+%% {Base, Offset, Untag} = untag_ptr(X, ?TAG_PRIMARY_BOXED),
+%% ...
+%% [Untag, hipe_rtl:mk_load(Dst, Base, hipe_rtl:mk_imm(Offset))].
+%%
+%% NB: Base might either be X or a new temp. It must thus not be modified.
+untag_ptr(X, Tag) ->
+ case ?ERTS_USE_LITERAL_TAG of
+ 0 ->
+ {X, -Tag, []};
+ 1 ->
+ Base = hipe_rtl:mk_new_reg(),
+ Untag = ptr_val(Base, X),
+ {Base, 0, Untag}
+ end.
+
+untag_ptr_nooffset(Dst, X, Tag) ->
+ %% We could just use ptr_val in all cases, but subtraction can use LEA on x86
+ %% and can be inlined into effective address computations on several
+ %% architectures.
+ case ?ERTS_USE_LITERAL_TAG of
+ 0 ->
+ hipe_rtl:mk_alu(Dst, X, 'sub', hipe_rtl:mk_imm(Tag));
+ 1 ->
+ ptr_val(Dst, X)
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
%%% Operations to test if an object has a known type T.
test_nil(X, TrueLab, FalseLab, Pred) ->
@@ -171,7 +208,8 @@ test_is_boxed(X, TrueLab, FalseLab, Pred) ->
hipe_rtl:mk_branch(X, 'and', Mask, 'eq', TrueLab, FalseLab, Pred).
get_header(Res, X) ->
- hipe_rtl:mk_load(Res, X, hipe_rtl:mk_imm(-(?TAG_PRIMARY_BOXED))).
+ {Base, Offset, Untag} = untag_ptr(X, ?TAG_PRIMARY_BOXED),
+ [Untag, hipe_rtl:mk_load(Res, Base, hipe_rtl:mk_imm(Offset))].
mask_and_compare(X, Mask, Value, TrueLab, FalseLab, Pred) ->
Tmp = hipe_rtl:mk_new_reg_gcsafe(),
@@ -617,21 +655,25 @@ test_either_immed(Arg1, Arg2, TrueLab, FalseLab) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
unsafe_car(Dst, Arg) ->
- hipe_rtl:mk_load(Dst, Arg, hipe_rtl:mk_imm(-(?TAG_PRIMARY_LIST))).
+ {Base, Offset, Untag} = untag_ptr(Arg, ?TAG_PRIMARY_LIST),
+ [Untag, hipe_rtl:mk_load(Dst, Base, hipe_rtl:mk_imm(Offset))].
unsafe_cdr(Dst, Arg) ->
+ {Base, Offset, Untag} = untag_ptr(Arg, ?TAG_PRIMARY_LIST),
WordSize = hipe_rtl_arch:word_size(),
- hipe_rtl:mk_load(Dst, Arg, hipe_rtl:mk_imm(-(?TAG_PRIMARY_LIST)+WordSize)).
+ [Untag, hipe_rtl:mk_load(Dst, Base, hipe_rtl:mk_imm(Offset+WordSize))].
unsafe_constant_element(Dst, Index, Tuple) -> % Index is an immediate
WordSize = hipe_rtl_arch:word_size(),
- Offset = -(?TAG_PRIMARY_BOXED) + WordSize * hipe_rtl:imm_value(Index),
- hipe_rtl:mk_load(Dst, Tuple, hipe_rtl:mk_imm(Offset)).
+ {Base, Offset0, Untag} = untag_ptr(Tuple, ?TAG_PRIMARY_BOXED),
+ Offset = Offset0 + WordSize * hipe_rtl:imm_value(Index),
+ [Untag, hipe_rtl:mk_load(Dst, Base, hipe_rtl:mk_imm(Offset))].
unsafe_update_element(Tuple, Index, Value) -> % Index is an immediate
WordSize = hipe_rtl_arch:word_size(),
- Offset = -(?TAG_PRIMARY_BOXED) + WordSize * hipe_rtl:imm_value(Index),
- hipe_rtl:mk_store(Tuple, hipe_rtl:mk_imm(Offset), Value).
+ {Base, Offset0, Untag} = untag_ptr(Tuple, ?TAG_PRIMARY_BOXED),
+ Offset = Offset0 + WordSize * hipe_rtl:imm_value(Index),
+ [Untag, hipe_rtl:mk_store(Base, hipe_rtl:mk_imm(Offset), Value)].
%%% wrong semantics
%% unsafe_variable_element(Dst, Index, Tuple) -> % Index is an unknown fixnum
@@ -644,10 +686,12 @@ unsafe_update_element(Tuple, Index, Value) -> % Index is an immediate
%% Tmp1 = hipe_rtl:mk_new_reg_gcsafe(),
%% Tmp2 = hipe_rtl:mk_new_reg_gcsafe(),
%% Shift = ?TAG_IMMED1_SIZE - 2,
-%% OffAdj = (?TAG_IMMED1_SMALL bsr Shift) + ?TAG_PRIMARY_BOXED,
+%% {Base, Off0, Untag} = untag_ptr(Tuple, ?TAG_PRIMARY_BOXED),
+%% OffAdj = (?TAG_IMMED1_SMALL bsr Shift) - Off0,
%% [hipe_rtl:mk_alu(Tmp1, Index, 'srl', hipe_rtl:mk_imm(Shift)),
%% hipe_rtl:mk_alu(Tmp2, Tmp1, 'sub', hipe_rtl:mk_imm(OffAdj)),
-%% hipe_rtl:mk_load(Dst, Tuple, Tmp2)].
+%% Untag,
+%% hipe_rtl:mk_load(Base, Tuple, Tmp2)].
element(Dst, Index, Tuple, FailLabName, {tuple, A}, IndexInfo) ->
FixnumOkLab = hipe_rtl:mk_new_label(),
@@ -660,7 +704,7 @@ element(Dst, Index, Tuple, FailLabName, {tuple, A}, IndexInfo) ->
Offset = hipe_rtl:mk_new_reg_gcsafe(),
Ptr = hipe_rtl:mk_new_reg(), % offset from Tuple
[untag_fixnum(UIndex, Index),
- hipe_rtl:mk_alu(Ptr, Tuple, 'sub', hipe_rtl:mk_imm(?TAG_PRIMARY_BOXED)),
+ untag_ptr_nooffset(Ptr, Tuple, ?TAG_PRIMARY_BOXED),
hipe_rtl:mk_alu(Offset, UIndex, 'sll',
hipe_rtl:mk_imm(hipe_rtl_arch:log2_word_size())),
hipe_rtl:mk_load(Dst, Ptr, Offset)];
@@ -769,7 +813,7 @@ gen_element_tail(Dst, Tuple, Arity, UIndex, FailLabName, IndexOkLab) ->
hipe_rtl:mk_branch(ZeroIndex, 'geu', Arity, FailLabName,
hipe_rtl:label_name(IndexOkLab), 0.01),
IndexOkLab,
- hipe_rtl:mk_alu(Ptr, Tuple, 'sub', hipe_rtl:mk_imm(?TAG_PRIMARY_BOXED)),
+ untag_ptr_nooffset(Ptr, Tuple, ?TAG_PRIMARY_BOXED),
hipe_rtl:mk_alu(Offset, UIndex, 'sll',
hipe_rtl:mk_imm(hipe_rtl_arch:log2_word_size())),
hipe_rtl:mk_load(Dst, Ptr, Offset)].
@@ -777,11 +821,13 @@ gen_element_tail(Dst, Tuple, Arity, UIndex, FailLabName, IndexOkLab) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
unsafe_closure_element(Dst, Index, Closure) -> % Index is an immediate
- Offset = -(?TAG_PRIMARY_BOXED) %% Untag
+ %% XXX: Can there even be closure literals?
+ {Base, Offset0, Untag} = untag_ptr(Closure, ?TAG_PRIMARY_BOXED),
+ Offset = Offset0 %% Untag
+ ?EFT_ENV %% Field offset
%% Index from 1 to N hence -1)
+ (hipe_rtl_arch:word_size() * (hipe_rtl:imm_value(Index)-1)),
- hipe_rtl:mk_load(Dst, Closure, hipe_rtl:mk_imm(Offset)).
+ [Untag, hipe_rtl:mk_load(Dst, Base, hipe_rtl:mk_imm(Offset))].
mk_fun_header() ->
hipe_rtl:mk_imm(?HEADER_FUN).
@@ -790,7 +836,7 @@ tag_fun(Res, X) ->
tag_boxed(Res, X).
%% untag_fun(Res, X) ->
-%% hipe_rtl:mk_alu(Res, X, 'sub', hipe_rtl:mk_imm(?TAG_PRIMARY_BOXED)).
+%% untag_ptr_nooffset(Res, X, ?TAG_PRIMARY_BOXED).
if_fun_get_arity_and_address(ArityReg, AddressReg, FunP, BadFunLab, Pred) ->
%% EmuAddressPtrReg = hipe_rtl:mk_new_reg(),
@@ -801,15 +847,15 @@ if_fun_get_arity_and_address(ArityReg, AddressReg, FunP, BadFunLab, Pred) ->
TrueLab0 = hipe_rtl:mk_new_label(),
%% TrueLab1 = hipe_rtl:mk_new_label(),
IsFunCode = test_closure(FunP, hipe_rtl:label_name(TrueLab0), BadFunLab, Pred),
+ {Base, Offset, Untag} = untag_ptr(FunP, ?TAG_PRIMARY_BOXED),
GetArityCode =
[TrueLab0,
%% Funp->arity contains the arity
- hipe_rtl:mk_load(ArityReg, FunP,
- hipe_rtl:mk_imm(-(?TAG_PRIMARY_BOXED)+
- ?EFT_ARITY)),
- hipe_rtl:mk_load(FEPtrReg, FunP,
- hipe_rtl:mk_imm(-(?TAG_PRIMARY_BOXED)+
- ?EFT_FE)),
+ Untag,
+ hipe_rtl:mk_load(ArityReg, Base,
+ hipe_rtl:mk_imm(Offset+?EFT_ARITY)),
+ hipe_rtl:mk_load(FEPtrReg, Base,
+ hipe_rtl:mk_imm(Offset+?EFT_FE)),
hipe_rtl:mk_load(AddressReg, FEPtrReg,
hipe_rtl:mk_imm(?EFE_NATIVE_ADDRESS))],
IsFunCode ++ GetArityCode.
@@ -927,20 +973,24 @@ test_subbinary(Binary, TrueLblName, FalseLblName) ->
unsafe_load_float(DstLo, DstHi, Src) ->
WordSize = hipe_rtl_arch:word_size(),
- Offset1 = -(?TAG_PRIMARY_BOXED) + WordSize,
+ {Base, Offset0, Untag} = untag_ptr(Src, ?TAG_PRIMARY_BOXED),
+ Offset1 = Offset0 + WordSize,
Offset2 = Offset1 + 4, %% This should really be 4 and not WordSize
case hipe_rtl_arch:endianess() of
little ->
- [hipe_rtl:mk_load(DstLo, Src, hipe_rtl:mk_imm(Offset1), int32, unsigned),
- hipe_rtl:mk_load(DstHi, Src, hipe_rtl:mk_imm(Offset2), int32, unsigned)];
+ [Untag,
+ hipe_rtl:mk_load(DstLo, Base, hipe_rtl:mk_imm(Offset1), int32, unsigned),
+ hipe_rtl:mk_load(DstHi, Base, hipe_rtl:mk_imm(Offset2), int32, unsigned)];
big ->
- [hipe_rtl:mk_load(DstHi, Src, hipe_rtl:mk_imm(Offset1), int32, unsigned),
- hipe_rtl:mk_load(DstLo, Src, hipe_rtl:mk_imm(Offset2), int32, unsigned)]
+ [Untag,
+ hipe_rtl:mk_load(DstHi, Base, hipe_rtl:mk_imm(Offset1), int32, unsigned),
+ hipe_rtl:mk_load(DstLo, Base, hipe_rtl:mk_imm(Offset2), int32, unsigned)]
end.
unsafe_untag_float(Dst, Src) ->
- Offset = -(?TAG_PRIMARY_BOXED) + hipe_rtl_arch:word_size(),
- [hipe_rtl:mk_fload(Dst, Src, hipe_rtl:mk_imm(Offset))].
+ {Base, Offset0, Untag} = untag_ptr(Src, ?TAG_PRIMARY_BOXED),
+ Offset = Offset0 + hipe_rtl_arch:word_size(),
+ [Untag, hipe_rtl:mk_fload(Dst, Base, hipe_rtl:mk_imm(Offset))].
unsafe_tag_float(Dst, Src) ->
{GetHPInsn, HP, PutHPInsn} = hipe_rtl_arch:heap_pointer(),
@@ -999,8 +1049,9 @@ get_one_word_pos_bignum(USize, Size, Fail) ->
unsafe_get_one_word_pos_bignum(USize, Size) ->
WordSize = hipe_rtl_arch:word_size(),
- Imm = hipe_rtl:mk_imm(1*WordSize-?TAG_PRIMARY_BOXED),
- [hipe_rtl:mk_load(USize, Size, Imm)].
+ {Base, Offset, Untag} = untag_ptr(Size, ?TAG_PRIMARY_BOXED),
+ Imm = hipe_rtl:mk_imm(1*WordSize+Offset),
+ [Untag, hipe_rtl:mk_load(USize, Base, Imm)].
-spec bignum_sizeneed(non_neg_integer()) -> non_neg_integer().
@@ -1040,7 +1091,7 @@ create_matchstate(Max, BinSize, Base, Offset, Orig, Ms) ->
SizeInWords = ((ByteSize div WordSize) - 1),
Header = hipe_rtl:mk_imm(mk_header(SizeInWords, ?TAG_HEADER_BIN_MATCHSTATE)),
[GetHPInsn,
- hipe_rtl:mk_alu(Ms, HP, add, hipe_rtl:mk_imm(?TAG_PRIMARY_BOXED)),
+ tag_boxed(Ms, HP),
set_field_from_term({matchstate,thing_word}, Ms, Header),
set_field_from_term({matchstate,{matchbuffer,orig}}, Ms, Orig),
set_field_from_term({matchstate,{matchbuffer,base}}, Ms, Base),
@@ -1078,7 +1129,10 @@ convert_matchstate(Ms) ->
size_from_header(SizeInWords, Header),
hipe_rtl:mk_alu(Hole, SizeInWords, sub, hipe_rtl:mk_imm(?SUB_BIN_WORDSIZE)),
mk_var_header(BigIntHeader, Hole, ?TAG_HEADER_POS_BIG),
- hipe_rtl:mk_store(Ms, hipe_rtl:mk_imm(?SUB_BIN_WORDSIZE*WordSize-?TAG_PRIMARY_BOXED),
+ %% Matchstates can't be literals; so untagging with ?TAG_PRIMARY_BOXED is
+ %% fine here
+ hipe_rtl:mk_store(Ms, hipe_rtl:mk_imm(?SUB_BIN_WORDSIZE*WordSize
+ -?TAG_PRIMARY_BOXED),
BigIntHeader)].
compare_matchstate(Max, Ms, LargeEnough, TooSmall) ->
@@ -1087,8 +1141,10 @@ compare_matchstate(Max, Ms, LargeEnough, TooSmall) ->
SizeInWords = ((ByteSize div WordSize) - 1),
Header = hipe_rtl:mk_imm(mk_header(SizeInWords, ?TAG_HEADER_BIN_MATCHSTATE)),
RealHeader = hipe_rtl:mk_new_reg_gcsafe(),
- [hipe_rtl:mk_load(RealHeader, Ms, hipe_rtl:mk_imm(-?TAG_PRIMARY_BOXED)),
- hipe_rtl:mk_branch(RealHeader, ge, Header, LargeEnough, TooSmall)].
+ %% Matchstates can't be literals; so untagging with ?TAG_PRIMARY_BOXED is fine
+ %% here
+ [hipe_rtl:mk_load(RealHeader, Ms, hipe_rtl:mk_imm(-?TAG_PRIMARY_BOXED)),
+ hipe_rtl:mk_branch(RealHeader, ge, Header, LargeEnough, TooSmall)].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
@@ -1207,15 +1263,22 @@ get_field_size1({matchbuffer, base}) ->
get_field_size1({matchbuffer, binsize}) ->
?MB_SIZE_SIZE.
+get_field_addr_from_term(Struct, Term, Dst) ->
+ {Base, Offset0, Untag} = untag_ptr(Term, ?TAG_PRIMARY_BOXED),
+ Offset = hipe_rtl:mk_imm(get_field_offset(Struct) + Offset0),
+ [Untag, hipe_rtl:mk_alu(Dst, Base, add, Offset)].
+
get_field_from_term(Struct, Term, Dst) ->
- Offset = hipe_rtl:mk_imm(get_field_offset(Struct) - ?TAG_PRIMARY_BOXED),
+ {Base, Offset0, Untag} = untag_ptr(Term, ?TAG_PRIMARY_BOXED),
+ Offset = hipe_rtl:mk_imm(get_field_offset(Struct) + Offset0),
Size = get_field_size(Struct),
- hipe_rtl:mk_load(Dst, Term, Offset, Size, unsigned).
+ [Untag, hipe_rtl:mk_load(Dst, Base, Offset, Size, unsigned)].
set_field_from_term(Struct, Term, Value) ->
- Offset = hipe_rtl:mk_imm(get_field_offset(Struct) - ?TAG_PRIMARY_BOXED),
+ {Base, Offset0, Untag} = untag_ptr(Term, ?TAG_PRIMARY_BOXED),
+ Offset = hipe_rtl:mk_imm(get_field_offset(Struct) + Offset0),
Size = get_field_size(Struct),
- hipe_rtl:mk_store(Term, Offset, Value, Size).
+ [Untag, hipe_rtl:mk_store(Base, Offset, Value, Size)].
get_field_from_pointer(Struct, Term, Dst) ->
Offset = hipe_rtl:mk_imm(get_field_offset(Struct)),
@@ -1229,6 +1292,8 @@ set_field_from_pointer(Struct, Term, Value) ->
extract_matchbuffer(Mb, Ms) ->
What = {matchstate, matchbuffer},
+ %% Matchstates can't be literals; so untagging with ?TAG_PRIMARY_BOXED is fine
+ %% here
Offset = hipe_rtl:mk_imm(get_field_offset(What) - ?TAG_PRIMARY_BOXED),
hipe_rtl:mk_alu(Mb, Ms, add, Offset).
diff --git a/lib/hipe/ssa/hipe_ssa.inc b/lib/hipe/ssa/hipe_ssa.inc
index c7c1a8e1d7..29e8b92266 100644
--- a/lib/hipe/ssa/hipe_ssa.inc
+++ b/lib/hipe/ssa/hipe_ssa.inc
@@ -463,20 +463,20 @@ updateStatementDefs([], Statement, Current, Acc) ->
%%----------------------------------------------------------------------
updateIndices(Current, Variable) ->
- case ?CODE:is_var(Variable) of
- true ->
- NewVar = ?CODE:mk_new_var(),
- {NewVar,gb_trees:enter(Variable, NewVar, Current)};
- false ->
- case is_fp_temp(Variable) of
- true ->
- NewFVar = mk_new_fp_temp(),
- {NewFVar,gb_trees:enter(Variable, NewFVar, Current)};
- false ->
- NewReg = ?CODE:mk_new_reg(),
- {NewReg,gb_trees:enter(Variable, NewReg, Current)}
- end
- end.
+ New =
+ case ?CODE:is_var(Variable) of
+ true -> ?CODE:mk_new_var();
+ false ->
+ case is_fp_temp(Variable) of
+ true -> mk_new_fp_temp();
+ false ->
+ case ?CODE:reg_is_gcsafe(Variable) of
+ true -> ?CODE:mk_new_reg_gcsafe();
+ false -> ?CODE:mk_new_reg()
+ end
+ end
+ end,
+ {New, gb_trees:enter(Variable, New, Current)}.
%%----------------------------------------------------------------------
%% Procedure : updateSuccPhi/4
diff --git a/lib/hipe/test/Makefile b/lib/hipe/test/Makefile
index 544888719f..3650cda663 100644
--- a/lib/hipe/test/Makefile
+++ b/lib/hipe/test/Makefile
@@ -7,12 +7,12 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
MODULES= \
hipe_SUITE \
- opt_verify_SUITE
+ opt_verify_SUITE \
+ erl_types_SUITE
# .erl files for these modules are automatically generated
GEN_MODULES= \
basic_SUITE \
- bs_SUITE \
maps_SUITE \
sanity_SUITE
diff --git a/lib/hipe/test/basic_SUITE_data/basic_exceptions.erl b/lib/hipe/test/basic_SUITE_data/basic_exceptions.erl
index 229a0516dc..ba9c03d4ba 100644
--- a/lib/hipe/test/basic_SUITE_data/basic_exceptions.erl
+++ b/lib/hipe/test/basic_SUITE_data/basic_exceptions.erl
@@ -6,12 +6,13 @@
%%%-------------------------------------------------------------------
-module(basic_exceptions).
--export([test/0, test_catches/0]).
+-export([test/0]).
%% functions used as arguments to spawn/3
-export([bad_guy/2]).
test() ->
+ ok = test_catches(),
ok = test_catch_exit(42),
ok = test_catch_throw(42),
ok = test_catch_element(),
@@ -22,6 +23,8 @@ test() ->
ok = test_pending_errors(),
ok = test_bad_fun_call(),
ok = test_guard_bif(),
+ ok = test_eclectic(),
+ ok = test_raise(),
ok.
%%--------------------------------------------------------------------
@@ -463,3 +466,213 @@ guard_bif('node/0', X, Y) when node() == Y ->
{'node/0', X, Y};
guard_bif('node/1', X, Y) when node(X) == Y ->
{'node/1', X, Y}.
+
+%%--------------------------------------------------------------------
+%% Taken from trycatch_SUITE.erl (compiler test suite).
+%%
+%% Cases that are commented out contain exception information that was
+%% added to Erlang/OTP in commit e8d45ae14c6c3bdfcbbc7964228b004ef4f11ea6
+%% (May 2017) only in the BEAM emulator. Thus, part of this test fails
+%% when compiled in native code.
+%% The remaining cases are uncommented so that they are properly tested
+%% in native code too.
+%%--------------------------------------------------------------------
+
+test_eclectic() ->
+ V = {make_ref(),3.1415926535,[[]|{}]},
+ {{value,{value,V},V},V} =
+ eclectic_1({foo,{value,{value,V}}}, undefined, {value,V}),
+ {{'EXIT',{V,[{?MODULE,foo,1,_}|_]}},V} =
+ eclectic_1({catch_foo,{error,V}}, undefined, {value,V}),
+ {{error,{exit,V},{'EXIT',V}},V} =
+ eclectic_1({foo,{error,{exit,V}}}, error, {value,V}),
+ %% {{value,{value,V},V},
+ %% {'EXIT',{badarith,[{erlang,'+',[0,a],_},{?MODULE,my_add,2,_}|_]}}} =
+ %% eclectic_1({foo,{value,{value,V}}}, undefined, {'add',{0,a}}),
+ {{'EXIT',V},V} =
+ eclectic_1({catch_foo,{exit,V}}, undefined, {throw,V}),
+ %% {{error,{'div',{1,0}},{'EXIT',{badarith,[{erlang,'div',[1,0],_},{?MODULE,my_div,2,_}|_]}}},
+ %% {'EXIT',V}} =
+ %% eclectic_1({foo,{error,{'div',{1,0}}}}, error, {exit,V}),
+ {{{error,V},{'EXIT',{V,[{?MODULE,foo,1,_}|_]}}},
+ {'EXIT',V}} =
+ eclectic_1({catch_foo,{throw,{error,V}}}, undefined, {exit,V}),
+ %%
+ {{value,{value,{value,V},V}},V} =
+ eclectic_2({value,{value,V}}, undefined, {value,V}),
+ {{value,{throw,{value,V},V}},V} =
+ eclectic_2({throw,{value,V}}, throw, {value,V}),
+ {{caught,{'EXIT',V}},undefined} =
+ eclectic_2({value,{value,V}}, undefined, {exit,V}),
+ {{caught,{'EXIT',{V,[{?MODULE,foo,1,_}|_]}}},undefined} =
+ eclectic_2({error,{value,V}}, throw, {error,V}),
+ %% The following fails in native code
+ %% %% {{caught,{'EXIT',{badarg,[{erlang,abs,[V],_}|_]}}},V} =
+ %% %% eclectic_2({value,{'abs',V}}, undefined, {value,V}),
+ %% {{caught,{'EXIT',{badarith,[{erlang,'+',[0,a],_},{?MODULE,my_add,2,_}|_]}}},V} =
+ %% eclectic_2({exit,{'add',{0,a}}}, exit, {value,V}),
+ {{caught,{'EXIT',V}},undefined} =
+ eclectic_2({value,{error,V}}, undefined, {exit,V}),
+ {{caught,{'EXIT',{V,[{?MODULE,foo,1,_}|_]}}},undefined} =
+ eclectic_2({throw,{'div',{1,0}}}, throw, {error,V}),
+ ok.
+
+eclectic_1(X, C, Y) ->
+ erase(eclectic),
+ Done = make_ref(),
+ Try =
+ try case X of
+ {catch_foo,V} -> catch {Done,foo(V)};
+ {foo,V} -> {Done,foo(V)}
+ end of
+ {Done,D} -> {value,D,catch foo(D)};
+ {'EXIT',_}=Exit -> Exit;
+ D -> {D,catch foo(D)}
+ catch
+ C:D -> {C,D,catch foo(D)}
+ after
+ put(eclectic, catch foo(Y))
+ end,
+ {Try,erase(eclectic)}.
+
+eclectic_2(X, C, Y) ->
+ Done = make_ref(),
+ erase(eclectic),
+ Catch =
+ case
+ catch
+ {Done,
+ try foo(X) of
+ V -> {value,V,foo(V)}
+ catch
+ C:D -> {C,D,foo(D)}
+ after
+ put(eclectic, foo(Y))
+ end} of
+ {Done,Z} -> {value,Z};
+ Z -> {caught,Z}
+ end,
+ {Catch,erase(eclectic)}.
+
+foo({value,Value}) -> Value;
+foo({'div',{A,B}}) ->
+ my_div(A, B);
+foo({'add',{A,B}}) ->
+ my_add(A, B);
+foo({'abs',X}) ->
+ my_abs(X);
+foo({error,Error}) ->
+ erlang:error(Error);
+foo({throw,Throw}) ->
+ erlang:throw(Throw);
+foo({exit,Exit}) ->
+ erlang:exit(Exit);
+foo({raise,{Class,Reason}}) ->
+ erlang:raise(Class, Reason);
+foo(Term) when not is_atom(Term) -> Term.
+%%foo(Atom) when is_atom(Atom) -> % must not be defined!
+
+my_div(A, B) ->
+ A div B.
+
+my_add(A, B) ->
+ A + B.
+
+my_abs(X) ->
+ abs(X).
+
+test_raise() ->
+ test_raise(fun() -> exit({exit,tuple}) end),
+ test_raise(fun() -> abs(id(x)) end),
+ test_raise(fun() -> throw({was,thrown}) end),
+
+ badarg = bad_raise(fun() -> abs(id(x)) end),
+
+ ok.
+
+bad_raise(Expr) ->
+ try
+ Expr()
+ catch
+ _:E:Stk ->
+ erlang:raise(bad_class, E, Stk)
+ end.
+
+test_raise(Expr) ->
+ test_raise_1(Expr),
+ test_raise_2(Expr),
+ test_raise_3(Expr).
+
+test_raise_1(Expr) ->
+ erase(exception),
+ try
+ do_test_raise_1(Expr)
+ catch
+ C:E:Stk ->
+ {C,E,Stk} = erase(exception)
+ end.
+
+do_test_raise_1(Expr) ->
+ try
+ Expr()
+ catch
+ C:E:Stk ->
+ %% Here the stacktrace must be built.
+ put(exception, {C,E,Stk}),
+ erlang:raise(C, E, Stk)
+ end.
+
+test_raise_2(Expr) ->
+ erase(exception),
+ try
+ do_test_raise_2(Expr)
+ catch
+ C:E:Stk ->
+ {C,E} = erase(exception),
+ try
+ Expr()
+ catch
+ _:_:S ->
+ [StkTop|_] = S,
+ [StkTop|_] = Stk
+ end
+ end.
+
+do_test_raise_2(Expr) ->
+ try
+ Expr()
+ catch
+ C:E:Stk ->
+ %% Here it is possible to replace erlang:raise/3 with
+ %% the raw_raise/3 instruction since the stacktrace is
+ %% not actually used.
+ put(exception, {C,E}),
+ erlang:raise(C, E, Stk)
+ end.
+
+test_raise_3(Expr) ->
+ try
+ do_test_raise_3(Expr)
+ catch
+ exit:{exception,C,E}:Stk ->
+ try
+ Expr()
+ catch
+ C:E:S ->
+ [StkTop|_] = S,
+ [StkTop|_] = Stk
+ end
+ end.
+
+do_test_raise_3(Expr) ->
+ try
+ Expr()
+ catch
+ C:E:Stk ->
+ %% Here it is possible to replace erlang:raise/3 with
+ %% the raw_raise/3 instruction since the stacktrace is
+ %% not actually used.
+ erlang:raise(exit, {exception,C,E}, Stk)
+ end.
+
+id(I) -> I.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_inline_function.erl b/lib/hipe/test/basic_SUITE_data/basic_inline_function.erl
deleted file mode 100644
index 4c08064670..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_inline_function.erl
+++ /dev/null
@@ -1,73 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% Author: Kostis Sagonas
-%%%
-%%% Contains tests that depend on the compiler inliner being turned on.
-%%%-------------------------------------------------------------------
--module(basic_inline_function).
-
--export([test/0]).
-
--compile({inline, [{to_objects, 3}]}).
-
-test() ->
- ok = test_inline_match(),
- ok.
-
-%%--------------------------------------------------------------------
-
-test_inline_match() ->
- bad_object = test1(a, {binary, foo, set}, c),
- bad_object = test2(a, {binary, foo, set}, c),
- bad_object = test3(a, {binary, foo, set}, c),
- ok.
-
-%% Inlined
-test1(KeysObjs, C, Ts) ->
- case catch to_objects(KeysObjs, C, Ts) of
- {'EXIT', _} ->
- bad_object;
- ok ->
- ok
- end.
-
-%% "Inlined" by hand
-test2(KeysObjs, C, _Ts) ->
- case catch (case C of
- {binary, _, set} ->
- <<_ObjSz0:32, _T/binary>> = KeysObjs;
- _ -> ok
- end) of
- {'EXIT', _} ->
- bad_object;
- ok ->
- ok
- end.
-
-%% Not inlined
-test3(KeysObjs, C, Ts) ->
- case catch fto_objects(KeysObjs, C, Ts) of
- {'EXIT', _} ->
- bad_object;
- ok ->
- ok
- end.
-
-%% Inlined.
-to_objects(Bin, {binary, _, set}, _Ts) ->
- <<_ObjSz0:32, _T/binary>> = Bin,
- ok;
-to_objects(<<_ObjSz0:32, _T/binary>> ,_, _) ->
- ok;
-to_objects(_Bin, _, _Ts) ->
- ok.
-
-%% Not Inlined.
-fto_objects(Bin, {binary, _, set}, _Ts) ->
- <<_ObjSz0:32, _T/binary>> = Bin,
- ok;
-fto_objects(<<_ObjSz0:32, _T/binary>> ,_,_) ->
- ok;
-fto_objects(_Bin, _, _Ts) ->
- ok.
-
diff --git a/lib/hipe/test/basic_SUITE_data/basic_issues_hipe.erl b/lib/hipe/test/basic_SUITE_data/basic_issues_hipe.erl
index e71045bfe2..fc87abb54e 100644
--- a/lib/hipe/test/basic_SUITE_data/basic_issues_hipe.erl
+++ b/lib/hipe/test/basic_SUITE_data/basic_issues_hipe.erl
@@ -8,8 +8,9 @@
-export([test/0]).
-%% functions that need to be exported so that they are retained.
--export([auth/4]).
+%% functions that need to be exported so that they are retained and/or
+%% not specialized away by the compiler.
+-export([auth/4, wxSizer_replace/2, parent_class/1]).
test() ->
ok = test_dominance_trees(),
@@ -18,6 +19,7 @@ test() ->
ok = test_bif_fails(),
ok = test_find_catches(),
ok = test_heap_allocate_trim(),
+ ok = wxSizer_replace(),
ok.
%%--------------------------------------------------------------------
@@ -151,3 +153,25 @@ get_next_retry(Error, Count) ->
end.
pair(A, B) -> {A, B}.
+
+%%--------------------------------------------------------------------
+%% Date: June 11, 2018
+%%
+%% Stripped down test case (from `wxSizer') that crashed the lazy code
+%% motion pass of the HiPE compiler in a pre-release of Erlang/OTP 21.
+%% A similar crash existed in `ssl_correction'.
+%%--------------------------------------------------------------------
+
+wxSizer_replace() ->
+ wxSizer_replace(?MODULE, ?MODULE).
+
+-define(CLASS(Type, Class), ((Type) =:= Class) orelse (Type):parent_class(Class)).
+
+wxSizer_replace(OldwinT, NewwinT) -> % this function was the culprit
+ ?CLASS(OldwinT, ?MODULE),
+ ?CLASS(NewwinT, ?MODULE),
+ ok.
+
+parent_class(wxWindow) -> true;
+parent_class(wxEvtHandler) -> true;
+parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
diff --git a/lib/hipe/test/basic_SUITE_data/basic_receive.erl b/lib/hipe/test/basic_SUITE_data/basic_receive.erl
index 5f865d7b7a..20e3f350e8 100644
--- a/lib/hipe/test/basic_SUITE_data/basic_receive.erl
+++ b/lib/hipe/test/basic_SUITE_data/basic_receive.erl
@@ -12,6 +12,7 @@ test() ->
ok = test_wait_timeout(),
ok = test_double_timeout(),
ok = test_reschedule(),
+ ok = test_recv_mark(),
ok.
%%--------------------------------------------------------------------
@@ -54,3 +55,91 @@ doit(First) ->
erts_debug:set_internal_state(hipe_test_reschedule_suspend, 1).
%%--------------------------------------------------------------------
+%% Check that we cannot cause a recv_mark,recv_set pair to misbehave and
+%% deadlock the process.
+
+test_recv_mark() ->
+ ok = test_recv_mark(fun disturber_nop/0),
+ ok = test_recv_mark(fun disturber_receive/0),
+ ok = test_recv_mark(fun disturber_other/0),
+ ok = test_recv_mark(fun disturber_recurse/0),
+ ok = test_recv_mark_after(self(), fun disturber_after_recurse/0, false),
+ ok = test_recv_mark(fun disturber_other_recurse/0),
+ ok = test_recv_mark(fun disturber_other_after/0),
+ ok = test_recv_mark_nested().
+
+test_recv_mark(Disturber) ->
+ Ref = make_ref(),
+ self() ! Ref,
+ Disturber(),
+ receive Ref -> ok
+ after 0 -> error(failure)
+ end.
+
+disturber_nop() -> ok.
+
+disturber_receive() ->
+ self() ! message,
+ receive message -> ok end.
+
+disturber_other() ->
+ Ref = make_ref(),
+ self() ! Ref,
+ receive Ref -> ok end.
+
+disturber_recurse() ->
+ aborted = (catch test_recv_mark(fun() -> throw(aborted) end)),
+ ok.
+
+test_recv_mark_after(Recipient, Disturber, IsInner) ->
+ Ref = make_ref(),
+ Recipient ! Ref,
+ Disturber(),
+ receive
+ Ref -> ok
+ after 0 ->
+ case IsInner of
+ true -> expected;
+ false -> error(failure)
+ end
+ end.
+
+disturber_after_recurse() ->
+ NoOp = fun() -> ok end,
+ BlackHole = spawn(NoOp),
+ expected = test_recv_mark_after(BlackHole, NoOp, true),
+ ok.
+
+disturber_other_recurse() ->
+ aborted = (catch disturber_other_recurse(fun() -> throw(aborted) end)),
+ ok.
+
+disturber_other_recurse(InnerD) ->
+ Ref = make_ref(),
+ self() ! Ref,
+ InnerD(),
+ receive Ref -> ok
+ after 0 -> error(failure)
+ end.
+
+disturber_other_after() ->
+ BlackHole = spawn(fun() -> ok end),
+ Ref = make_ref(),
+ BlackHole ! Ref,
+ receive Ref -> error(imposible)
+ after 0 -> ok
+ end.
+
+test_recv_mark_nested() ->
+ Ref1 = make_ref(),
+ self() ! Ref1,
+ begin
+ Ref2 = make_ref(),
+ self() ! Ref2,
+ receive Ref2 -> ok end
+ end,
+ receive Ref1 -> ok
+ after 0 -> error(failure)
+ end.
+
+%%--------------------------------------------------------------------
diff --git a/lib/hipe/test/erl_types_SUITE.erl b/lib/hipe/test/erl_types_SUITE.erl
new file mode 100644
index 0000000000..7d7c144b69
--- /dev/null
+++ b/lib/hipe/test/erl_types_SUITE.erl
@@ -0,0 +1,197 @@
+%% -*- erlang-indent-level: 4 -*-
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+-module(erl_types_SUITE).
+
+-export([all/0,
+ consistency_and_to_string/1]).
+
+%% Simplify calls into erl_types and avoid importing the entire module.
+-define(M, erl_types).
+
+-include_lib("common_test/include/ct.hrl").
+
+all() ->
+ [consistency_and_to_string].
+
+consistency_and_to_string(_Config) ->
+ %% Check consistency of types
+ Atom1 = ?M:t_atom(),
+ Atom2 = ?M:t_atom(foo),
+ Atom3 = ?M:t_atom(bar),
+ true = ?M:t_is_atom(Atom2),
+
+ True = ?M:t_atom(true),
+ False = ?M:t_atom(false),
+ Bool = ?M:t_boolean(),
+ true = ?M:t_is_boolean(True),
+ true = ?M:t_is_boolean(Bool),
+ false = ?M:t_is_boolean(Atom1),
+
+ Binary = ?M:t_binary(),
+ true = ?M:t_is_binary(Binary),
+
+ Bitstr = ?M:t_bitstr(),
+ true = ?M:t_is_bitstr(Bitstr),
+
+ Bitstr1 = ?M:t_bitstr(7, 3),
+ true = ?M:t_is_bitstr(Bitstr1),
+ false = ?M:t_is_binary(Bitstr1),
+
+ Bitstr2 = ?M:t_bitstr(16, 8),
+ true = ?M:t_is_bitstr(Bitstr2),
+ true = ?M:t_is_binary(Bitstr2),
+
+ BitStr816 = ?M:t_bitstr(8,16),
+ BitStr816 = ?M:t_subtract(?M:t_bitstr(4, 12), ?M:t_bitstr(8, 12)),
+
+ Int1 = ?M:t_integer(),
+ Int2 = ?M:t_integer(1),
+ Int3 = ?M:t_integer(16#ffffffff),
+ true = ?M:t_is_integer(Int2),
+ true = ?M:t_is_byte(Int2),
+ false = ?M:t_is_byte(Int3),
+ false = ?M:t_is_byte(?M:t_from_range(-1, 1)),
+ true = ?M:t_is_byte(?M:t_from_range(1, 255)),
+
+ Tuple1 = ?M:t_tuple(),
+ Tuple2 = ?M:t_tuple(3),
+ Tuple3 = ?M:t_tuple([Atom1, Int1]),
+ Tuple4 = ?M:t_tuple([Tuple1, Tuple2]),
+ Tuple5 = ?M:t_tuple([Tuple3, Tuple4]),
+ Tuple6 = ?M:t_limit(Tuple5, 2),
+ Tuple7 = ?M:t_limit(Tuple5, 3),
+ true = ?M:t_is_tuple(Tuple1),
+
+ Port = ?M:t_port(),
+ Pid = ?M:t_pid(),
+ Ref = ?M:t_reference(),
+ Identifier = ?M:t_identifier(),
+ false = ?M:t_is_reference(Port),
+ true = ?M:t_is_identifier(Port),
+
+ Function1 = ?M:t_fun(),
+ Function2 = ?M:t_fun(Pid),
+ Function3 = ?M:t_fun([], Pid),
+ Function4 = ?M:t_fun([Port, Pid], Pid),
+ Function5 = ?M:t_fun([Pid, Atom1], Int2),
+ true = ?M:t_is_fun(Function3),
+
+ List1 = ?M:t_list(),
+ List2 = ?M:t_list(?M:t_boolean()),
+ List3 = ?M:t_cons(?M:t_boolean(), List2),
+ List4 = ?M:t_cons(?M:t_boolean(), ?M:t_atom()),
+ List5 = ?M:t_cons(?M:t_boolean(), ?M:t_nil()),
+ List6 = ?M:t_cons_tl(List5),
+ List7 = ?M:t_sup(List4, List5),
+ List8 = ?M:t_inf(List7, ?M:t_list()),
+ List9 = ?M:t_cons(),
+ List10 = ?M:t_cons_tl(List9),
+ true = ?M:t_is_boolean(?M:t_cons_hd(List5)),
+ true = ?M:t_is_list(List5),
+ false = ?M:t_is_list(List4),
+
+ Product1 = ?M:t_product([Atom1, Atom2]),
+ Product2 = ?M:t_product([Atom3, Atom1]),
+ Product3 = ?M:t_product([Atom3, Atom2]),
+
+ Union1 = ?M:t_sup(Atom2, Atom3),
+ Union2 = ?M:t_sup(Tuple2, Tuple3),
+ Union3 = ?M:t_sup(Int2, Atom3),
+ Union4 = ?M:t_sup(Port, Pid),
+ Union5 = ?M:t_sup(Union4, Int1),
+ Union6 = ?M:t_sup(Function1, Function2),
+ Union7 = ?M:t_sup(Function4, Function5),
+ Union8 = ?M:t_sup(True, False),
+ true = ?M:t_is_boolean(Union8),
+ Union9 = ?M:t_sup(Int2, ?M:t_integer(2)),
+ true = ?M:t_is_byte(Union9),
+ Union10 = ?M:t_sup(?M:t_tuple([?M:t_atom(true), ?M:t_any()]),
+ ?M:t_tuple([?M:t_atom(false), ?M:t_any()])),
+
+ Any = ?M:t_any(),
+ Any = ?M:t_sup(Product3, Function5),
+
+ Atom3 = ?M:t_inf(Union3, Atom1),
+ Union2 = ?M:t_inf(Union2, Tuple1),
+ Int2 = ?M:t_inf(Int1, Union3),
+ Union4 = ?M:t_inf(Union4, Identifier),
+ Port = ?M:t_inf(Union5, Port),
+ Function4 = ?M:t_inf(Union7, Function4),
+ None = ?M:t_none(),
+ None = ?M:t_inf(Product2, Atom1),
+ Product3 = ?M:t_inf(Product1, Product2),
+ Function5 = ?M:t_inf(Union7, Function5),
+ true = ?M:t_is_byte(?M:t_inf(Union9, ?M:t_number())),
+ true = ?M:t_is_char(?M:t_inf(Union9, ?M:t_number())),
+
+ RecDict = #{{record, foo} => {{?FILE, ?LINE}, [{2, [{bar, [], ?M:t_any()},
+ {baz, [], ?M:t_any()}]}]}},
+ Record1 = ?M:t_from_term({foo, [1,2], {1,2,3}}),
+
+ %% Check string representations
+ "atom()" = ?M:t_to_string(Atom1),
+ "'foo'" = ?M:t_to_string(Atom2),
+ "'bar'" = ?M:t_to_string(Atom3),
+
+ "binary()" = ?M:t_to_string(Binary),
+
+ "integer()" = ?M:t_to_string(Int1),
+ "1" = ?M:t_to_string(Int2),
+
+ "tuple()" = ?M:t_to_string(Tuple1),
+ "{_,_,_}" = ?M:t_to_string(Tuple2),
+ "{atom(),integer()}" = ?M:t_to_string(Tuple3),
+ "{tuple(),{_,_,_}}" = ?M:t_to_string(Tuple4),
+ "{{atom(),integer()},{tuple(),{_,_,_}}}" = ?M:t_to_string(Tuple5),
+ "{{_,_},{_,_}}" = ?M:t_to_string(Tuple6),
+ "{{atom(),integer()},{tuple(),{_,_,_}}}" = ?M:t_to_string(Tuple7),
+
+ "reference()" = ?M:t_to_string(Ref),
+ "port()" = ?M:t_to_string(Port),
+ "pid()" = ?M:t_to_string(Pid),
+ "identifier()" = ?M:t_to_string(Identifier),
+
+ "[any()]" = ?M:t_to_string(List1),
+ "[boolean()]" = ?M:t_to_string(List2),
+ "[boolean(),...]" = ?M:t_to_string(List3),
+ "nonempty_improper_list(boolean(),atom())" = ?M:t_to_string(List4),
+ "[boolean(),...]" = ?M:t_to_string(List5),
+ "[boolean()]" = ?M:t_to_string(List6),
+ "nonempty_maybe_improper_list(boolean(),atom() | [])" = ?M:t_to_string(List7),
+ "[boolean(),...]" = ?M:t_to_string(List8),
+ "nonempty_maybe_improper_list()" = ?M:t_to_string(List9),
+ "any()" = ?M:t_to_string(List10),
+
+ "fun()" = ?M:t_to_string(Function1),
+ "fun((...) -> pid())" = ?M:t_to_string(Function2),
+ "fun(() -> pid())" = ?M:t_to_string(Function3),
+ "fun((port(),pid()) -> pid())" = ?M:t_to_string(Function4),
+ "fun((pid(),atom()) -> 1)" = ?M:t_to_string(Function5),
+
+ "<atom(),'foo'>" = ?M:t_to_string(Product1),
+ "<'bar',atom()>" = ?M:t_to_string(Product2),
+
+ "#foo{bar::[1 | 2,...],baz::{1,2,3}}" = ?M:t_to_string(Record1, RecDict),
+
+ "'bar' | 'foo'" = ?M:t_to_string(Union1),
+ "{atom(),integer()} | {_,_,_}" = ?M:t_to_string(Union2),
+ "'bar' | 1" = ?M:t_to_string(Union3),
+ "pid() | port()" = ?M:t_to_string(Union4),
+ "pid() | port() | integer()" = ?M:t_to_string(Union5),
+ "fun()" = ?M:t_to_string(Union6),
+ "fun((pid() | port(),atom() | pid()) -> pid() | 1)" = ?M:t_to_string(Union7),
+ "boolean()" = ?M:t_to_string(Union8),
+ "{'false',_} | {'true',_}" = ?M:t_to_string(Union10),
+ "{'true',integer()}" = ?M:t_to_string(?M:t_inf(Union10, ?M:t_tuple([?M:t_atom(true), ?M:t_integer()]))).
diff --git a/lib/hipe/test/hipe_testsuite_driver.erl b/lib/hipe/test/hipe_testsuite_driver.erl
index 88576775ca..c506dd5e1d 100644
--- a/lib/hipe/test/hipe_testsuite_driver.erl
+++ b/lib/hipe/test/hipe_testsuite_driver.erl
@@ -29,13 +29,9 @@ get_suites(SuitesWithSuiteSuffix) ->
[S || {yes, S} <- Prefixes].
suffix(String, Suffix) ->
- case string:rstr(String, Suffix) of
- 0 -> no;
- Index ->
- case string:substr(String, Index) =:= Suffix of
- true -> {yes, string:sub_string(String, 1, Index-1)};
- false -> no
- end
+ case string:split(String, Suffix, trailing) of
+ [Prefix,[]] -> {yes, Prefix};
+ _ -> no
end.
-spec file_type(file:filename()) -> {ok, file_type()} | {error, ext_posix()}.
@@ -165,7 +161,8 @@ run(TestCase, Dir, _OutDir) ->
%% end, DataFiles),
%% try
ok = TestCase:test(),
- HiPEOpts = try TestCase:hipe_options() catch error:undef -> [] end,
+ HiPEOpts0 = try TestCase:hipe_options() catch error:undef -> [] end,
+ HiPEOpts = HiPEOpts0 ++ hipe_options(),
{ok, TestCase} = hipe:c(TestCase, HiPEOpts),
ok = TestCase:test(),
{ok, TestCase} = hipe:c(TestCase, [o1|HiPEOpts]),
@@ -173,7 +170,7 @@ run(TestCase, Dir, _OutDir) ->
{ok, TestCase} = hipe:c(TestCase, [o0|HiPEOpts]),
ok = TestCase:test(),
ToLLVM = try TestCase:to_llvm() catch error:undef -> true end,
- case ToLLVM andalso hipe:llvm_support_available() of
+ case ToLLVM andalso hipe:erllvm_is_supported() of
true ->
{ok, TestCase} = hipe:c(TestCase, [to_llvm|HiPEOpts]),
ok = TestCase:test();
@@ -183,3 +180,6 @@ run(TestCase, Dir, _OutDir) ->
%% lists:foreach(fun (DF) -> ok end, % = file:delete(DF) end,
%% [filename:join(OutDir, D) || D <- DataFiles])
%% end.
+
+hipe_options() ->
+ [verify_gcsafe].
diff --git a/lib/hipe/test/opt_verify_SUITE.erl b/lib/hipe/test/opt_verify_SUITE.erl
index a323c10503..24f43af275 100644
--- a/lib/hipe/test/opt_verify_SUITE.erl
+++ b/lib/hipe/test/opt_verify_SUITE.erl
@@ -59,7 +59,7 @@ call_elim_test_file(Config, FileName, Option) ->
substring_count(Icode, Substring) ->
substring_count(Icode, Substring, 0).
substring_count(Icode, Substring, N) ->
- case string:str(Icode, Substring) of
- 0 -> N;
- I -> substring_count(lists:nthtail(I, Icode), Substring, N+1)
+ case string:find(Icode, Substring) of
+ nomatch -> N;
+ Prefix -> substring_count(string:prefix(Prefix, Substring), Substring, N+1)
end.
diff --git a/lib/hipe/vsn.mk b/lib/hipe/vsn.mk
index 0c517f9a7a..a91d92ca14 100644
--- a/lib/hipe/vsn.mk
+++ b/lib/hipe/vsn.mk
@@ -1 +1 @@
-HIPE_VSN = 3.17.1
+HIPE_VSN = 3.19
diff --git a/lib/hipe/x86/hipe_rtl_to_x86.erl b/lib/hipe/x86/hipe_rtl_to_x86.erl
index 31e4f6e4ac..22947da148 100644
--- a/lib/hipe/x86/hipe_rtl_to_x86.erl
+++ b/lib/hipe/x86/hipe_rtl_to_x86.erl
@@ -646,7 +646,7 @@ conv_imm(Opnd, Map) ->
is_imm64(Value) when is_integer(Value) ->
(Value < -(1 bsl (32 - 1))) or (Value > (1 bsl (32 - 1)) - 1);
is_imm64({_,atom}) -> false; % Atoms are 32 bits.
-is_imm64({_,c_const}) -> false; % c_consts are 32 bits.
+is_imm64({_,c_const}) -> true; % c_consts are 64 bits.
is_imm64({_,_}) -> true . % Other relocs are 64 bits.
-else.
conv_imm(Opnd, Map) ->
@@ -777,6 +777,18 @@ conv_fconv(Dst, Src) ->
%%% Finalise the conversion of a 2-address FP operation.
+-ifdef(HIPE_AMD64).
+conv_fp_unary(Dst, Src, 'fchs') ->
+ Tmp = new_untagged_temp(),
+ case same_opnd(Dst, Src) of
+ true ->
+ [];
+ _ ->
+ [hipe_x86:mk_fmove(Src, Dst)]
+ end ++
+ mk_load_address(c_const, hipe_x86:mk_imm({sse2_fnegate_mask, c_const}), Tmp) ++
+ [hipe_x86:mk_fp_binop('xorpd', hipe_x86:mk_mem(Tmp, hipe_x86:mk_imm(0), double), Dst)].
+-else.
conv_fp_unary(Dst, Src, FpUnOp) ->
case same_opnd(Dst, Src) of
true ->
@@ -785,6 +797,7 @@ conv_fp_unary(Dst, Src, FpUnOp) ->
[hipe_x86:mk_fmove(Src, Dst),
hipe_x86:mk_fp_unop(FpUnOp, Dst)]
end.
+-endif.
conv_fp_unop(RtlFpUnOp) ->
case RtlFpUnOp of
@@ -854,13 +867,8 @@ mk_jmp_switch(Index, JTabLab, Labels) ->
%%% Finalise the translation of a load_address instruction.
-ifdef(HIPE_AMD64).
-mk_load_address(Type, Src, Dst) ->
- case Type of
- c_const -> % 32 bits
- [hipe_x86:mk_move(Src, Dst)];
- _ ->
- [hipe_x86:mk_move64(Src, Dst)]
- end.
+mk_load_address(_Type, Src, Dst) ->
+ [hipe_x86:mk_move64(Src, Dst)].
-else.
mk_load_address(_Type, Src, Dst) ->
[hipe_x86:mk_move(Src, Dst)].
diff --git a/lib/hipe/x86/hipe_x86_assemble.erl b/lib/hipe/x86/hipe_x86_assemble.erl
index 50919bdf4e..9d2586a14d 100644
--- a/lib/hipe/x86/hipe_x86_assemble.erl
+++ b/lib/hipe/x86/hipe_x86_assemble.erl
@@ -735,6 +735,7 @@ resolve_sse2_op(Op) ->
fdiv -> divsd;
fmul -> mulsd;
fsub -> subsd;
+ xorpd -> xorpd;
_ -> exit({?MODULE, unknown_sse2_operator, Op})
end.
diff --git a/lib/ic/AUTHORS b/lib/ic/AUTHORS
deleted file mode 100644
index f3791aabaa..0000000000
--- a/lib/ic/AUTHORS
+++ /dev/null
@@ -1,8 +0,0 @@
-Original Authors:
-
-Peter Lundel
-Lars Thorsen
-Babbis Xagorarakis
-
-
-Contributors:
diff --git a/lib/ic/Makefile b/lib/ic/Makefile
deleted file mode 100644
index 624aa62a6e..0000000000
--- a/lib/ic/Makefile
+++ /dev/null
@@ -1,42 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1998-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include vsn.mk
-VSN=$(ORBER_VSN)
-
-# ----------------------------------------------------
-# Common Macros
-# ----------------------------------------------------
-
-SUB_DIRECTORIES = src c_src java_src doc/src examples/pre_post_condition
-
-SPECIAL_TARGETS =
-
-# ----------------------------------------------------
-# Default Subdir Targets
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_subdir.mk
-
diff --git a/lib/ic/c_src/Makefile b/lib/ic/c_src/Makefile
deleted file mode 100644
index 35d6013279..0000000000
--- a/lib/ic/c_src/Makefile
+++ /dev/null
@@ -1,25 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1998-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-#
-# Invoke with GNU make or clearmake -C gnu.
-#
-
-include $(ERL_TOP)/make/run_make.mk
diff --git a/lib/ic/c_src/Makefile.in b/lib/ic/c_src/Makefile.in
deleted file mode 100644
index c0dad59557..0000000000
--- a/lib/ic/c_src/Makefile.in
+++ /dev/null
@@ -1,165 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1998-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-CC = @CC@
-LIBS = @LIBS@
-
-LIBDIR = ../priv/lib/$(TARGET)
-OBJDIR = ../priv/obj/$(TARGET)
-INCDIR = ../include
-ERL_INTERFACE_FLAGS = \
- -I$(ERL_TOP)/lib/erl_interface/include \
- -I$(ERL_TOP)/lib/erl_interface/src
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(IC_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/ic-$(VSN)
-
-# ----------------------------------------------------
-# File Specs
-# ----------------------------------------------------
-
-IDL_FILES = \
- $(INCDIR)/erlang.idl
-
-ifeq ($(findstring win32,$(TARGET)),win32)
-USING_MINGW=@MIXED_CYGWIN_MINGW@
-ifeq ($(USING_MINGW),yes)
-AR_OUT = rcv
-CC_FLAGS =
-LIBRARY = $(LIBDIR)/libic.a
-SKIP_BUILDING_BINARIES := false
-else
-LIBRARY = $(LIBDIR)/ic.lib
-AR_OUT = -out:
-CC_FLAGS = -MT
-endif
-ifeq ($(HOST_OS),)
-HOST_OS := $(shell $(ERL_TOP)/erts/autoconf/config.guess)
-endif
-ifeq ($(findstring solaris,$(HOST_OS)),solaris)
-SKIP_BUILDING_BINARIES := true
-endif
-else
-ifeq ($(V),0)
-AR_OUT = rc
-else
-AR_OUT = rcv
-endif
-CC_FLAGS = @DED_CFLAGS@
-LIBRARY = $(LIBDIR)/libic.a
-SKIP_BUILDING_BINARIES := false
-endif
-
-C_FILES = \
- ic.c \
- ic_tmo.c \
- oe_ei_encode_version.c \
- oe_ei_encode_long.c \
- oe_ei_encode_ulong.c \
- oe_ei_encode_double.c \
- oe_ei_encode_char.c \
- oe_ei_encode_string.c \
- oe_ei_encode_atom.c \
- oe_ei_encode_pid.c \
- oe_ei_encode_port.c \
- oe_ei_encode_ref.c \
- oe_ei_encode_term.c \
- oe_ei_encode_tuple_header.c \
- oe_ei_encode_list_header.c \
- oe_ei_encode_longlong.c \
- oe_ei_encode_ulonglong.c \
- oe_ei_encode_wchar.c \
- oe_ei_encode_wstring.c \
- oe_ei_decode_longlong.c \
- oe_ei_decode_ulonglong.c \
- oe_ei_decode_wchar.c \
- oe_ei_decode_wstring.c \
- oe_ei_code_erlang_binary.c
-
-H_FILES = $(INCDIR)/ic.h
-
-OBJ_FILES= $(C_FILES:%.c=$(OBJDIR)/%.o)
-
-ALL_CFLAGS = @CFLAGS@ @DEFS@ -I$(INCDIR) $(ERL_INTERFACE_FLAGS) $(CFLAGS)
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-ifeq ($(SKIP_BUILDING_BINARIES), true)
-debug opt:
-else
-debug opt: $(LIBRARY)
-endif
-
-clean:
- rm -f $(LIBRARY) $(OBJ_FILES)
- rm -f core *~
-
-docs:
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-_create_dirs := $(shell mkdir -p $(OBJDIR) $(LIBDIR))
-
-$(LIBRARY): $(OBJ_FILES)
- -$(V_AR) $(AR_OUT) $@ $(OBJ_FILES)
- -$(V_RANLIB) $@
-
-$(OBJDIR)/%.o: %.c
- $(V_CC) $(CC_FLAGS) -c -o $@ $(ALL_CFLAGS) $<
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/c_src"
- $(INSTALL_DIR) "$(RELSYSDIR)/include"
- $(INSTALL_DIR) "$(RELSYSDIR)/priv/lib"
- $(INSTALL_DIR) "$(RELEASE_PATH)/usr/include"
- $(INSTALL_DIR) "$(RELEASE_PATH)/usr/lib"
- $(INSTALL_DATA) ic.c ic_tmo.c "$(RELSYSDIR)/c_src"
- $(INSTALL_DATA) $(IDL_FILES) $(H_FILES) "$(RELSYSDIR)/include"
- $(INSTALL_DATA) $(LIBRARY) "$(RELSYSDIR)/priv/lib"
- $(INSTALL_DATA) $(IDL_FILES) $(H_FILES) "$(RELEASE_PATH)/usr/include"
- $(INSTALL_DATA) $(LIBRARY) "$(RELEASE_PATH)/usr/lib"
-
-release_docs_spec:
-
-
-
-
-
-
diff --git a/lib/ic/c_src/Makefile.win32 b/lib/ic/c_src/Makefile.win32
deleted file mode 100644
index 670a17f958..0000000000
--- a/lib/ic/c_src/Makefile.win32
+++ /dev/null
@@ -1,109 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1999-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-
-CC = cl.exe
-LIBRARIAN = lib.exe /nologo
-
-IC_INCLUDE = ..\include
-EI_INCLUDE = \erts\lib\erl_interface\src
-
-CFLAGS = /MT /nologo /Ox /I$(IC_INCLUDE) /I$(EI_INCLUDE)
-TARGET = win32
-OBJDIR = ..\priv\obj\$(TARGET)
-LIBDIR = ..\priv\lib\$(TARGET)
-
-
-C_FILES = \
- ic.c \
- oe_ei_encode_version.c \
- oe_ei_encode_long.c \
- oe_ei_encode_ulong.c \
- oe_ei_encode_double.c \
- oe_ei_encode_char.c \
- oe_ei_encode_string.c \
- oe_ei_encode_atom.c \
- oe_ei_encode_pid.c \
- oe_ei_encode_port.c \
- oe_ei_encode_ref.c \
- oe_ei_encode_term.c \
- oe_ei_encode_tuple_header.c \
- oe_ei_encode_list_header.c \
- oe_ei_encode_longlong.c \
- oe_ei_encode_ulonglong.c \
- oe_ei_encode_wchar.c \
- oe_ei_encode_wstring.c \
- oe_ei_decode_longlong.c \
- oe_ei_decode_ulonglong.c \
- oe_ei_decode_wchar.c \
- oe_ei_decode_wstring.c
-
-OBJ_FILES = \
- $(OBJDIR)\ic.obj \
- $(OBJDIR)\oe_ei_encode_version.obj \
- $(OBJDIR)\oe_ei_encode_long.obj \
- $(OBJDIR)\oe_ei_encode_ulong.obj \
- $(OBJDIR)\oe_ei_encode_double.obj \
- $(OBJDIR)\oe_ei_encode_char.obj \
- $(OBJDIR)\oe_ei_encode_string.obj \
- $(OBJDIR)\oe_ei_encode_atom.obj \
- $(OBJDIR)\oe_ei_encode_pid.obj \
- $(OBJDIR)\oe_ei_encode_port.obj \
- $(OBJDIR)\oe_ei_encode_ref.obj \
- $(OBJDIR)\oe_ei_encode_term.obj \
- $(OBJDIR)\oe_ei_encode_tuple_header.obj \
- $(OBJDIR)\oe_ei_encode_list_header.obj \
- $(OBJDIR)\oe_ei_encode_longlong.obj \
- $(OBJDIR)\oe_ei_encode_ulonglong.obj \
- $(OBJDIR)\oe_ei_encode_wchar.obj \
- $(OBJDIR)\oe_ei_encode_wstring.obj \
- $(OBJDIR)\oe_ei_decode_longlong.obj \
- $(OBJDIR)\oe_ei_decode_ulonglong.obj \
- $(OBJDIR)\oe_ei_decode_wchar.obj \
- $(OBJDIR)\oe_ei_decode_wstring.obj
-
-
-LIBRARY = $(LIBDIR)\ic.lib
-
-
-all: $(OBJDIR) $(LIBDIR) $(LIBRARY)
-
-release:
- echo "Nothing to do"
-
-clean:
- -del $(OBJ_FILES) $(LIBRARY)
-
-$(LIBRARY): $(OBJ_FILES)
- $(LIBRARIAN) /OUT:$@ $**
-
-{}.c{$(OBJDIR)}.obj:
- $(CC) $(CFLAGS) /c /Fo$@ $<
-
-$(OBJDIR):
- -mkdir $(OBJDIR)
-
-$(LIBDIR):
- -mkdir $(LIBDIR)
-
-$(LIBRARY):
-
-
-{}.c: $(EI_INCLUDE)\ei.h $(IC_INCLUDE)\ic.
diff --git a/lib/ic/c_src/ic.c b/lib/ic/c_src/ic.c
deleted file mode 100644
index 6e55a13f4f..0000000000
--- a/lib/ic/c_src/ic.c
+++ /dev/null
@@ -1,613 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1998-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include <ic.h>
-
-static int oe_send(CORBA_Environment *env);
-
-void CORBA_free(void *p)
-{
- if (p != NULL)
- free(p);
-}
-
-
-CORBA_char *CORBA_string_alloc(CORBA_unsigned_long len)
-{
- return (CORBA_char *) malloc(len+1);
-}
-
-
-CORBA_wchar *CORBA_wstring_alloc(CORBA_unsigned_long len)
-{
- return (CORBA_wchar *) malloc(len*(__OE_WCHAR_SIZE_OF__+1));
-}
-
-
-CORBA_Environment *CORBA_Environment_alloc(int inbufsz, int outbufsz)
-{
- CORBA_Environment *env;
-
- env = malloc(sizeof(CORBA_Environment));
-
- if (env != NULL) {
-
- /* CORBA */
- env->_major = CORBA_NO_EXCEPTION;
-
- /* Set by user */
- env->_fd= -1;
- env->_inbufsz = inbufsz;
- env->_inbuf = malloc(inbufsz);
- env->_outbufsz = outbufsz;
- env->_outbuf = malloc(outbufsz);
- env->_memchunk = __OE_MEMCHUNK__;
- env->_regname[0] = '\0';
- env->_to_pid = NULL;
- env->_from_pid = NULL;
-
- /* Set by client or server */
- env->_iin = 0;
- env->_iout = 0;
- env->_operation[0] = '\0';
- env->_received = 0;
- /* env->_caller */
- /* env->_unique */
- env->_exc_id = NULL;
- env->_exc_value = NULL;
- env->_ref_counter_1 = 0;
- env->_ref_counter_2 = 0;
- env->_ref_counter_3 = 0;
- }
-
- return env;
-}
-
-#if 0
-/* NOT EXPORTED SO FAR */
-void CORBA_Environment_free(CORBA_Environment *env)
-{
-
- CORBA_free(env->_inbuf);
- CORBA_free(env->_outbuf);
- CORBA_exception_free(env);
- CORBA_free(env);
-}
-#endif
-
-
-CORBA_char *CORBA_exception_id(CORBA_Environment *env)
-{
-
- return env->_exc_id;
-}
-
-void *CORBA_exception_value(CORBA_Environment *env)
-{
-
- return env->_exc_value;
-}
-
-void CORBA_exception_free(CORBA_Environment *env)
-{
-
- /* Setting major value */
- env->_major=CORBA_NO_EXCEPTION;
-
- /* Freeing storage */
- CORBA_free(env->_exc_id);
- CORBA_free(env->_exc_value);
- env->_exc_id = env->_exc_value = NULL;
-}
-
-void CORBA_exc_set(CORBA_Environment *env,
- CORBA_exception_type Major,
- CORBA_char *Id,
- CORBA_char *Value)
-{
- int ilen,vlen;
-
- /* Create exception only if exception not already set */
- if (env->_major == CORBA_NO_EXCEPTION) {
-
- /* Counting lengths */
- ilen = strlen(Id)+1;
- vlen = strlen(Value)+1;
-
- /* Allocating storage */
- env->_exc_id = (CORBA_char *) malloc(ilen);
- env->_exc_value = (CORBA_char *) malloc(vlen);
-
- /* Initiating */
- env->_major = Major;
- strcpy(env->_exc_id,Id);
- strcpy(env->_exc_value,Value);
- }
-}
-
-#define ERLANG_REF_NUM_SIZE 18
-#define ERLANG_REF_MASK (~(~((unsigned int)0) << ERLANG_REF_NUM_SIZE))
-
-/* Initiating message reference */
-void ic_init_ref(CORBA_Environment *env, erlang_ref *ref)
-{
-
- strcpy(ref->node, erl_thisnodename());
-
- ref->len = 3;
-
- ++env->_ref_counter_1;
- env->_ref_counter_1 &= ERLANG_REF_MASK;
- if (env->_ref_counter_1 == 0)
- if (++env->_ref_counter_2 == 0)
- ++env->_ref_counter_3;
- ref->n[0] = env->_ref_counter_1;
- ref->n[1] = env->_ref_counter_2;
- ref->n[2] = env->_ref_counter_3;
-
- ref->creation = erl_thiscreation();
-}
-
-/* Comparing message references */
-int ic_compare_refs(erlang_ref *ref1, erlang_ref *ref2)
-{
- int i;
-
- if(strcmp(ref1->node, ref2->node) != 0)
- return -1;
-
- if (ref1->len != ref2->len)
- return -1;
-
- for (i = 0; i < ref1->len; i++)
- if (ref1->n[i] != ref2->n[i])
- return -1;
-
- return 0;
-}
-
-/* Length counter for wide strings */
-int ic_wstrlen(CORBA_wchar * p)
-{
- int len = 0;
-
- while(1) {
- if (p[len] == 0)
- return len;
-
- len+=1;
- }
-}
-
-
-/* Wide string compare function */
-int ic_wstrcmp(CORBA_wchar * ws1, CORBA_wchar * ws2)
-{
- int index = 0;
-
- while(1) {
- if (ws1[index] == ws2[index]) {
-
- if (ws1[index] == 0)
- return 0;
-
- index += 1;
-
- } else
- return -1;
- }
-}
-
-/* For backward compatibility -- replaced by prepare_request_decoding() */
-int ___call_info___(CORBA_Object obj, CORBA_Environment *env)
-{
- return oe_prepare_request_decoding(env);
-}
-
-/* #define DEBUG_MAP */
-
-#if defined(DEBUG_MAP)
-
-#define PRINT_MAPS(P, M, S) print_maps(P, M, S)
-#define PRINT_MAP(T, M) print_map(T, "", M)
-
-static void print_map(char *title, char *prefix, oe_map_t *map)
-{
- if (map == NULL) {
- fprintf(stdout, "%s => NULL\n", title);
- return;
- }
-
- fprintf(stdout, "%s%s\n", prefix, title);
-
- {
- int j, len = map->length;
-
- fprintf(stdout, "%s length: %d\n", prefix, len);
- fprintf(stdout, "%s operations: 0x%X%d\n", prefix, map->operations);
-
- for (j = 0 ; j < len ; j++) {
- fprintf(stdout, "%s operation[%d]:\n", prefix, j);
-
- if (map->operations[j].interface != NULL) {
- fprintf(stdout, "%s intf: %s\n", prefix,
- map->operations[j].interface);
- } else {
- fprintf(stdout, "%s intf: NULL\n", prefix);
- }
- fprintf(stdout, "%s name: %s\n", prefix,
- map->operations[j].name);
- fprintf(stdout, "%s func: 0x%X\n", prefix,
- map->operations[j].function);
- }
- }
- fflush(stdout);
-}
-
-static void print_maps(char* title, oe_map_t * maps, int size)
-{
- int i;
- char p[64];
-
- fprintf(stdout, "%s\n", title);
-
- for (i = 0 ; i < size ; i++) {
- sprintf(p, "map[%d]:", i);
- print_map(p, " ", &maps[i]);
- }
- fprintf(stdout, "\n");
- fflush(stdout);
-}
-
-#else
-
-#define PRINT_MAPS(P, M, S)
-#define PRINT_MAP(T, M)
-
-#endif /* if defined(DEBUG_MAP) */
-
-
-/* Generic server switch */
-int oe_exec_switch(CORBA_Object obj, CORBA_Environment *env, oe_map_t *map)
-{
- /* Setting local variables */
- int res = 0;
- int index = 0;
-
- /* XXX map may be NULL !! */
- int length = map->length;
- char* op = env->_operation;
-
- PRINT_MAP("switching on map", map);
-
- /* Initiating exception indicator */
- env->_major = CORBA_NO_EXCEPTION;
-
- if ((res = oe_prepare_request_decoding(env) < 0))
- return res;
-#if defined(DEBUG_MAP)
- fprintf(stdout, "looking for operation: %s\n", op); fflush(stdout);
-#endif
- for (index = 0; index < length; index++) {
-#if defined(DEBUG_MAP)
- fprintf(stdout, "map->operations[%d].name: %s\n",
- index, map->operations[index].name);
- fflush(stdout);
-#endif
- if(strcmp(map->operations[index].name, op) == 0) {
-#if defined(DEBUG_MAP)
- fprintf(stdout, "calling map->operations[%d].function: 0x%X\n",
- index, map->operations[index].function);
- fflush(stdout);
-#endif
- return map->operations[index].function(obj, env);
- }
- }
- /* Bad call */
- CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, BAD_OPERATION,
- "Invalid operation");
- return -1;
-}
-
-/* For backward compatibility */
-int ___switch___(CORBA_Object obj, CORBA_Environment *env, oe_map_t *map)
-{
- return oe_exec_switch(obj, env, map);
-}
-
-
-oe_map_t* oe_merge_maps(oe_map_t *maps, int size)
-{
- int i, j, length, len, maplen, malloc_size;
- void *memp;
- oe_map_t *merged;
-
- if ((maps == NULL) || (size <= 0))
- return NULL;
-
- PRINT_MAPS("merging maps", maps, size);
-
- length = 0;
- for (i = 0; i < size; i++)
- length += (maps[i].length);
-
- maplen = OE_ALIGN(sizeof(oe_map_t));
- malloc_size = maplen + OE_ALIGN(length*sizeof(oe_operation_t));
- if ((memp = malloc(malloc_size)) == NULL)
- return NULL;
-
- merged = memp;
- merged->length = length;
- merged->operations = (oe_operation_t *)((char*)memp + maplen);
-
- for (i = 0, len = 0; i < size; i++) {
- for(j = 0 ; j < maps[i].length; j++)
- merged->operations[len+j] = maps[i].operations[j];
- len += maps[i].length;
- }
- PRINT_MAP("merged map", merged);
- return merged;
-}
-
-/* For backward compatibility */
-oe_map_t* ___merge___(oe_map_t *maps, int size)
-{
- return oe_merge_maps(maps, size);
-}
-
-/* Client send message (Erlang distribution protocol) */
-static int oe_send(CORBA_Environment *env)
-{
- if (strlen(env->_regname) == 0) {
- if (ei_send_encoded(env->_fd, env->_to_pid, env->_outbuf,
- env->_iout) < 0) {
- /* XXX Cannot send to peer? */
- CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, NO_RESPONSE,
- "Cannot connect to server");
- return -1;
- }
- } else {
- if (ei_send_reg_encoded(env->_fd, env->_from_pid,
- env->_regname, env->_outbuf,
- env->_iout) < 0) {
- /* XXX Cannot send to peer? */
- CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, NO_RESPONSE,
- "Cannot connect to server");
- return -1;
- }
- }
- return 0;
-}
-
-/* Send notification (gen_server client) */
-int oe_send_notification(CORBA_Environment *env)
-{
- return oe_send(env);
-}
-
-/* Send request and receive reply (gen_server client) */
-int oe_send_request_and_receive_reply(CORBA_Environment *env)
-{
- int msgType = 0;
- erlang_msg msg;
-
- if (oe_send(env) < 0)
- return -1;
-
- do {
- if ((msgType = ei_receive_encoded(env->_fd,
- &env->_inbuf,
- &env->_inbufsz,
- &msg, &env->_iin)) < 0) {
- CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, MARSHAL,
- "Cannot decode message");
- return -1;
- }
- } while (msgType != ERL_SEND && msgType != ERL_REG_SEND);
-
- /* Extracting return message header */
- if (oe_prepare_reply_decoding(env) < 0) {
- CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, MARSHAL, "Bad message");
- return -1;
- }
- return 0;
-}
-
-/* Prepare notification encoding (gen_server client) */
-int oe_prepare_notification_encoding(CORBA_Environment *env)
-{
- env->_iout = 0;
- oe_ei_encode_version(env);
- oe_ei_encode_tuple_header(env, 2);
- oe_ei_encode_atom(env, "$gen_cast");
- return 0;
-}
-
-/* Prepare request encoding (gen_server client) */
-int oe_prepare_request_encoding(CORBA_Environment *env)
-{
- int error = 0;
-
- env->_iout = 0;
- oe_ei_encode_version(env);
- oe_ei_encode_tuple_header(env, 3);
- oe_ei_encode_atom(env, "$gen_call");
- oe_ei_encode_tuple_header(env, 2);
- if ((error = oe_ei_encode_pid(env, env->_from_pid)) < 0)
- return error;
- if ((error = oe_ei_encode_ref(env, &env->_unique)) < 0)
- return error;
- return 0;
-}
-
-/* Prepare reply decoding (gen_server client) */
-int oe_prepare_reply_decoding(CORBA_Environment *env)
-{
- int error = 0;
- int version = 0;
- erlang_ref unique;
-
- env->_iin = 0;
- env->_received = 0;
-
- if ((error = ei_decode_version(env->_inbuf,
- &env->_iin,
- &version)) < 0)
- return error;
- if ((error = ei_decode_tuple_header(env->_inbuf,
- &env->_iin,
- &env->_received)) < 0)
- return error;
- if ((error = ei_decode_ref(env->_inbuf,
- &env->_iin,
- &unique)) < 0)
- return error;
- return ic_compare_refs(&env->_unique, &unique);
-}
-
-
-/* Prepare request decoding (gen_server server) */
-int oe_prepare_request_decoding(CORBA_Environment *env)
-{
- char gencall_atom[10];
- int error = 0;
- int version = 0;
-
- env->_iin = 0;
- env->_received = 0;
- memset(gencall_atom, 0, 10);
- ei_decode_version(env->_inbuf, &env->_iin, &version);
- ei_decode_tuple_header(env->_inbuf, &env->_iin, &env->_received);
- ei_decode_atom(env->_inbuf, &env->_iin, gencall_atom);
-
- if (strcmp(gencall_atom, "$gen_cast") == 0) {
- if ((error = ei_decode_atom(env->_inbuf, &env->_iin,
- env->_operation)) < 0) {
- ei_decode_tuple_header(env->_inbuf, &env->_iin, &env->_received);
- if ((error = ei_decode_atom(env->_inbuf, &env->_iin,
- env->_operation)) < 0) {
- CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, BAD_OPERATION,
- "Bad Message, cannot extract operation");
- return error;
- }
- env->_received -= 1;
- } else
- env->_received -= 2;
- return 0;
- }
- if (strcmp(gencall_atom, "$gen_call") == 0) {
- ei_decode_tuple_header(env->_inbuf, &env->_iin, &env->_received);
- if ((error = ei_decode_pid(env->_inbuf, &env->_iin,
- &env->_caller)) < 0) {
- CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, MARSHAL,
- "Bad Message, bad caller identity");
- return error;
- }
- if ((error = ei_decode_ref(env->_inbuf, &env->_iin,
- &env->_unique)) < 0) {
- CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, MARSHAL,
- "Bad Message, bad message reference");
- return error;
- }
- if ((error = ei_decode_atom(env->_inbuf, &env->_iin,
- env->_operation)) < 0) {
-
- ei_decode_tuple_header(env->_inbuf, &env->_iin, &env->_received);
-
- if ((error = ei_decode_atom(env->_inbuf, &env->_iin,
- env->_operation)) < 0) {
- CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, BAD_OPERATION,
- "Bad Message, cannot extract operation");
- return error;
- }
- env->_received -= 1;
- return 0;
- }
- else {
- env->_received -= 2;
- return 0;
- }
- }
-
- CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, MARSHAL,
- "Bad message, neither cast nor call");
- return -1;
-}
-
-/* Prepare reply encoding (gen_server server) */
-int oe_prepare_reply_encoding(CORBA_Environment *env)
-{
- env->_iout = 0;
- oe_ei_encode_version(env);
- oe_ei_encode_tuple_header(env, 2);
- oe_ei_encode_ref(env, &env->_unique);
- return 0;
-}
-
-/* ---- Function for making it more easy to implement a server */
-/* Server receive (possibly) send reply (gen_server server) */
-
-int oe_server_receive(CORBA_Environment *env, oe_map_t *map)
-{
- int res = 0, loop = 1;
- erlang_msg msg;
-
- while (res >= 0 && loop > 0) {
- res = ei_receive_encoded(env->_fd, &env->_inbuf, &env->_inbufsz,
- &msg, &env->_iin);
- switch(res) {
- case ERL_SEND:
- case ERL_REG_SEND:
- oe_exec_switch(NULL, env, map);
- switch(env->_major) {
- case CORBA_NO_EXCEPTION:
- break;
- case CORBA_SYSTEM_EXCEPTION:
- /* XXX stderr */
- fprintf(stderr, "Request failure, reason : %s\n",
- (char *) CORBA_exception_value(env));
- CORBA_exception_free(env);
- break;
- default: /* Should not happen */
- CORBA_exception_free(env);
- break;
- }
- /* send reply */
- /* XXX We are required to set env->_iout = 0 if oneway?? */
- if (env->_iout > 0)
- ei_send_encoded(env->_fd, &env->_caller, env->_outbuf,
- env->_iout);
- loop = 0;
- break;
- case ERL_TICK:
- break;
- default:
- /* XXX */
- if (res < 0) {
- fprintf(stderr, "Result negative: %d\n", res);
- loop = 0;
- }
- break;
- }
- }
-
- return 0;
-}
-
diff --git a/lib/ic/c_src/ic_tmo.c b/lib/ic/c_src/ic_tmo.c
deleted file mode 100644
index ef66f67d55..0000000000
--- a/lib/ic/c_src/ic_tmo.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 2004-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include <ic.h>
-
-static int oe_send_tmo(CORBA_Environment *env, unsigned int ms);
-
-/* Client send message (Erlang distribution protocol) */
-static int oe_send_tmo(CORBA_Environment *env, unsigned int ms)
-{
- if (strlen(env->_regname) == 0) {
- if (ei_send_encoded_tmo(env->_fd, env->_to_pid, env->_outbuf,
- env->_iout, ms) < 0) {
- /* XXX Cannot send to peer? */
- CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, NO_RESPONSE,
- "Cannot connect to server");
- return -1;
- }
- } else {
- if (ei_send_reg_encoded_tmo(env->_fd, env->_from_pid,
- env->_regname, env->_outbuf,
- env->_iout, ms) < 0) {
- /* XXX Cannot send to peer? */
- CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, NO_RESPONSE,
- "Cannot connect to server");
- return -1;
- }
- }
- return 0;
-}
-
-/* Send notification (gen_server client) */
-int oe_send_notification_tmo(CORBA_Environment *env, unsigned int send_ms)
-{
- return oe_send_tmo(env, send_ms);
-}
-
-/* Send request and receive reply (gen_server client) */
-int oe_send_request_and_receive_reply_tmo(CORBA_Environment *env,
- unsigned int send_ms,
- unsigned int recv_ms)
-{
- int msgType = 0;
- erlang_msg msg;
-
- if (oe_send_tmo(env, send_ms) < 0)
- return -1;
-
- do {
- if ((msgType = ei_receive_encoded_tmo(env->_fd,
- &env->_inbuf,
- &env->_inbufsz,
- &msg, &env->_iin,
- recv_ms)) < 0) {
- CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, MARSHAL,
- "Cannot decode message");
- return -1;
- }
- } while (msgType != ERL_SEND && msgType != ERL_REG_SEND);
-
- /* Extracting return message header */
- if (oe_prepare_reply_decoding(env) < 0) {
- CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, MARSHAL, "Bad message");
- return -1;
- }
- return 0;
-}
-
-/* Server receive (possibly) send reply (gen_server server) */
-
-int oe_server_receive_tmo(CORBA_Environment *env, oe_map_t *map,
- unsigned int send_ms,
- unsigned int recv_ms)
-{
- int res = 0, loop = 1;
- erlang_msg msg;
-
- while (res >= 0 && loop > 0) {
- res = ei_receive_encoded_tmo(env->_fd, &env->_inbuf, &env->_inbufsz,
- &msg, &env->_iin, recv_ms);
- switch(res) {
- case ERL_SEND:
- case ERL_REG_SEND:
- oe_exec_switch(NULL, env, map);
- switch(env->_major) {
- case CORBA_NO_EXCEPTION:
- break;
- case CORBA_SYSTEM_EXCEPTION:
- /* XXX stderr */
- fprintf(stderr, "Request failure, reason : %s\n",
- (char *) CORBA_exception_value(env));
- CORBA_exception_free(env);
- break;
- default: /* Should not happen */
- CORBA_exception_free(env);
- break;
- }
- /* send reply */
- /* XXX We are required to set env->_iout = 0 if oneway?? */
- if (env->_iout > 0)
- ei_send_encoded_tmo(env->_fd, &env->_caller, env->_outbuf,
- env->_iout, send_ms);
- loop = 0;
- break;
- case ERL_TICK:
- break;
- default:
- /* XXX */
- if (res < 0) {
- fprintf(stderr, "Result negative: %d\n", res);
- loop = 0;
- }
- break;
- }
- }
-
- return 0;
-}
-
diff --git a/lib/ic/c_src/oe_ei_code_erlang_binary.c b/lib/ic/c_src/oe_ei_code_erlang_binary.c
deleted file mode 100644
index 81610facbc..0000000000
--- a/lib/ic/c_src/oe_ei_code_erlang_binary.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 2001-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include <ic.h>
-
-
-int oe_encode_erlang_binary(CORBA_Environment *ev, erlang_binary *binary) {
-
- int size = ev->_iout;
-
- ei_encode_binary(0, &size, binary->_buffer, binary->_length);
-
- if (size >= ev->_outbufsz) {
- char *buf = ev->_outbuf;
- int bufsz = ev->_outbufsz + ev->_memchunk;
-
- while (size >= bufsz)
- bufsz += ev->_memchunk;
-
- if ((buf = realloc(buf, bufsz)) == NULL) {
- CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding");
- return -1; /* OUT OF MEMORY */
- }
-
- ev->_outbuf = buf;
- ev->_outbufsz = bufsz;
- }
-
- return ei_encode_binary(ev->_outbuf, &ev->_iout, binary->_buffer, binary->_length);
-}
-
-
-
-int oe_sizecalc_erlang_binary(CORBA_Environment *ev, int* _index, int* _size) {
-
- long _malloc_size = 0;
- int _error = 0;
-
- if(*_size == 0)
- *_size = ((*_size + sizeof(erlang_binary))+sizeof(double)-1)&~(sizeof(double)-1);
-
- if ((_error = ei_decode_binary(ev->_inbuf, _index, 0, &_malloc_size)) < 0)
- return _error;
-
- *_size = ((*_size + (int)_malloc_size)+sizeof(double)-1)&~(sizeof(double)-1);
-
- return 0;
-}
-
-
-int oe_decode_erlang_binary(CORBA_Environment *ev, char *_first, int* _index, erlang_binary *binary) {
-
- long _length = 0;
- int _error = 0;
-
- if((char*) binary == _first)
- *_index = ((*_index + sizeof(erlang_binary))+sizeof(double)-1)&~(sizeof(double)-1);
-
- binary->_buffer = (CORBA_octet *)(_first+*_index);
-
- if ((_error = ei_decode_binary(ev->_inbuf, &ev->_iin, binary->_buffer, &_length)) < 0)
- return _error;
-
- binary->_length = (CORBA_unsigned_long)_length;
-
- *_index = ((*_index)+_length+sizeof(double)-1)&~(sizeof(double)-1);
-
- return 0;
-}
-
-
-
-int print_erlang_binary(erlang_binary *binary) {
-
- int i=0;
-
- if (binary == NULL)
- return -1;
-
- fprintf(stdout,"binary->_length : %ld\n",binary->_length);
- fprintf(stdout,"binary->_buffer : ");
- if(binary->_buffer != NULL) {
- for (i=0; i<binary->_length; i++)
- fprintf(stdout,"%c",binary->_buffer[i]);
- fprintf(stdout,"\n");
- } else
- fprintf(stdout,"NULL\n");
- return 0;
-}
diff --git a/lib/ic/c_src/oe_ei_decode_longlong.c b/lib/ic/c_src/oe_ei_decode_longlong.c
deleted file mode 100644
index 7d872ce94f..0000000000
--- a/lib/ic/c_src/oe_ei_decode_longlong.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include <ic.h>
-
-
-int oe_ei_decode_longlong(const char *buf, int *index, CORBA_long_long *p) {
- return ei_decode_long(buf, index, p);
-}
diff --git a/lib/ic/c_src/oe_ei_decode_ulonglong.c b/lib/ic/c_src/oe_ei_decode_ulonglong.c
deleted file mode 100644
index d071d09a43..0000000000
--- a/lib/ic/c_src/oe_ei_decode_ulonglong.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include <ic.h>
-
-
-int oe_ei_decode_ulonglong(const char *buf, int *index, CORBA_unsigned_long_long *p) {
- return ei_decode_ulong(buf, index, p);
-}
diff --git a/lib/ic/c_src/oe_ei_decode_wchar.c b/lib/ic/c_src/oe_ei_decode_wchar.c
deleted file mode 100644
index bb6899b7b3..0000000000
--- a/lib/ic/c_src/oe_ei_decode_wchar.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include <ic.h>
-
-
-int oe_ei_decode_wchar(const char *buf, int *index, CORBA_wchar *p) {
- return ei_decode_ulong(buf, index, p);
-}
diff --git a/lib/ic/c_src/oe_ei_decode_wstring.c b/lib/ic/c_src/oe_ei_decode_wstring.c
deleted file mode 100644
index 5b676fd579..0000000000
--- a/lib/ic/c_src/oe_ei_decode_wstring.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include <ic.h>
-
-
-/* Scratch function */
-int oe_ei_decode_wstring(const char *buf, int *index, CORBA_wchar *p) {
-
- int length,error_code,type,tmp=0;
- char * tmp_space = NULL;
-
-
- if ((error_code = ei_get_type(buf, index, &type, &length)) < 0)
- return error_code;
-
- switch(type) {
-
- case ERL_LIST_EXT: /* A list */
- case ERL_NIL_EXT: /* An empty list */
-
- if (p) { /* Decoding part */
-
- if ((error_code = ei_decode_list_header(buf, index, &length)) < 0)
- return error_code;
-
- if (length != 0) {
- for(tmp = 0; tmp < length; tmp++)
- if ((error_code = oe_ei_decode_wchar(buf, index, &(p[tmp]))) < 0)
- return error_code;
-
- /* Read list tail also */
- if ((error_code = ei_decode_list_header(buf, index, &length)) < 0)
- return error_code;
- }
-
- p[tmp] = 0; /* Wide NULL */
-
- } else { /* Allocation counting part */
-
- if ((error_code = ei_decode_list_header(buf, index, &length)) < 0)
- return error_code;
-
- if (length != 0) {
- for(tmp = 0; tmp < length; tmp++)
- if ((error_code = oe_ei_decode_wchar(buf, index, 0)) < 0)
- return error_code;
-
- /* Read list tail also */
- if ((error_code = ei_decode_list_header(buf, index, &length)) < 0)
- return error_code;
- }
- }
-
- break;
-
- case ERL_STRING_EXT: /* A string */
-
- if (p) { /* Decoding part */
-
- /* Allocate temporary string */
- tmp_space = (char*) malloc(length*(__OE_WCHARSZ__+1));
-
- if ((error_code = ei_decode_string(buf, index, tmp_space)) < 0)
- return error_code;
-
- /* Assign characters to wide characters */
- for(tmp = 0; tmp < length; tmp++)
- p[tmp] = tmp_space[tmp];
-
- p[tmp] = 0; /* Wide NULL */
-
- /* Free temporary string */
- CORBA_free(tmp_space);
-
- } else { /* Allocation counting part */
-
- if ((error_code = ei_decode_string(buf, index, 0)) < 0)
- return error_code;
-
- }
- break;
-
- default: /* Bad header */
- return -1;
- }
-
- return 0;
-}
-
-
diff --git a/lib/ic/c_src/oe_ei_encode_atom.c b/lib/ic/c_src/oe_ei_encode_atom.c
deleted file mode 100644
index 758586d1d4..0000000000
--- a/lib/ic/c_src/oe_ei_encode_atom.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1998-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include <ic.h>
-
-
-int oe_ei_encode_atom(CORBA_Environment *ev, const char *p) {
- int size = ev->_iout;
-
- ei_encode_atom(0,&size,p);
-
- if (size >= ev->_outbufsz) {
- char *buf = ev->_outbuf;
- int bufsz = ev->_outbufsz + ev->_memchunk;
-
- while (size >= bufsz)
- bufsz += ev->_memchunk;
-
- if ((buf = realloc(buf, bufsz)) == NULL) {
- CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding");
- return -1; /* OUT OF MEMORY */
- }
-
- ev->_outbuf = buf;
- ev->_outbufsz = bufsz;
- }
-
- return ei_encode_atom(ev->_outbuf,&ev->_iout,p);
-}
-
diff --git a/lib/ic/c_src/oe_ei_encode_char.c b/lib/ic/c_src/oe_ei_encode_char.c
deleted file mode 100644
index 9079cb4ecc..0000000000
--- a/lib/ic/c_src/oe_ei_encode_char.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1998-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include <ic.h>
-
-
-int oe_ei_encode_char(CORBA_Environment *ev, char p) {
- int size = ev->_iout + __OE_CHARSZ__;
-
- if (size >= ev->_outbufsz) {
- char *buf = ev->_outbuf;
- int bufsz = ev->_outbufsz + ev->_memchunk;
-
- if ((buf = realloc(buf,bufsz)) != NULL) {
- ev->_outbuf = buf;
- ev->_outbufsz += ev->_memchunk;
- }
- else {
- CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding");
- return -1; /* OUT OF MEMORY */
- }
- }
-
- return ei_encode_char(ev->_outbuf, &ev->_iout, p);
-}
-
-
-
diff --git a/lib/ic/c_src/oe_ei_encode_double.c b/lib/ic/c_src/oe_ei_encode_double.c
deleted file mode 100644
index 95fed6ff25..0000000000
--- a/lib/ic/c_src/oe_ei_encode_double.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1998-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include <ic.h>
-
-
-int oe_ei_encode_double(CORBA_Environment *ev, double p) {
- int size = ev->_iout + __OE_DOUBLESZ__;
-
- if (size >= ev->_outbufsz) {
- char *buf = ev->_outbuf;
- int bufsz = ev->_outbufsz + ev->_memchunk;
-
- if ((buf = realloc(buf,bufsz)) != NULL) {
- ev->_outbuf = buf;
- ev->_outbufsz += ev->_memchunk;
- }
- else {
- CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding");
- return -1; /* OUT OF MEMORY */
- }
- }
-
- return ei_encode_double(ev->_outbuf, &ev->_iout, p);
-}
-
-
diff --git a/lib/ic/c_src/oe_ei_encode_list_header.c b/lib/ic/c_src/oe_ei_encode_list_header.c
deleted file mode 100644
index 57a0fc0d0f..0000000000
--- a/lib/ic/c_src/oe_ei_encode_list_header.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1998-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include <ic.h>
-
-
-int oe_ei_encode_list_header(CORBA_Environment *ev, int arity) {
- int size = ev->_iout + __OE_LISTHDRSZ__;
-
- if (size >= ev->_outbufsz) {
- char *buf = ev->_outbuf;
- int bufsz = ev->_outbufsz + ev->_memchunk;
-
- if ((buf = realloc(buf,bufsz)) != NULL) {
- ev->_outbuf = buf;
- ev->_outbufsz += ev->_memchunk;
- }
- else {
- CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding");
- return -1; /* OUT OF MEMORY */
- }
- }
-
- return ei_encode_list_header(ev->_outbuf, &ev->_iout, arity);
-}
diff --git a/lib/ic/c_src/oe_ei_encode_long.c b/lib/ic/c_src/oe_ei_encode_long.c
deleted file mode 100644
index c0d8599b95..0000000000
--- a/lib/ic/c_src/oe_ei_encode_long.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1998-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include <ic.h>
-
-
-int oe_ei_encode_long(CORBA_Environment *ev, long p) {
- int size = ev->_iout + __OE_LONGSZ__;
-
- if (size >= ev->_outbufsz) {
- char *buf = ev->_outbuf;
- int bufsz = ev->_outbufsz + ev->_memchunk;
-
- if ((buf = realloc(buf,bufsz)) != NULL) {
- ev->_outbuf = buf;
- ev->_outbufsz += ev->_memchunk;
- }
- else {
- CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding");
- return -1; /* OUT OF MEMORY */
- }
- }
-
- return ei_encode_long(ev->_outbuf, &ev->_iout, p);
-}
-
-
-
diff --git a/lib/ic/c_src/oe_ei_encode_longlong.c b/lib/ic/c_src/oe_ei_encode_longlong.c
deleted file mode 100644
index ac208f1982..0000000000
--- a/lib/ic/c_src/oe_ei_encode_longlong.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include <ic.h>
-
-
-int oe_ei_encode_longlong(CORBA_Environment *ev, CORBA_long_long p) {
- int size = ev->_iout + __OE_LONGLONGSZ__;
-
- if (size >= ev->_outbufsz) {
- char *buf = ev->_outbuf;
- int bufsz = ev->_outbufsz + ev->_memchunk;
-
- if ((buf = realloc(buf,bufsz)) != NULL) {
- ev->_outbuf = buf;
- ev->_outbufsz += ev->_memchunk;
- }
- else {
- CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding");
- return -1; /* OUT OF MEMORY */
- }
- }
-
- /* CORBA_long_long = long because of erl_interface limitation */
- return ei_encode_long(ev->_outbuf, &ev->_iout, p);
-}
-
-
diff --git a/lib/ic/c_src/oe_ei_encode_pid.c b/lib/ic/c_src/oe_ei_encode_pid.c
deleted file mode 100644
index ebd0d0b6ef..0000000000
--- a/lib/ic/c_src/oe_ei_encode_pid.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1998-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include <ic.h>
-
-
-int oe_ei_encode_pid(CORBA_Environment *ev, const erlang_pid *p) {
- int size = ev->_iout;
-
- ei_encode_pid(NULL, &size, p);
-
- if (size >= ev->_outbufsz) {
- char *buf = ev->_outbuf;
- int bufsz = ev->_outbufsz + ev->_memchunk;
-
- while (size >= bufsz)
- bufsz += ev->_memchunk;
-
- if ((buf = realloc(buf, bufsz)) == NULL) {
- CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding");
- return -1; /* OUT OF MEMORY */
- }
-
- ev->_outbuf = buf;
- ev->_outbufsz = bufsz;
- }
-
- return ei_encode_pid(ev->_outbuf, &ev->_iout, p);
-}
diff --git a/lib/ic/c_src/oe_ei_encode_port.c b/lib/ic/c_src/oe_ei_encode_port.c
deleted file mode 100644
index a4ecf846b7..0000000000
--- a/lib/ic/c_src/oe_ei_encode_port.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1998-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include <ic.h>
-
-
-int oe_ei_encode_port(CORBA_Environment *ev, const erlang_port *p) {
- int size = ev->_iout;
-
- ei_encode_port(NULL, &size, p);
-
- if (size >= ev->_outbufsz) {
- char *buf = ev->_outbuf;
- int bufsz = ev->_outbufsz + ev->_memchunk;
-
- while (size >= bufsz)
- bufsz += ev->_memchunk;
-
- if ((buf = realloc(buf, bufsz)) == NULL) {
- CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding");
- return -1; /* OUT OF MEMORY */
- }
-
- ev->_outbuf = buf;
- ev->_outbufsz = bufsz;
- }
-
- return ei_encode_port(ev->_outbuf, &ev->_iout, p);
-}
-
diff --git a/lib/ic/c_src/oe_ei_encode_ref.c b/lib/ic/c_src/oe_ei_encode_ref.c
deleted file mode 100644
index 8dcbc3aeb7..0000000000
--- a/lib/ic/c_src/oe_ei_encode_ref.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1998-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include <ic.h>
-
-
-int oe_ei_encode_ref(CORBA_Environment *ev, const erlang_ref *p) {
- int size = ev->_iout;
-
- ei_encode_ref(NULL, &size, p);
-
- if (size >= ev->_outbufsz) {
- char *buf = ev->_outbuf;
- int bufsz = ev->_outbufsz + ev->_memchunk;
-
- while (size >= bufsz)
- bufsz += ev->_memchunk;
-
- if ((buf = realloc(buf, bufsz)) == NULL) {
- CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding");
- return -1; /* OUT OF MEMORY */
- }
-
- ev->_outbuf = buf;
- ev->_outbufsz = bufsz;
- }
-
- return ei_encode_ref(ev->_outbuf, &ev->_iout, p);
-}
-
diff --git a/lib/ic/c_src/oe_ei_encode_string.c b/lib/ic/c_src/oe_ei_encode_string.c
deleted file mode 100644
index 8612835e2b..0000000000
--- a/lib/ic/c_src/oe_ei_encode_string.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1998-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include <ic.h>
-
-
-int oe_ei_encode_string(CORBA_Environment *ev, const char *p) {
- int size = ev->_iout;
-
- ei_encode_string(0,&size,p);
-
- if (size >= ev->_outbufsz) {
- char *buf = ev->_outbuf;
- int bufsz = ev->_outbufsz + ev->_memchunk;
-
- while (size >= bufsz)
- bufsz += ev->_memchunk;
-
- if ((buf = realloc(buf, bufsz)) == NULL) {
- CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding");
- return -1; /* OUT OF MEMORY */
- }
-
- ev->_outbuf = buf;
- ev->_outbufsz = bufsz;
- }
-
- return ei_encode_string(ev->_outbuf,&ev->_iout,p);
-}
-
-
diff --git a/lib/ic/c_src/oe_ei_encode_term.c b/lib/ic/c_src/oe_ei_encode_term.c
deleted file mode 100644
index c36edbf493..0000000000
--- a/lib/ic/c_src/oe_ei_encode_term.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1998-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include <ic.h>
-
-
-int oe_ei_encode_term(CORBA_Environment *ev, void *t) {
- int size = ev->_iout;
-
- ei_encode_term(NULL, &size, t);
-
- if (size >= ev->_outbufsz) {
- char *buf = ev->_outbuf;
- int bufsz = ev->_outbufsz + ev->_memchunk;
-
- while (size >= bufsz)
- bufsz += ev->_memchunk;
-
- if ((buf = realloc(buf, bufsz)) == NULL) {
- CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding");
- return -1; /* OUT OF MEMORY */
- }
-
- ev->_outbuf = buf;
- ev->_outbufsz = bufsz;
- }
-
- return ei_encode_term(ev->_outbuf, &ev->_iout, t);
-}
-
-
-
diff --git a/lib/ic/c_src/oe_ei_encode_tuple_header.c b/lib/ic/c_src/oe_ei_encode_tuple_header.c
deleted file mode 100644
index 64f8b4b873..0000000000
--- a/lib/ic/c_src/oe_ei_encode_tuple_header.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1998-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include <ic.h>
-
-
-int oe_ei_encode_tuple_header(CORBA_Environment *ev, int arity) {
- int size = ev->_iout + __OE_TUPLEHDRSZ__;
-
- if (size >= ev->_outbufsz) {
- char *buf = ev->_outbuf;
- int bufsz = ev->_outbufsz + ev->_memchunk;
-
- if ((buf = realloc(buf,bufsz)) != NULL) {
- ev->_outbuf = buf;
- ev->_outbufsz += ev->_memchunk;
- }
- else {
- CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding");
- return -1; /* OUT OF MEMORY */
- }
- }
-
- return ei_encode_tuple_header(ev->_outbuf, &ev->_iout, arity);
-}
-
-
-
diff --git a/lib/ic/c_src/oe_ei_encode_ulong.c b/lib/ic/c_src/oe_ei_encode_ulong.c
deleted file mode 100644
index 249235935e..0000000000
--- a/lib/ic/c_src/oe_ei_encode_ulong.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1998-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include <ic.h>
-
-
-int oe_ei_encode_ulong(CORBA_Environment *ev, unsigned long p) {
- int size = ev->_iout + __OE_ULONGSZ__;
-
- if (size >= ev->_outbufsz) {
- char *buf = ev->_outbuf;
- int bufsz = ev->_outbufsz + ev->_memchunk;
-
- if ((buf = realloc(buf,bufsz)) != NULL) {
- ev->_outbuf = buf;
- ev->_outbufsz += ev->_memchunk;
- }
- else {
- CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding");
- return -1; /* OUT OF MEMORY */
- }
- }
-
- return ei_encode_ulong(ev->_outbuf, &ev->_iout, p);
-}
-
-
diff --git a/lib/ic/c_src/oe_ei_encode_ulonglong.c b/lib/ic/c_src/oe_ei_encode_ulonglong.c
deleted file mode 100644
index 7997f4ea39..0000000000
--- a/lib/ic/c_src/oe_ei_encode_ulonglong.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include <ic.h>
-
-
-int oe_ei_encode_ulonglong(CORBA_Environment *ev, CORBA_unsigned_long_long p) {
- int size = ev->_iout + __OE_ULONGLONGSZ__;
-
- if (size >= ev->_outbufsz) {
- char *buf = ev->_outbuf;
- int bufsz = ev->_outbufsz + ev->_memchunk;
-
- if ((buf = realloc(buf,bufsz)) != NULL) {
- ev->_outbuf = buf;
- ev->_outbufsz += ev->_memchunk;
- }
- else {
- CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding");
- return -1; /* OUT OF MEMORY */
- }
- }
-
- /* CORBA_long_long = long because of erl_interface limitation */
- return ei_encode_ulong(ev->_outbuf, &ev->_iout, p);
-}
-
-
diff --git a/lib/ic/c_src/oe_ei_encode_version.c b/lib/ic/c_src/oe_ei_encode_version.c
deleted file mode 100644
index 4bc6256c32..0000000000
--- a/lib/ic/c_src/oe_ei_encode_version.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1998-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include <ic.h>
-
-
-int oe_ei_encode_version(CORBA_Environment *ev) {
- int size = ev->_iout + __OE_VSNSZ__;
-
- if (size >= ev->_outbufsz) {
- char *buf = ev->_outbuf;
- int bufsz = ev->_outbufsz + ev->_memchunk;
-
- if ((buf = realloc(buf,bufsz)) != NULL) {
- ev->_outbuf = buf;
- ev->_outbufsz += ev->_memchunk;
- }
- else {
- CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding");
- return -1; /* OUT OF MEMORY */
- }
- }
-
- return ei_encode_version(ev->_outbuf, &ev->_iout);
-}
-
diff --git a/lib/ic/c_src/oe_ei_encode_wchar.c b/lib/ic/c_src/oe_ei_encode_wchar.c
deleted file mode 100644
index 0fd4027886..0000000000
--- a/lib/ic/c_src/oe_ei_encode_wchar.c
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include <ic.h>
-
-
-int oe_ei_encode_wchar(CORBA_Environment *ev, CORBA_wchar p) {
- return oe_ei_encode_ulong(ev, p);
-}
-
-
diff --git a/lib/ic/c_src/oe_ei_encode_wstring.c b/lib/ic/c_src/oe_ei_encode_wstring.c
deleted file mode 100644
index a799d475e7..0000000000
--- a/lib/ic/c_src/oe_ei_encode_wstring.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include <ic.h>
-
-
-int oe_ei_encode_wstring(CORBA_Environment *ev, CORBA_wchar *p) {
-
- int len,wchar,size,tmp,error_code;
-
- len = ic_wstrlen(p);
- size = ev->_iout + __OE_LISTHDRSZ__ +(len * __OE_WCHARSZ__);
-
- if (size >= ev->_outbufsz) {
- char *buf = ev->_outbuf;
- int bufsz = ev->_outbufsz + ev->_memchunk;
-
- while (size >= bufsz)
- bufsz += ev->_memchunk;
-
- if ((buf = realloc(buf, bufsz)) == NULL) {
- CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding");
- return -1; /* OUT OF MEMORY */
- }
-
- ev->_outbuf = buf;
- ev->_outbufsz = bufsz;
- }
-
- /* Encode the wide string */
- error_code = 0;
-
- if ((error_code = oe_ei_encode_list_header(ev, len)) < 0)
- return error_code;
-
- for(tmp = 0; tmp < len; tmp++)
- if ((error_code = oe_ei_encode_wchar(ev, p[tmp])) < 0)
- return error_code;
-
- if ((error_code = oe_ei_encode_empty_list(ev)) < 0)
- return error_code;
-
- return 0;
-}
-
-
diff --git a/lib/ic/doc/html/.gitignore b/lib/ic/doc/html/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/ic/doc/html/.gitignore
+++ /dev/null
diff --git a/lib/ic/doc/man1/.gitignore b/lib/ic/doc/man1/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/ic/doc/man1/.gitignore
+++ /dev/null
diff --git a/lib/ic/doc/man3/.gitignore b/lib/ic/doc/man3/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/ic/doc/man3/.gitignore
+++ /dev/null
diff --git a/lib/ic/doc/pdf/.gitignore b/lib/ic/doc/pdf/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/ic/doc/pdf/.gitignore
+++ /dev/null
diff --git a/lib/ic/doc/src/CORBA_Environment_alloc.xml b/lib/ic/doc/src/CORBA_Environment_alloc.xml
deleted file mode 100644
index 357d9c2e8a..0000000000
--- a/lib/ic/doc/src/CORBA_Environment_alloc.xml
+++ /dev/null
@@ -1,143 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE cref SYSTEM "cref.dtd">
-
-<cref>
- <header>
- <copyright>
- <year>1998</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>CORBA_Environment_alloc</title>
- <prepared></prepared>
- <docno></docno>
- <checked></checked>
- <date>1998-12-01</date>
- <rev>A</rev>
- </header>
- <lib>CORBA_Environment_alloc</lib>
- <libsummary>Allocation function for the CORBA_Environement struct</libsummary>
- <description>
- <p>The <em>CORBA_Environment_alloc()</em> function is the
- function used to allocate and initiate the <em>CORBA_Environment</em>
- structure.</p>
- </description>
- <funcs>
- <func>
- <name><ret>CORBA_Environment *</ret><nametext>CORBA_Environment_alloc(inbufsz, outbufsz)</nametext></name>
- <fsummary>Initialize communication</fsummary>
- <type>
- <v>int inbufsz;</v>
- <v>int outbufsz;</v>
- </type>
- <desc>
- <p>This function is used to create and initiate the <c>CORBA_Environment</c>
- structure. In particular, it is used to dynamically allocate a CORBA_Environment
- structure and set the default values for the structure's fields. </p>
- <p><em>inbufsize</em> is the wished size of input buffer.</p>
- <p><em>outbufsize</em> is the wished size of output buffer.</p>
- <p><em>CORBA_Environment</em> is the CORBA 2.0 state structure used by the
- generated stub.</p>
- <p>This function will set all needed default values and allocate buffers equal
- to the values passed, but will not allocate space for the _to_pid and _from_pid fields.</p>
- <p>To free the space allocated by CORBA_Environment_alloc/2 :</p>
- <list type="bulleted">
- <item>
- <p>First call CORBA_free for the input and output buffers.</p>
- </item>
- <item>
- <p>After freeing the buffer space, call CORBA_free for the CORBA_Environment space. </p>
- </item>
- </list>
- </desc>
- </func>
- </funcs>
-
- <section>
- <title>The CORBA_Environment structure</title>
- <p>Here is the complete definition of the CORBA_Environment structure,
- defined in file <em>ic.h</em> : </p>
- <code type="none">
-/* Environment definition */
-typedef struct {
-
- /*----- CORBA compatibility part ------------------------*/
- /* Exception tag, initially set to CORBA_NO_EXCEPTION ---*/
- CORBA_exception_type _major;
-
- /*----- External Implementation part - initiated by the user ---*/
- /* File descriptor */
- int _fd;
- /* Size of input buffer */
- int _inbufsz;
- /* Pointer to always dynamically allocated buffer for input */
- char *_inbuf;
- /* Size of output buffer */
- int _outbufsz;
- /* Pointer to always dynamically allocated buffer for output */
- char *_outbuf;
- /* Size of memory chunks in bytes, used for increasing the output
- buffer, set to >= 32, should be around >= 1024 for performance
- reasons */
- int _memchunk;
- /* Pointer for registered name */
- char _regname[256];
- /* Process identity for caller */
- erlang_pid *_to_pid;
- /* Process identity for callee */
- erlang_pid *_from_pid;
-
- /*- Internal Implementation part - used by the server/client ---*/
- /* Index for input buffer */
- int _iin;
- /* Index for output buffer */
- int _iout;
- /* Pointer for operation name */
- char _operation[256];
- /* Used to count parameters */
- int _received;
- /* Used to identify the caller */
- erlang_pid _caller;
- /* Used to identify the call */
- erlang_ref _unique;
- /* Exception id field */
- CORBA_char *_exc_id;
- /* Exception value field */
- void *_exc_value;
-
-
-} CORBA_Environment;
- </code>
- <note>
- <p>Remember to set the field values <em>_fd </em>, <em>_regname </em>, <em>*_to_pid </em> and/or
- <em>*_from_pid </em> to the appropriate application values. These are not automatically
- set by the stubs.</p>
- </note>
- <warning>
- <p>Never assign static buffers to the buffer pointers, never set the <em>_memchunk</em> field to
- a value less than <em>32</em>.</p>
- </warning>
- </section>
-
- <section>
- <title>SEE ALSO</title>
- <p>ic(3)</p>
- </section>
-
-</cref>
-
-
diff --git a/lib/ic/doc/src/Makefile b/lib/ic/doc/src/Makefile
deleted file mode 100644
index 118f42b605..0000000000
--- a/lib/ic/doc/src/Makefile
+++ /dev/null
@@ -1,227 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1998-2017. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../../vsn.mk
-VSN=$(IC_VSN)
-APPLICATION=ic
-
-# ----------------------------------------------------
-# Java specific
-# ----------------------------------------------------
-JAVADOC=javadoc
-JAVA_INCL_ROOT = $(ERL_TOP)/lib/jinterface/priv/
-JAVA_SRC_ROOT = $(ERL_TOP)/lib/ic/java_src/
-JAVA_CLASS_SUBDIR = com/ericsson/otp/ic/
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-XML_APPLICATION_FILES = ref_man.xml
-XML_REF3_FILES = ic.xml \
- ic_clib.xml \
- ic_c_protocol.xml
-
-XML_PART_FILES = part.xml
-
-XML_CHAPTER_FILES = \
- ch_introduction.xml \
- ch_basic_idl.xml \
- ch_ic_protocol.xml \
- ch_erl_plain.xml \
- ch_erl_genserv.xml \
- ch_c_mapping.xml \
- ch_c_client.xml \
- ch_c_server.xml \
- ch_c_corba_env.xml \
- ch_java.xml \
- notes.xml
-
-BOOK_FILES = book.xml
-
-XML_FILES = $(BOOK_FILES) $(XML_APPLICATION_FILES) $(XML_REF3_FILES) \
- $(XML_PART_FILES) $(XML_CHAPTER_FILES)
-
-GIF_FILES =
-
-# ----------------------------------------------------
-
-HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \
- $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html)
-
-INFO_FILE = ../../info
-EXTRA_FILES = \
- $(DEFAULT_GIF_FILES) \
- $(DEFAULT_HTML_FILES) \
- $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html) \
- $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html)
-
-MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-
-HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
-
-TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-
-JAVA_SOURCE_FILES = \
- Holder.java \
- BooleanHolder.java \
- ByteHolder.java \
- CharHolder.java \
- DoubleHolder.java \
- FloatHolder.java \
- IntHolder.java \
- LongHolder.java \
- ShortHolder.java \
- StringHolder.java \
- Environment.java \
- Any.java \
- AnyHelper.java \
- AnyHolder.java \
- TypeCode.java \
- TCKind.java \
- Pid.java \
- PidHolder.java \
- PidHelper.java \
- Ref.java \
- RefHolder.java \
- RefHelper.java \
- Port.java \
- PortHolder.java \
- PortHelper.java \
- Term.java \
- TermHolder.java \
- TermHelper.java
-
-
-JD_INDEX_HTML_FILES = \
- allclasses-frame.html \
- allclasses-noframe.html \
- deprecated-list.html \
- index-all.html \
- overview-tree.html \
- stylesheet.css \
- help-doc.html \
- index.html \
- package-list \
- serialized-form.html \
- constant-values.html
-
-JD_GIF_FILES = \
- ../html/java/resources/inherit.gif
-
-
-PACK_DIR = com/ericsson/otp/ic
-JAVA_SOURCE_DIR = ../../java_src/$(PACK_DIR)
-JAVA_OUT_DIR = ../html/java
-
-JD_PACK_HTML_FILES = \
- package-frame.html \
- package-summary.html \
- package-tree.html
-
-JAVADOC_PACK_HTML_FILES = \
- $(JAVA_SOURCE_FILES:%.java=$(JAVA_OUT_DIR)/$(PACK_DIR)/%.html) \
- $(JD_PACK_HTML_FILES:%=$(JAVA_OUT_DIR)/$(PACK_DIR)/%)
-
-JAVADOC_INDEX_HTML_FILES = $(JD_INDEX_HTML_FILES:%=$(JAVA_OUT_DIR)/%)
-
-JAVADOC_GENERATED_FILES = $(JAVADOC_PACK_HTML_FILES) $(JAVADOC_INDEX_HTML_FILES)
-
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-CLASSPATH = $(JAVA_SRC_ROOT):$(JAVA_INCL_ROOT)
-
-XML_FLAGS +=
-DVIPS_FLAGS +=
-JAVADOCFLAGS = \
- -classpath $(CLASSPATH) \
- -d ../doc/html/java \
- -windowtitle "Package com.ericsson.otp.ic version $(IC_VSN)" \
- -public \
- -footer "<CENTER><FONT SIZE=-1>Copyright &copy; 1991-2007 Ericsson AB<BR> </FONT> </CENTER>"
-
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-$(HTMLDIR)/%.gif: %.gif
- $(INSTALL_DATA) $< $@
-
-ifneq (,$(JAVA))
-docs: pdf html man $(JAVADOC_GENERATED_FILES)
-else
-docs: pdf html man
-endif
-
-$(TOP_PDF_FILE): $(XML_FILES)
-
-pdf: $(TOP_PDF_FILE)
-
-html: gifs $(HTML_REF_MAN_FILE)
-
-clean clean_docs:
- rm -rf $(HTMLDIR)/*
- rm -f $(MAN3DIR)/*
- rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
- rm -f errs core *~
-
-$(JAVADOC_GENERATED_FILES): JAVADOC-GENERATED
-
-JAVADOC-GENERATED: $(JAVA_SOURCE_FILES:%=$(JAVA_SOURCE_DIR)/%)
- @(cd ../../java_src; $(JAVADOC) $(JAVADOCFLAGS) com.ericsson.otp.ic)
- >JAVADOC-GENERATED
-
-man: $(MAN3_FILES)
-
-gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
-
-$(INDEX_TARGET): $(INDEX_SRC) ../../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
-
-debug opt:
-
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_docs_spec: docs
- $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
- $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
- $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
- $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
- ($(CP) -rf $(HTMLDIR) "$(RELSYSDIR)/doc")
- $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
- $(INSTALL_DATA) $(MAN3_FILES) "$(RELEASE_PATH)/man/man3"
-
-release_spec:
diff --git a/lib/ic/doc/src/book.xml b/lib/ic/doc/src/book.xml
deleted file mode 100644
index f6ef824f63..0000000000
--- a/lib/ic/doc/src/book.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE book SYSTEM "book.dtd">
-
-<book xmlns:xi="http://www.w3.org/2001/XInclude">
- <header titlestyle="normal">
- <copyright>
- <year>1998</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>ic</title>
- <prepared></prepared>
- <docno></docno>
- <date>1998-09-29</date>
- <rev>4.0.4</rev>
- <file>book.sgml</file>
- </header>
- <insidecover>
- </insidecover>
- <pagetext>ic</pagetext>
- <preamble>
- <contents level="2"></contents>
- </preamble>
- <parts lift="no">
- <xi:include href="part.xml"/>
- </parts>
- <applications>
- <xi:include href="ref_man.xml"/>
- </applications>
- <releasenotes>
- <xi:include href="notes.xml"/>
- </releasenotes>
- <listofterms></listofterms>
- <index></index>
-</book>
-
diff --git a/lib/ic/doc/src/c-part.xml b/lib/ic/doc/src/c-part.xml
deleted file mode 100644
index 968dd3135f..0000000000
--- a/lib/ic/doc/src/c-part.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE part SYSTEM "part.dtd">
-
-<part>
- <header>
- <copyright>
- <year>2002</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>IDL to C language Mapping</title>
- <prepared></prepared>
- <docno></docno>
- <date>2002-06-25</date>
- <rev>A</rev>
- </header>
- <description>
- <p>IDL to C</p>
- </description>
- <include file="ch_c_mapping"></include>
- <include file="ch_c_client"></include>
- <include file="ch_c_server"></include>
- <include file="ch_c_corba_env"></include>
-</part>
-
diff --git a/lib/ic/doc/src/ch_basic_idl.xml b/lib/ic/doc/src/ch_basic_idl.xml
deleted file mode 100644
index 485a0c44e5..0000000000
--- a/lib/ic/doc/src/ch_basic_idl.xml
+++ /dev/null
@@ -1,164 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2002</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>OMG IDL</title>
- <prepared></prepared>
- <docno></docno>
- <date>2002-07-15</date>
- <rev></rev>
- <file>ch_basic_idl.xml</file>
- </header>
-
- <section>
- <title>OMG IDL - Overview</title>
- <p>The purpose of OMG IDL, <em>Interface Definition Language</em>, mapping
- is to act as translator between platforms and languages. An IDL
- specification is supposed to describe data types, object types etc.</p>
- <p>Since the <c>C</c> and <c>Java</c> IC backends only supports a subset of the
- IDL types supported by the other backends, the mapping is divided into
- different parts. For more information about IDL to Erlang mapping,
- i.e., <c>CORBA</c>, plain Erlang and generic Erlang Server, see the Orber
- User's Guide. How to use the plain Erlang and generic Erlang Server is
- found in this User's Guide.</p>
-
- <section>
- <title>Reserved Compiler Names and Keywords</title>
- <p>The use of some names is strongly discouraged due to
- ambiguities. However, the use of some names is prohibited
- when using the Erlang mapping , as they are strictly reserved for IC.</p>
- <p>IC reserves all identifiers starting with <c>OE_</c> and <c>oe_</c>
- for internal use.</p>
- <p>Note also, that an identifier in IDL can contain alphabetic,
- digits and underscore characters, but the first character
- <em>must</em> be alphabetic.
- </p>
- <p>Using underscores in IDL names can lead to ambiguities
- due to the name mapping described above. It is advisable to
- avoid the use of underscores in identifiers.</p>
- <p>The OMG defines a set of reserved words, shown below, for use as keywords.
- These may <em>not</em> be used as, for example, identifiers.</p>
- <table>
- <row>
- <cell align="left" valign="middle">abstract</cell>
- <cell align="left" valign="middle">double</cell>
- <cell align="left" valign="middle">local</cell>
- <cell align="left" valign="middle">raises</cell>
- <cell align="left" valign="middle">typedef</cell>
- </row>
- <row>
- <cell align="left" valign="middle">any</cell>
- <cell align="left" valign="middle">exception</cell>
- <cell align="left" valign="middle">long</cell>
- <cell align="left" valign="middle">readonly</cell>
- <cell align="left" valign="middle">unsigned</cell>
- </row>
- <row>
- <cell align="left" valign="middle">attribute</cell>
- <cell align="left" valign="middle">enum</cell>
- <cell align="left" valign="middle">module</cell>
- <cell align="left" valign="middle">sequence</cell>
- <cell align="left" valign="middle">union</cell>
- </row>
- <row>
- <cell align="left" valign="middle">boolean</cell>
- <cell align="left" valign="middle">factory</cell>
- <cell align="left" valign="middle">native</cell>
- <cell align="left" valign="middle">short</cell>
- <cell align="left" valign="middle">ValueBase</cell>
- </row>
- <row>
- <cell align="left" valign="middle">case</cell>
- <cell align="left" valign="middle">FALSE</cell>
- <cell align="left" valign="middle">Object</cell>
- <cell align="left" valign="middle">string</cell>
- <cell align="left" valign="middle">valuetype</cell>
- </row>
- <row>
- <cell align="left" valign="middle">char</cell>
- <cell align="left" valign="middle">fixed</cell>
- <cell align="left" valign="middle">octet</cell>
- <cell align="left" valign="middle">struct</cell>
- <cell align="left" valign="middle">void</cell>
- </row>
- <row>
- <cell align="left" valign="middle">const</cell>
- <cell align="left" valign="middle">float</cell>
- <cell align="left" valign="middle">oneway</cell>
- <cell align="left" valign="middle">supports</cell>
- <cell align="left" valign="middle">wchar</cell>
- </row>
- <row>
- <cell align="left" valign="middle">context</cell>
- <cell align="left" valign="middle">in</cell>
- <cell align="left" valign="middle">out</cell>
- <cell align="left" valign="middle">switch</cell>
- <cell align="left" valign="middle">wstring</cell>
- </row>
- <row>
- <cell align="left" valign="middle">custom</cell>
- <cell align="left" valign="middle">inout</cell>
- <cell align="left" valign="middle">private</cell>
- <cell align="left" valign="middle">TRUE</cell>
- <cell align="left" valign="middle"></cell>
- </row>
- <row>
- <cell align="left" valign="middle">default</cell>
- <cell align="left" valign="middle">interface</cell>
- <cell align="left" valign="middle">public</cell>
- <cell align="left" valign="middle">truncatable</cell>
- <cell align="left" valign="middle"></cell>
- </row>
- <tcaption>OMG IDL keywords</tcaption>
- </table>
- <p>The keywords listed above must be written exactly as shown. Any usage
- of identifiers that collide with a keyword is illegal. For example,
- <em>long</em> is a valid keyword; <em>Long</em> and <em>LONG</em> are
- illegal as keywords and identifiers. But, since the OMG must be able
- to expand the IDL grammar, it is possible to use <em>Escaped Identifiers</em>. For example, it is not unlikely that <c>native</c>
- have been used in IDL-specifications as identifiers. One option is to
- change all occurrences to <c>myNative</c>. Usually, it is necessary
- to change programming language code that depends upon that IDL as well.
- Since Escaped Identifiers just disable type checking (i.e. if it is a reserved
- word or not) and leaves everything else unchanged, it is only necessary to
- update the IDL-specification. To escape an identifier, simply prefix it
- with <c>_</c>. The following IDL-code is illegal:</p>
- <code type="none">
-typedef string native;
-interface i {
- void foo(in native Arg);
- };
-};
- </code>
- <p>With Escaped Identifiers the code will look like:</p>
- <code type="none">
-typedef string _native;
-interface i {
- void foo(in _native Arg);
- };
-};
- </code>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/ic/doc/src/ch_c_client.xml b/lib/ic/doc/src/ch_c_client.xml
deleted file mode 100644
index e304c8acf4..0000000000
--- a/lib/ic/doc/src/ch_c_client.xml
+++ /dev/null
@@ -1,150 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1998</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>The C Client Back-end</title>
- <prepared></prepared>
- <docno></docno>
- <date>2004-01-14</date>
- <rev>C</rev>
- <file>ch_c_client.xml</file>
- </header>
-
- <section>
- <title>Introduction</title>
- <p>With the option <c>{be, c_client}</c> the IDL Compiler generates
- C client stubs according to the IDL to C mapping, on top of the
- Erlang distribution and gen_server protocols.</p>
- <p>The developer has to write additional code, that together with
- the generated C client stubs, form a hidden Erlang node. That
- additional code uses <c>erl_interface</c> functions for defining
- the hidden node, and for establishing connections to other
- Erlang nodes.</p>
- </section>
-
- <section>
- <title>Generated Stub Files</title>
- <p>The generated stub files are:</p>
- <list type="bulleted">
- <item>
- <p>For each IDL interface, a C source file, the name of which
- is <c><![CDATA[<Scoped Interface Name>.c]]></c>. Each operation of the
- IDL interface is mapped to a C function (with scoped name)
- in that file;</p>
- </item>
- <item>
- <p>C source files that contain functions for type conversion,
- memory allocation, and data encoding/decoding;</p>
- </item>
- <item>
- <p>C header files that contain function prototypes and type
- definitions.</p>
- </item>
- </list>
- <p>All C functions are exported (i.e. not declared static).</p>
- </section>
-
- <section>
- <title>C Interface Functions</title>
- <p>For each IDL operation a C interface function is
- generated, the prototype of which is:</p>
- <p><c><![CDATA[<Return Value> <Scoped Function Name>(<Interface Object> oe_obj, <Parameters>, CORBA_Environment *oe_env);]]></c></p>
- <p>where</p>
- <list type="bulleted">
- <item>
- <p><c><![CDATA[<Return Value>]]></c> is the value to be returned as defined
- by the IDL specification;</p>
- </item>
- <item>
- <p><c><![CDATA[<Interface Object> oe_obj]]></c> is the client interface
- object;</p>
- </item>
- <item>
- <p><c><![CDATA[<Parameters>]]></c> is a list of parameters of the
- operation, defined in the same order as defined by the IDL
- specification;</p>
- </item>
- <item>
- <p><c>CORBA_Environment *oe_env</c> is a pointer to the current
- client environment. It contains the current file descriptor,
- the current input and output buffers, etc. For details see
- <seealso marker="ch_c_corba_env#corbaenv">CORBA_Environment C Structure</seealso>.</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Generating, Compiling and Linking</title>
- <p>To generate the C client stubs type the following in an
- appropriate shell:</p>
- <p><c><![CDATA[erlc -I ICROOT/include "+{be, c_client}" File.idl]]></c>,</p>
- <p>where <c>ICROOT</c> is the root of the IC application. The
- <c>-I ICROOT/include</c> is only needed if <c>File.idl</c>
- refers to <c>erlang.idl</c>.</p>
- <p>When compiling a generated C stub file, the directories
- <c>ICROOT/include</c> and <c>EICROOT/include</c>, have to be
- specified as include directories, where <c>EIROOT</c> is the
- root directory of the Erl_interface application.</p>
- <p>When linking object files the <c>EIROOT/lib</c> and
- <c>ICROOT/priv/lib</c> directories have to be specified. </p>
- </section>
-
- <section>
- <title>An Example</title>
- <p>In this example the IDL specification file "random.idl" is used
- for generating C client stubs (the file is contained in the IC
- <c>/examples/c-client</c> directory):</p>
- <code type="none"><![CDATA[
-module rmod {
-
- interface random {
-
- double produce();
-
- oneway void init(in long seed1, in long seed2, in long seed3);
-
- };
-
-}; ]]></code>
- <p>Generate the C client stubs:</p>
-
- <code type="none"><![CDATA[
-erlc '+{be, c_client}' random.idl
-Erlang IDL compiler version X.Y.Z ]]></code>
-
- <p>Six files are generated. </p>
- <p>Compile the C client stubs:</p>
- <p>Please read the <c>ReadMe</c> file att the
- <c>examples/c-client</c> directory</p>
- <p>In the same
- directory you can find all the code for this example.</p>
- <p>In particular you will find the <c>client.c</c> file that contains
- all the additional code that must be written to obtain a complete
- client. </p>
- <p>In the <c>examples/c-client</c> directory you will also find
- source code for an Erlang server, which can be used for testing
- the C client.</p>
- </section>
-</chapter>
-
-
diff --git a/lib/ic/doc/src/ch_c_corba_env.xml b/lib/ic/doc/src/ch_c_corba_env.xml
deleted file mode 100644
index 1bd829307e..0000000000
--- a/lib/ic/doc/src/ch_c_corba_env.xml
+++ /dev/null
@@ -1,386 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1998</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>CORBA_Environment C Structure</title>
- <prepared></prepared>
- <docno></docno>
- <date>2003-12-15</date>
- <rev>PC1</rev>
- <file>ch_c_corba_env.xml</file>
- </header>
- <marker id="corbaenv"></marker>
- <p>This chapter describes the CORBA_Environment C structure.</p>
-
- <section>
- <title>C Structure</title>
- <p>Here is the complete definition of the CORBA_Environment
- C structure, defined in file "ic.h" : </p>
- <code type="none">
-/* Environment definition */
-typedef struct {
-
- /*----- CORBA compatibility part ------------------------*/
- /* Exception tag, initially set to CORBA_NO_EXCEPTION ---*/
- CORBA_exception_type _major;
-
- /*----- External Implementation part - initiated by the user ---*/
- /* File descriptor */
- int _fd;
- /* Size of input buffer */
- int _inbufsz;
- /* Pointer to always dynamically allocated buffer for input */
- char *_inbuf;
- /* Size of output buffer */
- int _outbufsz;
- /* Pointer to always dynamically allocated buffer for output */
- char *_outbuf;
- /* Size of memory chunks in bytes, used for increasing the output
- buffer, set to >= 32, should be around >= 1024 for performance
- reasons */
- int _memchunk;
- /* Pointer for registered name */
- char _regname[256];
- /* Process identity for caller */
- erlang_pid *_to_pid;
- /* Process identity for callee */
- erlang_pid *_from_pid;
-
- /*- Internal Implementation part - used by the server/client ---*/
- /* Index for input buffer */
- int _iin;
- /* Index for output buffer */
- int _iout;
- /* Pointer for operation name */
- char _operation[256];
- /* Used to count parameters */
- int _received;
- /* Used to identify the caller */
- erlang_pid _caller;
- /* Used to identify the call */
- erlang_ref _unique;
- /* Exception id field */
- CORBA_char *_exc_id;
- /* Exception value field */
- void *_exc_value;
-
-
-} CORBA_Environment;
- </code>
- <p>The structure is divided into three parts:</p>
- <list type="bulleted">
- <item>
- <p>The CORBA Compatibility part, demanded by the standard OMG
- IDL mapping v2.0.</p>
- </item>
- <item>
- <p>The external implementation part used for generated
- client/server code.</p>
- </item>
- <item>
- <p>The internal part useful for those who wish to define their
- own functions.</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>The CORBA Compatibility Part</title>
- <p>Contains only one field <c>_major</c> defined as a
- CORBA_Exception_type. The CORBA_Exception type is an integer
- which can be one of:</p>
- <list type="bulleted">
- <item>
- <p><em>CORBA_NO_EXCEPTION</em>, by default equal to 0, can be
- set by the application programmer to another value.</p>
- </item>
- <item>
- <p><em>CORBA_SYSTEM_EXCEPTION</em>, by default equal to -1, can
- be set by the application programmer to another value.</p>
- </item>
- </list>
- <p>The current definition of these values are:</p>
- <code type="none">
- #define CORBA_NO_EXCEPTION 0
- #define CORBA_SYSTEM_EXCEPTION -1
- </code>
- </section>
-
- <section>
- <title>The External Part</title>
- <p>This part contains the following fields:</p>
- <list type="bulleted">
- <item>
- <p>int <em>_fd</em> - a file descriptor returned from
- erl_connect. Used for connection setting.</p>
- </item>
- <item>
- <p>char* <em>_inbuf</em> - pointer to a buffer used for
- input. Buffer size checks are done under runtime that
- prevent buffer overflows. This is done by expanding the
- buffer to fit the input message. In order to allow buffer
- reallocation, the output buffer must always be dynamically
- allocated. The pointer value can change under runtime in
- case of buffer reallocation.</p>
- </item>
- <item>
- <p>int <em>_inbufsz</em> - start size of input buffer. Used
- for setting the input buffer size under initialization of
- the Erl_Interface function ei_receive_encoded/5. The value
- of this field can change under runtime in case of input
- buffer expansion to fit larger messages</p>
- </item>
- <item>
- <p>int <em>_outbufsz</em> - start size of output buffer. The
- value of this field can change under runtime in case of
- input buffer expansion to fit larger messages</p>
- </item>
- <item>
- <p>char* <em>_outbuf</em> - pointer to a buffer used for
- output. Buffer size checks prevent buffer overflows under
- runtime, by expanding the buffer to fit the output message
- in cases of lack of space in buffer. In order to allow
- buffer reallocation, the output buffer must always be
- dynamically allocated. The pointer value can change under
- runtime in case of buffer reallocation.</p>
- </item>
- <item>
- <p>int <em>_memchunk</em> - expansion unit size for the output
- buffer. This is the size of memory chunks in bytes used for
- increasing the output in case of buffer expansion. The value
- of this field must be always set to &gt;= 32, should be at
- least 1024 for performance reasons.</p>
- </item>
- <item>
- <p>char <em>regname[256]</em> - a registered name for a process. </p>
- </item>
- <item>
- <p>erlang_pid* <em>_to_pid</em> - an Erlang process identifier,
- is only used if the registered_name parameter is the empty
- string.</p>
- </item>
- <item>
- <p>erlang_pid* <em>_from_pid</em> - your own process id so the
- answer can be returned.</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>The Internal Part</title>
- <p>This part contains the following fields:</p>
- <list type="bulleted">
- <item>
- <p>int <em>_iin</em> - Index for input buffer. Initially set
- to zero. Updated to agree with the length of the received
- encoded message.</p>
- </item>
- <item>
- <p>int <em>_iout</em> - Index for output buffer Initially set
- to zero. Updated to agree with the length of the message
- encoded to the communication counterpart.</p>
- </item>
- <item>
- <p>char <em>_operation[256]</em> - Pointer for operation name.
- Set to the operation to be called.</p>
- </item>
- <item>
- <p>int <em>_received</em> - Used to count parameters.
- Initially set to zero.</p>
- </item>
- <item>
- <p>erlang_pid <em>_caller</em> - Used to identify the caller.
- Initiated to a value that identifies the caller.</p>
- </item>
- <item>
- <p>erlang_ref <em>_unique</em> - Used to identify the call.
- Set to a default value in the case of generated functions.</p>
- </item>
- <item>
- <p>CORBA_char* <em>_exc_id</em> - Exception id field.
- Initially set to NULL to agree with the initial value of
- _major (CORBA_NO_EXCEPTION).</p>
- </item>
- <item>
- <p>void* <em>_exc_value</em> - Exception value field Initially
- set to <em>NULL</em> to agree with the initial value of
- _major (CORBA_NO_EXCEPTION).</p>
- </item>
- </list>
- <p>The advanced user who defines his own functions has to
- update/support these values in a way similar to how they are
- updated in the generated code.</p>
- </section>
-
- <section>
- <title>Creating and Initiating the CORBA_Environment Structure</title>
- <p>There are two ways to set the CORBA_Environment structure:</p>
- <list type="bulleted">
- <item>
- <p>Manually</p>
- <p>The following default values must be set to the
- CORBA_Environment *<em>ev</em> fields, when buffers for
- input/output should have the size <em>inbufsz</em>/
- <em>outbufsz</em>:</p>
- <list type="bulleted">
- <item>
- <p><em>ev->_inbufsz</em> = <em>inbufsz</em>;</p>
- <p>The value for this field can be between 0 and maximum
- size of a signed integer.</p>
- </item>
- <item>
- <p><em>ev->_inbuf</em> = malloc(<em>inbufsz</em>);</p>
- <p>The size of the allocated buffer must be equal to the
- value of its corresponding index, _inbufsz.</p>
- </item>
- <item>
- <p><em>ev->_outbufsz</em> = <em>outbufsz</em>;</p>
- <p>The value for this field can be between 0 and maximum
- size of a signed integer.</p>
- </item>
- <item>
- <p><em>ev->_outbuf</em> = malloc(<em>outbufsz</em>);</p>
- <p>The size of the allocated buffer must be equal to the
- value of its corresponding index, _outbufsz.</p>
- </item>
- <item>
- <p><em>ev->_memchunk</em> = <em>__OE_MEMCHUNK__</em>;</p>
- <p>Please note that __OE_MEMCHUNK__ is equal to
- <em>1024</em>, you can set this value to a value bigger
- than 32 yourself.</p>
- </item>
- <item>
- <p><em>ev->_to_pid</em> = <em>NULL</em>;</p>
- </item>
- <item>
- <p><em>ev->_from_pid</em> = <em>NULL</em>;</p>
- </item>
- </list>
- <p></p>
- </item>
- <item>
- <p>By using the <em>CORBA_Environment_alloc</em>/2 function. </p>
- <p>The CORBA_Environment_alloc function is defined as:</p>
- <code type="none">
- CORBA_Environment *CORBA_Environment_alloc(int inbufsz,
- int outbufsz);
- </code>
- <p>where:</p>
- <list type="bulleted">
- <item>
- <p><em>inbufsz</em> is the desired size of input buffer</p>
- </item>
- <item>
- <p><em>outbufsz</em> is the desired size of output
- buffer</p>
- </item>
- <item>
- <p>return value is a <em>pointer</em> to an allocated and
- initialized <em>CORBA_Environment</em> structure.</p>
- <p></p>
- </item>
- </list>
- <p>This function will set all needed default values and
- allocate buffers equal to the values passed, but will not
- allocate space for the _to_pid and _from_pid fields.</p>
- <p>To free the space allocated by CORBA_Environment_alloc/2:</p>
- <list type="bulleted">
- <item>
- <p>First call CORBA_free for the input and output buffers.</p>
- </item>
- <item>
- <p>After freeing the buffer space, call CORBA_free for
- the CORBA_Environment space.</p>
- </item>
- </list>
- </item>
- </list>
- <note>
- <p>Remember to set the fields <em>_fd</em>, <em>_regname</em>,
- <em>*_to_pid</em> and/or <em>*_from_pid</em> to the
- appropriate application values. These are not automatically
- set by the stubs.</p>
- </note>
- <warning>
- <p>Never assign static buffers to the buffer pointers. Never set
- the <em>_memchunk</em> field to a value less than
- <em>32</em>.</p>
- </warning>
- </section>
-
- <section>
- <title>Setting System Exceptions</title>
- <p>If the user wishes to set own system exceptions at critical
- positions on the code, it is strongly recommended to use one of
- the current values:</p>
- <list type="bulleted">
- <item>
- <p>CORBA_NO_EXCEPTION upon success. The value of the _exc_id
- field should be then set to NULL. The value of the
- _exc_value field should be then set to NULL.</p>
- </item>
- <item>
- <p>CORBA_SYSTEM_EXCEPTION upon system failure. The value of
- the _exc_id field should be then set to one of the values
- defined in "ic.h" :</p>
- <code type="none">
- #define UNKNOWN "UNKNOWN"
- #define BAD_PARAM "BAD_PARAM"
- #define NO_MEMORY "NO_MEMORY"
- #define IMPL_LIMIT "IMP_LIMIT"
- #define COMM_FAILURE "COMM_FAILURE"
- #define INV_OBJREF "INV_OBJREF"
- #define NO_PERMISSION "NO_PERMISSION"
- #define INTERNAL "INTERNAL"
- #define MARSHAL "MARSHAL"
- #define INITIALIZE "INITIALIZE"
- #define NO_IMPLEMENT "NO_IMPLEMENT"
- #define BAD_TYPECODE "BAD_TYPECODE"
- #define BAD_OPERATION "BAD_OPERATION"
- #define NO_RESOURCES "NO_RESOURCES"
- #define NO_RESPONSE "NO_RESPONSE"
- #define PERSIST_STORE "PERSIST_STORE"
- #define BAD_INV_ORDER "BAD_INV_ORDER"
- #define TRANSIENT "TRANSIENT"
- #define FREE_MEM "FREE_MEM"
- #define INV_IDENT "INV_IDENT"
- #define INV_FLAG "INV_FLAG"
- #define INTF_REPOS "INTF_REPOS"
- #define BAD_CONTEXT "BAD_CONTEXT"
- #define OBJ_ADAPTER "OBJ_ADAPTER"
- #define DATA_CONVERSION "DATA_CONVERSION"
- #define OBJ_NOT_EXIST "OBJECT_NOT_EXIST"
- </code>
- </item>
- </list>
- <p>The value of the _exc_value field should be then set to a string
- that explains the problem in an informative way. The user
- should use the functions CORBA_exc_set/4 and
- CORBA_exception_free/1 to free the exception.
- The user has to use CORBA_exception_id/1 and
- CORBA_exception_value/1 to access exception information.
- Prototypes for these functions are declared in "ic.h"</p>
- </section>
-</chapter>
-
-
diff --git a/lib/ic/doc/src/ch_c_mapping.xml b/lib/ic/doc/src/ch_c_mapping.xml
deleted file mode 100644
index 1ea0ace91f..0000000000
--- a/lib/ic/doc/src/ch_c_mapping.xml
+++ /dev/null
@@ -1,893 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1998</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>IDL to C mapping</title>
- <prepared></prepared>
- <docno></docno>
- <date>2002-08-06</date>
- <rev>PB1</rev>
- <file>ch_c_mapping.xml</file>
- </header>
-
- <section>
- <title>Introduction</title>
- <p>The IC C mapping (used by the C client and C server back-ends) follows
- the <em>OMG C Language Mapping Specification</em>. </p>
- <p>The C mapping supports the following:</p>
- <list type="bulleted">
- <item>
- <p>All OMG IDL basic types except <c>long double</c> and <c>any</c>.</p>
- </item>
- <item>
- <p>All OMG IDL constructed types.</p>
- </item>
- <item>
- <p>OMG IDL constants.</p>
- </item>
- <item>
- <p>Operations with passing of parameters and receiving of
- results. <c>inout</c> parameters are not supported.</p>
- </item>
- </list>
- <p>The following is not supported:
- </p>
- <list type="bulleted">
- <item>
- <p>Access to attributes.</p>
- </item>
- <item>
- <p>User defined exceptions.</p>
- <p></p>
- </item>
- <item>
- <p>User defined objects.</p>
- <p></p>
- </item>
- </list>
- </section>
-
- <section>
- <title>C Mapping Characteristics</title>
-
- <section>
- <title>Reserved Names</title>
- <p>The IDL compiler reserves all identifiers starting with
- <c>OE_</c> and <c>oe_</c> for internal use.</p>
- </section>
-
- <section>
- <title>Scoped Names</title>
- <p>The C programmer must always use the global name for a type,
- constant or operation. The C global name corresponding to an
- OMG IDL global name is derived by converting occurrences of
- "::" to underscore, and eliminating the leading "::". So, for
- example, an operation <c>op1</c> defined in interface
- <c>I1</c> which is defined in module <c>M1</c> would be
- written as <c>M1::I1::op1</c> in IDL and as <c>M1_I1_op1</c>
- in C.</p>
- <warning>
- <p>If underscores are used in IDL names it can lead to
- ambiguities due to the name mapping described above,
- therefore it is advisable to avoid underscores in
- identifiers.</p>
- </warning>
- </section>
-
- <section>
- <title>Generated Files</title>
- <p>Two files will be generated for each scope. One set of files
- will be generated for each module and each interface scope.
- An extra set is generated for those definitions at top
- level scope. One of the files is a header file(<c>.h</c>), and the
- other file is a C source code file (<c>.c</c>). In addition to these
- files a number of C source files will be generated for type encodings,
- they are named according to the following template:
- <c><![CDATA[oe_code_<type>.c]]></c>.</p>
- <p>For example:</p>
- <code type="none"><![CDATA[
-// IDL, in the file "spec.idl"
-module m1 {
-
- typedef sequence<long> lseq;
-
- interface i1 {
- ...
- };
- ...
-};
- ]]></code>
- <p>XXX This is C client specific.
- Will produce the files <c>oe_spec.h</c> and
- <c>oe_spec.c</c> for the top scope level. Then the files
- <c>m1.h</c> and <c>m1.c</c> for the module <c>m1</c> and
- files <c>m1_i1.h</c> and <c>m1_i1.c</c> for the interface
- <c>i1</c>. The typedef will produce <c>oe_code_m1_lseq.c</c>.</p>
- <p>The header file contains type definitions for all
- <c>struct</c> types and sequences and constants in the IDL file. The
- c file contains all operation stubs if the the scope is an interface.</p>
- <p>In addition to the scope-related files a C source file will
- be generated for encoding operations of all <c>struct</c> and
- sequence types.</p>
- </section>
- </section>
-
- <section>
- <title>Basic OMG IDL Types</title>
- <p>The mapping of basic types is as follows.</p>
- <table>
- <row>
- <cell align="left" valign="middle"><em>OMG IDL type</em></cell>
- <cell align="left" valign="middle"><em>C type</em></cell>
- <cell align="left" valign="middle"><em>Mapped to C type</em></cell>
- </row>
- <row>
- <cell align="left" valign="middle">float</cell>
- <cell align="left" valign="middle">CORBA_float</cell>
- <cell align="left" valign="middle">float</cell>
- </row>
- <row>
- <cell align="left" valign="middle">double</cell>
- <cell align="left" valign="middle">CORBA_double</cell>
- <cell align="left" valign="middle">double</cell>
- </row>
- <row>
- <cell align="left" valign="middle">short</cell>
- <cell align="left" valign="middle">CORBA_short</cell>
- <cell align="left" valign="middle">short</cell>
- </row>
- <row>
- <cell align="left" valign="middle">unsigned short</cell>
- <cell align="left" valign="middle">CORBA_unsigned_short</cell>
- <cell align="left" valign="middle">unsigned short</cell>
- </row>
- <row>
- <cell align="left" valign="middle">long</cell>
- <cell align="left" valign="middle">CORBA_long</cell>
- <cell align="left" valign="middle">long</cell>
- </row>
- <row>
- <cell align="left" valign="middle">long long</cell>
- <cell align="left" valign="middle">CORBA_long_long</cell>
- <cell align="left" valign="middle">long</cell>
- </row>
- <row>
- <cell align="left" valign="middle">unsigned long</cell>
- <cell align="left" valign="middle">CORBA_unsigned_long</cell>
- <cell align="left" valign="middle">unsigned long</cell>
- </row>
- <row>
- <cell align="left" valign="middle">unsigned long long</cell>
- <cell align="left" valign="middle">CORBA_unsigned_long_long</cell>
- <cell align="left" valign="middle">unsigned long</cell>
- </row>
- <row>
- <cell align="left" valign="middle">char</cell>
- <cell align="left" valign="middle">CORBA_char</cell>
- <cell align="left" valign="middle">char</cell>
- </row>
- <row>
- <cell align="left" valign="middle">wchar</cell>
- <cell align="left" valign="middle">CORBA_wchar</cell>
- <cell align="left" valign="middle">unsigned long</cell>
- </row>
- <row>
- <cell align="left" valign="middle">boolean</cell>
- <cell align="left" valign="middle">CORBA_boolean</cell>
- <cell align="left" valign="middle">unsigned char</cell>
- </row>
- <row>
- <cell align="left" valign="middle">octet</cell>
- <cell align="left" valign="middle">CORBA_octet</cell>
- <cell align="left" valign="middle">char</cell>
- </row>
- <row>
- <cell align="left" valign="middle">any</cell>
- <cell align="left" valign="middle">Not supported</cell>
- <cell align="left" valign="middle"></cell>
- </row>
- <row>
- <cell align="left" valign="middle">long double</cell>
- <cell align="left" valign="middle">Not supported</cell>
- <cell align="left" valign="middle"></cell>
- </row>
- <row>
- <cell align="left" valign="middle">Object</cell>
- <cell align="left" valign="middle">Not supported</cell>
- <cell align="left" valign="middle"></cell>
- </row>
- <row>
- <cell align="left" valign="middle">void</cell>
- <cell align="left" valign="middle">void</cell>
- <cell align="left" valign="middle">void</cell>
- </row>
- <tcaption>OMG IDL Basic Types</tcaption>
- </table>
- <p>XXX Note that several mappings are not according to OMG C Language
- mapping.</p>
- </section>
-
- <section>
- <title>Constructed OMG IDL Types</title>
- <p>Constructed types have mappings as shown in the following table.</p>
- <table>
- <row>
- <cell align="left" valign="middle">OMG IDL type</cell>
- <cell align="left" valign="middle">Mapped to C type</cell>
- </row>
- <row>
- <cell align="left" valign="middle">string</cell>
- <cell align="left" valign="middle">CORBA_char*</cell>
- </row>
- <row>
- <cell align="left" valign="middle">wstring</cell>
- <cell align="left" valign="middle">CORBA_wchar*</cell>
- </row>
- <row>
- <cell align="left" valign="middle">struct</cell>
- <cell align="left" valign="middle">struct</cell>
- </row>
- <row>
- <cell align="left" valign="middle">union</cell>
- <cell align="left" valign="middle">union</cell>
- </row>
- <row>
- <cell align="left" valign="middle">enum</cell>
- <cell align="left" valign="middle">enum</cell>
- </row>
- <row>
- <cell align="left" valign="middle">sequence</cell>
- <cell align="left" valign="middle">struct (see below)</cell>
- </row>
- <row>
- <cell align="left" valign="middle">array</cell>
- <cell align="left" valign="middle">array</cell>
- </row>
- <tcaption>OMG IDL Constructed Types</tcaption>
- </table>
- <p>An OMG IDL sequence (an array of variable length), </p>
- <code type="none"><![CDATA[
-// IDL
-typedef sequence <IDL_TYPE> NAME;
- ]]></code>
- <p>is mapped to a C struct as follows:</p>
- <code type="none">
-/* C */
-typedef struct {
- CORBA_unsigned_long _maximum;
- CORBA_unsigned_long _length;
- C_TYPE* _buffer;
-} C_NAME;
- </code>
- <p>where <c>C_TYPE</c> is the mapping of <c>IDL_TYPE</c>, and where
- <c>C_NAME</c> is the scoped name of <c>NAME</c>.</p>
- </section>
-
- <section>
- <title>OMG IDL Constants</title>
- <p>An IDL constant is mapped to a C constant through a C
- <c>#define</c> macro, where the name of the macro is scoped.
- Example:</p>
- <code type="none">
-// IDL
-module M1 {
- const long c1 = 99;
-};
- </code>
- <p>results in the following:</p>
- <code type="none">
-/* C */
-#define M1_c1 99
- </code>
- </section>
-
- <section>
- <title>OMG IDL Operations</title>
- <p>An OMG IDL operation is mapped to C function. Each C operation
- function has two mandatory parameters: a first parameter of
- <em>interface object</em> type, and a last parameter of
- <em>environment</em> type.</p>
- <p></p>
- <p>In a C operation function the the <c>in</c> and <c>out</c>
- parameters are located between the first and last parameters
- described above, and they appear in the same order as in the IDL
- operation declaration.</p>
- <p>Notice that <c>inout</c> parameters are not supported. </p>
- <p></p>
- <p>The return value of an OMG IDL operation is mapped to a
- corresponding return value of the C operation function.</p>
- <p>Mandatory C operation function parameters:</p>
- <list type="bulleted">
- <item><c>CORBA_Object oe_obj</c> - the first parameter of a C
- operation function. This parameter is required by the <em>OMG C Language Mapping Specification</em>, but in the current
- implementation there is no particular use for it.</item>
- <item>
- <p><c>CORBA_Environment* oe_env</c> - the last parameter of a C
- operation function. The parameter is defined in the C header
- file <c>ic.h</c> and has the following public fields:</p>
- <list type="bulleted">
- <item>
- <p><c>CORBA_Exception_type _major</c> - indicates if an
- operation invocation was successful which will be one of
- the following:</p>
- <list type="bulleted">
- <item>CORBA_NO_EXCEPTION</item>
- <item>CORBA_SYSTEM_EXCEPTION</item>
- </list>
- </item>
- <item>int <em>_fd</em> - a file descriptor returned from
- <em>erl_connect</em> function.</item>
- <item>int <em>_inbufsz</em> - size of input buffer.</item>
- <item>char* <em>_inbuf</em> - pointer to a buffer used for
- input.</item>
- <item>int <em>_outbufsz</em> - size of output buffer.</item>
- <item>char* <em>_outbuf</em> - pointer to a buffer used for
- output.</item>
- <item>
- <p>int <em>_memchunk</em> - expansion unit size for the
- output buffer. This is the size of memory chunks in
- bytes used for increasing the output in case of buffer
- expansion. The value of this field must be always set
- to &gt;= 32, should be at least 1024 for performance
- reasons.</p>
- </item>
- <item>char <em>regname[256]</em> - a registered name for a
- process.</item>
- <item>erlang_pid* <em>_to_pid</em> - an Erlang process
- identifier, is only used if the registered_name parameter
- is the empty string.</item>
- <item>erlang_pid* <em>_from_pid</em> - your own process id so
- the answer can be returned</item>
- </list>
- <p>Beside the public fields, other private fields
- are internally used but are not mentioned here. </p>
- </item>
- </list>
- <p>Example:</p>
- <code type="none">
-// IDL
-interface i1 {
- long op1(in long a);
- long op2(in string s, out long count);
-};
- </code>
- <p>Is mapped to the following C functions</p>
- <code type="none">
-/* C */
-CORBA_long i1_op1(i1 oe_obj, CORBA_long a, CORBA_Environment* oe_env)
-{
- ...
-}
-CORBA_long i1_op2(i1 oe_obj, CORBA_char* s, CORBA_long *count,
-CORBA_Environment* oe_env)
-{
- ...
-}
- </code>
- <marker id="op_impl"></marker>
-
- <section>
- <title>Operation Implementation</title>
- <p>There is no standard CORBA mapping for the C-server side,
- as it is implementation-dependent but built in a similar way.
- The current server side mapping is different from the client
- side mapping in several ways:</p>
- <list type="bulleted">
- <item>Argument mappings</item>
- <item>Result values</item>
- <item>Structure</item>
- <item>Usage</item>
- <item>Exception handling</item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Exceptions</title>
- <p>Although exception mapping is not implemented, the stubs will
- generate CORBA system exceptions in case of operation failure.
- Thus, the only exceptions propagated by the system are built in
- system exceptions.</p>
- </section>
-
- <section>
- <title>Access to Attributes</title>
- <p>Not Supported</p>
- </section>
-
- <section>
- <title>Summary of Argument/Result Passing for the C-client</title>
- <p>The user-defined parameters can only be <c>in</c> or <c>out</c>
- parameters, as
- <c>inout</c> parameters are not supported.</p>
- <p>This table summarize the types a client passes as arguments to
- a stub, and receives as a result.</p>
- <table>
- <row>
- <cell align="left" valign="middle">OMG IDL type</cell>
- <cell align="left" valign="middle">In</cell>
- <cell align="left" valign="middle">Out</cell>
- <cell align="left" valign="middle">Return</cell>
- </row>
- <row>
- <cell align="left" valign="middle">short</cell>
- <cell align="left" valign="middle">CORBA_short</cell>
- <cell align="left" valign="middle">CORBA_short*</cell>
- <cell align="left" valign="middle">CORBA_short</cell>
- </row>
- <row>
- <cell align="left" valign="middle">long</cell>
- <cell align="left" valign="middle">CORBA_long</cell>
- <cell align="left" valign="middle">CORBA_long*</cell>
- <cell align="left" valign="middle">CORBA_long</cell>
- </row>
- <row>
- <cell align="left" valign="middle">long long</cell>
- <cell align="left" valign="middle">CORBA_long_long</cell>
- <cell align="left" valign="middle">CORBA_long_long*</cell>
- <cell align="left" valign="middle">CORBA_long_long</cell>
- </row>
- <row>
- <cell align="left" valign="middle">unsigned short</cell>
- <cell align="left" valign="middle">CORBA_unsigned_short</cell>
- <cell align="left" valign="middle">CORBA_unsigned_short*</cell>
- <cell align="left" valign="middle">CORBA_unsigned_short</cell>
- </row>
- <row>
- <cell align="left" valign="middle">unsigned long</cell>
- <cell align="left" valign="middle">CORBA_unsigned_long</cell>
- <cell align="left" valign="middle">CORBA_unsigned_long*</cell>
- <cell align="left" valign="middle">CORBA_unsigned_long</cell>
- </row>
- <row>
- <cell align="left" valign="middle">unsigned long long</cell>
- <cell align="left" valign="middle">CORBA_unsigned_long_long</cell>
- <cell align="left" valign="middle">CORBA_unsigned_long_long*</cell>
- <cell align="left" valign="middle">CORBA_unsigned_long_long</cell>
- </row>
- <row>
- <cell align="left" valign="middle">float</cell>
- <cell align="left" valign="middle">CORBA_float</cell>
- <cell align="left" valign="middle">CORBA_float*</cell>
- <cell align="left" valign="middle">CORBA_float</cell>
- </row>
- <row>
- <cell align="left" valign="middle">double</cell>
- <cell align="left" valign="middle">CORBA_double</cell>
- <cell align="left" valign="middle">CORBA_double*</cell>
- <cell align="left" valign="middle">CORBA_double</cell>
- </row>
- <row>
- <cell align="left" valign="middle">boolean</cell>
- <cell align="left" valign="middle">CORBA_boolean</cell>
- <cell align="left" valign="middle">CORBA_boolean*</cell>
- <cell align="left" valign="middle">CORBA_boolean</cell>
- </row>
- <row>
- <cell align="left" valign="middle">char</cell>
- <cell align="left" valign="middle">CORBA_char</cell>
- <cell align="left" valign="middle">CORBA_char*</cell>
- <cell align="left" valign="middle">CORBA_char</cell>
- </row>
- <row>
- <cell align="left" valign="middle">wchar</cell>
- <cell align="left" valign="middle">CORBA_wchar</cell>
- <cell align="left" valign="middle">CORBA_wchar*</cell>
- <cell align="left" valign="middle">CORBA_wchar</cell>
- </row>
- <row>
- <cell align="left" valign="middle">octet</cell>
- <cell align="left" valign="middle">CORBA_octet</cell>
- <cell align="left" valign="middle">CORBA_octet*</cell>
- <cell align="left" valign="middle">CORBA_octet</cell>
- </row>
- <row>
- <cell align="left" valign="middle">enum</cell>
- <cell align="left" valign="middle">CORBA_enum</cell>
- <cell align="left" valign="middle">CORBA_enum*</cell>
- <cell align="left" valign="middle">CORBA_enum</cell>
- </row>
- <row>
- <cell align="left" valign="middle">struct, fixed</cell>
- <cell align="left" valign="middle">struct*</cell>
- <cell align="left" valign="middle">struct*</cell>
- <cell align="left" valign="middle">struct</cell>
- </row>
- <row>
- <cell align="left" valign="middle">struct, variable</cell>
- <cell align="left" valign="middle">struct*</cell>
- <cell align="left" valign="middle">struct**</cell>
- <cell align="left" valign="middle">struct*</cell>
- </row>
- <row>
- <cell align="left" valign="middle">union, fixed</cell>
- <cell align="left" valign="middle">union*</cell>
- <cell align="left" valign="middle">union*</cell>
- <cell align="left" valign="middle">union</cell>
- </row>
- <row>
- <cell align="left" valign="middle">union, variable</cell>
- <cell align="left" valign="middle">union*</cell>
- <cell align="left" valign="middle">union**</cell>
- <cell align="left" valign="middle">union*</cell>
- </row>
- <row>
- <cell align="left" valign="middle">string</cell>
- <cell align="left" valign="middle">CORBA_char*</cell>
- <cell align="left" valign="middle">CORBA_char**</cell>
- <cell align="left" valign="middle">CORBA_char*</cell>
- </row>
- <row>
- <cell align="left" valign="middle">wstring</cell>
- <cell align="left" valign="middle">CORBA_wchar*</cell>
- <cell align="left" valign="middle">CORBA_wchar**</cell>
- <cell align="left" valign="middle">CORBA_wchar*</cell>
- </row>
- <row>
- <cell align="left" valign="middle">sequence</cell>
- <cell align="left" valign="middle">sequence*</cell>
- <cell align="left" valign="middle">sequence**</cell>
- <cell align="left" valign="middle">sequence*</cell>
- </row>
- <row>
- <cell align="left" valign="middle">array, fixed</cell>
- <cell align="left" valign="middle">array</cell>
- <cell align="left" valign="middle">array</cell>
- <cell align="left" valign="middle">array_slice*</cell>
- </row>
- <row>
- <cell align="left" valign="middle">array, variable</cell>
- <cell align="left" valign="middle">array</cell>
- <cell align="left" valign="middle">array_slice**</cell>
- <cell align="left" valign="middle">array_slice*</cell>
- </row>
- <tcaption>Basic Argument and Result passing</tcaption>
- </table>
- <p>A client is responsible for providing storage of all arguments passed
- as <em>in</em> arguments.</p>
- <table>
- <row>
- <cell align="left" valign="middle">OMG IDL type</cell>
- <cell align="left" valign="middle">Out</cell>
- <cell align="left" valign="middle">Return</cell>
- </row>
- <row>
- <cell align="left" valign="middle">short</cell>
- <cell align="left" valign="middle">1</cell>
- <cell align="left" valign="middle">1</cell>
- </row>
- <row>
- <cell align="left" valign="middle">long</cell>
- <cell align="left" valign="middle">1</cell>
- <cell align="left" valign="middle">1</cell>
- </row>
- <row>
- <cell align="left" valign="middle">long long</cell>
- <cell align="left" valign="middle">1</cell>
- <cell align="left" valign="middle">1</cell>
- </row>
- <row>
- <cell align="left" valign="middle">unsigned short</cell>
- <cell align="left" valign="middle">1</cell>
- <cell align="left" valign="middle">1</cell>
- </row>
- <row>
- <cell align="left" valign="middle">unsigned long</cell>
- <cell align="left" valign="middle">1</cell>
- <cell align="left" valign="middle">1</cell>
- </row>
- <row>
- <cell align="left" valign="middle">unsigned long long</cell>
- <cell align="left" valign="middle">1</cell>
- <cell align="left" valign="middle">1</cell>
- </row>
- <row>
- <cell align="left" valign="middle">float</cell>
- <cell align="left" valign="middle">1</cell>
- <cell align="left" valign="middle">1</cell>
- </row>
- <row>
- <cell align="left" valign="middle">double</cell>
- <cell align="left" valign="middle">1</cell>
- <cell align="left" valign="middle">1</cell>
- </row>
- <row>
- <cell align="left" valign="middle">boolean</cell>
- <cell align="left" valign="middle">1</cell>
- <cell align="left" valign="middle">1</cell>
- </row>
- <row>
- <cell align="left" valign="middle">char</cell>
- <cell align="left" valign="middle">1</cell>
- <cell align="left" valign="middle">1</cell>
- </row>
- <row>
- <cell align="left" valign="middle">wchar</cell>
- <cell align="left" valign="middle">1</cell>
- <cell align="left" valign="middle">1</cell>
- </row>
- <row>
- <cell align="left" valign="middle">octet</cell>
- <cell align="left" valign="middle">1</cell>
- <cell align="left" valign="middle">1</cell>
- </row>
- <row>
- <cell align="left" valign="middle">enum</cell>
- <cell align="left" valign="middle">1</cell>
- <cell align="left" valign="middle">1</cell>
- </row>
- <row>
- <cell align="left" valign="middle">struct, fixed</cell>
- <cell align="left" valign="middle">1</cell>
- <cell align="left" valign="middle">1</cell>
- </row>
- <row>
- <cell align="left" valign="middle">struct, variable</cell>
- <cell align="left" valign="middle">2</cell>
- <cell align="left" valign="middle">2</cell>
- </row>
- <row>
- <cell align="left" valign="middle">string</cell>
- <cell align="left" valign="middle">2</cell>
- <cell align="left" valign="middle">2</cell>
- </row>
- <row>
- <cell align="left" valign="middle">wstring</cell>
- <cell align="left" valign="middle">2</cell>
- <cell align="left" valign="middle">2</cell>
- </row>
- <row>
- <cell align="left" valign="middle">sequence</cell>
- <cell align="left" valign="middle">2</cell>
- <cell align="left" valign="middle">2</cell>
- </row>
- <row>
- <cell align="left" valign="middle">array, fixed</cell>
- <cell align="left" valign="middle">1</cell>
- <cell align="left" valign="middle">3</cell>
- </row>
- <row>
- <cell align="left" valign="middle">array, variable</cell>
- <cell align="left" valign="middle">3</cell>
- <cell align="left" valign="middle">3</cell>
- </row>
- <tcaption>Client argument storage responsibility</tcaption>
- </table>
- <table>
- <row>
- <cell align="left" valign="middle">Case</cell>
- <cell align="left" valign="middle">Description</cell>
- </row>
- <row>
- <cell align="left" valign="middle">1</cell>
- <cell align="left" valign="middle">Caller allocates all necessary storage, except that which may be encapsulated and managed within the parameter itself.</cell>
- </row>
- <row>
- <cell align="left" valign="middle">2</cell>
- <cell align="left" valign="middle">The caller allocates a pointer and passes it by reference to the callee. The callee sets the pointer to point to a valid instance of the parameter's type. The caller is responsible for releasing the returned storage. Following completion of a request, the caller is not allowed to modify any values in the returned storage. To do so the caller must first copy the returned instance into a new instance, then modify the new instance. </cell>
- </row>
- <row>
- <cell align="left" valign="middle">3</cell>
- <cell align="left" valign="middle">The caller allocates a pointer to an array slice which has all the same dimensions of the original array except the first, and passes it by reference to the callee. The callee sets the pointer to point to a valid instance of the array. The caller is responsible for releasing the returned storage. Following completion of a request, the caller is not allowed to modify any values in the returned storage. To do so the caller must first copy the returned instance into a new instance, then modify the new instance. </cell>
- </row>
- <tcaption>Argument passing cases</tcaption>
- </table>
- <p>The returned storage in case 2 and 3 is allocated as one block of memory
- so it is possible to deallocate it with one call of CORBA_free.</p>
- </section>
-
- <section>
- <title>Supported Memory Allocation Functions</title>
- <list type="bulleted">
- <item>
- <p><em>CORBA_Environment</em> can be allocated from the user by calling
- <em>CORBA_Environment_alloc()</em>.</p>
- <p>The interface for this function is </p>
- <p><c>CORBA_Environment *CORBA_Environment_alloc(int inbufsz, int outbufsz);</c></p>
- <p>where :</p>
- <list type="bulleted">
- <item>
- <p><em>inbufsz</em> is the desired size of input buffer</p>
- </item>
- <item>
- <p><em>outbufsz</em> is the desired size of output buffer</p>
- </item>
- <item>
- <p>return value is a <em>pointer</em> to an allocated and initialized
- <em>CORBA_Environment</em> structure</p>
- <p></p>
- </item>
- </list>
- </item>
- <item>
- <p>Strings can be allocated from the user by calling <em>CORBA_string_alloc()</em>.</p>
- <p>The interface for this function is </p>
- <p><c>CORBA_char *CORBA_string_alloc(CORBA_unsigned_long len);</c></p>
- <p>where :</p>
- <list type="bulleted">
- <item>
- <p><em>len</em> is the length of the string to be allocated.</p>
- </item>
- </list>
- </item>
- </list>
- <p>Thus far, no other type allocation function is supported.</p>
- </section>
-
- <section>
- <title>Special Memory Deallocation Functions</title>
- <list type="bulleted">
- <item>
- <p><c>void CORBA_free(void *storage)</c></p>
- <p>This function will free storage allocated by the stub.</p>
- </item>
- <item>
- <p><c>void CORBA_exception_free(CORBA_environment *ev)</c></p>
- <p>This function will free storage allocated under exception propagation. </p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Exception Access Functions</title>
- <list type="bulleted">
- <item>
- <p><c>CORBA_char *CORBA_exception_id(CORBA_Environment *ev)</c></p>
- <p>This function will return raised exception identity.</p>
- </item>
- <item>
- <p><c>void *CORBA_exception_value(CORBA_Environment *ev)</c></p>
- <p>This function will return the value of a raised exception. </p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Special Types</title>
- <list type="bulleted">
- <item>
- <p>The erlang binary type has some special features.</p>
- <p></p>
- <p>While the <c>erlang::binary</c> idl type has the same C-definition as
- a generated sequence of octets :</p>
- <code type="none"><![CDATA[
- module erlang
- {
-
- ....
-
- // an erlang binary
- typedef sequence<octet> binary;
-
- };
- ]]></code>
- <p>it provides a way on sending trasparent data between C and Erlang.</p>
- <p>The C-definition (ic.h) for an erlang binary is :</p>
- <code type="none">
- typedef struct {
- CORBA_unsigned_long _maximum;
- CORBA_unsigned_long _length;
- CORBA_octet* _buffer;
- } erlang_binary; /* ERLANG BINARY */
- </code>
- <p>The differences (between <c>erlang::binary</c> and <c><![CDATA[sequence< octet >]]></c>) are :</p>
- <list type="bulleted">
- <item>
- <p>on the erlang side the user is sending/receiving typical
- built in erlang binaries, using <c>term_to_binary() / binary_to_term()</c>
- to create / extract binary structures.</p>
- </item>
- <item>
- <p>no encoding/decoding functions are generated</p>
- </item>
- <item>
- <p>the underlying protocol is more efficient than usual sequences of
- octets</p>
- </item>
- </list>
- <p>The erlang binary IDL type is defined in <c>erlang.idl</c>, while its
- C definition is located in the <c>ic.h</c> header file, both in the
- <c><![CDATA[IC-< vsn >/include]]></c> directory.
- The user will have to include the file <c>erlang.idl</c> in order to use the
- <c>erlang::binary</c> type.</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>A Mapping Example</title>
- <p> <marker id="stack_idl"></marker>
-
- This is a small example of a simple stack. There are two
- operations on the stack, push and pop. The example shows all
- generated files as well as conceptual usage of the stack.</p>
- <code type="none">
-// The source IDL file: stack.idl
-
-struct s {
- long l;
- string s;
-};
-
-interface stack {
- void push(in s val);
- s pop();
-};
- </code>
- <p>When this file is compiled it produces four files, two for the
- top scope and two for the stack interface scope. The important parts
- of the generated C code for the stack API is shown below. <marker id="stack_serv"></marker>
-</p>
- <p>stack.c</p>
- <code type="none">
-
-void push(stack oe_obj, s val, CORBA_Environment* oe_env) {
- ...
-}
-
-
-s* pop(stack oe_obj, CORBA_Environment* oe_env) {
- ...
-}
- </code>
- <p>oe_stack.h</p>
- <code type="none">
-#ifndef OE_STACK_H
-#define OE_STACK_H
-
-
-/*------------------------------------------------------------
- * Struct definition: s
- */
-typedef struct {
- long l;
- char *s;
-} s;
-
-
-
-#endif
- </code>
- <p>stack.h just contains an include statement of <c>oe_stack.h</c>.</p>
- <p>oe_code_s.c</p>
- <code type="none">
-
-int oe_sizecalc_s(CORBA_Environment
- *oe_env, int* oe_size_count_index, int* oe_size) {
- ...
-}
-
-int oe_encode_s(CORBA_Environment *oe_env, s* oe_rec) {
- ...
-}
-
-int oe_decode_s(CORBA_Environment *oe_env, char *oe_first,
- int* oe_outindex, s *oe_out) {
- ...
-}
- </code>
- <p>The only files that are really important are the <c>.h</c>
- files and the stack.c file.</p>
- </section>
-</chapter>
-
diff --git a/lib/ic/doc/src/ch_c_server.xml b/lib/ic/doc/src/ch_c_server.xml
deleted file mode 100644
index df25927c90..0000000000
--- a/lib/ic/doc/src/ch_c_server.xml
+++ /dev/null
@@ -1,149 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1998</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>The C Server Back-end</title>
- <prepared></prepared>
- <docno></docno>
- <date>2004-01-14</date>
- <rev>C</rev>
- <file>ch_c_server.xml</file>
- </header>
-
- <section>
- <title>Introduction</title>
- <p>With the option <c>{be, c_server}</c> the IDL Compiler generates
- C server skeletons according to the IDL to C mapping, on top of
- the Erlang distribution and gen_server protocols.</p>
- <p>The developer has to write additional code, that together with
- the generated C server skeletons, form a hidden Erlang
- node. That additional code contains implementations of call-back
- functions that implement the true server functionality, and also
- code uses <c>erl_interface</c> functions for defining the hidden
- node and for establishing connections to other Erlang nodes.</p>
- </section>
-
- <section>
- <title>Generated Stub Files</title>
- <p>The generated stub files are:</p>
- <list type="bulleted">
- <item>
- <p>For each IDL interface, a C source file, the name of which
- is <c><![CDATA[<Scoped Interface Name>__s.c]]></c>. Each operation of the
- IDL interface is mapped to a C function (with scoped name)
- in that file;</p>
- </item>
- <item>
- <p>C source files that contain functions for type conversion,
- memory allocation, and data encoding/decoding;</p>
- </item>
- <item>
- <p>C header files that contain function prototypes and type
- definitions.</p>
- </item>
- </list>
- <p>All C functions are exported (i.e. not declared static).</p>
- </section>
-
- <section>
- <title>C Skeleton Functions</title>
- <p>For each IDL operation a C skeleton function is generated, the
- prototype of which is <c><![CDATA[int <Scoped Function Name>__exec(<Interface Object> oe_obj, CORBA_Environment *oe_env)]]></c>, where <c><![CDATA[<Interface Object>]]></c>, and
- <c>CORBA_Environment</c> are of the same type as for the
- generated C client stubs code.</p>
- <p>Each <c><![CDATA[<Scoped Function Name>__exec()]]></c> function calls the
- call-back function</p>
- <p><c><![CDATA[<Scoped Function Name>_rs* <Scoped Function Name>__cb(<Interface Object> oe_obj, <Parameters>, CORBA_Environment *oe_env)]]></c></p>
- <p>where the arguments are of the same type as those generated for
- C client stubs. </p>
- <p>The return value <c><![CDATA[<Scoped Function Name>_rs* ]]></c> is a pointer
- to a function with the same signature as the call-back function
- <c><![CDATA[<Scoped Function Name>_cb]]></c>, and is called after the call-back
- function has been evaluated (provided that the pointer is not equal
- to <c>NULL</c>). </p>
- </section>
-
- <section>
- <title>The Server Loop</title>
- <p>The developer has to implement code for establishing connections
- with other Erlang nodes, code for call-back functions and restore
- functions. </p>
- <p></p>
- <p>In addition, the developer also has to implement code for a
- server loop, that receives messages and calls the relevant
- <c>__exec</c> function. For that purpose the IC library function
- <c>oe_server_receive()</c> function can be used.</p>
- </section>
-
- <section>
- <title>Generating, Compiling and Linking</title>
- <p>To generate the C server skeletons type the following in an
- appropriate shell:</p>
- <p><c>erlc -I ICROOT/include "+{be, c_server}" File.idl</c>,</p>
- <p>where <c>ICROOT</c> is the root of the IC application. The
- <c>-I ICROOT/include</c> is only needed if <c>File.idl</c>
- refers to <c>erlang.idl</c>.</p>
- <p>When compiling a generated C skeleton file, the directories
- <c>ICROOT/include</c> and <c>EICROOT/include</c>, have to be
- specified as include directories, where <c>EIROOT</c> is the
- root directory of the Erl_interface application.</p>
- <p>When linking object files the <c>EIROOT/lib</c> and
- <c>ICROOT/priv/lib</c> directories have to be specified. </p>
- </section>
-
- <section>
- <title>An Example</title>
- <p>In this example the IDL specification file "random.idl" is used
- for generating C server skeletons (the file is contained in the IC
- <c>/examples/c-server</c> directory):</p>
- <code type="none">
-module rmod {
-
- interface random {
-
- double produce();
-
- oneway void init(in long seed1, in long seed2, in long seed3);
-
- };
-
-}; </code>
- <p>Generate the C server skeletons:</p>
- <code type="none">
-erlc '+{be, c_server}' random.idl
-Erlang IDL compiler version X.Y.Z </code>
- <p>Six files are generated. </p>
- <p>Compile the C server skeletons:</p>
- <p>Please read the <c>ReadMe</c> file in the
- <c>examples/c-server</c> directory.</p>
- <p>In the same directory you can find all the code for this
- example. In particular you will find the <c>server.c</c> file
- that contains all the additional code that must be written to
- obtain a complete server.</p>
- <p>In the <c>examples/c-server</c> directory you will also find
- source code for an Erlang client, which can be used for testing
- the C server.</p>
- </section>
-</chapter>
-
-
diff --git a/lib/ic/doc/src/ch_erl_genserv.xml b/lib/ic/doc/src/ch_erl_genserv.xml
deleted file mode 100644
index aa162b3652..0000000000
--- a/lib/ic/doc/src/ch_erl_genserv.xml
+++ /dev/null
@@ -1,206 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1998</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Using the Erlang Generic Server Back-end</title>
- <prepared></prepared>
- <docno></docno>
- <date>98-08-06</date>
- <rev>B</rev>
- <file>ch_erl_genserver.xml</file>
- </header>
-
- <section>
- <title>Introduction</title>
- <p>The mapping of OMG IDL to the Erlang programming language when Erlang
- generic server is the back-end of choice is similar to the one used in
- the chapter 'OMG IDL Mapping'.
- The only difference is in the generated code, a client stub and
- server skeleton to an Erlang <c>gen_server</c>. Orber's User's Guide
- contain a more detailed description of IDL to Erlang mapping.</p>
- </section>
-
- <section>
- <title>Compiling the Code</title>
- <p>The <c>ic:gen/2</c> function can be called from the command
- line as follows:</p>
- <p></p>
- <code type="none">
-shell> erlc "+{be, erl_genserv}" MyFile.idl
- </code>
- </section>
-
- <section>
- <title>Writing the Implementation File</title>
- <p>For each IDL interface <c><![CDATA[<interface name>]]></c> defined in the IDL file :</p>
- <list type="bulleted">
- <item>Create the corresponding Erlang file that will hold the
- Erlang implementation of the IDL definitions. </item>
- <item>Call the implementation file after the scope of the IDL interface,
- followed by the suffix <c>_impl</c>.</item>
- <item>Export the implementation functions.</item>
- </list>
- <p>For each function defined in the IDL interface :</p>
- <list type="bulleted">
- <item>Implement an Erlang function that uses as arguments in the same
- order, as the input arguments described in the IDL file, and returns
- the value described in the interface.</item>
- <item>When using the function, follow the mapping described in chapter 2.</item>
- </list>
- </section>
-
- <section>
- <title>An Example</title>
- <p>In this example, a file <c>random.idl</c> generates code for the Erlang
- gen_server back-end:</p>
- <code type="none">
-// Filename random.idl
-module rmod {
-
- interface random {
- // Generate a new random number
- double produce();
- // Initialize random generator
- oneway void init(in long seed1, in long seed2, in long seed3);
-
- };
-};
- </code>
- <p>When the file "random.idl" is compiled (e.g., <c>shell> erlc "+{be, erl_genserv}" random.idl</c>)
- five files are produced; two for the top scope, two for the interface scope,
- and one for the module scope. The header files for top scope and interface
- are empty and not shown here. In this case, the stub/skeleton file
- <c>rmod_random.erl</c> is the most important. This module exports two kinds of
- operations:</p>
- <list type="bulleted">
- <item><em>Administrative</em> - used when, for example, creating and
- terminating the server.</item>
- <item><em>IDL dependent</em> - operations defined in the IDL
- specification. In this case, <c>produce</c> and <c>init</c>.</item>
- </list>
-
- <section>
- <title>Administrative Operations</title>
- <p>To create a new server instance, one of the following functions should
- be used:</p>
- <list type="bulleted">
- <item><em>oe_create/0/1/2</em> - create a new instance of the object.
- Accepts <c>Env</c> and <c>RegName</c>, in that order, as parameters.
- The former is passed uninterpreted to the initialization operation
- of the call-back module, while the latter must be as the
- <c>gen_server</c> parameter <c>ServerName</c>. If <c>Env</c> is
- left out, an empty list will be passed.</item>
- <item><em>oe_create_link/0/1/2</em> - similar to <c>oe_create/0/1/2</c>,
- but create a linked server.</item>
- <item><em>typeID/0</em> - returns the scooped id compliant with the
- OMG standard. In this case the string
- <c>"IDL:rmod/random:1.0"</c>.</item>
- <item><em>stop/1</em> - asynchronously terminate the server. The required
- argument is the return value from any of the start functions.</item>
- </list>
- </section>
-
- <section>
- <title>IDL Dependent Operations</title>
- <p>Operations can either be synchronous or asynchronous
- (i.e., <c>oneway</c>). These are, respectively, mapped to
- <c>gen_server:call/2/3</c> and <c>gen_server:cast/2</c>.
- Consult the <c>gen_server</c> documentation for valid return values.</p>
- <p>The IDL dependent operations in this example are listed below.
- The first argument must be the whatever the create operation returned.</p>
- <list type="bulleted">
- <item><em>init(ServerReference, Seed1, Seed2, Seed3)</em> - initialize
- the random number generator.</item>
- <item><em>produce(ServerReference)</em> - generate a new random number.</item>
- </list>
- </section>
- <p>If the compile option <c>timeout</c> is used a timeout must be added
- (e.g., <c>produce(ServerReference, 5000)</c>). For more information, see
- the <c>gen_server</c> documentation.</p>
-
- <section>
- <title>Implementation Module</title>
- <p>The implementation module shall, unless the compile option
- <c>impl</c> is used, be named <c>rmod_random_impl.erl</c>.
- and could look like this:</p>
- <code type="none">
--module('rmod_random_impl').
-%% Mandatory gen_server operations
--export([init/1, terminate/2, code_change/3]).
-%% Add if 'handle_info' compile option used
--export([handle_info/2]).
-%% API defined in IDL specification
--export([produce/1,init/4]).
-
-%% Mandatory operations
-init(Env) ->
- {ok, []}.
-
-terminate(From, Reason) ->
- ok.
-
-code_change(OldVsn, State, Extra) ->
- {ok, State}.
-
-%% Optional
-handle_info(Info, State) ->
- {noreply, NewState}.
-
-%% IDL specification
-produce(State) ->
- case catch random:uniform() of
- {'EXIT',_} ->
- {stop, normal, "random:uniform/0 - EXIT", State};
- RUnif ->
- {reply, RUnif, State}
- end.
-
-
-init(State, S1, S2, S3) ->
- case catch random:seed(S1, S2, S3) of
- {'EXIT',_} ->
- {stop, normal, State};
- _ ->
- {noreply, State}
- end.
- </code>
- <p>Compile the code and run the example:</p>
- <code type="none"><![CDATA[
-1> make:all().
-Recompile: rmod_random
-Recompile: oe_random
-Recompile: rmod_random_impl
-up_to_date
-2> {ok,R} = rmod_random:oe_create().
-{ok,<0.30.0>}
-3> rmod_random:init(R, 1, 2, 3).
-ok
-4> rmod_random:produce(R).
-1.97963e-4
-5>
- ]]></code>
- </section>
- </section>
-</chapter>
-
-
diff --git a/lib/ic/doc/src/ch_erl_plain.xml b/lib/ic/doc/src/ch_erl_plain.xml
deleted file mode 100644
index 27387d1624..0000000000
--- a/lib/ic/doc/src/ch_erl_plain.xml
+++ /dev/null
@@ -1,176 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1998</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Using the Plain Erlang Back-end</title>
- <prepared></prepared>
- <docno></docno>
- <date>98-05-06</date>
- <rev>B</rev>
- <file>ch_erl_plain.xml</file>
- </header>
-
- <section>
- <title>Introduction</title>
- <p>The mapping of OMG IDL to the Erlang programming language when
- Plain Erlang
- is the back-end of choice is similar to the one used in pure Erlang IDL
- mapping. The only difference is on the generated code and the extended
- use of pragmas for code generation: IDL functions are translated
- to Erlang
- module function calls.</p>
- </section>
-
- <section>
- <title>Compiling the Code</title>
- <p>In the Erlang shell type :</p>
- <p>ic:gen(<c><![CDATA[<filename>, [{be, erl_plain}])]]></c>.</p>
- </section>
-
- <section>
- <title>Writing the Implementation File</title>
- <p>For each IDL interface <c><![CDATA[<interface name>]]></c> defined in the IDL file:</p>
- <list type="bulleted">
- <item>Create the corresponding Erlang file that will hold the
- Erlang implementation of the IDL definitions. </item>
- <item>Call the implementation file after the scope of the IDL interface,
- followed by the suffix <c>_impl</c>.</item>
- <item>Export the implementation functions.</item>
- </list>
- <p>For each function defined in the IDL interface :</p>
- <list type="bulleted">
- <item>Implement an Erlang function that uses as arguments in the same
- order, as the input arguments described in the IDL file, and returns
- the value described in the interface.</item>
- <item>When using the function, follow the mapping described in chapter 2.</item>
- </list>
- </section>
-
- <section>
- <title>An Example</title>
- <p> <marker id="plain_idl"></marker>
-
- In this example, a file "random.idl" is generates code for the plain Erlang
- back-end :</p>
- <list type="bulleted">
- <item>
- <p>Main file : "plain.idl"</p>
- <code type="none">
-
-module rmod {
-
- interface random {
-
- double produce();
-
- oneway void init(in long seed1, in long seed2, in long seed3);
-
- };
-
-};
- </code>
- </item>
- </list>
- <p>Compile the file :</p>
- <code type="none">
- Erlang (BEAM) emulator version 4.9
-
- Eshell V4.9 (abort with ^G)
- 1> ic:gen(random,[{be, erl_plain}]).
- Erlang IDL compiler version 2.5.1
- ok
- 2>
- </code>
- <p></p>
- <p>When the file "random.idl" is compiled it produces five files: two for
- the top scope, two for the interface scope, and one for the module
- scope. The header files for top scope and interface
- are empty and not shown here. In this case only the file for the interface
- <c>rmod_random.erl</c> is important :.
- <marker id="generated files"></marker>
-</p>
- <list type="bulleted">
- <item>
- <p>Erlang file for interface : "rmod_random.erl"</p>
- <code type="none">
-
--module(rmod_random).
-
-
-
-%% Interface functions
--export([produce/0, init/3]).
-
-%%------------------------------------------------------------
-%% Operation: produce
-%%
-%% Returns: RetVal
-%%
-produce() ->
- rmod_random_impl:produce().
-
-%%------------------------------------------------------------
-%% Operation: init
-%%
-%% Returns: RetVal
-%%
-init(Seed1, Seed2, Seed3) ->
- rmod_random_impl:init(Seed1, Seed2, Seed3).
- </code>
- </item>
- </list>
- <p>The implementation file should be called <c>rmod_random_impl.erl</c>
- and could look like this:</p>
- <code type="none">
- -module('rmod_random_impl').
-
- -export([produce/0,init/3]).
-
-
- produce() ->
- random:uniform().
-
-
- init(S1,S2,S3) ->
- random:seed(S1,S2,S3).
- </code>
- <p>Compiling the code : </p>
- <code type="none">
-2> make:all().
-Recompile: rmod_random
-Recompile: oe_random
-Recompile: rmod_random_impl
-up_to_date
- </code>
- <p></p>
- <p>Running the example : </p>
- <code type="none">
-3> rmod_random:init(1,2,3).
-ok
-4> rmod_random:produce().
-1.97963e-4
-5>
- </code>
- </section>
-</chapter>
-
diff --git a/lib/ic/doc/src/ch_ic_protocol.xml b/lib/ic/doc/src/ch_ic_protocol.xml
deleted file mode 100644
index cb64500f6e..0000000000
--- a/lib/ic/doc/src/ch_ic_protocol.xml
+++ /dev/null
@@ -1,234 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2003</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>IC Protocol</title>
- <prepared></prepared>
- <docno></docno>
- <date>2003-12-11</date>
- <rev>PA1</rev>
- <file>ch_ic_protocol.xml</file>
- </header>
- <p>The purpose of this chapter is to explain the bits and bytes of the
- IC protocol, which is a composition of the Erlang distribution protocol
- and the Erlang/OTP gen_server protocol. If you do not intend to replace
- the Erlang distribution protocol, or replace the gen_server protocol,
- skip over this chapter.
- </p>
-
- <section>
- <title>Introduction</title>
- <p>The IDL Compiler (IC) transforms Interface Definition Language
- (IDL) specifications files to interface code for Erlang, C, and
- Java. The Erlang language mapping is described in the Orber
- documentation, while the other mappings are described in the IC
- documentation (they are of course in accordance with the CORBA C
- and Java language mapping specifications, with some restrictions).
- </p>
- <p>The most important parts of an IDL specification are the operation
- declarations. An operation defines what information a client
- provides to a server, and what information (if any) the client
- gets back from the server. We consider IDL operations and language
- mappings in section 2.
- </p>
- <p>What we here call the IC protocol, is the description of messages
- exchanged between IC end-points (client and servers). It is valid
- for all IC back-ends, except the 'erl_plain' and 'erl_corba'
- back-ends.
- The IC protocol is in turn embedded into the Erlang gen_server
- protocol, which is described below.
- Finally, the gen_server protocol is embedded in the Erlang
- distribution protocol. Pertinent parts of that protocol is
- described further below.
- </p>
- </section>
-
- <section>
- <title>Language mappings and IDL operations</title>
-
- <section>
- <title>IDL Operations</title>
- <p>An IDL operation is declared as follows:</p>
- <code type="none">
- [oneway] RetType Op(in IType1 I1, in IType2 I2, ..., in ITypeN IN,
- out OType1 O1, out OType2 O2, ..., out OTypeM OM)
- N, M = 0, 1, 2, ... (2.1.1)
- </code>
- <p>`Op' is the operation name, RetType is the return type, and ITypei,
- i = 1, 2, ..., N, and OTypej, j = 1, 2, ..., M, are the `in' types
- and `out' types, respectively. The values I1, I2, ..., IN are
- provided by the caller, and the value of RetType, and the values
- O1, O2, ..., OM, are provided as results to the caller.
- </p>
- <p>The types can be any basic types or derived types declared in the
- IDL specification of which the operation declaration is a part.
- </p>
- <p>If the RetType has the special name `void' there is no return
- value (but there might still be result values O1, 02, ..., OM).
- </p>
- <p>The `in' and `out' parameters can be declared in any order, but
- for clarity we have listed all `in' parameters before the `out'
- parameters in the declaration above.
- </p>
- <p>If the keyword `oneway' is present, the operation is a cast, i.e.
- there is no confirmation of the operation, and consequently there
- must be no result values: RetType must be equal to `void', and M =
- 0 must hold.
- </p>
- <p>Otherwise the operation is a call, i.e. it is confirmed (or else
- an exception is raised).
- </p>
- <p>Note carefully that an operation declared without `oneway' is
- always a call, even if RetType is `void' and M = 0.
- </p>
- </section>
-
- <section>
- <title>Language Mappings</title>
- <p>There are several CORBA Language Mapping specifications. These are
- about mapping interfaces to various programming languages. IC
- supports the CORBA C and Java mapping specifications, and the
- Erlang language mapping specified in the Orber documentation.
- </p>
- <p>Excerpt from "6.4 Basic OMG IDL Types" in the Orber User's Guide:
- </p>
- <list type="bulleted">
- <item>
- <p>Functions with return type void will return the atom ok.</p>
- </item>
- </list>
- <p>Excerpt from "6.13 Invocations of Operations" in the Orber User's
- Guide:
- </p>
- <list type="bulleted">
- <item>
- <p>A function call will invoke an operation. The first parameter
- of the function should be the object reference and then all in
- and inout parameters follow in the same order as specified in
- the IDL specification. The result will be a return value
- unless the function has inout or out parameters specified; in
- which case, a tuple of the return value, followed by the
- parameters will be returned.</p>
- </item>
- </list>
- <p>Hence the function that is mapped from an IDL operation to Erlang
- always have a return value (an Erlang function always has). That
- fact has influenced the IC protocol, in that there is always a
- return value (which is 'ok' if the return type was declared 'void'). </p>
- </section>
- </section>
-
- <section>
- <title>IC Protocol</title>
- <p>Given the operation declaration (2.1.1) the IC protocol maps to
- messages as follows, defined in terms of Erlang terms.
- </p>
-
- <section>
- <title>Call (Request/Reply, i.e. not oneway)</title>
- <code type="none">
- request: Op atom() N = 0
- {Op, I1, I2, ..., IN} tuple() N > 0
- (3.1.1)
-
- reply: Ret M = 0
- {Ret, O1, O2, ..., OM} M > 0
- (3.1.2)</code>
- <p><em>Notice:</em> Even if the RetType of the operation Op is
- declared to be 'void', a return value 'ok' is returned in
- the reply message. That
- return value is of no significance, and is therefore ignored (note
- however that a C server back-end returns the atom 'void' instead
- of 'ok').
- </p>
- </section>
-
- <section>
- <title>Cast (oneway)</title>
- <code type="none">
-
- notification: Op atom() N = 0
- {Op, I1, I2, ..., IN} tuple() N > 0
- (3.2.1)</code>
- <p>(There is of course no return message).
- </p>
- </section>
- </section>
-
- <section>
- <title>Gen_server Protocol</title>
- <p>Most of the IC generated code deals with encoding and decoding the
- gen_server protocol.
- </p>
-
- <section>
- <title>Call</title>
- <code type="none">
-
- request: {'$gen_call', {self(), Ref}, Request} (4.1.1)
-
- reply: {Ref, Reply} (4.1.2)</code>
- <p>where Request and Reply are the messages defined in the previous
- chapter.
- </p>
- </section>
-
- <section>
- <title>Cast</title>
- <code type="none">
- notification: {'$gen_cast', Notification} (4.2.1) </code>
- <p>where Notification is the message defined in the previous chapter.
- </p>
- </section>
- </section>
-
- <section>
- <title>Erlang Distribution Protocol</title>
- <p>Messages (of interest here) between Erlang nodes are of the form: </p>
- <code type="none">
- Len(4), Type(1), CtrlBin(N), MsgBin(M) (5.1) </code>
- <p>Type is equal to 112 = PASS_THROUGH.
- </p>
- <p>CtrlBin and MsgBin are Erlang terms in binary form (as if created
- by term_to_binary/1), whence for each of them the first byte is
- equal to 131 = VERSION_MAGIC.
- </p>
- <p>CtrlBin (of interest here) contains the SEND and REG_SEND control
- messages, which are binary forms of the Erlang terms</p>
- <code type="none">
- {2, Cookie, ToPid} , (5.2) </code>
- <p>and</p>
- <code type="none">
- {6, FromPid, Cookie, ToName} , (5.3) </code>
- <p>respectively.
- </p>
- <p>The CtrlBin(N) message is read and written by erl_interface code
- (C), j_interface code (Java), or the Erlang distribution
- implementation, which are invoked from IC generated code.
- </p>
- <p>The MsgBin(N) is the "real" message, i.e. of the form described
- in the previous section.
- </p>
- </section>
-</chapter>
-
diff --git a/lib/ic/doc/src/ch_introduction.xml b/lib/ic/doc/src/ch_introduction.xml
deleted file mode 100644
index 9ac2f96a95..0000000000
--- a/lib/ic/doc/src/ch_introduction.xml
+++ /dev/null
@@ -1,149 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1998</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Using the IC Compiler</title>
- <prepared></prepared>
- <docno></docno>
- <date>2002-08-02</date>
- <rev>PB1</rev>
- <file>ch_introduction.xml</file>
- </header>
-
- <section>
- <title>Introduction</title>
- <p>The IC application is an IDL compiler implemented in Erlang.
- The IDL compiler generates client stubs and server skeletons.
- Several back-ends are supported, and they fall into three main
- groups.</p>
- <p>The first group consists of a CORBA back-end:</p>
- <taglist>
- <tag>IDL to Erlang CORBA</tag>
- <item>
- <p>This back-end is for CORBA communication and implementation,
- and the generated code uses the CORBA specific protocol for
- communication between clients and servers. See the
- <em>Orber</em> application User's Guide and manuals for
- further details.</p>
- </item>
- </taglist>
- <p>The second group consists of a simple Erlang back-end:</p>
- <taglist>
- <tag>IDL to plain Erlang</tag>
- <item>
- <p>This back-end provides a very simple Erlang client
- interface. It can only be used within an Erlang node,
- and the communication between client and "server" is
- therefore in terms of ordinary function calls. </p>
- <p>This back-end can be considered a short-circuit version of
- the IDL to Erlang gen_server back-end (see further below).</p>
- </item>
- </taglist>
- <p>The third group consists of backends for Erlang, C, and
- Java. The communication between clients and servers is by the
- Erlang distribution protocol, facilitated by
- <em>erl_interface</em> and <em>jinterface</em> for C and Java,
- respectively.</p>
- <p>All back-ends of the third group generate code compatible with
- the Erlang gen_server behavior protocol. Thus generated client
- code corresponds to <c>call()</c> or <c>cast()</c> of an Erlang
- <c>gen_server</c>. Similarly, generated server code corresponds
- to <c>handle_call()</c> or <c>handle_cast()</c> of an Erlang
- <c>gen_server</c>.</p>
- <p>The back-ends of the third group are:
- </p>
- <taglist>
- <tag>IDL to Erlang gen_server</tag>
- <item>
- <p>Client stubs and server skeletons are generated. Data types
- are mapped according to the IDL to Erlang mapping described
- in the <em>Orber User's Guide</em>.</p>
- <p></p>
- </item>
- <tag>IDL to C client</tag>
- <item>
- <p>Client stubs are generated. The mapping of data types is
- described further on in the C client part of this guide.</p>
- </item>
- <tag>IDL to C server</tag>
- <item>
- <p>Server skeletons are generated. The mapping of data types is
- described further on in the C server part of this guide.</p>
- </item>
- <tag>IDL to Java</tag>
- <item>
- <p>Client stubs and server skeletons are generated. The mapping
- of data types is described further on in the Java part of
- this guide.</p>
- </item>
- </taglist>
- </section>
-
- <section>
- <title>Compilation of IDL Files</title>
- <p>The IC compiler is invoked by executing the generic <c>erlc</c>
- compiler from a shell:</p>
- <code type="none">
-%> erlc +'{be,BackEnd}' File.idl
- </code>
- <p>where <c>BackEnd</c> is according to the table below, and
- <c>File.idl</c> is the IDL file to be compiled.</p>
- <table>
- <row>
- <cell align="left" valign="middle"><em>Back-end</em></cell>
- <cell align="left" valign="middle"><c>BackEnd</c>option</cell>
- </row>
- <row>
- <cell align="left" valign="middle">IDL to CORBA</cell>
- <cell align="left" valign="middle"><c>erl_corba</c></cell>
- </row>
- <row>
- <cell align="left" valign="middle">IDL to CORBA template</cell>
- <cell align="left" valign="middle"><c>erl_template</c></cell>
- </row>
- <row>
- <cell align="left" valign="middle">IDL to plain Erlang</cell>
- <cell align="left" valign="middle"><c>erl_plain</c></cell>
- </row>
- <row>
- <cell align="left" valign="middle">IDL to Erlang gen_server</cell>
- <cell align="left" valign="middle"><c>erl_genserv</c></cell>
- </row>
- <row>
- <cell align="left" valign="middle">IDL to C client</cell>
- <cell align="left" valign="middle"><c>c_client</c></cell>
- </row>
- <row>
- <cell align="left" valign="middle">IDL to C server</cell>
- <cell align="left" valign="middle"><c>c_server</c></cell>
- </row>
- <row>
- <cell align="left" valign="middle">IDL to Java</cell>
- <cell align="left" valign="middle"><c>java</c></cell>
- </row>
- <tcaption>Compiler back-ends and options</tcaption>
- </table>
- <p>For more details on IC compiler options consult the ic(3) manual page.</p>
- </section>
-</chapter>
-
diff --git a/lib/ic/doc/src/ch_java.xml b/lib/ic/doc/src/ch_java.xml
deleted file mode 100644
index a733adaf65..0000000000
--- a/lib/ic/doc/src/ch_java.xml
+++ /dev/null
@@ -1,738 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1999</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>IDL to Java language Mapping</title>
- <prepared></prepared>
- <docno></docno>
- <date>98-09-24</date>
- <rev>A</rev>
- <file>ch_java.xml</file>
- </header>
-
- <section>
- <title>Introduction</title>
- <p>This chapter describes the mapping of OMG IDL constructs to the Java
- programming language for the generation of native Java - Erlang
- communication. </p>
- <p>This language mapping defines the following:</p>
- <list type="bulleted">
- <item>
- <p>All OMG IDL basic types</p>
- </item>
- <item>
- <p>All OMG IDL constructed types</p>
- </item>
- <item>
- <p>References to constants defined in OMG IDL</p>
- </item>
- <item>
- <p>Invocations of operations, including passing of
- parameters and receiving of result</p>
- </item>
- <item>
- <p>Access to attributes</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Specialties in the Mapping</title>
-
- <section>
- <title>Names Reserved by the Compiler</title>
- <p>The IDL compiler reserves all identifiers starting with
- <c>OE_</c> and <c>oe_</c> for internal use.</p>
- </section>
- </section>
-
- <section>
- <title>Basic OMG IDL Types</title>
- <p>The mapping of basic types are according to the standard. All basic types have
- a special Holder class.</p>
- <table>
- <row>
- <cell align="left" valign="middle">OMG IDL type</cell>
- <cell align="left" valign="middle">Java type</cell>
- </row>
- <row>
- <cell align="left" valign="middle">float</cell>
- <cell align="left" valign="middle">float</cell>
- </row>
- <row>
- <cell align="left" valign="middle">double</cell>
- <cell align="left" valign="middle">double</cell>
- </row>
- <row>
- <cell align="left" valign="middle">short</cell>
- <cell align="left" valign="middle">short</cell>
- </row>
- <row>
- <cell align="left" valign="middle">unsigned short</cell>
- <cell align="left" valign="middle">short</cell>
- </row>
- <row>
- <cell align="left" valign="middle">long</cell>
- <cell align="left" valign="middle">int</cell>
- </row>
- <row>
- <cell align="left" valign="middle">long long</cell>
- <cell align="left" valign="middle">long</cell>
- </row>
- <row>
- <cell align="left" valign="middle">unsigned long</cell>
- <cell align="left" valign="middle">long</cell>
- </row>
- <row>
- <cell align="left" valign="middle">unsigned long long</cell>
- <cell align="left" valign="middle">long</cell>
- </row>
- <row>
- <cell align="left" valign="middle">char</cell>
- <cell align="left" valign="middle">char</cell>
- </row>
- <row>
- <cell align="left" valign="middle">wchar</cell>
- <cell align="left" valign="middle">char</cell>
- </row>
- <row>
- <cell align="left" valign="middle">boolean</cell>
- <cell align="left" valign="middle">boolean</cell>
- </row>
- <row>
- <cell align="left" valign="middle">octet</cell>
- <cell align="left" valign="middle">octet</cell>
- </row>
- <row>
- <cell align="left" valign="middle">string</cell>
- <cell align="left" valign="middle">java.lang.String</cell>
- </row>
- <row>
- <cell align="left" valign="middle">wstring</cell>
- <cell align="left" valign="middle">java.lang.String</cell>
- </row>
- <row>
- <cell align="left" valign="middle">any</cell>
- <cell align="left" valign="middle">Any</cell>
- </row>
- <row>
- <cell align="left" valign="middle">long double</cell>
- <cell align="left" valign="middle">Not supported</cell>
- </row>
- <row>
- <cell align="left" valign="middle">Object</cell>
- <cell align="left" valign="middle">Not supported</cell>
- </row>
- <row>
- <cell align="left" valign="middle">void</cell>
- <cell align="left" valign="middle">void</cell>
- </row>
- <tcaption>OMG IDL basic types</tcaption>
- </table>
- </section>
-
- <section>
- <title>Constructed OMG IDL Types</title>
- <p>All constructed types are according to the standard with three (3) major exceptions.</p>
- <p></p>
- <list type="bulleted">
- <item>
- <p>The IDL Exceptions are not implemented in this Java mapping.</p>
- <p></p>
- </item>
- <item>
- <p>The functions used for read/write to streams, defined in <c>Helper</c> functions
- are named unmarshal (instead for read) and marshal (instead for write). </p>
- <p></p>
- </item>
- <item>
- <p>The streams used in <c>Helper</c> functions are <c>OtpInputStream</c> for
- input and <c>OtpOutputStream</c> for output.</p>
- <p></p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Mapping for Constants</title>
- <p>Constants are mapped according to the standard.</p>
- </section>
-
- <section>
- <title>Invocations of Operations</title>
- <p>Operation invocation is implemented according to the standard.
- The implementation is in the class <c><![CDATA[_<nterfacename>Stub.java]]></c> which implements
- the interface in <c><![CDATA[<nterfacename>.java]]></c>.</p>
- <code type="none">
-test._iStub client;
-
-client.op(10);
- </code>
-
- <section>
- <title>Operation Implementation</title>
- <p>The server is implemented through extension of the class
- <c><![CDATA[_<nterfacename>ImplBase.java]]></c> and implementation of all the methods in the
- interface.</p>
- <code type="none">
-public class server extends test._iImplBase {
-
- public void op(int i) throws java.lang.Exception {
- System.out.println("Received call op()");
- o.value = i;
- return i;
- }
-
-}
- </code>
- </section>
- </section>
-
- <section>
- <title>Exceptions</title>
- <p>While exception mapping is not implemented, the stubs will
- generate some Java exceptions in case of operation failure.
- No exceptions are propagated through the communication.</p>
- </section>
-
- <section>
- <title>Access to Attributes</title>
- <p>Attributes are supported according to the standard.</p>
- </section>
-
- <section>
- <title>Summary of Argument/Result Passing for Java</title>
- <p>All types (<c>in</c>, <c>out</c> or <c>inout</c>) of user defined parameters are supported
- in the Java mapping. This is also the case in the Erlang mappings but <em>not</em> in the C
- mapping. <c>inout</c> parameters are not supported in the C mapping so if you are going to
- do calls to or from a C program <c>inout</c> cannot be used in the IDL specifications.</p>
- <p><c>out</c> and <c>inout</c> parameters must be of Holder types. There is a jar file ( <c>ic.jar</c>)
- with Holder classes for the basic types in the <c>ic</c> application. This library is in the directory
- <c><![CDATA[$OTPROOT/lib/ic_<version number>/priv]]></c>.</p>
- </section>
-
- <section>
- <title>Communication Toolbox</title>
- <p>The generated client and server stubs use the classes
- defined in the <c>jinterface</c> package to communicate
- with other nodes.
- The most important classes are :</p>
- <list type="bulleted">
- <item>
- <p><c>OtpInputStream</c> which is the stream class used for incoming message storage</p>
- <p></p>
- </item>
- <item>
- <p><c>OtpOutputStream</c> which is the stream class used for outgoing message storage</p>
- <p></p>
- </item>
- <item>
- <p><c>OtpErlangPid</c> which is the process identification class used to identify processes inside
- a java node.</p>
- <p>The recommended constructor function for the OtpErlangPid is
- <c>OtpErlangPid(String node, int id, int serial, int creation)</c> where :</p>
- <p></p>
- <list type="bulleted">
- <item>
- <p><c>String node</c>, is the name of the node where this process runs.</p>
- <p></p>
- </item>
- <item>
- <p><c>int id</c>, is the identification number for this identity.</p>
- <p></p>
- </item>
- <item>
- <p><c>int serial</c>, internal information, must be an 18-bit integer.</p>
- <p></p>
- </item>
- <item>
- <p><c>int creation</c>, internal information, must have value in range 0..3.</p>
- <p></p>
- </item>
- </list>
- </item>
- <item>
- <p><c>OtpConnection</c> which is used to define a connection between nodes.</p>
- <p>While the connection object is stub side constructed in client stubs, it is
- returned after calling the <c>accept</c> function from an OtpErlangServer object
- in server stubs.
- The following methods used for node connection :</p>
- <p></p>
- <list type="bulleted">
- <item>
- <p><c>OtpInputStream receiveBuf()</c>, which returns the incoming streams that
- contain the message arrived.</p>
- <p></p>
- </item>
- <item>
- <p><c>void sendBuf(OtpErlangPid client, OtpOutputStream reply)</c>, which sends
- a reply message (in an OtpOutputStream form) to the client node.</p>
- <p></p>
- </item>
- <item>
- <p><c>void close()</c>, which closes a connection.</p>
- <p></p>
- </item>
- </list>
- </item>
- <item>
- <p><c>OtpServer</c> which is used to define a server node.</p>
- <p>The recommended constructor function for the OtpServer is :</p>
- <p></p>
- <list type="bulleted">
- <item>
- <p><c>OtpServer(String node, String cookie)</c>. where :</p>
- <p></p>
- <list type="bulleted">
- <item>
- <p><c>node</c> is the requested name for the new java node,
- represented as a String object.</p>
- <p></p>
- </item>
- <item>
- <p><c>cookie</c> is the requested cookie name for the new java node,
- represented as a String object.</p>
- <p></p>
- </item>
- </list>
- </item>
- </list>
- <p>The following methods used for node registration and connection acceptance :</p>
- <p></p>
- <list type="bulleted">
- <item>
- <p><c>boolean publishPort()</c>, which registers the server node to <c>epmd</c> daemon.</p>
- <p></p>
- </item>
- <item>
- <p><c>OtpConnection accept()</c>, which waits for a connection and returns the
- OtpConnection object which is unique for each client node.</p>
- <p></p>
- </item>
- </list>
- </item>
- </list>
- </section>
-
- <section>
- <title>The Package com.ericsson.otp.ic</title>
- <p>The package <seealso marker="java/com/ericsson/otp/ic/package-summary">com.ericsson.otp.ic</seealso>
- contains a number of java classes specially designed for the IC generated java-back-ends :</p>
- <list type="bulleted">
- <item>
- <p>Standard java classes defined through OMG-IDL java mapping :</p>
- <list type="bulleted">
- <item>
- <p><seealso marker="java/com/ericsson/otp/ic/BooleanHolder">BooleanHolder</seealso></p>
- </item>
- <item>
- <p><seealso marker="java/com/ericsson/otp/ic/ByteHolder">ByteHolder</seealso></p>
- </item>
- <item>
- <p><seealso marker="java/com/ericsson/otp/ic/CharHolder">CharHolder</seealso></p>
- </item>
- <item>
- <p><seealso marker="java/com/ericsson/otp/ic/ShortHolder">ShortHolder</seealso></p>
- </item>
- <item>
- <p><seealso marker="java/com/ericsson/otp/ic/IntHolder">IntHolder</seealso></p>
- </item>
- <item>
- <p><seealso marker="java/com/ericsson/otp/ic/LongHolder">LongHolder</seealso></p>
- </item>
- <item>
- <p><seealso marker="java/com/ericsson/otp/ic/FloatHolder">FloatHolder</seealso></p>
- </item>
- <item>
- <p><seealso marker="java/com/ericsson/otp/ic/DoubleHolder">DoubleHolder</seealso></p>
- </item>
- <item>
- <p><seealso marker="java/com/ericsson/otp/ic/StringHolder">StringHolder</seealso></p>
- </item>
- <item>
- <p><seealso marker="java/com/ericsson/otp/ic/Any">Any</seealso>,
- <seealso marker="java/com/ericsson/otp/ic/AnyHelper">AnyHelper</seealso>,
- <seealso marker="java/com/ericsson/otp/ic/AnyHolder">AnyHolder</seealso></p>
- </item>
- <item>
- <p><seealso marker="java/com/ericsson/otp/ic/TypeCode">TypeCode</seealso></p>
- </item>
- <item>
- <p><seealso marker="java/com/ericsson/otp/ic/TCKind">TCKind</seealso></p>
- <p></p>
- </item>
- </list>
- </item>
- <item>
- <p>Implementation-dependant classes :</p>
- <list type="bulleted">
- <item>
- <p><seealso marker="java/com/ericsson/otp/ic/Environment">Environment</seealso></p>
- </item>
- <item>
- <p><seealso marker="java/com/ericsson/otp/ic/Holder">Holder</seealso></p>
- <p></p>
- </item>
- </list>
- </item>
- <item>
- <p>Erlang compatibility classes :</p>
- <list type="bulleted">
- <item>
- <p><seealso marker="java/com/ericsson/otp/ic/Pid">Pid</seealso>,
- <seealso marker="java/com/ericsson/otp/ic/PidHelper">PidHelper</seealso>,
- <seealso marker="java/com/ericsson/otp/ic/PidHolder">PidHolder</seealso></p>
- <p>The Pid class originates from <c>OtpErlangPid</c> and is used to
- represent the Erlang built-in <c>pid</c> type, a process's identity.
- PidHelper and PidHolder are helper respectively holder classes for Pid.</p>
- <p></p>
- </item>
- <item>
- <p><seealso marker="java/com/ericsson/otp/ic/Ref">Ref</seealso>,
- <seealso marker="java/com/ericsson/otp/ic/RefHelper">RefHelper</seealso>,
- <seealso marker="java/com/ericsson/otp/ic/RefHolder">RefHolder</seealso></p>
- <p>The Ref class originates from <c>OtpErlangRef</c> and is used to
- represent the Erlang built-in <c>ref</c> type, an Erlang reference.
- RefHelper and RefHolder are helper respectively holder classes for Ref.</p>
- <p></p>
- </item>
- <item>
- <p><seealso marker="java/com/ericsson/otp/ic/Port">Port</seealso>,
- <seealso marker="java/com/ericsson/otp/ic/PortHelper">PortHelper</seealso>,
- <seealso marker="java/com/ericsson/otp/ic/PortHolder">PortHolder</seealso></p>
- <p>The Port class originates from <c>OtpErlangPort</c> and is used to
- represent the Erlang built-in <c>port</c> type, an Erlang port.
- PortHelper and PortHolder are helper respectively holder classes for Port.</p>
- <p></p>
- </item>
- <item>
- <p><seealso marker="java/com/ericsson/otp/ic/Term">Term</seealso>,
- <seealso marker="java/com/ericsson/otp/ic/TermHelper">TermHelper</seealso>,
- <seealso marker="java/com/ericsson/otp/ic/TermHolder">TermHolder</seealso></p>
- <p>The Term class originates from <c>Any</c> and is used to
- represent the Erlang built-in <c>term</c> type, an Erlang term.
- TermHelper and TermHolder are helper respectively holder classes for Term.</p>
- <p></p>
- </item>
- </list>
- <p>To use the Erlang build-in classes, you will have to include the file <c>erlang.idl</c>
- located under <c>$OTPROOT/lib/ic/include</c>.</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>The Term Class</title>
- <p>The <c>Term</c> class is intended to represent the Erlang term generic type.
- It extends the <c>Any</c> class and it is basically used in the same way as
- in the Any type.</p>
- <p>The big difference between Term and Any is the use of <c>guard</c> methods
- instead of <c>TypeCode</c> to determine the data included in the Term.
- This is especially true when the Term's value class cannot be
- determined at compilation time. The guard methods found in Term :</p>
- <list type="bulleted">
- <item>
- <p><c>boolean isAtom()</c> returns <c>true</c> if the Term is an OtpErlangAtom, <c>false</c> otherwise</p>
- <p></p>
- </item>
- <item>
- <p><c>boolean isConstant()</c> returns <c>true</c> if the Term is neither an OtpErlangList nor an OtpErlangTuple, <c>false</c> otherwise</p>
- <p></p>
- </item>
- <item>
- <p><c>boolean isFloat()</c> returns <c>true</c> if the Term is an OtpErlangFloat, <c>false</c> otherwise</p>
- <p></p>
- </item>
- <item>
- <p><c>boolean isInteger()</c> returns <c>true</c> if the Term is an OtpErlangInt, <c>false</c> otherwise</p>
- <p></p>
- </item>
- <item>
- <p><c>boolean isList()</c> returns <c>true</c> if the Term is an OtpErlangList, <c>false</c> otherwise</p>
- <p></p>
- </item>
- <item>
- <p><c>boolean isString()</c> returns <c>true</c> if the Term is an OtpErlangString, <c>false</c> otherwise</p>
- <p></p>
- </item>
- <item>
- <p><c>boolean isNumber()</c> returns <c>true</c> if the Term is an OtpErlangInteger or an OtpErlangFloat, <c>false</c> otherwise</p>
- <p></p>
- </item>
- <item>
- <p><c>boolean isPid()</c> returns <c>true</c> if the Term is an OtpErlangPid or Pid, <c>false</c> otherwise</p>
- <p></p>
- </item>
- <item>
- <p><c>boolean isPort()</c> returns <c>true</c> if the Term is an OtpErlangPort or Port, <c>false</c> otherwise</p>
- <p></p>
- </item>
- <item>
- <p><c>boolean isReference()</c> returns <c>true</c> if the Term is an OtpErlangRef, <c>false</c> otherwise</p>
- <p></p>
- </item>
- <item>
- <p><c>boolean isTuple()</c> returns <c>true</c> if the Term is an OtpErlangTuple, <c>false</c> otherwise</p>
- <p></p>
- </item>
- <item>
- <p><c>boolean isBinary()</c> returns <c>true</c> if the Term is an OtpErlangBinary, <c>false</c> otherwise</p>
- <p></p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Stub File Types</title>
- <p>For each interface, three (3) stub/skeleton files are generated :</p>
- <list type="bulleted">
- <item>
- <p>A java interface file, named after the idl interface.</p>
- <p></p>
- </item>
- <item>
- <p>A client stub file, named after the convention <c><![CDATA[_< interface name >Stub]]></c>
- which implements the java interface. Example : <c>_stackStub</c>.java</p>
- <p></p>
- </item>
- <item>
- <p>A server stub file, named after the convention <c><![CDATA[_< interface name >ImplBase]]></c>
- which implements the java interface. Example : <c>_stackImplBase</c>.java</p>
- <p></p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Client Stub Initialization, Methods Exported</title>
- <p>The recommended constructor function for client stubs accepts four (4) parameters :</p>
- <p></p>
- <list type="bulleted">
- <item>
- <p><c>String selfNode</c>, the node identification name to be used in the new
- client node.</p>
- <p></p>
- </item>
- <item>
- <p><c>String peerNode</c>, the node identification name where the client process is running.</p>
- <p></p>
- </item>
- <item>
- <p><c>String cookie</c>, the cookie to be used.</p>
- <p></p>
- </item>
- <item>
- <p><c>Object server</c>, where the java Object can be one of:</p>
- <p></p>
- <list type="bulleted">
- <item>
- <p><c>OtpErlangPid</c>, the server's process identity under the node where the server
- process is running.</p>
- <p></p>
- </item>
- <item>
- <p><c>String</c>, the server's registered name under the node where the server
- process is running.</p>
- <p></p>
- </item>
- </list>
- </item>
- </list>
- <p>The methods exported from the generated client stub are :</p>
- <p></p>
- <list type="bulleted">
- <item>
- <p><c>void __disconnect()</c>, which disconnects the server connection.</p>
- <p></p>
- </item>
- <item>
- <p><c>void __reconnect()</c>, which disconnects the server connection if open,
- and then connects to the same peer.</p>
- <p></p>
- </item>
- <item>
- <p><c>void __stop()</c>, which sends the standard stop termination call.
- When connected to an Erlang server, the server will be terminated.
- When connected to a java server, this will set a stop flag that
- denotes that the server must be terminated.</p>
- <p></p>
- </item>
- <item>
- <p><c>com.ericsson.otp.erlang.OtpErlangRef __getRef()</c>, will return the message reference
- received from a server that denotes which call it is referring to.
- This is useful when building asynchronous clients.</p>
- <p></p>
- </item>
- <item>
- <p><c>java.lang.Object __server()</c>, which returns the server for the current connection.</p>
- <p></p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Server Skeleton Initialization, Server Stub Implementation, Methods Exported</title>
- <p>The constructor function for server skeleton accepts no parameters.</p>
- <p>The server skeleton file contains a server <c>switch</c> which
- decodes messages from the input stream and calls implementation
- (<c>callback</c>) functions.
- As the server skeleton is declared <c>abstract</c>, the application
- programmer will have to create a stub class that <c>extends</c> the
- skeleton file. In this class, all operations defined in the interface
- class, generated under compiling the idl file, are implemented.</p>
- <p>The server skeleton file exports the following methods:</p>
- <p></p>
- <list type="bulleted">
- <item>
- <p><c>OtpOutputStrem invoke(OtpInputStream request)</c>, where the input
- stream <c>request</c> is unmarshalled, the implementation function is called
- and a reply stream is marshalled.</p>
- <p></p>
- </item>
- <item>
- <p><c>boolean __isStopped()</c>, which returns true if a stop message is received.
- The implementation of the stub should always check if such a message is received
- and terminate if so.</p>
- <p></p>
- </item>
- <item>
- <p><c>boolean __isStopped(com.ericsson.otp.ic.Environment)</c>, which returns true if
- a stop message is received for a certain Environment and Connection.
- The implementation of the stub should always check if such a message is received
- and terminate if so.</p>
- <p></p>
- </item>
- <item>
- <p><c>OtpErlangPid __getCallerPid()</c>, which returns the caller identity for the latest call.</p>
- <p></p>
- </item>
- <item>
- <p><c>OtpErlangPid __getCallerPid(com.ericsson.otp.ic.Environment)</c>, which returns the caller
- identity for the latest call on a certain Environment.</p>
- <p></p>
- </item>
- <item>
- <p><c>java.util.Dictionary __operations()</c>, which returns the operation dictionary which
- holds all operations supported by the server skeleton.</p>
- <p></p>
- </item>
- </list>
- </section>
-
- <section>
- <title>A Mapping Example</title>
- <p> <marker id="stack_idl"></marker>
-
- This is a small example of a simple stack. There are two
- operations on the stack, push and pop. The example shows some of the
- generated files.</p>
- <code type="none">
-// The source IDL file: stack.idl
-
-struct s {
- long l;
- string s;
-};
-
-interface stack {
- void push(in s val);
- s pop();
-};
- </code>
- <p>When this file is compiled it produces eight files. Three important files
- are shown below. <marker id="stack_serv"></marker>
-</p>
- <p>The public interface is in <em>stack.java</em>.</p>
- <code type="none">
-
-public interface stack {
-
-/****
- * Operation "stack::push" interface functions
- *
- */
-
- void push(s val) throws java.lang.Exception;
-
-/****
- * Operation "stack::pop" interface functions
- *
- */
-
- s pop() throws java.lang.Exception;
-
-}
- </code>
- <p>For the IDL struct s three files are generated, a public class in <em>s.java</em>.</p>
- <code type="none">
-
-final public class s {
- // instance variables
- public int l;
- public java.lang.String s;
-
- // constructors
- public s() {};
- public s(int _l, java.lang.String _s) {
- l = _l;
- s = _s;
- };
-
-};
- </code>
- <p>A holder class in <em>sHolder.java</em> and a helper class in <em>sHelper.java</em>.
- The helper class is used for marshalling.</p>
- <code type="none">
-
-public class sHelper {
-
- // constructors
- private sHelper() {};
-
- // methods
- public static s unmarshal(OtpInputStream in)
- throws java.lang.Exception {
- :
- :
- };
-
- public static void marshal(OtpOutputStream out, s value)
- throws java.lang.Exception {
- :
- :
- };
-
-};
- </code>
- </section>
-
- <section>
- <title>Running the Compiled Code</title>
- <p>When using the generated java code you must have added
- <c><![CDATA[$OTPROOT/lib/ic_<version number>/priv]]></c> and
- <c><![CDATA[$OTPROOT/lib/jinterface_<version number>/priv]]></c> to your
- <c>CLASSPATH</c> variable to get
- basic Holder types and the communication classes.</p>
- </section>
-</chapter>
-
diff --git a/lib/ic/doc/src/erl-part.xml b/lib/ic/doc/src/erl-part.xml
deleted file mode 100644
index 9c9cb6a574..0000000000
--- a/lib/ic/doc/src/erl-part.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE part SYSTEM "part.dtd">
-
-<part>
- <header>
- <copyright>
- <year>2002</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>IDL to Erlang language Mapping</title>
- <prepared></prepared>
- <docno></docno>
- <date>2002-06-25</date>
- <rev>A</rev>
- </header>
- <description>
- <p>Tjosan Erlang</p>
- </description>
- <include file="ch_erl_plain"></include>
- <include file="ch_erl_genserv"></include>
-</part>
-
diff --git a/lib/ic/doc/src/ic.xml b/lib/ic/doc/src/ic.xml
deleted file mode 100644
index 98e8414a4e..0000000000
--- a/lib/ic/doc/src/ic.xml
+++ /dev/null
@@ -1,468 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1997</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>ic</title>
- <prepared></prepared>
- <docno></docno>
- <checked></checked>
- <date>2004-01-08</date>
- <rev>B</rev>
- </header>
- <module>ic</module>
- <modulesummary>The Erlang IDL Compiler</modulesummary>
- <description>
- <p>The ic module is an Erlang implementation of an OMG IDL
- compiler. Depending on the choice of back-end the code will map
- to Erlang, C, or Java. The compiler generates client stubs and
- server skeletons.</p>
- <p>Two kinds of files are generated for each scope: Ordinary code
- files and header files. The latter are used for defining record
- definitions, while the ordinary files contain the object
- interface functions.</p>
- </description>
- <funcs>
- <func>
- <name>ic:gen(FileName) -> Result</name>
- <name>ic:gen(FileName, [Option]) -> Result</name>
- <fsummary>Generate stub and server code according to the OMG CORBA standard.</fsummary>
- <type>
- <v>Result = ok | error | {ok, [Warning]} | {error, [Warning], [Error]}</v>
- <v></v>
- <v>Option = [ GeneralOption | CodeOption | WarningOption | BackendOption]</v>
- <v></v>
- <v>GeneralOption = </v>
- <v>{outdir, String()} | {cfgfile, String()} | {use_preproc, bool()} |</v>
- <v>{preproc_cmd, String()} | {preproc_flags, String()}</v>
- <v></v>
- <v>CodeOption =</v>
- <v>{gen_hrl, bool()} | {serv_last_call, exception | exit} | {{impl, String()}, String()} | {light_ifr, bool()}</v>
- <v>this | {this, String()} | {{this, String()}, bool()} |</v>
- <v>from | {from, String()} | {{from, String()}, bool()} |</v>
- <v>handle_info | {handle_info, String()} | {{handle_info, String()}, bool()} |</v>
- <v>timeout | {timeout, String()} | {{timeout, String()}, bool()} |</v>
- <v>{scoped_op_calls, bool()} | {scl, bool()} |</v>
- <v>{user_protocol, Prefix} |</v>
- <v>{c_timeout, {SendTimeout, RecvTimeout}} |</v>
- <v>{c_report, bool()} |</v>
- <v>{precond, {atom(), atom()}} | {{precond, String()} {atom(), atom()}} |</v>
- <v>{postcond, {atom(), atom()}} | {{postcond, String()} {atom(), atom()}}</v>
- <v></v>
- <v>WarningOption =</v>
- <v>{'Wall', bool()} | {maxerrs, int() | infinity} |</v>
- <v>{maxwarns, int() | infinity} | {nowarn, bool()} |</v>
- <v>{warn_name_shadow, bool()} | {pedantic, bool()} |</v>
- <v>{silent, bool()}</v>
- <v></v>
- <v>BackendOption = {be, Backend}</v>
- <v></v>
- <v>Backend = erl_corba | erl_template | erl_plain | erl_genserv | c_client | c_server | java</v>
- <v></v>
- <v>DirNAme = string() | atom()</v>
- <v>FileName = string() | atom()</v>
- </type>
- <desc>
- <p>The tuple <c>{Option, true}</c> can be replaced by
- <c>Option</c> for boolean values.</p>
- <p>The <c>ic:gen/2</c> function can be called from the command
- line as follows:</p>
- <p><c>erlc "+Option" ... File.idl</c></p>
- <p>Example:</p>
- <p><c>erlc "+{be,c_client}" '+{outdir, "../out"}' File.idl</c></p>
- </desc>
- </func>
- </funcs>
-
- <section>
- <title>General options</title>
- <taglist>
- <tag><em>outdir</em></tag>
- <item>
- <p>Places all output files in the directory given by the option.
- The directory will be created if it does not already exist.</p>
- <p>Example option: <c>{outdir, "output/generated"}</c>.</p>
- </item>
- <tag><em>cfgfile</em></tag>
- <item>
- <p>Uses <em>FileName</em> as configuration file. Options will
- override compiler defaults but can be overridden by command line
- options. Default value is <c>".ic_config"</c>.</p>
- <p>Example option: <c>{cfgfile, "special.cfg"}</c>.</p>
- </item>
- <tag><em>use_preproc</em></tag>
- <item>
- <p>Uses a preprocessor. Default value is true.</p>
- </item>
- <tag><em>preproc_cmd</em></tag>
- <item>
- <p>Command string to invoke the preprocessor. The actual
- command will be built as
- <c>preproc_cmd++preproc_flags++FileName</c></p>
- <p>Example option: <c>{preproc_cmd, "erl"})</c>.</p>
- <p>Example option: <c>{preproc_cmd, "gcc -x c++ -E"}</c>.</p>
- </item>
- <tag><em>preproc_flags</em></tag>
- <item>
- <p>Flags given to the preprocessor.</p>
- <p>Example option: <c>{preproc_flags, "-I../include"}</c>.</p>
- </item>
- </taglist>
- </section>
-
- <section>
- <title>Code options</title>
- <taglist>
- <tag><em>light_ifr</em></tag>
- <item>
- <p>Currently, the default setting is <c>false</c>. To be able to
- use this option Orber must be configured to use Light IFR (see
- Orber's User's Guide). When this options is used, the size of the
- generated files used to register the API in the IFR DB are minimized.</p>
- <p>Example option: <c>{light_ifr, true}</c>.</p>
- </item>
- <tag><em>gen_hrl</em></tag>
- <item>
- <p>Generate header files. Default is true.</p>
- </item>
- <tag><em>serv_last_call</em></tag>
- <item>
- <p>Makes the last <c>gen_server handle_call</c> either raise a
- CORBA exception or just exit plainly. Default is the exception.
- </p>
- </item>
- <tag><em>{{impl, IntfName}, ModName}</em></tag>
- <item>
- <p>Assumes that the interface with name <em>IntfName</em> is
- implemented by the module with name <em>ModName</em> and
- will generate calls to the <em>ModName</em> module in the
- server behavior. Note that the <em>IntfName</em> must be a
- fully scoped name as in <c>"M1::I1"</c>.</p>
- <p></p>
- </item>
- <tag><em>this</em></tag>
- <item>
- <p>Adds the object reference as the first parameter to the
- object implementation functions. This makes the
- implementation aware of its own object reference.
- <br></br>
-The option
- comes in three varieties: <c>this</c> which activates the
- parameter for all interfaces in the source file, <c>{this, IntfName}</c> which activates the parameter for a specified
- interface and <c>{{this, IntfName}, false}</c> which
- deactivates the parameter for a specified
- interface.</p>
- <p>Example option: <c>this)</c> activates the parameter for
- all interfaces.</p>
- <p>Example option: <c>{this, "M1::I1"}</c> activates the
- parameter for all functions of <c>M1::I1</c>.</p>
- <p>Example options: <c>[this, {{this, "M1::I2"}, false}]</c>
- activates the parameter for all interfaces except
- <c>M1::I2</c>.</p>
- </item>
- <tag><em>from</em></tag>
- <item>
- <p>Adds the invokers reference as the first parameter to the
- object implementation two-way functions. If both
- <c>from</c> and <c>this</c> options are used the invokers
- reference parameter will be passed as the second
- parameter. This makes it possible for the implementation to
- respond to a request and continue executing
- afterwards. Consult the <c>gen_server</c> and <c>Orber</c>
- documentation how this option may be used. <br></br>
-The option
- comes in three varieties: <c>from</c> which activates the
- parameter for all interfaces in the source file, <c>{from, IntfName}</c> which activates the parameter for a specified
- interface and <c>{{from, IntfName}, false}</c> which
- deactivates the parameter for a specified interface.</p>
- <p>Example option: <c>from)</c> activates the parameter for
- all interfaces.</p>
- <p>Example options: <c>[{from, "M1::I1"}]</c> activates the
- parameter for all functions of <c>M1::I1</c>.</p>
- <p>Example options: <c>[from, {{from, "M1::I2"}, false}]</c>
- activates the parameter for all interfaces except
- <c>M1::I2</c>.</p>
- </item>
- <tag><em>handle_info</em></tag>
- <item>
- <p>Makes the object server call a function <c>handle_info</c>
- in the object implementation module on all unexpected
- messages. Useful if the object implementation need to trap
- exits.</p>
- <p>Example option: <c>handle_info</c> will activates module
- implementation <c>handle_info</c> for all interfaces in the
- source file.</p>
- <p>Example option: <c>{{handle_info, "M1::I1"}, true}</c>
- will activates module implementation <c>handle_info</c> for
- the specified interface.</p>
- <p>Example options: <c>[handle_info, {{handle_info, "M1::I1"}, false}]</c> will generate the <c>handle_info</c>
- call for all interfaces except <c>M1::I1</c>.</p>
- </item>
- <tag><em>timeout</em></tag>
- <item>
- <p>Used to allow a server response time limit to be set by the user.
- This should be a string that represents the scope for the interface
- which should have an extra variable for wait time initialization.</p>
- <p>Example option: <c>{timeout,"M::I"})</c> produces server
- stub which will has an extra timeout parameter in the initialization
- function for that interface.</p>
- <p>Example option: <c>timeout</c> produces server
- stub which will has an extra timeout parameter in the initialization
- function for all interfaces in the source file.</p>
- <p>Example options: <c>[timeout, {{timeout,"M::I"}, false}]</c>
- produces server stub which will has an extra timeout
- parameter in the initialization function for all interfaces
- except <c>M1::I1</c>.</p>
- </item>
- <tag><em>scoped_op_calls</em></tag>
- <item>
- <p>Used to produce more refined request calls to server. When
- this option is set to true, the operation name which was
- mentioned in the call is scoped. This is essential to avoid
- name clashes when communicating with c-servers. This option
- is available for the c-client, c-server and the Erlang
- gen_server back ends. <c>All</c> of the parts generated by ic
- have to agree in the use of this option. Default is
- <c>false</c>. </p>
- <p>Example options:
- <c>[{be,c_genserv},{scoped_op_calls,true}])</c> produces
- client stubs which sends "scoped" requests to a gen_server
- or a c-server.</p>
- </item>
- <tag><em>user_protocol</em></tag>
- <item>
- <p>Used to define a own protocol different from the default
- Erlang distribution + gen_server protocol. Currently only
- valid for C back-ends. For further details see <seealso marker="ic_c_protocol">IC C protocol</seealso>.</p>
- <p>Example options:
- <c>[{be,c_client},{user_protocol, "my_special"}])</c> produces
- client stubs which use C protocol functions with the prefix
- "my_special".</p>
- </item>
- <tag><em>c_timeout</em></tag>
- <item>
- <p>Makes sends and receives to have timeouts (C back-ends only). These
- timeouts are specified in milliseconds. </p>
- <p>Example options:
- <c>[{be,c_client},{c_timeout, {10000, 20000}}])</c> produces
- client stubs which use a 10 seconds send timeout, and a
- 20 seconds receive timeout.</p>
- </item>
- <tag><em>c_report</em></tag>
- <item>
- <p>Generates code for writing encode/decode errors to <c>stderr</c> (C back-ends only).
- timeouts are specified in milliseconds. </p>
- <p>Example options:
- <c>[{be,c_client}, c_report])</c>.</p>
- </item>
- <tag><em>scl</em></tag>
- <item>
- <p>Used for compatibility with previous compiler versions up
- to <c>3.3</c>. Due to better semantic checks on enumerants,
- the compiler discovers name clashes between user defined
- types and enumerant values in the same name space. By
- enabling this option the compiler turns off the extended
- semantic check on enumerant values. Default is
- <c>false</c>. </p>
- <p>Example option: <c>{scl,true}</c></p>
- </item>
- <tag><em>precond</em></tag>
- <item>
- <p>Adds a precondition call before the call to the operation
- implementation on the server side.</p>
- <p>The option comes in three varieties: <c>{precond, {M, F}}</c> which activates the call for operations in all
- interfaces in the source file, <c>{{precond, IntfName}, {M, F}}</c> which activates the call for all operations in a
- specific interface and <c>{{precond, OpName}, {M, F}}</c>
- which activates the call for a specific operation.</p>
- <p>The precondition function has the following signature
- <c>m:f(Module, Function, Args)</c>.</p>
- <p>Example option: <c>{precond, {mod, fun}}</c> adds the call
- of m:f for all operations in the idl file.</p>
- <p>Example options: <c>[{{precond, "M1::I"}, {mod, fun}}]</c>
- adds the call of <c>m:f</c> for all operations in the
- interface <c>M1::I1</c>.</p>
- <p>Example options: <c>[{{precond, "M1::I::Op"}, {mod, fun}}]</c> adds the call of <c>m:f</c> for the operation
- <c>M1::I::Op</c>.</p>
- </item>
- <tag><em>postcond</em></tag>
- <item>
- <p>Adds a postcondition call after the call to the operation
- implementation on the server side. </p>
- <p>The option comes in three varieties: <c>{postcond, {M, F}}</c> which activates the call for operations in all
- interfaces in the source file, <c>{{postcond, IntfName}, {M, F}}</c> which activates the call for all operations in a
- specific interface and <c>{{postcond, OpName}, {M, F}}</c>
- which activates the call for a specific operation.</p>
- <p>The postcondition function has the following signature
- <c>m:f(Module, Function, Args, Result)</c>.</p>
- <p>Example option: <c>{postcond, {mod, fun}}</c> adds the call
- of m:f for all operations in the idl file.</p>
- <p>Example options: <c>[{{postcond, "M1::I"}, {mod, fun}}]</c>
- adds the call of <c>m:f</c> for all operations in the
- interface <c>M1::I1</c>.</p>
- <p>Example options: <c>[{{postcond, "M1::I::Op"}, {mod, fun}}]</c> adds the call of <c>m:f</c> for the operation
- <c>M1::I::Op</c>.</p>
- </item>
- </taglist>
- </section>
-
- <section>
- <title>Warning options</title>
- <taglist>
- <tag><em>'Wall'</em></tag>
- <item>
- <p>The option activates all reasonable warning messages in
- analogy with the gcc -Wall option. Default value is true.</p>
- </item>
- <tag><em>maxerrs</em></tag>
- <item>
- <p>The maximum numbers of errors that can be detected before
- the compiler gives up. The option can either have an integer
- value or the atom <c>infinity</c>. Default number is 10.</p>
- </item>
- <tag><em>maxwarns</em></tag>
- <item>
- <p>The maximum numbers of warnings that can be detected before
- the compiler gives up. The option can either have an integer
- value or the atom <c>infinity</c>. Default value is
- infinity.</p>
- </item>
- <tag><em>nowarn</em></tag>
- <item>
- <p>Suppresses all warnings. Default value is false.</p>
- </item>
- <tag><em>warn_name_shadow</em></tag>
- <item>
- <p>Warning appears whenever names are shadowed due to
- inheritance; for example, if a type name is redefined from a
- base interface. Note that it is illegal to overload
- operation and attribute names as this causes an error to be
- produced. Default value is true. </p>
- </item>
- <tag><em>pedantic</em></tag>
- <item>
- <p>Activates all warning options. Default value is false.</p>
- </item>
- <tag><em>silent</em></tag>
- <item>
- <p>Suppresses compiler printed output. Default value is false.</p>
- </item>
- </taglist>
- </section>
-
- <section>
- <title>Back-End options</title>
- <p>Which back-end IC will generate code for is determined by the supplied
- <c>{be,atom()}</c> option. If left out, <c>erl_corba</c> is used.
- Currently, IC support the following back-ends:</p>
- <taglist>
- <tag><em>erl_corba</em></tag>
- <item>
- <p>This option switches to the IDL generation for CORBA.</p>
- </item>
- <tag><em>erl_template</em></tag>
- <item>
- <p>Generate CORBA call-back module templates for each interface in the target
- IDL file. Note, will overwrite existing files.</p>
- </item>
- <tag><em>erl_plain</em></tag>
- <item>
- <p>Will produce plain Erlang modules which contain functions that
- map to the corresponding interface functions on the input file.</p>
- </item>
- <tag><em>erl_genserv</em></tag>
- <item>
- <p>This is an IDL to Erlang generic server generation option.</p>
- </item>
- <tag><em>c_client</em></tag>
- <item>
- <p>Will produce a C client to the generic Erlang server.</p>
- </item>
- <tag><em>c_server</em></tag>
- <item>
- <p>Will produce a C server switch with functionality of a
- generic Erlang server.</p>
- </item>
- <tag><em>java</em></tag>
- <item>
- <p>Will produce Java client stubs and server skeletons with
- functionality of a generic Erlang server.</p>
- </item>
- <tag><em>c_genserv</em></tag>
- <item>
- <p>Deprecated. Use <c>c_client</c> instead.</p>
- </item>
- </taglist>
- </section>
-
- <section>
- <title>Preprocessor</title>
- <p>The IDL compiler allows several preprocessors to be used, the
- <c>Erlang IDL preprocessor</c> or other standard <c>C</c> preprocessors.
- Options can be used to provide extra flags such as include
- directories to the preprocessor. The build in the Erlang IDL
- preprocessor is used by default, but any standard C preprocessor
- such as <c>gcc</c> is adequate.</p>
- <p>The preprocessor command is formed by appending the prepoc_cmd
- to the preproc_flags option and then appending the input IDL
- file name.</p>
- </section>
-
- <section>
- <title>Configuration</title>
- <p>The compiler can be configured in two ways:</p>
- <list type="ordered">
- <item>
- <p>Configuration file</p>
- </item>
- <item>
- <p>Command line options</p>
- </item>
- </list>
- <p>The configuration file is optional and overrides the compiler
- defaults and is in turn overridden by the command line options.
- The configuration file shall contain options in the form of
- Erlang terms. The configuration file is read using
- <c>file:consult</c>.</p>
- <p>An example of a configuration file, note the "." after each
- line.</p>
- <code type="none">
-{outdir, gen_dir}.
-{{impl, "M1::M2::object"}, "obj"}.
- </code>
- </section>
-
- <section>
- <title>Output files</title>
- <p>The compiler will produce output in several files depending on
- scope declarations found in the IDL file. At most
- three file types will be generated for each scope (including the top scope),
- depending on the compiler back-end and the compiled interface.
- Generally, the output per interface will be a header file (<c>.hrl</c>/
- <c>.h</c>) and one or more Erlang/C files (<c>.erl</c>/<c>.c</c>).
- Please look at the language mapping for each back-end for details.</p>
- <p>There will be at least one set of files for an IDL file, for the
- file level scope. Modules and interfaces also have their own set
- of generated files.</p>
- </section>
-
-</erlref>
-
diff --git a/lib/ic/doc/src/ic_c_protocol.xml b/lib/ic/doc/src/ic_c_protocol.xml
deleted file mode 100644
index ed4f21d661..0000000000
--- a/lib/ic/doc/src/ic_c_protocol.xml
+++ /dev/null
@@ -1,157 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE cref SYSTEM "cref.dtd">
-
-<cref>
- <header>
- <copyright>
- <year>2004</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>IC C Protocol Functions</title>
- <prepared></prepared>
- <docno></docno>
- <date>2004-04-06</date>
- <rev>A</rev>
- </header>
- <lib>ic_c_protocol</lib>
- <libsummary>IC C Protocol Functions</libsummary>
- <description>
- <p>This manual page lists some of the functions of the IC C runtime
- library that are used internally for the IC protocol.
- </p>
- <p>The listed functions are used internally by generated C client
- and server code. They are documented here for <em>the advanced user</em> that want to replace the default protocol (Erlang
- distribution + gen_server) by his own protocol, For each set of
- client or sever functions below with prefix <c>oe</c>, the user
- has to implement his own set of functions, the names of which
- are obtained by replacing the <c>oe</c> prefix by <c>Prefix</c>.
- The <c>Prefix</c> has to be set with the option
- <c>{user_protocol, Prefix}</c> at compile time.</p>
- <p>The following terminology is used (reflected in names of
- functions): a <em>notification</em> is a message send from
- client to server, without any reply back (i.e. a
- <em>oneway</em> operation); a <em>request</em> is a message sent
- from client to server, and where a <em>reply</em> message is
- sent back from the server to the client.</p>
- <p>In order to understand how the functions work and what they do
- the user <em>must</em> study their implementation in the IC C
- library (source file is <c>ic.c</c>), and also consider how they
- are used in the C code of ordinary generated client stubs or
- server skeletons.</p>
- <p></p>
- </description>
-
- <section>
- <title>Client Protocol Functions</title>
- <p>The following functions are used internally by generated C
- client code.</p>
- </section>
- <funcs>
- <func>
- <name><ret>int</ret><nametext>oe_prepare_notification_encoding(CORBA_Environment *env)</nametext></name>
- <fsummary>Prepare client notification encoding.</fsummary>
- <desc>
- <p>The result of this function is the beginning of a binary of
- in external format of the tuple <c>{'$gen_cast', X}</c> where
- <c>X</c> is not yet filled in. </p>
- <p>In generated client code this function is the first to be called
- in the encoding function for each oneway operation.</p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>oe_send_notification(CORBA_Environment *env)</nametext></name>
- <name><ret>int</ret><nametext>oe_send_notification_tmo(CORBA_Environment *env, unsigned int send_ms)</nametext></name>
- <fsummary>Send client notification.</fsummary>
- <desc>
- <p>Sends a client notification to a server according to the
- Erlang distribution + gen_server protocol.</p>
- <p>The <c>send_ms</c> parameter specified a timeout in milliseconds.</p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>oe_prepare_request_encoding(CORBA_Environment *env)</nametext></name>
- <fsummary>Prepare client request encoding.</fsummary>
- <desc>
- <p>The result of this function is the beginning of a binary in
- the external format of the tuple <c>{'$gen_call', {Pid, Ref}, X}</c> where <c>X</c> is not yet filled in.</p>
- <p>In generated client code this function is the first to be called
- in the encoding function for each twoway operation.</p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>oe_send_request_and_receive_reply(CORBA_Environment *env)</nametext></name>
- <name><ret>int</ret><nametext>oe_send_request_and_receive_reply_tmo(CORBA_Environment *env, unsigned int send_ms, unsigned int recv_ms)</nametext></name>
- <fsummary>Send client request and receive reply.</fsummary>
- <desc>
- <p>Sends a client request and receives the reply according to
- the Erlang distribution + gen_server protocol. This function
- calls the <c>oe_prepare_reply_decoding</c> function in order
- to obtain the gen_server reply.
- </p>
- <p><c>send_ms</c> and <c>recv_ms</c> specify timeouts for send
- and receive, respectively, in milliseconds.</p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>oe_prepare_reply_decoding(CORBA_Environment *env)</nametext></name>
- <fsummary>Prepare client decoding of reply.</fsummary>
- <desc>
- <p>Decodes the binary version of the tuple <c>{Ref, X}</c>,
- where <c>X</c> is to be decoded later by the specific client
- decoding function.</p>
- </desc>
- </func>
- </funcs>
-
- <section>
- <title>Server Protocol Functions</title>
- <p>The following functions are used internally by generated C
- server code.</p>
- </section>
- <funcs>
- <func>
- <name><ret>int</ret><nametext>oe_prepare_request_decoding(CORBA_Environment *env)</nametext></name>
- <fsummary>Prepare server decoding of request.</fsummary>
- <desc>
- <p>Decodes the binary version of the tuple <c>{'$gen_cast', Op}</c> (<c>Op</c> an atom), or the tuple <c>{'$gen_cast', {Op, X}}</c>, where <c>Op</c> is the operation name, and
- where <c>X</c> is to be decoded later by the specific
- operation decoding function; or</p>
- <p>decodes the binary version of the tuple <c>{'$gen_call', {Pid, Ref}, Op}</c> (<c>Op</c> an atom), or the tuple
- <c>{'$gen_call', {Pid, Ref}, {Op, X}}</c>, where <c>Op></c>
- is the operation name, and <c>X</c> is to be decode later by
- the specific operation decoding function.</p>
- </desc>
- </func>
- <func>
- <name><ret>int</ret><nametext>oe_prepare_reply_encoding(CORBA_Environment *env)</nametext></name>
- <fsummary>Prepare server encoding of reply.</fsummary>
- <desc>
- <p>Encodes the beginning of the binary version of the tuple
- <c>{{Ref,X}</c>, where <c>X</c> is to be filled in by the
- specific server encoding function.</p>
- </desc>
- </func>
- </funcs>
-
- <section>
- <title>SEE ALSO</title>
- <p>ic(3), ic_clib(3), <seealso marker="ch_ic_protocol">IC Protocol</seealso></p>
- </section>
-
-</cref>
-
diff --git a/lib/ic/doc/src/ic_clib.xml b/lib/ic/doc/src/ic_clib.xml
deleted file mode 100644
index 50b20d2ca8..0000000000
--- a/lib/ic/doc/src/ic_clib.xml
+++ /dev/null
@@ -1,247 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE cref SYSTEM "cref.dtd">
-
-<cref>
- <header>
- <copyright>
- <year>2003</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>IC C Library Functions</title>
- <prepared></prepared>
- <docno></docno>
- <date>2003-12-16</date>
- <rev>PB1</rev>
- </header>
- <lib>ic_clib</lib>
- <libsummary>IC C Library Functions</libsummary>
- <description>
- <p>This manual page lists some of the functions in the IC C runtime
- library. </p>
- </description>
-
- <section>
- <title>Allocation and Deallocation Functions</title>
- <p>The following functions are used for allocating and
- deallocating a <em>CORBA_Environment</em> structure.</p>
- </section>
- <funcs>
- <func>
- <name><ret>CORBA_Environment *</ret><nametext>CORBA_Environment_alloc(int inbufsz, int outbufsz)</nametext></name>
- <fsummary>Allocate environment data.</fsummary>
- <desc>
- <p>This function is used to allocate and initiate the
- <c>CORBA_Environment</c> structure. In particular, it is used
- to dynamically allocate a CORBA_Environment structure and set
- the default values for the structure's fields.</p>
- <p><em>inbufsize</em> is the initial size of the input
- buffer.</p>
- <p><em>outbufsize</em> is the initial size of the output
- buffer.</p>
- <p><em>CORBA_Environment</em> is the CORBA 2.0 state structure
- used by the generated stub.</p>
- <p>This function will set all needed default values and
- allocate buffers the lengths of which are equal to the
- values passed, but will not allocate space for the _to_pid
- and _from_pid fields.</p>
- <p>To free the space allocated by CORBA_Environment_alloc() do
- as follows.</p>
- <list type="bulleted">
- <item>
- <p>First call CORBA_free for the input and output buffers.</p>
- </item>
- <item>
- <p>After freeing the buffer space, call CORBA_free for the
- CORBA_Environment space.</p>
- </item>
- </list>
- </desc>
- </func>
- <func>
- <name><ret>void</ret><nametext>CORBA_free(void *p)</nametext></name>
- <fsummary>Free any allocated data.</fsummary>
- <desc>
- <p>Frees allocated space pointed to by <c>p</c>.</p>
- </desc>
- </func>
- <func>
- <name><ret>CORBA_char *</ret><nametext>CORBA_string_alloc(CORBA_unsigned_long len)</nametext></name>
- <fsummary>Allocate a string.</fsummary>
- <desc>
- <p>Allocates a (simple) CORBA character string of length <c>len + 1</c>.</p>
- </desc>
- </func>
- <func>
- <name><ret>CORBA_wchar *</ret><nametext>CORBA_wstring_alloc(CORBA_unsigned_long len)</nametext></name>
- <fsummary>Allocate a wide string.</fsummary>
- <desc>
- <p>Allocates a CORBA wide string of length <c>len + 1</c>.</p>
- </desc>
- </func>
- </funcs>
-
- <section>
- <title>Exception Functions</title>
- <p>Functions for retrieving exception ids and values, and for setting
- exceptions. </p>
- </section>
- <funcs>
- <func>
- <name><ret>CORBA_char *</ret><nametext>CORBA_exception_id(CORBA_Environment *env)</nametext></name>
- <fsummary>Get exception identity.</fsummary>
- <desc>
- <p>Returns the exception identity if an exception is set, otherwise
- it returns <c>NULL</c>.</p>
- </desc>
- </func>
- <func>
- <name><ret>void *</ret><nametext>CORBA_exception_value(CORBA_Environment *env)</nametext></name>
- <fsummary>Get exception value.</fsummary>
- <desc>
- <p>Returns the exception value, if an exception is set, otherwise
- it returns <c>NULL</c>.</p>
- </desc>
- </func>
- <func>
- <name><ret>void</ret><nametext>CORBA_exc_set(CORBA_Environment *env, CORBA_exception_type Major, CORBA_char *Id, CORBA_char *Value)</nametext></name>
- <fsummary>Set exception.</fsummary>
- <desc>
- <p>Sets the exception type, exception identity, and exception value
- in the environment pointed to by <c>env</c>.</p>
- </desc>
- </func>
- </funcs>
-
- <section>
- <title>Server Reception</title>
- <p>The following function is provided for convenience. </p>
- </section>
- <funcs>
- <func>
- <name><ret>int</ret><nametext>oe_server_receive(CORBA_Environment *env, oe_map_t *map)</nametext></name>
- <name><ret>int</ret><nametext>oe_server_receive_tmo(CORBA_Environment *env, oe_map_t *map, unsigned int send_ms, unsigned int recv_ms)</nametext></name>
- <fsummary>Server receive of notification or request, and sending of reply (in case of request).</fsummary>
- <desc>
- <p>Provides a loop that receives one message, executes the
- operation in question, and in case of a two-way operation
- sends a reply.</p>
- <p><c>send_ms</c> and <c>recv_ms</c> specify timeout values
- in milliseconds for send and receive, respectively.</p>
- </desc>
- </func>
- </funcs>
-
- <section>
- <title>Generic Execution Switch and Map Merging</title>
- <p>Function for searching for server operation function, and for
- calling it if found. Function for merging maps (see the include
- file <c>ic.h</c> for definitions). </p>
- </section>
- <funcs>
- <func>
- <name><ret>int</ret><nametext>oe_exec_switch(CORBA_Object obj, CORBA_Environment *env, oe_map_t *map)</nametext></name>
- <fsummary>Search for server operation and execute it.</fsummary>
- <desc>
- <p>Search for server operation and execute it.</p>
- </desc>
- </func>
- <func>
- <name><ret>oe_map_t *</ret><nametext>oe_merge_maps(oe_map_t *maps, int size)</nametext></name>
- <fsummary>Merge an array of server maps to one single map.</fsummary>
- <desc>
- <p>Merge an array of server maps to one single map.</p>
- </desc>
- </func>
- </funcs>
-
- <section>
- <title>The CORBA_Environment structure</title>
- <p>Here is the complete definition of the CORBA_Environment structure,
- defined in file <em>ic.h</em>: </p>
- <code type="none">
- /* Environment definition */
- typedef struct {
-
- /*----- CORBA compatibility part ------------------------*/
- /* Exception tag, initially set to CORBA_NO_EXCEPTION ---*/
- CORBA_exception_type _major;
-
- /*----- External Implementation part - initiated by the user ---*/
- /* File descriptor */
- int _fd;
- /* Size of input buffer */
- int _inbufsz;
- /* Pointer to always dynamically allocated buffer for input */
- char *_inbuf;
- /* Size of output buffer */
- int _outbufsz;
- /* Pointer to always dynamically allocated buffer for output */
- char *_outbuf;
- /* Size of memory chunks in bytes, used for increasing the output
- buffer, set to >= 32, should be around >= 1024 for performance
- reasons */
- int _memchunk;
- /* Pointer for registered name */
- char _regname[256];
- /* Process identity for caller */
- erlang_pid *_to_pid;
- /* Process identity for callee */
- erlang_pid *_from_pid;
-
- /*- Internal Implementation part - used by the server/client ---*/
- /* Index for input buffer */
- int _iin;
- /* Index for output buffer */
- int _iout;
- /* Pointer for operation name */
- char _operation[256];
- /* Used to count parameters */
- int _received;
- /* Used to identify the caller */
- erlang_pid _caller;
- /* Used to identify the call */
- erlang_ref _unique;
- /* Exception id field */
- CORBA_char *_exc_id;
- /* Exception value field */
- void *_exc_value;
-
-
- } CORBA_Environment;
- </code>
- <note>
- <p>Always set the field values <em>_fd</em>, <em>_regname</em>,
- <em>_to_pid</em> and/or <em>*_from_pid</em> to appropriate
- application values. These are not automatically set by the
- stubs.</p>
- </note>
- <warning>
- <p>Never assign static buffers to the buffer pointers, and never
- set the <em>_memchunk</em> field to a value less than
- <em>32</em>.</p>
- </warning>
- </section>
-
- <section>
- <title>SEE ALSO</title>
- <p>ic(3), ic_c_protocol(3)
- </p>
- </section>
-
-</cref>
-
diff --git a/lib/ic/doc/src/java-part.xml b/lib/ic/doc/src/java-part.xml
deleted file mode 100644
index 14b58a1df5..0000000000
--- a/lib/ic/doc/src/java-part.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE part SYSTEM "part.dtd">
-
-<part>
- <header>
- <copyright>
- <year>2002</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>IDL to Java language Mapping</title>
- <prepared></prepared>
- <docno></docno>
- <date>2002-06-25</date>
- <rev>A</rev>
- </header>
- <description>
- <p></p>
- </description>
- <include file="ch_java"></include>
-</part>
-
diff --git a/lib/ic/doc/src/notes.xml b/lib/ic/doc/src/notes.xml
deleted file mode 100644
index fc68ec386c..0000000000
--- a/lib/ic/doc/src/notes.xml
+++ /dev/null
@@ -1,791 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1998</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>IDL Compiler Release Notes</title>
- <prepared></prepared>
- <docno></docno>
- <checked></checked>
- <date>2004-04-06</date>
- <rev>AC</rev>
- <file>notes.xml</file>
- </header>
-
- <section><title>IC 4.4.3</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> Removed all old unused files in the documentation.
- </p>
- <p>
- Own Id: OTP-14475 Aux Id: ERL-409, PR-1493 </p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>IC 4.4.2</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> Correct bugs when path to mib or idl spec files
- contains UTF-8 characters. </p>
- <p>
- Own Id: OTP-13718 Aux Id: ERL-179 </p>
- </item>
- <item>
- <p>
- Update build scripts to not make assumtions about where
- env, cp and perl are located.</p>
- <p>
- Own Id: OTP-13800</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>IC 4.4.1</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Internal changes</p>
- <p>
- Own Id: OTP-13551</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>IC 4.4</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Change license text from Erlang Public License to Apache
- Public License v2</p>
- <p>
- Own Id: OTP-12845</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>IC 4.3.6</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Fix compiler warnings reported by LLVM</p>
- <p>
- Own Id: OTP-12138</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>IC 4.3.5</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> Added Latin-1 code directive in the generated files
- to keep old behaviour. Updated IC so it can handle
- Unicode characters in the path. </p>
- <p>
- Own Id: OTP-11783</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>IC 4.3.4</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Fix two small silent rules omissions. Thanks to Anthony
- Ramine.</p>
- <p>
- Own Id: OTP-11351</p>
- </item>
- <item>
- <p>
- Silence warnings (Thanks to Anthony Ramine)</p>
- <p>
- Own Id: OTP-11517</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>IC 4.3.3</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Header and library files from ic and erl_interface are
- now installed into usr/{include,lib}. Note that these
- directories are unversioned, so the latest installed
- version will be the one in the directory.</p>
- <p>
- Own Id: OTP-11284</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>IC 4.3.2</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Fixed some compilation warnings on miscellaneous
- platforms. Thanks to Anthony Ramine.</p>
- <p>
- Own Id: OTP-11086</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>IC 4.3.1</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Revert the structs <c>erlang_pid</c>, <c>erlang_port</c>
- and <c>erlang_ref</c> as they were before R16A (without
- <c>node_org_enc</c>) in order to be backward compatible
- with user code that accesses the fields of these structs.</p>
- <p>
- Own Id: OTP-10885 Aux Id: seq12256 </p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>IC 4.3</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Misc build updates</p>
- <p>
- Own Id: OTP-10784</p>
- </item>
- <item>
- <p>
- Adapt ic for changes in erl_interface and jinterface due
- to utf8 atom support. This change makes ic dependent on
- erl_interface-3.7.10 (R16) or later in order to build.</p>
- <p>
- Own Id: OTP-10785</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>IC 4.2.31</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Fix bug where the ic pre-processor would ignore
- whitespace quoting.</p>
- <p>
- Own Id: OTP-10109</p>
- </item>
- <item>
- <p> A bug regarding spaces in C function prototypes has
- been fixed. (Thanks to Richard O'Keefe.) </p>
- <p>
- Own Id: OTP-10138</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>IC 4.2.30</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Add generation of Erlang callback functions to generated
- Erlang source code to avoid compiler warnings.</p>
- <p>
- Own Id: OTP-9998</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>IC 4.2.29</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>Erlang/OTP can now be built using parallel make if you
- limit the number of jobs, for instance using '<c>make
- -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not
- work at the moment because of some missing
- dependencies.</p>
- <p>
- Own Id: OTP-9451</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section>
- <title>IC 4.2.28</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>
- Incorrect use of ets:match changed to ets:match_object.</p>
- <p>
- Own Id: OTP-9630 </p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>IC 4.2.27</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- Reduced compile overhead (Thanks to Haitao Li).</p>
- <p>
- Own Id: OTP-9460 </p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>IC 4.2.26</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- Partial support for recursive structs and unions. Only available
- for the erl_corba backend and requires that Light IFR is used.
- I.e. the IC option {light_ifr, true} and that Orber is configured
- in such a way that Light IFR is activated. Recursive TypeCode is
- currently not supported.</p>
- <p>
- Own Id: OTP-8868 Aux Id: seq11633</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>IC 4.2.25</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- The documentation can now be built and installed without Java.</p>
- <p>
- Own Id: OTP-8639 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>IC 4.2.24</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>Removed superfluous VT in the documentation.</p>
- <p>Own id: OTP-8353 Aux Id:</p>
- </item>
- <item>
- <p>The option c_timeout was not correctly documented.</p>
- <p>Own id: OTP-8307 Aux Id: seq11390</p>
- </item>
- <item>
- <p>Removed superfluous backslash in the documentation.</p>
- <p>Own id: OTP-8354 Aux Id:</p>
- </item>
- <item>
- <p>The documentation EIX file was not generated.</p>
- <p>Own id: OTP-8355 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>IC 4.2.23</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- The documentation is now built with open source tools (xsltproc and fop)
- that exists on most platforms. One visible change is that the frames are removed.</p>
- <p>
- Own Id: OTP-8201 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>IC 4.2.22</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>The 64-bit version of libic was not compiled with the -fPIC flag.</p>
- <p>Own id: OTP-8088</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>IC 4.2.21</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>The function print_erlang_binary (oe_ei_code_erlang_binary.c)
- updated to avoid compiler warning.</p>
- <p>Own id: OTP-7982</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>IC 4.2.20</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Updated file headers.</p>
- <p>Own id: OTP-7837</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>IC 4.2.19</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Documentation source included in open source releases.</p>
- <p>Own id: OTP-7595</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>IC 4.2.18</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>Insufficient buffer allocated when passing wide strings
- using the C backend on a 64-bit architecture.</p>
- <p>Own Id: OTP-7313 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>IC 4.2.17</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Updated file headers.</p>
- <p>Own id: OTP-7011</p>
- </item>
- <item>
- <p>IC no longer use the obsolete function file:rawopen/2.</p>
- <p>Own id: OTP-7182</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>IC 4.2.16</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Added links to classes inherited from Jinterface in the
- User's Guide.</p>
- <p>Own Id: OTP-6965 Aux Id: </p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>IC 4.2.15</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>If an inherited function name begun with a capital letter
- the generated stub/skeleton oe_tc/1 function was incorrect.</p>
- <p>Own Id: OTP-6855 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>IC 4.2.14</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>The documentation source has been converted from SGML to XML.</p>
- <p>Own Id: OTP-6754 Aux Id: </p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>IC 4.2.13</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Minor Makefile changes.</p>
- <p>Own Id: OTP-6701 Aux Id: </p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>IC 4.2.12</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Dead code was deleted from the following modules:
- ic_cclient, ic_code, ic_cserver, ic_erlbe, ic_java_type,
- ic_noc, ic_plainbe, ic_pp, ic_pragma, icscan, icstruct,
- ictype, icunion.</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>IC 4.2.11</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Changed code generation to avoid warnings such as unused
- variables.</p>
- <p>Own Id: OTP-5930 Aux Id: </p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>IC 4.2.10</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>The FD_SETSIZE limit has been increased to 2048 for
- VxWorks/PPC603.</p>
- <p>Own Id: OTP-5395 Aux Id: seq9751</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>IC 4.2.9</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>In C back-ends, the compiler crashed when generating C code
- for error reports when a scoped name was used as a type
- in a union.</p>
- <p>Own Id: OTP-5375 Aux Id: seq9740 </p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>IC 4.2.8</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>In C back-ends, when decoding a sequence of "small"
- integers, which from Erlang is sent as a string (i.e.
- each element between 0 and 255), each string element was
- considered to be of signed character type. Each such
- element is now correctly treated as an unsigned character
- type.</p>
- <p>Own Id: OTP-5205 Aux Id: seq9241 </p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>IC 4.2.7</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>A new compiler option <c>c_report</c> has been introduced
- for C back-ends (client and server). If that option is
- set, encoding/decoding errors will be reported to
- <c>stderr</c>.</p>
- <p>Own Id: OTP-4977</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>IC 4.2.6</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>The size of modules, used then registering data in the
- IFR DB (e.g., oe_MyModule:oe_register()), can be minimized
- if the compile option light_ifr is used and Orber is
- configured to use Light IFR. Requires that orber-3.5.1, or
- later, is used.</p>
- <p>Own Id: OTP-5036</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <list type="bulleted">
- <item>
- <p>The compile option <c>multiple_be</c> is no longer supported.</p>
- <p>Own Id: OTP-5049</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>IC 4.2.5</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Send and receive functions with timeouts have been added
- to the C back-ends for the standard protocol (i.e. Erlang
- distribution + gen_server protocol).</p>
- <p>Accordingly a new compiler option <c>{c_timeout, {SendTimeout, RecvTimeout}}</c> has been added. Timeouts
- are specified in milliseconds.</p>
- <p>A user that want to implement its own protocols with
- function timeouts has to implement the following functions.</p>
- <p>For C clients the functions <c>int PFX_send_notification(CORBA_Environment *env, unsigned int send_ms)</c>, and <c>int PFX_send_request_and_receive_reply(CORBA_Environment *env, unsigned int send_ms, unsigned int recv_ms)</c>
- have to be additionally implemented, where PFX is the
- user defined prefix.</p>
- <p>For C servers no additional functions have to be
- implemented, but a clone of the <c>int oe_server_receive_tmo(CORBA_Environment *env, oe_map_t *map, unsigned int send_ms, unsigned int recv_ms)</c>
- might be handy.</p>
- <p>Own Id: OTP-4972</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>IC 4.2.4</title>
-
- <section>
- <title>Improvements and new features</title>
- <list type="bulleted">
- <item>
- <p>The C back-ends has been opened up, so that a user can
- define his own protocol, differing from the Erlang
- distribution + gen_server protocol. <br></br>
-
- For C clients it means to replace the library functions
- <c>int oe_prepare_notification_encoding(CORBA_Environment *env)</c>, <c>int oe_send_notification(CORBA_Environment *env)</c>, <c>int oe_prepare_request_encoding(CORBA_Environment *env)</c>,
- <c>int oe_send_request_and_receive_reply(CORBA_Environment *env)</c>, and <c>int oe_prepare_reply_decoding(CORBA_Environment *env)</c>,
- with functions of the same signature, but with the prefix
- "oe" replaced by a user defined prefix.
- For C servers the functions <c>int oe_prepare_request_decoding(CORBA_Environment *env)</c>,
- and <c>int oe_prepare_reply_encoding(CORBA_Environment *env)</c>, are similarly replaced. <br></br>
-
- The new compiler option <c>{user_protocol, Prefix}</c> has
- been added.</p>
- <p>Own Id: OTP-4834</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>IC 4.2.3</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>In generated code for the C server back-end, the naming scope
- was in error for prototypes in C header files for interfaces
- inheriting base interfaces.</p>
- <p>Own Id: OTP-4881</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>IC 4.2.2</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>IDL long long and unsigned long long could not
- be used in a struct for the Java backend.</p>
- <p>All unsigned integer types for the Java backend
- had broken marshalling for large values.</p>
- <p>Own Id: OTP-4763</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>IC 4.2.1</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>A scoping problem (IC could not find typedefs contained
- inherited interfaces) in the C-backend solved.</p>
- <p>Own Id: OTP-4758</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>IC 4.2</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>The CORBA stub/skeleton-files generated by IC have been improved,
- i.e., depending on the IDL-files, reduced the size of the
- erl- and beam-files and decreased dependencies off Orber's
- Interface Repository. It is necessary to re-compile all IDL-files
- and use COS-applications, including Orber, compiled with
- IC-4.2.</p>
- <p>Own Id: OTP-4576</p>
- </item>
- </list>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/ic/doc/src/part.xml b/lib/ic/doc/src/part.xml
deleted file mode 100644
index 0bb7858745..0000000000
--- a/lib/ic/doc/src/part.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE part SYSTEM "part.dtd">
-
-<part xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>1998</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>IC User's Guide</title>
- <prepared></prepared>
- <docno></docno>
- <date>1998-08-07</date>
- <rev>2.1</rev>
- </header>
- <description>
- <p>The <em>IC</em> application is an Erlang implementation of an IDL
- compiler.</p>
- </description>
- <xi:include href="ch_introduction.xml"/>
- <xi:include href="ch_basic_idl.xml"/>
- <xi:include href="ch_ic_protocol.xml"/>
- <xi:include href="ch_erl_plain.xml"/>
- <xi:include href="ch_erl_genserv.xml"/>
- <xi:include href="ch_c_mapping.xml"/>
- <xi:include href="ch_c_client.xml"/>
- <xi:include href="ch_c_server.xml"/>
- <xi:include href="ch_c_corba_env.xml"/>
- <xi:include href="ch_java.xml"/>
-</part>
-
diff --git a/lib/ic/doc/src/ref_man.xml b/lib/ic/doc/src/ref_man.xml
deleted file mode 100644
index a6a4f187b3..0000000000
--- a/lib/ic/doc/src/ref_man.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE application SYSTEM "application.dtd">
-
-<application xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>1998</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>IC Reference Manual</title>
- <prepared></prepared>
- <docno></docno>
- <date>2003-12-16</date>
- <rev>PB1</rev>
- </header>
- <description>
- <p>The <em>IC</em> application is an Erlang implementation of an IDL
- compiler.</p>
- </description>
- <xi:include href="ic.xml"/>
- <xi:include href="ic_clib.xml"/>
- <xi:include href="ic_c_protocol.xml"/>
-</application>
-
diff --git a/lib/ic/ebin/.gitignore b/lib/ic/ebin/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/ic/ebin/.gitignore
+++ /dev/null
diff --git a/lib/ic/examples/all-against-all/Makefile b/lib/ic/examples/all-against-all/Makefile
deleted file mode 100644
index e772cab94e..0000000000
--- a/lib/ic/examples/all-against-all/Makefile
+++ /dev/null
@@ -1,118 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1999-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-# Point this at your version of OTP
-OTPROOT=/usr/local/otp/releases/otp_beam_sunos5_r7a
-
-# Type actual IC Version
-ICVSN=4.0.4
-
-# Type actual Erl Interface Vesrion
-EIVSN=3.2.2
-
-# Type actual Erl Interface Vesrion
-JIVSN=1.2
-
-# IDL file(s)
-IDLS=random.idl
-
-# Own C-server files
-CSRV=server callbacks
-
-# Own C-client files
-CCL=client
-
-# Generated C-server files
-GCSRVS=rmod_random__s
-
-# Generated C-server files
-GCCLS=rmod_random
-
-# Includes
-IFLAGS=-I$(OTPROOT)/lib/ic-$(ICVSN)/include \
- -I$(OTPROOT)/lib/erl_interface-$(EIVSN)/include
-
-LDFLAGS=-L$(OTPROOT)/lib/ic-$(ICVSN)/priv/lib \
- -L$(OTPROOT)/lib/erl_interface-$(EIVSN)/lib
-
-LDLIBS=-lic -lerl_interface -lei -lnsl -lsocket
-
-
-# Erlang compiler
-ERLC=$(OTPROOT)/bin/erlc
-
-# Erlang compiler flags.
-EFLAGS='+{scoped_op_calls,true}'
-
-# C compiler
-CC=gcc
-
-# C compiler flags
-CFLAGS=-ggdb -O2 -Wall $(IFLAGS)
-
-# Java compiler
-JAVAC=javac
-
-CLASSPATH= "./:$(OTPROOT)/lib/ic-$(ICVSN)/priv/ic.jar:$(OTPROOT)/lib/jinterface-$(JIVSN)/priv/OtpErlang.jar"
-JFLAGS=-classpath $(CLASSPATH) -O
-
-JGENJFILES = \
- ./rmod/_randomImplBase.java \
- ./rmod/random.java \
- ./rmod/randomHolder.java \
- ./rmod/_randomStub.java \
- ./rmod/randomHelper.java
-
-
-all: server client eall jall
-
-
-server:
- $(ERLC) $(EFLAGS) '+{be,c_server}' $(IDLS)
- $(CC) $(IFLAGS) -c $(CSRV:=.c) $(GCSRVS:=.c)
- $(CC) $(CSRV:=.o) $(GCSRVS:=.o) -o $@ $(LDFLAGS) $(LDLIBS)
-
-client:
- $(ERLC) $(EFLAGS) '+{be,c_client}' $(IDLS)
- $(CC) $(IFLAGS) -c $(CCL:=.c) $(GCCLS:=.c)
- $(CC) $(CCL:=.o) $(GCCLS:=.o) -o $@ $(LDFLAGS) $(LDLIBS)
-
-eall:
- $(ERLC) $(EFLAGS) '+{be,erl_genserv}' $(IDLS)
- $(ERLC) *.erl
-
-jall:
- $(ERLC) $(EFLAGS) '+{be,java}' $(IDLS)
- $(JAVAC) $(JFLAGS) */*.java *.java
-
-
-clean:
- /bin/rm -rf $(GCCLS:=.o) $(GCCLS:=.c) $(GCSRVS:=.o) $(GCSRVS:=.c) $(CCL:=.o) $(CSRV:=.o) rmod.erl rmod_random.erl *.jam *.beam oe* *.h *.hrl *~ core server client *.class
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/ic/examples/all-against-all/Makefile.win32 b/lib/ic/examples/all-against-all/Makefile.win32
deleted file mode 100644
index a8e480fd1f..0000000000
--- a/lib/ic/examples/all-against-all/Makefile.win32
+++ /dev/null
@@ -1,139 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2000-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-# Point this at your version of OTP
-OTPROOT=c:\Progra~1\erl5.0.1\
-
-# Type actual IC Version
-ICVSN=4.0.4
-
-# Type actual Erl Interface Vesrion
-EIVSN=3.2.2
-
-# Type actual Erl Interface Vesrion
-JIVSN=1.2
-
-# IDL file(s)
-IDLS=random.idl
-
-# Own C-server files
-CSRV=server.c callbacks.c
-CSRVO=server.obj callbacks.obj
-
-# Own C-client files
-CCL=client.c
-CCLO=client.obj
-
-# Generated C-server files
-GCSRVS=rmod_random__s.c
-GCSRVSO=rmod_random__s.obj
-
-# Generated C-client files
-GCCLS=rmod_random.c
-GCCLSO=rmod_random.obj
-
-# Includes
-IFLAGS=-I"$(OTPROOT)\lib\ic-$(ICVSN)\include" \
- -I"$(OTPROOT)\lib\erl_interface-$(EIVSN)\include"
-
-LDFLAGS=/LIBPATH:"$(OTPROOT)\lib\ic-$(ICVSN)\priv\lib" \
- /LIBPATH:"$(OTPROOT)\lib\erl_interface-$(EIVSN)\lib"
-
-LDLIBS=ic.lib erl_interface.lib ei.lib ws2_32.lib
-
-
-# Erlang compiler
-ERLC=$(OTPROOT)\bin\erlc
-
-# Erlang compiler flags.
-EFLAGS="+{scoped_op_calls,true}"
-
-
-# C compiler
-CC=cl
-
-# C compiler flags
-CFLAGS=-MT -D__WIN32__ $(IFLAGS)
-
-
-# Java compiler
-JAVAC=c:\Progra~1\jdk1.3\bin\javac
-
-# Java
-JAVA=c:\Progra~1\jdk1.3\bin\java
-
-
-# Java compiler flags
-CLASSPATH= ".;$(OTPROOT)\lib\ic-$(ICVSN)\priv\ic.jar;$(OTPROOT)\lib\jinterface-$(JIVSN)\priv\OtpErlang.jar"
-JFLAGS=-classpath $(CLASSPATH) -O
-
-
-all: server.exe client.exe client.beam client.class
-
-
-server.exe:
- $(ERLC) $(EFLAGS) "+{be,c_server}" $(IDLS)
- $(CC) -c $(CFLAGS) $(CSRV) $(GCSRVS)
- $(CC) -o server.exe $(CSRVO) $(GCSRVSO) -link $(LDFLAGS) $(LDLIBS)
-
-
-client.exe:
- $(ERLC) $(EFLAGS) "+{be,c_client}" $(IDLS)
- $(CC) -c $(CFLAGS) $(CCL) $(GCCLS)
- $(CC) -o client.exe $(CCLO) $(GCCLSO) -link $(LDFLAGS) $(LDLIBS)
-
-client.beam:
- $(ERLC) $(EFLAGS) "+{be,erl_genserv}" $(IDLS)
- $(ERLC) *.erl
-
-client.class:
- $(ERLC) $(EFLAGS) "+{be,java}" $(IDLS)
- $(JAVAC) $(JFLAGS) rmod/*.java
- $(JAVAC) $(JFLAGS) *.java
-
-jclient.run:
- $(JAVA) -classpath $(CLASSPATH) client
-
-jserver.run:
- $(JAVA) -classpath $(CLASSPATH) server
-
-
-clean:
- -@del /f /q rmod
- -@rmdir rmod
- -@del *.jam
- -@del *.beam
- -@del oe*
- -@del *.h
- -@del *.hrl
- -@del server.exe
- -@del client.exe
- -@del *.obj
- -@del rmod_random*.c
- -@del *~
- -@del *class
- -@del rmod.erl
- -@del rmod_random.erl
-
-
-
-
-
-
diff --git a/lib/ic/examples/all-against-all/ReadMe b/lib/ic/examples/all-against-all/ReadMe
deleted file mode 100644
index 7503291344..0000000000
--- a/lib/ic/examples/all-against-all/ReadMe
+++ /dev/null
@@ -1,122 +0,0 @@
-This is a short description on the use of Erlang,C or Java
-client and servers against each other.
-The base is a client that initiates and uses a random number
-generator that lies on an server.
-
-There are two make files, one for Unix and one for Windows,
-the Unix make file is just named "Makefile", while the Windows
-is named "Makefile.win32".
-
-Instructions.
-
-1) On Makefile :
- * Modify the OTPROOT variable on the Makefile to point
- to the root for your erlang instalation.
- * Modify IC and Erl_Interface versions to agree your
- OTP version.
-
-2) Type "make" to build the example.
-
-
-3) Start the empd deamon by using the command :
-
- epmd -daemon
-
-
-4) Do this when you want to run :
-
- * an Erlang server.
-
- Start erlang with the options
-
- -setcookie <Some Cookie> -sname <SomeNodeName>
-
- In this example you should use :
-
- erl -setcookie flash -sname babbis
-
- * a C server.
-
- Just type :
-
- server
-
- * a Java server.
-
- Set and export the CLASSPATH variable to
- point to the java classes located in java development kit,
- the Otp's classes and the current directory.
- Your classpath should look like this :
-
- .:<OTPROOT>/lib/ic-3.8.1/priv/ic.jar:<OTPROOT>/lib/jinterface_0.9.2/priv/OtpErlang.jar
-
- where :
-
- <OTPROOT> is the location there OTP is installed
-
- Then type :
-
- java server
-
-
-5) Do this when you want to run :
-
- * an Erlang client.
-
- ** If you have no valid named erlang node,
- start erlang with the options
-
- -setcookie <Some Cookie> -sname <SomeNodeName>
-
- In this example you should use :
-
- erl -setcookie flash -sname client
-
- On the erlang shell, type
-
- client:start().
-
- ** If you have a valid named erlang node, started
- whith the same "cookie", on the erlang shell, type
-
- client:start().
-
-
- * a C client, just type
-
- client
-
-
- * a Java client.
-
-
- Set and export the CLASSPATH variable to
- point to the java classes located in java development kit,
- the Otp's classes and the current directory.
- Your classpath should look like this :
-
- .:<OTPROOT>/lib/ic-4.0/priv/ic.jar:<OTPROOT>/lib/jinterface_1.1/priv/OtpErlang.jar
-
- where :
-
- <OTPROOT> is the location there OTP is installed
-
- Then type :
-
- java client
-
-
-
-6) Please note that :
-
- * you must always have the same cookie in order to eastablish connection
- between clients and servers.
-
- * you cannot start two servers with the same name.
- In this example all servers share the same name in order to test
- several constallations. Kill a server before starting another one.
-
-
-
-
-
diff --git a/lib/ic/examples/all-against-all/callbacks.c b/lib/ic/examples/all-against-all/callbacks.c
deleted file mode 100644
index 4e6edeb5e0..0000000000
--- a/lib/ic/examples/all-against-all/callbacks.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-
-#include <stdlib.h>
-#include "rmod_random__s.h"
-
-
-rmod_random_produce__rs*
-rmod_random_produce__cb(rmod_random oe_obj, double *rs, CORBA_Environment *oe_env)
-
-{
- *rs = (double) rand();
-
- return (rmod_random_produce__rs*) NULL;
-}
-
-
-rmod_random_init__rs*
-rmod_random_init__cb(rmod_random oe_obj, long* seed1, long* seed2, long* seed3, CORBA_Environment *oe_env)
-
-{
- srand(*seed1 * *seed2 * *seed3);
-
- return (rmod_random_init__rs*) NULL;
-}
-
-
-
diff --git a/lib/ic/examples/all-against-all/client.c b/lib/ic/examples/all-against-all/client.c
deleted file mode 100644
index 4f2f7e3eff..0000000000
--- a/lib/ic/examples/all-against-all/client.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-
-/* Just include the interface function */
-#include "rmod_random.h"
-
-
-/* Assign your own node name here */
-#define CLNODENAME "c50"
-#define SNODENAME "babbis"
-#define SREGNAME "rmod_random_impl"
-#define COOKIE "flash"
-#define INBUFSZ 1024
-#define OUTBUFSZ 1024
-#define HOSTNAMESZ 256
-
-
-
-/* Stopping node */
-void client_exit(CORBA_Environment *env) {
-
- /* Free env & buffers */
- CORBA_free(env->_inbuf);
- CORBA_free(env->_outbuf);
- CORBA_free(env);
-
- erl_close_connection(env->_fd);
- exit(1);
-}
-
-
-int main(){
-
- double result=0;
- int i=0;
- int error = 0;
- erlang_pid pid;
- char host[HOSTNAMESZ];
- char server_node[HOSTNAMESZ];
- char client_node[HOSTNAMESZ];
- CORBA_Environment *env;
-
- /* Initiate names */
-#ifdef __WIN32__
- WORD wVersionRequested;
- WSADATA wsaData;
-
- wVersionRequested = MAKEWORD(1, 1);
- if ((error = WSAStartup(wVersionRequested, &wsaData))) {
- fprintf(stderr,"Can't initialize windows sockets: %d",error);
- return 0;
- }
-#endif
- error = gethostname(host,HOSTNAMESZ);
- if (error) {
-#ifdef __WIN32__
- fprintf(stderr,"can't find own hostname (error = %ld) !\n",WSAGetLastError());
-#else /* not __WIN32__ */
- fprintf(stderr,"can't find own hostname !\n");
-#endif
- }
- sprintf(client_node,"%s@%s",CLNODENAME,host);
- sprintf(server_node,"%s@%s",SNODENAME,host);
-
- /* Create and init CORBA_Environment */
- env = CORBA_Environment_alloc(INBUFSZ,OUTBUFSZ);
-
- /* Initiating the connection */
- erl_init(NULL,0);
- erl_connect_init(50,COOKIE,0);
-
- /* Initiating pid*/
- strcpy(pid.node,client_node);
- pid.num = 99;
- pid.serial = 0;
- pid.creation = 0;
-
- /* Fixing environment variable */
- env->_fd=erl_connect(server_node);
- strcpy(env->_regname,SREGNAME);
- env->_to_pid = NULL;
- env->_from_pid = &pid;
-
- if (env->_fd < 0) {
- fprintf(stderr,"Error : Cannot connect to Server\n");
-
- /* Free env & buffers */
- CORBA_free(env->_inbuf);
- CORBA_free(env->_outbuf);
- CORBA_free(env);
- exit(1);
- }
-
- /* Calling the init function */
- rmod_random_init(NULL, 1, 2, 3, env);
-
- switch(env->_major) {
- case CORBA_NO_EXCEPTION: /* Success */
- printf("Init complete !\n");
- break;
- case CORBA_SYSTEM_EXCEPTION: /* System exception */
- printf("Init call failure, reason : %s\n",(char *) CORBA_exception_value(env));
- CORBA_exception_free(env);
- client_exit(env);
- default: /* Should not come here */
- client_exit(env);
- }
-
- /* Calling the produce function */
- for(i=1; i<=10; i++) {
- result = rmod_random_produce(NULL, env);
-
- switch(env->_major) {
- case CORBA_NO_EXCEPTION: /* Success */
- break;
- case CORBA_SYSTEM_EXCEPTION: /* System exception */
- printf("Init call failure, reason : %s\n",(char *) CORBA_exception_value(env));
- CORBA_exception_free(env);
- client_exit(env);
- default: /* Should not come here */
- client_exit(env);
- }
-
- printf("the random number nr%d is %f\n",i,result);
- }
-
- /* Closing the connection */
- erl_close_connection(env->_fd);
-
- /* Free env & buffers */
- CORBA_free(env->_inbuf);
- CORBA_free(env->_outbuf);
- CORBA_free(env);
-
- return 0;
-}
diff --git a/lib/ic/examples/all-against-all/client.erl b/lib/ic/examples/all-against-all/client.erl
deleted file mode 100644
index 3c147037a0..0000000000
--- a/lib/ic/examples/all-against-all/client.erl
+++ /dev/null
@@ -1,54 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : client.erl
-%% Purpose :
-%%----------------------------------------------------------------------
-
--module(client).
-
--export([produce/0,init/3,call/0]).
-
--define(SERVER,{rmod_random_impl,
- list_to_atom("babbis@"++hd(tl(string:tokens(atom_to_list(node()),"@"))))}).
--define(CLIENTMOD,'rmod_random').
-
-produce() ->
- ?CLIENTMOD:produce(?SERVER).
-
-
-init(Seed1, Seed2, Seed3) ->
- io:format("Init..."),
- ?CLIENTMOD:init(?SERVER,Seed1, Seed2, Seed3),
- io:format("ok\n").
-
-
-call() ->
- init(1,2,3),
- produce(0).
-
-
-produce(10) ->
- ok;
-produce(Ctr) ->
- N = produce(),
- io:format("Random~p = ~p\n",[Ctr,N]),
- produce(Ctr+1).
diff --git a/lib/ic/examples/all-against-all/client.java b/lib/ic/examples/all-against-all/client.java
deleted file mode 100644
index 48b5bc4f60..0000000000
--- a/lib/ic/examples/all-against-all/client.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-public class client {
-
- private static java.lang.String SNode = "client";
- private static java.lang.String PNode = "babbis";
- private static java.lang.String Cookie = "flash";
- private static java.lang.String Server = "rmod_random_impl";
-
- private static rmod._randomStub stub;
-
- public static void main(String[] args) {
-
- try {
-
- stub = new rmod._randomStub(SNode,PNode,Cookie,Server);
- int seed1 = 1;
- int seed2 = 2;
- int seed3 = 3;
- double random = 0;
-
- System.out.print("\nClient initialization....");
- stub.init(seed1,seed2,seed3);
- System.out.println("ok\n");
-
-
- for (int i = 0; i < 10; i++) {
- random = stub.produce();
- System.out.println("Random" + i + " = " + random);
- }
- System.out.println("\nClient terminated.\n");
-
- stub.__disconnect();
-
- } catch( Exception e) {
- System.out.println("Exception :");
- e.printStackTrace();
- }
-
- }
-
-}
-
diff --git a/lib/ic/examples/all-against-all/random.idl b/lib/ic/examples/all-against-all/random.idl
deleted file mode 100644
index 3402dfee2c..0000000000
--- a/lib/ic/examples/all-against-all/random.idl
+++ /dev/null
@@ -1,51 +0,0 @@
-// ``Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-// Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-// AB. All Rights Reserved.''
-//
-// $Id$
-//
-
-#ifndef _RANDOM_IDL
-#define _RANDOM_IDL
-
-module rmod {
-
- interface random {
-
- double produce();
-
- oneway void init(in long seed1, in long seed2, in long seed3);
-
- };
-
-};
-
-
-#endif
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/ic/examples/all-against-all/rmod_random_impl.erl b/lib/ic/examples/all-against-all/rmod_random_impl.erl
deleted file mode 100644
index 36b280c0b2..0000000000
--- a/lib/ic/examples/all-against-all/rmod_random_impl.erl
+++ /dev/null
@@ -1,49 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(rmod_random_impl).
--export([init/1, terminate/2]).
--export([produce/1,init/4]).
-
-
-init(Env) ->
- {ok, []}.
-
-terminate(From, Reason) ->
- ok.
-
-
-produce(_Random) ->
- case catch random:uniform() of
- {'EXIT',_} ->
- true;
- RUnif ->
- {reply,RUnif,[]}
- end.
-
-
-init(_Random,S1,S2,S3) ->
- case catch random:seed(S1,S2,S3) of
- {'EXIT',_} ->
- true;
- _ ->
- {noreply,[]}
- end.
-
diff --git a/lib/ic/examples/all-against-all/server.c b/lib/ic/examples/all-against-all/server.c
deleted file mode 100644
index 6d46ea7673..0000000000
--- a/lib/ic/examples/all-against-all/server.c
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <string.h>
-#ifdef __WIN32__
-#include <winsock2.h>
-#include <direct.h>
-#include <windows.h>
-#include <winbase.h>
-#else /* not __WIN32__ */
-#include <errno.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#endif
-#include "rmod_random__s.h"
-
-/* Used functions */
-static int getport(int sockd);
-static int getlisten(int port);
-static int init(int *sd, int *portnr, int *epmd_fd);
-void terminate(int *fd, int *sd, int *epmd_fd);
-static void server_loop(int fd, int sd);
-
-/* change these, or even better, make command-line args to program... */
-#define COOKIE "flash"
-#define SERVER "babbis"
-#define NODENAMESZ 512
-#define HOSTNAMESZ 256
-#define INBUFSZ 1024
-#define OUTBUFSZ 1024
-
-
-int main(int argc, char **argv)
-{
- int sd;
- int portnr;
- int epmd_fd;
-
- /* crate file descriptors */
- if (init(&sd, &portnr, &epmd_fd) < 0)
- return -1;
-
- /* start server loop */
- server_loop(sd,epmd_fd);
-
- return 0;
-}
-
-
-
-static void server_loop(int sd, int epmd_fd)
-{
- ErlConnect conn;
- erlang_msg msg;
- int status=1;
- CORBA_Environment *env;
-
- /* Create and init CORBA_Environment */
- env = CORBA_Environment_alloc(INBUFSZ,OUTBUFSZ);
-
- while (status >= 0) {
-
- status = 1;
-
- if ((env->_fd = erl_accept(sd,&conn)) < 0) {
- /* error */
- fprintf(stderr,"Accept failed: %s\n",strerror(errno));
- }
- else {
- /* connection */
- fprintf(stderr,"Accepted connection from %s\n",conn.nodename);
-
- while (status >= 0) {
-
- /* write message to buffer */
- status = ei_receive_encoded(env->_fd, &env->_inbuf, &env->_inbufsz, &msg, &env->_iin);
- switch(status) {
- case ERL_SEND:
- case ERL_REG_SEND :
- /* do transaction with fd */
- rmod_random__switch(NULL,env);
-
- switch(env->_major) {
- case CORBA_NO_EXCEPTION: /* Success */
- break;
- case CORBA_SYSTEM_EXCEPTION: /* System exception */
- printf("Request failure, reason : %s\n",(char *) CORBA_exception_value(env));
- CORBA_exception_free(env);
- break;
- default: /* Should not come here */
- CORBA_exception_free(env);
- break;
- }
-
- /* send outdata */
- if (env->_iout > 0)
- ei_send_encoded(env->_fd,&env->_caller,env->_outbuf,env->_iout);
- break;
-
- case ERL_TICK :
- break;
- default : /* < 0 */
- printf("Connection terminated\n");
- break;
- }
- }
- }
- status=0; /* restart */
- }
-
- /* close file descriptors */
- terminate(&env->_fd, &sd, &epmd_fd);
-
- /* Free env & buffers */
- CORBA_free(env->_inbuf);
- CORBA_free(env->_outbuf);
- CORBA_free(env);
-}
-
-
-
-static int init(int *sd, int *portnr, int *epmd_fd)
-{
- char host[HOSTNAMESZ];
- char servernode[NODENAMESZ];
- struct hostent *h;
- int error = 0;
-
-#ifdef __WIN32__
- WORD wVersionRequested;
- WSADATA wsaData;
-
- wVersionRequested = MAKEWORD(1, 1);
- if ((error = WSAStartup(wVersionRequested, &wsaData))) {
- fprintf(stderr,"Can't initialize windows sockets: %d",error);
- }
-#endif
- /* get the host name */
- error = gethostname(host,HOSTNAMESZ);
- if (error) {
-#ifdef __WIN32__
- fprintf(stderr,"can't find own hostname (error = %ld) !\n",WSAGetLastError());
-#else /* not __WIN32__ */
- fprintf(stderr,"can't find own hostname !\n");
-#endif
- }
- else {
- /* identify host */
- if (!(h = erl_gethostbyname(host)))
- fprintf(stdout,"can't find own ip address\n");
- else {
-
- /* get a listen port. 0 means let system choose port number */
- *sd = getlisten(0);
-
- /* what port did we get? */
- /* this call not necessary if we specified port in call to getlisten() */
- *portnr = getport(*sd);
-
- /* make the nodename server@host */
- sprintf(servernode,"%s@%s",SERVER,host);
-
- /* initiate */
- erl_init(NULL,0);
-
- /* host, alive, alive@host, addr, cookie, creation */
- erl_connect_xinit(host,SERVER,servernode,(Erl_IpAddr)(h->h_addr_list[0]),COOKIE,0);
-
- /* let epmd know we are here */
- *epmd_fd = erl_publish(*portnr);
-
- return 0;
- }
- }
- return -1;
-}
-
-
-void terminate(int *fd, int *sd, int *epmd_fd) {
-
- close(*fd);
-
- /* remove info from epnd */
- close(*epmd_fd);
-
- /* return socket */
- close(*sd);
-
-}
-
-
-
-/* tells you what port you are using on given socket */
-static int getport(int sockd)
-{
- struct sockaddr_in addr;
- int namelen = sizeof(addr);
- int i;
-
- memset(&addr,0,sizeof(addr));
-
- if ((i = getsockname(sockd,(struct sockaddr *)&addr,&namelen))<0)
- return i;
-
- return ntohs(addr.sin_port);
-}
-
-
-
-/* return a listen socket, bound to given port */
-/* specify port = 0 to let system assign port */
-static int getlisten(int port)
-{
- int sockd;
- struct sockaddr_in inaddr;
- int opt = 1;
- int i;
-
- /* get listen socket */
- if ((sockd = socket(AF_INET,SOCK_STREAM,0)) < 0) return sockd;
-
- if ((i=setsockopt(sockd,SOL_SOCKET,SO_REUSEADDR,(void *)&opt,sizeof(opt)))<0)
- return i;
-
- /* bind to requested port */
- memset(&inaddr,0,sizeof(inaddr));
- inaddr.sin_family = AF_INET;
- inaddr.sin_addr.s_addr = htonl(INADDR_ANY);
- inaddr.sin_port = htons(port);
-
- if ((i = bind(sockd,(struct sockaddr*) &inaddr, sizeof(inaddr))) < 0)
- return i;
-
- listen(sockd,5);
-
- return sockd;
-}
-
diff --git a/lib/ic/examples/all-against-all/server.erl b/lib/ic/examples/all-against-all/server.erl
deleted file mode 100644
index c5fa2589ae..0000000000
--- a/lib/ic/examples/all-against-all/server.erl
+++ /dev/null
@@ -1,41 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(server).
--export([start/0]).
-
-
-
-%% This starts up the random number server
-start() ->
- %% Start the gen server
- {ok,Pid} = rmod_random:oe_create([],{local,'rmod_random_impl'}),
- true.
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/ic/examples/all-against-all/server.java b/lib/ic/examples/all-against-all/server.java
deleted file mode 100644
index 79618ba8be..0000000000
--- a/lib/ic/examples/all-against-all/server.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-public class server {
-
- private static java.lang.String SNode = "babbis";
- private static java.lang.String Cookie = "flash";
- private static java.lang.String RegName = "rmod_random_impl";
-
- public static void main(String[] args) {
-
-
- System.out.println("\nServer running.\n");
- boolean serverState = true;
- boolean recState = true;
-
- try {
-
- com.ericsson.otp.erlang.OtpServer self = new com.ericsson.otp.erlang.OtpServer(SNode, Cookie);
- self.publishPort();
-
- /* Server loop */
- while(serverState == true) {
-
- com.ericsson.otp.erlang.OtpConnection connection = self.accept();
- serverImpl srv = new serverImpl();
- com.ericsson.otp.erlang.OtpInputStream request;
- com.ericsson.otp.erlang.OtpOutputStream reply;
- com.ericsson.otp.erlang.OtpErlangPid client;
-
- /* Server loop */
- while(recState == true) {
-
- if (connection.isConnected() == true)
- try {
-
- request = connection.receiveBuf();
-
- reply = srv.invoke(request);
-
- if (reply != null) {
- client = srv.__getCallerPid();
-
- connection.sendBuf(client,reply);
- }
-
- } catch( Exception e) {
- System.out.println("Server terminated.\n\n");
- recState = false;
- serverState = false;
- }
- }
-
- connection.close();
- }
-
- } catch( Exception e) {
- System.out.println("Initialization exception :");
- e.printStackTrace();
- }
- }
-}
-
-
-
-
diff --git a/lib/ic/examples/all-against-all/serverImpl.java b/lib/ic/examples/all-against-all/serverImpl.java
deleted file mode 100644
index 336bc7e327..0000000000
--- a/lib/ic/examples/all-against-all/serverImpl.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-public class serverImpl extends rmod._randomImplBase {
-
- java.util.Random random = null;
-
-
- public void init(int seed1, int seed2, int seed3) throws java.lang.Exception {
-
- random = new java.util.Random(seed1+seed2+seed3);
- };
-
-
- public double produce() throws java.lang.Exception {
-
- return random.nextDouble();
- }
-
-}
-
-
-
-
-
-
diff --git a/lib/ic/examples/c-client/Makefile b/lib/ic/examples/c-client/Makefile
deleted file mode 100644
index 1bfaaed477..0000000000
--- a/lib/ic/examples/c-client/Makefile
+++ /dev/null
@@ -1,87 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1998-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-# Point this at your version of OTP
-OTPROOT=/usr/local/otp/daily_build/otp_beam_sunos5_r8a.latest
-
-# Type actual IC Version
-ICVSN=4.1.1
-
-# Type actual Erl Interface Vesrion
-EIVSN=3.3.0
-
-# IDL file(s)
-IDLS=random.idl
-
-# Own C-client files
-CCL=client
-
-# Generated C-server files
-GCCLS=oe_code_seed rmod_random
-
-# Includes
-IFLAGS=-I$(OTPROOT)/lib/ic-$(ICVSN)/include \
- -I$(OTPROOT)/lib/erl_interface-$(EIVSN)/include
-
-LDFLAGS=-L$(OTPROOT)/lib/ic-$(ICVSN)/priv/lib \
- -L$(OTPROOT)/lib/erl_interface-$(EIVSN)/lib
-
-LDLIBS=-lic -lerl_interface -lei -lnsl -lsocket
-
-
-# Erlang compiler
-ERLC=$(OTPROOT)/bin/erlc
-
-# Erlang compiler flags.
-EFLAGS='+{preproc_flags,"-I $(OTPROOT)/usr/include"}' '+{scoped_op_calls,true}'
-
-
-# C compiler
-CC=gcc
-
-# C compiler flags
-CFLAGS=-ggdb -O2 -Wall $(IFLAGS)
-
-
-all: server client
-
-
-server:
- $(ERLC) $(EFLAGS) '+{be,erl_genserv}' $(IDLS)
- $(ERLC) *.erl
-
-client:
- $(ERLC) $(EFLAGS) '+{be,c_client}' $(IDLS)
- $(CC) $(IFLAGS) -c $(CCL:=.c) $(GCCLS:=.c)
- $(CC) $(CCL:=.o) $(GCCLS:=.o) -o $@ $(LDFLAGS) $(LDLIBS)
-
-
-
-clean:
- /bin/rm -f $(GCCLS:=.o) $(GCCLS:=.c) $(CCL:=.o) *.jam *.beam oe* rmod_random.erl *.h *.hrl *~ core client
-
-
-
-
-
-
-
-
-
diff --git a/lib/ic/examples/c-client/ReadMe b/lib/ic/examples/c-client/ReadMe
deleted file mode 100644
index 28372c3be2..0000000000
--- a/lib/ic/examples/c-client/ReadMe
+++ /dev/null
@@ -1,46 +0,0 @@
-This is a short description on the use of the c-client demo,
-a client that initiates and uses a random number generator
-that lies on an Erlang-genserver.
-
-Instructions.
-
-1) On Makefile :
- * Modify the OTPROOT variable on the Makefile to point
- to the root for your erlang instalation.
- * Modify IC and Erl_Interface versions to agree your
- OTP version.
-
-2) Type "make" to build the example.
-
-
-3) Start erlang with the options
- -setcookie <Some Cookie> -sname <SomeNodeName>
-
- In this example you should use :
-
- erl -setcookie flash -sname babbis
-
-
-4) On the erlang shell type :
- --------------------------
-
- rmod_random:oe_create([],{local,rmod_random_impl}). ( initializes the server )
-
- or
-
- test:start().
-
-
- Then start a new terminal window and type :
- -------------------------------------------
-
- client ( calls the client )
-
-
-
-
-
-
-
-
-
diff --git a/lib/ic/examples/c-client/client.c b/lib/ic/examples/c-client/client.c
deleted file mode 100644
index 652d8376fd..0000000000
--- a/lib/ic/examples/c-client/client.c
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1998-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-
-/* Include the interface function and ei_connect */
-#include "rmod_random.h"
-#include "ei_connect.h"
-
-/* Assign your own node name here */
-#define SNODE "babbis@balin"
-#define SERVER "rmod_random_impl"
-#define COOKIE "flash"
-#define CLNODE "c47@balin"
-#define INBUFSZ 1024
-#define OUTBUFSZ 1024
-
-/* Stopping node */
-void client_exit(CORBA_Environment *env) {
-
- /* Free env & buffers */
- CORBA_free(env->_inbuf);
- CORBA_free(env->_outbuf);
- CORBA_free(env);
-
- close(env->_fd);
- exit(1);
-}
-
-int main()
-{
- double result=0;
- int i=0;
- erlang_pid pid;
- CORBA_Environment *env;
- seed idata;
- ei_cnode ec;
-
- /* Create and init CORBA_Environment */
- env = CORBA_Environment_alloc(INBUFSZ,OUTBUFSZ);
-
- /* Initialize seed */
- idata.seed1 = 1;
- idata.seed2 = 2;
- idata.seed3 = 3;
-
- /* Initiating the connection */
- ei_connect_init(&ec, "c47", COOKIE, 0);
-
- /* Initiating pid*/
- strcpy(pid.node,CLNODE);
- pid.num = 99;
- pid.serial = 0;
- pid.creation = 0;
-
- /* Fixing environment variable */
- env->_fd = ei_connect(&ec, SNODE);
- strcpy(env->_regname, SERVER);
- env->_to_pid = NULL;
- env->_from_pid = &pid;
-
- if (env->_fd < 0) {
- fprintf(stderr,"Error : Cannot connect to Server\n");
-
- /* Free env & buffers */
- CORBA_free(env->_inbuf);
- CORBA_free(env->_outbuf);
- CORBA_free(env);
- exit(1);
- }
-
- /* Calling the init function */
- rmod_random_init(NULL, &idata, env);
-
- switch(env->_major) {
- case CORBA_NO_EXCEPTION: /* Success */
- printf("Init complete !\n");
- break;
- case CORBA_SYSTEM_EXCEPTION: /* System exception */
- printf("Init call failure, reason : %s\n",(char *) CORBA_exception_value(env));
- CORBA_exception_free(env);
- client_exit(env);
- default: /* Should not come here */
- client_exit(env);
- }
-
- /* Calling the produce function */
- for(i=1; i<=10; i++) {
- result = rmod_random_produce(NULL, env);
-
- switch(env->_major) {
- case CORBA_NO_EXCEPTION: /* Success */
- break;
- case CORBA_SYSTEM_EXCEPTION: /* System exception */
- printf("Init call failure, reason : %s\n",(char *) CORBA_exception_value(env));
- CORBA_exception_free(env);
- client_exit(env);
- default: /* Should not come here */
- client_exit(env);
- }
-
- printf("the random number nr%d is %f\n",i,result);
- }
-
- /* Closing the connection */
- close(env->_fd);
-
- /* Free env & buffers */
- CORBA_free(env->_inbuf);
- CORBA_free(env->_outbuf);
- CORBA_free(env);
-
- return 0;
-}
-
diff --git a/lib/ic/examples/c-client/random.idl b/lib/ic/examples/c-client/random.idl
deleted file mode 100644
index 8f54058e2b..0000000000
--- a/lib/ic/examples/c-client/random.idl
+++ /dev/null
@@ -1,52 +0,0 @@
-// ``Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-// Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-// AB. All Rights Reserved.''
-//
-// $Id$
-//
-#ifndef _RANDOM_IDL
-#define _RANDOM_IDL
-
-struct seed {
- long seed1;
- long seed2;
- long seed3;
-};
-
-module rmod {
-
- interface random {
-
- double produce();
-
- oneway void init(in seed idata);
-
- };
-
-};
-
-#endif
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/ic/examples/c-client/rmod_random_impl.erl b/lib/ic/examples/c-client/rmod_random_impl.erl
deleted file mode 100644
index 2948115f8d..0000000000
--- a/lib/ic/examples/c-client/rmod_random_impl.erl
+++ /dev/null
@@ -1,53 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module('rmod_random_impl').
--include("oe_random.hrl").
--export([init/1, terminate/2]).
--export([produce/1,init/2]).
-
-
-init(Env) ->
- {ok, []}.
-
-terminate(From, Reason) ->
- ok.
-
-
-produce(_Random) ->
- case catch random:uniform() of
- {'EXIT',_} ->
- true;
- RUnif ->
- {reply,RUnif,[]}
- end.
-
-
-init(_Random,IData) ->
- S1 = IData#seed.seed1,
- S2 = IData#seed.seed2,
- S3 = IData#seed.seed3,
- case catch random:seed(S1,S2,S3) of
- {'EXIT',_} ->
- true;
- _ ->
- {noreply,[]}
- end.
-
diff --git a/lib/ic/examples/c-client/test.erl b/lib/ic/examples/c-client/test.erl
deleted file mode 100644
index d1fa40ff44..0000000000
--- a/lib/ic/examples/c-client/test.erl
+++ /dev/null
@@ -1,44 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-% Start Erlang with : erl -sname <your name> -setcookie <your cookie>
-
--module(test).
-
--export([start/0,exec/0]).
-
-
-start() ->
- io:format("Starting server~n"),
- rmod_random:oe_create([],{local,'rmod_random_impl'}).
-
-exec() ->
- io:format("Running client~n"),
- OutPut = os:cmd("client"),
- io:format("~s",[OutPut]).
-
-
-
-
-
-
-
-
-
diff --git a/lib/ic/examples/c-server/Makefile b/lib/ic/examples/c-server/Makefile
deleted file mode 100644
index be23d3ddf9..0000000000
--- a/lib/ic/examples/c-server/Makefile
+++ /dev/null
@@ -1,90 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1998-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-# Point this at your version of OTP
-OTPROOT=/usr/local/otp/daily_build/otp_beam_sunos5_r8a.latest
-
-# Type actual IC Version
-ICVSN=4.1.1
-
-# Type actual Erl Interface Vesrion
-EIVSN=3.3.0
-
-# IDL file(s)
-IDLS=random.idl
-
-# Own C-server files
-CSRV=server callbacks
-
-# Own C-client files
-CCL=client
-
-# Generated C-server files
-GCSRVS=rmod_random__s
-
-# Generated C-server files
-GCCLS=rmod_random
-
-# Includes
-IFLAGS=-I$(OTPROOT)/lib/ic-$(ICVSN)/include \
- -I$(OTPROOT)/lib/erl_interface-$(EIVSN)/include
-
-LDFLAGS=-L$(OTPROOT)/lib/ic-$(ICVSN)/priv/lib \
- -L$(OTPROOT)/lib/erl_interface-$(EIVSN)/lib
-
-LDLIBS=-lic -lerl_interface -lei -lnsl -lsocket
-
-
-# Erlang compiler
-ERLC=$(OTPROOT)/bin/erlc
-
-# Erlang compiler flags.
-EFLAGS='+{preproc_flags,"-I $(OTPROOT)/usr/include"}' '+{scoped_op_calls,true}'
-
-
-# C compiler
-CC=gcc
-
-# C compiler flags
-CFLAGS=-ggdb -O2 -Wall $(IFLAGS)
-
-
-all: server client erlclient
-
-
-server:
- $(ERLC) $(EFLAGS) '+{be,c_server}' $(IDLS)
- $(CC) $(IFLAGS) -c $(CSRV:=.c) $(GCSRVS:=.c)
- $(CC) $(CSRV:=.o) $(GCSRVS:=.o) -o $@ $(LDFLAGS) $(LDLIBS)
-
-client:
- $(ERLC) $(EFLAGS) '+{be,c_client}' $(IDLS)
- $(CC) $(IFLAGS) -c $(CCL:=.c) $(GCCLS:=.c)
- $(CC) $(CCL:=.o) $(GCCLS:=.o) -o $@ $(LDFLAGS) $(LDLIBS)
-
-erlclient:
- $(ERLC) $(EFLAGS) '+{be,erl_genserv}' $(IDLS)
- $(ERLC) *.erl
-
-
-clean:
- /bin/rm -f $(GCCLS:=.o) $(GCCLS:=.c) $(GCSRVS:=.o) $(GCSRVS:=.c) $(CCL:=.o) $(CSRV:=.o) *.jam *.beam oe* *.h *.hrl *~ core server client
-
-
diff --git a/lib/ic/examples/c-server/ReadMe b/lib/ic/examples/c-server/ReadMe
deleted file mode 100644
index 69fce4cd07..0000000000
--- a/lib/ic/examples/c-server/ReadMe
+++ /dev/null
@@ -1,45 +0,0 @@
-This is a short description on the use of the client demo,
-a client that initiates and uses a random number generator
-that lies on a C-server.
-
-Instructions.
-
-1) Modify the OTPROOT variable on the Makefile to point
- to the root for your erlang instalation.
- Modify IC and Erl_Interface versions to agree your
- OTP version.
-
-2)
- Type :
- ------
-
- make ( generates and compiles all code )
-
- server ( starts the c-server )
-
-
- To test the c-client against the c-server start a new terminal window and type :
- --------------------------------------------------------------------------------
-
- client ( calls the server )
-
-
- To test the erlang-client against the c-server start a new terminal window and type :
- -------------------------------------------------------------------------------------
-
-
- erl -sname client -setcookie flash ( start erlang )
-
- client:init(1,2,3). ( initiates the random generator )
-
- client:produce(). ( calls the random generator )
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/ic/examples/c-server/callbacks.c b/lib/ic/examples/c-server/callbacks.c
deleted file mode 100644
index 2deca145f4..0000000000
--- a/lib/ic/examples/c-server/callbacks.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1998-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-
-#include <stdlib.h>
-#include "rmod_random__s.h"
-
-
-rmod_random_produce__rs*
-rmod_random_produce__cb(rmod_random oe_obj, double *rs, CORBA_Environment *oe_env)
-
-{
- *rs = (double) rand();
-
- return (rmod_random_produce__rs*) NULL;
-}
-
-
-rmod_random_init__rs*
-rmod_random_init__cb(rmod_random oe_obj, long* seed1, long* seed2, long* seed3, CORBA_Environment *oe_env)
-
-{
- srand(*seed1 * *seed2 * *seed3);
-
- return (rmod_random_init__rs*) NULL;
-}
-
-
-
diff --git a/lib/ic/examples/c-server/client.c b/lib/ic/examples/c-server/client.c
deleted file mode 100644
index c1d7a1c5a7..0000000000
--- a/lib/ic/examples/c-server/client.c
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1998-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-
-/* Include the interface function, and ei_connect */
-#include "rmod_random.h"
-#include "ei_connect.h"
-
-/* Assign your own node name here */
-#define SNODE "babbis@balin"
-#define SERVER "rmod_random_impl"
-#define COOKIE "flash"
-#define CLNODE "c47@balin"
-#define INBUFSZ 1024
-#define OUTBUFSZ 1024
-
-/* Stopping node */
-void client_exit(CORBA_Environment *env) {
-
- /* Free env & buffers */
- CORBA_free(env->_inbuf);
- CORBA_free(env->_outbuf);
- CORBA_free(env);
-
- close(env->_fd);
- exit(1);
-}
-
-int main()
-{
- double result=0;
- int i=0;
- erlang_pid pid;
- CORBA_Environment *env;
- ei_cnode ec;
-
- /* Create and init CORBA_Environment */
- env = CORBA_Environment_alloc(INBUFSZ,OUTBUFSZ);
-
- /* Initiating the connection */
- ei_connect_init(&ec, "c47", COOKIE, 0);
-
- /* Initiating pid*/
- strcpy(pid.node, CLNODE);
- pid.num = 99;
- pid.serial = 0;
- pid.creation = 0;
-
- /* Fixing environment variable */
- env->_fd = ei_connect(&ec, SNODE);
- strcpy(env->_regname,SERVER);
- env->_to_pid = NULL;
- env->_from_pid = &pid;
-
- if (env->_fd < 0) {
- fprintf(stderr,"Error : Cannot connect to Server\n");
-
- /* Free env & buffers */
- CORBA_free(env->_inbuf);
- CORBA_free(env->_outbuf);
- CORBA_free(env);
- exit(1);
- }
-
- /* Calling the init function */
- rmod_random_init(NULL, 1, 2, 3, env);
-
- switch(env->_major) {
- case CORBA_NO_EXCEPTION: /* Success */
- printf("Init complete !\n");
- break;
- case CORBA_SYSTEM_EXCEPTION: /* System exception */
- printf("Init call failure, reason : %s\n",(char *) CORBA_exception_value(env));
- CORBA_exception_free(env);
- client_exit(env);
- default: /* Should not come here */
- client_exit(env);
- }
-
- /* Calling the produce function */
- for(i=1; i<=10; i++) {
- result = rmod_random_produce(NULL, env);
-
- switch(env->_major) {
- case CORBA_NO_EXCEPTION: /* Success */
- break;
- case CORBA_SYSTEM_EXCEPTION: /* System exception */
- printf("Init call failure, reason : %s\n",(char *) CORBA_exception_value(env));
- CORBA_exception_free(env);
- client_exit(env);
- default: /* Should not come here */
- client_exit(env);
- }
-
- printf("the random number nr%d is %f\n",i,result);
- }
-
- /* Closing the connection */
- close(env->_fd);
-
- /* Free env & buffers */
- CORBA_free(env->_inbuf);
- CORBA_free(env->_outbuf);
- CORBA_free(env);
-
- return 0;
-}
-
diff --git a/lib/ic/examples/c-server/client.erl b/lib/ic/examples/c-server/client.erl
deleted file mode 100644
index da28cd504b..0000000000
--- a/lib/ic/examples/c-server/client.erl
+++ /dev/null
@@ -1,45 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%%----------------------------------------------------------------------
-%%% File : client.erl
-%%% Author : Babbis Xagorarakis <babbis@balin>
-%%% Purpose :
-%%% Created : 22 Oct 1998 by Babbis Xagorarakis <babbis@balin>
-%%%----------------------------------------------------------------------
-
--module(client).
--author('babbis@balin').
-
--export([produce/0,init/3]).
-
--define(SERVER,{rmod_random_impl,'babbis@balin'}).
--define(CLIENTMOD,'rmod_random').
-
-produce() ->
- ?CLIENTMOD:produce(?SERVER).
-
-
-init(Seed1, Seed2, Seed3) ->
- ?CLIENTMOD:init(?SERVER, Seed1, Seed2, Seed3).
-
-
-
-
diff --git a/lib/ic/examples/c-server/random.idl b/lib/ic/examples/c-server/random.idl
deleted file mode 100644
index 7ce302a2e7..0000000000
--- a/lib/ic/examples/c-server/random.idl
+++ /dev/null
@@ -1,50 +0,0 @@
-// ``Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-// Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-// AB. All Rights Reserved.''
-//
-// $Id$
-//
-
-#ifndef _RANDOM_IDL
-#define _RANDOM_IDL
-
-module rmod {
-
- interface random {
-
- double produce();
-
- oneway void init(in long seed1, in long seed2, in long seed3);
-
- };
-
-};
-
-#endif
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/ic/examples/c-server/server.c b/lib/ic/examples/c-server/server.c
deleted file mode 100644
index a04d60e9b1..0000000000
--- a/lib/ic/examples/c-server/server.c
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1998-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <string.h>
-#ifdef __WIN32__
-#include <winsock2.h>
-#include <direct.h>
-#include <windows.h>
-#include <winbase.h>
-#else /* not __WIN32__ */
-#include <errno.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#endif
-#include "rmod_random__s.h"
-#include "ei_connect.h"
-
-/* Used functions */
-extern int gethostname(char *buf, int buflen);
-static int getport(int sockd);
-static int getlisten(int port);
-static int init(ei_cnode *ec, int *sd, int *portnr, int *epmd_fd);
-void terminate(int *fd, int *sd, int *epmd_fd);
-static void server_loop(ei_cnode *ec, int fd, int sd);
-
-/* change these, or even better, make command-line args to program... */
-#define COOKIE "flash"
-#define SERVER "babbis"
-#define NODENAMESZ 512
-#define HOSTNAMESZ 256
-#define INBUFSZ 1024
-#define OUTBUFSZ 1024
-
-
-int main(int argc, char **argv)
-{
- int sd;
- int portnr;
- int epmd_fd;
- ei_cnode ec;
-
- /* crate file descriptors */
- if (init(&ec, &sd, &portnr, &epmd_fd) < 0)
- return -1;
-
- /* start server loop */
- server_loop(&ec, sd, epmd_fd);
-
- return 0;
-}
-
-
-
-static void server_loop(ei_cnode *ec, int sd, int epmd_fd)
-{
- ErlConnect conn;
- erlang_msg msg;
- int status=1;
- CORBA_Environment *env;
-
- /* Create and init CORBA_Environment */
- env = CORBA_Environment_alloc(INBUFSZ,OUTBUFSZ);
-
- while (status >= 0) {
- status = 1;
-
- if ((env->_fd = ei_accept(ec, sd, &conn)) < 0) {
- /* error */
- fprintf(stderr,"Accept failed: %s\n",strerror(errno));
- } else {
- /* connection */
- fprintf(stderr,"Accepted connection from %s\n",conn.nodename);
-
- while (status >= 0) {
-
- /* write message to buffer */
- status = ei_receive_encoded(env->_fd, &env->_inbuf, &env->_inbufsz, &msg, &env->_iin);
- switch(status) {
- case ERL_SEND:
- case ERL_REG_SEND :
- /* do transaction with fd */
- rmod_random__switch(NULL,env);
-
- switch(env->_major) {
- case CORBA_NO_EXCEPTION: /* Success */
- break;
- case CORBA_SYSTEM_EXCEPTION: /* System exception */
- printf("Request failure, reason : %s\n",(char *) CORBA_exception_value(env));
- CORBA_exception_free(env);
- break;
- default: /* Should not come here */
- CORBA_exception_free(env);
- break;
- }
-
- /* send outdata */
- if (env->_iout > 0)
- ei_send_encoded(env->_fd,&env->_caller,env->_outbuf,env->_iout);
- break;
-
- case ERL_TICK :
- break;
- default : /* < 0 */
- printf("Connection terminated\n");
- break;
- }
- }
- }
- status=0; /* restart */
- }
-
- /* close file descriptors */
- terminate(&env->_fd, &sd, &epmd_fd);
-
- /* Free env & buffers */
- CORBA_free(env->_inbuf);
- CORBA_free(env->_outbuf);
- CORBA_free(env);
-}
-
-
-
-static int init(int *sd, int *portnr, int *epmd_fd)
-{
- char host[HOSTNAMESZ];
- char servernode[NODENAMESZ];
- struct hostent *h;
-
- /* get the host name */
- if ((gethostname(host,HOSTNAMESZ)))
- fprintf(stderr,"can't find own hostname\n");
- else {
- /* identify host */
- if (!(h = erl_gethostbyname(host)))
- fprintf(stdout,"can't find own ip address\n");
- else {
-
- /* get a listen port. 0 means let system choose port number */
- *sd = getlisten(0);
-
- /* what port did we get? */
- /* this call not necessary if we specified port in call to getlisten() */
- *portnr = getport(*sd);
-
- /* make the nodename server@host */
- sprintf(servernode,"%s@%s",SERVER,host);
-
- /* initiate */
- /* cnode, host, alive, alive@host, addr, cookie, creation */
- if (ei_connect_xinit(ec, host, SERVER, servernode,
- (Erl_IpAddr)(h->h_addr_list[0]),
- COOKIE, 0) == 0) {
- /* let epmd know we are here */
- *epmd_fd = ei_publish(ec, *portnr);
- if (*epmd_fd >= 0)
- return 0;
- }
- }
- }
- return -1;
-}
-
-
-void terminate(int *fd, int *sd, int *epmd_fd) {
-
- close(*fd);
-
- /* remove info from epnd */
- close(*epmd_fd);
-
- /* return socket */
- close(*sd);
-
-}
-
-
-
-/* tells you what port you are using on given socket */
-static int getport(int sockd)
-{
- struct sockaddr_in addr;
- int namelen = sizeof(addr);
- int i;
-
- memset(&addr,0,sizeof(addr));
-
- if ((i = getsockname(sockd,(struct sockaddr *)&addr,&namelen))<0)
- return i;
-
- return ntohs(addr.sin_port);
-}
-
-
-
-/* return a listen socket, bound to given port */
-/* specify port = 0 to let system assign port */
-static int getlisten(int port)
-{
- int sockd;
- struct sockaddr_in inaddr;
- int opt = 1;
- int i;
-
- /* get listen socket */
- if ((sockd = socket(AF_INET,SOCK_STREAM,0)) < 0) return sockd;
-
- if ((i=setsockopt(sockd,SOL_SOCKET,SO_REUSEADDR,(void *)&opt,sizeof(opt)))<0)
- return i;
-
- /* bind to requested port */
- memset(&inaddr,0,sizeof(inaddr));
- inaddr.sin_family = AF_INET;
- inaddr.sin_addr.s_addr = htonl(INADDR_ANY);
- inaddr.sin_port = htons(port);
-
- if ((i = bind(sockd,(struct sockaddr*) &inaddr, sizeof(inaddr))) < 0)
- return i;
-
- listen(sockd,5);
-
- return sockd;
-}
diff --git a/lib/ic/examples/erl-genserv/ReadMe b/lib/ic/examples/erl-genserv/ReadMe
deleted file mode 100644
index cde588e269..0000000000
--- a/lib/ic/examples/erl-genserv/ReadMe
+++ /dev/null
@@ -1,30 +0,0 @@
-This is a short description on the use of the c-client demo,
-a client that initiates and uses a random number generator
-that lies on an Erlang-genserver.
-
-Instructions.
-
- On the erlang shell type :
- --------------------------
-
- ic:gen(random,[{be,erl_genserv}]). ( generates the plain code )
-
- make:all(). ( compiles the erlang code )
-
- {ok,R} = rmod_random:oe_create(). ( initializes the server )
-
-
- Running the example :
- ---------------------
-
- rmod_random:init(R,1,2,3). ( initializes the generator )
-
- rmod_random:produce(R). ( generates a random number )
-
-
-
-
-
-
-
-
diff --git a/lib/ic/examples/erl-genserv/random.idl b/lib/ic/examples/erl-genserv/random.idl
deleted file mode 100644
index 969b24b749..0000000000
--- a/lib/ic/examples/erl-genserv/random.idl
+++ /dev/null
@@ -1,51 +0,0 @@
-// ``Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-// Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-// AB. All Rights Reserved.''
-//
-// $Id$
-//
-
-#ifndef _RANDOM_IDL
-#define _RANDOM_IDL
-
-
-module rmod {
-
- interface random {
-
- double produce();
-
- oneway void init(in long seed1, in long seed2, in long seed3);
-
- };
-
-};
-
-#endif
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/ic/examples/erl-genserv/rmod_random_impl.erl b/lib/ic/examples/erl-genserv/rmod_random_impl.erl
deleted file mode 100644
index 9d9ca8afd4..0000000000
--- a/lib/ic/examples/erl-genserv/rmod_random_impl.erl
+++ /dev/null
@@ -1,64 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module('rmod_random_impl').
--export([init/1, terminate/2, start/0]).
--export([produce/1,init/4]).
-
-
-init(Env) ->
- {ok, []}.
-
-terminate(From, Reason) ->
- ok.
-
-
-produce(_Random) ->
- case catch random:uniform() of
- {'EXIT',_} ->
- true;
- RUnif ->
- {reply,RUnif,[]}
- end.
-
-
-init(_Random,S1,S2,S3) ->
- case catch random:seed(S1,S2,S3) of
- {'EXIT',_} ->
- true;
- _ ->
- {noreply,[]}
- end.
-
-
-%% This starts up the random number server
-start() ->
- %% Start the gen server
- {ok,Pid} = rmod_random:oe_create([],{local,'rmod_random_impl'}),
- true.
-
-
-
-
-
-
-
-
-
diff --git a/lib/ic/examples/erl-plain/ReadMe b/lib/ic/examples/erl-plain/ReadMe
deleted file mode 100644
index 26440b4d4f..0000000000
--- a/lib/ic/examples/erl-plain/ReadMe
+++ /dev/null
@@ -1,27 +0,0 @@
-This is a short description on the use of the erl-plain demo,
-a client that initiates and uses a random number generator
-that lies on an Erlang-genserver.
-
-Instructions.
-
- On the erlang shell type :
- --------------------------
-
- ic:gen(random,[{be,erl_plain}]). ( generates the plain code )
-
- make:all(). ( compiles the erlang code )
-
-
- Running the example :
- ---------------------
-
- rmod_random:init(1,2,3). ( initializes the generator )
-
- rmod_random:produce(). ( generates a random number )
-
-
-
-
-
-
-
diff --git a/lib/ic/examples/erl-plain/random.idl b/lib/ic/examples/erl-plain/random.idl
deleted file mode 100644
index 606d91f6c5..0000000000
--- a/lib/ic/examples/erl-plain/random.idl
+++ /dev/null
@@ -1,53 +0,0 @@
-// ``Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-// Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-// AB. All Rights Reserved.''
-//
-// $Id$
-//
-#pragma CODEOPT "[{be,c_genserv}]"
-
-
-#ifndef _RANDOM_IDL
-#define _RANDOM_IDL
-
-
-module rmod {
-
- interface random {
-
- double produce();
-
- oneway void init(in long seed1, in long seed2, in long seed3);
-
- };
-
-};
-
-#endif
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/ic/examples/erl-plain/rmod_random_impl.erl b/lib/ic/examples/erl-plain/rmod_random_impl.erl
deleted file mode 100644
index ee8623f82d..0000000000
--- a/lib/ic/examples/erl-plain/rmod_random_impl.erl
+++ /dev/null
@@ -1,33 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module('rmod_random_impl').
-
--export([produce/0,init/3]).
-
-
-produce() ->
- random:uniform().
-
-
-init(S1,S2,S3) ->
- random:seed(S1,S2,S3),
- ok.
-
diff --git a/lib/ic/examples/java-client-server/ReadMe b/lib/ic/examples/java-client-server/ReadMe
deleted file mode 100644
index 9fde464e09..0000000000
--- a/lib/ic/examples/java-client-server/ReadMe
+++ /dev/null
@@ -1,69 +0,0 @@
-This is a short description on the use of the java demo,
-a client that initiates and uses a random number generator
-that lies on a java-server. You will be able to shift the
-existing client/server with the ones refered to the other
-examples.
-
-Instructions.
-
-1) Start erlang
-
- On the erlang shell type :
- --------------------------
-
- ic:gen(random,[{be,java}]). ( generates the java code )
-
-
-2) Modify the "SNode" string on file "server.java" to the server
- node name thet suites for your machine.
-
-
-3) Modify the "SNode" string on file "client.java" to the client
- node for your machine and the "PNode" string for the server
- node ( = the same as the SNode for the "server.java" file ).
-
-
-4) Set and export the CLASSPATH variable to point to the
- java classes located in java development kit, the
- Otp's classes and the current directory.
- Your classpath should look like this :
-
- .:<OTPROOT>/lib/ic-4.0/priv/ic.jar:<OTPROOT>/lib/jinterface_1.1/priv/OtpErlang.jar
-
- where :
-
- <OTPROOT> is the location there OTP is installed
-
-
-5) Start the empd deamon by using the command :
-
- epmd -daemon
-
-
-6) Compile the generated java code :
-
- javac rmod/*.java ( compiles all generated java code )
-
- javac *.java ( compiles all manually writen java code )
-
-
-7) Start the java on an terminal window :
-
- java server ( starts the java-server )
-
-
-8) Start the client on an terminal window :
-
- java client ( calls the server )
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/ic/examples/java-client-server/client.java b/lib/ic/examples/java-client-server/client.java
deleted file mode 100644
index 48b5bc4f60..0000000000
--- a/lib/ic/examples/java-client-server/client.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-public class client {
-
- private static java.lang.String SNode = "client";
- private static java.lang.String PNode = "babbis";
- private static java.lang.String Cookie = "flash";
- private static java.lang.String Server = "rmod_random_impl";
-
- private static rmod._randomStub stub;
-
- public static void main(String[] args) {
-
- try {
-
- stub = new rmod._randomStub(SNode,PNode,Cookie,Server);
- int seed1 = 1;
- int seed2 = 2;
- int seed3 = 3;
- double random = 0;
-
- System.out.print("\nClient initialization....");
- stub.init(seed1,seed2,seed3);
- System.out.println("ok\n");
-
-
- for (int i = 0; i < 10; i++) {
- random = stub.produce();
- System.out.println("Random" + i + " = " + random);
- }
- System.out.println("\nClient terminated.\n");
-
- stub.__disconnect();
-
- } catch( Exception e) {
- System.out.println("Exception :");
- e.printStackTrace();
- }
-
- }
-
-}
-
diff --git a/lib/ic/examples/java-client-server/random.idl b/lib/ic/examples/java-client-server/random.idl
deleted file mode 100644
index 7ce302a2e7..0000000000
--- a/lib/ic/examples/java-client-server/random.idl
+++ /dev/null
@@ -1,50 +0,0 @@
-// ``Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-// Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-// AB. All Rights Reserved.''
-//
-// $Id$
-//
-
-#ifndef _RANDOM_IDL
-#define _RANDOM_IDL
-
-module rmod {
-
- interface random {
-
- double produce();
-
- oneway void init(in long seed1, in long seed2, in long seed3);
-
- };
-
-};
-
-#endif
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/ic/examples/java-client-server/server.java b/lib/ic/examples/java-client-server/server.java
deleted file mode 100644
index 79618ba8be..0000000000
--- a/lib/ic/examples/java-client-server/server.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-public class server {
-
- private static java.lang.String SNode = "babbis";
- private static java.lang.String Cookie = "flash";
- private static java.lang.String RegName = "rmod_random_impl";
-
- public static void main(String[] args) {
-
-
- System.out.println("\nServer running.\n");
- boolean serverState = true;
- boolean recState = true;
-
- try {
-
- com.ericsson.otp.erlang.OtpServer self = new com.ericsson.otp.erlang.OtpServer(SNode, Cookie);
- self.publishPort();
-
- /* Server loop */
- while(serverState == true) {
-
- com.ericsson.otp.erlang.OtpConnection connection = self.accept();
- serverImpl srv = new serverImpl();
- com.ericsson.otp.erlang.OtpInputStream request;
- com.ericsson.otp.erlang.OtpOutputStream reply;
- com.ericsson.otp.erlang.OtpErlangPid client;
-
- /* Server loop */
- while(recState == true) {
-
- if (connection.isConnected() == true)
- try {
-
- request = connection.receiveBuf();
-
- reply = srv.invoke(request);
-
- if (reply != null) {
- client = srv.__getCallerPid();
-
- connection.sendBuf(client,reply);
- }
-
- } catch( Exception e) {
- System.out.println("Server terminated.\n\n");
- recState = false;
- serverState = false;
- }
- }
-
- connection.close();
- }
-
- } catch( Exception e) {
- System.out.println("Initialization exception :");
- e.printStackTrace();
- }
- }
-}
-
-
-
-
diff --git a/lib/ic/examples/java-client-server/serverImpl.java b/lib/ic/examples/java-client-server/serverImpl.java
deleted file mode 100644
index 336bc7e327..0000000000
--- a/lib/ic/examples/java-client-server/serverImpl.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-public class serverImpl extends rmod._randomImplBase {
-
- java.util.Random random = null;
-
-
- public void init(int seed1, int seed2, int seed3) throws java.lang.Exception {
-
- random = new java.util.Random(seed1+seed2+seed3);
- };
-
-
- public double produce() throws java.lang.Exception {
-
- return random.nextDouble();
- }
-
-}
-
-
-
-
-
-
diff --git a/lib/ic/examples/pre_post_condition/Makefile b/lib/ic/examples/pre_post_condition/Makefile
deleted file mode 100644
index cd7e630724..0000000000
--- a/lib/ic/examples/pre_post_condition/Makefile
+++ /dev/null
@@ -1,135 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1999-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-# ``Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-# Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-# AB. All Rights Reserved.''
-#
-# $Id$
-#
-include $(ERL_TOP)/make/target.mk
-
-EBIN= ./
-
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../../vsn.mk
-VSN=$(IC_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/ic-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-
-IDL_FILES = \
- ex.idl
-
-GEN_ERL_MODULES = \
- oe_ex \
- m_i \
- m_NotAnInteger
-
-MODULES= \
- m_i_impl \
- tracer
-
-GEN_HRL_FILES = \
- oe_ex.hrl \
- m.hrl \
- m_i.hrl
-
-HRL_FILES =
-TXT_FILES = ReadMe.txt
-
-ERL_FILES= $(MODULES:%=%.erl)
-
-
-TARGET_FILES = \
- $(GEN_ERL_MODULES:%=$(EBIN)/%.$(EMULATOR)) \
- $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_LOCAL_FLAGS += -pa $(ERL_TOP)/lib/orber/ebin -pa $(ERL_TOP)/lib/ic/ebin
-# The -pa option is just used temporary until erlc can handle
-# includes from other directories than ../include .
-ERL_COMPILE_FLAGS += \
- $(ERL_LOCAL_FLAGS) \
- -pa $(ERL_TOP)/lib/orber -I$(ERL_TOP)/lib/orber
-YRL_FLAGS =
-
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-debug opt: $(TARGET_FILES)
-
-clean:
- rm -f $(TARGET_FILES) $(GEN_ERL_MODULES:%=%.erl) $(GEN_HRL_FILES) $(CLASS_FILES) IDL-GENERATED
- rm -f errs core *~
-
-docs:
-
-test: $(TEST_TARGET_FILES)
-
-
-IDL-GENERATED: ex.idl
- $(gen_verbose)erlc $(ERL_LOCAL_FLAGS) +'{precond,{tracer,pre}}' \
- +'{{postcond,"m::i::f"},{tracer,post}}' ex.idl
- $(V_at)>IDL-GENERATED
-
-$(GEN_ERL_MODULES:%=%.erl) $(GEN_HRL_FILES): IDL-GENERATED
-
-$(TARGET_FILES): IDL-GENERATED
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/examples/pre_post_condition"
- $(INSTALL_DATA) $(ERL_FILES) $(IDL_FILES) $(TXT_FILES) "$(RELSYSDIR)/examples/pre_post_condition"
-
-
-release_docs_spec:
-
-
diff --git a/lib/ic/examples/pre_post_condition/ReadMe.txt b/lib/ic/examples/pre_post_condition/ReadMe.txt
deleted file mode 100644
index 2fb3f0a04f..0000000000
--- a/lib/ic/examples/pre_post_condition/ReadMe.txt
+++ /dev/null
@@ -1,74 +0,0 @@
- ``Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson Utvecklings AB.
- Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
- AB. All Rights Reserved.''
-
- $Id$
-
-
-This example shows how pre and post condition can be used for a Corba server object.
-
-
-The example consists of three files;
-
-ex.idl - the interface specification
-m_i_impl.erl - the server implementation
-tracer.erl - a module which contains a pre and a post condition
-
-
-The IDL file can for example be compiled with the following options:
-
-ic:gen(ex, [{precond, {tracer, pre}},{{postcond, "m::i::f"}, {tracer, post}}]).
-
-The result is that the function m::i::f gets both a pre and post condition call while
-the function m::i::g just get a pre condition call.
-
-
-A pre/post condition function should always return the atom ok and if something is wrong
-it should raise an exception ( ex: corba:raise(#userexception{}) ).
-
-
-
-
-Compile all erlang files and test the application.
-
-First start an erlang node, then type the following commands in the erlang shell.
-
-1> mnesia:create_schema([]).
-2> orber:install([]).
-3> orber:start().
-3>
-3> X = m_i:oe_create().
-4> catch m_i:f(X, 17).
-Precond called in process <0.139.0>: m_i:f() [[],17]
-f working ....
-Postcond called in process <0.139.0>: m_i:f() [[],17] {reply,{17,17},[]}
-17
-5>
-5> catch m_i:f(X, q).
-6> {'EXCEPTION',{m_NotAnInteger,"IDL:m/NotAnInteger:1.0"}}
-7>
-7>m_i:g(X, 17).
-Precond called in process <0.139.0>: m_i:g() [[],17]
-ok
-g working ....
-8>
-8>corba_boa:dispose(X).
-9> orber:stop().
-10>
-
-
-
-
-
diff --git a/lib/ic/examples/pre_post_condition/ex.idl b/lib/ic/examples/pre_post_condition/ex.idl
deleted file mode 100644
index 29298c8efb..0000000000
--- a/lib/ic/examples/pre_post_condition/ex.idl
+++ /dev/null
@@ -1,30 +0,0 @@
-// ``Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-// Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-// AB. All Rights Reserved.''
-//
-// $Id$
-//
-
-module m {
-
- exception NotAnInteger {};
-
- interface i {
- short f(in short i);
- oneway void g(in long i);
- };
-
-};
-
diff --git a/lib/ic/examples/pre_post_condition/m_i_impl.erl b/lib/ic/examples/pre_post_condition/m_i_impl.erl
deleted file mode 100644
index fa6d9675a2..0000000000
--- a/lib/ic/examples/pre_post_condition/m_i_impl.erl
+++ /dev/null
@@ -1,50 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%------------------------------------------------------------
-%%
-%% Example
-%%
-%%------------------------------------------------------------
--module(m_i_impl).
-
-%% Standard functions
--export([init/1, terminate/2]).
-%% Interface functions
--export([f/2, g/2]).
-
-init(_Env) ->
- {ok, []}.
-
-terminate(_From, _Reason) ->
- ok.
-
-f(State, In) ->
- io:format("f working ....\n", []),
- {reply, In, State}.
-
-g(State, _In) ->
- io:format("g working ....\n", []),
- {noreply, State}.
-
-
-
-
-
diff --git a/lib/ic/examples/pre_post_condition/tracer.erl b/lib/ic/examples/pre_post_condition/tracer.erl
deleted file mode 100644
index c64459f4fd..0000000000
--- a/lib/ic/examples/pre_post_condition/tracer.erl
+++ /dev/null
@@ -1,57 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: tracer.erl
-%%
-%% Description:
-%% This file contains an example of pre and post conditions for
-%% the corba backend.
-%%
-%%-----------------------------------------------------------------
--module(tracer).
--include("m.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([pre/3, post/4]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-%%-----------------------------------------------------------------
-%% External functions
-%%-----------------------------------------------------------------
-pre(M, F, [State, I]) when is_integer(I) ->
- io:format("Precond called in process ~p: ~s:~s() ~p\n", [self(), M, F, [State, I]]),
- ok;
-pre(_M, _F, _A) -> %% Just an silly example to get an exception case
- corba:raise(#'m_NotAnInteger'{}).
-
-post(M, F, A, R) ->
- io:format("Postcond called in process ~p: ~s:~s() ~p ~p\n", [self(), M, F, A, R]),
- ok.
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
diff --git a/lib/ic/include/erlang.idl b/lib/ic/include/erlang.idl
deleted file mode 100644
index 87d1247b87..0000000000
--- a/lib/ic/include/erlang.idl
+++ /dev/null
@@ -1,58 +0,0 @@
-// ``Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-// Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-// AB. All Rights Reserved.''
-//
-// $Id$
-//
-
-#ifndef _ERLANG_IDL_
-#define _ERLANG_IDL_
-
-module erlang
-{
-
- // an erlang pid
- struct pid {
- string<256> node;
- unsigned long num;
- unsigned long serial;
- unsigned long creation;
- };
-
- // an erlang port
- struct port {
- string<256> node;
- unsigned long id;
- unsigned long creation;
- };
-
- // port and ref have identical structure
- struct ref {
- string<256> node;
- unsigned long id;
- unsigned long creation;
- };
-
-
- // an erlang term
- typedef any term;
-
-
- // an erlang binary
- typedef sequence<octet> binary;
-
-};
-
-#endif
diff --git a/lib/ic/include/ic.h b/lib/ic/include/ic.h
deleted file mode 100644
index 3dc5dbd4b5..0000000000
--- a/lib/ic/include/ic.h
+++ /dev/null
@@ -1,432 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1998-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <ei.h>
-#include <erl_interface.h>
-
-#ifdef __WIN32__
-/* Windows.h #defines interface to struct, get rid of it! */
-#ifdef interface
-#undef interface
-#endif
-#endif
-
-#ifndef __IC_H__
-#define __IC_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Standard type mapping */
-
-#ifndef __CORBA_SHORT__
-#define __CORBA_SHORT__
- typedef short CORBA_short;
-#endif
-
-#ifndef __CORBA_LONG__
-#define __CORBA_LONG__
- typedef long CORBA_long;
-#endif
-
-/* CORBA_long_long = long because of erl_interface limitation */
-#ifndef __CORBA_LONG_LONG__
-#define __CORBA_LONG_LONG__
- typedef long CORBA_long_long; /* LONG LONG */
-#endif
-
-#ifndef __CORBA_UNSIGNED_SHORT__
-#define __CORBA_UNSIGNED_SHORT__
- typedef unsigned short CORBA_unsigned_short;
-#endif
-
-#ifndef __CORBA_UNSIGNED_LONG__
-#define __CORBA_UNSIGNED_LONG__
- typedef unsigned long CORBA_unsigned_long;
-#endif
-
-/* CORBA_unsigned long_long = unsigned long because of erl_interface
- limitation */
-
-#ifndef __CORBA_UNSIGNED_LONG_LONG__
-#define __CORBA_UNSIGNED_LONG_LONG__
- typedef unsigned long CORBA_unsigned_long_long;
-#endif
-
-#ifndef __CORBA_FLOAT__
-#define __CORBA_FLOAT__
- typedef float CORBA_float;
-#endif
-
-#ifndef __CORBA_DOUBLE__
-#define __CORBA_DOUBLE__
- typedef double CORBA_double;
-#endif
-
-
-#ifndef __CORBA_LONG_DOUBLE__
-#define __CORBA_LONG_DOUBLE__
- typedef double CORBA_long_double;
-#endif
-
-#ifndef __CORBA_CHAR__
-#define __CORBA_CHAR__
- typedef char CORBA_char;
-#endif
-
-#ifndef __CORBA_WCHAR__
-#define __CORBA_WCHAR__
- typedef unsigned long CORBA_wchar;
-#endif
-
-#ifndef __CORBA_BOOLEAN__
-#define __CORBA_BOOLEAN__
- typedef unsigned char CORBA_boolean;
-#endif
-
-#ifndef __CORBA_OCTET__
-#define __CORBA_OCTET__
- typedef char CORBA_octet;
-#endif
-
-#ifndef CORBA_enum
-#define CORBA_enum enum
-#endif
-
-#ifndef __ERLANG_BINARY__
-#define __ERLANG_BINARY__
- typedef struct {
- CORBA_unsigned_long _maximum;
- CORBA_unsigned_long _length;
- CORBA_octet* _buffer;
- } erlang_binary;
-#endif
-
-
-/* Object definition */
- typedef void* CORBA_Object;
-
-
-/* Exception discriminators */
-#ifndef CORBA_NO_EXCEPTION
-#define CORBA_NO_EXCEPTION 0
-#endif
-
-#ifndef CORBA_SYSTEM_EXCEPTION
-#define CORBA_SYSTEM_EXCEPTION -1
-#endif
-
-#ifndef CORBA_USER_EXCEPTION
-#define CORBA_USER_EXCEPTION -2
-#endif
-
-/* System exceptions */
-
-#define UNKNOWN "UNKNOWN"
-#define BAD_PARAM "BAD_PARAM"
-#define NO_MEMORY "NO_MEMORY"
-#define IMPL_LIMIT "IMP_LIMIT"
-#define COMM_FAILURE "COMM_FAILURE"
-#define INV_OBJREF "INV_OBJREF"
-#define NO_PERMISSION "NO_PERMISSION"
-#define INTERNAL "INTERNAL"
-#define MARSHAL "MARSHAL"
-#define INITIALIZE "INITIALIZE"
-#define NO_IMPLEMENT "NO_IMPLEMENT"
-#define BAD_TYPECODE "BAD_TYPECODE"
-#define BAD_OPERATION "BAD_OPERATION"
-#define NO_RESOURCES "NO_RESOURCES"
-#define NO_RESPONSE "NO_RESPONSE"
-#define PERSIST_STORE "PERSIST_STORE"
-#define BAD_INV_ORDER "BAD_INV_ORDER"
-#define TRANSIENT "TRANSIENT"
-#define FREE_MEM "FREE_MEM"
-#define INV_IDENT "INV_IDENT"
-#define INV_FLAG "INV_FLAG"
-#define INTF_REPOS "INTF_REPOS"
-#define BAD_CONTEXT "BAD_CONTEXT"
-#define OBJ_ADAPTER "OBJ_ADAPTER"
-#define DATA_CONVERSION "DATA_CONVERSION"
-#define OBJ_NOT_EXIST "OBJECT_NOT_EXIST"
-
-
-
-/* Exception type */
- typedef int CORBA_exception_type;
-
-
-#ifndef __CORBA_ENVIRONMENT__
-#define __CORBA_ENVIRONMENT__
-
-/* Environment definition */
- typedef struct {
-
- /*----- CORBA compatibility part ------------------------------------*/
- CORBA_exception_type _major; /* Exception tag, initially set
- to CORBA_NO_EXCEPTION */
-
- /*----- External Implementation part - initiated by the user --------*/
- int _fd; /* File descriptor */
- int _inbufsz; /* Size of input buffer */
- char *_inbuf; /* Pointer to always
- dynamically allocated
- buffer for input */
- int _outbufsz; /* Size of output buffer */
- char *_outbuf; /* Pointer to always
- dynamically
- allocated buffer
- for output */
- int _memchunk; /* Size of memory
- chunks in bytes,
- used for increasing
- the output buffer,
- set to >= 32,
- should be around >=
- 1024 for
- performance reasons */
- char _regname[256]; /* Pointer for
- registered name */
- erlang_pid *_to_pid; /* Process identity
- for caller */
- erlang_pid *_from_pid; /* Process identity
- for callee */
- /*----- Internal Implementation part - used by the server/client ----*/
- int _iin; /* Index for input buffer */
- int _iout; /* Index for output buffer */
- char _operation[256]; /* Pointer for operation name*/
- int _received; /* Used to count parameters */
- erlang_pid _caller; /* Used to identify
- the caller*/
- erlang_ref _unique; /* Used to identify the call */
- CORBA_char *_exc_id; /* Exception id field */
- void *_exc_value; /* Exception value field */
-
- unsigned int _ref_counter_1; /* Counter for reference */
- unsigned int _ref_counter_2; /* Counter for reference */
- unsigned int _ref_counter_3; /* Counter for reference */
-
- } CORBA_Environment;
-
-#endif
-
-
-/* Corba standard functions */
-
- void CORBA_free(void *);
- CORBA_char *CORBA_string_alloc(CORBA_unsigned_long);
- CORBA_wchar *CORBA_wstring_alloc(CORBA_unsigned_long);
- CORBA_char *CORBA_exception_id(CORBA_Environment *env);
- void *CORBA_exception_value(CORBA_Environment *env);
- void CORBA_exception_free(CORBA_Environment *env);
- void CORBA_exc_set(CORBA_Environment *env,
- CORBA_exception_type Major,
- CORBA_char *Id,
- CORBA_char *Value);
- CORBA_Environment *CORBA_Environment_alloc(int inbufsz, int outbufsz);
- void ic_init_ref(CORBA_Environment *env, erlang_ref *ref);
- int ic_compare_refs(erlang_ref *ref1, erlang_ref *ref2);
-
-/* Used internally */
-
-#define __OE_MEMCHUNK__ 1024
-#define __OE_VSNSZ__ 1
-#define __OE_LONGSZ__ 7
-#define __OE_LONGLONGSZ__ 7
-#define __OE_ULONGSZ__ 7
-#define __OE_ULONGLONGSZ__ 7
-#define __OE_DOUBLESZ__ 32
-#define __OE_CHARSZ__ 2
-#define __OE_WCHARSZ__ 7
-#define __OE_TUPLEHDRSZ__ 5
-#define __OE_LISTHDRSZ__ 5
-
-/* The actual size of a wide char (used to be #define __OE_WCHAR_SIZE_OF__ 4) */
-#define __OE_WCHAR_SIZE_OF__ sizeof(CORBA_wchar)
-
-/* Size check macro */
-#define OE_MALLOC_SIZE_CHECK(env,x) { \
- assert((x) > 0); \
- if (!((x) > 0)) { \
- CORBA_exc_set((env), CORBA_SYSTEM_EXCEPTION, INTERNAL, \
- "Bad malloc size calculation"); \
- return -1; \
- } \
-}
-
-/* Exec function -- probably not needed */
- typedef int oe_exec_function_t(CORBA_Object, CORBA_Environment*);
-/* These are for backward compatibility */
- typedef oe_exec_function_t ___exec_function___;
- typedef oe_exec_function_t ___generic___;
-
-/* Operation declaration */
- typedef struct {
- char *interface;
- char *name;
- oe_exec_function_t *function;
- } oe_operation_t;
-
-/* For backward compatibility */
- typedef oe_operation_t ___operation___;
-
-/* Map declaration */
- typedef struct {
- int length;
- oe_operation_t *operations;
- } oe_map_t;
-/* For backward compatibility */
- typedef oe_map_t ___map___;
-
-/* Align macro */
-#define OE_ALIGN(x) (((x) + sizeof(double) - 1) & ~(sizeof(double) - 1))
-
-/* Encoders */
- int oe_ei_encode_version(CORBA_Environment *env);
- int oe_ei_encode_long(CORBA_Environment *env, long p);
- int oe_ei_encode_longlong(CORBA_Environment *env, CORBA_long_long p);
- int oe_ei_encode_ulong(CORBA_Environment *env, unsigned long p);
- int oe_ei_encode_ulonglong(CORBA_Environment *env,
- CORBA_unsigned_long_long p);
- int oe_ei_encode_double(CORBA_Environment *env, double p);
- int oe_ei_encode_char(CORBA_Environment *env, char p);
- int oe_ei_encode_wchar(CORBA_Environment *env, CORBA_wchar p);
- int oe_ei_encode_string(CORBA_Environment *env, const char *p);
- int oe_ei_encode_wstring(CORBA_Environment *env, CORBA_wchar *p);
- int oe_ei_encode_atom(CORBA_Environment *env, const char *p);
- int oe_ei_encode_pid(CORBA_Environment *env, const erlang_pid *p);
- int oe_ei_encode_port(CORBA_Environment *env, const erlang_port *p);
- int oe_ei_encode_ref(CORBA_Environment *env, const erlang_ref *p);
- int oe_ei_encode_term(CORBA_Environment *env, void *t);
- int oe_ei_encode_tuple_header(CORBA_Environment *env, int arity);
- int oe_ei_encode_list_header(CORBA_Environment *env, int arity);
- int oe_encode_erlang_binary(CORBA_Environment *env, erlang_binary *binary);
-
-#define oe_ei_encode_empty_list(ev) oe_ei_encode_list_header(ev,0)
-
-/* Decoders */
- int oe_ei_decode_wchar(const char *buf, int *index, CORBA_wchar *p);
- int oe_ei_decode_wstring(const char *buf, int *index, CORBA_wchar *p);
- int oe_ei_decode_longlong(const char *buf, int *index, CORBA_long_long *p);
- int oe_ei_decode_ulonglong(const char *buf, int *index,
- CORBA_unsigned_long_long *p);
- int oe_decode_erlang_binary(CORBA_Environment *env, char *buf, int *index,
- erlang_binary *binary);
-
-/* Generic client encoders (gen_server protocol) */
- int oe_prepare_notification_encoding(CORBA_Environment *env);
- int oe_prepare_request_encoding(CORBA_Environment *env);
-
-/* Generic client decoders (gen_server protocol) */
- int oe_prepare_reply_decoding(CORBA_Environment *env);
-
-/* Generic client send and receive functions (Erlang distribution protocol) */
- int oe_send_notification(CORBA_Environment *env);
- int oe_send_notification_tmo(CORBA_Environment *env, unsigned int send_ms);
- int oe_send_request_and_receive_reply(CORBA_Environment *env);
- int oe_send_request_and_receive_reply_tmo(CORBA_Environment *env,
- unsigned int send_ms,
- unsigned int recv_ms);
-
-/* Generic server decoder */
- int oe_prepare_request_decoding(CORBA_Environment *env);
-
-/* Generic server encoder */
- int oe_prepare_reply_encoding(CORBA_Environment *env);
-
-/* -------- */
-
-/* Generic server receive (possibly send reply) */
- int oe_server_receive(CORBA_Environment *env, oe_map_t *map);
- int oe_server_receive_tmo(CORBA_Environment *env, oe_map_t *map,
- unsigned int send_ms,
- unsigned int recv_ms);
-
-/* -------- */
-
-/* Size calculators */
- int oe_sizecalc_erlang_binary(CORBA_Environment *env, int *index,
- int *size);
-/* Print functions */
- int print_erlang_binary(erlang_binary*);
-
-/* Length counter for wide strings */
- int ic_wstrlen(CORBA_wchar * p);
-
-/* Wide string comparison */
- int ic_wstrcmp(CORBA_wchar * ws1, CORBA_wchar * ws2);
-
-/* Put for 64-bits integer type */
-#define put64le(s,n) do { \
- (s)[0] = (n) & 0xff; \
- (s)[1] = ((n) >> 8) & 0xff; \
- (s)[2] = ((n) >> 16) & 0xff; \
- (s)[3] = ((n) >> 24) & 0xff; \
- (s)[4] = ((n) >> 32) & 0xff; \
- (s)[5] = ((n) >> 40) & 0xff; \
- (s)[6] = ((n) >> 48) & 0xff; \
- (s)[7] = ((n) >> 56) & 0xff; \
- (s)[8] = ((n) >> 64) & 0xff; \
- (s) += 8; \
-} while (0)
-
-/* Get for 64-bits integer type */
-#define get64le(s) \
- ((s) += 8, \
- ((((unsigned char *)(s))[-1] << 56) | \
- (((unsigned char *)(s))[-2] << 48) | \
- (((unsigned char *)(s))[-3] << 40) | \
- (((unsigned char *)(s))[-4] << 32) | \
- (((unsigned char *)(s))[-5] << 24) | \
- (((unsigned char *)(s))[-6] << 16) | \
- (((unsigned char *)(s))[-7] << 8) | \
- ((unsigned char *)(s))[-8]))
-
-
-
-/* Exec function switch */
- int oe_exec_switch(CORBA_Object, CORBA_Environment*, oe_map_t*);
-/* For backward compatibility */
- int ___switch___(CORBA_Object, CORBA_Environment*, oe_map_t*);
-
-/* For backward compatibility -- replaced by oe_prepare_request_decoding() */
- int ___call_info___(CORBA_Object, CORBA_Environment*);
-
-/* Map merging */
- oe_map_t* oe_merge_maps(oe_map_t*, int);
-/* For backward compatibility */
- oe_map_t* ___merge___(oe_map_t*, int);
-
-/* Macro for error reporting */
-
-#ifdef OE_C_REPORT
-#define OE_RPT_ERR(x) fprintf(stderr, (x))
-#else
-#define OE_RPT_ERR(x)
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/lib/ic/info b/lib/ic/info
deleted file mode 100644
index 96cb88d01f..0000000000
--- a/lib/ic/info
+++ /dev/null
@@ -1,2 +0,0 @@
-group: orb Object Request Broker & IDL Applications
-short: IDL compiler
diff --git a/lib/ic/internal_doc/c-improvements-1.txt b/lib/ic/internal_doc/c-improvements-1.txt
deleted file mode 100644
index ccfdec7cbe..0000000000
--- a/lib/ic/internal_doc/c-improvements-1.txt
+++ /dev/null
@@ -1,84 +0,0 @@
-Peter Hogfeldt 2003-08-14 PA1
-
-IC C BACK-ENDS IMPROVEMENTS
-
-1 C CLIENT
-
-1.1 Cast
-
- Each oneway operation roughly consists of the following code
- parts:
-
- - encoding the cast message
- - setting index of the out buffer to zero (1.1.1)
- - encoding the magic (1.1.1)
- - encoding a tuple header of size 2 (1.1.1)
- - encoding '$gen_cast' (1.1.1)
- - encoding the operation parameters (1.1.2)
- - sending the cast message (1.1.3)
-
- Only (1.1.2) is unique for the operation in question.
-
-1.1.1 Todo
-
- Define functions:
-
- int oe_ei_encode_cast(CORBA_environment *) that performs (1.1.1)
-
- int oe_ei_cast(CORBA_environment *) that performs (1.1.3)
-
- This will reduce code size.
-
- As compiler options
-
- oe_ei_encode_cast(), and
- oe_ei_cast()
-
- may be replaced by user defined functions.
-
-1.2 Call
-
- Each (non-oneway) operation roughly consists of the following code
- parts:
-
- - encoding the call message
- - setting index of the out buffer to zero (1.2.1)
- - encoding the magic (1.2.1)
- - encoding a tuple header of size 3 (1.2.1)
- - encoding '$gen_call' (1.2.1)
- - encoding a tuple header of size 2 (1.2.1)
- - encoding the from pid (1.2.1)
- - encoding the unique ref (1.2.1)
- - encoding the operation parameters (1.2.2)
- - sending the call message (1.2.3)
- - receiving the reply message (1.2.3)
- - decoding the reply parameters (1.2.4)
-
- Only (1.2.2) and (1.2.4) are unique for the operation in question.
-
-1.2.1 Todo
-
- Define functions:
-
- int oe_ei_encode_send(CORBA_environment *) that performs (1.2.1)
-
- int oe_ei_send_and_receive(CORBA_environment *) that performs (1.2.3)
-
- This will reduce code size.
-
- As compiler options
-
- oe_ei_encode_send(), and
- oe_ei_send_and_receive()
-
- may be replaced by user defined function.
-
-
-2 SERVER
-
- We do not provide any code for receiving operation messages, execute
- operations, and send the result back. Should we not do that?
-
-
-
- \ No newline at end of file
diff --git a/lib/ic/internal_doc/protocol.txt b/lib/ic/internal_doc/protocol.txt
deleted file mode 100644
index 54e1ef55cf..0000000000
--- a/lib/ic/internal_doc/protocol.txt
+++ /dev/null
@@ -1,182 +0,0 @@
-Peter Hogfeldt 2003-08-18 PA3
-
-THE IC PROTOCOL
-
-1 INTRODUCTION
-
- The IDL Compiler (IC) transforms Interface Definition Language
- (IDL) specifications files to interface code for Erlang, C, and
- Java. The Erlang language mapping is described in the Orber
- documentation, while the other mappings are described in the IC
- documentation (they are of course in accordance with the CORBA C
- and Java language mapping specifications, with some restrictions).
-
- The most important parts of an IDL specification are the operation
- declarations. An operation defines what information a client
- provides to a server, and what information (if any) the client
- gets back from the server. We consider IDL operations and language
- mappings in section 2.
-
- What we here call the IC protocol, is the description of messages
- exchanged between IC end-points (client and servers). It is valid
- for all IC back-ends, except the 'erl_plain' and 'erl_corba'
- back-ends. The protocol is described in section 3.
-
- The IC protocol is in turn embedded into the Erlang gen_server
- protocol, which is described in section 4.
-
- Finally, the gen_server protocol is embedded in the Erlang
- distribution protocol. Pertinent parts of that protocol is
- described in section 5.
-
-
-2 LANGUAGE MAPPINGS AND IDL OPERATIONS
-
-2.1 IDL Operations
-
- An IDL operation is declared as follows:
-
- [oneway] RetType Op(in IType1 I1, in IType2 I2, ..., in ITypeN IN,
- out OType1 O1, out OType2 O2, ..., out OTypeM OM)
- N, M = 0, 1, 2, ... (2.1.1)
-
- `Op' is the operation name, RetType is the return type, and ITypei,
- i = 1, 2, ..., N, and OTypej, j = 1, 2, ..., M, are the `in' types
- and `out' types, respectively. The values I1, I2, ..., IN are
- provided by the caller, and the value of RetType, and the values
- O1, O2, ..., OM, are provided as results to the caller.
-
- The types can be any basic types or derived types declared in the
- IDL specification of which the operation declaration is a part.
-
- If the RetType has the special name `void' there is no return
- value (but there might still be result values O1, 02, ..., OM).
-
- The `in' and `out' parameters can be declared in any order, but
- for clarity we have listed all `in' parameters before the `out'
- parameters in the declaration above.
-
- If the keyword `oneway' is present, the operation is a cast, i.e.
- there is no confirmation of the operation, and consequently there
- must be no result values: RetType must be equal to `void', and M =
- 0 must hold.
-
- Otherwise the operation is a call, i.e. it is confirmed (or else
- an exception is raised).
-
- Note carefully that an operation declared without `oneway' is
- always a call, even if RetType is `void' and M = 0.
-
-2.2 Language Mappings
-
- There are several CORBA Language Mapping specifications. These are
- about mapping interfaces to various programming languages. IC
- supports the CORBA C and Java mapping specifications, and the
- Erlang language mapping specified in the Orber documentation.
-
- Excerpt from "6.4 Basic OMG IDL Types" in the Orber User's Guide:
-
- Functions with return type void will return the atom ok.
-
- Excerpt from "6.13 Invocations of Operations" in the Orber User's Guide:
-
- A function call will invoke an operation. The first parameter
- of the function should be the object reference and then all in
- and inout parameters follow in the same order as specified in
- the IDL specification. The result will be a return value
- unless the function has inout or out parameters specified; in
- which case, a tuple of the return value, followed by the
- parameters will be returned.
-
- Hence the function that is mapped from an IDL operation to Erlang
- always have a return value (an Erlang function always has). That
- fact has influenced the IC protocol, in that there is always a
- return value (which is 'ok' if the return type was declared 'void').
-
-
-3 IC PROTOCOL
-
- Given the operation declaration (2.1.1) the IC protocol maps to
- messages as follows, defined in terms of Erlang terms.
-
-3.1 Call (Request/Reply, i.e. not oneway)
-
- request: Op atom() N = 0
- {Op, I1, I2, ..., IN} tuple() N > 0
- (3.1.1)
-
- reply: Ret M = 0
- {Ret, O1, O2, ..., OM} M > 0
- (3.1.2)
-
- Notice; Even if the RetType of the operation Op is declared to be
- 'void', a return value 'ok' is returned in the reply message. That
- return value is of no significance, and is therefore ignored (note
- however that a C server back-end returns the atom 'void' instead
- of 'ok').
-
-3.2 Cast (oneway)
-
- notification: Op atom() N = 0
- {Op, I1, I2, ..., IN} tuple() N > 0
- (3.2.1)
- (There is of course no return message).
-
-3.3 Propagation of Exceptions
-
- Currently there is no propagation of exceptions from the server to
- the client. As it is now a an exception detected by the server
- will hang the client in a receive. That is unacceptable.
-
- Exception propagation is only meaningful for Call (request/reply).
-
-
-4 GEN_SERVER PROTOCOL
-
- Most of the IC generated code deals with encoding and decoding the
- gen_server protocol.
-
-4.1 Call
-
- request: {'$gen_call', {self(), Ref}, Request} (4.1.1)
-
- reply: {Ref, Reply} (4.1.2)
-
- where Request and Reply are the messages defined in 3.1 Call.
-
-4.2 Cast
-
- notification: {'$gen_cast', Notification} (4.2.1)
-
- where Notification is the message defined in 3.2 Cast.
-
-
-5 ERLANG DISTRIBUTION PROTOCOL
-
- Messages (of interest here) between Erlang nodes are of the form:
-
- Len(4), Type(1), CtrlBin(N), MsgBin(M) (5.1)
-
- Type is equal to 112 = PASS_THROUGH.
-
- CtrlBin and MsgBin are Erlang terms in binary form (as if created
- by term_to_binary/1), whence for each of them the first byte is
- equal to 131 = VERSION_MAGIC.
-
- CtrlBin (of interest here) contains the SEND and REG_SEND control
- messages, which are binary forms of the Erlang terms
-
- {2, Cookie, ToPid} , (5.2)
-
- and
-
- {6, FromPid, Cookie, ToName} , (5.3)
-
- respectively.
-
- The CtrlBin(N) message is read and written by erl_interface code
- (C), j_interface code (Java), or the Erlang distribution
- implementation, which are invoked from IC generated code.
-
- The MsgBin(N) is the "real" message, i.e. of the form described
- in section 4.
diff --git a/lib/ic/java_src/Makefile b/lib/ic/java_src/Makefile
deleted file mode 100644
index 86d1e54fff..0000000000
--- a/lib/ic/java_src/Makefile
+++ /dev/null
@@ -1,42 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1999-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(ORBER_VSN)
-
-# ----------------------------------------------------
-# Common Macros
-# ----------------------------------------------------
-
-SUB_DIRECTORIES = com/ericsson/otp/ic
-
-SPECIAL_TARGETS =
-
-# ----------------------------------------------------
-# Default Subdir Targets
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_subdir.mk
-
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/Any.java b/lib/ic/java_src/com/ericsson/otp/ic/Any.java
deleted file mode 100644
index d90b942877..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/Any.java
+++ /dev/null
@@ -1,1026 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-package com.ericsson.otp.ic;
-
-
-/**
-
-The Any class is the java mapping of the any OMG-IDL type.
-
-
-**/
-
-
-public class Any {
-
- // Typecode value holder
- protected TypeCode tcV;
-
- // Primitive value holder
- protected java.lang.String stringV;
- protected byte byteV;
- protected boolean booleanV;
- protected char charV;
- protected short shortV;
- protected int intV;
- protected long longV;
- protected float floatV;
- protected double doubleV;
-
- // Streams used for user defined types
- protected com.ericsson.otp.erlang.OtpInputStream is;
- protected com.ericsson.otp.erlang.OtpOutputStream os;
-
-
- // Constructor
- public Any() {
- tcV = null;
- }
-
- // Equal function
-
- /**
- Any comparison method
- @return true if the input Any is equal to the object, false otherwize
- **/
- public boolean equal(com.ericsson.otp.ic.Any _any) {
-
- int _is1Len,_is2Len;
- byte _compressed[];
- com.ericsson.otp.erlang.OtpInputStream _is1,_is2;
- TypeCode _tc = _any.type();
-
- if (!tcV.equal(_tc))
- return false;
-
- try {
-
- TCKind _tck = _tc.kind();
-
- switch (_tck.value()) {
-
- case TCKind._tk_short:
- return (_any.extract_short() == shortV);
-
- case TCKind._tk_ushort:
- return (_any.extract_ushort() == shortV);
-
- case TCKind._tk_long:
- return (_any.extract_long() == intV);
-
- case TCKind._tk_longlong:
- return (_any.extract_longlong() == longV);
-
- case TCKind._tk_ulong:
- return (_any.extract_ulong() == intV);
-
- case TCKind._tk_ulonglong:
- return (_any.extract_ulonglong() == longV);
-
- case TCKind._tk_float:
- return equal(_any.extract_float(),floatV);
-
- case TCKind._tk_double:
- return equal(_any.extract_double(),doubleV);
-
- case TCKind._tk_boolean:
- return (_any.extract_boolean() == booleanV);
-
- case TCKind._tk_char:
- return (_any.extract_char() == charV);
-
- case TCKind._tk_wchar:
- return (_any.extract_wchar() == charV);
-
- case TCKind._tk_octet:
- return (_any.extract_octet() == byteV);
-
- case TCKind._tk_string:
- return (_any.extract_string().compareTo(stringV) == 0);
-
- case TCKind._tk_wstring:
- return (_any.extract_wstring().compareTo(stringV) == 0);
-
- case TCKind._tk_sequence:
-
- _is1 = new com.ericsson.otp.erlang.OtpInputStream(os.toByteArray());
-
- _is2 = _any.extract_Streamable();
-
- if (_is1.peek() != _is2.peek()) {
-
- // _is1's sequence is compressed to string
- if(_is1.peek() == com.ericsson.otp.erlang.OtpExternal.stringTag) {
-
- _compressed = (_is1.read_string()).getBytes();
- _is1Len = _compressed.length;
-
- _is2.read_list_head();
-
- for(int i = 0; i < _is1Len; i++) {
- if ((long)(_compressed[i] & 0xff) != _is2.read_long())
- return false;
- }
-
- _is2.read_nil();
- }
- else { // _is2's sequence is compressed to string
-
- _compressed = (_is2.read_string()).getBytes();
- _is2Len = _compressed.length;
-
- _is1.read_list_head();
-
- for(int i = 0; i < _is2Len; i++)
- if ((long)(_compressed[i] & 0xff) != _is1.read_long())
- return false;
-
- _is1.read_nil();
- }
- }
- else { // None of them is compressed
-
- _is2Len = _is2.available();
-
- if (_is1.available() != _is2Len)
- return false;
-
- for(int i = 0; i < _is2Len; i++) {
- if (_is1.read() != _is2.read())
- return false;
- }
- }
-
- return true;
-
- case TCKind._tk_struct:
- case TCKind._tk_union:
- case TCKind._tk_array:
- case TCKind._tk_enum:
-
- _is1 = new com.ericsson.otp.erlang.OtpInputStream(os.toByteArray());
-
- _is2 = _any.extract_Streamable();
-
- _is2Len = _is2.available();
-
- if (_is1.available() != _is2Len)
- return false;
-
- for(int i = 0; i < _is2Len; i++) {
- if (_is1.read() != _is2.read())
- return false;
- }
-
- return true;
-
- // Not used in real
- case TCKind._tk_any:
- case TCKind._tk_void:
- case TCKind._tk_atom:
- case TCKind._tk_null:
- case TCKind._tk_TypeCode:
- case TCKind._tk_Principal:
- case TCKind._tk_objref:
- case TCKind._tk_alias:
- case TCKind._tk_except:
- case TCKind._tk_longdouble:
- case TCKind._tk_fixed:
- return true;
-
- default :
- return false;
-
- }
- } catch (Exception e) {
- //e.printStackTrace();
- return false;
- }
-
- }
-
-
- /* Equal function for floats ( relative diff ) */
- boolean equal(float x, float y) {
-
- if (x != 0)
- return (java.lang.Math.abs((x-y)/x) < 1.0E-15);
-
- if (y != 0)
- return (java.lang.Math.abs((y-x)/y) < 1.0E-15);
-
- return (x==y);
- }
-
- /* Equal function for doubles ( relative diff ) */
- boolean equal(double x, double y) {
-
- if (x != 0)
- return (java.lang.Math.abs((x-y)/x) < 1.0E-15);
-
- if (y != 0)
- return (java.lang.Math.abs((y-x)/y) < 1.0E-15);
-
- return (x==y);
- }
-
-
-
- /**
- TypeCode accessor method
- @return the Any's TypeCode
- **/
- public TypeCode type() {
- return tcV;
- }
-
-
- /**
- TypeCode insertion method
- **/
- public void type(TypeCode _tc) {
- tcV = _tc;
- }
-
-
- /* Value accessors */
-
- /**
- Reads a value from the stream, according to the inserted TypeCode
- **/
- public void read_value(com.ericsson.otp.erlang.OtpInputStream _is,
- TypeCode _tc)
- throws java.lang.Exception {
-
- tcV = _tc;
-
- switch(tcV.kind().value()) {
-
- case TCKind._tk_short :
- shortV = _is.read_short();
- break;
- case TCKind._tk_ushort :
- shortV = _is.read_ushort();
- break;
- case TCKind._tk_long :
- intV = _is.read_int();
- break;
- case TCKind._tk_ulong :
- intV = _is.read_uint();
- break;
- case TCKind._tk_longlong :
- longV = _is.read_long();
- break;
- case TCKind._tk_ulonglong :
- longV = _is.read_ulong();
- break;
- case TCKind._tk_float :
- floatV = _is.read_float();
- break;
- case TCKind._tk_double :
- doubleV = _is.read_double();
- break;
- case TCKind._tk_boolean :
- booleanV = _is.read_boolean();
- break;
- case TCKind._tk_char :
- case TCKind._tk_wchar :
- charV = _is.read_char();
- break;
- case TCKind._tk_octet :
- byteV = _is.read_byte();
- break;
- case TCKind._tk_string :
- case TCKind._tk_wstring :
- stringV = _is.read_string();
- break;
- case TCKind._tk_atom :
- stringV = _is.read_atom();
- break;
- case TCKind._tk_void :
- _is.read_atom();
- break;
-
- /*
- * Not supported types
- */
- case TCKind._tk_any :
- case TCKind._tk_null :
- case TCKind._tk_TypeCode :
- case TCKind._tk_Principal :
- case TCKind._tk_objref :
- case TCKind._tk_alias :
- case TCKind._tk_except :
- case TCKind._tk_longdouble :
- case TCKind._tk_fixed :
- throw new java.lang.Exception("Unsupported type");
-
- default: // User defined type
-
- if (os == null)
- os = new com.ericsson.otp.erlang.OtpOutputStream();
- else
- os.reset();
-
- try {
- read_user_defined(_is, _tc);
- is = new com.ericsson.otp.erlang.OtpInputStream(os.toByteArray());
- } catch (Exception e) {
- throw new java.lang.Exception("BAD VALUE");
- }
- }
-
- }
-
- void read_user_defined(com.ericsson.otp.erlang.OtpInputStream _is, TypeCode _tc)
- throws java.lang.Exception {
-
- TypeCode memberTC = null;
- int len = -1;
- int __tag;
-
- switch(_tc.kind().value()) {
-
- case TCKind._tk_short :
- os.write_short(_is.read_short());
- break;
- case TCKind._tk_ushort :
- os.write_ushort(_is.read_ushort());
- break;
- case TCKind._tk_long :
- os.write_int(_is.read_int());
- break;
- case TCKind._tk_longlong :
- os.write_long(_is.read_long());
- break;
- case TCKind._tk_ulong :
- os.write_uint(_is.read_uint());
- break;
- case TCKind._tk_ulonglong :
- os.write_ulong(_is.read_ulong());
- break;
- case TCKind._tk_float :
- os.write_float(_is.read_float());
- break;
- case TCKind._tk_double :
- os.write_double(_is.read_double());
- break;
- case TCKind._tk_boolean :
- os.write_boolean(_is.read_boolean());
- break;
- case TCKind._tk_char :
- case TCKind._tk_wchar :
- os.write_char(_is.read_char());
- break;
- case TCKind._tk_octet :
- os.write_byte(_is.read_byte());
- break;
- case TCKind._tk_string :
- case TCKind._tk_wstring :
- os.write_string(_is.read_string());
- break;
-
- case TCKind._tk_struct:
- len = _is.read_tuple_head();
- os.write_tuple_head(len);
- os.write_atom(_is.read_atom());
- // Member list
- len -=1;
- for(int i=0; i<len; i++)
- read_user_defined(_is,_tc.member_type(i));
- break;
-
- case TCKind._tk_union:
- os.write_tuple_head(_is.read_tuple_head());
- os.write_atom(_is.read_atom());
-
- int __mlen = _tc.member_count();
- __tag = _is.peek();
- boolean __found = false;
-
- switch (__tag) {
- case (com.ericsson.otp.erlang.OtpExternal.atomTag):
- case (com.ericsson.otp.erlang.OtpExternal.atomUtf8Tag):
- case (com.ericsson.otp.erlang.OtpExternal.smallAtomUtf8Tag):
- java.lang.String __elabel = _is.read_atom(); // Enumerant or Boolean
- os.write_atom(__elabel);
-
- for (int i=0; i<__mlen; i++) {
- java.lang.String __mlabel;
- if (_tc.member_label(i).type().kind().value() == TCKind._tk_string)
- __mlabel = _tc.member_label(i).extract_string();
- else // Default
- __mlabel = _tc.member_label(i).extract_atom();
-
- if (__elabel.compareTo(__mlabel)==0) {
- read_user_defined(_is,_tc.member_type(i));
- i = __mlen;
- __found = true;
- }
- }
- break;
-
- default: // Integer type
- long __ilabel = _is.read_long();
- os.write_long(__ilabel);
-
- for (int i=0; i<__mlen; i++) {
- boolean __itype = true;
- long __mlabel = 0;
-
- switch (_tc.member_label(i).type().kind().value()) {
-
- case TCKind._tk_short :
- __mlabel = _tc.member_label(i).extract_short();
- break;
- case TCKind._tk_ushort :
- __mlabel = _tc.member_label(i).extract_ushort();
- break;
- case TCKind._tk_long :
- __mlabel = _tc.member_label(i).extract_long();
- break;
- case TCKind._tk_longlong :
- __mlabel = _tc.member_label(i).extract_longlong();
- break;
- case TCKind._tk_ulong :
- __mlabel = _tc.member_label(i).extract_ulong();
- break;
- case TCKind._tk_ulonglong :
- __mlabel = _tc.member_label(i).extract_ulonglong();
- break;
- case TCKind._tk_char :
- __mlabel = _tc.member_label(i).extract_char();
- break;
- case TCKind._tk_wchar :
- __mlabel = _tc.member_label(i).extract_wchar();
- break;
-
- default : // Default label
- __itype = false;
-
- }
-
- if (__itype) {
- if (__ilabel == __mlabel) {
- read_user_defined(_is,_tc.member_type(i));
- i = __mlen;
- __found = true;
- }
- }
- }
- }
-
- // Use the default label instead
- if (!__found)
- read_user_defined(_is,_tc.member_type(_tc.default_index()));
-
- break;
-
- case TCKind._tk_sequence:
- __tag = _is.peek();
-
- switch(__tag) {
- case com.ericsson.otp.erlang.OtpExternal.stringTag:
- os.write_string(_is.read_string());
- break;
- default:
- len = _is.read_list_head();
- os.write_list_head(len);
-
- for (int i=0; i<len; i++)
- read_user_defined(_is,_tc.content_type());
-
- _is.read_nil();
- os.write_nil();
- }
- break;
-
- case TCKind._tk_array:
- len = _is.read_tuple_head();
- os.write_tuple_head(len);
- for (int i=0; i<len; i++)
- read_user_defined(_is,_tc.content_type());
- break;
-
- case TCKind._tk_enum:
- os.write_atom(_is.read_atom());
- break;
-
- case TCKind._tk_void :
- os.write_atom(_is.read_atom());
- break;
-
- case TCKind._tk_any :
- AnyHelper.marshal(os,AnyHelper.unmarshal(_is));
- break;
-
- /*
- * Not supported types
- */
- default :
- throw new java.lang.Exception("");
-
- }
-
- }
-
-
- /**
- Writes the Any's value to the ouput stream
- **/
- public void write_value(com.ericsson.otp.erlang.OtpOutputStream _os)
- throws java.lang.Exception {
-
- switch(tcV.kind().value()) {
-
- case TCKind._tk_short :
- _os.write_short(shortV);
- break;
- case TCKind._tk_ushort :
- _os.write_ushort(shortV);
- break;
- case TCKind._tk_long :
- _os.write_int(intV);
- break;
- case TCKind._tk_ulong :
- _os.write_uint(intV);
- break;
- case TCKind._tk_longlong :
- _os.write_long(longV);
- break;
- case TCKind._tk_ulonglong :
- _os.write_ulong(longV);
- break;
- case TCKind._tk_float :
- _os.write_float(floatV);
- break;
- case TCKind._tk_double :
- _os.write_double(doubleV);
- break;
- case TCKind._tk_boolean :
- _os.write_boolean(booleanV);
- break;
- case TCKind._tk_char :
- case TCKind._tk_wchar :
- _os.write_char(charV);
- break;
- case TCKind._tk_octet :
- _os.write_byte(byteV);
- break;
- case TCKind._tk_string :
- case TCKind._tk_wstring :
- _os.write_string(stringV);
- break;
- case TCKind._tk_atom :
- _os.write_atom(stringV);
- break;
- case TCKind._tk_void :
- _os.write_atom("ok");
- break;
-
- /*
- * Not supported types
- */
- case TCKind._tk_any :
- case TCKind._tk_null :
- case TCKind._tk_TypeCode :
- case TCKind._tk_Principal :
- case TCKind._tk_objref :
- case TCKind._tk_alias :
- case TCKind._tk_except :
- case TCKind._tk_longdouble :
- case TCKind._tk_fixed :
- throw new java.lang.Exception("BAD KIND");
-
- default:
- _os.write(os.toByteArray());
- }
- }
-
-
- /*
- * Insert and extract each primitive type
- */
-
- /* short */
-
- /**
- Short value extractor method
- @return short, the value of Any
- **/
- public short extract_short()
- throws java.lang.Exception {
- if (tcV.kind() == TCKind.tk_short)
- return shortV;
-
- throw new java.lang.Exception("");
- }
-
- /**
- Short value insertion method
- **/
- public void insert_short(short s) {
- shortV = s;
- tcV = new TypeCode(TCKind.tk_short);
- };
-
-
- /* long */
- /**
- Long value extractor method
- @return int, the value of Any
- **/
- public int extract_long()
- throws java.lang.Exception {
- if (tcV.kind() == TCKind.tk_long)
- return intV;
-
- throw new java.lang.Exception("");
- }
-
- /**
- Long value insertion method
- **/
- public void insert_long(int i){
- intV = i;
- tcV = new TypeCode(TCKind.tk_long);
- }
-
-
-
- /* long long */
- /**
- Long Long value extractor method
- @return long, the value of Any
- **/
- public long extract_longlong()
- throws java.lang.Exception {
- if (tcV.kind() == TCKind.tk_longlong)
- return longV;
-
- throw new java.lang.Exception("");
- }
-
- /**
- Long Long value insertion method
- **/
- public void insert_longlong(long l){
- longV = l;
- tcV = new TypeCode(TCKind.tk_longlong);
- }
-
-
- /* ushort */
- /**
- Unsigned Short value extractor method
- @return short, the value of Any
- **/
- public short extract_ushort()
- throws java.lang.Exception {
- if (tcV.kind() == TCKind.tk_ushort)
- return shortV;
-
- throw new java.lang.Exception("");
- }
-
- /**
- Unsigned Short value insertion method
- **/
- public void insert_ushort(short s){
- shortV = s;
- tcV = new TypeCode(TCKind.tk_ushort);
- }
-
-
- /* ulong */
-
- /**
- Unsigned Long value extractor method
- @return int, the value of Any
- **/
- public int extract_ulong()
- throws java.lang.Exception{
- if (tcV.kind() == TCKind.tk_ulong)
- return intV;
-
- throw new java.lang.Exception("");
- }
-
- /**
- Unsigned Long value insertion method
- **/
- public void insert_ulong(int i){
- intV = i;
- tcV = new TypeCode(TCKind.tk_ulong);
- }
-
-
-
-
- /* unsigned long long */
- /**
- Unsigned Long Long value extractor method
- @return long, the value of Any
- **/
- public long extract_ulonglong()
- throws java.lang.Exception {
- if (tcV.kind() == TCKind.tk_ulonglong)
- return longV;
-
- throw new java.lang.Exception("");
- }
-
- /**
- Unsigned Long Long value insertion method
- **/
- public void insert_ulonglong(long l){
- longV = l;
- tcV = new TypeCode(TCKind.tk_ulonglong);
- }
-
-
- /* float */
- /**
- Float value extractor method
- @return float, the value of Any
- **/
- public float extract_float()
- throws java.lang.Exception{
- if (tcV.kind() == TCKind.tk_float)
- return floatV;
-
- throw new java.lang.Exception("");
- }
-
- /**
- Float value insertion method
- **/
- public void insert_float(float f){
- floatV = f;
- tcV = new TypeCode(TCKind.tk_float);
- }
-
-
- /* double */
- /**
- Double value extractor method
- @return double, the value of Any
- **/
- public double extract_double()
- throws java.lang.Exception{
- if (tcV.kind() == TCKind.tk_double)
- return doubleV;
-
- throw new java.lang.Exception("");
- }
-
- /**
- Double value insertion method
- **/
- public void insert_double(double d){
- doubleV = d;
- tcV = new TypeCode(TCKind.tk_double);
- }
-
-
- /* boolean */
- /**
- Boolean value extractor method
- @return boolean, the value of Any
- **/
- public boolean extract_boolean()
- throws java.lang.Exception{
- if (tcV.kind() == TCKind.tk_boolean)
- return booleanV;
-
- throw new java.lang.Exception("");
- }
-
- /**
- Boolean value insertion method
- **/
- public void insert_boolean(boolean b){
- booleanV = b;
- tcV = new TypeCode(TCKind.tk_boolean);
- }
-
-
-
- /* char */
- /**
- Char value extractor method
- @return char, the value of Any
- **/
- public char extract_char()
- throws java.lang.Exception{
- if (tcV.kind() == TCKind.tk_char)
- return charV;
-
- throw new java.lang.Exception("");
- }
-
- /**
- Char value insertion method
- **/
- public void insert_char(char c) {
- charV = c;
- tcV = new TypeCode(TCKind.tk_char);
- }
-
-
- /* wchar */
- /**
- Wchar value extractor method
- @return char, the value of Any
- **/
- public char extract_wchar()
- throws java.lang.Exception{
- if (tcV.kind() == TCKind.tk_wchar)
- return charV;
-
- throw new java.lang.Exception("");
- }
-
- /**
- Wchar value insertion method
- **/
- public void insert_wchar(char c) {
- charV = c;
- tcV = new TypeCode(TCKind.tk_wchar);
- }
-
-
-
- /* octet */
- /**
- Octet value extractor method
- @return byte, the value of Any
- **/
- public byte extract_octet()
- throws java.lang.Exception{
- if (tcV.kind() == TCKind.tk_octet)
- return byteV;
-
- throw new java.lang.Exception("");
- }
-
- /**
- Octet value insertion method
- **/
- public void insert_octet(byte b){
- byteV = b;
- tcV = new TypeCode(TCKind.tk_octet);
- }
-
-
- /* string */
- /**
- String value extractor method
- @return String, the value of Any
- **/
- public java.lang.String extract_string()
- throws java.lang.Exception{
- if (tcV.kind() == TCKind.tk_string)
- return stringV;
-
- throw new java.lang.Exception("");
- }
-
- /**
- String value insertion method
- **/
- public void insert_string(java.lang.String s) {
- stringV = s;
- tcV = new TypeCode(TCKind.tk_string);
- }
-
-
-
- /* wstring */
- /**
- Wstring value extractor method
- @return String, the value of Any
- **/
- public java.lang.String extract_wstring()
- throws java.lang.Exception{
- if (tcV.kind() == TCKind.tk_wstring)
- return stringV;
-
- throw new java.lang.Exception("");
- }
-
- /**
- Wstring value insertion method
- **/
- public void insert_wstring(java.lang.String s) {
- stringV = s;
- tcV = new TypeCode(TCKind.tk_wstring);
- }
-
-
-
- /* atom */
- /**
- Atom value extractor method
- @return atom, the value of Any
- **/
- public java.lang.String extract_atom()
- throws java.lang.Exception{
- if (tcV.kind() == TCKind.tk_atom)
- return stringV;
-
- throw new java.lang.Exception("");
- }
-
- /**
- Atom value insertion method
- **/
- public void insert_atom(java.lang.String s) {
- stringV = s;
- tcV = new TypeCode(TCKind.tk_atom);
- }
-
-
- /**
- Object Stream insertion method
- **/
- public void insert_Streamable(com.ericsson.otp.erlang.OtpOutputStream _os) {
- os = _os;
- }
-
- /**
- Object Stream extractor method
- @return OtpInputStream, the stream value of Any
- **/
- public com.ericsson.otp.erlang.OtpInputStream extract_Streamable() {
-
- if (is == null) {
- if (os == null)
- return null;
- else {
- is = new com.ericsson.otp.erlang.OtpInputStream(os.toByteArray());
- }
- }
-
- is.reset();
- return is;
- }
-
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/AnyHelper.java b/lib/ic/java_src/com/ericsson/otp/ic/AnyHelper.java
deleted file mode 100644
index 518087a1ed..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/AnyHelper.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-package com.ericsson.otp.ic;
-
-/**
-
-Helper class for Any, according to OMG-IDL java mapping.
-<p>Instead for write,read methods, the methods marshal respective
-unmarshal are used to denote the implementation difference.
-
-**/
-
-
-public class AnyHelper {
-
- // Constructors
- private AnyHelper() {}
-
- // Methods
- /**
- Marshal method for the Any class, encodes the Any object to the output stream.
- **/
- public static void marshal(com.ericsson.otp.erlang.OtpOutputStream _out, Any _any)
- throws java.lang.Exception {
-
- TypeCode _tc = _any.type();
-
- _out.write_tuple_head(3);
- _out.write_atom("any");
-
- TypeCode.marshal(_out, _tc);
- _any.write_value(_out);
-
- }
-
- /**
- Unmarshal method for the Any class, decodes an Any object from the stream.
- @return Any, read from the input stream
- **/
- public static Any unmarshal(com.ericsson.otp.erlang.OtpInputStream _in)
- throws java.lang.Exception {
-
- Any _value;
- TypeCode _tc;
-
- _in.read_tuple_head();
-
- if ((_in.read_atom()).compareTo("any") != 0)
- throw new java.lang.Exception("");
-
- _tc = TypeCode.unmarshal(_in);
- _value = new Any();
- _value.read_value(_in,_tc);
-
- return _value;
- }
-
-}
-
-
-
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/AnyHolder.java b/lib/ic/java_src/com/ericsson/otp/ic/AnyHolder.java
deleted file mode 100644
index e22876f51e..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/AnyHolder.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-package com.ericsson.otp.ic;
-
-/**
-
-Holder class for Any, according to OMG-IDL java mapping.
-<p>Instead for _write,_read methods, the methods _marshal respective
-_unmarshal are used to denote the implementation difference.
-
-**/
-
-final public class AnyHolder {
-
- // Instance variables
- public Any value;
-
- // Constructors
- public AnyHolder() {}
-
- public AnyHolder(Any initial) {
- value = initial;
- }
-
- // Methods
- /**
- Marshal method for the Any class, encodes the Any object to the output stream.
- **/
- public void _marshal(com.ericsson.otp.erlang.OtpOutputStream out)
- throws java.lang.Exception {
- AnyHelper.marshal(out, value);
- }
-
- /**
- Unmarshal method for the Any class, decodes an Any object from the stream and
- assigns it to the Holder value.
- **/
- public void _unmarshal(com.ericsson.otp.erlang.OtpInputStream in)
- throws java.lang.Exception {
- value = AnyHelper.unmarshal(in);
- }
-
-}
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/BooleanHolder.java b/lib/ic/java_src/com/ericsson/otp/ic/BooleanHolder.java
deleted file mode 100644
index b71da196de..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/BooleanHolder.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-/**
- * A Holder class for IDL's out/inout argument passing modes for boolean
- *
- */
-package com.ericsson.otp.ic;
-
-/**
-
-Holder class for Boolean, according to OMG-IDL java mapping.
-
-**/
-
-
-final public class BooleanHolder implements Holder {
- public boolean value;
-
- public BooleanHolder() {}
-
- public BooleanHolder(boolean initial) {
- value = initial;
- }
-
- /* Extra methods not in standard. */
- /**
- Comparisson method for Booleans.
- @return true if the input object equals the current object, false otherwize
- **/
- public boolean equals( Object obj ) {
- if( obj instanceof Boolean )
- return ( value == ((Boolean)obj).booleanValue());
- else
- return false;
- }
-
- /**
- Comparisson method for Booleans.
- @return true if the input boolean value equals the value of the current object, false otherwize
- **/
- public boolean equals( boolean b ) {
- return ( value == b );
- }
-
-}
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/ByteHolder.java b/lib/ic/java_src/com/ericsson/otp/ic/ByteHolder.java
deleted file mode 100644
index 7c79e8f90d..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/ByteHolder.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-/**
- * A Holder class for IDL's out/inout argument passing modes for byte
- *
- */
-package com.ericsson.otp.ic;
-
-/**
-
-Holder class for Byte, according to OMG-IDL java mapping.
-
-**/
-
-final public class ByteHolder implements Holder {
- public byte value;
-
- public ByteHolder() {}
-
- public ByteHolder(byte initial) {
- value = initial;
- }
-
- /* Extra methods not in standard. */
- /**
- Comparisson method for Bytes.
- @return true if the input object equals the current object, false otherwize
- **/
- public boolean equals( Object obj ) {
- if( obj instanceof Byte )
- return ( value == ((Byte)obj).byteValue());
- else
- return false;
- }
-
- /**
- Comparisson method for Byte.
- @return true if the input boolean value equals the value of the current object, false otherwize
- **/
- public boolean equals( byte b ) {
- return ( value == b);
- }
-
-}
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/CharHolder.java b/lib/ic/java_src/com/ericsson/otp/ic/CharHolder.java
deleted file mode 100644
index 81d8c6ac73..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/CharHolder.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-/**
- * A Holder class for IDL's out/inout argument passing modes for char
- *
- */
-package com.ericsson.otp.ic;
-
-
-/**
-
-Holder class for Char, according to OMG-IDL java mapping.
-
-**/
-
-
-final public class CharHolder implements Holder {
- public char value;
-
- public CharHolder() {}
-
- public CharHolder(char initial) {
- value = initial;
- }
-
- /* Extra methods not in standard. */
- /**
- Comparisson method for Chars.
- @return true if the input object equals the current object, false otherwize
- **/
- public boolean equals( Object obj ) {
- if( obj instanceof Character )
- return ( value == ((Character)obj).charValue());
- else
- return false;
- }
-
- /**
- Comparisson method for Chars.
- @return true if the input char value equals the value of the current object, false otherwize
- **/
- public boolean equals( char c ) {
- return ( value == c);
- }
-
-}
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/DoubleHolder.java b/lib/ic/java_src/com/ericsson/otp/ic/DoubleHolder.java
deleted file mode 100644
index 6daaa25aa8..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/DoubleHolder.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-/**
- * A Holder class for IDL's out/inout argument passing modes for double
- *
- */
-package com.ericsson.otp.ic;
-
-/**
-
-Holder class for Double, according to OMG-IDL java mapping.
-
-**/
-
-final public class DoubleHolder implements Holder {
- public double value;
-
- public DoubleHolder() {}
-
- public DoubleHolder(double initial) {
- value = initial;
- }
-
- /* Extra methods not in standard. */
- /**
- Comparisson method for Doubles.
- @return true if the input object equals the current object, false otherwize
- **/
- public boolean equals( Object obj ) {
- if( obj instanceof Double )
- return ( value == ((Double)obj).doubleValue());
- else
- return false;
- }
-
- /**
- Comparisson method for Doubles.
- @return true if the input double value equals the value of the current object, false otherwize
- **/
- public boolean equals( double d ) {
- return ( value == d);
- }
-
-}
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/Environment.java b/lib/ic/java_src/com/ericsson/otp/ic/Environment.java
deleted file mode 100644
index bffa0e27e6..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/Environment.java
+++ /dev/null
@@ -1,480 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-/**
- * The Environment class for Java IDL
- *
- */
-package com.ericsson.otp.ic;
-
-/**
-
- The Environment class handles communication
- setup and stub state. The methods of this class
- are specially designed for the generated stubs.
- This class must be used when designing asynchronous
- message passing.
-
- **/
-
-
-public class Environment {
-
- // Private variables
- private com.ericsson.otp.erlang.OtpSelf self;
- private com.ericsson.otp.erlang.OtpPeer peer;
- private java.lang.Object server;
- private java.lang.String cookie;
- private com.ericsson.otp.erlang.OtpConnection connection;
- private com.ericsson.otp.erlang.OtpErlangRef send_ref; /* Client side send reference */
- private com.ericsson.otp.erlang.OtpErlangRef receive_ref; /* Client side received reference */
- private com.ericsson.otp.erlang.OtpErlangPid clientP;
- private com.ericsson.otp.erlang.OtpErlangPid serverP;
- private com.ericsson.otp.erlang.OtpOutputStream os; /* Output stream */
- private com.ericsson.otp.erlang.OtpInputStream is; /* Input stream */
- private boolean stopped;
-
- // Private variables used by server only
- private int tag;
- private java.lang.String operation;
- private java.lang.String type;
- private com.ericsson.otp.erlang.OtpErlangRef ref; /* Server side client reference */
- private com.ericsson.otp.erlang.OtpErlangPid caller; /* Server side client pid */
-
- // Tags to distiguish client / server environments
- private boolean clientT;
- private boolean serverT;
-
-
- /**
- Client stub side constructor.
- **/
- public Environment(com.ericsson.otp.erlang.OtpSelf _Self,
- com.ericsson.otp.erlang.OtpPeer _Peer,
- java.lang.Object _Server) throws java.lang.Exception {
-
- init();
- clientT = true;
- self = _Self;
- peer = _Peer;
- server = _Server;
- os = new com.ericsson.otp.erlang.OtpOutputStream();
- }
-
-
- /**
- Client stub side constructor.
- **/
- public Environment(java.lang.String _SelfNode,
- java.lang.String _PeerNode,
- java.lang.String _Cookie,
- java.lang.Object _Server) throws java.lang.Exception {
-
- init();
- clientT = true;
- self = new com.ericsson.otp.erlang.OtpSelf(_SelfNode, _Cookie);
- peer = new com.ericsson.otp.erlang.OtpPeer(_PeerNode);
- cookie = _Cookie;
- server = _Server;
- os = new com.ericsson.otp.erlang.OtpOutputStream();
- }
-
-
- /**
- Client stub side constructor.
- **/
- public Environment(com.ericsson.otp.erlang.OtpConnection _connection,
- java.lang.Object _Server) throws java.lang.Exception {
-
- init();
- clientT = true;
- self = _connection.self();
- peer = _connection.peer();
- connection = _connection;
- server = _Server;
- os = new com.ericsson.otp.erlang.OtpOutputStream();
- }
-
-
- /**
- Server skeleton side constructor.
- **/
- public Environment() throws java.lang.Exception {
-
- init();
- serverT = true;
- stopped = false;
- os = new com.ericsson.otp.erlang.OtpOutputStream();
-
- }
-
-
- /* Communication toolbox */
-
- /**
- Client stub side connector.
- **/
- public void connect() throws java.lang.Exception {
-
- if (connection == null)
- connection = self.connect(peer);
-
- clientP = self.createPid(); /* This is not perfect */
- send_ref = self.createRef();
-
- }
-
- /**
- Reconnects a client by closing existing connection
- and connecting.
- **/
- public void reconnect() throws java.lang.Exception {
-
- if (connection.isConnected())
- connection.close();
-
- connection = self.connect(peer);
-
- }
-
- /**
- Closes the established connection.
- **/
- public void disconnect() {
-
- connection.close();
-
- }
-
-
- /**
- Client side message sender.
- **/
- public void send() throws java.lang.Exception {
-
- if (server instanceof java.lang.String)
- connection.sendBuf((java.lang.String)server, os);
- else
- connection.sendBuf((com.ericsson.otp.erlang.OtpErlangPid)server, os);
-
- }
-
-
- /**
- Client message receiver.
- **/
- public void receive() throws java.lang.Exception {
-
- is = connection.receiveBuf();
-
- if (clientT) { // If client, decode message reference too
- is.read_tuple_head();
- receive_ref = is.read_ref();
- }
- }
-
-
- /**
- Universal message receiver.
- **/
- public void receive(com.ericsson.otp.erlang.OtpConnection _connection) throws java.lang.Exception {
-
- is = _connection.receiveBuf();
-
- if (clientT) { // If client, decode message reference too
- is.read_tuple_head();
- receive_ref = is.read_ref();
- }
- }
-
-
- /* Accessors */
-
- /**
- Server RegName/OtpErlangPid accessor.
- Used to access the server Reg/Pid, which
- initiated the connection.
- @return java.lang.Object, the server for the active OtpConnection.
- **/
- public java.lang.Object server() {
-
- return server;
-
- }
-
- /**
- Caller identity accessor. Used by a server stub to access the
- caller identity of the received message.
- @return OtpErlangPid, the caller identity.
- **/
- public com.ericsson.otp.erlang.OtpErlangPid caller_pid() {
-
- return clientP;
-
- }
-
-
- /**
- Received message reference accessor. Used by a server stub to access the
- reference of the received message.
- @return OtpErlangRef, the reference of the received message.
- **/
- public com.ericsson.otp.erlang.OtpErlangRef received_ref() {
-
- return receive_ref;
-
- }
-
-
- /* Encoders */
-
- /**
- Client Pid Encoder. Used by a server stub to encode the
- enclosed client process identity.
- **/
- public void write_client_pid() {
-
- os.write_pid(clientP.node(),clientP.id(),clientP.serial(),clientP.creation());
-
- }
-
- /**
- Client Ref Encoder. Used by a server stub to encode the
- enclosed client message reference.
- **/
- public void write_client_ref() {
-
- os.write_ref(send_ref.node(),send_ref.id(),send_ref.creation());
-
- }
-
-
-
- /* Field access functions */
-
- /**
- Output Stream accessor.
- @return OtpOutputStream, the enclosed output stream.
- **/
- public com.ericsson.otp.erlang.OtpOutputStream getOs() {
- return os;
- }
-
- /**
- Input Stream accessor.
- @return OtpInputStream, the enclosed input stream.
- **/
- public com.ericsson.otp.erlang.OtpInputStream getIs() {
- return is;
- }
-
- /**
- Server skeleton side client (caller) pid accessor.
- @return OtpErlangPid, the caller process identity.
- **/
- public com.ericsson.otp.erlang.OtpErlangPid getScaller() {
- return caller;
- }
-
- /**
- Server skeleton side client call reference accessor.
- @return OtpErlangRef, the latest call message reference.
- **/
- public com.ericsson.otp.erlang.OtpErlangRef getSref() {
- return ref;
- }
-
-
-
- /* Field modifiers */
-
-
-
- /* Decoders */
-
- /**
- Decodes the message head from existing stream.
- Assignes message data to private variables of the Environment Object.
- **/
- public void uHead() throws java.lang.Exception {
- uHead(is);
- }
-
- /**
- Decodes the message head and writes over input stream.
- Assignes message data to private variables of the Environment Object.
- **/
- public void uHead(com.ericsson.otp.erlang.OtpInputStream _is) throws java.lang.Exception {
-
- is = _is;
- is.read_tuple_head();
- type = is.read_atom();
-
- if (type.equals("$gen_call")) { // Call type operation
- is.read_tuple_head();
- caller = is.read_pid();
- ref = is.read_ref();
- tag = is.peek();
-
- switch (tag) {
- case com.ericsson.otp.erlang.OtpExternal.atomTag:
- case com.ericsson.otp.erlang.OtpExternal.atomUtf8Tag:
- case com.ericsson.otp.erlang.OtpExternal.smallAtomUtf8Tag:
- operation = is.read_atom();
- break;
- default:
- is.read_tuple_head();
- operation = is.read_atom();
- }
- } else { // Cast type operation
- tag = is.peek();
- switch (tag) {
- case com.ericsson.otp.erlang.OtpExternal.atomTag:
- case com.ericsson.otp.erlang.OtpExternal.atomUtf8Tag:
- case com.ericsson.otp.erlang.OtpExternal.smallAtomUtf8Tag:
- operation = is.read_atom();
- break;
- default:
- is.read_tuple_head();
- operation = is.read_atom();
- }
- }
- }
-
- /**
- Operation label accessor.
- @return int, the label hash value.
- **/
- public int uLabel(java.util.Dictionary _operations) {
-
- java.lang.Integer __label =
- (java.lang.Integer) _operations.get(operation);
-
- if(__label == null)
- return -1;
-
- return __label.intValue();
- }
-
-
-
- /* Controllers */
-
- /**
- Operation controller.
- @return boolean, true if the operation variable found in Environment class
- is supported in the input operation dictionary, false otherwize.
- **/
- public boolean validOp(java.util.Dictionary _operations) {
-
- if((_operations.get(operation)) == null)
- return false;
-
- return true;
- }
-
-
- /**
- Server stop request controller.
- @return boolean, true if there is a client request for the server
- to be stopped, false otherwize.
- **/
- public boolean isStopped() {
- return stopped;
- };
-
-
-
- /* Destroy functions */
-
- /*
- Creates and sends a stop message.
- Called by client stub to terminate the server.
- */
- public void client_stop_server()
- throws java.lang.Exception {
-
- // Message header assembly
- os.reset();
- os.write_tuple_head(2);
- os.write_atom("$gen_cast");
-
- os.write_atom("stop");
-
- send();
-
- }
-
- /*
- Sets the stop flag for the server.
- Called by server skeleton when stop message is received.
- */
- public void server_stop_server() {
-
- // Note at server is dead !
- stopped = true;
- }
-
-
- /* Private methods */
-
- /**
- Private variable initialization.
- **/
- public void init() {
-
- clientT = false;
- serverT = false;
- stopped = false;
- self = null;
- peer = null;
- server = null;
- cookie = null;
- connection = null;
- clientP = null;
- serverP = null;
- send_ref = null;
- receive_ref = null;
- os = null;
- is = null;
-
- tag = -1;
- operation = null;
- type = null;
-
- };
-
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/FloatHolder.java b/lib/ic/java_src/com/ericsson/otp/ic/FloatHolder.java
deleted file mode 100644
index c804973ad6..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/FloatHolder.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-/**
- * A Holder class for IDL's out/inout argument passing modes for float
- *
- */
-package com.ericsson.otp.ic;
-
-/**
-
-Holder class for Float, according to OMG-IDL java mapping.
-
-**/
-
-
-final public class FloatHolder implements Holder {
- public float value;
-
- public FloatHolder() {}
-
- public FloatHolder(float initial) {
- value = initial;
- }
-
- /* Extra methods not in standard. */
- /**
- Comparisson method for Floats.
- @return true if the input object equals the current object, false otherwize
- **/
- public boolean equals( Object obj ) {
- if( obj instanceof Float )
- return ( value == ((Float)obj).floatValue());
- else
- return false;
- }
-
- /**
- Comparisson method for Floats.
- @return true if the input float value equals the value of the current object, false otherwize
- **/
- public boolean equals( float f ) {
- return ( value == f);
- }
-
-}
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/Holder.java b/lib/ic/java_src/com/ericsson/otp/ic/Holder.java
deleted file mode 100644
index a2888539a9..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/Holder.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-/**
- * Holder interface class.
-*/
-package com.ericsson.otp.ic;
-import java.io.Serializable;
-
-/**
- Holder interface class.
- **/
-
-public interface Holder extends Serializable
-{
-
-}
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/IntHolder.java b/lib/ic/java_src/com/ericsson/otp/ic/IntHolder.java
deleted file mode 100644
index 7327d03843..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/IntHolder.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-/**
- * A Holder class for IDL's out/inout argument passing modes for long
- *
- */
-package com.ericsson.otp.ic;
-
-/**
-
-Holder class for Int, according to OMG-IDL java mapping.
-
-**/
-
-final public class IntHolder implements Holder {
- public int value;
-
- public IntHolder() {}
-
- public IntHolder(int initial) {
- value = initial;
- }
-
- /* Extra methods not in standard. */
-
- /**
- Comparisson method for Ints.
- @return true if the input object equals the current object, false otherwize
- **/
- public boolean equals( Object obj ) {
- if( obj instanceof Integer )
- return ( value == ((Integer)obj).intValue());
- else
- return false;
- }
-
- /**
- Comparisson method for Ints.
- @return true if the input int value equals the value of the current object, false otherwize
- **/
- public boolean equals( int i ) {
- return ( value == i);
- }
-
-}
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/LongHolder.java b/lib/ic/java_src/com/ericsson/otp/ic/LongHolder.java
deleted file mode 100644
index 34af201b42..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/LongHolder.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-/**
- * A Holder class for IDL's out/inout argument passing modes for long
- *
- */
-package com.ericsson.otp.ic;
-
-/**
-
-Holder class for Long, used by the Term class.
-
-**/
-
-final public class LongHolder implements Holder {
- public long value;
-
- public LongHolder() {}
-
- public LongHolder(long initial) {
- value = initial;
- }
-
- /**
- Comparisson method for Longs.
- @return true if the input object equals the current object, false otherwize
- **/
- public boolean equals( Object obj ) {
- if( obj instanceof Long )
- return ( value == ((Long)obj).longValue());
- else
- return false;
- }
-
- /**
- Comparisson method for Longs.
- @return true if the input long value equals the value of the current object, false otherwize
- **/
- public boolean equals( long l ) {
- return ( value == l);
- }
-
-}
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/Makefile b/lib/ic/java_src/com/ericsson/otp/ic/Makefile
deleted file mode 100644
index 21c38e54b5..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/Makefile
+++ /dev/null
@@ -1,122 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1999-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-
-
-JAVA_DEST_ROOT = $(ERL_TOP)/lib/ic/priv/
-JAVA_SRC_ROOT = $(ERL_TOP)/lib/ic/java_src/
-JAVA_CLASS_SUBDIR = com/ericsson/otp/ic/
-JAVA_INCL_ROOT = $(ERL_TOP)/lib/jinterface/priv/
-
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include $(ERL_TOP)/lib/ic/vsn.mk
-VSN=$(IC_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/ic-$(VSN)
-
-#
-# JAVA macros
-#
-JAVA_CLASSES = \
- Holder \
- BooleanHolder \
- ByteHolder \
- CharHolder \
- DoubleHolder \
- FloatHolder \
- IntHolder \
- LongHolder \
- ShortHolder \
- StringHolder \
- Environment \
- Any \
- AnyHelper \
- AnyHolder \
- TypeCode \
- TCKind \
- Pid \
- PidHolder \
- PidHelper \
- Ref \
- RefHolder \
- RefHelper \
- Port \
- PortHolder \
- PortHelper \
- Term \
- TermHolder \
- TermHelper
-
-TARGET_FILES= $(JAVA_CLASSES:%=$(JAVA_DEST_ROOT)$(JAVA_CLASS_SUBDIR)%.class)
-JAVA_FILES= $(JAVA_CLASSES:%=%.java)
-
-JARFILE= ic.jar
-
-# ----------------------------------------------------
-# Programs and Flags
-# ----------------------------------------------------
-CLASSPATH = $(JAVA_SRC_ROOT):$(JAVA_INCL_ROOT)
-
-JAR= jar
-
-JAVADOCFLAGS=-d $(DOCDIR)
-JAVAFLAGS=-d $(JAVA_DEST_ROOT)
-JARFLAGS= -cf
-ifneq ($(V),0)
-JARFLAGS= -cfv
-endif
-
-JAVA_OPTIONS =
-
-# ----------------------------------------------------
-# Make Rules
-# ----------------------------------------------------
-
-debug opt: $(JAVA_DEST_ROOT)$(JARFILE)
-
-$(JAVA_DEST_ROOT)$(JARFILE): $(TARGET_FILES)
- @(cd $(JAVA_DEST_ROOT) ; $(JAR) $(JARFLAGS) $(JARFILE) $(JAVA_CLASS_SUBDIR))
-
-clean:
- rm -f $(TARGET_FILES) *~
-
-docs:
-
-# ----------------------------------------------------
-# Release Targets
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/java_src/com/ericsson/otp/ic"
- $(INSTALL_DATA) $(JAVA_FILES) "$(RELSYSDIR)/java_src/com/ericsson/otp/ic"
- $(INSTALL_DIR) "$(RELSYSDIR)/priv"
- $(INSTALL_DATA) $(JAVA_DEST_ROOT)$(JARFILE) "$(RELSYSDIR)/priv"
-
-release_docs_spec:
-
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/Pid.java b/lib/ic/java_src/com/ericsson/otp/ic/Pid.java
deleted file mode 100644
index 0f26c32aef..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/Pid.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-package com.ericsson.otp.ic;
-
-
-/**
-
-Pid class mapps the built-in erlang type pid, a process identity.
-
-**/
-
-
-final public class Pid extends com.ericsson.otp.erlang.OtpErlangPid {
-
- public Pid(com.ericsson.otp.erlang.OtpSelf self) {
- super(self);
- }
-
- public Pid(com.ericsson.otp.erlang.OtpInputStream buf)
- throws com.ericsson.otp.erlang.OtpErlangDecodeException {
- super(buf);
- }
-
-
- public Pid(String node, int id, int serial, int creation) {
- super(node,id,serial,creation);
- }
-
-
- /**
- Comparisson method for Pid.
- @return true if the input Pid value equals the value of the current object, false otherwize
- **/
- public boolean equal(Pid _pid) {
- return super.equals(_pid);
- }
-
-}
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/PidHelper.java b/lib/ic/java_src/com/ericsson/otp/ic/PidHelper.java
deleted file mode 100644
index 4c51035738..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/PidHelper.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-package com.ericsson.otp.ic;
-
-/**
- Helper class for Pid.
- **/
-
-public class PidHelper {
-
- // constructors
- private PidHelper() {}
-
- // methods
- /**
- Marshal method for the Pid class, encodes the Pid object to the output stream.
- **/
- public static void marshal(com.ericsson.otp.erlang.OtpOutputStream _out, Pid _value)
- throws java.lang.Exception {
-
- _out.write_pid(_value.node(),_value.id(),_value.serial(),_value.creation());
- }
-
- /**
- Unmarshal method for the Pid class, decodes a Pid object from the stream.
- @return Pid, read from the input stream
- **/
- public static Pid unmarshal(com.ericsson.otp.erlang.OtpInputStream _in)
- throws java.lang.Exception {
-
- // Double job is done here, there should be
- // a function returning a Pid instead of an
- // OtpErlangPid
- com.ericsson.otp.erlang.OtpErlangPid oep = _in.read_pid();
-
- return new Pid(oep.node(),oep.id(),oep.serial(),oep.creation());
- }
-
- /**
- Standard method that returns the interface repository identity.
- @return String containing the interface repository identity of Pid
- **/
- public static String id() {
- return "IDL:com/ericsson/otp/ic/Pid:1.0";
- }
-
- /**
- Standard method that returns the Pid class name.
- @return String containing the class name of Pid
- **/
- public static String name() {
- return "Pid";
- }
-
- /**
- Holds the TypeCode
- **/
- private static com.ericsson.otp.ic.TypeCode _tc;
-
- /**
- Standard TypeCode accessor method.
- @return the TypeCode for Pid
- **/
- synchronized public static com.ericsson.otp.ic.TypeCode type() {
-
- if (_tc != null)
- return _tc;
-
- com.ericsson.otp.ic.TypeCode _tc0 =
- new com.ericsson.otp.ic.TypeCode();
- _tc0.kind(com.ericsson.otp.ic.TCKind.tk_struct);
- _tc0.id("IDL:com/ericsson/otp/ic/Pid:1.0");
- _tc0.name("Pid");
- _tc0.member_count(4);
- _tc0.member_name(0,"node");
- com.ericsson.otp.ic.TypeCode _tc1 =
- new com.ericsson.otp.ic.TypeCode();
- _tc1.kind(com.ericsson.otp.ic.TCKind.tk_string);
- _tc1.length(256);
- _tc0.member_type(0,_tc1);
- _tc0.member_name(1,"num");
- com.ericsson.otp.ic.TypeCode _tc2 =
- new com.ericsson.otp.ic.TypeCode();
- _tc2.kind(com.ericsson.otp.ic.TCKind.tk_ulong);
- _tc0.member_type(1,_tc2);
- _tc0.member_name(2,"serial");
- com.ericsson.otp.ic.TypeCode _tc3 =
- new com.ericsson.otp.ic.TypeCode();
- _tc3.kind(com.ericsson.otp.ic.TCKind.tk_ulong);
- _tc0.member_type(2,_tc3);
- _tc0.member_name(3,"creation");
- com.ericsson.otp.ic.TypeCode _tc4 =
- new com.ericsson.otp.ic.TypeCode();
- _tc4.kind(com.ericsson.otp.ic.TCKind.tk_ulong);
- _tc0.member_type(3,_tc4);
-
- _tc = _tc0;
-
- return _tc0;
- }
-
-
- /**
- Standard method for inserting a Pid to an Any.
- **/
- public static void insert(com.ericsson.otp.ic.Any _any, Pid _this)
- throws java.lang.Exception {
-
- com.ericsson.otp.erlang.OtpOutputStream _os =
- new com.ericsson.otp.erlang.OtpOutputStream();
-
- _any.type(type());
- marshal(_os, _this);
- _any.insert_Streamable(_os);
- }
-
- /**
- Standard method for extracting a Pid from an Any.
- @return Pid, the value found in an Any contained stream.
- **/
- public static Pid extract(com.ericsson.otp.ic.Any _any)
- throws java.lang.Exception {
-
- return unmarshal(_any.extract_Streamable());
- }
-
-}
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/PidHolder.java b/lib/ic/java_src/com/ericsson/otp/ic/PidHolder.java
deleted file mode 100644
index f5dfd81576..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/PidHolder.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-package com.ericsson.otp.ic;
-
-/**
- Holder class for Pid.
- **/
-
-final public class PidHolder {
-
- /**
- Pid instance variable.
- **/
- public Pid value;
-
- // constructors
- public PidHolder() {}
- public PidHolder(Pid initial) {
- value = initial;
- }
-
- // methods
- /**
- Marshal method for the PidHolder class, encodes the Pid object value to the output stream.
- **/
- public void _marshal(com.ericsson.otp.erlang.OtpOutputStream out) throws java.lang.Exception {
- PidHelper.marshal(out, value);
- }
-
- /**
- Unmarshal method for the PidHolder class, decodes a Pid object from the output stream
- and assigns it to the Holder value field.
- **/
- public void _unmarshal(com.ericsson.otp.erlang.OtpInputStream in) throws java.lang.Exception {
- value = PidHelper.unmarshal(in);
- }
-}
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/Port.java b/lib/ic/java_src/com/ericsson/otp/ic/Port.java
deleted file mode 100644
index 34edbea362..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/Port.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-package com.ericsson.otp.ic;
-
-/**
-
-Port class mapps the built-in erlang type port, a process port.
-
-**/
-
-final public class Port extends com.ericsson.otp.erlang.OtpErlangPort {
-
- public Port(com.ericsson.otp.erlang.OtpInputStream buf)
- throws com.ericsson.otp.erlang.OtpErlangDecodeException {
- super(buf);
- }
-
- public Port(String node, int id, int creation) {
- super(node,id,creation);
- }
-
- /**
- Comparisson method for Port.
- @return true if the input Port value equals the value of the current object, false otherwize
- **/
- public boolean equal(Port _port) {
- return super.equals(_port);
- }
-
-
-}
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/PortHelper.java b/lib/ic/java_src/com/ericsson/otp/ic/PortHelper.java
deleted file mode 100644
index 3e74758739..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/PortHelper.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-package com.ericsson.otp.ic;
-
-/**
- Helper class for Port.
- **/
-
-public class PortHelper {
-
- // constructors
- private PortHelper() {}
-
- // methods
-
- /**
- Marshal method for the Port class, encodes the Port object to the output stream.
- **/
- public static void marshal(com.ericsson.otp.erlang.OtpOutputStream _out, Port _value)
- throws java.lang.Exception {
-
- _out.write_port(_value.node(),_value.id(),_value.creation());
- }
-
- /**
- Unmarshal method for the Port class, decodes a Port object from the stream.
- @return Port, read from the input stream
- **/
- public static Port unmarshal(com.ericsson.otp.erlang.OtpInputStream _in)
- throws java.lang.Exception {
-
- // Double job is done here, there should be
- // a function returning a Port instead of an
- // OtpErlangPort
- com.ericsson.otp.erlang.OtpErlangPort oep = _in.read_port();
-
- return new Port(oep.node(),oep.id(),oep.creation());
- }
-
- /**
- Standard method that returns the interface repository identity.
- @return String containing the interface repository identity of Port
- **/
- public static String id() {
- return "IDL:com/ericsson/otp/ic/Port:1.0";
- }
-
- /**
- Standard method that returns the Port class name.
- @return String containing the class name of Port
- **/
- public static String name() {
- return "Port";
- }
-
- /**
- Holds the TypeCode
- **/
- private static com.ericsson.otp.ic.TypeCode _tc;
-
- /**
- Standard TypeCode accessor method.
- @return the TypeCode for Port
- **/
- synchronized public static com.ericsson.otp.ic.TypeCode type() {
-
- if (_tc != null)
- return _tc;
-
- com.ericsson.otp.ic.TypeCode _tc0 =
- new com.ericsson.otp.ic.TypeCode();
- _tc0.kind(com.ericsson.otp.ic.TCKind.tk_struct);
- _tc0.id("IDL:com/ericsson/otp/ic/Port:1.0");
- _tc0.name("Port");
- _tc0.member_count(3);
- _tc0.member_name(0,"node");
- com.ericsson.otp.ic.TypeCode _tc1 =
- new com.ericsson.otp.ic.TypeCode();
- _tc1.kind(com.ericsson.otp.ic.TCKind.tk_string);
- _tc1.length(256);
- _tc0.member_type(0,_tc1);
- _tc0.member_name(1,"id");
- com.ericsson.otp.ic.TypeCode _tc2 =
- new com.ericsson.otp.ic.TypeCode();
- _tc2.kind(com.ericsson.otp.ic.TCKind.tk_ulong);
- _tc0.member_type(1,_tc2);
- _tc0.member_name(2,"creation");
- com.ericsson.otp.ic.TypeCode _tc3 =
- new com.ericsson.otp.ic.TypeCode();
- _tc3.kind(com.ericsson.otp.ic.TCKind.tk_ulong);
- _tc0.member_type(2,_tc3);
-
- _tc = _tc0;
-
- return _tc0;
- }
-
-
- /**
- Standard method for inserting a Port to an Any.
- **/
- public static void insert(com.ericsson.otp.ic.Any _any, Port _this)
- throws java.lang.Exception {
-
- com.ericsson.otp.erlang.OtpOutputStream _os =
- new com.ericsson.otp.erlang.OtpOutputStream();
-
- _any.type(type());
- marshal(_os, _this);
- _any.insert_Streamable(_os);
- }
-
- /**
- Standard method for extracting a Port from an Any.
- @return Port, the value found in an Any contained stream.
- **/
- public static Port extract(com.ericsson.otp.ic.Any _any)
- throws java.lang.Exception {
-
- return unmarshal(_any.extract_Streamable());
- }
-
-}
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/PortHolder.java b/lib/ic/java_src/com/ericsson/otp/ic/PortHolder.java
deleted file mode 100644
index da0df3bbc7..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/PortHolder.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-package com.ericsson.otp.ic;
-
-/**
- Holder class for Port.
- **/
-
-final public class PortHolder {
-
- /**
- Port instance variable.
- **/
- public Port value;
-
- // constructors
- public PortHolder() {}
- public PortHolder(Port initial) {
- value = initial;
- }
-
- // methods
- /**
- Marshal method for the PortHolder class, encodes the Port object value to the output stream.
- **/
- public void _marshal(com.ericsson.otp.erlang.OtpOutputStream out)
- throws java.lang.Exception {
- PortHelper.marshal(out, value);
- }
-
- /**
- Unmarshal method for the PortHolder class, decodes a Port object from the output stream
- and assigns it to the Holder value field.
- **/
- public void _unmarshal(com.ericsson.otp.erlang.OtpInputStream in)
- throws java.lang.Exception {
- value = PortHelper.unmarshal(in);
- }
-}
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/Ref.java b/lib/ic/java_src/com/ericsson/otp/ic/Ref.java
deleted file mode 100644
index a55da87d0d..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/Ref.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-package com.ericsson.otp.ic;
-
-/**
-
-Ref class mapps the built-in erlang type Ref, a message reference.
-
-**/
-
-final public class Ref extends com.ericsson.otp.erlang.OtpErlangRef {
-
- public Ref(com.ericsson.otp.erlang.OtpSelf self) {
- super(self);
- }
-
-
- public Ref(com.ericsson.otp.erlang.OtpInputStream buf)
- throws com.ericsson.otp.erlang.OtpErlangDecodeException {
- super(buf);
- }
-
- /**
- Old style Ref costructor. Costructs an Ref that coresponds to the
- old erlang Ref type.
- **/
- public Ref(String node, int id, int creation) {
- super(node,id,creation);
- }
-
- public Ref(String node, int[] ids, int creation) {
- super(node,ids,creation);
- }
-
- /**
- Comparisson method for Ref.
- @return true if the input Ref value equals the value of the current object, false otherwize
- **/
- public boolean equal(Ref _ref) {
- return super.equals(_ref);
- }
-
-}
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/RefHelper.java b/lib/ic/java_src/com/ericsson/otp/ic/RefHelper.java
deleted file mode 100644
index cb145bbbb2..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/RefHelper.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-package com.ericsson.otp.ic;
-
-/**
- Helper class for Ref.
- **/
-
-public class RefHelper {
-
- // constructors
- private RefHelper() {}
-
- // methods
- /**
- Marshal method for the Ref class, encodes the Ref object to the output stream.
- **/
- public static void marshal(com.ericsson.otp.erlang.OtpOutputStream _out, Ref _value)
- throws java.lang.Exception {
-
- _out.write_ref(_value.node(),_value.id(),_value.creation());
- }
-
- /**
- Unmarshal method for the Ref class, decodes a Ref object from the stream.
- @return Ref, read from the input stream
- **/
- public static Ref unmarshal(com.ericsson.otp.erlang.OtpInputStream _in)
- throws java.lang.Exception {
-
- // Double job is done here, there should be
- // a function returning a Ref instead of an
- // OtpErlangRef
- com.ericsson.otp.erlang.OtpErlangRef oer = _in.read_ref();
-
- if (oer.isNewRef())
- return new Ref(oer.node(),oer.ids(),oer.creation());
- else
- return new Ref(oer.node(),oer.id(),oer.creation());
- }
-
- /**
- Standard method that returns the interface repository identity.
- @return String containing the interface repository identity of Ref
- **/
- public static String id() {
- return "IDL:com/ericsson/otp/ic/Ref:1.0";
- }
-
- /**
- Standard method that returns the Ref class name.
- @return String containing the class name of Ref
- **/
- public static String name() {
- return "Ref";
- }
-
- /**
- Holds the TypeCode
- **/
- private static com.ericsson.otp.ic.TypeCode _tc;
-
- /**
- Standard TypeCode accessor method.
- @return the TypeCode for Ref
- **/
- synchronized public static com.ericsson.otp.ic.TypeCode type() {
-
- if (_tc != null)
- return _tc;
-
- com.ericsson.otp.ic.TypeCode _tc0 =
- new com.ericsson.otp.ic.TypeCode();
- _tc0.kind(com.ericsson.otp.ic.TCKind.tk_struct);
- _tc0.id("IDL:com/ericsson/otp/ic/Ref:1.0");
- _tc0.name("Ref");
- _tc0.member_count(3);
- _tc0.member_name(0,"node");
- com.ericsson.otp.ic.TypeCode _tc1 =
- new com.ericsson.otp.ic.TypeCode();
- _tc1.kind(com.ericsson.otp.ic.TCKind.tk_string);
- _tc1.length(256);
- _tc0.member_type(0,_tc1);
- _tc0.member_name(1,"id");
- com.ericsson.otp.ic.TypeCode _tc2 =
- new com.ericsson.otp.ic.TypeCode();
- _tc2.kind(com.ericsson.otp.ic.TCKind.tk_ulong);
- _tc0.member_type(1,_tc2);
- _tc0.member_name(2,"creation");
- com.ericsson.otp.ic.TypeCode _tc3 =
- new com.ericsson.otp.ic.TypeCode();
- _tc3.kind(com.ericsson.otp.ic.TCKind.tk_ulong);
- _tc0.member_type(2,_tc3);
-
- _tc = _tc0;
-
- return _tc0;
- }
-
- /**
- Standard method for inserting a Ref to an Any.
- **/
- public static void insert(com.ericsson.otp.ic.Any _any, Ref _this)
- throws java.lang.Exception {
-
- com.ericsson.otp.erlang.OtpOutputStream _os =
- new com.ericsson.otp.erlang.OtpOutputStream();
-
- _any.type(type());
- marshal(_os, _this);
- _any.insert_Streamable(_os);
- }
-
- /**
- Standard method for extracting a Ref from an Any.
- @return Ref, the value found in an Any contained stream.
- **/
- public static Ref extract(com.ericsson.otp.ic.Any _any)
- throws java.lang.Exception {
-
- return unmarshal(_any.extract_Streamable());
- }
-
-}
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/RefHolder.java b/lib/ic/java_src/com/ericsson/otp/ic/RefHolder.java
deleted file mode 100644
index 9ef2eacea1..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/RefHolder.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-package com.ericsson.otp.ic;
-
-/**
- Holder class for Ref.
- **/
-
-final public class RefHolder {
-
- /**
- Ref instance variable.
- **/
- public Ref value;
-
- // constructors
- public RefHolder() {}
- public RefHolder(Ref initial) {
- value = initial;
- }
-
- // methods
- /**
- Marshal method for the RefHolder class, encodes the Ref object value to the output stream.
- **/
- public void _marshal(com.ericsson.otp.erlang.OtpOutputStream out) throws java.lang.Exception {
- RefHelper.marshal(out, value);
- }
-
- /**
- Unmarshal method for the RefHolder class, decodes a Ref object from the output stream
- and assigns it to the Holder value field.
- **/
- public void _unmarshal(com.ericsson.otp.erlang.OtpInputStream in) throws java.lang.Exception {
- value = RefHelper.unmarshal(in);
- }
-}
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/ShortHolder.java b/lib/ic/java_src/com/ericsson/otp/ic/ShortHolder.java
deleted file mode 100644
index 3b191dd633..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/ShortHolder.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-/**
- * A Holder class for IDL's out/inout argument passing modes for long
- *
- */
-package com.ericsson.otp.ic;
-
-/**
-
-Holder class for Short, according to OMG-IDL java mapping.
-
-**/
-
-final public class ShortHolder implements Holder {
- public short value;
-
- public ShortHolder() {}
-
- public ShortHolder(short initial) {
- value = initial;
- }
-
- /* Extra methods not in standard. */
- /**
- Comparisson method for Shorts.
- @return true if the input object equals the current object, false otherwize
- **/
- public boolean equals( Object obj ) {
- if( obj instanceof Short )
- return ( value == ((Short)obj).shortValue());
- else
- return false;
- }
-
- /**
- Comparisson method for Shorts.
- @return true if the input short value equals the value of the current object, false otherwize
- **/
- public boolean equals( short s ) {
- return ( value == s);
- }
-
-}
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/StringHolder.java b/lib/ic/java_src/com/ericsson/otp/ic/StringHolder.java
deleted file mode 100644
index f4cd069148..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/StringHolder.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-/**
- * A Holder class for IDL's out/inout argument passing modes for string
- *
- */
-package com.ericsson.otp.ic;
-
-
-/**
-
-Holder class for String, according to OMG-IDL java mapping.
-
-**/
-
-final public class StringHolder implements Holder {
- public String value;
-
- public StringHolder() {}
-
- public StringHolder(String initial) {
- value = initial;
- }
-
- /* Extra methods not in standard. */
- /**
- Comparisson method for Strings.
- @return true if the input object equals the current object, false otherwize
- **/
- public boolean equals( Object obj ) {
- if( obj instanceof String )
- return ( value == obj);
- else
- return false;
- }
-
- /**
- Comparisson method for Strings.
- @return true if the input String value equals the value of the current object, false otherwize
- **/
- public boolean equals( String s ) {
- return ( value == s);
- }
-
-}
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/TCKind.java b/lib/ic/java_src/com/ericsson/otp/ic/TCKind.java
deleted file mode 100644
index e6265ae586..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/TCKind.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-/**
- * The TCKind class for Java IDL
- *
- */
-package com.ericsson.otp.ic;
-
-/**
- The TCKind class is the implementation of the OMG-IDL enumerant type TCKind.
- **/
-
-final public class TCKind {
-
- // instance variables
- public static final int _tk_null = 0,
- _tk_void = 1,
- _tk_short = 2,
- _tk_long = 3,
- _tk_ushort = 4,
- _tk_ulong = 5,
- _tk_float = 6,
- _tk_double = 7,
- _tk_boolean = 8,
- _tk_char = 9,
- _tk_octet = 10,
- _tk_any = 11,
- _tk_TypeCode = 12,
- _tk_Principal = 13,
- _tk_objref = 14,
- _tk_struct = 15,
- _tk_union = 16,
- _tk_enum = 17,
- _tk_string = 18,
- _tk_sequence = 19,
- _tk_array = 20,
- _tk_alias = 21,
- _tk_except = 22,
- _tk_longlong = 23,
- _tk_ulonglong = 24,
- _tk_longdouble = 25,
- _tk_wchar = 26,
- _tk_wstring = 27,
- _tk_fixed = 28,
- _tk_atom = 20000, /* Used for union label default value only */
- _tk_pid = 20001, /* Used for special pid struct */
- _tk_port = 20002, /* Used for special port struct */
- _tk_ref = 20003, /* Used for special ref struct */
- _tk_term = 20004; /* Used for special term struct */
-
- public static final TCKind tk_null = new TCKind(_tk_null);
- public static final TCKind tk_void = new TCKind(_tk_void);
- public static final TCKind tk_short = new TCKind(_tk_short);
- public static final TCKind tk_long = new TCKind(_tk_long);
- public static final TCKind tk_ushort = new TCKind(_tk_ushort);
- public static final TCKind tk_ulong = new TCKind(_tk_ulong);
- public static final TCKind tk_float = new TCKind(_tk_float);
- public static final TCKind tk_double = new TCKind(_tk_double);
- public static final TCKind tk_boolean = new TCKind(_tk_boolean);
- public static final TCKind tk_char = new TCKind(_tk_char);
- public static final TCKind tk_octet = new TCKind(_tk_octet);
- public static final TCKind tk_any = new TCKind(_tk_any);
- public static final TCKind tk_TypeCode = new TCKind(_tk_TypeCode);
- public static final TCKind tk_Principal = new TCKind(_tk_Principal);
- public static final TCKind tk_objref = new TCKind(_tk_objref);
- public static final TCKind tk_struct = new TCKind(_tk_struct);
- public static final TCKind tk_union = new TCKind(_tk_union);
- public static final TCKind tk_enum = new TCKind(_tk_enum);
- public static final TCKind tk_string = new TCKind(_tk_string);
- public static final TCKind tk_sequence = new TCKind(_tk_sequence);
- public static final TCKind tk_array = new TCKind(_tk_array);
- public static final TCKind tk_alias = new TCKind(_tk_alias);
- public static final TCKind tk_except = new TCKind(_tk_except);
- public static final TCKind tk_longlong = new TCKind(_tk_longlong);
- public static final TCKind tk_ulonglong = new TCKind(_tk_ulonglong);
- public static final TCKind tk_longdouble = new TCKind(_tk_longdouble);
- public static final TCKind tk_wchar = new TCKind(_tk_wchar);
- public static final TCKind tk_wstring = new TCKind(_tk_wstring);
- public static final TCKind tk_fixed = new TCKind(_tk_fixed);
- protected static final TCKind tk_atom = new TCKind(_tk_atom);
- protected static final TCKind tk_pid = new TCKind(_tk_pid);
- protected static final TCKind tk_port = new TCKind(_tk_port);
- protected static final TCKind tk_ref = new TCKind(_tk_ref);
- protected static final TCKind tk_term = new TCKind(_tk_term);
- private int _value;
-
- // constructors
- private TCKind(int __value) {
- _value = __value;
- }
-
- // methods
-
- /**
- Accessor method for the value of TCKind.
- @return int, the value of TCKind object
- **/
- public int value() {
- return _value;
- }
-
- /**
- Translator method for TCKind.
- Traslates the input integer value to a TCKind enumerant object.
- @return TCKind, a TCKind object
- **/
- public static final TCKind from_int(int __value) throws java.lang.Exception {
- switch (__value) {
- case _tk_null:
- return tk_null;
- case _tk_void:
- return tk_void;
- case _tk_short:
- return tk_short;
- case _tk_long:
- return tk_long;
- case _tk_ushort:
- return tk_ushort;
- case _tk_ulong:
- return tk_ulong;
- case _tk_float:
- return tk_float;
- case _tk_double:
- return tk_double;
- case _tk_boolean:
- return tk_boolean;
- case _tk_char:
- return tk_char;
- case _tk_octet:
- return tk_octet;
- case _tk_any:
- return tk_any;
- case _tk_TypeCode:
- return tk_TypeCode;
- case _tk_Principal:
- return tk_Principal;
- case _tk_objref:
- return tk_objref;
- case _tk_struct:
- return tk_struct;
- case _tk_union:
- return tk_union;
- case _tk_enum:
- return tk_enum;
- case _tk_string:
- return tk_string;
- case _tk_sequence:
- return tk_sequence;
- case _tk_array:
- return tk_array;
- case _tk_alias:
- return tk_alias;
- case _tk_except:
- return tk_except;
- case _tk_longlong:
- return tk_longlong;
- case _tk_ulonglong:
- return tk_ulonglong;
- case _tk_longdouble:
- return tk_longdouble;
- case _tk_wchar:
- return tk_wchar;
- case _tk_wstring:
- return tk_wstring;
- case _tk_fixed:
- return tk_fixed;
- case _tk_atom:
- return tk_atom;
- case _tk_pid:
- return tk_pid;
- case _tk_port:
- return tk_port;
- case _tk_ref:
- return tk_ref;
- case _tk_term:
- return tk_term;
- default:
- throw new java.lang.Exception("");
- }
- }
-
-}
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/Term.java b/lib/ic/java_src/com/ericsson/otp/ic/Term.java
deleted file mode 100644
index 7a27905fcd..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/Term.java
+++ /dev/null
@@ -1,1113 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-package com.ericsson.otp.ic;
-
-/**
-
-The Term class is intended to represent the erlang term generic type.
-It extends the Any class and is basically used the same way as the Any class.
-<p>The main difference between Term and Any is the use of guard methods
-instead for TypeCode to determine the data included in the Term.
-This actual when cannot determine a Term's value class returned at compile time.
-
-**/
-
-final public class Term extends Any {
-
- // Primitive value holder
- protected java.lang.String atomV;
- protected long longV;
- protected Pid PidV;
- protected Ref RefV;
- protected Port PortV;
- protected com.ericsson.otp.erlang.OtpErlangObject ObjV;
- protected int tag;
-
- /**
- Tag accessor method
- @return int, the tag of the Object that denotes the erlang external format tag
- **/
- public int tag() {
- return tag;
- }
-
- /* Guards */
-
- /**
- Guard method
- @return true if the Term is an OtpErlangAtom, false otherwize
- **/
- public boolean isAtom() {
-
- if (ObjV == null) {
- if (tag == com.ericsson.otp.erlang.OtpExternal.atomTag ||
- tag == com.ericsson.otp.erlang.OtpExternal.atomUtf8Tag ||
- tag == com.ericsson.otp.erlang.OtpExternal.smallAtomUtf8Tag)
-
- return true;
-
- return false;
- }
-
- return (ObjV instanceof com.ericsson.otp.erlang.OtpErlangAtom) ;
- }
-
- /**
- Guard method
- @return true if the Term is not an OtpErlangList nor an OtpErlangTuple, false otherwize
- **/
- public boolean isConstant() {
- if (isList())
- return false;
-
- if (isTuple())
- return false;
-
- return true;
- }
-
- /**
- Guard method
- @return true if the Term is an OtpErlangFloat, false otherwize
- **/
- public boolean isFloat() {
- if (tag == com.ericsson.otp.erlang.OtpExternal.floatTag)
- return true;
-
- return false;
- }
-
- /**
- Guard method
- @return true if the Term is an OtpErlangInt, false otherwize
- **/
- public boolean isInteger() {
- switch(tag) {
- case com.ericsson.otp.erlang.OtpExternal.smallIntTag:
- case com.ericsson.otp.erlang.OtpExternal.intTag:
- case com.ericsson.otp.erlang.OtpExternal.smallBigTag:
- return true;
- default:
- return false;
- }
- }
-
- /**
- Guard method
- @return true if the Term is an OtpErlangList, false otherwize
- **/
- public boolean isList() {
-
- if (ObjV == null) {
- switch(tag) {
- case com.ericsson.otp.erlang.OtpExternal.listTag:
- case com.ericsson.otp.erlang.OtpExternal.stringTag:
- case com.ericsson.otp.erlang.OtpExternal.nilTag:
- return true;
- default:
- return false;
- }
- }
-
- if (ObjV instanceof com.ericsson.otp.erlang.OtpErlangList)
- return true;
-
- if (ObjV instanceof com.ericsson.otp.erlang.OtpErlangString)
- return true;
-
- return false;
- }
-
-
- /**
- Guard method
- @return true if the Term is an OtpErlangString, false otherwize
- **/
- public boolean isString() {
-
- if (ObjV == null) {
- switch(tag) {
- case com.ericsson.otp.erlang.OtpExternal.stringTag:
- case com.ericsson.otp.erlang.OtpExternal.nilTag:
- return true;
- default:
- try {
- stringV = extract_string();
- return true;
- } catch (Exception e) {
- return false;
- }
- }
- }
-
- if (ObjV instanceof com.ericsson.otp.erlang.OtpErlangString)
- return true;
-
- try {
- stringV = extract_string();
- return true;
- } catch (Exception e) {
- return false;
- }
- }
-
- /**
- Guard method
- @return true if the Term is an OtpErlangInteger or an OtpErlangFloat, false otherwize
- **/
- public boolean isNumber() {
- switch(tag) {
- case com.ericsson.otp.erlang.OtpExternal.smallIntTag:
- case com.ericsson.otp.erlang.OtpExternal.intTag:
- case com.ericsson.otp.erlang.OtpExternal.smallBigTag:
- case com.ericsson.otp.erlang.OtpExternal.floatTag:
- return true;
- default :
- return false;
- }
- }
-
-
- /**
- Guard method
- @return true if the Term is an OtpErlangPid or Pid, false otherwize
- **/
- public boolean isPid() {
-
- if (ObjV == null) {
- if (tag == com.ericsson.otp.erlang.OtpExternal.pidTag)
- return true;
-
- return false;
- }
-
- return (ObjV instanceof com.ericsson.otp.erlang.OtpErlangPid) ;
- }
-
-
- /**
- Guard method
- @return true if the Term is an OtpErlangPort or Port, false otherwize
- **/
- public boolean isPort() {
- if (ObjV == null) {
- if (tag == com.ericsson.otp.erlang.OtpExternal.portTag)
- return true;
-
- return false;
- }
-
- return (ObjV instanceof com.ericsson.otp.erlang.OtpErlangPort);
- }
-
-
- /**
- Guard method
- @return true if the Term is an OtpErlangRef, false otherwize
- **/
- public boolean isReference() {
- if (ObjV == null) {
- switch(tag) {
- case com.ericsson.otp.erlang.OtpExternal.refTag:
- case com.ericsson.otp.erlang.OtpExternal.newRefTag:
- return true;
- default :
- return false;
- }
- }
-
- return (ObjV instanceof com.ericsson.otp.erlang.OtpErlangRef) ;
- }
-
-
- /**
- Guard method
- @return true if the Term is an OtpErlangTuple, false otherwize
- **/
- public boolean isTuple() {
- if (ObjV == null) {
- switch(tag) {
- case com.ericsson.otp.erlang.OtpExternal.smallTupleTag:
- case com.ericsson.otp.erlang.OtpExternal.largeTupleTag:
- return true;
- default :
- return false;
- }
- }
-
- return (ObjV instanceof com.ericsson.otp.erlang.OtpErlangTuple);
- }
-
-
- /**
- Guard method
- @return true if the Term is an OtpErlangBinary, false otherwize
- **/
- public boolean isBinary() {
- if (ObjV == null) {
- if (tag == com.ericsson.otp.erlang.OtpExternal.binTag)
- return true;
-
- return false;
- }
-
- return (ObjV instanceof com.ericsson.otp.erlang.OtpErlangBinary);
- }
-
-
-
-
- // Equal function
- /**
- Term comparison method
- @return true if the input Term is equal to the object, false otherwize
- **/
- public boolean equal(Term _any) {
-
- try {
-
- /* Pids */
- if ((PidV != null) && (_any.PidV != null))
- if (PidV.equal(_any.PidV))
- return true;
-
- /* Refs */
- if ((RefV != null) && (_any.RefV != null))
- if (RefV.equal(_any.RefV))
- return true;
-
- /* Ports */
- if ((PortV != null) && (_any.PortV != null))
- if (PortV.equals(_any.PortV))
- return true;
-
- /* strings */
- if ((stringV != null) && (_any.stringV != null))
- if (stringV.equals(_any.stringV))
- return true;
-
- /* atoms and booleans */
- if ((atomV != null) && (_any.atomV != null))
- if (atomV.equals(_any.atomV))
- return true;
-
- /* booleans */
- if (atomV != null)
- if (_any.booleanV == Boolean.valueOf(atomV).booleanValue())
- return true;
-
- if (_any.atomV != null)
- if (booleanV == Boolean.valueOf(_any.atomV).booleanValue())
- return true;
-
- /* integer types plus floating point types */
- double _ownNS =
- longV+doubleV;
-
- double _othersNS =
- _any.longV+_any.doubleV;
-
- if ((equal(_ownNS,_othersNS)) &&
- (!equal(_ownNS,0)))
- return true;
-
- /* All together, 0 or false */
- if ((equal(_ownNS,_othersNS)) &&
- booleanV == _any.booleanV)
- return true;
-
-
- return false;
-
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- }
-
- /**
- Writes the value of Term to a stream
- **/
- public void write_value(com.ericsson.otp.erlang.OtpOutputStream _os)
- throws java.lang.Exception {
-
- if ((tcV == null) && (ObjV != null))
- _os.write_any(ObjV); // Type not generated by IC
-
- else {
-
- switch(tcV.kind().value()) {
-
- case TCKind._tk_octet :
- case TCKind._tk_char :
- case TCKind._tk_wchar :
- case TCKind._tk_short :
- case TCKind._tk_ushort :
- case TCKind._tk_long :
- case TCKind._tk_longlong :
- case TCKind._tk_ulong :
- case TCKind._tk_ulonglong :
- _os.write_long(longV);
- break;
-
- case TCKind._tk_float :
- _os.write_double(doubleV);
- break;
-
- case TCKind._tk_double :
- _os.write_double(doubleV);
- break;
-
- case TCKind._tk_boolean :
- _os.write_boolean(booleanV);
- break;
-
- case TCKind._tk_string :
- case TCKind._tk_wstring :
- _os.write_string(stringV);
- break;
-
- case TCKind._tk_atom :
- _os.write_atom(stringV);
- break;
-
- case TCKind._tk_struct:
- if (isPid())
- PidHelper.marshal(_os, PidV);
- else {
- if (isReference())
- RefHelper.marshal(_os, RefV);
- else {
- if (isPort())
- PortHelper.marshal(_os, PortV);
- else
- _os.write(os.toByteArray());
- }
- }
- break;
-
- case TCKind._tk_union:
- case TCKind._tk_array:
- case TCKind._tk_sequence:
- case TCKind._tk_enum:
- _os.write(os.toByteArray());
- break;
-
- case TCKind._tk_void :
- _os.write_atom("ok");
- break;
-
- /*
- * Not supported types
- */
- default:
- throw new java.lang.Exception("BAD KIND");
- }
- }
- }
-
-
-
- /*
- * Insert and extract each primitive type
- */
-
-
- /* short */
-
- /**
- Short value extractor method
- @return short, the value of Term
- **/
- public short extract_short()
- throws java.lang.Exception {
-
- if (tcV == null)
- return (short) longV;
-
- if (tcV.kind() == TCKind.tk_short)
- return (short) longV;
-
- throw new java.lang.Exception("");
- }
-
- /**
- Short value insertion method
- **/
- public void insert_short(short s) {
- longV = s;
- tag = com.ericsson.otp.erlang.OtpExternal.intTag;
- tcV = new TypeCode(TCKind.tk_short);
- };
-
- /**
- Short value insertion method
- **/
- public void insert_short(long l) {
- longV = l;
- tag = com.ericsson.otp.erlang.OtpExternal.intTag;
- tcV = new TypeCode(TCKind.tk_short);
- };
-
-
- /* long */
-
- /**
- Long value extractor method
- @return int, the value of Term
- **/
- public int extract_long()
- throws java.lang.Exception {
-
- if (tcV == null)
- return (int) longV;
-
- if (tcV.kind() == TCKind.tk_long)
- return (int) longV;
-
- throw new java.lang.Exception("");
- }
-
- /**
- Long value insertion method
- **/
- public void insert_long(int i){
- longV = i;
- tag = com.ericsson.otp.erlang.OtpExternal.intTag;
- tcV = new TypeCode(TCKind.tk_long);
- }
-
- /**
- Long value insertion method
- **/
- public void insert_long(long l){
- longV = l;
- tag = com.ericsson.otp.erlang.OtpExternal.intTag;
- tcV = new TypeCode(TCKind.tk_long);
- }
-
-
- /* longlong */
-
- /**
- Long Long value extractor method
- @return long, the value of Term
- **/
- public long extract_longlong()
- throws java.lang.Exception {
-
- if (tcV == null)
- return longV;
-
- if (tcV.kind() == TCKind.tk_longlong)
- return longV;
-
- throw new java.lang.Exception("");
- }
-
-
- /**
- Long Long value insertion method
- **/
- public void insert_longlong(long l){
- longV = l;
- tag = com.ericsson.otp.erlang.OtpExternal.intTag;
- tcV = new TypeCode(TCKind.tk_longlong);
- }
-
-
- /* ushort */
-
- /**
- Unsigned Short value extractor method
- @return short, the value of Term
- **/
- public short extract_ushort()
- throws java.lang.Exception {
-
- if (tcV == null)
- return (short) longV;
-
- if (tcV.kind() == TCKind.tk_ushort)
- return (short) longV;
-
- throw new java.lang.Exception("");
- }
-
- /**
- Unsigned Short value insertion method
- **/
- public void insert_ushort(short s){
- longV = s;
- tag = com.ericsson.otp.erlang.OtpExternal.intTag;
- tcV = new TypeCode(TCKind.tk_ushort);
- }
-
- /**
- Unsigned Short value insertion method
- **/
- public void insert_ushort(long l){
- longV = l;
- tag = com.ericsson.otp.erlang.OtpExternal.intTag;
- tcV = new TypeCode(TCKind.tk_ushort);
- }
-
-
- /* ulong */
-
- /**
- Unsigned Long value extractor method
- @return int, the value of Term
- **/
- public int extract_ulong()
- throws java.lang.Exception{
-
- if (tcV == null)
- return (int) longV;
-
- if (tcV.kind() == TCKind.tk_ulong)
- return (int) longV;
-
- throw new java.lang.Exception("");
- }
-
- /**
- Unsigned Long value insertion method
- **/
- public void insert_ulong(int i){
- longV = i;
- tag = com.ericsson.otp.erlang.OtpExternal.intTag;
- tcV = new TypeCode(TCKind.tk_ulong);
- }
-
-
- /**
- Unsigned Long value insertion method
- **/
- public void insert_ulong(long l){
- longV = l;
- tag = com.ericsson.otp.erlang.OtpExternal.intTag;
- tcV = new TypeCode(TCKind.tk_ulong);
- }
-
-
-
- /* ulonglong */
-
- /**
- Unsigned Long Long value extractor method
- @return long, the value of Term
- **/
- public long extract_ulonglong()
- throws java.lang.Exception {
-
- if (tcV == null)
- return longV;
-
- if (tcV.kind() == TCKind.tk_ulonglong)
- return longV;
-
- throw new java.lang.Exception("");
- }
-
-
- /**
- Unsigned Long Long value insertion method
- **/
- public void insert_ulonglong(long l){
- longV = l;
- tag = com.ericsson.otp.erlang.OtpExternal.intTag;
- tcV = new TypeCode(TCKind.tk_ulonglong);
- }
-
-
-
- /* float */
- /**
- Float value extractor method
- @return float, the value of Term
- **/
- public float extract_float()
- throws java.lang.Exception{
-
- if (tcV == null)
- return (float) doubleV;
-
- if (tcV.kind() == TCKind.tk_float)
- return (float) doubleV;
-
- throw new java.lang.Exception("");
- }
-
-
- /**
- Float value insertion method
- **/
- public void insert_float(float f){
- doubleV = f;
- tag = com.ericsson.otp.erlang.OtpExternal.floatTag;
- tcV = new TypeCode(TCKind.tk_float);
- }
-
- /**
- Float value insertion method
- **/
- public void insert_float(double f){
- doubleV = f;
- tag = com.ericsson.otp.erlang.OtpExternal.floatTag;
- tcV = new TypeCode(TCKind.tk_float);
- }
-
-
- /* double */
- /**
- Double value extractor method
- @return double, the value of Term
- **/
- public double extract_double()
- throws java.lang.Exception{
-
- if (tcV == null)
- return doubleV;
-
- if (tcV.kind() == TCKind.tk_double)
- return doubleV;
-
- throw new java.lang.Exception("");
- }
-
- /**
- Double value insertion method
- **/
- public void insert_double(double d){
- doubleV = d;
- tag = com.ericsson.otp.erlang.OtpExternal.floatTag;
- tcV = new TypeCode(TCKind.tk_double);
- }
-
-
- /* boolean */
- /**
- Boolean value extractor method
- @return boolean, the value of Term
- **/
- public boolean extract_boolean()
- throws java.lang.Exception{
-
- if ((tcV == null) && (atomV != null))
- return Boolean.valueOf(atomV).booleanValue();
-
- if (tcV.kind() == TCKind.tk_boolean)
- return booleanV;
-
- throw new java.lang.Exception("");
- }
-
- /**
- Boolean value insertion method
- **/
- public void insert_boolean(boolean b){
- booleanV = b;
- tag = com.ericsson.otp.erlang.OtpExternal.atomTag;
- tcV = new TypeCode(TCKind.tk_boolean);
- }
-
-
- /* char */
- /**
- Char value extractor method
- @return char, the value of Term
- **/
- public char extract_char()
- throws java.lang.Exception{
-
- if (tcV == null)
- return (char) longV;
-
- if (tcV.kind() == TCKind.tk_char)
- return (char) longV;
-
- throw new java.lang.Exception("");
- }
-
- /**
- Char value insertion method
- **/
- public void insert_char(char c) {
- longV = c;
- tag = com.ericsson.otp.erlang.OtpExternal.smallIntTag;
- tcV = new TypeCode(TCKind.tk_char);
- }
-
- /**
- Char value insertion method
- **/
- public void insert_char(long l) {
- longV = l;
- tag = com.ericsson.otp.erlang.OtpExternal.smallIntTag;
- tcV = new TypeCode(TCKind.tk_char);
- }
-
-
-
- /* wchar */
- /**
- Wchar value extractor method
- @return char, the value of Term
- **/
- public char extract_wchar()
- throws java.lang.Exception{
-
- if (tcV == null)
- return (char) longV;
-
- if (tcV.kind() == TCKind.tk_wchar)
- return (char) longV;
-
- throw new java.lang.Exception("");
- }
-
- /**
- Wchar value insertion method
- **/
- public void insert_wchar(char c) {
- longV = c;
- tag = com.ericsson.otp.erlang.OtpExternal.smallIntTag;
- tcV = new TypeCode(TCKind.tk_wchar);
- }
-
- /**
- Wchar value insertion method
- **/
- public void insert_wchar(long l) {
- longV = l;
- tag = com.ericsson.otp.erlang.OtpExternal.smallIntTag;
- tcV = new TypeCode(TCKind.tk_wchar);
- }
-
-
- /* octet */
- /**
- Octet value extractor method
- @return byte, the value of Term
- **/
- public byte extract_octet()
- throws java.lang.Exception{
-
- if (tcV == null)
- return (byte) longV;
-
- if (tcV.kind() == TCKind.tk_octet)
- return (byte) longV;
-
- throw new java.lang.Exception("");
- }
-
- /**
- Octet value insertion method
- **/
- public void insert_octet(byte b){
- longV = b;
- tag = com.ericsson.otp.erlang.OtpExternal.smallIntTag;
- tcV = new TypeCode(TCKind.tk_octet);
- }
-
- /**
- Octet value insertion method
- **/
- public void insert_octet(long l){
- longV = l;
- tag = com.ericsson.otp.erlang.OtpExternal.smallIntTag;
- tcV = new TypeCode(TCKind.tk_octet);
- }
-
-
-
- /* string */
-
- /**
- String value extractor method
- @return String, the value of Term
- **/
- public java.lang.String extract_string()
- throws java.lang.Exception{
-
- if (tcV == null) {
- if (stringV != null)
- return stringV;
- else {
- is = this.extract_Streamable();
- stringV = is.read_string();
- return stringV;
- }
- }
- else
- if (tcV.kind() == TCKind.tk_string)
- return stringV;
-
- throw new java.lang.Exception("");
- }
-
- /**
- String value insertion method
- **/
- public void insert_string(java.lang.String s) {
- stringV = s;
- tag = com.ericsson.otp.erlang.OtpExternal.stringTag;
- tcV = new TypeCode(TCKind.tk_string);
- }
-
-
-
- /* wstring */
- /**
- Wstring value extractor method
- @return String, the value of Term
- **/
- public java.lang.String extract_wstring()
- throws java.lang.Exception{
-
- if (tcV == null) {
- if (stringV != null)
- return stringV;
- else {
- is = this.extract_Streamable();
- stringV = is.read_string();
- return stringV;
- }
- }
- else
- if (tcV.kind() == TCKind.tk_wstring)
- return stringV;
-
- throw new java.lang.Exception("");
- }
-
- /**
- Wstring value insertion method
- **/
- public void insert_wstring(java.lang.String s) {
- stringV = s;
- tag = com.ericsson.otp.erlang.OtpExternal.stringTag;
- tcV = new TypeCode(TCKind.tk_wstring);
- }
-
-
-
- /* atom */
- /**
- Atom value extractor method
- @return atom, the value of Term
- **/
- public java.lang.String extract_atom()
- throws java.lang.Exception{
-
- if ((tcV == null) && (atomV != null))
- return atomV;
-
- if (tcV.kind() == TCKind.tk_atom)
- return stringV;
-
- throw new java.lang.Exception("");
- }
-
-
- /**
- Atom value insertion method
- **/
- public void insert_atom(java.lang.String s) {
- stringV = s;
- tag = com.ericsson.otp.erlang.OtpExternal.atomTag;
- tcV = new TypeCode(TCKind.tk_atom);
- }
-
-
- /* Pid */
- /**
- Pid value extractor method
- @return Pid, the value of Term
- **/
- public Pid extract_Pid()
- throws java.lang.Exception{
-
- if ((tcV == null) && (PidV != null))
- return PidV;
-
- if (tcV.equal(PidHelper.type()))
- return PidV;
-
- throw new java.lang.Exception("");
- }
-
-
- /**
- Pid value insertion method
- **/
- public void insert_Pid(Pid p) {
- PidV = p;
- tag = com.ericsson.otp.erlang.OtpExternal.pidTag;
- tcV = PidHelper.type();
- }
-
-
-
- /* Ref */
- /**
- Ref value extractor method
- @return Ref, the value of Term
- **/
- public Ref extract_Ref()
- throws java.lang.Exception{
-
- if ((tcV == null) && (RefV != null))
- return RefV;
-
- if (tcV.equal(RefHelper.type()))
- return RefV;
-
- throw new java.lang.Exception("");
- }
-
- /**
- Ref value insertion method
- **/
- public void insert_Ref(Ref r) {
- RefV = r;
-
- if (r.isNewRef())
- tag = com.ericsson.otp.erlang.OtpExternal.newRefTag;
- else
- tag = com.ericsson.otp.erlang.OtpExternal.refTag;
-
- tcV = RefHelper.type();
- }
-
-
-
- /* Port */
- /**
- Port value extractor method
- @return Port, the value of Term
- **/
- public Port extract_Port()
- throws java.lang.Exception{
-
- if ((tcV == null) && (PortV != null))
- return PortV;
-
- if (tcV.equal(PortHelper.type()))
- return PortV;
-
- throw new java.lang.Exception("");
- }
-
- /**
- Port value insertion method
- **/
- public void insert_Port(Port p) {
- PortV = p;
- tag = com.ericsson.otp.erlang.OtpExternal.portTag;
- tcV = PortHelper.type();
- }
-
-
- /**
- Object Stream extractor method
- @return OtpInputStream, the stream value of Term
- **/
- public com.ericsson.otp.erlang.OtpInputStream extract_Streamable() {
-
- if (is == null) {
- if (os == null) {
- if (stringV == null)
- return null;
- else {
- // A sequence that become a string !
- os = new com.ericsson.otp.erlang.OtpOutputStream();
- os.write_string(stringV);
- is = new com.ericsson.otp.erlang.OtpInputStream(os.toByteArray());
- }
- }
- else {
- is = new com.ericsson.otp.erlang.OtpInputStream(os.toByteArray());
- }
- }
-
- is.reset();
- return is;
- }
-
- /**
- Inserts Objects to Term
- **/
- public void insert_Object(com.ericsson.otp.erlang.OtpErlangObject o) {
- ObjV = o;
- }
-
- /**
- Extract Object value from Term
- @return OtpErlangObject, the Object value of Term
- **/
- public com.ericsson.otp.erlang.OtpErlangObject extract_Object() {
- return ObjV;
- }
-
-
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/TermHelper.java b/lib/ic/java_src/com/ericsson/otp/ic/TermHelper.java
deleted file mode 100644
index 1a6271d9c0..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/TermHelper.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-package com.ericsson.otp.ic;
-
-/**
- Helper class for Term.
- **/
-
-public class TermHelper {
-
- // Constructors
- private TermHelper() {}
-
- // Methods
- /**
- Marshal method for the Term class, encodes the Term object to the output stream.
- **/
- public static void marshal(com.ericsson.otp.erlang.OtpOutputStream _out, Term _any)
- throws java.lang.Exception {
-
- _any.write_value(_out);
- }
-
- /**
- Unmarshal method for the Term class, decodes a Term object from the stream.
- @return Term, read from the input stream
- **/
- public static Term unmarshal(com.ericsson.otp.erlang.OtpInputStream _in)
- throws java.lang.Exception {
-
- Term _value = new Term();
-
- int tag = _in.peek();
- if (tag == com.ericsson.otp.erlang.OtpExternal.versionTag) {
- _in.read1();
- tag = _in.peek();
- }
- _value.tag = tag;
-
-
- // Allways save the object in OtpErlangObject form
- _in.mark(0);
- com.ericsson.otp.erlang.OtpErlangObject _obj = _in.read_any();
- _value.insert_Object(_obj);
-
- switch (tag) {
- case com.ericsson.otp.erlang.OtpExternal.smallIntTag:
- case com.ericsson.otp.erlang.OtpExternal.intTag:
- case com.ericsson.otp.erlang.OtpExternal.smallBigTag:
- _in.reset();
- _value.longV = _in.read_long();
- break;
-
- case com.ericsson.otp.erlang.OtpExternal.atomTag:
- case com.ericsson.otp.erlang.OtpExternal.atomUtf8Tag:
- case com.ericsson.otp.erlang.OtpExternal.smallAtomUtf8Tag:
- _in.reset();
- _value.atomV = _in.read_atom();
- break;
-
- case com.ericsson.otp.erlang.OtpExternal.floatTag:
- _in.reset();
- _value.doubleV = _in.read_double();
- break;
-
- case com.ericsson.otp.erlang.OtpExternal.refTag:
- case com.ericsson.otp.erlang.OtpExternal.newRefTag:
- _in.reset();
- com.ericsson.otp.erlang.OtpErlangRef _eref =
- _in.read_ref();
-
- if (_eref.isNewRef())
- _value.RefV = new Ref(_eref.node(),_eref.ids(),_eref.creation());
- else
- _value.RefV = new Ref(_eref.node(),_eref.id(),_eref.creation());
-
- break;
-
- case com.ericsson.otp.erlang.OtpExternal.portTag:
- _in.reset();
- com.ericsson.otp.erlang.OtpErlangPort _eport =
- _in.read_port();
-
- _value.PortV = new Port(_eport.node(),_eport.id(),_eport.creation());
- break;
-
- case com.ericsson.otp.erlang.OtpExternal.pidTag:
- _in.reset();
- com.ericsson.otp.erlang.OtpErlangPid _epid =
- _in.read_pid();
-
- _value.PidV = new Pid(_epid.node(),_epid.id(),_epid.serial(),_epid.creation());
- break;
-
- case com.ericsson.otp.erlang.OtpExternal.stringTag:
- _in.reset();
- _value.stringV = _in.read_string();
- break;
-
- case com.ericsson.otp.erlang.OtpExternal.listTag:
- case com.ericsson.otp.erlang.OtpExternal.nilTag:
- case com.ericsson.otp.erlang.OtpExternal.smallTupleTag:
- case com.ericsson.otp.erlang.OtpExternal.largeTupleTag:
- case com.ericsson.otp.erlang.OtpExternal.binTag:
-
- com.ericsson.otp.erlang.OtpOutputStream _os =
- new com.ericsson.otp.erlang.OtpOutputStream();
-
- _obj.encode(_os);
- _value.insert_Streamable(_os);
- break;
-
- case com.ericsson.otp.erlang.OtpExternal.largeBigTag:
- default:
- throw new com.ericsson.otp.erlang.OtpErlangDecodeException("Uknown data type: " + tag);
- }
-
- return _value;
- }
-
-}
-
-
-
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/TermHolder.java b/lib/ic/java_src/com/ericsson/otp/ic/TermHolder.java
deleted file mode 100644
index 6a30bad5ea..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/TermHolder.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-package com.ericsson.otp.ic;
-
-/**
- Holder class for Term.
- **/
-
-final public class TermHolder {
-
- /**
- Term instance variable.
- **/
- public Term value;
-
- // Constructors
- public TermHolder() {}
-
- public TermHolder(Term initial) {
- value = initial;
- }
-
- // Methods
- /**
- Marshal method for the TermHolder class, encodes the Term object value to the output stream.
- **/
- public void _marshal(com.ericsson.otp.erlang.OtpOutputStream out)
- throws java.lang.Exception {
- TermHelper.marshal(out, value);
- }
-
- /**
- Unmarshal method for the TermHolder class, decodes a Term object from the output stream
- and assigns it to the Holder value field.
- **/
- public void _unmarshal(com.ericsson.otp.erlang.OtpInputStream in)
- throws java.lang.Exception {
- value = TermHelper.unmarshal(in);
- }
-
-}
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/TypeCode.java b/lib/ic/java_src/com/ericsson/otp/ic/TypeCode.java
deleted file mode 100644
index da036fea54..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/TypeCode.java
+++ /dev/null
@@ -1,883 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-/**
- * The TypeCode class for Java IDL
- *
- */
-package com.ericsson.otp.ic;
-
-/**
- The TypeCode class is the implementation of the OMG-IDL TypeCode type.
- **/
-
-public class TypeCode {
-
- private TCKind _kind;
- private java.lang.String _id,_name;
- private int _length,_member_count,_default_index;
- private TypeCode _member_type,_discriminator_type,_content_type;
- private Any _member_label;
- private boolean extracted;
- private TypeCode _members[];
- private java.lang.String _member_names[];
- private Any _member_labels[];
-
-
-
- /*
- * Constructors
- */
- public TypeCode() {
- extracted = false;
- _members = null;
- _member_names = null;
- _member_labels = null;
- _kind = null;
- _id = null;
- _name = null;
- _length = -1;
- _member_count = -1;
- _default_index = -1;
- _member_type = null;
- _content_type = null;
- _discriminator_type = null;
- _member_label = null;
- }
-
- public TypeCode(TCKind __kind) {
- _kind = __kind;
- }
-
-
- /*
- * Operation "TypeCode::equal"
- */
-
- /**
- Comparisson method for TypeCode.
- @return true if the input TypeCode value equals the value of the current object, false otherwize
- **/
- public boolean equal(TypeCode tc) {
-
- try {
-
- TCKind tck = tc.kind();
-
- switch (tck.value()) {
-
- case TCKind._tk_short:
- case TCKind._tk_long:
- case TCKind._tk_longlong:
- case TCKind._tk_ushort:
- case TCKind._tk_ulong:
- case TCKind._tk_ulonglong:
- case TCKind._tk_float:
- case TCKind._tk_double:
- case TCKind._tk_boolean:
- case TCKind._tk_char:
- case TCKind._tk_wchar:
- case TCKind._tk_octet:
- case TCKind._tk_string:
- case TCKind._tk_wstring:
- case TCKind._tk_any:
- case TCKind._tk_void:
- case TCKind._tk_atom:
-
- return (tck.value() == _kind.value());
-
- case TCKind._tk_struct:
-
- if((tc.id().compareTo(_id) == 0) &&
- (tc.name().compareTo(_name) == 0) &&
- (tc.member_count() == _member_count)){
-
- for (int i = 0; i < _member_count; i++)
- if (!tc.member_type(i).equal(_members[i]))
- return false;
-
- return true;
- }
- else
- return false;
-
- case TCKind._tk_union:
-
- if((tc.id().compareTo(_id) == 0) &&
- (tc.name().compareTo(_name) == 0) &&
- (tc.member_count() == _member_count) &&
- (tc.discriminator_type().equal(_discriminator_type))){
-
- for (int i = 0; i < _member_count; i++)
- if ((!tc.member_type(i).equal(_members[i])) &&
- (tc.member_name(i).compareTo(_member_names[i]) != 0))
- return false;
-
- return true;
- }
- else
- return false;
-
- case TCKind._tk_sequence:
- case TCKind._tk_array:
-
- if((tck.value() == _kind.value()) &&
- (tc.content_type().equal(_content_type)))
- return true;
- else
- return false;
-
- case TCKind._tk_enum:
- if((tck.value() == _kind.value()) &&
- (tc.member_count() == _member_count)) {
-
- for (int i = 0; i < _member_count; i++)
- if (tc.member_name(i).compareTo(_member_names[i]) != 0)
- return false;
-
- return true;
- }
- else
- return false;
-
- // Not used in real
- case TCKind._tk_null:
- case TCKind._tk_TypeCode:
- case TCKind._tk_Principal:
- case TCKind._tk_objref:
- case TCKind._tk_alias:
- case TCKind._tk_except:
- case TCKind._tk_longdouble:
- case TCKind._tk_fixed:
-
- return (tck.value() == _kind.value());
-
- default :
- return false;
-
- }
- } catch (Exception e) {
- return false;
- }
-
- }
-
-
- /*
- * Operation "TypeCode::kind"
- */
-
- /**
- Accessor method for the TCKind value of TypeCode.
- @return TCKind, the TCKind value of the TypeCode object.
- **/
- public TCKind kind() {
- return _kind;
- }
-
- /**
- Insertion method for the TCKind value of TypeCode.
- Sets the TCKind value of the object.
- **/
- public void kind(TCKind __kind) {
- _kind = __kind;
- }
-
- /**
- Insertion method for the TCKind value of TypeCode.
- Sets the TCKind value of the object.
- **/
- public static TCKind kind(java.lang.String atom)
- throws java.lang.Exception {
-
- if (atom.equals("tk_null"))
- return TCKind.tk_null;
- else
- if (atom.equals("tk_void"))
- return TCKind.tk_void;
- else
- if (atom.equals("tk_short"))
- return TCKind.tk_short;
- else
- if (atom.equals("tk_long"))
- return TCKind.tk_long;
- else
- if (atom.equals("tk_ushort"))
- return TCKind.tk_ushort;
- else
- if (atom.equals("tk_ulong"))
- return TCKind.tk_ulong;
- else
- if (atom.equals("tk_float"))
- return TCKind.tk_float;
- else
- if (atom.equals("tk_double"))
- return TCKind.tk_double;
- else
- if (atom.equals("tk_boolean"))
- return TCKind.tk_boolean;
- else
- if (atom.equals("tk_char"))
- return TCKind.tk_char;
- else
- if (atom.equals("tk_octet"))
- return TCKind.tk_octet;
- else
- if (atom.equals("tk_any"))
- return TCKind.tk_any;
- else
- if (atom.equals("tk_TypeCode"))
- return TCKind.tk_TypeCode;
- else
- if (atom.equals("tk_Principal"))
- return TCKind.tk_Principal;
- else
- if (atom.equals("tk_objref"))
- return TCKind.tk_objref;
- else
- if (atom.equals("tk_struct"))
- return TCKind.tk_struct;
- else
- if (atom.equals("tk_union"))
- return TCKind.tk_union;
- else
- if (atom.equals("tk_enum"))
- return TCKind.tk_enum;
- else
- if (atom.equals("tk_string"))
- return TCKind.tk_string;
- else
- if (atom.equals("tk_sequence"))
- return TCKind.tk_sequence;
- else
- if (atom.equals("tk_array"))
- return TCKind.tk_array;
- else
- if (atom.equals("tk_alias"))
- return TCKind.tk_alias;
- else
- if (atom.equals("tk_except"))
- return TCKind.tk_except;
- else
- if (atom.equals("tk_longlong"))
- return TCKind.tk_longlong;
- else
- if (atom.equals("tk_ulonglong"))
- return TCKind.tk_ulonglong;
- else
- if (atom.equals("tk_longdouble"))
- return TCKind.tk_longdouble;
- else
- if (atom.equals("tk_wchar"))
- return TCKind.tk_wchar;
- else
- if (atom.equals("tk_wstring"))
- return TCKind.tk_wstring;
- else
- if (atom.equals("tk_fixed"))
- return TCKind.tk_fixed;
- else
- if (atom.equals("tk_atom"))
- return TCKind.tk_atom;
- else
- throw new java.lang.Exception("BAD KIND");
-
- }
-
-
-
- /*
- * Operation "TypeCode::id"
- */
-
- /**
- Accessor method for the id value of TypeCode.
- @return String, the id value of TypeCode object
- **/
- public java.lang.String id()
- throws java.lang.Exception{
-
- if (_id == null)
- throw new java.lang.Exception("BAD KIND");
-
- return _id;
- }
-
-
- /**
- Insertion method for the id value of TypeCode.
- Sets the id value of the object.
- **/
- public void id(java.lang.String __id) {
-
- _id = __id;
- }
-
-
-
- /*
- * Operation "TypeCode::name"
- */
-
- /**
- Accessor method for the name value of TypeCode.
- @return String, the name value of TypeCode object
- **/
- public java.lang.String name()
- throws java.lang.Exception{
-
- if (_name == null)
- throw new java.lang.Exception("BAD KIND");
-
- return _name;
- }
-
- /**
- Insertion method for the name value of TypeCode.
- Sets the name value of the object.
- **/
- public void name(java.lang.String __name) {
- _name = __name;
- }
-
-
-
- /*
- * Operation "TypeCode::member_count"
- */
-
- /**
- Accessor method for the member number value of TypeCode.
- @return int, the number of members of TypeCode object
- **/
- public int member_count()
- throws java.lang.Exception{
-
- if (_member_count == -1)
- throw new java.lang.Exception("BAD KIND");
-
- return _member_count;
- }
-
- /**
- Insertion method for the member number value of TypeCode.
- Sets the number of members value of the object.
- **/
- public void member_count(int __member_count) {
-
- switch(_kind.value()) {
- case TCKind._tk_struct:
- _members = new TypeCode[__member_count];
- _member_names = new java.lang.String[__member_count];
- _member_count = __member_count;
- break;
- case TCKind._tk_union:
- _members = new TypeCode[__member_count];
- _member_names = new java.lang.String[__member_count];
- _member_labels = new Any[__member_count];
- _member_count = __member_count;
- break;
- case TCKind._tk_enum:
- _member_names = new java.lang.String[__member_count];
- _member_count = __member_count;
- break;
- default :
- // Do nothing
- }
- }
-
-
- /*
- * Operation "TypeCode::member_name"
- */
-
- /**
- Member name accessor method for TypeCode.
- @return String, the name value of the member of the TypeCode object
- on the selected index
- **/
- public java.lang.String member_name(int __index)
- throws java.lang.Exception{
-
- return _member_names[__index];
- }
-
- /**
- Insertion method for the indexed member name of TypeCode.
- Sets the name of a member value of the object at the selected index..
- **/
- public void member_name(int __index, java.lang.String __member_name) {
- _member_names[__index] = __member_name;
- }
-
-
- /*
- * Operation "TypeCode::member_type"
- */
-
- /**
- Member type accessor method for TypeCode.
- @return TypeCOde, the type of the member of the TypeCode object
- on the selected index
- **/
- public TypeCode member_type(int __index)
- throws java.lang.Exception{
-
- return _members[__index];
- }
-
- /**
- Insertion method for the indexed member type of TypeCode.
- Sets the type of a member value of the object at the selected index..
- **/
- public void member_type(int __index, TypeCode __member_type) {
- _members[__index] = __member_type;
- }
-
-
- /*
- * Operation "TypeCode::member_label"
- */
-
- /**
- Member label accessor method for TypeCode.
- @return Any, the label of the member of the TypeCode object
- on the selected index
- **/
- public Any member_label(int __index)
- throws java.lang.Exception{
-
- return _member_labels[__index];
- }
-
- /**
- Insertion method for the indexed member label of TypeCode.
- Sets the label of a member value of the object at the selected index.
- **/
- public void member_label(int __index, Any __member_label) {
- _member_labels[__index] = __member_label;
- }
-
-
- /*
- * Operation "TypeCode::discriminator_type"
- */
-
- /**
- Discriminator type accessor method for TypeCode.
- @return TypeCode, the type of the discriminator of the TypeCode object
- **/
- public TypeCode discriminator_type()
- throws java.lang.Exception{
-
- if (_discriminator_type == null)
- throw new java.lang.Exception("BAD KIND");
-
- return _discriminator_type;
- }
-
- /**
- Insertion method for the type of the discriminator value of TypeCode.
- Sets the discriminator type value of the object.
- **/
- public void discriminator_type(TypeCode __discriminator_type) {
- _discriminator_type = __discriminator_type;
- }
-
-
- /*
- * Operation "TypeCode::default_index"
- */
-
- /**
- Index accessor method for TypeCode.
- @return int, the default index value of the member of the TypeCode object
- **/
- public int default_index()
- throws java.lang.Exception{
-
- if (_default_index == -1)
- throw new java.lang.Exception("BAD KIND");
-
- return _default_index;
- }
-
- /**
- Insertion method for the default index value of TypeCode.
- Sets the default index value of the object.
- **/
- public void default_index(int __default_index) {
- _default_index = __default_index;
- }
-
-
- /*
- * Operation "TypeCode::length"
- */
-
- /**
- Length accessor method for TypeCode.
- @return int, the length of the TypeCode object
- **/
- public int length()
- throws java.lang.Exception{
-
- if (_length == -1)
- throw new java.lang.Exception("BAD KIND");
-
- return _length;
- }
-
- /**
- Insertion method for the length value of TypeCode.
- Sets the length value of the object.
- **/
- public void length(int __length) {
- _length = __length;
- }
-
-
- /*
- * Operation "TypeCode::content_type"
- */
-
- /**
- Content type accessor method for TypeCode.
- @return TypeCode, the content type of the TypeCode object
- **/
- public TypeCode content_type()
- throws java.lang.Exception {
-
- if (_content_type == null)
- throw new java.lang.Exception("BAD KIND");
-
- return _content_type;
- }
-
- /**
- Insertion method for the content type value of TypeCode.
- Sets the content type value of the object.
- **/
- public void content_type(TypeCode __content_type) {
- _content_type = __content_type;
- }
-
-
- /**
- Marshal operation for TypeCode.
- **/
- public static void marshal(com.ericsson.otp.erlang.OtpOutputStream _os, TypeCode _tc)
- throws java.lang.Exception {
-
- TypeCode memberTC = null;
- int len = -1;
-
- switch(_tc.kind().value()) {
-
- case TCKind._tk_short :
- _os.write_atom("tk_short");
- break;
- case TCKind._tk_ushort :
- _os.write_atom("tk_ushort");
- break;
- case TCKind._tk_long :
- _os.write_atom("tk_long");
- break;
- case TCKind._tk_longlong :
- _os.write_atom("tk_longlong");
- break;
- case TCKind._tk_ulong :
- _os.write_atom("tk_ulong");
- break;
- case TCKind._tk_ulonglong :
- _os.write_atom("tk_ulonglong");
- break;
- case TCKind._tk_float :
- _os.write_atom("tk_float");
- break;
- case TCKind._tk_double :
- _os.write_atom("tk_double");
- break;
- case TCKind._tk_boolean :
- _os.write_atom("tk_boolean");
- break;
- case TCKind._tk_char :
- _os.write_atom("tk_char");
- break;
- case TCKind._tk_wchar :
- _os.write_atom("tk_wchar");
- break;
- case TCKind._tk_octet :
- _os.write_atom("tk_octet");
- break;
- case TCKind._tk_string :
- _os.write_tuple_head(2);
- _os.write_atom("tk_string");
- _os.write_ulong(_tc.length());
- break;
- case TCKind._tk_wstring :
- _os.write_tuple_head(2);
- _os.write_atom("tk_wstring");
- _os.write_ulong(_tc.length());
- break;
- case TCKind._tk_struct:
- len = _tc.member_count();
- _os.write_tuple_head(4);
- _os.write_atom("tk_struct");
- _os.write_string(_tc.id());
- _os.write_string(_tc.name());
- // Member list
- _os.write_list_head(len);
- for(int i=0; i<len; i++) {
- _os.write_tuple_head(2);
- _os.write_string(_tc.member_name(i));
- marshal(_os,_tc.member_type(i));
- }
- _os.write_nil();
- break;
- case TCKind._tk_union:
- len = _tc.member_count();
- _os.write_tuple_head(6);
- _os.write_atom("tk_union");
- _os.write_string(_tc.id());
- _os.write_string(_tc.name());
- marshal(_os,_tc.discriminator_type());
- _os.write_int(_tc.default_index());
- // Member list
- _os.write_list_head(len);
- for(int i=0; i<len; i++) {
- _os.write_tuple_head(3);
- _tc.member_label(i).write_value(_os);
- _os.write_string(_tc.member_name(i));
- marshal(_os,_tc.member_type(i));
- }
- _os.write_nil();
- break;
- case TCKind._tk_sequence:
- _os.write_tuple_head(3);
- _os.write_atom("tk_sequence");
- marshal(_os,_tc.content_type());
- _os.write_int(_tc.length());
- break;
- case TCKind._tk_array:
- _os.write_tuple_head(3);
- _os.write_atom("tk_array");
- marshal(_os,_tc.content_type());
- _os.write_int(_tc.length());
- break;
- case TCKind._tk_enum:
- len = _tc.member_count();
- _os.write_tuple_head(4);
- _os.write_atom("tk_enum");
- _os.write_string(_tc.id());
- _os.write_string(_tc.name());
- _os.write_list_head(len);
- for(int i=0; i<len; i++)
- _os.write_string(_tc.member_name(i));
- _os.write_nil();
- break;
- case TCKind._tk_any:
- _os.write_atom("tk_any");
- break;
- case TCKind._tk_void :
- _os.write_atom("tk_void");
- break;
- /*
- * Not supported types
- */
- default :
- throw new java.lang.Exception("Unsupported type");
-
- }
-
- }
-
-
- /**
- Unmarshal operation for TypeCode.
- @return TypeCode, the TypeCode read from the input stream.
- **/
- public static TypeCode unmarshal(com.ericsson.otp.erlang.OtpInputStream _is)
- throws java.lang.Exception {
-
- TypeCode _tc, __member;
- TCKind __kind;
- int __len;
- int __tag = _is.peek();
-
- switch(__tag) {
- case (com.ericsson.otp.erlang.OtpExternal.atomTag):
- case (com.ericsson.otp.erlang.OtpExternal.atomUtf8Tag):
- case (com.ericsson.otp.erlang.OtpExternal.smallAtomUtf8Tag):
- __kind = TypeCode.kind(_is.read_atom());
-
- switch(__kind.value()) {
- case TCKind._tk_short :
- case TCKind._tk_ushort :
- case TCKind._tk_long :
- case TCKind._tk_longlong :
- case TCKind._tk_ulong :
- case TCKind._tk_ulonglong :
- case TCKind._tk_float :
- case TCKind._tk_double :
- case TCKind._tk_boolean :
- case TCKind._tk_char :
- case TCKind._tk_wchar :
- case TCKind._tk_octet :
- case TCKind._tk_void :
- case TCKind._tk_any :
- _tc = new TypeCode();
- _tc.kind(__kind);
-
- return _tc;
- default :
- throw new java.lang.Exception("Unsupported type");
- }
-
- case (com.ericsson.otp.erlang.OtpExternal.smallTupleTag):
- case (com.ericsson.otp.erlang.OtpExternal.largeTupleTag):
-
- __len = _is.read_tuple_head();
- __tag = _is.peek();
-
- switch(__tag) {
-
- case (com.ericsson.otp.erlang.OtpExternal.atomTag):
- case (com.ericsson.otp.erlang.OtpExternal.atomUtf8Tag):
- case (com.ericsson.otp.erlang.OtpExternal.smallAtomUtf8Tag):
-
- __kind = TypeCode.kind(_is.read_atom());
- _tc = new TypeCode();
- _tc.kind(__kind);
-
- switch(__kind.value()) {
-
- case TCKind._tk_string :
- _tc.length((int)_is.read_ulong());
- return _tc;
-
- case TCKind._tk_wstring :
- _tc.length((int)_is.read_ulong());
- return _tc;
-
- case TCKind._tk_struct:
-
- _tc.id(_is.read_string());
- _tc.name(_is.read_string());
- __len = _is.read_list_head();
- _tc.member_count(__len);
-
- for(int i=0; i<__len; i++) {
- _is.read_tuple_head();
- _tc.member_name(i,_is.read_string());
- _tc.member_type(i,unmarshal(_is));
- }
- _is.read_nil();
-
- return _tc;
-
-
- case TCKind._tk_union:
-
- _tc.id(_is.read_string());
- _tc.name(_is.read_string());
- _tc.discriminator_type(unmarshal(_is));
- _tc.default_index(_is.read_int());
- __len = _is.read_list_head();
- _tc.member_count(__len);
-
- for(int i=0; i<__len; i++) {
- _is.read_tuple_head();
-
- __tag = _is.peek();
- Any __label = new Any();
- TypeCode __label_type = new TypeCode();
-
- __label_type.kind(com.ericsson.otp.ic.TCKind.tk_long);
- __label.type(__label_type);
-
- switch(__tag) {
- case (com.ericsson.otp.erlang.OtpExternal.stringTag):
- java.lang.String __enum = _is.read_string();
- __label.insert_string(__enum);
- break;
- case (com.ericsson.otp.erlang.OtpExternal.atomTag):
- case (com.ericsson.otp.erlang.OtpExternal.atomUtf8Tag):
- case (com.ericsson.otp.erlang.OtpExternal.smallAtomUtf8Tag):
-
- java.lang.String __default = _is.read_atom();
- __label.insert_atom(__default);
- break;
- default:
- __label.insert_long(_is.read_int());
- }
-
- _tc.member_label(i,__label);
- _tc.member_name(i,_is.read_string());
- _tc.member_type(i,unmarshal(_is));
- }
- _is.read_nil();
-
- return _tc;
-
-
- case TCKind._tk_sequence:
- _tc.content_type(unmarshal(_is));
- _tc.length(_is.read_int());
- return _tc;
-
-
- case TCKind._tk_array:
- _tc.content_type(unmarshal(_is));
- _tc.length(_is.read_int());
- return _tc;
-
-
- case TCKind._tk_enum:
-
- _tc.id(_is.read_string());
- _tc.name(_is.read_string());
- __len = _is.read_list_head();
- _tc.member_count(__len);
-
- for(int i=0; i<__len; i++)
- _tc.member_name(i,_is.read_string());
-
- _is.read_nil();
-
- return _tc;
-
- default:
- throw new java.lang.Exception("Unsupported type");
-
- }
-
- default:
- throw new java.lang.Exception("Unsupported type");
- }
-
- }
-
- return null;
- }
-
-}
-
-
diff --git a/lib/ic/prebuild.skip b/lib/ic/prebuild.skip
deleted file mode 100644
index 8d1ef24091..0000000000
--- a/lib/ic/prebuild.skip
+++ /dev/null
@@ -1 +0,0 @@
-priv
diff --git a/lib/ic/priv/lib/.gitignore b/lib/ic/priv/lib/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/ic/priv/lib/.gitignore
+++ /dev/null
diff --git a/lib/ic/priv/obj/.gitignore b/lib/ic/priv/obj/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/ic/priv/obj/.gitignore
+++ /dev/null
diff --git a/lib/ic/src/Makefile b/lib/ic/src/Makefile
deleted file mode 100644
index 6ad2fbeeb7..0000000000
--- a/lib/ic/src/Makefile
+++ /dev/null
@@ -1,219 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1998-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-
-ifeq ($(TYPE),debug)
-ERL_COMPILE_FLAGS += -Ddebug -W
-endif
-
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(IC_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/ic-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-
-MODULES= \
- ic \
- ic_erlbe \
- ic_cbe \
- icscan \
- icparse \
- iceval \
- ictype \
- ictk \
- icstruct \
- icenum \
- icpreproc \
- icunion \
- ic_pp \
- ic_pragma \
- ic_noc \
- ic_plainbe \
- ic_cclient \
- ic_cserver \
- ic_fetch \
- ic_code \
- ic_codegen \
- ic_error \
- ic_file \
- ic_forms \
- ic_genobj \
- ic_options \
- ic_symtab \
- ic_util \
- ic_jbe \
- ic_struct_java \
- ic_union_java \
- ic_enum_java \
- ic_constant_java \
- ic_sequence_java \
- ic_array_java \
- ic_attribute_java \
- ic_java_type \
- ic_erl_template
-
-
-CCL_EX_FILES = \
- ../examples/c-client/ReadMe \
- ../examples/c-client/Makefile \
- ../examples/c-client/client.c \
- ../examples/c-client/random.idl \
- ../examples/c-client/rmod_random_impl.erl \
- ../examples/c-client/test.erl
-
-CSRV_EX_FILES = \
- ../examples/c-server/ReadMe \
- ../examples/c-server/Makefile \
- ../examples/c-server/client.c \
- ../examples/c-server/client.erl \
- ../examples/c-server/server.c \
- ../examples/c-server/callbacks.c \
- ../examples/c-server/random.idl
-
-EPL_EX_FILES = \
- ../examples/erl-plain/ReadMe \
- ../examples/erl-plain/rmod_random_impl.erl \
- ../examples/erl-plain/random.idl
-
-
-ESRV_EX_FILES = \
- ../examples/erl-genserv/ReadMe \
- ../examples/erl-genserv/rmod_random_impl.erl \
- ../examples/erl-genserv/random.idl
-
-JAVA_EX_FILES = \
- ../examples/java-client-server/ReadMe \
- ../examples/java-client-server/client.java \
- ../examples/java-client-server/server.java \
- ../examples/java-client-server/serverImpl.java \
- ../examples/java-client-server/random.idl
-
-MIXED_EX_FILES = \
- ../examples/all-against-all/ReadMe \
- ../examples/all-against-all/Makefile \
- ../examples/all-against-all/client.erl \
- ../examples/all-against-all/server.erl \
- ../examples/all-against-all/client.c \
- ../examples/all-against-all/server.c \
- ../examples/all-against-all/callbacks.c \
- ../examples/all-against-all/client.java \
- ../examples/all-against-all/server.java \
- ../examples/all-against-all/serverImpl.java \
- ../examples/all-against-all/random.idl
-
-
-EXTERNAL_HRL_FILES=
-
-INTERNAL_HRL_FILES = \
- ic.hrl \
- ic_debug.hrl \
- icforms.hrl
-
-ERL_FILES= $(MODULES:%=%.erl)
-
-TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-
-YRL_FILE = icparse.yrl
-
-GEN_FILES = icparse.erl
-
-APP_FILE = ic.app
-APP_SRC = $(APP_FILE).src
-APP_TARGET = $(EBIN)/$(APP_FILE)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_LOCAL_FLAGS += -pa ../../ic/ebin
-# The -pa option is just used temporary until erlc can handle
-# includes from other directories than ../include .
-ERL_COMPILE_FLAGS += \
- $(ERL_LOCAL_FLAGS) \
- +'{parse_transform,sys_pre_attributes}' \
- +'{attribute,insert,app_vsn,"ic_$(VSN)"}' \
- -D'COMPILERVSN="$(VSN)"'
-YRL_FLAGS = -Iicyeccpre.hrl
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-debug:
- @${MAKE} TYPE=debug opt
-
-opt: $(TARGET_FILES) $(APP_TARGET)
-
-clean:
- rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET)
- rm -f errs core *~
-
-$(APP_TARGET): $(APP_SRC) ../vsn.mk
- $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
-
-docs:
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-../ebin/icparse.beam: icparse.erl
- $(V_ERLC) $(ERL_COMPILE_FLAGS) +nowarn_unused_vars +nowarn_unused_function -o$(EBIN) +pj $<
-
-icparse.erl: icparse.yrl icyeccpre.hrl
-
-### $(ERLC) $(YRL_FLAGS) $<
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) "$(RELSYSDIR)/ebin"
- $(INSTALL_DIR) "$(RELSYSDIR)/src"
- $(INSTALL_DATA) $(ERL_FILES) $(YRL_FILE) $(INTERNAL_HRL_FILES) "$(RELSYSDIR)/src"
- $(INSTALL_DIR) "$(RELSYSDIR)/examples"
- $(INSTALL_DIR) "$(RELSYSDIR)/examples/c-client"
- $(INSTALL_DATA) $(CCL_EX_FILES) "$(RELSYSDIR)/examples/c-client"
- $(INSTALL_DIR) "$(RELSYSDIR)/examples/c-server"
- $(INSTALL_DATA) $(CSRV_EX_FILES) "$(RELSYSDIR)/examples/c-server"
- $(INSTALL_DIR) "$(RELSYSDIR)/examples/erl-plain"
- $(INSTALL_DATA) $(EPL_EX_FILES) "$(RELSYSDIR)/examples/erl-plain"
- $(INSTALL_DIR) "$(RELSYSDIR)/examples/erl-genserv"
- $(INSTALL_DATA) $(ESRV_EX_FILES) "$(RELSYSDIR)/examples/erl-genserv"
- $(INSTALL_DIR) "$(RELSYSDIR)/examples/java-client-server"
- $(INSTALL_DATA) $(JAVA_EX_FILES) "$(RELSYSDIR)/examples/java-client-server"
- $(INSTALL_DIR) "$(RELSYSDIR)/examples/all-against-all"
- $(INSTALL_DATA) $(MIXED_EX_FILES) "$(RELSYSDIR)/examples/all-against-all"
-
-release_docs_spec:
-
diff --git a/lib/ic/src/ic.app.src b/lib/ic/src/ic.app.src
deleted file mode 100644
index 7dd47ac9c6..0000000000
--- a/lib/ic/src/ic.app.src
+++ /dev/null
@@ -1,53 +0,0 @@
-{application, ic,
- [{description, "The IDL Compiler"},
- {vsn, "%VSN%"},
- {modules,
- [
- ic,
- ic_cclient,
- ic_cbe,
- ic_cserver,
- ic_erlbe,
- ic_fetch,
- ic_noc,
- ic_plainbe,
- ic_pp,
- ic_pragma,
- icenum,
- iceval,
- icparse,
- icpreproc,
- icscan,
- icstruct,
- ictk,
- ictype,
- ic_array_java,
- ic_attribute_java,
- ic_code,
- ic_codegen,
- ic_constant_java,
- ic_enum_java,
- ic_error,
- ic_file,
- ic_forms,
- ic_genobj,
- ic_java_type,
- ic_jbe,
- ic_options,
- ic_sequence_java,
- ic_struct_java,
- ic_symtab,
- ic_union_java,
- ic_util,
- icunion,
- ic_erl_template
- ]
- },
- {registered, []},
- {applications, [stdlib, kernel]},
- {env, []},
- {mod, {ic, []}},
- {runtime_dependencies, ["stdlib-2.0","kernel-3.0","erts-6.0"]}
-]}.
-
-
diff --git a/lib/ic/src/ic.erl b/lib/ic/src/ic.erl
deleted file mode 100644
index 062fbef435..0000000000
--- a/lib/ic/src/ic.erl
+++ /dev/null
@@ -1,415 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(ic).
-
-
--export([sgen/1, gen/1, gen/2, help/0, compile/3]).
-
-
-%%------------------------------------------------------------
-%%
-%% Internal stuff
-%%
-%%------------------------------------------------------------
-
--export([filter_params/2, handle_preproc/4, do_gen/4]).
-
--import(lists, [foldr/3]).
-
-
--include("icforms.hrl").
--include("ic.hrl").
-
--include_lib("stdlib/include/erl_compile.hrl").
-
--export([make_erl_options/1]). % For erlc
-
--export([main/3, do_scan/1, do_parse/2, do_type/2]).
-
-
-%%------------------------------------------------------------
-%%
-%% Entry point
-%%
-%%------------------------------------------------------------
-
-%% compile(AbsFileName, Outfile, Options)
-%% Compile entry point for erl_compile.
-
-compile(File, _OutFile, Options) ->
- case gen(File, make_erl_options(Options)) of
- ok -> ok;
- Other -> Other
- end.
-
-
-%% Entry for the -s switch
-sgen(ArgList) ->
-%%% io:format("sgen called w ~p~n", [ArgList]),
- apply(?MODULE, gen, ArgList).
-
-
-gen(File) ->
- gen(File, []).
-
-gen(File, Opts) ->
- G = ic_genobj:new(Opts),
- IdlFile = ic_file:add_dot_idl(File),
- case ic_options:get_opt(G, show_opts) of
- true ->
- io:format("Opts: ~p~n", [ic_options:which_opts(G)]);
- _ -> ok
- end,
- ic_genobj:set_idlfile(G, IdlFile),
- case catch gen2(G, File, Opts) of
- {_, {'EXIT', R}} ->
- ic_genobj:free_table_space(G), %% Free space for all ETS tables
- io:format("Fatal error : ~p~n",[R]),
- error;
- {_, {'EXIT', _, R}} ->
- ic_genobj:free_table_space(G), %% Free space for all ETS tables
- io:format("Fatal error : ~p~n",[R]),
- error;
- {'EXIT', R} ->
- ic_genobj:free_table_space(G), %% Free space for all ETS tables
- io:format("Fatal error : ~p~n",[R]),
- error;
- {'EXIT', _, R} ->
- ic_genobj:free_table_space(G), %% Free space for all ETS tables
- io:format("Fatal error : ~p~n",[R]),
- error;
- %% In this case, the pragma registration
- %% found errors so this should return error.
- error ->
- ic_genobj:free_table_space(G), %% Free space for all ETS tables
- error;
- _ ->
- X = ic_error:return(G),
- ic_genobj:free_table_space(G), %% Free space for all ETS tables
- X
- end.
-
-
-gen2(G, File, Opts) ->
- case ic_options:get_opt(G, time) of
- true ->
- time("TOTAL ", ic, main, [G, File, Opts]);
- _ ->
- case main(G, File, Opts) of
- error ->
- error;
- _ ->
- ok
- end
- end.
-
-
-
-do_gen(erl_corba, G, File, T) ->
- ic_erlbe:do_gen(G, File, T);
-do_gen(erl_template, G, File, T) ->
- ic_erl_template:do_gen(G, File, T);
-do_gen(erl_genserv, G, File, T) ->
- ic_erlbe:do_gen(G, File, T);
-do_gen(c_genserv, G, File, T) ->
- ic_cclient:do_gen(G, File, T);
-do_gen(noc, G, File, T) ->
- ic_noc:do_gen(G, File, T);
-do_gen(erl_plain, G, File, T) ->
- ic_plainbe:do_gen(G, File, T);
-do_gen(c_server, G, File, T) ->
- ic_cserver:do_gen(G, File, T);
-do_gen(c_client, G, File, T) ->
- ic_cclient:do_gen(G, File, T);
-%% Java backend
-do_gen(java, G, File, T) ->
- ic_jbe:do_gen(G, File, T);
-%% No language choice
-do_gen(_,_,_,_) ->
- ok.
-
-do_scan(G) ->
- icscan:scan(G, ic_genobj:idlfile(G)).
-
-
-do_parse(G, Tokens) ->
- case icparse:parse(Tokens) of
- {ok, L} -> L;
- X when element(1, X) == error ->
- Err = element(2, X),
- ic_error:fatal_error(G, {parse_error, element(1, Err),
- element(3, Err)});
- X -> exit(X)
- end.
-
-
-do_type(G, Form) ->
- ictype:type_check(G, Form).
-
-time(STR,M,F,A) ->
- case timer:tc(M, F, A) of
- {_, {'EXIT', R}} -> exit(R);
- {_, {'EXIT', _, R}} -> exit(R);
- {_, _X} when element(1, _X)==error -> throw(_X);
- {_T, _R} ->
- io:format("Time for ~s: ~10.2f~n", [STR, _T/1000000]),
- _R
- end.
-
-
-
-%% Filters parameters so that only those with certain attributes are
-%% seen. The filter parameter is a list of attributes that will be
-%% seen, ex. [in] or [inout, out]
-filter_params(Filter, Params) ->
- lists:filter(fun(P) ->
- lists:member(get_param_attr(P#param.inout), Filter) end,
- Params).
-
-
-%% Access primitive to get the attribute name (and discard the line
-%% number).
-get_param_attr({A, _N}) -> A.
-
-
-%%
-%% Fixing the preproc directives
-%%
-handle_preproc(G, _N, line_nr, X) ->
- Id = ic_forms:get_id2(X),
- Flags = X#preproc.aux,
- case Flags of
- [] -> ic_genobj:push_file(G, Id);
- _ ->
- foldr(fun({_, _, "1"}, Gprim) -> ic_genobj:push_file(Gprim, Id);
- ({_, _, "2"}, Gprim) -> ic_genobj:pop_file(Gprim, Id);
- ({_, _, "3"}, Gprim) -> ic_genobj:sys_file(Gprim, Id) end,
- G, Flags)
- end;
-handle_preproc(G, _N, _Other, _X) ->
- G.
-
-
-
-%%------------------------------------------------------------
-%%
-%% The help department
-%%
-%%
-%%
-%%------------------------------------------------------------
-
-help() ->
- io:format("No help available at the moment~n", []),
- ok.
-
-print_version_str(G) ->
- case {ic_options:get_opt(G, silent), ic_options:get_opt(G, silent2)} of
- {true, _} -> ok;
- {_, true} -> ok;
- _ ->
- io:format("Erlang IDL compiler version ~s~n", [?COMPILERVSN])
- end.
-
-
-
-%%
-%% Converts generic compiler options to specific options.
-%%
-%% Used by erlc
-%%
-
-make_erl_options(Opts) ->
-
- %% This way of extracting will work even if the record passed
- %% has more fields than known during compilation.
-
- Includes1 = Opts#options.includes,
- Defines = Opts#options.defines,
- Outdir = Opts#options.outdir,
- Warning = Opts#options.warning,
- Verbose = Opts#options.verbose,
- Specific = Opts#options.specific,
- Optimize = Opts#options.optimize,
- PreProc =
- lists:flatten(
- lists:map(fun(D) -> io_lib:format("-I\"~ts\" ", [ic_util:to_list(D)]) end,
- Includes1)++
- lists:map(
- fun ({Name, Value}) ->
- io_lib:format("-D~s=~s ", [ic_util:to_list(Name), ic_util:to_list(Value)]);
- (Name) ->
- io_lib:format("-D~s ", [ic_util:to_list(Name)])
- end,
- Defines)),
- Options =
- case Verbose of
- true -> [];
- false -> []
- end ++
- case Warning of
- 0 -> [nowarn];
- _ -> ['Wall']
- end ++
- case Optimize of
- 0 -> [];
- _ -> []
- end,
-
- Options++[{outdir, Outdir}, {preproc_flags, PreProc}]++Specific.
-
-
-%%%
-%%% NEW main, avoids memory fragmentation
-%%%
-main(G, File, _Opts) ->
- print_version_str(G),
- ?ifopt(G, time, io:format("File ~p compilation started : ~p/~p/~p ~p:~2.2.0p~n",
- [ic_genobj:idlfile(G),
- element(1,date()),
- element(2, date()),
- element(3, date()),
- element(1, time()),
- element(2, time())])),
-
- case ic_options:get_opt(G, help) of
- true -> help();
-
- _ ->
- scanning(G, File)
- end.
-
-
-
-scanning(G, File) ->
- S = ?ifopt2(G, time,
- time("input file scanning ", ic, do_scan, [G]),
- ic:do_scan(G)),
- ?ifopt2(G, tokens, io:format("TOKENS: ~p~n", [S]),
- parsing(G, File, S)).
-
-parsing(G, File, S) ->
- T = ?ifopt2(G,
- time,
- time("input file parsing ", ic, do_parse, [G,S]),
- ic:do_parse(G,S)),
- ?ifopt2(G, form, io:format("PARSE FORM: ~p~n", [T]),
- pragma(G, File, T)).
-
-
-
-pragma(G, File, T) ->
- case ?ifopt2(G,
- time,
- time("pragma registration ", ic_pragma, pragma_reg, [G,T]),
- ic_pragma:pragma_reg(G,T)) of
- %% All pragmas were successfully applied
- {ok,Clean} ->
- typing(G, File, Clean);
-
- error ->
- error
- end.
-
-
-typing(G, File, Clean) ->
- case catch ?ifopt2(G,
- time,
- time("type code appliance ", ic, do_type, [G,Clean]),
- ic:do_type(G,Clean)) of
- {'EXIT',Reason} ->
- io:format("Error under type appliance : ~p~n",[Reason]),
- error;
-
- T2 ->
- ?ifopt2(G, tform, io:format("TYPE FORM: ~p~n", [T2]),
- generation(G, File, T2))
- end.
-
-
-
-generation(G, File, T2) ->
- case ic_options:get_opt(G, multiple_be) of
- false ->
- single_generation(G, File, T2);
- List ->
- OutDir =
- case ic_options:get_opt(G, outdir) of
- false ->
- [];
- Dir ->
- Dir
- end,
-
- case ic_options:get_opt(G, be) of
- false ->
- ok;
- Be ->
- %% Generate this first
- ic_options:add_opt(G,[{outdir,OutDir++atom_to_list(Be)}],true),
- single_generation(G, File, T2)
- end,
- multiple_generation(G, File, T2, OutDir, List)
- end.
-
-multiple_generation(_G, _File, _T2, _RootDir, []) ->
- ok;
-multiple_generation(G, File, T2, RootDir, [Be|Bes]) ->
- ic_options:add_opt(G,[{outdir,RootDir++atom_to_list(Be)}],true),
- ic_options:add_opt(G,[{be,Be}],true),
- single_generation(G, File, T2),
-
- case ic_error:get_error_count(G) of
- 0 ->
- multiple_generation(G,File,T2,RootDir,Bes);
- _ ->
- %% Errors reported, abort
- ok
- end.
-
-
-single_generation(G, File, T2) ->
- case ic_error:get_error_count(G) of
- 0 ->
- %% Check if user has sett backend option
- case ic_options:get_opt(G, be) of
- false ->
- %% Use default backend option
- DefaultBe = ic_options:defaultBe(),
- ic_options:add_opt(G,[{be,DefaultBe}],true),
-
- ?ifopt2(G,
- time,
- time("code generation ", ic, do_gen, [DefaultBe, G, File, T2]),
- ic:do_gen(DefaultBe, G, File, T2));
- Be ->
- %% Use user defined backend
- ?ifopt2(G,
- time,
- time("code generation ", ic, do_gen, [Be, G, File, T2]),
- ic:do_gen(Be, G, File, T2))
- end;
- _ ->
- ok %% Does not matter
- end.
-
-
-
diff --git a/lib/ic/src/ic.hrl b/lib/ic/src/ic.hrl
deleted file mode 100644
index cf4b6a50d6..0000000000
--- a/lib/ic/src/ic.hrl
+++ /dev/null
@@ -1,159 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
-
-%%------------------------------------------------------------
-%% Configuration macros
--define(CORBAMOD, corba).
--define(ORBNAME, orber).
--define(CORBAHRL, "corba.hrl").
--define(CALL, "call").
--define(CAST, "cast").
--define(IFRREGID, "register").
--define(IFRTYPESHRL, "ifr_types.hrl").
-
--define(GENSERVMOD, gen_server).
-
-%%------------------------------------------------------------
-%% Flags. NOTE! Once assigned value may NOT be changed. Deprecate ok.
-%% Default flags. Can be changed if we change the default behavior.
--define(IC_FLAG_TEMPLATE_1, 16#01).
--define(IC_FLAG_TEMPLATE_2, 16#02).
-
--define(IC_INIT_FLAGS, 16#00).
-
-%% Flag operations
-%% USAGE: Boolean = ?IC_FLAG_TEST(Flags, ?IC_ATTRIBUTE)
--define(IC_FLAG_TEST(_F1, _I1), ((_F1 band _I1) == _I1)).
-
-%% USAGE: NewFlags = ?IC_SET_TRUE(Flags, ?IC_ATTRIBUTE)
--define(IC_SET_TRUE(_F2, _I2), (_I2 bor _F2)).
-
-%% USAGE: NewFlags = ?IC_SET_FALSE(Flags, ?IC_ATTRIBUTE)
--define(IC_SET_FALSE(_F3, _I3), ((_I3 bxor 16#ff) band _F3)).
-
-%% USAGE: NewFlags = ?IC_SET_FALSE_LIST(Flags, [?IC_SEC_ATTRIBUTE, ?IC_SOME])
--define(IC_SET_FALSE_LIST(_F4, _IList1),
- lists:foldl(fun(_I4, _F5) ->
- ((_I4 bxor 16#ff) band _F5)
- end,
- _F4, _IList1)).
-
-%% USAGE: NewFlags = ?IC_SET_TRUE_LIST(Flags, [?IC_ATTRIBUTE, ?IC_SOME])
--define(IC_SET_TRUE_LIST(_F6, _IList2),
- lists:foldl(fun(_I6, _F7) ->
- (_I6 bor _F7)
- end,
- _F6, _IList2)).
-
-%% USAGE: Boolean = ?IC_FLAG_TEST_LIST(Flags, [?IC_CONTEXT, ?IC_THING])
--define(IC_FLAG_TEST_LIST(_F8, _IList3),
- lists:all(fun(_I7) ->
- ((_F8 band _I7) == _I7)
- end,
- _IList3)).
-
-
-%%------------------------------------------------------------
-%% Usefull macros
-
--define(ifthen(P,ACTION), if P -> ACTION; true->true end).
-
-
-%%------------------------------------------------------------
-%% Option macros
-
--define(ifopt(G,OPT,ACTION),
- case ic_options:get_opt(G,OPT) of true -> ACTION; _ -> ok end).
-
--define(ifopt2(G,OPT,ACT1,ACT2),
- case ic_options:get_opt(G,OPT) of true -> ACT1; _ -> ACT2 end).
-
--define(ifnopt(G,OPT,ACTION),
- case ic_options:get_opt(G,OPT) of false -> ACTION; _ -> ok end).
-
-
-%% Internal record
--record(id_of, {id, type, tk}).
-
-%%--------------------------------------------------------------------
-%% The generator object definition
-
--record(genobj, {symtab, impl, options, warnings, auxtab,
- tktab, pragmatab, c_typedeftab,
- skelfile=[], skelfiled=[], skelscope=[],
- stubfile=[], stubfiled=[], stubscope=[],
- includefile=[], includefiled=[],
- interfacefile=[],interfacefiled=[],
- helperfile=[],helperfiled=[],
- holderfile=[],holderfiled=[],
- filestack=0, do_gen=true, sysfile=false}).
-
-%%--------------------------------------------------------------------
-%% The scooped id definition
--record(scoped_id, {type=local, line=-1, id=""}).
-
-
-
-
-
-
-
-
-%%--------------------------------------------------------------------
-%% Secret macros
-%%
-%% NOTE these macros are not general, they cannot be used
-%% everywhere.
-%%
--define(lookup(T,K), case ets:lookup(T, K) of [{_X, _Y}] -> _Y; _->[] end).
--define(insert(T,K,V), ets:insert(T, {K, V})).
-
-
-%%---------------------------------------------------------------------
-%%
-%% Java specific macros
-%%
-%%
--define(ERLANGPACKAGE,"com.ericsson.otp.erlang.").
--define(ICPACKAGE,"com.ericsson.otp.ic.").
-
-
-%%
-%% Macros for reporting encode/decode errors in C back-ends.
-%%
-%%
-
--define(emit_c_enc_rpt(Fd, Fill, Fmt, Vals),
- begin
- CType = ic_cbe:mk_c_type2(G, N, T),
- ic_codegen:emit_c_enc_rpt(Fd, Fill, "~s : " ++ Fmt, [CType| Vals])
- end).
--define(emit_c_dec_rpt(Fd, Fill, Fmt, Vals),
- begin
- CType = ic_cbe:mk_c_type2(G, N, T),
- ic_codegen:emit_c_dec_rpt(Fd, Fill, "~s : " ++ Fmt, [CType| Vals])
- end).
-
-
-
-
-
diff --git a/lib/ic/src/ic_array_java.erl b/lib/ic/src/ic_array_java.erl
deleted file mode 100644
index 64d1b8a9ba..0000000000
--- a/lib/ic/src/ic_array_java.erl
+++ /dev/null
@@ -1,296 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(ic_array_java).
-
--export([gen/4]).
-
--include("ic.hrl").
--include("icforms.hrl").
-
-
-gen(G, N, X, Array) when is_record(X, member) ->
- ArrayName = ic_forms:get_java_id(Array),
- ArrayElement = ic_forms:get_type(X),
- emit_holder_class(G, N, X, Array, ArrayName, ArrayElement),
- emit_helper_class(G, N, X, Array, ArrayName, ArrayElement);
-gen(G, N, X, Array) when is_record(X, case_dcl) ->
- ArrayName = ic_forms:get_java_id(Array),
- ArrayElement = ic_forms:get_type(X),
- emit_holder_class(G, N, X, Array, ArrayName, ArrayElement),
- emit_helper_class(G, N, X, Array, ArrayName, ArrayElement);
-gen(G, N, X, Array) ->
- ArrayName = ic_forms:get_java_id(Array),
- ArrayElement = ic_forms:get_body(X),
- emit_holder_class(G, N, X, Array, ArrayName, ArrayElement),
- emit_helper_class(G, N, X, Array, ArrayName, ArrayElement).
-
-
-
-%%-----------------------------------------------------------------
-%% Func: emit_holder_class/4
-%%-----------------------------------------------------------------
-emit_holder_class(G, N, _X, Array, ArrayName, ArrayElement) ->
- SName = string:concat(ArrayName, "Holder"),
- {Fd, _}= ic_file:open_java_file(G, N, SName),
-
- ArrayElementName = ic_java_type:getType(G, N, ArrayElement),
- EmptyDim = arrayEmptyDim(Array),
-
- ic_codegen:emit(Fd, "final public class ~sHolder {\n",[ArrayName]),
-
- ic_codegen:emit(Fd, " // instance variables\n", []),
- ic_codegen:emit(Fd, " public ~s~s value;\n\n",
- [ArrayElementName,EmptyDim]),
-
- ic_codegen:emit(Fd, " // constructors\n", []),
- ic_codegen:emit(Fd, " public ~sHolder() {}\n", [ArrayName]),
- ic_codegen:emit(Fd, " public ~sHolder(~s~s initial) {\n",
- [ArrayName,ArrayElementName,EmptyDim]),
- ic_codegen:emit(Fd, " value = initial;\n", []),
- ic_codegen:emit(Fd, " }\n", []),
- ic_codegen:nl(Fd),
-
- ic_codegen:emit(Fd, " // methods\n", []),
-
- ic_codegen:emit(Fd, " public void _marshal(~sOtpOutputStream out)\n", [?ERLANGPACKAGE]),
- ic_codegen:emit(Fd, " throws java.lang.Exception {\n"),
- ic_codegen:emit(Fd, " ~sHelper.marshal(out, value);\n", [ArrayName]),
- ic_codegen:emit(Fd, " }\n"),
- ic_codegen:nl(Fd),
- ic_codegen:emit(Fd, " public void _unmarshal(~sOtpInputStream in)\n", [?ERLANGPACKAGE]),
- ic_codegen:emit(Fd, " throws java.lang.Exception {\n"),
- ic_codegen:emit(Fd, " value = ~sHelper.unmarshal(in);\n", [ArrayName]),
- ic_codegen:emit(Fd, " }\n", []),
- ic_codegen:nl(Fd),
-
- ic_codegen:emit(Fd, "}\n", []),
- file:close(Fd).
-
-
-%%-----------------------------------------------------------------
-%% Func: emit_helper_class/4
-%%-----------------------------------------------------------------
-emit_helper_class(G, N, X, Array, ArrayName, ArrayElement) ->
- SName = string:concat(ArrayName, "Helper"),
- {Fd, _}= ic_file:open_java_file(G, N, SName),
-
- ArrayElementName = ic_java_type:getType(G, N, ArrayElement),
- EmptyDim = arrayEmptyDim(Array),
-% Dim = arrayDim(G,N,Array),
-
- ic_codegen:emit(Fd, "public class ~sHelper {\n",[ArrayName]),
-
- ic_codegen:emit(Fd, " // constructors\n"),
- ic_codegen:emit(Fd, " private ~sHelper() {}\n\n", [ArrayName]),
-
- ic_codegen:emit(Fd, " // methods\n"),
-
- ic_codegen:emit(Fd, " public static void marshal(~sOtpOutputStream _out, ~s~s _value)\n",
- [?ERLANGPACKAGE,ArrayElementName,EmptyDim]),
- ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"),
- emit_array_marshal_loop(G,N,X,Array,ArrayElement,Fd),
- ic_codegen:emit(Fd, " }\n"),
- ic_codegen:nl(Fd),
- ic_codegen:emit(Fd, " public static ~s~s unmarshal(~sOtpInputStream _in)\n",
- [ArrayElementName,EmptyDim,?ERLANGPACKAGE]),
- ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"),
- ic_codegen:emit(Fd, " ~s~s _value = new ~s;\n\n",
- [ArrayElementName,EmptyDim,ic_java_type:getFullType(G, N, X, Array)]),
- emit_array_unmarshal_loop(G,N,X,Array,ArrayElement,Fd),
- ic_codegen:emit(Fd, " return _value;\n"),
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_codegen:emit(Fd, " public static String id() {\n", []),
- ic_codegen:emit(Fd, " return ~p;\n",[ictk:get_IR_ID(G, N, Array)]),
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_codegen:emit(Fd, " public static String name() {\n", []),
- ic_codegen:emit(Fd, " return ~p;\n",[ArrayName]),
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_jbe:emit_type_function(G, N, X, Fd),
-
- ic_codegen:emit(Fd, " public static void insert(~sAny _any, ~s~s _this)\n",
- [?ICPACKAGE,ArrayElementName,EmptyDim]),
- ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"),
-
- ic_codegen:emit(Fd, " ~sOtpOutputStream _os = \n",[?ERLANGPACKAGE]),
- ic_codegen:emit(Fd, " new ~sOtpOutputStream();\n\n",[?ERLANGPACKAGE]),
-
- ic_codegen:emit(Fd, " _any.type(type());\n"),
- ic_codegen:emit(Fd, " marshal(_os, _this);\n"),
- ic_codegen:emit(Fd, " _any.insert_Streamable(_os);\n"),
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_codegen:emit(Fd, " public static ~s~s extract(~sAny _any)\n",
- [ArrayElementName,EmptyDim,?ICPACKAGE]),
- ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"),
-
- ic_codegen:emit(Fd, " return unmarshal(_any.extract_Streamable());\n"),
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_codegen:emit(Fd, "}\n"),
- file:close(Fd).
-
-
-
-
-emit_array_marshal_loop(G,N,X,Array,AEl,Fd) ->
- DimList = mk_array_dim_list(G,N,Array),
- emit_array_marshal_loop_1(G,N,X,Array,AEl,DimList,0,Fd).
-
-
-emit_array_marshal_loop_1(G,N,X,Array,AEl,[D],C,Fd) ->
-
- DimList = mk_array_dim_list(G,N,Array),
-
- ic_codegen:emit(Fd, " _out.write_tuple_head(~s);\n\n",[D]),
-
- ic_codegen:emit(Fd, " for(int _tmp~p = 0; _tmp~p < ~s; _tmp~p++)\n",[C,C,D,C]),
-
- case ic_java_type:isBasicType(G, N, AEl) of
- true ->
- ic_codegen:emit(Fd, " _out~s(_value",
- [ic_java_type:marshalFun(G, N, X, AEl)]);
- false ->
- ic_codegen:emit(Fd, " ~s(_out, _value",
- [ic_java_type:marshalFun(G, N, X, AEl)])
- end,
-
- emit_array_dimensions(DimList,0,Fd),
-
- ic_codegen:emit(Fd, ");\n\n");
-
-emit_array_marshal_loop_1(G,N,X,Array,AEl,[D|Ds],C,Fd) ->
-% DimList = mk_array_dim_list(G,N,Array),
-
- ic_codegen:emit(Fd, " _out.write_tuple_head(~s);\n\n",[D]),
-
- ic_codegen:emit(Fd, " for(int _tmp~p = 0; _tmp~p < ~s; _tmp~p++) {\n",[C,C,D,C]),
-
- emit_array_marshal_loop_1(G,N,X,Array,AEl,Ds,C+1,Fd),
-
- ic_codegen:emit(Fd, " }\n\n").
-
-
-
-
-
-emit_array_unmarshal_loop(G,N,X,Array,AEl,Fd) ->
- DimList = mk_array_dim_list(G,N,Array),
- case length(DimList) > 0 of
- true ->
- ic_codegen:emit(Fd, " _in.read_tuple_head();\n\n"),
-
- ic_codegen:emit(Fd, " for(int _tmp0 = 0; _tmp0 < ~s; _tmp0++) {\n\n",[hd(DimList)]),
- emit_array_unmarshal_loop_1(G,N,X,Array,AEl,tl(DimList),1,Fd),
- ic_codegen:emit(Fd, " }\n\n");
- false ->
- emit_array_unmarshal_loop_1(G,N,X,Array,AEl,DimList,0,Fd)
- end.
-
-emit_array_unmarshal_loop_1(G,N,X,_Array,AEl,[],1,Fd) -> %% One dimensional array
- case ic_java_type:isBasicType(G, N, AEl) of
- true ->
- ic_codegen:emit(Fd, " _value[_tmp0] = _in~s;\n",
- [ic_java_type:unMarshalFun(G, N, X, AEl)]);
- false ->
- ic_codegen:emit(Fd, " _value[_tmp0] = ~s.unmarshal(_in);\n\n",
- [ic_java_type:getUnmarshalType(G, N, X, AEl)])
- end;
-emit_array_unmarshal_loop_1(G,N,X,Array,AEl,[],_C,Fd) ->
- DimList = mk_array_dim_list(G,N,Array),
- ic_codegen:emit(Fd, " _value"),
- emit_array_dimensions(DimList,0,Fd),
- case ic_java_type:isBasicType(G,N,AEl) of
- true ->
- ic_codegen:emit(Fd, " = _in~s;\n",
- [ic_java_type:unMarshalFun(G, N, X, AEl)]);
- false ->
- ic_codegen:emit(Fd, " = ~s.unmarshal(_in);\n",
- [ic_java_type:getUnmarshalType(G, N, X, AEl)])
- end;
-emit_array_unmarshal_loop_1(G,N,X,Array,AEl,[D|Ds],C,Fd) ->
- ic_codegen:emit(Fd, " _in.read_tuple_head();\n\n"),
-
- ic_codegen:emit(Fd, " for(int _tmp~p = 0; _tmp~p < ~s; _tmp~p++) {\n\n",[C,C,D,C]),
- emit_array_unmarshal_loop_1(G,N,X,Array,AEl,Ds,C+1,Fd),
- ic_codegen:emit(Fd, " }\n").
-
-
-
-
-
-%%---------------------------------------------------
-%% Utilities
-%%---------------------------------------------------
-
-mk_array_dim_list(G,N,Array) ->
- mk_array_dim_list2(G,N,Array#array.size).
-
-
-mk_array_dim_list2(_G,_N,[]) ->
- [];
-
-mk_array_dim_list2(G,N,[D |Ds]) when is_record(D,scoped_id) ->
- {FSN, _, _, _} = ic_symtab:get_full_scoped_name(G, N, D),
- [ ic_util:to_dot(G,FSN) | mk_array_dim_list2(G,N,Ds)];
-
-mk_array_dim_list2(G,N,[D |Ds]) ->
- [ic_util:eval_java(G,N,D) | mk_array_dim_list2(G,N,Ds)].
-
-
-
-%% Array dimension string
-%arrayDim(G,N,X) ->
-% arrayDim2(G,N,X#array.size).
-
-%arrayDim2(_G,_N,[]) ->
-% "";
-%arrayDim2(G,N,[D|Ds]) when record(D,scoped_id) ->
-% {FSN, _, _, _} = ic_symtab:get_full_scoped_name(G, N, D),
-% "[" ++ ic_util:to_dot(G,FSN) ++ "]" ++ arrayDim2(G,N,Ds);
-%arrayDim2(G,N,[D|Ds]) ->
-% "[" ++ ic_util:eval_java(G,N,D) ++ "]" ++ arrayDim2(G,N,Ds).
-
-
-%% Array Empty dimension string
-arrayEmptyDim(X) ->
- arrayEmptyDim2(X#array.size).
-
-arrayEmptyDim2([_D]) ->
- "[]";
-arrayEmptyDim2([_D |Ds]) ->
- "[]" ++ arrayEmptyDim2(Ds).
-
-
-emit_array_dimensions([_D],C,Fd) ->
- ic_codegen:emit(Fd, "[_tmp~p]",[C]);
-emit_array_dimensions([_D|Ds],C,Fd) ->
- ic_codegen:emit(Fd, "[_tmp~p]",[C]),
- emit_array_dimensions(Ds,C+1,Fd).
-
-
-
-
-
-
diff --git a/lib/ic/src/ic_attribute_java.erl b/lib/ic/src/ic_attribute_java.erl
deleted file mode 100644
index ddbc6d24f5..0000000000
--- a/lib/ic/src/ic_attribute_java.erl
+++ /dev/null
@@ -1,413 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(ic_attribute_java).
-
--include("icforms.hrl").
--include("ic.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([emit_attribute_prototype/4,
- emit_attribute_stub_code/4,
- emit_atrribute_on_dictionary/5,
- emit_attribute_switch_case/5]).
-
-
-
-
-
-%%%-----------------------------------------------------
-%%%
-%%% Generates operation in interface
-%%%
-%%%-----------------------------------------------------
-emit_attribute_prototype(G, N, X, Fd) ->
- emit_attribute_prototype(G, N, X, Fd, ic_forms:get_idlist(X)).
-
-emit_attribute_prototype(_G, _N, _X, _Fd, []) ->
- ok;
-emit_attribute_prototype(G, N, X, Fd, [V|Vs]) ->
- WireAttrName = ic_forms:get_id(V),
- AttrName = ic_forms:get_java_id(WireAttrName),
- emit_attr_prototype(G, N, X, Fd, AttrName,WireAttrName),
- emit_attribute_prototype(G, N, X, Fd, Vs).
-
-
-emit_attr_prototype(G, N, X, Fd, OpName, WireOpName) ->
-
- ic_codegen:emit(Fd, "/****\n"),
- ic_codegen:emit(Fd, " * Attribute ~p interface functions \n", [ic_util:to_colon([WireOpName|N])]),
- ic_codegen:emit(Fd, " *\n"),
- ic_codegen:emit(Fd, " */\n\n"),
-
- AT = ic_forms:get_type(X),
- Type = ic_java_type:getType(G, N, AT),
-% HolderType = ic_java_type:getHolderType(G, N, AT),
-
- ic_codegen:emit(Fd, " ~s ~s() throws java.lang.Exception;\n\n",[Type, OpName]),
-
- case X#attr.readonly of
- {readonly, _} ->
- ok;
- _ ->
- ic_codegen:emit(Fd, " void ~s(~s _value) throws java.lang.Exception;\n\n",[OpName, Type])
- end.
-
-
-
-%%%-----------------------------------------------------
-%%%
-%%% Generates attribute insertion in dictionary
-%%%
-%%%-----------------------------------------------------
-emit_atrribute_on_dictionary(G, N, X, Fd, C) ->
- emit_atrribute_on_dictionary(G, N, X, Fd, C, ic_forms:get_idlist(X)).
-
-emit_atrribute_on_dictionary(_G, _N, _X, _Fd, C, []) ->
- C;
-emit_atrribute_on_dictionary(G, N, X, Fd, C, [V|Vs]) ->
-
- WireAttrName = ic_forms:get_id(V),
-
- ic_codegen:emit(Fd, " _operations.put(\"_get_~s\", new java.lang.Integer(~p));\n",
- [WireAttrName,C]),
-
- case X#attr.readonly of
- {readonly, _} ->
-
- emit_atrribute_on_dictionary(G, N, X, Fd, C+1, Vs);
-
- _ ->
-
- ic_codegen:emit(Fd, " _operations.put(\"_set_~s\", new java.lang.Integer(~p));\n",
- [WireAttrName,C+1]),
-
- emit_atrribute_on_dictionary(G, N, X, Fd, C+2, Vs)
- end.
-
-
-
-%%%-----------------------------------------------------
-%%%
-%%% Generates attribute case in server switch
-%%%
-%%%-----------------------------------------------------
-emit_attribute_switch_case(G, N, X, Fd, C) ->
- Tk = ic_forms:get_tk(X),
- emit_attribute_switch_case(G, N, X, Fd, Tk, C, ic_forms:get_idlist(X)).
-
-emit_attribute_switch_case(_G, _N, _X, _Fd, _Tk, C, []) ->
- C;
-emit_attribute_switch_case(G, N, X, Fd, Tk, C, [V|Vs]) ->
- AttrName = ic_forms:get_java_id(V),
-
- emit_attribute_switch_case1(G,N,X,Fd,"_get_",AttrName,Tk,C),
-
- case X#attr.readonly of
- {readonly, _} ->
- emit_attribute_switch_case(G, N, X, Fd, Tk, C+1, Vs);
-
- _ ->
- emit_attribute_switch_case1(G,N,X,Fd,"_set_",AttrName,Tk,C+1),
- emit_attribute_switch_case(G, N, X, Fd, Tk, C+2, Vs)
- end.
-
-
-emit_attribute_switch_case1(G, N, X, Fd, "_get_", Name, _Tk, C) ->
-
- R = ic_forms:get_type(X),
- RT = ic_java_type:getParamType(G,N,R,ret),
-
- ic_codegen:emit(Fd, " case ~p: { // Get operation for attribute ~s\n\n",[C,ic_util:to_dot([Name|N])]),
-
- ic_codegen:emit(Fd, " // Calling implementation function\n"),
- ic_codegen:emit(Fd, " ~s _result = this.~s();\n\n", [RT, Name]),
-
- ic_codegen:emit(Fd, " // Marshalling output\n"),
- ic_codegen:emit(Fd, " ~sOtpErlangRef __ref = __env.getSref();\n",[?ERLANGPACKAGE]),
- ic_codegen:emit(Fd, " __os.write_tuple_head(2);\n"),
- ic_codegen:emit(Fd, " __os.write_ref(__ref.node(),__ref.id(),__ref.creation()); // Call reference\n"),
-
- case ic_java_type:isBasicType(G,N,R) of
- true ->
- ic_codegen:emit(Fd, " __os~s(_result); // Return value\n\n",
- [ic_java_type:marshalFun(G,N,X,R)]);
- false ->
- ic_codegen:emit(Fd, " ~s(__os,_result); // Return value\n\n",
- [ic_java_type:marshalFun(G,N,X,R)])
- end,
-
- ic_codegen:emit(Fd, " } break;\n\n");
-
-
-emit_attribute_switch_case1(G, N, X, Fd, "_set_", Name, _Tk, C) ->
- ic_codegen:emit(Fd, " case ~p: { // Set operation for attribute ~s\n\n",[C,ic_util:to_dot([Name|N])]),
-
- Type = ic_forms:get_type(X),
-
- ic_codegen:emit(Fd, " // Preparing input\n"),
- ic_codegen:emit(Fd, " ~sOtpInputStream __is = __env.getIs();\n",[?ERLANGPACKAGE]),
-
- case ic_java_type:isBasicType(G,N,Type) of
- true ->
- ic_codegen:emit(Fd, " ~s _value = __is~s; // In value\n\n",
- [ic_java_type:getParamType(G,N,Type,in),
- ic_java_type:unMarshalFun(G,N,X,Type)]);
- false ->
- ic_codegen:emit(Fd, " ~s _value = ~s.unmarshal(__is); // In value\n\n",
- [ic_java_type:getParamType(G,N,Type,in),
- ic_java_type:getUnmarshalType(G,N,X,Type)])
- end,
-
-
- ic_codegen:emit(Fd, " // Calling implementation function\n"),
- ic_codegen:emit(Fd, " this.~s(_value);\n\n", [Name]),
-
- ic_codegen:emit(Fd, " // Marshalling output\n"),
- ic_codegen:emit(Fd, " ~sOtpErlangRef __ref = __env.getSref();\n",[?ERLANGPACKAGE]),
- ic_codegen:emit(Fd, " __os.write_tuple_head(2);\n"),
- ic_codegen:emit(Fd, " __os.write_ref(__ref.node(),__ref.id(),__ref.creation()); // Call reference\n"),
- ic_codegen:emit(Fd, " __os.write_atom(\"ok\");\n\n"),
-
- ic_codegen:emit(Fd, " } break;\n\n").
-
-
-
-
-
-
-
-%%%-----------------------------------------------------
-%%%
-%%% Generates attribute function in stub
-%%%
-%%%-----------------------------------------------------
-emit_attribute_stub_code(G, N, X, Fd) ->
- emit_attribute_stub_code(G, N, X, Fd, ic_forms:get_idlist(X)).
-
-emit_attribute_stub_code(_G, _N, _X, _Fd, []) ->
- ok;
-emit_attribute_stub_code(G, N, X, Fd, [V|Vs]) ->
- WireAttrName = ic_forms:get_id(V),
- AttrName = ic_forms:get_java_id(WireAttrName),
-
- emit_attribute_stub_code1(G,N,X,Fd,"_get_",AttrName,WireAttrName),
-
- case X#attr.readonly of
- {readonly, _} ->
- emit_attribute_stub_code(G, N, X, Fd, Vs);
-
- _ ->
- emit_attribute_stub_code1(G,N,X,Fd,"_set_",AttrName,WireAttrName),
- emit_attribute_stub_code(G, N, X, Fd, Vs)
- end.
-
-
-emit_attribute_stub_code1(G,N,X,Fd,"_get_",Name,WireName) ->
-
- Type = ic_forms:get_type(X),
- RT = ic_java_type:getType(G,N,Type),
-
- %%
- %% Main get operation
- %%
- ic_codegen:emit(Fd, " // Attribute ~p get operation implementation\n", [ic_util:to_colon([WireName|N])]),
- ic_codegen:emit(Fd, " public ~s ~s() throws java.lang.Exception {\n\n", [RT, Name]),
-
- %% Function marshal call
- ic_codegen:emit(Fd, " // Calling the marshal function\n"),
- ic_codegen:emit(Fd, " _~s_marshal(_env);\n\n", [Name]),
-
- %% Sending call
- ic_codegen:emit(Fd, " // Message send\n"),
- ic_codegen:emit(Fd, " _env.send();\n\n"),
-
- %% Receiving return value
- ic_codegen:emit(Fd, " // Message receive\n"),
- ic_codegen:emit(Fd, " _env.receive();\n\n"),
-
- ic_codegen:emit(Fd, " // Calling the unmarshal function\n"),
- ic_codegen:emit(Fd, " return _~s_get_unmarshal(_env);\n", [Name]),
- ic_codegen:emit(Fd, " }\n\n"),
-
-
- %%
- %% Marshal get operation
- %%
- ic_codegen:emit(Fd, " // Marshal operation for get attribute ~p\n", [Name]),
- ic_codegen:emit(Fd, " public static void _~s_marshal(~sEnvironment __env)\n",
- [Name, ?ICPACKAGE]),
- ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"),
-
- ic_codegen:emit(Fd, " // Get output stream\n"),
- ic_codegen:emit(Fd, " ~sOtpOutputStream __os = __env.getOs();\n\n",[?ERLANGPACKAGE]),
-
- %% Initiating Message header
- ic_codegen:emit(Fd, " // Message header assembly\n"),
- ic_codegen:emit(Fd, " __os.reset();\n"),
- ic_codegen:emit(Fd, " __os.write_tuple_head(3);\n"),
- ic_codegen:emit(Fd, " __os.write_atom(\"$gen_call\");\n\n"),
-
-
- %% Creating call identity tuple
- ic_codegen:emit(Fd, " // Message identity part creation\n"),
- ic_codegen:emit(Fd, " __os.write_tuple_head(2);\n"),
- ic_codegen:emit(Fd, " __env.write_client_pid();\n"),
- ic_codegen:emit(Fd, " __env.write_client_ref();\n\n"),
-
- OpCallName = case ic_options:get_opt(G, scoped_op_calls) of
- true ->
- ic_util:to_undersc(["_get_"++WireName|N]);
- false ->
- "_get_"++WireName
- end,
-
- %% Creating operation identity
- ic_codegen:emit(Fd, " // Message operation part creation\n"),
- ic_codegen:emit(Fd, " __os.write_atom(~p);\n\n",[OpCallName]),
-
- ic_codegen:emit(Fd, " }\n\n"),
-
-
- %%
- %% Unmarshal get operation
- %%
- MRT = ic_java_type:getParamType(G,N,Type,ret),
-
- ic_codegen:emit(Fd, " // Unmarshal operation for get attribute ~p\n", [Name]),
- ic_codegen:emit(Fd, " public static ~s _~s_get_unmarshal(~sEnvironment __env)\n",
- [MRT, Name, ?ICPACKAGE]),
- ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"),
-
-
- ic_codegen:emit(Fd, " // Get input stream\n"),
- ic_codegen:emit(Fd, " ~sOtpInputStream __is = __env.getIs();\n\n",[?ERLANGPACKAGE]),
-
- ic_codegen:emit(Fd, " // Extracting return value\n"),
- case ic_java_type:isBasicType(G, N, Type) of
- true ->
- ic_codegen:emit(Fd, " return __is~s;\n",
- [ic_java_type:unMarshalFun(G, N, X, Type)]);
- false ->
- ic_codegen:emit(Fd, " return ~s.unmarshal(__is);\n",
- [ic_java_type:getUnmarshalType(G, N, X, Type)])
- end,
-
- ic_codegen:emit(Fd, " }\n\n");
-
-
-emit_attribute_stub_code1(G,N,X,Fd,"_set_",Name,WireName) ->
-
- Type = ic_forms:get_type(X),
-
- %%
- %% Main set operation
- %%
- IT = ic_java_type:getType(G,N,Type),
-
- ic_codegen:emit(Fd, " // Attribute ~p set operation implementation\n", [ic_util:to_colon([WireName|N])]),
- ic_codegen:emit(Fd, " public void ~s(~s _value) throws java.lang.Exception {\n\n", [Name,IT]),
-
- %% Function marshal call
- ic_codegen:emit(Fd, " // Calling the marshal function\n"),
- ic_codegen:emit(Fd, " _~s_marshal(_env, _value);\n\n", [Name]),
-
- %% Sending call
- ic_codegen:emit(Fd, " // Message send\n"),
- ic_codegen:emit(Fd, " _env.send();\n\n"),
-
- %% Receiving return value
- ic_codegen:emit(Fd, " // Message receive\n"),
- ic_codegen:emit(Fd, " _env.receive();\n\n"),
-
- ic_codegen:emit(Fd, " // Calling the unmarshal function\n"),
- ic_codegen:emit(Fd, " _~s_set_unmarshal(_env);\n", [Name]),
-
- ic_codegen:emit(Fd, " }\n\n"),
-
-
- %%
- %% Marshal set operation
- %%
- IP = ic_java_type:getParamType(G, N, Type, in),
- OpCallName = case ic_options:get_opt(G, scoped_op_calls) of
- true ->
- ic_util:to_undersc(["_set_"++WireName|N]);
- false ->
- "_set_"++WireName
- end,
-
- ic_codegen:emit(Fd, " // Marshal operation for set attribute ~p\n", [Name]),
- ic_codegen:emit(Fd, " public static void _~s_marshal(~sEnvironment __env, ~s _value)\n",
- [Name, ?ICPACKAGE, IP]),
- ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"),
-
- ic_codegen:emit(Fd, " // Get output stream\n"),
- ic_codegen:emit(Fd, " ~sOtpOutputStream __os = __env.getOs();\n\n",[?ERLANGPACKAGE]),
-
- %% Initiating Message header
- ic_codegen:emit(Fd, " // Message header assembly\n"),
- ic_codegen:emit(Fd, " __os.reset();\n"),
- ic_codegen:emit(Fd, " __os.write_tuple_head(3);\n"),
- ic_codegen:emit(Fd, " __os.write_atom(\"$gen_call\");\n\n"),
-
-
- %% Creating call identity tuple
- ic_codegen:emit(Fd, " // Message identity part creation\n"),
- ic_codegen:emit(Fd, " __os.write_tuple_head(2);\n"),
- ic_codegen:emit(Fd, " __env.write_client_pid();\n"),
- ic_codegen:emit(Fd, " __env.write_client_ref();\n\n"),
-
-
- %% Creating operation identity
- ic_codegen:emit(Fd, " // Message operation part creation\n"),
- ic_codegen:emit(Fd, " __os.write_tuple_head(2);\n"),
- ic_codegen:emit(Fd, " __os.write_atom(~p);\n",[OpCallName]),
-
- case ic_java_type:isBasicType(G, N, Type) of
- true ->
- ic_codegen:emit(Fd, " __os~s(_value);\n\n",
- [ic_java_type:marshalFun(G, N, X, Type)]);
- false ->
- ic_codegen:emit(Fd, " ~s(__os, _value);\n\n",
- [ic_java_type:marshalFun(G, N, X, Type)])
- end,
- ic_codegen:emit(Fd, " }\n\n"),
-
-
- ic_codegen:emit(Fd, " // Unmarshal operation for set attribute ~p\n", [Name]),
- ic_codegen:emit(Fd, " public static void _~s_set_unmarshal(~sEnvironment __env)\n",
- [Name, ?ICPACKAGE]),
- ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"),
-
- ic_codegen:emit(Fd, " // Get input stream\n"),
- ic_codegen:emit(Fd, " ~sOtpInputStream __is = __env.getIs();\n\n",[?ERLANGPACKAGE]),
-
- ic_codegen:emit(Fd, " __is.read_atom();\n"),
- ic_codegen:emit(Fd, " }\n\n").
-
-
-
-
-
-
diff --git a/lib/ic/src/ic_cbe.erl b/lib/ic/src/ic_cbe.erl
deleted file mode 100644
index f6e64d23a0..0000000000
--- a/lib/ic/src/ic_cbe.erl
+++ /dev/null
@@ -1,1307 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
-%%------------------------------------------------------------
-%%
-%% This module is a main module for generation of C code, both
-%% for ic_cclient and ic_cserver.
-%%
-%% The former role of this module (ic_cbe) was to generate client
-%% code only.
-%%
--module(ic_cbe).
-
--export([emit_malloc_size_stmt/7, emit_encoding_stmt/6,
- emit_encoding_stmt/7, emit_decoding_stmt/10,
- emit_decoding_stmt/11, emit_dealloc_stmts/3,
- mk_variable_name/1, mk_c_type/3, mk_c_type/4, mk_c_type2/3,
- is_variable_size/1, is_variable_size/3, mk_dim/1,
- mk_slice_dim/1, emit_tmp_variables/1, store_tmp_decl/2,
- extract_info/3, normalize_type/1]).
-
-%%------------------------------------------------------------
-%%
-%% Internal stuff
-%%
-%%------------------------------------------------------------
-
--import(ic_codegen, [emit/2, emit/3, emit/4, emit_c_enc_rpt/4, emit_c_dec_rpt/4]).
-
--include("icforms.hrl").
--include ("ic.hrl").
-
-%%------------------------------------------------------------
-%% ENCODING
-%%------------------------------------------------------------
-
-emit_encoding_stmt(G, N, Fd, T, LName, OutBuffer) when element(1, T) == scoped_id ->
- case mk_c_type(G, N, T, evaluate_not) of
- "erlang_pid" ->
- %% Note prefix: oe_ei
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_pid(oe_env, ~s)) < 0) {\n",
- [LName]),
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n");
- "erlang_port" ->
- %% Note prefix: oe_ei
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_port(oe_env, ~s)) < 0) {\n",
- [LName]),
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n} \n");
- "erlang_ref" ->
- %% Note prefix: oe_ei
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_ref(oe_env, ~s)) < 0) {\n",
- [LName]),
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n");
- "ETERM*" ->
- %% Note prefix: oe_ei
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_term(oe_env, ~s)) < 0) {\n",
- [LName]),
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n");
- {enum, FSN} ->
- emit_encoding_stmt(G, N, Fd, FSN, LName, OutBuffer);
- FSN ->
- emit_encoding_stmt(G, N, Fd, FSN, LName, OutBuffer)
- end;
-
-%% XXX T is a string
-emit_encoding_stmt(G, N, Fd, T, LName, _OutBuffer) when is_list(T) ->
- %% Already a fullscoped name
- Type = ictype:name2type(G,T),
- case ictype:isBasicType(Type) of
- true ->
- emit_encoding_stmt_for_basic_type(G, N, T, Fd, Type, LName);
- false ->
- emit(Fd, " if ((oe_error_code = ~s~s(oe_env, ~s))"
- " < 0) {\n",
- [ic_util:mk_oe_name(G, "encode_"), T, LName]),
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), % XXX list
- emit(Fd, " return oe_error_code;\n }\n")
- end;
-emit_encoding_stmt(G, N, Fd, T, LName, _OutBuffer) when is_record(T, string) ->
- %% Note prefix: oe_ei
- emit(Fd, " if ((oe_error_code = oe_ei_encode_string(oe_env, "
- " ~s)) < 0) {\n",
- [LName]),
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n");
-emit_encoding_stmt(G, N, Fd, T, LName, _OutBuffer) when is_record(T, wstring) ->
- %% Note prefix: oe_ei
- emit(Fd, " if ((oe_error_code = oe_ei_encode_wstring(oe_env, "
- "~s)) < 0) {\n",
- [LName]),
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n");
-emit_encoding_stmt(G, N, Fd, T, LName, _OutBuffer) ->
- case normalize_type(T) of
- {basic, Type} ->
- emit_encoding_stmt_for_basic_type(G, N, T, Fd, Type, LName);
- %% XXX Why only returns?
- {void, _} ->
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n");
- {sequence, _, _} ->
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n");
- {_ArrayType, {array, _, _}} ->
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n");
- {union, _, _, _, _} ->
- %% Union as a member in struct !
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n");
- {struct, _, _, _} ->
- %% Struct as a member in struct !
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n");
- _ ->
- ic_error:fatal_error(G, {illegal_typecode_for_c, T, N})
- end.
-
-%% Arity = 7.
-%%
-emit_encoding_stmt(G, N, X, Fd, T, LName, OutBuffer) when element(1, T) == scoped_id ->
- case mk_c_type(G, N, T, evaluate_not) of
- "erlang_pid" ->
- %% Note prefix: oe_ei
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_pid(oe_env, ~s)) < 0) {\n",
- [LName]),
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n");
- "erlang_port" ->
- %% Note prefix: oe_ei
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_port(oe_env, ~s)) < 0) {\n",
- [LName]),
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n");
- "erlang_ref" ->
- %% Note prefix: oe_ei
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_ref(oe_env, ~s)) < 0) {\n",
- [LName]),
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n");
- "ETERM*" ->
- %% Note prefix: oe_ei
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_term(oe_env, ~s)) < 0) {\n",
- [LName]),
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n");
- {enum, FSN} ->
- emit_encoding_stmt(G, N, X, Fd, FSN, LName, OutBuffer);
- FSN ->
- emit_encoding_stmt(G, N, X, Fd, FSN, LName, OutBuffer)
- end;
-
-%% XXX T is a string
-emit_encoding_stmt(G, N, X, Fd, T, LName, _OutBuffer) when is_list(T) ->
- %% Already a fullscoped name
- case get_param_tk(LName,X) of
- error ->
- emit(Fd, " if ((oe_error_code = "
- "~s~s(oe_env, ~s)) < 0) {\n",
- [ic_util:mk_oe_name(G, "encode_"), T, LName]),
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n");
- ParamTK ->
- case is_variable_size(ParamTK) of
- true ->
- if is_tuple(ParamTK) ->
- case element(1,ParamTK) of
- tk_array ->
- %% Array of dynamic data
- emit(Fd,
- " if ((oe_error_code = "
- "~s~s(oe_env, ~s)) < 0) {\n",
- [ic_util:mk_oe_name(G,
- "encode_"),
- T, LName]),
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd,
- " return "
- "oe_error_code;\n }\n");
- _ ->
- emit(Fd,
- " if ((oe_error_code = "
- "~s~s(oe_env, ~s)) < 0) {\n",
- [ic_util:mk_oe_name(G,
- "encode_"),
- T, LName]),
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return "
- "oe_error_code;\n }\n")
- end;
- true ->
- emit(Fd,
- " if ((oe_error_code = "
- "~s~s(oe_env, ~s)) < 0) {\n",
- [ic_util:mk_oe_name(G, "encode_"),
- T, LName]),
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n")
- end;
- false ->
- if is_atom(ParamTK) ->
- case normalize_type(ParamTK) of
- {basic, Type} ->
- emit_encoding_stmt_for_basic_type(G, N, T, Fd,
- Type,
- LName);
- _ ->
- %% Why only return?
- ?emit_c_enc_rpt(Fd, " ", "~/slist/~s", [T, LName]),
- emit(Fd, " return oe_error_code;\n }\n"),
- ok
- end;
- true ->
- case element(1,ParamTK) of
- tk_enum ->
- emit(Fd, " if ((oe_error_code = "
- "~s~s(oe_env, ~s)) < 0) {\n",
- [ic_util:mk_oe_name(G, "encode_"),
- T, LName]),
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n");
- tk_array ->
- emit(Fd, " if ((oe_error_code = "
- "~s~s(oe_env, ~s)) < 0) {\n",
- [ic_util:mk_oe_name(G, "encode_"),
- T, LName]),
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n");
- tk_struct ->
- emit(Fd, " if ((oe_error_code = "
- "~s~s(oe_env, ~s)) < 0) {\n",
- [ic_util:mk_oe_name(G, "encode_"),
- T, LName]),
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n");
- tk_union ->
- emit(Fd, " if ((oe_error_code = "
- "~s~s(oe_env, ~s)) < 0) {\n",
- [ic_util:mk_oe_name(G, "encode_"),
- T, LName]),
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n");
- _ ->
- emit(Fd, " if ((oe_error_code = "
- "~s~s(oe_env, &~s)) < 0) {\n",
- [ic_util:mk_oe_name(G, "encode_"),
- T, LName]),
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n")
- end
- end
- end
- end;
-emit_encoding_stmt(G, N, _X, Fd, T, LName, _OutBuffer) when is_record(T, string) ->
- %% Note prefix: oe_ei
- emit(Fd, " if ((oe_error_code = oe_ei_encode_string(oe_env, ~s)) < 0) {\n",
- [LName]),
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n");
-emit_encoding_stmt(G, N, _X, Fd, T, LName, _OutBuffer) when is_record(T, wstring) ->
- %% Note prefix: oe_ei
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_wstring(oe_env, ~s)) < 0) {\n",
- [LName]),
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n");
-emit_encoding_stmt(G, N, _X, Fd, T, LName, _OutBuffer) ->
- case normalize_type(T) of
- {basic, Type} ->
- emit_encoding_stmt_for_basic_type(G, N, T, Fd, Type, LName);
- {void, _} ->
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n"),
- ok;
- {sequence, _, _} ->
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n"),
- ok;
- {_ArrayType, {array, _, _}} ->
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n"),
- ok;
- {struct, _, _, _} -> %% Struct as a member in struct !
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n"),
- ok;
- _ ->
- %%io:format("2 ------------> ~p~n", [T]),
- ic_error:fatal_error(G, {illegal_typecode_for_c, T, N})
- end.
-
-%%------------------------------------------------------------
-emit_encoding_stmt_for_basic_type(G, N, T, Fd, Type, LName) ->
- {Cast, DecType} =
- case Type of
- ushort -> {"(unsigned long) ", "ulong"};
- ulong -> {"", "ulong"};
- ulonglong -> {"", "ulonglong"};
- short -> {"(long) ", "long"};
- long -> {"", "long"};
- longlong -> {"", "longlong"};
- float -> {"(double) ", "double"};
- double -> {"", "double"};
- boolean -> {"", "atom"};
- char -> {"", "char"};
- wchar -> {"", "wchar"};
- octet -> {"", "char"};
- any -> {"", "long"} % Fix for any
- end,
- case Type of
- boolean ->
- %% Note prefix: oe_ei
- emit(Fd, " switch(~s) {\n",[LName]),
- emit(Fd, " case 0 :\n"),
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_atom(oe_env, "
- "\"false\")) < 0) {\n"),
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " break;\n"),
- emit(Fd, " case 1 :\n"),
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_atom(oe_env, "
- "\"true\")) < 0) {\n"),
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " break;\n"),
- emit(Fd, " default :\n"),
- emit(Fd, " return -1;\n"),
- emit(Fd, " }\n\n");
- _ ->
- Fmt =
- " if ((oe_error_code = oe_ei_encode_~s(oe_env, ~s~s)) < 0) {\n",
- emit(Fd, Fmt, [DecType, Cast, LName]),
- ?emit_c_enc_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n }\n")
- end.
-
-
-%%------------------------------------------------------------
-%% MALLOC SIZE (for Decode)
-%%------------------------------------------------------------
-
-emit_malloc_size_stmt(G, N, Fd, T, InBuffer,
- Align, CalcType) when element(1, T) == scoped_id ->
- case mk_c_type(G, N, T, evaluate_not) of
- "erlang_pid" ->
- emit(Fd, " oe_malloc_size += sizeof(erlang_pid);\n\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_pid(~s, "
- "oe_size_count_index, NULL)) < 0) {\n", [InBuffer]),
- ?emit_c_dec_rpt(Fd, " ", "erlang_pid", []),
- emit(Fd, " return oe_error_code;\n }\n");
- "erlang_port" ->
- emit(Fd, " oe_malloc_size += sizeof(erlang_port);\n\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_port(~s, "
- "oe_size_count_index, NULL)) < 0) {\n", [InBuffer]),
- ?emit_c_dec_rpt(Fd, " ", "erlang_port", []),
- emit(Fd, " return oe_error_code;\n }\n");
- "erlang_ref" ->
- emit(Fd, " oe_malloc_size += sizeof(erlang_ref);\n\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_ref(~s, "
- "oe_size_count_index, NULL)) < 0) {\n", [InBuffer]),
- ?emit_c_dec_rpt(Fd, " ", "erlang_ref", []),
- emit(Fd, " return oe_error_code;\n }\n");
- "ETERM*" ->
- emit(Fd, " oe_malloc_size += sizeof(char*);\n\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_term(~s, "
- "oe_size_count_index, NULL)) < 0) {\n", [InBuffer]),
- ?emit_c_dec_rpt(Fd, " ", "ETERM*", []),
- emit(Fd, " return oe_error_code;\n }\n");
- {enum, FSN} ->
- emit_malloc_size_stmt(G, N, Fd, FSN, InBuffer, Align, CalcType);
- FSN ->
- %% io:format("emit_malloc_size_stmt: ~p ~p~n",[FSN,
- %% CalcType]),
- emit_malloc_size_stmt(G, N, Fd, FSN, InBuffer, Align, CalcType)
- end;
-
-%% XXX T is a string
-emit_malloc_size_stmt(G, N, Fd, T, InBuffer,
- _Align, CalcType) when is_list(T) ->
- %% Already a fullscoped name
- Type = ictype:name2type(G,T),
- case ictype:isBasicType(Type) of
- true ->
- emit_malloc_size_stmt_for_basic_type(G, N, T, Fd, Type, InBuffer);
- false ->
- case CalcType of
- generator ->
- emit(Fd, " if ((oe_error_code = ~s~s(oe_env, "
- "oe_size_count_index, &oe_malloc_size)) < 0) {\n",
- [ic_util:mk_oe_name(G, "sizecalc_"), T]),
- ?emit_c_dec_rpt(Fd, " ", "~s", [T]),
- emit(Fd, " return oe_error_code;\n }\n");
- _ ->
- emit(Fd, " if ((oe_error_code = ~s~s(oe_env, "
- "&oe_size_count_index, &oe_malloc_size)) < 0) {\n",
- [ic_util:mk_oe_name(G, "sizecalc_"), T]),
- ?emit_c_dec_rpt(Fd, " ", "~s", [T]),
- emit(Fd, " return oe_error_code;\n }\n")
- end
- end;
-emit_malloc_size_stmt(G, N, Fd, T, InBuffer, _Align,
- CalcType) when is_record(T, string) ->
- Tname = mk_variable_name(op_variable_count),
- store_tmp_decl(" int ~s = 0;\n",[Tname]),
- case CalcType of
- generator ->
- emit(Fd, " if ((oe_error_code = ei_get_type(~s, "
- "oe_size_count_index, &oe_type, &~s)) < 0) {\n",
- [InBuffer, Tname]);
- _ ->
- emit(Fd, " int oe_type = 0;\n"),
- emit(Fd, " int oe_temp = 0;\n\n"),
- emit(Fd, " if ((oe_error_code = ei_get_type(~s, "
- "&oe_size_count_index, &oe_type, &oe_temp)) < 0) {\n",
- [InBuffer])
- end,
- ?emit_c_dec_rpt(Fd, " ", "ei_get_type", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- if
- T#string.length == 0 ->
- ok;
- true ->
- Length = ic_util:eval_c(G, N, T#string.length),
- case CalcType of
- generator ->
- emit(Fd, " if (~s > ~s)\n",[Tname, Length]),
- emit(Fd, " return -1;\n\n");
- _ ->
- emit(Fd, " if (oe_temp > ~s)\n",[Length]),
- emit(Fd, " return -1;\n\n")
- end
- end,
- case CalcType of
- generator ->
- emit(Fd, " if ((oe_error_code = ei_decode_string(~s, "
- "oe_size_count_index, NULL)) < 0) {\n", [InBuffer]);
- _ ->
- emit(Fd, " if ((oe_error_code = ei_decode_string(~s, "
- "&oe_size_count_index, NULL)) < 0) {\n", [InBuffer])
- end,
- ?emit_c_dec_rpt(Fd, " ", "ei_decode_string", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- case CalcType of
- generator ->
- emit(Fd, " oe_malloc_size = ~s;\n\n",
- [ic_util:mk_align("oe_malloc_size + " ++ Tname ++"+1")]);
- _ ->
- emit(Fd, " oe_malloc_size = ~s;\n\n",
- [ic_util:mk_align("oe_malloc_size + oe_temp+1")])
- end;
-emit_malloc_size_stmt(G, N, Fd, T, InBuffer, _Align,
- CalcType) when is_record(T, wstring) ->
- Tname = mk_variable_name(op_variable_count),
- store_tmp_decl(" int ~s = 0;\n",[Tname]),
- case CalcType of
- generator ->
- emit(Fd, " if ((oe_error_code = ei_get_type(~s, "
- "oe_size_count_index, &oe_type, &~s)) < 0) {\n",
- [InBuffer, Tname]);
- _ ->
- emit(Fd, " int oe_type = 0;\n"),
- emit(Fd, " int oe_temp = 0;\n\n"),
- emit(Fd, " if ((oe_error_code = ei_get_type(~s, "
- "&oe_size_count_index, &oe_type, &oe_temp)) < 0) {\n",
- [InBuffer])
- end,
- ?emit_c_dec_rpt(Fd, " ", "ei_get_type", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- if
- T#wstring.length == 0 ->
- ok;
- true ->
- Length = ic_util:eval_c(G, N, T#wstring.length),
- case CalcType of
- generator ->
- emit(Fd, " if (~s > ~s)\n",[Tname, Length]),
- emit(Fd, " return -1;\n\n");
- _ ->
- emit(Fd, " if (oe_temp > ~s)\n",[Length]),
- emit(Fd, " return -1;\n\n")
- end
- end,
- case CalcType of
- generator ->
- %% Note prefix: oe_ei
- emit(Fd, " if ((oe_error_code = oe_ei_decode_wstring(~s, "
- "oe_size_count_index, NULL)) < 0) {\n", [InBuffer]);
- _ ->
- %% Note prefix: oe_ei
- emit(Fd, " if ((oe_error_code = oe_ei_decode_wstring(~s, "
- "&oe_size_count_index, NULL)) < 0) {\n", [InBuffer])
- end,
- ?emit_c_dec_rpt(Fd, " ", "oe_ei_decode_wstring", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- case CalcType of
- generator ->
- emit(Fd, " oe_malloc_size =\n ~s;\n\n",
- [ic_util:mk_align("oe_malloc_size + (("
- ++ Tname
- ++"+ 1) * __OE_WCHAR_SIZE_OF__)")]);
- _ ->
- emit(Fd, " oe_malloc_size =\n ~s;\n\n",
- [ic_util:mk_align("oe_malloc_size + (("
- "oe_temp + 1) * __OE_WCHAR_SIZE_OF__)")])
- end;
-emit_malloc_size_stmt(G, N, Fd, T, InBuffer, Align, CalcType) ->
- case Align of
- 0 ->
- emit(Fd, " oe_malloc_size += sizeof(~s);\n\n",
- [mk_c_type(G, N, T)]);
- _ ->
- ok
- end,
- case normalize_type(T) of
- {basic, Type} ->
- emit_malloc_size_stmt_for_basic_type(G, N, T, Fd, Type, InBuffer);
- {void, _} ->
- ok;
- {sequence, _, _} ->
- ok;
- {_, {array, SId, _}} ->
- case CalcType of
- generator ->
- emit(Fd, " if ((oe_error_code = ~s~s(oe_env, "
- "oe_size_count_index, &oe_malloc_size)) < 0) {\n",
- [ic_util:mk_oe_name(G, "sizecalc_"),
- ic_forms:get_id2(SId)]),
- ?emit_c_dec_rpt(Fd, " ", "array1", []),
- emit(Fd, " return oe_error_code;\n\n");
- _ ->
- emit(Fd, " if ((oe_error_code = ~s~s(oe_env, "
- "&oe_size_count_index, &oe_malloc_size)) < 0) {\n",
- [ic_util:mk_oe_name(G, "sizecalc_"),
- ic_forms:get_id2(SId)]),
- ?emit_c_dec_rpt(Fd, " ", "array2", []),
- emit(Fd, " return oe_error_code;\n\n")
- end;
- {union, UId, _, _, _} ->
- case CalcType of
- generator ->
- emit(Fd, " if ((oe_error_code = ~s~s(oe_env, "
- "oe_size_count_index, &oe_malloc_size)) < 0) {\n",
- [ic_util:mk_oe_name(G, "sizecalc_"),
- ic_forms:get_id2(UId)]),
- ?emit_c_dec_rpt(Fd, " ", "union1", []),
- emit(Fd, " return oe_error_code;\n\n");
- _ ->
- emit(Fd, " if ((oe_error_code = ~s~s(oe_env, "
- "&oe_size_count_index, &oe_malloc_size)) < 0) {\n",
- [ic_util:mk_oe_name(G, "sizecalc_"),
- ic_forms:get_id2(UId)]),
- ?emit_c_dec_rpt(Fd, " ", "union2", []),
- emit(Fd, " return oe_error_code;\n\n")
- end;
- {struct, UId, _, _} -> %% Struct as a member in struct !
- case CalcType of
- generator ->
- emit(Fd, " if ((oe_error_code = ~s~s(oe_env, "
- "oe_size_count_index, &oe_malloc_size)) < 0) {\n",
- [ic_util:mk_oe_name(G, "sizecalc_"),
- ic_forms:get_id2(UId)]),
- ?emit_c_dec_rpt(Fd, " ", "struct1", []),
- emit(Fd, " return oe_error_code;\n\n");
- _ ->
- emit(Fd, " if ((oe_error_code = ~s~s(oe_env, "
- "&oe_size_count_index, &oe_malloc_size)) < 0) {\n",
- [ic_util:mk_oe_name(G, "sizecalc_"),
- ic_forms:get_id2(UId)]),
- ?emit_c_dec_rpt(Fd, " ", "struct2", []),
- emit(Fd, " return oe_error_code;\n\n")
- end;
- {any, _} -> %% Fix for any type
- emit(Fd, " if ((oe_error_code = ei_decode_long(~s, "
- "oe_size_count_index, NULL)) < 0) {\n",
- [InBuffer]),
- ?emit_c_dec_rpt(Fd, " ", "any", []),
- emit(Fd, " return oe_error_code;\n }\n");
- _ ->
- ic_error:fatal_error(G, {illegal_typecode_for_c, T, N})
- end.
-
-%%------------------------------------------------------------
-
-emit_malloc_size_stmt_for_basic_type(G, N, T, Fd, Type, InBuffer) ->
- {Pre, DecType} =
- case Type of
- ushort -> {"", "ulong"};
- ulong -> {"", "ulong"};
- ulonglong -> {"oe_", "ulonglong"};
- short -> {"", "long"};
- long -> {"", "long"};
- longlong -> {"oe_", "longlong"};
- float -> {"", "double"};
- double -> {"", "double"};
- boolean -> {"", "atom"};
- char -> {"", "char"};
- wchar -> {"oe_", "wchar"};
- octet -> {"", "char"};
- any -> {"", "long"}
- end,
- Fmt =
- " if ((oe_error_code = ~sei_decode_~s(~s, oe_size_count_index, "
- "NULL)) < 0) {\n",
- emit(Fd, Fmt, [Pre, DecType, InBuffer]),
- ?emit_c_dec_rpt(Fd, " ", "~s", [DecType]),
- emit(Fd, " return oe_error_code;\n }\n").
-
-%%------------------------------------------------------------
-%% DECODING
-%%------------------------------------------------------------
-
-emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, Align,
- NextPos, DecType) ->
- emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, Align,
- NextPos, DecType, []).
-
-emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, Align, NextPos,
- DecType, AllocedPars) when element(1, T) == scoped_id ->
- Fmt =
- " if ((oe_error_code = ei_decode_~s(~s, &oe_env->_iin, ~s~s)) < 0)"
- " {\n",
- Emit = fun(Type) ->
- emit(Fd, Fmt, [Type, InBuffer, IndOp, LName]),
- emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n"),
- emit(Fd, " }\n")
- end,
- case mk_c_type(G, N, T, evaluate_not) of
- "erlang_pid" ->
- Emit("pid");
- "erlang_port" ->
- Emit("port");
- "erlang_ref" ->
- Emit("ref");
- "ETERM*" ->
- Emit("term");
- {enum, FSN} ->
- emit_decoding_stmt(G, N, Fd, FSN, LName, IndOp, InBuffer,
- Align, NextPos, DecType, AllocedPars);
- FSN ->
- emit_decoding_stmt(G, N, Fd, FSN, LName, IndOp, InBuffer,
- Align, NextPos, DecType, AllocedPars)
- end;
-
-%% XXX T is a string
-emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, _Align, NextPos,
- DecType, AllocedPars) when is_list(T) ->
- %% Already a fullscoped name
- Type = ictype:name2type(G,T),
- case ictype:isBasicType(Type) of
- true ->
- emit_decoding_stmt_for_basic_type(G, N, T, Fd, Type, InBuffer, IndOp,
- LName, AllocedPars);
- false ->
- case DecType of
- generator ->
- emit(Fd, " if ((oe_error_code = ~s~s(oe_env, oe_first, "
- "~s, ~s)) < 0) {\n",
- [ic_util:mk_oe_name(G, "decode_"),
- T, NextPos, LName]),
- emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n"),
- emit(Fd, " }\n");
- caller -> %% No malloc used, define oe_first
- emit(Fd, " {\n"),
- emit(Fd, " void *oe_first = NULL;\n"),
- emit(Fd, " int oe_outindex = 0;\n\n"),
- emit(Fd, " if ((oe_error_code = ~s~s(oe_env, "
- "oe_first, ~s, ~s)) < 0) {\n",
- [ic_util:mk_oe_name(G, "decode_"),
- T, NextPos, LName]),
- emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n"),
- emit(Fd, " }\n"),
- emit(Fd, " }\n");
- caller_dyn -> %% Malloc used
- emit(Fd, " {\n"),
- emit(Fd, " int oe_outindex = 0;\n\n"),
- emit(Fd, " if ((oe_error_code = ~s~s(oe_env, "
- "oe_first, ~s, ~s)) < 0) {\n",
- [ic_util:mk_oe_name(G, "decode_"),
- T, NextPos, LName]),
- emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n"),
- emit(Fd, " }\n"),
- emit(Fd, " }\n");
- array_dyn -> %% Malloc used
- emit(Fd, " {\n"),
- emit(Fd, " int oe_outindex = 0;\n\n"),
- emit(Fd, " if ((oe_error_code = ~s~s(oe_env, "
- "oe_first, ~s, ~s)) < 0) {\n",
- [ic_util:mk_oe_name(G, "decode_"),
- T, NextPos, LName]),
- emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n"),
- emit(Fd, " }\n"),
- emit(Fd, " }\n");
- array_fix_ret ->
- emit(Fd, " {\n"),
- emit(Fd, " int oe_outindex = 0;\n\n"),
- emit(Fd, " if ((oe_error_code = ~s~s(oe_env, "
- "oe_first, ~s,*~s)) < 0) {\n",
- [ic_util:mk_oe_name(G, "decode_"),
- T, NextPos, LName]),
- emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n"),
- emit(Fd, " }\n"),
- emit(Fd, " }\n");
- array_fix_out -> %% No malloc used, define oe_first
- emit(Fd, " {\n"),
- emit(Fd, " void *oe_first = NULL;\n"),
- emit(Fd, " int oe_outindex = 0;\n\n"),
- emit(Fd, " if ((oe_error_code = ~s~s(oe_env, "
- "oe_first, ~s, ~s)) < 0) {\n",
- [ic_util:mk_oe_name(G, "decode_"),
- T, NextPos, LName]),
- emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n"),
- emit(Fd, " }\n"),
- emit(Fd, " }\n")
- end
- end;
-emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, _Align, _NextPos,
- DecType, AllocedPars) when is_record(T, string) ->
- case DecType of
- caller_dyn ->
- emit(Fd, " if ((oe_error_code = ei_decode_string(~s, "
- "&oe_env->_iin, ~s~s)) < 0) {\n",
- [InBuffer, IndOp, LName]),
- emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n"),
- emit(Fd, " }\n");
- _ ->
- emit(Fd, " ~s~s = oe_first + *oe_outindex;\n\n",
- [IndOp, LName]),
- emit(Fd, " {\n"),
- emit(Fd, " int oe_type=0;\n"),
- emit(Fd, " int oe_string_ctr=0;\n\n"),
-
- emit(Fd, " (int) ei_get_type(~s, "
- "&oe_env->_iin, &oe_type, &oe_string_ctr);\n\n",
- [InBuffer]),
-
- emit(Fd, " if ((oe_error_code = ei_decode_string(~s, "
- "&oe_env->_iin, ~s~s)) < 0) {\n",
- [InBuffer, IndOp, LName]),
- emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n"),
- emit(Fd, " }\n"),
- emit(Fd, " *oe_outindex = ~s;\n",
- [ic_util:mk_align("*oe_outindex+oe_string_ctr+1")]),
- emit(Fd, " }\n\n")
- end;
-emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, _Align, _NextPos,
- DecType, AllocedPars) when is_record(T, wstring) ->
- case DecType of
- caller_dyn ->
- %% Note prefix: oe_ei
- emit(Fd, " if ((oe_error_code = oe_ei_decode_wstring(~s, "
- "&oe_env->_iin, ~s~s)) < 0) {\n",
- [InBuffer, IndOp, LName]),
- emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n"),
- emit(Fd, " }/* --- */\n"); % XXX
- _ ->
- emit(Fd, " ~s~s = oe_first + *oe_outindex;\n\n",
- [IndOp, LName]),
-
- emit(Fd, " {\n"),
- emit(Fd, " int oe_type=0;\n"),
- emit(Fd, " int oe_string_ctr=0;\n\n"),
- emit(Fd, " (int) ei_get_type(~s, "
- "&oe_env->_iin, &oe_type, &oe_string_ctr);\n\n",
- [InBuffer]),
- %% Note prefix: oe_ei
- emit(Fd, " if ((oe_error_code = oe_ei_decode_wstring(~s, "
- "&oe_env->_iin, ~s~s)) < 0) {\n",
- [InBuffer, IndOp, LName]),
- emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n"),
- emit(Fd, " }\n"),
- emit(Fd, " *oe_outindex = ~s;\n",
- [ic_util:mk_align("*oe_outindex+oe_string_ctr+1")]),
- emit(Fd, " }\n")
- end;
-emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, _Align, NextPos,
- _DecType, AllocedPars) ->
- case normalize_type(T) of
- {basic, Type} ->
- emit_decoding_stmt_for_basic_type(G, N, T, Fd, Type, InBuffer, IndOp,
- LName, AllocedPars);
- {void, _} ->
- emit(Fd, " if ((oe_error_code = ei_decode_atom(~s, "
- "&oe_env->_iin, NULL)) < 0) {\n",
- [InBuffer]),
- emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n"),
- emit(Fd, " }\n");
- {sequence, _, _} ->
- ok;
- {_, {array, SId, Dims}} ->
- AName = ic_forms:get_id2({array, SId, Dims}),
- Ptr = "oe_out->"++AName,
- emit(Fd, " if ((oe_error_code = ~s~s(oe_env, "
- "oe_first, ~s, ~s)) < 0) {\n",
- [ic_util:mk_oe_name(G, "decode_"),
- ic_forms:get_id2(SId),
- NextPos, Ptr]),
- emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n"),
- emit(Fd, " }\n");
- {struct, _, _, _} -> %% Struct as a member in struct !
- ok;
- _ ->
- %%io:format("3 ------------> ~p~n", [T]),
- ic_error:fatal_error(G, {illegal_typecode_for_c, T, N})
- end.
-
-%% XXX DecType used in two senses in this file.
-emit_decoding_stmt_for_basic_type(G, N, T, Fd, Type, InBuffer, IndOp,
- LName, AllocedPars) ->
- Fmt =
- " if ((oe_error_code = ~sei_decode_~s(~s, &oe_env->_iin, "
- "~s~s)) < 0) {\n",
- Ret =
- " return oe_error_code;\n"
- "}\n",
-
- {Pre, DecType} =
- case Type of
- ushort -> {"", "ulong"};
- ulong -> {"", "ulong"};
- ulonglong -> {"oe_", "ulonglong"};
- short -> {"", "long"};
- long -> {"", "long"};
- longlong -> {"oe_", "longlong"};
- float -> {"", "double"};
- double -> {"", "double"};
- boolean -> {"", "atom"};
- char -> {"", "char"};
- wchar -> {"oe_", "wchar"};
- octet -> {"", "char"};
- any -> {"", "long"}
- end,
- case Type of
- ushort ->
- emit(Fd, " {\n"),
- emit(Fd, " unsigned long oe_ulong;\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_ulong(~s, "
- "&oe_env->_iin, &oe_ulong)) < 0) {\n",
- [InBuffer]),
- emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n"),
- emit(Fd, "}\n"),
- emit(Fd, " *(~s) = (unsigned short) oe_ulong;\n\n",
- [LName]),
- emit(Fd, " if (*(~s) != oe_ulong){\n",
- [LName]),
- emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return -1;\n"),
- emit(Fd, " }\n"),
- emit(Fd, " }\n\n");
- short ->
- emit(Fd, " {\n"),
- emit(Fd, " long oe_long;\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_long(~s, "
- "&oe_env->_iin, &oe_long)) < 0){\n",
- [InBuffer]),
- emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n\n"),
- emit(Fd, "}\n"),
- emit(Fd, " *(~s) = (short) oe_long;\n\n",[LName]),
- emit(Fd, " if (*(~s) != oe_long){\n", [LName]),
- emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return -1;\n"),
- emit(Fd, " }\n"),
- emit(Fd, " }\n");
- float ->
- emit(Fd, " {\n"),
- emit(Fd, " double oe_double;\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_double(~s, "
- "&oe_env->_iin, &oe_double)) < 0){\n",
- [InBuffer]),
- emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n\n"),
- emit(Fd, "}\n"),
- emit(Fd, " *(~s) = (float) oe_double;\n",[LName]),
- emit(Fd, " }\n");
- boolean ->
- emit(Fd, " {\n"),
- emit(Fd, " char oe_bool[25];\n\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_atom(~s, "
- "&oe_env->_iin, oe_bool)) < 0){\n",[InBuffer]),
- emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return oe_error_code;\n"),
- emit(Fd, "}\n"),
- emit(Fd, " if (strcmp(oe_bool, \"false\") == 0) {\n"),
- emit(Fd, " *(~s) = 0;\n",[LName]),
- emit(Fd, " }\n"),
- emit(Fd, " else if (strcmp(oe_bool, \"true\") == 0)"
- " {\n"),
- emit(Fd, " *(~s) = 1;\n",[LName]),
- emit(Fd, " }\n"),
- emit(Fd, " else {\n"),
- emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "~s", [LName]),
- emit(Fd, " return -1;\n"),
- emit(Fd, " }\n"),
- emit(Fd, " }\n");
- _ ->
- emit(Fd, Fmt, [Pre, DecType, InBuffer, IndOp, LName]),
- ?emit_c_dec_rpt(Fd, " ", "~s", [LName]),
- emit_dealloc_stmts(Fd, " ", AllocedPars),
- emit(Fd, Ret)
- end.
-
-%%------------------------------------------------------------
-%%
-%%------------------------------------------------------------
-emit_dealloc_stmts(Fd, Prefix, AllocedPars) ->
- Fmt = Prefix ++ "CORBA_free(~s);\n",
- lists:foreach(
- fun(Par) -> emit(Fd, Fmt, [Par]) end,
- AllocedPars).
-
-
-%%------------------------------------------------------------
-%%
-%%------------------------------------------------------------
-
-mk_variable_name(Var) ->
- Nr = get(Var),
- put(Var, Nr + 1),
- "oe_tmp" ++ integer_to_list(Nr).
-
-%% IDL to C type conversion
-%%------------------------------------------------------------
-mk_c_type(G, N, S) ->
- mk_c_type(G, N, S, evaluate).
-
-mk_c_type(G, N, S, evaluate) when element(1, S) == scoped_id ->
- {FullScopedName, _T, _TK, _} = ic_symtab:get_full_scoped_name(G, N, S),
- BT = ic_code:get_basetype(G, ic_util:to_undersc(FullScopedName)),
- case BT of
- "erlang_binary" ->
- "erlang_binary";
- "erlang_pid" ->
- "erlang_pid";
- "erlang_port" ->
- "erlang_port";
- "erlang_ref" ->
- "erlang_ref";
- "erlang_term" ->
- "ETERM*";
- {enum, Type} ->
- mk_c_type(G, N, Type, evaluate);
- Type ->
- mk_c_type(G, N, Type, evaluate)
- end;
-
-mk_c_type(G, N, S, evaluate_not) when element(1, S) == scoped_id ->
- {FullScopedName, _T, _TK, _} = ic_symtab:get_full_scoped_name(G, N, S),
- BT = ic_code:get_basetype(G, ic_util:to_undersc(FullScopedName)),
- case BT of
- "erlang_binary" ->
- "erlang_binary";
- "erlang_pid" ->
- "erlang_pid";
- "erlang_port" ->
- "erlang_port";
- "erlang_ref" ->
- "erlang_ref";
- "erlang_term" ->
- "ETERM*";
- Type ->
- Type
- end;
-mk_c_type(_G, _N, S, _) when is_list(S) ->
- S;
-mk_c_type(_G, _N, S, _) when is_record(S, string) ->
- "CORBA_char *";
-mk_c_type(_G, _N, S, _) when is_record(S, wstring) ->
- "CORBA_wchar *";
-mk_c_type(_G, _N, {boolean, _}, _) ->
- "CORBA_boolean";
-mk_c_type(_G, _N, {octet, _}, _) ->
- "CORBA_octet";
-mk_c_type(_G, _N, {void, _}, _) ->
- "void";
-mk_c_type(_G, _N, {unsigned, U}, _) ->
- case U of
- {short,_} ->
- "CORBA_unsigned_short";
- {long,_} ->
- "CORBA_unsigned_long";
- {'long long',_} ->
- "CORBA_unsigned_long_long"
- end;
-
-mk_c_type(_G, _N, {'long long', _}, _) ->
- "CORBA_long_long";
-
-mk_c_type(_G, _N, S, _) when is_record(S, union)->
- ic_forms:get_id2(S);
-
-mk_c_type(_G, N, S, _) when is_record(S, struct) -> %% Locally defined member
- Fullname = [ic_forms:get_id2(S) | N],
- ic_util:to_undersc(Fullname);
-
-mk_c_type(_G, _N, {'any', _}, _) -> %% Fix for any type
- "CORBA_long";
-
-mk_c_type(_G, _N, {T, _}, _) ->
- "CORBA_" ++ atom_to_list(T).
-
-%%-------------------------------------------------------------------
-%% IDL to C type conversion used by the emit_c_*_rpt macros.
-%%-------------------------------------------------------------------
-mk_c_type2(G, N, S) when element(1, S) == scoped_id ->
- {FullScopedName, _T, _TK, _} = ic_symtab:get_full_scoped_name(G, N, S),
- BT = ic_code:get_basetype(G, ic_util:to_undersc(FullScopedName)),
- case BT of
- "erlang_binary" ->
- "erlang_binary";
- "erlang_pid" ->
- "erlang_pid";
- "erlang_port" ->
- "erlang_port";
- "erlang_ref" ->
- "erlang_ref";
- "erlang_term" ->
- "ETERM*";
- {enum, Type} ->
- mk_c_type2(G, N, Type);
- Type ->
- mk_c_type2(G, N, Type)
- end;
-
-mk_c_type2(_G, _N, S) when is_list(S) ->
- S;
-mk_c_type2(_G, _N, S) when is_record(S, string) ->
- "CORBA_char *";
-mk_c_type2(_G, _N, S) when is_record(S, wstring) ->
- "CORBA_wchar *";
-mk_c_type2(_G, _N, {boolean, _}) ->
- "CORBA_boolean";
-mk_c_type2(_G, _N, {octet, _}) ->
- "CORBA_octet";
-mk_c_type2(_G, _N, {void, _}) ->
- "void";
-mk_c_type2(_G, _N, {unsigned, U}) ->
- case U of
- {short,_} ->
- "CORBA_unsigned_short";
- {long,_} ->
- "CORBA_unsigned_long";
- {'long long',_} ->
- "CORBA_unsigned_long_long"
- end;
-
-mk_c_type2(_G, _N, {'long long', _}) ->
- "CORBA_long_long";
-
-mk_c_type2(_G, _N, S) when is_record(S, union)->
- ic_forms:get_id2(S);
-
-mk_c_type2(_G, N, S) when is_record(S, struct) ->
- Fullname = [ic_forms:get_id2(S) | N],
- ic_util:to_undersc(Fullname);
-
-mk_c_type2(_G, _N, S) when is_record(S, sequence) ->
- mk_c_type2(_G, _N, S#sequence.type);
-
-mk_c_type2(_G, _N, {'any', _}) -> %% Fix for any type
- "CORBA_long";
-
-mk_c_type2(_G, _N, {T, _}) ->
- "CORBA_" ++ atom_to_list(T).
-
-%%-----
-
-is_variable_size_rec(Es) ->
- lists:any(
- fun({_N, T}) -> is_variable_size(T);
- ({_, _N, T}) -> is_variable_size(T)
- end, Es).
-
-is_variable_size({'tk_struct', _IFRId, "port", _ElementList}) ->
- false;
-is_variable_size({'tk_struct', _IFRId, "pid", _ElementList}) ->
- false;
-is_variable_size({'tk_struct', _IFRId, "ref", _ElementList}) ->
- false;
-is_variable_size({'tk_struct', _IFRId, "term", _ElementList}) ->
- false;
-is_variable_size({'tk_struct', _IFRId, _Name, ElementList}) ->
- is_variable_size_rec(ElementList);
-is_variable_size({'tk_array', ElemTC, _Length}) ->
- is_variable_size(ElemTC);
-is_variable_size({'tk_string', _}) ->
- true;
-is_variable_size({'tk_wstring', _}) ->
- true;
-is_variable_size({'tk_sequence', _ElemTC, _MaxLsextractength}) ->
- true;
-is_variable_size({'tk_union', _IFRId, _Name, _, _, ElementList}) ->
- is_variable_size_rec(ElementList);
-is_variable_size(_Other) ->
- false.
-
-
-is_variable_size(_G, _N, T) when is_record(T, string) ->
- true;
-is_variable_size(_G, _N, T) when is_record(T, wstring) ->
- true;
-is_variable_size(_G, _N, T) when is_record(T, sequence) ->
- true;
-is_variable_size(G, N, T) when is_record(T, union) ->
- %%io:format("~n~p = ~p~n",[ic_forms:get_id2(T),ictype:fetchTk(G, N, T)]),
- is_variable_size(ictype:fetchTk(G, N, T));
-is_variable_size(G, N, T) when is_record(T, struct) ->
- is_variable_size(ictype:fetchTk(G, N, T));
-is_variable_size(G, N, T) when element(1, T) == scoped_id ->
- case ic_symtab:get_full_scoped_name(G, N, T) of
- {_FullScopedName, _, TK, _} ->
- is_variable_size(TK);
- _ ->
- ic_error:fatal_error(G, {name_not_found, T})
- end;
-is_variable_size(_G, _N, _Other) ->
- false.
-
-%% mk_dim produces
-mk_dim([Arg | Args]) ->
- "[" ++ Arg ++ "]" ++ mk_dim(Args);
-mk_dim([]) -> [].
-
-mk_slice_dim(Args) ->
- mk_dim(tl(Args)).
-
-
-emit_tmp_variables(Fd) ->
- DeclList = get(tmp_declarations),
- emit_tmp_variables(Fd, DeclList),
- ok.
-
-emit_tmp_variables(Fd, [Decl |Rest]) ->
- emit_tmp_variables(Fd, Rest),
- emit(Fd, "~s", [Decl]);
-emit_tmp_variables(_Fd, []) ->
- ok.
-
-store_tmp_decl(Format, Args) ->
- Decl = io_lib:format(Format, Args),
- DeclList = get(tmp_declarations),
- put(tmp_declarations, [Decl |DeclList]).
-
-%%------------------------------------------------------------
-%%
-%% Parser utilities
-%%
-%% Called from the yecc parser. Expands the identifier list of an
-%% attribute so that the attribute generator never has to handle
-%% lists.
-%%
-%%------------------------------------------------------------
-
-extract_info(_G, N, X) when is_record(X, op) ->
- Name = ic_util:to_undersc([ic_forms:get_id2(X) | N]),
- Args = X#op.params,
- ArgNames = mk_c_vars(Args),
- TypeList = {ic_forms:get_type(X),
- lists:map(fun(Y) -> ic_forms:get_type(Y) end, Args),
- []
- },
- {Name, ArgNames, TypeList};
-extract_info(_G, N, X) ->
- Name = ic_util:to_undersc([ic_forms:get_id2(X) | N]),
- {Name, [], []}.
-
-
-
-%% Usefull functions
-get_param_tk(Name, Op) ->
- case get_param(Name, Op) of
- error ->
- error;
- Param ->
- ic_forms:get_tk(Param)
- end.
-
-get_param(Name, Op) when is_record(Op, op) ->
- get_param_loop(Name, Op#op.params);
-get_param(_Name, _Op) ->
- error.
-
-get_param_loop(Name,[Param|Params]) ->
- case ic_forms:get_id2(Param) of
- Name ->
- Param;
- _ ->
- get_param_loop(Name,Params)
- end;
-get_param_loop(_Name, []) ->
- error.
-
-
-%% Input is a list of parameters (in parse form) and output is a list
-%% of parameter attribute and variable names.
-mk_c_vars(Params) ->
- lists:map(fun(P) -> {A, _} = P#param.inout,
- {A, ic_forms:get_id(P#param.id)}
- end,
- Params).
-
-normalize_type({unsigned, {short, _}}) -> {basic, ushort};
-normalize_type({unsigned, {long, _}}) -> {basic, ulong};
-normalize_type({unsigned, {'long long', _}}) -> {basic, ulonglong};
-normalize_type({short,_}) -> {basic, short};
-normalize_type({long, _}) -> {basic, long};
-normalize_type({'long long', _}) -> {basic, longlong};
-normalize_type({float,_}) -> {basic, float};
-normalize_type({double, _}) -> {basic, double};
-normalize_type({boolean, _}) -> {basic, boolean};
-normalize_type({char, _}) -> {basic, char};
-normalize_type({wchar, _}) -> {basic, wchar};
-normalize_type({octet, _}) -> {basic, octet};
-normalize_type({any, _}) -> {basic, any};
-normalize_type(tk_ushort) -> {basic, ushort};
-normalize_type(tk_ulong) -> {basic, ulong};
-normalize_type(tk_ulonglong) -> {basic, ulonglong};
-normalize_type(tk_short) -> {basic, short};
-normalize_type(tk_long) -> {basic, long};
-normalize_type(tk_longlong) -> {basic, longlong};
-normalize_type(tk_float) -> {basic, float};
-normalize_type(tk_double) -> {basic, double};
-normalize_type(tk_boolean) -> {basic, boolean};
-normalize_type(tk_char) -> {basic, char};
-normalize_type(tk_wchar) -> {basic, wchar};
-normalize_type(tk_octet) -> {basic, octet};
-normalize_type(tk_any) -> {basic, any};
-normalize_type(ushort) -> {basic, ushort};
-normalize_type(ulong) -> {basic, ulong};
-normalize_type(ulonglong) -> {basic, ulonglong};
-normalize_type(short) -> {basic, short};
-normalize_type(long) -> {basic, long};
-normalize_type(longlong) -> {basic, longlong};
-normalize_type(float) -> {basic, float};
-normalize_type(double) -> {basic, double};
-normalize_type(boolean) -> {basic, boolean};
-normalize_type(char) -> {basic, char};
-normalize_type(wchar) -> {basic, wchar};
-normalize_type(octet) -> {basic, octet};
-normalize_type(any) -> {basic, any};
-normalize_type(Type) -> Type.
-
diff --git a/lib/ic/src/ic_cclient.erl b/lib/ic/src/ic_cclient.erl
deleted file mode 100644
index 8591acf33f..0000000000
--- a/lib/ic/src/ic_cclient.erl
+++ /dev/null
@@ -1,1210 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(ic_cclient).
-
-%% This module implements generation of C client code, where the
-%% client acts as an Erlang C-node, and where the communication thus
-%% is according to the Erlang distribution protocol.
-%%
-
--export([do_gen/3]).
-
-%%------------------------------------------------------------
-%% IMPLEMENTATION CONVENTIONS
-%%------------------------------------------------------------
-%% Functions:
-%%
-%% mk_* returns things to be used. No side effects.
-%% emit_* Writes to file. Has Fd in arguments.
-%% gen_* Same, but has no Fd. Usually for larger things.
-%%
-%% Terminology for generating C:
-%%
-%% par_list list of identifiers with types, types only, or with
-%% parameters (arguments) only.
-%% arg_list list of identifiers only (for function calls)
-%%
-
-%%------------------------------------------------------------
-%% Internal stuff
-%%------------------------------------------------------------
-
--import(lists, [foreach/2, foldl/3, foldr/3]).
--import(ic_codegen, [emit/2, emit/3, emit/4, emit_c_enc_rpt/4, emit_c_dec_rpt/4]).
-
--include("icforms.hrl").
--include("ic.hrl").
--include_lib("stdlib/include/erl_compile.hrl").
-
--define(IC_HEADER, "ic.h").
--define(ERL_INTERFACEHEADER, "erl_interface.h").
--define(EICONVHEADER, "ei.h").
--define(ERLANGATOMLENGTH, "256").
-
-
-%%------------------------------------------------------------
-%% ENTRY POINT
-%%------------------------------------------------------------
-do_gen(G, File, Form) ->
- OeName = ic_util:mk_oe_name(G, remove_ext(ic_util:to_list(File))),
- G2 = ic_file:filename_push(G, [], OeName, c),
- gen_headers(G2, [], Form),
- R = gen(G2, [], Form),
- ic_file:filename_pop(G2, c),
- R.
-
-remove_ext(File) ->
- filename:rootname(filename:basename(File)).
-
-%%------------------------------------------------------------
-%%
-%% Generate client side C stubs.
-%%
-%% - each module definition results in a separate file.
-%% - each interface definition results in a separate file.
-%%
-%% G = record(genobj) (see ic.hrl)
-%% N = scoped names in reverse
-%% X = current form to consider.
-%%------------------------------------------------------------
-
-gen(G, N, [X| Xs]) when is_record(X, preproc) ->
- G1 = change_file_stack(G, N, X),
- gen(G1, N, Xs);
-
-gen(G, N, [X| Xs]) when is_record(X, module) ->
- CD = ic_code:codeDirective(G, X),
- G2 = ic_file:filename_push(G, N, X, CD),
- N2 = [ic_forms:get_id2(X)| N],
- gen_headers(G2, N2, X),
- gen(G2, N2, ic_forms:get_body(X)),
- G3 = ic_file:filename_pop(G2, CD),
- gen(G3, N, Xs);
-
-gen(G, N, [X| Xs]) when is_record(X, interface) ->
-
- G2 = ic_file:filename_push(G, N, X, c),
- N2 = [ic_forms:get_id2(X)| N],
-
- %% Sets the temporary variable counter.
- put(op_variable_count, 0),
- put(tmp_declarations, []),
-
- gen_headers(G2, N2, X),
-
- gen(G2, N2, ic_forms:get_body(X)),
-
- lists:foreach(
- fun({_Name, Body}) ->
- gen(G2, N2, Body) end,
- X#interface.inherit_body),
-
- %% Generate Prototypes
- gen_prototypes(G2, N2, X),
-
- %% Generate generic preparation for decoding
- gen_receive_info(G2, N2, X),
-
- G3 = ic_file:filename_pop(G2, c),
-
- gen(G3, N, Xs);
-
-gen(G, N, [X| Xs]) when is_record(X, const) ->
- emit_constant(G, N, X),
- gen(G, N, Xs);
-
-gen(G, N, [X| Xs]) when is_record(X, op) ->
- {OpName, ArgNames, RetParTypes} = ic_cbe:extract_info(G, N, X),
- %% XXX Note: N is the list of scoped ids of the *interface*.
- gen_operation(G, N, X, OpName, ArgNames, RetParTypes),
- gen_encoder(G, N, X, OpName, ArgNames, RetParTypes),
- gen_decoder(G, N, X, OpName, ArgNames, RetParTypes),
- gen(G, N, Xs);
-
-gen(G, N, [X| Xs]) when is_record(X, attr) ->
- gen(G, N, Xs);
-
-gen(G, N, [X| Xs]) when is_record(X, except) ->
- icstruct:except_gen(G, N, X, c),
- gen(G, N, Xs);
-
-gen(G, N, [X| Xs]) when is_record(X, enum) ->
- icenum:enum_gen(G, N, X, c),
- gen(G, N, Xs);
-
-gen(G, N, [X| Xs]) when is_record(X, typedef) ->
- icstruct:struct_gen(G, N, X, c),
- gen(G, N, Xs);
-
-gen(G, N, [X| Xs]) when is_record(X, struct) ->
- icstruct:struct_gen(G, N, X, c),
- gen(G, N, Xs);
-
-gen(G, N, [X| Xs]) when is_record(X, union) ->
- icstruct:struct_gen(G, N, X, c),
- gen(G, N, Xs);
-
-gen(G, N, [_X| Xs]) ->
- %% XXX Should have debug message here.
- gen(G, N, Xs);
-
-gen(_G, _N, []) ->
- ok.
-
-%%------------------------------------------------------------
-%% Change file stack
-%%------------------------------------------------------------
-
-change_file_stack(G, _N, X) when X#preproc.cat == line_nr ->
- Id = ic_forms:get_id2(X),
- Flags = X#preproc.aux,
- case Flags of
- [] ->
- ic_genobj:push_file(G, Id);
- _ ->
- foldr(
- fun({_, _, "1"}, G1) ->
- ic_genobj:push_file(G1, Id);
- ({_, _, "2"}, G1) ->
- ic_genobj:pop_file(G1, Id);
- ({_, _, "3"}, G1) ->
- ic_genobj:sys_file(G1, Id)
- end, G, Flags)
- end;
-change_file_stack(G, _N, _X) ->
- G.
-
-%%------------------------------------------------------------
-%% Generate headers in stubfiles and header files
-%%------------------------------------------------------------
-
-gen_headers(G, N, X) when is_record(X, interface) ->
- case ic_genobj:is_hrlfile_open(G) of
- true ->
- %% Set the temporary variable counter
- put(op_variable_count, 0),
- put(tmp_declarations, []),
- HFd = ic_genobj:hrlfiled(G),
- IncludeFileStack = ic_genobj:include_file_stack(G),
- L = length(N),
- Filename =
- if
- L < 2 ->
- lists:nth(L + 1, IncludeFileStack);
- true ->
- lists:nth(2, IncludeFileStack)
- end,
- emit(HFd, "#include \"~s\"\n", [filename:basename(Filename)]),
- ic_code:gen_includes(HFd, G, X, c_client),
-
- IfName = ic_util:to_undersc(N),
- IfNameUC = ic_util:to_uppercase(IfName),
- emit(HFd, "\n#ifndef __~s__\n", [IfNameUC]),
- emit(HFd, "#define __~s__\n", [IfNameUC]),
- LCmt = io_lib:format("Interface object definition: ~s", [IfName]),
- ic_codegen:mcomment_light(HFd, [LCmt], c),
- case get_c_timeout(G, "") of
- "" ->
- ok;
- {SendTmo, RecvTmo} ->
- emit(HFd, "#define OE_~s_SEND_TIMEOUT ~s\n",
- [IfNameUC, SendTmo]),
- emit(HFd, "#define OE_~s_RECV_TIMEOUT ~s\n",
- [IfNameUC, RecvTmo]),
- emit(HFd, "#ifndef EI_HAVE_TIMEOUT\n"),
- emit(HFd, "#error Functions for send and receive with "
- "timeout not defined in erl_interface\n"),
- emit(HFd, "#endif\n\n")
- end,
-
- emit(HFd, "typedef CORBA_Object ~s;\n", [IfName]),
- emit(HFd, "#endif\n\n");
-
- false -> ok
- end,
- case ic_genobj:is_stubfile_open(G) of
- true ->
- Fd = ic_genobj:stubfiled(G),
- ic_codegen:nl(Fd),
- emit(Fd, "#include <stdlib.h>\n"),
- emit(Fd, "#include <string.h>\n"),
- case ic_options:get_opt(G, c_report) of
- true ->
- emit(Fd, "#ifndef OE_C_REPORT\n"),
- emit(Fd, "#define OE_C_REPORT\n"),
- emit(Fd, "#include <stdio.h>\n"),
- emit(Fd, "#endif\n");
- _ ->
- ok
- end,
- emit(Fd, "#include \"~s\"\n", [?IC_HEADER]),
- emit(Fd, "#include \"~s\"\n", [?ERL_INTERFACEHEADER]),
- emit(Fd, "#include \"~s\"\n", [?EICONVHEADER]),
- emit(Fd, "#include \"~s\"\n",
- [filename:basename(ic_genobj:include_file(G))]),
- ic_codegen:nl(Fd), ic_codegen:nl(Fd),
- Fd; % XXX ??
- false ->
- ok
- end;
-
-%% Some items have extra includes
-gen_headers(G, N, X) when is_record(X, module) ->
- case ic_genobj:is_hrlfile_open(G) of
- true ->
- HFd = ic_genobj:hrlfiled(G),
- IncludeFileStack = ic_genobj:include_file_stack(G),
- Filename = lists:nth(length(N) + 1, IncludeFileStack),
- emit(HFd, "#include \"~s\"\n", [filename:basename(Filename)]),
- ic_code:gen_includes(HFd, G, X, c_client);
- false -> ok
- end;
-gen_headers(G, [], _X) ->
- case ic_genobj:is_hrlfile_open(G) of
- true ->
- HFd = ic_genobj:hrlfiled(G),
- case ic_options:get_opt(G, c_report) of
- true ->
- emit(HFd, "#ifndef OE_C_REPORT\n"),
- emit(HFd, "#define OE_C_REPORT\n"),
- emit(HFd, "#include <stdio.h>\n"),
- emit(HFd, "#endif\n");
- _ ->
- ok
- end,
- emit(HFd, "#include \"~s\"\n", [?IC_HEADER]),
- emit(HFd, "#include \"~s\"\n", [?ERL_INTERFACEHEADER]),
- emit(HFd, "#include \"~s\"\n", [?EICONVHEADER]),
- ic_code:gen_includes(HFd, G, c_client);
- false -> ok
- end;
-gen_headers(_G, _N, _X) ->
- ok.
-
-
-%%------------------------------------------------------------
-%% Generate all prototypes (for interface)
-%%------------------------------------------------------------
-gen_prototypes(G, N, X) ->
- case ic_genobj:is_hrlfile_open(G) of
- false ->
- ok;
- true ->
- HFd = ic_genobj:hrlfiled(G),
- IfName = ic_util:to_undersc(N),
-
- %% Emit generated function prototypes
- emit(HFd, "\n/* Operation functions */\n"),
- lists:foreach(fun({_Name, Body}) ->
- emit_operation_prototypes(G, HFd, N, Body)
- end, [{x, ic_forms:get_body(X)}|
- X#interface.inherit_body]),
-
- UserProto = get_user_proto(G, false),
- %% Emit generic function prototypes
- case UserProto of
- false ->
- ok;
- UserProto ->
- emit(HFd,
- "\n/* Generic user defined encoders */\n"),
- emit(HFd,
- "int ~s_prepare_notification_encoding("
- "CORBA_Environment*);"
- "\n", [UserProto]),
- emit(HFd,
- "int ~s_prepare_request_encoding(CORBA_Environment*);"
- "\n", [UserProto])
- end,
- %% Emit encoding function prototypes
- emit(HFd, "\n/* Input encoders */\n"),
- lists:foreach(fun({_Name, Body}) ->
- emit_encoder_prototypes(G, HFd, N, Body)
- end,
- [{x, ic_forms:get_body(X)}|
- X#interface.inherit_body]),
-
- %% Emit generic function prototypes
- emit(HFd, "\n/* Generic decoders */\n"),
- emit(HFd, "int ~s__receive_info(~s, CORBA_Environment*);\n",
- [IfName, IfName]),
-
- case UserProto of
- false ->
- ok;
- UserProto ->
- emit(HFd, "\n/* Generic user defined decoders */\n"),
- emit(HFd,
- "int ~s_prepare_reply_decoding(CORBA_Environment*);"
- "\n", [UserProto])
- end,
- %% Emit decode function prototypes
- emit(HFd, "\n/* Result decoders */\n"),
- lists:foreach(fun({_Name, Body}) ->
- emit_decoder_prototypes(G, HFd, N, Body)
- end, [{x, ic_forms:get_body(X)}|
- X#interface.inherit_body]),
- case UserProto of
- false ->
- ok;
- UserProto ->
- %% Emit generic send and receive_prototypes
- {Sfx, TmoType} = case get_c_timeout(G, "") of
- "" ->
- {"", ""};
- _ ->
- {"_tmo", ", unsigned int"}
- end,
- emit(HFd,
- "\n/* Generic user defined send and receive "
- "functions */\n"),
- emit(HFd,
- "int ~s_send_notification~s(CORBA_Environment*~s);\n",
- [UserProto, Sfx, TmoType]),
- emit(HFd,
- "int ~s_send_request_and_receive_reply~s("
- "CORBA_Environment*~s~s);\n",
- [UserProto, Sfx, TmoType, TmoType])
- end
- end.
-
-%%------------------------------------------------------------
-%% Generate receive_info() (generic part for message reception)
-%% (for interface). For backward compatibility only.
-%%------------------------------------------------------------
-
-gen_receive_info(G, N, _X) ->
- case ic_genobj:is_stubfile_open(G) of
- false ->
- ok;
- true ->
- Fd = ic_genobj:stubfiled(G),
- IfName = ic_util:to_undersc(N),
- UserProto = get_user_proto(G, oe),
- Code =
- "
-/*
- * Generic function, used to return received message information.
- * Not used by oneways. Always generated. For backward compatibility only.
- */
-
-int ~s__receive_info(~s oe_obj, CORBA_Environment *oe_env)
-{
- return ~s_prepare_reply_decoding(oe_env);
-}\n",
- emit(Fd, Code, [IfName, IfName, UserProto])
-end.
-
-%%------------------------------------------------------------
-%% Emit constant
-%%------------------------------------------------------------
-
-emit_constant(G, N, ConstRecord) ->
- case ic_genobj:is_hrlfile_open(G) of
- false -> ok;
- true ->
- Fd = ic_genobj:hrlfiled(G),
- CName = ic_util:to_undersc(
- [ic_forms:get_id(ConstRecord#const.id)| N]),
- UCName = ic_util:to_uppercase(CName),
-
- emit(Fd, "\n#ifndef __~s__\n", [UCName]),
- emit(Fd, "#define __~s__\n", [UCName]),
-
- emit(Fd, "/* Constant: ~s */\n", [CName]),
-
- if is_record(ConstRecord#const.type, wstring) ->
- %% If wstring, add 'L'
- emit(Fd, "#define ~s L~p\n",
- [CName, ConstRecord#const.val]);
- true ->
- emit(Fd, "#define ~s ~p\n",
- [CName, ConstRecord#const.val])
- end,
- emit(Fd, "#endif\n\n")
- end.
-
-%%------------------------------------------------------------
-%% Generate operation (for interface)
-%%------------------------------------------------------------
-
-%% N is the list of scoped ids of the *interface*.
-%% X is the operation
-gen_operation(G, N, X, OpName, ArgNames, RetParTypes) ->
- case ic_genobj:is_stubfile_open(G) of
- true ->
- do_gen_operation(G, N, X, OpName, ArgNames, RetParTypes);
- false ->
- ok
- end.
-
-do_gen_operation(G, N, X, OpName, ArgNames, RetParTypes) ->
- Fd = ic_genobj:stubfiled(G),
- IfName = ic_util:to_undersc(N),
- IfNameUC = ic_util:to_uppercase(IfName),
-
- {R, ParTypes, _} = RetParTypes,
-
- IsOneway = ic_forms:is_oneway(X),
-
- emit(Fd, "\n"
- "/***\n"
- " *** Operation function \"~s\" ~s\n"
- " ***/\n\n",
- [OpName, ifelse(IsOneway, "(oneway)", "")]),
-
- RV = element(1, R),
- Ret = case IsOneway of
- false ->
- if RV /= void ->
- mk_ret_type(G, N, R);
- true ->
- "void"
- end;
- true ->
- "void"
- end,
- ParListStr = ic_util:chain(mk_par_type_list(G, N, X, [in, out],
- [types, args],
- ParTypes, ArgNames), ", "),
- emit(Fd,
- "~s ~s(~s, ~sCORBA_Environment *oe_env)\n{\n",
- [Ret, OpName, [IfName, " ", "oe_obj"], ParListStr]),
-
- case IsOneway of
- true ->
- ok;
- false ->
- case ictype:isArray(G, N, R) of
- true ->
- emit(Fd, " ~s oe_return = NULL;\n\n",
- [mk_ret_type(G, N, R)]);
- false ->
- if RV /= void ->
- emit(Fd, " ~s oe_return;\n\n",
- [Ret]);
- true ->
- ok
- end
- end,
- emit(Fd,
- " /* Initiating the message reference */\n"
- " ic_init_ref(oe_env, &oe_env->_unique);\n")
- end,
-
- emit(Fd,
- " /* Initiating exception indicator */ \n"
- " oe_env->_major = CORBA_NO_EXCEPTION;\n"),
-
- %% XXX Add pointer checks: checks of in-parameter
- %% pointers, and non-variable out-parameter pointers.
-
- emit(Fd," /* Creating ~s message */ \n",
- [ifelse(IsOneway, "cast", "call")]),
-
- EncParListStr = ic_util:chain(mk_arg_list_for_encoder(G, N, X,
- ParTypes, ArgNames),
- ", "),
- emit(Fd,
- " if (~s__client_enc(oe_obj, ~s""oe_env) < 0) {\n",
- [OpName, EncParListStr]),
- emit(Fd,
- " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, "
- "DATA_CONVERSION, \"Cannot encode message\");\n"),
-
- RetVar = ifelse(RV /= void, " oe_return", ""),
- emit_c_enc_rpt(Fd, " ", "client operation ~s\\n====\\n", [OpName]),
-
- emit(Fd, " return~s;\n }\n", [RetVar]),
-
- emit(Fd," /* Sending ~s message */ \n",
- [ifelse(IsOneway, "cast", "call")]),
-
- UserProto = get_user_proto(G, oe),
- {Sfx, SendTmo, RecvTmo} = case get_c_timeout(G, "") of
- "" ->
- {"", "", ""};
- _ ->
- {"_tmo",
- [", OE_", IfNameUC, "_SEND_TIMEOUT"],
- [", OE_", IfNameUC, "_RECV_TIMEOUT"]}
- end,
-
- case IsOneway of
- true ->
- emit(Fd,
- " if (~s_send_notification~s(oe_env~s) < 0)\n"
- " return~s;\n", [UserProto, Sfx, SendTmo, RetVar]);
- false ->
- emit(Fd,
- " if (~s_send_request_and_receive_reply~s(oe_env~s~s) < 0)\n"
- " return~s;\n",
- [UserProto, Sfx, SendTmo, RecvTmo, RetVar]),
-
- DecParList0 = mk_arg_list_for_decoder(G, N, X,
- ParTypes, ArgNames),
- DecParList1 = case mk_ret_type(G, N, R) of
- "void" ->
- DecParList0;
- _ ->
- ["&oe_return"| DecParList0]
- end,
-
- DecParListStr = ic_util:chain(DecParList1, ", "),
- %% YYY Extracting results
- emit(Fd,
- " /* Extracting result value(s) */ \n"
- " if (~s__client_dec(oe_obj, ~s""oe_env) < 0) {\n",
- [OpName, DecParListStr]),
- emit(Fd,
- " CORBA_exc_set(oe_env, "
- "CORBA_SYSTEM_EXCEPTION, DATA_CONVERSION, "
- "\"Bad result value(s)\");\n"),
- emit_c_dec_rpt(Fd, " ", "client operation ~s\\n=====\\n", [OpName]),
- emit(Fd,
- " return~s;\n"
- " }\n", [RetVar])
- end,
- emit(Fd, " return~s;\n", [RetVar]),
- emit(Fd, "}\n\n\n").
-
-%%------------------------------------------------------------
-%% Generate encoder
-%%------------------------------------------------------------
-%% N is the list of scoped ids of the *interface*.
-%% X is the operation
-gen_encoder(G, N, X, OpName, ArgNames, RetParTypes)->
- case ic_genobj:is_stubfile_open(G) of
- true ->
- Fd = ic_genobj:stubfiled(G),
- IfName = ic_util:to_undersc(N),
- {_R, ParTypes, _} = RetParTypes,
- TypeAttrArgs = mk_type_attr_arg_list(ParTypes, ArgNames),
- emit(Fd, "/*\n * Encode operation input for \"~s\"\n */\n\n",
- [OpName]),
- ParList = ic_util:chain(
- mk_par_type_list(G, N, X, [in], [types, args],
- ParTypes, ArgNames), ", "),
- emit(Fd,
- "int ~s__client_enc(~s oe_obj, ~s"
- "CORBA_Environment *oe_env)\n{\n",
- [OpName, IfName, ParList]),
-
- InTypeAttrArgs = lists:filter(fun({_, in, _}) -> true;
- ({_, _, _}) -> false
- end, TypeAttrArgs),
- case InTypeAttrArgs of
- [] ->
- ok;
- _ ->
- emit(Fd,
- " int oe_error_code = 0;\n\n")
- end,
-
- emit_encodings(G, N, Fd, X, InTypeAttrArgs,
- ic_forms:is_oneway(X)),
- emit(Fd, " return 0;\n}\n\n"),
- ok;
-
- false ->
- ok
- end.
-
-%%------------------------------------------------------------
-%% Generate decoder
-%%------------------------------------------------------------
-%% N is the list of scoped ids of the *interface*.
-%% X is the operation
-gen_decoder(G, N, X, OpName, ArgNames, RetParTypes)->
- case ic_forms:is_oneway(X) of
- true ->
- ok;
- false ->
- case ic_genobj:is_stubfile_open(G) of
- true ->
- Fd = ic_genobj:stubfiled(G),
- IfName = ic_util:to_undersc(N),
- {R, ParTypes, _} = RetParTypes,
- TypeAttrArgs = mk_type_attr_arg_list(ParTypes, ArgNames),
- emit(Fd, "/*\n * Decode operation results for "
- "\"~s\"\n */\n\n", [OpName]),
- ParList0 = mk_par_type_list(G, N, X, [out],
- [types, args],
- ParTypes, ArgNames),
- PARLIST = case mk_ret_type(G, N, R) of
- "void" ->
- ParList0;
- Else ->
- [Else ++ "* oe_return"| ParList0]
- end,
- PLFCD = ic_util:chain(PARLIST, ", "),
- emit(Fd,
- "int ~s__client_dec(~s oe_obj, ~s"
- "CORBA_Environment *oe_env)\n{\n",
- [OpName, IfName, PLFCD]),
- emit(Fd, " int oe_error_code = 0;\n"),
- OutTypeAttrArgs = lists:filter(fun({_, out, _}) -> true;
- ({_, _, _}) -> false
- end, TypeAttrArgs),
- emit_decodings(G, N, Fd, R, OutTypeAttrArgs),
- emit(Fd, " return 0;\n}\n\n"),
- ok;
-
- false ->
- ok
- end
- end.
-
-%%------------------------------------------------------------
-%% EMIT ENCODINGS/DECODINGS
-%%------------------------------------------------------------
-%%------------------------------------------------------------
-%% Emit encodings
-%%------------------------------------------------------------
-%% N is the list of scoped ids of the *interface*.
-%% X is the operation
-%% emit_encodings(G, N, Fd, X, TypeAttrArgs, IsOneWay)
-%%
-emit_encodings(G, N, Fd, X, TypeAttrArgs, true) ->
- %% Cast
- UserProto = get_user_proto(G, oe),
- emit(Fd,
- " if (~s_prepare_notification_encoding(oe_env) < 0)\n"
- " return -1;\n", [UserProto]),
- emit_encodings_1(G, N, Fd, X, TypeAttrArgs);
-emit_encodings(G, N, Fd, X, TypeAttrArgs, false) ->
- %% Call
- UserProto = get_user_proto(G, oe),
- emit(Fd,
- " if (~s_prepare_request_encoding(oe_env) < 0)\n"
- " return -1;\n", [UserProto]),
- emit_encodings_1(G, N, Fd, X, TypeAttrArgs).
-
-emit_encodings_1(G, N, Fd, X, TypeAttrArgs) ->
- {ScopedName, _, _} = ic_cbe:extract_info(G, N, X),
- Name = case ic_options:get_opt(G, scoped_op_calls) of
- true ->
- ScopedName;
- false ->
- ic_forms:get_id2(X)
- end,
- if
- TypeAttrArgs /= [] ->
- emit(Fd, " if (oe_ei_encode_tuple_header(oe_env, ~p) < 0) {\n",
- [length(TypeAttrArgs) + 1]),
- emit_c_enc_rpt(Fd, " ", "ei_encode_tuple_header", []),
- emit(Fd, " return -1;\n }\n");
- true ->
- ok
- end,
- emit(Fd, " if (oe_ei_encode_atom(oe_env, ~p) < 0) {\n", [Name]),
- emit_c_enc_rpt(Fd, " ", "oe_ei_encode_atom", []),
- emit(Fd, " return -1;\n }\n"),
-
- foreach(fun({{'void', _}, _, _}) ->
- ok;
- ({T1, A1, N1}) ->
- IndOp = mk_ind_op(A1),
- emit_coding_comment(G, N, Fd, "Encode", IndOp,
- T1, N1),
- ic_cbe:emit_encoding_stmt(G, N, X, Fd, T1, IndOp ++ N1,
- "oe_env->_outbuf")
- end, TypeAttrArgs),
- ok.
-
-%%------------------------------------------------------------
-%% Emit dedodings
-%%------------------------------------------------------------
-%% XXX Unfortunately we have to retain the silly `oe_first' variable,
-%% since its name is hardcoded in other modules (icstruct, icunion,
-%% etc).
-%% N is the list of scoped ids of the *interface*.
-%% X is the operation
-emit_decodings(G, N, Fd, RetType, TypeAttrArgs) ->
- if
- TypeAttrArgs /= [] ->
- %% Only if there are out parameters
- emit(Fd, " if ((oe_error_code = ei_decode_tuple_header("
- "oe_env->_inbuf, &oe_env->_iin, "
- "&oe_env->_received)) < 0) {\n"),
- emit_c_dec_rpt(Fd, " ", "ei_decode_tuple_header", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- Len = length(TypeAttrArgs) + 1,
- emit(Fd, " if (oe_env->_received != ~p) {\n", [Len]),
- emit_c_dec_rpt(Fd, " ", "tuple header size != ~p", [Len]),
- emit(Fd, " return -1;\n }\n");
- true ->
- ok
- end,
-
- %% Fetch the return value
- emit_coding_comment(G, N, Fd, "Decode return value", "*", RetType, "oe_return"),
- APars =
- case ic_cbe:is_variable_size(G, N, RetType) of
- true ->
- emit(Fd,
- " {\n"
- " int oe_size_count_index = oe_env->_iin;\n"
- " int oe_malloc_size = 0;\n"
- " void *oe_first = NULL;\n"),
- ic_cbe:emit_malloc_size_stmt(G, N, Fd, RetType,
- "oe_env->_inbuf",
- 1, caller),
- %% XXX Add malloc prefix from option
- emit(Fd,
- " OE_MALLOC_SIZE_CHECK(oe_env, oe_malloc_size);\n"
- " if ((*oe_return = oe_first = "
- "malloc(oe_malloc_size)) == NULL) {\n"
- " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, "
- "NO_MEMORY, \"Cannot malloc\");\n"
- " return -1;\n"
- " }\n"),
- Pars = ["*oe_return"],
- DecType = case ictype:isArray(G, N, RetType) of
- true -> array_dyn;
- false -> caller_dyn
- end,
- ic_cbe:emit_decoding_stmt(G, N, Fd, RetType,
- "(*oe_return)",
- "", "oe_env->_inbuf", 1,
- "&oe_outindex", DecType,
- Pars),
- emit(Fd, " }\n"),
- Pars;
- false ->
- case ictype:isArray(G, N, RetType) of
- true ->
- Pars = ["*oe_return"],
- emit(Fd,
- " {\n"
- " int oe_size_count_index = oe_env->_iin;\n"
- " int oe_malloc_size = 0;\n"
- " void *oe_first = NULL;\n"),
- ic_cbe:emit_malloc_size_stmt(G, N, Fd, RetType,
- "oe_env->_inbuf",
- 1, caller),
- %% XXX Add malloc prefix from option
- emit(Fd,
- " OE_MALLOC_SIZE_CHECK(oe_env, "
- "oe_malloc_size);\n"
- " if ((*oe_return = oe_first = "
- "malloc(oe_malloc_size)) == NULL) {\n"
- " CORBA_exc_set(oe_env, "
- "CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "
- "\"Cannot malloc\");\n"
- " return -1;"
- " }\n"),
- ic_cbe:emit_decoding_stmt(G, N, Fd, RetType,
- "oe_return", "",
- "oe_env->_inbuf", 1,
- "&oe_outindex",
- array_fix_ret,
- Pars),
- emit(Fd, " }\n"),
- Pars;
- false ->
- Pars = [],
- %% The last parameter "oe_outindex" is not interesting
- %% in the static case.
- ic_cbe:emit_decoding_stmt(G, N, Fd, RetType,
- "oe_return", "",
- "oe_env->_inbuf", 1,
- "&oe_outindex",
- caller, Pars),
- ic_codegen:nl(Fd),
- Pars
- end
- end,
-
- foldl(fun({{'void', _}, _, _}, Acc) ->
- Acc;
- ({T, A, N1}, Acc) ->
- emit_one_decoding(G, N, Fd, T, A, N1, Acc)
- end, APars, TypeAttrArgs),
- ok.
-
-emit_one_decoding(G, N, Fd, T, A, N1, Acc) ->
- IndOp = mk_ind_op(A),
- case ic_cbe:is_variable_size(G, N, T) of
- true ->
- emit_coding_comment(G, N, Fd, "Decode", IndOp,
- T, N1),
- emit(Fd,
- " {\n"
- " int oe_size_count_index = oe_env->_iin;\n"
- " int oe_malloc_size = 0;\n"
- " void *oe_first = NULL;\n"),
- ic_cbe:emit_malloc_size_stmt(G, N, Fd, T,
- "oe_env->_inbuf",
- 1, caller),
- %% XXX Add malloc prefix from option
- emit(Fd,
- " OE_MALLOC_SIZE_CHECK(oe_env, oe_malloc_size);\n"
- " if ((~s~s = oe_first = "
- "malloc(oe_malloc_size)) == NULL) {\n", [IndOp, N1]),
- ic_cbe:emit_dealloc_stmts(Fd, " ", Acc),
- emit(Fd,
- " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, "
- "NO_MEMORY, \"Cannot malloc\");\n"
- " return -1;\n"
- " }\n"),
- NAcc = [IndOp ++ N1| Acc],
- DecType = case ictype:isArray(G, N, T) of
- true ->
- array_dyn;
- false ->
- caller_dyn
- end,
- ic_cbe:emit_decoding_stmt(G, N, Fd, T,
- "(" ++ IndOp
- ++ N1 ++ ")", "",
- "oe_env->_inbuf", 1,
- "&oe_outindex",
- DecType, NAcc),
- emit(Fd, " }\n"),
- NAcc;
- false ->
- case ictype:isArray(G, N, T) of
- true ->
- emit_coding_comment(G, N, Fd, "Decode", "",
- T, N1),
- ic_cbe:emit_decoding_stmt(G, N, Fd, T, N1,
- "", "oe_env->_inbuf",
- 1, "&oe_outindex",
- array_fix_out, Acc),
- ic_codegen:nl(Fd),
- [N1| Acc];
- false ->
- %% The last parameter "oe_outindex" is
- %% not interesting in the static case, but
- %% must be present anyhow.
- emit_coding_comment(G, N, Fd, "Decode",
- IndOp, T, N1),
- ic_cbe:emit_decoding_stmt(G, N, Fd, T, N1,
- "", "oe_env->_inbuf",
- 1, "&oe_outindex",
- caller, Acc),
- ic_codegen:nl(Fd),
- Acc
- end
- end.
-
-%%------------------------------------------------------------
-%% GENERATE PROTOTYPES
-%%------------------------------------------------------------
-%%------------------------------------------------------------
-%% Generate operation prototypes
-%%------------------------------------------------------------
-emit_operation_prototypes(G, Fd, N, Xs) ->
- lists:foreach(
- fun(X) when is_record(X, op) ->
- {ScopedName, ArgNames, RetParTypes} =
- ic_cbe:extract_info(G, N, X),
- {R, ParTypes, _} = RetParTypes,
- IfName = ic_util:to_undersc(N),
- RT = mk_ret_type(G, N, R),
- ParList =
- ic_util:chain(
- mk_par_type_list(G, N, X, [in, out], [types],
- ParTypes, ArgNames),
- ", "),
- emit(Fd, "~s ~s(~s, ~sCORBA_Environment*);\n",
- [RT, ScopedName, IfName, ParList]);
- (_) ->
- ok
- end, Xs).
-
-%%------------------------------------------------------------
-%% Generate encoder prototypes
-%%------------------------------------------------------------
-emit_encoder_prototypes(G, Fd, N, Xs) ->
- lists:foreach(
- fun(X) when is_record(X, op) ->
- {ScopedName, ArgNames, RetParTypes} =
- ic_cbe:extract_info(G, N, X),
- {_R, ParTypes, _} = RetParTypes,
- IfName = ic_util:to_undersc(N),
- ParList = ic_util:chain(
- mk_par_type_list(G, N, X, [in], [types],
- ParTypes, ArgNames),
- ", "),
- emit(Fd, "int ~s__client_enc(~s, ~sCORBA_Environment*);\n",
- [ScopedName, IfName, ParList]);
- (_) ->
- ok
- end, Xs).
-
-%%------------------------------------------------------------
-%% Generate decoder prototypes
-%%------------------------------------------------------------
-emit_decoder_prototypes(G, Fd, N, Xs) ->
- lists:foreach(
- fun(X) when is_record(X, op) ->
- case ic_forms:is_oneway(X) of
- true ->
- true;
- false ->
- IfName = ic_util:to_undersc(N),
- {ScopedName, ArgNames, RetParTypes} =
- ic_cbe:extract_info(G, N, X),
- {R, ParTypes, _} = RetParTypes,
- ParList0 =
- mk_par_type_list(G, N, X, [out], [types],
- ParTypes, ArgNames),
- PARLIST = case mk_ret_type(G, N, R) of
- "void" ->
- ParList0;
- Else ->
- [Else ++ "*"| ParList0]
- end,
- ParList = ic_util:chain(PARLIST, ", "),
- emit(Fd, "int ~s__client_dec(~s, ~s"
- "CORBA_Environment*);\n",
- [ScopedName, IfName, ParList])
- end;
- (_) ->
- ok
- end, Xs).
-
-%%------------------------------------------------------------
-%% PARAMETER TYPE LISTS
-%%------------------------------------------------------------
-%%------------------------------------------------------------
-%% Make parameter type list
-%%
-%% InOrOut = in | out | [in | out]
-%% TypesOrArgs = types | args | [types | args]
-%%------------------------------------------------------------
-mk_par_type_list(G, N, X, InOrOut, TypesOrArgs, Types, Args) ->
- TypeAttrArgs =
- filterzip(
- fun(_, {inout, Arg}) ->
- ic_error:error(G, {inout_spec_for_c, X, Arg}),
- false;
- (Type, {Attr, Arg}) ->
- case lists:member(Attr, InOrOut) of
- true ->
- {true, {Type, Attr, Arg}};
- false ->
- false
- end
- end, Types, Args),
- lists:map(
- fun({Type, Attr, Arg}) ->
- Ctype = ic_cbe:mk_c_type(G, N, Type),
- IsArray = ictype:isArray(G, N, Type),
- IsStruct = ictype:isStruct(G, N, Type),
- IsUnion = ictype:isUnion(G, N, Type),
- Dyn =
- case ic_cbe:is_variable_size(G, N, Type) of
- true ->
- if
- is_record(Type, string) -> "";
- Ctype == "CORBA_char *" -> "";
- is_record(Type, wstring) -> "";
- Ctype == "CORBA_wchar *" -> "";
- true ->
- case IsArray of
- true ->
- "_slice*";
- false ->
- "*"
- end
- end;
- false ->
- if
- Attr == in, Ctype == "erlang_pid" ->
- "*";
- Attr == in, Ctype == "erlang_port" ->
- "*";
- Attr == in, Ctype == "erlang_ref" ->
- "*";
- Attr == in, IsStruct == true ->
- "*";
- Attr == in, IsUnion == true ->
- "*";
- Attr == in, IsArray == true ->
- "_slice*";
- Attr == out, IsArray == true ->
- "_slice";
- true ->
- ""
- end
- end,
- IndOp = mk_ind_op(Attr),
- case {lists:member(types, TypesOrArgs),
- lists:member(args, TypesOrArgs)} of
- {true, true} ->
- Ctype ++ Dyn ++ IndOp ++ " " ++ Arg;
- {true, false} ->
- Ctype ++ Dyn ++ IndOp;
- {false, true} ->
- Arg;
- {false, false} ->
- ""
- end
- end, TypeAttrArgs).
-
-%%------------------------------------------------------------
-%% ENCODER ARG LIST
-%%------------------------------------------------------------
-%%------------------------------------------------------------
-%% Make encoder argument list XXX
-%%------------------------------------------------------------
-mk_arg_list_for_encoder(G, _N, X, Types, Args) ->
- filterzip(
- fun(_, {out, _}) ->
- false;
- (_, {inout, Arg}) ->
- ic_error:error(G, {inout_spec_for_c, X, Arg}),
- false;
- (_Type, {in, Arg}) ->
- {true, Arg}
- end, Types, Args).
-
-%%------------------------------------------------------------
-%% DECODER ARG LIST
-%%------------------------------------------------------------
-%%------------------------------------------------------------
-%% Make decoder argument list XXX
-%%------------------------------------------------------------
-mk_arg_list_for_decoder(G, _N, X, Types, Args) ->
- filterzip(fun(_, {in, _}) ->
- false;
- (_, {inout, Arg}) ->
- ic_error:error(G, {inout_spec_for_c, X, Arg}),
- false;
- (_, {out, Arg}) ->
- {true, Arg}
- end, Types, Args).
-
-%%------------------------------------------------------------
-%% MISC
-%%------------------------------------------------------------
-%%------------------------------------------------------------
-%% Make list of {Type, Attr, Arg}
-%%------------------------------------------------------------
-mk_type_attr_arg_list(Types, Args) ->
- filterzip(fun(Type, {Attr, Arg}) ->
- {true, {Type, Attr, Arg}}
- end, Types, Args).
-
-%%------------------------------------------------------------
-%% Make return type
-%%------------------------------------------------------------
-mk_ret_type(G, N, Type) ->
- Ctype = ic_cbe:mk_c_type(G, N, Type),
- Dyn = case ic_cbe:is_variable_size(G, N, Type) of
- true ->
- if
- is_record(Type, string) ->
- "";
- Ctype == "CORBA_char *" ->
- "";
- is_record(Type, wstring) ->
- "";
- Ctype == "CORBA_wchar *" ->
- "";
- true ->
- case ictype:isArray(G, N, Type) of
- true ->
- "_slice*";
- false ->
- "*"
- end
- end;
- false ->
- case ictype:isArray(G, N, Type) of
- true ->
- "_slice*";
- false ->
- ""
- end
- end,
- Ctype ++ Dyn.
-
-
-%%------------------------------------------------------------
-%% Make indirection operator (to "*" or not to "*").
-%%------------------------------------------------------------
-mk_ind_op(in) ->
- "";
-mk_ind_op(inout) ->
- error;
-mk_ind_op(out) ->
- "*".
-
-%%------------------------------------------------------------
-%% Emit encoding/decoding comment
-%%------------------------------------------------------------
-emit_coding_comment(G, N, Fd, String, RefOrVal, Type, Name) ->
- emit(Fd, " /* ~s parameter: ~s~s ~s */\n",
- [String, ic_cbe:mk_c_type(G, N, Type), RefOrVal, Name]).
-
-%%------------------------------------------------------------
-%% User protocol prefix for generic functions
-%%------------------------------------------------------------
-get_user_proto(G, Default) ->
- case ic_options:get_opt(G, user_protocol) of
- false ->
- Default;
- Pfx ->
- Pfx
- end.
-
-%%------------------------------------------------------------
-%% Timeout. Returns a string (or Default).
-%%------------------------------------------------------------
-get_c_timeout(G, Default) ->
- case ic_options:get_opt(G, c_timeout) of
- Tmo when is_integer(Tmo) ->
- TmoStr = integer_to_list(Tmo),
- {TmoStr, TmoStr};
- {SendTmo, RecvTmo} when is_integer(SendTmo) andalso is_integer(RecvTmo) ->
- {integer_to_list(SendTmo), integer_to_list(RecvTmo)};
- false ->
- Default
- end.
-
-%%------------------------------------------------------------
-%% ZIPPERS (merging of successive elements of two lists).
-%%------------------------------------------------------------
-
-%% zip([H1| T1], [H2| T2]) ->
-%% [{H1, H2}| zip(T1, T2)];
-%% zip([], []) ->
-%% [].
-
-filterzip(F, [H1| T1], [H2| T2]) ->
- case F(H1, H2) of
- false ->
- filterzip(F, T1, T2);
- {true, Val} ->
- [Val| filterzip(F, T1, T2)]
- end;
-filterzip(_, [], []) ->
- [].
-
-
-ifelse(true, A, _) ->
- A;
-ifelse(false, _, B) ->
- B.
diff --git a/lib/ic/src/ic_code.erl b/lib/ic/src/ic_code.erl
deleted file mode 100644
index 98d57db93b..0000000000
--- a/lib/ic/src/ic_code.erl
+++ /dev/null
@@ -1,585 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(ic_code).
-
-
--include_lib("ic/src/ic.hrl").
--include_lib("ic/src/icforms.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([get_basetype/2, insert_typedef/3, codeDirective/2]).
--export([gen_includes/3, gen_includes/4, mk_list/1]).
-
--export([type_expand_op/4, type_expand_handle_op/4]).
--export([ type_expand_op_exec/4, type_expand_all/6, type_expand/7]).
-
--export([type_expand_null/3, type_expand_void/3, type_expand_float/3, type_expand_double/3]).
--export([type_expand_short/3, type_expand_ushort/3, type_expand_long/3, type_expand_ulong/3]).
--export([type_expand_longlong/3, type_expand_ulonglong/3]).
--export([type_expand_char/3, type_expand_wchar/3, type_expand_boolean/3]).
--export([type_expand_octet/3, type_expand_any/3, type_expand_wstring/3]).
--export([type_expand_object/3, type_expand_string/3, type_expand_struct/7, type_expand_union/7]).
--export([type_expand_enum/4, type_expand_sequence/7, type_expand_array/7, type_expand_error/3]).
-
--export([type_expand_struct_rule/3, type_expand_union_rule/2, type_expand_enum_rule/4]).
--export([type_expand_enum_elements/3, type_expand_longdouble/3, type_expand_typecode/3]).
--export([type_expand_principal/3, type_expand_exception/7]).
-
-%%-----------------------------------------------------------------
-%% External functions
-%%-----------------------------------------------------------------
-
-%%-------------------------------------------------------------------------------------
-%%
-%% Trackrecording of generated sequence type structs, thist is just used for C today.
-%%
-%%-------------------------------------------------------------------------------------
-
-get_basetype(G, MyId) ->
- case ?lookup(ic_genobj:typedeftab(G), MyId) of
- [] ->
- MyId;
- X ->
- get_basetype(G, X)
- end.
-
-insert_typedef(_G, "erlang_term", _) ->
- ok;
-insert_typedef(G, MyId, DefinedAsId) ->
- ?insert(ic_genobj:typedeftab(G), MyId, DefinedAsId).
-
-codeDirective(G,X) ->
- case produceCode(X) of
- true ->
- case ic_options:get_opt(G, be) of
- c_genserv ->
- c;
- c_client ->
- c;
- c_server ->
- c_server;
- _ ->
- erlang
- end;
- false ->
- case ic_options:get_opt(G, be) of
- c_genserv ->
- c_no_stub;
- c_client ->
- c_no_stub;
- c_server ->
- c_server_no_stub;
- _ ->
- erlang_no_stub
- end
- end.
-
-%% Checks if X should produce code
-produceCode(X) when is_record(X, module) ->
- case ic_forms:get_body(X) of
- [] ->
- true;
- List ->
- produceModuleCode(List)
- end;
-produceCode(_X) ->
- false.
-
-produceModuleCode([]) ->
- false;
-produceModuleCode([X|_Xs]) when is_record(X, const) ->
- true;
-produceModuleCode([_X|Xs]) ->
- produceModuleCode(Xs).
-
-%% Includes needed c file headers for included idl files
-gen_includes(Fd,G,Type) ->
- case Type of
- c_client ->
- IncludeList =
- ic_pragma:get_included_c_headers(G),
- gen_includes_loop(Fd,IncludeList,Type);
- c_server ->
- IncludeList =
- ic_pragma:get_included_c_headers(G),
- gen_includes_loop(Fd,IncludeList,Type);
- _ ->
- ok
- end,
- ic_codegen:nl(Fd),
- ic_codegen:emit(Fd, "#ifdef __cplusplus\n"),
- ic_codegen:emit(Fd, "extern \"C\" {\n"),
- ic_codegen:emit(Fd, "#endif\n\n").
-
-
-%% Includes needed c file headers for local interfaces
-gen_includes(Fd,G,X,Type) ->
- case Type of
- c_client ->
- IncludeList =
- ic_pragma:get_local_c_headers(G,X),
- gen_includes_loop(Fd,IncludeList,Type);
- c_server ->
- IncludeList =
- ic_pragma:get_local_c_headers(G,X),
- gen_includes_loop(Fd,IncludeList,Type);
- _ ->
- ok
- end,
- ic_codegen:nl(Fd),
- ic_codegen:emit(Fd, "#ifdef __cplusplus\n"),
- ic_codegen:emit(Fd, "extern \"C\" {\n"),
- ic_codegen:emit(Fd, "#endif\n\n").
-
-
-gen_includes_loop(_,[],_) ->
- ok;
-gen_includes_loop(Fd,[I|Is],Type) ->
- L = string:tokens(I,"/"),
- File = lists:last(L),
- case File of
- "erlang" -> % Erlang is NOT generated that way !
- gen_includes_loop(Fd,Is,Type);
- "oe_erlang" -> % Erlang is NOT generated that way !
- gen_includes_loop(Fd,Is,Type);
- _ ->
- case Type of
- c_client ->
- ic_codegen:emit(Fd, "#include \"~s.h\"\n", [File]);
- c_server ->
- ic_codegen:emit(Fd, "#include \"~s__s.h\"\n", [File])
- end,
- gen_includes_loop(Fd,Is,Type)
- end.
-
-
-
-
-%%
-%% Used in NOC only
-%%
-
-
-%%
-%% Type expand on function head comments
-%%
-type_expand_op(G,N,X,Fd) ->
- case catch type_expand_op_exec(G,N,X,Fd) of
- {'EXIT',_Reason} ->
- ic_codegen:nl(Fd),
- ic_codegen:emit(Fd,"%% Error under type expansion, does not affect generated code.~n",[]),
- ic_codegen:emit(Fd,"%%------------------------------------------------------------~n",[]);
- _ ->
- ic_codegen:emit(Fd,"%%------------------------------------------------------------~n",[])
- end.
-
-
-type_expand_op_exec(G,N,X,Fd) ->
- InArgs = ic:filter_params([in,inout], X#op.params),
- OutArgs = ic:filter_params([out,inout], X#op.params),
- ParamNr = length(InArgs)+1,
- Tabs = "",
-
- ic_codegen:nl(Fd),
- ic_codegen:emit(Fd,"%%------------------------------------------------------------~n",[]),
-
- case ic_forms:is_oneway(X) of
- false ->
- ic_codegen:emit(Fd,"%% Operation: ~s/~p~n",[ic_forms:get_id2(X),ParamNr]);
- true ->
- ic_codegen:emit(Fd,"%% Operation: ~s/~p (oneway)~n",[ic_forms:get_id2(X),ParamNr])
- end,
-
- if X#op.raises == [] -> [];
- true ->
- ic_codegen:emit(Fd,"%%~n",[]),
- RaisesList=["%% Raises: " ++
- mk_list(lists:map(fun(E) -> ic_util:to_colon(E) end,
- X#op.raises))],
- ic_codegen:emit(Fd,RaisesList,[]),
- ic_codegen:nl(Fd)
- end,
-
- %% Print argument names
- ic_codegen:emit(Fd,"%%\n",[]),
- InArgNames = ["OE_Ref"]++[ic_util:mk_var(ic_forms:get_id(InArg#param.id)) || InArg <- InArgs ],
- OutArgNames = ["Ret"]++[ic_util:mk_var(ic_forms:get_id(OutArg#param.id)) || OutArg <- OutArgs ],
- case length(InArgNames) > 1 of
- true ->
- ic_codegen:emit(Fd,"%% Input value(s) : ~s~n",[mk_list(InArgNames)]);
- false ->
- ic_codegen:emit(Fd,"%% Input value : ~s~n",[mk_list(InArgNames)])
- end,
- case length(OutArgNames) > 1 of
- true ->
- ic_codegen:emit(Fd,"%% Return value(s) : ~s~n",[mk_list(OutArgNames)]);
- false ->
- ic_codegen:emit(Fd,"%% Return value : ~s~n",[mk_list(OutArgNames)])
- end,
- ic_codegen:emit(Fd,"%%\n",[]),
-
- InArgsTypeList =
- [{ic_util:mk_var(ic_forms:get_id(InArg#param.id)),ic_forms:get_tk(InArg)} || InArg <- InArgs ],
- case InArgsTypeList of
- [] -> %% no input parameters
- ok;
- _ ->
- ic_codegen:emit(Fd,"%% --input-params-~n",[]),
- type_expand_all(G,N,X,Fd,Tabs,InArgsTypeList)
- end,
-
- ReturnTypeList =[{"Ret",X#op.tk}],
- ic_codegen:emit(Fd,"%% --return-value-~n",[]),
- type_expand_all(G,N,X,Fd,Tabs,ReturnTypeList),
-
- OutArgsTypeList =
- [{ic_util:mk_var(ic_forms:get_id(OutArg#param.id)),ic_forms:get_tk(OutArg)} || OutArg <- OutArgs ],
- case OutArgsTypeList of
- [] -> %% no input parameters
- ok;
- _ ->
- ic_codegen:emit(Fd,"%% -output-values-~n",[]),
- type_expand_all(G,N,X,Fd,Tabs,OutArgsTypeList)
- end.
-
-
-
-
-type_expand_handle_op(G,N,X,Fd) ->
- case catch type_expand_handle_op_exec(G,N,X,Fd) of
- {'EXIT',_Reason} ->
- ic_codegen:nl(Fd),
- ic_codegen:emit(Fd,"%% Error under type expansion, does not affect generated code.~n",[]),
- ic_codegen:emit(Fd,"%%------------------------------------------------------------~n",[]);
- _ ->
- ic_codegen:emit(Fd,"%%------------------------------------------------------------~n",[])
- end.
-
-
-type_expand_handle_op_exec(_G,_N,X,Fd) ->
- InArgs = ic:filter_params([in,inout], X#op.params),
- ParamNr = length(InArgs)+1,
-
- ic_codegen:nl(Fd),
- ic_codegen:emit(Fd,"%%------------------------------------------------------------~n",[]),
-
- case ic_forms:is_oneway(X) of
- false ->
- ic_codegen:emit(Fd,"%% Handle operation: handle_call/3~n",[]);
- true ->
- ic_codegen:emit(Fd,"%% Handle operation: handle_cast/3~n",[])
- end,
- ic_codegen:emit(Fd,"%%~n",[]),
- ic_codegen:emit(Fd,"%% Used for operation ~s/~p implementation~n",[ic_forms:get_id2(X),ParamNr]).
-
-
-
-type_expand_all(_G,_N,_X,_Fd,_Tabs,[]) ->
- ok;
-type_expand_all(G,N,X,Fd,Tabs,[{ArgName,Type}|Rest]) ->
- type_expand(G,N,X,Fd,Tabs,ArgName,Type),
- type_expand_all(G,N,X,Fd,Tabs,Rest);
-type_expand_all(G,N,X,Fd,Tabs,[{default,_ArgName,Type}|Rest]) ->
- type_expand(G,N,X,Fd,Tabs,"Def",Type),
- type_expand_all(G,N,X,Fd,Tabs,Rest);
-type_expand_all(G,N,X,Fd,Tabs,[{LabelNr,_ArgName,Type}|Rest]) when is_integer(LabelNr) ->
- type_expand(G,N,X,Fd,Tabs,"V" ++ integer_to_list(LabelNr),Type),
- type_expand_all(G,N,X,Fd,Tabs,Rest);
-type_expand_all(G,N,X,Fd,Tabs,[{Label,_ArgName,Type}|Rest]) ->
- type_expand(G,N,X,Fd,Tabs,Label,Type),
- type_expand_all(G,N,X,Fd,Tabs,Rest).
-
-
-
-type_expand(_G,_N,_X,Fd,Tabs,Name,tk_null) ->
- type_expand_null(Fd,Tabs,Name);
-type_expand(_G,_N,_X,Fd,Tabs,Name,tk_void) ->
- type_expand_void(Fd,Tabs,Name);
-type_expand(_G,_N,_X,Fd,Tabs,Name,tk_float) ->
- type_expand_float(Fd,Tabs,Name);
-type_expand(_G,_N,_X,Fd,Tabs,Name,tk_double) ->
- type_expand_double(Fd,Tabs,Name);
-type_expand(_G,_N,_X,Fd,Tabs,Name,tk_longdouble) ->
- type_expand_longdouble(Fd,Tabs,Name);
-type_expand(_G,_N,_X,Fd,Tabs,Name,tk_short) ->
- type_expand_short(Fd,Tabs,Name);
-type_expand(_G,_N,_X,Fd,Tabs,Name,tk_ushort) ->
- type_expand_ushort(Fd,Tabs,Name);
-type_expand(_G,_N,_X,Fd,Tabs,Name,tk_long) ->
- type_expand_long(Fd,Tabs,Name);
-type_expand(_G,_N,_X,Fd,Tabs,Name,tk_longlong) ->
- type_expand_longlong(Fd,Tabs,Name);
-type_expand(_G,_N,_X,Fd,Tabs,Name,tk_ulong) ->
- type_expand_ulong(Fd,Tabs,Name);
-type_expand(_G,_N,_X,Fd,Tabs,Name,tk_ulonglong) ->
- type_expand_ulonglong(Fd,Tabs,Name);
-type_expand(_G,_N,_X,Fd,Tabs,Name,tk_char) ->
- type_expand_char(Fd,Tabs,Name);
-type_expand(_G,_N,_X,Fd,Tabs,Name,tk_wchar) ->
- type_expand_wchar(Fd,Tabs,Name);
-type_expand(_G,_N,_X,Fd,Tabs,Name,tk_boolean) ->
- type_expand_boolean(Fd,Tabs,Name);
-type_expand(_G,_N,_X,Fd,Tabs,Name,tk_octet) ->
- type_expand_octet(Fd,Tabs,Name);
-type_expand(_G,_N,_X,Fd,Tabs,Name,tk_any) ->
- type_expand_any(Fd,Tabs,Name);
-type_expand(_G,_N,_X,Fd,Tabs,Name,tk_TypeCode) ->
- type_expand_typecode(Fd,Tabs,Name);
-type_expand(_G,_N,_X,Fd,Tabs,Name,tk_Principal) ->
- type_expand_principal(Fd,Tabs,Name);
-type_expand(G, N, X,Fd,Tabs,Name, {tk_except, Id, ExcName, ElementList}) ->
- type_expand_exception(G, N, X, Fd,Tabs,Name,
- {tk_except, Id, ExcName, ElementList});
-type_expand(_G,_N,_X,Fd,Tabs,Name,{tk_fixed, _Digits, _Scale}) ->
- type_expand_fixed(Fd,Tabs,Name);
-type_expand(_G,_N,_X,Fd,Tabs,Name,{tk_objref, _IFRId, _ObjTabs, _ObjName}) ->
- type_expand_object(Fd,Tabs,Name);
-type_expand(_G,_N,_X,Fd,Tabs,Name,{tk_objref, _IFRId, _ObjName}) ->
- type_expand_object(Fd,Tabs,Name);
-type_expand(_G,_N,_X,Fd,Tabs,Name,{tk_string, _Length}) ->
- type_expand_string(Fd,Tabs,Name);
-type_expand(_G,_N,_X,Fd,Tabs,Name,{tk_wstring, _Length}) ->
- type_expand_wstring(Fd,Tabs,Name);
-type_expand(G,N,X,Fd,Tabs,Name,{tk_union, IFRId, UnionName, DTC, DNr, LblList}) ->
- type_expand_union(G,N,X,Fd,Tabs,Name,{tk_union, IFRId, UnionName, DTC, DNr, LblList});
-type_expand(_G,_N,_X,Fd,Tabs,Name,{tk_enum, IFRId, EnumName, ElemNameList}) ->
- type_expand_enum(Fd,Tabs,Name,{tk_enum, IFRId, EnumName, ElemNameList});
-type_expand(G,N,X,Fd,Tabs,Name,{tk_sequence, ElemTC, Length}) ->
- type_expand_sequence(G,N,X,Fd,Tabs,Name,{tk_sequence, ElemTC, Length});
-type_expand(G,N,X,Fd,Tabs,Name,{tk_array, ElemTC, Length}) ->
- type_expand_array(G,N,X,Fd,Tabs,Name,{tk_array, ElemTC, Length});
-type_expand(G,N,X,Fd,Tabs,Name,{tk_struct, IFRId, StructName, TcList}) ->
- type_expand_struct(G,N,X,Fd,Tabs,Name,{tk_struct, IFRId, StructName, TcList});
-type_expand(_G,_N,_X,Fd,Tabs,Name,_) ->
- type_expand_error(Fd,Tabs,Name).
-
-
-%% Basic OMG IDL types
-
-type_expand_null(Fd,Tabs,Name) ->
- ic_codegen:emit(Fd,"%%~s ~s = null()~n",[Tabs,Name]).
-
-type_expand_void(Fd,Tabs,Name) ->
- ic_codegen:emit(Fd,"%%~s ~s = void()~n",[Tabs,Name]).
-
-type_expand_float(Fd,Tabs,Name) ->
- ic_codegen:emit(Fd,"%%~s ~s = float()~n",[Tabs,Name]).
-
-type_expand_double(Fd,Tabs,Name) ->
- ic_codegen:emit(Fd,"%%~s ~s = double()~n",[Tabs,Name]).
-
-type_expand_longdouble(Fd,Tabs,Name) ->
- ic_codegen:emit(Fd,"%%~s ~s = long_double()~n",[Tabs,Name]).
-
-type_expand_short(Fd,Tabs,Name) ->
- ic_codegen:emit(Fd,"%%~s ~s = short()~n",[Tabs,Name]).
-
-type_expand_ushort(Fd,Tabs,Name) ->
- ic_codegen:emit(Fd,"%%~s ~s = unsigned_Short()~n",[Tabs,Name]).
-
-type_expand_long(Fd,Tabs,Name) ->
- ic_codegen:emit(Fd,"%%~s ~s = long()~n",[Tabs,Name]).
-
-type_expand_longlong(Fd,Tabs,Name) ->
- ic_codegen:emit(Fd,"%%~s ~s = long_Long()~n",[Tabs,Name]).
-
-type_expand_ulong(Fd,Tabs,Name) ->
- ic_codegen:emit(Fd,"%%~s ~s = unsigned_Long()~n",[Tabs,Name]).
-
-type_expand_ulonglong(Fd,Tabs,Name) ->
- ic_codegen:emit(Fd,"%%~s ~s = unsigned_Long_Long()~n",[Tabs,Name]).
-
-type_expand_char(Fd,Tabs,Name) ->
- ic_codegen:emit(Fd,"%%~s ~s = char()~n",[Tabs,Name]).
-
-type_expand_wchar(Fd,Tabs,Name) ->
- ic_codegen:emit(Fd,"%%~s ~s = wchar()~n",[Tabs,Name]).
-
-type_expand_boolean(Fd,Tabs,Name) ->
- ic_codegen:emit(Fd,"%%~s ~s = boolean()~n",[Tabs,Name]).
-
-type_expand_octet(Fd,Tabs,Name) ->
- ic_codegen:emit(Fd,"%%~s ~s = octet()~n",[Tabs,Name]).
-
-type_expand_any(Fd,Tabs,Name) ->
- ic_codegen:emit(Fd,"%%~s ~s = any()~n",[Tabs,Name]).
-
-type_expand_typecode(Fd,Tabs,Name) ->
- ic_codegen:emit(Fd,"%%~s ~s = TypeCode()~n",[Tabs,Name]).
-
-type_expand_principal(Fd,Tabs,Name) ->
- ic_codegen:emit(Fd,"%%~s ~s = principal()~n",[Tabs,Name]).
-
-
-type_expand_fixed(Fd,Tabs,Name) ->
- ic_codegen:emit(Fd,"%%~s ~s = fixed()~n",[Tabs,Name]).
-
-type_expand_object(Fd,Tabs,Name) ->
- ic_codegen:emit(Fd,"%%~s ~s = Object_Ref()~n",[Tabs,Name]).
-
-
-%% Constructed OMG IDL types
-
-type_expand_string(Fd,Tabs,Name) ->
- ic_codegen:emit(Fd,"%%~s ~s = String()~n",[Tabs,Name]).
-
-type_expand_wstring(Fd,Tabs,Name) ->
- ic_codegen:emit(Fd,"%%~s ~s = WString()~n",[Tabs,Name]).
-
-type_expand_exception(G, N, X, Fd, Tabs, Name, {tk_except, Id, ExcName, ElementList}) ->
- ScopedStructName = getScopedName(G, N, ExcName, Id),
- ic_codegen:emit(Fd,"%%~s ~s = ",[Tabs, Name]),
- type_expand_exception_rule(Fd, ScopedStructName, ElementList),
- type_expand_all(G, N, X, Fd, Tabs, ElementList).
-
-type_expand_struct(G,N,X,Fd,Tabs,Name,{tk_struct, IFRId, StructName, TcList}) ->
- ScopedStructName = getScopedName(G,N,StructName,IFRId),
- ic_codegen:emit(Fd,"%%~s ~s = ",[Tabs,Name]),
- type_expand_struct_rule(Fd,ScopedStructName,TcList),
- type_expand_all(G,N,X,Fd,Tabs,TcList).
-
-type_expand_union(G,N,X,Fd,Tabs,Name,{tk_union, IFRId, UnionName, DTC, _DNr, LblList}) ->
- ScopedUnionName = getScopedName(G,N,UnionName,IFRId),
- ic_codegen:emit(Fd,"%%~s ~s = #'~s'{label, value}\n",[Tabs,Name,ScopedUnionName]),
- type_expand(G,N,X,Fd,Tabs,"label",DTC),
- ic_codegen:emit(Fd,"%%~s value = ",[Tabs]),
- type_expand_union_rule(Fd,LblList),
- type_expand_all(G,N,X,Fd,Tabs,LblList).
-
-type_expand_enum(Fd,Tabs,Name,{tk_enum, _IFRId, EnumName, ElemNameList}) ->
- ic_codegen:emit(Fd,"%%~s ~s = ~s~n",[Tabs,Name,EnumName]),
- type_expand_enum_rule(Fd,Tabs,EnumName,ElemNameList).
-
-type_expand_sequence(G,N,X,Fd,Tabs,Name,{tk_sequence, ElemTC, _Length}) ->
- ic_codegen:emit(Fd,"%%~s ~s = [ ~sElem ]~n",[Tabs,Name,Name]),
- type_expand(G,N,X,Fd,Tabs,Name++"Elem",ElemTC).
-
-type_expand_array(G,N,X,Fd,Tabs,Name,{tk_array, ElemTC, _Length}) ->
- ic_codegen:emit(Fd,"%%~s ~s = { ~sElem[,..~sElem] }~n",[Tabs,Name,Name,Name]),
- type_expand(G,N,X,Fd,Tabs,Name++"Elem",ElemTC).
-
-type_expand_error(Fd,Tabs,Name) ->
- ic_codegen:emit(Fd,"%%~s ~s = ????~n",[Tabs,Name]).
-
-
-type_expand_exception_rule(Fd,_Name,[]) ->
- ic_codegen:emit(Fd," ???? ");
-type_expand_exception_rule(Fd,Name,TcList) ->
- ic_codegen:emit(Fd,"#'~s'{",[Name]),
- type_expand_exception_rule(Fd,TcList).
-
-type_expand_exception_rule(Fd,[{Name,_TC}]) ->
- ic_codegen:emit(Fd,"~s}~n",[Name]);
-type_expand_exception_rule(Fd,[{Name,_TC}|Rest]) ->
- ic_codegen:emit(Fd,"~s,",[Name]),
- type_expand_exception_rule(Fd,Rest).
-
-type_expand_struct_rule(Fd,_Name,[]) ->
- ic_codegen:emit(Fd," ???? ");
-type_expand_struct_rule(Fd,Name,TcList) ->
- ic_codegen:emit(Fd,"#'~s'{",[Name]),
- type_expand_struct_rule(Fd,TcList).
-
-type_expand_struct_rule(Fd,[{Name,_TC}]) ->
- ic_codegen:emit(Fd,"~s}~n",[Name]);
-type_expand_struct_rule(Fd,[{Name,_TC}|Rest]) ->
- ic_codegen:emit(Fd,"~s,",[Name]),
- type_expand_struct_rule(Fd,Rest).
-
-
-type_expand_union_rule(Fd,[]) ->
- ic_codegen:emit(Fd," ????");
-type_expand_union_rule(Fd,[{default,_Name,_TC}]) ->
- ic_codegen:emit(Fd,"Def~n",[]);
-type_expand_union_rule(Fd,[{LNr,_Name,_TC}]) when is_integer(LNr)->
- ic_codegen:emit(Fd,"V~p~n",[LNr]);
-type_expand_union_rule(Fd,[{Label,_Name,_TC}]) ->
- ic_codegen:emit(Fd,"~s~n",[Label]);
-type_expand_union_rule(Fd,[{default,_Name,_TC}|Rest]) ->
- ic_codegen:emit(Fd,"Default | "),
- type_expand_union_rule(Fd,Rest);
-type_expand_union_rule(Fd,[{LNr,_Name,_TC}|Rest]) when is_integer(LNr) ->
- ic_codegen:emit(Fd,"V~p | ",[LNr]),
- type_expand_union_rule(Fd,Rest);
-type_expand_union_rule(Fd,[{Label,_Name,_TC}|Rest]) ->
- ic_codegen:emit(Fd,"~s | ",[Label]),
- type_expand_union_rule(Fd,Rest).
-
-
-type_expand_enum_rule(Fd,Tabs,Name,[]) ->
- ic_codegen:emit(Fd,"%%~s ~s = ????",[Tabs,Name]);
-type_expand_enum_rule(Fd,Tabs,Name,ElList) ->
- ic_codegen:emit(Fd,"%%~s ~s = ",[Tabs,Name]),
- type_expand_enum_rule(Fd,ElList).
-
-type_expand_enum_rule(Fd,[ElName]) ->
- ic_codegen:emit(Fd,"'~s' ~n",[ElName]);
-type_expand_enum_rule(Fd,[First|Rest]) ->
- ic_codegen:emit(Fd,"'~s' | ",[First]),
- type_expand_enum_rule(Fd,Rest).
-
-type_expand_enum_elements(_Fd,_Tabs,[]) ->
- ok;
-type_expand_enum_elements(Fd,Tabs,[Elem|Elems]) ->
- ic_codegen:emit(Fd,"%%~s ~s = Atom()~n",[Tabs,Elem]),
- type_expand_enum_elements(Fd,Tabs,Elems).
-
-
-
-%% Returns the right scoped name to be used
-%% along with the expansion comments
-getScopedName(G,N,Name,IfrId) ->
- PTab = ic_genobj:pragmatab(G),
- case ets:match(PTab,{alias,'$0',IfrId}) of
- [] -> %% No Alias - should never happen
- ic_util:to_undersc(ic_pragma:mk_scope(IfrId));
- [[[_S|N]]] -> %% An alias
- ic_util:to_undersc([Name|N]);
- [[[S|FoundScope]]] -> %% Maybe inherited
- case ic_pragma:is_inherited_by(FoundScope,N,PTab) of
- false -> %% Not inherited
- ic_util:to_undersc([S|FoundScope]);
- true -> %% inherited
- ic_util:to_undersc([Name|N])
- end
- end.
-
-
-%% mk_list produces a nice comma separated
-%% string of variable names
-mk_list([]) -> [];
-mk_list([Arg | Args]) ->
- Arg ++ mk_list2(Args).
-mk_list2([Arg | Args]) ->
- ", " ++ Arg ++ mk_list2(Args);
-mk_list2([]) -> [].
-
-
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-
-
-
diff --git a/lib/ic/src/ic_codegen.erl b/lib/ic/src/ic_codegen.erl
deleted file mode 100644
index a3f141f606..0000000000
--- a/lib/ic/src/ic_codegen.erl
+++ /dev/null
@@ -1,423 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(ic_codegen).
-
--include_lib("ic/src/ic.hrl").
--include_lib("ic/src/icforms.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([emit/2, emit/3]).
--export([emit_c_enc_rpt/4, emit_c_dec_rpt/4]).
--export([comment/2, comment/3, comment/4, comment_inlined/5, comment_prefixed/4]).
--export([mcomment/2, mcomment/3, mcomment_inlined/5, mcomment_prefixed/3]).
--export([mcomment_light/2, mcomment_light/3, mcomment_light_inlined/5, mcomment_light_prefixed/3]).
--export([nl/1, export/2]).
--export([record/5]).
--export([emit_stub_head/4, emit_hrl_head/4, emit_hrl_foot/2]).
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
-
-%%-----------------------------------------------------------------
-%% External functions
-%%-----------------------------------------------------------------
-
-%%--------------------------------------------------------------------
-%% Emit output as a formatted string, (old emit)
-%%--------------------------------------------------------------------
-emit(nil, _) -> ok;
-emit(Fd, Str) ->
- file:write(Fd, Str).
-
-emit(nil, _, _) -> ok;
-emit(Fd, Fmt, Args) ->
- file:write(Fd, io_lib:format(Fmt, Args)).
-
-emit_c_enc_rpt(Fd, Prefix, Fmt, Args) ->
- emit(Fd, Prefix ++ "OE_RPT_ERR(\"Encode error: " ++ Fmt ++ "\");\n", Args).
-
-emit_c_dec_rpt(Fd, Prefix, Fmt, Args) ->
- emit(Fd, Prefix ++ "OE_RPT_ERR(\"Decode error: " ++ Fmt ++ "\");\n", Args).
-
-%%--------------------------------------------------------------------
-%% Emit comments
-%%--------------------------------------------------------------------
-comment(Fd, C) ->
- comment_prefixed(Fd, C, [], "%%").
-
-comment(Fd, C, A) ->
- comment_prefixed(Fd, C, A, "%%").
-
-comment(Fd, C, A, c) ->
- comment_inlined(Fd, C, A, "/*", "*/");
-comment(Fd, C, A, erl) ->
- comment_prefixed(Fd, C, A, "%%");
-comment(Fd, C, A, java) ->
- comment_prefixed(Fd, C, A, "//");
-%% Should be removed after a check if it's used !!!!! (LTH)
-comment(Fd, C, A, CommentSequence) when is_list(CommentSequence) ->
- comment_prefixed(Fd, C, A, CommentSequence).
-
-comment_inlined(Fd, C, A, Start, End) ->
- emit(Fd, Start ++ " " ++ C ++ " " ++ End ++"\n", A).
-
-comment_prefixed(Fd, C, A, Prefix) ->
- emit(Fd, Prefix ++ " " ++ C ++ "\n", A).
-
-%%--------------------------------------------------------------------
-%% Emit multiline comments with nice delimiters
-%%--------------------------------------------------------------------
-mcomment(Fd, List) ->
- mcomment_prefixed(Fd, List, "%%").
-
-mcomment(Fd, List, c) ->
- mcomment_inlined(Fd, List, "/*", "*/", " *");
-mcomment(Fd, List, erl) ->
- mcomment_prefixed(Fd, List, "%%");
-mcomment(Fd, List, java) ->
- mcomment_prefixed(Fd, List, "//").
-
-mcomment_inlined(Fd, List, Start, End, Intermediate) ->
- emit(Fd, Start ++
- "------------------------------------------------------------\n"),
- emit(Fd, Intermediate ++ "\n"),
- lists:foreach(fun(C) -> comment(Fd, C, [], Intermediate) end, List),
- emit(Fd, Intermediate ++ "\n"),
- emit(Fd, Intermediate ++
- "------------------------------------------------------------" ++ End ++ "\n"),
- ok.
-mcomment_prefixed(Fd, List, Prefix) ->
- emit(Fd, Prefix ++
- "------------------------------------------------------------\n"),
- emit(Fd, Prefix ++ "\n"),
- lists:foreach(fun(C) -> comment(Fd, C, [], Prefix) end, List),
- emit(Fd, Prefix ++ "\n"),
- emit(Fd, Prefix ++
- "------------------------------------------------------------\n"),
- ok.
-
-
-%%--------------------------------------------------------------------
-%% Emit multiline comments with nice delimiters as above but a
-%% little lighter
-%%--------------------------------------------------------------------
-mcomment_light(Fd, List) ->
- mcomment_light_prefixed(Fd, List, "%%").
-
-mcomment_light(Fd, List, c) ->
- mcomment_light_inlined(Fd, List, "/*", " */", " *");
-mcomment_light(Fd, List, erl) ->
- mcomment_light_prefixed(Fd, List, "%%");
-mcomment_light(Fd, List, java) ->
- mcomment_light_prefixed(Fd, List, "//");
-%% Should be removed after a check if it's used !!!!! (LTH)
-mcomment_light(Fd, List, Prefix) when is_list(Prefix) ->
- mcomment_light_prefixed(Fd, List, Prefix).
-
-mcomment_light_inlined(Fd, List, Start, End, Intermediate) ->
- emit(Fd, "\n" ++ Start ++ "\n"),
- lists:foreach(fun(C) -> comment(Fd, C, [], Intermediate) end, List),
- emit(Fd, End ++ "\n"),
- ok.
-
-mcomment_light_prefixed(Fd, List, Prefix) ->
- emit(Fd, Prefix),
- lists:foreach(fun(C) -> comment(Fd, C, [], Prefix) end, List),
- emit(Fd, Prefix ++ "\n"),
- ok.
-
-%%--------------------------------------------------------------------
-%% New line
-%%--------------------------------------------------------------------
-nl(Fd) ->
- emit(Fd, "\n").
-
-
-%%--------------------------------------------------------------------
--define(IFRIDFIELD(G), ic_util:mk_name(G, "ID")).
-
-%%--------------------------------------------------------------------
-%% Emit record definitions for erlang
-%%--------------------------------------------------------------------
-record(G, X, Name, _IFRID, Recs) when is_record(X, struct) ->
- F = ic_genobj:hrlfiled(G),
- emit(F, "-record(~p, {~p", [ic_util:to_atom(Name),hd(Recs)]),
- lists:foreach(fun(Y) -> emit(F, ", ~p", [Y]) end, tl(Recs)),
- emit(F, "}).\n");
-record(G, X, Name, _IFRID, _Recs) when is_record(X, union) ->
- F = ic_genobj:hrlfiled(G),
- emit(F, "-record(~p, {label, value}).\n",[ic_util:to_atom(Name)]);
-record(G, _X, Name, IFRID, Recs) when length(Recs) > 3 ->
- F = ic_genobj:hrlfiled(G),
- emit(F, "-record(~p,~n {~p=~p",
- [ic_util:to_atom(Name), ic_util:to_atom(?IFRIDFIELD(G)), IFRID]),
- rec2(F, "", ", ", Recs),
- emit(F, "}).\n");
-record(G, _X, Name, IFRID, Recs) ->
- F = ic_genobj:hrlfiled(G),
- emit(F, "-record(~p, {~p=~p", [ic_util:to_atom(Name),
- ic_util:to_atom(?IFRIDFIELD(G)),
- IFRID]),
- lists:foreach(fun(Y) -> emit(F, ", ~p", [Y]) end, Recs),
- emit(F, "}).\n").
-
-
-rec2(F, Align, Delim, [M1 , M2, M3 | Ms]) ->
- emit(F, "~s~s~p, ~p, ~p", [Delim, Align, M1, M2, M3]),
- rec2(F, " ", ",\n", Ms);
-rec2(F, Align, Delim, [M1 , M2]) ->
- emit(F, "~s~s~p, ~p", [Delim, Align, M1, M2]);
-rec2(F, Align, Delim, [M]) ->
- emit(F, "~s~s~p", [Delim, Align, M]);
-rec2(_F, _Align, _Delim, []) ->
- ok.
-
-
-%%--------------------------------------------------------------------
-%% Emit export lists for erlang
-%%--------------------------------------------------------------------
-export(F, [E1, E2, E3 | Exports]) ->
- emit(F, "-export([~s]).\n", [exp_list([E1, E2, E3])]),
- export(F, Exports);
-export(_F, []) -> ok;
-export(F, Exports) ->
- emit(F, "-export([~s]).\n", [exp_list(Exports)]).
-
-exp_list([E1 | L]) ->
- exp_to_string(E1) ++
- lists:map(fun(E) -> ", " ++ exp_to_string(E) end, L).
-
-
-exp_to_string({F,N}) -> io_lib:format("~p/~p", [ic_util:to_atom(F), N]).
-
-
-%%--------------------------------------------------------------------
-%% Emit Stub file header
-%%--------------------------------------------------------------------
-emit_stub_head(_G, ignore, _Name, _) -> ignore;
-emit_stub_head(G, F1, Name, erlang) ->
- comment(F1, " coding: latin-1", []),
- mcomment(F1, stub_header(G, Name)),
- nl(F1),
- emit(F1, "-module(~p).\n", [list_to_atom(Name)]),
- emit(F1, "-ic_compiled(~p).\n", [compiler_vsn(?COMPILERVSN)]),
- emit(F1, "\n\n"), F1;
-emit_stub_head(G, F1, Name, erlang_template) ->
- comment(F1, " coding: latin-1", []),
- ic_erl_template:emit_header(G, F1, Name),
- F1;
-emit_stub_head(_G, F1, _Name, erlang_template_no_gen) ->
- F1;
-emit_stub_head(G, F1, Name, c) ->
- mcomment(F1, stub_header(G, Name), c),
- emit(F1, "int ic_compiled_~s_~s;\n", [compiler_vsn(?COMPILERVSN), Name]),
- emit(F1, "\n\n"), F1;
-emit_stub_head(G, F1, Name, c_server) ->
- CSName = [Name, "__s"],
- mcomment(F1, stub_header(G, CSName), c),
- emit(F1, "int ic_compiled_~s_~s;\n", [compiler_vsn(?COMPILERVSN), CSName]),
- emit(F1, "\n\n"), F1;
-emit_stub_head(G, F1, Name, java) ->
- mcomment(F1, stub_header(G, Name), java),
- emit(F1, "\n\n"), F1.
-
-stub_header(G, Name) ->
- ["Implementation stub file",
- "",
- io_lib:format("Target: ~ts", [Name]),
- io_lib:format("Source: ~ts", [ic_genobj:idlfile(G)]),
- io_lib:format("IC vsn: ~s", [?COMPILERVSN]),
- "",
- "This file is automatically generated. DO NOT EDIT IT."].
-
-compiler_vsn(Vsn) ->
- lists:map(fun($.) -> $_;
- (C) -> C
- end, Vsn).
-
-%%--------------------------------------------------------------------
-%% Emit include file header
-%%--------------------------------------------------------------------
-%% Name is Fully scoped (undescore) name of interface or module
-emit_hrl_head(_G, ignore, _Name, _) -> ignore;
-emit_hrl_head(G, Fd, Name, erlang) ->
- comment(Fd, " coding: latin-1", []),
- mcomment(Fd, ["Erlang header file" |
- hrl_header(G, Name)]),
- nl(Fd),
- nl(Fd),
- IfdefName = ic_util:to_uppercase(Name++"_HRL"),
- emit(Fd, "-ifndef(~s).~n", [IfdefName]),
- emit(Fd, "-define(~s, true).~n", [IfdefName]),
- nl(Fd),
- nl(Fd),
- Fd;
-emit_hrl_head(G, Fd, Name, c) ->
- mcomment(Fd, ["C header file" |
- hrl_header(G, Name)], c),
- nl(Fd),
- nl(Fd),
- IfdefName = ic_util:to_uppercase(Name++"_H"),
- emit(Fd, "#ifndef ~s~n", [IfdefName]),
- emit(Fd, "#define ~s ~n", [IfdefName]),
- nl(Fd),
- nl(Fd),
- Fd;
-emit_hrl_head(G, Fd, Name, c_server) ->
- mcomment(Fd, ["C header file" |
- hrl_header(G, [Name, "__s"])], c),
- nl(Fd),
- nl(Fd),
- IfdefName = ic_util:to_uppercase(Name++"__S_H"),
- emit(Fd, "#ifndef ~s~n", [IfdefName]),
- emit(Fd, "#define ~s ~n", [IfdefName]),
- nl(Fd),
- nl(Fd),
- Fd.
-
-hrl_header(G, Name) ->
- ["",
- io_lib:format("Target: ~ts", [Name]),
- io_lib:format("Source: ~ts", [ic_genobj:idlfile(G)]),
- io_lib:format("IC vsn: ~s", [?COMPILERVSN]),
- "",
- "This file is automatically generated. DO NOT EDIT IT."].
-
-
-
-
-%%--------------------------------------------------------------------
-%% Emit include file footer
-%%--------------------------------------------------------------------
-emit_hrl_foot(_G, erlang_template) ->
- ok;
-emit_hrl_foot(_G, erlang_template_no_gen) ->
- ok;
-emit_hrl_foot(G, erlang) ->
- case ic_genobj:is_hrlfile_open(G) of
- true ->
- Fd = ic_genobj:hrlfiled(G),
- nl(Fd),
- nl(Fd),
- emit(Fd, "-endif.\n"),
- nl(Fd),
- nl(Fd),
- Fd;
- false ->
- ok
- end;
-emit_hrl_foot(G, erlang_no_stub) ->
- case ic_genobj:is_hrlfile_open(G) of
- true ->
- Fd = ic_genobj:hrlfiled(G),
- nl(Fd),
- nl(Fd),
- emit(Fd, "-endif.\n"),
- nl(Fd),
- nl(Fd),
- Fd;
- false ->
- ok
- end;
-emit_hrl_foot(G, c) ->
- case ic_genobj:is_hrlfile_open(G) of
- true ->
- Fd = ic_genobj:hrlfiled(G),
- nl(Fd),
- nl(Fd),
- emit(Fd, "#ifdef __cplusplus\n"),
- emit(Fd, "}\n"),
- emit(Fd, "#endif\n"),
- nl(Fd),
- emit(Fd, "#endif\n"),
- nl(Fd),
- nl(Fd),
- Fd;
- false ->
- ok
- end;
-emit_hrl_foot(G, c_server) ->
- case ic_genobj:is_hrlfile_open(G) of
- true ->
- Fd = ic_genobj:hrlfiled(G),
- nl(Fd),
- nl(Fd),
- emit(Fd, "#ifdef __cplusplus\n"),
- emit(Fd, "}\n"),
- emit(Fd, "#endif\n"),
- nl(Fd),
- emit(Fd, "#endif\n"),
- nl(Fd),
- nl(Fd),
- Fd;
- false ->
- ok
- end;
-emit_hrl_foot(G, c_no_stub) ->
- case ic_genobj:is_hrlfile_open(G) of
- true ->
- Fd = ic_genobj:hrlfiled(G),
- nl(Fd),
- nl(Fd),
- emit(Fd, "#ifdef __cplusplus\n"),
- emit(Fd, "}\n"),
- emit(Fd, "#endif\n"),
- nl(Fd),
- emit(Fd, "#endif\n"),
- nl(Fd),
- nl(Fd),
- Fd;
- false ->
- ok
- end;
-emit_hrl_foot(G, c_server_no_stub) ->
- case ic_genobj:is_hrlfile_open(G) of
- true ->
- Fd = ic_genobj:hrlfiled(G),
- nl(Fd),
- nl(Fd),
- emit(Fd, "#ifdef __cplusplus\n"),
- emit(Fd, "}\n"),
- emit(Fd, "#endif\n"),
- nl(Fd),
- emit(Fd, "#endif\n"),
- nl(Fd),
- nl(Fd),
- Fd;
- false ->
- ok
- end.
-
-
-
-
-
-
-
-
-
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
diff --git a/lib/ic/src/ic_constant_java.erl b/lib/ic/src/ic_constant_java.erl
deleted file mode 100644
index 49150f96ac..0000000000
--- a/lib/ic/src/ic_constant_java.erl
+++ /dev/null
@@ -1,100 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(ic_constant_java).
-
-
--include("icforms.hrl").
--include("ic.hrl").
--include("ic_debug.hrl").
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([gen/3]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-%%-----------------------------------------------------------------
-%% External functions
-%%-----------------------------------------------------------------
-
-%%-----------------------------------------------------------------
-%% Func: gen/3
-%%-----------------------------------------------------------------
-gen(G, N, X) when is_record(X, const) ->
- ConstantName = ic_forms:get_java_id(X),
- case inInterface(G, N) of
- true ->
- emit_constant(G, N, X, ConstantName);
- false ->
- emit_constant_interface(G, N, X, ConstantName)
- end;
-gen(_G, _N, _X) ->
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-
-%%-----------------------------------------------------------------
-%% Func: emit_constant/4
-%%-----------------------------------------------------------------
-emit_constant(G, N, X, ConstantName) ->
- Fd = ic_genobj:interfacefiled(G),
- %%?PRINTDEBUG2("~p", [Fd]),
- Type = ic_java_type:getType(G, N, ic_forms:get_type(X)),
- ic_codegen:emit(Fd, " public static final ~s ~s = (~s) ~p;\n",
- [Type, ConstantName, Type, X#const.val]),
- ic_codegen:nl(Fd).
-
-%%-----------------------------------------------------------------
-%% Func: emit_constant_interface/4
-%%-----------------------------------------------------------------
-emit_constant_interface(G, N, X, ConstantName) ->
- {Fd, _} = ic_file:open_java_file(G, N, ConstantName),
-
- ic_codegen:emit(Fd, "final public class ~s {\n",[ConstantName]),
-
- Type = ic_java_type:getType(G, N, ic_forms:get_type(X)),
- ic_codegen:emit(Fd, " public static final ~s value = (~s) ~p;\n",
- [Type, Type, X#const.val]),
- ic_codegen:emit(Fd, "}\n", []),
- file:close(Fd).
-
-%%-----------------------------------------------------------------
-%% Func: emit_constant_interface/4
-%%-----------------------------------------------------------------
-inInterface(_G, []) -> % Global constant
- false;
-inInterface(G, N) ->
- [N1 |Ns] = N,
- {_FullScopedName, T, _TK, _} =
- ic_symtab:get_full_scoped_name(G, Ns, ic_symtab:scoped_id_new(N1)),
- case T of
- interface -> % Constant declare in an interface
- true;
- _ -> % Constant declared in a module
- false
- end.
-
diff --git a/lib/ic/src/ic_cserver.erl b/lib/ic/src/ic_cserver.erl
deleted file mode 100644
index 7c7506367e..0000000000
--- a/lib/ic/src/ic_cserver.erl
+++ /dev/null
@@ -1,2420 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(ic_cserver).
-
-%% This module implements generation of C server code, where the
-%% server acts as an Erlang C-node, where the functionality is that of
-%% a gen_server (in C), and where the communication thus is according
-%% to the Erlang distribution protocol.
-%%
-
--export([do_gen/3]).
-
-%% Silly dialyzer.
--export([filterzip/3]).
-
-%%------------------------------------------------------------
-%%
-%% Internal stuff
-%%
-%%------------------------------------------------------------
-
--import(lists, [foreach/2, foldl/3, foldr/3, map/2]).
--import(ic_codegen, [emit/2, emit/3, emit/4, emit_c_enc_rpt/4, emit_c_dec_rpt/4]).
-
--include("icforms.hrl").
--include("ic.hrl").
--include_lib("stdlib/include/erl_compile.hrl").
-
--define(IC_HEADER, "ic.h").
--define(ERL_INTERFACEHEADER, "erl_interface.h").
--define(EICONVHEADER, "ei.h").
--define(OE_MSGBUFSIZE, "OE_MSGBUFSIZE").
--define(ERLANGATOMLENGTH, "256").
-
-%%------------------------------------------------------------
-%%
-%% Entry point
-%%
-%%------------------------------------------------------------
-do_gen(G, File, Form) ->
- OeName = ic_util:mk_oe_name(G, remove_ext(ic_util:to_list(File))),
- G2 = ic_file:filename_push(G, [], OeName, c_server),
- gen_headers(G2, [], Form),
- R = gen(G2, [], Form),
- ic_file:filename_pop(G2, c),
- R.
-
-remove_ext(File) ->
- filename:rootname(filename:basename(File)).
-
-%%------------------------------------------------------------
-%%
-%% Generate the server side C stub and header files.
-%%
-%% For each module a separate file is generated.
-%%
-%%
-%%------------------------------------------------------------
-
-gen(G, N, [X| Xs]) when is_record(X, preproc) ->
- NewG = change_file_stack(G, N, X#preproc.cat, X),
- gen(NewG, N, Xs);
-
-gen(G, N, [X| Xs]) when is_record(X, module) ->
- CD = ic_code:codeDirective(G, X),
- G2 = ic_file:filename_push(G, N, X, CD),
- N2 = [ic_forms:get_id2(X)| N],
- gen_headers(G2, N2, X),
- gen(G2, N2, ic_forms:get_body(X)),
- G3 = ic_file:filename_pop(G2, CD),
- gen(G3, N, Xs);
-
-gen(G, N, [X| Xs]) when is_record(X, interface) ->
- G2 = ic_file:filename_push(G, N, X, c_server),
- N2 = [ic_forms:get_id2(X)| N],
- gen_prototypes(G2, N2, X),
- gen_serv(G2, N2, X),
- G3 = ic_file:filename_pop(G2, c),
- gen(G3, N, Xs);
-
-gen(G, N, [X| Xs]) when is_record(X, const) ->
- emit_constant(G, N, X),
- gen(G, N, Xs);
-
-gen(G, N, [X| Xs]) when is_record(X, op) ->
- gen(G, N, Xs);
-
-gen(G, N, [X| Xs]) when is_record(X, attr) ->
- gen(G, N, Xs);
-
-gen(G, N, [X| Xs]) when is_record(X, except) ->
- icstruct:except_gen(G, N, X, c),
- gen(G, N, Xs);
-
-gen(G, N, [X| Xs]) when is_record(X, enum) ->
- icenum:enum_gen(G, N, X, c),
- gen(G, N, Xs);
-
-gen(G, N, [X| Xs]) when is_record(X, typedef) ->
- icstruct:struct_gen(G, N, X, c),
- gen(G, N, Xs);
-
-gen(G, N, [X| Xs]) when is_record(X, struct) ->
- icstruct:struct_gen(G, N, X, c),
- gen(G, N, Xs);
-
-gen(G, N, [X| Xs]) when is_record(X, union) ->
- icstruct:struct_gen(G, N, X, c),
- gen(G, N, Xs);
-
-gen(G, N, [_| Xs]) ->
- gen(G, N, Xs);
-
-gen(_G, _N, []) ->
- ok.
-
-%%------------------------------------------------------------
-%% Change file stack
-%%------------------------------------------------------------
-
-change_file_stack(G, _N, line_nr, X) ->
- Id = ic_forms:get_id2(X),
- Flags = X#preproc.aux,
- case Flags of
- [] -> ic_genobj:push_file(G, Id);
- _ ->
- foldr(
- fun({_, _, "1"}, G1) -> ic_genobj:push_file(G1, Id);
- ({_, _, "2"}, G1) -> ic_genobj:pop_file(G1, Id);
- ({_, _, "3"}, G1) -> ic_genobj:sys_file(G1, Id)
- end, G, Flags)
- end;
-change_file_stack(G, _N, _Other, _X) ->
- G.
-
-%%------------------------------------------------------------
-%% Generate headers
-%%------------------------------------------------------------
-
-%% Some items have extra includes
-gen_headers(G, N, X) when is_record(X, module) ->
- case ic_genobj:is_hrlfile_open(G) of
- true ->
- HFd = ic_genobj:hrlfiled(G),
- IncludeFileStack = ic_genobj:include_file_stack(G),
- Filename = lists:nth(length(N) + 1, IncludeFileStack),
- emit(HFd, "#include \"~s\"\n", [filename:basename(Filename)]),
- ic_code:gen_includes(HFd, G, X, c_server);
- false -> ok
- end;
-gen_headers(G, [], _X) ->
- case ic_genobj:is_hrlfile_open(G) of
- true ->
- HFd = ic_genobj:hrlfiled(G),
- emit(HFd, "#include <stdlib.h>\n"),
- case ic_options:get_opt(G, c_report) of
- true ->
- emit(HFd, "#ifndef OE_C_REPORT\n"),
- emit(HFd, "#define OE_C_REPORT\n"),
- emit(HFd, "#include <stdio.h>\n"),
- emit(HFd, "#endif\n");
- _ ->
- ok
- end,
- emit(HFd, "#include \"~s\"\n", [?IC_HEADER]),
- emit(HFd, "#include \"~s\"\n", [?ERL_INTERFACEHEADER]),
- emit(HFd, "#include \"~s\"\n", [?EICONVHEADER]),
- ic_code:gen_includes(HFd, G, c_server);
- false -> ok
- end;
-gen_headers(_G, _N, _X) ->
- ok.
-
-%%------------------------------------------------------------
-%% Generate prototypes
-%%------------------------------------------------------------
-
-gen_prototypes(G, N, X) ->
- case ic_genobj:is_hrlfile_open(G) of
- true ->
- HFd = ic_genobj:hrlfiled(G),
- IncludeFileStack = ic_genobj:include_file_stack(G),
- L = length(N),
- Filename =
- if
- L < 2 ->
- lists:nth(L + 1, IncludeFileStack);
- true ->
- lists:nth(2, IncludeFileStack)
- end,
-
- IName = ic_util:to_undersc(N),
- INameUC = ic_util:to_uppercase(IName),
-
- emit(HFd, "#include \"~s\"\n", [filename:basename(Filename)]),
- ic_code:gen_includes(HFd, G, X, c_server),
- ic_codegen:nl(HFd),
-
- emit(HFd, "\n#ifndef __~s__\n", [ic_util:to_uppercase(IName)]),
- emit(HFd, "#define __~s__\n", [ic_util:to_uppercase(IName)]),
- ic_codegen:mcomment_light(HFd,
- [io_lib:format("Interface "
- "object "
- "definition: ~s",
- [IName])], c),
- case get_c_timeout(G, "") of
- "" ->
- ok;
- {SendTmo, RecvTmo} ->
- emit(HFd, "#define OE_~s_SEND_TIMEOUT ~s\n",
- [INameUC, SendTmo]),
- emit(HFd, "#define OE_~s_RECV_TIMEOUT ~s\n",
- [INameUC, RecvTmo]),
- emit(HFd, "#ifndef EI_HAVE_TIMEOUT\n"),
- emit(HFd, "#error Functions for send and receive with "
- "timeout not defined in erl_interface\n"),
- emit(HFd, "#endif\n\n")
- end,
-
- emit(HFd, "typedef CORBA_Object ~s;\n\n", [IName]),
- emit(HFd, "#endif\n\n"),
-
- Bodies = [{N, ic_forms:get_body(X)}| X#interface.inherit_body],
-
- emit(HFd, "\n/* Structure definitions */\n", []),
- foreach(fun({N2, Body}) ->
- emit_structs_inside_module(G, HFd, N2, Body) end,
- Bodies),
-
- emit(HFd, "\n/* Switch and exec functions */\n", []),
- emit(HFd, "int ~s__switch(~s oe_obj, CORBA_Environment "
- "*oe_env);\n", [IName, IName]),
- foreach(fun({_N2, Body}) ->
- emit_exec_prototypes(G, HFd, N, Body) end,
- Bodies),
-
- emit(HFd, "\n/* Generic decoder */\n", []),
- emit(HFd, "int ~s__call_info(~s oe_obj, CORBA_Environment "
- "*oe_env);\n", [IName, IName]),
-
- emit(HFd, "\n/* Restore function typedefs */\n", []),
- foreach(fun({_N2, Body}) ->
- emit_restore_typedefs(G, HFd, N, Body) end,
- Bodies),
-
- emit(HFd, "\n/* Callback functions */\n", []),
- foreach(fun({_N2, Body}) ->
- emit_callback_prototypes(G, HFd, N, Body) end,
- Bodies),
-
- emit(HFd, "\n/* Parameter decoders */\n", []),
- foreach(fun({_N2, Body}) ->
- emit_decoder_prototypes(G, HFd, N, Body) end,
- Bodies),
-
- emit(HFd, "\n/* Message encoders */\n", []),
- foreach(fun({_N2, Body}) ->
- emit_encoder_prototypes(G, HFd, N, Body) end,
- Bodies),
-
- %% Emit operation mapping structures
- emit_operation_mapping_declaration(G, HFd, N, Bodies),
-
- ok;
-
- false ->
- ok
- end.
-
-%%------------------------------------------------------------
-%% Generate the server encoding/decoding function
-%%------------------------------------------------------------
-
-
-gen_serv(G, N, X) ->
- case ic_genobj:is_stubfile_open(G) of
- true ->
- Fd = ic_genobj:stubfiled(G),
-
- emit_switch(G, Fd, N, X),
- emit_server_generic_decoding(G, Fd, N),
-
- %% Sets the temporary variable counter.
- put(op_variable_count, 0),
- put(tmp_declarations, []),
-
- %% Generate exec, decode and encoding functions, and
- %% table of exec functions.
- Bodies = [{N, ic_forms:get_body(X)}|
- X#interface.inherit_body],
-
- foreach(fun({_N2, Body}) ->
- emit_dispatch(G, Fd, N, Body) end,
- Bodies),
- emit_operation_mapping(G, Fd, N, Bodies);
- false ->
- ok
- end.
-
-%%------------------------------------------------------------
-%% Emit structs inside module
-%%------------------------------------------------------------
-
-emit_structs_inside_module(G, _Fd, N, Xs)->
- lists:foreach(
- fun(X) when is_record(X, enum) ->
- icenum:enum_gen(G, N, X, c);
- (X) when is_record(X, typedef) ->
- icstruct:struct_gen(G, N, X, c);
- (X) when is_record(X, struct) ->
- icstruct:struct_gen(G, N, X, c);
- (X) when is_record(X, union) ->
- icstruct:struct_gen(G, N, X, c);
- (_) ->
- ok
- end, Xs).
-
-%%------------------------------------------------------------
-%% Emit exec prototypes
-%%------------------------------------------------------------
-
-emit_exec_prototypes(G, Fd, N, Xs) ->
- lists:foreach(
- fun(X) when is_record(X, op) ->
- {ScopedName, _, _} = ic_cbe:extract_info(G, N, X),
- emit(Fd,
- "int ~s__exec(~s oe_obj, CORBA_Environment *oe_env);\n",
- [ScopedName, ic_util:to_undersc(N)]);
- (X) when is_record(X, const) ->
- emit_constant(G, N, X);
- (_) ->
- ok
- end, Xs).
-
-%%------------------------------------------------------------
-%% Emit restore typedefs
-%%------------------------------------------------------------
-
-emit_restore_typedefs(G, Fd, N, [X| Xs]) when is_record(X, op) ->
- %% Check if to use scoped call names
- {ScopedName, ArgNames, Types} = ic_cbe:extract_info(G, N, X),
- {RetType, ParTypes, _} = Types,
- TypeAttrArgs = mk_type_attr_arg_list(ParTypes, ArgNames),
- RT = mk_c_ret_type(G, N, RetType),
-
- PL = ic_util:mk_list(mk_par_list_for_callback_prototypes(G, N, X,
- TypeAttrArgs)),
- RPL = case PL of
- "" ->
- "";
- _PL ->
- ", " ++ PL
- end,
-
- case RT of
- "void" ->
- case PL of
- "" ->
- emit(Fd, "typedef void (*~s__rs(~s oe_obj, "
- "CORBA_Environment *oe_env));\n",
- [ScopedName, ic_util:to_undersc(N)]);
- _ ->
- emit(Fd, "typedef void (*~s__rs(~s oe_obj, ~s, "
- "CORBA_Environment *oe_env));\n",
- [ScopedName, ic_util:to_undersc(N), PL])
- end;
-
- "erlang_port*" ->
- emit(Fd, "typedef void (*~s__rs(~s oe_obj, ~s~s, "
- "CORBA_Environment *oe_env));\n",
- [ScopedName, ic_util:to_undersc(N), RT, RPL]);
-
- "erlang_pid*" ->
- emit(Fd, "typedef void (*~s__rs(~s oe_obj, ~s~s, "
- "CORBA_Environment *oe_env));\n",
- [ScopedName, ic_util:to_undersc(N), RT, RPL]);
-
- "erlang_ref*" ->
- emit(Fd, "typedef void (*~s__rs(~s oe_obj, ~s~s, "
- "CORBA_Environment *oe_env));\n",
- [ScopedName, ic_util:to_undersc(N), RT, RPL]);
-
- _ ->
- case ictype:isArray(G, N, RetType) of
- true ->
- emit(Fd, "typedef void (*~s__rs(~s oe_obj, ~s~s, "
- "CORBA_Environment *oe_env));\n",
- [ScopedName, ic_util:to_undersc(N), RT, RPL]);
- false ->
- emit(Fd, "typedef void (*~s__rs(~s oe_obj, ~s*~s, "
- "CORBA_Environment *oe_env));\n",
- [ScopedName, ic_util:to_undersc(N), RT, RPL])
- end
- end,
- emit_restore_typedefs(G, Fd, N, Xs);
-emit_restore_typedefs(G, Fd, N, [X| Xs]) when is_record(X, attr) ->
- emit_restore_typedefs(G, Fd, N, Xs);
-emit_restore_typedefs(G, Fd, N, [_X| Xs]) ->
- emit_restore_typedefs(G, Fd, N, Xs);
-emit_restore_typedefs(_G, _Fd, _N, []) -> ok.
-
-
-%%------------------------------------------------------------
-%% Emit call-back prototypes
-%%------------------------------------------------------------
-
-emit_callback_prototypes(G, Fd, N, [X| Xs]) when is_record(X, op) ->
- %% Check scoped names XXX
- {ScopedName, ArgNames, Types} = ic_cbe:extract_info(G, N, X),
- {RetType, ParTypes, _} = Types,
- TypeAttrArgs = mk_type_attr_arg_list(ParTypes, ArgNames),
- RT = mk_c_ret_type(G, N, RetType),
-
- PL = ic_util:mk_list(mk_par_list_for_callback_prototypes(G, N, X,
- TypeAttrArgs)),
- CBPL = case PL of
- "" ->
- "";
- _PL ->
- ", " ++ PL
- end,
- case RT of
- "void" ->
- case PL of
- "" ->
- emit(Fd, "~s__rs* ~s__cb(~s oe_obj, "
- "CORBA_Environment *oe_env);\n",
- [ScopedName, ScopedName, ic_util:to_undersc(N)]);
- _ ->
- emit(Fd, "~s__rs* ~s__cb(~s oe_obj, ~s, "
- "CORBA_Environment *oe_env);\n",
- [ScopedName, ScopedName, ic_util:to_undersc(N), PL])
- end;
- "erlang_port*" ->
- emit(Fd, "~s__rs* ~s__cb(~s oe_obj, ~s~s, "
- "CORBA_Environment *oe_env);\n",
- [ScopedName, ScopedName, ic_util:to_undersc(N), RT, CBPL]);
-
- "erlang_pid*" ->
- emit(Fd, "~s__rs* ~s__cb(~s oe_obj, ~s~s, "
- "CORBA_Environment *oe_env);\n",
- [ScopedName, ScopedName, ic_util:to_undersc(N), RT, CBPL]);
-
- "erlang_ref*" ->
- emit(Fd, "~s__rs* ~s__cb(~s oe_obj, ~s~s, "
- "CORBA_Environment *oe_env);\n",
- [ScopedName, ScopedName, ic_util:to_undersc(N), RT, CBPL]);
-
- _ ->
- case ictype:isArray(G, N, RetType) of
- true ->
- emit(Fd, "~s__rs* ~s__cb(~s oe_obj, ~s~s, "
- "CORBA_Environment *oe_env);\n",
- [ScopedName, ScopedName, ic_util:to_undersc(N), RT,
- CBPL]);
- false ->
- emit(Fd, "~s__rs* ~s__cb(~s oe_obj, ~s*~s, "
- "CORBA_Environment *oe_env);\n",
- [ScopedName, ScopedName, ic_util:to_undersc(N), RT,
- CBPL])
- end
- end,
- emit_callback_prototypes(G, Fd, N, Xs);
-emit_callback_prototypes(G, Fd, N, [X| Xs]) when is_record(X, attr) ->
- emit_callback_prototypes(G, Fd, N, Xs);
-emit_callback_prototypes(G, Fd, N, [_X| Xs]) ->
- emit_callback_prototypes(G, Fd, N, Xs);
-emit_callback_prototypes(_G, _Fd, _N, []) -> ok.
-
-%%------------------------------------------------------------
-%% Emit decoder prototypes
-%%------------------------------------------------------------
-
-emit_decoder_prototypes(G, Fd, N, [X| Xs]) when is_record(X, op) ->
- %% Check if to use scoped call names
- {ScopedName, ArgNames, Types} = ic_cbe:extract_info(G, N, X),
- {_RetType, ParTypes, _} = Types,
- TypeAttrArgs = mk_type_attr_arg_list(ParTypes, ArgNames),
- case ic_util:mk_list(mk_par_list_for_decoder_prototypes(G, N, X,
- TypeAttrArgs)) of
- "" ->
- ok;
- PLFDP ->
- emit(Fd, "int ~s__dec(~s oe_obj, ~s, CORBA_Environment "
- "*oe_env);\n",
- [ScopedName, ic_util:to_undersc(N), PLFDP])
- end,
- emit_decoder_prototypes(G, Fd, N, Xs);
-emit_decoder_prototypes(G, Fd, N, [X| Xs]) when is_record(X, attr) ->
- emit_decoder_prototypes(G, Fd, N, Xs);
-emit_decoder_prototypes(G, Fd, N, [_X| Xs]) ->
- emit_decoder_prototypes(G, Fd, N, Xs);
-emit_decoder_prototypes(_G, _Fd, _N, []) -> ok.
-
-
-%%------------------------------------------------------------
-%% Emit encoder prototypes
-%%------------------------------------------------------------
-
-emit_encoder_prototypes(G, Fd, N, [X| Xs]) when is_record(X, op) ->
- case ic_forms:is_oneway(X) of
- true ->
- emit_encoder_prototypes(G, Fd, N, Xs);
- false ->
- %% Check if to use scoped call names
- {ScopedName, ArgNames, Types} = ic_cbe:extract_info(G, N, X),
- {RetType, ParTypes, _} = Types,
- TypeAttrArgs = mk_type_attr_arg_list(ParTypes, ArgNames),
- RType = mk_c_ret_type(G, N, RetType),
- case ic_util:mk_list(mk_par_list_for_encoder_prototypes(
- G, N, X, TypeAttrArgs)) of
- "" ->
- case RType of
- "void" ->
- emit(Fd, "int ~s__enc(~s oe_obj, "
- "CORBA_Environment *oe_env);\n",
- [ScopedName, ic_util:to_undersc(N)]);
- _ ->
- emit(Fd, "int ~s__enc(~s oe_obj, ~s, "
- "CORBA_Environment *oe_env);\n",
- [ScopedName, ic_util:to_undersc(N), RType])
- end;
- PLFEP ->
- case RType of
- "void" ->
- emit(Fd, "int ~s__enc(~s oe_obj, ~s, "
- "CORBA_Environment *oe_env);\n",
- [ScopedName, ic_util:to_undersc(N), PLFEP]);
- _ ->
- emit(Fd, "int ~s__enc(~s oe_obj, ~s, ~s, "
- "CORBA_Environment *oe_env);\n",
- [ScopedName, ic_util:to_undersc(N), RType,
- PLFEP])
- end
- end,
- emit_encoder_prototypes(G, Fd, N, Xs)
- end;
-emit_encoder_prototypes(G, Fd, N, [X| Xs]) when is_record(X, attr) ->
- emit_encoder_prototypes(G, Fd, N, Xs);
-emit_encoder_prototypes(G, Fd, N, [_X| Xs]) ->
- emit_encoder_prototypes(G, Fd, N, Xs);
-emit_encoder_prototypes(_G, _Fd, _N, []) -> ok.
-
-%%------------------------------------------------------------
-%% Emit operation mapping declaration
-%%------------------------------------------------------------
-
-emit_operation_mapping_declaration(G, Fd, N, Bodies) ->
- Interface = ic_util:to_undersc(N),
- Length = erlang:length(get_all_opnames(G, N, Bodies)),
- emit(Fd, "\n/* Operation mapping */\n", []),
- emit(Fd, "extern oe_map_t oe_~s_map;\n", [Interface]),
- emit(Fd, "/* For backward compatibility */\n"),
- emit(Fd, "#define ___~s_map___ oe_~s_map\n",
- [Interface, Interface]),
- case Length of
- 0 ->
- ok;
- _ ->
- emit(Fd, "extern oe_operation_t oe_~s_operations[];\n",
- [Interface]),
- emit(Fd, "/* For backward compatibility */\n"),
- emit(Fd, "#define ___~s_operations___ oe_~s_operations\n",
- [Interface, Interface])
- end.
-
-
-%% Returns a list of {OpName, ScopedOpName} for all operations, where
-%% OpName == ScopedOpName in case the `scoped_op_calls' option has
-%% been set.
-%%
-get_all_opnames(G, N, Bodies) ->
- ScNF = fun(X) ->
- {ScName, _, _} = ic_cbe:extract_info(G, N, X),
- ScName
- end,
- NF = case ic_options:get_opt(G, scoped_op_calls) of
- true ->
- ScNF;
- false ->
- fun(X) -> ic_forms:get_id2(X) end
- end,
- Filter = fun(X) when is_record(X, op) ->
- {true, {NF(X), ScNF(X)}};
- (_) ->
- false
- end,
- %% zf == filtermap
- lists:flatmap(fun({_, Xs}) -> lists:zf(Filter, Xs) end, Bodies).
-
-%%------------------------------------------------------------
-%% Emit switch
-%%------------------------------------------------------------
-
-emit_switch(G, Fd, N, _X) ->
- emit(Fd, "#include <string.h>\n"),
- case ic_options:get_opt(G, c_report) of
- true ->
- emit(Fd, "#ifndef OE_C_REPORT\n"),
- emit(Fd, "#define OE_C_REPORT\n"),
- emit(Fd, "#include <stdio.h>\n"),
- emit(Fd, "#endif\n");
- _ ->
- ok
- end,
- StartCode =
- "#include \"ic.h\"\n"
- "#include \"erl_interface.h\"\n"
- "#include \"ei.h\"\n"
- "#include \"~s__s.h\"\n\n"
- "/*\n"
- " * Main switch\n"
- " */\n\n"
- "int ~s__switch(~s oe_obj, CORBA_Environment *oe_env)\n"
- "{\n"
- " return oe_exec_switch(oe_obj, oe_env, &oe_~s_map);\n"
- "}\n\n",
- ScopedName = ic_util:to_undersc(N),
- emit(Fd, StartCode, [ScopedName, ScopedName, ScopedName, ScopedName]).
-
-%%------------------------------------------------------------
-%% Emit server generic decoding.
-%%------------------------------------------------------------
-
-emit_server_generic_decoding(G, Fd, N) ->
- UserProto = get_user_proto(G, oe),
- Code =
- "/*\n"
- " * Returns call identity (left only for backward compatibility)\n"
- " */\n\n"
- "int ~s__call_info(~s oe_obj, CORBA_Environment *oe_env)\n"
- "{\n"
- " return ~s_prepare_request_decoding(oe_env);\n"
- "}\n\n",
- IName = ic_util:to_undersc(N),
- emit(Fd, Code, [IName, IName, UserProto]).
-
-%%------------------------------------------------------------
-%% Emit dispatch
-%%------------------------------------------------------------
-
-emit_dispatch(G, Fd, N, Xs) ->
- lists:foreach(
- fun(X) when is_record(X, op) ->
- {Name, ArgNames, Types} = ic_cbe:extract_info(G, N, X),
- {RetType, ParTypes, _} = Types,
- TypeAttrArgs = mk_type_attr_arg_list(ParTypes, ArgNames),
- emit_exec_function(G, Fd, N, X, Name, RetType, TypeAttrArgs),
- emit_parameter_decoder(G, Fd, N, X, Name, RetType, TypeAttrArgs),
- emit_message_encoder(G, Fd, N, X, Name, RetType, TypeAttrArgs);
- (_) ->
- ok
- end, Xs).
-
-%%------------------------------------------------------------
-%% Emit operation mapping
-%%------------------------------------------------------------
-
-emit_operation_mapping(G, Fd, N, Bodies) ->
- OpNames = get_all_opnames(G, N, Bodies),
- Interface = ic_util:to_undersc(N),
- Length = erlang:length(OpNames),
- emit(Fd, "\n/* Operation mapping */\n\n", []),
- case Length of
- 0 ->
- emit(Fd, "oe_map_t oe_~s_map = { 0, NULL };\n\n", [Interface]);
- _ ->
- emit(Fd, "\noe_operation_t oe_~s_operations[~p] = {\n",
- [Interface, Length]),
- Members = lists:map(
- fun({OpN, ScOpN}) ->
- Name = ic_util:to_undersc([OpN]),
- ScName = ic_util:to_undersc([ScOpN]),
- io_lib:fwrite(" {~p, ~p, ~s__exec}",
- [Interface, Name, ScName])
- end, OpNames),
- emit(Fd, ic_util:join(Members, ",\n")),
- emit(Fd, "};\n\n", []),
- emit(Fd, "oe_map_t oe_~s_map = "
- "{~p, oe_~s_operations};\n\n",
- [Interface, Length, Interface])
- end.
-
-%%------------------------------------------------------------
-%% Emit constant
-%%------------------------------------------------------------
-
-emit_constant(G, N, ConstRecord) ->
- case ic_genobj:is_hrlfile_open(G) of
- false -> ok;
- true ->
- Fd = ic_genobj:hrlfiled(G),
- CName = ic_util:to_undersc(
- [ic_forms:get_id(ConstRecord#const.id)| N]),
- UCName = ic_util:to_uppercase(CName),
-
- emit(Fd, "\n#ifndef __~s__\n", [UCName]),
- emit(Fd, "#define __~s__\n\n", [UCName]),
-
- emit(Fd, "/* Constant: ~s */\n", [CName]),
-
- if is_record(ConstRecord#const.type, wstring) ->
- %% If wstring, add 'L'
- emit(Fd, "#define ~s L~p\n\n", [CName,
- ConstRecord#const.val]);
- true ->
- emit(Fd, "#define ~s ~p\n\n", [CName,
- ConstRecord#const.val])
- end,
-
- emit(Fd, "#endif\n\n")
- end.
-
-%%------------------------------------------------------------
-%% Emit exec function
-%%------------------------------------------------------------
-
-emit_exec_function(G, Fd, N, X, Name, RetType, TypeAttrArgs) ->
- %% Decoding operation specific part
- InTypeAttrArgs = lists:filter(fun({_, in, _}) -> true;
- ({_, _, _}) -> false
- end, TypeAttrArgs),
- ic_codegen:nl(Fd),
-
- emit(Fd,
- "int ~s__exec(~s oe_obj, CORBA_Environment *oe_env)\n"
- "{\n",
- [Name, ic_util:to_undersc(N)]),
-
- emit(Fd, " if (oe_env->_received != ~p) {\n", [length(InTypeAttrArgs)]),
- emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, BAD_PARAM, "
- "\"Wrong number of operation parameters\");\n"),
- emit_c_dec_rpt(Fd, " ", "wrong number of parameters", []),
- emit_c_dec_rpt(Fd, " ", "server exec ~s\\n====\\n", [Name]),
- emit(Fd, " return -1;\n", []),
- emit(Fd, " }\n"),
- emit(Fd, " else {\n", []),
-
- case InTypeAttrArgs of
- [] ->
- true;
- _ ->
- emit(Fd, " int oe_error_code = 0;\n")
- end,
-
- %% Callback variable definition
- emit_variable_defs(G, Fd, N, X, Name, RetType, TypeAttrArgs),
-
- %% Call to parameter decoder
- emit_parameter_decoder_call(G, Fd, N, X, Name, RetType, TypeAttrArgs),
-
- %% Callback to user code
- emit_callback(G, Fd, N, X, Name, RetType, TypeAttrArgs),
-
- %% Call to return message encoder
- case ic_forms:is_oneway(X) of
- true ->
- true;
- false ->
- emit_message_encoder_call(G, Fd, N, X, Name, RetType, TypeAttrArgs)
- end,
-
- %% Restore function call
- emit_restore(G, Fd, N, X, Name, RetType, TypeAttrArgs),
-
- emit(Fd, " }\n return 0;\n}\n\n").
-
-%%------------------------------------------------------------
-%% Emit parameter decoder
-%%------------------------------------------------------------
-
-emit_parameter_decoder(G, Fd, N, X, Name, _RetType, TypeAttrArgs) ->
- %% Decoding operation specific part
- InTypeAttrArgs =
- lists:filter(fun({_, in, _}) -> true;
- ({_, _, _}) -> false
- end, TypeAttrArgs),
- case InTypeAttrArgs of
- [] ->
- ok;
- _ ->
- case ic_util:mk_list(mk_par_list_for_decoder(G, N, X,
- TypeAttrArgs)) of
- "" ->
- emit(Fd, "int ~s__dec(~s oe_obj, CORBA_Environment "
- "*oe_env)\n{\n int oe_error_code;\n\n",
- [Name, ic_util:to_undersc(N)]);
- PLFD ->
- emit(Fd, "int ~s__dec(~s oe_obj, ~s, CORBA_Environment "
- "*oe_env)\n{\n",
- [Name, ic_util:to_undersc(N), PLFD]),
- emit(Fd, " int oe_error_code;\n\n")
- end,
-
- APars = [], % XXX Alloced parameters
- foldl(
- fun({{'void', _}, _, _}, _Acc) ->
- ok;
- ({T1, A1, N1}, Acc) ->
- emit_one_decoding(G, N, Fd, T1, A1, N1, Acc)
- end, APars, InTypeAttrArgs),
-
- emit(Fd, " return 0;\n}\n\n")
- end.
-
-%%------------------------------------------------------------
-%% Emit one decoding
-%%------------------------------------------------------------
-
-emit_one_decoding(G, N, Fd, T1, A1, N1, AllocedPars) ->
- IndOp = mk_ind_op(A1),
- case ic_cbe:is_variable_size(G, N, T1) of
- false ->
- %% The last parameter "oe_outindex" is not used in
- %% the static case but must be there anyhow.
- emit_decoding_stmt(G, N, Fd, T1,
- N1, "", "oe_env->_inbuf", 1, "&oe_outindex",
- caller, AllocedPars),
- ic_codegen:nl(Fd),
- AllocedPars;
- true ->
- emit_encoding_comment(G, N, Fd, "Decode", IndOp, T1, N1),
- emit(Fd, " {\n"),
- emit(Fd, " int oe_size_count_index = oe_env->_iin;\n"),
- emit(Fd, " int oe_malloc_size = 0;\n"),
- emit(Fd, " void *oe_first = NULL;\n"),
- ic_cbe:emit_malloc_size_stmt(G, N, Fd, T1,
- "oe_env->_inbuf", 1, caller),
- %% This is the only malloc call in this file
- emit(Fd,
- " OE_MALLOC_SIZE_CHECK(oe_env, oe_malloc_size);\n"
- " if ((*~s = oe_first = "
- "malloc(oe_malloc_size)) == NULL) {\n", [N1]),
- ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars),
- emit(Fd,
- " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, "
- "NO_MEMORY, \"Cannot malloc\");\n"
- " return -1;\n"
- " }\n"),
- ParName = "*" ++ N1, % XXX Why not IndOp?
- NAllocedPars = [ParName| AllocedPars],
- case ictype:isArray(G, N, T1) of
- true ->
- emit_decoding_stmt(G, N, Fd, T1,
- "(*" ++ IndOp ++ N1 ++ ")", "",
- "oe_env->_inbuf", 1, "&oe_outindex",
- array_dyn, NAllocedPars);
- false ->
- emit_decoding_stmt(G, N, Fd, T1,
- "(*" ++ IndOp ++ N1 ++ ")", "",
- "oe_env->_inbuf", 1, "&oe_outindex",
- caller_dyn, NAllocedPars)
- end,
- emit(Fd, " }\n\n"),
- NAllocedPars
- end.
-
-%%------------------------------------------------------------
-%% Emit message encoder
-%%------------------------------------------------------------
-
-emit_message_encoder(G, Fd, N, X, Name, RetType, TypeAttrArgs) ->
- case ic_forms:is_oneway(X) of
- false ->
- %% Encoding operation specific part
- emit(Fd,
- "\nint ~s__enc(~s oe_obj",
- [Name, ic_util:to_undersc(N)]),
- RType = mk_c_ret_type(G, N, RetType),
- ParList = mk_par_list_for_encoder(G, N, X, TypeAttrArgs),
- case ic_util:mk_list(ParList) of
- "" ->
- case RType of
- "void" ->
- emit(Fd, ", CORBA_Environment *oe_env)\n{");
- _ ->
- emit(Fd, ", ~s oe_return, CORBA_Environment "
- "*oe_env)\n{", [RType])
- end;
- PLFD ->
- case RType of
- "void" ->
- emit(Fd, ", ~s, CORBA_Environment "
- "*oe_env)\n{", [PLFD]);
- _ ->
- emit(Fd, ", ~s oe_return~s, CORBA_Environment "
- "*oe_env)\n{", [RType, ", " ++ PLFD])
- end
- end,
-
-
- emit(Fd, "\n"),
- emit(Fd, " int oe_error_code;\n\n"),
- UserProto = get_user_proto(G, oe),
- emit(Fd, " ~s_prepare_reply_encoding(oe_env);\n", [UserProto]),
-
- OutTypeAttrArgs =
- lists:filter(fun({_, out, _}) -> true;
- ({_, _, _}) -> false
- end, TypeAttrArgs),
-
- OutLength = length(OutTypeAttrArgs),
- case OutLength > 0 of
- false ->
- ic_codegen:nl(Fd);
- true ->
- emit(Fd, " oe_ei_encode_tuple_header(oe_env, ~p);\n\n",
- [OutLength+1])
-
- end,
-
- emit_encoding_comment(G, N, Fd, "Encode", "", RetType,
- "oe_return"),
- emit_encoding_stmt(G, N, X, Fd, RetType, "oe_return"),
-
- foreach(fun({T1, _A1, N1}) ->
- case T1 of
- {'void', _} ->
- ok;
- _ ->
- emit_encoding_comment(G, N, Fd, "Encode",
- "", T1, N1),
- emit_encoding_stmt(G, N, X, Fd, T1, N1)
- end
- end, OutTypeAttrArgs),
- emit(Fd, " return 0;\n}\n\n");
- _ ->
- %% Oneway
- ok
- end.
-
-%%------------------------------------------------------------
-%% Emit message encoder call
-%%------------------------------------------------------------
-
-emit_message_encoder_call(G, Fd, N, X, Name, RetType, TypeAttrArgs) ->
- emit(Fd, " /* Encoding reply message */\n"),
- RType = mk_c_ret_type(G, N, RetType),
- case ic_util:mk_list(mk_enc_par_list(G, N, X, TypeAttrArgs)) of
- "" ->
- case RType of
- "void" ->
- emit(Fd, " ~s(oe_obj, oe_env);\n",
- [Name ++ "__enc"]);
- "erlang_pid*" ->
- emit(Fd, " ~s(oe_obj, &oe_return, oe_env);\n",
- [Name ++ "__enc"]);
- "erlang_port*" ->
- emit(Fd, " ~s(oe_obj, &oe_return, oe_env);\n",
- [Name ++ "__enc"]);
- "erlang_ref*" ->
- emit(Fd, " ~s(oe_obj, &oe_return, oe_env);\n",
- [Name ++ "__enc"]);
- _ ->
- emit(Fd, " ~s(oe_obj, oe_return, oe_env);\n",
- [Name ++ "__enc"])
- end;
-
- PLFE ->
- case RType of
- "void" ->
- emit(Fd, " ~s(oe_obj, ~s, oe_env);\n",
- [Name ++ "__enc", PLFE]);
- "erlang_pid*" ->
- emit(Fd, " ~s(oe_obj, &oe_return, ~s, oe_env);\n",
- [Name ++ "__enc", PLFE]);
- "erlang_port*" ->
- emit(Fd, " ~s(oe_obj, &oe_return, ~s, oe_env);\n",
- [Name ++ "__enc", PLFE]);
- "erlang_ref*" ->
- emit(Fd, " ~s(oe_obj, &oe_return, ~s, oe_env);\n",
- [Name ++ "__enc", PLFE]);
- _ ->
- emit(Fd, " ~s(oe_obj, oe_return, ~s, oe_env);\n",
- [Name ++ "__enc", PLFE])
- end
- end,
- ic_codegen:nl(Fd).
-
-%%------------------------------------------------------------
-%% Emit parameter decoding call
-%%------------------------------------------------------------
-
-emit_parameter_decoder_call(G, Fd, N, X, Name, _R, TypeAttrArgs) ->
- case ic_util:mk_list(mk_dec_par_list(G, N, X, TypeAttrArgs)) of
- "" -> %% No parameters ! skip it !
- ok;
- PLFDC ->
- ParDecName = Name ++ "__dec",
- emit(Fd,
- " /* Decode parameters */\n"
- " if((oe_error_code = ~s(oe_obj, ~s, oe_env)) < 0) {\n",
- [ParDecName, PLFDC]),
- emit_c_dec_rpt(Fd, " ", "parmeters", []),
- emit(Fd,
- " if(oe_env->_major == CORBA_NO_EXCEPTION)\n"
- " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad parameter on decode\");\n"
- " return oe_error_code;\n }\n\n")
- end.
-
-%%------------------------------------------------------------
-%% Emit call-back
-%%------------------------------------------------------------
-
-emit_callback(G, Fd, N, X, Name, RetType, TypeAttrArgs) ->
- CallBackName = Name ++ "__cb",
- emit(Fd, " /* Callback function call */\n"),
- PL = ic_util:mk_list(mk_cb_par_list(G, N, X, TypeAttrArgs)),
- case ic_forms:is_oneway(X) of
- true ->
- case PL of
- "" ->
- emit(Fd, " oe_restore = ~s(oe_obj, oe_env);\n\n",
- [CallBackName]);
- _ ->
- emit(Fd, " oe_restore = ~s(oe_obj, ~s, oe_env);\n\n",
- [CallBackName, PL])
- end;
- false ->
- CBPL = case PL of
- "" ->
- "";
- _PL ->
- ", " ++ PL
- end,
- case mk_c_ret_type(G, N, RetType) of
- "void" ->
- case PL of
- "" ->
- emit(Fd, " oe_restore = ~s(oe_obj, oe_env);"
- "\n\n", [CallBackName]);
- _ ->
- emit(Fd, " oe_restore = ~s(oe_obj, ~s, oe_env);"
- "\n\n", [CallBackName, PL])
- end;
- _ ->
- case ictype:isArray(G, N, RetType) of
- true ->
- emit(Fd,
- " oe_restore = ~s(oe_obj, oe_return~s, "
- " oe_env);\n\n", [CallBackName, CBPL]);
- false ->
- emit(Fd, " oe_restore = ~s(oe_obj, "
- "&oe_return~s, oe_env);\n\n",
- [CallBackName, CBPL])
- end
- end
- end.
-
-%%------------------------------------------------------------
-%% Emit restore
-%%------------------------------------------------------------
-
-emit_restore(G, Fd, N, X, _Name, RetType, TypeAttrArgs) ->
- emit(Fd, " /* Restore function call */\n"),
- emit(Fd, " if (oe_restore != NULL)\n"),
- PL = ic_util:mk_list(mk_cb_par_list(G, N, X, TypeAttrArgs)),
- case ic_forms:is_oneway(X) of
- true ->
- case PL of
- "" ->
- emit(Fd, " (*oe_restore)(oe_obj, oe_env);\n\n");
- _ ->
- emit(Fd, " (*oe_restore)(oe_obj, ~s, oe_env);\n\n",
- [PL])
- end;
- false ->
- RPL = case PL of
- "" ->
- "";
- _PL ->
- ", " ++ PL
- end,
- case mk_c_ret_type(G, N, RetType) of
- "void" ->
- case PL of
- "" ->
- emit(Fd, " (*oe_restore)(oe_obj, oe_env);"
- "\n\n");
- _ ->
- emit(Fd, " (*oe_restore)(oe_obj, ~s, oe_env);"
- "\n\n", [PL])
- end;
- _ ->
- case ictype:isArray(G, N, RetType) of
- true ->
- emit(Fd,
- " (*oe_restore)(oe_obj, oe_return~s, "
- " oe_env);\n\n", [RPL]);
- false ->
- emit(Fd, " (*oe_restore)(oe_obj, "
- "&oe_return~s, oe_env);\n\n", [RPL])
- end
- end
- end.
-
-%%------------------------------------------------------------
-%% Emit variable defs
-%%------------------------------------------------------------
-
-emit_variable_defs(G, Fd, N, X, _Name, RetType, TypeAttrArgs) ->
- {ScopedName, _, _} = ic_cbe:extract_info(G, N, X),
- emit(Fd, " ~s__rs* oe_restore = NULL;\n", [ScopedName]),
- RestVars = mk_var_list(mk_var_decl_list(G, N, X, TypeAttrArgs)),
- case ic_forms:is_oneway(X) of
- true ->
- emit(Fd, "~s\n\n", [RestVars]);
- false ->
- RType = mk_c_ret_type(G, N, RetType),
- case RType of
- "void" ->
- emit(Fd, "~s\n\n", [RestVars]);
- "CORBA_unsigned_long" ->
- emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]);
- "CORBA_unsigned_long_long" ->
- emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]);
- "CORBA_unsigned_short" ->
- emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]);
- "CORBA_short" ->
- emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]);
- "CORBA_long" ->
- emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]);
- "CORBA_long_long" ->
- emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]);
- "CORBA_float" ->
- emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]);
- "CORBA_double" ->
- emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]);
- "CORBA_char" ->
- emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]);
- "CORBA_wchar" -> %% WCHAR
- emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]);
- "CORBA_boolean" ->
- emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]);
- "CORBA_octet" ->
- emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]);
- _ ->
- case ic_cbe:is_variable_size(G, N, RetType) of
- true ->
- emit(Fd, "~s ~s oe_return;\n\n",
- [RestVars, RType]);
- false ->
- TK = ic_forms:get_tk(X),
- case TK of
- {tk_enum, _, _, _List} ->
- emit(Fd, "~s ~s oe_return;\n\n",
- [RestVars, RType]);
- _ ->
- case RType of
- "erlang_binary*" ->
- emit(Fd, "~s erlang_binary "
- "oe_return;\n\n", [RestVars]);
- "erlang_pid*" ->
- emit(Fd, "~s erlang_pid "
- "oe_return;\n\n", [RestVars]);
- "erlang_port*" ->
- emit(Fd, "~s erlang_port "
- "oe_return;\n\n", [RestVars]);
- "erlang_ref*" ->
- emit(Fd, "~s erlang_ref "
- "oe_return;\n\n", [RestVars]);
- _ ->
- %% Structures are
- %% initiated by memset
- emit(Fd, "~s ~s "
- "oe_return;\n\n",
- [RestVars, RType])
- end,
- emit(Fd, " memset(&oe_return, 0, "
- "sizeof(oe_return));\n\n")
- end
- end
- end
- end.
-
-%%------------------------------------------------------------
-%% Make variable list
-%%------------------------------------------------------------
-
-%% XXX Modify
-mk_var_list([]) ->
- "";
-mk_var_list([Arg| Args]) ->
- " " ++ Arg ++ ";\n" ++ mk_var_list(Args).
-
-%%------------------------------------------------------------
-%% Make return type
-%%------------------------------------------------------------
-
-mk_c_ret_type(G, N, Type) ->
- Ctype = mk_c_type(G, N, Type),
- Dyn = case ic_cbe:is_variable_size(G, N, Type) of
- true ->
- if
- is_record(Type, string) ->
- "*";
- Ctype == "CORBA_char *" ->
- "";
- is_record(Type, wstring) -> %% WSTRING
- "*";
- Ctype == "CORBA_wchar *" -> %% WSTRING
- "";
- true ->
- case ictype:isArray(G, N, Type) of
- true ->
- "";
- _ ->
- "*"
- end
- end;
- false ->
- if
- Ctype == "erlang_pid" ->
- "*";
- Ctype == "erlang_port" ->
- "*";
- Ctype == "erlang_ref" ->
- "*";
- true ->
- ""
- end
- end,
- Ctype ++ Dyn.
-
-%%------------------------------------------------------------
-%% Make call-back parameter list
-%%------------------------------------------------------------
-
-mk_cb_par_list(G, N, X, TypeAttrArgs0) ->
- TypeAttrArgs1 = filter_type_attr_arg_list(G, X, [in, out], TypeAttrArgs0),
- lists:map(
- fun({Type, Attr, Arg}) ->
- case ic_cbe:is_variable_size(G, N, Type) of
- true ->
- case Attr of
- in ->
- Arg;
- out ->
- case ictype:isArray(G, N, Type) of
- true ->
- Arg;
- _ ->
- "&" ++ Arg
- end
- end;
- false ->
- case ictype:isArray(G, N, Type) of
- true ->
- Arg;
- _ ->
- "&" ++ Arg
- end
- end
- end, TypeAttrArgs1).
-
-%%------------------------------------------------------------
-%% Make decoder parameter list
-%%------------------------------------------------------------
-
-mk_dec_par_list(G, N, X, TypeAttrArgs0) ->
- TypeAttrArgs1 = filter_type_attr_arg_list(G, X, [in],
- TypeAttrArgs0),
- lists:map(
- fun({Type, _Attr, Arg}) ->
- Ctype = mk_c_type(G, N, Type),
- case ic_cbe:is_variable_size(G, N, Type) of
- true ->
- if
- is_record(Type, string) ->
- "&" ++ Arg;
- Ctype == "CORBA_char *" ->
- Arg;
- is_record(Type, wstring) ->
- "&" ++ Arg;
- Ctype == "CORBA_wchar *" ->
- Arg;
- true ->
- "&" ++ Arg
- end;
- false ->
- case ictype:isArray(G, N, Type) of
- true ->
- Arg;
- _ ->
- "&" ++ Arg
- end
- end
- end, TypeAttrArgs1).
-
-%%------------------------------------------------------------
-%% Make encoder parameter list
-%%------------------------------------------------------------
-
-mk_enc_par_list(G, N, X, TypeAttrArgs0) ->
- TypeAttrArgs1 = filter_type_attr_arg_list(G, X, [out],
- TypeAttrArgs0),
- lists:map(
- fun({Type, _Attr, Arg}) ->
- Ctype = mk_c_type(G, N, Type),
- case Ctype of
- "erlang_pid" ->
- "&" ++ Arg;
- "erlang_port" ->
- "&" ++ Arg;
- "erlang_ref" ->
- "&" ++ Arg;
- _ ->
- Arg
- end
- end, TypeAttrArgs1).
-
-%%------------------------------------------------------------
-%% Make type argument list
-%%------------------------------------------------------------
-
-mk_type_attr_arg_list(Types, Args) ->
- filterzip(
- fun(Type, {Attr, Arg}) ->
- {true, {Type, Attr, Arg}}
- end, Types, Args).
-
-%%------------------------------------------------------------
-%% Filter type argument list
-%%------------------------------------------------------------
-
-filter_type_attr_arg_list(G, X, InOrOut, TypeAttrArgs) ->
- lists:filter(
-
- fun({_Type, inout, Arg}) ->
- ic_error:error(G, {inout_spec_for_c, X, Arg}),
- false;
- ({_Type, Attr, _Arg}) ->
- lists:member(Attr, InOrOut)
- end, TypeAttrArgs).
-
-%%------------------------------------------------------------
-%% Make indirection operator
-%%------------------------------------------------------------
-
-mk_ind_op(in) ->
- "";
-mk_ind_op(inout) ->
- error;
-mk_ind_op(_) ->
- "*".
-
-%%------------------------------------------------------------
-%% Make parameter list for decoder
-%%------------------------------------------------------------
-
-mk_par_list_for_decoder(G, N, X, TypeAttrArgs0) ->
- TypeAttrArgs1 = filter_type_attr_arg_list(G, X, [in], TypeAttrArgs0),
- lists:map(
- fun({Type, Attr, Arg}) ->
- Ctype = mk_c_type(G, N, Type),
- Dyn = case ic_cbe:is_variable_size(G, N, Type) of
- true ->
- if
- is_record(Type, string) ->
- "**";
- Ctype == "CORBA_char *" ->
- "";
- is_record(Type, wstring) -> %% WSTRING
- "**";
- Ctype == "CORBA_wchar *" -> %% WSTRING
- "";
- true ->
- case ictype:isArray(G, N, Type) of
- true ->
- slice(Attr) ++ "*";
- _ ->
- "**"
- end
- end;
- false ->
- case ictype:isArray(G, N, Type) of
- true ->
- "";
- _ ->
- "*"
- end
- end,
- Ctype ++ Dyn ++ " " ++ Arg
- end, TypeAttrArgs1).
-
-%%------------------------------------------------------------
-%% Make parameter list for encoder
-%%------------------------------------------------------------
-
-mk_par_list_for_encoder(G, N, X, TypeAttrArgs0) ->
- TypeAttrArgs1 = filter_type_attr_arg_list(G, X, [out], TypeAttrArgs0),
- lists:map(
- fun({Type, _Attr, Arg}) ->
- Ctype = mk_c_type(G, N, Type),
- Dyn = case ic_cbe:is_variable_size(G, N, Type) of
- true ->
- if
- is_record(Type, string) ->
- "*";
- Ctype == "CORBA_char *" ->
- "";
- is_record(Type, wstring) -> %% WSTRING
- "*";
- Ctype == "CORBA_wchar *" -> %% WSTRING
- "";
- true ->
- case ictype:isArray(G, N, Type) of
- true ->
- "";
- _ ->
- "*"
- end
- end;
- false ->
- if
- Ctype == "erlang_pid" ->
- "*";
- Ctype == "erlang_port" ->
- "*";
- Ctype == "erlang_ref" ->
- "*";
- true ->
- ""
- end
- end,
- Ctype ++ " " ++ Dyn ++ Arg
- end, TypeAttrArgs1).
-
-%%------------------------------------------------------------
-%% Make parameter list for decoder prototypes
-%%------------------------------------------------------------
-
-mk_par_list_for_decoder_prototypes(G, N, X, TypeAttrArgs0) ->
- TypeAttrArgs1 = filter_type_attr_arg_list(G, X, [in], TypeAttrArgs0),
- lists:map(
- fun({Type, Attr, _Arg}) ->
- Ctype = mk_c_type(G, N, Type),
- Dyn = case ic_cbe:is_variable_size(G, N, Type) of
- true ->
- if
- is_record(Type, string) ->
- "**";
- Ctype == "CORBA_char *" ->
- "";
- is_record(Type, wstring) -> %% WSTRING
- "**";
- Ctype == "CORBA_wchar *" -> %% WSTRING
- "";
- true ->
- case ictype:isArray(G, N, Type) of
- true ->
- slice(Attr) ++ "*";
- _ ->
- "**"
- end
- end;
- false ->
- case ictype:isArray(G, N, Type) of
- true ->
- "";
- _ ->
- "*"
- end
- end,
- Ctype ++ Dyn
- end, TypeAttrArgs1).
-
-%%------------------------------------------------------------
-%% Make parameter list for encoder prototypes
-%%------------------------------------------------------------
-
-mk_par_list_for_encoder_prototypes(G, N, X, TypeAttrArgs0) ->
- TypeAttrArgs1 = filter_type_attr_arg_list(G, X, [out], TypeAttrArgs0),
- lists:map(
- fun({Type, _Attr, _Arg}) ->
- Ctype = mk_c_type(G, N, Type),
- Dyn = case ic_cbe:is_variable_size(G, N, Type) of
- true ->
- if
- is_record(Type, string) ->
- "*";
- Ctype == "CORBA_char *" ->
- "";
- is_record(Type, wstring) -> %% WSTRING
- "*";
- Ctype == "CORBA_wchar *" -> %% WSTRING
- "";
- true ->
- case ictype:isArray(G, N, Type) of
- true ->
- "";
- _ ->
- "*"
- end
- end;
- false ->
- if
- Ctype == "erlang_pid" ->
- "*";
- Ctype == "erlang_port" ->
- "*";
- Ctype == "erlang_ref" ->
- "*";
- true ->
- ""
- end
- end,
- Ctype ++ Dyn
- end, TypeAttrArgs1).
-
-%%------------------------------------------------------------
-%% Make parameter list for call-back prototypes
-%%------------------------------------------------------------
-
-mk_par_list_for_callback_prototypes(G, N, X, TypeAttrArgs0) ->
- TypeAttrArgs1 = filter_type_attr_arg_list(G, X, [in, out],
- TypeAttrArgs0),
- lists:map(
- fun({Type, Attr, _Arg}) ->
- IndOp = mk_ind_op(Attr),
- Ctype = mk_c_type(G, N, Type),
- Dyn = case ic_cbe:is_variable_size(G, N, Type) of
- true ->
- if
- is_record(Type, string) ->
- "*" ++ IndOp;
- Ctype == "CORBA_char *" ->
- "" ++ IndOp;
- is_record(Type, wstring) -> %% WSTRING
- "*" ++ IndOp;
- Ctype == "CORBA_wchar *" -> %% WSTRING
- "" ++ IndOp;
- true ->
- case ictype:isArray(G, N, Type) of
- true ->
- "";
- _ ->
- "*" ++ IndOp
- end
- end;
- false ->
- case ictype:isArray(G, N, Type) of
- true ->
- "";
- _ ->
- case Attr of %% Should just be IndOp
- in ->
- "*" ++ IndOp;
- out ->
- IndOp
- end
- end
- end,
- Ctype ++ Dyn
- end, TypeAttrArgs1).
-
-%%------------------------------------------------------------
-%% Make variable declaration list
-%%------------------------------------------------------------
-
-mk_var_decl_list(G, N, X, TypeAttrArgs0) ->
- TypeAttrArgs1 = filter_type_attr_arg_list(G, X, [in, out],
- TypeAttrArgs0),
- lists:map(
- fun({Type, Attr, Arg}) ->
- Ctype = mk_c_type(G, N, Type),
- VarDecl = case ic_cbe:is_variable_size(G, N, Type) of
- true ->
- if
- is_record(Type, string) ->
- Ctype ++ "* " ++ Arg ++ " = NULL";
- Ctype == "CORBA_char *" ->
- Ctype ++ " " ++ Arg ++ " = NULL";
- is_record(Type, wstring) -> %% WSTRING
- Ctype ++ "* " ++ Arg ++ " = NULL";
- Ctype == "CORBA_wchar *" -> %% WSTRING
- Ctype ++ " " ++ Arg ++ " = NULL";
- true ->
- case ictype:isArray(G, N, Type) of
- true ->
- Ctype ++ slice(Attr) ++ " " ++
- Arg;
- _ ->
- Ctype ++ "* " ++ Arg
- end
- end;
- false ->
- Ctype ++ " " ++ Arg
- end,
-
- VarDecl
- end, TypeAttrArgs1).
-
-%%------------------------------------------------------------
-%% Slice
-%%------------------------------------------------------------
-
-slice(in) ->
- "_slice*";
-slice(_) ->
- "".
-
-%%------------------------------------------------------------
-%% Special comment functions
-%%------------------------------------------------------------
-
-emit_encoding_comment(G, N, F, String, RefOrVal, Type, Name) ->
- emit(F, [io_lib:format(" /* ~s parameter: ~s~s ~s */\n",
- [String, mk_c_type(G, N, Type),
- RefOrVal, Name])]).
-
-
-%%------------------------------------------------------------
-%% Make C type
-%%------------------------------------------------------------
-
-%%
-%% Warning this is NOT identical to mk_c_type in ic_cbe.erl
-%%
-mk_c_type(G, N, S) ->
- mk_c_type(G, N, S, evaluate).
-
-mk_c_type(G, N, S, evaluate) when element(1, S) == scoped_id ->
- {FullScopedName, _T, _TK, _} = ic_symtab:get_full_scoped_name(G, N, S),
- BT = ic_code:get_basetype(G, ic_util:to_undersc(FullScopedName)),
- case BT of
- "erlang_binary" ->
- "erlang_binary";
- "erlang_pid" ->
- "erlang_pid";
- "erlang_port" ->
- "erlang_port";
- "erlang_ref" ->
- "erlang_ref";
- "erlang_term" ->
- "ETERM*";
- {enum, Type} ->
- mk_c_type(G, N, Type, evaluate);
- Type ->
- mk_c_type(G, N, Type, evaluate)
- end;
-mk_c_type(G, N, S, evaluate_not) when element(1, S) == scoped_id ->
- {FullScopedName, _T, _TK, _} = ic_symtab:get_full_scoped_name(G, N, S),
- BT = ic_code:get_basetype(G, ic_util:to_undersc(FullScopedName)),
- case BT of
- "erlang_binary" ->
- "erlang_binary";
- "erlang_pid" ->
- "erlang_pid";
- "erlang_port" ->
- "erlang_port";
- "erlang_ref" ->
- "erlang_ref";
- "erlang_term" ->
- "ETERM*";
- Type ->
- Type
- end;
-mk_c_type(_G, _N, S, _) when is_list(S) ->
- S;
-mk_c_type(_G, _N, S, _) when is_record(S, string) ->
- "CORBA_char";
-mk_c_type(_G, _N, S, _) when is_record(S, wstring) -> %% WSTRING
- "CORBA_wchar";
-mk_c_type(_G, _N, {boolean, _}, _) ->
- "CORBA_boolean";
-mk_c_type(_G, _N, {octet, _}, _) ->
- "CORBA_octet";
-mk_c_type(_G, _N, {void, _}, _) ->
- "void";
-mk_c_type(_G, _N, {unsigned, U}, _) ->
- case U of
- {short, _} ->
- "CORBA_unsigned_short";
- {long, _} ->
- "CORBA_unsigned_long";
- {'long long', _} ->
- "CORBA_unsigned_long_long"
- end;
-mk_c_type(_G, _N, {'long long', _}, _) ->
- "CORBA_long_long";
-mk_c_type(_G, _N, {'any', _}, _) -> %% Fix for any type
- "CORBA_long";
-mk_c_type(_G, _N, {T, _}, _) ->
- "CORBA_" ++ atom_to_list(T).
-
-%%------------------------------------------------------------
-%% Emit encoding statement
-%%------------------------------------------------------------
-
-%% emit_encoding_stmt(G, N, X, Fd, T, LName)
-%%
-%%
-emit_encoding_stmt(G, N, X, Fd, T, LName) when element(1, T) == scoped_id ->
- case mk_c_type(G, N, T, evaluate_not) of
- "erlang_pid" ->
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_pid(oe_env, ~s)) < 0) {\n",
- [LName]),
- emit_c_enc_rpt(Fd, " ", "oe_ei_encode_pid", []),
- emit(Fd, " return oe_error_code;\n }\n");
- "erlang_port" ->
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_port(oe_env, ~s)) < 0) {\n",
- [LName]),
- emit_c_enc_rpt(Fd, " ", "oe_ei_encode_port", []),
- emit(Fd, " return oe_error_code;\n }\n");
- "erlang_ref" ->
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_ref(oe_env, ~s)) < 0) {\n",
- [LName]),
- emit_c_enc_rpt(Fd, " ", "oe_ei_encode_ref", []),
- emit(Fd, " return oe_error_code;\n }\n");
- "ETERM*" ->
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_term(oe_env, ~s)) < 0) {\n",
- [LName]),
- emit_c_enc_rpt(Fd, " ", "oe_ei_encode_term", []),
- emit(Fd, " return oe_error_code;\n }\n");
- {enum, FSN} ->
- emit_encoding_stmt(G, N, X, Fd, FSN, LName);
- FSN ->
- emit_encoding_stmt(G, N, X, Fd, FSN, LName)
- end;
-emit_encoding_stmt(G, N, X, Fd, T, LName) when is_list(T) ->
- %% Already a fullscoped name
- case get_param_tk(LName, X) of
- error ->
- emit(Fd, " if ((oe_error_code = ~s~s(oe_env, ~s)) < 0) {\n",
- [ic_util:mk_oe_name(G, "encode_"), T, LName]);
- ParamTK ->
- case ic_cbe:is_variable_size(ParamTK) of
- true ->
- emit(Fd, " if ((oe_error_code = ~s~s(oe_env, ~s)) < 0)"
- " {\n",
- [ic_util:mk_oe_name(G, "encode_"), T, LName]),
- emit(Fd, " CORBA_exc_set(oe_env, "
- "CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation parameter on encode\");"
- "\n"),
- ?emit_c_enc_rpt(Fd, " ", "", []),
- emit(Fd, " return oe_error_code;\n }\n\n");
- false ->
- if is_atom(ParamTK) ->
- case ParamTK of
- tk_ushort ->
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_ulong(oe_env, "
- "(unsigned long) ~s)) < 0) {\n",
- [LName]),
- emit(Fd, " CORBA_exc_set(oe_env, "
- "CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation "
- "parameter on encode\");\n"),
- ?emit_c_enc_rpt(Fd, " ", "ushort", []),
- emit(Fd, " return "
- "oe_error_code;\n }\n\n");
- tk_ulong ->
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_ulong(oe_env, "
- "~s)) < 0) {\n", [LName]),
- emit(Fd, " CORBA_exc_set(oe_env, "
- "CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation "
- "parameter on encode\");\n"),
- ?emit_c_enc_rpt(Fd, " ", "ulong", []),
- emit(Fd, " return "
- "oe_error_code;\n }\n\n");
- tk_ulonglong ->
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_ulonglong(oe_env, "
- "~s)) < 0) {\n", [LName]),
- emit(Fd, " CORBA_exc_set(oe_env, "
- "CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation "
- "parameter on encode\");\n"),
- ?emit_c_enc_rpt(Fd, " ", "ulonglong", []),
- emit(Fd, " return "
- "oe_error_code;\n }\n\n");
- tk_short ->
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_long(oe_env, "
- "(long) ~s)) < 0) {\n", [LName]),
- emit(Fd, " CORBA_exc_set(oe_env, "
- "CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation "
- "parameter on encode\");\n"),
- ?emit_c_enc_rpt(Fd, " ", "short", []),
- emit(Fd, " return "
- "oe_error_code;\n }\n\n");
- tk_long ->
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_long(oe_env, "
- "~s)) < 0) {\n", [LName]),
- emit(Fd, " CORBA_exc_set(oe_env, "
- "CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation "
- "parameter on encode\");\n"),
- ?emit_c_enc_rpt(Fd, " ", "long", []),
- emit(Fd, " return "
- "oe_error_code;\n }\n\n");
- tk_longlong ->
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_longlong(oe_env, "
- "~s)) < 0) {\n", [LName]),
- emit(Fd, " CORBA_exc_set(oe_env, "
- "CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation "
- "parameter on encode\");\n"),
- ?emit_c_enc_rpt(Fd, " ", "longlong", []),
- emit(Fd, " return "
- "oe_error_code;\n }\n\n");
- tk_float ->
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_double(oe_env, "
- "(double) ~s)) < 0) {\n", [LName]),
- emit(Fd, " CORBA_exc_set(oe_env, "
- "CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation "
- "parameter on encode\");\n"),
- ?emit_c_enc_rpt(Fd, " ", "float", []),
- emit(Fd, " return "
- "oe_error_code;\n }\n\n");
- tk_double ->
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_double(oe_env, "
- "~s)) < 0) {\n", [LName]),
- emit(Fd, " CORBA_exc_set(oe_env, "
- "CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation "
- "parameter on encode\");\n"),
- ?emit_c_enc_rpt(Fd, " ", "double", []),
- emit(Fd, " return "
- "oe_error_code;\n }\n\n");
- tk_boolean ->
- emit(Fd, " switch(~s) {\n", [LName]),
- emit(Fd, " case 0 :\n"),
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_atom(oe_env, "
- "\"false\")) < 0) {\n"),
- emit(Fd, " CORBA_exc_set(oe_env, "
- "CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation "
- "parameter on encode\");\n"),
- ?emit_c_enc_rpt(Fd, " ", "boolean", []),
- emit(Fd, " return "
- "oe_error_code;\n }\n"),
- emit(Fd, " break;\n"),
- emit(Fd, " case 1 :\n"),
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_atom(oe_env, "
- "\"true\")) < 0) {\n"),
- emit(Fd, " CORBA_exc_set(oe_env, "
- "CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation "
- "parameter on encode\");\n"),
- ?emit_c_enc_rpt(Fd, " ", "boolean", []),
- emit(Fd, " return "
- "oe_error_code;\n }\n"),
- emit(Fd, " break;\n"),
- emit(Fd, " default :\n"),
- emit(Fd, " CORBA_exc_set(oe_env, "
- "CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation "
- "parameter on encode\");\n"),
- ?emit_c_enc_rpt(Fd, " ", "boolean", []),
- emit(Fd, " return -1;\n"),
- emit(Fd, " }\n\n");
- tk_char ->
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_char(oe_env, "
- "~s)) < 0) {\n", [LName]),
- emit(Fd, " CORBA_exc_set(oe_env, "
- "CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation "
- "parameter on encode\");\n"),
- ?emit_c_enc_rpt(Fd, " ", "char", []),
- emit(Fd, " return "
- "oe_error_code;\n }\n\n");
- tk_wchar -> %% WCHAR
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_wchar(oe_env, "
- "~s)) < 0) {\n", [LName]),
- emit(Fd, " CORBA_exc_set(oe_env, "
- "CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation "
- "parameter on encode\");\n"),
- ?emit_c_enc_rpt(Fd, " ", "wchar", []),
- emit(Fd, " return "
- "oe_error_code;\n }\n\n");
- tk_octet ->
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_char(oe_env, "
- "~s)) < 0) {\n", [LName]),
- emit(Fd, " CORBA_exc_set(oe_env, "
- "CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation "
- "parameter on encode\");\n"),
- ?emit_c_enc_rpt(Fd, " ", "octet", []),
- emit(Fd, " return "
- "oe_error_code;\n }\n\n");
- tk_any ->
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_long(oe_env, "
- "~s)) < 0) {\n", [LName]),
- emit(Fd, " CORBA_exc_set(oe_env, "
- "CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation "
- "parameter on encode\");\n"),
- ?emit_c_enc_rpt(Fd, " ", "any", []),
- emit(Fd, " return "
- "oe_error_code;\n }\n\n");
- _ ->
- emit(Fd, " CORBA_exc_set(oe_env, "
- "CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation "
- "parameter on encode\");\n"),
- ?emit_c_enc_rpt(Fd, " ", "tk_unknown", []),
- emit(Fd, " return "
- "oe_error_code;\n }\n\n"),
- ok
- end;
- true ->
- case element(1, ParamTK) of
- tk_enum ->
- emit(Fd, " if ((oe_error_code = "
- "~s~s(oe_env, ~s)) < 0) {\n",
- [ic_util:mk_oe_name(G, "encode_"),
- T, LName]),
- ?emit_c_enc_rpt(Fd, " ", "enum", []);
- tk_array ->
- emit(Fd, " if ((oe_error_code = "
- "~s~s(oe_env, ~s)) < 0) {\n",
- [ic_util:mk_oe_name(G, "encode_"),
- T, LName]),
- ?emit_c_enc_rpt(Fd, " ", "array", []);
- _ ->
- emit(Fd, " if ((oe_error_code = "
- "~s~s(oe_env, &~s)) < 0) {\n",
- [ic_util:mk_oe_name(G, "encode_"),
- T, LName]),
- ?emit_c_enc_rpt(Fd, " ", "", [])
- end,
- emit(Fd, " CORBA_exc_set(oe_env, "
- "CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation "
- "parameter on encode\");\n"),
- emit(Fd, " return oe_error_code;\n }\n\n")
- end
- end
- end;
-emit_encoding_stmt(G, N, _X, Fd, T, LName) when is_record(T, string) ->
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_string(oe_env, (const char*) ~s)) < 0) {\n",
- [LName]),
- emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Cannot encode string\");\n"),
- ?emit_c_enc_rpt(Fd, " ", "string", []),
- emit(Fd, " return oe_error_code;\n }\n\n");
-emit_encoding_stmt(G, N, _X, Fd, T, LName) when is_record(T, wstring) ->
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_wstring(oe_env, ~s)) < 0) {\n",
- [LName]),
- ?emit_c_enc_rpt(Fd, " ", "wstring", []),
- emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Cannot encode string\");\n"),
- emit(Fd, " return oe_error_code;\n }\n\n");
-emit_encoding_stmt(G, N, _X, Fd, T, LName) ->
- case T of
- {unsigned, {short, _}} ->
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_ulong(oe_env, (unsigned long) ~s)) < 0) {\n",
- [LName]),
- ?emit_c_enc_rpt(Fd, " ", "ushort", []),
- emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation parameter on encode\");\n"),
- emit(Fd, " return oe_error_code;\n }\n\n");
- {unsigned, {long, _}} ->
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_ulong(oe_env, ~s)) < 0) {\n",
- [LName]),
- ?emit_c_enc_rpt(Fd, " ", "ulong", []),
- emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation parameter on encode\");\n"),
- emit(Fd, " return oe_error_code;\n }\n\n");
- {unsigned, {'long long', _}} ->
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_ulonglong(oe_env, ~s)) < 0) {\n",
- [LName]),
- ?emit_c_enc_rpt(Fd, " ", "ulonglong", []),
- emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation parameter on encode\");\n"),
- emit(Fd, " return oe_error_code;\n }\n\n");
- {short, _} ->
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_long(oe_env, (long) ~s)) < 0) {\n",
- [LName]),
- ?emit_c_enc_rpt(Fd, " ", "short", []),
- emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation parameter on encode\");\n"),
- emit(Fd, " return oe_error_code;\n }\n\n");
- {long, _} ->
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_long(oe_env, ~s)) < 0) {\n",
- [LName]),
- ?emit_c_enc_rpt(Fd, " ", "long", []),
- emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation parameter on encode\");\n"),
- emit(Fd, " return oe_error_code;\n }\n\n");
- {'long long', _} ->
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_longlong(oe_env, ~s)) < 0) {\n",
- [LName]),
- ?emit_c_enc_rpt(Fd, " ", "longlong", []),
- emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation parameter on encode\");\n"),
- emit(Fd, " return oe_error_code;\n }\n\n");
- {float, _} ->
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_double(oe_env, (double) ~s)) < 0) {\n",
- [LName]),
- ?emit_c_enc_rpt(Fd, " ", "float", []),
- emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation parameter on encode\");\n"),
- emit(Fd, " return oe_error_code;\n }\n\n");
- {double, _} ->
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_double(oe_env, ~s)) < 0) {\n",
- [LName]),
- ?emit_c_enc_rpt(Fd, " ", "double", []),
- emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation parameter on encode\");\n"),
- emit(Fd, " return oe_error_code;\n }\n\n");
- {boolean, _} ->
- emit(Fd, " switch(~s) {\n", [LName]),
- emit(Fd, " case 0 :\n"),
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_atom(oe_env, \"false\")) < 0) {\n"),
- ?emit_c_enc_rpt(Fd, " ", "boolean", []),
- emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation parameter on encode\");\n"),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " break;\n"),
- emit(Fd, " case 1 :\n"),
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_atom(oe_env, \"true\")) < 0) {\n"),
- ?emit_c_enc_rpt(Fd, " ", "boolean", []),
- emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation parameter on encode\");\n"),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " break;\n"),
- emit(Fd, " default :\n"),
- ?emit_c_enc_rpt(Fd, " ", "boolean", []),
- emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation parameter on encode\");\n"),
- emit(Fd, " return -1;\n"),
- emit(Fd, " }\n\n");
- {char, _} ->
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_char(oe_env, ~s)) < 0) {\n",
- [LName]),
- ?emit_c_enc_rpt(Fd, " ", "char", []),
- emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation parameter on encode\");\n"),
- emit(Fd, " return oe_error_code;\n }\n\n");
- {wchar, _} -> %% WCHAR
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_wchar(oe_env, ~s)) < 0) {\n",
- [LName]),
- ?emit_c_enc_rpt(Fd, " ", "wchar", []),
- emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation parameter on encode\");\n"),
- emit(Fd, " return oe_error_code;\n }\n\n");
- {octet, _} ->
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_char(oe_env, ~s)) < 0) {\n",
- [LName]),
- ?emit_c_enc_rpt(Fd, " ", "octet", []),
- emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation parameter on encode\");\n"),
- emit(Fd, " return oe_error_code;\n }\n\n");
- {void, _} ->
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_atom(oe_env, \"void\")) < 0) {\n"),
- ?emit_c_enc_rpt(Fd, " ", "void", []),
- emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation parameter on encode\");\n"),
- emit(Fd, " return oe_error_code;\n }\n\n");
- {sequence, _, _} ->
- ?emit_c_enc_rpt(Fd, " ", "sequence", []),
- emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation parameter on encode\");\n"),
- emit(Fd, " return oe_error_code;\n }\n\n");
- {any, _} -> %% Fix for any type
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_long(oe_env, ~s)) < 0) {\n",
- [LName]),
- ?emit_c_enc_rpt(Fd, " ", "any", []),
- emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, "
- "BAD_PARAM, \"Bad operation parameter on encode\");\n"),
- emit(Fd, " return oe_error_code;\n }\n\n");
- _ ->
- ic_error:fatal_error(G, {illegal_typecode_for_c, T, N})
- end.
-
-%%------------------------------------------------------------
-%% Get type kind parameter
-%%------------------------------------------------------------
-
-%% Useful functions
-get_param_tk("oe_return", Op) ->
- ic_forms:get_tk(Op);
-get_param_tk(Name, Op) ->
- case get_param(Name, Op) of
- error ->
- error;
- Param ->
- ic_forms:get_tk(Param)
- end.
-
-%%------------------------------------------------------------
-%% Get parameter (for what? XXX)
-%%------------------------------------------------------------
-
-get_param(Name, Op) when is_record(Op, op) ->
- get_param_loop(Name, Op#op.params);
-get_param(_Name, _Op) ->
- error.
-
-get_param_loop(_Name, []) ->
- error;
-get_param_loop(Name, [Param| Params]) ->
- case ic_forms:get_id2(Param) of
- Name ->
- Param;
- _ ->
- get_param_loop(Name, Params)
- end.
-
-%%------------------------------------------------------------
-%% Emit decoding statement
-%%------------------------------------------------------------
-
-emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, Align, NextPos,
- DecType, AllocedPars) when element(1, T) == scoped_id ->
- case mk_c_type(G, N, T, evaluate_not) of
- "erlang_pid" ->
- emit(Fd, " if ((oe_error_code = ei_decode_pid(~s, "
- "&oe_env->_iin, ~s~s)) < 0) {\n",
- [InBuffer, IndOp, LName]),
- ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "", []),
- emit(Fd, " return oe_error_code;\n"),
- emit(Fd, " }\n\n");
- "erlang_port" ->
- emit(Fd, " if ((oe_error_code = ei_decode_port(~s, "
- "&oe_env->_iin, ~s~s)) < 0) {\n",
- [InBuffer, IndOp, LName]),
- ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "", []),
- emit(Fd, " return oe_error_code;\n"),
- emit(Fd, " }\n\n");
- "erlang_ref" ->
- emit(Fd, " if ((oe_error_code = ei_decode_ref(~s, "
- "&oe_env->_iin, ~s~s)) < 0) {\n",
- [InBuffer, IndOp, LName]),
- ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "", []),
- emit(Fd, " return oe_error_code;\n"),
- emit(Fd, " }\n\n");
- "ETERM*" ->
- emit(Fd, " if ((oe_error_code = ei_decode_term(~s, "
- "&oe_env->_iin, (void**)~s~s)) < 0) {\n",
- [InBuffer, IndOp, LName]),
- ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "", []),
- emit(Fd, " return oe_error_code;\n"),
- emit(Fd, " }\n\n");
- {enum, FSN} ->
- emit_decoding_stmt(G, N, Fd, FSN, LName, IndOp,
- InBuffer, Align, NextPos, DecType, AllocedPars);
- FSN ->
- emit_decoding_stmt(G, N, Fd, FSN, LName, IndOp,
- InBuffer, Align, NextPos, DecType, AllocedPars)
- end;
-emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, _Align, NextPos,
- DecType, AllocedPars) when is_list(T) ->
- %% Already a fullscoped name
- Type = ictype:name2type(G, T),
- case ictype:isBasicType(Type) of
- true ->
- emit_decoding_stmt_for_basic_type(Fd, Type, InBuffer, IndOp,
- LName, AllocedPars);
- false ->
- emit(Fd, " {\n"),
- case DecType of
- caller -> %% No malloc used, define oe_first anyhow.
- emit(Fd, " void *oe_first = NULL;\n"),
- emit(Fd, " int oe_outindex = 0;\n\n");
- array_dyn -> %% Malloc used
- emit(Fd, " int oe_outindex = 0;\n\n");
- %% [ic_util:mk_align(io_lib:format("sizeof(~s)", [T]))]);
- caller_dyn -> %% Malloc used
- emit(Fd, " int oe_outindex = 0;\n\n")
- end,
- emit(Fd, " if ((oe_error_code = ~s~s(oe_env, oe_first, "
- "~s, ~s)) < 0) {\n",
- [ic_util:mk_oe_name(G, "decode_"),
- T, NextPos, LName]),
- ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "", []),
- emit(Fd, " return oe_error_code;\n"),
- emit(Fd, " }\n"),
- emit(Fd, " }\n")
- end;
-emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, _Align, _NextPos,
- _DecType, AllocedPars) when is_record(T, string) ->
- emit(Fd, " if ((oe_error_code = ei_decode_string(~s, "
- "&oe_env->_iin, ~s~s)) < 0) {\n",
- [InBuffer, IndOp, LName]),
- ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "", []),
- emit(Fd, " return oe_error_code;\n"),
- emit(Fd, " }\n");
-emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, _Align, _NextPos,
- _DecType, AllocedPars) when is_record(T, wstring) ->
- %% WSTRING
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_decode_wstring(~s, "
- "&oe_env->_iin, ~s~s)) < 0) {\n",
- [InBuffer, IndOp, LName]),
- ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "", []),
- emit(Fd, " return oe_error_code;\n\n"),
- emit(Fd, " }\n");
-emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, _Align, _NextPos,
- _DecType, AllocedPars) ->
- case ic_cbe:normalize_type(T) of
- {basic, Type} ->
- emit_decoding_stmt_for_basic_type(Fd, Type, InBuffer, IndOp,
- LName, AllocedPars);
- _ ->
- case T of
- {void, _} ->
- emit(Fd,
- " if ((oe_error_code = ei_decode_atom(~s, "
- "&oe_env->_iin, 0)) < 0) {\n",
- [InBuffer]),
- ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "", []),
- emit(Fd, " return oe_error_code;\n"),
- emit(Fd, " }\n");
- {sequence, _, _} ->
- %% XXX XXX Why?
- ?emit_c_dec_rpt(Fd, " ", "", []),
- emit(Fd, " return oe_error_code;\n\n");
- {any, _} -> %% Fix for any type
- emit(Fd,
- " if ((oe_error_code = ei_decode_long(~s, "
- "&oe_env->_iin, ~s~s)) < 0) {\n",
- [InBuffer, IndOp, LName]),
- ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars),
- ?emit_c_dec_rpt(Fd, " ", "", []),
- emit(Fd, " return oe_error_code;\n\n"),
- emit(Fd, " }\n");
- _ ->
- ic_error:fatal_error(G, {illegal_typecode_for_c, T, N})
- end
- end.
-
-emit_decoding_stmt_for_basic_type(Fd, Type, InBuffer, IndOp,
- LName, AllocedPars) ->
- Fmt =
- " if ((oe_error_code = ~sei_decode_~s(~s, &oe_env->_iin, "
- "~s~s)) < 0) {\n",
- Ret =
- " return oe_error_code;\n"
- "}\n",
-
- {Pre, DecType} =
- case Type of
- ushort -> {"", "ulong"};
- ulong -> {"", "ulong"};
- ulonglong -> {"oe_", "ulonglong"};
- short -> {"", "long"};
- long -> {"", "long"};
- longlong -> {"oe_", "longlong"};
- float -> {"", "double"};
- double -> {"", "double"};
- boolean -> {"", "atom"};
- char -> {"", "char"};
- wchar -> {"oe_", "wchar"};
- octet -> {"", "char"};
- any -> {"", "long"}
- end,
- case Type of
- ushort ->
- emit(Fd, " {\n"),
- emit(Fd, " unsigned long oe_ulong;\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_ulong(~s, "
- "&oe_env->_iin, &oe_ulong)) < 0) {\n", [InBuffer]),
- ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars),
- emit_c_dec_rpt(Fd, " ", "ushort", []),
- emit(Fd, " return oe_error_code;\n"),
- emit(Fd, " }\n"),
- emit(Fd, " *~s = (unsigned short) oe_ulong;\n", [LName]),
- emit(Fd, " }\n\n");
- short ->
- emit(Fd, " {\n"),
- emit(Fd, " long oe_long;\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_long(~s, "
- "&oe_env->_iin, &oe_long)) < 0) {\n", [InBuffer]),
- ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars),
- emit_c_dec_rpt(Fd, " ", "short", []),
- emit(Fd, " return oe_error_code;\n"),
- emit(Fd, " }\n"),
- emit(Fd, " *~s = (short) oe_long;\n", [LName]),
- emit(Fd, " }\n\n");
- float ->
- emit(Fd, " {\n"),
- emit(Fd, " double oe_double;\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_double(~s, "
- "&oe_env->_iin, &oe_double)) < 0) {\n", [InBuffer]),
- ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars),
- emit_c_dec_rpt(Fd, " ", "float", []),
- emit(Fd, " return oe_error_code;\n"),
- emit(Fd, " }\n"),
- emit(Fd, " *~s = (float) oe_double;\n", [LName]),
- emit(Fd, " }\n\n");
- boolean ->
- emit(Fd, " {\n"),
- emit(Fd, " char oe_bool[25];\n\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_atom(~s, "
- "&oe_env->_iin, oe_bool)) < 0) {\n", [InBuffer]),
- ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars),
- emit_c_dec_rpt(Fd, " ", "boolean", []),
- emit(Fd, " return oe_error_code;\n"),
- emit(Fd, " }\n"),
- emit(Fd, " if (strcmp(oe_bool, \"false\") == 0) {\n"),
- emit(Fd, " *(~s) = 0;\n", [LName]),
- emit(Fd, " }\n"),
- emit(Fd, " else if (strcmp(oe_bool, \"true\") == 0) {\n"),
- emit(Fd, " *(~s) = 1;\n", [LName]),
- emit(Fd, " } else {\n"),
- ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars),
- emit_c_dec_rpt(Fd, " ", "boolean", []),
- emit(Fd, " return -1;\n"),
- emit(Fd, " }\n"),
- emit(Fd, " }\n\n");
- _ ->
- emit(Fd, Fmt, [Pre, DecType, InBuffer, IndOp, LName]),
- ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars),
- emit(Fd, Ret)
- end.
-
-
-%%------------------------------------------------------------
-%% Prefix for generic functions
-%%------------------------------------------------------------
-get_user_proto(G, Default) ->
- case ic_options:get_opt(G, user_protocol) of
- false ->
- Default;
- Pfx ->
- Pfx
- end.
-
-%%------------------------------------------------------------
-%% Timeout. Returns a string (or Default).
-%%------------------------------------------------------------
-get_c_timeout(G, Default) ->
- case ic_options:get_opt(G, c_timeout) of
- Tmo when is_integer(Tmo) ->
- TmoStr = integer_to_list(Tmo),
- {TmoStr, TmoStr};
- {SendTmo, RecvTmo} when is_integer(SendTmo) andalso is_integer(RecvTmo) ->
- {integer_to_list(SendTmo), integer_to_list(RecvTmo)};
- false ->
- Default
- end.
-
-%%------------------------------------------------------------
-%% ZIPPERS (merging of successive elements of two lists).
-%%------------------------------------------------------------
-
-%% zip([H1| T1], [H2| T2]) ->
-%% [{H1, H2}| zip(T1, T2)];
-%% zip([], []) ->
-%% [].
-
-filterzip(F, [H1| T1], [H2| T2]) ->
- case F(H1, H2) of
- false ->
- filterzip(F, T1, T2);
- {true, Val} ->
- [Val| filterzip(F, T1, T2)]
- end;
-filterzip(_, [], []) ->
- [].
-
-
diff --git a/lib/ic/src/ic_debug.hrl b/lib/ic/src/ic_debug.hrl
deleted file mode 100644
index 97a56743d8..0000000000
--- a/lib/ic/src/ic_debug.hrl
+++ /dev/null
@@ -1,38 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
-%%----------------------------------------------------------------------
-%% Debug macro
-%%----------------------------------------------------------------------
--ifndef(ic_debug_hrl).
--define(ic_debug_hrl, true).
-
--ifdef(debug).
- -define(PRINTDEBUG(Msg),
- io:format("~p :~p ~p~n", [Msg, ?FILE, ?LINE])).
- -define(PRINTDEBUG2(F, A),
- io:format(F ++ ":~p ~p~n", A ++ [?FILE, ?LINE])).
--else.
- -define(PRINTDEBUG(Msg), ok).
- -define(PRINTDEBUG2(F, A), ok).
--endif.
-
--endif.
diff --git a/lib/ic/src/ic_enum_java.erl b/lib/ic/src/ic_enum_java.erl
deleted file mode 100644
index dbfa110089..0000000000
--- a/lib/ic/src/ic_enum_java.erl
+++ /dev/null
@@ -1,313 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(ic_enum_java).
-
--include("icforms.hrl").
--include("ic.hrl").
--include("ic_debug.hrl").
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([gen/3]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-%%-----------------------------------------------------------------
-%% External functions
-%%-----------------------------------------------------------------
-
-%%-----------------------------------------------------------------
-%% Func: gen/3
-%%-----------------------------------------------------------------
-gen(G, N, X) when is_record(X, enum) ->
- %%?PRINTDEBUG2("enum: ~p", [X]),
- EnumName = ic_forms:get_java_id(X),
- N2 = ["_" ++ EnumName |N],
- ic_jbe:gen(G, N2, ic_forms:get_body(X)),
-
- emit_enum_class(G, N, X, EnumName),
- emit_holder_class(G, N, X, EnumName),
- emit_helper_class(G, N, X, EnumName);
-gen(_G, _N, _X) ->
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-
-%%-----------------------------------------------------------------
-%% Func: emit_enum_class/4
-%%-----------------------------------------------------------------
-emit_enum_class(G, N, X, EnumName) ->
- {Fd, _} = ic_file:open_java_file(G, N, EnumName),
-
- EList = enum_member_name_list(G, N, X),
- %%?PRINTDEBUG2("EList: ~p", [EList]),
- ic_codegen:emit(Fd, ["final public class ",EnumName," {\n\n"
-
- " // instance variables\n"]),
-
- emit_enum_member_int_values_initialization(G, N, X, Fd, EList),
- emit_enum_public_instance_variables(G, N, X, Fd, EnumName, EList),
-
- ic_codegen:emit(Fd, [" private int _value;\n\n"
-
- " // constructors\n"
- " private ",EnumName,"(int __value) {\n"
- " _value = __value;\n"
- " }\n\n"
-
- " // methods\n"
- " public int value() {\n"
- " return _value;\n"
- " }\n"]),
-
- emit_enum_from_int_function(G, N, X, Fd, EnumName, EList),
-
- ic_codegen:emit(Fd, "\n}\n"),
- file:close(Fd).
-
-%%-----------------------------------------------------------------
-%% Func: emit_holder_class/4
-%%-----------------------------------------------------------------
-emit_holder_class(G, N, _X, EnumName) ->
- EName = string:concat(EnumName, "Holder"),
- {Fd, _} = ic_file:open_java_file(G, N, EName),
-
- ic_codegen:emit(Fd, ["final public class ",EnumName,"Holder {\n\n"
-
- " // instance variables\n"
- " public ",EnumName," value;\n\n"
-
- " // constructors\n"
- " public ",EnumName,"Holder() {}\n\n"
-
- " public ",EnumName,"Holder(",EnumName," initial) {\n"
- " value = initial;\n"
- " }\n\n"
-
- " // methods\n"
- " public void _marshal(",?ERLANGPACKAGE,"OtpOutputStream out) throws java.lang.Exception {\n"
- " ",EnumName,"Helper.marshal(out, value);\n"
- " }\n\n"
-
- " public void _unmarshal(",?ERLANGPACKAGE,"OtpInputStream in) throws java.lang.Exception {\n"
- " value = ",EnumName,"Helper.unmarshal(in);\n"
- " }\n\n"
- "}\n"]),
- file:close(Fd).
-
-
-%%-----------------------------------------------------------------
-%% Func: emit_helper_class/4
-%%-----------------------------------------------------------------
-emit_helper_class(G, N, X, EnumName) ->
- EName = string:concat(EnumName, "Helper"),
- WEList = enum_member_atom_list(G, N, X),
- {Fd, _} = ic_file:open_java_file(G, N, EName),
-
- ic_codegen:emit(Fd, ["public class ",EnumName,"Helper {\n\n"
-
- " // constructors\n"
- " private ",EnumName,"Helper() {}\n\n"
-
- " // methods\n"
-
- " public static void marshal(",?ERLANGPACKAGE,"OtpOutputStream _out, ",EnumName," _value)\n"
- " throws java.lang.Exception {\n\n"]),
-
- emit_enum_write_function(G, N, X, Fd, EnumName),
-
- ic_codegen:emit(Fd, [" }\n\n"
-
- " public static ",EnumName," unmarshal(",?ERLANGPACKAGE,"OtpInputStream _in)\n"
- " throws java.lang.Exception {\n\n"]),
-
- emit_enum_read_function(G, N, X, Fd, EnumName),
-
- ic_codegen:emit(Fd, "\n }\n\n"),
-
- emit_enum_private_member_variables(Fd, WEList),
-
- ic_codegen:emit(Fd, ["\n // Get integer value of enum from string\n"
- " private static int _getIntFromName(String name) throws java.lang.Exception {\n"
- " for(int i = 0; i < _memberCount; i++) {\n"
- " if (name.equals(_members[i]))\n"
- " return i;\n"
- " }\n"
- " throw new java.lang.Exception(\"\");\n"
- " }\n\n"
-
- " public static String id() {\n"
- " return \"",ictk:get_IR_ID(G, N, X),"\";\n"
- " }\n\n"
-
- " public static String name() {\n"
- " return \"",EnumName,"\";\n"
- " }\n\n"]),
-
- ic_jbe:emit_type_function(G, N, X, Fd),
-
- ic_codegen:emit(Fd, [" public static void insert(",?ICPACKAGE,"Any _any, ",EnumName," _this)\n"
- " throws java.lang.Exception {\n\n"
-
- " ",?ERLANGPACKAGE,"OtpOutputStream _os = \n"
- " new ",?ERLANGPACKAGE,"OtpOutputStream();\n\n"
-
- " _any.type(type());\n"
- " marshal(_os, _this);\n"
- " _any.insert_Streamable(_os);\n"
- " }\n\n"
-
- " public static ",EnumName," extract(",?ICPACKAGE,"Any _any)\n"
- " throws java.lang.Exception {\n\n"
-
- " return unmarshal(_any.extract_Streamable());\n"
- " }\n\n"
-
- "}\n"]),
- file:close(Fd).
-
-%%-----------------------------------------------------------------
-%% Func: emit_enum_public_instance_variables/6
-%%-----------------------------------------------------------------
-emit_enum_public_instance_variables(_G, _N, _X, _Fd, _EnumName, []) ->
- ok;
-emit_enum_public_instance_variables(G, N, X, Fd, EnumName, [Enumerator |EList]) ->
- ic_codegen:emit(Fd, [" public static final ",EnumName," ",Enumerator," = new ",EnumName,"(_",Enumerator,");\n"]),
- emit_enum_public_instance_variables(G, N, X, Fd, EnumName, EList).
-
-%%-----------------------------------------------------------------
-%% Func: emit_enum_member_int_values_initialization/5
-%%-----------------------------------------------------------------
-emit_enum_member_int_values_initialization(G, N, X, Fd, EList) ->
- InitString = emit_enum_member_int_values_initialization_1(G, N, X, Fd, EList, 0),
- ic_codegen:emit(Fd, [" public static final int ",InitString,";\n"]).
-
-
-%%-----------------------------------------------------------------
-%% Func: emit_enum_member_int_values_initialization_1/6
-%%-----------------------------------------------------------------
-emit_enum_member_int_values_initialization_1(_G, _N, _X, _Fd, [Enumerator], Num) ->
- " _" ++ Enumerator ++ " = " ++ ic_util:to_list(Num);
-emit_enum_member_int_values_initialization_1(G, N, X, Fd, [Enumerator |EList], Num) ->
- Spaces = if
- Num == 0 ->
- "";
- true ->
- " "
- end,
- Spaces ++ "_" ++ Enumerator ++ " = " ++ ic_util:to_list(Num) ++ ",\n" ++
- emit_enum_member_int_values_initialization_1(G, N, X, Fd, EList, Num + 1).
-
-%%-----------------------------------------------------------------
-%% Func: emit_enum_from_int_function/6
-%%-----------------------------------------------------------------
-emit_enum_from_int_function(_G, _N, _X, Fd, EnumName, EList) ->
- ic_codegen:emit(Fd,
- [" public static final ",EnumName," from_int(int __value) throws java.lang.Exception {\n"
- " switch (__value) {\n"]),
- emit_enum_from_int_function_switchbody(Fd, EList),
- ic_codegen:emit(Fd, [" }\n"
- " }\n"]).
-
-%%-----------------------------------------------------------------
-%% Func: emit_enum_from_int_function_switchbody/2
-%%-----------------------------------------------------------------
-emit_enum_from_int_function_switchbody(Fd, []) ->
- ic_codegen:emit(Fd, [" default:\n"
- " throw new java.lang.Exception(\"\");\n"]);
-emit_enum_from_int_function_switchbody(Fd, [Enumerator |EList]) ->
- ic_codegen:emit(Fd, [" case _",Enumerator,":\n"
- " return ",Enumerator,";\n"]),
- emit_enum_from_int_function_switchbody(Fd, EList).
-
-%%-----------------------------------------------------------------
-%% Func: emit_enum_private_member_variables/2
-%%-----------------------------------------------------------------
-emit_enum_private_member_variables(Fd, EList) ->
- ic_codegen:emit(Fd, [" private static final int _memberCount = ",integer_to_list(length(EList)),";\n"
- " private static String[] _members = {\n"]),
- emit_enum_private_member_variables_1(Fd, EList),
- ic_codegen:emit(Fd, " };\n").
-
-%%-----------------------------------------------------------------
-%% Func: emit_enum_private_member_variables_1/2
-%%-----------------------------------------------------------------
-emit_enum_private_member_variables_1(Fd, [Enumerator]) ->
- ic_codegen:emit(Fd, [" \"",Enumerator,"\"\n"]);
-emit_enum_private_member_variables_1(Fd, [Enumerator |EList]) ->
- ic_codegen:emit(Fd, [" \"",Enumerator,"\",\n"]),
- emit_enum_private_member_variables_1(Fd, EList).
-
-%%-----------------------------------------------------------------
-%% Func: emit_enum_read_function/5
-%%-----------------------------------------------------------------
-emit_enum_read_function(_G, _N, _X, Fd, EnumName) ->
- ic_codegen:emit(Fd, [" return ",EnumName,".from_int(_getIntFromName(_in.read_atom()));"]).
-
-%%-----------------------------------------------------------------
-%% Func: emit_enum_write_function/5
-%%-----------------------------------------------------------------
-emit_enum_write_function(_G, _N, _X, Fd, _EnumName) ->
- ic_codegen:emit(Fd, " _out.write_atom(_members[_value.value()]);\n").
-
-
-%%-----------------------------------------------------------------
-%% Func: enum_member_name_list/3
-%%
-%% Note: The names generated are checked for name coalition
-%% with java keywords. If so the name is always prefixed
-%% by "_"
-%%-----------------------------------------------------------------
-enum_member_name_list(_G, _N, X) ->
- lists:map(
- fun(Enumerator) ->
- ic_forms:get_java_id(Enumerator)
- end,
- ic_forms:get_body(X)).
-
-%%-----------------------------------------------------------------
-%% Func: enum_member_atom_list/3
-%%
-%% Note : Similar to the emit_member_list/3 but does not
-%% solves name coalitions with java keywords.
-%% Used for wire encoding only
-%%-----------------------------------------------------------------
-enum_member_atom_list(_G, _N, X) ->
- lists:map(
- fun(Enumerator) ->
- ic_forms:get_id2(Enumerator)
- end,
- ic_forms:get_body(X)).
-
-
-
-
-
-
-
-
diff --git a/lib/ic/src/ic_erl_template.erl b/lib/ic/src/ic_erl_template.erl
deleted file mode 100644
index 0839577701..0000000000
--- a/lib/ic/src/ic_erl_template.erl
+++ /dev/null
@@ -1,640 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(ic_erl_template).
-
-
--export([do_gen/3, emit_header/3]).
-
--import(ic_codegen, [emit/2, emit/3, nl/1]).
-
--include("icforms.hrl").
--include("ic.hrl").
-
--include_lib("stdlib/include/erl_compile.hrl").
-
--define(TAB, " ").
--define(TAB2, "% ").
-
--define(TEMPLATE_1_A,
- "%%----------------------------------------------------------------------\n"
- "%% <LICENSE>\n"
- "%% \n"
- "%% $Id$\n"
- "%%\n"
- "%%----------------------------------------------------------------------\n"
- "%% Module : ~s.erl\n"
- "%% \n"
- "%% Source : ~s\n"
- "%% \n"
- "%% Description : \n"
- "%% \n"
- "%% Creation date: ~s\n"
- "%%\n"
- "%%----------------------------------------------------------------------\n"
- "-module(~p).\n\n").
-
--define(TEMPLATE_1_B,
- "%%----------------------------------------------------------------------\n"
- "%% Internal Exports\n"
- "%%----------------------------------------------------------------------\n"
- "-export([init/1,\n"
- " terminate/2,\n"
- " code_change/3,\n"
- " handle_info/2]).\n\n"
- "%%----------------------------------------------------------------------\n"
- "%% Include Files\n"
- "%%----------------------------------------------------------------------\n"
- "\n\n"
- "%%----------------------------------------------------------------------\n"
- "%% Macros\n"
- "%%----------------------------------------------------------------------\n"
- "\n\n"
- "%%----------------------------------------------------------------------\n"
- "%% Records\n"
- "%%----------------------------------------------------------------------\n"
- "-record(state, {}).\n\n"
- "%%======================================================================\n"
- "%% API Functions\n"
- "%%======================================================================\n").
-
--define(TEMPLATE_1_C,
- "%%======================================================================\n"
- "%% Internal Functions\n"
- "%%======================================================================\n"
- "%%----------------------------------------------------------------------\n"
- "%% Function : init/1\n"
- "%% Arguments : Env = term()\n"
- "%% Returns : {ok, State} |\n"
- "%% {ok, State, Timeout} |\n"
- "%% ignore |\n"
- "%% {stop, Reason}\n"
- "%% Raises : -\n"
- "%% Description: Initiates the server\n"
- "%%----------------------------------------------------------------------\n"
- "init(_Env) ->\n"
- "\t{ok, #state{}}.\n\n\n"
- "%%----------------------------------------------------------------------\n"
- "%% Function : terminate/2\n"
- "%% Arguments : Reason = normal | shutdown | term()\n"
- "%% State = term()\n"
- "%% Returns : ok\n"
- "%% Raises : -\n"
- "%% Description: Invoked when the object is terminating.\n"
- "%%----------------------------------------------------------------------\n"
- "terminate(_Reason, _State) ->\n"
- "\tok.\n\n\n"
- "%%----------------------------------------------------------------------\n"
- "%% Function : code_change/3\n"
- "%% Arguments : OldVsn = undefined | term()\n"
- "%% State = NewState = term()\n"
- "%% Extra = term()\n"
- "%% Returns : {ok, NewState}\n"
- "%% Raises : -\n"
- "%% Description: Invoked when the object should update its internal state\n"
- "%% due to code replacement.\n"
- "%%----------------------------------------------------------------------\n"
- "code_change(_OldVsn, State, _Extra) ->\n"
- "\t{ok, State}.\n\n\n"
- "%%----------------------------------------------------------------------\n"
- "%% Function : handle_info/2\n"
- "%% Arguments : Info = normal | shutdown | term()\n"
- "%% State = NewState = term()\n"
- "%% Returns : {noreply, NewState} |\n"
- "%% {noreply, NewState, Timeout} |\n"
- "%% {stop, Reason, NewState}\n"
- "%% Raises : -\n"
- "%% Description: Invoked when, for example, the server traps exits.\n"
- "%%----------------------------------------------------------------------\n"
- "handle_info(_Info, State) ->\n"
- "\t{noreply, State}.\n\n\n").
-
--define(TEMPLATE_2_A,
- "%%% #0. BASIC INFORMATION\n"
- "%%% ----------------------------------------------------------------------\n"
- "%%% %CCaseFile : ~s.erl %\n"
- "%%% Author : \n"
- "%%% Description : \n"
- "%%%\n"
- "%%% Modules used: \n"
- "%%%\n"
- "%%%\n"
- "%%% ----------------------------------------------------------------------\n"
- "-module(~p).\n"
- "-author('unknown').\n"
- "-id('').\n"
- "-vsn('').\n"
- "-date('~s').\n\n"
- "%%% ----------------------------------------------------------------------\n"
- "%%% Template Id: <ID>\n"
- "%%%\n"
- "%%% #Copyright (C) 2004\n"
- "%%% by <COMPANY>\n"
- "%%% <ADDRESS>\n"
- "%%% <OTHER INFORMATION>\n"
- "%%% \n"
- "%%% <LICENSE>\n"
- "%%% \n"
- "%%% \n"
- "%%% ----------------------------------------------------------------------\n"
- "%%% #1. REVISION LOG\n"
- "%%% ----------------------------------------------------------------------\n"
- "%%% Rev Date Name What\n"
- "%%% ----- ------- -------- --------------------------\n"
- "%%% \n"
- "%%% ----------------------------------------------------------------------\n"
- "%%%\n"
- "%%% \n"
- "%%% #2. EXPORT LISTS\n"
- "%%% ----------------------------------------------------------------------\n"
- "%%% #2.1 EXPORTED INTERFACE FUNCTIONS\n"
- "%%% ----------------------------------------------------------------------\n").
-
--define(TEMPLATE_2_B,
- "%%% ----------------------------------------------------------------------\n"
- "%%% #2.2 EXPORTED INTERNAL FUNCTIONS\n"
- "%%% ----------------------------------------------------------------------\n"
- "-export([init/1,\n"
- " terminate/2,\n"
- " code_change/3,\n"
- " handle_info/2]).\n\n"
- "%%% ----------------------------------------------------------------------\n"
- "%%% #2.3 INCLUDE FILES\n"
- "%%% ----------------------------------------------------------------------\n"
- "\n\n"
- "%%% ----------------------------------------------------------------------\n"
- "%%% #2.4 MACROS\n"
- "%%% ----------------------------------------------------------------------\n"
- "\n\n"
- "%%% ----------------------------------------------------------------------\n"
- "%%% #2.5 RECORDS\n"
- "%%% ----------------------------------------------------------------------\n"
- "-record(state, {}).\n\n"
- "%%% ----------------------------------------------------------------------\n"
- "%%% #3. CODE\n"
- "%%% #---------------------------------------------------------------------\n"
- "%%% #3.1 CODE FOR EXPORTED INTERFACE FUNCTIONS\n"
- "%%% #---------------------------------------------------------------------\n").
-
--define(TEMPLATE_2_C,
- "%%% ----------------------------------------------------------------------\n"
- "%%% #3.3 CODE FOR INTERNAL FUNCTIONS\n"
- "%%% ----------------------------------------------------------------------\n"
- "%%% ----------------------------------------------------------------------\n"
- "%%% # init/1\n"
- "%%% Input : Env = term()\n"
- "%%% Output : {ok, State} |\n"
- "%%% {ok, State, Timeout} |\n"
- "%%% ignore |\n"
- "%%% {stop, Reason}\n"
- "%%% Exceptions : -\n"
- "%%% Description: Initiates the server\n"
- "%%% ----------------------------------------------------------------------\n"
- "init(_Env) ->\n"
- "\t{ok, #state{}}.\n\n\n"
- "%%% ----------------------------------------------------------------------\n"
- "%%% # terminate/2\n"
- "%%% Input : Reason = normal | shutdown | term()\n"
- "%%% State = term()\n"
- "%%% Output : ok\n"
- "%%% Exceptions : -\n"
- "%%% Description: Invoked when the object is terminating.\n"
- "%%% ----------------------------------------------------------------------\n"
- "terminate(_Reason, _State) ->\n"
- "\tok.\n\n\n"
- "%%% ----------------------------------------------------------------------\n"
- "%%% # code_change/3\n"
- "%%% Input : OldVsn = undefined | term()\n"
- "%%% State = NewState = term()\n"
- "%%% Extra = term()\n"
- "%%% Output : {ok, NewState}\n"
- "%%% Exceptions : -\n"
- "%%% Description: Invoked when the object should update its internal state\n"
- "%%% due to code replacement.\n"
- "%%% ----------------------------------------------------------------------\n"
- "code_change(_OldVsn, State, _Extra) ->\n"
- "\t{ok, State}.\n\n\n"
- "%%% ----------------------------------------------------------------------\n"
- "%%% # handle_info/2\n"
- "%%% Input : Info = normal | shutdown | term()\n"
- "%%% State = NewState = term()\n"
- "%%% Output : {noreply, NewState} |\n"
- "%%% {noreply, NewState, Timeout} |\n"
- "%%% {stop, Reason, NewState}\n"
- "%%% Exceptions : -\n"
- "%%% Description: Invoked when, for example, the server traps exits.\n"
- "%%% ----------------------------------------------------------------------\n"
- "handle_info(_Info, State) ->\n"
- "\t{noreply, State}.\n\n\n"
- "%%% ----------------------------------------------------------------------\n"
- "%%% #4 CODE FOR TEMPORARY CORRECTIONS\n"
- "%%% ----------------------------------------------------------------------\n\n").
-
-
-%%------------------------------------------------------------
-%%
-%% Generate the client side Erlang stubs.
-%%
-%% Each module is generated to a separate file.
-%%
-%% Export declarations for all interface functions must be
-%% generated. Each function then needs to generate a function head and
-%% a body. IDL parameters must be converted into Erlang parameters
-%% (variables, capitalised) and a type signature list must be
-%% generated (for later encode/decode).
-%%
-%%------------------------------------------------------------
-do_gen(G, _File, Form) ->
- gen_head(G, [], Form),
- gen(G, [], Form).
-
-
-gen(G, N, [X|Xs]) when is_record(X, preproc) ->
- NewG = ic:handle_preproc(G, N, X#preproc.cat, X),
- gen(NewG, N, Xs);
-gen(G, N, [X|Xs]) when is_record(X, module) ->
- G2 = ic_file:filename_push(G, N, X, erlang_template_no_gen),
- N2 = [ic_forms:get_id2(X) | N],
- gen_head(G2, N2, X),
- gen(G2, N2, ic_forms:get_body(X)),
- G3 = ic_file:filename_pop(G2, erlang_template_no_gen),
- gen(G3, N, Xs);
-gen(G, N, [X|Xs]) when is_record(X, interface) ->
- G2 = ic_file:filename_push(G, N, X, erlang_template),
- N2 = [ic_forms:get_id2(X) | N],
- gen_head(G2, N2, X),
- gen(G2, N2, ic_forms:get_body(X)),
- lists:foreach(fun({_Name, Body}) -> gen(G2, N2, Body) end,
- X#interface.inherit_body),
- Fd = ic_genobj:stubfiled(G2),
- case get_template_version(G2) of
- ?IC_FLAG_TEMPLATE_2 ->
- emit(Fd, ?TEMPLATE_2_C, []);
- _ ->
- emit(Fd, ?TEMPLATE_1_C, [])
- end,
- G3 = ic_file:filename_pop(G2, erlang_template),
- gen(G3, N, Xs);
-gen(G, N, [X|Xs]) when is_record(X, op) ->
- {Name, InArgNames, OutArgNames, Reply} = extract_info(X),
- emit_function(G, N, X, ic_genobj:is_stubfile_open(G),
- ic_forms:is_oneway(X), Name, InArgNames, OutArgNames, Reply),
- gen(G, N, Xs);
-gen(G, N, [X|Xs]) when is_record(X, attr) ->
- emit_attr(G, N, X, ic_genobj:is_stubfile_open(G), fun emit_function/9),
- gen(G, N, Xs);
-gen(G, N, [_X|Xs]) ->
- gen(G, N, Xs);
-gen(_G, _N, []) ->
- ok.
-
-%% Module Header
-emit_header(G, Fd, Name) ->
- Date = get_date(),
- case get_template_version(G) of
- ?IC_FLAG_TEMPLATE_2 ->
- emit(Fd, ?TEMPLATE_2_A, [Name, list_to_atom(Name), Date]);
- _ ->
- IDLFile = ic_genobj:idlfile(G),
- emit(Fd, ?TEMPLATE_1_A, [Name, IDLFile, Date, list_to_atom(Name)])
- end.
-
-
-emit_attr(G, N, X, Open, F) ->
- XX = #id_of{type=X},
- lists:foreach(fun(Id) ->
- X2 = XX#id_of{id=Id},
- IsOneWay = ic_forms:is_oneway(X2),
- {Get, Set} = mk_attr_func_names(N, ic_forms:get_id(Id)),
- F(G, N, X2, Open, IsOneWay, Get, [], [],
- [{ic_util:mk_var(ic_forms:get_id(Id)),
- ic_forms:get_tk(X)}]),
- case X#attr.readonly of
- {readonly, _} ->
- ok;
- _ ->
- F(G, N, X2, Open, IsOneWay, Set,
- [{ic_util:mk_var(ic_forms:get_id(Id)),
- ic_forms:get_tk(X)}], [], ["ok"])
- end
- end, ic_forms:get_idlist(X)).
-
-
-%% The automaticly generated get and set operation names for an
-%% attribute.
-mk_attr_func_names(_Scope, Name) ->
- {"_get_" ++ Name, "_set_" ++ Name}.
-
-
-extract_info(X) when is_record(X, op) ->
- Name = ic_forms:get_id2(X),
- InArgs = ic:filter_params([in,inout], X#op.params),
- OutArgs = ic:filter_params([out,inout], X#op.params),
- Reply = case ic_forms:get_tk(X) of
- tk_void ->
- ["ok"];
- Type ->
- [{"OE_Reply", Type}]
- end,
- InArgsTypeList =
- [{ic_util:mk_var(ic_forms:get_id(InArg#param.id)),
- ic_forms:get_tk(InArg)} || InArg <- InArgs ],
- OutArgsTypeList =
- [{ic_util:mk_var(ic_forms:get_id(OutArg#param.id)),
- ic_forms:get_tk(OutArg)} || OutArg <- OutArgs ],
- {Name, InArgsTypeList, OutArgsTypeList, Reply}.
-
-get_template_version(G) ->
- case ic_options:get_opt(G, flags) of
- Flags when is_integer(Flags) ->
- case ?IC_FLAG_TEST(Flags, ?IC_FLAG_TEMPLATE_2) of
- true ->
- ?IC_FLAG_TEMPLATE_2;
- false ->
- ?IC_FLAG_TEMPLATE_1
- end;
- _ ->
- ?IC_FLAG_TEMPLATE_1
- end.
-
-
-get_date() ->
- {{Y,M,D}, _} = calendar:now_to_datetime(now()),
- if
- M < 10, D < 10 ->
- lists:concat([Y, "-0", M, "-0",D]);
- M < 10 ->
- lists:concat([Y, "-0", M, "-", D]);
- D < 10 ->
- lists:concat([Y, "-", M, "-0", D]);
- true ->
- lists:concat([Y, "-", M, "-", D])
- end.
-
-
-%%------------------------------------------------------------
-%%
-%% Export stuff
-%%
-%% Gathering of all names that should be exported from a stub
-%% file.
-%%
-
-
-gen_head_special(G, N, X) when is_record(X, interface) ->
- Fd = ic_genobj:stubfiled(G),
- lists:foreach(fun({_Name, Body}) ->
- ic_codegen:export(Fd, exp_top(G, N, Body, []))
- end, X#interface.inherit_body),
- nl(Fd),
- ok;
-gen_head_special(_G, _N, _X) ->
- ok.
-
-
-%% Generate all export declarations
-gen_head(G, N, X) ->
- case ic_genobj:is_stubfile_open(G) of
- true ->
- Fd = ic_genobj:stubfiled(G),
- ic_codegen:export(Fd, exp_top(G, N, X, [])),
- gen_head_special(G, N, X),
- case get_template_version(G) of
- ?IC_FLAG_TEMPLATE_2 ->
- emit(Fd, ?TEMPLATE_2_B, []);
- _ ->
- emit(Fd, ?TEMPLATE_1_B, [])
- end;
- false ->
- ok
- end.
-
-exp_top(_G, _N, X, Acc) when element(1, X) == preproc ->
- Acc;
-exp_top(G, N, L, Acc) when is_list(L) ->
- exp_list(G, N, L, Acc);
-exp_top(G, N, M, Acc) when is_record(M, module) ->
- exp_list(G, N, ic_forms:get_body(M), Acc);
-exp_top(G, N, I, Acc) when is_record(I, interface) ->
- exp_list(G, N, ic_forms:get_body(I), Acc);
-exp_top(G, N, X, Acc) ->
- exp3(G, N, X, Acc).
-
-exp3(G, N, Op, Acc) when is_record(Op, op) ->
- FuncName = ic_forms:get_id(Op#op.id),
- Arity = length(ic:filter_params([in, inout], Op#op.params)) + 1 +
- count_extras(G, N, Op),
- [{FuncName, Arity} | Acc];
-exp3(G, N, A, Acc) when is_record(A, attr) ->
- Extra = count_extras(G, N, A),
- lists:foldr(fun(Id, Acc2) ->
- {Get, Set} = mk_attr_func_names([], ic_forms:get_id(Id)),
- case A#attr.readonly of
- {readonly, _} ->
- [{Get, 1 + Extra} | Acc2];
- _ ->
- [{Get, 1 + Extra}, {Set, 2 + Extra} | Acc2]
- end
- end, Acc, ic_forms:get_idlist(A));
-exp3(_G, _N, _X, Acc) ->
- Acc.
-
-exp_list(G, N, L, OrigAcc) ->
- lists:foldr(fun(X, Acc) ->
- exp3(G, N, X, Acc)
- end, OrigAcc, L).
-
-count_extras(G, N, Op) ->
- case {use_this(G, N, Op), use_from(G, N, Op)} of
- {[], []} ->
- 0;
- {[], _} ->
- 1;
- {_, []} ->
- 1;
- _ ->
- 2
- end.
-
-%%------------------------------------------------------------
-%%
-%% Emit stuff
-%%
-%% Low level generation primitives
-%%
-
-emit_function(_G, _N, _X, false, _, _, _, _, _) ->
- ok;
-emit_function(G, N, X, true, false, Name, InArgs, OutArgs, Reply) ->
- Fd = ic_genobj:stubfiled(G),
- This = use_this(G, N, Name),
- From = use_from(G, N, Name),
- State = ["State"],
- Vers = get_template_version(G),
- case OutArgs of
- [] ->
- ReplyString = create_string(Reply),
- emit_function_header(G, Fd, X, N, Name, create_extra(This, From, Vers),
- InArgs, length(InArgs), OutArgs, Reply,
- ReplyString, Vers),
- emit(Fd, "~p(~s) ->\n\t{reply, ~s, State}.\n\n",
- [ic_util:to_atom(Name), create_string(This ++ From ++ State ++ InArgs),
- ReplyString]);
- _ ->
- ReplyString = "{" ++ create_string(Reply ++ OutArgs) ++ "}",
- emit_function_header(G, Fd, X, N, Name, create_extra(This, From, Vers),
- InArgs, length(InArgs), OutArgs, Reply,
- ReplyString, Vers),
- emit(Fd, "~p(~s) ->\n\t{reply, ~s, State}.\n\n",
- [ic_util:to_atom(Name), create_string(This ++ From ++ State ++ InArgs),
- ReplyString])
- end;
-emit_function(G, N, X, true, true, Name, InArgs, _OutArgs, _Reply) ->
- Fd = ic_genobj:stubfiled(G),
- This = use_this(G, N, Name),
- State = ["State"],
- Vers = get_template_version(G),
- emit_function_header(G, Fd, X, N, Name, create_extra(This, [], Vers),
- InArgs, length(InArgs), "", "", "", Vers),
- emit(Fd, "~p(~s) ->\n\t{noreply, State}.\n\n",
- [ic_util:to_atom(Name), create_string(This ++ State ++ InArgs)]).
-
-create_string([]) ->
- "";
-create_string([{Name, _Type}|T]) ->
- Name ++ create_string2(T);
-create_string([Name|T]) ->
- Name ++ create_string2(T).
-
-create_string2([{Name, _Type}|T]) ->
- ", " ++ Name ++ create_string2(T);
-create_string2([Name|T]) ->
- ", " ++ Name ++ create_string2(T);
-create_string2([]) ->
- "".
-
-create_extra([], [], _Vers) ->
- {"State - term()", 1};
-create_extra([], _From, ?IC_FLAG_TEMPLATE_2) ->
- {"OE_From - term()\n%%% " ++ ?TAB ++ "State - term()", 2};
-create_extra([], _From, _Vers) ->
- {"OE_From - term()\n%% " ++ ?TAB ++ "State - term()", 2};
-create_extra(_This, [], ?IC_FLAG_TEMPLATE_2) ->
- {"OE_This - #objref{} (i.e., self())\n%%% " ++ ?TAB ++ "State - term()", 2};
-create_extra(_This, [], _Vers) ->
- {"OE_This - #objref{} (i.e., self())\n%% " ++ ?TAB ++ "State - term()", 2};
-create_extra(_This, _From, ?IC_FLAG_TEMPLATE_2) ->
- {"OE_This - #objref{} (i.e., self())\n%%% " ++ ?TAB ++
- "OE_From - term()\n%%% " ++ ?TAB ++ "State - term()", 3};
-create_extra(_This, _From, _Vers) ->
- {"OE_This - #objref{} (i.e., self())\n%% " ++ ?TAB ++
- "OE_From - term()\n%% " ++ ?TAB ++ "State - term()", 3}.
-
-use_this(G, N, OpName) ->
- FullOp = ic_util:to_colon([OpName|N]),
- FullIntf = ic_util:to_colon(N),
- case {ic_options:get_opt(G, {this, FullIntf}),
- ic_options:get_opt(G, {this, FullOp}),
- ic_options:get_opt(G, {this, true})} of
- {_, force_false, _} ->
- [];
- {force_false, false, _} ->
- [];
- {false, false, false} ->
- [];
- _ ->
- ["OE_This"]
- end.
-
-use_from(G, N, OpName) ->
- FullOp = ic_util:to_colon([OpName|N]),
- FullIntf = ic_util:to_colon(N),
- case {ic_options:get_opt(G, {from, FullIntf}),
- ic_options:get_opt(G, {from, FullOp}),
- ic_options:get_opt(G, {from, true})} of
- {_, force_false, _} ->
- [];
- {force_false, false, _} ->
- [];
- {false, false, false} ->
- [];
- _ ->
- ["OE_From"]
- end.
-
-
-emit_function_header(G, Fd, X, N, Name, {Extra, ExtraNo}, InP, Arity, OutP,
- Reply, ReplyString, ?IC_FLAG_TEMPLATE_2) ->
- emit(Fd,
- "%%% ----------------------------------------------------------------------\n"
- "%%% # ~p/~p\n"
- "%%% Input : ~s\n",
- [ic_util:to_atom(Name), (ExtraNo+Arity), Extra]),
- ic_code:type_expand_all(G, N, X, Fd, ?TAB2, InP),
- case Reply of
- ["ok"] ->
- emit(Fd, "%%% Output : ReturnValue = ~s\n", [ReplyString]);
- _ ->
- emit(Fd, "%%% Output : ReturnValue = ~s\n", [ReplyString]),
- ic_code:type_expand_all(G, N, X, Fd, "% ", Reply)
- end,
- ic_code:type_expand_all(G, N, X, Fd, ?TAB2, OutP),
- emit(Fd,
- "%%% Exceptions : ~s\n"
- "%%% Description: \n"
- "%%% ----------------------------------------------------------------------\n",
- [get_raises(X, ?IC_FLAG_TEMPLATE_2)]);
-emit_function_header(G, Fd, X, N, Name, {Extra, ExtraNo}, InP, Arity, OutP,
- Reply, ReplyString, Vers) ->
- emit(Fd,
- "%%----------------------------------------------------------------------\n"
- "%% Function : ~p/~p\n"
- "%% Arguments : ~s\n",
- [ic_util:to_atom(Name), (ExtraNo+Arity), Extra]),
- ic_code:type_expand_all(G, N, X, Fd, ?TAB, InP),
- case Reply of
- ["ok"] ->
- emit(Fd, "%% Returns : ReturnValue = ~s\n", [ReplyString]);
- _ ->
- emit(Fd, "%% Returns : ReturnValue = ~s\n", [ReplyString]),
- ic_code:type_expand_all(G, N, X, Fd, " ", Reply)
- end,
- ic_code:type_expand_all(G, N, X, Fd, ?TAB, OutP),
- emit(Fd,
- "%% Raises : ~s\n"
- "%% Description: \n"
- "%%----------------------------------------------------------------------\n",
- [get_raises(X, Vers)]).
-
-get_raises(#op{raises = []}, _Vers) ->
- "";
-get_raises(#op{raises = ExcList}, Vers) ->
- get_raises2(ExcList, [], Vers);
-get_raises(_X, _Vers) ->
- [].
-
-get_raises2([H], Acc, _Vers) ->
- lists:flatten(lists:reverse([ic_util:to_colon(H)|Acc]));
-get_raises2([H|T], Acc, ?IC_FLAG_TEMPLATE_2) ->
- get_raises2(T, ["\n%%% ", ic_util:to_colon(H) |Acc],
- ?IC_FLAG_TEMPLATE_2);
-get_raises2([H|T], Acc, _Vers) ->
- get_raises2(T, ["\n%% ", ic_util:to_colon(H) |Acc], _Vers).
-
diff --git a/lib/ic/src/ic_erlbe.erl b/lib/ic/src/ic_erlbe.erl
deleted file mode 100644
index d315a17e7c..0000000000
--- a/lib/ic/src/ic_erlbe.erl
+++ /dev/null
@@ -1,1142 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(ic_erlbe).
-
-
--export([do_gen/3]).
-%%------------------------------------------------------------
-%%
-%% Internal stuff
-%%
-%%------------------------------------------------------------
-
--export([unfold/1, mk_attr_func_names/2]).
-
-
--import(ic_util, [mk_name/2, mk_var/1, mk_oe_name/2, to_atom/1, to_list/1]).
--import(ic_forms, [get_id/1, get_id2/1, get_body/1, is_oneway/1]).
--import(ic_codegen, [emit/2, emit/3, nl/1]).
--import(ic_options, [get_opt/2]).
-
--import(lists, [foreach/2, foldr/3, map/2]).
-
-
--include("icforms.hrl").
--include("ic.hrl").
-
--include_lib("stdlib/include/erl_compile.hrl").
-
-
-%%------------------------------------------------------------
-%%
-%% Generate the client side Erlang stubs.
-%%
-%% Each module is generated to a separate file.
-%%
-%% Export declarations for all interface functions must be
-%% generated. Each function then needs to generate a function head and
-%% a body. IDL parameters must be converted into Erlang parameters
-%% (variables, capitalised) and a type signature list must be
-%% generated (for later encode/decode).
-%%
-%%------------------------------------------------------------
-do_gen(G, File, Form) ->
- GT = get_opt(G, be),
- G2 = ic_file:filename_push(G, [], mk_oe_name(G,
- ic_file:remove_ext(to_list(File))),
- erlang),
- Light = ic_options:get_opt(G, light_ifr),
- R = if
- GT == erl_corba, Light == false ->
- case ic_genobj:is_stubfile_open(G2) of
- true ->
- emit(ic_genobj:stubfiled(G2), "-include_lib(\"~s/include/~s\").\n\n",
- [?ORBNAME, ?IFRTYPESHRL]);
- false -> ok
- end,
- gen_head(G2, [], Form),
- ic_codegen:export(ic_genobj:stubfiled(G2),
- [{ictk:register_name(G2), 0},
- {ictk:unregister_name(G2), 0},
- {oe_get_module,5},
- {oe_dependency,0}]),
- R0= gen(G2, [], Form),
- ictk:reg_gen(G2, [], Form),
- ictk:unreg_gen(G2, [], Form), % "new" unreg_gen/3
- genDependency(G2), % creates code for dependency list
- R0;
- GT == erl_corba, Light == true ->
- case ic_genobj:is_stubfile_open(G2) of
- true ->
- emit(ic_genobj:stubfiled(G2), "-include_lib(\"~s/include/~s\").\n\n",
- [?ORBNAME, ?IFRTYPESHRL]);
- false -> ok
- end,
- gen_head(G2, [], Form),
- ic_codegen:export(ic_genobj:stubfiled(G2),
- [{ictk:register_name(G2), 0},
- {ictk:register_name(G2), 1},
- {ictk:unregister_name(G2), 0},
- {ictk:unregister_name(G2), 1}]),
- R0= gen(G2, [], Form),
- ictk:reg_gen(G2, [], Form),
- ictk:unreg_gen(G2, [], Form), % "new" unreg_gen/3
- R0;
- true ->
- gen_head(G2, [], Form),
- gen(G2, [], Form)
- end,
- ic_file:filename_pop(G2, erlang),
- R.
-
-
-gen(G, N, [X|Xs]) when is_record(X, preproc) ->
- NewG = ic:handle_preproc(G, N, X#preproc.cat, X),
- gen(NewG, N, Xs);
-
-gen(G, N, [X|Xs]) when is_record(X, module) ->
- CD = ic_code:codeDirective(G,X),
- G2 = ic_file:filename_push(G, N, X, CD),
- N2 = [get_id2(X) | N],
- gen_head(G2, N2, X),
- gen(G2, N2, get_body(X)),
- G3 = ic_file:filename_pop(G2, CD),
- gen(G3, N, Xs);
-
-gen(G, N, [X|Xs]) when is_record(X, interface) ->
- G2 = ic_file:filename_push(G, N, X, erlang),
- N2 = [get_id2(X) | N],
- gen_head(G2, N2, X),
- gen(G2, N2, get_body(X)),
- foreach(fun({_Name, Body}) -> gen(G2, N2, Body) end,
- X#interface.inherit_body),
- gen_serv(G2, N, X),
- G3 = ic_file:filename_pop(G2, erlang),
- gen(G3, N, Xs);
-
-gen(G, N, [X|Xs]) when is_record(X, const) ->
-% N2 = [get_id2(X) | N],
- emit_constant_func(G, X#const.id, X#const.val),
- gen(G, N, Xs); %% N2 or N?
-
-gen(G, N, [X|Xs]) when is_record(X, op) ->
- {Name, ArgNames, TypeList, OutArgs} = extract_info(G, N, X),
- emit_stub_func(G, N, X, Name, ArgNames, TypeList, OutArgs,
- is_oneway(X), get_opt(G, be)),
- gen(G, N, Xs);
-
-gen(G, N, [X|Xs]) when is_record(X, attr) ->
- emit_attr(G, N, X, fun emit_stub_func/9),
- gen(G, N, Xs);
-
-gen(G, N, [X|Xs]) when is_record(X, except) ->
- icstruct:except_gen(G, N, X, erlang),
- gen(G, N, Xs);
-
-gen(G, N, [X|Xs]) ->
- case may_contain_structs(X) of
- true -> icstruct:struct_gen(G, N, X, erlang);
- false -> ok
- end,
- gen(G, N, Xs);
-
-gen(_G, _N, []) -> ok.
-
-
-may_contain_structs(X) when is_record(X, typedef) -> true;
-may_contain_structs(X) when is_record(X, struct) -> true;
-may_contain_structs(X) when is_record(X, union) -> true;
-may_contain_structs(_X) -> false.
-
-
-
-%%--------------------------------------------------------------------
-%%
-%% Generate the server side (handle_call and handle_cast)
-%%
-
-gen_serv(G, N, X) ->
- case ic_genobj:is_stubfile_open(G) of
- true ->
- GT = get_opt(G, be),
- gen_oe_is_a(G, N, X, GT),
- N2 = [get_id2(X) | N],
- gen_oe_tc(G, N2, X, GT),
-
- emit_serv_std(GT, G, N, X),
-
- gen_calls(G, N2, get_body(X)),
- lists:foreach(fun({_Name, Body}) ->
- gen_calls(G, N2, Body) end,
- X#interface.inherit_body),
- gen_end_of_call(GT, G),
-
- gen_casts(G, N2, get_body(X)),
- lists:foreach(fun({_Name, Body}) ->
- gen_casts(G, N2, Body) end,
- X#interface.inherit_body),
- gen_end_of_cast(GT, G),
- emit_skel_footer(GT, G, N, X); % Note N instead of N2
- false ->
- ok
- end.
-
-gen_oe_is_a(G, N, X, erl_corba) when is_record(X, interface) ->
- Fd = ic_genobj:stubfiled(G),
- ic_codegen:mcomment(Fd, ["Inherited Interfaces"]),
- emit(Fd, "oe_is_a(~p) -> true;\n", [ictk:get_IR_ID(G, N, X)]),
- lists:foreach(fun(ScopedName) ->
- emit(Fd, "oe_is_a(~p) -> true;\n",
- [ic_pragma:scope2id(G, ScopedName)])
- end, X#interface.inherit),
- emit(Fd, "oe_is_a(_) -> false.\n"),
- nl(Fd),
- ok;
-gen_oe_is_a(_G, _N, _X, _BE) -> ok.
-
-
-%% Generates the oe_tc function
-gen_oe_tc(G, N, X, erl_corba) ->
- Fd = ic_genobj:stubfiled(G),
- ic_codegen:mcomment(Fd, ["Interface TypeCode"]),
- LocalInterface = gen_oe_tc2(G, N, get_body(X), Fd, []),
- CompleteInterface =
- lists:foldl(fun({Name, Body}, FunAcc) ->
- AName = ic_util:to_atom(ic_util:to_undersc(Name)),
- gen_oe_tc3(G, AName, Body, Fd, FunAcc)
- end, LocalInterface, X#interface.inherit_body),
- emit(Fd, "oe_tc(_) -> undefined.\n"),
- nl(Fd),
- emit(Fd, "oe_get_interface() -> \n\t["),
- emit_oe_get_interface(Fd, CompleteInterface),
- nl(Fd),
- ok;
-gen_oe_tc(_, _, _, _) ->
- ok.
-
-emit_oe_get_interface(Fd, []) ->
- emit(Fd, "].\n");
-emit_oe_get_interface(Fd, [Item]) ->
- emit(Fd, "~s].\n", [lists:flatten(Item)]);
-emit_oe_get_interface(Fd, [H|T]) ->
- emit(Fd, "~s,\n\t", [lists:flatten(H)]),
- emit_oe_get_interface(Fd, T).
-
-gen_oe_tc2(_,_,[],_, Acc) ->
- Acc;
-gen_oe_tc2(G, N, [X|Rest], Fd, Acc) when is_record(X, op) ->
- R = ic_forms:get_tk(X),
- IN = lists:map(fun(P) -> ic_forms:get_tk(P) end,
- ic:filter_params([in, inout], X#op.params)),
- OUT = lists:map(fun(P) -> ic_forms:get_tk(P) end,
- ic:filter_params([out, inout], X#op.params)),
- Function = get_id2(X),
- FunctionAtom = ic_util:to_atom(Function),
- emit(Fd, "oe_tc(~p) -> \n\t~p;\n",[FunctionAtom, {R, IN, OUT}]),
- GI = io_lib:format("{~p, oe_tc(~p)}",[Function, FunctionAtom]),
- gen_oe_tc2(G, N, Rest, Fd, [GI|Acc]);
-
-gen_oe_tc2(G, N, [X|Rest], Fd, Acc) when is_record(X, attr) ->
- {GetT, SetT} = mk_attr_func_types([], X),
- NewAcc =
- lists:foldl(fun(Id, FunAcc) ->
- {Get, Set} = mk_attr_func_names([], get_id(Id)),
- GetAttrAtom = ic_util:to_atom(Get),
- emit(Fd, "oe_tc(~p) -> \n\t~p;\n",
- [GetAttrAtom, GetT]),
- case X#attr.readonly of
- {readonly, _} ->
- GI = io_lib:format("{~p, oe_tc(~p)}",
- [Get, GetAttrAtom]),
- [GI|FunAcc];
- _ ->
- SetAttrAtom = ic_util:to_atom(Set),
-
- emit(Fd, "oe_tc(~p) -> \n\t~p;\n",
- [SetAttrAtom, SetT]),
- GetGI = io_lib:format("{~p, oe_tc(~p)}",
- [Get, GetAttrAtom]),
- SetGI = io_lib:format("{~p, oe_tc(~p)}",
- [Set, SetAttrAtom]),
- [GetGI, SetGI|FunAcc]
- end
- end, Acc, ic_forms:get_idlist(X)),
- gen_oe_tc2(G, N, Rest, Fd, NewAcc);
-
-gen_oe_tc2(G,N,[_X|Rest], Fd, Acc) ->
- gen_oe_tc2(G,N,Rest, Fd, Acc).
-
-
-gen_oe_tc3(_,_,[],_, Acc) ->
- Acc;
-gen_oe_tc3(G, N, [X|Rest], Fd, Acc) when is_record(X, op) ->
- Function = get_id2(X),
- FunctionAtom = ic_util:to_atom(get_id2(X)),
- GI = io_lib:format("{~p, ~p:oe_tc(~p)}",[Function, N, FunctionAtom]),
- emit(Fd, "oe_tc(~p) -> ~p:oe_tc(~p);\n",
- [FunctionAtom, N, FunctionAtom]),
- gen_oe_tc3(G, N, Rest, Fd, [GI|Acc]);
-
-gen_oe_tc3(G, N, [X|Rest], Fd, Acc) when is_record(X, attr) ->
- NewAcc = lists:foldl(fun(Id, FunAcc) ->
- {Get, Set} = mk_attr_func_names([], get_id(Id)),
- GetAttrAtom = ic_util:to_atom(Get),
- emit(Fd, "oe_tc(~p) -> ~p:oe_tc(~p);\n",
- [GetAttrAtom, N, GetAttrAtom]),
- case X#attr.readonly of
- {readonly, _} ->
- [io_lib:format("{~p, ~p:oe_tc(~p)}",
- [Get, N, GetAttrAtom])|FunAcc];
- _ ->
- SetAttrAtom = ic_util:to_atom(Set),
- emit(Fd, "oe_tc(~p) -> ~p:oe_tc(~p);\n",
- [SetAttrAtom, N, SetAttrAtom]),
- [io_lib:format("{~p, ~p:oe_tc(~p)}",
- [Get, N, GetAttrAtom]),
- io_lib:format("{~p, ~p:oe_tc(~p)}",
- [Set, N, SetAttrAtom])|FunAcc]
- end
- end, Acc, ic_forms:get_idlist(X)),
- gen_oe_tc3(G, N, Rest, Fd, NewAcc);
-
-gen_oe_tc3(G,N,[_X|Rest], Fd, Acc) ->
- gen_oe_tc3(G,N,Rest, Fd, Acc).
-
-gen_calls(G, N, [X|Xs]) when is_record(X, op) ->
- case is_oneway(X) of
- false ->
- {Name, ArgNames, TypeList, OutArgs} = extract_info(G, N, X),
- emit_skel_func(G, N, X, Name, ArgNames, TypeList, OutArgs, false,
- get_opt(G, be)),
- gen_calls(G, N, Xs);
- true ->
- gen_calls(G, N, Xs)
- end;
-
-gen_calls(G, N, [X|Xs]) when is_record(X, attr) ->
- emit_attr(G, N, X, fun emit_skel_func/9),
- gen_calls(G, N, Xs);
-
-gen_calls(G, N, [_X|Xs]) -> gen_calls(G, N, Xs);
-gen_calls(_G, _N, []) -> ok.
-
-gen_casts(G, N, [X|Xs]) when is_record(X, op) ->
- case is_oneway(X) of
- true ->
- {Name, ArgNames, TypeList, OutArgs} = extract_info(G, N, X),
- emit_skel_func(G, N, X, Name, ArgNames, TypeList, OutArgs, true,
- get_opt(G, be)),
- gen_casts(G, N, Xs);
- false ->
- gen_casts(G, N, Xs)
- end;
-
-gen_casts(G, N, [_X|Xs]) -> gen_casts(G, N, Xs);
-gen_casts(_G, _N, []) -> ok.
-
-emit_attr(G, N, X, F) ->
- XX = #id_of{type=X},
- BE = get_opt(G, be),
- {GetType, SetType} = mk_attr_func_types(N, X),
- lists:foreach(fun(Id) ->
- X2 = XX#id_of{id=Id},
- {Get, Set} = mk_attr_func_names(N, get_id(Id)),
- F(G, N, X2, Get, [], GetType, [],
- is_oneway(X2), BE),
- case X#attr.readonly of
- {readonly, _} -> ok;
- _ ->
- F(G, N, X2, Set, [mk_name(G, "Value")],
- SetType, [],
- is_oneway(X2), BE)
- end end, ic_forms:get_idlist(X)).
-
-
-extract_info(G, _N, X) when is_record(X, op) ->
- Name = get_id2(X),
- InArgs = ic:filter_params([in,inout], X#op.params),
- OutArgs = ic:filter_params([out,inout], X#op.params),
- ArgNames = mk_erl_vars(G, InArgs),
- TypeList = {ic_forms:get_tk(X),
- map(fun(Y) -> ic_forms:get_tk(Y) end, InArgs),
- map(fun(Y) -> ic_forms:get_tk(Y) end, OutArgs)
- },
- {Name, ArgNames, TypeList, OutArgs}.
-
-
-
-%% This function generates the standard functions of an object
-%% gen_server
-emit_serv_std(erl_corba, G, N, X) ->
- Fd = ic_genobj:stubfiled(G),
- Impl = ic_genobj:impl(G),
- TypeID = ictk:get_IR_ID(G, N, X),
-
- nl(Fd), nl(Fd), nl(Fd),
- ic_codegen:mcomment(Fd, ["Object server implementation."]),
- nl(Fd), nl(Fd),
- ic_codegen:mcomment(Fd, ["Function for fetching the interface type ID."]),
- nl(Fd),
- emit(Fd, "typeID() ->\n"),
- emit(Fd, " \"~s\".\n", [TypeID]),
- nl(Fd), nl(Fd),
- ic_codegen:mcomment(Fd, ["Object creation functions."]),
- nl(Fd),
- emit(Fd, "oe_create() ->\n"),
- emit(Fd, " corba:create(?MODULE, \"~s\").\n", [TypeID]),
- nl(Fd),
- emit(Fd, "oe_create_link() ->\n"),
- emit(Fd, " corba:create_link(?MODULE, \"~s\").\n", [TypeID]),
- nl(Fd),
- emit(Fd, "oe_create(Env) ->\n"),
- emit(Fd, " corba:create(?MODULE, \"~s\", Env).\n", [TypeID]),
- nl(Fd),
- emit(Fd, "oe_create_link(Env) ->\n"),
- emit(Fd, " corba:create_link(?MODULE, \"~s\", Env).\n", [TypeID]),
- nl(Fd),
- emit(Fd, "oe_create(Env, RegName) ->\n"),
- emit(Fd, " corba:create(?MODULE, \"~s\", Env, RegName).\n", [TypeID]),
- nl(Fd),
- emit(Fd, "oe_create_link(Env, RegName) ->\n"),
- emit(Fd, " corba:create_link(?MODULE, \"~s\", Env, RegName).\n", [TypeID]),
- nl(Fd),
- ic_codegen:mcomment(Fd, ["Init & terminate functions."]),
- nl(Fd),
- emit(Fd, "init(Env) ->\n"),
- ic_codegen:comment(Fd, "Call to implementation init"),
- emit(Fd, " corba:handle_init(~p, Env).\n", [to_atom(Impl)]),
- nl(Fd),
- emit(Fd, "terminate(Reason, State) ->\n"),
- emit(Fd, " corba:handle_terminate(~p, Reason, State).\n",
- [to_atom(Impl)]),
- nl(Fd), nl(Fd),
- Fd;
-emit_serv_std(erl_genserv, G, N, X) ->
- Fd = ic_genobj:stubfiled(G),
- Impl = ic_genobj:impl(G),
- TypeID = ictk:get_IR_ID(G, N, X),
-
- nl(Fd), nl(Fd), nl(Fd),
- ic_codegen:mcomment(Fd, ["Server implementation."]),
- nl(Fd), nl(Fd),
- ic_codegen:mcomment(Fd, ["Function for fetching the interface type ID."]),
- nl(Fd),
- emit(Fd, "typeID() ->\n"),
- emit(Fd, " \"~s\".\n", [TypeID]),
- nl(Fd), nl(Fd),
- ic_codegen:mcomment(Fd, ["Server creation functions."]),
- nl(Fd),
- emit(Fd, "oe_create() ->\n"),
- emit(Fd, " start([], []).\n", []),
- nl(Fd),
- emit(Fd, "oe_create_link() ->\n"),
- emit(Fd, " start_link([], []).\n", []),
- nl(Fd),
- emit(Fd, "oe_create(Env) ->\n"),
- emit(Fd, " start(Env, []).\n", []),
- nl(Fd),
- emit(Fd, "oe_create_link(Env) ->\n"),
- emit(Fd, " start_link(Env, []).\n", []),
- nl(Fd),
- emit(Fd, "oe_create(Env, RegName) ->\n"),
- emit(Fd, " start(RegName, Env, []).\n", []),
- nl(Fd),
- emit(Fd, "oe_create_link(Env, RegName) ->\n"),
- emit(Fd, " start_link(RegName, Env, []).\n", []),
- nl(Fd),
- ic_codegen:mcomment(Fd, ["Start functions."]),
- nl(Fd),
- emit(Fd, "start(Env, Opt) ->\n"),
- emit(Fd, " gen_server:start(?MODULE, Env, Opt).\n"),
- nl(Fd),
- emit(Fd, "start_link(Env, Opt) ->\n"),
- emit(Fd, " gen_server:start_link(?MODULE, Env, Opt).\n"),
- nl(Fd),
- emit(Fd, "start(RegName, Env, Opt) ->\n"),
- emit(Fd, " gen_server:start(RegName, ?MODULE, Env, Opt).\n"),
- nl(Fd),
- emit(Fd, "start_link(RegName, Env, Opt) ->\n"),
- emit(Fd, " gen_server:start_link(RegName, ?MODULE, Env, Opt).\n"),
- nl(Fd),
- ic_codegen:comment(Fd, "Standard gen_server termination"),
- emit(Fd, "stop(OE_THIS) ->\n"),
- emit(Fd, " gen_server:cast(OE_THIS,stop).\n"),
- nl(Fd),
- ic_codegen:comment(Fd, "Call to implementation init"),
- emit(Fd, "init(Env) ->\n"),
- emit(Fd, " ~p:~p(Env).\n", [to_atom(Impl), init]),
- nl(Fd),
- emit(Fd, "terminate(Reason, State) ->\n"),
- emit(Fd, " ~p:~p(Reason, State).\n",
- [to_atom(Impl), terminate]),
- nl(Fd), nl(Fd),
- Fd.
-
-gen_end_of_call(erl_corba, G) ->
- Fd = ic_genobj:stubfiled(G),
- nl(Fd), nl(Fd),
- ic_codegen:mcomment_light(Fd, ["Standard gen_server call handle"]),
- emit(Fd, "handle_call(stop, _, State) ->\n"),
- emit(Fd, " {stop, normal, ok, State}"),
- case get_opt(G, serv_last_call) of
- exception ->
- emit(Fd, ";\n"),
- nl(Fd),
- emit(Fd, "handle_call(_, _, State) ->\n"),
- emit(Fd, " {reply, catch corba:raise(#'BAD_OPERATION'{minor=1163001857, completion_status='COMPLETED_NO'}), State}.\n");
- exit ->
- emit(Fd, ".\n"),
- nl(Fd),
- nl(Fd)
- end,
- ok;
-gen_end_of_call(erl_genserv, G) ->
- Fd = ic_genobj:stubfiled(G),
- nl(Fd), nl(Fd),
- ic_codegen:mcomment_light(Fd, ["Standard gen_server call handle"]),
- emit(Fd, "handle_call(stop, _, State) ->\n"),
- emit(Fd, " {stop, normal, ok, State}"),
- emit(Fd, ".\n"),
- nl(Fd), nl(Fd),
- ok.
-
-gen_end_of_cast(erl_corba, G) ->
- Fd = ic_genobj:stubfiled(G),
- nl(Fd), nl(Fd),
- ic_codegen:mcomment_light(Fd, ["Standard gen_server cast handle"]),
- emit(Fd, "handle_cast(stop, State) ->\n"),
- emit(Fd, " {stop, normal, State}"),
- case get_opt(G, serv_last_call) of
- exception ->
- emit(Fd, ";\n"),
- nl(Fd),
- emit(Fd, "handle_cast(_, State) ->\n"),
- emit(Fd, " {noreply, State}.\n");
- exit ->
- emit(Fd, ".\n"),
- nl(Fd), nl(Fd)
- end,
- ok;
-gen_end_of_cast(erl_genserv, G) ->
- Fd = ic_genobj:stubfiled(G),
- nl(Fd), nl(Fd),
- ic_codegen:mcomment_light(Fd, ["Standard gen_server cast handle"]),
- emit(Fd, "handle_cast(stop, State) ->\n"),
- emit(Fd, " {stop, normal, State}"),
- emit(Fd, ".\n"),
- nl(Fd), nl(Fd),
- ok.
-
-emit_skel_footer(erl_corba, G, N, X) ->
- Fd = ic_genobj:stubfiled(G),
- nl(Fd), nl(Fd),
- ic_codegen:mcomment_light(Fd, ["Standard gen_server handles"]),
- case use_impl_handle_info(G, N, X) of
- true ->
- emit(Fd, "handle_info(Info, State) ->\n"),
- emit(Fd, " corba:handle_info(~p, Info, State).\n\n",
- [list_to_atom(ic_genobj:impl(G))]);
- false ->
- emit(Fd, "handle_info(_, State) ->\n"),
- emit(Fd, " {noreply, State}.\n\n")
- end,
- nl(Fd),
- case get_opt(G, no_codechange) of
- false ->
- emit(Fd, "code_change(OldVsn, State, Extra) ->\n"),
- emit(Fd, " corba:handle_code_change(~p, OldVsn, State, Extra).\n\n",
- [list_to_atom(ic_genobj:impl(G))]);
- true ->
- emit(Fd, "code_change(_, State, _) ->\n"),
- emit(Fd, " {ok, State}.\n\n")
- end,
- ok;
-emit_skel_footer(erl_genserv, G, N, X) ->
- Fd = ic_genobj:stubfiled(G),
- nl(Fd), nl(Fd),
- ic_codegen:mcomment_light(Fd, ["Standard gen_server handles"]),
- case use_impl_handle_info(G, N, X) of
- true ->
- emit(Fd, "handle_info(Info, State) ->\n"),
- emit(Fd, " ~p:handle_info(Info, State).\n\n",
- [list_to_atom(ic_genobj:impl(G))]);
- false ->
- emit(Fd, "handle_info(_, State) ->\n"),
- emit(Fd, " {noreply, State}.\n\n")
- end,
- nl(Fd), nl(Fd),
- case get_opt(G, no_codechange) of
- false ->
- emit(Fd, "code_change(OldVsn, State, Extra) ->\n"),
- emit(Fd, " ~p:code_change(OldVsn, State, Extra).\n\n",
- [list_to_atom(ic_genobj:impl(G))]);
- true ->
- emit(Fd, "code_change(_, State, _) ->\n"),
- emit(Fd, " {ok, State}.\n\n")
- end,
- ok.
-
-
-use_impl_handle_info(G, N, X) ->
- FullName = ic_util:to_colon([get_id2(X) | N]),
- case {get_opt(G, {handle_info, true}), get_opt(G, {handle_info, FullName})} of
- {_, force_false} -> false;
- {false, false} -> false;
- _ -> true
- end.
-
-use_timeout(G, N, _X) ->
- FullName = ic_util:to_colon(N),
- case {get_opt(G, {timeout, true}), get_opt(G, {timeout, FullName})} of
- {_, force_false} -> false;
- {false, false} -> false;
- _ -> true
- end.
-
-use_precond(G, N, X) ->
- FullName = ic_util:to_colon([get_id2(X) | N]),
- case get_opt(G, {precond, FullName}) of
- false ->
- InterfaceName = ic_util:to_colon(N),
- case get_opt(G, {precond, InterfaceName}) of
- false ->
- case get_opt(G, precond) of
- false -> false;
- V2 -> V2
- end;
- V2 -> V2
- end;
- V1 -> V1
- end.
-
-use_postcond(G, N, X) ->
- FullName = ic_util:to_colon([get_id2(X) | N]),
- case get_opt(G, {postcond, FullName}) of
- false ->
- InterfaceName = ic_util:to_colon(N),
- case get_opt(G, {postcond, InterfaceName}) of
- false ->
- case get_opt(G, postcond) of
- false -> false;
- V3 -> V3
- end;
- V2 -> V2
- end;
- V1 -> V1
- end.
-
-
-%%------------------------------------------------------------
-%%
-%% Export stuff
-%%
-%% Gathering of all names that should be exported from a stub
-%% file.
-%%
-
-
-gen_head_special(G, N, X) when is_record(X, interface) ->
- Fd = ic_genobj:stubfiled(G),
-
- foreach(fun({Name, Body}) ->
- ic_codegen:comment(Fd, "Exports from ~p",
- [ic_util:to_colon(Name)]),
- ic_codegen:export(Fd, exp_top(G, N, Body, [], get_opt(G, be))),
- nl(Fd)
- end, X#interface.inherit_body),
-
- ic_codegen:comment(Fd, "Type identification function"),
- ic_codegen:export(Fd, [{typeID, 0}]),
- nl(Fd),
- ic_codegen:comment(Fd, "Used to start server"),
- ic_codegen:export(Fd, [{oe_create, 0}, {oe_create_link, 0}, {oe_create, 1}, {oe_create_link, 1},
- {oe_create, 2}, {oe_create_link, 2}]),
- nl(Fd),
- case get_opt(G, be) of
- erl_corba ->
- ic_codegen:comment(Fd, "TypeCode Functions and inheritance"),
- ic_codegen:export(Fd, [{oe_tc, 1}, {oe_is_a, 1}, {oe_get_interface, 0}]);
- _ ->
- ic_codegen:export(Fd, [{start, 2}, {start_link, 3}])
- end,
- nl(Fd),
- ic_codegen:comment(Fd, "gen server export stuff"),
- emit(Fd, "-behaviour(gen_server).\n"),
-
- case get_opt(G, be) of
- erl_genserv -> %% stop/1 is only for erl_genserv backend
- ic_codegen:export(Fd, [{stop, 1}, {init, 1}, {terminate, 2}, {handle_call, 3},
- {handle_cast, 2}, {handle_info, 2}, {code_change, 3}]);
- _ ->
- ic_codegen:export(Fd, [{init, 1}, {terminate, 2}, {handle_call, 3},
- {handle_cast, 2}, {handle_info, 2}, {code_change, 3}])
- end,
-
- case get_opt(G, be) of
- erl_corba ->
- nl(Fd),
- emit(Fd, "-include_lib(\"~s/include/~s\").\n", [?ORBNAME, ?CORBAHRL]);
- _ ->
- ok
- end,
- nl(Fd), nl(Fd),
- ic_codegen:mcomment(Fd, ["Object interface functions."]),
- nl(Fd), nl(Fd), nl(Fd),
- Fd;
-gen_head_special(_G, _N, _X) -> ok.
-
-
-
-%% Shall generate all export declarations
-gen_head(G, N, X) ->
- case ic_genobj:is_stubfile_open(G) of
- true ->
- F = ic_genobj:stubfiled(G),
- ic_codegen:comment(F, "Interface functions"),
- ic_codegen:export(F, exp_top(G, N, X, [], get_opt(G, be))),
- nl(F),
- gen_head_special(G, N, X);
- false -> ok
- end.
-
-exp_top(_G, _N, X, Acc, _) when element(1, X) == preproc ->
- Acc;
-exp_top(G, N, L, Acc, BE) when is_list(L) ->
- exp_list(G, N, L, Acc, BE);
-exp_top(G, N, M, Acc, BE) when is_record(M, module) ->
- exp_list(G, N, get_body(M), Acc, BE);
-exp_top(G, N, I, Acc, BE) when is_record(I, interface) ->
- exp_list(G, N, get_body(I), Acc, BE);
-exp_top(G, N, X, Acc, BE) ->
- exp3(G, N, X, Acc, BE).
-
-exp3(_G, _N, C, Acc, _BE) when is_record(C, const) ->
- [{get_id(C#const.id), 0} | Acc];
-exp3(_G, _N, Op, Acc, erl_corba) when is_record(Op, op) ->
- FuncName = get_id(Op#op.id),
- Arity = length(ic:filter_params([in, inout], Op#op.params)) + 1,
- [{FuncName, Arity}, {FuncName, Arity+1} | Acc];
-exp3(G, N, Op, Acc, _BE) when is_record(Op, op) ->
- FuncName = get_id(Op#op.id),
- Arity =
- case use_timeout(G,N,Op) of
- true ->
- %% NO TimeOut on ONEWAYS here !!!!
- case is_oneway(Op) of
- true ->
- length(ic:filter_params([in, inout], Op#op.params)) + 1;
- false ->
- length(ic:filter_params([in, inout], Op#op.params)) + 2
- end;
- false ->
- length(ic:filter_params([in, inout], Op#op.params)) + 1
- end,
- [{FuncName, Arity} | Acc];
-
-exp3(_G, _N, A, Acc, erl_corba) when is_record(A, attr) ->
- lists:foldr(fun(Id, Acc2) ->
- {Get, Set} = mk_attr_func_names([], get_id(Id)),
- case A#attr.readonly of
- {readonly, _} -> [{Get, 1}, {Get, 2} | Acc2];
- _ -> [{Get, 1}, {Get, 2},
- {Set, 2}, {Set, 3} | Acc2]
- end end, Acc, ic_forms:get_idlist(A));
-exp3(_G, _N, A, Acc, _BE) when is_record(A, attr) ->
- lists:foldr(fun(Id, Acc2) ->
- {Get, Set} = mk_attr_func_names([], get_id(Id)),
- case A#attr.readonly of
- {readonly, _} -> [{Get, 1} | Acc2];
- _ -> [{Get, 1}, {Set, 2} | Acc2]
- end end, Acc, ic_forms:get_idlist(A));
-
-exp3(_G, _N, _X, Acc, _BE) -> Acc.
-
-exp_list(G, N, L, OrigAcc, BE) ->
- lists:foldr(fun(X, Acc) -> exp3(G, N, X, Acc, BE) end, OrigAcc, L).
-
-
-
-
-%%------------------------------------------------------------
-%%
-%% Emit stuff
-%%
-%% Low level generation primitives
-%%
-
-emit_stub_func(G, N, X, Name, ArgNames, _TypeList, OutArgs, Oneway, Backend) ->
- case ic_genobj:is_stubfile_open(G) of
- false ->
- ok;
- true ->
- Fd = ic_genobj:stubfiled(G),
- StubName = list_to_atom(Name),
- UsingTimeout = use_timeout(G, N, X),
- Timeout = case UsingTimeout of
- true ->
- mk_name(G, "Timeout");
- false ->
- "infinity"
- end,
- Options = mk_name(G, "Options"),
- This = mk_name(G, "THIS"),
- CallOrCast =
- case is_oneway(X) of
- true -> ?CAST;
- _ -> ?CALL
- end,
- emit_op_comment(G, Fd, X, StubName, ArgNames, OutArgs),
- case Backend of
- erl_corba ->
- emit(Fd, "~p(~s) ->\n",
- [StubName, mk_list([This | ArgNames])]),
- emit(Fd, " ~s:~s(~s, ~p, [~s], ?MODULE).\n\n",
- [?CORBAMOD, CallOrCast, This, StubName, mk_list(ArgNames)]),
- emit(Fd, "~p(~s) ->\n",
- [StubName, mk_list([This, Options| ArgNames])]),
- emit(Fd, " ~s:~s(~s, ~p, [~s], ?MODULE, ~s).\n\n",
- [?CORBAMOD, CallOrCast, This, StubName, mk_list(ArgNames),
- Options]);
- _ ->
- FunName = case ic_options:get_opt(G, scoped_op_calls) of
- true ->
- list_to_atom(ic_util:to_undersc([Name | N]));
- false ->
- StubName
- end,
- %% NO TimeOut on ONEWAYS here !!!!
- case Oneway of
- true ->
- emit(Fd, "~p(~s) ->\n",
- [StubName, mk_list([This | ArgNames])]);
- false ->
- case UsingTimeout of
- true ->
- emit(Fd, "~p(~s) ->\n",
- [StubName, mk_list([This, Timeout| ArgNames])]);
- false ->
- emit(Fd, "~p(~s) ->\n",
- [StubName, mk_list([This | ArgNames])])
- end
- end,
-
- %% NO TimeOut on ONEWAYS here !!!!
- if
- length(ArgNames) == 0 ->
- case is_oneway(X) of
- true ->
- emit(Fd, " ~s:~s(~s, ~p).\n\n",
- [?GENSERVMOD, CallOrCast, This, FunName]);
- false ->
- emit(Fd, " ~s:~s(~s, ~p, ~s).\n\n",
- [?GENSERVMOD, CallOrCast, This, FunName, Timeout])
- end;
- true ->
- case is_oneway(X) of
- true ->
- emit(Fd, " ~s:~s(~s, {~p, ~s}).\n\n",
- [?GENSERVMOD, CallOrCast, This, FunName,
- mk_list(ArgNames)]);
- false ->
- emit(Fd, " ~s:~s(~s, {~p, ~s}, ~s).\n\n",
- [?GENSERVMOD, CallOrCast, This, FunName,
- mk_list(ArgNames), Timeout])
- end
- end
- end
- end.
-
-emit_skel_func(G, N, X, OpName, ArgNames, TypeList, OutArgs, Oneway, Backend) ->
- case ic_genobj:is_stubfile_open(G) of
- false ->
- ok;
- true ->
- emit_skel_func_helper(G, N, X, OpName, ArgNames, TypeList, OutArgs,
- Oneway, Backend)
- end.
-
-emit_skel_func_helper(G, N, X, OpName, ArgNames, _TypeList, OutArgs, Oneway,
- erl_corba) ->
- Fd = ic_genobj:stubfiled(G),
- Name = list_to_atom(OpName),
- ImplF = Name,
- ImplM = list_to_atom(ic_genobj:impl(G)),
- ThisStr = mk_name(G, "THIS"),
- FromStr = mk_name(G, "From"),
- State = mk_name(G, "State"),
- Context = mk_name(G, "Context"),
-
- {UseFrom, From} =
- case Oneway of
- false ->
- case use_from(G, N, OpName) of
- true ->
- {FromStr, FromStr};
- false ->
- {"false", "_"}
- end;
- true ->
- {"false", "_"}
- end,
- {UseThis, This} =
- case use_this(G, N, OpName) of
- true ->
- {ThisStr, ThisStr};
- false ->
- {"false", "_"}
- end,
- %% Create argument list string
- CallArgs = mk_list(ArgNames),
- emit_op_comment(G, Fd, X, Name, ArgNames, OutArgs),
-
- %% Check if pre and post conditions are specified for this operation
- Precond = use_precond(G, N, X),
- Postcond = use_postcond(G, N, X),
-
- case Oneway of
- true ->
- emit(Fd, "handle_cast({~s, ~s, ~p, [~s]}, ~s) ->\n",
- [This, Context, Name, CallArgs, State]),
- case {Precond, Postcond} of
- {false, false} ->
- emit(Fd, " corba:handle_cast(~p, ~p, [~s], ~s, ~s, ~s);\n\n",
- [ImplM, ImplF, CallArgs, State, Context, UseThis]);
- _ ->
- emit(Fd, " corba:handle_cast(~p, ~p, [~s], ~s, ~s, ~s, ~p, ~p, ?MODULE);\n\n",
- [ImplM, ImplF, CallArgs, State, Context, UseThis,
- Precond, Precond])
- end;
- false ->
- emit(Fd, "handle_call({~s, ~s, ~p, [~s]}, ~s, ~s) ->\n",
- [This, Context, Name, CallArgs, From, State]),
- case {Precond, Postcond} of
- {false, false} ->
- emit(Fd, " corba:handle_call(~p, ~p, [~s], ~s, ~s, ~s, ~s);\n\n",
- [ImplM, ImplF, CallArgs, State, Context, UseThis, UseFrom]);
- _->
- emit(Fd, " corba:handle_call(~p, ~p, [~s], ~s, ~s, ~s, ~s, ~p, ~p, ?MODULE);\n\n",
- [ImplM, ImplF, CallArgs, State, Context, UseThis, UseFrom,
- Precond, Postcond])
- end
- end;
-emit_skel_func_helper(G, N, X, OpName, ArgNames, _TypeList, OutArgs, Oneway,
- _Backend) ->
- Fd = ic_genobj:stubfiled(G),
- Name = list_to_atom(OpName),
- ImplF = Name,
- ImplM = list_to_atom(ic_genobj:impl(G)),
- FromStr = mk_name(G, "From"),
- State = mk_name(G, "State"),
-
- %% Create argument list
- CallArgs1 = [State | ArgNames],
- {CallArgs2, From} =
- case is_oneway(X) of
- false ->
- case use_from(G, N, OpName) of
- true ->
- {[FromStr | CallArgs1], FromStr};
- false ->
- {CallArgs1, "_"}
- end;
- true ->
- {CallArgs1, "_"}
- end,
- %% Create argument list string
- CallArgs = mk_list(CallArgs2),
- emit_op_comment(G, Fd, X, Name, ArgNames, OutArgs),
- FunName = case ic_options:get_opt(G, scoped_op_calls) of
- true ->
- list_to_atom(ic_util:to_undersc([OpName | N]));
- false ->
- list_to_atom(OpName)
- end,
- case Oneway of
- true ->
- if
- length(ArgNames) == 0 ->
- emit(Fd, "handle_cast(~p, ~s) ->\n", [FunName, State]);
- true ->
- emit(Fd, "handle_cast({~p, ~s}, ~s) ->\n",
- [FunName, mk_list(ArgNames), State])
- end,
- emit(Fd, " ~p:~p(~s);\n\n", [ImplM, ImplF, CallArgs]);
- false ->
- if
- length(ArgNames) == 0 ->
- emit(Fd, "handle_call(~p, ~s, ~s) ->\n",
- [FunName, From, State]);
- true ->
- emit(Fd, "handle_call({~p, ~s}, ~s, ~s) ->\n",
- [FunName, mk_list(ArgNames), From, State])
- end,
- emit(Fd, " ~p:~p(~s);\n\n", [ImplM, ImplF, CallArgs])
- end.
-
-use_this(G, N, OpName) ->
- FullOp = ic_util:to_colon([OpName|N]),
- FullIntf = ic_util:to_colon(N),
- case {get_opt(G, {this, FullIntf}), get_opt(G, {this, FullOp}),
- get_opt(G, {this, true})} of
- {_, force_false, _} -> false;
- {force_false, false, _} -> false;
- {false, false, false} -> false;
- _ -> true
- end.
-
-use_from(G, N, OpName) ->
- FullOp = ic_util:to_colon([OpName|N]),
- FullIntf = ic_util:to_colon(N),
- case {get_opt(G, {from, FullIntf}), get_opt(G, {from, FullOp}),
- get_opt(G, {from, true})} of
- {_, force_false, _} -> false;
- {force_false, false, _} -> false;
- {false, false, false} -> false;
- _ -> true
- end.
-
-
-emit_constant_func(G, Id, Val) ->
- case ic_genobj:is_stubfile_open(G) of
- false -> ok;
- true ->
- Fd = ic_genobj:stubfiled(G),
- N = list_to_atom(get_id(Id)),
- emit_const_comment(G, Fd, Id, N),
- emit(Fd, "~p() -> ~p.\n\n", [N, Val])
- end.
-
-
-
-emit_const_comment(_G, F, _X, Name) ->
- ic_codegen:mcomment_light(F,
- [io_lib:format("Constant: ~p", [Name])]).
-
-
-emit_op_comment(G, F, X, Name, InP, OutP) ->
- ic_codegen:mcomment_light(F,
- [io_lib:format("~s: ~p", [get_title(X), Name]),
- "",
- get_returns(G, X, InP, OutP) |
- get_raises(X)]).
-
-get_title(X) when is_record(X, attr) -> "Attribute Operation";
-get_title(_X) -> "Operation".
-
-get_raises(X) when is_record(X, op) ->
- if X#op.raises == [] -> [];
- true ->
- [" Raises: " ++
- mk_list(lists:map(fun(E) -> ic_util:to_colon(E) end,
- X#op.raises))]
- end;
-get_raises(_X) -> [].
-
-get_returns(_G, _X, _InP, []) ->
- " Returns: RetVal";
-get_returns(G, _X, _InP, OutP) ->
- " Returns: "++mk_list(["RetVal" | mk_erl_vars(G, OutP)]).
-
-
-
-
-%%------------------------------------------------------------
-%%
-%% Utilities
-%%
-%% Convenient little go-get functions
-%%
-%%------------------------------------------------------------
-
-%% The automaticly generated get and set operation names for an
-%% attribute.
-mk_attr_func_names(_Scope, Name) ->
- {"_get_" ++ Name, "_set_" ++ Name}.
-%% {scoped_name(Scope, "_get_"++Name), scoped_name(Scope, "_set_"++Name)}.
-
-%% Returns TK of the Get and Set attribute functions.
-mk_attr_func_types(_N, X) ->
- TK = ic_forms:get_tk(X),
- {{TK, [], []}, {tk_void, [TK], []}}.
-
-
-
-%%------------------------------------------------------------
-%%
-%% Generation utilities and common stuff
-%%
-%% Convenient stuff for generation
-%%
-%%------------------------------------------------------------
-
-
-%% Input is a list of parameters (in parse form) and output is a list
-%% of capitalised variable names. mk_var is in icgen
-mk_erl_vars(_G, Params) ->
- map(fun(P) -> mk_var(get_id(P#param.id)) end, Params).
-
-
-%% mk_list produces a nice comma separated string of variable names
-mk_list([]) -> [];
-mk_list([Arg | Args]) ->
- Arg ++ mk_list2(Args).
-mk_list2([Arg | Args]) ->
- ", " ++ Arg ++ mk_list2(Args);
-mk_list2([]) -> [].
-
-
-%%------------------------------------------------------------
-%%
-%% Parser utilities
-%%
-%% Called from the yecc parser. Expands the identifier list of an
-%% attribute so that the attribute generator never has to handle
-%% lists.
-%%
-%%------------------------------------------------------------
-
-
-%% Unfold identifier lists or nested lists. Note that many records
-%% contain an entry named id that is a list before unfold and a single
-%% id afterwards.
-unfold(L) when is_list(L) ->
- lists:flatten(map(fun(X) -> unfold2(X) end, L));
-unfold(X) -> unfold2(X).
-
-unfold2(A) when is_record(A, attr) ->
- map(fun(Id) -> A#attr{id=Id} end, A#attr.id);
-unfold2(M) when is_record(M, member) ->
- map(fun(Id) -> M#member{id=Id} end, M#member.id);
-unfold2(M) when is_record(M, case_dcl) ->
- map(fun(Id) -> M#case_dcl{label=Id} end, M#case_dcl.label);
-unfold2(T) when is_record(T, typedef) ->
- map(fun(Id) -> T#typedef{id=Id} end, T#typedef.id).
-
-
-
-
-%% Code produce for dependency function
-genDependency(G) ->
- Fd = ic_genobj:stubfiled(G),
- nl(Fd),nl(Fd),
- ic_codegen:comment(Fd, "Idl file dependency list function"),
- emit(Fd, "oe_dependency() ->\n\n", []),
- emit(Fd, " ~p.\n\n", [ic_pragma:get_dependencies(G)]).
diff --git a/lib/ic/src/ic_error.erl b/lib/ic/src/ic_error.erl
deleted file mode 100644
index 790e1f0539..0000000000
--- a/lib/ic/src/ic_error.erl
+++ /dev/null
@@ -1,376 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(ic_error).
-
--include_lib("ic/src/ic.hrl").
--include_lib("ic/src/ic_debug.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([error/2,
- fatal_error/2,
- init_errors/1,
- return/1,
- warn/2,
- get_error_count/1]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-%%-----------------------------------------------------------------
-%% External functions
-%%-----------------------------------------------------------------
-
-%%--------------------------------------------------------------------
-%%
-%% Error and warning utilities.
-%%
-%% Note that errors are somewhat brutal and that warnings are kept in
-%% a list for the user to extract at a later stage. The handling of
-%% warnings is entirely up to the user while handling of errors is
-%% never left to the user.
-%%
-%%--------------------------------------------------------------------
-
-return(G) ->
- case ic_options:get_opt(G, silent2) of
- true ->
- case get_error_count(G) of
- 0 -> {ok, get_list(G, warn_list)};
- _X -> {error, get_list(G, warn_list), get_list(G, error_list)}
- end;
- false ->
- case get_error_count(G) of
- 0 -> ok;
- X -> print_error(G, {error, g, ic_genobj:idlfile(G), {error_count, X}}),
- error
- end
- end.
-
-
-get_list(G, ListName) ->
- ?lookup(G#genobj.options, ListName).
-
-
-%% Public function for reporting an error
-error(G, Err) ->
- Error = {error, g, ic_genobj:idlfile(G), Err},
- case insert_in_list(G, Error, error_list) of
- new ->
- print_error(G, Error),
- MaxErrs = ic_options:get_opt(G, maxerrs),
- case incr_counter(G, error_count) of
- X when X >= MaxErrs ->
- fatal_error(G, {error_count_exceeded, X});
- _ -> Error
- end;
- old ->
- Error
- end.
-
-%% Public function for reporting an error. NOTE: also stops execution
-fatal_error(G, Err) ->
- Error = {error, g, ic_genobj:idlfile(G), Err},
- insert_in_list(G, Error, error_list),
- incr_counter(G, error_count),
- print_error(G, Error),
- throw(Error).
-
-
-%% Public function for reporting a warning
-warn(G, Warn) ->
- Warning = {warn, g, ic_genobj:idlfile(G), Warn},
- case insert_in_list(G, Warning, warn_list) of
- new ->
- print_warn(G, Warning),
- MaxErrs = ic_options:get_opt(G, maxwarns),
- case incr_counter(G, warn_count) of
- X when X >= MaxErrs ->
- fatal_error(G, {warn_count_exceeded, X});
- _ -> ok
- end;
- old -> ok
-end.
-
-
-%% Initialisation of all counters and lists associated with errors and
-%% warnings.
-init_errors(G) ->
- reset_counter(G, error_count),
- reset_counter(G, warn_count),
- reset_list(G, error_list),
- reset_list(G, warn_list),
- ok.
-
-
-
-%%--------------------------------------------------------------------
-%% Counter and list (warn and error) handling
-%%
-
-incr_counter(G, Counter) ->
- Num = ?lookup(G#genobj.options, Counter) + 1,
- ?insert(G#genobj.options, Counter, Num),
- Num.
-
-reset_counter(G, Counter) ->
- ?insert(G#genobj.options, Counter, 0).
-
-get_error_count(G) ->
- ?lookup(G#genobj.options, error_count).
-
-reset_list(G, ListName) ->
- ?insert(G#genobj.options, ListName, []).
-
-insert_in_list(G, Item, ListName) ->
- List = ?lookup(G#genobj.options, ListName),
- case lists:member(Item, List) of
- true -> old;
- false ->
- ?insert(G#genobj.options, ListName, [Item| List]),
- new
- end.
-
-
-%%--------------------------------------------------------------------
-%%
-%% Nice printouts of errors and warnings
-%%
-
-
-%% Errors
-
-print_error(G, Error) ->
- case {ic_options:get_opt(G, silent), ic_options:get_opt(G, silent2)} of
- {true, _} -> ok;
- {_, true} -> ok;
- _ -> format_error(Error)
- end,
- error.
-
-format_error({error, _, File, {parse_error, Line, Args}}) ->
- Fmt = lists:foldl(fun(_, Acc) -> [$~, $s | Acc] end, [], Args),
- display(File, Line, Fmt, Args);
-format_error({error, _, File, {error_count, X}}) ->
- display(File, "~p errors found", [X]);
-format_error({error, _, File, {error_count_exceeded, X}}) ->
- display(File, "too many errors found (~p)", [X]);
-format_error({error, _, File, {warn_count_exceeded, X}}) ->
- display(File, "too many warnings found (~p)", [X]);
-format_error({error, _, File, {inherit_name_collision,
- {Orig, Item}, {Base, NewItem}}}) ->
- display(File, ic_forms:get_line(Item), "~s collides with ~s",
- [pp([ic_forms:get_id2(Item) | Orig]), pp([ic_forms:get_id2(NewItem) | Base])]);
-format_error({error, _, File, {unsupported_op, {'~', Line}}}) ->
- display(File, Line, "unsupported unary operation ~~", []);
-format_error({error, _, File, {multiply_defined, X}}) ->
- display(File, ic_forms:get_line(X), "multiple defined identifier ~p", [ic_forms:get_id2(X)]);
-format_error({error, _, File, {illegal_spelling, X}}) ->
- display(File, ic_forms:get_line(X),
-% "illegal spelling of identifier ~s (capitalisation?)",
- "identifier ~p multiply declared - differs in case only",
- [ic_forms:get_id2(X)]);
-format_error({error, _, File, {illegal_enumerant_value, X}}) ->
- display(File, ic_forms:get_line(X),
- "Enumerant ~s's value collide by name with other type",
- [ic_forms:get_id2(X)]);
-format_error({error, _, File, {illegal_forward, X}}) ->
- display(File, ic_forms:get_line(X),
- "cannot inherit from forwarded interface ~s", [ic_forms:get_id2(X)]);
-format_error({error, _, File, {illegal_const_t, X, Type}}) ->
- display(File, ic_forms:get_line(X),
- "Illegal constant type ~s of ~s", [pp(Type), ic_forms:get_id2(X)]);
-format_error({error, _, File, {multiple_cases, X}}) ->
- display(File, ic_forms:get_line(X), "multiple case values ~s", [pp(X)]);
-format_error({error, _, File, {symtab_not_found, X}}) ->
- display(File, ic_forms:get_line(X), "undeclared identifier ~s", [ic_forms:get_id2(X)]);
-format_error({error, _, File, {preproc, Lines}}) ->
- display(File, "preprocessor error: ~s", [hd(Lines)]);
-format_error({error, _, File, {ic_pp_error, Lines}}) ->
- display(File, "preprocessor error: ~s", [Lines]);
-format_error({error, _, File, {illegal_float, Line}}) ->
- display(File, Line, "illegal floating point number", []);
-format_error({error, _, File, {bad_type_combination, E, V1, V2}}) ->
- display(File, ic_forms:get_line(E), "incompatible types, ~p and ~p", [V1, V2]);
-format_error({error, _, File, {bad_oneway_type, X, _TK}}) ->
- display(File, ic_forms:get_line(X), "oneway operations must be declared void", []);
-format_error({error, _, File, {inout_spec_for_c, X, Arg}}) ->
- display(File, ic_forms:get_line(X), "inout parameter ~s specified in native c mode",
- [Arg]);
-format_error({error, _, File, {sequence_not_defined, X, Arg}}) ->
- display(File, ic_forms:get_line(X), "sequence ~s not defined", [Arg]);
-format_error({error, _, File, {illegal_typecode_for_c, Arg}}) ->
- display(File, not_specified, "illegal typecode ~s used in native c mode",
- [Arg]);
-format_error({error, _, File, {name_not_found, N}}) ->
- display(File, not_specified, "name ~s not found", [N]);
-format_error({error, _, File, {illegal_typecode_for_c, Arg, N}}) ->
- display(File, not_specified, "illegal typecode ~p used for ~p in native c mode", [Arg, N]);
-format_error({error, _, File, {oneway_outparams, X}}) ->
- display(File, ic_forms:get_line(X),
- "oneway operations may not have out or inout parameters", []);
-format_error({error, _, File, {oneway_raises, X}}) ->
- display(File, ic_forms:get_line(X), "oneway operations may not raise exceptions",
- []);
-format_error({error, _, File, {bad_tk_match, T, TK, V}}) ->
- display(File, ic_forms:get_line(T),
- "value ~p does not match declared type ~s", [V, pp(TK)]);
-format_error({error, _, File, {bad_scope_enum_case, ScopedId}}) ->
- display(File, ic_forms:get_line(ScopedId),
- "scoped enum identifiers not allowed as case (~s)",
- [pp(ScopedId)]);
-format_error({error, _, File, {bad_type, Expr, Op, _TypeList, V}}) ->
- display(File, ic_forms:get_line(Expr),
- "parameter value ~p to ~s is of illegal type", [V, pp(Op)]);
-format_error({error, _, File, {bad_case_type, TK, X, Val}}) ->
- display(File, ic_forms:get_line(X),
- "case value ~s does not match discriminator type ~s",
- [case_pp(X, Val), pp(TK)]);
-format_error({error, _, File, {tk_not_found, X}}) ->
- display(File, ic_forms:get_line(X), "undeclared identifier ~s", [pp(X)]);
-%%% New format_errors
-format_error({error, _, File, {bad_fixed, Format, Args, Line}}) ->
- display(File, Line, Format, Args);
-format_error({error, _, File, {illegal_switch_t, Arg, _N}}) ->
- display(File, ic_forms:get_line(Arg), "illegal switch", []);
-format_error({error, _, File, {inherit_resolve, Arg, N}}) ->
- display(File, ic_forms:get_line(Arg), "cannot resolve ~s", [N]);
-format_error({error, _, File, {bad_escape_character, Line, Char}}) ->
- display(File, Line, "bad escape character \"~c\"", [Char]);
-format_error({error, _, File, {pragma_code_opt_bad_option_list, Line}}) ->
- display(File, Line, "bad option list on pragma \"CODEOPT\"", []);
-format_error({error, _, File, {bad_string, Line}}) ->
- display(File, Line, "bad string", []);
-format_error({error, _, File, {create_dir, Path, Reason}}) ->
- display(File, not_specified, "couldn't create directory ~p due to ~p", [Path, Reason]);
-format_error({error, _, File, {open_file, Path, Reason}}) ->
- display(File, not_specified, "couldn't open ~p due to ~p", [Path, Reason]);
-format_error({error, _, File, {plain_error_string, ErrString}}) ->
- display(File, not_specified, "~s", [ErrString]);
-format_error({error, _, File, {plain_error_string, T, ErrString}}) ->
- display(File, ic_forms:get_line(T), "~s", [ErrString]);
-format_error({error, _, File, {ErrString, Line}}) ->
- display(File, Line, ErrString, []).
-
-
-%% Warnings
-print_warn(G, Warn) ->
- case {ic_options:get_opt(G, silent), ic_options:get_opt(G, silent2)} of
- {true, _} -> ok;
- {_, true} -> ok;
- _ -> format_warn(Warn)
- end.
-
-format_warn({warn, _, File, {ic_pp_warning, Lines}}) ->
- display(File, "preprocessor warning: ~s", [Lines]);
-format_warn({warn, _, _File, {cfg_open, _Reason, File}}) ->
- display(File, "warning: could not open file: ~p", [File]);
-format_warn({warn, _, _File, {cfg_read, File}}) ->
- display(File, "warning: syntax error in configuration file", []);
-format_warn({warn, _, File, {multi_modules, Id}}) ->
- display(File, ic_forms:get_line(Id), "warning: multiple modules in file", []);
-format_warn({warn, _, File, {illegal_opt, Opt}}) ->
- display(File, "warning: unrecognised option: ~p", [Opt]);
-format_warn({warn, _, File, {nested_mod, Id}}) ->
- display(File, ic_forms:get_line(Id), "warning: nested module: ~s", [ic_forms:get_id(Id)]);
-format_warn({warn, _, File, {inherit_name_shadow, {Orig, Item},
- {Base, NewItem}}}) ->
- display(File, ic_forms:get_line(Item),
- "warning: ~s shadows ~s", [pp([ic_forms:get_id2(Item) | Orig]),
- pp([ic_forms:get_id2(NewItem) | Base])]);
-format_warn({warn, _, File, {internal_307, X, Y}}) ->
- %% If global Scope variable is not [] at top level constant
- display(File, ic_forms:get_line(X), "warning: internal 307: ~p ~p", [X, Y]);
-format_warn({warn, _, File, {WarnString, Line}}) ->
- display(File, Line, WarnString, []).
-
-%% Display an error or warning
-display(File, not_specified, F, A) ->
- io:format("~p : ~s~n", [File, io_lib:format(F, A)]);
-display(File, Line, F, A) ->
- io:format("~p on line ~p: ~s~n", [File, Line, io_lib:format(F, A)]).
-display(File, F, A) ->
- io:format("~p: ~s~n", [File, io_lib:format(F, A)]).
-
-
-
-%%format_warn2(G, WarnStr) ->
-%% case {ic_options:get_opt(G, silent), ic_options:get_opt(G, silent2),
-%% ic_options:get_opt(G, nowarn)} of
-%% {false, false, false} ->
-%% io:format("~p: warning: ~s~n", [ic_genobj:idlfile(G), WarnStr]);
-%% _ -> ok
-%% end.
-
-%%format_warn2(G, Line, WarnStr) ->
-%% case {ic_options:get_opt(G, silent), ic_options:get_opt(G, silent2),
-%% ic_options:get_opt(G, nowarn)} of
-%% {false, false, false} ->
-%% io:format("~p on line ~p: warning: ~s~n",
-%% [ic_genobj:idlfile(G), Line, WarnStr]);
-%% _ -> ok
-%% end.
-
-
-
-
-%% pretty print various stuff
-
-pp({tk_string, _}) -> "string";
-pp({tk_wstring, _}) -> "wstring";
-pp(tk_long) -> "long";
-pp(tk_short) -> "short";
-pp(tk_ushort) -> "unsigned short";
-pp(tk_ulong) -> "unsigned long";
-pp(tk_float) -> "float";
-pp(tk_double) -> "double";
-pp(tk_boolean) -> "boolean";
-pp(tk_char) -> "char";
-pp(tk_wchar) -> "wchar";
-pp(tk_octet) -> "octet";
-pp(tk_null) -> "null";
-pp(tk_void) -> "void";
-pp(tk_any) -> "any";
-pp({tk_fixed, _, _}) -> "fixed";
-pp({tk_objref, _, _}) -> "object reference";
-pp(rshift) -> ">>";
-pp(lshift) -> "<<";
-pp(X) when element(1, X) == tk_enum -> "enum";
-pp(X) when is_record(X, scoped_id) -> ic_util:to_colon(X);
-pp(X) when element(1, X) == '<identifier>' -> ic_forms:get_id(X);
-pp(X) when is_list(X) andalso is_list(hd(X)) -> ic_util:to_colon(X);
-pp({_, Num, Beef}) when is_integer(Num) -> Beef;
-pp({Beef, Num}) when is_integer(Num) -> ic_util:to_list(Beef);
-pp(X) -> ic_util:to_list(X).
-
-%% special treatment of case label names
-case_pp(X, _Val) when is_record(X, scoped_id) -> pp(X);
-case_pp(_X, Val) -> pp(Val).
-
-
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
diff --git a/lib/ic/src/ic_fetch.erl b/lib/ic/src/ic_fetch.erl
deleted file mode 100644
index 59f21711ec..0000000000
--- a/lib/ic/src/ic_fetch.erl
+++ /dev/null
@@ -1,389 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(ic_fetch).
-
--include("icforms.hrl").
-
--export([member2type/3]).
-
--export([fetchTk/3, isArray/3, isBasicType/1, isBasicType/2,
- isBasicType/3, isBasicTypeOrEterm/3, isEterm/3, isString/3,
- isStruct/3, isUnion/3, name2type/2, searchIncludedTk/2,
- searchInsideTks/2, searchTk/2, searchTk/3]).
-
-name2type(G, Name) ->
- S = ic_genobj:tktab(G),
- ScopedName = lists:reverse(string:tokens(Name,"_")),
- InfoList = ets:lookup( S, ScopedName ),
- filter( InfoList ).
-
-
-
-%% This is en overloaded function,
-%% differs in input on unions
-member2type(_G, X, I) when is_record(X, union)->
- Name = ic_forms:get_id2(I),
- case lists:keysearch(Name,2,element(6,X#union.tk)) of
- false ->
- error;
- {value,Rec} ->
- fetchType(element(3,Rec))
- end;
-member2type( G, SName, MName ) ->
-
- S = ic_genobj:tktab( G ),
- SNList = lists:reverse(string:tokens(SName,"_")),
- ScopedName = [MName | SNList],
- InfoList = ets:lookup( S, ScopedName ),
-
- case filter( InfoList ) of
- error ->
- %% Try a little harder, seeking inside tktab
- case lookup_member_type_in_tktab(S, ScopedName, MName) of
- error ->
- %% Check if this is the "return to return1" case
- case MName of
- "return1" ->
- %% Do it all over again !
- ScopedName2 = ["return" | SNList],
- InfoList2 = ets:lookup( S, ScopedName2 ),
- case filter( InfoList2 ) of
- error ->
- %% Last resort: seek in pragma table
- lookup_type_in_pragmatab(G, SName);
-
- Other ->
- Other
- end;
- _ ->
- %% Last resort: seek in pragma table
- lookup_type_in_pragmatab(G, SName)
- end;
- Other ->
- Other
- end;
- Other ->
- Other
- end.
-
-
-lookup_member_type_in_tktab(S, ScopedName, MName) ->
- case ets:match_object(S, {'_',member,{MName,'_'},nil}) of
- [] ->
- error;
- [{_FullScopedName,member,{MName,TKInfo},nil}]->
- fetchType( TKInfo );
- List ->
- lookup_member_type_in_tktab(List,ScopedName)
- end.
-
-lookup_member_type_in_tktab([],_ScopedName) ->
- error;
-lookup_member_type_in_tktab([{FullScopedName,_,{_,TKInfo},_}|Rest],ScopedName) ->
- case lists:reverse(string:tokens(ic_util:to_undersc(FullScopedName),"_")) of
- ScopedName ->
- fetchType(TKInfo);
- _ ->
- lookup_member_type_in_tktab(Rest,ScopedName)
- end.
-
-
-lookup_type_in_pragmatab(G, SName) ->
- S = ic_genobj:pragmatab(G),
-
- %% Look locally first
- case ets:match(S,{file_data_local,'_','_','$2','_','_',SName,'_','_'}) of
- [] ->
- %% No match, seek included
- case ets:match(S,{file_data_included,'_','_','$2','_','_',SName,'_','_'}) of
-
- [] ->
- error;
- [[Type]] ->
- io:format("1 Found(~p) : ~p~n",[SName,Type]),
- Type
- end;
-
- [[Type]] ->
- io:format("2 Found(~p) : ~p~n",[SName,Type]),
- Type
- end.
-
-
-
-
-filter( [] ) ->
- error;
-filter( [I | Is ] ) ->
- case I of
- { _, member, { _, TKINFO }, _ } ->
- fetchType( TKINFO );
-
- { _, struct, _, _ } ->
- struct;
-
- { _, typedef, TKINFO, _ } ->
- fetchType( TKINFO );
-
- { _, module, _, _ } ->
- module;
-
- { _, interface, _, _ } ->
- interface;
-
- { _, op, _, _ } ->
- op;
-
- { _,enum, _, _ } ->
- enum;
-
- { _, spellcheck } ->
- filter( Is );
-
- _ ->
- error
- end.
-
-
-fetchType( { tk_sequence, _, _ } ) ->
- sequence;
-fetchType( { tk_array, _, _ } ) ->
- array;
-fetchType( { tk_struct, _, _, _} ) ->
- struct;
-fetchType( { tk_string, _} ) ->
- string;
-fetchType( tk_short ) ->
- short;
-fetchType( tk_long ) ->
- long;
-fetchType( tk_ushort ) ->
- ushort;
-fetchType( tk_ulong ) ->
- ulong;
-fetchType( tk_float ) ->
- float;
-fetchType( tk_double ) ->
- double;
-fetchType( tk_boolean ) ->
- boolean;
-fetchType( tk_char ) ->
- char;
-fetchType( tk_octet ) ->
- octet;
-fetchType( { tk_enum, _, _, _ } ) ->
- enum;
-fetchType( { tk_union, _, _, _, _, _ } ) ->
- union;
-fetchType( tk_any ) ->
- any;
-fetchType( _ ) ->
- error.
-
-isBasicTypeOrEterm(G, N, S) ->
- case isBasicType(G, N, S) of
- true ->
- true;
- false ->
- isEterm(G, N, S)
- end.
-
-
-isEterm(G, N, S) when element(1, S) == scoped_id ->
- {FullScopedName, _, _TK, _} = ic_symtab:get_full_scoped_name(G, N, S),
- case ic_code:get_basetype(G, ic_util:to_undersc(FullScopedName)) of
- "erlang_term" ->
- true;
- "ETERM*" ->
- true;
- _X ->
- false
- end;
-isEterm(_G, _Ni, _X) ->
- false.
-
-isBasicType(G, N, S) when element(1, S) == scoped_id ->
- {_, _, TK, _} = ic_symtab:get_full_scoped_name(G, N, S),
- isBasicType(fetchType(TK));
-isBasicType(_G, _N, {string, _} ) ->
- false;
-isBasicType(_G, _N, {Type, _} ) ->
- isBasicType(Type).
-
-
-isBasicType(G, Name) ->
- isBasicType(name2type(G, Name )).
-
-
-isBasicType(Type) ->
- lists:member(Type,
- [tk_short,short,
- tk_long,long,
- tk_ushort,ushort,
- tk_ulong,ulong,
- tk_float,float,
- tk_double,double,
- tk_boolean,boolean,
- tk_char,char,
- tk_octet,octet]).
-
-
-
-isString(G, N, T) when element(1, T) == scoped_id ->
- case ic_symtab:get_full_scoped_name(G, N, T) of
- {_FullScopedName, _, {'tk_string',_}, _} ->
- true;
- _ ->
- false
- end;
-isString(_G, _N, T) when is_record(T, string) ->
- true;
-isString(_G, _N, _Other) ->
- false.
-
-
-isArray(G, N, T) when element(1, T) == scoped_id ->
- case ic_symtab:get_full_scoped_name(G, N, T) of
- {_FullScopedName, _, {'tk_array', _, _}, _} ->
- true;
- _ ->
- false
- end;
-isArray(_G, _N, T) when is_record(T, array) ->
- true;
-isArray(_G, _N, _Other) ->
- false.
-
-
-
-isStruct(G, N, T) when element(1, T) == scoped_id ->
- case ic_symtab:get_full_scoped_name(G, N, T) of
- {_FullScopedName, _, {'tk_struct', _, _, _}, _} ->
- true;
- _ ->
- false
- end;
-isStruct(_G, _N, T) when is_record(T, struct) ->
- true;
-isStruct(_G, _N, _Other) ->
- false.
-
-
-
-isUnion(G, N, T) when element(1, T) == scoped_id ->
- case ic_symtab:get_full_scoped_name(G, N, T) of
- {_FullScopedName, _, {'tk_union', _, _, _,_,_}, _} ->
- true;
- _Other ->
- false
- end;
-isUnion(_G, _N, T) when is_record(T, union) ->
- true;
-isUnion(_G, _N, _Other) ->
- false.
-
-
-
-%%------------------------------------------------------------
-%%
-%% Always fetchs TK of a record.
-%%
-%%------------------------------------------------------------
-fetchTk(G,N,X) ->
- case ic_forms:get_tk(X) of
- undefined ->
- searchTk(G,ictk:get_IR_ID(G, N, X));
- TK ->
- TK
- end.
-
-
-%%------------------------------------------------------------
-%%
-%% seek type code when not accessible by get_tk/1
-%%
-%%------------------------------------------------------------
-searchTk(G,IR_ID) ->
- S = ic_genobj:tktab(G),
- case catch searchTk(S,IR_ID,typedef) of
- {value,TK} ->
- TK;
- _ -> %% false / exit
- case catch searchTk(S,IR_ID,struct) of
- {value,TK} ->
- TK;
- _ -> %% false / exit
- case catch searchTk(S,IR_ID,union) of
- {value,TK} ->
- TK;
- _ ->
- undefined
- end
- end
- end.
-
-
-searchTk(S,IR_ID,Type) ->
- L = lists:flatten(ets:match(S,{'_',Type,'$1','_'})),
- case lists:keysearch(IR_ID,2,L) of
- {value,TK} ->
- {value,TK};
- false ->
- searchInsideTks(L,IR_ID)
- end.
-
-
-searchInsideTks([],_IR_ID) ->
- false;
-searchInsideTks([{tk_array,TK,_}|Xs],IR_ID) ->
- case searchIncludedTk(TK,IR_ID) of
- {value,TK} ->
- {value,TK};
- false ->
- searchInsideTks(Xs,IR_ID)
- end.
-
-
-searchIncludedTk({tk_array,TK,_},IR_ID) ->
- searchIncludedTk(TK,IR_ID);
-searchIncludedTk({tk_sequence,TK,_},IR_ID) ->
- searchIncludedTk(TK,IR_ID);
-searchIncludedTk(TK,_IR_ID) when is_atom(TK) ->
- false;
-searchIncludedTk(TK,IR_ID) ->
- case element(2,TK) == IR_ID of
- true ->
- {value,TK};
- false ->
- false
- end.
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/ic/src/ic_file.erl b/lib/ic/src/ic_file.erl
deleted file mode 100644
index 688a777400..0000000000
--- a/lib/ic/src/ic_file.erl
+++ /dev/null
@@ -1,448 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(ic_file).
-
--include_lib("ic/src/ic.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([filename_push/4, filename_pop/2, open/2, close/1, remove_ext/1, join/2,
- add_dot_erl/1, add_dot_hrl/1, add_dot_c/1, add_dot_h/1, add_dot_java/1,
- add_dot_idl/1, javaInterfaceFilePush/3, javaInterfaceFilePop/1,
- createDirectory/2, createJavaDirectory/2, open_java_file/3]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-%%-----------------------------------------------------------------
-%% External functions
-%%-----------------------------------------------------------------
-
-%%-----------------------------------------------------------------
-%% Func: filename_push
-%%
-%% Pushes a file name, can also push ignore in which case means that
-%% no files should ever be opened at this scope. Note that empty in
-%% the file descriptor entries means that the file just isn't open
-%% yet.
-%%-----------------------------------------------------------------
-filename_push(G, _N, ignore, _) ->
- G#genobj{stubfile=[ignore | G#genobj.stubfile],
- stubfiled=[ignore | G#genobj.stubfiled],
- skelfile=[ignore | G#genobj.skelfile],
- skelfiled=[ignore | G#genobj.skelfiled],
- includefile=[ignore | G#genobj.includefile],
- includefiled=[ignore | G#genobj.includefiled]};
-
-filename_push(G, N, X, Lang) ->
- Fullname = [ic_forms:get_id2(X) | N],
- EName0 = ic_util:to_undersc(Fullname),
-
- DoGen = ic_genobj:do_gen(G),
-
- ImplName = find_impl_name(G, Fullname),
-
- {StubName, EName} =
- case Lang of
- erlang ->
- {join(ic_options:get_opt(G, stubdir), add_dot_erl(EName0)),
- EName0};
- erlang_template ->
- {join(ic_options:get_opt(G, stubdir), add_dot_erl(ImplName)),
- ImplName};
- c ->
- {join(ic_options:get_opt(G, stubdir), add_dot_c(EName0)),
- EName0};
- c_server ->
- {join(ic_options:get_opt(G, stubdir), add_dot_c(EName0++"__s")),
- EName0};
- erlang_template_no_gen ->
- {undefined, EName0};
- erlang_no_stub ->
- {undefined, EName0};
- c_no_stub ->
- {undefined, EName0};
- c_server_no_stub ->
- {undefined, EName0}
- end,
- Stub = if DoGen==true ->
- case StubName of
- undefined ->
- ignore;
- _ ->
- ic_codegen:emit_stub_head(G, open(empty, StubName), EName, Lang)
- end;
- true -> ignore end,
-
- HrlName = case Lang of
- erlang_template ->
- ignore;
- erlang_template_no_gen ->
- ignore;
- erlang ->
- ?ifopt2(G, gen_hrl,
- join(ic_options:get_opt(G, stubdir), add_dot_hrl(EName)),
- ignore);
- c ->
- ?ifopt2(G, gen_hrl,
- join(ic_options:get_opt(G, stubdir), add_dot_h(EName)),
- ignore);
- c_server ->
- ?ifopt2(G, gen_hrl,
- join(ic_options:get_opt(G, stubdir),
- add_dot_h(EName++"__s")),
- ignore);
- erlang_no_stub ->
- ?ifopt2(G, gen_hrl,
- join(ic_options:get_opt(G, stubdir), add_dot_hrl(EName)),
- ignore);
- c_no_stub ->
- ?ifopt2(G, gen_hrl,
- join(ic_options:get_opt(G, stubdir), add_dot_h(EName)),
- ignore);
- c_server_no_stub ->
- ?ifopt2(G, gen_hrl,
- join(ic_options:get_opt(G, stubdir),
- add_dot_h(EName++"__s")),
- ignore)
- end,
- Hrl = if DoGen==true ->
- case Lang of
- erlang_template ->
- ignore;
- erlang_template_no_gen ->
- ignore;
- erlang_no_stub ->
- ic_codegen:emit_hrl_head(G, open(empty, HrlName),
- EName, erlang);
- c_no_stub ->
- ic_codegen:emit_hrl_head(G, open(empty, HrlName),
- EName, c);
- c_server_no_stub ->
- ic_codegen:emit_hrl_head(G, open(empty, HrlName),
- EName, c_server);
- _ ->
- ic_codegen:emit_hrl_head(G, open(empty, HrlName),
- EName, Lang)
- end;
- true -> ignore end,
-
- G#genobj{impl=ImplName,
- stubfile=[StubName | G#genobj.stubfile],
- stubfiled=[Stub | G#genobj.stubfiled],
- includefile=[HrlName | G#genobj.includefile],
- includefiled=[Hrl | G#genobj.includefiled]}.
-
-%%-----------------------------------------------------------------
-%% Func: join/2
-%%
-%% Special version of filename join.
-%%-----------------------------------------------------------------
-join([], File) ->
- File;
-join(Path, File) ->
- filename:join(Path, File).
-
-
-%%-----------------------------------------------------------------
-%% Func: filename_pop/2
-%%-----------------------------------------------------------------
-filename_pop(G, Lang) ->
-%% io:format("Popped file names: ~p~n", [hd(G#genobj.stubfile)]),
-%% case is_skelfile_open(G) of
-%% true -> emit_skel_footer(G);
-%% false -> ok end,
-%% close(hd(G#genobj.skelfiled)),
- close(hd(G#genobj.stubfiled)),
- ic_codegen:emit_hrl_foot(G, Lang),
- close(hd(G#genobj.includefiled)),
- G#genobj{stubfile=tl(G#genobj.stubfile),
- stubfiled=tl(G#genobj.stubfiled),
-%% skelfile=tl(G#genobj.skelfile),
-%% skelfiled=tl(G#genobj.skelfiled),
- includefile=tl(G#genobj.includefile),
- includefiled=tl(G#genobj.includefiled)}.
-
-
-
-%%-----------------------------------------------------------------
-%% Func: javaInterfaceFilePush/3
-%%-----------------------------------------------------------------
-javaInterfaceFilePush(G, N, X) ->
- Name = ic_forms:get_java_id(X),
- {InterfaceFd, InterfaceFileName} = open_java_file(G, N, Name),
-
- StubClassName = "_" ++ Name ++ "Stub",
- {StubFd, StubFileName} = open_java_file(G, N, StubClassName),
-
- SkelClassName = "_" ++ Name ++ "ImplBase",
- {SkelFd, SkelFileName} = open_java_file(G, N, SkelClassName),
-
- HelperClassName = Name ++ "Helper",
- {HelperFd, HelperFileName} = open_java_file(G, N, HelperClassName),
-
- HolderClassName = Name ++ "Holder",
- {HolderFd, HolderFileName} = open_java_file(G, N, HolderClassName),
-
- G#genobj{
- interfacefile=[InterfaceFileName | G#genobj.interfacefile],
- interfacefiled=[InterfaceFd | G#genobj.interfacefiled],
- stubfile=[StubFileName | G#genobj.stubfile],
- stubfiled=[StubFd | G#genobj.stubfiled],
- skelfile=[SkelFileName | G#genobj.skelfile],
- skelfiled=[SkelFd | G#genobj.skelfiled],
- helperfile=[HelperFileName | G#genobj.helperfile],
- helperfiled=[HelperFd | G#genobj.helperfiled],
- holderfile=[HolderFileName | G#genobj.holderfile],
- holderfiled=[HolderFd | G#genobj.holderfiled]}.
-
-
-
-
-
-%%-----------------------------------------------------------------
-%% Func: javaInterfaceFilePop/1
-%%-----------------------------------------------------------------
-javaInterfaceFilePop(G) ->
- close(hd(G#genobj.interfacefiled)),
- close(hd(G#genobj.stubfiled)),
- close(hd(G#genobj.skelfiled)),
- close(hd(G#genobj.helperfiled)),
- close(hd(G#genobj.holderfiled)),
- G#genobj{
- interfacefile=tl(G#genobj.interfacefile),
- interfacefiled=tl(G#genobj.interfacefiled),
- stubfile=tl(G#genobj.stubfile),
- stubfiled=tl(G#genobj.stubfiled),
- skelfile=tl(G#genobj.skelfile),
- skelfiled=tl(G#genobj.skelfiled),
- helperfile=tl(G#genobj.helperfile),
- helperfiled=tl(G#genobj.helperfiled),
- holderfile=tl(G#genobj.holderfile),
- holderfiled=tl(G#genobj.holderfiled)}.
-
-%%-----------------------------------------------------------------
-%% Func: createDirectory/2
-%%-----------------------------------------------------------------
-createDirectory(_G, []) ->
- ok;
-createDirectory(G, Scope) ->
- Path = ic_file:join(ic_options:get_opt(G, stubdir), ic_pragma:slashify(Scope)),
- case file:make_dir(Path) of
- ok ->
- ok;
- {error, eexist} ->
- ok;
- {error, Reason} ->
- ic_error:fatal_error(G, {create_dir, Path, Reason})
- end.
-
-
-%%-----------------------------------------------------------------
-%% Func: createJavaDirectory/2
-%%-----------------------------------------------------------------
-createJavaDirectory(_G, []) ->
- ok;
-createJavaDirectory(G, Scope) ->
- JavaScope = ic_util:adjustScopeToJava(G,Scope),
- Path = ic_file:join(ic_options:get_opt(G, stubdir), ic_pragma:slashify(JavaScope)),
- case file:make_dir(Path) of
- ok ->
- ok;
- {error, eexist} ->
- ok;
- {error, Reason} ->
- ic_error:fatal_error(G, {create_dir, Path, Reason})
- end.
-
-
-
-
-%%-----------------------------------------------------------------
-%% Func: createJavaFileName/3
-%%-----------------------------------------------------------------
-createJavaFileName(G, Scope, FName) ->
- JavaScope = ic_util:adjustScopeToJava(G,Scope),
- join(ic_options:get_opt(G, stubdir),
- ic_pragma:slashify([FName++".java"|JavaScope])).
-
-%%-----------------------------------------------------------------
-%% Func: close/2 (used to be file_close)
-%%-----------------------------------------------------------------
-close(empty) -> ok;
-close(ignore) -> ok;
-close(Fd) ->
- file:close(Fd).
-
-%%-----------------------------------------------------------------
-%% Func: remove_ext/1
-%%-----------------------------------------------------------------
-remove_ext(File) ->
- filename:rootname(filename:basename(File)).
-
-%%-----------------------------------------------------------------
-%% Func: open/2 (used to be file_open)
-%%-----------------------------------------------------------------
-open(_, ignore) -> ignore;
-open(empty, Name) ->
- case file:open(Name, [raw, binary, write]) of
- {ok, Fd} ->
- Fd;
- {error, Reason} ->
- exit({error, Reason})
-%% ic_error:fatal_error(G, {open_file, Name, Reason})
- end.
-
-%%-----------------------------------------------------------------
-%% Func: open_java_file/3
-%%-----------------------------------------------------------------
-open_java_file(G, N, Name) ->
- createJavaDirectory(G, N),
- FName = createJavaFileName(G, N, Name),
- case file:open(FName, [raw, binary, write]) of
- {ok, Fd} ->
- ic_codegen:emit_stub_head(G, Fd, Name, java),
- emit_package(G, N, Fd),
- {Fd, FName};
- {error, Reason} ->
- ic_error:fatal_error(G, {open_file, FName, Reason})
- end.
-
-%%-----------------------------------------------------------------
-%% Func: emit_package/3
-%%-----------------------------------------------------------------
-emit_package(_G, [], _Fd) ->
- ok;
-emit_package(G, N, Fd) ->
- ic_codegen:emit(Fd, "package ~s;\n", [ic_util:to_dot(G,N)]),
- ic_codegen:nl(Fd).
-
-%%-----------------------------------------------------------------
-%% Func: add_dot_erl/1
-%%-----------------------------------------------------------------
-add_dot_erl(F) ->
- File = ic_util:to_list(F),
- F2 = lists:reverse(File),
- case F2 of
- [$l, $r, $e, $. | _Rest] ->
- File;
- _ ->
- File ++ ".erl"
- end.
-
-%%-----------------------------------------------------------------
-%% Func: add_dot_hrl/1
-%%-----------------------------------------------------------------
-add_dot_hrl(F) ->
- File = ic_util:to_list(F),
- F2 = lists:reverse(File),
- case F2 of
- [$l, $r, $h, $. | _Rest] ->
- File;
- _ ->
- File ++ ".hrl"
- end.
-
-%%-----------------------------------------------------------------
-%% Func: add_dot_c/1
-%%-----------------------------------------------------------------
-add_dot_c(F) ->
- File = ic_util:to_list(F),
- F2 = lists:reverse(File),
- case F2 of
- [$c, $. | _Rest] ->
- File;
- _ ->
- File ++ ".c"
- end.
-
-%%-----------------------------------------------------------------
-%% Func: add_dot_h/1
-%%-----------------------------------------------------------------
-add_dot_h(F) ->
- File = ic_util:to_list(F),
- F2 = lists:reverse(File),
- case F2 of
- [$h, $. | _Rest] ->
- File;
- _ ->
- File ++ ".h"
- end.
-
-%%-----------------------------------------------------------------
-%% Func: add_dot_java/1
-%%-----------------------------------------------------------------
-add_dot_java(F) ->
- File = ic_util:to_list(F),
- F2 = lists:reverse(File),
- case F2 of
- [$a, $v, $a, $j, $. | _Rest] ->
- File;
- _ ->
- File ++ ".java"
- end.
-
-%%-----------------------------------------------------------------
-%% Func: add_dot_idl/1
-%%-----------------------------------------------------------------
-add_dot_idl(F) ->
- File = ic_util:to_list(F),
- F2 = lists:reverse(File),
- case F2 of
- [$l, $d, $i, $. | _Rest] ->
- File;
- _ ->
- File ++ ".idl"
- end.
-
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-
-%%--------------------------------------------------------------------
-%%
-%% File handling stuff
-%%
-%%
-%% Shall open a file for writing. Also sets up the generator with
-%% usefull bits of information
-%%
-%%--------------------------------------------------------------------
-find_impl_name(G, Name) ->
- N1 = ic_util:to_colon(Name),
- N2 = ic_util:to_undersc(Name),
- case {ic_options:get_opt(G, {impl, N1}),
- ic_options:get_opt(G, {impl, N2})} of
- {false, false} ->
- case {ic_options:get_opt(G, {impl, "::"++N1}),
- ic_options:get_opt(G, {impl, N2})} of
- {false, false} -> N2 ++ "_impl";
- {X, _Y} when X /= false -> ic_util:to_list(X);
- {_X, Y} when Y /= false -> ic_util:to_list(Y)
- end;
- {X, _Y} when X /= false -> ic_util:to_list(X);
- {_X, Y} when Y /= false -> ic_util:to_list(Y)
- end.
diff --git a/lib/ic/src/ic_forms.erl b/lib/ic/src/ic_forms.erl
deleted file mode 100644
index ed4b3e9a22..0000000000
--- a/lib/ic/src/ic_forms.erl
+++ /dev/null
@@ -1,442 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(ic_forms).
-
--include_lib("ic/src/ic.hrl").
--include_lib("ic/src/icforms.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([get_id/1, get_id2/1, get_java_id/1, get_line/1]).
--export([get_type_code/3, search_tk/2, clean_up_scope/1]).
--export([get_body/1, get_dimension/1, get_idlist/1, get_type/1, get_tk/1, is_oneway/1]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-%%-----------------------------------------------------------------
-%% External functions
-%%-----------------------------------------------------------------
-
-%%--------------------------------------------------------------------
-%%
-%% Generation go-get utilities
-%%
-%% Feeble attempt at virtual funtions.
-%%
-%%--------------------------------------------------------------------
-
-get_dimension(X) when is_record(X, array) ->
- [element(3, L) || L <- X#array.size].
-
-%% Should find the name hidden in constructs
-get_id( [{'<identifier>', _LineNo, Id}] ) -> Id;
-get_id( {'<identifier>', _LineNo, Id} ) -> Id;
-get_id(Id) when is_list(Id) andalso is_integer(hd(Id)) -> Id;
-get_id(X) when is_record(X, scoped_id) -> X#scoped_id.id;
-get_id(X) when is_record(X, array) -> get_id(X#array.id);
-get_id( {'<string_literal>', _LineNo, Id} ) -> Id;
-get_id( {'<wstring_literal>', _LineNo, Id} ) -> Id.
-
-get_line([{'<identifier>', LineNo, _Id}]) -> LineNo;
-get_line({'<identifier>', LineNo, _Id}) -> LineNo;
-get_line(X) when is_record(X, scoped_id) -> X#scoped_id.line;
-get_line(X) when is_record(X, module) -> get_line(X#module.id);
-get_line(X) when is_record(X, interface) -> get_line(X#interface.id);
-get_line(X) when is_record(X, forward) -> get_line(X#forward.id);
-get_line(X) when is_record(X, constr_forward) -> get_line(X#constr_forward.id);
-get_line(X) when is_record(X, const) -> get_line(X#const.id);
-get_line(X) when is_record(X, typedef) -> get_line(X#typedef.id);
-get_line(X) when is_record(X, struct) -> get_line(X#struct.id);
-get_line(X) when is_record(X, member) -> get_line(X#member.id);
-get_line(X) when is_record(X, union) -> get_line(X#union.id);
-get_line(X) when is_record(X, case_dcl) -> get_line(X#case_dcl.id);
-get_line(X) when is_record(X, enum) -> get_line(X#enum.id);
-get_line(X) when is_record(X, enumerator) -> get_line(X#enumerator.id);
-get_line(X) when is_record(X, array) -> get_line(X#array.id);
-get_line(X) when is_record(X, attr) -> get_line(X#attr.id);
-get_line(X) when is_record(X, except) -> get_line(X#except.id);
-get_line(X) when is_record(X, op) -> get_line(X#op.id);
-get_line(X) when is_record(X, param) -> get_line(X#param.id);
-get_line(X) when is_record(X, id_of) -> get_line(X#id_of.id);
-
-get_line({'or', T1, _T2}) -> get_line(T1);
-get_line({'xor', T1, _T2}) -> get_line(T1);
-get_line({'and', T1, _T2}) -> get_line(T1);
-get_line({'rshift', T1, _T2}) ->get_line(T1);
-get_line({'lshift', T1, _T2}) ->get_line(T1);
-get_line({'+', T1, _T2}) -> get_line(T1);
-get_line({'-', T1, _T2}) -> get_line(T1);
-get_line({'*', T1, _T2}) -> get_line(T1);
-get_line({'/', T1, _T2}) -> get_line(T1);
-get_line({'%', T1, _T2}) -> get_line(T1);
-get_line({{'-', _Line}, T}) -> get_line(T);
-get_line({{'+', _Line}, T}) -> get_line(T);
-get_line({{'~', _Line}, T}) -> get_line(T);
-get_line({_, X, _}) when is_integer(X) -> X;
-get_line({_A, N}) when is_integer(N) -> N;
-get_line(_) -> -1.
-
-
-%%--------------------------------------------------------------------
-%%
-%% High level get functions.
-%%
-%% These are highly polymorphic functions that will get the id,
-%% body and type of a record (those records output from the
-%% parser).
-%%
-%% NOTE: The typedef node (the alias) is special, because the type
-%% field is a type definition and therefore considered a body,
-%% and the type of a typedef is its name.
-%%
-
-get_id2(X) when is_record(X, module) -> get_id(X#module.id);
-get_id2(X) when is_record(X, interface) -> get_id(X#interface.id);
-get_id2(X) when is_record(X, forward) -> get_id(X#forward.id);
-get_id2(X) when is_record(X, constr_forward) -> get_id(X#constr_forward.id);
-get_id2(X) when is_record(X, const) -> get_id(X#const.id);
-get_id2(X) when is_record(X, typedef) -> get_id(hd(X#typedef.id));
-get_id2(X) when is_record(X, struct) -> get_id(X#struct.id);
-get_id2(X) when is_record(X, member) -> get_id(hd(X#member.id));
-get_id2(X) when is_record(X, union) -> get_id(X#union.id);
-get_id2(X) when is_record(X, case_dcl) -> get_id(X#case_dcl.id);
-get_id2(X) when is_record(X, enum) -> get_id(X#enum.id);
-get_id2(X) when is_record(X, enumerator) -> get_id(X#enumerator.id);
-get_id2(X) when is_record(X, array) -> get_id(X#array.id);
-get_id2(X) when is_record(X, attr) -> get_id(X#attr.id);
-get_id2(X) when is_record(X, except) -> get_id(X#except.id);
-get_id2(X) when is_record(X, op) -> get_id(X#op.id);
-get_id2(X) when is_record(X, param) -> get_id(X#param.id);
-get_id2(X) when is_record(X, type_dcl) -> get_id2(X#type_dcl.type);
-get_id2(X) when is_record(X, scoped_id) -> ic_symtab:scoped_id_strip(X);
-get_id2(X) when is_record(X, preproc) -> get_id(X#preproc.id);
-get_id2(X) when is_record(X, id_of) -> get_id2(X#id_of.id);
-get_id2(X) -> get_id(X).
-
-get_body(X) when is_record(X, module) -> X#module.body;
-get_body(X) when is_record(X, interface) -> X#interface.body;
-get_body(X) when is_record(X, struct) -> X#struct.body;
-get_body(X) when is_record(X, union) -> X#union.body;
-get_body(X) when is_record(X, enum) -> X#enum.body;
-get_body(X) when is_record(X, typedef) -> X#typedef.type; % See Note
-get_body(X) when is_record(X, except) -> X#except.body.
-
-get_type(X) when is_record(X, const) -> X#const.type;
-get_type(X) when is_record(X, type_dcl) -> X#type_dcl.type;
-get_type(X) when is_record(X, typedef) -> X#typedef.id; % See Note
-get_type(X) when is_record(X, member) -> X#member.type;
-get_type(X) when is_record(X, union) -> X#union.type;
-get_type(X) when is_record(X, case_dcl) -> X#case_dcl.type;
-get_type(X) when is_record(X, sequence) -> X#sequence.type;
-get_type(X) when is_record(X, attr) -> X#attr.type;
-get_type(X) when is_record(X, op) -> X#op.type;
-get_type(X) when is_record(X, param) -> X#param.type.
-%%get_type(X) when record(X, id_of) -> get_type(X#id_of.type).
-
-%% Temporary place
-get_tk(X) when is_record(X, interface) -> X#interface.tk;
-get_tk(X) when is_record(X, forward) -> X#forward.tk;
-get_tk(X) when is_record(X, constr_forward) -> X#constr_forward.tk;
-get_tk(X) when is_record(X, const) -> X#const.tk;
-get_tk(X) when is_record(X, type_dcl) -> X#type_dcl.tk;
-get_tk(X) when is_record(X, typedef) -> X#typedef.tk;
-get_tk(X) when is_record(X, struct) -> X#struct.tk;
-get_tk(X) when is_record(X, union) -> X#union.tk;
-get_tk(X) when is_record(X, enum) -> X#enum.tk;
-get_tk(X) when is_record(X, attr) -> X#attr.tk;
-get_tk(X) when is_record(X, except) -> X#except.tk;
-get_tk(X) when is_record(X, op) -> X#op.tk;
-get_tk(X) when is_record(X, id_of) -> X#id_of.tk;
-get_tk(X) when is_record(X, param) -> X#param.tk.
-
-
-%% Get idlist returns the list of identifiers found in typedefs, case
-%% dcls etc.
-get_idlist(X) when is_record(X, typedef) -> X#typedef.id;
-get_idlist(X) when is_record(X, member) -> X#member.id;
-get_idlist(X) when is_record(X, case_dcl) -> X#case_dcl.label;
-get_idlist(X) when is_record(X, attr) -> X#attr.id.
-
-
-is_oneway(X) when is_record(X, op) ->
- case X#op.oneway of
- {oneway, _} -> true;
- _ -> false
- end;
-is_oneway(_X) -> false.
-
-
-
-
-
-%%------------------------------------------------------------
-%%
-%% Analyze the record and seek the correct type code.
-%%
-%% NOT equal to get_tk, this will always succed !
-%%
-%%------------------------------------------------------------
-get_type_code(G, N, X) ->
- case get_type_code2(G, N, X) of
- undefined ->
- %% Remove "Package" suffix from scope
- N2 = clean_up_scope(N),
- search_tk(G,ictk:get_IR_ID(G, N2, X));
- TC ->
- TC
- end.
-
-clean_up_scope(N) ->
- clean_up_scope(N,[]).
-
-clean_up_scope([],N) ->
- lists:reverse(N);
-clean_up_scope([N|Ns],Found) ->
- case lists:suffix("Package",N) of
- true ->
- Len = length(N),
- case Len > 7 of
- true ->
- N2 = string:substr(N,1,Len-7),
- clean_up_scope(Ns,[N2|Found]);
- false ->
- clean_up_scope(Ns,[N|Found])
- end;
- false ->
- clean_up_scope(Ns,[N|Found])
- end.
-
-
-get_type_code2(_, _, X) when is_record(X, interface) -> X#interface.tk;
-get_type_code2(_, _, X) when is_record(X, forward) -> X#forward.tk;
-get_type_code2(_, _, X) when is_record(X, constr_forward) -> X#constr_forward.tk;
-get_type_code2(_, _, X) when is_record(X, const) -> X#const.tk;
-get_type_code2(_, _, X) when is_record(X, type_dcl) -> X#type_dcl.tk;
-get_type_code2(_, _, X) when is_record(X, typedef) ->
- Id = X#typedef.id,
- ET = X#typedef.tk,
- if is_list(Id) ->
- Head = hd(Id),
- if is_tuple(Head) ->
- case element(1,Head) of
- array ->
- get_array_tc(ET, element(3,Head));
- _ ->
- ET
- end;
- true ->
- ET
- end;
- true ->
- ET
- end;
-
-get_type_code2(_, _, X) when is_record(X, struct) -> X#struct.tk;
-get_type_code2(_, _, X) when is_record(X, union) -> X#union.tk;
-get_type_code2(_, _, X) when is_record(X, enum) -> X#enum.tk;
-get_type_code2(_, _, X) when is_record(X, attr) -> X#attr.tk;
-get_type_code2(_, _, X) when is_record(X, except) -> X#except.tk;
-get_type_code2(_, _, X) when is_record(X, op) -> X#op.tk;
-get_type_code2(_, _, X) when is_record(X, id_of) -> X#id_of.tk;
-get_type_code2(_, _, X) when is_record(X, param) -> X#param.tk;
-
-get_type_code2(G, N, X) when is_record(X, member) ->
- ET = get_type_code(G, N, element(2,X)),
- Id = element(3,X),
-
- if is_list(Id) ->
- Head = hd(Id),
- if is_tuple(Head) ->
- case element(1,Head) of
- array ->
- get_array_tc(ET, element(3,Head));
- _ ->
- ET
- end;
- true ->
- ET
- end;
- true ->
- ET
- end;
-
-get_type_code2(G, N, X) when is_record(X, scoped_id) ->
- element(3,ic_symtab:get_full_scoped_name(G, N, X));
-
-get_type_code2(G, N, X) when is_record(X, sequence) ->
- if is_tuple(X#sequence.length) ->
- {tk_sequence,
- get_type_code(G, N, X#sequence.type),
- list_to_integer(element(3,X#sequence.length))};
- true ->
- {tk_sequence,
- get_type_code(G, N, X#sequence.type),
- X#sequence.length}
- end;
-
-get_type_code2(_G, _N, {unsigned,{short,_}}) -> tk_ushort;
-
-get_type_code2(_G, _N, {unsigned,{long,_}}) -> tk_ulong;
-
-get_type_code2(_G, _N, {unsigned,{'long long',_}}) -> tk_ulonglong;
-
-get_type_code2(_G, _N, X) when is_record(X, fixed) ->
- {tk_fixed, X#fixed.digits, X#fixed.scale};
-
-get_type_code2(G, N, {X,_}) ->
- get_type_code2(G, N, X);
-
-get_type_code2(_, _, short) -> tk_short;
-get_type_code2(_, _, long) -> tk_long;
-get_type_code2(_, _, 'long long') -> tk_longlong;
-get_type_code2(_, _, float) -> tk_float;
-get_type_code2(_, _, double) -> tk_double;
-get_type_code2(_, _, boolean) -> tk_boolean;
-get_type_code2(_, _, char) -> tk_char;
-get_type_code2(_, _, wchar) -> tk_wchar;
-get_type_code2(_, _, octet) -> tk_octet;
-get_type_code2(_, _, string) -> tk_string;
-get_type_code2(_, _, wstring) -> tk_wstring;
-get_type_code2(_, _, any) -> tk_any.
-
-
-get_array_tc(ET, []) ->
- ET;
-get_array_tc(ET, [L|Ls]) ->
- {tk_array,
- get_array_tc(ET,Ls),
- list_to_integer(element(3,L))}.
-
-
-
-
-%%------------------------------------------------------------
-%%
-%% seek type code when not accessible by ic_forms:get_tk/1 ( should be
-%% a part of "do_gen" related functions later )
-%%
-%%------------------------------------------------------------
-search_tk(G, IR_ID) ->
- S = ic_genobj:tktab(G),
- case catch search_tk(S,IR_ID,typedef) of
- {value,TK} ->
- TK;
- _ -> %% false / exit
- case catch search_tk(S,IR_ID,struct) of
- {value,TK} ->
- TK;
- _ -> %% false / exit
- case catch search_tk(S,IR_ID,union) of
- {value,TK} ->
- TK;
- _ ->
- undefined
- end
- end
- end.
-
-
-search_tk(S, IR_ID, Type) ->
- L = lists:flatten(ets:match(S,{'_',Type,'$1','_'})),
- case lists:keysearch(IR_ID,2,L) of
- {value,TK} ->
- {value,TK};
- false ->
- search_inside_tks(L,IR_ID)
- end.
-
-
-search_inside_tks([],_IR_ID) ->
- false;
-search_inside_tks([{tk_array,TK,_}|Xs],IR_ID) ->
- case search_included_tk(TK,IR_ID) of
- {value,TK} ->
- {value,TK};
- false ->
- search_inside_tks(Xs,IR_ID)
- end.
-
-
-search_included_tk({tk_array,TK,_}, IR_ID) ->
- search_included_tk(TK,IR_ID);
-search_included_tk({tk_sequence,TK,_}, IR_ID) ->
- search_included_tk(TK,IR_ID);
-search_included_tk(TK, _IR_ID) when is_atom(TK) ->
- false;
-search_included_tk(TK, IR_ID) ->
- case element(2,TK) == IR_ID of
- true ->
- {value,TK};
- false ->
- false
- end.
-
-
-
-
-%% This is similar to get_id2 but in everything else
-%% than a module it will generate an id prefixed
-get_java_id(Id) when is_list(Id) ->
- case java_keyword_coalition(Id) of
- true ->
- "_" ++ Id;
- false ->
- Id
- end;
-get_java_id(Id_atom) when is_atom(Id_atom) ->
- Id = atom_to_list(Id_atom),
- case java_keyword_coalition(Id) of
- true ->
- "_" ++ Id;
- false ->
- Id
- end;
-get_java_id(X) ->
- Id = get_id2(X),
- case java_keyword_coalition(Id) of
- true ->
- "_" ++ Id;
- false ->
- Id
- end.
-
-java_keyword_coalition(Id) ->
- lists:member(list_to_atom(Id),
- [abstract, default, 'if', private, throw, boolean,
- do, implements, protected, throws, break,
- double, import, public, transient, byte,
- else, instanceof, return, 'try', 'case', extends,
- int, short, void, 'catch', final, interface, static,
- volatile, char, finally, long, super, while, class,
- float, native, switch, const, for, new, synchronized,
- continue, goto, package, this, true, false]).
-
-
-
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
diff --git a/lib/ic/src/ic_genobj.erl b/lib/ic/src/ic_genobj.erl
deleted file mode 100644
index eb2c24c000..0000000000
--- a/lib/ic/src/ic_genobj.erl
+++ /dev/null
@@ -1,245 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(ic_genobj).
-
-
--include_lib("ic/src/ic.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([new/1, free_table_space/1, process_space/0]).
--export([skelfiled/1, stubfiled/1, hrlfiled/1, includefiled/1]).
--export([interfacefiled/1, helperfiled/1, holderfiled/1]).
--export([is_skelfile_open/1, is_stubfile_open/1, is_hrlfile_open/1]).
--export([include_file/1, include_file_stack/1]).
--export([push_file/2, pop_file/2, sys_file/2]).
-
--export([skelscope/1, stubscope/1, impl/1, do_gen/1]).
--export([symtab/1, auxtab/1, tktab/1, pragmatab/1, optiontab/1, typedeftab/1]).
--export([idlfile/1, module/1, set_idlfile/2, set_module/2]).
-
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-%%-----------------------------------------------------------------
-%% External functions
-%%-----------------------------------------------------------------
-
-%%--------------------------------------------------------------------
-%%
-%% Initialisation stuff
-%%
-%%
-%%
-%%--------------------------------------------------------------------
-
-
-new(Opts) ->
- OptDB = ets:new(options, [set, public]),
- Warns = ets:new(warnings, [set, public]),
- Aux = ets:new(aux, [set, public]),
- Tk = ets:new(tktab, [set, public]),
- PragmaTab = ets:new(pragmatab, [bag, public]),
- TypeDefTab = ets:new(c_typedeftab, [set, public]),
- G = #genobj{options=OptDB,
- warnings=Warns,
- symtab=ic_symtab:new(),
- auxtab=Aux,
- tktab=Tk,
- pragmatab=PragmaTab,
- c_typedeftab=TypeDefTab},
- ic_error:init_errors(G),
- ic_options:add_opt(G, default_opts, true),
- ic_options:read_cfg(G, Opts), % Read any config files
- ic_options:add_opt(G, Opts, true),
- ic_symtab:symtab_add_faked_included_types(G), % Add CORBA::<Types> that as if they
- % were defined in an included file
- case ic_options:get_opt(G, be) of
- false ->
- DefBE = ic_options:defaultBe(),
- case ic_options:get_opt(G, multiple_be) of
- false ->
- ic_options:add_opt(G, be, DefBE),
- G;
- List ->
- case lists:member(DefBE, List) of
- true ->
- %% Delete the default be from the list to avoid
- %% generating it twice.
- NewList = lists:delete(DefBE, List),
- ic_options:add_opt(G, multiple_be, NewList),
- ic_options:add_opt(G, be, DefBE),
- G;
- false ->
- G
- end
- end;
- _ ->
- G
- end.
-
-
-%%--------------------------------------------------------------------
-%%
-%% Table removal
-%%
-%%
-%%
-%%--------------------------------------------------------------------
-
-
-free_table_space(G) ->
- %% Free ets tables
- ets:delete(G#genobj.options),
- ets:delete(G#genobj.symtab),
- ets:delete(G#genobj.warnings),
- ets:delete(G#genobj.auxtab),
- ets:delete(G#genobj.tktab),
- ets:delete(G#genobj.pragmatab),
- ets:delete(G#genobj.c_typedeftab),
- %% Close file descriptors
- close_fd(G#genobj.skelfiled),
- close_fd(G#genobj.stubfiled),
- close_fd(G#genobj.interfacefiled),
- close_fd(G#genobj.helperfiled),
- close_fd(G#genobj.holderfiled),
- close_fd(G#genobj.includefiled).
-
-close_fd([]) ->
- ok;
-close_fd([Fd|Fds]) ->
- file_close(Fd),
- close_fd(Fds).
-
-file_close(empty) -> ok;
-file_close(ignore) -> ok;
-file_close(Fd) ->
- file:close(Fd).
-
-
-%%--------------------------------------------------------------------
-%%
-%% Process memory usage
-%%
-%%
-%%
-%%--------------------------------------------------------------------
-
-process_space() ->
- Pheap=4*element(2,element(2,lists:keysearch(heap_size,1,process_info(self())))),
- Pstack=4*element(2,element(2,lists:keysearch(stack_size,1,process_info(self())))),
- io:format("Process current heap = ~p bytes\n",[Pheap]),
- io:format("Symbol current stack = ~p bytes\n",[Pstack]),
- io:format("-----------------------------------------------\n"),
- io:format("Totally used ~p bytes\n\n",[Pheap+Pstack]).
-
-
-
-
-
-
-skelfiled(G) -> hd(G#genobj.skelfiled).
-stubfiled(G) -> hd(G#genobj.stubfiled).
-includefiled(G) -> hd(G#genobj.includefiled).
-hrlfiled(G) -> hd(G#genobj.includefiled).
-interfacefiled(G) -> hd(G#genobj.interfacefiled).
-helperfiled(G) -> hd(G#genobj.helperfiled).
-holderfiled(G) -> hd(G#genobj.holderfiled).
-
-include_file(G) -> hd(G#genobj.includefile).
-include_file_stack(G) -> G#genobj.includefile.
-
-is_skelfile_open(G) ->
- if hd(G#genobj.skelfiled) /= empty, hd(G#genobj.skelfiled) /= ignore
- -> true;
- true -> false
- end.
-is_stubfile_open(G) ->
- if hd(G#genobj.stubfiled) /= empty, hd(G#genobj.stubfiled) /= ignore
- -> true;
- true -> false
- end.
-
-is_hrlfile_open(G) ->
- if hd(G#genobj.includefiled) /= empty, hd(G#genobj.includefiled) /= ignore
- -> true;
- true -> false
- end.
-
-%%--------------------------------------------------------------------
-%%
-%% Handling of pre processor file commands
-%%
-%%--------------------------------------------------------------------
-
-push_file(G, Id) ->
- New = G#genobj.filestack+1,
- set_idlfile(G, Id),
- G#genobj{filestack=New, do_gen=true_or_not(New)}.
-pop_file(G, Id) ->
- New = G#genobj.filestack-1,
- set_idlfile(G, Id),
- G#genobj{filestack=New, do_gen=true_or_not(New)}.
-sys_file(G, _Id) -> G#genobj{sysfile=true}.
-
-
-do_gen(G) -> G#genobj.do_gen.
-
-%%--------------------------------------------------------------------
-%%
-%% Storage routines
-%%i
-%% The generator object G is used to store many usefull bits of
-%% information so that the information doesn't need to get passed
-%% around everywhere.
-%%
-%%--------------------------------------------------------------------
-
-
-skelscope(G) -> G#genobj.skelscope.
-stubscope(G) -> G#genobj.stubscope.
-symtab(G) -> G#genobj.symtab.
-auxtab(G) -> G#genobj.auxtab.
-tktab(G) -> G#genobj.tktab.
-impl(G) -> G#genobj.impl.
-pragmatab(G) -> G#genobj.pragmatab.
-optiontab(G) -> G#genobj.options.
-typedeftab(G) -> G#genobj.c_typedeftab.
-
-idlfile(G) -> ?lookup(G#genobj.options, idlfile).
-module(G) -> ?lookup(G#genobj.options, module).
-
-set_idlfile(G, X) -> ?insert(G#genobj.options, idlfile, X).
-set_module(G, X) -> ?insert(G#genobj.options, module, ic_forms:get_id(X)).
-
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-true_or_not(X) when X < 2 ->
- true;
-true_or_not(_) ->
- false.
diff --git a/lib/ic/src/ic_java_type.erl b/lib/ic/src/ic_java_type.erl
deleted file mode 100644
index 931aa92a8e..0000000000
--- a/lib/ic/src/ic_java_type.erl
+++ /dev/null
@@ -1,1214 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(ic_java_type).
-
-
--include("icforms.hrl").
--include("ic.hrl").
--include("ic_debug.hrl").
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([getType/3, getHolderType/3,
- getParamType/4, inlinedTypes/2,
- marshalFun/4, unMarshalFun/4, getFullType/4,
- getFullType/3, getMarshalType/4, getUnmarshalType/4,
- getdim/1]).
--export([isBasicType/3, isBasicType/1]).
--export([isIntegerType/3, isIntegerType/1]).
--export([isTermType/3]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-%%-----------------------------------------------------------------
-%% External functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: getType/3
-%%-----------------------------------------------------------------
-getType(G, N, T) when is_record(T, scoped_id) ->
- {FullScopedName, _, TK, _} = ic_symtab:get_full_scoped_name(G, N, T),
- BT = ic_code:get_basetype(G, ic_util:to_dot(G,FullScopedName)),
- case BT of
- "erlang.pid" ->
- ?ICPACKAGE ++ "Pid";
- "erlang.port" ->
- ?ICPACKAGE ++ "Port";
- "erlang.ref" ->
- ?ICPACKAGE ++ "Ref";
- "erlang.term" ->
- ?ICPACKAGE ++ "Term";
- {enum, Type} ->
- getType(G, N, Type);
- Type ->
- case TK of
- {tk_array,_,_} ->
- tk2type(G,N,T,TK);
- {tk_sequence,_,_} ->
- tk2type(G,N,T,TK);
- tk_any ->
- ?ICPACKAGE ++ "Any";
- _ ->
- case isBasicType(G,N,TK) of
- true ->
- tk2type(G,N,T,TK);
- false ->
- Type %% Other types
- end
- end
- end;
-
-getType(_G, _N, S) when is_list(S) ->
- S;
-
-getType(_G, _N, T) when is_record(T, string) ->
- "java.lang.String";
-
-getType(_G, _N, T) when is_record(T, wstring) -> %% WSTRING
- "java.lang.String";
-
-getType(G, N, T) when is_record(T, struct) ->
- ic_util:to_dot(G,[ic_forms:get_id2(T)|N]);
-
-getType(G, N, T) when is_record(T, union) ->
- ic_util:to_dot(G,[ic_forms:get_id2(T)|N]);
-
-getType(G, N, T) when is_record(T, sequence) ->
- getType(G, N, ic_forms:get_type(T)) ++ "[]";
-
-getType(G, N, T) when is_record(T, enum) ->
- ic_util:to_dot(G,[ic_forms:get_id2(T)|N]);
-
-%% NOTE i am using the new isJavaElementaryType
-%% to avoid members declared as keywords (except
-%% all java elementary types) to be used as a
-%% class
-getType(G, N, T) when is_record(T, member) ->
- Type = tk2type(G,N,T,ic_forms:get_type_code(G, N, T)),
- case isJavaElementaryType(list_to_atom(Type)) of
- true ->
- Type;
- false ->
- Prefix = list_to_atom(lists:flatten(string:tokens(Type,"[]"))),
- case isJavaElementaryType(Prefix) of %% Checks if Type is an array
- %% of elementary java types
- true ->
- Type;
- false ->
- ic_forms:get_java_id(getType(G,N,ic_forms:get_type(T))) ++
- if is_record(hd(T#member.id),array) ->
- arrayEmptyDim(hd(T#member.id));
- true ->
- ""
- end
- end
- end;
-
-getType(_G, _N, {boolean, _}) ->
- "boolean";
-
-getType(_G, _N, {octet, _}) ->
- "byte";
-
-getType(_G, _N, {void, _}) ->
- "void";
-
-getType(_G, _N, {unsigned, U}) ->
- case U of
- {short,_} ->
- "short";
- {long,_} ->
- "int";
- {'long long',_} ->
- "long"
- end;
-
-getType(_G, _N, {char, _}) ->
- "char";
-
-getType(_G, _N, {wchar, _}) -> %% WCHAR
- "char";
-
-getType(_G, _N, {short, _}) ->
- "short";
-
-getType(_G, _N, {long, _}) ->
- "int";
-
-getType(_G, _N, {'long long', _}) ->
- "long";
-
-getType(_G, _N, {float, _}) ->
- "float";
-
-getType(_G, _N, {double, _}) ->
- "double";
-
-getType(_G, _N, {any, _}) ->
- ?ICPACKAGE ++ "Any".
-
-
-
-
-
-
-%%-----------------------------------------------------------------
-%% Func: getHolderType/3
-%%-----------------------------------------------------------------
-getHolderType(G, N, T) when element(1, T) == scoped_id ->
- {FullScopedName, _, TK, _} = ic_symtab:get_full_scoped_name(G, N, T),
- BT = ic_code:get_basetype(G, ic_util:to_dot(G,FullScopedName)),
- case BT of
- "erlang.pid" ->
- ?ICPACKAGE ++ "PidHolder";
- "erlang.port" ->
- ?ICPACKAGE ++ "PortHolder";
- "erlang.ref" ->
- ?ICPACKAGE ++ "RefHolder";
- "erlang.term" ->
- ?ICPACKAGE ++ "TermHolder";
- {enum, Type} ->
- getHolderType(G, N, Type);
-
- Type ->
- case TK of
- {'tk_struct', _, _, _} ->
- Type ++ "Holder";
-
- {'tk_union', _, _, _, _, _} ->
- Type ++ "Holder";
-
- {'tk_array', _ , _} ->
- Type ++ "Holder";
-
- {'tk_sequence', _ , _} ->
- Type ++ "Holder";
-
- {'tk_string', _} ->
- ?ICPACKAGE ++ "StringHolder";
-
- {'tk_wstring', _} -> %% WSTRING
- ?ICPACKAGE ++ "StringHolder";
-
- {'tk_enum', _, _, _} ->
- Type ++ "Holder";
-
- 'tk_boolean' ->
- ?ICPACKAGE ++ "BooleanHolder";
-
- 'tk_octet' ->
- ?ICPACKAGE ++ "ByteHolder";
-
- 'tk_ushort' ->
- ?ICPACKAGE ++ "ShortHolder";
-
- 'tk_ulong' ->
- ?ICPACKAGE ++ "IntHolder";
-
- 'tk_ulonglong' -> %% ULLONG
- ?ICPACKAGE ++ "LongHolder";
-
- 'tk_short' ->
- ?ICPACKAGE ++ "ShortHolder";
-
- 'tk_long' ->
- ?ICPACKAGE ++ "IntHolder";
-
- 'tk_longlong' ->
- ?ICPACKAGE ++ "LongHolder"; %% LLONG
-
- 'tk_float' ->
- ?ICPACKAGE ++ "FloatHolder";
-
- 'tk_double' ->
- ?ICPACKAGE ++ "DoubleHolder";
-
- 'tk_char' ->
- ?ICPACKAGE ++ "CharHolder";
-
- 'tk_wchar' -> %% WCHAR
- ?ICPACKAGE ++ "CharHolder";
-
- 'tk_any' ->
- ?ICPACKAGE ++ "AnyHolder";
-
- _ ->
- case isBasicType(G,N,TK) of
- true ->
- %% Faked the type !
- getHolderType(G, N, {list_to_atom(tk2type(G,N,T,TK)), -1});
- false ->
- %%io:format("TK = ~p, Type = ~p\n",[TK,Type]),
- ic_util:to_dot(G,FullScopedName) ++ "Holder"
- end
- end
- end;
-
-getHolderType(G, N, S) when is_list(S) ->
- ic_util:to_dot(G,[S|N]) ++ "Holder";
-
-getHolderType(_G, _N, T) when is_record(T, string) ->
- ?ICPACKAGE ++"StringHolder";
-
-getHolderType(_G, _N, T) when is_record(T, wstring) -> %% WSTRING
- ?ICPACKAGE ++"StringHolder";
-
-getHolderType(G, N, T) when is_record(T, struct) ->
- ic_util:to_dot(G,[ic_forms:get_id2(T)|N]) ++ "Holder";
-
-getHolderType(G, N, T) when is_record(T, union) ->
- ic_util:to_dot(G,[ic_forms:get_id2(T)|N]) ++ "Holder";
-
-getHolderType(G, N, T) when is_record(T, array) ->
- ic_util:to_dot(G,[ic_forms:get_id2(T)|N]) ++ "Holder";
-
-getHolderType(G, N, T) when is_record(T, sequence) ->
- getType(G, N, ic_forms:get_type(T)) ++ "Holder[]";
-
-getHolderType(G, N, T) when is_record(T, enum) ->
- ic_util:to_dot(G,[ic_forms:get_id2(T)|N]) ++ "Holder";
-
-getHolderType(_G, _N, {boolean, _}) ->
- ?ICPACKAGE ++"BooleanHolder";
-
-getHolderType(_G, _N, {octet, _}) ->
- ?ICPACKAGE ++"ByteHolder";
-
-getHolderType(_G, _N, {void, _}) ->
- "void";
-
-getHolderType(_G, _N, {unsigned, U}) ->
- case U of
- {short,_} ->
- ?ICPACKAGE ++"ShortHolder";
- {long,_} ->
- ?ICPACKAGE ++"IntHolder";
- {'long long',_} ->
- ?ICPACKAGE ++"LongHolder"
- end;
-
-getHolderType(_G, _N, {char, _}) ->
- ?ICPACKAGE ++"CharHolder";
-
-getHolderType(_G, _N, {wchar, _}) -> %% WCHAR
- ?ICPACKAGE ++"CharHolder";
-
-getHolderType(_G, _N, {short, _}) ->
- ?ICPACKAGE ++"ShortHolder";
-
-getHolderType(_G, _N, {long, _}) ->
- ?ICPACKAGE ++"IntHolder";
-
-getHolderType(_G, _N, {'long long', _}) ->
- ?ICPACKAGE ++"LongHolder";
-
-getHolderType(_G, _N, {float, _}) ->
- ?ICPACKAGE ++"FloatHolder";
-
-getHolderType(_G, _N, {double, _}) ->
- ?ICPACKAGE ++"DoubleHolder";
-
-getHolderType(_G, _N, {any,_}) ->
- ?ICPACKAGE ++ "AnyHolder".
-
-
-%%-----------------------------------------------------------------
-%% Func: getParamType/4
-%%-----------------------------------------------------------------
-getParamType(G, N, S, in) ->
- getType(G, N, S);
-getParamType(G, N, S, ret) ->
- getType(G, N, S);
-getParamType(G, N, S, out) ->
- getHolderType(G, N, S);
-getParamType(G, N, S, inout) ->
- getHolderType(G, N, S).
-
-
-%%-----------------------------------------------------------------
-%% Func: getUnmarshalType/4
-%%-----------------------------------------------------------------
-getUnmarshalType(G, N, X, T) when element(1, T) == scoped_id ->
- {FullScopedName, _, TK, _} = ic_symtab:get_full_scoped_name(G, N, T),
- BT = ic_code:get_basetype(G, ic_util:to_dot(G,FullScopedName)),
- case BT of
- "erlang.pid" ->
- ?ICPACKAGE ++ "PidHelper";
- "erlang.port" ->
- ?ICPACKAGE ++ "PortHelper";
- "erlang.ref" ->
- ?ICPACKAGE ++ "RefHelper";
- "erlang.term" ->
- ?ICPACKAGE ++ "TermHelper";
- {enum, Type} ->
- getUnmarshalType(G, N, X, Type);
- Type ->
- case TK of
- {'tk_struct', _, _, _} ->
- Type ++ "Helper";
-
- {'tk_union', _, _, _, _, _} ->
- Type ++ "Helper";
-
- {'tk_sequence', _ , _} ->
- Type ++ "Helper";
-
- {'tk_array', _ , _} ->
- Type ++ "Helper";
-
- {'tk_enum', _, _, _} ->
- Type ++ "Helper";
-
- {'tk_string',_} ->
- ?ERLANGPACKAGE ++ "OtpErlangString";
-
- {'tk_wstring',_} -> %% WSTRING
- ?ERLANGPACKAGE ++ "OtpErlangString";
-
- 'tk_char' ->
- ?ERLANGPACKAGE ++ "OtpErlangLong";
-
- 'tk_wchar' -> %% WCHAR
- ?ERLANGPACKAGE ++ "OtpErlangLong";
-
- 'tk_octet' ->
- ?ERLANGPACKAGE ++ "OtpErlangLong";
-
- 'tk_ushort' ->
- ?ERLANGPACKAGE ++ "OtpErlangLong";
-
- 'tk_ulong' ->
- ?ERLANGPACKAGE ++ "OtpErlangLong";
-
- 'tk_ulonglong' -> %% ULLONG
- ?ERLANGPACKAGE ++ "OtpErlangLong";
-
- 'tk_short' ->
- ?ERLANGPACKAGE ++ "OtpErlangLong";
-
- 'tk_long' ->
- ?ERLANGPACKAGE ++ "OtpErlangLong";
-
- 'tk_longlong' -> %% LLONG
- ?ERLANGPACKAGE ++ "OtpErlangLong";
-
- 'tk_float' ->
- ?ERLANGPACKAGE ++ "OtpErlangDouble";
-
- 'tk_double' ->
- ?ERLANGPACKAGE ++ "OtpErlangDouble";
-
- 'tk_boolean' ->
- ?ERLANGPACKAGE ++ "OtpErlangAtom";
-
- 'tk_void' ->
- ?ERLANGPACKAGE ++ "OtpErlangAtom";
-
- 'tk_any' ->
- ?ICPACKAGE ++ "AnyHelper";
-
- _ ->
- case isBasicType(G,N,TK) of
- true ->
- %% Faked the type !
- getUnmarshalType(G, N, X, {list_to_atom(tk2type(G,N,T,TK)), -1});
- false ->
- ic_util:to_dot(G,FullScopedName) ++ "Helper"
- end
- end
- end;
-
-getUnmarshalType(_G, _N, _X, S) when is_list(S) ->
- S ++ "Helper";
-
-getUnmarshalType(_G, _N, _X, T) when is_record(T, string) ->
- ?ERLANGPACKAGE ++ "OtpErlangString";
-
-getUnmarshalType(_G, _N, _X, T) when is_record(T, wstring) -> %% WSTRING
- ?ERLANGPACKAGE ++ "OtpErlangString";
-
-getUnmarshalType(G, N, _X, T) when is_record(T, struct) ->
- ic_util:to_dot(G,[ic_forms:get_id2(T)|N]) ++ "Helper";
-
-getUnmarshalType(G, N, _X, T) when is_record(T, union) ->
- ic_util:to_dot(G,[ic_forms:get_id2(T)|N]) ++ "Helper";
-
-getUnmarshalType(G, N, X, T) when is_record(T, sequence) andalso
- is_record(X, member) ->
- ic_util:to_dot(G,[ic_forms:get_id2(X)|N]) ++ "Helper";
-
-getUnmarshalType(G, N, X, T) when is_record(T, sequence) andalso
- is_record(X, case_dcl) ->
- ic_util:to_dot(G,[ic_forms:get_id2(X)|N]) ++ "Helper";
-
-getUnmarshalType(G, N, X, T) when is_record(T, sequence) ->
- getUnmarshalType(G, N, X, ic_forms:get_type(T)) ++ "Helper";
-
-getUnmarshalType(G, N, X, T) when is_record(T, array) andalso
- is_record(X, case_dcl) ->
- ic_util:to_dot(G,[ic_forms:get_id2(T)|N]) ++ "Helper";
-
-getUnmarshalType(G, N, _X, T) when is_record(T, enum) ->
- ic_util:to_dot(G,[ic_forms:get_id2(T)|N]) ++
- "Helper";
-
-getUnmarshalType(_G, _N, _X, {boolean, _}) ->
- ?ERLANGPACKAGE ++ "OtpErlangAtom";
-
-getUnmarshalType(_G, _N, _X, {octet, _}) ->
- ?ERLANGPACKAGE ++ "OtpErlangLong";
-
-getUnmarshalType(_G, _N, _X, {void, _}) ->
- ?ERLANGPACKAGE ++ "OtpErlangAtom";
-
-getUnmarshalType(_G, _N, _X, {unsigned, U}) ->
- case U of
- {short,_} ->
- ?ERLANGPACKAGE ++ "OtpErlangLong";
- {long,_} ->
- ?ERLANGPACKAGE ++ "OtpErlangLong";
- {'long long',_} ->
- ?ERLANGPACKAGE ++ "OtpErlangLong"
- end;
-
-getUnmarshalType(_G, _N, _X, {char, _}) ->
- ?ERLANGPACKAGE ++ "OtpErlangLong";
-
-getUnmarshalType(_G, _N, _X, {wchar, _}) -> %% WCHAR
- ?ERLANGPACKAGE ++ "OtpErlangLong";
-
-getUnmarshalType(_G, _N, _X, {short, _}) ->
- ?ERLANGPACKAGE ++ "OtpErlangLong";
-
-getUnmarshalType(_G, _N, _X, {long, _}) ->
- ?ERLANGPACKAGE ++ "OtpErlangLong";
-
-getUnmarshalType(_G, _N, _X, {'long long', _}) ->
- ?ERLANGPACKAGE ++ "OtpErlangLong";
-
-getUnmarshalType(_G, _N, _X, {float, _}) ->
- ?ERLANGPACKAGE ++ "OtpErlangDouble";
-
-getUnmarshalType(_G, _N, _X, {double, _}) ->
- ?ERLANGPACKAGE ++ "OtpErlangDouble";
-
-getUnmarshalType(_G, _N, _X, {any, _}) ->
- ?ICPACKAGE ++ "AnyHelper".
-
-%%-----------------------------------------------------------------
-%% Func: getMarshalType/4
-%%-----------------------------------------------------------------
-getMarshalType(G, N, X, T) when element(1, T) == scoped_id ->
- {FullScopedName, _, TK, _} = ic_symtab:get_full_scoped_name(G, N, T),
- BT = ic_code:get_basetype(G, ic_util:to_dot(G,FullScopedName)),
- case BT of
- "erlang.pid" ->
- ?ICPACKAGE ++ "PidHelper";
- "erlang.port" ->
- ?ICPACKAGE ++ "PortHelper";
- "erlang.ref" ->
- ?ICPACKAGE ++ "RefHelper";
- "erlang.term" ->
- ?ICPACKAGE ++ "TermHelper";
- {enum, Type} ->
- getMarshalType(G, N, X, Type);
- Type ->
- case TK of
- {'tk_struct', _, _, _} ->
- Type ++ "Helper";
-
- {'tk_union', _, _, _, _, _} ->
- Type ++ "Helper";
-
- {'tk_array', _ , _} ->
- Type ++ "Helper";
-
- {'tk_sequence', _ , _} ->
- Type ++ "Helper";
-
- {'tk_enum', _, _, _} ->
- Type ++ "Helper";
-
- {'tk_string',_} ->
- "string";
-
- {'tk_wstring',_} -> %% WSTRING
- "string";
-
- 'tk_char' ->
- "char";
-
- 'tk_wchar' -> %% WCHAR
- "char";
-
- 'tk_octet' ->
- "byte";
-
- 'tk_ushort' ->
- "ushort";
-
- 'tk_ulong' ->
- "uint";
-
- 'tk_ulonglong' -> %% ULLONG
- "ulong";
-
- 'tk_short' ->
- "short";
-
- 'tk_long' ->
- "int";
-
- 'tk_longlong' -> %% LLONG
- "long";
-
- 'tk_float' ->
- "float";
-
- 'tk_double' ->
- "double";
-
- 'tk_boolean' ->
- "boolean";
-
- 'tk_void' ->
- "atom";
-
- 'tk_any' ->
- ?ICPACKAGE ++ "AnyHelper";
-
- _ ->
- case isBasicType(G,N,TK) of
- true ->
- %% Faked the type !
- getMarshalType(G, N, X, {list_to_atom(tk2type(G,N,T,TK)), -1});
- false ->
- ic_util:to_dot(G,FullScopedName) ++ "Helper"
- end
- end
- end;
-
-getMarshalType(_G, _N, _X, S) when is_list(S) ->
- S ++ "Helper";
-
-getMarshalType(_G, _N, _X, T) when is_record(T, string) ->
- "string";
-
-getMarshalType(_G, _N, _X, T) when is_record(T, wstring) -> %% WSTRING
- "string";
-
-getMarshalType(G, N, _X, T) when is_record(T, struct) ->
- ic_util:to_dot(G,[ic_forms:get_id2(T)|N]) ++
- "Helper";
-
-getMarshalType(G, N, _X, T) when is_record(T, union) ->
- ic_util:to_dot(G,[ic_forms:get_id2(T)|N]) ++
- "Helper";
-
-getMarshalType(G, N, X, T) when is_record(T, array) andalso
- is_record(X, case_dcl) ->
- ic_util:to_dot(G,[ic_forms:get_id2(T)|N]) ++
- "Helper";
-
-getMarshalType(G, N, X, T) when is_record(T, sequence) andalso
- is_record(X, member) ->
- ic_util:to_dot(G,[ic_forms:get_id2(X)|N]) ++
- "Helper";
-
-getMarshalType(G, N, _X, T) when is_record(T, sequence) ->
- getType(G, N, ic_forms:get_type(T)) ++
- "Helper";
-
-getMarshalType(G, N, _X, T) when is_record(T, enum) ->
- ic_util:to_dot(G,[ic_forms:get_id2(T)|N]) ++
- "Helper";
-
-getMarshalType(_G, _N, _X, {boolean, _}) ->
- "boolean";
-
-getMarshalType(_G, _N, _X, {octet, _}) ->
- "byte";
-
-getMarshalType(_G, _N, _X, {void, _}) ->
- ""; % <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
-
-getMarshalType(_G, _N, _X, {unsigned, U}) ->
- case U of
- {short,_} ->
- "ushort";
- {long,_} ->
- "uint";
- {'long long',_} ->
- "ulong"
- end;
-
-getMarshalType(_G, _N, _X, {short, _}) ->
- "short";
-getMarshalType(_G, _N, _X, {long, _}) ->
- "int";
-getMarshalType(_G, _N, _X, {'long long', _}) ->
- "long";
-getMarshalType(_G, _N, _X, {float, _}) ->
- "float";
-getMarshalType(_G, _N, _X, {double, _}) ->
- "double";
-getMarshalType(_G, _N, _X, {char, _}) ->
- "char";
-getMarshalType(_G, _N, _X, {wchar, _}) -> %% WCHAR
- "char";
-getMarshalType(_G, _N, _X, {any, _}) ->
- ?ICPACKAGE ++ "AnyHelper".
-
-
-
-
-%%-----------------------------------------------------------------
-%% Func: unMarshalFun/4
-%%-----------------------------------------------------------------
-unMarshalFun(G, N, X, T) when element(1, T) == scoped_id ->
- {FullScopedName, _, TK, _} = ic_symtab:get_full_scoped_name(G, N, T),
- BT = ic_code:get_basetype(G, ic_util:to_dot(G,FullScopedName)),
- case BT of
- "erlang.pid" ->
- ".read_pid()";
- "erlang.port" ->
- ".read_port()";
- "erlang.ref" ->
- ".read_ref()";
- "erlang.term" ->
- ".read_term()";
- {enum, Type} ->
- unMarshalFun(G, N, X, Type);
- _Type ->
- case isBasicType(G,N,TK) of
- true ->
- case TK of
- {'tk_string',_} ->
- ".read_string()";
-
- {'tk_wstring',_} -> %% WSTRING
- ".read_string()";
-
- 'tk_boolean' ->
- ".read_boolean()";
-
- 'tk_octet' ->
- ".read_byte()";
-
- 'tk_ushort' ->
- ".read_ushort()";
-
- 'tk_ulong' ->
- ".read_uint()";
-
- 'tk_ulonglong' -> %% ULLONG
- ".read_ulong()";
-
- 'tk_short' ->
- ".read_short()";
-
- 'tk_long' ->
- ".read_int()";
-
- 'tk_longlong' -> %% LLONG
- ".read_long()";
-
- 'tk_float' ->
- ".read_float()";
-
- 'tk_double' ->
- ".read_double()";
-
- 'tk_char' ->
- ".read_char()";
-
- 'tk_wchar' -> %% WCHAR
- ".read_char()";
-
- _ ->
- %% Faked the type !
- unMarshalFun(G, N, X, {list_to_atom(tk2type(G,N,X,TK)), -1})
- end;
- false ->
- ".unmarshal()"
- end
- end;
-
-unMarshalFun(_G, _N, _X, S) when is_list(S) ->
- ".unmarshal()";
-
-unMarshalFun(_G, _N, _X, T) when is_record(T, string) ->
- ".read_string()";
-
-unMarshalFun(_G, _N, _X, T) when is_record(T, wstring) -> %% WSTRING
- ".read_string()";
-
-unMarshalFun(_G, _N, _X, T) when is_record(T, struct) ->
- ".unmarshal((" ++ ?ERLANGPACKAGE ++ "OtpErlangTuple)";
-
-unMarshalFun(_G, _N, _X, T) when is_record(T, union) ->
- ".unmarshal((" ++ ?ERLANGPACKAGE ++ "OtpErlangTuple)";
-
-unMarshalFun(_G, _N, _X, T) when is_record(T, sequence) ->
- ".unmarshal((" ++ ?ERLANGPACKAGE ++ "OtpErlanglist)";
-
-unMarshalFun(_G, _N, _X, T) when is_record(T, enum) ->
- ".unmarshal((" ++ ?ERLANGPACKAGE ++ "OtpErlangAtom)";
-
-unMarshalFun(_G, _N, _X, {boolean, _}) ->
- ".read_boolean()";
-
-unMarshalFun(_G, _N, _X, {octet, _}) ->
- ".read_byte()";
-
-unMarshalFun(_G, _N, _X, {void, _}) ->
- "";
-
-unMarshalFun(_G, _N, _X, {unsigned, U}) ->
- case U of
- {short,_} ->
- ".read_ushort()";
- {long,_} ->
- ".read_uint()";
- {'long long',_} ->
- ".read_ulong()"
- end;
-
-unMarshalFun(_G, _N, _X, {short, _}) ->
- ".read_short()";
-unMarshalFun(_G, _N, _X, {long, _}) ->
- ".read_int()";
-unMarshalFun(_G, _N, _X, {'long long', _}) ->
- ".read_long()";
-unMarshalFun(_G, _N, _X, {float, _}) ->
- ".read_float()";
-unMarshalFun(_G, _N, _X, {double, _}) ->
- ".read_double()";
-unMarshalFun(_G, _N, _X, {char, _}) ->
- ".read_char()";
-unMarshalFun(_G, _N, _X, {wchar, _}) -> %% WCHAR
- ".read_char()".
-
-
-
-
-
-%%-----------------------------------------------------------------
-%% Func: getFullType/4 - /3
-%%
-%% Note : Similar to the getType/3 with the major difference
-%% thet on arrays and sequences it will also declare
-%% their sizes. Used for "new" declarations
-%%
-%%-----------------------------------------------------------------
-
-
-getFullType(G, N, X, T) when is_record(X, typedef) andalso is_record(T, array) ->
- FullDim =
- tk2FullType(G,N,X,ic_forms:get_tk(X)) ++
- getFullDim(G,N,T#array.size),
- fixArrayDims(FullDim);
-
-getFullType(G, N, X, T) when is_record(X, member) andalso is_record(T, array) ->
- FullDim =
- getFullType(G, N, ic_forms:get_type(X)) ++
- getFullDim(G,N,T#array.size),
- fixArrayDims(FullDim);
-
-getFullType(G, N, X, T) when is_record(X, case_dcl) andalso is_record(T, array) ->
- FullDim =
- getFullType(G, N, ic_forms:get_type(X)) ++
- getFullDim(G,N,T#array.size),
- fixArrayDims(FullDim);
-
-getFullType(G, N, _X, T) ->
- getFullType(G, N, T).
-
-
-
-getFullType(G, N, T) when is_record(T, scoped_id) ->
- {FullScopedName, _, TK, _} = ic_symtab:get_full_scoped_name(G, N, T),
- case TK of
- {tk_array,_,_} ->
- tk2FullType(G,N,T,TK);
- {tk_sequence,_,_} ->
- tk2FullType(G,N,T,TK);
- _ ->
- case isBasicType(G,N,TK) of
- true ->
- tk2FullType(G,N,T,TK);
- false ->
- %% Other types
- ic_code:get_basetype(G, ic_util:to_dot(G,FullScopedName))
- end
- end;
-
-getFullType(G, N, T) when is_record(T, sequence) ->
- fixSeqDims(getType(G,N,T),"_length");
-
-getFullType(G, N, T) ->
- getType(G, N, T).
-
-
-
-%% In order to make a legal declaration
-%% of an assignable array, the dimensions
-%% of empty array sequences are swifted to
-%% the end of the type
-fixArrayDims(Cs) ->
- fixArrayDims(Cs,[],[]).
-
-fixArrayDims([],Fulls,Emptys) ->
- lists:reverse(Fulls) ++ Emptys;
-fixArrayDims([91,93|Rest],Fulls,Emptys) ->
- fixArrayDims(Rest,Fulls,[91,93|Emptys]);
-fixArrayDims([C|Rest],Fulls,Emptys) ->
- fixArrayDims(Rest,[C|Fulls],Emptys).
-
-
-%% In order to make a legal declaration
-%% of an assignable array, the dimensions
-%% of empty array of sequences are swifted
-%% to the end of the type
-fixSeqDims(Cs,Length) ->
- fixSeqDims(Cs,Length,[]).
-
-fixSeqDims([],_Length,Found) ->
- lists:reverse(Found);
-fixSeqDims([91,93|Rest],Length,Found) when is_list(Length) ->
- lists:reverse([93|lists:reverse(Length)] ++
- [91|Found]) ++ Rest;
-fixSeqDims([C|Rest],Length,Found) ->
- fixSeqDims(Rest,Length,[C|Found]).
-
-
-
-%%-----------------------------------------------------------------
-%% Func: inlinedTypes/2
-%%-----------------------------------------------------------------
-inlinedTypes(PkgName, Type) when is_record(Type, struct) ->
- "_" ++ PkgName ++ ".";
-inlinedTypes(PkgName, Type) when is_record(Type, union) ->
- "_" ++ PkgName ++ ".";
-inlinedTypes(PkgName, Type) when is_record(Type, enum) ->
- "_" ++ PkgName ++ ".";
-inlinedTypes(_, _) ->
- "".
-
-%%-----------------------------------------------------------------
-%% Func: marshalFun/4
-%%-----------------------------------------------------------------
-marshalFun(G, N, X, Type) ->
- case isBasicType(G, N, Type) of
- true ->
- ".write_" ++ getMarshalType(G, N, X, Type);
- _ ->
- getMarshalType(G, N, X, Type) ++ ".marshal"
- end.
-
-
-%%-----------------------------------------------------------------
-%% Func: isBasicType/3
-%%-----------------------------------------------------------------
-isBasicType(G, N, S) when element(1, S) == scoped_id ->
- {_, _, TK, _} = ic_symtab:get_full_scoped_name(G, N, S),
- isBasicType(ictype:fetchType(TK));
-
-isBasicType(G, N, X) when is_record(X, member) ->
- if is_record(hd(element(3,X)), array) ->
- false;
- true ->
- isBasicType(G, N, element(2,X))
- end;
-
-isBasicType(_G, _N, {unsigned, {long, _}} ) ->
- true;
-
-isBasicType(_G, _N, {unsigned, {short, _}} ) ->
- true;
-
-isBasicType(_G, _N, {unsigned, {'long long', _}} ) ->
- true;
-
-isBasicType(_G, _N, {'long long', _} ) ->
- true;
-
-isBasicType(_G, _N, {Type, _} ) ->
- isBasicType(Type);
-
-isBasicType(_G, _N, Type) ->
- isBasicType(Type).
-
-
-%%-----------------------------------------------------------------
-%% Func: isBasicType/1
-%%-----------------------------------------------------------------
-
-isBasicType( Type ) ->
- lists:member(Type,
- [tk_short,short,
- tk_long,long,
- tk_longlong,longlong, %% LLONG
- tk_ushort,ushort,
- tk_ulong,ulong,
- tk_ulonglong,ulonglong, %% ULLONG
- tk_float,float,
- tk_double,double,
- tk_boolean,boolean,
- tk_char,char,
- tk_wchar,wchar, %% WCHAR
- tk_octet,octet,
- tk_wstring,wstring, %% WSTRING
- tk_string,string]).
-
-%% returns true if the Type is a java elementary type
-isJavaElementaryType( Type ) ->
- lists:member(Type,
- [byte, char, wchar, boolean,
- int, short, long, 'long long', float, double]).
-
-%%-----------------------------------------------------------------
-%% Func: isIntegerType/3
-%%-----------------------------------------------------------------
-isIntegerType(G, N, S) when element(1, S) == scoped_id ->
- {_, _, TK, _} = ic_symtab:get_full_scoped_name(G, N, S),
- isIntegerType(ictype:fetchType(TK));
-isIntegerType(_G, _N, {unsigned, {long, _}} ) ->
- true;
-isIntegerType(_G, _N, {unsigned, {short, _}} ) ->
- true;
-isIntegerType(_G, _N, {unsigned, {'long long', _}} ) ->
- true;
-isIntegerType(_G, _N, {'long long', _} ) ->
- true;
-isIntegerType(_G, _N, {Type, _} ) ->
- isIntegerType(Type);
-isIntegerType(_G, _N, Type) ->
- isIntegerType(Type).
-
-%%-----------------------------------------------------------------
-%% Func: isIntegerType/1
-%%-----------------------------------------------------------------
-
-isIntegerType( Type ) ->
- lists:member(Type,
- [tk_short,short,
- tk_long,long,
- tk_longlong,longlong, %% LLONG
- tk_ushort,ushort,
- tk_ulong,ulong,
- tk_ulonglong,ulonglong, %% ULLONG
- tk_char,char,
- tk_wchar,wchar, %% WCHAR
- tk_octet,octet]).
-
-
-
-%%-----------------------------------------------------------------
-%% Func: isTerm/3
-%%-----------------------------------------------------------------
-isTermType(G, N, T) ->
- case getType(G,N,T) of
- "com.ericsson.otp.ic.Term" ->
- true;
- _ ->
- false
- end.
-
-
-
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-
-
-%% Changes the typecode to the
-%% corresponding "basic" type
-tk2type(_G,_N,_X,{'tk_struct', _IFRId, "port", _ElementList}) ->
- ?ICPACKAGE ++ "Port";
-tk2type(_G,_N,_X,{'tk_struct', _IFRId, "pid", _ElementList}) ->
- ?ICPACKAGE ++ "Pid";
-tk2type(_G,_N,_X,{'tk_struct', _IFRId, "ref", _ElementList}) ->
- ?ICPACKAGE ++ "Ref";
-tk2type(_G,_N,_X,{'tk_struct', _IFRId, "term", _ElementList}) ->
- ?ICPACKAGE ++ "Term";
-tk2type(_G,_N,_X,{'tk_string', _}) ->
- "java.lang.String";
-tk2type(_G,_N,_X,{'tk_wstring', _}) -> %% WSTRING
- "java.lang.String";
-tk2type(G,N,X,{'tk_array', ElemTC, Dim}) ->
- tkarr2decl(G,N,X,{'tk_array', ElemTC, Dim});
-tk2type(G,N,X,{'tk_sequence', ElemTC, MaxLsextractength}) ->
- tkseq2decl(G,N,X,{'tk_sequence', ElemTC, MaxLsextractength});
-tk2type(G,N,_X,{'tk_struct', IFRId, Name, _ElementList}) ->
- ScopedId=
- lists:reverse(string:tokens(lists:nth(2,string:tokens(IFRId,":")),"/")),
-
- case ic_forms:clean_up_scope([Name|N]) of
- ScopedId ->
- %% Right path, use N instead
- ic_util:to_dot(G,[Name|N]);
- _ ->
- %% Ugly work arround
- ic_util:to_dot(G,ScopedId)
- end;
-tk2type(G,N,_X,{'tk_union', IFRId, Name, _, _, _ElementList}) ->
- ScopedId=
- lists:reverse(string:tokens(lists:nth(2,string:tokens(IFRId,":")),"/")),
-
- case ic_forms:clean_up_scope([Name|N]) of
- ScopedId ->
- %% Right path, use N instead
- ic_util:to_dot(G,[Name|N]);
- _ ->
- %% Ugly work arround
- ic_util:to_dot(G,ScopedId)
- end;
-tk2type(_G,_N,_X,{'tk_enum', _Id, Name, _ElementList}) ->
- Name;
-tk2type(_G,_N,_X,tk_void) ->
- "void";
-tk2type(_G,_N,_X,tk_long) ->
- "int";
-tk2type(_G,_N,_X,tk_longlong) -> %% LLONG
- "long";
-tk2type(_G,_N,_X,tk_short) ->
- "short";
-tk2type(_G,_N,_X,tk_ulong) ->
- "int";
-tk2type(_G,_N,_X,tk_ulonglong) -> %% ULLONG
- "long";
-tk2type(_G,_N,_X,tk_ushort) ->
- "short";
-tk2type(_G,_N,_X,tk_float) ->
- "float";
-tk2type(_G,_N,_X,tk_double) ->
- "double";
-tk2type(_G,_N,_X,tk_boolean) ->
- "boolean";
-tk2type(_G,_N,_X,tk_char) ->
- "char";
-tk2type(_G,_N,_X,tk_wchar) -> %% WCHAR
- "char";
-tk2type(_G,_N,_X,tk_octet) ->
- "byte";
-tk2type(_G,_N,_X,tk_string) ->
- "java.lang.String";
-tk2type(_G,_N,_X,tk_wstring) -> %% WSTRING
- "java.lang.String";
-tk2type(_G,_N,_X,tk_any) ->
- ?ICPACKAGE ++ "Any";
-tk2type(_G,_N,_X,tk_term) -> %% Term
- ?ICPACKAGE ++ "Term".
-
-%% Changes the sequence typecode to the
-%% corresponding "basic" structure
-tkseq2decl(G,N,X,TKSeq) ->
- tkseq2decl2(G,N,X,TKSeq,[],[]).
-
-tkseq2decl2(G,N,X,{tk_sequence,E,D},[],Ds) ->
- tkseq2decl2(G,N,X,E,[],[D|Ds]);
-tkseq2decl2(G,N,X,TkEl,[],Ds) ->
- ElName = tk2type(G,N,X,TkEl),
- ElName ++ getdim(Ds).
-
-%% Changes the array typecode to the
-%% corresponding "basic" structure
-tkarr2decl(G,N,X,TKArr) ->
- tkarr2decl2(G,N,X,TKArr,[],[]).
-
-tkarr2decl2(G,N,X,{tk_array,E,D},[],Ds) ->
- tkarr2decl2(G,N,X,E,[],[D|Ds]);
-tkarr2decl2(G,N,X,TkEl,[],Ds) ->
- ElName = tk2type(G,N,X,TkEl),
- ElName ++ getdim(Ds).
-
-getdim([]) ->
- "";
-getdim([_D|Ds]) ->
- getdim(Ds) ++ "[]".
-
-
-
-%% Changes the typecode to the corresponding "basic" type
-%% used for variable declarations where arrays and sequences
-%% are declared with there full dimensions
-tk2FullType(G,N,X,{'tk_array', ElemTC, Dim}) ->
- tkarr2FullDecl(G,N,X,{'tk_array', ElemTC, Dim});
-tk2FullType(G,N,X,{'tk_sequence', ElemTC, MaxLsextractength}) ->
- tkseq2FullDecl(G,N,X,{'tk_sequence', ElemTC, MaxLsextractength});
-tk2FullType(G,N,X,TK) ->
- tk2type(G,N,X,TK).
-
-
-%% Changes the sequence typecode to the
-%% corresponding "basic" structure here
-%% arrays and sequences are declared with
-%% their full dimensions
-tkseq2FullDecl(G,N,X,TKSeq) ->
- tkseq2FullDecl2(G,N,X,TKSeq,[],[]).
-
-tkseq2FullDecl2(G,N,X,{tk_sequence,E,D},[],Ds) ->
- tkseq2FullDecl2(G,N,X,E,[],[D|Ds]);
-tkseq2FullDecl2(G,N,X,TkEl,[],Ds) ->
- ElName = tk2FullType(G,N,X,TkEl),
- ElName ++ getdim(Ds).
-
-%% Changes the array typecode to the
-%% corresponding "basic" structure
-tkarr2FullDecl(G,N,X,TKArr) ->
- tkarr2FullDecl2(G,N,X,TKArr,[],[]).
-
-tkarr2FullDecl2(G,N,X,{tk_array,E,D},[],Ds) ->
- tkarr2FullDecl2(G,N,X,E,[],[D|Ds]);
-tkarr2FullDecl2(G,N,X,TkEl,[],Ds) ->
- ElName = tk2FullType(G,N,X,TkEl),
- ElName ++ getFullDim(G,N,Ds).
-
-getFullDim(_G,_N,[]) ->
- "";
-getFullDim(G,N,[D|Ds]) when is_record(D,scoped_id) ->
- {FSN, _, _, _} = ic_symtab:get_full_scoped_name(G, N, D),
- "[" ++ ic_util:to_dot(G,FSN) ++ "]" ++ getFullDim(G,N,Ds);
-getFullDim(G,N,[D|Ds]) when is_integer(D) ->
- "[" ++ integer_to_list(D) ++ "]" ++ getFullDim(G,N,Ds);
-getFullDim(G,N,[D|Ds]) when is_tuple(D) ->
- "[" ++ ic_util:eval_java(G,N,D) ++ "]" ++ getFullDim(G,N,Ds).
-
-
-
-%% Constructs an array empty dimension string
-%% used for array variable declaration
-arrayEmptyDim(X) ->
- arrayEmptyDim2(X#array.size).
-
-arrayEmptyDim2([_D]) ->
- "[]";
-arrayEmptyDim2([_D |Ds]) ->
- "[]" ++ arrayEmptyDim2(Ds).
-
-
-
diff --git a/lib/ic/src/ic_jbe.erl b/lib/ic/src/ic_jbe.erl
deleted file mode 100644
index 56518a681b..0000000000
--- a/lib/ic/src/ic_jbe.erl
+++ /dev/null
@@ -1,1488 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
-
--module(ic_jbe).
-
-
--export([do_gen/3, gen/3, emit_type_function/4]).
-
-
-
--include("icforms.hrl").
--include("ic.hrl").
--include("ic_debug.hrl").
--include_lib("stdlib/include/erl_compile.hrl").
-
-
-
-%%------------------------------------------------------------
-%%
-%% Entry point
-%%
-%%------------------------------------------------------------
-
-do_gen(G, _File, Form) ->
- gen(G, [], Form).
-
-
-%%------------------------------------------------------------
-%%
-%% Generate the client side C stubs.
-%%
-%% Each module is generated to a separate file.
-%%
-%% Each function needs to generate a function head and
-%% a body. IDL parameters must be converted into C parameters.
-%%
-%%------------------------------------------------------------
-
-gen(G, N, [X|Xs]) when is_record(X, preproc) ->
- NewG = handle_preproc(G, N, X#preproc.cat, X),
- gen(NewG, N, Xs);
-
-gen(G, N, [X|Xs]) when is_record(X, module) ->
- gen_module(G, N, X),
- gen(G, N, Xs);
-
-gen(G, N, [X|Xs]) when is_record(X, interface) ->
- gen_interface(G, N, X),
- gen(G, N, Xs);
-
-gen(G, N, [X|Xs]) when is_record(X, const) ->
- ic_constant_java:gen(G, N, X),
- gen(G, N, Xs);
-
-gen(G, N, [X|Xs]) when is_record(X, op) ->
- gen(G, N, Xs);
-
-gen(G, N, [X|Xs]) when is_record(X, attr) ->
- gen(G, N, Xs);
-
-gen(G, N, [X|Xs]) when is_record(X, except) ->
- gen_exception(G, N, X),
- gen(G, N, Xs);
-
-gen(G, N, [X|Xs]) when is_record(X, enum) ->
- ic_enum_java:gen(G, N, X),
- gen(G, N, Xs);
-
-gen(G, N, [X|Xs]) when is_record(X, struct) ->
- ic_struct_java:gen(G, N, X),
- gen(G, N, Xs);
-
-gen(G, N, [X|Xs]) when is_record(X, union) ->
- ic_union_java:gen(G, N, X),
- gen(G, N, Xs);
-
-gen(G, N, [X|Xs]) when is_record(X, typedef) ->
- gen_typedef(G, N, X),
- gen(G, N, Xs);
-
-gen(G, N, [X|Xs]) when is_record(X, member) ->
- %%?PRINTDEBUG2("gen member: ~p\n",[ic_forms:get_type(X)]),
- gen_member(G, N, X),
- gen(G, N, Xs);
-
-gen(G, N, [X|Xs]) when is_record(X, case_dcl) ->
- %%?PRINTDEBUG2("gen case decl: ~p\n",[ic_forms:get_type(X)]),
- gen(G, N, [ic_forms:get_type(X)]),
- gen(G, N, Xs);
-
-gen(G, N, [_|Xs]) ->
- gen(G, N, Xs);
-
-gen(_G, _N, []) ->
- ok.
-
-
-%%%--------------------------------------------
-%%%
-%%% Just generates the directory to host
-%%% the module files
-%%%
-%%%--------------------------------------------
-
-gen_module(G, N, X) ->
- case ic_genobj:do_gen(G) of
-
- true -> %% Generate & register
- N1 = [ic_forms:get_id2(X) | N],
- %% Create directory
- ic_file:createJavaDirectory(G, N1),
- gen(G, N1, ic_forms:get_body(X));
-
- false -> %% Register only
- N1 = [ic_forms:get_id2(X) | N],
- reg(G, N1, ic_forms:get_body(X))
- end.
-
-reg(G, N, [X|_Xs]) when is_record(X, module) ->
- reg(G, [ic_forms:get_id2(X) | N], ic_forms:get_body(X));
-
-reg(G, N, [X|_Xs]) when is_record(X, interface) ->
- reg(G, [ic_forms:get_id2(X) | N], ic_forms:get_body(X));
-
-reg(G, N, [X|Xs]) when is_record(X, typedef) ->
- Name = ic_util:to_dot(G,[ic_forms:get_java_id(X) | N]),
- case X#typedef.type of
- {scoped_id,_,_,_} ->
- {FullScopedName, _, _, _} =
- ic_symtab:get_full_scoped_name(G, N, X#typedef.type),
- Type = ic_code:get_basetype(G, ic_util:to_dot(G,FullScopedName)),
- ic_code:insert_typedef(G, Name, Type);
- _ ->
- ok
- end,
- reg(G, N, Xs);
-
-reg(G, N, [_|Xs]) ->
- reg(G, N, Xs);
-
-reg(_G, _N, []) ->
- ok.
-
-
-
-
-%%%----------------------------------------------
-%%%
-%%% Generates the interface code
-%%%
-%%%----------------------------------------------
-
-gen_interface(G, N, X) ->
- case ic_genobj:do_gen(G) of
- true ->
- G1 = ic_file:javaInterfaceFilePush(G, N, X),
-
- %% Generate Interface file
- InterfaceFd = ic_genobj:interfacefiled(G1),
- emit_interface(G1, N, X, InterfaceFd),
-
- %% Generate Helper file
- HelperFd = ic_genobj:helperfiled(G1),
- emit_helper(G1, N, X, HelperFd),
-
- %% Generate Holder file
- HolderFd = ic_genobj:holderfiled(G1),
- emit_holder(G1, N, X, HolderFd),
-
- %% Generate Stub file
- StubFd = ic_genobj:stubfiled(G1),
- emit_stub(G1,N,X,StubFd), %<--------------------------------------------------- 1
-
- %% Generate Skeleton file
- SkelFd = ic_genobj:skelfiled(G1),
- emit_skel(G1, N, X, SkelFd),
-
- ic_file:javaInterfaceFilePop(G1);
- false ->
- ok
- end.
-
-
-
-
-%%%--------------------------------------------
-%%%
-%%% Typedef redirection
-%%%
-%%%--------------------------------------------
-
-gen_typedef(G, N, X) ->
- Name = ic_util:to_dot(G,[ic_forms:get_java_id(X) | N]),
- case X#typedef.type of
- {scoped_id,_,_,_} ->
- {FullScopedName, _, _, _} =
- ic_symtab:get_full_scoped_name(G, N, X#typedef.type),
- Type = ic_code:get_basetype(G, ic_util:to_dot(G,FullScopedName)),
- ic_code:insert_typedef(G, Name, Type);
- _ ->
- ok
- end,
- gen_typedef_1(G, N, X, ic_forms:get_body(X)).
-
-gen_typedef_1(G, N, X, Type) when is_record(Type, sequence) ->
- ic_sequence_java:gen(G, N, Type, ic_forms:get_java_id(X));
-gen_typedef_1(G, N, X, Type) when is_record(Type, array) ->
- ic_array_java:gen(G, N, X, Type);
-gen_typedef_1(G, N, X, _Type) ->
- gen_typedef_2(G, N, X, X#typedef.id),
- ok.
-
-gen_typedef_2(G, N, X, Type) when is_record(Type, array) ->
- gen_typedef_1(G, N, X, Type);
-gen_typedef_2(G, N, X, Type) when is_list(Type) ->
- case Type of
- [] ->
- ok;
- _ ->
- gen_typedef_2(G, N, X, hd(Type)),
- gen_typedef_2(G, N, X, tl(Type))
- end;
-%gen_typedef_2(G, N, X, Type) -> %% Generating Helpers for typedef
-% %% Stoped due to compatibility problems
-% %% with erl_genserv backend
-% case ic_java_type:isBasicType(G,N,X#typedef.type) of
-% true ->
-% ok;
-% false ->
-% case ic_forms:get_type_code(G,N,X#typedef.type) of
-% {'tk_struct', _, _, _} ->
-% ic_struct_java:gen(G, N, X);
-% {'tk_sequence',_,_} ->
-% ic_sequence_java:gen(G, N, X, ic_forms:get_java_id(X)),
-% ok;
-% _ ->
-% ok
-% end
-% end;
-gen_typedef_2(_G, _N, _X, _Type) ->
- ok.
-
-
-
-%%%--------------------------------------------
-%%%
-%%% Member redirection
-%%%
-%%%--------------------------------------------
-
-gen_member(G, N, X) ->
- gen_member_1(G, N, X, [X#member.type]),
- gen_member_2(G, N, X, X#member.id).
-
-
-gen_member_1(_G, _N, _X, []) ->
- ok;
-
-gen_member_1(G, N, X, [T|Ts]) when is_record(T, sequence) ->
- ic_sequence_java:gen(G, N, T, ic_forms:get_java_id(X)),
- gen_member_1(G, N, X, Ts);
-
-gen_member_1(G, N, X, [T|Ts]) ->
- gen(G,N,[T]),
- gen_member_1(G,N,X,Ts).
-
-
-gen_member_2(_G, _N, _X, []) ->
- ok;
-
-gen_member_2(G, N, X, [T|Ts]) when is_record(T, array) -> %% BUG !
- ic_array_java:gen(G, N, X, T),
- gen_member_2(G, N, X, Ts);
-
-gen_member_2(G, N, X, [_T|Ts]) ->
- gen_member_2(G, N, X, Ts).
-
-
-
-gen_exception(_G, N, X) ->
- io:format("Warning : Exceptions not supported for java mapping, ~p ignored\n",
- [ic_util:to_colon([ic_forms:get_java_id(X)|N])]),
- ok.
-
-
-
-%%%-----------------------------------------------------
-%%%
-%%% Interface file generation
-%%%
-%%%-----------------------------------------------------
-
-emit_interface(G, N, X, Fd) ->
- Interface = ic_forms:get_java_id(X), %% Java Interface Name
- IFCName = ic_forms:get_id2(X), %% Internal Interface Name
-
- ic_codegen:emit(Fd, "public interface ~s {\n\n",[Interface]),
- Body = ic_forms:get_body(X),
-
- %% Generate type declarations inside interface
- gen(G, [IFCName |N], Body),
-
- lists:foreach(fun({_Name, Body1}) ->
- emit_interface_prototypes(G, [IFCName|N], Body1, Fd) end,
- [{x, Body} | X#interface.inherit_body]),
-
- ic_codegen:emit(Fd, "}\n\n").
-
-
-emit_interface_prototypes(G, N, [X |Xs], Fd) when is_record(X, op) ->
-
- {_, ArgNames, TypeList} = extract_info(G, N, X),
- {R, ParameterTypes, _} = TypeList,
-
- OpName = ic_forms:get_java_id(X),
- RT = ic_java_type:getParamType(G,N,R,ret),
- PL = ic_util:mk_list(gen_par_list(G, N, X, ParameterTypes,ArgNames)),
-
- ic_codegen:emit(Fd, "/*\n"),
- ic_codegen:emit(Fd, " * Operation ~p interface functions \n", [ic_util:to_colon([OpName|N])]),
- ic_codegen:emit(Fd, " */\n\n"),
-
- ic_codegen:emit(Fd, "~s ~s(~s)\n",[RT, OpName, PL]),
- ic_codegen:emit(Fd, " throws java.lang.Exception;\n\n\n"),
-
- emit_interface_prototypes(G, N, Xs, Fd);
-emit_interface_prototypes(G, N, [X |Xs], Fd) when is_record(X, attr) ->
- ic_attribute_java:emit_attribute_prototype(G, N, X, Fd),
- emit_interface_prototypes(G, N, Xs, Fd);
-emit_interface_prototypes(G, N, [_X|Xs], Fd) ->
- emit_interface_prototypes(G, N, Xs, Fd);
-emit_interface_prototypes(_G, _N, [], _Fd) -> ok.
-
-
-
-
-%%%-----------------------------------------------------
-%%%
-%%% Holder file generation
-%%%
-%%%-----------------------------------------------------
-
-emit_holder(_G, N, X, Fd) ->
- InterfaceName = ic_forms:get_java_id(X),
- FullInterfaceName = ic_util:to_dot([InterfaceName|N]),
-
- ic_codegen:emit(Fd, "public final class ~sHolder {\n\n",[InterfaceName]),
-
- ic_codegen:emit(Fd, " // Instance variable\n"),
- ic_codegen:emit(Fd, " public ~s value;\n\n",[FullInterfaceName]),
-
- ic_codegen:emit(Fd, " // Constructors\n"),
- ic_codegen:emit(Fd, " public ~sHolder() {\n",[InterfaceName]),
- ic_codegen:emit(Fd, " this(null);\n"),
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_codegen:emit(Fd, " public ~sHolder(~s _arg) {\n",[InterfaceName, FullInterfaceName]),
- ic_codegen:emit(Fd, " value = _arg;\n"),
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_codegen:emit(Fd, " public void _marshal() {\n"),
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_codegen:emit(Fd, " public void _unmarshal() {\n"),
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_codegen:emit(Fd, "}\n\n").
-
-
-
-
-%%%-----------------------------------------------------
-%%%
-%%% Helper file generation
-%%%
-%%%-----------------------------------------------------
-emit_helper(G, N, X, Fd) ->
- InterfaceName = ic_forms:get_java_id(X),
- FullInterfaceName = ic_util:to_dot([InterfaceName|N]),
-
- ic_codegen:emit(Fd, "public final class ~sHelper {\n\n",[InterfaceName]),
-
- ic_codegen:emit(Fd, " // Constructor\n"),
- ic_codegen:emit(Fd, " public ~sHelper() {\n",[InterfaceName]),
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_codegen:emit(Fd, " public static void _marshal() {\n"),
- ic_codegen:emit(Fd, " // Writing the object to the message\n"),
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_codegen:emit(Fd, " public static ~s _unmarshal() {\n",[FullInterfaceName]),
- ic_codegen:emit(Fd, " // Reading the object from the message\n"),
- ic_codegen:emit(Fd, " return null;\n"),
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_codegen:emit(Fd, " public static java.lang.String id() {\n"),
- ic_codegen:emit(Fd, " return ~p;\n",[ictk:get_IR_ID(G, N, X)]),
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_codegen:emit(Fd, "}\n\n").
-
-
-
-
-%%%-----------------------------------------------------
-%%%
-%%% Stub file generation
-%%%
-%%%-----------------------------------------------------
-
-emit_stub(G, N, X, Fd) ->
- InterfaceName = ic_forms:get_java_id(X), %% Java Interface Name
- IFCName = ic_forms:get_id2(X), %% Internal Interface Name
-
- FullInterfaceName = ic_util:to_dot([InterfaceName|N]),
- Body = ic_forms:get_body(X),
-
- ic_codegen:emit(Fd, "public class _~sStub implements ~s {\n\n",
- [InterfaceName,FullInterfaceName]),
-
- ic_codegen:emit(Fd, " // Client data\n"),
- ic_codegen:emit(Fd, " public ~sEnvironment _env;\n\n",[?ICPACKAGE]),
-
- ic_codegen:emit(Fd, " // Constructors\n"),
- ic_codegen:emit(Fd, " public _~sStub(~sOtpSelf _self,\n",[InterfaceName,?ERLANGPACKAGE]),
- ic_codegen:emit(Fd, " ~sOtpPeer _peer,\n",[?ERLANGPACKAGE]),
- ic_codegen:emit(Fd, " java.lang.Object _server) throws java.lang.Exception {\n\n"),
-
- ic_codegen:emit(Fd, " _env =\n"),
- ic_codegen:emit(Fd, " new ~sEnvironment(_self, _peer, _server);\n",[?ICPACKAGE]),
- ic_codegen:emit(Fd, " _env.connect();\n"),
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_codegen:emit(Fd, " public _~sStub(java.lang.String _selfN,\n",[InterfaceName]),
- ic_codegen:emit(Fd, " java.lang.String _peerN,\n"),
- ic_codegen:emit(Fd, " java.lang.String _cookie,\n"),
- ic_codegen:emit(Fd, " java.lang.Object _server) throws java.lang.Exception {\n\n"),
- ic_codegen:emit(Fd, " _env =\n"),
- ic_codegen:emit(Fd, " new ~sEnvironment(_selfN, _peerN, _cookie, _server);\n",[?ICPACKAGE]),
- ic_codegen:emit(Fd, " _env.connect();\n"),
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_codegen:emit(Fd, " public _~sStub(~sOtpConnection _connection,\n",[InterfaceName, ?ERLANGPACKAGE]),
- ic_codegen:emit(Fd, " java.lang.Object _server) throws java.lang.Exception {\n\n"),
- ic_codegen:emit(Fd, " _env =\n"),
- ic_codegen:emit(Fd, " new ~sEnvironment(_connection, _server);\n",[?ICPACKAGE]),
- ic_codegen:emit(Fd, " _env.connect();\n"),
- ic_codegen:emit(Fd, " }\n\n"),
-
- emit_message_reference_extraction(Fd),
-
- emit_servers_object_access(Fd),
-
- emit_client_connection_close(Fd),
-
- emit_client_connection_reconnect(Fd),
-
- emit_client_destroy(Fd),
-
- lists:foreach(fun({_Name, Body1}) ->
- emit_op_implementation(G, [IFCName|N], Body1, Fd) end,
- [{x, Body} | X#interface.inherit_body]),
-
- ic_codegen:emit(Fd, "}\n\n").
-
-
-emit_op_implementation(G, N, [X |Xs], Fd) when is_record(X, op) ->
-
- WireOpName = ic_forms:get_id2(X),
- OpName = ic_forms:get_java_id(WireOpName),
- {_, ArgNames, TypeList} = extract_info(G, N, X),
- {R, ParamTypes, _} = TypeList,
-
- RT = ic_java_type:getParamType(G,N,R,ret),
- PL = ic_util:mk_list(gen_par_list(G, N, X, ParamTypes, ArgNames)),
- CMCPL = ic_util:mk_list(gen_client_marshal_call_par_list(ArgNames)),
-
- ic_codegen:emit(Fd, " // Operation ~p implementation\n", [ic_util:to_colon([WireOpName|N])]),
- ic_codegen:emit(Fd, " public ~s ~s(~s)\n", [RT, OpName, PL]),
- ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"),
-
- %% Function marshal call
- ic_codegen:emit(Fd, " // Calling the marshal function\n"),
-
- case CMCPL of
- "" ->
- ic_codegen:emit(Fd, " _~s_marshal(_env);\n\n",[OpName]);
- _ ->
- ic_codegen:emit(Fd, " _~s_marshal(_env, ~s);\n\n",[OpName, CMCPL])
- end,
-
- %% Sending call
- ic_codegen:emit(Fd, " // Message send\n"),
- ic_codegen:emit(Fd, " _env.send();\n\n"),
-
- case ic_forms:is_oneway(X) of
- true ->
- ok;
- false ->
- %% Receiving return values
- ic_codegen:emit(Fd, " // Message receive\n"),
- ic_codegen:emit(Fd, " _env.receive();\n\n"),
-
- %% Function unmarshal call
- case RT of
- "void" ->
- case ic_util:mk_list(gen_client_unmarshal_call_par_list(ArgNames)) of
- "" ->
- ic_codegen:emit(Fd, " // Calling the unmarshal function\n"),
- ic_codegen:emit(Fd, " _~s_unmarshal(_env);\n",
- [OpName]);
- UMCPL ->
- ic_codegen:emit(Fd, " // Calling the unmarshal function\n"),
- ic_codegen:emit(Fd, " _~s_unmarshal(_env, ~s);\n",
- [OpName,UMCPL])
- end;
- _ ->
- ic_codegen:emit(Fd, " // Calling the unmarshal function\n"),
- case ic_util:mk_list(gen_client_unmarshal_call_par_list(ArgNames)) of
- "" ->
- ic_codegen:emit(Fd, " return _~s_unmarshal(_env);\n",
- [OpName]);
- UMCPL ->
- ic_codegen:emit(Fd, " return _~s_unmarshal(_env, ~s);\n",
- [OpName,UMCPL])
- end
- end
- end,
- ic_codegen:emit(Fd, " }\n\n"),
-
- %% Marshalling
- emit_op_marshal(G, N, X, Fd),
-
- %% UnMarshalling
- emit_op_unmarshal(G, N, X, Fd),
- ic_codegen:emit(Fd, "\n"),
-
- emit_op_implementation(G, N, Xs, Fd);
-emit_op_implementation(G, N, [X |Xs], Fd) when is_record(X, attr) ->
- ic_attribute_java:emit_attribute_stub_code(G, N, X, Fd),
- emit_op_implementation(G, N, Xs, Fd);
-emit_op_implementation(G, N, [_X|Xs], Fd) ->
- emit_op_implementation(G, N, Xs, Fd);
-emit_op_implementation(_G, _N, [], _Fd) -> ok.
-
-
-
-
-
-%%---------------------------------------
-%%
-%% Marshal operation generation
-%%
-%%---------------------------------------
-
-emit_op_marshal(G, N, X, Fd) ->
- WireOpName = ic_forms:get_id2(X),
- OpName = ic_forms:get_java_id(WireOpName),
- {_, ArgNames, TypeList} = extract_info(G, N, X),
- {_R, ParamTypes, _} = TypeList,
-
- PL = ic_util:mk_list(gen_marshal_par_list(G, N, X, ParamTypes, ArgNames)),
-
- ic_codegen:emit(Fd, " // Marshal operation for ~p\n", [OpName]),
- case PL of
- "" ->
- ic_codegen:emit(Fd, " public static void _~s_marshal(~sEnvironment __env)\n",
- [OpName, ?ICPACKAGE]),
- ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n");
- _ ->
- ic_codegen:emit(Fd, " public static void _~s_marshal(~sEnvironment __env, ~s)\n",
- [OpName, ?ICPACKAGE, PL]),
- ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n")
- end,
- %% Message encoding
- emit_op_encode(G, N, X, OpName, WireOpName, ParamTypes, ArgNames, Fd),
-
- ic_codegen:emit(Fd, " }\n\n").
-
-
-emit_op_encode(G, N, X, _OpN, WOpN, ParamTypes, ArgNames, Fd) ->
-
- OpCallName = case ic_options:get_opt(G, scoped_op_calls) of
- true ->
- ic_util:to_undersc([WOpN|N]);
- false ->
- WOpN
- end,
-
- SendParamNr = count_client_send(ArgNames),
-
- ic_codegen:emit(Fd, " ~sOtpOutputStream __os = __env.getOs();\n\n",
- [?ERLANGPACKAGE]),
-
- case ic_forms:is_oneway(X) of
- true ->
- %% Initiating call tuple
- ic_codegen:emit(Fd, " // Message header assembly\n"),
- ic_codegen:emit(Fd, " __os.reset();\n"),
- ic_codegen:emit(Fd, " __os.write_tuple_head(2);\n"),
- ic_codegen:emit(Fd, " __os.write_atom(\"$gen_cast\");\n\n");
- false ->
- %% Initiating call tuple
- ic_codegen:emit(Fd, " // Message header assembly\n"),
- ic_codegen:emit(Fd, " __os.reset();\n"),
- ic_codegen:emit(Fd, " __os.write_tuple_head(3);\n"),
- ic_codegen:emit(Fd, " __os.write_atom(\"$gen_call\");\n\n"),
-
- %% Initiating call identity tuple
- ic_codegen:emit(Fd, " // Message identity part creation\n"),
- ic_codegen:emit(Fd, " __os.write_tuple_head(2);\n"),
- ic_codegen:emit(Fd, " __env.write_client_pid();\n"),
- ic_codegen:emit(Fd, " __env.write_client_ref();\n\n")
- end,
-
- %% Operation part initializations
- case SendParamNr > 0 of
- true ->
- ic_codegen:emit(Fd, " // Operation attribute creation\n"),
- ic_codegen:emit(Fd, " __os.write_tuple_head(~p);\n", [SendParamNr+1]),
- ic_codegen:emit(Fd, " __os.write_atom(~p);\n", [OpCallName]),
- emit_op_encode_loop(G, N, X, ParamTypes, ArgNames, 1, Fd);
- false -> %% No in/inout paramaters
- ic_codegen:emit(Fd, " __os.write_atom(~p);\n", [OpCallName])
- end.
-
-
-
-emit_op_encode_loop(_,_,_,_,[],_,_Fd) ->
- ok;
-emit_op_encode_loop(G, N, X, [_Type|Types],[{out, _Arg}|Args], Counter, Fd) ->
- emit_op_encode_loop(G, N, X, Types, Args, Counter, Fd);
-emit_op_encode_loop(G, N, X, [Type|Types], [{inout, Arg}|Args], Counter, Fd) ->
- case ic_java_type:isBasicType(G, N, Type) of
- true ->
- ic_codegen:emit(Fd, " __os~s(~s.value);\n",
- [ic_java_type:marshalFun(G, N, X, Type),Arg]);
- false ->
- ic_codegen:emit(Fd, " ~s(__os, ~s.value);\n",
- [ic_java_type:marshalFun(G, N, X, Type),Arg])
- end,
- emit_op_encode_loop(G, N, X, Types, Args, Counter+1, Fd);
-emit_op_encode_loop(G, N, X, [Type|Types], [{in, Arg}|Args], Counter, Fd) ->
- case ic_java_type:isBasicType(G, N, Type) of
- true ->
- ic_codegen:emit(Fd, " __os~s(~s);\n",
- [ic_java_type:marshalFun(G, N, X, Type),Arg]);
- false ->
- ic_codegen:emit(Fd, " ~s(__os, ~s);\n",
- [ic_java_type:marshalFun(G, N, X, Type),Arg])
- end,
- emit_op_encode_loop(G, N, X, Types, Args, Counter+1, Fd).
-
-
-
-
-
-
-%%-------------------------------------
-%%
-%% UnMarshal operation generation
-%%
-%%-------------------------------------
-
-emit_op_unmarshal(G, N, X, Fd) ->
- case ic_forms:is_oneway(X) of
- true ->
- ok;
- false ->
- OpName = ic_forms:get_java_id(X),
- {_, ArgNames, TypeList} = extract_info(G, N, X),
- {R, ParamTypes, _} = TypeList,
-
- RT = ic_java_type:getParamType(G,N,R,ret),
- PL = ic_util:mk_list(gen_unmarshal_par_list(G, N, X, ParamTypes, ArgNames)),
-
- case PL of
- "" ->
- case RT of
- "void" ->
- ic_codegen:emit(Fd, " // Unmarshal operation for ~p\n", [OpName]),
- ic_codegen:emit(Fd, " public static void _~s_unmarshal(~sEnvironment __env)\n",
- [OpName, ?ICPACKAGE]),
- ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"),
- ic_codegen:emit(Fd, " __env.getIs().read_atom();\n"),
- ic_codegen:emit(Fd, " }\n\n");
- _ ->
- ic_codegen:emit(Fd, " // Unmarshal operation for ~p\n", [OpName]),
- ic_codegen:emit(Fd, " public static ~s _~s_unmarshal(~sEnvironment __env)\n",
- [RT, OpName, ?ICPACKAGE]),
- ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"),
-
- ic_codegen:emit(Fd, " // Get input stream\n"),
- ic_codegen:emit(Fd, " ~sOtpInputStream __is = __env.getIs();\n\n",
- [?ERLANGPACKAGE]),
-
- emit_op_decode(G, N, X, R, RT, ParamTypes, ArgNames, Fd),
- ic_codegen:emit(Fd, " }\n\n")
- end;
- _ ->
- ic_codegen:emit(Fd, " // Unmarshal operation for ~p\n", [OpName]),
- ic_codegen:emit(Fd, " public static ~s _~s_unmarshal(~sEnvironment __env, ~s)\n",
- [RT, OpName, ?ICPACKAGE, PL]),
- ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"),
-
- ic_codegen:emit(Fd, " // Get input stream\n"),
- ic_codegen:emit(Fd, " ~sOtpInputStream __is = __env.getIs();\n\n",
- [?ERLANGPACKAGE]),
-
- emit_op_decode(G, N, X, R, RT, ParamTypes, ArgNames, Fd),
- ic_codegen:emit(Fd, " }\n\n")
- end
- end.
-
-
-emit_op_decode(G, N, X, R, RT, ParamTypes, ArgNames, Fd) ->
- ReceiveNr = count_client_receive(ArgNames),
-
- case RT of
- "void" ->
- case ReceiveNr > 0 of
- true ->
- ic_codegen:emit(Fd, " // Extracting output values\n"),
- ic_codegen:emit(Fd, " __is.read_tuple_head();\n"),
- ic_codegen:emit(Fd, " __is.read_atom();\n"),
- emit_op_decode_loop(G, N, X, ParamTypes, ArgNames, 1, Fd);
- false ->
- ic_codegen:emit(Fd, " __is.read_atom();\n")
- end;
- _ ->
- case ReceiveNr > 0 of
- true ->
- ic_codegen:emit(Fd, " // Extracting return/output values\n"),
- ic_codegen:emit(Fd, " __is.read_tuple_head();\n"),
- case ic_java_type:isBasicType(G,N,R) of
- true ->
- ic_codegen:emit(Fd, " ~s _result = __is~s;\n",
- [RT,ic_java_type:unMarshalFun(G, N, X, R)]);
- false ->
- ic_codegen:emit(Fd, " ~s _result = ~s.unmarshal(__is);\n",
- [RT, ic_java_type:getUnmarshalType(G,N,X,R)])
- end,
- emit_op_decode_loop(G, N, X, ParamTypes, ArgNames, 1, Fd),
-
- ic_codegen:nl(Fd),
- ic_codegen:emit(Fd, " return _result;\n");
- false ->
- ic_codegen:emit(Fd, " // Extracting return value\n"),
- case ic_java_type:isBasicType(G,N,R) of
- true ->
- ic_codegen:emit(Fd, " return __is~s;\n",
- [ic_java_type:unMarshalFun(G, N, X, R)]);
- false ->
- ic_codegen:emit(Fd, " return ~s.unmarshal(__is);\n",
- [ic_java_type:getUnmarshalType(G,N,X,R)])
- end
- end
- end.
-
-emit_op_decode_loop(_,_,_,_,[],_,_Fd) ->
- ok;
-emit_op_decode_loop(G, N, X, [_Type|Types], [{in, _Arg}|Args], Counter, Fd) ->
- emit_op_decode_loop(G, N, X, Types, Args, Counter, Fd);
-emit_op_decode_loop(G, N, X, [Type|Types], [{_, Arg}|Args], Counter, Fd) ->
- case ic_java_type:isBasicType(G,N,Type) of
- true ->
- ic_codegen:emit(Fd, " ~s.value = __is~s;\n",
- [Arg,
- ic_java_type:unMarshalFun(G, N, X, Type)]);
- false ->
- ic_codegen:emit(Fd, " ~s.value = ~s.unmarshal(__is);\n",
- [Arg,
- ic_java_type:getUnmarshalType(G, N, X, Type)])
- end,
- emit_op_decode_loop(G, N, X, Types, Args, Counter+1, Fd).
-
-
-
-emit_message_reference_extraction(Fd) ->
- ic_codegen:emit(Fd, " // Returns call reference\n"),
- ic_codegen:emit(Fd, " public ~sOtpErlangRef __getRef()\n",
- [?ERLANGPACKAGE]),
- ic_codegen:emit(Fd, " throws java.lang.Exception {\n"),
- ic_codegen:emit(Fd, " return _env.received_ref();\n"),
- ic_codegen:emit(Fd, " }\n\n").
-
-emit_servers_object_access(Fd) ->
- ic_codegen:emit(Fd, " // Returns the server\n"),
- ic_codegen:emit(Fd, " public java.lang.Object __server() {\n"),
- ic_codegen:emit(Fd, " return _env.server();\n"),
- ic_codegen:emit(Fd, " }\n\n").
-
-emit_client_connection_close(Fd) ->
- ic_codegen:emit(Fd, " // Closes connection\n"),
- ic_codegen:emit(Fd, " public void __disconnect() {\n"),
- ic_codegen:emit(Fd, " _env.disconnect();\n"),
- ic_codegen:emit(Fd, " }\n\n").
-
-emit_client_connection_reconnect(Fd) ->
- ic_codegen:emit(Fd, " // Reconnects client\n"),
- ic_codegen:emit(Fd, " public void __reconnect()\n"),
- ic_codegen:emit(Fd, " throws java.lang.Exception {\n"),
- ic_codegen:emit(Fd, " _env.reconnect();\n"),
- ic_codegen:emit(Fd, " }\n\n").
-
-emit_client_destroy(Fd) ->
- ic_codegen:emit(Fd, " // Destroy server\n"),
- ic_codegen:emit(Fd, " public void __stop()\n"),
- ic_codegen:emit(Fd, " throws java.lang.Exception {\n"),
- ic_codegen:emit(Fd, " _env.client_stop_server();\n"),
- ic_codegen:emit(Fd, " }\n\n").
-
-
-
-%%%----------------------------------------------------
-%%%
-%%% Generates the server code
-%%%
-%%%----------------------------------------------------
-
-emit_skel(G, N, X, Fd) ->
- InterfaceName = ic_forms:get_java_id(X),
- FullInterfaceName = ic_util:to_dot([InterfaceName|N]),
-
- ic_codegen:emit(Fd, "public abstract class _~sImplBase implements ~s {\n\n",
- [InterfaceName,FullInterfaceName]),
-
- ic_codegen:emit(Fd, " // Server data\n"),
- ic_codegen:emit(Fd, " protected ~sEnvironment _env = null;\n\n",[?ICPACKAGE]),
-
- ic_codegen:emit(Fd, " // Constructors\n"),
- ic_codegen:emit(Fd, " public _~sImplBase() {\n",[InterfaceName]),
- ic_codegen:emit(Fd, " }\n\n"),
-
- emit_caller_pid(G, N, X, Fd),
-
- %% Emit operation dictionary
- emit_dictionary(G, N, X, Fd),
-
- %% Emit server switch
- emit_server_switch(G, N, X, Fd),
-
- ic_codegen:emit(Fd, "}\n").
-
-
-emit_server_switch(G, N, X, Fd) ->
-
- IFCName = ic_forms:get_id2(X), %% Internal Interface Name
- Body = ic_forms:get_body(X),
- Counter = 0,
-
- ic_codegen:emit(Fd, " // Operation invokation\n"),
- ic_codegen:emit(Fd, " public ~sOtpOutputStream invoke(~sOtpInputStream _in)\n",
- [?ERLANGPACKAGE,?ERLANGPACKAGE]),
- ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"),
-
- ic_codegen:emit(Fd, " // Create a new environment if needed\n"),
- ic_codegen:emit(Fd, " if (_env == null)\n"),
- ic_codegen:emit(Fd, " _env = new com.ericsson.otp.ic.Environment();\n\n"),
-
- ic_codegen:emit(Fd, " // Unmarshal head\n"),
- ic_codegen:emit(Fd, " _env.uHead(_in);\n\n"),
-
- ic_codegen:emit(Fd, " // Switch over operation\n"),
- ic_codegen:emit(Fd, " return __switch(_env);\n"),
-
- ic_codegen:emit(Fd, " }\n\n"),
-
-
- ic_codegen:emit(Fd, " // Operation switch\n"),
- ic_codegen:emit(Fd, " public ~sOtpOutputStream __switch(~sEnvironment __env)\n", [?ERLANGPACKAGE,?ICPACKAGE]),
- ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"),
-
- ic_codegen:emit(Fd, " // Setup streams and operation label\n"),
- ic_codegen:emit(Fd, " ~sOtpOutputStream __os = __env.getOs();\n",[?ERLANGPACKAGE]),
- ic_codegen:emit(Fd, " __os.reset();\n"),
- ic_codegen:emit(Fd, " int __label = __env.uLabel(__operations);\n\n"),
-
- ic_codegen:emit(Fd, " // Switch over operation\n"),
- ic_codegen:emit(Fd, " switch(__label) {\n\n"),
-
- OpNr = emit_server_op_switch_loop(G,
- [IFCName|N],
- [{x, Body} | X#interface.inherit_body],
- Counter,
- Fd),
-
- ic_codegen:emit(Fd, " case ~p: { // Standard stop operation\n\n",[OpNr]),
- ic_codegen:emit(Fd, " __env.server_stop_server();\n\n"),
- ic_codegen:emit(Fd, " } break;\n\n"),
-
- ic_codegen:emit(Fd, " default: // It will never come down here \n"),
- ic_codegen:emit(Fd, " throw new java.lang.Exception(\"BAD OPERATION\");\n\n", []),
-
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_codegen:emit(Fd, " if(__os.count() > 0)\n"),
- ic_codegen:emit(Fd, " return __os;\n\n"),
-
- ic_codegen:emit(Fd, " return null;\n"),
- ic_codegen:emit(Fd, " }\n\n").
-
-
-
-emit_server_op_switch_loop(_G, _N, [], C, _Fd) ->
- C;
-emit_server_op_switch_loop(G, N, [{_,X}|Xs], C, Fd) ->
- C1 = emit_server_op_switch(G, N, X, C, Fd),
- emit_server_op_switch_loop(G, N, Xs, C1, Fd).
-
-
-emit_server_op_switch(G, N, [X|Xs], C, Fd) when is_record(X, op) ->
-
- OpName = ic_forms:get_java_id(X),
-
- ic_codegen:emit(Fd, " case ~p: { // Operation ~s\n\n",[C,ic_util:to_dot([OpName|N])]),
-
- emit_invoke(G, N, X, Fd),
-
- ic_codegen:emit(Fd, " } break;\n\n"),
-
- emit_server_op_switch(G, N, Xs, C+1, Fd);
-emit_server_op_switch(G, N, [X |Xs], C, Fd) when is_record(X, attr) ->
- C1 = ic_attribute_java:emit_attribute_switch_case(G,N,X,Fd,C),
- emit_server_op_switch(G, N, Xs, C1, Fd);
-emit_server_op_switch(G, N, [_X|Xs], C, Fd) ->
- emit_server_op_switch(G, N, Xs, C, Fd);
-emit_server_op_switch(_G, _N, [], C, _Fd) ->
- C.
-
-
-emit_caller_pid(_G, _N, _X, Fd) ->
- ic_codegen:emit(Fd, " // Extracts caller identity\n"),
- ic_codegen:emit(Fd, " public ~sOtpErlangPid __getCallerPid() {\n", [?ERLANGPACKAGE]),
- ic_codegen:emit(Fd, " return _env.getScaller();\n"),
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_codegen:emit(Fd, " public ~sOtpErlangPid __getCallerPid(~sEnvironment __env) {\n",
- [?ERLANGPACKAGE, ?ICPACKAGE]),
- ic_codegen:emit(Fd, " return __env.getScaller();\n"),
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_codegen:emit(Fd, " public boolean __isStopped() {\n"),
- ic_codegen:emit(Fd, " return _env.isStopped();\n"),
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_codegen:emit(Fd, " public boolean __isStopped(~sEnvironment __env) {\n",
- [?ICPACKAGE]),
- ic_codegen:emit(Fd, " return __env.isStopped();\n"),
- ic_codegen:emit(Fd, " }\n\n").
-
-
-
-%% Creates an operation dictionary
-emit_dictionary(G, N, X, Fd) ->
-
- Counter = 0,
- Body = ic_forms:get_body(X),
-
- ic_codegen:emit(Fd, " // Operation dictionary\n"),
- ic_codegen:emit(Fd, " private static java.util.Dictionary __operations = new java.util.Hashtable();\n"),
- ic_codegen:emit(Fd, " static {\n"),
-
- emit_dictionary_loop(G,
- [ic_forms:get_id2(X)|N],
- [{x, Body} | X#interface.inherit_body],
- Counter,
- Fd),
-
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_codegen:emit(Fd, " // Operation dictionary access\n"),
- ic_codegen:emit(Fd, " public static java.util.Dictionary __operations() {\n"),
- ic_codegen:emit(Fd, " return __operations;\n"),
- ic_codegen:emit(Fd, " }\n\n").
-
-
-
-
-emit_dictionary_loop(_G, _N, [], C, Fd) ->
- ic_codegen:emit(Fd, " __operations.put(~p, new java.lang.Integer(~p));\n",
- ["stop",C]);
-emit_dictionary_loop(G, N, [{_,X}|Xs], C, Fd) ->
- C1 = emit_dictionary(G, N, X, C, Fd),
- emit_dictionary_loop(G, N, Xs, C1, Fd).
-
-
-emit_dictionary(G, N, [X|Xs], C, Fd) when is_record(X, op) ->
-
- OpName = case ic_options:get_opt(G, scoped_op_calls) of
- true ->
- ic_util:to_undersc([ic_forms:get_id2(X)|N]);
- false ->
- ic_forms:get_id2(X)
- end,
-
- ic_codegen:emit(Fd, " __operations.put(~p, new java.lang.Integer(~p));\n",
- [OpName,C]),
- emit_dictionary(G, N, Xs, C+1, Fd);
-
-emit_dictionary(G, N, [X |Xs], C, Fd) when is_record(X, attr) ->
- C1 = ic_attribute_java:emit_atrribute_on_dictionary(G, N, X, Fd, C),
- emit_dictionary(G, N, Xs, C1, Fd);
-
-emit_dictionary(G, N, [_X|Xs], C, Fd) ->
- emit_dictionary(G, N, Xs, C, Fd);
-
-emit_dictionary(_G, _N, [], C, _Fd) ->
- C.
-
-
-
-emit_invoke(G, N, X, Fd) ->
-
- {_, ArgNames, TypeList} = extract_info(G, N, X),
- {R, ParamTypes, _} = TypeList,
- OpName = ic_forms:get_java_id(X),
- RT = ic_java_type:getParamType(G,N,R,ret),
- PL = ic_util:mk_list(gen_cb_arg_list(ArgNames)),
- OutParamNr = count_server_send(ArgNames),
-
- case count_server_receive(ArgNames) of
- 0 ->
- ok;
- _C ->
- ic_codegen:emit(Fd, " // Preparing input\n"),
- ic_codegen:emit(Fd, " ~sOtpInputStream __is = __env.getIs();\n",
- [?ERLANGPACKAGE]),
- emit_server_unmarshal_loop(G, N, X, ParamTypes, ArgNames, 1, Fd)
- end,
-
- ic_codegen:emit(Fd, " // Calling implementation function\n"),
- case RT of
- "void" ->
- ic_codegen:emit(Fd, " this.~s(~s);\n\n",
- [OpName,PL]);
- _ ->
- ic_codegen:emit(Fd, " ~s _result = this.~s(~s);\n\n",
- [RT, OpName, PL])
- end,
-
- case ic_forms:is_oneway(X) of
- true ->
- ok;
- false ->
- ic_codegen:emit(Fd, " // Marshaling output\n"),
- ic_codegen:emit(Fd, " ~sOtpErlangRef __ref = __env.getSref();\n",[?ERLANGPACKAGE]),
-
- case RT of
- "void" ->
- case OutParamNr > 0 of
- true ->
- ic_codegen:emit(Fd, " __os.write_tuple_head(2);\n"),
- ic_codegen:emit(Fd, " __os.write_ref(__ref.node(),__ref.ids(),__ref.creation()); // Call reference\n"),
- ic_codegen:emit(Fd, " __os.write_tuple_head(~p);\n",[OutParamNr+1]),
- ic_codegen:emit(Fd, " __os.write_atom(\"ok\");\n"),
- emit_server_marshal_loop(G, N, X, ParamTypes,ArgNames,1,Fd);
- false ->
- ic_codegen:emit(Fd, " __os.write_tuple_head(2);\n"),
- ic_codegen:emit(Fd, " __os.write_ref(__ref.node(),__ref.ids(),__ref.creation()); // Call reference\n"),
- ic_codegen:emit(Fd, " __os.write_atom(\"ok\");\n\n")
- end;
- _ ->
- case OutParamNr > 0 of
- true ->
- ic_codegen:emit(Fd, " __os.write_tuple_head(2);\n"),
- ic_codegen:emit(Fd, " __os.write_ref(__ref.node(),__ref.ids(),__ref.creation()); // Call reference\n"),
- ic_codegen:emit(Fd, " __os.write_tuple_head(~p);\n",[OutParamNr+1]),
-
- case ic_java_type:isBasicType(G,N,R) of
- true ->
- ic_codegen:emit(Fd, " __os~s(_result); // Return value\n",
- [ic_java_type:marshalFun(G,N,X,R)]);
- false ->
- ic_codegen:emit(Fd, " ~s(__os,_result); // Return value\n",
- [ic_java_type:marshalFun(G,N,X,R)])
- end,
- emit_server_marshal_loop(G, N, X, ParamTypes,ArgNames,1,Fd);
- false ->
- ic_codegen:emit(Fd, " __os.write_tuple_head(2);\n"),
- ic_codegen:emit(Fd, " __os.write_ref(__ref.node(),__ref.ids(),__ref.creation()); // Call reference\n"),
-
- case ic_java_type:isBasicType(G,N,R) of
- true ->
- ic_codegen:emit(Fd, " __os~s(_result); // Return value\n\n",
- [ic_java_type:marshalFun(G,N,X,R)]);
- false ->
- ic_codegen:emit(Fd, " ~s(__os,_result); // Return value\n\n",
- [ic_java_type:marshalFun(G,N,X,R)])
- end
- end
- end,
- ic_codegen:nl(Fd)
- end.
-
-
-emit_server_unmarshal_loop(_,_,_,_,[],_,Fd) ->
- ic_codegen:nl(Fd);
-emit_server_unmarshal_loop(G, N, X, [Type|Types], [{in, Arg}|Args], Counter, Fd) ->
- case ic_java_type:isBasicType(G,N,Type) of
- true ->
- ic_codegen:emit(Fd, " ~s ~s = __is~s; // In value\n",
- [ic_java_type:getType(G,N,Type),
- Arg,
- ic_java_type:unMarshalFun(G,N,X,Type)]);
- false ->
- ic_codegen:emit(Fd, " ~s ~s = ~s.unmarshal(__is); // In value\n",
- [ic_java_type:getType(G,N,Type),
- Arg,
- ic_java_type:getUnmarshalType(G,N,X,Type)])
- end,
- emit_server_unmarshal_loop(G, N, X, Types, Args, Counter+1, Fd);
-emit_server_unmarshal_loop(G, N, X, [Type|Types],[{inout, Arg}|Args], Counter, Fd) ->
- Holder = ic_java_type:getHolderType(G,N,Type),
- case ic_java_type:isBasicType(G,N,Type) of
- true ->
-% OtpEncVar = ic_java_type:getUnmarshalType(G,N,X,Type),
- ic_codegen:emit(Fd, " ~s _~s = __is~s;\n",
- [ic_java_type:getType(G,N,Type),
- Arg,
- ic_java_type:unMarshalFun(G,N,X,Type)]),
- ic_codegen:emit(Fd, " ~s ~s = new ~s(_~s); // InOut value\n",
- [Holder,
- Arg,
- Holder,
- Arg]);
- false ->
- ic_codegen:emit(Fd, " ~s ~s = new ~s(); // InOut value\n",
- [Holder,
- Arg,
- Holder]),
- ic_codegen:emit(Fd, " ~s._unmarshal(__is);\n",
- [Arg])
- end,
- emit_server_unmarshal_loop(G, N, X, Types, Args, Counter+1, Fd);
-emit_server_unmarshal_loop(G, N, X, [Type|Types],[{out, Arg}|Args], Counter, Fd) ->
- Holder = ic_java_type:getHolderType(G,N,Type),
- ic_codegen:emit(Fd, " ~s ~s = new ~s(); // Out value\n", [Holder, Arg, Holder]),
- emit_server_unmarshal_loop(G, N, X, Types, Args, Counter, Fd).
-
-
-emit_server_marshal_loop(_,_,_,_,[],_,_Fd) ->
- ok;
-emit_server_marshal_loop(G, N, X, [_Type|Types],[{in, _Arg}|Args], Counter, Fd) ->
- emit_server_marshal_loop(G, N, X, Types, Args, Counter, Fd);
-emit_server_marshal_loop(G, N, X, [Type|Types],[{_, Arg}|Args], Counter, Fd) ->
-% Holder = ic_java_type:getHolderType(G,N,Type),
- case ic_java_type:isBasicType(G,N,Type) of
- true ->
- ic_codegen:emit(Fd, " __os~s(~s.value); // Out/InOut value\n",
- [ic_java_type:marshalFun(G,N,X,Type),Arg]);
- false ->
- ic_codegen:emit(Fd, " ~s._marshal(__os); // Out/InOut value\n",
- [Arg])
- end,
- emit_server_marshal_loop(G, N, X, Types, Args, Counter+1, Fd).
-
-
-
-
-
-%%%----------------------------------------------------
-%%%
-%%% Utilities
-%%%
-%%%----------------------------------------------------
-
-extract_info(_G, N, X) when is_record(X, op) ->
- Name = ic_util:to_undersc([ic_forms:get_id2(X) | N]),
- Args = X#op.params,
- ArgNames = mk_c_vars(Args),
- TypeList = {ic_forms:get_type(X),
- lists:map(fun(Y) -> ic_forms:get_type(Y) end, Args),
- []
- },
- {Name, ArgNames, TypeList};
-extract_info(_G, N, X) ->
- Name = ic_util:to_undersc([ic_forms:get_id2(X) | N]),
- {Name, [], []}.
-
-%% Input is a list of parameters (in parse form) and output is a list
-%% of parameter attribute and variable names.
-mk_c_vars(Params) ->
- lists:map(fun(P) -> {A, _} = P#param.inout,
- {A, ic_forms:get_id(P#param.id)}
- end,
- Params).
-
-%%
-handle_preproc(G, _N, line_nr, X) ->
- Id = ic_forms:get_java_id(X),
- Flags = X#preproc.aux,
- case Flags of
- [] -> ic_genobj:push_file(G, Id);
- _ ->
- lists:foldr(fun({_, _, "1"}, Gprim) -> ic_genobj:push_file(Gprim, Id);
- ({_, _, "2"}, Gprim) -> ic_genobj:pop_file(Gprim, Id);
- ({_, _, "3"}, Gprim) -> ic_genobj:sys_file(Gprim, Id) end,
- G, Flags)
- end;
-handle_preproc(G, _N, _Other, _X) ->
- G.
-
-
-%%
-gen_par_list(_, _, _, [], []) ->
- [];
-gen_par_list(G, N, X, [Type |Types], [{Attr, Arg}|Args]) ->
- JType = ic_java_type:getParamType(G, N, Type, Attr),
- [JType ++ " " ++ Arg |
- gen_par_list(G, N, X, Types, Args)].
-
-
-gen_marshal_par_list(_, _, _, [], []) ->
- [];
-gen_marshal_par_list(G, N, X, [_Type |Types], [{out, _Arg}|Args]) ->
- gen_marshal_par_list(G, N, X, Types, Args);
-gen_marshal_par_list(G, N, X, [Type |Types], [{Attr, Arg}|Args]) ->
- JType = ic_java_type:getParamType(G, N, Type, Attr),
- [JType ++ " " ++ Arg |
- gen_marshal_par_list(G, N, X, Types, Args)].
-
-
-gen_unmarshal_par_list(_, _, _, [], []) ->
- [];
-gen_unmarshal_par_list(G, N, X, [_Type |Types], [{in, _Arg}|Args]) ->
- gen_unmarshal_par_list(G, N, X, Types, Args);
-gen_unmarshal_par_list(G, N, X, [Type |Types], [{Attr, Arg}|Args]) ->
- JType = ic_java_type:getParamType(G, N, Type, Attr),
- [JType ++ " " ++ Arg |
- gen_unmarshal_par_list(G, N, X, Types, Args)].
-
-
-%%
-gen_client_marshal_call_par_list([]) ->
- [];
-gen_client_marshal_call_par_list([{out, _Arg}|Args]) ->
- gen_client_marshal_call_par_list(Args);
-gen_client_marshal_call_par_list([{_Attr, Arg}|Args]) ->
- [Arg | gen_client_marshal_call_par_list(Args)].
-
-
-gen_client_unmarshal_call_par_list([]) ->
- [];
-gen_client_unmarshal_call_par_list([{in, _Arg}|Args]) ->
- gen_client_unmarshal_call_par_list(Args);
-gen_client_unmarshal_call_par_list([{_Attr, Arg}|Args]) ->
- [Arg | gen_client_unmarshal_call_par_list(Args)].
-
-
-
-count_client_receive(ArgNames) ->
- count_client_receive(ArgNames,0).
-
-count_client_receive([],C) ->
- C;
-count_client_receive([{in, _Arg}|Args],C) ->
- count_client_receive(Args,C);
-count_client_receive([_|Args],C) ->
- count_client_receive(Args,C+1).
-
-
-
-count_client_send(ArgNames) ->
- count_client_send(ArgNames,0).
-
-count_client_send([],C) ->
- C;
-count_client_send([{out, _Arg}|Args],C) ->
- count_client_send(Args,C);
-count_client_send([_|Args],C) ->
- count_client_send(Args,C+1).
-
-
-gen_cb_arg_list([]) ->
- [];
-gen_cb_arg_list([{_Attr, Arg}|Args]) ->
- [Arg | gen_cb_arg_list(Args)].
-
-
-count_server_receive(ArgNames) ->
- count_server_receive(ArgNames,0).
-
-count_server_receive([],C) ->
- C;
-count_server_receive([_|Args],C) ->
- count_server_receive(Args,C+1).
-
-
-count_server_send(ArgNames) ->
- count_server_send(ArgNames,0).
-
-count_server_send([],C) ->
- C;
-count_server_send([{in, _Arg}|Args],C) ->
- count_server_send(Args,C);
-count_server_send([_|Args],C) ->
- count_server_send(Args,C+1).
-
-
-
-
-
-%%%-------------------------------------------------------
-
-
-emit_type_function(G, N, X, Fd) ->
-
- TC = ic_forms:get_type_code(G, N, X),
-
- %%io:format("X = ~p\nTC = ~p\n",[X,TC]),
-
- ic_codegen:emit(Fd, " private static ~sTypeCode _tc;\n",[?ICPACKAGE]),
- ic_codegen:emit(Fd, " synchronized public static ~sTypeCode type() {\n\n",[?ICPACKAGE]),
-
- ic_codegen:emit(Fd, " if (_tc != null)\n"),
- ic_codegen:emit(Fd, " return _tc;\n\n"),
-
- emit_type_function(TC, 0, Fd),
-
- ic_codegen:emit(Fd, "\n _tc = _tc0;\n"),
-
- ic_codegen:emit(Fd, "\n return _tc0;\n"),
- ic_codegen:emit(Fd, " }\n\n").
-
-
-
-emit_type_function({tk_struct, ID, Name, ML}, C, Fd) -> %% struct
- ic_codegen:emit(Fd, " ~sTypeCode _tc~p =\n",[?ICPACKAGE,C]),
- ic_codegen:emit(Fd, " new ~sTypeCode();\n", [?ICPACKAGE]),
- ic_codegen:emit(Fd, " _tc~p.kind(~sTCKind.tk_struct);\n", [C,?ICPACKAGE]),
- ic_codegen:emit(Fd, " _tc~p.id(~p);\n", [C,ID]),
- ic_codegen:emit(Fd, " _tc~p.name(~p);\n", [C,Name]),
- ic_codegen:emit(Fd, " _tc~p.member_count(~p);\n", [C,length(ML)]),
- emit_struct_members(ML, C, C+1, 0, Fd);
-
-emit_type_function({tk_enum, ID, Name, MNames}, C, Fd) -> %% enum
- ic_codegen:emit(Fd, " ~sTypeCode _tc~p =\n",[?ICPACKAGE,C]),
- ic_codegen:emit(Fd, " new ~sTypeCode();\n", [?ICPACKAGE]),
- ic_codegen:emit(Fd, " _tc~p.kind(~sTCKind.tk_enum);\n", [C,?ICPACKAGE]),
- ic_codegen:emit(Fd, " _tc~p.id(~p);\n", [C,ID]),
- ic_codegen:emit(Fd, " _tc~p.name(~p);\n", [C,Name]),
- ic_codegen:emit(Fd, " _tc~p.member_count(~p);\n", [C,length(MNames)]),
- emit_enum_members(MNames, C, 0, Fd),
- C+1;
-
-emit_type_function({tk_array, ET, L}, C, Fd) -> %% array
- ic_codegen:emit(Fd, " ~sTypeCode _tc~p =\n",[?ICPACKAGE,C]),
- ic_codegen:emit(Fd, " new ~sTypeCode();\n", [?ICPACKAGE]),
- ic_codegen:emit(Fd, " _tc~p.kind(~sTCKind.tk_array);\n", [C,?ICPACKAGE]),
- ic_codegen:emit(Fd, " _tc~p.id(id());\n",[C]),
- ic_codegen:emit(Fd, " _tc~p.length(~p);\n", [C,L]),
- C1 = C+1,
- C2 = emit_type_function(ET, C1, Fd),
- ic_codegen:emit(Fd, " _tc~p.content_type(_tc~p);\n", [C,C1]),
- C2;
-
-emit_type_function({tk_sequence, ET, L}, C, Fd) -> %% sequence
- ic_codegen:emit(Fd, " ~sTypeCode _tc~p =\n",[?ICPACKAGE,C]),
- ic_codegen:emit(Fd, " new ~sTypeCode();\n", [?ICPACKAGE]),
- ic_codegen:emit(Fd, " _tc~p.kind(~sTCKind.tk_sequence);\n", [C,?ICPACKAGE]),
- ic_codegen:emit(Fd, " _tc~p.id(id());\n",[C]),
- ic_codegen:emit(Fd, " _tc~p.length(~p);\n", [C,L]),
- C1 = C+1,
- C2 = emit_type_function(ET, C1, Fd),
- ic_codegen:emit(Fd, " _tc~p.content_type(_tc~p);\n", [C,C1]),
- C2;
-
-emit_type_function({tk_string, L}, C, Fd) -> %% string
- ic_codegen:emit(Fd, " ~sTypeCode _tc~p =\n",[?ICPACKAGE,C]),
- ic_codegen:emit(Fd, " new ~sTypeCode();\n", [?ICPACKAGE]),
- ic_codegen:emit(Fd, " _tc~p.kind(~sTCKind.tk_string);\n", [C,?ICPACKAGE]),
- ic_codegen:emit(Fd, " _tc~p.length(~p);\n", [C,L]),
- C+1;
-
-emit_type_function({tk_union, ID, Name, DT, DI, LL}, C, Fd) -> %% union
-
- ic_codegen:emit(Fd, " ~sTypeCode _tc~p =\n",[?ICPACKAGE,C]),
- ic_codegen:emit(Fd, " new ~sTypeCode();\n", [?ICPACKAGE]),
- ic_codegen:emit(Fd, " _tc~p.kind(~sTCKind.tk_union);\n", [C,?ICPACKAGE]),
- ic_codegen:emit(Fd, " _tc~p.id(~p);\n", [C,ID]),
- ic_codegen:emit(Fd, " _tc~p.name(~p);\n", [C,Name]),
-
- C1 = C+1,
- C2 = emit_type_function(DT, C1, Fd),
-
- ic_codegen:emit(Fd, " _tc~p.discriminator_type(_tc~p);\n", [C,C1]),
- ic_codegen:emit(Fd, " _tc~p.default_index(~p);\n", [C,DI]),
- ic_codegen:emit(Fd, " _tc~p.member_count(~p);\n", [C,length(LL)]),
-
- emit_union_labels(LL, C, DT, C2, 0, Fd);
-
-emit_type_function(tk_term, C, Fd) -> %% term, must change it to tk_any
- ic_codegen:emit(Fd, " ~sTypeCode _tc~p =\n",[?ICPACKAGE,C]),
- ic_codegen:emit(Fd, " new ~sTypeCode();\n", [?ICPACKAGE]),
- ic_codegen:emit(Fd, " _tc~p.kind(~sTCKind.tk_any);\n", [C,?ICPACKAGE]),
- C+1;
-
-emit_type_function(TC, C, Fd) -> %% other
- ic_codegen:emit(Fd, " ~sTypeCode _tc~p =\n",[?ICPACKAGE,C]),
- ic_codegen:emit(Fd, " new ~sTypeCode();\n", [?ICPACKAGE]),
- ic_codegen:emit(Fd, " _tc~p.kind(~sTCKind.~p);\n", [C,?ICPACKAGE,TC]),
- C+1.
-
-
-
-emit_struct_members([], _, TCtr, _, _Fd) ->
- TCtr;
-emit_struct_members([{Name,MT}|Rest], BTCtr, TCtr, I, Fd) ->
- ic_codegen:emit(Fd, " _tc~p.member_name(~p,~p);\n", [BTCtr,I,Name]),
- TCtr2 = emit_type_function(MT, TCtr, Fd),
- ic_codegen:emit(Fd, " _tc~p.member_type(~p,_tc~p);\n", [BTCtr,I,TCtr]),
- emit_struct_members(Rest, BTCtr, TCtr2, I+1, Fd).
-
-emit_enum_members([], _, _, _Fd) ->
- ok;
-emit_enum_members([Name|Names], BTCtr, I, Fd) ->
- ic_codegen:emit(Fd, " _tc~p.member_name(~p,~p);\n", [BTCtr,I,Name]),
- emit_enum_members(Names, BTCtr, I+1, Fd).
-
-
-emit_union_labels([], _, _, TCtr, _, _) ->
- TCtr;
-emit_union_labels([{L, LN, LT}|Rest], BTCtr, DT, TCtr, I, Fd) ->
- ic_codegen:emit(Fd, " ~sAny _any~p =\n",[?ICPACKAGE,TCtr]),
- ic_codegen:emit(Fd, " new ~sAny();\n", [?ICPACKAGE]),
- TCtr1 = TCtr+1,
- TCtr2 = emit_type_function(LT, TCtr1,Fd),
- ic_codegen:emit(Fd, " _any~p.type(_tc~p);\n",[TCtr,TCtr1]),
-
- case L of
- default ->
- ic_codegen:emit(Fd, " _any~p.insert_atom(\"default\");\n", [TCtr]);
- _ ->
- case DT of
- tk_boolean ->
- ic_codegen:emit(Fd, " _any~p.insert_boolean(~p);\n",[TCtr,L]);
- tk_char ->
- Default = if is_integer(L) ->
- [L];
- true ->
- L
- end,
- ic_codegen:emit(Fd, " _any~p.insert_char('~s');\n",[TCtr,Default]);
- tk_ushort ->
- ic_codegen:emit(Fd, " _any~p.insert_ushort(~p);\n",[TCtr,L]);
- tk_ulong ->
- ic_codegen:emit(Fd, " _any~p.insert_ulong(~p);\n",[TCtr,L]);
- tk_short ->
- ic_codegen:emit(Fd, " _any~p.insert_short(~p);\n",[TCtr,L]);
- tk_long ->
- ic_codegen:emit(Fd, " _any~p.insert_long(~p);\n",[TCtr,L]);
- _ ->
- ic_codegen:emit(Fd, " _any~p.insert_string(~p);\n", [TCtr,L])
- end
- end,
- ic_codegen:emit(Fd, " _tc~p.member_label(~p,_any~p);\n", [BTCtr,I,TCtr]),
- ic_codegen:emit(Fd, " _tc~p.member_name(~p,~p);\n", [BTCtr,I,LN]),
- TCtr3 = emit_type_function(LT, TCtr2, Fd),
- ic_codegen:emit(Fd, " _tc~p.member_type(~p,_tc~p);\n", [BTCtr,I,TCtr2]),
- emit_union_labels(Rest, BTCtr, DT, TCtr3, I+1, Fd).
-
-
-
-
-
-
-
-
diff --git a/lib/ic/src/ic_noc.erl b/lib/ic/src/ic_noc.erl
deleted file mode 100644
index 0e387b5e70..0000000000
--- a/lib/ic/src/ic_noc.erl
+++ /dev/null
@@ -1,1117 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(ic_noc).
-
-
--export([do_gen/3]).
-%%------------------------------------------------------------
-%%
-%% Internal stuff
-%%
-%%------------------------------------------------------------
-
--export([unfold/1, mk_attr_func_names/2]).
-
-
--import(ic_util, [mk_name/2, mk_var/1, mk_oe_name/2, to_atom/1, to_list/1]).
--import(ic_forms, [get_id/1, get_id2/1, get_body/1, is_oneway/1]).
--import(ic_codegen, [emit/2, emit/3, nl/1]).
--import(ic_options, [get_opt/2]).
-
-
--import(lists, [foreach/2, foldr/3, map/2]).
-
-
--include("icforms.hrl").
--include("ic.hrl").
-
-
-
-
-%%------------------------------------------------------------
-%%
-%% Generate the client side Erlang stubs.
-%%
-%% Each module is generated to a separate file.
-%%
-%% Export declarations for all interface functions must be
-%% generated. Each function then needs to generate a function head and
-%% a body. IDL parameters must be converted into Erlang parameters
-%% (variables, capitalised) and a type signature list must be
-%% generated (for later encode/decode).
-%%
-%%------------------------------------------------------------
-
-
-do_gen(G, File, Form) ->
- G2 = ic_file:filename_push(G, [], mk_oe_name(G,
- ic_file:remove_ext(to_list(File))),
- erlang),
- gen_head(G2, [], Form),
- exportDependency(G2),
- %% Loop through form and adds inheritence data
- ic_pragma:preproc(G2, [], Form),
- gen(G2, [], Form),
- genDependency(G2),
- ic_file:filename_pop(G2, erlang),
- ok.
-
-
-gen(G, N, [X|Xs]) when is_record(X, preproc) ->
- NewG = ic:handle_preproc(G, N, X#preproc.cat, X),
- gen(NewG, N, Xs);
-
-gen(G, N, [X|Xs]) when is_record(X, module) ->
- CD = ic_code:codeDirective(G,X),
- G2 = ic_file:filename_push(G, N, X, CD),
- N2 = [get_id2(X) | N],
- gen_head(G2, N2, X),
- gen(G2, N2, get_body(X)),
- G3 = ic_file:filename_pop(G2, CD),
- gen(G3, N, Xs);
-
-gen(G, N, [X|Xs]) when is_record(X, interface) ->
- G2 = ic_file:filename_push(G, N, X, erlang),
- N2 = [get_id2(X) | N],
- gen_head(G2, N2, X),
- gen(G2, N2, get_body(X)),
- foreach(fun({_Name, Body}) -> gen(G2, N2, Body) end,
- X#interface.inherit_body),
- gen_serv(G2, N, X),
- G3 = ic_file:filename_pop(G2, erlang),
- gen(G3, N, Xs);
-
-gen(G, N, [X|Xs]) when is_record(X, const) ->
-% N2 = [get_id2(X) | N],
- emit_constant_func(G, X#const.id, X#const.val),
- gen(G, N, Xs); %% N2 or N?
-
-gen(G, N, [X|Xs]) when is_record(X, op) ->
- {Name, ArgNames, TypeList, OutArgs} = extract_info(G, N, X),
-
- case getNocType(G,X,N) of
- transparent ->
- emit_transparent_func(G, N, X, Name, ArgNames, TypeList, OutArgs);
- multiple ->
- mark_not_transparent(G,N),
- emit_transparent_func(G, N, X, Name, ArgNames, TypeList, OutArgs);
- _XTuple ->
- mark_not_transparent(G,N),
- emit_stub_func(G, N, X, Name, ArgNames, TypeList, OutArgs)
- end,
-
- gen(G, N, Xs);
-
-
-gen(G, N, [X|Xs]) when is_record(X, attr) ->
- emit_attr(G, N, X, fun emit_stub_func/7),
- gen(G, N, Xs);
-
-gen(G, N, [X|Xs]) when is_record(X, except) ->
- icstruct:except_gen(G, N, X, erlang),
- gen(G, N, Xs);
-
-gen(G, N, [X|Xs]) ->
- case may_contain_structs(X) of
- true -> icstruct:struct_gen(G, N, X, erlang);
- false -> ok
- end,
- gen(G, N, Xs);
-
-gen(_G, _N, []) -> ok.
-
-
-may_contain_structs(X) when is_record(X, typedef) -> true;
-may_contain_structs(X) when is_record(X, struct) -> true;
-may_contain_structs(X) when is_record(X, union) -> true;
-may_contain_structs(_X) -> false.
-
-
-
-%%--------------------------------------------------------------------
-%%
-%% Generate the server side (handle_call and handle_cast)
-%%
-
-gen_serv(G, N, X) ->
- case ic_genobj:is_stubfile_open(G) of
- true ->
- emit_serv_std(G, N, X),
- N2 = [get_id2(X) | N],
- gen_calls(G, N2, get_body(X)),
- lists:foreach(fun({_Name, Body}) ->
- gen_calls(G, N2, Body) end,
- X#interface.inherit_body),
- get_if_gen(G, N2, X),
- gen_end_of_call(G, N, X), % Note N instead of N2
-
- gen_casts(G, N2, get_body(X)),
- lists:foreach(fun({_Name, Body}) ->
- gen_casts(G, N2, Body) end,
- X#interface.inherit_body),
- gen_end_of_cast(G, N, X), % Note N instead of N2
- emit_skel_footer(G, N, X); % Note N instead of N2
- false ->
- ok
- end.
-
-gen_calls(G, N, [X|Xs]) when is_record(X, op) ->
- case is_oneway(X) of
- false ->
- {Name, ArgNames, TypeList, OutArgs} = extract_info(G, N, X),
- emit_skel_func(G, N, X, Name, ArgNames, TypeList, OutArgs),
- gen_calls(G, N, Xs);
- true ->
- gen_calls(G, N, Xs)
- end;
-
-gen_calls(G, N, [X|Xs]) when is_record(X, attr) ->
- emit_attr(G, N, X, fun emit_skel_func/7),
- gen_calls(G, N, Xs);
-
-gen_calls(G, N, [_X|Xs]) -> gen_calls(G, N, Xs);
-gen_calls(_G, _N, []) -> ok.
-
-gen_casts(G, N, [X|Xs]) when is_record(X, op) ->
- case is_oneway(X) of
- true ->
- {Name, ArgNames, TypeList, OutArgs} = extract_info(G, N, X),
- emit_skel_func(G, N, X, Name, ArgNames, TypeList, OutArgs),
- gen_casts(G, N, Xs);
- false ->
- gen_casts(G, N, Xs)
- end;
-
-gen_casts(G, N, [_X|Xs]) -> gen_casts(G, N, Xs);
-gen_casts(_G, _N, []) -> ok.
-
-emit_attr(G, N, X, F) ->
- XX = #id_of{type=X},
- {GetType, SetType} = mk_attr_func_types(N, X),
- lists:foreach(fun(Id) ->
- X2 = XX#id_of{id=Id},
- {Get, Set} = mk_attr_func_names(N, get_id(Id)),
- F(G, N, X2, Get, [], GetType, []),
- case X#attr.readonly of
- {readonly, _} -> ok;
- _ ->
- F(G, N, X2, Set, [mk_name(G, "Value")],
- SetType, [])
- end end, ic_forms:get_idlist(X)).
-
-
-extract_info(G, _N, X) when is_record(X, op) ->
- Name = get_id2(X),
- InArgs = ic:filter_params([in,inout], X#op.params),
- OutArgs = ic:filter_params([out,inout], X#op.params),
- ArgNames = mk_erl_vars(G, InArgs),
- TypeList = {ic_forms:get_tk(X),
- map(fun(Y) -> ic_forms:get_tk(Y) end, InArgs),
- map(fun(Y) -> ic_forms:get_tk(Y) end, OutArgs)
- },
- {Name, ArgNames, TypeList, OutArgs}.
-
-
-
-
-emit_serv_std(G, N, X) ->
- Fd = ic_genobj:stubfiled(G),
- case transparent(G) of
- true ->
- true;
- _XTupleORMultiple ->
- Impl = getImplMod(G,X,[get_id2(X)|N]),
- TypeID = ictk:get_IR_ID(G, N, X),
-
- nl(Fd), nl(Fd), nl(Fd),
- ic_codegen:mcomment(Fd, ["Server implementation."]),
- nl(Fd), nl(Fd),
- ic_codegen:mcomment(Fd, ["Function for fetching the interface type ID."]),
- nl(Fd),
- emit(Fd, "typeID() ->\n"),
- emit(Fd, " \"~s\".\n", [TypeID]),
- nl(Fd), nl(Fd),
- ic_codegen:mcomment(Fd, ["Server creation functions."]),
- nl(Fd),
- emit(Fd, "oe_create() ->\n"),
- emit(Fd, " start([], []).\n", []),
- nl(Fd),
- emit(Fd, "oe_create_link() ->\n"),
- emit(Fd, " start_link([], []).\n", []),
- nl(Fd),
- emit(Fd, "oe_create(Env) ->\n"),
- emit(Fd, " start(Env, []).\n", []),
- nl(Fd),
- emit(Fd, "oe_create_link(Env) ->\n"),
- emit(Fd, " start_link(Env, []).\n", []),
- nl(Fd),
- emit(Fd, "oe_create(Env, RegName) ->\n"),
- emit(Fd, " start(RegName, Env, []).\n", []),
- nl(Fd),
- emit(Fd, "oe_create_link(Env, RegName) ->\n"),
- emit(Fd, " start_link(RegName, Env, []).\n", []),
- nl(Fd),
- ic_codegen:mcomment(Fd, ["Start functions."]),
- nl(Fd),
- emit(Fd, "start(Env, Opt) ->\n"),
- emit(Fd, " gen_server:start(?MODULE, Env, Opt).\n"),
- nl(Fd),
- emit(Fd, "start_link(Env, Opt) ->\n"),
- emit(Fd, " gen_server:start_link(?MODULE, Env, Opt).\n"),
- nl(Fd),
- emit(Fd, "start(RegName, Env, Opt) ->\n"),
- emit(Fd, " gen_server:start(RegName, ?MODULE, Env, Opt).\n"),
- nl(Fd),
- emit(Fd, "start_link(RegName, Env, Opt) ->\n"),
- emit(Fd, " gen_server:start_link(RegName, ?MODULE, Env, Opt).\n"),
- nl(Fd),
- ic_codegen:comment(Fd, "Call to implementation init"),
- emit(Fd, "init(Env) ->\n"),
- emit(Fd, " ~p:~p(Env).\n", [Impl, init]),
- nl(Fd),
- emit(Fd, "terminate(Reason, State) ->\n"),
- emit(Fd, " ~p:~p(Reason, State).\n",
- [Impl, terminate]),
- nl(Fd),
- emit(Fd, "code_change(_OldVsn, State, _Extra) ->\n"),
- emit(Fd, " {ok, State}.\n"),
- nl(Fd), nl(Fd)
- end,
- Fd.
-
-
-
-
-gen_end_of_call(G, _N, _X) ->
- case transparent(G) of
- true ->
- true;
- _XTuple ->
- Fd = ic_genobj:stubfiled(G),
- nl(Fd), nl(Fd),
- ic_codegen:mcomment_light(Fd, ["Standard gen_server call handle"]),
- emit(Fd, "handle_call(stop, _From, State) ->\n"),
- emit(Fd, " {stop, normal, ok, State}"),
- case get_opt(G, serv_last_call) of
- exception ->
- emit(Fd, ";\n"),
- nl(Fd),
- emit(Fd, "handle_call(_Req, _From, State) ->\n"),
- emit(Fd, " {reply, ~p, State}.\n",[getCallErr()]);
- exit ->
- emit(Fd, ".\n"),
- nl(Fd),
- nl(Fd)
- end
- end,
- ok.
-
-
-gen_end_of_cast(G, _N, _X) ->
- case transparent(G) of
- true ->
- true;
- _XTuple ->
- Fd = ic_genobj:stubfiled(G),
- nl(Fd), nl(Fd),
- ic_codegen:mcomment_light(Fd, ["Standard gen_server cast handle"]),
- emit(Fd, "handle_cast(stop, State) ->\n"),
- emit(Fd, " {stop, normal, State}"),
- case get_opt(G, serv_last_call) of
- exception ->
- emit(Fd, ";\n"),
- nl(Fd),
- emit(Fd, "handle_cast(_Req, State) ->\n"),
- emit(Fd, " {reply, ~p, State}.\n",[getCastErr()]);
- exit ->
- emit(Fd, ".\n"),
- nl(Fd), nl(Fd)
- end
- end,
- ok.
-
-
-emit_skel_footer(G, N, X) ->
- case transparent(G) of
- true ->
- true;
- _XTuple ->
- Fd = ic_genobj:stubfiled(G),
- nl(Fd), nl(Fd),
- ic_codegen:mcomment_light(Fd, ["Standard gen_server handles"]),
- case use_impl_handle_info(G, N, X) of
- true ->
- emit(Fd, "handle_info(X, State) ->\n"),
- emit(Fd, " ~p:handle_info(X, State).\n\n",
- [list_to_atom(ic_genobj:impl(G))]);
- false ->
- emit(Fd, "handle_info(_X, State) ->\n"),
- emit(Fd, " {reply, ~p, State}.\n\n",[getInfoErr()])
- end
- end,
- ok.
-
-
-use_impl_handle_info(G, N, X) ->
- FullName = ic_util:to_colon([get_id2(X) | N]),
- case {get_opt(G, {handle_info, true}), get_opt(G, {handle_info, FullName})} of
- {_, force_false} -> false;
- {false, false} -> false;
- _ -> true
- end.
-
-
-use_timeout(G, N, _X) ->
- FullName = ic_util:to_colon(N),
- case {get_opt(G, {timeout, true}), get_opt(G, {timeout, FullName})} of
- {_, force_false} -> false;
- {false, false} -> false;
- _ -> true
- end.
-
-
-get_if_name(G) -> mk_oe_name(G, "get_interface").
-
-
-%% Generates the get_interface function (for Lars)
-get_if_gen(G, N, X) ->
- case transparent(G) of
- true ->
- ok;
- _XTuple ->
- case ic_genobj:is_stubfile_open(G) of
- true ->
- IFC_TKS = tk_interface_data(G,N,X),
- Fd = ic_genobj:stubfiled(G),
- Name = to_atom(get_if_name(G)),
-
- ic_codegen:mcomment_light(Fd,
- [io_lib:format("Standard Operation: ~p",
- [Name])]),
-
- emit(Fd, "handle_call({_~s, ~p, []}, _From, State) ->~n",
- [mk_name(G, "Ref"), Name]),
- emit(Fd, " {reply, ~p, State};~n", [IFC_TKS]),
- nl(Fd),
- ok;
-
- false -> ok
- end
- end.
-
-
-get_if(G,N,[X|Rest]) when is_record(X, op) ->
- R = ic_forms:get_tk(X),
- IN = lists:map(fun(P) -> ic_forms:get_tk(P) end,
- ic:filter_params([in, inout], X#op.params)),
- OUT = lists:map(fun(P) -> ic_forms:get_tk(P) end,
- ic:filter_params([out, inout], X#op.params)),
- case print_tk(G,N,X) of
- true ->
- [{get_id2(X), {R, IN, OUT}} | get_if(G,N,Rest)];
- false ->
- get_if(G,N,Rest)
- end;
-
-get_if(G,N,[X|Rest]) when is_record(X, attr) -> %% Attributes not handled so far <<<<<<<<<<<<<<<<<<<<<<<<
- {GetT, SetT} = mk_attr_func_types([], X),
- AList = lists:map(fun(Id) ->
- {Get, Set} = mk_attr_func_names([], get_id(Id)),
- case X#attr.readonly of
- {readonly, _} ->
- {Get, GetT};
- _ ->
- [{Set, SetT}, {Get, GetT}]
- end end, ic_forms:get_idlist(X)),
- lists:flatten(AList) ++ get_if(G,N,Rest);
-
-get_if(G,N,[_X|Rest]) -> get_if(G,N,Rest);
-get_if(_,_,[]) -> [].
-
-
-
-
-%%------------------------------------------------------------
-%%
-%% Export stuff
-%%
-%% Gathering of all names that should be exported from a stub
-%% file.
-%%
-
-
-gen_head_special(G, N, X) when is_record(X, interface) ->
- Fd = ic_genobj:stubfiled(G),
- NocType = getNocType(G,X,N),
-
- foreach(fun({Name, Body}) ->
- ic_codegen:comment(Fd, "Exports from ~p",
- [ic_util:to_colon(Name)]),
- ic_codegen:export(Fd, exp_top(G, N, Body, NocType, [])),
- nl(Fd)
- end, X#interface.inherit_body),
-
- case transparent(G) of
- true ->
- nl(Fd), nl(Fd);
- _XTuple ->
- ic_codegen:comment(Fd, "Type identification function"),
- ic_codegen:export(Fd, [{typeID, 0}]),
- nl(Fd),
- ic_codegen:comment(Fd, "Used to start server"),
- ic_codegen:export(Fd, [{start, 2},{start_link, 3}]),
- ic_codegen:export(Fd, [{oe_create, 0}, {oe_create_link, 0}, {oe_create, 1},
- {oe_create_link, 1},{oe_create, 2}, {oe_create_link, 2}]),
- nl(Fd),
- ic_codegen:comment(Fd, "gen server export stuff"),
- emit(Fd, "-behaviour(gen_server).\n"),
- ic_codegen:export(Fd, [{init, 1}, {terminate, 2}, {code_change, 3},
- {handle_call, 3}, {handle_cast, 2}, {handle_info, 2}]),
- nl(Fd), nl(Fd),
- ic_codegen:mcomment(Fd, ["Object interface functions."]),
- nl(Fd), nl(Fd), nl(Fd)
- end,
- Fd;
-
-
-gen_head_special(_G, _N, _X) -> ok.
-
-
-
-%% Shall generate all export declarations
-gen_head(G, N, X) ->
- case ic_genobj:is_stubfile_open(G) of
- true ->
- F = ic_genobj:stubfiled(G),
- ic_codegen:comment(F, "Interface functions"),
- ic_codegen:export(F, exp_top(G, N, X, getNocType(G,X,N), [])),
- nl(F),
- gen_head_special(G, N, X);
- false -> ok
- end.
-
-exp_top(_G, _N, X, _NT, Acc) when element(1, X) == preproc ->
- Acc;
-exp_top(G, N, L, NT, Acc) when is_list(L) ->
- exp_list(G, N, L, NT, Acc);
-exp_top(G, N, M, NT, Acc) when is_record(M, module) ->
- exp_list(G, N, get_body(M), NT, Acc);
-exp_top(G, N, I, NT, Acc) when is_record(I, interface) ->
- exp_list(G, N, get_body(I), NT, Acc);
-exp_top(G, N, X, NT, Acc) ->
- exp3(G, N, X, NT, Acc).
-
-exp3(_G, _N, C, _NT, Acc) when is_record(C, const) ->
- [{get_id(C#const.id), 0} | Acc];
-
-exp3(G, N, Op, NocType, Acc) when is_record(Op, op) ->
- FuncName = get_id(Op#op.id),
-
- TA = case use_timeout(G,N,Op) of
- true ->
- 1;
- false ->
- 0
- end,
-
- case NocType of
- transparent ->
- Arity = length(ic:filter_params([in, inout], Op#op.params)) + TA + 1,
- [{FuncName, Arity} | Acc];
- multiple ->
- case getModType(G, Op, N) of
- dt ->
- Arity = length(ic:filter_params([in, inout], Op#op.params)) + TA + 1,
- [{FuncName, Arity} | Acc];
- do ->
- Arity = length(ic:filter_params([in, inout], Op#op.params)) + TA + 1,
- [{FuncName, Arity} | Acc];
- spt ->
- Arity = length(ic:filter_params([in, inout], Op#op.params)) + TA + 1,
- [{FuncName, Arity} | Acc];
- spo ->
- Arity = length(ic:filter_params([in, inout], Op#op.params)) + TA + 1,
- [{FuncName, Arity} | Acc]
- end;
- _ ->
- Arity = length(ic:filter_params([in, inout], Op#op.params)) + TA + 1,
- [{FuncName, Arity} | Acc]
- end;
-exp3(_G, _N, A, _NT, Acc) when is_record(A, attr) ->
- lists:foldr(fun(Id, Acc2) ->
- {Get, Set} = mk_attr_func_names([], get_id(Id)),
- case A#attr.readonly of
- {readonly, _} -> [{Get, 1} | Acc2];
- _ -> [{Get, 1}, {Set, 2} | Acc2]
- end end, Acc, ic_forms:get_idlist(A));
-
-exp3(_G, _N, _X, _NT, Acc) -> Acc.
-
-exp_list(G, N, L, NT, OrigAcc) ->
- lists:foldr(fun(X, Acc) -> exp3(G, N, X, NT, Acc) end, OrigAcc, L).
-
-
-
-
-%%------------------------------------------------------------
-%%
-%% Emit stuff
-%%
-%% Low level generation primitives
-%%
-
-emit_stub_func(G, N, X, Name, ArgNames, TypeList, _OutArgs) ->
- case ic_genobj:is_stubfile_open(G) of
- false -> ok;
- true ->
- Fd = ic_genobj:stubfiled(G),
- StubName = list_to_atom(Name),
- This = mk_name(G, "Ref"),
- XTuple = getNocType(G,X,N),
- CallOrCast =
- case is_oneway(X) of
- true -> ?CAST;
- _ -> ?CALL
- end,
-
- %% Type expand operation on comments
- ic_code:type_expand_op(G,N,X,Fd),
-
- case use_timeout(G,N,X) of
- true ->
- Timeout = mk_name(G,"Timeout"),
- emit(Fd, "~p(~s) ->\n",
- [StubName, mk_list([This, Timeout| ArgNames])]),
- emit(Fd, " ~p:~s(~s, ~s, ?MODULE, ~p, ~p, [~s], ~p).\n\n",
- [getImplMod(G,X,N),
- CallOrCast,
- This,
- Timeout,
- XTuple,
- StubName,
- mk_list(ArgNames),
- tk_operation_data(G, N, X, TypeList)]);
- false ->
- emit(Fd, "~p(~s) ->\n",
- [StubName, mk_list([This | ArgNames])]),
-
- emit(Fd, " ~p:~s(~s, ~p, ?MODULE, ~p, [~s], ~p).\n\n",
- [getImplMod(G,X,N),
- CallOrCast,
- This,
- XTuple,
- StubName,
- mk_list(ArgNames),
- tk_operation_data(G, N, X, TypeList)])
- end
- end.
-
-
-emit_transparent_func(G, N, X, Name, ArgNames, _TypeList, _OutArgs) ->
- case ic_genobj:is_stubfile_open(G) of
- false -> ok;
- true ->
- Fd = ic_genobj:stubfiled(G),
- OpName = list_to_atom(Name),
-
- ArgList = case use_timeout(G,N,X) of
- true ->
- mk_list([mk_name(G,"Ref"),mk_name(G,"Timeout")|ArgNames]);
- false ->
- mk_list([mk_name(G,"Ref")|ArgNames])
- end,
-
- %% Type expand operation on comments
- ic_code:type_expand_op(G,N,X,Fd),
-
- emit(Fd, "~p(~s) ->\n", [OpName,ArgList]),
- emit(Fd, " ~p:~s(~s).\n\n", [getImplMod(G,X,N), OpName, ArgList])
- end.
-
-
-
-
-
-
-emit_skel_func(G, N, X, OpName, ArgNames, _TypeList, _OutArgs) ->
- case getNocType(G,X,N) of
- transparent ->
- true;
- multiple ->
- true;
- XTuple ->
- case ic_genobj:is_stubfile_open(G) of
- false -> ok;
- true ->
- Fd = ic_genobj:stubfiled(G),
- Name = list_to_atom(OpName),
- This = mk_name(G, "Ref"),
- From = mk_name(G, "From"),
- State = mk_name(G, "State"),
-
- %% Type expand handle operation on comments
- ic_code:type_expand_handle_op(G,N,X,Fd),
-
- case is_oneway(X) of
- true ->
- emit(Fd, "handle_cast({~s, ~p, OE_Module, ~p, [~s]}, ~s) ->\n",
- [This, XTuple, Name, mk_list(ArgNames), State]),
- emit(Fd, " ~p:handle_cast({~s, ~p, OE_Module, ~p, [~s]}, ~s);\n\n",
- [getImplMod(G,X,N), This, XTuple, Name, mk_list(ArgNames), State]);
- false ->
- emit(Fd, "handle_call({~s, ~p, OE_Module, ~p, [~s]}, ~s, ~s) ->\n",
- [This, XTuple, Name, mk_list(ArgNames), From, State]),
- emit(Fd, " ~p:handle_call({~s, ~p, OE_Module, ~p, [~s]}, ~s, ~s);\n\n",
- [getImplMod(G,X,N), This, XTuple, Name, mk_list(ArgNames), From, State])
- end
- end
- end.
-
-
-
-emit_constant_func(G, Id, Val) ->
- case ic_genobj:is_stubfile_open(G) of
- false -> ok;
- true ->
- Fd = ic_genobj:stubfiled(G),
- N = list_to_atom(get_id(Id)),
- emit_const_comment(G, Fd, Id, N),
- emit(Fd, "~p() -> ~p.\n\n", [N, Val])
- end.
-
-
-emit_const_comment(_G, F, _X, Name) ->
- ic_codegen:mcomment_light(F,
- [io_lib:format("Constant: ~p", [Name])]).
-
-%%------------------------------------------------------------
-%%
-%% Utilities
-%%
-%% Convenient little go-get functions
-%%
-%%------------------------------------------------------------
-
-%% The automaticly generated get and set operation names for an
-%% attribute.
-mk_attr_func_names(_Scope, Name) ->
- {"_get_" ++ Name, "_set_" ++ Name}.
-
-%% Returns TK of the Get and Set attribute functions.
-mk_attr_func_types(_N, X) ->
- TK = ic_forms:get_tk(X),
- {{TK, [], []}, {tk_void, [TK], []}}.
-
-
-
-%%------------------------------------------------------------
-%%
-%% Generation utilities and common stuff
-%%
-%% Convenient stuff for generation
-%%
-%%------------------------------------------------------------
-
-
-%% Input is a list of parameters (in parse form) and output is a list
-%% of capitalised variable names. mk_var is in icgen
-mk_erl_vars(_G, Params) ->
- map(fun(P) -> mk_var(get_id(P#param.id)) end, Params).
-
-
-%% mk_list produces a nice comma separated string of variable names
-mk_list([]) -> [];
-mk_list([Arg | Args]) ->
- Arg ++ mk_list2(Args).
-mk_list2([Arg | Args]) ->
- ", " ++ Arg ++ mk_list2(Args);
-mk_list2([]) -> [].
-
-
-%%------------------------------------------------------------
-%%
-%% Parser utilities
-%%
-%% Called from the yecc parser. Expands the identifier list of an
-%% attribute so that the attribute generator never has to handle
-%% lists.
-%%
-%%------------------------------------------------------------
-
-
-%% Unfold identifier lists or nested lists. Note that many records
-%% contain an entry named id that is a list before unfold and a single
-%% id afterwards.
-unfold(L) when is_list(L) ->
- lists:flatten(map(fun(X) -> unfold2(X) end, L));
-unfold(X) -> unfold2(X).
-
-unfold2(A) when is_record(A, attr) ->
- map(fun(Id) -> A#attr{id=Id} end, A#attr.id);
-unfold2(M) when is_record(M, member) ->
- map(fun(Id) -> M#member{id=Id} end, M#member.id);
-unfold2(M) when is_record(M, case_dcl) ->
- map(fun(Id) -> M#case_dcl{label=Id} end, M#case_dcl.label);
-unfold2(T) when is_record(T, typedef) ->
- map(fun(Id) -> T#typedef{id=Id} end, T#typedef.id ).
-
-
-
-
-
-
-%% Export code produce for dependency function
-exportDependency(G) ->
- Fd = ic_genobj:stubfiled(G),
- ic_codegen:export(Fd, [{oe_dependency, 0}]),
- nl(Fd).
-
-%% Code produce for dependency function
-genDependency(G) ->
- Fd = ic_genobj:stubfiled(G),
- nl(Fd),nl(Fd),
- ic_codegen:comment(Fd, "Idl file dependency list function"),
- emit(Fd, "oe_dependency() ->\n", []),
- emit(Fd, " ~p.\n\n", [ic_pragma:get_dependencies(G)]).
-
-
-
-
-
-%%%%%%
-
-
-getImplMod(G,X,Scope) -> %% to_atom(ic_genobj:impl(G)) | ChoicedModuleName
-
- %% Get actual pragma appliance scope
- SpecScope = getActualScope(G,X,Scope),
-
- %% The "broker" option is passed
- %% only by pragmas, seek for module.
- case ic_pragma:getBrokerData(G,X,SpecScope) of
- {Module,_Type} ->
- Module;
- _List ->
- element(1,ic_pragma:defaultBrokerData(G))
- end.
-
-
-getNocType(G,X,Scope) when is_record(X, interface) -> %% default | specified
- OpList = getAllOperationScopes(G,Scope),
- getNocType2(G,X,OpList);
-getNocType(G,X,Scope) -> %% transparent | {extraarg1,....,extraargN}
- getNocType3(G,X,Scope).
-
-getNocType2(G,X,List) ->
- getNocType2(G,X,List,[]).
-
-getNocType2(_,_,[],Found) ->
- selectTypeFromList(Found);
-getNocType2(G,X,[OpScope|OpScopes],Found) ->
- getNocType2(G,X,OpScopes,[getNocType3(G,X,OpScope)|Found]).
-
-getNocType3(G,X,Scope) -> %% transparent | {extraarg1,....,extraargN}
-
- %% Get actual pragma appliance scope
- SpecScope = getActualScope(G,X,Scope),
-
- %% The "broker" option is passed
- %% only by pragmas, seek for type.
- case ic_pragma:getBrokerData(G,X,SpecScope) of
- {_Module,Type} ->
- Type;
- List ->
- selectTypeFromList(List) %%transparent/multiple
- end.
-
-
-getModType(G,X,Scope) -> %% default | specified
-
- %% Get actual pragma appliance scope
- SpecScope = getActualScope(G,X,Scope),
-
- %% The "broker" option is passed
- %% only by pragmas, seek for brokerdata.
- case ic_pragma:getBrokerData(G,X,SpecScope) of
- {Module,Type} ->
- case Module == ic_genobj:impl(G) of
- true ->
- case Type of
- transparent ->
- dt; %% default + transparent
- _ ->
- do %% default + opaque
- end;
- false ->
- case Type of
- transparent ->
- spt; %% specified + transparent
- _ ->
- spo %% specified + opaque
- end
- end;
- _List ->
- dt
- end.
-
-
-
-%%%%
-%%
-%% Returns a list of ALL operation full
-%% scoped names local and inherited
-%% from other interfaces
-%%
-
-getAllOperationScopes(G,Scope) ->
- getOperationScopes(G,Scope) ++
- getInhOperationScopes(G,Scope).
-
-
-getOperationScopes(G,Scope) ->
- getOpScopes(G,
- Scope,
- ets:match(ic_genobj:pragmatab(G),{op,'$0',Scope,'_','_'}),
- []).
-
-getOpScopes(_,_,[],OpScopes) ->
- OpScopes;
-getOpScopes(G,Scope,[[Name]|Names],Found) ->
- getOpScopes(G,Scope,Names,[[Name|Scope]|Found]).
-
-
-getInhOperationScopes(G,Scope) ->
- getInhOpScopes1(G,
- Scope,
- ets:match(ic_genobj:pragmatab(G),{inherits,Scope,'$1'}),
- []).
-
-getInhOpScopes1(G,_Scope,[],OpScopes) ->
- getInhOpScopes2(G,OpScopes);
-getInhOpScopes1(G,Scope,[[SC]|SCs],Found) ->
- getInhOpScopes1(G,Scope,SCs,[SC|Found]).
-
-
-getInhOpScopes2(G,Scopes) ->
- getInhOpScopes2(G,Scopes,[]).
-
-getInhOpScopes2(_G,[],Found) ->
- Found;
-getInhOpScopes2(G,[SC|SCs],Found) ->
- getOperationScopes(G,SC) ++ getInhOpScopes2(G,SCs,Found).
-
-%%
-%%
-%%%%
-
-
-
-%%%%
-%%
-%%
-%% Seek the actual operation scope :
-%%
-%% * if the operation is inherited, get the real scope for it
-%%
-%% * if the operation has a specific pragma, apply the real
-%% scope, otherwise return the including scope
-%%
-getActualScope(G, X, Scope) when is_record(X, op) ->
- OpScope = getRealOpScope(G,X,Scope),
- case ets:match(ic_genobj:pragmatab(G),{codeopt_specific,OpScope}) of
- [[]] ->
- OpScope;
- _ ->
- Scope
- end;
-getActualScope(_G, _X, N) ->
- N.
-
-%%
-%% Just seek and return the scope for the operation
-%% where it were originaly defined
-%%
-getRealOpScope(G,X,N) when is_record(X, op) ->
- Ptab = ic_genobj:pragmatab(G),
- Id = get_id2(X),
-
- case ets:match(Ptab,{op,Id,N,'_','_'}) of
- [[]] ->
- [Id|N];
- _ ->
- getRealOpScope(G, Ptab, X, N, Id, ets:match(Ptab,{inherits,N,'$1'}))
- end;
-getRealOpScope(_G,_X,N) ->
- N.
-
-getRealOpScope(_G, _S, _X, N, Id, []) ->
- [Id|N];
-getRealOpScope(G, S, X, N, Id, [[OS]|OSs]) ->
- case ets:match(S,{op,Id,OS,'_','_'}) of
- [[]] ->
- [Id|OS];
- _ ->
- getRealOpScope(G, S, X, N, Id, OSs)
- end.
-
-selectTypeFromList([]) ->
- transparent;
-selectTypeFromList([{_,transparent}|Rest]) ->
- selectTypeFromList(Rest);
-selectTypeFromList([transparent|Rest]) ->
- selectTypeFromList(Rest);
-selectTypeFromList([_|_Rest]) ->
- multiple.
-
-
-
-getCallErr() ->
- {'ERROR' ,"Bad Operation -- handle call"}.
-
-getCastErr() ->
- {'ERROR' ,"Bad Operation -- handle cast"}.
-
-getInfoErr() ->
- {'ERROR' ,"Bad Operation -- handle info"}.
-
-
-
-
-
-
-%%
-%% Type code access utilities
-%%
-
-tk_operation_data(G, N, X, TL) ->
- case print_tk(G,N,X) of
- true ->
- TL;
- false ->
- no_tk
- end.
-
-tk_interface_data(G, N, X) ->
- InfoList =
- foldr(fun({_Name, Body}, Acc) ->
- get_if(G,N,Body)++Acc end,
- get_if(G,N,get_body(X)),
- X#interface.inherit_body),
- case InfoList of
- [] ->
- no_tk; %%%%%%%% Should be changed to [] <<<<<<<<<<<<<<<<<<<<<<<<<<< Warning !
- _ ->
- InfoList
- end.
-
-
-print_tk(G, N, X) when is_record(X, op)-> %% operation
- case getNocType(G,X,N) of
- transparent ->
- false;
- multiple ->
- false;
- _XTuple -> %%check if there are any USETK pragmas
- operation_usetk(G,N,X)
- end;
-print_tk(_G, _N, _X) -> %% error
- false.
-
-
-operation_usetk(G,N,X) ->
- PTab = ic_genobj:pragmatab(G),
- OTab = ic_genobj:optiontab(G),
- OpName = get_id2(X),
-% SID = ic_util:to_colon(N),
- Res = case use_tk(OTab,[N]) of
- {ok,N} ->
- true;
- false ->
- %% Look if there is an operation with that name
- %% which can be found in an included file.
- case ets:match(PTab,{file_data_included,'_','_',op,'$3',OpName,'_','_','_'}) of
- [] ->
- false;
- ScopeList ->
- case use_tk(OTab,ScopeList) of
- %% There is an operation with that name,
- %% look if it is inherited by interface "N"
- {ok,FoundScope} ->
- ic_pragma:is_inherited_by(FoundScope,N,PTab);
- false ->
- false
- end
- end
- end,
- Res.
-
-
-use_tk(_,[]) ->
- false;
-use_tk(OTab,[[Scope]|Scopes]) ->
- SID = ic_util:to_colon(Scope),
- case ets:match(OTab,{{option,{use_tk,SID}},true}) of
- [] ->
- case ets:match(OTab,{{option,{use_tk,"::"++SID}},true}) of
- [] ->
- use_tk(OTab,Scopes);
- _ ->
- {ok,Scope}
- end;
- _ ->
- {ok,Scope}
- end;
-use_tk(OTab,[Scope|Scopes]) ->
- SID = ic_util:to_colon(Scope),
- case ets:match(OTab,{{option,{use_tk,SID}},true}) of
- [] ->
- case ets:match(OTab,{{option,{use_tk,"::"++SID}},true}) of
- [] ->
- use_tk(OTab,Scopes);
- _ ->
- {ok,Scope}
- end;
- _ ->
- {ok,Scope}
- end.
-
-
-
-
-
-mark_not_transparent(G,N) ->
-
- %% Mark that there are multiple
- %% functions in interface
- S = ic_genobj:pragmatab(G),
- ets:insert(S,{no_transparent,N}).
-
-
-transparent(G) ->
-
- S = ic_genobj:pragmatab(G),
- case ets:match_object(S,{no_transparent,'$0'}) of
- [] ->
- true;
- _ ->
- false
- end.
-
diff --git a/lib/ic/src/ic_options.erl b/lib/ic/src/ic_options.erl
deleted file mode 100644
index d7f56c0d46..0000000000
--- a/lib/ic/src/ic_options.erl
+++ /dev/null
@@ -1,364 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(ic_options).
-
--include_lib("ic/src/ic.hrl").
--include_lib("kernel/include/file.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([defaultBe/0, float_to_version/1, get_opt/2, add_opt/3,
- read_cfg/2, which_opts/1, allowed_opt/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-%%-----------------------------------------------------------------
-%% External functions
-%%-----------------------------------------------------------------
-
-%%--------------------------------------------------------------------
-%%
-%% Option handling
-%%
-%% Valid options are: (those with * is NotYetImpl)
-%%
-%% pedantic - makes the compiler really nitty-gritty about its input
-%%
-%% Wall - those warning options that we feel an IDL programmer should
-%% care about. Not as picky as pedantic
-%%
-%% warn_multi_mod - warn if several modules are declared in the same
-%% IDL file
-%%
-%% warn_nested_mod - warn if there are nested modules. This is not a
-%% problem but it breakes the rule that modules are put into one file
-%% each.
-%%
-%% warn_name_shadow - warn if identifiers are shadow through inherited
-%% interfaces. Default is true.
-%%
-%% warn_quoted_atom - warn if atoms needs quote, this makes Erlang
-%% code less nice but is certainly no error.
-%%
-%% nowarn - suppress all warning messages. Will still output warnings
-%% if silent2 option is used
-%%
-%% always_outargs - force object server implementation return the
-%% tuple {RetVal, OutArgs, NewState} even if there are no OutArgs. If
-%% this option is not set then such an operation implementation is
-%% assumed to return {RetVal, NewState}
-%%
-%% use_proc_dict - use the process dictionary in the client
-%% stubs. This means that client stubs return RetVal instead of {ok,
-%% RetVal, OutArgs} and that corba:get_outargs() returns OutArgs. The
-%% out arguments are stored with the key '$corba_outargs'.
-%%
-%% module_group - use the top module as file name for both skeletons
-%% and stubs. Default value is false which means that each interface
-%% is put in a separate file.
-%%
-%% skel_module_group - group all interfaces in a module in one
-%% skeleton file as opposed to one skeleton file for each
-%% interface. Defaults to false.
-%%
-%% stub_module_group - group all interface stubs from a module in one
-%% stub file as opposed to one stub file for each interface. Default
-%% is false.
-%%
-%% *help - prints a small summary of the compiler usage
-%%
-%% silent - suppresses all messages from the compiler
-%%
-%% silent2 - suppresses all messages from the compiler and returns all
-%% warnings or errors as lists. Returns {ok, WarnList} or {error,
-%% WarnList, ErrList}
-%%
-%% *noexec - runs the compiler but does not open files or write to
-%% files.
-%%
-%% {serv, <ModName>} - sets the name of the implementation skeleton
-%% file. This defaults to ModName_skel.
-%%
-%% {impl, <ModName>} - sets the name of the interface server
-%% implementation module name. This defaults to InterfaceName_impl
-%%
-%% {outdir, Dir} - use Dir as the directory to put all generated
-%% files.
-%%
-%% {servdir, Dir} - put all generated skel files in the directory Dir.
-%%
-%% {stubdir, Dir} - put all generated stub files in the directory Dir.
-%%
-%% {this, InterfaceOrOpName} - puts the OE_THIS parameter into the
-%% impl. call. This option can be used both on whole interfaces an on
-%% distinct operations. Fullscoped names must be used (as in {this,
-%% "M1::I1::Op"}). The option can be given in 3 ways: {this, Name}
-%% means this will be added to all matching Name or as {{this, Name},
-%% true} or this can explicitly be asked to be left out as in {{this,
-%% Name}, false} which enables OE_THIS to be passed to all ops of an
-%% interface except those set by the false flag.
-%%
-%% cfgfile - sets the name of the config file that is read at
-%% startup. The order of the different ways to set options is: default
-%% setting, configuration file, options given when generator is
-%% called. Default name for this file is .ic_config
-%%
-%% serv_last_call - tells what the last handle_call clause should
-%% do. It can have the values exception, which makes the last clause
-%% return a CORBA exception and exit which does not generate a last clause
-%% (which will make the server crash on an unknown call)
-%%
-%%
-%% -- UNDOCUMENTED --
-%%
-%% debug - prints debug information
-%%
-%% tokens - prints the tokens from the tokenizer and then exit
-%%
-%% form - prints the form from the parser and then exit
-%%
-%% tform - form returned from type check
-%%
-%% time - if true then time is measured during compilation
-%%
-%%
-%%--------------------------------------------------------------------
-allowed_opt(default_opts, _V) -> true;
-allowed_opt(debug, V) -> is_bool(V);
-allowed_opt(tokens, V) -> is_bool(V);
-allowed_opt(form, V) -> is_bool(V);
-allowed_opt(tform, V) -> is_bool(V);
-allowed_opt(time, V) -> is_bool(V);
-allowed_opt(maxerrs, V) -> is_intorinfinity(V);
-allowed_opt(maxwarns, V) -> is_intorinfinity(V);
-allowed_opt(nowarn, V) -> is_bool(V);
-allowed_opt(show_opts, V) -> is_bool(V);
-
-allowed_opt(help, V) -> is_bool(V);
-allowed_opt('Wall', V) -> is_bool(V);
-allowed_opt(warn_multi_mod, V) -> is_bool(V);
-allowed_opt(warn_quoted_atom, V) -> is_bool(V);
-allowed_opt(warn_nested_mod, V) -> is_bool(V);
-allowed_opt(warn_name_shadow, V) -> is_bool(V);
-allowed_opt(module_group, V) -> is_bool(V);
-allowed_opt(skel_module_group, V) -> is_bool(V);
-allowed_opt(stub_module_group, V) -> is_bool(V);
-allowed_opt(always_outargs, V) -> is_bool(V);
-allowed_opt(pedantic, V) -> is_bool(V);
-%%allowed_opt(gen_serv, V) -> is_bool(V);
-%%allowed_opt(gen_stub, V) -> is_bool(V);
-allowed_opt(gen_hrl, V) -> is_bool(V);
-allowed_opt(serv_last_call, exception) -> true;
-allowed_opt(serv_last_call, exit) -> true;
-allowed_opt(silent, V) -> is_bool(V);
-allowed_opt(silent2, V) -> is_bool(V);
-allowed_opt({serv, _}, _V) -> true;
-allowed_opt({impl, _}, _V) -> true;
-allowed_opt(outdir, _V) -> true;
-allowed_opt(servdir, _V) -> true;
-allowed_opt(stubdir, _V) -> true;
-allowed_opt(cfgfile, _V) -> true;
-allowed_opt(use_preproc, V) -> is_bool(V);
-allowed_opt(preproc_cmd, _V) -> true;
-allowed_opt(preproc_flags, _V) -> true;
-allowed_opt(this, _V) -> true;
-allowed_opt({this, _}, V) -> is_bool(V);
-allowed_opt(from, _V) -> true;
-allowed_opt({from, _}, V) -> is_bool(V);
-allowed_opt(handle_info, _V) -> true;
-allowed_opt({handle_info, _}, V) -> is_bool(V);
-allowed_opt(timeout, _V) -> true;
-allowed_opt({timeout, _}, V) -> is_bool(V);
-allowed_opt(c_timeout, {V1, V2}) -> is_int(V1) and is_int(V2);
-allowed_opt(c_timeout, V) -> is_int(V);
-allowed_opt(c_report, V) -> is_bool(V);
-allowed_opt(scoped_op_calls, V) -> is_bool(V);
-% Compatibility option (semantic check limitation)
-allowed_opt(scl, V) -> is_bool(V);
-% Added switches for non corba generation
-allowed_opt(flags, V) -> is_int(V);
-allowed_opt(be, erl_corba) -> true;
-allowed_opt(be, erl_template) -> true;
-allowed_opt(be, erl_genserv) -> true;
-allowed_opt(be, c_genserv) -> true;
-allowed_opt(be, erl_plain) -> true;
-allowed_opt(be, c_server) -> true;
-allowed_opt(be, c_client) -> true;
-allowed_opt(be, java) -> true;
-% Noc backend
-allowed_opt(be, noc) -> true;
-allowed_opt({broker,_},{_,transparent}) -> true;
-allowed_opt({broker,_},{_,Term}) -> is_term(Term);
-allowed_opt({use_tk,_},V) -> is_bool(V);
-%
-% Multiple be
-allowed_opt(multiple_be, _List) -> true;
-%
-allowed_opt(precond, {_M, _F}) -> true;
-allowed_opt({precond, _}, {_M, _F}) -> true;
-allowed_opt(postcond, {_M, _F}) -> true;
-allowed_opt({postcond, _}, {_M, _F}) -> true;
-allowed_opt(no_codechange, V) -> is_bool(V);
-allowed_opt(user_protocol, _V) -> true;
-allowed_opt(light_ifr, V) -> is_bool(V);
-allowed_opt(_, _) -> false.
-
-
--define(DEFAULTCFGFILE, ".ic_config").
-
-which_opts(G) ->
- ets:match(G#genobj.options, {{option, '$1'}, '$2'}).
-
-add_opt(G, KList, Val) when is_list(KList) ->
- lists:foreach(fun({K, V}) -> add_opt(G, K, V);
- (K) -> add_opt(G, K, Val) end,
- KList);
-
-add_opt(G, servdir, V) ->
- do_add_opt(G, servdir, assure_directory(G, ic_util:to_list(V)));
-add_opt(G, stubdir, V) ->
- do_add_opt(G, stubdir, assure_directory(G, ic_util:to_list(V)));
-add_opt(G, K, V) ->
- do_add_opt(G, K, V).
-
-
-assure_directory(_G, Dir) ->
- Dirs = filename:split(Dir),
- check_dirs(Dirs, [], filename:pathtype(Dir)).
-
-check_dirs([X | Xs], SoFar, Type) ->
- New = if SoFar == [], Type /= absolute ->
- X;
- true ->
- filename:join(SoFar, X)
- end,
- assert_dir(New),
- check_dirs(Xs, New, Type);
-check_dirs([], SoFar, _Type) ->
- SoFar.
-
-assert_dir(D) ->
- case file:read_file_info(D) of
- {ok, X} when X#file_info.type == directory -> ok;
- _ -> case file:make_dir(D) of
- ok -> ok;
- _ -> exit({could_not_create, D})
- end
- end.
-
-do_add_opt(G, handle_info, V) ->
- ?insert(G#genobj.options, {option, {handle_info, V}}, true);
-do_add_opt(G, {handle_info, V}, false) ->
- ?insert(G#genobj.options, {option, {handle_info, V}}, force_false);
-do_add_opt(G, timeout, V) ->
- ?insert(G#genobj.options, {option, {timeout, V}}, true);
-do_add_opt(G, {timeout, V}, false) ->
- ?insert(G#genobj.options, {option, {timeout, V}}, force_false);
-do_add_opt(G, this, V) ->
- ?insert(G#genobj.options, {option, {this, V}}, true);
-do_add_opt(G, {this, V}, false) ->
- ?insert(G#genobj.options, {option, {this, V}}, force_false);
-do_add_opt(G, from, V) ->
- ?insert(G#genobj.options, {option, {from, V}}, true);
-do_add_opt(G, {from, V}, false) ->
- ?insert(G#genobj.options, {option, {from, V}}, force_false);
-do_add_opt(G, scoped_op_calls, V) when V /= true, V /= false ->
- ?insert(G#genobj.options, {option, {scoped_op_calls, V}}, false);
-do_add_opt(G, K, V) ->
- case allowed_opt(K, V) of
- true ->
- case expand_opt(K) of
- L when is_list(L) ->
- add_opt(G, L, V);
- _ ->
- %%io:format("Add opt: ~p ~p~n", [K, V]),
- ?insert(G#genobj.options, {option, K}, V)
- end;
- _ ->
- ic_error:warn(G, {illegal_opt, K})
- end.
-
-get_opt(G, K) ->
- case ets:lookup(G#genobj.options, {option, K}) of
- [] -> false;
- [{{_, K}, V}] -> V
- end.
-
-expand_opt(pedantic) -> [warn_multi_mod, warn_quoted_atom, always_outargs];
-expand_opt(module_group) -> [skel_module_group, stub_module_group];
-expand_opt('Wall') -> [warn_multi_mod, warn_nested_mod, warn_name_shadow];
-expand_opt(outdir) -> [servdir, stubdir];
-expand_opt(default_opts) ->
- ['Wall', gen_hrl, {serv_last_call, exception},
- {outdir, []}, use_preproc, {preproc_cmd, "erl"},
- {preproc_flags, ""}, {maxerrs, 10}, {maxwarns, infinity}];
-%% gcc preproc command {preproc_cmd, "gcc -x c++ -E"}
-expand_opt(Opt) -> Opt.
-
-
-%% Use this if user not provide
-%% a backend.
-defaultBe() -> erl_corba.
-
-
-%%
-%% Read any config file
-read_cfg(G, Opts) ->
- Name = case lists:keysearch(cfgfile, 1, Opts) of
- {value, {_, N}} -> ic_util:to_list(N);
- _ -> ?DEFAULTCFGFILE
- end,
- case file:consult(Name) of
- {ok, OptList} ->
- add_opt(G, OptList, true);
- _X when Name == ?DEFAULTCFGFILE -> ok;
-%% {error, X} ->
-%% ic_error:warn(G, {cfg_open, X, Name});
- X -> ic_error:warn(G, {cfg_open, X, Name})
- end.
-
-
-float_to_version({_,_,Str}) -> Str.
-
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-is_bool(true) -> true;
-is_bool(false) -> true;
-is_bool(_) -> false.
-
-is_int(V) when is_integer(V) -> true;
-is_int(_) -> false.
-
-is_intorinfinity(X) when is_integer(X) -> true;
-is_intorinfinity(infinity) -> true;
-is_intorinfinity(_X) -> false.
-
-
-is_term(Term) when is_tuple(Term) -> true;
-is_term(_NoTerm) -> false.
-
diff --git a/lib/ic/src/ic_plainbe.erl b/lib/ic/src/ic_plainbe.erl
deleted file mode 100644
index 6875c1314e..0000000000
--- a/lib/ic/src/ic_plainbe.erl
+++ /dev/null
@@ -1,356 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(ic_plainbe).
-
-
--export([do_gen/3]).
-%%------------------------------------------------------------
-%%
-%% Internal stuff
-%%
-%%------------------------------------------------------------
-
--import(ic_util, [mk_var/1, mk_oe_name/2, to_atom/1, to_list/1]).
--import(ic_forms, [get_id/1, get_id2/1, get_body/1]).
--import(ic_codegen, [emit/3, nl/1]).
-
--import(lists, [foreach/2, map/2]).
-
--include("icforms.hrl").
--include("ic.hrl").
-
-%%------------------------------------------------------------
-%%
-%% Generate the client side Erlang stubs.
-%%
-%% Each module is generated to a separate file.
-%%
-%% Export declarations for all interface functions must be
-%% generated. Each function then needs to generate a function head and
-%% a body. IDL parameters must be converted into Erlang parameters
-%% (variables, capitalised) and a type signature list must be
-%% generated (for later encode/decode).
-%%
-%%------------------------------------------------------------
-
-
-do_gen(G, File, Form) ->
- G2 = ic_file:filename_push(G, [], mk_oe_name(G,
- ic_file:remove_ext(to_list(File))),
- erlang),
- gen_head(G2, [], Form),
- exportDependency(G2),
- gen(G2, [], Form),
- genDependency(G2),
- ic_file:filename_pop(G2, erlang),
- ok.
-
-
-gen(G, N, [X|Xs]) when is_record(X, preproc) ->
- NewG = ic:handle_preproc(G, N, X#preproc.cat, X),
- gen(NewG, N, Xs);
-
-gen(G, N, [X|Xs]) when is_record(X, module) ->
- CD = ic_code:codeDirective(G,X),
- G2 = ic_file:filename_push(G, N, X, CD),
- N2 = [get_id2(X) | N],
- gen_head(G2, N2, X),
- gen(G2, N2, get_body(X)),
- G3 = ic_file:filename_pop(G2, CD),
- gen(G3, N, Xs);
-
-gen(G, N, [X|Xs]) when is_record(X, interface) ->
- %% Add inheritence data to pragmatab
- ic_pragma:add_inh_data(G,N,X),
- G2 = ic_file:filename_push(G, N, X, erlang),
- N2 = [get_id2(X) | N],
- gen_head(G2, N2, X),
- gen(G2, N2, get_body(X)),
- foreach(fun({_Name, Body}) -> gen(G2, N2, Body) end,
- X#interface.inherit_body),
- G3 = ic_file:filename_pop(G2, erlang),
- gen(G3, N, Xs);
-
-gen(G, N, [X|Xs]) when is_record(X, const) ->
-% N2 = [get_id2(X) | N],
- emit_constant_func(G, X#const.id, X#const.val),
- gen(G, N, Xs); %% N or N2?
-
-gen(G, N, [X|Xs]) when is_record(X, op) ->
- {Name, ArgNames, TypeList, OutArgs} = extract_info(G, N, X),
- emit_func(G, N, X, Name, ArgNames, TypeList, OutArgs),
- gen(G, N, Xs);
-
-
-gen(G, N, [X|Xs]) when is_record(X, attr) ->
- emit_attr(G, N, X, fun emit_func/7),
- gen(G, N, Xs);
-
-gen(G, N, [X|Xs]) when is_record(X, except) ->
- icstruct:except_gen(G, N, X, erlang),
- gen(G, N, Xs);
-
-gen(G, N, [X|Xs]) ->
- case may_contain_structs(X) of
- true -> icstruct:struct_gen(G, N, X, erlang);
- false -> ok
- end,
- gen(G, N, Xs);
-
-gen(_G, _N, []) -> ok.
-
-
-may_contain_structs(X) when is_record(X, typedef) -> true;
-may_contain_structs(X) when is_record(X, struct) -> true;
-may_contain_structs(X) when is_record(X, union) -> true;
-may_contain_structs(_X) -> false.
-
-
-%%------------------------------------------------------------
-%%
-%% Export stuff
-%%
-%% Gathering of all names that should be exported from a stub
-%% file.
-%%
-
-
-gen_head_special(G, N, X) when is_record(X, interface) ->
- Fd = ic_genobj:stubfiled(G),
-
- foreach(fun({Name, Body}) ->
- ic_codegen:comment(Fd, "Exports from ~p",
- [ic_util:to_colon(Name)]),
- ic_codegen:export(Fd, exp_top(G, N, Body, [])),
- nl(Fd)
- end, X#interface.inherit_body),
- Fd;
-gen_head_special(_G, _N, _X) -> ok.
-
-
-
-%% Shall generate all export declarations
-gen_head(G, N, X) ->
- case ic_genobj:is_stubfile_open(G) of
- true ->
- F = ic_genobj:stubfiled(G),
- ic_codegen:comment(F, "Interface functions"),
- ic_codegen:export(F, exp_top(G, N, X, [])),
- nl(F),
- gen_head_special(G, N, X);
- false -> ok
- end.
-
-exp_top(_G, _N, X, Acc) when element(1, X) == preproc ->
- Acc;
-exp_top(G, N, L, Acc) when is_list(L) ->
- exp_list(G, N, L, Acc);
-exp_top(G, N, M, Acc) when is_record(M, module) ->
- exp_list(G, N, get_body(M), Acc);
-exp_top(G, N, I, Acc) when is_record(I, interface) ->
- exp_list(G, N, get_body(I), Acc);
-exp_top(G, N, X, Acc) ->
- exp3(G, N, X, Acc).
-
-exp3(_G, _N, C, Acc) when is_record(C, const) ->
- [{get_id(C#const.id), 0} | Acc];
-
-exp3(_G, _N, Op, Acc) when is_record(Op, op) ->
- FuncName = get_id(Op#op.id),
- Arity = length(ic:filter_params([in, inout], Op#op.params)),
- [{FuncName, Arity} | Acc];
-
-exp3(_G, _N, A, Acc) when is_record(A, attr) ->
- lists:foldr(fun(Id, Acc2) ->
- {Get, Set} = mk_attr_func_names([], get_id(Id)),
- case A#attr.readonly of
- {readonly, _} -> [{Get, 1} | Acc2];
- _ -> [{Get, 1}, {Set, 2} | Acc2]
- end end, Acc, ic_forms:get_idlist(A));
-
-exp3(_G, _N, _X, Acc) -> Acc.
-
-exp_list(G, N, L, OrigAcc) ->
- lists:foldr(fun(X, Acc) -> exp3(G, N, X, Acc) end, OrigAcc, L).
-
-
-
-
-%%------------------------------------------------------------
-%%
-%% Emit stuff
-%%
-%% Low level generation primitives
-%%
-
-
-emit_func(G, _N, X, Name, ArgNames, _TypeList, OutArgs) ->
- case ic_genobj:is_stubfile_open(G) of
- false -> ok;
- true ->
- Fd = ic_genobj:stubfiled(G),
- OpName = list_to_atom(Name),
- ArgList = mk_list(ArgNames),
- emit_op_comment(G, Fd, X, OpName, ArgNames, OutArgs),
- emit(Fd, "~p(~s) ->\n", [OpName,ArgList]),
- emit(Fd, " ~p:~p(~s).\n\n", [to_atom(ic_genobj:impl(G)), OpName, ArgList])
- end.
-
-emit_attr(G, N, X, F) ->
- XX = #id_of{type=X},
- {GetType, SetType} = mk_attr_func_types(N, X),
- lists:foreach(fun(Id) ->
- X2 = XX#id_of{id=Id},
- {Get, Set} = mk_attr_func_names(N, get_id(Id)),
- F(G, N, X2, Get, [], GetType, []),
- case X#attr.readonly of
- {readonly, _} -> ok;
- _ ->
- F(G, N, X2, Set, [ic_util:mk_name(G, "Value")],
- SetType, [])
- end end, ic_forms:get_idlist(X)).
-
-emit_constant_func(G, Id, Val) ->
- case ic_genobj:is_stubfile_open(G) of
- false -> ok;
- true ->
- Fd = ic_genobj:stubfiled(G),
- N = list_to_atom(get_id(Id)),
- emit_const_comment(G, Fd, Id, N),
- emit(Fd, "~p() -> ~p.\n\n", [N, Val])
- end.
-
-
-emit_const_comment(_G, F, _X, Name) ->
- ic_codegen:mcomment_light(F,
- [io_lib:format("Constant: ~p", [Name])]).
-
-
-emit_op_comment(G, F, X, Name, InP, OutP) ->
- ic_codegen:mcomment_light(F,
- [io_lib:format("~s: ~p", [get_title(X), Name]),
- "",
- get_returns(G, X, InP, OutP) |
- get_raises(X)]).
-
-get_title(X) when is_record(X, attr) -> "Attribute Operation";
-get_title(_X) -> "Operation".
-
-get_raises(X) when is_record(X, op) ->
- if X#op.raises == [] -> [];
- true ->
- [" Raises: " ++
- mk_list(lists:map(fun(E) -> ic_util:to_colon(E) end, X#op.raises))]
- end;
-get_raises(_X) -> [].
-
-get_returns(_G, _X, _InP, []) ->
- " Returns: RetVal";
-get_returns(G, _X, _InP, OutP) ->
- " Returns: "++mk_list(["RetVal" | mk_erl_vars(G, OutP)]).
-
-
-
-
-%%------------------------------------------------------------
-%%
-%% Utilities
-%%
-%% Convenient little go-get functions
-%%
-%%------------------------------------------------------------
-
-%% The automaticly generated get and set operation names for an
-%% attribute.
-mk_attr_func_names(_Scope, Name) ->
- {"_get_" ++ Name, "_set_" ++ Name}.
-
-%% Returns TK of the Get and Set attribute functions.
-mk_attr_func_types(_N, X) ->
- TK = ic_forms:get_tk(X),
- {{TK, [], []}, {tk_void, [TK], []}}.
-
-
-
-%%------------------------------------------------------------
-%%
-%% Generation utilities and common stuff
-%%
-%% Convenient stuff for generation
-%%
-%%------------------------------------------------------------
-
-
-%% Input is a list of parameters (in parse form) and output is a list
-%% of capitalised variable names. mk_var is in icgen
-mk_erl_vars(_G, Params) ->
- map(fun(P) -> mk_var(get_id(P#param.id)) end, Params).
-
-
-%% mk_list produces a nice comma separated string of variable names
-mk_list([]) -> [];
-mk_list([Arg | Args]) ->
- Arg ++ mk_list2(Args).
-mk_list2([Arg | Args]) ->
- ", " ++ Arg ++ mk_list2(Args);
-mk_list2([]) -> [].
-
-
-%%------------------------------------------------------------
-%%
-%% Parser utilities
-%%
-%% Called from the yecc parser. Expands the identifier list of an
-%% attribute so that the attribute generator never has to handle
-%% lists.
-%%
-%%------------------------------------------------------------
-
-
-
-
-%% Export code produce for dependency function
-exportDependency(G) ->
- Fd = ic_genobj:stubfiled(G),
- ic_codegen:export(Fd, [{oe_dependency, 0}]),
- nl(Fd).
-
-%% Code produce for dependency function
-genDependency(G) ->
- Fd = ic_genobj:stubfiled(G),
- nl(Fd),nl(Fd),
- ic_codegen:comment(Fd, "Idl file dependency list function"),
- emit(Fd, "oe_dependency() ->\n", []),
- emit(Fd, " ~p.\n\n", [ic_pragma:get_dependencies(G)]).
-
-
-
-
-extract_info(G, _N, X) when is_record(X, op) ->
- Name = get_id2(X),
- InArgs = ic:filter_params([in,inout], X#op.params),
- OutArgs = ic:filter_params([out,inout], X#op.params),
- ArgNames = mk_erl_vars(G, InArgs),
- TypeList = {ic_forms:get_tk(X),
- map(fun(Y) -> ic_forms:get_tk(Y) end, InArgs),
- map(fun(Y) -> ic_forms:get_tk(Y) end, OutArgs)
- },
- {Name, ArgNames, TypeList, OutArgs}.
diff --git a/lib/ic/src/ic_pp.erl b/lib/ic/src/ic_pp.erl
deleted file mode 100644
index 8c2e3a0ffe..0000000000
--- a/lib/ic/src/ic_pp.erl
+++ /dev/null
@@ -1,2245 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(ic_pp).
-
--export([run/2]).
-
--define(is_number(X), X >= $0, X =< $9).
--define(is_upper(X), X >= $A, X =< $Z).
--define(is_lower(X), X >= $a, X =< $z).
--define(is_underline(X), X == $_).
--define(is_tab(X), X == 9).
--define(is_space(X), X == 32).
--define(tab, 9).
--define(space, 32).
-
-
-%%======================================================================================
-%%======================================================================================
-%%======================================================================================
-%% Preprocessor
-%%
-%% This preprocessor is equivalent to the gcc-preprocessor. It takes a file name and
-%% a list of preprocessor flags as an input and returns a processed text file.
-%%
-%% The processing is done in two phases.
-%% In the first phase the input file is tokenised into a list where all comments are
-%% replaced by a space and all "backslash-newline" sequences are removed.
-%%
-%% In the second phase all macros are expanded.
-
-%% %% %% NOTE: #if, #else, and #elif are not yet implemented.
-%% Only '#if 0' is implemented to be possible to keep old code as a comment for
-%% future refence by putting '#if 0' before it and '#endif' after it.
-%%
-%%======================================================================================
-%%======================================================================================
-%%======================================================================================
-
-
-%%======================================================================================
-%% Variables which are used throughout the program:
-%% ------------------------------------------------
-%%
-%% Command A preprocessor command
-%% Current Temporary variable used when tokenising the file
-%% Defs The currently valid macro definitions
-%% Err The current list of errors = [{file, line number, error text}, ...]
-%% File The tokenised file (or what remains of it when expanding the macros)
-%% Flags The preprocessor flags
-%% FN or FileName Tbe name of the current file
-%% IfCou Used for ifdef/ifndef/endif values: check_all | {endif, Endif, IfLine}
-%% Endif = number of matching endif's yet to be found
-%% Ifline = the line number for the the first found ifdef/ifndef
-%% IncDir Directories to be searched for included files
-%% IncFile Stack of included files
-%% IncLine The line numer of an include
-%% L The current line number
-%% Name Name of a macro
-%% Nl Number of encountered newlines
-%% No_of_para Numer of parameters of the currently expanded macro
-%% Out The result of the second step
-%% Parameters The parameters of the currently expanded macro
-%% PrevFile The name of the "parent" file which includes the currently expanded file
-%% Rem Remaining of the file currently being expanded
-%% Removed The tokens removed, used when removing tokens to the end of a line
-%% Result The current result of something
-%% SelfRef List of variables which shoud not be expanded at the rescan to avoid
-%% endless loops due to self referencing
-%% Str Temporary string
-%% Text A variable used for string handling, e.g at error handling
-%% Tokens Temoprary list when tokenising
-%% War The current list of warnings = [{file, line number, warning text}, ...]
-%% X Temporary variable used when the value is not important
-%% Y Temporary variable used when the value is not important
-%%
-%%======================================================================================
-
-%% Multiple Include Optimization
-%%
-%% Algorithm described at:
-%% http://gcc.gnu.org/onlinedocs/cppinternals/Guard-Macros.html
--record(mio, {valid = true, %% multiple include valid
- cmacro, %% controlling macro of the current conditional directive
- depth = 0, %% conditional directive depth
- included = []}).
-
-
-
-%%======================================================================================
-%%======================================================================================
-%%======================================================================================
-%% The main entry for the preprocessor
-%%
-%%
-%% Output {ok, Out, War} | {error, Err}
-%%======================================================================================
-%%======================================================================================
-%%======================================================================================
-run(FileName, Flags) when is_atom(FileName) ->
- run(atom_to_list(FileName), Flags);
-
-run(FileName, Flags) ->
- IncDir = include_dir(Flags),
-
- case catch file:read_file(FileName) of
- {ok, Bin} ->
- FileList = binary_to_list(Bin),
- run(FileList, FileName, IncDir, Flags);
- {error, _} ->
- Text = "No such file or directory",
- {error, [FileName ++ ": " ++ Text]}
- end.
-
-
-run(FileList, FileName, IncDir, Flags) ->
- %%----------------------------------------------------------
- %% Run the first phase, i.e tokenise the file
- %%----------------------------------------------------------
- File = tokenise(FileList, FileName),
-
- %%----------------------------------------------------------
- %% Run the second phase, i.e expand macros
- %%----------------------------------------------------------
- {Out, Err, War, _Defs, _Mio, IfCou} = expand(File, FileName, IncDir, Flags),
-
- %%----------------------------------------------------------
- %% Check if all #if #ifdef #ifndef have a matching #endif
- %%----------------------------------------------------------
- IfError = case IfCou of
- {endif, Endif, IfLine} when Endif > 0 ->
- [{FileName, IfLine, "unterminated `#if' conditional"}];
- _ ->
- []
- end,
-
- Err2 = Err++IfError,
-
- case Err2 of
- [] ->
- {ok, lists:flatten(lists:reverse(Out)), lists:reverse(War)};
- _ ->
- {error, lists:reverse(Err2)}
- end.
-
-%%======================================================================================
-%% The entry for all included files
-%%
-%%
-%% Output {Out, Err, War, Defs, MultipleIncludeValid}
-%%======================================================================================
-run_include(FileName, FileList, _Out, Defs, Err, War, IncLine, IncFile, IncDir, Mio) ->
-
- %%----------------------------------------------------------
- %% Run the first phase, i.e tokenise the file
- %%----------------------------------------------------------
- [PrevFile | _T] = IncFile,
- {File, FileInfoStart, FileInfoEnd} =
- tokenise(FileList, FileName, IncLine, PrevFile),
-
- %%----------------------------------------------------------
- %% Run the second phase, i.e expand macros
- %%----------------------------------------------------------
- {Out2, Err2, War2, Defs2, Mio2, IfCou2} =
- expand([FileInfoStart|File]++FileInfoEnd, Defs, Err, War,
- [FileName|IncFile], IncDir,
- #mio{included=Mio#mio.included}),
-
- MergeIncluded = sets:to_list(sets:from_list(Mio#mio.included ++ Mio2#mio.included)),
-
- Mio3 =
- case {Mio2#mio.valid, Mio2#mio.cmacro} of
- {V, Macro} when V == false;
- Macro == undefined ->
- update_mio(Mio#mio{included=MergeIncluded});
- {true, _} ->
- update_mio({include, FileName}, Mio#mio{included=MergeIncluded})
- end,
-
- %%----------------------------------------------------------
- %% Check if all #if #ifdef #ifndef have a matching #endif
- %%----------------------------------------------------------
- IfError = case IfCou2 of
- {endif, Endif, IfLine} when Endif > 0 ->
- [{FileName, IfLine, "unterminated `#if' conditional"}];
- _ ->
- []
- end,
-
- {Out2, Defs2, Err2++IfError, War2, Mio3}.
-
-
-
-
-%%===================================================================================
-%%===================================================================================
-%%===================================================================================
-%% Tokenise the file
-%%
-%%
-%% Output: File
-%%
-%% Description:
-%% The input file is tokenised into a list where all comments are replaced
-%% by a space and all "backslash-newline" sequences are removed.
-%%
-%% A file information is added at start and end of an included file to set the
-%% current file name and line number.
-%%
-%%
-%% A token consists of:
-%% --------------------
-%%
-%% {char, Char} special characters like ()[]{},!%& etc
-%% {command,Command} a macro command
-%% {expanded,Str} an expanded variable, used to prevent infinite loops
-%% at self reference
-%% {file_info,FI} start and end information of a file
-%% FI is a string of the following format:
-%% "# Line FileName Int" were Int is
-%% 1 if start of an included file,
-%% 2 when returning to "parent" file
-%% {nl, L} newline
-%% {number,Num) variable, a string starting with a number
-%% {self_ref,Var} to allow reference to a variable again, used when expanding
-%% self refering macros
-%% space a space
-%% space_exp a space, special notation to prevent not wanted concatination
-%% {string, Str} a (tail of a) string constant
-%% {string_part, Str} a head of a string constant defined on several consecutive lines
-%% {sys_head, Str} (tail of) the file name of included system file
-%% {sys_head_part , Str} the file name of included system file
-%% {var,Var} variable, a string starting with minuscular or capital letter or
-%% an underline
-%%
-%% Note, comments are not removed within a character or string constant
-%% or inside an include-definition where the file name is delimited with < >
-%%===================================================================================
-%%===================================================================================
-%%===================================================================================
-
-tokenise(File, FileName) ->
- {Result, _L} = token(File, 2, [], not_set, 0),
- FI_start = lists:reverse(lists:flatten(io_lib:format("# 1 \"~ts\"~n",[FileName]))),
- FileInfoStart = {file_info, FI_start},
- [FileInfoStart | Result].
-
-tokenise(File, FileName, IncLine, PrevFile) ->
- {Result, _L} = token(File, 2, [], not_set, 0),
- FI_start = lists:reverse(lists:flatten(io_lib:format("# 1 \"~ts\" 1~n",[FileName]))),
- FileInfoStart = {file_info, FI_start},
- FI_end = lists:reverse(lists:flatten(io_lib:format("# ~p \"~ts\" 2~n~n",[IncLine-1,PrevFile]))),
- FileInfoEnd = [{file_info, FI_end}],
- {Result, FileInfoStart, FileInfoEnd}.
-% [FileInfoStart | Result] ++ FileInfoEnd.
-
-
-%%===================================================================================
-%% token(InputFile, L, Result, Gen)
-%% Gen information of the first token on the line, default = not_set
-%%
-%% Output: File
-%%===================================================================================
-
-%%==================================================================
-%% Normal line
-%%==================================================================
-%%---------------------------------------
-%% All file tokenised
-%%---------------------------------------
-token([], L, [{nl,NL}|Result], _Gen, _BsNl) when L == NL+1->
- {lists:reverse([{nl,NL}|Result]), L};
-token([], L, Result, _Gen, _BsNl) ->
- {lists:reverse([{nl,L-1}|Result]), L};
-
-%%---------------------------------------
-%% String
-%%---------------------------------------
-token(File, L, Result, string, BsNl) ->
- case token_string(File, []) of
- {Rem, Str, nl} ->
- Result1 = [{nl, L}, {string,Str} | Result],
- token(Rem, L+1, Result1, string, BsNl);
- {Rem, Str} ->
- token(Rem, L, [{string,Str}|Result], not_set, BsNl)
- end;
-
-token([$"|File], L, Result, Gen, BsNl) ->
- case token_string(File, []) of
- {Rem, Str, nl} ->
- Result1 = [{nl, L}, {string_part,Str} | Result],
- token(Rem, L+1, Result1, string, BsNl);
- {Rem, Str} ->
- token(Rem, L, [{string,Str}|Result], Gen, BsNl)
- end;
-
-%%---------------------------------------
-%% Include with < >
-%%---------------------------------------
-token(File, L, Result, include, BsNl) ->
- case token_include(File, []) of
- {Rem, Str, nl} ->
- Result1 = [{nl, L}, {sys_head,Str} | Result],
- token(Rem, L+1, Result1, include, BsNl);
- {Rem, Str} ->
- token(Rem, L, [{sys_head,Str}|Result], not_set, BsNl)
- end;
-
-token([$<|File], L, [space,{command,"include"}|Result], Gen, BsNl) ->
- case token_include(File, []) of
- {Rem, Str, nl} ->
- Result1 = [{nl, L}, {sys_head_part,Str}, space, {command,"include"} |Result],
- token(Rem, L+1,Result1, include, BsNl);
- {Rem, Str} ->
- Result1 = [{sys_head,Str}, space, {command,"include"} |Result],
- token(Rem, L, Result1, Gen, BsNl)
- end;
-token([$<|File], L, [{command,"include"}|Result], Gen, BsNl) ->
- case token_include(File, []) of
- {Rem, Str, nl} ->
- Result1 = [{nl, L}, {sys_head_part,Str}, space, {command,"include"} |Result],
- token(Rem, L+1,Result1, include, BsNl);
- {Rem, Str} ->
- Result1 = [{sys_head,Str}, space, {command,"include"} |Result],
- token(Rem, L, Result1, Gen, BsNl)
- end;
-
-
-
-
-%%---------------------------------------
-%% CR (just remove these)
-%%---------------------------------------
-token([$\r|File], L, Result, Gen, BsNl) ->
-% Bs = lists:duplicate(BsNl+1,{nl,L}),
- token(File, L, Result, Gen, BsNl); %% Bs or BsNl?
-
-%%---------------------------------------
-%% Newline
-%%---------------------------------------
-token([$\n|File], L, Result, _Gen, BsNl) ->
- Bs = lists:duplicate(BsNl+1,{nl,L}),
- token(File, L+1, Bs++Result, not_set, 0);
-
-token([$\\,$\n|File], L, Result, Gen, BsNl) ->
- token(File, L, Result, Gen, BsNl+1);
-
-%%---------------------------------------
-%% Comments
-%%---------------------------------------
-token([$/,$/|File], L, Result, not_set, BsNl) ->
- Rem = skip_to_nl(File),
- token(Rem, L+1,[{nl, L} | Result], not_set, BsNl);
-token([$/,$/|File], L, Result, _Gen, BsNl) ->
- Rem = skip_to_nl(File),
- token(Rem, L+1,[{nl, L} | Result], not_set, BsNl);
-
-token([$/,$*|File], L, Result, not_set, BsNl) ->
- case token_comment(File) of
- {Rem, nl} ->
- token(Rem, L+1, [{nl, L} | Result], not_set, BsNl);
- Rem ->
- token(Rem, L, Result, not_set, BsNl)
- end;
-token([$/,$*|File], L, Result, Gen, BsNl) ->
- case token_comment(File) of
- {Rem, nl} ->
- token(Rem, L+1, [{nl, L}, space | Result], not_set, BsNl);
- Rem ->
- token(Rem, L, [space|Result], Gen, BsNl)
- end;
-
-%%---------------------------------------
-%% Variable
-%%---------------------------------------
-token([X|File], L, Result, Gen, BsNl) when ?is_upper(X) ->
- GenNew = case Gen of not_set -> var; _ -> Gen end,
- {Rem, Var} = tok_var(File, [X]),
- token(Rem, L, [{var,Var}|Result], GenNew, BsNl);
-token([X|File], L, Result, Gen, BsNl) when ?is_lower(X) ->
- GenNew = case Gen of not_set -> var; _ -> Gen end,
- {Rem, Var} = tok_var(File, [X]),
- token(Rem, L, [{var,Var}|Result], GenNew, BsNl);
-token([X|File], L, Result, Gen, BsNl) when ?is_underline(X) ->
- GenNew = case Gen of not_set -> var; _ -> Gen end,
- {Rem, Var} = tok_var(File, [X]),
- token(Rem, L, [{var,Var}|Result], GenNew, BsNl);
-
-%%---------------------------------------
-%% Number
-%%---------------------------------------
-token([X|File], L, Result, Gen, BsNl) when ?is_number(X) ->
- GenNew = case Gen of not_set -> number; _ -> Gen end,
- {Rem, Tokens} = tok_number(File, [X]),
- token(Rem, L, [{number,Tokens}|Result], GenNew, BsNl);
-
-%%---------------------------------------
-%% Space
-%%---------------------------------------
-token([X|File], L, [Y|Result], Gen, BsNl) when ?is_space(X) ->
- case Y of
- space ->
- Rem = remove_leading_spaces(File),
- token(Rem, L, [Y|Result], Gen, BsNl);
- {nl,_,_} ->
- Rem = remove_leading_spaces(File),
- token(Rem, L, Result, Gen, BsNl);
- _ ->
- Rem = remove_leading_spaces(File),
- token(Rem, L, [space, Y |Result], Gen, BsNl)
- end;
-
-token([X|File], L, [Y|Result], Gen, BsNl) when ?is_tab(X) ->
- case Y of
- space ->
- Rem = remove_leading_spaces(File),
- token(Rem, L, [Y|Result], Gen, BsNl);
- {nl,_,_} ->
- Rem = remove_leading_spaces(File),
- token(Rem, L, Result, Gen, BsNl);
- _ ->
- Rem = remove_leading_spaces(File),
- token(Rem, L, [space, Y |Result], Gen, BsNl)
- end;
-
-%%---------------------------------------
-%% Command
-%%---------------------------------------
-token([$#|File], L, Result, not_set, BsNl) ->
- {Rem, Command} = token_pp_com(File),
- case catch list_to_integer(Command) of
- {'EXIT', _} ->
- token(Rem, L, [{command,Command}|Result], not_set, BsNl);
- _Int ->
- Result1 = [{number,Command}, {command,"line"}| Result],
- token(Rem, L, Result1, not_set, BsNl)
- end;
-
-%%---------------------------------------
-%% Char
-%%---------------------------------------
-token([X|File], L, Result, Gen, BsNl) ->
- GenNew = case Gen of not_set -> char; _ -> Gen end,
- token(File, L, [{char,X}|Result], GenNew, BsNl).
-
-
-%%==================================================================
-%% Scan to the end of a token
-%%==================================================================
-%%---------------------------------------
-%% Number
-%%---------------------------------------
-tok_number([], Str) ->
- {[], lists:reverse(Str)};
-tok_number([X|File], Str) when ?is_upper(X) ->
- tok_number(File, [X|Str]);
-tok_number([X|File], Str) when ?is_lower(X) ->
- tok_number(File, [X|Str]);
-tok_number([X|File], Str) when ?is_underline(X) ->
- tok_number(File, [X|Str]);
-tok_number([X|File], Str) when ?is_number(X) ->
- tok_number(File, [X|Str]);
-tok_number(File, Str) ->
- {File, lists:reverse(Str)}.
-
-
-%%---------------------------------------
-%% Variable
-%%---------------------------------------
-tok_var([], Str) ->
- {[], lists:reverse(Str)};
-tok_var([X|File], Str) when ?is_upper(X) ->
- tok_var(File, [X|Str]);
-tok_var([X|File], Str) when ?is_lower(X) ->
- tok_var(File, [X|Str]);
-tok_var([X|File], Str) when ?is_underline(X) ->
- tok_var(File, [X|Str]);
-tok_var([X|File], Str) when ?is_number(X) ->
- tok_var(File, [X|Str]);
-tok_var(File, Str) ->
- {File, lists:reverse(Str)}.
-
-
-%%---------------------------------------
-%% Preprocessor command
-%%---------------------------------------
-token_pp_com([X|File]) when ?is_upper(X) ->
- tok_var(File, [X]);
-token_pp_com([X|File]) when ?is_lower(X) ->
- tok_var(File, [X]);
-token_pp_com([X|File]) when ?is_underline(X) ->
- tok_var(File, [X]);
-token_pp_com([X|File]) when ?is_number(X) ->
- tok_var(File, [X]);
-token_pp_com(File) ->
- Rem = remove_leading_spaces(File),
- {Rem, "null"}.
-
-
-
-%%---------------------------------------
-%% Comment
-%%---------------------------------------
-token_comment([]) ->
- [];
-token_comment([$*,$/|File]) ->
- File;
-token_comment([$\n|File]) ->
- {[$/,$*|File], nl};
-token_comment([$\r,$\n|File]) ->
- {[$/,$*|File], nl};
-token_comment([$\\,$\n|File]) ->
- {[$/,$*|File], nl};
-%token_comment([$\\,$\n|File]) ->
-% token_comment(File);
-token_comment([_|File]) ->
- token_comment(File).
-
-
-%%---------------------------------------
-%% String
-%%---------------------------------------
-token_string([], Str) ->
- {[], lists:reverse(Str)};
-token_string([$"|File], Str) ->
- {File, lists:reverse(Str)};
-token_string([$\n|File], Str) ->
- {File, lists:reverse(Str), nl};
-token_string([$\r,$\n|File], Str) ->
- {File, lists:reverse(Str), nl};
-token_string([$\\,$\n|File], Str) ->
- token_string(File, Str);
-token_string([X|File], Str) ->
- token_string(File, [X|Str]).
-
-
-%%---------------------------------------
-%% Include
-%%---------------------------------------
-token_include([], Str) ->
- {[], lists:reverse(Str)};
-token_include([$>|File], Str) ->
- {File, lists:reverse(Str)};
-token_include([$\n|File], Str) ->
- {File, lists:reverse(Str), nl};
-token_include([$\r,$\n|File], Str) ->
- {File, lists:reverse(Str), nl};
-token_include([$\\,$\n|File], Str) ->
- token_include(File, Str);
-token_include([X|File], Str) ->
- token_include(File, [X|Str]).
-
-
-
-
-%%===================================================================================
-%% detokenise a list of tokens, until next newline
-%%
-%% Output: a string
-%%===================================================================================
-detokenise(Tokens) ->
- detokenise(Tokens, []).
-
-detokenise([], Result) ->
- lists:flatten(Result);
-detokenise([space], Result) ->
- lists:flatten(Result);
-detokenise([space_exp], Result) ->
- lists:flatten(Result);
-detokenise([space|Rem], Result) ->
- detokenise(Rem, Result++[?space]);
-detokenise([space_exp|Rem], Result) ->
- detokenise(Rem, Result++[?space]);
-detokenise([nl|Rem], Result) ->
- detokenise(Rem, Result++[$\n]);
-detokenise([{_, String}|Rem], Result) ->
- detokenise(Rem, Result++[String]).
-
-
-detokenise_pragma(Tokens) ->
- detokenise_pragma(Tokens, []).
-
-detokenise_pragma([], Result) ->
- lists:flatten(Result);
-detokenise_pragma([space], Result) ->
- lists:flatten(Result);
-detokenise_pragma([space|Rem], Result) ->
- detokenise_pragma(Rem, Result++[?space]);
-detokenise_pragma([nl|Rem], Result) ->
- detokenise_pragma(Rem, Result++[$\n]);
-detokenise_pragma([{string, String}|Rem], Result) ->
- detokenise_pragma(Rem, Result++[$"|String]++[$"]);
-detokenise_pragma([{_, String}|Rem], Result) ->
- detokenise_pragma(Rem, Result++[String]).
-
-
-
-
-
-
-
-%%======================================================================================
-%%======================================================================================
-%%======================================================================================
-%% Expand macros.
-%%
-%%
-%% Output: A text file
-%%
-%% Description: Expands all macros. All macro definitions are logged in a list 'Defs'
-%% and all found errors and warnings are logged in a list 'Err' and 'War',
-%% respectively.
-%%
-%% When a macro name is found in a source line it is expanded according
-%% to the current 'Defs'-list. The macro must agree both to the name
-%% and number of parameters, otherwise an error is reported.
-%%======================================================================================
-%%======================================================================================
-%%======================================================================================
-
-
-expand(List, FileName, IncDir, Flags) ->
- %% Get all definitions from preprocessor commnads
- %% and merge them on top of the file collected.
- CLDefs = get_cmd_line_defs(Flags),
- expand(List, [], [], CLDefs, [FileName], IncDir, #mio{}, check_all, [], [], 1, FileName).
-
-expand(List, Defs, Err, War, [FileName|IncFile], IncDir, Mio) ->
- expand(List, [], [], Defs, [FileName|IncFile], IncDir, Mio, check_all, Err, War, 1, FileName).
-
-%%=======================================================
-%% Main loop for the expansion
-%%=======================================================
-expand([], Out, _SelfRef, Defs, _IncFile, _IncDir, Mio, IfCou, Err, War, _L, _FN) ->
-% io:format("~n ===============~n"),
-% io:format(" definitions ~p~n",[lists:reverse(Defs)]),
-% io:format(" found warnings ~p~n",[lists:reverse(War)]),
-% io:format(" found errors ~p~n",[lists:reverse(Err)]),
-% io:format(" ===============~n~n~n"),
- {Out, Err, War, Defs, Mio, IfCou};
-
-expand([{file_info, Str} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
- expand(Rem, Str++Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN);
-
-%%---------------------------------------
-%% Searching for endif,
-%% i.e skip all source lines until matching
-%% end if is encountered
-%%---------------------------------------
-expand([{command,Command} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, {endif, Endif, IfLine}, Err, War, L, FN)
- when Command == "ifdef" ->
- {_Removed, Rem2, _Nl} = read_to_nl(Rem),
- IfCou2 = {endif, Endif+1, IfLine},
- expand(Rem2, Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou2, Err, War, L, FN);
-
-
-expand([{command,Command} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, {endif, Endif, IfLine}, Err, War, L, FN)
- when Command == "ifndef" ->
- {_Removed, Rem2, _Nl} = read_to_nl(Rem),
- IfCou2 = {endif, Endif+1, IfLine},
- expand(Rem2, Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou2, Err, War, L, FN);
-
-
-expand([{command,Command} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, {endif, Endif, IfLine}, Err, War, L, FN)
- when Command == "if" ->
- case pp_command(Command, Rem, Defs, IncDir, Mio, Err, War, L, FN) of
- {{'if', true}, Rem2, Err2, War2, Nl} ->
- IfCou2 = {endif, Endif+1, IfLine},
- expand(Rem2, Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou2, Err2, War2, L+Nl, FN);
-%% {{'if', false}, Rem2, Err2, War2, Nl} -> Not implemented yet
- {{'if', error}, Rem2, Err2, War2, Nl} ->
- IfCou2 = {endif, Endif, IfLine},
- expand(Rem2, Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou2, Err2, War2, L+Nl, FN)
- end;
-
-expand([{command,Command} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, {endif, Endif, IfLine}, Err, War, L, FN)
- when Command == "endif" ->
- {_Removed, Rem2, Nl} = read_to_nl(Rem),
- case Endif of
- 1 ->
- Out2 = lists:duplicate(Nl,$\n) ++ Out,
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio, check_all, Err, War, L+Nl, FN);
- _ ->
- IfCou2 = {endif, Endif-1, IfLine},
- expand(Rem2, Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou2, Err, War, L+Nl, FN)
- end;
-
-
-expand([{command,_Command} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, {endif, Endif, IfLine}, Err, War, L, FN) ->
- {_Removed, Rem2, _Nl} = read_to_nl(Rem),
- IfCou2 = {endif, Endif, IfLine},
- expand(Rem2, Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou2, Err, War, L, FN);
-
-%% Solves a bug when spaces in front of hashmark !
-expand([space | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, {endif, Endif, IfLine}, Err, War, L, FN) ->
- expand(Rem, Out, SelfRef, Defs, IncFile, IncDir, Mio, {endif, Endif, IfLine}, Err, War, L, FN);
-
-expand([{nl,_Nl} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, {endif, Endif, IfLine}, Err, War, L, FN) ->
- expand(Rem, Out, SelfRef, Defs, IncFile, IncDir, Mio, {endif, Endif, IfLine}, Err, War, L, FN);
-
-
-expand([_X | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, {endif, Endif, IfLine}, Err, War, L, FN) ->
- {_Removed, Rem2, Nl} = read_to_nl(Rem),
- Out2 = lists:duplicate(Nl,$\n) ++ Out,
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio, {endif, Endif, IfLine}, Err, War, L, FN);
-
-
-
-
-
-%%---------------------------------------
-%% Check all tokens
-%%---------------------------------------
-expand([{nl, _N} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
- expand(Rem, [$\n | Out], SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L+1, FN);
-
-expand([space | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
- expand(Rem, [?space | Out], SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN);
-
-expand([space_exp | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
- expand(Rem, [?space | Out], SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN);
-
-expand([{command,Command} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, check_all, Err, War, L, FN) ->
- case pp_command(Command, Rem, Defs, IncDir, Mio, Err, War, L, FN) of
- {define, Rem2, Defs2, Err2, War2, Nl} ->
- Out2 = lists:duplicate(Nl,$\n) ++ Out,
- expand(Rem2, Out2, SelfRef, Defs2, IncFile, IncDir, update_mio(Mio), check_all, Err2, War2, L+Nl, FN);
-
- {undef, Rem2, Defs2, Err2, War2, Nl} ->
- Out2 = lists:duplicate(Nl,$\n) ++ Out,
- expand(Rem2, Out2, SelfRef, Defs2, IncFile, IncDir, update_mio(Mio), check_all, Err2, War2, L+Nl, FN);
-
- {{include, ok}, FileName, FileCont, Rem2, Nl, Err2, War2} ->
- {Out3, Defs3, Err3, War3, Mio2} =
- run_include(FileName, FileCont, Out, Defs, Err2, War2, L+Nl, IncFile, IncDir, Mio),
- Nls = [],
- Out4 = Out3++Nls++Out,
- expand(Rem2, Out4, SelfRef, Defs3, IncFile, IncDir, Mio2, check_all, Err3, War3, L+Nl, FN);
-
- {{include, error}, Rem2, Nl, Err2, War2} ->
- Out2 = lists:duplicate(Nl,$\n) ++ Out,
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, update_mio(Mio), check_all, Err2, War2, L+Nl, FN);
-
- {{include, skip}, Rem2} ->
- Out2 = [$\n|Out],
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, update_mio(Mio), check_all, Err, War, L+1, FN);
-
- {{ifdef, true}, Rem2, Err2, War2, Nl} ->
- Out2 = lists:duplicate(Nl,$\n) ++ Out,
- IfCou2 = {endif, 1, L},
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio, IfCou2, Err2, War2, L+Nl, FN);
- {{ifdef, false}, Rem2, Err2, War2, Nl} ->
- Out2 = lists:duplicate(Nl,$\n) ++ Out,
- Mio2 = update_mio(ifdef, Mio),
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio2, check_all, Err2, War2, L+Nl, FN);
-
- {{ifndef, true}, Rem2, Err2, War2, Nl} ->
- Out2 = lists:duplicate(Nl,$\n) ++ Out,
- IfCou2 = {endif, 1, L},
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio, IfCou2, Err2, War2, L+Nl, FN);
- {{ifndef, false}, Macro, Rem2, Err2, War2, Nl} ->
- Out2 = lists:duplicate(Nl,$\n) ++ Out,
- Mio2 = update_mio({ifndef, Macro}, Mio),
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio2, check_all, Err2, War2, L+Nl, FN);
-
- {endif, Rem2, Err2, War2, Nl} ->
- Out2 = lists:duplicate(Nl,$\n) ++ Out,
- Mio2 = update_mio(endif, Mio),
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio2, check_all, Err2, War2, L+Nl, FN);
-
- {{'if', true}, Rem2, Err2, War2, Nl} ->
- Out2 = lists:duplicate(Nl,$\n) ++ Out,
- IfCou2 = {endif, 1, L},
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio, IfCou2, Err2, War2, L+Nl, FN);
-%% {{'if', false}, Removed, Rem2, Nl} -> Not implemented at present
- {{'if', error}, Rem2, Err2, War2, Nl} ->
- Out2 = lists:duplicate(Nl,$\n) ++ Out,
- Mio2 = update_mio('if', Mio),
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio2, check_all, Err2, War2, L+Nl, FN);
-
- {'else', {_Removed, Rem2, Nl}} ->
- Out2 = lists:duplicate(Nl,$\n) ++ Out,
- Err2 = {FN, L, "`else' command is not implemented at present"},
- Mio2 = update_mio('else', Mio),
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio2, check_all, [Err2|Err], War, L+Nl, FN);
-
- {'elif', {_Removed, Rem2, Nl}} ->
- Out2 = lists:duplicate(Nl,$\n) ++ Out,
- Err2 = {FN, L, "`elif' command is not implemented at present"},
- Mio2 = update_mio('elif', Mio),
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio2, check_all, [Err2|Err], War, L+Nl, FN);
-
- {warning, {WarningText, Rem2, Nl}} ->
- [FileName|_More] = IncFile,
- War2 = {FileName, L, "warning: #warning "++detokenise(WarningText)},
- Out2 = lists:duplicate(Nl,$\n) ++ Out,
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, update_mio(Mio), check_all, Err, [War2|War], L+Nl, FN);
-
- {error, {ErrorText, Rem2, Nl}} ->
- [FileName|_More] = IncFile,
- Err2 = {FileName, L, detokenise(ErrorText)},
- Out2 = lists:duplicate(Nl,$\n) ++ Out,
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, update_mio(Mio), check_all, [Err2|Err], War, L+Nl, FN);
-
- {{line, ok}, {_Removed, Rem2, Nl}, L2, FN2, LineText} ->
- Out2 = lists:duplicate(Nl,$\n)++LineText++Out,
- [_X|IF] = IncFile,
- IncFile2 = [FN2|IF],
- expand(Rem2, Out2, SelfRef, Defs, IncFile2, IncDir, update_mio(Mio), check_all, Err, War, L2, FN2);
- {{line, error}, {_Removed, Rem2, Nl}, Err2} ->
- Out2 = lists:duplicate(Nl,$\n) ++ Out,
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, update_mio(Mio), check_all, [Err2|Err], War, L+Nl, FN);
-
- hash_mark ->
- expand(Rem, Out, SelfRef, Defs, IncFile, IncDir, Mio, check_all, Err, War, L, FN);
-
- {pragma, Rem2, Nl, Text} ->
- Out2 = lists:duplicate(Nl,$\n)++Text++Out,
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, update_mio(Mio), check_all, Err, War, L+Nl, FN);
-
- {ident, Rem2, Nl, Text} ->
- Out2 = lists:duplicate(Nl,$\n)++Text++Out,
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, update_mio(Mio), check_all, Err, War, L+Nl, FN);
-
- {not_recognised, {Removed, Rem2, Nl}} ->
- Text = lists:reverse([$#|Command]),
- RemovedS = lists:reverse([?space|detokenise(Removed)]),
- Out2 = [$\n|RemovedS]++Text++Out,
- Mio2 = update_mio(Mio),
- case Command of
- [X|_T] when ?is_upper(X) ->
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio2, check_all, Err, War, L+Nl, FN);
- [X|_T] when ?is_lower(X) ->
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio2, check_all, Err, War, L+Nl, FN);
- [X|_T] when ?is_underline(X) ->
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio2, check_all, Err, War, L+Nl, FN);
- _ ->
- Err2 = {FN, L, "invalid preprocessing directive name"},
- expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, Mio2, check_all, [Err2|Err], War, L+Nl, FN)
- end;
-
- Else ->
-% io:format(" %%%%Else%%%%%% ~p~n",[Else]),
- exit(Else)
- end;
-
-
-expand([{var, "__LINE__"}|Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
- LL = io_lib:format("~p",[L]),
- expand(Rem, [LL | Out], SelfRef, Defs, IncFile, IncDir, update_mio(Mio), IfCou, Err, War, L, FN);
-
-expand([{var, "__FILE__"}|Rem], Out, SelfRef, Defs, IncFile, Mio, IncDir, IfCou, Err, War, L, FN) ->
- expand(Rem, [$",FN,$" | Out], SelfRef, Defs, IncFile, IncDir, update_mio(Mio), IfCou, Err, War, L, FN);
-
-expand([{var, "__DATE__"}|Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
- {{Y,M,D},{_H,_Mi,_S}} = calendar:universal_time(),
- Date = io_lib:format("\"~s ~p ~p\"",[month(M),D,Y]),
- expand(Rem, [Date | Out], SelfRef, Defs, IncFile, IncDir, update_mio(Mio), IfCou, Err, War, L, FN);
-
-expand([{var, "__TIME__"}|Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
- {{_Y,_M,_D},{H,Mi,S}} = calendar:universal_time(),
- HS = if H < 10 -> "0"++integer_to_list(H);
- true -> integer_to_list(H)
- end,
- MiS = if Mi < 10 -> "0"++integer_to_list(Mi);
- true -> integer_to_list(Mi)
- end,
- SS = if S < 10 -> "0"++integer_to_list(S);
- true -> integer_to_list(S)
- end,
- Time = io_lib:format("\"~s:~s:~s\"",[HS,MiS,SS]),
- expand(Rem, [Time | Out], SelfRef, Defs, IncFile, IncDir, update_mio(Mio), IfCou, Err, War, L, FN);
-
-expand([{var, "__INCLUDE_LEVEL__"}|Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
- IL = io_lib:format("~p",[length(IncFile)-1]),
- expand(Rem, [IL | Out], SelfRef, Defs, IncFile, IncDir, update_mio(Mio), IfCou, Err, War, L, FN);
-
-expand([{var, "__BASE_FILE__"}|Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
- [BF|_T] = lists:reverse(IncFile),
- expand(Rem, [$",BF,$" | Out], SelfRef, Defs, IncFile, IncDir, update_mio(Mio), IfCou, Err, War, L, FN);
-
-expand([{var, Var} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
- {Out2, Err2, War2, Rem2, SelfRef2} =
- source_line(Var, Rem, SelfRef, Defs, Err, War, L, FN),
- expand(Rem2, [Out2 | Out], SelfRef2, Defs, IncFile, IncDir, update_mio(Mio), IfCou, Err2, War2, L, FN);
-
-expand([{char, Char} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
- expand(Rem, [Char | Out], SelfRef, Defs, IncFile, IncDir, update_mio(Mio), IfCou, Err, War, L, FN);
-
-expand([{number, Number} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
- expand(Rem, [Number | Out], SelfRef, Defs, IncFile, IncDir, update_mio(Mio), IfCou, Err, War, L, FN);
-
-expand([{expanded, Str} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
- expand(Rem, [Str | Out], SelfRef, Defs, IncFile, IncDir, update_mio(Mio), IfCou, Err, War, L, FN);
-
-expand([{self_ref, Str} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
- SelfRef2 = lists:delete(Str,SelfRef),
- expand(Rem, Out, SelfRef2, Defs, IncFile, IncDir, update_mio(Mio), IfCou, Err, War, L, FN);
-
-expand([{string, Str} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
- expand(Rem, [$", Str, $" | Out], SelfRef, Defs, IncFile, IncDir, update_mio(Mio), IfCou, Err, War, L, FN);
-
-expand([{string_part, Str} | Rem], Out, SelfRef, Defs, IncFile, IncDir, Mio, IfCou, Err, War, L, FN) ->
- {Str2, Rem2, Nl} = expand_string_part([$"|Str], Rem),
- expand(Rem2, [Str2| Out], SelfRef, Defs, IncFile, IncDir, update_mio(Mio), IfCou, Err, War, L+Nl, FN).
-
-
-
-
-
-
-
-
-%%========================================================================
-%% Expand a line starting as a partial string
-%%========================================================================
-expand_string_part(Str, File) ->
- expand_string_part(File, Str, 0).
-
-expand_string_part([{string, Str_part} | Rem], Str, Nl) ->
- {Str++Str_part++[$"], Rem, Nl};
-expand_string_part([space | Rem], Str, Nl) ->
- expand_string_part(Rem, Str, Nl);
-expand_string_part([nl| Rem], Str, Nl) ->
- expand_string_part(Rem, Str++[$\n], Nl);
-expand_string_part([{string_part, Str_part} | Rem], Str, Nl) ->
- expand_string_part(Rem, Str++Str_part, Nl).
-
-
-
-
-
-%%========================================================================
-%% Parse and integrate command line macro directives
-%% At this momment, only -D and -U are supported (gcc like)
-%%========================================================================
-
-
-%% Collect all command line macro definitions
-get_cmd_line_defs(Flags) ->
- Adjusted = parse_cmd_line(Flags,[]),
-
- {_Out, _Err, _War, Defs, _IfCou, _Mio} =
- expand(tokenise(Adjusted,""),
- [],
- [],
- [],
- [],
- [],
- #mio{},
- check_all,
- [],
- [],
- 1,
- ""),
- Defs.
-
-%% Parse command line macros
-parse_cmd_line([],Found) ->
- lists:flatten(lists:reverse(Found));
-
-parse_cmd_line([45,68|Rest],Found) ->
- {Collected,RestCmds} = collect_define(Rest,[]),
- parse_cmd_line(RestCmds,[Collected|Found]);
-
-parse_cmd_line([45,85|Rest],Found) ->
- {Collected,RestCmds} = collect_undefine(Rest,[]),
- parse_cmd_line(RestCmds,[Collected|Found]);
-
-parse_cmd_line([_|Rest],Found) ->
- parse_cmd_line(Rest,Found).
-
-
-%% Collect defines and translate them
-%% into a text format
-collect_define([],Found) ->
- { "#define "++lists:reverse(Found)++"\n", [] };
-collect_define([32|Rest],Found) ->
- { "#define "++lists:reverse(Found)++"\n", Rest };
-collect_define([61|Rest],[]) ->
- { "", Rest };
-collect_define([61|Rest],Found) ->
- collect_define(Rest,[32|Found]);
-collect_define([C|Rest],Found) ->
- collect_define(Rest,[C|Found]).
-
-
-%% Collect undefines and translate them
-%% into a text format
-collect_undefine([],Found) ->
- { "#undef "++lists:reverse(Found)++"\n", [] };
-collect_undefine([32|Rest],Found) ->
- { "#undef "++lists:reverse(Found)++"\n", Rest };
-collect_undefine([C|Rest],Found) ->
- collect_undefine(Rest,[C|Found]).
-
-
-
-
-
-
-
-
-
-
-
-
-%%======================================================================================
-%%======================================================================================
-%%======================================================================================
-%% Read a preprocessor command
-%%
-%%
-%% Output: Depending of the command, typically = {Command, Rem, Err, War, Nl}
-%%
-%%======================================================================================
-%%======================================================================================
-%%======================================================================================
-
-pp_command(Command, [space|File], Defs, IncDir, Mio, Err, War, L, FN) ->
- pp_command(Command, File, Defs, IncDir, Mio, Err, War, L, FN);
-
-pp_command(Command, File, Defs, IncDir, Mio, Err, War, L, FN) ->
-
- case Command of
- %%----------------------------------------
- %% #define
- %%----------------------------------------
- "define" ->
- case define(File, Err, War, L, FN) of
- {error, Rem, Err2, War2, Nl} ->
- {define, Rem, Defs, Err2, War2, Nl};
- {warning, Rem, Name, No_of_para, Parameters, Macro, Err2, War2, Nl} ->
- case is_define_ok(Name, No_of_para, Parameters, Macro, Defs) of
- {yes, Defs2} ->
- {define, Rem, Defs2, Err2, War2, Nl};
- {no, Defs2} ->
- Text = lists:flatten(io_lib:format("`~s' redefined",[Name])),
- {define, Rem, Defs2, Err2, [{FN, L, Text}|War2], Nl};
- {error, Text, Defs2} ->
- {define, Rem, Defs2, [{FN, L, Text}|Err2], War2, Nl}
- end;
- {ok, Rem, Name, No_of_para, Parameters, Macro, Err2, War2, Nl} ->
- case is_define_ok(Name, No_of_para, Parameters, Macro, Defs) of
- {yes, Defs2} ->
- {define, Rem, Defs2, Err2, War2, Nl};
- {no, Defs2} ->
- Text = lists:flatten(io_lib:format("`~s' redefined",[Name])),
- {define, Rem, Defs2, Err2, [{FN, L, Text}|War2], Nl};
- {error, Text, Defs2} ->
- {define, Rem, Defs2, [{FN, L, Text}|Err2], War2, Nl}
- end
- end;
-
- %%----------------------------------------
- %% #undef
- %%----------------------------------------
- "undef" ->
- case undef(File, Err, War, L, FN) of
- {error, Rem, Err2, War2, Nl} ->
- {undef, Rem, Defs, Err2, War2, Nl};
- {ok, Rem, Name, Err2, War2, Nl} ->
- Defs2 = lists:keydelete(Name, 1, Defs),
- {undef, Rem, Defs2, Err2, War2, Nl}
- end;
-
- %%----------------------------------------
- %% #include
- %%----------------------------------------
- "include" ->
- case include(File, IncDir, Mio) of
- {error, Rem, Nl, Err2} ->
- {{include, error}, Rem, Nl, [{FN, L, Err2}|Err], War};
- {error, Rem, Nl, Err2, NameNl} ->
- {{include, error}, Rem, Nl, [{FN, L+ NameNl, Err2}|Err], War};
- {ok, FileNamePath, FileCont, Rem, Nl} ->
- {{include, ok}, FileNamePath, FileCont, Rem, Nl, Err, War};
- {skip, Rem} ->
- {{include, skip}, Rem}
- end;
-
- %%----------------------------------------
- %% #ifdef
- %%----------------------------------------
- "ifdef" ->
- case define(File, Err, War, L, FN) of
- {error, Rem, Err2, War2, Nl} ->
- {{ifdef, false}, Rem, Defs, Err2, War2, Nl};
- {warning, Rem, Name, No_of_para, _Parameters, _Macro, Err2, War2, Nl} ->
- case is_defined_before(Name, No_of_para, Defs) of
- yes ->
- {{ifdef, false}, Rem, Err2, War2, Nl};
- no ->
- {{ifdef, true}, Rem, Err2, War2, Nl}
- end;
- {ok, Rem, Name, No_of_para, _Parameters, _Macro, Err2, War2, Nl} ->
- case is_defined_before(Name, No_of_para, Defs) of
- yes ->
- {{ifdef, false}, Rem, Err2, War2, Nl};
- no ->
- {{ifdef, true}, Rem, Err2, War2, Nl}
- end
- end;
-
-
-
- %%----------------------------------------
- %% #ifndef
- %%----------------------------------------
- "ifndef" ->
- case define(File, Err, War, L, FN) of
- {error, Rem, Err2, War2, Nl} ->
- {{ifndef, false}, Rem, Defs, Err2, War2, Nl};
- {warning, Rem, Name, No_of_para, _Parameters, _Macro, Err2, War2, Nl} ->
- case is_defined_before(Name, No_of_para, Defs) of
- yes ->
- {{ifndef, true}, Rem, Err2, War2, Nl};
- no ->
- {{ifndef, false}, Name, Rem, Err2, War2, Nl}
- end;
- {ok, Rem, Name, No_of_para, _Parameters, _Macro, Err2, War2, Nl} ->
- case is_defined_before(Name, No_of_para, Defs) of
- yes ->
- {{ifndef, true}, Rem, Err2, War2, Nl};
- no ->
- {{ifndef, false}, Name, Rem, Err2, War2, Nl}
- end
- end;
-
-
- %%----------------------------------------
- %% #endif
- %%----------------------------------------
- "endif" ->
- {Removed, Rem, Nl} = read_to_nl(File),
- case Removed of
- [] ->
- {endif, Rem, Err, War, 1};
- _ ->
- Text = "ignoring the tail of the line",
- {ok, Rem, Err, [{FN, L, Text}|War], Nl}
- end;
-
-
- %%----------------------------------------
- %% #if
- %%----------------------------------------
- "if" ->
- case if_zero(File, Err, War, L, FN) of
- {error, Rem2, _Removed, Nl} ->
- Err2 = {FN, L, "only '#if 0' is implemented at present"},
- {{'if', error}, Rem2, [Err2 | Err], War, Nl};
- {ok, Rem2, 0, _Removed, Nl} ->
- {{'if', true}, Rem2, Err, War, Nl};
- {ok, Rem2, _Num, _Removed, Nl} ->
- Err2 = {FN, L, "only '#if 0' is implemented at present"},
- {{'if', error}, Rem2, [Err2 | Err], War, Nl}
- end;
-
- %%----------------------------------------
- %% #else
- %%----------------------------------------
- "else" ->
- {'else', read_to_nl(File)};
-
- %%----------------------------------------
- %% #elif
- %%----------------------------------------
- "elif" ->
- {'elif', read_to_nl(File)};
-
- %%----------------------------------------
- %% #pragma
- %%----------------------------------------
- "pragma" ->
- {Removed, Rem, Nl} = read_to_nl(File),
- {pragma, Rem, Nl, lists:reverse("#pragma " ++ detokenise_pragma(Removed))};
-
- %%----------------------------------------
- %% #ident
- %%----------------------------------------
- "ident" ->
- {Removed, Rem, Nl} = read_to_nl(File),
- {ident, Rem, Nl, lists:reverse("#ident " ++ detokenise_pragma(Removed))};
-
- %%----------------------------------------
- %% #warning
- %%----------------------------------------
- "warning" ->
- {warning, read_to_nl(File)};
-
- %%----------------------------------------
- %% #error
- %%----------------------------------------
- "error" ->
- {error, read_to_nl(File)};
-
- %%----------------------------------------
- %% #line
- %%----------------------------------------
- "line" ->
- line(File, L, FN);
-
- %%----------------------------------------
- %% #
- %%----------------------------------------
- "null" ->
- hash_mark;
-
- %%----------------------------------------
- %% not recognised preprocessor commands
- %%----------------------------------------
- _Else ->
- {not_recognised, read_to_nl(File)}
- end.
-
-
-
-
-%%===============================================================
-%%===============================================================
-%%===============================================================
-%% if
-%%
-%% Only #if 0 is implemented at the time to be able to use if
-%% to comment some code parts.
-%%===============================================================
-%%===============================================================
-%%===============================================================
-
-if_zero(File, _Err, _War, _L, _FN) ->
- case if_zero(File) of
- {ok, Remain, Num, Removed, Nl} ->
- case catch list_to_integer(Num) of
- {'EXIT', _} ->
- {Removed2, Rem2, Nl2} = read_to_nl(File),
- {error, Rem2, Removed2, Nl2};
- Int ->
- {ok, Remain, Int, Removed, Nl}
- end;
- E ->
- E
- end.
-
-if_zero([{number,Num}]) ->
- {ok, [], Num, [], 0};
-if_zero([{number,Num}, space]) ->
- {ok, [], Num, [], 0};
-if_zero([{number,Num} | Rem]) ->
- {Removed, Rem2, Nl} = read_to_nl(Rem),
- {ok, Rem2, Num, Removed, Nl};
-%if_zero([{number,Num}, {nl,_X} | Rem]) ->
-% {ok, Rem, Num, [], 1};
-if_zero(Rem) ->
- {Removed, Rem2, Nl} = read_to_nl(Rem),
- {error, Rem2, Removed, Nl}.
-
-
-
-%%===============================================================
-%%===============================================================
-%%===============================================================
-%% Define macro
-%%
-%% Check the syntax of the macro, extract the parameters if any.
-%% If valid macro it is added to the Defs-list.
-%% If a macro is redefined, a warning will be given, the latest
-%% definition is always the valid one.
-%%===============================================================
-%%===============================================================
-%%===============================================================
-
-define(File, Err, War, L, FN) ->
- case define_name(File) of
- {ok, Rem, Name, No_of_para, Parameters, Macro, Nl} ->
- {ok, Rem, Name, No_of_para, Parameters, Macro, Err, War, Nl};
- {{warning,no_space}, Rem, Name, No_of_para, Parameters, Macro, Nl} ->
- Text = lists:flatten(io_lib:format("missing white space after `#define ~s'",[Name])),
- {warning, Rem, Name, No_of_para, Parameters, Macro, Err, [{FN, L, Text}|War], Nl};
- {error, invalid_name, Nl} ->
- Text = "invalid macro name",
- {_Removed, Rem, Nl2} = read_to_nl(File),
- {error, Rem, [{FN, L, Text}|Err], War, Nl+Nl2};
- {error, invalid_name, Name, Nl} ->
- Text = lists:flatten(io_lib:format("invalid macro name `~s'",[Name])),
- {_Removed, Rem, Nl2} = read_to_nl(File),
- {error, Rem, [{FN, L, Text}|Err], War, Nl+Nl2};
- {error, illegal_arg} ->
- {Removed, Rem, Nl} = read_to_nl(File),
- RemovedS = detokenise(Removed),
- Text = lists:flatten(io_lib:format("Invalid argument list ~s",[RemovedS])),
- {error, Rem, [{FN, L, Text}|Err], War, Nl}
- end.
-
-
-
-%%===========================================================
-%% Check if valid macro
-%%===========================================================
-define_name([]) ->
- {warning, no_macro};
-define_name([space]) ->
- {warning, no_macro};
-%% Macro with parameters
-define_name([{var,Name},{char,$(}|Rem]) ->
- case read_para([{char,$(}|Rem]) of
- {ok, Rem2, Para, NoOfPara} ->
- {Removed, Rem3, _Nl} = read_to_nl(Rem2),
- {ok, Rem3, Name, NoOfPara, Para, Removed, 1};
- Error ->
- Error
- end;
-%% Macro without parameters
-define_name([{var,Name}]) ->
- {ok, [], Name, 0, [], [], 0};
-define_name([{var,Name}, space | Rem]) ->
- {Removed, Rem2, Nl} = read_to_nl(Rem),
- {ok, Rem2, Name, 0, [], Removed, Nl};
-define_name([{var,Name}, {nl,_X} | Rem]) ->
- {ok, Rem, Name, 0, [], [], 1};
-define_name([{var,Name} | Rem]) ->
- {Removed, Rem2, Nl} = read_to_nl(Rem),
- {{warning,no_space}, Rem2, Name, 0, [], Removed, Nl};
-%% Invalid macro name
-define_name([{number, Name} | _Rem]) ->
- {error, invalid_name, Name, 0};
-define_name(_Rem) ->
- {error, invalid_name, 0}.
-
-
-
-
-
-
-
-%%===============================================================
-%%===============================================================
-%%===============================================================
-%% Undefine macro
-%%
-%% If it is a valid undef command the macro name will be deleted
-%% from the Defs-list
-%%===============================================================
-%%===============================================================
-%%===============================================================
-
-undef(File, Err, War, L, FN) ->
- case undef(File) of
- {ok, Rem, Name, Nl} ->
- {ok, Rem, Name, Err, War, Nl};
- {warning, Rem, Name, Nl} ->
- Text = "ignoring the tail of the line",
- {ok, Rem, Name, Err, [{FN, L, Text}|War], Nl};
- {error, invalid_name} ->
- Text = "invalid macro name",
- {_Removed, Rem, Nl} = read_to_nl(File),
- {error, Rem, [{FN, L, Text}|Err], War, Nl};
- {error, invalid_name, Name} ->
- Text = lists:flatten(io_lib:format("invalid macro name `~s'",[Name])),
- {_Removed, Rem, Nl} = read_to_nl(File),
- {error, Rem, [{FN, L, Text}|Err], War, Nl}
- end.
-
-%%-------------------------------------------------
-%% Check if valid macro name
-%%-------------------------------------------------
-undef([]) ->
- {error, invalid_name, []};
-%% Valid name
-undef([{var,Name}]) ->
- {ok, [], Name, 0};
-undef([{var,Name}, {nl,_X} | Rem]) ->
- {ok, Rem, Name, 1};
-undef([{var,Name}, space, {nl,_X} | Rem]) ->
- {ok, Rem, Name, 1};
-undef([{var,Name} | Rem]) ->
- {_Removed, Rem2, Nl} = read_to_nl(Rem),
- {warning, Rem2, Name, Nl};
-%% Invalid macro name
-undef([{number, Name} | _Rem]) ->
- {error, invalid_name, Name};
-undef(_Rem) ->
- {error, invalid_name}.
-
-
-
-
-
-
-%%===============================================================
-%%===============================================================
-%%===============================================================
-%% Include macro
-%%
-%% Read the included file
-%%===============================================================
-%%===============================================================
-%%===============================================================
-
-include(File, IncDir, Mio) ->
- case include2(File) of
- {ok, FileName, Rem, Nl, FileType} ->
- Result = read_inc_file(FileName, IncDir, Mio),
- case {Result, Nl, FileType} of
- {{ok, FileNamePath, FileCont}, _, _} ->
- {ok, FileNamePath, FileCont, Rem, Nl};
- {skip, _, _} ->
- {skip, Rem};
- {{error, Text}, _, own_file} ->
- NameNl = count_nl(FileName,0),
- Error = lists:flatten(io_lib:format("~s: ~s",[FileName,Text])),
- {error, Rem, Nl, Error, NameNl};
- {{error, Text}, 1, sys_file} ->
- NameNl = count_nl(FileName,0),
- Error = lists:flatten(io_lib:format("~s: ~s",[FileName,Text])),
- {error, Rem, Nl, Error, NameNl};
- {{error, _Text}, _, sys_file} ->
- {error, Rem, Nl, "`#include' expects \"FILENAME\" or <FILENAME>"}
- end;
- {error, {_Removed, Rem, Nl}} ->
- {error, Rem, Nl, "`#include' expects \#FILENAME\" or <FILENAME>"}
- end.
-
-
-
-count_nl([],Nl) ->
- Nl;
-count_nl([$\n|T],Nl) ->
- count_nl(T,Nl+1);
-count_nl([_H|T],Nl) ->
- count_nl(T,Nl).
-
-%%=================================================
-%% Extract the file name from the token list
-%%=================================================
-include2([space|Rem]) ->
- include2(Rem);
-
-include2([{string, FileName}]) ->
- {ok, FileName, [], 1, own_file};
-include2([{string, FileName}, space]) ->
- {ok, FileName, [], 1, own_file};
-include2([{string, FileName}, {nl, _X} | Rem]) ->
- {ok, FileName, Rem, 1, own_file};
-include2([{string, FileName}, space, {nl, _X} | Rem]) ->
- {ok, FileName, Rem, 1, own_file};
-include2([{string, _FileName}, _No_nl | Rem]) ->
- {error, read_to_nl(Rem)};
-include2([{string_part, File_part}, {nl, _X} | Rem]) ->
- case include_read_string_file_name(File_part++[$\n], Rem, 1) of
- {ok, FileName, Rem2, Nl} ->
- {ok, FileName, Rem2, Nl, own_file};
- error ->
- {error, read_to_nl([{string_part,File_part} | Rem])}
- end;
-include2([{sys_head, FileName}]) ->
- {ok, FileName, [], 1, sys_file};
-include2([{sys_head, FileName}, space]) ->
- {ok, FileName, [], 1, sys_file};
-include2([{sys_head, FileName}, {nl, _X} | Rem]) ->
- {ok, FileName, Rem, 1, sys_file};
-include2([{sys_head, FileName}, space, {nl, _X} | Rem]) ->
- {ok, FileName, Rem, 1, sys_file};
-include2([{sys_head, _FileName}, _No_nl | Rem]) ->
- {error, read_to_nl(Rem)};
-include2([{sys_head_part ,File_part}, {nl, _X} | Rem]) ->
- case include_read_sys_file_name(File_part++[$\n], Rem, 1) of
- {ok, FileName, Rem2, Nl} ->
- {ok, FileName, Rem2, Nl, sys_file};
- error ->
- {error, read_to_nl([{sys_head_part, File_part} | Rem])}
- end;
-include2(Rem) ->
- {error, read_to_nl(Rem)}.
-
-
-
-%%-------------------------------------------------
-%% File name framed by " "
-%%-------------------------------------------------
-include_read_string_file_name(File, [{string, File_part}, {nl,_X} | Rem], Nl) ->
- {ok, File++File_part, Rem, Nl+1};
-include_read_string_file_name(File, [{string_part, File_part}, {nl,_X} | Rem], Nl) ->
- include_read_string_file_name(File++File_part++[$\n], Rem, Nl+1);
-include_read_string_file_name(_File, _X, _Nl) ->
- error.
-
-%%-------------------------------------------------
-%% File name framed by < >
-%%-------------------------------------------------
-include_read_sys_file_name(File, [{sys_head, File_part}, {nl,_X} | Rem], Nl) ->
- {ok, File++File_part, Rem, Nl+1};
-include_read_sys_file_name(File, [{sys_head_part, File_part}, {nl,_X} | Rem], Nl) ->
- include_read_sys_file_name(File++File_part++[$\n], Rem, Nl+1);
-include_read_sys_file_name(_File, _X, _Nl) ->
- error.
-
-
-
-
-
-
-
-%%===============================================================
-%%===============================================================
-%%===============================================================
-%% Line macro
-%%
-%% The line macro may redefine both the current line number and
-%% the current file name: #line ' new_line_nr' 'new_file_name'
-%%===============================================================
-%%===============================================================
-%%===============================================================
-
-line(File, L, FN) ->
- line(File, L, FN, not_defined, not_defined).
-
-
-
-line([], L, FN, _Line, _File) ->
- {{line, error}, {[],[],0}, {FN,L,"invalid format `#line' directive"}};
-
-line([space|Rem], L, FN, Line, File) ->
- line(Rem, L, FN, Line, File);
-
-%%------------------------------
-%% Line number expected
-%%------------------------------
-line([{number,Number}|Rem], L, FN, not_defined, File) ->
- case catch list_to_integer(Number) of
- {'EXIT', _} ->
- {{line, error}, read_to_nl(Rem), {FN,L,"invalid format `#line' directive"}};
- Int ->
- line(Rem, L, FN, Int, File)
- end;
-line(Rem, L, FN, not_defined, _File) ->
- {{line, error}, read_to_nl(Rem), {FN,L,"invalid format `#line' directive"}};
-
-%%------------------------------
-%% File name or newline expected
-%%------------------------------
-line([{nl, _NL}|Rem], _L, FN, Line, not_defined) ->
- {{line, ok}, {[],Rem,1}, Line, FN, io_lib:format("~n~p ~p #",[FN, Line-1])};
-line([{string,NewFN}|Rem], _L, _FN, Line, not_defined) ->
- {{line, ok}, read_to_nl(Rem), Line, NewFN, io_lib:format("~n~p ~p #",[NewFN, Line-1])};
-line(Rem, L, FN, _Line, _File) ->
- {{line, error}, read_to_nl(Rem), {FN,L,"invalid format `#line' directive"}}.
-
-
-
-
-%%======================================================================================
-%%======================================================================================
-%%======================================================================================
-%% Source line
-%%
-%%
-%% Output: {Str, Err, War, Rem, SelfRef}
-%%
-%% Description: The input source line is searched for macros. If a macro is found it
-%% is expanded. The result of an expansion is rescanned for more macros.
-%% To prevent infinite loops if the macro is self referring
-%% an extra token is put into the Rem list. The variable SelfRef
-%% contains all the macros which are inhibited to be expanded.
-%% A special specae token is also inserted to prevent not wanted
-%% concatinations if one of the variables to be concatinated is expanded.
-%%======================================================================================
-%%======================================================================================
-%%======================================================================================
-
-source_line(Str, Rem, SelfRef, Defs, Err, War, L, FN) ->
- {Rem2, Para, No_of_para} = case read_para(Rem) of
- {ok, RemT, ParaT, No_of_paraT} ->
- {RemT, ParaT, No_of_paraT};
- {error, illegal_arg} ->
- {[], [], 0}
- end,
-
-
- %%-------------------------------------------------
- %% Check if a valid macro
- %%-------------------------------------------------
- case lists:keysearch(Str, 1, Defs) of
- %% a macro without parameters
- {value, {Str, 0, _MacroPara, Macro}} ->
- case lists:member(Str, SelfRef) of
- true ->
- {[Str], Err, War, Rem, SelfRef};
- false ->
- ExpandedRes2 = sl_mark_expanded(Macro, Str),
- {[], Err, War, ExpandedRes2 ++ [{self_ref,Str}|Rem], [Str|SelfRef]}
- end;
-
- %% a macro with parameters
- {value, {Str, N, _MacroPara, Macro}} when N == No_of_para ->
- case lists:member(Str, SelfRef) of
- true ->
- {[Str], Err, War, Rem, SelfRef};
- false ->
- ExpandedRes = sl_macro_expand(Macro, Para, Defs),
- ExpandedRes2 = sl_mark_expanded(ExpandedRes, Str),
- {[], Err, War, ExpandedRes2 ++ [{self_ref,Str}|Rem2], [Str|SelfRef]}
- end;
-
- %% a variable, because it doesn't have any parameters
- {value, {Str, _N, _MacroPara, _Macro}} when No_of_para == 0 ->
- {Str, Err, War, Rem, SelfRef};
-
- %% illegal no of parameters
- {value, {Str, N, _MacroPara, _Macro}} when No_of_para < N ->
- Text = io_lib:format(" macro `~s' used with just ~p arg",[Str,No_of_para]),
- Err2 = {FN, L, lists:flatten(Text)},
- {Str, [Err2|Err], War, Rem, SelfRef};
- {value, {Str, _N, _MacroPara, _Macro}} ->
- Text = io_lib:format(" macro `~s' used with too many (~p) args",[Str,No_of_para]),
- Err2 = {FN, L, lists:flatten(Text)},
- {Str, [Err2|Err], War, Rem, SelfRef};
-
- %% no macro
- false ->
- {Str, Err, War, Rem, SelfRef}
- end.
-
-
-
-
-
-%%=================================================
-%% Expand a macro
-%%=================================================
-sl_macro_expand(Macro, Para, Defs) ->
- sl_macro_expand(Macro, Para, Defs, []).
-
-
-%%...................
-%% End
-%%...................
-sl_macro_expand([], _Para, _Defs, Res) ->
- lists:reverse(Res);
-
-%%...................
-%% Concatination
-%%...................
-%% para ## para
-sl_macro_expand([{para, N}, space, {char,$#}, {char,$#}, space, {para,M} | T], Para, Defs, Res) ->
- Exp = sl_para_para({para, N},{para, M}, Para),
- sl_macro_expand(Exp++T, Para, Defs, [space |Res]);
-%% para## para
-sl_macro_expand([{para, N}, {char,$#}, {char,$#}, space, {para,M} | T], Para, Defs, Res) ->
- Exp = sl_para_para({para, N},{para, M}, Para),
- sl_macro_expand(Exp++T, Para, Defs, [space |Res]);
-%% para ##para
-sl_macro_expand([{para, N}, space, {char,$#}, {char,$#}, {para,M} | T], Para, Defs, Res) ->
- Exp = sl_para_para({para, N},{para, M}, Para),
- sl_macro_expand(Exp++T, Para, Defs, [space |Res]);
-%% para##para
-sl_macro_expand([{para, N}, {char,$#}, {char,$#}, {para,M} | T], Para, Defs, Res) ->
- Exp = sl_para_para({para, N},{para, M}, Para),
- sl_macro_expand(Exp++T, Para, Defs, [space |Res]);
-
-%% para ## var
-sl_macro_expand([{para, N}, space, {char,$#}, {char,$#}, space, {var, Var}|T], Para, Defs, Res) ->
- Exp = sl_para_var({para, N}, {var, Var}, Para),
- sl_macro_expand(Exp++T, Para, Defs, [space |Res]);
-%% para## var
-sl_macro_expand([{para, N}, {char,$#}, {char,$#}, space, {var, Var} | T], Para, Defs, Res) ->
- [{var, VarN}] = lists:nth(N,Para),
- sl_macro_expand(T, Para, Defs, [{expanded,Var},{expanded,VarN}, space |Res]);
-%% para ##var
-sl_macro_expand([{para, N}, space, {char,$#}, {char,$#}, {var, Var} | T], Para, Defs, Res) ->
- [{var, VarN}] = lists:nth(N,Para),
- sl_macro_expand(T, Para, Defs, [{expanded,Var},{expanded,VarN}, space |Res]);
-%% para##var
-sl_macro_expand([{para, N}, {char,$#}, {char,$#}, {var, Var} | T], Para, Defs, Res) ->
- [{var, VarN}] = lists:nth(N,Para),
- sl_macro_expand(T, Para, Defs, [{expanded,Var},{expanded,VarN}, space |Res]);
-
-%% var ## para
-sl_macro_expand([{var, Var}, space, {char,$#}, {char,$#}, space, {para,M} | T], Para, Defs, Res) ->
- Exp = sl_var_para({var, Var},{para, M}, Para),
- sl_macro_expand(Exp++T, Para, Defs, [space |Res]);
-%% var## para
-sl_macro_expand([{var, Var}, {char,$#}, {char,$#}, space, {para,M} | T], Para, Defs, Res) ->
- Exp = sl_var_para({var, Var},{para, M}, Para),
- sl_macro_expand(Exp++T, Para, Defs, [space |Res]);
-%% var ##para
-sl_macro_expand([{var, Var}, space, {char,$#}, {char,$#}, {para,M} | T], Para, Defs, Res) ->
- Exp = sl_var_para({var, Var},{para, M}, Para),
- sl_macro_expand(Exp++T, Para, Defs, [space |Res]);
-%% var##para
-sl_macro_expand([{var, Var}, {char,$#}, {char,$#}, {para,M} | T], Para, Defs, Res) ->
- Exp = sl_var_para({var, Var},{para, M}, Para),
- sl_macro_expand(Exp++T, Para, Defs, [space |Res]);
-
-%% expanded ## para
-sl_macro_expand([space, {char,$#}, {char,$#}, space, {para,M} | T], Para, Defs, [{expanded, Var}|Res]) ->
- [{var, VarM}] = lists:nth(M,Para),
- sl_macro_expand(T, Para, Defs, [{expanded,VarM},{expanded,Var} |Res]);
-%% expanded## para
-sl_macro_expand([{char,$#}, {char,$#}, space, {para,M} | T], Para, Defs, [{expanded, Var}|Res]) ->
- [{var, VarM}] = lists:nth(M,Para),
- sl_macro_expand(T, Para, Defs, [{expanded,VarM},{expanded,Var} |Res]);
-%% expanded ##para
-sl_macro_expand([space, {char,$#}, {char,$#}, {para,M} | T], Para, Defs, [{expanded, Var}|Res]) ->
- [{var, VarM}] = lists:nth(M,Para),
- sl_macro_expand(T, Para, Defs, [{expanded,VarM},{expanded,Var} |Res]);
-%% expanded##para
-sl_macro_expand([{char,$#}, {char,$#}, {para,M} | T], Para, Defs, [{expanded, Var}|Res]) ->
- [{var, VarM}] = lists:nth(M,Para),
- sl_macro_expand(T, Para, Defs, [{expanded,VarM},{expanded,Var} |Res]);
-
-%% para ## ?
-sl_macro_expand([{para, N}, space, {char,$#}, {char,$#}, space, X | T], Para, Defs, Res) ->
- Reexp = sl_macro_reexpand(lists:nth(N,Para), Defs, []),
- sl_macro_expand([X, space|T], Para, Defs, lists:flatten([Reexp, space|Res]));
-%% para## ?
-sl_macro_expand([{para, N}, {char,$#}, {char,$#}, space, X | T], Para, Defs, Res) ->
- Reexp = sl_macro_reexpand(lists:nth(N,Para), Defs, []),
- sl_macro_expand([X, space|T], Para, Defs, lists:flatten([Reexp, space|Res]));
-%% para ##?
-sl_macro_expand([{para, N}, space, {char,$#}, {char,$#}, X | T], Para, Defs, Res) ->
- Reexp = sl_macro_reexpand(lists:nth(N,Para), Defs, []),
- sl_macro_expand([X, space|T], Para, Defs, lists:flatten([Reexp, space|Res]));
-%% para##?
-sl_macro_expand([{para, N}, {char,$#}, {char,$#}, X | T], Para, Defs, Res) ->
- Reexp = sl_macro_reexpand(lists:nth(N,Para), Defs, []),
- sl_macro_expand([X, space|T], Para, Defs, lists:flatten([Reexp, space|Res]));
-
-sl_macro_expand([{char,$#}, {char,$#}, space |T], Para, Defs, [space|Res]) ->
- sl_macro_expand(T, Para, Defs, Res);
-sl_macro_expand([{char,$#}, {char,$#} |T], Para, Defs, [space|Res]) ->
- sl_macro_expand(T, Para, Defs, Res);
-sl_macro_expand([{char,$#}, {char,$#}, space |T], Para, Defs, Res) ->
- sl_macro_expand(T, Para, Defs, Res);
-sl_macro_expand([{char,$#}, {char,$#} |T], Para, Defs, Res) ->
- sl_macro_expand(T, Para, Defs, Res);
-
-%%...................
-%% Stringification
-%%...................
-sl_macro_expand([{char,$#}, {para, N}|T], Para, Defs, Res) ->
- Nth = lists:nth(N,Para),
- Tokens = detokenise(Nth),
- sl_macro_expand(T, Para, Defs, [{string,Tokens}|Res]);
-sl_macro_expand([{char,$#}, space, {para, N}|T], Para, Defs, Res) ->
- Nth = lists:nth(N,Para),
- Tokens = detokenise(Nth),
- sl_macro_expand(T, Para, Defs, [{string,Tokens}|Res]);
-
-%%...................
-%% A parameter
-%%...................
-sl_macro_expand([{para, N}|T], Para, Defs, Res) ->
- Reexp = sl_macro_reexpand(lists:nth(N,Para), Defs, []),
- sl_macro_expand(T, Para, Defs, lists:flatten([Reexp|Res]));
-
-%%...................
-%% No parameter
-%%...................
-sl_macro_expand([H|T], Para, Defs, Res) ->
- sl_macro_expand(T, Para, Defs, [H|Res]).
-
-
-
-%%-------------------------------------------------
-%% Expand parameters
-%%-------------------------------------------------
-sl_para_para({para, N}, {para, M}, Para) ->
- case sl_para_1st(lists:nth(N,Para)) of
- {ok, Para1st} ->
- Para1st ++ sl_para_2nd(lists:nth(M,Para));
- {exp, Para1st} ->
- Para1st ++ sl_para_2nd(lists:nth(M,Para)) ++ [space_exp];
- {space, Para1st} ->
- Para1st ++ [space_exp | sl_para_2nd(lists:nth(M,Para))]
- end.
-
-
-sl_var_para(Var, {para, M}, Para) ->
- [Var|sl_para_2nd(lists:nth(M,Para))].
-
-
-sl_para_var({para, N}, Var, Para) ->
- case sl_para_1st(lists:nth(N,Para)) of
- {ok, Para1st} ->
- Para1st ++ [Var];
- {exp, Para1st} ->
- Para1st ++ [Var | space_exp];
- {space, Para1st} ->
- Para1st ++ [space_exp | Var]
- end.
-
-
-sl_para_1st([{var, Var}]) ->
- {ok,[{expanded,Var}]};
-sl_para_1st([{var, Var}, space]) ->
- {ok,[{expanded,Var}]};
-sl_para_1st([{var, Var}, space_exp]) ->
- {exp, [{expanded,Var}]};
-sl_para_1st(L) ->
- {space, L}.
-
-sl_para_2nd([{var, Var}]) ->
- [{expanded,Var}];
-sl_para_2nd([{var, Var}, space_exp]) ->
- [{expanded,Var}];
-sl_para_2nd([space, {var, Var}]) ->
- [{expanded,Var}];
-sl_para_2nd([space_exp, {var, Var}]) ->
- [{expanded,Var}];
-sl_para_2nd(L) ->
- L++[space].
-
-
-
-%%-------------------------------------------------
-%% Check if the expansion is a valid macro,
-%% do not reexpand if concatination
-%%-------------------------------------------------
-sl_macro_reexpand([], _Defs, Result) ->
- Result;
-sl_macro_reexpand([{var,Var}|Rem], Defs, Result) ->
- case lists:keysearch(Var, 1, Defs) of
- {value, {Var, 0, _MacroPara, Macro}} ->
- Rem2 = case Rem of
- [space | RemT] ->
- [space_exp | RemT];
- _ ->
- [space_exp | Rem]
- end,
- sl_macro_reexpand(Macro++Rem2, Defs, Result);
- _ ->
- sl_macro_reexpand(Rem, Defs, [{var,Var}|Result])
- end;
-sl_macro_reexpand([H|Rem], Defs, Result) ->
- sl_macro_reexpand(Rem, Defs, [H|Result]).
-
-
-
-%%-------------------------------------------------
-%% Self referring macros are marked not be reexpanded
-%%-------------------------------------------------
-sl_mark_expanded(QQ, Str) ->
- sl_mark_expanded(QQ, Str, []).
-
-sl_mark_expanded([], _Str, Res) ->
- lists:reverse(Res);
-sl_mark_expanded([H|T], Str, Res) ->
- case H of
- {_,Str} ->
- sl_mark_expanded(T, Str, [{expanded, Str}|Res]);
- _ ->
- sl_mark_expanded(T, Str, [H|Res])
- end.
-
-
-
-
-
-
-
-
-
-%%======================================================================================
-%%======================================================================================
-%%======================================================================================
-%% Misceleaneous functions
-%%======================================================================================
-%%======================================================================================
-%%======================================================================================
-
-
-%%===============================================================
-%% Check the Flags for include directories
-%%===============================================================
-include_dir(Flags) when is_list(Flags)->
- include_dir(Flags,[]);
-include_dir(_Flags) ->
- [].
-
-include_dir(Flags,IncDirs) ->
- case string:str(Flags,"-I") of
- 0 ->
- lists:reverse(IncDirs);
- X ->
- {NewDir, RemainingFlags} =
- gobble_inc_dir(string:sub_string(Flags, X+2),nq,[]),
- include_dir(RemainingFlags, [NewDir|IncDirs])
- end.
-
-% nq = not-quoted, q = quoted.
-% Possible strange scenarios:
-% /usr/test\ ing/
-% "/usr/test ing/"
-% /usr/test\"ing/
-% "/usr/test\"ing/"
-gobble_inc_dir([],nq,Acc) ->
- % Only accept nq here, if we end up here in q mode the user has missed a "
- {lists:reverse(Acc),[]};
-gobble_inc_dir([$\\,$"|R],Q,Acc) ->
- gobble_inc_dir(R,Q,[$"|Acc]);
-gobble_inc_dir([$"|R],nq,Acc) ->
- gobble_inc_dir(R,q,Acc);
-gobble_inc_dir([$"|R],q,Acc) ->
- gobble_inc_dir(R,nq,Acc);
-gobble_inc_dir([$\\,$ |R],nq,Acc) ->
- gobble_inc_dir(R,nq,[$ |Acc]);
-gobble_inc_dir([$ |R],nq,Acc) ->
- {lists:reverse(Acc),R};
-gobble_inc_dir([C|R],Q,Acc) ->
- gobble_inc_dir(R,Q,[C|Acc]).
-
-
-%%===============================================================
-%% Read a included file. Try current dir first then the IncDir list
-%%===============================================================
-
-read_inc_file(FileName, IncDir, Mio) ->
- case find_inc_file(FileName, IncDir) of
- {ok, AbsFile} ->
- %% is included before?
- case lists:member(FileName, Mio#mio.included) of
- false ->
- case catch file:read_file(AbsFile) of
- {ok, Bin} ->
- FileList = binary_to_list(Bin),
- {ok, AbsFile, FileList};
- {error, Text} ->
- {error, Text}
- end;
- true ->
- skip
- end;
- {error, Text} ->
- {error, Text}
- end.
-
-find_inc_file(FileName, IncDir) ->
- case catch file:read_file_info(FileName) of
- {ok, _} ->
- {ok, FileName};
- {error, _} ->
- find_inc_file2(FileName, IncDir)
- end.
-
-find_inc_file2(_FileName, []) ->
- {error, "No such file or directory"};
-find_inc_file2(FileName, [D|Rem]) ->
- Dir = case lists:last(D) of
- $/ ->
- D;
- _ ->
- D++"/"
- end,
- case catch file:read_file_info(Dir++FileName) of
- {ok, _} ->
- {ok, Dir++FileName};
- {error, _} ->
- find_inc_file2(FileName, Rem)
- end.
-
-
-%%===============================================================
-%% Read parameters of a macro or a variable in a source line
-%%===============================================================
-read_para([{char,$(} | Rem]) ->
- read_para(Rem, 1, [], [], 1);
-read_para([space,{char,$(} | Rem]) ->
- read_para(Rem, 1, [], [], 1);
-read_para(_Rem) ->
- {ok, [], [], 0}.
-
-
-%% Abrupt end of the list
-read_para([], _NoOfParen, _Current, _Para, _NoOfPara) ->
- {error, illegal_arg};
-%% All parameters checked
-read_para([{char,$)}|Rem], 1, [], Para, NoOfPara) ->
- {ok, Rem, lists:reverse(Para), NoOfPara};
-read_para([{char,$)}|Rem], 1, Current, Para, NoOfPara) ->
- {ok, Rem, lists:reverse([Current|Para]), NoOfPara};
-
-%% Continue reading
-read_para([{char,$)}|Rem], NoOfParen, Current, Para, NoOfPara) ->
- read_para(Rem, NoOfParen-1, Current++[{char,$)}], Para, NoOfPara);
-read_para([{char,$(}|Rem], NoOfParen, Current, Para, NoOfPara) ->
- read_para(Rem, NoOfParen+1, Current++[{char,$(}], Para, NoOfPara);
-read_para([{char,$,}|Rem], NoOfParen, Current, Para, NoOfPara) when NoOfParen == 1 ->
- read_para(Rem, NoOfParen, [], [Current|Para], NoOfPara+1);
-read_para([space|Rem], NoOfParen, [], Para, NoOfPara) ->
- read_para(Rem, NoOfParen, [], Para, NoOfPara);
-read_para([X|Rem], NoOfParen, Current, Para, NoOfPara) ->
- read_para(Rem, NoOfParen, Current++[X], Para, NoOfPara).
-
-
-
-
-
-
-%%===================================================================================
-%% check if a macro is already defined
-%%===================================================================================
-is_define_ok(Name, No_of_para, Parameters, Macro, Defs) ->
-
- case lists:keysearch(Name, 1, Defs) of
- {value, {Name, No_of_para, _MacroPara, Macro}} ->
- {yes, Defs};
- {value, _} ->
- Defs2 = lists:keydelete(Name, 1, Defs),
- NewMacro = is_define_ok_check_para(Parameters, Macro, []),
- case is_stringify_ok(NewMacro) of
- yes ->
- {no, [{Name, No_of_para, Parameters, NewMacro}|Defs2]};
- no ->
- ErrorText = "`#' operator is not followed by a macro argument name",
- {error, ErrorText, [{Name, No_of_para, Parameters, NewMacro}|Defs2]}
- end;
- false ->
- NewMacro = is_define_ok_check_para(Parameters, Macro, []),
- case is_stringify_ok(NewMacro) of
- yes ->
- {yes, [{Name, No_of_para, Parameters, NewMacro}|Defs]};
- no ->
- ErrorText = "`#' operator is not followed by a macro argument name",
- {error, ErrorText, [{Name, No_of_para, Parameters, NewMacro}|Defs]}
- end
- end.
-
-is_define_ok_check_para(_Para, [], Result) ->
- lists:reverse(Result);
-
-is_define_ok_check_para(Para, [H|T], Result) ->
- case define_arg_para_number(1, Para, H) of
- no_para ->
- is_define_ok_check_para(Para, T, [H|Result]);
- N ->
- is_define_ok_check_para(Para, T, [{para,N}|Result])
- end.
-
-define_arg_para_number(_N, [], _Current) ->
- no_para;
-define_arg_para_number(N, [H|_Para], Current) when H == [Current] ->
- N;
-define_arg_para_number(N, [_H|Para], Current) ->
- define_arg_para_number(N+1, Para, Current).
-
-
-is_stringify_ok([]) ->
- yes;
-is_stringify_ok([{char,$#},{char,$#}|T]) ->
- is_stringify_ok(T);
-is_stringify_ok([{char,$#},space,{para,_X}|T]) ->
- is_stringify_ok(T);
-is_stringify_ok([{char,$#},{para,_X}|T]) ->
- is_stringify_ok(T);
-is_stringify_ok([{char,$#},space,{var,_X}|T]) ->
- is_stringify_ok(T);
-is_stringify_ok([{char,$#},{var,_X}|T]) ->
- is_stringify_ok(T);
-is_stringify_ok([{char,$#},space,{nl,_X}|_T]) ->
- no;
-is_stringify_ok([{char,$#},{nl,_X}|_T]) ->
- no;
-is_stringify_ok([{char,$#}|_T]) ->
- no;
-is_stringify_ok([_H|T]) ->
- is_stringify_ok(T).
-
-%%===================================================================================
-%% check if a macro is already defined
-%%===================================================================================
-is_defined_before(Name, No_of_para, Defs) ->
- case lists:keysearch(Name, 1, Defs) of
- {value, {Name, No_of_para, _MacroPara, _Macro}} ->
- yes;
- {value, _} ->
- no;
- false ->
- no
- end.
-
-
-
-
-%%===================================================================================
-%% read_to_nl(File)
-%%===================================================================================
-read_to_nl([space|Rem]) ->
- read_to_nl(Rem, [], 1);
-read_to_nl(Rem) ->
- read_to_nl(Rem, [], 1).
-
-read_to_nl([], Result, Nl) ->
- {lists:reverse(Result), [], Nl};
-read_to_nl([{nl, _N}|Rem], [{string_part,String} | Result], Nl) ->
- read_to_nl(Rem, [nl, {string_part,String}|Result], Nl+1);
-read_to_nl([{nl, _N}|Rem], [{sys_head_part,String} | Result], Nl) ->
- read_to_nl(Rem, [nl, {sys_head_part,String}|Result], Nl+1);
-read_to_nl([{nl, _N}|Rem], Result, Nl) ->
- {lists:reverse(Result), Rem, Nl};
-read_to_nl([space|Rem], Result, Nl) ->
- read_to_nl(Rem, [space|Result], Nl);
-read_to_nl([{X,String}|Rem], Result, Nl) ->
- read_to_nl(Rem, [{X,String}|Result], Nl).
-
-
-
-
-%%===========================================================
-%% Read characters until next newline
-%%===========================================================
-%read_to_nl2(Str) -> read_to_nl2([],Str).
-
-%read_to_nl2(Line, []) -> {Line,[]};
-%read_to_nl2(Line, [$\n|Str]) -> {Line, Str};
-%read_to_nl2(Line, [X|Str]) -> read_to_nl2([X|Line], Str).
-
-
-
-
-%%===========================================================
-%% Remove leading spaces from a list
-%%===========================================================
-remove_leading_spaces([?space|List]) ->
- remove_leading_spaces(List);
-remove_leading_spaces([?tab|List]) ->
- remove_leading_spaces(List);
-remove_leading_spaces(List) ->
- List.
-
-
-
-
-%%===========================================================
-%% Skip characters until next newline
-%%===========================================================
-skip_to_nl([]) -> [];
-skip_to_nl([$\n | Str]) -> Str;
-skip_to_nl([$\\,$\n | Str]) -> [$/,$/|Str];
-skip_to_nl([_|Str]) -> skip_to_nl(Str).
-
-
-
-
-month(1) -> "Jan";
-month(2) -> "Feb";
-month(3) -> "Mar";
-month(4) -> "Apr";
-month(5) -> "May";
-month(6) -> "Jun";
-month(7) -> "Jul";
-month(8) -> "Aug";
-month(9) -> "Sep";
-month(10) -> "Oct";
-month(11) -> "Nov";
-month(12) -> "Dec".
-
-
-%% Multiple Include Optimization
-%%
-%% Algorithm described at:
-%% http://gcc.gnu.org/onlinedocs/cppinternals/Guard-Macros.html
-update_mio({include, FileName}, #mio{included=Inc}=Mio) ->
- Mio#mio{valid=false, included=[FileName|Inc]};
-
-%% valid=false & cmacro=undefined indicates it is already decided this file is
-%% not subject to MIO
-update_mio(_, #mio{valid=false, depth=0, cmacro=undefined}=Mio) ->
- Mio;
-
-%% if valid=true, there is no non-whitespace tokens before this ifndef
-update_mio({'ifndef', Macro}, #mio{valid=true, depth=0, cmacro=undefined}=Mio) ->
- Mio#mio{valid=false, cmacro=Macro, depth=1};
-
-%% detect any tokens before top level #ifndef
-update_mio(_, #mio{valid=true, depth=0, cmacro=undefined}=Mio) ->
- Mio#mio{valid=false};
-
-%% If cmacro is alreay set, this is after the top level #endif
-update_mio({'ifndef', _}, #mio{valid=true, depth=0}=Mio) ->
- Mio#mio{valid=false, cmacro=undefined};
-
-%% non-top level conditional, just update depth
-update_mio({'ifndef', _}, #mio{depth=D}=Mio) when D > 0 ->
- Mio#mio{depth=D+1};
-update_mio('ifdef', #mio{depth=D}=Mio) ->
- Mio#mio{depth=D+1};
-update_mio('if', #mio{depth=D}=Mio) ->
- Mio#mio{depth=D+1};
-
-%% top level #else #elif invalidates multiple include optimization
-update_mio('else', #mio{depth=1}=Mio) ->
- Mio#mio{valid=false, cmacro=undefined};
-update_mio('else', Mio) ->
- Mio;
-update_mio('elif', #mio{depth=1}=Mio) ->
- Mio#mio{valid=false, cmacro=undefined};
-update_mio('elif', Mio) ->
- Mio;
-
-%% AT exit to top level, if the controlling macro is not set, this could be the
-%% end of a non-ifndef conditional block, or there were tokens before entering
-%% the #ifndef block. In either way, this invalidates the MIO
-%%
-%% It doesn't matter if `valid` is true at the time of exiting, it is set to
-%% true. This will be used to detect if more tokens are following the top
-%% level #endif.
-update_mio('endif', #mio{depth=1, cmacro=undefined}=Mio) ->
- Mio#mio{valid=false, depth=0};
-update_mio('endif', #mio{depth=1}=Mio) ->
- Mio#mio{valid=true, depth=0};
-update_mio('endif', #mio{depth=D}=Mio) when D > 1 ->
- Mio#mio{valid=true, depth=D-1};
-
-%%if more tokens are following the top level #endif.
-update_mio('endif', #mio{depth=1, cmacro=undefined}=Mio) ->
- Mio#mio{valid=false, depth=0};
-update_mio('endif', #mio{depth=D}=Mio) when D > 0 ->
- Mio#mio{valid=true, depth=D-1};
-update_mio(_, Mio) ->
- Mio#mio{valid=false}.
-
-%% clear `valid`, this doesn't matter since #endif will restore it if
-%% appropriate
-update_mio(Mio) ->
- Mio#mio{valid=false}.
-
-
diff --git a/lib/ic/src/ic_pragma.erl b/lib/ic/src/ic_pragma.erl
deleted file mode 100644
index 13c02cfcba..0000000000
--- a/lib/ic/src/ic_pragma.erl
+++ /dev/null
@@ -1,1957 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(ic_pragma).
-
-
--export([pragma_reg/2,pragma_cover/3]).
--export([pragma_prefix/3,pragma_version/3,pragma_id/3]).
--export([mk_alias/3,get_alias/2,scope2id/2,id2scope/2,mk_scope/1]).
--export([mk_ref/3,get_incl_refs/1,get_local_refs/1]).
--export([get_dependencies/1, add_inh_data/3, preproc/3]).
--export([getBrokerData/3,defaultBrokerData/1,list_to_term/1]).
--export([get_local_c_headers/2,get_included_c_headers/1,is_inherited_by/3]).
--export([no_doubles/1,fetchRandomLocalType/1,fetchLocalOperationNames/2]).
--export([is_local/2]).
-
-%% Debug
--export([print_tab/1,slashify/1,is_short/1]).
-
--import(lists,[suffix/2,delete/2,reverse/1,keysearch/3,member/2,last/1,flatten/1]).
--import(string,[tokens/2]).
--import(ets,[insert/2,lookup/2]).
-
--import(ic_forms, [get_id2/1, get_body/1, get_line/1]).
--import(ic_util, [to_atom/1]).
--import(ic_genobj, [idlfile/1]).
--import(ic_options, [get_opt/2]).
-
--include("icforms.hrl").
--include("ic.hrl").
-
-
-
-
-%% Initialization of the pragma table and
-%% start of pragma registration.
-%% NOTE : this pragma registration is build
-%% as a separate stage under compilation.
-%% If it is to be optimised, it should be
-%% embodied in one of other compiling stages.
-pragma_reg(G,X) ->
- S = ic_genobj:pragmatab(G),
- init_idlfile(G,S),
- init_pragma_status(S),
- registerOptions(G,S),
- pragma_reg_all(G, S, [], X),
- denote_specific_code_opts(G),
- case get_pragma_compilation_status(S) of
- true ->
- %% Remove ugly pragmas from form
- PragmaCleanForm = cleanup(X),
- {ok,PragmaCleanForm};
- false ->
- ErrorNr = get_pragma_error_nr(S),
- %% Just print the number of errors found
- case ErrorNr > 1 of
- true ->
- io:format("There were ~p errors found on file ~p~n",
- [ErrorNr,get_idlfile(S)]),
- error;
- false ->
- io:format("There were ~p error found on file ~p~n",
- [ErrorNr,get_idlfile(S)]),
- error
- end
- end.
-
-
-
-registerOptions(G,S) ->
- OptList = ets:tab2list(ic_genobj:optiontab(G)),
- registerOptions(G,S,OptList).
-
-
-registerOptions(_G,_S,[]) ->
- true;
-registerOptions(G,S,[{{option,{broker,Scope}},{Mod,Type}}|Rest]) ->
- insert(S,
- {codeopt,
- reverse(tokens(Scope,":")),
- {broker,{Mod,Type}},
- -1,
- nil,
- nil}),
- registerOptions(G,S,Rest);
-registerOptions(G,S,[_|Rest]) ->
- registerOptions(G,S,Rest).
-
-
-%% Decide if to apply pragmas
-%% by checking backend switch
-applyPragmasInBe(G) ->
- case get_opt(G, be) of
- erl_plain ->
- false;
- _ ->
- true
- end.
-
-
-%% Decide if the code option directive
-%% is allowed to change backend
-applyCodeOpt(G) ->
- case get_opt(G, be) of
- erl_corba -> %% Does not support codeopt
- false;
- erl_plain -> %% Does not support codeopt
- false;
- c_native -> %% Does not support codeopt
- false;
- _ ->
- true
- end.
-
-
-
-%% This removes all pragma records from the form.
-%% When debugged, it can be enbodied in pragma_reg_all.
-cleanup(undefined,C) -> C;
-cleanup([],C) -> C;
-cleanup([X|Xs],CSF) ->
- cleanup(Xs, CSF++cleanup(X)).
-
-cleanup(X) when is_list(X) -> cleanup(X,[]);
-cleanup(X) when is_record(X, preproc) -> [X];
-cleanup(X) when is_record(X, pragma) -> [];
-cleanup(X) when is_record(X, op) -> % Clean inside operation parameters
- [ X#op{params = cleanup(X#op.params,[])}];
-
-cleanup(X) when is_record(X, module) -> % Clean inside module body
- [ X#module{body = cleanup(X#module.body,[])}];
-
-cleanup(X) when is_record(X, interface) -> % Clean inside interface body
- [ X#interface{body = cleanup(X#interface.body,[])}];
-
-cleanup(X) when is_record(X, except) -> % Clean inside exception body
- [ X#except{body = cleanup(X#except.body,[])}];
-
-cleanup(X) when is_record(X, struct) -> % Clean inside struct body
- [ X#struct{body = cleanup(X#struct.body,[])}];
-
-cleanup(X) when is_record(X, case_dcl) -> % Clean inside union body
- [ X#case_dcl{label = cleanup(X#case_dcl.label,[])}];
-
-cleanup(X) when is_record(X, union) -> % Clean inside union body
- [ X#union{body = cleanup(X#union.body,[])}];
-
-cleanup(X) when is_record(X, enum) -> % Clean inside enum body
- [ X#enum{body = cleanup(X#enum.body,[])}];
-
-cleanup(X) -> [X].
-
-
-
-
-%% pragma_reg_all is top level registration for pragmas
-pragma_reg_all(_G, _S, _N, []) -> ok;
-pragma_reg_all(G, S, N, [X|Xs]) ->
- pragma_reg(G, S, N, X),
- pragma_reg_all(G, S, N, Xs).
-
-
-%% pragma_reg is top level registration for pragmas
-pragma_reg(G, S, N, X) when is_list(X) -> pragma_reg_list(G, S, N, X);
-pragma_reg(_G, S, _N, X) when element(1, X) == preproc ->
- case X#preproc.aux of
- [{_, _, "1"}] ->
- IncludeEntryLNr = get_line(X#preproc.id),
- IncludeFileName = element(3,element(3,X)),
- insert(S,{includes,get_idlfile(S),IncludeFileName,IncludeEntryLNr});
- _Other ->
- ok
- end,
- set_idlfile(S,element(3,element(3,X)));
-pragma_reg(G, S, N, X) when element(1, X) == pragma ->
- case applyPragmasInBe(G) of
-
- %% Pragmas are allowed to be
- %% applied in this this backend.
- true ->
-
- File = get_idlfile(S), % The current file or an included one.
- Type = case idlfile(G) of % Local/Included flag
- File ->
- local;
- _ ->
- included
- end,
-
- %% Register pragmas into pragmatab.
- case X of
- {pragma,{_,LineNr,"prefix"}, _To, _Apply} ->
- insert(S,{prefix,X,LineNr,N,File,Type});
-
- {pragma,{_,_,"ID"},_,_} ->
- pragma_reg_ID(G, S, N, X);
-
- {pragma,{_,_,"version"},_,_} ->
- pragma_reg_version(G, S, N, X );
-
- {pragma,{_,_,"CODEOPT"},_,_} ->
- pragma_reg_codeOpt(G,S,N,X);
-
- {pragma,{_,LineNr,BadPragma}, _To, _Apply} ->
- io:format("Warning : on file ~p :~n",[get_idlfile(S)]),
- io:format(" Unknown pragma directive ~p on line ~p, ignored.~n",
- [BadPragma,LineNr])
- end;
-
- %% Pragmas are not to be applied in
- %% this backend, ignore all pragmas.
- false ->
- true
- end,
- ok;
-
-pragma_reg(G, S, N, X) when is_record(X, module) ->
- mk_ref(G,[get_id2(X) | N],mod_ref),
- mk_file_data(G,X,N,module),
- pragma_reg_all(G, S, [get_id2(X) | N], get_body(X));
-
-pragma_reg(G, S, N, X) when is_record(X, interface) ->
- mk_ref(G,[get_id2(X) | N],ifc_ref),
- mk_file_data(G,X,N,interface),
- pragma_reg_all(G, S, [get_id2(X) | N], get_body(X));
-
-pragma_reg(G, S, N, X) when is_record(X, op) ->
- %% Add operation in table
- insert(S,{op,
- get_id2(X),
- N,
- get_idlfile(S),
- get_filepath(S)}),
- mk_file_data(G,X,N,op),
- pragma_reg_all(G, S, N, X#op.params);
-
-pragma_reg(G, S, N, X) when is_record(X, except) ->
- mk_ref(G,[get_id2(X) | N],except_ref),
- mk_file_data(G,X,N,except),
- pragma_reg_all(G, S, N, X#except.body);
-
-pragma_reg(G, _S, N, X) when is_record(X, const) ->
- mk_ref(G,[get_id2(X) | N],const_ref),
- mk_file_data(G,X,N,const);
-
-pragma_reg(G, _S, N, X) when is_record(X, typedef) ->
- XX = #id_of{type=X},
- lists:foreach(fun(Id) ->
- mk_ref(G,[get_id2(Id) | N],typedef_ref),
- mk_file_data(G,XX#id_of{id=Id},N,typedef)
- end,
- ic_forms:get_idlist(X));
-
-pragma_reg(G, S, N, X) when is_record(X, enum) ->
- mk_ref(G,[get_id2(X) | N],enum_ref),
- mk_file_data(G,X,N,enum),
- pragma_reg_all(G, S, N, X#enum.body);
-
-pragma_reg(G, S, N, X) when is_record(X, union) ->
- mk_ref(G,[get_id2(X) | N],union_ref),
- mk_file_data(G,X,N,union),
- pragma_reg_all(G, S, N, X#union.body);
-
-pragma_reg(G, S, N, X) when is_record(X, struct) ->
- mk_ref(G,[get_id2(X) | N],struct_ref),
- mk_file_data(G,X,N,struct),
- case X#struct.body of
- undefined ->
- ok;
- _ ->
- pragma_reg_all(G, S, N, X#struct.body)
- end;
-
-pragma_reg(G, _S, N, X) when is_record(X, attr) ->
- XX = #id_of{type=X},
- lists:foreach(fun(Id) ->
- mk_ref(G,[get_id2(Id) | N],attr_ref),
- mk_file_data(G,XX#id_of{id=Id},N,attr)
- end,
- ic_forms:get_idlist(X));
-
-pragma_reg(_G, _S, _N, _X) -> ok.
-
-
-
-
-pragma_reg_list(_G, _S, _N, []) -> ok;
-pragma_reg_list(G, S, N, List ) ->
- CurrentFileName = get_idlfile(S),
- pragma_reg_list(G, S, N, CurrentFileName, List).
-
-pragma_reg_list(_G, _S, _N, _CFN, []) -> ok;
-pragma_reg_list(G, S, N, CFN, [X | Xs]) ->
- case X of
- {preproc,_,{_,_,FileName},_} ->
- set_idlfile(S,FileName),
- pragma_reg(G, S, N, X),
- pragma_reg_list(G, S, N, FileName, Xs);
- _ ->
- pragma_reg(G, S, N, X),
- pragma_reg_list(G, S, N, CFN, Xs)
- end.
-
-
-
-
-
-pragma_reg_ID(G, S, N, X) ->
- {pragma,{_,LineNr,"ID"}, _To, Apply} = X,
-
-
- File = get_idlfile(S), % The current file or an included one.
- Type = case idlfile(G) of % Local/Included flag
- File ->
- local;
- _ ->
- included
- end,
-
- %% Check if ID is one of the allowed types :
- %% * OMG IDL
- %% * DCE UUID
- %% * LOCAL
- case tokens(element(3,Apply),":") of
- ["IDL",_,_] ->
- insert(S,{id,X,LineNr,N,File,Type});
- ["DCE",_,VSN] ->
- case is_short(VSN) of
- true ->
- insert(S,{id,X,LineNr,N,File,Type});
- false ->
- set_compilation_failure(S),
- io:format("Error on file ~p :~n",[get_idlfile(S)]),
- io:format(" Bad pragma ID ~p on line ~p,~n",
- [element(3,Apply),LineNr]),
- io:format(" the version part of ID is not a short integer.~n")
- end;
- ["LOCAL"|_] ->
- insert(S,{id,X,LineNr,N,File,Type});
- _ ->
- set_compilation_failure(S),
- io:format("Error on file ~p :~n",[get_idlfile(S)]),
- io:format(" Bad pragma ID ~p on line ~p.~n",
- [element(3,Apply),LineNr])
- end.
-
-
-
-pragma_reg_version(G, S, N, X) ->
- {pragma,{_,LineNr,"version"}, _To, Apply} = X,
-
- File = get_idlfile(S), % The current file or an included one.
- Type = case idlfile(G) of % Local/Included flag
- File ->
- local;
- _ ->
- included
- end,
-
- case tokens(Apply,".") of
- [Major,Minor] ->
- case is_short(Major) and is_short(Minor) of
- true ->
- insert(S,{version,X,LineNr,N,File,Type});
- false ->
- set_compilation_failure(S),
- io:format("Error on file ~p :~n",[get_idlfile(S)]),
- io:format(" Bad pragma version ~p on line ~p,~n",
- [Apply,LineNr]),
- io:format(" the version is not valid.~n")
- end;
- _ ->
- set_compilation_failure(S),
- io:format("Error on file ~p :~n",[get_idlfile(S)]),
- io:format(" Bad pragma version ~p on line ~p,~n",
- [Apply,LineNr]),
- io:format(" the version is not valid.~n")
- end.
-
-
-pragma_reg_codeOpt(G, S, _N, {pragma,{_,LineNr,"CODEOPT"},_,Apply} )->
- case applyCodeOpt(G) of
- true ->
- {_,_,OptionList_str} = Apply,
- case list_to_term(OptionList_str) of
- error ->
- ic_error:error(G,{pragma_code_opt_bad_option_list,LineNr});
- OptionList ->
- case lists:keysearch(be,1,OptionList) of
- false ->
- %% Add the terms of the option list
- %% to the compiler option list
- applyCodeOpts(G,S,LineNr,OptionList);
- {value, {be,Type}} ->
- %% If backend is set from user,
- %% let the same backend be otherwize
- %% set backend by codeOpt directive
- case get_opt(G, be) of
- false ->
- %% Add the terms of the option list
- %% to the compiler option list
- applyCodeOpts(G,S,LineNr,OptionList);
- _ ->
- %% Add all the terms of the option list
- %% to the compiler option list but the
- %% backend option
- applyCodeOpts(G,
- S,
- LineNr,
- lists:delete({be,Type},OptionList))
- end
- end
- end;
- false ->
- true
- end.
-
-
-
-applyCodeOpts(_,_,_,[]) ->
- true;
-applyCodeOpts(G,S,LNr,[{{broker,Scope},{M,T}}|Xs]) ->
- ScopedId = reverse(tokens(Scope,":")),
- case ets:match(S,
- {codeopt,ScopedId,
- '$1','$2','_','_'}) of
- [] ->
- %% Add pragma in table
- insert(S,
- {codeopt,
- ScopedId,
- {broker,{M,T}},
- LNr,
- get_idlfile(S),
- get_filepath(S)}),
- %% Continue
- applyCodeOpts(G,S,LNr,Xs);
- _ ->
- %% Use the code option
- %% from user and continue
- applyCodeOpts(G,S,LNr,Xs)
- end;
-applyCodeOpts(G,S,LNr,[X|Xs]) ->
- case is_allowed_opt(X) of
- true ->
- %% Add that term of the option list
- %% to the compiler option list
- ic_options:add_opt(G, [X], true),
- %% Continue
- applyCodeOpts(G,S,LNr,Xs);
- false ->
- %% Print warning and continue
- io:format("Warning on file ~p :~n",[get_idlfile(S)]),
- io:format(" Bad option in pragma : ~p, ignored !~n",[X]),
- applyCodeOpts(G,S,LNr,Xs)
- end.
-
-
-is_allowed_opt({X,Y}) ->
- ic_options:allowed_opt(X,Y);
-is_allowed_opt(_X) ->
- false.
-
-
-
-%% Returns a tuple { PFX, VSN, ID }, that is the
-%% pragma prefix, version and id coverages of
-%% the scope SCOPE. This is done by use of the
-%% function pragma_cover/4.
-pragma_cover(G,Scope,Object) ->
- pragma_cover(ic_genobj:pragmatab(G),get_id2(Object),Scope,get_line(Object)).
-
-%% Returns a tuple { PFX, VSN, ID }, that is the
-%% pragma prefix, version and id coverages of
-%% the scope SCOPE
-pragma_cover(PragmaTab,Name,Scope,LineNr) ->
- PFX = pragma_prefix_cover(PragmaTab,Name,Scope,LineNr),
- VSN = pragma_version_cover(PragmaTab,Name,Scope,LineNr),
- ID = pragma_id_cover(PragmaTab,Name,Scope,LineNr),
- { PFX, VSN, ID }.
-
-
-
-%% Finds out which pragma PREFIX that affects
-%% the scope Scope
-pragma_prefix(G,Scope,Object) ->
- pragma_prefix_cover(ic_genobj:pragmatab(G),get_id2(Object),Scope,get_line(Object)).
-
-
-%% Finds out which pragma PREFIX that affects
-%% the scope Scope
-pragma_prefix_cover(PragmaTab,Name,Scope,LineNr) ->
- case lookup(PragmaTab,prefix) of
- [] ->
- none;
- PragmaPrefixList ->
- FilteredPragmaPrefixList =
- filter_pragma_prefix_list(PragmaTab,Name,Scope,PragmaPrefixList),
- case most_local(FilteredPragmaPrefixList,Scope) of
- [] ->
- none;
- MostLocalList ->
- case dominant_prefix(MostLocalList,LineNr) of
- none ->
- none;
-
- %% Just filter empty pragma prefix
- {prefix,{pragma,{_,_,_},_,{'<string_literal>',_,[]}},_,_,_,_} ->
- none;
-
- DP ->
- %% Return the scoped id (reversed list of
- %% path elements, but remember to remove
- %% '[]' that represents the top level
- slashify(lists:sublist(Scope, 1,
- length(Scope) - length(element(4,DP))) ++
- [ element(3,element(4,element(2,DP)))])
- end
- end
- end.
-
-
-%% Returns a slashified name, [I1, M1] becomes "M1/I1"
-slashify(List) -> lists:foldl(fun(X, Acc) -> X++"/"++Acc end,
- hd(List), tl(List)).
-
-
-%% Finds out which pragma VERSION that affects
-%% the scope Scope
-pragma_version(G,Scope,Object) ->
- pragma_version_cover(ic_genobj:pragmatab(G),get_id2(Object),Scope,get_line(Object)).
-
-%% Finds out which pragma VERSION that affects
-%% the scope Scope
-pragma_version_cover(PragmaTab,Name,Scope,LineNr) ->
- case lookup(PragmaTab,version) of
- [] ->
- default_version();
- PragmaVersionList ->
- case all_actual_for_version_or_id( PragmaVersionList, Name ) of
- [] ->
- default_version();
- ActualVersionList ->
- case most_local(ActualVersionList,Scope) of
- [] ->
- default_version();
- MostLocalList ->
- case dominant_version(MostLocalList,LineNr) of
- DV ->
- element(4,element(2,DV))
- end
- end
- end
- end.
-
-
-default_version() -> "1.0".
-
-
-
-%% Finds out which pragma ID that affects
-%% the scope Scope
-pragma_id(G,Scope,Object) ->
- pragma_id_cover(ic_genobj:pragmatab(G),get_id2(Object),Scope,get_line(Object)).
-
-%% Finds out which pragma ID that affects
-%% the scope Scope
-pragma_id_cover(PragmaTab,Name,Scope,LineNr) ->
- case lookup(PragmaTab,id) of
- [] ->
- none;
- PragmaIdList ->
- case all_actual_for_version_or_id( PragmaIdList, Name ) of
- [] ->
- none;
- ActualIdList ->
- case most_local(ActualIdList,Scope) of
- [] ->
- none;
- MostLocalList ->
- case dominant_id(MostLocalList,LineNr) of
- PI ->
- element(3,element(4,element(2,PI)))
- end
- end
- end
- end.
-
-
-
-
-%% Finds out which pragma VERSION ( or ID ) that
-%% that affects the scope object with name NAME
-all_actual_for_version_or_id(NList, Name) ->
- all_actual_for_version_or_id( NList, [], Name ).
-
-all_actual_for_version_or_id([], Actual, _) ->
- Actual;
-all_actual_for_version_or_id([First|Rest], Found, Name) ->
- case is_actual_for_version_or_id(First,Name) of
- true ->
- all_actual_for_version_or_id(Rest, [First|Found], Name);
- false ->
- all_actual_for_version_or_id(Rest, Found, Name)
- end.
-
-is_actual_for_version_or_id( Current, Name ) ->
- case element(3,element(3,element(2,Current))) of
- Name ->
- true;
- OtherName ->
- suffix([Name],tokens(OtherName,"::"))
- end.
-
-
-
-
-%% Find the most locally defind pragmas
-%% to the scope SCOPE
-most_local( SList, Scope ) ->
- case SList of
- [] ->
- [];
- [First|Rest] ->
- case suffix( element(4,First), Scope ) of
- true ->
- most_local( Rest, First, Scope, [First] );
- false ->
- most_local( Rest, Scope )
- end
- end.
-
-%% Returns a list of all pragmas found in the
-%% same scope. Should choose the right one by looking
-%% att the position of the pragma in relation to
-%% the current object..... ( For hairy cases ).
-most_local( SList, Current, Scope, AllFound ) ->
- case SList of
- [] ->
- AllFound;
- [First|Rest] ->
- FirstScope = element(4,First),
- case suffix( FirstScope, Scope ) of
- true ->
- CurrentScope = element(4,Current),
- case suffix( CurrentScope, FirstScope ) of
- true ->
- case length( CurrentScope ) == length( FirstScope ) of
- true -> %% SAME SCOPE ! KEEP BOTH
- most_local( Rest, Current, Scope, [First|AllFound] );
- false ->
- most_local( Rest, First, Scope, [First] )
- end;
- false ->
- most_local( Rest, Current, Scope, AllFound )
- end;
- false ->
- most_local( Rest, Current, Scope, AllFound )
- end
- end.
-
-
-
-
-%% Find the most dominant prefix pragmas
-%% located onto the SAME scope. Now
-%% we look att the line number, the position
-%% on the file.
-dominant_prefix(SList,LineNr) ->
- case SList of
- [First|Rest] ->
- dominant_prefix(Rest,First,LineNr)
- end.
-
-
-dominant_prefix([],{prefix,X,PLNr,N,F,T},LineNr) ->
- case LineNr > PLNr of
- true ->
- {prefix,X,PLNr,N,F,T};
- false ->
- none
- end;
-dominant_prefix([{prefix,FX,FPLNr,FN,F1,T1}|Rest],{prefix,CX,CPLNr,CN,F2,T2},LineNr) ->
- case LineNr > FPLNr of % Check if FIRST before the object
- true ->
- case FPLNr > CPLNr of % Check if FIRST after CURRENT
- true ->
- dominant_prefix(Rest,{prefix,FX,FPLNr,FN,F1,T1},LineNr);
- false ->
- dominant_prefix(Rest,{prefix,CX,CPLNr,CN,F2,T2},LineNr)
- end;
- false -> % FIRST does not affect the object
- dominant_prefix(Rest,{prefix,CX,CPLNr,CN,F2,T2},LineNr)
- end.
-
-
-
-
-%% Find the most dominant version pragmas
-%% located onto the SAME scope. Now
-%% we look att the line number, the position
-%% on the file.
-dominant_version(SList,LineNr) ->
- case SList of
- [First|Rest] ->
- dominant_version(Rest,First,LineNr)
- end.
-
-
-dominant_version([],Current,_) -> Current;
-dominant_version([{version,FX,FPLNr,FN,F1,T1}|Rest],{version,CX,CPLNr,CN,F2,T2},LineNr) ->
- case FPLNr > CPLNr of % Check if FIRST after CURRENT
- true ->
- dominant_version(Rest,{prefix,FX,FPLNr,FN,F1,T1},LineNr);
- false ->
- dominant_version(Rest,{prefix,CX,CPLNr,CN,F2,T2},LineNr)
- end.
-
-
-
-
-%% Find the most dominant id pragmas
-%% located onto the SAME scope. Now
-%% we look att the line number, the position
-%% on the file.
-dominant_id(SList,LineNr) ->
- case SList of
- [First|Rest] ->
- dominant_id(Rest,First,LineNr)
- end.
-
-
-dominant_id([],Current,_) -> Current;
-dominant_id([{id,FX,FPLNr,FN,F1,T1}|Rest],{id,CX,CPLNr,CN,F2,T2},LineNr) ->
- case FPLNr > CPLNr of % Check if FIRST after CURRENT
- true ->
- dominant_id(Rest,{id,FX,FPLNr,FN,F1,T1},LineNr);
- false ->
- dominant_id(Rest,{id,CX,CPLNr,CN,F2,T2},LineNr)
- end.
-
-
-
-
-
-%% This registers a module defined inside the file or
-%% an included file. A tuple that describes the module
-%% is added to the table.
-%% Observe that the modules registered are ONLY those
-%% who are in the top level, not definedd inside others !
-mk_ref(G,Name,Type) ->
- case length(Name) > 1 of
- true -> %% The interface is NOT defined att top level
- true;
- false ->
- S = ic_genobj:pragmatab(G),
- File = get_idlfile(S), % The current file or an included one.
- case idlfile(G) of % The current file to be compiled.
- File ->
- insert(S,{Type,Name,File,local});
- _ ->
- insert(S,{Type,Name,File,included})
- end
- end.
-
-
-%% The same as mk_ref/3 but this registers everything with
-%% all vital information available inside files.
-%% Registers ESSENTIAL data for included files
-mk_file_data(G,X,Scope,Type) ->
- S = ic_genobj:pragmatab(G),
- Name = get_id2(X),
- PreprocFile = get_idlfile(S), % The current file or an included one.
- CompFile = idlfile(G), % The current file compiled
- Depth = length(Scope), % The depth of the scope
- ScopedName = ic_util:to_undersc([Name|Scope]),
- Line = ic_forms:get_line(X),
- case PreprocFile of
- CompFile ->
- insert(S,{file_data_local,CompFile,CompFile,Type,Scope,Name,ScopedName,Depth,Line});
- PreprocFile ->
- insert(S,{file_data_included,PreprocFile,CompFile,Type,Scope,Name,ScopedName,Depth,Line})
- end.
-
-
-
-%% Return a list with all the headers from
-%% the local file that represent the module
-%% or interface that is preciding the current
-get_local_c_headers(G,X) ->
- S = ic_genobj:pragmatab(G),
- Local = lookup(S,file_data_local),
- FoundLocal = get_local_c_headers(X,Local,Local),
- no_doubles(FoundLocal).
-
-get_local_c_headers(X,Local,Local) ->
- get_local_c_headers(X,Local,Local,[]).
-
-get_local_c_headers(_X,[],_All,Found) ->
- Found;
-get_local_c_headers(X,[{file_data_local,_PF_idl,_,module,_,_,SN,_,Line}|Hs],All,Found)->
- case ic_forms:get_line(X) > Line of
- true ->
- get_local_c_headers(X,Hs,All,[SN|Found]);
- false ->
- get_local_c_headers(X,Hs,All,Found)
- end;
-get_local_c_headers(X,[{file_data_local,_PF_idl,_,interface,_,_,SN,_,Line}|Hs],All,Found)->
- case ic_forms:get_line(X) > Line of
- true ->
- get_local_c_headers(X,Hs,All,[SN|Found]);
- false ->
- get_local_c_headers(X,Hs,All,Found)
- end;
-get_local_c_headers(X,[_|Hs],All,Found) ->
- get_local_c_headers(X,Hs,All,Found).
-
-
-
-%% Return a list with all the headers from
-%% the included file that represent the module
-%% or interface that have to be included
-get_included_c_headers(G) ->
- S = ic_genobj:pragmatab(G),
- Included = lookup(S,file_data_included),
- FoundIncluded = get_included_c_headers(Included,Included),
- no_doubles(FoundIncluded).
-
-get_included_c_headers(Included,Included) ->
- get_included_c_headers(Included,Included,[]).
-
-get_included_c_headers([],_All,Found) ->
- Found;
-get_included_c_headers([{file_data_included,PF_idl,_CF_idl,T,_S,_N,SN,0,_}|Hs],All,Found) ->
- Len = length(PF_idl),
- FN = string:sub_string(PF_idl,1,Len-4),
- case only_top_level(PF_idl,All) of
- true ->
- %%
- L = string:tokens(FN,"/"),
- FN2 = lists:last(L),
- %%
- get_included_c_headers(Hs,All,["oe_"++FN2|Found]);
- false ->
- case T of
- module ->
- case contains_interface(PF_idl,All) of
- true ->
- %%
- L = string:tokens(FN,"/"),
- FN2 = lists:last(L),
- %%
- get_included_c_headers(Hs,All,["oe_"++FN2|Found]);
- false ->
- get_included_c_headers(Hs,All,[SN|Found])
- end;
- interface ->
- case contains_interface(PF_idl,All) of
- true ->
- %%
- L = string:tokens(FN,"/"),
- FN2 = lists:last(L),
- %%
- get_included_c_headers(Hs,All,["oe_"++FN2|Found]);
- false ->
- get_included_c_headers(Hs,All,[SN|Found])
- end;
- _ ->
- get_included_c_headers(Hs,All,["oe_"++FN|Found])
- end
- end;
-get_included_c_headers([{file_data_included,_PF_idl,_,module,_,_,SN,_,_}|Hs],All,Found)->
- get_included_c_headers(Hs,All,[SN|Found]);
-get_included_c_headers([{file_data_included,_PF_idl,_,interface,_,_,SN,_,_}|Hs],All,Found)->
- get_included_c_headers(Hs,All,[SN|Found]);
-get_included_c_headers([_|Hs],All,Found) ->
- get_included_c_headers(Hs,All,Found).
-
-%% Help functions for the above
-
-only_top_level(_PF_idl,[]) ->
- true;
-only_top_level(PF_idl,[H|Hs]) ->
- case element(2,H) of
- PF_idl ->
- case element(8,H) > 0 of
- true ->
- false;
- false ->
- only_top_level(PF_idl,Hs)
- end;
- _ ->
- only_top_level(PF_idl,Hs)
- end.
-
-contains_interface(_PF_idl,[]) ->
- false;
-contains_interface(PF_idl,[H|Hs]) ->
- case element(2,H) of
- PF_idl ->
- case element(4,H) of
- interface ->
- case element(8,H) > 0 of
- true ->
- true;
- false ->
- contains_interface(PF_idl,Hs)
- end;
- _ ->
- contains_interface(PF_idl,Hs)
- end;
- _ ->
- contains_interface(PF_idl,Hs)
- end.
-
-
-
-%% This returns a list of everything defined in an included file.
-get_incl_refs(G) ->
- S = ic_genobj:pragmatab(G),
-
- RefList =
- ets:match(S,{mod_ref,'$0','_',included}) ++
- ets:match(S,{ifc_ref,'$0','_',included}) ++
- ets:match(S,{const_ref,'$0','_',included}) ++
- ets:match(S,{typedef_ref,'$0','_',included}) ++
- ets:match(S,{except_ref,'$0','_',included}) ++
- ets:match(S,{struct_ref,'$0','_',included}) ++
- ets:match(S,{union_ref,'$0','_',included}) ++
- ets:match(S,{enum_ref,'$0','_',included}) ++
- ets:match(S,{attr_ref,'$0','_',included}),
-
- case RefList of
- [] ->
- none;
- _ ->
- RefList
- end.
-
-
-
-%% This returns a list of everything locally defined.
-get_local_refs(G) ->
- S = ic_genobj:pragmatab(G),
-
- RefList =
- ets:match(S,{mod_ref,'$0','_',local}) ++
- ets:match(S,{ifc_ref,'$0','_',local}) ++
- ets:match(S,{const_ref,'$0','_',local}) ++
- ets:match(S,{typedef_ref,'$0','_',local}) ++
- ets:match(S,{except_ref,'$0','_',local}) ++
- ets:match(S,{struct_ref,'$0','_',local}) ++
- ets:match(S,{union_ref,'$0','_',local}) ++
- ets:match(S,{enum_ref,'$0','_',local}) ++
- ets:match(S,{attr_ref,'$0','_',local}),
-
- case RefList of
- [] ->
- none;
- _ ->
- RefList
- end.
-
-
-
-
-
-%% This is intented to be used for solving the identification
-%% problem introduced by pragmas. It creates aliases between
-%% scoped and "final" identities.
-mk_alias(G,PragmaId,ScopedId) ->
- %io:format("~nMaking alias -> ~p~n",[PragmaId]),
- S = ic_genobj:pragmatab(G),
- insert(S,{alias,ScopedId,PragmaId}).
-
-
-%% This is used to find out if the object described with
-%% the scoped id is created. If this is the case, it should
-%% be registered as an alias and the identity of the object
-%% is returned. Otherwize "none" is returned.
-get_alias(G,ScopedId) ->
- S = ic_genobj:pragmatab(G),
- case ets:match(S,{alias,ScopedId,'$1'}) of
- [] ->
- none;
- [[IfrId]] ->
- %io:format("~nFound alias -> ~p~n",[IfrId]),
- IfrId
- end.
-
-
-
-%% Returns the alias id or constructs an id
-scope2id(G,ScopedId) ->
- case get_alias(G,ScopedId) of
- none ->
- case is_included(G,ScopedId) of
- true -> %% File included
- get_included_IR_ID(G,ScopedId);
- false -> %% File local
- NewIfrId = mk_id(ScopedId), % Create a "standard" id
- mk_alias(G,NewIfrId,ScopedId), % Create an alias
- NewIfrId
- end;
- IfrId ->
- IfrId
- end.
-
-
-
-
-is_included(G,ScopedId) ->
- S = ic_genobj:pragmatab(G),
- Name = ic_util:to_undersc(ScopedId),
- case ets:match(S,{file_data_included,'_','_','_','_','_',Name,'_','_'}) of
- [[]] ->
- true;
- _ ->
- false
- end.
-
-
-
-get_included_IR_ID(G,ScopedId) ->
- S = ic_genobj:pragmatab(G),
- ScopedName = ic_util:to_undersc(ScopedId),
- [[Scope,Name,LNr]] = ets:match(S,{file_data_included,'_','_','_','$3','$4',ScopedName,'_','$7'}),
- {Prefix,Vsn,Id} = pragma_cover(S,Name,Scope,LNr),
- case Id of
- none ->
- case Prefix of
- none ->
- IR_ID =
- lists:flatten(io_lib:format("IDL:~s:~s",[ScopedName, Vsn])),
- ic_pragma:mk_alias(G,IR_ID,ScopedId),
- IR_ID;
- _ ->
- IR_ID =
- lists:flatten(io_lib:format("IDL:~s:~s",[Prefix ++ "/" ++ ScopedName, Vsn])),
- ic_pragma:mk_alias(G,IR_ID,ScopedId),
- IR_ID
- end;
- _ ->
- ic_pragma:mk_alias(G,Id,ScopedId),
- Id
- end.
-
-
-
-
-
-%% Returns the scope for object
-id2scope(G,IfrId) ->
- S = ic_genobj:pragmatab(G),
- case lookup(S,alias) of
- [] ->
- mk_scope(IfrId);
- AliasList ->
- case keysearch(IfrId,3,AliasList) of
- false ->
- mk_scope(IfrId);
- {value,{alias,ScopedId,_}} ->
- ScopedId
- end
- end.
-
-%% Returns a "standard" IDL ID by getting the scope list
-mk_id(ScopedId) ->
- "IDL:" ++ ic_pragma:slashify(ScopedId) ++ ":" ++ default_version().
-
-%% Returns the scope of an object when getting a "standard" IDL ID
-mk_scope(IfrId) ->
- [_,Body,_] = tokens(IfrId,":"),
- reverse(tokens(Body,"/")).
-
-
-
-%% This is used to note the exact compiled file
-%% under pragma creation. There are two options, the
-%% main file or files included by the main file. This
-%% just denotes the CURRENT file, the main file or
-%% the included ones. A very usual field is the file
-%% path that shows the include path of the file
-
-init_idlfile(G,S) ->
- IdlFile = idlfile(G),
- insert(S,{file,IdlFile,[]}).
-
-set_idlfile(S,FileName) ->
- FilePath = get_filepath(S),
- case FilePath of
- [] ->
- ets:delete(S,file),
- insert(S,{file,FileName,[FileName|FilePath]});
- _ ->
- case hd(FilePath) of
- [] ->
- ets:delete(S,file),
- insert(S,{file,FileName,[FileName|FilePath]});
- _ ->
- case tl(FilePath) of
- [] ->
- ets:delete(S,file),
- insert(S,{file,FileName,[FileName|FilePath]});
- _ ->
- case hd(tl(FilePath)) of
- [] ->
- ets:delete(S,file),
- insert(S,{file,FileName,[FileName|FilePath]});
- FileName ->
- ets:delete(S,file),
- insert(S,{dependency,FilePath}), % Add dependency branch
- insert(S,{file,FileName,tl(FilePath)});
- _ ->
- ets:delete(S,file),
- insert(S,{file,FileName,[FileName|FilePath]})
- end
- end
- end
- end.
-
-get_idlfile(S) ->
- [FT] = lookup(S,file),
- element(2,FT).
-
-get_filepath(S) ->
- [FT] = lookup(S,file),
- element(3,FT).
-
-
-%% This returns a list of file names
-%% that direct or indirect the current
-%% compiled file is depended on.
-get_dependencies(G) ->
- S = ic_genobj:pragmatab(G),
- case lookup(S,dependency) of
- [] ->
- [];
- Dependencies ->
- {get_idlfile(S),get_dependencies(Dependencies,[])}
- end.
-
-get_dependencies([],Dependencies) ->
- no_doubles(Dependencies);
-get_dependencies([{dependency,Path}|Tail],Current) ->
- get_dependencies(Tail,[hd(Path)|Current]).
-
-
-no_doubles(List) ->
- no_doubles(List,[]).
-
-no_doubles([],NoDoubles) ->
- NoDoubles;
-no_doubles([X|Xs],Current) ->
- case member(X,Xs) of
- true ->
- no_doubles(Xs,Current);
- false ->
- no_doubles(Xs,[X|Current])
- end.
-
-
-
-
-%% Pragma compilation status initialization
-init_pragma_status(S) ->
- insert(S,{status,true,0}).
-
-%% Pragma compilation status set to failure
-%% and count up the number of errors
-set_compilation_failure(S) ->
- [{status,_,ErrorNr}] = lookup(S,status),
- ets:delete(S,status),
- insert(S,{status,false,ErrorNr+1}).
-
-%% Pragma compilation status set to lookup
-get_pragma_compilation_status(S) ->
- [Status] = lookup(S,status),
- element(2,Status).
-
-%% Pragma error number
-get_pragma_error_nr(S) ->
- [Status] = lookup(S,status),
- element(3,Status).
-
-
-%% Short check
-is_short(N_str) when is_list(N_str) ->
- case is_short_decimal_str(N_str) of
- true ->
- true;
- false ->
- false
- end;
-is_short(N) when is_integer(N)->
- (N < 65535) and (N > -65536);
-is_short(_) -> false.
-
-
-%% Check if the string is a
-%% list of characters representing
-%% a short. Avoid crash !.
-is_short_decimal_str(N_str) ->
- case is_decimal_str(N_str) of
- true ->
- N = list_to_integer(N_str),
- (N < 65535) and (N > -65536);
- false ->
- false
- end.
-
-%% Check if the string is a
-%% list of characters representing
-%% decimals.
-is_decimal_str([]) ->
- true;
-is_decimal_str([First|Rest]) ->
- case is_decimal_char(First) of
- true ->
- is_decimal_str(Rest);
- false ->
- false
- end.
-
-%% True if D is a character
-%% representing a decimal (0-9).
-is_decimal_char(D) ->
- case (48=<D) and (D=<57) of
- true ->
- true;
- false ->
- false
- end.
-
-
-%% Prints out all the table
-print_tab(G) ->
- io:format("~nPragmaTab = ~p~n",[ets:tab2list(ic_genobj:pragmatab(G))]).
-
-
-list_to_term(List) ->
- case catch erl_scan:string(List) of
- {ok, Tokens, _} ->
- case erl_parse:parse_term(Tokens ++ [{dot, 1}]) of
- {ok,Term} ->
- Term;
- _ ->
- error
- end;
- _ ->
- error
- end.
-
-
-
-%% Cleanup all other code options for a specified scope
-%% in the same file, but the most dominant.
-cleanup_codeOptions(G,S,ScopedId) ->
- case ets:match(S,{codeopt,ScopedId,'$1','$2',idlfile(G),'$4'}) of
- [] ->
- %% No codeOpt directive is placed inside the
- %% currently compiled file. Try to find other
- %% directives located in included files.
- true;
- List ->
- %% A codeOpt directive is placed inside the
- %% currently compiled file. This dominates
- %% all other directives.
- CodeOption = best_positioned_codeOpt(List),
- %% Remove code options that do not affect
- %% the code production (redundant)
- remove_redundant_codeOpt(S,[ScopedId|CodeOption])
- end.
-
-
-%% Best positioned is the codeopt located
-%% "highest" on the SAME file, the one with
-%% lowest line number.
-best_positioned_codeOpt([X|Xs]) ->
- best_positioned_codeOpt(Xs,X).
-
-best_positioned_codeOpt([],Found) ->
- Found;
-best_positioned_codeOpt([X|Xs],Current) ->
- case hd(tl(X)) > hd(tl(Current)) of
- true ->
- best_positioned_codeOpt(Xs,Current);
- false ->
- best_positioned_codeOpt(Xs,X)
- end.
-
-
-remove_redundant_codeOpt(S,[ScopedId,CodeOption,LNr,FilePath]) ->
- ets:match_delete(S,{codeopt,ScopedId,'$1','$2','$3','$4'}),
- ets:insert(S,{codeopt,ScopedId,CodeOption,LNr,last(FilePath),FilePath}).
-
-
-
-
-add_inh_data(G,InclScope,X) ->
- S = ic_genobj:pragmatab(G),
- case X#interface.inherit of
- [] ->
- true;
- [InhBody] ->
- Scope = [get_id2(X)|InclScope],
- insert(S,{inherits,Scope,InhBody});
- InhList ->
- add_inh_data(G, S, InclScope, X, InhList)
- end.
-
-add_inh_data(_,_,_,_,[]) ->
- true;
-add_inh_data(G, S, InclScope, X, [InhBody|InhBodies]) ->
- Scope = [get_id2(X)|InclScope],
- insert(S, {inherits,Scope,InhBody}),
- add_inh_data(G, S, InclScope, X, InhBodies).
-
-
-%% Returns a default broker data
-defaultBrokerData(G) ->
- {to_atom(ic_genobj:impl(G)),transparent}.
-
-
-%% Loops through the form and sdds inheritence data
-preproc(G, N, [X|Xs]) when is_record(X, interface) ->
- %% Add inheritence data to pragmatab
- ic_pragma:add_inh_data(G,N,X),
- N2 = [get_id2(X) | N],
- preproc(G, N2, get_body(X)),
- lists:foreach(fun({_Name, Body}) -> preproc(G, N2, Body) end,
- X#interface.inherit_body),
- preproc(G, N, Xs);
-
-preproc(G,N,[X|Xs]) when is_record(X, module) ->
- N2 = [get_id2(X) | N],
- preproc(G, N2, get_body(X)),
- preproc(G,N,Xs);
-
-preproc(G,N,[_X|Xs]) ->
- preproc(G,N,Xs);
-
-preproc(_G, _N, []) ->
- ok.
-
-
-%% Returns a tuple / list of tuples { Mod, Type }
-%% Does not check overridence because it is the
-%% top scope for the module to be produced and
-%% cannot be overriden.
-getBrokerData(G,X,Scope) ->
- S = ic_genobj:pragmatab(G),
- cleanup_codeOptions(G,S,Scope),
-
- %% Check if it is an operation denoted
- case isOperation(S,Scope) of
- %% Yes, check options
- true ->
- %% Look if there is a specific code option on top file
- case hasSpecificCodeoptionOnTopFile(S,ic_genobj:idlfile(G),Scope) of
- true ->
- %% Yes, let it work
- getBrokerData(G,S,X,Scope,[Scope],[]);
- false ->
- %% No, try to see if there is codeoption on top file
- case hasNonSpecificCodeoptionOnTopFile(S,ic_genobj:idlfile(G)) of
- true ->
- %% Yes, override every other specific code option
- [_H|T] = Scope,
- getBrokerData(G,S,X,Scope,[T],[]);
- false ->
- %% No, let inherited specific code options work
- getBrokerData(G,S,X,Scope,[Scope],[])
- end
- end;
- %% No, continue
- false ->
- getBrokerData(G,S,X,Scope,[Scope],[])
- end.
-
-%% Returns a tuple / list of tuples { Mod, Type }
-%% Inside loop, uses overridence.
-getBrokerData(G,X,RS,Scope,CSF) ->
- S = ic_genobj:pragmatab(G),
- cleanup_codeOptions(G,S,Scope),
- OvScope = overridedFrom(S,RS,Scope),
- getBrokerData(G,S,X,RS,[OvScope],[OvScope|CSF]).
-
-
-
-getBrokerData(G,S,X,RS,[[[First]|Rest]],CSF) when is_integer(First) ->
- Scope = [[First]|Rest],
- case ets:match(S,{codeopt,Scope,'$1','_','_','_'}) of
- [] ->
- case ets:match(S,{inherits,Scope,'$1'}) of
- [] -> %% No inheritence, no pragma codeopt
- defaultBrokerData(G); %% Default
- [InhScope] ->
- getBrokerData(G,S,X,RS,InhScope,CSF);
- InhList ->
- getBrokerDataInh(G,S,X,RS,Scope,CSF,InhList)
- end;
- [[{broker,{Module,Type}}]] -> %% A branch only, with pragma codeopt
- {Module,Type};
- List -> %% Multiple branches with pragma codeopt
- flatten(List)
- end;
-
-getBrokerData(G,S,X,RS,[[[First]|Rest]],CSF) ->
- getBrokerDataLoop(G,S,X,RS,[[First]|Rest],CSF);
-
-getBrokerData(G,S,X,RS,[Scope],CSF) ->
- %io:format(" 1"),
- case ets:match(S,{codeopt,Scope,'$1','_','_','_'}) of
- [] ->
- %io:format(" 2"),
- case ets:match(S,{inherits,Scope,'$1'}) of
- [] -> %% No inheritence, no pragma codeopt
- %io:format(" 5"),
- defaultBrokerData(G); %% Default
- [InhScope] ->
- %io:format(" 6"),
- getBrokerData(G,S,X,RS,InhScope,CSF);
- InhList ->
- %io:format(" 7"),
- getBrokerDataInh(G,S,X,RS,Scope,CSF,InhList)
- end;
- [[{broker,{Module,Type}}]] -> %% A branch only, with pragma codeopt
- %io:format(" 3"),
- {Module,Type};
- List -> %% Multiple branches with pragma codeopt
- %io:format(" 4"),
- flatten(List)
- end.
-
-
-%% Special treatment when X is an operation
-getBrokerDataInh(G,S,X,RS,Scope,CSF,InhList) when is_record(X,op)->
- %io:format(" 8"),
- case ets:match(S,{op,get_id2(X),'$1','_','_'}) of
- [] ->
- %io:format(" 10"),
- CleanList = remove_inherited(S,InhList),
- getBrokerDataLoop(G,S,X,RS,CleanList,CSF);
-
- [[Scope]] ->
- %io:format(" 11"),
- CleanList = remove_inherited(S,InhList),
- getBrokerDataLoop(G,S,X,RS,CleanList,CSF);
-
- [[OpScope]] ->
- %io:format(" 12"),
- case member([OpScope],InhList) of
- true ->
- %io:format(" 14"),
- %% No inherited scopes
- getBrokerData(G,X,RS,OpScope,CSF);
- false ->
- %io:format(" 15"),
- %% Inherited scopes
- CleanList = remove_inherited(S,InhList),
- getBrokerDataLoop(G,S,X,RS,CleanList,CSF)
- end;
-
- ListOfOpScopes ->
- %io:format(" 13"),
- case get_inherited(S,Scope,ListOfOpScopes) of
- [[OpScope]] ->
- case member([OpScope],InhList) of
- true ->
- getBrokerData(G,X,RS,OpScope,CSF);
- false ->
- CleanList = remove_inherited(S,InhList),
- getBrokerDataLoop(G,S,X,RS,CleanList,CSF)
- end;
- _ ->
- CleanList = remove_inherited(S,InhList),
- getBrokerDataLoop(G,S,X,RS,CleanList,CSF)
- end
- end;
-%% Just add InhList after removing all inherited
-getBrokerDataInh(G,S,X,RS,_Scope,CSF,InhList) ->
- %io:format(" 9"),
- CleanList = remove_inherited(S,InhList),
- getBrokerDataLoop(G,S,X,RS,CleanList,CSF).
-
-
-
-
-%% Loops over a list of scopes
-getBrokerDataLoop(G,S,X,RS,List,CSF) ->
- getBrokerDataLoop(G,S,X,RS,List,[],CSF).
-
-getBrokerDataLoop(G,_,_X,_RS,[],BrokerDataList,_CSF) ->
- case no_doubles(BrokerDataList) of
- [BrokerData] -> %% No pragma codeopt / Multiple branches with pragma codeopt
- BrokerData;
- List ->
- DefaultBD = defaultBrokerData(G),
- case member(DefaultBD,List) of
- true ->
- %% Remove default, choose codeoption
- NewList = delete(DefaultBD,List),
- case NewList of
- [BData] -> %% A branch only, with pragma codeopt
- BData;
- _Other -> %% Multiple branches with pragma codeopt
- %%io:format("Multiple branches ~p~n",[Other]),
- NewList
- end;
- false -> %% Multiple branches with pragma codeopt
- flatten(List)
- end
- end;
-
-getBrokerDataLoop(G,S,X,RS,[[Scope]|Scopes],_Found,CSF) when is_integer(Scope) ->
- getBrokerData(G,S,X,RS,[[Scope]|Scopes],CSF);
-
-getBrokerDataLoop(G,S,X,RS,[[Scope]|Scopes],Found,CSF) ->
- %% Start from the beginning, check for overridings
- case member(overridedFrom(S,RS,Scope),CSF) of %% Avoid infinite loops
- true ->
- getBrokerDataLoop(G,S,X,RS,Scopes,Found,CSF);
- false ->
- BrokerData = getBrokerData(G,X,RS,Scope,CSF),
- getBrokerDataLoop(G,S,X,RS,Scopes,[BrokerData|Found],[Scope|CSF])
- end.
-
-
-
-
-%%%--------------------------------------
-%%% Finds out the overrider of a scope
-%%%--------------------------------------
-overridedFrom(S,RS,Scope) ->
- overridedFrom(S,RS,Scope,Scope).
-
-overridedFrom(S,RS,Last,Scope) ->
- case ets:match(S,{inherits,'$0',Scope}) of
- [] ->
- %% No inheritence, no pragma codeopt,
- %% choose the last scope.
- Last;
-
- [[RS]] ->
- %% Garbage, unused interface with pragma
- %% code option ! Danger !
- Last;
-
- [[InhScope]] ->
- case ets:match(S,{codeopt,InhScope,'$1','_','_','_'}) of
- [] ->
- %% InhScope has no code options, keep Last.
- overridedFrom(S,RS,Scope,InhScope);
- _ ->
- %% InhScope has code option, Last = InhScope.
- overridedFrom(S,RS,InhScope,InhScope)
- end;
- List ->
- %% Several inherit from Scope, choose the one feeseble,
- %% the one DIRECTLY inherited by Scope and not through
- %% other interface.
- case remove_inheriters(S,RS,List) of
- [] ->
- Scope;
- Removed ->
- Removed
- end
- end.
-
-%%%------------------------------------------------------
-%%% Removes all the scopes that inherit from others
-%%%------------------------------------------------------
-remove_inheriters(S,RS,InheriterList) ->
- DominantList =
- dominantList(S,InheriterList),
- ReducedInhList =
- [X || X <- InheriterList,
- member(X,DominantList)],
-
- case ReducedInhList of
- [] ->
- [];
- [_OneOnly] ->
- ReducedInhList;
- _Other ->
- CleanList =
- ets:match_object(S, {inherits,'_','_'}),
-% CodeOptList =
-% [X || X <- EtsList, element(1,X) == codeopt],
- NoInheriters =remove_inheriters2(S,ReducedInhList,CleanList),
-
- [ [X] || [X] <- NoInheriters,
- inherits(RS,X,CleanList)]
- end.
-
-remove_inheriters2(_,[A],_) ->
- [A];
-remove_inheriters2(_S,[A,B],EtsList) ->
- case remove_inh(A,B,[A,B],EtsList) of
- [[X]] ->
- X;
- List ->
- List
- end;
-remove_inheriters2(S,[A,B|Rest],EtsList) ->
- case remove_inh(A,B,[A,B|Rest],EtsList) of
- [A,B|Rest] ->
- [A,B|Rest];
- NewList ->
- remove_inheriters2(S,NewList,EtsList)
- end.
-
-remove_inh([X],[Y],List,EtsList) ->
- case inherits(X,Y,EtsList) of
- true ->
- delete([X],List);
- false ->
- case inherits(Y,X,EtsList) of
- true ->
- delete([Y],List);
- false ->
- List
- end
- end.
-
-
-
-%%%----------------------------------------------
-%%% Should remove all scope links that inherit
-%%% from others in the list
-%%%----------------------------------------------
-remove_inherited(S,InheriterList) ->
- CleanList =
- ets:match_object(S, {inherits, '_', '_'}),
- remove_inherited(S,InheriterList,CleanList).
-
-
-remove_inherited(_S,[A,B],EtsList) ->
- case remove_inhed(A,B,[A,B],EtsList) of
- [[X]] ->
- [[X]];
- List ->
- List
- end;
-remove_inherited(S,[A,B|Rest],EtsList) ->
- case remove_inhed(A,B,[A,B|Rest],EtsList) of
- [A,B|Rest] ->
- [A,B|Rest];
- NewList ->
- remove_inherited(S,NewList,EtsList)
- end.
-
-
-remove_inhed([X],[Y],List,EtsList) ->
- case inherits(X,Y,EtsList) of
- true ->
- delete([Y],List);
- false ->
- case inherits(Y,X,EtsList) of
- true ->
- delete([X],List);
- false ->
- List
- end
- end.
-
-
-
-
-
-
-
-%%%----------------------------------------------
-%%% Should return all scope links that is
-%% are inherited from scope in the list
-%%%----------------------------------------------
-get_inherited(S,Scope,OpScopeList) ->
- EtsList1 = ets:match(S, {inherits, Scope, '$1'}),
- [X || X <- EtsList1, member(X, OpScopeList)].
-
-
-
-
-
-
-
-%%%---------------------------------------------------
-%%% Returns a the list of scopes that have codeoption
-%%% from a list of scopes
-%%%---------------------------------------------------
-dominantList(S,IL) ->
- dominantList(S,IL,[]).
-
-dominantList(_S,[],Found) ->
- Found;
-dominantList(S,[[X]|Xs],Found) ->
- case ets:match(S,{codeopt,X,'$1','_','_','_'}) of
- [] ->
- dominantList(S,Xs,Found);
- _ ->
- dominantList(S,Xs,[[X]|Found])
- end.
-
-
-
-
-%%%---------------------------------------------------
-%%% Returns true if X direct or indirect inherits Y
-%%%---------------------------------------------------
-inherits(X,Y,EtsList) ->
- case member({inherits,X,Y},EtsList) of
- true ->
- %% Direct inherited
- true;
- false ->
- %% Indirectly inherited
- AllInh = [ B || {inherits,A,B} <- EtsList, A == X ],
- inherits(X,Y,AllInh,EtsList)
- end.
-
-inherits(_X,_Y,[],_EtsList) ->
- false;
-inherits(X,Y,[Z|Zs],EtsList) ->
- case inherits2(X,Y,Z,EtsList) of
- true ->
- true;
- false ->
- inherits(X,Y,Zs,EtsList)
- end.
-
-inherits2(_X,Y,Z,EtsList) ->
- case member({inherits,Z,Y},EtsList) of
- true ->
- true;
- false ->
- inherits(Z,Y,EtsList)
- end.
-
-
-
-%%
-%% is_inherited_by/3
-%%
-%% Returns :
-%%
-%% true if the first parameter is
-%% inherited by the second one
-%%
-%% false otherwise
-%%
-is_inherited_by(Interface1,Interface2,PragmaTab) ->
- InheritsList = ets:match_object(PragmaTab, {inherits, '_', '_'}),
- inherits(Interface2,Interface1,InheritsList).
-
-
-
-
-%% Filters all pragma prefix from list not in same file
-%% the object
-
-filter_pragma_prefix_list(PragmaTab, Name, Scope, List) ->
- IdlFile = scoped_names_idl_file(PragmaTab, Name, Scope),
- filter_pragma_prefix_list2(PragmaTab,IdlFile,List,[]).
-
-
-filter_pragma_prefix_list2(_,_,[],Found) ->
- Found;
-filter_pragma_prefix_list2(PT, IdlFile, [PP|PPs], Found) ->
- case PP of
- {prefix,_,_,_,IdlFile,_} -> %% Same file as the Object, keep
- filter_pragma_prefix_list2(PT, IdlFile, PPs, [PP|Found]);
-
- _Other -> %% NOT in same file as the Object, throw away
- filter_pragma_prefix_list2(PT, IdlFile, PPs, Found)
- end.
-
-scoped_names_idl_file(PragmaTab, Name, Scope) ->
- case ets:match(PragmaTab,{'_','$0','_','$2',Scope,Name,'_','_','_'}) of
- [[IdlFile, _Type]] -> %% Usual case
- IdlFile;
- [[_File,module]|_Files] -> %% Multiple modules, get LOCAL file
- case ets:match(PragmaTab,{file_data_local,'$0','_',module,Scope,Name,'_','_','_'}) of
- [[LocalIdlFile]] ->
- LocalIdlFile;
- _ -> %% Should NEVER occur
- error
- end;
-
- _ ->
- error %% Should NEVER occur
- end.
-
-
-
-
-
-
-%%-------------------------------------------------
-%%
-%% Register specific pragma code options
-%%
-%% If there is an operation with that
-%% scope, denote this as {codeopt_specific,Scope}
-%%
-%%-------------------------------------------------
-denote_specific_code_opts(G) ->
- case ic_options:get_opt(G, be) of
- noc ->
- S = ic_genobj:pragmatab(G),
- COList = ets:match(S,{codeopt,'$0','_','_','_','_'}),
- OPList = ets:match(S,{op,'$0','$1','_','_'}),
- denote_specific_code_opts(S,COList,OPList);
- _ ->
- ok
- end.
-
-denote_specific_code_opts(_,_,[]) ->
- ok;
-denote_specific_code_opts(S,COList,[[OpN,OpS]|OPSs]) ->
- case lists:member([[OpN|OpS]],COList) of
- true ->
- insert(S, {codeopt_specific,[OpN|OpS]});
- false ->
- ok
- end,
- denote_specific_code_opts(S,COList,OPSs).
-
-
-
-%%---------------------------------------------
-%%
-%% Returns true/false if it denotes an operation
-%%
-%%---------------------------------------------
-isOperation(_S,[]) ->
- false;
-isOperation(_S,[_]) ->
- false;
-isOperation(S,[H|T]) ->
- case ets:match(S,{op,H,T,'$2','$3'}) of
- [] ->
- false;
- _ ->
- true
- end.
-
-
-hasSpecificCodeoptionOnTopFile(S,File,Scope) ->
- case ets:match(S,{codeopt,Scope,'_','$2',File,[File]}) of
- [] ->
- false;
- _ ->
- true
- end.
-
-
-hasNonSpecificCodeoptionOnTopFile(S,File) ->
- case ets:match(S,{codeopt,'_','_','$2',File,[File]}) of
- [] ->
- false;
- _ ->
- true
- end.
-
-
-
-%%---------------------------------------------
-%%
-%% Returns {ok,IfrId}/error when searching a random local type
-%%
-%%---------------------------------------------
-
-
-fetchRandomLocalType(G) ->
-
- S = ic_genobj:pragmatab(G),
-
- case ets:match(S,{file_data_local,'_','_','$2','$3','$4','_','_','_'}) of
- [] ->
- false;
-
- List ->
- fetchRandomLocalType(S,List)
- end.
-
-
-fetchRandomLocalType(_,[]) ->
- false;
-fetchRandomLocalType(S,[[module|_]|Tail]) ->
- fetchRandomLocalType(S,Tail);
-fetchRandomLocalType(S,[[_,Scope,Name]|Tail]) ->
- case ets:match(S,{alias,[Name|Scope],'$1'}) of
- [] ->
- fetchRandomLocalType(S,Tail);
- [[IfrId]] ->
- {ok,IfrId}
- end.
-
-
-
-%%---------------------------------------------
-%%
-%% Returns A list of local operation mapping
-%% for a given scope
-%%
-%%---------------------------------------------
-
-
-fetchLocalOperationNames(G,I) ->
- S = ic_genobj:pragmatab(G),
- case ets:match(S,{file_data_local,'_','_',op,I,'$4','_','_','_'}) of
- [] ->
- [];
- List ->
- fetchLocalOperationNames2(List,[])
- end.
-
-fetchLocalOperationNames2([],Found) ->
- lists:reverse(Found);
-fetchLocalOperationNames2([[Name]|Names],Found) ->
- fetchLocalOperationNames2(Names,[Name|Found]).
-
-
-
-%%------------------------------------------------
-%%
-%% Returns a true if this scoped id is a local
-%% one, false otherwise
-%%
-%%------------------------------------------------
-is_local(G,ScopedId) ->
- S = ic_genobj:pragmatab(G),
- Name = ic_util:to_undersc(ScopedId),
- case ets:match(S,{file_data_local,'_','_','_',tl(ScopedId),'_',Name,'_','_'}) of
- [[]] ->
- true;
- _ ->
- false
- end.
diff --git a/lib/ic/src/ic_sequence_java.erl b/lib/ic/src/ic_sequence_java.erl
deleted file mode 100644
index f4873a0691..0000000000
--- a/lib/ic/src/ic_sequence_java.erl
+++ /dev/null
@@ -1,240 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(ic_sequence_java).
-
-
--include("icforms.hrl").
--include("ic.hrl").
--include("ic_debug.hrl").
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([gen/4]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-%%-----------------------------------------------------------------
-%% External functions
-%%-----------------------------------------------------------------
-
-%%-----------------------------------------------------------------
-%% Func: gen/4
-%%-----------------------------------------------------------------
-gen(G, N, X, SequenceName) when is_record(X, sequence) ->
- emit_holder_class(G, N, X, SequenceName),
- emit_helper_class(G, N, X, SequenceName);
-gen(_G, _N, _X, _SequenceName) ->
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-
-
-%%-----------------------------------------------------------------
-%% Func: emit_holder_class/4
-%%-----------------------------------------------------------------
-emit_holder_class(G, N, X, SequenceName) ->
- SName = string:concat(SequenceName, "Holder"),
- {Fd, _}= ic_file:open_java_file(G, N, SName),
-
- SequenceType = ic_java_type:getType(G, N, X),
-
- ic_codegen:emit(Fd, ["final public class ",SequenceName,"Holder {\n"
- " // instance variables\n"
- " public ",SequenceType," value;\n\n"
- " // constructors\n"
- " public ",SequenceName,"Holder() {}\n"
- " public ",SequenceName,"Holder(",SequenceType," initial) {\n"
- " value = initial;\n"
- " }\n\n"
-
- " // methods\n"
-
- " public void _marshal(",?ERLANGPACKAGE,"OtpOutputStream out) throws java.lang.Exception{\n"
- " ",SequenceName,"Helper.marshal(out, value);\n"
- " }\n\n"
-
- " public void _unmarshal(",?ERLANGPACKAGE,"OtpInputStream in) throws java.lang.Exception {\n"
- " value = ",SequenceName,"Helper.unmarshal(in);\n"
- " }\n\n"
- "}\n"]),
- file:close(Fd).
-
-
-
-emit_helper_class(G, N, X, SequenceName) ->
- SName = string:concat(SequenceName, "Helper"),
- {Fd, _}= ic_file:open_java_file(G, N, SName),
-
- SequenceType = ic_java_type:getType(G, N, X),
- ElementType = ic_forms:get_type(X),
-
- ic_codegen:emit(Fd, ["public class ",SequenceName,"Helper {\n"
-
- " // constructors\n"
- " private ",SequenceName,"Helper() {}\n\n"
-
- " // methods\n"
- " public static void marshal(",?ERLANGPACKAGE,"OtpOutputStream _out, ",SequenceType," _value) \n"
- " throws java.lang.Exception {\n\n"]),
-
- emit_sequence_marshal_function(G, N, X, Fd, SequenceName, ElementType),
-
- ic_codegen:emit(Fd, [" }\n\n"
-
- " public static ",SequenceType," unmarshal(",?ERLANGPACKAGE,"OtpInputStream _in) \n"
- " throws java.lang.Exception {\n\n"]),
-
- emit_sequence_unmarshal_function(G, N, X, Fd, SequenceName, ElementType),
-
- ic_codegen:emit(Fd, [" }\n\n"
-
- " public static String id() {\n"
- " return \"",ic_pragma:scope2id(G, [SequenceName | N]),"\";\n"
- " }\n\n"
-
- " public static String name() {\n"
- " return \"",SequenceName,"\";\n"
- " }\n\n"]),
-
- ic_jbe:emit_type_function(G, N, X, Fd),
-
- ic_codegen:emit(Fd, [" public static void insert(",?ICPACKAGE,"Any _any, ",SequenceType," _this)\n"
- " throws java.lang.Exception {\n\n"
-
- " ",?ERLANGPACKAGE,"OtpOutputStream _os = \n"
- " new ",?ERLANGPACKAGE,"OtpOutputStream();\n\n"
-
- " _any.type(type());\n"
- " marshal(_os, _this);\n"
- " _any.insert_Streamable(_os);\n"
- " }\n\n"
-
- " public static ",SequenceType," extract(",?ICPACKAGE,"Any _any)\n"
- " throws java.lang.Exception {\n\n"
-
- " return unmarshal(_any.extract_Streamable());\n"
- " }\n\n"
-
-
- %% In corba mapping there is also a _type function here.
- "}\n\n"]),
- file:close(Fd).
-
-
-%%-----------------------------------------------------------------
-%% Func: emit_sequence_marshal_function/6
-%%-----------------------------------------------------------------
-emit_sequence_marshal_function(G, N, X, Fd, _SequenceName, ElementType) ->
- ic_codegen:emit(Fd, [" int _length = _value.length;\n\n"
-
- " _out.write_list_head(_length);\n\n"
-
- " if (_length > 0) {\n"
- " for(int _tmp = 0; _tmp < _length; _tmp++)\n"]),
-
- case ic_java_type:isBasicType(G, N, ElementType) of
- true ->
- ic_codegen:emit(Fd, [" _out",ic_java_type:marshalFun(G, N, X, ElementType),"(_value[_tmp]);\n\n"]);
- false ->
- ic_codegen:emit(Fd, [" ",ic_java_type:marshalFun(G, N, X, ElementType),"(_out, _value[_tmp]);\n\n"])
- end,
-
- ic_codegen:emit(Fd, [" _out.write_nil();\n"
- " }\n\n"]).
-
-
-
-
-%%-----------------------------------------------------------------
-%% Func: emit_sequence_unmarshal_function/6
-%%-----------------------------------------------------------------
-emit_sequence_unmarshal_function(G, N, X, Fd, _SequenceName, ElementType) ->
-
- SequenceElementType = ic_java_type:getType(G, N, ElementType),
-
- ic_codegen:emit(Fd, [" int _tag,_length;\n"
- " ",SequenceElementType," _sequence[];\n"
- " _tag = _in.peek();\n\n"]),
-
- case ic_java_type:isIntegerType(G, N, ElementType) of
- true ->
- ic_codegen:emit(Fd, [" switch(_tag) {\n"
- " case ",?ERLANGPACKAGE,"OtpExternal.stringTag:\n"
- " byte _compressed[] = (_in.read_string()).getBytes();\n"
- " _length = _compressed.length;\n"
- " _sequence = new ",ic_java_type:getFullType(G,N,X),";\n\n"
-
- " for(int _tmp = 0; _tmp < _length; _tmp++)\n"
- " _sequence[_tmp] = (",ic_java_type:getType(G, N, ElementType),")(_compressed[_tmp] & 0xff);\n\n"
-
- " break;\n"
- " default:\n"
- " _length = _in.read_list_head();\n"
- " _sequence = new ",ic_java_type:getFullType(G,N,X),";\n\n"
-
- " if(_length > 0) {\n"
- " for(int _tmp = 0; _tmp < _length; _tmp++)\n"
- " _sequence[_tmp] = _in",ic_java_type:unMarshalFun(G, N, X, ElementType),";\n\n"
-
- " _in.read_nil();\n"
- " }\n"
- " }\n"]);
- false ->
- ic_codegen:emit(Fd, [" _length = _in.read_list_head();\n"
- " _sequence = new ",ic_java_type:getFullType(G,N,X),";\n\n"
-
- " if(_length > 0) {\n"
- " for(int _tmp = 0; _tmp < _length; _tmp++)\n"]),
- case ic_java_type:isBasicType(G, N, ElementType) of
- true ->
- ic_codegen:emit(Fd, [" _sequence[_tmp] = _in",ic_java_type:unMarshalFun(G, N, X, ElementType),";\n\n"]);
- _ ->
- ic_codegen:emit(Fd, [" _sequence[_tmp] = ",ic_java_type:getUnmarshalType(G, N, X, ElementType),".unmarshal(_in);\n\n"])
- end,
-
- ic_codegen:emit(Fd, [" _in.read_nil();\n"
- " }\n\n"])
- end,
-
- ic_codegen:emit(Fd, " return _sequence;\n").
-
-
-
-
-%%---------------------------------------------------
-%% Utilities
-%%---------------------------------------------------
-
-
-
-
-
-
-
-
-
diff --git a/lib/ic/src/ic_struct_java.erl b/lib/ic/src/ic_struct_java.erl
deleted file mode 100644
index 94b98f6c52..0000000000
--- a/lib/ic/src/ic_struct_java.erl
+++ /dev/null
@@ -1,315 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(ic_struct_java).
-
--include("icforms.hrl").
--include("ic.hrl").
--include("ic_debug.hrl").
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([gen/3]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-%%-----------------------------------------------------------------
-%% External functions
-%%-----------------------------------------------------------------
-gen(G, N, X) when is_record(X, struct) ->
- StructName = ic_forms:get_java_id(X),
- WireStructName = ic_forms:get_id2(X),
- emit_struct_class(G, N, X, StructName),
- emit_holder_class(G, N, X, StructName),
- emit_helper_class(G, N, X, StructName, WireStructName),
- N2 = [StructName ++ "Package" |N],
- ic_jbe:gen(G, N2, ic_forms:get_body(X));
-gen(_G, _N, _X) ->
- ok.
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-
-%%-----------------------------------------------------------------
-%% Func: emit_struct_class/4
-%%-----------------------------------------------------------------
-emit_struct_class(G, N, X, StructName) ->
- {Fd, _}= ic_file:open_java_file(G, N, StructName),
-
- MList = struct_member_list(G, N, X),
- ArgList = gen_parameter_list(G, [ StructName ++ "Package" |N], X, MList),
-
- ic_codegen:emit(Fd, ["final public class ",StructName," {\n"
- " // instance variables\n"]),
-
- emit_struct_members_declarations(G, [StructName ++ "Package" |N],
- X, Fd, MList),
-
- ic_codegen:emit(Fd, ["\n // constructors\n"
- " public ",StructName,"() {}\n\n"
-
- " public ",StructName,"(",ArgList,") {\n"]),
-
- emit_struct_members_initialisation(G, N, X, Fd, MList),
-
- ic_codegen:emit(Fd, [" }\n\n"
-
- "}\n\n"]),
- file:close(Fd).
-
-
-%%-----------------------------------------------------------------
-%% Func: emit_holder_class/4
-%%-----------------------------------------------------------------
-emit_holder_class(G, N, _X, StructName) ->
- SName = string:concat(StructName, "Holder"),
- {Fd, _}= ic_file:open_java_file(G, N, SName),
-
- ic_codegen:emit(Fd, ["final public class ",StructName,"Holder {\n"
-
- " // instance variables\n"
- " public ",StructName," value;\n\n"
-
- " // constructors\n"
- " public ",StructName,"Holder() {}\n\n"
-
- " public ",StructName,"Holder(",StructName," initial) {\n"
- " value = initial;\n"
- " }\n\n"
-
- " // methods\n"]),
-
- ic_codegen:emit(Fd, [" public void _marshal(",?ERLANGPACKAGE,"OtpOutputStream out) throws java.lang.Exception {\n"
- " ",StructName,"Helper.marshal(out, value);\n"
- " }\n\n"
-
- " public void _unmarshal(",?ERLANGPACKAGE,"OtpInputStream in) throws java.lang.Exception {\n"
- " value = ",StructName,"Helper.unmarshal(in);\n"
- " }\n"
-
- "}\n\n"]),
- file:close(Fd).
-
-%%-----------------------------------------------------------------
-%% Func: emit_helper_class/5
-%%-----------------------------------------------------------------
-emit_helper_class(G, N, X, StructName, WireStructName) ->
- SName = string:concat(StructName, "Helper"),
- {Fd, _}= ic_file:open_java_file(G, N, SName),
-
- ic_codegen:emit(Fd, ["public class ",StructName,"Helper {\n"
-
- " // constructors\n"
- " private ",StructName,"Helper() {}\n\n"
-
- " // methods\n"]),
-
- MList = struct_member_list(G, N, X),
-
- ic_codegen:emit(Fd, [" public static void marshal(",?ERLANGPACKAGE,"OtpOutputStream _out, ",StructName," _value)\n"
- " throws java.lang.Exception {\n\n"]),
-
- emit_struct_marshal_function(G, N, X, Fd, StructName, WireStructName, MList),
-
- ic_codegen:emit(Fd, [" }\n\n"
-
- " public static ",StructName," unmarshal(",?ERLANGPACKAGE,"OtpInputStream _in)\n"
- " throws java.lang.Exception {\n\n"]),
-
- emit_struct_unmarshal_function(G, N, X, Fd, StructName, WireStructName, MList),
-
- ic_codegen:emit(Fd, [" }\n\n"
-
- " public static String id() {\n"
- " return \"",ictk:get_IR_ID(G, N, X),"\";\n"
- " }\n\n"
-
- " public static String name() {\n"
- " return \"",StructName,"\";\n"
- " }\n\n"]),
-
- ic_jbe:emit_type_function(G, N, X, Fd),
-
- ic_codegen:emit(Fd, [" public static void insert(",?ICPACKAGE,"Any _any, ",StructName," _this)\n"
- " throws java.lang.Exception {\n\n"
-
- " ",?ERLANGPACKAGE,"OtpOutputStream _os = \n"
- " new ",?ERLANGPACKAGE,"OtpOutputStream();\n\n"
-
- " _any.type(type());\n"
- " marshal(_os, _this);\n"
- " _any.insert_Streamable(_os);\n"
- " }\n\n"
-
- " public static ",StructName," extract(",?ICPACKAGE,"Any _any)\n"
- " throws java.lang.Exception {\n\n"
-
- " return unmarshal(_any.extract_Streamable());\n"
- " }\n\n"
-
-
- %% In corba mapping there is also a _type function here.
- "}\n"]),
- file:close(Fd).
-
-
-%%-----------------------------------------------------------------
-%% Func: emit_struct_members_declarations/
-%%-----------------------------------------------------------------
-emit_struct_members_declarations(_, _, _, _, []) ->
- ok;
-emit_struct_members_declarations(G, N, X, Fd, [{Member, _Type, Id} | MList]) ->
- ic_codegen:emit(Fd, [" public ",ic_java_type:getType(G, N, Member)," ",Id,";\n"]),
- emit_struct_members_declarations(G, N, X, Fd, MList).
-
-
-
-%%-----------------------------------------------------------------
-%% Func: emit_struct_members_initialisation/5
-%%-----------------------------------------------------------------
-emit_struct_members_initialisation(_, _, _, _, []) ->
- ok;
-emit_struct_members_initialisation(G, N, X, Fd, [{_Member, _Type, Id} | MList]) ->
- ic_codegen:emit(Fd, [" ",Id," = _",Id,";\n"]),
- emit_struct_members_initialisation(G, N, X, Fd, MList).
-
-
-
-
-%%-----------------------------------------------------------------
-%% Func: emit_struct_marshal_function/7
-%%-----------------------------------------------------------------
-emit_struct_marshal_function(G, N, X, Fd, StructName, WireStructName, MList) ->
-
- ic_codegen:emit(Fd, [" _out.write_tuple_head(",integer_to_list(length(MList) + 1),");\n"
- " _out.write_atom(\"",ic_util:to_undersc([WireStructName|N]),"\");\n\n"]),
-
- emit_struct_marshal_function_loop(G, [StructName ++ "Package" |N],
- X, Fd, MList, 1).
-
-%%-----------------------------------------------------------------
-%% Func: emit_struct_marshal_function_loop/6
-%%-----------------------------------------------------------------
-emit_struct_marshal_function_loop(_, _, _, Fd, [], _) ->
- ic_codegen:nl(Fd);
-emit_struct_marshal_function_loop(G, N, X, Fd, [{Member, Type, Id} |MList], Num) ->
-
- case ic_java_type:isBasicType(G, N, Member) of
- true ->
- ic_codegen:emit(Fd, [" _out",ic_java_type:marshalFun(G, N, Member, Type),"(_value.",Id,");\n"]);
- _ ->
- if (element(1,hd(element(3,Member))) == array) ->
- ic_codegen:emit(Fd,
- [" ",
- ic_util:to_dot(G,[ic_forms:get_id2(Member)|N]),
- "Helper.marshal(_out, _value.",Id,");\n"]);
- true ->
- ic_codegen:emit(Fd, [" ",
- ic_java_type:marshalFun(G, N, Member, Type),
- "(_out, _value.",Id,");\n"])
- end
- end,
-
- emit_struct_marshal_function_loop(G, N, X, Fd, MList, Num+1).
-
-
-
-
-%%-----------------------------------------------------------------
-%% Func: emit_struct_unmarshal_function/7
-%%-----------------------------------------------------------------
-emit_struct_unmarshal_function(G, N, X, Fd, StructName, WireStructName, MList) ->
-
- ic_codegen:emit(Fd, [" _in.read_tuple_head();\n\n"
-
- " if ((_in.read_atom()).compareTo(\"",
- ic_util:to_undersc([WireStructName|N]),
- "\") != 0)\n"
- " throw new java.lang.Exception(\"\");\n\n"
-
- " ",StructName," _value = new ",StructName,"();\n"]),
-
- emit_struct_unmarshal_function_loop(G, [StructName ++ "Package"|N],
- X, Fd, MList, 1),
-
- ic_codegen:emit(Fd, " return _value;\n").
-
-%%-----------------------------------------------------------------
-%% Func: emit_union_unmarshal_function_loop/6
-%%-----------------------------------------------------------------
-emit_struct_unmarshal_function_loop(_, _, _, Fd, [], _) ->
- ic_codegen:nl(Fd);
-emit_struct_unmarshal_function_loop(G, N, X, Fd, [{Member, Type, Id} |MList], Num) ->
-
- case ic_java_type:isBasicType(G, N, Member) of
- true ->
- ic_codegen:emit(Fd, [" _value.",Id," = _in",ic_java_type:unMarshalFun(G, N, Member, Type),";\n"]);
- _ ->
- if (element(1,hd(element(3,Member))) == array) ->
- ic_codegen:emit(Fd,
- [" _value.",Id," = ",ic_util:to_dot(G,[ic_forms:get_id2(Member)|N]),"Helper.unmarshal(_in);\n"]);
- true ->
- ic_codegen:emit(Fd,
- [" _value.",Id," = ",ic_java_type:getUnmarshalType(G, N, Member, Type),".unmarshal(_in);\n"])
- end
- end,
-
- emit_struct_unmarshal_function_loop(G, N, X, Fd, MList, Num +1).
-
-
-
-%%-----------------------------------------------------------------
-%% Func: gen_parameter_list/4
-%%-----------------------------------------------------------------
-gen_parameter_list(G, N, _X, [{Member, _Type, Id}]) ->
- ic_java_type:getType(G,N,Member) ++
- " _" ++
- ic_util:to_list(Id);
-gen_parameter_list(G, N, X, [{Member, _Type, Id} | MList]) ->
- ic_java_type:getType(G,N,Member) ++
- " _" ++
- ic_util:to_list(Id) ++
- ", " ++
- gen_parameter_list(G, N, X, MList).
-
-
-%%-----------------------------------------------------------------
-%% Func: struct_member_list/3
-%%-----------------------------------------------------------------
-struct_member_list(_G, _N, X) ->
- M = lists:map(
- fun(Member) ->
- lists:map(
- fun(Id) ->
- Type = ic_forms:get_type(Member),
- { Member, Type, ic_forms:get_java_id(Id)}
- end,
- ic_forms:get_idlist(Member))
- end,
- ic_forms:get_body(X)),
- lists:flatten(M).
-
-
-
diff --git a/lib/ic/src/ic_symtab.erl b/lib/ic/src/ic_symtab.erl
deleted file mode 100644
index 037d004049..0000000000
--- a/lib/ic/src/ic_symtab.erl
+++ /dev/null
@@ -1,235 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(ic_symtab).
-
-
--include_lib("ic/src/ic.hrl").
--include_lib("ic/src/icforms.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([new/0, store/3, retrieve/2, soft_retrieve/2, intf_resolv/3]).
--export([get_full_scoped_name/3, scoped_id_new_global/1, scoped_id_new/1]).
--export([scoped_id_strip/1,symtab_add_faked_included_types/1]).
--export([scoped_id_is_global/1, scoped_id_add/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-%%-----------------------------------------------------------------
-%% External functions
-%%-----------------------------------------------------------------
-
-
-%%--------------------------------------------------------------------
-%%
-%% Symbol table routines
-%%
-%% Symbol tables handles mappings Id -> Value, where Id is an
-%% ordinary Id from the parser (or a string) and value is an
-%% arbitrary term.
-%%
-%%--------------------------------------------------------------------
-
-%%-----------------------------------------------------------------
-%% Func: new/0 (used to be symtab_new)
-%%-----------------------------------------------------------------
-new() ->
- ets:new(symtab, [set, public]).
-
-%%-----------------------------------------------------------------
-%% Func: store/3 (used to be symtab_store)
-%%-----------------------------------------------------------------
-store(G, N, X) ->
- Name = [ic_forms:get_id2(X) | N],
- %%io:format("Adding id: ~p~n", [N]),
- case soft_retrieve(G, Name) of
- {error, _} ->
- ets:insert(G#genobj.symtab, {Name, X});
- {ok, Y} when is_record(Y, forward) ->
- ets:insert(G#genobj.symtab, {Name, X});
- {ok, Y} when is_record(Y, constr_forward) ->
- ets:insert(G#genobj.symtab, {Name, X});
- {ok, _Y} ->
- ic_error:error(G, {multiply_defined, X})
- end.
-
-
-%%-----------------------------------------------------------------
-%% Func: retrieve/2 (used to be symtab_retrieve)
-%%
-%% Makes a lookup in the symbol table for Id. Will throw
-%% not_found if it fails.
-%%-----------------------------------------------------------------
-retrieve(G, Id) ->
- case ets:lookup(G#genobj.symtab, Id) of
- [{_, Val}] -> Val;
- [] -> ic_error:error(G, {symtab_not_found, Id})
- end.
-
-
-%%-----------------------------------------------------------------
-%% Func: soft_retrieve/2 (used to be symtab_soft_retrieve)
-%%
-%% Same as retrieve but will use tagged return values.
-%%
-%%-----------------------------------------------------------------
-soft_retrieve(G, Id) ->
- case ets:lookup(G#genobj.symtab, Id) of
- [{_, Val}] -> {ok, Val};
- [] -> {error, {symtab_not_found, Id}}
- end.
-
-
-%%-----------------------------------------------------------------
-%% Func: intf_resolv/3 and resolv2/3
-%% (used to be symtab_intf_resolv and symtab_intf_resolv2)
-%%
-%% Tries to resolv the interface identifier reference. The id can
-%% be either a scoped name or an standard identifier. The
-%% function returns a global reference to the id.
-%%
-%% Will throw not_found if the id really cannot be found. Will
-%% throw illegal_forward if any forward references are founf in
-%% the inheritance list.
-%%
-%%-----------------------------------------------------------------
-intf_resolv(G, Scope, Id) ->
- case scoped_id_is_global(Id) of
- true ->
- retrieve(G, Id),
- Id;
- false ->
- intf_resolv2(G, Scope, Id)
- end.
-
-intf_resolv2(G, Scope, Id) ->
- N = scoped_id_add(Scope, Id),
- case soft_retrieve(G, scoped_id_strip(N)) of
- {ok, F} when is_record(F, forward) ->
- ic_error:error(G, {illegal_forward, Id}), [];
- {ok, _Val} ->
- scoped_id_mk_global(N);
- _ ->
- case scoped_id_is_top(Scope) of
- false ->
- intf_resolv2(G, scoped_id_up_one(Scope), Id);
- true ->
- ic_error:error(G, {symtab_not_found, Id}), []
- end
- end.
-
-
-
-%%--------------------------------------------------------------------
-%%
-%% Scoped id routines
-%%
-%% A scoped id is an id written as M::Id in IDL. Scoped ids are
-%% implemented as lists of id in reverse order, so M1::F1 becomes
-%% [F1, M1].
-%%
-%%--------------------------------------------------------------------
-
-get_full_scoped_name(G, N, S) when element(1, S) == scoped_id ->
- ictype:scoped_lookup(G, ic_genobj:tktab(G), N, S).
-
-scoped_id_new_global(Id) ->
- X=scoped_id_new(Id), X#scoped_id{type=global}.
-
-scoped_id_new(Id) ->
- #scoped_id{line=ic_forms:get_line(Id), id=[ic_forms:get_id(Id)]}.
-
-%% Adds one more id to the list of ids
-scoped_id_add(S1, S2) when is_record(S2, scoped_id) ->
- S1#scoped_id{id=S2#scoped_id.id ++ S1#scoped_id.id,
- line=S2#scoped_id.line};
-scoped_id_add(S, Id) ->
- S#scoped_id{id=[ic_forms:get_id(Id) | S#scoped_id.id], line=ic_forms:get_line(Id)}.
-
-
-scoped_id_mk_global(S) -> S#scoped_id{type=global}.
-
-scoped_id_is_global(S) when is_record(S, scoped_id), S#scoped_id.type==global ->
- true;
-scoped_id_is_global(_) -> false.
-
-%% Top level scope (i.e no more cd ..)
-scoped_id_is_top(S) when S#scoped_id.id==[] -> true;
-scoped_id_is_top(_) -> false.
-
-
-scoped_id_up_one(S) -> S#scoped_id{id=tl(S#scoped_id.id)}. % cd .. in scope
-%%scoped_id_get_def(S) -> hd(S#scoped_id.id). % Last added id
-scoped_id_strip(S) -> S#scoped_id.id. % Strips all junk
-
-
-
-
-% Add CORBA::<Types> that as if they
-% were defined in an included file.
-% This is only supported in the case
-% of Corba backend
-symtab_add_faked_included_types(G) ->
- case ic_options:get_opt(G, be) of
- false ->
- %% Add TypeCode as if it were defiend in included file
- ets:insert(G#genobj.symtab, {["CORBA"],
- {interface,{'<identifier>',0,"TypeCode"},
- [],
- [],
- [],
- {tk_objref,
- "IDL:omg.org/CORBA/TypeCode:1.0",
- "TypeCode"}}});
- erl_corba ->
- %% Add TypeCode as if it were defiend in included file
- ets:insert(G#genobj.symtab, {["CORBA"],
- {interface,{'<identifier>',0,"TypeCode"},
- [],
- [],
- [],
- {tk_objref,
- "IDL:omg.org/CORBA/TypeCode:1.0",
- "TypeCode"}}});
- erl_template ->
- %% Add TypeCode as if it were defiend in included file
- ets:insert(G#genobj.symtab, {["CORBA"],
- {interface,{'<identifier>',0,"TypeCode"},
- [],
- [],
- [],
- {tk_objref,
- "IDL:omg.org/CORBA/TypeCode:1.0",
- "TypeCode"}}});
- _ ->
- ok
- end.
-
-
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
diff --git a/lib/ic/src/ic_union_java.erl b/lib/ic/src/ic_union_java.erl
deleted file mode 100644
index 14d585b0a4..0000000000
--- a/lib/ic/src/ic_union_java.erl
+++ /dev/null
@@ -1,755 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
-
--module(ic_union_java).
-
--include("icforms.hrl").
--include("ic.hrl").
--include("ic_debug.hrl").
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([gen/3]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-%%-----------------------------------------------------------------
-%% External functions
-%%-----------------------------------------------------------------
-
-%%-----------------------------------------------------------------
-%% Func: gen/3
-%%-----------------------------------------------------------------
-gen(G, N, X) when is_record(X, union) ->
-
- %% Create a TK value if not existed
- %% Should be integrated in fetchTk
- %% instead
- NewX = case ic_forms:get_tk(X) of
- undefined ->
- S = ic_genobj:tktab(G),
- Tk = ictype:tk(G, S, N, X),
- #union{ id = X#union.id,
- type = X#union.type,
- body = X#union.body,
- tk = Tk };
- _Tk ->
- X
- end,
-
- UnionName = ic_forms:get_java_id(NewX),
- WiredUnionName = ic_forms:get_id2(NewX),
- N2 = [UnionName ++ "Package"|N],
- %%?PRINTDEBUG2("Recursive call over type ~p",
- %% [[ic_forms:get_type(NewX)]]),
- ic_jbe:gen(G, N, [ic_forms:get_type(NewX)]),
- %%?PRINTDEBUG2("Recursive call over body: ~p",
- %% [ic_forms:get_body(NewX)]),
- ic_jbe:gen(G, N2, ic_forms:get_body(NewX)),
-
- emit_union_class(G, N, NewX, UnionName),
- emit_holder_class(G, N, NewX, UnionName),
- emit_helper_class(G, N, NewX, UnionName, WiredUnionName);
-gen(_G, _N, _X) ->
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-
-%%-----------------------------------------------------------------
-%% Func: emit_union_class/4
-%%-----------------------------------------------------------------
-emit_union_class(G, N, X, UnionName) ->
- {Fd, _} = ic_file:open_java_file(G, N, UnionName),
-
- DiscrType = ic_java_type:getType(G, [UnionName ++ "Package"|N],
- ic_forms:get_type(X)),
-
- MList = union_member_list(G, N, X, DiscrType),
-
- ic_codegen:emit(Fd, "final public class ~s {\n",[UnionName]),
-
- ic_codegen:emit(Fd, " // instance variables\n", []),
- ic_codegen:emit(Fd, " private boolean _initialized;\n", []),
- ic_codegen:emit(Fd, " private ~s _discriminator;\n", [DiscrType]),
- ic_codegen:emit(Fd, " private java.lang.Object _value;\n", []),
-
- {tk_union,_, _,DiscrTk, _, _} = ic_forms:get_tk(X),
-
- DV = get_default_val(G, [UnionName |N], DiscrType, DiscrTk, MList),
-
- case DV of
- none -> %% all values in case
- ok;
- _ ->
- ic_codegen:emit(Fd, " private ~s _default = ~s;\n",
- [DiscrType, DV])
- end,
-
- ic_codegen:nl(Fd),
- ic_codegen:emit(Fd, " // constructors\n", []),
-
- ic_codegen:emit(Fd, " public ~s() {\n", [UnionName]),
- ic_codegen:emit(Fd, " _initialized = false;\n", []),
- ic_codegen:emit(Fd, " _value = null;\n", []),
- ic_codegen:emit(Fd, " }\n", []),
- ic_codegen:nl(Fd),
-
- ic_codegen:emit(Fd, " // discriminator access\n", []),
-
- ic_codegen:emit(Fd, " public ~s discriminator() "
- "throws java.lang.Exception {\n", [DiscrType]),
- ic_codegen:emit(Fd, " if (!_initialized) {\n", []),
- ic_codegen:emit(Fd, " throw new java.lang.Exception(\"\");\n",[]),
- ic_codegen:emit(Fd, " }\n", []),
- ic_codegen:emit(Fd, " return _discriminator;\n", []),
- ic_codegen:emit(Fd, " }\n", []),
- ic_codegen:nl(Fd),
-
- emit_union_members_functions(G, [UnionName ++ "Package"|N], X,
- Fd, UnionName, DiscrType, MList, MList),
- ic_codegen:nl(Fd),
-
- ic_codegen:emit(Fd, "}\n", []),
- file:close(Fd).
-
-%%-----------------------------------------------------------------
-%% Func: emit_holder_class/4
-%%-----------------------------------------------------------------
-emit_holder_class(G, N, _X, UnionName) ->
- UName = string:concat(UnionName, "Holder"),
- {Fd, _} = ic_file:open_java_file(G, N, UName),
-
- ic_codegen:emit(Fd, "final public class ~sHolder {\n",[UnionName]),
-
- ic_codegen:emit(Fd, " // instance variables\n"),
- ic_codegen:emit(Fd, " public ~s value;\n", [UnionName]),
- ic_codegen:nl(Fd),
-
- ic_codegen:emit(Fd, " // constructors\n"),
- ic_codegen:emit(Fd, " public ~sHolder() {}\n", [UnionName]),
- ic_codegen:emit(Fd, " public ~sHolder(~s initial) {\n",
- [UnionName, UnionName]),
- ic_codegen:emit(Fd, " value = initial;\n"),
- ic_codegen:emit(Fd, " }\n"),
- ic_codegen:nl(Fd),
-
- ic_codegen:emit(Fd, " // methods\n"),
-
- ic_codegen:emit(Fd, " public void _marshal(~sOtpOutputStream out) throws java.lang.Exception {\n",
- [?ERLANGPACKAGE]),
- ic_codegen:emit(Fd, " ~sHelper.marshal(out, value);\n", [UnionName]),
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_codegen:emit(Fd, " public void _unmarshal(~sOtpInputStream in) throws java.lang.Exception {\n",
- [?ERLANGPACKAGE]),
- ic_codegen:emit(Fd, " value = ~sHelper.unmarshal(in);\n", [UnionName]),
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_codegen:emit(Fd, "}\n"),
- file:close(Fd).
-
-
-%%-----------------------------------------------------------------
-%% Func: emit_helper_class/4
-%%-----------------------------------------------------------------
-emit_helper_class(G, N, X, UnionName, WiredUnionName) ->
- UName = string:concat(UnionName, "Helper"),
- {Fd, _} = ic_file:open_java_file(G, N, UName),
-
- DiscrType = ic_java_type:getType(G, [ UnionName ++ "Package" |N],
- ic_forms:get_type(X)),
-
- ic_codegen:emit(Fd, "public class ~sHelper {\n",[UnionName]),
-
- ic_codegen:emit(Fd, " // constructors\n", []),
- ic_codegen:emit(Fd, " private ~sHelper() {}\n", [UnionName]),
- ic_codegen:nl(Fd),
-
- ic_codegen:emit(Fd, " // methods\n", []),
- MList = union_member_list(G, N, X, DiscrType),
-
- ic_codegen:emit(Fd, " public static void marshal(~sOtpOutputStream _out, ~s _value)\n",
- [?ERLANGPACKAGE, UnionName]),
- ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"),
- emit_union_marshal_function(G, N, X, Fd, UnionName, WiredUnionName, MList),
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_codegen:emit(Fd, " public static ~s unmarshal(~sOtpInputStream _in)\n",
- [UnionName, ?ERLANGPACKAGE]),
- ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"),
- emit_union_unmarshal_function(G, N, X, Fd, UnionName, WiredUnionName, MList),
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_codegen:emit(Fd, " public static String id() {\n"),
- ic_codegen:emit(Fd, " return ~p;\n",[ictk:get_IR_ID(G, N, X)]),
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_codegen:emit(Fd, " public static String name() {\n"),
- ic_codegen:emit(Fd, " return ~p;\n",[UnionName]),
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_jbe:emit_type_function(G, N, X, Fd),
-
-
- ic_codegen:emit(Fd, " public static void insert(~sAny _any, ~s _this)\n",
- [?ICPACKAGE,UnionName]),
- ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"),
-
- ic_codegen:emit(Fd, " ~sOtpOutputStream _os = \n",[?ERLANGPACKAGE]),
- ic_codegen:emit(Fd, " new ~sOtpOutputStream();\n\n",[?ERLANGPACKAGE]),
-
- ic_codegen:emit(Fd, " _any.type(type());\n"),
- ic_codegen:emit(Fd, " marshal(_os, _this);\n"),
- ic_codegen:emit(Fd, " _any.insert_Streamable(_os);\n"),
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_codegen:emit(Fd, " public static ~s extract(~sAny _any)\n",
- [UnionName,?ICPACKAGE]),
- ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"),
-
- ic_codegen:emit(Fd, " return unmarshal(_any.extract_Streamable());\n"),
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_codegen:emit(Fd, " public static int discriminatorAsInt(~s _discriminator)\n",
- [DiscrType]),
- ic_codegen:emit(Fd, " throws java.lang.Exception {\n"),
- emit_discriminator_as_int(G, N, ic_forms:get_type(X), Fd),
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_codegen:emit(Fd, "}\n"),
- file:close(Fd).
-
-%%-----------------------------------------------------------------
-%% Func: emit_union_members_functions/7
-%%-----------------------------------------------------------------
-emit_union_members_functions(_, _, _, _, _, _, [], _) ->
- ok;
-emit_union_members_functions(G, N, X, Fd, UnionName, DiscrType,
- [{Label, Case, TypeDef, Id, Ls} | MList], MListTot) ->
-
- CaseId = Case#case_dcl.id, %% Maybe Array
- CaseType = Case#case_dcl.type, %% Maybe Sequence
-
- Type = if element(1,CaseId) == array ->
- ic_java_type:getType(G, N, TypeDef) ++
- ic_java_type:getdim(CaseId#array.size);
- true ->
- ic_java_type:getType(G, N, TypeDef)
- end,
-
- HolderType =
- if element(1,CaseId) == array ->
- ic_java_type:getHolderType(G, N, CaseId);
- true ->
- if element(1,CaseType) == sequence ->
- ic_util:to_dot(G,[Id|N]) ++"Holder";
- true ->
- ic_java_type:getHolderType(G, N, TypeDef)
- end
- end,
-
- %%
- %% Set method
- %%
- ic_codegen:emit(Fd, " // ~s access and set functions\n",[Id]),
- ic_codegen:emit(Fd, " public void ~s(~s value) "
- "throws java.lang.Exception {\n",
- [Id, Type]),
- ic_codegen:emit(Fd, " _initialized = true;\n", []),
- case Label of
- "default" ->
- ic_codegen:emit(Fd, " _discriminator = (~s) _default;\n",
- [DiscrType]);
- _ ->
- case ic_java_type:isBasicType(G, N, ic_forms:get_type(X)) of
- true ->
- ic_codegen:emit(Fd, " _discriminator = (~s) "
- "~s;\n",
- [DiscrType, Label]);
- _ ->
- ic_codegen:emit(Fd, " _discriminator = (~s) "
- "~s.~s;\n",
- [DiscrType, DiscrType, Label])
- end
- end,
- ic_codegen:emit(Fd, " _value = new ~s(value);\n",
- [HolderType]),
- ic_codegen:emit(Fd, " }\n", []),
-
- %%
- %% Check this entry has more than one label and the generate an extra set method.
- %%
- case Ls of
- [] ->
- ok;
- _ ->
- ic_codegen:emit(Fd, " public void ~s(~s discriminator, ~s value) "
- "throws java.lang.Exception {\n",
- [Id, DiscrType, Type]),
- ic_codegen:emit(Fd, " _initialized = true;\n", []),
- ic_codegen:emit(Fd, " _discriminator = (~s) discriminator;\n",
- [DiscrType]),
- ic_codegen:emit(Fd, " _value = new ~s(value);\n",
- [HolderType]),
- ic_codegen:emit(Fd, " }\n", [])
- end,
-
- %%
- %% Get method
- %%
- ic_codegen:emit(Fd, " public ~s ~s() throws java.lang.Exception {\n",
- [Type, Id]),
- ic_codegen:emit(Fd, " if (!_initialized) {\n", []),
- ic_codegen:emit(Fd, " throw new java.lang.Exception(\"\");\n",[]),
- ic_codegen:emit(Fd, " }\n", []),
- ic_codegen:emit(Fd, " switch (~sHelper.discriminatorAsInt"
- "(discriminator())) {\n",
- [UnionName]),
- if
- Label == "default" ->
- ic_codegen:emit(Fd, " default:\n", []),
- ic_codegen:emit(Fd, " break;\n", []),
- emit_default_access_fun_switch_cases(G, N, X, Fd, DiscrType,
- MListTot),
- ic_codegen:emit(Fd, " throw new java.lang.Exception(\"\");\n", []);
- true ->
- ic_codegen:emit(Fd, " case ~s:\n",
- [get_case_as_int(G, N, ic_forms:get_type(X),
- DiscrType, Label)]),
- ic_codegen:emit(Fd, " break;\n", []),
- ic_codegen:emit(Fd, " default:\n", []),
- ic_codegen:emit(Fd, " throw new java.lang.Exception(\"\");\n", [])
- end,
- ic_codegen:emit(Fd, " }\n", []),
-
- ic_codegen:emit(Fd, " return ((~s) _value).value;\n",
- [HolderType]),
- ic_codegen:emit(Fd, " }\n", []),
- ic_codegen:nl(Fd),
- emit_union_members_functions(G, N, X, Fd, UnionName, DiscrType, MList,
- MListTot).
-
-
-%%-----------------------------------------------------------------
-%% Func: emit_default_access_fun_switch_cases/6
-%%-----------------------------------------------------------------
-emit_default_access_fun_switch_cases(_G, _N, _X, _Fd, _DiscrType, []) ->
- ok;
-emit_default_access_fun_switch_cases(G, N, X, Fd, DiscrType,
- [{"default", _, _, _, _} |MList]) ->
- emit_default_access_fun_switch_cases(G, N, X, Fd, DiscrType, MList);
-emit_default_access_fun_switch_cases(G, N, X, Fd, DiscrType,
- [{Label, _Case, _TypeDef, _Id, _} | MList]) ->
- ic_codegen:emit(Fd, " case ~s:\n",
- [get_case_as_int(G, N, ic_forms:get_type(X),
- DiscrType, Label)]),
- emit_default_access_fun_switch_cases(G, N, X, Fd, DiscrType, MList).
-
-
-
-%%-----------------------------------------------------------------
-%% Func: emit_union_unmarshal_function/5
-%%-----------------------------------------------------------------
-emit_union_unmarshal_function(G, N, X, Fd, UnionName, WiredUnionName, MList) ->
- DiscrTypeForm = ic_forms:get_type(X),
- DiscrType = ic_java_type:getType(G, [UnionName ++ "Package"|N],
- DiscrTypeForm),
-
- ic_codegen:emit(Fd, " _in.read_tuple_head();\n\n"),
-
- ic_codegen:emit(Fd, " if ((_in.read_atom()).compareTo(~p) != 0)\n",
- [ic_util:to_undersc([WiredUnionName|N])]),
- ic_codegen:emit(Fd, " throw new java.lang.Exception(\"\");\n\n",[]),
-
- ic_codegen:emit(Fd, " ~s _value = new ~s();\n", [UnionName, UnionName]),
-
- %% Decode discriminator
- case ic_java_type:isBasicType(G, N, DiscrTypeForm) of
- true ->
- ic_codegen:emit(Fd, " ~s _discriminator = _in~s;\n\n",
- [DiscrType,
- ic_java_type:unMarshalFun(G, N, X, DiscrTypeForm)]);
- _ ->
- ic_codegen:emit(Fd, " ~s _discriminator = ~s.unmarshal(_in);\n\n",
- [DiscrType,ic_java_type:getUnmarshalType(G, N, X, DiscrTypeForm)])
- end,
-
- ic_codegen:emit(Fd, " switch (~sHelper.discriminatorAsInt(_discriminator)) {\n",
- [UnionName]),
-
- emit_union_unmarshal_function_loop(G, [UnionName ++ "Package"|N], X,
- Fd, DiscrType, MList),
-
- ic_codegen:emit(Fd, " }\n\n"),
-
- ic_codegen:emit(Fd, " return _value;\n").
-
-%%-----------------------------------------------------------------
-%% Func: emit_union_unmarshal_function_loop/6
-%%-----------------------------------------------------------------
-emit_union_unmarshal_function_loop(_, _, _, _, _, []) ->
- ok;
-emit_union_unmarshal_function_loop(G, N, X, Fd, DiscrType,
- [{Label, Case, Type, Id, Ls} |MList]) ->
- case Label of
- "default" ->
- ic_codegen:emit(Fd, " default:\n");
- _ ->
- ic_codegen:emit(Fd, " case ~s:\n",
- [get_case_as_int(G, N, ic_forms:get_type(X),
- DiscrType, Label)])
- end,
-
- gen_multiple_cases(G, N, X, Fd, DiscrType, Ls),
-
- CaseId = Case#case_dcl.id, %% Maybe Array
- CaseType = Case#case_dcl.type, %% Maybe Sequence
-
- case element(1,CaseId) of
- array ->
- ic_codegen:emit(Fd, " _value.~s(~s.unmarshal(_in));\n",
- [Id,
- ic_java_type:getUnmarshalType(G, N, Case, CaseId)]);
-
- _ ->
- case element(1, CaseType) of
- sequence ->
- ic_codegen:emit(Fd, " _value.~s(~s.unmarshal(_in));\n",
- [Id,
- ic_java_type:getUnmarshalType(G, N, Case, CaseType)]);
- _ ->
- case ic_java_type:isBasicType(G, N, CaseType) of
- true ->
- ic_codegen:emit(Fd, " _value.~s(_in~s);\n",
- [Id,
- ic_java_type:unMarshalFun(G, N, X, Type)]);
- false ->
- ic_codegen:emit(Fd, " _value.~s(~s.unmarshal(_in));\n",
- [Id,
- ic_java_type:getUnmarshalType(G, N, X, Type)])
- end
- end
- end,
-
- ic_codegen:emit(Fd, " break;\n", []),
- emit_union_unmarshal_function_loop(G, N, X, Fd, DiscrType, MList).
-
-
-
-
-
-%%-----------------------------------------------------------------
-%% Func: emit_union_marshal_function/6
-%%-----------------------------------------------------------------
-emit_union_marshal_function(G, N, X, Fd, UnionName, WiredUnionName, MList) ->
-
- DiscrTypeForm = ic_forms:get_type(X),
- DiscrType = ic_java_type:getType(G, [UnionName ++ "Package" |N],
- DiscrTypeForm),
-
- ic_codegen:emit(Fd, " _out.write_tuple_head(3);\n"),
- ic_codegen:emit(Fd, " _out.write_atom(~p);\n",
- [ic_util:to_undersc([WiredUnionName|N])]),
-
- case ic_java_type:isBasicType(G, N, DiscrTypeForm) of
- true ->
- ic_codegen:emit(Fd, " _out~s(_value.discriminator());\n\n",
- [ic_java_type:marshalFun(G, N, X, DiscrTypeForm)]);
- false ->
- ic_codegen:emit(Fd, " ~s(_out, _value.discriminator());\n\n",
- [ic_java_type:marshalFun(G, N, X, DiscrTypeForm)])
- end,
-
- ic_codegen:emit(Fd, " switch(~sHelper.discriminatorAsInt(_value.discriminator())) {\n",
- [UnionName]),
-
- emit_union_marshal_function_loop(G,
- [ UnionName ++ "Package"|N],
- X,
- Fd,
- DiscrType,
- MList),
-
- ic_codegen:emit(Fd, " }\n\n", []).
-
-
-%%-----------------------------------------------------------------
-%% Func: emit_union_marshal_function_loop/
-%%-----------------------------------------------------------------
-emit_union_marshal_function_loop(_, _, _, _, _, []) ->
- ok;
-emit_union_marshal_function_loop(G, N, X, Fd, DiscrType,
- [{Label, Case, Type, Id, Ls} |MList]) ->
- case Label of
- "default" ->
- ic_codegen:emit(Fd, " default:\n",
- []);
- _ ->
- ic_codegen:emit(Fd, " case ~s:\n",
- [get_case_as_int(G, N, ic_forms:get_type(X),
- DiscrType, Label)])
- end,
-
- gen_multiple_cases(G, N, X, Fd, DiscrType, Ls),
-
-
- CaseId = Case#case_dcl.id, %% Maybe Array
- CaseType = Case#case_dcl.type, %% Maybe Sequence
-
- case element(1,CaseId) of
- array ->
- ic_codegen:emit(Fd, " ~s(_out, _value.~s());\n",
- [ic_java_type:marshalFun(G, N, Case, CaseId),
- Id]);
- _ ->
- case element(1, CaseType) of
- sequence ->
- ic_codegen:emit(Fd, " ~s.marshal(_out, _value.~s());\n",
- [ic_util:to_dot(G,[Id|N]) ++ "Helper",
- Id]);
- _ ->
- case ic_java_type:isBasicType(G, N, CaseType) of
- true ->
- ic_codegen:emit(Fd, " _out~s(_value.~s());\n",
- [ic_java_type:marshalFun(G, N, X, Type),
- Id]);
- false ->
- ic_codegen:emit(Fd, " ~s(_out, _value.~s());\n",
- [ic_java_type:marshalFun(G, N, X, Type),
- Id])
- end
- end
- end,
-
- ic_codegen:emit(Fd, " break;\n", []),
- emit_union_marshal_function_loop(G, N, X, Fd, DiscrType, MList).
-
-
-
-gen_multiple_cases(_G, _N, _X, _Fd, _DiscrType, []) ->
- ok;
-gen_multiple_cases(G, N, X, Fd, DiscrType, [Label |Ls]) ->
- ic_codegen:emit(Fd, " case ~s:\n",
- [get_case_as_int(G, N, ic_forms:get_type(X),
- DiscrType, getLabel(DiscrType, Label))]),
- gen_multiple_cases(G, N, X, Fd, DiscrType, Ls).
-
-
-%%-----------------------------------------------------------------
-%% Func: union_member_list/3
-%%-----------------------------------------------------------------
-union_member_list(G, N, X, DiscrType) ->
- M = lists:map(
- fun(Case) ->
- {Label, LabelList} = case check_default(ic_forms:get_idlist(Case)) of
- {{default, C}, List} ->
- {{default, C}, List};
- {L, []} ->
- {L, []};
- {_, [L |Ls]} ->
- {L, Ls}
- end,
-
- CName = ic_forms:get_java_id(Case),
- CId = Case#case_dcl.id,
- CType = Case#case_dcl.type,
-
- if element(1,CId) == array ->
- N2 = [ic_forms:get_id2(X) ++ "Package" |N],
- ic_array_java:gen(G, N2, Case, CId);
- true ->
- if element(1,Case#case_dcl.type) == sequence ->
- N2 = [ic_forms:get_id2(X) ++ "Package" |N],
- ic_sequence_java:gen(G, N2, CType, CName);
- true ->
- ok
- end
- end,
-
- {getLabel(DiscrType, Label),
- Case,
- ic_forms:get_type(Case),
- CName,
- LabelList}
- end,
- ic_forms:get_body(X)),
- lists:flatten(M).
-
-check_default([]) ->
- {false, []};
-check_default([{default, X} |Ls]) ->
- {{default, X}, Ls};
-check_default([L]) ->
- {false, [L]};
-check_default([L |Ls]) ->
- {X, Y} = check_default(Ls),
- {X, [L | Y]}.
-
-getLabel(_, {'<integer_literal>', _, N}) ->
- N;
-getLabel(_, {'<character_literal>', _, N}) ->
- "'" ++ N ++ "'";
-getLabel(_, {'<wcharacter_literal>', _, N}) ->
- "'" ++ N ++ "'";
-getLabel(_, {'TRUE',_}) ->
- "true";
-getLabel(_, {'FALSE',_}) ->
- "true";
-getLabel(_, {default, _}) ->
- "default";
-getLabel(_DiscrType, X) -> %%DiscrType ++ "." ++
- ic_util:to_dot(ic_forms:get_id(X)).
-
-get_default_val(G, N, _, tk_short, MList) ->
- integer_default_val(G, N, 1, lists:map(fun({V, _, _, _, _}) -> V end, MList));
-get_default_val(G, N, _, tk_long, MList) ->
- integer_default_val(G, N, 1, lists:map(fun({V, _, _, _, _}) -> V end, MList));
-get_default_val(G, N, _, tk_ushort, MList) ->
- integer_default_val(G, N, 1, lists:map(fun({V, _, _, _, _}) -> V end, MList));
-get_default_val(G, N, _, tk_ulong, MList) ->
- integer_default_val(G, N, 1, lists:map(fun({V, _, _, _, _}) -> V end, MList));
-get_default_val(G, N, _, tk_char, MList) ->
- char_default_val(G, N, $a, lists:map(fun({V, _, _, _, _}) -> V end, MList));
-get_default_val(G, N, _, tk_boolean, MList) ->
- boolean_default_val(G, N, lists:map(fun({V, _, _, _, _}) -> V end, MList));
-get_default_val(G, N, DiscrType, {tk_enum, _, _, Values}, MList) ->
- enum_default_val(G, N, DiscrType, Values, MList).
-
-integer_default_val(G, N, Num, MList) ->
- Num2 = integer_to_list(Num),
- case lists:member(Num2, MList) of
- true ->
- integer_default_val(G, N, Num + 1, MList);
- false ->
- Num2
- end.
-
-char_default_val(G, N, CharNum, MList) ->
- Str = "'",
- CharNum2 = Str ++ [CharNum | Str],
- case lists:member(CharNum2, MList) of
- true ->
- char_default_val(G, N, CharNum + 1, MList);
- false ->
- CharNum2
- end.
-
-boolean_default_val(G, N, MList) ->
- if
- length(MList) > 2 ->
- ic_error:error(G, {plain_error_string,
- lists:flatten(
- io_lib:format("Default value found while all values have label on ~s",
- [ic_util:to_colon(N)]))}),
- none;
- true ->
- case MList of
- ["true"] ->
- "false";
- ["false"] ->
- "true";
- ["default","true"] ->
- "false";
- ["true","default"] ->
- "false";
- ["default","false"] ->
- "true";
- ["false","default"] ->
- "true";
- _ ->
- none
- end
- end.
-
-
-
-
-enum_default_val(G, N, DiscrType, Values, Mlist) ->
-
- VLen = length(Values),
- MLen = length(Mlist),
-
- case MLen > VLen of
- true ->
- ic_error:error(G, {plain_error_string,
- lists:flatten(
- io_lib:format("Default value found while all values have label on ~s",
- [ic_util:to_colon(N)]))}),
- none;
- false ->
- enum_default_val_loop(G, N, DiscrType, Values, Mlist)
- end.
-
-enum_default_val_loop(_G, _N, _, [], []) ->
- none;
-enum_default_val_loop(_G, _N, DiscrType, [Value| _], []) ->
- DiscrType ++ "." ++ Value;
-enum_default_val_loop(G, N, DiscrType, Values, [Case | MList]) when is_tuple(Case) ->
- NewValues = lists:delete(element(1,Case), Values),
- enum_default_val_loop(G, N, DiscrType, NewValues, MList).
-
-
-
-emit_discriminator_as_int(G, N, T, Fd) ->
- case ictype:isBoolean(G,N,T) of
- true ->
- ic_codegen:emit(Fd, " if(_discriminator)\n", []),
- ic_codegen:emit(Fd, " return 1;\n", []),
- ic_codegen:emit(Fd, " else\n", []),
- ic_codegen:emit(Fd, " return 0;\n", []);
- false ->
- case ictype:isEnum(G, N, T) of
- true ->
- ic_codegen:emit(Fd, " return _discriminator.value();\n",
- []);
- false ->
- ic_codegen:emit(Fd, " return _discriminator;\n", [])
- end
- end.
-
-
-get_case_as_int(G, N, T, DiscrJavaTypeName, Label) ->
- case ictype:isBoolean(G,N,T) of
- true ->
- case Label of
- "true" ->
- "1";
- "false" ->
- "0"
- end;
- false ->
- case ictype:isEnum(G, N, T) of
- true ->
- DiscrJavaTypeName ++ "._" ++ Label;
- false ->
- "(" ++ DiscrJavaTypeName ++ ") " ++ Label
- end
- end.
-
-
-
diff --git a/lib/ic/src/ic_util.erl b/lib/ic/src/ic_util.erl
deleted file mode 100644
index b1263ae63d..0000000000
--- a/lib/ic/src/ic_util.erl
+++ /dev/null
@@ -1,314 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(ic_util).
-
-
--include("icforms.hrl").
--include("ic.hrl").
--include("ic_debug.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
-
--export([mk_align/1, mk_list/1, join/2, chain/2, mk_name/2,
- mk_OE_name/2, mk_oe_name/2, mk_var/1]).
-
--export([to_atom/1, to_colon/1, to_list/1, to_undersc/1, to_dot/1,
- to_dot/2]).
--export([to_uppercase/1, adjustScopeToJava/2, eval_java/3, eval_c/3]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-%%-----------------------------------------------------------------
-%% External functions
-%%-----------------------------------------------------------------
-
-%% mk_list produces a nice comma separated string of variable names
-mk_list([]) -> [];
-mk_list([Arg | Args]) ->
- Arg ++ mk_list2(Args).
-mk_list2([Arg | Args]) ->
- ", " ++ Arg ++ mk_list2(Args);
-mk_list2([]) -> [].
-
-%% Produce a list of items separated by S.
-join([E1, E2| Es], S) ->
- [E1, S| join([E2| Es], S)];
-join([E], _) ->
- [E];
-join([], _) ->
- [].
-
-%% Produce a list of items, each terminated by T.
-chain([E| Es], T) ->
- [E, T| chain(Es, T)];
-chain([], _) ->
- [].
-
-
-%% Shall convert a string to a Erlang variable name (Capitalise)
-mk_var( [N | Str] ) when N >= $a, N =< $z ->
- [ N+$A-$a | Str ];
-mk_var( [N | Str] ) when N >= $A, N =< $Z -> [N | Str].
-
-%% Shall produce a "public" name for name. When we introduce new
-%% identifiers in the mapping that must not collide with those from
-%% the IDL spec.
-%%
-%% NOTE: Change name of IFR ID in system exceptions in corba.hrl when
-%% prefix is changed here.
-%%
-mk_name(_Gen, Name) -> lists:flatten(["OE_" | Name]).
-mk_OE_name(_Gen, Name) -> lists:flatten(["OE_" | Name]).
-mk_oe_name(_Gen, Name) -> lists:flatten(["oe_" | Name]).
-
-mk_align(String) ->
- io_lib:format("OE_ALIGN(~s)",[String]).
-
-to_atom(A) when is_atom(A) -> A;
-to_atom(L) when is_list(L) -> list_to_atom(L).
-
-to_list(A) when is_list(A) -> A;
-to_list(L) when is_atom(L) -> atom_to_list(L);
-to_list(X) when is_integer(X) -> integer_to_list(X).
-
-
-
-%% Produce a colon (or under score) separated string repr of the name
-%% X
-%%
-to_colon(X) when element(1, X) == scoped_id ->
- to_colon2(ic_symtab:scoped_id_strip(X));
-to_colon(L) -> to_colon2(L).
-
-to_colon2([X]) -> X;
-to_colon2([X | Xs]) -> to_colon2(Xs) ++ "::" ++ X;
-to_colon2([]) -> "".
-
-
-to_undersc(X) when element(1, X) == scoped_id ->
- to_undersc2(ic_symtab:scoped_id_strip(X));
-to_undersc(L) -> to_undersc2(L).
-
-to_undersc2([X]) -> X;
-to_undersc2([X | Xs]) -> to_undersc2(Xs) ++ "_" ++ X;
-to_undersc2([]) -> "".
-
-
-%% Z is a single name
-to_uppercase(Z) ->
- lists:map(fun(X) when X>=$a, X=<$z -> X-$a+$A;
- (X) -> X end, Z).
-
-
-%%
-to_dot(X) when element(1, X) == scoped_id ->
- to_dotLoop(ic_symtab:scoped_id_strip(X));
-to_dot(L) -> to_dotLoop(L).
-
-to_dotLoop([X]) -> ic_forms:get_java_id(X);
-to_dotLoop([X | Xs]) -> to_dotLoop(Xs) ++ "." ++ ic_forms:get_java_id(X);
-to_dotLoop([]) -> "".
-
-
-
-%%
-to_dot(G,X) when element(1, X) == scoped_id ->
- S = ic_genobj:pragmatab(G),
- ScopedId = ic_symtab:scoped_id_strip(X),
- case isConstScopedId(S, ScopedId) of %% Costants are left as is
- true ->
- to_dotLoop(ScopedId) ++ addDotValue(S, ScopedId);
- false ->
- to_dotLoop(S,ScopedId)
- end;
-to_dot(G,ScopedId) ->
- S = ic_genobj:pragmatab(G),
- case isConstScopedId(S, ScopedId) of %% Costants are left as is
- true ->
- to_dotLoop(ScopedId) ++ addDotValue(S, ScopedId);
- false ->
- to_dotLoop(S,ScopedId)
- end.
-
-addDotValue(S, [_C | Ss]) ->
- case isInterfaceScopedId(S, Ss) of
- true ->
- "";
- false ->
- ".value"
- end.
-
-to_dotLoop(S,[X]) ->
- case isInterfaceScopedId(S, [X]) of
- true ->
- ic_forms:get_java_id(X) ++ "Package";
- false ->
- ic_forms:get_java_id(X)
- end;
-to_dotLoop(S,[X | Xs]) ->
- case isInterfaceScopedId(S, [X | Xs]) of
- true ->
- to_dotLoop(S,Xs) ++ "." ++ ic_forms:get_java_id(X) ++ "Package";
- false ->
- to_dotLoop(S,Xs) ++ "." ++ ic_forms:get_java_id(X)
- end;
-to_dotLoop(_S,[]) -> "".
-
-isInterfaceScopedId(_S,[]) ->
- false;
-isInterfaceScopedId(S,[X|Xs]) ->
- case ets:match(S,{file_data_local,'_','_',interface,Xs,X,'_','_','_'}) of
- [] ->
- case ets:match(S,{file_data_included,'_','_',interface,Xs,X,'_','_','_'}) of
- [] ->
- false;
- _ ->
- true
- end;
- _ ->
- true
- end.
-
-isConstScopedId(_S,[]) ->
- false;
-isConstScopedId(S,[X|Xs]) ->
- case ets:match(S,{file_data_local,'_','_',const,Xs,X,'_','_','_'}) of
- [] ->
- case ets:match(S,{file_data_included,'_','_',const,Xs,X,'_','_','_'}) of
- [] ->
- false;
- _ ->
- true
- end;
- _ ->
- true
- end.
-
-
-
-%%
-adjustScopeToJava(G,X) when element(1, X) == scoped_id ->
- S = ic_genobj:pragmatab(G),
- ScopedId = ic_symtab:scoped_id_strip(X),
- case isConstScopedId(S, ScopedId) of %% Costants are left as is
- true ->
- ic_forms:get_java_id(ScopedId);
- false ->
- adjustScopeToJavaLoop(S,ScopedId)
- end;
-adjustScopeToJava(G,ScopedId) ->
- S = ic_genobj:pragmatab(G),
- case isConstScopedId(S, ScopedId) of %% Costants are left as is
- true ->
- ic_forms:get_java_id(ScopedId);
- false ->
- adjustScopeToJavaLoop(S,ScopedId)
- end.
-
-
-
-adjustScopeToJavaLoop(_S,[]) ->
- [];
-adjustScopeToJavaLoop(S,[X | Xs]) ->
- case isInterfaceScopedId(S, [X | Xs]) of
- true ->
- [ic_forms:get_java_id(X) ++ "Package" | adjustScopeToJavaLoop(S,Xs)];
- false ->
- [ic_forms:get_java_id(X) | adjustScopeToJavaLoop(S,Xs)]
- end.
-
-
-%%
-%% Expression evaluator for java
-%%
-%% Well, this is not an evaluator, it just
-%% prints the hole operation, sorry.
-%%
-eval_java(G,N,Arg) when is_record(Arg, scoped_id) ->
- {FSN, _, _, _} =
- ic_symtab:get_full_scoped_name(G, N, Arg),
- ic_util:to_dot(G,FSN);
-eval_java(_G,_N,Arg) when is_tuple(Arg) andalso element(1,Arg) == '<integer_literal>' ->
- element(3,Arg);
-eval_java(_G,_N,Arg) when is_tuple(Arg) andalso element(1,Arg) == '<character_literal>' ->
- element(3,Arg);
-eval_java(_G,_N,Arg) when is_tuple(Arg) andalso element(1,Arg) == '<wcharacter_literal>' ->
- element(3,Arg);
-eval_java(_G,_N,Arg) when is_tuple(Arg) andalso element(1,Arg) == '<boolean_literal>' ->
- element(3,Arg);
-eval_java(_G,_N,Arg) when is_tuple(Arg) andalso element(1,Arg) == '<floating_pt_literal>' ->
- element(3,Arg);
-eval_java(_G,_N,Arg) when is_tuple(Arg) andalso element(1,Arg) == '<string_literal>' ->
- element(3,Arg);
-eval_java(_G,_N,Arg) when is_tuple(Arg) andalso element(1,Arg) == '<wstring_literal>' ->
- element(3,Arg);
-eval_java(G,N,{Op,Arg1,Arg2}) ->
- "(" ++ eval_java(G,N,Arg1) ++
- ic_forms:get_java_id(Op) ++
- eval_java(G,N,Arg2) ++ ")".
-
-
-
-%%
-%% Expression evaluator for c
-%%
-%% Well, this is not an evaluator, it just
-%% prints the hole operation, sorry.
-%%
-eval_c(G,N,Arg) when is_record(Arg, scoped_id) ->
- {FSN, _, _, _} =
- ic_symtab:get_full_scoped_name(G, N, Arg),
- ic_util:to_undersc(FSN);
-eval_c(_G,_N,Arg) when is_tuple(Arg) andalso element(1,Arg) == '<integer_literal>' ->
- element(3,Arg);
-eval_c(_G,_N,Arg) when is_tuple(Arg) andalso element(1,Arg) == '<character_literal>' ->
- element(3,Arg);
-eval_c(_G,_N,Arg) when is_tuple(Arg) andalso element(1,Arg) == '<wcharacter_literal>' ->
- element(3,Arg);
-eval_c(_G,_N,Arg) when is_tuple(Arg) andalso element(1,Arg) == '<boolean_literal>' ->
- element(3,Arg);
-eval_c(_G,_N,Arg) when is_tuple(Arg) andalso element(1,Arg) == '<floating_pt_literal>' ->
- element(3,Arg);
-eval_c(_G,_N,Arg) when is_tuple(Arg) andalso element(1,Arg) == '<string_literal>' ->
- element(3,Arg);
-eval_c(_G,_N,Arg) when is_tuple(Arg) andalso element(1,Arg) == '<wstring_literal>' ->
- element(3,Arg);
-eval_c(G,N,{Op,Arg1,Arg2}) ->
- "(" ++ eval_c(G,N,Arg1) ++
- atom_to_list(Op) ++
- eval_c(G,N,Arg2) ++ ")".
-
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-
-
-
-
-
-
diff --git a/lib/ic/src/icenum.erl b/lib/ic/src/icenum.erl
deleted file mode 100644
index cab68d17fa..0000000000
--- a/lib/ic/src/icenum.erl
+++ /dev/null
@@ -1,206 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: icenum.erl
-%%
-%%
-%%-----------------------------------------------------------------
-%%
-%% Code generation for enum's.
-%%-----------------------------------------------------------------
--module(icenum).
-
--import(ic_codegen, [emit/2, emit/3, emit/4, emit_c_enc_rpt/4, emit_c_dec_rpt/4]).
-
--include("icforms.hrl").
--include("ic.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([enum_gen/4]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-enum_gen(G, N, X, c) when is_record(X, enum) ->
- emit_c_enum(G, N, X);
-enum_gen(_G, _N, _X, _L) ->
- ok.
-
-
-emit_c_enum(G, N, X) ->
- case ic_genobj:is_hrlfile_open(G) of
- true ->
- EnumName = [ic_forms:get_id2(X) | N],
-
- case ic_pragma:is_local(G,EnumName) of
- true ->
-
- Fd = ic_genobj:hrlfiled(G),
- EnumNameStr = ic_util:to_undersc(EnumName),
- ic_code:insert_typedef(G, EnumNameStr, {enum, EnumNameStr}),
- {tk_enum,_,_,EList} = ic_forms:get_tk(X),
- emit(Fd, "\n#ifndef __~s__\n",[ic_util:to_uppercase(EnumNameStr)]),
- emit(Fd, "#define __~s__\n",[ic_util:to_uppercase(EnumNameStr)]),
- ic_codegen:mcomment_light(Fd,
- [io_lib:format("Enum definition: ~s",
- [EnumNameStr])],
- c),
- emit(Fd, "typedef CORBA_enum {", []),
- emit_c_enum_values(G, N, Fd, EList),
- emit(Fd, "} ~s ;\n\n", [EnumNameStr]),
- create_c_enum_file(G, N, EnumNameStr, EList),
- emit(Fd, "\n#endif\n\n");
-
- false -> %% Do not generate included types att all.
- ok
- end;
-
- false ->
- ok
- end.
-
-
-emit_c_enum_values(_G, N, Fd, [E]) ->
- emit(Fd, "~s", [ic_util:to_undersc([E| N])]);
-emit_c_enum_values(G, N, Fd, [E |Es]) ->
- emit(Fd, "~s, ", [ic_util:to_undersc([E| N])]),
- emit_c_enum_values(G, N, Fd, Es).
-
-
-open_c_coding_file(G, Name) ->
- SName = string:concat(ic_util:mk_oe_name(G, "code_"), Name),
- FName =
- ic_file:join(ic_options:get_opt(G, stubdir),ic_file:add_dot_c(SName)),
- case file:open(FName, [write]) of
- {ok, Fd} ->
- {Fd, SName};
- Other ->
- exit(Other)
- end.
-
-
-create_c_enum_file(G, N, Name, Elist) ->
-
- {Fd , SName} = open_c_coding_file(G, Name),
- HFd = ic_genobj:hrlfiled(G), %% Write on stubfile header
- HrlFName = filename:basename(ic_genobj:include_file(G)),
- ic_codegen:emit_stub_head(G, Fd, SName, c),
- emit(Fd, "#include \"~s\"\n\n",[HrlFName]),
-
- %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %% Fd = ic_genobj:stubfiled(G), %% Write on stubfile
- %% HFd = ic_genobj:hrlfiled(G), %% Write on stubfile header
- %% HrlFName = filename:basename(ic_genobj:include_file(G)),
- %% emit(Fd, "#include \"~s\"\n\n",[HrlFName]),
- %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- emit(Fd, "char* ~s[~p] = {\n", [ic_util:mk_oe_name(G, Name),
- length(Elist)]),
- emit_c_enum_array_values(Fd, Elist),
- emit(Fd, "};\n\n",[]),
- emit_sizecount(G, N, Fd, HFd, Name, Elist),
- emit_encode(G, N, Fd, HFd, Name, Elist),
- emit_decode(G, N, Fd, HFd, Name, Elist),
- file:close(Fd).
-
-emit_c_enum_array_values(Fd, [E]) ->
- emit(Fd, " ~p\n", [E]);
-emit_c_enum_array_values(Fd, [E |Es]) ->
- emit(Fd, " ~p,\n", [E]),
- emit_c_enum_array_values(Fd, Es).
-
-
-emit_sizecount(G, _N, Fd, HFd, Name, _Elist) ->
-
- emit(HFd, "int ~s~s(CORBA_Environment *oe_env, int*, int*);\n",
- [ic_util:mk_oe_name(G, "sizecalc_"), Name]),
-
- emit(Fd, "int ~s~s(CORBA_Environment *oe_env, int* oe_size_count_index, int* oe_size)\n"
- "{\n",
- [ic_util:mk_oe_name(G, "sizecalc_"), Name]),
- emit(Fd, " int oe_error_code = 0;\n\n",[]),
-
- AlignName = lists:concat(["*oe_size + sizeof(",Name,")"]),
- emit(Fd, " *oe_size = ~s;\n\n",[ic_util:mk_align(AlignName)]),
-
- emit(Fd, " if ((oe_error_code = ei_decode_atom(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"),
- emit_c_enc_rpt(Fd, " ", "ei_decode_atom", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " return 0;\n\n",[]),
- emit(Fd, "}\n\n",[]).
-
-
-emit_encode(G, _N, Fd, HFd, Name, _Elist) ->
-
- emit(HFd, "int ~s~s(CORBA_Environment *oe_env, ~s);\n",
- [ic_util:mk_oe_name(G, "encode_"), Name, Name]),
-
- emit(Fd, "int ~s~s(CORBA_Environment *oe_env, ~s oe_rec) {\n",
- [ic_util:mk_oe_name(G, "encode_"), Name, Name]),
- emit(Fd, " int oe_error_code = 0;\n\n",[]),
-
- emit(Fd, " if ((oe_error_code = oe_ei_encode_atom(oe_env, ~s[oe_rec])) < 0) {\n",
- [ic_util:mk_oe_name(G, Name)]),
- emit_c_enc_rpt(Fd, " ", "oe_ei_encode_atom", []),
- emit(Fd, " return oe_error_code;\n }\n"),
-
- emit(Fd, " return 0;\n\n",[]),
- emit(Fd, "}\n\n",[]).
-
-emit_decode(G, _N, Fd, HFd, Name, Elist) ->
-
- emit(HFd, "int ~s~s(CORBA_Environment *oe_env, char *, int*, ~s *);\n",
- [ic_util:mk_oe_name(G, "decode_"), Name, Name]),
-
- emit(Fd, "int ~s~s(CORBA_Environment *oe_env, char *oe_first, int* oe_outindex, "
- "~s *oe_out) {\n\n",
- [ic_util:mk_oe_name(G, "decode_"), Name, Name]),
- emit(Fd, " int oe_error_code = 0;\n",[]),
- emit(Fd, " int oe_i;\n",[]),
- emit(Fd, " char oe_atom[256];\n\n",[]),
-
- AlignName = lists:concat(["*oe_outindex + sizeof(",Name,")"]),
- emit(Fd, " *oe_outindex = ~s;\n\n",[ic_util:mk_align(AlignName)]),
-
- emit(Fd, " if ((oe_error_code = ei_decode_atom(oe_env->_inbuf, &oe_env->_iin, oe_atom)) < 0) {\n"),
- emit_c_enc_rpt(Fd, " ", "ei_decode_atom", []),
- emit(Fd, " return oe_error_code;\n }\n"),
-
- Len = length(Elist),
- emit(Fd, " for(oe_i = 0; oe_i < ~p && strcmp(oe_atom, ~s[oe_i]); oe_i++);\n",
- [Len, ic_util:mk_oe_name(G, Name)]),
- emit(Fd, " *oe_out = oe_i;\n\n", []),
-
- emit(Fd, " if (oe_i == ~p) {\n",[Len]),
- emit_c_enc_rpt(Fd, " ", "decode atom failure", []),
- emit(Fd, " return oe_error_code;\n }\n"),
-
- emit(Fd, " return 0;\n",[]),
- emit(Fd, "}\n\n",[]).
-
-
-
-
-
diff --git a/lib/ic/src/iceval.erl b/lib/ic/src/iceval.erl
deleted file mode 100644
index a93e60124c..0000000000
--- a/lib/ic/src/iceval.erl
+++ /dev/null
@@ -1,556 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(iceval).
-
--include("icforms.hrl").
-
--export([eval_const/5, eval_e/5]).
-
--export([check_tk/3, get_val/1, mk_val/1]).
-
--define(get_max(__X, __Y), if __X > __Y -> __X; true -> __Y end).
--define(get_min(__X, __Y), if __X > __Y -> __Y; true -> __X end).
-
--define(BASE, 100000000000000000000000000000000).
--define(FIXED_MAX, 9999999999999999999999999999999).
-
-%% Called fr: ictype 99, 522, 533
-%% Fixed constants can be declared as:
-%% (1) const fixed pi = 3.14D; or
-%% (2) typedef fixed<3,2> f32;
-%% const f32 pi = 3.14D;
-%% Hence, if fixed is declared as (1) we must handle it especially.
-eval_const(G, S, N, tk_fixed, Expr) ->
- case catch eval_e(G, S, N, tk_fixed, Expr) of
- T when element(1, T) == error -> 0;
- V when is_record(V, fixed) ->
- {ok, {tk_fixed, V#fixed.digits, V#fixed.scale}, V};
- V ->
- ic_error:error(G, {bad_tk_match, Expr, tk_fixed, get_val(V)})
- end;
-eval_const(G, S, N, TK, Expr) ->
- case catch eval_e(G, S, N, TK, Expr) of
- T when element(1, T) == error -> 0;
- V ->
- case check_tk(G, TK, V) of
- true -> ok;
- false ->
- ic_error:error(G, {bad_tk_match, Expr, TK, get_val(V)})
- end,
- get_val(V)
- end.
-
-
-check_op(G, S, N, Tk, Types, Op, E1, E2) ->
- V1 = eval_e(G, S, N, Tk, E1),
- V2 = eval_e(G, S, N, Tk, E2),
- check_types(G, Op, E1, Types, V1),
- check_types(G, Op, E2, Types, V2),
- case check_comb(V1, V2) of
- true ->
- {V1, V2};
- false ->
- Err = {bad_type_combination, E1, get_val(V1), get_val(V2)},
- ic_error:error(G, Err),
- throw({error, Err})
- end.
-
-check_op(G, S, N, Tk, Types, Op, E1) ->
- V1 = eval_e(G, S, N, Tk, E1),
- check_types(G, Op, E1, Types, V1),
- V1.
-
-%% Match the declared type TK against the factual value of an constant
-%%
-check_tk(_G, _Any, default) -> true; % Default case in union
-check_tk(_G, positive_int, V) when is_integer(V) andalso V >= 0 -> true;
-check_tk(_G, tk_long, V) when is_integer(V) -> true;
-check_tk(_G, tk_longlong, V) when is_integer(V) -> true; %% LLON_G
-check_tk(_G, tk_short, V) when is_integer(V) -> true;
-check_tk(_G, tk_ushort, V) when is_integer(V) andalso V >= 0 -> true;
-check_tk(_G, tk_ulong, V) when is_integer(V) andalso V >= 0 -> true;
-check_tk(_G, tk_ulonglong, V) when is_integer(V) andalso V >= 0 -> true; %% ULLON_G
-check_tk(_G, tk_float, V) when is_float(V) -> true;
-check_tk(_G, tk_double, V) when is_float(V) -> true;
-check_tk(_G, tk_boolean, V) -> is_bool(V);
-check_tk(_G, tk_char, {char, _V}) -> true;
-check_tk(_G, tk_wchar, {wchar, _V}) -> true; %% WCHAR
-check_tk(_G, {tk_string, _Len}, {string, _V}) -> true;
-check_tk(_G, {tk_wstring, _Len}, {wstring, _V}) -> true; %% WSTRING
-check_tk(_G, {tk_fixed, Digits, Scale}, {fixed, Digits, Scale, _V}) -> true;
-check_tk(_G, tk_octet, V) when is_integer(V) -> true;
-%%check_tk(_G, tk_null, V) when integer(V) -> true;
-%%check_tk(_G, tk_void, V) when integer(V) -> true;
-%%check_tk(_G, tk_any, V) when integer(V) -> true;
-%%check_tk(_G, {tk_objref, "", "Object"}, V) when integer(V) -> true.
-check_tk(_G, {tk_enum, _, _, Body}, {enum_id, Id}) ->
- until(fun(X) when X == Id -> true;
- (_X) ->
- false
- end, Body);
-check_tk(_G, _TK, _V) ->
- false.
-
-get_val({string, X}) -> X;
-get_val({wstring, X}) -> X; %% WCHAR
-get_val({char, X}) -> X;
-get_val({wchar, X}) -> X; %% WSTRING
-get_val({enum_id, X}) -> X;
-get_val(X) -> X.
-
-check_types(G, Op, Expr, TypeList, V) ->
- case until(fun(int) when is_integer(V) -> true;
- (float) when is_float(V) -> true;
- (bool) when V==true -> true;
- (bool) when V==false -> true;
- (fixed) when is_record(V, fixed) -> true;
- (_) -> false end,
- TypeList) of
- true -> true;
- false ->
- Err = {bad_type, Expr, Op, TypeList, V},
- ic_error:error(G, Err),
- throw({error, Err})
- end.
-
-%%get_op(T) when tuple(T) -> element(1, T).
-
-%% Should be in lists
-until(F, [H|T]) ->
- case F(H) of
- true -> true;
- false -> until(F, T)
- end;
-until(_F, []) -> false.
-
-%% Section of all the boolean operators (because Erlang ops don't like
-%% boolean values.
-e_or(X, Y) when is_integer(X) andalso is_integer(Y) -> X bor Y;
-e_or(true, _) -> true;
-e_or(_, true) -> true;
-e_or(_, _) -> false.
-
-e_and(X, Y) when is_integer(X) andalso is_integer(Y) -> X band Y;
-e_and(true, true) -> true;
-e_and(_, _) -> false.
-
-e_xor(X, Y) when is_integer(X) andalso is_integer(Y) -> X bxor Y;
-e_xor(X, X) -> false;
-e_xor(_, _) -> true.
-
-%% Handling infix operators (+,-,*,/) for fixed type.
-%% Boundries determined as fixed<max(d1-s1,d2-s2) + max(s1,s2) + 1, max(s1,s2)>
-e_fixed_add(#fixed{digits = D1, scale = S1, value = V1},
- #fixed{digits = D2, scale = S2, value = V2}) ->
- Scale = ?get_max(S1, S2),
- Digits = ?get_max((D1-S1), (D2-S2)) + Scale +1,
- %% We must normalize the values before adding. Why?
- %% 4.23 and 5.2 are represented as 423 and 52. To be able to get the
- %% correct result we must add 4230 and 5200 == 9430.
- {PV1, PV2} = normalize(S1, V1, S2, V2),
- check_fixed_overflow(#fixed{digits = Digits,
- scale = Scale,
- value = (PV1 + PV2)}).
-
-%% Boundries determined as fixed<max(d1-s1,d2-s2) + max(s1,s2) + 1, max(s1,s2)>
-e_fixed_sub(#fixed{digits = D1, scale = S1, value = V1},
- #fixed{digits = D2, scale = S2, value = V2}) ->
- Scale = ?get_max(S1, S2),
- Digits = ?get_max((D1-S1), (D2-S2)) + Scale +1,
- {PV1, PV2} = normalize(S1, V1, S2, V2),
- check_fixed_overflow(#fixed{digits = Digits,
- scale = Scale,
- value = (PV1 - PV2)}).
-
-%% Boundries determined as fixed<d1+d2, s1+s2>
-e_fixed_mul(#fixed{digits = D1, scale = S1, value = V1},
- #fixed{digits = D2, scale = S2, value = V2}) ->
- check_fixed_overflow(#fixed{digits = (D1+D2),
- scale = (S1+S2),
- value = V1*V2}).
-
-%% Boundries determined as fixed<(d1-s1+s2) + s inf ,s inf>
-e_fixed_div(#fixed{digits = D1, scale = S1, value = V1},
- #fixed{digits = _D2, scale = S2, value = V2}) ->
- {PV1, PV2} = normalize(S1, V1, S2, V2),
- DigitsMin = (D1-S1+S2),
- R1 = (PV1 div PV2),
- R2 = (R1*?BASE + (PV1 rem PV2) * (?BASE div PV2)),
- {Result2, Sinf} = delete_zeros_value(R2, 0, R1),
- check_fixed_overflow(#fixed{digits = DigitsMin + Sinf, scale = Sinf,
- value = Result2}).
-
-
-%% Checks combination of argument types, basically floats and ints are
-%% interchangeable, and all types are allowed with themselves. No
-%% other combinations are allowed
-%%
-check_comb(X, Y) when is_integer(X) andalso is_integer(Y) -> true;
-check_comb(X, Y) when is_float(X) andalso is_integer(Y) -> true;
-check_comb(X, Y) when is_integer(X) andalso is_float(Y) -> true;
-check_comb(X, Y) when is_float(X) andalso is_float(Y) -> true;
-check_comb({X, _}, {X, _}) -> true; % Strings and chars are tuples
-check_comb({fixed, _, _, _}, {fixed, _, _, _}) -> true;
-check_comb(X, Y) ->
- case {is_bool(X), is_bool(Y)} of
- {true, true} ->
- true;
- _ ->
- false
- end.
-
-is_bool(true) -> true;
-is_bool(false) -> true;
-is_bool(_) -> false.
-
-
-%%%% (15)
-eval_e(G, S, N, Tk, {'or', T1, T2}) ->
- {E1, E2} = check_op(G, S, N, Tk, [int, bool], 'or', T1, T2),
- e_or(E1, E2);
-
-%%%% (16)
-eval_e(G, S, N, Tk, {'xor', T1, T2}) ->
- {E1, E2} = check_op(G, S, N, Tk, [int, bool], 'xor', T1, T2),
- e_xor(E1, E2);
-
-%%%% (17)
-eval_e(G, S, N, Tk, {'and', T1, T2}) ->
- {E1, E2} = check_op(G, S, N, Tk, [int, bool], 'and', T1, T2),
- e_and(E1, E2);
-
-%%%% (18)
-eval_e(G, S, N, Tk, {'rshift', T1, T2}) ->
- {E1, E2} = check_op(G, S, N, Tk, [int], 'rshift', T1, T2),
- E1 bsr E2;
-eval_e(G, S, N, Tk, {'lshift', T1, T2}) ->
- {E1, E2} = check_op(G, S, N, Tk, [int], 'lshift', T1, T2),
- E1 bsl E2;
-
-%%%% (19)
-eval_e(G, S, N, Tk, {'+', T1, T2}) ->
- case check_op(G, S, N, Tk, [int, float, fixed], '+', T1, T2) of
- {F1, F2} when is_record(F1,fixed) andalso is_record(F2,fixed) ->
- e_fixed_add(F1, F2);
- {E1, E2} ->
- E1 + E2
- end;
-eval_e(G, S, N, Tk, {'-', T1, T2}) ->
- case check_op(G, S, N, Tk, [int, float, fixed], '-', T1, T2) of
- {F1, F2} when is_record(F1,fixed) andalso is_record(F2,fixed) ->
- e_fixed_sub(F1, F2);
- {E1, E2} ->
- E1 - E2
- end;
-
-%%%% (20)
-eval_e(G, S, N, Tk, {'*', T1, T2}) ->
- case check_op(G, S, N, Tk, [int, float, fixed], '*', T1, T2) of
- {F1, F2} when is_record(F1,fixed) andalso is_record(F2,fixed) ->
- e_fixed_mul(F1, F2);
- {E1, E2} ->
- E1 * E2
- end;
-eval_e(G, S, N, Tk, {'/', T1, T2}) ->
- case check_op(G, S, N, Tk, [int, float, fixed], '/', T1, T2) of
- {F1, F2} when is_record(F1,fixed) andalso is_record(F2,fixed) ->
- e_fixed_div(F1, F2);
- {E1, E2} ->
- E1 / E2
- end;
-eval_e(G, S, N, Tk, {'%', T1, T2}) ->
- {E1, E2} = check_op(G, S, N, Tk, [int], '%', T1, T2),
- E1 rem E2;
-
-%%%% (21)
-eval_e(G, S, N, Tk, {{'-', _Line}, T}) ->
- case check_op(G, S, N, Tk, [int, float, fixed], '-', T) of
- F when is_record(F,fixed) ->
- F#fixed{value = -(F#fixed.value)};
- Number ->
- -Number
- end;
-eval_e(G, S, N, Tk, {{'+', _Line}, T}) ->
- check_op(G, S, N, Tk, [int, float, fixed], '+', T);
-eval_e(G, S, N, Tk, {{'~', Line}, T}) ->
- ic_error:error(G, {unsupported_op, {'~', Line}}),
- eval_e(G, S, N, Tk, T);
-
-
-%% Ints are repr. by an Erlang integer val, floats and doubles by
-%% Erlang floats, chars and strings must be tuplerized for type
-%% checking. These tuples are removed just before returning from top
-%% function.
-%%
-eval_e(_G, _S, _N, tk_fixed, {'<fixed_pt_literal>', _Line, X}) ->
- create_fixed(X);
-eval_e(G, _S, _N, {tk_fixed, Digits, Scale}, {'<fixed_pt_literal>', Line, X})
- when Digits < 32, Digits >= Scale ->
- case convert_fixed(X, [], Digits, Digits-Scale) of
- {error, Format, Args} ->
- ic_error:error(G, {bad_fixed, Format, Args, Line});
- FixedData ->
- {fixed, Digits, Scale, FixedData}
- end;
-eval_e(_G, _S, _N, _Tk, {'<integer_literal>', _Line, X}) -> list_to_integer(X);
-eval_e(_G, _S, _N, {tk_string,_}, {'<string_literal>', _Line, X}) -> {string, X};
-eval_e(_G, _S, _N, {tk_wstring,_}, {'<wstring_literal>', _Line, X}) -> {wstring, X}; %% WSTRING
-eval_e(_G, _S, _N, tk_char, {'<character_literal>', _Line, X}) -> {char, hd(X)};
-eval_e(_G, _S, _N, tk_wchar, {'<wcharacter_literal>', _Line, X}) -> {wchar, hd(X)}; %% WCHAR
-eval_e(_G, _S, _N, _Tk, {'TRUE', _Line}) -> true;
-eval_e(_G, _S, _N, _Tk, {'FALSE', _Line}) -> false;
-eval_e(_G, _S, _N, _Tk, {'<floating_pt_literal>', _Line, X}) -> to_float(X);
-%% Some possible error conditions
-eval_e(_G, _S, _N, _Tk, {'<character_literal>', _Line, X}) -> {char, hd(X)}; %% ERROR?
-%%
-eval_e(G, S, N, _Tk, X) when element(1, X) == scoped_id ->
- mk_val(ictype:scoped_lookup(G, S, N, X));
-eval_e(_G, _S, _N, _Tk, {default, _}) -> default; % Default case in union
-eval_e(G, _S, _N, Tk, Val) ->
- ic_error:error(G, {plain_error_string, Val,
- io_lib:format("value and declared type ~p differ", [Tk])}).
-
-%% A fixed type can be 123.45 or 123 but we represent it as integers (i.e. 12345 or 123).
-convert_fixed([], Acc, 0, _) ->
- list_to_integer(lists:reverse(Acc));
-convert_fixed([], _Acc, _, _) ->
- {error, "Fixed type do not match the digits field", []};
-convert_fixed([$.|Rest], Acc, Digits, 0) ->
- convert_fixed(Rest, Acc, Digits, -1);
-convert_fixed([$.|_Rest], _Acc, _, _) ->
- {error, "Fixed decimal point placed incorrectly", []};
-convert_fixed([X|Rest], Acc, Digits, Position) ->
- convert_fixed(Rest, [X|Acc], Digits-1, Position-1).
-
-
-create_fixed([$0|Rest]) ->
- %% Leading zeros shall be ignored.
- create_fixed(Rest);
-create_fixed(Fixed) ->
- create_fixed(Fixed, [], 0, 0, false).
-
-create_fixed([], Acc, Total, Frac, true) ->
- {Fixed, N} = remove_trailing_zeros(Acc, 0),
- Digits = Total-N,
- Scale = Frac-N,
- #fixed{digits = Digits, scale = Scale, value = list_to_integer(Fixed)};
-create_fixed([], Acc, Total, _Frac, false) ->
- %% A '.' never found. Hence, must be 2000D
- #fixed{digits = Total, scale = 0, value = list_to_integer(lists:reverse(Acc))};
-create_fixed([$.|Rest], Acc, Total, _, _) ->
- create_fixed(Rest, Acc, Total, 0, true);
-create_fixed([X|Rest], Acc, Total, Frac, FoundDot) ->
- create_fixed(Rest, [X|Acc], Total+1, Frac+1, FoundDot).
-
-remove_trailing_zeros([$0|Rest], N) ->
- remove_trailing_zeros(Rest, N+1);
-remove_trailing_zeros(Fixed, N) ->
- {lists:reverse(Fixed), N}.
-
-%% Make the newly looked up value a value that can be type checked.
-mk_val({_, _, {tk_string, _}, V}) -> {string, V};
-mk_val({_, _, {tk_wstring, _}, V}) -> {wstring, V}; %% WSTRING
-mk_val({_, _, tk_char, V}) -> {char, V};
-mk_val({_, _, tk_wchar, V}) -> {wchar, V}; %% WCHAR
-mk_val({_, _, enum_val, V}) ->
- {enum_id, ic_forms:get_id2(V)};
-mk_val(X) when element(1, X) == error -> X;
-mk_val({_, _, _TK, V}) ->
- V;
-mk_val(V) -> V.
-
-
-
-%% Floating point numbers
-%%
-%% Conversion to Erlang floating points is neccessary because
-%% list_to_float BIF differs from IDL floats. "1e2" ".4e2" is
-%% allowed in IDL and must be translated to "1.0e2" and "0.4e2"
-
-to_float(X) ->
- list_to_float(erlangify(X)).
-
-erlangify([$. | R]) ->
- [$0, $. | R];
-erlangify(R) ->
- look_for_dot(R).
-
-look_for_dot([$. | R]) -> [$. | dot_pending(R)];
-look_for_dot([$e | R]) -> [$., $0, $e | R];
-look_for_dot([$E | R]) -> [$., $0, $E | R];
-look_for_dot([X | R]) -> [X | look_for_dot(R)].
-
-dot_pending([$e | R]) -> [$0, $e | R];
-dot_pending([$E | R]) -> [$0, $E | R];
-dot_pending([]) -> [$0];
-dot_pending(R) -> R.
-
-
-%%------------------------------------------------------------------
-%%--------------- Fixed Datatype Helper Functions ------------------
-%%------------------------------------------------------------------
-%% Pretty?! No, but since we now the upper-limit this is the fastest way
-%% to calculate 10^x
-power(0) -> 1;
-power(1) -> 10;
-power(2) -> 100;
-power(3) -> 1000;
-power(4) -> 10000;
-power(5) -> 100000;
-power(6) -> 1000000;
-power(7) -> 10000000;
-power(8) -> 100000000;
-power(9) -> 1000000000;
-power(10) -> 10000000000;
-power(11) -> 100000000000;
-power(12) -> 1000000000000;
-power(13) -> 10000000000000;
-power(14) -> 100000000000000;
-power(15) -> 1000000000000000;
-power(16) -> 10000000000000000;
-power(17) -> 100000000000000000;
-power(18) -> 1000000000000000000;
-power(19) -> 10000000000000000000;
-power(20) -> 100000000000000000000;
-power(21) -> 1000000000000000000000;
-power(22) -> 10000000000000000000000;
-power(23) -> 100000000000000000000000;
-power(24) -> 1000000000000000000000000;
-power(25) -> 10000000000000000000000000;
-power(26) -> 100000000000000000000000000;
-power(27) -> 1000000000000000000000000000;
-power(28) -> 10000000000000000000000000000;
-power(29) -> 100000000000000000000000000000;
-power(30) -> 1000000000000000000000000000000;
-power(31) -> 10000000000000000000000000000000;
-power(_) -> 10000000000000000000000000000000.
-
-
-
-%% If the result of an operation (+, -, * or /) causes overflow we use this
-%% operation. However, since these calculations are performed during compiletime,
-%% shouldn't the IDL-specification be changed to not cause overflow?! But, since
-%% the OMG standard allows this we must support it.
-check_fixed_overflow(#fixed{digits = Digits, scale = Scale, value = Value}) ->
- case count_digits(abs(Value)) of
- overflow ->
- {N, NewVal} = cut_overflow(0, Value),
-% NewDigits = Digits - N,
- if
- N > Scale ->
- #fixed{digits = 31, scale = 0, value = NewVal};
- true ->
- NewScale = Scale - N,
- {NewVal2, Removed} = delete_zeros(NewVal, NewScale),
- #fixed{digits = 31, scale = NewScale-Removed, value = NewVal2}
- end;
- Count when Count > Digits ->
- Diff = Count-Digits,
- if
- Diff > Scale ->
- #fixed{digits = Digits, scale = 0,
- value = (Value div power(Diff))};
- true ->
- NewScale = Scale-Diff,
- {NewVal, Removed} = delete_zeros((Value div power(Diff)), NewScale),
- #fixed{digits = Digits-Removed,
- scale = NewScale-Removed,
- value = NewVal}
- end;
- Count ->
- {NewVal, Removed} = delete_zeros(Value, Scale),
- #fixed{digits = Count-Removed, scale = Scale-Removed, value = NewVal}
- end.
-
-%% This function see to that the values are of the same baase.
-normalize(S, V1, S, V2) ->
- {V1, V2};
-normalize(S1, V1, S2, V2) when S1 > S2 ->
- {V1, V2*power(S1-S2)};
-normalize(S1, V1, S2, V2) ->
- {V1*power(S2-S1), V2}.
-
-%% If we have access to the integer part of the fixed type we use this
-%% operation to remove all trailing zeros. If we know the scale, length of
-%% fraction part, we can use delete_zeros as well. But, after a division
-%% it's hard to know the scale and we don't need to calcluate the integer part.
-delete_zeros_value(0, N, _) ->
- {0, 32-N};
-delete_zeros_value(X, N, M) when X > M, (X rem 10) == 0 ->
- delete_zeros_value((X div 10), N+1, M);
-delete_zeros_value(X, N, _) ->
- {X, 32-N}.
-
-%% If we know the exact scale of a fixed type we can use this operation to
-%% remove all trailing zeros.
-delete_zeros(0, _) ->
- {0,0};
-delete_zeros(X, Max) ->
- delete_zeros(X, 0, Max).
-delete_zeros(X, Max, Max) ->
- {X, Max};
-delete_zeros(X, N, Max) when (X rem 10) == 0 ->
- delete_zeros((X div 10), N+1, Max);
-delete_zeros(X, N, _) ->
- {X, N}.
-
-cut_overflow(N, X) when X > ?FIXED_MAX ->
- cut_overflow(N+1, (X div 10));
-cut_overflow(N, X) ->
- {N, X}.
-
-%% A fast way to check the size of a fixed data type.
-count_digits(X) when X > ?FIXED_MAX -> overflow;
-count_digits(X) when X >= 1000000000000000000000000000000 -> 31;
-count_digits(X) when X >= 100000000000000000000000000000 -> 30;
-count_digits(X) when X >= 10000000000000000000000000000 -> 29;
-count_digits(X) when X >= 1000000000000000000000000000 -> 28;
-count_digits(X) when X >= 100000000000000000000000000 -> 27;
-count_digits(X) when X >= 10000000000000000000000000 -> 26;
-count_digits(X) when X >= 1000000000000000000000000 -> 25;
-count_digits(X) when X >= 100000000000000000000000 -> 24;
-count_digits(X) when X >= 10000000000000000000000 -> 23;
-count_digits(X) when X >= 1000000000000000000000 -> 22;
-count_digits(X) when X >= 100000000000000000000 -> 21;
-count_digits(X) when X >= 10000000000000000000 -> 20;
-count_digits(X) when X >= 1000000000000000000 -> 19;
-count_digits(X) when X >= 100000000000000000 -> 18;
-count_digits(X) when X >= 10000000000000000 -> 17;
-count_digits(X) when X >= 1000000000000000 -> 16;
-count_digits(X) when X >= 100000000000000 -> 15;
-count_digits(X) when X >= 10000000000000 -> 14;
-count_digits(X) when X >= 1000000000000 -> 13;
-count_digits(X) when X >= 100000000000 -> 12;
-count_digits(X) when X >= 10000000000 -> 11;
-count_digits(X) when X >= 1000000000 -> 10;
-count_digits(X) when X >= 100000000 -> 9;
-count_digits(X) when X >= 10000000 -> 8;
-count_digits(X) when X >= 1000000 -> 7;
-count_digits(X) when X >= 100000 -> 6;
-count_digits(X) when X >= 10000 -> 5;
-count_digits(X) when X >= 1000 -> 4;
-count_digits(X) when X >= 100 -> 3;
-count_digits(X) when X >= 10 -> 2;
-count_digits(_X) -> 1.
-
-%%------------------------------------------------------------------
-%%--------------- END Fixed Datatype Helper Functions --------------
-%%------------------------------------------------------------------
diff --git a/lib/ic/src/icforms.hrl b/lib/ic/src/icforms.hrl
deleted file mode 100644
index f71aee3664..0000000000
--- a/lib/ic/src/icforms.hrl
+++ /dev/null
@@ -1,70 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%
-%% Module documentation:
-%% ---------------------
-%%
-%% Header file for the Erlang IDL compiler. Contains all records
-%% used in the parse tree
-%%
-%%
-%%------------------------------------------------------------
-
-
-
-%%------------------------------------------------------------
-
--record(module, {id, body}).
--record(interface, {id, inherit, body, inherit_body, tk}).
--record(forward, {id, tk}).
--record(constr_forward, {id, tk}).
--record(const, {type, id, val, tk}).
--record(type_dcl, {type, tk}).
--record(typedef, {type, id, tk}).
--record(struct, {id, body, tk}).
--record(member, {type, id}).
--record(union, {id, type, body, tk}).
--record(case_dcl, {label, id, type}).
--record(enum, {id, body, tk}).
--record(enumerator, {id}).
--record(sequence, {type, length=0}).
--record(string, {length=0}).
--record(wstring, {length=0}). %% WSTRING
--record(array, {id, size}).
--record(attr, {readonly, type, id, tk}).
--record(except, {id, body, tk}).
--record(op, {oneway, type, id, params, raises, ctx, tk}).
--record(param, {inout, type, id, tk}).
--record(fixed, {digits, scale, value}).
-
-%% NON-STANDARD
--record(preproc, {cat, id, aux}).
--record(pragma, {type, to, apply}).
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/ic/src/icparse.yrl b/lib/ic/src/icparse.yrl
deleted file mode 100644
index 27e949729c..0000000000
--- a/lib/ic/src/icparse.yrl
+++ /dev/null
@@ -1,872 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%------------------------------------------------------------
-%% Yecc spec for IDL
-%%
-%%
-%%
-%% Implementation Detail:
-%% OorM_ means OneORMany and is used instead of
-%% the "+" BNF notation
-%% ZorM_ means ZeroORMany and is used instead of
-%% the "*" BNF notation
-%%
-%% All the reverse/1 calls are because yecc+lists naturally leads
-%% to reversed lists, which then have to be reversed. Maybe fix
-%% this?
-%%
-%% Implementation history
-%%
-%% The IDL language supported is not the complete IDL. We skipped
-%% the multiple declarator syntax allowed (i.e. typedef long T1,
-%% T2). This also applies to attributes members in structs,
-%% unions and exceptions, and to case labels in unions. The cases
-%% where IDL has been altered is marked with comments containing
-%% NIY.
-%%
-%% Above is chaging. Whenever we change a clause, we put (FIXED) in
-%% its comment.
-%%
-%%------------------------------------------------------------
-
-
-
-
-
-Nonterminals
- '<op_type_spec>'
- '<enumerator>'
- '<switch_body>'
- 'OorM_<case>'
- '<member_list>'
- '<struct_type>'
- '<unsigned_int>'
- '<constr_type_spec>'
- '<shift_expr>'
- '<or_expr>'
- '<inheritance_spec>'
- 'ZorM_<param_dcl>'
- 'Opt_<context_expr>'
- '<attr_dcl>'
- '<array_declarator>'
- '<element_spec>'
- '<signed_int>'
- '<primary_expr>'
- '<interface_dcl>'
- 'ZorM_<string_literal>'
- 'Opt_<raises_expr>'
- '<integer_type>'
- '<signed_long_int>'
- '<literal>'
- '<export>'
- '<forward_dcl>'
- 'OorM_<definition>'
- '<base_type_spec>'
- '<op_dcl>'
- '<const_exp>'
- '<case>'
- '<any_type>'
- '<signed_short_int>'
- '<unary_expr>'
- '<context_expr>'
- 'ZorM_<scoped_name>'
- '<switch_type_spec>'
- '<complex_declarator>'
- '<declarators>'
- 'OorM_<member>'
- '<interface>'
- '<parameter_dcls>'
- '<op_attribute>'
- '<positive_int_const>'
- 'OorM_<fixed_array_size>'
- '<sequence_type>'
- '<case_label>'
- '<octet_type>'
- '<type_dcl>'
- '<module>'
- '<specification>'
- '<declarator>'
- '<boolean_type>'
- '<union_type>'
- '<add_expr>'
- '<interface_body>'
- '<except_dcl>'
- '<fixed_array_size>'
- '<unsigned_short_int>'
- '<boolean_literal>'
- '<and_expr>'
- 'Opt_<inheritance_spec>'
- '<scoped_name>'
- '<param_type_spec>'
- 'ZorM_<member>'
- '<char_type>'
- '<const_dcl>'
- '<param_dcl>'
- 'ZorM_<simple_declarator>'
- 'ZorM_<declarator>'
- '<const_type>'
- '<definition>'
- '<param_attribute>'
- '<simple_declarator>'
- 'Opt_readonly'
- '<simple_type_spec>'
- '<enum_type>'
- '<type_spec>'
- 'OorM_<case_label>'
- '<floating_pt_type>'
- '<template_type_spec>'
- '<mult_expr>'
- '<xor_expr>'
- '<string_type>'
- '<raises_expr>'
- 'Opt_<op_attribute>'
- 'ZorM_<enumerator>'
- '<member>'
- '<unsigned_long_int>'
- '<type_declarator>'
- '<unary_operator>'
- 'ZorM_<export>'
- '<interface_header>'
- 'OE_preproc' % NON standard
- 'OE_pragma' % NON standard
- 'Ugly_pragmas' % NON standard
- 'ZorM_<integer_literal>'
- '<fixed_pt_type>'
- '<fixed_pt_const_type>'
- '<constr_forward_decl>'
- .
-
-
-Terminals
- '#'
- 'in'
- '['
- 'interface'
- '('
- 'case'
- 'union'
- 'struct'
- '<character_literal>'
- '<wcharacter_literal>'
- ')'
- ']'
- 'any'
- 'long'
- 'float'
- 'out'
- '*'
- '^'
- 'enum'
- 'double'
- '+'
- 'context'
- 'oneway'
- 'sequence'
- ','
- 'FALSE'
- '<identifier>'
- '{'
- 'readonly'
- ':'
- '-'
- 'void'
- ';'
- 'char'
- 'wchar' %% WCHAR
- '|'
- 'inout'
- '}'
- 'attribute'
- '<'
- 'octet'
- '/'
- 'TRUE'
- '~'
- '='
- '>'
- 'switch'
- 'unsigned'
- 'typedef'
- '>>'
- 'const'
- '<string_literal>'
- '<wstring_literal>'
- 'raises'
- 'string'
- 'wstring'
- 'fixed'
- 'default'
- 'short'
- '%'
- '<<'
- 'module'
- 'exception'
- 'boolean'
- '<integer_literal>'
- '<fixed_pt_literal>'
- '<floating_pt_literal>'
- '&'
- '::'
- 'Object'
- .
-
-
-Rootsymbol '<specification>'.
-
-
-Expect 9.
-
-
-%%------------------------------------------------------------
-%% Clauses
-%%
-
-%% Handling of pragmas.
-%% Pragma prefix, id and version are not standard.
-
-%% pragma prefix, or codeopt
-OE_pragma -> '#' '<integer_literal>' '<identifier>'
- '<identifier>' '<string_literal>' '#'
- : #pragma{type='$4', to=followed, apply='$5'} .
-
-%% pragma id
-OE_pragma -> '#' '<integer_literal>' '<identifier>'
- '<identifier>' '<identifier>' '<string_literal>' '#'
- : #pragma{type='$4', to='$5', apply='$6'} .
-
-%% pragma version
-OE_pragma -> '#' '<integer_literal>' '<identifier>'
- '<identifier>' '<identifier>' '<floating_pt_literal>' '#'
- : #pragma{type='$4', to='$5', apply=ic_options:float_to_version('$6')} .
-
-
-
-
-
-
-
-%% Ugly pragmas
-Ugly_pragmas -> '$empty' : [].
-Ugly_pragmas -> 'Ugly_pragmas' 'OE_pragma' : ['$2'|'$1'].
-
-
-
-%% (0) Handling of preprocessor stuff.
-
-OE_preproc -> '#' '#' .
-
-OE_preproc -> '#' '<integer_literal>' '<string_literal>'
- 'ZorM_<integer_literal>' '#'
- : case '$4' of
- [] ->
- case '$2' of
- {_,_,"1"} ->
- #preproc{cat=line_nr, id='$3', aux='$4'};
- _ ->
- []
- end;
- _ ->
- #preproc{cat=line_nr, id='$3', aux='$4'}
- end.
-
-%% (0b) Non-standard
-'ZorM_<integer_literal>' -> '$empty' : [] .
-'ZorM_<integer_literal>' -> '<integer_literal>' 'ZorM_<integer_literal>'
- : ['$1' | '$2'] .
-
-%% (1)
-'<specification>' -> 'OorM_<definition>' : reverse('$1') .
-
-
-%% Added clause
-'OorM_<definition>' -> '<definition>' : ['$1'] .
-'OorM_<definition>' -> 'OorM_<definition>' '<definition>'
-: ['$2' | '$1'] .
-
-
-%% (2)
-'<definition>' -> '<type_dcl>' ';' : '$1' .
-'<definition>' -> '<const_dcl>' ';' : '$1' .
-'<definition>' -> '<except_dcl>' ';' : '$1' .
-'<definition>' -> '<interface>' ';' : '$1' .
-'<definition>' -> '<module>' ';' : '$1' .
-'<definition>' -> 'OE_preproc' : '$1' .
-'<definition>' -> 'OE_pragma' : '$1' .
-
-
-%% (3)
-'<module>' -> 'module' '<identifier>' '{' 'OorM_<definition>' '}'
-: #module{ id='$2', body=reverse('$4')}.
-
-
-%% (4)
-'<interface>' -> '<interface_dcl>' : '$1' .
-'<interface>' -> '<forward_dcl>' : '$1' .
-
-
-%% (5)
-'<interface_dcl>' -> '<interface_header>' '{' '<interface_body>' '}'
- : #interface{id=element(1, '$1'), inherit=element(2, '$1'),
- body=lists:reverse('$3')} .
-
-
-%% (6)
-'<forward_dcl>' -> 'interface' '<identifier>'
-: #forward{id='$2'} .
-
-
-%% (7)
-'<interface_header>' -> 'interface' '<identifier>' 'Opt_<inheritance_spec>'
-: {'$2', '$3'} .
-
-
-%% (8)
-'<interface_body>' -> 'ZorM_<export>' : '$1' .
-
-
-%% Added clause
-'ZorM_<export>' -> '$empty' : [] .
-'ZorM_<export>' -> 'ZorM_<export>' '<export>'
- %% Complicated because <export> might be a list (of type defs for instance)
- : if is_list('$2') -> '$2' ++ '$1';
- true -> ['$2' | '$1']
- end .
-
-
-%% (9)
-'<export>' -> '<type_dcl>' ';' : '$1' .
-'<export>' -> '<const_dcl>' ';' : '$1' .
-'<export>' -> '<except_dcl>' ';' : '$1' .
-'<export>' -> '<attr_dcl>' ';' : '$1' .
-'<export>' -> '<op_dcl>' ';' : '$1' .
-'<export>' -> 'OE_preproc' : '$1' .
-'<export>' -> 'OE_pragma' : '$1' .
-
-%% Added clause
-'Opt_<inheritance_spec>' -> '$empty' : [].
-'Opt_<inheritance_spec>' -> '<inheritance_spec>' : '$1'.
-
-%% (10)
-'<inheritance_spec>' -> ':' '<scoped_name>' 'ZorM_<scoped_name>'
- : ['$2' | reverse('$3')] .
-
-
-%% Added clause
-'ZorM_<scoped_name>' -> '$empty' : [] .
-'ZorM_<scoped_name>' -> 'ZorM_<scoped_name>' ',' '<scoped_name>'
- : ['$3' | '$1'] .
-
-
-%% (11)
-'<scoped_name>' -> '<identifier>' : ic_symtab:scoped_id_new('$1') .
-'<scoped_name>' -> '::' '<identifier>' : ic_symtab:scoped_id_new_global('$2') .
-'<scoped_name>' -> '<scoped_name>' '::' '<identifier>'
- : ic_symtab:scoped_id_add('$1', '$3') .
-
-
-%% (12)
-'<const_dcl>' -> 'const' '<const_type>' '<identifier>' '=' '<const_exp>'
- : #const{type='$2', id='$3', val='$5'} .
-
-
-%% (13)
-'<const_type>' -> '<integer_type>' : '$1' .
-'<const_type>' -> '<char_type>' : '$1' .
-'<const_type>' -> '<boolean_type>' : '$1' .
-'<const_type>' -> '<floating_pt_type>' : '$1' .
-'<const_type>' -> '<string_type>' : '$1' .
-'<const_type>' -> '<fixed_pt_const_type>' : '$1' .
-'<const_type>' -> '<scoped_name>' : '$1' .
-'<const_type>' -> '<octet_type>' : '$1' .
-
-
-%% (14)
-'<const_exp>' -> '<or_expr>' : '$1' .
-
-
-%% (15)
-'<or_expr>' -> '<xor_expr>' : '$1' .
-'<or_expr>' -> '<or_expr>' '|' '<xor_expr>' : {'or', '$1', '$3'} .
-
-
-%% (16)
-'<xor_expr>' -> '<and_expr>' : '$1' .
-'<xor_expr>' -> '<xor_expr>' '^' '<and_expr>' : {'xor', '$1', '$3'} .
-
-
-%% (17)
-'<and_expr>' -> '<shift_expr>' : '$1' .
-'<and_expr>' -> '<and_expr>' '&' '<shift_expr>' : {'and', '$1', '$3'} .
-
-
-%% (18)
-'<shift_expr>' -> '<add_expr>' : '$1' .
-'<shift_expr>' -> '<shift_expr>' '>>' '<add_expr>' : {'rshift', '$1', '$3'} .
-'<shift_expr>' -> '<shift_expr>' '<<' '<add_expr>' : {'lshift', '$1', '$3'} .
-
-
-%% (19)
-'<add_expr>' -> '<mult_expr>' : '$1' .
-'<add_expr>' -> '<add_expr>' '+' '<mult_expr>' : {'+', '$1', '$3'} .
-'<add_expr>' -> '<add_expr>' '-' '<mult_expr>' : {'-', '$1', '$3'} .
-
-
-%% (20)
-'<mult_expr>' -> '<unary_expr>' : '$1' .
-'<mult_expr>' -> '<mult_expr>' '*' '<unary_expr>' : {'*', '$1', '$3'} .
-'<mult_expr>' -> '<mult_expr>' '/' '<unary_expr>' : {'/', '$1', '$3'} .
-'<mult_expr>' -> '<mult_expr>' '%' '<unary_expr>' : {'%', '$1', '$3'} .
-
-
-%% (21)
-'<unary_expr>' -> '<unary_operator>' '<primary_expr>' : {'$1', '$2'} .
-'<unary_expr>' -> '<primary_expr>' : '$1' .
-
-
-%% (22)
-'<unary_operator>' -> '-' : '$1' .
-'<unary_operator>' -> '+' : '$1' .
-'<unary_operator>' -> '~' : '$1' .
-
-
-%% (23)
-'<primary_expr>' -> '<scoped_name>' : '$1' .
-'<primary_expr>' -> '<literal>' : '$1' .
-'<primary_expr>' -> '(' '<const_exp>' ')' : '$2' .
-
-
-%% (24)
-'<literal>' -> '<integer_literal>' : '$1' .
-'<literal>' -> '<wstring_literal>' : '$1' .
-'<literal>' -> '<string_literal>' : '$1' .
-'<literal>' -> '<character_literal>' : '$1' .
-'<literal>' -> '<wcharacter_literal>' : '$1' .
-'<literal>' -> '<fixed_pt_literal>' : '$1' .
-'<literal>' -> '<floating_pt_literal>' : '$1' .
-'<literal>' -> '<boolean_literal>' : '$1' .
-
-
-%% (25)
-'<boolean_literal>' -> 'TRUE' : '$1' .
-'<boolean_literal>' -> 'FALSE' : '$1' .
-
-
-%% (26)
-'<positive_int_const>' -> '<const_exp>' : '$1' .
-
-
-%% (27)
-'<type_dcl>' -> 'typedef' '<type_declarator>' : '$2' .
-'<type_dcl>' -> '<struct_type>' : '$1' .
-'<type_dcl>' -> '<union_type>' : '$1' .
-'<type_dcl>' -> '<enum_type>' : '$1' .
-'<type_dcl>' -> '<constr_forward_decl>' : '$1' .
-
-%% (28) NIY multiple declarators (FIXED)
-'<type_declarator>' -> '<type_spec>' '<declarators>'
- : #typedef{type='$1', id='$2'} . %%%ic:unfold(#typedef{type='$1', id='$2'}) .
-%%'<type_declarator>' -> '<type_spec>' '<declarator>'
-%% : #typedef{type='$1', id='$2'} .
-
-%% (29)
-'<type_spec>' -> '<simple_type_spec>' : '$1' .
-'<type_spec>' -> '<constr_type_spec>' : '$1' .
-
-
-%% (30)
-'<simple_type_spec>' -> '<base_type_spec>' : '$1' .
-'<simple_type_spec>' -> '<template_type_spec>' : '$1' .
-'<simple_type_spec>' -> '<scoped_name>' : '$1' .
-
-
-%% (31)
-'<base_type_spec>' -> '<floating_pt_type>' : '$1' .
-'<base_type_spec>' -> '<integer_type>' : '$1' .
-'<base_type_spec>' -> '<char_type>' : '$1' .
-'<base_type_spec>' -> '<boolean_type>' : '$1' .
-'<base_type_spec>' -> '<octet_type>' : '$1' .
-'<base_type_spec>' -> '<any_type>' : '$1' .
-'<base_type_spec>' -> 'Object' : '$1' . %% NON Standard, isn't a base type
-
-
-%% (32)
-'<template_type_spec>' -> '<sequence_type>' : '$1' .
-'<template_type_spec>' -> '<string_type>' : '$1' .
-'<template_type_spec>' -> '<fixed_pt_type>' : '$1' .
-
-
-%% (33)
-'<constr_type_spec>' -> '<struct_type>' : '$1' .
-'<constr_type_spec>' -> '<union_type>' : '$1' .
-'<constr_type_spec>' -> '<enum_type>' : '$1' .
-
-
-%% (34)
-'<declarators>' -> '<declarator>' 'ZorM_<declarator>'
-: ['$1' | reverse('$2')] .
-
-%% Added clause
-'ZorM_<declarator>' -> '$empty' : [] .
-'ZorM_<declarator>' -> 'ZorM_<declarator>' ',' '<declarator>'
-: ['$3' | '$1'] .
-
-
-%% (35)
-'<declarator>' -> '<simple_declarator>' : '$1' .
-'<declarator>' -> '<complex_declarator>' : '$1' .
-
-
-%% (36)
-'<simple_declarator>' -> '<identifier>' : '$1' .
-
-
-%% (37)
-'<complex_declarator>' -> '<array_declarator>' : '$1' .
-
-
-%% (38)
-'<floating_pt_type>' -> 'float' : '$1' .
-'<floating_pt_type>' -> 'double' : '$1' .
-
-
-%% (39)
-'<integer_type>' -> '<signed_int>' : '$1' .
-'<integer_type>' -> '<unsigned_int>' : {'unsigned', '$1'} .
-
-
-%% (40)
-'<signed_int>' -> '<signed_long_int>' : '$1' .
-'<signed_int>' -> '<signed_short_int>' : '$1' .
-
-
-%% (41)
-'<signed_long_int>' -> 'long' : '$1' .
-'<signed_long_int>' -> 'long' 'long': {'long long', element(2,'$2')} .
-
-
-%% (42)
-'<signed_short_int>' -> 'short' : '$1' .
-
-
-%% (43)
-'<unsigned_int>' -> '<unsigned_long_int>' : '$1' .
-'<unsigned_int>' -> '<unsigned_short_int>' : '$1' .
-
-
-%% (44)
-'<unsigned_long_int>' -> 'unsigned' 'long' : '$2' .
-'<unsigned_long_int>' -> 'unsigned' 'long' 'long' : {'long long', element(2,'$2')} . %% ULLONG
-
-
-%% (45)
-'<unsigned_short_int>' -> 'unsigned' 'short' : '$2' .
-
-
-%% (46)
-'<char_type>' -> 'char' : '$1' .
-'<char_type>' -> 'wchar' : '$1' . %% WCHAR
-
-
-%% (47)
-'<boolean_type>' -> 'boolean' : '$1' .
-
-
-%% (48)
-'<octet_type>' -> 'octet' : '$1' .
-
-
-%% (49)
-'<any_type>' -> 'any' : '$1' .
-
-%%
-'<fixed_pt_const_type>' -> 'fixed' : '$1'.
-
-%% (50) NIY: unfolding of struct decls (FIXED)
-%%'<struct_type>' -> 'struct' '<identifier>' '{' '<member_list>' '}'
-%% : #struct{id='$2', body=ic:unfold('$4')} .
-'<struct_type>' -> 'struct' '<identifier>' '{' '<member_list>' '}'
- : #struct{id='$2', body='$4'} .
-
-
-%% (51)
-'<member_list>' -> 'OorM_<member>' : reverse('$1') .
-
-
-%% Added clause
-%%'OorM_<member>' -> '<member>' : ['$1'] .
-%%'OorM_<member>' -> 'OorM_<member>' '<member>'
-%% : ['$2' | '$1'] .
-
-'OorM_<member>' -> '<member>' : '$1' .
-'OorM_<member>' -> 'OorM_<member>' '<member>'
- : '$2' ++ '$1' .
-
-
-
-%% (52) NIY: member multiple declarators (FIXED)
-%%'<member>' -> '<type_spec>' '<declarators>' ';'
-%% : #member{type='$1', id='$2'} .
-
-'<member>' -> 'Ugly_pragmas' '<type_spec>' '<declarators>' 'Ugly_pragmas' ';' 'Ugly_pragmas'
- : '$1' ++ '$4' ++ '$6' ++ [#member{type='$2', id='$3'}] .
-
-
-%% (53) NIY: unfolding of union cases (FIXED)
-%%'<union_type>' -> 'union' '<identifier>' 'switch'
-%% '(' '<switch_type_spec>' ')' '{' '<switch_body>' '}'
-%% : #union{id='$2', type='$5', body=ic:unfold('$8')} .
-'<union_type>' -> 'union' '<identifier>' 'switch'
- '(' '<switch_type_spec>' ')' '{' '<switch_body>' '}'
- : #union{id='$2', type='$5', body='$8'} .
-
-
-%% (54)
-'<switch_type_spec>' -> '<integer_type>' : '$1' .
-'<switch_type_spec>' -> '<char_type>' : '$1' .
-'<switch_type_spec>' -> '<boolean_type>' : '$1' .
-'<switch_type_spec>' -> '<enum_type>' : '$1' .
-'<switch_type_spec>' -> '<scoped_name>' : '$1' .
-
-
-%% (55)
-'<switch_body>' -> 'OorM_<case>' : reverse(lists:flatten('$1')) .
-
-%%'<switch_body>' -> 'OorM_<case>' : '$1' .
-
-
-%% Added clause
-'OorM_<case>' -> '<case>' : ['$1'] .
-'OorM_<case>' -> 'OorM_<case>' '<case>' : ['$2' | '$1'] .
-
-
-%% (56) NIY thing: multiple case labels (FIXED)
-%%'<case>' -> 'OorM_<case_label>' '<element_spec>' ';'
-%% : '$2'#case_dcl{label=reverse('$1')} .
-
-'<case>' ->
- 'Ugly_pragmas' 'OorM_<case_label>'
- 'Ugly_pragmas' '<element_spec>'
- 'Ugly_pragmas' ';' 'Ugly_pragmas'
- : '$1' ++ '$3' ++ '$5' ++ '$7' ++ [ '$4'#case_dcl{label=reverse('$2')} ] .
-
-
-%% Added clause
-%%'OorM_<case_label>' -> '<case_label>' : ['$1'] .
-%%'OorM_<case_label>' -> 'OorM_<case_label>' '<case_label>' : ['$2' | '$1'] .
-
-'OorM_<case_label>' -> 'Ugly_pragmas' '<case_label>' 'Ugly_pragmas'
- : '$1' ++ ['$2'] ++ '$3' .
-'OorM_<case_label>' -> 'OorM_<case_label>' 'Ugly_pragmas' '<case_label>' 'Ugly_pragmas'
- : '$2' ++ ['$3'|'$1'] ++ '$4'.
-
-
-%% (57)
-'<case_label>' -> 'case' '<const_exp>' ':' : '$2' .
-'<case_label>' -> 'default' ':' : '$1' .
-
-
-%% (58)
-'<element_spec>' -> '<type_spec>' '<declarator>'
-: #case_dcl{type='$1', id='$2'} .
-
-
-%% (59)
-%%'<enum_type>' -> 'enum' '<identifier>'
-%%'{' '<enumerator>' 'ZorM_<enumerator>' '}'
-%%: #enum{id='$2', body=['$4' | reverse('$5')]} .
-
-'<enum_type>' -> 'enum' '<identifier>'
-'{' 'Ugly_pragmas' '<enumerator>' 'Ugly_pragmas' 'ZorM_<enumerator>' 'Ugly_pragmas' '}'
-: #enum{id='$2', body='$4'++'$6'++'$8'++['$5' | reverse('$7')]} .
-
-
-
-%% Added clause
-%%'ZorM_<enumerator>' -> '$empty' : [] .
-%%'ZorM_<enumerator>' -> 'ZorM_<enumerator>' ',' '<enumerator>' : ['$3' | '$1'] .
-
-'ZorM_<enumerator>' -> '$empty' : [] .
-'ZorM_<enumerator>' -> 'ZorM_<enumerator>' 'Ugly_pragmas' ',' 'Ugly_pragmas' '<enumerator>'
- : '$2'++'$4'++['$5' | '$1'] .
-
-%% (60)
-'<enumerator>' -> '<identifier>' : #enumerator{id='$1'} .
-
-
-%% (61)
-'<sequence_type>' -> 'sequence' '<' '<simple_type_spec>' ','
- '<positive_int_const>' '>'
- : #sequence{type='$3', length='$5'} .
-'<sequence_type>' -> 'sequence' '<' '<simple_type_spec>' '>'
- : #sequence{type='$3'} .
-
-
-%% (62)
-'<string_type>' -> 'string' '<' '<positive_int_const>' '>'
- : #string{length='$3'} .
-'<string_type>' -> 'string' : #string{} .
-
-'<string_type>' -> 'wstring' '<' '<positive_int_const>' '>' %% WSTRING
- : #wstring{length='$3'} .
-'<string_type>' -> 'wstring' : #wstring{} . %% WSTRING
-
-
-%% (63)
-'<array_declarator>' -> '<identifier>' 'OorM_<fixed_array_size>'
- : #array{id='$1', size=reverse('$2')} .
-
-
-%% Added clause
-'OorM_<fixed_array_size>' -> '<fixed_array_size>' : ['$1'] .
-'OorM_<fixed_array_size>' -> 'OorM_<fixed_array_size>' '<fixed_array_size>'
- : ['$2' | '$1'] .
-
-
-%% (64)
-'<fixed_array_size>' -> '[' '<positive_int_const>' ']' : '$2' .
-
-
-%% (65) NIY: multiple attribute declarators (FIXED)
-'<attr_dcl>' -> 'Opt_readonly' 'attribute' '<param_type_spec>'
- '<simple_declarator>' 'ZorM_<simple_declarator>'
- : #attr{readonly='$1', type='$3', id=['$4' | reverse('$5')]} .
-%% : ic:unfold(#attr{readonly='$1', type='$3', id=['$4' | reverse('$5')]}) .
-%%'<attr_dcl>' -> 'Opt_readonly' 'attribute' '<param_type_spec>'
-%% '<simple_declarator>'
-
-
-%% (66) NIY: unfolding of exception bodies (FIXED)
-%%'<except_dcl>' -> 'exception' '<identifier>' '{' 'ZorM_<member>' '}'
-%% : #except{id='$2', body=ic:unfold('$4')} .
-'<except_dcl>' -> 'exception' '<identifier>' '{' 'ZorM_<member>' '}'
- : #except{id='$2', body=reverse('$4')} .
-
-%% (67)
-'<op_dcl>' -> 'Opt_<op_attribute>' '<op_type_spec>' '<identifier>' '<parameter_dcls>' 'Opt_<raises_expr>' 'Opt_<context_expr>'
- : #op{oneway='$1', type='$2', id='$3', params='$4', raises='$5', ctx='$6'} .
-
-%% Added clause
-'Opt_<op_attribute>' -> '$empty' : nil.
-'Opt_<op_attribute>' -> '<op_attribute>' : '$1'.
-
-%% (68)
-'<op_attribute>' -> 'oneway' : '$1' .
-
-
-%% (69)
-'<op_type_spec>' -> '<param_type_spec>' : '$1' .
-'<op_type_spec>' -> 'void' : '$1' .
-
-
-%% (70) Rewritten
-%'<parameter_dcls>' -> '(' '<param_dcl>' 'ZorM_<param_dcl>' ')'
-% : ['$2' | reverse('$3')] .
-%'<parameter_dcls>' -> '(' ')' : [] .
-
-'<parameter_dcls>' -> '(' 'Ugly_pragmas' '<param_dcl>' 'ZorM_<param_dcl>' ')'
- : '$2' ++ ['$3' | reverse('$4')] .
-'<parameter_dcls>' -> '(' 'Ugly_pragmas' ')' : '$2' .
-
-
-%% Added clause
-%'ZorM_<param_dcl>' -> '$empty' : [] .
-%'ZorM_<param_dcl>' -> 'ZorM_<param_dcl>' ',' '<param_dcl>' : ['$3' | '$1'] .
-
-
-'ZorM_<param_dcl>' -> 'Ugly_pragmas' : '$1' .
-'ZorM_<param_dcl>' -> 'ZorM_<param_dcl>' 'Ugly_pragmas' ',' 'Ugly_pragmas' '<param_dcl>' 'Ugly_pragmas'
- : '$2' ++ '$4' ++ '$6' ++ ['$5' | '$1'] .
-
-
-
-
-%% (71)
-'<param_dcl>' -> '<param_attribute>' '<param_type_spec>' '<simple_declarator>'
- : #param{inout='$1', type='$2', id='$3'} .
-
-
-%% (72)
-'<param_attribute>' -> 'in' : '$1' .
-'<param_attribute>' -> 'out' : '$1' .
-'<param_attribute>' -> 'inout' : '$1' .
-
-
-%% Added clause
-'Opt_<raises_expr>' -> '$empty' : [] .
-'Opt_<raises_expr>' -> '<raises_expr>' : '$1' .
-
-%% (73)
-'<raises_expr>' -> 'raises' '(' '<scoped_name>' 'ZorM_<scoped_name>' ')'
- : ['$3'| reverse('$4')] .
-
-
-%% Added clause
-'Opt_<context_expr>' -> '$empty' : [] .
-'Opt_<context_expr>' -> '<context_expr>' : '$1'.
-
-%% (74)
-'<context_expr>' -> 'context' '(' '<string_literal>' 'ZorM_<string_literal>'')'
- : ['$3' | reverse('$4')] .
-
-
-
-%% (75)
-'<param_type_spec>' -> '<base_type_spec>' : '$1' .
-'<param_type_spec>' -> '<string_type>' : '$1' .
-'<param_type_spec>' -> '<scoped_name>' : '$1' .
-
-
-%% (96)
-'<fixed_pt_type>' -> 'fixed' '<' '<positive_int_const>' ',' '<positive_int_const>' '>'
- : #fixed{digits='$3',scale='$5'} .
-
-%% (99)
-'<constr_forward_decl>' -> 'struct' '<identifier>' : #constr_forward{id='$2', tk=tk_struct} .
-'<constr_forward_decl>' -> 'union' '<identifier>' : #constr_forward{id='$2', tk=tk_union} .
-
-%% Added clause
-'ZorM_<string_literal>' -> '$empty' : [] .
-'ZorM_<string_literal>' -> 'ZorM_<string_literal>' ',' '<string_literal>'
- : ['$3' | '$1'] .
-
-%% Added clause
-'ZorM_<simple_declarator>' -> '$empty' : [] .
-'ZorM_<simple_declarator>' -> 'ZorM_<simple_declarator>' ','
-'<simple_declarator>' : ['$3' | '$1'] .
-
-%% Added clause
-%%'ZorM_<member>' -> '$empty' : [] .
-%%'ZorM_<member>' -> 'ZorM_<member>' '<member>' : ['$2' | '$1'] .
-
-'ZorM_<member>' -> 'Ugly_pragmas' : '$1' .
-'ZorM_<member>' -> 'ZorM_<member>' '<member>' : '$2' ++ '$1' .
-
-
-%% Added clause
-'Opt_readonly' -> '$empty' : nil.
-'Opt_readonly' -> 'readonly' : '$1'.
-
-
-
-Erlang code.
-%%-----------------------------------------------------------
-
-
-
diff --git a/lib/ic/src/icpreproc.erl b/lib/ic/src/icpreproc.erl
deleted file mode 100644
index fc936c4bf3..0000000000
--- a/lib/ic/src/icpreproc.erl
+++ /dev/null
@@ -1,112 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(icpreproc).
-
-
-
--export([preproc/2]).
-
-
--import(lists, [filter/2]).
-
-
-%%----------------------------------------------------------------------
-%%----------------------------------------------------------------------
-
-
-preproc(G, File) ->
- Cmd = ic_options:get_opt(G, preproc_cmd),
- Flags = ic_options:get_opt(G, preproc_flags),
-
-
- case Cmd of
- "erl" ->
- case ic_pp:run(File,Flags) of
- {ok, [$#, $ , $1 | Rest], []} ->
- [$#, $ , $1 | Rest];
- {ok, [$#, $ , $1 | Rest], Warning} ->
- print_warning(G,Warning),
- [$#, $ , $1 | Rest];
- {error,Error} ->
- print_error(G,Error)
- end;
-
- _ ->
- Line = Cmd++" "++Flags++" "++File,
- % FIXME: Check status code of command instead of this test
- case os:cmd(Line) of
- [$#, $ , C | Rest] when is_integer(C), C > $0, C =< $9 ->
- [$#, $ , C | Rest];
- X ->
- ic_error:fatal_error(G, {preproc, filter(X)})
- end
- end.
-
-
-filter(X) ->
- X2 = divide_nl(X, []),
- filter_x_switch(X2).
-
-
-divide_nl([10 | Xs], Out) ->
- [lists:reverse(Out) | divide_nl(Xs, [])];
-divide_nl([X | Xs], Out) -> divide_nl(Xs, [X|Out]);
-divide_nl([], Out) -> lists:reverse(Out).
-
-
-filter_x_switch(L) ->
- filter(fun([$g,$c,$c,$:,$ ,$W,$a,$r,$n,$i,$n,$g,$:,$ ,$`,$-,$x,$ | _]) ->
- false;
- (_) -> true end, L).
-
-
-print_error(_G,[]) ->
- ok;
-print_error(G,[{File,Line,Text}]) ->
- ErrorText = File++":"++integer_to_list(Line)++": "++Text,
- ic_error:fatal_error(G, {ic_pp_error, ErrorText}),
- ok;
-print_error(G,[{File,Line,Text}|T]) ->
- ErrorText = File++":"++integer_to_list(Line)++": "++Text,
- ic_error:error(G, {ic_pp_error, ErrorText}),
- print_error(G,T);
-print_error(G,[H]) ->
- ErrorText = H++"\n",
- ic_error:fatal_error(G, {ic_pp_error, ErrorText}),
- ok;
-print_error(G,[H|T]) ->
- ErrorText = H++"\n",
- ic_error:error(G, {ic_pp_error, ErrorText}),
- print_error(G,T).
-
-
-print_warning(_G,[]) ->
- ok;
-print_warning(G,[{File,Line,Text}|T]) ->
- WarText = File++":"++integer_to_list(Line)++": "++Text,
- ic_error:warn(G, {ic_pp_warning, WarText}),
- print_warning(G,T);
-print_warning(G,[H|T]) ->
- WarText = H++"\n",
- ic_error:warn(G, {ic_pp_warning, WarText}),
- print_warning(G,T).
-
-
diff --git a/lib/ic/src/icscan.erl b/lib/ic/src/icscan.erl
deleted file mode 100644
index 123041495e..0000000000
--- a/lib/ic/src/icscan.erl
+++ /dev/null
@@ -1,453 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(icscan).
-
-
--export([scan/2]).
-
--include("ic.hrl").
-
-
-%%----------------------------------------------------------------------
-%%----------------------------------------------------------------------
-
--import(lists, [reverse/1]).
-
-
-scan(G, File) ->
- PL = call_preproc(G, File),
- call_scan(G, PL).
-
-call_preproc(G, File) ->
- case ic_options:get_opt(G, use_preproc) of
- true ->
- icpreproc:preproc(G, File);
- false ->
- case catch file:read_file(File) of
- {ok, Bin} ->
- binary_to_list(Bin);
- Other ->
- exit(Other)
- end
- end.
-
-call_scan(G, PL) ->
- BE = ic_options:get_opt(G, be),
- RSL = scan(G, BE, PL, 1, []),
- lists:reverse(RSL).
-
-
-%% Guard macros used at top scan functions only
--define(is_number(X), X >= $0 , X =< $9).
--define(is_upper(X), X >= $A , X =< $Z).
--define(is_lower(X), X >= $a, X =< $z).
--define(is_hex_uc(X), X >= $A , X =< $F).
--define(is_hex_lc(X), X >= $a , X =< $f).
--define(is_octal(X), X >=$0, X =< $7).
-
-%% Handle:
-%% const wchar aWChar = L'X';
-scan(G, BE, [$L, $'|Str], Line, Out) ->
- scan_const(G, BE, wchar, Str, [], Line, Out);
-scan(G, BE, [$L, $"|Str], Line, Out) ->
- scan_const(G, BE, wstring, Str, [], Line, Out);
-scan(G, BE, [$_, X|Str], Line, Out) when ?is_upper(X) ->
- scan_name(G, BE, Str, [X], false, Line, Out);
-scan(G, BE, [$_, X|Str], Line, Out) when ?is_lower(X) ->
- scan_name(G, BE, Str, [X], false, Line, Out);
-scan(G, BE, [X|Str], Line, Out) when ?is_upper(X) ->
- scan_name(G, BE, Str, [X], true, Line, Out);
-scan(G, BE, [X|Str], Line, Out) when ?is_lower(X) ->
- scan_name(G, BE, Str, [X], true, Line, Out);
-scan(G, BE, [X|Str], Line, Out) when ?is_number(X) ->
- scan_number(G, BE, Str, [X], Line, Out);
-scan(G, BE, [9| T], Line, Out) -> scan(G, BE, T, Line, Out);
-scan(G, BE, [32| T], Line, Out) -> scan(G, BE, T, Line, Out);
-scan(G, BE, [$\r|Str], Line, Out) ->
- scan(G, BE, Str, Line, Out);
-scan(G, BE, [$\n|Str], Line, Out) ->
- scan(G, BE, Str, Line+1, Out);
-scan(G, BE, [$:, $: | Str], Line, Out) ->
- scan(G, BE, Str, Line, [{'::', Line} | Out]);
-scan(G, BE, [$/, $/ | Str], Line, Out) ->
- Rest = skip_to_nl(Str),
- scan(G, BE, Rest, Line, Out);
-scan(G, BE, [$/, $* | Str], Line, Out) ->
- Rest = skip_comment(Str),
- scan(G, BE, Rest, Line, Out);
-scan(G, BE, [$", $\\|Str], Line, Out) ->
- scan_const(G, BE, string, [$\\|Str], [], Line, Out);
-scan(G, BE, [$"|Str], Line, Out) ->
- scan_const(G, BE, string, Str, [], Line, Out);
-scan(G, BE, [$', $\\|Str], Line, Out) ->
- scan_const(G, BE, char, [$\\|Str], [], Line, Out);
-scan(G, BE, [$'|Str], Line, Out) ->
- scan_const(G, BE, char, Str, [], Line, Out);
-scan(G, BE, [$\\|Str], Line, Out) ->
- scan_const(G, BE, escaped, [$\\|Str], [], Line, Out);
-scan(G, BE, [$. | Str], Line, Out) ->
- scan_frac(G, BE, Str, [$.], Line, Out);
-scan(G, BE, [$# | Str], Line, Out) ->
- scan_preproc(G, BE, Str, Line, Out);
-scan(G, BE, [$<, $< | Str], Line, Out) ->
- scan(G, BE, Str, Line, [{'<<', Line} | Out]);
-scan(G, BE, [$>, $> | Str], Line, Out) ->
- scan(G, BE, Str, Line, [{'>>', Line} | Out]);
-scan(G, BE, [C|Str], Line, Out) ->
- scan(G, BE, Str, Line, [{list_to_atom([C]), Line} | Out]);
-
-scan(_G, _BE, [], _Line, Out) ->
- Out.
-
-
-scan_number(G, BE, [X|Str], [$0], Line, Out) when X == $X ; X ==$x ->
- case Str of
- [D|_TmpStr] when ?is_number(D); ?is_hex_uc(D); ?is_hex_lc(D) ->
- {Num,Rest} = scan_hex_number(Str,0),
- scan(G, BE, Rest, Line, [{'<integer_literal>', Line,
- integer_to_list(Num)} | Out]);
- [D|TmpStr] ->
- scan(G, BE, TmpStr, Line, [{list_to_atom([D]), Line} | Out])
- end;
-scan_number(G, BE, Str, [$0], Line, Out) ->
- %% If an integer literal starts with a 0 it may indicate that
- %% it is represented as an octal number. But, it can also be a fixed
- %% type which must use padding to match a fixed typedef. For example:
- %% typedef fixed<5,2> fixed52;
- %% 123.45d, 123.00d and 023.00d is all valid fixed values.
- %% Naturally, a float can be defined as 0.14 or 00.14.
- case pre_scan_number(Str, [], octal) of
- octal ->
- {Num, Rest} = scan_octal_number(Str,0),
- scan(G, BE, Rest, Line, [{'<integer_literal>', Line,
- integer_to_list(Num)} | Out]);
- {fixed, Fixed, Rest} ->
- scan(G, BE, Rest, Line, [{'<fixed_pt_literal>', Line, Fixed} | Out]);
- float ->
- %% Not very likely that someone defines a constant as 00.14 but ...
- NewStr = remove_leading_zeroes(Str),
- scan(G, BE, NewStr, Line, Out)
- end;
-scan_number(G, BE, [X|Str], Accum, Line, Out) when ?is_number(X) ->
- scan_number(G, BE, Str, [X|Accum], Line, Out);
-scan_number(G, BE, [X|Str], Accum, Line, Out) when X==$. ->
- scan_frac(G, BE, Str, [X|Accum], Line, Out);
-scan_number(G, BE, [X|Str], Accum, Line, Out) when X==$e ; X==$e ->
- scan_exp(G, BE, Str, [X|Accum], Line, Out);
-scan_number(G, BE, [X|Str], Accum, Line, Out) when X==$D ; X==$d ->
- scan(G, BE, Str, Line, [{'<fixed_pt_literal>', Line,
- (lists:reverse(Accum))} | Out]);
-scan_number(G, BE, Str, Accum, Line, Out) ->
- scan(G, BE, Str, Line, [{'<integer_literal>', Line,
- (lists:reverse(Accum))} | Out]).
-
-
-remove_leading_zeroes([$0|Rest]) ->
- remove_leading_zeroes(Rest);
-remove_leading_zeroes(L) ->
- L.
-
-scan_hex_number([X|Rest],Acc) when X >=$a, X =< $f ->
- scan_hex_number(Rest,(Acc bsl 4) + (X - $a + 10));
-scan_hex_number([X|Rest],Acc) when X >=$A, X =< $F ->
- scan_hex_number(Rest,(Acc bsl 4) + (X - $A + 10));
-scan_hex_number([X|Rest],Acc) when X >=$0, X =< $9 ->
- scan_hex_number(Rest,(Acc bsl 4) + (X-$0));
-scan_hex_number(Rest,Acc) ->
- {Acc,Rest}.
-
-pre_scan_number([$d|Rest], Acc, _) ->
- {fixed, [$0|lists:reverse(Acc)], Rest};
-pre_scan_number([$D|Rest], Acc, _) ->
- {fixed, [$0|lists:reverse(Acc)], Rest};
-pre_scan_number([$.|Rest], Acc, _) ->
- %% Actually, we don't know if it's a float since it can be a fixed.
- pre_scan_number(Rest, [$.|Acc], float);
-pre_scan_number([X|_], _Acc, _) when X == $E ; X ==$e ->
- %% Now we now it's a float.
- float;
-pre_scan_number([X|Rest], Acc, Type) when ?is_number(X) ->
- pre_scan_number(Rest, [X|Acc], Type);
-pre_scan_number(_Rest, _Acc, Type) ->
- %% At this point we know it's a octal or float.
- Type.
-
-scan_octal_number([X|Rest],Acc) when ?is_octal(X) ->
- scan_octal_number(Rest,(Acc bsl 3) + (X-$0));
-scan_octal_number(Rest,Acc) ->
- {Acc, Rest}.
-
-%% Floating point number scan.
-%%
-%% Non trivial scan. A float consists of an integral part, a
-%% decimal point, a fraction part, an e or E and a signed integer
-%% exponent. Either the integer part or the fraction part but not
-%% both may be missing, and either the decimal point or the
-%% exponent part but not both may be missing. The exponent part
-%% must consist of an e or E and a possibly signed exponent.
-%%
-%% Analysis shows that "1." ".7" "1e2" ".5e-3" "1.7e2" "1.7e-2"
-%% is allowed and "1" ".e9" is not. The sign is only allowed just
-%% after an e or E. The scanner reads a number as an integer
-%% until it encounters a "." so the integer part only error case
-%% will not be caught in the scanner (but rather in expression
-%% evaluation)
-
-scan_frac(G, _BE, [$e | _Str], [$.], Line, _Out) ->
- ic_error:fatal_error(G, {illegal_float, Line});
-scan_frac(G, _BE, [$E | _Str], [$.], Line, _Out) ->
- ic_error:fatal_error(G, {illegal_float, Line});
-scan_frac(G, BE, Str, Accum, Line, Out) ->
- scan_frac2(G, BE, Str, Accum, Line, Out).
-
-scan_frac2(G, BE, [X|Str], Accum, Line, Out) when ?is_number(X) ->
- scan_frac2(G, BE, Str, [X|Accum], Line, Out);
-scan_frac2(G, BE, [X|Str], Accum, Line, Out) when X==$e ; X==$E ->
- scan_exp(G, BE, Str, [X|Accum], Line, Out);
-%% The following case is for fixed (e.g. 123.45d).
-scan_frac2(G, BE, [X|Str], Accum, Line, Out) when X==$d ; X==$D ->
- scan(G, BE, Str, Line, [{'<fixed_pt_literal>', Line,
- (lists:reverse(Accum))} | Out]);
-scan_frac2(G, BE, Str, Accum, Line, Out) ->
- scan(G, BE, Str, Line, [{'<floating_pt_literal>', Line,
- (lists:reverse(Accum))} | Out]).
-
-scan_exp(G, BE, [X|Str], Accum, Line, Out) when X==$- ->
- scan_exp2(G, BE, Str, [X|Accum], Line, Out);
-scan_exp(G, BE, Str, Accum, Line, Out) ->
- scan_exp2(G, BE, Str, Accum, Line, Out).
-
-scan_exp2(G, BE, [X|Str], Accum, Line, Out) when ?is_number(X) ->
- scan_exp2(G, BE, Str, [X|Accum], Line, Out);
-scan_exp2(G, BE, Str, Accum, Line, Out) ->
- scan(G, BE, Str, Line, [{'<floating_pt_literal>', Line,
- (lists:reverse(Accum))} | Out]).
-
-
-scan_name(G, BE, [X|Str], Accum, TypeCheck, Line, Out) when ?is_upper(X) ->
- scan_name(G, BE, Str, [X|Accum], TypeCheck, Line, Out);
-scan_name(G, BE, [X|Str], Accum, TypeCheck, Line, Out) when ?is_lower(X) ->
- scan_name(G, BE, Str, [X|Accum], TypeCheck, Line, Out);
-scan_name(G, BE, [X|Str], Accum, TypeCheck, Line, Out) when ?is_number(X) ->
- scan_name(G, BE, Str, [X|Accum], TypeCheck, Line, Out);
-scan_name(G, BE, [$_|Str], Accum, TypeCheck, Line, Out) ->
- scan_name(G, BE, Str, [$_|Accum], TypeCheck, Line, Out);
-scan_name(G, BE, S, Accum, false, Line, Out) ->
- %% The CORBA 2.3 specification allows the user to override typechecking:
- %% typedef string _native;
- %% interface i {
- %% void foo(in _native VT);
- %% };
- %% BUT, the IFR-id remains the same ("IDL:native:1.0") etc. The reason for
- %% this is that one don't have to re-write a large chunk of IDL- and
- %% application-code.
- scan(G, BE, S, Line, [{'<identifier>', Line, lists:reverse(Accum)} | Out]);
-scan_name(G, BE, S, Accum, _, Line, Out) ->
- L = lists:reverse(Accum),
- X = case is_reserved(L, BE) of
- undefined ->
- {'<identifier>', Line, L};
- Yes ->
- {Yes, Line}
- end,
- scan(G, BE, S, Line, [X | Out]).
-
-%% Shall scan a constant
-scan_const(G, BE, string, [$" | Rest], Accum, Line, [{'<string_literal>', _, Str}|Out]) ->
- scan(G, BE, Rest, Line,
- [{'<string_literal>', Line, Str ++ lists:reverse(Accum)} | Out]);
-scan_const(G, BE, string, [$" | Rest], Accum, Line, Out) ->
- scan(G, BE, Rest, Line,
- [{'<string_literal>', Line, lists:reverse(Accum)} | Out]);
-scan_const(G, BE, wstring, [$" | Rest], Accum, Line, [{'<wstring_literal>', _,Wstr}|Out]) -> %% WSTRING
- scan(G, BE, Rest, Line,
- [{'<wstring_literal>', Line, Wstr ++ lists:reverse(Accum)} | Out]);
-scan_const(G, BE, wstring, [$" | Rest], Accum, Line, Out) -> %% WSTRING
- scan(G, BE, Rest, Line,
- [{'<wstring_literal>', Line, lists:reverse(Accum)} | Out]);
-scan_const(G, _BE, string, [], _Accum, Line, Out) -> %% Bad string
- ic_error:error(G, {bad_string, Line}),
- Out;
-scan_const(G, _BE, wstring, [], _Accum, Line, Out) -> %% Bad WSTRING
- ic_error:error(G, {bad_string, Line}),
- Out;
-scan_const(G, BE, char, [$' | Rest], Accum, Line, Out) ->
- scan(G, BE, Rest, Line,
- [{'<character_literal>', Line, lists:reverse(Accum)} | Out]);
-scan_const(G, BE, wchar, [$' | Rest], Accum, Line, Out) -> %% WCHAR
- scan(G, BE, Rest, Line,
- [{'<wcharacter_literal>', Line, lists:reverse(Accum)} | Out]);
-scan_const(G, BE, Mode, [$\\, C | Rest], Accum, Line, Out) ->
- case escaped_char(C) of
- error ->
- ic_error:error(G, {bad_escape_character, Line, C}), %% Bad escape character
- scan_const(G, BE, Mode, Rest, [C | Accum], Line, Out);
- octal ->
- {Num,Rest2} = scan_octal_number([C|Rest], 0),
- scan_const(G, BE, Mode, Rest2, [Num|Accum], Line, Out);
- hexadecimal ->
- {Num,Rest2} = scan_hex_number(Rest, 0),
- if
- Num > 255 -> %% 16#FF
- ic_error:error(G, {bad_escape_character, Line, C}),
- scan_const(G, BE, Mode, Rest, [C | Accum], Line, Out);
- true ->
- scan_const(G, BE, Mode, Rest2, [Num|Accum], Line, Out)
- end;
- unicode ->
- {Num,Rest2} = scan_hex_number(Rest, 0),
- if
- Num > 65535 -> %% 16#FFFF
- ic_error:error(G, {bad_escape_character, Line, C}),
- scan_const(G, BE, Mode, Rest, [C | Accum], Line, Out);
- true ->
- scan_const(G, BE, Mode, Rest2, [Num|Accum], Line, Out)
- end;
- EC ->
- scan_const(G, BE, Mode, Rest, [EC | Accum], Line, Out)
- end;
-scan_const(G, BE, Mode, [C | Rest], Accum, Line, Out) ->
- scan_const(G, BE, Mode, Rest, [C | Accum], Line, Out).
-
-
-%%
-%% Preprocessor output handling
-%%
-%% gcc outputs a line with line number, file name (within \") and
-%% one or more integer flags. The scanner scans the line number,
-%% the id and all integers up to nl.
-%%
-%% NOTE: This will have to be enhanced in order to eat #pragma
-%%
-scan_preproc(G, BE, Str, Line, Out) ->
- {List, Rest} = scan_to_nl(strip(Str), []),
- NewLine = get_new_line_nr(strip(List), Line+1, []),
- case scan_number(G, BE, List, [], Line, [{'#', Line} | Out]) of
- L when is_list(L) ->
- scan(G, BE, Rest, NewLine, [{'#', Line} | L])
- end.
-
-get_new_line_nr([C|R], Line, Acc) when C>=$0, C=<$9 ->
- get_new_line_nr(R, Line, [C|Acc]);
-get_new_line_nr(_, Line, []) -> Line; % No line nr found
-get_new_line_nr(_, _, Acc) -> list_to_integer(reverse(Acc)).
-
-scan_to_nl([], Acc) -> {reverse(Acc), []};
-scan_to_nl([$\n|Str], Acc) -> {reverse(Acc), Str};
-scan_to_nl([$\r|R], Acc) -> scan_to_nl(R, Acc);
-scan_to_nl([C|R], Acc) -> scan_to_nl(R, [C|Acc]).
-
-strip([$ |R]) -> strip(R);
-strip(L) -> L.
-
-%% Escaped character. Escaped chars are repr as two characters in the
-%% input list of letters and this is translated into one char.
-escaped_char($n) -> $\n;
-escaped_char($t) -> $\t;
-escaped_char($v) -> $\v;
-escaped_char($b) -> $\b;
-escaped_char($r) -> $ ;
-escaped_char($f) -> $\f;
-escaped_char($a) -> $\a;
-escaped_char($\\) -> $\\;
-escaped_char($?) -> $?;
-escaped_char($') -> $';
-escaped_char($") -> $";
-escaped_char($x) -> hexadecimal;
-escaped_char($u) -> unicode;
-escaped_char(X) when ?is_octal(X) -> octal;
-%% Error
-escaped_char(_Other) -> error.
-
-skip_to_nl([]) -> [];
-skip_to_nl([$\n | Str]) ->[$\n | Str];
-skip_to_nl([_|Str]) ->
- skip_to_nl(Str).
-
-skip_comment([$\\, _ | Str]) ->
- skip_comment(Str);
-skip_comment([$*, $/ | Str]) -> Str;
-skip_comment([_|Str]) ->
- skip_comment(Str).
-
-
-%%----------------------------------------------------------------------
-%% Shall separate keywords from identifiers and numbers
-
-%% Fill in the ets of reserved words
-is_reserved("Object", _) -> 'Object';
-is_reserved("in", _) -> in;
-is_reserved("interface", _) -> interface;
-is_reserved("case", _) -> 'case';
-is_reserved("union", _) -> union;
-is_reserved("struct", _) -> struct;
-is_reserved("any", _) -> any;
-is_reserved("long", _) -> long;
-is_reserved("float", _) -> float;
-is_reserved("out", _) -> out;
-is_reserved("enum", _) -> enum;
-is_reserved("double", _) -> double;
-is_reserved("context", _) -> context;
-is_reserved("oneway", _) -> oneway;
-is_reserved("sequence", _) -> sequence;
-is_reserved("FALSE", _) -> 'FALSE';
-is_reserved("readonly", _) -> readonly;
-is_reserved("char", _) -> char;
-is_reserved("wchar", _) -> wchar;
-is_reserved("void", _) -> void;
-is_reserved("inout", _) -> inout;
-is_reserved("attribute", _) -> attribute;
-is_reserved("octet", _) -> octet;
-is_reserved("TRUE", _) -> 'TRUE';
-is_reserved("switch", _) -> switch;
-is_reserved("unsigned", _) -> unsigned;
-is_reserved("typedef", _) -> typedef;
-is_reserved("const", _) -> const;
-is_reserved("raises", _) -> raises;
-is_reserved("string", _) -> string;
-is_reserved("wstring", _) -> wstring;
-is_reserved("default", _) -> default;
-is_reserved("short", _) -> short;
-is_reserved("module", _) -> module;
-is_reserved("exception", _) -> exception;
-is_reserved("boolean", _) -> boolean;
-%% --- New keywords Introduced in CORBA-2.3.1 ---
-%% For now we cannot add these for all backends right now since it would cause
-%% some problems for at least one customer.
-is_reserved("fixed", BE) -> check_be(BE, fixed);
-%is_reserved("abstract", BE) -> check_be(BE, abstract);
-%is_reserved("custom", BE) -> check_be(BE, custom);
-%is_reserved("factory", BE) -> check_be(BE, factory);
-%is_reserved("local", BE) -> check_be(BE, local);
-%is_reserved("native", BE) -> check_be(BE, native);
-%is_reserved("private", BE) -> check_be(BE, private);
-%is_reserved("public", BE) -> check_be(BE, public);
-%is_reserved("supports", BE) -> check_be(BE, supports);
-%is_reserved("truncatable", BE) -> check_be(BE, truncatable);
-%is_reserved("ValueBase", BE) -> check_be(BE, 'ValueBase');
-%is_reserved("valuetype", BE) -> check_be(BE, valuetype);
-is_reserved(_, _) -> undefined.
-
-check_be(erl_corba, KeyWord) ->
- KeyWord;
-check_be(_, _) ->
- undefined.
-
diff --git a/lib/ic/src/icstruct.erl b/lib/ic/src/icstruct.erl
deleted file mode 100644
index 713ac87287..0000000000
--- a/lib/ic/src/icstruct.erl
+++ /dev/null
@@ -1,1917 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(icstruct).
-
-
--export([struct_gen/4, except_gen/4, create_c_array_coding_file/5]).
-
-%%------------------------------------------------------------
-%%
-%% Internal stuff
-%%
-%%------------------------------------------------------------
--import(ic_codegen, [emit/2, emit/3, emit/4, emit_c_enc_rpt/4, emit_c_dec_rpt/4]).
-
--include("icforms.hrl").
--include("ic.hrl").
-
-
-
-%%------------------------------------------------------------
-
-%%------------------------------------------------------------
-%%
-%% File handling stuff
-%%
-%%------------------------------------------------------------
-
-
-
-%%------------------------------------------------------------
-%%
-%% Generation loop
-%%
-%% The idea is to traverse everything and find every struct that
-%% may be hiding down in nested types. All structs that are found
-%% are generated to a hrl file.
-%%
-%% struct_gen is entry point for structs and types, except_gen is
-%% for exceptions
-%%
-%%------------------------------------------------------------
-
-
-except_gen(G, N, X, L) when is_record(X, except) ->
- N2 = [ic_forms:get_id2(X) | N],
- if
- L == c ->
- io:format("Warning : Exception not defined for c mapping\n", []);
- true ->
- emit_struct(G, N, X, L)
- end,
- struct_gen_list(G, N2, ic_forms:get_body(X), L).
-
-struct_gen(G, N, X, L) when is_record(X, struct) ->
- N2 = [ic_forms:get_id2(X) | N],
- struct_gen_list(G, N2, ic_forms:get_body(X), L),
- emit_struct(G, N, X, L);
-struct_gen(G, N, X, L) when is_record(X, union) ->
- N2 = [ic_forms:get_id2(X) | N],
- if
- L == c ->
- %% Produce the "body" first
- struct_gen_list(G, N2, ic_forms:get_body(X), L),
- icunion:union_gen(G, N, X, c);
- true ->
- struct_gen(G, N, ic_forms:get_type(X), L),
- struct_gen_list(G, N2, ic_forms:get_body(X), L)
- end,
- emit_union(G, N, X, L);
-struct_gen(G, N, X, L) when is_record(X, member) ->
- struct_gen(G, N, ic_forms:get_type(X), L);
-struct_gen(G, N, X, L) when is_record(X, typedef) ->
- struct_gen(G, N, ic_forms:get_body(X), L),
- emit_typedef(G, N, X, L);
-struct_gen(G, N, X, L) when is_record(X, type_dcl) ->
- struct_gen_list(G, N, ic_forms:get_type(X), L);
-struct_gen(G, N, X, L) when is_record(X, case_dcl) ->
- struct_gen(G, N, ic_forms:get_type(X), L);
-struct_gen(G, N, X, L) when is_record(X, sequence) ->
- struct_gen(G, N, ic_forms:get_type(X), L),
- X;
-struct_gen(G, N, X, L) when is_record(X, enum) ->
- icenum:enum_gen(G, N, X, L);
-struct_gen(_G, _N, _X, _L) ->
- ok.
-
-%% List clause for struct_gen
-struct_gen_list(G, N, Xs, L) ->
- lists:foreach(
- fun(X) ->
- R = struct_gen(G, N, X, L),
- if
- L == c ->
- if
- is_record(R,sequence) ->
- emit_sequence_head_def(G,N,X,R,L);
- true ->
- ok
- end;
- true ->
- ok
- end
- end, Xs).
-
-
-%% emit primitive for structs.
-emit_struct(G, N, X, erlang) ->
- case ic_genobj:is_hrlfile_open(G) of
- true ->
- %% Make a straight list of all member ids (this is a
- %% variant of flatten)
- EList = lists:map(
- fun(XX) ->
- lists:map(
- fun(XXX) ->
- ic_util:to_atom(ic_forms:get_id2(XXX))
- end,
- ic_forms:get_idlist(XX))
- end,
- ic_forms:get_body(X)),
- ic_codegen:record(G, X,
- ic_util:to_undersc([ic_forms:get_id2(X) | N]),
- ictk:get_IR_ID(G, N, X), lists:flatten(EList)),
- mkFileRecObj(G,N,X,erlang);
- false ->
- ok
- end;
-emit_struct(G, N, X, c) ->
-
- N1 = [ic_forms:get_id2(X) | N],
- case ic_pragma:is_local(G,N1) of
- true ->
- emit_c_struct(G, N, X,local);
- false ->
- emit_c_struct(G, N, X,included)
- end.
-
-
-emit_c_struct(_G, _N, _X, included) ->
- %% Do not generate included types att all.
- ok;
-emit_c_struct(G, N, X, local) ->
- case ic_genobj:is_hrlfile_open(G) of
- true ->
- Fd = ic_genobj:hrlfiled(G),
-
- N1 = [ic_forms:get_id2(X) | N],
- StructName = ic_util:to_undersc(N1),
-
- %% Make a straight list of all member ids (this is a
- %% variant of flatten)
- M = lists:map(
- fun(XX) ->
- lists:map(
- fun(XXX) ->
- if
- is_record(XXX, array) ->
- Type = ic_forms:get_type(XX),
- Name = element(3,element(2,XXX)),
- {_, _, StructTK, _} =
- ic_symtab:get_full_scoped_name(
- G,
- N,
- ic_symtab:scoped_id_new(
- ic_forms:get_id2(X))),
- ArrayTK =
- get_structelement_tk(StructTK,
- Name),
- Dim = extract_dim(ArrayTK),
- %% emit array file
- emit(Fd, "\n#ifndef __~s__\n",
- [ic_util:to_uppercase(
- StructName ++ "_"
- ++ Name)]),
- emit(Fd, "#define __~s__\n\n",
- [ic_util:to_uppercase(
- StructName ++ "_"
- ++ Name)]),
- create_c_array_coding_file(
- G,
- N,
- {StructName ++ "_" ++ Name, Dim},
- Type,
- no_typedef),
- emit(Fd, "\n#endif\n\n"),
- {{Type, XXX},
- ic_forms:get_id2(XXX)};
- true ->
- %% Ugly work around to fix the ETO
- %% return patch problem
- Name =
- case ic_forms:get_id2(XXX) of
- "return" ->
- "return1";
- Other ->
- Other
- end,
- {ic_forms:get_type(XX), Name}
- end
- end,
- ic_forms:get_idlist(XX))
- end,
- ic_forms:get_body(X)),
- EList = lists:flatten(M),
- %%io:format("Elist = ~p~n",[EList]),
-
- emit(Fd, "\n#ifndef __~s__\n",[ic_util:to_uppercase(StructName)]),
- emit(Fd, "#define __~s__\n",[ic_util:to_uppercase(StructName)]),
- ic_codegen:mcomment_light(Fd,
- [io_lib:format("Struct definition: ~s",
- [StructName])],
- c),
- emit(Fd, "typedef struct {\n"),
- lists:foreach(
- fun({Type, Name}) ->
- emit_struct_member(Fd, G, N1, X, Name, Type)
- end,
- EList),
- emit(Fd, "} ~s;\n\n", [StructName]),
- create_c_struct_coding_file(G, N, X, nil, StructName,
- EList, struct),
- emit(Fd, "\n#endif\n\n");
- false ->
- ok
- end.
-
-%% Extracts array dimention(s)
-
-get_structelement_tk({tk_struct, _, _, EList}, EN) ->
- {value, {EN, ArrayTK}} = lists:keysearch(EN, 1, EList),
- ArrayTK.
-
-extract_dim({tk_array, {tk_array, T, D1}, D}) ->
- [integer_to_list(D) | extract_dim({tk_array, T, D1})];
-extract_dim({tk_array, _, D}) ->
- [integer_to_list(D)].
-
-%% Makes the array name
-mk_array_name(Name,Dim) ->
- Name ++ mk_array_name(Dim).
-
-mk_array_name([]) ->
- "";
-mk_array_name([Dim|Dims]) ->
- "[" ++ Dim ++ "]" ++ mk_array_name(Dims).
-
-
-emit_struct_member(Fd, G, N, X, Name,{Type,Array}) when is_record(Array, array)->
- {_, _, StructTK, _} =
- ic_symtab:get_full_scoped_name(
- G,
- N,
- ic_symtab:scoped_id_new(ic_forms:get_id2(X))),
- ArrayTK = get_structelement_tk(StructTK, Name),
- Dim = extract_dim(ArrayTK),
- emit(Fd, " ~s ~s;\n",
- [ic_cbe:mk_c_type(G, N, Type),mk_array_name(Name,Dim)]);
-emit_struct_member(Fd, _G, N, _X, Name, Union) when is_record(Union, union)->
- emit(Fd, " ~s ~s;\n",
- [ic_util:to_undersc([ic_forms:get_id2(Union) | N]),Name]);
-emit_struct_member(Fd, _G, _N, _X, Name, {string, _}) ->
- emit(Fd, " CORBA_char *~s;\n",
- [Name]);
-emit_struct_member(Fd, _G, N, _X, Name, {sequence, _Type, _Length}) ->
- %% Sequence used as struct
- emit(Fd, " ~s ~s;\n",
- [ic_util:to_undersc([Name | N]), Name]);
-emit_struct_member(Fd, G, N, X, Name, Type)
- when element(1, Type) == scoped_id ->
- CType = ic_cbe:mk_c_type(G, N, Type, evaluate_not),
- emit_struct_member(Fd, G, N, X, Name, CType);
-emit_struct_member(Fd, G, N, _X, Name, {enum, Type}) ->
- emit(Fd, " ~s ~s;\n",
- [ic_cbe:mk_c_type(G, N, Type),
- Name]);
-emit_struct_member(Fd, _G, _N, _X, Name, "ETERM*") ->
- emit(Fd, " ETERM* ~s;\n",
- [Name]);
-emit_struct_member(Fd, _G, _N, _X, Name, Type) when is_list(Type) ->
- emit(Fd, " ~s ~s;\n",
- [Type, Name]);
-emit_struct_member(Fd, G, N, _X, Name, Type) ->
- emit(Fd, " ~s ~s;\n",
- [ic_cbe:mk_c_type(G, N, Type),
- Name]).
-
-
-emit_typedef(G, N, X, erlang) ->
- case X of
- {typedef,_,[{array,_,_}],_} -> %% Array but not a typedef of
- %% an array definition
- case ic_options:get_opt(G, be) of
- noc ->
- mkFileArrObj(G,N,X,erlang);
- _ ->
- %% Search the table to see if the type is local or
- %% inherited.
- PTab = ic_genobj:pragmatab(G),
- Id = ic_forms:get_id2(X),
- case ets:match(PTab,{file_data_local,'_','_',
- typedef,N,Id,
- ic_util:to_undersc([Id | N]),
- '_','_'}) of
- [[]] ->
- %% Local, create erlang file for the array
- mkFileArrObj(G,N,X,erlang);
- _ ->
- %% Inherited, do nothing
- ok
- end
- end;
-
- {typedef,{sequence,_,_},_,{tk_sequence,_,_}} ->
- %% Sequence but not a typedef of
- %% a typedef of a sequence definition
- case ic_options:get_opt(G, be) of
- noc ->
- mkFileRecObj(G,N,X,erlang);
- _ ->
- %% Search the table to see if the type is local or
- %% inherited.
- PTab = ic_genobj:pragmatab(G),
- Id = ic_forms:get_id2(X),
- case ets:match(PTab,{file_data_local,'_','_',typedef,
- N,Id,
- ic_util:to_undersc([Id | N]),
- '_','_'}) of
- [[]] ->
- %% Local, create erlang file for the sequence
- mkFileRecObj(G,N,X,erlang);
- _ ->
- %% Inherited, do nothing
- ok
- end
- end;
- _ ->
- ok
- end;
-emit_typedef(G, N, X, c) ->
- B = ic_forms:get_body(X),
- if
- is_record(B, sequence) ->
- emit_sequence_head_def(G, N, X, B, c);
- true ->
- lists:foreach(fun(D) ->
- emit_typedef(G, N, D, B, c)
- end,
- ic_forms:get_idlist(X))
- end.
-
-emit_typedef(G, N, D, Type, c) when is_record(D, array) ->
- emit_array(G, N, D, Type);
-emit_typedef(G, N, D, Type, c) ->
- Name = ic_util:to_undersc([ic_forms:get_id2(D) | N]),
- CType = ic_cbe:mk_c_type(G, N, Type),
- TDType = mk_base_type(G, N, Type),
- ic_code:insert_typedef(G, Name, TDType),
- case ic_genobj:is_hrlfile_open(G) of
- true ->
- Fd = ic_genobj:hrlfiled(G),
- emit(Fd, "\n#ifndef __~s__\n",[ic_util:to_uppercase(Name)]),
- emit(Fd, "#define __~s__\n",[ic_util:to_uppercase(Name)]),
- ic_codegen:mcomment_light(Fd,
- [io_lib:format("Type definition ~s "
- "for type ~s",
- [Name, CType])],
- c),
- emit(Fd, "typedef ~s ~s;\n",
- [CType, Name]),
- emit(Fd, "\n#endif\n\n"),
- ic_codegen:nl(Fd);
- false ->
- ok
- end.
-
-
-mk_base_type(G, N, S) when element(1, S) == scoped_id ->
- {FullScopedName, _T, _TK, _} = ic_symtab:get_full_scoped_name(G, N, S),
- BT = ic_code:get_basetype(G, ic_util:to_undersc(FullScopedName)),
- case BT of
- "erlang_binary" ->
- "erlang_binary";
- "erlang_pid" ->
- "erlang_pid";
- "erlang_port" ->
- "erlang_port";
- "erlang_ref" ->
- "erlang_ref";
- "erlang_term" ->
- "ETERM*";
- Type ->
- Type
- end;
-mk_base_type(_G, _N, S) ->
- S.
-
-emit_array(G, N, D, Type) ->
- case ic_genobj:is_hrlfile_open(G) of
- true ->
- Fd = ic_genobj:hrlfiled(G),
- Name = ic_util:to_undersc([ic_forms:get_id2(D) | N]),
- {_, _, ArrayTK, _} =
- ic_symtab:get_full_scoped_name(G, N,
- ic_symtab:scoped_id_new(
- ic_forms:get_id(D))),
- Dim = extract_dim(ArrayTK),
- CType = ic_cbe:mk_c_type(G, N, Type),
- emit(Fd, "\n#ifndef __~s__\n",[ic_util:to_uppercase(Name)]),
- emit(Fd, "#define __~s__\n",[ic_util:to_uppercase(Name)]),
- ic_codegen:mcomment_light(Fd,
- [io_lib:format("Array definition ~s "
- "for type ~s",
- [Name, CType])],
- c),
- emit(Fd, "typedef ~s ~s~s;\n",
- [CType, Name, ic_cbe:mk_dim(Dim)]),
- emit(Fd, "typedef ~s ~s_slice~s;\n",
- [CType, Name, ic_cbe:mk_slice_dim(Dim)]),
- ic_codegen:nl(Fd),
- create_c_array_coding_file(G, N, {Name, Dim}, Type, typedef),
- emit(Fd, "\n#endif\n\n");
- false ->
- ok
- end.
-
-open_c_coding_file(G, Name) ->
- SName = string:concat(ic_util:mk_oe_name(G, "code_"), Name),
- FName =
- ic_file:join(ic_options:get_opt(G, stubdir),ic_file:add_dot_c(SName)),
- case file:open(FName, [write]) of
- {ok, Fd} ->
- {Fd, SName};
- Other ->
- exit(Other)
- end.
-
-
-
-create_c_array_coding_file(G, N, {Name, Dim}, Type, TypeDefFlag) ->
-
- {Fd , SName} = open_c_coding_file(G, Name),
- HFd = ic_genobj:hrlfiled(G), %% Write on stubfile header
- HrlFName = filename:basename(ic_genobj:include_file(G)),
- ic_codegen:emit_stub_head(G, Fd, SName, c),
- emit(Fd, "#include \"~s\"\n\n",[HrlFName]),
-
- %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %% Fd = ic_genobj:stubfiled(G), %% Write on stubfile
- %% HFd = ic_genobj:hrlfiled(G), %% Write on stubfile header
- %% HrlFName = filename:basename(ic_genobj:include_file(G)),
- %% emit(Fd, "#include \"~s\"\n\n",[HrlFName]),
- %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- put(op_variable_count, 0),
- put(tmp_declarations, []),
-
- emit(HFd, "int ~s~s(CORBA_Environment *oe_env, int*, int*);\n",
- [ic_util:mk_oe_name(G, "sizecalc_"), Name]),
-
- emit(Fd, "int ~s~s(CORBA_Environment *oe_env, int* oe_size_count_index, "
- "int* oe_size) {\n", [ic_util:mk_oe_name(G, "sizecalc_"), Name]),
-
- emit(Fd, " int oe_malloc_size = 0;\n",[]),
- emit(Fd, " int oe_error_code = 0;\n",[]),
- emit(Fd, " int oe_type = 0;\n",[]),
- emit(Fd, " int oe_array_size = 0;\n",[]),
-
- {ok, RamFd} = ram_file:open([], [binary, write]),
-
- emit_sizecount(array, G, N, nil, RamFd, {Name, Dim}, Type),
-
- ic_cbe:emit_tmp_variables(Fd),
- ic_codegen:nl(Fd),
- %% Move data from ram file to output file.
- {ok, Data} = ram_file:get_file(RamFd),
- emit(Fd, Data),
- ram_file:close(RamFd),
-
- emit(Fd, " return 0;\n\n",[]),
- emit(Fd, "}\n",[]),
-
- put(op_variable_count, 0),
- put(tmp_declarations, []),
-
- RefStr = get_refStr(Dim),
-
- case TypeDefFlag of
- typedef ->
- emit(HFd, "int ~s~s(CORBA_Environment *oe_env, ~s);\n",
- [ic_util:mk_oe_name(G, "encode_"), Name, Name]),
-
- emit(Fd, "int ~s~s(CORBA_Environment *oe_env, ~s oe_rec) {\n",
- [ic_util:mk_oe_name(G, "encode_"), Name, Name]);
- no_typedef ->
-
- emit(HFd, "int ~s~s(CORBA_Environment *oe_env, ~s oe_rec~s);\n",
- [ic_util:mk_oe_name(G, "encode_"),
- Name,
- ic_cbe:mk_c_type(G, N, Type),
- RefStr]),
-
- emit(Fd, "int ~s~s(CORBA_Environment *oe_env, ~s oe_rec~s) {\n",
- [ic_util:mk_oe_name(G, "encode_"),
- Name,
- ic_cbe:mk_c_type(G, N, Type),
- RefStr])
- end,
-
- emit(Fd, " int oe_error_code = 0;\n",[]),
-
- {ok, RamFd1} = ram_file:open([], [binary, write]),
-
- case TypeDefFlag of
- typedef ->
- emit_encode(array, G, N, nil, RamFd1, {Name, Dim}, Type);
- no_typedef ->
- emit_encode(array_no_typedef, G, N, nil, RamFd1, {Name, Dim}, Type)
- end,
-
- ic_cbe:emit_tmp_variables(Fd),
- ic_codegen:nl(Fd),
- %% Move data from ram file to output file.
- {ok, Data1} = ram_file:get_file(RamFd1),
- emit(Fd, Data1),
- ram_file:close(RamFd1),
-
- emit(Fd, " return 0;\n\n",[]),
- emit(Fd, "}\n",[]),
-
- put(op_variable_count, 0),
- put(tmp_declarations, []),
-
- case TypeDefFlag of
- typedef ->
- emit(HFd, "int ~s~s(CORBA_Environment *oe_env, char *, "
- "int*, ~s);\n",
- [ic_util:mk_oe_name(G, "decode_"), Name, Name]),
-
- emit(Fd, "int ~s~s(CORBA_Environment *oe_env, char *oe_first, "
- "int* oe_outindex, ~s oe_out) {\n",
- [ic_util:mk_oe_name(G, "decode_"), Name, Name]);
- no_typedef ->
- emit(HFd, "int ~s~s(CORBA_Environment *oe_env, char *, int*, "
- "~s oe_rec~s);\n",
- [ic_util:mk_oe_name(G, "decode_"),
- Name,
- ic_cbe:mk_c_type(G, N, Type),
- RefStr]),
-
- emit(Fd, "int ~s~s(CORBA_Environment *oe_env, char *oe_first, "
- "int* oe_outindex, ~s oe_out~s) {\n",
- [ic_util:mk_oe_name(G, "decode_"),
- Name,
- ic_cbe:mk_c_type(G, N, Type),
- RefStr])
- end,
-
- emit(Fd, " int oe_error_code = 0;\n",[]),
- emit(Fd, " int oe_array_size = 0;\n",[]),
-
- {ok, RamFd2} = ram_file:open([], [binary, write]),
-
- case TypeDefFlag of
- typedef ->
- emit_decode(array, G, N, nil, RamFd2, {Name, Dim}, Type);
- no_typedef ->
- emit_decode(array_no_typedef, G, N, nil, RamFd2, {Name, Dim}, Type)
- end,
-
-
- ic_cbe:emit_tmp_variables(Fd),
- ic_codegen:nl(Fd),
- %% Move data from ram file to output file.
- {ok, Data2} = ram_file:get_file(RamFd2),
- emit(Fd, Data2),
- ram_file:close(RamFd2),
-
- emit(Fd, " *oe_outindex = ~s;\n\n",[align("*oe_outindex")]),
-
- emit(Fd, " return 0;\n\n",[]),
- emit(Fd, "}\n",[]),
- file:close(Fd).
-
-
-get_refStr([]) ->
- "";
-get_refStr([X|Xs]) ->
- "[" ++ X ++ "]" ++ get_refStr(Xs).
-
-
-emit_sequence_head_def(G, N, X, T, c) ->
- %% T is the sequence
- case ic_genobj:is_hrlfile_open(G) of
- true ->
- Fd = ic_genobj:hrlfiled(G),
- SeqName = ic_util:to_undersc([ic_forms:get_id2(X) | N]),
- emit(Fd, "\n#ifndef __~s__\n",[ic_util:to_uppercase(SeqName)]),
- emit(Fd, "#define __~s__\n",[ic_util:to_uppercase(SeqName)]),
- ic_codegen:mcomment_light(Fd,
- [io_lib:format("Struct definition: ~s",
- [SeqName])],
- c),
- emit(Fd, "typedef struct {\n"),
- emit(Fd, " CORBA_unsigned_long _maximum;\n"),
- emit(Fd, " CORBA_unsigned_long _length;\n"),
- emit_seq_buffer(Fd, G, N, T#sequence.type),
- emit(Fd, "} ~s;\n\n", [SeqName]),
- create_c_struct_coding_file(G, N, X, T, SeqName,
- T#sequence.type, sequence_head),
- emit(Fd, "\n#endif\n\n");
-
- false ->
- ok
- end.
-
-emit_seq_buffer(Fd, G, N, Type) ->
- emit(Fd, " ~s* _buffer;\n",
- [ic_cbe:mk_c_type(G, N, Type)]).
-
-%%------------------------------------------------------------
-%%
-%% Emit decode bodies for functions in C for array, sequences and
-%% structs.
-%%
-%%------------------------------------------------------------
-emit_decode(array, G, N, _T, Fd, {_Name, Dim}, Type) ->
- emit(Fd, " if((char*) oe_out == oe_first)\n",[]),
- AlignName =
- lists:concat(["*oe_outindex + ", dim_multiplication(Dim),
- " * sizeof(", ic_cbe:mk_c_type(G, N, Type),")"]),
- emit(Fd, " *oe_outindex = ~s;\n\n",[align(AlignName)]),
- array_decode_dimension_loop(G, N, Fd, Dim, "", Type, array);
-emit_decode(array_no_typedef, G, N, _T, Fd, {_Name, Dim}, Type) ->
- emit(Fd, " if((char*) oe_out == oe_first)\n",[]),
- AlignName =
- lists:concat(["*oe_outindex + ", dim_multiplication(Dim),
- " * sizeof(", ic_cbe:mk_c_type(G, N, Type),")"]),
- emit(Fd, " *oe_outindex = ~s;\n\n",[align(AlignName)]),
- array_decode_dimension_loop(G, N, Fd, Dim, "", Type, array_no_typedef);
-emit_decode(sequence_head, G, N, T, Fd, SeqName, ElType) ->
- ic_cbe:store_tmp_decl(" int oe_seq_len = 0;\n", []),
- ic_cbe:store_tmp_decl(" int oe_seq_count = 0;\n", []),
- ic_cbe:store_tmp_decl(" int oe_seq_dummy = 0;\n", []),
-
- TmpBuf =
- case ictype:isBasicTypeOrEterm(G, N, ElType) of
- true ->
- Tmp = "oe_seq_tmpbuf",
- ic_cbe:store_tmp_decl(" char* ~s = 0;\n", [Tmp]),
- Tmp;
- false ->
- "NOT USED"
- end,
-
- MaxSize = get_seq_max(T),
- emit(Fd, " if((char*) oe_out == oe_first)\n",[]),
- emit(Fd, " *oe_outindex = ~s;\n\n",
- [align(["*oe_outindex + sizeof(", SeqName, ")"])]),
-
- Ctype = ic_cbe:mk_c_type(G, N, ElType),
- emit(Fd, " if ((oe_error_code = ei_decode_list_header(oe_env->_inbuf, "
- "&oe_env->_iin, &oe_seq_len)) < 0) {\n"),
- case ictype:isBasicTypeOrEterm(G, N, ElType) of
- true ->
- emit(Fd, " int oe_type = 0;\n"),
- emit(Fd, " (int) ei_get_type(oe_env->_inbuf, &oe_env->_iin, "
- "&oe_type, &oe_seq_len);\n\n"),
-
- if
- MaxSize == infinity ->
- ok;
- true ->
- emit(Fd, " if (oe_seq_len > ~w) {\n", [MaxSize]),
- emit(Fd, " CORBA_exc_set(oe_env, "
- "CORBA_SYSTEM_EXCEPTION, DATA_CONVERSION, "
- "\"Length of sequence `~s' out of bound\");\n"
- " return -1;\n }\n", [SeqName])
- end,
- emit(Fd, " oe_out->_maximum = oe_seq_len;\n"),
- emit(Fd, " oe_out->_length = oe_seq_len;\n"),
- emit(Fd, " oe_out->_buffer = (void *) (oe_first + "
- "*oe_outindex);\n"),
- emit(Fd, " *oe_outindex = ~s;\n",
- [align(["*oe_outindex + (sizeof(", Ctype, ") * "
- "oe_out->_length)"])]),
- emit(Fd,
- " if ((~s = malloc(oe_seq_len + 1)) == NULL) {\n"
- " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, "
- "NO_MEMORY, \"Cannot malloc\");\n"
- " return -1;\n"
- " }\n", [TmpBuf]),
- emit(Fd, " if ((oe_error_code = ei_decode_string("
- "oe_env->_inbuf, &oe_env->_iin, ~s)) < 0) {\n", [TmpBuf]),
- emit(Fd, " CORBA_free(~s);\n\n", [TmpBuf]),
- emit_c_dec_rpt(Fd, " ", "string1", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " for (oe_seq_count = 0; "
- "oe_seq_count < oe_out->_length; oe_seq_count++)\n"),
- case ictype:isBasicType(G, N, ElType) of
- true ->
- emit(Fd, " oe_out->_buffer[oe_seq_count] = (unsigned char) "
- "~s[oe_seq_count];\n\n", [TmpBuf]);
- false -> %% Term
- emit(Fd, " oe_out->_buffer[oe_seq_count] = "
- "erl_mk_int(~s[oe_seq_count]);\n\n",[TmpBuf]) % XXXX What?
- end,
- emit(Fd, " CORBA_free(~s);\n\n", [TmpBuf]);
- false ->
- emit(Fd, " return oe_error_code;\n")
- end,
-
- emit(Fd, " } else {\n"),
-
- if
- MaxSize == infinity ->
- ok;
- true ->
- emit(Fd, " if (oe_seq_len > ~w) {\n", [MaxSize]),
- emit(Fd, " CORBA_exc_set(oe_env, "
- "CORBA_SYSTEM_EXCEPTION, DATA_CONVERSION, "
- "\"Length of sequence `~s' out of bound\");\n"
- " return -1;\n }\n", [SeqName])
- end,
-
- emit(Fd, " oe_out->_maximum = oe_seq_len;\n"),
- emit(Fd, " oe_out->_length = oe_seq_len;\n"),
- emit(Fd, " oe_out->_buffer = (void *) (oe_first + *oe_outindex);\n"),
- emit(Fd, " *oe_outindex = ~s;\n\n",
- [align(["*oe_outindex + (sizeof(", Ctype, ") * oe_out->_length)"])]),
-
- if
- Ctype == "CORBA_char *" ->
- emit(Fd, " for (oe_seq_count = 0; "
- "oe_seq_count < oe_out->_length; oe_seq_count++) {\n"),
- emit(Fd, " oe_out->_buffer[oe_seq_count] = "
- "(void*) (oe_first + *oe_outindex);\n\n"),
- ic_cbe:emit_decoding_stmt(G, N, Fd, ElType,
- "oe_out->_buffer[oe_seq_count]",
- "",
- "oe_env->_inbuf", 0, "", caller_dyn),
- emit(Fd, " *oe_outindex = ~s;",
- [align(["*oe_outindex + strlen(oe_out->_buffer["
- "oe_seq_count]) + 1"])]);
- true ->
- emit(Fd, " for (oe_seq_count = 0; "
- "oe_seq_count < oe_out->_length; oe_seq_count++) {\n"),
- case ictype:isArray(G, N, ElType) of
- %% XXX Silly. There is no real difference between the
- %% C statements produced by the following calls.
- true ->
- ic_cbe:emit_decoding_stmt(G, N, Fd, ElType,
- "oe_out->_buffer[oe_seq_count]",
- "",
- "oe_env->_inbuf",
- 0, "oe_outindex", generator);
- false ->
- ic_cbe:emit_decoding_stmt(G, N, Fd, ElType,
- "oe_out->_buffer + oe_seq_count",
- "",
- "oe_env->_inbuf",
- 0, "oe_outindex", generator)
- end
- end,
- emit(Fd, " }\n"),
- emit(Fd, " if (oe_out->_length != 0) {\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_list_header("
- "oe_env->_inbuf, &oe_env->_iin, &oe_seq_dummy)) < 0) {\n"),
- emit_c_dec_rpt(Fd, " ", "ei_decode_list_header", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " } else\n"),
- emit(Fd, " oe_out->_buffer = NULL;\n"),
- emit(Fd, " }\n");
-
-emit_decode(struct, G, N, _T, Fd, StructName, ElTypes) ->
- Length = length(ElTypes) + 1,
- Tname = ic_cbe:mk_variable_name(op_variable_count),
- Tname1 = ic_cbe:mk_variable_name(op_variable_count),
-
- ic_cbe:store_tmp_decl(" int ~s = 0;\n",[Tname]),
- ic_cbe:store_tmp_decl(" char ~s[256];\n\n",[Tname1]),
-
- emit(Fd, " if((char*) oe_out == oe_first)\n",[]),
- AlignName = lists:concat(["*oe_outindex + sizeof(",StructName,")"]),
- emit(Fd, " *oe_outindex = ~s;\n\n", [align(AlignName)]),
-
- emit(Fd, " if ((oe_error_code = ei_decode_tuple_header(oe_env->_inbuf, "
- "&oe_env->_iin, &~s)) < 0) {\n", [Tname]),
- emit_c_dec_rpt(Fd, " ", "ei_decode_tuple_header", []),
- emit(Fd, " return oe_error_code;\n }\n"),
-
- emit(Fd, " if (~s != ~p) {\n",[Tname, Length]),
- emit_c_dec_rpt(Fd, " ", "tuple header size != ~p", [Length]),
- emit(Fd, " return -1;\n }\n"),
-
- emit(Fd, " if ((oe_error_code = ei_decode_atom(oe_env->_inbuf, "
- "&oe_env->_iin, ~s)) < 0) {\n", [Tname1]),
- emit_c_dec_rpt(Fd, " ", "ei_decode_atom", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " if (strcmp(~s, ~p) != 0)\n",[Tname1, StructName]),
- emit(Fd, " return -1;\n\n"),
- lists:foreach(
- fun({ET, EN}) ->
- case ic_cbe:is_variable_size(G, N, ET) of
- true ->
- case ET of
-
- {struct, _, _, _} ->
- %% Sequence member = a struct
- ic_cbe:emit_decoding_stmt(G, N, Fd,
- StructName ++ "_" ++
- ic_forms:get_id2(ET),
- "&oe_out->" ++ EN,
- "", "oe_env->_inbuf",
- 0,
- "oe_outindex",
- generator);
-
- {sequence, _, _} ->
- %% Sequence member = a struct XXX ??
- ic_cbe:emit_decoding_stmt(G, N, Fd,
- StructName ++ "_" ++
- EN,
- "&oe_out->" ++ EN,
- "",
- "oe_env->_inbuf",
- 0,
- "oe_outindex",
- generator);
- {_,{array, _, _}} ->
- emit(Fd, " oe_out->~s = (void *) "
- "(oe_first+*oe_outindex);\n\n",[EN]),
- ic_cbe:emit_decoding_stmt(G, N, Fd,
- StructName ++ "_" ++
- EN, "oe_out->" ++ EN ,
- "",
- "oe_env->_inbuf",
- 0,
- "oe_outindex",
- generator);
-
- {union, _, _, _, _} ->
- %% Sequence member = a union
- ic_cbe:emit_decoding_stmt(G, N, Fd,
- StructName ++ "_" ++
- ic_forms:get_id2(ET),
- "&oe_out->" ++ EN,
- "",
- "oe_env->_inbuf",
- 0,
- "oe_outindex",
- generator);
-
- {string,_} ->
- ic_cbe:emit_decoding_stmt(G, N, Fd,
- ET,
- "oe_out->" ++ EN ,
- "",
- "oe_env->_inbuf",
- 0,
- "oe_outindex",
- generator_malloc);
-
- {scoped_id,_,_,_} ->
- case ictype:member2type(G,StructName,EN) of
- array ->
- ic_cbe:emit_decoding_stmt(G, N, Fd,
- ET,
- "oe_out->" ++
- EN,
- "",
- "oe_env->"
- "_inbuf",
- 0,
- "oe_outindex",
- generator);
- struct ->
- ic_cbe:emit_decoding_stmt(G, N, Fd,
- ET,
- "&oe_out->" ++
- EN ,
- "",
- "oe_env->"
- "_inbuf",
- 0,
- "oe_outindex",
- generator);
- sequence ->
- ic_cbe:emit_decoding_stmt(G, N, Fd,
- ET,
- "&oe_out->" ++
- EN,
- "",
- "oe_env->"
- "_inbuf",
- 0,
- "oe_outindex",
- generator);
- union ->
- ic_cbe:emit_decoding_stmt(G, N, Fd,
- ET,
- "&oe_out->" ++
- EN,
- "",
- "oe_env->"
- "_inbuf",
- 0,
- "oe_outindex",
- generator);
- _ ->
- ic_cbe:emit_decoding_stmt(G, N, Fd,
- ET,
- "oe_out->" ++
- EN,
- "",
- "oe_env->"
- "_inbuf",
- 0,
- "oe_outindex",
- generator)
- end;
-
- _ ->
- emit(Fd, " oe_out->~s = (void *) "
- "(oe_first+*oe_outindex);\n\n",[EN]),
- ic_cbe:emit_decoding_stmt(G, N, Fd,
- ET,
- "oe_out->" ++ EN ,
- "",
- "oe_env->_inbuf",
- 0, "oe_outindex",
- generator)
- end;
- false ->
- case ET of
-
- {struct, _, _, _} ->
- %% A struct member
- ic_cbe:emit_decoding_stmt(G, N, Fd,
- StructName ++ "_" ++
- ic_forms:get_id2(ET),
- "&oe_out->" ++ EN ,
- "",
- "oe_env->_inbuf",
- 0,
- "oe_outindex",
- generator);
-
- {_,{array, _, _}} ->
- ic_cbe:emit_decoding_stmt(G, N, Fd,
- StructName ++ "_" ++
- EN,
- "oe_out->" ++ EN ,
- "",
- "oe_env->_inbuf",
- 0,
- "oe_outindex",
- generator);
-
- {union, _, _, _, _} ->
- %% Sequence member = a union
- ic_cbe:emit_decoding_stmt(G, N, Fd,
- StructName ++ "_" ++
- ic_forms:get_id2(ET),
- "&oe_out->" ++ EN ,
- "",
- "oe_env->_inbuf",
- 0,
- "oe_outindex",
- generator);
-
- {_,_} ->
- ic_cbe:emit_decoding_stmt(G, N, Fd,
- ET,
- "&oe_out->" ++ EN ,
- "",
- "oe_env->_inbuf",
- 0,
- "oe_outindex",
- generator);
- {scoped_id,_,_,_} ->
- case ic_symtab:get_full_scoped_name(G, N, ET) of
- {_FullScopedName, _, {tk_array,_,_}, _} ->
- ic_cbe:emit_decoding_stmt(G, N, Fd,
- ET,
- "oe_out->" ++
- EN,
- "",
- "oe_env->"
- "_inbuf",
- 0,
- "oe_outindex",
- generator);
- {_FullScopedName, _, {tk_string,_}, _} ->
- ic_cbe:emit_decoding_stmt(G, N, Fd,
- ET,
- "oe_out->" ++
- EN,
- "",
- "oe_env->"
- "_inbuf",
- 0,
- "oe_outindex",
- generator);
- {_FullScopedName, _, {tk_struct,_,_,_}, _} ->
- ic_cbe:emit_decoding_stmt(G, N, Fd,
- ET,
- "&oe_out->" ++
- EN,
- "",
- "oe_env->"
- "_inbuf",
- 0,
- "oe_outindex",
- generator);
-
- {_FullScopedName, _,
- {tk_union,_,_,_,_,_}, _} ->
- ic_cbe:emit_decoding_stmt(G, N, Fd,
- ET,
- "&oe_out->" ++
- EN,
- "",
- "oe_env->"
- "_inbuf",
- 0,
- "oe_outindex",
- generator);
-
- _ ->
- ic_cbe:emit_decoding_stmt(G, N, Fd,
- ET,
- "&oe_out->" ++
- EN,
- "",
- "oe_env->"
- "_inbuf",
- 0,
- "oe_outindex",
- generator)
- end
- end
- end
- end,
- ElTypes).
-
-
-ref_array_static_dec(array, true) ->
- %% Typedef, Static, Basic Type
- "&(oe_out)";
-ref_array_static_dec(array, false) ->
- %% Typedef, Static, Constr Type
- "&(oe_out)";
-ref_array_static_dec(array_no_typedef, true) ->
- %% No Typedef, Static, Basic Type
- "&oe_out";
-ref_array_static_dec(array_no_typedef, false) ->
- %% No Typedef, Static, Constr Type
- "&oe_out".
-
-
-ref_array_dynamic_dec(G, N, T, array) ->
- case ictype:isString(G, N, T) of
- true -> % Typedef, Dynamic, String
- "oe_out";
- false -> % Typedef, Dynamic, No String
- "&(oe_out)"
- end;
-ref_array_dynamic_dec(G, N, T, array_no_typedef) ->
- case ictype:isString(G, N, T) of
- true -> % No Typedef, Dynamic, String
- "oe_out";
- false -> % No Typedef, Dynamic, No String
- "&oe_out"
- end.
-
-
-
-array_decode_dimension_loop(G, N, Fd, [Dim], Dimstr, Type, TDFlag) ->
- Tname = ic_cbe:mk_variable_name(op_variable_count),
- ic_cbe:store_tmp_decl(" int ~s = 0;\n",[Tname]),
-
- emit(Fd, " if ((oe_error_code = ei_decode_tuple_header(oe_env->_inbuf, "
- "&oe_env->_iin, &oe_array_size)) < 0) {\n",
- []),
- emit_c_dec_rpt(Fd, " ", "ei_decode_tuple_header", []),
- emit(Fd, " return oe_error_code;\n }\n"),
-
- %% This is disabled due to a bug in erl_interface :
- %% tuples inside tuples hae no correct data about the size
- %% of the tuple........( allways = 0 )
- %%emit(Fd, " if (oe_array_size != ~s)\n",[Dim]),
- %%emit(Fd, " return -1;\n\n"),
-
- emit(Fd, " for (~s = 0; ~s < ~s; ~s++) {\n",
- [Tname, Tname, Dim, Tname]),
-
-
- ArrAccess =
- case ic_cbe:is_variable_size(G, N, Type) of
- true ->
- ref_array_dynamic_dec(G, N, Type, TDFlag) ++
- Dimstr ++ "[" ++ Tname ++ "]";
- false ->
- ref_array_static_dec(TDFlag, ictype:isBasicType(G,N,Type)) ++
- Dimstr ++ "[" ++ Tname ++ "]"
- end,
-
- ic_cbe:emit_decoding_stmt(G, N, Fd, Type,
- ArrAccess,
- "", "oe_env->_inbuf", 0,
- "oe_outindex", generator),
-
- %% emit(Fd, "\n *oe_outindex +=
- %% sizeof(~s);\n",[ic_cbe:mk_c_type(G, N, Type)]),
- emit(Fd, " }\n");
-array_decode_dimension_loop(G, N, Fd, [Dim | Ds], _Dimstr, Type, TDFlag) ->
- Tname = ic_cbe:mk_variable_name(op_variable_count),
- ic_cbe:store_tmp_decl(" int ~s = 0;\n",[Tname]),
-
- emit(Fd, " if ((oe_error_code = ei_decode_tuple_header(oe_env->_inbuf, "
- "&oe_env->_iin, &oe_array_size)) < 0) {\n",
- []),
- emit_c_dec_rpt(Fd, " ", "ei_decode_tuple_header", []),
- emit(Fd, " return oe_error_code;\n }\n"),
-
- %% This is disabled due to a bug in erl_interface :
- %% tuples inside tuples hae no correct data about the size
- %% of the tuple........( allways = 0 )
- %%emit(Fd, " if (oe_array_size != ~s)\n",[Dim]),
- %%emit(Fd, " return -1;\n\n"),
-
- emit(Fd, " for (~s = 0; ~s < ~s; ~s++) {\n",
- [Tname, Tname, Dim, Tname]),
- array_decode_dimension_loop(G, N, Fd, Ds, "[" ++ Tname ++ "]" , Type,
- TDFlag),
-
- emit(Fd, " }\n").
-
-dim_multiplication([D]) ->
- D;
-dim_multiplication([D |Ds]) ->
- D ++ "*" ++ dim_multiplication(Ds).
-
-emit_encode(array, G, N, _T, Fd, {_Name, Dim}, Type) ->
- array_encode_dimension_loop(G, N, Fd, Dim, {"",""}, Type, array);
-emit_encode(array_no_typedef, G, N, _T, Fd, {_Name, Dim}, Type) ->
- array_encode_dimension_loop(G, N, Fd, Dim, {"",""}, Type,
- array_no_typedef);
-emit_encode(sequence_head, G, N, T, Fd, SeqName, ElType) ->
- Tname = ic_cbe:mk_variable_name(op_variable_count),
- ic_cbe:store_tmp_decl(" int ~s = 0;\n\n",[Tname]),
-
- MaxSize = get_seq_max(T),
- if
- MaxSize == infinity ->
- ok;
- true ->
- emit(Fd, " if (oe_rec->_length > ~w) {\n", [MaxSize]),
- emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, "
- "DATA_CONVERSION, \"Length of sequence `~s' "
- "out of bound\");\n"
- " return -1;\n }\n", [SeqName])
- end,
-
- emit(Fd, " if (oe_rec->_length != 0) {\n"),
-
- emit(Fd, " if ((oe_error_code = oe_ei_encode_list_header(oe_env, "
- "oe_rec->_length)) < 0) {\n",
- []),
- emit_c_enc_rpt(Fd, " ", "oi_ei_encode_list_header", []),
- emit(Fd, " return oe_error_code;\n }\n"),
-
- emit(Fd, " for (~s = 0; ~s < oe_rec->_length; ~s++) {\n",
- [Tname, Tname, Tname]),
- case ElType of
- {_,_} -> %% ElType = elementary type or pointer type
- ic_cbe:emit_encoding_stmt(G, N, Fd, ElType, "oe_rec->_buffer[" ++
- Tname ++ "]", "oe_env->_outbuf");
-
- {scoped_id,local,_,["term","erlang"]} ->
- ic_cbe:emit_encoding_stmt(G, N, Fd, ElType, "oe_rec->_buffer[" ++
- Tname ++ "]", "oe_env->_outbuf");
-
- {scoped_id,_,_,_} ->
- case ic_symtab:get_full_scoped_name(G, N, ElType) of
- {_, typedef, TDef, _} ->
- case TDef of
- {tk_struct,_,_,_} ->
- ic_cbe:emit_encoding_stmt(G, N, Fd, ElType,
- "&oe_rec->_buffer[" ++
- Tname ++ "]",
- "oe_env->_outbuf");
- {tk_sequence,_,_} ->
- ic_cbe:emit_encoding_stmt(G, N, Fd, ElType,
- "&oe_rec->_buffer[" ++
- Tname ++ "]",
- "oe_env->_outbuf");
- {tk_union,_,_,_,_,_} ->
- ic_cbe:emit_encoding_stmt(G, N, Fd, ElType,
- "&oe_rec->_buffer[" ++
- Tname ++ "]",
- "oe_env->_outbuf");
- _ ->
- ic_cbe:emit_encoding_stmt(G, N, Fd, ElType,
- "oe_rec->_buffer[" ++
- Tname ++ "]",
- "oe_env->_outbuf")
- end;
- {_,enum,_,_} ->
- ic_cbe:emit_encoding_stmt(G, N, Fd, ElType,
- "oe_rec->_buffer[" ++
- Tname ++ "]",
- "oe_env->_outbuf");
- _ ->
- ic_cbe:emit_encoding_stmt(G, N, Fd, ElType,
- "&oe_rec->_buffer[" ++
- Tname ++ "]",
- "oe_env->_outbuf")
- end;
-
- _ -> %% ElType = structure
- ic_cbe:emit_encoding_stmt(G, N, Fd, ElType,
- "&oe_rec->_buffer[" ++ Tname ++ "]",
- "oe_env->_outbuf")
- end,
- emit(Fd, " }\n"),
- emit(Fd, " }\n"),
- emit(Fd, " if ((oe_error_code = oe_ei_encode_empty_list(oe_env)) < 0) {\n"),
- emit_c_enc_rpt(Fd, " ", "oe_ei_encode_empty_list", []),
- emit(Fd, " return oe_error_code;\n }\n");
-emit_encode(struct, G, N, _T, Fd, StructName, ElTypes) ->
- Length = length(ElTypes) + 1,
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_tuple_header(oe_env, ~p)) < 0) {\n", [Length]),
- emit_c_enc_rpt(Fd, " ", "oe_ei_encode_tuple_header", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_atom(oe_env, ~p)) < 0) {\n", [StructName]),
- emit_c_enc_rpt(Fd, " ", "oe_ei_encode_atom", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- lists:foreach(
- fun({ET, EN}) ->
- case ET of
- {sequence, _, _} ->
- %% Sequence = struct
- ic_cbe:emit_encoding_stmt(G, N, Fd,
- StructName ++ "_" ++ EN,
- "&oe_rec->" ++ EN,
- "oe_env->_outbuf");
- {_,{array, _, _Dims}} ->
- ic_cbe:emit_encoding_stmt(G, N, Fd,
- StructName ++ "_" ++ EN,
- "oe_rec->" ++ EN,
- "oe_env->_outbuf");
-
- {union,_,_,_,_} ->
- ic_cbe:emit_encoding_stmt(G, N, Fd,
- StructName ++ "_" ++
- ic_forms:get_id2(ET),
- "&oe_rec->" ++ EN,
- "oe_env->_outbuf");
-
- {struct,_,_,_} ->
- ic_cbe:emit_encoding_stmt(G, N, Fd,
- StructName ++ "_" ++
- ic_forms:get_id2(ET),
- "&oe_rec->" ++ EN,
- "oe_env->_outbuf");
-
- {scoped_id,_,_,_} ->
- case ictype:member2type(G,StructName,EN) of
- struct ->
- ic_cbe:emit_encoding_stmt(G, N, Fd,
- ET,
- "&oe_rec->" ++ EN,
- "oe_env->_outbuf");
- sequence ->
- ic_cbe:emit_encoding_stmt(G, N, Fd,
- ET,
- "&oe_rec->" ++ EN,
- "oe_env->_outbuf");
- union ->
- ic_cbe:emit_encoding_stmt(G, N, Fd,
- ET,
- "&oe_rec->" ++ EN,
- "oe_env->_outbuf");
- array ->
- ic_cbe:emit_encoding_stmt(G, N, Fd,
- ET,
- "oe_rec->" ++ EN,
- "oe_env->_outbuf");
- _ ->
- ic_cbe:emit_encoding_stmt(G, N, Fd,
- ET,
- "oe_rec->" ++ EN,
- "oe_env->_outbuf")
- end;
- _ ->
- ic_cbe:emit_encoding_stmt(G, N, Fd,
- ET,
- "oe_rec->" ++ EN,
- "oe_env->_outbuf")
- end
- end,
- ElTypes).
-
-ref_array_static_enc(array, true) ->
- %% Typedef, Static, Basic Type
- "oe_rec";
-ref_array_static_enc(array, false) ->
- %% Typedef, Static, Constr Type
- "&(oe_rec)";
-ref_array_static_enc(array_no_typedef, true) ->
- %% No Typedef, Static, Basic Type
- "oe_rec";
-ref_array_static_enc(array_no_typedef, false) ->
- %% No Typedef, Static, Constr Type
- "&oe_rec".
-
-
-ref_array_dynamic_enc(G, N, T, array) ->
- case ictype:isString(G, N, T) of
- true -> % Typedef, Dynamic, String
- "oe_rec";
- false -> % Typedef, Dynamic, No String
- "&(oe_rec)"
- end;
-ref_array_dynamic_enc(G, N, T, array_no_typedef) ->
- case ictype:isString(G, N, T) of
- true -> % No Typedef, Dynamic, String
- "oe_rec";
- false -> % No Typedef, Dynamic, No String
- "&oe_rec"
- end.
-
-
-
-array_encode_dimension_loop(G, N, Fd, [Dim], {Str1,_Str2}, Type, TDFlag) ->
- Tname = ic_cbe:mk_variable_name(op_variable_count),
- ic_cbe:store_tmp_decl(" int ~s = 0;\n",[Tname]),
-
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_tuple_header(oe_env, ~s)) < 0) {\n", [Dim]),
- emit_c_enc_rpt(Fd, " ", "oe_ei_encode_tuple_header", []),
- emit(Fd, " return oe_error_code;\n }\n"),
-
- emit(Fd, " for (~s = 0; ~s < ~s; ~s++) {\n",
- [Tname, Tname, Dim, Tname]),
-
- ArrAccess =
- case ic_cbe:is_variable_size(G, N, Type) of
- true ->
- ref_array_dynamic_enc(G, N, Type, TDFlag) ++
- Str1 ++ "[" ++ Tname ++ "]";
- false ->
- ref_array_static_enc(TDFlag, ictype:isBasicType(G,N,Type)) ++
- Str1 ++ "[" ++ Tname ++ "]"
- end,
-
- ic_cbe:emit_encoding_stmt(G, N, Fd, Type, ArrAccess, "oe_env->_outbuf"),
- emit(Fd, " }\n");
-array_encode_dimension_loop(G, N, Fd, [Dim | Ds],{Str1,Str2}, Type, TDFlag) ->
- Tname = ic_cbe:mk_variable_name(op_variable_count),
- ic_cbe:store_tmp_decl(" int ~s = 0;\n",[Tname]),
-
- emit(Fd, " if ((oe_error_code = "
- "oe_ei_encode_tuple_header(oe_env, ~s)) < 0) {\n", [Dim]),
- emit_c_enc_rpt(Fd, " ", "oe_ei_encode_tuple_header", []),
- emit(Fd, " return oe_error_code;\n }\n"),
-
- emit(Fd, " for (~s = 0; ~s < ~s; ~s++) {\n",
- [Tname, Tname, Dim, Tname]),
- array_encode_dimension_loop(G, N, Fd, Ds,
- {Str1 ++ "[" ++ Tname ++ "]", Str2},
- Type, TDFlag),
- emit(Fd, " }\n").
-
-
-emit_sizecount(array, G, N, _T, Fd, {_Name, Dim}, Type) ->
- emit(Fd, " if(*oe_size == 0)\n",[]),
- AlignName = lists:concat(["*oe_size + ", dim_multiplication(Dim),
- " * sizeof(", ic_cbe:mk_c_type(G, N, Type),")"]),
- emit(Fd, " *oe_size = ~s;\n\n",[align(AlignName)]),
- array_size_dimension_loop(G, N, Fd, Dim, Type),
- emit(Fd, " *oe_size = ~s;\n\n",
- [align("*oe_size + oe_malloc_size")]),
- ic_codegen:nl(Fd);
-
-emit_sizecount(sequence_head, G, N, T, Fd, SeqName, ElType) ->
- ic_cbe:store_tmp_decl(" int oe_seq_len = 0;\n", []),
- ic_cbe:store_tmp_decl(" int oe_seq_count = 0;\n", []),
-
- emit(Fd, " if(*oe_size == 0)\n",[]),
- emit(Fd, " *oe_size = ~s;\n\n",
- [align(["*oe_size + sizeof(", SeqName, ")"])]),
-
- MaxSize = get_seq_max(T),
-
- emit(Fd, " if ((oe_error_code = ei_get_type(oe_env->_inbuf, "
- "oe_size_count_index, &oe_type, &oe_seq_len)) < 0) {\n"),
- emit_c_dec_rpt(Fd, " ", "ei_get_type", []),
- emit(Fd, " return oe_error_code;\n }\n"),
-
- if
- MaxSize == infinity ->
- ok;
- true ->
- emit(Fd, " if (oe_seq_len > ~w) {\n", [MaxSize]),
- emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, "
- "DATA_CONVERSION, \"Length of sequence `~s' "
- "out of bound\");\n"
- " return -1;\n }\n", [SeqName])
- end,
-
- CType = ic_cbe:mk_c_type(G, N, ElType),
-
- emit(Fd, " if ((oe_error_code = ei_decode_list_header(oe_env->_inbuf, "
- "oe_size_count_index, NULL)) < 0) {\n"),
-
- case ictype:isBasicTypeOrEterm(G, N, ElType) of
- true ->
- emit(Fd, " if ((oe_error_code = ei_decode_string(oe_env->"
- "_inbuf, oe_size_count_index, NULL)) < 0) {\n"),
- emit_c_dec_rpt(Fd, " ", "ei_decode_string", []),
- emit(Fd, " return oe_error_code;\n }\n"),
-
- emit(Fd, " oe_malloc_size = ~s;\n\n",
- [align(["sizeof(", CType, ") * oe_seq_len"])]);
- false ->
- emit_c_dec_rpt(Fd, " ", "non mea culpa", []),
- emit(Fd, " return oe_error_code;\n\n")
- end,
-
- emit(Fd, " } else {\n"),
-
- emit(Fd, " oe_malloc_size = ~s;\n\n",
- [align(["sizeof(", CType, ") * oe_seq_len"])]),
-
- emit(Fd, " for (oe_seq_count = 0; oe_seq_count < oe_seq_len; "
- "oe_seq_count++) {\n"),
- ic_cbe:emit_malloc_size_stmt(G, N, Fd, ElType,
- "oe_env->_inbuf", 0, generator),
- emit(Fd, " }\n"),
-
- emit(Fd, " if (oe_seq_len != 0) \n"),
- emit(Fd, " if ((oe_error_code = ei_decode_list_header(oe_env->_inbuf,"
- "oe_size_count_index, NULL)) < 0) {\n"),
- emit_c_dec_rpt(Fd, " ", "ei_decode_list_header", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " }\n"),
- emit(Fd, " *oe_size = ~s;\n\n", [align("*oe_size + oe_malloc_size")]);
-
-emit_sizecount(struct, G, N, _T, Fd, StructName, ElTypes) ->
- Length = length(ElTypes) + 1,
- Tname = ic_cbe:mk_variable_name(op_variable_count),
- ic_cbe:store_tmp_decl(" int ~s = 0;\n\n",[Tname]),
-
- emit(Fd, " if(*oe_size == 0)\n",[]),
- AlignName = lists:concat(["*oe_size + sizeof(",StructName,")"]),
- emit(Fd, " *oe_size = ~s;\n\n", [align(AlignName)]),
- ic_codegen:nl(Fd),
-
- emit(Fd, " if ((oe_error_code = "
- "ei_get_type(oe_env->_inbuf, oe_size_count_index, &oe_type, "
- "&~s)) < 0) {\n", [Tname]),
- emit_c_dec_rpt(Fd, " ", "ei_get_type", []),
- emit(Fd, " return oe_error_code;\n }\n"),
-
- emit(Fd, " if (~s != ~p) {\n",[Tname, Length]),
- emit_c_dec_rpt(Fd, " ", "~s != ~p", [Tname, Length]),
- emit(Fd, " return -1;\n }\n"),
-
-
- emit(Fd, " if ((oe_error_code = "
- "ei_decode_tuple_header(oe_env->_inbuf, "
- "oe_size_count_index, 0)) < 0) {\n"),
- emit_c_dec_rpt(Fd, " ", "ei_decode_tuple_header", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " if ((oe_error_code = "
- "ei_decode_atom(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n", []),
- emit_c_dec_rpt(Fd, " ", "ei_decode_atom", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- lists:foreach(
- fun({ET, EN}) ->
- case ic_cbe:is_variable_size(G, N, ET) of
- true ->
- case ET of
- {sequence, _, _} ->
- ic_cbe:emit_malloc_size_stmt(
- G, N, Fd,
- StructName ++ "_" ++ EN,
- "oe_env->_inbuf",
- 0,
- generator);
- {_,{array, _, _}} ->
- ic_cbe:emit_malloc_size_stmt(
- G, N, Fd,
- StructName ++ "_" ++ EN,
- "oe_env->_inbuf",
- 0,
- generator);
- {union,_,_,_,_} ->
- ic_cbe:emit_malloc_size_stmt(
- G, N, Fd,
- StructName ++ "_" ++ ic_forms:get_id2(ET),
- "oe_env->_inbuf",
- 0,
- generator);
-
- {struct,_,_,_} ->
- ic_cbe:emit_malloc_size_stmt(
- G, N, Fd,
- StructName ++ "_" ++ ic_forms:get_id2(ET),
- "oe_env->_inbuf",
- 0,
- generator);
-
- _ ->
- ic_cbe:emit_malloc_size_stmt(
- G, N, Fd,
- ET,
- "oe_env->_inbuf",
- 0,
- generator)
- end;
- false ->
- case ET of
- {_,{array, _, _}} ->
- ic_cbe:emit_malloc_size_stmt(
- G, N, Fd,
- StructName ++ "_" ++ EN,
- "oe_env->_inbuf",
- 0,
- generator);
-
- {union,_,_,_,_} ->
- ic_cbe:emit_malloc_size_stmt(
- G, N, Fd,
- StructName ++ "_" ++ ic_forms:get_id2(ET),
- "oe_env->_inbuf",
- 0,
- generator);
-
- {struct,_,_,_} ->
- ic_cbe:emit_malloc_size_stmt(
- G, N, Fd,
- StructName ++ "_" ++ ic_forms:get_id2(ET),
- "oe_env->_inbuf",
- 0,
- generator);
- _ ->
- ic_cbe:emit_malloc_size_stmt(
- G, N, Fd,
- ET,
- "oe_env->_inbuf",
- 1,
- generator)
- end
- end
- end,
- ElTypes),
-
- emit(Fd, " *oe_size = ~s;\n\n",
- [align("*oe_size + oe_malloc_size")]).
-
-
-array_size_dimension_loop(G, N, Fd, [Dim], Type) ->
- Tname = ic_cbe:mk_variable_name(op_variable_count),
-
- ic_cbe:store_tmp_decl(" int ~s = 0;\n",[Tname]),
- emit(Fd, " if ((oe_error_code = "
- "ei_get_type(oe_env->_inbuf, oe_size_count_index, "
- "&oe_type, &oe_array_size)) < 0) {\n",
- []),
- emit_c_dec_rpt(Fd, " ", "ei_get_type", []),
- emit(Fd, " return oe_error_code;\n }\n"),
-
- emit(Fd, " if (oe_array_size != ~s) {\n",[Dim]),
- emit_c_dec_rpt(Fd, " ", "array size != ~s", [Dim]),
- emit(Fd, " return -1;\n }\n"),
-
- emit(Fd, " if ((oe_error_code = ei_decode_tuple_header(oe_env->_inbuf, "
- "oe_size_count_index, 0)) < 0) {\n", []),
- emit_c_dec_rpt(Fd, " ", "ei_decode_tuple_header", []),
- emit(Fd, " return oe_error_code;\n }\n"),
-
- emit(Fd, " for (~s = 0; ~s < ~s; ~s++) {\n",
- [Tname, Tname, Dim, Tname]),
- ic_cbe:emit_malloc_size_stmt(G, N, Fd,
- Type, "oe_env->_inbuf", 0, generator),
- emit(Fd, " }\n");
-array_size_dimension_loop(G, N, Fd, [Dim | Ds], Type) ->
- Tname = ic_cbe:mk_variable_name(op_variable_count),
-
- ic_cbe:store_tmp_decl(" int ~s = 0;\n",[Tname]),
- emit(Fd, " if ((oe_error_code = "
- "ei_get_type(oe_env->_inbuf, oe_size_count_index, "
- "&oe_type, &oe_array_size)) < 0) {\n", []),
- emit_c_dec_rpt(Fd, " ", "ei_get_type", []),
- emit(Fd, " return oe_error_code;\n }\n"),
-
- emit(Fd, " if (oe_array_size != ~s) {\n",[Dim]),
- emit_c_dec_rpt(Fd, " ", "array size != ~s", [Dim]),
- emit(Fd, " return -1;\n }\n"),
-
- emit(Fd, " if ((oe_error_code = ei_decode_tuple_header(oe_env->_inbuf, "
- "oe_size_count_index, 0)) < 0) {\n",
- []),
- emit_c_dec_rpt(Fd, " ", "ei_decode_tuple_header", []),
- emit(Fd, " return oe_error_code;\n }\n"),
-
- emit(Fd, " for (~s = 0; ~s < ~s; ~s++) {\n",
- [Tname, Tname, Dim, Tname]),
- array_size_dimension_loop(G, N, Fd, Ds, Type),
- emit(Fd, " }\n").
-
-
-create_c_struct_coding_file(G, N, _X, T, StructName, ElTypes, StructType) ->
-
- {Fd , SName} = open_c_coding_file(G, StructName), % stub file
- HFd = ic_genobj:hrlfiled(G), % stub header file
- HrlFName = filename:basename(ic_genobj:include_file(G)),
-
- ic_codegen:emit_stub_head(G, Fd, SName, c),
- HrlFName = filename:basename(ic_genobj:include_file(G)),
- emit(Fd, "#include \"~s\"\n\n",[HrlFName]),
-
- %% Size count
-
- put(op_variable_count, 0),
- put(tmp_declarations, []),
-
- emit(HFd, "int ~s~s(CORBA_Environment *oe_env, int*, int*);\n",
- [ic_util:mk_oe_name(G, "sizecalc_"), StructName]),
-
- emit(Fd, "int ~s~s(CORBA_Environment *oe_env, "
- "int* oe_size_count_index, int* oe_size)\n{\n",
- [ic_util:mk_oe_name(G, "sizecalc_"), StructName]),
-
- emit(Fd, " int oe_malloc_size = 0;\n",[]),
- emit(Fd, " int oe_error_code = 0;\n",[]),
- emit(Fd, " int oe_type = 0;\n",[]),
-
- {ok, RamFd} = ram_file:open([], [binary, write]),
-
- emit_sizecount(StructType, G, N, T, RamFd, StructName, ElTypes),
-
- ic_cbe:emit_tmp_variables(Fd),
- ic_codegen:nl(Fd),
- %% Move data from ram file to output file.
- {ok, Data} = ram_file:get_file(RamFd),
- emit(Fd, Data),
- ram_file:close(RamFd),
-
- emit(Fd, " return 0;\n\n",[]),
- emit(Fd, "}\n\n",[]),
-
- %% Encode
-
- put(op_variable_count, 0),
- put(tmp_declarations, []),
-
-
- emit(HFd, "int ~s~s(CORBA_Environment *oe_env, ~s*);\n",
- [ic_util:mk_oe_name(G, "encode_"), StructName, StructName]),
-
- emit(Fd, "int ~s~s(CORBA_Environment *oe_env, ~s* oe_rec)\n{\n",
- [ic_util:mk_oe_name(G, "encode_"), StructName, StructName]),
-
- emit(Fd, " int oe_error_code = 0;\n",[]),
-
- {ok, RamFd1} = ram_file:open([], [binary, write]),
-
- emit_encode(StructType, G, N, T, RamFd1, StructName, ElTypes),
-
- ic_cbe:emit_tmp_variables(Fd),
- ic_codegen:nl(Fd),
- %% Move data from ram file to output file.
- {ok, Data1} = ram_file:get_file(RamFd1),
- emit(Fd, Data1),
- ram_file:close(RamFd1),
-
- emit(Fd, " return 0;\n\n",[]),
- emit(Fd, "}\n\n",[]),
-
- %% Decode
-
- put(op_variable_count, 0),
- put(tmp_declarations, []),
-
- emit(HFd, "int ~s~s(CORBA_Environment *oe_env, char *, int*, ~s *);\n",
- [ic_util:mk_oe_name(G, "decode_"), StructName, StructName]),
-
- emit(Fd, "int ~s~s(CORBA_Environment *oe_env, char *oe_first, "
- "int* oe_outindex, "
- "~s *oe_out)\n{\n",
- [ic_util:mk_oe_name(G, "decode_"), StructName, StructName]),
-
- emit(Fd, " int oe_error_code = 0;\n",[]),
-
- {ok, RamFd2} = ram_file:open([], [binary, write]),
-
- emit_decode(StructType, G, N, T, RamFd2, StructName, ElTypes),
-
- ic_cbe:emit_tmp_variables(Fd),
- ic_codegen:nl(Fd),
- %% Move data from ram file to output file.
- {ok, Data2} = ram_file:get_file(RamFd2),
- emit(Fd, Data2),
- ram_file:close(RamFd2),
-
- emit(Fd, " *oe_outindex = ~s;\n",[align("*oe_outindex")]),
- emit(Fd, " return 0;\n\n",[]),
- emit(Fd, "}\n\n",[]),
- file:close(Fd).
-
-
-%%------------------------------------------------------------
-%%
-%% emit primitive for unions.
-%%
-%%------------------------------------------------------------
-emit_union(G, N, X, erlang) ->
- case ic_genobj:is_hrlfile_open(G) of
- true ->
- ic_codegen:record(G, X,
- ic_util:to_undersc([ic_forms:get_id2(X) | N]),
- nil,nil),
- mkFileRecObj(G,N,X,erlang);
- false -> ok
- end;
-emit_union(_G, _N, _X, c) -> %% Not supported in c backend
- true.
-
-
-%%------------------------------------------------------------
-%%
-%% emit erlang modules for objects with record definitions
-%% (such as unions or structs), or sequences
-%%
-%% The record files, other than headers are only generated
-%% for CORBA...... If wished an option could allows even
-%% for other backends ( not necessary anyway )
-%%
-%%------------------------------------------------------------
-mkFileRecObj(G,N,X,erlang) ->
- case ic_options:get_opt(G, be) of
- erl_corba ->
- SName =
- ic_util:to_undersc([ic_forms:get_id2(X) | N]),
- FName =
- ic_file:join(ic_options:get_opt(G, stubdir),
- ic_file:add_dot_erl(SName)),
-
- case file:open(FName, [write]) of
- {ok, Fd} ->
- HrlFName = filename:basename(ic_genobj:include_file(G)),
-
- ic_codegen:emit_stub_head(G, Fd, SName, erlang),
- emit(Fd, "-include(~p).\n\n",[HrlFName]),
- emit_exports(G,Fd),
- emit_rec_methods(G,N,X,SName,Fd),
- ic_codegen:nl(Fd),
- ic_codegen:nl(Fd),
- file:close(Fd);
- Other ->
- exit(Other)
- end;
- _ ->
- true
- end.
-
-
-%%------------------------------------------------------------
-%%
-%% emit erlang modules for objects with array definitions..
-%%
-%%------------------------------------------------------------
-mkFileArrObj(G,N,X,erlang) ->
- SName =
- ic_util:to_undersc([ic_forms:get_id2(X) | N]),
- FName =
- ic_file:join(ic_options:get_opt(G, stubdir),
- ic_file:add_dot_erl(SName)),
-
- case file:open(FName, [write]) of
- {ok, Fd} ->
- HrlFName = filename:basename(ic_genobj:include_file(G)),
-
- ic_codegen:emit_stub_head(G, Fd, SName, erlang),
- emit(Fd, "-include(~p).\n\n",[HrlFName]),
- emit_exports(G,Fd),
- emit_arr_methods(G,N,X,SName,Fd),
- ic_codegen:nl(Fd),
- ic_codegen:nl(Fd),
- file:close(Fd);
- Other ->
- exit(Other)
- end.
-
-
-
-
-%%------------------------------------------------------------
-%%
-%% emit exports for erlang modules which represent records.
-%%
-%%------------------------------------------------------------
-emit_exports(G,Fd) ->
- case ic_options:get_opt(G, be) of
- erl_corba ->
- emit(Fd, "-export([tc/0,id/0,name/0]).\n\n\n\n",[]);
- _ ->
- emit(Fd, "-export([id/0,name/0]).\n\n\n\n",[])
- end.
-
-
-%%------------------------------------------------------------
-%%
-%% emit erlang module functions which represent records, yields
-%% record information such as type code, identity and name.
-%%
-%%------------------------------------------------------------
-emit_rec_methods(G,N,X,Name,Fd) ->
-
- IR_ID = ictk:get_IR_ID(G, N, X),
-
- case ic_options:get_opt(G, be) of
-
- erl_corba ->
- TK = ic_forms:get_tk(X),
-
- case TK of
- undefined ->
- STK = ic_forms:search_tk(G,ictk:get_IR_ID(G, N, X)),
- emit(Fd, "%% returns type code\n",[]),
- emit(Fd, "tc() -> ~p.\n\n",[STK]),
- emit(Fd, "%% returns id\n",[]),
- emit(Fd, "id() -> ~p.\n\n",[IR_ID]),
- emit(Fd, "%% returns name\n",[]),
- emit(Fd, "name() -> ~p.\n\n",[Name]);
- _ ->
- emit(Fd, "%% returns type code\n",[]),
- emit(Fd, "tc() -> ~p.\n\n",[TK]),
- emit(Fd, "%% returns id\n",[]),
- emit(Fd, "id() -> ~p.\n\n",[IR_ID]),
- emit(Fd, "%% returns name\n",[]),
- emit(Fd, "name() -> ~p.\n\n",[Name])
- end;
-
- _ ->
- emit(Fd, "%% returns id\n",[]),
- emit(Fd, "id() -> ~p.\n\n",[IR_ID]),
- emit(Fd, "%% returns name\n",[]),
- emit(Fd, "name() -> ~p.\n\n",[Name])
- end.
-
-
-
-%%------------------------------------------------------------
-%%
-%% emit erlang module functions which represent arrays, yields
-%% record information such as type code, identity and name.
-%%
-%%------------------------------------------------------------
-emit_arr_methods(G,N,X,Name,Fd) ->
-
- IR_ID = ictk:get_IR_ID(G, N, X),
-
- case ic_options:get_opt(G, be) of
-
- erl_corba ->
-
- TK = ic_forms:get_type_code(G, N, X),
-
- emit(Fd, "%% returns type code\n",[]),
- emit(Fd, "tc() -> ~p.\n\n",[TK]),
- emit(Fd, "%% returns id\n",[]),
- emit(Fd, "id() -> ~p.\n\n",[IR_ID]),
- emit(Fd, "%% returns name\n",[]),
- emit(Fd, "name() -> ~p.\n\n",[Name]);
-
- _ ->
-
- emit(Fd, "%% returns id\n",[]),
- emit(Fd, "id() -> ~p.\n\n",[IR_ID]),
- emit(Fd, "%% returns name\n",[]),
- emit(Fd, "name() -> ~p.\n\n",[Name])
- end.
-
-get_seq_max(T) when is_record(T, sequence) andalso T#sequence.length == 0 ->
- infinity;
-get_seq_max(T) when is_record(T, sequence) andalso is_tuple(T#sequence.length) ->
- list_to_integer(element(3, T#sequence.length)).
-
-
-align(Cs) ->
- ic_util:mk_align(Cs).
-
diff --git a/lib/ic/src/ictk.erl b/lib/ic/src/ictk.erl
deleted file mode 100644
index 701d662776..0000000000
--- a/lib/ic/src/ictk.erl
+++ /dev/null
@@ -1,874 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(ictk).
-
-
-%% Toplevel generation functions
--export([reg_gen/3, unreg_gen/3]).
-
-
-%% Utilities
--export([get_IR_ID/3, get_IR_VSN/3, register_name/1, unregister_name/1]).
-
--import(ic_forms, [get_id2/1, get_body/1, get_idlist/1]).
--import(ic_util, [mk_name/2, mk_oe_name/2, to_atom/1, to_list/1]).
--import(ic_codegen, [emit/2, emit/3, nl/1]).
-
--include("icforms.hrl").
--include("ic.hrl").
-
-%%--------------------------------------------------------------------
-%%
-%% IFR Registration Generation
-%%
-%%
-%%--------------------------------------------------------------------
-
--define(IFRID(G), mk_name(G, "IFR")).
--define(VARID(G), mk_name(G, "VAR")).
--define(IFRMOD, orber_ifr).
-
-reg_gen(G, N, X) ->
- S = ic_genobj:tktab(G),
- Light = ic_options:get_opt(G, light_ifr),
- init_var(),
- case ic_genobj:is_stubfile_open(G) of
- true when Light == false ->
- Var = ?IFRID(G),
- Fd = ic_genobj:stubfiled(G),
- nl(Fd), nl(Fd), nl(Fd),
- emit(Fd, "~p() ->\n", [to_atom(register_name(G))]),
- emit(Fd, " ~s = ~p:find_repository(),\n",
- [Var, ?IFRMOD]),
- nl(Fd),
-
- %% Write call function that checks if included
- %% modules and interfaces are created.
- emit(Fd, " register_tests(~s),\n",[?IFRID(G)]),
-
- reg2(G, S, N, Var, X),
- nl(Fd),
- emit(Fd, " ok.\n"),
-
- %% Write general register test function.
- register_tests(Fd,G),
-
- %% Write functopn that registers modules only if
- %% they are not registered.
- register_if_unregistered(Fd);
- true when Light == true ->
- Fd = ic_genobj:stubfiled(G),
- nl(Fd), nl(Fd), nl(Fd),
- Regname = to_atom(register_name(G)),
- emit(Fd, "~p() ->\n\t~p([]).\n\n", [Regname, Regname]),
- emit(Fd, "~p(OE_Options) ->\n\t~p:add_items(?MODULE, OE_Options,\n\t[",
- [Regname, ?IFRMOD]),
- reg_light(G, N, X),
- emit(Fd, "ok]),\n\tok.\n");
- false ->
- ok
- end.
-
-reg_light(G, N, X) when is_list(X) ->
- reg_light_list(G, N, X);
-reg_light(G, N, X) when is_record(X, module) ->
- reg_light_list(G, [get_id2(X) | N], get_body(X));
-reg_light(G, N, X) when is_record(X, struct) ->
- emit(ic_genobj:stubfiled(G), "{~p, ~p, struct},\n\t",
- [get_IR_ID(G, N, X), get_module(X, N)]);
-reg_light(G, N, X) when is_record(X, except) ->
- emit(ic_genobj:stubfiled(G), "{~p, ~p, except},\n\t",
- [get_IR_ID(G, N, X), get_module(X, N)]);
-reg_light(G, N, X) when is_record(X, union) ->
- emit(ic_genobj:stubfiled(G), "{~p, ~p, union},\n\t",
- [get_IR_ID(G, N, X), get_module(X, N)]);
-reg_light(G, N, X) when is_record(X, interface) ->
- emit(ic_genobj:stubfiled(G), "{~p, ~p, interface},\n\t",
- [get_IR_ID(G, N, X), get_module(X, N)]),
- reg_light_list(G, [get_id2(X)|N], get_body(X));
-reg_light(_G, _N, _X) ->
- ok.
-
-get_module(X, N) ->
- List = [get_id2(X) | N],
- list_to_atom(lists:foldl(fun(E, Acc) -> E++"_"++Acc end,
- hd(List), tl(List))).
-
-%% This function filters off all "#include <FileName>.idl" code that
-%% come along from preprocessor and scanner. Produces code ONLY for
-%% the actuall file. See ticket OTP-2133
-reg_light_list(_G, _N, []) -> [];
-reg_light_list(G, N, List ) ->
- CurrentFileName = ic_genobj:idlfile(G),
- reg_light_list(G, N, {CurrentFileName,true}, List).
-
-%% The filter function + loop
-reg_light_list(_G, _N, {_CFN, _Status}, []) -> [];
-reg_light_list(G, N, {CFN,Status}, [X | Xs]) ->
- case Status of
- true ->
- case X of
- {preproc,_,{_,_,_FileName},[{_,_,"1"}]} ->
- reg_light_list(G, N, {CFN,false}, Xs);
- _ ->
- reg_light(G, N, X),
- reg_light_list(G, N, {CFN,Status}, Xs)
- end;
- false ->
- case X of
- {preproc,_,{_,_,CFN},[{_,_,"2"}]} ->
- reg_light(G, N, X),
- reg_light_list(G, N, {CFN,true}, Xs);
- _ ->
- reg_light_list(G, N, {CFN,Status}, Xs)
- end
- end.
-
-
-%% reg2 is top level registration
-
-reg2(G, S, N, Var, X) ->
- reg2(G, S, N, "Repository_create_", Var, X).
-
-reg2(G, S, N, C, V, X) when is_list(X) -> reg2_list(G, S, N, C, V, X);
-
-reg2(G, S, N, C, V, X) when is_record(X, module) ->
- NewV = r_emit2(G, S, N, C, V, X, "", []),
- reg2_list(G, S, [get_id2(X) | N], "ModuleDef_create_", NewV, get_body(X));
-
-reg2(G, S, N, C, V, X) when is_record(X, const) ->
- r_emit2(G, S, N, C, V, X, ", ~s, ~p",
- [get_idltype(G, S, N, X), {X#const.tk, X#const.val}]);
-
-reg2(G, S, N, C, V, X) when is_record(X, struct) ->
- do_struct(G, S, N, C, V, X, ic_forms:get_tk(X));
-
-reg2(G, S, N, C, V, X) when is_record(X, except) ->
- do_except(G, S, N, C, V, X, ic_forms:get_tk(X));
-
-reg2(G, S, N, C, V, X) when is_record(X, union) ->
- do_union(G, S, N, C, V, X, ic_forms:get_tk(X));
-
-reg2(G, S, N, C, V, X) when is_record(X, enum) ->
- r_emit2(G, S, N, C, V, X, ", ~p",
- [get_enum_member_list(G, S, N, get_body(X))]);
-
-reg2(G, S, N, C, V, X) when is_record(X, typedef) ->
- do_typedef(G, S, N, C, V, X),
- look_for_types(G, S, N, C, V, get_body(X));
-
-reg2(G, S, N, C, V, X) when is_record(X, attr) ->
- XX = #id_of{type=X},
- lists:foreach(fun(Id) -> r_emit2(G, S, N, C, V, XX#id_of{id=Id}, ", ~s, ~p",
- [get_idltype(G, S, N, X), get_mode(G, N, X)])
- end,
- get_idlist(X));
-
-reg2(G, S, N, C, V, X) when is_record(X, interface) ->
- N2 = [get_id2(X) | N],
- Body = get_body(X),
- BIs = get_base_interfaces(G,X), %% produce code for the interface inheritance
- NewV = r_emit2(G, S, N, C, V, X, ", " ++ BIs,[]),
- reg2_list(G, S, N2, "InterfaceDef_create_", NewV, Body);
-
-
-reg2(G, S, N, C, V, X) when is_record(X, op) ->
- r_emit2(G, S, N, C, V, X, ", ~s, ~p, [~s], [~s], ~p",
- [get_idltype(G, S, N, X), get_mode(G, N, X),
- get_params(G, S, N, X#op.params), get_exceptions(G, S, N, X),
- get_context(G, S, N, X)]);
-
-reg2(_G, _S, _N, _C, _V, X) when is_record(X, preproc) -> ok;
-
-reg2(_G, _S, _N, _C, _V, X) when is_record(X, pragma) -> ok;
-
-reg2(_G, _S, _N, _C, _V, _X) -> ok.
-
-
-%% This function filters off all "#include <FileName>.idl" code that
-%% come along from preprocessor and scanner. Produces code ONLY for
-%% the actuall file. See ticket OTP-2133
-reg2_list(_G, _S, _N, _C, _V, []) -> [];
-reg2_list(G, S, N, C, V, List ) ->
- CurrentFileName = ic_genobj:idlfile(G),
- reg2_list(G, S, N, C, V, {CurrentFileName,true}, List).
-
-%% The filter function + loop
-reg2_list(_G, _S, _N, _C, _V, {_CFN, _Status}, []) -> [];
-reg2_list(G, S, N, C, V, {CFN,Status}, [X | Xs]) ->
- case Status of
- true ->
- case X of
- {preproc,_,{_,_,_FileName},[{_,_,"1"}]} ->
- reg2_list(G, S, N, C, V, {CFN,false}, Xs);
- _ ->
- F = reg2(G, S, N, C, V, X),
- [F | reg2_list(G, S, N, C, V, {CFN,Status}, Xs)]
- end;
- false ->
- case X of
- {preproc,_,{_,_,CFN},[{_,_,"2"}]} ->
- F = reg2(G, S, N, C, V, X),
- [F | reg2_list(G, S, N, C, V, {CFN,true}, Xs)];
- _ ->
- reg2_list(G, S, N, C, V, {CFN,Status}, Xs)
- end
- end.
-
-
-
-
-
-%% General registration tests
-register_tests(Fd,G) ->
- IfrId = ?IFRID(G),
- emit(Fd,"\n\n%% General IFR registration checks.\n", []),
- emit(Fd,"register_tests(~s)->\n",[IfrId]),
- emit(Fd," re_register_test(~s),\n",[IfrId]),
- emit(Fd," include_reg_test(~s).\n\n",[IfrId]),
-
- emit(Fd,"\n%% IFR type Re-registration checks.\n", []),
- case ic_pragma:fetchRandomLocalType(G) of
- {ok,TypeId} ->
- emit(Fd,"re_register_test(~s)->\n",[IfrId]),
- emit(Fd," case orber_ifr:'Repository_lookup_id'(~s,~p) of\n", [IfrId,TypeId]),
- emit(Fd," [] ->\n true;\n",[]),
- emit(Fd," _ ->\n exit({allready_registered,~p})\n end.\n\n", [TypeId]);
- false ->
- emit(Fd,"re_register_test(_)-> true.\n",[])
- end,
-
- emit(Fd,"~s",[check_include_regs(G)]).
-
-
-
-
-%% This function produces code for existance check over
-%% top level included modules and interfaces
-check_include_regs(G) ->
- IfrId = ?IFRID(G),
- case ic_pragma:get_incl_refs(G) of
- none ->
- io_lib:format("\n%% No included idl-files detected.\n", []) ++
- io_lib:format("include_reg_test(_~s) -> true.\n",[IfrId]);
- IMs ->
- io_lib:format("\n%% IFR registration checks for included idl files.\n", []) ++
- io_lib:format("include_reg_test(~s) ->\n",[IfrId]) ++
- check_incl_refs(G,IfrId,IMs)
- end.
-
-
-
-check_incl_refs(_,_,[]) ->
- io_lib:format(" true.\n",[]);
-check_incl_refs(G,IfrId,[[First]|Rest]) ->
- ModId = ic_pragma:scope2id(G,First),
- io_lib:format(" case orber_ifr:'Repository_lookup_id'(~s,~p) of~n", [IfrId,ModId]) ++
- io_lib:format(" [] ->~n exit({unregistered,~p});~n", [ModId]) ++
- io_lib:format(" _ ->~n true~n end,~n",[]) ++
- check_incl_refs(G,IfrId,Rest).
-
-
-
-%% This function will return module ref, it will
-%% also register module if not registered.
-register_if_unregistered(Fd) ->
- emit(Fd, "\n\n%% Fetch top module reference, register if unregistered.\n"),
- emit(Fd, "oe_get_top_module(OE_IFR, ID, Name, Version) ->\n"),
- emit(Fd, " case orber_ifr:'Repository_lookup_id'(OE_IFR, ID) of\n"),
- emit(Fd, " [] ->\n"),
- emit(Fd, " orber_ifr:'Repository_create_module'(OE_IFR, ID, Name, Version);\n"),
- emit(Fd, " Mod ->\n"),
- emit(Fd, " Mod\n",[]),
- emit(Fd, " end.\n\n"),
- emit(Fd, "%% Fetch module reference, register if unregistered.\n"),
- emit(Fd, "oe_get_module(OE_IFR, OE_Parent, ID, Name, Version) ->\n"),
- emit(Fd, " case orber_ifr:'Repository_lookup_id'(OE_IFR, ID) of\n"),
- emit(Fd, " [] ->\n"),
- emit(Fd, " orber_ifr:'ModuleDef_create_module'(OE_Parent, ID, Name, Version);\n"),
- emit(Fd, " Mod ->\n"),
- emit(Fd, " Mod\n",[]),
- emit(Fd, " end.\n").
-
-
-
-do_typedef(G, S, N, C, V, X) ->
- case ic_genobj:is_stubfile_open(G) of
- false -> ok;
- true ->
- Fd = ic_genobj:stubfiled(G),
- Thing = get_thing_name(X),
- IR_VSN = get_IR_VSN(G, N, X),
- TK = ic_forms:get_tk(X),
-
- lists:foreach(
- fun(Id) ->
- r_emit_raw(G, X, Fd, "", C, Thing, V,
- get_IR_ID(G, N, Id), get_id2(Id),
- IR_VSN, ", ~s",
- [get_idltype_tk(G, S, N,
- ictype:maybe_array(G, S, N,
- Id, TK))])
- end, get_idlist(X))
- end.
-
-
-do_union(G, S, N, C, V, X, {tk_union, _IFRID, _Name, DiscrTK, _DefNr, L}) ->
- N2 = [get_id2(X) | N],
- r_emit2(G, S, N, C, V, X, ", ~s, [~s]",
- [get_idltype_tk(G, S, N, DiscrTK),
- get_union_member_def(G, S, N2, L)]),
- look_for_types(G, S, N2, C, V, get_body(X)).
-
-do_struct(G, S, N, C, V, X, {tk_struct, _IFRID, _Name, ElemList}) ->
- N2 = [get_id2(X) | N],
- r_emit2(G, S, N, C, V, X, ", [~s]",
- [get_member_def(G, S, N, ElemList)]),
- look_for_types(G, S, N2, C, V, get_body(X)).
-
-do_except(G, S, N, C, V, X, {tk_except, _IFRID, _Name, ElemList}) ->
- N2 = [get_id2(X) | N],
- r_emit2(G, S, N, C, V, X, ", [~s]",
- [get_member_def(G, S, N, ElemList)]),
- look_for_types(G, S, N2, C, V, get_body(X)).
-
-
-%% new_var finds an unused Erlang variable name by increasing a
-%% counter.
-new_var(_G) ->
- lists:flatten(["_OE_", integer_to_list(put(var_count, get(var_count) + 1))]).
-init_var() ->
- put(var_count, 1).
-
-%% Public interface. The name of the register function.
-register_name(G) ->
- mk_oe_name(G, "register").
-unregister_name(G) ->
- mk_oe_name(G, "unregister").
-
-
-
-look_for_types(G, S, N, C, V, L) when is_list(L) ->
- lists:foreach(fun(X) -> look_for_types(G, S, N, C, V, X) end, L);
-look_for_types(G, S, N, C, V, {_Name, TK}) -> % member
- look_for_types(G, S, N, C, V, TK);
-look_for_types(_G, _S, _N, _C, _V, {tk_union, _IFRID, _Name, _DT, _Def, _L}) ->
- ok;
-look_for_types(G, S, N, C, V, {_Label, _Name, TK}) -> % case_dcl
- look_for_types(G, S, N, C, V, TK);
-look_for_types(_G, _S, _N, _C, _V, {tk_struct, _IFRID, _Name, _L}) ->
- ok;
-look_for_types(_G, _S, _N, _C, _V, _X) ->
- ok.
-
-
-
-
-%% This function produces code for the interface inheritance registration.
-%% It produces a string that represents a list of function calls.
-%% This list becomes a list of object references when the main function
-%% "orber_ifr:ModuleDef_create_interface" is called.
-
-get_base_interfaces(G,X) ->
- case element(3,X) of
- [] ->
- "[]";
- L ->
- "[" ++
- lists:flatten(
- lists:foldl(
- fun(E, Acc) -> [call_fun_str(G,E), ", " | Acc] end,
- call_fun_str(G,hd(L)),
- tl(L)
- )
- ) ++ "]"
- end.
-
-call_fun_str(G,S) ->
- lists:flatten(
- io_lib:format("orber_ifr:lookup_id(~s,\"~s\")",
- [ ?IFRID(G),
- ic_pragma:scope2id(G,S)] )).
-
-
-
-
-
-%%--------------------------------------------------------------------
-%%
-%% r_emit emits an IFR register function call. It returns a new
-%% variable (if further defs should be added to that one)
-%%
-%% G is genobj
-%%
-%% S is symbol table (ets)
-%%
-%% N is list of ids describing scope
-%%
-%% C is create stub (eg. "Repository_create_")
-%%
-%% V is variable name where current def should be added,
-%%
-%% X is the current def item,
-%%
-%% F and A is auxillary format and args that will be io_lib
-%% formatted and inserted as a string (don't forget to start with
-%% ", ")
-%%
-r_emit2(G, _S, N, C, V, X, F, A) ->
- case ic_genobj:is_stubfile_open(G) of
- false -> ok;
- true ->
- {NewV, Str} = get_assign(G, V, X),
- r_emit_raw(G, X, ic_genobj:stubfiled(G), Str,
- C, get_thing_name(X), V,
- get_IR_ID(G, N, X), get_id2(X), get_IR_VSN(G, N, X),
- F, A),
- NewV
- end.
-
-
-%%--------------------------------------------------------------------
-%%
-%% An IFR register line registers an entity (Thing) into the IFR. The
-%% thing is registered INTO something, an type is registered into a
-%% module for instance, and this is reflected in the Var parameter
-%% below. The var parameter is the name of the parent IFR object. The
-%% Thing parameter is the name of the thing we're trying to register,
-%% a typdef is called an alias and an interface is called an
-%% interface. Sometimes we need to store the thing we're registering
-%% into a variable because we're going to add other things to it
-%% later, modules and interfaces are such containers, so we must
-%% remember that variable for later use.
-%%
-%% All parameters shall be strings unless otherwise noted
-%%
-%% Fd - File descriptor
-%% AssignStr - Assign or not, empty except for interfaces and modules
-%% Create - Create has diff. names dep. on into what we register
-%% Thing - WHAT is registered, interface
-%% Var - The name of the variable we register into
-%% IR_ID - The IFR identifier (may be "")
-%% Id - The identifier (name) of the object
-%% IR_VSN - The IFR version as a string
-%% AuxStr - An auxillary string
-%%
-%%r_emit_raw(Fd, AssignStr, Create, Thing, Var, IR_ID, Id, IR_VSN) ->
-%% r_emit_raw(Fd, AssignStr, Create, Thing, Var, IR_ID, Id, IR_VSN, "", []).
-r_emit_raw(_G, X, Fd, AssignStr, "Repository_create_", Thing, Var, IR_ID, Id, IR_VSN, F, A)
- when is_record(X, module) ->
- emit(Fd, "~n ~s~p(~s, \"~s\", \"~s\", \"~s\"~s),~n",
- [AssignStr, to_atom("oe_get_top_"++Thing), Var, IR_ID, Id,
- IR_VSN, io_lib:format(F, A)]);
-r_emit_raw(G, X, Fd, AssignStr, "ModuleDef_create_", Thing, Var, IR_ID, Id, IR_VSN, F, A)
- when is_record(X, module) ->
- emit(Fd, "~n ~s~p(~s, ~s, \"~s\", \"~s\", \"~s\"~s),~n",
- [AssignStr, to_atom("oe_get_"++Thing), ?IFRID(G), Var, IR_ID, Id,
- IR_VSN, io_lib:format(F, A)]);
-r_emit_raw(_G, _X, Fd, AssignStr, Create, Thing, Var, IR_ID, Id, IR_VSN, F, A) ->
- emit(Fd, "~n ~s~p:~p(~s, \"~s\", \"~s\", \"~s\"~s),~n",
- [AssignStr, ?IFRMOD, to_atom(Create++Thing), Var, IR_ID, Id,
- IR_VSN, io_lib:format(F, A)]).
-
-
-
-
-%% Used by r_emit. Returns tuple {Var, Str} where Var is the resulting
-%% output var (if any, otherwise same as input arg) and Str is a
-%% string of the assignment if any ("" or "Var = ")
-get_assign(G, _V, X) when is_record(X, module) ->
- mk_assign(G);
-get_assign(G, _V, X) when is_record(X, interface) ->
- mk_assign(G);
-get_assign(_G, V, _X) -> {V, ""}.
-mk_assign(G) ->
- V = new_var(G),
- {V, io_lib:format("~s = ", [V])}.
-
-%% Returns a list of strings of all enum members (suitable for ~p)
-get_enum_member_list(_G, _S, _N, L) ->
- lists:map(fun(M) -> get_id2(M) end, L).
-
-%% Will output a string of the union members.
-get_union_member_def(_G, _S, _N, []) -> [];
-get_union_member_def(G, S, N, L) ->
- [union_member2str(G, S, N, hd(L)) |
- lists:map(fun(M) -> [", ", union_member2str(G, S, N, M)] end, tl(L))].
-%% lists:foldl(fun(M, Acc) ->
-%% [union_member2str(G, S, N, M),", " | Acc] end,
-%% union_member2str(G, S, N, hd(L)), tl(L)).
-
-union_member2str(G, S, N, {Label, Name, TK}) ->
- io_lib:format("~s{name=~p, label=~p, type=~p, type_def=~s}",
- ["#unionmember", Name, Label, TK,
- get_idltype_tk(G, S, N, TK)]).
-
-
-%% Will output a string of the struct members. Works for exceptions
-%% and structs
-%%
-get_member_def(_G, _S, _N, []) -> [];
-get_member_def(G, S, N, L) ->
- [member2str(G, S, N, hd(L)) |
- lists:map(fun(M) -> [", ", member2str(G, S, N, M)] end, tl(L))].
-
-member2str(G, S, N, {Id, TK}) ->
- io_lib:format("~s{name=~p, type=~p, type_def=~s}",
- ["#structmember", Id, TK, get_idltype_tk(G, S, N, TK)]).
-
-%% Translates between record names and create operation names.
-get_thing_name(X) when is_record(X, op) -> "operation";
-get_thing_name(X) when is_record(X, const) -> "constant";
-get_thing_name(X) when is_record(X, typedef) -> "alias";
-get_thing_name(X) when is_record(X, attr) -> "attribute";
-get_thing_name(X) when is_record(X, except) -> "exception";
-get_thing_name(X) when is_record(X, id_of) -> get_thing_name(X#id_of.type);
-get_thing_name(X) -> to_list(element(1,X)).
-
-
-%% Returns the mode (in, out, oneway etc) of ops and params. Return
-%% value is an atom.
-get_mode(_G, _N, X) when is_record(X, op) ->
- case X#op.oneway of
- {oneway, _} -> 'OP_ONEWAY';
- _ -> 'OP_NORMAL'
- end;
-get_mode(_G, _N, X) when is_record(X, attr) ->
- case X#attr.readonly of
- {readonly, _} -> 'ATTR_READONLY';
- _ -> 'ATTR_NORMAL'
- end;
-get_mode(_G, _N, X) when is_record(X, param) ->
- case X#param.inout of
- {in, _} -> 'PARAM_IN';
- {inout, _} -> 'PARAM_INOUT';
- {out, _} -> 'PARAM_OUT'
- end.
-
-
-%% Returns a string form of idltype creation.
-%%get_idltype_id(G, S, N, X, Id) ->
-%% TK = ictype:tk_lookup(G, S, N, Id),
-%% get_idltype_tk(G, S, N, TK).
-get_idltype(G, S, N, X) ->
- get_idltype_tk(G, S, N, ic_forms:get_tk(X)).
-get_idltype_tk(G, _S, _N, TK) ->
- io_lib:format("~p:~p(~s, ~p)", [orber_ifr, 'Repository_create_idltype',
- ?IFRID(G), TK]).
-
-%% Returns a string form of typecode creation. This shall be found in
-%% the type code symbol table.
-%%get_typecode(G, S, N, X) -> typecode.
-%%get_typecode(G, S, N, X) -> tk(G, S, N, get_type(X)).
-
-
-%% Returns the string form of a list of parameters.
-get_params(_G, _S, _N, []) -> "";
-get_params(G, S, N, L) ->
- lists:foldl(fun(X, Acc) -> param2str(G, S, N, X)++", "++Acc end,
- param2str(G, S, N, hd(L)), tl(L)).
-
-
-%% Converts a parameter to a string.
-param2str(G, S, N, X) ->
- io_lib:format("~s{name=~p, type=~p, type_def=~s, mode=~p}~n",
- ["#parameterdescription", get_id2(X),
- ic_forms:get_tk(X),
- %%tk_lookup(G, S, N, get_type(X)),
- get_idltype(G, S, N, X),
- get_mode(G, N, X)]).
-
-
-
-
-%% Public interface. Returns the IFR ID of an object. This
-%% is updated to comply with CORBA 2.0 pragma directives.
-get_IR_ID(G, N, X) ->
- ScopedId = [get_id2(X) | N],
- case ic_pragma:get_alias(G,ScopedId) of
- none ->
- case ic_pragma:pragma_id(G, N, X) of
- none ->
- case ic_pragma:pragma_prefix(G, N, X) of
- none ->
- IR_ID = lists:flatten(
- io_lib:format("IDL:~s:~s",
- [slashify(ScopedId),
- get_IR_VSN(G, N, X)])),
- ic_pragma:mk_alias(G,IR_ID,ScopedId),
- IR_ID;
- PF ->
- IR_ID = lists:flatten(
- io_lib:format("IDL:~s:~s",
- [ PF ++ "/" ++
- get_id2(X),
- get_IR_VSN(G, N, X)])),
- ic_pragma:mk_alias(G,IR_ID,ScopedId),
- IR_ID
- end;
- PI ->
- ic_pragma:mk_alias(G,PI,ScopedId),
- PI
- end;
- Alias ->
- Alias
- end.
-
-
-%% Public interface. Returns the IFR Version of an object. This
-%% is updated to comply with CORBA 2.0 pragma directives.
-get_IR_VSN(G, N, X) ->
- ic_pragma:pragma_version(G,N,X).
-
-
-
-
-
-%% Returns a slashified name, [I1, M1] becomes "M1/I1"
-%slashify(List) -> lists:foldl(fun(X, Acc) -> get_id2(X)++"/"++Acc end,
-% hd(List), tl(List)).
-
-%% Returns a slashified name, [I1, M1] becomes "M1/I1"
-slashify(List) -> lists:foldl(fun(X, Acc) -> X++"/"++Acc end,
- hd(List), tl(List)).
-
-
-%% Returns the context literals of an op
-get_context(_G, _S, _N, X) ->
- lists:map(fun(C) -> element(3, C) end, X#op.ctx).
-
-
-
-%% Returns the list of the exceptions of an operation
-get_exceptions(G, S, N, X) ->
- case X#op.raises of
- [] ->
- "";
- L ->
- lists:flatten(
- lists:foldl(
- fun(E, Acc) -> [excdef(G, S, N, X, E), ", " | Acc] end,
- excdef(G, S, N, X, hd(L)),
- tl(L)
- )
- )
- end.
-
-
-%% Returns the definition of an exception of an operation
-excdef(G, S, N, X, L) ->
- io_lib:format("orber_ifr:lookup_id(~s,\"~s\")",
- [ ?IFRID(G),
- get_EXC_ID(G, S, N, X, L) ] ).
-
-
-
-
-
-
-%% This function produces code for the exception registration.
-%% It produces a string that represents a list of function calls.
-%% This list becomes a list of object references when the main function
-%% "orber_ifr:InterfaceDef_create_operation" is called.
-
-get_EXC_ID(G, _S, N, X, ScopedId) ->
- case ic_pragma:get_alias(G,ScopedId) of
- none ->
- case ic_pragma:pragma_id(G, N, X) of
- none ->
- case ic_pragma:pragma_prefix(G, N, X) of
- none ->
- EXC_ID = lists:flatten(
- io_lib:format("IDL:~s:~s", [slashify(ScopedId),
- get_IR_VSN(G, N, X)])),
- ic_pragma:mk_alias(G,EXC_ID,ScopedId),
- EXC_ID;
- PF ->
- EXC_ID = lists:flatten(
- io_lib:format("IDL:~s:~s", [ PF ++ "/" ++
- hd(ScopedId),
- get_IR_VSN(G, N, X)])),
- ic_pragma:mk_alias(G,EXC_ID,ScopedId),
- EXC_ID
- end;
- PI ->
- ic_pragma:mk_alias(G,PI,ScopedId),
- PI
- end;
- Alias ->
- Alias
- end.
-
-
-
-
-
-%% unreg_gen/1 uses the information stored in pragma table
-%% to decide which modules are to be unregistered
-unreg_gen(G, N, X) ->
- Light = ic_options:get_opt(G, light_ifr),
- case ic_genobj:is_stubfile_open(G) of
- true when Light == false ->
- Var = ?IFRID(G),
- Fd = ic_genobj:stubfiled(G),
- nl(Fd), nl(Fd), nl(Fd),
- emit(Fd, "~p() ->\n", [to_atom(unregister_name(G))]),
- emit(Fd, " ~s = ~p:find_repository(),\n",
- [Var, ?IFRMOD]),
- nl(Fd),
-
- unreg2(G, N, X),
- emit(Fd, " ok.\n\n"),
- destroy(Fd);
- true ->
- Fd = ic_genobj:stubfiled(G),
- nl(Fd), nl(Fd),
- Unregname = to_atom(unregister_name(G)),
- emit(Fd, "~p() ->\n\t~p([]).\n\n~p(OE_Options) ->\n",
- [Unregname, Unregname, Unregname]),
- emit(Fd, "\t~p:remove(?MODULE, OE_Options),\n\tok.\n\n", [?IFRMOD]);
- false -> ok
- end.
-
-
-destroy(Fd) ->
-emit(Fd,"
-oe_destroy_if_empty(OE_IFR,IFR_ID) ->
- case orber_ifr:'Repository_lookup_id'(OE_IFR, IFR_ID) of
- [] ->
- ok;
- Ref ->
- case orber_ifr:contents(Ref, \'dk_All\', \'true\') of
- [] ->
- orber_ifr:destroy(Ref),
- ok;
- _ ->
- ok
- end
- end.
-
-oe_destroy(OE_IFR,IFR_ID) ->
- case orber_ifr:'Repository_lookup_id'(OE_IFR, IFR_ID) of
- [] ->
- ok;
- Ref ->
- orber_ifr:destroy(Ref),
- ok
- end.
-
-",[]).
-
-
-
-
-
-
-
-
-
-
-%% unreg2 is top level registration
-
-unreg2(G, N, X) ->
- emit(ic_genobj:stubfiled(G),"~s",[lists:flatten(unreg3(G, N, X))]).
-
-unreg3(G, N, X) when is_list(X) ->
- unreg3_list(G, N, X, []);
-
-unreg3(G, N, X) when is_record(X, module) ->
- unreg3_list(G, [get_id2(X) | N], get_body(X), [unreg_collect(G, N, X)]);
-
-unreg3(G, N, X) when is_record(X, const) ->
- unreg_collect(G, N, X);
-
-unreg3(G, N, X) when is_record(X, struct) ->
- unreg_collect(G, N, X);
-
-unreg3(G, N, X) when is_record(X, except) ->
- unreg_collect(G, N, X);
-
-unreg3(G, N, X) when is_record(X, union) ->
- unreg_collect(G, N, X);
-
-unreg3(G, N, X) when is_record(X, enum) ->
- unreg_collect(G, N, X);
-
-unreg3(G, N, X) when is_record(X, typedef) ->
- unreg_collect(G, N, X);
-
-unreg3(G, N, X) when is_record(X, interface) ->
- unreg_collect(G, N, X);
-
-unreg3(_G, _N, X) when is_record(X, op) -> [];
-
-unreg3(_G, _N, X) when is_record(X, attr) -> [];
-
-unreg3(_G, _N, X) when is_record(X, preproc) -> [];
-
-unreg3(_G, _N, X) when is_record(X, pragma) -> [];
-
-unreg3(_G, _N, _X) -> [].
-
-
-unreg3_list(_G, _N, [], Found) ->
- Found;
-unreg3_list(G, N, List, Found) ->
- CurrentFileName = ic_genobj:idlfile(G),
- unreg3_list(G, N, {CurrentFileName,true}, List, Found).
-
-%% The filter function + loop
-unreg3_list(_G, _N, {_CFN, _Status}, [], Found) ->
- Found;
-unreg3_list(G, N, {CFN,Status}, [X | Xs], Found) ->
- case Status of
- true ->
- case X of
- {preproc,_,{_,_,_FileName},[{_,_,"1"}]} ->
- unreg3_list(G, N, {CFN,false}, Xs, Found);
- _ ->
- unreg3_list(G, N, {CFN,Status}, Xs, [unreg3(G, N, X) | Found])
- end;
- false ->
- case X of
- {preproc,_,{_,_,CFN},[{_,_,"2"}]} ->
- unreg3_list(G, N, {CFN,true}, Xs,[unreg3(G, N, X) | Found]);
- _ ->
- unreg3_list(G, N, {CFN,Status}, Xs, Found)
- end
- end.
-
-
-
-unreg_collect(G, N, X) when is_record(X, module) ->
- io_lib:format(" oe_destroy_if_empty(OE_IFR, ~p),\n",
- [get_IR_ID(G, N, X)]);
-unreg_collect(G, N, X) when is_record(X, typedef) ->
- lists:map(fun(Id) ->
- io_lib:format(" oe_destroy(OE_IFR, ~p),\n",
- [get_IR_ID(G, N, Id)])
- end,
- ic_forms:get_idlist(X));
-unreg_collect(G, N, X) ->
- io_lib:format(" oe_destroy(OE_IFR, ~p),\n",
- [get_IR_ID(G, N, X)]).
-
-
-
diff --git a/lib/ic/src/ictype.erl b/lib/ic/src/ictype.erl
deleted file mode 100644
index eb6f2088d7..0000000000
--- a/lib/ic/src/ictype.erl
+++ /dev/null
@@ -1,1417 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(ictype).
-
-
--include("ic.hrl").
--include("icforms.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([type_check/2, scoped_lookup/4, maybe_array/5, to_uppercase/1]).
-
--export([name2type/2, member2type/3, isBasicTypeOrEterm/3, isEterm/3]).
--export([isBasicType/1, isBasicType/2, isBasicType/3, isString/3, isWString/3,
- isArray/3, isStruct/3, isUnion/3, isEnum/3, isSequence/3, isBoolean/3 ]).
--export([fetchTk/3, fetchType/1, tk/4]).
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-%%-----------------------------------------------------------------
-%% Macros
-%%-----------------------------------------------------------------
-%%-define(DBG(F,A), io:format(F,A)).
--define(DBG(F,A), true).
--define(STDDBG, ?DBG(" dbg: ~p: ~p~n", [element(1,X), ic_forms:get_id2(X)])).
-
-%%-----------------------------------------------------------------
-%% External functions
-%%-----------------------------------------------------------------
-
-type_check(G, Forms) ->
- S = ic_genobj:tktab(G),
- check_list(G, S, [], Forms).
-
-scoped_lookup(G, S, N, X) ->
- Id = ic_symtab:scoped_id_strip(X),
- case ic_symtab:scoped_id_is_global(X) of
- true ->
- lookup(G, S, [], X, Id);
- false ->
- lookup(G, S, N, X, Id)
- end.
-
-
-%%--------------------------------------------------------------------
-%% maybe_array
-%%
-%% Array declarators are indicated on the declarator and not on
-%% the type, therefore the declarator decides if the array type
-%% kind is added or not.
-%%
-maybe_array(G, S, N, X, TK) when is_record(X, array) ->
- mk_array(G, S, N, X#array.size, TK);
-maybe_array(_G, _S, _N, _, TK) -> TK.
-
-
-
-name2type(G, Name) ->
- S = ic_genobj:tktab(G),
- ScopedName = lists:reverse(string:tokens(Name, "_")),
- InfoList = ets:lookup(S, ScopedName ),
- filter( InfoList ).
-
-
-%% This is en overloaded function,
-%% differs in input on unions
-member2type(_G, X, I) when is_record(X, union)->
- Name = ic_forms:get_id2(I),
- case lists:keysearch(Name,2,element(6,X#union.tk)) of
- false ->
- error;
- {value,Rec} ->
- fetchType(element(3,Rec))
- end;
-member2type( G, SName, MName ) ->
-
- S = ic_genobj:tktab( G ),
- SNList = lists:reverse(string:tokens(SName,"_")),
- ScopedName = [MName | SNList],
- InfoList = ets:lookup( S, ScopedName ),
-
- case filter( InfoList ) of
- error ->
- %% Try a little harder, seeking inside tktab
- case lookup_member_type_in_tktab(S, ScopedName, MName) of
- error ->
- %% Check if this is the "return to return1" case
- case MName of
- "return1" ->
- %% Do it all over again !
- ScopedName2 = ["return" | SNList],
- InfoList2 = ets:lookup( S, ScopedName2 ),
- case filter( InfoList2 ) of
- error ->
- %% Last resort: seek in pragma table
- lookup_type_in_pragmatab(G, SName);
-
- Other ->
- Other
- end;
- _ ->
- %% Last resort: seek in pragma table
- lookup_type_in_pragmatab(G, SName)
- end;
- Other ->
- Other
- end;
- Other ->
- Other
- end.
-
-
-lookup_member_type_in_tktab(S, ScopedName, MName) ->
- case ets:match_object(S, {'_',member,{MName,'_'},nil}) of
- [] ->
- error;
- [{_FullScopedName,member,{MName,TKInfo},nil}]->
- fetchType( TKInfo );
- List ->
- lookup_member_type_in_tktab(List,ScopedName)
- end.
-
-lookup_member_type_in_tktab([], _ScopedName) ->
- error;
-lookup_member_type_in_tktab([{FullScopedName,_,{_,TKInfo},_}|Rest],ScopedName) ->
- case lists:reverse(string:tokens(ic_util:to_undersc(FullScopedName),"_")) of
- ScopedName ->
- fetchType(TKInfo);
- _ ->
- lookup_member_type_in_tktab(Rest,ScopedName)
- end.
-
-
-lookup_type_in_pragmatab(G, SName) ->
- S = ic_genobj:pragmatab(G),
-
- %% Look locally first
- case ets:match(S,{file_data_local,'_','_','$2','_','_',SName,'_','_'}) of
- [] ->
- %% No match, seek included
- case ets:match(S,{file_data_included,'_','_','$2','_','_',SName,'_','_'}) of
-
- [] ->
- error;
- [[Type]] ->
- io:format("1 Found(~p) : ~p~n",[SName,Type]),
- Type
- end;
-
- [[Type]] ->
- io:format("2 Found(~p) : ~p~n",[SName,Type]),
- Type
- end.
-
-
-
-
-isString(G, N, T) when element(1, T) == scoped_id ->
- case ic_symtab:get_full_scoped_name(G, N, T) of
- {_FullScopedName, _, {'tk_string',_}, _} ->
- true;
- _ ->
- false
- end;
-isString(_G, _N, T) when is_record(T, string) ->
- true;
-isString(_G, _N, _Other) ->
- false.
-
-
-isWString(G, N, T) when element(1, T) == scoped_id -> %% WSTRING
- case ic_symtab:get_full_scoped_name(G, N, T) of
- {_FullScopedName, _, {'tk_wstring',_}, _} ->
- true;
- _ ->
- false
- end;
-isWString(_G, _N, T) when is_record(T, wstring) ->
- true;
-isWString(_G, _N, _Other) ->
- false.
-
-
-isArray(G, N, T) when element(1, T) == scoped_id ->
- case ic_symtab:get_full_scoped_name(G, N, T) of
- {_FullScopedName, _, {'tk_array', _, _}, _} ->
- true;
- _ ->
- false
- end;
-isArray(_G, _N, T) when is_record(T, array) ->
- true;
-isArray(_G, _N, _Other) ->
- false.
-
-
-isSequence(G, N, T) when element(1, T) == scoped_id ->
- case ic_symtab:get_full_scoped_name(G, N, T) of
- {_FullScopedName, _, {'tk_sequence', _, _}, _} ->
- true;
- _ ->
- false
- end;
-isSequence(_G, _N, T) when is_record(T, sequence) ->
- true;
-isSequence(_G, _N, _Other) ->
- false.
-
-
-isStruct(G, N, T) when element(1, T) == scoped_id ->
- case ic_symtab:get_full_scoped_name(G, N, T) of
- {_FullScopedName, _, {'tk_struct', _, _, _}, _} ->
- true;
- _ ->
- false
- end;
-isStruct(_G, _N, T) when is_record(T, struct) ->
- true;
-isStruct(_G, _N, _Other) ->
- false.
-
-
-isUnion(G, N, T) when element(1, T) == scoped_id ->
- case ic_symtab:get_full_scoped_name(G, N, T) of
- {_FullScopedName, _, {'tk_union', _, _, _,_,_}, _} ->
- true;
- _Other ->
- false
- end;
-isUnion(_G, _N, T) when is_record(T, union) ->
- true;
-isUnion(_G, _N, _Other) ->
- false.
-
-
-
-isEnum(G, N, T) when element(1, T) == scoped_id ->
- case ic_symtab:get_full_scoped_name(G, N, T) of
- {_FullScopedName, _, {'tk_enum',_,_,_}, _} ->
- true;
- _Other ->
- false
- end;
-isEnum(_G, _N, T) when is_record(T, enum) ->
- true;
-isEnum(_G, _N, _Other) ->
- false.
-
-
-
-isBoolean(G, N, T) when element(1, T) == scoped_id ->
- {_, _, TK, _} =
- ic_symtab:get_full_scoped_name(G, N, T),
- case fetchType(TK) of
- 'boolean' ->
- true;
- _ ->
- false
- end;
-isBoolean(_, _, {'tk_boolean',_}) ->
- true;
-isBoolean(_, _, {'boolean',_}) ->
- true;
-isBoolean(_, _, _) ->
- false.
-
-
-%%% Just used for C
-
-isBasicTypeOrEterm(G, N, S) ->
- case isBasicType(G, N, S) of
- true ->
- true;
- false ->
- isEterm(G, N, S)
- end.
-
-isEterm(G, N, S) when element(1, S) == scoped_id ->
- {FullScopedName, _, _TK, _} = ic_symtab:get_full_scoped_name(G, N, S),
- case ic_code:get_basetype(G, ic_util:to_undersc(FullScopedName)) of
- "erlang_term" ->
- true;
- "ETERM*" ->
- true;
- _X ->
- false
- end;
-isEterm(_G, _Ni, _X) ->
- false.
-
-isBasicType(_G, _N, {scoped_id,_,_,["term","erlang"]}) ->
- false;
-isBasicType(G, N, S) when element(1, S) == scoped_id ->
- {_, _, TK, _} = ic_symtab:get_full_scoped_name(G, N, S),
- isBasicType(fetchType(TK));
-isBasicType(_G, _N, {string, _} ) ->
- false;
-isBasicType(_G, _N, {wstring, _} ) -> %% WSTRING
- false;
-isBasicType(_G, _N, {unsigned, {long, _}} ) ->
- true;
-isBasicType(_G, _N, {unsigned, {short, _}} ) ->
- true;
-isBasicType(_G, _N, {Type, _} ) ->
- isBasicType(Type);
-isBasicType(_G, _N, _X) ->
- false.
-
-
-isBasicType( G, Name ) ->
- isBasicType( name2type( G, Name ) ).
-
-
-isBasicType( Type ) ->
- lists:member(Type,
- [tk_short,short,
- tk_long,long,
- tk_longlong,longlong, %% LLONG
- tk_ushort,ushort,
- tk_ulong,ulong,
- tk_ulonglong,ulonglong, %% ULLONG
- tk_float,float,
- tk_double,double,
- tk_boolean,boolean,
- tk_char,char,
- tk_wchar,wchar, %% WCHAR
- tk_octet,octet,
- tk_any,any]). %% Fix for any
-
-
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-check(G, _S, N, X) when is_record(X, preproc) ->
- handle_preproc(G, N, X#preproc.cat, X),
- X;
-
-check(G, S, N, X) when is_record(X, op) ->
- ?STDDBG,
- TK = tk_base(G, S, N, ic_forms:get_type(X)),
- tktab_add(G, S, N, X),
- N2 = [ic_forms:get_id2(X) | N],
- Ps = lists:map(fun(P) ->
- tktab_add(G, S, N2, P),
- P#param{tk=tk_base(G, S, N, ic_forms:get_type(P))} end,
- X#op.params),
- %% Check for exception defs.
- Raises = lists:map(fun(E) -> name_lookup(G, S, N, E) end,
- X#op.raises),
- case ic_forms:is_oneway(X) of
- true ->
- if TK /= tk_void ->
- ic_error:error(G, {bad_oneway_type, X, TK});
- true -> ok
- end,
- case ic:filter_params([inout, out], X#op.params) of
- [] -> ok; % No out parameters!
- _ ->
- ic_error:error(G, {oneway_outparams, X})
- end,
- case X#op.raises of
- [] -> ok;
- _ ->
- ic_error:error(G, {oneway_raises, X})
- end;
- false ->
- ok
- end,
- X#op{params=Ps, tk=TK, raises=Raises};
-
-check(G, S, N, X) when is_record(X, interface) ->
- ?STDDBG,
- N2 = [ic_forms:get_id2(X) | N],
- TK = {tk_objref, ictk:get_IR_ID(G, N, X), ic_forms:get_id2(X)},
- Inherit = inherit_resolve(G, S, N, X#interface.inherit, []),
- tktab_add(G, S, N, X, TK, Inherit),
- CheckedBody = check_list(G, S, N2, ic_forms:get_body(X)),
- InhBody = calc_inherit_body(G, N2, CheckedBody, Inherit, []),
- X2 = X#interface{inherit=Inherit, tk=TK, body=CheckedBody,
- inherit_body=InhBody},
- ic_symtab:store(G, N, X2),
- X2;
-
-check(G, S, N, X) when is_record(X, forward) ->
- ?STDDBG,
- tktab_add(G, S, N, X, {tk_objref, ictk:get_IR_ID(G, N, X), ic_forms:get_id2(X)}),
- X;
-
-check(G, S, N, #constr_forward{tk = tk_struct} = X) ->
- ?STDDBG,
- ID = ic_forms:get_id2(X),
- Module = list_to_atom(string:join(lists:reverse([ID|N]), "_")),
- tktab_add(G, S, N, X, {tk_struct, ictk:get_IR_ID(G, N, X), ID, Module}),
- X;
-check(G, S, N, #constr_forward{tk = tk_union} = X) ->
- ?STDDBG,
- ID = ic_forms:get_id2(X),
- Module = list_to_atom(string:join(lists:reverse([ID|N]), "_")),
- tktab_add(G, S, N, X, {tk_union, ictk:get_IR_ID(G, N, X), ID, [], [], Module}),
- X;
-
-check(G, S, N, X) when is_record(X, const) ->
- ?STDDBG,
- case tk_base(G, S, N, ic_forms:get_type(X)) of
- Err when element(1, Err) == error -> X;
- TK ->
- check_const_tk(G, S, N, X, TK),
- case iceval:eval_const(G, S, N, TK, X#const.val) of
- Err when element(1, Err) == error -> X;
- {ok, NewTK, Val} ->
- V = iceval:get_val(Val),
- tktab_add(G, S, N, X, NewTK, V),
- X#const{val=V, tk=NewTK};
- Val ->
- V = iceval:get_val(Val),
- tktab_add(G, S, N, X, TK, V),
- X#const{val=V, tk=TK}
- end
- end;
-
-check(G, S, N, X) when is_record(X, except) ->
- ?STDDBG,
- TK = tk(G, S, N, X),
- X#except{tk=TK};
-
-check(G, S, N, X) when is_record(X, struct) ->
- ?STDDBG,
- TK = tk(G, S, N, X),
- X#struct{tk=TK};
-
-check(G, S, N, X) when is_record(X, enum) ->
- ?STDDBG,
- TK = tk(G, S, N, X),
- X#enum{tk=TK};
-
-check(G, S, N, X) when is_record(X, union) ->
- ?STDDBG,
- TK = tk(G, S, N, X),
- X#union{tk=TK};
-
-check(G, S, N, X) when is_record(X, attr) ->
- ?STDDBG,
- TK = tk_base(G, S, N, ic_forms:get_type(X)),
- XX = #id_of{type=X},
- lists:foreach(fun(Id) -> tktab_add(G, S, N, XX#id_of{id=Id}) end,
- ic_forms:get_idlist(X)),
- X#attr{tk=TK};
-
-check(G, S, N, X) when is_record(X, module) ->
- ?STDDBG,
- tktab_add(G, S, N, X),
- X#module{body=check_list(G, S, [ic_forms:get_id2(X) | N], ic_forms:get_body(X))};
-
-check(G, S, N, X) when is_record(X, typedef) ->
- ?STDDBG,
- TKbase = tk(G, S, N, X),
- X#typedef{tk=TKbase};
-
-check(_G, _S, _N, X) ->
- ?DBG(" dbg: ~p~n", [element(1,X)]),
- X.
-
-handle_preproc(G, _N, line_nr, X) -> ic_genobj:set_idlfile(G, ic_forms:get_id2(X));
-handle_preproc(_G, _N, _C, _X) -> ok.
-
-
-%%--------------------------------------------------------------------
-%%
-%% TK calculation
-%%
-%%--------------------------------------------------------------------
-
-tk(G, S, N, X) when is_record(X, union) ->
- N2 = [ic_forms:get_id2(X) | N],
- DisrcTK = tk(G, S, N, ic_forms:get_type(X)),
- case check_switch_tk(G, S, N, X, DisrcTK) of
- true ->
- do_special_enum(G, S, N2, ic_forms:get_type(X)),
- BodyTK = lists:reverse(
- tk_caselist(G, S, N2, DisrcTK, ic_forms:get_body(X))),
- tktab_add(G, S, N, X,
- {tk_union, ictk:get_IR_ID(G, N, X), ic_forms:get_id2(X),
- DisrcTK, default_count(ic_forms:get_body(X)), BodyTK});
- false ->
- tk_void
- end;
-
-tk(G, S, N, X) when is_record(X, enum) ->
- N2 = [ic_forms:get_id2(X) | N],
- tktab_add(G, S, N, X,
- {tk_enum, ictk:get_IR_ID(G, N, X), ic_forms:get_id2(X),
- enum_body(G, S, N2, ic_forms:get_body(X))});
-
-
-%% Note that the TK returned from this function is the base TK. It
-%% must be modified for each of the identifiers in the idlist (for
-%% array reasons).
-tk(G, S, N, X) when is_record(X, typedef) ->
- case X of
- %% Special case only for term and java backend !
- {typedef,{any,_},[{'<identifier>',_,"term"}],undefined} ->
- case ic_options:get_opt(G, be) of
- java ->
- tktab_add(G, S, N, X, tk_term),
- tk_term;
- _ ->
- TK = tk(G, S, N, ic_forms:get_body(X)),
- lists:foreach(fun(Id) ->
- tktab_add(G, S, N, #id_of{id=Id, type=X},
- maybe_array(G, S, N, Id, TK))
- end,
- X#typedef.id),
- TK
- end;
- _ ->
- TK = tk(G, S, N, ic_forms:get_body(X)),
- lists:foreach(fun(Id) ->
- tktab_add(G, S, N, #id_of{id=Id, type=X},
- maybe_array(G, S, N, Id, TK))
- end,
- X#typedef.id),
- TK
- end;
-
-tk(G, S, N, X) when is_record(X, struct) ->
- N2 = [ic_forms:get_id2(X) | N],
- tktab_add(G, S, N, X, {tk_struct, ictk:get_IR_ID(G, N, X), ic_forms:get_id2(X),
- tk_memberlist(G, S, N2, ic_forms:get_body(X))});
-
-tk(G, S, N, X) when is_record(X, except) ->
- N2 = [ic_forms:get_id2(X) | N],
- tktab_add(G, S, N, X, {tk_except, ictk:get_IR_ID(G, N, X), ic_forms:get_id2(X),
- tk_memberlist(G, S, N2, ic_forms:get_body(X))});
-
-tk(G, S, N, X) -> tk_base(G, S, N, X).
-
-
-tk_base(G, S, N, X) when is_record(X, sequence) ->
- {tk_sequence, tk(G, S, N, X#sequence.type),
- len_eval(G, S, N, X#sequence.length)};
-
-tk_base(G, S, N, X) when is_record(X, string) ->
- {tk_string, len_eval(G, S, N, X#string.length)};
-
-tk_base(G, S, N, X) when is_record(X, wstring) -> %% WSTRING
- {tk_wstring, len_eval(G, S, N, X#wstring.length)};
-
-%% Fixed constants can be declared as:
-%% (1) const fixed pi = 3.14D; or
-%% (2) typedef fixed<3,2> f32;
-%% const f32 pi = 3.14D;
-tk_base(G, S, N, X) when is_record(X, fixed) ->
- %% Case 2
- {tk_fixed, len_eval(G, S, N, X#fixed.digits), len_eval(G, S, N, X#fixed.scale)};
-tk_base(_G, _S, _N, {fixed, _}) ->
- %% Case 1
- tk_fixed;
-
-
-%% Special case, here CORBA::TypeCode is built in
-%% ONLY when erl_corba is the backend of choice
-tk_base(G, S, N, {scoped_id,V1,V2,["TypeCode","CORBA"]}) ->
- case ic_options:get_opt(G, be) of
- false ->
- tk_TypeCode;
- erl_corba ->
- tk_TypeCode;
- erl_template ->
- tk_TypeCode;
- _ ->
- case scoped_lookup(G, S, N, {scoped_id,V1,V2,["TypeCode","CORBA"]}) of
- T when element(1, T) == error -> T;
- T when is_tuple(T) -> element(3, T)
- end
- end;
-
-tk_base(G, S, N, X) when element(1, X) == scoped_id ->
- case scoped_lookup(G, S, N, X) of
- T when element(1, T) == error -> T;
- T when is_tuple(T) -> element(3, T)
- end;
-tk_base(_G, _S, _N, {long, _}) -> tk_long;
-tk_base(_G, _S, _N, {'long long', _}) -> tk_longlong; %% LLONG
-tk_base(_G, _S, _N, {short, _}) -> tk_short;
-tk_base(_G, _S, _N, {'unsigned', {short, _}}) -> tk_ushort;
-tk_base(_G, _S, _N, {'unsigned', {long, _}}) -> tk_ulong;
-tk_base(_G, _S, _N, {'unsigned', {'long long', _}})-> tk_ulonglong; %% ULLONG
-tk_base(_G, _S, _N, {float, _}) -> tk_float;
-tk_base(_G, _S, _N, {double, _}) -> tk_double;
-tk_base(_G, _S, _N, {boolean, _}) -> tk_boolean;
-tk_base(_G, _S, _N, {char, _}) -> tk_char;
-tk_base(_G, _S, _N, {wchar, _}) -> tk_wchar; %% WCHAR
-tk_base(_G, _S, _N, {octet, _}) -> tk_octet;
-tk_base(_G, _S, _N, {null, _}) -> tk_null;
-tk_base(_G, _S, _N, {void, _}) -> tk_void;
-tk_base(_G, _S, _N, {any, _}) -> tk_any;
-tk_base(_G, _S, _N, {'Object', _}) -> {tk_objref, "", "Object"}.
-
-
-%%--------------------------------------------------------------------
-%%
-%% Special handling of idlists. Note that the recursion case is given
-%% as accumulator to foldr. Idlists are those lists of identifiers
-%% that share the same definition, i.e. multiple cases, multiple type
-%% declarations, multiple member names.
-%%
-tk_memberlist(G, S, N, [X | Xs]) ->
- BaseTK = tk(G, S, N, ic_forms:get_type(X)),
-
- XX = #id_of{type=X},
- lists:foldr(fun(Id, Acc) ->
- [tk_member(G, S, N, XX#id_of{id=Id}, BaseTK) | Acc] end,
- tk_memberlist(G, S, N, Xs),
- ic_forms:get_idlist(X));
-tk_memberlist(_G, _S, _N, []) -> [].
-
-%% same as above but for case dcls
-tk_caselist(G, S, N, DiscrTK, Xs) ->
- lists:foldl(fun(Case, Acc) ->
- BaseTK = tk(G, S, N, ic_forms:get_type(Case)),
- %% tktab_add for the uniqueness check of the declarator
- tktab_add(G, S, N, Case),
- lists:foldl(fun(Id, Acc2) ->
- case tk_case(G, S, N, Case, BaseTK,
- DiscrTK, Id) of
- Err when element(1, Err)==error ->
- Acc2;
- TK ->
- unique_add_case_label(G, S, N, Id,
- TK, Acc2)
- end
- end,
- Acc,
- ic_forms:get_idlist(Case))
- end,
- [],
- Xs).
-
-
-%% Handling of the things that can be in an idlist or caselist
-tk_member(G, S, N, X, BaseTK) ->
- tktab_add(G, S, N, X,
- {ic_forms:get_id2(X), maybe_array(G, S, N, X#id_of.id, BaseTK)}).
-
-
-get_case_id_and_check(G, _S, _N, _X, ScopedId) ->
- case ic_symtab:scoped_id_is_global(ScopedId) of
- true -> ic_error:error(G, {bad_scope_enum_case, ScopedId});
- false -> ok
- end,
- case ic_symtab:scoped_id_strip(ScopedId) of
- [Id] -> Id;
- _List ->
- ic_error:error(G, {bad_scope_enum_case, ScopedId}),
- ""
- end.
-
-
-tk_case(G, S, N, X, BaseTK, DiscrTK, Id) ->
- case case_eval(G, S, N, DiscrTK, Id) of
- Err when element(1, Err) == error -> Err;
- Val ->
- case iceval:check_tk(G, DiscrTK, Val) of
- true ->
- {iceval:get_val(Val), ic_forms:get_id2(X),
- maybe_array(G, S, N, X#case_dcl.id, BaseTK)};
- false ->
- ic_error:error(G, {bad_case_type, DiscrTK, X,
- iceval:get_val(Val)})
- end
- end.
-
-tktab_add(G, S, N, X) ->
- tktab_add_id(G, S, N, X, ic_forms:get_id2(X), nil, nil).
-tktab_add(G, S, N, X, TK) ->
- tktab_add_id(G, S, N, X, ic_forms:get_id2(X), TK, nil).
-tktab_add(G, S, N, X, TK, Aux) ->
- tktab_add_id(G, S, N, X, ic_forms:get_id2(X), TK, Aux).
-
-
-tktab_add_id(G, S, N, X, Id, TK, Aux) when is_record(X,enumerator) ->
-
- %% Check if the "scl" flag is set to true
- %% if so, allow old semantics ( errornous )
- %% Warning, this is for compatibility reasons only.
- Name = case ic_options:get_opt(G, scl) of
- true ->
- [Id | N];
- false ->
- [Id | tl(N)]
- end,
-
- UName = mk_uppercase(Name),
- case ets:lookup(S, Name) of
- [_] -> ic_error:error(G, {multiply_defined, X});
- [] ->
- case ets:lookup(S, UName) of
- [] -> ok;
- [_] -> ic_error:error(G, {illegal_spelling, X})
- end
- end,
- ets:insert(S, {Name, element(1, get_beef(X)), TK, Aux}),
- if UName =/= Name -> ets:insert(S, {UName, spellcheck});
- true -> true end,
- TK;
-%%
-%% Fixes the multiple file module definition check
-%% but ONLY for Corba backend
-%%
-tktab_add_id(G, S, N, X, Id, TK, Aux) when is_record(X,module) ->
- case ic_options:get_opt(G, be) of
- erl_template ->
- Name = [Id | N],
- UName = mk_uppercase(Name),
- ets:insert(S, {Name, element(1, get_beef(X)), TK, Aux}),
- if UName =/= Name -> ets:insert(S, {UName, spellcheck});
- true -> true end,
- TK;
- erl_corba ->
- Name = [Id | N],
- UName = mk_uppercase(Name),
- ets:insert(S, {Name, element(1, get_beef(X)), TK, Aux}),
- if UName =/= Name -> ets:insert(S, {UName, spellcheck});
- true -> true end,
- TK;
- false -> %% default == erl_corba
- Name = [Id | N],
- UName = mk_uppercase(Name),
- ets:insert(S, {Name, element(1, get_beef(X)), TK, Aux}),
- if UName =/= Name -> ets:insert(S, {UName, spellcheck});
- true -> true end,
- TK;
- java ->
- Name = [Id | N],
- UName = mk_uppercase(Name),
- ets:insert(S, {Name, element(1, get_beef(X)), TK, Aux}),
- if UName =/= Name -> ets:insert(S, {UName, spellcheck});
- true -> true end,
- TK;
- erl_genserv ->
- Name = [Id | N],
- UName = mk_uppercase(Name),
- ets:insert(S, {Name, element(1, get_beef(X)), TK, Aux}),
- if UName =/= Name -> ets:insert(S, {UName, spellcheck});
- true -> true end,
- TK;
- erl_plain ->
- Name = [Id | N],
- UName = mk_uppercase(Name),
- ets:insert(S, {Name, element(1, get_beef(X)), TK, Aux}),
- if UName =/= Name -> ets:insert(S, {UName, spellcheck});
- true -> true end,
- TK;
- _Be ->
- Name = [Id | N],
- UName = mk_uppercase(Name),
- case ets:lookup(S, Name) of
- [_] -> ic_error:error(G, {multiply_defined, X});
- [] ->
- case ets:lookup(S, UName) of
- [] -> ok;
- [_] -> ic_error:error(G, {illegal_spelling, X})
- end
- end,
- ets:insert(S, {Name, element(1, get_beef(X)), TK, Aux}),
- if UName =/= Name -> ets:insert(S, {UName, spellcheck});
- true -> true end,
- TK
- end;
-tktab_add_id(G, S, N, X, Id, TK, Aux) ->
- Name = [Id | N],
- UName = mk_uppercase(Name),
- case ets:lookup(S, Name) of
- [{_, forward, _, _}] when is_record(X, interface) ->
- ok;
- [{_, constr_forward, _, _}] when is_record(X, union) orelse
- is_record(X, struct) ->
- ok;
- [XX] when is_record(X, forward) andalso element(2, XX)==interface ->
- ok;
- [_] ->
- ic_error:error(G, {multiply_defined, X});
- [] ->
- case ets:lookup(S, UName) of
- [] -> ok;
- [_] -> ic_error:error(G, {illegal_spelling, X})
- end
- end,
- ets:insert(S, {Name, element(1, get_beef(X)), TK, Aux}),
- if UName =/= Name -> ets:insert(S, {UName, spellcheck});
- true -> true end,
- TK.
-
-
-
-
-%%--------------------------------------------------------------------
-%% enum_body
-%%
-%% Special because ids are treated different than usual.
-%%
-enum_body(G, S, N, [Enum | EnumList]) ->
- tktab_add(G, S, N, Enum), %%%, enum_val, Enum),
- %% tktab_add(G, S, N, X, TK, V),
- [ic_forms:get_id2(Enum) | enum_body(G, S, N, EnumList)];
-enum_body(_G, _S, _N, []) -> [].
-
-
-%%--------------------------------------------------------------------
-%% mk_array
-%%
-%% Multi dimensional arrays are written as nested tk_array
-%%
-mk_array(G, S, N, [Sz | Szs], TK) ->
- case iceval:eval_const(G, S, N, positive_int, Sz) of
- Err when element(1, Err) == error -> TK;
- Val ->
- {tk_array, mk_array(G, S, N, Szs, TK), iceval:get_val(Val)}
- end;
-mk_array(_G, _S, _N, [], TK) -> TK.
-
-
-%%--------------------------------------------------------------------
-%% len_eval
-%%
-%% Evaluates the length, which in case it has been left out is a
-%% plain 0 (zero)
-%%
-len_eval(_G, _S, _N, 0) -> 0;
-len_eval(G, S, N, X) -> %%iceval:eval_const(G, S, N, positive_int, X).
- case iceval:eval_const(G, S, N, positive_int, X) of
- Err when element(1, Err) == error -> 0;
- Val -> iceval:get_val(Val)
- end.
-
-
-%%--------------------------------------------------------------------
-%% case_eval
-%%
-%% Evaluates the case label.
-%%
-
-case_eval(G, S, N, DiscrTK, X) when element(1, DiscrTK) == tk_enum,
- element(1, X) == scoped_id ->
- {tk_enum, _, _, Cases} = DiscrTK,
- Id = get_case_id_and_check(G, S, N, X, X),
- %%io:format("Matching: ~p to ~p~n", [Id, Cases]),
- case lists:member(Id, Cases) of
- true ->
- {enum_id, Id};
- false ->
- iceval:mk_val(scoped_lookup(G, S, N, X)) % Will generate error
- end;
-
-case_eval(G, S, N, DiscrTK, X) ->
- iceval:eval_e(G, S, N, DiscrTK, X).
-
-
-%% The enum declarator is in the union scope.
-do_special_enum(G, S, N, X) when is_record(X, enum) ->
- tktab_add(G, S, N, #id_of{id=X#enum.id, type=X});
-do_special_enum(_G, _S, _N, _X) ->
- ok.
-
-
-unique_add_case_label(G, _S, _N, Id, TK, TKList) ->
-%%%io:format("check_case_labels: TK:~p TKLIST:~p ~n", [TK, TKList]),
- if element(1, TK) == error ->
- TKList;
- true ->
- case lists:keysearch(element(1, TK), 1, TKList) of
- {value, _} ->
- ic_error:error(G, {multiple_cases, Id}),
- TKList;
- false ->
- [TK | TKList]
- end
- end.
-
-
-%%--------------------------------------------------------------------
-%% default_count
-%%
-%% Returns the position of the default case.
-%%
-%% Modified for OTP-2007
-%%
-default_count(Xs) ->
- default_count2(Xs, 0).
-
-default_count2([X | Xs], N) -> default_count3(X#case_dcl.label, Xs, N);
-default_count2([], _) -> -1.
-
-default_count3([{default, _} | _Ys], _Xs, N) -> N;
-default_count3([_ | Ys], Xs, N) -> default_count3(Ys, Xs, N+1);
-default_count3([], Xs, N) -> default_count2(Xs, N).
-
-
-
-
-%%
-%% Type checks.
-%%
-%% Check constant type references (only for the scoped id case, others
-%% are caught by the BNF)
-%%
-check_const_tk(_G, _S, _N, _X, tk_long) -> true;
-check_const_tk(_G, _S, _N, _X, tk_longlong) -> true; %% LLONG
-check_const_tk(_G, _S, _N, _X, tk_short) -> true;
-check_const_tk(_G, _S, _N, _X, tk_ushort) -> true;
-check_const_tk(_G, _S, _N, _X, tk_ulong) -> true;
-check_const_tk(_G, _S, _N, _X, tk_ulonglong) -> true; %% ULLONG
-check_const_tk(_G, _S, _N, _X, tk_float) -> true;
-check_const_tk(_G, _S, _N, _X, tk_double) -> true;
-check_const_tk(_G, _S, _N, _X, tk_boolean) -> true;
-check_const_tk(_G, _S, _N, _X, tk_char) -> true;
-check_const_tk(_G, _S, _N, _X, tk_wchar) -> true; %% WCHAR
-check_const_tk(_G, _S, _N, _X, tk_octet) -> true;
-check_const_tk(_G, _S, _N, _X, {tk_string, _Len}) -> true;
-check_const_tk(_G, _S, _N, _X, {tk_wstring, _Len}) -> true; %% WSTRING
-check_const_tk(_G, _S, _N, _X, tk_fixed) -> true;
-check_const_tk(_G, _S, _N, _X, {tk_fixed, _Digits, _Scale}) -> true;
-check_const_tk(G, _S, _N, X, TK) -> ic_error:error(G, {illegal_const_t, X, TK}).
-
-
-check_switch_tk(_G, _S, _N, _X, tk_long) -> true;
-check_switch_tk(_G, _S, _N, _X, tk_longlong) -> true; %% LLONG
-check_switch_tk(_G, _S, _N, _X, tk_short) -> true;
-check_switch_tk(_G, _S, _N, _X, tk_ushort) -> true;
-check_switch_tk(_G, _S, _N, _X, tk_ulong) -> true;
-check_switch_tk(_G, _S, _N, _X, tk_ulonglong) -> true; %% ULLONG
-check_switch_tk(_G, _S, _N, _X, tk_boolean) -> true;
-check_switch_tk(_G, _S, _N, _X, tk_char) -> true;
-check_switch_tk(_G, _S, _N, _X, tk_wchar) -> true; %% WCHAR
-check_switch_tk(_G, _S, _N, _X, TK) when element(1, TK) == tk_enum -> true;
-check_switch_tk(G, _S, _N, X, TK) -> ic_error:error(G, {illegal_switch_t, X, TK}),
- false.
-
-
-
-%% Lookup a name
-name_lookup(G, S, N, X) ->
- case scoped_lookup(G, S, N, X) of
- T when is_tuple(T) -> element(1, T)
- end.
-
-
-lookup(G, S, N, X, Id) ->
- N2 = Id ++ N,
- ?DBG(" Trying ~p ...~n", [N2]),
- case ets:lookup(S, N2) of
- [] ->
- case look_for_interface(G, S, [hd(N2)], tl(N2)) of
-
- %% First attempt: filtering inherited members !
- [{_, member, _, _}] ->
- case look_for_interface(G, S, [hd(N)], tl(N2)) of
- [T] ->
- ?DBG(" -- found ~p~n", [T]),
- T;
- _ ->
- lookup(G, S, tl(N), X, Id)
- end;
- %%
-
- [T] ->
- ?DBG(" -- found ~p~n", [T]),
- T;
-
- _ ->
- if N == [] ->
- ic_error:error(G, {tk_not_found, X});
- true ->
- lookup(G, S, tl(N), X, Id)
- end
-
- end;
-
- %% Second attempt: filtering members !
- [{_, member, _, _}] ->
- case look_for_interface(G, S, [hd(N2)], tl(N2)) of
- [T] ->
- ?DBG(" -- found ~p~n", [T]),
- T;
- _ ->
- if N == [] ->
- ic_error:error(G, {tk_not_found, X});
- true ->
- lookup(G, S, tl(N), X, Id)
- end
- end;
- %%
- [T] ->
- ?DBG(" -- found ~p~n", [T]),
- T
- end.
-
-
-look_for_interface(_G, _S, _Hd, []) ->
- false;
-look_for_interface(G, S, Hd, Tl) ->
- case ets:lookup(S, Tl) of
- [{_, interface, _TK, Inh}] ->
- case look_in_inherit(G, S, Hd, Inh) of
- %% gather_inherit(G, S, Inh, [])) of
- [X] when is_tuple(X) ->
- [X];
- _ ->
- look_for_interface(G, S, Hd ++ [hd(Tl)], tl(Tl))
- end;
- _ ->
- look_for_interface(G, S, Hd ++ [hd(Tl)], tl(Tl))
- end.
-
-look_in_inherit(G, S, Id, [I | Is]) ->
- case ets:lookup(S, Id ++ I) of
- [X] when is_tuple(X) ->
- [X];
- [] ->
- look_in_inherit(G, S, Id, Is)
- end;
-look_in_inherit(_G, _S, _Id, []) ->
- false.
-
-
-%% L is a list of names
-mk_uppercase(L) ->
- lists:map(fun(Z) -> lists:map(fun(X) when X>=$a, X=<$z -> X-$a+$A;
- (X) -> X end, Z) end, L).
-
-
-%%--------------------------------------------------------------------
-%%
-%% Inheritance stuff
-%%
-%%
-%%--------------------------------------------------------------------
-
-%% InhBody is an accumulating parameter
-
-calc_inherit_body(G, N, OrigBody, [X|Xs], InhBody) ->
- case ic_symtab:retrieve(G, X) of
- Intf when is_record(Intf, interface) ->
- Body = filter_body(G, X, ic_forms:get_body(Intf), N, OrigBody, InhBody),
- calc_inherit_body(G, N, OrigBody, Xs, [{X, Body} | InhBody]);
- XXX ->
- io:format("Oops, not found ~p~n", [XXX]),
- calc_inherit_body(G, N, OrigBody, Xs, InhBody)
- end;
-calc_inherit_body(_G, _N, _OrigBody, [], InhBody) -> lists:reverse(InhBody).
-
-
-filter_body(G, XPath, [X | Xs], OrigPath, OrigBody, InhBody) ->
- case complex_body_member(G, XPath, X, OrigPath, OrigBody, InhBody) of
- true ->
- %%io:format("NOT adding ~p~n", [ic_forms:get_id2(X)]),
- filter_body(G, XPath, Xs, OrigPath, OrigBody, InhBody);
- {false, NewX} -> % For those with idlist
- %%io:format("Adding from idlist~n", []),
- [NewX | filter_body(G, XPath, Xs, OrigPath, OrigBody, InhBody)];
- false ->
- %%io:format("Adding: ~p~n", [ic_forms:get_id2(X)]),
- [X | filter_body(G, XPath, Xs, OrigPath, OrigBody, InhBody)]
- end;
-filter_body(_G, _XPath, [], _OrigPath, _OrigBody, _InhBody) -> [].
-
-
-complex_body_member(G, XPath, X, OrigPath, OrigBody, InhBody) ->
- case has_idlist(X) of
- true ->
- idlist_member(G, XPath, X, OrigPath, OrigBody, InhBody);
- false ->
- straight_member(G, XPath, X, OrigPath, OrigBody, InhBody)
- end.
-
-
-idlist_member(G, XPath, X, OrigPath, OrigBody, InhBody) ->
- XX = #id_of{type=X},
- F = fun(Id) ->
- not(straight_member(G, XPath, XX#id_of{id=Id}, OrigPath,
- OrigBody, InhBody))
- end,
- case lists:filter(F, ic_forms:get_idlist(X)) of
- [] ->
- true;
- IdList ->
-%%% io:format("Idlist added: ~p~n",[IdList]),
- {false, replace_idlist(X, IdList)}
- end.
-
-
-straight_member(G, XPath, X, OrigPath, OrigBody, InhBody) ->
- %%io:format("straight member: ~p~n", [ic_forms:get_id2(X)]),
- case body_member(G, XPath, X, OrigPath, OrigBody) of
- true ->
- true;
- false ->
- inh_body_member(G, XPath, X, InhBody)
- end.
-
-
-inh_body_member(G, XPath, X, [{Name, Body} | InhBody]) ->
- case body_member(G, XPath, X, Name, Body) of
- true ->
- true;
- false ->
- inh_body_member(G, XPath, X, InhBody)
- end;
-inh_body_member(_G, _XPath, _X, []) -> false.
-
-
-body_member(G, XPath, X, YPath, [Y|Ys]) ->
- case has_idlist(Y) of
- true ->
- YY = #id_of{type=Y},
- case list_and(fun(Y2) ->
- not(is_equal(G, XPath, X, YPath,
- YY#id_of{id=Y2})) end,
- ic_forms:get_idlist(Y)) of
- true ->
- body_member(G, XPath, X, YPath, Ys);
- false ->
- true
- end;
- false ->
- case is_equal(G, XPath, X, YPath, Y) of
- false ->
- body_member(G, XPath, X, YPath, Ys);
- true ->
- true
- end
- end;
-body_member(_G, _XPath, _X, _YPath, []) -> false.
-
-
-is_equal(G, XPath, X, YPath, Y) ->
- case {ic_forms:get_id2(X), ic_forms:get_id2(Y)} of
- {ID, ID} ->
- collision(G, XPath, X, YPath, Y),
- true;
- _ ->
- false
- end.
-
-
-%% X is the new item, Y is the old one. So it is X that collides with
-%% Y and Y shadows X.
-collision(G, XPath, X, YPath, Y) ->
- I1 = get_beef(X),
- % I2 = get_beef(Y),
- if is_record(I1, op) -> %%, record(I2, op) ->
- ic_error:error(G, {inherit_name_collision,
- {YPath, Y}, {XPath, X}});
- is_record(I1, attr) -> %%, record(I2, attr) ->
- ic_error:error(G, {inherit_name_collision,
- {YPath, Y}, {XPath, X}});
- true ->
- ?ifopt(G, warn_name_shadow,
- ic_error:warn(G, {inherit_name_shadow,
- {YPath, Y}, {XPath, X}}))
- end.
-
-has_idlist(X) when is_record(X, typedef) -> true;
-has_idlist(X) when is_record(X, member) -> true;
-has_idlist(X) when is_record(X, case_dcl) -> true;
-has_idlist(X) when is_record(X, attr) -> true;
-has_idlist(_) -> false.
-
-replace_idlist(X, IdList) when is_record(X, typedef) -> X#typedef{id=IdList};
-replace_idlist(X, IdList) when is_record(X, attr) -> X#attr{id=IdList}.
-
-get_beef(X) when is_record(X, id_of) -> X#id_of.type;
-get_beef(X) -> X.
-
-
-%% And among all elements in list
-list_and(F, [X|Xs]) ->
- case F(X) of
- true -> list_and(F, Xs);
- false -> false
- end;
-list_and(_F, []) -> true.
-
-
-
-
-
-%%--------------------------------------------------------------------
-%%
-%% resolve_inherit shall return a list of resolved inheritances,
-%% that is all names replaced with their global names.
-%%
-
-inherit_resolve(G, S, N, [X|Rest], Out) ->
- case scoped_lookup(G, S, N, X) of
- {Name, _T, _TK, Inh} ->
- case lists:member(Name, Out) of
- true ->
- inherit_resolve(G, S, N, Rest, Out);
- false ->
- case unique_append(Inh, [Name|Out]) of
- error ->
- ic_error:error(G, {inherit_resolve, X, Name}),
- inherit_resolve(G, S, N, Rest, []);
- UA ->
- inherit_resolve(G, S, N, Rest, UA)
- end
- end;
- _ -> inherit_resolve(G, S, N, Rest, Out)
- end;
-inherit_resolve(_G, _S, _N, [], Out) -> lists:reverse(Out).
-
-unique_append([X|Xs], L) ->
- case lists:member(X, L) of
- true -> unique_append(Xs, L);
- false -> unique_append(Xs, [X|L])
- end;
-unique_append([], L) -> L;
-%% Error
-unique_append(_, _L) -> error.
-
-
-
-
-%%--------------------------------------------------------------------
-%%
-%% Utilities
-%%
-
-%% Must preserve order, therefore had to write my own (instead of lists:map)
-check_list(G, S, N, [X|Xs]) ->
- X1 = check(G, S, N, X),
- [X1 | check_list(G, S, N, Xs)];
-check_list(_G, _S, _N, []) -> [].
-
-
-
-filter( [] ) ->
- error;
-filter( [I | Is ] ) ->
- case I of
- { _, member, { _, TKINFO }, _ } ->
- fetchType( TKINFO );
-
- { _, struct, _, _ } ->
- struct;
-
- { _, typedef, TKINFO, _ } ->
- fetchType( TKINFO );
-
- { _, module, _, _ } ->
- module;
-
- { _, interface, _, _ } ->
- interface;
-
- { _, op, _, _ } ->
- op;
-
- { _,enum, _, _ } ->
- enum;
-
- { _, spellcheck } ->
- filter( Is );
-
- _ ->
- error
- end.
-
-
-fetchType( { tk_sequence, _, _ } ) ->
- sequence;
-fetchType( { tk_array, _, _ } ) ->
- array;
-fetchType( { tk_struct, _, _, _} ) ->
- struct;
-fetchType( { tk_string, _} ) ->
- string;
-fetchType( { tk_wstring, _} ) -> %% WSTRING
- wstring;
-fetchType( { tk_fixed, _, _} ) ->
- fixed;
-fetchType( tk_short ) ->
- short;
-fetchType( tk_long ) ->
- long;
-fetchType( tk_longlong ) -> %% LLONG
- longlong;
-fetchType( tk_ushort ) ->
- ushort;
-fetchType( tk_ulong ) ->
- ulong;
-fetchType( tk_ulonglong ) -> %% ULLONG
- ulonglong;
-fetchType( tk_float ) ->
- float;
-fetchType( tk_double ) ->
- double;
-fetchType( tk_boolean ) ->
- boolean;
-fetchType( tk_char ) ->
- char;
-fetchType( tk_wchar ) -> %% WCHAR
- wchar;
-fetchType( tk_octet ) ->
- octet;
-fetchType( { tk_enum, _, _, _ } ) ->
- enum;
-fetchType( { tk_union, _, _, _, _, _ } ) ->
- union;
-fetchType( tk_any ) ->
- any;
-fetchType( _ ) ->
- error.
-
-%% Z is a single name
-to_uppercase(Z) ->
- lists:map(fun(X) when X>=$a, X=<$z -> X-$a+$A;
- (X) -> X end, Z).
-
-
-%%------------------------------------------------------------
-%%
-%% Always fetchs TK of a record.
-%%
-%%------------------------------------------------------------
-fetchTk(G,N,X) ->
- case ic_forms:get_tk(X) of
- undefined ->
- searchTk(G,ictk:get_IR_ID(G, N, X));
- TK ->
- TK
- end.
-
-
-%%------------------------------------------------------------
-%%
-%% seek type code when not accessible by get_tk/1
-%%
-%%------------------------------------------------------------
-searchTk(G,IR_ID) ->
- S = ic_genobj:tktab(G),
- case catch searchTk(S,IR_ID,typedef) of
- {value,TK} ->
- TK;
- _ -> %% false / exit
- case catch searchTk(S,IR_ID,struct) of
- {value,TK} ->
- TK;
- _ -> %% false / exit
- case catch searchTk(S,IR_ID,union) of
- {value,TK} ->
- TK;
- _ ->
- undefined
- end
- end
- end.
-
-
-searchTk(S,IR_ID,Type) ->
- L = lists:flatten(ets:match(S,{'_',Type,'$1','_'})),
- case lists:keysearch(IR_ID,2,L) of
- {value,TK} ->
- {value,TK};
- false ->
- searchInsideTks(L,IR_ID)
- end.
-
-
-searchInsideTks([],_IR_ID) ->
- false;
-searchInsideTks([{tk_array,TK,_}|Xs],IR_ID) ->
- case searchIncludedTk(TK,IR_ID) of
- {value,TK} ->
- {value,TK};
- false ->
- searchInsideTks(Xs,IR_ID)
- end.
-
-
-searchIncludedTk({tk_array,TK,_},IR_ID) ->
- searchIncludedTk(TK,IR_ID);
-searchIncludedTk({tk_sequence,TK,_},IR_ID) ->
- searchIncludedTk(TK,IR_ID);
-searchIncludedTk(TK, _IR_ID) when is_atom(TK) ->
- false;
-searchIncludedTk(TK,IR_ID) ->
- case element(2,TK) == IR_ID of
- true ->
- {value,TK};
- false ->
- false
- end.
-
diff --git a/lib/ic/src/icunion.erl b/lib/ic/src/icunion.erl
deleted file mode 100644
index c39a5177e7..0000000000
--- a/lib/ic/src/icunion.erl
+++ /dev/null
@@ -1,1491 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(icunion).
-
--import(ic_codegen, [emit/2, emit/3, emit/4, emit_c_enc_rpt/4, emit_c_dec_rpt/4]).
--import(ic_cbe, [mk_c_type/3, mk_c_type/4]).
-
--include("icforms.hrl").
--include("ic.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([union_gen/4]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-union_gen(G, N, X, c) when is_record(X, union) ->
- emit_c_union(G, N, X);
-union_gen(_G, _N, _X, _L) ->
- ok.
-
-
-%% Emits the union
-emit_c_union(G, N, X) ->
- %%io:format("Rec = ~p\n",[X]),
- case ic_genobj:is_hrlfile_open(G) of
- true ->
-
- %% Sort Union Default = put it last in case list
- NewX = #union{ id = X#union.id,
- type = X#union.type,
- body = mvDefaultToTail(X#union.body),
- tk = X#union.tk },
-
- UnionScope = [ic_forms:get_id2(NewX) | N],
-
- case ic_pragma:is_local(G,UnionScope) of
-
- true ->
-
- HFd = ic_genobj:hrlfiled(G),
- emit_c_union_values(G, N, NewX, HFd),
- UnionName = ic_util:to_undersc(UnionScope),
-
- emit(HFd, "\n#ifndef __~s__\n",[ictype:to_uppercase(UnionName)]),
- emit(HFd, "#define __~s__\n",[ictype:to_uppercase(UnionName)]),
- ic_codegen:mcomment_light(HFd,
- [io_lib:format("Union definition: ~s",
- [UnionName])],
- c),
- emit(HFd, "typedef struct {\n"),
- emit(HFd, " ~s _d;\n", [get_c_union_discriminator(G, N, NewX)]),
- emit(HFd, " union {\n"),
- emit_c_union_values_decl(G, N, NewX, HFd),
- emit(HFd, " } _u;\n"),
- emit(HFd, "} ~s;\n\n", [UnionName]),
-
- emit(HFd, "int ~s~s(CORBA_Environment *oe_env, int*, int*);\n",
- [ic_util:mk_oe_name(G, "sizecalc_"), UnionName]),
- emit(HFd, "int ~s~s(CORBA_Environment *oe_env, ~s*);\n",
- [ic_util:mk_oe_name(G, "encode_"), UnionName, UnionName]),
- emit(HFd, "int ~s~s(CORBA_Environment *oe_env, char *, int*, ~s*);\n",
- [ic_util:mk_oe_name(G, "decode_"), UnionName, UnionName]),
- emit(HFd, "\n#endif\n\n"),
- create_c_union_file(G, N, NewX, UnionName);
-
- false -> %% Do not generate included types att all.
- ok
- end;
- false ->
- ok
- end.
-
-
-
-%% Loops over union members and creates members typedefs
-emit_c_union_values(G, N, X, Fd) ->
- emit_c_union_values_loop(G, N, X, Fd, X#union.body).
-
-emit_c_union_values_loop(G, N, X, Fd, [CU]) ->
- case CU of
- {case_dcl,_,Id,Type} ->
- case Id of
- {array, _AID, _SZ} -> % Check for arrays
- mk_array_file(G,N,X,Id,Type,Fd);
- _ -> % Elementary types or seq/struct
- ok
- end;
- _ ->
- error
- end;
-emit_c_union_values_loop(G, N, X, Fd, [CU |CUs]) ->
- case CU of
- {case_dcl,_,Id,Type} ->
- case Id of
- {array, _AID, _SZ} -> % Check for arrays
- mk_array_file(G,N,X,Id,Type,Fd);
- _ -> % Elementary types or seq/struct
- emit_c_union_values_loop(G, N, X, Fd, CUs)
- end;
- _ ->
- error
- end.
-
-
-%% Loops over union members and declares members inside union structure
-emit_c_union_values_decl(G, N, X, Fd) ->
- emit_c_union_values_decl_loop(G, N, X, Fd, X#union.body).
-
-emit_c_union_values_decl_loop(G, N, X, Fd, [CU]) ->
- case CU of
- {case_dcl,_,Id,Type} ->
- case Id of
- {array, _AID, _SZ} -> % Check for arrays
- mk_array_decl(G,N,X,Id,Type,Fd);
- _ -> % Elementary types or seq/struct
- mk_union_member_decl(G,N,X,Id,Type,Fd),
- ok
- end;
- _ ->
- error
- end;
-emit_c_union_values_decl_loop(G, N, X, Fd, [CU |CUs]) ->
- case CU of
- {case_dcl,_,Id,Type} ->
- case Id of
- {array, _AID, _SZ} -> % Check for arrays
- mk_array_decl(G,N,X,Id,Type,Fd),
- emit_c_union_values_decl_loop(G, N, X, Fd, CUs);
- _ -> % Elementary types or seq/struct
- mk_union_member_decl(G,N,X,Id,Type,Fd),
- emit_c_union_values_decl_loop(G, N, X, Fd, CUs)
- end;
- _ ->
- error
- end.
-
-
-%% Makes the declaration for the array in union
-mk_array_decl(G,N,X,Id,Type,Fd) ->
- emit(Fd, " ~s ~s;\n",
- [getCaseTypeStr(G,N,X,Id,Type),
- mk_array_name(Id)]).
-
-mk_array_name({array,Id,D}) ->
- ic_forms:get_id2(Id) ++ mk_array_dim(D).
-
-mk_array_dim([]) ->
- "";
-mk_array_dim([{_,_,Dim}|Dims]) ->
- "[" ++ Dim ++ "]" ++ mk_array_dim(Dims).
-
-
-%% Creates the array file
-mk_array_file(G,N,X,{array,AID,SZ},Type,HFd) ->
- ArrayName = ic_util:to_undersc([ic_forms:get_id2(AID),ic_forms:get_id2(X) | N]),
- ArrayDim = extract_array_dim(SZ),
- emit(HFd, "\n#ifndef __~s__\n",[ictype:to_uppercase(ArrayName)]),
- emit(HFd, "#define __~s__\n\n",[ictype:to_uppercase(ArrayName)]),
- icstruct:create_c_array_coding_file(G,
- N,
- {ArrayName,ArrayDim},
- Type,
- no_typedef),
- emit(HFd, "\n#endif\n\n").
-
-extract_array_dim([{_,_,Dim}]) ->
- [Dim];
-extract_array_dim([{_,_,Dim}|Dims]) ->
- [Dim | extract_array_dim(Dims)].
-
-
-%% Makes the declaration for the member in union
-mk_union_member_decl(G,N,X,Id,Type,Fd) ->
- emit(Fd, " ~s ~s;\n",
- [getCaseTypeStr(G,N,X,Id,Type),
- ic_forms:get_id2(Id)]).
-
-
-
-
-%% File utilities
-create_c_union_file(G, N, X, UnionName) ->
-
- {Fd , SName} = open_c_coding_file(G, UnionName),
- _HFd = ic_genobj:hrlfiled(G), %% Write on stubfile header
- HrlFName = filename:basename(ic_genobj:include_file(G)),
- ic_codegen:emit_stub_head(G, Fd, SName, c),
- emit(Fd, "#include \"~s\"\n\n",[HrlFName]),
-
- %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %% Fd = ic_genobj:stubfiled(G), %% Write on stubfile
- %% HFd = ic_genobj:hrlfiled(G), %% Write on stubfile header
- %% HrlFName = filename:basename(ic_genobj:include_file(G)),
- %% emit(Fd, "#include \"~s\"\n\n",[HrlFName]),
- %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- put(op_variable_count, 0),
- put(tmp_declarations, []),
-
- %% Write generated code on file
- emit_union_sizecount(G, N, X, Fd, UnionName),
- emit_union_encode(G, N, X, Fd, UnionName),
- emit_union_decode(G, N, X, Fd, UnionName),
- file:close(Fd).
-
-open_c_coding_file(G, Name) ->
- SName = string:concat(ic_util:mk_oe_name(G, "code_"), Name),
- FName =
- ic_file:join(ic_options:get_opt(G, stubdir),ic_file:add_dot_c(SName)),
- case file:open(FName, [write]) of
- {ok, Fd} ->
- {Fd, SName};
- Other ->
- exit(Other)
- end.
-
-
-
-
-get_c_union_discriminator(G, N, X) ->
- case getDiscrStr(G, N, X#union.type) of
- error ->
- ic_error:fatal_error(G, {illegal_typecode_for_c, X#union.type, N});
- DiscrStr ->
- case ic_code:get_basetype(G, DiscrStr) of
- {short, _} ->
- "CORBA_short";
- {unsigned,{short, _}} ->
- "CORBA_unsigned_short";
- {long, _} ->
- "CORBA_long";
- {unsigned,{long, _}} ->
- "CORBA_unsigned_long";
- {boolean,_} ->
- "CORBA_boolean";
- {char,_} ->
- "CORBA_char";
- {enum, EnumType} ->
- EnumType;
- _ ->
- DiscrStr
- end
- end.
-
-getDiscrStr(G, N, S) when element(1, S) == scoped_id ->
- case ic_symtab:get_full_scoped_name(G, N, S) of
- {FSN, _, tk_short, _} ->
- ic_util:to_undersc(FSN);
- {FSN, _, tk_ushort, _} ->
- ic_util:to_undersc(FSN);
- {FSN, _, tk_long, _} ->
- ic_util:to_undersc(FSN);
- {FSN, _, tk_ulong, _} ->
- ic_util:to_undersc(FSN);
- {FSN, _, tk_boolean, _} ->
- ic_util:to_undersc(FSN);
- {FSN, _, tk_char, _} ->
- ic_util:to_undersc(FSN);
- {FSN, _, {tk_enum,_,_,_}, _} ->
- ic_util:to_undersc(FSN);
- _ ->
- error
- end;
-getDiscrStr(_G, N, X) ->
- case X of
- {short,_} ->
- "CORBA_short";
- {unsigned,{short,_}} ->
- "CORBA_unsigned_short";
- {long, _} ->
- "CORBA_long";
- {unsigned,{long,_}} ->
- "CORBA_unsigned_long";
- {boolean,_} ->
- "CORBA_boolean";
- {char,_} ->
- "CORBA_char";
- {enum,TID,_,_} ->
- ic_util:to_undersc([ic_forms:get_id2(TID) | N]);
- _ ->
- error
- end.
-
-
-
-
-getCaseTypeStr(G, N, X, I, T) when element(1, T) == scoped_id ->
- case catch ic_symtab:get_full_scoped_name(G, N, T) of
- {FSN, _, _, _} ->
- BT = ic_code:get_basetype(G, ic_util:to_undersc(FSN)),
- case isList(BT) of
- true ->
- BT;
- false ->
- case BT of
- {short,_} ->
- "CORBA_short";
- {unsigned,{short,_}} ->
- "CORBA_unsigned_short";
- {long, _} ->
- "CORBA_long";
- {unsigned,{long,_}} ->
- "CORBA_unsigned_long";
- {float,_} ->
- "CORBA_float";
- {double,_} ->
- "CORBA_double";
- {boolean,_} ->
- "CORBA_boolean";
- {char,_} ->
- "CORBA_char";
- {wchar,_} ->
- "CORBA_wchar";
- {octet,_} ->
- "CORBA_octet";
- {string,_} ->
- "CORBA_char*";
- {wstring,_} ->
- "CORBA_wchar*";
- {sequence,_,_} ->
- ic_util:to_undersc([ic_forms:get_id2(I), ic_forms:get_id2(X) | N]);
- {struct,SID,_,_} ->
- ic_util:to_undersc([ic_forms:get_id2(SID), ic_forms:get_id2(X) | N]);
- {enum,EID} ->
- EID;
- {any, _} -> %% Fix for any type
- "CORBA_long";
- _ ->
- %%io:format("BT = ~p~n",[BT]),
- error
- end
- end
- end;
-getCaseTypeStr(_G, N, X, I, T) ->
- case T of
- {short,_} ->
- "CORBA_short";
- {unsigned,{short,_}} ->
- "CORBA_unsigned_short";
- {long, _} ->
- "CORBA_long";
- {unsigned,{long,_}} ->
- "CORBA_unsigned_long";
- {float,_} ->
- "CORBA_float";
- {double,_} ->
- "CORBA_double";
- {boolean,_} ->
- "CORBA_boolean";
- {char,_} ->
- "CORBA_char";
- {wchar,_} ->
- "CORBA_wchar";
- {octet,_} ->
- "CORBA_octet";
- {string,_} ->
- "CORBA_char*";
- {wstring,_} ->
- "CORBA_wchar*";
- {sequence,_,_} ->
- ic_util:to_undersc([ic_forms:get_id2(I), ic_forms:get_id2(X) | N]);
- {struct,SID,_,_} ->
- ic_util:to_undersc([ic_forms:get_id2(SID), ic_forms:get_id2(X) | N]);
- {union,UID,_,_,_} ->
- ic_util:to_undersc([ic_forms:get_id2(UID), ic_forms:get_id2(X) | N]);
- {any, _} -> %% Fix for any type
- "CORBA_long";
- _ ->
- error
- end.
-
-isList(L) when is_list(L) ->
- true;
-isList(_) ->
- false.
-
-%%
-%% Sizecount facilities
-%%
-emit_union_sizecount(G, N, X, Fd, UnionName) ->
- emit(Fd, "int ~s~s(CORBA_Environment *oe_env, int* oe_size_count_index, int* oe_size) {\n\n",
- [ic_util:mk_oe_name(G, "sizecalc_"), UnionName]),
-
- emit(Fd, " int oe_malloc_size = 0;\n"),
- emit(Fd, " int oe_error_code = 0;\n"),
- emit(Fd, " int oe_type = 0;\n"),
- emit(Fd, " int oe_tmp = 0;\n"),
- emit_union_discr_var_decl(G, N, X, Fd),
-
- ic_codegen:nl(Fd),
- emit(Fd, " if(*oe_size == 0)\n",[]),
- AlignName = lists:concat(["*oe_size + sizeof(",UnionName,")"]),
- emit(Fd, " *oe_size = ~s;\n\n", [ic_util:mk_align(AlignName)]),
-
- emit(Fd, " if ((oe_error_code = ei_get_type(oe_env->_inbuf, oe_size_count_index, &oe_type, &oe_tmp)) < 0) {\n"),
- emit_c_dec_rpt(Fd, " ", "ei_get_type", []),
- emit(Fd, " return oe_error_code;\n }\n"),
-
- %%emit(Fd, " if (oe_tmp != 3)\n"),
- %%emit(Fd, " return -1;\n\n"),
-
- emit(Fd, " if ((oe_error_code = ei_decode_tuple_header(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"),
- emit_c_dec_rpt(Fd, " ", "ei_decode_tuple_header", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_atom(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n", []),
- emit_c_dec_rpt(Fd, " ", "ei_decode_atom", []),
- emit(Fd, " return oe_error_code;\n }\n"),
-
- emit_c_union_discr_sizecount(G, N, X, Fd),
- emit(Fd, " /* Calculate union size */\n"),
- emit(Fd, " switch(oe_discr) {\n"),
-
- emit_c_union_loop(G, N, X, Fd, X#union.body, sizecalc),
- emit(Fd, " }\n\n"),
-
- emit(Fd, " *oe_size = ~s;\n",[ic_util:mk_align("*oe_size+oe_malloc_size")]),
- emit(Fd, " return 0;\n"),
- emit(Fd, "}\n\n\n").
-
-
-emit_union_discr_var_decl(G, N, X, Fd) ->
- UD = get_c_union_discriminator(G, N, X),
- case UD of
- "CORBA_short" ->
- emit(Fd, " long oe_discr = 0;\n");
- "CORBA_unsigned_short" ->
- emit(Fd, " unsigned long oe_discr = 0;\n");
- "CORBA_long" ->
- emit(Fd, " long oe_discr = 0;\n");
- "CORBA_unsigned_long" ->
- emit(Fd, " unsigned long oe_discr = 0;\n");
- "CORBA_boolean" ->
- emit(Fd, " int oe_discr = 0;\n"),
- emit(Fd, " char oe_bool[256];\n");
- "CORBA_char" ->
- emit(Fd, " char oe_discr = 0;\n");
- _T ->
- emit(Fd, " int oe_dummy = 0;\n"),
- emit(Fd, " ~s oe_discr = 0;\n",[UD])
- end.
-
-
-emit_c_union_discr_sizecount(G, N, X, Fd) ->
- emit(Fd, " /* Calculate discriminator size */\n"),
- UD = get_c_union_discriminator(G, N, X),
- case UD of
- "CORBA_short" ->
- emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, oe_size_count_index, &oe_discr)) < 0) {\n"),
- emit_c_dec_rpt(Fd, " ", "ei_decode_long", []),
- emit(Fd, " return oe_error_code;\n }\n");
- "CORBA_unsigned_short" ->
- emit(Fd, " if ((oe_error_code = ei_decode_ulong(oe_env->_inbuf, oe_size_count_index, &oe_discr)) < 0) {\n"),
- emit_c_dec_rpt(Fd, " ", "ei_decode_ulong", []),
- emit(Fd, " return oe_error_code;\n }\n");
- "CORBA_long" ->
- emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, oe_size_count_index, &oe_discr)) < 0) {\n"),
- emit_c_dec_rpt(Fd, " ", "ei_decode_long", []),
- emit(Fd, " return oe_error_code;\n }\n");
- "CORBA_unsigned_long" ->
- emit(Fd, " if ((oe_error_code = ei_decode_ulong(oe_env->_inbuf, oe_size_count_index, &oe_discr)) < 0) {\n"),
- emit_c_dec_rpt(Fd, " ", "ei_decode_ulong", []),
- emit(Fd, " return oe_error_code;\n }\n");
- "CORBA_boolean" ->
- emit(Fd, " if ((oe_error_code = ei_decode_atom(oe_env->_inbuf, oe_size_count_index, oe_bool)) < 0) {\n"),
- emit_c_dec_rpt(Fd, " ", "ei_decode_atom", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " if (strcmp(oe_bool, \"false\") == 0) {\n"),
- emit(Fd, " oe_discr = 0;\n"),
- emit(Fd, " }\n"),
- emit(Fd, " else if (strcmp(oe_bool, \"true\") == 0) {\n"),
- emit(Fd, " oe_discr = 1;\n"),
- emit(Fd, " }\n"),
- emit(Fd, " else {\n"),
- emit_c_dec_rpt(Fd, " ", "not boolean", []),
- emit(Fd, " return -1;\n }\n");
-
- "CORBA_char" ->
- emit(Fd, " if ((oe_error_code = ei_decode_char(oe_env->_inbuf, oe_size_count_index, &oe_discr)) < 0) {\n"),
- emit_c_dec_rpt(Fd, " ", "ei_decode_char", []),
- emit(Fd, " return oe_error_code;\n }\n");
- T ->
- emit(Fd, " oe_tmp = *oe_size_count_index;\n"),
- emit(Fd, " if ((oe_error_code = oe_sizecalc_~s(oe_env, oe_size_count_index, &oe_malloc_size)) < 0) {\n", [T]),
- ?emit_c_dec_rpt(Fd, " ", "oe_size_calc_~s", [T]),
- emit(Fd, " return oe_error_code;\n }\n"),
-
- emit(Fd, " *oe_size_count_index = oe_tmp;\n"),
- emit(Fd, " oe_tmp = oe_env->_iin;\n"),
- emit(Fd, " oe_env->_iin = *oe_size_count_index;\n"),
- emit(Fd, " if ((oe_error_code = oe_decode_~s(oe_env, NULL, &oe_dummy, &oe_discr)) < 0) {\n", [T]),
- ?emit_c_dec_rpt(Fd, " ", "oe_decode_~s", [T]),
- emit(Fd, " return oe_error_code;\n }\n"),
-
- emit(Fd, " *oe_size_count_index = oe_env->_iin;\n"),
- emit(Fd, " oe_env->_iin = oe_tmp;\n\n")
- end.
-
-
-
-emit_c_union_loop(G, N, X, Fd, CaseList, Case) ->
- emit_c_union_loop(G, N, X, Fd, CaseList, false, Case).
-
-emit_c_union_loop(G, N, X, Fd, [], GotDefaultCase, Case) ->
- case GotDefaultCase of
- false ->
- emit_c_union_valueless_discriminator(G, N, X, Fd, Case)
- end;
-emit_c_union_loop(G, N, X, Fd, [CU|CUs], GotDefaultCase, Case) ->
- case CU of
- {case_dcl,CaseList,I,T} ->
- GotDefaultCase = emit_c_union_case(G, N, X, Fd, I, T, CaseList, Case),
- emit_c_union_loop(G, N, X, Fd, CUs, GotDefaultCase, Case);
- _ ->
- error
- end.
-
-emit_c_union_valueless_discriminator(_G, _N, _X, Fd, Case) ->
- emit(Fd, " default:\n"),
- case Case of
- sizecalc ->
- emit(Fd, " {\n"),
- emit(Fd, " char oe_undefined[15];\n\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_atom(oe_env->_inbuf, "
- "oe_size_count_index, oe_undefined)) < 0) {\n"),
- emit_c_dec_rpt(Fd, " ", "ei_decode_atom", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " }\n");
- encode ->
- emit(Fd, " if ((oe_error_code = oe_ei_encode_atom(oe_env, \"undefined\")) < 0) {\n"),
- emit_c_enc_rpt(Fd, " ", "oe_ei_encode_atom", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " break;\n");
- decode ->
- emit(Fd, " {\n"),
- emit(Fd, " char oe_undefined[15];\n\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_atom(oe_env->_inbuf, &oe_env->_iin, "
- "oe_undefined)) < 0) {\n"),
- emit_c_dec_rpt(Fd, " ", "ei_decode_atom", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " if (strcmp(oe_undefined, \"undefined\") != 0) {\n"),
- emit_c_dec_rpt(Fd, " ", "undefined", []),
- emit(Fd, " return -1;\n }\n"),
- emit(Fd, " }\n")
- end.
-
-
-emit_c_union_case(G, N, X, Fd, I, T, [{default,_}], Case) ->
- emit(Fd, " default:\n"),
- case Case of
- sizecalc ->
- getCaseTypeSizecalc(G, N, X, Fd, I, T);
- encode ->
- getCaseTypeEncode(G, N, X, Fd, I, T);
- decode ->
- getCaseTypeDecode(G, N, X, Fd, I, T)
- end,
- true;
-emit_c_union_case(G, N, X, Fd, I, T, [{Bool,_}], Case) -> %% Boolean discriminator
- case Bool of
- 'TRUE' ->
- emit(Fd, " case 1:\n");
- 'FALSE' ->
- emit(Fd, " case 0:\n")
- end,
- case Case of
- sizecalc ->
- getCaseTypeSizecalc(G, N, X, Fd, I, T);
- encode ->
- getCaseTypeEncode(G, N, X, Fd, I, T);
- decode ->
- getCaseTypeDecode(G, N, X, Fd, I, T)
- end,
- emit(Fd, " break;\n\n"),
- false;
-emit_c_union_case(G, N, X, Fd, I, T, [{Bool,_}|Rest], Case) -> %% Boolean discriminator
- case Bool of
- 'TRUE' ->
- emit(Fd, " case 1:\n");
- 'FALSE' ->
- emit(Fd, " case 0:\n")
- end,
- emit_c_union_case(G, N, X, Fd, I, T, Rest, Case),
- false;
-emit_c_union_case(G, N, X, Fd, I, T, [{_,_,NrStr}], Case) -> %% Integer type discriminator
- case get_c_union_discriminator(G, N, X) of
- "CORBA_char" ->
- emit(Fd, " case \'~s\':\n",[NrStr]);
- _ ->
- emit(Fd, " case ~s:\n",[NrStr])
- end,
- case Case of
- sizecalc ->
- getCaseTypeSizecalc(G, N, X, Fd, I, T);
- encode ->
- getCaseTypeEncode(G, N, X, Fd, I, T);
- decode ->
- getCaseTypeDecode(G, N, X, Fd, I, T)
- end,
- emit(Fd, " break;\n\n"),
- false;
-emit_c_union_case(G, N, X, Fd, I, T, [{_,_,NrStr}|Rest], Case) -> %% Integer type discriminator
- emit(Fd, " case ~s:\n",[NrStr]),
- emit_c_union_case(G, N, X, Fd, I, T, Rest, Case),
- false;
-emit_c_union_case(G, N, X, Fd, I, T, [{scoped_id,_,_,[EID]}], Case) -> %% Enumerant type discriminator
- SID = ic_util:to_undersc([EID|get_c_union_discriminator_scope(G, N, X)]),
- %%io:format("SID = ~p~n",[SID]),
- emit(Fd, " case ~s:\n",[SID]),
- case Case of
- sizecalc ->
- getCaseTypeSizecalc(G, N, X, Fd, I, T);
- encode ->
- getCaseTypeEncode(G, N, X, Fd, I, T);
- decode ->
- getCaseTypeDecode(G, N, X, Fd, I, T)
- end,
- emit(Fd, " break;\n\n"),
- false;
-emit_c_union_case(G, N, X, Fd, I, T, [{scoped_id,_,_,[EID]}|Rest], Case) -> %% Enumerant type discriminator
- SID = ic_util:to_undersc([EID|get_c_union_discriminator_scope(G, N, X)]),
- %%io:format("SID = ~p~n",[SID]),
- emit(Fd, " case ~s:\n",[SID]),
- emit_c_union_case(G, N, X, Fd, I, T, Rest, Case),
- false.
-
-
-%%
-%% Returns the enumerant discriminator scope
-%%
-get_c_union_discriminator_scope(G, N, X) ->
- {FullScopedName, _, _TK, _} = ic_symtab:get_full_scoped_name(G, N, X#union.type),
- BT = case ic_code:get_basetype(G, ic_util:to_undersc(FullScopedName)) of
- {enum,ST} ->
- ST;
- Other ->
- Other
- end,
- tl(lists:reverse(string:tokens(BT,"_"))). %% Ugly work arround
-
-
-
-
-
-getCaseTypeSizecalc(G, N, X, Fd, I, T) when element(1, T) == scoped_id ->
- case ic_fetch:member2type(G,X,I) of
- ushort ->
- emit(Fd, " if ((oe_error_code = ei_decode_ulong(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "ushort:ei_decode_ulong", []),
- emit(Fd, " return oe_error_code;\n }\n");
- ulong ->
- emit(Fd, " if ((oe_error_code = ei_decode_ulong(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "ulong:ei_decode_ulong", []),
- emit(Fd, " return oe_error_code;\n }\n");
- short ->
- emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "short:ei_decode_long", []),
- emit(Fd, " return oe_error_code;\n }\n");
- long ->
- emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "long:ei_decode_long", []),
- emit(Fd, " return oe_error_code;\n }\n");
- float ->
- emit(Fd, " if ((oe_error_code = ei_decode_double(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "float:ei_decode_double", []),
- emit(Fd, " return oe_error_code;\n }\n");
- double ->
- emit(Fd, " if ((oe_error_code = ei_decode_double(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "double:ei_decode_double", []),
- emit(Fd, " return oe_error_code;\n }\n");
- boolean ->
- emit(Fd, " if ((oe_error_code = ei_decode_atom(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "boolean:ei_decode_atom", []),
- emit(Fd, " return oe_error_code;\n }\n");
- char ->
- emit(Fd, " if ((oe_error_code = ei_decode_char(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "char:ei_decode_char", []),
- emit(Fd, " return oe_error_code;\n }\n");
- octet ->
- emit(Fd, " if ((oe_error_code = ei_decode_char(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "octet:ei_decode_char", []),
- emit(Fd, " return oe_error_code;\n }\n");
- string ->
- emit(Fd, " if ((oe_error_code = ei_get_type(oe_env->_inbuf, oe_size_count_index, &oe_type, &oe_tmp)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "ei_get_type", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_string(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "ei_decode_string", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " oe_malloc_size = ~s;\n",[ic_util:mk_align("oe_malloc_size+oe_tmp+1")]);
- any -> %% Fix for any type
- emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "ei_decode_long", []),
- emit(Fd, " return oe_error_code;\n }\n");
-
- _ ->
- case getCaseTypeStr(G, N, X, I, T) of
- "erlang_pid" ->
- emit(Fd, " if ((oe_error_code = ei_decode_pid(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n",
- []),
- ?emit_c_dec_rpt(Fd, " ", "ei_decode_pid", []),
- emit(Fd, " return oe_error_code;\n }\n");
- "erlang_port" ->
- emit(Fd, " if ((oe_error_code = ei_decode_port(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n",
- []),
- ?emit_c_dec_rpt(Fd, " ", "ei_decode_port", []),
- emit(Fd, " return oe_error_code;\n }\n");
- "erlang_ref" ->
- emit(Fd, " if ((oe_error_code = ei_decode_ref(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n",
- []),
- ?emit_c_dec_rpt(Fd, " ", "ei_decode_ref", []),
- emit(Fd, " return oe_error_code;\n }\n");
- "erlang_term" ->
- emit(Fd, " if ((oe_error_code = ei_decode_term(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n",
- []),
- ?emit_c_dec_rpt(Fd, " ", "ei_deoce_term", []),
- emit(Fd, " return oe_error_code;\n }\n");
-
- Other ->
-
- emit(Fd, " if ((oe_error_code = oe_sizecalc_~s(oe_env, oe_size_count_index, &oe_malloc_size)) < 0) {\n",
- [Other]),
- ?emit_c_dec_rpt(Fd, " ", "oe_sizecalc_~s", [Other]),
- emit(Fd, " return oe_error_code;\n }\n")
- end
- end;
-getCaseTypeSizecalc(G, N, X, Fd, I, T) ->
- case I of
- {array,_,_} ->
- ArrayName = ic_util:to_undersc([ic_forms:get_id2(I),ic_forms:get_id2(X) | N]),
- emit(Fd, " if ((oe_error_code = oe_sizecalc_~s(oe_env, oe_size_count_index, &oe_malloc_size)) < 0) {\n",
- [ArrayName]),
- ?emit_c_dec_rpt(Fd, " ", "oe_sizecalc_~s", [ArrayName]),
- emit(Fd, " return oe_error_code;\n }\n");
- _ ->
- case T of
- {short,_} ->
- emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "short:ei_decode_long", []),
- emit(Fd, " return oe_error_code;\n }\n");
- {unsigned,{short,_}} ->
- emit(Fd, " if ((oe_error_code = ei_decode_ulong(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "ushort:ei_decode_ulong", []),
- emit(Fd, " return oe_error_code;\n }\n");
- {long, _} ->
- emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "long:ei_decode_long", []),
- emit(Fd, " return oe_error_code;\n }\n");
- {unsigned,{long,_}} ->
- emit(Fd, " if ((oe_error_code = ei_decode_ulong(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "ulong:ei_decode_ulong", []),
- emit(Fd, " return oe_error_code;\n }\n");
- {float,_} ->
- emit(Fd, " if ((oe_error_code = ei_decode_double(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "float:ei_decode_double", []),
- emit(Fd, " return oe_error_code;\n }");
- {double,_} ->
- emit(Fd, " if ((oe_error_code = ei_decode_double(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "double:ei_decode_double", []),
- emit(Fd, " return oe_error_code;\n }\n");
- {boolean,_} ->
- emit(Fd, " if ((oe_error_code = ei_decode_atom(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "boolean:ei_decode_atom", []),
- emit(Fd, " return oe_error_code;\n }\n");
- {char,_} ->
- emit(Fd, " if ((oe_error_code = ei_decode_char(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "char:ei_decode_char", []),
- emit(Fd, " return oe_error_code;\n }\n");
- {octet,_} ->
- emit(Fd, " if ((oe_error_code = ei_decode_char(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "octet:ei_decode_char", []),
- emit(Fd, " return oe_error_code;\n }\n");
- {string,_} ->
- emit(Fd, " if ((oe_error_code = ei_get_type(oe_env->_inbuf, oe_size_count_index, &oe_type, &oe_tmp)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "ei_get_type", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_string(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "ei_decode_string", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " oe_malloc_size = ~s;\n",[ic_util:mk_align("oe_malloc_size+oe_tmp+1")]);
- {sequence,_,_} ->
- SeqName = ic_util:to_undersc([ic_forms:get_id2(I), ic_forms:get_id2(X) | N]),
- emit(Fd, " if ((oe_error_code = oe_sizecalc_~s(oe_env, oe_size_count_index, &oe_malloc_size)) < 0) {\n",
- [SeqName]),
- ?emit_c_dec_rpt(Fd, " ", "sequence:oe_sizecalc_~s", [SeqName]),
- emit(Fd, " return oe_error_code;\n }\n");
- {struct,SID,_,_} ->
- StructName = ic_util:to_undersc([ic_forms:get_id2(SID), ic_forms:get_id2(X) | N]),
- emit(Fd, " if ((oe_error_code = oe_sizecalc_~s(oe_env, oe_size_count_index, &oe_malloc_size)) < 0) {\n",
- [StructName]),
- ?emit_c_dec_rpt(Fd, " ", "struct:oe_sizecalc_~s", [StructName]),
- emit(Fd, " return oe_error_code;\n }\n");
- {union,UID,_,_,_} ->
- UnionName = ic_util:to_undersc([ic_forms:get_id2(UID), ic_forms:get_id2(X) | N]),
- emit(Fd, " if ((oe_error_code = oe_sizecalc_~s(oe_env, oe_size_count_index, &oe_malloc_size)) < 0) {\n",
- [UnionName]),
- ?emit_c_dec_rpt(Fd, " ", "union:oe_sizecalce_~s", [UnionName]),
- emit(Fd, " return oe_error_code;\n }\n");
- {any, _} -> %% Fix for any type
- emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "any:ei_decode_long", []),
- emit(Fd, " return oe_error_code;\n }\n");
- _ ->
- ic_error:fatal_error(G, {illegal_typecode_for_c, T, N})
- end
- end.
-
-
-
-
-
-%%
-%% Encode facilities
-%%
-emit_union_encode(G, N, X, Fd, UnionName) ->
- emit(Fd, "int ~s~s(CORBA_Environment *oe_env, ~s* oe_rec) {\n\n",
- [ic_util:mk_oe_name(G, "encode_"), UnionName, UnionName]),
-
- emit(Fd, " int oe_error_code = 0;\n\n"),
-
- emit(Fd, " if ((oe_error_code = oe_ei_encode_tuple_header(oe_env, 3)) < 0) {\n"),
- emit_c_enc_rpt(Fd, " ", "oe_ei_encode_tuple_header", []),
- emit(Fd, " return oe_error_code;\n }\n"),
-
- emit(Fd, " if ((oe_error_code = oe_ei_encode_atom(oe_env, \"~s\")) < 0) {\n",
- [UnionName]),
- emit_c_enc_rpt(Fd, " ", "oe_ei_encode_atom", []),
- emit(Fd, " return oe_error_code;\n }\n"),
-
- emit_c_union_discr_encode(G, N, X, Fd),
- emit(Fd, " /* Encode union */\n"),
- emit(Fd, " switch(oe_rec->_d) {\n"),
- emit_c_union_loop(G, N, X, Fd, X#union.body, encode),
- emit(Fd, " }\n\n"),
- emit(Fd, " return 0;\n"),
- emit(Fd, "}\n\n\n").
-
-
-emit_c_union_discr_encode(G, N, X, Fd) ->
- emit(Fd, " /* Encode descriminator */\n"),
- UD = get_c_union_discriminator(G, N, X),
- case UD of
- "CORBA_short" ->
- emit(Fd, " if ((oe_error_code = oe_ei_encode_long(oe_env, oe_rec->_d)) < 0) {\n"),
- emit_c_enc_rpt(Fd, " ", "oe_ei_encode_long", []),
- emit(Fd, " return oe_error_code;\n }\n");
- "CORBA_unsigned_short" ->
- emit(Fd, " if ((oe_error_code = oe_ei_encode_ulong(oe_env, oe_rec->_d)) < 0) {\n"),
- emit_c_enc_rpt(Fd, " ", "oe_ei_encode_ulong", []),
- emit(Fd, " return oe_error_code;\n }\n");
- "CORBA_long" ->
- emit(Fd, " if ((oe_error_code = oe_ei_encode_long(oe_env, oe_rec->_d)) < 0) {\n"),
- emit_c_enc_rpt(Fd, " ", "oe_ei_encode_long", []),
- emit(Fd, " return oe_error_code;\n }\n");
- "CORBA_unsigned_long" ->
- emit(Fd, " if ((oe_error_code = oe_ei_encode_ulong(oe_env, oe_rec->_d)) < 0) {\n"),
- emit_c_enc_rpt(Fd, " ", "oe_ei_encode_ulong", []),
- emit(Fd, " return oe_error_code;\n }\n");
- "CORBA_boolean" ->
- emit(Fd, " switch(oe_rec->_d) {\n"),
- emit(Fd, " case 0:\n"),
- emit(Fd, " if ((oe_error_code = oe_ei_encode_atom(oe_env, \"false\")) < 0) {\n"),
- emit_c_enc_rpt(Fd, " ", "oe_ei_encode_atom", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " break;\n"),
- emit(Fd, " case 1:\n"),
- emit(Fd, " if ((oe_error_code = oe_ei_encode_atom(oe_env, \"true\")) < 0) {\n"),
- emit_c_enc_rpt(Fd, " ", "oe_ei_encode_atom", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " break;\n"),
- emit(Fd, " default:\n"),
- emit_c_enc_rpt(Fd, " ", "boolean failure", []),
- emit(Fd, " return -1;\n"),
- emit(Fd, " }\n\n");
- "CORBA_char" ->
- emit(Fd, " if ((oe_error_code = oe_ei_encode_char(oe_env, oe_rec->_d)) < 0) {\n"),
- emit_c_enc_rpt(Fd, " ", "oe_ei_encode_char", []),
- emit(Fd, " return oe_error_code;\n }\n");
- T ->
- emit(Fd, " if ((oe_error_code = oe_encode_~s(oe_env, oe_rec->_d)) < 0) {\n", [T]),
- ?emit_c_enc_rpt(Fd, " ", "oe_encode_~s", [T]),
- emit(Fd, " return oe_error_code;\n }\n")
- end.
-
-
-getCaseTypeEncode(G, N, X, Fd, I, T) when element(1, T) == scoped_id ->
- case ic_fetch:member2type(G,X,I) of
- ushort ->
- emit(Fd, " if ((oe_error_code = oe_ei_encode_ulong(oe_env, oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "ushort:oe_ei_encode_ulong", []),
- emit(Fd, " return oe_error_code;\n }\n");
- ulong ->
- emit(Fd, " if ((oe_error_code = oe_ei_encode_ulong(oe_env, oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "ulong:oe_ei_encode_ulong", []),
- emit(Fd, " return oe_error_code;\n }\n");
- short ->
- emit(Fd, " if ((oe_error_code = oe_ei_encode_long(oe_env, oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "short:oe_ei_encode_long", []),
- emit(Fd, " return oe_error_code;\n }\n");
- long ->
- emit(Fd, " if ((oe_error_code = oe_ei_encode_long(oe_env, oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "long:oe_ei_encode_long", []),
- emit(Fd, " return oe_error_code;\n }\n");
- float ->
- emit(Fd, " if ((oe_error_code = oe_ei_encode_double(oe_env, oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "float:oe_ei_encode_double", []),
- emit(Fd, " return oe_error_code;\n }\n");
- double ->
- emit(Fd, " if ((oe_error_code = oe_ei_encode_double(oe_env, oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "double:oe_ei_encode_double", []),
- emit(Fd, " return oe_error_code;\n }\n");
- boolean ->
- emit(Fd, " switch(oe_rec->_u.~s) {\n",[ic_forms:get_id2(I)]),
- emit(Fd, " case 0:\n"),
- emit(Fd, " if ((oe_error_code = oe_ei_encode_atom(oe_env, \"false\")) < 0) {\n"),
- ?emit_c_enc_rpt(Fd, " ", "boolean:oe_ei_encode_atom", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " break;\n"),
- emit(Fd, " case 1:\n"),
- emit(Fd, " if ((oe_error_code = oe_ei_encode_atom(oe_env, \"true\")) < 0) {\n"),
- ?emit_c_enc_rpt(Fd, " ", "boolean:oe_ei_encode_atom", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " break;\n"),
- emit(Fd, " default:\n"),
- ?emit_c_enc_rpt(Fd, " ", "boolean failure", []),
- emit(Fd, " return -1;\n"),
- emit(Fd, " }\n");
- char ->
- emit(Fd, " if ((oe_error_code = oe_ei_encode_char(oe_env, oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "char:oe_ei_encode_char", []),
- emit(Fd, " return oe_error_code;\n }\n");
- octet ->
- emit(Fd, " if ((oe_error_code = oe_ei_encode_char(oe_env, oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "octet:oe_ei_encode_char", []),
- emit(Fd, " return oe_error_code;\n }\n");
- string ->
- emit(Fd, " if ((oe_error_code = oe_ei_encode_string(oe_env, oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "oe_ei_encode_string", []),
- emit(Fd, " return oe_error_code;\n }\n");
- struct ->
- case ic_cbe:mk_c_type(G, N, T, evaluate_not) of
- "erlang_pid" ->
- emit(Fd, " if ((oe_error_code = oe_ei_encode_pid(oe_env, &oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "oe_ei_encode_pid", []),
- emit(Fd, " return oe_error_code;\n }\n");
- "erlang_port" ->
- emit(Fd, " if ((oe_error_code = oe_ei_encode_port(oe_env, &oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "oe_ei_encode_port", []),
- emit(Fd, " return oe_error_code;\n }\n");
- "erlang_ref" ->
- emit(Fd, " if ((oe_error_code = oe_ei_encode_ref(oe_env, &oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "oe_ei_encode_ref", []),
- emit(Fd, " return oe_error_code;\n }\n");
- "ETERM*" ->
- emit(Fd, " if ((oe_error_code = oe_ei_encode_term(oe_env, &oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "oe_ei_encode_term", []),
- emit(Fd, " return oe_error_code;\n }\n");
- _ ->
- emit(Fd, " if ((oe_error_code = oe_encode_~s(oe_env, &oe_rec->_u.~s)) < 0) {\n",
- [getCaseTypeStr(G, N, X, I, T), ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "oe_encode_~s",
- [getCaseTypeStr(G, N, X, I, T)]),
- emit(Fd, " return oe_error_code;\n }\n")
- end;
- sequence ->
- emit(Fd, " if ((oe_error_code = oe_encode_~s(oe_env, &oe_rec->_u.~s)) < 0) {\n",
- [getCaseTypeStr(G, N, X, I, T),ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "sequence:oe_encode_~s",
- [getCaseTypeStr(G, N, X, I, T)]),
- emit(Fd, " return oe_error_code;\n }\n");
- array ->
- emit(Fd, " if ((oe_error_code = oe_encode_~s(oe_env, oe_rec->_u.~s)) < 0) {\n",
- [getCaseTypeStr(G, N, X, I, T),ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "array:oe_encode_~s",
- [getCaseTypeStr(G, N, X, I, T)]),
- emit(Fd, " return oe_error_code;\n }\n");
- union ->
- emit(Fd, " if ((oe_error_code = oe_encode_~s(oe_env, &oe_rec->_u.~s)) < 0) {\n",
- [getCaseTypeStr(G, N, X, I, T),ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "union:oe_encode_~s",
- [getCaseTypeStr(G, N, X, I, T)]),
- emit(Fd, " return oe_error_code;\n }\n");
- enum ->
- emit(Fd, " if ((oe_error_code = oe_encode_~s(oe_env, oe_rec->_u.~s)) < 0) {\n",
- [getCaseTypeStr(G, N, X, I, T),ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "enum:oe_encode_~s",
- [getCaseTypeStr(G, N, X, I, T)]),
- emit(Fd, " return oe_error_code;\n }\n");
- any -> %% Fix for any type
- emit(Fd, " if ((oe_error_code = oe_ei_encode_long(oe_env, oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "enum:oe_ei_encodelong", []),
- emit(Fd, " return oe_error_code;\n }\n");
- _ ->
- ic_error:fatal_error(G, {illegal_typecode_for_c, T, N})
- end;
-getCaseTypeEncode(G, N, X, Fd, I, T) ->
- case I of
- {array,AID,_} ->
- ArrayName = ic_util:to_undersc([ic_forms:get_id2(AID),ic_forms:get_id2(X) | N]),
- emit(Fd, " if ((oe_error_code = oe_encode_~s(oe_env, oe_rec->_u.~s)) < 0) {\n",
- [ArrayName,ic_forms:get_id2(AID)]),
- ?emit_c_enc_rpt(Fd, " ", "array:oe_encode_~s", [ArrayName]),
- emit(Fd, " return oe_error_code;\n }\n");
- _ ->
- case T of
- {short,_} ->
- emit(Fd, " if ((oe_error_code = oe_ei_encode_long(oe_env, oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "short:oe_ei_encode_long", []),
- emit(Fd, " return oe_error_code;\n }\n");
- {unsigned,{short,_}} ->
- emit(Fd, " if ((oe_error_code = oe_ei_encode_ulong(oe_env, oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "ushort:oe_ei_encode_ulong", []),
- emit(Fd, " return oe_error_code;\n }\n");
- {long, _} ->
- emit(Fd, " if ((oe_error_code = oe_ei_encode_long(oe_env, oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "long:oe_ei_encode_long", []),
- emit(Fd, " return oe_error_code;\n }\n");
- {unsigned,{long,_}} ->
- emit(Fd, " if ((oe_error_code = oe_ei_encode_ulong(oe_env, oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "ulong:oe_ei_encode_ulong", []),
- emit(Fd, " return oe_error_code;\n }\n");
- {float,_} ->
- emit(Fd, " if ((oe_error_code = oe_ei_encode_double(oe_env, oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "float:oe_ei_encode_double", []),
- emit(Fd, " return oe_error_code;\n }\n");
- {double,_} ->
- emit(Fd, " if ((oe_error_code = oe_ei_encode_double(oe_env, oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "double:oe_ei_encode_double", []),
- emit(Fd, " return oe_error_code;\n }\n");
- {boolean,_} ->
- emit(Fd, " switch(oe_rec->_u.~s) {\n",[ic_forms:get_id2(I)]),
- emit(Fd, " case 0:\n"),
- emit(Fd, " if ((oe_error_code = oe_ei_encode_atom(oe_env, \"false\")) < 0) {\n"),
- ?emit_c_enc_rpt(Fd, " ", "boolean:oe_ei_encode_atom", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " break;\n"),
- emit(Fd, " case 1:\n"),
- emit(Fd, " if ((oe_error_code = oe_ei_encode_atom(oe_env, \"true\")) < 0) {\n"),
- ?emit_c_enc_rpt(Fd, " ", "boolean:oe_ei_encode_atom", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " break;\n"),
- emit(Fd, " default:\n"),
- ?emit_c_enc_rpt(Fd, " ", "boolean failure", []),
- emit(Fd, " return -1;\n"),
- emit(Fd, " }\n");
- {char,_} ->
- emit(Fd, " if ((oe_error_code = oe_ei_encode_char(oe_env, oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "char:oe_ei_encode_char", []),
- emit(Fd, " return oe_error_code;\n }\n");
- {octet,_} ->
- emit(Fd, " if ((oe_error_code = oe_ei_encode_char(oe_env, oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "octet:oe_ei_encode_char", []),
- emit(Fd, " return oe_error_code;\n }\n");
- {string,_} ->
- emit(Fd, " if ((oe_error_code = oe_ei_encode_string(oe_env, oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "oe_ei_encode_string", []),
- emit(Fd, " return oe_error_code;\n }\n");
- {sequence,_,_} ->
- SeqName = ic_util:to_undersc([ic_forms:get_id2(I), ic_forms:get_id2(X) | N]),
- emit(Fd, " if ((oe_error_code = oe_encode_~s(oe_env, &oe_rec->_u.~s)) < 0) {\n",
- [SeqName,ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "sequence:oe_encode_~s", [SeqName]),
- emit(Fd, " return oe_error_code;\n }\n");
- {struct,SID,_,_} ->
- StructName = ic_util:to_undersc([ic_forms:get_id2(SID), ic_forms:get_id2(X) | N]),
- emit(Fd, " if ((oe_error_code = oe_encode_~s(oe_env, &oe_rec->_u.~s)) < 0) {\n",
- [StructName,ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "struct:oe_encode_~s", [StructName]),
- emit(Fd, " return oe_error_code;\n }\n");
- {union,UID,_,_,_} ->
- UnionName = ic_util:to_undersc([ic_forms:get_id2(UID), ic_forms:get_id2(X) | N]),
- emit(Fd, " if ((oe_error_code = oe_encode_~s(oe_env, &oe_rec->_u.~s)) < 0) {\n",
- [UnionName,ic_forms:get_id2(I)]),
- ?emit_c_enc_rpt(Fd, " ", "union:oe_encode_~s", [UnionName]),
- emit(Fd, " return oe_error_code;\n }\n");
- _ ->
- ic_error:fatal_error(G, {illegal_typecode_for_c, T, N})
- end
- end.
-
-
-
-
-%%
-%% Decode facilities
-%%
-emit_union_decode(G, N, X, Fd, UnionName) ->
- emit(Fd, "int ~s~s(CORBA_Environment *oe_env, char *oe_first, int* oe_index, ~s* oe_rec) {\n\n",
- [ic_util:mk_oe_name(G, "decode_"), UnionName, UnionName]),
-
- emit(Fd, " int oe_error_code = 0;\n"),
- emit(Fd, " int oe_tmp = 0;\n"),
- emit(Fd, " char oe_union_name[256];\n\n"),
-
- emit(Fd, " if((char*) oe_rec == oe_first)\n",[]),
- AlignName = lists:concat(["*oe_index + sizeof(",UnionName,")"]),
- emit(Fd, " *oe_index = ~s;\n\n", [ic_util:mk_align(AlignName)]),
-
- emit(Fd, " if ((oe_error_code = ei_decode_tuple_header(oe_env->_inbuf, &oe_env->_iin, &oe_tmp)) < 0) {\n"),
- emit_c_dec_rpt(Fd, " ", "ei_decode_tuple_header", []),
- emit(Fd, " return oe_error_code;\n }\n"),
-
- emit(Fd, " if ((oe_error_code = ei_decode_atom(oe_env->_inbuf, &oe_env->_iin, oe_union_name)) < 0) {\n"),
- emit_c_dec_rpt(Fd, " ", "ei_decode_atom", []),
- emit(Fd, " return oe_error_code;\n }\n"),
-
- emit_c_union_discr_decode(G, N, X, Fd),
- emit(Fd, " /* Decode union */\n"),
- emit(Fd, " switch(oe_rec->_d) {\n"),
- emit_c_union_loop(G, N, X, Fd, X#union.body, decode),
- emit(Fd, " }\n\n"),
-
- emit(Fd, " *oe_index = ~s;\n", [ic_util:mk_align("*oe_index")]),
- emit(Fd, " return 0;\n"),
- emit(Fd, "}\n\n\n").
-
-
-emit_c_union_discr_decode(G, N, X, Fd) ->
- emit(Fd, " /* Decode descriminator */\n"),
- UD = get_c_union_discriminator(G, N, X),
- case UD of
- "CORBA_short" ->
- emit(Fd, " {\n"),
- emit(Fd, " long oe_long;\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, &oe_env->_iin, &oe_long)) < 0) {\n"),
- emit_c_dec_rpt(Fd, " ", "short:ei_decode_long", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " oe_rec->_d = (short) oe_long;\n\n"),
- emit(Fd, " if (oe_rec->_d != oe_long)\n return -1;\n"),
- emit(Fd, " }\n\n");
- "CORBA_unsigned_short" ->
- emit(Fd, " {\n"),
- emit(Fd, " unsigned long oe_ulong;\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_ulong(oe_env->_inbuf, &oe_env->_iin, &oe_ulong)) < 0) {\n"),
- emit_c_dec_rpt(Fd, " ", "unshort:ei_decode_ulong", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " oe_rec->_d = (unsigned short) oe_ulong;\n\n"),
- emit(Fd, " if (oe_rec->_d != oe_ulong)\n return -1;\n"),
- emit(Fd, " }\n\n");
- "CORBA_long" ->
- emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_d)) < 0) {\n"),
- emit_c_dec_rpt(Fd, " ", "long:ei_decode_long", []),
- emit(Fd, " return oe_error_code;\n }\n");
- "CORBA_unsigned_long" ->
- emit(Fd, " if ((oe_error_code = ei_decode_ulong(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_d)) < 0) {\n"),
- emit_c_dec_rpt(Fd, " ", "ulong:ei_decode_ulong", []),
- emit(Fd, " return oe_error_code;\n }\n");
- "CORBA_boolean" ->
- emit(Fd, " {\n"),
- emit(Fd, " char oe_bool[25];\n\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_atom(oe_env->_inbuf, &oe_env->_iin, oe_bool)) < 0) {\n"),
- emit_c_dec_rpt(Fd, " ", "boolean:ei_decode_atom", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " if (strcmp(oe_bool, \"false\") == 0) {\n"),
- emit(Fd, " oe_rec->_d = 0;\n"),
- emit(Fd, " }else if (strcmp(oe_bool, \"true\") == 0) {\n"),
- emit(Fd, " oe_rec->_d = 1;\n"),
- emit(Fd, " } else {\n"),
- emit_c_dec_rpt(Fd, " ", "boolean failure", []),
- emit(Fd, " return -1;\n }\n"),
- emit(Fd, " }\n\n");
- "CORBA_char" ->
- emit(Fd, " if ((oe_error_code = ei_decode_char(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_d)) < 0) {\n"),
- emit_c_dec_rpt(Fd, " ", "char:ei_decode_char", []),
- emit(Fd, " return oe_error_code;\n }\n");
- T ->
- emit(Fd, " if ((oe_error_code = oe_decode_~s(oe_env, oe_first, oe_index, &oe_rec->_d)) < 0) {\n",
- [T]),
- ?emit_c_dec_rpt(Fd, " ", "oe_decode_~s", [T]),
- emit(Fd, " return oe_error_code;\n }\n")
- end.
-
-
-
-getCaseTypeDecode(G, N, X, Fd, I, T) when element(1, T) == scoped_id ->
- case ic_fetch:member2type(G,X,I) of
- ushort ->
- emit(Fd, " {\n"),
- emit(Fd, " unsigned long oe_ulong;\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_ulong(oe_env->_inbuf, &oe_env->_iin, &oe_ulong)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "ushort:ei_decode_ulong", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " oe_rec->_u.~s = (unsigned short) oe_ulong;\n\n",[ic_forms:get_id2(I)]),
- emit(Fd, " if (oe_rec->_u.~s != oe_ulong)\n return -1;\n",[ic_forms:get_id2(I)]),
- emit(Fd, " }\n");
- ulong ->
- emit(Fd, " if ((oe_error_code = ei_decode_ulong(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_dec_rpt(Fd, " ", "ulong:ei_decode_ulong", []),
- emit(Fd, " return oe_error_code;\n }\n");
- short ->
- emit(Fd, " {\n"),
- emit(Fd, " long oe_long;\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, &oe_env->_iin, &oe_long)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "short:ei_decode_long", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " oe_rec->_u.~s = (short) oe_long;\n\n",[ic_forms:get_id2(I)]),
- emit(Fd, " if (oe_rec->_u.~s != oe_long)\n return -1;\n",[ic_forms:get_id2(I)]),
- emit(Fd, " }\n");
- long ->
- emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_dec_rpt(Fd, " ", "long:ei_decode_long", []),
- emit(Fd, " return oe_error_code;\n }\n");
- float ->
- emit(Fd, " {\n"),
- emit(Fd, " double oe_double;\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_double(oe_env->_inbuf, &oe_env->_iin, &oe_double)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "float:ei_decode_double", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " oe_rec->_u.~s = (float) oe_double;\n",[ic_forms:get_id2(I)]),
- emit(Fd, " }\n");
- double ->
- emit(Fd, " if ((oe_error_code = ei_decode_double(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_dec_rpt(Fd, " ", "double:ei_decode_double", []),
- emit(Fd, " return oe_error_code;\n }\n");
- boolean ->
- emit(Fd, " {\n"),
- emit(Fd, " char oe_bool[25];\n\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_atom(oe_env->_inbuf, &oe_env->_iin, oe_bool)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "boolean:ei_decode_atom", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " if (strcmp(oe_bool, \"false\") == 0) {\n"),
- emit(Fd, " oe_rec->_u.~s = 0;\n",[ic_forms:get_id2(I)]),
- emit(Fd, " } else if (strcmp(oe_bool, \"true\") == 0) {\n"),
- emit(Fd, " oe_rec->_u.~s = 1;\n",[ic_forms:get_id2(I)]),
- emit(Fd, " } else {\n"),
- ?emit_c_dec_rpt(Fd, " ", "boolean failure", []),
- emit(Fd, " return -1;\n }\n"),
- emit(Fd, " }\n");
- char ->
- emit(Fd, " if ((oe_error_code = ei_decode_char(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_dec_rpt(Fd, " ", "char:ei_decode_char", []),
- emit(Fd, " return oe_error_code;\n }\n");
- octet ->
- emit(Fd, " if ((oe_error_code = ei_decode_char(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_dec_rpt(Fd, " ", "octet:ei_decode_char", []),
- emit(Fd, " return oe_error_code;\n }\n");
- string ->
- emit(Fd, " {\n"),
- emit(Fd, " int oe_type = 0;\n"),
- emit(Fd, " int oe_string_ctr = 0;\n\n"),
-
- emit(Fd, " (int) ei_get_type(oe_env->_inbuf, &oe_env->_iin, &oe_type, &oe_string_ctr);\n\n"),
-
- emit(Fd, " oe_rec->_u.~s = (void *) (oe_first + *oe_index);\n\n",[ic_forms:get_id2(I)]),
-
- emit(Fd, " if ((oe_error_code = ei_decode_string(oe_env->_inbuf, &oe_env->_iin, oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_dec_rpt(Fd, " ", "ei_decode_string", []),
- emit(Fd, " return oe_error_code;\n }\n"),
-
- emit(Fd, " *oe_index = ~s;\n",[ic_util:mk_align("*oe_index+oe_string_ctr+1")]),
- emit(Fd, " }\n");
- struct ->
- case ic_cbe:mk_c_type(G, N, T, evaluate_not) of
- "erlang_pid" ->
- emit(Fd, " if ((oe_error_code = ei_decode_pid(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_dec_rpt(Fd, " ", "ei_decode_pid", []),
- emit(Fd, " return oe_error_code;\n }\n");
- "erlang_port" ->
- emit(Fd, " if ((oe_error_code = ei_decode_port(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_dec_rpt(Fd, " ", "ei_decode_port", []),
- emit(Fd, " return oe_error_code;\n }\n");
- "erlang_ref" ->
- emit(Fd, " if ((oe_error_code = ei_decode_ref(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_dec_rpt(Fd, " ", "ei_decode_ref", []),
- emit(Fd, " return oe_error_code;\n }\n");
- "ETERM*" ->
- emit(Fd, " if ((oe_error_code = ei_decode_term(oe_env->_inbuf, &oe_env->_iin, (void **)&oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_dec_rpt(Fd, " ", "ei_decode_term", []),
- emit(Fd, " return oe_error_code;\n }\n");
-
- _ ->
- emit(Fd, " if ((oe_error_code = oe_decode_~s(oe_env, oe_first, oe_index, &oe_rec->_u.~s)) < 0) {\n",
- [getCaseTypeStr(G, N, X, I, T),ic_forms:get_id2(I)]),
- ?emit_c_dec_rpt(Fd, " ", "oe_decode_~s",
- [getCaseTypeStr(G, N, X, I, T)]),
- emit(Fd, " return oe_error_code;\n }\n")
- end;
- sequence ->
- emit(Fd, " if ((oe_error_code = oe_decode_~s(oe_env, oe_first, oe_index, &oe_rec->_u.~s)) < 0) {\n",
- [getCaseTypeStr(G, N, X, I, T),ic_forms:get_id2(I)]),
- ?emit_c_dec_rpt(Fd, " ", "sequence:oe_decode_~s",
- [getCaseTypeStr(G, N, X, I, T)]),
- emit(Fd, " return oe_error_code;\n }\n");
- array ->
- emit(Fd, " if ((oe_error_code = oe_decode_~s(oe_env, oe_first, oe_index, oe_rec->_u.~s)) < 0) {\n",
- [getCaseTypeStr(G, N, X, I, T),ic_forms:get_id2(I)]),
- ?emit_c_dec_rpt(Fd, " ", "array:oe_decode_~s", [getCaseTypeStr(G, N, X, I, T)]),
- emit(Fd, " return oe_error_code;\n }\n");
- union ->
- emit(Fd, " if ((oe_error_code = oe_decode_~s(oe_env, oe_first, oe_index, &oe_rec->_u.~s)) < 0) {\n",
- [getCaseTypeStr(G, N, X, I, T),ic_forms:get_id2(I)]),
- ?emit_c_dec_rpt(Fd, " ", "union:oe_decode_~s", [getCaseTypeStr(G, N, X, I, T)]),
- emit(Fd, " return oe_error_code;\n }\n");
- enum ->
- emit(Fd, " if ((oe_error_code = oe_decode_~s(oe_env, oe_first, oe_index, &oe_rec->_u.~s)) < 0) {\n",
- [getCaseTypeStr(G, N, X, I, T),ic_forms:get_id2(I)]),
- ?emit_c_dec_rpt(Fd, " ", "enum:oe_decode_~s", [getCaseTypeStr(G, N, X, I, T)]),
- emit(Fd, " return oe_error_code;\n }\n");
- any -> %% Fix for any type
- emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_dec_rpt(Fd, " ", "any:ei_decodelong", []),
- emit(Fd, " return oe_error_code;\n }\n");
- _ ->
- ic_error:fatal_error(G, {illegal_typecode_for_c, T, N})
- end;
-getCaseTypeDecode(G, N, X, Fd, I, T) ->
- case I of
- {array,AID,_} ->
- ArrayName = ic_util:to_undersc([ic_forms:get_id2(AID),ic_forms:get_id2(X) | N]),
- emit(Fd, " if ((oe_error_code = oe_decode_~s(oe_env, oe_first, oe_index, oe_rec->_u.~s)) < 0) {\n",
- [ArrayName,ic_forms:get_id2(AID)]),
- ?emit_c_dec_rpt(Fd, " ", "array:oe_decode_~s", [ArrayName]),
- emit(Fd, " return oe_error_code;\n }\n");
- _ ->
- case T of
- {short,_} ->
- emit(Fd, " {\n"),
- emit(Fd, " long oe_long;\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, &oe_env->_iin, &oe_long)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "short:ei_decode_long", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " oe_rec->_u.~s = (short) oe_long;\n\n",[ic_forms:get_id2(I)]),
- emit(Fd, " if (oe_rec->_u.~s != oe_long)\n return -1;\n",[ic_forms:get_id2(I)]),
- emit(Fd, " }\n");
- {unsigned,{short,_}} ->
- emit(Fd, " {\n"),
- emit(Fd, " unsigned long oe_ulong;\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_ulong(oe_env->_inbuf, &oe_env->_iin, &oe_ulong)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "ushort:ei_decode_ulong", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " oe_rec->_u.~s = (unsigned short) oe_ulong;\n\n",[ic_forms:get_id2(I)]),
- emit(Fd, " if (oe_rec->_u.~s != oe_ulong)\n return -1;\n",[ic_forms:get_id2(I)]),
- emit(Fd, " }\n");
- {long, _} ->
- emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_dec_rpt(Fd, " ", "long:ei_decode_long", []),
- emit(Fd, " return oe_error_code;\n }\n");
- {unsigned,{long,_}} ->
- emit(Fd, " if ((oe_error_code = ei_decode_ulong(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_dec_rpt(Fd, " ", "ulong:ei_decode_ulong", []),
- emit(Fd, " return oe_error_code;\n }\n");
- {float,_} ->
- emit(Fd, " {\n"),
- emit(Fd, " double oe_double;\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_double(oe_env->_inbuf, &oe_env->_iin, &oe_double)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "float:ei_decode_double", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " oe_rec->_u.~s = (float) oe_double;\n",[ic_forms:get_id2(I)]),
- emit(Fd, " }\n");
- {double,_} ->
- emit(Fd, " if ((oe_error_code = ei_decode_double(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_dec_rpt(Fd, " ", "dobule:ei_decode_double", []),
- emit(Fd, " return oe_error_code;\n }\n");
- {boolean,_} ->
- emit(Fd, " {\n"),
- emit(Fd, " char oe_bool[25];\n\n"),
- emit(Fd, " if ((oe_error_code = ei_decode_atom(oe_env->_inbuf, &oe_env->_iin, oe_bool)) < 0) {\n"),
- ?emit_c_dec_rpt(Fd, " ", "boolean:ei_decode_atom", []),
- emit(Fd, " return oe_error_code;\n }\n"),
- emit(Fd, " if (strcmp(oe_bool, \"false\") == 0) {\n"),
- emit(Fd, " oe_rec->_u.~s = 0;\n",[ic_forms:get_id2(I)]),
- emit(Fd, " } else if (strcmp(oe_bool, \"true\") == 0) {\n"),
- emit(Fd, " oe_rec->_u.~s = 1;\n",[ic_forms:get_id2(I)]),
- emit(Fd, " } else {\n"),
- ?emit_c_dec_rpt(Fd, " ", "boolean failure", []),
- emit(Fd, " return -1;\n }\n"),
- emit(Fd, " }\n");
- {char,_} ->
- emit(Fd, " if ((oe_error_code = ei_decode_char(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_dec_rpt(Fd, " ", "char:ei_decode_char", []),
- emit(Fd, " return oe_error_code;\n }\n");
- {octet,_} ->
- emit(Fd, " if ((oe_error_code = ei_decode_char(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- emit(Fd, " return oe_error_code;\n }\n");
- {string,_} ->
- emit(Fd, " {\n"),
- emit(Fd, " int oe_type = 0;\n"),
- emit(Fd, " int oe_string_ctr = 0;\n\n"),
-
- emit(Fd, " (int) ei_get_type(oe_env->_inbuf, &oe_env->_iin, &oe_type, &oe_string_ctr);\n\n"),
-
- emit(Fd, " oe_rec->_u.~s = (void *) (oe_first + *oe_index);\n\n",[ic_forms:get_id2(I)]),
-
- emit(Fd, " if ((oe_error_code = ei_decode_string(oe_env->_inbuf, &oe_env->_iin, oe_rec->_u.~s)) < 0) {\n",
- [ic_forms:get_id2(I)]),
- ?emit_c_dec_rpt(Fd, " ", "ei_decode_string", []),
- emit(Fd, " return oe_error_code;\n }\n"),
-
- emit(Fd, " *oe_index = ~s;\n",[ic_util:mk_align("*oe_index+oe_string_ctr+1")]),
- emit(Fd, " }\n");
- {sequence,_,_} ->
- SeqName = ic_util:to_undersc([ic_forms:get_id2(I), ic_forms:get_id2(X) | N]),
- emit(Fd, " if ((oe_error_code = oe_decode_~s(oe_env, oe_first, oe_index, &oe_rec->_u.~s)) < 0) {\n",
- [SeqName,ic_forms:get_id2(I)]),
- ?emit_c_dec_rpt(Fd, " ", "sequence:oe_decode_~s", [SeqName]),
- emit(Fd, " return oe_error_code;\n }\n");
- {struct,SID,_,_} ->
- StructName = ic_util:to_undersc([ic_forms:get_id2(SID), ic_forms:get_id2(X) | N]),
- emit(Fd, " if ((oe_error_code = oe_decode_~s(oe_env, oe_first, oe_index, &oe_rec->_u.~s)) < 0) {\n",
- [StructName,ic_forms:get_id2(I)]),
- ?emit_c_dec_rpt(Fd, " ", "struct:oe_decode_~s", [StructName]),
- emit(Fd, " return oe_error_code;\n }\n");
- {union,UID,_,_,_} ->
- UnionName = ic_util:to_undersc([ic_forms:get_id2(UID), ic_forms:get_id2(X) | N]),
- emit(Fd, " if ((oe_error_code = oe_decode_~s(oe_env, oe_first, oe_index, &oe_rec->_u.~s)) < 0) {\n",
- [UnionName,ic_forms:get_id2(I)]),
- ?emit_c_dec_rpt(Fd, " ", "union:oe_decode_~s", [UnionName]),
- emit(Fd, " return oe_error_code;\n }");
- _ ->
- ic_error:fatal_error(G, {illegal_typecode_for_c, T, N})
- end
- end.
-
-mvDefaultToTail(CDclL) ->
- mvDefaultToTail(CDclL,[],[]).
-
-
-mvDefaultToTail([], F, FD) ->
- lists:reverse(F) ++ FD;
-mvDefaultToTail([{case_dcl,CaseList,I,T}|Rest], Found, FoundDefault) ->
- case lists:keysearch(default, 1, CaseList) of
- {value,Default} ->
- NewCaseList = lists:delete(Default, CaseList) ++ [Default],
- mvDefaultToTail(Rest, Found, [{case_dcl,NewCaseList,I,T}|FoundDefault]);
- false ->
- mvDefaultToTail(Rest, [{case_dcl,CaseList,I,T}|Found], FoundDefault)
- end.
-
-
diff --git a/lib/ic/src/icyeccpre.hrl b/lib/ic/src/icyeccpre.hrl
deleted file mode 100644
index 3a2fad185f..0000000000
--- a/lib/ic/src/icyeccpre.hrl
+++ /dev/null
@@ -1,125 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
-
--export([parse/1, parse_and_scan/1, format_error/1]).
-
--import(lists, [reverse/1]).
-
--ifdef(JAM).
--compile([{parse_transform,jam_yecc_pj},pj]).
--endif.
-
-
--include("icforms.hrl").
-
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% The parser generator will insert appropriate declarations before this line.%
-
-parse(Tokens) ->
- case catch yeccpars1(Tokens, false, 0, [], []) of
- error ->
- Errorline =
- if Tokens == [] -> 0; true -> element(2, hd(Tokens)) end,
- {error,
- {Errorline, ?MODULE, "syntax error at or after this line."}};
- Other ->
- Other
- end.
-
-parse_and_scan({Mod, Fun, Args}) ->
- case apply(Mod, Fun, Args) of
- {eof, _} ->
- {ok, eof};
- {error, Descriptor, _} ->
- {error, Descriptor};
- {ok, Tokens, _} ->
- yeccpars1(Tokens, {Mod, Fun, Args}, 0, [], [])
- end.
-
-format_error(Message) ->
- case io_lib:deep_char_list(Message) of
- true ->
- Message;
- _ ->
- io_lib:write(Message)
- end.
-
-% To be used in grammar files to throw an error message to the parser toplevel.
-% Doesn't have to be exported!
-return_error(Line, Message) ->
- throw({error, {Line, ?MODULE, Message}}).
-
-
-% Don't change yeccpars1/6 too much, it is called recursively by yeccpars2/8!
-yeccpars1([Token | Tokens], Tokenizer, State, States, Vstack) ->
- yeccpars2(State, element(1, Token), States, Vstack, Token, Tokens,
- Tokenizer);
-yeccpars1([], {M, F, A}, State, States, Vstack) ->
- case catch apply(M, F, A) of
- {eof, Endline} ->
- {error, {Endline, ?MODULE, "end_of_file"}};
- {error, Descriptor, _Endline} ->
- {error, Descriptor};
- {'EXIT', Reason} ->
- {error, {0, ?MODULE, Reason}};
- {ok, Tokens, _Endline} ->
- case catch yeccpars1(Tokens, {M, F, A}, State, States, Vstack) of
- error ->
- Errorline = element(2, hd(Tokens)),
- {error, {Errorline, ?MODULE,
- "syntax error at or after this line."}};
- Other ->
- Other
- end
- end;
-yeccpars1([], false, State, States, Vstack) ->
- yeccpars2(State, '$end', States, Vstack, {'$end', 999999}, [], false).
-
-% For internal use only.
-yeccerror(Token) ->
- {error,
- {element(2, Token), ?MODULE,
- ["syntax error before: ", yecctoken2string(Token)]}}.
-
-yecctoken2string({atom, _, A}) -> io_lib:write(A);
-yecctoken2string({integer,_,N}) -> io_lib:write(N);
-yecctoken2string({float,_,F}) -> io_lib:write(F);
-yecctoken2string({char,_,C}) -> io_lib:write_char(C);
-yecctoken2string({var,_,V}) -> io_lib:format("~s", [V]);
-yecctoken2string({string,_,S}) -> io_lib:write_string(S);
-yecctoken2string({reserved_symbol, _, A}) -> io_lib:format("~w", [A]);
-yecctoken2string({'dot', _}) -> "'.'";
-yecctoken2string({'$end', _}) ->
- [];
-yecctoken2string({Other, _}) when is_atom(Other) ->
- io_lib:format("~w", [Other]);
-yecctoken2string({_, _, Other}) when is_list(Other) andalso is_number(hd(Other)) ->
- Other;
-yecctoken2string({_, _, Other}) ->
- io_lib:format("~p", [Other]);
-yecctoken2string(Other) ->
- io_lib:write(Other).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
diff --git a/lib/ic/test/Makefile b/lib/ic/test/Makefile
deleted file mode 100644
index 55b8915875..0000000000
--- a/lib/ic/test/Makefile
+++ /dev/null
@@ -1,276 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1998-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(IC_VSN)
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/ic_test
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-TEST_SPEC_FILE = ic.spec ic_smoke.spec
-
-
-IDL_FILES =
-
-COMPILER_TEST_FILES = \
- ic_SUITE_data/Corba.idl \
- ic_SUITE_data/Coss.idl \
- ic_SUITE_data/attr.idl \
- ic_SUITE_data/c_err1.idl \
- ic_SUITE_data/c_err2.idl \
- ic_SUITE_data/c_err3.idl \
- ic_SUITE_data/c_norm.idl \
- ic_SUITE_data/enum.idl \
- ic_SUITE_data/forward.idl \
- ic_SUITE_data/include.idl \
- ic_SUITE_data/include2.idl \
- ic_SUITE_data/include3.idl \
- ic_SUITE_data/inherit.idl \
- ic_SUITE_data/inherit_err.idl \
- ic_SUITE_data/inherit_warn.idl \
- ic_SUITE_data/mult_ids.idl \
- ic_SUITE_data/nasty.idl \
- ic_SUITE_data/one.idl \
- ic_SUITE_data/one_out.idl \
- ic_SUITE_data/one_raises.idl \
- ic_SUITE_data/one_followed.idl \
- ic_SUITE_data/one_void.idl \
- ic_SUITE_data/raises_reg.idl \
- ic_SUITE_data/struct.idl \
- ic_SUITE_data/syntax1.idl \
- ic_SUITE_data/syntax2.idl \
- ic_SUITE_data/syntax3.idl \
- ic_SUITE_data/syntax4.idl \
- ic_SUITE_data/syntax5.idl \
- ic_SUITE_data/syntax6.idl \
- ic_SUITE_data/type.idl \
- ic_SUITE_data/typeid.idl \
- ic_SUITE_data/u_case_mult.idl \
- ic_SUITE_data/u_mult.idl \
- ic_SUITE_data/u_norm.idl \
- ic_SUITE_data/u_type.idl \
- ic_SUITE_data/u_default.idl \
- ic_SUITE_data/undef_id.idl
-
-
-COMPILER_TEST_FILES2 = \
- ic_register_SUITE_data/reg_m8.idl \
- ic_register_SUITE_data/reg_m9.idl \
- ic_register_SUITE_data/reg_m10.idl \
- ic_register_SUITE_data/reg_m11.idl \
- ic_register_SUITE_data/reg_m12.idl
-
-
-COMPILER_TEST_FILES3 = \
- ic_pragma_SUITE_data/reg_m0.idl \
- ic_pragma_SUITE_data/reg_m1.idl \
- ic_pragma_SUITE_data/reg_m2.idl \
- ic_pragma_SUITE_data/reg_m3.idl \
- ic_pragma_SUITE_data/reg_m4.idl \
- ic_pragma_SUITE_data/reg_m5.idl \
- ic_pragma_SUITE_data/reg_m6.idl \
- ic_pragma_SUITE_data/reg_m7.idl \
- ic_pragma_SUITE_data/uggly.idl
-
-
-COMPILER_TEST_FILES4 = \
- ic_be_SUITE_data/plain.idl
-
-
-PREPROCESSOR_TEST_FILES = \
- ic_pp_SUITE_data/arg.idl \
- ic_pp_SUITE_data/cascade.idl \
- ic_pp_SUITE_data/comment.idl \
- ic_pp_SUITE_data/concat.idl \
- ic_pp_SUITE_data/define.idl \
- ic_pp_SUITE_data/if.idl \
- ic_pp_SUITE_data/if_zero.idl \
- ic_pp_SUITE_data/improp_nest_constr.idl \
- ic_pp_SUITE_data/inc.idl \
- ic_pp_SUITE_data/line.idl \
- ic_pp_SUITE_data/misc.idl \
- ic_pp_SUITE_data/nopara.idl \
- ic_pp_SUITE_data/predef.idl \
- ic_pp_SUITE_data/predef_time.idl \
- ic_pp_SUITE_data/self_ref.idl \
- ic_pp_SUITE_data/separate.idl \
- ic_pp_SUITE_data/swallow_sc.idl \
- ic_pp_SUITE_data/unintended_grp.idl
-
-C_CLIENT_ERL_SERVER_TEST_FILES = \
- c_client_erl_server_SUITE_data/Makefile.src \
- c_client_erl_server_SUITE_data/c_erl_test.idl \
- c_client_erl_server_SUITE_data/c_client.c \
- c_client_erl_server_SUITE_data/m_i_impl.erl
-
-C_CLIENT_ERL_SERVER_PROTO_TEST_FILES = \
- c_client_erl_server_proto_SUITE_data/Makefile.src \
- c_client_erl_server_proto_SUITE_data/c_erl_test.idl \
- c_client_erl_server_proto_SUITE_data/c_client.c \
- c_client_erl_server_proto_SUITE_data/my.c \
- c_client_erl_server_proto_SUITE_data/m_i_impl.erl
-
-C_CLIENT_ERL_SERVER_PROTO_TMO_TEST_FILES = \
- c_client_erl_server_proto_tmo_SUITE_data/Makefile.src \
- c_client_erl_server_proto_tmo_SUITE_data/c_erl_test.idl \
- c_client_erl_server_proto_tmo_SUITE_data/c_client.c \
- c_client_erl_server_proto_tmo_SUITE_data/my.c \
- c_client_erl_server_proto_tmo_SUITE_data/m_i_impl.erl
-
-ERL_CLIENT_C_SERVER_TEST_FILES = \
- erl_client_c_server_SUITE_data/Makefile.src \
- erl_client_c_server_SUITE_data/erl_c_test.idl \
- erl_client_c_server_SUITE_data/erl_client.erl \
- erl_client_c_server_SUITE_data/c_server.c \
- erl_client_c_server_SUITE_data/callbacks.c
-
-ERL_CLIENT_C_SERVER_PROTO_TEST_FILES = \
- erl_client_c_server_proto_SUITE_data/Makefile.src \
- erl_client_c_server_proto_SUITE_data/erl_c_test.idl \
- erl_client_c_server_proto_SUITE_data/erl_client.erl \
- erl_client_c_server_proto_SUITE_data/c_server.c \
- erl_client_c_server_proto_SUITE_data/callbacks.c
-
-JAVA_CLIENT_ERL_SERVER_TEST_FILES = \
- java_client_erl_server_SUITE_data/Makefile.src \
- java_client_erl_server_SUITE_data/java_erl_test.idl \
- java_client_erl_server_SUITE_data/JavaClient.java \
- java_client_erl_server_SUITE_data/m_i_impl.erl
-
-MODULES = \
- ic_SUITE \
- ic_register_SUITE \
- ic_pragma_SUITE \
- ic_pp_SUITE \
- ic_be_SUITE \
- c_client_erl_server_SUITE \
- c_client_erl_server_proto_SUITE \
- c_client_erl_server_proto_tmo_SUITE \
- erl_client_c_server_SUITE \
- erl_client_c_server_proto_SUITE \
- java_client_erl_server_SUITE
-
-GEN_MODULES =
-
-ERL_FILES = $(MODULES:%=%.erl)
-
-HRL_FILES =
-
-GEN_HRL_FILES =
-
-
-GEN_FILES = \
- $(GEN_HRL_FILES:%=$(IDLOUTDIR)/%) \
- $(GEN_MODULES=:%=$(IDLOUTDIR)/%.erl)
-
-GEN_TARGET_FILES = $(GEN_MODULES:%=$(IDLOUTDIR)/%.$(EMULATOR))
-
-SUITE_TARGET_FILES = $(MODULES:%=%.$(EMULATOR))
-
-TARGET_FILES = \
- $(GEN_TARGET_FILES) \
- $(SUITE_TARGET_FILES)
-
-# ----------------------------------------------------
-# PROGRAMS
-# ----------------------------------------------------
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_LOCAL_FLAGS += -pa $(ERL_TOP)/lib/orber/ebin -pa $(ERL_TOP)/lib/ic/ebin
-
-ERL_COMPILE_FLAGS += \
- $(ERL_LOCAL_FLAGS) \
- -pa $(ERL_TOP)/lib/orber/ebin \
- -I$(ERL_TOP)/lib/orber
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-tests debug opt: $(TARGET_FILES)
-
-clean:
- rm -f $(TARGET_FILES)
- rm -f errs core *~
-
-docs:
-
-# ----------------------------------------------------
-# Special Targets
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# Release Targets
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec:
-
-release_docs_spec:
-
-release_tests_spec: tests
- $(INSTALL_DIR) "$(RELSYSDIR)"
- $(INSTALL_DIR) "$(RELSYSDIR)/ic_SUITE_data"
- $(INSTALL_DIR) "$(RELSYSDIR)/ic_register_SUITE_data"
- $(INSTALL_DIR) "$(RELSYSDIR)/ic_pragma_SUITE_data"
- $(INSTALL_DIR) "$(RELSYSDIR)/ic_pp_SUITE_data"
- $(INSTALL_DIR) "$(RELSYSDIR)/ic_be_SUITE_data"
- $(INSTALL_DIR) "$(RELSYSDIR)/c_client_erl_server_SUITE_data"
- $(INSTALL_DIR) "$(RELSYSDIR)/c_client_erl_server_proto_SUITE_data"
- $(INSTALL_DIR) "$(RELSYSDIR)/c_client_erl_server_proto_tmo_SUITE_data"
- $(INSTALL_DIR) "$(RELSYSDIR)/erl_client_c_server_SUITE_data"
- $(INSTALL_DIR) "$(RELSYSDIR)/erl_client_c_server_proto_SUITE_data"
- $(INSTALL_DIR) "$(RELSYSDIR)/java_client_erl_server_SUITE_data"
- $(INSTALL_DATA) $(IDL_FILES) ic.cover $(TEST_SPEC_FILE) $(ERL_FILES) \
- "$(RELSYSDIR)"
- $(INSTALL_DATA) $(COMPILER_TEST_FILES) "$(RELSYSDIR)/ic_SUITE_data"
- $(INSTALL_DATA) $(COMPILER_TEST_FILES2) \
- "$(RELSYSDIR)/ic_register_SUITE_data"
- $(INSTALL_DATA) $(COMPILER_TEST_FILES3) \
- "$(RELSYSDIR)/ic_pragma_SUITE_data"
- $(INSTALL_DATA) $(COMPILER_TEST_FILES4) \
- "$(RELSYSDIR)/ic_be_SUITE_data"
- $(INSTALL_DATA) $(PREPROCESSOR_TEST_FILES) \
- "$(RELSYSDIR)/ic_pp_SUITE_data"
- $(INSTALL_DATA) $(C_CLIENT_ERL_SERVER_TEST_FILES) \
- "$(RELSYSDIR)/c_client_erl_server_SUITE_data"
- $(INSTALL_DATA) $(C_CLIENT_ERL_SERVER_PROTO_TEST_FILES) \
- "$(RELSYSDIR)/c_client_erl_server_proto_SUITE_data"
- $(INSTALL_DATA) $(C_CLIENT_ERL_SERVER_PROTO_TMO_TEST_FILES) \
- "$(RELSYSDIR)/c_client_erl_server_proto_tmo_SUITE_data"
- $(INSTALL_DATA) $(ERL_CLIENT_C_SERVER_TEST_FILES) \
- "$(RELSYSDIR)/erl_client_c_server_SUITE_data"
- $(INSTALL_DATA) $(ERL_CLIENT_C_SERVER_PROTO_TEST_FILES) \
- "$(RELSYSDIR)/erl_client_c_server_proto_SUITE_data"
- $(INSTALL_DATA) $(SUITE_TARGET_FILES) "$(RELSYSDIR)"
- $(INSTALL_DATA) $(JAVA_CLIENT_ERL_SERVER_TEST_FILES) \
- "$(RELSYSDIR)/java_client_erl_server_SUITE_data"
diff --git a/lib/ic/test/c_client_erl_server_SUITE.erl b/lib/ic/test/c_client_erl_server_SUITE.erl
deleted file mode 100644
index b6e100e102..0000000000
--- a/lib/ic/test/c_client_erl_server_SUITE.erl
+++ /dev/null
@@ -1,265 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
-%%----------------------------------------------------------------------
-%% Purpose : Test suite for c-client/erl-server
-%%----------------------------------------------------------------------
-
-
--module(c_client_erl_server_SUITE).
--include_lib("common_test/include/ct.hrl").
-
--export([init_per_testcase/2, end_per_testcase/2,
- all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2,
- void_test/1, long_test/1, long_long_test/1,
- unsigned_short_test/1, unsigned_long_test/1,
- unsigned_long_long_test/1, double_test/1, char_test/1,
- wchar_test/1, octet_test/1, bool_test/1, struct_test/1,
- struct2_test/1, seq1_test/1, seq2_test/1, seq3_test/1,
- seq4_test/1, seq5_test/1, array1_test/1, array2_test/1,
- enum_test/1, string1_test/1, string2_test/1, string3_test/1,
- string4_test/1, pid_test/1, port_test/1, ref_test/1, term_test/1,
- typedef_test/1, inline_sequence_test/1, term_sequence_test/1,
- term_struct_test/1, wstring1_test/1]).
-
--define(DEFAULT_TIMEOUT, 20000).
--define(PORT_TIMEOUT, 15000).
--define(ERLANG_SERVER_NAME, idl_erlang_server).
--define(C_CLIENT_NODE_NAME, c_client_idl_test).
-
-%% Add/remove code path and watchdog before/after each test case.
-%%
-init_per_testcase(_Case, Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- code:add_patha(DataDir),
-
- %% Since other test suites use the module m_i, we have
- %% to make sure we are using the right m_i module.
- code:purge(m_i),
- code:load_file(m_i),
-
- WatchDog = test_server:timetrap(?DEFAULT_TIMEOUT),
- [{watchdog, WatchDog}| Config].
-
-end_per_testcase(_Case, Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- code:del_path(DataDir),
- WatchDog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(WatchDog).
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [void_test, long_test, long_long_test,
- unsigned_short_test, unsigned_long_test,
- unsigned_long_long_test, double_test, char_test,
- wchar_test, octet_test, bool_test, struct_test,
- struct2_test, seq1_test, seq2_test, seq3_test,
- seq4_test, seq5_test, array1_test, array2_test,
- enum_test, string1_test, string2_test, string3_test,
- string4_test, pid_test, port_test, ref_test, term_test,
- typedef_test, inline_sequence_test, term_sequence_test,
- term_struct_test, wstring1_test].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-array1_test(Config) ->
- do_test(array1_test, Config).
-
-array2_test(Config) ->
- do_test(array2_test, Config).
-
-bool_test(Config) ->
- do_test(bool_test, Config).
-
-char_test(Config) ->
- do_test(char_test, Config).
-
-double_test(Config) ->
- do_test(double_test, Config).
-
-enum_test(Config) ->
- do_test(enum_test, Config).
-
-inline_sequence_test(Config) ->
- do_test(inline_sequence_test, Config).
-
-long_long_test(Config) ->
- do_test(long_long_test, Config).
-
-long_test(Config) ->
- do_test(long_test, Config).
-
-octet_test(Config) ->
- do_test(octet_test, Config).
-
-pid_test(Config) ->
- do_test(pid_test, Config).
-
-port_test(Config) ->
- do_test(port_test, Config).
-
-ref_test(Config) ->
- do_test(ref_test, Config).
-
-seq1_test(Config) ->
- do_test(seq1_test, Config).
-
-seq2_test(Config) ->
- do_test(seq2_test, Config).
-
-seq3_test(Config) ->
- do_test(seq3_test, Config).
-
-seq4_test(Config) ->
- do_test(seq4_test, Config).
-
-seq5_test(Config) ->
- do_test(seq5_test, Config).
-
-string1_test(Config) ->
- do_test(string1_test, Config).
-
-string2_test(Config) ->
- do_test(string2_test, Config).
-
-string3_test(Config) ->
- do_test(string3_test, Config).
-
-string4_test(Config) ->
- do_test(string4_test, Config).
-
-struct2_test(Config) ->
- do_test(struct2_test, Config).
-
-struct_test(Config) ->
- do_test(struct_test, Config).
-
-term_sequence_test(Config) ->
- do_test(term_sequence_test, Config).
-
-term_struct_test(Config) ->
- do_test(term_struct_test, Config).
-
-term_test(Config) ->
- do_test(term_test, Config).
-
-typedef_test(Config) ->
- do_test(typedef_test, Config).
-
-unsigned_long_long_test(Config) ->
- do_test(unsigned_long_long_test, Config).
-
-unsigned_long_test(Config) ->
- do_test(unsigned_long_test, Config).
-
-unsigned_short_test(Config) ->
- do_test(unsigned_short_test, Config).
-
-void_test(Config) ->
- do_test(void_test, Config).
-
-wchar_test(Config) ->
- do_test(wchar_test, Config).
-
-wstring1_test(Config) ->
- do_test(wstring1_test, Config).
-
-
-%% It is here that all tests really are done.
-%%
-
-do_test(Case, Config) ->
- %% Trap exits
- process_flag(trap_exit, true),
- %% Start the server
- {ok, _Pid} = m_i:oe_create_link([], {local, ?ERLANG_SERVER_NAME}),
- Node = atom_to_list(node()),
- DataDir = proplists:get_value(data_dir, Config),
- %% io:format("~p: data directory: ~p~n", [?MODULE, DataDir]),
- Cookie = atom_to_list(erlang:get_cookie()),
- %% Start C-client node as a port program.
- Cmd = filename:join([DataDir, "c_client"]) ++
- " -this-node-name " ++ atom_to_list(?C_CLIENT_NODE_NAME) ++
- " -peer-node " ++ Node ++
- " -peer-process-name " ++ atom_to_list(?ERLANG_SERVER_NAME) ++
- " -cookie " ++ Cookie ++
- " -test-case " ++ atom_to_list(Case),
- Port = open_port({spawn, Cmd}, [exit_status, eof, stderr_to_stdout]),
- Res = wait_for_completion(Port),
- %% Kill off node if there was timeout
- case Res of
- {error, timeout} ->
- catch rpc:cast(?C_CLIENT_NODE_NAME, erlang, halt, [1]);
- _ ->
- ok
- end,
- process_flag(trap_exit, false),
- catch m_i:stop(?ERLANG_SERVER_NAME),
- ok = Res.
-
-
-%% Wait for eof *and* exit status, but return if exit status indicates
-%% an error, or we have been waiting more than PORT_TIMEOUT seconds.
-%%
-wait_for_completion(Port) ->
- wait_for_completion(Port, 0).
-
-wait_for_completion(Port, N) when N < 2 ->
- receive
- {Port, {data, Bytes}} ->
- %% Relay output
- io:format("~s", [Bytes]),
- wait_for_completion(Port, N);
- {Port, {exit_status, 0}} ->
- wait_for_completion(Port, N + 1);
- {Port, {exit_status, Status}} ->
- {error, Status};
- {Port, eof} ->
- wait_for_completion(Port, N + 1);
- {'EXIT', Port, Reason} ->
- io:format("Port exited with reason: ~w~n", [Reason]),
- wait_for_completion(Port, N);
- {'EXIT', From, Reason} ->
- io:format("Got unexpected exit: ~p~n", [{'EXIT', From, Reason}]),
- wait_for_completion(Port, N)
- after ?PORT_TIMEOUT ->
- {error, timeout}
- end;
-wait_for_completion(_, _) ->
- ok.
-
-
-
diff --git a/lib/ic/test/c_client_erl_server_SUITE_data/Makefile.src b/lib/ic/test/c_client_erl_server_SUITE_data/Makefile.src
deleted file mode 100644
index 60ea8ea598..0000000000
--- a/lib/ic/test/c_client_erl_server_SUITE_data/Makefile.src
+++ /dev/null
@@ -1,155 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2001-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-# Makefile.src for c_client_erl_server test
-# Note: This file *must* work for both Unix and Windows
-#
-# We use both `rm' (Unix) and `del' (Windows) for removing files, but
-# with a `-' in front so that the error in not finding `rm' (`del') on
-# Windows (Unix) is ignored.
-#
-# VxWorks? XXX
-#
-
-.SUFFIXES:
-.SUFFIXES: .c .h .erl .idl @obj@ .@EMULATOR@
-
-
-# Variables from ts:
-#
-
-ERL_INCLUDE = @erl_include@
-
-IC_INCLUDE_PATH = @ic_include_path@
-IC_LIB = @ic_lib@
-
-ERL_INTERFACE_INCLUDE = @erl_interface_include@
-ERL_INTERFACE_LIB = @erl_interface_lib@
-ERL_INTERFACE_EILIB = @erl_interface_eilib@
-ERL_INTERFACE_THREADLIB = @erl_interface_threadlib@
-ERL_INTERFACE_SOCK_LIBS = @erl_interface_sock_libs@
-
-CC = @CC@
-## XXX Should set warning flag with a DEBUG_FLAG
-CFLAGS = @CFLAGS@ @DEFS@ -I@erl_include@ \
- -I@ic_include_path@ -I@erl_interface_include@
-
-LD = @LD@
-LDFLAGS = @CROSSLDFLAGS@
-LIBS = $(IC_LIB) $(ERL_INTERFACE_LIB) $(ERL_INTERFACE_EILIB) \
- $(ERL_INTERFACE_THREADLIB) @LIBS@ $(ERL_INTERFACE_SOCK_LIBS)
-ERLC = erlc
-
-# Generated C header files
-GEN_H_FILES = \
- m.h \
- m_i.h \
- oe_c_erl_test.h
-
-# Generated C files
-GEN_C_FILES = \
- m.c \
- m_i.c \
- oe_c_erl_test.c \
- oe_code_m_a.c \
- oe_code_m_arr1.c \
- oe_code_m_arr2.c \
- oe_code_m_arr3.c \
- oe_code_m_aseq.c \
- oe_code_m_b.c \
- oe_code_m_bseq.c \
- oe_code_m_dd.c \
- oe_code_m_dyn.c \
- oe_code_m_dyn_sl.c \
- oe_code_m_es.c \
- oe_code_m_et.c \
- oe_code_m_etseq.c \
- oe_code_m_fruit.c \
- oe_code_m_lseq.c \
- oe_code_m_s.c \
- oe_code_m_s_sl.c \
- oe_code_m_sarr3.c \
- oe_code_m_simple.c \
- oe_code_m_ssarr3.c \
- oe_code_m_sseq.c \
- oe_code_m_ssstr3.c \
- oe_code_m_sstr3.c \
- oe_code_m_str1.c \
- oe_code_m_str3.c \
- oe_code_m_strRec.c \
- oe_code_m_strRec_str5.c \
- oe_code_m_strRec_str7.c
-
-GEN_HRL_FILES = \
- m.hrl \
- m_i.hrl \
- oe_c_erl_test.hrl
-
-GEN_ERL_FILES = \
- m.erl \
- m_arr2.erl \
- m_arr3.erl \
- m_i.erl \
- m_str3.erl \
- oe_c_erl_test.erl
-
-C_FILES = $(GEN_C_FILES) c_client.c
-
-OBJS = $(C_FILES:.c=@obj@)
-
-PGMS = c_client@exe@
-
-ERL_FILES = $(GEN_ERL_FILES) m_i_impl.erl
-
-EBINS = $(ERL_FILES:.erl=.@EMULATOR@)
-
-
-all: $(PGMS) $(EBINS)
-
-$(GEN_ERL_FILES) $(GEN_HRL_FILES): c_erl_test.built_erl
-$(GEN_C_FILES) $(GEN_H_FILES): c_erl_test.built_c
-$(OBJS): $(GEN_C_FILES) $(GEN_H_FILES)
-$(EBINS): $(GEN_ERL_FILES) $(GEN_HRL_FILES)
-
-clean:
- -rm -f $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \
- $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) \
- c_erl_test.built_erl c_erl_test.built_c
- -del /F /Q $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \
- $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) \
- c_erl_test.built_erl c_erl_test.built_c
-
-$(PGMS): $(OBJS)
- $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
-
-c_erl_test.built_c: c_erl_test.idl
- $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,c_client}" c_erl_test.idl
- echo done > c_erl_test.built_c
-
-c_erl_test.built_erl: c_erl_test.idl
- $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,erl_genserv}" c_erl_test.idl
- echo done > c_erl_test.built_erl
-
-.c@obj@:
- $(CC) -c -o $*@obj@ $(CFLAGS) $<
-
-.erl.@EMULATOR@:
- $(ERLC) -I $(IC_INCLUDE_PATH) $<
-
diff --git a/lib/ic/test/c_client_erl_server_SUITE_data/c_client.c b/lib/ic/test/c_client_erl_server_SUITE_data/c_client.c
deleted file mode 100644
index 446b46ad82..0000000000
--- a/lib/ic/test/c_client_erl_server_SUITE_data/c_client.c
+++ /dev/null
@@ -1,1760 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 2001-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-/* C-client for test of IC.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#ifndef __WIN32__
-# include <unistd.h>
-#endif
-
-#include <string.h>
-
-#ifdef __WIN32__
-# include <time.h>
-# include <sys/timeb.h>
-#elif defined VXWORKS
-#include <time.h>
-#include <sys/times.h>
-#else
-#include <sys/time.h>
-#endif
-
-#include <ctype.h>
-
-#ifdef __WIN32__
-# include <winsock2.h>
-# include <windows.h>
-#else
-# include <sys/types.h>
-# include <sys/socket.h>
-# include <netinet/in.h>
-# include <arpa/inet.h>
-# include <netdb.h>
-#endif
-
-#include "ei.h"
-#include "erl_interface.h"
-#include "m_i.h"
-
-#define HOSTNAMESZ 255
-#define NODENAMESZ 512
-
-#define INBUFSZ 10
-#define OUTBUFSZ 0
-
-#define MAXTRIES 5
-
-#define CHECK_EXCEPTION(x) \
- if ((x)->_major != CORBA_NO_EXCEPTION) { \
- fprintf(stderr,"\n\nException: %s\n\n", \
- (char *)CORBA_exception_value((x))); \
- CORBA_exception_free((x)); \
- return -1; \
- } \
-
-/* XXX Should free things here too! */
-#define RETURN_IF_OK(x) \
- if ((x)) {\
- fprintf(stdout, "ok\n");\
- return 0;\
- }\
-
-#define cmp_str(x,y) (!strcmp((x),(y)))
-#define cmp_wstr(x,y) (!ic_wstrcmp((x),(y)))
-
-typedef CORBA_Environment IC_Env;
-
-typedef int (*TestFunc)(IC_Env *);
-typedef struct {
- char *name;
- TestFunc func;
-} TestCase;
-
-static char longtext[] =
-"Introduction The IC application is an IDL compiler implemented in Erlang."
-" The IDL compiler generates client stubs and server skeletons."
-" Several back-ends are supported, and they fall into three main groups."
-" For more details on IC compiler options consult the ic(3) manual page."
-" Argument passing cases 1 Caller allocates all necessary storage,"
-" except that which may be encapsulated and managed within the parameter itself."
-" 2 The caller allocates a pointer and passes it by reference to the callee."
-" The callee sets the pointer to point to a valid instance of the parameter's type."
-" The caller is responsible for releasing the returned storage."
-" Following completion of a request, the caller is not allowed to modify any values"
-" in the returned storage. To do so the caller must first copy the returned instance"
-" into a new instance, then modify the new instance. 3 The caller allocates a"
-" pointer to an array slice which has all the same dimensions of the original"
-" array except the first, and passes it by reference to the callee. The callee sets"
-" the pointer to point to a valid instance of the array. The caller is responsible for"
-" releasing the returned storage. Following completion of a request, the caller is not"
-" allowed to modify any values in the returned storage. To do so the caller must first"
-" copy the returned instance into a new instance, then modify the new instance."
-" Generated Files Two files will be generated for each scope. One set of files will be"
-" generated for each module and each interface scope. An extra set is generated for"
-" those definitions at top level scope. One of the files is a header file(.h), and the"
-" other file is a C source code file (.c). In addition to these files a number of C"
-" source files will be generated for type encodings, they are named according to the "
-"following template: oe_code_<type>.c.";
-static char this_node[NODENAMESZ + 1];
-static char *progname;
-
-/* Test function prototypes */
-
-static int void_test(IC_Env *env);
-static int long_test(IC_Env *env);
-static int long_long_test(IC_Env *env);
-static int unsigned_short_test(IC_Env *env);
-static int unsigned_long_test(IC_Env *env);
-static int unsigned_long_long_test(IC_Env *env);
-static int double_test(IC_Env *env);
-static int char_test(IC_Env *env);
-static int wchar_test(IC_Env *env);
-static int octet_test(IC_Env *env);
-static int bool_test(IC_Env *env);
-static int struct_test(IC_Env *env);
-static int struct2_test(IC_Env *env);
-static int seq1_test(IC_Env *env);
-static int seq2_test(IC_Env *env);
-static int seq3_test(IC_Env *env);
-static int seq4_test(IC_Env *env);
-static int seq5_test(IC_Env *env);
-static int array1_test(IC_Env *env);
-static int array2_test(IC_Env *env);
-static int enum_test(IC_Env *env);
-static int string1_test(IC_Env *env);
-static int string2_test(IC_Env *env);
-static int string3_test(IC_Env *env);
-static int string4_test(IC_Env *env);
-static int pid_test(IC_Env *env);
-static int port_test(IC_Env *env);
-static int ref_test(IC_Env *env);
-static int term_test(IC_Env *env);
-static int typedef_test(IC_Env *env);
-static int inline_sequence_test(IC_Env *env);
-static int term_sequence_test(IC_Env *env);
-static int term_struct_test(IC_Env *env);
-static int wstring1_test(IC_Env *env);
-
-static TestCase test_cases[] = {
- {"void_test", void_test},
- {"long_test", long_test},
- {"long_long_test", long_long_test},
- {"unsigned_short_test", unsigned_short_test},
- {"unsigned_long_test", unsigned_long_test},
- {"unsigned_long_long_test", unsigned_long_long_test},
- {"double_test", double_test},
- {"char_test", char_test},
- {"wchar_test", wchar_test},
- {"octet_test", octet_test},
- {"bool_test", bool_test},
- {"struct_test", struct_test},
- {"struct2_test", struct2_test},
- {"seq1_test", seq1_test},
- {"seq2_test", seq2_test},
- {"seq3_test", seq3_test},
- {"seq4_test", seq4_test},
- {"seq5_test", seq5_test},
- {"array1_test", array1_test},
- {"array2_test", array2_test},
- {"enum_test", enum_test},
- {"string1_test", string1_test},
- {"string2_test", string2_test},
- {"string3_test", string3_test},
- {"string4_test", string4_test},
- {"pid_test", pid_test},
- {"port_test", port_test},
- {"ref_test", ref_test},
- {"term_test", term_test},
- {"typedef_test", typedef_test},
- {"inline_sequence_test", inline_sequence_test},
- {"term_sequence_test", term_sequence_test},
- {"term_struct_test", term_struct_test},
- {"wstring1_test", wstring1_test},
- {"", NULL}
-};
-
-/* Other prototypes */
-static int cmp_aseq(m_aseq *a1, m_aseq *a2);
-static int cmp_a(m_a *a1, m_a *a2);
-static int cmp_bseq(m_bseq *b1, m_bseq *b2);
-static int cmp_b(m_b *b1, m_b *b2);
-static int cmp_lseq(m_lseq *b1, m_lseq *b2);
-static int cmp_etseq(m_etseq *b1, m_etseq *b2);
-static int cmp_et(m_et* b1, m_et *b2);
-static int cmp_es(m_es *b1, m_es *b2);
-static int cmp_arr1(m_arr1 b1, m_arr1 b2);
-static int cmp_dd(m_dd b1, m_dd b2);
-static int cmp_strRec(m_strRec *b1, m_strRec *b2);
-static int cmp_sseq(m_sseq *b1, m_sseq *b2);
-static int cmp_pid(erlang_pid *p1, erlang_pid *p2);
-static int cmp_port(erlang_port *p1, erlang_port *p2);
-static int cmp_ref(erlang_ref *p1, erlang_ref *p2);
-static int cmp_s(m_s *b1, m_s *b2);
-static int cmp_ssstr3(m_ssstr3 *b1, m_ssstr3 *b2);
-static int cmp_ssarr3(m_ssarr3 *b1, m_ssarr3 *b2);
-static int cmp_sarr3(m_sarr3 *b1, m_sarr3 *b2);
-static int cmp_arr3(m_arr3 b1, m_arr3 b2);
-
-static void print_aseq(m_aseq *a);
-static void print_a(m_a *a);
-static void print_bseq(m_bseq *b);
-static void print_lseq(m_lseq *b);
-static void print_b(m_b *b);
-static void print_etseq(m_etseq *b);
-static void print_et(m_et* b);
-static void print_es(m_es *b);
-static void print_arr1(long a[500]);
-static void print_dd(long a[2][3]);
-static void print_strRec(m_strRec* sr);
-static void print_sseq(m_sseq *b);
-static void print_pid(erlang_pid *p);
-static void print_port(erlang_port *p);
-static void print_ref(erlang_ref *p);
-static void print_term(ETERM *t);
-static void print_s(m_s *p);
-static void print_ssstr3(m_ssstr3 *b1);
-static void print_ssarr3(m_ssarr3 *b1);
-static void print_sarr3(m_sarr3 *b1);
-static void print_arr3(m_arr3 b1);
-static void print_wstr(CORBA_wchar *ws);
-
-static void free_etseq_buf(m_etseq *b);
-static void free_et(m_et* b);
-
-#ifdef __WIN32__
-typedef struct {
- long tv_sec;
- long tv_usec;
-} MyTimeval;
-#else
-typedef struct timeval MyTimeval;
-#endif
-static void my_gettimeofday(MyTimeval *tv);
-static void showtime(MyTimeval *start, MyTimeval *stop);
-static void usage(void);
-static void done(int r);
-
-
-
-/* main */
-
-#ifdef VXWORKS
-int client(int argc, char **argv)
-#else
-int main(int argc, char **argv)
-#endif
-{
- struct hostent *hp;
- erlang_pid pid;
- MyTimeval start, stop;
- int i, fd, ires, tres;
- IC_Env *env;
- int tries = 0;
- char *this_node_name = NULL;
- char *peer_node = NULL;
- char *peer_process_name = NULL;
- char *cookie = NULL;
- char host[HOSTNAMESZ + 1];
- TestFunc test_func = NULL;
- TestCase *test_case;
- char *test_case_name = NULL;
-
-#ifdef __WIN32__
- WORD wVersionRequested;
- WSADATA wsaData;
-
- wVersionRequested = MAKEWORD(2, 0);
-
- if (WSAStartup(wVersionRequested, &wsaData) != 0) {
- fprintf(stderr, "Could not load winsock2 v2.0 compatible DLL");
- exit(1);
- }
-#endif
-
- progname = argv[0];
- host[HOSTNAMESZ] = '\0';
- if (gethostname(host, HOSTNAMESZ + 1) < 0) {
- fprintf(stderr, "Can't find own hostname\n");
- done(1);
- }
- if ((hp = gethostbyname(host)) == 0) {
- fprintf(stderr, "Can't get ip address for host %s\n", host);
- done(1);
- }
- for (i = 1; i < argc; i++) {
- if (cmp_str(argv[i], "-help")) {
- usage();
- done(0);
- } else if (cmp_str(argv[i], "-this-node-name")) {
- i++;
- this_node_name = argv[i];
- } else if (cmp_str(argv[i], "-peer-node")) {
- i++;
- peer_node = argv[i];
- } else if (cmp_str(argv[i], "-peer-process-name")) {
- i++;
- peer_process_name = argv[i];
- } else if (cmp_str(argv[i], "-cookie")) {
- i++;
- cookie = argv[i];
- } else if (cmp_str(argv[i], "-test-case")) {
- i++;
- test_case_name = argv[i];
- } else {
- fprintf(stderr, "Error : invalid argument \"%s\"\n", argv[i]);
- usage();
- done(1);
- }
- }
-
- if (this_node_name == NULL || peer_node == NULL || test_case_name == NULL
- || peer_process_name == NULL || cookie == NULL) {
- fprintf(stderr, "Error: missing option\n");
- usage();
- done(1);
- }
-
- test_case = test_cases;
- while (test_case->func) {
- if (cmp_str(test_case->name, test_case_name)) {
- test_func = test_case->func;
- break;
- }
- test_case++;
- }
- if (test_func == NULL) {
- fprintf(stderr, "Error: illegal test case: \"%s\"\n", test_case_name);
- done(1);
- }
-
- /* Behead hostname at first dot */
- for (i=0; host[i] != '\0'; i++) {
- if (host[i] == '.') { host[i] = '\0'; break; }
- }
- sprintf(this_node, "%s@%s", this_node_name, host);
- fprintf(stderr, "c_client: this node: \"%s\"\n", this_node);
- fprintf(stderr, "c_client: peer node: \"%s\"\n", peer_node);
- fprintf(stderr, "c_client: test case: \"%s\"\n", test_case_name);
-
- fprintf(stderr, "c_client: starting\n");
-
- /* initialize erl_interface */
- erl_init(NULL, 0);
-
- for (tries = 0; tries < MAXTRIES; tries++) {
-
- /* connect to erlang node */
-
- ires = erl_connect_xinit(host, this_node_name, this_node,
- (struct in_addr *)*hp->h_addr_list,
- cookie, 0);
-
- fprintf(stderr, "c_client: erl_connect_xinit(): %d\n", ires);
-
- fd = erl_connect(peer_node);
- fprintf(stderr, "c_client: erl_connect(): %d\n", fd);
-
- if (fd >= 0)
- break;
- fprintf(stderr, "c_client: cannot connect, retrying\n");
- }
- if (fd < 0) {
- fprintf(stderr, "c_client: cannot connect, exiting\n");
- done(1);
- }
- env = CORBA_Environment_alloc(INBUFSZ, OUTBUFSZ);
- env->_fd = fd;
- strcpy(env->_regname, peer_process_name);
- env->_to_pid = NULL;
- env->_from_pid = &pid;
-
- strcpy(pid.node, this_node);
- pid.num = fd;
- pid.serial = 0;
- pid.creation = 0;
-
- my_gettimeofday(&start);
- tres = test_func(env); /* Call test case */
- my_gettimeofday(&stop);
- showtime(&start, &stop);
- erl_close_connection(fd);
-
- printf("c_client: env->_inbuf before : %d\n", INBUFSZ);
- printf("c_client: env->_outbuf before : %d\n", OUTBUFSZ);
- printf("c_client: env->_inbuf after : %d\n", env->_inbufsz);
- printf("c_client: env->_outbuf after : %d\n", env->_outbufsz);
-
- CORBA_free(env->_inbuf);
- CORBA_free(env->_outbuf);
- CORBA_free(env);
- done(tres);
-}
-
-static void usage()
-{
- fprintf(stderr, "Usage: %s [-help] -this-node-name <name> "
- "-peer-node <nodename> -peer-process-name <name> "
- "-cookie <cookie> -test-case <test case name>\n", progname);
- fprintf(stderr, "Example:\n %s -this-node-name kalle "
- "-peer-node olle@home -peer-process-name idltest "
- "-cookie oa678er -test-case octet_test\n", progname);
-}
-
-static void done(int r)
-{
-#ifdef __WIN32__
- WSACleanup();
-#endif
- exit(r);
-}
-
-
-/* TESTS */
-
-static int void_test(IC_Env *env)
-{
- fprintf(stdout, "\n======== m_i_void test ======\n\n");
- m_i_void_test(NULL,env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(1);
-}
-
-static int long_test(IC_Env *env)
-{
- long l = 4711, lo, lr;
-
- fprintf(stdout, "\n======== m_i_long test ======\n\n");
- lr = m_i_long_test(NULL, l, &lo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(l == lo && l == lr);
- if (l != lo)
- fprintf(stdout, " out parameter error, sent: %ld, got: %ld\n", l, lo);
- if (l != lr)
- fprintf(stdout, " result error, sent: %ld, got: %ld\n", l, lr);
- return -1;
-}
-
-static int long_long_test(IC_Env *env)
-{
- CORBA_long_long ll = 4711, llo, llr;
-
- fprintf(stdout, "\n======== m_i_longlong test ======\n\n");
- llr = m_i_longlong_test(NULL, ll, &llo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(ll == llo && ll == llr);
- if (ll != llo)
- fprintf(stdout, " out parameter error, sent: %ld, got: %ld\n",
- ll, llo);
- if (ll != llr)
- fprintf(stdout, " result error, sent: %ld, got: %ld\n", ll, llr);
- return -1;
-}
-
-static int unsigned_short_test(IC_Env *env)
-{
- unsigned short x, y = 2, z;
-
- fprintf(stdout, "\n======== m_i_ushort test ======\n\n");
- x = m_i_ushort_test(NULL, y, &z, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(y == z && y == x);
- if (y != z)
- fprintf(stdout, " out parameter error, sent: %d, got: %d\n", y, z);
- if (y != x)
- fprintf(stdout, " result error, sent: %d, got: %d\n", y, x);
- return -1;
-}
-
-
-static int unsigned_long_test(IC_Env *env)
-{
- unsigned long ul = 5050, ulo, ulr;
-
- fprintf(stdout, "\n======== m_i_ulong test ======\n\n");
- ulr = m_i_ulong_test(NULL, ul, &ulo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(ul == ulo && ul == ulr);
- if (ul != ulo)
- fprintf(stdout, " out parameter error, sent: %lu, got: %lu\n",
- ul, ulo);
- if (ul != ulr)
- fprintf(stdout, " result error, sent: %lu, got: %lu\n", ul, ulr);
- return -1;
-}
-
-/*
- * Note: CORBA_unsigned_long_long is in fact a plain long.
- */
-static int unsigned_long_long_test(IC_Env *env)
-{
- CORBA_unsigned_long_long ull = 5050, ullo, ullr;
-
- fprintf(stdout, "\n======== m_i_ulonglong test ======\n\n");
- ullr = m_i_ulonglong_test(NULL, ull, &ullo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(ull == ullo && ull == ullr);
- if (ull != ullo)
- fprintf(stdout, " out parameter error, sent: %lu, got: %lu\n",
- ull, ullo);
- if (ull != ullr)
- fprintf(stdout, " result error, sent: %lu, got: %lu\n",
- ull, ullr);
- return -1;
-}
-
-static int double_test(IC_Env *env)
-{
- double d = 12.1212, db, dr;
-
- fprintf(stdout, "\n======== m_i_double test ======\n\n");
- dr = m_i_double_test(NULL, d, &db, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(d == db && d == dr);
- if (d != db)
- fprintf(stdout, " out parameter error, sent: %f, got: %f\n", d, db);
- if (d != dr)
- fprintf(stdout, " result error, sent: %f, got: %f\n", d, dr);
- return -1;
-}
-
-static int char_test(IC_Env *env)
-{
- char c = 'g', co, cr;
-
- /* char test */
- fprintf(stdout, "\n======== m_i_char test ======\n\n");
- cr = m_i_char_test(NULL, c, &co, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(c == co && c == cr);
- if (c !=co)
- fprintf(stdout, " out parameter error, sent: %c, got: %c\n", c, co);
- if (c != cr)
- fprintf(stdout, " result error, sent: %c, got: %c\n", c, cr);
- return -1;
-}
-
-static int wchar_test(IC_Env *env)
-{
- CORBA_wchar wc = 103, wco, wcr;
-
- fprintf(stdout, "\n======== m_i_wchar test ======\n\n");
- wcr = m_i_wchar_test(NULL, wc, &wco, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(wc == wco && wc == wcr);
- if (wc != wco)
- fprintf(stdout, " out parameter error, sent: %lu, got: %lu\n",
- wc, wco);
- if (wc != wcr)
- fprintf(stdout, " result error, sent: %lu, got: %lu\n",
- wc, wcr);
- return -1;
-}
-
-static int octet_test(IC_Env *env)
-{
- char o ='r', oo, or;
-
- fprintf(stdout, "\n======== m_i_octet test ======\n\n");
- or = m_i_octet_test(NULL, o, &oo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(o == oo && o == or);
- if (o != oo)
- fprintf(stdout, " out parameter error, sent: %c, got: %c\n", o, oo);
- if (o != or)
- fprintf(stdout, " result error, sent: %c, got: %c\n", o, or);
- return -1;
-}
-
-static int bool_test(IC_Env *env)
-{
- unsigned char i = 0, io, ir;
-
- fprintf(stdout, "\n======== m_i_bool test ======\n\n");
- ir = m_i_bool_test(NULL, i, &io, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(i == io && i == ir);
- if (i != io)
- fprintf(stdout, " out parameter error, sent: %d, got: %d\n", i, io);
- if (i != ir)
- fprintf(stdout, " result error, sent: %d, got: %d\n", i, ir);
- return -1;
-}
-
-static int struct_test(IC_Env *env)
-{
- m_b b = {4711, 'a'}, bo, br;
-
- fprintf(stdout, "\n======== m_i_struct test ======\n\n");
- br = m_i_struct_test(NULL, &b, &bo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_b(&b, &bo) && cmp_b(&b, &br));
- if (!cmp_b(&b, &bo)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_b(&b);
- fprintf(stdout, " got:\n");
- print_b(&bo);
- fprintf(stdout, "\n");
- }
- if (!cmp_b(&b, &br)) {
- fprintf(stdout, " result error, sent:\n");
- print_b(&b);
- fprintf(stdout, " got:\n");
- print_b(&br);
- fprintf(stdout, "\n");
- }
- return -1;
-}
-
-static int struct2_test(IC_Env *env)
-{
- m_es esi = {m_peach, 5050}, eso, esr;
-
- fprintf(stdout, "\n======== m_i_struct2 test ======\n\n");
- esr = m_i_struct2_test(NULL, &esi, &eso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_es(&esi, &eso) && cmp_es(&esi, &esr));
- if (!cmp_es(&esi, &eso)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_es(&esi);
- fprintf(stdout, " got:\n");
- print_es(&eso);
- fprintf(stdout, "\n");
- }
- if (!cmp_es(&esi, &esr)) {
- fprintf(stdout, " result error, sent:\n");
- print_es(&esi);
- fprintf(stdout, " got:\n");
- print_es(&esr);
- fprintf(stdout, "\n");
- }
- return -1;
-}
-
-
-static int seq1_test(IC_Env *env)
-{
- m_bseq bs, *bso, *bsr;
-
- m_b ba[3] = {{4711, 'a'}, {4712, 'b'}, {4713, 'c'}};
- bs._length = 3;
- bs._buffer = ba;
-
- fprintf(stdout, "\n======== m_i_seq1 test ======\n\n");
- bsr = m_i_seq1_test(NULL, &bs, &bso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_bseq(&bs, bso) && cmp_bseq(&bs, bsr));
- if (!cmp_bseq(&bs, bso)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_bseq(&bs);
- fprintf(stdout, " got:\n");
- print_bseq(bso);
- fprintf(stdout, "\n");
- }
- if (!cmp_bseq(&bs, bsr)) {
- fprintf(stdout, " result error, sent:\n");
- print_bseq(&bs);
- fprintf(stdout, " got:\n");
- print_bseq(bsr);
- fprintf(stdout, "\n");
- }
- CORBA_free(bso);
- CORBA_free(bsr);
- return -1;
-}
-
-static int seq2_test(IC_Env *env)
-{
- m_b ba[3] = {{4711, 'a'}, {4712, 'b'}, {4713, 'c'}};
- m_a a;
- m_a aa[2];
- m_aseq as, *aso, *asr;
-
- a.l = 9999;
- a.y._length = 3;
- a.y._buffer = ba;
- a.d = 66.89898989;
-
- aa[0] = a;
- aa[1] = a;
- as._length = 2;
- as._buffer = aa;
-
- fprintf(stdout, "\n======== m_i_seq2 test ======\n\n");
- asr = m_i_seq2_test(NULL, &as, &aso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_aseq(&as, aso) && cmp_aseq(&as, asr));
- if (!cmp_aseq(&as, aso)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_aseq(&as);
- fprintf(stdout, " got:\n");
- print_aseq(aso);
- fprintf(stdout, "\n");
- }
- if (!cmp_aseq(&as, asr)) {
- fprintf(stdout, " result error, sent:\n");
- print_aseq(&as);
- fprintf(stdout, " got:\n");
- print_aseq(asr);
- fprintf(stdout, "\n");
- }
- CORBA_free(aso);
- CORBA_free(asr);
- return -1;
-}
-
-static int seq3_test(IC_Env *env)
-{
- m_lseq lsi, *lso, *lsr;
- long al[500];
- int i=0;
-
- for (i = 0; i < 500; i++)
- al[i]=i;
- lsi._length = 500;
- lsi._buffer = al;
-
- fprintf(stdout, "\n======== m_i_seq3 test ======\n\n");
- lsr = m_i_seq3_test(NULL, &lsi, &lso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_lseq(&lsi, lso) && cmp_lseq(&lsi, lsr));
- if (!cmp_lseq(&lsi, lso)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_lseq(&lsi);
- fprintf(stdout, " got:\n");
- print_lseq(lso);
- fprintf(stdout, "\n");
- }
- if (!cmp_lseq(&lsi, lsr)) {
- fprintf(stdout, " result error, sent:\n");
- print_lseq(&lsi);
- fprintf(stdout, " got:\n");
- print_lseq(lsr);
- fprintf(stdout, "\n");
- }
- CORBA_free(lso);
- CORBA_free(lsr);
- return -1;
-}
-
-static int seq4_test(IC_Env *env)
-{
- char *stra0[3] = {"a", "long", "time"};
- char *stra1[3] = {"ago", "there", "was"};
- char *stra2[3] = {"a", "buggy", "compiler"};
- m_sstr3 str3s[3] = {{3, 3, stra0}, {3, 3, stra1}, {3, 3, stra2}};
- m_ssstr3 str3ssi = {3, 3, str3s};
- m_ssstr3 *str3sso, *str3ssr;
-
- fprintf(stdout, "\n======== m_i_seq4 test ======\n\n");
- str3ssr = m_i_seq4_test(NULL, &str3ssi, &str3sso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_ssstr3(&str3ssi, str3sso) &&
- cmp_ssstr3(&str3ssi, str3ssr));
- if (!cmp_ssstr3(&str3ssi, str3sso)){
- fprintf(stdout, " out parameter error, sent:\n");
- print_ssstr3(&str3ssi);
- fprintf(stdout, " got:\n");
- print_ssstr3(str3sso);
- fprintf(stdout, "\n");
- }
- if (!cmp_ssstr3(&str3ssi, str3ssr)) {
- fprintf(stdout, " result error, sent:\n");
- print_ssstr3(&str3ssi);
- fprintf(stdout, " got:\n");
- print_ssstr3(str3ssr);
- fprintf(stdout, "\n");
- }
- CORBA_free(str3sso);
- CORBA_free(str3ssr);
- return -1;
-}
-
-static int seq5_test(IC_Env *env)
-{
- m_arr3 arr3a[3] = {
- {4711, 18931947, 3},
- {4711, 18931947, 3},
- {4711, 18931947, 3}};
- m_sarr3 arr3sa[3] = {{3, 3, arr3a}, {3, 3, arr3a}, {3, 3, arr3a}};
- m_ssarr3 arr3ssi = {3, 3, arr3sa};
- m_ssarr3 *arr3sso;
- m_ssarr3 *arr3ssr;
-
- fprintf(stdout, "\n======== m_i_seq5 test ======\n\n");
- arr3ssr = m_i_seq5_test(NULL, &arr3ssi, &arr3sso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_ssarr3(&arr3ssi, arr3sso) &&
- cmp_ssarr3(&arr3ssi, arr3ssr));
- if (!cmp_ssarr3(&arr3ssi, arr3sso)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_ssarr3(&arr3ssi);
- fprintf(stdout, " got:\n");
- print_ssarr3(arr3sso);
- fprintf(stdout, "\n");
- }
- if (!cmp_ssarr3(&arr3ssi, arr3ssr)) {
- fprintf(stdout, " result error, sent:\n");
- print_ssarr3(&arr3ssi);
- fprintf(stdout, " got:\n");
- print_ssarr3(arr3ssr);
- fprintf(stdout, "\n");
- }
- CORBA_free(arr3sso);
- CORBA_free(arr3ssr);
- return -1;
-}
-
-static int array1_test(IC_Env *env)
-{
- int i;
- long al[500];
- m_arr1 alo;
- m_arr1_slice* alr;
-
- for (i = 0; i < 500; i++)
- al[i]=i;
-
- fprintf(stdout, "\n======== m_i_array1 test ======\n\n");
- alr = m_i_array1_test(NULL, al, alo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_arr1(al, alo) && cmp_arr1(al, alr));
- if (!cmp_arr1(al, alo)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_arr1(al);
- fprintf(stdout, " got:\n");
- print_arr1(alo);
- fprintf(stdout, "\n");
- }
- if (!cmp_arr1(al,alr)) {
- fprintf(stdout, " result error, sent:\n");
- print_arr1(al);
- fprintf(stdout, " got:\n");
- print_arr1(alr);
- fprintf(stdout, "\n");
- }
- free(alr);
- return -1;
-}
-
-static int array2_test(IC_Env *env)
-{
- long dl[2][3] = {{11, 2, 7}, {22, 8 ,13}};
- m_dd dlo;
- m_dd_slice* dlr;
-
- fprintf(stdout, "\n======== m_i_array2 test ======\n\n");
- dlr = m_i_array2_test(NULL, dl, dlo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_dd(dl,dlo) && cmp_dd(dl,dlr));
- if (!cmp_dd(dl,dlo)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_dd(dl);
- fprintf(stdout, " got:\n");
- print_dd(dlo);
- fprintf(stdout, "\n");
- }
- if (!cmp_dd(dl,dlr)) {
- fprintf(stdout, " result error, sent:\n");
- print_dd(dl);
- fprintf(stdout, " got:\n");
- print_dd(dlr);
- fprintf(stdout, "\n");
- }
- free(*dlr);
- return -1;
-}
-
-static int enum_test(IC_Env *env)
-{
- m_fruit ei = m_banana, eo, er;
-
- fprintf(stdout, "\n======== m_i_enum test ======\n\n");
- er = m_i_enum_test(NULL, ei, &eo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(ei == eo && ei == er);
- if (ei != eo)
- fprintf(stdout, " out parameter error, sent: %d, got: %d\n", ei, eo);
- if (ei != er)
- fprintf(stdout, " result error, sent: %d, got: %d\n", ei, er);
- return -1;
-}
-
-static int string1_test(IC_Env *env)
-{
- char* si = longtext;
- char* so;
- char* sr;
-
- fprintf(stdout, "\n======== m_i_string1 test ======\n\n");
- sr = m_i_string1_test(NULL, si, &so, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_str(si, so) && cmp_str(si, sr));
- if (!cmp_str(si, so))
- fprintf(stdout, " out parameter error, sent: %s, got: %s\n", si, so);
- if (!cmp_str(si, sr))
- fprintf(stdout, " result error, sent: %s, got: %s\n", si, sr);
- CORBA_free(so);
- CORBA_free(sr);
- return -1;
-}
-
-static int string2_test(IC_Env *env)
-{
- char* sa[3] = {"hello", "foo", "bar"};
- m_sseq ssi = {3, 3, sa};
- m_sseq *sso, *ssr;
-
- fprintf(stdout, "\n======== m_i_string2 test ======\n\n");
- ssr = m_i_string2_test(NULL, &ssi, &sso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_sseq(&ssi, sso) && cmp_sseq(&ssi, sso));
- if (!cmp_sseq(&ssi, sso)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_sseq(&ssi);
- fprintf(stdout, "got:\n");
- print_sseq(sso);
- }
- if (!cmp_sseq(&ssi, ssr)) {
- fprintf(stdout, " result error, sent:\n");
- print_sseq(&ssi);
- fprintf(stdout, "got:\n");
- print_sseq(ssr);
- }
- CORBA_free(sso);
- CORBA_free(ssr);
- return -1;
-}
-
-static int string3_test(IC_Env *env)
-{
- char* si = longtext;
- char* so;
- char* sr;
-
- fprintf(stdout, "\n======== m_i_string3 test ======\n\n");
- sr = m_i_string3_test(NULL, si, &so, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_str(si, so) && cmp_str(si, so));
- if (!cmp_str(si, so))
- fprintf(stdout, " out parameter error, sent: %s, got: %s\n", si, so);
- if (!cmp_str(si, sr))
- fprintf(stdout, " result error, sent: %s, got: %s\n", si, sr);
- CORBA_free(so);
- CORBA_free(sr);
- return -1;
-}
-
-static int string4_test(IC_Env *env)
-{
- char as1[100] = "a string", as2[200] = "help", as3[200] = "hello there";
- m_strRec stri = { 1, /* dd */
- as1, /* str4 */
- {{'a', 'k'}, {'z', 'g'}, {'n', 'q'}}, /* str7 */
- {3, 3, "buf"}, /* str5 */
- as2, /* str6 */
- {'m', 'f', 'o'}, /* str8 */
- as3, /* str9 */
- {3, 3, "stu"} /* str10 */
- };
- m_strRec *stro, *strr;
-
- fprintf(stdout, "\n======== m_i_string4 test ======\n\n");
- strr = m_i_string4_test(NULL, &stri, &stro, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_strRec(&stri,stro) && cmp_strRec(&stri,strr));
- if (!cmp_strRec(&stri,stro)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_strRec(&stri);
- fprintf(stdout, " got:\n");
- print_strRec(stro);
- fprintf(stdout, "\n");
- }
- if (!cmp_strRec(&stri,strr)) {
- fprintf(stdout, " result error, sent:\n");
- print_strRec(&stri);
- fprintf(stdout, " got:\n");
- print_strRec(strr);
- fprintf(stdout, "\n");
- }
- CORBA_free(stro);
- CORBA_free(strr);
- return -1;
-}
-
-
-static int pid_test(IC_Env *env)
-{
- erlang_pid pid = {"", 7, 0, 0}, pido, pidr;
-
- strcpy(pid.node, this_node), /* this currently running node */
- fprintf(stdout, "\n======== m_i_pid test ======\n\n");
- pidr = m_i_pid_test(NULL, &pid, &pido, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_pid(&pid, &pido) && cmp_pid(&pid, &pidr));
- if (!cmp_pid(&pid, &pido)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_pid(&pid);
- fprintf(stdout, "got:\n");
- print_pid(&pido);
- }
- if (!cmp_pid(&pid, &pidr)) {
- fprintf(stdout, " result error, sent:\n");
- print_pid(&pid);
- fprintf(stdout, "got:\n");
- print_pid(&pidr);
- }
- return -1;
-}
-
-static int port_test(IC_Env *env)
-{
- erlang_port porti = {"node", 5, 1}, porto, portr;
-
- fprintf(stdout, "\n======== m_i_port test ======\n\n");
- portr = m_i_port_test(NULL, &porti, &porto, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_port(&porti, &porto) && cmp_port(&porti, &portr));
- if (!cmp_port(&porti, &porto)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_port(&porti);
- fprintf(stdout, "got:\n");
- print_port(&porto);
- }
- if (!cmp_port(&porti, &portr)) {
- fprintf(stdout, " result error, sent:\n");
- print_port(&porti);
- fprintf(stdout, "got:\n");
- print_port(&portr);
- }
- return -1;
-}
-
-static int ref_test(IC_Env *env)
-{
- erlang_ref refi = { "node1", 3, {1, 2, 3}, 1},
- refo, refr;
-
- fprintf(stdout, "\n======== m_i_ref test ======\n\n");
- refr = m_i_ref_test(NULL, &refi, &refo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_ref(&refi, &refo) && cmp_ref(&refi, &refr));
- if (!cmp_ref(&refi, &refo)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_ref(&refi);
- fprintf(stdout, "got:\n");
- print_ref(&refo);
- }
- if (!cmp_ref(&refi, &refr)) {
- fprintf(stdout, " result error, sent:\n");
- print_ref(&refi);
- fprintf(stdout, "got:\n");
- print_ref(&refr);
- }
- return -1;
-}
-
-static int term_test(IC_Env *env)
-{
- ETERM *ti, *to, *tr;
-
- ti = erl_format("[{hej, 1, 23}, \"string\", {1.23, 45}]");
-
- fprintf(stdout, "\n======== m_i_term test ======\n\n");
- tr = m_i_term_test(NULL, ti, &to, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(erl_match(ti, to) && erl_match(ti, tr));
- if (!erl_match(ti, to)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_term(ti);
- fprintf(stdout, "got:\n");
- print_term(to);
- }
- if (!erl_match(ti, tr)) {
- fprintf(stdout, " result error, sent:\n");
- print_term(ti);
- fprintf(stdout, "got:\n");
- print_term(tr);
- }
- erl_free_term(ti);
- erl_free_term(to);
- erl_free_term(tr);
- return -1;
-}
-
-static int typedef_test(IC_Env *env)
-{
- m_banan mbi, mbo; /* erlang_port */
- m_apa mai; /* ETERM* */
- m_apa mao = NULL;
- long tl;
-
- strcpy(mbi.node,"node");
- mbi.id = 15;
- mbi.creation = 1;
-
- fprintf(stdout, "\n======== m_i_typedef test ======\n\n");
- mai = erl_format("[{hej, 1, 23}, \"string\", {1.23, 45}]");
- tl = m_i_typedef_test(NULL, mai, &mbi, &mao, &mbo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(erl_match(mai, mao) && cmp_port(&mbi, &mbo) && tl == 4711);
- if (!erl_match(mai, mao)) {
- fprintf(stdout, " out parameter error (term), sent:\n");
- print_term(mai);
- fprintf(stdout, "got:\n");
- print_term(mao);
- }
- if (!cmp_port(&mbi, &mbo)) {
- fprintf(stdout, " out parameter error (port), sent:\n");
- print_port(&mbi);
- fprintf(stdout, "got:\n");
- print_port(&mbo);
- }
- if (tl != 4711) {
- fprintf(stdout, " result error, sent: 4711, got %ld\n", tl);
- }
- erl_free_term(mai);
- erl_free_term(mao);
- return -1;
-}
-
-static int inline_sequence_test(IC_Env *env)
-{
- int i;
- long al[500];
- m_s isi = {4711, {500, 10, al}},
- *iso, *isr;
-
- for (i = 0; i < 500; i++)
- al[i]=i;
- fprintf(stdout, "\n======== m_i_inline_sequence test ======\n\n");
- isr = m_i_inline_sequence_test(NULL, &isi, &iso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_s(&isi, iso) && cmp_s(&isi, isr));
- if (!cmp_s(&isi, iso)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_s(&isi);
- fprintf(stdout, "got:\n");
- print_s(iso);
- }
- if (!cmp_s(&isi, isr)) {
- fprintf(stdout, " result error, sent:\n");
- print_s(&isi);
- fprintf(stdout, "got:\n");
- print_s(isr);
- }
- CORBA_free(iso);
- CORBA_free(isr);
- return -1;
-}
-
-static int term_sequence_test(IC_Env *env)
-{
- ETERM* et_array[4] = {
- erl_format("[{apa, 1, 23}, \"string\", {1.23, 45}]"),
- erl_format("[{banan, 1, 23}, \"string\", {1.23, 45}]"),
- erl_format("[{apelsin, 1, 23}, \"string\", {1.23, 45}]"),
- erl_format("[{mango, 1, 23}, \"string\", {1.23, 45}]")};
- m_etseq etsi = {4, 4, et_array}, *etso, *etsr;
-
- fprintf(stdout, "\n======== m_i_term_sequence test ======\n\n");
- etsr = m_i_term_sequence_test(NULL, &etsi, &etso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_etseq(&etsi, etso) && cmp_etseq(&etsi, etsr));
- if (!cmp_etseq(&etsi, etso)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_etseq(&etsi);
- fprintf(stdout, "got:\n");
- print_etseq(etso);
- }
- if (!cmp_etseq(&etsi, etsr)) {
- fprintf(stdout, " result error, sent:\n");
- print_etseq(&etsi);
- fprintf(stdout, "got:\n");
- print_etseq(etsr);
- }
- free_etseq_buf(&etsi);
- free_etseq_buf(etso);
- free_etseq_buf(etsr);
- CORBA_free(etso);
- CORBA_free(etsr);
- return -1;
-}
-
-static int term_struct_test(IC_Env *env)
-{
- m_et eti = { erl_format("[{hej, 1, 23}, \"string\", {1.23, 45}]"),
- 121212 };
- m_et eto, etr;
-
- fprintf(stdout, "\n======== m_i_term_struct test ======\n\n");
- etr = m_i_term_struct_test(NULL, &eti, &eto, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_et(&eti, &eto) && cmp_et(&eti, &etr));
- if (!cmp_et(&eti, &eto)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_et(&eti);
- fprintf(stdout, "got:\n");
- print_et(&eto);
- }
- if (!cmp_et(&eti, &etr)) {
- fprintf(stdout, " result error, sent:\n");
- print_et(&eti);
- fprintf(stdout, "got:\n");
- print_et(&etr);
- }
- free_et(&eti);
- free_et(&eto);
- free_et(&etr);
- return -1;
-}
-
-static int wstring1_test(IC_Env *env)
-{
- CORBA_wchar wsi[] = {100, 101, 102, 103, 104, 0}, *wso, *wsr;
-
- fprintf(stdout, "\n======== m_i_wstring1 test ======\n\n");
- wsr = m_i_wstring1_test(NULL, wsi, &wso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_wstr(wsi, wso) && cmp_wstr(wsi, wsr));
- if (!cmp_wstr(wsi, wso)) {
- fprintf(stdout, " out parameter error, sent: \n");
- print_wstr(wsi);
- fprintf(stdout, "got:\n");
- print_wstr(wso);
- }
- if (!cmp_wstr(wsi, wsr)) {
- fprintf(stdout, " result error, sent: \n");
- print_wstr(wsi);
- fprintf(stdout, "got:\n");
- print_wstr(wsr);
- }
- CORBA_free(wso);
- CORBA_free(wsr);
- return -1;
-}
-
-/* Compare functions */
-static int cmp_aseq(m_aseq *a1, m_aseq *a2)
-{
- int i;
-
- if (a1->_length != a2->_length)
- return 0;
- for (i = 0; i < a1->_length; i++)
- if (cmp_a(&(a1->_buffer[i]), &(a2->_buffer[i])) == 0)
- return 0;
- return 1;
-}
-
-static int cmp_a(m_a *a1, m_a *a2)
-{
- return a1->l == a2->l &&
- a1->d == a2->d &&
- cmp_bseq(&a1->y, &a2->y);
-}
-
-static int cmp_bseq(m_bseq *b1, m_bseq *b2)
-{
- int i;
-
- if (b1->_length != b2->_length)
- return 0;
- for (i = 0; i < b1->_length; i++)
- if (cmp_b(&(b1->_buffer[i]), &(b2->_buffer[i])) == 0)
- return 0;
- return 1;
-}
-
-static int cmp_b(m_b *b1, m_b *b2)
-{
- return b1->l == b2->l && b1->c == b2->c;
-}
-
-static int cmp_lseq(m_lseq *b1, m_lseq *b2)
-{
- int i;
-
- if (b1->_length != b2->_length)
- return 0;
- for (i = 0; i < b1->_length; i++)
- if (b1->_buffer[i] != b2->_buffer[i])
- return 0;
- return 1;
-}
-
-static int cmp_etseq(m_etseq *b1, m_etseq *b2)
-{
- int i;
-
- if (b1->_length != b2->_length)
- return 0;
- for (i = 0; i < b1->_length; i++)
- if (!erl_match(b1->_buffer[i], b2->_buffer[i]))
- return 0;
- return 1;
-}
-
-static int cmp_et(m_et* b1, m_et *b2)
-{
- return erl_match(b1->e, b2->e) && b1->l == b2->l;
-}
-
-static int cmp_es(m_es *b1, m_es *b2)
-{
- return b1->f == b2->f && b1->l == b2->l;
-}
-
-static int cmp_arr1(m_arr1 b1, m_arr1 b2)
-{
- int i;
-
- for (i = 0; i < 500; i++)
- if (b1[i] != b2[i])
- return 0;
- return 1;
-}
-
-static int cmp_dd(m_dd b1, m_dd b2)
-{
-
- int i, j;
-
- for (i = 0; i < 2; i++)
- for (j = 0; j < 3; j++)
- if (b1[i][j] != b2[i][j])
- return 0;
- return 1;
-}
-
-
-
-static int cmp_strRec(m_strRec *b1, m_strRec *b2)
-{
- int i, j;
-
- if (b1->bb != b2->bb)
- return 0;
- if (!cmp_str(b1->str4,b2->str4))
- return 0;
- if (b1->str5._length != b2->str5._length)
- return 0;
- for (j = 0; j < b1->str5._length; j++)
- if (b1->str5._buffer[j] != b2->str5._buffer[j])
- return 0;
- if (!cmp_str(b1->str6,b2->str6))
- return 0;
- for (i = 0; i < 3; i++)
- for (j = 0; j < 2; j++)
- if (b1->str7[i][j] != b2->str7[i][j])
- return 0;
- for (j = 0; j < 3; j++)
- if (b1->str8[j] != b2->str8[j])
- return 0;
- if (!cmp_str(b1->str9,b2->str9))
- return 0;
- if (b1->str10._length != b2->str10._length)
- return 0;
- for (j = 0; j < b1->str10._length; j++)
- if (b1->str10._buffer[j] != b2->str10._buffer[j])
- return 0;
- return 1;
-}
-
-
-static int cmp_sseq(m_sseq *b1, m_sseq *b2)
-{
- int i;
-
- if (b1->_length != b2->_length)
- return 0;
- for (i = 0; i < b1->_length; i++)
- if (!cmp_str(b1->_buffer[i], b2->_buffer[i]))
- return 0;
- return 1;
-}
-
-
-static int cmp_pid(erlang_pid *p1, erlang_pid *p2)
-{
- return cmp_str(p1->node,p2-> node) &&
- p1->num == p2->num &&
- p1->serial == p2->serial &&
- p1->creation == p2->creation;
-}
-
-static int cmp_port(erlang_port *p1, erlang_port *p2)
-{
- return cmp_str(p1->node,p2-> node) && p1->id == p2->id;
-}
-
-static int cmp_ref(erlang_ref *p1, erlang_ref *p2)
-{
- return cmp_str(p1->node, p2->node) &&
- p1->len == p2->len &&
- (p1->len < 1 || p1->n[0] == p2->n[0]) &&
- (p1->len < 2 || p1->n[1] == p2->n[1]) &&
- (p1->len < 3 || p1->n[2] == p2->n[2]);
-}
-
-static int cmp_s(m_s *b1, m_s *b2)
-{
- int i;
-
- if (b1->l != b2->l)
- return 0;
- if (b1->sl._length != b2->sl._length)
- return 0;
- for (i = 0; i < b1->sl._length; i++)
- if (b1->sl._buffer[i] != b2->sl._buffer[i])
- return 0;
- return 1;
-}
-
-
-static int cmp_ssstr3(m_ssstr3 *b1, m_ssstr3 *b2)
-{
- int i,j;
-
- if (b1->_length != b2->_length)
- return 0;
- for (i = 0; i < b1->_length; i++) {
- if (b1->_buffer[i]._length != b2->_buffer[i]._length)
- return 0;
- for (j = 0; j < b1->_buffer[i]._length; j++)
- if (!cmp_str(b1->_buffer[i]._buffer[j],
- b2->_buffer[i]._buffer[j]))
- return 0;
- }
- return 1;
-}
-
-
-
-static int cmp_ssarr3(m_ssarr3 *b1, m_ssarr3 *b2)
-{
- int i;
-
- if (b1->_length != b2->_length)
- return 0;
- for (i = 0; i < b1->_length; i++) {
- if (!cmp_sarr3(&b1->_buffer[i], &b2->_buffer[i]))
- return 0;
- }
- return 1;
-}
-
-static int cmp_sarr3(m_sarr3 *b1, m_sarr3 *b2)
-{
- int i;
-
- if (b1->_length != b2->_length)
- return 0;
- for (i = 0; i < b1->_length; i++) {
- if (!cmp_arr3(b1->_buffer[i], b2->_buffer[i]))
- return 0;
- }
- return 1;
-}
-
-static int cmp_arr3(m_arr3 b1, m_arr3 b2)
-{
- int i;
-
- for (i = 0; i < sizeof(m_arr3)/sizeof(CORBA_long); i++) {
- if (b1[i] != b2[i])
- return 0;
- }
- return 1;
-}
-
-/* Print functions */
-static void print_aseq(m_aseq *a)
-{
- int i;
- fprintf(stdout, "\nm_aseq size: %ld --------\n", a->_length);
- for (i = 0; i < a->_length; i++)
- print_a(&(a->_buffer[i]));
-}
-
-static void print_a(m_a *a)
-{
- fprintf(stdout, "\nm_a --------\n l: %ld\n d:%f\n", a->l, a->d);
- print_bseq(&a->y);
-}
-
-static void print_bseq(m_bseq *b)
-{
- int i;
-
- fprintf(stdout, "\nm_bseq size: %ld --------\n",b->_length);
- for (i = 0; i < b->_length; i++)
- print_b(&(b->_buffer[i]));
-}
-
-static void print_lseq(m_lseq *b)
-{
- int i;
-
- fprintf(stdout, "\nm_lseq size: %ld --------\n",b->_length);
- for (i = 0; i < b->_length; i++)
- fprintf(stdout, "[%d]: %ld\n", i, b->_buffer[i]);
-}
-
-static void print_b(m_b *b)
-{
- fprintf(stdout, "\nm_b --------\n l: %ld\n c: %c\n", b->l, b->c);
-}
-
-
-static void print_etseq(m_etseq *b)
-{
- int i;
-
- for (i = 0; i < b->_length; i++) {
- fprintf(stdout, "[%d]:\n", i);
- erl_print_term(stdout, b->_buffer[i]);
- }
-}
-
-
-static void print_et(m_et* b)
-{
- fprintf(stdout, "\net struct --------\n");
- erl_print_term(stdout, b->e);
- fprintf(stdout, "long: %ld\n", b->l);
- fprintf(stdout, "\n--------\n");
-}
-
-static void print_es(m_es *b)
-{
- fprintf(stdout, "\nm_es --------\n f: %d\n l: %ld\n", b->f, b->l);
-}
-
-
-static void print_arr1(long a[10])
-{
- int i;
-
- for (i = 0; i < 10; i++)
- fprintf(stdout, "\n[%d]: %ld\n", i, a[i]);
-}
-
-static void print_dd(long a[2][3])
-{
- int i, j;
-
- fprintf(stdout, "\nlong dd[2][3] --------\n");
- for (i = 0; i < 2; i++)
- for (j = 0; j < 3; j++)
- fprintf(stdout, "\n[%d][%d]: %ld\n", i, j, a[i][j]);
-}
-
-
-static void print_strRec(m_strRec* sr)
-{
- int i, j;
-
- fprintf(stdout, "\nboolean bb : %d\n",sr->bb);
- fprintf(stdout, "string str4 : %s\n",sr->str4);
- fprintf(stdout, "str7[2][3] :\n");
- for (i = 0; i < 3; i++)
- for (j = 0; j < 2; j++)
- fprintf(stdout, "str7[%d][%d]: %ld\n", i, j, sr->str7[i][j]);
- fprintf(stdout, "str5._length : %ld\n",sr->str5._length);
- for (j = 0; j < sr->str5._length; j++)
- fprintf(stdout, "str5._buffer[%d]: %c\n", j, sr->str5._buffer[j]);
- fprintf(stdout, "string str6 : %s\n",sr->str6);
- fprintf(stdout, "str8 :\n");
- for (j = 0; j < 3; j++)
- fprintf(stdout, "str8[%d]: %c\n", j, sr->str8[j]);
- fprintf(stdout, "string str9 : %s\n",sr->str9);
- fprintf(stdout, "str10._length : %ld\n",sr->str10._length);
- for (j = 0; j < sr->str10._length; j++)
- fprintf(stdout, "str10._buffer[%d]: %c\n", j, sr->str10._buffer[j]);
-}
-
-static void print_sseq(m_sseq *b)
-{
- int i;
-
- fprintf(stdout, "\nm_sseq size: %ld --------\n",b->_length);
- for (i = 0; i < b->_length; i++)
- fprintf(stdout, "%s\n", b->_buffer[i]);
-
-}
-
-
-static void print_pid(erlang_pid *p)
-{
- fprintf(stdout, "\nerlang_pid --------\n node: %s\n num: %d\n "
- "serial: %d\n creation: %d\n",
- p->node, p->num, p->serial, p->creation);
-}
-
-static void print_port(erlang_port *p)
-{
- fprintf(stdout, "\nerlang_port --------\n node: %s\n id: %d\n "
- "creation: %d\n", p->node, p->id, p->creation);
-}
-
-static void print_ref(erlang_ref *p)
-{
- fprintf(stdout, "\nerlang_ref --------\n node: %s\n len: %d\n "
- "n[0]: %d\n n[1]: %d\n n[2]: %d\n creation: %d\n",
- p->node, p->len, p->n[0], p->n[1], p->n[2], p->creation);
-}
-
-static void print_term(ETERM *t)
-{
- fprintf(stdout, "\nETERM --------\n");
- erl_print_term(stdout, t);
- fprintf(stdout, "\n--------\n");
-}
-
-static void print_s(m_s *p)
-{
- int i;
-
- fprintf(stdout, "\n%ld\n", p->l);
- for (i = 0; i < p->sl._length; i++)
- fprintf(stdout, "\n[%d]: %ld\n", i, p->sl._buffer[i]);
-}
-
-
-static void print_ssstr3(m_ssstr3 *b1)
-{
- int i,j;
-
- fprintf(stdout, "\nSSSTR3 --------\n");
- fprintf(stdout,"b1->_length = %ld\n",b1->_length);
- for (i = 0; i < b1->_length; i++) {
- fprintf(stdout,"\nb1->_buffer[%d]._length %ld\n",
- i, b1->_buffer[i]._length);
- for (j = 0; j < b1->_buffer[i]._length; j++)
- fprintf(stdout,"b1->_buffer[%d]._buffer[%d] = %s\n",
- i, j, b1->_buffer[i]._buffer[j]);
- }
- fprintf(stdout, "\n--------\n");
-}
-
-static void print_wstr(CORBA_wchar *ws)
-{
- int i = 0;
-
- fprintf(stdout, "\nwstr --------\n");
- while (ws[i]) {
- fprintf(stdout, "[%d]: %ld\n", i, ws[i]);
- i++;
- }
- fprintf(stdout, "\n--------\n");
-}
-
-
-static void print_ssarr3(m_ssarr3 *b1)
-{
- int i;
-
- fprintf(stdout, "\nssarr3 --------\n");
- fprintf(stdout,"length: %ld\n",b1->_length);
- fprintf(stdout, "buffer:\n");
- for (i = 0; i < b1->_length; i++)
- print_sarr3(&b1->_buffer[i]);
- fprintf(stdout, "\n--------\n");
-}
-
-static void print_sarr3(m_sarr3 *b1)
-{
- int i;
-
- fprintf(stdout, "\nsarr3 --------\n");
- fprintf(stdout,"length: %ld\n",b1->_length);
- fprintf(stdout, "buffer:\n");
- for (i = 0; i < b1->_length; i++)
- print_arr3(b1->_buffer[i]);
- fprintf(stdout, "\n--------\n");
-}
-
-static void print_arr3(m_arr3 b1)
-{
- int i;
-
- fprintf(stdout, "\narr3 --------\n");
- for (i = 0; i < sizeof(m_arr3)/sizeof(CORBA_long); i++)
- fprintf(stdout, "%ld ", b1[i]);
- fprintf(stdout, "\n--------\n");
-}
-
-static void free_etseq_buf(m_etseq *b)
-{
- int i;
-
- for (i = 0; i < b->_length; i++)
- erl_free_term(b->_buffer[i]);
-}
-
-static void free_et(m_et* b)
-{
- erl_free_term(b->e);
-}
-
-static void showtime(MyTimeval *start, MyTimeval *stop)
-{
- MyTimeval elapsed;
-
- elapsed.tv_sec = stop->tv_sec - start->tv_sec;
- elapsed.tv_usec = stop->tv_usec - start->tv_usec;
- while (elapsed.tv_usec < 0) {
- elapsed.tv_sec -= 1;
- elapsed.tv_usec += 1000000;
- }
- fprintf(stderr,"%ld.%06ld seconds\n",elapsed.tv_sec, elapsed.tv_usec);
-}
-
-static void my_gettimeofday(MyTimeval *tv)
-#ifdef __WIN32__
-#define EPOCH_JULIAN_DIFF 11644473600i64
-{
- SYSTEMTIME t;
- FILETIME ft;
- LONGLONG lft;
-
- GetSystemTime(&t);
- SystemTimeToFileTime(&t, &ft);
- memcpy(&lft, &ft, sizeof(lft));
- tv->tv_usec = (long) ((lft / 10i64) % 1000000i64);
- tv->tv_sec = (long) ((lft / 10000000i64) - EPOCH_JULIAN_DIFF);
-}
-#elif defined VXWORKS
-{
- int rate = sysClkRateGet(); /* Ticks per second */
- unsigned long ctick = tickGet();
- tv->tv_sec = ctick / rate; /* secs since reboot */
- tv->tv_usec = ((ctick - (tv->tv_sec * rate))*1000000)/rate;
-}
-#else
-{
- gettimeofday(tv, NULL);
-}
-#endif
diff --git a/lib/ic/test/c_client_erl_server_SUITE_data/c_erl_test.idl b/lib/ic/test/c_client_erl_server_SUITE_data/c_erl_test.idl
deleted file mode 100644
index 126389b01d..0000000000
--- a/lib/ic/test/c_client_erl_server_SUITE_data/c_erl_test.idl
+++ /dev/null
@@ -1,175 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 2001-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-#include "erlang.idl"
-
-
-const short TestConst = 1;
-
-module m {
-
- const short TestConst = 2;
-
- struct b {
- long l;
- char c;
- };
-
- struct simple {
- long l;
- b b_t;
- };
-
- enum fruit {orange, banana, apple, peach, pear};
-
- typedef sequence<long> lseq;
-
- typedef sequence<b> bseq;
-
- struct a {
- long l;
- bseq y;
- double d;
- };
-
- typedef sequence<a> aseq;
-
- typedef sequence<string> sseq;
- typedef string str;
- typedef long myLong;
-
- typedef long arr1[500], dd[2][3];
-
- typedef erlang::term apa;
- typedef erlang::port banan;
-
- typedef sequence<erlang::term> etseq;
-
- struct s {
- long l;
- sequence<long> sl;
- };
-
- struct es {
- fruit f;
- myLong l;
- };
-
- struct et {
- erlang::term e;
- long l;
- };
-
-
- typedef sequence<char> str1;
- typedef string<12> str2;
- typedef char str3[3];
-
- typedef sequence<string> sstr3; // sequence of string
- typedef sequence<sstr3> ssstr3; // sequence of sequences of strings
-
- typedef long arr3[3]; // array of long
- typedef sequence<arr3> sarr3; // sequence of array
- typedef sequence<sarr3> ssarr3; // sequence of sequnces of arrays of strings
-
- struct strRec{
- boolean bb;
- string str4;
- long str7[3][2];
- sequence<char> str5;
- string<12> str6;
- str3 str8;
- str2 str9;
- str1 str10;
- };
-
-
- struct dyn {
- long l;
- sequence<long> sl;
- };
- typedef dyn arr2[1][2];
-
-
- interface i {
-
- const short TestConst = 3;
-
- //arr2 suck(in arr2 x, out arr2 y );
-
- ///////////////////////////////// attribute long l;
-
- // simple types
- void void_test();
- long long_test(in long a, out long a1);
- long long longlong_test(in long long a, out long long a1);
- unsigned short ushort_test(in unsigned short a, out unsigned short a1);
- unsigned long ulong_test(in unsigned long a, out unsigned long a1);
- unsigned long long ulonglong_test(in unsigned long long a, out unsigned long long a1);
- double double_test(in double a, out double a1);
- char char_test(in char a, out char a1);
- wchar wchar_test(in wchar a, out wchar a1);
- octet octet_test(in octet a, out octet a1);
- boolean bool_test(in boolean a, out boolean a1);
-
- // Seq. and struct tests
- b struct_test(in b a, out b a1);
- es struct2_test(in es a, out es a1);
- //simple struct3_test(in simple x, out simple y);
- bseq seq1_test(in bseq a, out bseq a1);
- aseq seq2_test(in aseq a, out aseq a1);
- lseq seq3_test(in lseq a, out lseq a1);
- ssstr3 seq4_test(in ssstr3 a, out ssstr3 a1);
- ssarr3 seq5_test(in ssarr3 a, out ssarr3 a1);
-
- // Array tests
- arr1 array1_test(in arr1 a, out arr1 a1);
- dd array2_test(in dd a, out dd a1);
-
- // enum test
- fruit enum_test(in fruit a, out fruit a1);
-
- // string tests
- string string1_test(in string a, out string a1);
- wstring wstring1_test(in wstring a, out wstring a1);
- sseq string2_test(in sseq a, out sseq a1);
- str string3_test(in str a, out str a1);
- strRec string4_test(in strRec a, out strRec a1);
-
- // Special erlang types
- erlang::pid pid_test(in erlang::pid a, out erlang::pid a1);
- erlang::port port_test(in erlang::port a, out erlang::port a1);
- erlang::ref ref_test(in erlang::ref a, out erlang::ref a1);
- erlang::term term_test(in erlang::term a, out erlang::term a1);
-
- // typedef test
- long typedef_test(in apa a, in banan b, out apa a1, out banan b1);
-
- // inlined seq. test
- s inline_sequence_test(in s a, out s a1);
-
- // term seq. test
- etseq term_sequence_test(in etseq a, out etseq a1);
- // term struct test
- et term_struct_test(in et a, out et a1);
-
- };
-
-};
diff --git a/lib/ic/test/c_client_erl_server_SUITE_data/erl_server.erl b/lib/ic/test/c_client_erl_server_SUITE_data/erl_server.erl
deleted file mode 100644
index 159d3b9b89..0000000000
--- a/lib/ic/test/c_client_erl_server_SUITE_data/erl_server.erl
+++ /dev/null
@@ -1,29 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(erl_server).
-
--export([run/0, stop/0]).
-
-run() ->
- m_i:oe_create().
-
-stop() ->
- gen_server:cast(cidl_test, stop).
diff --git a/lib/ic/test/c_client_erl_server_SUITE_data/m_i_impl.erl b/lib/ic/test/c_client_erl_server_SUITE_data/m_i_impl.erl
deleted file mode 100644
index c530991058..0000000000
--- a/lib/ic/test/c_client_erl_server_SUITE_data/m_i_impl.erl
+++ /dev/null
@@ -1,162 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(m_i_impl).
--include("m.hrl").
-
--export([init/1, terminate/2, void_test/1, long_test/2, ushort_test/2,
- longlong_test/2, ulong_test/2, ulonglong_test/2,
- double_test/2, char_test/2, wchar_test/2, octet_test/2,
- bool_test/2, struct_test/2, struct2_test/2, seq1_test/2,
- seq2_test/2, seq3_test/2, seq4_test/2, seq5_test/2,
- array1_test/2, array2_test/2, enum_test/2, string1_test/2,
- string2_test/2, string3_test/2, string4_test/2, pid_test/2,
- port_test/2, ref_test/2, term_test/2, typedef_test/3,
- inline_sequence_test/2, '_set_l'/2, '_get_l'/1,
- term_struct_test/2, term_sequence_test/2, wstring1_test/2]).
-
--define(PRINTDEBUG(Case),
- io:format("erl_server: case: ~p~n"
- "erl_server: location: ~p~n", [Case, [?FILE, ?LINE]])).
--define(PRINTDEBUG2(Case, Msg),
- io:format("erl_server: case: ~p~n"
- "erl_server: Msg: ~p~n"
- "erl_server: location: ~p~n", [Case, Msg, [?FILE, ?LINE]])).
-
-init(Env) ->
- {ok, []}.
-
-terminate(F, R) ->
- ok.
-
-'_get_l'(State) ->
- ?PRINTDEBUG("_get_l"),
- {reply, State, State}.
-void_test(State) ->
- ?PRINTDEBUG("void_test"),
- {reply, ok, State}.
-
-'_set_l'(State, V) ->
- ?PRINTDEBUG2("_set_l", V),
- {reply, ok, V}.
-ushort_test(State, V) ->
- ?PRINTDEBUG2("ushort_test", V),
- {reply, {V, V}, State}.
-long_test(State, V) ->
- ?PRINTDEBUG2("long_test", V),
- {reply, {V, V}, State}.
-longlong_test(State, V) ->
- ?PRINTDEBUG2("longlong_test", V),
- {reply, {V, V}, State}.
-ulong_test(State, V) ->
- ?PRINTDEBUG2("ulong_test", V),
- {reply, {V, V}, State}.
-ulonglong_test(State, V) ->
- ?PRINTDEBUG2("ulonglong_test", V),
- {reply, {V, V}, State}.
-double_test(State, V) ->
- ?PRINTDEBUG2("double_test", V),
- {reply, {V, V}, State}.
-char_test(State, V) ->
- ?PRINTDEBUG2("char_test", V),
- {reply, {V, V}, State}.
-wchar_test(State, V) ->
- ?PRINTDEBUG2("wchar_test", V),
- {reply, {V, V}, State}.
-octet_test(State, V) ->
- ?PRINTDEBUG2("octet_test", V),
- {reply, {V, V}, State}.
-bool_test(State, V) ->
- ?PRINTDEBUG2("bool_test", V),
- {reply, {V, V}, State}.
-
-struct_test(State, V) ->
- ?PRINTDEBUG2("struct_test", V),
- {reply, {V, V}, State}.
-struct2_test(State, V) ->
- ?PRINTDEBUG2("struct2_test", V),
- {reply, {V, V}, State}.
-seq1_test(State, V) ->
- ?PRINTDEBUG2("seq1_test", V),
- {reply, {V, V}, State}.
-seq2_test(State, V) ->
- ?PRINTDEBUG2("seq2_test", V),
- {reply, {V, V}, State}.
-seq3_test(State, V) ->
- ?PRINTDEBUG2("seq3_test", V),
- {reply, {V, V}, State}.
-seq4_test(State, V) ->
- ?PRINTDEBUG2("seq4_test", V),
- {reply, {V, V}, State}.
-seq5_test(State, V) ->
- ?PRINTDEBUG2("seq5_test", V),
- {reply, {V, V}, State}.
-array1_test(State, V) ->
- ?PRINTDEBUG2("array1_test", V),
- {reply, {V, V}, State}.
-array2_test(State, V) ->
- ?PRINTDEBUG2("array2_test", V),
- {reply, {V, V}, State}.
-enum_test(State, V) ->
- ?PRINTDEBUG2("enum_test", V),
- {reply, {V, V}, State}.
-string1_test(State, V) ->
- ?PRINTDEBUG2("string1_test", V),
- {reply, {V, V}, State}.
-string2_test(State, V) ->
- ?PRINTDEBUG2("string2_test", V),
- {reply, {V, V}, State}.
-string3_test(State, V) ->
- ?PRINTDEBUG2("string3_test", V),
- {reply, {V, V}, State}.
-string4_test(State, V) ->
- ?PRINTDEBUG2("string4_test", V),
- {reply, {V, V}, State}.
-pid_test(State, V) ->
- ?PRINTDEBUG2("pid_test", V),
- {reply, {V, V}, State}.
-port_test(State, V) ->
- ?PRINTDEBUG2("port_test", binary_to_list(term_to_binary(V))),
- {reply, {V, V}, State}.
-ref_test(State, V) ->
- ?PRINTDEBUG2("ref_test", binary_to_list(term_to_binary(V))),
- {reply, {V, V}, State}.
-term_test(State, V) ->
- ?PRINTDEBUG2("term_test", V),
- {reply, {V, V}, State}.
-typedef_test(State, A, B) ->
- ?PRINTDEBUG2("typedef_test", [A,B]),
- {reply, {4711, A, B}, State}.
-inline_sequence_test(State, V) ->
- ?PRINTDEBUG2("inline_sequence_test", V),
- {reply, {V, V}, State}.
-term_sequence_test(State, V) ->
- ?PRINTDEBUG2("term_sequence_test", V),
- {reply, {V, V}, State}.
-term_struct_test(State, V) ->
- ?PRINTDEBUG2("term_struct_test", V),
- {reply, {V, V}, State}.
-wstring1_test(State, V) ->
- ?PRINTDEBUG2("wstring1_test", V),
- {reply, {V, V}, State}.
-
-
-
-
diff --git a/lib/ic/test/c_client_erl_server_proto_SUITE.erl b/lib/ic/test/c_client_erl_server_proto_SUITE.erl
deleted file mode 100644
index c15617ea3f..0000000000
--- a/lib/ic/test/c_client_erl_server_proto_SUITE.erl
+++ /dev/null
@@ -1,265 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
-%%----------------------------------------------------------------------
-%% Purpose : Test suite for c-client/erl-server
-%%----------------------------------------------------------------------
-
--module(c_client_erl_server_proto_SUITE).
--include_lib("common_test/include/ct.hrl").
-
--export([init_per_testcase/2, end_per_testcase/2,
- all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2,
- void_test/1, long_test/1, long_long_test/1,
- unsigned_short_test/1, unsigned_long_test/1,
- unsigned_long_long_test/1, double_test/1, char_test/1,
- wchar_test/1, octet_test/1, bool_test/1, struct_test/1,
- struct2_test/1, seq1_test/1, seq2_test/1, seq3_test/1,
- seq4_test/1, seq5_test/1, array1_test/1, array2_test/1,
- enum_test/1, string1_test/1, string2_test/1, string3_test/1,
- string4_test/1, pid_test/1, port_test/1, ref_test/1, term_test/1,
- typedef_test/1, inline_sequence_test/1, term_sequence_test/1,
- term_struct_test/1, wstring1_test/1]).
-
--define(DEFAULT_TIMEOUT, 20000).
--define(PORT_TIMEOUT, 15000).
--define(ERLANG_SERVER_NAME, idl_erlang_server).
--define(C_CLIENT_NODE_NAME, c_client_idl_test).
-
-%% Add/remove code path and watchdog before/after each test case.
-%%
-init_per_testcase(_Case, Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- code:add_patha(DataDir),
-
- %% Since other test suites use the module m_i, we have
- %% to make sure we are using the right m_i module.
- code:purge(m_i),
- code:load_file(m_i),
-
- WatchDog = test_server:timetrap(?DEFAULT_TIMEOUT),
- [{watchdog, WatchDog}| Config].
-
-end_per_testcase(_Case, Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- code:del_path(DataDir),
- WatchDog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(WatchDog).
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [void_test, long_test, long_long_test,
- unsigned_short_test, unsigned_long_test,
- unsigned_long_long_test, double_test, char_test,
- wchar_test, octet_test, bool_test, struct_test,
- struct2_test, seq1_test, seq2_test, seq3_test,
- seq4_test, seq5_test, array1_test, array2_test,
- enum_test, string1_test, string2_test, string3_test,
- string4_test, pid_test, port_test, ref_test, term_test,
- typedef_test, inline_sequence_test, term_sequence_test,
- term_struct_test, wstring1_test].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-array1_test(Config) ->
- do_test(array1_test, Config).
-
-array2_test(Config) ->
- do_test(array2_test, Config).
-
-bool_test(Config) ->
- do_test(bool_test, Config).
-
-char_test(Config) ->
- do_test(char_test, Config).
-
-double_test(Config) ->
- do_test(double_test, Config).
-
-enum_test(Config) ->
- do_test(enum_test, Config).
-
-inline_sequence_test(Config) ->
- do_test(inline_sequence_test, Config).
-
-long_long_test(Config) ->
- do_test(long_long_test, Config).
-
-long_test(Config) ->
- do_test(long_test, Config).
-
-octet_test(Config) ->
- do_test(octet_test, Config).
-
-pid_test(Config) ->
- do_test(pid_test, Config).
-
-port_test(Config) ->
- do_test(port_test, Config).
-
-ref_test(Config) ->
- do_test(ref_test, Config).
-
-seq1_test(Config) ->
- do_test(seq1_test, Config).
-
-seq2_test(Config) ->
- do_test(seq2_test, Config).
-
-seq3_test(Config) ->
- do_test(seq3_test, Config).
-
-seq4_test(Config) ->
- do_test(seq4_test, Config).
-
-seq5_test(Config) ->
- do_test(seq5_test, Config).
-
-string1_test(Config) ->
- do_test(string1_test, Config).
-
-string2_test(Config) ->
- do_test(string2_test, Config).
-
-string3_test(Config) ->
- do_test(string3_test, Config).
-
-string4_test(Config) ->
- do_test(string4_test, Config).
-
-struct2_test(Config) ->
- do_test(struct2_test, Config).
-
-struct_test(Config) ->
- do_test(struct_test, Config).
-
-term_sequence_test(Config) ->
- do_test(term_sequence_test, Config).
-
-term_struct_test(Config) ->
- do_test(term_struct_test, Config).
-
-term_test(Config) ->
- do_test(term_test, Config).
-
-typedef_test(Config) ->
- do_test(typedef_test, Config).
-
-unsigned_long_long_test(Config) ->
- do_test(unsigned_long_long_test, Config).
-
-unsigned_long_test(Config) ->
- do_test(unsigned_long_test, Config).
-
-unsigned_short_test(Config) ->
- do_test(unsigned_short_test, Config).
-
-void_test(Config) ->
- do_test(void_test, Config).
-
-wchar_test(Config) ->
- do_test(wchar_test, Config).
-
-wstring1_test(Config) ->
- do_test(wstring1_test, Config).
-
-
-%% It is here that all tests really are done.
-%%
-
-do_test(Case, Config) ->
- %% Trap exits
- process_flag(trap_exit, true),
- %% Start the server
- {ok, _Pid} = m_i:oe_create_link([], {local, ?ERLANG_SERVER_NAME}),
- Node = atom_to_list(node()),
- %% [NodeName, HostName] = string:tokens(Node, "@"),
- DataDir = proplists:get_value(data_dir, Config),
- %% io:format("~p: data directory: ~p~n", [?MODULE, DataDir]),
- Cookie = atom_to_list(erlang:get_cookie()),
- %% Start C-client node as a port program.
- Cmd = filename:join([DataDir, "c_client"]) ++
- " -this-node-name " ++ atom_to_list(?C_CLIENT_NODE_NAME) ++
- " -peer-node " ++ Node ++
- " -peer-process-name " ++ atom_to_list(?ERLANG_SERVER_NAME) ++
- " -cookie " ++ Cookie ++
- " -test-case " ++ atom_to_list(Case),
- Port = open_port({spawn, Cmd}, [exit_status, eof, stderr_to_stdout]),
- Res = wait_for_completion(Port),
- %% Kill off node if there was timeout
- case Res of
- {error, timeout} ->
- catch rpc:cast(?C_CLIENT_NODE_NAME, erlang, halt, [1]);
- _ ->
- ok
- end,
- process_flag(trap_exit, false),
- catch m_i:stop(?ERLANG_SERVER_NAME),
- ok = Res.
-
-
-%% Wait for eof *and* exit status, but return if exit status indicates
-%% an error, or we have been waiting more than PORT_TIMEOUT seconds.
-%%
-wait_for_completion(Port) ->
- wait_for_completion(Port, 0).
-
-wait_for_completion(Port, N) when N < 2 ->
- receive
- {Port, {data, Bytes}} ->
- %% Relay output
- io:format("~s", [Bytes]),
- wait_for_completion(Port, N);
- {Port, {exit_status, 0}} ->
- wait_for_completion(Port, N + 1);
- {Port, {exit_status, Status}} ->
- {error, Status};
- {Port, eof} ->
- wait_for_completion(Port, N + 1);
- {'EXIT', Port, Reason} ->
- io:format("Port exited with reason: ~w~n", [Reason]),
- wait_for_completion(Port, N);
- {'EXIT', From, Reason} ->
- io:format("Got unexpected exit: ~p~n", [{'EXIT', From, Reason}]),
- wait_for_completion(Port, N)
- after ?PORT_TIMEOUT ->
- {error, timeout}
- end;
-wait_for_completion(_, _) ->
- ok.
-
-
-
diff --git a/lib/ic/test/c_client_erl_server_proto_SUITE_data/Makefile.src b/lib/ic/test/c_client_erl_server_proto_SUITE_data/Makefile.src
deleted file mode 100644
index fc6d416316..0000000000
--- a/lib/ic/test/c_client_erl_server_proto_SUITE_data/Makefile.src
+++ /dev/null
@@ -1,156 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2003-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-# Makefile.src for c_client_erl_server test
-# Note: This file *must* work for both Unix and Windows
-#
-# We use both `rm' (Unix) and `del' (Windows) for removing files, but
-# with a `-' in front so that the error in not finding `rm' (`del') on
-# Windows (Unix) is ignored.
-#
-# VxWorks? XXX
-#
-
-.SUFFIXES:
-.SUFFIXES: .c .h .erl .idl @obj@ .@EMULATOR@
-
-
-# Variables from ts:
-#
-
-ERL_INCLUDE = @erl_include@
-
-IC_INCLUDE_PATH = @ic_include_path@
-IC_LIB = @ic_lib@
-
-ERL_INTERFACE_INCLUDE = @erl_interface_include@
-ERL_INTERFACE_LIB = @erl_interface_lib@
-ERL_INTERFACE_EILIB = @erl_interface_eilib@
-ERL_INTERFACE_THREADLIB = @erl_interface_threadlib@
-ERL_INTERFACE_SOCK_LIBS = @erl_interface_sock_libs@
-
-CC = @CC@
-## XXX Should set warning flag with a DEBUG_FLAG
-CFLAGS = @CFLAGS@ @DEFS@ -I@erl_include@ \
- -I@ic_include_path@ -I@erl_interface_include@
-
-LD = @LD@
-LDFLAGS = @CROSSLDFLAGS@
-LIBS = $(IC_LIB) $(ERL_INTERFACE_LIB) $(ERL_INTERFACE_EILIB) \
- $(ERL_INTERFACE_THREADLIB) @LIBS@ $(ERL_INTERFACE_SOCK_LIBS)
-ERLC = erlc
-
-# Generated C header files
-GEN_H_FILES = \
- m.h \
- m_i.h \
- oe_c_erl_test.h
-
-# Generated C files
-GEN_C_FILES = \
- m.c \
- m_i.c \
- oe_c_erl_test.c \
- oe_code_m_a.c \
- oe_code_m_arr1.c \
- oe_code_m_arr2.c \
- oe_code_m_arr3.c \
- oe_code_m_aseq.c \
- oe_code_m_b.c \
- oe_code_m_bseq.c \
- oe_code_m_dd.c \
- oe_code_m_dyn.c \
- oe_code_m_dyn_sl.c \
- oe_code_m_es.c \
- oe_code_m_et.c \
- oe_code_m_etseq.c \
- oe_code_m_fruit.c \
- oe_code_m_lseq.c \
- oe_code_m_s.c \
- oe_code_m_s_sl.c \
- oe_code_m_sarr3.c \
- oe_code_m_simple.c \
- oe_code_m_ssarr3.c \
- oe_code_m_sseq.c \
- oe_code_m_ssstr3.c \
- oe_code_m_sstr3.c \
- oe_code_m_str1.c \
- oe_code_m_str3.c \
- oe_code_m_strRec.c \
- oe_code_m_strRec_str5.c \
- oe_code_m_strRec_str7.c
-
-GEN_HRL_FILES = \
- m.hrl \
- m_i.hrl \
- oe_c_erl_test.hrl
-
-GEN_ERL_FILES = \
- m.erl \
- m_arr2.erl \
- m_arr3.erl \
- m_i.erl \
- m_str3.erl \
- oe_c_erl_test.erl
-
-C_FILES = $(GEN_C_FILES) c_client.c my.c
-
-OBJS = $(C_FILES:.c=@obj@)
-
-PGMS = c_client@exe@
-
-ERL_FILES = $(GEN_ERL_FILES) m_i_impl.erl
-
-EBINS = $(ERL_FILES:.erl=.@EMULATOR@)
-
-
-all: $(PGMS) $(EBINS)
-
-$(GEN_ERL_FILES) $(GEN_HRL_FILES): c_erl_test.built_erl
-$(GEN_C_FILES) $(GEN_H_FILES): c_erl_test.built_c
-$(OBJS): $(GEN_C_FILES) $(GEN_H_FILES)
-$(EBINS): $(GEN_ERL_FILES) $(GEN_HRL_FILES)
-
-clean:
- -rm -f $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \
- $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) \
- c_erl_test.built_erl c_erl_test.built_c
- -del /F /Q $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \
- $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) \
- c_erl_test.built_erl c_erl_test.built_c
-
-$(PGMS): $(OBJS)
- $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
-
-c_erl_test.built_c: c_erl_test.idl
- $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,c_client}" \
- "+{user_protocol,my}" c_erl_test.idl
- echo done > c_erl_test.built_c
-
-c_erl_test.built_erl: c_erl_test.idl
- $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,erl_genserv}" c_erl_test.idl
- echo done > c_erl_test.built_erl
-
-.c@obj@:
- $(CC) -c -o $*@obj@ $(CFLAGS) $<
-
-.erl.@EMULATOR@:
- $(ERLC) -I $(IC_INCLUDE_PATH) $<
-
diff --git a/lib/ic/test/c_client_erl_server_proto_SUITE_data/c_client.c b/lib/ic/test/c_client_erl_server_proto_SUITE_data/c_client.c
deleted file mode 100644
index d6a78d2481..0000000000
--- a/lib/ic/test/c_client_erl_server_proto_SUITE_data/c_client.c
+++ /dev/null
@@ -1,1764 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 2003-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-/* C-client for test of IC.
- *
- * TODO:
- *
- * 1. XXX #includes for VxWorks, Windows
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#ifndef __WIN32__
-# include <unistd.h>
-#endif
-
-#include <string.h>
-
-#ifdef __WIN32__
-# include <time.h>
-# include <sys/timeb.h>
-#elif defined VXWORKS
-#include <time.h>
-#include <sys/times.h>
-#else
-#include <sys/time.h>
-#endif
-
-#include <ctype.h>
-
-#ifdef __WIN32__
-# include <winsock2.h>
-# include <windows.h>
-#else
-# include <sys/types.h>
-# include <sys/socket.h>
-# include <netinet/in.h>
-# include <arpa/inet.h>
-# include <netdb.h>
-#endif
-
-#include "ei.h"
-#include "erl_interface.h"
-#include "m_i.h"
-
-#define HOSTNAMESZ 255
-#define NODENAMESZ 512
-
-#define INBUFSZ 10
-#define OUTBUFSZ 0
-
-#define MAXTRIES 5
-
-#define CHECK_EXCEPTION(x) \
- if ((x)->_major != CORBA_NO_EXCEPTION) { \
- fprintf(stderr,"\n\nException: %s\n\n", \
- (char *)CORBA_exception_value((x))); \
- CORBA_exception_free((x)); \
- return -1; \
- } \
-
-/* XXX Should free things here too! */
-#define RETURN_IF_OK(x) \
- if ((x)) {\
- fprintf(stdout, "ok\n");\
- return 0;\
- }\
-
-#define cmp_str(x,y) (!strcmp((x),(y)))
-#define cmp_wstr(x,y) (!ic_wstrcmp((x),(y)))
-
-typedef CORBA_Environment IC_Env;
-
-typedef int (*TestFunc)(IC_Env *);
-typedef struct {
- char *name;
- TestFunc func;
-} TestCase;
-
-static char longtext[] =
-"Introduction The IC application is an IDL compiler implemented in Erlang."
-" The IDL compiler generates client stubs and server skeletons."
-" Several back-ends are supported, and they fall into three main groups."
-" For more details on IC compiler options consult the ic(3) manual page."
-" Argument passing cases 1 Caller allocates all necessary storage,"
-" except that which may be encapsulated and managed within the parameter itself."
-" 2 The caller allocates a pointer and passes it by reference to the callee."
-" The callee sets the pointer to point to a valid instance of the parameter's type."
-" The caller is responsible for releasing the returned storage."
-" Following completion of a request, the caller is not allowed to modify any values"
-" in the returned storage. To do so the caller must first copy the returned instance"
-" into a new instance, then modify the new instance. 3 The caller allocates a"
-" pointer to an array slice which has all the same dimensions of the original"
-" array except the first, and passes it by reference to the callee. The callee sets"
-" the pointer to point to a valid instance of the array. The caller is responsible for"
-" releasing the returned storage. Following completion of a request, the caller is not"
-" allowed to modify any values in the returned storage. To do so the caller must first"
-" copy the returned instance into a new instance, then modify the new instance."
-" Generated Files Two files will be generated for each scope. One set of files will be"
-" generated for each module and each interface scope. An extra set is generated for"
-" those definitions at top level scope. One of the files is a header file(.h), and the"
-" other file is a C source code file (.c). In addition to these files a number of C"
-" source files will be generated for type encodings, they are named according to the "
-"following template: oe_code_<type>.c.";
-static char this_node[NODENAMESZ + 1];
-static char *progname;
-
-/* Test function prototypes */
-
-static int void_test(IC_Env *env);
-static int long_test(IC_Env *env);
-static int long_long_test(IC_Env *env);
-static int unsigned_short_test(IC_Env *env);
-static int unsigned_long_test(IC_Env *env);
-static int unsigned_long_long_test(IC_Env *env);
-static int double_test(IC_Env *env);
-static int char_test(IC_Env *env);
-static int wchar_test(IC_Env *env);
-static int octet_test(IC_Env *env);
-static int bool_test(IC_Env *env);
-static int struct_test(IC_Env *env);
-static int struct2_test(IC_Env *env);
-static int seq1_test(IC_Env *env);
-static int seq2_test(IC_Env *env);
-static int seq3_test(IC_Env *env);
-static int seq4_test(IC_Env *env);
-static int seq5_test(IC_Env *env);
-static int array1_test(IC_Env *env);
-static int array2_test(IC_Env *env);
-static int enum_test(IC_Env *env);
-static int string1_test(IC_Env *env);
-static int string2_test(IC_Env *env);
-static int string3_test(IC_Env *env);
-static int string4_test(IC_Env *env);
-static int pid_test(IC_Env *env);
-static int port_test(IC_Env *env);
-static int ref_test(IC_Env *env);
-static int term_test(IC_Env *env);
-static int typedef_test(IC_Env *env);
-static int inline_sequence_test(IC_Env *env);
-static int term_sequence_test(IC_Env *env);
-static int term_struct_test(IC_Env *env);
-static int wstring1_test(IC_Env *env);
-
-static TestCase test_cases[] = {
- {"void_test", void_test},
- {"long_test", long_test},
- {"long_long_test", long_long_test},
- {"unsigned_short_test", unsigned_short_test},
- {"unsigned_long_test", unsigned_long_test},
- {"unsigned_long_long_test", unsigned_long_long_test},
- {"double_test", double_test},
- {"char_test", char_test},
- {"wchar_test", wchar_test},
- {"octet_test", octet_test},
- {"bool_test", bool_test},
- {"struct_test", struct_test},
- {"struct2_test", struct2_test},
- {"seq1_test", seq1_test},
- {"seq2_test", seq2_test},
- {"seq3_test", seq3_test},
- {"seq4_test", seq4_test},
- {"seq5_test", seq5_test},
- {"array1_test", array1_test},
- {"array2_test", array2_test},
- {"enum_test", enum_test},
- {"string1_test", string1_test},
- {"string2_test", string2_test},
- {"string3_test", string3_test},
- {"string4_test", string4_test},
- {"pid_test", pid_test},
- {"port_test", port_test},
- {"ref_test", ref_test},
- {"term_test", term_test},
- {"typedef_test", typedef_test},
- {"inline_sequence_test", inline_sequence_test},
- {"term_sequence_test", term_sequence_test},
- {"term_struct_test", term_struct_test},
- {"wstring1_test", wstring1_test},
- {"", NULL}
-};
-
-/* Other prototypes */
-static int cmp_aseq(m_aseq *a1, m_aseq *a2);
-static int cmp_a(m_a *a1, m_a *a2);
-static int cmp_bseq(m_bseq *b1, m_bseq *b2);
-static int cmp_b(m_b *b1, m_b *b2);
-static int cmp_lseq(m_lseq *b1, m_lseq *b2);
-static int cmp_etseq(m_etseq *b1, m_etseq *b2);
-static int cmp_et(m_et* b1, m_et *b2);
-static int cmp_es(m_es *b1, m_es *b2);
-static int cmp_arr1(m_arr1 b1, m_arr1 b2);
-static int cmp_dd(m_dd b1, m_dd b2);
-static int cmp_strRec(m_strRec *b1, m_strRec *b2);
-static int cmp_sseq(m_sseq *b1, m_sseq *b2);
-static int cmp_pid(erlang_pid *p1, erlang_pid *p2);
-static int cmp_port(erlang_port *p1, erlang_port *p2);
-static int cmp_ref(erlang_ref *p1, erlang_ref *p2);
-static int cmp_s(m_s *b1, m_s *b2);
-static int cmp_ssstr3(m_ssstr3 *b1, m_ssstr3 *b2);
-static int cmp_ssarr3(m_ssarr3 *b1, m_ssarr3 *b2);
-static int cmp_sarr3(m_sarr3 *b1, m_sarr3 *b2);
-static int cmp_arr3(m_arr3 b1, m_arr3 b2);
-
-static void print_aseq(m_aseq *a);
-static void print_a(m_a *a);
-static void print_bseq(m_bseq *b);
-static void print_lseq(m_lseq *b);
-static void print_b(m_b *b);
-static void print_etseq(m_etseq *b);
-static void print_et(m_et* b);
-static void print_es(m_es *b);
-static void print_arr1(long a[500]);
-static void print_dd(long a[2][3]);
-static void print_strRec(m_strRec* sr);
-static void print_sseq(m_sseq *b);
-static void print_pid(erlang_pid *p);
-static void print_port(erlang_port *p);
-static void print_ref(erlang_ref *p);
-static void print_term(ETERM *t);
-static void print_s(m_s *p);
-static void print_ssstr3(m_ssstr3 *b1);
-static void print_ssarr3(m_ssarr3 *b1);
-static void print_sarr3(m_sarr3 *b1);
-static void print_arr3(m_arr3 b1);
-static void print_wstr(CORBA_wchar *ws);
-
-static void free_etseq_buf(m_etseq *b);
-static void free_et(m_et* b);
-
-#ifdef __WIN32__
-typedef struct {
- long tv_sec;
- long tv_usec;
-} MyTimeval;
-#else
-typedef struct timeval MyTimeval;
-#endif
-static void my_gettimeofday(MyTimeval *tv);
-static void showtime(MyTimeval *start, MyTimeval *stop);
-static void usage(void);
-static void done(int r);
-
-
-
-/* main */
-
-#ifdef VXWORKS
-int client(int argc, char **argv)
-#else
-int main(int argc, char **argv)
-#endif
-{
- struct hostent *hp;
- erlang_pid pid;
- MyTimeval start, stop;
- int i, fd, ires, tres;
- IC_Env *env;
- int tries = 0;
- char *this_node_name = NULL;
- char *peer_node = NULL;
- char *peer_process_name = NULL;
- char *cookie = NULL;
- char host[HOSTNAMESZ + 1];
- TestFunc test_func = NULL;
- TestCase *test_case;
- char *test_case_name = NULL;
-
-#ifdef __WIN32__
- WORD wVersionRequested;
- WSADATA wsaData;
-
- wVersionRequested = MAKEWORD(2, 0);
-
- if (WSAStartup(wVersionRequested, &wsaData) != 0) {
- fprintf(stderr, "Could not load winsock2 v2.0 compatible DLL");
- exit(1);
- }
-#endif
-
- progname = argv[0];
- host[HOSTNAMESZ] = '\0';
- if (gethostname(host, HOSTNAMESZ + 1) < 0) {
- fprintf(stderr, "Can't find own hostname\n");
- done(1);
- }
- if ((hp = gethostbyname(host)) == 0) {
- fprintf(stderr, "Can't get ip address for host %s\n", host);
- done(1);
- }
- for (i = 1; i < argc; i++) {
- if (cmp_str(argv[i], "-help")) {
- usage();
- done(0);
- } else if (cmp_str(argv[i], "-this-node-name")) {
- i++;
- this_node_name = argv[i];
- } else if (cmp_str(argv[i], "-peer-node")) {
- i++;
- peer_node = argv[i];
- } else if (cmp_str(argv[i], "-peer-process-name")) {
- i++;
- peer_process_name = argv[i];
- } else if (cmp_str(argv[i], "-cookie")) {
- i++;
- cookie = argv[i];
- } else if (cmp_str(argv[i], "-test-case")) {
- i++;
- test_case_name = argv[i];
- } else {
- fprintf(stderr, "Error : invalid argument \"%s\"\n", argv[i]);
- usage();
- done(1);
- }
- }
-
- if (this_node_name == NULL || peer_node == NULL || test_case_name == NULL
- || peer_process_name == NULL || cookie == NULL) {
- fprintf(stderr, "Error: missing option\n");
- usage();
- done(1);
- }
-
- test_case = test_cases;
- while (test_case->func) {
- if (cmp_str(test_case->name, test_case_name)) {
- test_func = test_case->func;
- break;
- }
- test_case++;
- }
- if (test_func == NULL) {
- fprintf(stderr, "Error: illegal test case: \"%s\"\n", test_case_name);
- done(1);
- }
-
- /* Behead hostname at first dot */
- for (i=0; host[i] != '\0'; i++) {
- if (host[i] == '.') { host[i] = '\0'; break; }
- }
- sprintf(this_node, "%s@%s", this_node_name, host);
- fprintf(stderr, "c_client: this node: \"%s\"\n", this_node);
- fprintf(stderr, "c_client: peer node: \"%s\"\n", peer_node);
- fprintf(stderr, "c_client: test case: \"%s\"\n", test_case_name);
-
- fprintf(stderr, "c_client: starting\n");
-
- /* initialize erl_interface */
- erl_init(NULL, 0);
-
- for (tries = 0; tries < MAXTRIES; tries++) {
-
- /* connect to erlang node */
-
- ires = erl_connect_xinit(host, this_node_name, this_node,
- (struct in_addr *)*hp->h_addr_list,
- cookie, 0);
-
- fprintf(stderr, "c_client: erl_connect_xinit(): %d\n", ires);
-
- fd = erl_connect(peer_node);
- fprintf(stderr, "c_client: erl_connect(): %d\n", fd);
-
- if (fd >= 0)
- break;
- fprintf(stderr, "c_client: cannot connect, retrying\n");
- }
- if (fd < 0) {
- fprintf(stderr, "c_client: cannot connect, exiting\n");
- done(1);
- }
- env = CORBA_Environment_alloc(INBUFSZ, OUTBUFSZ);
- env->_fd = fd;
- strcpy(env->_regname, peer_process_name);
- env->_to_pid = NULL;
- env->_from_pid = &pid;
-
- strcpy(pid.node, this_node);
- pid.num = fd;
- pid.serial = 0;
- pid.creation = 0;
-
- my_gettimeofday(&start);
- tres = test_func(env); /* Call test case */
- my_gettimeofday(&stop);
- showtime(&start, &stop);
- erl_close_connection(fd);
-
- printf("c_client: env->_inbuf before : %d\n", INBUFSZ);
- printf("c_client: env->_outbuf before : %d\n", OUTBUFSZ);
- printf("c_client: env->_inbuf after : %d\n", env->_inbufsz);
- printf("c_client: env->_outbuf after : %d\n", env->_outbufsz);
-
- CORBA_free(env->_inbuf);
- CORBA_free(env->_outbuf);
- CORBA_free(env);
- done(tres);
-}
-
-static void usage()
-{
- fprintf(stderr, "Usage: %s [-help] -this-node-name <name> "
- "-peer-node <nodename> -peer-process-name <name> "
- "-cookie <cookie> -test-case <test case name>\n", progname);
- fprintf(stderr, "Example:\n %s -this-node-name kalle "
- "-peer-node olle@home -peer-process-name idltest "
- "-cookie oa678er -test-case octet_test\n", progname);
-}
-
-static void done(int r)
-{
-#ifdef __WIN32__
- WSACleanup();
-#endif
- exit(r);
-}
-
-
-/* TESTS */
-
-static int void_test(IC_Env *env)
-{
- fprintf(stdout, "\n======== m_i_void test ======\n\n");
- m_i_void_test(NULL,env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(1);
-}
-
-static int long_test(IC_Env *env)
-{
- long l = 4711, lo, lr;
-
- fprintf(stdout, "\n======== m_i_long test ======\n\n");
- lr = m_i_long_test(NULL, l, &lo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(l == lo && l == lr);
- if (l != lo)
- fprintf(stdout, " out parameter error, sent: %ld, got: %ld\n", l, lo);
- if (l != lr)
- fprintf(stdout, " result error, sent: %ld, got: %ld\n", l, lr);
- return -1;
-}
-
-static int long_long_test(IC_Env *env)
-{
- CORBA_long_long ll = 4711, llo, llr;
-
- fprintf(stdout, "\n======== m_i_longlong test ======\n\n");
- llr = m_i_longlong_test(NULL, ll, &llo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(ll == llo && ll == llr);
- if (ll != llo)
- fprintf(stdout, " out parameter error, sent: %ld, got: %ld\n",
- ll, llo);
- if (ll != llr)
- fprintf(stdout, " result error, sent: %ld, got: %ld\n", ll, llr);
- return -1;
-}
-
-static int unsigned_short_test(IC_Env *env)
-{
- unsigned short x, y = 2, z;
-
- fprintf(stdout, "\n======== m_i_ushort test ======\n\n");
- x = m_i_ushort_test(NULL, y, &z, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(y == z && y == x);
- if (y != z)
- fprintf(stdout, " out parameter error, sent: %d, got: %d\n", y, z);
- if (y != x)
- fprintf(stdout, " result error, sent: %d, got: %d\n", y, x);
- return -1;
-}
-
-
-static int unsigned_long_test(IC_Env *env)
-{
- unsigned long ul = 5050, ulo, ulr;
-
- fprintf(stdout, "\n======== m_i_ulong test ======\n\n");
- ulr = m_i_ulong_test(NULL, ul, &ulo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(ul == ulo && ul == ulr);
- if (ul != ulo)
- fprintf(stdout, " out parameter error, sent: %lu, got: %lu\n",
- ul, ulo);
- if (ul != ulr)
- fprintf(stdout, " result error, sent: %lu, got: %lu\n", ul, ulr);
- return -1;
-}
-
-/*
- * Note: CORBA_unsigned_long_long is in fact a plain long.
- */
-static int unsigned_long_long_test(IC_Env *env)
-{
- CORBA_unsigned_long_long ull = 5050, ullo, ullr;
-
- fprintf(stdout, "\n======== m_i_ulonglong test ======\n\n");
- ullr = m_i_ulonglong_test(NULL, ull, &ullo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(ull == ullo && ull == ullr);
- if (ull != ullo)
- fprintf(stdout, " out parameter error, sent: %lu, got: %lu\n",
- ull, ullo);
- if (ull != ullr)
- fprintf(stdout, " result error, sent: %lu, got: %lu\n",
- ull, ullr);
- return -1;
-}
-
-static int double_test(IC_Env *env)
-{
- double d = 12.1212, db, dr;
-
- fprintf(stdout, "\n======== m_i_double test ======\n\n");
- dr = m_i_double_test(NULL, d, &db, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(d == db && d == dr);
- if (d != db)
- fprintf(stdout, " out parameter error, sent: %f, got: %f\n", d, db);
- if (d != dr)
- fprintf(stdout, " result error, sent: %f, got: %f\n", d, dr);
- return -1;
-}
-
-static int char_test(IC_Env *env)
-{
- char c = 'g', co, cr;
-
- /* char test */
- fprintf(stdout, "\n======== m_i_char test ======\n\n");
- cr = m_i_char_test(NULL, c, &co, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(c == co && c == cr);
- if (c !=co)
- fprintf(stdout, " out parameter error, sent: %c, got: %c\n", c, co);
- if (c != cr)
- fprintf(stdout, " result error, sent: %c, got: %c\n", c, cr);
- return -1;
-}
-
-static int wchar_test(IC_Env *env)
-{
- CORBA_wchar wc = 103, wco, wcr;
-
- fprintf(stdout, "\n======== m_i_wchar test ======\n\n");
- wcr = m_i_wchar_test(NULL, wc, &wco, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(wc == wco && wc == wcr);
- if (wc != wco)
- fprintf(stdout, " out parameter error, sent: %lu, got: %lu\n",
- wc, wco);
- if (wc != wcr)
- fprintf(stdout, " result error, sent: %lu, got: %lu\n",
- wc, wcr);
- return -1;
-}
-
-static int octet_test(IC_Env *env)
-{
- char o ='r', oo, or;
-
- fprintf(stdout, "\n======== m_i_octet test ======\n\n");
- or = m_i_octet_test(NULL, o, &oo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(o == oo && o == or);
- if (o != oo)
- fprintf(stdout, " out parameter error, sent: %c, got: %c\n", o, oo);
- if (o != or)
- fprintf(stdout, " result error, sent: %c, got: %c\n", o, or);
- return -1;
-}
-
-static int bool_test(IC_Env *env)
-{
- unsigned char i = 0, io, ir;
-
- fprintf(stdout, "\n======== m_i_bool test ======\n\n");
- ir = m_i_bool_test(NULL, i, &io, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(i == io && i == ir);
- if (i != io)
- fprintf(stdout, " out parameter error, sent: %d, got: %d\n", i, io);
- if (i != ir)
- fprintf(stdout, " result error, sent: %d, got: %d\n", i, ir);
- return -1;
-}
-
-static int struct_test(IC_Env *env)
-{
- m_b b = {4711, 'a'}, bo, br;
-
- fprintf(stdout, "\n======== m_i_struct test ======\n\n");
- br = m_i_struct_test(NULL, &b, &bo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_b(&b, &bo) && cmp_b(&b, &br));
- if (!cmp_b(&b, &bo)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_b(&b);
- fprintf(stdout, " got:\n");
- print_b(&bo);
- fprintf(stdout, "\n");
- }
- if (!cmp_b(&b, &br)) {
- fprintf(stdout, " result error, sent:\n");
- print_b(&b);
- fprintf(stdout, " got:\n");
- print_b(&br);
- fprintf(stdout, "\n");
- }
- return -1;
-}
-
-static int struct2_test(IC_Env *env)
-{
- m_es esi = {m_peach, 5050}, eso, esr;
-
- fprintf(stdout, "\n======== m_i_struct2 test ======\n\n");
- esr = m_i_struct2_test(NULL, &esi, &eso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_es(&esi, &eso) && cmp_es(&esi, &esr));
- if (!cmp_es(&esi, &eso)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_es(&esi);
- fprintf(stdout, " got:\n");
- print_es(&eso);
- fprintf(stdout, "\n");
- }
- if (!cmp_es(&esi, &esr)) {
- fprintf(stdout, " result error, sent:\n");
- print_es(&esi);
- fprintf(stdout, " got:\n");
- print_es(&esr);
- fprintf(stdout, "\n");
- }
- return -1;
-}
-
-
-static int seq1_test(IC_Env *env)
-{
- m_bseq bs, *bso, *bsr;
-
- m_b ba[3] = {{4711, 'a'}, {4712, 'b'}, {4713, 'c'}};
- bs._length = 3;
- bs._buffer = ba;
-
- fprintf(stdout, "\n======== m_i_seq1 test ======\n\n");
- bsr = m_i_seq1_test(NULL, &bs, &bso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_bseq(&bs, bso) && cmp_bseq(&bs, bsr));
- if (!cmp_bseq(&bs, bso)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_bseq(&bs);
- fprintf(stdout, " got:\n");
- print_bseq(bso);
- fprintf(stdout, "\n");
- }
- if (!cmp_bseq(&bs, bsr)) {
- fprintf(stdout, " result error, sent:\n");
- print_bseq(&bs);
- fprintf(stdout, " got:\n");
- print_bseq(bsr);
- fprintf(stdout, "\n");
- }
- CORBA_free(bso);
- CORBA_free(bsr);
- return -1;
-}
-
-static int seq2_test(IC_Env *env)
-{
- m_b ba[3] = {{4711, 'a'}, {4712, 'b'}, {4713, 'c'}};
- m_a a;
- m_a aa[2];
- m_aseq as, *aso, *asr;
-
- a.l = 9999;
- a.y._length = 3;
- a.y._buffer = ba;
- a.d = 66.89898989;
-
- aa[0] = a;
- aa[1] = a;
- as._length = 2;
- as._buffer = aa;
-
- fprintf(stdout, "\n======== m_i_seq2 test ======\n\n");
- asr = m_i_seq2_test(NULL, &as, &aso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_aseq(&as, aso) && cmp_aseq(&as, asr));
- if (!cmp_aseq(&as, aso)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_aseq(&as);
- fprintf(stdout, " got:\n");
- print_aseq(aso);
- fprintf(stdout, "\n");
- }
- if (!cmp_aseq(&as, asr)) {
- fprintf(stdout, " result error, sent:\n");
- print_aseq(&as);
- fprintf(stdout, " got:\n");
- print_aseq(asr);
- fprintf(stdout, "\n");
- }
- CORBA_free(aso);
- CORBA_free(asr);
- return -1;
-}
-
-static int seq3_test(IC_Env *env)
-{
- m_lseq lsi, *lso, *lsr;
- long al[500];
- int i=0;
-
- for (i = 0; i < 500; i++)
- al[i]=i;
- lsi._length = 500;
- lsi._buffer = al;
-
- fprintf(stdout, "\n======== m_i_seq3 test ======\n\n");
- lsr = m_i_seq3_test(NULL, &lsi, &lso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_lseq(&lsi, lso) && cmp_lseq(&lsi, lsr));
- if (!cmp_lseq(&lsi, lso)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_lseq(&lsi);
- fprintf(stdout, " got:\n");
- print_lseq(lso);
- fprintf(stdout, "\n");
- }
- if (!cmp_lseq(&lsi, lsr)) {
- fprintf(stdout, " result error, sent:\n");
- print_lseq(&lsi);
- fprintf(stdout, " got:\n");
- print_lseq(lsr);
- fprintf(stdout, "\n");
- }
- CORBA_free(lso);
- CORBA_free(lsr);
- return -1;
-}
-
-static int seq4_test(IC_Env *env)
-{
- char *stra0[3] = {"a", "long", "time"};
- char *stra1[3] = {"ago", "there", "was"};
- char *stra2[3] = {"a", "buggy", "compiler"};
- m_sstr3 str3s[3] = {{3, 3, stra0}, {3, 3, stra1}, {3, 3, stra2}};
- m_ssstr3 str3ssi = {3, 3, str3s};
- m_ssstr3 *str3sso, *str3ssr;
-
- fprintf(stdout, "\n======== m_i_seq4 test ======\n\n");
- str3ssr = m_i_seq4_test(NULL, &str3ssi, &str3sso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_ssstr3(&str3ssi, str3sso) &&
- cmp_ssstr3(&str3ssi, str3ssr));
- if (!cmp_ssstr3(&str3ssi, str3sso)){
- fprintf(stdout, " out parameter error, sent:\n");
- print_ssstr3(&str3ssi);
- fprintf(stdout, " got:\n");
- print_ssstr3(str3sso);
- fprintf(stdout, "\n");
- }
- if (!cmp_ssstr3(&str3ssi, str3ssr)) {
- fprintf(stdout, " result error, sent:\n");
- print_ssstr3(&str3ssi);
- fprintf(stdout, " got:\n");
- print_ssstr3(str3ssr);
- fprintf(stdout, "\n");
- }
- CORBA_free(str3sso);
- CORBA_free(str3ssr);
- return -1;
-}
-
-static int seq5_test(IC_Env *env)
-{
- m_arr3 arr3a[3] = {
- {4711, 18931947, 3},
- {4711, 18931947, 3},
- {4711, 18931947, 3}};
- m_sarr3 arr3sa[3] = {{3, 3, arr3a}, {3, 3, arr3a}, {3, 3, arr3a}};
- m_ssarr3 arr3ssi = {3, 3, arr3sa};
- m_ssarr3 *arr3sso;
- m_ssarr3 *arr3ssr;
-
- fprintf(stdout, "\n======== m_i_seq5 test ======\n\n");
- arr3ssr = m_i_seq5_test(NULL, &arr3ssi, &arr3sso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_ssarr3(&arr3ssi, arr3sso) &&
- cmp_ssarr3(&arr3ssi, arr3ssr));
- if (!cmp_ssarr3(&arr3ssi, arr3sso)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_ssarr3(&arr3ssi);
- fprintf(stdout, " got:\n");
- print_ssarr3(arr3sso);
- fprintf(stdout, "\n");
- }
- if (!cmp_ssarr3(&arr3ssi, arr3ssr)) {
- fprintf(stdout, " result error, sent:\n");
- print_ssarr3(&arr3ssi);
- fprintf(stdout, " got:\n");
- print_ssarr3(arr3ssr);
- fprintf(stdout, "\n");
- }
- CORBA_free(arr3sso);
- CORBA_free(arr3ssr);
- return -1;
-}
-
-static int array1_test(IC_Env *env)
-{
- int i;
- long al[500];
- m_arr1 alo;
- m_arr1_slice* alr;
-
- for (i = 0; i < 500; i++)
- al[i]=i;
-
- fprintf(stdout, "\n======== m_i_array1 test ======\n\n");
- alr = m_i_array1_test(NULL, al, alo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_arr1(al, alo) && cmp_arr1(al, alr));
- if (!cmp_arr1(al, alo)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_arr1(al);
- fprintf(stdout, " got:\n");
- print_arr1(alo);
- fprintf(stdout, "\n");
- }
- if (!cmp_arr1(al,alr)) {
- fprintf(stdout, " result error, sent:\n");
- print_arr1(al);
- fprintf(stdout, " got:\n");
- print_arr1(alr);
- fprintf(stdout, "\n");
- }
- free(alo);
- free(alr);
- return -1;
-}
-
-static int array2_test(IC_Env *env)
-{
- long dl[2][3] = {{11, 2, 7}, {22, 8 ,13}};
- m_dd dlo;
- m_dd_slice* dlr;
-
- fprintf(stdout, "\n======== m_i_array2 test ======\n\n");
- dlr = m_i_array2_test(NULL, dl, dlo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_dd(dl,dlo) && cmp_dd(dl,dlr));
- if (!cmp_dd(dl,dlo)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_dd(dl);
- fprintf(stdout, " got:\n");
- print_dd(dlo);
- fprintf(stdout, "\n");
- }
- if (!cmp_dd(dl,dlr)) {
- fprintf(stdout, " result error, sent:\n");
- print_dd(dl);
- fprintf(stdout, " got:\n");
- print_dd(dlr);
- fprintf(stdout, "\n");
- }
- free(*dlr);
- return -1;
-}
-
-static int enum_test(IC_Env *env)
-{
- m_fruit ei = m_banana, eo, er;
-
- fprintf(stdout, "\n======== m_i_enum test ======\n\n");
- er = m_i_enum_test(NULL, ei, &eo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(ei == eo && ei == er);
- if (ei != eo)
- fprintf(stdout, " out parameter error, sent: %d, got: %d\n", ei, eo);
- if (ei != er)
- fprintf(stdout, " result error, sent: %d, got: %d\n", ei, er);
- return -1;
-}
-
-static int string1_test(IC_Env *env)
-{
- char* si = longtext;
- char* so;
- char* sr;
-
- fprintf(stdout, "\n======== m_i_string1 test ======\n\n");
- sr = m_i_string1_test(NULL, si, &so, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_str(si, so) && cmp_str(si, sr));
- if (!cmp_str(si, so))
- fprintf(stdout, " out parameter error, sent: %s, got: %s\n", si, so);
- if (!cmp_str(si, sr))
- fprintf(stdout, " result error, sent: %s, got: %s\n", si, sr);
- CORBA_free(so);
- CORBA_free(sr);
- return -1;
-}
-
-static int string2_test(IC_Env *env)
-{
- char* sa[3] = {"hello", "foo", "bar"};
- m_sseq ssi = {3, 3, sa};
- m_sseq *sso, *ssr;
-
- fprintf(stdout, "\n======== m_i_string2 test ======\n\n");
- ssr = m_i_string2_test(NULL, &ssi, &sso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_sseq(&ssi, sso) && cmp_sseq(&ssi, sso));
- if (!cmp_sseq(&ssi, sso)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_sseq(&ssi);
- fprintf(stdout, "got:\n");
- print_sseq(sso);
- }
- if (!cmp_sseq(&ssi, ssr)) {
- fprintf(stdout, " result error, sent:\n");
- print_sseq(&ssi);
- fprintf(stdout, "got:\n");
- print_sseq(ssr);
- }
- CORBA_free(sso);
- CORBA_free(ssr);
- return -1;
-}
-
-static int string3_test(IC_Env *env)
-{
- char* si = longtext;
- char* so;
- char* sr;
-
- fprintf(stdout, "\n======== m_i_string3 test ======\n\n");
- sr = m_i_string3_test(NULL, si, &so, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_str(si, so) && cmp_str(si, so));
- if (!cmp_str(si, so))
- fprintf(stdout, " out parameter error, sent: %s, got: %s\n", si, so);
- if (!cmp_str(si, sr))
- fprintf(stdout, " result error, sent: %s, got: %s\n", si, sr);
- CORBA_free(so);
- CORBA_free(sr);
- return -1;
-}
-
-static int string4_test(IC_Env *env)
-{
- char as1[100] = "a string", as2[200] = "help", as3[200] = "hello there";
- m_strRec stri = { 1, /* dd */
- as1, /* str4 */
- {{'a', 'k'}, {'z', 'g'}, {'n', 'q'}}, /* str7 */
- {3, 3, "buf"}, /* str5 */
- as2, /* str6 */
- {'m', 'f', 'o'}, /* str8 */
- as3, /* str9 */
- {3, 3, "stu"} /* str10 */
- };
- m_strRec *stro, *strr;
-
- fprintf(stdout, "\n======== m_i_string4 test ======\n\n");
- strr = m_i_string4_test(NULL, &stri, &stro, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_strRec(&stri,stro) && cmp_strRec(&stri,strr));
- if (!cmp_strRec(&stri,stro)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_strRec(&stri);
- fprintf(stdout, " got:\n");
- print_strRec(stro);
- fprintf(stdout, "\n");
- }
- if (!cmp_strRec(&stri,strr)) {
- fprintf(stdout, " result error, sent:\n");
- print_strRec(&stri);
- fprintf(stdout, " got:\n");
- print_strRec(strr);
- fprintf(stdout, "\n");
- }
- CORBA_free(stro);
- CORBA_free(strr);
- return -1;
-}
-
-
-static int pid_test(IC_Env *env)
-{
- erlang_pid pid = {"", 7, 0, 0}, pido, pidr;
-
- strcpy(pid.node, this_node), /* this currently running node */
- fprintf(stdout, "\n======== m_i_pid test ======\n\n");
- pidr = m_i_pid_test(NULL, &pid, &pido, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_pid(&pid, &pido) && cmp_pid(&pid, &pidr));
- if (!cmp_pid(&pid, &pido)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_pid(&pid);
- fprintf(stdout, "got:\n");
- print_pid(&pido);
- }
- if (!cmp_pid(&pid, &pidr)) {
- fprintf(stdout, " result error, sent:\n");
- print_pid(&pid);
- fprintf(stdout, "got:\n");
- print_pid(&pidr);
- }
- return -1;
-}
-
-static int port_test(IC_Env *env)
-{
- erlang_port porti = {"node", 5, 1}, porto, portr;
-
- fprintf(stdout, "\n======== m_i_port test ======\n\n");
- portr = m_i_port_test(NULL, &porti, &porto, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_port(&porti, &porto) && cmp_port(&porti, &portr));
- if (!cmp_port(&porti, &porto)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_port(&porti);
- fprintf(stdout, "got:\n");
- print_port(&porto);
- }
- if (!cmp_port(&porti, &portr)) {
- fprintf(stdout, " result error, sent:\n");
- print_port(&porti);
- fprintf(stdout, "got:\n");
- print_port(&portr);
- }
- return -1;
-}
-
-static int ref_test(IC_Env *env)
-{
- erlang_ref refi = { "node1", 3, {1, 2, 3}, 1},
- refo, refr;
-
- fprintf(stdout, "\n======== m_i_ref test ======\n\n");
- refr = m_i_ref_test(NULL, &refi, &refo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_ref(&refi, &refo) && cmp_ref(&refi, &refr));
- if (!cmp_ref(&refi, &refo)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_ref(&refi);
- fprintf(stdout, "got:\n");
- print_ref(&refo);
- }
- if (!cmp_ref(&refi, &refr)) {
- fprintf(stdout, " result error, sent:\n");
- print_ref(&refi);
- fprintf(stdout, "got:\n");
- print_ref(&refr);
- }
- return -1;
-}
-
-static int term_test(IC_Env *env)
-{
- ETERM *ti, *to, *tr;
-
- ti = erl_format("[{hej, 1, 23}, \"string\", {1.23, 45}]");
-
- fprintf(stdout, "\n======== m_i_term test ======\n\n");
- tr = m_i_term_test(NULL, ti, &to, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(erl_match(ti, to) && erl_match(ti, tr));
- if (!erl_match(ti, to)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_term(ti);
- fprintf(stdout, "got:\n");
- print_term(to);
- }
- if (!erl_match(ti, tr)) {
- fprintf(stdout, " result error, sent:\n");
- print_term(ti);
- fprintf(stdout, "got:\n");
- print_term(tr);
- }
- erl_free_term(ti);
- erl_free_term(to);
- erl_free_term(tr);
- return -1;
-}
-
-static int typedef_test(IC_Env *env)
-{
- m_banan mbi, mbo; /* erlang_port */
- m_apa mai; /* ETERM* */
- m_apa mao = NULL;
- long tl;
-
- strcpy(mbi.node,"node");
- mbi.id = 15;
- mbi.creation = 1;
-
- fprintf(stdout, "\n======== m_i_typedef test ======\n\n");
- mai = erl_format("[{hej, 1, 23}, \"string\", {1.23, 45}]");
- tl = m_i_typedef_test(NULL, mai, &mbi, &mao, &mbo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(erl_match(mai, mao) && cmp_port(&mbi, &mbo) && tl == 4711);
- if (!erl_match(mai, mao)) {
- fprintf(stdout, " out parameter error (term), sent:\n");
- print_term(mai);
- fprintf(stdout, "got:\n");
- print_term(mao);
- }
- if (!cmp_port(&mbi, &mbo)) {
- fprintf(stdout, " out parameter error (port), sent:\n");
- print_port(&mbi);
- fprintf(stdout, "got:\n");
- print_port(&mbo);
- }
- if (tl != 4711) {
- fprintf(stdout, " result error, sent: 4711, got %ld\n", tl);
- }
- erl_free_term(mai);
- erl_free_term(mao);
- return -1;
-}
-
-static int inline_sequence_test(IC_Env *env)
-{
- int i;
- long al[500];
- m_s isi = {4711, {500, 10, al}},
- *iso, *isr;
-
- for (i = 0; i < 500; i++)
- al[i]=i;
- fprintf(stdout, "\n======== m_i_inline_sequence test ======\n\n");
- isr = m_i_inline_sequence_test(NULL, &isi, &iso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_s(&isi, iso) && cmp_s(&isi, isr));
- if (!cmp_s(&isi, iso)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_s(&isi);
- fprintf(stdout, "got:\n");
- print_s(iso);
- }
- if (!cmp_s(&isi, isr)) {
- fprintf(stdout, " result error, sent:\n");
- print_s(&isi);
- fprintf(stdout, "got:\n");
- print_s(isr);
- }
- CORBA_free(iso);
- CORBA_free(isr);
- return -1;
-}
-
-static int term_sequence_test(IC_Env *env)
-{
- ETERM* et_array[4] = {
- erl_format("[{apa, 1, 23}, \"string\", {1.23, 45}]"),
- erl_format("[{banan, 1, 23}, \"string\", {1.23, 45}]"),
- erl_format("[{apelsin, 1, 23}, \"string\", {1.23, 45}]"),
- erl_format("[{mango, 1, 23}, \"string\", {1.23, 45}]")};
- m_etseq etsi = {4, 4, et_array}, *etso, *etsr;
-
- fprintf(stdout, "\n======== m_i_term_sequence test ======\n\n");
- etsr = m_i_term_sequence_test(NULL, &etsi, &etso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_etseq(&etsi, etso) && cmp_etseq(&etsi, etsr));
- if (!cmp_etseq(&etsi, etso)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_etseq(&etsi);
- fprintf(stdout, "got:\n");
- print_etseq(etso);
- }
- if (!cmp_etseq(&etsi, etsr)) {
- fprintf(stdout, " result error, sent:\n");
- print_etseq(&etsi);
- fprintf(stdout, "got:\n");
- print_etseq(etsr);
- }
- free_etseq_buf(&etsi);
- free_etseq_buf(etso);
- free_etseq_buf(etsr);
- CORBA_free(etso);
- CORBA_free(etsr);
- return -1;
-}
-
-static int term_struct_test(IC_Env *env)
-{
- m_et eti = { erl_format("[{hej, 1, 23}, \"string\", {1.23, 45}]"),
- 121212 };
- m_et eto, etr;
-
- fprintf(stdout, "\n======== m_i_term_struct test ======\n\n");
- etr = m_i_term_struct_test(NULL, &eti, &eto, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_et(&eti, &eto) && cmp_et(&eti, &etr));
- if (!cmp_et(&eti, &eto)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_et(&eti);
- fprintf(stdout, "got:\n");
- print_et(&eto);
- }
- if (!cmp_et(&eti, &etr)) {
- fprintf(stdout, " result error, sent:\n");
- print_et(&eti);
- fprintf(stdout, "got:\n");
- print_et(&etr);
- }
- free_et(&eti);
- free_et(&eto);
- free_et(&etr);
- return -1;
-}
-
-static int wstring1_test(IC_Env *env)
-{
- CORBA_wchar wsi[] = {100, 101, 102, 103, 104, 0}, *wso, *wsr;
-
- fprintf(stdout, "\n======== m_i_wstring1 test ======\n\n");
- wsr = m_i_wstring1_test(NULL, wsi, &wso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_wstr(wsi, wso) && cmp_wstr(wsi, wsr));
- if (!cmp_wstr(wsi, wso)) {
- fprintf(stdout, " out parameter error, sent: \n");
- print_wstr(wsi);
- fprintf(stdout, "got:\n");
- print_wstr(wso);
- }
- if (!cmp_wstr(wsi, wsr)) {
- fprintf(stdout, " result error, sent: \n");
- print_wstr(wsi);
- fprintf(stdout, "got:\n");
- print_wstr(wsr);
- }
- CORBA_free(wso);
- CORBA_free(wsr);
- return -1;
-}
-
-/* Compare functions */
-static int cmp_aseq(m_aseq *a1, m_aseq *a2)
-{
- int i;
-
- if (a1->_length != a2->_length)
- return 0;
- for (i = 0; i < a1->_length; i++)
- if (cmp_a(&(a1->_buffer[i]), &(a2->_buffer[i])) == 0)
- return 0;
- return 1;
-}
-
-static int cmp_a(m_a *a1, m_a *a2)
-{
- return a1->l == a2->l &&
- a1->d == a2->d &&
- cmp_bseq(&a1->y, &a2->y);
-}
-
-static int cmp_bseq(m_bseq *b1, m_bseq *b2)
-{
- int i;
-
- if (b1->_length != b2->_length)
- return 0;
- for (i = 0; i < b1->_length; i++)
- if (cmp_b(&(b1->_buffer[i]), &(b2->_buffer[i])) == 0)
- return 0;
- return 1;
-}
-
-static int cmp_b(m_b *b1, m_b *b2)
-{
- return b1->l == b2->l && b1->c == b2->c;
-}
-
-static int cmp_lseq(m_lseq *b1, m_lseq *b2)
-{
- int i;
-
- if (b1->_length != b2->_length)
- return 0;
- for (i = 0; i < b1->_length; i++)
- if (b1->_buffer[i] != b2->_buffer[i])
- return 0;
- return 1;
-}
-
-static int cmp_etseq(m_etseq *b1, m_etseq *b2)
-{
- int i;
-
- if (b1->_length != b2->_length)
- return 0;
- for (i = 0; i < b1->_length; i++)
- if (!erl_match(b1->_buffer[i], b2->_buffer[i]))
- return 0;
- return 1;
-}
-
-static int cmp_et(m_et* b1, m_et *b2)
-{
- return erl_match(b1->e, b2->e) && b1->l == b2->l;
-}
-
-static int cmp_es(m_es *b1, m_es *b2)
-{
- return b1->f == b2->f && b1->l == b2->l;
-}
-
-static int cmp_arr1(m_arr1 b1, m_arr1 b2)
-{
- int i;
-
- for (i = 0; i < 500; i++)
- if (b1[i] != b2[i])
- return 0;
- return 1;
-}
-
-static int cmp_dd(m_dd b1, m_dd b2)
-{
-
- int i, j;
-
- for (i = 0; i < 2; i++)
- for (j = 0; j < 3; j++)
- if (b1[i][j] != b2[i][j])
- return 0;
- return 1;
-}
-
-
-
-static int cmp_strRec(m_strRec *b1, m_strRec *b2)
-{
- int i, j;
-
- if (b1->bb != b2->bb)
- return 0;
- if (!cmp_str(b1->str4,b2->str4))
- return 0;
- if (b1->str5._length != b2->str5._length)
- return 0;
- for (j = 0; j < b1->str5._length; j++)
- if (b1->str5._buffer[j] != b2->str5._buffer[j])
- return 0;
- if (!cmp_str(b1->str6,b2->str6))
- return 0;
- for (i = 0; i < 3; i++)
- for (j = 0; j < 2; j++)
- if (b1->str7[i][j] != b2->str7[i][j])
- return 0;
- for (j = 0; j < 3; j++)
- if (b1->str8[j] != b2->str8[j])
- return 0;
- if (!cmp_str(b1->str9,b2->str9))
- return 0;
- if (b1->str10._length != b2->str10._length)
- return 0;
- for (j = 0; j < b1->str10._length; j++)
- if (b1->str10._buffer[j] != b2->str10._buffer[j])
- return 0;
- return 1;
-}
-
-
-static int cmp_sseq(m_sseq *b1, m_sseq *b2)
-{
- int i;
-
- if (b1->_length != b2->_length)
- return 0;
- for (i = 0; i < b1->_length; i++)
- if (!cmp_str(b1->_buffer[i], b2->_buffer[i]))
- return 0;
- return 1;
-}
-
-
-static int cmp_pid(erlang_pid *p1, erlang_pid *p2)
-{
- return cmp_str(p1->node,p2-> node) &&
- p1->num == p2->num &&
- p1->serial == p2->serial &&
- p1->creation == p2->creation;
-}
-
-static int cmp_port(erlang_port *p1, erlang_port *p2)
-{
- return cmp_str(p1->node,p2-> node) && p1->id == p2->id;
-}
-
-static int cmp_ref(erlang_ref *p1, erlang_ref *p2)
-{
- return cmp_str(p1->node, p2->node) &&
- p1->len == p2->len &&
- (p1->len < 1 || p1->n[0] == p2->n[0]) &&
- (p1->len < 2 || p1->n[1] == p2->n[1]) &&
- (p1->len < 3 || p1->n[2] == p2->n[2]);
-}
-
-static int cmp_s(m_s *b1, m_s *b2)
-{
- int i;
-
- if (b1->l != b2->l)
- return 0;
- if (b1->sl._length != b2->sl._length)
- return 0;
- for (i = 0; i < b1->sl._length; i++)
- if (b1->sl._buffer[i] != b2->sl._buffer[i])
- return 0;
- return 1;
-}
-
-
-static int cmp_ssstr3(m_ssstr3 *b1, m_ssstr3 *b2)
-{
- int i,j;
-
- if (b1->_length != b2->_length)
- return 0;
- for (i = 0; i < b1->_length; i++) {
- if (b1->_buffer[i]._length != b2->_buffer[i]._length)
- return 0;
- for (j = 0; j < b1->_buffer[i]._length; j++)
- if (!cmp_str(b1->_buffer[i]._buffer[j],
- b2->_buffer[i]._buffer[j]))
- return 0;
- }
- return 1;
-}
-
-
-
-static int cmp_ssarr3(m_ssarr3 *b1, m_ssarr3 *b2)
-{
- int i;
-
- if (b1->_length != b2->_length)
- return 0;
- for (i = 0; i < b1->_length; i++) {
- if (!cmp_sarr3(&b1->_buffer[i], &b2->_buffer[i]))
- return 0;
- }
- return 1;
-}
-
-static int cmp_sarr3(m_sarr3 *b1, m_sarr3 *b2)
-{
- int i;
-
- if (b1->_length != b2->_length)
- return 0;
- for (i = 0; i < b1->_length; i++) {
- if (!cmp_arr3(b1->_buffer[i], b2->_buffer[i]))
- return 0;
- }
- return 1;
-}
-
-static int cmp_arr3(m_arr3 b1, m_arr3 b2)
-{
- int i;
-
- for (i = 0; i < sizeof(m_arr3)/sizeof(CORBA_long); i++) {
- if (b1[i] != b2[i])
- return 0;
- }
- return 1;
-}
-
-/* Print functions */
-static void print_aseq(m_aseq *a)
-{
- int i;
- fprintf(stdout, "\nm_aseq size: %ld --------\n", a->_length);
- for (i = 0; i < a->_length; i++)
- print_a(&(a->_buffer[i]));
-}
-
-static void print_a(m_a *a)
-{
- fprintf(stdout, "\nm_a --------\n l: %ld\n d:%f\n", a->l, a->d);
- print_bseq(&a->y);
-}
-
-static void print_bseq(m_bseq *b)
-{
- int i;
-
- fprintf(stdout, "\nm_bseq size: %ld --------\n",b->_length);
- for (i = 0; i < b->_length; i++)
- print_b(&(b->_buffer[i]));
-}
-
-static void print_lseq(m_lseq *b)
-{
- int i;
-
- fprintf(stdout, "\nm_lseq size: %ld --------\n",b->_length);
- for (i = 0; i < b->_length; i++)
- fprintf(stdout, "[%d]: %ld\n", i, b->_buffer[i]);
-}
-
-static void print_b(m_b *b)
-{
- fprintf(stdout, "\nm_b --------\n l: %ld\n c: %c\n", b->l, b->c);
-}
-
-
-static void print_etseq(m_etseq *b)
-{
- int i;
-
- for (i = 0; i < b->_length; i++) {
- fprintf(stdout, "[%d]:\n", i);
- erl_print_term(stdout, b->_buffer[i]);
- }
-}
-
-
-static void print_et(m_et* b)
-{
- fprintf(stdout, "\net struct --------\n");
- erl_print_term(stdout, b->e);
- fprintf(stdout, "long: %ld\n", b->l);
- fprintf(stdout, "\n--------\n");
-}
-
-static void print_es(m_es *b)
-{
- fprintf(stdout, "\nm_es --------\n f: %d\n l: %ld\n", b->f, b->l);
-}
-
-
-static void print_arr1(long a[10])
-{
- int i;
-
- for (i = 0; i < 10; i++)
- fprintf(stdout, "\n[%d]: %ld\n", i, a[i]);
-}
-
-static void print_dd(long a[2][3])
-{
- int i, j;
-
- fprintf(stdout, "\nlong dd[2][3] --------\n");
- for (i = 0; i < 2; i++)
- for (j = 0; j < 3; j++)
- fprintf(stdout, "\n[%d][%d]: %ld\n", i, j, a[i][j]);
-}
-
-
-static void print_strRec(m_strRec* sr)
-{
- int i, j;
-
- fprintf(stdout, "\nboolean bb : %d\n",sr->bb);
- fprintf(stdout, "string str4 : %s\n",sr->str4);
- fprintf(stdout, "str7[2][3] :\n");
- for (i = 0; i < 3; i++)
- for (j = 0; j < 2; j++)
- fprintf(stdout, "str7[%d][%d]: %ld\n", i, j, sr->str7[i][j]);
- fprintf(stdout, "str5._length : %ld\n",sr->str5._length);
- for (j = 0; j < sr->str5._length; j++)
- fprintf(stdout, "str5._buffer[%d]: %c\n", j, sr->str5._buffer[j]);
- fprintf(stdout, "string str6 : %s\n",sr->str6);
- fprintf(stdout, "str8 :\n");
- for (j = 0; j < 3; j++)
- fprintf(stdout, "str8[%d]: %c\n", j, sr->str8[j]);
- fprintf(stdout, "string str9 : %s\n",sr->str9);
- fprintf(stdout, "str10._length : %ld\n",sr->str10._length);
- for (j = 0; j < sr->str10._length; j++)
- fprintf(stdout, "str10._buffer[%d]: %c\n", j, sr->str10._buffer[j]);
-}
-
-static void print_sseq(m_sseq *b)
-{
- int i;
-
- fprintf(stdout, "\nm_sseq size: %ld --------\n",b->_length);
- for (i = 0; i < b->_length; i++)
- fprintf(stdout, "%s\n", b->_buffer[i]);
-
-}
-
-
-static void print_pid(erlang_pid *p)
-{
- fprintf(stdout, "\nerlang_pid --------\n node: %s\n num: %d\n "
- "serial: %d\n creation: %d\n",
- p->node, p->num, p->serial, p->creation);
-}
-
-static void print_port(erlang_port *p)
-{
- fprintf(stdout, "\nerlang_port --------\n node: %s\n id: %d\n "
- "creation: %d\n", p->node, p->id, p->creation);
-}
-
-static void print_ref(erlang_ref *p)
-{
- fprintf(stdout, "\nerlang_ref --------\n node: %s\n len: %d\n "
- "n[0]: %d\n n[1]: %d\n n[2]: %d\n creation: %d\n",
- p->node, p->len, p->n[0], p->n[1], p->n[2], p->creation);
-}
-
-static void print_term(ETERM *t)
-{
- fprintf(stdout, "\nETERM --------\n");
- erl_print_term(stdout, t);
- fprintf(stdout, "\n--------\n");
-}
-
-static void print_s(m_s *p)
-{
- int i;
-
- fprintf(stdout, "\n%ld\n", p->l);
- for (i = 0; i < p->sl._length; i++)
- fprintf(stdout, "\n[%d]: %ld\n", i, p->sl._buffer[i]);
-}
-
-
-static void print_ssstr3(m_ssstr3 *b1)
-{
- int i,j;
-
- fprintf(stdout, "\nSSSTR3 --------\n");
- fprintf(stdout,"b1->_length = %ld\n",b1->_length);
- for (i = 0; i < b1->_length; i++) {
- fprintf(stdout,"\nb1->_buffer[%d]._length %ld\n",
- i, b1->_buffer[i]._length);
- for (j = 0; j < b1->_buffer[i]._length; j++)
- fprintf(stdout,"b1->_buffer[%d]._buffer[%d] = %s\n",
- i, j, b1->_buffer[i]._buffer[j]);
- }
- fprintf(stdout, "\n--------\n");
-}
-
-static void print_wstr(CORBA_wchar *ws)
-{
- int i = 0;
-
- fprintf(stdout, "\nwstr --------\n");
- while (ws[i]) {
- fprintf(stdout, "[%d]: %ld\n", i, ws[i]);
- i++;
- }
- fprintf(stdout, "\n--------\n");
-}
-
-
-static void print_ssarr3(m_ssarr3 *b1)
-{
- int i;
-
- fprintf(stdout, "\nssarr3 --------\n");
- fprintf(stdout,"length: %ld\n",b1->_length);
- fprintf(stdout, "buffer:\n");
- for (i = 0; i < b1->_length; i++)
- print_sarr3(&b1->_buffer[i]);
- fprintf(stdout, "\n--------\n");
-}
-
-static void print_sarr3(m_sarr3 *b1)
-{
- int i;
-
- fprintf(stdout, "\nsarr3 --------\n");
- fprintf(stdout,"length: %ld\n",b1->_length);
- fprintf(stdout, "buffer:\n");
- for (i = 0; i < b1->_length; i++)
- print_arr3(b1->_buffer[i]);
- fprintf(stdout, "\n--------\n");
-}
-
-static void print_arr3(m_arr3 b1)
-{
- int i;
-
- fprintf(stdout, "\narr3 --------\n");
- for (i = 0; i < sizeof(m_arr3)/sizeof(CORBA_long); i++)
- fprintf(stdout, "%ld ", b1[i]);
- fprintf(stdout, "\n--------\n");
-}
-
-static void free_etseq_buf(m_etseq *b)
-{
- int i;
-
- for (i = 0; i < b->_length; i++)
- erl_free_term(b->_buffer[i]);
-}
-
-static void free_et(m_et* b)
-{
- erl_free_term(b->e);
-}
-
-static void showtime(MyTimeval *start, MyTimeval *stop)
-{
- MyTimeval elapsed;
-
- elapsed.tv_sec = stop->tv_sec - start->tv_sec;
- elapsed.tv_usec = stop->tv_usec - start->tv_usec;
- while (elapsed.tv_usec < 0) {
- elapsed.tv_sec -= 1;
- elapsed.tv_usec += 1000000;
- }
- fprintf(stderr,"%ld.%06ld seconds\n",elapsed.tv_sec, elapsed.tv_usec);
-}
-
-static void my_gettimeofday(MyTimeval *tv)
-#ifdef __WIN32__
-#define EPOCH_JULIAN_DIFF 11644473600i64
-{
- SYSTEMTIME t;
- FILETIME ft;
- LONGLONG lft;
-
- GetSystemTime(&t);
- SystemTimeToFileTime(&t, &ft);
- memcpy(&lft, &ft, sizeof(lft));
- tv->tv_usec = (long) ((lft / 10i64) % 1000000i64);
- tv->tv_sec = (long) ((lft / 10000000i64) - EPOCH_JULIAN_DIFF);
-}
-#elif defined VXWORKS
-{
- int rate = sysClkRateGet(); /* Ticks per second */
- unsigned long ctick = tickGet();
- tv->tv_sec = ctick / rate; /* secs since reboot */
- tv->tv_usec = ((ctick - (tv->tv_sec * rate))*1000000)/rate;
-}
-#else
-{
- gettimeofday(tv, NULL);
-}
-#endif
diff --git a/lib/ic/test/c_client_erl_server_proto_SUITE_data/c_erl_test.idl b/lib/ic/test/c_client_erl_server_proto_SUITE_data/c_erl_test.idl
deleted file mode 100644
index b6ba1583f3..0000000000
--- a/lib/ic/test/c_client_erl_server_proto_SUITE_data/c_erl_test.idl
+++ /dev/null
@@ -1,174 +0,0 @@
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 2003-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-#include "erlang.idl"
-
-
-const short TestConst = 1;
-
-module m {
-
- const short TestConst = 2;
-
- struct b {
- long l;
- char c;
- };
-
- struct simple {
- long l;
- b b_t;
- };
-
- enum fruit {orange, banana, apple, peach, pear};
-
- typedef sequence<long> lseq;
-
- typedef sequence<b> bseq;
-
- struct a {
- long l;
- bseq y;
- double d;
- };
-
- typedef sequence<a> aseq;
-
- typedef sequence<string> sseq;
- typedef string str;
- typedef long myLong;
-
- typedef long arr1[500], dd[2][3];
-
- typedef erlang::term apa;
- typedef erlang::port banan;
-
- typedef sequence<erlang::term> etseq;
-
- struct s {
- long l;
- sequence<long> sl;
- };
-
- struct es {
- fruit f;
- myLong l;
- };
-
- struct et {
- erlang::term e;
- long l;
- };
-
-
- typedef sequence<char> str1;
- typedef string<12> str2;
- typedef char str3[3];
-
- typedef sequence<string> sstr3; // sequence of string
- typedef sequence<sstr3> ssstr3; // sequence of sequences of strings
-
- typedef long arr3[3]; // array of long
- typedef sequence<arr3> sarr3; // sequence of array
- typedef sequence<sarr3> ssarr3; // sequence of sequnces of arrays of strings
-
- struct strRec{
- boolean bb;
- string str4;
- long str7[3][2];
- sequence<char> str5;
- string<12> str6;
- str3 str8;
- str2 str9;
- str1 str10;
- };
-
-
- struct dyn {
- long l;
- sequence<long> sl;
- };
- typedef dyn arr2[1][2];
-
-
- interface i {
-
- const short TestConst = 3;
-
- //arr2 suck(in arr2 x, out arr2 y );
-
- ///////////////////////////////// attribute long l;
-
- // simple types
- void void_test();
- long long_test(in long a, out long a1);
- long long longlong_test(in long long a, out long long a1);
- unsigned short ushort_test(in unsigned short a, out unsigned short a1);
- unsigned long ulong_test(in unsigned long a, out unsigned long a1);
- unsigned long long ulonglong_test(in unsigned long long a, out unsigned long long a1);
- double double_test(in double a, out double a1);
- char char_test(in char a, out char a1);
- wchar wchar_test(in wchar a, out wchar a1);
- octet octet_test(in octet a, out octet a1);
- boolean bool_test(in boolean a, out boolean a1);
-
- // Seq. and struct tests
- b struct_test(in b a, out b a1);
- es struct2_test(in es a, out es a1);
- //simple struct3_test(in simple x, out simple y);
- bseq seq1_test(in bseq a, out bseq a1);
- aseq seq2_test(in aseq a, out aseq a1);
- lseq seq3_test(in lseq a, out lseq a1);
- ssstr3 seq4_test(in ssstr3 a, out ssstr3 a1);
- ssarr3 seq5_test(in ssarr3 a, out ssarr3 a1);
-
- // Array tests
- arr1 array1_test(in arr1 a, out arr1 a1);
- dd array2_test(in dd a, out dd a1);
-
- // enum test
- fruit enum_test(in fruit a, out fruit a1);
-
- // string tests
- string string1_test(in string a, out string a1);
- wstring wstring1_test(in wstring a, out wstring a1);
- sseq string2_test(in sseq a, out sseq a1);
- str string3_test(in str a, out str a1);
- strRec string4_test(in strRec a, out strRec a1);
-
- // Special erlang types
- erlang::pid pid_test(in erlang::pid a, out erlang::pid a1);
- erlang::port port_test(in erlang::port a, out erlang::port a1);
- erlang::ref ref_test(in erlang::ref a, out erlang::ref a1);
- erlang::term term_test(in erlang::term a, out erlang::term a1);
-
- // typedef test
- long typedef_test(in apa a, in banan b, out apa a1, out banan b1);
-
- // inlined seq. test
- s inline_sequence_test(in s a, out s a1);
-
- // term seq. test
- etseq term_sequence_test(in etseq a, out etseq a1);
- // term struct test
- et term_struct_test(in et a, out et a1);
-
- };
-
-};
diff --git a/lib/ic/test/c_client_erl_server_proto_SUITE_data/erl_server.erl b/lib/ic/test/c_client_erl_server_proto_SUITE_data/erl_server.erl
deleted file mode 100644
index 2fe1dc2f79..0000000000
--- a/lib/ic/test/c_client_erl_server_proto_SUITE_data/erl_server.erl
+++ /dev/null
@@ -1,29 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(erl_server).
-
--export([run/0, stop/0]).
-
-run() ->
- m_i:oe_create().
-
-stop() ->
- gen_server:cast(cidl_test, stop).
diff --git a/lib/ic/test/c_client_erl_server_proto_SUITE_data/m_i_impl.erl b/lib/ic/test/c_client_erl_server_proto_SUITE_data/m_i_impl.erl
deleted file mode 100644
index 92420eaeb4..0000000000
--- a/lib/ic/test/c_client_erl_server_proto_SUITE_data/m_i_impl.erl
+++ /dev/null
@@ -1,162 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(m_i_impl).
--include("m.hrl").
-
--export([init/1, terminate/2, void_test/1, long_test/2, ushort_test/2,
- longlong_test/2, ulong_test/2, ulonglong_test/2,
- double_test/2, char_test/2, wchar_test/2, octet_test/2,
- bool_test/2, struct_test/2, struct2_test/2, seq1_test/2,
- seq2_test/2, seq3_test/2, seq4_test/2, seq5_test/2,
- array1_test/2, array2_test/2, enum_test/2, string1_test/2,
- string2_test/2, string3_test/2, string4_test/2, pid_test/2,
- port_test/2, ref_test/2, term_test/2, typedef_test/3,
- inline_sequence_test/2, '_set_l'/2, '_get_l'/1,
- term_struct_test/2, term_sequence_test/2, wstring1_test/2]).
-
--define(PRINTDEBUG(Case),
- io:format("erl_server: case: ~p~n"
- "erl_server: location: ~p~n", [Case, [?FILE, ?LINE]])).
--define(PRINTDEBUG2(Case, Msg),
- io:format("erl_server: case: ~p~n"
- "erl_server: Msg: ~p~n"
- "erl_server: location: ~p~n", [Case, Msg, [?FILE, ?LINE]])).
-
-init(Env) ->
- {ok, []}.
-
-terminate(F, R) ->
- ok.
-
-'_get_l'(State) ->
- ?PRINTDEBUG("_get_l"),
- {reply, State, State}.
-void_test(State) ->
- ?PRINTDEBUG("void_test"),
- {reply, ok, State}.
-
-'_set_l'(State, V) ->
- ?PRINTDEBUG2("_set_l", V),
- {reply, ok, V}.
-ushort_test(State, V) ->
- ?PRINTDEBUG2("ushort_test", V),
- {reply, {V, V}, State}.
-long_test(State, V) ->
- ?PRINTDEBUG2("long_test", V),
- {reply, {V, V}, State}.
-longlong_test(State, V) ->
- ?PRINTDEBUG2("longlong_test", V),
- {reply, {V, V}, State}.
-ulong_test(State, V) ->
- ?PRINTDEBUG2("ulong_test", V),
- {reply, {V, V}, State}.
-ulonglong_test(State, V) ->
- ?PRINTDEBUG2("ulonglong_test", V),
- {reply, {V, V}, State}.
-double_test(State, V) ->
- ?PRINTDEBUG2("double_test", V),
- {reply, {V, V}, State}.
-char_test(State, V) ->
- ?PRINTDEBUG2("char_test", V),
- {reply, {V, V}, State}.
-wchar_test(State, V) ->
- ?PRINTDEBUG2("wchar_test", V),
- {reply, {V, V}, State}.
-octet_test(State, V) ->
- ?PRINTDEBUG2("octet_test", V),
- {reply, {V, V}, State}.
-bool_test(State, V) ->
- ?PRINTDEBUG2("bool_test", V),
- {reply, {V, V}, State}.
-
-struct_test(State, V) ->
- ?PRINTDEBUG2("struct_test", V),
- {reply, {V, V}, State}.
-struct2_test(State, V) ->
- ?PRINTDEBUG2("struct2_test", V),
- {reply, {V, V}, State}.
-seq1_test(State, V) ->
- ?PRINTDEBUG2("seq1_test", V),
- {reply, {V, V}, State}.
-seq2_test(State, V) ->
- ?PRINTDEBUG2("seq2_test", V),
- {reply, {V, V}, State}.
-seq3_test(State, V) ->
- ?PRINTDEBUG2("seq3_test", V),
- {reply, {V, V}, State}.
-seq4_test(State, V) ->
- ?PRINTDEBUG2("seq4_test", V),
- {reply, {V, V}, State}.
-seq5_test(State, V) ->
- ?PRINTDEBUG2("seq5_test", V),
- {reply, {V, V}, State}.
-array1_test(State, V) ->
- ?PRINTDEBUG2("array1_test", V),
- {reply, {V, V}, State}.
-array2_test(State, V) ->
- ?PRINTDEBUG2("array2_test", V),
- {reply, {V, V}, State}.
-enum_test(State, V) ->
- ?PRINTDEBUG2("enum_test", V),
- {reply, {V, V}, State}.
-string1_test(State, V) ->
- ?PRINTDEBUG2("string1_test", V),
- {reply, {V, V}, State}.
-string2_test(State, V) ->
- ?PRINTDEBUG2("string2_test", V),
- {reply, {V, V}, State}.
-string3_test(State, V) ->
- ?PRINTDEBUG2("string3_test", V),
- {reply, {V, V}, State}.
-string4_test(State, V) ->
- ?PRINTDEBUG2("string4_test", V),
- {reply, {V, V}, State}.
-pid_test(State, V) ->
- ?PRINTDEBUG2("pid_test", V),
- {reply, {V, V}, State}.
-port_test(State, V) ->
- ?PRINTDEBUG2("port_test", binary_to_list(term_to_binary(V))),
- {reply, {V, V}, State}.
-ref_test(State, V) ->
- ?PRINTDEBUG2("ref_test", binary_to_list(term_to_binary(V))),
- {reply, {V, V}, State}.
-term_test(State, V) ->
- ?PRINTDEBUG2("term_test", V),
- {reply, {V, V}, State}.
-typedef_test(State, A, B) ->
- ?PRINTDEBUG2("typedef_test", [A,B]),
- {reply, {4711, A, B}, State}.
-inline_sequence_test(State, V) ->
- ?PRINTDEBUG2("inline_sequence_test", V),
- {reply, {V, V}, State}.
-term_sequence_test(State, V) ->
- ?PRINTDEBUG2("term_sequence_test", V),
- {reply, {V, V}, State}.
-term_struct_test(State, V) ->
- ?PRINTDEBUG2("term_struct_test", V),
- {reply, {V, V}, State}.
-wstring1_test(State, V) ->
- ?PRINTDEBUG2("wstring1_test", V),
- {reply, {V, V}, State}.
-
-
-
-
diff --git a/lib/ic/test/c_client_erl_server_proto_SUITE_data/my.c b/lib/ic/test/c_client_erl_server_proto_SUITE_data/my.c
deleted file mode 100644
index 46920ce05f..0000000000
--- a/lib/ic/test/c_client_erl_server_proto_SUITE_data/my.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 2004-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-
-#include "ic.h"
-#include "m_i.h"
-
-int my_prepare_notification_encoding(CORBA_Environment *env)
-{
- return oe_prepare_notification_encoding(env);
-}
-
-int my_send_notification(CORBA_Environment *env)
-{
- return oe_send_notification(env);
-}
-
-int my_prepare_request_encoding(CORBA_Environment *env)
-{
- return oe_prepare_request_encoding(env);
-}
-
-int my_send_request_and_receive_reply(CORBA_Environment *env)
-{
- return oe_send_request_and_receive_reply(env);
-}
-
-int my_prepare_reply_decoding(CORBA_Environment *env)
-{
- return oe_prepare_reply_decoding(env);
-}
-
-
-
diff --git a/lib/ic/test/c_client_erl_server_proto_tmo_SUITE.erl b/lib/ic/test/c_client_erl_server_proto_tmo_SUITE.erl
deleted file mode 100644
index 334db7c1da..0000000000
--- a/lib/ic/test/c_client_erl_server_proto_tmo_SUITE.erl
+++ /dev/null
@@ -1,265 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
-%%----------------------------------------------------------------------
-%% Purpose : Test suite for c-client/erl-server
-%%----------------------------------------------------------------------
-
--module(c_client_erl_server_proto_tmo_SUITE).
--include_lib("common_test/include/ct.hrl").
-
--export([init_per_testcase/2, end_per_testcase/2,
- all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2,
- void_test/1, long_test/1, long_long_test/1,
- unsigned_short_test/1, unsigned_long_test/1,
- unsigned_long_long_test/1, double_test/1, char_test/1,
- wchar_test/1, octet_test/1, bool_test/1, struct_test/1,
- struct2_test/1, seq1_test/1, seq2_test/1, seq3_test/1,
- seq4_test/1, seq5_test/1, array1_test/1, array2_test/1,
- enum_test/1, string1_test/1, string2_test/1, string3_test/1,
- string4_test/1, pid_test/1, port_test/1, ref_test/1, term_test/1,
- typedef_test/1, inline_sequence_test/1, term_sequence_test/1,
- term_struct_test/1, wstring1_test/1]).
-
--define(DEFAULT_TIMEOUT, 20000).
--define(PORT_TIMEOUT, 15000).
--define(ERLANG_SERVER_NAME, idl_erlang_server).
--define(C_CLIENT_NODE_NAME, c_client_idl_test).
-
-%% Add/remove code path and watchdog before/after each test case.
-%%
-init_per_testcase(_Case, Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- code:add_patha(DataDir),
-
- %% Since other test suites use the module m_i, we have
- %% to make sure we are using the right m_i module.
- code:purge(m_i),
- code:load_file(m_i),
-
- WatchDog = test_server:timetrap(?DEFAULT_TIMEOUT),
- [{watchdog, WatchDog}| Config].
-
-end_per_testcase(_Case, Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- code:del_path(DataDir),
- WatchDog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(WatchDog).
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [void_test, long_test, long_long_test,
- unsigned_short_test, unsigned_long_test,
- unsigned_long_long_test, double_test, char_test,
- wchar_test, octet_test, bool_test, struct_test,
- struct2_test, seq1_test, seq2_test, seq3_test,
- seq4_test, seq5_test, array1_test, array2_test,
- enum_test, string1_test, string2_test, string3_test,
- string4_test, pid_test, port_test, ref_test, term_test,
- typedef_test, inline_sequence_test, term_sequence_test,
- term_struct_test, wstring1_test].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-array1_test(Config) ->
- do_test(array1_test, Config).
-
-array2_test(Config) ->
- do_test(array2_test, Config).
-
-bool_test(Config) ->
- do_test(bool_test, Config).
-
-char_test(Config) ->
- do_test(char_test, Config).
-
-double_test(Config) ->
- do_test(double_test, Config).
-
-enum_test(Config) ->
- do_test(enum_test, Config).
-
-inline_sequence_test(Config) ->
- do_test(inline_sequence_test, Config).
-
-long_long_test(Config) ->
- do_test(long_long_test, Config).
-
-long_test(Config) ->
- do_test(long_test, Config).
-
-octet_test(Config) ->
- do_test(octet_test, Config).
-
-pid_test(Config) ->
- do_test(pid_test, Config).
-
-port_test(Config) ->
- do_test(port_test, Config).
-
-ref_test(Config) ->
- do_test(ref_test, Config).
-
-seq1_test(Config) ->
- do_test(seq1_test, Config).
-
-seq2_test(Config) ->
- do_test(seq2_test, Config).
-
-seq3_test(Config) ->
- do_test(seq3_test, Config).
-
-seq4_test(Config) ->
- do_test(seq4_test, Config).
-
-seq5_test(Config) ->
- do_test(seq5_test, Config).
-
-string1_test(Config) ->
- do_test(string1_test, Config).
-
-string2_test(Config) ->
- do_test(string2_test, Config).
-
-string3_test(Config) ->
- do_test(string3_test, Config).
-
-string4_test(Config) ->
- do_test(string4_test, Config).
-
-struct2_test(Config) ->
- do_test(struct2_test, Config).
-
-struct_test(Config) ->
- do_test(struct_test, Config).
-
-term_sequence_test(Config) ->
- do_test(term_sequence_test, Config).
-
-term_struct_test(Config) ->
- do_test(term_struct_test, Config).
-
-term_test(Config) ->
- do_test(term_test, Config).
-
-typedef_test(Config) ->
- do_test(typedef_test, Config).
-
-unsigned_long_long_test(Config) ->
- do_test(unsigned_long_long_test, Config).
-
-unsigned_long_test(Config) ->
- do_test(unsigned_long_test, Config).
-
-unsigned_short_test(Config) ->
- do_test(unsigned_short_test, Config).
-
-void_test(Config) ->
- do_test(void_test, Config).
-
-wchar_test(Config) ->
- do_test(wchar_test, Config).
-
-wstring1_test(Config) ->
- do_test(wstring1_test, Config).
-
-
-%% It is here that all tests really are done.
-%%
-
-do_test(Case, Config) ->
- %% Trap exits
- process_flag(trap_exit, true),
- %% Start the server
- {ok, _Pid} = m_i:oe_create_link([], {local, ?ERLANG_SERVER_NAME}),
- Node = atom_to_list(node()),
- %% [NodeName, HostName] = string:tokens(Node, "@"),
- DataDir = proplists:get_value(data_dir, Config),
- %% io:format("~p: data directory: ~p~n", [?MODULE, DataDir]),
- Cookie = atom_to_list(erlang:get_cookie()),
- %% Start C-client node as a port program.
- Cmd = filename:join([DataDir, "c_client"]) ++
- " -this-node-name " ++ atom_to_list(?C_CLIENT_NODE_NAME) ++
- " -peer-node " ++ Node ++
- " -peer-process-name " ++ atom_to_list(?ERLANG_SERVER_NAME) ++
- " -cookie " ++ Cookie ++
- " -test-case " ++ atom_to_list(Case),
- Port = open_port({spawn, Cmd}, [exit_status, eof, stderr_to_stdout]),
- Res = wait_for_completion(Port),
- %% Kill off node if there was timeout
- case Res of
- {error, timeout} ->
- catch rpc:cast(?C_CLIENT_NODE_NAME, erlang, halt, [1]);
- _ ->
- ok
- end,
- process_flag(trap_exit, false),
- catch m_i:stop(?ERLANG_SERVER_NAME),
- ok = Res.
-
-
-%% Wait for eof *and* exit status, but return if exit status indicates
-%% an error, or we have been waiting more than PORT_TIMEOUT seconds.
-%%
-wait_for_completion(Port) ->
- wait_for_completion(Port, 0).
-
-wait_for_completion(Port, N) when N < 2 ->
- receive
- {Port, {data, Bytes}} ->
- %% Relay output
- io:format("~s", [Bytes]),
- wait_for_completion(Port, N);
- {Port, {exit_status, 0}} ->
- wait_for_completion(Port, N + 1);
- {Port, {exit_status, Status}} ->
- {error, Status};
- {Port, eof} ->
- wait_for_completion(Port, N + 1);
- {'EXIT', Port, Reason} ->
- io:format("Port exited with reason: ~w~n", [Reason]),
- wait_for_completion(Port, N);
- {'EXIT', From, Reason} ->
- io:format("Got unexpected exit: ~p~n", [{'EXIT', From, Reason}]),
- wait_for_completion(Port, N)
- after ?PORT_TIMEOUT ->
- {error, timeout}
- end;
-wait_for_completion(_, _) ->
- ok.
-
-
-
diff --git a/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/Makefile.src b/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/Makefile.src
deleted file mode 100644
index 6d6bd9baab..0000000000
--- a/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/Makefile.src
+++ /dev/null
@@ -1,155 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2004-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-# Makefile.src for c_client_erl_server test
-# Note: This file *must* work for both Unix and Windows
-#
-# We use both `rm' (Unix) and `del' (Windows) for removing files, but
-# with a `-' in front so that the error in not finding `rm' (`del') on
-# Windows (Unix) is ignored.
-#
-# VxWorks? XXX
-#
-
-.SUFFIXES:
-.SUFFIXES: .c .h .erl .idl @obj@ .@EMULATOR@
-
-
-# Variables from ts:
-#
-
-ERL_INCLUDE = @erl_include@
-
-IC_INCLUDE_PATH = @ic_include_path@
-IC_LIB = @ic_lib@
-
-ERL_INTERFACE_INCLUDE = @erl_interface_include@
-ERL_INTERFACE_LIB = @erl_interface_lib@
-ERL_INTERFACE_EILIB = @erl_interface_eilib@
-ERL_INTERFACE_THREADLIB = @erl_interface_threadlib@
-ERL_INTERFACE_SOCK_LIBS = @erl_interface_sock_libs@
-
-CC = @CC@
-## XXX Should set warning flag with a DEBUG_FLAG
-CFLAGS = @CFLAGS@ @DEFS@ -I@erl_include@ \
- -I@ic_include_path@ -I@erl_interface_include@
-
-LD = @LD@
-LDFLAGS = @CROSSLDFLAGS@
-LIBS = $(IC_LIB) $(ERL_INTERFACE_LIB) $(ERL_INTERFACE_EILIB) \
- $(ERL_INTERFACE_THREADLIB) @LIBS@ $(ERL_INTERFACE_SOCK_LIBS)
-ERLC = erlc
-
-# Generated C header files
-GEN_H_FILES = \
- m.h \
- m_i.h \
- oe_c_erl_test.h
-
-# Generated C files
-GEN_C_FILES = \
- m.c \
- m_i.c \
- oe_c_erl_test.c \
- oe_code_m_a.c \
- oe_code_m_arr1.c \
- oe_code_m_arr2.c \
- oe_code_m_arr3.c \
- oe_code_m_aseq.c \
- oe_code_m_b.c \
- oe_code_m_bseq.c \
- oe_code_m_dd.c \
- oe_code_m_dyn.c \
- oe_code_m_dyn_sl.c \
- oe_code_m_es.c \
- oe_code_m_et.c \
- oe_code_m_etseq.c \
- oe_code_m_fruit.c \
- oe_code_m_lseq.c \
- oe_code_m_s.c \
- oe_code_m_s_sl.c \
- oe_code_m_sarr3.c \
- oe_code_m_simple.c \
- oe_code_m_ssarr3.c \
- oe_code_m_sseq.c \
- oe_code_m_ssstr3.c \
- oe_code_m_sstr3.c \
- oe_code_m_str1.c \
- oe_code_m_str3.c \
- oe_code_m_strRec.c \
- oe_code_m_strRec_str5.c \
- oe_code_m_strRec_str7.c
-
-GEN_HRL_FILES = \
- m.hrl \
- m_i.hrl \
- oe_c_erl_test.hrl
-
-GEN_ERL_FILES = \
- m.erl \
- m_arr2.erl \
- m_arr3.erl \
- m_i.erl \
- m_str3.erl \
- oe_c_erl_test.erl
-
-C_FILES = $(GEN_C_FILES) c_client.c my.c
-
-OBJS = $(C_FILES:.c=@obj@)
-
-PGMS = c_client@exe@
-
-ERL_FILES = $(GEN_ERL_FILES) m_i_impl.erl
-
-EBINS = $(ERL_FILES:.erl=.@EMULATOR@)
-
-
-all: $(PGMS) $(EBINS)
-
-$(GEN_ERL_FILES) $(GEN_HRL_FILES): c_erl_test.built_erl
-$(GEN_C_FILES) $(GEN_H_FILES): c_erl_test.built_c
-$(OBJS): $(GEN_C_FILES) $(GEN_H_FILES)
-$(EBINS): $(GEN_ERL_FILES) $(GEN_HRL_FILES)
-
-clean:
- -rm -f $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \
- $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) \
- c_erl_test.built_erl c_erl_test.built_c
- -del /F /Q $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \
- $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) \
- c_erl_test.built_erl c_erl_test.built_c
-
-$(PGMS): $(OBJS)
- $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
-
-c_erl_test.built_c: c_erl_test.idl
- $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,c_client}" c_erl_test.idl
- echo done > c_erl_test.built_c
-
-c_erl_test.built_erl: c_erl_test.idl
- $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,erl_genserv}" c_erl_test.idl
- echo done > c_erl_test.built_erl
-
-.c@obj@:
- $(CC) -c -o $*@obj@ $(CFLAGS) $<
-
-.erl.@EMULATOR@:
- $(ERLC) -I $(IC_INCLUDE_PATH) $<
-
diff --git a/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/c_client.c b/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/c_client.c
deleted file mode 100644
index 17ef21f4f4..0000000000
--- a/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/c_client.c
+++ /dev/null
@@ -1,1764 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 2004-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-/* C-client for test of IC.
- *
- * TODO:
- *
- * 1. XXX #includes for VxWorks, Windows
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#ifndef __WIN32__
-# include <unistd.h>
-#endif
-
-#include <string.h>
-
-#ifdef __WIN32__
-# include <time.h>
-# include <sys/timeb.h>
-#elif defined VXWORKS
-#include <time.h>
-#include <sys/times.h>
-#else
-#include <sys/time.h>
-#endif
-
-#include <ctype.h>
-
-#ifdef __WIN32__
-# include <winsock2.h>
-# include <windows.h>
-#else
-# include <sys/types.h>
-# include <sys/socket.h>
-# include <netinet/in.h>
-# include <arpa/inet.h>
-# include <netdb.h>
-#endif
-
-#include "ei.h"
-#include "erl_interface.h"
-#include "m_i.h"
-
-#define HOSTNAMESZ 255
-#define NODENAMESZ 512
-
-#define INBUFSZ 10
-#define OUTBUFSZ 0
-
-#define MAXTRIES 5
-
-#define CHECK_EXCEPTION(x) \
- if ((x)->_major != CORBA_NO_EXCEPTION) { \
- fprintf(stderr,"\n\nException: %s\n\n", \
- (char *)CORBA_exception_value((x))); \
- CORBA_exception_free((x)); \
- return -1; \
- } \
-
-/* XXX Should free things here too! */
-#define RETURN_IF_OK(x) \
- if ((x)) {\
- fprintf(stdout, "ok\n");\
- return 0;\
- }\
-
-#define cmp_str(x,y) (!strcmp((x),(y)))
-#define cmp_wstr(x,y) (!ic_wstrcmp((x),(y)))
-
-typedef CORBA_Environment IC_Env;
-
-typedef int (*TestFunc)(IC_Env *);
-typedef struct {
- char *name;
- TestFunc func;
-} TestCase;
-
-static char longtext[] =
-"Introduction The IC application is an IDL compiler implemented in Erlang."
-" The IDL compiler generates client stubs and server skeletons."
-" Several back-ends are supported, and they fall into three main groups."
-" For more details on IC compiler options consult the ic(3) manual page."
-" Argument passing cases 1 Caller allocates all necessary storage,"
-" except that which may be encapsulated and managed within the parameter itself."
-" 2 The caller allocates a pointer and passes it by reference to the callee."
-" The callee sets the pointer to point to a valid instance of the parameter's type."
-" The caller is responsible for releasing the returned storage."
-" Following completion of a request, the caller is not allowed to modify any values"
-" in the returned storage. To do so the caller must first copy the returned instance"
-" into a new instance, then modify the new instance. 3 The caller allocates a"
-" pointer to an array slice which has all the same dimensions of the original"
-" array except the first, and passes it by reference to the callee. The callee sets"
-" the pointer to point to a valid instance of the array. The caller is responsible for"
-" releasing the returned storage. Following completion of a request, the caller is not"
-" allowed to modify any values in the returned storage. To do so the caller must first"
-" copy the returned instance into a new instance, then modify the new instance."
-" Generated Files Two files will be generated for each scope. One set of files will be"
-" generated for each module and each interface scope. An extra set is generated for"
-" those definitions at top level scope. One of the files is a header file(.h), and the"
-" other file is a C source code file (.c). In addition to these files a number of C"
-" source files will be generated for type encodings, they are named according to the "
-"following template: oe_code_<type>.c.";
-static char this_node[NODENAMESZ + 1];
-static char *progname;
-
-/* Test function prototypes */
-
-static int void_test(IC_Env *env);
-static int long_test(IC_Env *env);
-static int long_long_test(IC_Env *env);
-static int unsigned_short_test(IC_Env *env);
-static int unsigned_long_test(IC_Env *env);
-static int unsigned_long_long_test(IC_Env *env);
-static int double_test(IC_Env *env);
-static int char_test(IC_Env *env);
-static int wchar_test(IC_Env *env);
-static int octet_test(IC_Env *env);
-static int bool_test(IC_Env *env);
-static int struct_test(IC_Env *env);
-static int struct2_test(IC_Env *env);
-static int seq1_test(IC_Env *env);
-static int seq2_test(IC_Env *env);
-static int seq3_test(IC_Env *env);
-static int seq4_test(IC_Env *env);
-static int seq5_test(IC_Env *env);
-static int array1_test(IC_Env *env);
-static int array2_test(IC_Env *env);
-static int enum_test(IC_Env *env);
-static int string1_test(IC_Env *env);
-static int string2_test(IC_Env *env);
-static int string3_test(IC_Env *env);
-static int string4_test(IC_Env *env);
-static int pid_test(IC_Env *env);
-static int port_test(IC_Env *env);
-static int ref_test(IC_Env *env);
-static int term_test(IC_Env *env);
-static int typedef_test(IC_Env *env);
-static int inline_sequence_test(IC_Env *env);
-static int term_sequence_test(IC_Env *env);
-static int term_struct_test(IC_Env *env);
-static int wstring1_test(IC_Env *env);
-
-static TestCase test_cases[] = {
- {"void_test", void_test},
- {"long_test", long_test},
- {"long_long_test", long_long_test},
- {"unsigned_short_test", unsigned_short_test},
- {"unsigned_long_test", unsigned_long_test},
- {"unsigned_long_long_test", unsigned_long_long_test},
- {"double_test", double_test},
- {"char_test", char_test},
- {"wchar_test", wchar_test},
- {"octet_test", octet_test},
- {"bool_test", bool_test},
- {"struct_test", struct_test},
- {"struct2_test", struct2_test},
- {"seq1_test", seq1_test},
- {"seq2_test", seq2_test},
- {"seq3_test", seq3_test},
- {"seq4_test", seq4_test},
- {"seq5_test", seq5_test},
- {"array1_test", array1_test},
- {"array2_test", array2_test},
- {"enum_test", enum_test},
- {"string1_test", string1_test},
- {"string2_test", string2_test},
- {"string3_test", string3_test},
- {"string4_test", string4_test},
- {"pid_test", pid_test},
- {"port_test", port_test},
- {"ref_test", ref_test},
- {"term_test", term_test},
- {"typedef_test", typedef_test},
- {"inline_sequence_test", inline_sequence_test},
- {"term_sequence_test", term_sequence_test},
- {"term_struct_test", term_struct_test},
- {"wstring1_test", wstring1_test},
- {"", NULL}
-};
-
-/* Other prototypes */
-static int cmp_aseq(m_aseq *a1, m_aseq *a2);
-static int cmp_a(m_a *a1, m_a *a2);
-static int cmp_bseq(m_bseq *b1, m_bseq *b2);
-static int cmp_b(m_b *b1, m_b *b2);
-static int cmp_lseq(m_lseq *b1, m_lseq *b2);
-static int cmp_etseq(m_etseq *b1, m_etseq *b2);
-static int cmp_et(m_et* b1, m_et *b2);
-static int cmp_es(m_es *b1, m_es *b2);
-static int cmp_arr1(m_arr1 b1, m_arr1 b2);
-static int cmp_dd(m_dd b1, m_dd b2);
-static int cmp_strRec(m_strRec *b1, m_strRec *b2);
-static int cmp_sseq(m_sseq *b1, m_sseq *b2);
-static int cmp_pid(erlang_pid *p1, erlang_pid *p2);
-static int cmp_port(erlang_port *p1, erlang_port *p2);
-static int cmp_ref(erlang_ref *p1, erlang_ref *p2);
-static int cmp_s(m_s *b1, m_s *b2);
-static int cmp_ssstr3(m_ssstr3 *b1, m_ssstr3 *b2);
-static int cmp_ssarr3(m_ssarr3 *b1, m_ssarr3 *b2);
-static int cmp_sarr3(m_sarr3 *b1, m_sarr3 *b2);
-static int cmp_arr3(m_arr3 b1, m_arr3 b2);
-
-static void print_aseq(m_aseq *a);
-static void print_a(m_a *a);
-static void print_bseq(m_bseq *b);
-static void print_lseq(m_lseq *b);
-static void print_b(m_b *b);
-static void print_etseq(m_etseq *b);
-static void print_et(m_et* b);
-static void print_es(m_es *b);
-static void print_arr1(long a[500]);
-static void print_dd(long a[2][3]);
-static void print_strRec(m_strRec* sr);
-static void print_sseq(m_sseq *b);
-static void print_pid(erlang_pid *p);
-static void print_port(erlang_port *p);
-static void print_ref(erlang_ref *p);
-static void print_term(ETERM *t);
-static void print_s(m_s *p);
-static void print_ssstr3(m_ssstr3 *b1);
-static void print_ssarr3(m_ssarr3 *b1);
-static void print_sarr3(m_sarr3 *b1);
-static void print_arr3(m_arr3 b1);
-static void print_wstr(CORBA_wchar *ws);
-
-static void free_etseq_buf(m_etseq *b);
-static void free_et(m_et* b);
-
-#ifdef __WIN32__
-typedef struct {
- long tv_sec;
- long tv_usec;
-} MyTimeval;
-#else
-typedef struct timeval MyTimeval;
-#endif
-static void my_gettimeofday(MyTimeval *tv);
-static void showtime(MyTimeval *start, MyTimeval *stop);
-static void usage(void);
-static void done(int r);
-
-
-
-/* main */
-
-#ifdef VXWORKS
-int client(int argc, char **argv)
-#else
-int main(int argc, char **argv)
-#endif
-{
- struct hostent *hp;
- erlang_pid pid;
- MyTimeval start, stop;
- int i, fd, ires, tres;
- IC_Env *env;
- int tries = 0;
- char *this_node_name = NULL;
- char *peer_node = NULL;
- char *peer_process_name = NULL;
- char *cookie = NULL;
- char host[HOSTNAMESZ + 1];
- TestFunc test_func = NULL;
- TestCase *test_case;
- char *test_case_name = NULL;
-
-#ifdef __WIN32__
- WORD wVersionRequested;
- WSADATA wsaData;
-
- wVersionRequested = MAKEWORD(2, 0);
-
- if (WSAStartup(wVersionRequested, &wsaData) != 0) {
- fprintf(stderr, "Could not load winsock2 v2.0 compatible DLL");
- exit(1);
- }
-#endif
-
- progname = argv[0];
- host[HOSTNAMESZ] = '\0';
- if (gethostname(host, HOSTNAMESZ + 1) < 0) {
- fprintf(stderr, "Can't find own hostname\n");
- done(1);
- }
- if ((hp = gethostbyname(host)) == 0) {
- fprintf(stderr, "Can't get ip address for host %s\n", host);
- done(1);
- }
- for (i = 1; i < argc; i++) {
- if (cmp_str(argv[i], "-help")) {
- usage();
- done(0);
- } else if (cmp_str(argv[i], "-this-node-name")) {
- i++;
- this_node_name = argv[i];
- } else if (cmp_str(argv[i], "-peer-node")) {
- i++;
- peer_node = argv[i];
- } else if (cmp_str(argv[i], "-peer-process-name")) {
- i++;
- peer_process_name = argv[i];
- } else if (cmp_str(argv[i], "-cookie")) {
- i++;
- cookie = argv[i];
- } else if (cmp_str(argv[i], "-test-case")) {
- i++;
- test_case_name = argv[i];
- } else {
- fprintf(stderr, "Error : invalid argument \"%s\"\n", argv[i]);
- usage();
- done(1);
- }
- }
-
- if (this_node_name == NULL || peer_node == NULL || test_case_name == NULL
- || peer_process_name == NULL || cookie == NULL) {
- fprintf(stderr, "Error: missing option\n");
- usage();
- done(1);
- }
-
- test_case = test_cases;
- while (test_case->func) {
- if (cmp_str(test_case->name, test_case_name)) {
- test_func = test_case->func;
- break;
- }
- test_case++;
- }
- if (test_func == NULL) {
- fprintf(stderr, "Error: illegal test case: \"%s\"\n", test_case_name);
- done(1);
- }
-
- /* Behead hostname at first dot */
- for (i=0; host[i] != '\0'; i++) {
- if (host[i] == '.') { host[i] = '\0'; break; }
- }
- sprintf(this_node, "%s@%s", this_node_name, host);
- fprintf(stderr, "c_client: this node: \"%s\"\n", this_node);
- fprintf(stderr, "c_client: peer node: \"%s\"\n", peer_node);
- fprintf(stderr, "c_client: test case: \"%s\"\n", test_case_name);
-
- fprintf(stderr, "c_client: starting\n");
-
- /* initialize erl_interface */
- erl_init(NULL, 0);
-
- for (tries = 0; tries < MAXTRIES; tries++) {
-
- /* connect to erlang node */
-
- ires = erl_connect_xinit(host, this_node_name, this_node,
- (struct in_addr *)*hp->h_addr_list,
- cookie, 0);
-
- fprintf(stderr, "c_client: erl_connect_xinit(): %d\n", ires);
-
- fd = erl_connect(peer_node);
- fprintf(stderr, "c_client: erl_connect(): %d\n", fd);
-
- if (fd >= 0)
- break;
- fprintf(stderr, "c_client: cannot connect, retrying\n");
- }
- if (fd < 0) {
- fprintf(stderr, "c_client: cannot connect, exiting\n");
- done(1);
- }
- env = CORBA_Environment_alloc(INBUFSZ, OUTBUFSZ);
- env->_fd = fd;
- strcpy(env->_regname, peer_process_name);
- env->_to_pid = NULL;
- env->_from_pid = &pid;
-
- strcpy(pid.node, this_node);
- pid.num = fd;
- pid.serial = 0;
- pid.creation = 0;
-
- my_gettimeofday(&start);
- tres = test_func(env); /* Call test case */
- my_gettimeofday(&stop);
- showtime(&start, &stop);
- erl_close_connection(fd);
-
- printf("c_client: env->_inbuf before : %d\n", INBUFSZ);
- printf("c_client: env->_outbuf before : %d\n", OUTBUFSZ);
- printf("c_client: env->_inbuf after : %d\n", env->_inbufsz);
- printf("c_client: env->_outbuf after : %d\n", env->_outbufsz);
-
- CORBA_free(env->_inbuf);
- CORBA_free(env->_outbuf);
- CORBA_free(env);
- done(tres);
-}
-
-static void usage()
-{
- fprintf(stderr, "Usage: %s [-help] -this-node-name <name> "
- "-peer-node <nodename> -peer-process-name <name> "
- "-cookie <cookie> -test-case <test case name>\n", progname);
- fprintf(stderr, "Example:\n %s -this-node-name kalle "
- "-peer-node olle@home -peer-process-name idltest "
- "-cookie oa678er -test-case octet_test\n", progname);
-}
-
-static void done(int r)
-{
-#ifdef __WIN32__
- WSACleanup();
-#endif
- exit(r);
-}
-
-
-/* TESTS */
-
-static int void_test(IC_Env *env)
-{
- fprintf(stdout, "\n======== m_i_void test ======\n\n");
- m_i_void_test(NULL,env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(1);
-}
-
-static int long_test(IC_Env *env)
-{
- long l = 4711, lo, lr;
-
- fprintf(stdout, "\n======== m_i_long test ======\n\n");
- lr = m_i_long_test(NULL, l, &lo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(l == lo && l == lr);
- if (l != lo)
- fprintf(stdout, " out parameter error, sent: %ld, got: %ld\n", l, lo);
- if (l != lr)
- fprintf(stdout, " result error, sent: %ld, got: %ld\n", l, lr);
- return -1;
-}
-
-static int long_long_test(IC_Env *env)
-{
- CORBA_long_long ll = 4711, llo, llr;
-
- fprintf(stdout, "\n======== m_i_longlong test ======\n\n");
- llr = m_i_longlong_test(NULL, ll, &llo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(ll == llo && ll == llr);
- if (ll != llo)
- fprintf(stdout, " out parameter error, sent: %ld, got: %ld\n",
- ll, llo);
- if (ll != llr)
- fprintf(stdout, " result error, sent: %ld, got: %ld\n", ll, llr);
- return -1;
-}
-
-static int unsigned_short_test(IC_Env *env)
-{
- unsigned short x, y = 2, z;
-
- fprintf(stdout, "\n======== m_i_ushort test ======\n\n");
- x = m_i_ushort_test(NULL, y, &z, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(y == z && y == x);
- if (y != z)
- fprintf(stdout, " out parameter error, sent: %d, got: %d\n", y, z);
- if (y != x)
- fprintf(stdout, " result error, sent: %d, got: %d\n", y, x);
- return -1;
-}
-
-
-static int unsigned_long_test(IC_Env *env)
-{
- unsigned long ul = 5050, ulo, ulr;
-
- fprintf(stdout, "\n======== m_i_ulong test ======\n\n");
- ulr = m_i_ulong_test(NULL, ul, &ulo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(ul == ulo && ul == ulr);
- if (ul != ulo)
- fprintf(stdout, " out parameter error, sent: %lu, got: %lu\n",
- ul, ulo);
- if (ul != ulr)
- fprintf(stdout, " result error, sent: %lu, got: %lu\n", ul, ulr);
- return -1;
-}
-
-/*
- * Note: CORBA_unsigned_long_long is in fact a plain long.
- */
-static int unsigned_long_long_test(IC_Env *env)
-{
- CORBA_unsigned_long_long ull = 5050, ullo, ullr;
-
- fprintf(stdout, "\n======== m_i_ulonglong test ======\n\n");
- ullr = m_i_ulonglong_test(NULL, ull, &ullo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(ull == ullo && ull == ullr);
- if (ull != ullo)
- fprintf(stdout, " out parameter error, sent: %lu, got: %lu\n",
- ull, ullo);
- if (ull != ullr)
- fprintf(stdout, " result error, sent: %lu, got: %lu\n",
- ull, ullr);
- return -1;
-}
-
-static int double_test(IC_Env *env)
-{
- double d = 12.1212, db, dr;
-
- fprintf(stdout, "\n======== m_i_double test ======\n\n");
- dr = m_i_double_test(NULL, d, &db, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(d == db && d == dr);
- if (d != db)
- fprintf(stdout, " out parameter error, sent: %f, got: %f\n", d, db);
- if (d != dr)
- fprintf(stdout, " result error, sent: %f, got: %f\n", d, dr);
- return -1;
-}
-
-static int char_test(IC_Env *env)
-{
- char c = 'g', co, cr;
-
- /* char test */
- fprintf(stdout, "\n======== m_i_char test ======\n\n");
- cr = m_i_char_test(NULL, c, &co, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(c == co && c == cr);
- if (c !=co)
- fprintf(stdout, " out parameter error, sent: %c, got: %c\n", c, co);
- if (c != cr)
- fprintf(stdout, " result error, sent: %c, got: %c\n", c, cr);
- return -1;
-}
-
-static int wchar_test(IC_Env *env)
-{
- CORBA_wchar wc = 103, wco, wcr;
-
- fprintf(stdout, "\n======== m_i_wchar test ======\n\n");
- wcr = m_i_wchar_test(NULL, wc, &wco, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(wc == wco && wc == wcr);
- if (wc != wco)
- fprintf(stdout, " out parameter error, sent: %lu, got: %lu\n",
- wc, wco);
- if (wc != wcr)
- fprintf(stdout, " result error, sent: %lu, got: %lu\n",
- wc, wcr);
- return -1;
-}
-
-static int octet_test(IC_Env *env)
-{
- char o ='r', oo, or;
-
- fprintf(stdout, "\n======== m_i_octet test ======\n\n");
- or = m_i_octet_test(NULL, o, &oo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(o == oo && o == or);
- if (o != oo)
- fprintf(stdout, " out parameter error, sent: %c, got: %c\n", o, oo);
- if (o != or)
- fprintf(stdout, " result error, sent: %c, got: %c\n", o, or);
- return -1;
-}
-
-static int bool_test(IC_Env *env)
-{
- unsigned char i = 0, io, ir;
-
- fprintf(stdout, "\n======== m_i_bool test ======\n\n");
- ir = m_i_bool_test(NULL, i, &io, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(i == io && i == ir);
- if (i != io)
- fprintf(stdout, " out parameter error, sent: %d, got: %d\n", i, io);
- if (i != ir)
- fprintf(stdout, " result error, sent: %d, got: %d\n", i, ir);
- return -1;
-}
-
-static int struct_test(IC_Env *env)
-{
- m_b b = {4711, 'a'}, bo, br;
-
- fprintf(stdout, "\n======== m_i_struct test ======\n\n");
- br = m_i_struct_test(NULL, &b, &bo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_b(&b, &bo) && cmp_b(&b, &br));
- if (!cmp_b(&b, &bo)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_b(&b);
- fprintf(stdout, " got:\n");
- print_b(&bo);
- fprintf(stdout, "\n");
- }
- if (!cmp_b(&b, &br)) {
- fprintf(stdout, " result error, sent:\n");
- print_b(&b);
- fprintf(stdout, " got:\n");
- print_b(&br);
- fprintf(stdout, "\n");
- }
- return -1;
-}
-
-static int struct2_test(IC_Env *env)
-{
- m_es esi = {m_peach, 5050}, eso, esr;
-
- fprintf(stdout, "\n======== m_i_struct2 test ======\n\n");
- esr = m_i_struct2_test(NULL, &esi, &eso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_es(&esi, &eso) && cmp_es(&esi, &esr));
- if (!cmp_es(&esi, &eso)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_es(&esi);
- fprintf(stdout, " got:\n");
- print_es(&eso);
- fprintf(stdout, "\n");
- }
- if (!cmp_es(&esi, &esr)) {
- fprintf(stdout, " result error, sent:\n");
- print_es(&esi);
- fprintf(stdout, " got:\n");
- print_es(&esr);
- fprintf(stdout, "\n");
- }
- return -1;
-}
-
-
-static int seq1_test(IC_Env *env)
-{
- m_bseq bs, *bso, *bsr;
-
- m_b ba[3] = {{4711, 'a'}, {4712, 'b'}, {4713, 'c'}};
- bs._length = 3;
- bs._buffer = ba;
-
- fprintf(stdout, "\n======== m_i_seq1 test ======\n\n");
- bsr = m_i_seq1_test(NULL, &bs, &bso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_bseq(&bs, bso) && cmp_bseq(&bs, bsr));
- if (!cmp_bseq(&bs, bso)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_bseq(&bs);
- fprintf(stdout, " got:\n");
- print_bseq(bso);
- fprintf(stdout, "\n");
- }
- if (!cmp_bseq(&bs, bsr)) {
- fprintf(stdout, " result error, sent:\n");
- print_bseq(&bs);
- fprintf(stdout, " got:\n");
- print_bseq(bsr);
- fprintf(stdout, "\n");
- }
- CORBA_free(bso);
- CORBA_free(bsr);
- return -1;
-}
-
-static int seq2_test(IC_Env *env)
-{
- m_b ba[3] = {{4711, 'a'}, {4712, 'b'}, {4713, 'c'}};
- m_a a;
- m_a aa[2];
- m_aseq as, *aso, *asr;
-
- a.l = 9999;
- a.y._length = 3;
- a.y._buffer = ba;
- a.d = 66.89898989;
-
- aa[0] = a;
- aa[1] = a;
- as._length = 2;
- as._buffer = aa;
-
- fprintf(stdout, "\n======== m_i_seq2 test ======\n\n");
- asr = m_i_seq2_test(NULL, &as, &aso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_aseq(&as, aso) && cmp_aseq(&as, asr));
- if (!cmp_aseq(&as, aso)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_aseq(&as);
- fprintf(stdout, " got:\n");
- print_aseq(aso);
- fprintf(stdout, "\n");
- }
- if (!cmp_aseq(&as, asr)) {
- fprintf(stdout, " result error, sent:\n");
- print_aseq(&as);
- fprintf(stdout, " got:\n");
- print_aseq(asr);
- fprintf(stdout, "\n");
- }
- CORBA_free(aso);
- CORBA_free(asr);
- return -1;
-}
-
-static int seq3_test(IC_Env *env)
-{
- m_lseq lsi, *lso, *lsr;
- long al[500];
- int i=0;
-
- for (i = 0; i < 500; i++)
- al[i]=i;
- lsi._length = 500;
- lsi._buffer = al;
-
- fprintf(stdout, "\n======== m_i_seq3 test ======\n\n");
- lsr = m_i_seq3_test(NULL, &lsi, &lso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_lseq(&lsi, lso) && cmp_lseq(&lsi, lsr));
- if (!cmp_lseq(&lsi, lso)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_lseq(&lsi);
- fprintf(stdout, " got:\n");
- print_lseq(lso);
- fprintf(stdout, "\n");
- }
- if (!cmp_lseq(&lsi, lsr)) {
- fprintf(stdout, " result error, sent:\n");
- print_lseq(&lsi);
- fprintf(stdout, " got:\n");
- print_lseq(lsr);
- fprintf(stdout, "\n");
- }
- CORBA_free(lso);
- CORBA_free(lsr);
- return -1;
-}
-
-static int seq4_test(IC_Env *env)
-{
- char *stra0[3] = {"a", "long", "time"};
- char *stra1[3] = {"ago", "there", "was"};
- char *stra2[3] = {"a", "buggy", "compiler"};
- m_sstr3 str3s[3] = {{3, 3, stra0}, {3, 3, stra1}, {3, 3, stra2}};
- m_ssstr3 str3ssi = {3, 3, str3s};
- m_ssstr3 *str3sso, *str3ssr;
-
- fprintf(stdout, "\n======== m_i_seq4 test ======\n\n");
- str3ssr = m_i_seq4_test(NULL, &str3ssi, &str3sso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_ssstr3(&str3ssi, str3sso) &&
- cmp_ssstr3(&str3ssi, str3ssr));
- if (!cmp_ssstr3(&str3ssi, str3sso)){
- fprintf(stdout, " out parameter error, sent:\n");
- print_ssstr3(&str3ssi);
- fprintf(stdout, " got:\n");
- print_ssstr3(str3sso);
- fprintf(stdout, "\n");
- }
- if (!cmp_ssstr3(&str3ssi, str3ssr)) {
- fprintf(stdout, " result error, sent:\n");
- print_ssstr3(&str3ssi);
- fprintf(stdout, " got:\n");
- print_ssstr3(str3ssr);
- fprintf(stdout, "\n");
- }
- CORBA_free(str3sso);
- CORBA_free(str3ssr);
- return -1;
-}
-
-static int seq5_test(IC_Env *env)
-{
- m_arr3 arr3a[3] = {
- {4711, 18931947, 3},
- {4711, 18931947, 3},
- {4711, 18931947, 3}};
- m_sarr3 arr3sa[3] = {{3, 3, arr3a}, {3, 3, arr3a}, {3, 3, arr3a}};
- m_ssarr3 arr3ssi = {3, 3, arr3sa};
- m_ssarr3 *arr3sso;
- m_ssarr3 *arr3ssr;
-
- fprintf(stdout, "\n======== m_i_seq5 test ======\n\n");
- arr3ssr = m_i_seq5_test(NULL, &arr3ssi, &arr3sso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_ssarr3(&arr3ssi, arr3sso) &&
- cmp_ssarr3(&arr3ssi, arr3ssr));
- if (!cmp_ssarr3(&arr3ssi, arr3sso)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_ssarr3(&arr3ssi);
- fprintf(stdout, " got:\n");
- print_ssarr3(arr3sso);
- fprintf(stdout, "\n");
- }
- if (!cmp_ssarr3(&arr3ssi, arr3ssr)) {
- fprintf(stdout, " result error, sent:\n");
- print_ssarr3(&arr3ssi);
- fprintf(stdout, " got:\n");
- print_ssarr3(arr3ssr);
- fprintf(stdout, "\n");
- }
- CORBA_free(arr3sso);
- CORBA_free(arr3ssr);
- return -1;
-}
-
-static int array1_test(IC_Env *env)
-{
- int i;
- long al[500];
- m_arr1 alo;
- m_arr1_slice* alr;
-
- for (i = 0; i < 500; i++)
- al[i]=i;
-
- fprintf(stdout, "\n======== m_i_array1 test ======\n\n");
- alr = m_i_array1_test(NULL, al, alo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_arr1(al, alo) && cmp_arr1(al, alr));
- if (!cmp_arr1(al, alo)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_arr1(al);
- fprintf(stdout, " got:\n");
- print_arr1(alo);
- fprintf(stdout, "\n");
- }
- if (!cmp_arr1(al,alr)) {
- fprintf(stdout, " result error, sent:\n");
- print_arr1(al);
- fprintf(stdout, " got:\n");
- print_arr1(alr);
- fprintf(stdout, "\n");
- }
- free(alo);
- free(alr);
- return -1;
-}
-
-static int array2_test(IC_Env *env)
-{
- long dl[2][3] = {{11, 2, 7}, {22, 8 ,13}};
- m_dd dlo;
- m_dd_slice* dlr;
-
- fprintf(stdout, "\n======== m_i_array2 test ======\n\n");
- dlr = m_i_array2_test(NULL, dl, dlo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_dd(dl,dlo) && cmp_dd(dl,dlr));
- if (!cmp_dd(dl,dlo)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_dd(dl);
- fprintf(stdout, " got:\n");
- print_dd(dlo);
- fprintf(stdout, "\n");
- }
- if (!cmp_dd(dl,dlr)) {
- fprintf(stdout, " result error, sent:\n");
- print_dd(dl);
- fprintf(stdout, " got:\n");
- print_dd(dlr);
- fprintf(stdout, "\n");
- }
- free(*dlr);
- return -1;
-}
-
-static int enum_test(IC_Env *env)
-{
- m_fruit ei = m_banana, eo, er;
-
- fprintf(stdout, "\n======== m_i_enum test ======\n\n");
- er = m_i_enum_test(NULL, ei, &eo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(ei == eo && ei == er);
- if (ei != eo)
- fprintf(stdout, " out parameter error, sent: %d, got: %d\n", ei, eo);
- if (ei != er)
- fprintf(stdout, " result error, sent: %d, got: %d\n", ei, er);
- return -1;
-}
-
-static int string1_test(IC_Env *env)
-{
- char* si = longtext;
- char* so;
- char* sr;
-
- fprintf(stdout, "\n======== m_i_string1 test ======\n\n");
- sr = m_i_string1_test(NULL, si, &so, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_str(si, so) && cmp_str(si, sr));
- if (!cmp_str(si, so))
- fprintf(stdout, " out parameter error, sent: %s, got: %s\n", si, so);
- if (!cmp_str(si, sr))
- fprintf(stdout, " result error, sent: %s, got: %s\n", si, sr);
- CORBA_free(so);
- CORBA_free(sr);
- return -1;
-}
-
-static int string2_test(IC_Env *env)
-{
- char* sa[3] = {"hello", "foo", "bar"};
- m_sseq ssi = {3, 3, sa};
- m_sseq *sso, *ssr;
-
- fprintf(stdout, "\n======== m_i_string2 test ======\n\n");
- ssr = m_i_string2_test(NULL, &ssi, &sso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_sseq(&ssi, sso) && cmp_sseq(&ssi, sso));
- if (!cmp_sseq(&ssi, sso)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_sseq(&ssi);
- fprintf(stdout, "got:\n");
- print_sseq(sso);
- }
- if (!cmp_sseq(&ssi, ssr)) {
- fprintf(stdout, " result error, sent:\n");
- print_sseq(&ssi);
- fprintf(stdout, "got:\n");
- print_sseq(ssr);
- }
- CORBA_free(sso);
- CORBA_free(ssr);
- return -1;
-}
-
-static int string3_test(IC_Env *env)
-{
- char* si = longtext;
- char* so;
- char* sr;
-
- fprintf(stdout, "\n======== m_i_string3 test ======\n\n");
- sr = m_i_string3_test(NULL, si, &so, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_str(si, so) && cmp_str(si, so));
- if (!cmp_str(si, so))
- fprintf(stdout, " out parameter error, sent: %s, got: %s\n", si, so);
- if (!cmp_str(si, sr))
- fprintf(stdout, " result error, sent: %s, got: %s\n", si, sr);
- CORBA_free(so);
- CORBA_free(sr);
- return -1;
-}
-
-static int string4_test(IC_Env *env)
-{
- char as1[100] = "a string", as2[200] = "help", as3[200] = "hello there";
- m_strRec stri = { 1, /* dd */
- as1, /* str4 */
- {{'a', 'k'}, {'z', 'g'}, {'n', 'q'}}, /* str7 */
- {3, 3, "buf"}, /* str5 */
- as2, /* str6 */
- {'m', 'f', 'o'}, /* str8 */
- as3, /* str9 */
- {3, 3, "stu"} /* str10 */
- };
- m_strRec *stro, *strr;
-
- fprintf(stdout, "\n======== m_i_string4 test ======\n\n");
- strr = m_i_string4_test(NULL, &stri, &stro, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_strRec(&stri,stro) && cmp_strRec(&stri,strr));
- if (!cmp_strRec(&stri,stro)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_strRec(&stri);
- fprintf(stdout, " got:\n");
- print_strRec(stro);
- fprintf(stdout, "\n");
- }
- if (!cmp_strRec(&stri,strr)) {
- fprintf(stdout, " result error, sent:\n");
- print_strRec(&stri);
- fprintf(stdout, " got:\n");
- print_strRec(strr);
- fprintf(stdout, "\n");
- }
- CORBA_free(stro);
- CORBA_free(strr);
- return -1;
-}
-
-
-static int pid_test(IC_Env *env)
-{
- erlang_pid pid = {"", 7, 0, 0}, pido, pidr;
-
- strcpy(pid.node, this_node), /* this currently running node */
- fprintf(stdout, "\n======== m_i_pid test ======\n\n");
- pidr = m_i_pid_test(NULL, &pid, &pido, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_pid(&pid, &pido) && cmp_pid(&pid, &pidr));
- if (!cmp_pid(&pid, &pido)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_pid(&pid);
- fprintf(stdout, "got:\n");
- print_pid(&pido);
- }
- if (!cmp_pid(&pid, &pidr)) {
- fprintf(stdout, " result error, sent:\n");
- print_pid(&pid);
- fprintf(stdout, "got:\n");
- print_pid(&pidr);
- }
- return -1;
-}
-
-static int port_test(IC_Env *env)
-{
- erlang_port porti = {"node", 5, 1}, porto, portr;
-
- fprintf(stdout, "\n======== m_i_port test ======\n\n");
- portr = m_i_port_test(NULL, &porti, &porto, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_port(&porti, &porto) && cmp_port(&porti, &portr));
- if (!cmp_port(&porti, &porto)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_port(&porti);
- fprintf(stdout, "got:\n");
- print_port(&porto);
- }
- if (!cmp_port(&porti, &portr)) {
- fprintf(stdout, " result error, sent:\n");
- print_port(&porti);
- fprintf(stdout, "got:\n");
- print_port(&portr);
- }
- return -1;
-}
-
-static int ref_test(IC_Env *env)
-{
- erlang_ref refi = { "node1", 3, {1, 2, 3}, 1},
- refo, refr;
-
- fprintf(stdout, "\n======== m_i_ref test ======\n\n");
- refr = m_i_ref_test(NULL, &refi, &refo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_ref(&refi, &refo) && cmp_ref(&refi, &refr));
- if (!cmp_ref(&refi, &refo)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_ref(&refi);
- fprintf(stdout, "got:\n");
- print_ref(&refo);
- }
- if (!cmp_ref(&refi, &refr)) {
- fprintf(stdout, " result error, sent:\n");
- print_ref(&refi);
- fprintf(stdout, "got:\n");
- print_ref(&refr);
- }
- return -1;
-}
-
-static int term_test(IC_Env *env)
-{
- ETERM *ti, *to, *tr;
-
- ti = erl_format("[{hej, 1, 23}, \"string\", {1.23, 45}]");
-
- fprintf(stdout, "\n======== m_i_term test ======\n\n");
- tr = m_i_term_test(NULL, ti, &to, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(erl_match(ti, to) && erl_match(ti, tr));
- if (!erl_match(ti, to)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_term(ti);
- fprintf(stdout, "got:\n");
- print_term(to);
- }
- if (!erl_match(ti, tr)) {
- fprintf(stdout, " result error, sent:\n");
- print_term(ti);
- fprintf(stdout, "got:\n");
- print_term(tr);
- }
- erl_free_term(ti);
- erl_free_term(to);
- erl_free_term(tr);
- return -1;
-}
-
-static int typedef_test(IC_Env *env)
-{
- m_banan mbi, mbo; /* erlang_port */
- m_apa mai; /* ETERM* */
- m_apa mao = NULL;
- long tl;
-
- strcpy(mbi.node,"node");
- mbi.id = 15;
- mbi.creation = 1;
-
- fprintf(stdout, "\n======== m_i_typedef test ======\n\n");
- mai = erl_format("[{hej, 1, 23}, \"string\", {1.23, 45}]");
- tl = m_i_typedef_test(NULL, mai, &mbi, &mao, &mbo, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(erl_match(mai, mao) && cmp_port(&mbi, &mbo) && tl == 4711);
- if (!erl_match(mai, mao)) {
- fprintf(stdout, " out parameter error (term), sent:\n");
- print_term(mai);
- fprintf(stdout, "got:\n");
- print_term(mao);
- }
- if (!cmp_port(&mbi, &mbo)) {
- fprintf(stdout, " out parameter error (port), sent:\n");
- print_port(&mbi);
- fprintf(stdout, "got:\n");
- print_port(&mbo);
- }
- if (tl != 4711) {
- fprintf(stdout, " result error, sent: 4711, got %ld\n", tl);
- }
- erl_free_term(mai);
- erl_free_term(mao);
- return -1;
-}
-
-static int inline_sequence_test(IC_Env *env)
-{
- int i;
- long al[500];
- m_s isi = {4711, {500, 10, al}},
- *iso, *isr;
-
- for (i = 0; i < 500; i++)
- al[i]=i;
- fprintf(stdout, "\n======== m_i_inline_sequence test ======\n\n");
- isr = m_i_inline_sequence_test(NULL, &isi, &iso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_s(&isi, iso) && cmp_s(&isi, isr));
- if (!cmp_s(&isi, iso)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_s(&isi);
- fprintf(stdout, "got:\n");
- print_s(iso);
- }
- if (!cmp_s(&isi, isr)) {
- fprintf(stdout, " result error, sent:\n");
- print_s(&isi);
- fprintf(stdout, "got:\n");
- print_s(isr);
- }
- CORBA_free(iso);
- CORBA_free(isr);
- return -1;
-}
-
-static int term_sequence_test(IC_Env *env)
-{
- ETERM* et_array[4] = {
- erl_format("[{apa, 1, 23}, \"string\", {1.23, 45}]"),
- erl_format("[{banan, 1, 23}, \"string\", {1.23, 45}]"),
- erl_format("[{apelsin, 1, 23}, \"string\", {1.23, 45}]"),
- erl_format("[{mango, 1, 23}, \"string\", {1.23, 45}]")};
- m_etseq etsi = {4, 4, et_array}, *etso, *etsr;
-
- fprintf(stdout, "\n======== m_i_term_sequence test ======\n\n");
- etsr = m_i_term_sequence_test(NULL, &etsi, &etso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_etseq(&etsi, etso) && cmp_etseq(&etsi, etsr));
- if (!cmp_etseq(&etsi, etso)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_etseq(&etsi);
- fprintf(stdout, "got:\n");
- print_etseq(etso);
- }
- if (!cmp_etseq(&etsi, etsr)) {
- fprintf(stdout, " result error, sent:\n");
- print_etseq(&etsi);
- fprintf(stdout, "got:\n");
- print_etseq(etsr);
- }
- free_etseq_buf(&etsi);
- free_etseq_buf(etso);
- free_etseq_buf(etsr);
- CORBA_free(etso);
- CORBA_free(etsr);
- return -1;
-}
-
-static int term_struct_test(IC_Env *env)
-{
- m_et eti = { erl_format("[{hej, 1, 23}, \"string\", {1.23, 45}]"),
- 121212 };
- m_et eto, etr;
-
- fprintf(stdout, "\n======== m_i_term_struct test ======\n\n");
- etr = m_i_term_struct_test(NULL, &eti, &eto, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_et(&eti, &eto) && cmp_et(&eti, &etr));
- if (!cmp_et(&eti, &eto)) {
- fprintf(stdout, " out parameter error, sent:\n");
- print_et(&eti);
- fprintf(stdout, "got:\n");
- print_et(&eto);
- }
- if (!cmp_et(&eti, &etr)) {
- fprintf(stdout, " result error, sent:\n");
- print_et(&eti);
- fprintf(stdout, "got:\n");
- print_et(&etr);
- }
- free_et(&eti);
- free_et(&eto);
- free_et(&etr);
- return -1;
-}
-
-static int wstring1_test(IC_Env *env)
-{
- CORBA_wchar wsi[] = {100, 101, 102, 103, 104, 0}, *wso, *wsr;
-
- fprintf(stdout, "\n======== m_i_wstring1 test ======\n\n");
- wsr = m_i_wstring1_test(NULL, wsi, &wso, env);
- CHECK_EXCEPTION(env);
- RETURN_IF_OK(cmp_wstr(wsi, wso) && cmp_wstr(wsi, wsr));
- if (!cmp_wstr(wsi, wso)) {
- fprintf(stdout, " out parameter error, sent: \n");
- print_wstr(wsi);
- fprintf(stdout, "got:\n");
- print_wstr(wso);
- }
- if (!cmp_wstr(wsi, wsr)) {
- fprintf(stdout, " result error, sent: \n");
- print_wstr(wsi);
- fprintf(stdout, "got:\n");
- print_wstr(wsr);
- }
- CORBA_free(wso);
- CORBA_free(wsr);
- return -1;
-}
-
-/* Compare functions */
-static int cmp_aseq(m_aseq *a1, m_aseq *a2)
-{
- int i;
-
- if (a1->_length != a2->_length)
- return 0;
- for (i = 0; i < a1->_length; i++)
- if (cmp_a(&(a1->_buffer[i]), &(a2->_buffer[i])) == 0)
- return 0;
- return 1;
-}
-
-static int cmp_a(m_a *a1, m_a *a2)
-{
- return a1->l == a2->l &&
- a1->d == a2->d &&
- cmp_bseq(&a1->y, &a2->y);
-}
-
-static int cmp_bseq(m_bseq *b1, m_bseq *b2)
-{
- int i;
-
- if (b1->_length != b2->_length)
- return 0;
- for (i = 0; i < b1->_length; i++)
- if (cmp_b(&(b1->_buffer[i]), &(b2->_buffer[i])) == 0)
- return 0;
- return 1;
-}
-
-static int cmp_b(m_b *b1, m_b *b2)
-{
- return b1->l == b2->l && b1->c == b2->c;
-}
-
-static int cmp_lseq(m_lseq *b1, m_lseq *b2)
-{
- int i;
-
- if (b1->_length != b2->_length)
- return 0;
- for (i = 0; i < b1->_length; i++)
- if (b1->_buffer[i] != b2->_buffer[i])
- return 0;
- return 1;
-}
-
-static int cmp_etseq(m_etseq *b1, m_etseq *b2)
-{
- int i;
-
- if (b1->_length != b2->_length)
- return 0;
- for (i = 0; i < b1->_length; i++)
- if (!erl_match(b1->_buffer[i], b2->_buffer[i]))
- return 0;
- return 1;
-}
-
-static int cmp_et(m_et* b1, m_et *b2)
-{
- return erl_match(b1->e, b2->e) && b1->l == b2->l;
-}
-
-static int cmp_es(m_es *b1, m_es *b2)
-{
- return b1->f == b2->f && b1->l == b2->l;
-}
-
-static int cmp_arr1(m_arr1 b1, m_arr1 b2)
-{
- int i;
-
- for (i = 0; i < 500; i++)
- if (b1[i] != b2[i])
- return 0;
- return 1;
-}
-
-static int cmp_dd(m_dd b1, m_dd b2)
-{
-
- int i, j;
-
- for (i = 0; i < 2; i++)
- for (j = 0; j < 3; j++)
- if (b1[i][j] != b2[i][j])
- return 0;
- return 1;
-}
-
-
-
-static int cmp_strRec(m_strRec *b1, m_strRec *b2)
-{
- int i, j;
-
- if (b1->bb != b2->bb)
- return 0;
- if (!cmp_str(b1->str4,b2->str4))
- return 0;
- if (b1->str5._length != b2->str5._length)
- return 0;
- for (j = 0; j < b1->str5._length; j++)
- if (b1->str5._buffer[j] != b2->str5._buffer[j])
- return 0;
- if (!cmp_str(b1->str6,b2->str6))
- return 0;
- for (i = 0; i < 3; i++)
- for (j = 0; j < 2; j++)
- if (b1->str7[i][j] != b2->str7[i][j])
- return 0;
- for (j = 0; j < 3; j++)
- if (b1->str8[j] != b2->str8[j])
- return 0;
- if (!cmp_str(b1->str9,b2->str9))
- return 0;
- if (b1->str10._length != b2->str10._length)
- return 0;
- for (j = 0; j < b1->str10._length; j++)
- if (b1->str10._buffer[j] != b2->str10._buffer[j])
- return 0;
- return 1;
-}
-
-
-static int cmp_sseq(m_sseq *b1, m_sseq *b2)
-{
- int i;
-
- if (b1->_length != b2->_length)
- return 0;
- for (i = 0; i < b1->_length; i++)
- if (!cmp_str(b1->_buffer[i], b2->_buffer[i]))
- return 0;
- return 1;
-}
-
-
-static int cmp_pid(erlang_pid *p1, erlang_pid *p2)
-{
- return cmp_str(p1->node,p2-> node) &&
- p1->num == p2->num &&
- p1->serial == p2->serial &&
- p1->creation == p2->creation;
-}
-
-static int cmp_port(erlang_port *p1, erlang_port *p2)
-{
- return cmp_str(p1->node,p2-> node) && p1->id == p2->id;
-}
-
-static int cmp_ref(erlang_ref *p1, erlang_ref *p2)
-{
- return cmp_str(p1->node, p2->node) &&
- p1->len == p2->len &&
- (p1->len < 1 || p1->n[0] == p2->n[0]) &&
- (p1->len < 2 || p1->n[1] == p2->n[1]) &&
- (p1->len < 3 || p1->n[2] == p2->n[2]);
-}
-
-static int cmp_s(m_s *b1, m_s *b2)
-{
- int i;
-
- if (b1->l != b2->l)
- return 0;
- if (b1->sl._length != b2->sl._length)
- return 0;
- for (i = 0; i < b1->sl._length; i++)
- if (b1->sl._buffer[i] != b2->sl._buffer[i])
- return 0;
- return 1;
-}
-
-
-static int cmp_ssstr3(m_ssstr3 *b1, m_ssstr3 *b2)
-{
- int i,j;
-
- if (b1->_length != b2->_length)
- return 0;
- for (i = 0; i < b1->_length; i++) {
- if (b1->_buffer[i]._length != b2->_buffer[i]._length)
- return 0;
- for (j = 0; j < b1->_buffer[i]._length; j++)
- if (!cmp_str(b1->_buffer[i]._buffer[j],
- b2->_buffer[i]._buffer[j]))
- return 0;
- }
- return 1;
-}
-
-
-
-static int cmp_ssarr3(m_ssarr3 *b1, m_ssarr3 *b2)
-{
- int i;
-
- if (b1->_length != b2->_length)
- return 0;
- for (i = 0; i < b1->_length; i++) {
- if (!cmp_sarr3(&b1->_buffer[i], &b2->_buffer[i]))
- return 0;
- }
- return 1;
-}
-
-static int cmp_sarr3(m_sarr3 *b1, m_sarr3 *b2)
-{
- int i;
-
- if (b1->_length != b2->_length)
- return 0;
- for (i = 0; i < b1->_length; i++) {
- if (!cmp_arr3(b1->_buffer[i], b2->_buffer[i]))
- return 0;
- }
- return 1;
-}
-
-static int cmp_arr3(m_arr3 b1, m_arr3 b2)
-{
- int i;
-
- for (i = 0; i < sizeof(m_arr3)/sizeof(CORBA_long); i++) {
- if (b1[i] != b2[i])
- return 0;
- }
- return 1;
-}
-
-/* Print functions */
-static void print_aseq(m_aseq *a)
-{
- int i;
- fprintf(stdout, "\nm_aseq size: %ld --------\n", a->_length);
- for (i = 0; i < a->_length; i++)
- print_a(&(a->_buffer[i]));
-}
-
-static void print_a(m_a *a)
-{
- fprintf(stdout, "\nm_a --------\n l: %ld\n d:%f\n", a->l, a->d);
- print_bseq(&a->y);
-}
-
-static void print_bseq(m_bseq *b)
-{
- int i;
-
- fprintf(stdout, "\nm_bseq size: %ld --------\n",b->_length);
- for (i = 0; i < b->_length; i++)
- print_b(&(b->_buffer[i]));
-}
-
-static void print_lseq(m_lseq *b)
-{
- int i;
-
- fprintf(stdout, "\nm_lseq size: %ld --------\n",b->_length);
- for (i = 0; i < b->_length; i++)
- fprintf(stdout, "[%d]: %ld\n", i, b->_buffer[i]);
-}
-
-static void print_b(m_b *b)
-{
- fprintf(stdout, "\nm_b --------\n l: %ld\n c: %c\n", b->l, b->c);
-}
-
-
-static void print_etseq(m_etseq *b)
-{
- int i;
-
- for (i = 0; i < b->_length; i++) {
- fprintf(stdout, "[%d]:\n", i);
- erl_print_term(stdout, b->_buffer[i]);
- }
-}
-
-
-static void print_et(m_et* b)
-{
- fprintf(stdout, "\net struct --------\n");
- erl_print_term(stdout, b->e);
- fprintf(stdout, "long: %ld\n", b->l);
- fprintf(stdout, "\n--------\n");
-}
-
-static void print_es(m_es *b)
-{
- fprintf(stdout, "\nm_es --------\n f: %d\n l: %ld\n", b->f, b->l);
-}
-
-
-static void print_arr1(long a[10])
-{
- int i;
-
- for (i = 0; i < 10; i++)
- fprintf(stdout, "\n[%d]: %ld\n", i, a[i]);
-}
-
-static void print_dd(long a[2][3])
-{
- int i, j;
-
- fprintf(stdout, "\nlong dd[2][3] --------\n");
- for (i = 0; i < 2; i++)
- for (j = 0; j < 3; j++)
- fprintf(stdout, "\n[%d][%d]: %ld\n", i, j, a[i][j]);
-}
-
-
-static void print_strRec(m_strRec* sr)
-{
- int i, j;
-
- fprintf(stdout, "\nboolean bb : %d\n",sr->bb);
- fprintf(stdout, "string str4 : %s\n",sr->str4);
- fprintf(stdout, "str7[2][3] :\n");
- for (i = 0; i < 3; i++)
- for (j = 0; j < 2; j++)
- fprintf(stdout, "str7[%d][%d]: %ld\n", i, j, sr->str7[i][j]);
- fprintf(stdout, "str5._length : %ld\n",sr->str5._length);
- for (j = 0; j < sr->str5._length; j++)
- fprintf(stdout, "str5._buffer[%d]: %c\n", j, sr->str5._buffer[j]);
- fprintf(stdout, "string str6 : %s\n",sr->str6);
- fprintf(stdout, "str8 :\n");
- for (j = 0; j < 3; j++)
- fprintf(stdout, "str8[%d]: %c\n", j, sr->str8[j]);
- fprintf(stdout, "string str9 : %s\n",sr->str9);
- fprintf(stdout, "str10._length : %ld\n",sr->str10._length);
- for (j = 0; j < sr->str10._length; j++)
- fprintf(stdout, "str10._buffer[%d]: %c\n", j, sr->str10._buffer[j]);
-}
-
-static void print_sseq(m_sseq *b)
-{
- int i;
-
- fprintf(stdout, "\nm_sseq size: %ld --------\n",b->_length);
- for (i = 0; i < b->_length; i++)
- fprintf(stdout, "%s\n", b->_buffer[i]);
-
-}
-
-
-static void print_pid(erlang_pid *p)
-{
- fprintf(stdout, "\nerlang_pid --------\n node: %s\n num: %d\n "
- "serial: %d\n creation: %d\n",
- p->node, p->num, p->serial, p->creation);
-}
-
-static void print_port(erlang_port *p)
-{
- fprintf(stdout, "\nerlang_port --------\n node: %s\n id: %d\n "
- "creation: %d\n", p->node, p->id, p->creation);
-}
-
-static void print_ref(erlang_ref *p)
-{
- fprintf(stdout, "\nerlang_ref --------\n node: %s\n len: %d\n "
- "n[0]: %d\n n[1]: %d\n n[2]: %d\n creation: %d\n",
- p->node, p->len, p->n[0], p->n[1], p->n[2], p->creation);
-}
-
-static void print_term(ETERM *t)
-{
- fprintf(stdout, "\nETERM --------\n");
- erl_print_term(stdout, t);
- fprintf(stdout, "\n--------\n");
-}
-
-static void print_s(m_s *p)
-{
- int i;
-
- fprintf(stdout, "\n%ld\n", p->l);
- for (i = 0; i < p->sl._length; i++)
- fprintf(stdout, "\n[%d]: %ld\n", i, p->sl._buffer[i]);
-}
-
-
-static void print_ssstr3(m_ssstr3 *b1)
-{
- int i,j;
-
- fprintf(stdout, "\nSSSTR3 --------\n");
- fprintf(stdout,"b1->_length = %ld\n",b1->_length);
- for (i = 0; i < b1->_length; i++) {
- fprintf(stdout,"\nb1->_buffer[%d]._length %ld\n",
- i, b1->_buffer[i]._length);
- for (j = 0; j < b1->_buffer[i]._length; j++)
- fprintf(stdout,"b1->_buffer[%d]._buffer[%d] = %s\n",
- i, j, b1->_buffer[i]._buffer[j]);
- }
- fprintf(stdout, "\n--------\n");
-}
-
-static void print_wstr(CORBA_wchar *ws)
-{
- int i = 0;
-
- fprintf(stdout, "\nwstr --------\n");
- while (ws[i]) {
- fprintf(stdout, "[%d]: %ld\n", i, ws[i]);
- i++;
- }
- fprintf(stdout, "\n--------\n");
-}
-
-
-static void print_ssarr3(m_ssarr3 *b1)
-{
- int i;
-
- fprintf(stdout, "\nssarr3 --------\n");
- fprintf(stdout,"length: %ld\n",b1->_length);
- fprintf(stdout, "buffer:\n");
- for (i = 0; i < b1->_length; i++)
- print_sarr3(&b1->_buffer[i]);
- fprintf(stdout, "\n--------\n");
-}
-
-static void print_sarr3(m_sarr3 *b1)
-{
- int i;
-
- fprintf(stdout, "\nsarr3 --------\n");
- fprintf(stdout,"length: %ld\n",b1->_length);
- fprintf(stdout, "buffer:\n");
- for (i = 0; i < b1->_length; i++)
- print_arr3(b1->_buffer[i]);
- fprintf(stdout, "\n--------\n");
-}
-
-static void print_arr3(m_arr3 b1)
-{
- int i;
-
- fprintf(stdout, "\narr3 --------\n");
- for (i = 0; i < sizeof(m_arr3)/sizeof(CORBA_long); i++)
- fprintf(stdout, "%ld ", b1[i]);
- fprintf(stdout, "\n--------\n");
-}
-
-static void free_etseq_buf(m_etseq *b)
-{
- int i;
-
- for (i = 0; i < b->_length; i++)
- erl_free_term(b->_buffer[i]);
-}
-
-static void free_et(m_et* b)
-{
- erl_free_term(b->e);
-}
-
-static void showtime(MyTimeval *start, MyTimeval *stop)
-{
- MyTimeval elapsed;
-
- elapsed.tv_sec = stop->tv_sec - start->tv_sec;
- elapsed.tv_usec = stop->tv_usec - start->tv_usec;
- while (elapsed.tv_usec < 0) {
- elapsed.tv_sec -= 1;
- elapsed.tv_usec += 1000000;
- }
- fprintf(stderr,"%ld.%06ld seconds\n",elapsed.tv_sec, elapsed.tv_usec);
-}
-
-static void my_gettimeofday(MyTimeval *tv)
-#ifdef __WIN32__
-#define EPOCH_JULIAN_DIFF 11644473600i64
-{
- SYSTEMTIME t;
- FILETIME ft;
- LONGLONG lft;
-
- GetSystemTime(&t);
- SystemTimeToFileTime(&t, &ft);
- memcpy(&lft, &ft, sizeof(lft));
- tv->tv_usec = (long) ((lft / 10i64) % 1000000i64);
- tv->tv_sec = (long) ((lft / 10000000i64) - EPOCH_JULIAN_DIFF);
-}
-#elif defined VXWORKS
-{
- int rate = sysClkRateGet(); /* Ticks per second */
- unsigned long ctick = tickGet();
- tv->tv_sec = ctick / rate; /* secs since reboot */
- tv->tv_usec = ((ctick - (tv->tv_sec * rate))*1000000)/rate;
-}
-#else
-{
- gettimeofday(tv, NULL);
-}
-#endif
diff --git a/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/c_erl_test.idl b/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/c_erl_test.idl
deleted file mode 100644
index ec74d36cea..0000000000
--- a/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/c_erl_test.idl
+++ /dev/null
@@ -1,174 +0,0 @@
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 2004-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-#include "erlang.idl"
-
-
-const short TestConst = 1;
-
-module m {
-
- const short TestConst = 2;
-
- struct b {
- long l;
- char c;
- };
-
- struct simple {
- long l;
- b b_t;
- };
-
- enum fruit {orange, banana, apple, peach, pear};
-
- typedef sequence<long> lseq;
-
- typedef sequence<b> bseq;
-
- struct a {
- long l;
- bseq y;
- double d;
- };
-
- typedef sequence<a> aseq;
-
- typedef sequence<string> sseq;
- typedef string str;
- typedef long myLong;
-
- typedef long arr1[500], dd[2][3];
-
- typedef erlang::term apa;
- typedef erlang::port banan;
-
- typedef sequence<erlang::term> etseq;
-
- struct s {
- long l;
- sequence<long> sl;
- };
-
- struct es {
- fruit f;
- myLong l;
- };
-
- struct et {
- erlang::term e;
- long l;
- };
-
-
- typedef sequence<char> str1;
- typedef string<12> str2;
- typedef char str3[3];
-
- typedef sequence<string> sstr3; // sequence of string
- typedef sequence<sstr3> ssstr3; // sequence of sequences of strings
-
- typedef long arr3[3]; // array of long
- typedef sequence<arr3> sarr3; // sequence of array
- typedef sequence<sarr3> ssarr3; // sequence of sequnces of arrays of strings
-
- struct strRec{
- boolean bb;
- string str4;
- long str7[3][2];
- sequence<char> str5;
- string<12> str6;
- str3 str8;
- str2 str9;
- str1 str10;
- };
-
-
- struct dyn {
- long l;
- sequence<long> sl;
- };
- typedef dyn arr2[1][2];
-
-
- interface i {
-
- const short TestConst = 3;
-
- //arr2 suck(in arr2 x, out arr2 y );
-
- ///////////////////////////////// attribute long l;
-
- // simple types
- void void_test();
- long long_test(in long a, out long a1);
- long long longlong_test(in long long a, out long long a1);
- unsigned short ushort_test(in unsigned short a, out unsigned short a1);
- unsigned long ulong_test(in unsigned long a, out unsigned long a1);
- unsigned long long ulonglong_test(in unsigned long long a, out unsigned long long a1);
- double double_test(in double a, out double a1);
- char char_test(in char a, out char a1);
- wchar wchar_test(in wchar a, out wchar a1);
- octet octet_test(in octet a, out octet a1);
- boolean bool_test(in boolean a, out boolean a1);
-
- // Seq. and struct tests
- b struct_test(in b a, out b a1);
- es struct2_test(in es a, out es a1);
- //simple struct3_test(in simple x, out simple y);
- bseq seq1_test(in bseq a, out bseq a1);
- aseq seq2_test(in aseq a, out aseq a1);
- lseq seq3_test(in lseq a, out lseq a1);
- ssstr3 seq4_test(in ssstr3 a, out ssstr3 a1);
- ssarr3 seq5_test(in ssarr3 a, out ssarr3 a1);
-
- // Array tests
- arr1 array1_test(in arr1 a, out arr1 a1);
- dd array2_test(in dd a, out dd a1);
-
- // enum test
- fruit enum_test(in fruit a, out fruit a1);
-
- // string tests
- string string1_test(in string a, out string a1);
- wstring wstring1_test(in wstring a, out wstring a1);
- sseq string2_test(in sseq a, out sseq a1);
- str string3_test(in str a, out str a1);
- strRec string4_test(in strRec a, out strRec a1);
-
- // Special erlang types
- erlang::pid pid_test(in erlang::pid a, out erlang::pid a1);
- erlang::port port_test(in erlang::port a, out erlang::port a1);
- erlang::ref ref_test(in erlang::ref a, out erlang::ref a1);
- erlang::term term_test(in erlang::term a, out erlang::term a1);
-
- // typedef test
- long typedef_test(in apa a, in banan b, out apa a1, out banan b1);
-
- // inlined seq. test
- s inline_sequence_test(in s a, out s a1);
-
- // term seq. test
- etseq term_sequence_test(in etseq a, out etseq a1);
- // term struct test
- et term_struct_test(in et a, out et a1);
-
- };
-
-};
diff --git a/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/erl_server.erl b/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/erl_server.erl
deleted file mode 100644
index f2a6ed83fa..0000000000
--- a/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/erl_server.erl
+++ /dev/null
@@ -1,29 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(erl_server).
-
--export([run/0, stop/0]).
-
-run() ->
- m_i:oe_create().
-
-stop() ->
- gen_server:cast(cidl_test, stop).
diff --git a/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/m_i_impl.erl b/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/m_i_impl.erl
deleted file mode 100644
index ab62ee40c0..0000000000
--- a/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/m_i_impl.erl
+++ /dev/null
@@ -1,162 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(m_i_impl).
--include("m.hrl").
-
--export([init/1, terminate/2, void_test/1, long_test/2, ushort_test/2,
- longlong_test/2, ulong_test/2, ulonglong_test/2,
- double_test/2, char_test/2, wchar_test/2, octet_test/2,
- bool_test/2, struct_test/2, struct2_test/2, seq1_test/2,
- seq2_test/2, seq3_test/2, seq4_test/2, seq5_test/2,
- array1_test/2, array2_test/2, enum_test/2, string1_test/2,
- string2_test/2, string3_test/2, string4_test/2, pid_test/2,
- port_test/2, ref_test/2, term_test/2, typedef_test/3,
- inline_sequence_test/2, '_set_l'/2, '_get_l'/1,
- term_struct_test/2, term_sequence_test/2, wstring1_test/2]).
-
--define(PRINTDEBUG(Case),
- io:format("erl_server: case: ~p~n"
- "erl_server: location: ~p~n", [Case, [?FILE, ?LINE]])).
--define(PRINTDEBUG2(Case, Msg),
- io:format("erl_server: case: ~p~n"
- "erl_server: Msg: ~p~n"
- "erl_server: location: ~p~n", [Case, Msg, [?FILE, ?LINE]])).
-
-init(Env) ->
- {ok, []}.
-
-terminate(F, R) ->
- ok.
-
-'_get_l'(State) ->
- ?PRINTDEBUG("_get_l"),
- {reply, State, State}.
-void_test(State) ->
- ?PRINTDEBUG("void_test"),
- {reply, ok, State}.
-
-'_set_l'(State, V) ->
- ?PRINTDEBUG2("_set_l", V),
- {reply, ok, V}.
-ushort_test(State, V) ->
- ?PRINTDEBUG2("ushort_test", V),
- {reply, {V, V}, State}.
-long_test(State, V) ->
- ?PRINTDEBUG2("long_test", V),
- {reply, {V, V}, State}.
-longlong_test(State, V) ->
- ?PRINTDEBUG2("longlong_test", V),
- {reply, {V, V}, State}.
-ulong_test(State, V) ->
- ?PRINTDEBUG2("ulong_test", V),
- {reply, {V, V}, State}.
-ulonglong_test(State, V) ->
- ?PRINTDEBUG2("ulonglong_test", V),
- {reply, {V, V}, State}.
-double_test(State, V) ->
- ?PRINTDEBUG2("double_test", V),
- {reply, {V, V}, State}.
-char_test(State, V) ->
- ?PRINTDEBUG2("char_test", V),
- {reply, {V, V}, State}.
-wchar_test(State, V) ->
- ?PRINTDEBUG2("wchar_test", V),
- {reply, {V, V}, State}.
-octet_test(State, V) ->
- ?PRINTDEBUG2("octet_test", V),
- {reply, {V, V}, State}.
-bool_test(State, V) ->
- ?PRINTDEBUG2("bool_test", V),
- {reply, {V, V}, State}.
-
-struct_test(State, V) ->
- ?PRINTDEBUG2("struct_test", V),
- {reply, {V, V}, State}.
-struct2_test(State, V) ->
- ?PRINTDEBUG2("struct2_test", V),
- {reply, {V, V}, State}.
-seq1_test(State, V) ->
- ?PRINTDEBUG2("seq1_test", V),
- {reply, {V, V}, State}.
-seq2_test(State, V) ->
- ?PRINTDEBUG2("seq2_test", V),
- {reply, {V, V}, State}.
-seq3_test(State, V) ->
- ?PRINTDEBUG2("seq3_test", V),
- {reply, {V, V}, State}.
-seq4_test(State, V) ->
- ?PRINTDEBUG2("seq4_test", V),
- {reply, {V, V}, State}.
-seq5_test(State, V) ->
- ?PRINTDEBUG2("seq5_test", V),
- {reply, {V, V}, State}.
-array1_test(State, V) ->
- ?PRINTDEBUG2("array1_test", V),
- {reply, {V, V}, State}.
-array2_test(State, V) ->
- ?PRINTDEBUG2("array2_test", V),
- {reply, {V, V}, State}.
-enum_test(State, V) ->
- ?PRINTDEBUG2("enum_test", V),
- {reply, {V, V}, State}.
-string1_test(State, V) ->
- ?PRINTDEBUG2("string1_test", V),
- {reply, {V, V}, State}.
-string2_test(State, V) ->
- ?PRINTDEBUG2("string2_test", V),
- {reply, {V, V}, State}.
-string3_test(State, V) ->
- ?PRINTDEBUG2("string3_test", V),
- {reply, {V, V}, State}.
-string4_test(State, V) ->
- ?PRINTDEBUG2("string4_test", V),
- {reply, {V, V}, State}.
-pid_test(State, V) ->
- ?PRINTDEBUG2("pid_test", V),
- {reply, {V, V}, State}.
-port_test(State, V) ->
- ?PRINTDEBUG2("port_test", binary_to_list(term_to_binary(V))),
- {reply, {V, V}, State}.
-ref_test(State, V) ->
- ?PRINTDEBUG2("ref_test", binary_to_list(term_to_binary(V))),
- {reply, {V, V}, State}.
-term_test(State, V) ->
- ?PRINTDEBUG2("term_test", V),
- {reply, {V, V}, State}.
-typedef_test(State, A, B) ->
- ?PRINTDEBUG2("typedef_test", [A,B]),
- {reply, {4711, A, B}, State}.
-inline_sequence_test(State, V) ->
- ?PRINTDEBUG2("inline_sequence_test", V),
- {reply, {V, V}, State}.
-term_sequence_test(State, V) ->
- ?PRINTDEBUG2("term_sequence_test", V),
- {reply, {V, V}, State}.
-term_struct_test(State, V) ->
- ?PRINTDEBUG2("term_struct_test", V),
- {reply, {V, V}, State}.
-wstring1_test(State, V) ->
- ?PRINTDEBUG2("wstring1_test", V),
- {reply, {V, V}, State}.
-
-
-
-
diff --git a/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/my.c b/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/my.c
deleted file mode 100644
index 6045034052..0000000000
--- a/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/my.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 2004-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include "ic.h"
-#include "m_i.h"
-
-int my_prepare_notification_encoding(CORBA_Environment *env)
-{
- return oe_prepare_notification_encoding(env);
-}
-
-int my_send_notification_tmo(CORBA_Environment *env, unsigned int send_ms)
-{
- return oe_send_notification_tmo(env, send_ms);
-}
-
-int my_prepare_request_encoding(CORBA_Environment *env)
-{
- return oe_prepare_request_encoding(env);
-}
-
-int my_send_request_and_receive_reply_tmo(CORBA_Environment *env,
- unsigned int send_ms,
- unsigned int recv_ms)
-{
- return oe_send_request_and_receive_reply_tmo(env, send_ms, recv_ms);
-}
-
-int my_prepare_reply_decoding(CORBA_Environment *env)
-{
- return oe_prepare_reply_decoding(env);
-}
-
-
-
diff --git a/lib/ic/test/erl_client_c_server_SUITE.erl b/lib/ic/test/erl_client_c_server_SUITE.erl
deleted file mode 100644
index d592a611f7..0000000000
--- a/lib/ic/test/erl_client_c_server_SUITE.erl
+++ /dev/null
@@ -1,298 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
-%%----------------------------------------------------------------------
-%% Purpose : Test suite for erl-client/c-server
-%%----------------------------------------------------------------------
-
-
--module(erl_client_c_server_SUITE).
--include_lib("common_test/include/ct.hrl").
-
--export([init_per_testcase/2, end_per_testcase/2,all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, void_test/1,
- long_test/1, longlong_test/1, ushort_test/1, ulong_test/1,
- ulonglong_test/1, double_test/1, char_test/1, wchar_test/1,
- octet_test/1, bool_test/1, struct_test/1, struct2_test/1,
- seq1_test/1, seq2_test/1, seq3_test/1, seq4_test/1,
- seq5_test/1, array1_test/1, array2_test/1, enum_test/1,
- string1_test/1, string2_test/1, string3_test/1,
- string4_test/1, pid_test/1, port_test/1, ref_test/1,
- term_test/1, typedef_test/1, inline_sequence_test/1,
- term_sequence_test/1, term_struct_test/1, wstring1_test/1]).
-
--define(DEFAULT_TIMEOUT, 20000).
--define(PORT_TIMEOUT, 15000).
--define(CALL_TIMEOUT, 5000).
-
--define(C_SERVER_NODE_NAME, idl_c_server_test).
-
-%% Add/remove code path and watchdog before/after each test case.
-%%
-init_per_testcase(_Case, Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- code:add_patha(DataDir),
-
- %% Since other test suites use the module m_i, we have
- %% to make sure we are using the right m_i module.
- code:purge(m_i),
- code:load_file(m_i),
-
- WatchDog = test_server:timetrap(?DEFAULT_TIMEOUT),
- [{watchdog, WatchDog}| Config].
-
-end_per_testcase(_Case, Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- code:del_path(DataDir),
- WatchDog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(WatchDog).
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
-[void_test, long_test, longlong_test, ushort_test,
- ulong_test, ulonglong_test, double_test, char_test,
- wchar_test, octet_test, bool_test, struct_test,
- struct2_test, seq1_test, seq2_test, seq3_test,
- seq4_test, seq5_test, array1_test, array2_test,
- enum_test, string1_test, string2_test, string3_test,
- string4_test, pid_test, port_test, ref_test, term_test,
- typedef_test, inline_sequence_test, term_sequence_test,
- term_struct_test, wstring1_test].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-array1_test(Config) ->
- do_test(array1_test, Config).
-
-array2_test(Config) ->
- do_test(array2_test, Config).
-
-bool_test(Config) ->
- do_test(bool_test, Config).
-
-char_test(Config) ->
- do_test(char_test, Config).
-
-double_test(Config) ->
- do_test(double_test, Config).
-
-enum_test(Config) ->
- do_test(enum_test, Config).
-
-inline_sequence_test(Config) ->
- do_test(inline_sequence_test, Config).
-
-longlong_test(Config) ->
- do_test(longlong_test, Config).
-
-long_test(Config) ->
- do_test(long_test, Config).
-
-octet_test(Config) ->
- do_test(octet_test, Config).
-
-pid_test(Config) ->
- do_test(pid_test, Config).
-
-port_test(Config) ->
- do_test(port_test, Config).
-
-ref_test(Config) ->
- do_test(ref_test, Config).
-
-seq1_test(Config) ->
- do_test(seq1_test, Config).
-
-seq2_test(Config) ->
- do_test(seq2_test, Config).
-
-seq3_test(Config) ->
- do_test(seq3_test, Config).
-
-seq4_test(Config) ->
- do_test(seq4_test, Config).
-
-seq5_test(Config) ->
- do_test(seq5_test, Config).
-
-string1_test(Config) ->
- do_test(string1_test, Config).
-
-string2_test(Config) ->
- do_test(string2_test, Config).
-
-string3_test(Config) ->
- do_test(string3_test, Config).
-
-string4_test(Config) ->
- do_test(string4_test, Config).
-
-struct2_test(Config) ->
- do_test(struct2_test, Config).
-
-struct_test(Config) ->
- do_test(struct_test, Config).
-
-term_sequence_test(Config) ->
- do_test(term_sequence_test, Config).
-
-term_struct_test(Config) ->
- do_test(term_struct_test, Config).
-
-term_test(Config) ->
- do_test(term_test, Config).
-
-typedef_test(Config) ->
- do_test(typedef_test, Config).
-
-ulonglong_test(Config) ->
- do_test(ulonglong_test, Config).
-
-ulong_test(Config) ->
- do_test(ulong_test, Config).
-
-ushort_test(Config) ->
- do_test(ushort_test, Config).
-
-void_test(Config) ->
- do_test(void_test, Config).
-
-wchar_test(Config) ->
- do_test(wchar_test, Config).
-
-wstring1_test(Config) ->
- do_test(wstring1_test, Config).
-
-
-do_test(Case, Config) ->
- %% Trap exits
- process_flag(trap_exit, true),
- Node = atom_to_list(node()),
- [_NodeName, HostName] = string:tokens(Node, "@"),
- DataDir = proplists:get_value(data_dir, Config),
- %% io:format("~p: data directory: ~p~n", [?MODULE, DataDir]),
- Cookie = atom_to_list(erlang:get_cookie()),
- ServerNodeName = atom_to_list(?C_SERVER_NODE_NAME),
- %% Start C-server node as a port program. We wait for the node
- %% to connect to us.
- Cmd = filename:join([DataDir, "c_server"]) ++
- " -this-node-name " ++ ServerNodeName ++
- " -peer-node " ++ Node ++
- " -cookie " ++ Cookie,
- Port = open_port({spawn, Cmd}, [exit_status, eof, stderr_to_stdout]),
- ServerNode = list_to_atom(ServerNodeName ++ "@" ++ HostName),
- Res = case wait_for_hidden_node(ServerNode) of
- ok ->
- %% Need a port for port_test and typedef_test
- put(port_test_port, Port),
- R = (catch erl_client:Case(ServerNode, ?CALL_TIMEOUT)),
- case wait_for_completion(Port) of
- {error, timeout} ->
- kill_off_node(ServerNode);
- _ ->
- ok
- end,
- R;
- {error, timeout} ->
- case wait_for_completion(Port) of
- {error, timeout} ->
- kill_off_node(ServerNode);
- _ ->
- ok
- end,
- {error, timeout}
- end,
- process_flag(trap_exit, false),
- true = Res.
-
-
-%% Wait for eof *and* exit status, but return if exit status indicates
-%% an error, or we have been waiting more than PORT_TIMEOUT seconds.
-%%
-wait_for_completion(Port) ->
- wait_for_completion(Port, 0).
-
-wait_for_completion(Port, N) when N < 2 ->
- receive
- {Port, {data, Bytes}} ->
- %% Relay output
- io:format("~s", [Bytes]),
- wait_for_completion(Port, N);
- {Port, {exit_status, 0}} ->
- wait_for_completion(Port, N + 1);
- {Port, {exit_status, Status}} ->
- {error, Status};
- {Port, eof} ->
- wait_for_completion(Port, N + 1);
- {'EXIT', Port, Reason} ->
- io:format("Port exited with reason: ~w~n", [Reason]),
- wait_for_completion(Port, N);
- {'EXIT', From, Reason} ->
- io:format("Got unexpected exit: ~p~n", [{'EXIT', From, Reason}]),
- wait_for_completion(Port, N)
- after ?PORT_TIMEOUT ->
- {error, timeout}
- end;
-wait_for_completion(_, _) ->
- ok.
-
-wait_for_hidden_node(Node) ->
- Times = ?DEFAULT_TIMEOUT div 100,
- wait_for_hidden_node(Node, Times, 100).
-
-wait_for_hidden_node(Node, Times, WaitTime) when Times > 0 ->
- io:format("Waiting for hidden node: ~p~n", [Node]),
- case lists:member(Node, erlang:nodes(hidden)) of
- true ->
- ok;
- false ->
- delay(WaitTime),
- wait_for_hidden_node(Node, Times - 1, WaitTime)
- end;
-wait_for_hidden_node(_Node, _, _WaitTime) ->
- {error, timeout}.
-
-kill_off_node(Node) ->
- catch rpc:cast(Node, erlang, halt, [1]).
-
-delay(Time) ->
- receive
- after Time ->
- ok
- end.
-
-
-
-
diff --git a/lib/ic/test/erl_client_c_server_SUITE_data/Makefile.src b/lib/ic/test/erl_client_c_server_SUITE_data/Makefile.src
deleted file mode 100644
index 11eee8b7ac..0000000000
--- a/lib/ic/test/erl_client_c_server_SUITE_data/Makefile.src
+++ /dev/null
@@ -1,160 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2002-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-# Makefile.src for erl_client_c_server test
-# Note: This file *must* work for both Unix and Windows
-#
-# We use both `rm' (Unix) and `del' (Windows) for removing files, but
-# with a `-' in front so that the error in not finding `rm' (`del') on
-# Windows (Unix) is ignored.
-#
-# VxWorks? XXX
-#
-
-.SUFFIXES:
-.SUFFIXES: .c .h .erl .idl @obj@ .@EMULATOR@
-
-
-# Variables from ts:
-#
-
-ERL_INCLUDE = @erl_include@
-
-IC_INCLUDE_PATH = @ic_include_path@
-IC_LIB = @ic_lib@
-
-ERL_INTERFACE_INCLUDE = @erl_interface_include@
-ERL_INTERFACE_LIB = @erl_interface_lib@
-ERL_INTERFACE_EILIB = @erl_interface_eilib@
-ERL_INTERFACE_THREADLIB = @erl_interface_threadlib@
-ERL_INTERFACE_SOCK_LIBS = @erl_interface_sock_libs@
-
-CC = @CC@
-## XXX Should set warning flag with a DEBUG_FLAG
-CFLAGS = @CFLAGS@ @DEFS@ -I$(ERL_INCLUDE) \
- -I$(IC_INCLUDE_PATH) -I$(ERL_INTERFACE_INCLUDE)
-
-LD = @LD@
-LDFLAGS = @CROSSLDFLAGS@
-LIBS = $(IC_LIB) $(ERL_INTERFACE_LIB) $(ERL_INTERFACE_EILIB) \
- $(ERL_INTERFACE_THREADLIB) @LIBS@ $(ERL_INTERFACE_SOCK_LIBS)
-ERLC = erlc
-
-# Generated C header files
-GEN_H_FILES = \
- m__s.h \
- m_i__s.h \
- oe_erl_c_test__s.h
-
-# Generated C files
-GEN_C_FILES = \
- m__s.c \
- m_i__s.c \
- oe_code_m_a.c \
- oe_code_m_arr1.c \
- oe_code_m_arr2.c \
- oe_code_m_arr3.c \
- oe_code_m_aseq.c \
- oe_code_m_b.c \
- oe_code_m_bseq.c \
- oe_code_m_dd.c \
- oe_code_m_dyn.c \
- oe_code_m_dyn_sl.c \
- oe_code_m_es.c \
- oe_code_m_et.c \
- oe_code_m_etseq.c \
- oe_code_m_fruit.c \
- oe_code_m_lseq.c \
- oe_code_m_s.c \
- oe_code_m_s_sl.c \
- oe_code_m_sarr3.c \
- oe_code_m_simple.c \
- oe_code_m_ssarr3.c \
- oe_code_m_sseq.c \
- oe_code_m_ssstr3.c \
- oe_code_m_sstr3.c \
- oe_code_m_str1.c \
- oe_code_m_str3.c \
- oe_code_m_strRec.c \
- oe_code_m_strRec_str5.c \
- oe_code_m_strRec_str7.c \
- oe_erl_c_test__s.c
-
-GEN_HRL_FILES = \
- m.hrl \
- m_i.hrl \
- oe_erl_c_test.hrl
-
-GEN_ERL_FILES = \
- m.erl \
- m_arr2.erl \
- m_arr3.erl \
- m_i.erl \
- m_str3.erl \
- oe_erl_c_test.erl
-
-C_FILES = $(GEN_C_FILES) c_server.c callbacks.c
-
-OBJS = $(C_FILES:.c=@obj@)
-
-PGMS = c_server@exe@
-
-ERL_FILES = $(GEN_ERL_FILES) erl_client.erl
-
-EBINS = $(ERL_FILES:.erl=.@EMULATOR@)
-
-
-all: $(PGMS) $(EBINS)
-
-$(GEN_ERL_FILES) $(GEN_HRL_FILES): c_erl_test.built_erl
-$(GEN_C_FILES) $(GEN_H_FILES): c_erl_test.built_c
-$(OBJS): $(GEN_C_FILES) $(GEN_H_FILES)
-$(EBINS): $(GEN_ERL_FILES) $(GEN_HRL_FILES)
-
-clean:
- -rm -f $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \
- $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) \
- c_erl_test.built_erl c_erl_test.built_c
- -del /F /Q $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \
- $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) \
- c_erl_test.built_erl c_erl_test.built_c
-
-$(PGMS): $(OBJS)
- $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
-
-c_erl_test.built_c: erl_c_test.idl
- $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,c_server}" \
- "+{scoped_op_calls,true}" erl_c_test.idl
- echo done > c_erl_test.built_c
-
-# If we have scoped operation calls for C, we must have that for
-# Erlang as well, if we use the m_i.erl file for calling the server.
-
-c_erl_test.built_erl: erl_c_test.idl
- $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,erl_genserv}" \
- "+{scoped_op_calls,true}" "+{timeout,true}" erl_c_test.idl
- echo done > c_erl_test.built_erl
-
-.c@obj@:
- $(CC) -c -o $*@obj@ $(CFLAGS) $<
-
-.erl.@EMULATOR@:
- $(ERLC) -W -I $(IC_INCLUDE_PATH) $<
-
diff --git a/lib/ic/test/erl_client_c_server_SUITE_data/c_server.c b/lib/ic/test/erl_client_c_server_SUITE_data/c_server.c
deleted file mode 100644
index f48480e8dc..0000000000
--- a/lib/ic/test/erl_client_c_server_SUITE_data/c_server.c
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 2002-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-/* C-server for test of IC.
- *
- * The C-node implemented here connects to its peer node, waits for
- * one message, evaluates the message, returns an result message, and
- * terminates.
- *
- * TODO:
- *
- * 1. XXX #includes for VxWorks, Windows
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#ifndef __WIN32__
-# include <unistd.h>
-#endif
-
-#include <string.h>
-
-#ifdef __WIN32__
-# include <time.h>
-# include <sys/timeb.h>
-#elif defined VXWORKS
-# include <time.h>
-# include <sys/times.h>
-#else
-# include <sys/time.h>
-#endif
-
-#include <ctype.h>
-
-#ifdef __WIN32__
-# include <winsock2.h>
-# include <windows.h>
-#else
-# include <sys/types.h>
-# include <sys/socket.h>
-# include <netinet/in.h>
-# include <arpa/inet.h>
-# include <netdb.h>
-#endif
-
-#include "ic.h"
-#include "ei.h"
-#include "erl_interface.h"
-#include "eicode.h"
-#include "m_i__s.h"
-#include "m__s.h"
-
-#ifdef __WIN32__
-typedef struct {
- long tv_sec;
- long tv_usec;
-} MyTimeval;
-#else
-typedef struct timeval MyTimeval;
-#endif
-static void my_gettimeofday(MyTimeval *tv);
-static void showtime(MyTimeval *start, MyTimeval *stop);
-static void usage(void);
-static void done(int r);
-
-#define HOSTNAMESZ 255
-#define NODENAMESZ 512
-#define INBUFSZ 10
-#define OUTBUFSZ 0
-#define MAXTRIES 5
-
-static char *progname;
-
-/* main */
-#ifdef VXWORKS
-int c_server(int argc, char **argv)
-#else
-int main(int argc, char **argv)
-#endif
-{
- struct hostent *hp;
- MyTimeval start, stop;
- int i, fd, ires, tries;
- CORBA_Environment *env;
- char *this_node_name = NULL;
- char *peer_node = NULL;
- char *cookie = NULL;
- char host[HOSTNAMESZ + 1];
- char this_node[NODENAMESZ + 1];
- erlang_msg msg;
- int status, loop;
-
-#ifdef __WIN32__
- WORD wVersionRequested;
- WSADATA wsaData;
-
- wVersionRequested = MAKEWORD(2, 0);
-
- if (WSAStartup(wVersionRequested, &wsaData) != 0) {
- fprintf(stderr, "Could not load winsock2 v2.0 compatible DLL");
- exit(1);
- }
-#endif
-
- progname = argv[0];
- host[HOSTNAMESZ] = '\0';
- if (gethostname(host, HOSTNAMESZ + 1) < 0) {
- fprintf(stderr, "Can't find own hostname\n");
- done(1);
- }
- if ((hp = gethostbyname(host)) == 0) {
- fprintf(stderr, "Can't get ip address for host %s\n", host);
- done(1);
- }
- for (i = 1; i < argc; i++) {
- if (strcmp(argv[i], "-help") == 0) {
- usage();
- done(0);
- } else if (strcmp(argv[i], "-this-node-name") == 0) {
- i++;
- this_node_name = argv[i];
- } else if (strcmp(argv[i], "-peer-node") == 0) {
- i++;
- peer_node = argv[i];
- } else if (strcmp(argv[i], "-cookie") == 0) {
- i++;
- cookie = argv[i];
- } else {
- fprintf(stderr, "Error : invalid argument \"%s\"\n", argv[i]);
- usage();
- done(1);
- }
- }
-
- if (this_node_name == NULL || peer_node == NULL || cookie == NULL) {
- fprintf(stderr, "Error: missing option\n");
- usage();
- done(1);
- }
-
- /* Behead hostname at first dot */
- for (i=0; host[i] != '\0'; i++) {
- if (host[i] == '.') { host[i] = '\0'; break; }
- }
- sprintf(this_node, "%s@%s", this_node_name, host);
-
- fprintf(stderr, "c_server: this node: \"%s\"\n", this_node);
- fprintf(stderr, "c_server: peer node: \"%s\"\n", peer_node);
-
- /* initialize erl_interface */
- erl_init(NULL, 0);
-
- for (tries = 0; tries < MAXTRIES; tries++) {
- /* connect to peer node */
- ires = erl_connect_xinit(host, this_node_name, this_node,
- (struct in_addr *)*hp->h_addr_list,
- cookie, 0);
- fprintf(stderr, "c_server: erl_connect_xinit(): %d\n", ires);
-
- fd = erl_connect(peer_node);
- fprintf(stderr, "c_server: erl_connect(): %d\n", fd);
- if (fd >= 0)
- break;
- fprintf(stderr, "c_server: cannot connect, retrying\n");
- }
- if (fd < 0) {
- fprintf(stderr, "c_server: cannot connect, exiting\n");
- done(1);
- }
- env = CORBA_Environment_alloc(INBUFSZ, OUTBUFSZ);
- env->_fd = fd;
-
- status = 1;
- loop = 1;
- my_gettimeofday(&start);
- while (status >= 0 && loop > 0) {
- status = ei_receive_encoded(env->_fd, &env->_inbuf, &env->_inbufsz,
- &msg, &env->_iin);
- switch(status) {
- case ERL_SEND:
- case ERL_REG_SEND:
- /* get result */
- m_i__switch(NULL, env);
- switch(env->_major) {
- case CORBA_NO_EXCEPTION:
- break;
- case CORBA_SYSTEM_EXCEPTION:
- fprintf(stderr, "Request failure, reason : %s\n",
- (char *) CORBA_exception_value(env));
- CORBA_exception_free(env);
- break;
- default: /* Should not happen */
- CORBA_exception_free(env);
- break;
- }
- /* send back result data */
- if (env->_iout > 0)
- ei_send_encoded(env->_fd, &env->_caller, env->_outbuf,
- env->_iout);
- loop = 0;
- break;
- case ERL_TICK:
- break;
- default:
- if (status < 0) {
- fprintf(stderr, "Status negative: %d\n", status);
- loop = 0;
- }
- break;
- }
- }
- my_gettimeofday(&stop);
- showtime(&start, &stop);
-
- erl_close_connection(fd);
-
- CORBA_free(env->_inbuf);
- CORBA_free(env->_outbuf);
- CORBA_free(env);
- if (status < 0)
- done(-status);
- else
- done(0);
-}
-
-static void usage()
-{
- fprintf(stderr, "Usage: %s [-help] -this-node-name <name> "
- "-peer-node <nodename> -cookie <cookie>\n", progname);
- fprintf(stderr, "Example:\n %s -this-node-name kalle "
- "-peer-node olle@home -cookie oa678er\n", progname);
-}
-
-static void done(int r)
-{
-#ifdef __WIN32__
- WSACleanup();
-#endif
- exit(r);
-}
-
-static void showtime(MyTimeval *start, MyTimeval *stop)
-{
- MyTimeval elapsed;
-
- elapsed.tv_sec = stop->tv_sec - start->tv_sec;
- elapsed.tv_usec = stop->tv_usec - start->tv_usec;
- while (elapsed.tv_usec < 0) {
- elapsed.tv_sec -= 1;
- elapsed.tv_usec += 1000000;
- }
- fprintf(stderr,"%ld.%06ld seconds\n",elapsed.tv_sec, elapsed.tv_usec);
-}
-
-
-
-static void my_gettimeofday(MyTimeval *tv)
-#ifdef __WIN32__
-#define EPOCH_JULIAN_DIFF 11644473600i64
-{
- SYSTEMTIME t;
- FILETIME ft;
- LONGLONG lft;
-
- GetSystemTime(&t);
- SystemTimeToFileTime(&t, &ft);
- memcpy(&lft, &ft, sizeof(lft));
- tv->tv_usec = (long) ((lft / 10i64) % 1000000i64);
- tv->tv_sec = (long) ((lft / 10000000i64) - EPOCH_JULIAN_DIFF);
-}
-#elif defined VXWORKS
-{
- int rate = sysClkRateGet(); /* Ticks per second */
- unsigned long ctick = tickGet();
- tv->tv_sec = ctick / rate; /* secs since reboot */
- tv->tv_usec = ((ctick - (tv->tv_sec * rate))*1000000)/rate;
-}
-#else
-{
- gettimeofday(tv, NULL);
-}
-#endif
diff --git a/lib/ic/test/erl_client_c_server_SUITE_data/callbacks.c b/lib/ic/test/erl_client_c_server_SUITE_data/callbacks.c
deleted file mode 100644
index 2611e15f5a..0000000000
--- a/lib/ic/test/erl_client_c_server_SUITE_data/callbacks.c
+++ /dev/null
@@ -1,611 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 2002-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include <stdio.h>
-#include <stdlib.h>
-#ifndef __WIN32__
-# include <unistd.h>
-#endif
-#include <string.h>
-#include <ctype.h>
-#include <ic.h>
-#include <erl_interface.h>
-#include <ei.h>
-#include "m_i__s.h"
-
-
-
-/* OK */
-
-void my_void_test(CORBA_Object oe_obj,
- CORBA_Environment *oe_env)
-{
- /* printf("void test !\n"); */
-}
-
-m_i_void_test__rs* m_i_void_test__cb(CORBA_Object oe_obj,
- CORBA_Environment *oe_env)
-{
- return (m_i_void_test__rs*) (my_void_test);
-}
-
-
-
-/* OK */
-
-void my_long_test(CORBA_Object oe_obj,
- long* a,
- long* b,
- long* c,
- CORBA_Environment *oe_env)
-{
- /* printf("long test !\n"); */
-}
-
-
-m_i_long_test__rs* m_i_long_test__cb(CORBA_Object oe_obj,
- long* a,
- long* b,
- long* c,
- CORBA_Environment *oe_env)
-{
- *a = *b;
- *c = *b;
- return (m_i_long_test__rs*) (my_long_test);
-}
-
-/* OK */
-
-void my_longlong_test(CORBA_Object oe_obj,
- CORBA_long_long* a,
- CORBA_long_long* b,
- CORBA_long_long* c,
- CORBA_Environment *oe_env)
-{
- /* printf("long test !\n"); */
-}
-
-m_i_longlong_test__rs* m_i_longlong_test__cb(CORBA_Object oe_obj,
- CORBA_long_long* a,
- CORBA_long_long* b,
- CORBA_long_long* c,
- CORBA_Environment *oe_env)
-{
- *a = *b;
- *c = *b;
- return (m_i_longlong_test__rs*) (my_longlong_test);
-}
-
-/* OK */
-void my_ulong_test(CORBA_Object oe_obj,
- unsigned long* a,
- unsigned long* b,
- unsigned long* c,
- CORBA_Environment *oe_env)
-{
- /* printf("ulong test !\n"); */
-}
-
-m_i_ulong_test__rs* m_i_ulong_test__cb(CORBA_Object oe_obj,
- unsigned long* a,
- unsigned long* b,
- unsigned long* c,
- CORBA_Environment *oe_env)
-{
- *a = *b;
- *c = *b;
- return (m_i_ulong_test__rs*) (my_ulong_test);
-}
-
-/* OK */
-void my_ulonglong_test(CORBA_Object oe_obj,
- CORBA_unsigned_long_long* a,
- CORBA_unsigned_long_long* b,
- CORBA_unsigned_long_long* c,
- CORBA_Environment *oe_env)
-{
- /* printf("ulong test !\n"); */
-}
-
-m_i_ulonglong_test__rs* m_i_ulonglong_test__cb(CORBA_Object oe_obj,
- CORBA_unsigned_long_long* a,
- CORBA_unsigned_long_long* b,
- CORBA_unsigned_long_long* c,
- CORBA_Environment *oe_env)
-{
- *a = *b;
- *c = *b;
- return (m_i_ulonglong_test__rs*) (my_ulonglong_test);
-}
-
-m_i_ushort_test__rs* m_i_ushort_test__cb(CORBA_Object oe_obj,
- unsigned short* a,
- unsigned short* b,
- unsigned short* c,
- CORBA_Environment *oe_env)
-{
- *a = *b;
- *c = *b;
- return (m_i_ushort_test__rs*) NULL;
-}
-
-
-/* OK */
-void my_double_test(CORBA_Object oe_obj,
- double* a,
- double* b,
- double* c,
- CORBA_Environment *oe_env)
-{
- /* printf("double test !\n"); */
-}
-
-m_i_double_test__rs* m_i_double_test__cb(CORBA_Object oe_obj,
- double* a,
- double* b,
- double* c,
- CORBA_Environment *oe_env)
-{
- *a = *b;
- *c = *b;
- return (m_i_double_test__rs*) (my_double_test);
-}
-
-/* OK */
-m_i_char_test__rs* m_i_char_test__cb(CORBA_Object oe_obj,
- char* a,
- char* b,
- char* c,
- CORBA_Environment *oe_env)
-{
- m_i_char_test__rs* rs = NULL;
-
- *a = *b;
- *c = *b;
- return rs;
-}
-
-
-/* OK */
-m_i_wchar_test__rs* m_i_wchar_test__cb(CORBA_Object oe_obj,
- CORBA_wchar* a,
- CORBA_wchar* b,
- CORBA_wchar* c,
- CORBA_Environment *oe_env)
-{
- m_i_wchar_test__rs* rs = NULL;
-
- *a = *b;
- *c = *b;
- return rs;
-}
-
-/* OK */
-m_i_octet_test__rs* m_i_octet_test__cb(CORBA_Object oe_obj,
- char* a,
- char* b,
- char* c,
- CORBA_Environment *oe_env)
-{
- m_i_octet_test__rs* rs = NULL;
-
- *a = *b;
- *c = *b;
- return rs;
-}
-
-/* OK */
-m_i_bool_test__rs* m_i_bool_test__cb(CORBA_Object oe_obj,
- CORBA_boolean* a,
- CORBA_boolean* b,
- CORBA_boolean* c,
- CORBA_Environment *oe_env)
-{
- m_i_bool_test__rs* rs = NULL;
-
- *a = *b;
- *c = *b;
- return rs;
-}
-
-/* OK */
-void my_struct_test(CORBA_Object oe_obj,
- m_b* a,
- m_b* b,
- m_b* c,
- CORBA_Environment *oe_env)
-{
- /* printf("struct test !\n"); */
-}
-
-m_i_struct_test__rs* m_i_struct_test__cb(CORBA_Object oe_obj,
- m_b* a,
- m_b* b,
- m_b* c,
- CORBA_Environment *oe_env)
-{
- *a = *b;
- *c = *b;
- return (m_i_struct_test__rs*) (my_struct_test);
-}
-
-/* OK */
-m_i_struct2_test__rs* m_i_struct2_test__cb(CORBA_Object oe_obj,
- m_es* a,
- m_es* b,
- m_es* c,
- CORBA_Environment *oe_env)
-{
- m_i_struct2_test__rs* rs = NULL;
-
- *a = *b;
- *c = *b;
- return rs;
-}
-
-/* OK */
-/* XXX Commented out
-m_i_struct3_test__rs* m_i_struct3_test__cb(CORBA_Object oe_obj,
- m_simple* a,
- m_simple* b,
- m_simple* c,
- CORBA_Environment *oe_env)
-{
- m_i_struct3_test__rs* rs = NULL;
- *a = *b;
- *c = *b;
- return rs;
-}
-*/
-
-/* OK */
-m_i_seq1_test__rs* m_i_seq1_test__cb(CORBA_Object oe_obj,
- m_bseq** a,
- m_bseq* b,
- m_bseq** c,
- CORBA_Environment *oe_env)
-{
- m_i_seq1_test__rs* rs = NULL;
-
- *a = b;
- *c = b;
- return rs;
-}
-
-
-/* OK */
-m_i_seq2_test__rs* m_i_seq2_test__cb(CORBA_Object oe_obj,
- m_aseq** a,
- m_aseq* b,
- m_aseq** c,
- CORBA_Environment *oe_env)
-{
- m_i_seq2_test__rs* rs = NULL;
-
- *a = b;
- *c = b;
- return rs;
-}
-
-/* OK */
-m_i_seq3_test__rs* m_i_seq3_test__cb(CORBA_Object oe_obj,
- m_lseq** a,
- m_lseq* b,
- m_lseq** c,
- CORBA_Environment *oe_env)
-{
- m_i_seq3_test__rs* rs = NULL;
-
- *a = b;
- *c = b;
- return rs;
-}
-
-/* OK */
-m_i_seq4_test__rs* m_i_seq4_test__cb(CORBA_Object oe_obj,
- m_ssstr3** a,
- m_ssstr3* b,
- m_ssstr3** c,
- CORBA_Environment *oe_env)
-{
- m_i_seq4_test__rs* rs = NULL;
-
- *a = b;
- *c = b;
- return rs;
-}
-
-/* OK */
-m_i_seq5_test__rs* m_i_seq5_test__cb(CORBA_Object oe_obj,
- m_ssarr3** a,
- m_ssarr3* b,
- m_ssarr3** c,
- CORBA_Environment *oe_env)
-{
- m_i_seq5_test__rs* rs = NULL;
-
- *a = b;
- *c = b;
- return rs;
-}
-
-/* OK */
-m_i_array1_test__rs* m_i_array1_test__cb(CORBA_Object oe_obj,
- m_arr1 a,
- m_arr1 b,
- m_arr1 c,
- CORBA_Environment *oe_env)
-{
- int i;
- m_i_array1_test__rs* rs = NULL;
-
- for (i = 0; i < 500; i++) {
- a[i] = b[i];
- c[i] = b[i];
- }
- return rs;
-}
-
-/* OK */
-m_i_array2_test__rs* m_i_array2_test__cb(CORBA_Object oe_obj,
- m_dd a,
- m_dd b,
- m_dd c,
- CORBA_Environment *oe_env)
-{
- int i,j;
- m_i_array2_test__rs* rs = NULL;
-
- for (i = 0; i < 2; i++)
- for (j = 0; j < 3; j++) {
- a[i][j] = b[i][j];
- c[i][j] = b[i][j];
- }
- return rs;
-}
-
-
-/* OK */
-m_i_enum_test__rs* m_i_enum_test__cb(CORBA_Object oe_obj,
- m_fruit* a,
- m_fruit* b,
- m_fruit* c,
- CORBA_Environment *oe_env)
-{
- m_i_enum_test__rs* rs = NULL;
-
- *a = *b;
- *c = *b;
- return rs;
-}
-
-/* OK */
-m_i_string1_test__rs* m_i_string1_test__cb(CORBA_Object oe_obj,
- char ** a,
- char * b,
- char ** c,
- CORBA_Environment *oe_env)
-{
- m_i_string1_test__rs* rs = NULL;
-
- /*printf("\nString in ------> %s\n\n",b);*/
- *a = b;
- *c = b;
- return rs;
-}
-
-/* OK */
-m_i_string2_test__rs* m_i_string2_test__cb(CORBA_Object oe_obj,
- m_sseq** a,
- m_sseq* b,
- m_sseq** c,
- CORBA_Environment *oe_env)
-{
- m_i_string2_test__rs* rs = NULL;
-
- *a = b;
- *c = b;
- return rs;
-}
-
-/* OK */
-m_i_string3_test__rs* m_i_string3_test__cb(CORBA_Object oe_obj,
- char ** a,
- char * b,
- char ** c,
- CORBA_Environment *oe_env)
-{
- m_i_string3_test__rs* rs = NULL;
-
- *a = b;
- *c = b;
- return rs;
-}
-
-m_i_string4_test__rs* m_i_string4_test__cb(CORBA_Object oe_obj,
- m_strRec** a,
- m_strRec* b,
- m_strRec** c,
- CORBA_Environment *oe_env)
-{
- *a = b;
- *c = b;
-
- return (m_i_string4_test__rs*) NULL;
-}
-
-/* OK */
-m_i_wstring1_test__rs* m_i_wstring1_test__cb(CORBA_Object oe_obj,
- CORBA_wchar ** a,
- CORBA_wchar * b,
- CORBA_wchar ** c,
- CORBA_Environment *oe_env)
-{
- int tmp;
- m_i_wstring1_test__rs* rs = NULL;
-
- /*printf("\nString in ------> %s\n\n",b);*/
-
- for(tmp = 0; tmp < 5; tmp++)
- fprintf(stderr,"\np[%d] = %ld\n", tmp, b[tmp]);
- *a = b;
- *c = b;
- return rs;
-}
-
-
-/* OK */
-m_i_pid_test__rs* m_i_pid_test__cb(CORBA_Object oe_obj,
- erlang_pid* a,
- erlang_pid* b,
- erlang_pid* c,
- CORBA_Environment *oe_env)
-{
- m_i_pid_test__rs* rs = NULL;
-
- *a = *b;
- *c = *b;
- return rs;
-}
-
-/* OK */
-m_i_port_test__rs* m_i_port_test__cb(CORBA_Object oe_obj,
- erlang_port* a,
- erlang_port* b,
- erlang_port* c,
- CORBA_Environment *oe_env)
-{
- m_i_port_test__rs* rs = NULL;
-
- strcpy((*a).node,(*b).node);
- (*a).id = (*b).id;
- (*a).creation = 0;
-
- strcpy((*c).node,(*b).node);
- (*c).id = (*b).id;
- (*c).creation = 0;
- return rs;
-}
-
-/* OK */
-m_i_ref_test__rs* m_i_ref_test__cb(CORBA_Object oe_obj,
- erlang_ref* a,
- erlang_ref* b,
- erlang_ref* c,
- CORBA_Environment *oe_env)
-{
-
- m_i_ref_test__rs* rs = NULL;
-
- strcpy((*a).node,(*b).node);
- /*(*a).id = (*b).id;*/
- (*a).len = (*b).len;
- (*a).n[0] = (*b).n[0];
- (*a).n[1] = (*b).n[1];
- (*a).n[2] = (*b).n[2];
- (*a).creation = 0;
-
- strcpy((*c).node,(*b).node);
- /*(*c).id = (*b).id;*/
- (*c).len = (*b).len;
- (*c).n[0] = (*b).n[0];
- (*c).n[1] = (*b).n[1];
- (*c).n[2] = (*b).n[2];
- (*c).creation = 0;
- return rs;
-}
-
-/* OK */
-m_i_term_test__rs* m_i_term_test__cb(CORBA_Object oe_obj,
- ETERM** a,
- ETERM** b,
- ETERM** c,
- CORBA_Environment *oe_env)
-{
- m_i_term_test__rs* rs = NULL;
-
- *a = *b;
- *c = *b;
- return rs;
-}
-
-m_i_typedef_test__rs* m_i_typedef_test__cb(CORBA_Object oe_obj,
- long* a,
- ETERM** b,
- erlang_port* c,
- ETERM** d ,
- erlang_port* e,
- CORBA_Environment *oe_env)
-{
- m_i_typedef_test__rs* rs = NULL;
-
- *d = *b;
- strcpy((*e).node,(*c).node);
- (*e).id = (*c).id;
- (*e).creation = 0;
- *a = 4711;
- return rs;
-}
-
-/* OK */
-m_i_inline_sequence_test__rs* m_i_inline_sequence_test__cb(
- CORBA_Object oe_obj,
- m_s** a,
- m_s* b,
- m_s** c,
- CORBA_Environment *oe_env)
-{
- m_i_inline_sequence_test__rs* rs = NULL;
-
- *a = b;
- *c = b;
- return rs;
-}
-
-/* OK */
-m_i_term_sequence_test__rs* m_i_term_sequence_test__cb(
- CORBA_Object oe_obj,
- m_etseq** a,
- m_etseq* b,
- m_etseq** c,
- CORBA_Environment *oe_env)
-{
- m_i_term_sequence_test__rs* rs = NULL;
-
- *a = b;
- *c = b;
- return rs;
-}
-
-
-/* OK */
-m_i_term_struct_test__rs* m_i_term_struct_test__cb(CORBA_Object oe_obj,
- m_et* a,
- m_et* b,
- m_et* c,
- CORBA_Environment *oe_env)
-{
- m_i_term_struct_test__rs* rs = NULL;
-
- *a = *b;
- *c = *b;
- return rs;
-}
-
diff --git a/lib/ic/test/erl_client_c_server_SUITE_data/erl_c_test.idl b/lib/ic/test/erl_client_c_server_SUITE_data/erl_c_test.idl
deleted file mode 100644
index 6ed28f0822..0000000000
--- a/lib/ic/test/erl_client_c_server_SUITE_data/erl_c_test.idl
+++ /dev/null
@@ -1,175 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 2002-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-#include "erlang.idl"
-
-
-const short TestConst = 1;
-
-module m {
-
- const short TestConst = 2;
-
- struct b {
- long l;
- char c;
- };
-
- struct simple {
- long l;
- b b_t;
- };
-
- enum fruit {orange, banana, apple, peach, pear};
-
- typedef sequence<long> lseq;
-
- typedef sequence<b> bseq;
-
- struct a {
- long l;
- bseq y;
- double d;
- };
-
- typedef sequence<a> aseq;
-
- typedef sequence<string> sseq;
- typedef string str;
- typedef long myLong;
-
- typedef long arr1[500], dd[2][3];
-
- typedef erlang::term apa;
- typedef erlang::port banan;
-
- typedef sequence<erlang::term> etseq;
-
- struct s {
- long l;
- sequence<long> sl;
- };
-
- struct es {
- fruit f;
- myLong l;
- };
-
- struct et {
- erlang::term e;
- long l;
- };
-
-
- typedef sequence<char> str1;
- typedef string<12> str2;
- typedef char str3[3];
-
- typedef sequence<string> sstr3; // sequence of string
- typedef sequence<sstr3> ssstr3; // sequence of sequences of strings
-
- typedef long arr3[3]; // array of long
- typedef sequence<arr3> sarr3; // sequence of array
- typedef sequence<sarr3> ssarr3; // sequence of sequnces of arrays of strings
-
- struct strRec{
- boolean bb;
- string str4;
- long str7[3][2];
- sequence<char> str5;
- string<12> str6;
- str3 str8;
- str2 str9;
- str1 str10;
- };
-
-
- struct dyn {
- long l;
- sequence<long> sl;
- };
- typedef dyn arr2[1][2];
-
-
- interface i {
-
- const short TestConst = 3;
-
- //arr2 suck(in arr2 x, out arr2 y );
-
- ///////////////////////////////// attribute long l;
-
- // simple types
- void void_test();
- long long_test(in long a, out long a1);
- long long longlong_test(in long long a, out long long a1);
- unsigned short ushort_test(in unsigned short a, out unsigned short a1);
- unsigned long ulong_test(in unsigned long a, out unsigned long a1);
- unsigned long long ulonglong_test(in unsigned long long a, out unsigned long long a1);
- double double_test(in double a, out double a1);
- char char_test(in char a, out char a1);
- wchar wchar_test(in wchar a, out wchar a1);
- octet octet_test(in octet a, out octet a1);
- boolean bool_test(in boolean a, out boolean a1);
-
- // Seq. and struct tests
- b struct_test(in b a, out b a1);
- es struct2_test(in es a, out es a1);
- //simple struct3_test(in simple x, out simple y);
- bseq seq1_test(in bseq a, out bseq a1);
- aseq seq2_test(in aseq a, out aseq a1);
- lseq seq3_test(in lseq a, out lseq a1);
- ssstr3 seq4_test(in ssstr3 a, out ssstr3 a1);
- ssarr3 seq5_test(in ssarr3 a, out ssarr3 a1);
-
- // Array tests
- arr1 array1_test(in arr1 a, out arr1 a1);
- dd array2_test(in dd a, out dd a1);
-
- // enum test
- fruit enum_test(in fruit a, out fruit a1);
-
- // string tests
- string string1_test(in string a, out string a1);
- wstring wstring1_test(in wstring a, out wstring a1);
- sseq string2_test(in sseq a, out sseq a1);
- str string3_test(in str a, out str a1);
- strRec string4_test(in strRec a, out strRec a1);
-
- // Special erlang types
- erlang::pid pid_test(in erlang::pid a, out erlang::pid a1);
- erlang::port port_test(in erlang::port a, out erlang::port a1);
- erlang::ref ref_test(in erlang::ref a, out erlang::ref a1);
- erlang::term term_test(in erlang::term a, out erlang::term a1);
-
- // typedef test
- long typedef_test(in apa a, in banan b, out apa a1, out banan b1);
-
- // inlined seq. test
- s inline_sequence_test(in s a, out s a1);
-
- // term seq. test
- etseq term_sequence_test(in etseq a, out etseq a1);
- // term struct test
- et term_struct_test(in et a, out et a1);
-
- };
-
-};
diff --git a/lib/ic/test/erl_client_c_server_SUITE_data/erl_client.erl b/lib/ic/test/erl_client_c_server_SUITE_data/erl_client.erl
deleted file mode 100644
index 139e2d7661..0000000000
--- a/lib/ic/test/erl_client_c_server_SUITE_data/erl_client.erl
+++ /dev/null
@@ -1,332 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(erl_client).
-
--export([void_test/2, long_test/2, longlong_test/2, ushort_test/2,
- ulong_test/2, ulonglong_test/2, double_test/2, char_test/2,
- wchar_test/2, octet_test/2, bool_test/2, struct_test/2,
- struct2_test/2, seq1_test/2, seq2_test/2, seq3_test/2,
- seq4_test/2, seq5_test/2, array1_test/2, array2_test/2,
- enum_test/2, string1_test/2, wstring1_test/2, string2_test/2,
- string3_test/2, string4_test/2, pid_test/2, port_test/2,
- ref_test/2, term_test/2, typedef_test/2,
- inline_sequence_test/2, term_sequence_test/2,
- term_struct_test/2
-
-]).
-
--include("m.hrl").
--include("m_i.hrl").
--include("oe_erl_c_test.hrl").
-
-%%b
-void_test(Node, Timeout) ->
- Ret = m_i:void_test({olsson, Node}, Timeout),
- Ret == void. % XXX Not documented
-%%e
-
-%%b
-long_test(Node, Timeout) ->
- In = max_long(),
- {Ret, Out} = m_i:long_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-longlong_test(Node, Timeout) ->
- In = 65537,
- {Ret, Out} = m_i:longlong_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-ushort_test(Node, Timeout) ->
- In = max_ushort(),
- {Ret, Out} = m_i:ushort_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-ulong_test(Node, Timeout) ->
- In = max_ulong(),
- {Ret, Out} = m_i:ulong_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-ulonglong_test(Node, Timeout) ->
- In = 65537,
- {Ret, Out} = m_i:ulonglong_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-double_test(Node, Timeout) ->
- In = 37768.93,
- {Ret, Out} = m_i:double_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-char_test(Node, Timeout) ->
- In = 80,
- {Ret, Out} = m_i:char_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-wchar_test(Node, Timeout) ->
- In = 4097,
- {Ret, Out} = m_i:wchar_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-octet_test(Node, Timeout) ->
- In = 255,
- {Ret, Out} = m_i:octet_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-bool_test(Node, Timeout) ->
- In = false,
- {Ret, Out} = m_i:bool_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-struct_test(Node, Timeout) ->
- In = #m_b{l = max_long(), c = $a},
- {Ret, Out} = m_i:struct_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-struct2_test(Node, Timeout) ->
- In = #m_es{ f = banana, l = max_long()},
- {Ret, Out} = m_i:struct2_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-seq1_test(Node, Timeout) ->
- B1 = #m_b{l = max_long(), c = $a},
- B2 = #m_b{l = min_long(), c = $b},
- In = [B1, B2],
- {Ret, Out} = m_i:seq1_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-seq2_test(Node, Timeout) ->
- B = #m_b{l = max_long(), c = $a},
- A = #m_a{l = min_long(), y = [B, B], d = 4711.31},
- In = [A, A, A],
- {Ret, Out} = m_i:seq2_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-seq3_test(Node, Timeout) ->
- In = [max_long(), min_long(), max_long()],
- {Ret, Out} = m_i:seq3_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-seq4_test(Node, Timeout) ->
- In = [["hello", "all"], ["Erlang", "users", "!"]],
- {Ret, Out} = m_i:seq4_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-seq5_test(Node, Timeout) ->
- Arr3 = mk_array(3, max_long()),
- In = [[Arr3, Arr3], [Arr3, Arr3, Arr3]],
- {Ret, Out} = m_i:seq5_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-array1_test(Node, Timeout) ->
- In = mk_array(500, min_long()),
- {Ret, Out} = m_i:array1_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-array2_test(Node, Timeout) ->
- In = mk_array(2, mk_array(3, min_long())),
- {Ret, Out} = m_i:array2_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-enum_test(Node, Timeout) ->
- In = banana,
- {Ret, Out} = m_i:enum_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-string1_test(Node, Timeout) ->
- In = "Developing Erlang applications is fun!",
- {Ret, Out} = m_i:string1_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-wstring1_test(Node, Timeout) ->
- In = [1047| "eveloping Erlang applications is fun!"],
- {Ret, Out} = m_i:wstring1_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-string2_test(Node, Timeout) ->
- In = ["Developing Erlang applications ", "is fun!"],
- {Ret, Out} = m_i:string2_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-string3_test(Node, Timeout) ->
- In = "Developing Erlang applications is fun!",
- {Ret, Out} = m_i:string3_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-string4_test(Node, Timeout) ->
-
- In = #m_strRec{
- bb = true,
- str4 = "Developing Erlang applications "
- "is fun!",
- str7 = mk_array(3, mk_array(2, max_long())),
- str5 = [$a, $b, $c, $d, $e, $f],
- str6 = "123456789012",
- str8 = {$x, $y, $x},
- str9 = "123456789012",
- str10 = [$a, $b, $c, $d, $e, $f]
- },
- {Ret, Out} = m_i:string4_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-pid_test(Node, Timeout) ->
- In = self(),
- {Ret, Out} = m_i:pid_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-port_test(Node, Timeout) ->
- In = get(port_test_port),
- {Ret, Out} = m_i:port_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-ref_test(Node, Timeout) ->
- In = make_ref(),
- {Ret, Out} = m_i:ref_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-term_test(Node, Timeout) ->
- In = {[a, b], 17, kalle},
- {Ret, Out} = m_i:term_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-typedef_test(Node, Timeout) ->
- In1 = {nisse, [1, 2], olsson},
- In2 = get(port_test_port),
- {Ret, Out1, Out2} = m_i:typedef_test({olsson, Node}, Timeout, In1, In2),
- %% XXX Should check that Ret is an integer.
- (Out1 == In1) and (Out2 == In2).
-%%e
-
-%%b
-inline_sequence_test(Node, Timeout) ->
- In = #m_s{l = min_long(), sl = [max_long(), min_long()]},
- {Ret, Out} = m_i:inline_sequence_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-term_sequence_test(Node, Timeout) ->
- In = lists:duplicate(17, {nisse, [1, 2], {kalle, olsson}}),
- {Ret, Out} = m_i:term_sequence_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-term_struct_test(Node, Timeout) ->
- In = #m_et{e = {nisse, ["abcde"], {kalle, olsson}}, l = 4711},
- {Ret, Out} = m_i:term_struct_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-
-%% Locals
-
-mk_array(Es) ->
- list_to_tuple(Es).
-
-mk_array(N, E) ->
- mk_array(lists:duplicate(N, E)).
-
-%% max_short() ->
-%% power_of_two(15) - 1.
-max_long() ->
- power_of_two(31) - 1.
-max_longlong() ->
- power_of_two(63) - 1.
-max_ushort() ->
- power_of_two(16) - 1.
-max_ulong() ->
- power_of_two(32) - 1.
-max_ulonglong() ->
- power_of_two(64) - 1.
-
-%% min_short() ->
-%% -power_of_two(15).
-min_long() ->
- -power_of_two(31).
-%% min_longlong() ->
-%% -power_of_two(63).
-%% min_ushort() ->
-%% 0.
-%% min_ulong() ->
-%% 0.
-%% min_ulonglong() ->
-%% 0.
-
-power_of_two(N) ->
- round(math:pow(2, N)).
-
diff --git a/lib/ic/test/erl_client_c_server_proto_SUITE.erl b/lib/ic/test/erl_client_c_server_proto_SUITE.erl
deleted file mode 100644
index 99eeed01ad..0000000000
--- a/lib/ic/test/erl_client_c_server_proto_SUITE.erl
+++ /dev/null
@@ -1,298 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
-%%----------------------------------------------------------------------
-%% Purpose : Test suite for erl-client/c-server
-%%----------------------------------------------------------------------
-
-
--module(erl_client_c_server_proto_SUITE).
--include_lib("common_test/include/ct.hrl").
-
--export([init_per_testcase/2, end_per_testcase/2,all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, void_test/1,
- long_test/1, longlong_test/1, ushort_test/1, ulong_test/1,
- ulonglong_test/1, double_test/1, char_test/1, wchar_test/1,
- octet_test/1, bool_test/1, struct_test/1, struct2_test/1,
- seq1_test/1, seq2_test/1, seq3_test/1, seq4_test/1,
- seq5_test/1, array1_test/1, array2_test/1, enum_test/1,
- string1_test/1, string2_test/1, string3_test/1,
- string4_test/1, pid_test/1, port_test/1, ref_test/1,
- term_test/1, typedef_test/1, inline_sequence_test/1,
- term_sequence_test/1, term_struct_test/1, wstring1_test/1]).
-
--define(DEFAULT_TIMEOUT, 20000).
--define(PORT_TIMEOUT, 15000).
--define(CALL_TIMEOUT, 5000).
-
--define(C_SERVER_NODE_NAME, idl_c_server_test).
-
-%% Add/remove code path and watchdog before/after each test case.
-%%
-init_per_testcase(_Case, Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- code:add_patha(DataDir),
-
- %% Since other test suites use the module m_i, we have
- %% to make sure we are using the right m_i module.
- code:purge(m_i),
- code:load_file(m_i),
-
- WatchDog = test_server:timetrap(?DEFAULT_TIMEOUT),
- [{watchdog, WatchDog}| Config].
-
-end_per_testcase(_Case, Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- code:del_path(DataDir),
- WatchDog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(WatchDog).
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
-[void_test, long_test, longlong_test, ushort_test,
- ulong_test, ulonglong_test, double_test, char_test,
- wchar_test, octet_test, bool_test, struct_test,
- struct2_test, seq1_test, seq2_test, seq3_test,
- seq4_test, seq5_test, array1_test, array2_test,
- enum_test, string1_test, string2_test, string3_test,
- string4_test, pid_test, port_test, ref_test, term_test,
- typedef_test, inline_sequence_test, term_sequence_test,
- term_struct_test, wstring1_test].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-array1_test(Config) ->
- do_test(array1_test, Config).
-
-array2_test(Config) ->
- do_test(array2_test, Config).
-
-bool_test(Config) ->
- do_test(bool_test, Config).
-
-char_test(Config) ->
- do_test(char_test, Config).
-
-double_test(Config) ->
- do_test(double_test, Config).
-
-enum_test(Config) ->
- do_test(enum_test, Config).
-
-inline_sequence_test(Config) ->
- do_test(inline_sequence_test, Config).
-
-longlong_test(Config) ->
- do_test(longlong_test, Config).
-
-long_test(Config) ->
- do_test(long_test, Config).
-
-octet_test(Config) ->
- do_test(octet_test, Config).
-
-pid_test(Config) ->
- do_test(pid_test, Config).
-
-port_test(Config) ->
- do_test(port_test, Config).
-
-ref_test(Config) ->
- do_test(ref_test, Config).
-
-seq1_test(Config) ->
- do_test(seq1_test, Config).
-
-seq2_test(Config) ->
- do_test(seq2_test, Config).
-
-seq3_test(Config) ->
- do_test(seq3_test, Config).
-
-seq4_test(Config) ->
- do_test(seq4_test, Config).
-
-seq5_test(Config) ->
- do_test(seq5_test, Config).
-
-string1_test(Config) ->
- do_test(string1_test, Config).
-
-string2_test(Config) ->
- do_test(string2_test, Config).
-
-string3_test(Config) ->
- do_test(string3_test, Config).
-
-string4_test(Config) ->
- do_test(string4_test, Config).
-
-struct2_test(Config) ->
- do_test(struct2_test, Config).
-
-struct_test(Config) ->
- do_test(struct_test, Config).
-
-term_sequence_test(Config) ->
- do_test(term_sequence_test, Config).
-
-term_struct_test(Config) ->
- do_test(term_struct_test, Config).
-
-term_test(Config) ->
- do_test(term_test, Config).
-
-typedef_test(Config) ->
- do_test(typedef_test, Config).
-
-ulonglong_test(Config) ->
- do_test(ulonglong_test, Config).
-
-ulong_test(Config) ->
- do_test(ulong_test, Config).
-
-ushort_test(Config) ->
- do_test(ushort_test, Config).
-
-void_test(Config) ->
- do_test(void_test, Config).
-
-wchar_test(Config) ->
- do_test(wchar_test, Config).
-
-wstring1_test(Config) ->
- do_test(wstring1_test, Config).
-
-
-do_test(Case, Config) ->
- %% Trap exits
- process_flag(trap_exit, true),
- Node = atom_to_list(node()),
- [_NodeName, HostName] = string:tokens(Node, "@"),
- DataDir = proplists:get_value(data_dir, Config),
- %% io:format("~p: data directory: ~p~n", [?MODULE, DataDir]),
- Cookie = atom_to_list(erlang:get_cookie()),
- ServerNodeName = atom_to_list(?C_SERVER_NODE_NAME),
- %% Start C-server node as a port program. We wait for the node
- %% to connect to us.
- Cmd = filename:join([DataDir, "c_server"]) ++
- " -this-node-name " ++ ServerNodeName ++
- " -peer-node " ++ Node ++
- " -cookie " ++ Cookie,
- Port = open_port({spawn, Cmd}, [exit_status, eof, stderr_to_stdout]),
- ServerNode = list_to_atom(ServerNodeName ++ "@" ++ HostName),
- Res = case wait_for_hidden_node(ServerNode) of
- ok ->
- %% Need a port for port_test and typedef_test
- put(port_test_port, Port),
- R = (catch erl_client:Case(ServerNode, ?CALL_TIMEOUT)),
- case wait_for_completion(Port) of
- {error, timeout} ->
- kill_off_node(ServerNode);
- _ ->
- ok
- end,
- R;
- {error, timeout} ->
- case wait_for_completion(Port) of
- {error, timeout} ->
- kill_off_node(ServerNode);
- _ ->
- ok
- end,
- {error, timeout}
- end,
- process_flag(trap_exit, false),
- true = Res.
-
-
-%% Wait for eof *and* exit status, but return if exit status indicates
-%% an error, or we have been waiting more than PORT_TIMEOUT seconds.
-%%
-wait_for_completion(Port) ->
- wait_for_completion(Port, 0).
-
-wait_for_completion(Port, N) when N < 2 ->
- receive
- {Port, {data, Bytes}} ->
- %% Relay output
- io:format("~s", [Bytes]),
- wait_for_completion(Port, N);
- {Port, {exit_status, 0}} ->
- wait_for_completion(Port, N + 1);
- {Port, {exit_status, Status}} ->
- {error, Status};
- {Port, eof} ->
- wait_for_completion(Port, N + 1);
- {'EXIT', Port, Reason} ->
- io:format("Port exited with reason: ~w~n", [Reason]),
- wait_for_completion(Port, N);
- {'EXIT', From, Reason} ->
- io:format("Got unexpected exit: ~p~n", [{'EXIT', From, Reason}]),
- wait_for_completion(Port, N)
- after ?PORT_TIMEOUT ->
- {error, timeout}
- end;
-wait_for_completion(_, _) ->
- ok.
-
-wait_for_hidden_node(Node) ->
- Times = ?DEFAULT_TIMEOUT div 100,
- wait_for_hidden_node(Node, Times, 100).
-
-wait_for_hidden_node(Node, Times, WaitTime) when Times > 0 ->
- io:format("Waiting for hidden node: ~p~n", [Node]),
- case lists:member(Node, erlang:nodes(hidden)) of
- true ->
- ok;
- false ->
- delay(WaitTime),
- wait_for_hidden_node(Node, Times - 1, WaitTime)
- end;
-wait_for_hidden_node(_Node, _, _WaitTime) ->
- {error, timeout}.
-
-kill_off_node(Node) ->
- catch rpc:cast(Node, erlang, halt, [1]).
-
-delay(Time) ->
- receive
- after Time ->
- ok
- end.
-
-
-
-
diff --git a/lib/ic/test/erl_client_c_server_proto_SUITE_data/Makefile.src b/lib/ic/test/erl_client_c_server_proto_SUITE_data/Makefile.src
deleted file mode 100644
index 4ef7a74cde..0000000000
--- a/lib/ic/test/erl_client_c_server_proto_SUITE_data/Makefile.src
+++ /dev/null
@@ -1,160 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2004-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-# Makefile.src for erl_client_c_server test
-# Note: This file *must* work for both Unix and Windows
-#
-# We use both `rm' (Unix) and `del' (Windows) for removing files, but
-# with a `-' in front so that the error in not finding `rm' (`del') on
-# Windows (Unix) is ignored.
-#
-# VxWorks? XXX
-#
-
-.SUFFIXES:
-.SUFFIXES: .c .h .erl .idl @obj@ .@EMULATOR@
-
-
-# Variables from ts:
-#
-
-ERL_INCLUDE = @erl_include@
-
-IC_INCLUDE_PATH = @ic_include_path@
-IC_LIB = @ic_lib@
-
-ERL_INTERFACE_INCLUDE = @erl_interface_include@
-ERL_INTERFACE_LIB = @erl_interface_lib@
-ERL_INTERFACE_EILIB = @erl_interface_eilib@
-ERL_INTERFACE_THREADLIB = @erl_interface_threadlib@
-ERL_INTERFACE_SOCK_LIBS = @erl_interface_sock_libs@
-
-CC = @CC@
-## XXX Should set warning flag with a DEBUG_FLAG
-CFLAGS = @CFLAGS@ @DEFS@ -I$(ERL_INCLUDE) \
- -I$(IC_INCLUDE_PATH) -I$(ERL_INTERFACE_INCLUDE)
-
-LD = @LD@
-LDFLAGS = @CROSSLDFLAGS@
-LIBS = $(IC_LIB) $(ERL_INTERFACE_LIB) $(ERL_INTERFACE_EILIB) \
- $(ERL_INTERFACE_THREADLIB) @LIBS@ $(ERL_INTERFACE_SOCK_LIBS)
-ERLC = erlc
-
-# Generated C header files
-GEN_H_FILES = \
- m__s.h \
- m_i__s.h \
- oe_erl_c_test__s.h
-
-# Generated C files
-GEN_C_FILES = \
- m__s.c \
- m_i__s.c \
- oe_code_m_a.c \
- oe_code_m_arr1.c \
- oe_code_m_arr2.c \
- oe_code_m_arr3.c \
- oe_code_m_aseq.c \
- oe_code_m_b.c \
- oe_code_m_bseq.c \
- oe_code_m_dd.c \
- oe_code_m_dyn.c \
- oe_code_m_dyn_sl.c \
- oe_code_m_es.c \
- oe_code_m_et.c \
- oe_code_m_etseq.c \
- oe_code_m_fruit.c \
- oe_code_m_lseq.c \
- oe_code_m_s.c \
- oe_code_m_s_sl.c \
- oe_code_m_sarr3.c \
- oe_code_m_simple.c \
- oe_code_m_ssarr3.c \
- oe_code_m_sseq.c \
- oe_code_m_ssstr3.c \
- oe_code_m_sstr3.c \
- oe_code_m_str1.c \
- oe_code_m_str3.c \
- oe_code_m_strRec.c \
- oe_code_m_strRec_str5.c \
- oe_code_m_strRec_str7.c \
- oe_erl_c_test__s.c
-
-GEN_HRL_FILES = \
- m.hrl \
- m_i.hrl \
- oe_erl_c_test.hrl
-
-GEN_ERL_FILES = \
- m.erl \
- m_arr2.erl \
- m_arr3.erl \
- m_i.erl \
- m_str3.erl \
- oe_erl_c_test.erl
-
-C_FILES = $(GEN_C_FILES) c_server.c callbacks.c
-
-OBJS = $(C_FILES:.c=@obj@)
-
-PGMS = c_server@exe@
-
-ERL_FILES = $(GEN_ERL_FILES) erl_client.erl
-
-EBINS = $(ERL_FILES:.erl=.@EMULATOR@)
-
-
-all: $(PGMS) $(EBINS)
-
-$(GEN_ERL_FILES) $(GEN_HRL_FILES): c_erl_test.built_erl
-$(GEN_C_FILES) $(GEN_H_FILES): c_erl_test.built_c
-$(OBJS): $(GEN_C_FILES) $(GEN_H_FILES)
-$(EBINS): $(GEN_ERL_FILES) $(GEN_HRL_FILES)
-
-clean:
- -rm -f $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \
- $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) \
- c_erl_test.built_erl c_erl_test.built_c
- -del /F /Q $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \
- $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) \
- c_erl_test.built_erl c_erl_test.built_c
-
-$(PGMS): $(OBJS)
- $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
-
-c_erl_test.built_c: erl_c_test.idl
- $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,c_server}" \
- "+{scoped_op_calls,true}" erl_c_test.idl
- echo done > c_erl_test.built_c
-
-# If we have scoped operation calls for C, we must have that for
-# Erlang as well, if we use the m_i.erl file for calling the server.
-
-c_erl_test.built_erl: erl_c_test.idl
- $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,erl_genserv}" \
- "+{scoped_op_calls,true}" "+{timeout,true}" erl_c_test.idl
- echo done > c_erl_test.built_erl
-
-.c@obj@:
- $(CC) -c -o $*@obj@ $(CFLAGS) $<
-
-.erl.@EMULATOR@:
- $(ERLC) -W -I $(IC_INCLUDE_PATH) $<
-
diff --git a/lib/ic/test/erl_client_c_server_proto_SUITE_data/c_server.c b/lib/ic/test/erl_client_c_server_proto_SUITE_data/c_server.c
deleted file mode 100644
index e2ba5bd5b6..0000000000
--- a/lib/ic/test/erl_client_c_server_proto_SUITE_data/c_server.c
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 2004-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-/* C-server for test of IC.
- *
- * The C-node implemented here connects to its peer node, waits for
- * one message, evaluates the message, returns an result message, and
- * terminates.
- *
- * TODO:
- *
- * 1. XXX #includes for VxWorks, Windows
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#ifndef __WIN32__
-# include <unistd.h>
-#endif
-
-#include <string.h>
-
-#ifdef __WIN32__
-# include <time.h>
-# include <sys/timeb.h>
-#elif defined VXWORKS
-# include <time.h>
-# include <sys/times.h>
-#else
-# include <sys/time.h>
-#endif
-
-#include <ctype.h>
-
-#ifdef __WIN32__
-# include <winsock2.h>
-# include <windows.h>
-#else
-# include <sys/types.h>
-# include <sys/socket.h>
-# include <netinet/in.h>
-# include <arpa/inet.h>
-# include <netdb.h>
-#endif
-
-#include "ic.h"
-#include "ei.h"
-#include "erl_interface.h"
-#include "eicode.h"
-#include "m_i__s.h"
-#include "m__s.h"
-
-#ifdef __WIN32__
-typedef struct {
- long tv_sec;
- long tv_usec;
-} MyTimeval;
-#else
-typedef struct timeval MyTimeval;
-#endif
-static void my_gettimeofday(MyTimeval *tv);
-static void showtime(MyTimeval *start, MyTimeval *stop);
-static void usage(void);
-static void done(int r);
-
-#define HOSTNAMESZ 255
-#define NODENAMESZ 512
-#define INBUFSZ 10
-#define OUTBUFSZ 0
-#define MAXTRIES 5
-
-static char *progname;
-
-/* main */
-#ifdef VXWORKS
-int c_server(int argc, char **argv)
-#else
-int main(int argc, char **argv)
-#endif
-{
- struct hostent *hp;
- MyTimeval start, stop;
- int i, fd, ires, tries;
- CORBA_Environment *env;
- char *this_node_name = NULL;
- char *peer_node = NULL;
- char *cookie = NULL;
- char host[HOSTNAMESZ + 1];
- char this_node[NODENAMESZ + 1];
- erlang_msg msg;
- int status, loop;
-
-#ifdef __WIN32__
- WORD wVersionRequested;
- WSADATA wsaData;
-
- wVersionRequested = MAKEWORD(2, 0);
-
- if (WSAStartup(wVersionRequested, &wsaData) != 0) {
- fprintf(stderr, "Could not load winsock2 v2.0 compatible DLL");
- exit(1);
- }
-#endif
-
- progname = argv[0];
- host[HOSTNAMESZ] = '\0';
- if (gethostname(host, HOSTNAMESZ + 1) < 0) {
- fprintf(stderr, "Can't find own hostname\n");
- done(1);
- }
- if ((hp = gethostbyname(host)) == 0) {
- fprintf(stderr, "Can't get ip address for host %s\n", host);
- done(1);
- }
- for (i = 1; i < argc; i++) {
- if (strcmp(argv[i], "-help") == 0) {
- usage();
- done(0);
- } else if (strcmp(argv[i], "-this-node-name") == 0) {
- i++;
- this_node_name = argv[i];
- } else if (strcmp(argv[i], "-peer-node") == 0) {
- i++;
- peer_node = argv[i];
- } else if (strcmp(argv[i], "-cookie") == 0) {
- i++;
- cookie = argv[i];
- } else {
- fprintf(stderr, "Error : invalid argument \"%s\"\n", argv[i]);
- usage();
- done(1);
- }
- }
-
- if (this_node_name == NULL || peer_node == NULL || cookie == NULL) {
- fprintf(stderr, "Error: missing option\n");
- usage();
- done(1);
- }
-
- /* Behead hostname at first dot */
- for (i=0; host[i] != '\0'; i++) {
- if (host[i] == '.') { host[i] = '\0'; break; }
- }
- sprintf(this_node, "%s@%s", this_node_name, host);
-
- fprintf(stderr, "c_server: this node: \"%s\"\n", this_node);
- fprintf(stderr, "c_server: peer node: \"%s\"\n", peer_node);
-
- /* initialize erl_interface */
- erl_init(NULL, 0);
-
- for (tries = 0; tries < MAXTRIES; tries++) {
- /* connect to peer node */
- ires = erl_connect_xinit(host, this_node_name, this_node,
- (struct in_addr *)*hp->h_addr_list,
- cookie, 0);
- fprintf(stderr, "c_server: erl_connect_xinit(): %d\n", ires);
-
- fd = erl_connect(peer_node);
- fprintf(stderr, "c_server: erl_connect(): %d\n", fd);
- if (fd >= 0)
- break;
- fprintf(stderr, "c_server: cannot connect, retrying\n");
- }
- if (fd < 0) {
- fprintf(stderr, "c_server: cannot connect, exiting\n");
- done(1);
- }
- env = CORBA_Environment_alloc(INBUFSZ, OUTBUFSZ);
- env->_fd = fd;
-
- status = 1;
- loop = 1;
- my_gettimeofday(&start);
- while (status >= 0 && loop > 0) {
- status = ei_receive_encoded(env->_fd, &env->_inbuf, &env->_inbufsz,
- &msg, &env->_iin);
- switch(status) {
- case ERL_SEND:
- case ERL_REG_SEND:
- /* get result */
- m_i__switch(NULL, env);
- switch(env->_major) {
- case CORBA_NO_EXCEPTION:
- break;
- case CORBA_SYSTEM_EXCEPTION:
- fprintf(stderr, "Request failure, reason : %s\n",
- (char *) CORBA_exception_value(env));
- CORBA_exception_free(env);
- break;
- default: /* Should not happen */
- CORBA_exception_free(env);
- break;
- }
- /* send back result data */
- if (env->_iout > 0)
- ei_send_encoded(env->_fd, &env->_caller, env->_outbuf,
- env->_iout);
- loop = 0;
- break;
- case ERL_TICK:
- break;
- default:
- if (status < 0) {
- fprintf(stderr, "Status negative: %d\n", status);
- loop = 0;
- }
- break;
- }
- }
- my_gettimeofday(&stop);
- showtime(&start, &stop);
-
- erl_close_connection(fd);
-
- CORBA_free(env->_inbuf);
- CORBA_free(env->_outbuf);
- CORBA_free(env);
- if (status < 0)
- done(-status);
- else
- done(0);
-}
-
-static void usage()
-{
- fprintf(stderr, "Usage: %s [-help] -this-node-name <name> "
- "-peer-node <nodename> -cookie <cookie>\n", progname);
- fprintf(stderr, "Example:\n %s -this-node-name kalle "
- "-peer-node olle@home -cookie oa678er\n", progname);
-}
-
-static void done(int r)
-{
-#ifdef __WIN32__
- WSACleanup();
-#endif
- exit(r);
-}
-
-static void showtime(MyTimeval *start, MyTimeval *stop)
-{
- MyTimeval elapsed;
-
- elapsed.tv_sec = stop->tv_sec - start->tv_sec;
- elapsed.tv_usec = stop->tv_usec - start->tv_usec;
- while (elapsed.tv_usec < 0) {
- elapsed.tv_sec -= 1;
- elapsed.tv_usec += 1000000;
- }
- fprintf(stderr,"%ld.%06ld seconds\n",elapsed.tv_sec, elapsed.tv_usec);
-}
-
-
-
-static void my_gettimeofday(MyTimeval *tv)
-#ifdef __WIN32__
-#define EPOCH_JULIAN_DIFF 11644473600i64
-{
- SYSTEMTIME t;
- FILETIME ft;
- LONGLONG lft;
-
- GetSystemTime(&t);
- SystemTimeToFileTime(&t, &ft);
- memcpy(&lft, &ft, sizeof(lft));
- tv->tv_usec = (long) ((lft / 10i64) % 1000000i64);
- tv->tv_sec = (long) ((lft / 10000000i64) - EPOCH_JULIAN_DIFF);
-}
-#elif defined VXWORKS
-{
- int rate = sysClkRateGet(); /* Ticks per second */
- unsigned long ctick = tickGet();
- tv->tv_sec = ctick / rate; /* secs since reboot */
- tv->tv_usec = ((ctick - (tv->tv_sec * rate))*1000000)/rate;
-}
-#else
-{
- gettimeofday(tv, NULL);
-}
-#endif
diff --git a/lib/ic/test/erl_client_c_server_proto_SUITE_data/callbacks.c b/lib/ic/test/erl_client_c_server_proto_SUITE_data/callbacks.c
deleted file mode 100644
index bed1dc2dd3..0000000000
--- a/lib/ic/test/erl_client_c_server_proto_SUITE_data/callbacks.c
+++ /dev/null
@@ -1,611 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 2004-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include <stdio.h>
-#include <stdlib.h>
-#ifndef __WIN32__
-# include <unistd.h>
-#endif
-#include <string.h>
-#include <ctype.h>
-#include <ic.h>
-#include <erl_interface.h>
-#include <ei.h>
-#include "m_i__s.h"
-
-
-
-/* OK */
-
-void my_void_test(CORBA_Object oe_obj,
- CORBA_Environment *oe_env)
-{
- /* printf("void test !\n"); */
-}
-
-m_i_void_test__rs* m_i_void_test__cb(CORBA_Object oe_obj,
- CORBA_Environment *oe_env)
-{
- return (m_i_void_test__rs*) (my_void_test);
-}
-
-
-
-/* OK */
-
-void my_long_test(CORBA_Object oe_obj,
- long* a,
- long* b,
- long* c,
- CORBA_Environment *oe_env)
-{
- /* printf("long test !\n"); */
-}
-
-
-m_i_long_test__rs* m_i_long_test__cb(CORBA_Object oe_obj,
- long* a,
- long* b,
- long* c,
- CORBA_Environment *oe_env)
-{
- *a = *b;
- *c = *b;
- return (m_i_long_test__rs*) (my_long_test);
-}
-
-/* OK */
-
-void my_longlong_test(CORBA_Object oe_obj,
- CORBA_long_long* a,
- CORBA_long_long* b,
- CORBA_long_long* c,
- CORBA_Environment *oe_env)
-{
- /* printf("long test !\n"); */
-}
-
-m_i_longlong_test__rs* m_i_longlong_test__cb(CORBA_Object oe_obj,
- CORBA_long_long* a,
- CORBA_long_long* b,
- CORBA_long_long* c,
- CORBA_Environment *oe_env)
-{
- *a = *b;
- *c = *b;
- return (m_i_longlong_test__rs*) (my_longlong_test);
-}
-
-/* OK */
-void my_ulong_test(CORBA_Object oe_obj,
- unsigned long* a,
- unsigned long* b,
- unsigned long* c,
- CORBA_Environment *oe_env)
-{
- /* printf("ulong test !\n"); */
-}
-
-m_i_ulong_test__rs* m_i_ulong_test__cb(CORBA_Object oe_obj,
- unsigned long* a,
- unsigned long* b,
- unsigned long* c,
- CORBA_Environment *oe_env)
-{
- *a = *b;
- *c = *b;
- return (m_i_ulong_test__rs*) (my_ulong_test);
-}
-
-/* OK */
-void my_ulonglong_test(CORBA_Object oe_obj,
- CORBA_unsigned_long_long* a,
- CORBA_unsigned_long_long* b,
- CORBA_unsigned_long_long* c,
- CORBA_Environment *oe_env)
-{
- /* printf("ulong test !\n"); */
-}
-
-m_i_ulonglong_test__rs* m_i_ulonglong_test__cb(CORBA_Object oe_obj,
- CORBA_unsigned_long_long* a,
- CORBA_unsigned_long_long* b,
- CORBA_unsigned_long_long* c,
- CORBA_Environment *oe_env)
-{
- *a = *b;
- *c = *b;
- return (m_i_ulonglong_test__rs*) (my_ulonglong_test);
-}
-
-m_i_ushort_test__rs* m_i_ushort_test__cb(CORBA_Object oe_obj,
- unsigned short* a,
- unsigned short* b,
- unsigned short* c,
- CORBA_Environment *oe_env)
-{
- *a = *b;
- *c = *b;
- return (m_i_ushort_test__rs*) NULL;
-}
-
-
-/* OK */
-void my_double_test(CORBA_Object oe_obj,
- double* a,
- double* b,
- double* c,
- CORBA_Environment *oe_env)
-{
- /* printf("double test !\n"); */
-}
-
-m_i_double_test__rs* m_i_double_test__cb(CORBA_Object oe_obj,
- double* a,
- double* b,
- double* c,
- CORBA_Environment *oe_env)
-{
- *a = *b;
- *c = *b;
- return (m_i_double_test__rs*) (my_double_test);
-}
-
-/* OK */
-m_i_char_test__rs* m_i_char_test__cb(CORBA_Object oe_obj,
- char* a,
- char* b,
- char* c,
- CORBA_Environment *oe_env)
-{
- m_i_char_test__rs* rs = NULL;
-
- *a = *b;
- *c = *b;
- return rs;
-}
-
-
-/* OK */
-m_i_wchar_test__rs* m_i_wchar_test__cb(CORBA_Object oe_obj,
- CORBA_wchar* a,
- CORBA_wchar* b,
- CORBA_wchar* c,
- CORBA_Environment *oe_env)
-{
- m_i_wchar_test__rs* rs = NULL;
-
- *a = *b;
- *c = *b;
- return rs;
-}
-
-/* OK */
-m_i_octet_test__rs* m_i_octet_test__cb(CORBA_Object oe_obj,
- char* a,
- char* b,
- char* c,
- CORBA_Environment *oe_env)
-{
- m_i_octet_test__rs* rs = NULL;
-
- *a = *b;
- *c = *b;
- return rs;
-}
-
-/* OK */
-m_i_bool_test__rs* m_i_bool_test__cb(CORBA_Object oe_obj,
- CORBA_boolean* a,
- CORBA_boolean* b,
- CORBA_boolean* c,
- CORBA_Environment *oe_env)
-{
- m_i_bool_test__rs* rs = NULL;
-
- *a = *b;
- *c = *b;
- return rs;
-}
-
-/* OK */
-void my_struct_test(CORBA_Object oe_obj,
- m_b* a,
- m_b* b,
- m_b* c,
- CORBA_Environment *oe_env)
-{
- /* printf("struct test !\n"); */
-}
-
-m_i_struct_test__rs* m_i_struct_test__cb(CORBA_Object oe_obj,
- m_b* a,
- m_b* b,
- m_b* c,
- CORBA_Environment *oe_env)
-{
- *a = *b;
- *c = *b;
- return (m_i_struct_test__rs*) (my_struct_test);
-}
-
-/* OK */
-m_i_struct2_test__rs* m_i_struct2_test__cb(CORBA_Object oe_obj,
- m_es* a,
- m_es* b,
- m_es* c,
- CORBA_Environment *oe_env)
-{
- m_i_struct2_test__rs* rs = NULL;
-
- *a = *b;
- *c = *b;
- return rs;
-}
-
-/* OK */
-/* XXX Commented out
-m_i_struct3_test__rs* m_i_struct3_test__cb(CORBA_Object oe_obj,
- m_simple* a,
- m_simple* b,
- m_simple* c,
- CORBA_Environment *oe_env)
-{
- m_i_struct3_test__rs* rs = NULL;
- *a = *b;
- *c = *b;
- return rs;
-}
-*/
-
-/* OK */
-m_i_seq1_test__rs* m_i_seq1_test__cb(CORBA_Object oe_obj,
- m_bseq** a,
- m_bseq* b,
- m_bseq** c,
- CORBA_Environment *oe_env)
-{
- m_i_seq1_test__rs* rs = NULL;
-
- *a = b;
- *c = b;
- return rs;
-}
-
-
-/* OK */
-m_i_seq2_test__rs* m_i_seq2_test__cb(CORBA_Object oe_obj,
- m_aseq** a,
- m_aseq* b,
- m_aseq** c,
- CORBA_Environment *oe_env)
-{
- m_i_seq2_test__rs* rs = NULL;
-
- *a = b;
- *c = b;
- return rs;
-}
-
-/* OK */
-m_i_seq3_test__rs* m_i_seq3_test__cb(CORBA_Object oe_obj,
- m_lseq** a,
- m_lseq* b,
- m_lseq** c,
- CORBA_Environment *oe_env)
-{
- m_i_seq3_test__rs* rs = NULL;
-
- *a = b;
- *c = b;
- return rs;
-}
-
-/* OK */
-m_i_seq4_test__rs* m_i_seq4_test__cb(CORBA_Object oe_obj,
- m_ssstr3** a,
- m_ssstr3* b,
- m_ssstr3** c,
- CORBA_Environment *oe_env)
-{
- m_i_seq4_test__rs* rs = NULL;
-
- *a = b;
- *c = b;
- return rs;
-}
-
-/* OK */
-m_i_seq5_test__rs* m_i_seq5_test__cb(CORBA_Object oe_obj,
- m_ssarr3** a,
- m_ssarr3* b,
- m_ssarr3** c,
- CORBA_Environment *oe_env)
-{
- m_i_seq5_test__rs* rs = NULL;
-
- *a = b;
- *c = b;
- return rs;
-}
-
-/* OK */
-m_i_array1_test__rs* m_i_array1_test__cb(CORBA_Object oe_obj,
- m_arr1 a,
- m_arr1 b,
- m_arr1 c,
- CORBA_Environment *oe_env)
-{
- int i;
- m_i_array1_test__rs* rs = NULL;
-
- for (i = 0; i < 500; i++) {
- a[i] = b[i];
- c[i] = b[i];
- }
- return rs;
-}
-
-/* OK */
-m_i_array2_test__rs* m_i_array2_test__cb(CORBA_Object oe_obj,
- m_dd a,
- m_dd b,
- m_dd c,
- CORBA_Environment *oe_env)
-{
- int i,j;
- m_i_array2_test__rs* rs = NULL;
-
- for (i = 0; i < 2; i++)
- for (j = 0; j < 3; j++) {
- a[i][j] = b[i][j];
- c[i][j] = b[i][j];
- }
- return rs;
-}
-
-
-/* OK */
-m_i_enum_test__rs* m_i_enum_test__cb(CORBA_Object oe_obj,
- m_fruit* a,
- m_fruit* b,
- m_fruit* c,
- CORBA_Environment *oe_env)
-{
- m_i_enum_test__rs* rs = NULL;
-
- *a = *b;
- *c = *b;
- return rs;
-}
-
-/* OK */
-m_i_string1_test__rs* m_i_string1_test__cb(CORBA_Object oe_obj,
- char ** a,
- char * b,
- char ** c,
- CORBA_Environment *oe_env)
-{
- m_i_string1_test__rs* rs = NULL;
-
- /*printf("\nString in ------> %s\n\n",b);*/
- *a = b;
- *c = b;
- return rs;
-}
-
-/* OK */
-m_i_string2_test__rs* m_i_string2_test__cb(CORBA_Object oe_obj,
- m_sseq** a,
- m_sseq* b,
- m_sseq** c,
- CORBA_Environment *oe_env)
-{
- m_i_string2_test__rs* rs = NULL;
-
- *a = b;
- *c = b;
- return rs;
-}
-
-/* OK */
-m_i_string3_test__rs* m_i_string3_test__cb(CORBA_Object oe_obj,
- char ** a,
- char * b,
- char ** c,
- CORBA_Environment *oe_env)
-{
- m_i_string3_test__rs* rs = NULL;
-
- *a = b;
- *c = b;
- return rs;
-}
-
-m_i_string4_test__rs* m_i_string4_test__cb(CORBA_Object oe_obj,
- m_strRec** a,
- m_strRec* b,
- m_strRec** c,
- CORBA_Environment *oe_env)
-{
- *a = b;
- *c = b;
-
- return (m_i_string4_test__rs*) NULL;
-}
-
-/* OK */
-m_i_wstring1_test__rs* m_i_wstring1_test__cb(CORBA_Object oe_obj,
- CORBA_wchar ** a,
- CORBA_wchar * b,
- CORBA_wchar ** c,
- CORBA_Environment *oe_env)
-{
- int tmp;
- m_i_wstring1_test__rs* rs = NULL;
-
- /*printf("\nString in ------> %s\n\n",b);*/
-
- for(tmp = 0; tmp < 5; tmp++)
- fprintf(stderr,"\np[%d] = %ld\n", tmp, b[tmp]);
- *a = b;
- *c = b;
- return rs;
-}
-
-
-/* OK */
-m_i_pid_test__rs* m_i_pid_test__cb(CORBA_Object oe_obj,
- erlang_pid* a,
- erlang_pid* b,
- erlang_pid* c,
- CORBA_Environment *oe_env)
-{
- m_i_pid_test__rs* rs = NULL;
-
- *a = *b;
- *c = *b;
- return rs;
-}
-
-/* OK */
-m_i_port_test__rs* m_i_port_test__cb(CORBA_Object oe_obj,
- erlang_port* a,
- erlang_port* b,
- erlang_port* c,
- CORBA_Environment *oe_env)
-{
- m_i_port_test__rs* rs = NULL;
-
- strcpy((*a).node,(*b).node);
- (*a).id = (*b).id;
- (*a).creation = 0;
-
- strcpy((*c).node,(*b).node);
- (*c).id = (*b).id;
- (*c).creation = 0;
- return rs;
-}
-
-/* OK */
-m_i_ref_test__rs* m_i_ref_test__cb(CORBA_Object oe_obj,
- erlang_ref* a,
- erlang_ref* b,
- erlang_ref* c,
- CORBA_Environment *oe_env)
-{
-
- m_i_ref_test__rs* rs = NULL;
-
- strcpy((*a).node,(*b).node);
- /*(*a).id = (*b).id;*/
- (*a).len = (*b).len;
- (*a).n[0] = (*b).n[0];
- (*a).n[1] = (*b).n[1];
- (*a).n[2] = (*b).n[2];
- (*a).creation = 0;
-
- strcpy((*c).node,(*b).node);
- /*(*c).id = (*b).id;*/
- (*c).len = (*b).len;
- (*c).n[0] = (*b).n[0];
- (*c).n[1] = (*b).n[1];
- (*c).n[2] = (*b).n[2];
- (*c).creation = 0;
- return rs;
-}
-
-/* OK */
-m_i_term_test__rs* m_i_term_test__cb(CORBA_Object oe_obj,
- ETERM** a,
- ETERM** b,
- ETERM** c,
- CORBA_Environment *oe_env)
-{
- m_i_term_test__rs* rs = NULL;
-
- *a = *b;
- *c = *b;
- return rs;
-}
-
-m_i_typedef_test__rs* m_i_typedef_test__cb(CORBA_Object oe_obj,
- long* a,
- ETERM** b,
- erlang_port* c,
- ETERM** d ,
- erlang_port* e,
- CORBA_Environment *oe_env)
-{
- m_i_typedef_test__rs* rs = NULL;
-
- *d = *b;
- strcpy((*e).node,(*c).node);
- (*e).id = (*c).id;
- (*e).creation = 0;
- *a = 4711;
- return rs;
-}
-
-/* OK */
-m_i_inline_sequence_test__rs* m_i_inline_sequence_test__cb(
- CORBA_Object oe_obj,
- m_s** a,
- m_s* b,
- m_s** c,
- CORBA_Environment *oe_env)
-{
- m_i_inline_sequence_test__rs* rs = NULL;
-
- *a = b;
- *c = b;
- return rs;
-}
-
-/* OK */
-m_i_term_sequence_test__rs* m_i_term_sequence_test__cb(
- CORBA_Object oe_obj,
- m_etseq** a,
- m_etseq* b,
- m_etseq** c,
- CORBA_Environment *oe_env)
-{
- m_i_term_sequence_test__rs* rs = NULL;
-
- *a = b;
- *c = b;
- return rs;
-}
-
-
-/* OK */
-m_i_term_struct_test__rs* m_i_term_struct_test__cb(CORBA_Object oe_obj,
- m_et* a,
- m_et* b,
- m_et* c,
- CORBA_Environment *oe_env)
-{
- m_i_term_struct_test__rs* rs = NULL;
-
- *a = *b;
- *c = *b;
- return rs;
-}
-
diff --git a/lib/ic/test/erl_client_c_server_proto_SUITE_data/erl_c_test.idl b/lib/ic/test/erl_client_c_server_proto_SUITE_data/erl_c_test.idl
deleted file mode 100644
index ef9556dd42..0000000000
--- a/lib/ic/test/erl_client_c_server_proto_SUITE_data/erl_c_test.idl
+++ /dev/null
@@ -1,175 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 2004-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-#include "erlang.idl"
-
-
-const short TestConst = 1;
-
-module m {
-
- const short TestConst = 2;
-
- struct b {
- long l;
- char c;
- };
-
- struct simple {
- long l;
- b b_t;
- };
-
- enum fruit {orange, banana, apple, peach, pear};
-
- typedef sequence<long> lseq;
-
- typedef sequence<b> bseq;
-
- struct a {
- long l;
- bseq y;
- double d;
- };
-
- typedef sequence<a> aseq;
-
- typedef sequence<string> sseq;
- typedef string str;
- typedef long myLong;
-
- typedef long arr1[500], dd[2][3];
-
- typedef erlang::term apa;
- typedef erlang::port banan;
-
- typedef sequence<erlang::term> etseq;
-
- struct s {
- long l;
- sequence<long> sl;
- };
-
- struct es {
- fruit f;
- myLong l;
- };
-
- struct et {
- erlang::term e;
- long l;
- };
-
-
- typedef sequence<char> str1;
- typedef string<12> str2;
- typedef char str3[3];
-
- typedef sequence<string> sstr3; // sequence of string
- typedef sequence<sstr3> ssstr3; // sequence of sequences of strings
-
- typedef long arr3[3]; // array of long
- typedef sequence<arr3> sarr3; // sequence of array
- typedef sequence<sarr3> ssarr3; // sequence of sequnces of arrays of strings
-
- struct strRec{
- boolean bb;
- string str4;
- long str7[3][2];
- sequence<char> str5;
- string<12> str6;
- str3 str8;
- str2 str9;
- str1 str10;
- };
-
-
- struct dyn {
- long l;
- sequence<long> sl;
- };
- typedef dyn arr2[1][2];
-
-
- interface i {
-
- const short TestConst = 3;
-
- //arr2 suck(in arr2 x, out arr2 y );
-
- ///////////////////////////////// attribute long l;
-
- // simple types
- void void_test();
- long long_test(in long a, out long a1);
- long long longlong_test(in long long a, out long long a1);
- unsigned short ushort_test(in unsigned short a, out unsigned short a1);
- unsigned long ulong_test(in unsigned long a, out unsigned long a1);
- unsigned long long ulonglong_test(in unsigned long long a, out unsigned long long a1);
- double double_test(in double a, out double a1);
- char char_test(in char a, out char a1);
- wchar wchar_test(in wchar a, out wchar a1);
- octet octet_test(in octet a, out octet a1);
- boolean bool_test(in boolean a, out boolean a1);
-
- // Seq. and struct tests
- b struct_test(in b a, out b a1);
- es struct2_test(in es a, out es a1);
- //simple struct3_test(in simple x, out simple y);
- bseq seq1_test(in bseq a, out bseq a1);
- aseq seq2_test(in aseq a, out aseq a1);
- lseq seq3_test(in lseq a, out lseq a1);
- ssstr3 seq4_test(in ssstr3 a, out ssstr3 a1);
- ssarr3 seq5_test(in ssarr3 a, out ssarr3 a1);
-
- // Array tests
- arr1 array1_test(in arr1 a, out arr1 a1);
- dd array2_test(in dd a, out dd a1);
-
- // enum test
- fruit enum_test(in fruit a, out fruit a1);
-
- // string tests
- string string1_test(in string a, out string a1);
- wstring wstring1_test(in wstring a, out wstring a1);
- sseq string2_test(in sseq a, out sseq a1);
- str string3_test(in str a, out str a1);
- strRec string4_test(in strRec a, out strRec a1);
-
- // Special erlang types
- erlang::pid pid_test(in erlang::pid a, out erlang::pid a1);
- erlang::port port_test(in erlang::port a, out erlang::port a1);
- erlang::ref ref_test(in erlang::ref a, out erlang::ref a1);
- erlang::term term_test(in erlang::term a, out erlang::term a1);
-
- // typedef test
- long typedef_test(in apa a, in banan b, out apa a1, out banan b1);
-
- // inlined seq. test
- s inline_sequence_test(in s a, out s a1);
-
- // term seq. test
- etseq term_sequence_test(in etseq a, out etseq a1);
- // term struct test
- et term_struct_test(in et a, out et a1);
-
- };
-
-};
diff --git a/lib/ic/test/erl_client_c_server_proto_SUITE_data/erl_client.erl b/lib/ic/test/erl_client_c_server_proto_SUITE_data/erl_client.erl
deleted file mode 100644
index 5fe80cdd7a..0000000000
--- a/lib/ic/test/erl_client_c_server_proto_SUITE_data/erl_client.erl
+++ /dev/null
@@ -1,332 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(erl_client).
-
--export([void_test/2, long_test/2, longlong_test/2, ushort_test/2,
- ulong_test/2, ulonglong_test/2, double_test/2, char_test/2,
- wchar_test/2, octet_test/2, bool_test/2, struct_test/2,
- struct2_test/2, seq1_test/2, seq2_test/2, seq3_test/2,
- seq4_test/2, seq5_test/2, array1_test/2, array2_test/2,
- enum_test/2, string1_test/2, wstring1_test/2, string2_test/2,
- string3_test/2, string4_test/2, pid_test/2, port_test/2,
- ref_test/2, term_test/2, typedef_test/2,
- inline_sequence_test/2, term_sequence_test/2,
- term_struct_test/2
-
-]).
-
--include("m.hrl").
--include("m_i.hrl").
--include("oe_erl_c_test.hrl").
-
-%%b
-void_test(Node, Timeout) ->
- Ret = m_i:void_test({olsson, Node}, Timeout),
- Ret == void. % XXX Not documented
-%%e
-
-%%b
-long_test(Node, Timeout) ->
- In = max_long(),
- {Ret, Out} = m_i:long_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-longlong_test(Node, Timeout) ->
- In = 65537,
- {Ret, Out} = m_i:longlong_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-ushort_test(Node, Timeout) ->
- In = max_ushort(),
- {Ret, Out} = m_i:ushort_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-ulong_test(Node, Timeout) ->
- In = max_ulong(),
- {Ret, Out} = m_i:ulong_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-ulonglong_test(Node, Timeout) ->
- In = 65537,
- {Ret, Out} = m_i:ulonglong_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-double_test(Node, Timeout) ->
- In = 37768.93,
- {Ret, Out} = m_i:double_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-char_test(Node, Timeout) ->
- In = 80,
- {Ret, Out} = m_i:char_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-wchar_test(Node, Timeout) ->
- In = 4097,
- {Ret, Out} = m_i:wchar_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-octet_test(Node, Timeout) ->
- In = 255,
- {Ret, Out} = m_i:octet_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-bool_test(Node, Timeout) ->
- In = false,
- {Ret, Out} = m_i:bool_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-struct_test(Node, Timeout) ->
- In = #m_b{l = max_long(), c = $a},
- {Ret, Out} = m_i:struct_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-struct2_test(Node, Timeout) ->
- In = #m_es{ f = banana, l = max_long()},
- {Ret, Out} = m_i:struct2_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-seq1_test(Node, Timeout) ->
- B1 = #m_b{l = max_long(), c = $a},
- B2 = #m_b{l = min_long(), c = $b},
- In = [B1, B2],
- {Ret, Out} = m_i:seq1_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-seq2_test(Node, Timeout) ->
- B = #m_b{l = max_long(), c = $a},
- A = #m_a{l = min_long(), y = [B, B], d = 4711.31},
- In = [A, A, A],
- {Ret, Out} = m_i:seq2_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-seq3_test(Node, Timeout) ->
- In = [max_long(), min_long(), max_long()],
- {Ret, Out} = m_i:seq3_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-seq4_test(Node, Timeout) ->
- In = [["hej", "hopp"], ["ditt", "feta", "nylle"]],
- {Ret, Out} = m_i:seq4_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-seq5_test(Node, Timeout) ->
- Arr3 = mk_array(3, max_long()),
- In = [[Arr3, Arr3], [Arr3, Arr3, Arr3]],
- {Ret, Out} = m_i:seq5_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-array1_test(Node, Timeout) ->
- In = mk_array(500, min_long()),
- {Ret, Out} = m_i:array1_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-array2_test(Node, Timeout) ->
- In = mk_array(2, mk_array(3, min_long())),
- {Ret, Out} = m_i:array2_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-enum_test(Node, Timeout) ->
- In = banana,
- {Ret, Out} = m_i:enum_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-string1_test(Node, Timeout) ->
- In = "Die Paula muss beim Tango immer weinen",
- {Ret, Out} = m_i:string1_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-wstring1_test(Node, Timeout) ->
- In = [1047| "ie Paula muss beim Tango immer weinen"],
- {Ret, Out} = m_i:wstring1_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-string2_test(Node, Timeout) ->
- In = ["Lass doch die Blumen,", "Konrad!"],
- {Ret, Out} = m_i:string2_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-string3_test(Node, Timeout) ->
- In = "Seeman, lass uns freuden!",
- {Ret, Out} = m_i:string3_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-string4_test(Node, Timeout) ->
-
- In = #m_strRec{
- bb = true,
- str4 = "Paula war zu Hause in ihrem Stadtchen als die beste Tanzerin"
- "bekannt",
- str7 = mk_array(3, mk_array(2, max_long())),
- str5 = [$a, $b, $c, $d, $e, $f],
- str6 = "123456789012",
- str8 = {$x, $y, $x},
- str9 = "123456789012",
- str10 = [$a, $b, $c, $d, $e, $f]
- },
- {Ret, Out} = m_i:string4_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-pid_test(Node, Timeout) ->
- In = self(),
- {Ret, Out} = m_i:pid_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-port_test(Node, Timeout) ->
- In = get(port_test_port),
- {Ret, Out} = m_i:port_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-ref_test(Node, Timeout) ->
- In = make_ref(),
- {Ret, Out} = m_i:ref_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-term_test(Node, Timeout) ->
- In = {[a, b], 17, kalle},
- {Ret, Out} = m_i:term_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-typedef_test(Node, Timeout) ->
- In1 = {nisse, [1, 2], olsson},
- In2 = get(port_test_port),
- {Ret, Out1, Out2} = m_i:typedef_test({olsson, Node}, Timeout, In1, In2),
- %% XXX Should check that Ret is an integer.
- (Out1 == In1) and (Out2 == In2).
-%%e
-
-%%b
-inline_sequence_test(Node, Timeout) ->
- In = #m_s{l = min_long(), sl = [max_long(), min_long()]},
- {Ret, Out} = m_i:inline_sequence_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-term_sequence_test(Node, Timeout) ->
- In = lists:duplicate(17, {nisse, [1, 2], {kalle, olsson}}),
- {Ret, Out} = m_i:term_sequence_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-%%b
-term_struct_test(Node, Timeout) ->
- In = #m_et{e = {nisse, ["abcde"], {kalle, olsson}}, l = 4711},
- {Ret, Out} = m_i:term_struct_test({olsson, Node}, Timeout, In),
- (Ret == In) and (Out == In).
-%%e
-
-
-%% Locals
-
-mk_array(Es) ->
- list_to_tuple(Es).
-
-mk_array(N, E) ->
- mk_array(lists:duplicate(N, E)).
-
-%% max_short() ->
-%% power_of_two(15) - 1.
-max_long() ->
- power_of_two(31) - 1.
-max_longlong() ->
- power_of_two(63) - 1.
-max_ushort() ->
- power_of_two(16) - 1.
-max_ulong() ->
- power_of_two(32) - 1.
-max_ulonglong() ->
- power_of_two(64) - 1.
-
-%% min_short() ->
-%% -power_of_two(15).
-min_long() ->
- -power_of_two(31).
-%% min_longlong() ->
-%% -power_of_two(63).
-%% min_ushort() ->
-%% 0.
-%% min_ulong() ->
-%% 0.
-%% min_ulonglong() ->
-%% 0.
-
-power_of_two(N) ->
- round(math:pow(2, N)).
-
diff --git a/lib/ic/test/erl_client_c_server_proto_SUITE_data/my.c b/lib/ic/test/erl_client_c_server_proto_SUITE_data/my.c
deleted file mode 100644
index aff03253d6..0000000000
--- a/lib/ic/test/erl_client_c_server_proto_SUITE_data/my.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 2004-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include "ic.h"
-#include "m_i.h"
-
-int my_prepare_request_decoding(CORBA_Environment *env)
-{
- return oe_prepare_request_decoding(env);
-}
-
-int my_prepare_reply_encoding(CORBA_Environment *env)
-{
- return oe_prepare_reply_encoding(env);
-}
-
-
-
diff --git a/lib/ic/test/ic.cover b/lib/ic/test/ic.cover
deleted file mode 100644
index 5a679c8b6f..0000000000
--- a/lib/ic/test/ic.cover
+++ /dev/null
@@ -1,2 +0,0 @@
-{incl_app,ic,details}.
-
diff --git a/lib/ic/test/ic.spec b/lib/ic/test/ic.spec
deleted file mode 100644
index 22905dcee4..0000000000
--- a/lib/ic/test/ic.spec
+++ /dev/null
@@ -1 +0,0 @@
-{suites,"../ic_test",all}.
diff --git a/lib/ic/test/ic.spec.vxworks b/lib/ic/test/ic.spec.vxworks
deleted file mode 100644
index b15260ab70..0000000000
--- a/lib/ic/test/ic.spec.vxworks
+++ /dev/null
@@ -1,2 +0,0 @@
-{topcase, {dir, "../ic_test"}}.
-{skip,{ic_pp_SUITE,"Uses gcc"}}.
diff --git a/lib/ic/test/ic_SUITE.erl b/lib/ic/test/ic_SUITE.erl
deleted file mode 100644
index 42c1dbb415..0000000000
--- a/lib/ic/test/ic_SUITE.erl
+++ /dev/null
@@ -1,894 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%%----------------------------------------------------------------------
-%%% Purpose : Test suite for the IDL compiler
-%%%----------------------------------------------------------------------
-
--module(ic_SUITE).
--include_lib("common_test/include/ct.hrl").
-
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2]).
-
-
--include_lib("orber/src/orber_ifr.hrl").
--include_lib("orber/src/ifr_objects.hrl").
--include_lib("orber/include/ifr_types.hrl").
-
-
-%% The type cases
--export([ type_norm/1]).
-
-%% The syntax case
--export([]).
--export([syntax1/1, syntax2/1, syntax3/1, syntax4/1, syntax5/1, syntax6/1]).
-
-%% The constant cases
--export([]).
--export([const_norm/1, const_bad_tk/1, const_bad_type/1]).
--export([const_bad_comb/1]).
-
-%% The union cases
--export([]).
--export([union_norm/1, union_type/1, union_mult_err/1, union_case_mult/1]).
--export([union_default/1]).
-
-%% The enum cases
--export([]).
--export([enum_norm/1]).
-
-%% The struct cases
--export([]).
--export([struct_norm/1]).
-
-%% The oneway cases
--export([]).
--export([oneway_norm/1, oneway_raises/1, oneway_out/1, oneway_void/1, oneway_followed/1]).
-
-%% The attributes cases
--export([]).
--export([attr_norm/1]).
-
-%% The raises registration case
--export([raises_reg/1]).
-
-
-%% The typeID case
-
-%% general stuff
--export([]).
--export([typeid/1, undef_id/1, dir/1, nasty_names/1, coss/1, mult_ids/1]).
--export([forward/1, include/1, app_test/1]).
-
-%% inheritance stuff
--export([ inherit_norm/1, inherit_warn/1, inherit_err/1]).
-
-%% Standard options to the ic compiler, NOTE unholy use of OutDir
-
--define(OUT(X), filename:join([proplists:get_value(priv_dir, Config), gen, to_list(X)])).
-
-
-%% Top of cases
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [app_test, {group, const}, {group, union},
- {group, enum}, {group, attr}, {group, type},
- {group, struct}, {group, general}, {group, inherit},
- {group, oneway}, {group, syntax}, raises_reg].
-
-groups() ->
- [{const, [],
- [const_norm, const_bad_tk, const_bad_type,
- const_bad_comb]},
- {union, [],
- [union_norm, union_type, union_mult_err,
- union_case_mult, union_default]},
- {enum, [], [enum_norm]}, {struct, [], [struct_norm]},
- {general, [],
- [typeid, undef_id, mult_ids, forward, include,
- nasty_names]},
- {inherit, [],
- [inherit_norm, inherit_warn, inherit_err]},
- {oneway, [],
- [oneway_norm, oneway_out, oneway_raises, oneway_void,
- oneway_followed]},
- {attr, [], [attr_norm]}, {type, [], [type_norm]},
- {syntax, [],
- [syntax1, syntax2, syntax3, syntax4, syntax5, syntax6]}].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-app_test(_Config) ->
- ok=test_server:app_test(ic),
- ok.
-
-%%---------------------------------------------------------------------
-%%
-%% Test of constant expressions.
-%%
-
-%% Checks normal constant types and values
-const_norm(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(const_norm),
- File = filename:join(DataDir, c_norm),
- ok = ic:gen(File, stdopts(OutDir)),
- {ok, []} = ic:gen(File, stdopts(OutDir)++[silent2]),
- ok = compile(OutDir, const_norm_files()),
- ok.
-
-%% Checks when the constant value doesn't match the declared type
-const_bad_tk(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(slask),
- File = filename:join(DataDir, c_err1),
- error = ic:gen(File, stdopts(OutDir)),
- {error, [], R} =
- ic:gen(File, stdopts(OutDir)++[silent2]),
- check_errors(18, bad_tk_match, R),
- ok.
-
-%% Checks operands of ops are of correct type
-const_bad_type(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(slask),
- File = filename:join(DataDir, c_err2),
- error = ic:gen(File, stdopts(OutDir)),
- {error, [], R} =
- ic:gen(File, stdopts(OutDir)++[silent2]),
- check_errors(4, bad_type, R),
- ok.
-
-%% Checks operands of ops are of conflicting types
-const_bad_comb(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(slask),
- File = filename:join(DataDir, c_err3),
- error = ic:gen(File, stdopts(OutDir)),
- {error, [], R} =
- ic:gen(File, stdopts(OutDir)++[silent2]),
- check_errors(3, bad_type_combination, R),
- ok.
-
-
-%% Checks that normal union declarations works.
-union_norm(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(union_norm),
- File = filename:join(DataDir, u_norm),
-
- ok = ic:gen(File, stdopts(OutDir)),
- {ok, []} = ic:gen(File, stdopts(OutDir)++[silent2]),
- ok = compile(OutDir, union_norm_files()),
- ok.
-
-
-%% Checks OTP-2007
-%% Checks that default cases are correct in type code.
-union_default(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(union_default),
- File = filename:join(DataDir, u_default),
-
- ok = ic:gen(File, stdopts(OutDir)),
- {ok, []} = ic:gen(File, stdopts(OutDir)++[silent2]),
- ok = compile(OutDir, union_default_files(), [load]),
- TkList = i1:oe_get_interface(),
- check_label("op0", 0, TkList),
- check_label("op1", 1, TkList),
- check_label("op2", 2, TkList),
- check_label("op3", -1, TkList),
- ok.
-
-check_label(Id, N, List) ->
- case lists:keysearch(Id, 1, List) of
- {value, {_, {{_, _, _, _, D, L}, _, _}}} ->
- if D /= N ->
- test_server:fail({bad_default_num, D, N});
- D /= -1 ->
- case lists:nth(D+1, L) of
- T when element(1, T) == default ->
- ok;
- _Que ->
- test_server:fail({bad_default_list, D, L})
- end;
- true ->
- %% D = N = -1, just check that there is no default label
- case lists:keysearch(default, 1, L) of
- false ->
- ok;
- _ ->
- test_server:fail({bad_default_label, D, L})
- end
- end;
- _ ->
- test_server:fail({'no_such_op!', Id, List})
- end.
-
-%% Checks that errors are detected. Check that mismatch between case
-%% value and declared discriminator type is detected.
-union_type(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(slask),
- File = filename:join(DataDir, u_type),
- error = ic:gen(File, stdopts(OutDir)),
- {error, [], R} =
- ic:gen(File, stdopts(OutDir)++[silent2]),
- check_errors(28, bad_case_type, R),
- ok.
-
-
-%% Check that multiple declared declarators are caught.
-%% Also check that if the discriminator is an enum, then the enum name
-%% must not be used as a declarator in the union switch (declarator
-%% as opposed to label).
-union_mult_err(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(slask),
- File = filename:join(DataDir, u_mult),
- error = ic:gen(File, stdopts(OutDir)),
- {error, [], R} =
- ic:gen(File, stdopts(OutDir)++[silent2]),
- check_errors(8, multiply_defined, R),
- ok.
-
-%% Check that multiply defined case labels are found in the
-%% correct order
-union_case_mult(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(slask),
- File = filename:join(DataDir, u_case_mult),
- error = ic:gen(File, stdopts(OutDir)),
- {error, [], R} =
- ic:gen(File, stdopts(OutDir)++[silent2]),
- check_errors(7, multiple_cases, R),
- ok.
-
-
-%%--------------------------------------------------------------------
-%%
-%% Enum cases
-%%
-%%Checks that normal enum declarations works.
-enum_norm(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(enum_norm),
- File = filename:join(DataDir, enum),
-
- ok = ic:gen(File, stdopts(OutDir)),
- {ok, []} = ic:gen(File, stdopts(OutDir)++[silent2]),
- ok = compile(OutDir, enum_norm_files()),
- ok.
-
-
-%%--------------------------------------------------------------------
-%%
-%% Struct cases
-%%
-%% Checks that normal struct declarations works.
-struct_norm(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(struct_norm),
- File = filename:join(DataDir, struct),
-
- ok = ic:gen(File, stdopts(OutDir)),
- {ok, []} = ic:gen(File, stdopts(OutDir)++[silent2]),
- ok = compile(OutDir, struct_norm_files()),
- Mod = ridiculous_name_to_avoid_clash_svenne,
- TestFile = filename:join(OutDir, Mod),
- ok = gen_struct_file(TestFile, Mod),
- ok = compile(OutDir, [Mod], [load]),
-%% {ok, Mod, []} = compile:file(TestFile,
-%% [{i, OutDir}, {outdir, OutDir},
-%% return, load]),
- ok = Mod:test(),
- ok.
-
-
-%%--------------------------------------------------------------------
-%%
-%% General cases
-%%
-
-%% coss (add sometimes, takes 440 seconds!)
-%% Check that type id's are generated correctly
-typeid(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(typeid),
- File = filename:join(DataDir, typeid),
-
- ok = ic:gen(File, stdopts(OutDir)),
- {ok, []} = ic:gen(File, stdopts(OutDir)++[silent2]),
- ok = compile(OutDir, typeid_files(), [load]),
- "IDL:I1:1.0" = 'I1':'typeID'(),
- "IDL:M1/I1:1.0" = 'M1_I1':'typeID'(),
- "IDL:M2/M1/I1:1.0" = 'M2_M1_I1':'typeID'(),
- "IDL:M3/M2/M1/I1:1.0" = 'M3_M2_M1_I1':'typeID'(),
- ok.
-
-
-%%% This test case is removed because there's no way to test this from
-%%% an automated test suite.
-%% Check that relative directories work, absolute is used in
-%% all other cases in the suite.
-dir(Config) when is_list(Config) ->
- ok;
-dir(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
-
- %% Needs a unique directory (any better way?)
- OutDir = mk_unique("oe_the_dir"),
-
- %% More unique names
- File = filename:join(DataDir, mk_unique("oe_the_file")),
- Const = mk_unique("oe_the_constant"),
- Mod = list_to_atom(File),
- Func = list_to_atom(Const),
-
- %% Generate a unique IDL file with a single constant
- gen_file(File, Const),
-
- ok = ic:gen(File, stdopts(OutDir)),
- ok = compile(OutDir, [load]),
- 19955 = Mod:Func(),
- {ok, []} = ic:gen(File, stdopts(OutDir)++[silent2]),
- ok = compile(OutDir, [load]),
- 19955 = Mod:Func(),
-
- ok = ic:gen(File),
-%%% ok = compile(".", [load]),
- ok.
-
-%% Check that various undefied id's are detected correctly
-undef_id(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(slask),
- File = filename:join(DataDir, undef_id),
- error = ic:gen(File, stdopts(OutDir)),
- {error, [], R} =
- ic:gen(File, stdopts(OutDir)++[silent2]),
- check_errors(16, tk_not_found, R),
- ok.
-
-%% Check that multiply defined ids are caught.
-mult_ids(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(slask),
- File = filename:join(DataDir, mult_ids),
- error = ic:gen(File, stdopts(OutDir)),
- {error, [], R} =
- ic:gen(File, stdopts(OutDir)++[silent2]),
- check_errors(22, multiply_defined, R),
- ok.
-
-
-%% Check that various nasty names can be generated.
-%% Try to provoke name clashes and name conflicts with
-%% Erlang and IDL
-nasty_names(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(nasty_names),
- File = filename:join(DataDir, nasty),
-
- ok = ic:gen(File, stdopts(OutDir)),
- {ok, []} = ic:gen(File, stdopts(OutDir)++[silent2]),
- ok = compile(OutDir, nasty_names_files(), [load]),
- ok.
-
-%% Check that the Coss standard specification works.
-coss(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(coss),
- File = filename:join(DataDir, 'Coss'),
-
- ok = ic:gen(File, stdopts(OutDir)),
- {ok, [_W1]} = ic:gen(File, stdopts(OutDir)++[silent2]),
- ok = compile(OutDir, []),
- ok.
-
-%% Check that forward declaratios work.
-forward(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(forward),
- File = filename:join(DataDir, forward),
-
- ok = ic:gen(File, stdopts(OutDir)),
- {ok, []} = ic:gen(File, stdopts(OutDir)++[silent2]),
- ok = compile(OutDir, forward_files(), [load]),
- ok.
-
-%% Check that various undefied id's are detected correctly
-include(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(slask),
- File = filename:join(DataDir, include),
- error = ic:gen(File, stdopts(OutDir)++[{preproc_flags,"-I" ++ DataDir}]),
- {error, [], R} =
- ic:gen(File, stdopts(OutDir)++[{preproc_flags,"-I" ++ DataDir},silent2]),
- case lists:map(fun(D) ->
- filename:rootname(filename:basename(element(3, D)))
- end,
- lists:sort(R)) of
- ["include",
- "include2",
- "include2",
- "include3"] ->
- ok;
- RRR ->
- test_server:fail({bad_include_file, RRR})
- end,
- ok.
-
-
-
-
-%%--------------------------------------------------------------------
-%%
-%% Inhertit cases
-%%
-
-%% Checks that normal inheritance works.
-inherit_norm(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(inherit_norm),
- File = filename:join(DataDir, inherit),
-
- ok = ic:gen(File, stdopts(OutDir)),
- {ok, _Ws} = ic:gen(File, stdopts(OutDir)++[silent2]),
- ok = compile(OutDir, inherit_norm_files(), [load]),
-
- %% Now check constant values:
- 9 = m1_I1:c1(),
-
- 9 = m1_I2:c1(),
- 14 = m1_I2:c2(),
- 27 = m1_I2:c3(),
-
- 50 = m1_I3:c1(),
- 14 = m1_I3:c2(),
- 27 = m1_I3:c3(),
- 91 = m1_I3:c4(),
- 100 = m1_I3:c5(),
- ok.
-
-%% Check that various inheritance shadowing is detected
-inherit_warn(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(slask),
- File = filename:join(DataDir, inherit_warn),
- ok = ic:gen(File, stdopts(OutDir)),
- {ok, R} =
- ic:gen(File, stdopts(OutDir)++[silent2]),
- check_errors(7, inherit_name_shadow, R),
- ok.
-
-%% Check that various inheritance errors is detected
-inherit_err(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(slask),
- File = filename:join(DataDir, inherit_err),
- error = ic:gen(File, stdopts(OutDir)),
- {error, _Ws, R} =
- ic:gen(File, stdopts(OutDir)++[silent2]),
- check_errors(21, inherit_name_collision, R),
- ok.
-
-
-%% Checks that normal oneway operations works.
-oneway_norm(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(oneway_norm),
- File = filename:join(DataDir, one),
-
- ok = ic:gen(File, stdopts(OutDir)),
- ok = compile(OutDir, oneway_norm_files(), [load]),
- {ok, []} = ic:gen(File, stdopts(OutDir)++[silent2]),
- ok = compile(OutDir, oneway_norm_files(), [load]),
- ok.
-
-%% Check that non-void oneways are detected.
-oneway_void(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(slask),
- File = filename:join(DataDir, one_void),
- error = ic:gen(File, stdopts(OutDir)),
- {error, [], R} =
- ic:gen(File, stdopts(OutDir)++[silent2]),
- check_errors(2, bad_oneway_type, R),
- ok.
-
-%% Check that oneways cannot raise exceptions.
-oneway_raises(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(slask),
- File = filename:join(DataDir, one_raises),
- error = ic:gen(File, stdopts(OutDir)),
- {error, [], R} =
- ic:gen(File, stdopts(OutDir)++[silent2]),
- check_errors(3, oneway_raises, R),
- ok.
-
-%% Check that illegal out parameters are detected
-oneway_out(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(slask),
- File = filename:join(DataDir, one_out),
- error = ic:gen(File, stdopts(OutDir)),
- {error, [], R} =
- ic:gen(File, stdopts(OutDir)++[silent2]),
- check_errors(2, oneway_outparams, R),
- ok.
-
-%% Checks that normal oneways, followed by other operations.
-oneway_followed(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(oneway_followed),
- File = filename:join(DataDir, one_followed),
-
- ok = ic:gen(File, stdopts(OutDir)),
- ok = compile(OutDir, oneway_followed_files(), [load]),
- {ok, []} = ic:gen(File, stdopts(OutDir)++[silent2]),
- ok = compile(OutDir, oneway_followed_files(), [load]),
- ok.
-
-
-%% Checks that normal attr operations works.
-attr_norm(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(attr_norm),
- File = filename:join(DataDir, attr),
-
- ok = ic:gen(File, stdopts(OutDir)),
- ok = compile(OutDir, attr_norm_files(), [load]),
- {ok, []} = ic:gen(File, stdopts(OutDir)++[silent2]),
- ok = compile(OutDir, attr_norm_files(), [load]),
- ok.
-
-
-%% Checks all types are handled.
-type_norm(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(type_norm),
- File = filename:join(DataDir, type),
-
- ok = ic:gen(File, stdopts(OutDir)),
- ok = compile(OutDir, type_norm_files(), [load]),
- {ok, []} = ic:gen(File, stdopts(OutDir)++[silent2]),
- ok = compile(OutDir, type_norm_files(), [load]),
- ok.
-
-syntax1(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(slask),
- File = filename:join(DataDir, syntax1),
-
- error = ic:gen(File, stdopts(OutDir)),
- {error, [], R} =
- ic:gen(File, stdopts(OutDir)++[silent2]),
- check_errors(1, parse_error, R),
- ok.
-
-syntax2(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(slask),
- File = filename:join(DataDir, syntax2),
-
- error = ic:gen(File, stdopts(OutDir)),
- {error, [], R} =
- ic:gen(File, stdopts(OutDir)++[silent2]),
- check_errors(1, parse_error, R),
- ok.
-
-syntax3(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(slask),
- File = filename:join(DataDir, syntax3),
-
- error = ic:gen(File, stdopts(OutDir)),
- {error, [], R} =
- ic:gen(File, stdopts(OutDir)++[silent2]),
- check_errors(1, parse_error, R),
- ok.
-
-syntax4(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(slask),
- File = filename:join(DataDir, syntax4),
-
- error = ic:gen(File, stdopts(OutDir)),
- {error, [], R} =
- ic:gen(File, stdopts(OutDir)++[silent2]),
- check_errors(1, parse_error, R),
- ok.
-
-syntax5(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(slask),
- File = filename:join(DataDir, syntax5),
-
- error = ic:gen(File, stdopts(OutDir)),
- {error, [], R} =
- ic:gen(File, stdopts(OutDir)++[silent2]),
- check_errors(1, parse_error, R),
- ok.
-
-syntax6(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(slask),
- File = filename:join(DataDir, syntax6),
-
- error = ic:gen(File, stdopts(OutDir)),
- {error, [], R} =
- ic:gen(File, stdopts(OutDir)++[silent2]),
- check_errors(1, parse_error, R),
- ok.
-
-
-
-%%--------------------------------------------------------------------
-%%
-%% Checks RAISES to be registered under IFR operation registration
-%% ( OTP-2102 )
-%%
-
-%% Check that exceptions are really registered to operations.
-raises_reg(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(raises_reg_check),
- File = filename:join(DataDir, raises_reg),
-
- ok = ic:gen(File, stdopts(OutDir)),
- {ok, []} = ic:gen(File, stdopts(OutDir)++[silent2]),
- ok = compile(OutDir, raises_reg_files(), [load]),
-
- set_up('oe_raises_reg'),
-
- io:format("~n##### Starting the test case #####~n"),
- io:format("Checking for existance of exception : ~s~n",["IDL:Raises_RegModule/Exception_1:1.0"]),
- raises_register_check("IDL:Raises_RegModule/R_R/op:1.0","IDL:Raises_RegModule/Exception_1:1.0"),
-
- io:format("Checking for existance of exception : ~s~n",["IDL:Raises_RegModule/Exception_2:1.0"]),
- raises_register_check("IDL:Raises_RegModule/R_R/op:1.0","IDL:Raises_RegModule/Exception_2:1.0"),
-
- io:format("Checking for existance of exception : ~s~n",["IDL:Raises_RegModule/XXXXXXXX:1.0"]),
- raises_register_check("IDL:Raises_RegModule/R_R/op:1.0","IDL:RaisesModule/XXXXXXXX:1.0"),
-
- set_down('oe_raises_reg'),
-
- ok.
-
-set_up(Register) ->
- io:format("Setting up.....~n"),
- mnesia:stop(),
- mnesia:delete_schema([node()]),
- mnesia:create_schema([node()]),
- mnesia:start(),
- orber:install([node()]),
- orber:start(),
- io:format("Running OE_register()~n"),
- Register:'oe_register'().
-
-set_down(Register) ->
- io:format("Running OE_unregister()~n"),
- Register:'oe_unregister'(),
- io:format("Setting down.....~n"),
- orber:stop(),
- orber:uninstall(),
- mnesia:stop(),
- mnesia:delete_schema([node()]).
-
-
-raises_register_check(OpId,ExcId) ->
- case is_valid_exc(OpId,ExcId) of
- true ->
- ok; % Because right exception where found,
- % the test succeeds for normal cases.
- false ->
- ok; % Because the exception tested, is not
- % registered for that operation.
- FailReason ->
- test_server:fail({FailReason, OpId, ExcId})
- % Because the test descovered errors in a previous
- % stage, or no exceptions where registered att all.
- % ( This testcase assumes that operations to be
- % checked allways raise excption(s) )
- end.
-
-is_valid_exc(OpId,ExcId) ->
- OE_IFR = orber_ifr:find_repository(),
- OpDef = orber_ifr:'Repository_lookup_id'(OE_IFR,OpId),
- ExcDefList = orber_ifr:get_exceptions(OpDef),
- case ExcDefList of
- [] ->
- no_exceptions_registered;
- _ ->
- ExcDef=orber_ifr:lookup_id(OE_IFR,ExcId),
- lists:member(ExcDef,ExcDefList)
- end.
-
-%%--------------------------------------------------------------------
-%%
-%% Utilities
-
-
-stdopts(OutDir) ->
- [{outdir, OutDir},{maxerrs, infinity}].
-
-mk_unique(Prefix) ->
- {A,B,C} = now(),
- Prefix++"_"++integer_to_list(A)++"_"++integer_to_list(B)++"_"++
- integer_to_list(C).
-
-gen_file(File, Const) ->
- {ok, Fd} = file:open(File++".idl", [write]),
- io:format(Fd, "interface ~s {~n", [File]),
- io:format(Fd, " const long ~s = 19955;~n", [Const]),
- io:format(Fd, "};~n", []),
- file:close(Fd).
-
-
-%% Compile all files in Dir. Used for checking that valid Erlang has
-%% been generated.
-%%compile(Dir) ->
-%% compile(Dir, []).
-%%compile(Dir, Opts) ->
-%% {ok, Cwd} = file:get_cwd(),
-%% catch do_compile(Dir, Opts),
-%% file:set_cwd(Cwd).
-
-%%do_compile(Dir, Opts) ->
-%% ok = file:set_cwd(Dir),
-%% up_to_date = ts_make_erl:all(Opts),
-%% ok.
-
-compile(Dir, Files) ->
- compile(Dir, Files, []).
-
-compile(Dir, Files, Opts) ->
- {ok, Cwd} = file:get_cwd(),
- file:set_cwd(Dir),
- io:format("Changing to ~p~n", [Dir]),
- case catch do_compile(Files, Opts) of
- ok ->
- file:set_cwd(Cwd);
- Err ->
- file:set_cwd(Cwd),
- test_server:fail(Err)
- end.
-
-do_compile([], _Opts) -> ok;
-do_compile([F | Fs], Opts) ->
- io:format("Compiling ~p", [F]),
- case compile:file(F, Opts) of
- ok ->
- io:format(" ok~n", []),
- do_load(F, Opts),
- do_compile(Fs, Opts);
- {ok, _} ->
- io:format(" ok~n", []),
- do_load(F, Opts),
- do_compile(Fs, Opts);
- {ok, _, _} ->
- io:format(" ok~n", []),
- do_load(F, Opts),
- do_compile(Fs, Opts);
- Err ->
- io:format(" error: ~p~n", [Err]),
- Err
- end.
-
-do_load(File, Opts) ->
- case lists:member(load, Opts) of
- true ->
- io:format("Loading file ~p", [File]),
- code:purge(File),
- R = code:load_abs(File),
- io:format("Loaded: ~p", [R]);
- false ->
- ok
- end.
-
-
-%% Check that ErrList consists of exactly Num errors of type ErrType
-check_errors(Num, ErrType, ErrList) ->
- Num = length(ErrList),
- lists:foreach(fun(T) ->
- case catch element(1, element(4, T)) of
- ErrType -> ok;
- Else ->
- test_server:fail({bad, ErrType, Else})
- end end, ErrList).
-
-to_list(X) when is_atom(X) -> atom_to_list(X);
-to_list(X) -> X.
-
-
-%% File must be an atom
-gen_struct_file(File, Mod) ->
-
- {ok, Fd} = file:open(to_list(File)++".erl", [write]),
- io:format(Fd, "~n", []),
- io:format(Fd, "-module(~p).~n", [Mod]),
- io:format(Fd, "-export([test/0]).~n", []),
- io:format(Fd, "-include(\"oe_struct.hrl\").~n", []),
- io:format(Fd, "test() ->~n", []),
- io:format(Fd, " A = #'S1'{a=99, b=$a, s=\"123456789\"},~n", []),
- io:format(Fd, " B = #'S2'{a=9, b=#'S2_S3'{a=1, b=9, b1=5, c=$2},~n", []),
- io:format(Fd, " c=[#'S1'{a=1}, #'S1'{a=2}],~n", []),
- io:format(Fd,
-" c2=[#'S1'{a=2}, #'S1'{a=3}, #'S1'{a=2}, #'S1'{a=3}]},~n", []),
- io:format(Fd, " C = #'S2_S3'{a=11, b=999, b1=19},~n", []),
- io:format(Fd, " D = #s4{a=7},~n", []),
- io:format(Fd, " E = {1, #'U1_S5'{a=3}},~n", []),
- io:format(Fd, " F = {2, {$b, #'U1_U2_s6'{a=6, b=false}}},~n", []),
- io:format(Fd, " ok.~n", []),
- file:close(Fd).
-
-
-union_norm_files() -> ['oe_u_norm'].
-union_default_files() -> ['oe_u_default', i1].
-
-typeid_files() -> ['oe_typeid', 'M3_M2_M1_I1', 'M2_M1_I1', 'M1_I1', 'I1'].
-
-struct_norm_files() -> ['oe_struct'].
-oneway_norm_files() -> ['oe_one', 'I1'].
-oneway_followed_files() -> ['oe_one_followed', 'I1'].
-nasty_names_files() -> ['oe_nasty', 'I2', 'I1'].
-
-inherit_norm_files() -> [m1_I3, m1_I2, m1_I1, 'oe_inherit', 'I4', 'I3',
- 'I2', 'I1'].
-
-forward_files() -> [i1, 'oe_forward'].
-enum_norm_files() -> ['oe_enum'].
-const_norm_files() -> ['oe_c_norm'].
-attr_norm_files() -> ['oe_attr', 'I1', 'I2'].
-type_norm_files() -> ['oe_type'].
-
-raises_reg_files() -> ['oe_raises_reg'].
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/ic/test/ic_SUITE_data/Corba.idl b/lib/ic/test/ic_SUITE_data/Corba.idl
deleted file mode 100644
index 6b81132500..0000000000
--- a/lib/ic/test/ic_SUITE_data/Corba.idl
+++ /dev/null
@@ -1,1013 +0,0 @@
-// This file contains OMG IDL from CORBA V2.0, July 1995.
-// Includes IDL for CORBA Core
-// (Interface Repository, ORB Interface, Basic Object Adapter Interface)
-// and CORBA Interoperability (IOP, GIOP, IIOP, and DCE CIOP modules)
-
-// Complete OMG IDL for Interface Repository starts on pg 6-42, CORBA V2.0 July 1995
-// IRObject interface described on pg 6-9 CORBA V2.0, July 1995
-// Contained interface: pg 6-11 CORBA V2, 7-95
-// Container interface: pg 6-12 thru 6-15 CORBA V2, 7-95
-// IDLType interface: pg 6-15 CORBA V2, 7-95
-// Repository interface: pg 6-16 CORBA V2, 7-95
-// ModuleDef interface: pg 6-17 CORBA V2, 7-95
-// ConstantDef interface: pg 6-18 CORBA V2, 7-95
-// TypeDef interface: pg 6-19 CORBA V2, 7-95
-// StructDef interface: pg 6-19 CORBA V2, 7-95
-// UnionDef interface: pg 6-19 CORBA V2, 7-95
-// EnumDef interface: pg 6-20 CORBA V2, 7-95
-// AliasDef interface: pg 6-21 CORBA V2, 7-95
-// PrimitiveDef interface: pg 6-21 CORBA V2, 7-95
-// StringDef interface: pg 6-22 CORBA V2, 7-95
-// SequenceDef interface: pg 6-22 CORBA V2, 7-95
-// ArrayDef interface: pg 6-23 CORBA V2, 7-95
-// ExceptionDef interface: pg 6-24 CORBA V2, 7-95
-// AttributeDef interface: pg 6-25 CORBA V2, 7-95
-// OperationDef interface: pg 6-26 CORBA V2, 7-95
-// InterfaceDef interface: pg 6-28 CORBA V2, 7-95
-// TypeCode interface (PIDL): pg 6-34 CORBA V2, 7-95
-// ORB interface: pg 6-40 CORBA V2, 7-95
-
-#ifndef __CORBA_IDL
-#define __CORBA_IDL
-
-// #pragma prefix "omg.org"
-module CORBA {
-
- interface TypeCode;
- typedef string Identifier;
- typedef string ScopedName;
- typedef string RepositoryId;
-
- /*
- * start of section added by Christian Blum
- */
-
- typedef enum new_type {NO,USER,SYSTEM_EXCEPTION} exception_type;
-
- /**
- * no definition for this type
- */
- interface ImplementationDef
- {
- };
-
- /**
- * no definition for this type
- */
- //interface Principal
- struct Principal
- {
- string str;
- };
-
- /**
- * no definition for this type
- */
- interface Environment
- {
-
- };
-
- typedef unsigned long Flags;
- typedef unsigned long Status;
-
- struct NamedValue // PIDL
- {
- Identifier name; // argument name
- any argument; // argument
- long len; // length/count of argument value
- Flags arg_modes; // argument mode flags
-
- };
-
- typedef sequence<NamedValue> NVList; /* C */
-
- interface Request // PIDL
- {
-
- Status add_arg (
- in Identifier name, // argument name
- in TypeCode arg_type, // argument datatype
- // in void * value, // argument value to be added
- in any value_LOOK_AT_SOURCE, // changed by blum
- in long len, // length/count of argument value
- in Flags arg_flags // argument flags
- );
-
- Status invoke (
- in Flags invoke_flags // invocation flags
- );
-
- Status delete ();
- Status send (
- in Flags invoke_flags // invocation flags
- );
-
- Status get_response (
- in Flags response_flags // response flags
- );
-
- };
-
-
- interface Context // PIDL
- {
-
- Status set_one_value (
- in Identifier prop_name, // property name to add
- in string value // property value to add
- );
-
- Status set_values (
- in NVList values // property values to be changed
- );
-
- Status get_values (
- in Identifier start_scope, // search scope
- in Flags op_flags, // operation flags
- in Identifier prop_name, // name of property(s) to retrieve
- out NVList values // requested property(s)
- );
-
- Status delete_values (
- in Identifier prop_name // name of property(s) to delete
- );
-
- Status create_child (
- in Identifier ctx_name, // name of context object
- out Context child_ctx // newly created context object
- );
-
- Status delete (
- in Flags del_flags // flags controlling deletion
- );
-
- };
-
- /*
- * end of section added by Christian Blum
- */
-
-
- enum DefinitionKind {
- dk_none, dk_all,
- dk_Attribute, dk_Constant, dk_Exception, dk_Interface,
- dk_Module, dk_Operation, dk_Typedef,
- dk_Alias, dk_Struct, dk_Union, dk_Enum,
- dk_Primitive, dk_String, dk_Sequence, dk_Array,
- dk_Repository
- };
-
-
- interface IRObject {
- // read interface
- readonly attribute DefinitionKind def_kind;
-
- // write interface
- void destroy ();
- };
-
-
-
- typedef string VersionSpec;
-
- interface Contained;
- interface Repository;
- interface Container;
-
- interface Contained : IRObject {
- // read/write interface
-
- attribute RepositoryId id;
- attribute Identifier name;
- attribute VersionSpec version;
-
- // read interface
-
- readonly attribute Container defined_in;
- readonly attribute ScopedName absolute_name;
- readonly attribute Repository containing_repository;
-
- struct Description {
- DefinitionKind kind;
- any value;
- };
-
- Description describe ();
-
- // write interface
-
- void move (
- in Container new_container,
- in Identifier new_name,
- in VersionSpec new_version
- );
- };
-
-
- interface ModuleDef;
- interface ConstantDef;
- interface IDLType;
- interface StructDef;
- interface UnionDef;
- interface EnumDef;
- interface AliasDef;
- interface InterfaceDef;
- typedef sequence <InterfaceDef> InterfaceDefSeq;
-
- typedef sequence <Contained> ContainedSeq;
-
- struct StructMember {
- Identifier name;
- TypeCode type;
- IDLType type_def;
- };
- typedef sequence <StructMember> StructMemberSeq;
-
- struct UnionMember {
- Identifier name;
- any label;
- TypeCode type;
- IDLType type_def;
- };
- typedef sequence <UnionMember> UnionMemberSeq;
-
- typedef sequence <Identifier> EnumMemberSeq;
-
- interface Container : IRObject {
- // read interface
-
- Contained lookup ( in ScopedName search_name);
-
- ContainedSeq contents (
- in DefinitionKind limit_type,
- in boolean exclude_inherited
- );
-
- ContainedSeq lookup_name (
- in Identifier search_name,
- in long levels_to_search,
- in DefinitionKind limit_type,
- in boolean exclude_inherited
- );
-
- struct Description {
- Contained contained_object;
- DefinitionKind kind;
- any value;
- };
-
- typedef sequence<Description> DescriptionSeq;
-
- DescriptionSeq describe_contents (
- in DefinitionKind limit_type,
- in boolean exclude_inherited,
- in long max_returned_objs
- );
-
- // write interface
-
- ModuleDef create_module (
- in RepositoryId id,
- in Identifier name,
- in VersionSpec version
- );
-
- ConstantDef create_constant (
- in RepositoryId id,
- in Identifier name,
- in VersionSpec version,
- in IDLType type,
- in any value
- );
-
- StructDef create_struct (
- in RepositoryId id,
- in Identifier name,
- in VersionSpec version,
- in StructMemberSeq members
- );
-
- UnionDef create_union (
- in RepositoryId id,
- in Identifier name,
- in VersionSpec version,
- in IDLType discriminator_type,
- in UnionMemberSeq members
- );
-
- EnumDef create_enum (
- in RepositoryId id,
- in Identifier name,
- in VersionSpec version,
- in EnumMemberSeq members
- );
-
- AliasDef create_alias (
- in RepositoryId id,
- in Identifier name,
- in VersionSpec version,
- in IDLType original_type
- );
-
- InterfaceDef create_interface (
- in RepositoryId id,
- in Identifier name,
- in VersionSpec version,
- in InterfaceDefSeq base_interfaces
- );
- };
-
-
-
- interface IDLType : IRObject {
- readonly attribute TypeCode type;
- };
-
-
-
- interface PrimitiveDef;
- interface StringDef;
- interface SequenceDef;
- interface ArrayDef;
-
- enum PrimitiveKind {
- pk_null, pk_void, pk_short, pk_long, pk_ushort, pk_ulong,
- pk_float, pk_double, pk_boolean, pk_char, pk_octet,
- pk_any, pk_TypeCode, pk_Principal, pk_string, pk_objref
- };
-
- interface Repository : Container {
- // read interface
-
- Contained lookup_id (in RepositoryId search_id);
-
- PrimitiveDef get_primitive (in PrimitiveKind kind);
-
- // write interface
-
- StringDef create_string (in unsigned long bound);
-
- SequenceDef create_sequence (
- in unsigned long bound,
- in IDLType element_type
- );
-
- ArrayDef create_array (
- in unsigned long length,
- in IDLType element_type
- );
- };
-
-
- interface ModuleDef : Container, Contained {
- };
-
- struct ModuleDescription {
- Identifier name;
- RepositoryId id;
- RepositoryId defined_in;
- VersionSpec version;
- };
-
-
- interface ConstantDef : Contained {
- readonly attribute TypeCode type;
- attribute IDLType type_def;
- attribute any value;
- };
-
- struct ConstantDescription {
- Identifier name;
- RepositoryId id;
- RepositoryId defined_in;
- VersionSpec version;
- TypeCode type;
- any value;
- };
-
-
- interface TypedefDef : Contained, IDLType {
- };
-
- struct TypeDescription {
- Identifier name;
- RepositoryId id;
- RepositoryId defined_in;
- VersionSpec version;
- TypeCode type;
- };
-
-
- interface StructDef : TypedefDef {
- attribute StructMemberSeq members;
- };
-
-
- interface UnionDef : TypedefDef {
- readonly attribute TypeCode discriminator_type;
- attribute IDLType discriminator_type_def;
- attribute UnionMemberSeq members;
- };
-
-
- interface EnumDef : TypedefDef {
- attribute EnumMemberSeq members;
- };
-
-
- interface AliasDef : TypedefDef {
- attribute IDLType original_type_def;
- };
-
-
- interface PrimitiveDef: IDLType {
- readonly attribute PrimitiveKind kind;
- };
-
-
- interface StringDef : IDLType {
- attribute unsigned long bound;
- };
-
-
- interface SequenceDef : IDLType {
- attribute unsigned long bound;
- readonly attribute TypeCode element_type;
- attribute IDLType element_type_def;
- };
-
- interface ArrayDef : IDLType {
- attribute unsigned long length;
- readonly attribute TypeCode element_type;
- attribute IDLType element_type_def;
- };
-
-
- interface ExceptionDef : Contained {
- readonly attribute TypeCode type;
- attribute StructMemberSeq members;
- };
- struct ExceptionDescription {
- Identifier name;
- RepositoryId id;
- RepositoryId defined_in;
- VersionSpec version;
- TypeCode type;
- };
-
-
-
- enum AttributeMode {ATTR_NORMAL, ATTR_READONLY};
-
- interface AttributeDef : Contained {
- readonly attribute TypeCode type;
- attribute IDLType type_def;
- attribute AttributeMode mode;
- };
-
- struct AttributeDescription {
- Identifier name;
- RepositoryId id;
- RepositoryId defined_in;
- VersionSpec version;
- TypeCode type;
- AttributeMode mode;
- };
-
-
-
- enum OperationMode {OP_NORMAL, OP_ONEWAY};
-
- enum ParameterMode {PARAM_IN, PARAM_OUT, PARAM_INOUT};
- struct ParameterDescription {
- Identifier name;
- TypeCode type;
- IDLType type_def;
- ParameterMode mode;
- };
- typedef sequence <ParameterDescription> ParDescriptionSeq;
-
- typedef Identifier ContextIdentifier;
- typedef sequence <ContextIdentifier> ContextIdSeq;
-
- typedef sequence <ExceptionDef> ExceptionDefSeq;
- typedef sequence <ExceptionDescription> ExcDescriptionSeq;
-
- interface OperationDef : Contained {
- readonly attribute TypeCode result;
- attribute IDLType result_def;
- attribute ParDescriptionSeq params;
- attribute OperationMode mode;
- attribute ContextIdSeq contexts;
- attribute ExceptionDefSeq exceptions;
- };
-
- struct OperationDescription {
- Identifier name;
- RepositoryId id;
- RepositoryId defined_in;
- VersionSpec version;
- TypeCode result;
- OperationMode mode;
- ContextIdSeq contexts;
- ParDescriptionSeq parameters;
- ExcDescriptionSeq exceptions;
- };
-
-
-
- typedef sequence <RepositoryId> RepositoryIdSeq;
- typedef sequence <OperationDescription> OpDescriptionSeq;
- typedef sequence <AttributeDescription> AttrDescriptionSeq;
-
- interface InterfaceDef : Container, Contained, IDLType {
- // read/write interface
-
- attribute InterfaceDefSeq base_interfaces;
-
- // read interface
-
- boolean is_a (in RepositoryId interface_id);
-
- struct FullInterfaceDescription {
- Identifier name;
- RepositoryId id;
- RepositoryId defined_in;
- VersionSpec version;
- OpDescriptionSeq operations;
- AttrDescriptionSeq attributes;
- RepositoryIdSeq base_interfaces;
- TypeCode type;
- };
-
- FullInterfaceDescription describe_interface();
-
- // write interface
-
- AttributeDef create_attribute (
- in RepositoryId id,
- in Identifier name,
- in VersionSpec version,
- in IDLType type,
- in AttributeMode mode
- );
-
- OperationDef create_operation (
- in RepositoryId id,
- in Identifier name,
- in VersionSpec version,
- in IDLType result,
- in OperationMode mode,
- in ParDescriptionSeq params,
- in ExceptionDefSeq exceptions,
- in ContextIdSeq contexts
- );
- };
-
- struct InterfaceDescription {
- Identifier name;
- RepositoryId id;
- RepositoryId defined_in;
- VersionSpec version;
- RepositoryIdSeq base_interfaces;
- };
-
-
-
- enum TCKind {
- tk_null, tk_void,
- tk_short, tk_long, tk_ushort, tk_ulong,
- tk_float, tk_double, tk_boolean, tk_char,
- tk_octet, tk_any, tk_TypeCode, tk_Principal, tk_objref,
- tk_struct, tk_union, tk_enum, tk_string,
- tk_sequence, tk_array, tk_alias, tk_except
- };
-
- interface TypeCode { // PIDL
- exception Bounds {};
- exception BadKind {};
-
- // for all TypeCode kinds
- boolean equal (in TypeCode tc);
- TCKind kind ();
-
- // for tk_objref, tk_struct, tk_union, tk_enum, tk_alias, and tk_except
- RepositoryId id () raises (BadKind);
-
- // for tk_objref, tk_struct, tk_union, tk_enum, tk_alias, and tk_except
- Identifier name () raises (BadKind);
-
- // for tk_struct, tk_union, tk_enum, and tk_except
- unsigned long member_count () raises (BadKind);
- Identifier member_name (in unsigned long index) raises (BadKind, Bounds);
-
- // for tk_struct, tk_union, and tk_except
- TypeCode member_type (in unsigned long index) raises (BadKind, Bounds);
-
- // for tk_union
- any member_label (in unsigned long index) raises (BadKind, Bounds);
- TypeCode discriminator_type () raises (BadKind);
- long default_index () raises (BadKind);
-
- // for tk_string, tk_sequence, and tk_array
- unsigned long length () raises (BadKind);
-
- // for tk_sequence, tk_array, and tk_alias
- TypeCode content_type () raises (BadKind);
-
- // deprecated interface
- long param_count ();
- any parameter (in long index) raises (Bounds);
- };
-
-
- /*
- * following line added by Christian Blum
- */
- interface BOA;
-
- interface ORB {
- // other operations ...
-
- TypeCode create_struct_tc (
- in RepositoryId id,
- in Identifier name,
- in StructMemberSeq members
- );
-
- TypeCode create_union_tc (
- in RepositoryId id,
- in Identifier name,
- in TypeCode discriminator_type,
- in UnionMemberSeq members
- );
-
- TypeCode create_enum_tc (
- in RepositoryId id,
- in Identifier name,
- in EnumMemberSeq members
- );
-
- TypeCode create_alias_tc (
- in RepositoryId id,
- in Identifier name,
- in TypeCode original_type
- );
-
- TypeCode create_exception_tc (
- in RepositoryId id,
- in Identifier name,
- in StructMemberSeq members
- );
-
- TypeCode create_interface_tc (
- in RepositoryId id,
- in Identifier name
- );
-
- TypeCode create_string_tc (
- in unsigned long bound
- );
-
- TypeCode create_sequence_tc (
- in unsigned long bound,
- in TypeCode element_type
- );
-
- TypeCode create_recursive_sequence_tc (
- in unsigned long bound,
- in unsigned long offset
- );
-
- TypeCode create_array_tc (
- in unsigned long length,
- in TypeCode element_type
- );
-
- /*
- * following line commented out by Christian Blum
- */
- // };
-
- // The ORB interface (PIDL) is described in Chapter 7, CORBA V2.0 July 1995
- // Object interface (object reference operations): pg 7-3 CORBA V2, 7-95
- // ORB initialization: pg 7-7 CORBA V2, 7-95
- // Object Adapter and Basic Object Adapter initialization: pg 7-8 CORBA V2 7-95
- // Getting initial references: pg 7-10 CORBA V2 7-95
- //PIDL
-
- /*
- * following line commented out by Christian Blum
- */
- //interface ORB {
-
-
- string object_to_string (in Object obj);
- Object string_to_object (in string str);
-
- Status create_list (
- in long count,
- out NVList new_list
- );
- Status create_operation_list (
- in OperationDef oper,
- out NVList new_list
- );
- Status get_default_context (out Context ctx);
-
- // Initializing the ORB
- typedef string ORBid;
- typedef sequence <string> arg_list;
- ORB ORB_init (inout arg_list argv, in ORBid orb_identifier);
-
- // Initializing an object adapter and the Basic Object Adapter
- typedef string OAid;
-
- // Template for OA initialization operations
- // <OA> <OA>_init (inout arg_list argv,
- // in OAid oa_identifier);
-
-
-
- BOA BOA_init (inout arg_list argv,
- in OAid boa_identifier);
-
-
-
- // Getting initial object references
- typedef string ObjectId;
- typedef sequence <ObjectId> ObjectIdList;
-
- exception InvalidName {};
-
- ObjectIdList list_initial_services ();
-
- Object resolve_initial_references (in ObjectId identifier)
- raises (InvalidName);
- };
-
- // had to be changed..., Gerald Brose 1996
- interface ORBject {
-
- ImplementationDef get_implementation ();
- InterfaceDef get_interface ();
- boolean is_nil();
- Object duplicate ();
- void release ();
- boolean is_a (in string logical_type_id);
- boolean non_existent();
- boolean is_equivalent (in Object other_object);
- unsigned long hash(in unsigned long maximum);
-
-
- Status create_request (
- in Context ctx,
- in Identifier operation,
- in NVList arg_list,
- inout NamedValue result,
- out Request request,
- in Flags req_flags
- );
- };
-
-
- // Basic Object Adapter interface described in Chapter 8, CORBA V2.0, July 1995
- // interface InterfaceDef; // from Interface Repository // PIDL
- // interface ImplementationDef; // from Implementation Repository
- // interface Object; // an object reference
- // interface Principal; // for the authentication service
- typedef sequence <octet, 1024> ReferenceData;
-
- interface BOA {
- Object create (
- in ReferenceData id,
- in InterfaceDef intf,
- in ImplementationDef impl
- );
- void dispose (in Object obj);
- ReferenceData get_id (in Object obj);
-
- void change_implementation (in Object obj,
- in ImplementationDef impl
- );
-
- Principal get_principal (in Object obj,
- in Environment ev
- );
-
- void set_exception (in exception_type major, // NO, USER,
- //or SYSTEM_EXCEPTION
- in string userid, // exception type id
- in any param_LOOK_AT_SOURCE
- // in void *param // pointer to associated data
- );
-
- void impl_is_ready (in ImplementationDef impl);
- void deactivate_impl (in ImplementationDef impl);
- void obj_is_ready (in Object obj, in ImplementationDef impl);
- void deactivate_obj (in Object obj);
- };
-};
-
-// IOP module described in chap 10 CORBA V2, 7-95
-module IOP{ // IDL
- //
- // Standard Protocol Profile tag values
- //
- typedef unsigned long ProfileId;
- const ProfileId TAG_INTERNET_IOP = 0;
- const ProfileId TAG_MULTIPLE_COMPONENTS = 1;
-
- struct TaggedProfile {
- ProfileId tag;
- sequence <octet> profile_data;
- };
-
- //
- // an Interoperable Object Reference is a sequence of
- // object-specific protocol profiles, plus a type ID.
- //
- struct IOR {
- string type_id;
- sequence <TaggedProfile> profiles;
- };
-
- //
- // Standard way of representing multicomponent profiles.
- // This would be encapsulated in a TaggedProfile.
- //
- typedef unsigned long ComponentId;
- struct TaggedComponent {
- ComponentId tag;
- sequence <octet> component_data;
- };
- typedef sequence <TaggedComponent> MultipleComponentProfile;
-
-
- typedef unsigned long ServiceID;
-
- struct ServiceContext {
- ServiceID context_id;
- sequence <octet> context_data;
- };
- typedef sequence <ServiceContext> ServiceContextList;
-
- const ServiceID TransactionService = 0;
-
-
-
-};
-// GIOP module described in CORBA V2, 7-95 chap 12
-// Complete IDL for GIOP module in CORBA
-// V2.0, 7-95 p 10-29
-// GIOP message header: CORBA V2, 7-95 p 12-16
-// GIOP request header: CORBA V2, 7-95 p 12-17
-// GIOP reply header: CORBA V2, 7-95 p 12-19
-// GIOP cancel request and locate request: CORBA V2, 7-95 pp 12-20 -- 12-21
-// GIOP locate reply: CORBA V2, 7-95 p 12-22
-module GIOP { // IDL
- enum MsgType {
- Request, Reply, CancelRequest,
- LocateRequest, LocateReply,
- CloseConnection, MessageError
- };
-
- struct Version {
- char major;
- char minor;
- };
-
- struct MessageHeader {
- char magic [4];
- Version GIOP_version;
- boolean byte_order;
- octet message_type;
- unsigned long message_size;
- };
-
- struct RequestHeader {
- ::IOP::ServiceContextList service_context;
- unsigned long request_id;
- boolean response_expected;
- sequence <octet> object_key;
- string operation;
-
- /*
- * ::CORBA:: added for correct scope
- */
- ::CORBA::Principal requesting_principal;
- };
-
- enum ReplyStatusType {
- NO_EXCEPTION,
- USER_EXCEPTION,
- SYSTEM_EXCEPTION,
- LOCATION_FORWARD
- };
-
- struct ReplyHeader {
- ::IOP::ServiceContextList service_context;
- unsigned long request_id;
- ReplyStatusType reply_status;
- };
-
- struct CancelRequestHeader {
- unsigned long request_id;
- };
-
- struct LocateRequestHeader {
- unsigned long request_id;
- sequence <octet> object_key;
- };
-
- enum LocateStatusType {
- UNKNOWN_OBJECT,
- OBJECT_HERE,
- OBJECT_FORWARD
- };
-
- struct LocateReplyHeader {
- unsigned long request_id;
- LocateStatusType locate_status;
- };
-};
-// IIOP module described in CORBA V2, 7-95 chap 12
-// Complete IDL for IIOP module: CORBA V2, 7-95 p 12-31
-module IIOP { // IDL
- struct Version {
- char major;
- char minor;
- };
-
- struct ProfileBody {
- Version iiop_version;
- string host;
- unsigned short port;
- sequence <octet> object_key;
- };
-};
-// DCE CIOP module described in CORBA V2, 7-95 chap 13
-// IDL for DCE CIOP module: CORBA V2, 7-95 p 13-2
-module DCE_CIOP {
- struct InvokeRequestHeader {
- boolean byte_order;
- ::IOP::ServiceContextList service_context;
- sequence <octet> object_key;
- string endpoint_id;
- string operation;
- ::CORBA::Principal principal;
- sequence <string> client_context;
-
- // in and inout parameters follow
- };
- enum InvokeResponseStatus {
- INVOKE_NO_EXCEPTION,
- INVOKE_USER_EXCEPTION,
- INVOKE_SYSTEM_EXCEPTION,
- INVOKE_LOCATION_FORWARD,
- INVOKE_TRY_AGAIN
- };
-
- struct InvokeResponseHeader {
- boolean byte_order;
- ::IOP::ServiceContextList service_context;
- InvokeResponseStatus status;
-
- // if status = INVOKE_NO_EXCEPTION,
- // result then inouts and outs follow
-
- // if status = INVOKE_USER_EXCEPTION or
- // INVOKE_SYSTEM_EXCEPTION, an exception follows
-
- // if status = INVOKE_LOCATION_FORWARD, an
- // ::IOP::MultipleComponentsProfile follows
- };
-
- struct LocateRequestHeader {
- boolean byte_order;
- sequence <octet> object_key;
- string endpoint_id;
- string operation;
-
- // no body follows
- };
-
- module IOP {
-
- /*
- * ::IOP:: added to get the right scope
- */
- const ::IOP::ComponentId TAG_OBJECT_KEY = 10;
- const ::IOP::ComponentId TAG_ENDPOINT_ID = 11;
- const ::IOP::ComponentId TAG_LOCATION_POLICY = 12;
- // illegal IDL
- /* const octet LOCATE_NEVER = 0;
- const octet LOCATE_OBJECT = 1;
- const octet LOCATE_OPERATION = 2;
- const octet LOCATE_ALWAYS = 3;
- */
- };
-};
-
-#endif
diff --git a/lib/ic/test/ic_SUITE_data/Coss.idl b/lib/ic/test/ic_SUITE_data/Coss.idl
deleted file mode 100644
index c84d4a8247..0000000000
--- a/lib/ic/test/ic_SUITE_data/Coss.idl
+++ /dev/null
@@ -1,1537 +0,0 @@
-// This file contains OMG IDL and PIDL for the Common Object Services.
-// CosNaming Module, p 3-6 CORBAservices, Naming Service V1.0, 3/94
-
-// A few minor changes for the JacORB distribution:
-//
-// added am enclosing COSS module and changed scoped names accordingly
-//
-// corrected a few syntax errors
-//
-// commented out:
-// #includes
-// forward declaration of Object
-
-#include "Corba.idl"
-
-module COSS {
-
-module CosNaming {
-
- typedef string Istring;
- struct NameComponent {
- Istring id;
- Istring kind;
- };
-
- typedef sequence <NameComponent> Name;
-
- enum BindingType {nobject, ncontext};
-
- struct Binding {
- Name binding_name;
- BindingType binding_type;
- };
-
- typedef sequence <Binding> BindingList;
- interface BindingIterator;
-
- interface NamingContext {
-
- enum NotFoundReason { missing_node, not_context, not_object};
-
- exception NotFound {
- NotFoundReason why;
- Name rest_of_name;
- };
-
- exception CannotProceed {
- NamingContext cxt;
- Name rest_of_name;
- };
-
- exception InvalidName{};
- exception AlreadyBound {};
- exception NotEmpty{};
-
- void bind(in Name n, in Object obj)
- raises(NotFound, CannotProceed, InvalidName, AlreadyBound);
- void rebind(in Name n, in Object obj)
- raises(NotFound, CannotProceed, InvalidName);
- void bind_context(in Name n, in NamingContext nc)
- raises(NotFound, CannotProceed, InvalidName, AlreadyBound);
- void rebind_context(in Name n, in NamingContext nc)
- raises(NotFound, CannotProceed, InvalidName);
- Object resolve (in Name n)
- raises(NotFound, CannotProceed, InvalidName);
- void unbind(in Name n)
- raises(NotFound, CannotProceed, InvalidName);
- NamingContext new_context();
- NamingContext bind_new_context(in Name n)
- raises(NotFound, AlreadyBound, CannotProceed, InvalidName);
- void destroy( )
- raises(NotEmpty);
- void list (in unsigned long how_many,
- out BindingList bl, out BindingIterator bi);
- };
-
- interface BindingIterator {
- boolean next_one(out Binding b);
- boolean next_n(in unsigned long how_many,
- out BindingList bl);
- void destroy();
- };
-};
-
-// Names Library interface in PIDL, CORBAservices p 3- 14, Naming Service V1.0 3/94
-/*
-interface LNameComponent { // PIDL
- exception NotSet{};
- string get_id()
- raises(NotSet);
- void set_id(in string i);
- string get_kind()
- raises(NotSet);
- void set_kind(in string k);
- void destroy();
-};
-
-interface LName { // PIDL
- exception NoComponent{};
- exception OverFlow{};
- exception InvalidName{};
- LName insert_component(in unsigned long i,
- in LNameComponent n)
- raises(NoComponent, OverFlow);
- LNameComponent get_component(in unsigned long i)
- raises(NoComponent);
- LNameComponent delete_component(in unsigned long i)
- raises(NoComponent);
- unsigned long num_components();
- boolean equal(in LName ln);
- boolean less_than(in LName ln);
- Name to_idl_form()
- raises(InvalidName);
- void from_idl_form(in Name n);
- void destroy();
-};
-
-LName create_lname(); // C/C++
-LNameComponent create_lname_component(); // C/C++
-*/
-
-// CosEventComm Module, CORBAservices p 4-8, Event Service V1.0 3/94
-
-module CosEventComm {
-
- exception Disconnected{};
-
- interface PushConsumer {
- void push (in any data) raises(Disconnected);
- void disconnect_push_consumer();
- };
-
- interface PushSupplier {
- void disconnect_push_supplier();
- };
-
- interface PullSupplier {
- any pull () raises(Disconnected);
- any try_pull (out boolean has_event)
- raises(Disconnected);
- void disconnect_pull_supplier();
- };
-
- interface PullConsumer {
- void disconnect_pull_consumer();
- };
-
-};
-
-// CosEventChannelAdmin Module, p 4-15 CORBAservices, Event
-// Service V1.0, 3/94
-
-// #include "CosEventComm.idl"
-
-module CosEventChannelAdmin {
-
- exception AlreadyConnected {};
- exception TypeError {};
-
- interface ProxyPushConsumer: ::COSS::CosEventComm::PushConsumer {
- void connect_push_supplier(
- in ::COSS::CosEventComm::PushSupplier push_supplier)
- raises(AlreadyConnected);
- };
-
- interface ProxyPullSupplier: ::COSS::CosEventComm::PullSupplier {
- void connect_pull_consumer(
- in ::COSS::CosEventComm::PullConsumer pull_consumer)
- raises(AlreadyConnected);
- };
-
- interface ProxyPullConsumer: ::COSS::CosEventComm::PullConsumer {
- void connect_pull_supplier(
- in ::COSS::CosEventComm::PullSupplier pull_supplier)
- raises(AlreadyConnected,TypeError);
- };
-
- interface ProxyPushSupplier: ::COSS::CosEventComm::PushSupplier {
- void connect_push_consumer(
- in ::COSS::CosEventComm::PushConsumer
- push_consumer)
- raises(AlreadyConnected, TypeError);
- };
-
-
- interface ConsumerAdmin {
- ProxyPushSupplier obtain_push_supplier();
- ProxyPullSupplier obtain_pull_supplier();
- };
-
- interface SupplierAdmin {
- ProxyPushConsumer obtain_push_consumer();
- ProxyPullConsumer obtain_pull_consumer();
- };
-
- interface EventChannel {
- ConsumerAdmin for_consumers();
- SupplierAdmin for_suppliers();
- void destroy();
- };
-
-};
-
-
-// CosTyped Event Module, p 4-22 CORBAservices, Event Service
-// V1.0, 3/94
-
-// // #include "CosEventComm.idl"
-
-module CosTypedEventComm {
-
- interface TypedPushConsumer : ::COSS::CosEventComm::PushConsumer {
- Object get_typed_consumer();
- };
-
- interface TypedPullSupplier : ::COSS::CosEventComm::PullSupplier {
- Object get_typed_supplier();
- };
-
-};
-
-// CosTypedEventChannelAdmin Module, p 4- 25 CORBAservices,
-// Event Service V1.0, 3/94
-
-// // #include "CosEventChannel.idl"
-// // #include "CosTypedEventComm.idl"
-module CosTypedEventChannelAdmin {
- exception InterfaceNotSupported {};
- exception NoSuchImplementation {};
- typedef string Key;
-
- interface TypedProxyPushConsumer :
- ::COSS::CosEventChannelAdmin::ProxyPushConsumer,
- ::COSS::CosTypedEventComm::TypedPushConsumer { };
-
- interface TypedProxyPullSupplier :
- ::COSS::CosEventChannelAdmin::ProxyPullSupplier,
- ::COSS::CosTypedEventComm::TypedPullSupplier { };
-
- interface TypedSupplierAdmin :
- ::COSS::CosEventChannelAdmin::SupplierAdmin {
- TypedProxyPushConsumer obtain_typed_push_consumer(
- in Key supported_interface)
- raises(InterfaceNotSupported);
- ::COSS::CosEventChannelAdmin::ProxyPullConsumer obtain_typed_pull_consumer (
- in Key uses_interface)
- raises(NoSuchImplementation);
- };
-
- interface TypedConsumerAdmin :
- ::COSS::CosEventChannelAdmin::ConsumerAdmin {
- TypedProxyPullSupplier obtain_typed_pull_supplier(
- in Key supported_interface)
- raises (InterfaceNotSupported);
- ::COSS::CosEventChannelAdmin::ProxyPushSupplier obtain_typed_push_supplier(
- in Key uses_interface)
- raises(NoSuchImplementation);
- };
-
- interface TypedEventChannel {
- TypedConsumerAdmin for_consumers();
- TypedSupplierAdmin for_suppliers();
- void destroy ();
- };
-};
-
-
-// CosPersistencePID Module, p 5-20 CORBAservices,
-// Persistent Object Service V1.0, 3/94
-
-//#ifndef __COSPERSISTENCE
-//#define __COSPERSISTENCE
-
-module CosPersistencePID {
-
- interface PID {
- attribute string datastore_type;
- string get_PIDString();
- };
-};
-
-
-// CosPersistencePDS Module, p 5-20 CORBAservices,
-// Persistent Object Service V1.0, 3/94
-
-// #include "CosPersistencePID.idl"
-
-module CosPersistencePDS {
-
-// interface Object;
- interface PDS {
- PDS connect (in Object obj,
- in ::COSS::CosPersistencePID::PID p);
- void disconnect (in Object obj,
- in ::COSS::CosPersistencePID::PID p);
- void store (in Object obj,
- in ::COSS::CosPersistencePID::PID p);
- void restore (in Object obj,
- in ::COSS::CosPersistencePID::PID p);
- void delete (in Object obj,
- in ::COSS::CosPersistencePID::PID p);
- };
-};
-
-
-// CosPersistencePO Module, p 5-12 CORBAservices,
-// Persistent Object Service V1.0, 3/94
-
-// // #include "CosPersistencePDS.idl"
-// CosPersistencePDS.idl
-// // #includes CosPersistencePID.idl
-
-module CosPersistencePO {
-
- interface PO {
- attribute ::COSS::CosPersistencePID::PID p;
- ::COSS::CosPersistencePDS::PDS connect (
- in ::COSS::CosPersistencePID::PID p);
- void disconnect (in ::COSS::CosPersistencePID::PID p);
- void store (in ::COSS::CosPersistencePID::PID p);
- void restore (in ::COSS::CosPersistencePID::PID p);
- void delete (in ::COSS::CosPersistencePID::PID p);
- };
-
- interface SD {
- void pre_store();
- void post_restore();
- };
-};
-
-
-// CosPersistencePOM Module, p 5-15 CORBAservices,
-// Persistent Object Service V1.0, 3/94
-
-// #include "CosPersistencePDS.idl"
-
-// CosPersistencePDS.idl // #includes CosPersistencePID.idl
-
-module CosPersistencePOM {
-
-// interface Object;
-
- interface POM {
- ::COSS::CosPersistencePDS::PDS connect (
- in Object obj,
- in ::COSS::CosPersistencePID::PID p);
- void disconnect (
- in Object obj,
- in ::COSS::CosPersistencePID::PID p);
- void store (
- in Object obj,
- in ::COSS::CosPersistencePID::PID p);
- void restore (
- in Object obj,
- in ::COSS::CosPersistencePID::PID p);
- void delete (
- in Object obj,
- in ::COSS::CosPersistencePID::PID p);
- };
- };
-
-// CosPersistencePDS_DA Module, p 5-22 CORBAservices,
-// Persistent Object Service, V1.0, 3/94
-
-// #include "CosPersistencePDS.idl"
-// CosPersistencePDS.idl // #includes CosPersistencePID.idl
-
-module CosPersistencePDS_DA {
-
- typedef string DAObjectID;
-
- interface PID_DA : ::COSS::CosPersistencePID::PID {
- attribute DAObjectID oid;
- };
-
- interface DAObject {
- boolean dado_same(in DAObject d);
- DAObjectID dado_oid();
- PID_DA dado_pid();
- void dado_remove();
- void dado_free();
- };
-
- interface DAObjectFactory {
- DAObject create();
- };
-
- interface DAObjectFactoryFinder {
- DAObjectFactory find_factory(in string key);
- };
-
- interface PDS_DA : ::COSS::CosPersistencePDS::PDS {
- DAObject get_data();
- void set_data(in DAObject new_data);
- DAObject lookup(in DAObjectID id);
- PID_DA get_pid();
- PID_DA get_object_pid(in DAObject dao);
- DAObjectFactoryFinder data_factories();
- };
-
- typedef sequence<string> AttributeNames;
- interface DynamicAttributeAccess {
- AttributeNames attribute_names();
- any attribute_get(in string name);
- void attribute_set(in string name, in any value);
- };
-
- typedef string ClusterID;
- typedef sequence<ClusterID> ClusterIDs;
- interface PDS_ClusteredDA : PDS_DA{
- ClusterID cluster_id();
- string cluster_kind();
- ClusterIDs clusters_of();
- PDS_ClusteredDA create_cluster(in string kind);
- PDS_ClusteredDA open_cluster(in ClusterID cluster);
- PDS_ClusteredDA copy_cluster(
- in PDS_DA source);
- };
-};
-
-// CosPersistenceDDO Module, p 5-32 CORBAservices, Persistent Object Service V1.0, 3/94
-
-// #include "CosPersistencePID.idl"
-module CosPersistenceDDO {
-
- interface DDO {
- attribute string object_type;
- attribute ::COSS::CosPersistencePID::PID p;
- short add_data();
- short add_data_property (in short data_id);
- short get_data_count();
- short get_data_property_count (in short data_id);
- void get_data_property (in short data_id,
- in short property_id,
- out string property_name,
- out any property_value);
- void set_data_property (in short data_id,
- in short property_id,
- in string property_name,
- in any property_value);
- void get_data (in short data_id,
- out string data_name,
- out any data_value);
- void set_data (in short data_id,
- in string data_name,
- in any data_value);
- };
-};
-
-// CosPersistenceDS_CLI module, p 5-34 CORBAservices,
-// Persistent Object Service V1.0, 3/94
-
-// #include "CosPersistenceDDO.idl"
-// CosPersistenceDDO.idl // #includes CosPersistencePID.idl
-
-module CosPersistenceDS_CLI {
- interface UserEnvironment {
- void set_option (in long option,in any value);
- void get_option (in long option,out any value);
- void release();
- };
-
- interface Connection {
- void set_option (in long option,in any value);
- void get_option (in long option,out any value);
- };
-
- interface ConnectionFactory {
- Connection create_object (
- in UserEnvironment user_envir);
- };
-
- interface Cursor {
- void set_position (in long position,in any value);
- ::COSS::CosPersistenceDDO::DDO fetch_object();
- };
-
- interface CursorFactory {
- Cursor create_object (
- in Connection connection);
- };
-
- interface PID_CLI : ::COSS::CosPersistencePID::PID {
- attribute string datastore_id;
- attribute string id;
- };
-
-
-
- interface Datastore_CLI {
- void connect (in Connection connection,
- in string datastore_id,
- in string user_name,
- in string authentication);
- void disconnect (in Connection connection);
- Connection get_connection (
- in string datastore_id,
- in string user_name);
- void add_object (in Connection connection,
- in ::COSS::CosPersistenceDDO::DDO data_obj);
- void delete_object (
- in Connection connection,
- in ::COSS::CosPersistenceDDO::DDO data_obj);
- void update_object (
- in Connection connection,
- in ::COSS::CosPersistenceDDO::DDO data_obj);
- void retrieve_object(
- in Connection connection,
- in ::COSS::CosPersistenceDDO::DDO data_obj);
- Cursor select_object(
- in Connection connection,
- in string key);
- void transact (in UserEnvironment user_envir,
- in short completion_type);
- void assign_PID (in PID_CLI p);
- void assign_PID_relative (
- in PID_CLI source_pid,
- in PID_CLI target_pid);
- boolean is_identical_PID (
- in PID_CLI pid_1,
- in PID_CLI pid_2);
- string get_object_type (in PID_CLI p);
- void register_mapping_schema (in string schema_file);
- Cursor execute (in Connection connection,
- in string command);
- };
-
-};
-
-
-// CosLifeCycle Module, p 6-10 CORBAservices, LifeCycle Service V1.0, 3/94
-
-// #include "Naming.idl"
-
-module CosLifeCycle
-{
- typedef ::COSS::CosNaming::Name Key;
- typedef Object Factory;
- typedef sequence <Factory> Factories;
- typedef struct NVP {
- ::COSS::CosNaming::Istring name;
- any value;
- } NameValuePair;
- typedef sequence <NameValuePair> Criteria;
-
- exception NoFactory {
- Key search_key;
- };
- exception NotCopyable { string reason; };
- exception NotMovable { string reason; };
- exception NotRemovable { string reason; };
- exception InvalidCriteria{
- Criteria invalid_criteria;
- };
- exception CannotMeetCriteria {
- Criteria unmet_criteria;
- };
-
-
- interface FactoryFinder {
- Factories find_factories(in Key factory_key)
- raises(NoFactory);
- };
-
- interface LifeCycleObject {
- LifeCycleObject copy(in FactoryFinder there,
- in Criteria the_criteria)
- raises(NoFactory, NotCopyable, InvalidCriteria,
- CannotMeetCriteria);
- void move(in FactoryFinder there,
- in Criteria the_criteria)
- raises(NoFactory, NotMovable, InvalidCriteria,
- CannotMeetCriteria);
- void remove()
- raises(NotRemovable);
- };
-
- interface GenericFactory {
- boolean supports(in Key k);
- Object create_object(
- in Key k,
- in Criteria the_criteria)
- raises (NoFactory, InvalidCriteria,
- CannotMeetCriteria);
- };
-};
-
-
-
-// LifeCycleService Module, p 6- 55 CORBAservices, Life Cycle
-// Service V1.0, 3/94
-
-// #include "LifeCycle.idl"
-
-module LifeCycleService {
-
- typedef sequence <::COSS::CosLifeCycle::NameValuePair> PolicyList;
- typedef sequence <::COSS::CosLifeCycle::Key> Keys;
- typedef sequence <::COSS::CosLifeCycle::NameValuePair> PropertyList;
- typedef sequence <::COSS::CosNaming::NameComponent> NameComponents;
-
- interface LifeCycleServiceAdmin {
-
- attribute PolicyList policies;
-
- void bind_generic_factory(
- in ::COSS::CosLifeCycle::GenericFactory gf,
- in ::COSS::CosNaming::NameComponent name,
- in Keys key_set,
- in PropertyList other_properties)
- raises (::COSS::CosNaming::NamingContext::AlreadyBound, ::COSS::CosNaming::NamingContext::InvalidName);
-
- void unbind_generic_factory(
- in ::COSS::CosNaming::NameComponent name)
- raises (::COSS::CosNaming::NamingContext::NotFound, ::COSS::CosNaming::NamingContext::InvalidName);
-
- ::COSS::CosLifeCycle::GenericFactory resolve_generic_factory(
- in ::COSS::CosNaming::NameComponent name)
- raises (::COSS::CosNaming::NamingContext::NotFound, ::COSS::CosNaming::NamingContext::InvalidName);
-
- NameComponents list_generic_factories();
-
- boolean match_service (in ::COSS::CosLifeCycle::GenericFactory f);
-
- string get_hint();
-
- void get_link_properties(
- in ::COSS::CosNaming::NameComponent name,
- out Keys key_set,
- out PropertyList other_properties)
- raises (::COSS::CosNaming::NamingContext::NotFound, ::COSS::CosNaming::NamingContext::InvalidName);
- };
-};
-
-// CosTransactions Module, p 10-66
-// CORBAservices, Transaction Service V1.0, 3/94
-
-module CosTransactions {
-// DATATYPES
-enum Status {
- StatusActive,
- StatusMarkedRollback,
- StatusPrepared,
- StatusCommitted,
- StatusRolledBack,
- StatusUnknown,
- StatusNoTransaction
-};
-
-enum Vote {
- VoteCommit,
- VoteRollback,
- VoteReadOnly
-};
-
-// Standard exceptions
-exception TransactionRequired {};
-exception TransactionRolledBack {};
-exception InvalidTransaction {};
-
-// Heuristic exceptions
-exception HeuristicRollback {};
-exception HeuristicCommit {};
-exception HeuristicMixed {};
-exception HeuristicHazard {};
-
-// Exception from Orb operations
-exception WrongTransaction {};
-
-// Other transaction-specific exceptions
-exception SubtransactionsUnavailable {};
-exception NotSubtransaction {};
-exception Inactive {};
-exception NotPrepared {};
-exception NoTransaction {};
-exception InvalidControl {};
-exception Unavailable {};
-
-// Forward references for interfaces defined later in module
-interface Control;
-interface Terminator;
-interface Coordinator;
-interface Resource;
-interface RecoveryCoordinator;
-interface SubtransactionAwareResource;
-interface TransactionFactory;
-interface TransactionalObject;
-interface Current;
-
-// Current transaction pseudo object (PIDL)
- interface Current {
- void begin()
- raises(SubtransactionsUnavailable);
- void commit(in boolean report_heuristics)
- raises(
- NoTransaction,
- HeuristicMixed,
- HeuristicHazard
- );
- void rollback()
- raises(NoTransaction);
- void rollback_only()
- raises(NoTransaction);
-
- Status get_status();
- string get_transaction_name();
- void set_timeout(in unsigned long seconds);
-
- Control get_control();
- Control suspend();
- void resume(in Control which)
- raises(InvalidControl);
- };
-
- interface TransactionFactory {
- Control create(in unsigned long time_out);
- };
-
- interface Control {
- Terminator get_terminator()
- raises(Unavailable);
- Coordinator get_coordinator()
- raises(Unavailable);
- };
-
- interface Terminator {
- void commit(in boolean report_heuristics)
- raises(
- HeuristicMixed,
- HeuristicHazard
- );
- void rollback();
- };
-
-
- interface Coordinator {
-
- Status get_status();
- Status get_parent_status();
- Status get_top_level_status();
-
- boolean is_same_transaction(in Coordinator tc);
- boolean is_related_transaction(in Coordinator tc);
- boolean is_ancestor_transaction(in Coordinator tc);
- boolean is_descendant_transaction(in Coordinator tc);
- boolean is_top_level_transaction();
-
- unsigned long hash_transaction();
- unsigned long hash_top_level_tran();
-
- RecoveryCoordinator register_resource(in Resource r)
- raises(Inactive);
-
- void register_subtran_aware(in SubtransactionAwareResource r)
- raises(Inactive, NotSubtransaction);
-
- void rollback_only()
- raises(Inactive);
-
- string get_transaction_name();
-
- Control create_subtransaction()
- raises(SubtransactionsUnavailable, Inactive);
- };
-
- interface RecoveryCoordinator {
- Status replay_completion(in Resource r)
- raises(NotPrepared);
- };
-
-}; // end module CosTransactions
-
-
-// CosConcurrency Control Module, p 7-8 CORBAservices,
-// Concurrency Control Service V1.0, 3/94
-
-// #include <CosTransactions.idl>
-module CosConcurrencyControl {
-
- enum lock_mode {
- read,
- write,
- upgrade,
- intention_read,
- intention_write
- };
-
- exception LockNotHeld{};
-
- interface LockCoordinator
- {
- void drop_locks();
- };
-
- interface LockSet
- {
- void lock(in lock_mode mode);
- boolean try_lock(in lock_mode mode);
-
- void unlock(in lock_mode mode)
- raises(LockNotHeld);
- void change_mode(in lock_mode held_mode,
- in lock_mode new_mode)
- raises(LockNotHeld);
- LockCoordinator get_coordinator(
- in ::COSS::CosTransactions::Coordinator which);
- };
-
- interface TransactionalLockSet
- {
- void lock(in ::COSS::CosTransactions::Coordinator current,
- in lock_mode mode);
- boolean try_lock(in ::COSS::CosTransactions::Coordinator current,
- in lock_mode mode);
- void unlock(in ::COSS::CosTransactions::Coordinator current,
- in lock_mode mode)
- raises(LockNotHeld);
- void change_mode(in ::COSS::CosTransactions::Coordinator current,
- in lock_mode held_mode,
- in lock_mode new_mode)
- raises(LockNotHeld);
- LockCoordinator get_coordinator(
- in ::COSS::CosTransactions::Coordinator which);
- };
-
- interface LockSetFactory
- {
- LockSet create();
- LockSet create_related(in LockSet which);
- TransactionalLockSet create_transactional();
- TransactionalLockSet create_transactional_related(in
- TransactionalLockSet which);
- };
-};
-
-// CosObjectIdentity Module, p 9-19 CORBAservices, Relationship
-// Service V1.0, 3/94
-
-
-module CosObjectIdentity {
-
- typedef unsigned long ObjectIdentifier;
-
- interface IdentifiableObject {
- readonly attribute ObjectIdentifier constant_random_id;
- boolean is_identical (
- in IdentifiableObject other_object);
- };
-
-};
-
-
-// CosRelationships Module, p 9-21 CORBAservices, Relationship
-// Service V1.0, 3/94
-
-// #include <ObjectIdentity.idl>
-
-module CosRelationships {
-
- interface RoleFactory;
- interface RelationshipFactory;
- interface Relationship;
- interface Role;
- interface RelationshipIterator;
-
- typedef Object RelatedObject;
- typedef sequence<Role> Roles;
- typedef string RoleName;
- typedef sequence<RoleName> RoleNames;
-
- struct NamedRole {RoleName name; Role aRole;};
- typedef sequence<NamedRole> NamedRoles;
-
- struct RelationshipHandle {
- Relationship the_relationship;
- ::COSS::CosObjectIdentity::ObjectIdentifier constant_random_id;
- };
- typedef sequence<RelationshipHandle> RelationshipHandles;
-
- interface RelationshipFactory {
- struct NamedRoleType {
- RoleName name;
- ::CORBA::InterfaceDef named_role_type;
- };
- typedef sequence<NamedRoleType> NamedRoleTypes;
- readonly attribute ::CORBA::InterfaceDef relationship_type;
- readonly attribute unsigned short degree;
- readonly attribute NamedRoleTypes named_role_types;
- exception RoleTypeError {NamedRoles culprits;};
- exception MaxCardinalityExceeded {
- NamedRoles culprits;};
- exception DegreeError {unsigned short required_degree;};
- exception DuplicateRoleName {NamedRoles culprits;};
- exception UnknownRoleName {NamedRoles culprits;};
-
- Relationship create (in NamedRoles named_roles)
- raises (RoleTypeError,
- MaxCardinalityExceeded,
- DegreeError,
- DuplicateRoleName,
- UnknownRoleName);
- };
-
- interface Relationship :
- ::COSS::CosObjectIdentity::IdentifiableObject {
- exception CannotUnlink {
- Roles offending_roles;
- };
- readonly attribute NamedRoles named_roles;
- void destroy () raises(CannotUnlink);
- };
-
- interface Role {
- exception UnknownRoleName {};
- exception UnknownRelationship {};
- exception RelationshipTypeError {};
- exception CannotDestroyRelationship {
- RelationshipHandles offenders;
- };
- exception ParticipatingInRelationship {
- RelationshipHandles the_relationships;
- };
- readonly attribute RelatedObject related_object;
- RelatedObject get_other_related_object (
- in RelationshipHandle rel,
- in RoleName target_name)
- raises (UnknownRoleName,
- UnknownRelationship);
- Role get_other_role (in RelationshipHandle rel,
- in RoleName target_name)
- raises (UnknownRoleName, UnknownRelationship);
- void get_relationships (
- in unsigned long how_many,
- out RelationshipHandles rels,
- out RelationshipIterator iterator);
- void destroy_relationships()
- raises(CannotDestroyRelationship);
- void destroy() raises(ParticipatingInRelationship);
- boolean check_minimum_cardinality ();
- void link (in RelationshipHandle rel,
- in NamedRoles named_roles)
- raises(RelationshipFactory::MaxCardinalityExceeded,
- RelationshipTypeError);
- void unlink (in RelationshipHandle rel)
- raises (UnknownRelationship);
- };
-
- interface RoleFactory {
- exception NilRelatedObject {};
- exception RelatedObjectTypeError {};
- readonly attribute ::CORBA::InterfaceDef role_type;
- readonly attribute unsigned long max_cardinality;
- readonly attribute unsigned long min_cardinality;
-// the following isn't allowed in IDL,
-// readonly attribute sequence <::CORBA::InterfaceDef> related_object_types;
- typedef sequence <::CORBA::InterfaceDef> InterfaceDefSeq;
- readonly attribute InterfaceDefSeq related_object_types;
- Role create_role (in RelatedObject related_object)
- raises (NilRelatedObject, RelatedObjectTypeError);
- };
-
- interface RelationshipIterator {
- boolean next_one (out RelationshipHandle rel);
- boolean next_n (in unsigned long how_many,
- out RelationshipHandles rels);
- void destroy ();
- };
-
-};
-
-// CosCompoundExternalization Module, p 8-20 CORBAservices,
-// Externalization Service V1.0, 3/94
-
-// #include <Graphs.idl>
-// #include <Stream.idl>
-
-// CosGraphs Module, p 9-39 CORBAservices, Relationship Service
-// V1.0, 3/94
-
-// #include <Relationships.idl>
-// #include <ObjectIdentity.idl>
-
-module CosGraphs {
-
- interface TraversalFactory;
- interface Traversal;
- interface TraversalCriteria;
- interface Node;
- interface NodeFactory;
- interface Role;
- interface EdgeIterator;
-
- struct NodeHandle {
- Node the_node;
- ::COSS::CosObjectIdentity::ObjectIdentifier constant_random_id;
- };
- typedef sequence<NodeHandle> NodeHandles;
-
- struct NamedRole {
- Role the_role;
- ::COSS::CosRelationships::RoleName the_name;
- };
- typedef sequence<NamedRole> NamedRoles;
-
- struct EndPoint {
- NodeHandle the_node;
- NamedRole the_role;
- };
- typedef sequence<EndPoint> EndPoints;
-
- struct Edge {
- EndPoint from;
- ::COSS::CosRelationships::RelationshipHandle the_relationship;
- EndPoints relatives;
- };
- typedef sequence<Edge> Edges;
-
- enum PropagationValue {deep, shallow, none, inhibit};
- enum Mode {depthFirst, breadthFirst, bestFirst};
-
- interface TraversalFactory {
- Traversal create_traversal_on (
- in NodeHandle root_node,
- in TraversalCriteria the_criteria,
- in Mode how);
- };
-
- interface Traversal {
- typedef unsigned long TraversalScopedId;
- struct ScopedEndPoint {
- EndPoint point;
- TraversalScopedId id;
- };
- typedef sequence<ScopedEndPoint> ScopedEndPoints;
- struct ScopedRelationship {
- ::COSS::CosRelationships::RelationshipHandle
- scoped_relationship;
- TraversalScopedId id;
- };
- struct ScopedEdge {
- ScopedEndPoint from;
- ScopedRelationship the_relationship;
- ScopedEndPoints relatives;
- };
- typedef sequence<ScopedEdge> ScopedEdges;
- boolean next_one (out ScopedEdge the_edge);
- boolean next_n (in short how_many,
- out ScopedEdges the_edges);
- void destroy ();
- };
-
- interface TraversalCriteria {
- struct WeightedEdge {
- Edge the_edge;
- unsigned long weight;
- sequence<NodeHandle> next_nodes;
- };
- typedef sequence<WeightedEdge> WeightedEdges;
- void visit_node(in NodeHandle a_node,
- in Mode search_mode);
- boolean next_one (out WeightedEdge the_edge);
- boolean next_n (in short how_many,
- out WeightedEdges the_edges);
- void destroy();
- };
-
- interface Node: ::COSS::CosObjectIdentity::IdentifiableObject {
- typedef sequence<Role> Roles;
- exception NoSuchRole {};
- exception DuplicateRoleType {};
-
- readonly attribute ::COSS::CosRelationships::RelatedObject
- related_object;
- readonly attribute Roles roles_of_node;
- Roles roles_of_type (
- in ::CORBA::InterfaceDef role_type);
- void add_role (in Role a_role)
- raises (DuplicateRoleType);
- void remove_role (in ::CORBA::InterfaceDef of_type)
- raises (NoSuchRole);
- };
-
- interface NodeFactory {
- Node create_node (in Object related_object);
- };
-
- interface Role : ::COSS::CosRelationships::Role {
- void get_edges ( in long how_many,
- out Edges the_edges,
- out EdgeIterator the_rest);
- };
-
- interface EdgeIterator {
- boolean next_one (out Edge the_edge);
- boolean next_n ( in unsigned long how_many,
- out Edges the_edges);
- void destroy ();
- };
-
-};
-
-
-
-// CosStream Module, 8-15 CORBAservices,
-// Externalization Service V1.0, 3/94
-
-// #include <LifeCycle.idl>
-// #include <ObjectIdentity.idl>
-// #include <CompoundExternalization.idl>
-module CosStream {
- exception ObjectCreationError{};
- exception StreamDataFormatError{};
- interface StreamIO;
-
- interface Streamable: ::COSS::CosObjectIdentity::IdentifiableObject
- {
- readonly attribute ::COSS::CosLifeCycle::Key external_form_id;
- void externalize_to_stream(
- in StreamIO targetStreamIO);
- void internalize_from_stream(
- in StreamIO sourceStreamIO,
- in ::COSS::CosLifeCycle::FactoryFinder there)
- raises( ::COSS::CosLifeCycle::NoFactory,
- ObjectCreationError,
- StreamDataFormatError );
- };
-
- interface StreamableFactory {
- Streamable create_uninitialized();
- };
-
-
- interface StreamIO {
- void write_string(in string aString);
- void write_char(in char aChar);
- void write_octet(in octet anOctet);
- void write_unsigned_long(
- in unsigned long anUnsignedLong);
- void write_unsigned_short(
- in unsigned short anUnsignedShort);
- void write_long(in long aLong);
- void write_short(in short aShort);
- void write_float(in float aFloat);
- void write_double(in double aDouble);
- void write_boolean(in boolean aBoolean);
- void write_object(in Streamable aStreamable);
- // void write_graph(in ::COSS::CosCompoundExternalization::Node aNode);
- string read_string()
- raises(StreamDataFormatError);
- char read_char()
- raises(StreamDataFormatError );
- octet read_octet()
- raises(StreamDataFormatError );
- unsigned long read_unsigned_long()
- raises(StreamDataFormatError );
- unsigned short read_unsigned_short()
- raises( StreamDataFormatError );
- long read_long()
- raises(StreamDataFormatError );
- short read_short()
- raises(StreamDataFormatError );
- float read_float()
- raises(StreamDataFormatError );
- double read_double()
- raises(StreamDataFormatError );
- boolean read_boolean()
- raises(StreamDataFormatError );
- Streamable read_object(
- in ::COSS::CosLifeCycle::FactoryFinder there,
- in Streamable aStreamable)
- raises(StreamDataFormatError );
-// void read_graph(
-// in ::COSS::CosCompoundExternalization::Node starting_node,
-// in ::COSS::CosLifeCycle::FactoryFinder there)
-// raises(StreamDataFormatError );
- };
-};
-
-module CosCompoundExternalization {
- interface Node;
- interface Role;
- interface Relationship;
- interface PropagationCriteriaFactory;
-
- struct RelationshipHandle {
- Relationship theRelationship;
- ::COSS::CosObjectIdentity::ObjectIdentifier constantRandomId;
- };
-
- interface Node : ::COSS::CosGraphs::Node, ::COSS::CosStream::Streamable{
- void externalize_node (in ::COSS::CosStream::StreamIO sio);
- void internalize_node (in ::COSS::CosStream::StreamIO sio,
- in ::COSS::CosLifeCycle::FactoryFinder there,
- out ::COSS::CosGraphs::Node::Roles rolesOfNode)
- raises (::COSS::CosLifeCycle::NoFactory);
- };
-
- interface Role : ::COSS::CosGraphs::Role {
- void externalize_role (in ::COSS::CosStream::StreamIO sio);
- void internalize_role (in ::COSS::CosStream::StreamIO sio);
- ::COSS::CosGraphs::PropagationValue externalize_propagation (
- in RelationshipHandle rel,
- in ::COSS::CosRelationships::RoleName toRoleName,
- out boolean sameForAll);
- };
-
- interface Relationship :
- ::COSS::CosRelationships::Relationship {
- void externalize_relationship (
- in ::COSS::CosStream::StreamIO sio);
- void internalize_relationship(
- in ::COSS::CosStream::StreamIO sio,
- in ::COSS::CosGraphs::NamedRoles newRoles);
- ::COSS::CosGraphs::PropagationValue externalize_propagation (
- in ::COSS::CosRelationships::RoleName fromRoleName,
- in ::COSS::CosRelationships::RoleName toRoleName,
- out boolean sameForAll);
- };
-
- interface PropagationCriteriaFactory {
- ::COSS::CosGraphs::TraversalCriteria create_for_externalize( );
- };
-
-};
-
-// CosExternalization Module, 8-12 CORBAservices,
-// Externalization Service V1.0, 3/94
-
-
-// #include <LifeCycle.idl>
-// #include <Stream.idl>
-module CosExternalization {
- exception InvalidFileNameError{};
- exception ContextAlreadyRegistered{};
- interface Stream: ::COSS::CosLifeCycle::LifeCycleObject{
- void externalize(
- in ::COSS::CosStream::Streamable theObject);
- ::COSS::CosStream::Streamable internalize(
- in ::COSS::CosLifeCycle::FactoryFinder there)
- raises( ::COSS::CosLifeCycle::NoFactory,
- ::COSS::CosStream::StreamDataFormatError );
- void begin_context()
- raises( ContextAlreadyRegistered);
- void end_context();
- void flush();
- };
- interface StreamFactory {
- Stream create();
- };
- interface FileStreamFactory {
- Stream create(
- in string theFileName)
- raises( InvalidFileNameError );
- };
-};
-
-// CosContainment Module, p 9- 48 CORBAservices, Relationship
-// Service V1.0, 3/94
-
-// #include <Graphs.idl>
-
-module CosContainment {
-
- interface Relationship :
- ::COSS::CosRelationships::Relationship {};
-
- interface ContainsRole : ::COSS::CosGraphs::Role {};
-
- interface ContainedInRole : ::COSS::CosGraphs::Role {};
-
-};
-
-// CosExternalizationContainment Module, p 8-26 CORBAservices,
-// Externalization Service V1.0, 3/94
-
-// #include <Containment.idl>
-// #include <CompoundExternalization.idl>
-
-module CosExternalizationContainment {
-
- interface Relationship :
- ::COSS::CosCompoundExternalization::Relationship,
- ::COSS::CosContainment::Relationship {};
-
- interface ContainsRole :
- ::COSS::CosCompoundExternalization::Role,
- ::COSS::CosContainment::ContainsRole {};
-
- interface ContainedInRole :
- ::COSS::CosCompoundExternalization::Role,
- ::COSS::CosContainment::ContainedInRole {};
-};
-
-// CosReference Module, p 9-50 CORBAservices,
-// Relationship Service V1.0, 3/94
-
-// #include <Graphs.idl>
-
-module CosReference {
-
- interface Relationship :
- ::COSS::CosRelationships::Relationship {};
-
- interface ReferencesRole : ::COSS::CosGraphs::Role {};
-
- interface ReferencedByRole : ::COSS::CosGraphs::Role {};
-
-};
-
-// CosExternalizationReference Module, p 8-28 CORBAservices,
-// Externalization Service V1.0, 3/94
-
-// #include <Reference.idl>
-// #include <CompoundExternalization.idl>
-
-module CosExternalizationReference {
-
- interface Relationship :
- ::COSS::CosCompoundExternalization::Relationship,
- ::COSS::CosReference::Relationship {};
-
- interface ReferencesRole :
- ::COSS::CosCompoundExternalization::Role,
- ::COSS::CosReference::ReferencesRole {};
-
- interface ReferencedByRole :
- ::COSS::CosCompoundExternalization::Role,
- ::COSS::CosReference::ReferencedByRole {};
-};
-
-// PIDL for CosTSInteroperation Module, p 10-59
-// CORBAservices, Transaction Service V1.0, 3/94
-module CosTSInteroperation { // PIDL
- struct otid_t {
- long formatID; /*format identifier. 0 is OSI TP */
- long bequal_length;
- sequence <octet> tid;
- };
- struct TransIdentity {
- ::COSS::CosTransactions::Coordinator coordinator;
- ::COSS::CosTransactions::Terminator terminator;
- otid_t otid;
- };
- struct PropagationContext {
- unsigned long timeout;
- TransIdentity current;
- sequence <TransIdentity> parents;
- any implementation_specific_data;
- };
-};
-
-// PIDL for CosTSPortability Module, p 10-63
-// CORBAservices, Transaction Service V1.0, 3/94
-
-module CosTSPortability { // PIDL
- typedef long ReqId;
-
- interface Sender {
- void sending_request(in ReqId id,
- out ::COSS::CosTSInteroperation::PropagationContext ctx);
- void received_reply(in ReqId id,
- in ::COSS::CosTSInteroperation::PropagationContext ctx,
- in ::CORBA::Environment env);
- };
-
- interface Receiver {
- void received_request(in ReqId id,
- in ::COSS::CosTSInteroperation::PropagationContext ctx);
- void sending_reply(in ReqId id,
- out::COSS::CosTSInteroperation::PropagationContext ctx);
- };
-};
-
-// CosCompoundLifeCycle Module, p 6-30 CORBAservices,
-// Life Cycle Service V1.0, 3/94
-
-// #include <LifeCycle.idl>
-// #include <Relationships.idl>
-// #include <Graphs.idl>
-
-module CosCompoundLifeCycle {
- interface OperationsFactory;
- interface Operations;
- interface Node;
- interface Role;
- interface Relationship;
- interface PropagationCriteriaFactory;
-
- enum Operation {copy, move, remove};
-
- struct RelationshipHandle {
- Relationship the_relationship;
- ::COSS::CosObjectIdentity::ObjectIdentifier constant_random_id;
- };
-
- interface OperationsFactory {
- Operations create_compound_operations();
- };
-
- interface Operations {
- Node copy (
- in Node starting_node,
- in ::COSS::CosLifeCycle::FactoryFinder there,
- in ::COSS::CosLifeCycle::Criteria the_criteria)
- raises (::COSS::CosLifeCycle::NoFactory,
- ::COSS::CosLifeCycle::NotCopyable,
- ::COSS::CosLifeCycle::InvalidCriteria,
- ::COSS::CosLifeCycle::CannotMeetCriteria);
- void move (
- in Node starting_node,
- in ::COSS::CosLifeCycle::FactoryFinder there,
- in ::COSS::CosLifeCycle::Criteria the_criteria)
- raises (::COSS::CosLifeCycle::NoFactory,
- ::COSS::CosLifeCycle::NotMovable,
- ::COSS::CosLifeCycle::InvalidCriteria,
- ::COSS::CosLifeCycle::CannotMeetCriteria);
- void remove (in Node starting_node)
- raises (::COSS::CosLifeCycle::NotRemovable);
- void destroy();
- };
-
- interface Node : ::COSS::CosGraphs::Node {
- exception NotLifeCycleObject {};
- void copy_node ( in ::COSS::CosLifeCycle::FactoryFinder there,
- in ::COSS::CosLifeCycle::Criteria the_criteria,
- out Node new_node,
- out ::COSS::CosGraphs::Node::Roles roles_of_new_node)
- raises (::COSS::CosLifeCycle::NoFactory,
- ::COSS::CosLifeCycle::NotCopyable,
- ::COSS::CosLifeCycle::InvalidCriteria,
- ::COSS::CosLifeCycle::CannotMeetCriteria);
- void move_node (in ::COSS::CosLifeCycle::FactoryFinder there,
- in ::COSS::CosLifeCycle::Criteria the_criteria)
- raises (::COSS::CosLifeCycle::NoFactory,
- ::COSS::CosLifeCycle::NotMovable,
- ::COSS::CosLifeCycle::InvalidCriteria,
- ::COSS::CosLifeCycle::CannotMeetCriteria);
- void remove_node ()
- raises (::COSS::CosLifeCycle::NotRemovable);
- ::COSS::CosLifeCycle::LifeCycleObject get_life_cycle_object()
- raises (NotLifeCycleObject);
- };
-
- interface Role : ::COSS::CosGraphs::Role {
- Role copy_role (in ::COSS::CosLifeCycle::FactoryFinder there,
- in ::COSS::CosLifeCycle::Criteria the_criteria)
- raises (::COSS::CosLifeCycle::NoFactory,
- ::COSS::CosLifeCycle::NotCopyable,
- ::COSS::CosLifeCycle::InvalidCriteria,
- ::COSS::CosLifeCycle::CannotMeetCriteria);
- void move_role (in ::COSS::CosLifeCycle::FactoryFinder there,
- in ::COSS::CosLifeCycle::Criteria the_criteria)
- raises (::COSS::CosLifeCycle::NoFactory,
- ::COSS::CosLifeCycle::NotMovable,
- ::COSS::CosLifeCycle::InvalidCriteria,
- ::COSS::CosLifeCycle::CannotMeetCriteria);
- ::COSS::CosGraphs::PropagationValue life_cycle_propagation (
- in Operation op,
- in RelationshipHandle rel,
- in ::COSS::CosRelationships::RoleName to_role_name,
- out boolean same_for_all);
- };
-
- interface Relationship :
- ::COSS::CosRelationships::Relationship {
- Relationship copy_relationship (
- in ::COSS::CosLifeCycle::FactoryFinder there,
- in ::COSS::CosLifeCycle::Criteria the_criteria,
- in ::COSS::CosGraphs::NamedRoles new_roles)
- raises (::COSS::CosLifeCycle::NoFactory,
- ::COSS::CosLifeCycle::NotCopyable,
- ::COSS::CosLifeCycle::InvalidCriteria,
- ::COSS::CosLifeCycle::CannotMeetCriteria);
- void move_relationship (
- in ::COSS::CosLifeCycle::FactoryFinder there,
- in ::COSS::CosLifeCycle::Criteria the_criteria)
- raises (::COSS::CosLifeCycle::NoFactory,
- ::COSS::CosLifeCycle::NotMovable,
- ::COSS::CosLifeCycle::InvalidCriteria,
- ::COSS::CosLifeCycle::CannotMeetCriteria);
- ::COSS::CosGraphs::PropagationValue life_cycle_propagation (
- in Operation op,
- in ::COSS::CosRelationships::RoleName from_role_name,
- in ::COSS::CosRelationships::RoleName to_role_name,
- out boolean same_for_all);
- };
-
- interface PropagationCriteriaFactory {
- ::COSS::CosGraphs::TraversalCriteria create(in Operation op);
- };
-
-};
-
-// CosLifeCycleContainment Module, p 6-42 CORBAservices,
-// Life Cycle Service V1.0, 3/94
-
-// #include <Containment.idl>
-// #include <CompoundLifeCycle.idl>
-
-module CosLifeCycleContainment {
-
- interface Relationship :
- ::COSS::CosCompoundLifeCycle::Relationship,
- ::COSS::CosContainment::Relationship {};
-
- interface ContainsRole :
- ::COSS::CosCompoundLifeCycle::Role,
- ::COSS::CosContainment::ContainsRole {};
-
- interface ContainedInRole :
- ::COSS::CosCompoundLifeCycle::Role,
- ::COSS::CosContainment::ContainedInRole {};
-};
-
-// CosLifeCycleReference Module, p 6-44 CORBAservices,
-// Life Cycle Service V1.0, 3/94
-
-// #include <Reference.idl>
-// #include <CompoundLifeCycle.idl>
-
-module CosLifeCycleReference {
-
- interface Relationship :
- ::COSS::CosCompoundLifeCycle::Relationship,
- ::COSS::CosReference::Relationship {};
-
- interface ReferencesRole :
- ::COSS::CosCompoundLifeCycle::Role,
- ::COSS::CosReference::ReferencesRole {};
-
- interface ReferencedByRole :
- ::COSS::CosCompoundLifeCycle::Role,
- ::COSS::CosReference::ReferencedByRole {};
-};
-
-
-}; // end module COSS
diff --git a/lib/ic/test/ic_SUITE_data/attr.idl b/lib/ic/test/ic_SUITE_data/attr.idl
deleted file mode 100644
index 0a1edc787c..0000000000
--- a/lib/ic/test/ic_SUITE_data/attr.idl
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-interface I1 {
- attribute long a1, a2;
- attribute char a3;
-};
-
-interface I2 : I1 {
- attribute short a4;
- readonly attribute char a5;
-};
-
diff --git a/lib/ic/test/ic_SUITE_data/c_err1.idl b/lib/ic/test/ic_SUITE_data/c_err1.idl
deleted file mode 100644
index d50c51c807..0000000000
--- a/lib/ic/test/ic_SUITE_data/c_err1.idl
+++ /dev/null
@@ -1,64 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-//
-// This file forces the bad_tk_match. This triggers when the type of
-// the expression does not match the declared type of the constant
-//
-
-const long c1 = TRUE;
-const unsigned short c1b= TRUE;
-const boolean c2 = +5;
-const long c3 = 'c';
-const float c5 = 3;
-const unsigned long c6 = -2; // Maybe not checked in compiler or suite
-
-const boolean c4 = 1 | 2;
-
-
-// Now define some correct constants for use in reference checking
-
-const long longC = -9;
-const short shortC = -9;
-const unsigned long ulongC = 1;
-const unsigned short ushortC = 0;
-
-const float floatC = 5.1;
-const double doubleC = -2.111;
-
-const boolean boolC = TRUE;
-
-const char charC = 'f';
-const string stringC = "hej";
-const string<9> stringCb = "hejdu";
-
-// Check the reference errors
-
-const long c19 = floatC;
-const short c20 = doubleC;
-const unsigned long c21 = charC;
-const unsigned short c22 = stringC;
-const float c23 = stringCb;
-const double c24 = boolC;
-const boolean c25 = longC;
-const char c26 = shortC;
-const string c27 = ushortC;
-const string<9> c28 = ulongC;
-const long c29 = 3+floatC;
diff --git a/lib/ic/test/ic_SUITE_data/c_err2.idl b/lib/ic/test/ic_SUITE_data/c_err2.idl
deleted file mode 100644
index 84c12421ef..0000000000
--- a/lib/ic/test/ic_SUITE_data/c_err2.idl
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-//
-// Checks bad type of operands
-//
-
-
-const long c1 = 1 + TRUE;
-const boolean c3 = TRUE | FALSE | 19.8;
-const long c4 = 1 << TRUE;
-const long c5 = TRUE >> TRUE;
-
-
diff --git a/lib/ic/test/ic_SUITE_data/c_err3.idl b/lib/ic/test/ic_SUITE_data/c_err3.idl
deleted file mode 100644
index 910f7abcf1..0000000000
--- a/lib/ic/test/ic_SUITE_data/c_err3.idl
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-//
-// Checks ill-formed expressions (type conflict in operands)
-//
-
-
-const long c1 = 5|TRUE;
-const long c2 = 5&TRUE;
-const long c3 = 5^TRUE;
-
diff --git a/lib/ic/test/ic_SUITE_data/c_norm.idl b/lib/ic/test/ic_SUITE_data/c_norm.idl
deleted file mode 100644
index b573ac3f3d..0000000000
--- a/lib/ic/test/ic_SUITE_data/c_norm.idl
+++ /dev/null
@@ -1,164 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-//
-// Check normal values and expressions for constants
-//
-
-// Integer types
-const long co1 = 077;
-const long ch1 = 0xf1;
-const long ch2 = 0XAB;
-const long c1 = 1;
-const short c2 = 3;
-const unsigned long c3 = 1;
-const unsigned short c4 = 3;
-
-// Unary ops
-const long c1hb = -0x1;
-const long c1b = -1;
-const short c2b = -3;
-const long c1c = +1;
-const short c2c = +3;
-// ~ not supported
-
-// Check binary ops
-const long c1d = 9+1-3;
-const long c1hd = 9+1-0xf3;
-const short c2d = 7+3;
-const short c2e = 7*3;
-const long c1e = 1 | 7;
-const long c1f = 7 & 9;
-const long c1g = (1 | 7) & 9;
-const long c1h = 1^7;
-
-//floats
-const float c5 = 1.9;
-const double c6 = 1.9;
-const float c5b = -1.9;
-const double c6b = -1.9;
-
-// Check type operand casting
-const float c5c = 1/(9+2) * 2;
-const double c6c = 1.9-1;
-//const double c6d = 1; // Does not work yet
-
-// Booleans and expressions
-const boolean c7 = TRUE;
-const boolean c7b = FALSE;
-const boolean c7c = TRUE | FALSE;
-const boolean c7d = TRUE & FALSE;
-const boolean c7e = TRUE&TRUE | FALSE&TRUE;
-const boolean c7f = TRUE&TRUE ^ FALSE&TRUE;
-
-// Character and string
-const char c8 = 'c';
-const char c8b = '\n';
-const string c9 = "hej";
-const string<9> c9b = "hejdu";
-
-
-//
-// Check that value references work
-//
-
-const long rc1 = c1g;
-const long rc1h = c1h + 9;
-const short rc2 = c2;
-const unsigned long rc3 = c3;
-const unsigned short rc4 = c4;
-
-
-const float rc5c = c5c;
-const double rc6c = c6c;
-const double rc6d = c6c+1.3;
-
-const boolean rc7 = c7;
-const boolean rc7c = c7c | TRUE;
-
-const char rc8 = c8;
-const char rc8b = c8b;
-const string rc9 = c9;
-const string<9> rc9b = c9b;
-
-
-
-
-//
-// Now check that all typerefs work
-//
-
-typedef long longT;
-typedef short shortT;
-typedef unsigned long ulongT;
-typedef unsigned short ushortT;
-
-typedef float floatT;
-typedef double doubleT;
-
-typedef char charT;
-typedef string stringT;
-
-typedef boolean booleanT;
-
-const longT cc1 = 1;
-const shortT cc2 = 3;
-const ::longT cc1b = -1;
-const ::shortT cc2b = -3;
-
-const floatT cc5 = 1.9;
-const doubleT cc6 = 1.9;
-const floatT cc5b = -1.9;
-const doubleT cc6b = -1.9;
-const floatT cc5c = 1/(9+2) * 2;
-const doubleT cc6c = 1.9-1;
-
-const booleanT cc7 = TRUE;
-const booleanT cc7b = TRUE;
-const booleanT cc7c = TRUE | FALSE;
-const booleanT cc7d = TRUE & FALSE;
-const booleanT cc7e = TRUE&TRUE | FALSE&TRUE;
-
-
-const charT cc8 = 'c';
-const charT cc8b = '\n';
-const stringT cc9 = "hej";
-const stringT cc9b = "hejdu";
-
-
-//
-// Check value casting
-//
-const long longC = -9;
-const short shortC = -9;
-const unsigned long ulongC = 1;
-const unsigned short ushortC = 0;
-
-const float floatC = 5.1;
-const double doubleC = -2.111;
-
-const long c20 = shortC;
-const long c21 = ulongC;
-const long c22 = ushortC;
-const short c23 = ushortC;
-const double c34 = floatC;
-
-
-
diff --git a/lib/ic/test/ic_SUITE_data/enum.idl b/lib/ic/test/ic_SUITE_data/enum.idl
deleted file mode 100644
index 397212baf8..0000000000
--- a/lib/ic/test/ic_SUITE_data/enum.idl
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-
-enum E1 {kalle, sune};
-
-enum E2 { el0, el1, el2, el3, el4, el5, el6, el7, el8, el9, el10, el11, el12, el13,
-el14, el15, el16, el17, el18, el19, el20, el21, el22, el23, el24, el25, el26, el27,
-el28, el29, el30, el31, el32, el33, el34, el35, el36, el37, el38, el39, el40, el41,
-el42, el43, el44, el45, el46, el47, el48, el49, el50, el51, el52, el53, el54, el55,
-el56, el57, el58, el59};
-
-
-
-
-
diff --git a/lib/ic/test/ic_SUITE_data/forward.idl b/lib/ic/test/ic_SUITE_data/forward.idl
deleted file mode 100644
index e9e8edb89e..0000000000
--- a/lib/ic/test/ic_SUITE_data/forward.idl
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-//
-// Check that forward declarations are handled correctly
-//
-
-
-interface i1;
-
-
-interface i1 {
- typedef long T;
-};
-
-
-interface i1;
-
diff --git a/lib/ic/test/ic_SUITE_data/include.idl b/lib/ic/test/ic_SUITE_data/include.idl
deleted file mode 100644
index 292de177c2..0000000000
--- a/lib/ic/test/ic_SUITE_data/include.idl
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-// Check that errors are given with the correct file name reference
-
-#include "include2.idl"
-
-
-typedef T1 T7;
-typedef long T7;
-typedef long T111;
-
-
-
diff --git a/lib/ic/test/ic_SUITE_data/include2.idl b/lib/ic/test/ic_SUITE_data/include2.idl
deleted file mode 100644
index 37caa0bf54..0000000000
--- a/lib/ic/test/ic_SUITE_data/include2.idl
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-// Check that errors are given with the correct file name reference
-
-#include "include3.idl"
-
-
-typedef T7 T1;
-
diff --git a/lib/ic/test/ic_SUITE_data/include3.idl b/lib/ic/test/ic_SUITE_data/include3.idl
deleted file mode 100644
index 18424b3318..0000000000
--- a/lib/ic/test/ic_SUITE_data/include3.idl
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-// Check that errors are given with the correct file name reference
-
-typedef T7 T1;
-
-
-
diff --git a/lib/ic/test/ic_SUITE_data/inherit.idl b/lib/ic/test/ic_SUITE_data/inherit.idl
deleted file mode 100644
index 93fd4b42ba..0000000000
--- a/lib/ic/test/ic_SUITE_data/inherit.idl
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-
-interface I1 {
- typedef long T1;
- typedef struct S1 {long a; boolean b;} T2;
- typedef string StringT, StringT_arr[10];
-
- T1 op1( in StringT a, inout char b, out StringT_arr c );
- T2 op2( in char a, inout char b, out StringT_arr c );
-
- const T1 LongC = 10;
- const StringT StringC = "Hola bambino";
-
-};
-
-
-interface I2 : I1 {
- T1 op3( in long a);
-
- const long c1 = LongC;
- const string c2 = StringC;
-};
-
-interface I3 : I1 {};
-
-interface I4 : I3, I2 {}; // Check that branced inherit works
-
-
-
-// Now use cnstants to check that inheritance works as expected
-
-module m1 {
- interface I1 {
- typedef long T1;
-
- const T1 c1 = 9;
- };
-
- interface I2 : I1 {
- const T1 c2 = c1+5; // c2 = 14
- const long c3 = c2+c1+4; // c3 = 27
- };
-
- interface I3 : I2, I1 {
- const long c1 = 50; // Overrides I1::c1
- const T1 c4 = c1+c2+c3; // c4=91
- const T1 c5 = I1::c1+c1+c2+c3; // 100
- };
-};
-
diff --git a/lib/ic/test/ic_SUITE_data/inherit_err.idl b/lib/ic/test/ic_SUITE_data/inherit_err.idl
deleted file mode 100644
index 3b4989dd8b..0000000000
--- a/lib/ic/test/ic_SUITE_data/inherit_err.idl
+++ /dev/null
@@ -1,72 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-//
-// Ops and attributes must not be redefined (shadowed)
-
-interface I1 {
- long op1( in long a, inout char b, out boolean c );
- long op2( in char a, inout char b, out boolean c );
- attribute long a1, a2;
- readonly attribute char a3;
-};
-
-interface I2 : I1 {
- long op1( in float a, inout char b, out boolean c );
- long op2( in char a, inout char b, out boolean c );
- attribute long a1, a2;
- readonly attribute char a3;
-};
-
-interface I3 : I1 {
- long op3 (in string<19> b);
-};
-
-
-interface I4 : I3 {
- long op1( in float a, inout char b, out boolean c );
- long op2( in char a, inout char b, out boolean c );
- attribute long a1, a2;
- readonly attribute char a3;
-
- long op3 (in string<19> b);
-};
-
-
-interface I11 {
- long op1( in float a, inout char b, out boolean c );
- long op2( in char a, inout char b, out boolean c );
- attribute long a1, a2;
- readonly attribute char a3;
-};
-
-
-
-interface I5 : I1, I11 {};
-
-interface I6 : I1 {
- const long op1=0;
- const long op2=0;
- const long a1=0;
- const long a2=0;
- const long a3=0;
-};
-
-
diff --git a/lib/ic/test/ic_SUITE_data/inherit_warn.idl b/lib/ic/test/ic_SUITE_data/inherit_warn.idl
deleted file mode 100644
index 07f57f1a7d..0000000000
--- a/lib/ic/test/ic_SUITE_data/inherit_warn.idl
+++ /dev/null
@@ -1,65 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-//
-// Checks that shadow warnings comes out as expected
-//
-
-
-interface I1 {
- typedef long T1;
- typedef struct S1 {long a; boolean b;} T2;
- typedef string StringT, StringT_arr[10];
-
- T1 op1( in StringT a, inout char b, out StringT_arr c );
- T2 op2( in char a, inout char b, out StringT_arr c );
-
- const T1 LongC = 10;
- const StringT StringC = "Hola bambino";
-
-};
-
-
-interface I2 : I1 {
- typedef char T1; // Shadows I1::T1
- const boolean StringC = FALSE; // shadows I1::StringC
-
- T1 op3( in long a);
-
- const long c1 = LongC;
- const boolean c2 = StringC;
-};
-
-interface I3 : I2 {}; // More shadows
-
-interface I4 : I1 {
- T1 op4();
- const T1 c2 = 66;
-};
-
-interface I5 : I4 {
- typedef string T1; // Shadows I1::T1
- const char LongC = 'a'; // Shadows I1::LongC
-};
-
-
-interface I6 : I4, I3 {
-};
-
diff --git a/lib/ic/test/ic_SUITE_data/mult_ids.idl b/lib/ic/test/ic_SUITE_data/mult_ids.idl
deleted file mode 100644
index 577e1031fb..0000000000
--- a/lib/ic/test/ic_SUITE_data/mult_ids.idl
+++ /dev/null
@@ -1,93 +0,0 @@
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-//
-// Check that multiply defined identifiers are detected
-//
-
-typedef long T1;
-typedef long T1;
-typedef long T2;
-exception T2 {};
-
-
-//Exceptions
-exception Exc1 {};
-exception Exc1 {};
-
-
-// Enums
-enum E1 {kalle};
-enum E1 {kalle};
-enum E2 {kalle, sune, kalle};
-
-
-// Structs
-struct S1 {long a;};
-struct S1 {long a;};
-struct S2 {long a; short a;};
-struct S3 {long a,b; short a;};
-struct S4 {long a,a; short a;};
-
-
-// Constants
-const long c1 = 0;
-const long c1 = 0;
-
-
-// Interfaces
-
-interface i1 {};
-interface i1 {};
-
-interface i2 {
- attribute long a1;
- attribute long a1;
-};
-
-interface i3 {
- attribute long a1, a2;
- attribute long a2;
-};
-
-interface i4 {
- attribute long a1, a1;
-};
-
-interface i5 {
- long op1();
- long op1();
-
- long op2(in long a, inout char a);
-};
-
-
-// Unions
-
-union U1 switch (long) {case 1: long a;};
-union U1 switch (long) {case 1: long a;};
-
-union U2 switch (long) {
-case 1: long a;
-default: char a;
-};
-
-
-
-
-
diff --git a/lib/ic/test/ic_SUITE_data/nasty.idl b/lib/ic/test/ic_SUITE_data/nasty.idl
deleted file mode 100644
index e55060f762..0000000000
--- a/lib/ic/test/ic_SUITE_data/nasty.idl
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-//
-// Checks nasty name collisions
-//
-
-typedef string T;
-
-
-#define nasty01 version
-#define nasty02 preproc
-#define nasty03 pragma
-#define nasty04 compile
-#define nasty05 if
-#define nasty06 receive
-#define nasty07 foldr
-#define nasty08 length
-#define nasty09 ID
-
-interface I1 {
- attribute T nasty01;
- attribute T nasty02;
- attribute T nasty03;
- attribute T nasty04;
- attribute T nasty05;
- attribute T nasty06;
- attribute T nasty07;
- attribute T nasty08;
- attribute T nasty09;
-};
-
-interface I2 {
- T nasty01();
- T nasty02();
- T nasty03();
- T nasty04();
- T nasty05();
- T nasty06();
- T nasty07();
- T nasty08();
- T nasty09();
-};
-
diff --git a/lib/ic/test/ic_SUITE_data/one.idl b/lib/ic/test/ic_SUITE_data/one.idl
deleted file mode 100644
index 7fb9808767..0000000000
--- a/lib/ic/test/ic_SUITE_data/one.idl
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-// Test oneway operations
-
-interface I1 {
- long op1(in char a, inout boolean b, out string c);
- oneway void op2(in char a, in boolean b, in string c);
- oneway void op3();
-};
-
-
-
diff --git a/lib/ic/test/ic_SUITE_data/one_followed.idl b/lib/ic/test/ic_SUITE_data/one_followed.idl
deleted file mode 100644
index 17074f7e55..0000000000
--- a/lib/ic/test/ic_SUITE_data/one_followed.idl
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-// Test oneway operations followed by other operations
-
-interface I1 {
- oneway void op1();
- oneway void op2(in char a, in boolean b, in string c);
- long op3(in char a, inout boolean b, out string c);
-};
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/ic/test/ic_SUITE_data/one_out.idl b/lib/ic/test/ic_SUITE_data/one_out.idl
deleted file mode 100644
index 1e75c2d962..0000000000
--- a/lib/ic/test/ic_SUITE_data/one_out.idl
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-// Test oneway operations not using in out params
-
-interface I1 {
- oneway void op1(in char a, inout boolean b, in string c);
- oneway void op2(in char a, out boolean b, in string c);
-};
-
-
-
diff --git a/lib/ic/test/ic_SUITE_data/one_raises.idl b/lib/ic/test/ic_SUITE_data/one_raises.idl
deleted file mode 100644
index 4cd7ae00bb..0000000000
--- a/lib/ic/test/ic_SUITE_data/one_raises.idl
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-// Test oneway operations not using in out params
-
-exception hell {boolean burn; unsigned long for_how_long;};
-exception high_water {long mark;};
-
-interface I1 {
- oneway void op1(in char a) raises (hell);
- oneway void op2(in char a) raises (hell);
- oneway void op3() raises (hell, high_water);
-};
-
-
-
diff --git a/lib/ic/test/ic_SUITE_data/one_void.idl b/lib/ic/test/ic_SUITE_data/one_void.idl
deleted file mode 100644
index 6e8c39197c..0000000000
--- a/lib/ic/test/ic_SUITE_data/one_void.idl
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-// Test oneway operations not using in out params
-
-typedef long T;
-
-interface I1 {
- oneway char op1(in char a);
- oneway T op2(in char a);
-};
-
-
-
diff --git a/lib/ic/test/ic_SUITE_data/raises_reg.idl b/lib/ic/test/ic_SUITE_data/raises_reg.idl
deleted file mode 100644
index 52aba10b8d..0000000000
--- a/lib/ic/test/ic_SUITE_data/raises_reg.idl
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-#ifndef _RAISES_REG_IDL
-#define _RAISES_REG_IDL
-
-module Raises_RegModule {
-
- exception Exception_1 {};
-
- exception Exception_2 {};
-
- interface R_R {
-
- void op()
- raises(Raises_RegModule::Exception_1,Raises_RegModule::Exception_2);
-
- };
-
-};
-
-#endif
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/ic/test/ic_SUITE_data/struct.idl b/lib/ic/test/ic_SUITE_data/struct.idl
deleted file mode 100644
index 011c2404d9..0000000000
--- a/lib/ic/test/ic_SUITE_data/struct.idl
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-
-struct S1 {
- long a;
- char b;
- string<9> s;
-};
-
-struct S2 {
- long a;
- struct S3 {
- long a;
- short b, b1;
- char c;
- } b;
- sequence <S1> c, c2, c3, c4, c5, c6, c7;
-};
-
-
-// Check that structs are detected down in other types
-
-
-typedef struct s4 {long a;} T1;
-union U1 switch (long) {
-case 1:
- struct S5 {unsigned short a;} a;
-case 2:
- union U2 switch (char) {
- case 'a':
- boolean a;
- case 'b':
- struct s6 {long a; boolean b;} c;
- } b;
-};
-
diff --git a/lib/ic/test/ic_SUITE_data/syntax1.idl b/lib/ic/test/ic_SUITE_data/syntax1.idl
deleted file mode 100644
index 2de35a6ddf..0000000000
--- a/lib/ic/test/ic_SUITE_data/syntax1.idl
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-//
-// Check syntax errors
-//
-
-
-typedef long T1 _;
-
-
-
diff --git a/lib/ic/test/ic_SUITE_data/syntax2.idl b/lib/ic/test/ic_SUITE_data/syntax2.idl
deleted file mode 100644
index 39f28392e6..0000000000
--- a/lib/ic/test/ic_SUITE_data/syntax2.idl
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-struct S2 {
- long a_arr[99];
- struct S3 {
- long a;_arr[99]
- boolean b_arr[99];
- } b;
-};
-
-
diff --git a/lib/ic/test/ic_SUITE_data/syntax3.idl b/lib/ic/test/ic_SUITE_data/syntax3.idl
deleted file mode 100644
index 2bb9ac7229..0000000000
--- a/lib/ic/test/ic_SUITE_data/syntax3.idl
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-typdef long T1;
-
diff --git a/lib/ic/test/ic_SUITE_data/syntax4.idl b/lib/ic/test/ic_SUITE_data/syntax4.idl
deleted file mode 100644
index e41ad60ed6..0000000000
--- a/lib/ic/test/ic_SUITE_data/syntax4.idl
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-union U1 switch (long) {
-case 1: long a;
-2: short b;
-};
-
diff --git a/lib/ic/test/ic_SUITE_data/syntax5.idl b/lib/ic/test/ic_SUITE_data/syntax5.idl
deleted file mode 100644
index 6468f0adc0..0000000000
--- a/lib/ic/test/ic_SUITE_data/syntax5.idl
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-union U1 switch (enum E1 {kalle, sune}) {
-case kalle: long a;
-sune: short b;
-};
diff --git a/lib/ic/test/ic_SUITE_data/syntax6.idl b/lib/ic/test/ic_SUITE_data/syntax6.idl
deleted file mode 100644
index 6012cc868c..0000000000
--- a/lib/ic/test/ic_SUITE_data/syntax6.idl
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-constant long c1 = 0;
diff --git a/lib/ic/test/ic_SUITE_data/type.idl b/lib/ic/test/ic_SUITE_data/type.idl
deleted file mode 100644
index 6109661c4f..0000000000
--- a/lib/ic/test/ic_SUITE_data/type.idl
+++ /dev/null
@@ -1,191 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-//
-// Check all types in IDL
-//
-
-typedef long T01;
-typedef unsigned long T02;
-typedef short T03;
-typedef unsigned short T04;
-typedef float T05;
-typedef double T06;
-typedef char T07;
-typedef boolean T08;
-typedef octet T09;
-typedef any T10;
-typedef Object T11;
-typedef T01 T12;
-
-// Template types
-typedef sequence <long> T21;
-typedef sequence <unsigned long> T22;
-typedef sequence <short, 2> T23;
-typedef sequence <unsigned short, 6> T24;
-typedef sequence <float, 12> T25;
-typedef sequence <double> T26;
-typedef sequence <char, 1> T27;
-typedef sequence <boolean> T28;
-typedef sequence <octet, 9> T29;
-typedef sequence <any> T30;
-typedef sequence <Object,2 > T31;
-typedef sequence <T01> T32;
-typedef sequence <sequence <sequence <T32> > > T33;
-
-struct S1 {
- long a;
- boolean b;
-};
-
-struct S2 {
- long a;
- struct S3 {
- long a;
- boolean b;
- } b;
-};
-
-union U1 switch (enum E1 {kalle1, sune1}) {
-case kalle1: long a;
-default: boolean b;
-case sune1: octet c;
-};
-
-union U2 switch (enum E2 {kalle2, sune2}) {
-case kalle2: long a;
-default: struct S4 { long a; short b;} b;
-case sune2: octet c;
-};
-
-// Typedefs of above types
-
-typedef struct S11 {
- long a;
- boolean b;
-} T41;
-
-typedef struct S21 {
- long a;
- struct S3 {
- long a;
- boolean b;
- } b;
-} T42;
-
-typedef union U11 switch (enum E3 {kalle3, sune3}) {
-case kalle3: long a;
-default: boolean b;
-case sune3: octet c;
-} T43;
-
-typedef union U21 switch (enum E4 {kalle4, sune4}) {
-case kalle4: long a;
-default: struct S4 { long a; short b;} b;
-case sune4: octet c;
-} T44;
-
-
-
-
-// Array versions
-
-typedef long T01_arr[99];
-typedef unsigned long T02_arr[99];
-typedef short T03_arr[99];
-typedef unsigned short T04_arr[99];
-typedef float T05_arr[99];
-typedef double T06_arr[99];
-typedef char T07_arr[99];
-typedef boolean T08_arr[99];
-typedef octet T09_arr[99];
-typedef any T10_arr[99];
-typedef Object T11_arr[99];
-typedef T01 T12_arr[99];
-
-typedef sequence <long> T21_arr[99];
-typedef sequence <unsigned long> T22_arr[99];
-typedef sequence <short, 2> T23_arr[99];
-typedef sequence <unsigned short, 6> T24_arr[99];
-typedef sequence <float, 12> T25_arr[99];
-typedef sequence <double> T26_arr[99];
-typedef sequence <char, 1> T27_arr[99];
-typedef sequence <boolean> T28_arr[99];
-typedef sequence <octet, 9> T29_arr[99];
-typedef sequence <any> T30_arr[99];
-typedef sequence <Object,2 > T31_arr[99];
-typedef sequence <T01> T32_arr[99];
-typedef sequence <sequence <sequence <T32> > > T33_arr[99];
-
-struct S12 {
- long a;
- boolean b_arr[99];
-};
-
-struct S22 {
- long a_arr[99];
- struct S3 {
- long a_arr[99];
- boolean b_arr[99];
- } b;
-};
-
-union U12 switch (enum E12 {kalle12, sune12}) {
-case kalle12: long a_arr[99];
-default: boolean b;
-case sune12: octet c;
-};
-
-union U22 switch (enum E22 {kalle22, sune22}) {
-case kalle22: long a;
-default: struct S4 { long a; short b;} b_arr[99];
-case sune22: octet c;
-};
-
-// Typedefs of above types
-
-typedef struct S13 {
- long a_arr[99];
- boolean b;
-} T41_arr[99];
-
-typedef struct S23 {
- long a;
- struct S3 {
- long a;
- boolean b_arr[99];
- char c;
- } b;
-} T42_arr[99];
-
-typedef union U13 switch (enum E13 {kalle13, sune13}) {
-case kalle13: long a;
-default: boolean b_arr[99];
-case sune13: octet c;
-} T43_arr[99];
-
-typedef union U23 switch (enum E23 {kalle23, sune23}) {
-case kalle23: long a_arr[99];
-default: struct S4 { long a; short b;} b_arr[99];
-case sune23: octet c_arr[99];
-} T44_arr[99];
-
-
-
diff --git a/lib/ic/test/ic_SUITE_data/typeid.idl b/lib/ic/test/ic_SUITE_data/typeid.idl
deleted file mode 100644
index 9a5ce28bdf..0000000000
--- a/lib/ic/test/ic_SUITE_data/typeid.idl
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-interface I1 {};
-
-module M1 { interface I1 {};};
-
-module M2 { module M1 { interface I1 {};};};
-
-module M3 { module M2 { module M1 { interface I1 {};};};};
-
-
diff --git a/lib/ic/test/ic_SUITE_data/u_case_mult.idl b/lib/ic/test/ic_SUITE_data/u_case_mult.idl
deleted file mode 100644
index 3d1523b5f5..0000000000
--- a/lib/ic/test/ic_SUITE_data/u_case_mult.idl
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-// Check that case labels are not duplicated
-
-union U1 switch (long) {
-case 1 : long a;
-case 1 : short b;
-};
-
-union U2 switch (char) {
-case 'c' : long a;
-case 'c' : short b;
-};
-
-union U2b switch (char) {
-case 'c' :
-case 'c' : long a;
-case 'e': long b;
-case 'c': long c;
-};
-
-union U3 switch (enum E1 {kalle, kula}) {
-case kula : long a;
-case kula : short b;
-};
-
-union U4 switch (boolean) {
-case TRUE : long a;
-case TRUE : short b;
-};
-
-union U5 switch (boolean) {
-case TRUE : long a;
-default: short p;
-default: short pp;
-};
-
diff --git a/lib/ic/test/ic_SUITE_data/u_default.idl b/lib/ic/test/ic_SUITE_data/u_default.idl
deleted file mode 100644
index 050b876aad..0000000000
--- a/lib/ic/test/ic_SUITE_data/u_default.idl
+++ /dev/null
@@ -1,52 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-//
-// Checking that default labels are correct in TK
-//
-
-interface i1 {
- union U1 switch (long) {
- default: long a;
- case 1: case 2: long b;
- };
-
- union U2 switch (long) {
- case 0: default: long a;
- case 1: case 2: long b;
- };
-
- union U3 switch (long) {
- case -1: long aa;
- case 0: default: long a;
- case 1: case 2: long b;
- };
-
- union U4 switch (long) {
- case -1: long aa;
- case 0: long a;
- case 1: case 2: long b;
- };
-
- U1 op0();
- U2 op1();
- U3 op2();
- U4 op3();
-};
diff --git a/lib/ic/test/ic_SUITE_data/u_mult.idl b/lib/ic/test/ic_SUITE_data/u_mult.idl
deleted file mode 100644
index 3ab47c40a5..0000000000
--- a/lib/ic/test/ic_SUITE_data/u_mult.idl
+++ /dev/null
@@ -1,62 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-
-// Check multiply defined declarators
-
-enum E2 {kal, kula, E1}; // legal, but used below
-
-// Now check that declarator a is multiply defined in all unions below
-union U0 switch (long) {
-case 0: long a;
-case 1: short a;
-};
-union U00 switch (char) {
-case 'c' : long a;
-case 'f' : char c;
-case 'b' : short a;
-};
-union U000 switch (boolean) {
-case TRUE: long a;
-case FALSE: short a;
-};
-union U0000 switch (E2) {
-case kal: long a;
-case kula: short a;
-};
-
-
-
-
-// Check that enum name duplication is found.
-
-union U1 switch (enum E1 {kalle, kula, E1}) {
-case E1 : long a; // legal
-case kalle : short E1; // illegal
-};
-
-
-// This is legal, but ended up here anyway
-
-union U2 switch(::E2) {
-case kal : long a;
-case kula : short b;
-default : boolean E1;
-};
diff --git a/lib/ic/test/ic_SUITE_data/u_norm.idl b/lib/ic/test/ic_SUITE_data/u_norm.idl
deleted file mode 100644
index b2f146f45a..0000000000
--- a/lib/ic/test/ic_SUITE_data/u_norm.idl
+++ /dev/null
@@ -1,64 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-
-union U1 switch (long) {
-case 1: long a;
-case 2: case 3: short b;
-};
-
-
-union U2 switch (unsigned short) {
-case 10: boolean a;
-case 188: char b;
-default: string c;
-};
-
-
-union U3 switch (enum E1 {kalle, kula, boll}) {
-case kalle: long a;
-case kula: U2 b;
-};
-
-enum E2 {Cissi, Anders};
-
-union U4 switch (::E2) {
-case Cissi: U1 a;
-default: case Anders: unsigned long b;
-};
-
-union U5 switch(char) {
-case 'e': long a;
-case 'b': case 'f': char b;
-default: struct S {long a; boolean b;} c;
-};
-
-
-// Now check that references can be used as case values
-
-const long c1 = 9;
-const long c2 = 10;
-
-union U6 switch (long) {
-case c1: boolean a;
-case ::c2: boolean b;
-};
-
-
diff --git a/lib/ic/test/ic_SUITE_data/u_type.idl b/lib/ic/test/ic_SUITE_data/u_type.idl
deleted file mode 100644
index 8a46b9375f..0000000000
--- a/lib/ic/test/ic_SUITE_data/u_type.idl
+++ /dev/null
@@ -1,83 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-
-//
-// Check that case values match declared discriminator type
-//
-
-
-const long longC = 0;
-const short shortC = 0;
-const char charC = 'c';
-const string stringC = "Yacht";
-
-enum E1 {kalle, kula};
-
-union U1 switch (long) {
-case 'c' : long a;
-case TRUE : long b;
-case stringC : long d;
-case kalle : long f;
-};
-
-union U2 switch (unsigned long) {
-case 'c' : long a;
-case TRUE : long b;
-case stringC : long d;
-case kalle : long f;
-};
-
-union U3 switch (short) {
-case 'c' : long a;
-case TRUE : long b;
-case stringC : long d;
-case kalle : long f;
-};
-
-union U4 switch (unsigned short) {
-case 'c' : long a;
-case TRUE : long b;
-case stringC : long d;
-case kalle : long f;
-};
-
-union U5 switch (char) {
-case TRUE : long b;
-case stringC : long d;
-case shortC : long e;
-case kalle : long f;
-};
-
-
-union U6 switch (E1) {
-case 'c' : long a;
-case TRUE : long b;
-case stringC : long d;
-case shortC : long e;
-};
-
-union U7 switch (enum E2 {ja, nej, kanske}) {
-case 'c' : long a;
-case TRUE : long b;
-case stringC : long d;
-case shortC : long e;
-};
-
diff --git a/lib/ic/test/ic_SUITE_data/undef_id.idl b/lib/ic/test/ic_SUITE_data/undef_id.idl
deleted file mode 100644
index a09598f0a7..0000000000
--- a/lib/ic/test/ic_SUITE_data/undef_id.idl
+++ /dev/null
@@ -1,64 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-//
-// Check that undefined ids are detected
-//
-
-typedef T7 T1;
-
-const char c1 = ::c0;
-const T01 c2 = 'h';
-const T7 c3 = 9;
-
-interface i1 {
- T17 op();
- long op2( in T7 a);
- attribute T7 a1, a2;
- readonly attribute T17 a3;
-};
-
-union U1 switch (long) {
-case 1: long a;
-case ::g : short b;
-};
-
-union U2 switch (enum E1 {kalle, kula}) {
-case kula1: long a;
-case kalle : short b;
-};
-
-union U3 switch (long) {
-case kula2: long a;
-case ::E3::kalle : short b;
-case ::E4::kalle : short c;
-};
-
-enum E2 {kalle2, kula2};
-
-union U4 switch (E2) {
-case kula1: long a;
-case kula1: long b;
-case c3: short c;
-};
-
-
-
-
diff --git a/lib/ic/test/ic_be_SUITE.erl b/lib/ic/test/ic_be_SUITE.erl
deleted file mode 100644
index d5d3038a6e..0000000000
--- a/lib/ic/test/ic_be_SUITE.erl
+++ /dev/null
@@ -1,75 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%%----------------------------------------------------------------------
-%%% Purpose : Test suite for the backends of the IDL compiler
-%%%----------------------------------------------------------------------
-
--module(ic_be_SUITE).
--include_lib("common_test/include/ct.hrl").
-
-
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2,plain/1]).
-
-
--define(OUT(X), filename:join([proplists:get_value(priv_dir, Config), gen, to_list(X)])).
-
-
-%% Top of cases
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [plain].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%% Checking code for the plain backend.
-plain(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(slask),
- File = filename:join(DataDir, plain),
- ok = ic:gen(File,stdopts(OutDir)++[{be,erl_plain}]),
- ok.
-
-%%--------------------------------------------------------------------
-%%
-%% Utilities
-stdopts(OutDir) ->
- [{outdir, OutDir}, {maxerrs, infinity}].
-
-to_list(X) when is_atom(X) -> atom_to_list(X);
-to_list(X) -> X.
-
diff --git a/lib/ic/test/ic_be_SUITE_data/plain.idl b/lib/ic/test/ic_be_SUITE_data/plain.idl
deleted file mode 100644
index 1ee20eeb1f..0000000000
--- a/lib/ic/test/ic_be_SUITE_data/plain.idl
+++ /dev/null
@@ -1,34 +0,0 @@
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-module m {
-
- struct s {
- long x;
- long y;
- };
-
- interface i {
-
- void foo( in s a, out short b );
-
- };
-
-};
-
diff --git a/lib/ic/test/ic_pp_SUITE.erl b/lib/ic/test/ic_pp_SUITE.erl
deleted file mode 100644
index be37953126..0000000000
--- a/lib/ic/test/ic_pp_SUITE.erl
+++ /dev/null
@@ -1,569 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% Purpose : Test suite for the IDL preprocessor
-%%----------------------------------------------------------------------
-
--module(ic_pp_SUITE).
--include_lib("common_test/include/ct.hrl").
-
-
-
-%% Standard options to the ic compiler, NOTE unholy use of OutDir
-
--define(OUT(X), filename:join([proplists:get_value(priv_dir, Config), gen, to_list(X)])).
--define(GCC, "g++").
--define(GCC_VER, "2.95.3").
-
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2]).
--export([arg_norm/1]).
--export([cascade_norm/1]).
--export([comment_norm/1]).
--export([concat_norm/1]).
--export([define_norm/1]).
--export([if_norm/1]).
--export([if_zero/1]).
--export([misc_norm/1]).
--export([improp_nest_constr_norm/1]).
--export([inc_norm/1]).
--export([line_norm/1]).
--export([nopara_norm/1]).
--export([predef_norm/1]).
--export([predef_time_norm/1]).
--export([self_ref_norm/1]).
--export([separate_norm/1]).
--export([swallow_sc_norm/1]).
--export([unintended_grp_norm/1]).
--export([cases/0, init_per_suite/1, end_per_suite/1]).
-
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- cases().
-
-groups() ->
- [{arg, [], [arg_norm]}, {cascade, [], [cascade_norm]},
- {comment, [], [comment_norm]},
- {concat, [], [concat_norm]},
- {define, [], [define_norm]}, {inc, [], [inc_norm]},
- {improp_nest_constr, [], [improp_nest_constr_norm]},
- {misc, [], [misc_norm]}, {line, [], [line_norm]},
- {nopara, [], [nopara_norm]},
- {predef, [], [predef_norm]},
- {predef_time, [], [predef_time_norm]},
- {self_ref, [], [self_ref_norm]},
- {separate, [], [separate_norm]},
- {swallow_sc, [], [swallow_sc_norm]},
- {unintended_grp, [], [unintended_grp_norm]},
- {'if', [],[if_norm, if_zero]}].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-init_per_suite(Config) ->
- if
- is_list(Config) ->
- case os:type() of
- {win32, _} ->
- {skipped, "Very unplesent to run on windows"};
- _ ->
- check_gcc(Config)
- end;
- true ->
- exit("Config not a list")
- end.
-
-check_gcc(Config) ->
- case os:find_executable(?GCC) of
- false ->
- {skipped,
- lists:flatten(io_lib:format("Can not run without ~s in path",
- [?GCC]))};
- _ ->
- case trim(os:cmd(?GCC++" --version")) of
- ?GCC_VER++[] ->
- Config;
- ?GCC_VER++[D|_] when is_integer(D), D>=$0, D=<$9 ->
- fail_gcc(?GCC_VER++[D]);
- ?GCC_VER++_ ->
- Config;
- Ver ->
- fail_gcc(Ver)
- end
- end.
-
-fail_gcc(Ver) ->
- {skipped, lists:flatten(io_lib:format("Need ~s v~s, not ~s",
- [?GCC, ?GCC_VER, Ver]))}.
-
-trim(S) -> lists:reverse(skip_white(lists:reverse(skip_white(S)))).
-
-skip_white([$\s|T]) -> skip_white(T);
-skip_white([$\n|T]) -> skip_white(T);
-skip_white([$\r|T]) -> skip_white(T);
-skip_white([$\t|T]) -> skip_white(T);
-skip_white(L) -> L.
-
-
-end_per_suite(Config) ->
- Config.
-
-
-cases() ->
- [{group, arg}, {group, cascade}, {group, comment},
- {group, concat}, {group, define}, {group, misc}, {group, 'if'},
- {group, improp_nest_constr}, {group, inc},
- {group, line}, {group, nopara}, {group, predef},
- {group, predef_time}, {group, self_ref},
- {group, separate}, {group, swallow_sc},
- {group, unintended_grp}].
-
-
-
-%%--------------------------------------------------------------------
-%% arg
-%%--------------------------------------------------------------------
-%% Checks arguments for #define.
-arg_norm(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- _OutDir = ?OUT(arg_norm),
- File = filename:join(DataDir, arg),
-
- ok = test_file(File, DataDir),
- ok.
-
-
-%%--------------------------------------------------------------------
-%% cascade
-%%--------------------------------------------------------------------
-%% Check cascade #define.
-cascade_norm(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- _OutDir = ?OUT(cascade_norm),
- File = filename:join(DataDir, cascade),
-
- ok = test_file(File, DataDir),
- ok.
-
-
-%%--------------------------------------------------------------------
-%% comment
-%%--------------------------------------------------------------------
-%% Check comments.
-comment_norm(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- _OutDir = ?OUT(comment_norm),
- File = filename:join(DataDir, comment),
-
- ok = test_file(File, DataDir),
- ok.
-
-
-%%--------------------------------------------------------------------
-%% concat
-%%--------------------------------------------------------------------
-%% Check concatinations, i.e ## .
-concat_norm(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- _OutDir = ?OUT(concat_norm),
- File = filename:join(DataDir, concat),
-
- ok = test_file(File, DataDir),
- ok.
-
-
-%%--------------------------------------------------------------------
-%% define
-%%--------------------------------------------------------------------
-%% Check misceleaneous #define.
-define_norm(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- _OutDir = ?OUT(define_norm),
- File = filename:join(DataDir, define),
-
- ok = test_file(File, DataDir),
- ok.
-
-
-%%--------------------------------------------------------------------
-%% if
-%%--------------------------------------------------------------------
-%% Check #if, #elif, and #endif.
-if_norm(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- _OutDir = ?OUT(if_norm),
- File = filename:join(DataDir, 'if'),
-
- ok = test_file(File, DataDir),
- ok.
-
-%% Check #if 0
-if_zero(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- _OutDir = ?OUT(if_zero),
- File = filename:join(DataDir, if_zero),
-
- ok = test_file(File, DataDir),
- ok.
-
-
-%%--------------------------------------------------------------------
-%% inc
-%%--------------------------------------------------------------------
-%% Check #include.
-inc_norm(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- _OutDir = ?OUT(inc_norm),
- File = filename:join(DataDir, inc),
-
- ok = test_file(File, DataDir),
- ok.
-
-
-
-%%--------------------------------------------------------------------
-%% improp_nest_constr
-%%--------------------------------------------------------------------
-%% Check improperly nested constructs.
-improp_nest_constr_norm(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- _OutDir = ?OUT(improp_nest_constr_norm),
- File = filename:join(DataDir, improp_nest_constr),
-
- ok = test_file(File, DataDir),
- ok.
-
-
-%%--------------------------------------------------------------------
-%% misc
-%%--------------------------------------------------------------------
-%% Misceleaneous checks.
-misc_norm(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- _OutDir = ?OUT(misc_norm),
- File = filename:join(DataDir, misc),
-
- ok = test_file(File, DataDir),
- ok.
-
-
-%%--------------------------------------------------------------------
-%% line
-%%--------------------------------------------------------------------
-%% Checks #line.
-line_norm(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- _OutDir = ?OUT(line_norm),
- File = filename:join(DataDir, line),
-
- ok = test_file(File, DataDir),
- ok.
-
-
-%%--------------------------------------------------------------------
-%% nopara
-%%--------------------------------------------------------------------
-%% Checks #define with no parameters.
-nopara_norm(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- _OutDir = ?OUT(nopara_norm),
- File = filename:join(DataDir, nopara),
-
- ok = test_file(File, DataDir),
- ok.
-
-
-%%--------------------------------------------------------------------
-%% predef
-%%--------------------------------------------------------------------
-%% Checks predefined macros. Note: not __TIME__ and __DATE__.
-predef_norm(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- _OutDir = ?OUT(predef_norm),
- File = filename:join(DataDir, predef),
-
- ok = test_file(File, DataDir),
- ok.
-
-
-%%--------------------------------------------------------------------
-%% predef_time
-%%--------------------------------------------------------------------
-%% Checks the predefined macros __TIME__ and __DATE__.
-predef_time_norm(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- _OutDir = ?OUT(predef_time_norm),
- File = filename:join(DataDir, predef_time),
-
- ok = test_file(File, DataDir),
- ok.
-
-
-%%--------------------------------------------------------------------
-%% self_ref
-%%--------------------------------------------------------------------
-%% Checks self referring macros.
-self_ref_norm(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- _OutDir = ?OUT(self_ref_norm),
- File = filename:join(DataDir, self_ref),
-
- ok = test_file(File, DataDir),
- ok.
-
-
-%%--------------------------------------------------------------------
-%% separate
-%%--------------------------------------------------------------------
-%% Checks separete expansion of macro arguments.
-separate_norm(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- _OutDir = ?OUT(separate_norm),
- File = filename:join(DataDir, separate),
-
- ok = test_file(File, DataDir),
- ok.
-
-
-%%--------------------------------------------------------------------
-%% swallow_sc
-%%--------------------------------------------------------------------
-%% Checks swallowing an undesirable semicolon.
-swallow_sc_norm(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- _OutDir = ?OUT(swallow_sc_norm),
- File = filename:join(DataDir, swallow_sc),
-
- ok = test_file(File, DataDir),
- ok.
-
-
-%%--------------------------------------------------------------------
-%% unintended_grp
-%%--------------------------------------------------------------------
-%% Checks unintended grouping of arithmetic.
-unintended_grp_norm(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- _OutDir = ?OUT(unintended_grp_norm),
- File = filename:join(DataDir, unintended_grp),
-
- ok = test_file(File, DataDir),
- ok.
-
-
-test_file(FileT, DataDir) ->
- case test_file_1(FileT, DataDir) of
- ok -> ok;
- Chars ->
- io:put_chars(Chars),
- {error,{FileT,DataDir}}
- end.
-
-test_file_1(FileT, DataDir) ->
- Tok = string:tokens(FileT, "/"),
- FileName = lists:last(Tok),
- File = FileT++".idl",
-
- test_server:format("File ~p~n",[File]),
- test_server:format("FileName ~p~n",[FileName]),
-
- Flags = "-I"++DataDir,
-
- test_server:format("Flags ~p~n",[Flags]),
-
- Erl = pp_erl(File, Flags),
- Gcc = pp_gcc(File, Flags),
-
- case Erl of
- {error,_ErlError} ->
- test_server:format("Internal_pp Result ~n==================~n~p~n~n",[Erl]);
- {warning, _ErlWar} ->
- test_server:format("Internal_pp Result ~n==================~n~p~n~n",[Erl]);
- _ ->
- test_server:format("Internal_pp Result ~n==================~n~s~n~n",[Erl])
- end,
-
- case Gcc of
- {error,GccError} ->
- Error = string:tokens(GccError, "\n"),
- test_server:format(?GCC" Result ~n==========~n~p~n~n",
- [Error]);
- _ ->
- test_server:format(?GCC" Result ~n==========~n~s~n~n",[Gcc])
- end,
-
-
-
- case {Erl,Gcc} of
- {{warning,W}, {error,X}} ->
- case is_ok(W,X) of
- yes ->
- ok;
- no ->
- io_lib:format("Internal_pp found Warning = ~p ~n"
- ?GCC" found Error = ~p~n",[W,X])
- end;
-
-
- {{warning,W}, _} ->
- io_lib:format(?GCC" did not find warnings while ~n"
- "Internal_pp found the following Warning = ~p~n",[W]);
-
- {{error,E}, {error,X}} ->
- case is_ok(E,X) of
- yes ->
- ok;
- no ->
- io_lib:format("Internal_pp found Error = ~p ~n"
- ?GCC" found Error = ~p~n",[E,X])
- end;
-
- {{error,E}, _} ->
- case FileName of
- "if" ->
- case if_res(E) of
- ok ->
- ok;
- _ ->
- io_lib:format(?GCC" did not find errors while ~n"
- "Internal_pp found the following Error = ~p~n",[E])
- end;
- _ ->
- io_lib:format(?GCC" did not find errors while ~n"
- "Internal_pp found the following Error = ~p~n",[lists:flatten(E)])
- end;
-
- {_, {error,X}} ->
- io_lib:format("Internal_pp did not find errors while ~n"
- ?GCC" found the following Error = ~p~n",[X]);
-
- _ ->
-
- file:write_file("/tmp/Erl.pp",list_to_binary(Erl)),
- file:write_file("/tmp/Gcc.pp",list_to_binary(Gcc)),
-
- Res = os:cmd("diff -b -w /tmp/Erl.pp /tmp/Gcc.pp"),
- test_server:format("///////////{error,E} E ~p FileName~p~n",[Res,FileName]),
- case {Res, FileName} of
- {[], _} ->
- test_server:format("Diff = [] OK!!!!!!~n"),
- ok;
- {_, "predef_time"} ->
- Tokens = string:tokens(Res,"\n"),
- test_server:format("///////////{error,E} Tokens~p~n",[Tokens]),
- case Tokens of
- ["3c3",_,"---",_,"5c5",_,"---",_,"9c9",_,"---",_] ->
- ok;
- _ ->
- io_lib:format("Diff Result = ~p~n",[Res])
- end;
- _ ->
- io_lib:format("Diff Result = ~p~n",[Res])
- end
- end.
-
-
-
-
-
-pp_erl(File, Flags) ->
- case ic_pp:run(File,Flags) of
- {ok, [$#, $ , $1 | Rest], []} ->
- [$#, $ , $1 | Rest];
- {ok, [$#, $ , $1 | _Rest], Warning} ->
- {warning,Warning};
- {error,Error} ->
- {error,Error}
- end.
-
-pp_gcc(File, Flags) ->
- Cmd = ?GCC" -x c++ -E",
- Line = Cmd++" "++Flags++" "++File,
-
- case os:cmd(Line) of
- [$#, $ , $1 | Rest] ->
- [$#, $ , $1 | Rest];
- Res ->
-
- case string:str(Res,"# 1 \"") of
- 0 ->
- {error,Res};
- X ->
- {error, string:sub_string(Res, 1, X-1)}
- end
- end.
-
-
-is_ok([],_Gcc) ->
- yes;
-is_ok([{FileName,Line,Text}|T],Gcc) ->
- Str = FileName++":"++integer_to_list(Line)++": "++Text,
- case string:str(Gcc,Str) of
- 0 ->
- io:format("~n is_ok Internal_pp missed Error = ~s~n",[Str]),
- no;
- _X ->
- is_ok(T,Gcc)
- end;
-is_ok([Str|T],Gcc) ->
- case string:str(Gcc,Str) of
- 0 ->
- io:format("~n is_ok Internal_pp missed Error = ~s~n",[Str]),
- no;
- _X ->
- is_ok(T,Gcc)
- end.
-
-
-to_list(X) when is_atom(X) -> atom_to_list(X);
-to_list(X) -> X.
-
-
-
-if_res(E) ->
- if_res(E,1).
-
-if_res([H|T],Nr) ->
- %% Dir = "/clearcase/otp/libraries/ic/test/ic_pp_SUITE_data/if.idl",
- case {Nr, H} of
- {1, {_Dir, 2, "only '#if 0' is implemented at present"}} ->
- if_res(T,Nr+1);
- {2, {_Dir, 3, "only '#if 0' is implemented at present"}} ->
- if_res(T,Nr+1);
- {3, {_Dir, 5, "`else' command is not implemented at present"}} ->
- if_res(T,Nr+1);
- {4, {_Dir, 9, "`elif' command is not implemented at present"}} ->
- if_res(T,Nr+1);
- {5, {_Dir, 11, "`else' command is not implemented at present"}} ->
- ok;
- _ ->
- error
- end;
-if_res(_, _) ->
- error.
-
-
-
diff --git a/lib/ic/test/ic_pp_SUITE_data/arg.idl b/lib/ic/test/ic_pp_SUITE_data/arg.idl
deleted file mode 100644
index 42d8457f2c..0000000000
--- a/lib/ic/test/ic_pp_SUITE_data/arg.idl
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-#define xstr (s) str(s)
-#define str(s) #s
-#define foo 4
-
-xstr(foo);
-
-#define x(kalle)stina
-x(kurt)
-x
-
-#define y(kalle) stina
-y(kurt)
-y
-
-#define a(kalle) stina
-a(kurt)
-a
-
-#define b (kalle) stina
-b(kurt)
diff --git a/lib/ic/test/ic_pp_SUITE_data/cascade.idl b/lib/ic/test/ic_pp_SUITE_data/cascade.idl
deleted file mode 100644
index f96f2a0bd7..0000000000
--- a/lib/ic/test/ic_pp_SUITE_data/cascade.idl
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-#define BUFS 1020
-#define TABS BUFS
-#undef BUFS
-#define BUFS 37
-
-
-main()
-{
- TABS;
-
-}
diff --git a/lib/ic/test/ic_pp_SUITE_data/comment.idl b/lib/ic/test/ic_pp_SUITE_data/comment.idl
deleted file mode 100644
index 9b5e310e6c..0000000000
--- a/lib/ic/test/ic_pp_SUITE_data/comment.idl
+++ /dev/null
@@ -1,73 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-#define T 12
-#define F T
-
-//comment
-/*exception except {};*/
-
-// comment
- // comment
-/* another */
- /* another */
-/* still
-another */
- /* still
- another */
-__LINE__
-/* yet \
- another */
-// yet \
- another
-__LINE__
-
-#include "all.c"
-#include <all.c>
-#include /* comment */ "all.c"
-#include /* comment */ <all.c>
-#include "all.c" /* comment */
-#include <all.c> /* comment */
-#include // "all.c"
-#include // <all.c>
-#include "all.c" // comment
-#include <all.c> // comment
-#include "all/*cc*/.c"
-#include <all/*cc*/.c>
-
-main()
-{
- printf(" %d \n",F);
- a();
-
-}
-//comment
-/*exception hell {};*/
-#undef T
-#define T "3/*com\
-ment*/4"
-a()
-{
- printf(" %d \n",F);
- printf(" %d \n",T);
-}
-
-b()
-{}
-
diff --git a/lib/ic/test/ic_pp_SUITE_data/concat.idl b/lib/ic/test/ic_pp_SUITE_data/concat.idl
deleted file mode 100644
index eb1f6aa1ad..0000000000
--- a/lib/ic/test/ic_pp_SUITE_data/concat.idl
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-#define sune kurt
-#define a(name) a #name name##_command
-#define b(name) b #name name## _command
-#define c(name) c #name name ##_command
-#define d(name) d #name name ## _command
-#define e(name) e #name command ## _command
-#define f(name) f #name command ## %_command
-#define g(name) g #name name ## %_command
-#define h(name) h #name %_command ## name
-#define i(name) i #name name ## _ ## name
-#define j(name) j #name name ## name
-#define k(name) k #name name ## name
-#define l(name) l #name !name ## name
-#define m(name) m #name name ## !name
-#define n(name) n #name !name ## !name
-#define o(name) stina
-#define p(name) name
-#define q1(name) q1 #name j(name) ## j(name)
-#define q2(name) q2 #name j(name)
-#define q3(name) q3 #name !! ## j(name)
-#define q4(name) q4 #name ## j(name)
-
-a(quit)
-b(quit)
-c(quit)
-d(quit)
-e(quit)
-f(quit)
-g(sune)
-h(sune)
-i(sune)
-j(sune)
-l(sune)
-m(sune)
-n(sune)
-k(j(sune))
-k(o(sune))
-k(p(sune))
-q1(sune)
-q2(sune)
-q3(sune)
-q4(sune)
diff --git a/lib/ic/test/ic_pp_SUITE_data/define.idl b/lib/ic/test/ic_pp_SUITE_data/define.idl
deleted file mode 100644
index 76a3b5ec22..0000000000
--- a/lib/ic/test/ic_pp_SUITE_data/define.idl
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-#define 8
-#define
-#define a
-#define _a
-#define b dfs
-#define 9 fdas
-#define a8
-#define A
-#define (c) fadfas
-#define )c) fadfas
-#define % c) fadfas
-#define d(p) kfdsa
-#define e(p) sinus(p)
-#warning warning line
-#define w%er percent
-#define q() no_para
-#warning warning line
-#undef
-#undef 8
-#undef a
-#undef b
-#undef _a d(kk)
-
diff --git a/lib/ic/test/ic_pp_SUITE_data/if.idl b/lib/ic/test/ic_pp_SUITE_data/if.idl
deleted file mode 100644
index 437ea7c2e1..0000000000
--- a/lib/ic/test/ic_pp_SUITE_data/if.idl
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-#define kurt 12
-#if !true
-#if X == 1
-ett
-#else
-else
-#endif
-true
-#elif kurt
-trueelif
-#else
-trueelse
-#endif
-end
diff --git a/lib/ic/test/ic_pp_SUITE_data/if_zero.idl b/lib/ic/test/ic_pp_SUITE_data/if_zero.idl
deleted file mode 100644
index a0184f8bff..0000000000
--- a/lib/ic/test/ic_pp_SUITE_data/if_zero.idl
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-#if 0
-pelle = mallan
-#endif
-pelle = stina
-#if 0
-kalle = stina
-#endif
-kalle = mallan
-#if 0
-kurt = fia
-#endif
-fia = kurt
-
diff --git a/lib/ic/test/ic_pp_SUITE_data/improp_nest_constr.idl b/lib/ic/test/ic_pp_SUITE_data/improp_nest_constr.idl
deleted file mode 100644
index b658811277..0000000000
--- a/lib/ic/test/ic_pp_SUITE_data/improp_nest_constr.idl
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-#define double(x) (2*(x))
-#define call_with_1(x) x(1)
-
-#define strange(file) fprintf (file, "%s %d",
-
-main()
-{
- call_with_1(double);
- strange(stderr) p, 35)
-
-}
-
diff --git a/lib/ic/test/ic_pp_SUITE_data/inc.idl b/lib/ic/test/ic_pp_SUITE_data/inc.idl
deleted file mode 100644
index e13875b10c..0000000000
--- a/lib/ic/test/ic_pp_SUITE_data/inc.idl
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-int x;
-
-#include "head.h"
-#warning line nr
-main()
-{
- printf(test());
-}
-
-
-
-
-
-
-
-
-#define C false
-#define Z on
-#include "inc2.h"
-#undef Z
-"Ca" C
-"Za" Z
-#include "inc2.h"
-"Cb" C
-"Zb" Z
-
-main()
-{
-#define Q(a,b) sinus(a,b kurt ## b)
- if (Q(34,56)=='NULL') printf(" T AAA%sEEEE \n",Q);
- printf(" %d \n",F);
- a();
-}
-//comment
-/*exception
-hell {};*/
-#undef T
-#define T "3/*com\ment*/4"
-#define T 33
-#define F again
-a ()
-{
- printf(" %d \n",F);
- printf(" %d \n",T);
-}
-
-b()
-{}
-
diff --git a/lib/ic/test/ic_pp_SUITE_data/included1.idl b/lib/ic/test/ic_pp_SUITE_data/included1.idl
deleted file mode 100644
index f3cc40f549..0000000000
--- a/lib/ic/test/ic_pp_SUITE_data/included1.idl
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 2000-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-#ifndef INCLUDED1_IDL
-#define INCLUDED1_IDL
-
-
-#ifndef SOMETHING
-#endif
-
-
-struct s {
-
- long l;
-
-};
-
-
-
-#endif
diff --git a/lib/ic/test/ic_pp_SUITE_data/included2.idl b/lib/ic/test/ic_pp_SUITE_data/included2.idl
deleted file mode 100644
index 6a718ce021..0000000000
--- a/lib/ic/test/ic_pp_SUITE_data/included2.idl
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 2000-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-#ifndef INCLUDED2_IDL
-#define INCLUDED2_IDL
-
-#include "included1.idl"
-
-
-#ifdef SOMETHING
-#endif
-
-
-module m {
-
- struct t {
-
- s st;
-
- };
-
-
-};
-
-
-#endif
diff --git a/lib/ic/test/ic_pp_SUITE_data/includer.idl b/lib/ic/test/ic_pp_SUITE_data/includer.idl
deleted file mode 100644
index d4fabd024a..0000000000
--- a/lib/ic/test/ic_pp_SUITE_data/includer.idl
+++ /dev/null
@@ -1,46 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 2000-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-#ifndef INCLUDER_IDL
-#define INCLUDER_IDL
-
-#include "included1.idl"
-#include "included2.idl"
-
-#ifdef SOMETHING
-#endif
-
-
-
-module n {
-
- interface j {
-
- s op(in m::t inpar);
-
- };
-
-};
-
-
-
-
-#endif
-
-
diff --git a/lib/ic/test/ic_pp_SUITE_data/line.idl b/lib/ic/test/ic_pp_SUITE_data/line.idl
deleted file mode 100644
index 83783dff03..0000000000
--- a/lib/ic/test/ic_pp_SUITE_data/line.idl
+++ /dev/null
@@ -1,46 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-#line
-#line 8
-#line 8a
-#line 12 abc.c
-#line 12 "kurt.c"
-#warning fdafdsaf
-
-
-#define T 12
-#define F T
-#define Q(a) sinus(a)
-#undef Q
-#
-#line 12
-#warning test of warning
-#warning second of warning
-#warning third of warning
-#pragma kurt
-#ident kurt
-#kurt fdsafd
-#line 20
-main()
-{
- if (Q(34,56)=='NULL') printf(" T AAA%sEEEE \n",Q);
- printf(" %d \n",F);
-}
-sune
diff --git a/lib/ic/test/ic_pp_SUITE_data/misc.idl b/lib/ic/test/ic_pp_SUITE_data/misc.idl
deleted file mode 100644
index 512ccb16b1..0000000000
--- a/lib/ic/test/ic_pp_SUITE_data/misc.idl
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-#define str(s) #s
-str(fool);
-str(foo);
-str(kurt);
-#define xstr(s) str(s)
-#define foo 4
-#define kurt sune
-#define sune 17
-
-xstr(fool);
-xstr(foo);
-xstr(kurt);
-
-#define a(b) b #8b
-#define r(b) b #
-#define t(b) b ## a
-a(sinus)
-
-#define ww #www
-ww
-
-#define x 14 + y
-#define y 12 + #x
-x
-
-#define e(a) cosinus(a)
diff --git a/lib/ic/test/ic_pp_SUITE_data/nopara.idl b/lib/ic/test/ic_pp_SUITE_data/nopara.idl
deleted file mode 100644
index 9d5253bf38..0000000000
--- a/lib/ic/test/ic_pp_SUITE_data/nopara.idl
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-#11a
-#define xstr str(s) + kurt*2;
-#define asdf pragma
-#asdf
-#define asd #pragma asd
-
-#10
-#12 8kurt
-
-#define sss "stringing in the rain"
-#define ddd "string
-ing in the rain" asd
-#line 20
-#include "head.h" qqqq
-#include %!#
-#include <sys.h>
-
diff --git a/lib/ic/test/ic_pp_SUITE_data/predef.idl b/lib/ic/test/ic_pp_SUITE_data/predef.idl
deleted file mode 100644
index 8805501d66..0000000000
--- a/lib/ic/test/ic_pp_SUITE_data/predef.idl
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-#define b(q,w) kurt q w
-
-
-b(__LINE__, __FILE__)
-__LINE__
-__FILE__
-
-
-
-b(__INCLUDE_LEVEL__, __BASE_FILE__)
-__INCLUDE_LEVEL__
-__BASE_FILE__
-
-Line __LINE__
-#include "predef.h"
diff --git a/lib/ic/test/ic_pp_SUITE_data/predef_time.idl b/lib/ic/test/ic_pp_SUITE_data/predef_time.idl
deleted file mode 100644
index 7ce8d2a313..0000000000
--- a/lib/ic/test/ic_pp_SUITE_data/predef_time.idl
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-#define b(q,w) kurt q w
-b(__DATE__, __TIME__)
-__DATE__
-__TIME__
-
-#include "predef_time.h"
diff --git a/lib/ic/test/ic_pp_SUITE_data/self_ref.idl b/lib/ic/test/ic_pp_SUITE_data/self_ref.idl
deleted file mode 100644
index 50f8a04e69..0000000000
--- a/lib/ic/test/ic_pp_SUITE_data/self_ref.idl
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-#define foo (4 + foo)
-
-
-main()
-{
- foo;
-
-}
diff --git a/lib/ic/test/ic_pp_SUITE_data/separate.idl b/lib/ic/test/ic_pp_SUITE_data/separate.idl
deleted file mode 100644
index 6151a41709..0000000000
--- a/lib/ic/test/ic_pp_SUITE_data/separate.idl
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-#define xstr(s) str(s)
-#define str(s) #s
-#define foo 4
-#define str1(s) #s lose(s)
-#define foo1 4
-
-main()
-{
- str(foo);
- str1(foo1);
- xstr(foo);
-
-#define qxstr(s) qstr(s)
- qxstr(qfoo);
-#define qstr(s) #s
- qstr( 4 ) ;
-#define qfoo 4
- qstr(qfoo);
-}
diff --git a/lib/ic/test/ic_pp_SUITE_data/swallow_sc.idl b/lib/ic/test/ic_pp_SUITE_data/swallow_sc.idl
deleted file mode 100644
index a42fcc6295..0000000000
--- a/lib/ic/test/ic_pp_SUITE_data/swallow_sc.idl
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-/* comment \
- ends */
-// comment\
-ends
-Line __LINE__
-#define SKIP_SPACES(p, limit) \
-{register char *lim = (limit); \
- while (p != lim) { \
- if (*p++ != ' ') { \
- p--; break; }}}
-
-
-main()
-{
- if (*p != 0)
- SKIP_SPACES (ppp, lim);
- else
- a = 17;
-}
diff --git a/lib/ic/test/ic_pp_SUITE_data/unintended_grp.idl b/lib/ic/test/ic_pp_SUITE_data/unintended_grp.idl
deleted file mode 100644
index ba744ac938..0000000000
--- a/lib/ic/test/ic_pp_SUITE_data/unintended_grp.idl
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-#define ceil_div( xz, yz) (xz + yz - 1) / yz
-#define ceil_div2(xz, yz) ((xz) + (yz) - 1) / (yz)
-
-#define b kurt
-
-main()
-{
- ceil_div(b & c, sizeof(int));
- ceil_div2(b & c, sizeof(int));
-
-}
diff --git a/lib/ic/test/ic_pragma_SUITE.erl b/lib/ic/test/ic_pragma_SUITE.erl
deleted file mode 100644
index bb95e59109..0000000000
--- a/lib/ic/test/ic_pragma_SUITE.erl
+++ /dev/null
@@ -1,301 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: ic_pragma_SUITE.erl
-%%
-%% Description:
-%% Test suite for the IFR object registration when
-%% pragmas are engaged
-%%
-%%-----------------------------------------------------------------
--module(ic_pragma_SUITE).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/include/corba.hrl").
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
- init_per_suite/1, end_per_suite/1]).
--export([ifr_pragma_reg/1, pragma_error/1, uggly_pragmas/1]).
-
-
-%%-----------------------------------------------------------------
-%% Macros
-%%-----------------------------------------------------------------
--define(REMAP_EXCEPT(F), case catch F of
- {'EXCEPTION', E} -> exit(E);
- R -> R
- end).
-%% Standard options to the ic compiler, NOTE unholy use of OutDir
-
--define(OUT(X), filename:join([proplists:get_value(priv_dir, Config), gen, to_list(X)])).
-
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- cases().
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-cases() ->
- [ifr_pragma_reg, pragma_error, uggly_pragmas].
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-init_per_suite(Config) ->
- io:format("Setting up.....~n"),
- mnesia:stop(),
- mnesia:delete_schema([node()]),
- mnesia:create_schema([node()]),
- mnesia:start(),
- orber:install([node()]),
- orber:start(),
- if
- is_list(Config) ->
- Config;
- true ->
- exit("Config not a list")
- end.
-
-end_per_suite(Config) ->
- io:format("Setting down.....~n"),
- orber:stop(),
- orber:uninstall(),
- mnesia:stop(),
- mnesia:delete_schema([node()]),
- Config.
-
-
-
-
-%%-----------------------------------------------------------------
-%% Test Case: IFR registration with pragmas
-%%-----------------------------------------------------------------
-%% Checks that IFR object is correctly registered under pragma engagement.
-ifr_pragma_reg(Config) when is_list(Config) ->
- ?REMAP_EXCEPT(ifr_pragma_reg_run(Config)).
-
-ifr_pragma_reg_run(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(ifr_pragma_reg),
- File0 = filename:join(DataDir, reg_m0),
- ok = ic:gen(File0, stdopts(OutDir)++[{preproc_flags,
- "-I" ++ DataDir}]),
- ok = compile(OutDir, ifr_pragma_files()),
- code:add_pathz(OutDir),
-
- %% OE_register for all files
- ok = 'oe_reg_m0':'oe_register'(),
-
- %% Pragma registration test
- OE_IFR = orber_ifr:find_repository(),
- io:format("~n##### Starting the test case #####~n"),
- check_pragma_effect(OE_IFR,"IDL:M1/T1:1.0"),
- check_pragma_effect(OE_IFR,"DCE:d62207a2-011e-11ce-88b4-0800090b5d3e:3"),
- check_pragma_effect(OE_IFR,"IDL:P2/T3:1.0"),
- check_pragma_effect(OE_IFR,"IDL:P1/M2/T4:2.4"),
-
- %% OE_unregister for all files
- ok = 'oe_reg_m0':'oe_unregister'(),
- code:del_path(OutDir),
- ok.
-
-
-ifr_pragma_files() -> ['oe_reg_m0'].
-
-
-check_pragma_effect(OE_IFR,ID) ->
- io:format("Checking for existance of : ~s~n",[ID]),
- case orber_ifr:lookup_id(OE_IFR,ID) of
- [] ->
- test_server:fail(ID ++ " does not exist"),
- false;
- {Def,_} ->
- io:format("Id refers to = {~p,#Bin}~n",[Def]),
- true
- end.
-
-
-
-
-%%-----------------------------------------------------------------
-%% Test Case: Syntactical / Semantical error pragma definitions
-%%-----------------------------------------------------------------
-%% Finds errornous pragma definitions under compilation.
-pragma_error(Config) when is_list(Config) ->
- ?REMAP_EXCEPT(pragma_error_run(Config)).
-
-pragma_error_run(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(pragma_error),
- File1 = filename:join(DataDir, reg_m1),
- File2 = filename:join(DataDir, reg_m2),
- File3 = filename:join(DataDir, reg_m3),
- File4 = filename:join(DataDir, reg_m4),
- File5 = filename:join(DataDir, reg_m5),
- File6 = filename:join(DataDir, reg_m6),
-
- error = ic:gen(File1, stdopts(OutDir)++[{preproc_flags,
- "-I" ++ DataDir}] ),
-
- error = ic:gen(File2, stdopts(OutDir)++[{preproc_flags,
- "-I" ++ DataDir}] ),
-
- error = ic:gen(File3, stdopts(OutDir)++[{preproc_flags,
- "-I" ++ DataDir}] ),
-
- ok = ic:gen(File4, stdopts(OutDir)++[{preproc_flags,
- "-I" ++ DataDir}] ),
-
- error = ic:gen(File5, stdopts(OutDir)++[{preproc_flags,
- "-I" ++ DataDir}] ),
-
- error = ic:gen(File6, stdopts(OutDir)++[{preproc_flags,
- "-I" ++ DataDir}] ),
- ok.
-
-
-
-
-%%-----------------------------------------------------------------
-%% Test Case: IFR registration with realy uggly placed pragmas
-%%-----------------------------------------------------------------
-%% Checks that IFR object is correctly registered under really uggly pragma engagement.
-uggly_pragmas(Config) when is_list(Config) ->
- ?REMAP_EXCEPT(uggly_pragmas_run(Config)).
-
-uggly_pragmas_run(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(ifr_pragma_reg),
- File0 = filename:join(DataDir, uggly),
-
- ok = ic:gen(File0, stdopts(OutDir)++[{preproc_flags,
- "-I" ++ DataDir}]),
-
- ok = compile(OutDir, uggly_pragma_files()),
- code:add_pathz(OutDir),
-
- %% OE_register for all files
- ok = 'oe_uggly':'oe_register'(),
-
- %% Pragma registration test
- OE_IFR = orber_ifr:find_repository(),
- io:format("~n##### Starting the test case #####~n"),
-
- check_pragma_effect(OE_IFR, "IDL:M:1.0"),
- check_pragma_effect(OE_IFR, "LOCAL:SomeLocalId:10"),
- check_pragma_effect(OE_IFR, "LOCAL:SomeLocalId:11"),
- check_pragma_effect(OE_IFR, "LOCAL:SomeLocalId:17"),
- check_pragma_effect(OE_IFR, "LOCAL:SomeLocalId:34"),
- check_pragma_effect(OE_IFR, "IDL:Exc1:2.2"),
- check_pragma_effect(OE_IFR, "IDL:Exc2:2.2"),
- check_pragma_effect(OE_IFR, "IDL:S:1.0"),
- check_pragma_effect(OE_IFR, "IDL:U:1.0"),
- check_pragma_effect(OE_IFR, "LOCAL:SomeLocalId:23"),
-
- %% OE_unregister for all files
- ok = 'oe_uggly':'oe_unregister'(),
-
- code:del_path(OutDir),
- ok.
-
-
-uggly_pragma_files() -> ['oe_uggly'].
-
-
-
-
-%%----------------------------
-
-
-stdopts(OutDir) ->
- [{outdir, OutDir}, {maxerrs, infinity}].
-
-
-compile(Dir, Files) ->
- compile(Dir, Files, []).
-
-compile(Dir, Files, Opts) ->
- {ok, Cwd} = file:get_cwd(),
- file:set_cwd(Dir),
- io:format("Changing to ~p~n", [Dir]),
- case catch do_compile(Files, Opts) of
- ok ->
- file:set_cwd(Cwd);
- Err ->
- file:set_cwd(Cwd),
- test_server:fail(Err)
- end.
-
-do_compile([], _Opts) -> ok;
-do_compile([F | Fs], Opts) ->
- io:format("Compiling ~p", [F]),
- case compile:file(F, Opts) of
- ok ->
- io:format(" ok~n", []),
- do_load(F, Opts),
- do_compile(Fs, Opts);
- {ok, _} ->
- io:format(" ok~n", []),
- do_load(F, Opts),
- do_compile(Fs, Opts);
- {ok, _, _} ->
- io:format(" ok~n", []),
- do_load(F, Opts),
- do_compile(Fs, Opts);
- Err ->
- io:format(" error: ~p~n", [Err]),
- Err
- end.
-
-do_load(File, Opts) ->
- case lists:member(load, Opts) of
- true ->
- io:format("Loading file ~p", [File]),
- code:purge(File),
- R = code:load_abs(File),
- io:format("Loaded: ~p", [R]);
- false ->
- ok
- end.
-
-
-to_list(X) when is_atom(X) -> atom_to_list(X);
-to_list(X) -> X.
-
-
-
diff --git a/lib/ic/test/ic_pragma_SUITE_data/reg_m0.idl b/lib/ic/test/ic_pragma_SUITE_data/reg_m0.idl
deleted file mode 100644
index a7a90edc92..0000000000
--- a/lib/ic/test/ic_pragma_SUITE_data/reg_m0.idl
+++ /dev/null
@@ -1,78 +0,0 @@
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-// Normal pragmas
-
-module M1 {
-
- typedef long T1;
-
- typedef long T2;
-
-#pragma ID T2 "DCE:d62207a2-011e-11ce-88b4-0800090b5d3e:3"
-
-};
-
-
-#pragma prefix "P1"
-
-module M2 {
-
- module M3 {
-
-#pragma prefix "P2"
-
- interface I1 {
- void Op( in short b,
- out short c);
- };
- typedef long T3;
- };
-
-
- typedef long T4;
-
-#pragma version T4 2.4
-
-};
-
-
-
-/*
-
- Specified types with the following scoped names
- and RepositoryIds
-
- ::M1::T1 IDL:M1/T1:1.0
-
- ::M1::T2 DCE:d62207a2-011e-11ce-88b4-0800090b5d3e:3
-
- ::M2::M3::T3 IDL:P2/T3:1.0
-
- ::M2::T4 IDL:P1/M2/T4:2.4
-
-*/
-
-
-
-
-
-
-
-
diff --git a/lib/ic/test/ic_pragma_SUITE_data/reg_m1.idl b/lib/ic/test/ic_pragma_SUITE_data/reg_m1.idl
deleted file mode 100644
index e222dcddc7..0000000000
--- a/lib/ic/test/ic_pragma_SUITE_data/reg_m1.idl
+++ /dev/null
@@ -1,76 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-// Bad pragma IDs
-
-// Completelly bad id
-module M1 {
-
- typedef long T1;
-
- typedef long T2;
-
-#pragma ID T2 "CompletelyBadId"
-
-};
-
-
-// Bad id, should start with DCE
-module M2 {
-
- typedef long T1;
-
- typedef long T2;
-
-#pragma ID T2 "BAD:d62207a2-011e-11ce-88b4-0800090b5d3e:3"
-
-};
-
-
-// Bad version in ID : not a short number
-module M3 {
-
- typedef long T1;
-
- typedef long T2;
-
-#pragma ID T2 "DCE:d62207a2-011e-11ce-88b4-0800090b5d3e:ABCD"
-
-};
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/ic/test/ic_pragma_SUITE_data/reg_m2.idl b/lib/ic/test/ic_pragma_SUITE_data/reg_m2.idl
deleted file mode 100644
index 351e662ac7..0000000000
--- a/lib/ic/test/ic_pragma_SUITE_data/reg_m2.idl
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-// Bad pragma versions
-
-
-// Bad major version : not a short number
-module M1 {
-
- typedef long T4;
-
-#pragma version T4 2000000000.4
-
-};
-
-// Bad minor version : not a short number
-module M2 {
-
- typedef long T4;
-
-#pragma version T4 2.4000000000000
-
-};
-
-
diff --git a/lib/ic/test/ic_pragma_SUITE_data/reg_m3.idl b/lib/ic/test/ic_pragma_SUITE_data/reg_m3.idl
deleted file mode 100644
index 4f876da8bc..0000000000
--- a/lib/ic/test/ic_pragma_SUITE_data/reg_m3.idl
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-// Bad pragma prefixs
-
-module M2 {
-
- module M3 {
-
-#pragma prefix P2 // Should be "P2"
-
- interface I1 {
- void foo( in short b,
- out short c);
- };
- typedef long T3;
- };
-
-
- typedef long T4;
-};
-
-
diff --git a/lib/ic/test/ic_pragma_SUITE_data/reg_m4.idl b/lib/ic/test/ic_pragma_SUITE_data/reg_m4.idl
deleted file mode 100644
index 9de19b645b..0000000000
--- a/lib/ic/test/ic_pragma_SUITE_data/reg_m4.idl
+++ /dev/null
@@ -1,65 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-// Unrecognmizable pragmas
-
-module M1 {
-
- typedef long T1;
-
- typedef long T2;
-
-
- // Should be ID directive
-
-#pragma ShouldBeId T2 "DCE:d62207a2-011e-11ce-88b4-0800090b5d3e:3"
-
-};
-
- // Should be prefix directive
-
-#pragma ShouldBePrefix "P1"
-
-module M2 {
-
- module M3 {
-
- // Should be prefix directive
-
-#pragma ShouldBePrefix "P2"
-
- interface I1 {
- void foo( in short b,
- out short c);
- };
- typedef long T3;
- };
-
-
- typedef long T4;
-
-
- // Should be version
-
-#pragma ShouldBeVersion T4 2.4
-
-};
-
-
-
diff --git a/lib/ic/test/ic_pragma_SUITE_data/reg_m5.idl b/lib/ic/test/ic_pragma_SUITE_data/reg_m5.idl
deleted file mode 100644
index 85ff419689..0000000000
--- a/lib/ic/test/ic_pragma_SUITE_data/reg_m5.idl
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-// Version not in valid form : major.ninor
-
-module M1 {
-
- typedef long T4;
-
- #pragma version T4 2
-
-};
diff --git a/lib/ic/test/ic_pragma_SUITE_data/reg_m6.idl b/lib/ic/test/ic_pragma_SUITE_data/reg_m6.idl
deleted file mode 100644
index 4f876da8bc..0000000000
--- a/lib/ic/test/ic_pragma_SUITE_data/reg_m6.idl
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-// Bad pragma prefixs
-
-module M2 {
-
- module M3 {
-
-#pragma prefix P2 // Should be "P2"
-
- interface I1 {
- void foo( in short b,
- out short c);
- };
- typedef long T3;
- };
-
-
- typedef long T4;
-};
-
-
diff --git a/lib/ic/test/ic_pragma_SUITE_data/reg_m7.idl b/lib/ic/test/ic_pragma_SUITE_data/reg_m7.idl
deleted file mode 100644
index 038b670dd9..0000000000
--- a/lib/ic/test/ic_pragma_SUITE_data/reg_m7.idl
+++ /dev/null
@@ -1,63 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-
-// Very uggly pragmas
-
-
-#pragma prefix "P1" // Normal pragma
-
-module M4 {
-
- module M5 {
-
-#pragma prefix "P2" // Inside a parameter list
-
- interface I1 {
- void Op(
- #pragma prefix "P2" // Inside a parameter list
- in short b,
- #pragma prefix "P2" // Inside a parameter list
- out short c
- #pragma prefix "P2" // Inside a parameter list
- );
- };
- typedef long T3;
- };
-
-};
-
-
-
-/*
-
- Specified types with the following scoped names
- and RepositoryIds
-
- ::M4::M5::T3 IDL:P2/T3:1.0
-
-*/
-
-
-
-
-
-
-
-
diff --git a/lib/ic/test/ic_pragma_SUITE_data/uggly.idl b/lib/ic/test/ic_pragma_SUITE_data/uggly.idl
deleted file mode 100644
index d12909c00e..0000000000
--- a/lib/ic/test/ic_pragma_SUITE_data/uggly.idl
+++ /dev/null
@@ -1,205 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-// Really uggly pragmas
-
-
-struct S {
-
-#pragma ID TDL1 "LOCAL:SomeLocalId:1"
-#pragma ID TDL1 "LOCAL:SomeLocalId:2"
-
-long a
-
-#pragma ID TDL1 "LOCAL:SomeLocalId:3"
-#pragma ID TDL1 "LOCAL:SomeLocalId:4"
-
-;
-
-#pragma ID TDL1 "LOCAL:SomeLocalId:5"
-#pragma ID TDL1 "LOCAL:SomeLocalId:6"
-
-long b
-
-#pragma ID TDL1 "LOCAL:SomeLocalId:7"
-#pragma ID TDL1 "LOCAL:SomeLocalId:8"
-
-;
-
-
-#pragma ID TDL1 "LOCAL:SomeLocalId:9"
-#pragma ID TDL1 "LOCAL:SomeLocalId:10"
-
-};
-
-
-typedef long TDL1;
-
-
-exception Exc1{
-
-#pragma version Exc1 2.2
-#pragma ID TDL2 "LOCAL:SomeLocalId:11"
-
-};
-
-
-typedef long TDL2;
-
-
-exception Exc2 {
-
-#pragma version Exc2 2.2
-#pragma ID TDL3 "LOCAL:SomeLocalId:11"
-
- long a
-
-#pragma ID TDL3 "LOCAL:SomeLocalId:12"
-#pragma ID TDL3 "LOCAL:SomeLocalId:13"
-
- ;
-
-#pragma ID TDL3 "LOCAL:SomeLocalId:14"
-#pragma ID TDL3 "LOCAL:SomeLocalId:15"
-
- long b
-
-#pragma ID TDL3 "LOCAL:SomeLocalId:16"
-
- ;
-
-#pragma ID TDL3 "LOCAL:SomeLocalId:17"
-
-
-};
-
-typedef long TDL3;
-
-enum E {
-#pragma ID E "LOCAL:SomeLocalId:18"
- a
-#pragma ID E "LOCAL:SomeLocalId:19"
- ,
-#pragma ID E "LOCAL:SomeLocalId:20"
- b
-#pragma ID E "LOCAL:SomeLocalId:21"
-,
-#pragma ID E "LOCAL:SomeLocalId:22"
- c
-#pragma ID E "LOCAL:SomeLocalId:23"
-};
-
-
-
-union U switch (long) {
-
-#pragma ID TDL4 "LOCAL:SomeLocalId:24"
-
- case 1:
-
-#pragma ID TDL4 "LOCAL:SomeLocalId:25"
-
- long a
-
-#pragma ID TDL4 "LOCAL:SomeLocalId:26"
-
-;
-
-#pragma ID TDL4 "LOCAL:SomeLocalId:27"
-
- case 2:
-
-#pragma ID TDL4 "LOCAL:SomeLocalId:28"
-
- case 3:
-
-#pragma ID TDL4 "LOCAL:SomeLocalId:29"
-
-long b
-
-#pragma ID TDL4 "LOCAL:SomeLocalId:30"
-
-;
-
-#pragma ID TDL4 "LOCAL:SomeLocalId:31"
-
- default :
-
-#pragma ID TDL4 "LOCAL:SomeLocalId:32"
-
-long c
-
-#pragma ID TDL4 "LOCAL:SomeLocalId:33"
-
-;
-
-#pragma ID TDL4 "LOCAL:SomeLocalId:34"
-
-};
-
-
-typedef long TDL4;
-
-
-
-module M {
-
- interface I {
-
- void fun1(
-
-#pragma version fun1 3.0
-#pragma ID TDL5 "LOCAL:SomeLocalId:35"
-
- in short b
-
-#pragma ID TDL5 "LOCAL:SomeLocalId:36"
-#pragma ID TDL5 "LOCAL:SomeLocalId:37"
-
- ,
-
-#pragma ID TDL5 "LOCAL:SomeLocalId:38"
-#pragma ID TDL5 "LOCAL:SomeLocalId:39"
-
- out short c
-
-#pragma ID TDL5 "LOCAL:SomeLocalId:40"
-#pragma ID TDL5 "LOCAL:SomeLocalId:41"
-
- );
-
-
- typedef long TDL5;
-
-
- void fun2(
-
-#pragma ID TDL6 "LOCAL:SomeLocalId:42"
-#pragma ID TDL6 "LOCAL:SomeLocalId:43"
-
- );
-
- typedef long TDL6;
-
- };
-
-
-
-};
-
diff --git a/lib/ic/test/ic_register_SUITE.erl b/lib/ic/test/ic_register_SUITE.erl
deleted file mode 100644
index 69eb923f85..0000000000
--- a/lib/ic/test/ic_register_SUITE.erl
+++ /dev/null
@@ -1,422 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: ic_register_SUITE.erl
-%%
-%% Description:
-%% Test suite for the IFR object registration
-%%
-%%-----------------------------------------------------------------
--module(ic_register_SUITE).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/include/corba.hrl").
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
- init_per_suite/1, end_per_suite/1, ifr_reg_unreg/1]).
--export([ifr_inheritence_reg/1,ifr_reg_unreg_with_inheritence/1]).
--export([ifr_reg_unreg_with_inheritence_bad_order/1]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-%%-----------------------------------------------------------------
-%% Macros
-%%-----------------------------------------------------------------
--define(REMAP_EXCEPT(F), case catch F of
- {'EXCEPTION', E} -> exit(E);
- R -> R
- end).
-%% Standard options to the ic compiler, NOTE unholy use of OutDir
-
--define(OUT(X), filename:join([proplists:get_value(priv_dir, Config), gen, to_list(X)])).
-
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- cases().
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-cases() ->
- [ifr_reg_unreg, ifr_reg_unreg_with_inheritence,
- ifr_reg_unreg_with_inheritence_bad_order,
- ifr_inheritence_reg].
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-
-init_per_suite(Config) ->
- io:format("Setting up.....~n"),
- mnesia:stop(),
- mnesia:delete_schema([node()]),
- mnesia:create_schema([node()]),
- mnesia:start(),
- orber:install([node()]),
- orber:start(),
- if
- is_list(Config) ->
- Config;
- true ->
- exit("Config not a list")
- end.
-
-end_per_suite(Config) ->
- io:format("Setting down.....~n"),
- orber:stop(),
- orber:uninstall(),
- mnesia:stop(),
- mnesia:delete_schema([node()]),
- Config.
-
-
-
-%%-----------------------------------------------------------------
-%% Test Case: IFR type registration
-%%-----------------------------------------------------------------
-%% Checks that the generated register/unregister
-%% code for the IFR is correct.
-ifr_reg_unreg(Config) when is_list(Config) ->
- ?REMAP_EXCEPT(ifr_reg_unregt_run(Config)).
-
-ifr_reg_unregt_run(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(ifr_reg_unreg),
- File0 = filename:join(DataDir, reg_m8),
- File1 = filename:join(DataDir, reg_m9),
- File2 = filename:join(DataDir, reg_m10),
- ok = ic:gen(File0, stdopts(OutDir)++[{preproc_flags,
- "-I" ++ DataDir}] ),
- {ok, []} = ic:gen(File0, stdopts(OutDir)++[silent2, {preproc_flags,
- "-I" ++ DataDir}]),
- ok = ic:gen(File1, stdopts(OutDir)++[{preproc_flags,
- "-I" ++ DataDir}] ),
- {ok, []} = ic:gen(File1, stdopts(OutDir)++[silent2, {preproc_flags,
- "-I" ++ DataDir}]),
- ok = ic:gen(File2, stdopts(OutDir)++[{preproc_flags,
- "-I" ++ DataDir}] ),
- {ok, []} = ic:gen(File2, stdopts(OutDir)++[silent2, {preproc_flags,
- "-I" ++ DataDir}]),
- ok = compile(OutDir, ifr_reg_unreg_files()),
- code:add_pathz(OutDir),
- ok = 'oe_reg_m8':'oe_register'(),
- ok = 'oe_reg_m9':'oe_register'(),
- ok = 'oe_reg_m10':'oe_register'(),
- ok = 'oe_reg_m10':'oe_unregister'(),
- ok = 'oe_reg_m9':'oe_unregister'(),
- ok = 'oe_reg_m8':'oe_unregister'(),
- code:del_path(OutDir),
- ok.
-
-ifr_reg_unreg_files() -> ['oe_reg_m8', 'oe_reg_m9', 'oe_reg_m10'].
-
-
-
-%%-----------------------------------------------------------------
-%% Test Case: IFR registration when object inheritence
-%% is applied and registered.
-%%-----------------------------------------------------------------
-%% Checks that the generated register/unregister
-%% code for the IFR is correct, and works even when
-%% the object inheritence is registered. This fixes
-%% two bugs in ifr that caused crash when trying to
-%% use OE_register/OE_unregister in a sequence of
-%% compiled files that contained interfaces who
-%% inherited others in sequence.
-ifr_reg_unreg_with_inheritence(Config) when is_list(Config) ->
- ?REMAP_EXCEPT(ifr_reg_unreg_with_inheritence_run(Config)).
-
-ifr_reg_unreg_with_inheritence_run(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(ifr_reg_unreg),
- File0 = filename:join(DataDir, reg_m8),
- File1 = filename:join(DataDir, reg_m9),
- File2 = filename:join(DataDir, reg_m10),
- File3 = filename:join(DataDir, reg_m11),
- File4 = filename:join(DataDir, reg_m12),
- ok = ic:gen(File0, stdopts(OutDir)++[{preproc_flags,
- "-I" ++ DataDir}] ),
- {ok, []} = ic:gen(File0, stdopts(OutDir)++[silent2, {preproc_flags,
- "-I" ++ DataDir}]),
- ok = ic:gen(File1, stdopts(OutDir)++[{preproc_flags,
- "-I" ++ DataDir}] ),
- {ok, []} = ic:gen(File1, stdopts(OutDir)++[silent2, {preproc_flags,
- "-I" ++ DataDir}]),
- ok = ic:gen(File2, stdopts(OutDir)++[{preproc_flags,
- "-I" ++ DataDir}] ),
- {ok, []} = ic:gen(File2, stdopts(OutDir)++[silent2, {preproc_flags,
- "-I" ++ DataDir}]),
- ok = ic:gen(File3, stdopts(OutDir)++[{preproc_flags,
- "-I" ++ DataDir}] ),
- {ok, []} = ic:gen(File3, stdopts(OutDir)++[silent2, {preproc_flags,
- "-I" ++ DataDir}]),
- ok = ic:gen(File4, stdopts(OutDir)++[{preproc_flags,
- "-I" ++ DataDir}] ),
- {ok, []} = ic:gen(File4, stdopts(OutDir)++[silent2, {preproc_flags,
- "-I" ++ DataDir}]),
- ok = compile(OutDir, ifr_reg_unreg_with_inheritence_files()),
- code:add_pathz(OutDir),
- ok = 'oe_reg_m8':'oe_register'(),
- ok = 'oe_reg_m9':'oe_register'(),
- ok = 'oe_reg_m10':'oe_register'(),
- ok = 'oe_reg_m11':'oe_register'(),
- ok = 'oe_reg_m12':'oe_register'(),
- ok = 'oe_reg_m8':'oe_unregister'(),
- ok = 'oe_reg_m9':'oe_unregister'(),
- ok = 'oe_reg_m10':'oe_unregister'(),
- ok = 'oe_reg_m11':'oe_unregister'(),
- ok = 'oe_reg_m12':'oe_unregister'(),
- code:del_path(OutDir),
- ok.
-
-ifr_reg_unreg_with_inheritence_files() ->
- ['oe_reg_m8', 'oe_reg_m9', 'oe_reg_m10', 'oe_reg_m11', 'oe_reg_m12'].
-
-
-
-
-
-%%-----------------------------------------------------------------
-%% Test Case: IFR registration when object inheritence
-%% is applied and registered in a bad order.
-%% Modules included and used from an ifr object
-%% are not allready registered when the current
-%% object is getting registered.
-%%-----------------------------------------------------------------
-ifr_reg_unreg_with_inheritence_bad_order(Config) when is_list(Config) ->
- ?REMAP_EXCEPT(ifr_reg_unreg_with_inheritence_bad_order_run(Config)).
-
-ifr_reg_unreg_with_inheritence_bad_order_run(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(ifr_reg_unreg),
- File1 = filename:join(DataDir, reg_m9),
- File2 = filename:join(DataDir, reg_m10),
- File4 = filename:join(DataDir, reg_m12),
- ok = ic:gen(File1, stdopts(OutDir)++[{preproc_flags,
- "-I" ++ DataDir}] ),
- {ok, []} = ic:gen(File1, stdopts(OutDir)++[silent2, {preproc_flags,
- "-I" ++ DataDir}]),
- ok = ic:gen(File2, stdopts(OutDir)++[{preproc_flags,
- "-I" ++ DataDir}] ),
- {ok, []} = ic:gen(File2, stdopts(OutDir)++[silent2, {preproc_flags,
- "-I" ++ DataDir}]),
- ok = ic:gen(File4, stdopts(OutDir)++[{preproc_flags,
- "-I" ++ DataDir}] ),
- {ok, []} = ic:gen(File4, stdopts(OutDir)++[silent2, {preproc_flags,
- "-I" ++ DataDir}]),
- ok = compile(OutDir, ifr_reg_unreg_with_inheritence_files()),
- code:add_pathz(OutDir),
- case catch 'oe_reg_m12':'oe_register'() of
- {'EXIT',Reason1} ->
- io:format("IFR object missing detected : ~p~n",[Reason1]),
- true;
- _ ->
- test_server:fail("Failed to detect object missing : IDL:M1:1.0~n")
- end,
- ok = 'oe_reg_m9':'oe_register'(),
- case catch 'oe_reg_m10':'oe_register'() of
- {'EXIT',Reason2} ->
- io:format("IFR object missing detected : ~p~n",[Reason2]),
- true;
- _ ->
- test_server:fail("Failed to detect object missing : IDL:M0:1.0~n")
- end,
- ok = 'oe_reg_m9':'oe_unregister'(),
- code:del_path(OutDir),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: IFR registration with inheritence is correctly registered
-%%-----------------------------------------------------------------
-ifr_inheritence_reg(Config) when is_list(Config) ->
- ?REMAP_EXCEPT(ifr_inh_reg_run(Config)).
-
-ifr_inh_reg_run(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- OutDir = ?OUT(ifr_reg_unreg),
- File0 = filename:join(DataDir, reg_m8),
- File1 = filename:join(DataDir, reg_m9),
- File2 = filename:join(DataDir, reg_m10),
- File3 = filename:join(DataDir, reg_m11),
- File4 = filename:join(DataDir, reg_m12),
- ok = ic:gen(File0, stdopts(OutDir)++[{preproc_flags,
- "-I" ++ DataDir}] ),
- {ok, []} = ic:gen(File0, stdopts(OutDir)++[silent2, {preproc_flags,
- "-I" ++ DataDir}]),
- ok = ic:gen(File1, stdopts(OutDir)++[{preproc_flags,
- "-I" ++ DataDir}] ),
- {ok, []} = ic:gen(File1, stdopts(OutDir)++[silent2, {preproc_flags,
- "-I" ++ DataDir}]),
- ok = ic:gen(File2, stdopts(OutDir)++[{preproc_flags,
- "-I" ++ DataDir}] ),
- {ok, []} = ic:gen(File2, stdopts(OutDir)++[silent2, {preproc_flags,
- "-I" ++ DataDir}]),
- ok = ic:gen(File3, stdopts(OutDir)++[{preproc_flags,
- "-I" ++ DataDir}] ),
- {ok, []} = ic:gen(File3, stdopts(OutDir)++[silent2, {preproc_flags,
- "-I" ++ DataDir}]),
- ok = ic:gen(File4, stdopts(OutDir)++[{preproc_flags,
- "-I" ++ DataDir}] ),
- {ok, []} = ic:gen(File4, stdopts(OutDir)++[silent2, {preproc_flags,
- "-I" ++ DataDir}]),
- ok = compile(OutDir, ifr_reg_unreg_with_inheritence_files()),
- code:add_pathz(OutDir),
- %% OE_register for all files
- ok = 'oe_reg_m8':'oe_register'(),
- ok = 'oe_reg_m9':'oe_register'(),
- ok = 'oe_reg_m10':'oe_register'(),
- ok = 'oe_reg_m11':'oe_register'(),
- ok = 'oe_reg_m12':'oe_register'(),
-
- %% Inheritence registration test
- OE_IFR = orber_ifr:find_repository(),
- %% Interfaces that not inherit from other interfaces
- [] = get_inh(OE_IFR, "IDL:m0/i0:1.0"),
- [] = get_inh(OE_IFR, "IDL:m1/i1:1.0"),
- [] = get_inh(OE_IFR, "IDL:m3/i3:1.0"),
- %% Interfaces that inherit from other interfaces
- ["IDL:m1/i1:1.0"] = get_inh(OE_IFR, "IDL:m2/i2:1.0"),
- ["IDL:m1/i1:1.0","IDL:m2/i2:1.0"] = get_inh(OE_IFR, "IDL:m4/i4:1.0"),
- ["IDL:m3/i3:1.0"] = get_inh(OE_IFR, "IDL:m4/i5:1.0"),
-
- %% OE_unregister for all files
- ok = 'oe_reg_m8':'oe_unregister'(),
- ok = 'oe_reg_m9':'oe_unregister'(),
- ok = 'oe_reg_m10':'oe_unregister'(),
- ok = 'oe_reg_m11':'oe_unregister'(),
- ok = 'oe_reg_m12':'oe_unregister'(),
- code:del_path(OutDir),
- ok.
-
-
-get_inh(OE_IFR,ID) ->
- OE_CURRENT = orber_ifr:lookup_id(OE_IFR,ID),
- INH_LIST = orber_ifr:get_base_interfaces(OE_CURRENT),
- case INH_LIST of
- [] ->
- io:format("~nInterface ~p inherits from nobody.~n",[ID]),
- [];
- _ ->
- print_inh_list_ids(ID, INH_LIST, [])
- end.
-
-print_inh_list_ids(_ID, [], Acc) ->
- lists:reverse(Acc);
-print_inh_list_ids(ID, [H|T], Acc) ->
- io:format("~n"),
- Parent = orber_ifr:get_id(H),
- io:format("Interface ~p inherits from ~p.~n", [ID, Parent]),
- print_inh_list_ids(ID, T, [Parent|Acc]).
-
-
-
-
-stdopts(OutDir) ->
- [{outdir, OutDir}, {maxerrs, infinity}].
-
-
-compile(Dir, Files) ->
- compile(Dir, Files, []).
-
-compile(Dir, Files, Opts) ->
- {ok, Cwd} = file:get_cwd(),
- file:set_cwd(Dir),
- io:format("Changing to ~p~n", [Dir]),
- case catch do_compile(Files, Opts) of
- ok ->
- file:set_cwd(Cwd);
- Err ->
- file:set_cwd(Cwd),
- test_server:fail(Err)
- end.
-
-do_compile([], _Opts) -> ok;
-do_compile([F | Fs], Opts) ->
- io:format("Compiling ~p", [F]),
- case compile:file(F, Opts) of
- ok ->
- io:format(" ok~n", []),
- do_load(F, Opts),
- do_compile(Fs, Opts);
- {ok, _} ->
- io:format(" ok~n", []),
- do_load(F, Opts),
- do_compile(Fs, Opts);
- {ok, _, _} ->
- io:format(" ok~n", []),
- do_load(F, Opts),
- do_compile(Fs, Opts);
- Err ->
- io:format(" error: ~p~n", [Err]),
- Err
- end.
-
-do_load(File, Opts) ->
- case lists:member(load, Opts) of
- true ->
- io:format("Loading file ~p", [File]),
- code:purge(File),
- R = code:load_abs(File),
- io:format("Loaded: ~p", [R]);
- false ->
- ok
- end.
-
-
-to_list(X) when is_atom(X) -> atom_to_list(X);
-to_list(X) -> X.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/ic/test/ic_register_SUITE_data/reg_m10.idl b/lib/ic/test/ic_register_SUITE_data/reg_m10.idl
deleted file mode 100644
index cc9156ae0c..0000000000
--- a/lib/ic/test/ic_register_SUITE_data/reg_m10.idl
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-//
-// IDL for testing register/unregister in the IFR when using included specs
-//
-#include "reg_m9.idl"
-
-typedef sequence<long> Sequence1;
-
-#include "reg_m8.idl"
-
-module m2 {
-
- interface i2 : m1::i1
- {
- short op3( in long a, inout char b, out long c );
- };
-
-
-};
-
diff --git a/lib/ic/test/ic_register_SUITE_data/reg_m11.idl b/lib/ic/test/ic_register_SUITE_data/reg_m11.idl
deleted file mode 100644
index 6a6c49a48e..0000000000
--- a/lib/ic/test/ic_register_SUITE_data/reg_m11.idl
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-//
-// IDL for testing register/unregister in the IFR when using included specs
-//
-
-module m3 {
-
- interface i3
- {
- short op4( in long a, inout char b, out long c );
- };
-
-
-};
-
diff --git a/lib/ic/test/ic_register_SUITE_data/reg_m12.idl b/lib/ic/test/ic_register_SUITE_data/reg_m12.idl
deleted file mode 100644
index 0c5f8083b5..0000000000
--- a/lib/ic/test/ic_register_SUITE_data/reg_m12.idl
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-//
-// IDL for testing register/unregister in the IFR when using included specs
-// Special case with multiple inheritence.
-//
-#include "reg_m10.idl"
-#include "reg_m11.idl"
-
-module m4 {
-
- interface i4 : m2::i2
- {
- short op5( in long a, inout char b, out long c );
- };
-
- interface i5 : m3::i3
- {
- short op6( in long a, inout char b, out long c );
- };
-
-
-};
-
diff --git a/lib/ic/test/ic_register_SUITE_data/reg_m8.idl b/lib/ic/test/ic_register_SUITE_data/reg_m8.idl
deleted file mode 100644
index 5129b6b636..0000000000
--- a/lib/ic/test/ic_register_SUITE_data/reg_m8.idl
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-//
-// IDL for testing register/unregister in the IFR when using included specs
-//
-module m0 {
-
- interface i0 {
- void op1( in short c );
- float op2( in char a);
-
- };
-
-
-};
-
diff --git a/lib/ic/test/ic_register_SUITE_data/reg_m9.idl b/lib/ic/test/ic_register_SUITE_data/reg_m9.idl
deleted file mode 100644
index c077d289b6..0000000000
--- a/lib/ic/test/ic_register_SUITE_data/reg_m9.idl
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1998-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-//
-// IDL for testing register/unregister in the IFR when using included specs
-//
-module m1 {
-
- interface i1 {
- void op1( in short c );
- float op2( in char a);
-
- };
-
-
-};
-
diff --git a/lib/ic/test/ic_smoke.spec b/lib/ic/test/ic_smoke.spec
deleted file mode 100644
index ec3b5758b1..0000000000
--- a/lib/ic/test/ic_smoke.spec
+++ /dev/null
@@ -1 +0,0 @@
-{suites,"../ic_test",[ic_SUITE]}.
diff --git a/lib/ic/test/java_client_erl_server_SUITE.erl b/lib/ic/test/java_client_erl_server_SUITE.erl
deleted file mode 100644
index 9fe52249ba..0000000000
--- a/lib/ic/test/java_client_erl_server_SUITE.erl
+++ /dev/null
@@ -1,319 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%%----------------------------------------------------------------------
-%%% Purpose : Test suite for the backends of the IDL compiler
-%%%----------------------------------------------------------------------
-
--module(java_client_erl_server_SUITE).
--include_lib("common_test/include/ct.hrl").
-
-
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
- init_per_suite/1,end_per_suite/1,
- init_per_testcase/2,end_per_testcase/2]).
--export([marshal_ll/1,marshal_ull/1,
- marshal_l/1,marshal_ul/1,
- marshal_s/1,marshal_us/1,
- marshal_c/1,marshal_wc/1,
- marshal_str/1,
- marshal_any_3/1,marshal_any_2/1]).
-
-
-%% Top of cases
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- cases().
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-cases() ->
- [marshal_ll, marshal_ull, marshal_l, marshal_ul,
- marshal_s, marshal_us, marshal_c, marshal_wc,
- marshal_str, marshal_any_3, marshal_any_2].
-
-init_per_suite(Config) when is_list(Config) ->
- case case code:priv_dir(jinterface) of
- {error,bad_name} ->
- false;
- P ->
- case filelib:wildcard(filename:join(P, "*.jar")) of
- [_|_] ->
- true;
- [] ->
- false
- end
- end
- of
- true ->
- case find_executable(["java"]) of
- false ->
- {skip,"Found no Java VM"};
- Path ->
- [{java,Path}|Config]
- end;
- false ->
- {skip,"No jinterface application"}
- end.
-
-
-find_executable([]) ->
- false;
-find_executable([E|T]) ->
- case os:find_executable(E) of
- false -> find_executable(T);
- Path -> Path
- end.
-
-end_per_suite(Config) -> Config.
-
-
-
-%% Add/remove code path and watchdog before/after each test case.
-%%
-init_per_testcase(_Case, Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- code:add_patha(DataDir),
-
- %% Since other test suites use the module m_i et,al, we have
- %% to make sure we are using the right modules.
- code:purge(m_i),
- code:purge(m_i_impl),
- code:purge(oe_java_erl_test),
- code:load_file(m_i),
- code:load_file(m_i_impl),
- code:load_file(oe_java_erl_test),
-
- WatchDog = test_server:timetrap(test_server:seconds(20)),
- [{watchdog, WatchDog}| Config].
-
-end_per_testcase(_Case, Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- code:del_path(DataDir),
- WatchDog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(WatchDog).
-
-
-
-%%--------------------------------------------------------------------
-%%
-%% Test cases
-
-%% Testing marshalling of IDL long long
-marshal_ll(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- {ok,Server} = m_i:oe_create_link([], {local,marshal_ll}),
- ok = java(proplists:get_value(java, Config), DataDir, "JavaClient",
- ["JavaClient",node(),erlang:get_cookie(),marshal_ll]),
- ok = m_i:stop(Server),
- ok.
-
-%% Testing marshalling of IDL unsigned long long
-marshal_ull(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- {ok,Server} = m_i:oe_create_link([], {local,marshal_ull}),
- ok = java(proplists:get_value(java, Config), DataDir, "JavaClient",
- ["JavaClient",node(),erlang:get_cookie(),marshal_ull]),
- ok = m_i:stop(Server),
- ok.
-
-%% Testing marshalling of IDL long
-marshal_l(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- {ok,Server} = m_i:oe_create_link([], {local,marshal_l}),
- ok = java(proplists:get_value(java, Config), DataDir, "JavaClient",
- ["JavaClient",node(),erlang:get_cookie(),marshal_l]),
- ok = m_i:stop(Server),
- ok.
-
-%% Testing marshalling of IDL unsigned long
-marshal_ul(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- {ok,Server} = m_i:oe_create_link([], {local,marshal_ul}),
- ok = java(proplists:get_value(java, Config), DataDir, "JavaClient",
- ["JavaClient",node(),erlang:get_cookie(),marshal_ul]),
- ok = m_i:stop(Server),
- ok.
-
-%% Testing marshalling of IDL short
-marshal_s(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- {ok,Server} = m_i:oe_create_link([], {local,marshal_s}),
- ok = java(proplists:get_value(java, Config), DataDir, "JavaClient",
- ["JavaClient",node(),erlang:get_cookie(),marshal_s]),
- ok = m_i:stop(Server),
- ok.
-
-%% Testing marshalling of IDL unsigned short
-marshal_us(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- {ok,Server} = m_i:oe_create_link([], {local,marshal_us}),
- ok = java(proplists:get_value(java, Config), DataDir, "JavaClient",
- ["JavaClient",node(),erlang:get_cookie(),marshal_us]),
- ok = m_i:stop(Server),
- ok.
-
-%% Testing marshalling of IDL char
-marshal_c(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- {ok,Server} = m_i:oe_create_link([], {local,marshal_c}),
- ok = java(proplists:get_value(java, Config), DataDir, "JavaClient",
- ["JavaClient",node(),erlang:get_cookie(),marshal_c]),
- ok = m_i:stop(Server),
- ok.
-
-%% Testing marshalling of IDL char
-marshal_wc(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- {ok,Server} = m_i:oe_create_link([], {local,marshal_wc}),
- ok = java(proplists:get_value(java, Config), DataDir, "JavaClient",
- ["JavaClient",node(),erlang:get_cookie(),marshal_wc]),
- ok = m_i:stop(Server),
- ok.
-
-%% Testing marshalling of IDL string
-marshal_str(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- {ok,Server} = m_i:oe_create_link([], {local,marshal_str}),
- ok = java(proplists:get_value(java, Config), DataDir,
-%%% "-DOtpConnection.trace=4 "
- "JavaClient",
- ["JavaClient",node(),erlang:get_cookie(),marshal_str]),
- ok = m_i:stop(Server),
- ok.
-
-%% Testing marshalling of IDL any
-marshal_any_3(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- {ok,Server} = m_i:oe_create_link([], {local,marshal_any_3}),
- ok = java(proplists:get_value(java, Config), DataDir, "JavaClient",
- ["JavaClient",node(),erlang:get_cookie(),marshal_any_3]),
- ok = m_i:stop(Server),
- ok.
-
-marshal_any_2(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- {ok,Server} = m_i:oe_create_link([], {local,marshal_any_2}),
- ok = java(proplists:get_value(java, Config), DataDir, "JavaClient",
- ["JavaClient",node(),erlang:get_cookie(),marshal_any_2]),
- ok = m_i:stop(Server),
- ok.
-
-%%--------------------------------------------------------------------
-%%
-%% Utilities
-
-
-java(Java, Dir, ClassAndArgs) ->
- cmd(Java++" -classpath \""++classpath(Dir)++"\" "++ClassAndArgs).
-
-java(Java, Dir, Class, Args) ->
- java(Java, Dir, Class++" "++to_string(Args)).
-
-to_string([H|T]) when is_integer(H) ->
- integer_to_list(H)++" "++to_string(T);
-to_string([H|T]) when is_atom(H) ->
- atom_to_list(H)++" "++to_string(T);
-to_string([H|T]) when is_list(H) ->
- lists:flatten(H)++" "++to_string(T);
-to_string([]) -> [].
-
-% javac(Dir, File) ->
-% cmd("javac -d "++Dir++" -classpath "++classpath(Dir)++" "++
-% filename:join(Dir, File)).
-
-classpath(Dir) ->
- PS =
- case os:type() of
- {win32, _} -> ";";
- _ -> ":"
- end,
- Dir++PS++
- filename:join([code:lib_dir(ic),"priv","ic.jar"])++PS++
- filename:join([code:lib_dir(jinterface),"priv","OtpErlang.jar"])++PS++
- os:getenv("CLASSPATH", "").
-
-cmd(Cmd) ->
- PortOpts = [{line,80},eof,exit_status,stderr_to_stdout],
- io:format("<cmd> ~ts~n", [Cmd]),
- case catch open_port({spawn,Cmd}, PortOpts) of
- Port when is_port(Port) ->
- Result = cmd_loop(Port, []),
- io:format("<cmd=~w>~n", [Result]),
- case Result of
- 0 -> ok;
- ExitCode when is_integer(ExitCode) -> {error,ExitCode};
- Error -> Error
- end;
- {'EXIT',Reason} ->
- {error,Reason}
- end.
-
-cmd_loop(Port, Line) ->
- receive
- {Port,eof} ->
- receive
- {Port,{exit_status,ExitStatus}} ->
- ExitStatus
- after 1 ->
- undefined
- end;
- {Port,{exit_status,ExitStatus}} ->
- receive
- {Port,eof} ->
- ok after 1 -> ok end,
- ExitStatus;
- {Port,{data,{Tag,Data}}} ->
- case Tag of
- eol ->
- io:put_chars([Line|cr_to_nl(Data)]),
- io:nl(),
- cmd_loop(Port, []);
- noeol ->
- cmd_loop(Port, [Line|cr_to_nl(Data)])
- end;
- {'EXIT',Port,Reason} ->
- {error,Reason};
- Other ->
- io:format("WARNING: Unexpected at ~s:~p: ~p~n",
- [?MODULE_STRING,?LINE,Other]),
- cmd_loop(Port, Line)
- end.
-
-%% Convert lonely CR to NL, and CRLF to NL
-%%
-cr_to_nl([$\r,$\n|T]) ->
- [$\n|cr_to_nl(T)];
-cr_to_nl([$\r|T]) ->
- [$\n|cr_to_nl(T)];
-cr_to_nl([C|T]) ->
- [C|cr_to_nl(T)];
-cr_to_nl([]) ->
- [].
diff --git a/lib/ic/test/java_client_erl_server_SUITE_data/JavaClient.java b/lib/ic/test/java_client_erl_server_SUITE_data/JavaClient.java
deleted file mode 100644
index 8092d7c627..0000000000
--- a/lib/ic/test/java_client_erl_server_SUITE_data/JavaClient.java
+++ /dev/null
@@ -1,760 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 2003-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-public class JavaClient {
-
- public static void main(String[] argv)
- {
- System.out.println("Hello World!");
- if (argv.length < 4) {
- System.out.println("Too few arguments!");
- System.exit(1);
- }
- // for (int j = 0; j < argv.length; j++)
- // System.out.println(argv[j]);
- try {
- if (argv[3].equals("marshal_ll")) {
- System.out.println("marshal_ll");
- marshal_ll(argv[0], argv[1], argv[2], argv[3]);
- }
- else if (argv[3].equals("marshal_ull")) {
- marshal_ull(argv[0], argv[1], argv[2], argv[3]);
- }
- else if (argv[3].equals("marshal_l")) {
- marshal_l(argv[0], argv[1], argv[2], argv[3]);
- }
- else if (argv[3].equals("marshal_ul")) {
- marshal_ul(argv[0], argv[1], argv[2], argv[3]);
- }
- else if (argv[3].equals("marshal_s")) {
- marshal_s(argv[0], argv[1], argv[2], argv[3]);
- }
- else if (argv[3].equals("marshal_us")) {
- marshal_us(argv[0], argv[1], argv[2], argv[3]);
- }
- else if (argv[3].equals("marshal_c")) {
- marshal_c(argv[0], argv[1], argv[2], argv[3]);
- }
- else if (argv[3].equals("marshal_wc")) {
- marshal_wc(argv[0], argv[1], argv[2], argv[3]);
- }
- else if (argv[3].equals("marshal_str")) {
- marshal_str(argv[0], argv[1], argv[2], argv[3]);
- }
- else if (argv[3].equals("marshal_any_3")) {
- marshal_any_3(argv[0], argv[1], argv[2], argv[3]);
- }
- else if (argv[3].equals("marshal_any_2")) {
- marshal_any_2(argv[0], argv[1], argv[2], argv[3]);
- }
- else {
- System.out.println("Unknown test: "+argv[3]);
- System.exit(2);
- }
- } catch (java.lang.Exception e) {
- System.out.println("Exception!: "+e);
- System.exit(3);
- }
- System.exit(0);
- }
-
-
-
- static void marshal_ll(String selfNode, String peerNode,
- String cookie, String serverName)
- throws java.lang.Exception
- {
- m._iStub i = new m._iStub(selfNode, peerNode, cookie, serverName);
- // Just warming up..
- System.out.println("Just warming up.."+i);
- verify_ll(i, 3, 2, 1);
- verify_ll(i, 5, 4, 3);
- verify_ll(i, -128, 0, 1);
- // The small integer border
- verify_ll(i, 255, 0, 1);
- verify_ll(i, 256, 0, 1);
- // The integer border
- verify_ll(i, (1L<<26)-1L, 0L, 1);
- verify_ll(i, 1L<<26, 0L, 1);
- verify_ll(i, -(1L<<26), 0L, 1);
- verify_ll(i, (1L<<27)-1L, 0L, 1);
- verify_ll(i, 1L<<27, 0L, 1);
- verify_ll(i, -(1L<<27), 0L, 1);
- // Bignum byte borders
- verify_ll(i, (1L<<32)-1L, 0L, 1);
- verify_ll(i, 1L<<32, 0L, 1);
- verify_ll(i, -(1L<<32)+1L, 0L, 1);
- verify_ll(i, -(1L<<32), 0L, 1);
- verify_ll(i, (1L<<40)-1L, 0L, 1);
- verify_ll(i, 1L<<40, 0L, 1);
- verify_ll(i, -(1L<<40)+1L, 0L, 1);
- verify_ll(i, -(1L<<40), 0L, 1);
- verify_ll(i, (1L<<48)-1L, 0L, 1);
- verify_ll(i, 1L<<48, 0L, 1);
- verify_ll(i, -(1L<<48)+1L, 0L, 1);
- verify_ll(i, -(1L<<48), 0L, 1);
- // Java long border
- verify_ll(i, java.lang.Long.MAX_VALUE, 0L, 1);
- verify_ll(i, java.lang.Long.MIN_VALUE, 0L, 1);
- verify_ll(i, -1L, 0L, 1);
- // Impossible decodes
- verify_ll_bad(i, java.lang.Long.MAX_VALUE, -1L, 1);
- verify_ll_bad(i, java.lang.Long.MIN_VALUE, 1L, 1);
- verify_ll_bad(i, java.lang.Long.MIN_VALUE, 0L, -1);
- verify_ll_bad(i, java.lang.Long.MAX_VALUE, -1L, 2);
- verify_ll_bad(i, java.lang.Long.MIN_VALUE, 0L, 2);
- }
-
- static void marshal_ull(String selfNode, String peerNode,
- String cookie, String serverName)
- throws java.lang.Exception
- {
- m._iStub i = new m._iStub(selfNode, peerNode, cookie, serverName);
- // Just warming up..
- verify_ull(i, 3, 2, 1);
- verify_ull(i, 5, 4, 3);
- // The small integer border
- verify_ull(i, 255, 0, 1);
- verify_ull(i, 256, 0, 1);
- // The integer border
- verify_ull(i, (1L<<26)-1L, 0L, 1);
- verify_ull(i, 1L<<26, 0L, 1);
- verify_ull(i, (1L<<27)-1L, 0L, 1);
- verify_ull(i, 1L<<27, 0L, 1);
- // Bignum byte borders
- verify_ull(i, (1L<<32)-1L, 0L, 1);
- verify_ull(i, 1L<<32, 0L, 1);
- verify_ull(i, (1L<<40)-1L, 0L, 1);
- verify_ull(i, 1L<<40, 0L, 1);
- verify_ull(i, (1L<<48)-1L, 0L, 1);
- verify_ull(i, 1L<<48, 0L, 1);
- // Java long border
- verify_ull(i, java.lang.Long.MAX_VALUE, 0L, 1);
- verify_ull(i, java.lang.Long.MIN_VALUE, 0L, 1);
- verify_ull(i, -1L, 0L, 1);
- verify_ull(i, java.lang.Long.MAX_VALUE,
- java.lang.Long.MIN_VALUE, 1);
- // Impossible decodes
- verify_ull_bad(i, -1L, -1L, 1);
- verify_ull_bad(i, java.lang.Long.MAX_VALUE, -1L, 2);
- }
-
- static void marshal_l(String selfNode, String peerNode,
- String cookie, String serverName)
- throws java.lang.Exception
- {
- m._iStub i = new m._iStub(selfNode, peerNode, cookie, serverName);
- // Just warming up..
- verify_l(i, 3, 2, 1);
- verify_l(i, 5, 4, 3);
- verify_l(i, -128, 0, 1);
- // The small integer border
- verify_l(i, 255, 0, 1);
- verify_l(i, 256, 0, 1);
- // The integer border
- verify_l(i, (1<<26)-1, 0, 1);
- verify_l(i, 1<<26, 0, 1);
- verify_l(i, -(1<<26), 0, 1);
- verify_l(i, (1<<27)-1, 0, 1);
- verify_l(i, 1<<27, 0, 1);
- verify_l(i, -(1<<27), 0, 1);
- // Java int border
- verify_l(i, java.lang.Integer.MAX_VALUE, 0, 1);
- verify_l(i, java.lang.Integer.MIN_VALUE, 0, 1);
- // Impossible decodes
- verify_l_bad(i, java.lang.Integer.MAX_VALUE, -1, 1);
- verify_l_bad(i, java.lang.Integer.MIN_VALUE, 1, 1);
- verify_l_bad(i, java.lang.Integer.MIN_VALUE, 0, -1);
- }
-
- static void marshal_ul(String selfNode, String peerNode,
- String cookie, String serverName)
- throws java.lang.Exception
- {
- m._iStub i = new m._iStub(selfNode, peerNode, cookie, serverName);
- // Just warming up..
- verify_ul(i, 3, 2, 1);
- verify_ul(i, 5, 4, 3);
- // The small integer border
- verify_ul(i, 255, 0, 1);
- verify_ul(i, 256, 0, 1);
- // The integer border
- verify_ul(i, (1<<26)-1, 0, 1);
- verify_ul(i, 1<<26, 0, 1);
- verify_ul(i, (1<<27)-1, 0, 1);
- verify_ul(i, 1<<27, 0, 1);
- // Java int border
- verify_ul(i, java.lang.Integer.MAX_VALUE, 0, 1);
- verify_ul(i, java.lang.Integer.MIN_VALUE, 0, 1);
- verify_ul(i, -1, 0, 1);
- verify_ul(i, java.lang.Integer.MAX_VALUE,
- java.lang.Integer.MIN_VALUE, 1);
- // Impossible decodes
- verify_ul_bad(i, -1, -1, 1);
- }
-
- static void marshal_s(String selfNode, String peerNode,
- String cookie, String serverName)
- throws java.lang.Exception
- {
- m._iStub i = new m._iStub(selfNode, peerNode, cookie, serverName);
- // Just warming up..
- verify_s(i, 3, 2, 1);
- verify_s(i, 5, 4, 3);
- verify_s(i, -128, 0, 1);
- // The small integer border
- verify_s(i, 255, 0, 1);
- verify_s(i, 256, 0, 1);
- // Java short border
- verify_s(i, java.lang.Short.MAX_VALUE, 0, 1);
- verify_s(i, java.lang.Short.MIN_VALUE, 0, 1);
- // Impossible decodes
- verify_s_bad(i, java.lang.Short.MAX_VALUE, -1, 1);
- verify_s_bad(i, java.lang.Short.MIN_VALUE, 1, 1);
- verify_s_bad(i, java.lang.Short.MIN_VALUE, 0, -1);
- }
-
- static void marshal_us(String selfNode, String peerNode,
- String cookie, String serverName)
- throws java.lang.Exception
- {
- m._iStub i = new m._iStub(selfNode, peerNode, cookie, serverName);
- // Just warming up..
- verify_us(i, 3, 2, 1);
- verify_us(i, 5, 4, 3);
- // The small integer border
- verify_us(i, 255, 0, 1);
- verify_us(i, 256, 0, 1);
- // Java short border
- verify_us(i, java.lang.Short.MAX_VALUE, 0, 1);
- verify_us(i, java.lang.Short.MIN_VALUE, 0, 1);
- verify_us(i, -1, 0, 1);
- verify_us(i, java.lang.Short.MAX_VALUE,
- java.lang.Short.MIN_VALUE, 1);
- // Impossible decodes
- verify_us_bad(i, -1, -1, 1);
- }
-
- static void marshal_c(String selfNode, String peerNode,
- String cookie, String serverName)
- throws java.lang.Exception
- {
- m._iStub i = new m._iStub(selfNode, peerNode, cookie, serverName);
- // Just warming up..
- verify_c(i, '\3', '\2', 1);
- verify_c(i, '\5', '\4', 3);
- // The small integer border
- verify_c(i, '\u00FF', '\0', 1);
- verify_c(i, '\u0100', '\0', 1);
- // Java char border
- verify_c(i, java.lang.Character.MAX_VALUE, '\0', 1);
- verify_c(i, java.lang.Character.MIN_VALUE, '\0', 1);
- verify_c(i, java.lang.Character.MAX_VALUE,
- java.lang.Character.MIN_VALUE, 1);
- // Impossible decodes
- verify_c_bad(i, '\u8000', '\0', 2);
- }
-
- static void marshal_wc(String selfNode, String peerNode,
- String cookie, String serverName)
- throws java.lang.Exception
- {
- m._iStub i = new m._iStub(selfNode, peerNode, cookie, serverName);
- // Just warming up..
- verify_wc(i, '\3', '\2', 1);
- verify_wc(i, '\5', '\4', 3);
- // The small integer border
- verify_wc(i, '\u00FF', '\0', 1);
- verify_wc(i, '\u0100', '\0', 1);
- // Java char border
- verify_wc(i, java.lang.Character.MAX_VALUE, '\0', 1);
- verify_wc(i, java.lang.Character.MIN_VALUE, '\0', 1);
- verify_wc(i, java.lang.Character.MAX_VALUE,
- java.lang.Character.MIN_VALUE, 1);
- // Impossible decodes
- verify_c_bad(i, '\u8000', '\0', 2);
- }
-
- static void marshal_str(String selfNode, String peerNode,
- String cookie, String serverName)
- throws java.lang.Exception
- {
- m._iStub i = new m._iStub(selfNode, peerNode, cookie, serverName);
- // Just warming up..
- verify_str(i, 100, 100);
- verify_str(i, 100, 1);
- // Erlang string border
- verify_str(i, 65535, 1);
- verify_str(i, 2, 65535);
- // Erlang string border out
- verify_str(i, 65536, 1);
- verify_str(i, 65536, 65536);
- }
-
- static void marshal_any_3(String selfNode, String peerNode,
- String cookie, String serverName)
- throws java.lang.Exception
- {
- m._iStub i = new m._iStub(selfNode, peerNode, cookie, serverName);
- com.ericsson.otp.ic.Any x = new com.ericsson.otp.ic.Any();
- com.ericsson.otp.ic.Any y = new com.ericsson.otp.ic.Any();
- com.ericsson.otp.ic.Any z = new com.ericsson.otp.ic.Any();
-
- x.insert_longlong(java.lang.Long.MAX_VALUE);
- y.insert_longlong(1L);
- z.insert_longlong(java.lang.Long.MAX_VALUE-1L);
- System.out.println("verify_any_3 longlong max");
- verify_any_3(i, x, y, 1, z);
-
- x.insert_longlong(java.lang.Long.MIN_VALUE);
- y.insert_longlong(-1L);
- z.insert_longlong(java.lang.Long.MIN_VALUE+1L);
- System.out.println("verify_any_3 longlong min");
- verify_any_3(i, x, y, 1, z);
-
- x.insert_ulonglong(-1L);
- y.insert_longlong(1L);
- z.insert_ulonglong(-2L);
- System.out.println("verify_any_3 ulonglong max");
- verify_any_3(i, x, y, 1, z);
-
- x.insert_ulonglong(0L);
- y.insert_longlong(-1L);
- z.insert_ulonglong(1L);
- System.out.println("verify_any_3 ulonglong min");
- verify_any_3(i, x, y, 1, z);
-
- x.insert_long(java.lang.Integer.MAX_VALUE);
- y.insert_long(1);
- z.insert_long(java.lang.Integer.MAX_VALUE-1);
- System.out.println("verify_any_3 long max");
- verify_any_3(i, x, y, 1, z);
-
- x.insert_long(java.lang.Integer.MIN_VALUE);
- y.insert_long(-1);
- z.insert_long(java.lang.Integer.MIN_VALUE+1);
- System.out.println("verify_any_3 long min");
- verify_any_3(i, x, y, 1, z);
-
- x.insert_ulong(-1);
- y.insert_long(1);
- z.insert_ulong(-2);
- System.out.println("verify_any_3 ulong max");
- verify_any_3(i, x, y, 1, z);
-
- x.insert_ulong(0);
- y.insert_long(-1);
- z.insert_ulong(1);
- System.out.println("verify_any_3 ulong min");
- verify_any_3(i, x, y, 1, z);
-
- x.insert_short(java.lang.Short.MAX_VALUE);
- y.insert_short((short)1);
- z.insert_short((short)(java.lang.Short.MAX_VALUE-1));
- System.out.println("verify_any_3 short max");
- verify_any_3(i, x, y, 1, z);
-
- x.insert_short(java.lang.Short.MIN_VALUE);
- y.insert_short((short)-1);
- z.insert_short((short)(java.lang.Short.MIN_VALUE+1));
- System.out.println("verify_any_3 short min");
- verify_any_3(i, x, y, 1, z);
-
- x.insert_ushort((short)-1);
- y.insert_short((short)1);
- z.insert_ushort((short)-2);
- System.out.println("verify_any_3 ushort max");
- verify_any_3(i, x, y, 1, z);
-
- x.insert_ushort((short)0);
- y.insert_short((short)-1);
- z.insert_ushort((short)1);
- System.out.println("verify_any_3 ushort min");
- verify_any_3(i, x, y, 1, z);
-
- x.insert_char('\377');
- y.insert_char('\1');
- z.insert_char('\376');
- System.out.println("verify_any_3 char max");
- verify_any_3(i, x, y, 1, z);
-
- x.insert_wchar('\uFFFF');
- y.insert_wchar('\u0001');
- z.insert_wchar('\uFFFE');
- System.out.println("verify_any_3 char max");
- verify_any_3(i, x, y, 1, z);
- }
-
- static void marshal_any_2(String selfNode, String peerNode,
- String cookie, String serverName)
- throws java.lang.Exception
- {
- m._iStub i = new m._iStub(selfNode, peerNode, cookie, serverName);
- m.s s = new m.s();
- com.ericsson.otp.ic.Any a = new com.ericsson.otp.ic.Any();
- //
- s.ull_x = -1L;
- s.ll_x = java.lang.Long.MAX_VALUE;
- s.ll_y = 1L;
- s.ull_z = -2L;
- s.ll_z = java.lang.Long.MAX_VALUE-1L;
- //
- s.ul_x = -1;
- s.l_x = java.lang.Integer.MAX_VALUE;
- s.l_y = 1;
- s.ul_z = -2;
- s.l_z = java.lang.Integer.MAX_VALUE-1;
- //
- s.us_x = (short)-1;
- s.s_x = java.lang.Short.MAX_VALUE;
- s.s_y = (short)1;
- s.us_z = (short)-2;
- s.s_z = (short)(java.lang.Short.MAX_VALUE-1);
- //
- s.c_x = '\377';
- s.c_y = '\1';
- s.c_z = '\376';
- s.wc_x = '\uFFFF';
- s.wc_y = '\u0001';
- s.wc_z = '\uFFFE';
- m.sHelper.insert(a, s);
- verify_any_2(i, a, 1);
-
- s.ull_x = 0L;
- s.ll_x = java.lang.Long.MIN_VALUE;
- s.ll_y = -1L;
- s.ull_z = 1L;
- s.ll_z = java.lang.Long.MIN_VALUE+1L;
- //
- s.ul_x = 0;
- s.l_x = java.lang.Integer.MIN_VALUE;
- s.l_y = -1;
- s.ul_z = 1;
- s.l_z = java.lang.Integer.MIN_VALUE+1;
- //
- s.us_x = (short)0;
- s.s_x = java.lang.Short.MIN_VALUE;
- s.s_y = (short)-1;
- s.us_z = (short)1;
- s.s_z = (short)(java.lang.Short.MIN_VALUE+1);
- //
- s.c_x = '\0';
- s.c_y = '\0';
- s.c_z = '\0';
- s.wc_x = '\u0000';
- s.wc_y = '\u0000';
- s.wc_z = '\u0000';
- m.sHelper.insert(a, s);
- verify_any_2(i, a, 1);
- }
-
-
- static void verify_ll(m._iStub i, long x, long y, int b)
- throws java.lang.Exception
- {
- m.s a = new m.s();
- System.out.println("verify_ll "+a);
- a.ll_x = x;
- a.ll_y = y;
- long expected = (x - y)*(short)b;
- long result = i.marshal_ll(a, (short)b);
- if (result == expected) {
- System.out.println("verify_ll("+x+", "+y+", "+b+") => "
- +result);
- } else {
- System.out.println("verify_ll("+x+", "+y+", "+b+") => "
- +result+" != "+expected);
- System.exit(4);
- }
- }
-
- static void verify_ull(m._iStub i, long x, long y, int b)
- throws java.lang.Exception
- {
- m.s a = new m.s();
- a.ull_x = x;
- a.ll_y = y;
- long expected = (x - y)*(short)b;
- long result = i.marshal_ull(a, (short)b);
- if (result == expected) {
- System.out.println("verify_ull("+x+", "+y+", "+b+") => "
- +result);
- } else {
- System.out.println("verify_ull("+x+", "+y+", "+b+") => "
- +result+" != "+expected);
- System.exit(4);
- }
- }
-
- static void verify_l(m._iStub i, int x, int y, int b)
- throws java.lang.Exception
- {
- m.s a = new m.s();
- a.l_x = x;
- a.l_y = y;
- int expected = (x - y)*(short)b;
- int result = i.marshal_l(a, (short)b);
- if (result == expected) {
- System.out.println("verify_l("+x+", "+y+", "+b+") => "
- +result);
- } else {
- System.out.println("verify_l("+x+", "+y+", "+b+") => "
- +result+" != "+expected);
- System.exit(4);
- }
- }
-
- static void verify_ul(m._iStub i, int x, int y, int b)
- throws java.lang.Exception
- {
- m.s a = new m.s();
- a.ul_x = x;
- a.l_y = y;
- int expected = (x - y)*(short)b;
- int result = i.marshal_ul(a, (short)b);
- if (result == expected) {
- System.out.println("verify_ul("+x+", "+y+", "+b+") => "
- +result);
- } else {
- System.out.println("verify_ul("+x+", "+y+", "+b+") => "
- +result+" != "+expected);
- System.exit(4);
- }
- }
-
- static void verify_s(m._iStub i, int x, int y, int b)
- throws java.lang.Exception
- {
- m.s a = new m.s();
- a.s_x = (short)x;
- a.s_y = (short)y;
- short expected = (short)((x - y)*(short)b);
- short result = i.marshal_s(a, (short)b);
- if (result == expected) {
- System.out.println("verify_s("+x+", "+y+", "+b+") => "
- +result);
- } else {
- System.out.println("verify_s("+x+", "+y+", "+b+") => "
- +result+" != "+expected);
- System.exit(4);
- }
- }
-
- static void verify_us(m._iStub i, int x, int y, int b)
- throws java.lang.Exception
- {
- m.s a = new m.s();
- a.us_x = (short)x;
- a.s_y = (short)y;
- short expected = (short)((x - y)*(short)b);
- short result = i.marshal_us(a, (short)b);
- if (result == expected) {
- System.out.println("verify_us("+x+", "+y+", "+b+") => "
- +result);
- } else {
- System.out.println("verify_us("+x+", "+y+", "+b+") => "
- +result+" != "+expected);
- System.exit(4);
- }
- }
-
- static void verify_c(m._iStub i, char x, char y, int b)
- throws java.lang.Exception
- {
- m.s a = new m.s();
- a.c_x = x;
- a.c_y = y;
- char expected = (char)(((int)x - (int)y)*(short)b);
- char result = i.marshal_c(a, (short)b);
- if (result == expected) {
- System.out.println("verify_c("+x+", "+y+", "+b+") => "
- +result);
- } else {
- System.out.println("verify_c("+x+", "+y+", "+b+") => "
- +result+" != "+expected);
- System.exit(4);
- }
- }
-
- static void verify_wc(m._iStub i, char x, char y, int b)
- throws java.lang.Exception
- {
- m.s a = new m.s();
- a.wc_x = x;
- a.wc_y = y;
- char expected = (char)(((int)x - (int)y)*(short)b);
- char result = i.marshal_wc(a, (short)b);
- if (result == expected) {
- System.out.println("verify_wc("+x+", "+y+", "+b+") => "
- +result);
- } else {
- System.out.println("verify_wc("+x+", "+y+", "+b+") => "
- +result+" != "+expected);
- System.exit(4);
- }
- }
-
- static void verify_str(m._iStub i, int a_len, int b_len)
- throws java.lang.Exception
- {
- String a = mk_str(a_len);
- String b = mk_str(b_len);
- String expected = a + b;
- String result = i.strcat(a, b);
- if (result.equals(expected)) {
- System.out.println("verify_str(\""+a+"\", \""+b+"\") => \""
- +result+"\"");
- } else {
- System.out.println("verify_str(\""+a+"\", \""+b+"\") => \""
- +result+"\" != \""+expected.length()+"\"");
- System.exit(4);
- }
- }
-
- static String mk_str(int len)
- throws StringIndexOutOfBoundsException
- {
- StringBuffer s = new StringBuffer();
- // 17 characters is prime relative all bases of two - on purpose
- do s.append("qwertyuiopasdfghj"); while (s.length() < len);
- return s.substring(0, len);
- }
-
- static void verify_any_3(m._iStub i,
- com.ericsson.otp.ic.Any x,
- com.ericsson.otp.ic.Any y,
- int b,
- com.ericsson.otp.ic.Any expected)
- throws java.lang.Exception
- {
- com.ericsson.otp.ic.Any result = i.marshal_any_3(x, y, (short)b);
- if (! expected.equal(result)) {
- System.exit(4);
- }
- }
-
- static void verify_any_2(m._iStub i, com.ericsson.otp.ic.Any a, int b)
- throws java.lang.Exception
- {
- com.ericsson.otp.ic.Any result = i.marshal_any_2(a, (short)b);
- if (! a.equal(result)) {
- System.exit(4);
- }
- }
-
-
-
- static void verify_ll_bad(m._iStub i, long x, long y, int b)
- throws java.lang.Exception
- {
- try {
- verify_ll(i, x, y, b);
- System.out.println("Expected exception missing!");
- System.exit(5);
- } catch (com.ericsson.otp.erlang.OtpErlangDecodeException e) {
- System.out.println("Expected exception: "+e);
- }
- }
-
- static void verify_ull_bad(m._iStub i, long x, long y, int b)
- throws java.lang.Exception
- {
- try {
- verify_ull(i, x, y, b);
- System.out.println("Expected exception missing!");
- System.exit(5);
- } catch (com.ericsson.otp.erlang.OtpErlangDecodeException e) {
- System.out.println("Expected exception: "+e);
- }
- }
-
- static void verify_l_bad(m._iStub i, int x, int y, int b)
- throws java.lang.Exception
- {
- try {
- verify_l(i, x, y, b);
- System.out.println("Expected exception missing!");
- System.exit(5);
- } catch (com.ericsson.otp.erlang.OtpErlangDecodeException e) {
- System.out.println("Expected exception: "+e);
- }
- }
-
- static void verify_ul_bad(m._iStub i, int x, int y, int b)
- throws java.lang.Exception
- {
- try {
- verify_ul(i, x, y, b);
- System.out.println("Expected exception missing!");
- System.exit(5);
- } catch (com.ericsson.otp.erlang.OtpErlangDecodeException e) {
- System.out.println("Expected exception: "+e);
- }
- }
-
- static void verify_s_bad(m._iStub i, int x, int y, int b)
- throws java.lang.Exception
- {
- try {
- verify_s(i, x, y, b);
- System.out.println("Expected exception missing!");
- System.exit(5);
- } catch (com.ericsson.otp.erlang.OtpErlangDecodeException e) {
- System.out.println("Expected exception: "+e);
- }
- }
-
- static void verify_us_bad(m._iStub i, int x, int y, int b)
- throws java.lang.Exception
- {
- try {
- verify_us(i, x, y, b);
- System.out.println("Expected exception missing!");
- System.exit(5);
- } catch (com.ericsson.otp.erlang.OtpErlangDecodeException e) {
- System.out.println("Expected exception: "+e);
- }
- }
-
- static void verify_c_bad(m._iStub i, char x, char y, int b)
- throws java.lang.Exception
- {
- try {
- verify_c(i, x, y, b);
- System.out.println("Expected exception missing!");
- System.exit(5);
- } catch (com.ericsson.otp.erlang.OtpErlangDecodeException e) {
- System.out.println("Expected exception: "+e);
- }
- }
-
- static void verify_wc_bad(m._iStub i, char x, char y, int b)
- throws java.lang.Exception
- {
- try {
- verify_wc(i, x, y, b);
- System.out.println("Expected exception missing!");
- System.exit(5);
- } catch (com.ericsson.otp.erlang.OtpErlangDecodeException e) {
- System.out.println("Expected exception: "+e);
- }
- }
-
-}
diff --git a/lib/ic/test/java_client_erl_server_SUITE_data/Makefile.src b/lib/ic/test/java_client_erl_server_SUITE_data/Makefile.src
deleted file mode 100644
index bcc59e87db..0000000000
--- a/lib/ic/test/java_client_erl_server_SUITE_data/Makefile.src
+++ /dev/null
@@ -1,101 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2003-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-# Makefile.src for java_client_erl_server test
-# Note: This file *must* work for both Unix and Windows
-#
-# We use both `rm' (Unix) and `del' (Windows) for removing files, but
-# with a `-' in front so that the error in not finding `rm' (`del') on
-# Windows (Unix) is ignored.
-#
-# VxWorks? XXX
-#
-
-.SUFFIXES:
-.SUFFIXES: .erl .idl .@EMULATOR@ .java
-
-
-JAVAC = @JAVAC@
-ERLC = erlc
-
-# ic variables available from ts:
-#
-# ic_libpath: @ic_libpath@
-# ic_include_path: @ic_include_path@
-
-IC_INCLUDE_PATH = @ic_include_path@
-IC_CLASSPATH = @ic_classpath@
-
-JINTERFACE_CLASSPATH = @jinterface_classpath@
-
-CLASSPATH = .@PS@$(IC_CLASSPATH)@PS@$(JINTERFACE_CLASSPATH)@PS@
-
-GEN_JAVA_FILES = \
- m@DS@_iImplBase.java \
- m@DS@_iStub.java \
-
-GEN_HRL_FILES = \
- m.hrl \
- m_i.hrl \
- oe_java_erl_test.hrl
-
-GEN_ERL_FILES = \
- m_i.erl \
- oe_java_erl_test.erl
-
-JAVA_FILES = $(GEN_JAVA_FILES) JavaClient.java
-CLASS_FILES = $(JAVA_FILES:.java=.class)
-ERL_FILES = $(GEN_ERL_FILES) m_i_impl.erl
-EBINS = $(ERL_FILES:.erl=.@EMULATOR@)
-
-@IFEQ@ (@jinterface@,not_found)
-all:
-@ELSE@
-all: $(CLASS_FILES) $(EBINS)
-@ENDIF@
-
-$(GEN_ERL_FILES) $(GEN_HRL_FILES): java_erl_test.built_erl
-$(GEN_JAVA_FILES): java_erl_test.built_java
-$(CLASS_FILES): $(GEN_JAVA_FILES)
-$(EBINS): $(GEN_ERL_FILES) $(GEN_HRL_FILES)
-
-clean:
- -rm -f $(GEN_JAVA_FILES) $(CLASS_FILES) \
- $(GEN_ERL_FILES) $(GEN_HRL_FILES) $(EBINS) \
- java_erl_test.built_erl java_erl_test.built_java
- -del /F /Q $(GEN_JAVA_FILES) $(CLASS_FILES) \
- $(GEN_ERL_FILES) $(GEN_HRL_FILES) $(EBINS) \
- java_erl_test.built_erl java_erl_test.built_java
-
-java_erl_test.built_java: java_erl_test.idl
- $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,java}" java_erl_test.idl
- echo done > java_erl_test.built_java
-
-$(CLASS_FILES) : $(JAVA_FILES)
- $(JAVAC) -classpath $(CLASSPATH) $(JAVA_FILES)
-
-java_erl_test.built_erl: java_erl_test.idl
- $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,erl_genserv}" java_erl_test.idl
- echo done > java_erl_test.built_erl
-
-.erl.@EMULATOR@:
- $(ERLC) -I $(IC_INCLUDE_PATH) $<
diff --git a/lib/ic/test/java_client_erl_server_SUITE_data/java_erl_test.idl b/lib/ic/test/java_client_erl_server_SUITE_data/java_erl_test.idl
deleted file mode 100644
index 55194cf911..0000000000
--- a/lib/ic/test/java_client_erl_server_SUITE_data/java_erl_test.idl
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 2003-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-module m {
-
- struct s {
- long long ll_x;
- unsigned long long ull_x;
- long long ll_y;
- long long ll_z;
- unsigned long long ull_z;
-
- long l_x;
- unsigned long ul_x;
- long l_y;
- long l_z;
- unsigned long ul_z;
-
- short s_x;
- unsigned short us_x;
- short s_y;
- short s_z;
- unsigned short us_z;
-
- char c_x;
- char c_y;
- char c_z;
-
- wchar wc_x;
- wchar wc_y;
- wchar wc_z;
- };
-
- interface i {
- long long marshal_ll( in s a, in short b );
- unsigned long long marshal_ull( in s a, in short b );
-
- long marshal_l( in s a, in short b );
- unsigned long marshal_ul( in s a, in short b );
-
- short marshal_s( in s a, in short b );
- unsigned short marshal_us( in s a, in short b );
-
- char marshal_c( in s a, in short b );
- wchar marshal_wc( in s a, in short b );
-
- string strcat( in string a, in string b );
-
- any marshal_any_3( in any x, in any y, in short b );
- any marshal_any_2( in any a, in short b );
- };
-
-};
diff --git a/lib/ic/test/java_client_erl_server_SUITE_data/m_i_impl.erl b/lib/ic/test/java_client_erl_server_SUITE_data/m_i_impl.erl
deleted file mode 100644
index 31b4c1dd7a..0000000000
--- a/lib/ic/test/java_client_erl_server_SUITE_data/m_i_impl.erl
+++ /dev/null
@@ -1,170 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%--------------------------------------------------------------------
--module(m_i_impl).
-
--export([marshal_ll/3,marshal_ull/3,
- marshal_l/3,marshal_ul/3,
- marshal_s/3,marshal_us/3,
- marshal_c/3,marshal_wc/3,
- strcat/3,
- marshal_any_3/4,marshal_any_2/3]).
--export([init/1,terminate/2,code_change/3]).
-
--include("m.hrl").
-
--define(TK_M_S, {tk_struct,
- "IDL:m/s:1.0",
- "s",
- [{"ll_x",tk_longlong},
- {"ull_x",tk_ulonglong},
- {"ll_y",tk_longlong},
- {"ll_z",tk_longlong},
- {"ull_z",tk_ulonglong},
- {"l_x",tk_long},
- {"ul_x",tk_ulong},
- {"l_y",tk_long},
- {"l_z",tk_long},
- {"ul_z",tk_ulong},
- {"s_x",tk_short},
- {"us_x",tk_ushort},
- {"s_y",tk_short},
- {"s_z",tk_short},
- {"us_z",tk_ushort},
- {"c_x",tk_char},
- {"c_y",tk_char},
- {"c_z",tk_char},
- {"wc_x",tk_wchar},
- {"wc_y",tk_wchar},
- {"wc_z",tk_wchar}|_]}).
-
-
-
-marshal_ll(State, #m_s{ll_x = X, ll_y = Y}=_A, B) when integer(B) ->
- R = (X - Y)*B,
- io:format("~p", [{?MODULE,?LINE,[X,Y,B,R]}]),
- {reply, R, State}.
-
-marshal_ull(State, #m_s{ull_x = X, ll_y = Y}=_A, B) when integer(B) ->
- R = (X - Y)*B,
- io:format("~p", [{?MODULE,?LINE,[X,Y,B,R]}]),
- {reply, R, State}.
-
-
-marshal_l(State, #m_s{l_x = X, l_y = Y}=_A, B) when integer(B) ->
- R = (X - Y)*B,
- io:format("~p", [{?MODULE,?LINE,[X,Y,B,R]}]),
- {reply, R, State}.
-
-marshal_ul(State, #m_s{ul_x = X, l_y = Y}=_A, B) when integer(B) ->
- R = (X - Y)*B,
- io:format("~p", [{?MODULE,?LINE,[X,Y,B,R]}]),
- {reply, R, State}.
-
-
-marshal_s(State, #m_s{s_x = X, s_y = Y}=_A, B) when integer(B) ->
- R = (X - Y)*B,
- io:format("~p", [{?MODULE,?LINE,[X,Y,B,R]}]),
- {reply, R, State}.
-
-marshal_us(State, #m_s{us_x = X, s_y = Y}=_A, B) when integer(B) ->
- R = (X - Y)*B,
- io:format("~p", [{?MODULE,?LINE,[X,Y,B,R]}]),
- {reply, R, State}.
-
-
-marshal_c(State, #m_s{c_x = X, c_y = Y}=_A, B) when integer(B) ->
- R = (X - Y)*B,
- io:format("~p", [{?MODULE,?LINE,[X,Y,B,R]}]),
- {reply, R, State}.
-
-marshal_wc(State, #m_s{wc_x = X, wc_y = Y}=_A, B) when integer(B) ->
- R = (X - Y)*B,
- io:format("~p", [{?MODULE,?LINE,[X,Y,B,R]}]),
- {reply, R, State}.
-
-strcat(State, A, B) when list(A), list(B) ->
- R = A++B,
- io:format("~p", [{?MODULE,?LINE,[length(A),length(B),A,B,R]}]),
- {reply, R, State};
-strcat(State, A, B) ->
- io:format("~p", [{?MODULE,?LINE,[A,B]}]),
- {reply, [], State}.
-
-marshal_any_3(State, {any,TkX,_}=X, {any,_,_}=Y, B) when integer(B) ->
- R = any(mul(sub(any(X), any(Y)), B), TkX),
- io:format("~p", [{?MODULE,?LINE,[X,Y,B,R]}]),
- {reply, R, State}.
-
-marshal_any_2(State,
- {any,TkA,#m_s{ll_x=LL_X, ull_x=ULL_X, ll_y=LL_Y,
- l_x=L_X, ul_x=UL_X, l_y=L_Y,
- s_x=S_X, us_x=US_X, s_y=S_Y,
- c_x=C_X, c_y=C_Y,
- wc_x=WC_X, wc_y=WC_Y} = A},
- B) when integer(B) ->
- {check_type_code,?TK_M_S} = {check_type_code,TkA},
- ULL_Z = (ULL_X - LL_Y) * B,
- LL_Z = (LL_X - LL_Y) * B,
- UL_Z = (UL_X - L_Y) * B,
- L_Z = (L_X - L_Y) * B,
- US_Z = (US_X - S_Y) * B,
- S_Z = (S_X - S_Y) * B,
- C_Z = (C_X - C_Y) * B,
- WC_Z = (WC_X - WC_Y) * B,
- R = A#m_s{ll_z=LL_Z, ull_z=ULL_Z,
- l_z=L_Z, ul_z=UL_Z,
- s_z=S_Z, us_z=US_Z,
- c_z=C_Z, wc_z=WC_Z},
- io:format("~p", [{?MODULE,?LINE,[A,B,R]}]),
- {reply, {any,TkA,R}, State}.
-
-
-
-init(_Env) ->
- {ok, []}.
-
-terminate(_Reason, _State) ->
- ok.
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-
-any({any,tk_longlong,X}) -> X;
-any({any,tk_long,X}) -> X;
-any({any,tk_short,X}) -> X;
-any({any,tk_ulonglong,X}) -> X;
-any({any,tk_ulong,X}) -> X;
-any({any,tk_ushort,X}) -> X;
-any({any,tk_char,X}) -> X;
-any({any,tk_wchar,X}) -> X.
-
-any(X, Tk) when integer(X) -> {any,Tk,X}.
-
-sub(X, Y) when integer(X), integer(Y) ->
- X - Y.
-
-mul(X, Y) when integer(X), integer(Y) ->
- X * Y.
-
-napp(0, L) -> L;
-napp(N, L) when integer(N), N >= 1 -> napp(N-1, L)++L.
diff --git a/lib/ic/vsn.mk b/lib/ic/vsn.mk
deleted file mode 100644
index b9f1ef7f20..0000000000
--- a/lib/ic/vsn.mk
+++ /dev/null
@@ -1 +0,0 @@
-IC_VSN = 4.4.3
diff --git a/lib/inets/doc/src/Makefile b/lib/inets/doc/src/Makefile
index cbfa5c9e30..cbc0e384d8 100644
--- a/lib/inets/doc/src/Makefile
+++ b/lib/inets/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2015. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -43,13 +43,10 @@ XML_CHAPTER_FILES = \
inets_services.xml \
http_client.xml \
http_server.xml \
- ftp_client.xml \
notes.xml
XML_REF3_FILES = \
inets.xml \
- ftp.xml \
- tftp.xml \
http_uri.xml\
httpc.xml\
httpd.xml \
@@ -118,6 +115,7 @@ pdf: $(TOP_PDF_FILE)
html: gifs $(HTML_REF_MAN_FILE)
clean clean_docs: clean_html clean_man clean_pdf
+ rm -rf $(XMLDIR)
rm -f errs core *~
man: $(MAN3_FILES)
diff --git a/lib/inets/doc/src/ftp.xml b/lib/inets/doc/src/ftp.xml
deleted file mode 100644
index 42bece4d38..0000000000
--- a/lib/inets/doc/src/ftp.xml
+++ /dev/null
@@ -1,948 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1997</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>ftp</title>
- <prepared>Peter H&ouml;gfeldt</prepared>
- <docno></docno>
- <date>1997-11-05</date>
- <rev>B</rev>
- <file>ftp.xml</file>
- </header>
- <module>ftp</module>
- <modulesummary>A File Transfer Protocol client.</modulesummary>
-
- <description>
-
- <p>This module implements a client for file transfer
- according to a subset of the File Transfer Protocol (FTP), see
- <url href="http://www.ietf.org/rfc/rfc959.txt">RFC 959</url>.</p>
-
- <p>As from <c>Inets</c> 4.4.1, the FTP
- client always tries to use passive FTP mode and only resort
- to active FTP mode if this fails. This default behavior can be
- changed by start option <seealso marker="#mode">mode</seealso>.</p>
-
- <marker id="two_start"></marker>
-
- <p>An FTP client can be started in two ways. One is using the
- <seealso marker="#service_start">Inets service framework</seealso>,
- the other is to start it directly as a standalone process
- using function <seealso marker="#open">open</seealso>.</p>
-
- <p>For a simple example of an FTP session, see
- <seealso marker="ftp_client">Inets User's Guide</seealso>.</p>
-
- <p>In addition to the ordinary functions for receiving and sending
- files (see <c>recv/2</c>, <c>recv/3</c>, <c>send/2</c>, and
- <c>send/3</c>) there are functions for receiving remote files as
- binaries (see <c>recv_bin/2</c>) and for sending binaries to be
- stored as remote files (see <c>send_bin/3</c>).</p>
-
- <p>A set of functions is provvided for sending and receiving
- contiguous parts of a file to be stored in a remote file. For send,
- see <c>send_chunk_start/2</c>, <c>send_chunk/2</c>, and
- <c>send_chunk_end/1</c>. For receive, see
- <c>recv_chunk_start/2</c> and <c>recv_chunk/</c>).</p>
-
- <p>The return values of the following functions depend
- much on the implementation of the FTP server at the remote
- host. In particular, the results from <c>ls</c> and <c>nlist</c>
- varies. Often real errors are not reported as errors by <c>ls</c>,
- even if, for example, a file or directory does not
- exist. <c>nlist</c> is usually more strict, but some
- implementations have the peculiar behaviour of responding with an
- error if the request is a listing of the contents of a directory
- that exists but is empty.</p>
-
- <marker id="service_start"></marker>
- </description>
-
- <section>
- <title>FTP CLIENT SERVICE START/STOP</title>
-
- <p>The FTP client can be started and stopped dynamically in runtime by
- calling the <c>Inets</c> application API
- <c>inets:start(ftpc, ServiceConfig)</c>,
- or <c>inets:start(ftpc, ServiceConfig, How)</c>, and
- <c>inets:stop(ftpc, Pid)</c>.
- For details, see <seealso marker="inets">inets(3)</seealso>.</p>
-
- <p>The available configuration options are as follows:</p>
-
- <taglist>
- <tag>{host, Host}</tag>
- <item>
- <marker id="host"></marker>
- <p>Host = <c>string() | ip_address()</c></p>
- </item>
-
- <tag>{port, Port}</tag>
- <item>
- <marker id="port"></marker>
- <p>Port = <c>integer() > 0</c></p>
- <p>Default is <c>21</c>.</p>
- </item>
-
- <tag>{mode, Mode}</tag>
- <item>
- <marker id="mode"></marker>
- <p>Mode = <c>active | passive</c></p>
- <p>Default is <c>passive</c>.</p>
- </item>
-
- <tag>{verbose, Verbose}</tag>
- <item>
- <marker id="verbose"></marker>
- <p>Verbose = <c>boolean()</c> </p>
- <p>Determines if the FTP communication is to be
- verbose or not.</p>
- <p>Default is <c>false</c>.</p>
- </item>
-
- <tag>{debug, Debug}</tag>
- <item>
- <marker id="debug"></marker>
- <p>Debug = <c>trace | debug | disable</c> </p>
- <p>Debugging using the dbg toolkit. </p>
- <p>Default is <c>disable</c>.</p>
- </item>
-
- <tag>{ipfamily, IpFamily}</tag>
- <item>
- <marker id="ipfamily"></marker>
- <p>IpFamily = <c>inet | inet6 | inet6fb4</c> </p>
- <p>With <c>inet6fb4</c> the client behaves as before, that is,
- tries to use IPv6, and only if that does not work it
- uses IPv4).</p>
- <p>Default is <c>inet</c> (IPv4).</p>
- </item>
-
- <tag>{timeout, Timeout}</tag>
- <item>
- <marker id="timeout"></marker>
- <p>Timeout = <c>non_neg_integer()</c></p>
- <p>Connection time-out.</p>
- <p>Default is <c>60000</c> (milliseconds).</p>
- </item>
-
- <tag>{dtimeout, DTimeout}</tag>
- <item>
- <marker id="dtimeout"></marker>
- <p>DTimeout = <c>non_neg_integer() | infinity</c> </p>
- <p>Data connect time-out.
- The time the client waits for the server to connect to the
- data socket.</p>
- <p>Default is <c>infinity</c>. </p>
- </item>
-
- <tag>{progress, Progress}</tag>
- <item>
- <marker id="progress"></marker>
- <p>Progress = <c>ignore | {CBModule, CBFunction, InitProgress}</c></p>
- <p><c>CBModule = atom()</c>, <c>CBFunction = atom()</c></p>
- <p><c>InitProgress = term()</c></p>
- <p>Default is <c>ignore</c>.</p>
- </item>
-
- </taglist>
-
- <p>Option <c>progress</c> is intended to be used by applications that
- want to create some type of progress report, such as a progress bar in
- a GUI. Default for the progress option is <c>ignore</c>,
- that is, the option is not used. When the progress option is
- specified, the following happens when <c>ftp:send/[3,4]</c> or
- <c>ftp:recv/[3,4]</c> are called:</p>
-
- <list type="bulleted">
- <item>
- <p>Before a file is transferred, the following call is
- made to indicate the start of the file transfer and how large
- the file is. The return value of the callback function
- is to be a new value for the <c>UserProgressTerm</c> that will
- be used as input the next time the callback function is
- called.</p>
- <p><c>
- CBModule:CBFunction(InitProgress, File, {file_size, FileSize})
- </c></p>
- </item>
-
- <item>
- <p>Every time a chunk of bytes is transferred the
- following call is made:</p>
- <p><c>
- CBModule:CBFunction(UserProgressTerm, File, {transfer_size, TransferSize})
- </c></p>
- </item>
-
- <item>
- <p>At the end of the file the following call is
- made to indicate the end of the transfer:</p>
- <p><c>
- CBModule:CBFunction(UserProgressTerm, File, {transfer_size, 0})
- </c></p>
- </item>
- </list>
-
- <p>The callback function is to be defined as follows:</p>
-
- <p><c>
- CBModule:CBFunction(UserProgressTerm, File, Size) -> UserProgressTerm
- </c></p>
-
- <p><c>
- CBModule = CBFunction = atom()
- </c></p>
-
- <p><c>
- UserProgressTerm = term()
- </c></p>
-
- <p><c>
- File = string()
- </c></p>
-
- <p><c>
- Size = {transfer_size, integer()} | {file_size, integer()} | {file_size, unknown}
- </c></p>
-
- <p>For remote files, <c>ftp</c> cannot determine the
- file size in a platform independent way. In this case the size
- becomes <c>unknown</c> and it is left to the application to
- determine the size.</p>
-
- <note>
- <p>The callback is made by a middleman process, hence the
- file transfer is not affected by the code in the progress
- callback function. If the callback crashes, this is
- detected by the FTP connection process, which then prints an
- info-report and goes on as if the progress option was set
- to <c>ignore</c>.</p>
- </note>
-
- <p>The file transfer type is set to the default of the FTP server
- when the session is opened. This is usually ASCCI mode.
- </p>
-
- <p>The current local working directory (compare <c>lpwd/1</c>) is set
- to the value reported by <c>file:get_cwd/1</c>, the wanted
- local directory.
- </p>
-
- <p>The return value <c>Pid</c> is used as a reference to the
- newly created FTP client in all other functions, and they are to
- be called by the process that created the connection. The FTP
- client process monitors the process that created it and
- terminates if that process terminates.</p>
- </section>
-
- <section>
- <title>DATA TYPES</title>
- <p>The following type definitions are used by more than one
- function in the FTP client API:</p>
- <p><c>pid()</c> = identifier of an FTP connection</p>
- <p><c>string()</c> = list of ASCII characters</p>
- <p><c>shortage_reason()</c> = <c>etnospc | epnospc</c></p>
- <p><c>restriction_reason()</c> = <c>epath | efnamena | elogin | enotbinary</c>
- - all restrictions are not always relevant to all functions
- </p>
- <p><c>common_reason()</c> = <c>econn | eclosed | term()</c>
- - some explanation of what went wrong</p>
-
- <marker id="account"></marker>
- </section>
-
- <funcs>
- <func>
- <name>account(Pid, Account) -> ok | {error, Reason}</name>
- <fsummary>Specifies which account to use.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>Account = string()</v>
- <v>Reason = eacct | common_reason()</v>
- </type>
- <desc>
- <p>Sets the account for an operation, if needed.</p>
-
- <marker id="append"></marker>
- <marker id="append2"></marker>
- <marker id="append3"></marker>
- </desc>
- </func>
-
- <func>
- <name>append(Pid, LocalFile) -> </name>
- <name>append(Pid, LocalFile, RemoteFile) -> ok | {error, Reason}</name>
- <fsummary>Transfers a file to remote server, and appends it to
- <c>Remotefile</c>.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>LocalFile = RemoteFile = string()</v>
- <v>Reason = epath | elogin | etnospc | epnospc | efnamena | common_reason</v>
- </type>
- <desc>
- <p>Transfers the file <c>LocalFile</c> to the remote server. If
- <c>RemoteFile</c> is specified, the name of the remote file that the
- file is appended to is set to <c>RemoteFile</c>, otherwise
- to <c>LocalFile</c>. If the file does not exists,
- it is created.</p>
-
- <marker id="append_bin"></marker>
- </desc>
- </func>
-
- <func>
- <name>append_bin(Pid, Bin, RemoteFile) -> ok | {error, Reason}</name>
- <fsummary>Transfers a binary into a remote file.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>Bin = binary()()</v>
- <v>RemoteFile = string()</v>
- <v>Reason = restriction_reason()| shortage_reason() | common_reason()</v>
- </type>
- <desc>
- <p>Transfers the binary <c>Bin</c> to the remote server and appends
- it to the file <c>RemoteFile</c>. If the file does not exist, it
- is created.</p>
-
- <marker id="append_chunk"></marker>
- </desc>
- </func>
-
- <func>
- <name>append_chunk(Pid, Bin) -> ok | {error, Reason}</name>
- <fsummary>Appends a chunk to the remote file.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>Bin = binary()</v>
- <v>Reason = echunk | restriction_reason() | common_reason()</v>
- </type>
- <desc>
- <p>Transfers the chunk <c>Bin</c> to the remote server, which
- appends it to the file specified in the call to
- <c>append_chunk_start/2</c>.</p>
- <p>For some errors, for example, file system full, it is
- necessary to call <c>append_chunk_end</c> to get the
- proper reason.</p>
-
- <marker id="append_chunk_start"></marker>
- </desc>
- </func>
-
- <func>
- <name>append_chunk_start(Pid, File) -> ok | {error, Reason}</name>
- <fsummary>Starts transfer of file chunks for appending to <c>File</c>.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>File = string()</v>
- <v>Reason = restriction_reason() | common_reason()</v>
- </type>
- <desc>
- <p>Starts the transfer of chunks for appending to the file
- <c>File</c> at the remote server. If the file does not exist,
- it is created.</p>
-
- <marker id="append_chunk_end"></marker>
- </desc>
- </func>
-
- <func>
- <name>append_chunk_end(Pid) -> ok | {error, Reason}</name>
- <fsummary>Stops transfer of chunks for appending.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>Reason = echunk | restriction_reason() | shortage_reason() </v>
- </type>
- <desc>
- <p>Stops transfer of chunks for appending to the remote server.
- The file at the remote server, specified in the call to
- <c>append_chunk_start/2</c>, is closed by the server.</p>
-
- <marker id="cd"></marker>
- </desc>
- </func>
-
- <func>
- <name>cd(Pid, Dir) -> ok | {error, Reason}</name>
- <fsummary>Changes remote working directory.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>Dir = string()</v>
- <v>Reason = restriction_reason() | common_reason() </v>
- </type>
- <desc>
- <p>Changes the working directory at the remote server to
- <c>Dir</c>.</p>
-
- <marker id="close"></marker>
- </desc>
- </func>
-
- <func>
- <name>close(Pid) -> ok</name>
- <fsummary>Ends the FTP session.</fsummary>
- <type>
- <v>Pid = pid()</v>
- </type>
- <desc>
- <p>Ends an FTP session, created using function
- <seealso marker="#open">open</seealso>.</p>
-
- <marker id="delete"></marker>
- </desc>
- </func>
-
- <func>
- <name>delete(Pid, File) -> ok | {error, Reason}</name>
- <fsummary>Deletes a file at the remote server.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>File = string()</v>
- <v>Reason = restriction_reason() | common_reason()</v>
- </type>
- <desc>
- <p>Deletes the file <c>File</c> at the remote server.</p>
-
- <marker id="append"></marker>
- </desc>
- </func>
-
- <func>
- <name>formaterror(Tag) -> string()</name>
- <fsummary>Returns error diagnostics.</fsummary>
- <type>
- <v>Tag = {error, atom()} | atom()</v>
- </type>
- <desc>
- <p>Given an error return value <c>{error, AtomReason}</c>,
- this function returns a readable string describing the error.</p>
-
- <marker id="lcd"></marker>
- </desc>
- </func>
-
- <func>
- <name>lcd(Pid, Dir) -> ok | {error, Reason}</name>
- <fsummary>Changes local working directory.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>Dir = string()</v>
- <v>Reason = restriction_reason()</v>
- </type>
- <desc>
- <p>Changes the working directory to <c>Dir</c> for the local client.</p>
-
- <marker id="lpwd"></marker>
- </desc>
- </func>
-
- <func>
- <name>lpwd(Pid) -> {ok, Dir}</name>
- <fsummary>Gets local current working directory.</fsummary>
- <type>
- <v>Pid = pid()</v>
- </type>
- <desc>
- <p>Returns the current working directory at the local client.</p>
-
- <marker id="ls"></marker>
- <marker id="ls1"></marker>
- <marker id="ls2"></marker>
- </desc>
- </func>
-
- <func>
- <name>ls(Pid) -> </name>
- <name>ls(Pid, Pathname) -> {ok, Listing} | {error, Reason}</name>
- <fsummary>List of files.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>Pathname = string()</v>
- <v>Listing = string()</v>
- <v>Reason = restriction_reason() | common_reason()</v>
- </type>
- <desc>
- <p>Returns a list of files in long format.</p>
- <p><c>Pathname</c> can be a directory, a group of files, or
- a file. The <c>Pathname</c> string can contain wildcards.</p>
- <p><c>ls/1</c> implies the current remote directory of the user.</p>
- <p>The format of <c>Listing</c> depends on the operating system.
- On UNIX, it is typically produced from the output of the
- <c>ls -l</c> shell command.</p>
-
- <marker id="mkdir"></marker>
- </desc>
- </func>
-
- <func>
- <name>mkdir(Pid, Dir) -> ok | {error, Reason}</name>
- <fsummary>Creates a remote directory.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>Dir = string()</v>
- <v>Reason = restriction_reason() | common_reason()</v>
- </type>
- <desc>
- <p>Creates the directory <c>Dir</c> at the remote server.</p>
-
- <marker id="nlist"></marker>
- <marker id="nlist1"></marker>
- <marker id="nlist2"></marker>
- </desc>
- </func>
-
- <func>
- <name>nlist(Pid) -> </name>
- <name>nlist(Pid, Pathname) -> {ok, Listing} | {error, Reason}</name>
- <fsummary>List of files.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>Pathname = string()</v>
- <v>Listing = string()</v>
- <v>Reason = restriction_reason() | common_reason()</v>
- </type>
- <desc>
- <p>Returns a list of files in short format.</p>
- <p><c>Pathname</c> can be a directory, a group of files, or
- a file. The <c>Pathname</c> string can contain wildcards.</p>
- <p><c>nlist/1</c> implies the current remote directory of the user.</p>
- <p>The format of <c>Listing</c> is a stream of
- filenames where each filename is separated by &lt;CRLF&gt; or
- &lt;NL&gt;. Contrary to function <c>ls</c>, the purpose of
- <c>nlist</c> is to enable a program to
- process filename information automatically.</p>
-
- <marker id="open"></marker>
- </desc>
- </func>
-
- <func>
- <name>open(Host) -> {ok, Pid} | {error, Reason}</name>
- <name>open(Host, Opts) -> {ok, Pid} | {error, Reason}</name>
- <fsummary>Starts a standalone FTP client.</fsummary>
- <type>
- <v>Host = string() | ip_address()</v>
- <v>Opts = options()</v>
- <v>options() = [option()]</v>
- <v>option() = start_option() | open_option()</v>
- <v>start_option() = {verbose, verbose()} | {debug, debug()}</v>
- <v>verbose() = boolean() (default is false)</v>
- <v>debug() = disable | debug | trace (default is disable)</v>
- <v>open_option() = {ipfamily, ipfamily()} | {port, port()} | {mode, mode()} | {tls, tls_options()} | {timeout, timeout()} | {dtimeout, dtimeout()} | {progress, progress()}</v>
- <v>ipfamily() = inet | inet6 | inet6fb4 (default is inet)</v>
- <v>port() = integer() > 0 (default is 21)</v>
- <v>mode() = active | passive (default is passive)</v>
- <v>tls_options() = [<seealso marker="ssl:ssl#type-ssloption">ssl:ssloption()</seealso>]</v>
- <v>timeout() = integer() > 0 (default is 60000 milliseconds)</v>
- <v>dtimeout() = integer() > 0 | infinity (default is infinity)</v>
- <v>pogress() = ignore | {module(), function(), initial_data()} (default is ignore)</v>
- <v>module() = atom()</v>
- <v>function() = atom()</v>
- <v>initial_data() = term()</v>
- <v>Reason = ehost | term()</v>
- </type>
-
- <desc>
- <p>Starts a standalone FTP client process
- (without the <c>Inets</c> service framework) and
- opens a session with the FTP server at <c>Host</c>. </p>
-
- <p>If option <c>{tls, tls_options()}</c> is present, the FTP session
- is transported over <c>tls</c> (<c>ftps</c>, see
- <url href="http://www.ietf.org/rfc/rfc4217.txt">RFC 4217</url>).
- The list <c>tls_options()</c> can be empty. The function
- <seealso marker="ssl:ssl#connect/3"><c>ssl:connect/3</c></seealso>
- is used for securing both the control connection and the data sessions.
- </p>
-
- <p>A session opened in this way is closed using function
- <seealso marker="#close">close</seealso>.</p>
-
- <marker id="pwd"></marker>
- </desc>
- </func>
-
- <func>
- <name>pwd(Pid) -> {ok, Dir} | {error, Reason}</name>
- <fsummary>Gets the remote current working directory.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>Reason = restriction_reason() | common_reason()</v>
- </type>
- <desc>
- <p>Returns the current working directory at the remote server.</p>
-
- <marker id="recv"></marker>
- <marker id="recv2"></marker>
- <marker id="recv3"></marker>
- </desc>
- </func>
-
- <func>
- <name>recv(Pid, RemoteFile) -> </name>
- <name>recv(Pid, RemoteFile, LocalFile) -> ok | {error, Reason}</name>
- <fsummary>Transfers a file from remote server.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>RemoteFile = LocalFile = string()</v>
- <v>Reason = restriction_reason() | common_reason() | file_write_error_reason() </v>
- <v>file_write_error_reason() = see file:write/2</v>
- </type>
- <desc>
- <p>Transfers the file <c>RemoteFile</c> from the remote server
- to the file system of the local client. If
- <c>LocalFile</c> is specified, the local file will be
- <c>LocalFile</c>, otherwise
- <c>RemoteFile</c>.</p>
- <p>If the file write fails (for example, <c>enospc</c>), the command is
- aborted and <c>{error, file_write_error_reason()}</c> is returned.
- However, the file is <em>not</em> removed.</p>
-
- <marker id="recv_bin"></marker>
- </desc>
- </func>
-
- <func>
- <name>recv_bin(Pid, RemoteFile) -> {ok, Bin} | {error, Reason}</name>
- <fsummary>Transfers a file from remote server as a binary.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>Bin = binary()</v>
- <v>RemoteFile = string()</v>
- <v>Reason = restriction_reason() | common_reason()</v>
- </type>
- <desc>
- <p>Transfers the file <c>RemoteFile</c> from the remote server and
- receives it as a binary.</p>
-
- <marker id="recv_chunk_start"></marker>
- </desc>
- </func>
-
- <func>
- <name>recv_chunk_start(Pid, RemoteFile) -> ok | {error, Reason}</name>
- <fsummary>Starts chunk-reading of the remote file.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>RemoteFile = string()</v>
- <v>Reason = restriction_reason() | common_reason()</v>
- </type>
- <desc>
- <p>Starts transfer of the file <c>RemoteFile</c> from the
- remote server.</p>
-
- <marker id="recv_chunk"></marker>
- </desc>
- </func>
-
- <func>
- <name>recv_chunk(Pid) -> ok | {ok, Bin} | {error, Reason}</name>
- <fsummary>Receives a chunk of the remote file.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>Bin = binary()</v>
- <v>Reason = restriction_reason() | common_reason()</v>
- </type>
- <desc>
- <p>Receives a chunk of the remote file (<c>RemoteFile</c> of
- <c>recv_chunk_start</c>). The return values have the following
- meaning:</p>
- <list type="bulleted">
- <item><c>ok</c> = the transfer is complete.</item>
- <item><c>{ok, Bin}</c> = just another chunk of the file.</item>
- <item><c>{error, Reason}</c> = transfer failed.</item>
- </list>
-
- <marker id="rename"></marker>
- </desc>
- </func>
-
- <func>
- <name>rename(Pid, Old, New) -> ok | {error, Reason}</name>
- <fsummary>Renames a file at the remote server.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>CurrFile = NewFile = string()</v>
- <v>Reason = restriction_reason() | common_reason()</v>
- </type>
- <desc>
- <p>Renames <c>Old</c> to <c>New</c> at the remote server.</p>
-
- <marker id="rmdir"></marker>
- </desc>
- </func>
-
- <func>
- <name>rmdir(Pid, Dir) -> ok | {error, Reason}</name>
- <fsummary>Removes a remote directory.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>Dir = string()</v>
- <v>Reason = restriction_reason() | common_reason()</v>
- </type>
- <desc>
- <p>Removes directory <c>Dir</c> at the remote server.</p>
-
- <marker id="send"></marker>
- <marker id="send2"></marker>
- <marker id="send3"></marker>
- </desc>
- </func>
-
- <func>
- <name>send(Pid, LocalFile) -></name>
- <name>send(Pid, LocalFile, RemoteFile) -> ok | {error, Reason}</name>
- <fsummary>Transfers a file to the remote server.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>LocalFile = RemoteFile = string()</v>
- <v>Reason = restriction_reason() | common_reason() | shortage_reason()</v>
- </type>
- <desc>
- <p>Transfers the file <c>LocalFile</c> to the remote server. If
- <c>RemoteFile</c> is specified, the name of the remote file is set
- to <c>RemoteFile</c>, otherwise to <c>LocalFile</c>.</p>
-
- <marker id="send_bin"></marker>
- </desc>
- </func>
-
- <func>
- <name>send_bin(Pid, Bin, RemoteFile) -> ok | {error, Reason}</name>
- <fsummary>Transfers a binary into a remote file.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>Bin = binary()()</v>
- <v>RemoteFile = string()</v>
- <v>Reason = restriction_reason() | common_reason() | shortage_reason()</v>
- </type>
- <desc>
- <p>Transfers the binary <c>Bin</c> into the file <c>RemoteFile</c>
- at the remote server.</p>
-
- <marker id="send_chunk"></marker>
- </desc>
- </func>
-
- <func>
- <name>send_chunk(Pid, Bin) -> ok | {error, Reason}</name>
- <fsummary>Writes a chunk to the remote file.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>Bin = binary()</v>
- <v>Reason = echunk | restriction_reason() | common_reason()</v>
- </type>
- <desc>
- <p>Transfers the chunk <c>Bin</c> to the remote server, which
- writes it into the file specified in the call to
- <c>send_chunk_start/2</c>.</p>
- <p>For some errors, for example, file system full, it is
- necessary to to call <c>send_chunk_end</c> to get the
- proper reason.</p>
-
- <marker id="send_chunk_start"></marker>
- </desc>
- </func>
-
- <func>
- <name>send_chunk_start(Pid, File) -> ok | {error, Reason}</name>
- <fsummary>Starts transfer of file chunks.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>File = string()</v>
- <v>Reason = restriction_reason() | common_reason()</v>
- </type>
- <desc>
- <p>Starts transfer of chunks into the file <c>File</c> at the
- remote server.</p>
-
- <marker id="send_chunk_end"></marker>
- </desc>
- </func>
-
- <func>
- <name>send_chunk_end(Pid) -> ok | {error, Reason}</name>
- <fsummary>Stops transfer of chunks.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>Reason = restriction_reason() | common_reason() | shortage_reason()</v>
- </type>
- <desc>
- <p>Stops transfer of chunks to the remote server. The file at the
- remote server, specified in the call to <c>send_chunk_start/2</c>
- is closed by the server.</p>
-
- <marker id="type"></marker>
- </desc>
- </func>
-
- <func>
- <name>type(Pid, Type) -> ok | {error, Reason}</name>
- <fsummary>Sets transfer type to <c>ascii</c>or <c>binary</c>.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>Type = ascii | binary</v>
- <v>Reason = etype | restriction_reason() | common_reason()</v>
- </type>
- <desc>
- <p>Sets the file transfer type to <c>ascii</c> or <c>binary</c>. When
- an FTP session is opened, the default transfer type of the
- server is used, most often <c>ascii</c>, which is default
- according to <url href="http://www.ietf.org/rfc/rfc959.txt">RFC 959</url>.</p>
- <marker id="user3"></marker>
- </desc>
- </func>
-
- <func>
- <name>user(Pid, User, Password) -> ok | {error, Reason}</name>
- <fsummary>User login.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>User = Password = string()</v>
- <v>Reason = euser | common_reason()</v>
- </type>
- <desc>
- <p>Performs login of <c>User</c> with <c>Password</c>.</p>
-
- <marker id="user4"></marker>
- </desc>
- </func>
-
- <func>
- <name>user(Pid, User, Password, Account) -> ok | {error, Reason}</name>
- <fsummary>User login.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>User = Password = string()</v>
- <v>Reason = euser | common_reason() </v>
- </type>
- <desc>
- <p>Performs login of <c>User</c> with <c>Password</c> to the account
- specified by <c>Account</c>.</p>
-
- <marker id="quote"></marker>
- </desc>
- </func>
-
- <func>
- <name>quote(Pid, Command) -> [FTPLine]</name>
- <fsummary>Sends an arbitrary FTP command.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>Command = string()</v>
- <v>FTPLine = string(</v>
- </type>
- <desc><note><p>The telnet end of line characters, from the FTP
- protocol definition, CRLF, for example, "\\r\\n" has been removed.</p></note>
- <p>Sends an arbitrary FTP command and returns verbatim a list
- of the lines sent back by the FTP server. This function is
- intended to give application accesses to FTP commands
- that are server-specific or that cannot be provided by
- this FTP client.</p>
- <note>
- <p>FTP commands requiring a data connection cannot be
- successfully issued with this function.</p>
- </note>
- </desc>
- </func>
- </funcs>
-
- <section>
- <title>ERRORS</title>
- <p>The possible error reasons and the corresponding diagnostic strings
- returned by <c>formaterror/1</c> are as follows:
- </p>
- <taglist>
- <tag><c>echunk</c></tag>
- <item>
- <p>Synchronization error during chunk sending according to one
- of the following:
- </p><list type="bulleted">
- <item>A call is made to <c>send_chunk/2</c> or <c>send_chunk_end/1</c>
- before a call to <c>send_chunk_start/2</c>.</item>
- <item>A call has been made to another transfer function during chunk
- sending, that is, before a call to <c>send_chunk_end/1</c>.</item>
- </list>
- </item>
- <tag><c>eclosed</c></tag>
- <item>
- <p>The session is closed.</p>
- </item>
- <tag><c>econn</c></tag>
- <item>
- <p>Connection to the remote server is prematurely closed.</p>
- </item>
- <tag><c>ehost</c></tag>
- <item>
- <p>Host is not found, FTP server is not found, or connection is rejected
- by FTP server.</p>
- </item>
- <tag><c>elogin</c></tag>
- <item>
- <p>User is not logged in.</p>
- </item>
- <tag><c>enotbinary</c></tag>
- <item>
- <p>Term is not a binary.</p>
- </item>
- <tag><c>epath</c></tag>
- <item>
- <p>No such file or directory, or directory already exists, or
- permission denied.</p>
- </item>
- <tag><c>etype</c></tag>
- <item>
- <p>No such type.</p>
- </item>
- <tag><c>euser</c></tag>
- <item>
- <p>Invalid username or password.</p>
- </item>
- <tag><c>etnospc</c></tag>
- <item>
- <p>Insufficient storage space in system [452].</p>
- </item>
- <tag><c>epnospc</c></tag>
- <item>
- <p>Exceeded storage allocation (for current directory or
- dataset) [552].</p>
- </item>
- <tag><c>efnamena</c></tag>
- <item>
- <p>Filename not allowed [553].</p>
- </item>
- </taglist>
- </section>
-
- <section>
- <title>SEE ALSO</title>
- <p><seealso marker="kernel:file">file(3)</seealso>
- <seealso marker="stdlib:filename">filename(3)</seealso>
- and J. Postel and J. Reynolds: File Transfer Protocol
- (<url href="http://www.ietf.org/rfc/rfc959.txt">RFC 959</url>).
- </p>
- </section>
-
-</erlref>
-
-
diff --git a/lib/inets/doc/src/ftp_client.xml b/lib/inets/doc/src/ftp_client.xml
deleted file mode 100644
index 990dd68604..0000000000
--- a/lib/inets/doc/src/ftp_client.xml
+++ /dev/null
@@ -1,86 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2004</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>FTP Client</title>
- <prepared>Ingela Anderton Andin</prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date></date>
- <rev></rev>
- <file>ftp_client.xml</file>
- </header>
-
- <section>
- <title>Getting Started</title>
-
- <p>FTP clients are considered to be rather temporary. Thus,
- they are only started and stopped during runtime and cannot
- be started at application startup.
- The FTP client API is designed to allow some functions to
- return intermediate results. This implies that only the process
- that started the FTP client can access it with
- preserved sane semantics.
- If the process that started the FTP session
- dies, the FTP client process terminates.</p>
-
- <p>The client supports IPv6 as long as the underlying mechanisms
- also do so.</p>
-
- <p>The following is a simple example of an FTP session, where
- the user <c>guest</c> with password <c>password</c> logs on to
- the remote host <c>erlang.org</c>:</p>
- <code type="erl"><![CDATA[
- 1> inets:start().
- ok
- 2> {ok, Pid} = inets:start(ftpc, [{host, "erlang.org"}]).
- {ok,<0.22.0>}
- 3> ftp:user(Pid, "guest", "password").
- ok
- 4> ftp:pwd(Pid).
- {ok, "/home/guest"}
- 5> ftp:cd(Pid, "appl/examples").
- ok
- 6> ftp:lpwd(Pid).
- {ok, "/home/fred"}.
- 7> ftp:lcd(Pid, "/home/eproj/examples").
- ok
- 8> ftp:recv(Pid, "appl.erl").
- ok
- 9> inets:stop(ftpc, Pid).
- ok
- ]]></code>
- <p> The file
- <c>appl.erl</c> is transferred from the remote to the local
- host. When the session is opened, the current directory at
- the remote host is <c>/home/guest</c>, and <c>/home/fred</c>
- at the local host. Before transferring the file, the current
- local directory is changed to <c>/home/eproj/examples</c>, and
- the remote directory is set to
- <c>/home/guest/appl/examples</c>.</p>
- </section>
-</chapter>
-
-
diff --git a/lib/inets/doc/src/http_client.xml b/lib/inets/doc/src/http_client.xml
index 15e383ec77..c31a47f4f4 100644
--- a/lib/inets/doc/src/http_client.xml
+++ b/lib/inets/doc/src/http_client.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2016</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/inets/doc/src/http_uri.xml b/lib/inets/doc/src/http_uri.xml
index f57214a7ce..6d3547f4fe 100644
--- a/lib/inets/doc/src/http_uri.xml
+++ b/lib/inets/doc/src/http_uri.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2012</year><year>2017</year>
+ <year>2012</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -30,7 +30,7 @@
<rev></rev>
</header>
- <module>http_uri</module>
+ <module since="OTP R15B01">http_uri</module>
<modulesummary>URI utility module</modulesummary>
<description>
@@ -79,7 +79,7 @@
<funcs>
<func>
- <name>decode(HexEncodedURI) -> URI</name>
+ <name since="OTP R15B01">decode(HexEncodedURI) -> URI</name>
<fsummary>Decodes a hexadecimal encoded URI.</fsummary>
<type>
@@ -93,7 +93,7 @@
</desc>
</func>
<func>
- <name>encode(URI) -> HexEncodedURI</name>
+ <name since="OTP R15B01">encode(URI) -> HexEncodedURI</name>
<fsummary>Encodes a hexadecimal encoded URI.</fsummary>
<type>
@@ -109,8 +109,8 @@
</func>
<func>
- <name>parse(URI) -> {ok, Result} | {error, Reason}</name>
- <name>parse(URI, Options) -> {ok, Result} | {error, Reason}</name>
+ <name since="OTP R15B01">parse(URI) -> {ok, Result} | {error, Reason}</name>
+ <name since="OTP R15B01">parse(URI, Options) -> {ok, Result} | {error, Reason}</name>
<fsummary>Parses a URI.</fsummary>
<type>
<v>URI = uri()</v>
@@ -165,7 +165,7 @@ fun(SchemeStr :: string() | binary()) ->
</func>
<func>
- <name>scheme_defaults() -> SchemeDefaults</name>
+ <name since="OTP R15B01">scheme_defaults() -> SchemeDefaults</name>
<fsummary>A list of the scheme and their default ports.</fsummary>
<type>
<v>SchemeDefaults = [{scheme(), default_scheme_port_number()}] </v>
diff --git a/lib/inets/doc/src/httpc.xml b/lib/inets/doc/src/httpc.xml
index befcd83827..7451b314ec 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>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -30,7 +30,7 @@
<rev></rev>
</header>
- <module>httpc</module>
+ <module since="OTP R13B04">httpc</module>
<modulesummary>An HTTP/1.1 client</modulesummary>
<description>
@@ -151,8 +151,8 @@
<funcs>
<func>
- <name>cancel_request(RequestId) -></name>
- <name>cancel_request(RequestId, Profile) -> ok</name>
+ <name since="OTP R13B04">cancel_request(RequestId) -></name>
+ <name since="OTP R13B04">cancel_request(RequestId, Profile) -> ok</name>
<fsummary>Cancels an asynchronous HTTP request.</fsummary>
<type>
<v>RequestId = request_id() - A unique identifier as returned
@@ -169,9 +169,9 @@
</func>
<func>
- <name>cookie_header(Url) -> </name>
- <name>cookie_header(Url, Profile | Opts) -> header() | {error, Reason}</name>
- <name>cookie_header(Url, Opts, Profile) -> header() | {error, Reason}</name>
+ <name since="OTP R13B04">cookie_header(Url) -> </name>
+ <name since="OTP R13B04">cookie_header(Url, Profile | Opts) -> header() | {error, Reason}</name>
+ <name since="OTP R15B">cookie_header(Url, Opts, Profile) -> header() | {error, Reason}</name>
<fsummary>Returns the cookie header that would have been sent when
making a request to URL using the profile <c>Profile</c>.</fsummary>
<type>
@@ -193,8 +193,8 @@
</func>
<func>
- <name>get_options(OptionItems) -> {ok, Values} | {error, Reason}</name>
- <name>get_options(OptionItems, Profile) -> {ok, Values} | {error, Reason}</name>
+ <name since="OTP R15B01">get_options(OptionItems) -> {ok, Values} | {error, Reason}</name>
+ <name since="OTP R15B01">get_options(OptionItems, Profile) -> {ok, Values} | {error, Reason}</name>
<fsummary>Gets the currently used options.</fsummary>
<type>
<v>OptionItems = all | [option_item()]</v>
@@ -223,8 +223,8 @@
</func>
<func>
- <name>info() -> list()</name>
- <name>info(Profile) -> list()</name>
+ <name since="OTP R15B02">info() -> list()</name>
+ <name since="OTP R15B02">info(Profile) -> list()</name>
<fsummary>Produces a list of miscellaneous information.</fsummary>
<type>
<v>Profile = profile() | pid()</v>
@@ -239,8 +239,8 @@
<func>
- <name>reset_cookies() -> void()</name>
- <name>reset_cookies(Profile) -> void()</name>
+ <name since="OTP R13B04">reset_cookies() -> void()</name>
+ <name since="OTP R13B04">reset_cookies(Profile) -> void()</name>
<fsummary>Resets the cookie database.</fsummary>
<type>
<v>Profile = profile() | pid()</v>
@@ -254,8 +254,8 @@
</func>
<func>
- <name>request(Url) -> </name>
- <name>request(Url, Profile) -> {ok, Result} | {error, Reason}</name>
+ <name since="OTP R13B04">request(Url) -> </name>
+ <name since="OTP R13B04">request(Url, Profile) -> {ok, Result} | {error, Reason}</name>
<fsummary>Sends a get HTTP request.</fsummary>
<type>
<v>Url = url()</v>
@@ -272,8 +272,8 @@
</func>
<func>
- <name>request(Method, Request, HTTPOptions, Options) -></name>
- <name>request(Method, Request, HTTPOptions, Options, Profile) -> {ok, Result} | {ok, saved_to_file} | {error, Reason}</name>
+ <name since="OTP R13B04">request(Method, Request, HTTPOptions, Options) -></name>
+ <name since="OTP R13B04">request(Method, Request, HTTPOptions, Options, Profile) -> {ok, Result} | {ok, saved_to_file} | {error, Reason}</name>
<fsummary>Sends an HTTP request.</fsummary>
<type>
@@ -288,8 +288,7 @@
{autoredirect, boolean()} |
{proxy_auth, {userstring(), passwordstring()}} |
{version, http_version()} |
- {relaxed, boolean()} |
- {url_encode, boolean()}</v>
+ {relaxed, boolean()}</v>
<v>timeout() = integer() >= 0 | infinity</v>
<v>Options = options()</v>
<v>options() = [option()]</v>
@@ -313,8 +312,7 @@
<v>Body = string() | binary()</v>
<v>Profile = profile() | pid()</v>
<d>When started <c>stand_alone</c> only the pid can be used.</d>
- <v>Reason = {connect_failed, term()} |
- {send_failed, term()} | term()</v>
+ <v>Reason = term()</v>
</type>
<desc>
@@ -380,13 +378,6 @@
from the HTTP-standard are enabled.</p>
<p>Default is <c>false</c>.</p>
</item>
-
- <tag><c><![CDATA[url_encode]]></c></tag>
- <item>
- <p>Applies Percent-encoding, also known as URL encoding on the
- URL.</p>
- <p>Default is <c>false</c>.</p>
- </item>
</taglist>
<p>Option (<c>option()</c>) details:</p>
@@ -450,17 +441,22 @@
<tag><c><![CDATA[socket_opts]]></c></tag>
<item>
- <p>Socket options to be used for this and subsequent
- requests.</p>
+ <p>Socket options to be used for this request.</p>
<p>Overrides any value set by function
<seealso marker="#set_options-1">set_options</seealso>.</p>
<p>The validity of the options is <em>not</em> checked by
the HTTP client they are assumed to be correct and passed
on to ssl application and inet driver, which may reject
- them if they are not correct. Note that the current
- implementation assumes the requests to the same host, port
- combination will use the same socket options.
+ them if they are not correct.
</p>
+ <note>
+ <p>
+ Persistent connections are not supported when setting the
+ <c>socket_opts</c> option. When <c>socket_opts</c> is not
+ set the current implementation assumes the requests to the
+ same host, port combination will use the same socket options.
+ </p>
+ </note>
<p>By default the socket options set by function
<seealso marker="#set_options-1">set_options/[1,2]</seealso>
@@ -525,8 +521,8 @@
<func>
- <name>set_options(Options) -> </name>
- <name>set_options(Options, Profile) -> ok | {error, Reason}</name>
+ <name since="OTP R13B04">set_options(Options) -> </name>
+ <name since="OTP R13B04">set_options(Options, Profile) -> ok | {error, Reason}</name>
<fsummary>Sets options to be used for subsequent requests.</fsummary>
<type>
<v>Options = [Option]</v>
@@ -633,15 +629,18 @@
to complete. The HTTP/1.1 specification suggests a
limit of two persistent connections per server, which is the
default value of option <c>max_sessions</c>.</p>
+ <p>
+ The current implementation assumes the requests to the same host, port
+ combination will use the same socket options.
+ </p>
</note>
-
<marker id="get_options"></marker>
</desc>
</func>
<func>
- <name>store_cookies(SetCookieHeaders, Url) -> </name>
- <name>store_cookies(SetCookieHeaders, Url, Profile) -> ok | {error, Reason}</name>
+ <name since="OTP R14B02">store_cookies(SetCookieHeaders, Url) -> </name>
+ <name since="OTP R14B02">store_cookies(SetCookieHeaders, Url, Profile) -> ok | {error, Reason}</name>
<fsummary>Saves the cookies defined in <c>SetCookieHeaders</c> in the
client profile cookie database.</fsummary>
<type>
@@ -659,7 +658,7 @@
</func>
<func>
- <name>stream_next(Pid) -> ok</name>
+ <name since="OTP R13B04">stream_next(Pid) -> ok</name>
<fsummary>Triggers the next message to be streamed, that is,
the same behavior as active one for sockets.
</fsummary>
@@ -677,8 +676,8 @@
</func>
<func>
- <name>which_cookies() -> cookies()</name>
- <name>which_cookies(Profile) -> cookies()</name>
+ <name since="OTP R13B04">which_cookies() -> cookies()</name>
+ <name since="OTP R13B04">which_cookies(Profile) -> cookies()</name>
<fsummary>Dumps the entire cookie database.</fsummary>
<type>
<v>Profile = profile() | pid()</v>
@@ -696,8 +695,8 @@
</func>
<func>
- <name>which_sessions() -> session_info()</name>
- <name>which_sessions(Profile) -> session_info()</name>
+ <name since="OTP R15B02">which_sessions() -> session_info()</name>
+ <name since="OTP R15B02">which_sessions(Profile) -> session_info()</name>
<fsummary>Produces a slightly processed dump of the sessions database.</fsummary>
<type>
<v>Profile = profile() | pid()</v>
diff --git a/lib/inets/doc/src/httpd.xml b/lib/inets/doc/src/httpd.xml
index edf8731a82..1750078db0 100644
--- a/lib/inets/doc/src/httpd.xml
+++ b/lib/inets/doc/src/httpd.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -29,7 +29,7 @@
<rev>2.2</rev>
<file>httpd.sgml</file>
</header>
- <module>httpd</module>
+ <module since="">httpd</module>
<modulesummary>
HTTP server API
</modulesummary>
@@ -173,7 +173,7 @@
<item>
<p>For <c>ip_comm</c> configuration options, see
<seealso marker="kernel:gen_tcp#listen-2">gen_tcp:listen/2</seealso>, some options
- that are used internally by httpd can not be set.</p>
+ that are used internally by httpd cannot be set.</p>
<p>For <c>SSL</c> configuration options, see
<seealso marker="ssl:ssl#listen-2">ssl:listen/2</seealso>.</p>
<p>Default is <c>ip_comm</c>.</p>
@@ -874,8 +874,8 @@ text/plain asc txt</pre>
<funcs>
<func>
- <name>info(Pid) -></name>
- <name>info(Pid, Properties) -> [{Option, Value}]</name>
+ <name since="">info(Pid) -></name>
+ <name since="">info(Pid, Properties) -> [{Option, Value}]</name>
<fsummary>Fetches information about the HTTP server.</fsummary>
<type>
<v>Properties = [property()]</v>
@@ -899,10 +899,10 @@ text/plain asc txt</pre>
</func>
<func>
- <name>info(Address, Port) -> </name>
- <name>info(Address, Port, Profile) -> </name>
- <name>info(Address, Port, Profile, Properties) -> [{Option, Value}] </name>
- <name>info(Address, Port, Properties) -> [{Option, Value}] </name>
+ <name since="">info(Address, Port) -> </name>
+ <name since="">info(Address, Port, Profile) -> </name>
+ <name since="OTP 18.0">info(Address, Port, Profile, Properties) -> [{Option, Value}] </name>
+ <name since="">info(Address, Port, Properties) -> [{Option, Value}] </name>
<fsummary>Fetches information about the HTTP server.</fsummary>
<type>
<v>Address = ip_address()</v>
@@ -927,7 +927,7 @@ text/plain asc txt</pre>
</func>
<func>
- <name>reload_config(Config, Mode) -> ok | {error, Reason}</name>
+ <name since="">reload_config(Config, Mode) -> ok | {error, Reason}</name>
<fsummary>Reloads the HTTP server configuration without
restarting the server.</fsummary>
<type>
@@ -1051,7 +1051,7 @@ text/plain asc txt</pre>
</section>
<funcs>
<func>
- <name>Module:do(ModData)-> {proceed, OldData} | {proceed, NewData} | {break, NewData} | done</name>
+ <name since="">Module:do(ModData)-> {proceed, OldData} | {proceed, NewData} | {break, NewData} | done</name>
<fsummary>Called for each request to the web server.</fsummary>
<type>
<v>OldData = list()</v>
@@ -1105,7 +1105,7 @@ text/plain asc txt</pre>
</func>
<func>
- <name>Module:load(Line, AccIn)-> eof | ok | {ok, AccOut} | {ok, AccOut, {Option, Value}} | {ok, AccOut, [{Option, Value}]} | {error, Reason}</name>
+ <name since="">Module:load(Line, AccIn)-> eof | ok | {ok, AccOut} | {ok, AccOut, {Option, Value}} | {ok, AccOut, [{Option, Value}]} | {error, Reason}</name>
<fsummary>Converts a line in an Apache-like config
file to an <c>{Option, Value}</c> tuple.</fsummary>
<type>
@@ -1128,7 +1128,7 @@ text/plain asc txt</pre>
</func>
<func>
- <name>Module:remove(ConfigDB) -> ok | {error, Reason} </name>
+ <name since="">Module:remove(ConfigDB) -> ok | {error, Reason} </name>
<fsummary>Callback function that is called when the web server is closed.</fsummary>
<type>
<v>ConfigDB = ets_table()</v>
@@ -1143,7 +1143,7 @@ text/plain asc txt</pre>
</func>
<func>
- <name>Module:store({Option, Value}, Config)-> {ok, {Option, NewValue}} | {error, Reason}</name>
+ <name since="">Module:store({Option, Value}, Config)-> {ok, {Option, NewValue}} | {error, Reason}</name>
<fsummary>Checks the validity of the configuration options.</fsummary>
<type>
<v>Line = string()</v>
@@ -1171,7 +1171,7 @@ text/plain asc txt</pre>
</section>
<funcs>
<func>
- <name>parse_query(QueryString) -> [{Key,Value}]</name>
+ <name since="">parse_query(QueryString) -> [{Key,Value}]</name>
<fsummary>Parses incoming data to <c>erl</c> and <c>eval</c> scripts.</fsummary>
<type>
<v>QueryString = string()</v>
diff --git a/lib/inets/doc/src/httpd_custom_api.xml b/lib/inets/doc/src/httpd_custom_api.xml
index d2e5441895..2c0f92ff83 100644
--- a/lib/inets/doc/src/httpd_custom_api.xml
+++ b/lib/inets/doc/src/httpd_custom_api.xml
@@ -25,7 +25,7 @@
<title>httpd_custom_api</title>
<file>httpd_custom_api.xml</file>
</header>
- <module>httpd_custom_api</module>
+ <module since="OTP 17.5.6">httpd_custom_api</module>
<modulesummary>Behaviour with optional callbacks to customize the inets HTTP server.</modulesummary>
<description>
<p> The module implementing this behaviour shall be supplied to to the servers
@@ -34,7 +34,7 @@
</description>
<funcs>
<func>
- <name>response_default_headers() -> [Header] </name>
+ <name since="OTP 18.1.1">response_default_headers() -> [Header] </name>
<fsummary>Provide default headers for the HTTP servers responses.</fsummary>
<type>
<v>Header = {HeaderName :: string(), HeaderValue::string()}</v>
@@ -48,7 +48,7 @@
</func>
<func>
- <name>response_header({HeaderName, HeaderValue}) -> {true, Header} | false </name>
+ <name since="OTP 17.5.6">response_header({HeaderName, HeaderValue}) -> {true, Header} | false </name>
<fsummary>Filter and possible alter HTTP response headers.</fsummary>
<type>
<v>Header = {HeaderName :: string(), HeaderValue::string()}</v>
@@ -61,7 +61,7 @@
</func>
<func>
- <name>request_header({HeaderName, HeaderValue}) -> {true, Header} | false </name>
+ <name since="OTP 17.5.6">request_header({HeaderName, HeaderValue}) -> {true, Header} | false </name>
<fsummary>Filter and possible alter HTTP request headers.</fsummary>
<type>
<v>Header = {HeaderName :: string(), HeaderValue::string()}</v>
diff --git a/lib/inets/doc/src/httpd_socket.xml b/lib/inets/doc/src/httpd_socket.xml
index d3aa82a540..22ead06f38 100644
--- a/lib/inets/doc/src/httpd_socket.xml
+++ b/lib/inets/doc/src/httpd_socket.xml
@@ -29,7 +29,7 @@
<rev>2.2</rev>
<file>httpd_socket.sgml</file>
</header>
- <module>httpd_socket</module>
+ <module since="">httpd_socket</module>
<modulesummary>Communication utility functions to be used by the Erlang
web server API programmer.</modulesummary>
<description>
@@ -43,7 +43,7 @@
<funcs>
<func>
- <name>deliver(SocketType, Socket, Data) -> Result</name>
+ <name since="">deliver(SocketType, Socket, Data) -> Result</name>
<fsummary>Sends binary data over socket.</fsummary>
<type>
<v>SocketType = socket_type()</v>
@@ -63,7 +63,7 @@
</func>
<func>
- <name>peername(SocketType,Socket) -> {Port,IPAddress}</name>
+ <name since="">peername(SocketType,Socket) -> {Port,IPAddress}</name>
<fsummary>Returns the port and IP address of the remote socket.</fsummary>
<type>
<v>SocketType = socket_type()</v>
@@ -81,7 +81,7 @@
</func>
<func>
- <name>resolve() -> HostName</name>
+ <name since="">resolve() -> HostName</name>
<fsummary>Returns the official name of the current host.</fsummary>
<type>
<v>HostName = string()</v>
diff --git a/lib/inets/doc/src/httpd_util.xml b/lib/inets/doc/src/httpd_util.xml
index 220a2ede35..e0f947f860 100644
--- a/lib/inets/doc/src/httpd_util.xml
+++ b/lib/inets/doc/src/httpd_util.xml
@@ -29,7 +29,7 @@
<rev>2.2</rev>
<file>httpd_util.sgml</file>
</header>
- <module>httpd_util</module>
+ <module since="">httpd_util</module>
<modulesummary>Miscellaneous utility functions to be used when implementing
Erlang web server API modules.</modulesummary>
<description>
@@ -41,12 +41,11 @@
<funcs>
<func>
- <name>convert_request_date(DateString) -> ErlDate|bad_date</name>
+ <name since="">convert_request_date(DateString) -> ErlDate|bad_date</name>
<fsummary>Converts the date to the Erlang date format.</fsummary>
<type>
<v>DateString = string()</v>
- <v>ErlDate = {{Year,Month,Date},{Hour,Min,Sec}}</v>
- <v>Year = Month = Date = Hour = Min = Sec = integer()</v>
+ <v>ErlDate = calendar:datetime() </v>
</type>
<desc>
<p><c>convert_request_date/1</c> converts <c>DateString</c> to
@@ -57,7 +56,7 @@
</func>
<func>
- <name>create_etag(FileInfo) -> Etag</name>
+ <name since="">create_etag(FileInfo) -> Etag</name>
<fsummary>Calculates the Etag for a file.</fsummary>
<type>
<v>FileInfo = file_info()</v>
@@ -71,7 +70,7 @@
</func>
<func>
- <name>day(NthDayOfWeek) -> DayOfWeek</name>
+ <name since="">day(NthDayOfWeek) -> DayOfWeek</name>
<fsummary>Converts the day of the week
(integer [1-7]) to an abbreviated string.</fsummary>
<type>
@@ -87,7 +86,7 @@
</func>
<func>
- <name>decode_hex(HexValue) -> DecValue</name>
+ <name since="">decode_hex(HexValue) -> DecValue</name>
<fsummary>Converts a hexadecimal value into its decimal equivalent.</fsummary>
<type>
<v>HexValue = DecValue = string()</v>
@@ -99,7 +98,7 @@
</func>
<func>
- <name>flatlength(NestedList) -> Size</name>
+ <name since="">flatlength(NestedList) -> Size</name>
<fsummary>Computes the size of a possibly nested list.</fsummary>
<type>
<v>NestedList = list()</v>
@@ -112,7 +111,7 @@
</func>
<func>
- <name>hexlist_to_integer(HexString) -> Number</name>
+ <name since="">hexlist_to_integer(HexString) -> Number</name>
<fsummary>Converts a hexadecimal string to an integer.</fsummary>
<type>
<v>Number = integer()</v>
@@ -125,7 +124,7 @@
</func>
<func>
- <name>integer_to_hexlist(Number) -> HexString</name>
+ <name since="">integer_to_hexlist(Number) -> HexString</name>
<fsummary>Converts an integer to a hexadecimal string.</fsummary>
<type>
<v>Number = integer()</v>
@@ -138,8 +137,8 @@
</func>
<func>
- <name>lookup(ETSTable,Key) -> Result</name>
- <name>lookup(ETSTable,Key,Undefined) -> Result</name>
+ <name since="">lookup(ETSTable,Key) -> Result</name>
+ <name since="">lookup(ETSTable,Key,Undefined) -> Result</name>
<fsummary>Extracts the first value associated with a <c>Key</c>
in an ETS table.</fsummary>
<type>
@@ -160,8 +159,8 @@
</func>
<func>
- <name>lookup_mime(ConfigDB,Suffix)</name>
- <name>lookup_mime(ConfigDB,Suffix,Undefined) -> MimeType</name>
+ <name since="">lookup_mime(ConfigDB,Suffix)</name>
+ <name since="">lookup_mime(ConfigDB,Suffix,Undefined) -> MimeType</name>
<fsummary>Returns the MIME type associated with a specific file suffix.</fsummary>
<type>
<v>ConfigDB = ets_table()</v>
@@ -179,8 +178,8 @@
</func>
<func>
- <name>lookup_mime_default(ConfigDB,Suffix)</name>
- <name>lookup_mime_default(ConfigDB,Suffix,Undefined) -> MimeType</name>
+ <name since="">lookup_mime_default(ConfigDB,Suffix)</name>
+ <name since="">lookup_mime_default(ConfigDB,Suffix,Undefined) -> MimeType</name>
<fsummary>Returns the MIME type associated with a specific file suffix
or the value of the DefaultType.</fsummary>
<type>
@@ -201,7 +200,7 @@
</func>
<func>
- <name>message(StatusCode,PhraseArgs,ConfigDB) -> Message</name>
+ <name since="">message(StatusCode,PhraseArgs,ConfigDB) -> Message</name>
<fsummary>Returns an informative HTTP 1.1 status string in HTML.</fsummary>
<type>
<v>StatusCode = 301 | 400 | 403 | 404 | 500 | 501 | 504</v>
@@ -236,7 +235,7 @@
</func>
<func>
- <name>month(NthMonth) -> Month</name>
+ <name since="">month(NthMonth) -> Month</name>
<fsummary>Converts the month as an integer (1-12) to an abbreviated string.</fsummary>
<type>
<v>NthMonth = 1-12</v>
@@ -250,7 +249,7 @@
</func>
<func>
- <name>multi_lookup(ETSTable,Key) -> Result</name>
+ <name since="">multi_lookup(ETSTable,Key) -> Result</name>
<fsummary>Extracts the values associated with a key in an ETS table.</fsummary>
<type>
<v>ETSTable = ets_table()</v>
@@ -265,7 +264,7 @@
</func>
<func>
- <name>reason_phrase(StatusCode) -> Description</name>
+ <name since="">reason_phrase(StatusCode) -> Description</name>
<fsummary>Returns the description of an HTTP 1.1 status code.</fsummary>
<type>
<v>StatusCode = 100| 200 | 201 | 202 | 204 | 205 | 206 | 300 | 301 | 302 | 303 | 304 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 410 411 | 412 | 413 | 414 415 | 416 | 417 | 500 | 501 | 502 | 503 | 504 | 505</v>
@@ -280,11 +279,11 @@
</func>
<func>
- <name>rfc1123_date() -> RFC1123Date</name>
- <name>rfc1123_date({{YYYY,MM,DD},{Hour,Min,Sec}}) -> RFC1123Date</name>
+ <name since="">rfc1123_date() -> RFC1123Date</name>
+ <name since="">rfc1123_date(Date) -> RFC1123Date</name>
<fsummary>Returns the current date in RFC 1123 format.</fsummary>
<type>
- <v>YYYY = MM = DD = Hour = Min = Sec = integer()</v>
+ <v> Date = calendar:datetime()</v>
<v>RFC1123Date = string()</v>
</type>
<desc>
@@ -295,7 +294,7 @@
</func>
<func>
- <name>split(String,RegExp,N) -> SplitRes</name>
+ <name since="">split(String,RegExp,N) -> SplitRes</name>
<fsummary>Splits a string in N chunks using a regular expression.</fsummary>
<type>
<v>String = RegExp = string()</v>
@@ -313,7 +312,7 @@
</func>
<func>
- <name>split_script_path(RequestLine) -> Splitted</name>
+ <name since="">split_script_path(RequestLine) -> Splitted</name>
<fsummary>Splits a <c>RequestLine</c> in a file reference to an executable,
and a <c>QueryString</c> or a <c>PathInfo</c>string.</fsummary>
<type>
@@ -330,7 +329,7 @@
</func>
<func>
- <name>split_path(RequestLine) -> {Path,QueryStringOrPathInfo}</name>
+ <name since="">split_path(RequestLine) -> {Path,QueryStringOrPathInfo}</name>
<fsummary>Splits a <c>RequestLine</c> in a file reference, and a
<c>QueryString</c> or a <c>PathInfo</c> string.</fsummary>
<type>
@@ -356,7 +355,7 @@
</func>
<func>
- <name>strip(String) -> Stripped</name>
+ <name since="">strip(String) -> Stripped</name>
<fsummary>Returns <c>String</c> where the leading and trailing space
tabs are removed.</fsummary>
<type>
@@ -370,7 +369,7 @@
</func>
<func>
- <name>suffix(FileName) -> Suffix</name>
+ <name since="">suffix(FileName) -> Suffix</name>
<fsummary>Extracts the file suffix from a given filename.</fsummary>
<type>
<v>FileName = Suffix = string()</v>
diff --git a/lib/inets/doc/src/inets.xml b/lib/inets/doc/src/inets.xml
index 137381cbe9..176af3137a 100644
--- a/lib/inets/doc/src/inets.xml
+++ b/lib/inets/doc/src/inets.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2007</year><year>2016</year>
+ <year>2007</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -29,7 +29,7 @@
<date></date>
<rev></rev>
</header>
- <module>inets</module>
+ <module since="">inets</module>
<modulesummary>The Inets services API.</modulesummary>
<description>
<p>This module provides the most basic API to the
@@ -51,7 +51,7 @@
<funcs>
<func>
- <name>services() -> [{Service, Pid}]</name>
+ <name since="">services() -> [{Service, Pid}]</name>
<fsummary>Returns a list of currently running services.</fsummary>
<type>
<v>Service = service()</v>
@@ -68,7 +68,7 @@
</func>
<func>
- <name>services_info() -> [{Service, Pid, Info}]</name>
+ <name since="">services_info() -> [{Service, Pid, Info}]</name>
<fsummary>Returns a list of currently running services where
each service is described by an <c>[{Option, Value}]</c>
list.</fsummary>
@@ -91,7 +91,7 @@
</func>
<func>
- <name>service_names() -> [Service] </name>
+ <name since="">service_names() -> [Service] </name>
<fsummary>Returns a list of available service names.</fsummary>
<type>
<v>Service = service()</v>
@@ -104,8 +104,8 @@
</func>
<func>
- <name>start() -> </name>
- <name>start(Type) -> ok | {error, Reason}</name>
+ <name since="">start() -> </name>
+ <name since="">start(Type) -> ok | {error, Reason}</name>
<fsummary>Starts the <c>Inets</c> application.</fsummary>
<type>
<v>Type = permanent | transient | temporary</v>
@@ -120,8 +120,8 @@
</func>
<func>
- <name>start(Service, ServiceConfig) -> {ok, Pid} | {error, Reason}</name>
- <name>start(Service, ServiceConfig, How) -> {ok, Pid} | {error, Reason}</name>
+ <name since="">start(Service, ServiceConfig) -> {ok, Pid} | {error, Reason}</name>
+ <name since="">start(Service, ServiceConfig, How) -> {ok, Pid} | {error, Reason}</name>
<fsummary>Dynamically starts an <c>Inets</c>
service after the <c>Inets</c> application has been started.</fsummary>
<type>
@@ -156,7 +156,7 @@
</func>
<func>
- <name>stop() -> ok </name>
+ <name since="">stop() -> ok </name>
<fsummary>Stops the <c>Inets</c> application.</fsummary>
<desc>
<p>Stops the <c>Inets</c> application. See also
@@ -167,7 +167,7 @@
</func>
<func>
- <name>stop(Service, Reference) -> ok | {error, Reason} </name>
+ <name since="">stop(Service, Reference) -> ok | {error, Reason} </name>
<fsummary>Stops a started service of the <c>Inets</c> application or takes
down a <c>stand_alone </c>service gracefully.</fsummary>
<type>
@@ -188,10 +188,9 @@
<section>
<title>SEE ALSO</title>
- <p><seealso marker="ftp">ftp(3)</seealso>,
- <seealso marker="httpc">httpc(3)</seealso>,
- <seealso marker="httpd">httpd(3)</seealso>,
- <seealso marker="tftp">tftp(3)</seealso></p>
+ <p><seealso marker="httpc">httpc(3)</seealso>,
+ <seealso marker="httpd">httpd(3)</seealso>
+ </p>
</section>
</erlref>
diff --git a/lib/inets/doc/src/introduction.xml b/lib/inets/doc/src/introduction.xml
index 1af2ef5dae..faf911f188 100644
--- a/lib/inets/doc/src/introduction.xml
+++ b/lib/inets/doc/src/introduction.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -22,12 +22,12 @@
</legalnotice>
<title>Introduction</title>
- <prepared>Ingela Anderton Andin</prepared>
+ <prepared>Péter Dimitrov</prepared>
<responsible></responsible>
<docno></docno>
<approved></approved>
<checked></checked>
- <date>2004-09-28</date>
+ <date>2018-02-28</date>
<rev>A</rev>
<file>introduction.xml</file>
</header>
@@ -37,8 +37,6 @@
<p><c>Inets</c> is a container for Internet clients and servers
including the following:</p>
<list type="bulleted">
- <item>An FTP client</item>
- <item>A TFTP client and server</item>
<item>An <term id="HTTP"></term> client and server</item>
</list>
<p>The HTTP client and server are HTTP 1.1 compliant as
@@ -50,7 +48,7 @@
<title>Prerequisites</title>
<p>It is assumed that the reader is familiar with the Erlang
programming language, concepts of OTP, and has a basic
- understanding of the FTP, TFTP, and HTTP protocols.</p>
+ understanding of and HTTP protocol.</p>
</section>
</chapter>
diff --git a/lib/inets/doc/src/mod_alias.xml b/lib/inets/doc/src/mod_alias.xml
index 6ae19700a5..ff57d49d08 100644
--- a/lib/inets/doc/src/mod_alias.xml
+++ b/lib/inets/doc/src/mod_alias.xml
@@ -29,7 +29,7 @@
<rev>2.2</rev>
<file>mod_alias.sgml</file>
</header>
- <module>mod_alias</module>
+ <module since="">mod_alias</module>
<modulesummary>URL aliasing.</modulesummary>
<description>
<p>Erlang web server internal API for handling of, for example,
@@ -40,7 +40,7 @@
<funcs>
<func>
- <name>default_index(ConfigDB, Path) -> NewPath</name>
+ <name since="">default_index(ConfigDB, Path) -> NewPath</name>
<fsummary>Returns a new path with the default resource or file appended.</fsummary>
<type>
<v>ConfigDB = config_db()</v>
@@ -64,7 +64,7 @@
</func>
<func>
- <name>path(PathData, ConfigDB, RequestURI) -> Path</name>
+ <name since="">path(PathData, ConfigDB, RequestURI) -> Path</name>
<fsummary>Returns the file path to a URL.</fsummary>
<type>
<v>PathData = interaction_data()</v>
@@ -89,7 +89,7 @@
</func>
<func>
- <name>real_name(ConfigDB, RequestURI, Aliases) -> Ret</name>
+ <name since="">real_name(ConfigDB, RequestURI, Aliases) -> Ret</name>
<fsummary>Expands a request URI using <c>Aliases</c> config directives.</fsummary>
<type>
<v>ConfigDB = config_db()</v>
@@ -120,7 +120,7 @@
</func>
<func>
- <name>real_script_name(ConfigDB, RequestURI, ScriptAliases) -> Ret</name>
+ <name since="">real_script_name(ConfigDB, RequestURI, ScriptAliases) -> Ret</name>
<fsummary>Expands a request URI using <c>ScriptAliases</c>
config directives.</fsummary>
<type>
diff --git a/lib/inets/doc/src/mod_auth.xml b/lib/inets/doc/src/mod_auth.xml
index c4f844622b..ad864ca4d1 100644
--- a/lib/inets/doc/src/mod_auth.xml
+++ b/lib/inets/doc/src/mod_auth.xml
@@ -29,7 +29,7 @@
<rev>2.3</rev>
<file>mod_auth.sgml</file>
</header>
- <module>mod_auth</module>
+ <module since="">mod_auth</module>
<modulesummary>User authentication using text files, Dets, or Mnesia database.</modulesummary>
<description>
<p>This module provides for basic user authentication using
@@ -38,9 +38,9 @@
<funcs>
<func>
- <name>add_group_member(GroupName, UserName, Options) -> true | {error, Reason}</name>
- <name>add_group_member(GroupName, UserName, Port, Dir) -> true | {error, Reason}</name>
- <name>add_group_member(GroupName, UserName, Address, Port, Dir) -> true | {error, Reason}</name>
+ <name since="">add_group_member(GroupName, UserName, Options) -> true | {error, Reason}</name>
+ <name since="">add_group_member(GroupName, UserName, Port, Dir) -> true | {error, Reason}</name>
+ <name since="">add_group_member(GroupName, UserName, Address, Port, Dir) -> true | {error, Reason}</name>
<fsummary>Adds a user to a group.</fsummary>
<type>
<v>GroupName = string()</v>
@@ -65,9 +65,9 @@
</func>
<func>
- <name>add_user(UserName, Options) -> true| {error, Reason}</name>
- <name>add_user(UserName, Password, UserData, Port, Dir) -> true | {error, Reason}</name>
- <name>add_user(UserName, Password, UserData, Address, Port, Dir) -> true | {error, Reason}</name>
+ <name since="">add_user(UserName, Options) -> true| {error, Reason}</name>
+ <name since="">add_user(UserName, Password, UserData, Port, Dir) -> true | {error, Reason}</name>
+ <name since="">add_user(UserName, Password, UserData, Address, Port, Dir) -> true | {error, Reason}</name>
<fsummary>Adds a user to the user database.</fsummary>
<type>
<v>UserName = string()</v>
@@ -92,8 +92,8 @@
</func>
<func>
- <name>delete_group(GroupName, Options) -> true | {error,Reason} &lt;name>delete_group(GroupName, Port, Dir) -> true | {error, Reason}</name>
- <name>delete_group(GroupName, Address, Port, Dir) -> true | {error, Reason}</name>
+ <name since="">delete_group(GroupName, Options) -> true | {error,Reason} &lt;name>delete_group(GroupName, Port, Dir) -> true | {error, Reason}</name>
+ <name since="">delete_group(GroupName, Address, Port, Dir) -> true | {error, Reason}</name>
<fsummary>Deletes a group.</fsummary>
<type>
<v>Options = [Option]</v>
@@ -115,9 +115,9 @@
</func>
<func>
- <name>delete_group_member(GroupName, UserName, Options) -> true | {error, Reason}</name>
- <name>delete_group_member(GroupName, UserName, Port, Dir) -> true | {error, Reason}</name>
- <name>delete_group_member(GroupName, UserName, Address, Port, Dir) -> true | {error, Reason}</name>
+ <name since="">delete_group_member(GroupName, UserName, Options) -> true | {error, Reason}</name>
+ <name since="">delete_group_member(GroupName, UserName, Port, Dir) -> true | {error, Reason}</name>
+ <name since="">delete_group_member(GroupName, UserName, Address, Port, Dir) -> true | {error, Reason}</name>
<fsummary>Removes a user from a group.</fsummary>
<type>
<v>GroupName = string()</v>
@@ -141,9 +141,9 @@
</func>
<func>
- <name>delete_user(UserName,Options) -> true | {error, Reason}</name>
- <name>delete_user(UserName, Port, Dir) -> true | {error, Reason}</name>
- <name>delete_user(UserName, Address, Port, Dir) -> true | {error, Reason}</name>
+ <name since="">delete_user(UserName,Options) -> true | {error, Reason}</name>
+ <name since="">delete_user(UserName, Port, Dir) -> true | {error, Reason}</name>
+ <name since="">delete_user(UserName, Address, Port, Dir) -> true | {error, Reason}</name>
<fsummary>Deletes a user from the user database.</fsummary>
<type>
<v>UserName = string()</v>
@@ -166,9 +166,9 @@
</func>
<func>
- <name>get_user(UserName,Options) -> {ok, #httpd_user} |{error, Reason}</name>
- <name>get_user(UserName, Port, Dir) -> {ok, #httpd_user} | {error, Reason}</name>
- <name>get_user(UserName, Address, Port, Dir) -> {ok, #httpd_user} | {error, Reason}</name>
+ <name since="">get_user(UserName,Options) -> {ok, #httpd_user} |{error, Reason}</name>
+ <name since="">get_user(UserName, Port, Dir) -> {ok, #httpd_user} | {error, Reason}</name>
+ <name since="">get_user(UserName, Address, Port, Dir) -> {ok, #httpd_user} | {error, Reason}</name>
<fsummary>Returns a user from the user database.</fsummary>
<type>
<v>UserName = string()</v>
@@ -190,9 +190,9 @@
</func>
<func>
- <name>list_groups(Options) -> {ok, Groups} | {error, Reason}</name>
- <name>list_groups(Port, Dir) -> {ok, Groups} | {error, Reason}</name>
- <name>list_groups(Address, Port, Dir) -> {ok, Groups} | {error, Reason}</name>
+ <name since="">list_groups(Options) -> {ok, Groups} | {error, Reason}</name>
+ <name since="">list_groups(Port, Dir) -> {ok, Groups} | {error, Reason}</name>
+ <name since="">list_groups(Address, Port, Dir) -> {ok, Groups} | {error, Reason}</name>
<fsummary>Lists all the groups.</fsummary>
<type>
<v>Options = [Option]</v>
@@ -214,9 +214,9 @@
</func>
<func>
- <name>list_group_members(GroupName, Options) -> {ok, Users} | {error, Reason}</name>
- <name>list_group_members(GroupName, Port, Dir) -> {ok, Users} | {error, Reason}</name>
- <name>list_group_members(GroupName, Address, Port, Dir) -> {ok, Users} | {error, Reason}</name>
+ <name since="">list_group_members(GroupName, Options) -> {ok, Users} | {error, Reason}</name>
+ <name since="">list_group_members(GroupName, Port, Dir) -> {ok, Users} | {error, Reason}</name>
+ <name since="">list_group_members(GroupName, Address, Port, Dir) -> {ok, Users} | {error, Reason}</name>
<fsummary>Lists the members of a group.</fsummary>
<type>
<v>GroupName = string()</v>
@@ -240,9 +240,9 @@
</func>
<func>
- <name>list_users(Options) -> {ok, Users} | {error, Reason}</name>
- <name>list_users(Port, Dir) -> {ok, Users} | {error, Reason}</name>
- <name>list_users(Address, Port, Dir) -> {ok, Users} | {error, Reason}</name>
+ <name since="">list_users(Options) -> {ok, Users} | {error, Reason}</name>
+ <name since="OTP R14B01">list_users(Port, Dir) -> {ok, Users} | {error, Reason}</name>
+ <name since="">list_users(Address, Port, Dir) -> {ok, Users} | {error, Reason}</name>
<fsummary>Lists users in the user database.</fsummary>
<type>
<v>Options = [Option]</v>
@@ -264,8 +264,8 @@
</func>
<func>
- <name>update_password(Port, Dir, OldPassword, NewPassword, NewPassword) -> ok | {error, Reason}</name>
- <name>update_password(Address,Port, Dir, OldPassword, NewPassword, NewPassword) -> ok | {error, Reason}</name>
+ <name since="">update_password(Port, Dir, OldPassword, NewPassword, NewPassword) -> ok | {error, Reason}</name>
+ <name since="">update_password(Address,Port, Dir, OldPassword, NewPassword, NewPassword) -> ok | {error, Reason}</name>
<fsummary>Changes <c>AuthAcessPassword</c>.</fsummary>
<type>
<v>Port = integer()</v>
diff --git a/lib/inets/doc/src/mod_esi.xml b/lib/inets/doc/src/mod_esi.xml
index d024c8afa8..bc5f98068f 100644
--- a/lib/inets/doc/src/mod_esi.xml
+++ b/lib/inets/doc/src/mod_esi.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -25,7 +25,7 @@
<title>mod_esi</title>
<file>mod_esi.sgml</file>
</header>
- <module>mod_esi</module>
+ <module since="">mod_esi</module>
<modulesummary>Erlang Server Interface</modulesummary>
<description>
<p>This module defines the Erlang Server Interface (ESI) API.
@@ -88,7 +88,7 @@
<funcs>
<func>
- <name>deliver(SessionID, Data) -> ok | {error, Reason}</name>
+ <name since="">deliver(SessionID, Data) -> ok | {error, Reason}</name>
<fsummary>Sends <c>Data</c> back to client.</fsummary>
<type>
<v>SessionID = term()</v>
@@ -121,7 +121,7 @@
<funcs>
<func>
- <name>Module:Function(SessionID, Env, Input)-> {continue, State} | _ </name>
+ <name since="">Module:Function(SessionID, Env, Input)-> {continue, State} | _ </name>
<fsummary>Creates a dynamic web page and returns it chunk by chunk
to the server process by calling <c>mod_esi:deliver/2</c>.</fsummary>
<type>
@@ -179,7 +179,7 @@
</func>
<func>
- <name>Module:Function(Env, Input)-> Response </name>
+ <name since="">Module:Function(Env, Input)-> Response </name>
<fsummary>Creates a dynamic web page and returns it as a list.
This function is deprecated and is only kept for backwards compatibility.</fsummary>
<type>
diff --git a/lib/inets/doc/src/mod_security.xml b/lib/inets/doc/src/mod_security.xml
index ec8d6ec42c..c26d7468c2 100644
--- a/lib/inets/doc/src/mod_security.xml
+++ b/lib/inets/doc/src/mod_security.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1998</year><year>2016</year>
+ <year>1998</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -29,7 +29,7 @@
<rev>1.0</rev>
<file>mod_security.sgml</file>
</header>
- <module>mod_security</module>
+ <module since="">mod_security</module>
<modulesummary>Security Audit and Trailing Functionality</modulesummary>
<description>
<p>Security Audit and Trailing Functionality</p>
@@ -37,8 +37,8 @@
<funcs>
<func>
- <name>block_user(User, Port, Dir, Seconds) -> true | {error, Reason}</name>
- <name>block_user(User, Address, Port, Dir, Seconds) -> true | {error, Reason}</name>
+ <name since="">block_user(User, Port, Dir, Seconds) -> true | {error, Reason}</name>
+ <name since="">block_user(User, Address, Port, Dir, Seconds) -> true | {error, Reason}</name>
<fsummary>Blocks a user from access to a directory for a certain amount of time.</fsummary>
<type>
<v>User = string()</v>
@@ -56,10 +56,10 @@
</func>
<func>
- <name>list_auth_users(Port) -> Users | []</name>
- <name>list_auth_users(Address, Port) -> Users | []</name>
- <name>list_auth_users(Port, Dir) -> Users | []</name>
- <name>list_auth_users(Address, Port, Dir) -> Users | []</name>
+ <name since="">list_auth_users(Port) -> Users | []</name>
+ <name since="">list_auth_users(Address, Port) -> Users | []</name>
+ <name since="">list_auth_users(Port, Dir) -> Users | []</name>
+ <name since="">list_auth_users(Address, Port, Dir) -> Users | []</name>
<fsummary>Lists users that have authenticated within the <c>SecurityAuthTimeout</c>
time for a given address (if specified), port number, and directory
(if specified).</fsummary>
@@ -77,10 +77,10 @@
</desc>
</func>
<func>
- <name>list_blocked_users(Port) -> Users | []</name>
- <name>list_blocked_users(Address, Port) -> Users | []</name>
- <name>list_blocked_users(Port, Dir) -> Users | []</name>
- <name>list_blocked_users(Address, Port, Dir) -> Users | []</name>
+ <name since="">list_blocked_users(Port) -> Users | []</name>
+ <name since="">list_blocked_users(Address, Port) -> Users | []</name>
+ <name since="">list_blocked_users(Port, Dir) -> Users | []</name>
+ <name since="">list_blocked_users(Address, Port, Dir) -> Users | []</name>
<fsummary>Lists users that are currently blocked from access to a
specified port number, for a given address (if specified).</fsummary>
<type>
@@ -97,10 +97,10 @@
</func>
<func>
- <name>unblock_user(User, Port) -> true | {error, Reason}</name>
- <name>unblock_user(User, Address, Port) -> true | {error, Reason}</name>
- <name>unblock_user(User, Port, Dir) -> true | {error, Reason}</name>
- <name>unblock_user(User, Address, Port, Dir) -> true | {error, Reason}</name>
+ <name since="">unblock_user(User, Port) -> true | {error, Reason}</name>
+ <name since="">unblock_user(User, Address, Port) -> true | {error, Reason}</name>
+ <name since="">unblock_user(User, Port, Dir) -> true | {error, Reason}</name>
+ <name since="">unblock_user(User, Address, Port, Dir) -> true | {error, Reason}</name>
<fsummary>Removes a blocked user from the block list.</fsummary>
<type>
<v>User = string()</v>
@@ -129,13 +129,14 @@
<funcs>
<func>
- <name>Module:event(What, Port, Dir, Data) -> ignored</name>
- <name>Module:event(What, Address, Port, Dir, Data) -> ignored</name>
+ <name since="OTP 18.1">Module:event(What, Port, Dir, Data) -> ignored</name>
+ <name since="OTP 18.1">Module:event(What, Address, Port, Dir, Data) -> ignored</name>
<fsummary>Called whenever an event occurs in <c>mod_security</c>.</fsummary>
<type>
<v>What = atom()</v>
<v>Port = integer()</v>
- <v>Address = {A,B,C,D} | string() &lt;v>Dir = string()</v>
+ <v>Address = {A,B,C,D} | string()</v>
+ <v>Dir = string()</v>
<v>Data = [Info]</v>
<v>Info = {Name, Value}</v>
</type>
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index 0417e07de8..03bd1d8042 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2002</year><year>2017</year>
+ <year>2002</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -33,7 +33,368 @@
<file>notes.xml</file>
</header>
- <section><title>Inets 6.5</title>
+ <section><title>Inets 7.0.8</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ All incorrect (that is, all) uses of "can not" has been
+ corrected to "cannot" in source code comments,
+ documentation, examples, and so on.</p>
+ <p>
+ Own Id: OTP-14282 Aux Id: PR-1891 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 7.0.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix the internal handling of the option
+ erl_script_timeout in httpd. If explicit
+ erl_script_timeout value was supplied in seconds it was
+ not correctly converted to millisecond units for internal
+ usage.</p>
+ <p>
+ This change fixes the handling of erl_script_timeout in
+ all possible configuration scenarios.</p>
+ <p>
+ Own Id: OTP-15769 Aux Id: ERIERL-345 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 7.0.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix the internal handling of the option
+ erl_script_timeout in httpd. When httpd was started with
+ explicit erl_script_timeout, the value of the option was
+ converted to milliseconds before storage. Subsequent
+ calls to httpd:info/1 returned the input value multiplied
+ by 1000.</p>
+ <p>
+ This change fixes the handing of erl_script_timeout by
+ storing the timeout in seconds and converting to
+ milliseconds before usage.</p>
+ <p>
+ Own Id: OTP-15669 Aux Id: ERIERL-321 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Enhance documentation</p>
+ <p>
+ Own Id: OTP-15508 Aux Id: ERL-816 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 7.0.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed bug that causes a crash in http client when using
+ hostnames (e.g. localhost) with the the option
+ ipv6_host_with_brackets set to true.</p>
+ <p>
+ This change also fixes a regression: httpc:request fails
+ with connection error (nxdomain) if option
+ ipv6_host_with_brackets set to true and host component of
+ the URI is an IPv6 address.</p>
+ <p>
+ Own Id: OTP-15554 Aux Id: ERIERL-289 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 7.0.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Make sure ipv6 addresses with brackets in URIs are
+ converted correctly before passing to lower level
+ functions like gen_tcp and ssl functions. Could cause
+ connection to fail.</p>
+ <p>
+ Own Id: OTP-15544 Aux Id: ERIERL-289 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 7.0.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed http client to not send 'content-length' header in
+ chunked encoded requests.</p>
+ <p>
+ Own Id: OTP-15338 Aux Id: ERL-733 </p>
+ </item>
+ <item>
+ <p>
+ Fixed http client to not drop explicit 'Content-Type'
+ header in requests without a body such as requests with
+ the 'Content-Type' of application/x-www-form-urlencoded.</p>
+ <p>
+ Own Id: OTP-15339 Aux Id: ERL-736 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 7.0.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Enhance error handling, that is mod_get will return 403
+ if a path is a directory and not a file.</p>
+ <p>
+ Own Id: OTP-15192</p>
+ </item>
+ <item>
+ <p>
+ Do not use chunked-encoding with 1xx, 204 and 304
+ responses when using mod_esi. Old behavior was not
+ compliant with HTTP/1.1 RFC and could cause clients to
+ hang when they received 1xx, 204 or 304 responses that
+ included an empty chunked-encoded body.</p>
+ <p>
+ Own Id: OTP-15241</p>
+ </item>
+ <item>
+ <p>
+ Add robust handling of chunked-encoded HTTP responses
+ with an empty body (1xx, 204, 304). Old behavior could
+ cause the client to hang when connecting to a faulty
+ server implementation.</p>
+ <p>
+ Own Id: OTP-15242</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 7.0.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Change status code for no mod found to handle request to
+ 501</p>
+ <p>
+ Own Id: OTP-15215</p>
+ </item>
+ </list>
+ </section>
+
+ </section>
+
+ <section><title>Inets 7.0</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed HTTP content injection bug in httpc (ERL-456).</p>
+ <p>
+ Own Id: OTP-14726</p>
+ </item>
+ <item>
+ <p>
+ Fixed support for URI-references in HTTP 'Location'
+ header (ERL-333).</p>
+ <p>
+ Own Id: OTP-14729</p>
+ </item>
+ <item>
+ <p>
+ Fix broken 'Content-Type' handling in httpc (ERL-536).</p>
+ <p>
+ Own Id: OTP-15006</p>
+ </item>
+ <item>
+ <p>
+ Fix handling of relative paths in the script_alias
+ property of httpd (ERL-574).</p>
+ <p>
+ Own Id: OTP-15021</p>
+ </item>
+ <item>
+ <p>
+ Fix httpd:reload_config/2 with path() as the first
+ argument (ERL-578).</p>
+ <p>
+ Own Id: OTP-15025</p>
+ </item>
+ <item>
+ <p>
+ Improved gracefulness.</p>
+ <p>
+ Own Id: OTP-15042</p>
+ </item>
+ </list>
+ </section>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Split inets and create separate ftp and tftp apps.</p>
+ <p>
+ Own Id: OTP-14113</p>
+ </item>
+ </list>
+ </section>
+
+ </section>
+
+ <section><title>Inets 6.5.2.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Do not use chunked-encoding with 1xx, 204 and 304
+ responses when using mod_esi. Old behavior was not
+ compliant with HTTP/1.1 RFC and could cause clients to
+ hang when they received 1xx, 204 or 304 responses that
+ included an empty chunked-encoded body.</p>
+ <p>
+ Own Id: OTP-15241</p>
+ </item>
+ <item>
+ <p>
+ Add robust handling of chunked-encoded HTTP responses
+ with an empty body (1xx, 204, 304). Old behavior could
+ cause the client to hang when connecting to a faulty
+ server implementation.</p>
+ <p>
+ Own Id: OTP-15242</p>
+ </item>
+ </list>
+ </section>
+
+ </section>
+
+ <section><title>Inets 6.5.2.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Change status code for no mod found to handle request to
+ 501</p>
+ <p>
+ Own Id: OTP-15215</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 6.5.2.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Enhance error handling, that is mod_get will return 403
+ if a path is a directory and not a file.</p>
+ <p>
+ Own Id: OTP-15192</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+ <section><title>Inets 6.5.2.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Options added for setting low-level properties on the
+ underlying TCP connections. The options are:
+ <c>sock_ctrl</c>, <c>sock_data_act</c> and
+ <c>sock_data_pass</c>. See the manual for details.</p>
+ <p>
+ Own Id: OTP-15120 Aux Id: ERIERL-192 </p>
+ </item>
+ </list>
+ </section>
+
+ </section>
+
+<section><title>Inets 6.5.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ inets: httpd - Gracefully handle bad headers</p>
+ <p>
+ The option max_headers operated on the individual header
+ length instead of the total length of all headers. Also
+ headers with empty keys are now discarded.</p>
+ <p>
+ Own Id: OTP-15092</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 6.5.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix broken options handling in httpc (ERL-441).</p>
+ <p>
+ Own Id: OTP-15007</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 6.5</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
@@ -1055,7 +1416,7 @@
Add option {ftp_extension, boolean} to enable use of
extended commands EPSV and EPRT, as specified in RFC
2428, for IPv4 instead of using the legacy commands. Ipv6
- can not be supported without the extended commands.</p>
+ cannot be supported without the extended commands.</p>
<p>
Own Id: OTP-12255</p>
</item>
@@ -1766,7 +2127,7 @@
<list>
<item>
<p>[ftpc] Add a config option to specify a
- <seealso marker="ftp#dtimeout">data connect timeout</seealso>.
+ <seealso marker="ftp:ftp#dtimeout">data connect timeout</seealso>.
That is how long the ftp client will wait for the server to connect
to the data socket. If this timeout occurs, an error will be
returned to the caller and the ftp client process will be
@@ -2649,10 +3010,10 @@
<item>
<p>It is now also possible to start a standalone FTP client
process using the re-introduced
- <seealso marker="ftp#open">ftp:open</seealso>
+ <seealso marker="ftp:ftp#open">ftp:open</seealso>
function. </p>
<p>This is an alternative to starting the client using the
- <seealso marker="ftp#service_start">inets service framework</seealso>. </p>
+ <seealso marker="ftp:ftp#service_start">inets service framework</seealso>. </p>
<p>The old <c>ftp:open/1</c>, undocumented, function,
caused the client to be hooken into the inets service
supervision framework. This is <em>no</em> longer the
@@ -2665,10 +3026,10 @@
flag), and only used IPv4 if this did not work.
This has now been <em>changed</em>. </p>
<p>A new option,
- <seealso marker="ftp#ipfamily">ipfamily</seealso>,
+ <seealso marker="ftp:ftp#ipfamily">ipfamily</seealso>,
has been introduced, with the default value
<c>inet</c> (IPv4). </p>
- <p>See <seealso marker="ftp#open">ftp:open</seealso>
+ <p>See <seealso marker="ftp:ftp#open">ftp:open</seealso>
for more info.</p>
<p>*** POTENTIAL INCOMPATIBILITY ***</p>
</item>
@@ -2702,9 +3063,9 @@
<item>
<p>[ftpc] - The
- <seealso marker="ftp#ls2">ls/2</seealso> function (LIST command)
+ <seealso marker="ftp:ftp#ls2">ls/2</seealso> function (LIST command)
and the
- <seealso marker="ftp#nlist2">nlist/2</seealso> function
+ <seealso marker="ftp:ftp#nlist2">nlist/2</seealso> function
(NLST command)
with wildcards did
not work properly. </p>
diff --git a/lib/inets/doc/src/notes_history.xml b/lib/inets/doc/src/notes_history.xml
index c12899e614..1523827db9 100644
--- a/lib/inets/doc/src/notes_history.xml
+++ b/lib/inets/doc/src/notes_history.xml
@@ -1149,8 +1149,8 @@
<list type="bulleted">
<item>
<p>When further testing the functionality of https requests
- that goes through a proxy. We realised that alas this can
- not currently be supported as it requires features from
+ that goes through a proxy. We realised that alas this
+ cannot currently be supported as it requires features from
the ssl implementation that is not currently available.
So for now an error message will be returned when trying
to use this functionality.</p>
diff --git a/lib/inets/doc/src/part.xml b/lib/inets/doc/src/part.xml
index f777481b5c..b9c8ed674c 100644
--- a/lib/inets/doc/src/part.xml
+++ b/lib/inets/doc/src/part.xml
@@ -4,7 +4,7 @@
<part xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>2004</year><year>2016</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -23,9 +23,9 @@
</legalnotice>
<title>Inets User's Guide</title>
- <prepared>Ingela Anderton Andin</prepared>
+ <prepared>Péter Dimitrov</prepared>
<docno></docno>
- <date>2002-09-17</date>
+ <date>2018-02-28</date>
<rev>A</rev>
<file>part.sgml</file>
</header>
@@ -33,8 +33,6 @@
<p>The <c>Inets</c> application provides a set of
Internet-related services as follows:</p>
<list type="bulleted">
- <item>An FTP client</item>
- <item>A TFTP client and server</item>
<item>An <term id="HTTP"></term> client and server</item>
</list>
<p>The HTTP client and server are HTTP 1.1 compliant as
@@ -43,7 +41,6 @@
</description>
<xi:include href="introduction.xml"/>
<xi:include href="inets_services.xml"/>
- <xi:include href="ftp_client.xml"/>
<xi:include href="http_client.xml"/>
<xi:include href="http_server.xml"/>
</part>
diff --git a/lib/inets/doc/src/ref_man.xml b/lib/inets/doc/src/ref_man.xml
index 27021ea09a..58c1a651f9 100644
--- a/lib/inets/doc/src/ref_man.xml
+++ b/lib/inets/doc/src/ref_man.xml
@@ -4,7 +4,7 @@
<application xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>1997</year><year>2015</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -23,20 +23,16 @@
</legalnotice>
<title>Inets Reference Manual</title>
- <prepared>Joakim Greben&ouml;</prepared>
+ <prepared>Péter Dimitrov</prepared>
<docno></docno>
- <date>1997-07-16</date>
+ <date>2018-02-28</date>
<rev>2.1</rev>
<file>ref_man.xml</file>
</header>
<description>
- <p><c>Inets</c> is a container for Internet clients and
- servers. An FTP client, an HTTP client and server, and
- a TFTP client and server are incorporated in <c>Inets</c>.</p>
+ <p><c>Inets</c> is a container for an HTTP client and server.</p>
</description>
<xi:include href="inets.xml"/>
- <xi:include href="ftp.xml"/>
- <xi:include href="tftp.xml"/>
<xi:include href="httpc.xml"/>
<xi:include href="httpd.xml"/>
<xi:include href="httpd_custom_api.xml"/>
diff --git a/lib/inets/doc/src/tftp.xml b/lib/inets/doc/src/tftp.xml
deleted file mode 100644
index 10398f5088..0000000000
--- a/lib/inets/doc/src/tftp.xml
+++ /dev/null
@@ -1,647 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2006</year><year>2015</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>tftp</title>
- <prepared></prepared>
- <docno></docno>
- <date></date>
- <rev></rev>
- </header>
- <module>tftp</module>
- <modulesummary>Trivial FTP.</modulesummary>
- <description>
- <p>This is a complete implementation of the following IETF standards:</p>
- <list type="bulleted">
- <item>RFC 1350, The TFTP Protocol (revision 2)</item>
- <item>RFC 2347, TFTP Option Extension</item>
- <item>RFC 2348, TFTP Blocksize Option</item>
- <item>RFC 2349, TFTP Timeout Interval and Transfer Size Options</item>
- </list>
- <p>The only feature that not is implemented is
- the "netascii" transfer mode.</p>
- <p>The <seealso marker="#start/1">start/1</seealso> function starts
- a daemon process listening for UDP packets on a port. When it
- receives a request for read or write, it spawns a temporary server
- process handling the transfer.</p>
- <p>On the client side,
- function <seealso marker="#read_file/3">read_file/3</seealso>
- and <seealso marker="#write_file/3">write_file/3</seealso>
- spawn a temporary client process establishing
- contact with a TFTP daemon and perform the file transfer.</p>
- <p><c>tftp</c> uses a callback module to handle the file
- transfer. Two such callback modules are provided,
- <c>tftp_binary</c> and <c>tftp_file</c>. See
- <seealso marker="#read_file/3">read_file/3</seealso> and
- <seealso marker="#write_file/3">write_file/3</seealso> for details.
- You can also implement your own callback modules, see
- <seealso marker="#tftp_callback">CALLBACK FUNCTIONS</seealso>.
- A callback module provided by
- the user is registered using option <c>callback</c>, see
- <seealso marker="#options">DATA TYPES</seealso>.</p>
- </description>
-
- <section>
- <title>TFTP SERVER SERVICE START/STOP</title>
-
- <p>A TFTP server can be configured to start statically when starting
- the <c>Inets</c> application. Alternatively, it can be started dynamically
- (when <c>Inets</c> is already started) by calling the <c>Inets</c> application
- API <c>inets:start(tftpd, ServiceConfig)</c> or
- <c>inets:start(tftpd, ServiceConfig, How)</c>,
- see <seealso marker="inets">inets(3)</seealso> for details.
- The <c>ServiceConfig</c> for TFTP is described in
- the <seealso marker="#options">DATA TYPES</seealso>
- section.</p>
-
- <p>The TFTP server can be stopped using <c>inets:stop(tftpd, Pid)</c>,
- see <seealso marker="inets">inets(3)</seealso> for details.</p>
-
- <p>The TPFT client is of such a temporary nature that it is not
- handled as a service in the <c>Inets</c> service framework.</p>
-
- </section>
-
- <section>
- <marker id="options"></marker>
- <title>DATA TYPES</title>
- <p><c>ServiceConfig = Options</c></p>
- <p><c>Options = [option()]</c></p>
- <p>Most of the options are common for both the client and the server
- side, but some of them differs a little.
- The available <c>option()</c>s are as follows:</p>
- <taglist>
- <tag><c>{debug, Level}</c></tag>
- <item>
- <p><c>Level = none | error | warning | brief | normal | verbose | all</c></p>
- <p>Controls the level of debug printouts.
- Default is <c>none</c>.</p>
- </item>
- <tag><c>{host, Host}</c></tag>
- <item>
- <p><c>Host = hostname()</c>, see
- <seealso marker="kernel:inet">inet(3)</seealso>.</p>
- <p>The name or IP address of the host where the TFTP daemon
- resides. This option is only used by the client.</p>
- </item>
- <tag><c>{port, Port}</c></tag>
- <item>
- <p><c>Port = int()</c></p>
- <p>The TFTP port where the daemon listens. Defaults is
- the standardized number 69. On the server side, it can
- sometimes make sense to set it to 0, meaning that
- the daemon just picks a free port (which one is
- returned by function <c>info/1</c>).</p>
- <p>If a socket is connected already, option
- <c>{udp, [{fd, integer()}]}</c> can be used to pass the
- open file descriptor to <c>gen_udp</c>. This can be automated
- by using a command-line argument stating the
- prebound file descriptor number. For example, if the
- port is 69 and file descriptor 22 is opened by
- <c>setuid_socket_wrap</c>, the command-line argument
- "-tftpd_69 22" triggers the prebound file
- descriptor 22 to be used instead of opening port 69.
- The UDP option <c>{udp, [{fd, 22}]}</c> is automatically added.
- See <c>init:get_argument/</c> about command-line arguments and
- <c>gen_udp:open/2</c> about UDP options.</p>
- </item>
- <tag><c>{port_policy, Policy}</c></tag>
- <item>
- <p><c>Policy = random | Port | {range, MinPort, MaxPort}</c></p>
- <p><c>Port = MinPort = MaxPort = int()</c></p>
- <p>Policy for the selection of the temporary port that is used
- by the server/client during the file transfer. Default is
- <c>random</c>, which is the standardized policy. With this
- policy a randomized free port is used. A single port or a range
- of ports can be useful if the protocol passes through a
- firewall.</p>
- </item>
- <tag><c>{udp, Options}</c></tag>
- <item>
- <p><c>Options = [Opt]</c>, see
- <seealso marker="kernel:gen_udp#open/1">gen_udp:open/2</seealso>.</p>
- </item>
- <tag><c>{use_tsize, Bool}</c></tag>
- <item>
- <p><c>Bool = bool()</c></p>
- <p>Flag for automated use of option <c>tsize</c>. With
- this set to <c>true</c>, the <c>write_file/3</c> client
- determines the filesize and sends it to the server as
- the standardized <c>tsize</c> option. A <c>read_file/3</c>
- client acquires only a filesize from the server by sending
- a zero <c>tsize</c>.</p>
- </item>
- <tag><c>{max_tsize, MaxTsize}</c></tag>
- <item>
- <p><c>MaxTsize = int() | infinity</c></p>
- <p>Threshold for the maximal filesize in bytes. The transfer
- is aborted if the limit is exceeded.
- Default is <c>infinity</c>.</p>
- </item>
- <tag><c>{max_conn, MaxConn}</c></tag>
- <item>
- <p><c>MaxConn = int() | infinity</c></p>
- <p>Threshold for the maximal number of active connections.
- The daemon rejects the setup of new connections if
- the limit is exceeded. Default is <c>infinity</c>.</p>
- </item>
- <tag><c>{TftpKey, TftpVal}</c></tag>
- <item>
- <p><c>TftpKey = string()</c> <br></br>
-<c>TftpVal = string()</c></p>
- <p>Name and value of a TFTP option.</p>
- </item>
- <tag><c>{reject, Feature}</c></tag>
- <item>
- <p><c>Feature = Mode | TftpKey</c> <br></br>
-<c>&nbsp;Mode = read | write</c> <br></br>
-<c>&nbsp;TftpKey = string()</c></p>
- <p>Controls which features to reject. This is
- mostly useful for the server as it can restrict the use
- of certain TFTP options or read/write access.</p>
- </item>
- <tag><c>{callback, {RegExp, Module, State}}</c></tag>
- <item>
- <p><c>RegExp = string()</c> <br></br>
-<c>Module = atom()</c> <br></br>
-<c>State = term()</c></p>
- <p>Registration of a callback module. When a file is to be
- transferred, its local filename is matched to the regular
- expressions of the registered callbacks. The first matching
- callback is used during the transfer. See
- <seealso marker="#read_file/3">read_file/3</seealso> and
- <seealso marker="#write_file/3">write_file/3</seealso>.
- </p>
- <p>The callback module must implement the <c>tftp</c> behavior, see
- <seealso marker="#tftp_callback">CALLBACK FUNCTIONS</seealso>.</p>
- </item>
-
- <tag><c>{logger, Module}</c></tag>
- <item>
- <p><c>Module = module()()</c></p>
-
- <p>Callback module for customized logging of errors, warnings, and
- info messages. The callback module must implement the
- <c>tftp_logger</c> behavior, see
- <seealso marker="#tftp_logger">LOGGER FUNCTIONS</seealso>.
- The default module is <c>tftp_logger</c>.</p>
- </item>
-
- <tag><c>{max_retries, MaxRetries}</c></tag>
- <item>
- <p><c>MaxRetries = int()</c></p>
-
- <p>Threshold for the maximal number of retries. By default
- the server/client tries to resend a message up to
- five times when the time-out expires.</p>
- </item>
- </taglist>
- </section>
-
- <funcs>
- <func>
- <name>change_config(daemons, Options) -> [{Pid, Result}]</name>
- <fsummary>Changes configuration for all daemons.
- </fsummary>
- <type>
- <v>Options = [option()]</v>
- <v>Pid = pid()</v>
- <v>Result = ok | {error, Reason}</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Changes configuration for all TFTP daemon processes. </p>
- </desc>
- </func>
-
- <func>
- <name>change_config(servers, Options) -> [{Pid, Result}]</name>
- <fsummary>Changes configuration for all servers.
- </fsummary>
- <type>
- <v>Options = [option()]</v>
- <v>Pid = pid()</v>
- <v>Result = ok | {error, Reason}</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Changes configuration for all TFTP server processes.</p>
- </desc>
- </func>
-
- <func>
- <name>change_config(Pid, Options) -> Result</name>
- <fsummary>Changes configuration for a TFTP daemon, server,
- or client process.</fsummary>
- <type>
- <v>Pid = pid()</v>
- <v>Options = [option()]</v>
- <v>Result = ok | {error, Reason}</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Changes configuration for a TFTP daemon, server, or client process.</p>
- </desc>
- </func>
-
- <func>
- <name>info(daemons) -> [{Pid, Options}]</name>
- <fsummary>Returns information about all daemons.</fsummary>
- <type>
- <v>Pid = [pid()()]</v>
- <v>Options = [option()]</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Returns information about all TFTP daemon processes.</p>
- </desc>
- </func>
-
- <func>
- <name>info(servers) -> [{Pid, Options}]</name>
- <fsummary>Returns information about all servers.</fsummary>
- <type>
- <v>Pid = [pid()()]</v>
- <v>Options = [option()]</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Returns information about all TFTP server processes. </p>
- </desc>
- </func>
-
- <func>
- <name>info(Pid) -> {ok, Options} | {error, Reason}</name>
- <fsummary>Returns information about a daemon, server, or client process.</fsummary>
- <type>
- <v>Options = [option()]</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Returns information about a TFTP daemon, server, or client process.</p>
- </desc>
- </func>
-
- <func>
- <name>read_file(RemoteFilename, LocalFilename, Options) -> {ok, LastCallbackState} | {error, Reason}</name>
- <fsummary>Reads a (virtual) file from a TFTP server.</fsummary>
- <type>
- <v>RemoteFilename = string()</v>
- <v>LocalFilename = binary | string()</v>
- <v>Options = [option()]</v>
- <v>LastCallbackState = term()</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Reads a (virtual) file <c>RemoteFilename</c> from a TFTP
- server.</p>
- <p>If <c>LocalFilename</c> is the atom <c>binary</c>,
- <c>tftp_binary</c> is used as callback module. It concatenates
- all transferred blocks and returns them as one single binary
- in <c>LastCallbackState</c>.</p>
- <p>If <c>LocalFilename</c> is a string and there are no
- registered callback modules, <c>tftp_file</c> is used as
- callback module. It writes each transferred block to the file
- named <c>LocalFilename</c> and returns the number of
- transferred bytes in <c>LastCallbackState</c>.</p>
- <p>If <c>LocalFilename</c> is a string and there are registered
- callback modules, <c>LocalFilename</c> is tested against
- the regexps of these and the callback module corresponding to
- the first match is used, or an error tuple is returned if no
- matching regexp is found.</p>
- </desc>
- </func>
-
- <func>
- <name>start(Options) -> {ok, Pid} | {error, Reason}</name>
- <fsummary>Starts a daemon process.</fsummary>
- <type>
- <v>Options = [option()]</v>
- <v>Pid = pid()</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Starts a daemon process listening for UDP packets on a
- port. When it receives a request for read or write, it spawns
- a temporary server process handling the actual transfer
- of the (virtual) file.</p>
- </desc>
- </func>
-
- <func>
- <name>write_file(RemoteFilename, LocalFilename, Options) -> {ok, LastCallbackState} | {error, Reason}</name>
- <fsummary>Writes a (virtual) file to a TFTP server.</fsummary>
- <type>
- <v>RemoteFilename = string()</v>
- <v>LocalFilename = binary() | string()</v>
- <v>Options = [option()]</v>
- <v>LastCallbackState = term()</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Writes a (virtual) file <c>RemoteFilename</c> to a TFTP
- server.</p>
- <p>If <c>LocalFilename</c> is a binary, <c>tftp_binary</c> is
- used as callback module. The binary is transferred block by
- block and the number of transferred bytes is returned in
- <c>LastCallbackState</c>.</p>
- <p>If <c>LocalFilename</c> is a string and there are no
- registered callback modules, <c>tftp_file</c> is used as
- callback module. It reads the file named <c>LocalFilename</c>
- block by block and returns the number of transferred bytes
- in <c>LastCallbackState</c>.</p>
- <p>If <c>LocalFilename</c> is a string and there are registered
- callback modules, <c>LocalFilename</c> is tested against
- the regexps of these and the callback module corresponding to
- the first match is used, or an error tuple is returned if no
- matching regexp is found.</p>
- </desc>
- </func>
- </funcs>
-
- <section>
- <marker id="tftp_callback"></marker>
- <title>CALLBACK FUNCTIONS</title>
- <p>A <c>tftp</c> callback module is to be implemented as a
- <c>tftp</c> behavior and export the functions listed
- in the following.</p>
- <p>On the server side, the callback interaction starts with a call to
- <c>open/5</c> with the registered initial callback state.
- <c>open/5</c> is expected to open the (virtual) file. Then either
- function <c>read/1</c> or <c>write/2</c> is invoked
- repeatedly, once per transferred block. At each function call,
- the state returned from the previous call is obtained. When
- the last block is encountered, function <c>read/1</c> or
- <c>write/2</c> is expected to close the (virtual) file
- and return its last state. Function <c>abort/3</c> is only
- used in error situations. Function <c>prepare/5</c> is not used on
- the server side.</p>
- <p>On the client side, the callback interaction is the same, but it
- starts and ends a bit differently. It starts with a call to
- <c>prepare/5</c> with the same arguments as <c>open/5</c> takes.
- <c>prepare/5</c> is expected to validate the TFTP options
- suggested by the user and to return the subset of them that it
- accepts. Then the options are sent to the server, which performs
- the same TFTP option negotiation procedure. The options that are
- accepted by the server are forwarded to function <c>open/5</c>
- on the client side. On the client side, function <c>open/5</c>
- must accept all option as-is or reject the transfer. Then
- the callback interaction follows the same pattern as described
- for the server side. When the last block is encountered in
- <c>read/1</c> or <c>write/2</c>, the returned state is forwarded to
- the user and returned from <c>read_file</c>/3 or
- <c>write_file/3</c>.</p>
-
- <p> If a callback (performing the file access
- in the TFTP server) takes too long time (more than
- the double TFTP time-out), the server aborts the
- connection and sends an error reply to the client.
- This implies that the server releases resources
- attached to the connection faster than before. The
- server simply assumes that the client has given
- up.</p>
-
- <p>If the TFTP server receives yet another request from
- the same client (same host and port) while it
- already has an active connection to the client, it
- ignores the new request if the request is
- equal to the first one (same filename and options).
- This implies that the (new) client will be served
- by the already ongoing connection on the server
- side. By not setting up yet another connection, in
- parallel with the ongoing one, the server
- consumes less resources.</p>
-
- <marker id="prepare"></marker>
- </section>
-
- <funcs>
- <func>
- <name>Module:abort(Code, Text, State) -> ok</name>
- <fsummary>Aborts the file transfer.</fsummary>
- <type>
- <v>Code = undef | enoent | eacces | enospc</v>
- <v>&nbsp;&nbsp;| badop | eexist | baduser | badopt</v>
- <v>&nbsp;&nbsp;| int()</v>
- <v>Text = string()</v>
- <v>State = term()</v>
- </type>
- <desc>
- <p>Invoked when the file transfer is aborted.</p>
- <p>The callback function is expected to clean
- up its used resources after the aborted file
- transfer, such as closing open file
- descriptors and so on. The function is not
- invoked if any of the other callback
- functions returns an error, as it is
- expected that they already have cleaned up
- the necessary resources. However, it is
- invoked if the functions fail (crash).</p>
- </desc>
- </func>
-
- <func>
- <name>Module:open(Peer, Access, Filename, Mode, SuggestedOptions, State) -> {ok, AcceptedOptions, NewState} | {error, {Code, Text}}</name>
- <fsummary>Opens a file for read or write access.</fsummary>
- <type>
- <v>Peer = {PeerType, PeerHost, PeerPort}</v>
- <v>PeerType = inet | inet6</v>
- <v>PeerHost = ip_address()</v>
- <v>PeerPort = integer()</v>
- <v>Access = read | write</v>
- <v>Filename = string()</v>
- <v>Mode = string()</v>
- <v>SuggestedOptions = AcceptedOptions = [{Key, Value}]</v>
- <v>&nbsp;Key = Value = string()</v>
- <v>State = InitialState | term()</v>
- <v>&nbsp;InitialState = [] | [{root_dir, string()}]</v>
- <v>NewState = term()</v>
- <v>Code = undef | enoent | eacces | enospc</v>
- <v>&nbsp;&nbsp;| badop | eexist | baduser | badopt</v>
- <v>&nbsp;&nbsp;| int()</v>
- <v>Text = string()</v>
- </type>
- <desc>
- <p>Opens a file for read or write access.</p>
- <p>On the client side, where the <c>open/5</c> call has been
- preceded by a call to <c>prepare/5</c>, all options must be
- accepted or rejected.</p>
- <p>On the server side, where there is no preceding
- <c>prepare/5</c> call, no new options can be added, but
- those present in <c>SuggestedOptions</c> can be
- omitted or replaced with new values in <c>AcceptedOptions</c>.</p>
-
- <marker id="read"></marker>
- </desc>
- </func>
-
- <func>
- <name>Module:prepare(Peer, Access, Filename, Mode, SuggestedOptions, InitialState) -> {ok, AcceptedOptions, NewState} | {error, {Code, Text}}</name>
- <fsummary>Prepares to open a file on the client side.</fsummary>
- <type>
- <v>Peer = {PeerType, PeerHost, PeerPort}</v>
- <v>PeerType = inet | inet6</v>
- <v>PeerHost = ip_address()</v>
- <v>PeerPort = integer()</v>
- <v>Access = read | write</v>
- <v>Filename = string()</v>
- <v>Mode = string()</v>
- <v>SuggestedOptions = AcceptedOptions = [{Key, Value}]</v>
- <v>&nbsp;Key = Value = string()</v>
- <v>InitialState = [] | [{root_dir, string()}]</v>
- <v>NewState = term()</v>
- <v>Code = undef | enoent | eacces | enospc</v>
- <v>&nbsp;&nbsp;| badop | eexist | baduser | badopt</v>
- <v>&nbsp;&nbsp;| int()</v>
- <v>Text = string()</v>
- </type>
- <desc>
- <p>Prepares to open a file on the client side.</p>
- <p>No new options can be added, but those present in
- <c>SuggestedOptions</c> can be omitted or replaced with new
- values in <c>AcceptedOptions</c>.</p>
- <p>This is followed by a call to <c>open/4</c> before any
- read/write access is performed. <c>AcceptedOptions</c> is
- sent to the server, which replies with the options that it
- accepts. These are then forwarded to <c>open/4</c> as
- <c>SuggestedOptions</c>.</p>
-
- <marker id="open"></marker>
- </desc>
- </func>
-
- <func>
- <name>Module:read(State) -> {more, Bin, NewState} | {last, Bin, FileSize} | {error, {Code, Text}}</name>
- <fsummary>Reads a chunk from the file.</fsummary>
- <type>
- <v>State = NewState = term()</v>
- <v>Bin = binary()</v>
- <v>FileSize = int()</v>
- <v>Code = undef | enoent | eacces | enospc</v>
- <v>&nbsp;&nbsp;| badop | eexist | baduser | badopt</v>
- <v>&nbsp;&nbsp;| int()</v>
- <v>Text = string()</v>
- </type>
- <desc>
- <p>Reads a chunk from the file.</p>
- <p>The callback function is expected to close
- the file when the last file chunk is
- encountered. When an error is encountered,
- the callback function is expected to clean
- up after the aborted file transfer, such as
- closing open file descriptors, and so on. In both
- cases there will be no more calls to any of
- the callback functions.</p>
-
- <marker id="write"></marker>
- </desc>
- </func>
-
- <func>
- <name>Module:write(Bin, State) -> {more, NewState} | {last, FileSize} | {error, {Code, Text}}</name>
- <fsummary>Writes a chunk to the file.</fsummary>
- <type>
- <v>Bin = binary()</v>
- <v>State = NewState = term()</v>
- <v>FileSize = int()</v>
- <v>Code = undef | enoent | eacces | enospc</v>
- <v>&nbsp;&nbsp;| badop | eexist | baduser | badopt</v>
- <v>&nbsp;&nbsp;| int()</v>
- <v>Text = string()</v>
- </type>
- <desc>
- <p>Writes a chunk to the file.</p>
- <p>The callback function is expected to close
- the file when the last file chunk is
- encountered. When an error is encountered,
- the callback function is expected to clean
- up after the aborted file transfer, such as
- closing open file descriptors, and so on. In both
- cases there will be no more calls to any of
- the callback functions.</p>
-
- <marker id="abort"></marker>
- </desc>
- </func>
- </funcs>
-
- <section>
- <marker id="tftp_logger"></marker>
- <title>LOGGER FUNCTIONS</title>
-
- <p>A <c>tftp_logger</c> callback module is to be implemented as a
- <c>tftp_logger</c> behavior and export the following functions:</p>
-
- <marker id="error_msg"></marker>
- </section>
-
- <funcs>
- <func>
- <name>Logger:error_msg(Format, Data) -> ok | exit(Reason)</name>
- <fsummary>Logs an error message.</fsummary>
- <type>
- <v>Format = string()</v>
- <v>Data = [term()]</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Logs an error message.
- See <c>error_logger:error_msg/2</c> for details.</p>
-
- <marker id="warning_msg"></marker>
- </desc>
- </func>
-
- <func>
- <name>Logger:info_msg(Format, Data) -> ok | exit(Reason)</name>
- <fsummary>Logs an info message.</fsummary>
- <type>
- <v>Format = string()</v>
- <v>Data = [term()]</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Logs an info message.
- See <c>error_logger:info_msg/2</c> for details.</p>
- </desc>
- </func>
-
- <func>
- <name>Logger:warning_msg(Format, Data) -> ok | exit(Reason)</name>
- <fsummary>Logs a warning message.</fsummary>
- <type>
- <v>Format = string()</v>
- <v>Data = [term()]</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Logs a warning message.
- See <c>error_logger:warning_msg/2</c> for details.</p>
-
- <marker id="info_msg"></marker>
- </desc>
- </func>
- </funcs>
-</erlref>
-
-
diff --git a/lib/inets/examples/httpd_load_test/hdlt_slave.erl b/lib/inets/examples/httpd_load_test/hdlt_slave.erl
index 5ee005629d..30ddfd76af 100644
--- a/lib/inets/examples/httpd_load_test/hdlt_slave.erl
+++ b/lib/inets/examples/httpd_load_test/hdlt_slave.erl
@@ -44,18 +44,17 @@
%% this to work is that the 'erl' program can be found in PATH.
%%
%% If the master and slave are on different hosts, start/N uses
-%% the 'rsh' program to spawn an Erlang node on the other host.
+%% the 'ssh' program to spawn an Erlang node on the other host.
%% Alternative, if the master was started as
%% 'erl -sname xxx -rsh my_rsh...', then 'my_rsh' will be used instead
-%% of 'rsh' (this is useful for systems where the rsh program is named
-%% 'remsh').
+%% of 'ssh' (this is useful for systems still using rsh or remsh).
%%
%% For this to work, the following conditions must be fulfilled:
%%
-%% 1. There must be an Rsh program on computer; if not an error
+%% 1. There must be an ssh program on computer; if not an error
%% is returned.
%%
-%% 2. The hosts must be configured to allowed 'rsh' access without
+%% 2. The hosts must be configured to allow 'ssh' access without
%% prompts for password.
%%
%% The slave node will have its filer and user server redirected
@@ -244,7 +243,7 @@ register_unique_name(Number) ->
%% Makes up the command to start the nodes.
%% If the node should run on the local host, there is
-%% no need to use rsh.
+%% no need to use ssh.
mk_cmd(Host, Name, Paths, Args, Waiter, Prog) ->
PaPaths = [[" -pa ", Path] || Path <- Paths],
diff --git a/lib/inets/src/ftp/Makefile b/lib/inets/src/ftp/Makefile
deleted file mode 100644
index 6b99694ea7..0000000000
--- a/lib/inets/src/ftp/Makefile
+++ /dev/null
@@ -1,104 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2005-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-
-include $(ERL_TOP)/make/target.mk
-EBIN = ../../ebin
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../../vsn.mk
-
-VSN = $(INETS_VSN)
-
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
-
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-MODULES = \
- ftp \
- ftp_progress \
- ftp_response \
- ftp_sup
-
-HRL_FILES = ftp_internal.hrl
-
-ERL_FILES = $(MODULES:%=%.erl)
-
-TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-
-include ../inets_app/inets.mk
-
-ifeq ($(FTP_DEBUG),true)
- INETS_FLAGS += -Dftp_debug
-endif
-
-ERL_COMPILE_FLAGS += \
- $(INETS_FLAGS) \
- $(INETS_ERL_COMPILE_FLAGS) \
- -I../../include \
- -I../inets_app
-
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug opt: $(TARGET_FILES)
-
-clean:
- rm -f $(TARGET_FILES)
- rm -f core
-
-docs:
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/src"
- $(INSTALL_DIR) "$(RELSYSDIR)/src/ftp"
- $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) "$(RELSYSDIR)/src/ftp"
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
-
-release_docs_spec:
-
-info:
- @echo "APPLICATION = $(APPLICATION)"
- @echo "INETS_DEBUG = $(INETS_DEBUG)"
- @echo "INETS_FLAGS = $(INETS_FLAGS)"
- @echo "ERL_COMPILE_FLAGS = $(ERL_COMPILE_FLAGS)"
diff --git a/lib/inets/src/ftp/ftp.erl b/lib/inets/src/ftp/ftp.erl
deleted file mode 100644
index e0430654eb..0000000000
--- a/lib/inets/src/ftp/ftp.erl
+++ /dev/null
@@ -1,2596 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%% Description: This module implements an ftp client, RFC 959.
-%% It also supports ipv6 RFC 2428 and starttls RFC 4217.
-
--module(ftp).
-
--behaviour(gen_server).
--behaviour(inets_service).
-
-
-%% API - Client interface
--export([cd/2, close/1, delete/2, formaterror/1,
- lcd/2, lpwd/1, ls/1, ls/2,
- mkdir/2, nlist/1, nlist/2,
- open/1, open/2,
- pwd/1, quote/2,
- recv/2, recv/3, recv_bin/2,
- recv_chunk_start/2, recv_chunk/1,
- rename/3, rmdir/2,
- send/2, send/3, send_bin/3,
- send_chunk_start/2, send_chunk/2, send_chunk_end/1,
- type/2, user/3, user/4, account/2,
- append/3, append/2, append_bin/3,
- append_chunk/2, append_chunk_end/1, append_chunk_start/2,
- info/1, latest_ctrl_response/1]).
-
-%% gen_server callbacks
--export([init/1, handle_call/3, handle_cast/2,
- handle_info/2, terminate/2, code_change/3]).
-
-%% supervisor callbacks
--export([start_link/1, start_link/2]).
-
-%% Behavior callbacks
--export([start_standalone/1, start_service/1,
- stop_service/1, services/0, service_info/1]).
-
--include("ftp_internal.hrl").
-
-%% Constants used in internal state definition
--define(CONNECTION_TIMEOUT, 60*1000).
--define(DATA_ACCEPT_TIMEOUT, infinity).
--define(DEFAULT_MODE, passive).
--define(PROGRESS_DEFAULT, ignore).
--define(FTP_EXT_DEFAULT, false).
-
-%% Internal Constants
--define(FTP_PORT, 21).
--define(FILE_BUFSIZE, 4096).
-
-%% Internal state
--record(state, {
- csock = undefined, % socket() - Control connection socket
- dsock = undefined, % socket() - Data connection socket
- tls_options = undefined, % list()
- verbose = false, % boolean()
- ldir = undefined, % string() - Current local directory
- type = ftp_server_default, % atom() - binary | ascii
- chunk = false, % boolean() - Receiving data chunks
- mode = ?DEFAULT_MODE, % passive | active
- timeout = ?CONNECTION_TIMEOUT, % integer()
- %% Data received so far on the data connection
- data = <<>>, % binary()
- %% Data received so far on the control connection
- %% {BinStream, AccLines}. If a binary sequence
- %% ends with ?CR then keep it in the binary to
- %% be able to detect if the next received byte is ?LF
- %% and hence the end of the response is reached!
- ctrl_data = {<<>>, [], start}, % {binary(), [bytes()], LineStatus}
- %% pid() - Client pid (note not the same as "From")
- latest_ctrl_response = "",
- owner = undefined,
- client = undefined, % "From" to be used in gen_server:reply/2
- %% Function that activated a connection and maybe some
- %% data needed further on.
- caller = undefined, % term()
- ipfamily, % inet | inet6 | inet6fb4
- progress = ignore, % ignore | pid()
- dtimeout = ?DATA_ACCEPT_TIMEOUT, % non_neg_integer() | infinity
- tls_upgrading_data_connection = false,
- ftp_extension = ?FTP_EXT_DEFAULT
- }).
-
--record(recv_chunk_closing, {
- dconn_closed = false,
- pos_compl_received = false,
- client_called_us = false
- }).
-
-
--type shortage_reason() :: 'etnospc' | 'epnospc'.
--type restriction_reason() :: 'epath' | 'efnamena' | 'elogin' | 'enotbinary'.
--type common_reason() :: 'econn' | 'eclosed' | term().
--type file_write_error_reason() :: term(). % See file:write for more info
-
--define(DBG(F,A), 'n/a').
-%%-define(DBG(F,A), io:format(F,A)).
-%%-define(DBG(F,A), ct:pal("~p:~p " ++ if is_list(F) -> F; is_atom(F) -> atom_to_list(F) end, [?MODULE,?LINE|A])).
-
-%%%=========================================================================
-%%% API - CLIENT FUNCTIONS
-%%%=========================================================================
-
-%%--------------------------------------------------------------------------
-%% open(HostOrOtpList, <Port>, <Flags>) -> {ok, Pid} | {error, ehost}
-%% HostOrOtpList = string() | [{option_list, Options}]
-%% Port = integer(),
-%% Flags = [Flag],
-%% Flag = verbose | debug | trace
-%%
-%% Description: Start an ftp client and connect to a host.
-%%--------------------------------------------------------------------------
-
--spec open(Host :: string() | inet:ip_address()) ->
- {'ok', Pid :: pid()} | {'error', Reason :: 'ehost' | term()}.
-
-%% <BACKWARD-COMPATIBILLITY>
-open({option_list, Options}) when is_list(Options) ->
- try
- {ok, StartOptions} = start_options(Options),
- {ok, OpenOptions} = open_options(Options),
- case ftp_sup:start_child([[[{client, self()} | StartOptions], []]]) of
- {ok, Pid} ->
- call(Pid, {open, ip_comm, OpenOptions}, plain);
- Error1 ->
- Error1
- end
- catch
- throw:Error2 ->
- Error2
- end;
-%% </BACKWARD-COMPATIBILLITY>
-
-open(Host) ->
- open(Host, []).
-
--spec open(Host :: string() | inet:ip_address(), Opts :: list()) ->
- {'ok', Pid :: pid()} | {'error', Reason :: 'ehost' | term()}.
-
-%% <BACKWARD-COMPATIBILLITY>
-open(Host, Port) when is_integer(Port) ->
- open(Host, [{port, Port}]);
-%% </BACKWARD-COMPATIBILLITY>
-
-open(Host, Opts) when is_list(Opts) ->
- ?fcrt("open", [{host, Host}, {opts, Opts}]),
- try
- {ok, StartOptions} = start_options(Opts),
- ?fcrt("open", [{start_options, StartOptions}]),
- {ok, OpenOptions} = open_options([{host, Host}|Opts]),
- ?fcrt("open", [{open_options, OpenOptions}]),
- case start_link(StartOptions, []) of
- {ok, Pid} ->
- do_open(Pid, OpenOptions, tls_options(Opts));
- Error1 ->
- ?fcrt("open - error", [{error1, Error1}]),
- Error1
- end
- catch
- throw:Error2 ->
- ?fcrt("open - error", [{error2, Error2}]),
- Error2
- end.
-
-do_open(Pid, OpenOptions, TLSOpts) ->
- case call(Pid, {open, ip_comm, OpenOptions}, plain) of
- {ok, Pid} ->
- maybe_tls_upgrade(Pid, TLSOpts);
- Error ->
- Error
- end.
-%%--------------------------------------------------------------------------
-%% user(Pid, User, Pass, <Acc>) -> ok | {error, euser} | {error, econn}
-%% | {error, eacct}
-%% Pid = pid(),
-%% User = Pass = Acc = string()
-%%
-%% Description: Login with or without a supplied account name.
-%%--------------------------------------------------------------------------
--spec user(Pid :: pid(),
- User :: string(),
- Pass :: string()) ->
- 'ok' | {'error', Reason :: 'euser' | common_reason()}.
-
-user(Pid, User, Pass) ->
- case {is_name_sane(User), is_name_sane(Pass)} of
- {true, true} ->
- call(Pid, {user, User, Pass}, atom);
- _ ->
- {error, euser}
- end.
-
--spec user(Pid :: pid(),
- User :: string(),
- Pass :: string(),
- Acc :: string()) ->
- 'ok' | {'error', Reason :: 'euser' | common_reason()}.
-
-user(Pid, User, Pass, Acc) ->
- case {is_name_sane(User), is_name_sane(Pass), is_name_sane(Acc)} of
- {true, true, true} ->
- call(Pid, {user, User, Pass, Acc}, atom);
- _ ->
- {error, euser}
- end.
-
-
-%%--------------------------------------------------------------------------
-%% account(Pid, Acc) -> ok | {error, eacct}
-%% Pid = pid()
-%% Acc= string()
-%%
-%% Description: Set a user Account.
-%%--------------------------------------------------------------------------
-
--spec account(Pid :: pid(), Acc :: string()) ->
- 'ok' | {'error', Reason :: 'eacct' | common_reason()}.
-
-account(Pid, Acc) ->
- case is_name_sane(Acc) of
- true ->
- call(Pid, {account, Acc}, atom);
- _ ->
- {error, eacct}
- end.
-
-
-%%--------------------------------------------------------------------------
-%% pwd(Pid) -> {ok, Dir} | {error, elogin} | {error, econn}
-%% Pid = pid()
-%% Dir = string()
-%%
-%% Description: Get the current working directory at remote server.
-%%--------------------------------------------------------------------------
-
--spec pwd(Pid :: pid()) ->
- {'ok', Dir :: string()} |
- {'error', Reason :: restriction_reason() | common_reason()}.
-
-pwd(Pid) ->
- call(Pid, pwd, ctrl).
-
-
-%%--------------------------------------------------------------------------
-%% lpwd(Pid) -> {ok, Dir}
-%% Pid = pid()
-%% Dir = string()
-%%
-%% Description: Get the current working directory at local server.
-%%--------------------------------------------------------------------------
-
--spec lpwd(Pid :: pid()) ->
- {'ok', Dir :: string()}.
-
-lpwd(Pid) ->
- call(Pid, lpwd, string).
-
-
-%%--------------------------------------------------------------------------
-%% cd(Pid, Dir) -> ok | {error, epath} | {error, elogin} | {error, econn}
-%% Pid = pid()
-%% Dir = string()
-%%
-%% Description: Change current working directory at remote server.
-%%--------------------------------------------------------------------------
-
--spec cd(Pid :: pid(), Dir :: string()) ->
- 'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
-
-cd(Pid, Dir) ->
- case is_name_sane(Dir) of
- true ->
- call(Pid, {cd, Dir}, atom);
- _ ->
- {error, efnamena}
- end.
-
-
-%%--------------------------------------------------------------------------
-%% lcd(Pid, Dir) -> ok | {error, epath}
-%% Pid = pid()
-%% Dir = string()
-%%
-%% Description: Change current working directory for the local client.
-%%--------------------------------------------------------------------------
-
--spec lcd(Pid :: pid(), Dir :: string()) ->
- 'ok' | {'error', Reason :: restriction_reason()}.
-
-lcd(Pid, Dir) ->
- call(Pid, {lcd, Dir}, string).
-
-
-%%--------------------------------------------------------------------------
-%% ls(Pid) -> Result
-%% ls(Pid, <Dir>) -> Result
-%%
-%% Pid = pid()
-%% Dir = string()
-%% Result = {ok, Listing} | {error, Reason}
-%% Listing = string()
-%% Reason = epath | elogin | econn
-%%
-%% Description: Returns a list of files in long format.
-%%--------------------------------------------------------------------------
-
--spec ls(Pid :: pid()) ->
- {'ok', Listing :: string()} |
- {'error', Reason :: restriction_reason() | common_reason()}.
-
-ls(Pid) ->
- ls(Pid, "").
-
--spec ls(Pid :: pid(), Dir :: string()) ->
- {'ok', Listing :: string()} |
- {'error', Reason :: restriction_reason() | common_reason()}.
-
-ls(Pid, Dir) ->
- case is_name_sane(Dir) of
- true ->
- call(Pid, {dir, long, Dir}, string);
- _ ->
- {error, efnamena}
- end.
-
-
-%%--------------------------------------------------------------------------
-%% nlist(Pid) -> Result
-%% nlist(Pid, Pathname) -> Result
-%%
-%% Pid = pid()
-%% Pathname = string()
-%% Result = {ok, Listing} | {error, Reason}
-%% Listing = string()
-%% Reason = epath | elogin | econn
-%%
-%% Description: Returns a list of files in short format
-%%--------------------------------------------------------------------------
-
--spec nlist(Pid :: pid()) ->
- {'ok', Listing :: string()} |
- {'error', Reason :: restriction_reason() | common_reason()}.
-
-nlist(Pid) ->
- nlist(Pid, "").
-
--spec nlist(Pid :: pid(), Pathname :: string()) ->
- {'ok', Listing :: string()} |
- {'error', Reason :: restriction_reason() | common_reason()}.
-
-nlist(Pid, Dir) ->
- case is_name_sane(Dir) of
- true ->
- call(Pid, {dir, short, Dir}, string);
- _ ->
- {error, efnamena}
- end.
-
-
-%%--------------------------------------------------------------------------
-%% rename(Pid, Old, New) -> ok | {error, epath} | {error, elogin}
-%% | {error, econn}
-%% Pid = pid()
-%% CurrFile = NewFile = string()
-%%
-%% Description: Rename a file at remote server.
-%%--------------------------------------------------------------------------
-
--spec rename(Pid :: pid(), Old :: string(), New :: string()) ->
- 'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
-
-rename(Pid, Old, New) ->
- case {is_name_sane(Old), is_name_sane(New)} of
- {true, true} ->
- call(Pid, {rename, Old, New}, string);
- _ ->
- {error, efnamena}
- end.
-
-
-%%--------------------------------------------------------------------------
-%% delete(Pid, File) -> ok | {error, epath} | {error, elogin} |
-%% {error, econn}
-%% Pid = pid()
-%% File = string()
-%%
-%% Description: Remove file at remote server.
-%%--------------------------------------------------------------------------
-
--spec delete(Pid :: pid(), File :: string()) ->
- 'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
-
-delete(Pid, File) ->
- case is_name_sane(File) of
- true ->
- call(Pid, {delete, File}, string);
- _ ->
- {error, efnamena}
- end.
-
-
-%%--------------------------------------------------------------------------
-%% mkdir(Pid, Dir) -> ok | {error, epath} | {error, elogin} | {error, econn}
-%% Pid = pid(),
-%% Dir = string()
-%%
-%% Description: Make directory at remote server.
-%%--------------------------------------------------------------------------
-
--spec mkdir(Pid :: pid(), Dir :: string()) ->
- 'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
-
-mkdir(Pid, Dir) ->
- case is_name_sane(Dir) of
- true ->
- call(Pid, {mkdir, Dir}, atom);
- _ ->
- {error, efnamena}
- end.
-
-
-%%--------------------------------------------------------------------------
-%% rmdir(Pid, Dir) -> ok | {error, epath} | {error, elogin} | {error, econn}
-%% Pid = pid(),
-%% Dir = string()
-%%
-%% Description: Remove directory at remote server.
-%%--------------------------------------------------------------------------
-
--spec rmdir(Pid :: pid(), Dir :: string()) ->
- 'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
-
-rmdir(Pid, Dir) ->
- case is_name_sane(Dir) of
- true ->
- call(Pid, {rmdir, Dir}, atom);
- _ ->
- {error, efnamena}
- end.
-
-
-%%--------------------------------------------------------------------------
-%% type(Pid, Type) -> ok | {error, etype} | {error, elogin} | {error, econn}
-%% Pid = pid()
-%% Type = ascii | binary
-%%
-%% Description: Set transfer type.
-%%--------------------------------------------------------------------------
-
--spec type(Pid :: pid(), Type :: ascii | binary) ->
- 'ok' |
- {'error', Reason :: 'etype' | restriction_reason() | common_reason()}.
-
-type(Pid, Type) ->
- call(Pid, {type, Type}, atom).
-
-
-%%--------------------------------------------------------------------------
-%% recv(Pid, RemoteFileName [, LocalFileName]) -> ok | {error, epath} |
-%% {error, elogin} | {error, econn}
-%% Pid = pid()
-%% RemoteFileName = LocalFileName = string()
-%%
-%% Description: Transfer file from remote server.
-%%--------------------------------------------------------------------------
-
--spec recv(Pid :: pid(), RemoteFileName :: string()) ->
- 'ok' | {'error', Reason :: restriction_reason() |
- common_reason() |
- file_write_error_reason()}.
-
-recv(Pid, RemotFileName) ->
- recv(Pid, RemotFileName, RemotFileName).
-
--spec recv(Pid :: pid(),
- RemoteFileName :: string(),
- LocalFileName :: string()) ->
- 'ok' | {'error', Reason :: term()}.
-
-recv(Pid, RemotFileName, LocalFileName) ->
- case is_name_sane(RemotFileName) of
- true ->
- call(Pid, {recv, RemotFileName, LocalFileName}, atom);
- _ ->
- {error, efnamena}
- end.
-
-
-%%--------------------------------------------------------------------------
-%% recv_bin(Pid, RemoteFile) -> {ok, Bin} | {error, epath} | {error, elogin}
-%% | {error, econn}
-%% Pid = pid()
-%% RemoteFile = string()
-%% Bin = binary()
-%%
-%% Description: Transfer file from remote server into binary.
-%%--------------------------------------------------------------------------
-
--spec recv_bin(Pid :: pid(),
- RemoteFile :: string()) ->
- {'ok', Bin :: binary()} |
- {'error', Reason :: restriction_reason() | common_reason()}.
-
-recv_bin(Pid, RemoteFile) ->
- case is_name_sane(RemoteFile) of
- true ->
- call(Pid, {recv_bin, RemoteFile}, bin);
- _ ->
- {error, efnamena}
- end.
-
-
-%%--------------------------------------------------------------------------
-%% recv_chunk_start(Pid, RemoteFile) -> ok | {error, elogin} | {error, epath}
-%% | {error, econn}
-%% Pid = pid()
-%% RemoteFile = string()
-%%
-%% Description: Start receive of chunks of remote file.
-%%--------------------------------------------------------------------------
-
--spec recv_chunk_start(Pid :: pid(),
- RemoteFile :: string()) ->
- 'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
-
-recv_chunk_start(Pid, RemoteFile) ->
- case is_name_sane(RemoteFile) of
- true ->
- call(Pid, {recv_chunk_start, RemoteFile}, atom);
- _ ->
- {error, efnamena}
- end.
-
-
-%%--------------------------------------------------------------------------
-%% recv_chunk(Pid, RemoteFile) -> ok | {ok, Bin} | {error, Reason}
-%% Pid = pid()
-%% RemoteFile = string()
-%%
-%% Description: Transfer file from remote server into binary in chunks
-%%--------------------------------------------------------------------------
-
--spec recv_chunk(Pid :: pid()) ->
- 'ok' |
- {'ok', Bin :: binary()} |
- {'error', Reason :: restriction_reason() | common_reason()}.
-
-recv_chunk(Pid) ->
- call(Pid, recv_chunk, atom).
-
-
-%%--------------------------------------------------------------------------
-%% send(Pid, LocalFileName [, RemotFileName]) -> ok | {error, epath}
-%% | {error, elogin}
-%% | {error, econn}
-%% Pid = pid()
-%% LocalFileName = RemotFileName = string()
-%%
-%% Description: Transfer file to remote server.
-%%--------------------------------------------------------------------------
-
--spec send(Pid :: pid(), LocalFileName :: string()) ->
- 'ok' |
- {'error', Reason :: restriction_reason() |
- common_reason() |
- shortage_reason()}.
-
-send(Pid, LocalFileName) ->
- send(Pid, LocalFileName, LocalFileName).
-
--spec send(Pid :: pid(),
- LocalFileName :: string(),
- RemoteFileName :: string()) ->
- 'ok' |
- {'error', Reason :: restriction_reason() |
- common_reason() |
- shortage_reason()}.
-
-send(Pid, LocalFileName, RemotFileName) ->
- case is_name_sane(RemotFileName) of
- true ->
- call(Pid, {send, LocalFileName, RemotFileName}, atom);
- _ ->
- {error, efnamena}
- end.
-
-
-%%--------------------------------------------------------------------------
-%% send_bin(Pid, Bin, RemoteFile) -> ok | {error, epath} | {error, elogin}
-%% | {error, enotbinary} | {error, econn}
-%% Pid = pid()
-%% Bin = binary()
-%% RemoteFile = string()
-%%
-%% Description: Transfer a binary to a remote file.
-%%--------------------------------------------------------------------------
-
--spec send_bin(Pid :: pid(), Bin :: binary(), RemoteFile :: string()) ->
- 'ok' |
- {'error', Reason :: restriction_reason() |
- common_reason() |
- shortage_reason()}.
-
-send_bin(Pid, Bin, RemoteFile) when is_binary(Bin) ->
- case is_name_sane(RemoteFile) of
- true ->
- call(Pid, {send_bin, Bin, RemoteFile}, atom);
- _ ->
- {error, efnamena}
- end;
-send_bin(_Pid, _Bin, _RemoteFile) ->
- {error, enotbinary}.
-
-
-%%--------------------------------------------------------------------------
-%% send_chunk_start(Pid, RemoteFile) -> ok | {error, elogin} | {error, epath}
-%% | {error, econn}
-%% Pid = pid()
-%% RemoteFile = string()
-%%
-%% Description: Start transfer of chunks to remote file.
-%%--------------------------------------------------------------------------
-
--spec send_chunk_start(Pid :: pid(), RemoteFile :: string()) ->
- 'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
-
-send_chunk_start(Pid, RemoteFile) ->
- case is_name_sane(RemoteFile) of
- true ->
- call(Pid, {send_chunk_start, RemoteFile}, atom);
- _ ->
- {error, efnamena}
- end.
-
-
-%%--------------------------------------------------------------------------
-%% append_chunk_start(Pid, RemoteFile) -> ok | {error, elogin} |
-%% {error, epath} | {error, econn}
-%% Pid = pid()
-%% RemoteFile = string()
-%%
-%% Description: Start append chunks of data to remote file.
-%%--------------------------------------------------------------------------
-
--spec append_chunk_start(Pid :: pid(), RemoteFile :: string()) ->
- 'ok' | {'error', Reason :: term()}.
-
-append_chunk_start(Pid, RemoteFile) ->
- case is_name_sane(RemoteFile) of
- true ->
- call(Pid, {append_chunk_start, RemoteFile}, atom);
- _ ->
- {error, efnamena}
- end.
-
-
-%%--------------------------------------------------------------------------
-%% send_chunk(Pid, Bin) -> ok | {error, elogin} | {error, enotbinary}
-%% | {error, echunk} | {error, econn}
-%% Pid = pid()
-%% Bin = binary().
-%%
-%% Purpose: Send chunk to remote file.
-%%--------------------------------------------------------------------------
-
--spec send_chunk(Pid :: pid(), Bin :: binary()) ->
- 'ok' |
- {'error', Reason :: 'echunk' |
- restriction_reason() |
- common_reason()}.
-
-send_chunk(Pid, Bin) when is_binary(Bin) ->
- call(Pid, {transfer_chunk, Bin}, atom);
-send_chunk(_Pid, _Bin) ->
- {error, enotbinary}.
-
-
-%%--------------------------------------------------------------------------
-%% append_chunk(Pid, Bin) -> ok | {error, elogin} | {error, enotbinary}
-%% | {error, echunk} | {error, econn}
-%% Pid = pid()
-%% Bin = binary()
-%%
-%% Description: Append chunk to remote file.
-%%--------------------------------------------------------------------------
-
--spec append_chunk(Pid :: pid(), Bin :: binary()) ->
- 'ok' |
- {'error', Reason :: 'echunk' |
- restriction_reason() |
- common_reason()}.
-
-append_chunk(Pid, Bin) when is_binary(Bin) ->
- call(Pid, {transfer_chunk, Bin}, atom);
-append_chunk(_Pid, _Bin) ->
- {error, enotbinary}.
-
-
-%%--------------------------------------------------------------------------
-%% send_chunk_end(Pid) -> ok | {error, elogin} | {error, echunk}
-%% | {error, econn}
-%% Pid = pid()
-%%
-%% Description: End sending of chunks to remote file.
-%%--------------------------------------------------------------------------
-
--spec send_chunk_end(Pid :: pid()) ->
- 'ok' |
- {'error', Reason :: restriction_reason() |
- common_reason() |
- shortage_reason()}.
-
-send_chunk_end(Pid) ->
- call(Pid, chunk_end, atom).
-
-
-%%--------------------------------------------------------------------------
-%% append_chunk_end(Pid) -> ok | {error, elogin} | {error, echunk}
-%% | {error, econn}
-%% Pid = pid()
-%%
-%% Description: End appending of chunks to remote file.
-%%--------------------------------------------------------------------------
-
--spec append_chunk_end(Pid :: pid()) ->
- 'ok' |
- {'error', Reason :: restriction_reason() |
- common_reason() |
- shortage_reason()}.
-
-append_chunk_end(Pid) ->
- call(Pid, chunk_end, atom).
-
-
-%%--------------------------------------------------------------------------
-%% append(Pid, LocalFileName [, RemotFileName]) -> ok | {error, epath}
-%% | {error, elogin}
-%% | {error, econn}
-%% Pid = pid()
-%% LocalFileName = RemotFileName = string()
-%%
-%% Description: Append the local file to the remote file
-%%--------------------------------------------------------------------------
-
--spec append(Pid :: pid(), LocalFileName :: string()) ->
- 'ok' |
- {'error', Reason :: 'epath' |
- 'elogin' |
- 'etnospc' |
- 'epnospc' |
- 'efnamena' | common_reason()}.
-
-append(Pid, LocalFileName) ->
- append(Pid, LocalFileName, LocalFileName).
-
--spec append(Pid :: pid(),
- LocalFileName :: string(),
- RemoteFileName :: string()) ->
- 'ok' | {'error', Reason :: term()}.
-
-append(Pid, LocalFileName, RemotFileName) ->
- case is_name_sane(RemotFileName) of
- true ->
- call(Pid, {append, LocalFileName, RemotFileName}, atom);
- _ ->
- {error, efnamena}
- end.
-
-
-%%--------------------------------------------------------------------------
-%% append_bin(Pid, Bin, RemoteFile) -> ok | {error, epath} | {error, elogin}
-%% | {error, enotbinary} | {error, econn}
-%% Pid = pid()
-%% Bin = binary()
-%% RemoteFile = string()
-%%
-%% Purpose: Append a binary to a remote file.
-%%--------------------------------------------------------------------------
-
--spec append_bin(Pid :: pid(),
- Bin :: binary(),
- RemoteFile :: string()) ->
- 'ok' |
- {'error', Reason :: restriction_reason() |
- common_reason() |
- shortage_reason()}.
-
-append_bin(Pid, Bin, RemoteFile) when is_binary(Bin) ->
- case is_name_sane(RemoteFile) of
- true ->
- call(Pid, {append_bin, Bin, RemoteFile}, atom);
- _ ->
- {error, efnamena}
- end;
-append_bin(_Pid, _Bin, _RemoteFile) ->
- {error, enotbinary}.
-
-
-%%--------------------------------------------------------------------------
-%% quote(Pid, Cmd) -> list()
-%% Pid = pid()
-%% Cmd = string()
-%%
-%% Description: Send arbitrary ftp command.
-%%--------------------------------------------------------------------------
-
--spec quote(Pid :: pid(), Cmd :: string()) -> list().
-
-quote(Pid, Cmd) when is_list(Cmd) ->
- call(Pid, {quote, Cmd}, atom).
-
-
-%%--------------------------------------------------------------------------
-%% close(Pid) -> ok
-%% Pid = pid()
-%%
-%% Description: End the ftp session.
-%%--------------------------------------------------------------------------
-
--spec close(Pid :: pid()) -> 'ok'.
-
-close(Pid) ->
- cast(Pid, close),
- ok.
-
-
-%%--------------------------------------------------------------------------
-%% formaterror(Tag) -> string()
-%% Tag = atom() | {error, atom()}
-%%
-%% Description: Return diagnostics.
-%%--------------------------------------------------------------------------
-
--spec formaterror(Tag :: term()) -> string().
-
-formaterror(Tag) ->
- ftp_response:error_string(Tag).
-
-
-info(Pid) ->
- call(Pid, info, list).
-
-
-%%--------------------------------------------------------------------------
-%% latest_ctrl_response(Pid) -> string()
-%% Pid = pid()
-%%
-%% Description: The latest received response from the server
-%%--------------------------------------------------------------------------
-
--spec latest_ctrl_response(Pid :: pid()) -> string().
-
-latest_ctrl_response(Pid) ->
- call(Pid, latest_ctrl_response, string).
-
-%%%========================================================================
-%%% Behavior callbacks
-%%%========================================================================
-start_standalone(Options) ->
- try
- {ok, StartOptions} = start_options(Options),
- {ok, OpenOptions} = open_options(Options),
- case start_link(StartOptions, []) of
- {ok, Pid} ->
- call(Pid, {open, ip_comm, OpenOptions}, plain);
- Error1 ->
- Error1
- end
- catch
- throw:Error2 ->
- Error2
- end.
-
-start_service(Options) ->
- try
- {ok, StartOptions} = start_options(Options),
- {ok, OpenOptions} = open_options(Options),
- case ftp_sup:start_child([[[{client, self()} | StartOptions], []]]) of
- {ok, Pid} ->
- call(Pid, {open, ip_comm, OpenOptions}, plain);
- Error1 ->
- Error1
- end
- catch
- throw:Error2 ->
- Error2
- end.
-
-stop_service(Pid) ->
- close(Pid).
-
-services() ->
- [{ftpc, Pid} || {_, Pid, _, _} <-
- supervisor:which_children(ftp_sup)].
-service_info(Pid) ->
- {ok, Info} = call(Pid, info, list),
- {ok, [proplists:lookup(mode, Info),
- proplists:lookup(local_port, Info),
- proplists:lookup(peer, Info),
- proplists:lookup(peer_port, Info)]}.
-
-
-%% This function extracts the start options from the
-%% Valid options:
-%% debug,
-%% verbose
-%% ipfamily
-%% priority
-%% flags (for backward compatibillity)
-start_options(Options) ->
- ?fcrt("start_options", [{options, Options}]),
- case lists:keysearch(flags, 1, Options) of
- {value, {flags, Flags}} ->
- Verbose = lists:member(verbose, Flags),
- IsTrace = lists:member(trace, Flags),
- IsDebug = lists:member(debug, Flags),
- DebugLevel =
- if
- (IsTrace =:= true) ->
- trace;
- IsDebug =:= true ->
- debug;
- true ->
- disable
- end,
- {ok, [{verbose, Verbose},
- {debug, DebugLevel},
- {priority, low}]};
- false ->
- ValidateVerbose =
- fun(true) -> true;
- (false) -> true;
- (_) -> false
- end,
- ValidateDebug =
- fun(trace) -> true;
- (debug) -> true;
- (disable) -> true;
- (_) -> false
- end,
- ValidatePriority =
- fun(low) -> true;
- (normal) -> true;
- (high) -> true;
- (_) -> false
- end,
- ValidOptions =
- [{verbose, ValidateVerbose, false, false},
- {debug, ValidateDebug, false, disable},
- {priority, ValidatePriority, false, low}],
- validate_options(Options, ValidOptions, [])
- end.
-
-
-%% This function extracts and validates the open options from the
-%% Valid options:
-%% mode
-%% host
-%% port
-%% timeout
-%% dtimeout
-%% progress
-%% ftp_extension
-
-open_options(Options) ->
- ?fcrt("open_options", [{options, Options}]),
- ValidateMode =
- fun(active) -> true;
- (passive) -> true;
- (_) -> false
- end,
- ValidateHost =
- fun(Host) when is_list(Host) ->
- true;
- (Host) when is_tuple(Host) andalso
- ((size(Host) =:= 4) orelse (size(Host) =:= 8)) ->
- true;
- (_) ->
- false
- end,
- ValidatePort =
- fun(Port) when is_integer(Port) andalso (Port > 0) -> true;
- (_) -> false
- end,
- ValidateIpFamily =
- fun(inet) -> true;
- (inet6) -> true;
- (inet6fb4) -> true;
- (_) -> false
- end,
- ValidateTimeout =
- fun(Timeout) when is_integer(Timeout) andalso (Timeout >= 0) -> true;
- (_) -> false
- end,
- ValidateDTimeout =
- fun(DTimeout) when is_integer(DTimeout) andalso (DTimeout >= 0) -> true;
- (infinity) -> true;
- (_) -> false
- end,
- ValidateProgress =
- fun(ignore) ->
- true;
- ({Mod, Func, _InitProgress}) when is_atom(Mod) andalso
- is_atom(Func) ->
- true;
- (_) ->
- false
- end,
- ValidateFtpExtension =
- fun(true) -> true;
- (false) -> true;
- (_) -> false
- end,
- ValidOptions =
- [{mode, ValidateMode, false, ?DEFAULT_MODE},
- {host, ValidateHost, true, ehost},
- {port, ValidatePort, false, ?FTP_PORT},
- {ipfamily, ValidateIpFamily, false, inet},
- {timeout, ValidateTimeout, false, ?CONNECTION_TIMEOUT},
- {dtimeout, ValidateDTimeout, false, ?DATA_ACCEPT_TIMEOUT},
- {progress, ValidateProgress, false, ?PROGRESS_DEFAULT},
- {ftp_extension, ValidateFtpExtension, false, ?FTP_EXT_DEFAULT}],
- validate_options(Options, ValidOptions, []).
-
-tls_options(Options) ->
- %% Options will be validated by ssl application
- proplists:get_value(tls, Options, undefined).
-
-validate_options([], [], Acc) ->
- ?fcrt("validate_options -> done", [{acc, Acc}]),
- {ok, lists:reverse(Acc)};
-validate_options([], ValidOptions, Acc) ->
- ?fcrt("validate_options -> done",
- [{valid_options, ValidOptions}, {acc, Acc}]),
- %% Check if any mandatory options are missing!
- case [{Key, Reason} || {Key, _, true, Reason} <- ValidOptions] of
- [] ->
- Defaults =
- [{Key, Default} || {Key, _, _, Default} <- ValidOptions],
- {ok, lists:reverse(Defaults ++ Acc)};
- [{_, Reason}|_Missing] ->
- throw({error, Reason})
- end;
-validate_options([{Key, Value}|Options], ValidOptions, Acc) ->
- ?fcrt("validate_options -> check",
- [{key, Key}, {value, Value}, {acc, Acc}]),
- case lists:keysearch(Key, 1, ValidOptions) of
- {value, {Key, Validate, _, Default}} ->
- case (catch Validate(Value)) of
- true ->
- ?fcrt("validate_options -> check - accept", []),
- NewValidOptions = lists:keydelete(Key, 1, ValidOptions),
- validate_options(Options, NewValidOptions,
- [{Key, Value} | Acc]);
- _ ->
- ?fcrt("validate_options -> check - reject",
- [{default, Default}]),
- NewValidOptions = lists:keydelete(Key, 1, ValidOptions),
- validate_options(Options, NewValidOptions,
- [{Key, Default} | Acc])
- end;
- false ->
- validate_options(Options, ValidOptions, Acc)
- end;
-validate_options([_|Options], ValidOptions, Acc) ->
- validate_options(Options, ValidOptions, Acc).
-
-
-
-%%%========================================================================
-%%% gen_server callback functions
-%%%========================================================================
-
-%%-------------------------------------------------------------------------
-%% init(Args) -> {ok, State} | {ok, State, Timeout} | {stop, Reason}
-%% Description: Initiates the erlang process that manages a ftp connection.
-%%-------------------------------------------------------------------------
-init(Options) ->
- process_flag(trap_exit, true),
-
- %% Keep track of the client
- {value, {client, Client}} = lists:keysearch(client, 1, Options),
- erlang:monitor(process, Client),
-
- %% Make sure inet is started
- _ = inet_db:start(),
-
- %% Where are we
- {ok, Dir} = file:get_cwd(),
-
- %% Maybe activate dbg
- case key_search(debug, Options, disable) of
- trace ->
- dbg:tracer(),
- dbg:p(all, [call]),
- {ok, _} = dbg:tpl(ftp, [{'_', [], [{return_trace}]}]),
- {ok, _} = dbg:tpl(ftp_response, [{'_', [], [{return_trace}]}]),
- {ok, _} = dbg:tpl(ftp_progress, [{'_', [], [{return_trace}]}]),
- ok;
- debug ->
- dbg:tracer(),
- dbg:p(all, [call]),
- {ok, _} = dbg:tp(ftp, [{'_', [], [{return_trace}]}]),
- {ok, _} = dbg:tp(ftp_response, [{'_', [], [{return_trace}]}]),
- {ok, _} = dbg:tp(ftp_progress, [{'_', [], [{return_trace}]}]),
- ok;
- _ ->
- %% Keep silent
- ok
- end,
-
- %% Verbose?
- Verbose = key_search(verbose, Options, false),
-
- %% IpFamily?
- IpFamily = key_search(ipfamily, Options, inet),
-
- State = #state{owner = Client,
- verbose = Verbose,
- ipfamily = IpFamily,
- ldir = Dir},
-
- %% Set process prio
- Priority = key_search(priority, Options, low),
- process_flag(priority, Priority),
-
- %% And we are done
- {ok, State}.
-
-
-%%--------------------------------------------------------------------------
-%% handle_call(Request, From, State) -> {reply, Reply, State} |
-%% {reply, Reply, State, Timeout} |
-%% {noreply, State} |
-%% {noreply, State, Timeout} |
-%% {stop, Reason, Reply, State} |
-%% Description: Handle incoming requests.
-%%-------------------------------------------------------------------------
-
-%% Anyone can ask this question
-handle_call({_, info}, _, #state{verbose = Verbose,
- mode = Mode,
- timeout = Timeout,
- ipfamily = IpFamily,
- csock = Socket,
- progress = Progress} = State) ->
- {ok, {_, LocalPort}} = sockname(Socket),
- {ok, {Address, Port}} = peername(Socket),
- Options = [{verbose, Verbose},
- {ipfamily, IpFamily},
- {mode, Mode},
- {peer, Address},
- {peer_port, Port},
- {local_port, LocalPort},
- {timeout, Timeout},
- {progress, Progress}],
- {reply, {ok, Options}, State};
-
-handle_call({_,latest_ctrl_response}, _, #state{latest_ctrl_response=Resp} = State) ->
- {reply, {ok,Resp}, State};
-
-%% But everything else must come from the owner
-handle_call({Pid, _}, _, #state{owner = Owner} = State) when Owner =/= Pid ->
- {reply, {error, not_connection_owner}, State};
-
-handle_call({_, {open, ip_comm, Opts}}, From, State) ->
- ?fcrd("handle_call(open)", [{opts, Opts}]),
- case key_search(host, Opts, undefined) of
- undefined ->
- {stop, normal, {error, ehost}, State};
- Host ->
- Mode = key_search(mode, Opts, ?DEFAULT_MODE),
- Port = key_search(port, Opts, ?FTP_PORT),
- Timeout = key_search(timeout, Opts, ?CONNECTION_TIMEOUT),
- DTimeout = key_search(dtimeout, Opts, ?DATA_ACCEPT_TIMEOUT),
- Progress = key_search(progress, Opts, ignore),
- IpFamily = key_search(ipfamily, Opts, inet),
- FtpExt = key_search(ftp_extension, Opts, ?FTP_EXT_DEFAULT),
-
- State2 = State#state{client = From,
- mode = Mode,
- progress = progress(Progress),
- ipfamily = IpFamily,
- dtimeout = DTimeout,
- ftp_extension = FtpExt},
-
- ?fcrd("handle_call(open) -> setup ctrl connection with",
- [{host, Host}, {port, Port}, {timeout, Timeout}]),
- case setup_ctrl_connection(Host, Port, Timeout, State2) of
- {ok, State3, WaitTimeout} ->
- ?fcrd("handle_call(open) -> ctrl connection setup done",
- [{waittimeout, WaitTimeout}]),
- {noreply, State3, WaitTimeout};
- {error, Reason} ->
- ?fcrd("handle_call(open) -> ctrl connection setup failed",
- [{reason, Reason}]),
- gen_server:reply(From, {error, ehost}),
- {stop, normal, State2#state{client = undefined}}
- end
- end;
-
-handle_call({_, {open, ip_comm, Host, Opts}}, From, State) ->
- Mode = key_search(mode, Opts, ?DEFAULT_MODE),
- Port = key_search(port, Opts, ?FTP_PORT),
- Timeout = key_search(timeout, Opts, ?CONNECTION_TIMEOUT),
- DTimeout = key_search(dtimeout, Opts, ?DATA_ACCEPT_TIMEOUT),
- Progress = key_search(progress, Opts, ignore),
- FtpExt = key_search(ftp_extension, Opts, ?FTP_EXT_DEFAULT),
-
- State2 = State#state{client = From,
- mode = Mode,
- progress = progress(Progress),
- dtimeout = DTimeout,
- ftp_extension = FtpExt},
-
- case setup_ctrl_connection(Host, Port, Timeout, State2) of
- {ok, State3, WaitTimeout} ->
- {noreply, State3, WaitTimeout};
- {error, _Reason} ->
- gen_server:reply(From, {error, ehost}),
- {stop, normal, State2#state{client = undefined}}
- end;
-
-handle_call({_, {open, tls_upgrade, TLSOptions}}, From, State) ->
- send_ctrl_message(State, mk_cmd("AUTH TLS", [])),
- activate_ctrl_connection(State),
- {noreply, State#state{client = From, caller = open, tls_options = TLSOptions}};
-
-handle_call({_, {user, User, Password}}, From,
- #state{csock = CSock} = State) when (CSock =/= undefined) ->
- handle_user(User, Password, "", State#state{client = From});
-
-handle_call({_, {user, User, Password, Acc}}, From,
- #state{csock = CSock} = State) when (CSock =/= undefined) ->
- handle_user(User, Password, Acc, State#state{client = From});
-
-handle_call({_, {account, Acc}}, From, State)->
- handle_user_account(Acc, State#state{client = From});
-
-handle_call({_, pwd}, From, #state{chunk = false} = State) ->
- send_ctrl_message(State, mk_cmd("PWD", [])),
- activate_ctrl_connection(State),
- {noreply, State#state{client = From, caller = pwd}};
-
-handle_call({_, lpwd}, From, #state{ldir = LDir} = State) ->
- {reply, {ok, LDir}, State#state{client = From}};
-
-handle_call({_, {cd, Dir}}, From, #state{chunk = false} = State) ->
- send_ctrl_message(State, mk_cmd("CWD ~s", [Dir])),
- activate_ctrl_connection(State),
- {noreply, State#state{client = From, caller = cd}};
-
-handle_call({_,{lcd, Dir}}, _From, #state{ldir = LDir0} = State) ->
- LDir = filename:absname(Dir, LDir0),
- case file:read_file_info(LDir) of %% FIX better check that LDir is a dir.
- {ok, _ } ->
- {reply, ok, State#state{ldir = LDir}};
- _ ->
- {reply, {error, epath}, State}
- end;
-
-handle_call({_, {dir, Len, Dir}}, {_Pid, _} = From,
- #state{chunk = false} = State) ->
- setup_data_connection(State#state{caller = {dir, Dir, Len},
- client = From});
-handle_call({_, {rename, CurrFile, NewFile}}, From,
- #state{chunk = false} = State) ->
- send_ctrl_message(State, mk_cmd("RNFR ~s", [CurrFile])),
- activate_ctrl_connection(State),
- {noreply, State#state{caller = {rename, NewFile}, client = From}};
-
-handle_call({_, {delete, File}}, {_Pid, _} = From,
- #state{chunk = false} = State) ->
- send_ctrl_message(State, mk_cmd("DELE ~s", [File])),
- activate_ctrl_connection(State),
- {noreply, State#state{client = From}};
-
-handle_call({_, {mkdir, Dir}}, From, #state{chunk = false} = State) ->
- send_ctrl_message(State, mk_cmd("MKD ~s", [Dir])),
- activate_ctrl_connection(State),
- {noreply, State#state{client = From}};
-
-handle_call({_,{rmdir, Dir}}, From, #state{chunk = false} = State) ->
- send_ctrl_message(State, mk_cmd("RMD ~s", [Dir])),
- activate_ctrl_connection(State),
- {noreply, State#state{client = From}};
-
-handle_call({_,{type, Type}}, From, #state{chunk = false} = State) ->
- case Type of
- ascii ->
- send_ctrl_message(State, mk_cmd("TYPE A", [])),
- activate_ctrl_connection(State),
- {noreply, State#state{caller = type, type = ascii,
- client = From}};
- binary ->
- send_ctrl_message(State, mk_cmd("TYPE I", [])),
- activate_ctrl_connection(State),
- {noreply, State#state{caller = type, type = binary,
- client = From}};
- _ ->
- {reply, {error, etype}, State}
- end;
-
-handle_call({_,{recv, RemoteFile, LocalFile}}, From,
- #state{chunk = false, ldir = LocalDir} = State) ->
- progress_report({remote_file, RemoteFile}, State),
- NewLocalFile = filename:absname(LocalFile, LocalDir),
-
- case file_open(NewLocalFile, write) of
- {ok, Fd} ->
- setup_data_connection(State#state{client = From,
- caller =
- {recv_file,
- RemoteFile, Fd}});
- {error, _What} ->
- {reply, {error, epath}, State}
- end;
-
-handle_call({_, {recv_bin, RemoteFile}}, From, #state{chunk = false} =
- State) ->
- setup_data_connection(State#state{caller = {recv_bin, RemoteFile},
- client = From});
-
-handle_call({_,{recv_chunk_start, RemoteFile}}, From, #state{chunk = false}
- = State) ->
- setup_data_connection(State#state{caller = {start_chunk_transfer,
- "RETR", RemoteFile},
- client = From});
-
-handle_call({_, recv_chunk}, _, #state{chunk = false} = State) ->
- {reply, {error, "ftp:recv_chunk_start/2 not called"}, State};
-
-handle_call({_, recv_chunk}, _From, #state{chunk = true,
- caller = #recv_chunk_closing{dconn_closed = true,
- pos_compl_received = true
- }
- } = State0) ->
- %% The ftp:recv_chunk call was the last event we waited for, finnish and clean up
- ?DBG("recv_chunk_closing ftp:recv_chunk, last event",[]),
- activate_ctrl_connection(State0),
- {reply, ok, State0#state{caller = undefined,
- chunk = false,
- client = undefined}};
-
-handle_call({_, recv_chunk}, From, #state{chunk = true,
- caller = #recv_chunk_closing{} = R
- } = State) ->
- %% Waiting for more, don't care what
- ?DBG("recv_chunk_closing ftp:recv_chunk, get more",[]),
- {noreply, State#state{client = From, caller = R#recv_chunk_closing{client_called_us=true}}};
-
-handle_call({_, recv_chunk}, From, #state{chunk = true} = State0) ->
- State = activate_data_connection(State0),
- {noreply, State#state{client = From, caller = recv_chunk}};
-
-handle_call({_, {send, LocalFile, RemoteFile}}, From,
- #state{chunk = false, ldir = LocalDir} = State) ->
- progress_report({local_file, filename:absname(LocalFile, LocalDir)},
- State),
- setup_data_connection(State#state{caller = {transfer_file,
- {"STOR",
- LocalFile, RemoteFile}},
- client = From});
-handle_call({_, {append, LocalFile, RemoteFile}}, From,
- #state{chunk = false} = State) ->
- setup_data_connection(State#state{caller = {transfer_file,
- {"APPE",
- LocalFile, RemoteFile}},
- client = From});
-handle_call({_, {send_bin, Bin, RemoteFile}}, From,
- #state{chunk = false} = State) ->
- setup_data_connection(State#state{caller = {transfer_data,
- {"STOR", Bin, RemoteFile}},
- client = From});
-handle_call({_,{append_bin, Bin, RemoteFile}}, From,
- #state{chunk = false} = State) ->
- setup_data_connection(State#state{caller = {transfer_data,
- {"APPE", Bin, RemoteFile}},
- client = From});
-handle_call({_, {send_chunk_start, RemoteFile}}, From, #state{chunk = false}
- = State) ->
- setup_data_connection(State#state{caller = {start_chunk_transfer,
- "STOR", RemoteFile},
- client = From});
-handle_call({_, {append_chunk_start, RemoteFile}}, From, #state{chunk = false}
- = State) ->
- setup_data_connection(State#state{caller = {start_chunk_transfer,
- "APPE", RemoteFile},
- client = From});
-handle_call({_, {transfer_chunk, Bin}}, _, #state{chunk = true} = State) ->
- send_data_message(State, Bin),
- {reply, ok, State};
-
-handle_call({_, {transfer_chunk, _}}, _, #state{chunk = false} = State) ->
- {reply, {error, echunk}, State};
-
-handle_call({_, chunk_end}, From, #state{chunk = true} = State) ->
- close_data_connection(State),
- activate_ctrl_connection(State),
- {noreply, State#state{client = From, dsock = undefined,
- caller = end_chunk_transfer, chunk = false}};
-
-handle_call({_, chunk_end}, _, #state{chunk = false} = State) ->
- {reply, {error, echunk}, State};
-
-handle_call({_, {quote, Cmd}}, From, #state{chunk = false} = State) ->
- send_ctrl_message(State, mk_cmd(Cmd, [])),
- activate_ctrl_connection(State),
- {noreply, State#state{client = From, caller = quote}};
-
-handle_call({_, _Req}, _From, #state{csock = CSock} = State)
- when (CSock =:= undefined) ->
- {reply, {error, not_connected}, State};
-
-handle_call(_, _, #state{chunk = true} = State) ->
- {reply, {error, echunk}, State};
-
-%% Catch all - This can only happen if the application programmer writes
-%% really bad code that violates the API.
-handle_call(Request, _Timeout, State) ->
- {stop, {'API_violation_connection_closed', Request},
- {error, {connection_terminated, 'API_violation'}}, State}.
-
-%%--------------------------------------------------------------------------
-%% handle_cast(Request, State) -> {noreply, State} |
-%% {noreply, State, Timeout} |
-%% {stop, Reason, State}
-%% Description: Handles cast messages.
-%%-------------------------------------------------------------------------
-handle_cast({Pid, close}, #state{owner = Pid} = State) ->
- send_ctrl_message(State, mk_cmd("QUIT", [])),
- close_ctrl_connection(State),
- close_data_connection(State),
- {stop, normal, State#state{csock = undefined, dsock = undefined}};
-
-handle_cast({Pid, close}, State) ->
- Report = io_lib:format("A none owner process ~p tried to close an "
- "ftp connection: ~n", [Pid]),
- error_logger:info_report(Report),
- {noreply, State};
-
-%% Catch all - This can oly happen if the application programmer writes
-%% really bad code that violates the API.
-handle_cast(Msg, State) ->
- {stop, {'API_violation_connection_closed', Msg}, State}.
-
-%%--------------------------------------------------------------------------
-%% handle_info(Msg, State) -> {noreply, State} | {noreply, State, Timeout} |
-%% {stop, Reason, State}
-%% Description: Handles tcp messages from the ftp-server.
-%% Note: The order of the function clauses is significant.
-%%--------------------------------------------------------------------------
-
-handle_info(timeout, #state{caller = open} = State) ->
- {stop, timeout, State};
-
-handle_info(timeout, State) ->
- {noreply, State};
-
-%%% Data socket messages %%%
-handle_info({Trpt, Socket, Data},
- #state{dsock = {Trpt,Socket},
- caller = {recv_file, Fd}} = State0) when Trpt==tcp;Trpt==ssl ->
- ?DBG('L~p --data ~p ----> ~s~p~n',[?LINE,Socket,Data,State0]),
- ok = file_write(binary_to_list(Data), Fd),
- progress_report({binary, Data}, State0),
- State = activate_data_connection(State0),
- {noreply, State};
-
-handle_info({Trpt, Socket, Data}, #state{dsock = {Trpt,Socket}, client = From,
- caller = recv_chunk}
- = State) when Trpt==tcp;Trpt==ssl ->
- ?DBG('L~p --data ~p ----> ~s~p~n',[?LINE,Socket,Data,State]),
- gen_server:reply(From, {ok, Data}),
- {noreply, State#state{client = undefined, data = <<>>}};
-
-handle_info({Trpt, Socket, Data}, #state{dsock = {Trpt,Socket}} = State0) when Trpt==tcp;Trpt==ssl ->
- ?DBG('L~p --data ~p ----> ~s~p~n',[?LINE,Socket,Data,State0]),
- State = activate_data_connection(State0),
- {noreply, State#state{data = <<(State#state.data)/binary,
- Data/binary>>}};
-
-handle_info({Cls, Socket}, #state{dsock = {Trpt,Socket},
- caller = {recv_file, Fd}} = State)
- when {Cls,Trpt}=={tcp_closed,tcp} ; {Cls,Trpt}=={ssl_closed,ssl} ->
- file_close(Fd),
- progress_report({transfer_size, 0}, State),
- activate_ctrl_connection(State),
- ?DBG("Data channel close",[]),
- {noreply, State#state{dsock = undefined, data = <<>>}};
-
-handle_info({Cls, Socket}, #state{dsock = {Trpt,Socket},
- client = Client,
- caller = recv_chunk} = State)
- when {Cls,Trpt}=={tcp_closed,tcp} ; {Cls,Trpt}=={ssl_closed,ssl} ->
- ?DBG("Data channel close recv_chunk",[]),
- activate_ctrl_connection(State),
- {noreply, State#state{dsock = undefined,
- caller = #recv_chunk_closing{dconn_closed = true,
- client_called_us = Client =/= undefined}
- }};
-
-handle_info({Cls, Socket}, #state{dsock = {Trpt,Socket}, caller = recv_bin,
- data = Data} = State)
- when {Cls,Trpt}=={tcp_closed,tcp} ; {Cls,Trpt}=={ssl_closed,ssl} ->
- ?DBG("Data channel close",[]),
- activate_ctrl_connection(State),
- {noreply, State#state{dsock = undefined, data = <<>>,
- caller = {recv_bin, Data}}};
-
-handle_info({Cls, Socket}, #state{dsock = {Trpt,Socket}, data = Data,
- caller = {handle_dir_result, Dir}}
- = State) when {Cls,Trpt}=={tcp_closed,tcp} ; {Cls,Trpt}=={ssl_closed,ssl} ->
- ?DBG("Data channel close",[]),
- activate_ctrl_connection(State),
- {noreply, State#state{dsock = undefined,
- caller = {handle_dir_result, Dir, Data},
-% data = <<?CR,?LF>>}};
- data = <<>>}};
-
-handle_info({Err, Socket, Reason}, #state{dsock = {Trpt,Socket},
- client = From} = State)
- when {Err,Trpt}=={tcp_error,tcp} ; {Err,Trpt}=={ssl_error,ssl} ->
- gen_server:reply(From, {error, Reason}),
- close_data_connection(State),
- {noreply, State#state{dsock = undefined, client = undefined,
- data = <<>>, caller = undefined, chunk = false}};
-
-%%% Ctrl socket messages %%%
-handle_info({Transport, Socket, Data}, #state{csock = {Transport, Socket},
- verbose = Verbose,
- caller = Caller,
- client = From,
- ctrl_data = {CtrlData, AccLines,
- LineStatus}}
- = State) ->
- ?DBG('--ctrl ~p ----> ~s~p~n',[Socket,<<CtrlData/binary, Data/binary>>,State]),
- case ftp_response:parse_lines(<<CtrlData/binary, Data/binary>>,
- AccLines, LineStatus) of
- {ok, Lines, NextMsgData} ->
- verbose(Lines, Verbose, 'receive'),
- CtrlResult = ftp_response:interpret(Lines),
- case Caller of
- quote ->
- gen_server:reply(From, string:tokens(Lines, [?CR, ?LF])),
- {noreply, State#state{client = undefined,
- caller = undefined,
- latest_ctrl_response = Lines,
- ctrl_data = {NextMsgData, [],
- start}}};
- _ ->
- ?DBG(' ...handle_ctrl_result(~p,...) ctrl_data=~p~n',[CtrlResult,{NextMsgData, [], start}]),
- handle_ctrl_result(CtrlResult,
- State#state{latest_ctrl_response = Lines,
- ctrl_data =
- {NextMsgData, [], start}})
- end;
- {continue, NewCtrlData} ->
- ?DBG(' ...Continue... ctrl_data=~p~n',[NewCtrlData]),
- activate_ctrl_connection(State),
- {noreply, State#state{ctrl_data = NewCtrlData}}
- end;
-
-%% If the server closes the control channel it is
-%% the expected behavior that connection process terminates.
-handle_info({Cls, Socket}, #state{csock = {Trpt, Socket}})
- when {Cls,Trpt}=={tcp_closed,tcp} ; {Cls,Trpt}=={ssl_closed,ssl} ->
- exit(normal); %% User will get error message from terminate/2
-
-handle_info({Err, Socket, Reason}, _) when Err==tcp_error ; Err==ssl_error ->
- Report =
- io_lib:format("~p on socket: ~p for reason: ~p~n",
- [Err, Socket, Reason]),
- error_logger:error_report(Report),
- %% If tcp does not work the only option is to terminate,
- %% this is the expected behavior under these circumstances.
- exit(normal); %% User will get error message from terminate/2
-
-%% Monitor messages - if the process owning the ftp connection goes
-%% down there is no point in continuing.
-handle_info({'DOWN', _Ref, _Type, _Process, normal}, State) ->
- {stop, normal, State#state{client = undefined}};
-
-handle_info({'DOWN', _Ref, _Type, _Process, shutdown}, State) ->
- {stop, normal, State#state{client = undefined}};
-
-handle_info({'DOWN', _Ref, _Type, _Process, timeout}, State) ->
- {stop, normal, State#state{client = undefined}};
-
-handle_info({'DOWN', _Ref, _Type, Process, Reason}, State) ->
- {stop, {stopped, {'EXIT', Process, Reason}},
- State#state{client = undefined}};
-
-handle_info({'EXIT', Pid, Reason}, #state{progress = Pid} = State) ->
- Report = io_lib:format("Progress reporting stopped for reason ~p~n",
- [Reason]),
- error_logger:info_report(Report),
- {noreply, State#state{progress = ignore}};
-
-%% Catch all - throws away unknown messages (This could happen by "accident"
-%% so we do not want to crash, but we make a log entry as it is an
-%% unwanted behaviour.)
-handle_info(Info, State) ->
- Report = io_lib:format("ftp : ~p : Unexpected message: ~p~nState: ~p~n",
- [self(), Info, State]),
- error_logger:info_report(Report),
- {noreply, State}.
-
-%%--------------------------------------------------------------------------
-%% terminate/2 and code_change/3
-%%--------------------------------------------------------------------------
-terminate(normal, State) ->
- %% If terminate reason =/= normal the progress reporting process will
- %% be killed by the exit signal.
- progress_report(stop, State),
- do_terminate({error, econn}, State);
-terminate(Reason, State) ->
- Report = io_lib:format("Ftp connection closed due to: ~p~n", [Reason]),
- error_logger:error_report(Report),
- do_terminate({error, eclosed}, State).
-
-do_terminate(ErrorMsg, State) ->
- close_data_connection(State),
- close_ctrl_connection(State),
- case State#state.client of
- undefined ->
- ok;
- From ->
- gen_server:reply(From, ErrorMsg)
- end,
- ok.
-
-code_change(_Vsn, State1, upgrade_from_pre_5_12) ->
- {state, CSock, DSock, Verbose, LDir, Type, Chunk, Mode, Timeout,
- Data, CtrlData, Owner, Client, Caller, IPv6Disable, Progress} = State1,
- IpFamily =
- if
- (IPv6Disable =:= true) ->
- inet;
- true ->
- inet6fb4
- end,
- State2 = #state{csock = CSock,
- dsock = DSock,
- verbose = Verbose,
- ldir = LDir,
- type = Type,
- chunk = Chunk,
- mode = Mode,
- timeout = Timeout,
- data = Data,
- ctrl_data = CtrlData,
- owner = Owner,
- client = Client,
- caller = Caller,
- ipfamily = IpFamily,
- progress = Progress},
- {ok, State2};
-
-code_change(_Vsn, State1, downgrade_to_pre_5_12) ->
- #state{csock = CSock,
- dsock = DSock,
- verbose = Verbose,
- ldir = LDir,
- type = Type,
- chunk = Chunk,
- mode = Mode,
- timeout = Timeout,
- data = Data,
- ctrl_data = CtrlData,
- owner = Owner,
- client = Client,
- caller = Caller,
- ipfamily = IpFamily,
- progress = Progress} = State1,
- IPv6Disable =
- if
- (IpFamily =:= inet) ->
- true;
- true ->
- false
- end,
- State2 =
- {state, CSock, DSock, Verbose, LDir, Type, Chunk, Mode, Timeout,
- Data, CtrlData, Owner, Client, Caller, IPv6Disable, Progress},
- {ok, State2};
-
-code_change(_Vsn, State, _Extra) ->
- {ok, State}.
-
-
-%%%=========================================================================
-%% Start/stop
-%%%=========================================================================
-%%--------------------------------------------------------------------------
-%% start_link([Opts, GenServerOptions]) -> {ok, Pid} | {error, Reason}
-%%
-%% Description: Callback function for the ftp supervisor. It is called
-%% : when start_service/1 calls ftp_sup:start_child/1 to start an
-%% : instance of the ftp process. Also called by start_standalone/1
-%%--------------------------------------------------------------------------
-start_link([Opts, GenServerOptions]) ->
- start_link(Opts, GenServerOptions).
-
-start_link(Opts, GenServerOptions) ->
- case lists:keysearch(client, 1, Opts) of
- {value, _} ->
- %% Via the supervisor
- gen_server:start_link(?MODULE, Opts, GenServerOptions);
- false ->
- Opts2 = [{client, self()} | Opts],
- gen_server:start_link(?MODULE, Opts2, GenServerOptions)
- end.
-
-
-%%% Stop functionality is handled by close/1
-
-%%%========================================================================
-%%% Internal functions
-%%%========================================================================
-
-%%--------------------------------------------------------------------------
-%%% Help functions to handle_call and/or handle_ctrl_result
-%%--------------------------------------------------------------------------
-%% User handling
-handle_user(User, Password, Acc, State) ->
- send_ctrl_message(State, mk_cmd("USER ~s", [User])),
- activate_ctrl_connection(State),
- {noreply, State#state{caller = {handle_user, Password, Acc}}}.
-
-handle_user_passwd(Password, Acc, State) ->
- send_ctrl_message(State, mk_cmd("PASS ~s", [Password])),
- activate_ctrl_connection(State),
- {noreply, State#state{caller = {handle_user_passwd, Acc}}}.
-
-handle_user_account(Acc, State) ->
- send_ctrl_message(State, mk_cmd("ACCT ~s", [Acc])),
- activate_ctrl_connection(State),
- {noreply, State#state{caller = handle_user_account}}.
-
-
-%%--------------------------------------------------------------------------
-%% handle_ctrl_result
-%%--------------------------------------------------------------------------
-handle_ctrl_result({tls_upgrade, _}, #state{csock = {tcp, Socket},
- tls_options = TLSOptions,
- timeout = Timeout,
- caller = open, client = From}
- = State0) ->
- ?DBG('<--ctrl ssl:connect(~p, ~p)~n~p~n',[Socket,TLSOptions,State0]),
- case ssl:connect(Socket, TLSOptions, Timeout) of
- {ok, TLSSocket} ->
- State = State0#state{csock = {ssl,TLSSocket}},
- send_ctrl_message(State, mk_cmd("PBSZ 0", [])),
- activate_ctrl_connection(State),
- {noreply, State#state{tls_upgrading_data_connection = {true, pbsz}} };
- {error, _} = Error ->
- gen_server:reply(From, {Error, self()}),
- {stop, normal, State0#state{client = undefined,
- caller = undefined,
- tls_upgrading_data_connection = false}}
- end;
-
-handle_ctrl_result({pos_compl, _}, #state{tls_upgrading_data_connection = {true, pbsz}} = State) ->
- send_ctrl_message(State, mk_cmd("PROT P", [])),
- activate_ctrl_connection(State),
- {noreply, State#state{tls_upgrading_data_connection = {true, prot}}};
-
-handle_ctrl_result({pos_compl, _}, #state{tls_upgrading_data_connection = {true, prot},
- client = From} = State) ->
- gen_server:reply(From, {ok, self()}),
- {noreply, State#state{client = undefined,
- caller = undefined,
- tls_upgrading_data_connection = false}};
-
-handle_ctrl_result({pos_compl, _}, #state{caller = open, client = From}
- = State) ->
- gen_server:reply(From, {ok, self()}),
- {noreply, State#state{client = undefined,
- caller = undefined }};
-handle_ctrl_result({_, Lines}, #state{caller = open} = State) ->
- ctrl_result_response(econn, State, {error, Lines});
-
-%%--------------------------------------------------------------------------
-%% Data connection setup active mode
-handle_ctrl_result({pos_compl, _Lines},
- #state{mode = active,
- caller = {setup_data_connection,
- {LSock, Caller}}} = State) ->
- handle_caller(State#state{caller = Caller, dsock = {lsock, LSock}});
-
-handle_ctrl_result({Status, _Lines},
- #state{mode = active,
- caller = {setup_data_connection, {LSock, _}}}
- = State) ->
- close_connection({tcp,LSock}),
- ctrl_result_response(Status, State, {error, Status});
-
-%% Data connection setup passive mode
-handle_ctrl_result({pos_compl, Lines},
- #state{mode = passive,
- ipfamily = inet6,
- client = From,
- caller = {setup_data_connection, Caller},
- csock = CSock,
- timeout = Timeout}
- = State) ->
- [_, PortStr | _] = lists:reverse(string:tokens(Lines, "|")),
- {ok, {IP, _}} = peername(CSock),
- case connect(IP, list_to_integer(PortStr), Timeout, State) of
- {ok, _, Socket} ->
- handle_caller(State#state{caller = Caller, dsock = {tcp, Socket}});
- {error, _Reason} = Error ->
- gen_server:reply(From, Error),
- {noreply, State#state{client = undefined, caller = undefined}}
- end;
-
-handle_ctrl_result({pos_compl, Lines},
- #state{mode = passive,
- ipfamily = inet,
- client = From,
- caller = {setup_data_connection, Caller},
- timeout = Timeout,
- ftp_extension = false} = State) ->
-
- {_, [?LEFT_PAREN | Rest]} =
- lists:splitwith(fun(?LEFT_PAREN) -> false; (_) -> true end, Lines),
- {NewPortAddr, _} =
- lists:splitwith(fun(?RIGHT_PAREN) -> false; (_) -> true end, Rest),
- [A1, A2, A3, A4, P1, P2] =
- lists:map(fun(X) -> list_to_integer(X) end,
- string:tokens(NewPortAddr, [$,])),
- IP = {A1, A2, A3, A4},
- Port = (P1 * 256) + P2,
-
- ?DBG('<--data tcp connect to ~p:~p, Caller=~p~n',[IP,Port,Caller]),
- case connect(IP, Port, Timeout, State) of
- {ok, _, Socket} ->
- handle_caller(State#state{caller = Caller, dsock = {tcp,Socket}});
- {error, _Reason} = Error ->
- gen_server:reply(From, Error),
- {noreply,State#state{client = undefined, caller = undefined}}
- end;
-
-handle_ctrl_result({pos_compl, Lines},
- #state{mode = passive,
- ipfamily = inet,
- client = From,
- caller = {setup_data_connection, Caller},
- csock = CSock,
- timeout = Timeout,
- ftp_extension = true} = State) ->
-
- [_, PortStr | _] = lists:reverse(string:tokens(Lines, "|")),
- {ok, {IP, _}} = peername(CSock),
-
- ?DBG('<--data tcp connect to ~p:~p, Caller=~p~n',[IP,PortStr,Caller]),
- case connect(IP, list_to_integer(PortStr), Timeout, State) of
- {ok, _, Socket} ->
- handle_caller(State#state{caller = Caller, dsock = {tcp, Socket}});
- {error, _Reason} = Error ->
- gen_server:reply(From, Error),
- {noreply, State#state{client = undefined, caller = undefined}}
- end;
-
-
-%% FTP server does not support passive mode: try to fallback on active mode
-handle_ctrl_result(_,
- #state{mode = passive,
- caller = {setup_data_connection, Caller}} = State) ->
- setup_data_connection(State#state{mode = active, caller = Caller});
-
-
-%%--------------------------------------------------------------------------
-%% User handling
-handle_ctrl_result({pos_interm, _},
- #state{caller = {handle_user, PassWord, Acc}} = State) ->
- handle_user_passwd(PassWord, Acc, State);
-handle_ctrl_result({Status, _},
- #state{caller = {handle_user, _, _}} = State) ->
- ctrl_result_response(Status, State, {error, euser});
-
-%% Accounts
-handle_ctrl_result({pos_interm_acct, _},
- #state{caller = {handle_user_passwd, Acc}} = State)
- when Acc =/= "" ->
- handle_user_account(Acc, State);
-handle_ctrl_result({Status, _},
- #state{caller = {handle_user_passwd, _}} = State) ->
- ctrl_result_response(Status, State, {error, euser});
-
-%%--------------------------------------------------------------------------
-%% Print current working directory
-handle_ctrl_result({pos_compl, Lines},
- #state{caller = pwd, client = From} = State) ->
- Dir = pwd_result(Lines),
- gen_server:reply(From, {ok, Dir}),
- {noreply, State#state{client = undefined, caller = undefined}};
-
-%%--------------------------------------------------------------------------
-%% Directory listing
-handle_ctrl_result({pos_prel, _}, #state{caller = {dir, Dir}} = State0) ->
- case accept_data_connection(State0) of
- {ok, State1} ->
- State = activate_data_connection(State1),
- {noreply, State#state{caller = {handle_dir_result, Dir}}};
- {error, _Reason} = ERROR ->
- case State0#state.client of
- undefined ->
- {stop, ERROR, State0};
- From ->
- gen_server:reply(From, ERROR),
- {stop, normal, State0#state{client = undefined}}
- end
- end;
-
-handle_ctrl_result({pos_compl, _}, #state{caller = {handle_dir_result, Dir,
- Data}, client = From}
- = State) ->
- case Dir of
- "" -> % Current directory
- gen_server:reply(From, {ok, Data}),
- {noreply, State#state{client = undefined,
- caller = undefined}};
- _ ->
- %% <WTF>
- %% Dir cannot be assumed to be a dir. It is a string that
- %% could be a dir, but could also be a file or even a string
- %% containing wildcards (*).
- %%
- %% %% If there is only one line it might be a directory with one
- %% %% file but it might be an error message that the directory
- %% %% was not found. So in this case we have to endure a little
- %% %% overhead to be able to give a good return value. Alas not
- %% %% all ftp implementations behave the same and returning
- %% %% an error string is allowed by the FTP RFC.
- %% case lists:dropwhile(fun(?CR) -> false;(_) -> true end,
- %% binary_to_list(Data)) of
- %% L when (L =:= [?CR, ?LF]) orelse (L =:= []) ->
- %% send_ctrl_message(State, mk_cmd("PWD", [])),
- %% activate_ctrl_connection(State),
- %% {noreply,
- %% State#state{caller = {handle_dir_data, Dir, Data}}};
- %% _ ->
- %% gen_server:reply(From, {ok, Data}),
- %% {noreply, State#state{client = undefined,
- %% caller = undefined}}
- %% end
- %% </WTF>
- gen_server:reply(From, {ok, Data}),
- {noreply, State#state{client = undefined,
- caller = undefined}}
- end;
-
-handle_ctrl_result({pos_compl, Lines},
- #state{caller = {handle_dir_data, Dir, DirData}} =
- State) ->
- OldDir = pwd_result(Lines),
- send_ctrl_message(State, mk_cmd("CWD ~s", [Dir])),
- activate_ctrl_connection(State),
- {noreply, State#state{caller = {handle_dir_data_second_phase, OldDir,
- DirData}}};
-handle_ctrl_result({Status, _},
- #state{caller = {handle_dir_data, _, _}} = State) ->
- ctrl_result_response(Status, State, {error, epath});
-
-handle_ctrl_result(S={_Status, _},
- #state{caller = {handle_dir_result, _, _}} = State) ->
- %% OTP-5731, macosx
- ctrl_result_response(S, State, {error, epath});
-
-handle_ctrl_result({pos_compl, _},
- #state{caller = {handle_dir_data_second_phase, OldDir,
- DirData}} = State) ->
- send_ctrl_message(State, mk_cmd("CWD ~s", [OldDir])),
- activate_ctrl_connection(State),
- {noreply, State#state{caller = {handle_dir_data_third_phase, DirData}}};
-handle_ctrl_result({Status, _},
- #state{caller = {handle_dir_data_second_phase, _, _}}
- = State) ->
- ctrl_result_response(Status, State, {error, epath});
-handle_ctrl_result(_, #state{caller = {handle_dir_data_third_phase, DirData},
- client = From} = State) ->
- gen_server:reply(From, {ok, DirData}),
- {noreply, State#state{client = undefined, caller = undefined}};
-
-handle_ctrl_result({Status, _}, #state{caller = cd} = State) ->
- ctrl_result_response(Status, State, {error, Status});
-
-handle_ctrl_result(Status={epath, _}, #state{caller = {dir,_}} = State) ->
- ctrl_result_response(Status, State, {error, epath});
-
-%%--------------------------------------------------------------------------
-%% File renaming
-handle_ctrl_result({pos_interm, _}, #state{caller = {rename, NewFile}}
- = State) ->
- send_ctrl_message(State, mk_cmd("RNTO ~s", [NewFile])),
- activate_ctrl_connection(State),
- {noreply, State#state{caller = rename_second_phase}};
-
-handle_ctrl_result({Status, _},
- #state{caller = {rename, _}} = State) ->
- ctrl_result_response(Status, State, {error, Status});
-
-handle_ctrl_result({Status, _},
- #state{caller = rename_second_phase} = State) ->
- ctrl_result_response(Status, State, {error, Status});
-
-%%--------------------------------------------------------------------------
-%% File handling - recv_bin
-handle_ctrl_result({pos_prel, _}, #state{caller = recv_bin} = State0) ->
- case accept_data_connection(State0) of
- {ok, State1} ->
- State = activate_data_connection(State1),
- {noreply, State};
- {error, _Reason} = ERROR ->
- case State0#state.client of
- undefined ->
- {stop, ERROR, State0};
- From ->
- gen_server:reply(From, ERROR),
- {stop, normal, State0#state{client = undefined}}
- end
- end;
-
-handle_ctrl_result({pos_compl, _}, #state{caller = {recv_bin, Data},
- client = From} = State) ->
- gen_server:reply(From, {ok, Data}),
- close_data_connection(State),
- {noreply, State#state{client = undefined, caller = undefined}};
-
-handle_ctrl_result({Status, _}, #state{caller = recv_bin} = State) ->
- close_data_connection(State),
- ctrl_result_response(Status, State#state{dsock = undefined},
- {error, epath});
-
-handle_ctrl_result({Status, _}, #state{caller = {recv_bin, _}} = State) ->
- close_data_connection(State),
- ctrl_result_response(Status, State#state{dsock = undefined},
- {error, epath});
-%%--------------------------------------------------------------------------
-%% File handling - start_chunk_transfer
-handle_ctrl_result({pos_prel, _}, #state{client = From,
- caller = start_chunk_transfer}
- = State0) ->
- case accept_data_connection(State0) of
- {ok, State1} ->
- State = start_chunk(State1),
- {noreply, State};
- {error, _Reason} = ERROR ->
- case State0#state.client of
- undefined ->
- {stop, ERROR, State0};
- From ->
- gen_server:reply(From, ERROR),
- {stop, normal, State0#state{client = undefined}}
- end
- end;
-
-%%--------------------------------------------------------------------------
-%% File handling - chunk_transfer complete
-
-handle_ctrl_result({pos_compl, _}, #state{client = From,
- caller = #recv_chunk_closing{dconn_closed = true,
- client_called_us = true,
- pos_compl_received = false
- }}
- = State0) when From =/= undefined ->
- %% The pos_compl was the last event we waited for, finnish and clean up
- ?DBG("recv_chunk_closing pos_compl, last event",[]),
- gen_server:reply(From, ok),
- activate_ctrl_connection(State0),
- {noreply, State0#state{caller = undefined,
- chunk = false,
- client = undefined}};
-
-handle_ctrl_result({pos_compl, _}, #state{caller = #recv_chunk_closing{}=R}
- = State0) ->
- %% Waiting for more, don't care what
- ?DBG("recv_chunk_closing pos_compl, wait more",[]),
- {noreply, State0#state{caller = R#recv_chunk_closing{pos_compl_received=true}}};
-
-
-%%--------------------------------------------------------------------------
-%% File handling - recv_file
-handle_ctrl_result({pos_prel, _}, #state{caller = {recv_file, _}} = State0) ->
- case accept_data_connection(State0) of
- {ok, State1} ->
- State = activate_data_connection(State1),
- {noreply, State};
- {error, _Reason} = ERROR ->
- case State0#state.client of
- undefined ->
- {stop, ERROR, State0};
- From ->
- gen_server:reply(From, ERROR),
- {stop, normal, State0#state{client = undefined}}
- end
- end;
-
-handle_ctrl_result({Status, _}, #state{caller = {recv_file, Fd}} = State) ->
- file_close(Fd),
- close_data_connection(State),
- ctrl_result_response(Status, State#state{dsock = undefined},
- {error, epath});
-%%--------------------------------------------------------------------------
-%% File handling - transfer_*
-handle_ctrl_result({pos_prel, _}, #state{caller = {transfer_file, Fd}}
- = State0) ->
- case accept_data_connection(State0) of
- {ok, State1} ->
- send_file(State1, Fd);
- {error, _Reason} = ERROR ->
- case State0#state.client of
- undefined ->
- {stop, ERROR, State0};
- From ->
- gen_server:reply(From, ERROR),
- {stop, normal, State0#state{client = undefined}}
- end
- end;
-
-handle_ctrl_result({pos_prel, _}, #state{caller = {transfer_data, Bin}}
- = State0) ->
- case accept_data_connection(State0) of
- {ok, State} ->
- send_bin(State, Bin);
- {error, _Reason} = ERROR ->
- case State0#state.client of
- undefined ->
- {stop, ERROR, State0};
- From ->
- gen_server:reply(From, ERROR),
- {stop, normal, State0#state{client = undefined}}
- end
- end;
-
-%%--------------------------------------------------------------------------
-%% Default
-handle_ctrl_result({Status, _Lines}, #state{client = From} = State)
- when From =/= undefined ->
- ctrl_result_response(Status, State, {error, Status}).
-
-%%--------------------------------------------------------------------------
-%% Help functions to handle_ctrl_result
-%%--------------------------------------------------------------------------
-ctrl_result_response(pos_compl, #state{client = From} = State, _) ->
- gen_server:reply(From, ok),
- {noreply, State#state{client = undefined, caller = undefined}};
-
-ctrl_result_response(enofile, #state{client = From} = State, _) ->
- gen_server:reply(From, {error, enofile}),
- {noreply, State#state{client = undefined, caller = undefined}};
-
-ctrl_result_response(Status, #state{client = From} = State, _)
- when (Status =:= etnospc) orelse
- (Status =:= epnospc) orelse
- (Status =:= efnamena) orelse
- (Status =:= econn) ->
- gen_server:reply(From, {error, Status}),
-%% {stop, normal, {error, Status}, State#state{client = undefined}};
- {stop, normal, State#state{client = undefined}};
-
-ctrl_result_response(_, #state{client = From} = State, ErrorMsg) ->
- gen_server:reply(From, ErrorMsg),
- {noreply, State#state{client = undefined, caller = undefined}}.
-
-%%--------------------------------------------------------------------------
-handle_caller(#state{caller = {dir, Dir, Len}} = State) ->
- Cmd = case Len of
- short -> "NLST";
- long -> "LIST"
- end,
- case Dir of
- "" ->
- send_ctrl_message(State, mk_cmd(Cmd, ""));
- _ ->
- send_ctrl_message(State, mk_cmd(Cmd ++ " ~s", [Dir]))
- end,
- activate_ctrl_connection(State),
- {noreply, State#state{caller = {dir, Dir}}};
-
-handle_caller(#state{caller = {recv_bin, RemoteFile}} = State) ->
- send_ctrl_message(State, mk_cmd("RETR ~s", [RemoteFile])),
- activate_ctrl_connection(State),
- {noreply, State#state{caller = recv_bin}};
-
-handle_caller(#state{caller = {start_chunk_transfer, Cmd, RemoteFile}} =
- State) ->
- send_ctrl_message(State, mk_cmd("~s ~s", [Cmd, RemoteFile])),
- activate_ctrl_connection(State),
- {noreply, State#state{caller = start_chunk_transfer}};
-
-handle_caller(#state{caller = {recv_file, RemoteFile, Fd}} = State) ->
- send_ctrl_message(State, mk_cmd("RETR ~s", [RemoteFile])),
- activate_ctrl_connection(State),
- {noreply, State#state{caller = {recv_file, Fd}}};
-
-handle_caller(#state{caller = {transfer_file, {Cmd, LocalFile, RemoteFile}},
- ldir = LocalDir, client = From} = State) ->
- case file_open(filename:absname(LocalFile, LocalDir), read) of
- {ok, Fd} ->
- send_ctrl_message(State, mk_cmd("~s ~s", [Cmd, RemoteFile])),
- activate_ctrl_connection(State),
- {noreply, State#state{caller = {transfer_file, Fd}}};
- {error, _} ->
- gen_server:reply(From, {error, epath}),
- {noreply, State#state{client = undefined, caller = undefined,
- dsock = undefined}}
- end;
-
-handle_caller(#state{caller = {transfer_data, {Cmd, Bin, RemoteFile}}} =
- State) ->
- send_ctrl_message(State, mk_cmd("~s ~s", [Cmd, RemoteFile])),
- activate_ctrl_connection(State),
- {noreply, State#state{caller = {transfer_data, Bin}}}.
-
-%% ----------- FTP SERVER COMMUNICATION -------------------------
-
-%% Connect to FTP server at Host (default is TCP port 21)
-%% in order to establish a control connection.
-setup_ctrl_connection(Host, Port, Timeout, State) ->
- MsTime = erlang:monotonic_time(),
- case connect(Host, Port, Timeout, State) of
- {ok, IpFam, CSock} ->
- NewState = State#state{csock = {tcp, CSock}, ipfamily = IpFam},
- activate_ctrl_connection(NewState),
- case Timeout - inets_lib:millisec_passed(MsTime) of
- Timeout2 when (Timeout2 >= 0) ->
- {ok, NewState#state{caller = open}, Timeout2};
- _ ->
- %% Oups: Simulate timeout
- {ok, NewState#state{caller = open}, 0}
- end;
- Error ->
- Error
- end.
-
-setup_data_connection(#state{mode = active,
- caller = Caller,
- csock = CSock,
- ftp_extension = FtpExt} = State) ->
- case (catch sockname(CSock)) of
- {ok, {{_, _, _, _, _, _, _, _} = IP, _}} ->
- {ok, LSock} =
- gen_tcp:listen(0, [{ip, IP}, {active, false},
- inet6, binary, {packet, 0}]),
- {ok, {_, Port}} = sockname({tcp,LSock}),
- IpAddress = inet_parse:ntoa(IP),
- Cmd = mk_cmd("EPRT |2|~s|~p|", [IpAddress, Port]),
- send_ctrl_message(State, Cmd),
- activate_ctrl_connection(State),
- {noreply, State#state{caller = {setup_data_connection,
- {LSock, Caller}}}};
- {ok, {{_,_,_,_} = IP, _}} ->
- {ok, LSock} = gen_tcp:listen(0, [{ip, IP}, {active, false},
- binary, {packet, 0}]),
- {ok, Port} = inet:port(LSock),
- case FtpExt of
- false ->
- {IP1, IP2, IP3, IP4} = IP,
- {Port1, Port2} = {Port div 256, Port rem 256},
- send_ctrl_message(State,
- mk_cmd("PORT ~w,~w,~w,~w,~w,~w",
- [IP1, IP2, IP3, IP4, Port1, Port2]));
- true ->
- IpAddress = inet_parse:ntoa(IP),
- Cmd = mk_cmd("EPRT |1|~s|~p|", [IpAddress, Port]),
- send_ctrl_message(State, Cmd)
- end,
- activate_ctrl_connection(State),
- {noreply, State#state{caller = {setup_data_connection,
- {LSock, Caller}}}}
- end;
-
-setup_data_connection(#state{mode = passive, ipfamily = inet6,
- caller = Caller} = State) ->
- send_ctrl_message(State, mk_cmd("EPSV", [])),
- activate_ctrl_connection(State),
- {noreply, State#state{caller = {setup_data_connection, Caller}}};
-
-setup_data_connection(#state{mode = passive, ipfamily = inet,
- caller = Caller,
- ftp_extension = false} = State) ->
- send_ctrl_message(State, mk_cmd("PASV", [])),
- activate_ctrl_connection(State),
- {noreply, State#state{caller = {setup_data_connection, Caller}}};
-
-setup_data_connection(#state{mode = passive, ipfamily = inet,
- caller = Caller,
- ftp_extension = true} = State) ->
- send_ctrl_message(State, mk_cmd("EPSV", [])),
- activate_ctrl_connection(State),
- {noreply, State#state{caller = {setup_data_connection, Caller}}}.
-
-connect(Host, Port, Timeout, #state{ipfamily = inet = IpFam}) ->
- connect2(Host, Port, IpFam, Timeout);
-
-connect(Host, Port, Timeout, #state{ipfamily = inet6 = IpFam}) ->
- connect2(Host, Port, IpFam, Timeout);
-
-connect(Host, Port, Timeout, #state{ipfamily = inet6fb4}) ->
- case inet:getaddr(Host, inet6) of
- {ok, {0, 0, 0, 0, 0, 16#ffff, _, _} = IPv6} ->
- case inet:getaddr(Host, inet) of
- {ok, IPv4} ->
- IpFam = inet,
- connect2(IPv4, Port, IpFam, Timeout);
-
- _ ->
- IpFam = inet6,
- connect2(IPv6, Port, IpFam, Timeout)
- end;
-
- {ok, IPv6} ->
- IpFam = inet6,
- connect2(IPv6, Port, IpFam, Timeout);
-
- _ ->
- case inet:getaddr(Host, inet) of
- {ok, IPv4} ->
- IpFam = inet,
- connect2(IPv4, Port, IpFam, Timeout);
- Error ->
- Error
- end
- end.
-
-connect2(Host, Port, IpFam, Timeout) ->
- Opts = [IpFam, binary, {packet, 0}, {active, false}],
- case gen_tcp:connect(Host, Port, Opts, Timeout) of
- {ok, Sock} ->
- {ok, IpFam, Sock};
- Error ->
- Error
- end.
-
-
-accept_data_connection(#state{mode = active,
- dtimeout = DTimeout,
- tls_options = TLSOptions,
- dsock = {lsock, LSock}} = State0) ->
- case gen_tcp:accept(LSock, DTimeout) of
- {ok, Socket} when is_list(TLSOptions) ->
- gen_tcp:close(LSock),
- ?DBG('<--data ssl:connect(~p, ~p)~n~p~n',[Socket,TLSOptions,State0]),
- case ssl:connect(Socket, TLSOptions, DTimeout) of
- {ok, TLSSocket} ->
- {ok, State0#state{dsock={ssl,TLSSocket}}};
- {error, Reason} ->
- {error, {ssl_connect_failed, Reason}}
- end;
- {ok, Socket} ->
- gen_tcp:close(LSock),
- {ok, State0#state{dsock={tcp,Socket}}};
- {error, Reason} ->
- {error, {data_connect_failed, Reason}}
- end;
-
-accept_data_connection(#state{mode = passive,
- dtimeout = DTimeout,
- dsock = {tcp,Socket},
- tls_options = TLSOptions} = State) when is_list(TLSOptions) ->
- ?DBG('<--data ssl:connect(~p, ~p)~n~p~n',[Socket,TLSOptions,State]),
- case ssl:connect(Socket, TLSOptions, DTimeout) of
- {ok, TLSSocket} ->
- {ok, State#state{dsock={ssl,TLSSocket}}};
- {error, Reason} ->
- {error, {ssl_connect_failed, Reason}}
- end;
-accept_data_connection(#state{mode = passive} = State) ->
- {ok,State}.
-
-
-send_ctrl_message(_S=#state{csock = Socket, verbose = Verbose}, Message) ->
- verbose(lists:flatten(Message),Verbose,send),
- ?DBG('<--ctrl ~p ---- ~s~p~n',[Socket,Message,_S]),
- _ = send_message(Socket, Message).
-
-send_data_message(_S=#state{dsock = Socket}, Message) ->
- ?DBG('<==data ~p ==== ~s~n~p~n',[Socket,Message,_S]),
- case send_message(Socket, Message) of
- ok ->
- ok;
- {error, Reason} ->
- Report = io_lib:format("send/2 for socket ~p failed with "
- "reason ~p~n", [Socket, Reason]),
- error_logger:error_report(Report),
- %% If tcp/ssl does not work the only option is to terminate,
- %% this is the expected behavior under these circumstances.
- exit(normal) %% User will get error message from terminate/2
- end.
-
-send_message({tcp, Socket}, Message) ->
- gen_tcp:send(Socket, Message);
-send_message({ssl, Socket}, Message) ->
- ssl:send(Socket, Message).
-
-activate_ctrl_connection(#state{csock = CSock, ctrl_data = {<<>>, _, _}}) ->
- activate_connection(CSock);
-activate_ctrl_connection(#state{csock = CSock}) ->
- activate_connection(CSock),
- %% We have already received at least part of the next control message,
- %% that has been saved in ctrl_data, process this first.
- self() ! {socket_type(CSock), unwrap_socket(CSock), <<>>},
- ok.
-
-activate_data_connection(#state{dsock = DSock} = State) ->
- activate_connection(DSock),
- State.
-
-activate_connection(Socket) ->
- ignore_return_value(
- case socket_type(Socket) of
- tcp -> inet:setopts(unwrap_socket(Socket), [{active, once}]);
- ssl -> ssl:setopts(unwrap_socket(Socket), [{active, once}])
- end).
-
-
-ignore_return_value(_) -> ok.
-
-unwrap_socket({tcp,Socket}) -> Socket;
-unwrap_socket({ssl,Socket}) -> Socket.
-
-socket_type({tcp,_Socket}) -> tcp;
-socket_type({ssl,_Socket}) -> ssl.
-
-close_ctrl_connection(#state{csock = undefined}) -> ok;
-close_ctrl_connection(#state{csock = Socket}) -> close_connection(Socket).
-
-close_data_connection(#state{dsock = undefined}) -> ok;
-close_data_connection(#state{dsock = Socket}) -> close_connection(Socket).
-
-close_connection({lsock,Socket}) -> ignore_return_value( gen_tcp:close(Socket) );
-close_connection({tcp, Socket}) -> ignore_return_value( gen_tcp:close(Socket) );
-close_connection({ssl, Socket}) -> ignore_return_value( ssl:close(Socket) ).
-
-%% ------------ FILE HANDLING ----------------------------------------
-send_file(#state{tls_upgrading_data_connection = {true, CTRL, _}} = State, Fd) ->
- {noreply, State#state{tls_upgrading_data_connection = {true, CTRL, ?MODULE, send_file, Fd}}};
-send_file(State, Fd) ->
- case file_read(Fd) of
- {ok, N, Bin} when N > 0 ->
- send_data_message(State, Bin),
- progress_report({binary, Bin}, State),
- send_file(State, Fd);
- {ok, _, _} ->
- file_close(Fd),
- close_data_connection(State),
- progress_report({transfer_size, 0}, State),
- activate_ctrl_connection(State),
- {noreply, State#state{caller = transfer_file_second_phase,
- dsock = undefined}};
- {error, Reason} ->
- gen_server:reply(State#state.client, {error, Reason}),
- {stop, normal, State#state{client = undefined}}
- end.
-
-file_open(File, Option) ->
- file:open(File, [raw, binary, Option]).
-
-file_close(Fd) ->
- ignore_return_value( file:close(Fd) ).
-
-file_read(Fd) ->
- case file:read(Fd, ?FILE_BUFSIZE) of
- {ok, Bytes} ->
- {ok, size(Bytes), Bytes};
- eof ->
- {ok, 0, []};
- Other ->
- Other
- end.
-
-file_write(Bytes, Fd) ->
- file:write(Fd, Bytes).
-
-%% -------------- MISC ----------------------------------------------
-
-call(GenServer, Msg, Format) ->
- call(GenServer, Msg, Format, infinity).
-call(GenServer, Msg, Format, Timeout) ->
- Req = {self(), Msg},
- case (catch gen_server:call(GenServer, Req, Timeout)) of
- {ok, Bin} when is_binary(Bin) andalso (Format =:= string) ->
- {ok, binary_to_list(Bin)};
- {'EXIT', _} ->
- {error, eclosed};
- Result ->
- Result
- end.
-
-cast(GenServer, Msg) ->
- gen_server:cast(GenServer, {self(), Msg}).
-
-send_bin(#state{tls_upgrading_data_connection = {true, CTRL, _}} = State, Bin) ->
- State#state{tls_upgrading_data_connection = {true, CTRL, ?MODULE, send_bin, Bin}};
-send_bin(State, Bin) ->
- send_data_message(State, Bin),
- close_data_connection(State),
- activate_ctrl_connection(State),
- {noreply, State#state{caller = transfer_data_second_phase,
- dsock = undefined}}.
-
-mk_cmd(Fmt, Args) ->
- [io_lib:format(Fmt, Args)| [?CR, ?LF]]. % Deep list ok.
-
-is_name_sane([]) ->
- true;
-is_name_sane([?CR| _]) ->
- false;
-is_name_sane([?LF| _]) ->
- false;
-is_name_sane([_| Rest]) ->
- is_name_sane(Rest).
-
-pwd_result(Lines) ->
- {_, [?DOUBLE_QUOTE | Rest]} =
- lists:splitwith(fun(?DOUBLE_QUOTE) -> false; (_) -> true end, Lines),
- {Dir, _} =
- lists:splitwith(fun(?DOUBLE_QUOTE) -> false; (_) -> true end, Rest),
- Dir.
-
-
-key_search(Key, List, Default) ->
- case lists:keysearch(Key, 1, List) of
- {value, {_,Val}} ->
- Val;
- false ->
- Default
- end.
-
-verbose(Lines, true, Direction) ->
- DirStr =
- case Direction of
- send ->
- "Sending: ";
- _ ->
- "Receiving: "
- end,
- Str = string:strip(string:strip(Lines, right, ?LF), right, ?CR),
- erlang:display(DirStr++Str);
-verbose(_, false,_) ->
- ok.
-
-progress(Options) ->
- ftp_progress:start_link(Options).
-
-progress_report(_, #state{progress = ignore}) ->
- ok;
-progress_report(stop, #state{progress = ProgressPid}) ->
- ftp_progress:stop(ProgressPid);
-progress_report({binary, Data}, #state{progress = ProgressPid}) ->
- ftp_progress:report(ProgressPid, {transfer_size, size(Data)});
-progress_report(Report, #state{progress = ProgressPid}) ->
- ftp_progress:report(ProgressPid, Report).
-
-
-peername({tcp, Socket}) -> inet:peername(Socket);
-peername({ssl, Socket}) -> ssl:peername(Socket).
-
-sockname({tcp, Socket}) -> inet:sockname(Socket);
-sockname({ssl, Socket}) -> ssl:sockname(Socket).
-
-maybe_tls_upgrade(Pid, undefined) ->
- {ok, Pid};
-maybe_tls_upgrade(Pid, TLSOptions) ->
- catch ssl:start(),
- call(Pid, {open, tls_upgrade, TLSOptions}, plain).
-
-start_chunk(#state{tls_upgrading_data_connection = {true, CTRL, _}} = State) ->
- State#state{tls_upgrading_data_connection = {true, CTRL, ?MODULE, start_chunk, undefined}};
-start_chunk(#state{client = From} = State) ->
- gen_server:reply(From, ok),
- State#state{chunk = true,
- client = undefined,
- caller = undefined}.
diff --git a/lib/inets/src/ftp/ftp_internal.hrl b/lib/inets/src/ftp/ftp_internal.hrl
deleted file mode 100644
index f29bb4a099..0000000000
--- a/lib/inets/src/ftp/ftp_internal.hrl
+++ /dev/null
@@ -1,33 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--ifndef(ftp_internal_hrl).
--define(ftp_internal_hrl, true).
-
--include_lib("inets/src/inets_app/inets_internal.hrl").
-
--define(SERVICE, ftpc).
--define(fcri(Label, Content), ?report_important(Label, ?SERVICE, Content)).
--define(fcrv(Label, Content), ?report_verbose(Label, ?SERVICE, Content)).
--define(fcrd(Label, Content), ?report_debug(Label, ?SERVICE, Content)).
--define(fcrt(Label, Content), ?report_trace(Label, ?SERVICE, Content)).
-
--endif. % -ifdef(ftp_internal_hrl).
diff --git a/lib/inets/src/ftp/ftp_progress.erl b/lib/inets/src/ftp/ftp_progress.erl
deleted file mode 100644
index a6263e5cd7..0000000000
--- a/lib/inets/src/ftp/ftp_progress.erl
+++ /dev/null
@@ -1,136 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%% Description: This module impements a temporary process that
-%% performes progress reporting during file transfer calling a user
-%% defined callback function. Its life span is as long as the ftp connection
-%% processes that spawned it lives. The purpose of this process is to
-%% shild the ftp connection process from errors and time consuming operations
-%% in the user defined callback function.
-
--module(ftp_progress).
-
-%% Internal API
--export([start_link/1, report/2, stop/1]).
-
-%% Spawn export
--export([init/1]).
-
--include_lib("kernel/include/file.hrl").
-
--record(progress, {
- file :: string() | 'undefined',
- cb_module :: module(),
- cb_function :: atom(),
- init_progress_term :: term(),
- current_progress_term :: term()
- }).
-
-%%%=========================================================================
-%%% Internal application API
-%%%=========================================================================
-%%--------------------------------------------------------------------------
-%% start_link(Options) -> ignore | pid()
-%% Options = ignore | {CBModule, CBFunction, InitProgressTerm}
-%%
-%% Description: Starts the progress report process unless progress reporting
-%% should not be performed.
-%%--------------------------------------------------------------------------
--type options() :: 'ignore' | {module(), atom(), term()}.
--spec start_link(options()) -> 'ignore' | pid().
-start_link(ignore) ->
- ignore;
-start_link(Options) ->
- spawn_link(?MODULE, init, [Options]).
-
-%%--------------------------------------------------------------------------
-%% report_progress(Pid, Report) -> ok
-%% Pid = pid()
-%% Report = {local_file, File} | {remote_file, File} |
-%% {transfer_size, Size}
-%% Size = integer()
-%%
-%% Description: Reports progress to the reporting process that calls the
-%% user defined callback function.
-%%--------------------------------------------------------------------------
--type report() :: {'local_file', string()} | {'remote_file', string()}
- | {'transfer_size', non_neg_integer()}.
--spec report(pid(), report()) -> 'ok'.
-report(Pid, Report) ->
- Pid ! {progress_report, Report},
- ok.
-
-%%--------------------------------------------------------------------------
-%% stop(Pid) -> ok
-%% Pid = pid()
-%%
-%% Description:
-%%--------------------------------------------------------------------------
--spec stop(pid()) -> 'ok'.
-stop(Pid) ->
- Pid ! stop,
- ok.
-
-%%%=========================================================================
-%%% Internal functions
-%%%=========================================================================
-init(Options) ->
- loop(progress(Options)).
-
-loop(Progress) ->
- receive
- {progress_report, Report} ->
- NewProgress = report_progress(Report, Progress),
- loop(NewProgress);
- stop ->
- ok
- end.
-
-progress({CBModule, CBFunction, InitProgressTerm}) when is_atom(CBModule),
- is_atom(CBFunction) ->
- #progress{cb_module = CBModule,
- cb_function = CBFunction,
- init_progress_term = InitProgressTerm,
- current_progress_term = InitProgressTerm}.
-
-report_progress({local_file, File}, Progress) ->
- {ok, FileInfo} = file:read_file_info(File),
- report_progress({file_size, FileInfo#file_info.size},
- Progress#progress{file = File});
-
-report_progress({remote_file, File}, Progress) ->
- report_progress({file_size, unknown}, Progress#progress{file = File});
-
-report_progress(Size, #progress{file = File,
- cb_module = CBModule,
- cb_function = CBFunction,
- current_progress_term = Term,
- init_progress_term = InitTerm} = Progress) ->
-
- NewProgressTerm = CBModule:CBFunction(Term, File, Size),
-
- case Size of
- {transfer_size, 0} ->
- %% Transfer is compleat reset initial values
- Progress#progress{current_progress_term = InitTerm,
- file = undefined};
- _ ->
- Progress#progress{current_progress_term = NewProgressTerm}
- end.
diff --git a/lib/inets/src/ftp/ftp_response.erl b/lib/inets/src/ftp/ftp_response.erl
deleted file mode 100644
index d54d97dc91..0000000000
--- a/lib/inets/src/ftp/ftp_response.erl
+++ /dev/null
@@ -1,203 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%% Description: This module impements handling of ftp server responses.
-
--module(ftp_response).
-
-%% Internal API
--export([parse_lines/3, interpret/1, error_string/1]).
-
--include("ftp_internal.hrl").
-
-%% First group of reply code digits
--define(POS_PREL, 1).
--define(POS_COMPL, 2).
--define(POS_INTERM, 3).
--define(TRANS_NEG_COMPL, 4).
--define(PERM_NEG_COMPL, 5).
-%% Second group of reply code digits
--define(SYNTAX,0).
--define(INFORMATION,1).
--define(CONNECTION,2).
--define(AUTH_ACC,3).
--define(UNSPEC,4).
--define(FILE_SYSTEM,5).
-
-%%%=========================================================================
-%%% INTERNAL API
-%%%=========================================================================
-
-%%--------------------------------------------------------------------------
-%% parse_lines(Data, AccLines, StatusCode) -> {ok, Lines} |
-%% {continue, {Data,
-%% AccLines, StatusCode}}
-%%
-%% Data = binary() - data recived on the control connection from the
-%% ftp-server.
-%% AccLines = [string()]
-%% StatusCode = start | {byte(), byte(), byte()} | finish -
-%% Indicates where in the parsing process we are.
-%% start - (looking for the status code of the message)
-%% {byte(), byte(), byte()} - status code found, now
-%% looking for the last line indication.
-%% finish - now on the last line.
-%% Description: Parses a ftp control response message.
-%% "A reply is defined to contain the 3-digit code, followed by Space
-%% <SP>, followed by one line of text (where some maximum line length
-%% has been specified), and terminated by the Telnet end-of-line
-%% code (CRLF), or a so called multilined reply for example:
-%%
-%% 123-First line
-%% Second line
-%% 234 A line beginning with numbers
-%% 123 The last line
-%%
-%% The user-process then simply needs to search for the second
-%% occurrence of the same reply code, followed by <SP> (Space), at
-%% the beginning of a line, and ignore all intermediary lines. If
-%% an intermediary line begins with a 3-digit number, the Server
-%% will pad the front to avoid confusion.
-%%--------------------------------------------------------------------------
-
-%% Make sure we received the first 4 bytes so we know how to parse
-%% the FTP server response e.i. is the response composed of one
-%% or multiple lines.
-parse_lines(Bin, Lines, start) when size(Bin) < 4 ->
- {continue, {Bin, Lines, start}};
-%% Multiple lines exist
-parse_lines(<<C1, C2, C3, $-, Rest/binary>>, Lines, start) ->
- parse_lines(Rest, [$-, C3, C2, C1 | Lines], {C1, C2, C3});
-%% Only one line exists
-parse_lines(<<C1, C2, C3, ?WHITE_SPACE, Bin/binary>>, Lines, start) ->
- parse_lines(Bin, [?WHITE_SPACE, C3, C2, C1 | Lines], finish);
-
-%% Last line found
-parse_lines(<<?CR, ?LF, C1, C2, C3, ?WHITE_SPACE, Rest/binary>>, Lines, {C1, C2, C3}) ->
- parse_lines(Rest, [?WHITE_SPACE, C3, C2, C1, ?LF, ?CR | Lines], finish);
-%% Potential end found wait for more data
-parse_lines(<<?CR, ?LF, C1, C2, C3>> = Bin, Lines, {C1, C2, C3}) ->
- {continue, {Bin, Lines, {C1, C2, C3}}};
-%% Intermidate line begining with status code
-parse_lines(<<?CR, ?LF, C1, C2, C3, Rest/binary>>, Lines, {C1, C2, C3}) ->
- parse_lines(Rest, [C3, C2, C1, ?LF, ?CR | Lines], {C1, C2, C3});
-
-%% Potential last line wait for more data
-parse_lines(<<?CR, ?LF, C1, C2>> = Data, Lines, {C1, C2, _} = StatusCode) ->
- {continue, {Data, Lines, StatusCode}};
-parse_lines(<<?CR, ?LF, C1>> = Data, Lines, {C1, _, _} = StatusCode) ->
- {continue, {Data, Lines, StatusCode}};
-parse_lines(<<?CR, ?LF>> = Data, Lines, {_,_,_} = StatusCode) ->
- {continue, {Data, Lines, StatusCode}};
-parse_lines(<<?LF>> = Data, Lines, {_,_,_} = StatusCode) ->
- {continue, {Data, Lines, StatusCode}};
-parse_lines(<<>> = Data, Lines, {_,_,_} = StatusCode) ->
- {continue, {Data, Lines, StatusCode}};
-%% Part of the multiple lines
-parse_lines(<<Octet, Rest/binary>>, Lines, {_,_, _} = StatusCode) ->
- parse_lines(Rest, [Octet | Lines], StatusCode);
-
-%% End of FTP server response found
-parse_lines(<<?CR, ?LF>>, Lines, finish) ->
- {ok, lists:reverse([?LF, ?CR | Lines]), <<>>};
-parse_lines(<<?CR, ?LF, Rest/binary>>, Lines, finish) ->
- {ok, lists:reverse([?LF, ?CR | Lines]), Rest};
-
-%% Potential end found wait for more data
-parse_lines(<<?CR>> = Data, Lines, finish) ->
- {continue, {Data, Lines, finish}};
-parse_lines(<<>> = Data, Lines, finish) ->
- {continue, {Data, Lines, finish}};
-%% Part of last line
-parse_lines(<<Octet, Rest/binary>>, Lines, finish) ->
- parse_lines(Rest, [Octet | Lines], finish).
-
-%%--------------------------------------------------------------------------
-%% interpret(Lines) -> {Status, Text}
-%% Lines = [byte(), byte(), byte() | Text] - ftp server response as
-%% returned by parse_lines/3
-%% Stauts = atom() (see interpret_status/3)
-%% Text = [string()]
-%%
-%% Description: Create nicer data to match on.
-%%--------------------------------------------------------------------------
-interpret([Didgit1, Didgit2, Didgit3 | Data]) ->
- Code1 = Didgit1 - $0,
- Code2 = Didgit2 - $0,
- Code3 = Didgit3 - $0,
- {interpret_status(Code1, Code2, Code3), Data}.
-
-%%--------------------------------------------------------------------------
-%% error_string(Error) -> string()
-%% Error = {error, term()} | term()
-%%
-%% Description: Translates error codes into strings intended for
-%% human interpretation.
-%%--------------------------------------------------------------------------
-error_string({error, Reason}) ->
- error_string(Reason);
-
-error_string(echunk) -> "Synchronisation error during chunk sending.";
-error_string(eclosed) -> "Session has been closed.";
-error_string(econn) -> "Connection to remote server prematurely closed.";
-error_string(eexists) ->"File or directory already exists.";
-error_string(ehost) -> "Host not found, FTP server not found, "
- "or connection rejected.";
-error_string(elogin) -> "User not logged in.";
-error_string(enotbinary) -> "Term is not a binary.";
-error_string(epath) -> "No such file or directory, already exists, "
- "or permission denied.";
-error_string(etype) -> "No such type.";
-error_string(euser) -> "User name or password not valid.";
-error_string(etnospc) -> "Insufficient storage space in system.";
-error_string(enofile) -> "No files found or file unavailable";
-error_string(epnospc) -> "Exceeded storage allocation "
- "(for current directory or dataset).";
-error_string(efnamena) -> "File name not allowed.";
-error_string(Reason) ->
- lists:flatten(io_lib:format("Unknown error: ~w", [Reason])).
-
-%%%========================================================================
-%%% Internal functions
-%%%========================================================================
-
-%% Positive Preleminary Reply
-interpret_status(?POS_PREL,_,_) -> pos_prel;
-%%FIXME ??? 3??? interpret_status(?POS_COMPL, ?AUTH_ACC, 3) -> tls_upgrade;
-interpret_status(?POS_COMPL, ?AUTH_ACC, 4) -> tls_upgrade;
-%% Positive Completion Reply
-interpret_status(?POS_COMPL,_,_) -> pos_compl;
-%% Positive Intermediate Reply nedd account
-interpret_status(?POS_INTERM,?AUTH_ACC,2) -> pos_interm_acct;
-%% Positive Intermediate Reply
-interpret_status(?POS_INTERM,_,_) -> pos_interm;
-%% No files found or file not available
-interpret_status(?TRANS_NEG_COMPL,?FILE_SYSTEM,0) -> enofile;
-%% No storage area no action taken
-interpret_status(?TRANS_NEG_COMPL,?FILE_SYSTEM,2) -> etnospc;
-%% Temporary Error, no action taken
-interpret_status(?TRANS_NEG_COMPL,_,_) -> trans_neg_compl;
-%% Permanent disk space error, the user shall not try again
-interpret_status(?PERM_NEG_COMPL,?FILE_SYSTEM,0) -> epath;
-interpret_status(?PERM_NEG_COMPL,?FILE_SYSTEM,2) -> epnospc;
-interpret_status(?PERM_NEG_COMPL,?FILE_SYSTEM,3) -> efnamena;
-interpret_status(?PERM_NEG_COMPL,?AUTH_ACC,0) -> elogin;
-interpret_status(?PERM_NEG_COMPL,_,_) -> perm_neg_compl.
-
diff --git a/lib/inets/src/ftp/ftp_sup.erl b/lib/inets/src/ftp/ftp_sup.erl
deleted file mode 100644
index 21dcfb6ab2..0000000000
--- a/lib/inets/src/ftp/ftp_sup.erl
+++ /dev/null
@@ -1,60 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% Purpose: The top supervisor for the ftp hangs under inets_sup.
-%%----------------------------------------------------------------------
--module(ftp_sup).
-
--behaviour(supervisor).
-
-%% API
--export([start_link/0]).
--export([start_child/1]).
-
-%% Supervisor callback
--export([init/1]).
-
-%%%=========================================================================
-%%% API
-%%%=========================================================================
-start_link() ->
- supervisor:start_link({local, ?MODULE}, ?MODULE, []).
-
-start_child(Args) ->
- supervisor:start_child(?MODULE, Args).
-
-%%%=========================================================================
-%%% Supervisor callback
-%%%=========================================================================
-init(_) ->
- RestartStrategy = simple_one_for_one,
- MaxR = 0,
- MaxT = 3600,
-
- Name = undefined, % As simple_one_for_one is used.
- StartFunc = {ftp, start_link, []},
- Restart = temporary, % E.g. should not be restarted
- Shutdown = 4000,
- Modules = [ftp],
- Type = worker,
-
- ChildSpec = {Name, StartFunc, Restart, Shutdown, Type, Modules},
- {ok, {{RestartStrategy, MaxR, MaxT}, [ChildSpec]}}.
diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl
index dd493d7554..24a205ced9 100644
--- a/lib/inets/src/http_client/httpc.erl
+++ b/lib/inets/src/http_client/httpc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -176,10 +176,10 @@ request(Method,
(Method =:= delete) orelse
(Method =:= trace) andalso
(is_atom(Profile) orelse is_pid(Profile)) ->
- case uri_parse(Url, Options) of
- {error, Reason} ->
+ case uri_string:parse(uri_string:normalize(Url)) of
+ {error, Reason, _} ->
{error, Reason};
- {ok, ParsedUrl} ->
+ ParsedUrl ->
case header_parse(Headers) of
{error, Reason} ->
{error, Reason};
@@ -190,10 +190,10 @@ request(Method,
end.
do_request(Method, {Url, Headers, ContentType, Body}, HTTPOptions, Options, Profile) ->
- case uri_parse(Url, Options) of
- {error, Reason} ->
+ case uri_string:parse(uri_string:normalize(Url)) of
+ {error, Reason, _} ->
{error, Reason};
- {ok, ParsedUrl} ->
+ ParsedUrl ->
handle_request(Method, Url,
ParsedUrl, Headers, ContentType, Body,
HTTPOptions, Options, Profile)
@@ -313,23 +313,28 @@ store_cookies(SetCookieHeaders, Url) ->
store_cookies(SetCookieHeaders, Url, Profile)
when is_atom(Profile) orelse is_pid(Profile) ->
- try
- begin
+ case uri_string:parse(uri_string:normalize(Url)) of
+ {error, Bad, _} ->
+ {error, {parse_failed, Bad}};
+ URI ->
+ Scheme = scheme_to_atom(maps:get(scheme, URI, '')),
+ Host = maps:get(host, URI, ""),
+ Port = maps:get(port, URI, default_port(Scheme)),
+ Path = uri_string:recompose(#{path => maps:get(path, URI, "")}),
%% Since the Address part is not actually used
%% by the manager when storing cookies, we dont
%% care about ipv6-host-with-brackets.
- {ok, {_, _, Host, Port, Path, _}} = uri_parse(Url),
Address = {Host, Port},
ProfileName = profile_name(Profile),
Cookies = httpc_cookie:cookies(SetCookieHeaders, Path, Host),
httpc_manager:store_cookies(Cookies, Address, ProfileName),
ok
- end
- catch
- error:{badmatch, Bad} ->
- {error, {parse_failed, Bad}}
end.
+default_port(http) ->
+ 80;
+default_port(https) ->
+ 443.
%%--------------------------------------------------------------------------
%% cookie_header(Url) -> Header | {error, Reason}
@@ -496,7 +501,7 @@ service_info(Pid) ->
%%% Internal functions
%%%========================================================================
handle_request(Method, Url,
- {Scheme, UserInfo, Host, Port, Path, Query},
+ URI,
Headers0, ContentType, Body0,
HTTPOptions0, Options0, Profile) ->
@@ -521,39 +526,42 @@ handle_request(Method, Url,
throw({error, {bad_body, Body0}})
end,
- HTTPOptions = http_options(HTTPOptions0),
- Options = request_options(Options0),
- Sync = proplists:get_value(sync, Options),
- Stream = proplists:get_value(stream, Options),
- Host2 = http_request:normalize_host(Scheme, Host, Port),
- HeadersRecord = header_record(NewHeaders, Host2, HTTPOptions),
- Receiver = proplists:get_value(receiver, Options),
- SocketOpts = proplists:get_value(socket_opts, Options),
+ HTTPOptions = http_options(HTTPOptions0),
+ Options = request_options(Options0),
+ Sync = proplists:get_value(sync, Options),
+ Stream = proplists:get_value(stream, Options),
+ Receiver = proplists:get_value(receiver, Options),
+ SocketOpts = proplists:get_value(socket_opts, Options),
UnixSocket = proplists:get_value(unix_socket, Options),
- BracketedHost = proplists:get_value(ipv6_host_with_brackets,
- Options),
- MaybeEscPath = maybe_encode_uri(HTTPOptions, Path),
- MaybeEscQuery = maybe_encode_uri(HTTPOptions, Query),
- AbsUri = maybe_encode_uri(HTTPOptions, Url),
+ BracketedHost = proplists:get_value(ipv6_host_with_brackets,
+ Options),
+
+ Scheme = scheme_to_atom(maps:get(scheme, URI, '')),
+ Userinfo = maps:get(userinfo, URI, ""),
+ Host = http_util:maybe_add_brackets(maps:get(host, URI, ""), BracketedHost),
+ Port = maps:get(port, URI, default_port(Scheme)),
+ Host2 = http_request:normalize_host(Scheme, Host, Port),
+ Path = uri_string:recompose(#{path => maps:get(path, URI, "")}),
+ Query = add_question_mark(maps:get(query, URI, "")),
+ HeadersRecord = header_record(NewHeaders, Host2, HTTPOptions),
Request = #request{from = Receiver,
- scheme = Scheme,
- address = {host_address(Host, BracketedHost), Port},
- path = MaybeEscPath,
- pquery = MaybeEscQuery,
+ scheme = Scheme,
+ address = {Host, Port},
+ path = Path,
+ pquery = Query,
method = Method,
headers = HeadersRecord,
content = {ContentType, Body},
settings = HTTPOptions,
- abs_uri = AbsUri,
- userinfo = UserInfo,
+ abs_uri = Url,
+ userinfo = Userinfo,
stream = Stream,
headers_as_is = headers_as_is(Headers0, Options),
socket_opts = SocketOpts,
started = Started,
unix_socket = UnixSocket,
ipv6_host_with_brackets = BracketedHost},
-
case httpc_manager:request(Request, profile_name(Profile)) of
{ok, RequestId} ->
handle_answer(RequestId, Sync, Options);
@@ -568,14 +576,31 @@ handle_request(Method, Url,
Error
end.
+
+add_question_mark(<<>>) ->
+ <<>>;
+add_question_mark([]) ->
+ [];
+add_question_mark(Comp) when is_binary(Comp) ->
+ <<$?, Comp/binary>>;
+add_question_mark(Comp) when is_list(Comp) ->
+ [$?|Comp].
+
+
+scheme_to_atom("http") ->
+ http;
+scheme_to_atom("https") ->
+ https;
+scheme_to_atom('') ->
+ '';
+scheme_to_atom(Scheme) ->
+ throw({error, {bad_scheme, Scheme}}).
+
+
ensure_chunked_encoding(Hdrs) ->
Key = "transfer-encoding",
lists:keystore(Key, 1, Hdrs, {Key, "chunked"}).
-maybe_encode_uri(#http_options{url_encode = true}, URI) ->
- http_uri:encode(URI);
-maybe_encode_uri(_, URI) ->
- URI.
mk_chunkify_fun(ProcessBody) ->
fun(eof_body) ->
@@ -1232,17 +1257,6 @@ validate_headers(RequestHeaders, _, _) ->
%% These functions is just simple wrappers to parse specifically HTTP URIs
%%--------------------------------------------------------------------------
-scheme_defaults() ->
- [{http, 80}, {https, 443}].
-
-uri_parse(URI) ->
- http_uri:parse(URI, [{scheme_defaults, scheme_defaults()}]).
-
-uri_parse(URI, Opts) ->
- http_uri:parse(URI, [{scheme_defaults, scheme_defaults()} | Opts]).
-
-
-%%--------------------------------------------------------------------------
header_parse([]) ->
ok;
header_parse([{Field, Value}|T]) when is_list(Field), is_list(Value) ->
@@ -1263,10 +1277,6 @@ child_name(Pid, [{Name, Pid} | _]) ->
child_name(Pid, [_ | Children]) ->
child_name(Pid, Children).
-host_address(Host, false) ->
- Host;
-host_address(Host, true) ->
- string:strip(string:strip(Host, right, $]), left, $[).
check_body_gen({Fun, _}) when is_function(Fun) ->
ok;
diff --git a/lib/inets/src/http_client/httpc_cookie.erl b/lib/inets/src/http_client/httpc_cookie.erl
index cbf428ab3e..2e647a1438 100644
--- a/lib/inets/src/http_client/httpc_cookie.erl
+++ b/lib/inets/src/http_client/httpc_cookie.erl
@@ -271,7 +271,7 @@ lookup_cookies(CookieDb, Host, Path) ->
lookup_domain_cookies(_CookieDb, [], AccCookies) ->
lists:flatten(AccCookies);
-%% Top domains can not have cookies
+%% Top domains cannot have cookies
lookup_domain_cookies(_CookieDb, [_], AccCookies) ->
lists:flatten(AccCookies);
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl
index 26e4f4e699..8d443a1477 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -48,19 +48,17 @@
queue_timer :: reference() | 'undefined'
}).
--type session_failed() :: {'connect_failed',term()} | {'send_failed',term()}.
-
-record(state,
{
request :: request() | 'undefined',
- session :: session() | session_failed() | 'undefined',
+ session :: session() | 'undefined',
status_line, % {Version, StatusCode, ReasonPharse}
headers :: http_response_h() | 'undefined',
body :: binary() | 'undefined',
mfa, % {Module, Function, Args}
pipeline = queue:new() :: queue:queue(),
keep_alive = queue:new() :: queue:queue(),
- status, % undefined | new | pipeline | keep_alive | close | {ssl_tunnel, Request}
+ status :: undefined | new | pipeline | keep_alive | close | {ssl_tunnel, request()},
canceled = [], % [RequestId]
max_header_size = nolimit :: nolimit | integer(),
max_body_size = nolimit :: nolimit | integer(),
@@ -255,8 +253,8 @@ handle_call(Request, From, State) ->
Result ->
Result
catch
- _:Reason ->
- {stop, {shutdown, Reason} , State}
+ Class:Reason:ST ->
+ {stop, {shutdown, {{Class, Reason}, ST}}, State}
end.
@@ -271,8 +269,8 @@ handle_cast(Msg, State) ->
Result ->
Result
catch
- _:Reason ->
- {stop, {shutdown, Reason} , State}
+ Class:Reason:ST ->
+ {stop, {shutdown, {{Class, Reason}, ST}}, State}
end.
%%--------------------------------------------------------------------
@@ -286,8 +284,8 @@ handle_info(Info, State) ->
Result ->
Result
catch
- _:Reason ->
- {stop, {shutdown, Reason} , State}
+ Class:Reason:ST ->
+ {stop, {shutdown, {{Class, Reason}, ST}}, State}
end.
%%--------------------------------------------------------------------
@@ -295,23 +293,6 @@ handle_info(Info, State) ->
%% Description: Shutdown the httpc_handler
%%--------------------------------------------------------------------
-%% Init error there is no socket to be closed.
-terminate(normal,
- #state{request = Request,
- session = {send_failed, _} = Reason} = State) ->
- maybe_send_answer(Request,
- httpc_response:error(Request, Reason),
- State),
- ok;
-
-terminate(normal,
- #state{request = Request,
- session = {connect_failed, _} = Reason} = State) ->
- maybe_send_answer(Request,
- httpc_response:error(Request, Reason),
- State),
- ok;
-
terminate(normal, #state{session = undefined}) ->
ok;
@@ -588,11 +569,11 @@ do_handle_info({Proto, _Socket, Data},
activate_once(Session),
{noreply, State#state{mfa = NewMFA}}
catch
- _:Reason ->
+ Class:Reason:ST ->
ClientReason = {could_not_parse_as_http, Data},
ClientErrMsg = httpc_response:error(Request, ClientReason),
NewState = answer_request(Request, ClientErrMsg, State),
- {stop, {shutdown, Reason}, NewState}
+ {stop, {shutdown, {{Class, Reason}, ST}}, NewState}
end;
do_handle_info({Proto, Socket, Data},
@@ -828,7 +809,7 @@ connect_and_send_first_request(Address, Request, #state{options = Options0} = St
SocketType = socket_type(Request),
ConnTimeout = (Request#request.settings)#http_options.connect_timeout,
Options = handle_unix_socket_options(Request, Options0),
- case connect(SocketType, Address, Options, ConnTimeout) of
+ case connect(SocketType, format_address(Address), Options, ConnTimeout) of
{ok, Socket} ->
ClientClose =
httpc_request:is_client_closing(
@@ -858,7 +839,7 @@ connect_and_send_first_request(Address, Request, #state{options = Options0} = St
self() ! {init_error, error_sending,
httpc_response:error(Request, Reason)},
{ok, State#state{request = Request,
- session = #session{socket = Socket}}}
+ session = Session}}
end;
{error, Reason} ->
self() ! {init_error, error_connecting,
@@ -980,13 +961,23 @@ handle_http_body(_, #state{status = {ssl_tunnel, Request},
NewState = answer_request(Request, ClientErrMsg, State),
{stop, normal, NewState};
-handle_http_body(<<>>, #state{status_line = {_,304, _}} = State) ->
+%% All 1xx (informational), 204 (no content), and 304 (not modified)
+%% responses MUST NOT include a message-body, and thus are always
+%% terminated by the first empty line after the header fields.
+%% This implies that chunked encoding MUST NOT be used for these
+%% status codes.
+handle_http_body(<<>>, #state{headers = Headers,
+ status_line = {_,StatusCode, _}} = State)
+ when Headers#http_response_h.'transfer-encoding' =/= "chunked" andalso
+ (StatusCode =:= 204 orelse %% No Content
+ StatusCode =:= 304 orelse %% Not Modified
+ 100 =< StatusCode andalso StatusCode =< 199) -> %% Informational
handle_response(State#state{body = <<>>});
-handle_http_body(<<>>, #state{status_line = {_,204, _}} = State) ->
- handle_response(State#state{body = <<>>});
-handle_http_body(<<>>, #state{request = #request{method = head}} = State) ->
+handle_http_body(<<>>, #state{headers = Headers,
+ request = #request{method = head}} = State)
+ when Headers#http_response_h.'transfer-encoding' =/= "chunked" ->
handle_response(State#state{body = <<>>});
handle_http_body(Body, #state{headers = Headers,
@@ -1058,15 +1049,15 @@ handle_response(#state{status = new} = State) ->
?hcrd("handle response - status = new", []),
handle_response(try_to_enable_pipeline_or_keep_alive(State));
-handle_response(#state{request = Request,
- status = Status,
- session = Session,
- status_line = StatusLine,
- headers = Headers,
- body = Body,
- options = Options,
- profile_name = ProfileName} = State)
- when Status =/= new ->
+handle_response(#state{status = Status0} = State0) when Status0 =/= new ->
+ State = handle_server_closing(State0),
+ #state{request = Request,
+ session = Session,
+ status_line = StatusLine,
+ headers = Headers,
+ body = Body,
+ options = Options,
+ profile_name = ProfileName} = State,
handle_cookies(Headers, Request, Options, ProfileName),
case httpc_response:result({StatusLine, Headers, Body}, Request) of
%% 100-continue
@@ -1330,6 +1321,14 @@ try_to_enable_pipeline_or_keep_alive(
State#state{status = close}
end.
+handle_server_closing(State = #state{status = close}) -> State;
+handle_server_closing(State = #state{headers = undefined}) -> State;
+handle_server_closing(State = #state{headers = Headers}) ->
+ case httpc_response:is_server_closing(Headers) of
+ true -> State#state{status = close};
+ false -> State
+ end.
+
answer_request(#request{id = RequestId, from = From} = Request, Msg,
#state{session = Session,
timers = Timers,
@@ -1711,9 +1710,8 @@ update_session(ProfileName, #session{id = SessionId} = Session, Pos, Value) ->
insert_session(Session2, ProfileName);
error:badarg ->
{stop, normal};
- T:E ->
+ T:E:Stacktrace ->
%% Unexpected this must be an error!
- Stacktrace = erlang:get_stacktrace(),
error_logger:error_msg("Failed updating session: "
"~n ProfileName: ~p"
"~n SessionId: ~p"
@@ -1740,4 +1738,8 @@ update_session(ProfileName, #session{id = SessionId} = Session, Pos, Value) ->
{stacktrace, Stacktrace}]}}
end.
-
+format_address({[$[|T], Port}) ->
+ {ok, Address} = inet:parse_address(string:strip(T, right, $])),
+ {Address, Port};
+format_address(HostPort) ->
+ HostPort.
diff --git a/lib/inets/src/http_client/httpc_internal.hrl b/lib/inets/src/http_client/httpc_internal.hrl
index c5fe439722..a14d8aa71b 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-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl
index 7b8d7875de..0dc0483fa9 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-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -750,8 +750,26 @@ handle_request(#request{settings =
start_handler(NewRequest#request{headers = NewHeaders}, State),
{reply, {ok, NewRequest#request.id}, State};
-handle_request(Request, State = #state{options = Options}) ->
+%% Simple socket options handling (ERL-441).
+%%
+%% TODO: Refactor httpc to enable sending socket options in requests
+%% using persistent connections. This workaround opens a new
+%% connection for each request with non-empty socket_opts.
+handle_request(Request0 = #request{socket_opts = SocketOpts},
+ State0 = #state{options = Options0})
+ when is_list(SocketOpts) andalso length(SocketOpts) > 0 ->
+ Request = handle_cookies(generate_request_id(Request0), State0),
+ Options = convert_options(SocketOpts, Options0),
+ State = State0#state{options = Options},
+ Headers =
+ (Request#request.headers)#http_request_h{connection
+ = "close"},
+ %% Reset socket_opts to avoid setopts failure.
+ start_handler(Request#request{headers = Headers, socket_opts = []}, State),
+ %% Do not change the state
+ {reply, {ok, Request#request.id}, State0};
+handle_request(Request, State = #state{options = Options}) ->
NewRequest = handle_cookies(generate_request_id(Request), State),
SessionType = session_type(Options),
case select_session(Request#request.method,
@@ -775,6 +793,18 @@ handle_request(Request, State = #state{options = Options}) ->
{reply, {ok, NewRequest#request.id}, State}.
+%% Convert Request options to State options
+convert_options([], Options) ->
+ Options;
+convert_options([{ipfamily, Value}|T], Options) ->
+ convert_options(T, Options#options{ipfamily = Value});
+convert_options([{ip, Value}|T], Options) ->
+ convert_options(T, Options#options{ip = Value});
+convert_options([{port, Value}|T], Options) ->
+ convert_options(T, Options#options{port = Value});
+convert_options([Option|T], Options = #options{socket_opts = SocketOpts}) ->
+ convert_options(T, Options#options{socket_opts = SocketOpts ++ [Option]}).
+
start_handler(#request{id = Id,
from = From} = Request,
#state{profile_name = ProfileName,
@@ -833,7 +863,7 @@ select_session(Candidates, _, Max, pipeline) ->
select_session(Candidates, Max).
select_session([] = _Candidates, _Max) ->
- ?hcrd("select session - no candicate", []),
+ ?hcrd("select session - no candidate", []),
no_connection;
select_session(Candidates, Max) ->
NewCandidates =
diff --git a/lib/inets/src/http_client/httpc_request.erl b/lib/inets/src/http_client/httpc_request.erl
index 89872a3831..0f20d93bc1 100644
--- a/lib/inets/src/http_client/httpc_request.erl
+++ b/lib/inets/src/http_client/httpc_request.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -190,35 +190,11 @@ is_client_closing(Headers) ->
%%%========================================================================
post_data(Method, Headers, {ContentType, Body}, HeadersAsIs)
when (Method =:= post)
- orelse (Method =:= put)
- orelse (Method =:= patch)
- orelse (Method =:= delete) ->
-
- NewBody = case Headers#http_request_h.expect of
- "100-continue" ->
- "";
- _ ->
- Body
- end,
-
- NewHeaders = case HeadersAsIs of
- [] ->
- Headers#http_request_h{
- 'content-type' = ContentType,
- 'content-length' = case body_length(Body) of
- undefined ->
- % on upload streaming the caller must give a
- % value to the Content-Length header
- % (or use chunked Transfer-Encoding)
- Headers#http_request_h.'content-length';
- Len when is_list(Len) ->
- Len
- end
- };
- _ ->
- HeadersAsIs
- end,
-
+ orelse (Method =:= put)
+ orelse (Method =:= patch)
+ orelse (Method =:= delete) ->
+ NewBody = update_body(Headers, Body),
+ NewHeaders = update_headers(Headers, ContentType, Body, HeadersAsIs),
{NewHeaders, NewBody};
post_data(_, Headers, _, []) ->
@@ -226,14 +202,56 @@ post_data(_, Headers, _, []) ->
post_data(_, _, _, HeadersAsIs = [_|_]) ->
{HeadersAsIs, ""}.
+update_body(Headers, Body) ->
+ case Headers#http_request_h.expect of
+ "100-continue" ->
+ "";
+ _ ->
+ Body
+ end.
+
+update_headers(Headers, ContentType, Body, []) ->
+ case Body of
+ [] ->
+ Headers1 = Headers#http_request_h{'content-length' = "0"},
+ handle_content_type(Headers1, ContentType);
+ <<>> ->
+ Headers1 = Headers#http_request_h{'content-length' = "0"},
+ handle_content_type(Headers1, ContentType);
+ {Fun, _Acc} when is_function(Fun, 1) ->
+ %% A client MUST NOT generate a 100-continue expectation in a request
+ %% that does not include a message body. This implies that either the
+ %% Content-Length or the Transfer-Encoding header MUST be present.
+ %% DO NOT send content-type when Body is empty.
+ Headers1 = Headers#http_request_h{'content-type' = ContentType},
+ handle_transfer_encoding(Headers1);
+ _ ->
+ Headers#http_request_h{
+ 'content-length' = body_length(Body),
+ 'content-type' = ContentType}
+ end;
+update_headers(_, _, _, HeadersAsIs) ->
+ HeadersAsIs.
+
+handle_transfer_encoding(Headers = #http_request_h{'transfer-encoding' = undefined}) ->
+ Headers;
+handle_transfer_encoding(Headers) ->
+ %% RFC7230 3.3.2
+ %% A sender MUST NOT send a 'Content-Length' header field in any message
+ %% that contains a 'Transfer-Encoding' header field.
+ Headers#http_request_h{'content-length' = undefined}.
+
body_length(Body) when is_binary(Body) ->
integer_to_list(size(Body));
body_length(Body) when is_list(Body) ->
- integer_to_list(length(Body));
+ integer_to_list(length(Body)).
-body_length({DataFun, _Acc}) when is_function(DataFun, 1) ->
- undefined.
+%% Set 'Content-Type' when it is explicitly set.
+handle_content_type(Headers, "") ->
+ Headers;
+handle_content_type(Headers, ContentType) ->
+ Headers#http_request_h{'content-type' = ContentType}.
method(Method) ->
http_util:to_upper(atom_to_list(Method)).
diff --git a/lib/inets/src/http_client/httpc_response.erl b/lib/inets/src/http_client/httpc_response.erl
index 91638f5d2e..bb6b76da89 100644
--- a/lib/inets/src/http_client/httpc_response.erl
+++ b/lib/inets/src/http_client/httpc_response.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -83,7 +83,6 @@ whole_body(Body, Length) ->
%% result(Response, Request) ->
%% Response - {StatusLine, Headers, Body}
%% Request - #request{}
-%% Session - #tcp_session{}
%%
%% Description: Checks the status code ...
%%-------------------------------------------------------------------------
@@ -190,7 +189,7 @@ parse_status_code(<<?CR, ?LF, Rest/binary>>, StatusCodeStr,
MaxHeaderSize, Result, true) ->
parse_headers(Rest, [], [], MaxHeaderSize,
[" ", list_to_integer(lists:reverse(
- string:strip(StatusCodeStr)))
+ string:trim(StatusCodeStr)))
| Result], true);
parse_status_code(<<?SP, Rest/binary>>, StatusCodeStr,
@@ -377,58 +376,180 @@ status_server_error_50x(Response, Request) ->
{stop, {Request#request.id, Msg}}.
-redirect(Response = {StatusLine, Headers, Body}, Request) ->
+redirect(Response = {_, Headers, _}, Request) ->
{_, Data} = format_response(Response),
case Headers#http_response_h.location of
- undefined ->
- transparent(Response, Request);
- RedirUrl ->
- UrlParseOpts = [{ipv6_host_with_brackets,
- Request#request.ipv6_host_with_brackets}],
- case uri_parse(RedirUrl, UrlParseOpts) of
- {error, no_scheme} when
- (Request#request.settings)#http_options.relaxed ->
- NewLocation = fix_relative_uri(Request, RedirUrl),
- redirect({StatusLine, Headers#http_response_h{
- location = NewLocation},
- Body}, Request);
- {error, Reason} ->
- {ok, error(Request, Reason), Data};
- %% Automatic redirection
- {ok, {Scheme, _, Host, Port, Path, Query}} ->
- HostPort = http_request:normalize_host(Scheme, Host, Port),
- NewHeaders =
- (Request#request.headers)#http_request_h{host = HostPort},
- NewRequest =
- Request#request{redircount =
- Request#request.redircount+1,
- scheme = Scheme,
- headers = NewHeaders,
- address = {Host,Port},
- path = Path,
- pquery = Query,
- abs_uri =
- atom_to_list(Scheme) ++ "://" ++
- Host ++ ":" ++
- integer_to_list(Port) ++
- Path ++ Query},
- {redirect, NewRequest, Data}
- end
+ undefined ->
+ transparent(Response, Request);
+ RedirUrl ->
+ Brackets = Request#request.ipv6_host_with_brackets,
+ case uri_string:parse(RedirUrl) of
+ {error, Reason, _} ->
+ {ok, error(Request, Reason), Data};
+ %% Automatic redirection
+ URI ->
+ {Host, Port0} = Request#request.address,
+ Port = maybe_to_integer(Port0),
+ Path = Request#request.path,
+ Scheme = atom_to_list(Request#request.scheme),
+ Query = Request#request.pquery,
+ URIMap = resolve_uri(Scheme, Host, Port, Path, Query, URI),
+ TScheme = list_to_atom(maps:get(scheme, URIMap)),
+ THost = http_util:maybe_add_brackets(maps:get(host, URIMap), Brackets),
+ TPort = maps:get(port, URIMap),
+ TPath = maps:get(path, URIMap),
+ TQuery = add_question_mark(maps:get(query, URIMap, "")),
+ NewURI = uri_string:normalize(
+ uri_string:recompose(URIMap)),
+ HostPort = http_request:normalize_host(TScheme, THost, TPort),
+ NewHeaders =
+ (Request#request.headers)#http_request_h{host = HostPort},
+ NewRequest =
+ Request#request{redircount =
+ Request#request.redircount+1,
+ scheme = TScheme,
+ headers = NewHeaders,
+ address = {THost,TPort},
+ path = TPath,
+ pquery = TQuery,
+ abs_uri = NewURI},
+ {redirect, NewRequest, Data}
+ end
+ end.
+
+add_question_mark(<<>>) ->
+ <<>>;
+add_question_mark([]) ->
+ [];
+add_question_mark(Comp) when is_binary(Comp) ->
+ <<$?, Comp/binary>>;
+add_question_mark(Comp) when is_list(Comp) ->
+ [$?|Comp].
+
+%% RFC3986 - 5.2.2. Transform References
+resolve_uri(Scheme, Host, Port, Path, Query, URI) ->
+ resolve_uri(Scheme, Host, Port, Path, Query, URI, #{}).
+%%
+resolve_uri(Scheme, Host, Port, Path, Query, URI, Map0) ->
+ case maps:get(scheme, URI, undefined) of
+ undefined ->
+ Port0 = get_port(Scheme, URI),
+ Map = Map0#{scheme => Scheme,
+ port => Port0},
+ resolve_authority(Host, Port, Path, Query, URI, Map);
+ URIScheme ->
+ Port0 = get_port(URIScheme, URI),
+ maybe_add_query(
+ Map0#{scheme => URIScheme,
+ host => maps:get(host, URI),
+ port => Port0,
+ path => maps:get(path, URI)},
+ URI)
+ end.
+
+
+get_port(Scheme, URI) ->
+ case maps:get(port, URI, undefined) of
+ undefined ->
+ get_default_port(Scheme);
+ Port ->
+ Port
end.
-maybe_to_list(Port) when is_integer(Port) ->
- integer_to_list(Port);
-maybe_to_list(Port) when is_list(Port) ->
+
+get_default_port("http") ->
+ 80;
+get_default_port("https") ->
+ 443.
+
+
+resolve_authority(Host, Port, Path, Query, RelURI, Map) ->
+ case maps:is_key(host, RelURI) of
+ true ->
+ maybe_add_query(
+ Map#{host => maps:get(host, RelURI),
+ path => maps:get(path, RelURI)},
+ RelURI);
+ false ->
+ Map1 = Map#{host => Host,
+ port => Port},
+ resolve_path(Path, Query, RelURI, Map1)
+ end.
+
+
+maybe_add_query(Map, RelURI) ->
+ case maps:is_key(query, RelURI) of
+ true ->
+ Map#{query => maps:get(query, RelURI)};
+ false ->
+ Map
+ end.
+
+
+resolve_path(Path, Query, RelURI, Map) ->
+ case maps:is_key(path, RelURI) of
+ true ->
+ Path1 = calculate_path(Path, maps:get(path, RelURI)),
+ maybe_add_query(
+ Map#{path => Path1},
+ RelURI);
+ false ->
+ Map1 = Map#{path => Path},
+ resolve_query(Query, RelURI, Map1)
+ end.
+
+
+calculate_path(BaseP, RelP) ->
+ case starts_with_slash(RelP) of
+ true ->
+ RelP;
+ false ->
+ merge_paths(BaseP, RelP)
+ end.
+
+
+starts_with_slash([$/|_]) ->
+ true;
+starts_with_slash(<<$/,_/binary>>) ->
+ true;
+starts_with_slash(_) ->
+ false.
+
+
+%% RFC3986 - 5.2.3. Merge Paths
+merge_paths("", RelP) ->
+ [$/|RelP];
+merge_paths(BaseP, RelP) when is_list(BaseP) ->
+ do_merge_paths(lists:reverse(BaseP), RelP);
+merge_paths(BaseP, RelP) when is_binary(BaseP) ->
+ B = binary_to_list(BaseP),
+ R = binary_to_list(RelP),
+ Res = merge_paths(B, R),
+ list_to_binary(Res).
+
+
+do_merge_paths([$/|_] = L, RelP) ->
+ lists:reverse(L) ++ RelP;
+do_merge_paths([_|T], RelP) ->
+ do_merge_paths(T, RelP).
+
+
+resolve_query(Query, RelURI, Map) ->
+ case maps:is_key(query, RelURI) of
+ true ->
+ Map#{query => maps:get(query, RelURI)};
+ false ->
+ Map#{query => Query}
+ end.
+
+
+maybe_to_integer(Port) when is_list(Port) ->
+ {Port1, _} = string:to_integer(Port),
+ Port1;
+maybe_to_integer(Port) when is_integer(Port) ->
Port.
-%%% Guessing that we received a relative URI, fix it to become an absoluteURI
-fix_relative_uri(Request, RedirUrl) ->
- {Server, Port0} = Request#request.address,
- Port = maybe_to_list(Port0),
- Path = Request#request.path,
- atom_to_list(Request#request.scheme) ++ "://" ++ Server ++ ":" ++ Port
- ++ Path ++ RedirUrl.
-
+
error(#request{id = Id}, Reason) ->
{Id, {error, Reason}}.
@@ -478,18 +599,3 @@ format_response({StatusLine, Headers, Body}) ->
{Body, <<>>}
end,
{{StatusLine, http_response:header_list(Headers), NewBody}, Data}.
-
-%%--------------------------------------------------------------------------
-%% These functions is just simple wrappers to parse specifically HTTP URIs
-%%--------------------------------------------------------------------------
-
-scheme_defaults() ->
- [{http, 80}, {https, 443}].
-
-uri_parse(URI, Opts) ->
- http_uri:parse(URI, [{scheme_defaults, scheme_defaults()} | Opts]).
-
-
-%%--------------------------------------------------------------------------
-
-
diff --git a/lib/inets/src/http_lib/http_request.erl b/lib/inets/src/http_lib/http_request.erl
index f68b233e10..2b1a0bd40f 100644
--- a/lib/inets/src/http_lib/http_request.erl
+++ b/lib/inets/src/http_lib/http_request.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -27,10 +27,12 @@
key_value(KeyValueStr) ->
case lists:splitwith(fun($:) -> false; (_) -> true end, KeyValueStr) of
- {Key, [$: | Value]} ->
+ {Key, [$: | Value]} when Key =/= [] ->
{http_util:to_lower(string:strip(Key)), string:strip(Value)};
{_, []} ->
- undefined
+ undefined;
+ _ ->
+ undefined
end.
%%-------------------------------------------------------------------------
%% headers(HeaderList, #http_request_h{}) -> #http_request_h{}
diff --git a/lib/inets/src/http_lib/http_uri.erl b/lib/inets/src/http_lib/http_uri.erl
index d02913121c..6805b0293d 100644
--- a/lib/inets/src/http_lib/http_uri.erl
+++ b/lib/inets/src/http_lib/http_uri.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -197,7 +197,7 @@ extract_scheme(Str, Opts) ->
{value, {scheme_validation_fun, Fun}} when is_function(Fun) ->
case Fun(Str) of
valid ->
- {ok, list_to_atom(http_util:to_lower(Str))};
+ {ok, to_atom(http_util:to_lower(Str))};
{error, Error} ->
{error, Error}
end;
diff --git a/lib/inets/src/http_lib/http_util.erl b/lib/inets/src/http_lib/http_util.erl
index 487d04f7aa..5577b00cc8 100644
--- a/lib/inets/src/http_lib/http_util.erl
+++ b/lib/inets/src/http_lib/http_util.erl
@@ -27,7 +27,8 @@
convert_month/1,
is_hostname/1,
timestamp/0, timeout/2,
- html_encode/1
+ html_encode/1,
+ maybe_add_brackets/2
]).
@@ -194,6 +195,24 @@ html_encode(Chars) ->
lists:append([char_to_html_entity(Char, Reserved) || Char <- Chars]).
+maybe_add_brackets(Addr, false) ->
+ Addr;
+maybe_add_brackets(Addr, true) when is_list(Addr) ->
+ case is_ipv6_address(Addr) of
+ true ->
+ [$[|Addr] ++ "]";
+ false ->
+ Addr
+ end;
+maybe_add_brackets(Addr, true) when is_binary(Addr) ->
+ case is_ipv6_address(Addr) of
+ true ->
+ <<$[,Addr/binary,$]>>;
+ false ->
+ Addr
+ end.
+
+
%%%========================================================================
%%% Internal functions
%%%========================================================================
@@ -205,3 +224,14 @@ char_to_html_entity(Char, Reserved) ->
false ->
[Char]
end.
+
+is_ipv6_address(Addr) when is_binary(Addr) ->
+ B = binary_to_list(Addr),
+ is_ipv6_address(B);
+is_ipv6_address(Addr) when is_list(Addr) ->
+ case inet:parse_ipv6strict_address(Addr) of
+ {ok, _ } ->
+ true;
+ {error, _} ->
+ false
+ end.
diff --git a/lib/inets/src/http_server/httpd.erl b/lib/inets/src/http_server/httpd.erl
index 540e68e749..f4b53ce129 100644
--- a/lib/inets/src/http_server/httpd.erl
+++ b/lib/inets/src/http_server/httpd.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -36,7 +36,13 @@
]).
%% API
--export([parse_query/1, reload_config/2, info/1, info/2, info/3]).
+-export([
+ parse_query/1,
+ reload_config/2,
+ info/1,
+ info/2,
+ info/3
+ ]).
%%%========================================================================
%%% API
@@ -49,13 +55,24 @@ parse_query(String) ->
reload_config(Config = [Value| _], Mode) when is_tuple(Value) ->
do_reload_config(Config, Mode);
reload_config(ConfigFile, Mode) ->
- case httpd_conf:load(ConfigFile) of
- {ok, ConfigList} ->
- do_reload_config(ConfigList, Mode);
- Error ->
- Error
+ try file:consult(ConfigFile) of
+ {ok, [PropList]} ->
+ %% Erlang terms format
+ do_reload_config(PropList, Mode);
+ {error, _ } ->
+ %% Apache format
+ case httpd_conf:load(ConfigFile) of
+ {ok, ConfigList} ->
+ do_reload_config(ConfigList, Mode);
+ Error ->
+ Error
+ end
+ catch
+ exit:_ ->
+ throw({error, {could_not_consult_proplist_file, ConfigFile}})
end.
+
info(Pid) when is_pid(Pid) ->
info(Pid, []).
diff --git a/lib/inets/src/http_server/httpd_esi.erl b/lib/inets/src/http_server/httpd_esi.erl
index f5493f6fad..3b66b86348 100644
--- a/lib/inets/src/http_server/httpd_esi.erl
+++ b/lib/inets/src/http_server/httpd_esi.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/src/http_server/httpd_example.erl b/lib/inets/src/http_server/httpd_example.erl
index 47a8c48d01..aaa7e428c2 100644
--- a/lib/inets/src/http_server/httpd_example.erl
+++ b/lib/inets/src/http_server/httpd_example.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -22,9 +22,9 @@
-export([print/1]).
-export([get/2, put/2, post/2, yahoo/2, test1/2, get_bin/2, peer/2,new_status_and_location/2]).
--export([newformat/3, post_chunked/3]).
+-export([newformat/3, post_chunked/3, post_204/3]).
%% These are used by the inets test-suite
--export([delay/1, chunk_timeout/3]).
+-export([delay/1, chunk_timeout/3, get_chunks/3]).
print(String) ->
@@ -151,6 +151,12 @@ post_chunked(SessionID, _Env, {last, _Body, undefined} = _Bodychunk) ->
post_chunked(_, _, _Body) ->
exit(body_not_chunked).
+post_204(SessionID, _Env, _Input) ->
+ mod_esi:deliver(SessionID,
+ ["Status: 204 No Content" ++ "\r\n\r\n"]),
+ mod_esi:deliver(SessionID, []).
+
+
newformat(SessionID,_,_) ->
mod_esi:deliver(SessionID, "Content-Type:text/html\r\n\r\n"),
mod_esi:deliver(SessionID, top("new esi format test")),
@@ -190,3 +196,22 @@ chunk_timeout(SessionID, _, _StrInt) ->
mod_esi:deliver(SessionID, top("Test chunk encoding timeout")),
timer:sleep(20000),
mod_esi:deliver(SessionID, footer()).
+
+get_chunks(Sid, _Env, In) ->
+ Tokens = string:tokens(In, [$&]),
+ PropList = lists:map(fun(E) ->
+ list_to_tuple(string:tokens(E,[$=])) end,
+ Tokens),
+ HeaderDelay =
+ list_to_integer(proplists:get_value("header_delay", PropList, "0")),
+ ChunkDelay =
+ list_to_integer(proplists:get_value("chunk_delay", PropList, "0")),
+ BadChunkDelay =
+ list_to_integer(proplists:get_value("bad_chunk_delay", PropList, "0")),
+ timer:sleep(HeaderDelay),
+ mod_esi:deliver(Sid, ["Content-Type: text/plain\r\n\r\n"]),
+ mod_esi:deliver(Sid, "Chunk 0 ms\r\n"),
+ timer:sleep(ChunkDelay),
+ mod_esi:deliver(Sid, io_lib:format("Chunk ~p ms\r\n", [ChunkDelay])),
+ timer:sleep(ChunkDelay + BadChunkDelay),
+ mod_esi:deliver(Sid, "BAD Chunk\r\n").
diff --git a/lib/inets/src/http_server/httpd_file.erl b/lib/inets/src/http_server/httpd_file.erl
index 4d419172d0..bf7554bd08 100644
--- a/lib/inets/src/http_server/httpd_file.erl
+++ b/lib/inets/src/http_server/httpd_file.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -33,6 +33,9 @@ handle_error(enoent, Op, ModData, Path) ->
handle_error(enotdir, Op, ModData, Path) ->
handle_error(404, Op, ModData, Path,
": A component of the file name is not a directory");
+handle_error(eisdir, Op, ModData, Path) ->
+ handle_error(403, Op, ModData, Path,
+ ":Ilegal operation expected a file not a directory");
handle_error(emfile, Op, _ModData, Path) ->
handle_error(500, Op, none, Path, ": Too many open files");
handle_error({enfile,_}, Op, _ModData, Path) ->
diff --git a/lib/inets/src/http_server/httpd_request.erl b/lib/inets/src/http_server/httpd_request.erl
index 007d272323..9d7538a13d 100644
--- a/lib/inets/src/http_server/httpd_request.erl
+++ b/lib/inets/src/http_server/httpd_request.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -259,17 +259,17 @@ parse_headers(<<?LF, Octet, Rest/binary>>, Header, Headers, Current, Max,
%% If ?CR is is missing RFC2616 section-19.3
parse_headers(<<?CR,?LF, Octet, Rest/binary>>, Header, Headers, Current, Max,
Options, Result);
-parse_headers(<<?CR,?LF, Octet, Rest/binary>>, Header, Headers, _, Max,
+parse_headers(<<?CR,?LF, Octet, Rest/binary>>, Header, Headers, Current, Max,
Options, Result) ->
case http_request:key_value(lists:reverse(Header)) of
undefined -> %% Skip headers with missing :
parse_headers(Rest, [Octet], Headers,
- 0, Max, Options, Result);
+ Current, Max, Options, Result);
NewHeader ->
case check_header(NewHeader, Options) of
ok ->
parse_headers(Rest, [Octet], [NewHeader | Headers],
- 0, Max, Options, Result);
+ Current, Max, Options, Result);
{error, Reason} ->
HttpVersion = lists:nth(3, lists:reverse(Result)),
{error, Reason, HttpVersion}
diff --git a/lib/inets/src/http_server/httpd_response.erl b/lib/inets/src/http_server/httpd_response.erl
index 6b9053fda6..bb946664f9 100644
--- a/lib/inets/src/http_server/httpd_response.erl
+++ b/lib/inets/src/http_server/httpd_response.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -61,8 +61,12 @@ generate_and_send_response(#mod{config_db = ConfigDB} = ModData) ->
{StatusCode, Response} -> %% Old way
send_response_old(ModData, StatusCode, Response),
ok;
- undefined ->
- send_status(ModData, 500, none),
+ undefined ->
+ %% Happens when no mod_*
+ %% handles the request
+ send_status(ModData, 501, {ModData#mod.method,
+ ModData#mod.request_uri,
+ ModData#mod.http_version}),
ok
end
end
@@ -84,14 +88,14 @@ traverse_modules(ModData,[Module|Rest]) ->
{proceed, NewData} ->
traverse_modules(ModData#mod{data = NewData}, Rest)
catch
- T:E ->
+ T:E:Stacktrace ->
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()])),
+ [Module, T, E, Stacktrace])),
httpd_util:error_log(ModData#mod.config_db, String),
send_status(ModData, 500, none),
done
diff --git a/lib/inets/src/http_server/httpd_script_env.erl b/lib/inets/src/http_server/httpd_script_env.erl
index d7c92c59ef..055edca211 100644
--- a/lib/inets/src/http_server/httpd_script_env.erl
+++ b/lib/inets/src/http_server/httpd_script_env.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/src/http_server/mod_alias.erl b/lib/inets/src/http_server/mod_alias.erl
index 0333076546..68a3de0229 100644
--- a/lib/inets/src/http_server/mod_alias.erl
+++ b/lib/inets/src/http_server/mod_alias.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -163,28 +163,24 @@ longest_match([], _RequestURI, _LongestNo, LongestAlias) ->
real_script_name(_ConfigDB, _RequestURI, []) ->
not_a_script;
-
-real_script_name(ConfigDB, RequestURI, [{MP,Replacement} | Rest])
- when element(1, MP) =:= re_pattern ->
- case re:run(RequestURI, MP, [{capture, none}]) of
- match ->
- ActualName =
- re:replace(RequestURI, MP, Replacement, [{return,list}]),
- httpd_util:split_script_path(default_index(ConfigDB, ActualName));
- nomatch ->
- real_script_name(ConfigDB, RequestURI, Rest)
- end;
-
real_script_name(ConfigDB, RequestURI, [{FakeName,RealName} | Rest]) ->
case re:run(RequestURI, "^" ++ FakeName, [{capture, none}]) of
match ->
- ActualName =
+ ActualName0 =
re:replace(RequestURI, "^" ++ FakeName, RealName, [{return,list}]),
+ ActualName = abs_script_path(ConfigDB, ActualName0),
httpd_util:split_script_path(default_index(ConfigDB, ActualName));
nomatch ->
real_script_name(ConfigDB, RequestURI, Rest)
end.
+%% ERL-574: relative path in script_alias property results in malformed url
+abs_script_path(ConfigDB, [$.|_] = RelPath) ->
+ Root = httpd_util:lookup(ConfigDB, server_root),
+ Root ++ "/" ++ RelPath;
+abs_script_path(_, RelPath) ->
+ RelPath.
+
%% default_index
default_index(ConfigDB, Path) ->
diff --git a/lib/inets/src/http_server/mod_disk_log.erl b/lib/inets/src/http_server/mod_disk_log.erl
index 2023546f01..190cf91416 100644
--- a/lib/inets/src/http_server/mod_disk_log.erl
+++ b/lib/inets/src/http_server/mod_disk_log.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/src/http_server/mod_esi.erl b/lib/inets/src/http_server/mod_esi.erl
index 3206d957d9..8cbd9798e6 100644
--- a/lib/inets/src/http_server/mod_esi.erl
+++ b/lib/inets/src/http_server/mod_esi.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -33,7 +33,7 @@
-include("httpd_internal.hrl").
-define(VMODULE,"ESI").
--define(DEFAULT_ERL_TIMEOUT,15000).
+-define(DEFAULT_ERL_TIMEOUT,15).
%%%=========================================================================
@@ -119,7 +119,7 @@ load("EvalScriptAlias " ++ EvalScriptAlias, []) ->
load("ErlScriptTimeout " ++ Timeout, [])->
case catch list_to_integer(string:strip(Timeout)) of
TimeoutSec when is_integer(TimeoutSec) ->
- {ok, [], {erl_script_timeout, TimeoutSec * 1000}};
+ {ok, [], {erl_script_timeout, TimeoutSec}};
_ ->
{error, ?NICE(string:strip(Timeout) ++
" is an invalid ErlScriptTimeout")}
@@ -174,7 +174,7 @@ store({erl_script_alias, Value}, _) ->
{error, {wrong_type, {erl_script_alias, Value}}};
store({erl_script_timeout, TimeoutSec}, _)
when is_integer(TimeoutSec) andalso (TimeoutSec >= 0) ->
- {ok, {erl_script_timeout, TimeoutSec * 1000}};
+ {ok, {erl_script_timeout, TimeoutSec}};
store({erl_script_timeout, Value}, _) ->
{error, {wrong_type, {erl_script_timeout, Value}}};
store({erl_script_nocache, Value} = Conf, _)
@@ -394,7 +394,16 @@ deliver_webpage_chunk(#mod{config_db = Db} = ModData, Pid, Timeout) ->
Continue;
{Headers, Body} ->
{ok, NewHeaders, StatusCode} = httpd_esi:handle_headers(Headers),
- IsDisableChunkedSend = httpd_response:is_disable_chunked_send(Db),
+ %% All 1xx (informational), 204 (no content), and 304 (not modified)
+ %% responses MUST NOT include a message-body, and thus are always
+ %% terminated by the first empty line after the header fields.
+ %% This implies that chunked encoding MUST NOT be used for these
+ %% status codes.
+ IsDisableChunkedSend =
+ httpd_response:is_disable_chunked_send(Db) orelse
+ StatusCode =:= 204 orelse %% No Content
+ StatusCode =:= 304 orelse %% Not Modified
+ (100 =< StatusCode andalso StatusCode =< 199), %% Informational
case (ModData#mod.http_version =/= "HTTP/1.1") or
(IsDisableChunkedSend) of
true ->
@@ -405,8 +414,8 @@ deliver_webpage_chunk(#mod{config_db = Db} = ModData, Pid, Timeout) ->
send_headers(ModData, StatusCode,
[{"transfer-encoding",
"chunked"} | NewHeaders])
- end,
- handle_body(Pid, ModData, Body, Timeout, length(Body),
+ end,
+ handle_body(Pid, ModData, Body, Timeout, length(Body),
IsDisableChunkedSend);
timeout ->
send_headers(ModData, 504, [{"connection", "close"}]),
@@ -491,7 +500,7 @@ kill_esi_delivery_process(Pid) ->
erl_script_timeout(Db) ->
- httpd_util:lookup(Db, erl_script_timeout, ?DEFAULT_ERL_TIMEOUT).
+ httpd_util:lookup(Db, erl_script_timeout, ?DEFAULT_ERL_TIMEOUT) * 1000.
script_elements(FuncAndInput, Input) ->
case input_type(FuncAndInput) of
@@ -561,7 +570,7 @@ eval(#mod{method = Method} = ModData, ESIBody, Modules)
end.
generate_webpage(ESIBody) ->
- (catch lib:eval_str(string:concat(ESIBody,". "))).
+ (catch erl_eval:eval_str(string:concat(ESIBody,". "))).
is_authorized(_ESIBody, [all]) ->
true;
diff --git a/lib/inets/src/http_server/mod_log.erl b/lib/inets/src/http_server/mod_log.erl
index ec570504be..0323918578 100644
--- a/lib/inets/src/http_server/mod_log.erl
+++ b/lib/inets/src/http_server/mod_log.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/src/http_server/mod_responsecontrol.erl b/lib/inets/src/http_server/mod_responsecontrol.erl
index 07129940a5..a32ba65c22 100644
--- a/lib/inets/src/http_server/mod_responsecontrol.erl
+++ b/lib/inets/src/http_server/mod_responsecontrol.erl
@@ -71,7 +71,7 @@ do_responsecontrol(Info) ->
%% If a client sends more then one of the if-XXXX fields in a request
-%% The standard says it does not specify the behaviuor so I specified it :-)
+%% The standard says it does not specify the behaviour so I specified it :-)
%% The priority between the fields is
%% 1.If-modified
%% 2.If-Unmodified
diff --git a/lib/inets/src/inets_app/Makefile b/lib/inets/src/inets_app/Makefile
index eb0098dbee..ec1ae70305 100644
--- a/lib/inets/src/inets_app/Makefile
+++ b/lib/inets/src/inets_app/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2005-2016. All Rights Reserved.
+# Copyright Ericsson AB 2005-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -48,7 +48,9 @@ MODULES = \
inets_app \
inets_sup \
inets_trace \
- inets_lib
+ inets_lib \
+ inets_ftp_wrapper \
+ inets_tftp_wrapper
INTERNAL_HRL_FILES = inets_internal.hrl
EXTERNAL_HRL_FILES = ../../include/httpd.hrl \
diff --git a/lib/inets/src/inets_app/inets.app.src b/lib/inets/src/inets_app/inets.app.src
index eb4be932ac..e5780b2a4c 100644
--- a/lib/inets/src/inets_app/inets.app.src
+++ b/lib/inets/src/inets_app/inets.app.src
@@ -1,7 +1,7 @@
%% This is an -*- erlang -*- file.
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -30,10 +30,7 @@
inets_lib,
%% FTP
- ftp,
- ftp_progress,
- ftp_response,
- ftp_sup,
+ inets_ftp_wrapper,
%% HTTP client:
httpc,
@@ -101,17 +98,11 @@
mod_trace,
%% TFTP
- tftp,
- tftp_binary,
- tftp_engine,
- tftp_file,
- tftp_lib,
- tftp_logger,
- tftp_sup
+ inets_tftp_wrapper
]},
{registered,[inets_sup, httpc_manager]},
%% If the "new" ssl is used then 'crypto' must be started before inets.
{applications,[kernel,stdlib]},
{mod,{inets_app,[]}},
- {runtime_dependencies, ["stdlib-2.0","ssl-5.3.4","runtime_tools-1.8.14",
+ {runtime_dependencies, ["stdlib-3.5","ssl-5.3.4","runtime_tools-1.8.14",
"mnesia-4.12","kernel-3.0","erts-6.0"]}]}.
diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src
index a86413147c..b197590bfd 100644
--- a/lib/inets/src/inets_app/inets.appup.src
+++ b/lib/inets/src/inets_app/inets.appup.src
@@ -1,7 +1,7 @@
%% -*- erlang -*-
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,10 +18,12 @@
%% %CopyrightEnd%
{"%VSN%",
[
+ {<<"7\\..*">>,[{restart_application, inets}]},
{<<"6\\..*">>,[{restart_application, inets}]},
{<<"5\\..*">>,[{restart_application, inets}]}
],
[
+ {<<"7\\..*">>,[{restart_application, inets}]},
{<<"6\\..*">>,[{restart_application, inets}]},
{<<"5\\..*">>,[{restart_application, inets}]}
]
diff --git a/lib/inets/src/inets_app/inets.erl b/lib/inets/src/inets_app/inets.erl
index 2d380012d7..ab2bc5b784 100644
--- a/lib/inets/src/inets_app/inets.erl
+++ b/lib/inets/src/inets_app/inets.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -465,13 +465,19 @@ call_service(Service, Call, Args) ->
exit:{noproc, _} ->
{error, inets_not_started}
end.
-
+
+%% Obsolete! Kept for backward compatiblity!
+%% TFTP application has been moved out from inets
service_module(tftpd) ->
- tftp;
+ inets_tftp_wrapper;
service_module(tftpc) ->
- tftp;
+ inets_tftp_wrapper;
+service_module(tftp) ->
+ inets_tftp_wrapper;
+%% Obsolete! Kept for backward compatiblity!
+%% FTP application has been moved out from inets
service_module(ftpc) ->
- ftp;
+ inets_ftp_wrapper;
service_module(Service) ->
Service.
diff --git a/lib/inets/src/inets_app/inets_ftp_wrapper.erl b/lib/inets/src/inets_app/inets_ftp_wrapper.erl
new file mode 100644
index 0000000000..e350a490f7
--- /dev/null
+++ b/lib/inets/src/inets_app/inets_ftp_wrapper.erl
@@ -0,0 +1,48 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(inets_ftp_wrapper).
+
+
+-export([start_standalone/1,
+ start_service/1,
+ stop_service/1,
+ services/0,
+ service_info/1]).
+
+
+start_standalone(Options) ->
+ ftp:start_standalone(Options).
+
+
+start_service(Options) ->
+ application:ensure_started(ftp),
+ ftp:start_service(Options).
+
+
+stop_service(Pid) ->
+ ftp:stop_service(Pid).
+
+
+services() ->
+ [].
+
+
+service_info(_) ->
+ [].
diff --git a/lib/inets/src/inets_app/inets_internal.hrl b/lib/inets/src/inets_app/inets_internal.hrl
index 079b415b56..38b7e68638 100644
--- a/lib/inets/src/inets_app/inets_internal.hrl
+++ b/lib/inets/src/inets_app/inets_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -22,8 +22,6 @@
-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/src/inets_app/inets_sup.erl b/lib/inets/src/inets_app/inets_sup.erl
index d8ae7eff26..0d3c7475fc 100644
--- a/lib/inets/src/inets_app/inets_sup.erl
+++ b/lib/inets/src/inets_app/inets_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -61,19 +61,7 @@ children() ->
Services = get_services(),
HttpdServices = [Service || Service <- Services, is_httpd(Service)],
HttpcServices = [Service || Service <- Services, is_httpc(Service)],
- TftpdServices = [Service || Service <- Services, is_tftpd(Service)],
- [ftp_child_spec(), httpc_child_spec(HttpcServices),
- httpd_child_spec(HttpdServices), tftpd_child_spec(TftpdServices)].
-
-ftp_child_spec() ->
- Name = ftp_sup,
- StartFunc = {ftp_sup, start_link, []},
- Restart = permanent,
- Shutdown = infinity,
- Modules = [ftp_sup],
- Type = supervisor,
- {Name, StartFunc, Restart, Shutdown, Type, Modules}.
-
+ [httpc_child_spec(HttpcServices), httpd_child_spec(HttpdServices)].
httpc_child_spec(HttpcServices0) ->
HttpcServices = default_profile(HttpcServices0, []),
@@ -94,15 +82,6 @@ httpd_child_spec(HttpdServices) ->
Type = supervisor,
{Name, StartFunc, Restart, Shutdown, Type, Modules}.
-tftpd_child_spec(TftpServices) ->
- Name = tftp_sup,
- StartFunc = {tftp_sup, start_link, [TftpServices]},
- Restart = permanent,
- Shutdown = infinity,
- Modules = [tftp_sup],
- Type = supervisor,
- {Name, StartFunc, Restart, Shutdown, Type, Modules}.
-
is_httpd({httpd, _}) ->
true;
is_httpd({httpd, _, _}) ->
@@ -115,11 +94,6 @@ is_httpc({httpc, _}) ->
is_httpc(_) ->
false.
-is_tftpd({tftpd, _}) ->
- true;
-is_tftpd(_) ->
- false.
-
default_profile([], Acc) ->
[{httpc, {default, only_session_cookies}} | Acc];
default_profile([{httpc, {default, _}} | _] = Profiles, Acc) ->
diff --git a/lib/inets/src/inets_app/inets_tftp_wrapper.erl b/lib/inets/src/inets_app/inets_tftp_wrapper.erl
new file mode 100644
index 0000000000..1e5deb234b
--- /dev/null
+++ b/lib/inets/src/inets_app/inets_tftp_wrapper.erl
@@ -0,0 +1,48 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(inets_tftp_wrapper).
+
+
+-export([start_standalone/1,
+ start_service/1,
+ stop_service/1,
+ services/0,
+ service_info/1]).
+
+
+start_standalone(Options) ->
+ tftp:start_standalone(Options).
+
+
+start_service(Options) ->
+ application:ensure_started(tftp),
+ tftp:start_service(Options).
+
+
+stop_service(Pid) ->
+ tftp:stop_service(Pid).
+
+
+services() ->
+ [].
+
+
+service_info(_) ->
+ [].
diff --git a/lib/inets/src/subdirs.mk b/lib/inets/src/subdirs.mk
index 9f2a0079f2..e9f4de959c 100644
--- a/lib/inets/src/subdirs.mk
+++ b/lib/inets/src/subdirs.mk
@@ -1,3 +1,3 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SUB_DIRECTORIES = inets_app http_lib http_client http_server ftp tftp
+SUB_DIRECTORIES = inets_app http_lib http_client http_server
diff --git a/lib/inets/src/tftp/Makefile b/lib/inets/src/tftp/Makefile
deleted file mode 100644
index 4eaa959cce..0000000000
--- a/lib/inets/src/tftp/Makefile
+++ /dev/null
@@ -1,109 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2005-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-
-include $(ERL_TOP)/make/target.mk
-EBIN = ../../ebin
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../../vsn.mk
-
-VSN = $(INETS_VSN)
-
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
-
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-BEHAVIOUR_MODULES= \
- tftp
-
-MODULES = \
- tftp_binary \
- tftp_engine \
- tftp_file \
- tftp_lib \
- tftp_logger \
- tftp_sup
-
-HRL_FILES = tftp.hrl
-
-ERL_FILES= \
- $(MODULES:%=%.erl) \
- $(BEHAVIOUR_MODULES:%=%.erl)
-
-TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-
-BEHAVIOUR_TARGET_FILES= $(BEHAVIOUR_MODULES:%=$(EBIN)/%.$(EMULATOR))
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-
-include ../inets_app/inets.mk
-
-ERL_COMPILE_FLAGS += \
- $(INETS_FLAGS) \
- $(INETS_ERL_COMPILE_FLAGS) \
- -I../../include \
- -I../inets_app
-
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-$(TARGET_FILES): $(BEHAVIOUR_TARGET_FILES)
-
-debug opt: $(TARGET_FILES)
-
-clean:
- rm -f $(TARGET_FILES) $(BEHAVIOUR_TARGET_FILES)
- rm -f core
-
-docs:
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/src"
- $(INSTALL_DIR) "$(RELSYSDIR)/src/tftp"
- $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) "$(RELSYSDIR)/src/tftp"
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGET_FILES) $(BEHAVIOUR_TARGET_FILES) "$(RELSYSDIR)/ebin"
-
-release_docs_spec:
-
-info:
- @echo "APPLICATION = $(APPLICATION)"
- @echo "INETS_DEBUG = $(INETS_DEBUG)"
- @echo "INETS_FLAGS = $(INETS_FLAGS)"
- @echo "ERL_COMPILE_FLAGS = $(ERL_COMPILE_FLAGS)"
diff --git a/lib/inets/src/tftp/tftp.erl b/lib/inets/src/tftp/tftp.erl
deleted file mode 100644
index c8804ea55f..0000000000
--- a/lib/inets/src/tftp/tftp.erl
+++ /dev/null
@@ -1,398 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
-%%%-------------------------------------------------------------------
-%%% File : tftp.erl
-%%% Author : Hakan Mattsson <[email protected]>
-%%% Description : Trivial FTP
-%%% Created : 18 May 2004 by Hakan Mattsson <[email protected]>
-%%%-------------------------------------------------------------------
-%%%
-%%% This is a complete implementation of the following IETF standards:
-%%%
-%%% RFC 1350, The TFTP Protocol (revision 2).
-%%% RFC 2347, TFTP Option Extension.
-%%% RFC 2348, TFTP Blocksize Option.
-%%% RFC 2349, TFTP Timeout Interval and Transfer Size Options.
-%%%
-%%% The only feature that not is implemented in this release is
-%%% the "netascii" transfer mode.
-%%%
-%%% The start/1 function starts a daemon process which, listens for
-%%% UDP packets on a port. When it receives a request for read or
-%%% write it spawns a temporary server process which handles the
-%%% actual transfer of the file. On the client side the read_file/3
-%%% and write_file/3 functions spawns a temporary client process which
-%%% establishes contact with a TFTP daemon and performs the actual
-%%% transfer of the file.
-%%%
-%%% Most of the options are common for both the client and the server
-%%% side, but some of them differs a little. Here are the available
-%%% options:
-%%%
-%%% {debug, Level}
-%%%
-%%% Level = none | error | warning brief | normal | verbose | all
-%%%
-%%% Controls the level of debug printouts. The default is none.
-%%%
-%%% {host, Host}
-%%%
-%%% The name or IP address of the host where the TFTP daemon
-%%% resides. This option is only used by the client. See
-%%% 'inet' about valid host names.
-%%%
-%%% {port, Port}
-%%%
-%%% Port = integer()
-%%%
-%%% The TFTP port where the daemon listens. It defaults to the
-%%% standardized number 69. On the server side it may sometimes
-%%% make sense to set it to 0, which means that the daemon just
-%%% will pick a free port (which is returned by the start/1
-%%% function).
-%%%
-%%% If a socket has somehow already has been connected, the
-%%% {udp, [{fd, integer()}]} option can be used to pass the
-%%% open file descriptor to gen_udp. This can be automated
-%%% a bit by using a command line argument stating the
-%%% prebound file descriptor number. For example, if the
-%%% Port is 69 and the file descriptor 22 has been opened by
-%%% setuid_socket_wrap. Then the command line argument
-%%% "-tftpd_69 22" will trigger the prebound file
-%%% descriptor 22 to be used instead of opening port 69.
-%%% The UDP option {udp, [{fd, 22}]} autmatically be added.
-%%% See init:get_argument/ about command line arguments and
-%%% gen_udp:open/2 about UDP options.
-%%%
-%%% {port_policy, Policy}
-%%%
-%%% Policy = random | Port | {range, MinPort, MaxPort}
-%%% Port = MinPort = MaxPort = integer()
-%%%
-%%% Policy for the selection of the temporary port which is used
-%%% by the server/client during the file transfer. It defaults to
-%%% 'random' which is the standardized policy. With this policy a
-%%% randomized free port used. A single port or a range of ports
-%%% can be useful if the protocol should pass thru a firewall.
-%%%
-%%% {prebound_fd, InitArgFlag}
-%%%
-%%% InitArgFlag = atom()
-%%%
-%%% If a socket has somehow already has been connected, the
-%%% {udp, [{fd, integer()}]} option can be used to pass the
-%%% open file descriptor to gen_udp.
-%%%
-%%% The prebound_fd option makes it possible to pass give the
-%%% file descriptor as a command line argument. The typical
-%%% usage is when used in conjunction with setuid_socket_wrap
-%%% to be able to open privileged sockets. For example if the
-%%% file descriptor 22 has been opened by setuid_socket_wrap
-%%% and you have choosen my_tftp_fd as init argument, the
-%%% command line should like this "erl -my_tftp_fd 22" and
-%%% FileDesc should be set to my_tftpd_fd. This would
-%%% automatically imply {fd, 22} to be set as UDP option.
-%%%
-%%% {udp, UdpOptions}
-%%%
-%%% Options to gen_udp:open/2.
-%%%
-%%% {use_tsize, Bool}
-%%%
-%%% Bool = boolean()
-%%%
-%%% Flag for automated usage of the "tsize" option. With this set
-%%% to true, the write_file/3 client will determine the filesize
-%%% and send it to the server as the standardized "tsize" option.
-%%% A read_file/3 client will just acquire filesize from the
-%%% server by sending a zero "tsize".
-%%%
-%%% {max_tsize, MaxTsize}
-%%%
-%%% MaxTsize = integer() | infinity
-%%%
-%%% Threshold for the maximal filesize in bytes. The transfer will
-%%% be aborted if the limit is exceeded. It defaults to
-%%% 'infinity'.
-%%%
-%%% {max_conn, MaxConn}
-%%%
-%%% MaxConn = integer() | infinity
-%%%
-%%% Threshold for the maximal number of active connections. The
-%%% daemon will reject the setup of new connections if the limit
-%%% is exceeded. It defaults to 'infinity'.
-%%%
-%%% {TftpKey, TftpVal}
-%%%
-%%% TftpKey = string()
-%%% TftpVal = string()
-%%%
-%%% The name and value of a TFTP option.
-%%%
-%%% {reject, Feature}
-%%%
-%%% Feature = Mode | TftpKey
-%%% Mode = read | write
-%%% TftpKey = string()
-%%%
-%%% Control which features that should be rejected.
-%%% This is mostly useful for the server as it may restrict
-%%% usage of certain TFTP options or read/write access.
-%%%
-%%% {callback, {RegExp, Module, State}}
-%%%
-%%% RegExp = string()
-%%% Module = atom()
-%%% State = term()
-%%%
-%%% Registration of a callback module. When a file is to be
-%%% transferred, its local filename will be matched to the
-%%% regular expressions of the registered callbacks. The first
-%%% matching callback will be used the during the transfer.The
-%%% callback module must implement the 'tftp' behaviour.
-%%%
-%%% On the server side the callback interaction starts with a
-%%% call to open/5 with the registered initial callback
-%%% state. open/5 is expected to open the (virtual) file. Then
-%%% either the read/1 or write/2 functions are invoked
-%%% repeatedly, once per transfererred block. At each function
-%%% call the state returned from the previous call is
-%%% obtained. When the last block has been encountered the read/1
-%%% or write/2 functions is expected to close the (virtual)
-%%% file.and return its last state. The abort/3 function is only
-%%% used in error situations. prepare/5 is not used on the server
-%%% side.
-%%%
-%%% On the client side the callback interaction is the same, but
-%%% it starts and ends a bit differently. It starts with a call
-%%% to prepare/5 with the same arguments as open/5
-%%% takes. prepare/5 is expected to validate the TFTP options,
-%%% suggested by the user and return the subset of them that it
-%%% accepts. Then the options is sent to the server which will
-%%% perform the same TFTP option negotiation procedure. The
-%%% options that are accepted by the server is forwarded to the
-%%% open/5 function on the client side. On the client side the
-%%% open/5 function must accept all option as is or reject the
-%%% transfer. Then the callback interaction follows the same
-%%% pattern as described above for the server side. When the last
-%%% block is encountered in read/1 or write/2 the returned stated
-%%% is forwarded to the user and returned from read_file/3 or
-%%% write_file/3.
-%%%-------------------------------------------------------------------
-
--module(tftp).
-
-%%-------------------------------------------------------------------
-%% Interface
-%%-------------------------------------------------------------------
-
-%% Public functions
--export([
- read_file/3,
- write_file/3,
- start/1,
- info/1,
- change_config/2,
- start/0
- ]).
-
-%% Application local functions
--export([
- start_standalone/1,
- start_service/1,
- stop_service/1,
- services/0,
- service_info/1
- ]).
-
-
--type peer() :: {PeerType :: inet | inet6,
- PeerHost :: inet:ip_address(),
- PeerPort :: port()}.
-
--type access() :: read | write.
-
--type options() :: [{Key :: string(), Value :: string()}].
-
--type error_code() :: undef | enoent | eacces | enospc |
- badop | eexist | baduser | badopt |
- integer().
-
--callback prepare(Peer :: peer(),
- Access :: access(),
- Filename :: file:name(),
- Mode :: string(),
- SuggestedOptions :: options(),
- InitialState :: [] | [{root_dir, string()}]) ->
- {ok, AcceptedOptions :: options(), NewState :: term()} |
- {error, {Code :: error_code(), string()}}.
-
--callback open(Peer :: peer(),
- Access :: access(),
- Filename :: file:name(),
- Mode :: string(),
- SuggestedOptions :: options(),
- State :: [] | [{root_dir, string()}] | term()) ->
- {ok, AcceptedOptions :: options(), NewState :: term()} |
- {error, {Code :: error_code(), string()}}.
-
--callback read(State :: term()) -> {more, binary(), NewState :: term()} |
- {last, binary(), integer()} |
- {error, {Code :: error_code(), string()}}.
-
--callback write(binary(), State :: term()) ->
- {more, NewState :: term()} |
- {last, FileSize :: integer()} |
- {error, {Code :: error_code(), string()}}.
-
--callback abort(Code :: error_code(), string(), State :: term()) -> 'ok'.
-
--include("tftp.hrl").
-
-
-%%-------------------------------------------------------------------
-%% read_file(RemoteFilename, LocalFilename, Options) ->
-%% {ok, LastCallbackState} | {error, Reason}
-%%
-%% RemoteFilename = string()
-%% LocalFilename = binary | string()
-%% Options = [option()]
-%% LastCallbackState = term()
-%% Reason = term()
-%%
-%% Reads a (virtual) file from a TFTP server
-%%
-%% If LocalFilename is the atom 'binary', tftp_binary will be used as
-%% callback module. It will concatenate all transferred blocks and
-%% return them as one single binary in the CallbackState.
-%%
-%% When LocalFilename is a string, it will be matched to the
-%% registered callback modules and hopefully one of them will be
-%% selected. By default, tftp_file will be used as callback module. It
-%% will write each transferred block to the file named
-%% LocalFilename. The number of transferred bytes will be returned as
-%% LastCallbackState.
-%%-------------------------------------------------------------------
-
-read_file(RemoteFilename, LocalFilename, Options) ->
- tftp_engine:client_start(read, RemoteFilename, LocalFilename, Options).
-
-%%-------------------------------------------------------------------
-%% write(RemoteFilename, LocalFilename, Options) ->
-%% {ok, LastCallbackState} | {error, Reason}
-%%
-%% RemoteFilename = string()
-%% LocalFilename = binary() | string()
-%% Options = [option()]
-%% LastCallbackState = term()
-%% Reason = term()
-%%
-%% Writes a (virtual) file to a TFTP server
-%%
-%% If LocalFilename is a binary, tftp_binary will be used as callback
-%% module. The binary will be transferred block by block and the number
-%% of transferred bytes will be returned as LastCallbackState.
-%%
-%% When LocalFilename is a string, it will be matched to the
-%% registered callback modules and hopefully one of them will be
-%% selected. By default, tftp_file will be used as callback module. It
-%% will read the file named LocalFilename block by block. The number
-%% of transferred bytes will be returned as LastCallbackState.
-%%-------------------------------------------------------------------
-
-write_file(RemoteFilename, LocalFilename, Options) ->
- tftp_engine:client_start(write, RemoteFilename, LocalFilename, Options).
-
-%%-------------------------------------------------------------------
-%% start(Options) -> {ok, Pid} | {error, Reason}
-%%
-%% Options = [option()]
-%% Pid = pid()
-%% Reason = term()
-%%
-%% Starts a daemon process which listens for udp packets on a
-%% port. When it receives a request for read or write it spawns
-%% a temporary server process which handles the actual transfer
-%% of the (virtual) file.
-%%-------------------------------------------------------------------
-
-start(Options) ->
- tftp_engine:daemon_start(Options).
-
-%%-------------------------------------------------------------------
-%% info(Pid) -> {ok, Options} | {error, Reason}
-%%
-%% Options = [option()]
-%% Reason = term()
-%%
-%% Returns info about a tftp daemon, server or client process
-%%-------------------------------------------------------------------
-
-info(Pid) ->
- tftp_engine:info(Pid).
-
-%%-------------------------------------------------------------------
-%% change_config(Pid, Options) -> ok | {error, Reason}
-%%
-%% Options = [option()]
-%% Reason = term()
-%%
-%% Changes config for a tftp daemon, server or client process
-%% Must be used with care.
-%%-------------------------------------------------------------------
-
-change_config(Pid, Options) ->
- tftp_engine:change_config(Pid, Options).
-
-%%-------------------------------------------------------------------
-%% start() -> ok | {error, Reason}
-%%
-%% Reason = term()
-%%
-%% Start the application
-%%-------------------------------------------------------------------
-
-start() ->
- application:start(inets).
-
-%%-------------------------------------------------------------------
-%% Inets service behavior
-%%-------------------------------------------------------------------
-
-start_standalone(Options) ->
- start(Options).
-
-start_service(Options) ->
- tftp_sup:start_child(Options).
-
-stop_service(Pid) ->
- tftp_sup:stop_child(Pid).
-
-services() ->
- tftp_sup:which_children().
-
-service_info(Pid) ->
- info(Pid).
-
-
-
diff --git a/lib/inets/src/tftp/tftp.hrl b/lib/inets/src/tftp/tftp.hrl
deleted file mode 100644
index 25543e0b9e..0000000000
--- a/lib/inets/src/tftp/tftp.hrl
+++ /dev/null
@@ -1,69 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
-%%%-------------------------------------------------------------------
-%%% Defines
-%%%-------------------------------------------------------------------
-
--define(TFTP_DEFAULT_PORT, 69).% Default server port
-
--define(TFTP_OPCODE_RRQ, 1). % Read request
--define(TFTP_OPCODE_WRQ, 2). % Write request
--define(TFTP_OPCODE_DATA, 3). % Data
--define(TFTP_OPCODE_ACK, 4). % Acknowledgement
--define(TFTP_OPCODE_ERROR, 5). % Error
--define(TFTP_OPCODE_OACK, 6). % Option acknowledgment
-
--define(TFTP_ERROR_UNDEF, 0). % Not defined, see error message (if any)
--define(TFTP_ERROR_ENOENT, 1). % File not found.
--define(TFTP_ERROR_EACCES, 2). % Access violation.
--define(TFTP_ERROR_ENOSPC, 3). % Disk full or allocation exceeded.
--define(TFTP_ERROR_BADOP, 4). % Illegal TFTP operation.
--define(TFTP_ERROR_BADBLK, 5). % Unknown transfer ID.
--define(TFTP_ERROR_EEXIST, 6). % File already exists.
--define(TFTP_ERROR_BADUSER, 7). % No such user.
--define(TFTP_ERROR_BADOPT, 8). % Unrequested or illegal option.
-
--record(tftp_msg_req, {access, filename, mode, options, local_filename}).
--record(tftp_msg_data, {block_no, data}).
--record(tftp_msg_ack, {block_no}).
--record(tftp_msg_error, {code, text, details}).
--record(tftp_msg_oack, {options}).
-
--record(config, {parent_pid = self(),
- udp_socket,
- udp_options = [binary, {reuseaddr, true}, {active, once}],
- udp_host = "localhost",
- udp_port = ?TFTP_DEFAULT_PORT,
- port_policy = random,
- use_tsize = false,
- max_tsize = infinity, % Filesize
- max_conn = infinity,
- rejected = [],
- polite_ack = false,
- debug_level = none,
- timeout,
- user_options = [],
- callbacks = [],
- logger = tftp_logger,
- max_retries = 5}).
-
--record(callback, {regexp, internal, module, state, block_no, count}).
diff --git a/lib/inets/src/tftp/tftp_binary.erl b/lib/inets/src/tftp/tftp_binary.erl
deleted file mode 100644
index 09adcfc41f..0000000000
--- a/lib/inets/src/tftp/tftp_binary.erl
+++ /dev/null
@@ -1,239 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
-%%%-------------------------------------------------------------------
-%%% File : tft_binary.erl
-%%% Author : Hakan Mattsson <[email protected]>
-%%% Description :
-%%%
-%%% Created : 24 May 2004 by Hakan Mattsson <[email protected]>
-%%%-------------------------------------------------------------------
-
--module(tftp_binary).
-
-%%%-------------------------------------------------------------------
-%%% Interface
-%%%-------------------------------------------------------------------
-
--behaviour(tftp).
-
--export([prepare/6, open/6, read/1, write/2, abort/3]).
-
--record(read_state, {options, blksize, bin, is_native_ascii, is_network_ascii, count}).
--record(write_state, {options, blksize, list, is_native_ascii, is_network_ascii}).
-
-%%-------------------------------------------------------------------
-%% Prepare
-%%-------------------------------------------------------------------
-
-prepare(_Peer, Access, Filename, Mode, SuggestedOptions, Initial) when is_list(Initial) ->
- %% Client side
- IsNativeAscii = is_native_ascii(Initial),
- case catch handle_options(Access, Filename, Mode, SuggestedOptions, IsNativeAscii) of
- {ok, IsNetworkAscii, AcceptedOptions} when Access =:= read, is_binary(Filename) ->
- State = #read_state{options = AcceptedOptions,
- blksize = lookup_blksize(AcceptedOptions),
- bin = Filename,
- is_network_ascii = IsNetworkAscii,
- count = size(Filename),
- is_native_ascii = IsNativeAscii},
- {ok, AcceptedOptions, State};
- {ok, IsNetworkAscii, AcceptedOptions} when Access =:= write, Filename =:= binary ->
- State = #write_state{options = AcceptedOptions,
- blksize = lookup_blksize(AcceptedOptions),
- list = [],
- is_network_ascii = IsNetworkAscii,
- is_native_ascii = IsNativeAscii},
- {ok, AcceptedOptions, State};
- {ok, _, _} ->
- {error, {undef, "Illegal callback usage. Mode and filename is incompatible."}};
- {error, {Code, Text}} ->
- {error, {Code, Text}}
- end;
-prepare(_Peer, _Access, _Bin, _Mode, _SuggestedOptions, _Initial) ->
- {error, {undef, "Illegal callback options."}}.
-
-%%-------------------------------------------------------------------
-%% Open
-%%-------------------------------------------------------------------
-
-open(Peer, Access, Filename, Mode, SuggestedOptions, Initial) when is_list(Initial) ->
- %% Server side
- case prepare(Peer, Access, Filename, Mode, SuggestedOptions, Initial) of
- {ok, AcceptedOptions, State} ->
- open(Peer, Access, Filename, Mode, AcceptedOptions, State);
- {error, {Code, Text}} ->
- {error, {Code, Text}}
- end;
-open(_Peer, Access, Filename, Mode, NegotiatedOptions, State) when is_record(State, read_state) ->
- %% Both sides
- case catch handle_options(Access, Filename, Mode, NegotiatedOptions, State#read_state.is_native_ascii) of
- {ok, IsNetworkAscii, Options}
- when Options =:= NegotiatedOptions,
- IsNetworkAscii =:= State#read_state.is_network_ascii ->
- {ok, NegotiatedOptions, State};
- {error, {Code, Text}} ->
- {error, {Code, Text}}
- end;
-open(_Peer, Access, Filename, Mode, NegotiatedOptions, State) when is_record(State, write_state) ->
- %% Both sides
- case catch handle_options(Access, Filename, Mode, NegotiatedOptions, State#write_state.is_native_ascii) of
- {ok, IsNetworkAscii, Options}
- when Options =:= NegotiatedOptions,
- IsNetworkAscii =:= State#write_state.is_network_ascii ->
- {ok, NegotiatedOptions, State};
- {error, {Code, Text}} ->
- {error, {Code, Text}}
- end;
-open(Peer, Access, Filename, Mode, NegotiatedOptions, State) ->
- %% Handle upgrade from old releases. Please, remove this clause in next release.
- State2 = upgrade_state(State),
- open(Peer, Access, Filename, Mode, NegotiatedOptions, State2).
-
-%%-------------------------------------------------------------------
-%% Read
-%%-------------------------------------------------------------------
-
-read(#read_state{bin = Bin} = State) when is_binary(Bin) ->
- BlkSize = State#read_state.blksize,
- if
- size(Bin) >= BlkSize ->
- <<Block:BlkSize/binary, Bin2/binary>> = Bin,
- State2 = State#read_state{bin = Bin2},
- {more, Block, State2};
- size(Bin) < BlkSize ->
- {last, Bin, State#read_state.count}
- end;
-read(State) ->
- %% Handle upgrade from old releases. Please, remove this clause in next release.
- State2 = upgrade_state(State),
- read(State2).
-
-%%-------------------------------------------------------------------
-%% Write
-%%-------------------------------------------------------------------
-
-write(Bin, #write_state{list = List} = State) when is_binary(Bin), is_list(List) ->
- Size = size(Bin),
- BlkSize = State#write_state.blksize,
- if
- Size =:= BlkSize ->
- {more, State#write_state{list = [Bin | List]}};
- Size < BlkSize ->
- Bin2 = list_to_binary(lists:reverse([Bin | List])),
- {last, Bin2}
- end;
-write(Bin, State) ->
- %% Handle upgrade from old releases. Please, remove this clause in next release.
- State2 = upgrade_state(State),
- write(Bin, State2).
-
-%%-------------------------------------------------------------------
-%% Abort
-%%-------------------------------------------------------------------
-
-abort(_Code, _Text, #read_state{bin = Bin} = State)
- when is_record(State, read_state), is_binary(Bin) ->
- ok;
-abort(_Code, _Text, #write_state{list = List} = State)
- when is_record(State, write_state), is_list(List) ->
- ok;
-abort(Code, Text, State) ->
- %% Handle upgrade from old releases. Please, remove this clause in next release.
- State2 = upgrade_state(State),
- abort(Code, Text, State2).
-
-%%-------------------------------------------------------------------
-%% Process options
-%%-------------------------------------------------------------------
-
-handle_options(Access, Bin, Mode, Options, IsNativeAscii) ->
- IsNetworkAscii = handle_mode(Mode, IsNativeAscii),
- Options2 = do_handle_options(Access, Bin, Options),
- {ok, IsNetworkAscii, Options2}.
-
-handle_mode(Mode, IsNativeAscii) ->
- case Mode of
- "netascii" when IsNativeAscii =:= true -> true;
- "octet" -> false;
- _ -> throw({error, {badop, "Illegal mode " ++ Mode}})
- end.
-
-do_handle_options(Access, Bin, [{Key, Val} | T]) ->
- case Key of
- "tsize" ->
- case Access of
- read when Val =:= "0", is_binary(Bin) ->
- Tsize = integer_to_list(size(Bin)),
- [{Key, Tsize} | do_handle_options(Access, Bin, T)];
- _ ->
- handle_integer(Access, Bin, Key, Val, T, 0, infinity)
- end;
- "blksize" ->
- handle_integer(Access, Bin, Key, Val, T, 8, 65464);
- "timeout" ->
- handle_integer(Access, Bin, Key, Val, T, 1, 255);
- _ ->
- do_handle_options(Access, Bin, T)
- end;
-do_handle_options(_Access, _Bin, []) ->
- [].
-
-
-handle_integer(Access, Bin, Key, Val, Options, Min, Max) ->
- case catch list_to_integer(Val) of
- {'EXIT', _} ->
- do_handle_options(Access, Bin, Options);
- Int when Int >= Min, Int =< Max ->
- [{Key, Val} | do_handle_options(Access, Bin, Options)];
- Int when Int >= Min, Max =:= infinity ->
- [{Key, Val} | do_handle_options(Access, Bin, Options)];
- _Int ->
- throw({error, {badopt, "Illegal " ++ Key ++ " value " ++ Val}})
- end.
-
-lookup_blksize(Options) ->
- case lists:keysearch("blksize", 1, Options) of
- {value, {_, Val}} ->
- list_to_integer(Val);
- false ->
- 512
- end.
-
-is_native_ascii([]) ->
- is_native_ascii();
-is_native_ascii([{native_ascii, Bool}]) ->
- case Bool of
- true -> true;
- false -> false
- end.
-
-is_native_ascii() ->
- case os:type() of
- {win32, _} -> true;
- _ -> false
- end.
-
-%% Handle upgrade from old releases. Please, remove this function in next release.
-upgrade_state({read_state, Options, Blksize, Bin, IsNetworkAscii, Count}) ->
- {read_state, Options, Blksize, Bin, false, IsNetworkAscii, Count};
-upgrade_state({write_state, Options, Blksize, List, IsNetworkAscii}) ->
- {write_state, Options, Blksize, List, false, IsNetworkAscii}.
diff --git a/lib/inets/src/tftp/tftp_engine.erl b/lib/inets/src/tftp/tftp_engine.erl
deleted file mode 100644
index fb2c9749e5..0000000000
--- a/lib/inets/src/tftp/tftp_engine.erl
+++ /dev/null
@@ -1,1422 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%-------------------------------------------------------------------
-%% Protocol engine for trivial FTP
-%%-------------------------------------------------------------------
-
--module(tftp_engine).
-
-%%%-------------------------------------------------------------------
-%%% Interface
-%%%-------------------------------------------------------------------
-
-%% application internal functions
--export([
- daemon_start/1,
- daemon_loop/1,
- daemon_loop/3, %% Handle upgrade from old releases. Please, remove this function in next release.
- client_start/4,
- common_loop/6,
- info/1,
- change_config/2
- ]).
-
-%% module internal
--export([
- daemon_init/1,
- server_init/2,
- client_init/2,
- wait_for_msg/3,
- callback/4
- ]).
-
-%% sys callback functions
--export([
- system_continue/3,
- system_terminate/4,
- system_code_change/4
- ]).
-
--include("tftp.hrl").
-
--type prep_status() :: 'error' | 'last' | 'more' | 'terminate'.
-
--record(daemon_state, {config, n_servers, server_tab, file_tab}).
--record(server_info, {pid, req, peer}).
--record(file_info, {peer_req, pid}).
--record(sys_misc, {module, function, arguments}).
--record(error, {where, code, text, filename}).
--record(prepared, {status :: prep_status() | 'undefined',
- result, block_no, next_data, prev_data}).
--record(transfer_res, {status, decoded_msg, prepared}).
--define(ERROR(Where, Code, Text, Filename),
- #error{where = Where, code = Code, text = Text, filename = Filename}).
-
-%%%-------------------------------------------------------------------
-%%% Info
-%%%-------------------------------------------------------------------
-
-info(daemons) ->
- Daemons = supervisor:which_children(tftp_sup),
- [{Pid, info(Pid)} || {_, Pid, _, _} <- Daemons];
-info(servers) ->
- [{Pid, info(Pid)} || {_, {ok, DeamonInfo}} <- info(daemons),
- {server, Pid} <- DeamonInfo];
-info(ToPid) when is_pid(ToPid) ->
- call(info, ToPid, timer:seconds(10)).
-
-change_config(daemons, Options) ->
- Daemons = supervisor:which_children(tftp_sup),
- [{Pid, change_config(Pid, Options)} || {_, Pid, _, _} <- Daemons];
-change_config(servers, Options) ->
- [{Pid, change_config(Pid, Options)} || {_, {ok, DeamonInfo}} <- info(daemons),
- {server, Pid} <- DeamonInfo];
-change_config(ToPid, Options) when is_pid(ToPid) ->
- BadKeys = [host, port, udp],
- BadOptions = [{Key, Val} || {Key, Val} <- Options,
- BadKey <- BadKeys,
- Key =:= BadKey],
- case BadOptions of
- [] ->
- call({change_config, Options}, ToPid, timer:seconds(10));
- [{Key, Val} | _] ->
- {error, {badarg, {Key, Val}}}
- end.
-
-call(Req, ToPid, Timeout) when is_pid(ToPid) ->
- Type = process,
- Ref = erlang:monitor(Type, ToPid),
- ToPid ! {Req, Ref, self()},
- receive
- {Reply, Ref, FromPid} when FromPid =:= ToPid ->
- erlang:demonitor(Ref, [flush]),
- Reply;
- {'DOWN', Ref, Type, FromPid, _Reason} when FromPid =:= ToPid ->
- {error, timeout}
- after Timeout ->
- {error, timeout}
- end.
-
-reply(Reply, Ref, ToPid) ->
- ToPid ! {Reply, Ref, self()}.
-
-%%%-------------------------------------------------------------------
-%%% Daemon
-%%%-------------------------------------------------------------------
-
-%% Returns {ok, Port}
-daemon_start(Options) when is_list(Options) ->
- Config = tftp_lib:parse_config(Options),
- proc_lib:start_link(?MODULE, daemon_init, [Config], infinity).
-
-daemon_init(Config) when is_record(Config, config),
- is_pid(Config#config.parent_pid) ->
- process_flag(trap_exit, true),
- {Port, UdpOptions} = prepare_daemon_udp(Config),
- case catch gen_udp:open(Port, UdpOptions) of
- {ok, Socket} ->
- {ok, ActualPort} = inet:port(Socket),
- proc_lib:init_ack({ok, self()}),
- Config2 = Config#config{udp_socket = Socket,
- udp_port = ActualPort},
- print_debug_info(Config2, daemon, open, #tftp_msg_req{filename = ""}),
- ServerTab = ets:new(tftp_daemon_servers, [{keypos, 2}]),
- FileTab = ets:new(tftp_daemon_files, [{keypos, 2}]),
- State = #daemon_state{config = Config2,
- n_servers = 0,
- server_tab = ServerTab,
- file_tab = FileTab},
- daemon_loop(State);
- {error, Reason} ->
- Text = lists:flatten(io_lib:format("UDP open ~p -> ~p", [UdpOptions, Reason])),
- print_debug_info(Config, daemon, open, ?ERROR(open, undef, Text, "")),
- exit({gen_udp_open, UdpOptions, Reason});
- Reason ->
- Text = lists:flatten(io_lib:format("UDP open ~p -> ~p", [UdpOptions, Reason])),
- print_debug_info(Config, daemon, open, ?ERROR(open, undef, Text, "")),
- exit({gen_udp_open, UdpOptions, Reason})
- end.
-
-prepare_daemon_udp(#config{udp_port = Port, udp_options = UdpOptions} = Config) ->
- case lists:keymember(fd, 1, UdpOptions) of
- true ->
- %% Use explicit fd
- {Port, UdpOptions};
- false ->
- %% Use fd from setuid_socket_wrap, such as -tftpd_69
- InitArg = list_to_atom("tftpd_" ++ integer_to_list(Port)),
- case init:get_argument(InitArg) of
- {ok, [[FdStr]] = Badarg} when is_list(FdStr) ->
- case catch list_to_integer(FdStr) of
- Fd when is_integer(Fd) ->
- {0, [{fd, Fd} | lists:keydelete(ip, 1, UdpOptions)]};
- {'EXIT', _} ->
- Text = lists:flatten(io_lib:format("Illegal prebound fd ~p: ~p", [InitArg, Badarg])),
- print_debug_info(Config, daemon, open, ?ERROR(open, undef, Text, "")),
- exit({badarg, {prebound_fd, InitArg, Badarg}})
- end;
- {ok, Badarg} ->
- Text = lists:flatten(io_lib:format("Illegal prebound fd ~p: ~p", [InitArg, Badarg])),
- print_debug_info(Config, daemon, open, ?ERROR(open, undef, Text, "")),
- exit({badarg, {prebound_fd, InitArg, Badarg}});
- error ->
- {Port, UdpOptions}
- end
- end.
-
-daemon_loop(DaemonConfig, N, Servers) when is_list(Servers) ->
- %% Handle upgrade from old releases. Please, remove this function in next release.
- ServerTab = ets:new(tftp_daemon_servers, [{keypos, 2}]),
- FileTab = ets:new(tftp_daemon_files, [{keypos, 2}]),
- State = #daemon_state{config = DaemonConfig,
- n_servers = N,
- server_tab = ServerTab,
- file_tab = FileTab},
- Req = #tftp_msg_req{filename = dummy},
- [ets:insert(ServerTab, #server_info{pid = Pid, req = Req, peer = dummy}) || Pid <- Servers],
- daemon_loop(State).
-
-daemon_loop(#daemon_state{config = DaemonConfig,
- n_servers = N,
- server_tab = ServerTab,
- file_tab = FileTab} = State) when is_record(DaemonConfig, config) ->
- %% info_msg(DaemonConfig, "=====> TFTP: Daemon #~p\n", [N]), %% XXX
- receive
- {info, Ref, FromPid} when is_pid(FromPid) ->
- Fun = fun(#server_info{pid = Pid}, Acc) -> [{server, Pid} | Acc] end,
- ServerInfo = ets:foldl(Fun, [], ServerTab),
- Info = internal_info(DaemonConfig, daemon) ++ [{n_conn, N}] ++ ServerInfo,
- reply({ok, Info}, Ref, FromPid),
- ?MODULE:daemon_loop(State);
- {{change_config, Options}, Ref, FromPid} when is_pid(FromPid) ->
- case catch tftp_lib:parse_config(Options, DaemonConfig) of
- {'EXIT', Reason} ->
- reply({error, Reason}, Ref, FromPid),
- ?MODULE:daemon_loop(State);
- DaemonConfig2 when is_record(DaemonConfig2, config) ->
- reply(ok, Ref, FromPid),
- ?MODULE:daemon_loop(State#daemon_state{config = DaemonConfig2})
- end;
- {udp, Socket, RemoteHost, RemotePort, Bin} when is_binary(Bin) ->
- inet:setopts(Socket, [{active, once}]),
- ServerConfig = DaemonConfig#config{parent_pid = self(),
- udp_host = RemoteHost,
- udp_port = RemotePort},
- Msg = (catch tftp_lib:decode_msg(Bin)),
- print_debug_info(ServerConfig, daemon, recv, Msg),
- case Msg of
- Req when is_record(Req, tftp_msg_req),
- N =< DaemonConfig#config.max_conn ->
- Peer = peer_info(ServerConfig),
- PeerReq = {Peer, Req},
- PeerInfo = lists:flatten(io_lib:format("~p", [Peer])),
- case ets:lookup(FileTab, PeerReq) of
- [] ->
- Args = [ServerConfig, Req],
- Pid = proc_lib:spawn_link(?MODULE, server_init, Args),
- ets:insert(ServerTab, #server_info{pid = Pid, req = Req, peer = Peer}),
- ets:insert(FileTab, #file_info{peer_req = PeerReq, pid = Pid}),
- ?MODULE:daemon_loop(State#daemon_state{n_servers = N + 1});
- [#file_info{pid = Pid}] ->
- %% Yet another request of the file from same peer
- warning_msg(DaemonConfig, "~p Reuse connection for ~s\n\t~p\n",
- [Pid, PeerInfo, Req#tftp_msg_req.filename]),
- ?MODULE:daemon_loop(State)
- end;
- Req when is_record(Req, tftp_msg_req) ->
- Reply = #tftp_msg_error{code = enospc, text = "Too many connections"},
- Peer = peer_info(ServerConfig),
- PeerInfo = lists:flatten(io_lib:format("~p", [Peer])),
- warning_msg(DaemonConfig,
- "Daemon has too many connections (~p)."
- "\n\tRejecting request from ~s\n",
- [N, PeerInfo]),
- send_msg(ServerConfig, daemon, Reply),
- ?MODULE:daemon_loop(State);
- {'EXIT', Reply} when is_record(Reply, tftp_msg_error) ->
- send_msg(ServerConfig, daemon, Reply),
- ?MODULE:daemon_loop(State);
- Req ->
- Reply = #tftp_msg_error{code = badop,
- text = "Illegal TFTP operation"},
- warning_msg(DaemonConfig, "Daemon received: ~p.\n\tfrom ~p:~p",
- [Req, RemoteHost, RemotePort]),
- send_msg(ServerConfig, daemon, Reply),
- ?MODULE:daemon_loop(State)
- end;
- {system, From, Msg} ->
- Misc = #sys_misc{module = ?MODULE, function = daemon_loop, arguments = [State]},
- sys:handle_system_msg(Msg, From, DaemonConfig#config.parent_pid, ?MODULE, [], Misc);
- {'EXIT', Pid, Reason} when DaemonConfig#config.parent_pid =:= Pid ->
- close_port(DaemonConfig, daemon, #tftp_msg_req{filename = ""}),
- exit(Reason);
- {'EXIT', Pid, _Reason} = Info ->
- case ets:lookup(ServerTab, Pid) of
- [] ->
- warning_msg(DaemonConfig, "Daemon received: ~p", [Info]),
- ?MODULE:daemon_loop(State);
- [#server_info{req = Req, peer = Peer}] ->
- PeerReq = {Peer, Req},
- ets:delete(FileTab, PeerReq),
- ets:delete(ServerTab, Pid),
- ?MODULE:daemon_loop(State#daemon_state{n_servers = N - 1})
- end;
- Info ->
- warning_msg(DaemonConfig, "Daemon received: ~p", [Info]),
- ?MODULE:daemon_loop(State)
- end;
-daemon_loop(#daemon_state{config = Config} = State) ->
- %% Handle upgrade from old releases. Please, remove this clause in next release.
- Config2 = upgrade_config(Config),
- daemon_loop(State#daemon_state{config = Config2}).
-
-upgrade_config({config, ParentPid, UdpSocket, UdpOptions, UdpHost, UdpPort, PortPolicy,
- UseTsize, MaxTsize, MaxConn, Rejected, PoliteAck, DebugLevel,
- Timeout, UserOptions, Callbacks}) ->
- Callbacks2 = tftp_lib:add_default_callbacks(Callbacks),
- Logger = tftp_logger,
- MaxRetries = 5,
- {config, ParentPid, UdpSocket, UdpOptions, UdpHost, UdpPort, PortPolicy,
- UseTsize, MaxTsize, MaxConn, Rejected, PoliteAck, DebugLevel,
- Timeout, UserOptions, Callbacks2, Logger, MaxRetries}.
-
-%%%-------------------------------------------------------------------
-%%% Server
-%%%-------------------------------------------------------------------
-
-server_init(Config, Req) when is_record(Config, config),
- is_pid(Config#config.parent_pid),
- is_record(Req, tftp_msg_req) ->
- process_flag(trap_exit, true),
- %% Config =
- %% case os:getenv("TFTPDEBUG") of
- %% false ->
- %% Config0;
- %% DebugLevel ->
- %% Config0#config{debug_level = list_to_atom(DebugLevel)}
- %% end,
- SuggestedOptions = Req#tftp_msg_req.options,
- UdpOptions = Config#config.udp_options,
- UdpOptions2 = lists:keydelete(fd, 1, UdpOptions),
- Config1 = Config#config{udp_options = UdpOptions2},
- Config2 = tftp_lib:parse_config(SuggestedOptions, Config1),
- SuggestedOptions2 = Config2#config.user_options,
- Req2 = Req#tftp_msg_req{options = SuggestedOptions2},
- case open_free_port(Config2, server, Req2) of
- {ok, Config3} ->
- Filename = Req#tftp_msg_req.filename,
- case match_callback(Filename, Config3#config.callbacks) of
- {ok, Callback} ->
- print_debug_info(Config3, server, match, Callback),
- case pre_verify_options(Config3, Req2) of
- ok ->
- case callback({open, server_open}, Config3, Callback, Req2) of
- {Callback2, {ok, AcceptedOptions}} ->
- {LocalAccess, _} = local_file_access(Req2),
- OptText = "Internal error. Not allowed to add new options.",
- case post_verify_options(Config3, Req2, AcceptedOptions, OptText) of
- {ok, Config4, Req3} when AcceptedOptions =/= [] ->
- Reply = #tftp_msg_oack{options = AcceptedOptions},
- BlockNo =
- case LocalAccess of
- read -> 0;
- write -> 1
- end,
- {Config5, Callback3, TransferRes} =
- transfer(Config4, Callback2, Req3, Reply, LocalAccess, BlockNo, #prepared{}),
- common_loop(Config5, Callback3, Req3, TransferRes, LocalAccess, BlockNo);
- {ok, Config4, Req3} when LocalAccess =:= write ->
- BlockNo = 0,
- common_ack(Config4, Callback2, Req3, LocalAccess, BlockNo, #prepared{});
- {ok, Config4, Req3} when LocalAccess =:= read ->
- BlockNo = 0,
- common_read(Config4, Callback2, Req3, LocalAccess, BlockNo, BlockNo, #prepared{});
- {error, {Code, Text}} ->
- {undefined, Error} =
- callback({abort, {Code, Text}}, Config3, Callback2, Req2),
- send_msg(Config3, Req, Error),
- terminate(Config3, Req2, ?ERROR(post_verify_options, Code, Text, Req2#tftp_msg_req.filename))
- end;
- {undefined, #tftp_msg_error{code = Code, text = Text} = Error} ->
- send_msg(Config3, Req, Error),
- terminate(Config3, Req, ?ERROR(server_open, Code, Text, Req2#tftp_msg_req.filename))
- end;
- {error, {Code, Text}} ->
- {undefined, Error} =
- callback({abort, {Code, Text}}, Config2, Callback, Req2),
- send_msg(Config2, Req, Error),
- terminate(Config2, Req2, ?ERROR(pre_verify_options, Code, Text, Req2#tftp_msg_req.filename))
- end;
- {error, #tftp_msg_error{code = Code, text = Text} = Error} ->
- send_msg(Config3, Req, Error),
- terminate(Config3, Req, ?ERROR(match_callback, Code, Text, Req2#tftp_msg_req.filename))
- end;
- #error{} = Error ->
- terminate(Config2, Req, Error)
- end;
-server_init(Config, Req) when is_record(Req, tftp_msg_req) ->
- Config2 = upgrade_config(Config),
- server_init(Config2, Req).
-
-%%%-------------------------------------------------------------------
-%%% Client
-%%%-------------------------------------------------------------------
-
-%% LocalFilename = filename() | 'binary' | binary()
-%% Returns {ok, LastCallbackState} | {error, Reason}
-client_start(Access, RemoteFilename, LocalFilename, Options) ->
- Config = tftp_lib:parse_config(Options),
- Config2 = Config#config{parent_pid = self(),
- udp_socket = undefined},
- Req = #tftp_msg_req{access = Access,
- filename = RemoteFilename,
- mode = lookup_mode(Config2#config.user_options),
- options = Config2#config.user_options,
- local_filename = LocalFilename},
- Args = [Config2, Req],
- case proc_lib:start_link(?MODULE, client_init, Args, infinity) of
- {ok, LastCallbackState} ->
- {ok, LastCallbackState};
- {error, Error} ->
- {error, Error}
- end.
-
-client_init(Config, Req) when is_record(Config, config),
- is_pid(Config#config.parent_pid),
- is_record(Req, tftp_msg_req) ->
- process_flag(trap_exit, true),
- %% Config =
- %% case os:getenv("TFTPDEBUG") of
- %% false ->
- %% Config0;
- %% "none" ->
- %% Config0;
- %% DebugLevel ->
- %% info_msg(Config, "TFTPDEBUG: ~s\n", [DebugLevel]),
- %% Config0#config{debug_level = list_to_atom(DebugLevel)}
- %% end,
- case open_free_port(Config, client, Req) of
- {ok, Config2} ->
- Req2 =
- case Config2#config.use_tsize of
- true ->
- SuggestedOptions = Req#tftp_msg_req.options,
- SuggestedOptions2 = tftp_lib:replace_val("tsize", "0", SuggestedOptions),
- Req#tftp_msg_req{options = SuggestedOptions2};
- false ->
- Req
- end,
- LocalFilename = Req2#tftp_msg_req.local_filename,
- case match_callback(LocalFilename, Config2#config.callbacks) of
- {ok, Callback} ->
- print_debug_info(Config2, client, match, Callback),
- client_prepare(Config2, Callback, Req2);
- {error, #tftp_msg_error{code = Code, text = Text}} ->
- terminate(Config, Req, ?ERROR(match, Code, Text, Req#tftp_msg_req.filename))
- end;
- #error{} = Error ->
- terminate(Config, Req, Error)
- end.
-
-client_prepare(Config, Callback, Req) when is_record(Req, tftp_msg_req) ->
- case pre_verify_options(Config, Req) of
- ok ->
- case callback({open, client_prepare}, Config, Callback, Req) of
- {Callback2, {ok, AcceptedOptions}} ->
- OptText = "Internal error. Not allowed to add new options.",
- case post_verify_options(Config, Req, AcceptedOptions, OptText) of
- {ok, Config2, Req2} ->
- {LocalAccess, _} = local_file_access(Req2),
- BlockNo = 0,
- {Config3, Callback3, TransferRes} =
- transfer(Config2, Callback2, Req2, Req2, LocalAccess, BlockNo, #prepared{}),
- client_open(Config3, Callback3, Req2, BlockNo, TransferRes);
- {error, {Code, Text}} ->
- callback({abort, {Code, Text}}, Config, Callback2, Req),
- terminate(Config, Req, ?ERROR(post_verify_options, Code, Text, Req#tftp_msg_req.filename))
- end;
- {undefined, #tftp_msg_error{code = Code, text = Text}} ->
- terminate(Config, Req, ?ERROR(client_prepare, Code, Text, Req#tftp_msg_req.filename))
- end;
- {error, {Code, Text}} ->
- callback({abort, {Code, Text}}, Config, Callback, Req),
- terminate(Config, Req, ?ERROR(pre_verify_options, Code, Text, Req#tftp_msg_req.filename))
- end.
-
-client_open(Config, Callback, Req, BlockNo, #transfer_res{status = Status, decoded_msg = DecodedMsg, prepared = Prepared}) ->
- {LocalAccess, _} = local_file_access(Req),
- case Status of
- ok when is_record(Prepared, prepared) ->
- case DecodedMsg of
- Msg when is_record(Msg, tftp_msg_oack) ->
- ServerOptions = Msg#tftp_msg_oack.options,
- OptText = "Protocol violation. Server is not allowed new options",
- case post_verify_options(Config, Req, ServerOptions, OptText) of
- {ok, Config2, Req2} ->
- {Config3, Callback2, Req3} =
- do_client_open(Config2, Callback, Req2),
- case LocalAccess of
- read ->
- common_read(Config3, Callback2, Req3, LocalAccess, BlockNo, BlockNo, Prepared);
- write ->
- common_ack(Config3, Callback2, Req3, LocalAccess, BlockNo, Prepared)
- end;
- {error, {Code, Text}} ->
- {undefined, Error} =
- callback({abort, {Code, Text}}, Config, Callback, Req),
- send_msg(Config, Req, Error),
- terminate(Config, Req, ?ERROR(verify_server_options, Code, Text, Req#tftp_msg_req.filename))
- end;
- #tftp_msg_ack{block_no = ActualBlockNo} when LocalAccess =:= read ->
- Req2 = Req#tftp_msg_req{options = []},
- {Config2, Callback2, Req2} = do_client_open(Config, Callback, Req2),
- ExpectedBlockNo = 0,
- common_read(Config2, Callback2, Req2, LocalAccess, ExpectedBlockNo, ActualBlockNo, Prepared);
- #tftp_msg_data{block_no = ActualBlockNo, data = Data} when LocalAccess =:= write ->
- Req2 = Req#tftp_msg_req{options = []},
- {Config2, Callback2, Req2} = do_client_open(Config, Callback, Req2),
- ExpectedBlockNo = 1,
- common_write(Config2, Callback2, Req2, LocalAccess, ExpectedBlockNo, ActualBlockNo, Data, Prepared);
- %% #tftp_msg_error{code = Code, text = Text} when Req#tftp_msg_req.options =/= [] ->
- %% %% Retry without options
- %% callback({abort, {Code, Text}}, Config, Callback, Req),
- %% Req2 = Req#tftp_msg_req{options = []},
- %% client_prepare(Config, Callback, Req2);
- #tftp_msg_error{code = Code, text = Text} ->
- callback({abort, {Code, Text}}, Config, Callback, Req),
- terminate(Config, Req, ?ERROR(client_open, Code, Text, Req#tftp_msg_req.filename));
- {'EXIT', #tftp_msg_error{code = Code, text = Text}} ->
- callback({abort, {Code, Text}}, Config, Callback, Req),
- terminate(Config, Req, ?ERROR(client_open, Code, Text, Req#tftp_msg_req.filename));
- Msg when is_tuple(Msg) ->
- Code = badop,
- Text = "Illegal TFTP operation",
- {undefined, Error} =
- callback({abort, {Code, Text}}, Config, Callback, Req),
- send_msg(Config, Req, Error),
- Text2 = lists:flatten([Text, ". ", io_lib:format("~p", [element(1, Msg)])]),
- terminate(Config, Req, ?ERROR(client_open, Code, Text2, Req#tftp_msg_req.filename))
- end;
- error when is_record(Prepared, tftp_msg_error) ->
- #tftp_msg_error{code = Code, text = Text} = Prepared,
- callback({abort, {Code, Text}}, Config, Callback, Req),
- terminate(Config, Req, ?ERROR(client_open, Code, Text, Req#tftp_msg_req.filename))
- end.
-
-do_client_open(Config, Callback, Req) ->
- case callback({open, client_open}, Config, Callback, Req) of
- {Callback2, {ok, FinalOptions}} ->
- OptText = "Internal error. Not allowed to change options.",
- case post_verify_options(Config, Req, FinalOptions, OptText) of
- {ok, Config2, Req2} ->
- {Config2, Callback2, Req2};
- {error, {Code, Text}} ->
- {undefined, Error} =
- callback({abort, {Code, Text}}, Config, Callback2, Req),
- send_msg(Config, Req, Error),
- terminate(Config, Req, ?ERROR(post_verify_options, Code, Text, Req#tftp_msg_req.filename))
- end;
- {undefined, #tftp_msg_error{code = Code, text = Text} = Error} ->
- send_msg(Config, Req, Error),
- terminate(Config, Req, ?ERROR(client_open, Code, Text, Req#tftp_msg_req.filename))
- end.
-
-%%%-------------------------------------------------------------------
-%%% Common loop for both client and server
-%%%-------------------------------------------------------------------
-
-common_loop(Config, Callback, Req, #transfer_res{status = Status, decoded_msg = DecodedMsg, prepared = Prepared}, LocalAccess, ExpectedBlockNo)
- when is_record(Config, config)->
- %% Config =
- %% case os:getenv("TFTPMAX") of
- %% false ->
- %% Config0;
- %% MaxBlockNoStr when Config0#config.debug_level =/= none ->
- %% case list_to_integer(MaxBlockNoStr) of
- %% MaxBlockNo when ExpectedBlockNo > MaxBlockNo ->
- %% info_msg(Config, "TFTPMAX: ~p\n", [MaxBlockNo]),
- %% info_msg(Config, "TFTPDEBUG: none\n", []),
- %% Config0#config{debug_level = none};
- %% _ ->
- %% Config0
- %% end;
- %% _MaxBlockNoStr ->
- %% Config0
- %% end,
- case Status of
- ok when is_record(Prepared, prepared) ->
- case DecodedMsg of
- #tftp_msg_ack{block_no = ActualBlockNo} when LocalAccess =:= read ->
- common_read(Config, Callback, Req, LocalAccess, ExpectedBlockNo, ActualBlockNo, Prepared);
- #tftp_msg_data{block_no = ActualBlockNo, data = Data} when LocalAccess =:= write ->
- common_write(Config, Callback, Req, LocalAccess, ExpectedBlockNo, ActualBlockNo, Data, Prepared);
- #tftp_msg_error{code = Code, text = Text} ->
- callback({abort, {Code, Text}}, Config, Callback, Req),
- terminate(Config, Req, ?ERROR(common_loop, Code, Text, Req#tftp_msg_req.filename));
- {'EXIT', #tftp_msg_error{code = Code, text = Text} = Error} ->
- callback({abort, {Code, Text}}, Config, Callback, Req),
- send_msg(Config, Req, Error),
- terminate(Config, Req, ?ERROR(common_loop, Code, Text, Req#tftp_msg_req.filename));
- Msg when is_tuple(Msg) ->
- Code = badop,
- Text = "Illegal TFTP operation",
- {undefined, Error} =
- callback({abort, {Code, Text}}, Config, Callback, Req),
- send_msg(Config, Req, Error),
- Text2 = lists:flatten([Text, ". ", io_lib:format("~p", [element(1, Msg)])]),
- terminate(Config, Req, ?ERROR(common_loop, Code, Text2, Req#tftp_msg_req.filename))
- end;
- error when is_record(Prepared, tftp_msg_error) ->
- #tftp_msg_error{code = Code, text = Text} = Prepared,
- send_msg(Config, Req, Prepared),
- terminate(Config, Req, ?ERROR(transfer, Code, Text, Req#tftp_msg_req.filename))
- end;
-common_loop(Config, Callback, Req, TransferRes, LocalAccess, ExpectedBlockNo) ->
- %% Handle upgrade from old releases. Please, remove this clause in next release.
- Config2 = upgrade_config(Config),
- common_loop(Config2, Callback, Req, TransferRes, LocalAccess, ExpectedBlockNo).
-
--spec common_read(#config{}, #callback{}, _, 'read', _, _, #prepared{}) -> no_return().
-
-common_read(Config, _, Req, _, _, _, #prepared{status = terminate, result = Result}) ->
- terminate(Config, Req, {ok, Result});
-common_read(Config, Callback, Req, LocalAccess, ExpectedBlockNo, ActualBlockNo, Prepared)
- when ActualBlockNo =:= ExpectedBlockNo, is_record(Prepared, prepared) ->
- case early_read(Config, Callback, Req, LocalAccess, ActualBlockNo, Prepared) of
- {Callback2, #prepared{status = more, next_data = Data} = Prepared2} when is_binary(Data) ->
- Prepared3 = Prepared2#prepared{prev_data = Data, next_data = undefined},
- do_common_read(Config, Callback2, Req, LocalAccess, ActualBlockNo, Data, Prepared3);
- {undefined, #prepared{status = last, next_data = Data} = Prepared2} when is_binary(Data) ->
- Prepared3 = Prepared2#prepared{status = terminate},
- do_common_read(Config, undefined, Req, LocalAccess, ActualBlockNo, Data, Prepared3);
- {undefined, #prepared{status = error, result = Error}} ->
- #tftp_msg_error{code = Code, text = Text} = Error,
- send_msg(Config, Req, Error),
- terminate(Config, Req, ?ERROR(read, Code, Text, Req#tftp_msg_req.filename))
- end;
-common_read(Config, Callback, Req, LocalAccess, ExpectedBlockNo, ActualBlockNo, Prepared)
- when ActualBlockNo =:= (ExpectedBlockNo - 1), is_record(Prepared, prepared) ->
- case Prepared of
- #prepared{status = more, prev_data = Data} when is_binary(Data) ->
- do_common_read(Config, Callback, Req, LocalAccess, ActualBlockNo, Data, Prepared);
- #prepared{status = last, prev_data = Data} when is_binary(Data) ->
- do_common_read(Config, Callback, Req, LocalAccess, ActualBlockNo, Data, Prepared);
- #prepared{status = error, result = Error} ->
- #tftp_msg_error{code = Code, text = Text} = Error,
- send_msg(Config, Req, Error),
- terminate(Config, Req, ?ERROR(read, Code, Text, Req#tftp_msg_req.filename))
- end;
-common_read(Config, Callback, Req, LocalAccess, ExpectedBlockNo, ActualBlockNo, Prepared)
- when ActualBlockNo =< ExpectedBlockNo, is_record(Prepared, prepared) ->
- %% error_logger:error_msg("TFTP READ ~s: Expected block ~p but got block ~p - IGNORED\n",
- %% [Req#tftp_msg_req.filename, ExpectedBlockNo, ActualBlockNo]),
- case Prepared of
- #prepared{status = more, prev_data = Data} when is_binary(Data) ->
- Reply = #tftp_msg_data{block_no = ExpectedBlockNo, data = Data},
- {Config2, Callback2, TransferRes} =
- wait_for_msg_and_handle_timeout(Config, Callback, Req, Reply, LocalAccess, ExpectedBlockNo, Prepared),
- ?MODULE:common_loop(Config2, Callback2, Req, TransferRes, LocalAccess, ExpectedBlockNo);
- #prepared{status = last, prev_data = Data} when is_binary(Data) ->
- Reply = #tftp_msg_data{block_no = ExpectedBlockNo, data = Data},
- {Config2, Callback2, TransferRes} =
- wait_for_msg_and_handle_timeout(Config, Callback, Req, Reply, LocalAccess, ExpectedBlockNo, Prepared),
- ?MODULE:common_loop(Config2, Callback2, Req, TransferRes, LocalAccess, ExpectedBlockNo);
- #prepared{status = error, result = Error} ->
- #tftp_msg_error{code = Code, text = Text} = Error,
- send_msg(Config, Req, Error),
- terminate(Config, Req, ?ERROR(read, Code, Text, Req#tftp_msg_req.filename))
- end;
-common_read(Config, Callback, Req, _LocalAccess, ExpectedBlockNo, ActualBlockNo, Prepared)
- when is_record(Prepared, prepared) ->
- Code = badblk,
- Text = "Unknown transfer ID = " ++
- integer_to_list(ActualBlockNo) ++ " (" ++ integer_to_list(ExpectedBlockNo) ++ ")",
- {undefined, Error} =
- callback({abort, {Code, Text}}, Config, Callback, Req),
- send_msg(Config, Req, Error),
- terminate(Config, Req, ?ERROR(read, Code, Text, Req#tftp_msg_req.filename)).
-
--spec do_common_read(#config{}, #callback{} | undefined, _, 'read', integer(), binary(), #prepared{}) -> no_return().
-
-do_common_read(Config, Callback, Req, LocalAccess, BlockNo, Data, Prepared)
- when is_binary(Data), is_record(Prepared, prepared) ->
- NextBlockNo = (BlockNo + 1) rem 65536,
- Reply = #tftp_msg_data{block_no = NextBlockNo, data = Data},
- {Config2, Callback2, TransferRes} =
- transfer(Config, Callback, Req, Reply, LocalAccess, NextBlockNo, Prepared),
- ?MODULE:common_loop(Config2, Callback2, Req, TransferRes, LocalAccess, NextBlockNo).
-
--spec common_write(#config{}, #callback{}, _, 'write', integer(), integer(), _, #prepared{}) -> no_return().
-
-common_write(Config, _, Req, _, _, _, _, #prepared{status = terminate, result = Result}) ->
- terminate(Config, Req, {ok, Result});
-common_write(Config, Callback, Req, LocalAccess, ExpectedBlockNo, ActualBlockNo, Data, Prepared)
- when ActualBlockNo =:= ExpectedBlockNo, is_binary(Data), is_record(Prepared, prepared) ->
- case callback({write, Data}, Config, Callback, Req) of
- {Callback2, #prepared{status = more} = Prepared2} ->
- common_ack(Config, Callback2, Req, LocalAccess, ActualBlockNo, Prepared2);
- {undefined, #prepared{status = last, result = Result} = Prepared2} ->
- Config2 = pre_terminate(Config, Req, {ok, Result}),
- Prepared3 = Prepared2#prepared{status = terminate},
- common_ack(Config2, undefined, Req, LocalAccess, ActualBlockNo, Prepared3);
- {undefined, #prepared{status = error, result = Error}} ->
- #tftp_msg_error{code = Code, text = Text} = Error,
- send_msg(Config, Req, Error),
- terminate(Config, Req, ?ERROR(write, Code, Text, Req#tftp_msg_req.filename))
- end;
-common_write(Config, Callback, Req, LocalAccess, ExpectedBlockNo, ActualBlockNo, Data, Prepared)
- when ActualBlockNo =:= (ExpectedBlockNo - 1), is_binary(Data), is_record(Prepared, prepared) ->
- common_ack(Config, Callback, Req, LocalAccess, ExpectedBlockNo - 1, Prepared);
-common_write(Config, Callback, Req, LocalAccess, ExpectedBlockNo, ActualBlockNo, Data, Prepared)
- when ActualBlockNo =< ExpectedBlockNo, is_binary(Data), is_record(Prepared, prepared) ->
- %% error_logger:error_msg("TFTP WRITE ~s: Expected block ~p but got block ~p - IGNORED\n",
- %% [Req#tftp_msg_req.filename, ExpectedBlockNo, ActualBlockNo]),
- Reply = #tftp_msg_ack{block_no = ExpectedBlockNo},
- {Config2, Callback2, TransferRes} =
- wait_for_msg_and_handle_timeout(Config, Callback, Req, Reply, LocalAccess, ExpectedBlockNo, Prepared),
- ?MODULE:common_loop(Config2, Callback2, Req, TransferRes, LocalAccess, ExpectedBlockNo);
-common_write(Config, Callback, Req, _, ExpectedBlockNo, ActualBlockNo, Data, Prepared)
- when is_binary(Data), is_record(Prepared, prepared) ->
- Code = badblk,
- Text = "Unknown transfer ID = " ++
- integer_to_list(ActualBlockNo) ++ " (" ++ integer_to_list(ExpectedBlockNo) ++ ")",
- {undefined, Error} =
- callback({abort, {Code, Text}}, Config, Callback, Req),
- send_msg(Config, Req, Error),
- terminate(Config, Req, ?ERROR(write, Code, Text, Req#tftp_msg_req.filename)).
-
-common_ack(Config, Callback, Req, LocalAccess, BlockNo, Prepared)
- when is_record(Prepared, prepared) ->
- Reply = #tftp_msg_ack{block_no = BlockNo},
- NextBlockNo = (BlockNo + 1) rem 65536,
- {Config2, Callback2, TransferRes} =
- transfer(Config, Callback, Req, Reply, LocalAccess, NextBlockNo, Prepared),
- ?MODULE:common_loop(Config2, Callback2, Req, TransferRes, LocalAccess, NextBlockNo).
-
-pre_terminate(Config, Req, Result) ->
- if
- Req#tftp_msg_req.local_filename =/= undefined,
- Config#config.parent_pid =/= undefined ->
- proc_lib:init_ack(Result),
- unlink(Config#config.parent_pid),
- Config#config{parent_pid = undefined, polite_ack = true};
- true ->
- Config#config{polite_ack = true}
- end.
-
--spec terminate(#config{}, #tftp_msg_req{}, {'ok', _} | #error{}) -> no_return().
-
-terminate(Config, Req, Result) ->
- Result2 =
- case Result of
- {ok, _} ->
- Result;
- #error{where = Where, code = Code, text = Text} = Error ->
- print_debug_info(Config, Req, Where, Error#error{filename = Req#tftp_msg_req.filename}),
- {error, {Where, Code, Text}}
- end,
- if
- Config#config.parent_pid =:= undefined ->
- close_port(Config, client, Req),
- exit(normal);
- Req#tftp_msg_req.local_filename =/= undefined ->
- %% Client
- close_port(Config, client, Req),
- proc_lib:init_ack(Result2),
- unlink(Config#config.parent_pid),
- exit(normal);
- true ->
- %% Server
- close_port(Config, server, Req),
- exit(shutdown)
- end.
-
-close_port(Config, Who, Req) when is_record(Req, tftp_msg_req) ->
- case Config#config.udp_socket of
- undefined ->
- ignore;
- Socket ->
- print_debug_info(Config, Who, close, Req),
- gen_udp:close(Socket)
- end.
-
-open_free_port(Config, Who, Req) when is_record(Config, config), is_record(Req, tftp_msg_req) ->
- UdpOptions = Config#config.udp_options,
- case Config#config.port_policy of
- random ->
- %% BUGBUG: Should be a random port
- case catch gen_udp:open(0, UdpOptions) of
- {ok, Socket} ->
- Config2 = Config#config{udp_socket = Socket},
- print_debug_info(Config2, Who, open, Req),
- {ok, Config2};
- {error, Reason} ->
- Text = lists:flatten(io_lib:format("UDP open ~p -> ~p", [[0 | UdpOptions], Reason])),
- ?ERROR(open, undef, Text, Req#tftp_msg_req.filename);
- {'EXIT', _} = Reason ->
- Text = lists:flatten(io_lib:format("UDP open ~p -> ~p", [[0 | UdpOptions], Reason])),
- ?ERROR(open, undef, Text, Req#tftp_msg_req.filename)
- end;
- {range, Port, Max} when Port =< Max ->
- case catch gen_udp:open(Port, UdpOptions) of
- {ok, Socket} ->
- Config2 = Config#config{udp_socket = Socket},
- print_debug_info(Config2, Who, open, Req),
- {ok, Config2};
- {error, eaddrinuse} ->
- PortPolicy = {range, Port + 1, Max},
- Config2 = Config#config{port_policy = PortPolicy},
- open_free_port(Config2, Who, Req);
- {error, Reason} ->
- Text = lists:flatten(io_lib:format("UDP open ~p -> ~p", [[Port | UdpOptions], Reason])),
- ?ERROR(open, undef, Text, Req#tftp_msg_req.filename);
- {'EXIT', _} = Reason->
- Text = lists:flatten(io_lib:format("UDP open ~p -> ~p", [[Port | UdpOptions], Reason])),
- ?ERROR(open, undef, Text, Req#tftp_msg_req.filename)
- end;
- {range, Port, _Max} ->
- Reason = "Port range exhausted",
- Text = lists:flatten(io_lib:format("UDP open ~p -> ~p", [[Port | UdpOptions], Reason])),
- ?ERROR(Who, undef, Text, Req#tftp_msg_req.filename)
- end.
-
-%%-------------------------------------------------------------------
-%% Transfer
-%%-------------------------------------------------------------------
-
-%% Returns {Config, Callback, #transfer_res{}}
-transfer(Config, Callback, Req, Msg, LocalAccess, NextBlockNo, Prepared)
- when is_record(Prepared, prepared) ->
- IoList = tftp_lib:encode_msg(Msg),
- Retries = Config#config.max_retries + 1,
- do_transfer(Config, Callback, Req, Msg, IoList, LocalAccess, NextBlockNo, Prepared, Retries).
-
-do_transfer(Config, Callback, Req, Msg, IoList, LocalAccess, NextBlockNo, Prepared, Retries)
- when is_record(Prepared, prepared), is_integer(Retries), Retries >= 0 ->
- case do_send_msg(Config, Req, Msg, IoList) of
- ok ->
- {Callback2, Prepared2} =
- early_read(Config, Callback, Req, LocalAccess, NextBlockNo, Prepared),
- do_wait_for_msg_and_handle_timeout(Config, Callback2, Req, Msg, IoList, LocalAccess, NextBlockNo, Prepared2, Retries);
- {error, _Reason} when Retries > 0 ->
- Retries2 = 0, % Just retry once when send fails
- do_transfer(Config, Callback, Req, Msg, IoList, LocalAccess, NextBlockNo, Prepared, Retries2);
- {error, Reason} ->
- Code = undef,
- Text = lists:flatten(io_lib:format("Transfer failed - giving up -> ~p", [Reason])),
- Error = #tftp_msg_error{code = Code, text = Text},
- {Config, Callback, #transfer_res{status = error, prepared = Error}}
- end.
-
-wait_for_msg_and_handle_timeout(Config, Callback, Req, Msg, LocalAccess, NextBlockNo, Prepared) ->
- IoList = tftp_lib:encode_msg(Msg),
- Retries = Config#config.max_retries + 1,
- do_wait_for_msg_and_handle_timeout(Config, Callback, Req, Msg, IoList, LocalAccess, NextBlockNo, Prepared, Retries).
-
-do_wait_for_msg_and_handle_timeout(Config, Callback, Req, Msg, IoList, LocalAccess, NextBlockNo, Prepared, Retries) ->
- Code = undef,
- Text = "Transfer timed out.",
- case wait_for_msg(Config, Callback, Req) of
- timeout when Config#config.polite_ack =:= true ->
- do_send_msg(Config, Req, Msg, IoList),
- case Prepared of
- #prepared{status = terminate, result = Result} ->
- terminate(Config, Req, {ok, Result});
- #prepared{} ->
- terminate(Config, Req, ?ERROR(transfer, Code, Text, Req#tftp_msg_req.filename))
- end;
- timeout when Retries > 0 ->
- Retries2 = Retries - 1,
- do_transfer(Config, Callback, Req, Msg, IoList, LocalAccess, NextBlockNo, Prepared, Retries2);
- timeout ->
- Error = #tftp_msg_error{code = Code, text = Text},
- {Config, Callback, #transfer_res{status = error, prepared = Error}};
- {Config2, DecodedMsg} ->
- {Config2, Callback, #transfer_res{status = ok, decoded_msg = DecodedMsg, prepared = Prepared}}
- end.
-
-send_msg(Config, Req, Msg) ->
- case catch tftp_lib:encode_msg(Msg) of
- {'EXIT', Reason} ->
- Code = undef,
- Text = "Internal error. Encode failed",
- Msg2 = #tftp_msg_error{code = Code, text = Text, details = Reason},
- send_msg(Config, Req, Msg2);
- IoList ->
- do_send_msg(Config, Req, Msg, IoList)
- end.
-
-do_send_msg(#config{udp_socket = Socket, udp_host = RemoteHost, udp_port = RemotePort} = Config, Req, Msg, IoList) ->
- %% {ok, LocalPort} = inet:port(Socket),
- %% if
- %% LocalPort =/= ?TFTP_DEFAULT_PORT ->
- %% ok;
- %% true ->
- %% print_debug_info(Config#config{debug_level = all}, Req, send, Msg),
- %% error(Config,
- %% "Daemon replies from the default port (~p)\n\t to ~p:~p\n\t¨~p\n",
- %% [LocalPort, RemoteHost, RemotePort, Msg])
- %% end,
-
- print_debug_info(Config, Req, send, Msg),
-
- %% case os:getenv("TFTPDUMP") of
- %% false ->
- %% ignore;
- %% DumpPath ->
- %% trace_udp_send(Req, Msg, IoList, DumpPath)
- %% end,
- Res = gen_udp:send(Socket, RemoteHost, RemotePort, IoList),
- case Res of
- ok ->
- ok;
- {error, einval = Reason} ->
- error_msg(Config,
- "Stacktrace; ~p\n gen_udp:send(~p, ~p, ~p, ~p) -> ~p\n",
- [erlang:get_stacktrace(), Socket, RemoteHost, RemotePort, IoList, {error, Reason}]);
- {error, Reason} ->
- {error, Reason}
- end.
-
-%% trace_udp_send(#tftp_msg_req{filename = [$/ | RelFile]} = Req, Msg, IoList, DumpPath) ->
-%% trace_udp_send(Req#tftp_msg_req{filename = RelFile}, Msg, IoList, DumpPath);
-%% trace_udp_send(#tftp_msg_req{filename = RelFile},
-%% #tftp_msg_data{block_no = BlockNo, data = Data},
-%% _IoList,
-%% DumpPath) ->
-%% File = filename:join([DumpPath, RelFile, "block" ++ string:right(integer_to_list(BlockNo), 5, $0) ++ ".dump"]),
-%% if
-%% (BlockNo rem 1000) =:= 1 ->
-%% info_msg(Config, "TFTPDUMP: Data ~s\n", [File]);
-%% true ->
-%% ignore
-%% end,
-%% ok = filelib:ensure_dir(File),
-%% ok = file:write_file(File, Data);
-%% trace_udp_send(#tftp_msg_req{filename = RelFile}, Msg, _IoList, _DumpPath) ->
-%% info_msg(Config, "TFTPDUMP: No data ~s -> ~p\n", [RelFile, element(1, Msg)]).
-
-wait_for_msg(Config, Callback, Req) ->
- receive
- {udp, Socket, RemoteHost, RemotePort, Bin}
- when is_binary(Bin), Callback#callback.block_no =:= undefined ->
- %% Client prepare
- inet:setopts(Socket, [{active, once}]),
- Config2 = Config#config{udp_host = RemoteHost,
- udp_port = RemotePort},
- DecodedMsg = (catch tftp_lib:decode_msg(Bin)),
- print_debug_info(Config2, Req, recv, DecodedMsg),
- {Config2, DecodedMsg};
- {udp, Socket, Host, Port, Bin} when is_binary(Bin),
- Config#config.udp_host =:= Host,
- Config#config.udp_port =:= Port ->
- inet:setopts(Socket, [{active, once}]),
- DecodedMsg = (catch tftp_lib:decode_msg(Bin)),
- print_debug_info(Config, Req, recv, DecodedMsg),
- {Config, DecodedMsg};
- {info, Ref, FromPid} when is_pid(FromPid) ->
- Type =
- case Req#tftp_msg_req.local_filename =/= undefined of
- true -> client;
- false -> server
- end,
- Info = internal_info(Config, Type),
- reply({ok, Info}, Ref, FromPid),
- wait_for_msg(Config, Callback, Req);
- {{change_config, Options}, Ref, FromPid} when is_pid(FromPid) ->
- case catch tftp_lib:parse_config(Options, Config) of
- {'EXIT', Reason} ->
- reply({error, Reason}, Ref, FromPid),
- wait_for_msg(Config, Callback, Req);
- Config2 when is_record(Config2, config) ->
- reply(ok, Ref, FromPid),
- wait_for_msg(Config2, Callback, Req)
- end;
- {system, From, Msg} ->
- Misc = #sys_misc{module = ?MODULE, function = wait_for_msg, arguments = [Config, Callback, Req]},
- sys:handle_system_msg(Msg, From, Config#config.parent_pid, ?MODULE, [], Misc);
- {'EXIT', Pid, _Reason} when Config#config.parent_pid =:= Pid ->
- Code = undef,
- Text = "Parent exited.",
- terminate(Config, Req, ?ERROR(wait_for_msg, Code, Text, Req#tftp_msg_req.filename));
- Msg when Req#tftp_msg_req.local_filename =/= undefined ->
- warning_msg(Config, "Client received : ~p", [Msg]),
- wait_for_msg(Config, Callback, Req);
- Msg when Req#tftp_msg_req.local_filename =:= undefined ->
- warning_msg(Config, "Server received : ~p", [Msg]),
- wait_for_msg(Config, Callback, Req)
- after Config#config.timeout * 1000 ->
- print_debug_info(Config, Req, recv, timeout),
- timeout
- end.
-
-early_read(Config, Callback, Req, LocalAccess, _NextBlockNo,
- #prepared{status = Status, next_data = NextData, prev_data = PrevData} = Prepared) ->
- if
- Status =/= terminate,
- LocalAccess =:= read,
- Callback#callback.block_no =/= undefined,
- NextData =:= undefined ->
- case callback(read, Config, Callback, Req) of
- {undefined, Error} when is_record(Error, tftp_msg_error) ->
- {undefined, Error};
- {Callback2, Prepared2} when is_record(Prepared2, prepared)->
- {Callback2, Prepared2#prepared{prev_data = PrevData}}
- end;
- true ->
- {Callback, Prepared}
- end.
-
-%%-------------------------------------------------------------------
-%% Callback
-%%-------------------------------------------------------------------
-
-callback(Access, Config, Callback, Req) ->
- {Callback2, Result} =
- do_callback(Access, Config, Callback, Req),
- print_debug_info(Config, Req, call, {Callback2, Result}),
- {Callback2, Result}.
-
-do_callback(read = Fun, Config, Callback, Req)
- when is_record(Config, config),
- is_record(Callback, callback),
- is_record(Req, tftp_msg_req) ->
- Args = [Callback#callback.state],
- NextBlockNo = Callback#callback.block_no + 1,
- case catch safe_apply(Callback#callback.module, Fun, Args) of
- {more, Bin, NewState} when is_binary(Bin) ->
- Count = Callback#callback.count + size(Bin),
- Callback2 = Callback#callback{state = NewState,
- block_no = NextBlockNo,
- count = Count},
- Prepared = #prepared{status = more,
- result = undefined,
- block_no = NextBlockNo,
- next_data = Bin},
- verify_count(Config, Callback2, Req, Prepared);
- {last, Bin, Result} when is_binary(Bin) ->
- Prepared = #prepared{status = last,
- result = Result,
- block_no = NextBlockNo,
- next_data = Bin},
- {undefined, Prepared};
- {error, {Code, Text}} ->
- Error = #tftp_msg_error{code = Code, text = Text},
- Prepared = #prepared{status = error,
- result = Error},
- {undefined, Prepared};
- Illegal ->
- Code = undef,
- Text = "Internal error. File handler error.",
- callback({abort, {Code, Text, Illegal}}, Config, Callback, Req)
- end;
-do_callback({write = Fun, Bin}, Config, Callback, Req)
- when is_record(Config, config),
- is_record(Callback, callback),
- is_record(Req, tftp_msg_req),
- is_binary(Bin) ->
- Args = [Bin, Callback#callback.state],
- NextBlockNo = Callback#callback.block_no + 1,
- case catch safe_apply(Callback#callback.module, Fun, Args) of
- {more, NewState} ->
- Count = Callback#callback.count + size(Bin),
- Callback2 = Callback#callback{state = NewState,
- block_no = NextBlockNo,
- count = Count},
- Prepared = #prepared{status = more,
- block_no = NextBlockNo},
- verify_count(Config, Callback2, Req, Prepared);
- {last, Result} ->
- Prepared = #prepared{status = last,
- result = Result,
- block_no = NextBlockNo},
- {undefined, Prepared};
- {error, {Code, Text}} ->
- Error = #tftp_msg_error{code = Code, text = Text},
- Prepared = #prepared{status = error,
- result = Error},
- {undefined, Prepared};
- Illegal ->
- Code = undef,
- Text = "Internal error. File handler error.",
- callback({abort, {Code, Text, Illegal}}, Config, Callback, Req)
- end;
-do_callback({open, Type}, Config, Callback, Req)
- when is_record(Config, config),
- is_record(Callback, callback),
- is_record(Req, tftp_msg_req) ->
- {Access, Filename} = local_file_access(Req),
- {Fun, BlockNo} =
- case Type of
- client_prepare -> {prepare, undefined};
- client_open -> {open, 0};
- server_open -> {open, 0}
- end,
- Mod = Callback#callback.module,
- Args = [Access,
- Filename,
- Req#tftp_msg_req.mode,
- Req#tftp_msg_req.options,
- Callback#callback.state],
- PeerInfo = peer_info(Config),
- fast_ensure_loaded(Mod),
- Args2 =
- case erlang:function_exported(Mod, Fun, length(Args)) of
- true -> Args;
- false -> [PeerInfo | Args]
- end,
- case catch safe_apply(Mod, Fun, Args2) of
- {ok, AcceptedOptions, NewState} ->
- Callback2 = Callback#callback{state = NewState,
- block_no = BlockNo,
- count = 0},
- {Callback2, {ok, AcceptedOptions}};
- {error, {Code, Text}} ->
- {undefined, #tftp_msg_error{code = Code, text = Text}};
- Illegal ->
- Code = undef,
- Text = "Internal error. File handler error.",
- callback({abort, {Code, Text, Illegal}}, Config, Callback, Req)
- end;
-do_callback({abort, {Code, Text}}, Config, Callback, Req) ->
- Error = #tftp_msg_error{code = Code, text = Text},
- do_callback({abort, Error}, Config, Callback, Req);
-do_callback({abort, {Code, Text, Details}}, Config, Callback, Req) ->
- Error = #tftp_msg_error{code = Code, text = Text, details = Details},
- do_callback({abort, Error}, Config, Callback, Req);
-do_callback({abort = Fun, #tftp_msg_error{code = Code, text = Text} = Error}, Config, Callback, Req)
- when is_record(Config, config),
- is_record(Callback, callback),
- is_record(Req, tftp_msg_req) ->
- Args = [Code, Text, Callback#callback.state],
- catch safe_apply(Callback#callback.module, Fun, Args),
- {undefined, Error};
-do_callback({abort, Error}, _Config, undefined, _Req) when is_record(Error, tftp_msg_error) ->
- {undefined, Error}.
-
-peer_info(#config{udp_host = Host, udp_port = Port}) ->
- if
- is_tuple(Host), size(Host) =:= 4 ->
- {inet, tftp_lib:host_to_string(Host), Port};
- is_tuple(Host), size(Host) =:= 8 ->
- {inet6, tftp_lib:host_to_string(Host), Port};
- true ->
- {undefined, Host, Port}
- end.
-
-match_callback(Filename, Callbacks) ->
- if
- Filename =:= binary ->
- lookup_callback_mod(tftp_binary, Callbacks);
- is_binary(Filename) ->
- lookup_callback_mod(tftp_binary, Callbacks);
- true ->
- do_match_callback(Filename, Callbacks)
- end.
-
-do_match_callback(Filename, [C | Tail]) when is_record(C, callback) ->
- case catch re:run(Filename, C#callback.internal, [{capture, none}]) of
- match ->
- {ok, C};
- nomatch ->
- do_match_callback(Filename, Tail);
- Details ->
- Code = baduser,
- Text = "Internal error. File handler not found",
- {error, #tftp_msg_error{code = Code, text = Text, details = Details}}
- end;
-do_match_callback(Filename, []) ->
- Code = baduser,
- Text = "Internal error. File handler not found",
- {error, #tftp_msg_error{code = Code, text = Text, details = Filename}}.
-
-lookup_callback_mod(Mod, Callbacks) ->
- {value, C} = lists:keysearch(Mod, #callback.module, Callbacks),
- {ok, C}.
-
-verify_count(Config, Callback, Req, Result) ->
- case Config#config.max_tsize of
- infinity ->
- {Callback, Result};
- Max when Callback#callback.count =< Max ->
- {Callback, Result};
- _Max ->
- Code = enospc,
- Text = "Too large file.",
- callback({abort, {Code, Text}}, Config, Callback, Req)
- end.
-
-%%-------------------------------------------------------------------
-%% Miscellaneous
-%%-------------------------------------------------------------------
-
-internal_info(Config, Type) when is_record(Config, config) ->
- {ok, ActualPort} = inet:port(Config#config.udp_socket),
- [
- {type, Type},
- {host, tftp_lib:host_to_string(Config#config.udp_host)},
- {port, Config#config.udp_port},
- {local_port, ActualPort},
- {port_policy, Config#config.port_policy},
- {udp, Config#config.udp_options},
- {use_tsize, Config#config.use_tsize},
- {max_tsize, Config#config.max_tsize},
- {max_conn, Config#config.max_conn},
- {rejected, Config#config.rejected},
- {timeout, Config#config.timeout},
- {polite_ack, Config#config.polite_ack},
- {debug, Config#config.debug_level},
- {parent_pid, Config#config.parent_pid}
- ] ++ Config#config.user_options ++ Config#config.callbacks.
-
-local_file_access(#tftp_msg_req{access = Access,
- local_filename = Local,
- filename = Filename}) ->
- case Local =:= undefined of
- true ->
- %% Server side
- {Access, Filename};
- false ->
- %% Client side
- case Access of
- read -> {write, Local};
- write -> {read, Local}
- end
- end.
-
-pre_verify_options(Config, Req) ->
- Options = Req#tftp_msg_req.options,
- case catch verify_reject(Config, Req, Options) of
- ok ->
- case verify_integer("tsize", 0, Config#config.max_tsize, Options) of
- true ->
- case verify_integer("blksize", 0, 65464, Options) of
- true ->
- ok;
- false ->
- {error, {badopt, "Too large blksize"}}
- end;
- false ->
- {error, {badopt, "Too large tsize"}}
- end;
- {error, Reason} ->
- {error, Reason}
- end.
-
-post_verify_options(Config, Req, NewOptions, Text) ->
- OldOptions = Req#tftp_msg_req.options,
- BadOptions =
- [Key || {Key, _Val} <- NewOptions,
- not lists:keymember(Key, 1, OldOptions)],
- case BadOptions =:= [] of
- true ->
- Config2 = Config#config{timeout = lookup_timeout(NewOptions)},
- Req2 = Req#tftp_msg_req{options = NewOptions},
- {ok, Config2, Req2};
- false ->
- {error, {badopt, Text}}
- end.
-
-verify_reject(Config, Req, Options) ->
- Access = Req#tftp_msg_req.access,
- Rejected = Config#config.rejected,
- case lists:member(Access, Rejected) of
- true ->
- {error, {eacces, atom_to_list(Access) ++ " mode not allowed"}};
- false ->
- [throw({error, {badopt, Key ++ " not allowed"}}) ||
- {Key, _} <- Options, lists:member(Key, Rejected)],
- ok
- end.
-
-lookup_timeout(Options) ->
- case lists:keysearch("timeout", 1, Options) of
- {value, {_, Val}} ->
- list_to_integer(Val);
- false ->
- 3
- end.
-
-lookup_mode(Options) ->
- case lists:keysearch("mode", 1, Options) of
- {value, {_, Val}} ->
- Val;
- false ->
- "octet"
- end.
-
-verify_integer(Key, Min, Max, Options) ->
- case lists:keysearch(Key, 1, Options) of
- {value, {_, Val}} when is_list(Val) ->
- case catch list_to_integer(Val) of
- {'EXIT', _} ->
- false;
- Int when Int >= Min, is_integer(Min),
- Max =:= infinity ->
- true;
- Int when Int >= Min, is_integer(Min),
- Int =< Max, is_integer(Max) ->
- true;
- _ ->
- false
- end;
- false ->
- true
- end.
-
-error_msg(#config{logger = Logger, debug_level = _Level}, F, A) ->
- safe_apply(Logger, error_msg, [F, A]).
-
-warning_msg(#config{logger = Logger, debug_level = Level}, F, A) ->
- case Level of
- none -> ok;
- error -> ok;
- _ -> safe_apply(Logger, warning_msg, [F, A])
- end.
-
-info_msg(#config{logger = Logger}, F, A) ->
- safe_apply(Logger, info_msg, [F, A]).
-
-safe_apply(Mod, Fun, Args) ->
- fast_ensure_loaded(Mod),
- apply(Mod, Fun, Args).
-
-fast_ensure_loaded(Mod) ->
- case erlang:function_exported(Mod, module_info, 0) of
- true ->
- ok;
- false ->
- Res = code:load_file(Mod),
- %% io:format("tftp: code:load_file(~p) -> ~p\n", [Mod, Res]), %% XXX
- Res
- end.
-
-print_debug_info(#config{debug_level = Level} = Config, Who, Where, Data) ->
- if
- Level =:= none ->
- ok;
- is_record(Data, error) ->
- do_print_debug_info(Config, Who, Where, Data);
- Level =:= warning ->
- ok;
- Level =:= error ->
- ok;
- Level =:= all ->
- do_print_debug_info(Config, Who, Where, Data);
- Where =:= open ->
- do_print_debug_info(Config, Who, Where, Data);
- Where =:= close ->
- do_print_debug_info(Config, Who, Where, Data);
- Level =:= brief ->
- ok;
- Where =/= recv, Where =/= send ->
- ok;
- is_record(Data, tftp_msg_data), Level =:= normal ->
- ok;
- is_record(Data, tftp_msg_ack), Level =:= normal ->
- ok;
- true ->
- do_print_debug_info(Config, Who, Where, Data)
- end.
-
-do_print_debug_info(Config, Who, Where, #tftp_msg_data{data = Bin} = Msg) when is_binary(Bin) ->
- Msg2 = Msg#tftp_msg_data{data = {bytes, size(Bin)}},
- do_print_debug_info(Config, Who, Where, Msg2);
-do_print_debug_info(Config, Who, Where, #tftp_msg_req{local_filename = Filename} = Msg) when is_binary(Filename) ->
- Msg2 = Msg#tftp_msg_req{local_filename = binary},
- do_print_debug_info(Config, Who, Where, Msg2);
-do_print_debug_info(Config, Who, Where, Data) ->
- Local =
- case catch inet:port(Config#config.udp_socket) of
- {'EXIT', _Reason} ->
- 0;
- {ok, Port} ->
- Port
- end,
- %% Remote = Config#config.udp_port,
- PeerInfo = lists:flatten(io_lib:format("~p", [peer_info(Config)])),
- Side =
- if
- is_record(Who, tftp_msg_req),
- Who#tftp_msg_req.local_filename =/= undefined ->
- client;
- is_record(Who, tftp_msg_req),
- Who#tftp_msg_req.local_filename =:= undefined ->
- server;
- is_atom(Who) ->
- Who
- end,
- case {Where, Data} of
- {_, #error{where = Where, code = Code, text = Text, filename = Filename}} ->
- do_format(Config, Side, Local, "error ~s ->\n\t~p ~p\n\t~p ~p: ~s\n",
- [PeerInfo, self(), Filename, Where, Code, Text]);
- {open, #tftp_msg_req{filename = Filename}} ->
- do_format(Config, Side, Local, "open ~s ->\n\t~p ~p\n",
- [PeerInfo, self(), Filename]);
- {close, #tftp_msg_req{filename = Filename}} ->
- do_format(Config, Side, Local, "close ~s ->\n\t~p ~p\n",
- [PeerInfo, self(), Filename]);
- {recv, _} ->
- do_format(Config, Side, Local, "recv ~s <-\n\t~p\n",
- [PeerInfo, Data]);
- {send, _} ->
- do_format(Config, Side, Local, "send ~s ->\n\t~p\n",
- [PeerInfo, Data]);
- {match, _} when is_record(Data, callback) ->
- Mod = Data#callback.module,
- State = Data#callback.state,
- do_format(Config, Side, Local, "match ~s ~p =>\n\t~p\n",
- [PeerInfo, Mod, State]);
- {call, _} ->
- case Data of
- {Callback, _Result} when is_record(Callback, callback) ->
- Mod = Callback#callback.module,
- State = Callback#callback.state,
- do_format(Config, Side, Local, "call ~s ~p =>\n\t~p\n",
- [PeerInfo, Mod, State]);
- {undefined, Result} ->
- do_format(Config, Side, Local, "call ~s result =>\n\t~p\n",
- [PeerInfo, Result])
- end
- end.
-
-do_format(Config, Side, Local, Format, Args) ->
- info_msg(Config, "~p(~p): " ++ Format, [Side, Local | Args]).
-
-%%-------------------------------------------------------------------
-%% System upgrade
-%%-------------------------------------------------------------------
-
-system_continue(_Parent, _Debug, #sys_misc{module = Mod, function = Fun, arguments = Args}) ->
- apply(Mod, Fun, Args);
-system_continue(Parent, Debug, {Fun, Args}) ->
- %% Handle upgrade from old releases. Please, remove this clause in next release.
- system_continue(Parent, Debug, #sys_misc{module = ?MODULE, function = Fun, arguments = Args}).
-
--spec system_terminate(_, _, _, #sys_misc{} | {_, _}) -> no_return().
-
-system_terminate(Reason, _Parent, _Debug, #sys_misc{}) ->
- exit(Reason);
-system_terminate(Reason, Parent, Debug, {Fun, Args}) ->
- %% Handle upgrade from old releases. Please, remove this clause in next release.
- system_terminate(Reason, Parent, Debug, #sys_misc{module = ?MODULE, function = Fun, arguments = Args}).
-
-system_code_change({Fun, Args}, _Module, _OldVsn, _Extra) ->
- {ok, {Fun, Args}}.
diff --git a/lib/inets/src/tftp/tftp_file.erl b/lib/inets/src/tftp/tftp_file.erl
deleted file mode 100644
index 7664324808..0000000000
--- a/lib/inets/src/tftp/tftp_file.erl
+++ /dev/null
@@ -1,390 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
-%%%-------------------------------------------------------------------
-%%% File : tft_file.erl
-%%% Author : Hakan Mattsson <[email protected]>
-%%% Description :
-%%%
-%%% Created : 24 May 2004 by Hakan Mattsson <[email protected]>
-%%%-------------------------------------------------------------------
-
--module(tftp_file).
-
-%%%-------------------------------------------------------------------
-%%% Interface
-%%%-------------------------------------------------------------------
-
--behaviour(tftp).
-
--export([prepare/6, open/6, read/1, write/2, abort/3]).
-
-%%%-------------------------------------------------------------------
-%%% Defines
-%%%-------------------------------------------------------------------
-
--include_lib("kernel/include/file.hrl").
-
--record(initial,
- {filename,
- is_native_ascii}).
-
--record(state,
- {access,
- filename,
- is_native_ascii,
- is_network_ascii,
- root_dir,
- options,
- blksize,
- fd,
- count,
- buffer}).
-
-%%-------------------------------------------------------------------
-%% prepare(Peer, Access, Filename, Mode, SuggestedOptions, InitialState) ->
-%% {ok, AcceptedOptions, NewState} | {error, Code, Text}
-%%
-%% Peer = {PeerType, PeerHost, PeerPort}
-%% PeerType = inet | inet6
-%% PeerHost = ip_address()
-%% PeerPort = integer()
-%% Acess = read | write
-%% Filename = string()
-%% Mode = string()
-%% SuggestedOptions = [{Key, Value}]
-%% AcceptedOptions = [{Key, Value}]
-%% Key = string()
-%% Value = string()
-%% InitialState = [] | [{root_dir, string()}]
-%% NewState = term()
-%% Code = undef | enoent | eacces | enospc |
-%% badop | eexist | baduser | badopt |
-%% integer()
-%% Text = string()
-%%
-%% Prepares open of a file on the client side.
-%%
-%% Will be followed by a call to open/4 before any read/write access
-%% is performed. The AcceptedOptions will be sent to the server which
-%% will reply with those options that it accepts. The options that are
-%% accepted by the server will be forwarded to open/4 as SuggestedOptions.
-%%
-%% No new options may be added, but the ones that are present as
-%% SuggestedOptions may be omitted or replaced with new values
-%% in the AcceptedOptions.
-%%-------------------------------------------------------------------
-
-prepare(_Peer, Access, Filename, Mode, SuggestedOptions, Initial) when is_list(Initial) ->
- %% Client side
- case catch handle_options(Access, Filename, Mode, SuggestedOptions, Initial) of
- {ok, Filename2, IsNativeAscii, IsNetworkAscii, AcceptedOptions} ->
- State = #state{access = Access,
- filename = Filename2,
- is_native_ascii = IsNativeAscii,
- is_network_ascii = IsNetworkAscii,
- options = AcceptedOptions,
- blksize = lookup_blksize(AcceptedOptions),
- count = 0,
- buffer = []},
- {ok, AcceptedOptions, State};
- {error, {Code, Text}} ->
- {error, {Code, Text}}
- end.
-
-%% ---------------------------------------------------------
-%% open(Peer, Access, Filename, Mode, SuggestedOptions, State) ->
-%% {ok, AcceptedOptions, NewState} | {error, Code, Text}
-%%
-%% Peer = {PeerType, PeerHost, PeerPort}
-%% PeerType = inet | inet6
-%% PeerHost = ip_address()
-%% PeerPort = integer()
-%% Acess = read | write
-%% Filename = string()
-%% Mode = string()
-%% SuggestedOptions = [{Key, Value}]
-%% AcceptedOptions = [{Key, Value}]
-%% Key = string()
-%% Value = string()
-%% State = InitialState | #state{}
-%% InitialState = [] | [{root_dir, string()}]
-%% NewState = term()
-%% Code = undef | enoent | eacces | enospc |
-%% badop | eexist | baduser | badopt |
-%% integer()
-%% Text = string()
-%%
-%% Opens a file for read or write access.
-%%
-%% On the client side where the open/4 call has been preceeded by a
-%% call to prepare/4, all options must be accepted or rejected.
-%% On the server side, where there are no preceeding prepare/4 call,
-%% noo new options may be added, but the ones that are present as
-%% SuggestedOptions may be omitted or replaced with new values
-%% in the AcceptedOptions.
-%%-------------------------------------------------------------------
-
-open(Peer, Access, Filename, Mode, SuggestedOptions, Initial) when is_list(Initial) ->
- %% Server side
- case prepare(Peer, Access, Filename, Mode, SuggestedOptions, Initial) of
- {ok, AcceptedOptions, State} ->
- open(Peer, Access, Filename, Mode, AcceptedOptions, State);
- {error, {Code, Text}} ->
- {error, {Code, Text}}
- end;
-open(_Peer, Access, Filename, Mode, NegotiatedOptions, State) when is_record(State, state) ->
- %% Both sides
- case catch handle_options(Access, Filename, Mode, NegotiatedOptions, State) of
- {ok, _Filename2, _IsNativeAscii, _IsNetworkAscii, Options}
- when Options =:= NegotiatedOptions ->
- do_open(State);
- {error, {Code, Text}} ->
- {error, {Code, Text}}
- end;
-open(Peer, Access, Filename, Mode, NegotiatedOptions, State) ->
- %% Handle upgrade from old releases. Please, remove this clause in next release.
- State2 = upgrade_state(State),
- open(Peer, Access, Filename, Mode, NegotiatedOptions, State2).
-
-do_open(State) when is_record(State, state) ->
- case file:open(State#state.filename, file_options(State)) of
- {ok, Fd} ->
- {ok, State#state.options, State#state{fd = Fd}};
- {error, Reason} when is_atom(Reason) ->
- {error, file_error(Reason)}
- end.
-
-file_options(State) ->
- case State#state.access of
- read -> [read, read_ahead, raw, binary];
- write -> [write, delayed_write, raw, binary]
- end.
-
-file_error(Reason) when is_atom(Reason) ->
- Details = file:format_error(Reason),
- case Reason of
- eexist -> {Reason, Details};
- enoent -> {Reason, Details};
- eacces -> {Reason, Details};
- eperm -> {eacces, Details};
- enospc -> {Reason, Details};
- _ -> {undef, Details ++ " (" ++ atom_to_list(Reason) ++ ")"}
- end.
-
-%%-------------------------------------------------------------------
-%% read(State) ->
-%% {more, Bin, NewState} | {last, Bin, FileSize} | {error, {Code, Text}}
-%%
-%% State = term()
-%% NewState = term()
-%% Bin = binary()
-%% FileSize = integer()
-%% Code = undef | enoent | eacces | enospc |
-%% badop | eexist | baduser | badopt |
-%% integer()
-%% Text = string()
-%%
-%% Reads a chunk from the file
-%%
-%% The file is automatically closed when the last chunk is read.
-%%-------------------------------------------------------------------
-
-read(#state{access = read} = State) ->
- BlkSize = State#state.blksize,
- case file:read(State#state.fd, BlkSize) of
- {ok, Bin} when is_binary(Bin), size(Bin) =:= BlkSize ->
- Count = State#state.count + size(Bin),
- {more, Bin, State#state{count = Count}};
- {ok, Bin} when is_binary(Bin), size(Bin) < BlkSize ->
- file:close(State#state.fd),
- Count = State#state.count + size(Bin),
- {last, Bin, Count};
- eof ->
- {last, <<>>, State#state.count};
- {error, Reason} ->
- file:close(State#state.fd),
- {error, file_error(Reason)}
- end;
-read(State) ->
- %% Handle upgrade from old releases. Please, remove this clause in next release.
- State2 = upgrade_state(State),
- read(State2).
-
-%%-------------------------------------------------------------------
-%% write(Bin, State) ->
-%% {more, NewState} | {last, FileSize} | {error, {Code, Text}}
-%%
-%% State = term()
-%% NewState = term()
-%% Bin = binary()
-%% FileSize = integer()
-%% Code = undef | enoent | eacces | enospc |
-%% badop | eexist | baduser | badopt |
-%% integer()
-%% Text = string()
-%%
-%% Writes a chunk to the file
-%%
-%% The file is automatically closed when the last chunk is written
-%%-------------------------------------------------------------------
-
-write(Bin, #state{access = write} = State) when is_binary(Bin) ->
- Size = size(Bin),
- BlkSize = State#state.blksize,
- case file:write(State#state.fd, Bin) of
- ok when Size =:= BlkSize->
- Count = State#state.count + Size,
- {more, State#state{count = Count}};
- ok when Size < BlkSize->
- file:close(State#state.fd),
- Count = State#state.count + Size,
- {last, Count};
- {error, Reason} ->
- file:close(State#state.fd),
- file:delete(State#state.filename),
- {error, file_error(Reason)}
- end;
-write(Bin, State) ->
- %% Handle upgrade from old releases. Please, remove this clause in next release.
- State2 = upgrade_state(State),
- write(Bin, State2).
-
-%%-------------------------------------------------------------------
-%% abort(Code, Text, State) -> ok
-%%
-%% State = term()
-%% Code = undef | enoent | eacces | enospc |
-%% badop | eexist | baduser | badopt |
-%% badblk | integer()
-%% Text = string()
-%%
-%% Aborts the file transfer
-%%-------------------------------------------------------------------
-
-abort(_Code, _Text, #state{fd = Fd, access = Access} = State) ->
- file:close(Fd),
- case Access of
- write ->
- ok = file:delete(State#state.filename);
- read ->
- ok
- end.
-
-%%-------------------------------------------------------------------
-%% Process options
-%%-------------------------------------------------------------------
-
-handle_options(Access, Filename, Mode, Options, Initial) ->
- I = #initial{filename = Filename, is_native_ascii = is_native_ascii()},
- {Filename2, IsNativeAscii} = handle_initial(Initial, I),
- IsNetworkAscii = handle_mode(Mode, IsNativeAscii),
- Options2 = do_handle_options(Access, Filename2, Options),
- {ok, Filename2, IsNativeAscii, IsNetworkAscii, Options2}.
-
-handle_mode(Mode, IsNativeAscii) ->
- case Mode of
- "netascii" when IsNativeAscii =:= true -> true;
- "octet" -> false;
- _ -> throw({error, {badop, "Illegal mode " ++ Mode}})
- end.
-
-handle_initial([{root_dir, Dir} | Initial], I) ->
- case catch filename_join(Dir, I#initial.filename) of
- {'EXIT', _} ->
- throw({error, {badop, "Internal error. root_dir is not a string"}});
- Filename2 ->
- handle_initial(Initial, I#initial{filename = Filename2})
- end;
-handle_initial([{native_ascii, Bool} | Initial], I) ->
- case Bool of
- true -> handle_initial(Initial, I#initial{is_native_ascii = true});
- false -> handle_initial(Initial, I#initial{is_native_ascii = false})
- end;
-handle_initial([], I) when is_record(I, initial) ->
- {I#initial.filename, I#initial.is_native_ascii};
-handle_initial(State, _) when is_record(State, state) ->
- {State#state.filename, State#state.is_native_ascii}.
-
-filename_join(Dir, Filename) ->
- case filename:pathtype(Filename) of
- absolute ->
- [_ | RelFilename] = filename:split(Filename),
- filename:join([Dir, RelFilename]);
- _ ->
- filename:join([Dir, Filename])
- end.
-
-do_handle_options(Access, Filename, [{Key, Val} | T]) ->
- case Key of
- "tsize" ->
- case Access of
- read when Val =:= "0" ->
- case file:read_file_info(Filename) of
- {ok, FI} ->
- Tsize = integer_to_list(FI#file_info.size),
- [{Key, Tsize} | do_handle_options(Access, Filename, T)];
- {error, _} ->
- do_handle_options(Access, Filename, T)
- end;
- _ ->
- handle_integer(Access, Filename, Key, Val, T, 0, infinity)
- end;
- "blksize" ->
- handle_integer(Access, Filename, Key, Val, T, 8, 65464);
- "timeout" ->
- handle_integer(Access, Filename, Key, Val, T, 1, 255);
- _ ->
- do_handle_options(Access, Filename, T)
- end;
-do_handle_options(_Access, _Filename, []) ->
- [].
-
-
-handle_integer(Access, Filename, Key, Val, Options, Min, Max) ->
- case catch list_to_integer(Val) of
- {'EXIT', _} ->
- do_handle_options(Access, Filename, Options);
- Int when Int >= Min, Int =< Max ->
- [{Key, Val} | do_handle_options(Access, Filename, Options)];
- Int when Int >= Min, Max =:= infinity ->
- [{Key, Val} | do_handle_options(Access, Filename, Options)];
- _Int ->
- throw({error, {badopt, "Illegal " ++ Key ++ " value " ++ Val}})
- end.
-
-lookup_blksize(Options) ->
- case lists:keysearch("blksize", 1, Options) of
- {value, {_, Val}} ->
- list_to_integer(Val);
- false ->
- 512
- end.
-
-is_native_ascii() ->
- case os:type() of
- {win32, _} -> true;
- _ -> false
- end.
-
-%% Handle upgrade from old releases. Please, remove this function in next release.
-upgrade_state({state, Access, Filename, RootDir, Options, BlkSize, Fd, Count, Buffer}) ->
- {state, Access, Filename, false, false, RootDir, Options, BlkSize, Fd, Count, Buffer}.
diff --git a/lib/inets/src/tftp/tftp_lib.erl b/lib/inets/src/tftp/tftp_lib.erl
deleted file mode 100644
index 454754f0a3..0000000000
--- a/lib/inets/src/tftp/tftp_lib.erl
+++ /dev/null
@@ -1,474 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
-%%%-------------------------------------------------------------------
-%%% File : tftp_lib.erl
-%%% Author : Hakan Mattsson <[email protected]>
-%%% Description : Option parsing, decode, encode etc.
-%%%
-%%% Created : 18 May 2004 by Hakan Mattsson <[email protected]>
-%%%-------------------------------------------------------------------
-
--module(tftp_lib).
-
-%%-------------------------------------------------------------------
-%% Interface
-%%-------------------------------------------------------------------
-
-%% application internal functions
--export([
- parse_config/1,
- parse_config/2,
- decode_msg/1,
- encode_msg/1,
- replace_val/3,
- to_lower/1,
- host_to_string/1,
- add_default_callbacks/1
- ]).
-
-%%-------------------------------------------------------------------
-%% Defines
-%%-------------------------------------------------------------------
-
--include("tftp.hrl").
-
--define(LOWER(Char),
- if
- Char >= $A, Char =< $Z ->
- Char - ($A - $a);
- true ->
- Char
- end).
-
-%%-------------------------------------------------------------------
-%% Config
-%%-------------------------------------------------------------------
-
-parse_config(Options) ->
- parse_config(Options, #config{}).
-
-parse_config(Options, Config) ->
- do_parse_config(Options, Config).
-
-do_parse_config([{Key, Val} | Tail], Config) when is_record(Config, config) ->
- case Key of
- debug ->
- if
- Val =:= 0; Val =:= none ->
- do_parse_config(Tail, Config#config{debug_level = none});
- Val =:= 1; Val =:= error ->
- do_parse_config(Tail, Config#config{debug_level = error});
- Val =:= 2; Val =:= warning ->
- do_parse_config(Tail, Config#config{debug_level = warning});
- Val =:= 3; Val =:= brief ->
- do_parse_config(Tail, Config#config{debug_level = brief});
- Val =:= 4; Val =:= normal ->
- do_parse_config(Tail, Config#config{debug_level = normal});
- Val =:= 5; Val =:= verbose ->
- do_parse_config(Tail, Config#config{debug_level = verbose});
- Val =:= 6; Val =:= all ->
- do_parse_config(Tail, Config#config{debug_level = all});
- true ->
- exit({badarg, {Key, Val}})
- end;
- host ->
- if
- is_list(Val) ->
- do_parse_config(Tail, Config#config{udp_host = Val});
- is_tuple(Val), size(Val) =:= 4 ->
- do_parse_config(Tail, Config#config{udp_host = Val});
- is_tuple(Val), size(Val) =:= 8 ->
- do_parse_config(Tail, Config#config{udp_host = Val});
- true ->
- exit({badarg, {Key, Val}})
- end;
- port ->
- if
- is_integer(Val), Val >= 0 ->
- Config2 = Config#config{udp_port = Val, udp_options = Config#config.udp_options},
- do_parse_config(Tail, Config2);
- true ->
- exit({badarg, {Key, Val}})
- end;
- port_policy ->
- case Val of
- random ->
- do_parse_config(Tail, Config#config{port_policy = Val});
- 0 ->
- do_parse_config(Tail, Config#config{port_policy = random});
- MinMax when is_integer(MinMax), MinMax > 0 ->
- do_parse_config(Tail, Config#config{port_policy = {range, MinMax, MinMax}});
- {range, Min, Max} when Max >= Min,
- is_integer(Min), Min > 0,
- is_integer(Max), Max > 0 ->
- do_parse_config(Tail, Config#config{port_policy = Val});
- true ->
- exit({badarg, {Key, Val}})
- end;
- udp when is_list(Val) ->
- Fun =
- fun({K, V}, List) when K /= active ->
- replace_val(K, V, List);
- (V, List) when V /= list, V /= binary ->
- List ++ [V];
- (V, _List) ->
- exit({badarg, {udp, [V]}})
- end,
- UdpOptions = lists:foldl(Fun, Config#config.udp_options, Val),
- do_parse_config(Tail, Config#config{udp_options = UdpOptions});
- use_tsize ->
- case Val of
- true ->
- do_parse_config(Tail, Config#config{use_tsize = Val});
- false ->
- do_parse_config(Tail, Config#config{use_tsize = Val});
- _ ->
- exit({badarg, {Key, Val}})
- end;
- max_tsize ->
- if
- Val =:= infinity ->
- do_parse_config(Tail, Config#config{max_tsize = Val});
- is_integer(Val), Val >= 0 ->
- do_parse_config(Tail, Config#config{max_tsize = Val});
- true ->
- exit({badarg, {Key, Val}})
- end;
- max_conn ->
- if
- Val =:= infinity ->
- do_parse_config(Tail, Config#config{max_conn = Val});
- is_integer(Val), Val > 0 ->
- do_parse_config(Tail, Config#config{max_conn = Val});
- true ->
- exit({badarg, {Key, Val}})
- end;
- _ when is_list(Key), is_list(Val) ->
- Key2 = to_lower(Key),
- Val2 = to_lower(Val),
- TftpOptions = replace_val(Key2, Val2, Config#config.user_options),
- do_parse_config(Tail, Config#config{user_options = TftpOptions});
- reject ->
- case Val of
- read ->
- Rejected = [Val | Config#config.rejected],
- do_parse_config(Tail, Config#config{rejected = Rejected});
- write ->
- Rejected = [Val | Config#config.rejected],
- do_parse_config(Tail, Config#config{rejected = Rejected});
- _ when is_list(Val) ->
- Rejected = [Val | Config#config.rejected],
- do_parse_config(Tail, Config#config{rejected = Rejected});
- _ ->
- exit({badarg, {Key, Val}})
- end;
- callback ->
- case Val of
- {RegExp, Mod, State} when is_list(RegExp), is_atom(Mod) ->
- case re:compile(RegExp) of
- {ok, Internal} ->
- Callback = #callback{regexp = RegExp,
- internal = Internal,
- module = Mod,
- state = State},
- Callbacks = Config#config.callbacks ++ [Callback],
- do_parse_config(Tail, Config#config{callbacks = Callbacks});
- {error, Reason} ->
- exit({badarg, {Key, Val}, Reason})
- end;
- _ ->
- exit({badarg, {Key, Val}})
- end;
- logger ->
- if
- is_atom(Val) ->
- do_parse_config(Tail, Config#config{logger = Val});
- true ->
- exit({badarg, {Key, Val}})
- end;
- max_retries ->
- if
- is_integer(Val), Val > 0 ->
- do_parse_config(Tail, Config#config{max_retries = Val});
- true ->
- exit({badarg, {Key, Val}})
- end;
- _ ->
- exit({badarg, {Key, Val}})
- end;
-do_parse_config([], #config{udp_host = Host,
- udp_options = UdpOptions,
- user_options = UserOptions,
- callbacks = Callbacks} = Config) ->
- IsInet6 = lists:member(inet6, UdpOptions),
- IsInet = lists:member(inet, UdpOptions),
- Host2 =
- if
- (IsInet and not IsInet6); (not IsInet and not IsInet6) ->
- case inet:getaddr(Host, inet) of
- {ok, Addr} ->
- Addr;
- {error, Reason} ->
- exit({badarg, {host, Reason}})
- end;
- (IsInet6 and not IsInet) ->
- case inet:getaddr(Host, inet6) of
- {ok, Addr} ->
- Addr;
- {error, Reason} ->
- exit({badarg, {host, Reason}})
- end;
- true ->
- %% Conflicting options
- exit({badarg, {udp, [inet]}})
- end,
- UdpOptions2 = lists:reverse(UdpOptions),
- TftpOptions = lists:reverse(UserOptions),
- Callbacks2 = add_default_callbacks(Callbacks),
- Config#config{udp_host = Host2,
- udp_options = UdpOptions2,
- user_options = TftpOptions,
- callbacks = Callbacks2};
-do_parse_config(Options, Config) when is_record(Config, config) ->
- exit({badarg, Options}).
-
-add_default_callbacks(Callbacks) ->
- RegExp = "",
- {ok, Internal} = re:compile(RegExp),
- File = #callback{regexp = RegExp,
- internal = Internal,
- module = tftp_file,
- state = []},
- Bin = #callback{regexp = RegExp,
- internal = Internal,
- module = tftp_binary,
- state = []},
- Callbacks ++ [File, Bin].
-
-host_to_string(Host) ->
- case Host of
- String when is_list(String) ->
- String;
- {A1, A2, A3, A4} -> % inet
- lists:concat([A1, ".", A2, ".", A3, ".",A4]);
- {A1, A2, A3, A4, A5, A6, A7, A8} -> % inet6
- lists:concat([
- int16_to_hex(A1), "::",
- int16_to_hex(A2), "::",
- int16_to_hex(A3), "::",
- int16_to_hex(A4), "::",
- int16_to_hex(A5), "::",
- int16_to_hex(A6), "::",
- int16_to_hex(A7), "::",
- int16_to_hex(A8)
- ])
- end.
-
-int16_to_hex(0) ->
- [$0];
-int16_to_hex(I) ->
- N1 = ((I bsr 8) band 16#ff),
- N2 = (I band 16#ff),
- [code_character(N1 div 16), code_character(N1 rem 16),
- code_character(N2 div 16), code_character(N2 rem 16)].
-
-code_character(N) when N < 10 ->
- $0 + N;
-code_character(N) ->
- $A + (N - 10).
-
-%%-------------------------------------------------------------------
-%% Decode
-%%-------------------------------------------------------------------
-
-decode_msg(Bin) when is_binary(Bin) ->
- case Bin of
- <<?TFTP_OPCODE_RRQ:16/integer, Tail/binary>> ->
- case decode_strings(Tail, [keep_case, lower_case]) of
- [Filename, Mode | Strings] ->
- Options = decode_options(Strings),
- #tftp_msg_req{access = read,
- filename = Filename,
- mode = to_lower(Mode),
- options = Options};
- [_Filename | _Strings] ->
- exit(#tftp_msg_error{code = undef,
- text = "Missing mode"});
- _ ->
- exit(#tftp_msg_error{code = undef,
- text = "Missing filename"})
- end;
- <<?TFTP_OPCODE_WRQ:16/integer, Tail/binary>> ->
- case decode_strings(Tail, [keep_case, lower_case]) of
- [Filename, Mode | Strings] ->
- Options = decode_options(Strings),
- #tftp_msg_req{access = write,
- filename = Filename,
- mode = to_lower(Mode),
- options = Options};
- [_Filename | _Strings] ->
- exit(#tftp_msg_error{code = undef,
- text = "Missing mode"});
- _ ->
- exit(#tftp_msg_error{code = undef,
- text = "Missing filename"})
- end;
- <<?TFTP_OPCODE_DATA:16/integer, SeqNo:16/integer, Data/binary>> ->
- #tftp_msg_data{block_no = SeqNo, data = Data};
- <<?TFTP_OPCODE_ACK:16/integer, SeqNo:16/integer>> ->
- #tftp_msg_ack{block_no = SeqNo};
- <<?TFTP_OPCODE_ERROR:16/integer, ErrorCode:16/integer, Tail/binary>> ->
- case decode_strings(Tail, [keep_case]) of
- [ErrorText] ->
- ErrorCode2 = decode_error_code(ErrorCode),
- #tftp_msg_error{code = ErrorCode2,
- text = ErrorText};
- _ ->
- exit(#tftp_msg_error{code = undef,
- text = "Trailing garbage"})
- end;
- <<?TFTP_OPCODE_OACK:16/integer, Tail/binary>> ->
- Strings = decode_strings(Tail, [lower_case]),
- Options = decode_options(Strings),
- #tftp_msg_oack{options = Options};
- _ ->
- exit(#tftp_msg_error{code = undef,
- text = "Invalid syntax"})
- end.
-
-decode_strings(Bin, Cases) when is_binary(Bin), is_list(Cases) ->
- do_decode_strings(Bin, Cases, []).
-
-do_decode_strings(<<>>, _Cases, Strings) ->
- lists:reverse(Strings);
-do_decode_strings(Bin, [Case | Cases], Strings) ->
- {String, Tail} = decode_string(Bin, Case, []),
- if
- Cases =:= [] ->
- do_decode_strings(Tail, [Case], [String | Strings]);
- true ->
- do_decode_strings(Tail, Cases, [String | Strings])
- end.
-
-decode_string(<<Char:8/integer, Tail/binary>>, Case, String) ->
- if
- Char =:= 0 ->
- {lists:reverse(String), Tail};
- Case =:= keep_case ->
- decode_string(Tail, Case, [Char | String]);
- Case =:= lower_case ->
- Char2 = ?LOWER(Char),
- decode_string(Tail, Case, [Char2 | String])
- end;
-decode_string(<<>>, _Case, _String) ->
- exit(#tftp_msg_error{code = undef, text = "Trailing null missing"}).
-
-decode_options([Key, Value | Strings]) ->
- [{to_lower(Key), Value} | decode_options(Strings)];
-decode_options([]) ->
- [].
-
-decode_error_code(Int) ->
- case Int of
- ?TFTP_ERROR_UNDEF -> undef;
- ?TFTP_ERROR_ENOENT -> enoent;
- ?TFTP_ERROR_EACCES -> eacces;
- ?TFTP_ERROR_ENOSPC -> enospc;
- ?TFTP_ERROR_BADOP -> badop;
- ?TFTP_ERROR_BADBLK -> badblk;
- ?TFTP_ERROR_EEXIST -> eexist;
- ?TFTP_ERROR_BADUSER -> baduser;
- ?TFTP_ERROR_BADOPT -> badopt;
- Int when is_integer(Int), Int >= 0, Int =< 65535 -> Int;
- _ -> exit(#tftp_msg_error{code = undef, text = "Error code outside range."})
- end.
-
-%%-------------------------------------------------------------------
-%% Encode
-%%-------------------------------------------------------------------
-
-encode_msg(#tftp_msg_req{access = Access,
- filename = Filename,
- mode = Mode,
- options = Options}) ->
- OpCode = case Access of
- read -> ?TFTP_OPCODE_RRQ;
- write -> ?TFTP_OPCODE_WRQ
- end,
- [
- <<OpCode:16/integer>>,
- Filename,
- 0,
- Mode,
- 0,
- [[Key, 0, Val, 0] || {Key, Val} <- Options]
- ];
-encode_msg(#tftp_msg_data{block_no = BlockNo, data = Data}) when BlockNo =< 65535 ->
- [
- <<?TFTP_OPCODE_DATA:16/integer, BlockNo:16/integer>>,
- Data
- ];
-encode_msg(#tftp_msg_ack{block_no = BlockNo}) when BlockNo =< 65535 ->
- <<?TFTP_OPCODE_ACK:16/integer, BlockNo:16/integer>>;
-encode_msg(#tftp_msg_error{code = Code, text = Text}) ->
- IntCode = encode_error_code(Code),
- [
- <<?TFTP_OPCODE_ERROR:16/integer, IntCode:16/integer>>,
- Text,
- 0
- ];
-encode_msg(#tftp_msg_oack{options = Options}) ->
- [
- <<?TFTP_OPCODE_OACK:16/integer>>,
- [[Key, 0, Val, 0] || {Key, Val} <- Options]
- ].
-
-encode_error_code(Code) ->
- case Code of
- undef -> ?TFTP_ERROR_UNDEF;
- enoent -> ?TFTP_ERROR_ENOENT;
- eacces -> ?TFTP_ERROR_EACCES;
- enospc -> ?TFTP_ERROR_ENOSPC;
- badop -> ?TFTP_ERROR_BADOP;
- badblk -> ?TFTP_ERROR_BADBLK;
- eexist -> ?TFTP_ERROR_EEXIST;
- baduser -> ?TFTP_ERROR_BADUSER;
- badopt -> ?TFTP_ERROR_BADOPT;
- Int when is_integer(Int), Int >= 0, Int =< 65535 -> Int
- end.
-
-%%-------------------------------------------------------------------
-%% Miscellaneous
-%%-------------------------------------------------------------------
-
-replace_val(Key, Val, List) ->
- case lists:keysearch(Key, 1, List) of
- false ->
- List ++ [{Key, Val}];
- {value, {_, OldVal}} when OldVal =:= Val ->
- List;
- {value, {_, _}} ->
- lists:keyreplace(Key, 1, List, {Key, Val})
- end.
-
-to_lower(Chars) ->
- [?LOWER(Char) || Char <- Chars].
diff --git a/lib/inets/src/tftp/tftp_logger.erl b/lib/inets/src/tftp/tftp_logger.erl
deleted file mode 100644
index a869958484..0000000000
--- a/lib/inets/src/tftp/tftp_logger.erl
+++ /dev/null
@@ -1,99 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(tftp_logger).
-
-%%-------------------------------------------------------------------
-%% Interface
-%%-------------------------------------------------------------------
-
-%% public functions
--export([
- error_msg/2,
- warning_msg/2,
- info_msg/2
- ]).
-
--export([behaviour_info/1]).
-
-behaviour_info(callbacks) ->
- [{error_msg, 2}, {warning_msg, 2}, {info_msg, 2}];
-behaviour_info(_) ->
- undefined.
-
-%%-------------------------------------------------------------------
-%% error_msg(Format, Data) -> ok | exit(Reason)
-%%
-%% Format = string()
-%% Data = [term()]
-%% Reason = term()
-%%
-%% Log an error message
-%%-------------------------------------------------------------------
-
-error_msg(Format, Data) ->
- {Format2, Data2} = add_timestamp(Format, Data),
- error_logger:error_msg(Format2, Data2).
-
-%%-------------------------------------------------------------------
-%% warning_msg(Format, Data) -> ok | exit(Reason)
-%%
-%% Format = string()
-%% Data = [term()]
-%% Reason = term()
-%%
-%% Log a warning message
-%%-------------------------------------------------------------------
-
-warning_msg(Format, Data) ->
- {Format2, Data2} = add_timestamp(Format, Data),
- error_logger:warning_msg(Format2, Data2).
-
-%%-------------------------------------------------------------------
-%% info_msg(Format, Data) -> ok | exit(Reason)
-%%
-%% Format = string()
-%% Data = [term()]
-%% Reason = term()
-%%
-%% Log an info message
-%%-------------------------------------------------------------------
-
-info_msg(Format, Data) ->
- {Format2, Data2} = add_timestamp(Format, Data),
- io:format(Format2, Data2).
-
-%%-------------------------------------------------------------------
-%% Add timestamp to log message
-%%-------------------------------------------------------------------
-
-add_timestamp(Format, Data) ->
- Time = erlang:timestamp(),
- {{_Y, _Mo, _D}, {H, Mi, S}} = calendar:now_to_universal_time(Time),
- %% {"~p-~s-~sT~s:~s:~sZ,~6.6.0w tftp: " ++ Format ++ "\n",
- %% [Y, t(Mo), t(D), t(H), t(Mi), t(S), MicroSecs | Data]}.
- {"~s:~s:~s tftp: " ++ Format, [t(H), t(Mi), t(S) | Data]}.
-
-%% Convert 9 to "09".
-t(Int) ->
- case integer_to_list(Int) of
- [Single] -> [$0, Single];
- Multi -> Multi
- end.
diff --git a/lib/inets/src/tftp/tftp_sup.erl b/lib/inets/src/tftp/tftp_sup.erl
deleted file mode 100644
index 40b67c499c..0000000000
--- a/lib/inets/src/tftp/tftp_sup.erl
+++ /dev/null
@@ -1,111 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% Purpose: The top supervisor for tftp hangs under inets_sup.
-%%----------------------------------------------------------------------
-
--module(tftp_sup).
-
--behaviour(supervisor).
-
-%% API
--export([start_link/1,
- start_child/1,
- stop_child/1,
- which_children/0]).
-
-%% Supervisor callback
--export([init/1]).
-
-%%%=========================================================================
-%%% API
-%%%=========================================================================
-
-start_link(TftpServices) ->
- supervisor:start_link({local, ?MODULE}, ?MODULE, [TftpServices]).
-
-start_child(Options) ->
- KillAfter = default_kill_after(),
- ChildSpec = worker_spec(KillAfter, Options),
- supervisor:start_child(?MODULE, ChildSpec).
-
-stop_child(Pid) when is_pid(Pid) ->
- Children = supervisor:which_children(?MODULE),
- case [Id || {Id, P, _Type, _Modules} <- Children, P =:= Pid] of
- [] ->
- {error, not_found};
- [Id] ->
- case supervisor:terminate_child(?MODULE, Id) of
- ok ->
- supervisor:delete_child(?MODULE, Id);
- {error, not_found} ->
- supervisor:delete_child(?MODULE, Id);
- {error, Reason} ->
- {error, Reason}
- end
- end.
-
-which_children() ->
- Children = supervisor:which_children(?MODULE),
- [{tftpd, Pid} || {_Id, Pid, _Type, _Modules} <- Children, Pid =/= undefined].
-
-%%%=========================================================================
-%%% Supervisor callback
-%%%=========================================================================
-
-init([Services]) when is_list(Services) ->
- RestartStrategy = one_for_one,
- MaxR = 10,
- MaxT = 3600,
- KillAfter = default_kill_after(),
- Children = [worker_spec(KillAfter, Options) || {tftpd, Options} <- Services],
- {ok, {{RestartStrategy, MaxR, MaxT}, Children}}.
-
-%%%=========================================================================
-%%% Internal functions
-%%%=========================================================================
-
-worker_spec(KillAfter, Options) ->
- Modules = [proc_lib, tftp, tftp_engine],
- KA = supervisor_timeout(KillAfter),
- Name = unique_name(Options),
- {Name, {tftp, start, [Options]}, permanent, KA, worker, Modules}.
-
-unique_name(Options) ->
- case lists:keysearch(port, 1, Options) of
- {value, {_, Port}} when is_integer(Port), Port > 0 ->
- {tftpd, Port};
- _ ->
- {tftpd, erlang:unique_integer([positive])}
- end.
-
-default_kill_after() ->
- timer:seconds(3).
-
-%% supervisor_spec(Name) ->
-%% {Name, {Name, start, []}, permanent, infinity, supervisor,
-%% [Name, supervisor]}.
-
--ifdef(debug_shutdown).
-supervisor_timeout(_KillAfter) -> timer:hours(24).
--else.
-supervisor_timeout(KillAfter) -> KillAfter.
--endif.
diff --git a/lib/inets/test/Makefile b/lib/inets/test/Makefile
index 99a7e6a9db..6ab9771a8f 100644
--- a/lib/inets/test/Makefile
+++ b/lib/inets/test/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -44,8 +44,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
INCLUDES = -I. \
-I$(ERL_TOP)/lib/inets/src/inets_app \
-I$(ERL_TOP)/lib/inets/src/http_lib \
- -I$(ERL_TOP)/lib/inets/src/http_client \
- -I$(ERL_TOP)/lib/inets/src/ftp
+ -I$(ERL_TOP)/lib/inets/src/http_client
CP = cp
@@ -68,34 +67,6 @@ INETS_FLAGS = -Dinets_data_dir='"$(INETS_DATA_DIR)"' \
###
### test suite debug flags
###
-ifeq ($(FTP_DEBUG_CLIENT),)
- FTP_DEBUG_CLIENT = y
-endif
-
-ifeq ($(FTP_DEBUG_CLIENT),)
- FTP_FLAGS += -Dftp_debug_client
-endif
-
-ifeq ($(FTP_TRACE_CLIENT),)
- FTP_DEBUG_CLIENT = y
-endif
-
-ifeq ($(FTP_TRACE_CLIENT),y)
- FTP_FLAGS += -Dftp_trace_client
-endif
-
-ifneq ($(FTP_DEBUG),)
- FTP_DEBUG = s
-endif
-
-ifeq ($(FTP_DEBUG),l)
- FTP_FLAGS += -Dftp_log
-endif
-
-ifeq ($(FTP_DEBUG),d)
- FTP_FLAGS += -Dftp_debug -Dftp_log
-endif
-
ifeq ($(INETS_DEBUG),)
INETS_DEBUG = d
endif
@@ -151,8 +122,6 @@ MODULES = \
inets_test_lib \
erl_make_certs \
make_certs \
- ftp_SUITE \
- ftp_format_SUITE \
http_format_SUITE \
httpc_SUITE \
httpc_cookie_SUITE \
@@ -169,8 +138,6 @@ MODULES = \
httpd_test_lib \
inets_sup_SUITE \
inets_SUITE \
- tftp_test_lib \
- tftp_SUITE \
uri_SUITE \
inets_socketwrap_SUITE
@@ -179,10 +146,8 @@ EBIN = .
HRL_FILES = inets_test_lib.hrl \
inets_internal.hrl \
- ftp_internal.hrl \
httpc_internal.hrl \
- http_internal.hrl \
- tftp_test_lib.hrl
+ http_internal.hrl
ERL_FILES = $(MODULES:%=%.erl)
@@ -197,18 +162,15 @@ INETS_FILES = inets.config $(INETS_SPECS)
# SUB_SUITES = \
# inets_sup_suite \
# inets_httpd_suite \
-# inets_httpc_suite \
-# inets_ftp_suite \
-# inets_tftp_suite
+# inets_httpc_suite
INETS_DATADIRS = inets_SUITE_data inets_socketwrap_SUITE_data
HTTPD_DATADIRS = httpd_test_data httpd_SUITE_data httpd_basic_SUITE_data old_httpd_SUITE_data httpd_bench_SUITE_data
HTTPC_DATADIRS = httpc_SUITE_data httpc_proxy_SUITE_data
-FTP_DATADIRS = ftp_SUITE_data
-DATADIRS = $(INETS_DATADIRS) $(HTTPD_DATADIRS) $(HTTPC_DATADIRS) $(FTP_DATADIRS)
+DATADIRS = $(INETS_DATADIRS) $(HTTPD_DATADIRS) $(HTTPC_DATADIRS)
EMAKEFILE = Emakefile
MAKE_EMAKE = $(wildcard $(ERL_TOP)/make/make_emakefile)
@@ -238,7 +200,6 @@ RELTESTSYSBINDIR = $(RELTESTSYSALLDATADIR)/bin
# ----------------------------------------------------
ERL_COMPILE_FLAGS += \
$(INCLUDES) \
- $(FTP_FLAGS) \
$(INETS_FLAGS)
# ----------------------------------------------------
@@ -334,11 +295,3 @@ info:
@echo "INETS_PRIV_DIR = $(INETS_PRIV_DIR)"
@echo "INETS_ROOT = $(INETS_ROOT)"
@echo "INETS_FLAGS = $(INETS_FLAGS)"
- @echo "FTP_FLAGS = $(FTP_FLAGS)"
-
-tftp:
- erlc $(ERL_COMPILE_FLAGS) tftp_test_lib.erl tftp_SUITE.erl && erl -pa ../../inets/ebin -s tftp_SUITE t -s erlang halt
-
-tftp_work:
- echo "tftp_test_lib:t([{tftp_SUITE, all}])."
- erlc $(ERL_COMPILE_FLAGS) tftp_test_lib.erl tftp_SUITE.erl && erl -pa ../../inets/ebin
diff --git a/lib/inets/test/ftp_SUITE.erl b/lib/inets/test/ftp_SUITE.erl
deleted file mode 100644
index 3dfec01ba2..0000000000
--- a/lib/inets/test/ftp_SUITE.erl
+++ /dev/null
@@ -1,1180 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
-%%
-%% ct:run("../inets_test", ftp_SUITE).
-%%
-
--module(ftp_SUITE).
-
--include_lib("kernel/include/file.hrl").
--include_lib("common_test/include/ct.hrl").
--include("inets_test_lib.hrl").
-
-%% Note: This directive should only be used in test suites.
--compile(export_all).
-
--define(FTP_USER, "anonymous").
--define(FTP_PASS(Cmnt), (fun({ok,__H}) -> "ftp_SUITE_"++Cmnt++"@" ++ __H;
- (_) -> "ftp_SUITE_"++Cmnt++"@localhost"
- end)(inet:gethostname())
- ).
-
--define(BAD_HOST, "badhostname").
--define(BAD_USER, "baduser").
--define(BAD_DIR, "baddirectory").
-
--record(progress, {
- current = 0,
- total
- }).
-
-%%--------------------------------------------------------------------
-%% Common Test interface functions -----------------------------------
-%%--------------------------------------------------------------------
-suite() ->
- [{timetrap,{seconds,20}}].
-
-all() ->
- [
- {group, ftp_passive},
- {group, ftp_active},
- {group, ftps_passive},
- {group, ftps_active},
- error_ehost,
- clean_shutdown
- ].
-
-groups() ->
- [
- {ftp_passive, [], ftp_tests()},
- {ftp_active, [], ftp_tests()},
- {ftps_passive, [], ftp_tests()},
- {ftps_active, [], ftp_tests()}
- ].
-
-ftp_tests()->
- [
- user,
- bad_user,
- pwd,
- cd,
- lcd,
- ls,
- nlist,
- rename,
- delete,
- mkdir,
- rmdir,
- send,
- send_3,
- send_bin,
- send_chunk,
- append,
- append_bin,
- append_chunk,
- recv,
- recv_3,
- recv_bin,
- recv_bin_twice,
- recv_chunk,
- recv_chunk_twice,
- recv_chunk_three_times,
- type,
- quote,
- error_elogin,
- progress_report_send,
- progress_report_recv,
- not_owner,
- unexpected_call,
- unexpected_cast,
- unexpected_bang
- ].
-
-%%--------------------------------------------------------------------
-
-%%% Config
-%%% key meaning
-%%% ................................................................
-%%% ftpservers list of servers to check if they are available
-%%% The element is:
-%%% {Name, % string(). The os command name
-%%% Path, % string(). The os PATH syntax, e.g "/bin:/usr/bin"
-%%% StartCommand, % fun()->{ok,start_result()} | {error,string()}.
-%%% % The command to start the daemon with.
-%%% ChkUp, % fun(start_result()) -> string(). Os command to check
-%%% % if the server is running. [] if not running.
-%%% % The string in string() is suitable for logging.
-%%% StopCommand, % fun(start_result()) -> void(). The command to stop the daemon with.
-%%% AugmentFun, % fun(config()) -> config() Adds two funs for transforming names of files
-%%% % and directories to the form they are returned from this server
-%%% ServerHost, % string(). Mostly "localhost"
-%%% ServerPort % pos_integer()
-%%% }
-%%%
-
--define(default_ftp_servers,
- [{"vsftpd",
- "/sbin:/usr/sbin:/usr/local/sbin",
- fun(__CONF__, AbsName) ->
- DataDir = proplists:get_value(data_dir,__CONF__),
- ConfFile = filename:join(DataDir, "vsftpd.conf"),
- PrivDir = proplists:get_value(priv_dir,__CONF__),
- AnonRoot = PrivDir,
- Cmd = [AbsName ++" "++filename:join(DataDir,"vsftpd.conf"),
- " -oftpd_banner=erlang_otp_testing",
- " -oanon_root=\"",AnonRoot,"\"",
- " -orsa_cert_file=\"",filename:join(DataDir,"server-cert.pem"),"\"",
- " -orsa_private_key_file=\"",filename:join(DataDir,"server-key.pem"),"\""
- ],
- Result = os:cmd(Cmd),
- ct:log("Config file:~n~s~n~nServer start command:~n ~s~nResult:~n ~p",
- [case file:read_file(ConfFile) of
- {ok,X} -> X;
- _ -> ""
- end,
- Cmd, Result
- ]),
- case Result of
- [] -> {ok,'dont care'};
- [Msg] -> {error,Msg}
- end
- end,
- fun(_StartResult) -> os:cmd("ps ax | grep erlang_otp_testing | grep -v grep")
- end,
- fun(_StartResult) -> os:cmd("kill `ps ax | grep erlang_otp_testing | awk '/vsftpd/{print $1}'`")
- end,
- fun(__CONF__) ->
- AnonRoot = proplists:get_value(priv_dir,__CONF__),
- [{id2ftp, fun(Id) -> filename:join(AnonRoot,Id) end},
- {id2ftp_result,fun(Id) -> filename:join(AnonRoot,Id) end} | __CONF__]
- end,
- "localhost",
- 9999
- }
- ]
- ).
-
-
-init_per_suite(Config) ->
- case find_executable(Config) of
- false ->
- {skip, "No ftp server found"};
- {ok,Data} ->
- TstDir = filename:join(proplists:get_value(priv_dir,Config), "test"),
- file:make_dir(TstDir),
- make_cert_files(dsa, rsa, "server-", proplists:get_value(data_dir,Config)),
- start_ftpd([{test_dir,TstDir},
- {ftpd_data,Data}
- | Config])
- end.
-
-end_per_suite(Config) ->
- ps_ftpd(Config),
- stop_ftpd(Config),
- ps_ftpd(Config),
- ok.
-
-%%--------------------------------------------------------------------
-init_per_group(Group, Config) when Group == ftps_active,
- Group == ftps_passive ->
- catch crypto:stop(),
- try crypto:start() of
- ok ->
- Config
- catch
- _:_ ->
- {skip, "Crypto did not start"}
- end;
-
-init_per_group(_Group, Config) ->
- Config.
-
-end_per_group(_Group, Config) ->
- Config.
-
-%%--------------------------------------------------------------------
-init_per_testcase(Case, Config0) ->
- Group = proplists:get_value(name, proplists:get_value(tc_group_properties,Config0)),
- TLS = [{tls,[{reuse_sessions,true}]}],
- ACTIVE = [{mode,active}],
- PASSIVE = [{mode,passive}],
- CaseOpts = case Case of
- progress_report_send -> [{progress, {?MODULE,progress,#progress{}}}];
- progress_report_recv -> [{progress, {?MODULE,progress,#progress{}}}];
- _ -> []
- end,
- ExtraOpts = [verbose | CaseOpts],
- Config =
- case Group of
- ftp_active -> ftp__open(Config0, ACTIVE ++ ExtraOpts);
- ftps_active -> ftp__open(Config0, TLS++ ACTIVE ++ ExtraOpts);
- ftp_passive -> ftp__open(Config0, PASSIVE ++ ExtraOpts);
- ftps_passive -> ftp__open(Config0, TLS++PASSIVE ++ ExtraOpts);
- undefined -> Config0
- end,
- case Case of
- user -> Config;
- bad_user -> Config;
- error_elogin -> Config;
- error_ehost -> Config;
- clean_shutdown -> Config;
- _ ->
- Pid = proplists:get_value(ftp,Config),
- ok = ftp:user(Pid, ?FTP_USER, ?FTP_PASS(atom_to_list(Group)++"-"++atom_to_list(Case)) ),
- ok = ftp:cd(Pid, proplists:get_value(priv_dir,Config)),
- Config
- end.
-
-
-end_per_testcase(user, _Config) -> ok;
-end_per_testcase(bad_user, _Config) -> ok;
-end_per_testcase(error_elogin, _Config) -> ok;
-end_per_testcase(error_ehost, _Config) -> ok;
-end_per_testcase(clean_shutdown, _Config) -> ok;
-end_per_testcase(_Case, Config) ->
- case proplists:get_value(tc_status,Config) of
- ok -> ok;
- _ ->
- try ftp:latest_ctrl_response(proplists:get_value(ftp,Config))
- of
- {ok,S} -> ct:log("***~n*** Latest ctrl channel response:~n*** ~p~n***",[S])
- catch
- _:_ -> ok
- end
- end,
- ftp__close(Config).
-
-%%--------------------------------------------------------------------
-%% Test Cases --------------------------------------------------------
-%%--------------------------------------------------------------------
-user() -> [
- {doc, "Open an ftp connection to a host, and logon as anonymous ftp,"
- " then logoff"}].
-user(Config) ->
- Pid = proplists:get_value(ftp, Config),
- ok = ftp:user(Pid, ?FTP_USER, ?FTP_PASS("")),% logon
- ok = ftp:close(Pid), % logoff
- {error,eclosed} = ftp:pwd(Pid), % check logoff result
- ok.
-
-%%-------------------------------------------------------------------------
-bad_user() ->
- [{doc, "Open an ftp connection to a host, and logon with bad user."}].
-bad_user(Config) ->
- Pid = proplists:get_value(ftp, Config),
- {error, euser} = ftp:user(Pid, ?BAD_USER, ?FTP_PASS("")),
- ok.
-
-%%-------------------------------------------------------------------------
-pwd() ->
- [{doc, "Test ftp:pwd/1 & ftp:lpwd/1"}].
-pwd(Config0) ->
- Config = set_state([reset], Config0),
- Pid = proplists:get_value(ftp, Config),
- {ok, PWD} = ftp:pwd(Pid),
- {ok, PathLpwd} = ftp:lpwd(Pid),
- PWD = id2ftp_result("", Config),
- PathLpwd = id2ftp_result("", Config).
-
-%%-------------------------------------------------------------------------
-cd() ->
- ["Open an ftp connection, log on as anonymous ftp, and cd to a"
- "directory and to a non-existent directory."].
-cd(Config0) ->
- Dir = "test",
- Config = set_state([reset,{mkdir,Dir}], Config0),
- Pid = proplists:get_value(ftp, Config),
- ok = ftp:cd(Pid, id2ftp(Dir,Config)),
- {ok, PWD} = ftp:pwd(Pid),
- ExpectedPWD = id2ftp_result(Dir, Config),
- PWD = ExpectedPWD,
- {error, epath} = ftp:cd(Pid, ?BAD_DIR),
- ok.
-
-%%-------------------------------------------------------------------------
-lcd() ->
- [{doc, "Test api function ftp:lcd/2"}].
-lcd(Config0) ->
- Dir = "test",
- Config = set_state([reset,{mkdir,Dir}], Config0),
- Pid = proplists:get_value(ftp, Config),
- ok = ftp:lcd(Pid, id2ftp(Dir,Config)),
- {ok, PWD} = ftp:lpwd(Pid),
- ExpectedPWD = id2ftp_result(Dir, Config),
- PWD = ExpectedPWD,
- {error, epath} = ftp:lcd(Pid, ?BAD_DIR).
-
-%%-------------------------------------------------------------------------
-ls() ->
- [{doc, "Open an ftp connection; ls the current directory, and the "
- "\"test\" directory. We assume that ls never fails, since "
- "it's output is meant to be read by humans. "}].
-ls(Config0) ->
- Config = set_state([reset,{mkdir,"test"}], Config0),
- Pid = proplists:get_value(ftp, Config),
- {ok, _R1} = ftp:ls(Pid),
- {ok, _R2} = ftp:ls(Pid, id2ftp("test",Config)),
- %% neither nlist nor ls operates on a directory
- %% they operate on a pathname, which *can* be a
- %% directory, but can also be a filename or a group
- %% of files (including wildcards).
- case proplists:get_value(wildcard_support, Config) of
- true ->
- {ok, _R3} = ftp:ls(Pid, id2ftp("te*",Config));
- _ ->
- ok
- end.
-
-%%-------------------------------------------------------------------------
-nlist() ->
- [{doc,"Open an ftp connection; nlist the current directory, and the "
- "\"test\" directory. Nlist does not behave consistenly over "
- "operating systems. On some it is an error to have an empty "
- "directory."}].
-nlist(Config0) ->
- Config = set_state([reset,{mkdir,"test"}], Config0),
- Pid = proplists:get_value(ftp, Config),
- {ok, _R1} = ftp:nlist(Pid),
- {ok, _R2} = ftp:nlist(Pid, id2ftp("test",Config)),
- %% neither nlist nor ls operates on a directory
- %% they operate on a pathname, which *can* be a
- %% directory, but can also be a filename or a group
- %% of files (including wildcards).
- case proplists:get_value(wildcard_support, Config) of
- true ->
- {ok, _R3} = ftp:nlist(Pid, id2ftp("te*",Config));
- _ ->
- ok
- end.
-
-%%-------------------------------------------------------------------------
-rename() ->
- [{doc, "Rename a file."}].
-rename(Config0) ->
- Contents = <<"ftp_SUITE test ...">>,
- OldFile = "old.txt",
- NewFile = "new.txt",
- Config = set_state([reset,{mkfile,OldFile,Contents}], Config0),
- Pid = proplists:get_value(ftp, Config),
-
- ok = ftp:rename(Pid,
- id2ftp(OldFile,Config),
- id2ftp(NewFile,Config)),
-
- true = (chk_file(NewFile,Contents,Config)
- and chk_no_file([OldFile],Config)),
- {error,epath} = ftp:rename(Pid,
- id2ftp("non_existing_file",Config),
- id2ftp(NewFile,Config)),
- ok.
-
-%%-------------------------------------------------------------------------
-send() ->
- [{doc, "Transfer a file with ftp using send/2."}].
-send(Config0) ->
- Contents = <<"ftp_SUITE test ...">>,
- SrcDir = "data",
- File = "file.txt",
- Config = set_state([reset,{mkfile,[SrcDir,File],Contents}], Config0),
- Pid = proplists:get_value(ftp, Config),
-
- chk_no_file([File],Config),
- chk_file([SrcDir,File],Contents,Config),
-
- ok = ftp:lcd(Pid, id2ftp(SrcDir,Config)),
- ok = ftp:cd(Pid, id2ftp("",Config)),
- ok = ftp:send(Pid, File),
- chk_file(File, Contents, Config),
-
- {error,epath} = ftp:send(Pid, "non_existing_file"),
- ok.
-
-%%-------------------------------------------------------------------------
-send_3() ->
- [{doc, "Transfer a file with ftp using send/3."}].
-send_3(Config0) ->
- Contents = <<"ftp_SUITE test ...">>,
- Dir = "incoming",
- File = "file.txt",
- RemoteFile = "remfile.txt",
- Config = set_state([reset,{mkfile,File,Contents},{mkdir,Dir}], Config0),
- Pid = proplists:get_value(ftp, Config),
-
- ok = ftp:cd(Pid, id2ftp(Dir,Config)),
- ok = ftp:lcd(Pid, id2ftp("",Config)),
- ok = ftp:send(Pid, File, RemoteFile),
- chk_file([Dir,RemoteFile], Contents, Config),
-
- {error,epath} = ftp:send(Pid, "non_existing_file", RemoteFile),
- ok.
-
-%%-------------------------------------------------------------------------
-send_bin() ->
- [{doc, "Send a binary."}].
-send_bin(Config0) ->
- BinContents = <<"ftp_SUITE test ...">>,
- File = "file.txt",
- Config = set_state([reset], Config0),
- Pid = proplists:get_value(ftp, Config),
- {error, enotbinary} = ftp:send_bin(Pid, "some string", id2ftp(File,Config)),
- ok = ftp:send_bin(Pid, BinContents, id2ftp(File,Config)),
- chk_file(File, BinContents, Config),
- {error, efnamena} = ftp:send_bin(Pid, BinContents, "/nothere"),
- ok.
-
-%%-------------------------------------------------------------------------
-send_chunk() ->
- [{doc, "Send a binary using chunks."}].
-send_chunk(Config0) ->
- Contents1 = <<"1: ftp_SUITE test ...">>,
- Contents2 = <<"2: ftp_SUITE test ...">>,
- File = "file.txt",
- Config = set_state([reset,{mkdir,"incoming"}], Config0),
- Pid = proplists:get_value(ftp, Config),
-
- ok = ftp:send_chunk_start(Pid, id2ftp(File,Config)),
- {error, echunk} = ftp:send_chunk_start(Pid, id2ftp(File,Config)),
- {error, echunk} = ftp:cd(Pid, "incoming"),
- {error, enotbinary} = ftp:send_chunk(Pid, "some string"),
- ok = ftp:send_chunk(Pid, Contents1),
- ok = ftp:send_chunk(Pid, Contents2),
- ok = ftp:send_chunk_end(Pid),
- chk_file(File, <<Contents1/binary,Contents2/binary>>, Config),
-
- {error, echunk} = ftp:send_chunk(Pid, Contents1),
- {error, echunk} = ftp:send_chunk_end(Pid),
- {error, efnamena} = ftp:send_chunk_start(Pid, "/"),
- ok.
-
-%%-------------------------------------------------------------------------
-delete() ->
- [{doc, "Delete a file."}].
-delete(Config0) ->
- Contents = <<"ftp_SUITE test ...">>,
- File = "file.txt",
- Config = set_state([reset,{mkfile,File,Contents}], Config0),
- Pid = proplists:get_value(ftp, Config),
- ok = ftp:delete(Pid, id2ftp(File,Config)),
- chk_no_file([File], Config),
- {error,epath} = ftp:delete(Pid, id2ftp(File,Config)),
- ok.
-
-%%-------------------------------------------------------------------------
-mkdir() ->
- [{doc, "Make a remote directory."}].
-mkdir(Config0) ->
- NewDir = "new_dir",
- Config = set_state([reset], Config0),
- Pid = proplists:get_value(ftp, Config),
- ok = ftp:mkdir(Pid, id2ftp(NewDir,Config)),
- chk_dir([NewDir], Config),
- {error,epath} = ftp:mkdir(Pid, id2ftp(NewDir,Config)),
- ok.
-
-%%-------------------------------------------------------------------------
-rmdir() ->
- [{doc, "Remove a directory."}].
-rmdir(Config0) ->
- Dir = "dir",
- Config = set_state([reset,{mkdir,Dir}], Config0),
- Pid = proplists:get_value(ftp, Config),
- ok = ftp:rmdir(Pid, id2ftp(Dir,Config)),
- chk_no_dir([Dir], Config),
- {error,epath} = ftp:rmdir(Pid, id2ftp(Dir,Config)),
- ok.
-
-%%-------------------------------------------------------------------------
-append() ->
- [{doc, "Append a local file twice to a remote file"}].
-append(Config0) ->
- SrcFile = "f_src.txt",
- DstFile = "f_dst.txt",
- Contents = <<"ftp_SUITE test ...">>,
- Config = set_state([reset,{mkfile,SrcFile,Contents}], Config0),
- Pid = proplists:get_value(ftp, Config),
- ok = ftp:append(Pid, id2ftp(SrcFile,Config), id2ftp(DstFile,Config)),
- ok = ftp:append(Pid, id2ftp(SrcFile,Config), id2ftp(DstFile,Config)),
- chk_file(DstFile, <<Contents/binary,Contents/binary>>, Config),
- {error,epath} = ftp:append(Pid, id2ftp("non_existing_file",Config), id2ftp(DstFile,Config)),
- ok.
-
-%%-------------------------------------------------------------------------
-append_bin() ->
- [{doc, "Append a local file twice to a remote file using append_bin"}].
-append_bin(Config0) ->
- DstFile = "f_dst.txt",
- Contents = <<"ftp_SUITE test ...">>,
- Config = set_state([reset], Config0),
- Pid = proplists:get_value(ftp, Config),
- ok = ftp:append_bin(Pid, Contents, id2ftp(DstFile,Config)),
- ok = ftp:append_bin(Pid, Contents, id2ftp(DstFile,Config)),
- chk_file(DstFile, <<Contents/binary,Contents/binary>>, Config).
-
-%%-------------------------------------------------------------------------
-append_chunk() ->
- [{doc, "Append chunks."}].
-append_chunk(Config0) ->
- File = "f_dst.txt",
- Contents = [<<"ER">>,<<"LE">>,<<"RL">>],
- Config = set_state([reset], Config0),
- Pid = proplists:get_value(ftp, Config),
- ok = ftp:append_chunk_start(Pid, id2ftp(File,Config)),
- {error, enotbinary} = ftp:append_chunk(Pid, binary_to_list(lists:nth(1,Contents))),
- ok = ftp:append_chunk(Pid,lists:nth(1,Contents)),
- ok = ftp:append_chunk(Pid,lists:nth(2,Contents)),
- ok = ftp:append_chunk(Pid,lists:nth(3,Contents)),
- ok = ftp:append_chunk_end(Pid),
- chk_file(File, <<"ERLERL">>, Config).
-
-%%-------------------------------------------------------------------------
-recv() ->
- [{doc, "Receive a file using recv/2"}].
-recv(Config0) ->
- File1 = "f_dst1.txt",
- File2 = "f_dst2.txt",
- SrcDir = "a_dir",
- Contents1 = <<"1 ftp_SUITE test ...">>,
- Contents2 = <<"2 ftp_SUITE test ...">>,
- Config = set_state([reset, {mkfile,[SrcDir,File1],Contents1}, {mkfile,[SrcDir,File2],Contents2}], Config0),
- Pid = proplists:get_value(ftp, Config),
- ok = ftp:cd(Pid, id2ftp(SrcDir,Config)),
- ok = ftp:lcd(Pid, id2ftp("",Config)),
- ok = ftp:recv(Pid, File1),
- chk_file(File1, Contents1, Config),
- ok = ftp:recv(Pid, File2),
- chk_file(File2, Contents2, Config),
- {error,epath} = ftp:recv(Pid, "non_existing_file"),
- ok.
-
-%%-------------------------------------------------------------------------
-recv_3() ->
- [{doc,"Receive a file using recv/3"}].
-recv_3(Config0) ->
- DstFile = "f_src.txt",
- SrcFile = "f_dst.txt",
- Contents = <<"ftp_SUITE test ...">>,
- Config = set_state([reset, {mkfile,SrcFile,Contents}], Config0),
- Pid = proplists:get_value(ftp, Config),
- ok = ftp:cd(Pid, id2ftp("",Config)),
- ok = ftp:recv(Pid, SrcFile, id2abs(DstFile,Config)),
- chk_file(DstFile, Contents, Config).
-
-%%-------------------------------------------------------------------------
-recv_bin() ->
- [{doc, "Receive a file as a binary."}].
-recv_bin(Config0) ->
- File = "f_dst.txt",
- Contents = <<"ftp_SUITE test ...">>,
- Config = set_state([reset, {mkfile,File,Contents}], Config0),
- Pid = proplists:get_value(ftp, Config),
- {ok,Received} = ftp:recv_bin(Pid, id2ftp(File,Config)),
- find_diff(Received, Contents),
- {error,epath} = ftp:recv_bin(Pid, id2ftp("non_existing_file",Config)),
- ok.
-
-%%-------------------------------------------------------------------------
-recv_bin_twice() ->
- [{doc, "Receive two files as a binaries."}].
-recv_bin_twice(Config0) ->
- File1 = "f_dst1.txt",
- File2 = "f_dst2.txt",
- Contents1 = <<"1 ftp_SUITE test ...">>,
- Contents2 = <<"2 ftp_SUITE test ...">>,
- Config = set_state([reset, {mkfile,File1,Contents1}, {mkfile,File2,Contents2}], Config0),
- ct:log("First transfer",[]),
- Pid = proplists:get_value(ftp, Config),
- {ok,Received1} = ftp:recv_bin(Pid, id2ftp(File1,Config)),
- find_diff(Received1, Contents1),
- ct:log("Second transfer",[]),
- {ok,Received2} = ftp:recv_bin(Pid, id2ftp(File2,Config)),
- find_diff(Received2, Contents2),
- ct:log("Transfers ready!",[]),
- {error,epath} = ftp:recv_bin(Pid, id2ftp("non_existing_file",Config)),
- ok.
-%%-------------------------------------------------------------------------
-recv_chunk() ->
- [{doc, "Receive a file using chunk-wise."}].
-recv_chunk(Config0) ->
- File = "big_file.txt",
- Contents = list_to_binary( lists:duplicate(1000, lists:seq(0,255)) ),
- Config = set_state([reset, {mkfile,File,Contents}], Config0),
- Pid = proplists:get_value(ftp, Config),
- {{error, "ftp:recv_chunk_start/2 not called"},_} = recv_chunk(Pid, <<>>),
- ok = ftp:recv_chunk_start(Pid, id2ftp(File,Config)),
- {ok, ReceivedContents, _Ncunks} = recv_chunk(Pid, <<>>),
- find_diff(ReceivedContents, Contents).
-
-recv_chunk_twice() ->
- [{doc, "Receive two files using chunk-wise."}].
-recv_chunk_twice(Config0) ->
- File1 = "big_file1.txt",
- File2 = "big_file2.txt",
- Contents1 = list_to_binary( lists:duplicate(1000, lists:seq(0,255)) ),
- Contents2 = crypto:strong_rand_bytes(1200),
- Config = set_state([reset, {mkfile,File1,Contents1}, {mkfile,File2,Contents2}], Config0),
- Pid = proplists:get_value(ftp, Config),
- {{error, "ftp:recv_chunk_start/2 not called"},_} = recv_chunk(Pid, <<>>),
- ok = ftp:recv_chunk_start(Pid, id2ftp(File1,Config)),
- {ok, ReceivedContents1, _Ncunks1} = recv_chunk(Pid, <<>>),
- ok = ftp:recv_chunk_start(Pid, id2ftp(File2,Config)),
- {ok, ReceivedContents2, _Ncunks2} = recv_chunk(Pid, <<>>),
- find_diff(ReceivedContents1, Contents1),
- find_diff(ReceivedContents2, Contents2).
-
-recv_chunk_three_times() ->
- [{doc, "Receive two files using chunk-wise."},
- {timetrap,{seconds,120}}].
-recv_chunk_three_times(Config0) ->
- File1 = "big_file1.txt",
- File2 = "big_file2.txt",
- File3 = "big_file3.txt",
- Contents1 = list_to_binary( lists:duplicate(1000, lists:seq(0,255)) ),
- Contents2 = crypto:strong_rand_bytes(1200),
- Contents3 = list_to_binary( lists:duplicate(1000, lists:seq(255,0,-1)) ),
-
- Config = set_state([reset, {mkfile,File1,Contents1}, {mkfile,File2,Contents2}, {mkfile,File3,Contents3}], Config0),
- Pid = proplists:get_value(ftp, Config),
- {{error, "ftp:recv_chunk_start/2 not called"},_} = recv_chunk(Pid, <<>>),
-
- ok = ftp:recv_chunk_start(Pid, id2ftp(File1,Config)),
- {ok, ReceivedContents1, Nchunks1} = recv_chunk(Pid, <<>>),
-
- ok = ftp:recv_chunk_start(Pid, id2ftp(File2,Config)),
- {ok, ReceivedContents2, _Nchunks2} = recv_chunk(Pid, <<>>),
-
- ok = ftp:recv_chunk_start(Pid, id2ftp(File3,Config)),
- {ok, ReceivedContents3, _Nchunks3} = recv_chunk(Pid, <<>>, 10000, 0, Nchunks1),
-
- find_diff(ReceivedContents1, Contents1),
- find_diff(ReceivedContents2, Contents2),
- find_diff(ReceivedContents3, Contents3).
-
-
-
-recv_chunk(Pid, Acc) ->
- recv_chunk(Pid, Acc, 0, 0, undefined).
-
-
-
-%% ExpectNchunks :: integer() | undefined
-recv_chunk(Pid, Acc, DelayMilliSec, N, ExpectNchunks) when N+1 < ExpectNchunks ->
- %% for all I in integer(), I < undefined
- recv_chunk1(Pid, Acc, DelayMilliSec, N, ExpectNchunks);
-
-recv_chunk(Pid, Acc, DelayMilliSec, N, ExpectNchunks) ->
- %% N >= ExpectNchunks-1
- timer:sleep(DelayMilliSec),
- recv_chunk1(Pid, Acc, DelayMilliSec, N, ExpectNchunks).
-
-
-recv_chunk1(Pid, Acc, DelayMilliSec, N, ExpectNchunks) ->
- ct:log("Call ftp:recv_chunk",[]),
- case ftp:recv_chunk(Pid) of
- ok -> {ok, Acc, N};
- {ok, Bin} -> recv_chunk(Pid, <<Acc/binary, Bin/binary>>, DelayMilliSec, N+1, ExpectNchunks);
- Error -> {Error, N}
- end.
-
-%%-------------------------------------------------------------------------
-type() ->
- [{doc,"Test that we can change btween ASCCI and binary transfer mode"}].
-type(Config) ->
- Pid = proplists:get_value(ftp, Config),
- ok = ftp:type(Pid, ascii),
- ok = ftp:type(Pid, binary),
- ok = ftp:type(Pid, ascii),
- {error, etype} = ftp:type(Pid, foobar).
-
-%%-------------------------------------------------------------------------
-quote(Config) ->
- Pid = proplists:get_value(ftp, Config),
- ["257 \""++_Rest] = ftp:quote(Pid, "pwd"), %% 257
- [_| _] = ftp:quote(Pid, "help"),
- %% This negativ test causes some ftp servers to hang. This test
- %% is not important for the client, so we skip it for now.
- %%["425 Can't build data connection: Connection refused."]
- %% = ftp:quote(Pid, "list"),
- ok.
-
-%%-------------------------------------------------------------------------
-progress_report_send() ->
- [{doc, "Test the option progress for ftp:send/[2,3]"}].
-progress_report_send(Config) when is_list(Config) ->
- ReportPid =
- spawn_link(?MODULE, progress_report_receiver_init, [self(), 1]),
- send(Config),
- receive
- {ReportPid, ok} ->
- ok
- end.
-
-%%-------------------------------------------------------------------------
-progress_report_recv() ->
- [{doc, "Test the option progress for ftp:recv/[2,3]"}].
-progress_report_recv(Config) when is_list(Config) ->
- ReportPid =
- spawn_link(?MODULE, progress_report_receiver_init, [self(), 3]),
- recv(Config),
- receive
- {ReportPid, ok} ->
- ok
- end.
-
-%%-------------------------------------------------------------------------
-
-not_owner() ->
- [{doc, "Test what happens if a process that not owns the connection tries "
- "to use it"}].
-not_owner(Config) when is_list(Config) ->
- Pid = proplists:get_value(ftp, Config),
-
- Parent = self(),
- OtherPid = spawn_link(
- fun() ->
- {error, not_connection_owner} = ftp:pwd(Pid),
- ftp:close(Pid),
- Parent ! {self(), ok}
- end),
- receive
- {OtherPid, ok} ->
- {ok, _} = ftp:pwd(Pid)
- end.
-
-
-%%-------------------------------------------------------------------------
-
-
-unexpected_call()->
- [{doc, "Test that behaviour of the ftp process if the api is abused"}].
-unexpected_call(Config) when is_list(Config) ->
- Flag = process_flag(trap_exit, true),
- Pid = proplists:get_value(ftp, Config),
-
- %% Serious programming fault, connetion will be shut down
- case (catch gen_server:call(Pid, {self(), foobar, 10}, infinity)) of
- {error, {connection_terminated, 'API_violation'}} ->
- ok;
- Unexpected1 ->
- exit({unexpected_result, Unexpected1})
- end,
- ct:sleep(500),
- undefined = process_info(Pid, status),
- process_flag(trap_exit, Flag).
-%%-------------------------------------------------------------------------
-
-unexpected_cast()->
- [{doc, "Test that behaviour of the ftp process if the api is abused"}].
-unexpected_cast(Config) when is_list(Config) ->
- Flag = process_flag(trap_exit, true),
- Pid = proplists:get_value(ftp, Config),
- %% Serious programming fault, connetion will be shut down
- gen_server:cast(Pid, {self(), foobar, 10}),
- ct:sleep(500),
- undefined = process_info(Pid, status),
- process_flag(trap_exit, Flag).
-%%-------------------------------------------------------------------------
-
-unexpected_bang()->
- [{doc, "Test that connection ignores unexpected bang"}].
-unexpected_bang(Config) when is_list(Config) ->
- Flag = process_flag(trap_exit, true),
- Pid = proplists:get_value(ftp, Config),
- %% Could be an innocent misstake the connection lives.
- Pid ! foobar,
- ct:sleep(500),
- {status, _} = process_info(Pid, status),
- process_flag(trap_exit, Flag).
-
-%%-------------------------------------------------------------------------
-
-clean_shutdown() ->
- [{doc, "Test that owning process that exits with reason "
- "'shutdown' does not cause an error message. OTP 6035"}].
-
-clean_shutdown(Config) ->
- Parent = self(),
- HelperPid = spawn(
- fun() ->
- ftp__open(Config, [verbose]),
- Parent ! ok,
- receive
- nothing -> ok
- end
- end),
- receive
- ok ->
- PrivDir = proplists:get_value(priv_dir, Config),
- LogFile = filename:join([PrivDir,"ticket_6035.log"]),
- error_logger:logfile({open, LogFile}),
- exit(HelperPid, shutdown),
- timer:sleep(2000),
- error_logger:logfile(close),
- case is_error_report_6035(LogFile) of
- true -> ok;
- false -> {fail, "Bad logfile"}
- end
- end.
-
-%%%----------------------------------------------------------------
-%%% Error codes not tested elsewhere
-
-error_elogin(Config0) ->
- Dir = "test",
- OldFile = "old.txt",
- NewFile = "new.txt",
- SrcDir = "data",
- File = "file.txt",
- Config = set_state([reset,
- {mkdir,Dir},
- {mkfile,OldFile,<<"Contents..">>},
- {mkfile,[SrcDir,File],<<"Contents..">>}], Config0),
-
- Pid = proplists:get_value(ftp, Config),
- ok = ftp:lcd(Pid, id2ftp(SrcDir,Config)),
- {error,elogin} = ftp:send(Pid, File),
- ok = ftp:lcd(Pid, id2ftp("",Config)),
- {error,elogin} = ftp:pwd(Pid),
- {error,elogin} = ftp:cd(Pid, id2ftp(Dir,Config)),
- {error,elogin} = ftp:rename(Pid,
- id2ftp(OldFile,Config),
- id2ftp(NewFile,Config)),
- ok.
-
-error_ehost(_Config) ->
- {error, ehost} = ftp:open("nohost.nodomain"),
- ok.
-
-%%--------------------------------------------------------------------
-%% Internal functions -----------------------------------------------
-%%--------------------------------------------------------------------
-
-make_cert_files(Alg1, Alg2, Prefix, Dir) ->
- CaInfo = {CaCert,_} = erl_make_certs:make_cert([{key,Alg1}]),
- {Cert,CertKey} = erl_make_certs:make_cert([{key,Alg2},{issuer,CaInfo}]),
- CaCertFile = filename:join(Dir, Prefix++"cacerts.pem"),
- CertFile = filename:join(Dir, Prefix++"cert.pem"),
- KeyFile = filename:join(Dir, Prefix++"key.pem"),
- der_to_pem(CaCertFile, [{'Certificate', CaCert, not_encrypted}]),
- der_to_pem(CertFile, [{'Certificate', Cert, not_encrypted}]),
- der_to_pem(KeyFile, [CertKey]),
- ok.
-
-der_to_pem(File, Entries) ->
- PemBin = public_key:pem_encode(Entries),
- file:write_file(File, PemBin).
-
-%%--------------------------------------------------------------------
-chk_file(Path=[C|_], ExpectedContents, Config) when 0<C,C=<255 ->
- chk_file([Path], ExpectedContents, Config);
-
-chk_file(PathList, ExpectedContents, Config) ->
- Path = filename:join(PathList),
- AbsPath = id2abs(Path,Config),
- case file:read_file(AbsPath) of
- {ok,ExpectedContents} ->
- true;
- {ok,ReadContents} ->
- {error,{diff,Pos,RC,LC}} = find_diff(ReadContents, ExpectedContents, 1),
- ct:log("Bad contents of ~p.~nGot:~n~p~nExpected:~n~p~nDiff at pos ~p ~nRead: ~p~nExp : ~p",
- [AbsPath,ReadContents,ExpectedContents,Pos,RC,LC]),
- ct:fail("Bad contents of ~p", [Path]);
- {error,Error} ->
- try begin
- {ok,CWD} = file:get_cwd(),
- ct:log("file:get_cwd()=~p~nfiles:~n~p",[CWD,file:list_dir(CWD)])
- end
- of _ -> ok
- catch _:_ ->ok
- end,
- ct:fail("Error reading ~p: ~p",[Path,Error])
- end.
-
-
-chk_no_file(Path=[C|_], Config) when 0<C,C=<255 ->
- chk_no_file([Path], Config);
-
-chk_no_file(PathList, Config) ->
- Path = filename:join(PathList),
- AbsPath = id2abs(Path,Config),
- case file:read_file(AbsPath) of
- {error,enoent} ->
- true;
- {ok,Contents} ->
- ct:log("File ~p exists although it shouldn't. Contents:~n~p",
- [AbsPath,Contents]),
- ct:fail("File exists: ~p", [Path]);
- {error,Error} ->
- ct:fail("Unexpected error reading ~p: ~p",[Path,Error])
- end.
-
-
-chk_dir(Path=[C|_], Config) when 0<C,C=<255 ->
- chk_dir([Path], Config);
-
-chk_dir(PathList, Config) ->
- Path = filename:join(PathList),
- AbsPath = id2abs(Path,Config),
- case file:read_file_info(AbsPath) of
- {ok, #file_info{type=directory}} ->
- true;
- {ok, #file_info{type=Type}} ->
- ct:fail("Expected dir ~p is a ~p",[Path,Type]);
- {error,Error} ->
- ct:fail("Expected dir ~p: ~p",[Path,Error])
- end.
-
-chk_no_dir(PathList, Config) ->
- Path = filename:join(PathList),
- AbsPath = id2abs(Path,Config),
- case file:read_file_info(AbsPath) of
- {error,enoent} ->
- true;
- {ok, #file_info{type=directory}} ->
- ct:fail("Dir ~p erroneously exists",[Path]);
- {ok, #file_info{type=Type}} ->
- ct:fail("~p ~p erroneously exists",[Type,Path]);
- {error,Error} ->
- ct:fail("Unexpected error for ~p: ~p",[Path,Error])
- end.
-
-%%--------------------------------------------------------------------
-find_executable(Config) ->
- search_executable(proplists:get_value(ftpservers, Config, ?default_ftp_servers)).
-
-
-search_executable([{Name,Paths,_StartCmd,_ChkUp,_StopCommand,_ConfigUpd,_Host,_Port}|Srvrs]) ->
- case os_find(Name,Paths) of
- false ->
- ct:log("~p not found",[Name]),
- search_executable(Srvrs);
- AbsName ->
- ct:comment("Found ~p",[AbsName]),
- {ok, {AbsName,_StartCmd,_ChkUp,_StopCommand,_ConfigUpd,_Host,_Port}}
- end;
-search_executable([]) ->
- false.
-
-
-os_find(Name, Paths) ->
- case os:find_executable(Name, Paths) of
- false -> os:find_executable(Name);
- AbsName -> AbsName
- end.
-
-%%%----------------------------------------------------------------
-start_ftpd(Config0) ->
- {AbsName,StartCmd,_ChkUp,_StopCommand,ConfigRewrite,Host,Port} =
- proplists:get_value(ftpd_data, Config0),
- case StartCmd(Config0, AbsName) of
- {ok,StartResult} ->
- Config = [{ftpd_host,Host},
- {ftpd_port,Port},
- {ftpd_start_result,StartResult} | ConfigRewrite(Config0)],
- try
- ftp__close(ftp__open(Config,[verbose]))
- of
- Config1 when is_list(Config1) ->
- ct:log("Usuable ftp server ~p started on ~p:~p",[AbsName,Host,Port]),
- Config
- catch
- Class:Exception ->
- ct:log("Ftp server ~p started on ~p:~p but is unusable:~n~p:~p",
- [AbsName,Host,Port,Class,Exception]),
- {skip, [AbsName," started but unusuable"]}
- end;
- {error,Msg} ->
- {skip, [AbsName," not started: ",Msg]}
- end.
-
-stop_ftpd(Config) ->
- {_Name,_StartCmd,_ChkUp,StopCommand,_ConfigUpd,_Host,_Port} = proplists:get_value(ftpd_data, Config),
- StopCommand(proplists:get_value(ftpd_start_result,Config)).
-
-ps_ftpd(Config) ->
- {_Name,_StartCmd,ChkUp,_StopCommand,_ConfigUpd,_Host,_Port} = proplists:get_value(ftpd_data, Config),
- ct:log( ChkUp(proplists:get_value(ftpd_start_result,Config)) ).
-
-
-ftpd_running(Config) ->
- {_Name,_StartCmd,ChkUp,_StopCommand,_ConfigUpd,_Host,_Port} = proplists:get_value(ftpd_data, Config),
- ChkUp(proplists:get_value(ftpd_start_result,Config)).
-
-ftp__open(Config, Options) ->
- Host = proplists:get_value(ftpd_host,Config),
- Port = proplists:get_value(ftpd_port,Config),
- ct:log("Host=~p, Port=~p",[Host,Port]),
- {ok,Pid} = ftp:open(Host, [{port,Port} | Options]),
- [{ftp,Pid}|Config].
-
-ftp__close(Config) ->
- ok = ftp:close(proplists:get_value(ftp,Config)),
- Config.
-
-split(Cs) -> string:tokens(Cs, "\r\n").
-
-find_diff(Bin1, Bin2) ->
- case find_diff(Bin1, Bin2, 1) of
- {error, {diff,Pos,RC,LC}} ->
- ct:log("Contents differ at position ~p.~nOp1: ~p~nOp2: ~p",[Pos,RC,LC]),
- ct:fail("Contents differ at pos ~p",[Pos]);
- Other ->
- Other
- end.
-
-find_diff(A, A, _) -> true;
-find_diff(<<H,T1/binary>>, <<H,T2/binary>>, Pos) -> find_diff(T1, T2, Pos+1);
-find_diff(RC, LC, Pos) -> {error, {diff, Pos, RC, LC}}.
-
-set_state(Ops, Config) when is_list(Ops) -> lists:foldl(fun set_state/2, Config, Ops);
-
-set_state(reset, Config) ->
- rm('*', id2abs("",Config)),
- PrivDir = proplists:get_value(priv_dir,Config),
- file:set_cwd(PrivDir),
- ftp:lcd(proplists:get_value(ftp,Config),PrivDir),
- set_state({mkdir,""},Config);
-set_state({mkdir,Id}, Config) ->
- Abs = id2abs(Id, Config),
- mk_path(Abs),
- file:make_dir(Abs),
- Config;
-set_state({mkfile,Id,Contents}, Config) ->
- Abs = id2abs(Id, Config),
- mk_path(Abs),
- ok = file:write_file(Abs, Contents),
- Config.
-
-mk_path(Abs) -> lists:foldl(fun mk_path/2, [], filename:split(filename:dirname(Abs))).
-
-mk_path(F, Pfx) ->
- case file:read_file_info(AbsName=filename:join(Pfx,F)) of
- {ok,#file_info{type=directory}} ->
- AbsName;
- {error,eexist} ->
- AbsName;
- {error,enoent} ->
- ok = file:make_dir(AbsName),
- AbsName
- end.
-
-rm('*', Pfx) ->
- {ok,Fs} = file:list_dir(Pfx),
- lists:foreach(fun(F) -> rm(F, Pfx) end, Fs);
-rm(F, Pfx) ->
- case file:read_file_info(AbsName=filename:join(Pfx,F)) of
- {ok,#file_info{type=directory}} ->
- {ok,Fs} = file:list_dir(AbsName),
- lists:foreach(fun(F1) -> rm(F1,AbsName) end, Fs),
- ok = file:del_dir(AbsName);
-
- {ok,#file_info{type=regular}} ->
- ok = file:delete(AbsName);
-
- {error,enoent} ->
- ok
- end.
-
-id2abs(Id, Conf) -> filename:join(proplists:get_value(priv_dir,Conf),ids(Id)).
-id2ftp(Id, Conf) -> (proplists:get_value(id2ftp,Conf))(ids(Id)).
-id2ftp_result(Id, Conf) -> (proplists:get_value(id2ftp_result,Conf))(ids(Id)).
-
-ids([[_|_]|_]=Ids) -> filename:join(Ids);
-ids(Id) -> Id.
-
-
-is_expected_absName(Id, File, Conf) -> File = (proplists:get_value(id2abs,Conf))(Id).
-is_expected_ftpInName(Id, File, Conf) -> File = (proplists:get_value(id2ftp,Conf))(Id).
-is_expected_ftpOutName(Id, File, Conf) -> File = (proplists:get_value(id2ftp_result,Conf))(Id).
-
-
-%%%----------------------------------------------------------------
-%%% Help functions for the option '{progress,Progress}'
-%%%
-
-%%%----------------
-%%% Callback:
-
-progress(#progress{} = P, _File, {file_size, Total} = M) ->
- ct:pal("Progress: ~p",[M]),
- progress_report_receiver ! start,
- P#progress{total = Total};
-
-progress(#progress{current = Current} = P, _File, {transfer_size, 0} = M) ->
- ct:pal("Progress: ~p",[M]),
- progress_report_receiver ! finish,
- case P#progress.total of
- unknown -> P;
- Current -> P;
- Total -> ct:fail({error, {progress, {total,Total}, {current,Current}}}),
- P
- end;
-
-progress(#progress{current = Current} = P, _File, {transfer_size, Size} = M) ->
- ct:pal("Progress: ~p",[M]),
- progress_report_receiver ! update,
- P#progress{current = Current + Size};
-
-progress(P, _File, M) ->
- ct:pal("Progress **** Strange: ~p",[M]),
- P.
-
-
-%%%----------------
-%%% Help process that counts the files transferred:
-
-progress_report_receiver_init(Parent, N) ->
- register(progress_report_receiver, self()),
- progress_report_receiver_expect_N_files(Parent, N).
-
-progress_report_receiver_expect_N_files(_Parent, 0) ->
- ct:pal("progress_report got all files!", []);
-progress_report_receiver_expect_N_files(Parent, N) ->
- ct:pal("progress_report expects ~p more files",[N]),
- receive
- start -> ok
- end,
- progress_report_receiver_loop(Parent, N-1).
-
-
-progress_report_receiver_loop(Parent, N) ->
- ct:pal("progress_report expect update | finish. N = ~p",[N]),
- receive
- update ->
- ct:pal("progress_report got update",[]),
- progress_report_receiver_loop(Parent, N);
- finish ->
- ct:pal("progress_report got finish, send ~p to ~p",[{self(),ok}, Parent]),
- Parent ! {self(), ok},
- progress_report_receiver_expect_N_files(Parent, N)
- end.
-
-%%%----------------------------------------------------------------
-%%% Help functions for bug OTP-6035
-
-is_error_report_6035(LogFile) ->
- case file:read_file(LogFile) of
- {ok, Bin} ->
- nomatch =/= binary:match(Bin, <<"=ERROR REPORT====">>);
- _ ->
- false
- end.
-
diff --git a/lib/inets/test/ftp_SUITE_data/vsftpd.conf b/lib/inets/test/ftp_SUITE_data/vsftpd.conf
deleted file mode 100644
index a5584f5916..0000000000
--- a/lib/inets/test/ftp_SUITE_data/vsftpd.conf
+++ /dev/null
@@ -1,26 +0,0 @@
-
-###
-### Some parameters are given in the vsftpd start command.
-###
-### Typical command-line paramters are such that has a file path
-### component like cert files.
-###
-
-
-listen=YES
-listen_port=9999
-run_as_launching_user=YES
-ssl_enable=YES
-allow_anon_ssl=YES
-
-background=YES
-
-write_enable=YES
-anonymous_enable=YES
-anon_upload_enable=YES
-anon_mkdir_write_enable=YES
-anon_other_write_enable=YES
-anon_world_readable_only=NO
-
-### Shouldn't be necessary....
-require_ssl_reuse=NO
diff --git a/lib/inets/test/ftp_format_SUITE.erl b/lib/inets/test/ftp_format_SUITE.erl
deleted file mode 100644
index 95d594a44b..0000000000
--- a/lib/inets/test/ftp_format_SUITE.erl
+++ /dev/null
@@ -1,328 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(ftp_format_SUITE).
--author('[email protected]').
-
--include_lib("common_test/include/ct.hrl").
--include("ftp_internal.hrl").
-
-%% Note: This directive should only be used in test suites.
--compile(export_all).
-
-suite() ->
- [{ct_hooks,[ts_install_cth]},
- {timetrap,{seconds,5}}
- ].
-
-all() ->
- [{group, ftp_response}, format_error].
-
-groups() ->
- [{ftp_response, [],
- [ftp_150, ftp_200, ftp_220, ftp_226, ftp_257, ftp_331,
- ftp_425, ftp_other_status_codes, ftp_multiple_lines_status_in_msg,
- ftp_multiple_lines, ftp_multipel_ctrl_messages]}].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-init_per_testcase(_, Config) ->
- Config.
-end_per_testcase(_, _) ->
- ok.
-
-%%-------------------------------------------------------------------------
-%% Test cases starts here.
-%%-------------------------------------------------------------------------
-
-ftp_150() ->
- [{doc, "Especially check that respons can be devided in a random place."}].
-ftp_150(Config) when is_list(Config) ->
- FtpResponse = ["150 ASCII data conn", "ection for /bin/ls ",
- "(134.138.177", ".89,50434) (0 bytes).\r\n"],
-
- "150 ASCII data connection for /bin/ls "
- "(134.138.177.89,50434) (0 bytes).\r\n" = Msg =
- parse(ftp_response, parse_lines, [[], start], FtpResponse),
- {pos_prel, _} = ftp_response:interpret(Msg).
-
-ftp_200() ->
- [{doc, "Especially check that respons can be devided after the first status "
- "code character and in the end delimiter."}].
-ftp_200(Config) when is_list(Config) ->
- FtpResponse = ["2", "00 PORT command successful.", [?CR], [?LF]],
-
- "200 PORT command successful.\r\n" = Msg =
- parse(ftp_response, parse_lines, [[], start], FtpResponse),
- {pos_compl, _} = ftp_response:interpret(Msg),
- ok.
-
-ftp_220() ->
- [{doc, "Especially check that respons can be devided after the "
- "first with space "}].
-ftp_220(Config) when is_list(Config) ->
- FtpResponse = ["220 ","fingon FTP server (SunOS 5.8) ready.\r\n"],
-
- "220 fingon FTP server (SunOS 5.8) ready.\r\n" = Msg =
- parse(ftp_response, parse_lines, [[], start], FtpResponse),
- {pos_compl, _} = ftp_response:interpret(Msg),
- ok.
-
-ftp_226() ->
- [{doc, "Especially check that respons can be devided after second status code"
- " character and in the end delimiter."}].
-ftp_226(Config) when is_list(Config) ->
- FtpResponse = ["22" "6 Transfer complete.\r", [?LF]],
-
- "226 Transfer complete.\r\n" = Msg =
- parse(ftp_response, parse_lines, [[], start], FtpResponse),
- {pos_compl, _} = ftp_response:interpret(Msg),
- ok.
-
-ftp_257() ->
- [{doc, "Especially check that quoted chars do not cause a problem."}].
-ftp_257(Config) when is_list(Config) ->
- FtpResponse = ["257 \"/\" is current directory.\r\n"],
-
- "257 \"/\" is current directory.\r\n" = Msg =
- parse(ftp_response, parse_lines, [[], start], FtpResponse),
- {pos_compl, _} = ftp_response:interpret(Msg),
- ok.
-
-ftp_331() ->
- [{doc, "Especially check that respons can be devided after the third status "
- " status code character."}].
-ftp_331(Config) when is_list(Config) ->
- %% Brake before white space after code
- FtpResponse =
- ["331"," Guest login ok, send ient as password.\r\n"],
-
- "331 Guest login ok, send ient as password.\r\n" = Msg =
- parse(ftp_response, parse_lines, [[], start], FtpResponse),
- {pos_interm, _} = ftp_response:interpret(Msg),
- ok.
-
-ftp_425() ->
- [{doc, "Especially check a message that was received in only one part."}].
-ftp_425(Config) when is_list(Config) ->
- FtpResponse =
- ["425 Can't build data connection: Connection refused.\r\n"],
-
- "425 Can't build data connection: Connection refused.\r\n"
- = Msg = parse(ftp_response, parse_lines, [[], start], FtpResponse),
- {trans_neg_compl, _} = ftp_response:interpret(Msg),
- ok.
-
-ftp_multiple_lines_status_in_msg() ->
- [{doc, "check that multiple lines gets parsed correct, even if we have "
- " the status code within the msg being sent"}].
-ftp_multiple_lines_status_in_msg(Config) when is_list(Config) ->
- ML = "230-User usr-230 is logged in\r\n" ++
- "230 OK. Current directory is /\r\n",
- {ok, ML, <<>>} = ftp_response:parse_lines(list_to_binary(ML), [], start),
- ok.
-
-ftp_multiple_lines() ->
- [{doc, "Especially check multiple lines devided in significant places"}].
-ftp_multiple_lines(Config) when is_list(Config) ->
- FtpResponse = ["21", "4","-The",
- " following commands are recognized:\r\n"
- " USER EPRT STRU MAIL* ALLO CWD",
- " STAT* XRMD \r\n"
- " PASS LPRT MODE MSND* "
- " REST* XCWD HELP PWD ", [?CRLF],
- " ACCT* EPSV RETR MSOM* RNFR LIST "
- " NOOP XPWD \r\n",
- " REIN* LPSV STOR MSAM* RNTO NLST "
- " MKD CDUP \r\n"
- " QUIT PASV APPE MRSQ* ABOR SITE* "
- " XMKD XCUP \r\n"
- " PORT TYPE MLFL* MRCP* DELE SYST "
- " RMD STOU \r\n"
- "214 (*'s => unimplemented)", [?CR], [?LF]],
-
-
- FtpResponse1 = ["214-", "The",
- " following commands are recognized:\r\n"
- " USER EPRT STRU MAIL* ALLO CWD",
- " STAT* XRMD \r\n"
- " PASS LPRT MODE MSND* "
- " REST* XCWD HELP PWD ", [?CRLF],
- " ACCT* EPSV RETR MSOM* RNFR LIST "
- " NOOP XPWD \r\n",
- " REIN* LPSV STOR MSAM* RNTO NLST "
- " MKD CDUP \r\n"
- " QUIT PASV APPE MRSQ* ABOR SITE* "
- " XMKD XCUP \r\n"
- " PORT TYPE MLFL* MRCP* DELE SYST "
- " RMD STOU \r\n"
- "2", "14 (*'s => unimplemented)", [?CR], [?LF]],
-
- FtpResponse2 = ["214-", "The",
- " following commands are recognized:\r\n"
- " USER EPRT STRU MAIL* ALLO CWD",
- " STAT* XRMD \r\n"
- " PASS LPRT MODE MSND* "
- " REST* XCWD HELP PWD ", [?CRLF],
- " ACCT* EPSV RETR MSOM* RNFR LIST "
- " NOOP XPWD \r\n",
- " REIN* LPSV STOR MSAM* RNTO NLST "
- " MKD CDUP \r\n"
- " QUIT PASV APPE MRSQ* ABOR SITE* "
- " XMKD XCUP \r\n"
- " PORT TYPE MLFL* MRCP* DELE SYST "
- " RMD STOU \r\n"
- "21", "4"," (*'s => unimplemented)", [?CR], [?LF]],
-
- MultiLineResultStr =
- "214-The following commands are recognized:\r\n"
- " USER EPRT STRU MAIL* ALLO CWD STAT* "
- "XRMD \r\n"
- " PASS LPRT MODE MSND* REST* XCWD HELP "
- "PWD \r\n"
- " ACCT* EPSV RETR MSOM* RNFR LIST NOOP "
- "XPWD \r\n"
- " REIN* LPSV STOR MSAM* RNTO NLST MKD "
- "CDUP \r\n"
- " QUIT PASV APPE MRSQ* ABOR SITE* XMKD "
- "XCUP \r\n"
- " PORT TYPE MLFL* MRCP* DELE SYST RMD "
- "STOU \r\n"
- "214 (*'s => unimplemented)\r\n",
-
- MultiLineResultStr =
- parse(ftp_response, parse_lines, [[], start], FtpResponse),
- {pos_compl, _} = ftp_response:interpret(MultiLineResultStr),
-
- MultiLineResultStr = parse(ftp_response, parse_lines, [[], start],
- FtpResponse1),
-
- MultiLineResultStr = parse(ftp_response, parse_lines, [[], start],
- FtpResponse2),
- ok.
-
-ftp_other_status_codes() ->
- [{doc, "Check that other valid status codes, than the ones above, are handled"
- "by ftp_response:interpret/1. Note there are som ftp status codes"
- "that will not be received with the current ftp instruction support,"
- "they are not included here."}].
-ftp_other_status_codes(Config) when is_list(Config) ->
-
- %% 1XX
- {pos_prel, _ } = ftp_response:interpret("120 Foobar\r\n"),
-
- %% 2XX
- {pos_compl, _ } = ftp_response:interpret("202 Foobar\r\n"),
- {pos_compl, _ } = ftp_response:interpret("221 Foobar\r\n"),
- {pos_compl, _ } = ftp_response:interpret("227 Foobar\r\n"),
- {pos_compl, _ } = ftp_response:interpret("230 Foobar\r\n"),
- {pos_compl, _ } = ftp_response:interpret("250 Foobar\r\n"),
-
- %% 3XX
- {pos_interm_acct, _ } = ftp_response:interpret("332 Foobar\r\n"),
- {pos_interm, _ } = ftp_response:interpret("350 Foobar\r\n"),
-
- %% 4XX
- {trans_neg_compl, _ } = ftp_response:interpret("421 Foobar\r\n"),
- {trans_neg_compl, _ } = ftp_response:interpret("426 Foobar\r\n"),
- {enofile, _ } = ftp_response:interpret("450 Foobar\r\n"),
- {trans_neg_compl, _ } = ftp_response:interpret("451 Foobar\r\n"),
- {etnospc, _ } = ftp_response:interpret("452 Foobar\r\n"),
-
- %% 5XX
- {perm_neg_compl, _ } = ftp_response:interpret("500 Foobar\r\n"),
- {perm_neg_compl, _ } = ftp_response:interpret("501 Foobar\r\n"),
- {perm_neg_compl, _ } = ftp_response:interpret("503 Foobar\r\n"),
- {perm_neg_compl, _ } = ftp_response:interpret("504 Foobar\r\n"),
- {elogin, _ } = ftp_response:interpret("530 Foobar\r\n"),
- {perm_neg_compl, _ } = ftp_response:interpret("532 Foobar\r\n"),
- {epath, _ } = ftp_response:interpret("550 Foobar\r\n"),
- {epnospc, _ } = ftp_response:interpret("552 Foobar\r\n"),
- {efnamena, _ } = ftp_response:interpret("553 Foobar\r\n"),
- ok.
-
-ftp_multipel_ctrl_messages() ->
- [{doc, "The ftp server may send more than one control message as a reply,"
- "check that they are handled one at the time."}].
-ftp_multipel_ctrl_messages(Config) when is_list(Config) ->
- FtpResponse = ["200 PORT command successful.\r\n200 Foobar\r\n"],
-
- {"200 PORT command successful.\r\n" = Msg, NextMsg} =
- parse(ftp_response, parse_lines, [[], start], FtpResponse),
- {pos_compl, _} = ftp_response:interpret(Msg),
- NewMsg = parse(ftp_response, parse_lines, [[], start], NextMsg),
- {pos_compl, _} = ftp_response:interpret(NewMsg),
- ok.
-
-
-%%-------------------------------------------------------------------------
-format_error(Config) when is_list(Config) ->
- "Synchronisation error during chunk sending." =
- ftp:formaterror(echunk),
- "Session has been closed." = ftp:formaterror(eclosed),
- "Connection to remote server prematurely closed." =
- ftp:formaterror(econn),
- "File or directory already exists." = ftp:formaterror(eexists),
- "Host not found, FTP server not found, or connection rejected." =
- ftp:formaterror(ehost),
- "User not logged in." = ftp:formaterror(elogin),
- "Term is not a binary." = ftp:formaterror(enotbinary),
- "No such file or directory, already exists, or permission denied."
- = ftp:formaterror(epath),
- "No such type." = ftp:formaterror(etype),
- "User name or password not valid." = ftp:formaterror(euser),
- "Insufficient storage space in system." = ftp:formaterror(etnospc),
- "Exceeded storage allocation (for current directory or dataset)."
- = ftp:formaterror(epnospc),
- "File name not allowed." = ftp:formaterror(efnamena),
- "Unknown error: foobar" = ftp:formaterror({error, foobar}).
-
-%%--------------------------------------------------------------------
-%%% Internal functions
-%%--------------------------------------------------------------------
-parse(Module, Function, Args, Bin) when is_binary(Bin) ->
- parse(Module, Function, Args, [binary_to_list(Bin)]);
-
-parse(Module, Function, [AccLines, StatusCode], [Data | Rest]) ->
- case Module:Function(list_to_binary(Data), AccLines, StatusCode) of
- {ok, Result, <<>>} ->
- Result;
- {ok, Result, Next} ->
- {Result, Next};
- {continue, {NewData, NewAccLines, NewStatusCode}} ->
- case Rest of
- [] ->
- ct:fail({wrong_input, Data, Rest});
- [_ | _] ->
- parse(Module, Function, [NewAccLines, NewStatusCode],
- [binary_to_list(NewData) ++ hd(Rest) | tl(Rest)])
- end
- end.
diff --git a/lib/inets/test/ftp_internal.hrl b/lib/inets/test/ftp_internal.hrl
deleted file mode 120000
index af57081f14..0000000000
--- a/lib/inets/test/ftp_internal.hrl
+++ /dev/null
@@ -1 +0,0 @@
-../src/ftp/ftp_internal.hrl \ No newline at end of file
diff --git a/lib/inets/test/ftp_property_test_SUITE.erl b/lib/inets/test/ftp_property_test_SUITE.erl
deleted file mode 100644
index b314882296..0000000000
--- a/lib/inets/test/ftp_property_test_SUITE.erl
+++ /dev/null
@@ -1,53 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
-%%% Run like this:
-%%% ct:run_test([{suite,"ftp_property_test_SUITE"}, {logdir,"/ldisk/OTP/LOG"}]).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%% %%%
-%%% WARNING %%%
-%%% %%%
-%%% This is experimental code which may be changed or removed %%%
-%%% anytime without any warning. %%%
-%%% %%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--module(ftp_property_test_SUITE).
-
--compile(export_all).
-
--include_lib("common_test/include/ct.hrl").
-
-all() -> [prop_ftp_case].
-
-
-init_per_suite(Config) ->
- inets:start(),
- ct_property_test:init_per_suite(Config).
-
-
-%%%---- test case
-prop_ftp_case(Config) ->
- ct_property_test:quickcheck(
- ftp_simple_client_server:prop_ftp(Config),
- Config
- ).
diff --git a/lib/inets/test/http_format_SUITE.erl b/lib/inets/test/http_format_SUITE.erl
index 647eff4f7c..0a5aed67d5 100644
--- a/lib/inets/test/http_format_SUITE.erl
+++ b/lib/inets/test/http_format_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -435,7 +435,7 @@ http_request(Config) when is_list(Config) ->
[<<>>, Length1], HttpBody1)).
%%-------------------------------------------------------------------------
validate_request_line() ->
- [{doc, "Test httpd_request:validate/3. Makes sure you can not get past"
+ [{doc, "Test httpd_request:validate/3. Makes sure you cannot get past"
" the server_root and that the request is recognized by the server"
" and protcol version."}].
validate_request_line(Config) when is_list(Config) ->
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index 9bf58f18e5..d4b33ae2c6 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -53,29 +53,37 @@ suite() ->
all() ->
[
{group, http},
+ {group, http_ipv6},
{group, sim_http},
{group, http_internal},
{group, http_unix_socket},
{group, https},
{group, sim_https},
- {group, misc}
+ {group, misc},
+ {group, sim_mixed} % HTTP and HTTPS sim servers
].
groups() ->
[
{http, [], real_requests()},
- {sim_http, [], only_simulated() ++ [process_leak_on_keepalive]},
+ {http_ipv6, [], [request_options]},
+ %% process_leak_on_keepalive is depending on stream_fun_server_close
+ %% and it shall be the last test case in the suite otherwise cookie
+ %% will fail.
+ {sim_http, [], only_simulated() ++ server_closing_connection() ++ [process_leak_on_keepalive]},
{http_internal, [], real_requests_esi()},
{http_unix_socket, [], simulated_unix_socket()},
{https, [], real_requests()},
{sim_https, [], only_simulated()},
- {misc, [], misc()}
+ {misc, [], misc()},
+ {sim_mixed, [], sim_mixed()}
].
real_requests()->
[
head,
get,
+ get_query_string,
post,
delete,
post_stream,
@@ -141,18 +149,36 @@ only_simulated() ->
redirect_found,
redirect_see_other,
redirect_temporary_redirect,
+ redirect_relative_uri,
port_in_host_header,
redirect_port_in_host_header,
relaxed,
multipart_chunks,
+ get_space,
+ delete_no_body,
+ post_with_content_type,
stream_fun_server_close
].
+server_closing_connection() ->
+ [
+ server_closing_connection_on_first_response,
+ server_closing_connection_on_second_response
+ ].
+
misc() ->
[
server_does_not_exist,
timeout_memory_leak,
- wait_for_whole_response
+ wait_for_whole_response,
+ post_204_chunked,
+ chunkify_fun
+ ].
+
+sim_mixed() ->
+ [
+ redirect_http_to_https,
+ redirect_relative_different_port
].
%%--------------------------------------------------------------------
@@ -180,7 +206,8 @@ init_per_group(misc = Group, Config) ->
Config;
-init_per_group(Group, Config0) when Group =:= sim_https; Group =:= https->
+init_per_group(Group, Config0) when Group =:= sim_https; Group =:= https;
+ Group =:= sim_mixed ->
catch crypto:stop(),
try crypto:start() of
ok ->
@@ -201,6 +228,16 @@ init_per_group(http_unix_socket = Group, Config0) ->
Port = server_start(Group, server_config(Group, Config)),
[{port, Port} | Config]
end;
+init_per_group(http_ipv6 = Group, Config0) ->
+ case is_ipv6_supported() of
+ true ->
+ start_apps(Group),
+ Config = proplists:delete(port, Config0),
+ Port = server_start(Group, server_config(Group, Config)),
+ [{port, Port} | Config];
+ false ->
+ {skip, "Host does not support IPv6"}
+ end;
init_per_group(Group, Config0) ->
start_apps(Group),
Config = proplists:delete(port, Config0),
@@ -213,10 +250,44 @@ end_per_group(http_unix_socket,_Config) ->
end_per_group(_, _Config) ->
ok.
+do_init_per_group(Group=sim_mixed, Config0) ->
+ % The mixed group uses two server ports (http and https), so we use
+ % different config names here.
+ Config1 = init_ssl(Config0),
+ Config2 = proplists:delete(http_port, proplists:delete(https_port, Config1)),
+ {HttpPort, HttpsPort} = server_start(Group, server_config(sim_https, Config2)),
+ [{http_port, HttpPort} | [{https_port, HttpsPort} | Config2]];
do_init_per_group(Group, Config0) ->
- Config = proplists:delete(port, Config0),
+ Config1 =
+ case Group of
+ https ->
+ init_ssl(Config0);
+ sim_https ->
+ init_ssl(Config0);
+ _ ->
+ Config0
+ end,
+ Config = proplists:delete(port, Config1),
Port = server_start(Group, server_config(Group, Config)),
[{port, Port} | Config].
+
+init_ssl(Config) ->
+ ClientFileBase = filename:join([proplists:get_value(priv_dir, Config), "client"]),
+ ServerFileBase = filename:join([proplists:get_value(priv_dir, Config), "server"]),
+ GenCertData =
+ public_key:pkix_test_data(#{server_chain =>
+ #{root => [{key, inets_test_lib:hardcode_rsa_key(1)}],
+ intermediates => [[{key, inets_test_lib:hardcode_rsa_key(2)}]],
+ peer => [{key, inets_test_lib:hardcode_rsa_key(3)}
+ ]},
+ client_chain =>
+ #{root => [{key, inets_test_lib:hardcode_rsa_key(4)}],
+ intermediates => [[{key, inets_test_lib:hardcode_rsa_key(5)}]],
+ peer => [{key, inets_test_lib:hardcode_rsa_key(6)}]}}),
+
+ Conf = inets_test_lib:gen_pem_config_files(GenCertData, ClientFileBase, ServerFileBase),
+ [{ssl_conf, Conf} | Config].
+
%%--------------------------------------------------------------------
init_per_testcase(pipeline, Config) ->
inets:start(httpc, [{profile, pipeline}]),
@@ -227,7 +298,7 @@ init_per_testcase(pipeline, Config) ->
init_per_testcase(persistent_connection, Config) ->
inets:start(httpc, [{profile, persistent}]),
httpc:set_options([{keep_alive_timeout, 50000},
- {max_keep_alive_length, 3}], persistent_connection),
+ {max_keep_alive_length, 3}], persistent),
Config;
init_per_testcase(wait_for_whole_response, Config) ->
@@ -246,10 +317,30 @@ end_per_testcase(pipeline, _Config) ->
inets:stop(httpc, pipeline);
end_per_testcase(persistent_connection, _Config) ->
inets:stop(httpc, persistent);
+end_per_testcase(Case, Config)
+ when Case == server_closing_connection_on_first_response;
+ Case == server_closing_connection_on_second_response ->
+ %% Test case uses at most one session. Ensure no leftover
+ %% sessions left behind.
+ {_, Status} = proplists:lookup(tc_status, Config),
+ ShallCleanup = case Status of
+ ok -> true;
+ {failed, _} -> true;
+ {skipped, _} -> false
+ end,
+ if ShallCleanup =:= true ->
+ httpc:request(url(group_name(Config), "/just_close.html", Config)),
+ ok;
+ true ->
+ ct:pal("Not cleaning up because test case status was ~p", [Status]),
+ ok
+ end;
end_per_testcase(_Case, _Config) ->
ok.
+
+
%%--------------------------------------------------------------------
%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
@@ -271,6 +362,25 @@ get(Config) when is_list(Config) ->
{ok, {{_,200,_}, [_ | _], BinBody}} = httpc:request(get, Request, [], [{body_format, binary}]),
true = is_binary(BinBody).
+
+
+get_query_string() ->
+ [{doc, "Test http get request with query string against local server"}].
+get_query_string(Config) when is_list(Config) ->
+ Request = {url(group_name(Config), "/dummy.html?foo=bar", Config), []},
+ {ok, {{_,200,_}, [_ | _], Body = [_ | _]}} = httpc:request(get, Request, [], []),
+
+ inets_test_lib:check_body(Body).
+
+%%--------------------------------------------------------------------
+get_space() ->
+ [{"Test http get request with '%20' in the path of the URL."}].
+get_space(Config) when is_list(Config) ->
+ Request = {url(group_name(Config), "/space%20.html", Config), []},
+ {ok, {{_,200,_}, [_ | _], Body = [_ | _]}} = httpc:request(get, Request, [], []),
+
+ inets_test_lib:check_body(Body).
+
%%--------------------------------------------------------------------
post() ->
[{"Test http post request against local server. We do in this case "
@@ -604,7 +714,26 @@ redirect_temporary_redirect(Config) when is_list(Config) ->
{ok, {{_,200,_}, [_ | _], [_|_]}}
= httpc:request(post, {URL307, [],"text/plain", "foobar"},
[], []).
+%%-------------------------------------------------------------------------
+redirect_relative_uri() ->
+ [{doc, "The server SHOULD generate a Location header field in the response "
+ "containing a preferred URI reference for the new permanent URI. The user "
+ "agent MAY use the Location field value for automatic redirection. The server's "
+ "response payload usually contains a short hypertext note with a "
+ "hyperlink to the new URI(s)."}].
+redirect_relative_uri(Config) when is_list(Config) ->
+
+ URL301 = url(group_name(Config), "/301_rel_uri.html", Config),
+ {ok, {{_,200,_}, [_ | _], [_|_]}}
+ = httpc:request(get, {URL301, []}, [], []),
+
+ {ok, {{_,200,_}, [_ | _], []}}
+ = httpc:request(head, {URL301, []}, [], []),
+
+ {ok, {{_,200,_}, [_ | _], [_|_]}}
+ = httpc:request(post, {URL301, [],"text/plain", "foobar"},
+ [], []).
%%-------------------------------------------------------------------------
redirect_loop() ->
[{"doc, Test redirect loop detection"}].
@@ -616,6 +745,48 @@ redirect_loop(Config) when is_list(Config) ->
= httpc:request(get, {URL, []}, [], []).
%%-------------------------------------------------------------------------
+redirect_http_to_https() ->
+ [{doc, "Test that a 30X redirect from one scheme to another is handled "
+ "correctly."}].
+redirect_http_to_https(Config) when is_list(Config) ->
+ URL301 = mixed_url(http, "/301_custom_url.html", Config),
+ TargetUrl = mixed_url(https, "/dummy.html", Config),
+ Headers = [{"x-test-301-url", TargetUrl}],
+
+ {ok, {{_,200,_}, [_ | _], [_|_]}}
+ = httpc:request(get, {URL301, Headers}, [], []),
+
+ {ok, {{_,200,_}, [_ | _], []}}
+ = httpc:request(head, {URL301, Headers}, [], []),
+
+ {ok, {{_,200,_}, [_ | _], [_|_]}}
+ = httpc:request(post, {URL301, Headers, "text/plain", "foobar"},
+ [], []).
+%%-------------------------------------------------------------------------
+redirect_relative_different_port() ->
+ [{doc, "Test that a 30X redirect with a relative target, but different "
+ "port, is handled correctly."}].
+redirect_relative_different_port(Config) when is_list(Config) ->
+ URL301 = mixed_url(http, "/301_custom_url.html", Config),
+
+ % We need an extra server of the same protocol here, so spawn a new
+ % HTTP-protocol one
+ Port = server_start(sim_http, []),
+ {ok, Host} = inet:gethostname(),
+ % Prefix the URI with '/' instead of a scheme
+ TargetUrl = "//" ++ Host ++ ":" ++ integer_to_list(Port) ++ "/dummy.html",
+ Headers = [{"x-test-301-url", TargetUrl}],
+
+ {ok, {{_,200,_}, [_ | _], [_|_]}}
+ = httpc:request(get, {URL301, Headers}, [], []),
+
+ {ok, {{_,200,_}, [_ | _], []}}
+ = httpc:request(head, {URL301, Headers}, [], []),
+
+ {ok, {{_,200,_}, [_ | _], [_|_]}}
+ = httpc:request(post, {URL301, Headers, "text/plain", "foobar"},
+ [], []).
+%%-------------------------------------------------------------------------
cookie() ->
[{doc, "Test cookies."}].
cookie(Config) when is_list(Config) ->
@@ -1082,8 +1253,6 @@ remote_socket_close_async(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
process_leak_on_keepalive(Config) ->
- {ok, ClosedSocket} = gen_tcp:listen(6666, [{active, false}]),
- ok = gen_tcp:close(ClosedSocket),
Request = {url(group_name(Config), "/dummy.html", Config), []},
HttpcHandlers0 = supervisor:which_children(httpc_handler_sup),
{ok, {{_, 200, _}, _, Body}} = httpc:request(get, Request, [], []),
@@ -1095,11 +1264,10 @@ process_leak_on_keepalive(Config) ->
ordsets:to_list(
ordsets:subtract(ordsets:from_list(HttpcHandlers1),
ordsets:from_list(HttpcHandlers0))),
- sys:replace_state(
- Pid, fun (State) ->
- Session = element(3, State),
- setelement(3, State, Session#session{socket=ClosedSocket})
- end),
+ State = sys:get_state(Pid),
+ #session{socket=Socket} = element(3, State),
+ gen_tcp:close(Socket),
+
{ok, {{_, 200, _}, _, Body}} = httpc:request(get, Request, [], []),
%% bad handler with the closed socket should get replaced by
%% the new one, so children count should stay the same
@@ -1218,6 +1386,109 @@ wait_for_whole_response(Config) when is_list(Config) ->
ReqSeqNumServer ! shutdown.
%%--------------------------------------------------------------------
+post_204_chunked() ->
+ [{doc,"Test that chunked encoded 204 responses do not freeze the http client"}].
+post_204_chunked(_Config) ->
+ Msg = "HTTP/1.1 204 No Content\r\n" ++
+ "Date: Thu, 23 Aug 2018 13:36:29 GMT\r\n" ++
+ "Content-Type: text/html\r\n" ++
+ "Server: inets/6.5.2.3\r\n" ++
+ "Cache-Control: no-cache\r\n" ++
+ "Pragma: no-cache\r\n" ++
+ "Expires: Fri, 24 Aug 2018 07:49:35 GMT\r\n" ++
+ "Transfer-Encoding: chunked\r\n" ++
+ "\r\n",
+ Chunk = "0\r\n\r\n",
+
+ {ok, ListenSocket} = gen_tcp:listen(0, [{active,once}, binary]),
+ {ok,{_,Port}} = inet:sockname(ListenSocket),
+ spawn(fun () -> custom_server(Msg, Chunk, ListenSocket,
+ fun post_204_receive/0) end),
+
+ {ok,Host} = inet:gethostname(),
+ End = "/cgi-bin/erl/httpd_example:post_204",
+ URL = ?URL_START ++ Host ++ ":" ++ integer_to_list(Port) ++ End,
+ {ok, _} = httpc:request(post, {URL, [], "text/html", []}, [], []),
+ timer:sleep(500),
+ %% Second request times out in the faulty case.
+ {ok, _} = httpc:request(post, {URL, [], "text/html", []}, [], []).
+
+post_204_receive() ->
+ receive
+ {tcp, _, Msg} ->
+ ct:log("Message received: ~p", [Msg])
+ after
+ 1000 ->
+ ct:fail("Timeout: did not recive packet")
+ end.
+
+%% Custom server is used to test special cases when using chunked encoding
+custom_server(Msg, Chunk, ListenSocket, ReceiveFun) ->
+ {ok, Accept} = gen_tcp:accept(ListenSocket),
+ ReceiveFun(),
+ send_response(Msg, Chunk, Accept),
+ custom_server_loop(Msg, Chunk, Accept, ReceiveFun).
+
+custom_server_loop(Msg, Chunk, Accept, ReceiveFun) ->
+ ReceiveFun(),
+ send_response(Msg, Chunk, Accept),
+ custom_server_loop(Msg, Chunk, Accept, ReceiveFun).
+
+send_response(Msg, Chunk, Socket) ->
+ inet:setopts(Socket, [{active, once}]),
+ gen_tcp:send(Socket, Msg),
+ timer:sleep(250),
+ gen_tcp:send(Socket, Chunk).
+
+%%--------------------------------------------------------------------
+chunkify_fun() ->
+ [{doc,"Test that a chunked encoded request does not include the 'Content-Length header'"}].
+chunkify_fun(_Config) ->
+ Msg = "HTTP/1.1 204 No Content\r\n" ++
+ "Date: Thu, 23 Aug 2018 13:36:29 GMT\r\n" ++
+ "Content-Type: text/html\r\n" ++
+ "Server: inets/6.5.2.3\r\n" ++
+ "Cache-Control: no-cache\r\n" ++
+ "Pragma: no-cache\r\n" ++
+ "Expires: Fri, 24 Aug 2018 07:49:35 GMT\r\n" ++
+ "Transfer-Encoding: chunked\r\n" ++
+ "\r\n",
+ Chunk = "0\r\n\r\n",
+
+ {ok, ListenSocket} = gen_tcp:listen(0, [{active,once}, binary]),
+ {ok,{_,Port}} = inet:sockname(ListenSocket),
+ spawn(fun () -> custom_server(Msg, Chunk, ListenSocket,
+ fun chunkify_receive/0) end),
+
+ {ok,Host} = inet:gethostname(),
+ End = "/cgi-bin/erl/httpd_example",
+ URL = ?URL_START ++ Host ++ ":" ++ integer_to_list(Port) ++ End,
+ Fun = fun(_) -> {ok,<<1>>,eof_body} end,
+ Acc = start,
+
+ {ok, {{_,204,_}, _, _}} =
+ httpc:request(put, {URL, [], "text/html", {chunkify, Fun, Acc}}, [], []).
+
+chunkify_receive() ->
+ Error = "HTTP/1.1 500 Internal Server Error\r\n" ++
+ "Content-Length: 0\r\n\r\n",
+ receive
+ {tcp, Port, Msg} ->
+ case binary:match(Msg, <<"content-length">>) of
+ nomatch ->
+ ct:log("Message received: ~s", [binary_to_list(Msg)]);
+ {_, _} ->
+ ct:log("Message received (negative): ~s", [binary_to_list(Msg)]),
+ %% Signal a testcase failure when the received HTTP request
+ %% contains a 'Content-Length' header.
+ gen_tcp:send(Port, Error),
+ ct:fail("Content-Length present in received headers.")
+ end
+ after
+ 1000 ->
+ ct:fail("Timeout: did not recive packet")
+ end.
+%%--------------------------------------------------------------------
stream_fun_server_close() ->
[{doc, "Test that an error msg is received when using a receiver fun as stream target"}].
stream_fun_server_close(Config) when is_list(Config) ->
@@ -1234,6 +1505,53 @@ stream_fun_server_close(Config) when is_list(Config) ->
end.
%%--------------------------------------------------------------------
+server_closing_connection_on_first_response() ->
+ [{doc, "Client receives \"Connection: close\" on first response."
+ "A client that receives a \"close\" connection option MUST cease sending"
+ "requests on that connection and close the connection after reading"
+ "the response message containing the \"close\""}].
+server_closing_connection_on_first_response(Config) when is_list(Config) ->
+ ReqSrvSendOctFun =
+ fun(V, U, S) ->
+ {ok, {{V, S, _}, Headers0, []}} =
+ httpc:request(get, {U, []}, [{version, V}], []),
+ {_, SendOctStr} =
+ proplists:lookup("x-socket-stat-send-oct", Headers0),
+ list_to_integer(SendOctStr)
+ end,
+ V = "HTTP/1.1",
+ Url0 = url(group_name(Config), "/http_1_1_send_oct.html", Config),
+ Url1 = url(group_name(Config), "/http_1_1_send_oct_and_connection_close.html", Config),
+ %% Test case assumes at most one reusable past session.
+ _ = ReqSrvSendOctFun(V, Url1, 204),
+ 0 = ReqSrvSendOctFun(V, Url0, 204),
+ ok.
+
+%%--------------------------------------------------------------------
+server_closing_connection_on_second_response() ->
+ [{doc, "Client receives \"Connection: close\" on second response."
+ "A client that receives a \"close\" connection option MUST cease sending"
+ "requests on that connection and close the connection after reading"
+ "the response message containing the \"close\""}].
+server_closing_connection_on_second_response(Config) when is_list(Config) ->
+ ReqSrvSendOctFun =
+ fun(V, U, S) ->
+ {ok, {{V, S, _}, Headers0, []}} =
+ httpc:request(get, {U, []}, [{version, V}], []),
+ {_, SendOctStr} =
+ proplists:lookup("x-socket-stat-send-oct", Headers0),
+ list_to_integer(SendOctStr)
+ end,
+ V = "HTTP/1.1",
+ Url0 = url(group_name(Config), "/http_1_1_send_oct.html", Config),
+ Url1 = url(group_name(Config), "/http_1_1_send_oct_and_connection_close.html", Config),
+ %% Test case assumes no reusable past sessions.
+ SendOct0 = 0 = ReqSrvSendOctFun(V, Url0, 204),
+ case ReqSrvSendOctFun(V, Url1, 204) of SendOct1 when SendOct1 > SendOct0 -> ok end,
+ 0 = ReqSrvSendOctFun(V, Url0, 204),
+ ok.
+
+%%--------------------------------------------------------------------
slow_connection() ->
[{doc, "Test that a request on a slow keep-alive connection won't crash the httpc_manager"}].
slow_connection(Config) when is_list(Config) ->
@@ -1264,6 +1582,36 @@ unix_domain_socket(Config) when is_list(Config) ->
{ok, {{_,200,_}, [_ | _], _}}
= httpc:request(get, {URL, []}, [], []).
+%%-------------------------------------------------------------------------
+delete_no_body(doc) ->
+ ["Test that a DELETE request without Body does not send a Content-Type header - Solves ERL-536"];
+delete_no_body(Config) when is_list(Config) ->
+ URL = url(group_name(Config), "/delete_no_body.html", Config),
+ %% Simulated server replies 500 if 'Content-Type' header is present
+ {ok, {{_,200,_}, _, _}} =
+ httpc:request(delete, {URL, []}, [], []),
+ {ok, {{_,500,_}, _, _}} =
+ httpc:request(delete, {URL, [], "text/plain", "TEST"}, [], []).
+
+%%--------------------------------------------------------------------
+post_with_content_type(doc) ->
+ ["Test that a POST request with explicit 'Content-Type' does not drop the 'Content-Type' header - Solves ERL-736"];
+post_with_content_type(Config) when is_list(Config) ->
+ URL = url(group_name(Config), "/delete_no_body.html", Config),
+ %% Simulated server replies 500 if 'Content-Type' header is present
+ {ok, {{_,500,_}, _, _}} =
+ httpc:request(post, {URL, [], "application/x-www-form-urlencoded", ""}, [], []).
+
+%%--------------------------------------------------------------------
+request_options() ->
+ [{require, ipv6_hosts},
+ {doc, "Test http get request with socket options against local server (IPv6)"}].
+request_options(Config) when is_list(Config) ->
+ Request = {url(group_name(Config), "/dummy.html", Config), []},
+ {ok, {{_,200,_}, [_ | _], _ = [_ | _]}} = httpc:request(get, Request, [],
+ [{socket_opts,[{ipfamily, inet6}]}]),
+ {error,{failed_connect,_ }} = httpc:request(get, Request, [], []).
+
%%--------------------------------------------------------------------
@@ -1353,6 +1701,9 @@ url(http, End, Config) ->
Port = proplists:get_value(port, Config),
{ok,Host} = inet:gethostname(),
?URL_START ++ Host ++ ":" ++ integer_to_list(Port) ++ End;
+url(http_ipv6, End, Config) ->
+ Port = proplists:get_value(port, Config),
+ ?URL_START ++ "[::1]" ++ ":" ++ integer_to_list(Port) ++ End;
url(https, End, Config) ->
Port = proplists:get_value(port, Config),
{ok,Host} = inet:gethostname(),
@@ -1374,6 +1725,21 @@ url(sim_http, UserInfo, End, Config) ->
url(sim_https, UserInfo, End, Config) ->
url(https, UserInfo, End, Config).
+% Only for use in the `mixed` test group, where both http and https
+% URLs are possible.
+mixed_url(http, End, Config) ->
+ mixed_url(http_port, End, Config);
+mixed_url(https, End, Config) ->
+ mixed_url(https_port, End, Config);
+mixed_url(PortType, End, Config) ->
+ Port = proplists:get_value(PortType, Config),
+ {ok, Host} = inet:gethostname(),
+ Start = case PortType of
+ http_port -> ?URL_START;
+ https_port -> ?TLS_URL_START
+ end,
+ Start ++ Host ++ ":" ++ integer_to_list(Port) ++ End.
+
group_name(Config) ->
GroupProp = proplists:get_value(tc_group_properties, Config),
proplists:get_value(name, GroupProp).
@@ -1397,7 +1763,14 @@ server_start(http_unix_socket, Config) ->
{_Pid, Port} = http_test_lib:dummy_server(unix_socket, Inet, [{content_cb, ?MODULE},
{unix_socket, Socket}]),
Port;
-
+server_start(http_ipv6, HttpdConfig) ->
+ {ok, Pid} = inets:start(httpd, HttpdConfig),
+ Serv = inets:services_info(),
+ {value, {_, _, Info}} = lists:keysearch(Pid, 2, Serv),
+ proplists:get_value(port, Info);
+server_start(sim_mixed, Config) ->
+ % For the mixed http/https case, we start two servers and return both ports.
+ {server_start(sim_http, []), server_start(sim_https, Config)};
server_start(_, HttpdConfig) ->
{ok, Pid} = inets:start(httpd, HttpdConfig),
Serv = inets:services_info(),
@@ -1416,6 +1789,17 @@ server_config(http, Config) ->
{mime_type, "text/plain"},
{script_alias, {"/cgi-bin/", filename:join(ServerRoot, "cgi-bin") ++ "/"}}
];
+server_config(http_ipv6, Config) ->
+ ServerRoot = proplists:get_value(server_root, Config),
+ [{port, 0},
+ {server_name,"httpc_test"},
+ {server_root, ServerRoot},
+ {document_root, proplists:get_value(doc_root, Config)},
+ {bind_address, {0,0,0,0,0,0,0,1}},
+ {ipfamily, inet6},
+ {mime_type, "text/plain"},
+ {script_alias, {"/cgi-bin/", filename:join(ServerRoot, "cgi-bin") ++ "/"}}
+ ];
server_config(http_internal, Config) ->
ServerRoot = proplists:get_value(server_root, Config),
[{port, 0},
@@ -1445,14 +1829,14 @@ start_apps(https) ->
inets_test_lib:start_apps([crypto, public_key, ssl]);
start_apps(sim_https) ->
inets_test_lib:start_apps([crypto, public_key, ssl]);
+start_apps(sim_mixed) ->
+ inets_test_lib:start_apps([crypto, public_key, ssl]);
start_apps(_) ->
ok.
ssl_config(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- [{certfile, filename:join(DataDir, "ssl_server_cert.pem")},
- {verify, verify_none}
- ].
+ SSLConf = proplists:get_value(ssl_conf, Config),
+ proplists:get_value(server_config, SSLConf).
setup_server_dirs(ServerRoot, DocRoot, DataDir) ->
CgiDir = filename:join(ServerRoot, "cgi-bin"),
@@ -1770,6 +2154,13 @@ auth_header([{"authorization", Value} | _]) ->
auth_header([_ | Tail]) ->
auth_header(Tail).
+content_type_header([]) ->
+ not_found;
+content_type_header([{"content-type", Value}|_]) ->
+ {ok, string:strip(Value)};
+content_type_header([_|T]) ->
+ content_type_header(T).
+
handle_auth("Basic " ++ UserInfo, Challange, DefaultResponse) ->
case string:tokens(base64:decode_to_string(UserInfo), ":") of
["alladin", "sesame"] = Auth ->
@@ -1794,6 +2185,15 @@ content_length(["content-length:" ++ Value | _]) ->
content_length([_Head | Tail]) ->
content_length(Tail).
+handle_uri("GET","/dummy.html?foo=bar",_,_,_,_) ->
+ "HTTP/1.0 200 OK\r\n\r\nTEST";
+
+handle_uri("GET","/space%20.html",_,_,_,_) ->
+ Body = "<HTML><BODY>foobar</BODY></HTML>",
+ "HTTP/1.1 200 OK\r\n" ++
+ "Content-Length:" ++ integer_to_list(length(Body)) ++ "\r\n\r\n" ++
+ Body;
+
handle_uri(_,"/just_close.html",_,_,_,_) ->
close;
handle_uri(_,"/no_content.html",_,_,_,_) ->
@@ -1859,6 +2259,37 @@ handle_uri(_,"/301.html",Port,_,Socket,_) ->
"Content-Length:" ++ integer_to_list(length(Body))
++ "\r\n\r\n" ++ Body;
+
+handle_uri("HEAD","/301_rel_uri.html",_,_,_,_) ->
+ NewUri = "/dummy.html",
+ "HTTP/1.1 301 Moved Permanently\r\n" ++
+ "Location:" ++ NewUri ++ "\r\n" ++
+ "Content-Length:0\r\n\r\n";
+
+handle_uri(_,"/301_rel_uri.html",_,_,_,_) ->
+ NewUri = "/dummy.html",
+ Body = "<HTML><BODY><a href=" ++ NewUri ++
+ ">New place</a></BODY></HTML>",
+ "HTTP/1.1 301 Moved Permanently\r\n" ++
+ "Location:" ++ NewUri ++ "\r\n" ++
+ "Content-Length:" ++ integer_to_list(length(Body))
+ ++ "\r\n\r\n" ++ Body;
+
+handle_uri("HEAD","/301_custom_url.html",_,Headers,_,_) ->
+ NewUri = proplists:get_value("x-test-301-url", Headers),
+ "HTTP/1.1 301 Moved Permanently\r\n" ++
+ "Location:" ++ NewUri ++ "\r\n" ++
+ "Content-Length:0\r\n\r\n";
+
+handle_uri(_,"/301_custom_url.html",_,Headers,_,_) ->
+ NewUri = proplists:get_value("x-test-301-url", Headers),
+ Body = "<HTML><BODY><a href=" ++ NewUri ++
+ ">New place</a></BODY></HTML>",
+ "HTTP/1.1 301 Moved Permanently\r\n" ++
+ "Location:" ++ NewUri ++ "\r\n" ++
+ "Content-Length:" ++ integer_to_list(length(Body))
+ ++ "\r\n\r\n" ++ Body;
+
handle_uri("HEAD","/302.html",Port,_,Socket,_) ->
NewUri = url_start(Socket) ++
integer_to_list(Port) ++ "/dummy.html",
@@ -2165,10 +2596,40 @@ handle_uri("GET","/v1/kv/foo",_,_,_,_) ->
"Content-Length: 24\r\n" ++
"Content-Type: application/json\r\n\r\n" ++
"[{\"Value\": \"aGVsbG8=\"}]\n";
-
+handle_uri(_,"/http_1_1_send_oct.html",_,_,Socket,_) ->
+ "HTTP/1.1 204 No Content\r\n" ++
+ "X-Socket-Stat-Send-Oct: " ++ integer_to_list(get_stat(Socket, send_oct)) ++ "\r\n" ++
+ "\r\n";
+handle_uri(_,"/http_1_1_send_oct_and_connection_close.html",_,_,Socket,_) ->
+ "HTTP/1.1 204 No Content\r\n" ++
+ "X-Socket-Stat-Send-Oct: " ++ integer_to_list(get_stat(Socket, send_oct)) ++ "\r\n" ++
+ "Connection: close\r\n" ++
+ "\r\n";
+handle_uri(_,"/delete_no_body.html", _,Headers,_, DefaultResponse) ->
+ Error = "HTTP/1.1 500 Internal Server Error\r\n" ++
+ "Content-Length:0\r\n\r\n",
+ case content_type_header(Headers) of
+ {ok, _} ->
+ Error;
+ not_found ->
+ DefaultResponse
+ end;
handle_uri(_,_,_,_,_,DefaultResponse) ->
DefaultResponse.
+get_stat(S, Opt) ->
+ case getstat(S, [Opt]) of
+ {ok, [{Opt, V}]} when is_integer(V) ->
+ V;
+ {error, _} = E ->
+ E
+ end.
+
+getstat(#sslsocket{} = S, Opts) ->
+ ssl:getstat(S, Opts);
+getstat(S, Opts) ->
+ inet:getstat(S, Opts).
+
url_start(#sslsocket{}) ->
{ok,Host} = inet:gethostname(),
?TLS_URL_START ++ Host ++ ":";
@@ -2477,3 +2938,12 @@ receive_stream_n(Ref, N) ->
ct:pal("Data: ~p", [Data]),
receive_stream_n(Ref, N-1)
end.
+
+is_ipv6_supported() ->
+ {ok, Hostname0} = inet:gethostname(),
+ try
+ lists:member(list_to_atom(Hostname0), ct:get_config(ipv6_hosts))
+ catch
+ _: _ ->
+ false
+ end.
diff --git a/lib/inets/test/httpc_proxy_SUITE.erl b/lib/inets/test/httpc_proxy_SUITE.erl
index 198b245399..3ee7981660 100644
--- a/lib/inets/test/httpc_proxy_SUITE.erl
+++ b/lib/inets/test/httpc_proxy_SUITE.erl
@@ -534,7 +534,7 @@ init_local_proxy(Config) ->
ct:fail({local_proxy_start_failed,Error})
end;
_ ->
- {skip,"Platform can not run local proxy start script"}
+ {skip,"Platform cannot run local proxy start script"}
end.
init_local_proxy_string(String, Config) ->
diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl
index 9a85c51d24..fc5ca14dcd 100644
--- a/lib/inets/test/httpd_SUITE.erl
+++ b/lib/inets/test/httpd_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -75,7 +75,14 @@ all() ->
{group, http_mime_types},
{group, http_logging},
{group, http_post},
- mime_types_format
+ {group, http_rel_path_script_alias},
+ {group, http_not_sup},
+ {group, https_not_sup},
+ mime_types_format,
+ erl_script_timeout_default,
+ erl_script_timeout_option,
+ erl_script_timeout_proplist,
+ erl_script_timeout_apache
].
groups() ->
@@ -102,6 +109,8 @@ groups() ->
{http_reload, [], [{group, reload}]},
{https_reload, [], [{group, reload}]},
{http_post, [], [{group, post}]},
+ {http_not_sup, [], [{group, not_sup}]},
+ {https_not_sup, [], [{group, not_sup}]},
{http_mime_types, [], [alias_1_1, alias_1_0, alias_0_9]},
{limit, [], [max_clients_1_1, max_clients_1_0, max_clients_0_9]},
{custom, [], [customize, add_default]},
@@ -112,9 +121,10 @@ groups() ->
non_disturbing_0_9,
disturbing_1_1,
disturbing_1_0,
- disturbing_0_9
+ disturbing_0_9,
+ reload_config_file
]},
- {post, [], [chunked_post, chunked_chunked_encoded_post]},
+ {post, [], [chunked_post, chunked_chunked_encoded_post, post_204]},
{basic_auth, [], [basic_auth_1_1, basic_auth_1_0, basic_auth_0_9]},
{auth_api, [], [auth_api_1_1, auth_api_1_0, auth_api_0_9
]},
@@ -131,7 +141,9 @@ groups() ->
trace, range, if_modified_since, mod_esi_chunk_timeout,
esi_put, esi_post] ++ http_head() ++ http_get() ++ load()},
{http_1_0, [], [host, cgi, trace] ++ http_head() ++ http_get() ++ load()},
- {http_0_9, [], http_head() ++ http_get() ++ load()}
+ {http_0_9, [], http_head() ++ http_get() ++ load()},
+ {http_rel_path_script_alias, [], [cgi]},
+ {not_sup, [], [put_not_sup]}
].
basic_groups ()->
@@ -168,6 +180,7 @@ init_per_suite(Config) ->
ServerRoot = filename:join(PrivDir, "server_root"),
inets_test_lib:del_dirs(ServerRoot),
DocRoot = filename:join(ServerRoot, "htdocs"),
+ setup_tmp_dir(PrivDir),
setup_server_dirs(ServerRoot, DocRoot, DataDir),
{ok, Hostname0} = inet:gethostname(),
Inet =
@@ -203,7 +216,8 @@ init_per_group(Group, Config0) when Group == https_basic;
Group == https_auth_api_dets;
Group == https_auth_api_mnesia;
Group == https_security;
- Group == https_reload
+ Group == https_reload;
+ Group == https_not_sup
->
catch crypto:stop(),
try crypto:start() of
@@ -222,6 +236,7 @@ init_per_group(Group, Config0) when Group == http_basic;
Group == http_auth_api_mnesia;
Group == http_security;
Group == http_reload;
+ Group == http_not_sup;
Group == http_post;
Group == http_mime_types
->
@@ -268,6 +283,11 @@ init_per_group(http_logging, Config) ->
ServerRoot = proplists:get_value(server_root, Config1),
Path = ServerRoot ++ "/httpd_log_transfer",
[{transfer_log, Path} | Config1];
+init_per_group(http_rel_path_script_alias = Group, Config) ->
+ ok = start_apps(Group),
+ init_httpd(Group, [{type, ip_comm},{http_version, "HTTP/1.1"}| Config]);
+init_per_group(not_sup, Config) ->
+ [{http_version, "HTTP/1.1"} | Config];
init_per_group(_, Config) ->
Config.
@@ -367,6 +387,10 @@ init_per_testcase(disk_log_bad_file, Config0) ->
ct:timetrap({seconds, 20}),
dbg(disk_log_internal, Config1, init);
+init_per_testcase(erl_script_timeout_default, Config) ->
+ ct:timetrap({seconds, 60}),
+ dbg(erl_script_timeout_default, Config, init);
+
init_per_testcase(Case, Config) ->
ct:timetrap({seconds, 20}),
dbg(Case, Config, init).
@@ -441,8 +465,19 @@ get(Config) when is_list(Config) ->
{header, "Content-Type", "text/html"},
{header, "Date"},
{header, "Server"},
+ {version, Version}]),
+
+ ok = httpd_test_lib:verify_request(proplists:get_value(type, Config), Host,
+ proplists:get_value(port, Config),
+ transport_opts(Type, Config),
+ proplists:get_value(node, Config),
+ http_request("GET /open/ ", Version, Host),
+ [{statuscode, 403},
+ {header, "Content-Type", "text/html"},
+ {header, "Date"},
+ {header, "Server"},
{version, Version}]).
-
+
basic_auth_1_1(Config) when is_list(Config) ->
basic_auth([{http_version, "HTTP/1.1"} | Config]).
@@ -726,6 +761,42 @@ chunked_chunked_encoded_post(Config) when is_list(Config) ->
[{http_version, "HTTP/1.1"} | Config],
[{statuscode, 200}]).
+%%-------------------------------------------------------------------------
+post_204() ->
+ [{doc,"Test that 204 responses are not chunk encoded"}].
+post_204(Config) ->
+ Host = proplists:get_value(host, Config),
+ Port = proplists:get_value(port, Config),
+ SockType = proplists:get_value(type, Config),
+ TranspOpts = transport_opts(SockType, Config),
+ Request = "POST /cgi-bin/erl/httpd_example:post_204 ",
+
+ try inets_test_lib:connect_bin(SockType, Host, Port, TranspOpts) of
+ {ok, Socket} ->
+ RequestStr = http_request(Request, "HTTP/1.1", Host),
+ ok = inets_test_lib:send(SockType, Socket, RequestStr),
+ receive
+ {tcp, Socket, Data} ->
+ case binary:match(Data, <<"chunked">>,[]) of
+ nomatch ->
+ ok;
+ {_, _} ->
+ ct:fail("Chunked encoding detected.")
+ end
+ after 2000 ->
+ ct:fail(connection_timed_out)
+ end;
+ ConnectError ->
+ ct:fail({connect_error, ConnectError,
+ [SockType, Host, Port, TranspOpts]})
+ catch
+ T:E ->
+ ct:fail({connect_failure,
+ [{type, T},
+ {error, E},
+ {stacktrace, erlang:get_stacktrace()},
+ {args, [SockType, Host, Port, TranspOpts]}]})
+ end.
%%-------------------------------------------------------------------------
htaccess_1_1(Config) when is_list(Config) ->
@@ -891,6 +962,33 @@ max_clients_0_9() ->
max_clients_0_9(Config) when is_list(Config) ->
do_max_clients([{http_version, "HTTP/0.9"} | Config]).
+
+
+%%-------------------------------------------------------------------------
+put_not_sup() ->
+ [{doc, "Test unhandled request"}].
+
+put_not_sup(Config) when is_list(Config) ->
+ ok = http_status("PUT /index.html ",
+ {"Content-Length:100 \r\n",
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"},
+ Config, [{statuscode, 501}]).
%%-------------------------------------------------------------------------
esi() ->
[{doc, "Test mod_esi"}].
@@ -1536,6 +1634,45 @@ non_disturbing(Config) when is_list(Config)->
end,
inets_test_lib:close(Type, Socket),
[{server_name, "httpd_non_disturbing_" ++ Version}] = httpd:info(Server, [server_name]).
+%%-------------------------------------------------------------------------
+reload_config_file(Config) when is_list(Config) ->
+ ServerRoot = proplists:get_value(server_root, Config),
+ HttpdConf = filename:join(get_tmp_dir(Config), "inets_httpd_server.conf"),
+ ServerConfig =
+ "[\n" ++
+ "{bind_address, \"localhost\"}," ++
+ "{port,0}," ++
+ "{server_name,\"httpd_test\"}," ++
+ "{server_root,\"" ++ ServerRoot ++ "\"}," ++
+ "{document_root,\"" ++ proplists:get_value(doc_root, Config) ++ "\"}" ++
+ "].",
+ ok = file:write_file(HttpdConf, ServerConfig),
+ {ok, Server} = inets:start(httpd, [{proplist_file, HttpdConf}]),
+ Port = proplists:get_value(port, httpd:info(Server)),
+ NewConfig =
+ "[\n" ++
+ "{bind_address, \"localhost\"}," ++
+ "{port," ++ integer_to_list(Port) ++ "}," ++
+ "{server_name,\"httpd_test_new\"}," ++
+ "{server_root,\"" ++ ServerRoot ++ "\"}," ++
+ "{document_root,\"" ++ proplists:get_value(doc_root, Config) ++ "\"}" ++
+ "].",
+ NewConfigApache =
+ "BindAddress localhost\n" ++
+ "Port " ++ integer_to_list(Port) ++ "\n" ++
+ "ServerName httpd_test_new_apache\n" ++
+ "ServerRoot " ++ ServerRoot ++ "\n" ++
+ "DocumentRoot " ++ proplists:get_value(doc_root, Config) ++ "\n",
+
+ %% Test Erlang term format
+ ok = file:write_file(HttpdConf, NewConfig),
+ ok = httpd:reload_config(HttpdConf, non_disturbing),
+ "httpd_test_new" = proplists:get_value(server_name, httpd:info(Server)),
+
+ %% Test Apache format
+ ok = file:write_file(HttpdConf, NewConfigApache),
+ ok = httpd:reload_config(HttpdConf, non_disturbing),
+ "httpd_test_new_apache" = proplists:get_value(server_name, httpd:info(Server)).
%%-------------------------------------------------------------------------
mime_types_format(Config) when is_list(Config) ->
@@ -1647,6 +1784,131 @@ mime_types_format(Config) when is_list(Config) ->
{"cpt","application/mac-compactpro"},
{"hqx","application/mac-binhex40"}]} = httpd_conf:load_mime_types(MimeTypes).
+erl_script_timeout_default(Config) when is_list(Config) ->
+ inets:start(),
+ {ok, Pid} = inets:start(httpd,
+ [{port, 0},
+ {server_name,"localhost"},
+ {server_root,"./"},
+ {document_root,"./"},
+ {bind_address, any},
+ {mimetypes, [{"html", "text/html"}]},
+ {modules,[mod_esi]},
+ {erl_script_alias, {"/erl", [httpd_example]}}
+ ]),
+ Info = httpd:info(Pid),
+
+ Port = proplists:get_value(port, Info),
+
+ %% Default erl_script_timeout is 15.
+ %% Verify: 13 =< erl_script_timeout =< 17
+ Url = http_get_url(Port, 500, 13000, 4000),
+
+ {ok, {_, _, Body}} = httpc:request(get, {Url, []}, [{timeout, 45000}], []),
+ ct:log("Response: ~p~n", [Body]),
+ verify_body(Body, 13000),
+ inets:stop().
+
+erl_script_timeout_option(Config) when is_list(Config) ->
+ inets:start(),
+ {ok, Pid} = inets:start(httpd,
+ [{port, 0},
+ {server_name,"localhost"},
+ {server_root,"./"},
+ {document_root,"./"},
+ {bind_address, any},
+ {mimetypes, [{"html", "text/html"}]},
+ {modules,[mod_esi]},
+ {erl_script_timeout, 2},
+ {erl_script_alias, {"/erl", [httpd_example]}}
+ ]),
+ Info = httpd:info(Pid),
+ verify_timeout(Info, 2),
+
+ Port = proplists:get_value(port, Info),
+
+ %% Verify: 1 =< erl_script_timeout =< 3
+ Url = http_get_url(Port, 500, 1000, 2000),
+
+ {ok, {_, _, Body}} = httpc:request(Url),
+ ct:log("Response: ~p~n", [Body]),
+ verify_body(Body, 1000),
+ inets:stop().
+
+erl_script_timeout_proplist(Config) when is_list(Config) ->
+ HttpdConf = filename:join(get_tmp_dir(Config),
+ "httpd_erl_script_timeout_proplist.conf"),
+ ServerConfig =
+ "[{port, 0},\n" ++
+ " {server_name,\"localhost\"},\n" ++
+ " {server_root,\"./\"},\n" ++
+ " {document_root,\"./\"},\n" ++
+ " {bind_address, any},\n" ++
+ " {mimetypes, [{\"html\", \"text/html\"}]},\n" ++
+ " {modules,[mod_esi]},\n" ++
+ " {erl_script_timeout, 5},\n" ++
+ " {erl_script_alias, {\"/erl\", [httpd_example]}}\n" ++
+ "].",
+ ok = file:write_file(HttpdConf, ServerConfig),
+
+ inets:start(),
+ {ok, Pid} = inets:start(httpd,
+ [{proplist_file, HttpdConf}]),
+ Info = httpd:info(Pid),
+ verify_timeout(Info, 5),
+
+ Port = proplists:get_value(port, Info),
+
+ %% Verify: 3 =< erl_script_timeout =< 7
+ Url = http_get_url(Port, 500, 3000, 4000),
+
+ {ok, {_, _, Body}} = httpc:request(Url),
+ ct:log("Response: ~p~n", [Body]),
+ verify_body(Body, 3000),
+ inets:stop().
+
+erl_script_timeout_apache(Config) when is_list(Config) ->
+ HttpdConf = filename:join(get_tmp_dir(Config),
+ "httpd_erl_script_timeout.conf"),
+ MimeTypes = filename:join(get_tmp_dir(Config),
+ "erl_script_timeout_mime_types.conf"),
+
+ MimeTypesConf =
+ "html\n" ++
+ "text/html\n",
+
+ ok = file:write_file(MimeTypes, MimeTypesConf),
+
+ ServerConfig =
+ "Port 0\n" ++
+ "ServerName localhost\n" ++
+ "ServerRoot ./\n" ++
+ "DocumentRoot ./\n" ++
+ "BindAddress 0.0.0.0\n" ++
+ "MimeTypes " ++ MimeTypes ++ "\n" ++
+ "Modules mod_esi\n" ++
+ "ErlScriptTimeout 8\n" ++
+ "ErlScriptAlias /erl httpd_example\n",
+
+ ok = file:write_file(HttpdConf, ServerConfig),
+
+ inets:start(),
+ {ok, Pid} = inets:start(httpd,
+ [{file, HttpdConf}]),
+ Info = httpd:info(Pid),
+ verify_timeout(Info, 8),
+
+ Port = proplists:get_value(port, Info),
+
+ %% Verify: 6 =< erl_script_timeout =< 10
+ Url = http_get_url(Port, 500, 6000, 4000),
+
+ {ok, {_, _, Body}} = httpc:request(Url),
+ ct:log("Response: ~p~n", [Body]),
+ verify_body(Body, 6000),
+ inets:stop().
+
+
%%--------------------------------------------------------------------
%% Internal functions -----------------------------------
%%--------------------------------------------------------------------
@@ -1655,6 +1917,38 @@ url(http, End, Config) ->
{ok,Host} = inet:gethostname(),
?URL_START ++ Host ++ ":" ++ integer_to_list(Port) ++ End.
+http_get_url(Port0, HeaderDelay, ChunkDelay, BadChunkDelay) ->
+ {ok, Host} = inet:gethostname(),
+ Port = integer_to_list(Port0),
+ HD = integer_to_list(HeaderDelay),
+ CD = integer_to_list(ChunkDelay),
+ BD = integer_to_list(BadChunkDelay),
+ "http://" ++ Host ++ ":" ++ Port ++
+ "/erl/httpd_example/get_chunks?header_delay=" ++ HD ++
+ "&chunk_delay=" ++ CD ++
+ "&bad_chunk_delay=" ++ BD.
+
+verify_body(Body, Timeout0) ->
+ Timeout = integer_to_list(Timeout0),
+ Res = string:find(Body, Timeout),
+ ct:log("Result: ~p~n", [Res]),
+ %% Fail if BAD chunk is found.
+ case Res =:= Timeout ++ " ms\r\n" of
+ true ->
+ ok;
+ false ->
+ ct:fail("Unexpected chunk received!")
+ end.
+
+verify_timeout(Info, Expected) ->
+ Timeout = proplists:get_value(erl_script_timeout, Info),
+ case Timeout =:= Expected of
+ true ->
+ ok;
+ false ->
+ ct:fail("Bad Timeout - Expected: ~p Got: ~p", [Expected, Timeout])
+ end.
+
do_max_clients(Config) ->
Version = proplists:get_value(http_version, Config),
Host = proplists:get_value(host, Config),
@@ -1728,7 +2022,15 @@ setup_server_dirs(ServerRoot, DocRoot, DataDir) ->
{ok, FileInfo1} = file:read_file_info(EnvCGI),
ok = file:write_file_info(EnvCGI,
FileInfo1#file_info{mode = 8#00755}).
-
+
+setup_tmp_dir(PrivDir) ->
+ TmpDir = filename:join(PrivDir, "tmp"),
+ ok = file:make_dir(TmpDir).
+
+get_tmp_dir(Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ filename:join(PrivDir, "tmp").
+
start_apps(Group) when Group == https_basic;
Group == https_limit;
Group == https_custom;
@@ -1738,7 +2040,8 @@ start_apps(Group) when Group == https_basic;
Group == https_auth_api_mnesia;
Group == https_htaccess;
Group == https_security;
- Group == https_reload
+ Group == https_reload;
+ Group == https_not_sup
->
inets_test_lib:start_apps([inets, asn1, crypto, public_key, ssl]);
start_apps(Group) when Group == http_basic;
@@ -1753,6 +2056,9 @@ start_apps(Group) when Group == http_basic;
Group == http_logging;
Group == http_reload;
Group == http_post;
+ Group == http_mime_types;
+ Group == http_rel_path_script_alias;
+ Group == http_not_sup;
Group == http_mime_types->
inets_test_lib:start_apps([inets]).
@@ -1763,32 +2069,23 @@ server_start(_, HttpdConfig) ->
{Pid, proplists:get_value(port, Info)}.
init_ssl(Group, Config) ->
- PrivDir = proplists:get_value(priv_dir, Config),
- CaKey = {_Trusted,_} =
- erl_make_certs:make_cert([{key, dsa},
- {subject,
- [{name, "Public Key"},
- {?'id-at-name',
- {printableString, "public_key"}},
- {?'id-at-pseudonym',
- {printableString, "pubkey"}},
- {city, "Stockholm"},
- {country, "SE"},
- {org, "erlang"},
- {org_unit, "testing dep"}
- ]}
- ]),
- ok = erl_make_certs:write_pem(PrivDir, "public_key_cacert", CaKey),
-
- CertK1 = {_Cert1, _} = erl_make_certs:make_cert([{issuer, CaKey}]),
- CertK2 = {_Cert2,_} = erl_make_certs:make_cert([{issuer, CertK1},
- {digest, md5},
- {extensions, false}]),
- ok = erl_make_certs:write_pem(PrivDir, "public_key_cert", CertK2),
-
+ ClientFileBase = filename:join([proplists:get_value(priv_dir, Config), "client"]),
+ ServerFileBase = filename:join([proplists:get_value(priv_dir, Config), "server"]),
+ GenCertData =
+ public_key:pkix_test_data(#{server_chain =>
+ #{root => [{key, inets_test_lib:hardcode_rsa_key(1)}],
+ intermediates => [[{key, inets_test_lib:hardcode_rsa_key(2)}]],
+ peer => [{key, inets_test_lib:hardcode_rsa_key(3)}
+ ]},
+ client_chain =>
+ #{root => [{key, inets_test_lib:hardcode_rsa_key(4)}],
+ intermediates => [[{key, inets_test_lib:hardcode_rsa_key(5)}]],
+ peer => [{key, inets_test_lib:hardcode_rsa_key(6)}]}}),
+
+ Conf = inets_test_lib:gen_pem_config_files(GenCertData, ClientFileBase, ServerFileBase),
case start_apps(Group) of
ok ->
- init_httpd(Group, [{type, ssl} | Config]);
+ init_httpd(Group, [{type, ssl}, {ssl_conf, Conf} | Config]);
_ ->
{skip, "Could not start https apps"}
end.
@@ -1797,6 +2094,10 @@ server_config(http_basic, Config) ->
basic_conf() ++ server_config(http, Config);
server_config(https_basic, Config) ->
basic_conf() ++ server_config(https, Config);
+server_config(http_not_sup, Config) ->
+ not_sup_conf() ++ server_config(http, Config);
+server_config(https_not_sup, Config) ->
+ not_sup_conf() ++ server_config(https, Config);
server_config(http_reload, Config) ->
[{keep_alive_timeout, 2}] ++ server_config(http, Config);
server_config(http_post, Config) ->
@@ -1878,18 +2179,33 @@ server_config(http, Config) ->
{erl_script_alias, {"/cgi-bin/erl", [httpd_example, io]}},
{eval_script_alias, {"/eval", [httpd_example, io]}}
];
-
+server_config(http_rel_path_script_alias, Config) ->
+ ServerRoot = proplists:get_value(server_root, Config),
+ [{port, 0},
+ {socket_type, {ip_comm, [{nodelay, true}]}},
+ {server_name,"httpd_test"},
+ {server_root, ServerRoot},
+ {document_root, proplists:get_value(doc_root, Config)},
+ {bind_address, any},
+ {ipfamily, proplists:get_value(ipfamily, Config)},
+ {max_header_size, 256},
+ {max_header_action, close},
+ {directory_index, ["index.html", "welcome.html"]},
+ {mime_types, [{"html","text/html"},{"htm","text/html"}, {"shtml","text/html"},
+ {"gif", "image/gif"}]},
+ {alias, {"/icons/", filename:join(ServerRoot,"icons") ++ "/"}},
+ {alias, {"/pics/", filename:join(ServerRoot,"icons") ++ "/"}},
+ {script_alias, {"/cgi-bin/", "./cgi-bin/"}},
+ {script_alias, {"/htbin/", "./cgi-bin/"}},
+ {erl_script_alias, {"/cgi-bin/erl", [httpd_example, io]}},
+ {eval_script_alias, {"/eval", [httpd_example, io]}}
+ ];
server_config(https, Config) ->
- PrivDir = proplists:get_value(priv_dir, Config),
+ SSLConf = proplists:get_value(ssl_conf, Config),
+ ServerConf = proplists:get_value(server_config, SSLConf),
[{socket_type, {essl,
- [{nodelay, true},
- {cacertfile,
- filename:join(PrivDir, "public_key_cacert.pem")},
- {certfile,
- filename:join(PrivDir, "public_key_cert.pem")},
- {keyfile,
- filename:join(PrivDir, "public_key_cert_key.pem")}
- ]}}] ++ proplists:delete(socket_type, server_config(http, Config)).
+ [{nodelay, true} | ServerConf]}}]
+ ++ proplists:delete(socket_type, server_config(http, Config)).
init_httpd(Group, Config0) ->
Config1 = proplists:delete(port, Config0),
@@ -1930,7 +2246,10 @@ head_status(_) ->
basic_conf() ->
[{modules, [mod_alias, mod_range, mod_responsecontrol,
- mod_trace, mod_esi, mod_cgi, mod_dir, mod_get, mod_head]}].
+ mod_trace, mod_esi, mod_cgi, mod_get, mod_head]}].
+
+not_sup_conf() ->
+ [{modules, [mod_get]}].
auth_access_conf() ->
[{modules, [mod_alias, mod_htaccess, mod_dir, mod_get, mod_head]},
@@ -2144,9 +2463,9 @@ cleanup_mnesia() ->
ok.
transport_opts(ssl, Config) ->
- PrivDir = proplists:get_value(priv_dir, Config),
- [proplists:get_value(ipfamily, Config),
- {cacertfile, filename:join(PrivDir, "public_key_cacert.pem")}];
+ SSLConf = proplists:get_value(ssl_conf, Config),
+ ClientConf = proplists:get_value(client_config, SSLConf),
+ [proplists:get_value(ipfamily, Config) | ClientConf];
transport_opts(_, Config) ->
[proplists:get_value(ipfamily, Config)].
diff --git a/lib/inets/test/httpd_basic_SUITE.erl b/lib/inets/test/httpd_basic_SUITE.erl
index 931cd076cc..94d22ea76c 100644
--- a/lib/inets/test/httpd_basic_SUITE.erl
+++ b/lib/inets/test/httpd_basic_SUITE.erl
@@ -303,7 +303,10 @@ escaped_url_in_error_body(Config) when is_list(Config) ->
%% Ask for a non-existing page(1)
Path = "/<b>this_is_bold<b>",
HTMLEncodedPath = http_util:html_encode(Path),
- URL2 = URL1 ++ Path,
+ URL2 = uri_string:recompose(#{scheme => "http",
+ host => "localhost",
+ port => Port,
+ path => Path}),
{ok, {404, Body3}} = httpc:request(get, {URL2, []},
[{url_encode, true},
{version, "HTTP/1.0"}],
diff --git a/lib/inets/test/httpd_bench_SUITE.erl b/lib/inets/test/httpd_bench_SUITE.erl
index 9d8cbf9ae2..087516f56c 100644
--- a/lib/inets/test/httpd_bench_SUITE.erl
+++ b/lib/inets/test/httpd_bench_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -37,7 +37,8 @@
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
suite() ->
- [{ct_hooks,[{ts_install_cth,[{nodenames,2}]}]}].
+ [{timetrap, {minutes, 1}},
+ {ct_hooks,[{ts_install_cth,[{nodenames,2}]}]}].
all() ->
[
@@ -499,8 +500,8 @@ start_dummy("http"= Protocol, Config) ->
Conf = [
%%{big, filename:join(DataDir, "1M_file")},
%%{small, filename:join(DataDir, "1k_file")},
- {big, {gen, crypto:rand_bytes(1000000)}},
- {small, {gen, crypto:rand_bytes(1000)}},
+ {big, {gen, crypto:strong_rand_bytes(1000000)}},
+ {small, {gen, crypto:strong_rand_bytes(1000)}},
{http_version, HTTPVersion},
{keep_alive, ?config(keep_alive, Config)}
],
@@ -519,8 +520,8 @@ start_dummy("https" = Protocol, Config) ->
Opts = [{active, true}, {nodelay, true}, {reuseaddr, true} | SSLOpts],
Conf = [%%{big, filename:join(DataDir, "1M_file")},
%%{small, filename:join(DataDir, "1k_file")},
- {big, {gen, crypto:rand_bytes(1000000)}},
- {small, {gen, crypto:rand_bytes(1000)}},
+ {big, {gen, crypto:strong_rand_bytes(1000000)}},
+ {small, {gen, crypto:strong_rand_bytes(1000)}},
{http_version, HTTPVersion},
{keep_alive, ?config(keep_alive, Config)}
],
diff --git a/lib/inets/test/httpd_mod.erl b/lib/inets/test/httpd_mod.erl
index 2035b50248..6e3635001a 100644
--- a/lib/inets/test/httpd_mod.erl
+++ b/lib/inets/test/httpd_mod.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/test/inets_SUITE.erl b/lib/inets/test/inets_SUITE.erl
index 1abd96a228..e7964ff7f1 100644
--- a/lib/inets/test/inets_SUITE.erl
+++ b/lib/inets/test/inets_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -41,9 +41,7 @@ groups() ->
[{services_test, [],
[start_inets,
start_httpc,
- start_httpd,
- start_ftpc,
- start_tftpd
+ start_httpd
]},
{app_test, [], [app, appup]}].
@@ -298,79 +296,6 @@ start_httpd(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
-start_ftpc(doc) ->
- [{doc, "Start/stop of ftpc service"}];
-start_ftpc(Config0) when is_list(Config0) ->
- process_flag(trap_exit, true),
- ok = inets:start(),
- case ftp_SUITE:init_per_suite(Config0) of
- {skip, _} = Skip ->
- Skip;
- Config ->
- FtpdHost = proplists:get_value(ftpd_host,Config),
- {ok, Pid0} = inets:start(ftpc, [{host, FtpdHost}]),
- Pids0 = [ServicePid || {_, ServicePid} <-
- inets:services()],
- true = lists:member(Pid0, Pids0),
- [_|_] = inets:services_info(),
- inets:stop(ftpc, Pid0),
- ct:sleep(100),
- Pids1 = [ServicePid || {_, ServicePid} <-
- inets:services()],
- false = lists:member(Pid0, Pids1),
- {ok, Pid1} =
- inets:start(ftpc, [{host, FtpdHost}], stand_alone),
- Pids2 = [ServicePid || {_, ServicePid} <-
- inets:services()],
- false = lists:member(Pid1, Pids2),
- ok = inets:stop(stand_alone, Pid1),
- receive
- {'EXIT', Pid1, shutdown} ->
- ok
- after 100 ->
- ct:fail(stand_alone_not_shutdown)
- end,
- ok = inets:stop(),
- catch ftp_SUITE:end_per_SUITE(Config)
- end.
-
-%%-------------------------------------------------------------------------
-
-start_tftpd() ->
- [{doc, "Start/stop of tfpd service"}].
-start_tftpd(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ok = inets:start(),
- {ok, Pid0} = inets:start(tftpd, [{host, "localhost"}, {port, 0}]),
- Pids0 = [ServicePid || {_, ServicePid} <- inets:services()],
- true = lists:member(Pid0, Pids0),
- [_|_] = inets:services_info(),
- inets:stop(tftpd, Pid0),
- ct:sleep(100),
- Pids1 = [ServicePid || {_, ServicePid} <- inets:services()],
- false = lists:member(Pid0, Pids1),
- {ok, Pid1} =
- inets:start(tftpd, [{host, "localhost"}, {port, 0}], stand_alone),
- Pids2 = [ServicePid || {_, ServicePid} <- inets:services()],
- false = lists:member(Pid1, Pids2),
- ok = inets:stop(stand_alone, Pid1),
- receive
- {'EXIT', Pid1, shutdown} ->
- ok
- after 100 ->
- ct:fail(stand_alone_not_shutdown)
- end,
- ok = inets:stop(),
- application:load(inets),
- application:set_env(inets, services, [{tftpd,[{host, "localhost"},
- {port, 0}]}]),
- ok = inets:start(),
- (?NUM_DEFAULT_SERVICES + 1) = length(inets:services()),
- application:unset_env(inets, services),
- ok = inets:stop().
-
-%%-------------------------------------------------------------------------
-
httpd_reload() ->
[{doc, "Reload httpd configuration without restarting service"}].
httpd_reload(Config) when is_list(Config) ->
diff --git a/lib/inets/test/inets_socketwrap_SUITE.erl b/lib/inets/test/inets_socketwrap_SUITE.erl
index 7ea7e08ed1..b88cff4e90 100644
--- a/lib/inets/test/inets_socketwrap_SUITE.erl
+++ b/lib/inets/test/inets_socketwrap_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -30,7 +30,7 @@ suite() ->
[{ct_hooks,[ts_install_cth]}].
all() ->
- [start_httpd_fd, start_tftpd_fd].
+ [start_httpd_fd].
init_per_suite(Config) ->
case os:type() of
@@ -90,37 +90,7 @@ start_httpd_fd(Config) when is_list(Config) ->
ct:fail(open_port_failed)
end
end.
-%%-------------------------------------------------------------------------
-start_tftpd_fd() ->
- [{doc, "Start/stop of tfpd service with socket wrapper"}].
-start_tftpd_fd(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- case setup_node_info(node()) of
- {skip, _} = Skip ->
- Skip;
- {Node, NodeArg} ->
- InetPort = inets_test_lib:inet_port(node()),
- ct:pal("Node: ~p~n", [Node]),
- Wrapper = filename:join(DataDir, "setuid_socket_wrap"),
- Cmd = Wrapper ++
- " -s -tftpd_69,0:" ++ integer_to_list(InetPort)
- ++ " -p " ++ os:find_executable("erl") ++
- " -- " ++ NodeArg,
- ct:pal("cmd: ~p~n", [Cmd]),
- case open_port({spawn, Cmd}, [stderr_to_stdout]) of
- Port when is_port(Port) ->
- wait_node_up(Node, 10),
- ct:pal("~p", [rpc:call(Node, init, get_argument, [tftpd_69])]),
- ok = rpc:call(Node, inets, start, []),
- {ok, Pid} = rpc:call(Node, inets, start,
- [tftpd,[{host, "localhost"}]]),
- {ok, Info} = rpc:call(Node, tftp, info, [Pid]),
- {value,{port, InetPort}} = lists:keysearch(port, 1, Info),
- rpc:call(Node, erlang, halt, []);
- _ ->
- ct:fail(open_port_failed)
- end
- end.
+
%%-------------------------------------------------------------------------
%% Internal functions
%%-------------------------------------------------------------------------
diff --git a/lib/inets/test/inets_sup_SUITE.erl b/lib/inets/test/inets_sup_SUITE.erl
index 1e664337e6..b90d55dadf 100644
--- a/lib/inets/test/inets_sup_SUITE.erl
+++ b/lib/inets/test/inets_sup_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,8 +32,7 @@ suite() ->
].
all() ->
- [default_tree, ftpc_worker, tftpd_worker,
- httpd_config, httpd_subtree, httpd_subtree_profile,
+ [default_tree, httpd_config, httpd_subtree, httpd_subtree_profile,
httpc_subtree].
groups() ->
@@ -147,15 +146,11 @@ default_tree() ->
"in the default case."}].
default_tree(Config) when is_list(Config) ->
TopSupChildren = supervisor:which_children(inets_sup),
- 4 = length(TopSupChildren),
+ 2 = length(TopSupChildren),
{value, {httpd_sup, _, supervisor,[httpd_sup]}} =
lists:keysearch(httpd_sup, 1, TopSupChildren),
{value, {httpc_sup, _,supervisor,[httpc_sup]}} =
lists:keysearch(httpc_sup, 1, TopSupChildren),
- {value, {ftp_sup,_,supervisor,[ftp_sup]}} =
- lists:keysearch(ftp_sup, 1, TopSupChildren),
- {value, {tftp_sup,_,supervisor,[tftp_sup]}} =
- lists:keysearch(tftp_sup, 1, TopSupChildren),
HttpcSupChildren = supervisor:which_children(httpc_sup),
{value, {httpc_profile_sup,_, supervisor, [httpc_profile_sup]}} =
@@ -163,8 +158,6 @@ default_tree(Config) when is_list(Config) ->
{value, {httpc_handler_sup,_, supervisor, [httpc_handler_sup]}} =
lists:keysearch(httpc_handler_sup, 1, HttpcSupChildren),
- [] = supervisor:which_children(ftp_sup),
-
[] = supervisor:which_children(httpd_sup),
%% Default profile
@@ -172,48 +165,7 @@ default_tree(Config) when is_list(Config) ->
= supervisor:which_children(httpc_profile_sup),
[] = supervisor:which_children(httpc_handler_sup),
-
- [] = supervisor:which_children(tftp_sup),
-
- ok.
-ftpc_worker() ->
- [{doc, "Makes sure the ftp worker processes are added and removed "
- "appropriatly to/from the supervison tree."}].
-ftpc_worker(Config0) when is_list(Config0) ->
- [] = supervisor:which_children(ftp_sup),
- case ftp_SUITE:init_per_suite(Config0) of
- {skip, _} = Skip ->
- Skip;
- Config ->
- FtpdHost = proplists:get_value(ftpd_host,Config),
- {ok, Pid} = inets:start(ftpc, [{host, FtpdHost}]),
- case supervisor:which_children(ftp_sup) of
- [{_,_, worker, [ftp]}] ->
- inets:stop(ftpc, Pid),
- ct:sleep(5000),
- [] = supervisor:which_children(ftp_sup),
- catch ftp_SUITE:end_per_SUITE(Config),
- ok;
- Children ->
- catch ftp_SUITE:end_per_SUITE(Config),
- exit({unexpected_children, Children})
- end
- end.
-
-tftpd_worker() ->
- [{doc, "Makes sure the tftp sub tree is correct."}].
-tftpd_worker(Config) when is_list(Config) ->
- [] = supervisor:which_children(tftp_sup),
- {ok, Pid0} = inets:start(tftpd, [{host, inets_test_lib:hostname()},
- {port, 0}]),
- {ok, _Pid1} = inets:start(tftpd, [{host, inets_test_lib:hostname()},
- {port, 0}], stand_alone),
-
- [{_,Pid0, worker, _}] = supervisor:which_children(tftp_sup),
- inets:stop(tftpd, Pid0),
- ct:sleep(5000),
- [] = supervisor:which_children(tftp_sup),
ok.
httpd_config() ->
diff --git a/lib/inets/test/inets_test_lib.erl b/lib/inets/test/inets_test_lib.erl
index 2529cc5f9b..1cc4e11e45 100644
--- a/lib/inets/test/inets_test_lib.erl
+++ b/lib/inets/test/inets_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@
-include("inets_test_lib.hrl").
-include_lib("inets/src/http_lib/http_internal.hrl").
+-include_lib("public_key/include/public_key.hrl").
%% Note: This directive should only be used in test suites.
-compile(export_all).
@@ -594,3 +595,158 @@ read_junk(OpensslPort) ->
after 500 ->
ok
end.
+hardcode_rsa_key(1) ->
+ #'RSAPrivateKey'{
+ version = 'two-prime',
+ modulus = 23995666614853919027835084074500048897452890537492185072956789802729257783422306095699263934587064480357348855732149402060270996295002843755712064937715826848741191927820899197493902093529581182351132392364214171173881547273475904587683433713767834856230531387991145055273426806331200574039205571401702219159773947658558490957010003143162250693492642996408861265758000254664396313741422909188635443907373976005987612936763564996605457102336549804831742940035613780926178523017685712710473543251580072875247250504243621640157403744718833162626193206685233710319205099867303242759099560438381385658382486042995679707669,
+ publicExponent = 17,
+ privateExponent = 11292078406990079542510627799764728892919007311761028269626724613049062486316379339152594792746853873109340637991599718616598115903530750002688030558925094987642913848386305504703012749896273497577003478759630198199473669305165131570674557041773098755873191241407597673069847908861741446606684974777271632545629600685952292605647052193819136445675100211504432575554351515262198132231537860917084269870590492135731720141577986787033006338680118008484613510063003323516659048210893001173583018220214626635609151105287049126443102976056146630518124476470236027123782297108342869049542023328584384300970694412006494684657,
+ prime1 = 169371138592582642967021557955633494538845517070305333860805485424261447791289944610138334410987654265476540480228705481960508520379619587635662291973699651583489223555422528867090299996446070521801757353675026048850480903160224210802452555900007597342687137394192939372218903554801584969667104937092080815197,
+ prime2 = 141675062317286527042995673340952251894209529891636708844197799307963834958115010129693036021381525952081167155681637592199810112261679449166276939178032066869788822014115556349519329537177920752776047051833616197615329017439297361972726138285974555338480581117881706656603857310337984049152655480389797687577,
+ exponent1 = 119556097830058336212015217380447172615655659108450823901745048534772786676204666783627059584226579481512852103690850928442711896738555003036938088452023283470698275450886490965004917644550167427154181661417665446247398284583687678213495921811770068712485038160606780733330990744565824684470897602653233516609,
+ exponent2 = 41669135975672507953822256864985956439473391144599032012999352737636422046504414744027363535700448809435637398729893409470532385959317485048904982111185902020526124121798693043976273393287623750816484427009887116945685005129205106462566511260580751570141347387612266663707016855981760014456663376585234613993,
+ coefficient = 76837684977089699359024365285678488693966186052769523357232308621548155587515525857011429902602352279058920284048929101483304120686557782043616693940283344235057989514310975192908256494992960578961614059245280827077951132083993754797053182279229469590276271658395444955906108899267024101096069475145863928441,
+ otherPrimeInfos = asn1_NOVALUE};
+
+hardcode_rsa_key(2) ->
+ #'RSAPrivateKey'{
+ version = 'two-prime',
+ modulus = 21343679768589700771839799834197557895311746244621307033143551583788179817796325695589283169969489517156931770973490560582341832744966317712674900833543896521418422508485833901274928542544381247956820115082240721897193055368570146764204557110415281995205343662628196075590438954399631753508888358737971039058298703003743872818150364935790613286541190842600031570570099801682794056444451081563070538409720109449780410837763602317050353477918147758267825417201591905091231778937606362076129350476690460157227101296599527319242747999737801698427160817755293383890373574621116766934110792127739174475029121017282777887777,
+ publicExponent = 17,
+ privateExponent = 18832658619343853622211588088997845201745658451136447382185486691577805721584993260814073385267196632785528033211903435807948675951440868570007265441362261636545666919252206383477878125774454042314841278013741813438699754736973658909592256273895837054592950290554290654932740253882028017801960316533503857992358685308186680144968293076156011747178275038098868263178095174694099811498968993700538293188879611375604635940554394589807673542938082281934965292051746326331046224291377703201248790910007232374006151098976879987912446997911775904329728563222485791845480864283470332826504617837402078265424772379987120023773,
+ prime1 = 146807662748886761089048448970170315054939768171908279335181627815919052012991509112344782731265837727551849787333310044397991034789843793140419387740928103541736452627413492093463231242466386868459637115999163097726153692593711599245170083315894262154838974616739452594203727376460632750934355508361223110419,
+ prime2 = 145385325050081892763917667176962991350872697916072592966410309213561884732628046256782356731057378829876640317801978404203665761131810712267778698468684631707642938779964806354584156202882543264893826268426566901882487709510744074274965029453915224310656287149777603803201831202222853023280023478269485417083,
+ exponent1 = 51814469205489445090252393754177758254684624060673510353593515699736136004585238510239335081623236845018299924941168250963996835808180162284853901555621683602965806809675350150634081614988136541809283687999704622726877773856604093851236499993845033701707873394143336209718962603456693912094478414715725803677,
+ exponent2 = 51312467664734785681382706062457526359131540440966797517556579722433606376221663384746714140373192528191755406283051201483646739222992016094510128871300458249756331334105225772206172777487956446433115153562317730076172132768497908567634716277852432109643395464627389577600646306666889302334125933506877206029,
+ coefficient = 30504662229874176232343608562807118278893368758027179776313787938167236952567905398252901545019583024374163153775359371298239336609182249464886717948407152570850677549297935773605431024166978281486607154204888016179709037883348099374995148481968169438302456074511782717758301581202874062062542434218011141540,
+ otherPrimeInfos = asn1_NOVALUE};
+hardcode_rsa_key(3) ->
+ #'RSAPrivateKey'{
+ version = 'two-prime',
+ modulus = 25089040456112869869472694987833070928503703615633809313972554887193090845137746668197820419383804666271752525807484521370419854590682661809972833718476098189250708650325307850184923546875260207894844301992963978994451844985784504212035958130279304082438876764367292331581532569155681984449177635856426023931875082020262146075451989132180409962870105455517050416234175675478291534563995772675388370042873175344937421148321291640477650173765084699931690748536036544188863178325887393475703801759010864779559318631816411493486934507417755306337476945299570726975433250753415110141783026008347194577506976486290259135429,
+ publicExponent = 17,
+ privateExponent = 8854955455098659953931539407470495621824836570223697404931489960185796768872145882893348383311931058684147950284994536954265831032005645344696294253579799360912014817761873358888796545955974191021709753644575521998041827642041589721895044045980930852625485916835514940558187965584358347452650930302268008446431977397918214293502821599497633970075862760001650736520566952260001423171553461362588848929781360590057040212831994258783694027013289053834376791974167294527043946669963760259975273650548116897900664646809242902841107022557239712438496384819445301703021164043324282687280801738470244471443835900160721870265,
+ prime1 = 171641816401041100605063917111691927706183918906535463031548413586331728772311589438043965564336865070070922328258143588739626712299625805650832695450270566547004154065267940032684307994238248203186986569945677705100224518137694769557564475390859269797990555863306972197736879644001860925483629009305104925823,
+ prime2 =146170909759497809922264016492088453282310383272504533061020897155289106805616042710009332510822455269704884883705830985184223718261139908416790475825625309815234508695722132706422885088219618698987115562577878897003573425367881351537506046253616435685549396767356003663417208105346307649599145759863108910523,
+ exponent1 = 60579464612132153154728441333538327425711971378777222246428851853999433684345266860486105493295364142377972586444050678378691780811632637288529186629507258781295583787741625893888579292084087601124818789392592131211843947578009918667375697196773859928702549128225990187436545756706539150170692591519448797349,
+ exponent2 = 137572620950115585809189662580789132500998007785886619351549079675566218169991569609420548245479957900898715184664311515467504676010484619686391036071176762179044243478326713135456833024206699951987873470661533079532774988581535389682358631768109586527575902839864474036157372334443583670210960715165278974609,
+ coefficient = 15068630434698373319269196003209754243798959461311186548759287649485250508074064775263867418602372588394608558985183294561315208336731894947137343239541687540387209051236354318837334154993136528453613256169847839789803932725339395739618592522865156272771578671216082079933457043120923342632744996962853951612,
+ otherPrimeInfos = asn1_NOVALUE};
+hardcode_rsa_key(4) ->
+ #'RSAPrivateKey'{
+ version ='two-prime',
+ modulus = 28617237755030755643854803617273584643843067580642149032833640135949799721163782522787597288521902619948688786051081993247908700824196122780349730169173433743054172191054872553484065655968335396052034378669869864779940355219732200954630251223541048434478476115391643898092650304645086338265930608997389611376417609043761464100338332976874588396803891301015812818307951159858145399281035705713082131199940309445719678087542976246147777388465712394062188801177717719764254900022006288880246925156931391594131839991579403409541227225173269459173129377291869028712271737734702830877034334838181789916127814298794576266389,
+ publicExponent = 17,
+ privateExponent = 26933870828264240605980991639786903194205240075898493207372837775011576208154148256741268036255908348187001210401018346586267012540419880263858569570986761169933338532757527109161473558558433313931326474042230460969355628442100895016122589386862163232450330461545076609969553227901257730132640573174013751883368376011370428995523268034111482031427024082719896108094847702954695363285832195666458915142143884210891427766607838346722974883433132513540317964796373298134261669479023445911856492129270184781873446960437310543998533283339488055776892320162032014809906169940882070478200435536171854883284366514852906334641,
+ prime1 = 177342190816702392178883147766999616783253285436834252111702533617098994535049411784501174309695427674025956656849179054202187436663487378682303508229883753383891163725167367039879190685255046547908384208614573353917213168937832054054779266431207529839577747601879940934691505396807977946728204814969824442867,
+ prime2 = 161367340863680900415977542864139121629424927689088951345472941851682581254789586032968359551717004797621579428672968948552429138154521719743297455351687337112710712475376510559020211584326773715482918387500187602625572442687231345855402020688502483137168684570635690059254866684191216155909970061793538842967,
+ exponent1 = 62591361464718491357252875682470452982324688977706206627659717747211409835899792394529826226951327414362102349476180842659595565881230839534930649963488383547255704844176717778780890830090016428673547367746320007264898765507470136725216211681602657590439205035957626212244060728285168687080542875871702744541,
+ exponent2 = 28476589564178982426348978152495139111074987239250991413906989738532220221433456358759122273832412611344984605059935696803369847909621479954699550944415412431654831613301737157474154985469430655673456186029444871051571607533040825739188591886206320553618003159523945304574388238386685203984112363845918619347,
+ coefficient = 34340318160575773065401929915821192439103777558577109939078671096408836197675640654693301707202885840826672396546056002756167635035389371579540325327619480512374920136684787633921441576901246290213545161954865184290700344352088099063404416346968182170720521708773285279884132629954461545103181082503707725012,
+ otherPrimeInfos = asn1_NOVALUE};
+
+hardcode_rsa_key(5) ->
+ #'RSAPrivateKey'{
+ version= 'two-prime',
+ modulus = 26363170152814518327068346871197765236382539835597898797762992537312221863402655353436079974302838986536256364057947538018476963115004626096654613827403121905035011992899481598437933532388248462251770039307078647864188314916665766359828262009578648593031111569685489178543405615478739906285223620987558499488359880003693226535420421293716164794046859453204135383236667988765227190694994861629971618548127529849059769249520775574008363789050621665120207265361610436965088511042779948238320901918522125988916609088415989475825860046571847719492980547438560049874493788767083330042728150253120940100665370844282489982633,
+ publicExponent = 17,
+ privateExponent = 10855423004100095781734025182257903332628104638187370093196526338893267826106975733767797636477639582691399679317978398007608161282648963686857782164224814902073240232370374775827384395689278778574258251479385325591136364965685903795223402003944149420659869469870495544106108194608892902588033255700759382142132115013969680562678811046675523365751498355532768935784747314021422035957153013494814430893022253205880275287307995039363642554998244274484818208792520243113824379110193356010059999642946040953102866271737127640405568982049887176990990501963784502429481034227543991366980671390566584211881030995602076468001,
+ prime1 =163564135568104310461344551909369650951960301778977149705601170951529791054750122905880591964737953456660497440730575925978769763154927541340839715938951226089095007207042122512586007411328664679011914120351043948122025612160733403945093961374276707993674792189646478659304624413958625254578122842556295400709,
+ prime2 = 161179405627326572739107057023381254841260287988433675196680483761672455172873134522398837271764104320975746111042211695289319249471386600030523328069395763313848583139553961129874895374324504709512019736703349829576024049432816885712623938437949550266365056310544300920756181033500610331519029869549723159637,
+ exponent1 = 115457036871603042678596154288966812436677860079277988027483179495197499568058910286503947269226790675289762899339230065396778656344654735064122152427494983121714122734382674714766593466820233891067233496718383963380253373289929461608301619793607087995535147427985749641862087821617853120878674947686796753441,
+ exponent2 = 142217122612346975946270932667689342506994371754500301644129838613240401623123353990351915239791856753802128921507833848784693455415929352968108818884760967629866396887841730408713142977345151214275311532385308673155315337734838428569962298621720191411498579097539089047726042088382891468987379296661520434973,
+ coefficient = 40624877259097915043489529504071755460170951428490878553842519165800720914888257733191322215286203357356050737713125202129282154441426952501134581314792133018830748896123382106683994268028624341502298766844710276939303555637478596035491641473828661569958212421472263269629366559343208764012473880251174832392,
+ otherPrimeInfos = asn1_NOVALUE};
+hardcode_rsa_key(6) ->
+ #'RSAPrivateKey'{
+ version = 'two-prime',
+ modulus = 22748888494866396715768692484866595111939200209856056370972713870125588774286266397044592487895293134537316190976192161177144143633669641697309689280475257429554879273045671863645233402796222694405634510241820106743648116753479926387434021380537483429927516962909367257212902212159798399531316965145618774905828756510318897899298783143203190245236381440043169622358239226123652592179006905016804587837199618842875361941208299410035232803124113612082221121192550063791073372276763648926636149384299189072950588522522800393261949880796214514243704858378436010975184294077063518776479282353562934591448646412389762167039,
+ publicExponent = 17,
+ privateExponent = 6690849557313646092873144848490175032923294179369428344403739373566349639495960705013115437616262686628622409110644753287395336362844012263914614494257428655751435080307550548130951000822418439531068973600535325512837681398082331290421770994275730420566916753796872722709677121223470117509210872101652580854566448661533030419787125312956120661097410038933324613372774190658239039998357548275441758790939430824924502690997433186652165055694361752689819209062683281242276039100201318203707142383491769671330743466041394101421674581185260900666085723130684175548215193875544802254923825103844262661010117443222587769713,
+ prime1 = 164748737139489923768181260808494855987398781964531448608652166632780898215212977127034263859971474195908846263894581556691971503119888726148555271179103885786024920582830105413607436718060544856016793981261118694063993837665813285582095833772675610567592660039821387740255651489996976698808018635344299728063,
+ prime2 = 138082323967104548254375818343885141517788525705334488282154811252858957969378263753268344088034079842223206527922445018725900110643394926788280539200323021781309918753249061620424428562366627334409266756720941754364262467100514166396917565961434203543659974860389803369482625510495464845206228470088664021953,
+ exponent1 = 19382204369351755737433089506881747763223386113474288071606137250915399790025056132592266336467232258342217207517009594904937823896457497193947678962247515974826461245038835931012639613889475865413740468383661022831058098548919210068481862796785365949128548239978986792971253116470232552800943368864035262125,
+ exponent2 = 48734937870742781736838524121371226418043009072470995864289933383361985165662916618800592031070851709019955245149098241903258862580021738866451955011878713569874088971734962924855680669070574353320917678842685325069739694270769705787147376221682660074232932303666989424523279591939575827719845342384234360689,
+ coefficient = 81173034184183681160439870161505779100040258708276674532866007896310418779840630960490793104541748007902477778658270784073595697910785917474138815202903114440800310078464142273778315781957021015333260021813037604142367434117205299831740956310682461174553260184078272196958146289378701001596552915990080834227,
+ otherPrimeInfos = asn1_NOVALUE}.
+
+gen_pem_config_files(#{server_config := ServerConf,
+ client_config := ClientConf}, ClientBase, ServerBase) ->
+
+ ServerCaCertFile = ServerBase ++ "_server_cacerts.pem",
+ ServerCertFile = ServerBase ++ "_server_cert.pem",
+ ServerKeyFile = ServerBase ++ "_server_key.pem",
+
+ ClientCaCertFile = ClientBase ++ "_client_cacerts.pem",
+ ClientCertFile = ClientBase ++ "_client_cert.pem",
+ ClientKeyFile = ClientBase ++ "_client_key.pem",
+
+ do_gen_pem_config_files(ServerConf,
+ ServerCertFile,
+ ServerKeyFile,
+ ServerCaCertFile),
+ do_gen_pem_config_files(ClientConf,
+ ClientCertFile,
+ ClientKeyFile,
+ ClientCaCertFile),
+ [{server_config, [{certfile, ServerCertFile},
+ {keyfile, ServerKeyFile}, {cacertfile, ServerCaCertFile}]},
+ {client_config, [{certfile, ClientCertFile},
+ {keyfile, ClientKeyFile}, {cacertfile, ClientCaCertFile}]}].
+extensions(Exts) ->
+ [extension(Ext) || Ext <- Exts].
+
+
+do_gen_pem_config_files(Config, CertFile, KeyFile, CAFile) ->
+ CAs = proplists:get_value(cacerts, Config),
+ Cert = proplists:get_value(cert, Config),
+ Key = proplists:get_value(key, Config),
+ der_to_pem(CertFile, [cert_entry(Cert)]),
+ der_to_pem(KeyFile, [key_entry(Key)]),
+ der_to_pem(CAFile, ca_entries(CAs)).
+
+cert_entry(Cert) ->
+ {'Certificate', Cert, not_encrypted}.
+
+key_entry({'RSAPrivateKey', DERKey}) ->
+ {'RSAPrivateKey', DERKey, not_encrypted};
+key_entry({'DSAPrivateKey', DERKey}) ->
+ {'DSAPrivateKey', DERKey, not_encrypted};
+key_entry({'ECPrivateKey', DERKey}) ->
+ {'ECPrivateKey', DERKey, not_encrypted}.
+
+ca_entries(CAs) ->
+ [{'Certificate', CACert, not_encrypted} || CACert <- CAs].
+
+extension({_, undefined}) ->
+ [];
+extension({basic_constraints, Data}) ->
+ case Data of
+ default ->
+ #'Extension'{extnID = ?'id-ce-basicConstraints',
+ extnValue = #'BasicConstraints'{cA=true},
+ critical=true};
+ false ->
+ [];
+ Len when is_integer(Len) ->
+ #'Extension'{extnID = ?'id-ce-basicConstraints',
+ extnValue = #'BasicConstraints'{cA=true, pathLenConstraint = Len},
+ critical = true};
+ _ ->
+ #'Extension'{extnID = ?'id-ce-basicConstraints',
+ extnValue = Data}
+ end;
+extension({key_usage, Value}) ->
+ #'Extension'{extnID = ?'id-ce-keyUsage',
+ extnValue = Value,
+ critical = false};
+extension({subject_alt, Hostname}) ->
+ #'Extension'{extnID = ?'id-ce-subjectAltName',
+ extnValue = [{dNSName, Hostname}],
+ critical = false};
+extension({Id, Data, Critical}) ->
+ #'Extension'{extnID = Id, extnValue = Data, critical = Critical}.
+
+der_to_pem(File, Entries) ->
+ PemBin = public_key:pem_encode(Entries),
+ file:write_file(File, PemBin).
diff --git a/lib/inets/test/tftp_SUITE.erl b/lib/inets/test/tftp_SUITE.erl
deleted file mode 100644
index 09049e36af..0000000000
--- a/lib/inets/test/tftp_SUITE.erl
+++ /dev/null
@@ -1,949 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
--module(tftp_SUITE).
-
--compile(export_all).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Includes and defines
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--include("tftp_test_lib.hrl").
-
--define(START_DAEMON(PortX, OptionsX),
- fun(Port, Options) ->
- {ok, Pid} = ?VERIFY({ok, _Pid}, tftp:start([{port, Port} | Options])),
- if
- Port == 0 ->
- {ok, ActualOptions} = ?IGNORE(tftp:info(Pid)),
- {value, {port, ActualPort}} =
- lists:keysearch(port, 1, ActualOptions),
- {ActualPort, Pid};
- true ->
- {Port, Pid}
- end
- end(PortX, OptionsX)).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% API
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-t() ->
- tftp_test_lib:t([{?MODULE, all}]).
-
-t(Cases) ->
- tftp_test_lib:t(Cases, default_config()).
-
-t(Cases, Config) ->
- tftp_test_lib:t(Cases, Config).
-
-default_config() ->
- [].
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Test server callbacks
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-init_per_testcase(Case, Config) ->
- tftp_test_lib:init_per_testcase(Case, Config).
-
-end_per_testcase(Case, Config) when is_list(Config) ->
- tftp_test_lib:end_per_testcase(Case, Config).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Top test case
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [simple, extra, reuse_connection, resend_client,
- resend_server, large_file].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Simple
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-simple(doc) ->
- ["Start the daemon and perform simple a read and write."];
-simple(suite) ->
- [];
-simple(Config) when is_list(Config) ->
- ?VERIFY(ok, application:start(inets)),
-
- {Port, DaemonPid} = ?IGNORE(?START_DAEMON(0, [{debug, brief}])),
-
- %% Read fail
- RemoteFilename = "tftp_temporary_remote_test_file.txt",
- LocalFilename = "tftp_temporary_local_test_file.txt",
- Blob = list_to_binary(lists:duplicate(2000, $1)),
- %% Blob = <<"Some file contents\n">>,
- Size = size(Blob),
- ?IGNORE(file:delete(RemoteFilename)),
- ?VERIFY({error, {client_open, enoent, _}},
- tftp:read_file(RemoteFilename, binary, [{port, Port}])),
-
- %% Write and read
- ?VERIFY({ok, Size}, tftp:write_file(RemoteFilename, Blob, [{port, Port}])),
- ?VERIFY({ok, Blob}, tftp:read_file(RemoteFilename, binary, [{port, Port}])),
- ?IGNORE(file:delete(LocalFilename)),
- ?VERIFY({ok, Size}, tftp:read_file(RemoteFilename, LocalFilename, [{port, Port}])),
-
- %% Cleanup
- unlink(DaemonPid),
- exit(DaemonPid, kill),
- ?VERIFY(ok, file:delete(LocalFilename)),
- ?VERIFY(ok, file:delete(RemoteFilename)),
- ?VERIFY(ok, application:stop(inets)),
- ok.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Extra
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-extra(doc) ->
- ["Verify new stuff for IS 1.2."];
-extra(suite) ->
- [];
-extra(Config) when is_list(Config) ->
- ?VERIFY({'EXIT', {badarg,{fake_key, fake_flag}}},
- tftp:start([{port, 0}, {fake_key, fake_flag}])),
-
- {Port, DaemonPid} = ?IGNORE(?START_DAEMON(0, [{debug, brief}])),
-
- RemoteFilename = "tftp_extra_temporary_remote_test_file.txt",
- LocalFilename = "tftp_extra_temporary_local_test_file.txt",
- Blob = <<"Some file contents\n">>,
- Size = size(Blob),
- Host = "127.0.0.1",
- Peer = {inet, Host, Port},
- Generic =
- [
- {state, []},
- {prepare, fun extra_prepare/6},
- {open, fun extra_open/6},
- {read, fun extra_read/1},
- {write, fun extra_write/2},
- {abort, fun extra_abort/3 }
- ],
- Options = [{host, Host},
- {port, Port},
- %%{ debug,all},
- {callback, {".*", tftp_test_lib, Generic}}],
- ?VERIFY(ok, file:write_file(LocalFilename, Blob)),
- ?VERIFY({ok, [{count, Size}, Peer]},
- tftp:write_file(RemoteFilename, LocalFilename, Options)),
- ?VERIFY(ok, file:delete(LocalFilename)),
-
- ?VERIFY({ok,[{bin, Blob}, Peer]},
- tftp:read_file(RemoteFilename, LocalFilename, Options)),
-
- %% Cleanup
- unlink(DaemonPid),
- exit(DaemonPid, kill),
- ?VERIFY(ok, file:delete(LocalFilename)),
- ?VERIFY(ok, file:delete(RemoteFilename)),
- ok.
-
--record(extra_state, {file, blksize, count, acc, peer}).
-
-%%-------------------------------------------------------------------
-%% Prepare
-%%-------------------------------------------------------------------
-
-extra_prepare(Peer, Access, LocalFilename, Mode, SuggestedOptions, []) ->
- %% Client side
- BlkSize = list_to_integer(tftp_test_lib:lookup_option("blksize", "512", SuggestedOptions)),
- State = #extra_state{blksize = BlkSize, peer = Peer},
- extra_open(Peer, Access, LocalFilename, Mode, SuggestedOptions, State),
- {ok, SuggestedOptions, State};
-extra_prepare(_Peer, _Access, _Bin, _Mode, _SuggestedOptions, _Initial) ->
- {error, {undef, "Illegal callback options."}}.
-
-%%-------------------------------------------------------------------
-%% Open
-%%-------------------------------------------------------------------
-
-extra_open(Peer, Access, LocalFilename, Mode, SuggestedOptions, []) ->
- %% Server side
- case extra_prepare(Peer, Access, LocalFilename, Mode, SuggestedOptions, []) of
- {ok, AcceptedOptions, []} ->
- BlkSize = list_to_integer(tftp_test_lib:lookup_option("blksize", "512", AcceptedOptions)),
- State = #extra_state{blksize = BlkSize, peer = Peer},
- extra_open(Peer, Access, LocalFilename, Mode, AcceptedOptions, State);
- {error, {Code, Text}} ->
- {error, {Code, Text}}
- end;
-extra_open(_Peer, Access, LocalFilename, _Mode, NegotiatedOptions, #extra_state{} = State) ->
- {File, Acc} =
- case Access of
- read ->
- if
- is_binary(LocalFilename) ->
- {undefined, LocalFilename};
- is_list(LocalFilename) ->
- {ok, Bin} = file:read_file(LocalFilename),
- {LocalFilename, Bin}
- end;
- write ->
- {LocalFilename, []}
- end,
- %% Both sides
- State2 = State#extra_state{file = File, acc = Acc, count = 0},
- {ok, NegotiatedOptions, State2}.
-
-%%-------------------------------------------------------------------
-%% Read
-%%-------------------------------------------------------------------
-
-extra_read(#extra_state{acc = Bin} = State) when is_binary(Bin) ->
- BlkSize = State#extra_state.blksize,
- Count = State#extra_state.count + size(Bin),
- if
- size(Bin) >= BlkSize ->
- <<Block:BlkSize/binary, Bin2/binary>> = Bin,
- State2 = State#extra_state{acc = Bin2, count = Count},
- {more, Block, State2};
- size(Bin) < BlkSize ->
- Res = [{count, Count}, State#extra_state.peer],
- {last, Bin, Res}
- end.
-
-%%-------------------------------------------------------------------
-%% Write
-%%-------------------------------------------------------------------
-
-extra_write(Bin, #extra_state{acc = List} = State) when is_binary(Bin), is_list(List) ->
- Size = size(Bin),
- BlkSize = State#extra_state.blksize,
- if
- Size == BlkSize ->
- {more, State#extra_state{acc = [Bin | List]}};
- Size < BlkSize ->
- Bin2 = list_to_binary(lists:reverse([Bin | List])),
- Res = [{bin, Bin2}, State#extra_state.peer],
- file:write_file(State#extra_state.file, Bin2),
- {last, Res}
- end.
-
-%%-------------------------------------------------------------------
-%% Abort
-%%-------------------------------------------------------------------
-
-extra_abort(_Code, _Text, #extra_state{}) ->
- ok.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Re-send client
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-resend_client(doc) ->
- ["Verify that the server behaves correctly when the client re-sends packets."];
-resend_client(suite) ->
- [];
-resend_client(Config) when is_list(Config) ->
- Host = {127, 0, 0, 1},
- {Port, DaemonPid} = ?IGNORE(?START_DAEMON(0, [{debug, all}])),
-
- ?VERIFY(ok, resend_read_client(Host, Port, 10)),
- ?VERIFY(ok, resend_read_client(Host, Port, 512)),
- ?VERIFY(ok, resend_read_client(Host, Port, 1025)),
-
- ?VERIFY(ok, resend_write_client(Host, Port, 10)),
- ?VERIFY(ok, resend_write_client(Host, Port, 512)),
- ?VERIFY(ok, resend_write_client(Host, Port, 1025)),
-
- %% Cleanup
- unlink(DaemonPid),
- exit(DaemonPid, kill),
- ok.
-
-resend_read_client(Host, Port, BlkSize) ->
- RemoteFilename = "tftp_resend_read_client.tmp",
- Block1 = lists:duplicate(BlkSize, $1),
- Block2 = lists:duplicate(BlkSize, $2),
- Block3 = lists:duplicate(BlkSize, $3),
- Block4 = lists:duplicate(BlkSize, $4),
- Block5 = lists:duplicate(BlkSize, $5),
- Blocks = [Block1, Block2, Block3, Block4, Block5],
- Blob = list_to_binary(Blocks),
- ?VERIFY(ok, file:write_file(RemoteFilename, Blob)),
-
- Timeout = timer:seconds(3),
- ?VERIFY(timeout, recv(0)),
-
- %% Open socket
- {ok, Socket} = ?VERIFY({ok, _}, gen_udp:open(0, [binary, {reuseaddr, true}, {active, true}])),
-
- ReadList = [0, 1, RemoteFilename, 0, "octet", 0],
- Data1Bin = list_to_binary([0, 3, 0, 1 | Block1]),
- NewPort =
- if
- BlkSize =:= 512 ->
- %% Send READ
- ReadBin = list_to_binary(ReadList),
- ?VERIFY(ok, gen_udp:send(Socket, Host, Port, ReadBin)),
-
- %% Sleep a while in order to provoke the server to re-send the packet
- timer:sleep(Timeout + timer:seconds(1)),
-
- %% Recv DATA #1 (the packet that the server think that we have lost)
- {udp, _, _, NewPort0, _} = ?VERIFY({udp, Socket, Host, _, Data1Bin}, recv(Timeout)),
- NewPort0;
- true ->
- %% Send READ
- BlkSizeList = integer_to_list(BlkSize),
- Options = ["blksize", 0, BlkSizeList, 0],
- ReadBin = list_to_binary([ReadList | Options]),
- ?VERIFY(ok, gen_udp:send(Socket, Host, Port, ReadBin)),
-
- %% Recv OACK
- OptionAckBin = list_to_binary([0, 6 | Options]),
- {udp, _, _, NewPort0, _} = ?VERIFY({udp, Socket, Host, _, OptionAckBin}, recv(Timeout)),
-
- %% Send ACK #0
- Ack0Bin = <<0, 4, 0, 0>>,
- ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort0, Ack0Bin)),
-
- %% Send ACK #0 AGAIN (pretend that we timed out)
- timer:sleep(timer:seconds(1)),
- ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort0, Ack0Bin)),
-
- %% Recv DATA #1 (the packet that the server think that we have lost)
- ?VERIFY({udp, Socket, Host, NewPort0, Data1Bin}, recv(Timeout)),
- NewPort0
- end,
-
- %% Recv DATA #1 AGAIN (the re-sent package)
- ?VERIFY({udp, Socket, Host, NewPort, Data1Bin}, recv(Timeout)),
-
- %% Send ACK #1
- Ack1Bin = <<0, 4, 0, 1>>,
- ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack1Bin)),
-
- %% Recv DATA #2
- Data2Bin = list_to_binary([0, 3, 0, 2 | Block2]),
- ?VERIFY({udp, Socket, Host, NewPort, Data2Bin}, recv(Timeout)),
-
- %% Send ACK #2
- Ack2Bin = <<0, 4, 0, 2>>,
- ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack2Bin)),
-
- %% Recv DATA #3
- Data3Bin = list_to_binary([0, 3, 0, 3 | Block3]),
- ?VERIFY({udp, Socket, Host, NewPort, Data3Bin}, recv(Timeout)),
-
- %% Send ACK #3
- Ack3Bin = <<0, 4, 0, 3>>,
- ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack3Bin)),
-
- %% Send ACK #3 AGAIN (pretend that we timed out)
- timer:sleep(timer:seconds(1)),
- ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack3Bin)),
-
- %% Recv DATA #4 (the packet that the server think that we have lost)
- Data4Bin = list_to_binary([0, 3, 0, 4 | Block4]),
- ?VERIFY({udp, Socket, Host, NewPort, Data4Bin}, recv(Timeout)),
-
- %% Recv DATA #4 AGAIN (the re-sent package)
- ?VERIFY({udp, Socket, Host, NewPort, Data4Bin}, recv(Timeout)),
-
- %% Send ACK #2 which is out of range
- ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack2Bin)),
-
- %% Send ACK #4
- Ack4Bin = <<0, 4, 0, 4>>,
- ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack4Bin)),
-
- %% Recv DATA #5
- Data5Bin = list_to_binary([0, 3, 0, 5 | Block5]),
- ?VERIFY({udp, Socket, Host, NewPort, Data5Bin}, recv(Timeout)),
-
- %% Send ACK #5
- Ack5Bin = <<0, 4, 0, 5>>,
- ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack5Bin)),
-
- %% Close socket
- ?VERIFY(ok, gen_udp:close(Socket)),
-
- ?VERIFY(timeout, recv(Timeout)),
- ?VERIFY(ok, file:delete(RemoteFilename)),
- ok.
-
-resend_write_client(Host, Port, BlkSize) ->
- RemoteFilename = "tftp_resend_write_client.tmp",
- Block1 = lists:duplicate(BlkSize, $1),
- Block2 = lists:duplicate(BlkSize, $2),
- Block3 = lists:duplicate(BlkSize, $3),
- Block4 = lists:duplicate(BlkSize, $4),
- Block5 = lists:duplicate(BlkSize, $5),
- Blocks = [Block1, Block2, Block3, Block4, Block5],
- Blob = list_to_binary(Blocks),
- ?IGNORE(file:delete(RemoteFilename)),
- ?VERIFY({error, enoent}, file:read_file(RemoteFilename)),
-
- Timeout = timer:seconds(3),
- ?VERIFY(timeout, recv(0)),
-
- %% Open socket
- {ok, Socket} = ?VERIFY({ok, _}, gen_udp:open(0, [binary, {reuseaddr, true}, {active, true}])),
-
- WriteList = [0, 2, RemoteFilename, 0, "octet", 0],
- NewPort =
- if
- BlkSize =:= 512 ->
- %% Send WRITE
- WriteBin = list_to_binary(WriteList),
- ?VERIFY(ok, gen_udp:send(Socket, Host, Port, WriteBin)),
-
- %% Sleep a while in order to provoke the server to re-send the packet
- timer:sleep(Timeout + timer:seconds(1)),
-
- %% Recv ACK #0 (the packet that the server think that we have lost)
- Ack0Bin = <<0, 4, 0, 0>>,
- ?VERIFY({udp, Socket, Host, _, Ack0Bin}, recv(Timeout)),
-
- %% Recv ACK #0 AGAIN (the re-sent package)
- {udp, _, _, NewPort0, _} = ?VERIFY({udp, Socket, Host, _, Ack0Bin}, recv(Timeout)),
- NewPort0;
- true ->
- %% Send WRITE
- BlkSizeList = integer_to_list(BlkSize),
- WriteBin = list_to_binary([WriteList, "blksize", 0, BlkSizeList, 0]),
- ?VERIFY(ok, gen_udp:send(Socket, Host, Port, WriteBin)),
-
- %% Sleep a while in order to provoke the server to re-send the packet
- timer:sleep(timer:seconds(1)),
-
- %% Recv OACK (the packet that the server think that we have lost)
- OptionAckBin = list_to_binary([0, 6, "blksize",0, BlkSizeList, 0]),
- ?VERIFY({udp, Socket, Host, _, OptionAckBin}, recv(Timeout)),
-
- %% Recv OACK AGAIN (the re-sent package)
- {udp, _, _, NewPort0, _} = ?VERIFY({udp, Socket, Host, _, OptionAckBin}, recv(Timeout)),
- NewPort0
- end,
-
- %% Send DATA #1
- Data1Bin = list_to_binary([0, 3, 0, 1 | Block1]),
- ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Data1Bin)),
-
- %% Recv ACK #1
- Ack1Bin = <<0, 4, 0, 1>>,
- ?VERIFY({udp, Socket, Host, NewPort, Ack1Bin}, recv(Timeout)),
-
- %% Send DATA #2
- Data2Bin = list_to_binary([0, 3, 0, 2 | Block2]),
- ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Data2Bin)),
-
- %% Recv ACK #2
- Ack2Bin = <<0, 4, 0, 2>>,
- ?VERIFY({udp, Socket, Host, NewPort, Ack2Bin}, recv(Timeout)),
-
- %% Send DATA #3
- Data3Bin = list_to_binary([0, 3, 0, 3 | Block3]),
- ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Data3Bin)),
-
- %% Recv ACK #3
- Ack3Bin = <<0, 4, 0, 3>>,
- ?VERIFY({udp, Socket, Host, NewPort, Ack3Bin}, recv(Timeout)),
-
- %% Send DATA #3 AGAIN (pretend that we timed out)
- timer:sleep(timer:seconds(1)),
- ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Data3Bin)),
-
- %% Recv ACK #3 AGAIN (the packet that the server think that we have lost)
- ?VERIFY({udp, Socket, Host, NewPort, Ack3Bin}, recv(Timeout)),
-
- %% Send DATA #2 which is out of range
- ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Data2Bin)),
-
- %% Send DATA #4
- Data4Bin = list_to_binary([0, 3, 0, 4 | Block4]),
- ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Data4Bin)),
-
- %% Recv ACK #4
- Ack4Bin = <<0, 4, 0, 4>>,
- ?VERIFY({udp, Socket, Host, NewPort, Ack4Bin}, recv(Timeout)),
-
- %% Send DATA #5
- Data5Bin = list_to_binary([0, 3, 0, 5 | Block5]),
- ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Data5Bin)),
-
- %% Recv ACK #5
- Ack5Bin = <<0, 4, 0, 5>>,
- ?VERIFY({udp, Socket, Host, NewPort, Ack5Bin}, recv(Timeout)),
-
- %% Close socket
- ?VERIFY(ok, gen_udp:close(Socket)),
-
- ?VERIFY(timeout, recv(Timeout)),
- ?VERIFY({ok, Blob}, file:read_file(RemoteFilename)),
- ?VERIFY(ok, file:delete(RemoteFilename)),
- ok.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Re-send server
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-resend_server(doc) ->
- ["Verify that the server behaves correctly when the server re-sends packets."];
-resend_server(suite) ->
- [];
-resend_server(Config) when is_list(Config) ->
- Host = {127, 0, 0, 1},
-
- ?VERIFY(ok, resend_read_server(Host, 10)),
- ?VERIFY(ok, resend_read_server(Host, 512)),
- ?VERIFY(ok, resend_read_server(Host, 1025)),
-
- ?VERIFY(ok, resend_write_server(Host, 10)),
- ?VERIFY(ok, resend_write_server(Host, 512)),
- ?VERIFY(ok, resend_write_server(Host, 1025)),
- ok.
-
-resend_read_server(Host, BlkSize) ->
- RemoteFilename = "tftp_resend_read_server.tmp",
- Block1 = lists:duplicate(BlkSize, $1),
- Block2 = lists:duplicate(BlkSize, $2),
- Block3 = lists:duplicate(BlkSize, $3),
- Block4 = lists:duplicate(BlkSize, $4),
- Block5 = lists:duplicate(BlkSize, $5),
- Block6 = [],
- Blocks = [Block1, Block2, Block3, Block4, Block5, Block6],
- Blob = list_to_binary(Blocks),
-
- Timeout = timer:seconds(3),
- ?VERIFY(timeout, recv(0)),
-
- %% Open daemon socket
- {ok, DaemonSocket} = ?VERIFY({ok, _}, gen_udp:open(0, [binary, {reuseaddr, true}, {active, true}])),
- {ok, DaemonPort} = ?IGNORE(inet:port(DaemonSocket)),
-
- %% Open server socket
- {ok, ServerSocket} = ?VERIFY({ok, _}, gen_udp:open(0, [binary, {reuseaddr, true}, {active, true}])),
- ?IGNORE(inet:port(ServerSocket)),
-
- %% Prepare client process
- ReplyTo = self(),
- ClientFun =
- fun(Extra) ->
- Options = [{port, DaemonPort}, {debug, brief}] ++ Extra,
- Res = ?VERIFY({ok, Blob}, tftp:read_file(RemoteFilename, binary, Options)),
- ReplyTo ! {self(), {tftp_client_reply, Res}},
- exit(normal)
- end,
-
- ReadList = [0, 1, RemoteFilename, 0, "octet", 0],
- Data1Bin = list_to_binary([0, 3, 0, 1 | Block1]),
- Ack1Bin = <<0, 4, 0, 1>>,
- {ClientPort, ClientPid} =
- if
- BlkSize =:= 512 ->
- %% Start client process
- ClientPid0 = spawn_link(fun() -> ClientFun([]) end),
-
- %% Recv READ
- ReadBin = list_to_binary(ReadList),
- {udp, _, _, ClientPort0, _} = ?VERIFY({udp, DaemonSocket, Host, _, ReadBin}, recv(Timeout)),
-
- %% Send DATA #1
- ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort0, Data1Bin)),
-
- %% Sleep a while in order to provoke the client to re-send the packet
- timer:sleep(Timeout + timer:seconds(1)),
-
- %% Recv ACK #1 (the packet that the server think that we have lost)
- ?VERIFY({udp, ServerSocket, Host, ClientPort0, Ack1Bin}, recv(Timeout)),
-
- %% Recv ACK #1 AGAIN (the re-sent package)
- ?VERIFY({udp, ServerSocket, Host, _, Ack1Bin}, recv(Timeout)),
- {ClientPort0, ClientPid0};
- true ->
- %% Start client process
- BlkSizeList = integer_to_list(BlkSize),
- ClientPid0 = spawn_link(fun() -> ClientFun([{"blksize", BlkSizeList}]) end),
-
- %% Recv READ
- Options = ["blksize", 0, BlkSizeList, 0],
- ReadBin = list_to_binary([ReadList | Options]),
- {udp, _, _, ClientPort0, _} = ?VERIFY({udp, DaemonSocket, Host, _, ReadBin}, recv(Timeout)),
-
- %% Send OACK
- BlkSizeList = integer_to_list(BlkSize),
- OptionAckBin = list_to_binary([0, 6, "blksize",0, BlkSizeList, 0]),
- ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort0, OptionAckBin)),
-
- %% Sleep a while in order to provoke the client to re-send the packet
- timer:sleep(Timeout + timer:seconds(1)),
-
- %% Recv ACK #0 (the packet that the server think that we have lost)
- Ack0Bin = <<0, 4, 0, 0>>,
- ?VERIFY({udp, ServerSocket, Host, ClientPort0, Ack0Bin}, recv(Timeout)),
-
- %% Recv ACK #0 AGAIN (the re-sent package)
- ?VERIFY({udp, ServerSocket, Host, ClientPort0, Ack0Bin}, recv(Timeout)),
-
- %% Send DATA #1
- ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort0, Data1Bin)),
-
- %% Recv ACK #1
- ?VERIFY({udp, ServerSocket, Host, _, Ack1Bin}, recv(Timeout)),
- {ClientPort0, ClientPid0}
- end,
-
- %% Send DATA #2
- Data2Bin = list_to_binary([0, 3, 0, 2 | Block2]),
- ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Data2Bin)),
-
- %% Recv ACK #2
- Ack2Bin = <<0, 4, 0, 2>>,
- ?VERIFY({udp, ServerSocket, Host, ClientPort, Ack2Bin}, recv(Timeout)),
-
- %% Send DATA #3
- Data3Bin = list_to_binary([0, 3, 0, 3 | Block3]),
- ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Data3Bin)),
-
- %% Recv ACK #3
- Ack3Bin = <<0, 4, 0, 3>>,
- ?VERIFY({udp, ServerSocket, Host, ClientPort, Ack3Bin}, recv(Timeout)),
-
- %% Send DATA #3 AGAIN (pretend that we timed out)
- timer:sleep(timer:seconds(1)),
- ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Data3Bin)),
-
- %% Recv ACK #3 AGAIN (the packet that the server think that we have lost)
- ?VERIFY({udp, ServerSocket, Host, ClientPort, Ack3Bin}, recv(Timeout)),
-
- %% Send DATA #4
- Data4Bin = list_to_binary([0, 3, 0, 4 | Block4]),
- ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Data4Bin)),
-
- %% Recv ACK #4
- Ack4Bin = <<0, 4, 0, 4>>,
- ?VERIFY({udp, ServerSocket, Host, ClientPort, Ack4Bin}, recv(Timeout)),
-
- %% Send DATA #3 which is out of range
- ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Data3Bin)),
-
- %% Send DATA #5
- Data5Bin = list_to_binary([0, 3, 0, 5 | Block5]),
- ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Data5Bin)),
-
- %% Recv ACK #5
- Ack5Bin = <<0, 4, 0, 5>>,
- ?VERIFY({udp, ServerSocket, Host, ClientPort, Ack5Bin}, recv(Timeout)),
-
- %% Send DATA #6
- Data6Bin = list_to_binary([0, 3, 0, 6 | Block6]),
- ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Data6Bin)),
-
- %% Close daemon and server sockets
- ?VERIFY(ok, gen_udp:close(ServerSocket)),
- ?VERIFY(ok, gen_udp:close(DaemonSocket)),
-
- ?VERIFY({ClientPid, {tftp_client_reply, {ok, Blob}}}, recv(Timeout)),
-
- ?VERIFY(timeout, recv(Timeout)),
- ok.
-
-resend_write_server(Host, BlkSize) ->
- RemoteFilename = "tftp_resend_write_server.tmp",
- Block1 = lists:duplicate(BlkSize, $1),
- Block2 = lists:duplicate(BlkSize, $2),
- Block3 = lists:duplicate(BlkSize, $3),
- Block4 = lists:duplicate(BlkSize, $4),
- Block5 = lists:duplicate(BlkSize, $5),
- Block6 = [],
- Blocks = [Block1, Block2, Block3, Block4, Block5, Block6],
- Blob = list_to_binary(Blocks),
- Size = size(Blob),
-
- Timeout = timer:seconds(3),
- ?VERIFY(timeout, recv(0)),
-
- %% Open daemon socket
- {ok, DaemonSocket} = ?VERIFY({ok, _}, gen_udp:open(0, [binary, {reuseaddr, true}, {active, true}])),
- {ok, DaemonPort} = ?IGNORE(inet:port(DaemonSocket)),
-
- %% Open server socket
- {ok, ServerSocket} = ?VERIFY({ok, _}, gen_udp:open(0, [binary, {reuseaddr, true}, {active, true}])),
- ?IGNORE(inet:port(ServerSocket)),
-
- %% Prepare client process
- ReplyTo = self(),
- ClientFun =
- fun(Extra) ->
- Options = [{port, DaemonPort}, {debug, brief}] ++ Extra,
- Res = ?VERIFY({ok, Size}, tftp:write_file(RemoteFilename, Blob, Options)),
- ReplyTo ! {self(), {tftp_client_reply, Res}},
- exit(normal)
- end,
-
- WriteList = [0, 2, RemoteFilename, 0, "octet", 0],
- Data1Bin = list_to_binary([0, 3, 0, 1 | Block1]),
- {ClientPort, ClientPid} =
- if
- BlkSize =:= 512 ->
- %% Start client process
- ClientPid0 = spawn_link(fun() -> ClientFun([]) end),
-
- %% Recv WRITE
- WriteBin = list_to_binary(WriteList),
- io:format("WriteBin ~p\n", [WriteBin]),
- {udp, _, _, ClientPort0, _} = ?VERIFY({udp, DaemonSocket, Host, _, WriteBin}, recv(Timeout)),
-
- %% Send ACK #1
- Ack0Bin = <<0, 4, 0, 0>>,
- ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort0, Ack0Bin)),
-
- %% Sleep a while in order to provoke the client to re-send the packet
- timer:sleep(Timeout + timer:seconds(1)),
-
- %% Recv DATA #1 (the packet that the server think that we have lost)
- ?VERIFY({udp, ServerSocket, Host, ClientPort0, Data1Bin}, recv(Timeout)),
-
- %% Recv DATA #1 AGAIN (the re-sent package)
- ?VERIFY({udp, ServerSocket, Host, _, Data1Bin}, recv(Timeout)),
- {ClientPort0, ClientPid0};
- true ->
- %% Start client process
- BlkSizeList = integer_to_list(BlkSize),
- ClientPid0 = spawn_link(fun() -> ClientFun([{"blksize", BlkSizeList}]) end),
-
- %% Recv WRITE
- Options = ["blksize", 0, BlkSizeList, 0],
- WriteBin = list_to_binary([WriteList | Options]),
- {udp, _, _, ClientPort0, _} = ?VERIFY({udp, DaemonSocket, Host, _, WriteBin}, recv(Timeout)),
-
- %% Send OACK
- BlkSizeList = integer_to_list(BlkSize),
- OptionAckBin = list_to_binary([0, 6, "blksize",0, BlkSizeList, 0]),
- ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort0, OptionAckBin)),
-
- %% Sleep a while in order to provoke the client to re-send the packet
- timer:sleep(Timeout + timer:seconds(1)),
-
- %% Recv DATA #1 (the packet that the server think that we have lost)
- ?VERIFY({udp, ServerSocket, Host, ClientPort0, Data1Bin}, recv(Timeout)),
-
- %% Recv DATA #1 AGAIN (the re-sent package)
- ?VERIFY({udp, ServerSocket, Host, ClientPort0, Data1Bin}, recv(Timeout)),
- {ClientPort0, ClientPid0}
- end,
-
- %% Send ACK #1
- Ack1Bin = <<0, 4, 0, 1>>,
- ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Ack1Bin)),
-
- %% Recv DATA #2
- Data2Bin = list_to_binary([0, 3, 0, 2 | Block2]),
- ?VERIFY({udp, ServerSocket, Host, ClientPort, Data2Bin}, recv(Timeout)),
-
- %% Send ACK #2
- Ack2Bin = <<0, 4, 0, 2>>,
- ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Ack2Bin)),
-
- %% Recv DATA #3
- Data3Bin = list_to_binary([0, 3, 0, 3 | Block3]),
- ?VERIFY({udp, ServerSocket, Host, ClientPort, Data3Bin}, recv(Timeout)),
-
- %% Send ACK #3
- Ack3Bin = <<0, 4, 0, 3>>,
- ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Ack3Bin)),
-
- %% Send ACK #3 AGAIN (pretend that we timed out)
- timer:sleep(timer:seconds(1)),
- ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Ack3Bin)),
-
- %% Recv DATA #4 (the packet that the server think that we have lost)
- Data4Bin = list_to_binary([0, 3, 0, 4 | Block4]),
- ?VERIFY({udp, ServerSocket, Host, ClientPort, Data4Bin}, recv(Timeout)),
-
- %% Recv DATA #4 AGAIN (the re-sent package)
- ?VERIFY({udp, ServerSocket, Host, ClientPort, Data4Bin}, recv(Timeout)),
-
- %% Send ACK #4
- Ack4Bin = <<0, 4, 0, 4>>,
- ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Ack4Bin)),
-
- %% Recv DATA #5
- Data5Bin = list_to_binary([0, 3, 0, 5 | Block5]),
- ?VERIFY({udp, ServerSocket, Host, ClientPort, Data5Bin}, recv(Timeout)),
-
- %% Send ACK #3 which is out of range
- ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Ack3Bin)),
-
- %% Send ACK #5
- Ack5Bin = <<0, 4, 0, 5>>,
- ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Ack5Bin)),
-
- %% Recv DATA #6
- Data6Bin = list_to_binary([0, 3, 0, 6 | Block6]),
- ?VERIFY({udp, ServerSocket, Host, ClientPort, Data6Bin}, recv(Timeout)),
-
- %% Send ACK #6
- Ack6Bin = <<0, 4, 0, 6>>,
- ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Ack6Bin)),
-
- %% Close daemon and server sockets
- ?VERIFY(ok, gen_udp:close(ServerSocket)),
- ?VERIFY(ok, gen_udp:close(DaemonSocket)),
-
- ?VERIFY({ClientPid, {tftp_client_reply, {ok, Size}}}, recv(Timeout)),
-
- ?VERIFY(timeout, recv(Timeout)),
- ok.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-reuse_connection(doc) ->
- ["Verify that the server can reuse an ongiong connection when same client resends request."];
-reuse_connection(suite) ->
- [];
-reuse_connection(Config) when is_list(Config) ->
- Host = {127, 0, 0, 1},
- {Port, DaemonPid} = ?IGNORE(?START_DAEMON(0, [{debug, all}])),
-
- RemoteFilename = "reuse_connection.tmp",
- BlkSize = 512,
- Block1 = lists:duplicate(BlkSize, $1),
- Block2 = lists:duplicate(BlkSize div 2, $2),
- Blocks = [Block1, Block2],
- Blob = list_to_binary(Blocks),
- ?VERIFY(ok, file:write_file(RemoteFilename, Blob)),
-
- Seconds = 3,
- Timeout = timer:seconds(Seconds),
- ?VERIFY(timeout, recv(0)),
-
- %% Open socket
- {ok, Socket} = ?VERIFY({ok, _}, gen_udp:open(0, [binary, {reuseaddr, true}, {active, true}])),
-
- ReadList = [0, 1, RemoteFilename, 0, "octet", 0],
- Data1Bin = list_to_binary([0, 3, 0, 1 | Block1]),
-
- %% Send READ
- TimeoutList = integer_to_list(Seconds),
- Options = ["timeout", 0, TimeoutList, 0],
- ReadBin = list_to_binary([ReadList | Options]),
- ?VERIFY(ok, gen_udp:send(Socket, Host, Port, ReadBin)),
-
- %% Send yet another READ for same file
- ?VERIFY(ok, gen_udp:send(Socket, Host, Port, ReadBin)),
-
- %% Recv OACK
- OptionAckBin = list_to_binary([0, 6 | Options]),
- {udp, _, _, NewPort, _} = ?VERIFY({udp, Socket, Host, _, OptionAckBin}, recv(Timeout)),
-
- %% Send ACK #0
- Ack0Bin = <<0, 4, 0, 0>>,
- ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack0Bin)),
-
- %% Recv DATA #1
- ?VERIFY({udp, Socket, Host, NewPort, Data1Bin}, recv(Timeout)),
-
- %% Send ACK #1
- Ack1Bin = <<0, 4, 0, 1>>,
- ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack1Bin)),
-
- %% Recv DATA #2
- Data2Bin = list_to_binary([0, 3, 0, 2 | Block2]),
- ?VERIFY({udp, Socket, Host, NewPort, Data2Bin}, recv(Timeout)),
-
- %% Send ACK #2
- Ack2Bin = <<0, 4, 0, 2>>,
- ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack2Bin)),
-
- %% Close socket
- ?VERIFY(ok, gen_udp:close(Socket)),
-
- ?VERIFY(timeout, recv(Timeout)),
- ?VERIFY(ok, file:delete(RemoteFilename)),
-
- %% Cleanup
- unlink(DaemonPid),
- exit(DaemonPid, kill),
- ok.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Large file: transfer > 65535 blocks
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-large_file(doc) ->
- ["Start the daemon and test transfer of files greater than 32M."];
-large_file(suite) ->
- [];
-large_file(Config) when is_list(Config) ->
- ?VERIFY(ok, application:start(inets)),
-
- {Port, DaemonPid} = ?IGNORE(?START_DAEMON(0, [{debug, brief}])),
-
- %% Read fail
- RemoteFilename = "tftp_temporary_large_file_remote_test_file.txt",
- LocalFilename = "tftp_temporary_large_file_local_test_file.txt",
-
- {ok, FH} = file:open(LocalFilename, [write,exclusive]),
- {ok, Size} = file:position(FH, {eof, 2*512*65535}),
- ok = file:truncate(FH),
- ?IGNORE(file:close(FH)),
-
- %% Write and read
- ?VERIFY({ok, Size}, tftp:write_file(RemoteFilename, LocalFilename, [{port, Port}])),
- ?IGNORE(file:delete(LocalFilename)),
- ?VERIFY({ok, Size}, tftp:read_file(RemoteFilename, LocalFilename, [{port, Port}])),
-
- %% Cleanup
- unlink(DaemonPid),
- exit(DaemonPid, kill),
- ?VERIFY(ok, file:delete(LocalFilename)),
- ?VERIFY(ok, file:delete(RemoteFilename)),
- ?VERIFY(ok, application:stop(inets)),
- ok.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Goodies
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-recv(Timeout) ->
- receive
- Msg ->
- Msg
- after Timeout ->
- timeout
- end.
diff --git a/lib/inets/test/tftp_test_lib.erl b/lib/inets/test/tftp_test_lib.erl
deleted file mode 100644
index f07795324f..0000000000
--- a/lib/inets/test/tftp_test_lib.erl
+++ /dev/null
@@ -1,308 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
--module(tftp_test_lib).
-
--compile(export_all).
-
--include("tftp_test_lib.hrl").
-
-%%
-%% -----
-%%
-
-init_per_testcase(_Case, Config) when is_list(Config) ->
- io:format("\n ", []),
- ?IGNORE(application:stop(inets)),
- Config.
-
-end_per_testcase(_Case, Config) when is_list(Config) ->
- ?IGNORE(application:stop(inets)),
- Config.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Infrastructure for test suite
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-error(Actual, Mod, Line) ->
- (catch global:send(tftp_global_logger, {failed, Mod, Line})),
- log("<ERROR> Bad result: ~p\n", [Actual], Mod, Line),
- Label = lists:concat([Mod, "(", Line, ") unexpected result"]),
- et:report_event(60, Mod, Mod, Label,
- [{line, Mod, Line}, {error, Actual}]),
- case global:whereis_name(tftp_test_case_sup) of
- undefined ->
- ignore;
- Pid ->
- Fail = #'REASON'{mod = Mod, line = Line, desc = Actual},
- Pid ! {fail, self(), Fail}
- end,
- Actual.
-
-log(Format, Args, Mod, Line) ->
- case global:whereis_name(tftp_global_logger) of
- undefined ->
- io:format(user, "~p(~p): " ++ Format,
- [Mod, Line] ++ Args);
- Pid ->
- io:format(Pid, "~p(~p): " ++ Format,
- [Mod, Line] ++ Args)
- end.
-
-default_config() ->
- [].
-
-t() ->
- t([{?MODULE, all}]).
-
-t(Cases) ->
- t(Cases, default_config()).
-
-t(Cases, Config) ->
- process_flag(trap_exit, true),
- Res = lists:flatten(do_test(Cases, Config)),
- io:format("Res: ~p\n", [Res]),
- display_result(Res),
- Res.
-
-do_test({Mod, Fun}, Config) when is_atom(Mod), is_atom(Fun) ->
- case catch apply(Mod, Fun, [suite]) of
- [] ->
- io:format("Eval: ~p:", [{Mod, Fun}]),
- Res = eval(Mod, Fun, Config),
- {R, _, _} = Res,
- io:format(" ~p\n", [R]),
- Res;
-
- Cases when is_list(Cases) ->
- io:format("Expand: ~p ...\n", [{Mod, Fun}]),
- Map = fun(Case) when is_atom(Case)-> {Mod, Case};
- (Case) -> Case
- end,
- do_test(lists:map(Map, Cases), Config);
-
- {req, _, {conf, Init, Cases, Finish}} ->
- case (catch apply(Mod, Init, [Config])) of
- Conf when is_list(Conf) ->
- io:format("Expand: ~p ...\n", [{Mod, Fun}]),
- Map = fun(Case) when is_atom(Case)-> {Mod, Case};
- (Case) -> Case
- end,
- Res = do_test(lists:map(Map, Cases), Conf),
- (catch apply(Mod, Finish, [Conf])),
- Res;
-
- {'EXIT', {skipped, Reason}} ->
- io:format(" => skipping: ~p\n", [Reason]),
- [{skipped, {Mod, Fun}, Reason}];
-
- Error ->
- io:format(" => failed: ~p\n", [Error]),
- [{failed, {Mod, Fun}, Error}]
- end;
-
- {'EXIT', {undef, _}} ->
- io:format("Undefined: ~p\n", [{Mod, Fun}]),
- [{nyi, {Mod, Fun}, ok}];
-
- Error ->
- io:format("Ignoring: ~p: ~p\n", [{Mod, Fun}, Error]),
- [{failed, {Mod, Fun}, Error}]
- end;
-do_test(Mod, Config) when is_atom(Mod) ->
- Res = do_test({Mod, all}, Config),
- Res;
-do_test(Cases, Config) when is_list(Cases) ->
- [do_test(Case, Config) || Case <- Cases];
-do_test(Bad, _Config) ->
- [{badarg, Bad, ok}].
-
-eval(Mod, Fun, Config) ->
- TestCase = {?MODULE, Mod, Fun},
- Label = lists:concat(["TEST CASE: ", Fun]),
- et:report_event(40, ?MODULE, Mod, Label ++ " started",
- [TestCase, Config]),
- global:register_name(tftp_test_case_sup, self()),
- Flag = process_flag(trap_exit, true),
- Config2 = Mod:init_per_testcase(Fun, Config),
- Pid = spawn_link(?MODULE, do_eval, [self(), Mod, Fun, Config2]),
- R = wait_for_evaluator(Pid, Mod, Fun, Config2, []),
- Mod:end_per_testcase(Fun, Config2),
- global:unregister_name(tftp_test_case_sup),
- process_flag(trap_exit, Flag),
- R.
-
-wait_for_evaluator(Pid, Mod, Fun, Config, Errors) ->
- TestCase = {?MODULE, Mod, Fun},
- Label = lists:concat(["TEST CASE: ", Fun]),
- receive
- {done, Pid, ok} when Errors == [] ->
- et:report_event(40, Mod, ?MODULE, Label ++ " ok",
- [TestCase, Config]),
- {ok, {Mod, Fun}, Errors};
- {done, Pid, {ok, _}} when Errors == [] ->
- et:report_event(40, Mod, ?MODULE, Label ++ " ok",
- [TestCase, Config]),
- {ok, {Mod, Fun}, Errors};
- {done, Pid, Fail} ->
- et:report_event(20, Mod, ?MODULE, Label ++ " failed",
- [TestCase, Config, {return, Fail}, Errors]),
- {failed, {Mod,Fun}, Fail};
- {'EXIT', Pid, {skipped, Reason}} ->
- et:report_event(20, Mod, ?MODULE, Label ++ " skipped",
- [TestCase, Config, {skipped, Reason}]),
- {skipped, {Mod, Fun}, Errors};
- {'EXIT', Pid, Reason} ->
- et:report_event(20, Mod, ?MODULE, Label ++ " crashed",
- [TestCase, Config, {'EXIT', Reason}]),
- {crashed, {Mod, Fun}, [{'EXIT', Reason} | Errors]};
- {fail, Pid, Reason} ->
- wait_for_evaluator(Pid, Mod, Fun, Config, Errors ++ [Reason])
- end.
-
-do_eval(ReplyTo, Mod, Fun, Config) ->
- case (catch apply(Mod, Fun, [Config])) of
- {'EXIT', {skipped, Reason}} ->
- ReplyTo ! {'EXIT', self(), {skipped, Reason}};
- Other ->
- ReplyTo ! {done, self(), Other}
- end,
- unlink(ReplyTo),
- exit(shutdown).
-
-display_result([]) ->
- io:format("OK\n", []);
-display_result(Res) when is_list(Res) ->
- Ok = [MF || {ok, MF, _} <- Res],
- Nyi = [MF || {nyi, MF, _} <- Res],
- Skipped = [{MF, Reason} || {skipped, MF, Reason} <- Res],
- Failed = [{MF, Reason} || {failed, MF, Reason} <- Res],
- Crashed = [{MF, Reason} || {crashed, MF, Reason} <- Res],
- display_summary(Ok, Nyi, Skipped, Failed, Crashed),
- display_skipped(Skipped),
- display_failed(Failed),
- display_crashed(Crashed).
-
-display_summary(Ok, Nyi, Skipped, Failed, Crashed) ->
- io:format("\nTest case summary:\n", []),
- display_summary(Ok, "successful"),
- display_summary(Nyi, "not yet implemented"),
- display_summary(Skipped, "skipped"),
- display_summary(Failed, "failed"),
- display_summary(Crashed, "crashed"),
- io:format("\n", []).
-
-display_summary(Res, Info) ->
- io:format(" ~w test cases ~s\n", [length(Res), Info]).
-
-display_skipped([]) ->
- ok;
-display_skipped(Skipped) ->
- io:format("Skipped test cases:\n", []),
- F = fun({MF, Reason}) -> io:format(" ~p => ~p\n", [MF, Reason]) end,
- lists:foreach(F, Skipped),
- io:format("\n", []).
-
-
-display_failed([]) ->
- ok;
-display_failed(Failed) ->
- io:format("Failed test cases:\n", []),
- F = fun({MF, Reason}) -> io:format(" ~p => ~p\n", [MF, Reason]) end,
- lists:foreach(F, Failed),
- io:format("\n", []).
-
-display_crashed([]) ->
- ok;
-display_crashed(Crashed) ->
- io:format("Crashed test cases:\n", []),
- F = fun({MF, Reason}) -> io:format(" ~p => ~p\n", [MF, Reason]) end,
- lists:foreach(F, Crashed),
- io:format("\n", []).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% generic callback
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--record(generic_state, {state, prepare, open, read, write, abort}).
-
-prepare(Peer, Access, LocalFilename, Mode, SuggestedOptions, Initial) when is_list(Initial) ->
- State = lookup_option(state, mandatory, Initial),
- Prepare = lookup_option(prepare, mandatory, Initial),
- Open = lookup_option(open, mandatory, Initial),
- Read = lookup_option(read, mandatory, Initial),
- Write = lookup_option(write, mandatory, Initial),
- Abort = lookup_option(abort, mandatory, Initial),
- case Prepare(Peer, Access, LocalFilename, Mode, SuggestedOptions, State) of
- {ok, AcceptedOptions, NewState} ->
- {ok,
- AcceptedOptions,
- #generic_state{state = NewState,
- prepare = Prepare,
- open = Open,
- read = Read,
- write = Write,
- abort = Abort}};
- Other ->
- Other
- end.
-
-open(Peer, Access, LocalFilename, Mode, SuggestedOptions, Initial) when is_list(Initial) ->
- case prepare(Peer, Access, LocalFilename, Mode, SuggestedOptions, Initial) of
- {ok, SuggestedOptions2, GenericState} ->
- open(Peer, Access, LocalFilename, Mode, SuggestedOptions2, GenericState);
- Other ->
- Other
- end;
-open(Peer, Access, LocalFilename, Mode, SuggestedOptions, #generic_state{state = State, open = Open} = GenericState) ->
- case Open(Peer, Access, LocalFilename, Mode, SuggestedOptions, State) of
- {ok, SuggestedOptions2, NewState} ->
- {ok, SuggestedOptions2, GenericState#generic_state{state = NewState}};
- Other ->
- Other
- end.
-
-read(#generic_state{state = State, read = Read} = GenericState) ->
- case Read(State) of
- {more, DataBlock, NewState} ->
- {more, DataBlock, GenericState#generic_state{state = NewState}};
- Other ->
- Other
- end.
-
-write(DataBlock, #generic_state{state = State, write = Write} = GenericState) ->
- case Write(DataBlock, State) of
- {more, NewState} ->
- {more, GenericState#generic_state{state = NewState}};
- Other ->
- Other
- end.
-
-abort(Code, Text, #generic_state{state = State, abort = Abort}) ->
- Abort(Code, Text, State).
-
-lookup_option(Key, Default, Options) ->
- case lists:keysearch(Key, 1, Options) of
- {value, {_, Val}} ->
- Val;
- false ->
- Default
- end.
-
diff --git a/lib/inets/test/tftp_test_lib.hrl b/lib/inets/test/tftp_test_lib.hrl
deleted file mode 100644
index e7a5a37d2c..0000000000
--- a/lib/inets/test/tftp_test_lib.hrl
+++ /dev/null
@@ -1,44 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
--record('REASON', {mod, line, desc}).
-
--define(LOG(Format, Args),
- tftp_test_lib:log(Format, Args, ?MODULE, ?LINE)).
-
--define(ERROR(Reason),
- tftp_test_lib:error(Reason, ?MODULE, ?LINE)).
-
--define(VERIFY(Expected, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- Expected -> ?LOG("Ok, ~p\n", [AcTuAlReS]);
- _ -> ?ERROR(AcTuAlReS)
- end,
- AcTuAlReS
- end()).
-
--define(IGNORE(Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- ?LOG("Ok, ~p\n", [AcTuAlReS]),
- AcTuAlReS
- end()).
diff --git a/lib/inets/test/uri_SUITE.erl b/lib/inets/test/uri_SUITE.erl
index f973296af6..db6a8bdfc3 100644
--- a/lib/inets/test/uri_SUITE.erl
+++ b/lib/inets/test/uri_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -52,6 +52,7 @@ all() ->
escaped,
hexed_query,
scheme_validation,
+ scheme_validation_bin,
encode_decode
].
@@ -273,6 +274,26 @@ scheme_validation(Config) when is_list(Config) ->
http_uri:parse("https://localhost#fragment",
[{scheme_validation_fun, none}]).
+scheme_validation_bin(Config) when is_list(Config) ->
+ {ok, {http,<<>>,<<"localhost">>,80,<<"/">>,<<>>}} =
+ http_uri:parse(<<"http://localhost#fragment">>),
+
+ ValidationFun =
+ fun(<<"http">>) -> valid;
+ (_) -> {error, bad_scheme}
+ end,
+
+ {ok, {http,<<>>,<<"localhost">>,80,<<"/">>,<<>>}} =
+ http_uri:parse(<<"http://localhost#fragment">>,
+ [{scheme_validation_fun, ValidationFun}]),
+ {error, bad_scheme} =
+ http_uri:parse(<<"https://localhost#fragment">>,
+ [{scheme_validation_fun, ValidationFun}]),
+ %% non-fun scheme_validation_fun works as no option passed
+ {ok, {https,<<>>,<<"localhost">>,443,<<"/">>,<<>>}} =
+ http_uri:parse(<<"https://localhost#fragment">>,
+ [{scheme_validation_fun, none}]).
+
encode_decode(Config) when is_list(Config) ->
?assertEqual("foo%20bar", http_uri:encode("foo bar")),
?assertEqual(<<"foo%20bar">>, http_uri:encode(<<"foo bar">>)),
diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk
index 1fad9afe33..5dbec9e7b3 100644
--- a/lib/inets/vsn.mk
+++ b/lib/inets/vsn.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2001-2017. All Rights Reserved.
+# Copyright Ericsson AB 2001-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -19,6 +19,6 @@
# %CopyrightEnd%
APPLICATION = inets
-INETS_VSN = 6.5
+INETS_VSN = 7.0.8
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)"
diff --git a/lib/jinterface/doc/src/Makefile b/lib/jinterface/doc/src/Makefile
index 37de0a35c5..f5cba9d074 100644
--- a/lib/jinterface/doc/src/Makefile
+++ b/lib/jinterface/doc/src/Makefile
@@ -3,7 +3,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2000-2017. All Rights Reserved.
+# Copyright Ericsson AB 2000-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -129,6 +129,7 @@ html: gifs $(HTML_REF_MAN_FILE)
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
@@ -136,6 +137,7 @@ clean clean_docs:
jdoc:$(JAVA_SRC_FILES)
(cd ../../java_src;$(JAVADOC) -sourcepath . -d $(JAVADOC_DEST) \
-windowtitle $(JAVADOC_TITLE) $(JAVADOC_PKGS))
+ touch jdoc
man:
@@ -151,15 +153,8 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
$(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
$(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
- $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
- $(INSTALL_DIR) "$(RELSYSDIR)/doc/html/java/$(JAVA_PKG_PATH)"
$(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
- ($(CP) -rf ../html "$(RELSYSDIR)/doc")
-
-# $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \
-# "$(RELSYSDIR)/doc/html"
-# $(INSTALL_DATA) $(JAVA_EXTRA_FILES) "$(RELSYSDIR)/doc/html/java"
-# $(INSTALL_DATA) $(TOP_HTML_FILES) "$(RELSYSDIR)/doc"
+ $(INSTALL_DIR_DATA) $(HTMLDIR) "$(RELSYSDIR)/doc/html"
release_spec:
diff --git a/lib/jinterface/doc/src/jinterface_users_guide.xml b/lib/jinterface/doc/src/jinterface_users_guide.xml
index 56f88124bf..504c77f339 100644
--- a/lib/jinterface/doc/src/jinterface_users_guide.xml
+++ b/lib/jinterface/doc/src/jinterface_users_guide.xml
@@ -366,20 +366,20 @@ OtpNode node = new OtpNode("gurka"); </code>
<seealso marker="java/com/ericsson/otp/erlang/OtpEpmd">OtpEpmd</seealso> class.
Nodes wishing to contact other nodes must first request information
from Epmd before a connection can be set up, however this is done automatically
- by <seealso marker="java/com/ericsson/otp/erlang/OtpSelf#connect(com.ericsson.otp.erlang.OtpPeer)">OtpSelf.connect()</seealso> when necessary. </p>
- <p>When you use <seealso marker="java/com/ericsson/otp/erlang/OtpSelf#connect(com.ericsson.otp.erlang.OtpPeer)">OtpSelf.connect()</seealso> to connect to an Erlang node,
+ by <seealso marker="java/com/ericsson/otp/erlang/OtpSelf#connect-com.ericsson.otp.erlang.OtpPeer-">OtpSelf.connect()</seealso> when necessary. </p>
+ <p>When you use <seealso marker="java/com/ericsson/otp/erlang/OtpSelf#connect-com.ericsson.otp.erlang.OtpPeer-">OtpSelf.connect()</seealso> to connect to an Erlang node,
a connection is first made to epmd and, if the node is known, a
connection is then made to the Erlang node.</p>
<p>Java nodes can also register themselves with epmd if they want other
nodes in the system to be able to find and connect to them.
- This is done by call to method <seealso marker="java/com/ericsson/otp/erlang/OtpEpmd#publishPort(com.ericsson.otp.erlang.OtpLocalNode)">OtpEpmd.publishPort()</seealso>.</p>
+ This is done by call to method <seealso marker="java/com/ericsson/otp/erlang/OtpEpmd#publishPort-com.ericsson.otp.erlang.OtpLocalNode-">OtpEpmd.publishPort()</seealso>.</p>
<p>Be aware that on some systems (such as VxWorks), a failed node will
not be detected by this mechanism since the operating system does not
automatically close descriptors that were left open when the node
failed. If a node has failed in this way, epmd will prevent you from
registering a new node with the old name, since it thinks that the old
name is still in use. In this case, you must unregister the name
- explicitly, by using <seealso marker="java/com/ericsson/otp/erlang/OtpEpmd#unPublishPort(com.ericsson.otp.erlang.OtpLocalNode)">OtpEpmd.unPublishPort()</seealso></p>
+ explicitly, by using <seealso marker="java/com/ericsson/otp/erlang/OtpEpmd#unPublishPort-com.ericsson.otp.erlang.OtpLocalNode-">OtpEpmd.unPublishPort()</seealso></p>
<p>This will cause epmd to close the connection from the far end. Note
that if the name was in fact still in use by a node, the results of
this operation are unpredictable. Also, doing this does not cause the
diff --git a/lib/jinterface/doc/src/notes.xml b/lib/jinterface/doc/src/notes.xml
index 346d467c2d..e79ada47f1 100644
--- a/lib/jinterface/doc/src/notes.xml
+++ b/lib/jinterface/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2000</year><year>2017</year>
+ <year>2000</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,6 +31,72 @@
</header>
<p>This document describes the changes made to the Jinterface application.</p>
+<section><title>Jinterface 1.10</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ All incorrect (that is, all) uses of "can not" has been
+ corrected to "cannot" in source code comments,
+ documentation, examples, and so on.</p>
+ <p>
+ Own Id: OTP-14282 Aux Id: PR-1891 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>Added support to receive export funs (<c>fun
+ M:F/A</c>).</p>
+ <p>Before this change, export funs sent to a jinterface
+ node were encoded using an undocumented fallback tuple
+ format <c>{M,F}</c>. Existing jinterface implementations
+ expecting these tuples must be changed to instead use the
+ existing <c>OtpErlangExternalFun</c> class.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15774 Aux Id: OTP-15712 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Jinterface 1.9.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Jinterface 1.9</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Add module package name for Java 9</p>
+ <p>
+ Own Id: OTP-14844</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Jinterface 1.8.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -690,7 +756,7 @@
<item>
<p><c>OtpMbox.receive()</c> and <c>OtpMbox.receive(long timeout)</c> can now throw
<c>OtpErlangDecodeException</c> if the received message
- can not be decoded. <c>null</c> is now only returned from
+ cannot be decoded. <c>null</c> is now only returned from
<c>OtpMbox.receive(long timeout)</c> if a timeout occurs.
<c>OtpMbox.receive()</c> will never return <c>null</c>.</p>
<p>*** POTENTIAL INCOMPATIBILITY ***</p>
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/AbstractNode.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/AbstractNode.java
index 222330654a..c3f71a84f0 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/AbstractNode.java
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/AbstractNode.java
@@ -89,7 +89,7 @@ public class AbstractNode implements OtpTransportFactory {
static final int dFlagHiddenAtomCache = 0x40; // NOT SUPPORTED
static final int dflagNewFunTags = 0x80;
static final int dFlagExtendedPidsPorts = 0x100;
- static final int dFlagExportPtrTag = 0x200; // NOT SUPPORTED
+ static final int dFlagExportPtrTag = 0x200;
static final int dFlagBitBinaries = 0x400;
static final int dFlagNewFloats = 0x800;
static final int dFlagUnicodeIo = 0x1000;
@@ -105,6 +105,7 @@ public class AbstractNode implements OtpTransportFactory {
int flags = dFlagExtendedReferences | dFlagExtendedPidsPorts
| dFlagBitBinaries | dFlagNewFloats | dFlagFunTags
| dflagNewFunTags | dFlagUtf8Atoms | dFlagMapTag
+ | dFlagExportPtrTag
| dFlagBigCreation;
/* initialize hostname and default cookie */
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile b/lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile
index 001acfdd2e..ee616f3d7e 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile
@@ -3,7 +3,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2000-2016. All Rights Reserved.
+# Copyright Ericsson AB 2000-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpEpmd.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpEpmd.java
index 363fdb950a..fffb8475d3 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpEpmd.java
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpEpmd.java
@@ -102,7 +102,7 @@ public class OtpEpmd {
/**
* Set the port number to be used to contact the epmd process. Only needed
* when the default port is not desired and system environment variable
- * ERL_EPMD_PORT can not be read (applet).
+ * ERL_EPMD_PORT cannot be read (applet).
*/
public static void useEpmdPort(final int port) {
EpmdPort.set(port);
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpInputStream.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpInputStream.java
index ded8f6e1e5..6d81ce630b 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpInputStream.java
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpInputStream.java
@@ -601,7 +601,7 @@ public class OtpInputStream extends ByteArrayInputStream {
* @return the integer value.
*
* @exception OtpErlangDecodeException
- * if the next term in the stream can not be represented as a
+ * if the next term in the stream cannot be represented as a
* positive integer.
*/
public int read_uint() throws OtpErlangDecodeException {
@@ -622,7 +622,7 @@ public class OtpInputStream extends ByteArrayInputStream {
* @return the integer value.
*
* @exception OtpErlangDecodeException
- * if the next term in the stream can not be represented as
+ * if the next term in the stream cannot be represented as
* an integer.
*/
public int read_int() throws OtpErlangDecodeException {
@@ -643,7 +643,7 @@ public class OtpInputStream extends ByteArrayInputStream {
* @return the short value.
*
* @exception OtpErlangDecodeException
- * if the next term in the stream can not be represented as a
+ * if the next term in the stream cannot be represented as a
* positive short.
*/
public short read_ushort() throws OtpErlangDecodeException {
@@ -664,7 +664,7 @@ public class OtpInputStream extends ByteArrayInputStream {
* @return the short value.
*
* @exception OtpErlangDecodeException
- * if the next term in the stream can not be represented as a
+ * if the next term in the stream cannot be represented as a
* short.
*/
public short read_short() throws OtpErlangDecodeException {
@@ -685,7 +685,7 @@ public class OtpInputStream extends ByteArrayInputStream {
* @return the long value.
*
* @exception OtpErlangDecodeException
- * if the next term in the stream can not be represented as a
+ * if the next term in the stream cannot be represented as a
* positive long.
*/
public long read_ulong() throws OtpErlangDecodeException {
@@ -698,7 +698,7 @@ public class OtpInputStream extends ByteArrayInputStream {
* @return the long value.
*
* @exception OtpErlangDecodeException
- * if the next term in the stream can not be represented as a
+ * if the next term in the stream cannot be represented as a
* long.
*/
public long read_long() throws OtpErlangDecodeException {
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java
index 42e178c3f6..29a8bc1540 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java
@@ -156,7 +156,7 @@ public class OtpMbox {
* of the next message waiting in this mailbox.
*
* @exception OtpErlangDecodeException
- * if the message can not be decoded.
+ * if the message cannot be decoded.
*
* @exception OtpErlangExit
* if a linked {@link OtpErlangPid pid} has exited or has
@@ -184,7 +184,7 @@ public class OtpMbox {
* of the next message waiting in this mailbox.
*
* @exception OtpErlangDecodeException
- * if the message can not be decoded.
+ * if the message cannot be decoded.
*
* @exception OtpErlangExit
* if a linked {@link OtpErlangPid pid} has exited or has
diff --git a/lib/jinterface/java_src/pom.xml.src b/lib/jinterface/java_src/pom.xml.src
index 98232db78c..584bd81076 100644
--- a/lib/jinterface/java_src/pom.xml.src
+++ b/lib/jinterface/java_src/pom.xml.src
@@ -76,6 +76,17 @@
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifestEntries>
+ <Automatic-Module-Name>com.ericsson.otp.erlang</Automatic-Module-Name>
+ </manifestEntries>
+ </archive>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<executions>
diff --git a/lib/jinterface/test/jinterface_SUITE.erl b/lib/jinterface/test/jinterface_SUITE.erl
index 8c6a6368a9..468981a557 100644
--- a/lib/jinterface/test/jinterface_SUITE.erl
+++ b/lib/jinterface/test/jinterface_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/jinterface/test/nc_SUITE.erl b/lib/jinterface/test/nc_SUITE.erl
index 81944f71d4..7833d070b7 100644
--- a/lib/jinterface/test/nc_SUITE.erl
+++ b/lib/jinterface/test/nc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -142,7 +142,8 @@ fun_roundtrip(Config) when is_list(Config)->
do_echo([fun(A, B) -> A + B end,
fun(A) -> lists:reverse(A) end,
fun() -> ok end,
- fun fun_roundtrip/1],
+ fun fun_roundtrip/1,
+ fun ?MODULE:fun_roundtrip/1],
Config).
port_roundtrip(doc) -> [];
@@ -651,11 +652,10 @@ do_echo(DataList, Config, OutTrans, InTrans, ExtraArgs)
echo_loop([D|Ds], Echoer, OutTrans, InTrans, TermAcc) ->
OutMsg = OutTrans(D),
Echoer ! OutMsg,
- io:format("echo_server ~p: ~p ! ~P~n", [self(),Echoer,OutMsg,10]),
+ %%io:format("echo_server ~p: ~p ! ~P~n", [self(),Echoer,OutMsg,10]),
receive
Reply ->
- io:format("echo_server ~p: receive ~P~n",
- [self(),Reply,10]),
+ %%io:format("echo_server ~p: receive ~P~n", [self(),Reply,10]),
InTrans(Echoer, D, Reply)
end,
Term = case OutMsg of
@@ -670,11 +670,10 @@ echo_loop(Cont, Echoer, OutTrans, InTrans, TermAcc)
when is_function(Cont, 0) ->
check_terms(Echoer, TermAcc),
OutMsg = Echoer ! {self(),undefined,hash_clear},
- io:format("echo_server ~p: ~p ! ~P~n", [self(),Echoer,OutMsg,10]),
+ %%io:format("echo_server ~p: ~p ! ~P~n", [self(),Echoer,OutMsg,10]),
receive
{Echoer,hash_cleared,hash_clear}=Reply ->
- io:format("echo_server ~p: receive ~P~n",
- [self(),Reply,10]),
+ %%io:format("echo_server ~p: receive ~P~n", [self(),Reply,10]),
ok;
Other ->
io:format("echo_server_terms unexpected ~p: receive ~P~n",
@@ -686,11 +685,10 @@ echo_loop(Cont, Echoer, OutTrans, InTrans, TermAcc)
check_terms(Echoer, [Term | Rest]) ->
OutMsg = {self(),Term,hash_lookup},
Echoer ! OutMsg,
- io:format("check_terms ~p: ~p ! ~P~n", [self(),Echoer,OutMsg,10]),
+ %%io:format("check_terms ~p: ~p ! ~P~n", [self(),Echoer,OutMsg,10]),
receive
{Echoer,true,hash_lookup} = ReplyMsg ->
- io:format("check_terms ~p: receive ~P~n",
- [self(),ReplyMsg,10]),
+ %%io:format("check_terms ~p: receive ~P~n", [self(),ReplyMsg,10]),
check_terms(Echoer, Rest);
Other ->
io:format("check_terms unexpected ~p: receive ~P~n",
diff --git a/lib/jinterface/vsn.mk b/lib/jinterface/vsn.mk
index 0a8a1190ec..95c7c95726 100644
--- a/lib/jinterface/vsn.mk
+++ b/lib/jinterface/vsn.mk
@@ -1 +1 @@
-JINTERFACE_VSN = 1.8.1
+JINTERFACE_VSN = 1.10
diff --git a/lib/kernel/doc/src/.gitignore b/lib/kernel/doc/src/.gitignore
new file mode 100644
index 0000000000..c2813ac866
--- /dev/null
+++ b/lib/kernel/doc/src/.gitignore
@@ -0,0 +1 @@
+*.eps \ No newline at end of file
diff --git a/lib/kernel/doc/src/Makefile b/lib/kernel/doc/src/Makefile
index 0759f362d4..f8867ccf25 100644
--- a/lib/kernel/doc/src/Makefile
+++ b/lib/kernel/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -42,6 +42,7 @@ XML_REF3_FILES = application.xml \
disk_log.xml \
erl_boot_server.xml \
erl_ddll.xml \
+ erl_epmd.xml \
erl_prim_loader_stub.xml \
erlang_stub.xml \
error_handler.xml \
@@ -56,6 +57,11 @@ XML_REF3_FILES = application.xml \
inet.xml \
inet_res.xml \
init_stub.xml \
+ logger.xml \
+ logger_std_h.xml \
+ logger_disk_log_h.xml \
+ logger_filters.xml \
+ logger_formatter.xml \
net_adm.xml \
net_kernel.xml \
os.xml \
@@ -70,11 +76,18 @@ XML_REF4_FILES = app.xml config.xml
XML_REF6_FILES = kernel_app.xml
-XML_PART_FILES =
-XML_CHAPTER_FILES = notes.xml
+XML_PART_FILES = part.xml
+XML_CHAPTER_FILES = \
+ notes.xml \
+ introduction_chapter.xml \
+ logger_chapter.xml
BOOK_FILES = book.xml
+# The .png file is generated from a .dia file with target 'update_png'
+IMAGE_FILES = \
+ logger_arch.png
+
XML_FILES = \
$(BOOK_FILES) $(XML_CHAPTER_FILES) \
$(XML_PART_FILES) $(XML_REF3_FILES) $(XML_REF4_FILES)\
@@ -100,6 +113,17 @@ SPECS_FILES = $(XML_REF3_FILES:%.xml=$(SPECDIR)/specs_%.xml)
TOP_SPECS_FILE = specs.xml
# ----------------------------------------------------
+# FIGURES
+# ----------------------------------------------------
+# In order to update the figures you have to have both dia
+# and imagemagick installed.
+# The generated .png file must be committed.
+
+update_png:
+ dia --export=logger_arch.eps logger_arch.dia
+ convert logger_arch.eps -resize 65% logger_arch.png
+
+# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
XML_FLAGS +=
@@ -111,7 +135,7 @@ SPECS_FLAGS = -I../../include
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
-$(HTMLDIR)/%.gif: %.gif
+$(HTMLDIR)/%: %
$(INSTALL_DATA) $< $@
docs: man pdf html
@@ -120,33 +144,35 @@ $(TOP_PDF_FILE): $(XML_FILES)
pdf: $(TOP_PDF_FILE)
-html: gifs $(HTML_REF_MAN_FILE)
+html: images $(HTML_REF_MAN_FILE)
man: $(MAN3_FILES) $(MAN4_FILES) $(MAN6_FILES)
-gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
+images: $(IMAGE_FILES:%=$(HTMLDIR)/%)
+
debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(MAN4DIR)/*
rm -f $(MAN6DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f $(SPECDIR)/*
- rm -f errs core *~
+ rm -f errs core *~ *.eps
$(SPECDIR)/specs_erl_prim_loader_stub.xml:
- escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \
+ $(gen_verbose)escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \
-o$(dir $@) -module erl_prim_loader_stub
$(SPECDIR)/specs_erlang_stub.xml:
- escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \
+ $(gen_verbose)escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \
-o$(dir $@) -module erlang_stub
$(SPECDIR)/specs_init_stub.xml:
- escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \
+ $(gen_verbose)escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \
-o$(dir $@) -module init_stub
$(SPECDIR)/specs_zlib_stub.xml:
- escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \
+ $(gen_verbose)escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \
-o$(dir $@) -module zlib_stub
# ----------------------------------------------------
diff --git a/lib/kernel/doc/src/application.xml b/lib/kernel/doc/src/application.xml
index 886286b76d..f4ec2c610f 100644
--- a/lib/kernel/doc/src/application.xml
+++ b/lib/kernel/doc/src/application.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>application</module>
+ <module since="">application</module>
<modulesummary>Generic OTP application functions</modulesummary>
<description>
<p>In OTP, <em>application</em> denotes a component implementing
@@ -67,8 +67,8 @@
</datatypes>
<funcs>
<func>
- <name name="ensure_all_started" arity="1"/>
- <name name="ensure_all_started" arity="2"/>
+ <name name="ensure_all_started" arity="1" since="OTP R16B02"/>
+ <name name="ensure_all_started" arity="2" since="OTP R16B02"/>
<fsummary>Load and start an application and its dependencies, recursively.</fsummary>
<desc>
<p>Equivalent to calling
@@ -85,8 +85,8 @@
</desc>
</func>
<func>
- <name name="ensure_started" arity="1"/>
- <name name="ensure_started" arity="2"/>
+ <name name="ensure_started" arity="1" since="OTP R16B01"/>
+ <name name="ensure_started" arity="2" since="OTP R16B01"/>
<fsummary>Load and start an application.</fsummary>
<desc>
<p>Equivalent to
@@ -95,8 +95,8 @@
</desc>
</func>
<func>
- <name name="get_all_env" arity="0"/>
- <name name="get_all_env" arity="1"/>
+ <name name="get_all_env" arity="0" since=""/>
+ <name name="get_all_env" arity="1" since=""/>
<fsummary>Get the configuration parameters for an application.</fsummary>
<desc>
<p>Returns the configuration parameters and their values for
@@ -108,8 +108,8 @@
</desc>
</func>
<func>
- <name name="get_all_key" arity="0"/>
- <name name="get_all_key" arity="1"/>
+ <name name="get_all_key" arity="0" since=""/>
+ <name name="get_all_key" arity="1" since=""/>
<fsummary>Get the application specification keys.</fsummary>
<desc>
<p>Returns the application specification keys and their values
@@ -122,8 +122,8 @@
</desc>
</func>
<func>
- <name name="get_application" arity="0"/>
- <name name="get_application" arity="1"/>
+ <name name="get_application" arity="0" since=""/>
+ <name name="get_application" arity="1" since=""/>
<fsummary>Get the name of an application containing a certain process or module.</fsummary>
<desc>
<p>Returns the name of the application to which the process
@@ -136,8 +136,8 @@
</desc>
</func>
<func>
- <name name="get_env" arity="1"/>
- <name name="get_env" arity="2"/>
+ <name name="get_env" arity="1" since=""/>
+ <name name="get_env" arity="2" since=""/>
<fsummary>Get the value of a configuration parameter.</fsummary>
<desc>
<p>Returns the value of configuration parameter <c><anno>Par</anno></c>
@@ -153,7 +153,7 @@
</desc>
</func>
<func>
- <name name="get_env" arity="3"/>
+ <name name="get_env" arity="3" since="OTP R16B"/>
<fsummary>Get the value of a configuration parameter using a default.</fsummary>
<desc>
<p>Works like <seealso marker="#get_env/2"><c>get_env/2</c></seealso> but returns
@@ -162,8 +162,8 @@
</desc>
</func>
<func>
- <name name="get_key" arity="1"/>
- <name name="get_key" arity="2"/>
+ <name name="get_key" arity="1" since=""/>
+ <name name="get_key" arity="2" since=""/>
<fsummary>Get the value of an application specification key.</fsummary>
<desc>
<p>Returns the value of the application specification key
@@ -180,8 +180,8 @@
</desc>
</func>
<func>
- <name name="load" arity="1"/>
- <name name="load" arity="2"/>
+ <name name="load" arity="1" since=""/>
+ <name name="load" arity="2" since=""/>
<fsummary>Load an application.</fsummary>
<type name="application_spec"/>
<type name="application_opt"/>
@@ -226,7 +226,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</desc>
</func>
<func>
- <name name="loaded_applications" arity="0"/>
+ <name name="loaded_applications" arity="0" since=""/>
<fsummary>Get the currently loaded applications.</fsummary>
<desc>
<p>Returns a list with information about the applications, and included
@@ -238,7 +238,42 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</desc>
</func>
<func>
- <name name="permit" arity="2"/>
+ <name name="set_env" arity="1" since="OTP 21.3"/>
+ <name name="set_env" arity="2" since="OTP 21.3"/>
+ <fsummary>Sets the configuration parameters of multiple applications.</fsummary>
+ <desc>
+ <p>Sets the configuration <c><anno>Config</anno></c> for multiple
+ applications. It is equivalent to calling <c>set_env/4</c> on
+ each application individially, except it is more efficient.
+ The given <c><anno>Config</anno></c> is validated before the
+ configuration is set.</p>
+ <p><c>set_env/2</c> uses the standard <c>gen_server</c> time-out
+ value (5000 ms). Option <c>timeout</c> can be specified
+ if another time-out value is useful, for example, in situations
+ where the application controller is heavily loaded.</p>
+ <p>Option <c>persistent</c> can be set to <c>true</c>
+ to guarantee that parameters set with <c>set_env/2</c>
+ are not overridden by those defined in the application resource
+ file on load. This means that persistent values will stick after the application
+ is loaded and also on application reload.</p>
+ <p>If an application is given more than once or if an application
+ has the same key given more than once, the behaviour is undefined
+ and a warning message will be logged. In future releases, an error
+ will be raised.</p>
+ <p><c>set_env/1</c> is equivalent to <c>set_env(Config, [])</c>.</p>
+ <warning>
+ <p>Use this function only if you know what you are doing,
+ that is, on your own applications. It is very
+ application-dependent and
+ configuration parameter-dependent when and how often
+ the value is read by the application. Careless use
+ of this function can put the application in a
+ weird, inconsistent, and malfunctioning state.</p>
+ </warning>
+ </desc>
+ </func>
+ <func>
+ <name name="permit" arity="2" since=""/>
<fsummary>Change the permission for an application to run at a node.</fsummary>
<desc>
<p>Changes the permission for <c><anno>Application</anno></c> to run at
@@ -271,8 +306,8 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</desc>
</func>
<func>
- <name name="set_env" arity="3"/>
- <name name="set_env" arity="4"/>
+ <name name="set_env" arity="3" since=""/>
+ <name name="set_env" arity="4" since=""/>
<fsummary>Set the value of a configuration parameter.</fsummary>
<desc>
<p>Sets the value of configuration parameter <c><anno>Par</anno></c> for
@@ -302,8 +337,8 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</desc>
</func>
<func>
- <name name="start" arity="1"/>
- <name name="start" arity="2"/>
+ <name name="start" arity="1" since=""/>
+ <name name="start" arity="2" since=""/>
<fsummary>Load and start an application.</fsummary>
<desc>
<p>Starts <c><anno>Application</anno></c>. If it is not loaded,
@@ -318,8 +353,13 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
<c>{error,{not_started,App}}</c> is returned, where <c>App</c>
is the name of the missing application.</p>
<p>The application controller then creates an <em>application master</em>
- for the application. The application master is
- the group leader of all the processes in the application.
+ for the application. The application master becomes the
+ group leader of all the processes in the application. I/O is
+ forwarded to the previous group leader, though, this is just
+ a way to identify processes that belong to the application.
+ Used for example to find itself from any process, or,
+ reciprocally, to kill them all when it terminates.</p>
+ <p>
The application master starts the application by calling
the application callback function <c>Module:start/2</c> as
defined by the application specification key <c>mod</c>.</p>
@@ -348,7 +388,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</desc>
</func>
<func>
- <name name="start_type" arity="0"/>
+ <name name="start_type" arity="0" since=""/>
<fsummary>Get the start type of an ongoing application startup.</fsummary>
<desc>
<p>This function is intended to be called by a process belonging
@@ -365,7 +405,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</desc>
</func>
<func>
- <name name="stop" arity="1"/>
+ <name name="stop" arity="1" since=""/>
<fsummary>Stop an application.</fsummary>
<desc>
<p>Stops <c><anno>Application</anno></c>. The application master calls
@@ -394,7 +434,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</desc>
</func>
<func>
- <name name="takeover" arity="2"/>
+ <name name="takeover" arity="2" since=""/>
<fsummary>Take over a distributed application.</fsummary>
<desc>
<p>Takes over the distributed application
@@ -419,7 +459,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</desc>
</func>
<func>
- <name name="unload" arity="1"/>
+ <name name="unload" arity="1" since=""/>
<fsummary>Unload an application.</fsummary>
<desc>
<p>Unloads the application specification for <c><anno>Application</anno></c>
@@ -430,8 +470,8 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</desc>
</func>
<func>
- <name name="unset_env" arity="2"/>
- <name name="unset_env" arity="3"/>
+ <name name="unset_env" arity="2" since=""/>
+ <name name="unset_env" arity="3" since=""/>
<fsummary>Unset the value of a configuration parameter.</fsummary>
<desc>
<p>Removes the configuration parameter <c><anno>Par</anno></c> and its value
@@ -454,8 +494,8 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</desc>
</func>
<func>
- <name name="which_applications" arity="0"/>
- <name name="which_applications" arity="1"/>
+ <name name="which_applications" arity="0" since=""/>
+ <name name="which_applications" arity="1" since=""/>
<fsummary>Get the currently running applications.</fsummary>
<desc>
<p>Returns a list with information about the applications that
@@ -479,7 +519,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</section>
<funcs>
<func>
- <name>Module:start(StartType, StartArgs) -> {ok, Pid} | {ok, Pid, State} | {error, Reason}</name>
+ <name since="">Module:start(StartType, StartArgs) -> {ok, Pid} | {ok, Pid, State} | {error, Reason}</name>
<fsummary>Start an application.</fsummary>
<type>
<v>StartType = <seealso marker="#type-start_type"><c>start_type()</c></seealso></v>
@@ -521,7 +561,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</desc>
</func>
<func>
- <name>Module:start_phase(Phase, StartType, PhaseArgs) -> ok | {error, Reason}</name>
+ <name since="">Module:start_phase(Phase, StartType, PhaseArgs) -> ok | {error, Reason}</name>
<fsummary>Extended start of an application.</fsummary>
<type>
<v>Phase = atom()</v>
@@ -542,11 +582,11 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
the primary application) for the primary application and all
included applications, for which the start phase is defined.</p>
<p>For a description of <c>StartType</c>, see
- <seealso marker="Module:start/2"><c>Module:start/2</c></seealso>.</p>
+ <seealso marker="#Module:start/2"><c>Module:start/2</c></seealso>.</p>
</desc>
</func>
<func>
- <name>Module:prep_stop(State) -> NewState</name>
+ <name since="">Module:prep_stop(State) -> NewState</name>
<fsummary>Prepare an application for termination.</fsummary>
<type>
<v>State = NewState = term()</v>
@@ -564,7 +604,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</desc>
</func>
<func>
- <name>Module:stop(State)</name>
+ <name since="">Module:stop(State)</name>
<fsummary>Clean up after termination of an application.</fsummary>
<type>
<v>State = term()</v>
@@ -580,7 +620,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
</desc>
</func>
<func>
- <name>Module:config_change(Changed, New, Removed) -> ok</name>
+ <name since="">Module:config_change(Changed, New, Removed) -> ok</name>
<fsummary>Update the configuration parameters for an application.</fsummary>
<type>
<v>Changed = [{Par,Val}]</v>
@@ -608,4 +648,3 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
<seealso marker="app">app(4)</seealso></p>
</section>
</erlref>
-
diff --git a/lib/kernel/doc/src/auth.xml b/lib/kernel/doc/src/auth.xml
index 5901446960..c735d02fed 100644
--- a/lib/kernel/doc/src/auth.xml
+++ b/lib/kernel/doc/src/auth.xml
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>auth</module>
+ <module since="">auth</module>
<modulesummary>Erlang network authentication server.</modulesummary>
<description>
<p>This module is deprecated. For a description of the Magic
@@ -42,28 +42,28 @@
</datatypes>
<funcs>
<func>
- <name name="cookie" arity="0"/>
+ <name name="cookie" arity="0" since=""/>
<fsummary>Magic cookie for local node (deprecated).</fsummary>
<desc>
<p>Use
- <seealso marker="erts:erlang#erlang:get_cookie/0"><c>erlang:get_cookie()</c></seealso>
+ <seealso marker="erts:erlang#get_cookie/0"><c>erlang:get_cookie()</c></seealso>
in ERTS instead.</p>
</desc>
</func>
<func>
- <name name="cookie" arity="1"/>
+ <name name="cookie" arity="1" since=""/>
<fsummary>Set the magic for the local node (deprecated).</fsummary>
<type_desc variable="TheCookie">
The cookie can also be specified as a list with a single atom element.
</type_desc>
<desc>
<p>Use
- <seealso marker="erts:erlang#erlang:set_cookie/2"><c>erlang:set_cookie(node(), <anno>Cookie</anno>)</c>
+ <seealso marker="erts:erlang#set_cookie/2"><c>erlang:set_cookie(node(), <anno>Cookie</anno>)</c>
in ERTS</seealso> instead.</p>
</desc>
</func>
<func>
- <name name="is_auth" arity="1"/>
+ <name name="is_auth" arity="1" since=""/>
<fsummary>Status of communication authorization (deprecated).</fsummary>
<desc>
<p>Returns <c>yes</c> if communication with <c><anno>Node</anno></c> is
@@ -76,7 +76,7 @@
</desc>
</func>
<func>
- <name>node_cookie([Node, Cookie]) -> yes | no</name>
+ <name since="">node_cookie([Node, Cookie]) -> yes | no</name>
<fsummary>Set the magic cookie for a node and verify authorization (deprecated).</fsummary>
<type>
<v>Node = node()</v>
@@ -88,13 +88,13 @@
</desc>
</func>
<func>
- <name name="node_cookie" arity="2"/>
+ <name name="node_cookie" arity="2" since=""/>
<fsummary>Set the magic cookie for a node and verify authorization (deprecated).</fsummary>
<desc>
<p>Sets the magic cookie of <c><anno>Node</anno></c> to
<c><anno>Cookie</anno></c> and verifies the status of the authorization.
Equivalent to calling
- <seealso marker="erts:erlang#erlang:set_cookie/2"><c>erlang:set_cookie(<anno>Node</anno>, <anno>Cookie</anno>)</c></seealso>, followed by
+ <seealso marker="erts:erlang#set_cookie/2"><c>erlang:set_cookie(<anno>Node</anno>, <anno>Cookie</anno>)</c></seealso>, followed by
<seealso marker="#is_auth/1"><c>auth:is_auth(<anno>Node</anno>)</c></seealso>.</p>
</desc>
</func>
diff --git a/lib/kernel/doc/src/book.xml b/lib/kernel/doc/src/book.xml
index 81a87d126d..4b3573b9fe 100644
--- a/lib/kernel/doc/src/book.xml
+++ b/lib/kernel/doc/src/book.xml
@@ -4,7 +4,7 @@
<book xmlns:xi="http://www.w3.org/2001/XInclude">
<header titlestyle="normal">
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -34,6 +34,9 @@
<preamble>
<contents level="2"></contents>
</preamble>
+ <parts lift="yes">
+ <xi:include href="part.xml"/>
+ </parts>
<applications>
<xi:include href="ref_man.xml"/>
</applications>
diff --git a/lib/kernel/doc/src/code.xml b/lib/kernel/doc/src/code.xml
index c94f612c01..4aa9e8b9d2 100644
--- a/lib/kernel/doc/src/code.xml
+++ b/lib/kernel/doc/src/code.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -28,32 +28,34 @@
<date></date>
<rev></rev>
</header>
- <module>code</module>
+ <module since="">code</module>
<modulesummary>Erlang code server.</modulesummary>
<description>
<p>This module contains the interface to the Erlang
<em>code server</em>, which deals with the loading of compiled
code into a running Erlang runtime system.</p>
- <p>The runtime system can be started in <em>embedded</em> or
- <em>interactive</em> mode. Which one is decided by command-line
+ <p>The runtime system can be started in <em>interactive</em> or
+ <em>embedded</em> mode. Which one is decided by the command-line
flag <c>-mode</c>:</p>
<pre>
% <input>erl -mode interactive</input></pre>
<p>The modes are as follows:</p>
<list type="bulleted">
<item>
- <p>In embedded mode, all code is loaded during system startup
- according to the boot script. (Code can also be loaded later
- by explicitly ordering the code server to do so).</p>
- </item>
- <item>
<p>In interactive mode, which is default, only some code is loaded
- during system startup, basically the modules needed by the runtime
+ during system startup, basically the modules needed by the runtime
system. Other code is dynamically loaded when first
referenced. When a call to a function in a certain module is
made, and the module is not loaded, the code server searches
for and tries to load the module.</p>
</item>
+ <item>
+ <p>In embedded mode, modules are not auto loaded. Trying to use
+ a module that has not been loaded results in an error. This mode is
+ recommended when the boot script loads all modules, as it is
+ typically done in OTP releases. (Code can still be loaded later
+ by explicitly ordering the code server to do so).</p>
+ </item>
</list>
<p>To prevent accidentally reloading of modules affecting the Erlang
runtime system, directories <c>kernel</c>, <c>stdlib</c>,
@@ -320,7 +322,7 @@ zip:create("mnesia-4.4.7.ez",
<funcs>
<func>
- <name name="set_path" arity="1"/>
+ <name name="set_path" arity="1" since=""/>
<fsummary>Set the code server search path.</fsummary>
<desc>
<p>Sets the code path to the list of directories <c><anno>Path</anno></c>.</p>
@@ -334,15 +336,15 @@ zip:create("mnesia-4.4.7.ez",
</desc>
</func>
<func>
- <name name="get_path" arity="0"/>
+ <name name="get_path" arity="0" since=""/>
<fsummary>Return the code server search path.</fsummary>
<desc>
<p>Returns the code path.</p>
</desc>
</func>
<func>
- <name name="add_path" arity="1"/>
- <name name="add_pathz" arity="1"/>
+ <name name="add_path" arity="1" since=""/>
+ <name name="add_pathz" arity="1" since=""/>
<fsummary>Add a directory to the end of the code path.</fsummary>
<type name="add_path_ret"/>
<desc>
@@ -355,7 +357,7 @@ zip:create("mnesia-4.4.7.ez",
</desc>
</func>
<func>
- <name name="add_patha" arity="1"/>
+ <name name="add_patha" arity="1" since=""/>
<fsummary>Add a directory to the beginning of the code path.</fsummary>
<type name="add_path_ret"/>
<desc>
@@ -368,8 +370,8 @@ zip:create("mnesia-4.4.7.ez",
</desc>
</func>
<func>
- <name name="add_paths" arity="1"/>
- <name name="add_pathsz" arity="1"/>
+ <name name="add_paths" arity="1" since=""/>
+ <name name="add_pathsz" arity="1" since=""/>
<fsummary>Add directories to the end of the code path.</fsummary>
<desc>
<p>Adds the directories in <c><anno>Dirs</anno></c> to the end of the code
@@ -379,7 +381,7 @@ zip:create("mnesia-4.4.7.ez",
</desc>
</func>
<func>
- <name name="add_pathsa" arity="1"/>
+ <name name="add_pathsa" arity="1" since=""/>
<fsummary>Add directories to the beginning of the code path.</fsummary>
<desc>
<p>Traverses <c><anno>Dirs</anno></c> and adds
@@ -395,7 +397,7 @@ zip:create("mnesia-4.4.7.ez",
</desc>
</func>
<func>
- <name name="del_path" arity="1"/>
+ <name name="del_path" arity="1" since=""/>
<fsummary>Delete a directory from the code path.</fsummary>
<desc>
<p>Deletes a directory from the code path. The argument can be
@@ -415,7 +417,7 @@ zip:create("mnesia-4.4.7.ez",
</desc>
</func>
<func>
- <name name="replace_path" arity="2"/>
+ <name name="replace_path" arity="2" since=""/>
<fsummary>Replace a directory with another in the code path.</fsummary>
<desc>
<p>Replaces an old occurrence of a directory
@@ -439,7 +441,7 @@ zip:create("mnesia-4.4.7.ez",
</desc>
</func>
<func>
- <name name="load_file" arity="1"/>
+ <name name="load_file" arity="1" since=""/>
<fsummary>Load a module.</fsummary>
<type name="load_ret"/>
<desc>
@@ -458,7 +460,7 @@ zip:create("mnesia-4.4.7.ez",
</desc>
</func>
<func>
- <name name="load_abs" arity="1"/>
+ <name name="load_abs" arity="1" since=""/>
<fsummary>Load a module, residing in a specified file.</fsummary>
<type name="load_ret"/>
<type name="loaded_filename"/>
@@ -475,7 +477,7 @@ zip:create("mnesia-4.4.7.ez",
</desc>
</func>
<func>
- <name name="ensure_loaded" arity="1"/>
+ <name name="ensure_loaded" arity="1" since=""/>
<fsummary>Ensure that a module is loaded.</fsummary>
<desc>
<p>Tries to load a module in the same way as
@@ -487,7 +489,7 @@ zip:create("mnesia-4.4.7.ez",
</desc>
</func>
<func>
- <name name="load_binary" arity="3"/>
+ <name name="load_binary" arity="3" since=""/>
<fsummary>Load object code for a module.</fsummary>
<type name="loaded_filename"/>
<type name="loaded_ret_atoms"/>
@@ -505,7 +507,7 @@ zip:create("mnesia-4.4.7.ez",
</desc>
</func>
<func>
- <name name="atomic_load" arity="1"/>
+ <name name="atomic_load" arity="1" since="OTP 19.0"/>
<fsummary>Load a list of modules atomically</fsummary>
<desc>
<p>Tries to load all of the modules in the list
@@ -536,7 +538,7 @@ zip:create("mnesia-4.4.7.ez",
</item>
<tag><c>not_purged</c></tag>
<item>
- <p>The object code can not be loaded because an old version
+ <p>The object code cannot be loaded because an old version
of the code already exists.</p>
</item>
<tag><c>sticky_directory</c></tag>
@@ -564,7 +566,7 @@ ok = code:finish_loading(Prepared),
</desc>
</func>
<func>
- <name name="prepare_loading" arity="1"/>
+ <name name="prepare_loading" arity="1" since="OTP 19.0"/>
<fsummary>Prepare a list of modules atomically</fsummary>
<desc>
<p>Prepares to load the modules in the list
@@ -596,7 +598,7 @@ ok = code:finish_loading(Prepared),
</desc>
</func>
<func>
- <name name="finish_loading" arity="1"/>
+ <name name="finish_loading" arity="1" since="OTP 19.0"/>
<fsummary>Finish loading a list of prepared modules atomically</fsummary>
<desc>
<p>Tries to load code for all modules that have been previously
@@ -609,7 +611,7 @@ ok = code:finish_loading(Prepared),
<taglist>
<tag><c>not_purged</c></tag>
<item>
- <p>The object code can not be loaded because an old version
+ <p>The object code cannot be loaded because an old version
of the code already exists.</p>
</item>
<tag><c>sticky_directory</c></tag>
@@ -625,7 +627,7 @@ ok = code:finish_loading(Prepared),
</desc>
</func>
<func>
- <name name="ensure_modules_loaded" arity="1"/>
+ <name name="ensure_modules_loaded" arity="1" since="OTP 19.0"/>
<fsummary>Ensure that a list of modules is loaded</fsummary>
<desc>
<p>Tries to load any modules not already loaded in the list
@@ -637,7 +639,7 @@ ok = code:finish_loading(Prepared),
</desc>
</func>
<func>
- <name name="delete" arity="1"/>
+ <name name="delete" arity="1" since=""/>
<fsummary>Remove current code for a module.</fsummary>
<desc>
<p>Removes the current code for <c><anno>Module</anno></c>, that is,
@@ -650,7 +652,7 @@ ok = code:finish_loading(Prepared),
</desc>
</func>
<func>
- <name name="purge" arity="1"/>
+ <name name="purge" arity="1" since=""/>
<fsummary>Remove old code for a module.</fsummary>
<desc>
<p>Purges the code for <c><anno>Module</anno></c>, that is, removes code
@@ -666,7 +668,7 @@ ok = code:finish_loading(Prepared),
</desc>
</func>
<func>
- <name name="soft_purge" arity="1"/>
+ <name name="soft_purge" arity="1" since=""/>
<fsummary>Remove old code for a module, unless no process uses it.</fsummary>
<desc>
<p>Purges the code for <c><anno>Module</anno></c>, that is, removes code
@@ -681,7 +683,7 @@ ok = code:finish_loading(Prepared),
</desc>
</func>
<func>
- <name name="is_loaded" arity="1"/>
+ <name name="is_loaded" arity="1" since=""/>
<fsummary>Check if a module is loaded.</fsummary>
<type name="loaded_filename"/>
<type name="loaded_ret_atoms"/>
@@ -700,7 +702,7 @@ ok = code:finish_loading(Prepared),
</desc>
</func>
<func>
- <name name="all_loaded" arity="0"/>
+ <name name="all_loaded" arity="0" since=""/>
<fsummary>Get all loaded modules.</fsummary>
<type name="loaded_filename"/>
<type name="loaded_ret_atoms"/>
@@ -714,7 +716,7 @@ ok = code:finish_loading(Prepared),
</desc>
</func>
<func>
- <name name="which" arity="1"/>
+ <name name="which" arity="1" since=""/>
<fsummary>The object code file of a module.</fsummary>
<type name="loaded_ret_atoms"/>
<desc>
@@ -729,7 +731,7 @@ ok = code:finish_loading(Prepared),
</desc>
</func>
<func>
- <name name="get_object_code" arity="1"/>
+ <name name="get_object_code" arity="1" since=""/>
<fsummary>Gets the object code for a module.</fsummary>
<desc>
<p>Searches the code path for the object code of module
@@ -748,7 +750,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="root_dir" arity="0"/>
+ <name name="root_dir" arity="0" since=""/>
<fsummary>Root directory of Erlang/OTP.</fsummary>
<desc>
<p>Returns the root directory of Erlang/OTP, which is
@@ -760,7 +762,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="lib_dir" arity="0"/>
+ <name name="lib_dir" arity="0" since=""/>
<fsummary>Library directory of Erlang/OTP.</fsummary>
<desc>
<p>Returns the library directory, <c>$OTPROOT/lib</c>, where
@@ -772,7 +774,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="lib_dir" arity="1"/>
+ <name name="lib_dir" arity="1" since=""/>
<fsummary>Library directory for an application.</fsummary>
<desc>
<p>Returns the path
@@ -805,7 +807,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="lib_dir" arity="2"/>
+ <name name="lib_dir" arity="2" since=""/>
<fsummary>Subdirectory for an application.</fsummary>
<desc>
<p>Returns the path to a subdirectory directly under the top
@@ -825,7 +827,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="compiler_dir" arity="0"/>
+ <name name="compiler_dir" arity="0" since=""/>
<fsummary>Library directory for the compiler.</fsummary>
<desc>
<p>Returns the compiler library directory. Equivalent to
@@ -833,7 +835,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="priv_dir" arity="1"/>
+ <name name="priv_dir" arity="1" since=""/>
<fsummary>Priv directory for an application.</fsummary>
<desc>
<p>Returns the path to the <c>priv</c> directory in an
@@ -844,7 +846,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="objfile_extension" arity="0"/>
+ <name name="objfile_extension" arity="0" since=""/>
<fsummary>Object code file extension.</fsummary>
<desc>
<p>Returns the object code file extension corresponding to
@@ -852,7 +854,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="stick_dir" arity="1"/>
+ <name name="stick_dir" arity="1" since=""/>
<fsummary>Mark a directory as sticky.</fsummary>
<desc>
<p>Marks <c><anno>Dir</anno></c> as sticky.</p>
@@ -860,7 +862,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="unstick_dir" arity="1"/>
+ <name name="unstick_dir" arity="1" since=""/>
<fsummary>Remove a sticky directory mark.</fsummary>
<desc>
<p>Unsticks a directory that is marked as
@@ -869,7 +871,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="is_sticky" arity="1"/>
+ <name name="is_sticky" arity="1" since=""/>
<fsummary>Test if a module is sticky.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Module</anno></c> is the
@@ -880,7 +882,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="where_is_file" arity="1"/>
+ <name name="where_is_file" arity="1" since=""/>
<fsummary>Full name of a file located in the code path.</fsummary>
<desc>
<p>Searches the code path for <c><anno>Filename</anno></c>, a file of
@@ -891,7 +893,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="clash" arity="0"/>
+ <name name="clash" arity="0" since=""/>
<fsummary>Search for modules with identical names.</fsummary>
<desc>
<p>Searches all directories in the code path for module names with
@@ -899,7 +901,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="module_status" arity="1"/>
+ <name name="module_status" arity="1" since="OTP 20.0"/>
<fsummary>Return the status of the module in relation to object file on disk.</fsummary>
<desc>
<p>Returns:</p>
@@ -932,7 +934,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="modified_modules" arity="0"/>
+ <name name="modified_modules" arity="0" since="OTP 20.0"/>
<fsummary>Return a list of all modules modified on disk.</fsummary>
<desc>
<p>Returns the list of all currently loaded modules for which
@@ -941,7 +943,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</desc>
</func>
<func>
- <name name="is_module_native" arity="1"/>
+ <name name="is_module_native" arity="1" since=""/>
<fsummary>Test if a module has native code.</fsummary>
<desc>
<p>Returns:</p>
@@ -959,7 +961,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]),
</func>
<func>
- <name name="get_mode" arity="0"/>
+ <name name="get_mode" arity="0" since="OTP R16B"/>
<fsummary>The mode of the code server.</fsummary>
<desc>
<p>Returns an atom describing the mode of the code server:
diff --git a/lib/kernel/doc/src/config.xml b/lib/kernel/doc/src/config.xml
index fdb2d29f63..714af93f4d 100644
--- a/lib/kernel/doc/src/config.xml
+++ b/lib/kernel/doc/src/config.xml
@@ -4,7 +4,7 @@
<fileref>
<header>
<copyright>
- <year>1997</year><year>2017</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -37,10 +37,10 @@
data in the system configuration file <c>Name.config</c>.</p>
<p>Configuration parameter values in the configuration file
override the values in the application resource files (see
- <seealso marker="app"><c>app(4)</c></seealso>.
+ <seealso marker="app"><c>app(4)</c></seealso>).
The values in the configuration file can be
overridden by command-line flags (see
- <seealso marker="erts:erl"><c>erts:erl(1)</c></seealso>.</p>
+ <seealso marker="erts:erl"><c>erts:erl(1)</c></seealso>).</p>
<p>The value of a configuration parameter is retrieved by calling
<c>application:get_env/1,2</c>.</p>
</description>
@@ -86,8 +86,13 @@
<tag><c>File = string()</c></tag>
<item>Name of another <c>.config</c> file.
Extension <c>.config</c> can be omitted. It is
- recommended to use absolute paths. A relative path is
- relative the current working directory of the emulator.</item>
+ recommended to use absolute paths. If a relative path is used,
+ <c>File</c> is searched, first, relative from <c>sys.config</c> directory, then relative
+ to the current working directory of the emulator, for backward compatibility.
+ This allow to use a <c>sys.config</c> pointing out other <c>.config</c> files in a release
+ or in a node started manually using <c>-config ...</c> with same result whatever
+ the current working directory.
+ </item>
</taglist>
<p>When traversing the contents of <c>sys.config</c> and a filename
is encountered, its contents are read and merged with the result
diff --git a/lib/kernel/doc/src/disk_log.xml b/lib/kernel/doc/src/disk_log.xml
index 884cb32c0c..e308b06f3c 100644
--- a/lib/kernel/doc/src/disk_log.xml
+++ b/lib/kernel/doc/src/disk_log.xml
@@ -34,7 +34,7 @@
<rev>D</rev>
<file>disk_log.sgml</file>
</header>
- <module>disk_log</module>
+ <module since="">disk_log</module>
<modulesummary>A disk-based term logging facility.</modulesummary>
<description>
<p><c>disk_log</c> is a disk-based term logger that enables
@@ -238,7 +238,7 @@
</datatypes>
<funcs>
<func>
- <name name="accessible_logs" arity="0"/>
+ <name name="accessible_logs" arity="0" since=""/>
<fsummary>Return the accessible disk logs on the current node.</fsummary>
<desc>
<p>Returns the names of the disk logs accessible on the current node.
@@ -248,8 +248,8 @@
</desc>
</func>
<func>
- <name name="alog" arity="2"/>
- <name name="balog" arity="2"/>
+ <name name="alog" arity="2" since=""/>
+ <name name="balog" arity="2" since=""/>
<fsummary>Asynchronously log an item on to a disk log.</fsummary>
<type variable="Log"/>
<type variable="Term" name_i="1"/>
@@ -275,8 +275,8 @@
</desc>
</func>
<func>
- <name name="alog_terms" arity="2"/>
- <name name="balog_terms" arity="2"/>
+ <name name="alog_terms" arity="2" since=""/>
+ <name name="balog_terms" arity="2" since=""/>
<fsummary>Asynchronously log many items on to a disk log.</fsummary>
<type variable="Log"/>
<type variable="TermList" name_i="1"/>
@@ -303,8 +303,8 @@
</desc>
</func>
<func>
- <name name="block" arity="1"/>
- <name name="block" arity="2"/>
+ <name name="block" arity="1" since=""/>
+ <name name="block" arity="2" since=""/>
<fsummary>Block a disk log.</fsummary>
<type name="block_error_rsn"/>
<desc>
@@ -330,21 +330,21 @@
</desc>
</func>
<func>
- <name name="change_header" arity="2"/>
+ <name name="change_header" arity="2" since=""/>
<fsummary>Change option head or head_func for an owner of a disk log.</fsummary>
<desc>
<p>Changes the value of option <c>head</c> or <c>head_func</c> for an owner of a disk log.</p>
</desc>
</func>
<func>
- <name name="change_notify" arity="3"/>
+ <name name="change_notify" arity="3" since=""/>
<fsummary>Change option notify for an owner of a disk log.</fsummary>
<desc>
<p>Changes the value of option <c>notify</c> for an owner of a disk log. </p>
</desc>
</func>
<func>
- <name name="change_size" arity="2"/>
+ <name name="change_size" arity="2" since=""/>
<fsummary>Change the size of an open disk log.</fsummary>
<desc>
<p>Changes the size of an open log.
@@ -384,10 +384,10 @@
</desc>
</func>
<func>
- <name name="chunk" arity="2"/>
- <name name="chunk" arity="3"/>
- <name name="bchunk" arity="2"/>
- <name name="bchunk" arity="3"/>
+ <name name="chunk" arity="2" since=""/>
+ <name name="chunk" arity="3" since=""/>
+ <name name="bchunk" arity="2" since=""/>
+ <name name="bchunk" arity="3" since=""/>
<fsummary>Read a chunk of items written to a disk log.</fsummary>
<type variable="Log"/>
<type variable="Continuation"/>
@@ -447,7 +447,7 @@
</desc>
</func>
<func>
- <name name="chunk_info" arity="1"/>
+ <name name="chunk_info" arity="1" since=""/>
<fsummary>Return information about a chunk continuation of a disk log.</fsummary>
<desc>
<p>Returns the pair <c>{node, <anno>Node</anno>}</c>,
@@ -457,7 +457,7 @@
</desc>
</func>
<func>
- <name name="chunk_step" arity="3"/>
+ <name name="chunk_step" arity="3" since=""/>
<fsummary>Step forward or backward among the wrap log files of a disk log.</fsummary>
<desc>
<p>Can be used with <c>chunk/2,3</c> and <c>bchunk/2,3</c>
@@ -480,7 +480,7 @@
</desc>
</func>
<func>
- <name name="close" arity="1"/>
+ <name name="close" arity="1" since=""/>
<fsummary>Close a disk log.</fsummary>
<type name="close_error_rsn"/>
<desc>
@@ -505,7 +505,7 @@
</desc>
</func>
<func>
- <name name="format_error" arity="1"/>
+ <name name="format_error" arity="1" since=""/>
<fsummary>Return an English description of a disk log error reply.</fsummary>
<desc>
<p>Given the error returned by any function in this module,
@@ -517,7 +517,7 @@
</desc>
</func>
<func>
- <name name="inc_wrap_file" arity="1"/>
+ <name name="inc_wrap_file" arity="1" since=""/>
<fsummary>Change to the next wrap log file of a disk log.</fsummary>
<type name="inc_wrap_error_rsn"/>
<type name="invalid_header"/>
@@ -534,7 +534,7 @@
</desc>
</func>
<func>
- <name name="info" arity="1"/>
+ <name name="info" arity="1" since=""/>
<fsummary>Return information about a disk log.</fsummary>
<type name="dlog_info"/>
<desc>
@@ -685,8 +685,8 @@
</desc>
</func>
<func>
- <name name="lclose" arity="1"/>
- <name name="lclose" arity="2"/>
+ <name name="lclose" arity="1" since=""/>
+ <name name="lclose" arity="2" since=""/>
<fsummary>Close a disk log on one node.</fsummary>
<type name="lclose_error_rsn"/>
<desc>
@@ -704,8 +704,8 @@
</desc>
</func>
<func>
- <name name="log" arity="2"/>
- <name name="blog" arity="2"/>
+ <name name="log" arity="2" since=""/>
+ <name name="blog" arity="2" since=""/>
<fsummary>Log an item onto a disk log.</fsummary>
<type variable="Log"/>
<type variable="Term" name_i="1"/>
@@ -739,8 +739,8 @@
</desc>
</func>
<func>
- <name name="log_terms" arity="2"/>
- <name name="blog_terms" arity="2"/>
+ <name name="log_terms" arity="2" since=""/>
+ <name name="blog_terms" arity="2" since=""/>
<fsummary>Log many items onto a disk log.</fsummary>
<type variable="Log"/>
<type variable="TermList" name_i="1"/>
@@ -768,7 +768,7 @@
</desc>
</func>
<func>
- <name name="open" arity="1"/>
+ <name name="open" arity="1" since=""/>
<fsummary>Open a disk log file.</fsummary>
<type name="dlog_options"/>
<type name="dlog_option"/>
@@ -1041,7 +1041,7 @@
</desc>
</func>
<func>
- <name name="pid2name" arity="1"/>
+ <name name="pid2name" arity="1" since=""/>
<fsummary>Return the name of the disk log handled by a pid.</fsummary>
<desc>
<p>Returns the log name
@@ -1053,9 +1053,9 @@
</desc>
</func>
<func>
- <name name="reopen" arity="2"/>
- <name name="reopen" arity="3"/>
- <name name="breopen" arity="3"/>
+ <name name="reopen" arity="2" since=""/>
+ <name name="reopen" arity="3" since=""/>
+ <name name="breopen" arity="3" since=""/>
<fsummary>Reopen a disk log and save the old log.</fsummary>
<type variable="Log"/>
<type variable="File" name_i="1"/>
@@ -1087,7 +1087,7 @@
</desc>
</func>
<func>
- <name name="sync" arity="1"/>
+ <name name="sync" arity="1" since=""/>
<fsummary>Flush the contents of a disk log to the disk.</fsummary>
<type name="sync_error_rsn"/>
<desc>
@@ -1097,9 +1097,9 @@
</desc>
</func>
<func>
- <name name="truncate" arity="1"/>
- <name name="truncate" arity="2"/>
- <name name="btruncate" arity="2"/>
+ <name name="truncate" arity="1" since=""/>
+ <name name="truncate" arity="2" since=""/>
+ <name name="btruncate" arity="2" since=""/>
<fsummary>Truncate a disk log.</fsummary>
<type variable="Log"/>
<type variable="Head" name_i="2"/>
@@ -1129,7 +1129,7 @@
</desc>
</func>
<func>
- <name name="unblock" arity="1"/>
+ <name name="unblock" arity="1" since=""/>
<fsummary>Unblock a disk log.</fsummary>
<type name="unblock_error_rsn"/>
<desc>
diff --git a/lib/kernel/doc/src/erl_boot_server.xml b/lib/kernel/doc/src/erl_boot_server.xml
index 4109251387..89f9855c49 100644
--- a/lib/kernel/doc/src/erl_boot_server.xml
+++ b/lib/kernel/doc/src/erl_boot_server.xml
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>erl_boot_server</module>
+ <module since="">erl_boot_server</module>
<modulesummary>Boot server for other Erlang machines.</modulesummary>
<description>
<p>This server is used to assist diskless Erlang nodes that fetch
@@ -52,14 +52,14 @@
</description>
<funcs>
<func>
- <name name="add_slave" arity="1"/>
+ <name name="add_slave" arity="1" since=""/>
<fsummary>Add a slave to the list of allowed slaves.</fsummary>
<desc>
<p>Adds a <c><anno>Slave</anno></c> node to the list of allowed slave hosts.</p>
</desc>
</func>
<func>
- <name name="delete_slave" arity="1"/>
+ <name name="delete_slave" arity="1" since=""/>
<fsummary>Delete a slave from the list of allowed slaves.</fsummary>
<desc>
<p>Deletes a <c><anno>Slave</anno></c> node from the list of allowed slave
@@ -67,7 +67,7 @@
</desc>
</func>
<func>
- <name name="start" arity="1"/>
+ <name name="start" arity="1" since=""/>
<fsummary>Start the boot server.</fsummary>
<desc>
<p>Starts the boot server. <c><anno>Slaves</anno></c> is a list of
@@ -76,7 +76,7 @@
</desc>
</func>
<func>
- <name name="start_link" arity="1"/>
+ <name name="start_link" arity="1" since=""/>
<fsummary>Start the boot server and link to the the caller.</fsummary>
<desc>
<p>Starts the boot server and links to the caller. This function
@@ -85,7 +85,7 @@
</desc>
</func>
<func>
- <name name="which_slaves" arity="0"/>
+ <name name="which_slaves" arity="0" since=""/>
<fsummary>Return the current list of allowed slave hosts.</fsummary>
<desc>
<p>Returns the current list of allowed slave hosts.</p>
diff --git a/lib/kernel/doc/src/erl_ddll.xml b/lib/kernel/doc/src/erl_ddll.xml
index 75114e015c..52d5bcd079 100644
--- a/lib/kernel/doc/src/erl_ddll.xml
+++ b/lib/kernel/doc/src/erl_ddll.xml
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>erl_ddll</module>
+ <module since="">erl_ddll</module>
<modulesummary>Dynamic driver loader and linker.</modulesummary>
<description>
<p>This module provides an interface for loading
@@ -196,11 +196,11 @@
</datatypes>
<funcs>
<func>
- <name name="demonitor" arity="1"/>
+ <name name="demonitor" arity="1" since=""/>
<fsummary>Remove a monitor for a driver.</fsummary>
<desc>
<p>Removes a driver monitor in much the same way as
- <seealso marker="erts:erlang#erlang:demonitor/1"><c>erlang:demonitor/1</c></seealso>
+ <seealso marker="erts:erlang#demonitor/1"><c>erlang:demonitor/1</c></seealso>
in ERTS
does with process monitors. For details about how to create
driver monitors, see
@@ -212,7 +212,7 @@
</desc>
</func>
<func>
- <name name="format_error" arity="1"/>
+ <name name="format_error" arity="1" since=""/>
<fsummary>Format an error descriptor.</fsummary>
<desc>
<p>Takes an <c><anno>ErrorDesc</anno></c> returned by load, unload, or
@@ -229,7 +229,7 @@
</desc>
</func>
<func>
- <name name="info" arity="0"/>
+ <name name="info" arity="0" since=""/>
<fsummary>Retrieve information about all drivers.</fsummary>
<desc>
<p>Returns a list of tuples <c>{<anno>DriverName</anno>, <anno>InfoList</anno>}</c>,
@@ -240,7 +240,7 @@
</desc>
</func>
<func>
- <name name="info" arity="1"/>
+ <name name="info" arity="1" since=""/>
<fsummary>Retrieve information about one driver.</fsummary>
<desc>
<p>Returns a list of tuples <c>{<anno>Tag</anno>, <anno>Value</anno>}</c>,
@@ -266,7 +266,7 @@
</desc>
</func>
<func>
- <name name="info" arity="2"/>
+ <name name="info" arity="2" since=""/>
<fsummary>Retrieve specific information about one driver.</fsummary>
<desc>
<p>Returns specific information about one aspect of a driver.
@@ -328,7 +328,7 @@
</desc>
</func>
<func>
- <name name="load" arity="2"/>
+ <name name="load" arity="2" since=""/>
<fsummary>Load a driver.</fsummary>
<desc>
<p>Loads and links the dynamic driver <c><anno>Name</anno></c>.
@@ -390,7 +390,7 @@
</desc>
</func>
<func>
- <name name="load_driver" arity="2"/>
+ <name name="load_driver" arity="2" since=""/>
<fsummary>Load a driver.</fsummary>
<desc>
<p>Works essentially as <c>load/2</c>, but loads the driver
@@ -413,7 +413,7 @@
</desc>
</func>
<func>
- <name name="loaded_drivers" arity="0"/>
+ <name name="loaded_drivers" arity="0" since=""/>
<fsummary>List loaded drivers.</fsummary>
<desc>
<p>Returns a list of all the available drivers, both
@@ -425,12 +425,12 @@
</desc>
</func>
<func>
- <name name="monitor" arity="2"/>
+ <name name="monitor" arity="2" since=""/>
<fsummary>Create a monitor for a driver.</fsummary>
<desc>
<p>Creates a driver monitor and works in many
ways as
- <seealso marker="erts:erlang#erlang:monitor/2"><c>erlang:monitor/2</c></seealso>
+ <seealso marker="erts:erlang#monitor/2"><c>erlang:monitor/2</c></seealso>
in ERTS,
does for processes. When a driver changes state, the monitor
results in a monitor message that is sent to the calling
@@ -588,7 +588,7 @@
</desc>
</func>
<func>
- <name name="reload" arity="2"/>
+ <name name="reload" arity="2" since=""/>
<fsummary>Replace a driver.</fsummary>
<desc>
<p>Reloads the driver named <c><anno>Name</anno></c> from a possibly
@@ -626,7 +626,7 @@
</desc>
</func>
<func>
- <name name="reload_driver" arity="2"/>
+ <name name="reload_driver" arity="2" since=""/>
<fsummary>Replace a driver.</fsummary>
<desc>
<p>Works exactly as <seealso marker="#reload/2"><c>reload/2</c></seealso>,
@@ -644,7 +644,7 @@
</desc>
</func>
<func>
- <name name="try_load" arity="3"/>
+ <name name="try_load" arity="3" since=""/>
<fsummary>Load a driver.</fsummary>
<desc>
<p>Provides more control than the
@@ -931,7 +931,7 @@
</desc>
</func>
<func>
- <name name="try_unload" arity="2"/>
+ <name name="try_unload" arity="2" since=""/>
<fsummary>Unload a driver.</fsummary>
<desc>
<p>This is the low-level function to unload (or decrement
@@ -1116,7 +1116,7 @@
</desc>
</func>
<func>
- <name name="unload" arity="1"/>
+ <name name="unload" arity="1" since=""/>
<fsummary>Unload a driver.</fsummary>
<desc>
<p>Unloads, or at least dereferences the driver named
@@ -1143,7 +1143,7 @@
</desc>
</func>
<func>
- <name name="unload_driver" arity="1"/>
+ <name name="unload_driver" arity="1" since=""/>
<fsummary>Unload a driver.</fsummary>
<desc>
<p>Unloads, or at least dereferences the driver named
diff --git a/lib/kernel/doc/src/erl_epmd.xml b/lib/kernel/doc/src/erl_epmd.xml
new file mode 100644
index 0000000000..2adbf11a28
--- /dev/null
+++ b/lib/kernel/doc/src/erl_epmd.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2018</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>erl_epmd</title>
+ <prepared>Timmo Verlaan</prepared>
+ <docno>1</docno>
+ <date>2018-02-19</date>
+ <rev>A</rev>
+ </header>
+ <module since="OTP R14B">erl_epmd</module>
+ <modulesummary>
+ Erlang interface towards epmd
+ </modulesummary>
+ <description>
+ <p>This module communicates with the EPMD daemon, see <seealso
+ marker="erts:epmd">epmd</seealso>. To implement your own epmd module please
+ see <seealso marker="erts:alt_disco">ERTS User's Guide: How to Implement an
+ Alternative Service Discovery for Erlang Distribution</seealso></p>
+ </description>
+
+ <funcs>
+ <func>
+ <name name="start_link" arity="0" since="OTP 21.0"/>
+ <fsummary>Callback for erl_distribution supervisor.</fsummary>
+ <desc>
+ <p>This function is invoked as this module is added as a child of the
+ <c>erl_distribution</c> supervisor.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="register_node" arity="2" since="OTP 21.0"/>
+ <name name="register_node" arity="3" since="OTP 21.0"/>
+ <fsummary>Registers the node with <c>epmd</c>.</fsummary>
+ <desc>
+ <p>Registers the node with <c>epmd</c> and tells epmd what port will be
+ used for the current node. It returns a creation number. This number is
+ incremented on each register to help with identifying if a node is
+ reconnecting to epmd.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="port_please" arity="2" since="OTP 21.0"/>
+ <name name="port_please" arity="3" since="OTP 21.0"/>
+ <fsummary>Returns the port number for a given node.</fsummary>
+ <desc>
+ <p>Requests the distribution port for the given node of an EPMD
+ instance. Together with the port it returns a distribution protocol
+ version which has been 5 since Erlang/OTP R6.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="address_please" arity="3" since="OTP 21.0"/>
+ <fsummary>Returns address and port.</fsummary>
+ <desc>
+ <p>Called by the distribution module. Resolves the <c>Host</c> to an IP
+ address.</p>
+ <p>Another epmd module may return port and distribution protocol version
+ as well.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="names" arity="1" since="OTP 21.0"/>
+ <fsummary>Names of Erlang nodes at a host.</fsummary>
+ <desc>
+ <p>Called by <seealso marker="net_adm"><c>net_adm:names/0</c></seealso>.
+ <c>Host</c> defaults to the localhost. Returns the names and associated
+ port numbers of the Erlang nodes that <c>epmd</c> registered at the
+ specified host. Returns <c>{error, address}</c> if <c>epmd</c> is not
+ operational.</p>
+ <p><em>Example:</em></p>
+ <pre>
+(arne@dunn)1> <input>erl_epmd:names(localhost).</input>
+{ok,[{"arne",40262}]}</pre>
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/kernel/doc/src/error_handler.xml b/lib/kernel/doc/src/error_handler.xml
index e5639487dc..eb01e87aee 100644
--- a/lib/kernel/doc/src/error_handler.xml
+++ b/lib/kernel/doc/src/error_handler.xml
@@ -30,7 +30,7 @@
<date></date>
<rev></rev>
</header>
- <module>error_handler</module>
+ <module since="">error_handler</module>
<modulesummary>Default system error handler.</modulesummary>
<description>
<p>This module defines what happens when certain types
@@ -38,7 +38,7 @@
</description>
<funcs>
<func>
- <name name="raise_undef_exception" arity="3"/>
+ <name name="raise_undef_exception" arity="3" since="OTP R16B"/>
<fsummary>Raise an undef exception.</fsummary>
<type_desc variable="Args">
A (possibly empty) list of arguments <c>Arg1,..,ArgN</c>
@@ -51,7 +51,7 @@
</desc>
</func>
<func>
- <name name="undefined_function" arity="3"/>
+ <name name="undefined_function" arity="3" since=""/>
<fsummary>Called when an undefined function is encountered.</fsummary>
<type_desc variable="Args">
A (possibly empty) list of arguments <c>Arg1,..,ArgN</c>
@@ -93,7 +93,7 @@
</desc>
</func>
<func>
- <name name="undefined_lambda" arity="3"/>
+ <name name="undefined_lambda" arity="3" since=""/>
<fsummary>Called when an undefined lambda (fun) is encountered.</fsummary>
<type_desc variable="Args">
A (possibly empty) list of arguments <c>Arg1,..,ArgN</c>
diff --git a/lib/kernel/doc/src/error_logger.xml b/lib/kernel/doc/src/error_logger.xml
index 91bf57cb91..c170b4fa34 100644
--- a/lib/kernel/doc/src/error_logger.xml
+++ b/lib/kernel/doc/src/error_logger.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -28,39 +28,40 @@
<date></date>
<rev></rev>
</header>
- <module>error_logger</module>
+ <module since="">error_logger</module>
<modulesummary>Erlang error logger.</modulesummary>
<description>
+
+ <note>
+ <p>In Erlang/OTP 21.0, a new API for logging was added. The
+ old <c>error_logger</c> module can still be used by legacy
+ code, but log events are redirected to the new Logger API. New
+ code should use the Logger API directly.</p>
+ <p><c>error_logger</c> is no longer started by default, but is
+ automatically started when an event handler is added
+ with <c>error_logger:add_report_handler/1,2</c>. The <c>error_logger</c>
+ module is then also added as a handler to the new logger.</p>
+ <p>See <seealso marker="logger"><c>logger(3)</c></seealso> and
+ the <seealso marker="logger_chapter">Logging</seealso> chapter
+ in the User's Guide for more information.</p>
+ </note>
+
<p>The Erlang <em>error logger</em> is an event manager (see
<seealso marker="doc/design_principles:des_princ">OTP Design Principles</seealso> and
<seealso marker="stdlib:gen_event"><c>gen_event(3)</c></seealso>),
- registered as <c>error_logger</c>. Errors, warnings, and info events
- are sent to the error logger from the Erlang runtime system and
- the different Erlang/OTP applications. The events are, by default,
- logged to the terminal. Notice that an event from a process <c>P</c> is
- logged at the node of the group leader of <c>P</c>. This means
- that log output is directed to the node from which a process was
- created, which not necessarily is the same node as where it is
- executing.</p>
- <p>Initially, <c>error_logger</c> has only a primitive event
- handler, which buffers and prints the raw event messages. During
- system startup, the Kernel application replaces this with a
- <em>standard event handler</em>, by default one that writes
- nicely formatted output to the terminal. Kernel can also be
- configured so that events are logged to a file instead, or not logged at all,
- see <seealso marker="kernel_app"><c>kernel(6)</c></seealso>.</p>
- <p>Also the SASL application, if started, adds its own event
- handler, which by default writes supervisor, crash, and progress
- reports to the terminal. See
- <seealso marker="sasl:sasl_app"><c>sasl(6)</c></seealso>.</p>
- <p>It is recommended that user-defined applications report
- errors through the error logger to get uniform reports.
- User-defined event handlers can be added to handle application-specific
- events, see
- <seealso marker="#add_report_handler/1"><c>add_report_handler/1,2</c></seealso>.
- Also, a useful event handler is provided in STDLIB for multi-file
- logging of events, see
- <seealso marker="stdlib:log_mf_h"><c>log_mf_h(3)</c></seealso>.</p>
+ registered as <c>error_logger</c>.</p>
+ <p>Error logger is no longer started by default, but is
+ automatically started when an event handler is added
+ with <seealso marker="#add_report_handler/1">
+ <c>add_report_handler/1,2</c></seealso>. The <c>error_logger</c>
+ module is then also added as a handler to the new logger,
+ causing log events to be forwarded from logger to error logger,
+ and consequently to all installed error logger event
+ handlers.</p>
+ <p>User-defined event handlers can be added to handle application-specific
+ events.</p>
+ <p>Existing event handlers provided by STDLIB and SASL are still
+ available, but are no longer used by OTP.</p>
<p>Warning events were introduced in Erlang/OTP R9C and are enabled
by default as from Erlang/OTP 18.0. To retain backwards compatibility
with existing user-defined event handlers, the warning events can be
@@ -75,8 +76,8 @@
</datatypes>
<funcs>
<func>
- <name name="add_report_handler" arity="1"/>
- <name name="add_report_handler" arity="2"/>
+ <name name="add_report_handler" arity="1" since=""/>
+ <name name="add_report_handler" arity="2" since=""/>
<fsummary>Add an event handler to the error logger.</fsummary>
<desc>
<p>Adds a new event handler to the error logger. The event
@@ -89,167 +90,213 @@
The function returns <c>ok</c> if successful.</p>
<p>The event handler must be able to handle the events in this module, see
section <seealso marker="#events">Events</seealso>.</p>
+ <p>The first time this function is called,
+ <c>error_logger</c> is added as a Logger handler, and
+ the <c>error_logger</c> process is started.</p>
</desc>
</func>
<func>
- <name name="delete_report_handler" arity="1"/>
+ <name name="delete_report_handler" arity="1" since=""/>
<fsummary>Delete an event handler from the error logger.</fsummary>
<desc>
<p>Deletes an event handler from the error logger by calling
<c>gen_event:delete_handler(error_logger, <anno>Handler</anno>, [])</c>,
see <seealso marker="stdlib:gen_event"><c>gen_event(3)</c></seealso>.</p>
+ <p>If no more event handlers exist after the deletion,
+ <c>error_logger</c> is removed as a Logger handler, and
+ the <c>error_logger</c> process is stopped.</p>
</desc>
</func>
<func>
- <name name="error_msg" arity="1"/>
- <name name="error_msg" arity="2"/>
- <name name="format" arity="2"/>
- <fsummary>Send a standard error event to the error logger.</fsummary>
+ <name name="error_msg" arity="1" since=""/>
+ <name name="error_msg" arity="2" since=""/>
+ <name name="format" arity="2" since=""/>
+ <fsummary>Log a standard error event.</fsummary>
<desc>
- <p>Sends a standard error event to the error logger.
- The <c><anno>Format</anno></c> and <c><anno>Data</anno></c> arguments
- are the same as the arguments of
+ <p>Log a standard error event. The <c><anno>Format</anno></c>
+ and <c><anno>Data</anno></c> arguments are the same as the
+ arguments of
<seealso marker="stdlib:io#format/2"><c>io:format/2</c></seealso>
- in STDLIB.
- The event is handled by the standard event handler.</p>
+ in STDLIB.</p>
+ <p>Error logger forwards the event to Logger, including
+ metadata that allows backwards compatibility with legacy
+ error logger event handlers.</p>
+ <p>The event is handled by the default Logger handler.</p>
+ <p>These functions are kept for backwards compatibility and
+ must not be used by new code. Use the <seealso marker="logger#macros">
+ <c>?LOG_ERROR</c></seealso> macro or
+ <seealso marker="logger#error-1"><c>logger:error/1,2,3</c></seealso>
+ instead.</p>
<p><em>Example:</em></p>
<pre>
-1> <input>error_logger:error_msg("An error occurred in ~p~n", [a_module]).</input>
-
-=ERROR REPORT==== 11-Aug-2005::14:03:19 ===
+1> <input>error_logger:error_msg("An error occurred in ~p", [a_module]).</input>
+=ERROR REPORT==== 22-May-2018::11:18:43.376917 ===
An error occurred in a_module
ok</pre>
<warning>
- <p>If called with bad arguments, this function can crash
- the standard event handler, meaning no further events are
- logged. When in doubt, use
- <seealso marker="#error_report/1"><c>error_report/1</c></seealso>
- instead.</p>
- </warning>
- <warning>
<p>If the Unicode translation modifier (<c>t</c>) is used in
- the format string, all error handlers must ensure that the
+ the format string, all event handlers must ensure that the
formatted output is correctly encoded for the I/O
device.</p>
</warning>
</desc>
</func>
<func>
- <name name="error_report" arity="1"/>
- <fsummary>Send a standard error report event to the error logger.</fsummary>
+ <name name="error_report" arity="1" since=""/>
+ <fsummary>Log a standard error event.</fsummary>
<desc>
- <p>Sends a standard error report event to the error logger.
- The event is handled by the standard event handler.</p>
+ <p>Log a standard error event. Error logger forwards the event
+ to Logger, including metadata that allows backwards
+ compatibility with legacy error logger event handlers.</p>
+ <p>The event is handled by the default Logger handler.</p>
+ <p>This functions is kept for backwards compatibility and
+ must not be used by new code. Use the <seealso marker="logger#macros">
+ <c>?LOG_ERROR</c></seealso> macro or
+ <seealso marker="logger#error-1"><c>logger:error/1,2,3</c></seealso>
+ instead.</p>
<p><em>Example:</em></p>
<pre>
2> <input>error_logger:error_report([{tag1,data1},a_term,{tag2,data}]).</input>
-
-=ERROR REPORT==== 11-Aug-2005::13:45:41 ===
+=ERROR REPORT==== 22-May-2018::11:24:23.699306 ===
tag1: data1
a_term
tag2: data
ok
3> <input>error_logger:error_report("Serious error in my module").</input>
-
-=ERROR REPORT==== 11-Aug-2005::13:45:49 ===
+=ERROR REPORT==== 22-May-2018::11:24:45.972445 ===
Serious error in my module
ok</pre>
</desc>
</func>
<func>
- <name name="error_report" arity="2"/>
- <fsummary>Send a user-defined error report event to the error logger.</fsummary>
+ <name name="error_report" arity="2" since=""/>
+ <fsummary>Log a user-defined error event.</fsummary>
<desc>
- <p>Sends a user-defined error report event to the error logger.
- An event handler to handle the event is supposed to have been
- added. The event is ignored by the standard event handler.</p>
+ <p>Log a user-defined error event. Error logger forwards the
+ event to Logger, including metadata that allows backwards
+ compatibility with legacy error logger event handlers.</p>
+ <p>Error logger also adds a <c>domain</c> field with
+ value <c>[<anno>Type</anno>]</c> to this event's metadata,
+ causing the filters of the default Logger handler to discard
+ the event. A different Logger handler, or an error logger
+ event handler, must be added to handle this event.</p>
<p>It is recommended that <c><anno>Report</anno></c> follows the same
structure as for
<seealso marker="#error_report/1"><c>error_report/1</c></seealso>.</p>
+ <p>This functions is kept for backwards compatibility and
+ must not be used by new code. Use the <seealso marker="logger#macros">
+ <c>?LOG_ERROR</c></seealso> macro or
+ <seealso marker="logger#error-1"><c>logger:error/1,2,3</c></seealso>
+ instead.</p>
</desc>
</func>
<func>
- <name name="get_format_depth" arity="0"/>
+ <name name="get_format_depth" arity="0" since="OTP 20.0"/>
<fsummary>Get the value of the Kernel application variable
<c>error_logger_format_depth</c>.</fsummary>
<desc>
<p>Returns <c>max(10, Depth)</c>, where <c>Depth</c> is the
- value of
- <seealso marker="kernel:kernel_app#error_logger_format_depth">
- error_logger_format_depth</seealso>
+ value of <c>error_logger_format_depth</c>
in the Kernel application, if Depth is an integer. Otherwise,
<c>unlimited</c> is returned.</p>
+ <note>
+ <p>The <c>error_logger_format_depth</c> variable
+ is <seealso marker="kernel_app#deprecated-configuration-parameters">
+ deprecated</seealso> since
+ the <seealso marker="logger">Logger API</seealso> was
+ introduced in Erlang/OTP 21.0. The variable, and this
+ function, are kept for backwards compatibility since they
+ still might be used by legacy report handlers.</p>
+ </note>
</desc>
</func>
<func>
- <name name="info_msg" arity="1"/>
- <name name="info_msg" arity="2"/>
- <fsummary>Send a standard information event to the error logger.</fsummary>
+ <name name="info_msg" arity="1" since=""/>
+ <name name="info_msg" arity="2" since=""/>
+ <fsummary>Log a standard information event.</fsummary>
<desc>
- <p>Sends a standard information event to the error logger.
- The <c><anno>Format</anno></c> and <c><anno>Data</anno></c> arguments
- are the same as the arguments of
+ <p>Log a standard information event. The <c><anno>Format</anno></c>
+ and <c><anno>Data</anno></c> arguments are the same as the
+ arguments of
<seealso marker="stdlib:io#format/2"><c>io:format/2</c></seealso>
- in STDLIB. The event is handled by the standard event handler.</p>
+ in STDLIB.</p>
+ <p>Error logger forwards the event to Logger, including
+ metadata that allows backwards compatibility with legacy
+ error logger event handlers.</p>
+ <p>The event is handled by the default Logger handler.</p>
+ <p>These functions are kept for backwards compatibility and
+ must not be used by new code. Use the <seealso marker="logger#macros">
+ <c>?LOG_INFO</c></seealso> macro or
+ <seealso marker="logger#info-1"><c>logger:info/1,2,3</c></seealso>
+ instead.</p>
<p><em>Example:</em></p>
<pre>
-1> <input>error_logger:info_msg("Something happened in ~p~n", [a_module]).</input>
-
-=INFO REPORT==== 11-Aug-2005::14:06:15 ===
+1> <input>error_logger:info_msg("Something happened in ~p", [a_module]).</input>
+=INFO REPORT==== 22-May-2018::12:03:32.612462 ===
Something happened in a_module
ok</pre>
<warning>
- <p>If called with bad arguments, this function can crash
- the standard event handler, meaning no further events are
- logged. When in doubt, use <c>info_report/1</c> instead.</p>
- </warning>
- <warning>
<p>If the Unicode translation modifier (<c>t</c>) is used in
- the format string, all error handlers must ensure that the
+ the format string, all event handlers must ensure that the
formatted output is correctly encoded for the I/O
device.</p>
</warning>
</desc>
</func>
<func>
- <name name="info_report" arity="1"/>
- <fsummary>Send a standard information report event to the error logger.</fsummary>
+ <name name="info_report" arity="1" since=""/>
+ <fsummary>Log a standard information event.</fsummary>
<desc>
- <p>Sends a standard information report event to the error
- logger. The event is handled by the standard event handler.</p>
+ <p>Log a standard information event. Error logger forwards the
+ event to Logger, including metadata that allows backwards
+ compatibility with legacy error logger event handlers.</p>
+ <p>The event is handled by the default Logger handler.</p>
+ <p>This functions is kept for backwards compatibility and
+ must not be used by new code. Use the <seealso marker="logger#macros">
+ <c>?LOG_INFO</c></seealso> macro or
+ <seealso marker="logger#info-1"><c>logger:info/1,2,3</c></seealso>
+ instead.</p>
<p><em>Example:</em></p>
<pre>
2> <input>error_logger:info_report([{tag1,data1},a_term,{tag2,data}]).</input>
-
-=INFO REPORT==== 11-Aug-2005::13:55:09 ===
+=INFO REPORT==== 22-May-2018::12:06:35.994440 ===
tag1: data1
a_term
tag2: data
ok
3> <input>error_logger:info_report("Something strange happened").</input>
-
-=INFO REPORT==== 11-Aug-2005::13:55:36 ===
+=INFO REPORT==== 22-May-2018::12:06:49.066872 ===
Something strange happened
ok</pre>
</desc>
</func>
<func>
- <name name="info_report" arity="2"/>
- <fsummary>Send a user-defined information report event to the error logger.</fsummary>
+ <name name="info_report" arity="2" since=""/>
+ <fsummary>Log a user-defined information event.</fsummary>
<desc>
- <p>Sends a user-defined information report event to the error
- logger. An event handler to handle the event is supposed to
- have been added. The event is ignored by the standard event
- handler.</p>
+ <p>Log a user-defined information event. Error logger forwards
+ the event to Logger, including metadata that allows
+ backwards compatibility with legacy error logger event
+ handlers.</p>
+ <p>Error logger also adds a <c>domain</c> field with
+ value <c>[<anno>Type</anno>]</c> to this event's metadata,
+ causing the filters of the default Logger handler to discard
+ the event. A different Logger handler, or an error logger
+ event handler, must be added to handle this event.</p>
<p>It is recommended that <c><anno>Report</anno></c> follows the same
structure as for
<seealso marker="#info_report/1"><c>info_report/1</c></seealso>.</p>
+ <p>This functions is kept for backwards compatibility and
+ must not be used by new code. Use the <seealso marker="logger#macros">
+ <c>?LOG_INFO</c></seealso> macro or
+ <seealso marker="logger#info-1"><c>logger:info/1,2,3</c></seealso>
+ instead.</p>
</desc>
</func>
<func>
- <name name="logfile" arity="1" clause_i="1"/>
- <name name="logfile" arity="1" clause_i="2"/>
- <name name="logfile" arity="1" clause_i="3"/>
+ <name name="logfile" arity="1" clause_i="1" since=""/>
+ <name name="logfile" arity="1" clause_i="2" since=""/>
+ <name name="logfile" arity="1" clause_i="3" since=""/>
<fsummary>Enable or disable error printouts to a file.</fsummary>
<type variable="Filename"/>
<type variable="OpenReason" name_i="1"/>
@@ -258,14 +305,22 @@ ok</pre>
<type name="open_error"/>
<desc>
<p>Enables or disables printout of standard events to a file.</p>
- <p>This is done by adding or deleting the standard event handler
- for output to file. Thus, calling this function overrides
- the value of the Kernel <c>error_logger</c> configuration
- parameter.</p>
- <p>Enabling file logging can be used together with calling
- <c>tty(false)</c>, to have a silent system where
- all standard events are logged to a file only.
- Only one log file can be active at a time.</p>
+ <p>This is done by adding or deleting
+ the <c>error_logger_file_h</c> event handler, and thus
+ indirectly adding <c>error_logger</c> as a Logger
+ handler.</p>
+ <p>Notice that this function does not manipulate the Logger
+ configuration directly, meaning that if the default Logger
+ handler is already logging to a file, this function can
+ potentially cause logging to a second file.</p>
+ <p>This function is useful as a shortcut during development
+ and testing, but must not be used in a production
+ system. See
+ section <seealso marker="logger_chapter">Logging</seealso>
+ in the Kernel User's Guide, and
+ the <seealso marker="logger"><c>logger(3)</c></seealso>
+ manual page for information about how to configure Logger
+ for live systems.</p>
<p><c>Request</c> is one of the following:</p>
<taglist>
<tag><c>{open, <anno>Filename</anno>}</c></tag>
@@ -291,19 +346,24 @@ ok</pre>
</desc>
</func>
<func>
- <name name="tty" arity="1"/>
+ <name name="tty" arity="1" since=""/>
<fsummary>Enable or disable printouts to the terminal.</fsummary>
<desc>
<p>Enables (<c><anno>Flag</anno> == true</c>) or disables
(<c><anno>Flag</anno> == false</c>) printout of standard events
to the terminal.</p>
- <p>This is done by adding or deleting the standard event handler
- for output to the terminal. Thus, calling this function overrides
- the value of the Kernel <c>error_logger</c> configuration parameter.</p>
+ <p>This is done by manipulating the Logger configuration. The
+ function is useful as a shortcut during development and
+ testing, but must not be used in a production system. See
+ section <seealso marker="logger_chapter">Logging</seealso>
+ in the Kernel User's Guide, and
+ the <seealso marker="logger"><c>logger(3)</c></seealso>
+ manual page for information about how to configure Logger
+ for live systems.</p>
</desc>
</func>
<func>
- <name name="warning_map" arity="0"/>
+ <name name="warning_map" arity="0" since=""/>
<fsummary>Return the current mapping for warning events.</fsummary>
<desc>
<p>Returns the current mapping for warning events. Events sent
@@ -340,51 +400,73 @@ ok</pre>
</desc>
</func>
<func>
- <name name="warning_msg" arity="1"/>
- <name name="warning_msg" arity="2"/>
- <fsummary>Send a standard warning event to the error logger.</fsummary>
+ <name name="warning_msg" arity="1" since=""/>
+ <name name="warning_msg" arity="2" since=""/>
+ <fsummary>Log a standard warning event.</fsummary>
<desc>
- <p>Sends a standard warning event to the error logger.
- The <c><anno>Format</anno></c> and <c><anno>Data</anno></c> arguments
- are the same as the arguments of
+ <p>Log a standard warning event. The <c><anno>Format</anno></c>
+ and <c><anno>Data</anno></c> arguments are the same as the
+ arguments of
<seealso marker="stdlib:io#format/2"><c>io:format/2</c></seealso>
- in STDLIB.
- The event is handled by the standard event handler. It is tagged
- as an error, warning, or info, see
+ in STDLIB.</p>
+ <p>Error logger forwards the event to Logger, including
+ metadata that allows backwards compatibility with legacy
+ error logger event handlers.</p>
+ <p>The event is handled by the default Logger handler. The log
+ level can be changed to error or info, see
<seealso marker="#warning_map/0"><c>warning_map/0</c></seealso>.</p>
- <warning>
- <p>If called with bad arguments, this function can crash
- the standard event handler, meaning no further events are
- logged. When in doubt, use <c>warning_report/1</c> instead.</p>
- </warning>
+ <p>These functions are kept for backwards compatibility and
+ must not be used by new code. Use the <seealso marker="logger#macros">
+ <c>?LOG_WARNING</c></seealso> macro or
+ <seealso marker="logger#warning-1"><c>logger:warning/1,2,3</c></seealso>
+ instead.</p>
<warning>
<p>If the Unicode translation modifier (<c>t</c>) is used in
- the format string, all error handlers must ensure that the
+ the format string, all event handlers must ensure that the
formatted output is correctly encoded for the I/O
device.</p>
</warning>
</desc>
</func>
<func>
- <name name="warning_report" arity="1"/>
- <fsummary>Send a standard warning report event to the error logger.</fsummary>
+ <name name="warning_report" arity="1" since=""/>
+ <fsummary>Log a standard warning event.</fsummary>
<desc>
- <p>Sends a standard warning report event to the error logger.
- The event is handled by the standard event handler. It is
- tagged as an error, warning, or info, see
+ <p>Log a standard warning event. Error logger forwards the event
+ to Logger, including metadata that allows backwards
+ compatibility with legacy error logger event handlers.</p>
+ <p>The event is handled by the default Logger handler. The log
+ level can be changed to error or info, see
<seealso marker="#warning_map/0"><c>warning_map/0</c></seealso>.</p>
+ <p>This functions is kept for backwards compatibility and
+ must not be used by new code. Use the <seealso marker="logger#macros">
+ <c>?LOG_WARNING</c></seealso> macro or
+ <seealso marker="logger#warning-1"><c>logger:warning/1,2,3</c></seealso>
+ instead.</p>
</desc>
</func>
<func>
- <name name="warning_report" arity="2"/>
- <fsummary>Send a user-defined warning report event to the error logger.</fsummary>
+ <name name="warning_report" arity="2" since=""/>
+ <fsummary>Log a user-defined warning event.</fsummary>
<desc>
- <p>Sends a user-defined warning report event to the error
- logger. An event handler to handle the event is supposed to
- have been added. The event is ignored by the standard event
- handler. It is tagged as an error, warning, or info,
- depending on the value of
+ <p>Log a user-defined warning event. Error logger forwards the
+ event to Logger, including metadata that allows backwards
+ compatibility with legacy error logger event handlers.</p>
+ <p>Error logger also adds a <c>domain</c> field with
+ value <c>[<anno>Type</anno>]</c> to this event's metadata,
+ causing the filters of the default Logger handler to discard
+ the event. A different Logger handler, or an error logger
+ event handler, must be added to handle this event.</p>
+ <p>The log level can be changed to error or info, see
<seealso marker="#warning_map/0"><c>warning_map/0</c></seealso>.</p>
+ <p>It is recommended that <c><anno>Report</anno></c> follows the same
+ structure as for
+ <seealso marker="#warning_report/1"><c>warning_report/1</c></seealso>.</p>
+ <p>This functions is kept for backwards compatibility and
+ must not be used by new code. Use the <seealso marker="logger#macros">
+ <c>?LOG_WARNING</c></seealso> macro or
+ <seealso marker="logger#warning-1"><c>logger:warning/1,2,3</c></seealso>
+ instead.</p>
</desc>
</func>
</funcs>
@@ -448,8 +530,9 @@ ok</pre>
<section>
<title>See Also</title>
<p><seealso marker="stdlib:gen_event"><c>gen_event(3)</c></seealso>,
- <seealso marker="stdlib:log_mf_h"><c>log_mf_h(3)</c></seealso>
- <seealso marker="kernel_app"><c>kernel(6)</c></seealso>
+ <seealso marker="kernel:logger"><c>logger(3)</c></seealso>,
+ <seealso marker="stdlib:log_mf_h"><c>log_mf_h(3)</c></seealso>,
+ <seealso marker="kernel_app"><c>kernel(6)</c></seealso>,
<seealso marker="sasl:sasl_app"><c>sasl(6)</c></seealso></p>
</section>
</erlref>
diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml
index b674b3ca93..fc25e83d40 100644
--- a/lib/kernel/doc/src/file.xml
+++ b/lib/kernel/doc/src/file.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -28,20 +28,23 @@
<date></date>
<rev></rev>
</header>
- <module>file</module>
+ <module since="">file</module>
<modulesummary>File interface module.</modulesummary>
<description>
<p>This module provides an interface to the file system.</p>
- <p>On operating systems with thread support,
- file operations can be performed in threads of their own, allowing
- other Erlang processes to continue executing in parallel with
- the file operations. See command-line flag
- <c>+A</c> in <seealso marker="erts:erl"><c>erl(1)</c></seealso>.</p>
+ <warning>
+ <p>File operations are only guaranteed to appear atomic when going
+ through the same file server. A NIF or other OS process may observe
+ intermediate steps on certain operations on some operating systems,
+ eg. renaming an existing file on Windows, or
+ <seealso marker="#write_file_info/2"><c>write_file_info/2</c>
+ </seealso> on any OS at the time of writing.</p>
+ </warning>
<p>Regarding filename encoding, the Erlang VM can operate in
two modes. The current mode can be queried using function
- <seealso marker="#native_name_encoding"><c>native_name_encoding/0</c></seealso>.
+ <seealso marker="#native_name_encoding/0"><c>native_name_encoding/0</c></seealso>.
It returns <c>latin1</c> or <c>utf8</c>.</p>
<p>In <c>latin1</c> mode, the Erlang VM does not change the
@@ -59,7 +62,7 @@
terminal supports UTF-8, otherwise <c>latin1</c>. The default can
be overridden using <c>+fnl</c> (to force <c>latin1</c> mode)
or <c>+fnu</c> (to force <c>utf8</c> mode) when starting
- <seealso marker="erts:erl"><c>erts:erl</c></seealso>.</p>
+ <seealso marker="erts:erl"><c>erl</c></seealso>.</p>
<p>On operating systems with transparent naming, files can be
inconsistently named, for example, some files are encoded in UTF-8 while
@@ -81,6 +84,16 @@
<p>See also section <seealso marker="stdlib:unicode_usage#notes-about-raw-filenames">Notes About Raw Filenames</seealso> in the STDLIB User's Guide.</p>
+ <note><p>
+ File operations used to accept filenames containing
+ null characters (integer value zero). This caused
+ the name to be truncated and in some cases arguments
+ to primitive operations to be mixed up. Filenames
+ containing null characters inside the filename
+ are now <em>rejected</em> and will cause primitive
+ file operations fail.
+ </p></note>
+
</description>
<datatypes>
@@ -96,9 +109,21 @@
</datatype>
<datatype>
<name name="filename"/>
+ <desc>
+ <p>
+ See also the documentation of the
+ <seealso marker="#type-name_all"><c>name_all()</c></seealso> type.
+ </p>
+ </desc>
</datatype>
<datatype>
<name name="filename_all"/>
+ <desc>
+ <p>
+ See also the documentation of the
+ <seealso marker="#type-name_all"><c>name_all()</c></seealso> type.
+ </p>
+ </desc>
</datatype>
<datatype>
<name name="io_device"/>
@@ -112,21 +137,23 @@
<name name="name"/>
<desc>
<p>If VM is in Unicode filename mode, <c>string()</c> and <c>char()</c>
- are allowed to be &gt; 255.
+ are allowed to be &gt; 255. See also the documentation of the
+ <seealso marker="#type-name_all"><c>name_all()</c></seealso> type.
</p>
</desc>
</datatype>
<datatype>
<name name="name_all"/>
<desc>
- <p>If VM is in Unicode filename mode, <c>string()</c> and <c>char()</c>
+ <p>If VM is in Unicode filename mode, characters
are allowed to be &gt; 255.
<c><anno>RawFilename</anno></c> is a filename not subject to
Unicode translation,
meaning that it can contain characters not conforming to
the Unicode encoding expected from the file system
(that is, non-UTF-8 characters although the VM is started
- in Unicode filename mode).
+ in Unicode filename mode). Null characters (integer value zero)
+ are <em>not</em> allowed in filenames (not even at the end).
</p>
</desc>
</datatype>
@@ -159,7 +186,7 @@
<funcs>
<func>
- <name name="advise" arity="4"/>
+ <name name="advise" arity="4" since="OTP R14B"/>
<fsummary>Predeclare an access pattern for file data.</fsummary>
<type name="posix_file_advise"/>
<desc>
@@ -170,7 +197,7 @@
</desc>
</func>
<func>
- <name name="allocate" arity="3"/>
+ <name name="allocate" arity="3" since="OTP R16B"/>
<fsummary>Allocate file space.</fsummary>
<desc>
<p><c>allocate/3</c> can be used to preallocate space for a file.</p>
@@ -182,7 +209,7 @@
</desc>
</func>
<func>
- <name name="change_group" arity="2"/>
+ <name name="change_group" arity="2" since=""/>
<fsummary>Change group of a file.</fsummary>
<desc>
<p>Changes group of a file. See
@@ -190,7 +217,7 @@
</desc>
</func>
<func>
- <name name="change_mode" arity="2"/>
+ <name name="change_mode" arity="2" since="OTP R14B"/>
<fsummary>Change permissions of a file.</fsummary>
<desc>
<p>Changes permissions of a file. See
@@ -198,7 +225,7 @@
</desc>
</func>
<func>
- <name name="change_owner" arity="2"/>
+ <name name="change_owner" arity="2" since=""/>
<fsummary>Change owner of a file.</fsummary>
<desc>
<p>Changes owner of a file. See
@@ -206,7 +233,7 @@
</desc>
</func>
<func>
- <name name="change_owner" arity="3"/>
+ <name name="change_owner" arity="3" since=""/>
<fsummary>Change owner and group of a file.</fsummary>
<desc>
<p>Changes owner and group of a file. See
@@ -214,7 +241,7 @@
</desc>
</func>
<func>
- <name name="change_time" arity="2"/>
+ <name name="change_time" arity="2" since=""/>
<fsummary>Change the modification time of a file.</fsummary>
<desc>
<p>Changes the modification and access times of a file. See
@@ -222,7 +249,7 @@
</desc>
</func>
<func>
- <name name="change_time" arity="3"/>
+ <name name="change_time" arity="3" since=""/>
<fsummary>Change the modification and last access time of a file.</fsummary>
<desc>
<p>Changes the modification and last access times of a file. See
@@ -230,7 +257,7 @@
</desc>
</func>
<func>
- <name name="close" arity="1"/>
+ <name name="close" arity="1" since=""/>
<fsummary>Close a file.</fsummary>
<desc>
<p>Closes the file referenced by <c><anno>IoDevice</anno></c>. It mostly
@@ -243,7 +270,7 @@
</desc>
</func>
<func>
- <name name="consult" arity="1"/>
+ <name name="consult" arity="1" since=""/>
<fsummary>Read Erlang terms from a file.</fsummary>
<desc>
<p>Reads Erlang terms, separated by '.', from
@@ -281,8 +308,8 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="copy" arity="2"/>
- <name name="copy" arity="3"/>
+ <name name="copy" arity="2" since=""/>
+ <name name="copy" arity="3" since=""/>
<fsummary>Copy file contents.</fsummary>
<desc>
<p>Copies <c><anno>ByteCount</anno></c> bytes from
@@ -319,7 +346,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="datasync" arity="1"/>
+ <name name="datasync" arity="1" since="OTP R14B"/>
<fsummary>Synchronize the in-memory data of a file, ignoring most of its metadata, with that on the physical medium.</fsummary>
<desc>
<p>Ensures that any buffers kept by the operating system
@@ -342,7 +369,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="del_dir" arity="1"/>
+ <name name="del_dir" arity="1" since=""/>
<fsummary>Delete a directory.</fsummary>
<desc>
<p>Tries to delete directory <c><anno>Dir</anno></c>.
@@ -378,7 +405,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="delete" arity="1"/>
+ <name name="delete" arity="1" since=""/>
<fsummary>Delete a file.</fsummary>
<desc>
<p>Tries to delete file <c><anno>Filename</anno></c>.
@@ -415,7 +442,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="eval" arity="1"/>
+ <name name="eval" arity="1" since=""/>
<fsummary>Evaluate Erlang expressions in a file.</fsummary>
<desc>
<p>Reads and evaluates Erlang expressions, separated by '.' (or
@@ -449,7 +476,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="eval" arity="2"/>
+ <name name="eval" arity="2" since=""/>
<fsummary>Evaluate Erlang expressions in a file.</fsummary>
<desc>
<p>The same as <c>eval/1</c>, but the variable bindings
@@ -459,7 +486,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="format_error" arity="1"/>
+ <name name="format_error" arity="1" since=""/>
<fsummary>Return a descriptive string for an error reason.</fsummary>
<desc>
<p>Given the error reason returned by any function in this
@@ -467,7 +494,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="get_cwd" arity="0"/>
+ <name name="get_cwd" arity="0" since=""/>
<fsummary>Get the current working directory.</fsummary>
<desc>
<p>Returns <c>{ok, <anno>Dir</anno>}</c>, where <c><anno>Dir</anno></c>
@@ -489,7 +516,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="get_cwd" arity="1"/>
+ <name name="get_cwd" arity="1" since=""/>
<fsummary>Get the current working directory for the specified drive.</fsummary>
<desc>
<p>Returns <c>{ok, <anno>Dir</anno>}</c> or
@@ -520,7 +547,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="list_dir" arity="1"/>
+ <name name="list_dir" arity="1" since=""/>
<fsummary>List files in a directory.</fsummary>
<desc>
<p>Lists all files in a directory, <em>except</em> files
@@ -551,7 +578,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="list_dir_all" arity="1"/>
+ <name name="list_dir_all" arity="1" since="OTP R16B"/>
<fsummary>List all files in a directory.</fsummary>
<desc>
<p><marker id="list_dir_all"/>Lists all the files in a directory,
@@ -576,7 +603,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="make_dir" arity="1"/>
+ <name name="make_dir" arity="1" since=""/>
<fsummary>Make a directory.</fsummary>
<desc>
<p>Tries to create directory <c><anno>Dir</anno></c>. Missing parent
@@ -610,7 +637,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="make_link" arity="2"/>
+ <name name="make_link" arity="2" since=""/>
<fsummary>Make a hard link to a file.</fsummary>
<desc>
<p>Makes a hard link from <c><anno>Existing</anno></c> to
@@ -639,7 +666,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="make_symlink" arity="2"/>
+ <name name="make_symlink" arity="2" since=""/>
<fsummary>Make a symbolic link to a file or directory.</fsummary>
<desc>
<p>Creates a symbolic link <c><anno>New</anno></c> to
@@ -675,7 +702,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="native_name_encoding" arity="0"/>
+ <name name="native_name_encoding" arity="0" since="OTP R14B01"/>
<fsummary>Return the configured filename encoding of the VM.</fsummary>
<desc>
<p><marker id="native_name_encoding"/>Returns
@@ -687,7 +714,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="open" arity="2"/>
+ <name name="open" arity="2" since=""/>
<fsummary>Open a file.</fsummary>
<desc>
<p>Opens file <c><anno>File</anno></c> in the mode determined
@@ -954,8 +981,7 @@ f.txt: {person, "kalle", 25}.
</item>
<tag><c>eisdir</c></tag>
<item>
- <p>The named file is not a regular file. It can be a
- directory, a FIFO, or a device.</p>
+ <p>The named file is a directory.</p>
</item>
<tag><c>enotdir</c></tag>
<item>
@@ -971,7 +997,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="path_consult" arity="2"/>
+ <name name="path_consult" arity="2" since=""/>
<fsummary>Read Erlang terms from a file.</fsummary>
<desc>
<p>Searches the path <c><anno>Path</anno></c> (a list of directory
@@ -1013,7 +1039,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="path_eval" arity="2"/>
+ <name name="path_eval" arity="2" since=""/>
<fsummary>Evaluate Erlang expressions in a file.</fsummary>
<desc>
<p>Searches the path <c><anno>Path</anno></c> (a list of directory
@@ -1059,7 +1085,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="path_open" arity="3"/>
+ <name name="path_open" arity="3" since=""/>
<fsummary>Open a file.</fsummary>
<desc>
<p>Searches the path <c><anno>Path</anno></c> (a list of directory
@@ -1088,7 +1114,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="path_script" arity="2"/>
+ <name name="path_script" arity="2" since=""/>
<fsummary>Evaluate and return the value of Erlang expressions in a file.</fsummary>
<desc>
<p>Searches the path <c><anno>Path</anno></c> (a list of directory
@@ -1132,7 +1158,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="path_script" arity="3"/>
+ <name name="path_script" arity="3" since=""/>
<fsummary>Evaluate and return the value of Erlang expressions in a file.</fsummary>
<desc>
<p>The same as <c>path_script/2</c> but the variable bindings
@@ -1142,7 +1168,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="pid2name" arity="1"/>
+ <name name="pid2name" arity="1" since=""/>
<fsummary>Return the name of the file handled by a pid.</fsummary>
<desc>
<p>If <c><anno>Pid</anno></c> is an I/O device, that is, a pid returned from
@@ -1167,7 +1193,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="position" arity="2"/>
+ <name name="position" arity="2" since=""/>
<fsummary>Set position in a file.</fsummary>
<desc>
<p>Sets the position of the file referenced by <c><anno>IoDevice</anno></c>
@@ -1219,7 +1245,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="pread" arity="2"/>
+ <name name="pread" arity="2" since=""/>
<fsummary>Read from a file at certain positions.</fsummary>
<desc>
<p>Performs a sequence of <c>pread/3</c> in one operation,
@@ -1237,7 +1263,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="pread" arity="3"/>
+ <name name="pread" arity="3" since=""/>
<fsummary>Read from a file at a certain position.</fsummary>
<desc>
<p>Combines <c>position/2</c> and <c>read/2</c> in one
@@ -1257,7 +1283,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="pwrite" arity="2"/>
+ <name name="pwrite" arity="2" since=""/>
<fsummary>Write to a file at certain positions.</fsummary>
<desc>
<p>Performs a sequence of <c>pwrite/3</c> in one operation,
@@ -1272,7 +1298,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="pwrite" arity="3"/>
+ <name name="pwrite" arity="3" since=""/>
<fsummary>Write to a file at a certain position.</fsummary>
<desc>
<p>Combines <c>position/2</c> and <c>write/2</c> in one
@@ -1291,7 +1317,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="read" arity="2"/>
+ <name name="read" arity="2" since=""/>
<fsummary>Read from a file.</fsummary>
<desc>
<p>Reads <c><anno>Number</anno></c> bytes/characters from the file
@@ -1345,7 +1371,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="read_file" arity="1"/>
+ <name name="read_file" arity="1" since=""/>
<fsummary>Read a file.</fsummary>
<desc>
<p>Returns <c>{ok, <anno>Binary</anno>}</c>, where
@@ -1381,8 +1407,8 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="read_file_info" arity="1"/>
- <name name="read_file_info" arity="2"/>
+ <name name="read_file_info" arity="1" since=""/>
+ <name name="read_file_info" arity="2" since="OTP R15B"/>
<fsummary>Retrieve information about a file.</fsummary>
<desc>
<p>Retrieves information about a file. Returns
@@ -1407,8 +1433,12 @@ f.txt: {person, "kalle", 25}.
which is 1970-01-01 00:00 UTC.</p></item>
</taglist>
<p>Default is <c>{time, local}</c>.</p>
- <p>If the option <c>raw</c> is set, the file server is not called
- and only information about local files is returned.</p>
+ <p>If the option <c>raw</c> is set, the file server is not called and
+ only information about local files is returned. Note that this will
+ break this module's atomicity guarantees as it can race with a
+ concurrent call to
+ <seealso marker="#write_file_info/2"><c>write_file_info/1,2</c>
+ </seealso></p>
<note>
<p>As file times are stored in POSIX time on most OS, it is faster to
query file information with option <c>posix</c>.</p>
@@ -1532,7 +1562,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="read_line" arity="1"/>
+ <name name="read_line" arity="1" since=""/>
<fsummary>Read a line from a file.</fsummary>
<desc>
<p>Reads a line of bytes/characters from the file referenced by
@@ -1589,7 +1619,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="read_link" arity="1"/>
+ <name name="read_link" arity="1" since=""/>
<fsummary>See what a link is pointing to.</fsummary>
<desc>
<p><marker id="read_link_all"/>Returns
@@ -1619,7 +1649,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="read_link_all" arity="1"/>
+ <name name="read_link_all" arity="1" since="OTP R16B"/>
<fsummary>See what a link is pointing to.</fsummary>
<desc>
<p>Returns <c>{ok, <anno>Filename</anno>}</c> if
@@ -1647,8 +1677,8 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="read_link_info" arity="1"/>
- <name name="read_link_info" arity="2"/>
+ <name name="read_link_info" arity="1" since=""/>
+ <name name="read_link_info" arity="2" since="OTP R15B"/>
<fsummary>Retrieve information about a link or file.</fsummary>
<desc>
<p>Works like
@@ -1656,8 +1686,12 @@ f.txt: {person, "kalle", 25}.
except that if <c><anno>Name</anno></c> is a symbolic link, information
about the link is returned in the <c>file_info</c> record and
the <c>type</c> field of the record is set to <c>symlink</c>.</p>
- <p>If the option <c>raw</c> is set, the file server is not called
- and only information about local files is returned.</p>
+ <p>If the option <c>raw</c> is set, the file server is not called and
+ only information about local files is returned. Note that this will
+ break this module's atomicity guarantees as it can race with a
+ concurrent call to
+ <seealso marker="#write_file_info/2"><c>write_file_info/1,2</c>
+ </seealso></p>
<p>If <c><anno>Name</anno></c> is not a symbolic link, this function returns
the same result as <c>read_file_info/1</c>.
On platforms that do not support symbolic links, this function
@@ -1665,7 +1699,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="rename" arity="2"/>
+ <name name="rename" arity="2" since=""/>
<fsummary>Rename a file.</fsummary>
<desc>
<p>Tries to rename the file <c><anno>Source</anno></c> to
@@ -1728,7 +1762,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="script" arity="1"/>
+ <name name="script" arity="1" since=""/>
<fsummary>Evaluate and return the value of Erlang expressions in a file.</fsummary>
<desc>
<p>Reads and evaluates Erlang expressions, separated by '.' (or
@@ -1763,7 +1797,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="script" arity="2"/>
+ <name name="script" arity="2" since=""/>
<fsummary>Evaluate and return the value of Erlang expressions in a file.</fsummary>
<desc>
<p>The same as <c>script/1</c> but the variable bindings
@@ -1773,7 +1807,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="sendfile" arity="2"/>
+ <name name="sendfile" arity="2" since="OTP R15B"/>
<fsummary>Send a file to a socket.</fsummary>
<desc>
<p>Sends the file <c>Filename</c> to <c>Socket</c>.
@@ -1782,7 +1816,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="sendfile" arity="5"/>
+ <name name="sendfile" arity="5" since="OTP R15B"/>
<fsummary>Send a file to a socket.</fsummary>
<type name="sendfile_option"/>
<desc>
@@ -1795,29 +1829,21 @@ f.txt: {person, "kalle", 25}.
<p>The file used must be opened using the <c>raw</c> flag, and the process
calling <c>sendfile</c> must be the controlling process of the socket.
See <seealso marker="gen_tcp#controlling_process-2"><c>gen_tcp:controlling_process/2</c></seealso>.</p>
- <p>If the OS used does not support <c>sendfile</c>, an Erlang fallback
- using
- <seealso marker="#read/2"><c>read/2</c></seealso> and
- <seealso marker="gen_tcp#send/2"><c>gen_tcp:send/2</c></seealso> is used.</p>
+ <p>If the OS used does not support non-blocking <c>sendfile</c>, an
+ Erlang fallback using <seealso marker="#read/2"><c>read/2</c></seealso>
+ and <seealso marker="gen_tcp#send/2"><c>gen_tcp:send/2</c></seealso> is
+ used.</p>
<p>The option list can contain the following options:</p>
<taglist>
<tag><c>chunk_size</c></tag>
<item><p>The chunk size used by the Erlang fallback to send
data. If using the fallback, set this to a value
that comfortably fits in the systems memory. Default is 20 MB.</p></item>
- <tag><c>use_threads</c></tag>
- <item><p>Instructs the emulator to use the <c>async</c> thread pool for the
- <c>sendfile</c> system call. This can be useful if the OS you are running
- on does not properly support non-blocking <c>sendfile</c> calls. Notice that
- using <c>async</c> threads potentially makes your system vulnerable to slow
- client attacks. If set to <c>true</c> and no <c>async</c> threads are available,
- the <c>sendfile</c> call returns <c>{error,einval}</c>.
- Introduced in Erlang/OTP 17.0. Default is <c>false</c>.</p></item>
</taglist>
</desc>
</func>
<func>
- <name name="set_cwd" arity="1"/>
+ <name name="set_cwd" arity="1" since=""/>
<fsummary>Set the current working directory.</fsummary>
<desc>
<p>Sets the current working directory of the file server to
@@ -1825,7 +1851,7 @@ f.txt: {person, "kalle", 25}.
<p>The functions in the module <c>file</c> usually treat binaries
as raw filenames, that is, they are passed "as is" even when the
encoding of the binary does not agree with
- <seealso marker="#native_name_encoding"><c>native_name_encoding()</c></seealso>.
+ <seealso marker="#native_name_encoding/0"><c>native_name_encoding()</c></seealso>.
However, this function expects binaries to be encoded according to the
value returned by <c>native_name_encoding()</c>.</p>
<p>Typical error reasons are:</p>
@@ -1864,7 +1890,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="sync" arity="1"/>
+ <name name="sync" arity="1" since=""/>
<fsummary>Synchronize the in-memory state of a file with that on the physical medium.</fsummary>
<desc>
<p>Ensures that any buffers kept by the operating system
@@ -1880,7 +1906,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="truncate" arity="1"/>
+ <name name="truncate" arity="1" since=""/>
<fsummary>Truncate a file.</fsummary>
<desc>
<p>Truncates the file referenced by <c><anno>IoDevice</anno></c> at
@@ -1889,7 +1915,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="write" arity="2"/>
+ <name name="write" arity="2" since=""/>
<fsummary>Write to a file.</fsummary>
<desc>
<p>Writes <c><anno>Bytes</anno></c> to the file referenced by
@@ -1915,7 +1941,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="write_file" arity="2"/>
+ <name name="write_file" arity="2" since=""/>
<fsummary>Write a file.</fsummary>
<desc>
<p>Writes the contents of the <c>iodata</c> term <c><anno>Bytes</anno></c>
@@ -1952,7 +1978,7 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="write_file" arity="3"/>
+ <name name="write_file" arity="3" since=""/>
<fsummary>Write a file.</fsummary>
<desc>
<p>Same as <c>write_file/2</c>, but takes a third argument
@@ -1963,8 +1989,8 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
- <name name="write_file_info" arity="2"/>
- <name name="write_file_info" arity="3"/>
+ <name name="write_file_info" arity="2" since=""/>
+ <name name="write_file_info" arity="3" since="OTP R15B"/>
<fsummary>Change file information.</fsummary>
<desc>
<p>Changes file information. Returns <c>ok</c> if successful,
@@ -2117,144 +2143,77 @@ f.txt: {person, "kalle", 25}.
<section>
<title>Performance</title>
- <p>Some operating system file operations, for example, a
- <c>sync/1</c> or <c>close/1</c> on a huge file, can block their
- calling thread for seconds. If this affects the emulator main
- thread, the response time is no longer in the order of
- milliseconds, depending on the definition of "soft" in soft
- real-time system.</p>
- <p>If the device driver thread pool is active, file operations are
- done through those threads instead, so the emulator can go on
- executing Erlang processes. Unfortunately, the time for serving a
- file operation increases because of the extra scheduling required
- from the operating system.</p>
- <p>If the device driver thread pool is disabled or of size 0, large
- file reads and writes are segmented into many smaller, which
- enable the emulator to serve other processes during the file
- operation. This has the same effect as when using the thread
- pool, but with larger overhead. Other file operations, for
- example, <c>sync/1</c> or <c>close/1</c> on a huge file, still are
- a problem.</p>
- <p>For increased performance, raw files are recommended. Raw files
- use the file system of the host machine of the node.</p>
+ <p>For increased performance, raw files are recommended.</p>
+ <p>A normal file is really a process so it can be used as an I/O
+ device (see <seealso marker="stdlib:io"><c>io</c></seealso>).
+ Therefore, when data is written to a normal file, the sending of the
+ data to the file process, copies all data that are not binaries. Opening
+ the file in binary mode and writing binaries is therefore recommended.
+ If the file is opened on another node, or if the file server runs as
+ slave to the file server of another node, also binaries are copied.</p>
<note>
- <p>
- For normal files (non-raw), the file server is used to find the files,
- and if the node is running its file server as slave to the file server
- of another node, and the other node runs on some other host machine,
- they can have different file systems.
- However, this is seldom a problem.</p>
+ <p>Raw files use the file system of the host machine of the node.
+ For normal files (non-raw), the file server is used to find the files,
+ and if the node is running its file server as slave to the file server
+ of another node, and the other node runs on some other host machine,
+ they can have different file systems.
+ However, this is seldom a problem.</p>
</note>
- <p>A normal file is really a process so it can be used as an I/O
- device (see
- <seealso marker="stdlib:io"><c>io</c></seealso>).
- Therefore, when data is written to a
- normal file, the sending of the data to the file process, copies
- all data that are not binaries. Opening the file in binary mode
- and writing binaries is therefore recommended. If the file is
- opened on another node, or if the file server runs as slave to
- the file server of another node, also binaries are copied.</p>
- <p>Caching data to reduce the number of file operations, or rather
- the number of calls to the file driver, generally increases
- performance. The following function writes 4 MBytes in 23
- seconds when tested:</p>
+ <p><seealso marker="#open/2"><c>open/2</c></seealso> can be given the
+ options <c>delayed_write</c> and <c>read_ahead</c> to turn on caching,
+ which will reduce the number of operating system calls and greatly
+ improve performance for small reads and writes. However, the overhead
+ won't disappear completely and it's best to keep the number of file
+ operations to a minimum. As a contrived example, the following function
+ writes 4MB in 2.5 seconds when tested:</p>
+
<code type="none"><![CDATA[
-create_file_slow(Name, N) when integer(N), N >= 0 ->
- {ok, FD} = file:open(Name, [raw, write, delayed_write, binary]),
- ok = create_file_slow(FD, 0, N),
- ok = ?FILE_MODULE:close(FD),
- ok.
-
-create_file_slow(FD, M, M) ->
+create_file_slow(Name) ->
+ {ok, Fd} = file:open(Name, [raw, write, delayed_write, binary]),
+ create_file_slow_1(Fd, 4 bsl 20),
+ file:close(Fd).
+
+create_file_slow_1(_Fd, 0) ->
ok;
-create_file_slow(FD, M, N) ->
- ok = file:write(FD, <<M:32/unsigned>>),
- create_file_slow(FD, M+1, N).]]></code>
+create_file_slow_1(Fd, M) ->
+ ok = file:write(Fd, <<0>>),
+ create_file_slow_1(Fd, M - 1).]]></code>
+
+ <p>The following functionally equivalent code writes 128 bytes per call
+ to <seealso marker="#write/2"><c>write/2</c></seealso> and so does the
+ same work in 0.08 seconds, which is roughly 30 times faster:</p>
- <p>The following, functionally equivalent, function collects 1024
- entries into a list of 128 32-byte binaries before each call to
- <seealso marker="#write/2"><c>write/2</c></seealso> and so
- does the same work in 0.52 seconds,
- which is 44 times faster:</p>
<code type="none"><![CDATA[
-create_file(Name, N) when integer(N), N >= 0 ->
- {ok, FD} = file:open(Name, [raw, write, delayed_write, binary]),
- ok = create_file(FD, 0, N),
- ok = ?FILE_MODULE:close(FD),
+create_file(Name) ->
+ {ok, Fd} = file:open(Name, [raw, write, delayed_write, binary]),
+ create_file_1(Fd, 4 bsl 20),
+ file:close(Fd),
ok.
-
-create_file(FD, M, M) ->
+
+create_file_1(_Fd, 0) ->
ok;
-create_file(FD, M, N) when M + 1024 =&lt; N ->
- create_file(FD, M, M + 1024, []),
- create_file(FD, M + 1024, N);
-create_file(FD, M, N) ->
- create_file(FD, M, N, []).
-
-create_file(FD, M, M, R) ->
- ok = file:write(FD, R);
-create_file(FD, M, N0, R) when M + 8 =&lt; N0 ->
- N1 = N0-1, N2 = N0-2, N3 = N0-3, N4 = N0-4,
- N5 = N0-5, N6 = N0-6, N7 = N0-7, N8 = N0-8,
- create_file(FD, M, N8,
- [<<N8:32/unsigned, N7:32/unsigned,
- N6:32/unsigned, N5:32/unsigned,
- N4:32/unsigned, N3:32/unsigned,
- N2:32/unsigned, N1:32/unsigned>> | R]);
-create_file(FD, M, N0, R) ->
- N1 = N0-1,
- create_file(FD, M, N1, [<<N1:32/unsigned>> | R]).]]></code>
+create_file_1(Fd, M) when M >= 128 ->
+ ok = file:write(Fd, <<0:(128)/unit:8>>),
+ create_file_1(Fd, M - 128);
+create_file_1(Fd, M) ->
+ ok = file:write(Fd, <<0:(M)/unit:8>>),
+ create_file_1(Fd, M - 1).]]></code>
- <note>
- <p>Trust only your own benchmarks. If the list length in
- <c>create_file/2</c> above is increased, it runs slightly
- faster, but consumes more memory and causes more memory
- fragmentation. How much this affects your application is
- something that this simple benchmark cannot predict.</p>
- <p>If the size of each binary is increased to 64 bytes, it
- also runs slightly faster, but the code is then twice as clumsy.
- In the current implementation, binaries larger than 64 bytes are
- stored in memory common to all processes and not copied when
- sent between processes, while these smaller binaries are stored
- on the process heap and copied when sent like any other term.</p>
- <p>So, with a binary size of 68 bytes, <c>create_file/2</c> runs
- 30 percent slower than with 64 bytes, and causes much more
- memory fragmentation. Notice that if the binaries were to be sent
- between processes (for example, a non-raw file), the results
- would probably be completely different.</p>
- </note>
- <p>A raw file is really a port. When writing data to a port, it is
- efficient to write a list of binaries. It is not needed to
- flatten a deep list before writing. On Unix hosts, scatter output,
- which writes a set of buffers in one operation, is used when
- possible. In this way <c>write(FD, [Bin1, Bin2 | Bin3])</c>
- writes the contents of the binaries without copying the data
- at all, except for perhaps deep down in the operating system
- kernel.</p>
- <p>For raw files, <c>pwrite/2</c> and <c>pread/2</c> are
- efficiently implemented. The file driver is called only once for
- the whole operation, and the list iteration is done in the file
- driver.</p>
- <p>The options <c>delayed_write</c> and <c>read_ahead</c> to
- <seealso marker="#open/2"><c>open/2</c></seealso>
- make the file driver cache data to reduce
- the number of operating system calls. The function
- <c>create_file/2</c> in the recent example takes 60 seconds
- without option <c>delayed_write</c>, which is 2.6
- times slower.</p>
- <p>As a bad example, <c>create_file_slow/2</c>
- without options <c>raw</c>, <c>binary</c>, and <c>delayed_write</c>,
- meaning it calls <c>open(Name, [write])</c>, needs
- 1 min 20 seconds for the job, which is 3.5 times slower than
- the first example, and 150 times slower than the optimized
- <c>create_file/2</c>.</p>
- <warning>
- <p>If an error occurs when accessing an open file with module
- <seealso marker="stdlib:io"><c>io</c></seealso>,
- the process handling the file exits. The dead
- file process can hang if a process tries to access it later.
- This will be fixed in a future release.</p>
- </warning>
+ <p>When writing data it's generally more efficient to write a list of
+ binaries rather than a list of integers. It is not needed to
+ flatten a deep list before writing. On Unix hosts, scatter output,
+ which writes a set of buffers in one operation, is used when
+ possible. In this way <c>write(FD, [Bin1, Bin2 | Bin3])</c>
+ writes the contents of the binaries without copying the data
+ at all, except for perhaps deep down in the operating system
+ kernel.</p>
+ <warning>
+ <p>If an error occurs when accessing an open file with module
+ <seealso marker="stdlib:io"><c>io</c></seealso>, the process
+ handling the file exits. The dead file process can hang if a process
+ tries to access it later. This will be fixed in a future release.
+ </p>
+ </warning>
</section>
<section>
diff --git a/lib/kernel/doc/src/gen_sctp.xml b/lib/kernel/doc/src/gen_sctp.xml
index 737800c6b1..61ac1485c1 100644
--- a/lib/kernel/doc/src/gen_sctp.xml
+++ b/lib/kernel/doc/src/gen_sctp.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2007</year><year>2016</year>
+ <year>2007</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>gen_sctp.xml</file>
</header>
- <module>gen_sctp</module>
+ <module since="">gen_sctp</module>
<modulesummary>Functions for communicating with sockets using the SCTP
protocol.</modulesummary>
<description>
@@ -100,7 +100,7 @@
<funcs>
<func>
- <name name="abort" arity="2"/>
+ <name name="abort" arity="2" since=""/>
<fsummary>Abnormally terminate the association specified by
<c>Assoc</c>, without flushing of unsent data.</fsummary>
<desc>
@@ -113,7 +113,7 @@
</func>
<func>
- <name name="close" arity="1"/>
+ <name name="close" arity="1" since=""/>
<fsummary>Close the socket and all associations on it.</fsummary>
<desc>
<p>Closes the socket and all associations on it. The unsent
@@ -128,7 +128,7 @@
</func>
<func>
- <name name="connect" arity="4"/>
+ <name name="connect" arity="4" since=""/>
<fsummary>Same as <c>connect(Socket, Addr, Port, Opts, infinity)</c>.</fsummary>
<desc>
<p>Same as <c>connect(<anno>Socket</anno>, <anno>Addr</anno>,
@@ -137,7 +137,7 @@
</func>
<func>
- <name name="connect" arity="5"/>
+ <name name="connect" arity="5" since=""/>
<fsummary>Establish a new association for socket <c>Socket</c>, with a
peer (SCTP server socket).</fsummary>
<desc>
@@ -213,7 +213,7 @@ connect(Socket, Ip, Port>,
</func>
<func>
- <name name="connect_init" arity="4"/>
+ <name name="connect_init" arity="4" since="OTP R13B04"/>
<fsummary>Same as <c>connect_init(Socket, Addr, Port, Opts, infinity)</c>..</fsummary>
<desc>
<p>Same as <c>connect_init(<anno>Socket</anno>, <anno>Addr</anno>,
@@ -222,7 +222,7 @@ connect(Socket, Ip, Port>,
</func>
<func>
- <name name="connect_init" arity="5"/>
+ <name name="connect_init" arity="5" since="OTP R13B04"/>
<fsummary>Initiate a new association for socket <c>Socket</c>, with a
peer (SCTP server socket).</fsummary>
<desc>
@@ -248,18 +248,18 @@ connect(Socket, Ip, Port>,
</func>
<func>
- <name name="controlling_process" arity="2"/>
+ <name name="controlling_process" arity="2" since=""/>
<fsummary>Assign a new controlling process pid to the socket.</fsummary>
<desc>
<p>Assigns a new controlling process <c><anno>Pid</anno></c> to
<c><anno>Socket</anno></c>. Same implementation as
- <seealso marker="gen_udp:controlling_process/2"><c>gen_udp:controlling_process/2</c></seealso>.
+ <seealso marker="gen_udp#controlling_process/2"><c>gen_udp:controlling_process/2</c></seealso>.
</p>
</desc>
</func>
<func>
- <name name="eof" arity="2"/>
+ <name name="eof" arity="2" since=""/>
<fsummary>Gracefully terminate the association specified by <c>Assoc</c>,
with flushing of all unsent data.</fsummary>
<desc>
@@ -272,7 +272,7 @@ connect(Socket, Ip, Port>,
</func>
<func>
- <name name="error_string" arity="1"/>
+ <name name="error_string" arity="1" since=""/>
<fsummary>Translate an SCTP error number into a string.</fsummary>
<desc>
<p>Translates an SCTP error number from, for example,
@@ -283,8 +283,8 @@ connect(Socket, Ip, Port>,
</func>
<func>
- <name name="listen" arity="2" clause_i="1"/>
- <name name="listen" arity="2" clause_i="2"/>
+ <name name="listen" arity="2" clause_i="1" since=""/>
+ <name name="listen" arity="2" clause_i="2" since="OTP R15B"/>
<fsummary>Set up a socket to listen.</fsummary>
<desc>
<p>Sets up a socket to listen on the IP address and port number
@@ -300,10 +300,10 @@ connect(Socket, Ip, Port>,
</func>
<func>
- <name name="open" arity="0"/>
- <name name="open" arity="1" clause_i="1"/>
- <name name="open" arity="1" clause_i="2"/>
- <name name="open" arity="2"/>
+ <name name="open" arity="0" since=""/>
+ <name name="open" arity="1" clause_i="1" since=""/>
+ <name name="open" arity="1" clause_i="2" since=""/>
+ <name name="open" arity="2" since=""/>
<fsummary>Create an SCTP socket and binds it to local addresses.</fsummary>
<desc>
<p>Creates an SCTP socket and binds it to the local addresses
@@ -331,11 +331,42 @@ connect(Socket, Ip, Port>,
with <anno>SockType</anno> <c>seqpacket</c>, and with reasonably large
<seealso marker="inet#option-sndbuf">kernel</seealso> and driver
<seealso marker="inet#option-buffer">buffers</seealso>.</p>
+ <p>
+ If the socket is in
+ <seealso marker="#option-active">passive</seealso>
+ mode data can be received through the
+ <seealso marker="#recv/1"><c>recv/1,2</c></seealso>
+ calls.
+ </p>
+ <p>
+ If the socket is in
+ <seealso marker="#option-active">active</seealso>
+ mode data received data is delivered to the controlling process
+ as messages:
+ </p>
+ <code type="none">
+{sctp, <anno>Socket</anno>, FromIP, FromPort, {AncData, Data}}
+ </code>
+ <p>
+ See
+ <seealso marker="#recv/1"><c>recv/1,2</c></seealso>
+ for a description of the message fields.
+ </p>
+ <note>
+ <p>
+ This message format unfortunately differs slightly from the
+ <seealso marker="gen_udp#open/1"><c>gen_udp</c></seealso>
+ message format with ancillary data,
+ and from the
+ <seealso marker="#recv/1"><c>recv/1,2</c></seealso>
+ return tuple format.
+ </p>
+ </note>
</desc>
</func>
<func>
- <name name="peeloff" arity="2"/>
+ <name name="peeloff" arity="2" since="OTP R15B"/>
<fsummary>Peel off a type <c>stream</c> socket from a type
<c>seqpacket</c> one.</fsummary>
<desc>
@@ -356,8 +387,8 @@ connect(Socket, Ip, Port>,
</func>
<func>
- <name name="recv" arity="1"/>
- <name name="recv" arity="2"/>
+ <name name="recv" arity="1" since=""/>
+ <name name="recv" arity="2" since=""/>
<fsummary>Receive a message from a socket.</fsummary>
<desc>
<p>Receives the <c><anno>Data</anno></c> message from any association
@@ -380,6 +411,19 @@ connect(Socket, Ip, Port>,
socket option
<seealso marker="#option-sctp_get_peer_addr_info"><c>sctp_get_peer_addr_info</c></seealso>,
but this does still not produce the stream number).</p>
+ <p>
+ <c><anno>AncData</anno></c> may also contain
+ <seealso marker="inet#type-ancillary_data">
+ ancillary data
+ </seealso>
+ from the socket
+ <seealso marker="#type-option">options</seealso>
+ <seealso marker="inet#option-recvtos"><c>recvtos</c></seealso>,
+ <seealso marker="inet#option-recvtclass"><c>recvtclass</c></seealso>
+ or
+ <seealso marker="inet#option-recvttl"><c>recvttl</c></seealso>,
+ if that is supported by the platform for the socket.
+ </p>
<p>The <c><anno>Data</anno></c> received can be a <c>binary()</c>
or a <c>list()</c> of bytes (integers in the range 0 through 255)
depending on the socket mode, or an SCTP event.</p>
@@ -488,7 +532,7 @@ connect(Socket, Ip, Port>,
</func>
<func>
- <name name="send" arity="3"/>
+ <name name="send" arity="3" since=""/>
<fsummary>Send a message using an <c>#sctp_sndrcvinfo{}</c>record.</fsummary>
<desc>
<p>Sends the <c><anno>Data</anno></c> message with all sending
@@ -503,7 +547,7 @@ connect(Socket, Ip, Port>,
</func>
<func>
- <name name="send" arity="4"/>
+ <name name="send" arity="4" since=""/>
<fsummary>Send a message over an existing association and specified
stream.</fsummary>
<desc>
@@ -544,12 +588,25 @@ connect(Socket, Ip, Port>,
<seealso marker="#recv/1"><c>recv</c></seealso> call
to retrieve the available data from the socket.</p>
</item>
+ <item>
+ <p>
+ If <c>true|once|N</c> (active modes)
+ received data or events are sent to the owning process.
+ See <seealso marker="#open/0"><c>open/0..2</c></seealso>
+ for the message format.
+ </p>
+ </item>
<item>
- <p>If <c>true</c> (full active mode), the pending data or events are
- sent to the owning process.</p>
- <p>Notice that this can cause the message queue to overflow,
- as there is no way to throttle the sender in this case
- (no flow control).</p>
+ <p>
+ If <c>true</c> (full active mode) there is no flow control.
+ </p>
+ <note>
+ <p>
+ Note that this can cause the message queue to overflow
+ causing for example the virtual machine
+ to run out of memory and crash.
+ </p>
+ </note>
</item>
<item>
<p>If <c>once</c>, only one message is automatically placed
diff --git a/lib/kernel/doc/src/gen_tcp.xml b/lib/kernel/doc/src/gen_tcp.xml
index e6104b0c76..f8b41d24e2 100644
--- a/lib/kernel/doc/src/gen_tcp.xml
+++ b/lib/kernel/doc/src/gen_tcp.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2017</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -27,7 +27,7 @@
<date>1997-10-24</date>
<rev>A</rev>
</header>
- <module>gen_tcp</module>
+ <module since="">gen_tcp</module>
<modulesummary>Interface to TCP/IP sockets.</modulesummary>
<description>
<p>This module provides functions for communicating
@@ -70,6 +70,32 @@ do_recv(Sock, Bs) ->
<name name="option"/>
</datatype>
<datatype>
+ <name name="pktoptions_value"/>
+ <desc>
+ <p>
+ If the platform implements the IPv4 option
+ <c>IP_PKTOPTIONS</c>, or the IPv6 option
+ <c>IPV6_PKTOPTIONS</c> or <c>IPV6_2292PKTOPTIONS</c> for the socket
+ this value is returned from
+ <seealso marker="inet#getopts/2"><c>inet:getopts/2</c></seealso>
+ when called with the option name
+ <seealso marker="#type-option_name"><c>pktoptions</c></seealso>.
+ </p>
+ <note>
+ <p>
+ This option appears to be VERY Linux specific,
+ and its existence in future Linux kernel versions
+ is also worrying since the option is part of RFC 2292
+ which is since long (2003) obsoleted by RFC 3542
+ that <em>explicitly</em> removes this possibility to get
+ packet information from a stream socket.
+ For comparision: it has existed in FreeBSD but is now removed,
+ at least since FreeBSD 10.
+ </p>
+ </note>
+ </desc>
+ </datatype>
+ <datatype>
<name name="option_name"/>
</datatype>
<datatype>
@@ -90,8 +116,8 @@ do_recv(Sock, Bs) ->
<funcs>
<func>
- <name name="accept" arity="1"/>
- <name name="accept" arity="2"/>
+ <name name="accept" arity="1" since=""/>
+ <name name="accept" arity="2" since=""/>
<fsummary>Accept an incoming connection request on a listening socket.</fsummary>
<type_desc variable="ListenSocket">Returned by
<seealso marker="#listen/2"><c>listen/2</c></seealso>.
@@ -137,7 +163,7 @@ do_recv(Sock, Bs) ->
</func>
<func>
- <name name="close" arity="1"/>
+ <name name="close" arity="1" since=""/>
<fsummary>Close a TCP socket.</fsummary>
<desc>
<p>Closes a TCP socket.</p>
@@ -162,8 +188,8 @@ do_recv(Sock, Bs) ->
</func>
<func>
- <name name="connect" arity="3"/>
- <name name="connect" arity="4"/>
+ <name name="connect" arity="3" since=""/>
+ <name name="connect" arity="4" since=""/>
<fsummary>Connect to a TCP port.</fsummary>
<desc>
<p>Connects to a server on TCP port <c><anno>Port</anno></c> on the host
@@ -233,6 +259,12 @@ do_recv(Sock, Bs) ->
<p>The optional <c><anno>Timeout</anno></c> parameter specifies a
time-out in milliseconds. Defaults to <c>infinity</c>.</p>
<note>
+ <p>Keep in mind that if the underlying OS <c>connect()</c> call returns
+ a timeout, <c>gen_tcp:connect</c> will also return a timeout
+ (i.e. <c>{error, etimedout}</c>), even if a larger <c>Timeout</c> was
+ specified.</p>
+ </note>
+ <note>
<p>The default values for options specified to <c>connect</c> can
be affected by the Kernel configuration parameter
<c>inet_default_connect_options</c>. For details, see
@@ -242,7 +274,7 @@ do_recv(Sock, Bs) ->
</func>
<func>
- <name name="controlling_process" arity="2"/>
+ <name name="controlling_process" arity="2" since=""/>
<fsummary>Change controlling process of a socket.</fsummary>
<desc>
<p>Assigns a new controlling process <c><anno>Pid</anno></c> to
@@ -266,7 +298,7 @@ do_recv(Sock, Bs) ->
</func>
<func>
- <name name="listen" arity="2"/>
+ <name name="listen" arity="2" since=""/>
<fsummary>Set up a socket to listen on a port.</fsummary>
<desc>
<p>Sets up a socket to listen on port <c><anno>Port</anno></c> on
@@ -323,8 +355,8 @@ do_recv(Sock, Bs) ->
</func>
<func>
- <name name="recv" arity="2"/>
- <name name="recv" arity="3"/>
+ <name name="recv" arity="2" since=""/>
+ <name name="recv" arity="3" since=""/>
<fsummary>Receive a packet from a passive socket.</fsummary>
<type_desc variable="HttpPacket">See the description of
<c>HttpPacket</c> in
@@ -349,7 +381,7 @@ do_recv(Sock, Bs) ->
</func>
<func>
- <name name="send" arity="2"/>
+ <name name="send" arity="2" since=""/>
<fsummary>Send a packet.</fsummary>
<desc>
<p>Sends a packet on a socket.</p>
@@ -360,7 +392,7 @@ do_recv(Sock, Bs) ->
</func>
<func>
- <name name="shutdown" arity="2"/>
+ <name name="shutdown" arity="2" since=""/>
<fsummary>Asynchronously close a socket.</fsummary>
<desc>
<p>Closes a socket in one or two directions.</p>
diff --git a/lib/kernel/doc/src/gen_udp.xml b/lib/kernel/doc/src/gen_udp.xml
index f79566ef71..d20fc1fdfd 100644
--- a/lib/kernel/doc/src/gen_udp.xml
+++ b/lib/kernel/doc/src/gen_udp.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -28,7 +28,7 @@
<date>1997-12-03</date>
<rev>A</rev>
</header>
- <module>gen_udp</module>
+ <module since="">gen_udp</module>
<modulesummary>Interface to UDP sockets.</modulesummary>
<description>
<p>This module provides functions for communicating
@@ -53,7 +53,7 @@
<funcs>
<func>
- <name name="close" arity="1"/>
+ <name name="close" arity="1" since=""/>
<fsummary>Close a UDP socket.</fsummary>
<desc>
<p>Closes a UDP socket.</p>
@@ -61,7 +61,7 @@
</func>
<func>
- <name name="controlling_process" arity="2"/>
+ <name name="controlling_process" arity="2" since=""/>
<fsummary>Change controlling process of a socket.</fsummary>
<desc>
<p>Assigns a new controlling process <c><anno>Pid</anno></c> to
@@ -77,8 +77,8 @@
</func>
<func>
- <name name="open" arity="1"/>
- <name name="open" arity="2"/>
+ <name name="open" arity="1" since=""/>
+ <name name="open" arity="2" since=""/>
<fsummary>Associate a UDP port number with the process calling it.</fsummary>
<desc>
<p>Associates a UDP port number (<c><anno>Port</anno></c>) with the
@@ -147,7 +147,21 @@
at the opened port, if the socket is in an active mode, the packets
are delivered as messages to the controlling process:</p>
<code type="none">
-{udp, Socket, IP, InPortNo, Packet}</code>
+{udp, Socket, IP, InPortNo, Packet} % Without ancillary data
+{udp, Socket, IP, InPortNo, AncData, Packet} % With ancillary data
+ </code>
+ <p>
+ The message contains an <c>AncData</c> field
+ if any of the socket
+ <seealso marker="#type-option">options</seealso>
+ <seealso marker="inet#option-recvtos"><c>recvtos</c></seealso>,
+ <seealso marker="inet#option-recvtclass"><c>recvtclass</c></seealso>
+ or
+ <seealso marker="inet#option-recvttl"><c>recvttl</c></seealso>
+ are active, otherwise it does not.
+ </p>
+ <p>
+ </p>
<p>If the socket is not in an active mode, data can be
retrieved through the
<seealso marker="#recv/2"><c>recv/2,3</c></seealso> calls.
@@ -175,18 +189,31 @@
</func>
<func>
- <name name="recv" arity="2"/>
- <name name="recv" arity="3"/>
+ <name name="recv" arity="2" since=""/>
+ <name name="recv" arity="3" since=""/>
<fsummary>Receive a packet from a passive socket.</fsummary>
<desc>
- <p>Receives a packet from a socket in passive mode. Optional parameter
+ <p>
+ Receives a packet from a socket in passive mode. Optional parameter
<c><anno>Timeout</anno></c> specifies a time-out in milliseconds.
- Defaults to <c>infinity</c>.</p>
+ Defaults to <c>infinity</c>.
+ </p>
+ <p>
+ If any of the socket
+ <seealso marker="#type-option">options</seealso>
+ <seealso marker="inet#option-recvtos"><c>recvtos</c></seealso>,
+ <seealso marker="inet#option-recvtclass"><c>recvtclass</c></seealso>
+ or
+ <seealso marker="inet#option-recvttl"><c>recvttl</c></seealso>
+ are active, the <c><anno>RecvData</anno></c> tuple contains an
+ <c><anno>AncData</anno></c> field,
+ otherwise it does not.
+ </p>
</desc>
</func>
<func>
- <name name="send" arity="4"/>
+ <name name="send" arity="4" since=""/>
<fsummary>Send a packet.</fsummary>
<desc>
<p>
diff --git a/lib/kernel/doc/src/global.xml b/lib/kernel/doc/src/global.xml
index 4442741f54..dfe71de5ce 100644
--- a/lib/kernel/doc/src/global.xml
+++ b/lib/kernel/doc/src/global.xml
@@ -28,7 +28,7 @@
<date>1997-11-17</date>
<rev></rev>
</header>
- <module>global</module>
+ <module since="">global</module>
<modulesummary>A global name registration facility.</modulesummary>
<description>
<p>This module consists of the following services:</p>
@@ -100,8 +100,8 @@
<funcs>
<func>
- <name name="del_lock" arity="1"/>
- <name name="del_lock" arity="2"/>
+ <name name="del_lock" arity="1" since=""/>
+ <name name="del_lock" arity="2" since=""/>
<fsummary>Delete a lock.</fsummary>
<desc>
<p>Deletes the lock <c><anno>Id</anno></c> synchronously.</p>
@@ -109,7 +109,7 @@
</func>
<func>
- <name name="notify_all_name" arity="3"/>
+ <name name="notify_all_name" arity="3" since=""/>
<fsummary>Name resolving function that notifies both pids.</fsummary>
<desc>
<p>Can be used as a name resolving function for
@@ -123,7 +123,7 @@
</func>
<func>
- <name name="random_exit_name" arity="3"/>
+ <name name="random_exit_name" arity="3" since=""/>
<fsummary>Name resolving function that kills one pid.</fsummary>
<desc>
<p>Can be used as a name resolving function for
@@ -136,7 +136,7 @@
</func>
<func>
- <name name="random_notify_name" arity="3"/>
+ <name name="random_notify_name" arity="3" since=""/>
<fsummary>Name resolving function that notifies one pid.</fsummary>
<desc>
<p>Can be used as a name resolving function for
@@ -150,8 +150,8 @@
</func>
<func>
- <name name="re_register_name" arity="2"/>
- <name name="re_register_name" arity="3"/>
+ <name name="re_register_name" arity="2" since=""/>
+ <name name="re_register_name" arity="3" since=""/>
<fsummary>Atomically re-register a name.</fsummary>
<type name="method"/>
<type_desc name="method">{<c>Module</c>, <c>Function</c>}
@@ -167,8 +167,8 @@
</func>
<func>
- <name name="register_name" arity="2"/>
- <name name="register_name" arity="3"/>
+ <name name="register_name" arity="2" since=""/>
+ <name name="register_name" arity="3" since=""/>
<fsummary>Globally register a name for a pid.</fsummary>
<type name="method"/>
<type_desc name="method">{<c>Module</c>, <c>Function</c>} is also
@@ -221,7 +221,7 @@
</func>
<func>
- <name name="registered_names" arity="0"/>
+ <name name="registered_names" arity="0" since=""/>
<fsummary>All globally registered names.</fsummary>
<desc>
<p>Returns a list of all globally registered names.</p>
@@ -229,7 +229,7 @@
</func>
<func>
- <name name="send" arity="2"/>
+ <name name="send" arity="2" since=""/>
<fsummary>Send a message to a globally registered pid.</fsummary>
<desc>
<p>Sends message <c><anno>Msg</anno></c> to the pid globally registered
@@ -241,9 +241,9 @@
</func>
<func>
- <name name="set_lock" arity="1"/>
- <name name="set_lock" arity="2"/>
- <name name="set_lock" arity="3"/>
+ <name name="set_lock" arity="1" since=""/>
+ <name name="set_lock" arity="2" since=""/>
+ <name name="set_lock" arity="3" since=""/>
<fsummary>Set a lock on the specified nodes.</fsummary>
<type name="id"/>
<type name="retries"/>
@@ -287,7 +287,7 @@
</func>
<func>
- <name name="sync" arity="0"/>
+ <name name="sync" arity="0" since=""/>
<fsummary>Synchronize the global name server.</fsummary>
<desc>
<p>Synchronizes the global name server with all nodes known to
@@ -302,9 +302,9 @@
</func>
<func>
- <name name="trans" arity="2"/>
- <name name="trans" arity="3"/>
- <name name="trans" arity="4"/>
+ <name name="trans" arity="2" since=""/>
+ <name name="trans" arity="3" since=""/>
+ <name name="trans" arity="4" since=""/>
<fsummary>Micro transaction facility.</fsummary>
<type name="retries"/>
<type name="trans_fun"/>
@@ -322,7 +322,7 @@
</func>
<func>
- <name name="unregister_name" arity="1"/>
+ <name name="unregister_name" arity="1" since=""/>
<fsummary>Remove a globally registered name for a pid.</fsummary>
<desc>
<p>Removes the globally registered name <c><anno>Name</anno></c> from
@@ -331,7 +331,7 @@
</func>
<func>
- <name name="whereis_name" arity="1"/>
+ <name name="whereis_name" arity="1" since=""/>
<fsummary>Get the pid with a specified globally registered name.</fsummary>
<desc>
<p>Returns the pid with the globally registered name
diff --git a/lib/kernel/doc/src/global_group.xml b/lib/kernel/doc/src/global_group.xml
index 8f947b9adf..74d15cd476 100644
--- a/lib/kernel/doc/src/global_group.xml
+++ b/lib/kernel/doc/src/global_group.xml
@@ -28,7 +28,7 @@
<date>1998-12-18</date>
<rev>B</rev>
</header>
- <module>global_group</module>
+ <module since="">global_group</module>
<modulesummary>Grouping nodes to global name registration groups.</modulesummary>
<description>
<p>This module makes it possible to partition the nodes of a
@@ -105,7 +105,7 @@
<funcs>
<func>
- <name name="global_groups" arity="0"/>
+ <name name="global_groups" arity="0" since=""/>
<fsummary>Return the global group names.</fsummary>
<desc>
<p>Returns a tuple containing the name of the global group that
@@ -116,7 +116,7 @@
</func>
<func>
- <name name="info" arity="0"/>
+ <name name="info" arity="0" since=""/>
<fsummary>Information about global groups.</fsummary>
<type name="info_item"/>
<type name="sync_state"/>
@@ -173,7 +173,7 @@
</func>
<func>
- <name name="monitor_nodes" arity="1"/>
+ <name name="monitor_nodes" arity="1" since=""/>
<fsummary>Subscribe to node status changes.</fsummary>
<desc>
<p>Depending on <c><anno>Flag</anno></c>, the calling process
@@ -187,7 +187,7 @@
</func>
<func>
- <name name="own_nodes" arity="0"/>
+ <name name="own_nodes" arity="0" since=""/>
<fsummary>Return the group nodes.</fsummary>
<desc>
<p>Returns the names of all group nodes, regardless of their
@@ -196,7 +196,7 @@
</func>
<func>
- <name name="registered_names" arity="1"/>
+ <name name="registered_names" arity="1" since=""/>
<fsummary>Return globally registered names.</fsummary>
<desc>
<p>Returns a list of all names that are globally registered
@@ -205,8 +205,8 @@
</func>
<func>
- <name name="send" arity="2"/>
- <name name="send" arity="3"/>
+ <name name="send" arity="2" since=""/>
+ <name name="send" arity="3" since=""/>
<fsummary>Send a message to a globally registered pid.</fsummary>
<desc>
<p>Searches for <c><anno>Name</anno></c>, globally registered on
@@ -224,7 +224,7 @@
</func>
<func>
- <name name="sync" arity="0"/>
+ <name name="sync" arity="0" since=""/>
<fsummary>Synchronize the group nodes.</fsummary>
<desc>
<p>Synchronizes the group nodes, that is, the global name
@@ -242,8 +242,8 @@
</func>
<func>
- <name name="whereis_name" arity="1"/>
- <name name="whereis_name" arity="2"/>
+ <name name="whereis_name" arity="1" since=""/>
+ <name name="whereis_name" arity="2" since=""/>
<fsummary>Get the pid with a specified globally registered name.</fsummary>
<desc>
<p>Searches for <c><anno>Name</anno></c>, globally registered on
diff --git a/lib/kernel/doc/src/heart.xml b/lib/kernel/doc/src/heart.xml
index 5b5b71e521..4243b1ffe8 100644
--- a/lib/kernel/doc/src/heart.xml
+++ b/lib/kernel/doc/src/heart.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -28,7 +28,7 @@
<date>1998-01-28</date>
<rev>A</rev>
</header>
- <module>heart</module>
+ <module since="">heart</module>
<modulesummary>Heartbeat monitoring of an Erlang runtime system.</modulesummary>
<description>
<p>This modules contains the interface to the <c>heart</c> process.
@@ -59,8 +59,9 @@
<pre>
% <input>erl -heart -env HEART_BEAT_TIMEOUT 30 ...</input></pre>
<p>The value (in seconds) must be in the range 10 &lt; X &lt;= 65535.</p>
- <p>Notice that if the system clock is adjusted with
- more than <c>HEART_BEAT_TIMEOUT</c> seconds, <c>heart</c>
+ <p>When running on OSs lacking support for monotonic time,
+ <c>heart</c> is susceptible to system clock adjustments of more than
+ <c>HEART_BEAT_TIMEOUT</c> seconds. When this happens, <c>heart</c>
times out and tries to reboot the system. This can occur, for
example, if the system clock is adjusted automatically by use of the
Network Time Protocol (NTP).</p>
@@ -118,7 +119,7 @@
<funcs>
<func>
- <name name="set_cmd" arity="1"/>
+ <name name="set_cmd" arity="1" since=""/>
<fsummary>Set a temporary reboot command.</fsummary>
<desc>
<p>Sets a temporary reboot command. This command is used if
@@ -135,7 +136,7 @@
</func>
<func>
- <name name="clear_cmd" arity="0"/>
+ <name name="clear_cmd" arity="0" since=""/>
<fsummary>Clear the temporary boot command.</fsummary>
<desc>
<p>Clears the temporary boot command. If the system terminates,
@@ -144,7 +145,7 @@
</func>
<func>
- <name name="get_cmd" arity="0"/>
+ <name name="get_cmd" arity="0" since=""/>
<fsummary>Get the temporary reboot command.</fsummary>
<desc>
<p>Gets the temporary reboot command. If the command is cleared,
@@ -153,7 +154,7 @@
</func>
<func>
- <name name="set_callback" arity="2"/>
+ <name name="set_callback" arity="2" since="OTP 18.3"/>
<fsummary>Set a validation callback</fsummary>
<desc>
<p> This validation callback will be executed before any
@@ -165,14 +166,14 @@
</desc>
</func>
<func>
- <name name="clear_callback" arity="0"/>
+ <name name="clear_callback" arity="0" since="OTP 18.3"/>
<fsummary>Clear the validation callback</fsummary>
<desc>
<p>Removes the validation callback call before heartbeats.</p>
</desc>
</func>
<func>
- <name name="get_callback" arity="0"/>
+ <name name="get_callback" arity="0" since="OTP 18.3"/>
<fsummary>Get the validation callback</fsummary>
<desc>
<p>Get the validation callback. If the callback is cleared, <c>none</c> will be returned.</p>
@@ -180,7 +181,7 @@
</func>
<func>
- <name name="set_options" arity="1"/>
+ <name name="set_options" arity="1" since="OTP 18.3"/>
<fsummary>Set a list of options</fsummary>
<desc>
<p> Valid options <c>set_options</c> are: </p>
@@ -198,7 +199,7 @@
</desc>
</func>
<func>
- <name name="get_options" arity="0"/>
+ <name name="get_options" arity="0" since="OTP 18.3"/>
<fsummary>Get the temporary reboot command</fsummary>
<desc>
<p>Returns <c>{ok, Options}</c> where <c>Options</c> is a list of current options enabled for heart.
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index 169a76463b..d4678ca5db 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2017</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -28,7 +28,7 @@
<date>1998-02-04</date>
<rev>A</rev>
</header>
- <module>inet</module>
+ <module since="">inet</module>
<modulesummary>Access to TCP/IP protocols.</modulesummary>
<description>
<p>This module provides access to TCP/IP protocols.</p>
@@ -177,6 +177,100 @@ fe80::204:acff:fe17:bf38
</desc>
</datatype>
<datatype>
+ <name name="ancillary_data"/>
+ <desc>
+ <p>
+ Ancillary data received with the data packet
+ or read with the socket option
+ <seealso marker="gen_tcp#type-pktoptions_value">
+ <c>pktoptions</c>
+ </seealso>
+ from a TCP socket.
+ </p>
+ <p>
+ The value(s) correspond to the currently active socket
+ <seealso marker="#type-socket_setopt">options</seealso>
+ <seealso marker="inet#option-recvtos"><c>recvtos</c></seealso>,
+ <seealso marker="inet#option-recvtclass"><c>recvtclass</c></seealso>
+ and
+ <seealso marker="inet#option-recvttl"><c>recvttl</c></seealso>.
+ </p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="getifaddrs_ifopts"/>
+ <desc>
+ <p>
+ Interface address description list returned from
+ <seealso marker="#getifaddrs/0"><c>getifaddrs/0,1</c></seealso>
+ for a named interface, translated from the returned
+ data of the POSIX API function <c>getaddrinfo()</c>.
+ </p>
+ <p>
+ <c><anno>Hwaddr</anno></c> is hardware dependent,
+ for example, on Ethernet interfaces it is
+ the 6-byte Ethernet address (MAC address (EUI-48 address)).
+ </p>
+ <p>
+ The tuples <c>{addr,<anno>Addr</anno>}</c>,
+ <c>{netmask,<anno>Netmask</anno>}</c>, and possibly
+ <c>{broadaddr,<anno>Broadaddr</anno>}</c> or
+ <c>{dstaddr,<anno>Dstaddr</anno>}</c>
+ are repeated in the list
+ if the interface has got multiple addresses.
+ An interface may have multiple <c>{flag,_}</c> tuples
+ for example if it has different flags
+ for different address families.
+ Multiple <c>{hwaddr,<anno>Hwaddr</anno>}</c> tuples
+ is hard to say anything definite about, though.
+ The tuple <c>{flag,<anno>Flags</anno>}</c> is mandatory,
+ all others are optional.
+ </p>
+ <p>
+ Do not rely too much on the order
+ of <c><anno>Flags</anno></c> atoms
+ or the <c><anno>Ifopt</anno></c> tuples.
+ There are however some rules:
+ </p>
+ <list type="bulleted">
+ <item><p>
+ A <c>{flag,_}</c> tuple applies to all other tuples that follow.
+ </p></item>
+ <item><p>
+ Immediately after <c>{addr,_}</c> follows <c>{netmask,_}</c>.
+ </p></item>
+ <item><p>
+ Immediately thereafter may <c>{broadaddr,_}</c> follow
+ if <c>broadcast</c> is member of <c><anno>Flags</anno></c>,
+ or <c>{dstaddr,_}</c> if <c>pointtopoint</c>
+ is member of <c><anno>Flags</anno></c>.
+ Both <c>{dstaddr,_}</c> and <c>{broadaddr,_}</c>
+ does not occur for the same <c>{addr,_}</c>.
+ </p></item>
+ <item><p>
+ Any <c>{netmask,_}</c>, <c>{broadaddr,_}</c>, or
+ <c>{dstaddr,_}</c> tuples that follow an
+ <c>{addr,<anno>Addr</anno>}</c>
+ tuple concerns the address <c><anno>Addr</anno></c>.
+ </p></item>
+ </list>
+ <p>
+ The tuple <c>{hwaddr,_}</c> is not returned on Solaris, as the
+ hardware address historically belongs to the link layer
+ and it is not returned by the Solaris API function
+ <c>getaddrinfo()</c>.
+ </p>
+ <warning>
+ <p>
+ On Windows, the data is fetched from different
+ OS API functions, so the <c><anno>Netmask</anno></c>
+ and <c><anno>Broadaddr</anno></c> values may be calculated,
+ just as some <c><anno>Flags</anno></c> values.
+ </p>
+ </warning>
+ </desc>
+ </datatype>
+ <datatype>
<name name="posix"/>
<desc>
<p>An atom that is named from the POSIX error codes used in Unix,
@@ -197,11 +291,17 @@ fe80::204:acff:fe17:bf38
<datatype>
<name name="address_family"/>
</datatype>
+ <datatype>
+ <name name="socket_protocol"/>
+ </datatype>
+ <datatype>
+ <name name="stat_option"/>
+ </datatype>
</datatypes>
<funcs>
<func>
- <name name="close" arity="1"/>
+ <name name="close" arity="1" since=""/>
<fsummary>Close a socket of any type.</fsummary>
<desc>
<p>Closes a socket of any type.</p>
@@ -209,7 +309,7 @@ fe80::204:acff:fe17:bf38
</func>
<func>
- <name name="format_error" arity="1"/>
+ <name name="format_error" arity="1" since=""/>
<fsummary>Return a descriptive string for an error reason.</fsummary>
<desc>
<p>Returns a diagnostic error string. For possible POSIX values and
@@ -219,7 +319,7 @@ fe80::204:acff:fe17:bf38
</func>
<func>
- <name name="get_rc" arity="0"/>
+ <name name="get_rc" arity="0" since=""/>
<fsummary>Return a list of IP configuration parameters.</fsummary>
<desc>
<p>
@@ -238,7 +338,7 @@ fe80::204:acff:fe17:bf38
</func>
<func>
- <name name="getaddr" arity="2"/>
+ <name name="getaddr" arity="2" since=""/>
<fsummary>Return the IP address for a host.</fsummary>
<desc>
<p>Returns the IP address for <c><anno>Host</anno></c> as a tuple of
@@ -248,7 +348,7 @@ fe80::204:acff:fe17:bf38
</func>
<func>
- <name name="getaddrs" arity="2"/>
+ <name name="getaddrs" arity="2" since=""/>
<fsummary>Return the IP addresses for a host.</fsummary>
<desc>
<p>Returns a list of all IP addresses for <c><anno>Host</anno></c>.
@@ -258,7 +358,7 @@ fe80::204:acff:fe17:bf38
</func>
<func>
- <name name="gethostbyaddr" arity="1"/>
+ <name name="gethostbyaddr" arity="1" since=""/>
<fsummary>Return a hostent record for the host with the specified
address.</fsummary>
<desc>
@@ -267,21 +367,19 @@ fe80::204:acff:fe17:bf38
</func>
<func>
- <name name="gethostbyname" arity="1"/>
+ <name name="gethostbyname" arity="1" since=""/>
<fsummary>Return a hostent record for the host with the specified name.
</fsummary>
<desc>
<p>Returns a <c>hostent</c> record for the host with the specified
hostname.</p>
<p>If resolver option <c>inet6</c> is <c>true</c>,
- an IPv6 address is looked up. If that fails,
- the IPv4 address is looked up and returned on
- IPv6-mapped IPv4 format.</p>
+ an IPv6 address is looked up.</p>
</desc>
</func>
<func>
- <name name="gethostbyname" arity="2"/>
+ <name name="gethostbyname" arity="2" since=""/>
<fsummary>Return a hostent record for the host with the specified name.
</fsummary>
<desc>
@@ -291,7 +389,7 @@ fe80::204:acff:fe17:bf38
</func>
<func>
- <name name="gethostname" arity="0"/>
+ <name name="gethostname" arity="0" since=""/>
<fsummary>Return the local hostname.</fsummary>
<desc>
<p>Returns the local hostname. Never fails.</p>
@@ -299,51 +397,81 @@ fe80::204:acff:fe17:bf38
</func>
<func>
- <name name="getifaddrs" arity="0"/>
+ <name name="getifaddrs" arity="0" since="OTP R14B01"/>
<fsummary>Return a list of interfaces and their addresses.</fsummary>
<desc>
- <p>Returns a list of 2-tuples containing interface names and the
- interface addresses. <c><anno>Ifname</anno></c> is a Unicode string.
- <c><anno>Hwaddr</anno></c> is hardware dependent, for example, on
- Ethernet interfaces
- it is the 6-byte Ethernet address (MAC address (EUI-48 address)).</p>
- <p>The tuples <c>{addr,<anno>Addr</anno>}</c>, <c>{netmask,_}</c>, and
- <c>{broadaddr,_}</c> are repeated in the result list if the interface
- has multiple addresses. If you come across an interface with
- multiple <c>{flag,_}</c> or <c>{hwaddr,_}</c> tuples, you have
- a strange interface or possibly a bug in this function. The tuple
- <c>{flag,_}</c> is mandatory, all others are optional.</p>
- <p>Do not rely too much on the order of <c><anno>Flag</anno></c> atoms
- or <c><anno>Ifopt</anno></c> tuples. There are however some rules:</p>
- <list type="bulleted">
- <item><p>Immediately after
- <c>{addr,_}</c> follows <c>{netmask,_}</c>.</p></item>
- <item><p>Immediately thereafter follows <c>{broadaddr,_}</c> if flag
- <c>broadcast</c> is <em>not</em> set and flag
- <c>pointtopoint</c> <em>is</em> set.</p></item>
- <item><p>Any <c>{netmask,_}</c>, <c>{broadaddr,_}</c>, or
- <c>{dstaddr,_}</c> tuples that follow an <c>{addr,_}</c>
- tuple concerns that address.</p></item>
- </list>
- <p>The tuple <c>{hwaddr,_}</c> is not returned on Solaris, as the
- hardware address historically belongs to the link layer and only
- the superuser can read such addresses.</p>
- <warning>
- <p>On Windows, the data is fetched from different OS API functions,
- so the <c><anno>Netmask</anno></c> and <c><anno>Broadaddr</anno></c>
- values can be calculated, just as some <c><anno>Flag</anno></c>
- values. Report flagrant bugs.</p>
- </warning>
+ <p>
+ Returns a list of 2-tuples containing interface names and
+ the interfaces' addresses. <c><anno>Ifname</anno></c>
+ is a Unicode string and
+ <c><anno>Ifopts</anno></c> is a list of
+ interface address description tuples.
+ </p>
+ <p>
+ The interface address description tuples
+ are documented under the type of the
+ <seealso marker="#type-getifaddrs_ifopts">
+ <c><anno>Ifopts</anno></c>
+ </seealso>
+ value.
+ </p>
</desc>
</func>
<func>
- <name name="getopts" arity="2"/>
+ <name since="OTP 21.2">getifaddrs(Opts) ->
+ {ok, [{Ifname, Ifopts}]} | {error, Posix}
+ </name>
+ <fsummary>Return a list of interfaces and their addresses.</fsummary>
+ <type>
+ <v>
+ Opts = [{netns, Namespace}]
+ </v>
+ <v>
+ Namespace =
+ <seealso marker="file#type-filename_all">
+ file:filename_all()
+ </seealso>
+ </v>
+ <v>Ifname = string()</v>
+ <v>
+ Ifopts =
+ <seealso marker="#type-getifaddrs_ifopts">
+ getifaddrs_ifopts()
+ </seealso>
+ </v>
+ <v>Posix = <seealso marker="#type-posix">posix()</seealso></v>
+ </type>
+ <desc>
+ <p>
+ The same as
+ <seealso marker="#getifaddrs/0"><c>getifaddrs/0</c></seealso>
+ but the <c>Option</c>
+ <c>{netns, Namespace}</c> sets a network namespace
+ for the OS call, on platforms that supports that feature.
+ </p>
+ <p>
+ See the socket option
+ <seealso marker="#option-netns">
+ <c>{netns, Namespace}</c>
+ </seealso>
+ under
+ <seealso marker="#setopts/2"><c>setopts/2</c></seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="getopts" arity="2" since=""/>
<fsummary>Get one or more options for a socket.</fsummary>
<desc>
<p>Gets one or more options for a socket. For a list of available
options, see
- <seealso marker="#setopts/2"><c>setopts/2</c></seealso>.</p>
+ <seealso marker="#setopts/2"><c>setopts/2</c></seealso>.
+ See also the description for the type
+ <seealso marker="gen_tcp#type-pktoptions_value">
+ <c>gen_tcp:pktoptions_value()</c>
+ </seealso>.</p>
<p>The number of elements in the returned
<c><anno>OptionValues</anno></c>
list does not necessarily correspond to the number of options
@@ -359,7 +487,7 @@ fe80::204:acff:fe17:bf38
socket options not (explicitly) supported by the emulator. The
use of raw socket options makes the code non-portable, but
allows the Erlang programmer to take advantage of unusual features
- present on the current platform.</p>
+ present on a particular platform.</p>
<p><c>RawOptReq</c> consists of tag <c>raw</c> followed
by the protocol level, the option number, and either a binary
or the size, in bytes, of the
@@ -404,8 +532,8 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
- <name name="getstat" arity="1"/>
- <name name="getstat" arity="2"/>
+ <name name="getstat" arity="1" since=""/>
+ <name name="getstat" arity="2" since=""/>
<fsummary>Get one or more statistic options for a socket.</fsummary>
<type name="stat_option"/>
<desc>
@@ -461,7 +589,62 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
- <name name="ntoa" arity="1" />
+ <name name="i" arity="0" since="OTP 21.0"/>
+ <name name="i" arity="1" since="OTP 21.0"/>
+ <name name="i" arity="2" since="OTP 21.0"/>
+ <fsummary>Displays information and statistics about sockets on the terminal</fsummary>
+ <desc>
+ <p>
+ Lists all TCP, UDP and SCTP sockets, including those that the Erlang runtime system uses as well as
+ those created by the application.
+ </p>
+ <p>
+ The following options are available:
+ </p>
+
+ <taglist>
+ <tag><c>port</c></tag>
+ <item>
+ <p>The internal index of the port.</p>
+ </item>
+ <tag><c>module</c></tag>
+ <item>
+ <p>The callback module of the socket.</p>
+ </item>
+ <tag><c>recv</c></tag>
+ <item>
+ <p>Number of bytes received by the socket.</p>
+ </item>
+ <tag><c>sent</c></tag>
+ <item>
+ <p>Number of bytes sent from the socket.</p>
+ </item>
+ <tag><c>owner</c></tag>
+ <item>
+ <p>The socket owner process.</p>
+ </item>
+ <tag><c>local_address</c></tag>
+ <item>
+ <p>The local address of the socket.</p>
+ </item>
+ <tag><c>foreign_address</c></tag>
+ <item>
+ <p>The address and port of the other end of the connection.</p>
+ </item>
+ <tag><c>state</c></tag>
+ <item>
+ <p>The connection state.</p>
+ </item>
+ <tag><c>type</c></tag>
+ <item>
+ <p>STREAM or DGRAM or SEQPACKET.</p>
+ </item>
+ </taglist>
+ </desc>
+ </func>
+
+ <func>
+ <name name="ntoa" arity="1" since="OTP R16B02"/>
<fsummary>Convert IPv6/IPV4 address to ASCII.</fsummary>
<desc>
<p>Parses an
@@ -471,7 +654,7 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
- <name name="parse_address" arity="1" />
+ <name name="parse_address" arity="1" since="OTP R16B"/>
<fsummary>Parse an IPv4 or IPv6 address.</fsummary>
<desc>
<p>Parses an IPv4 or IPv6 address string and returns an
@@ -482,7 +665,7 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
- <name name="parse_ipv4_address" arity="1" />
+ <name name="parse_ipv4_address" arity="1" since="OTP R16B"/>
<fsummary>Parse an IPv4 address.</fsummary>
<desc>
<p>Parses an IPv4 address string and returns an
@@ -492,7 +675,7 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
- <name name="parse_ipv4strict_address" arity="1" />
+ <name name="parse_ipv4strict_address" arity="1" since="OTP R16B"/>
<fsummary>Parse an IPv4 address strict.</fsummary>
<desc>
<p>Parses an IPv4 address string containing four fields, that is,
@@ -503,7 +686,7 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
- <name name="parse_ipv6_address" arity="1" />
+ <name name="parse_ipv6_address" arity="1" since="OTP R16B"/>
<fsummary>Parse an IPv6 address.</fsummary>
<desc>
<p>Parses an IPv6 address string and returns an
@@ -514,7 +697,7 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
- <name name="parse_ipv6strict_address" arity="1" />
+ <name name="parse_ipv6strict_address" arity="1" since="OTP R16B"/>
<fsummary>Parse an IPv6 address strict.</fsummary>
<desc>
<p>Parses an IPv6 address string and returns an
@@ -524,7 +707,20 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
- <name name="parse_strict_address" arity="1" />
+ <name name="ipv4_mapped_ipv6_address" arity="1" since="OTP 21.0"/>
+ <fsummary>Convert to and from IPv4-mapped IPv6 address.</fsummary>
+ <desc>
+ <p>
+ Convert an IPv4 address to an IPv4-mapped IPv6 address
+ or the reverse. When converting from an IPv6 address
+ all but the 2 low words are ignored so this function also
+ works on some other types of addresses than IPv4-mapped.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="parse_strict_address" arity="1" since="OTP R16B"/>
<fsummary>Parse an IPv4 or IPv6 address strict.</fsummary>
<desc>
<p>Parses an IPv4 or IPv6 address string and returns an
@@ -535,7 +731,7 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
- <name name="peername" arity="1"/>
+ <name name="peername" arity="1" since=""/>
<fsummary>Return the address and port for the other end of a connection.
</fsummary>
<desc>
@@ -548,7 +744,7 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
- <name name="peernames" arity="1"/>
+ <name name="peernames" arity="1" since="OTP R16B03"/>
<fsummary>Return all address/port numbers for the other end of a
connection.</fsummary>
<desc>
@@ -562,7 +758,7 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
- <name name="peernames" arity="2"/>
+ <name name="peernames" arity="2" since="OTP R16B03"/>
<fsummary>Return all address/port numbers for the other end of a
connection.</fsummary>
<desc>
@@ -581,7 +777,7 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
- <name name="port" arity="1"/>
+ <name name="port" arity="1" since=""/>
<fsummary>Return the local port number for a socket.</fsummary>
<desc>
<p>Returns the local port number for a socket.</p>
@@ -589,7 +785,7 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
- <name name="setopts" arity="2"/>
+ <name name="setopts" arity="2" since=""/>
<fsummary>Set one or more options for a socket.</fsummary>
<desc>
<p>Sets one or more options for a socket.</p>
@@ -665,22 +861,23 @@ get_tcpi_sacked(Sock) ->
</item>
<tag><c>{buffer, Size}</c></tag>
<item>
- <p>The size of the user-level software buffer used by
- the driver.
- Not to be confused with options <c>sndbuf</c>
+ <p>The size of the user-level buffer used by
+ the driver. Not to be confused with options <c>sndbuf</c>
and <c>recbuf</c>, which correspond to the
- Kernel socket buffers. It is recommended
- to have <c>val(buffer) &gt;= max(val(sndbuf),val(recbuf))</c> to
+ Kernel socket buffers. For TCP it is recommended
+ to have <c>val(buffer) &gt;= val(recbuf)</c> to
avoid performance issues because of unnecessary copying.
+ For UDP the same recommendation applies, but the max should
+ not be larger than the MTU of the network path.
<c>val(buffer)</c> is automatically set to the above
- maximum when values <c>sndbuf</c> or <c>recbuf</c> are set.
- However, as the sizes set for <c>sndbuf</c> and <c>recbuf</c>
+ maximum when <c>recbuf</c> is set.
+ However, as the size set for <c>recbuf</c>
usually become larger, you are encouraged to use
<seealso marker="#getopts/2"><c>getopts/2</c></seealso>
to analyze the behavior of your operating system.</p>
<p>Note that this is also the maximum amount of data that can be
- received from a single recv call. If you are using higher than
- normal MTU consider setting buffer higher.</p>
+ received from a single recv call. If you are using higher than
+ normal MTU consider setting buffer higher.</p>
</item>
<tag><c>{delay_send, Boolean}</c></tag>
<item>
@@ -813,13 +1010,34 @@ get_tcpi_sacked(Sock) ->
<marker id="option-linger"></marker>
</item>
<tag><c>{linger, {true|false, Seconds}}</c></tag>
- <item>
+ <item>
<p>Determines the time-out, in seconds, for flushing unsent data
- in the <c>close/1</c> socket call. If the first component of
- the value tuple is <c>false</c>, the second is ignored. This
- means that <c>close/1</c> returns immediately, not waiting
- for data to be flushed. Otherwise, the second component is
- the flushing time-out, in seconds.</p>
+ in the <c>close/1</c> socket call. </p>
+ <p>The first component is if linger is enabled, the second component
+ is the flushing time-out, in seconds. There are 3 alternatives:</p>
+ <taglist>
+ <tag><c>{false, _}</c></tag>
+ <item>
+ <p>close/1 or shutdown/2 returns immediately,
+ not waiting for data to be flushed, with closing
+ happening in the background.</p>
+ </item>
+ <tag><c>{true, 0}</c></tag>
+ <item>
+ <p>Aborts the connection when it is closed.
+ Discards any data still remaining in the send buffers
+ and sends RST to the peer.</p>
+ <p>This avoids TCP's TIME_WAIT state, but leaves open
+ the possibility that another "incarnation" of this connection
+ being created.</p>
+ </item>
+ <tag><c>{true, Time} when Time > 0</c></tag>
+ <item>
+ <p>close/1 or shutdown/2 will not return until
+ all queued messages for the socket have been successfully
+ sent or the linger timeout (Time) has been reached.</p>
+ </item>
+ </taglist>
</item>
<tag><c>{low_msgq_watermark, Size}</c></tag>
<item>
@@ -855,20 +1073,29 @@ get_tcpi_sacked(Sock) ->
</item>
<tag><c>{mode, Mode :: binary | list}</c></tag>
<item>
- <p>Received <c>Packet</c> is delivered as defined by <c>Mode</c>.
+ <p>
+ Received <c>Packet</c> is delivered as defined by <c>Mode</c>.
</p>
</item>
- <tag><c>{netns, Namespace :: file:filename_all()}</c></tag>
+ <tag>
+ <marker id="option-netns"/>
+ <c>{netns, Namespace :: file:filename_all()}</c>
+ </tag>
<item>
- <p>Sets a network namespace for the socket. Parameter
+ <p>
+ Sets a network namespace for the socket. Parameter
<c>Namespace</c> is a filename defining the namespace, for
example, <c>"/var/run/netns/example"</c>, typically created by
command <c>ip netns add example</c>. This option must be used in
a function call that creates a socket, that is,
<seealso marker="gen_tcp#connect/3"><c>gen_tcp:connect/3,4</c></seealso>,
<seealso marker="gen_tcp#listen/2"><c>gen_tcp:listen/2</c></seealso>,
- <seealso marker="gen_udp#open/1"><c>gen_udp:open/1,2</c></seealso>, or
- <seealso marker="gen_sctp#open/0"><c>gen_sctp:open/0,1,2</c></seealso>.</p>
+ <seealso marker="gen_udp#open/1"><c>gen_udp:open/1,2</c></seealso>
+ or
+ <seealso marker="gen_sctp#open/0"><c>gen_sctp:open/0,1,2</c></seealso>,
+ and also
+ <seealso marker="#getifaddrs/1"><c>getifaddrs/1</c></seealso>.
+ </p>
<p>This option uses the Linux-specific syscall
<c>setns()</c>, such as in Linux kernel 3.0 or later,
and therefore only exists when the runtime system
@@ -944,6 +1171,18 @@ setcap cap_sys_admin,cap_sys_ptrace,cap_dac_read_search+epi beam.smp</code>
is turned on for the socket, which means that also small
amounts of data are sent immediately.</p>
</item>
+ <tag><c>{nopush, Boolean}</c>(TCP/IP sockets)</tag>
+ <item>
+ <p>This translates to <c>TCP_NOPUSH</c> on BSD and
+ to <c>TCP_CORK</c> on Linux.</p>
+ <p>If <c>Boolean == true</c>, the corresponding option
+ is turned on for the socket, which means that small
+ amounts of data are accumulated until a full MSS-worth
+ of data is available or this option is turned off.</p>
+ <p>Note that while <c>TCP_NOPUSH</c> socket option is available on OSX, its semantics
+ is very different (e.g., unsetting it does not cause immediate send
+ of accumulated data). Hence, <c>nopush</c> option is intentionally ignored on OSX.</p>
+ </item>
<tag><c>{packet, PacketType}</c>(TCP/IP sockets)</tag>
<item>
<p><marker id="packet"/>Defines the type of packets to use for a socket.
@@ -1045,6 +1284,100 @@ setcap cap_sys_admin,cap_sys_ptrace,cap_dac_read_search+epi beam.smp</code>
the socket. You are encouraged to use
<seealso marker="#getopts/2"><c>getopts/2</c></seealso>
to retrieve the size set by your operating system.</p>
+ <marker id="option-recvtclass"></marker>
+ </item>
+ <tag><c>{recvtclass, Boolean}</c></tag>
+ <item>
+ <p>
+ If set to <c>true</c> activates returning the received
+ <c>TCLASS</c> value on platforms that implements
+ the protocol <c>IPPROTO_IPV6</c>
+ option <c>IPV6_RECVTCLASS</c> or <c>IPV6_2292RECVTCLASS</c>
+ for the socket.
+ The value is returned as a <c>{tclass,TCLASS}</c> tuple
+ regardless of if the platform returns an <c>IPV6_TCLASS</c>
+ or an <c>IPV6_RECVTCLASS</c> CMSG value.
+ </p>
+ <p>
+ For packet oriented sockets that supports receiving
+ ancillary data with the payload data
+ (<c>gen_udp</c> and <c>gen_sctp</c>),
+ the <c>TCLASS</c> value is returned
+ in an extended return tuple contained in an
+ <seealso marker="inet#type-ancillary_data">
+ ancillary data
+ </seealso>
+ list.
+ For stream oriented sockets (<c>gen_tcp</c>)
+ the only way to get the <c>TCLASS</c>
+ value is if the platform supports the
+ <seealso marker="gen_tcp#type-pktoptions_value">
+ <c>pktoptions</c>
+ </seealso>
+ option.
+ </p>
+ <marker id="option-recvtos"></marker>
+ </item>
+ <tag><c>{recvtos, Boolean}</c></tag>
+ <item>
+ <p>
+ If set to <c>true</c> activates returning the received
+ <c>TOS</c> value on platforms that implements
+ the protocol <c>IPPROTO_IP</c> option <c>IP_RECVTOS</c>
+ for the socket.
+ The value is returned as a <c>{tos,TOS}</c> tuple
+ regardless of if the platform returns an <c>IP_TOS</c>
+ or an <c>IP_RECVTOS</c> CMSG value.
+ </p>
+ <p>
+ For packet oriented sockets that supports receiving
+ ancillary data with the payload data
+ (<c>gen_udp</c> and <c>gen_sctp</c>),
+ the <c>TOS</c> value is returned
+ in an extended return tuple contained in an
+ <seealso marker="inet#type-ancillary_data">
+ ancillary data
+ </seealso>
+ list.
+ For stream oriented sockets (<c>gen_tcp</c>)
+ the only way to get the <c>TOS</c>
+ value is if the platform supports the
+ <seealso marker="gen_tcp#type-pktoptions_value">
+ <c>pktoptions</c>
+ </seealso>
+ option.
+ </p>
+ <marker id="option-recvttl"></marker>
+ </item>
+ <tag><c>{recvttl, Boolean}</c></tag>
+ <item>
+ <p>
+ If set to <c>true</c> activates returning the received
+ <c>TTL</c> value on platforms that implements
+ the protocol <c>IPPROTO_IP</c> option <c>IP_RECVTTL</c>
+ for the socket.
+ The value is returned as a <c>{ttl,TTL}</c> tuple
+ regardless of if the platform returns an <c>IP_TTL</c>
+ or an <c>IP_RECVTTL</c> CMSG value.
+ </p>
+ <p>
+ For packet oriented sockets that supports receiving
+ ancillary data with the payload data
+ (<c>gen_udp</c> and <c>gen_sctp</c>),
+ the <c>TTL</c> value is returned
+ in an extended return tuple contained in an
+ <seealso marker="inet#type-ancillary_data">
+ ancillary data
+ </seealso>
+ list.
+ For stream oriented sockets (<c>gen_tcp</c>)
+ the only way to get the <c>TTL</c>
+ value is if the platform supports the
+ <seealso marker="gen_tcp#type-pktoptions_value">
+ <c>pktoptions</c>
+ </seealso>
+ option.
+ </p>
</item>
<tag><c>{reuseaddr, Boolean}</c></tag>
<item>
@@ -1080,7 +1413,7 @@ setcap cap_sys_admin,cap_sys_ptrace,cap_dac_read_search+epi beam.smp</code>
<seealso marker="gen_tcp#recv/2"><c>gen_tcp:recv/2</c></seealso>
gets <c>{error, closed}</c>. In active
mode, the controlling process receives a
- <c>{tcp_close, Socket}</c> message, indicating that the
+ <c>{tcp_closed, Socket}</c> message, indicating that the
peer has closed the connection.</p>
<p>Setting this option to <c>true</c> allows you to
distinguish between a connection that was closed normally,
@@ -1177,7 +1510,7 @@ inet:setopts(Sock,[{raw,6,8,<<30:32/native>>}]),]]></code>
</func>
<func>
- <name name="sockname" arity="1"/>
+ <name name="sockname" arity="1" since=""/>
<fsummary>Return the local address and port number for a socket.
</fsummary>
<desc>
@@ -1190,7 +1523,7 @@ inet:setopts(Sock,[{raw,6,8,<<30:32/native>>}]),]]></code>
</func>
<func>
- <name name="socknames" arity="1"/>
+ <name name="socknames" arity="1" since="OTP R16B03"/>
<fsummary>Return all local address/port numbers for a socket.</fsummary>
<desc>
<p>Equivalent to
@@ -1200,7 +1533,7 @@ inet:setopts(Sock,[{raw,6,8,<<30:32/native>>}]),]]></code>
</func>
<func>
- <name name="socknames" arity="2"/>
+ <name name="socknames" arity="2" since="OTP R16B03"/>
<fsummary>Return all local address/port numbers for a socket.</fsummary>
<desc>
<p>Returns a list of all local address/port number pairs for a socket
@@ -1214,7 +1547,7 @@ inet:setopts(Sock,[{raw,6,8,<<30:32/native>>}]),]]></code>
For one-to-many style sockets, the special value <c>0</c>
is defined to mean that the returned addresses must be
without any particular association.
- How different SCTP implementations interprets this varies somewhat.
+ How different SCTP implementations interpret this varies somewhat.
</p>
</desc>
</func>
diff --git a/lib/kernel/doc/src/inet_res.xml b/lib/kernel/doc/src/inet_res.xml
index 4ada4203c0..1904e371f7 100644
--- a/lib/kernel/doc/src/inet_res.xml
+++ b/lib/kernel/doc/src/inet_res.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2009</year><year>2015</year>
+ <year>2009</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -28,7 +28,7 @@
<date>2009-09-11</date>
<rev>A</rev>
</header>
- <module>inet_res</module>
+ <module since="">inet_res</module>
<modulesummary>A rudimentary DNS client.</modulesummary>
<description>
<p>This module performs DNS name resolving to recursive name servers.</p>
@@ -130,7 +130,7 @@ dns_header() = DnsHeader
inet_dns:header(DnsHeader) ->
[ {id, integer()}
| {qr, boolean()}
- | {opcode, 'query' | iquery | status | integer()}
+ | {opcode, query | iquery | status | integer()}
| {aa, boolean()}
| {tc, boolean()}
| {rd, boolean()}
@@ -185,8 +185,8 @@ inet_dns:record_type(_) -> undefined.</pre>
<funcs>
<func>
- <name name="getbyname" arity="2"/>
- <name name="getbyname" arity="3"/>
+ <name name="getbyname" arity="2" since=""/>
+ <name name="getbyname" arity="3" since=""/>
<fsummary>Resolve a DNS record of the specified type for the specified
host.</fsummary>
<desc>
@@ -205,8 +205,8 @@ inet_dns:record_type(_) -> undefined.</pre>
</func>
<func>
- <name name="gethostbyaddr" arity="1"/>
- <name name="gethostbyaddr" arity="2"/>
+ <name name="gethostbyaddr" arity="1" since=""/>
+ <name name="gethostbyaddr" arity="2" since=""/>
<fsummary>Return a hostent record for the host with the specified
address.</fsummary>
<desc>
@@ -217,9 +217,9 @@ inet_dns:record_type(_) -> undefined.</pre>
</func>
<func>
- <name name="gethostbyname" arity="1"/>
- <name name="gethostbyname" arity="2"/>
- <name name="gethostbyname" arity="3"/>
+ <name name="gethostbyname" arity="1" since=""/>
+ <name name="gethostbyname" arity="2" since=""/>
+ <name name="gethostbyname" arity="3" since=""/>
<fsummary>Return a hostent record for the host with the specified name.
</fsummary>
<desc>
@@ -230,16 +230,14 @@ inet_dns:record_type(_) -> undefined.</pre>
<seealso marker="#getbyname/2"><c>getbyname/2,3</c></seealso>.
</p>
<p>If resolver option <c>inet6</c> is <c>true</c>,
- an IPv6 address is looked up. If that fails,
- the IPv4 address is looked up and returned on
- IPv6-mapped IPv4 format.</p>
+ an IPv6 address is looked up.</p>
</desc>
</func>
<func>
- <name name="lookup" arity="3"/>
- <name name="lookup" arity="4"/>
- <name name="lookup" arity="5"/>
+ <name name="lookup" arity="3" since=""/>
+ <name name="lookup" arity="4" since=""/>
+ <name name="lookup" arity="5" since=""/>
<fsummary>Resolve the DNS data for the record of the specified type
and class for the specified name.</fsummary>
<desc>
@@ -259,9 +257,9 @@ inet_dns:record_type(_) -> undefined.</pre>
</func>
<func>
- <name name="resolve" arity="3"/>
- <name name="resolve" arity="4"/>
- <name name="resolve" arity="5"/>
+ <name name="resolve" arity="3" since=""/>
+ <name name="resolve" arity="4" since=""/>
+ <name name="resolve" arity="5" since=""/>
<fsummary>Resolve a DNS record of the specified type and class
for the specified name.</fsummary>
<desc>
@@ -328,9 +326,9 @@ example_lookup(Name, Class, Type) ->
<funcs>
<func>
- <name name="nslookup" arity="3"/>
- <name name="nslookup" arity="4" clause_i="1"/>
- <name name="nslookup" arity="4" clause_i="2"/>
+ <name name="nslookup" arity="3" since=""/>
+ <name name="nslookup" arity="4" clause_i="1" since=""/>
+ <name name="nslookup" arity="4" clause_i="2" since=""/>
<fsummary>Resolve a DNS record of the specified type and class for the
specified name.</fsummary>
<type variable="Name"/>
@@ -346,8 +344,8 @@ example_lookup(Name, Class, Type) ->
</func>
<func>
- <name name="nnslookup" arity="4"/>
- <name name="nnslookup" arity="5"/>
+ <name name="nnslookup" arity="4" since=""/>
+ <name name="nnslookup" arity="5" since=""/>
<fsummary>Resolve a DNS record of the specified type and class
for the specified name.</fsummary>
<desc>
diff --git a/lib/kernel/doc/src/introduction_chapter.xml b/lib/kernel/doc/src/introduction_chapter.xml
new file mode 100644
index 0000000000..d02b1a2ee5
--- /dev/null
+++ b/lib/kernel/doc/src/introduction_chapter.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2017</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>Introduction</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>introduction.xml</file>
+ </header>
+
+ <section>
+ <title>Scope</title>
+ <p>The Kernel application has all the code necessary to run
+ the Erlang runtime system: file servers, code servers,
+ and so on.</p>
+ <p>The Kernel application is the first application started. It is
+ mandatory in the sense that the minimal system based on
+ Erlang/OTP consists of Kernel and STDLIB. Kernel
+ contains the following functional areas:</p>
+ <list type="bulleted">
+ <item>Start, stop, supervision, configuration, and distribution of applications</item>
+ <item>Code loading</item>
+ <item>Logging</item>
+ <item>Global name service</item>
+ <item>Supervision of Erlang/OTP</item>
+ <item>Communication with sockets</item>
+ <item>Operating system interface</item>
+ </list>
+ </section>
+
+ <section>
+ <title>Prerequisites</title>
+ <p>It is assumed that the reader is familiar with the Erlang programming
+ language.</p>
+ </section>
+</chapter>
+
+
diff --git a/lib/kernel/doc/src/kernel_app.xml b/lib/kernel/doc/src/kernel_app.xml
index 0762cebc94..7f9609d5c1 100644
--- a/lib/kernel/doc/src/kernel_app.xml
+++ b/lib/kernel/doc/src/kernel_app.xml
@@ -42,7 +42,6 @@
<item>Start, stop, supervision, configuration, and distribution of applications</item>
<item>Code loading</item>
<item>Logging</item>
- <item>Error logging</item>
<item>Global name service</item>
<item>Supervision of Erlang/OTP</item>
<item>Communication with sockets</item>
@@ -51,10 +50,13 @@
</description>
<section>
- <title>Error Logger Event Handlers</title>
- <p>Two standard error logger event handlers are defined in
- the Kernel application. These are described in
- <seealso marker="error_logger"><c>error_logger(3)</c></seealso>.</p>
+ <title>Logger Handlers</title>
+ <p>Two standard logger handlers are defined in
+ the Kernel application. These are described in the
+ <seealso marker="logger_chapter">Kernel User's Guide</seealso>,
+ and in the <seealso marker="logger_std_h"><c>logger_std_h(3)</c></seealso>
+ and <seealso marker="logger_disk_log_h"><c>logger_disk_log_h(3)</c>
+ </seealso> manual pages.</p>
</section>
<section>
@@ -113,26 +115,12 @@
</section>
<section>
+ <marker id="configuration"/>
<title>Configuration</title>
<p>The following configuration parameters are defined for the Kernel
application. For more information about configuration parameters,
see file <seealso marker="app"><c>app(4)</c></seealso>.</p>
<taglist>
- <tag><c>browser_cmd = string() | {M,F,A}</c></tag>
- <item>
- <p>When pressing the <em>Help</em> button in a tool such as Debugger,
- the help text (an HTML file <c>File</c>) is by default
- displayed in a Netscape browser, which is required to be
- operational. This parameter can be used to change the command for
- how to display the help text if another browser than Netscape
- is preferred, or if another platform than Unix or Windows is
- used.</p>
- <p>If set to a string <c>Command</c>, the command
- <c>"Command File"</c> is evaluated using
- <seealso marker="os#cmd/1"><c>os:cmd/1</c></seealso>.</p>
- <p>If set to a module-function-args tuple, <c>{M,F,A}</c>,
- the call <c>apply(M,F,[File|A])</c> is evaluated.</p>
- </item>
<tag><c>distributed = [Distrib]</c></tag>
<item>
<p>Specifies which applications that are distributed and on which
@@ -176,65 +164,74 @@
<p>Permissions are described in
<seealso marker="application#permit/2"><c>application:permit/2</c></seealso>.</p>
</item>
- <tag><c>error_logger = Value</c></tag>
- <item>
- <p><c>Value</c> is one of:</p>
- <taglist>
- <tag><c>tty</c></tag>
- <item><p>Installs the standard event handler, which prints error
- reports to <c>stdio</c>. This is the default option.</p></item>
- <tag><c>{file, FileName}</c></tag>
- <item><p>Installs the standard event handler, which prints error
- reports to file <c>FileName</c>, where <c>FileName</c>
- is a string. The file is opened with encoding UTF-8.</p></item>
- <tag><c>false</c></tag>
- <item>
- <p>No standard event handler is installed, but
- the initial, primitive event handler is kept, printing
- raw event messages to <c>tty</c>.</p>
- </item>
- <tag><c>silent</c></tag>
- <item>
- <p>Error logging is turned off.</p>
- </item>
- </taglist>
+ <tag><marker id="logger"/><c>logger = [Config]</c></tag>
+ <item>
+ <p>Specifies the configuration
+ for <seealso marker="logger">Logger</seealso>, except the
+ primary log level, which is specified
+ with <seealso marker="#logger_level"><c>logger_level</c></seealso>,
+ and the compatibility
+ with <seealso marker="sasl:error_logging">SASL Error
+ Logging</seealso>, which is specified
+ with <seealso marker="#logger_sasl_compatible">
+ <c>logger_sasl_compatible</c></seealso>.</p>
+ <p>The <c>logger </c> parameter is described in
+ section <seealso marker="logger_chapter#logger_parameter">
+ Logging</seealso> in the Kernel User's Guide.</p>
+ </item>
+ <tag><marker id="logger_level"/><c>logger_level = Level</c></tag>
+ <item>
+ <p>Specifies the primary log level for Logger. Log events with
+ the same, or a more severe level, pass through the primary
+ log level check. See
+ section <seealso marker="logger_chapter">Logging</seealso>
+ in the Kernel User's Guide for more information about Logger
+ and log levels.</p>
+ <p><c>Level = emergency | alert | critical | error | warning |
+ notice | info | debug | all | none</c></p>
+ <p>To change the primary log level at runtime, use
+ <seealso marker="logger#set_primary_config/2">
+ <c>logger:set_primary_config(level, Level)</c></seealso>.</p>
+ <p>Defaults to <c>notice</c>.</p>
+ </item>
+ <tag><marker id="logger_sasl_compatible"/>
+ <c>logger_sasl_compatible = true | false</c></tag>
+ <item>
+ <p>Specifies if Logger behaves backwards compatible with the
+ SASL error logging functionality from releases prior to
+ Erlang/OTP 21.0.</p>
+ <p>If this parameter is set to <c>true</c>, the default Logger
+ handler does not log any progress-, crash-, or supervisor
+ reports. If the SASL application is then started, it adds a
+ Logger handler named <c>sasl</c>, which logs these events
+ according to values of the SASL configuration
+ parameter <c>sasl_error_logger</c>
+ and <c>sasl_errlog_type</c>.</p>
+ <p>See section
+ <seealso marker="sasl:sasl_app#deprecated_error_logger_config">
+ Deprecated Error Logger Event Handlers and
+ Configuration</seealso> in the sasl(6) manual page for
+ information about the SASL configuration parameters.</p>
+ <p>See section <seealso marker="sasl:error_logging">SASL Error
+ Logging</seealso> in the SASL User's Guide, and
+ section <seealso marker="logger_chapter#compatibility">Backwards
+ Compatibility with error_logger</seealso> in the Kernel
+ User's Guide for information about the SASL error logging
+ functionality, and how Logger can be backwards compatible
+ with this.</p>
+ <p>Defaults to <c>false</c>.</p>
+ <note>
+ <p>If this parameter is set to <c>true</c>,
+ <c>sasl_errlog_type</c> indicates that progress reports
+ shall be logged, and the configured primary log level
+ is <c>notice</c> or more severe, then SASL automatically
+ sets the primary log level to <c>info</c>. That is, this
+ setting can potentially overwrite the value of the Kernel
+ configuration parameter <c>logger_level</c>. This is to
+ allow progress reports, which have log level <c>info</c>,
+ to be forwarded to the handlers.</p>
+ </note>
</item>
- <tag><c>error_logger_format_depth = Depth</c></tag>
- <item>
- <marker id="error_logger_format_depth"></marker>
- <p>Can be used to limit the size of the
- formatted output from the error logger event handlers.</p>
-
- <note><p>This configuration parameter was introduced in OTP 18.1
- and is experimental. Based on user feedback, it
- can be changed or improved in future releases, for example,
- to gain better control over how to limit the size of the
- formatted output. We have no plans to remove this
- new feature entirely, unless it turns out to be
- useless.</p></note>
-
- <p><c>Depth</c> is a positive integer representing the maximum
- depth to which terms are printed by the error logger event
- handlers included in OTP. This
- configuration parameter is used by the two event handlers
- defined by the Kernel application and the two event
- handlers in the SASL application.
- (If you have implemented your own error handlers, this configuration
- parameter has no effect on them.)</p>
-
- <p><c>Depth</c> is used as follows: Format strings
- passed to the event handlers are rewritten.
- The format controls <c>~p</c> and <c>~w</c> are replaced with
- <c>~P</c> and <c>~W</c>, respectively, and <c>Depth</c> is
- used as the depth parameter. For details, see
- <seealso marker="stdlib:io#format/2"><c>io:format/2</c></seealso>
- in STDLIB.</p>
-
- <note><p>A reasonable starting value for <c>Depth</c> is
- <c>30</c>. We recommend to test crashing various processes in your
- application, examine the logs from the crashes, and then
- increase or decrease the value.</p></note>
- </item>
<tag><c>global_groups = [GroupTuple]</c></tag>
<item>
<marker id="global_groups"></marker>
@@ -286,9 +283,8 @@
</item>
<tag><c>inet_parse_error_log = silent</c></tag>
<item>
- <p>If set, no
- <c>error_logger</c> messages are generated when erroneous
- lines are found and skipped in the various Inet configuration
+ <p>If set, no log events are issued when erroneous lines are
+ found and skipped in the various Inet configuration
files.</p>
</item>
<tag><c>inetrc = Filename</c></tag>
@@ -314,24 +310,31 @@
<tag><c>net_ticktime = TickTime</c></tag>
<item>
<marker id="net_ticktime"></marker>
- <p>Specifies the <c>net_kernel</c> tick time. <c>TickTime</c>
- is specified in seconds. Once every <c>TickTime/4</c> second, all
- connected nodes are ticked (if anything else is written
- to a node). If nothing is received from another node
- within the last four tick times, that node is considered
- to be down. This ensures that nodes that are not responding,
- for reasons such as hardware errors, are considered to be
- down.</p>
- <p>The time <c>T</c>, in which a node that is not responding is
- detected, is calculated as <c><![CDATA[MinT < T < MaxT]]></c>, where:</p>
+ <p>Specifies the <c>net_kernel</c> tick time in seconds. This is the
+ approximate time a connected node may be unresponsive until it is
+ considered down and thereby disconnected.</p>
+ <p>Once every <c>TickTime/4</c> seconds, each connected node is ticked
+ if nothing has been sent to it during that last <c>TickTime/4</c>
+ interval. A tick is a small package sent on the connection. A connected
+ node is considered to be down if no ticks or payload packages have been
+ received during the last four <c>TickTime/4</c> intervals. This ensures
+ that nodes that are not responding, for reasons such as hardware errors,
+ are considered to be down.</p>
+ <p>As the availability is only checked every <c>TickTime/4</c> seconds,
+ the actual time <c>T</c> a node have been unresponsive when
+ detected may vary between <c>MinT</c> and <c>MaxT</c>,
+ where:</p>
<code type="none">
MinT = TickTime - TickTime / 4
MaxT = TickTime + TickTime / 4</code>
- <p><c>TickTime</c> defaults to <c>60</c> (seconds). Thus,
- <c><![CDATA[45 < T < 75]]></c> seconds.</p>
- <p>Notice that <em>all</em> communicating nodes are to have the <em>same</em>
- <c>TickTime</c> value specified.</p>
- <p>Normally, a terminating node is detected immediately.</p>
+ <p><c>TickTime</c> defaults to <c>60</c> seconds. Thus,
+ <c><![CDATA[45 < T < 75]]></c> seconds.</p>
+ <p>Notice that <em>all</em> communicating nodes are to have the
+ <em>same</em> <c>TickTime</c> value specified, as it determines both the
+ frequency of outgoing ticks and the expected frequency of incominging
+ ticks.</p>
+ <p>Normally, a terminating node is detected immediately by the transport
+ protocol (like TCP/IP).</p>
</item>
<tag><c>shutdown_timeout = integer() | infinity</c></tag>
<item>
@@ -366,6 +369,14 @@ MaxT = TickTime + TickTime / 4</code>
performed. This option ensures that <c>global</c> is
synchronized.</p>
</item>
+ <tag><c>start_distribution = true | false</c></tag>
+ <item>
+ <p>Starts all distribution services, such as <c>rpc</c>,
+ <c>global</c>, and <c>net_kernel</c> if the parameter is
+ <c>true</c>. This parameter is to be set to <c>false</c>
+ for systems who want to disable all distribution functionality.</p>
+ <p>Defaults to <c>true</c>.</p>
+ </item>
<tag><c>start_dist_ac = true | false</c></tag>
<item>
<p>Starts the <c>dist_ac</c> server if the parameter is
@@ -497,6 +508,39 @@ MaxT = TickTime + TickTime / 4</code>
</section>
<section>
+ <title>Deprecated Configuration Parameters</title>
+ <p>In Erlang/OTP 21.0, a new API for logging was added. The
+ old <c>error_logger</c> event manager, and event handlers
+ running on this manager, still work, but they are no longer used
+ by default.</p>
+ <p>The following application configuration parameters can still be
+ set, but they are only used if the corresponding configuration
+ parameters for Logger are not set.</p>
+ <taglist>
+ <tag><c>error_logger</c></tag>
+ <item>Replaced by setting the <seealso
+ marker="logger_std_h#type"><c>type</c></seealso>, and possibly
+ <seealso marker="logger_std_h#file"><c>file</c></seealso> and
+ <seealso marker="logger_std_h#modes"><c>modes</c></seealso>
+ parameters of the default <c>logger_std_h</c> handler. Example:
+ <code type="none">
+erl -kernel logger '[{handler,default,logger_std_h,#{config=>#{file=>"/tmp/erlang.log"}}}]'
+ </code>
+ </item>
+ <tag><c>error_logger_format_depth</c></tag>
+ <item>Replaced by setting the <seealso marker="logger_formatter#depth"><c>depth</c></seealso>
+ parameter of the default handlers formatter. Example:
+ <code type="none">
+erl -kernel logger '[{handler,default,logger_std_h,#{formatter=>{logger_formatter,#{legacy_header=>true,template=>[{logger_formatter,header},"\n",msg,"\n"],depth=>10}}}]'
+ </code>
+ </item>
+ </taglist>
+ <p>See <seealso marker="logger_chapter#compatibility">Backwards
+ compatibility with error_logger</seealso> for more
+ information.</p>
+ </section>
+
+ <section>
<title>See Also</title>
<p><seealso marker="app"><c>app(4)</c></seealso>,
<seealso marker="application"><c>application(3)</c></seealso>,
@@ -504,12 +548,12 @@ MaxT = TickTime + TickTime / 4</code>
<seealso marker="disk_log"><c>disk_log(3)</c></seealso>,
<seealso marker="erl_boot_server"><c>erl_boot_server(3)</c></seealso>,
<seealso marker="erl_ddll"><c>erl_ddll(3)</c></seealso>,
- <seealso marker="error_logger"><c>error_logger(3)</c></seealso>,
<seealso marker="file"><c>file(3)</c></seealso>,
<seealso marker="global"><c>global(3)</c></seealso>,
<seealso marker="global_group"><c>global_group(3)</c></seealso>,
<seealso marker="heart"><c>heart(3)</c></seealso>,
<seealso marker="inet"><c>inet(3)</c></seealso>,
+ <seealso marker="logger"><c>logger(3)</c></seealso>,
<seealso marker="net_kernel"><c>net_kernel(3)</c></seealso>,
<seealso marker="os"><c>os(3)</c></seealso>,
<seealso marker="pg2"><c>pg2(3)</c></seealso>,
diff --git a/lib/kernel/doc/src/logger.xml b/lib/kernel/doc/src/logger.xml
new file mode 100644
index 0000000000..2a060ce1f9
--- /dev/null
+++ b/lib/kernel/doc/src/logger.xml
@@ -0,0 +1,1353 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2017</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>logger</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev>A</rev>
+ <file>logger.xml</file>
+ </header>
+ <module since="OTP 21.0">logger</module>
+ <modulesummary>API module for Logger, the standard logging facility
+ in Erlang/OTP.</modulesummary>
+
+ <description>
+ <p>This module implements the main API for logging in
+ Erlang/OTP. To create a log event, use the
+ <seealso marker="#logging_API">API functions</seealso> or the
+ log
+ <seealso marker="#macros">macros</seealso>, for example:</p>
+ <code>
+?LOG_ERROR("error happened because: ~p", [Reason]). % With macro
+logger:error("error happened because: ~p", [Reason]). % Without macro
+ </code>
+ <p>To configure the Logger backend,
+ use <seealso marker="kernel_app#logger">Kernel configuration
+ parameters</seealso>
+ or <seealso marker="#configuration_API">configuration
+ functions</seealso> in the Logger API.</p>
+
+ <p>By default, the Kernel application installs one log handler at
+ system start. This handler is named <c>default</c>. It receives
+ and processes standard log events produced by the Erlang runtime
+ system, standard behaviours and different Erlang/OTP
+ applications. The log events are by default printed to the
+ terminal.</p>
+ <p>If you want your systems logs to be printed to a file instead,
+ you must configure the default handler to do so. The simplest
+ way is to include the following in
+ your <seealso marker="config"><c>sys.config</c></seealso>:</p>
+ <code>
+[{kernel,
+ [{logger,
+ [{handler, default, logger_std_h,
+ #{config => #{file => "path/to/file.log"}}}]}]}].
+ </code>
+ <p>
+ For more information about:
+ </p>
+ <list type="bulleted">
+ <item>the Logger facility in general, see
+ the <seealso marker="logger_chapter">User's
+ Guide</seealso>.</item>
+ <item>how to configure Logger, see
+ the <seealso marker="logger_chapter#configuration">Configuration</seealso>
+ section in the User's Guide.</item>
+ <item>the built-in handlers,
+ see <seealso marker="logger_std_h">logger_std_h</seealso> and
+ <seealso marker="logger_disk_log_h">logger_disk_log_h</seealso>.</item>
+ <item>the built-in formatter,
+ see <seealso marker="logger_formatter">logger_formatter</seealso>.</item>
+ <item>built-in filters,
+ see <seealso marker="logger_filters">logger_filters</seealso>.</item>
+ </list>
+
+ <note>
+ <p>Since Logger is new in Erlang/OTP 21.0, we do reserve the right
+ to introduce changes to the Logger API and functionality in
+ patches following this release. These changes might or might not
+ be backwards compatible with the initial version.</p>
+ </note>
+
+ </description>
+
+ <datatypes>
+ <datatype>
+ <name name="filter"/>
+ <desc>
+ <p>A filter which can be installed as a handler filter, or as
+ a primary filter in Logger.</p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="filter_arg"/>
+ <desc>
+ <p>The second argument to the filter fun.</p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="filter_id"/>
+ <desc>
+ <p>A unique identifier for a filter.</p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="filter_return"/>
+ <desc>
+ <p>The return value from the filter fun.</p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="formatter_config"/>
+ <desc>
+ <p>Configuration data for the
+ formatter. See <seealso marker="logger_formatter">
+ <c>logger_formatter(3)</c></seealso>
+ for an example of a formatter implementation.</p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="handler_config"/>
+ <desc>
+ <p>Handler configuration data for Logger. The following
+ default values apply:</p>
+ <list>
+ <item><c>level => all</c></item>
+ <item><c>filter_default => log</c></item>
+ <item><c>filters => []</c></item>
+ <item><c>formatter => {logger_formatter, DefaultFormatterConfig</c>}</item>
+ </list>
+ <p>In addition to these, the following fields are
+ automatically inserted by Logger, values taken from the
+ two first parameters
+ to <seealso marker="#add_handler-3"><c>add_handler/3</c></seealso>:</p>
+ <list>
+ <item><c>id => HandlerId</c></item>
+ <item><c>module => Module</c></item>
+ </list>
+ <p>These are read-only and cannot be changed in runtime.</p>
+ <p>Handler specific configuration data is inserted by the
+ handler callback itself, in a sub structure associated with
+ the field named <c>config</c>. See
+ the <seealso marker="logger_std_h"><c>logger_std_h(3)</c></seealso>
+ and <seealso marker="logger_disk_log_h"><c>logger_disk_log_h</c></seealso>
+ manual pages for information about the specifc configuration
+ for these handlers.</p>
+ <p>See the <seealso marker="logger_formatter#type-config">
+ <c>logger_formatter(3)</c></seealso> manual page for
+ information about the default configuration for this
+ formatter.</p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="handler_id"/>
+ <desc>
+ <p>A unique identifier for a handler instance.</p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="level"/>
+ <desc>
+ <p>The severity level for the message to be logged.</p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="log_event"/>
+ <desc>
+ <p></p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="metadata"/>
+ <desc>
+ <p>Metadata for the log event.</p>
+ <p>Logger adds the following metadata to each log event:</p>
+ <list>
+ <item><c>pid => self()</c></item>
+ <item><c>gl => group_leader()</c></item>
+ <item><c>time => logger:timestamp()</c></item>
+ </list>
+ <p>When a log macro is used, Logger also inserts location
+ information:</p>
+ <list>
+ <item><c>mfa => {?MODULE, ?FUNCTION_NAME, ?FUNCTION_ARITY}</c></item>
+ <item><c>file => ?FILE</c></item>
+ <item><c>line => ?LINE</c></item>
+ </list>
+ <p>You can add custom metadata, either by specifying a map as
+ the last parameter to any of the log macros or the API
+ functions, or by setting process metadata
+ with <seealso marker="#set_process_metadata-1">
+ <c>set_process_metadata/1</c></seealso>
+ or <seealso marker="#update_process_metadata-1">
+ <c>update_process_metadata/1</c></seealso>.</p>
+ <p>Logger merges all the metadata maps before forwarding the
+ log event to the handlers. If the same keys occur, values
+ from the log call overwrite process metadata, which in turn
+ overwrite values set by Logger.</p>
+ <p>The following custom metadata keys have special meaning:</p>
+ <taglist>
+ <tag><c>domain</c></tag>
+ <item>
+ <p>The value associated with this key is used by filters
+ for grouping log events originating from, for example,
+ specific functional
+ areas. See <seealso marker="logger_filters#domain-2">
+ <c>logger_filters:domain/2</c></seealso>
+ for a description of how this field can be used.</p>
+ </item>
+ <tag><c>report_cb</c></tag>
+ <item>
+ <p>If the log message is specified as
+ a <seealso marker="#type-report"><c>report()</c></seealso>,
+ the <c>report_cb</c> key can be associated with a fun
+ (report callback) that converts the report to a format
+ string and arguments, or directly to a string. See the
+ type definition
+ of <seealso marker="#type-report_cb"><c>report_cb()</c></seealso>,
+ and
+ section <seealso marker="logger_chapter#log_message">Log
+ Message</seealso> in the User's Guide for more
+ information about report callbacks.</p>
+ </item>
+ </taglist>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="msg_fun"/>
+ <desc>
+ <p></p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="olp_config"/>
+ <desc>
+ <p></p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="primary_config"/>
+ <desc>
+ <p>Primary configuration data for Logger. The following
+ default values apply:</p>
+ <list>
+ <item><c>level => info</c></item>
+ <item><c>filter_default => log</c></item>
+ <item><c>filters => []</c></item>
+ </list>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="report"/>
+ <desc>
+ <p></p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="report_cb"/>
+ <desc>
+ <p>A fun which converts a <seealso marker="#type-report"><c>report()</c>
+ </seealso> to a format string and arguments, or directly to a string.
+ See section <seealso marker="logger_chapter#log_message">Log
+ Message</seealso> in the User's Guide for more
+ information.</p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="report_cb_config"/>
+ <desc>
+ <p></p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="timestamp"/>
+ <desc>
+ <p>A timestamp produced
+ with <seealso marker="#timestamp-0">
+ <c>logger:timestamp()</c></seealso>.</p>
+ </desc>
+ </datatype>
+ </datatypes>
+
+ <section>
+ <title>Macros</title>
+ <p>The following macros are defined in <c>logger.hrl</c>, which
+ is included in a module with the directive</p>
+ <code>
+ -include_lib("kernel/include/logger.hrl").</code>
+
+ <list>
+ <item><c>?LOG_EMERGENCY(StringOrReport[,Metadata])</c></item>
+ <item><c>?LOG_EMERGENCY(FunOrFormat,Args[,Metadata])</c></item>
+ <item><c>?LOG_ALERT(StringOrReport[,Metadata])</c></item>
+ <item><c>?LOG_ALERT(FunOrFormat,Args[,Metadata])</c></item>
+ <item><c>?LOG_CRITICAL(StringOrReport[,Metadata])</c></item>
+ <item><c>?LOG_CRITICAL(FunOrFormat,Args[,Metadata])</c></item>
+ <item><c>?LOG_ERROR(StringOrReport[,Metadata])</c></item>
+ <item><c>?LOG_ERROR(FunOrFormat,Args[,Metadata])</c></item>
+ <item><c>?LOG_WARNING(StringOrReport[,Metadata])</c></item>
+ <item><c>?LOG_WARNING(FunOrFormat,Args[,Metadata])</c></item>
+ <item><c>?LOG_NOTICE(StringOrReport[,Metadata])</c></item>
+ <item><c>?LOG_NOTICE(FunOrFormat,Args[,Metadata])</c></item>
+ <item><c>?LOG_INFO(StringOrReport[,Metadata])</c></item>
+ <item><c>?LOG_INFO(FunOrFormat,Args[,Metadata])</c></item>
+ <item><c>?LOG_DEBUG(StringOrReport[,Metadata])</c></item>
+ <item><c>?LOG_DEBUG(FunOrFormat,Args[,Metadata])</c></item>
+ <item><c>?LOG(Level,StringOrReport[,Metadata])</c></item>
+ <item><c>?LOG(Level,FunOrFormat,Args[,Metadata])</c></item>
+ </list>
+
+ <p>All macros expand to a call to Logger, where <c>Level</c> is
+ taken from the macro name, or from the first argument in the
+ case of the <c>?LOG</c> macro. Location data is added to the
+ metadata as described under
+ the <seealso marker="#type-metadata"><c>metadata()</c></seealso>
+ type definition.</p>
+
+ <p>The call is wrapped in a case statement and will be evaluated
+ only if <c>Level</c> is equal to or below the configured log
+ level.</p>
+ </section>
+
+ <section>
+ <marker id="logging_API"/>
+ <title>Logging API functions</title>
+ </section>
+ <funcs>
+ <func>
+ <name since="OTP 21.0">emergency(StringOrReport[,Metadata])</name>
+ <name since="OTP 21.0">emergency(Format,Args[,Metadata])</name>
+ <name since="OTP 21.0">emergency(Fun,FunArgs[,Metadata])</name>
+ <fsummary>Logs the given message as level <c>emergency</c>.</fsummary>
+ <desc>
+ <p>Equivalent to
+ <seealso marker="#log-2"><c>log(emergency,...)</c></seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0">alert(StringOrReport[,Metadata])</name>
+ <name since="OTP 21.0">alert(Format,Args[,Metadata])</name>
+ <name since="OTP 21.0">alert(Fun,FunArgs[,Metadata])</name>
+ <fsummary>Logs the given message as level <c>alert</c>.</fsummary>
+ <desc>
+ <p>Equivalent to
+ <seealso marker="#log-2"><c>log(alert,...)</c></seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0">critical(StringOrReport[,Metadata])</name>
+ <name since="OTP 21.0">critical(Format,Args[,Metadata])</name>
+ <name since="OTP 21.0">critical(Fun,FunArgs[,Metadata])</name>
+ <fsummary>Logs the given message as level <c>critical</c>.</fsummary>
+ <desc>
+ <p>Equivalent to
+ <seealso marker="#log-2"><c>log(critical,...)</c></seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0">error(StringOrReport[,Metadata])</name>
+ <name since="OTP 21.0">error(Format,Args[,Metadata])</name>
+ <name since="OTP 21.0">error(Fun,FunArgs[,Metadata])</name>
+ <fsummary>Logs the given message as level <c>error</c>.</fsummary>
+ <desc>
+ <p>Equivalent to
+ <seealso marker="#log-2"><c>log(error,...)</c></seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0">warning(StringOrReport[,Metadata])</name>
+ <name since="OTP 21.0">warning(Format,Args[,Metadata])</name>
+ <name since="OTP 21.0">warning(Fun,FunArgs[,Metadata])</name>
+ <fsummary>Logs the given message as level <c>warning</c>.</fsummary>
+ <desc>
+ <p>Equivalent to
+ <seealso marker="#log-2"><c>log(warning,...)</c></seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0">notice(StringOrReport[,Metadata])</name>
+ <name since="OTP 21.0">notice(Format,Args[,Metadata])</name>
+ <name since="OTP 21.0">notice(Fun,FunArgs[,Metadata])</name>
+ <fsummary>Logs the given message as level <c>notice</c>.</fsummary>
+ <desc>
+ <p>Equivalent to
+ <seealso marker="#log-2"><c>log(notice,...)</c></seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0">info(StringOrReport[,Metadata])</name>
+ <name since="OTP 21.0">info(Format,Args[,Metadata])</name>
+ <name since="OTP 21.0">info(Fun,FunArgs[,Metadata])</name>
+ <fsummary>Logs the given message as level <c>info</c>.</fsummary>
+ <desc>
+ <p>Equivalent to
+ <seealso marker="#log-2"><c>log(info,...)</c></seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0">debug(StringOrReport[,Metadata])</name>
+ <name since="OTP 21.0">debug(Format,Args[,Metadata])</name>
+ <name since="OTP 21.0">debug(Fun,FunArgs[,Metadata])</name>
+ <fsummary>Logs the given message as level <c>debug</c>.</fsummary>
+ <desc>
+ <p>Equivalent to
+ <seealso marker="#log-2"><c>log(debug,...)</c></seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="log" arity="2" since="OTP 21.0"/>
+ <name name="log" arity="3" clause_i="1" since="OTP 21.0"/>
+ <name name="log" arity="3" clause_i="2" since="OTP 21.0"/>
+ <name name="log" arity="3" clause_i="3" since="OTP 21.0"/>
+ <name name="log" arity="4" clause_i="1" since="OTP 21.0"/>
+ <name name="log" arity="4" clause_i="2" since="OTP 21.0"/>
+ <fsummary>Logs the given message.</fsummary>
+ <type variable="Level"/>
+ <type variable="StringOrReport" name_i="1"/>
+ <type variable="Format" name_i="3"/>
+ <type variable="Args" name_i="3"/>
+ <type variable="Fun" name_i="4"/>
+ <type variable="FunArgs" name_i="4"/>
+ <type variable="Metadata"/>
+ <desc>
+ <p>Log the given message.</p>
+ </desc>
+ </func>
+ </funcs>
+
+ <section>
+ <marker id="configuration_API"/>
+ <title>Configuration API functions</title>
+ </section>
+ <funcs>
+ <func>
+ <name name="add_handler" arity="3" since="OTP 21.0"/>
+ <fsummary>Add a handler with the given configuration.</fsummary>
+ <desc>
+ <p>Add a handler with the given configuration.</p>
+ <p><c><anno>HandlerId</anno></c> is a unique identifier which
+ must be used in all subsequent calls referring to this
+ handler.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="add_handler_filter" arity="3" since="OTP 21.0"/>
+ <fsummary>Add a filter to the specified handler.</fsummary>
+ <desc>
+ <p>Add a filter to the specified handler.</p>
+ <p>The filter fun is called with the log event as the first
+ parameter, and the specified <c>filter_args()</c> as the
+ second parameter.</p>
+ <p>The return value of the fun specifies if a log event is to
+ be discarded or forwarded to the handler callback:</p>
+ <taglist>
+ <tag><c>log_event()</c></tag>
+ <item>
+ <p>The filter <em>passed</em>. The next handler filter, if
+ any, is applied. If no more filters exist for this
+ handler, the log event is forwarded to the handler
+ callback.</p>
+ </item>
+ <tag><c>stop</c></tag>
+ <item>
+ <p>The filter <em>did not pass</em>, and the log event is
+ immediately discarded.</p>
+ </item>
+ <tag><c>ignore</c></tag>
+ <item>
+ <p>The filter has no knowledge of the log event. The next
+ handler filter, if any, is applied. If no more filters
+ exist for this handler, the value of
+ the <c>filter_default</c> configuration parameter for
+ the handler specifies if the log event shall be
+ discarded or forwarded to the handler callback.</p>
+ </item>
+ </taglist>
+ <p>See
+ section <seealso marker="logger_chapter#filters">Filters</seealso>
+ in the User's Guide for more information about filters.</p>
+ <p>Some built-in filters exist. These are defined in
+ <seealso marker="logger_filters"><c>logger_filters</c></seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="add_handlers" arity="1" clause_i="1" since="OTP 21.0"/>
+ <fsummary>Set up log handlers from the application's
+ configuration parameters.</fsummary>
+ <desc>
+ <p>Reads the application configuration parameter <c>logger</c> and
+ calls <c>add_handlers/1</c> with its contents.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="add_handlers" arity="1" clause_i="2" since="OTP 21.0"/>
+ <fsummary>Setup logger handlers.</fsummary>
+ <type name="config_handler"/>
+ <desc>
+ <p>This function should be used by custom Logger handlers to make
+ configuration consistent no matter which handler the system uses.
+ Normal usage is to add a call to <c>logger:add_handlers/1</c>
+ just after the processes that the handler needs are started,
+ and pass the application's <c>logger</c> configuration as the argument.
+ For example:</p>
+ <code>
+-behaviour(application).
+start(_, []) ->
+ case supervisor:start_link({local, my_sup}, my_sup, []) of
+ {ok, Pid} ->
+ ok = logger:add_handlers(my_app),
+ {ok, Pid, []};
+ Error -> Error
+ end.</code>
+ <p>This reads the <c>logger</c> configuration parameter from
+ the <c>my_app</c> application and starts the configured
+ handlers. The contents of the configuration use the same
+ rules as the
+ <seealso marker="logger_chapter#handler-configuration">logger handler configuration</seealso>.
+ </p>
+ <p>If the handler is meant to replace the default handler, the Kernel's
+ default handler have to be disabled before the new handler is added.
+ A <c>sys.config</c> file that disables the Kernel handler and adds
+ a custom handler could look like this:</p>
+ <code>
+[{kernel,
+ [{logger,
+ %% Disable the default Kernel handler
+ [{handler, default, undefined}]}]},
+ {my_app,
+ [{logger,
+ %% Enable this handler as the default
+ [{handler, default, my_handler, #{}}]}]}].
+ </code>
+ </desc>
+ </func>
+
+ <func>
+ <name name="add_primary_filter" arity="2" since="OTP 21.0"/>
+ <fsummary>Add a primary filter to Logger.</fsummary>
+ <desc>
+ <p>Add a primary filter to Logger.</p>
+ <p>The filter fun is called with the log event as the first
+ parameter, and the specified <c>filter_args()</c> as the
+ second parameter.</p>
+ <p>The return value of the fun specifies if a log event is to
+ be discarded or forwarded to the handlers:</p>
+ <taglist>
+ <tag><c>log_event()</c></tag>
+ <item>
+ <p>The filter <em>passed</em>. The next primary filter, if
+ any, is applied. If no more primary filters exist, the
+ log event is forwarded to the handler part of Logger,
+ where handler filters are applied.</p>
+ </item>
+ <tag><c>stop</c></tag>
+ <item>
+ <p>The filter <em>did not pass</em>, and the log event is
+ immediately discarded.</p>
+ </item>
+ <tag><c>ignore</c></tag>
+ <item>
+ <p>The filter has no knowledge of the log event. The next
+ primary filter, if any, is applied. If no more primary
+ filters exist, the value of the
+ primary <c>filter_default</c> configuration parameter
+ specifies if the log event shall be discarded or
+ forwarded to the handler part.</p>
+ </item>
+ </taglist>
+ <p>See section <seealso marker="logger_chapter#filters">
+ Filters</seealso> in the User's Guide for more information
+ about filters.</p>
+ <p>Some built-in filters exist. These are defined
+ in <seealso marker="logger_filters"><c>logger_filters</c></seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="get_config" arity="0" since="OTP 21.0"/>
+ <fsummary>Look up the current Logger configuration</fsummary>
+ <desc>
+ <p>Look up all current Logger configuration, including primary,
+ handler, and proxy configuration, and module level settings.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="get_handler_config" arity="0" since="OTP 21.0"/>
+ <fsummary>Look up the current configuration for all handlers.</fsummary>
+ <desc>
+ <p>Look up the current configuration for all handlers.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="get_handler_config" arity="1" since="OTP 21.0"/>
+ <fsummary>Look up the current configuration for the given
+ handler.</fsummary>
+ <desc>
+ <p>Look up the current configuration for the given handler.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="get_handler_ids" arity="0" since="OTP 21.0"/>
+ <fsummary>Look up the identities for all installed handlers.</fsummary>
+ <desc>
+ <p>Look up the identities for all installed handlers.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="get_primary_config" arity="0" since="OTP 21.0"/>
+ <fsummary>Look up the current primary configuration for Logger.</fsummary>
+ <desc>
+ <p>Look up the current primary configuration for Logger.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="get_proxy_config" arity="0" since="OTP 21.3"/>
+ <fsummary>Look up the current configuration for the Logger proxy.</fsummary>
+ <desc>
+ <p>Look up the current configuration for the Logger proxy.</p>
+ <p>For more information about the proxy, see
+ section <seealso marker="logger_chapter#proxy">Logger
+ Proxy</seealso> in the Kernel User's Guide.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="get_module_level" arity="0" since="OTP 21.0"/>
+ <fsummary>Look up all current module levels.</fsummary>
+ <desc>
+ <p>Look up all current module levels. Returns a list
+ containing one <c>{Module,Level}</c> element for each module
+ for which the module level was previously set
+ with <seealso marker="#set_module_level-2">
+ <c>set_module_level/2</c></seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="get_module_level" arity="1" since="OTP 21.0"/>
+ <fsummary>Look up the current level for the given modules.</fsummary>
+ <desc>
+ <p>Look up the current level for the given modules. Returns a
+ list containing one <c>{Module,Level}</c> element for each
+ of the given modules for which the module level was
+ previously set with <seealso marker="#set_module_level-2">
+ <c>set_module_level/2</c></seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="get_process_metadata" arity="0" since="OTP 21.0"/>
+ <fsummary>Retrieve data set with set_process_metadata/1.</fsummary>
+ <desc>
+ <p>Retrieve data set
+ with <seealso marker="#set_process_metadata-1">
+ <c>set_process_metadata/1</c></seealso> or
+ <seealso marker="#update_process_metadata-1">
+ <c>update_process_metadata/1</c></seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="i" arity="0" since="OTP 21.3"/>
+ <name name="i" arity="1" since="OTP 21.3"/>
+ <fsummary>Pretty print the Logger configuration.</fsummary>
+ <desc>
+ <p>Pretty print the Logger configuration.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="remove_handler" arity="1" since="OTP 21.0"/>
+ <fsummary>Remove the handler with the specified identity.</fsummary>
+ <desc>
+ <p>Remove the handler identified by <c><anno>HandlerId</anno></c>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="remove_handler_filter" arity="2" since="OTP 21.0"/>
+ <fsummary>Remove a filter from the specified handler.</fsummary>
+ <desc>
+ <p>Remove the filter identified
+ by <c><anno>FilterId</anno></c> from the handler identified
+ by <c><anno>HandlerId</anno></c>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="remove_primary_filter" arity="1" since="OTP 21.0"/>
+ <fsummary>Remove a primary filter from Logger.</fsummary>
+ <desc>
+ <p>Remove the primary filter identified
+ by <c><anno>FilterId</anno></c> from Logger.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="set_application_level" arity="2" since="OTP 21.1"/>
+ <fsummary>Set the log level for all modules in the specified application.</fsummary>
+ <desc>
+ <p>Set the log level for all the modules of the specified application.</p>
+ <p>This function is a convenience function that calls
+ <seealso marker="#set_module_level/2">logger:set_module_level/2</seealso>
+ for each module associated with an application.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="set_handler_config" arity="2" since="OTP 21.0"/>
+ <fsummary>Set configuration data for the specified handler.</fsummary>
+ <desc>
+ <p>Set configuration data for the specified handler. This
+ overwrites the current handler configuration.</p>
+ <p>To modify the existing configuration,
+ use <seealso marker="#update_handler_config-2">
+ <c>update_handler_config/2</c></seealso>, or, if a more
+ complex merge is needed, read the current configuration
+ with <seealso marker="#get_handler_config-1"><c>get_handler_config/1</c>
+ </seealso>, then do the merge before writing the new
+ configuration back with this function.</p>
+ <p>If a key is removed compared to the current configuration,
+ and the key is known by Logger, the default value is used. If
+ it is a custom key, then it is up to the handler
+ implementation if the value is removed or a default value is
+ inserted.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="set_handler_config" arity="3" clause_i="1" since="OTP 21.0"/>
+ <name name="set_handler_config" arity="3" clause_i="2" since="OTP 21.0"/>
+ <name name="set_handler_config" arity="3" clause_i="3" since="OTP 21.0"/>
+ <name name="set_handler_config" arity="3" clause_i="4" since="OTP 21.0"/>
+ <name name="set_handler_config" arity="3" clause_i="5" since="OTP 21.0"/>
+ <fsummary>Add or update configuration data for the specified
+ handler.</fsummary>
+ <type variable="HandlerId"/>
+ <type variable="Level" name_i="1"/>
+ <type variable="FilterDefault" name_i="2"/>
+ <type variable="Filters" name_i="3"/>
+ <type variable="Formatter" name_i="4"/>
+ <type variable="Config" name_i="5"/>
+ <type variable="Return"/>
+ <desc>
+ <p>Add or update configuration data for the specified
+ handler. If the given <c><anno>Key</anno></c> already
+ exists, its associated value will be changed
+ to the given value. If it does not exist, it will
+ be added.</p>
+ <p>If the value is incomplete, which for example can be the
+ case for the <c>config</c> key, it is up to the handler
+ implementation how the unspecified parts are set. For all
+ handlers in the Kernel application, unspecified data for
+ the <c>config</c> key is set to default values. To update
+ only specified data, and keep the existing configuration for
+ the rest, use <seealso marker="#update_handler_config-3">
+ <c>update_handler_config/3</c></seealso>.</p>
+ <p>See the definition of
+ the <seealso marker="#type-handler_config">
+ <c>handler_config()</c></seealso> type for more
+ information about the different parameters.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="set_primary_config" arity="1" since="OTP 21.0"/>
+ <fsummary>Set primary configuration data for Logger.</fsummary>
+ <desc>
+ <p>Set primary configuration data for Logger. This
+ overwrites the current configuration.</p>
+ <p>To modify the existing configuration,
+ use <seealso marker="#update_primary_config-1">
+ <c>update_primary_config/1</c></seealso>, or, if a more
+ complex merge is needed, read the current configuration
+ with <seealso marker="#get_primary_config-0"><c>get_primary_config/0</c>
+ </seealso>, then do the merge before writing the new
+ configuration back with this function.</p>
+ <p>If a key is removed compared to the current configuration,
+ the default value is used.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="set_primary_config" arity="2" clause_i="1" since="OTP 21.0"/>
+ <name name="set_primary_config" arity="2" clause_i="2" since="OTP 21.0"/>
+ <name name="set_primary_config" arity="2" clause_i="3" since="OTP 21.0"/>
+ <fsummary>Add or update primary configuration data for Logger.</fsummary>
+ <type variable="Level" name_i="1"/>
+ <type variable="FilterDefault" name_i="2"/>
+ <type variable="Filters" name_i="3"/>
+ <desc>
+ <p>Add or update primary configuration data for Logger. If the
+ given <c><anno>Key</anno></c> already exists, its associated
+ value will be changed to the given value. If it does not
+ exist, it will be added.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="set_proxy_config" arity="1" since="OTP 21.3"/>
+ <fsummary>Set configuration data for the Logger proxy.</fsummary>
+ <desc>
+ <p>Set configuration data for the Logger proxy. This
+ overwrites the current proxy configuration. Keys that are not
+ specified in the <c><anno>Config</anno></c> map gets default
+ values.</p>
+ <p>To modify the existing configuration,
+ use <seealso marker="#update_proxy_config-1">
+ <c>update_proxy_config/1</c></seealso>, or, if a more
+ complex merge is needed, read the current configuration
+ with <seealso marker="#get_proxy_config-0"><c>get_proxy_config/0</c>
+ </seealso>, then do the merge before writing the new
+ configuration back with this function.</p>
+ <p>For more information about the proxy, see
+ section <seealso marker="logger_chapter#proxy">Logger
+ Proxy</seealso> in the Kernel User's Guide.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="set_module_level" arity="2" since="OTP 21.0"/>
+ <fsummary>Set the log level for the specified modules.</fsummary>
+ <desc>
+ <p>Set the log level for the specified modules.</p>
+ <p>The log level for a module overrides the primary log level
+ of Logger for log events originating from the module in
+ question. Notice, however, that it does not override the
+ level configuration for any handler.</p>
+ <p>For example: Assume that the primary log level for Logger
+ is <c>info</c>, and there is one handler, <c>h1</c>, with
+ level <c>info</c> and one handler, <c>h2</c>, with
+ level <c>debug</c>.</p>
+ <p>With this configuration, no debug messages will be logged,
+ since they are all stopped by the primary log level.</p>
+ <p>If the level for <c>mymodule</c> is now set
+ to <c>debug</c>, then debug events from this module will be
+ logged by the handler <c>h2</c>, but not by
+ handler <c>h1</c>.</p>
+ <p>Debug events from other modules are still not logged.</p>
+ <p>To change the primary log level for Logger, use
+ <seealso marker="#set_primary_config/2">
+ <c>set_primary_config(level, Level)</c></seealso>.</p>
+ <p>To change the log level for a handler, use
+ <seealso marker="#set_handler_config/3">
+ <c>set_handler_config(HandlerId, level, Level)</c>
+ </seealso>.</p>
+ <note>
+ <p>The originating module for a log event is only detected
+ if the key <c>mfa</c> exists in the metadata, and is
+ associated with <c>{Module, Function, Arity}</c>. When log
+ macros are used, this association is automatically added
+ to all log events. If an API function is called directly,
+ without using a macro, the logging client must explicitly
+ add this information if module levels shall have any
+ effect.</p>
+ </note>
+ </desc>
+ </func>
+
+ <func>
+ <name name="set_process_metadata" arity="1" since="OTP 21.0"/>
+ <fsummary>Set metadata to use when logging from current process.</fsummary>
+ <desc>
+ <p>Set metadata which Logger shall automatically insert in
+ all log events produced on the current process.</p>
+ <p>Location data produced by the log macros, and/or metadata
+ given as argument to the log call (API function or macro),
+ are merged with the process metadata. If the same keys
+ occur, values from the metadata argument to the log call
+ overwrite values from the process metadata, which in turn
+ overwrite values from the location data.</p>
+ <p>Subsequent calls to this function overwrites previous data
+ set. To update existing data instead of overwriting it,
+ see <seealso marker="#update_process_metadata-1">
+ <c>update_process_metadata/1</c></seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="unset_application_level" arity="1" since="OTP 21.1"/>
+ <fsummary>Unset the log level for all modules in the specified application.</fsummary>
+ <desc>
+ <p>Unset the log level for all the modules of the specified application.</p>
+ <p>This function is a convinience function that calls
+ <seealso marker="#unset_module_level/1">logger:unset_module_level/2</seealso>
+ for each module associated with an application.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="unset_module_level" arity="0" since="OTP 21.0"/>
+ <fsummary>Remove module specific log settings for all modules.</fsummary>
+ <desc>
+ <p>Remove module specific log settings. After this, the
+ primary log level is used for all modules.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="unset_module_level" arity="1" since="OTP 21.0"/>
+ <fsummary>Remove module specific log settings for the given
+ modules.</fsummary>
+ <desc>
+ <p>Remove module specific log settings. After this, the
+ primary log level is used for the specified modules.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="unset_process_metadata" arity="0" since="OTP 21.0"/>
+ <fsummary>Delete data set with set_process_metadata/1.</fsummary>
+ <desc>
+ <p>Delete data set
+ with <seealso marker="#set_process_metadata-1">
+ <c>set_process_metadata/1</c></seealso> or
+ <seealso marker="#update_process_metadata-1">
+ <c>update_process_metadata/1</c></seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="update_formatter_config" arity="2" since="OTP 21.0"/>
+ <fsummary>Update the formatter configuration for the specified handler.</fsummary>
+ <desc>
+ <p>Update the formatter configuration for the specified handler.</p>
+ <p>The new configuration is merged with the existing formatter
+ configuration.</p>
+ <p>To overwrite the existing configuration without any merge,
+ use</p>
+ <pre>
+<seealso marker="#set_handler_config-3">set_handler_config(HandlerId, formatter,
+ {FormatterModule, FormatterConfig})</seealso>.</pre>
+ </desc>
+ </func>
+
+ <func>
+ <name name="update_formatter_config" arity="3" since="OTP 21.0"/>
+ <fsummary>Update the formatter configuration for the specified handler.</fsummary>
+ <desc>
+ <p>Update the formatter configuration for the specified handler.</p>
+ <p>This is equivalent to</p>
+ <pre>
+<seealso marker="#update_formatter_config-2">update_formatter_config(<anno>HandlerId</anno>, #{<anno>Key</anno> => <anno>Value</anno>})</seealso></pre>
+ </desc>
+ </func>
+
+ <func>
+ <name name="update_handler_config" arity="2" since="OTP 21.0"/>
+ <fsummary>Update configuration data for the specified handler.</fsummary>
+ <desc>
+ <p>Update configuration data for the specified handler. This function
+ behaves as if it was implemented as follows:</p>
+ <code type="erl">
+{ok, {_, Old}} = logger:get_handler_config(HandlerId),
+logger:set_handler_config(HandlerId, maps:merge(Old, Config)).
+ </code>
+ <p>To overwrite the existing configuration without any merge,
+ use <seealso marker="#set_handler_config-2"><c>set_handler_config/2</c>
+ </seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="update_handler_config" arity="3" clause_i="1" since="OTP 21.2"/>
+ <name name="update_handler_config" arity="3" clause_i="2" since="OTP 21.2"/>
+ <name name="update_handler_config" arity="3" clause_i="3" since="OTP 21.2"/>
+ <name name="update_handler_config" arity="3" clause_i="4" since="OTP 21.2"/>
+ <name name="update_handler_config" arity="3" clause_i="5" since="OTP 21.2"/>
+ <fsummary>Add or update configuration data for the specified
+ handler.</fsummary>
+ <type variable="HandlerId"/>
+ <type variable="Level" name_i="1"/>
+ <type variable="FilterDefault" name_i="2"/>
+ <type variable="Filters" name_i="3"/>
+ <type variable="Formatter" name_i="4"/>
+ <type variable="Config" name_i="5"/>
+ <type variable="Return"/>
+ <desc>
+ <p>Add or update configuration data for the specified
+ handler. If the given <c><anno>Key</anno></c> already
+ exists, its associated value will be changed
+ to the given value. If it does not exist, it will
+ be added.</p>
+ <p>If the value is incomplete, which for example can be the
+ case for the <c>config</c> key, it is up to the handler
+ implementation how the unspecified parts are set. For all
+ handlers in the Kernel application, unspecified data for
+ the <c>config</c> key is not changed. To reset unspecified
+ data to default values,
+ use <seealso marker="#set_handler_config-3">
+ <c>set_handler_config/3</c></seealso>.</p>
+ <p>See the definition of
+ the <seealso marker="#type-handler_config">
+ <c>handler_config()</c></seealso> type for more
+ information about the different parameters.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="update_primary_config" arity="1" since="OTP 21.0"/>
+ <fsummary>Update primary configuration data for Logger.</fsummary>
+ <desc>
+ <p>Update primary configuration data for Logger. This function
+ behaves as if it was implemented as follows:</p>
+ <code type="erl">
+Old = logger:get_primary_config(),
+logger:set_primary_config(maps:merge(Old, Config)).
+ </code>
+ <p>To overwrite the existing configuration without any merge,
+ use <seealso marker="#set_primary_config-1"><c>set_primary_config/1</c>
+ </seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="update_process_metadata" arity="1" since="OTP 21.0"/>
+ <fsummary>Set or update metadata to use when logging from
+ current process.</fsummary>
+ <desc>
+ <p>Set or update metadata to use when logging from current
+ process</p>
+ <p>If process metadata exists for the current process, this
+ function behaves as if it was implemented as follows:</p>
+ <code type="erl">
+logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)).
+ </code>
+ <p>If no process metadata exists, the function behaves as
+ <seealso marker="#set_process_metadata-1">
+ <c>set_process_metadata/1</c>
+ </seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="update_proxy_config" arity="1" since="OTP 21.3"/>
+ <fsummary>Update configuration data for the Logger proxy.</fsummary>
+ <desc>
+ <p>Update configuration data for the Logger proxy. This function
+ behaves as if it was implemented as follows:</p>
+ <code type="erl">
+Old = logger:get_proxy_config(),
+logger:set_proxy_config(maps:merge(Old, Config)).
+ </code>
+ <p>To overwrite the existing configuration without any merge,
+ use <seealso marker="#set_proxy_config-1"><c>set_proxy_config/1</c>
+ </seealso>.</p>
+ <p>For more information about the proxy, see
+ section <seealso marker="logger_chapter#proxy">Logger
+ Proxy</seealso> in the Kernel User's Guide.</p>
+ </desc>
+ </func>
+ </funcs>
+
+ <section>
+ <marker id="misc_API"/>
+ <title>Miscellaneous API functions</title>
+ </section>
+ <funcs>
+ <func>
+ <name name="compare_levels" arity="2" since="OTP 21.0"/>
+ <fsummary>Compare the severity of two log levels.</fsummary>
+ <desc>
+ <p>Compare the severity of two log levels. Returns <c>gt</c>
+ if <c>Level1</c> is more severe than
+ <c>Level2</c>, <c>lt</c> if <c>Level1</c> is less severe,
+ and <c>eq</c> if the levels are equal.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="format_report" arity="1" since="OTP 21.0"/>
+ <fsummary>Convert a log message on report form to {Format, Args}.</fsummary>
+ <desc>
+ <p>Convert a log message on report form to <c>{Format,
+ Args}</c>. This is the default report callback used
+ by <seealso marker="logger_formatter">
+ <c>logger_formatter</c></seealso> when no custom report
+ callback is found. See
+ section <seealso marker="logger_chapter#log_message">Log
+ Message</seealso> in the Kernel User's Guide for
+ information about report callbacks and valid forms of log
+ messages.</p>
+ <p>The function produces lines of <c>Key: Value</c> from
+ key-value lists. Strings are printed with <c>~ts</c> and
+ other terms with <c>~tp</c>.</p>
+ <p>If <c><anno>Report</anno></c> is a map, it is converted to
+ a key-value list before formatting as such.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="timestamp" arity="0" since="OTP 21.3"/>
+ <fsummary>Return a timestamp to insert in meta data for a log
+ event.</fsummary>
+ <desc>
+ <p>Return a timestamp that can be inserted as the <c>time</c>
+ field in the meta data for a log event. It is produced with
+ <seealso marker="kernel:os#system_time-1">
+ <c>os:system_time(microsecond)</c></seealso>.</p>
+ <p>Notice that Logger automatically inserts a timestamp in the
+ meta data unless it already exists. This function is
+ exported for the rare case when the timestamp must be taken
+ at a different point in time than when the log event is
+ issued.</p>
+ </desc>
+ </func>
+
+ </funcs>
+
+ <section>
+ <marker id="handler_callback_functions"/>
+ <title>Handler Callback Functions</title>
+ <p>The following functions are to be exported from a handler
+ callback module.</p>
+ </section>
+
+ <funcs>
+ <func>
+ <name since="OTP 21.0">HModule:adding_handler(Config1) -> {ok, Config2} | {error,
+ Reason}</name>
+ <fsummary>An instance of this handler is about to be added.</fsummary>
+ <type>
+ <v>Config1 = Config2 =
+ <seealso marker="#type-handler_config">handler_config()</seealso></v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>This callback function is optional.</p>
+ <p>The function is called on a temporary process when an new
+ handler is about to be added. The purpose is to verify the
+ configuration and initiate all resources needed by the
+ handler.</p>
+ <p>The handler identity is associated with the <c>id</c> key
+ in <c>Config1</c>.</p>
+ <p>If everything succeeds, the callback function can add
+ possible default values or internal state values to the
+ configuration, and return the adjusted map
+ in <c>{ok,Config2}</c>.</p>
+ <p>If the configuration is faulty, or if the initiation fails,
+ the callback function must return <c>{error,Reason}</c>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.2">HModule:changing_config(SetOrUpdate, OldConfig, NewConfig) -> {ok, Config} | {error, Reason}</name>
+ <fsummary>The configuration for this handler is about to change.</fsummary>
+ <type>
+ <v>SetOrUpdate = set | update</v>
+ <v>OldConfig = NewConfig = Config =
+ <seealso marker="#type-handler_config">handler_config()</seealso></v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>This callback function is optional.</p>
+ <p>The function is called on a temporary process when the
+ configuration for a handler is about to change. The purpose
+ is to verify and act on the new configuration.</p>
+ <p><c>OldConfig</c> is the existing configuration
+ and <c>NewConfig</c> is the new configuration.</p>
+ <p>The handler identity is associated with the <c>id</c> key
+ in <c>OldConfig</c>.</p>
+ <p><c>SetOrUpdate</c> has the value <c>set</c> if the
+ configuration change originates from a call to
+ <seealso marker="#set_handler_config-2">
+ <c>set_handler_config/2,3</c></seealso>, and <c>update</c>
+ if it originates from <seealso marker="#update_handler_config-2">
+ <c>update_handler_config/2,3</c></seealso>. The handler can
+ use this parameteter to decide how to update the value of
+ the <c>config</c> field, that is, the handler specific
+ configuration data. Typically, if <c>SetOrUpdate</c>
+ equals <c>set</c>, values that are not specified must be
+ given their default values. If <c>SetOrUpdate</c>
+ equals <c>update</c>, the values found in <c>OldConfig</c>
+ must be used instead.</p>
+ <p>If everything succeeds, the callback function must return a
+ possibly adjusted configuration in <c>{ok,Config}</c>.</p>
+ <p>If the configuration is faulty, the callback function must
+ return <c>{error,Reason}</c>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.2">HModule:filter_config(Config) -> FilteredConfig</name>
+ <fsummary>Remove internal data from configuration.</fsummary>
+ <type>
+ <v>Config = FilteredConfig =
+ <seealso marker="#type-handler_config">handler_config()</seealso></v>
+ </type>
+ <desc>
+ <p>This callback function is optional.</p>
+ <p>The function is called when one of the Logger API functions
+ for fetching the handler configuration is called, for
+ example
+ <seealso marker="#get_handler_config-1">
+ <c>logger:get_handler_config/1</c></seealso>.</p>
+ <p>It allows the handler to remove internal data fields from
+ its configuration data before it is returned to the
+ caller.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0">HModule:log(LogEvent, Config) -> void()</name>
+ <fsummary>Log the given log event.</fsummary>
+ <type>
+ <v>LogEvent =
+ <seealso marker="#type-log_event">log_event()</seealso></v>
+ <v>Config =
+ <seealso marker="#type-handler_config">handler_config()</seealso></v>
+ </type>
+ <desc>
+ <p>This callback function is mandatory.</p>
+ <p>The function is called when all primary filters and all
+ handler filters for the handler in question have passed for
+ the given log event. It is called on the client process, that
+ is, the process that issued the log event.</p>
+ <p>The handler identity is associated with the <c>id</c> key
+ in <c>Config</c>.</p>
+ <p>The handler must log the event.</p>
+ <p>The return value from this function is ignored by
+ Logger.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0">HModule:removing_handler(Config) -> ok</name>
+ <fsummary>The given handler is about to be removed.</fsummary>
+ <type>
+ <v>Config =
+ <seealso marker="#type-handler_config">handler_config()</seealso></v>
+ </type>
+ <desc>
+ <p>This callback function is optional.</p>
+ <p>The function is called on a temporary process when a
+ handler is about to be removed. The purpose is to release
+ all resources used by the handler.</p>
+ <p>The handler identity is associated with the <c>id</c> key
+ in <c>Config</c>.</p>
+ <p>The return value is ignored by Logger.</p>
+ </desc>
+ </func>
+
+ </funcs>
+
+ <section>
+ <marker id="formatter_callback_functions"/>
+ <title>Formatter Callback Functions</title>
+ <p>The following functions are to be exported from a formatter
+ callback module.</p>
+ </section>
+
+ <funcs>
+ <func>
+ <name since="OTP 21.0">FModule:check_config(FConfig) -> ok | {error, Reason}</name>
+ <fsummary>Validate the given formatter configuration.</fsummary>
+ <type>
+ <v>FConfig =
+ <seealso marker="#type-formatter_config">formatter_config()</seealso></v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>This callback function is optional.</p>
+ <p>The function is called by a Logger when formatter
+ configuration is set or modified. The formatter must
+ validate the given configuration and return <c>ok</c> if it
+ is correct, and <c>{error,Reason}</c> if it is faulty.</p>
+ <p>The following Logger API functions can trigger this callback:</p>
+ <list>
+ <item><seealso marker="logger#add_handler-3">
+ <c>logger:add_handler/3</c></seealso></item>
+ <item><seealso marker="logger#set_handler_config-2">
+ <c>logger:set_handler_config/2,3</c></seealso></item>
+ <item><seealso marker="logger#update_handler_config-2">
+ <c>logger:update_handler_config/2,3</c></seealso></item>
+ <item><seealso marker="logger#update_formatter_config-2">
+ <c>logger:update_formatter_config/2</c></seealso></item>
+ </list>
+ <p>See <seealso marker="logger_formatter">
+ <c>logger_formatter(3)</c></seealso>
+ for an example implementation. <c>logger_formatter</c> is the
+ default formatter used by Logger.</p>
+ </desc>
+ </func>
+ <func>
+ <name since="OTP 21.0">FModule:format(LogEvent, FConfig) -> FormattedLogEntry</name>
+ <fsummary>Format the given log event.</fsummary>
+ <type>
+ <v>LogEvent =
+ <seealso marker="#type-log_event">log_event()</seealso></v>
+ <v>FConfig =
+ <seealso marker="#type-formatter_config">formatter_config()</seealso></v>
+ <v>FormattedLogEntry =
+ <seealso marker="unicode#type-chardata">unicode:chardata()</seealso></v>
+ </type>
+ <desc>
+ <p>This callback function is mandatory.</p>
+ <p>The function can be called by a log handler to convert a
+ log event term to a printable string. The returned value
+ can, for example, be printed as a log entry to the console
+ or a file using <seealso marker="stdlib:io#put_chars-1">
+ <c>io:put_chars/1,2</c></seealso>.</p>
+ <p>See <seealso marker="logger_formatter">
+ <c>logger_formatter(3)</c></seealso>
+ for an example implementation. <c>logger_formatter</c> is the
+ default formatter used by Logger.</p>
+ </desc>
+ </func>
+ </funcs>
+
+ <section>
+ <title>See Also</title>
+ <p>
+ <seealso marker="config"><c>config(4)</c></seealso>,
+ <seealso marker="erts:erlang"><c>erlang(3)</c></seealso>,
+ <seealso marker="stdlib:io"><c>io(3)</c></seealso>,
+ <seealso marker="logger_disk_log_h"><c>logger_disk_log_h(3)</c></seealso>,
+ <seealso marker="logger_filters"><c>logger_filters(3)</c></seealso>,
+ <seealso marker="logger_formatter"><c>logger_formatter(3)</c></seealso>,
+ <seealso marker="logger_std_h"><c>logger_std_h(3)</c></seealso>,
+ <seealso marker="stdlib:unicode"><c>unicode(3)</c></seealso>
+ </p>
+ </section>
+</erlref>
diff --git a/lib/kernel/doc/src/logger_arch.dia b/lib/kernel/doc/src/logger_arch.dia
new file mode 100644
index 0000000000..97be31856e
--- /dev/null
+++ b/lib/kernel/doc/src/logger_arch.dia
Binary files differ
diff --git a/lib/kernel/doc/src/logger_arch.png b/lib/kernel/doc/src/logger_arch.png
new file mode 100644
index 0000000000..70933a5a41
--- /dev/null
+++ b/lib/kernel/doc/src/logger_arch.png
Binary files differ
diff --git a/lib/kernel/doc/src/logger_chapter.xml b/lib/kernel/doc/src/logger_chapter.xml
new file mode 100644
index 0000000000..1aa4b7a3a2
--- /dev/null
+++ b/lib/kernel/doc/src/logger_chapter.xml
@@ -0,0 +1,1399 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2017</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>Logging</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>logger_chapter.xml</file>
+ </header>
+
+ <p>Erlang/OTP 21.0 provides a standard API for logging
+ through <c>Logger</c>, which is part of the Kernel
+ application. Logger consists of the API for issuing log events,
+ and a customizable backend where log handlers, filters and
+ formatters can be plugged in.</p>
+ <p>By default, the Kernel application installs one log handler at
+ system start. This handler is named <c>default</c>. It receives
+ and processes standard log events produced by the Erlang runtime
+ system, standard behaviours and different Erlang/OTP
+ applications. The log events are by default written to the
+ terminal.</p>
+ <p>You can also configure the system so that the default handler
+ prints log events to a single file, or to a set of wrap logs
+ via <seealso marker="disk_log"><c>disk_log</c></seealso>.</p>
+ <p>By configuration, you can also modify or disable the default
+ handler, replace it by a custom handler, and install additional
+ handlers.</p>
+
+ <note>
+ <p>Since Logger is new in Erlang/OTP 21.0, we do reserve the right
+ to introduce changes to the Logger API and functionality in
+ patches following this release. These changes might or might not
+ be backwards compatible with the initial version.</p>
+ </note>
+
+ <section>
+ <title>Overview</title>
+ <p>A <em>log event</em> consists of a <em>log level</em>, the
+ <em>message</em> to be logged, and <em>metadata</em>.</p>
+ <p>The Logger backend forwards log events from the API, first
+ through a set of <em>primary filters</em>, then through a set of
+ secondary filters attached to each log handler. The secondary
+ filters are in the following named <em>handler filters</em>.</p>
+ <p>Each filter set consists of a <em>log level check</em>,
+ followed by zero or more <em>filter functions</em>.</p>
+ <p>The following figure shows a conceptual overview of Logger. The
+ figure shows two log handlers, but any number of handlers can be
+ installed.</p>
+
+ <!-- The image is edited with dia in logger_arch.dia file,
+ and .png file generated with make target 'png'. -->
+ <image file="logger_arch.png">
+ <icaption>Conceptual Overview</icaption>
+ </image>
+
+ <p>Log levels are expressed as atoms. Internally in Logger, the
+ atoms are mapped to integer values, and a log event passes the
+ log level check if the integer value of its log level is less
+ than or equal to the currently configured log level. That is,
+ the check passes if the event is equally or more severe than the
+ configured level. See section <seealso marker="#log_level">Log
+ Level</seealso> for a listing and description of all log
+ levels.</p>
+ <p>The primary log level can be overridden by a log level
+ configured per module. This is to, for instance, allow more
+ verbose logging from a specific part of the system.</p>
+ <p>Filter functions can be used for more sophisticated filtering
+ than the log level check provides. A filter function can stop or
+ pass a log event, based on any of the event's contents. It can
+ also modify all parts of the log event. See see
+ section <seealso marker="#filters">Filters</seealso> for more
+ details.</p>
+ <p>If a log event passes through all primary filters and all
+ handler filters for a specific handler, Logger forwards the
+ event to the <em>handler callback</em>. The handler formats and
+ prints the event to its destination. See
+ section <seealso marker="#handlers">Handlers</seealso> for more
+ details.</p>
+ <p>Everything up to and including the call to the handler
+ callbacks is executed on the client process, that is, the
+ process where the log event was issued. It is up to the handler
+ implementation if other processes are involved or not.</p>
+ <p>The handlers are called in sequence, and the order is not
+ defined.</p>
+ </section>
+ <section>
+ <marker id="logger_api"/>
+ <title>Logger API</title>
+ <p>The API for logging consists of a set
+ of <seealso marker="logger#macros">macros</seealso>, and a set
+ of functions on the form <c>logger:Level/1,2,3</c>, which are
+ all shortcuts
+ for <seealso marker="logger#log-2">
+ <c>logger:log(Level,Arg1[,Arg2[,Arg3]])</c></seealso>.</p>
+ <p>The macros are defined in <c>logger.hrl</c>, which is included
+ in a module with the directive</p>
+ <code>-include_lib("kernel/include/logger.hrl").</code>
+ <p>The difference between using the macros and the exported
+ functions is that macros add location (originator) information
+ to the metadata, and performs lazy evaluation by wrapping the
+ logger call in a case statement, so it is only evaluated if the
+ log level of the event passes the primary log level check.</p>
+ <section>
+ <marker id="log_level"/>
+ <title>Log Level</title>
+ <p>The log level indicates the severity of a event. In
+ accordance with the Syslog protocol,
+ <url href="https://www.ietf.org/rfc/rfc5424.txt">RFC
+ 5424</url>, eight log levels can be specified. The following
+ table lists all possible log levels by name (atom), integer
+ value, and description:</p>
+
+ <table align="left">
+ <row>
+ <cell><strong>Level</strong></cell>
+ <cell align="center"><strong>Integer</strong></cell>
+ <cell><strong>Description</strong></cell>
+ </row>
+ <row>
+ <cell>emergency</cell>
+ <cell align="center">0</cell>
+ <cell>system is unusable</cell>
+ </row>
+ <row>
+ <cell>alert</cell>
+ <cell align="center">1</cell>
+ <cell>action must be taken immediately</cell>
+ </row>
+ <row>
+ <cell>critical</cell>
+ <cell align="center">2</cell>
+ <cell>critical conditions</cell>
+ </row>
+ <row>
+ <cell>error</cell>
+ <cell align="center">3</cell>
+ <cell>error conditions</cell>
+ </row>
+ <row>
+ <cell>warning</cell>
+ <cell align="center">4</cell>
+ <cell>warning conditions</cell>
+ </row>
+ <row>
+ <cell>notice</cell>
+ <cell align="center">5</cell>
+ <cell>normal but significant conditions</cell>
+ </row>
+ <row>
+ <cell>info</cell>
+ <cell align="center">6</cell>
+ <cell>informational messages</cell>
+ </row>
+ <row>
+ <cell>debug</cell>
+ <cell align="center">7</cell>
+ <cell>debug-level messages</cell>
+ </row>
+ <tcaption>Log Levels</tcaption>
+ </table>
+ <p>Notice that the integer value is only used internally in
+ Logger. In the API, you must always use the atom. To compare
+ the severity of two log levels,
+ use <seealso marker="logger#compare_levels-2">
+ <c>logger:compare_levels/2</c></seealso>.</p>
+ </section>
+ <section>
+ <marker id="log_message"/>
+ <title>Log Message</title>
+ <p>The log message contains the information to be logged. The
+ message can consist of a format string and arguments (given as
+ two separate parameters in the Logger API), a string or a
+ report. The latter, which is either a map or a key-value list,
+ can be accompanied by a <em>report callback</em> specified in
+ the log event's <seealso marker="#metadata">metadata</seealso>.
+ The report callback is a convenience function that
+ the <seealso marker="#formatters">formatter</seealso> can use
+ to convert the report to a format string and arguments, or
+ directly to a string. The
+ formatter can also use its own conversion function, if no
+ callback is provided, or if a customized formatting is
+ desired.</p>
+ <p>The report callback must be a fun with one or two
+ arguments. If it takes one argument, this is the report
+ itself, and the fun returns a format string and arguments:</p>
+ <pre>fun((<seealso marker="logger#type-report"><c>logger:report()</c></seealso>) -> {<seealso marker="stdlib:io#type-format"><c>io:format()</c></seealso>,[term()]})</pre>
+ <p>If it takes two arguments, the first is the report, and the
+ second is a map containing extra data that allows direct
+ coversion to a string:</p>
+ <pre>fun((<seealso marker="logger#type-report"><c>logger:report()</c></seealso>,<seealso marker="logger#type-report_cb_config"><c>logger:report_cb_config()</c></seealso>) -> <seealso marker="stdlib:unicode#type-chardata"><c>unicode:chardata()</c></seealso>)
+ </pre>
+ <p>The fun must obey the <c>depth</c> and <c>chars_limit</c>
+ parameters provided in the second argument, as the formatter
+ cannot do anything useful of these parameters with the
+ returned string. The extra data also contains a field named
+ <c>single_line</c>, indicating if the printed log message may
+ contain line breaks or not. This variant is used when the
+ formatting of the report depends on the size or single line
+ parameters.</p>
+ <p>Example, format string and arguments:</p>
+ <code>logger:error("The file does not exist: ~ts",[Filename])</code>
+ <p>Example, string:</p>
+ <code>logger:notice("Something strange happened!")</code>
+ <p>Example, report, and metadata with report callback:</p>
+ <code>
+logger:debug(#{got => connection_request, id => Id, state => State},
+ #{report_cb => fun(R) -> {"~p",[R]} end})</code>
+ <p>The log message can also be provided through a fun for lazy
+ evaluation. The fun is only evaluated if the primary log level
+ check passes, and is therefore recommended if it is expensive
+ to generate the message. The lazy fun must return a string, a
+ report, or a tuple with format string and arguments.</p>
+ </section>
+ <section>
+ <title>Metadata</title>
+ <p>Metadata contains additional data associated with a log
+ message. Logger inserts some metadata fields by default, and
+ the client can add custom metadata in two different ways:</p>
+ <taglist>
+ <tag>Set process metadata</tag>
+ <item>
+ <p>Process metadata is set and updated
+ with <seealso marker="logger#set_process_metadata-1">
+ <c>logger:set_process_metadata/1</c></seealso>
+ and <seealso marker="logger#update_process_metadata-1">
+ <c>logger:update_process_metadata/1</c></seealso>,
+ respectively. This metadata applies to the process on
+ which these calls are made, and Logger adds the metadata
+ to all log events issued on that process.</p>
+ </item>
+ <tag>Add metadata to a specific log event</tag>
+ <item>
+ <p>Metadata associated with one specific log event is given
+ as the last parameter to the log macro or Logger API
+ function when the event is issued. For example:</p>
+ <code>?LOG_ERROR("Connection closed",#{context => server})</code>
+ </item>
+ </taglist>
+ <p>See the description of
+ the <seealso marker="logger#type-metadata">
+ <c>logger:metadata()</c></seealso> type for information
+ about which default keys Logger inserts, and how the different
+ metadata maps are merged.</p>
+ </section>
+ </section>
+ <section>
+ <marker id="filter"/>
+ <title>Filters</title>
+ <p>Filters can be primary, or attached to a specific
+ handler. Logger calls the primary filters first, and if they all
+ pass, it calls the handler filters for each handler. Logger
+ calls the handler callback only if all filters attached to the
+ handler in question also pass.</p>
+ <p>A filter is defined as:</p>
+ <pre>{FilterFun, Extra}</pre>
+ <p>where <c>FilterFun</c> is a function of arity 2,
+ and <c>Extra</c> is any term. When applying the filter, Logger
+ calls the function with the log event as the first argument,
+ and the value of <c>Extra</c> as the second
+ argument. See <seealso marker="logger#type-filter">
+ <c>logger:filter()</c></seealso> for type definitions.</p>
+ <p>The filter function can return <c>stop</c>, <c>ignore</c> or
+ the (possibly modified) log event.</p>
+ <p>If <c>stop</c> is returned, the log event is immediately
+ discarded. If the filter is primary, no handler filters or
+ callbacks are called. If it is a handler filter, the
+ corresponding handler callback is not called, but the log event
+ is forwarded to filters attached to the next handler, if
+ any.</p>
+ <p>If the log event is returned, the next filter function is
+ called with the returned value as the first argument. That is,
+ if a filter function modifies the log event, the next filter
+ function receives the modified event. The value returned from
+ the last filter function is the value that the handler callback
+ receives.</p>
+ <p>If the filter function returns <c>ignore</c>, it means that it
+ did not recognize the log event, and thus leaves to other
+ filters to decide the event's destiny.</p>
+ <p>The configuration option <c>filter_default</c> specifies the
+ behaviour if all filter functions return <c>ignore</c>, or if no
+ filters exist. <c>filter_default</c> is by default set
+ to <c>log</c>, meaning that if all existing filters ignore a log
+ event, Logger forwards the event to the handler
+ callback. If <c>filter_default</c> is set to <c>stop</c>, Logger
+ discards such events.</p>
+ <p>Primary filters are added
+ with <seealso marker="logger#add_primary_filter-2">
+ <c>logger:add_primary_filter/2</c></seealso>
+ and removed
+ with <seealso marker="logger#remove_primary_filter-1">
+ <c>logger:remove_primary_filter/1</c></seealso>. They can also
+ be added at system start via the Kernel configuration
+ parameter <seealso marker="#logger_parameter"><c>logger</c></seealso>.</p>
+ <p>Handler filters are added
+ with <seealso marker="logger#add_handler_filter-3">
+ <c>logger:add_handler_filter/3</c></seealso>
+ and removed
+ with <seealso marker="logger#remove_handler_filter-2">
+ <c>logger:remove_handler_filter/2</c></seealso>. They can also
+ be specified directly in the configuration when adding a handler
+ with <seealso marker="logger#add_handler/3">
+ <c>logger:add_handler/3</c></seealso>
+ or via the Kernel configuration
+ parameter <seealso marker="#logger_parameter"><c>logger</c></seealso>.</p>
+
+ <p>To see which filters are currently installed in the system,
+ use <seealso marker="logger#get_config-0">
+ <c>logger:get_config/0</c></seealso>,
+ or <seealso marker="logger#get_primary_config-0">
+ <c>logger:get_primary_config/0</c></seealso>
+ and <seealso marker="logger#get_handler_config-1">
+ <c>logger:get_handler_config/1</c></seealso>. Filters are
+ listed in the order they are applied, that is, the first
+ filter in the list is applied first, and so on.</p>
+
+ <p>For convenience, the following built-in filters exist:</p>
+
+ <taglist>
+ <tag><seealso marker="logger_filters#domain-2">
+ <c>logger_filters:domain/2</c></seealso></tag>
+ <item>
+ <p>Provides a way of filtering log events based on a
+ <c>domain</c> field in <c>Metadata</c>.</p>
+ </item>
+ <tag><seealso marker="logger_filters#level-2">
+ <c>logger_filters:level/2</c></seealso></tag>
+ <item>
+ <p>Provides a way of filtering log events based on the log
+ level.</p>
+ </item>
+ <tag><seealso marker="logger_filters#progress-2">
+ <c>logger_filters:progress/2</c></seealso></tag>
+ <item>
+ <p>Stops or allows progress reports from <c>supervisor</c>
+ and <c>application_controller</c>.</p>
+ </item>
+ <tag><seealso marker="logger_filters#remote_gl-2">
+ <c>logger_filters:remote_gl/2</c></seealso></tag>
+ <item>
+ <p>Stops or allows log events originating from a process
+ that has its group leader on a remote node.</p>
+ </item>
+ </taglist>
+ </section>
+
+ <section>
+ <marker id="handlers"/>
+ <title>Handlers</title>
+ <p>A handler is defined as a module exporting at least the
+ following callback function:</p>
+
+ <pre><seealso marker="logger#HModule:log-2">log(LogEvent, Config) -> void()</seealso></pre>
+
+ <p>This function is called when a log event has passed through all
+ primary filters, and all handler filters attached to the handler
+ in question. The function call is executed on the client
+ process, and it is up to the handler implementation if other
+ processes are involved or not.</p>
+
+ <p>Logger allows adding multiple instances of a handler
+ callback. That is, if a callback module implementation allows
+ it, you can add multiple handler instances using the same
+ callback module. The different instances are identified by
+ unique handler identities.</p>
+
+ <p>In addition to the mandatory callback function <c>log/2</c>, a
+ handler module can export the optional callback
+ functions <c>adding_handler/1</c>, <c>changing_config/3</c>,
+ <c>filter_config/1</c>, and <c>removing_handler/1</c>. See
+ section <seealso marker="logger#handler_callback_functions">Handler
+ Callback Functions</seealso> in the logger(3) manual page for
+ more information about these function.</p>
+
+ <p>The following built-in handlers exist:</p>
+
+ <taglist>
+ <tag><c>logger_std_h</c></tag>
+ <item>
+ <p>This is the default handler used by OTP. Multiple instances
+ can be started, and each instance will write log events to a
+ given destination, terminal or file.</p>
+ </item>
+
+ <tag><c>logger_disk_log_h</c></tag>
+ <item>
+ <p>This handler behaves much like <c>logger_std_h</c>, except it uses
+ <seealso marker="disk_log"><c>disk_log</c></seealso> as its
+ destination.</p>
+ </item>
+
+ <tag><marker id="ErrorLoggerManager"/><c>error_logger</c></tag>
+ <item>
+ <p>This handler is provided for backwards compatibility
+ only. It is not started by default, but will be
+ automatically started the first time an <c>error_logger</c>
+ event handler is added
+ with <seealso marker="error_logger#add_report_handler-1">
+ <c>error_logger:add_report_handler/1,2</c></seealso>.</p>
+
+ <p>The old <c>error_logger</c> event handlers in STDLIB and
+ SASL still exist, but they are not added by Erlang/OTP 21.0
+ or later.</p>
+ </item>
+ </taglist>
+ </section>
+
+ <section>
+ <marker id="formatters"/>
+ <title>Formatters</title>
+ <p>A formatter can be used by the handler implementation to do the
+ final formatting of a log event, before printing to the
+ handler's destination. The handler callback receives the
+ formatter information as part of the handler configuration,
+ which is passed as the second argument
+ to <seealso marker="logger#HModule:log-2">
+ <c>HModule:log/2</c></seealso>.</p>
+ <p>The formatter information consist of a formatter
+ module, <c>FModule</c> and its
+ configuration, <c>FConfig</c>. <c>FModule</c> must export the
+ following function, which can be called by the handler:</p>
+ <pre><seealso marker="logger#FModule:format-2">format(LogEvent,FConfig)
+ -> FormattedLogEntry</seealso></pre>
+ <p>The formatter information for a handler is set as a part of its
+ configuration when the handler is added. It can also be changed
+ during runtime
+ with <seealso marker="logger#set_handler_config-3">
+ <c>logger:set_handler_config(HandlerId,formatter,{FModule,FConfig})</c>
+ </seealso>, which overwrites the current formatter information,
+ or with <seealso marker="logger#update_formatter_config-2">
+ <c>logger:update_formatter_config/2,3</c></seealso>, which
+ only modifies the formatter configuration.</p>
+ <p>If the formatter module exports the optional callback
+ function <seealso marker="logger#FModule:check_config-1">
+ <c>check_config(FConfig)</c></seealso>, Logger calls this
+ function when the formatter information is set or modified, to
+ verify the validity of the formatter configuration.</p>
+ <p>If no formatter information is specified for a handler, Logger
+ uses <c>logger_formatter</c> as default. See
+ the <seealso marker="logger_formatter"><c>logger_formatter(3)</c></seealso>
+ manual page for more information about this module.</p>
+ </section>
+
+ <section>
+ <title>Configuration</title>
+
+ <p>At system start, Logger is configured through Kernel
+ configuration parameters. The parameters that apply to Logger
+ are described in
+ section <seealso marker="#kernel_config_params">Kernel
+ Configuration Parameters</seealso>. Examples are found in
+ section <seealso marker="#config_examples">Configuration
+ Examples</seealso>.</p>
+ <p>During runtime, Logger configuration is changed via API
+ functions. See
+ section <seealso marker="logger#configuration_API">Configuration
+ API Functions</seealso> in the <c>logger(3)</c> manual page.</p>
+
+ <section>
+ <title>Primary Logger Configuration</title>
+ <p>Logger API functions that apply to the primary Logger
+ configuration are:</p>
+ <list>
+ <item><seealso marker="logger#get_primary_config-0">
+ <c>get_primary_config/0</c></seealso></item>
+ <item><seealso marker="logger#set_primary_config-1">
+ <c>set_primary_config/1,2</c></seealso></item>
+ <item><seealso marker="logger#update_primary_config-1">
+ <c>update_primary_config/1</c></seealso></item>
+ <item><seealso marker="logger#add_primary_filter-2">
+ <c>add_primary_filter/2</c></seealso></item>
+ <item><seealso marker="logger#remove_primary_filter-1">
+ <c>remove_primary_filter/1</c></seealso></item>
+ </list>
+ <p>The primary Logger configuration is a map with the following
+ keys:</p>
+ <taglist>
+ <tag><marker id="primary_level"/>
+ <c>level = </c><seealso marker="logger#type-level">
+ <c>logger:level()</c></seealso><c> | all | none</c></tag>
+ <item>
+ <p>Specifies the primary log level, that is, log event that
+ are equally or more severe than this level, are forwarded
+ to the primary filters. Less severe log events are
+ immediately discarded.</p>
+ <p>See section <seealso marker="#log_level">Log
+ Level</seealso> for a listing and description of
+ possible log levels.</p>
+ <p>The initial value of this option is set by the Kernel
+ configuration parameter <seealso marker="#logger_level">
+ <c>logger_level</c></seealso>. It is changed during
+ runtime with <seealso marker="logger#set_primary_config-2">
+ <c>logger:set_primary_config(level,Level)</c></seealso>.</p>
+ <p>Defaults to <c>notice</c>.</p>
+ </item>
+ <tag><c>filters = [{FilterId,Filter}]</c></tag>
+ <item>
+ <p>Specifies the primary filters.</p>
+ <list>
+ <item><c>FilterId = </c><seealso marker="logger#type-filter_id">
+ <c>logger:filter_id()</c></seealso></item>
+ <item><c>Filter = </c><seealso marker="logger#type-filter">
+ <c>logger:filter()</c></seealso></item>
+ </list>
+ <p>The initial value of this option is set by the Kernel
+ configuration
+ parameter <seealso marker="#logger_parameter"><c>logger</c></seealso>.
+ During runtime, primary filters are added and removed with
+ <seealso marker="logger#add_primary_filter-2">
+ <c>logger:add_primary_filter/2</c></seealso> and
+ <seealso marker="logger#remove_primary_filter-1">
+ <c>logger:remove_primary_filter/1</c></seealso>,
+ respectively.</p>
+ <p>See section <seealso marker="#filters">Filters</seealso>
+ for more detailed information.</p>
+ <p>Defaults to <c>[]</c>.</p>
+ </item>
+ <tag><c>filter_default = log | stop</c></tag>
+ <item>
+ <p>Specifies what happens to a log event if all filters
+ return <c>ignore</c>, or if no filters exist.</p>
+ <p>See section <seealso marker="#filters">Filters</seealso>
+ for more information about how this option is used.</p>
+ <p>Defaults to <c>log</c>.</p>
+ </item>
+ </taglist>
+ </section>
+
+ <section>
+ <marker id="handler_configuration"/>
+ <title>Handler Configuration</title>
+ <p>Logger API functions that apply to handler configuration
+ are:</p>
+ <list>
+ <item><seealso marker="logger#get_handler_config-0">
+ <c>get_handler_config/0,1</c></seealso></item>
+ <item><seealso marker="logger#set_handler_config-2">
+ <c>set_handler_config/2,3</c></seealso></item>
+ <item><seealso marker="logger#update_handler_config-2">
+ <c>update_handler_config/2,3</c></seealso></item>
+ <item><seealso marker="logger#add_handler_filter-3">
+ <c>add_handler_filter/3</c></seealso></item>
+ <item><seealso marker="logger#remove_handler_filter-2">
+ <c>remove_handler_filter/2</c></seealso></item>
+ <item><seealso marker="logger#update_formatter_config-2">
+ <c>update_formatter_config/2,3</c></seealso></item>
+ </list>
+ <p>The configuration for a handler is a map with the following keys:</p>
+ <taglist>
+ <tag><c>id = </c><seealso marker="logger#type-handler_id">
+ <c>logger:handler_id()</c></seealso></tag>
+ <item>
+ <p>Automatically inserted by Logger. The value is the same
+ as the <c>HandlerId</c> specified when adding the handler,
+ and it cannot be changed.</p>
+ </item>
+ <tag><c>module = module()</c></tag>
+ <item>
+ <p>Automatically inserted by Logger. The value is the same
+ as the <c>Module</c> specified when adding the handler,
+ and it cannot be changed.</p>
+ </item>
+ <tag><c>level = </c><seealso marker="logger#type-level">
+ <c>logger:level()</c></seealso><c> | all | none</c></tag>
+ <item>
+ <p>Specifies the log level for the handler, that is, log
+ events that are equally or more severe than this level,
+ are forwarded to the handler filters for this
+ handler.</p>
+ <p>See section <seealso marker="#log_level">Log
+ Level</seealso> for a listing and description of
+ possible log levels.</p>
+ <p>The log level is specified when adding the handler, or
+ changed during runtime with, for
+ instance, <seealso marker="logger#set_handler_config/3">
+ <c>logger:set_handler_config(HandlerId,level,Level)</c></seealso>.
+ </p>
+ <p>Defaults to <c>all</c>.</p>
+ </item>
+ <tag><c>filters = [{FilterId,Filter}]</c></tag>
+ <item>
+ <p>Specifies the handler filters.</p>
+ <list>
+ <item><c>FilterId = </c><seealso marker="logger#type-filter_id">
+ <c>logger:filter_id()</c></seealso></item>
+ <item><c>Filter = </c><seealso marker="logger#type-filter">
+ <c>logger:filter()</c></seealso></item>
+ </list>
+ <p>Handler filters are specified when adding the handler,
+ or added or removed during runtime with
+ <seealso marker="logger#add_handler_filter-3">
+ <c>logger:add_handler_filter/3</c></seealso> and
+ <seealso marker="logger#remove_handler_filter-2">
+ <c>logger:remove_handler_filter/2</c></seealso>,
+ respectively.</p>
+ <p>See <seealso marker="#filters">Filters</seealso> for more
+ detailed information.</p>
+ <p>Defaults to <c>[]</c>.</p>
+ </item>
+ <tag><c>filter_default = log | stop</c></tag>
+ <item>
+ <p>Specifies what happens to a log event if all filters
+ return <c>ignore</c>, or if no filters exist.</p>
+ <p>See section <seealso marker="#filters">Filters</seealso>
+ for more information about how this option is used.</p>
+ <p>Defaults to <c>log</c>.</p>
+ </item>
+ <tag><c>formatter = {FormatterModule,FormatterConfig}</c></tag>
+ <item>
+ <p>Specifies a formatter that the handler can use for
+ converting the log event term to a printable string.</p>
+ <list>
+ <item><c>FormatterModule = module()</c></item>
+ <item><c>FormatterConfig = </c>
+ <seealso marker="logger#type-formatter_config">
+ <c>logger:formatter_config()</c></seealso></item>
+ </list>
+ <p>The formatter information is specified when adding the
+ handler. The formatter configuration can be changed during
+ runtime
+ with <seealso marker="logger#update_formatter_config-2">
+ <c>logger:update_formatter_config/2,3</c></seealso>,
+ or the complete formatter information can be overwritten
+ with, for
+ instance, <seealso marker="logger#set_handler_config-3">
+ <c>logger:set_handler_config/3</c></seealso>.</p>
+ <p>See
+ section <seealso marker="#formatters">Formatters</seealso>
+ for more detailed information.</p>
+ <p>Defaults
+ to <c>{logger_formatter,DefaultFormatterConfig}</c>. See
+ the <seealso marker="logger_formatter">
+ <c>logger_formatter(3)</c></seealso> manual page for
+ information about this formatter and its default
+ configuration.</p>
+ </item>
+ <tag><c>config = term()</c></tag>
+ <item>
+ <p>Handler specific configuration, that is, configuration
+ data related to a specific handler implementation.</p>
+ <p>The configuration for the built-in handlers is described
+ in
+ the <seealso marker="logger_std_h"><c>logger_std_h(3)</c></seealso>
+ and
+ <seealso marker="logger_disk_log_h"><c>logger_disk_log_h(3)</c>
+ </seealso> manual pages.</p>
+ </item>
+ </taglist>
+
+ <p>Notice that <c>level</c> and <c>filters</c> are obeyed by
+ Logger itself before forwarding the log events to each
+ handler, while <c>formatter</c> and all handler specific
+ options are left to the handler implementation.</p>
+ </section>
+
+ <section>
+ <marker id="kernel_config_params"/>
+ <title>Kernel Configuration Parameters</title>
+
+ <p>The following Kernel configuration parameters apply to
+ Logger:</p>
+ <taglist>
+ <tag><marker id="logger_parameter"/><c>logger = [Config]</c></tag>
+ <item>
+ <p>Specifies the configuration
+ for <seealso marker="logger">Logger</seealso>, except the
+ primary log level, which is specified
+ with <seealso marker="#logger_level"><c>logger_level</c></seealso>,
+ and the compatibility
+ with <seealso marker="sasl:error_logging">SASL Error
+ Logging</seealso>, which is specified
+ with <seealso marker="#logger_sasl_compatible">
+ <c>logger_sasl_compatible</c></seealso>.</p>
+ <p>With this parameter, you can modify or disable the default
+ handler, add custom handlers and primary logger filters, set
+ log levels per module, and modify
+ the <seealso marker="#proxy">proxy</seealso>
+ configuration.</p>
+ <p><c>Config</c> is any (zero or more) of the following:</p>
+ <taglist>
+ <tag><c>{handler, default, undefined}</c></tag>
+ <item>
+ <p>Disables the default handler. This allows another
+ application to add its own default handler.</p>
+ <p>Only one entry of this type is allowed.</p>
+ </item>
+ <tag><c>{handler, HandlerId, Module, HandlerConfig}</c></tag>
+ <item>
+ <p>If <c>HandlerId</c> is <c>default</c>, then this entry
+ modifies the default handler, equivalent to calling</p>
+ <pre><seealso marker="logger#remove_handler-1">
+ logger:remove_handler(default)
+ </seealso></pre>
+ <p>followed by</p>
+ <pre><seealso marker="logger#add_handler-3">
+ logger:add_handler(default, Module, HandlerConfig)
+ </seealso></pre>
+ <p>For all other values of <c>HandlerId</c>, this entry
+ adds a new handler, equivalent to calling</p>
+ <pre><seealso marker="logger#add_handler/3">
+ logger:add_handler(HandlerId, Module, HandlerConfig)
+ </seealso></pre>
+ <p>Multiple entries of this type are allowed.</p></item>
+ <tag><c>{filters, FilterDefault, [Filter]}</c></tag>
+ <item>
+ <p>Adds the specified primary filters.</p>
+ <list>
+ <item><c>FilterDefault = log | stop</c></item>
+ <item><c>Filter = {FilterId, {FilterFun, FilterConfig}}</c></item>
+ </list>
+ <p>Equivalent to calling</p>
+ <pre><seealso marker="logger#add_primary_filter/2">
+ logger:add_primary_filter(FilterId, {FilterFun, FilterConfig})
+ </seealso></pre>
+ <p>for each <c>Filter</c>.</p>
+ <p><c>FilterDefault</c> specifies the behaviour if all
+ primary filters return <c>ignore</c>, see
+ section <seealso marker="#filters">Filters</seealso>.</p>
+ <p>Only one entry of this type is allowed.</p>
+ </item>
+ <tag><c>{module_level, Level, [Module]}</c></tag>
+ <item>
+ <p>Sets module log level for the given modules. Equivalent
+ to calling</p>
+ <pre><seealso marker="logger#set_module_level/2">
+ logger:set_module_level(Module, Level)</seealso></pre>
+ <p>for each <c>Module</c>.</p>
+ <p>Multiple entries of this type are allowed.</p>
+ </item>
+ <tag><c>{proxy, ProxyConfig}</c></tag>
+ <item>
+ <p>Sets the proxy configuration, equivalent to calling</p>
+ <pre><seealso marker="logger#set_proxy_config/1">
+ logger:set_proxy_config(ProxyConfig)
+ </seealso></pre>
+ <p>Only one entry of this type is allowed.</p>
+ </item>
+ </taglist>
+ <p>See
+ section <seealso marker="#config_examples">Configuration
+ Examples</seealso> for examples using the <c>logger</c>
+ parameter for system configuration.</p>
+ </item>
+ <tag><marker id="logger_level"/>
+ <c>logger_level = Level</c></tag>
+ <item>
+ <p>Specifies the primary log level. See
+ the <seealso marker="kernel_app#logger_level"><c>kernel(6)</c></seealso>
+ manual page for more information about this parameter.</p>
+ </item>
+ <tag><marker id="logger_sasl_compatible"/>
+ <c>logger_sasl_compatible = true | false</c></tag>
+ <item>
+ <p>Specifies Logger's compatibility
+ with <seealso marker="sasl:error_logging">SASL Error
+ Logging</seealso>. See
+ the <seealso marker="kernel_app#logger_sasl_compatible">
+ <c>kernel(6)</c></seealso> manual page for more
+ information about this parameter.</p>
+ </item>
+ </taglist>
+ </section>
+
+ <section>
+ <marker id="config_examples"/>
+ <title>Configuration Examples</title>
+ <p>The value of the Kernel configuration parameter <c>logger</c>
+ is a list of tuples. It is possible to write the term on the
+ command line when starting an erlang node, but as the term
+ grows, a better approach is to use the system configuration
+ file. See
+ the <seealso marker="config"><c>config(4)</c></seealso> manual
+ page for more information about this file.</p>
+ <p>Each of the following examples shows a simple system
+ configuration file that configures Logger according to the
+ description.</p>
+ <p>Modify the default handler to print to a file instead of
+ <c>standard_io</c>:</p>
+ <code>
+[{kernel,
+ [{logger,
+ [{handler, default, logger_std_h, % {handler, HandlerId, Module,
+ #{config => #{file => "log/erlang.log"}}} % Config}
+ ]}]}].
+ </code>
+ <p>Modify the default handler to print each log event as a
+ single line:</p>
+ <code>
+[{kernel,
+ [{logger,
+ [{handler, default, logger_std_h,
+ #{formatter => {logger_formatter, #{single_line => true}}}}
+ ]}]}].
+ </code>
+ <p>Modify the default handler to print the pid of the logging
+ process for each log event:</p>
+ <code>
+[{kernel,
+ [{logger,
+ [{handler, default, logger_std_h,
+ #{formatter => {logger_formatter,
+ #{template => [time," ",pid," ",msg,"\n"]}}}}
+ ]}]}].
+ </code>
+ <p>Modify the default handler to only print errors and more
+ severe log events to "log/erlang.log", and add another handler
+ to print all log events to "log/debug.log".</p>
+ <code>
+[{kernel,
+ [{logger,
+ [{handler, default, logger_std_h,
+ #{level => error,
+ config => #{file => "log/erlang.log"}}},
+ {handler, info, logger_std_h,
+ #{level => debug,
+ config => #{file => "log/debug.log"}}}
+ ]}]}].
+ </code>
+ </section>
+
+ </section>
+
+ <section>
+ <marker id="compatibility"/>
+ <title>Backwards Compatibility with error_logger</title>
+ <p>Logger provides backwards compatibility with
+ <c>error_logger</c> in the following ways:</p>
+
+ <taglist>
+ <tag>API for Logging</tag>
+ <item>
+ <p>The <c>error_logger</c> API still exists, but should only
+ be used by legacy code. It will be removed in a later
+ release.</p>
+ <p>Calls
+ to <seealso marker="error_logger#error_report-1">
+ <c>error_logger:error_report/1,2</c></seealso>,
+ <seealso marker="error_logger#error_msg-1">
+ <c>error_logger:error_msg/1,2</c></seealso>, and
+ corresponding functions for warning and info messages, are
+ all forwarded to Logger as calls
+ to <seealso marker="logger#log-3">
+ <c>logger:log(Level,Report,Metadata)</c></seealso>.</p>
+ <p><c>Level = error | warning | info</c> and is taken
+ from the function name. <c>Report</c> contains the actual
+ log message, and <c>Metadata</c> contains additional
+ information which can be used for creating backwards
+ compatible events for legacy <c>error_logger</c> event
+ handlers, see
+ section <seealso marker="#legacy_event_handlers">Legacy
+ Event Handlers</seealso>.</p>
+ </item>
+ <tag>Output Format</tag>
+ <item>
+ <p>To get log events on the same format as produced
+ by <c>error_logger_tty_h</c> and <c>error_logger_file_h</c>,
+ use the default formatter, <c>logger_formatter</c>, with
+ configuration parameter <c>legacy_header</c> set
+ to <c>true</c>. This is the default configuration of
+ the <c>default</c> handler started by Kernel.</p>
+ </item>
+ <tag>Default Format of Log Events from OTP</tag>
+ <item>
+ <p>By default, all log events originating from within OTP,
+ except the former so called "SASL reports", look the same as
+ before.</p>
+ </item>
+ <tag><marker id="sasl_reports"/>SASL Reports</tag>
+ <item>
+ <p>By SASL reports we mean supervisor reports, crash reports
+ and progress reports.</p>
+ <p>Prior to Erlang/OTP 21.0, these reports were only logged
+ when the SASL application was running, and they were printed
+ trough SASL's own event handlers <c>sasl_report_tty_h</c>
+ and <c>sasl_report_file_h</c>.</p>
+ <p>The destination of these log events was configured by
+ <seealso marker="sasl:sasl_app#deprecated_error_logger_config">SASL
+ configuration parameters</seealso>.</p>
+ <p>Due to the specific event handlers, the output format
+ slightly differed from other log events.</p>
+ <p>As of Erlang/OTP 21.0, the concept of SASL reports is
+ removed, meaning that the default behaviour is as
+ follows:</p>
+ <list>
+ <item>Supervisor reports, crash reports, and progress reports
+ are no longer connected to the SASL application.</item>
+ <item>Supervisor reports and crash reports are issued
+ as <c>error</c> level log events, and are logged through
+ the default handler started by Kernel.</item>
+ <item>Progress reports are issued as <c>info</c> level log
+ events, and since the default primary log level
+ is <c>notice</c>, these are not logged by default. To
+ enable printing of progress reports, set
+ the <seealso marker="#primary_level">primary log
+ level</seealso> to <c>info</c>.</item>
+ <item>The output format is the same for all log
+ events.</item>
+ </list>
+ <p>If the old behaviour is preferred, the Kernel configuration
+ parameter <seealso marker="kernel_app#logger_sasl_compatible">
+ <c>logger_sasl_compatible</c></seealso> can be set
+ to <c>true</c>. The
+ <seealso marker="sasl:sasl_app#deprecated_error_logger_config">SASL
+ configuration parameters</seealso> can then be used as
+ before, and the SASL reports will only be printed if the
+ SASL application is running, through a second log handler
+ named <c>sasl</c>.</p>
+ <p>All SASL reports have a metadata field <c>domain</c> which
+ is set to <c>[otp,sasl]</c>. This field can be
+ used by filters to stop or allow the log events.</p>
+ <p>See section <seealso marker="sasl:error_logging">SASL User's
+ Guide</seealso> for more information about the old SASL
+ error logging functionality.</p>
+ </item>
+ <tag><marker id="legacy_event_handlers"/>Legacy Event Handlers</tag>
+ <item>
+ <p>To use event handlers written for <c>error_logger</c>, just
+ add your event handler with</p>
+ <code>
+error_logger:add_report_handler/1,2.
+ </code>
+ <p>This automatically starts the error logger event manager,
+ and adds <c>error_logger</c> as a handler to Logger, with
+ the following configuration:</p>
+<code>
+#{level => info,
+ filter_default => log,
+ filters => []}.
+</code>
+ <note>
+ <p>This handler ignores events that do not originate from
+ the <c>error_logger</c> API, or from within OTP. This
+ means that if your code uses the Logger API for logging,
+ then your log events will be discarded by this
+ handler.</p>
+ <p>The handler is not overload protected.</p>
+ </note>
+ </item>
+ </taglist>
+ </section>
+
+
+ <section>
+ <title>Error Handling</title>
+ <p>Logger does, to a certain extent, check its input data before
+ forwarding a log event to filters and handlers. It does,
+ however, not evaluate report callbacks, or check the validity of
+ format strings and arguments. This means that all filters and
+ handlers must be careful when formatting the data of a log
+ event, making sure that it does not crash due to bad input data
+ or faulty callbacks.</p>
+ <p>If a filter or handler still crashes, Logger will remove the
+ filter or handler in question from the configuration, and print
+ a short error message to the terminal. A debug event containing
+ the crash reason and other details is also issued.</p>
+ <p>See section <seealso marker="#log_message">Log
+ Message</seealso> for more information about report callbacks
+ and valid forms of log messages.</p>
+ </section>
+
+ <section>
+ <title>Example: Add a handler to log info events to file</title>
+ <p>When starting an Erlang node, the default behaviour is that all
+ log events on level <c>notice</c> or more severe, are logged to
+ the terminal via the default handler. To also log info events,
+ you can either change the primary log level to <c>info</c>:</p>
+ <pre>
+1> <input>logger:set_primary_config(level, info).</input>
+ok</pre>
+ <p>or set the level for one or a few modules only:</p>
+ <pre>
+2> <input>logger:set_module_level(mymodule, info).</input>
+ok</pre>
+ <p>This allows info events to pass through to the default handler,
+ and be printed to the terminal as well. If there are many info
+ events, it can be useful to print these to a file instead.</p>
+ <p>First, set the log level of the default handler
+ to <c>notice</c>, preventing it from printing info events to the
+ terminal:</p>
+ <pre>
+3> <input>logger:set_handler_config(default, level, notice).</input>
+ok</pre>
+ <p>Then, add a new handler which prints to file. You can use the
+ handler
+ module <seealso marker="logger_std_h"><c>logger_std_h</c></seealso>,
+ and configure it to log to file:</p>
+ <pre>
+4> <input>Config = #{config => #{file => "./info.log"}, level => info}.</input>
+#{config => #{file => "./info.log"},level => info}
+5> <input>logger:add_handler(myhandler, logger_std_h, Config).</input>
+ok</pre>
+ <p>Since <c>filter_default</c> defaults to <c>log</c>, this
+ handler now receives all log events. If you want info events
+ only in the file, you must add a filter to stop all non-info
+ events. The built-in
+ filter <seealso marker="logger_filters#level-2">
+ <c>logger_filters:level/2</c></seealso>
+ can do this:</p>
+ <pre>
+6> <input>logger:add_handler_filter(myhandler, stop_non_info,
+ {fun logger_filters:level/2, {stop, neq, info}}).</input>
+ok</pre>
+ <p>See section <seealso marker="#filters">Filters</seealso> for
+ more information about the filters and the <c>filter_default</c>
+ configuration parameter.</p>
+
+ </section>
+
+ <section>
+ <title>Example: Implement a handler</title>
+ <p>Section <seealso marker="logger#handler_callback_functions">Handler
+ Callback Functions</seealso> in the logger(3) manual page
+ describes the callback functions that can be implemented for a
+ Logger handler.</p>
+ <p>A handler callback module must export:</p>
+ <list>
+ <item><c>log(Log, Config)</c></item>
+ </list>
+ <p>It can optionally also export some, or all, of the following:</p>
+ <list>
+ <item><c>adding_handler(Config)</c></item>
+ <item><c>removing_handler(Config)</c></item>
+ <item><c>changing_config(SetOrUpdate, OldConfig, NewConfig)</c></item>
+ <item><c>filter_config(Config)</c></item>
+ </list>
+ <p>When a handler is added, by for example a call
+ to <seealso marker="logger#add_handler-3">
+ <c>logger:add_handler(Id, HModule, Config)</c></seealso>,
+ Logger first calls <c>HModule:adding_handler(Config)</c>. If
+ this function returns <c>{ok,Config1}</c>, Logger
+ writes <c>Config1</c> to the configuration database, and
+ the <c>logger:add_handler/3</c> call returns. After this, the
+ handler is installed and must be ready to receive log events as
+ calls to <c>HModule:log/2</c>.</p>
+ <p>A handler can be removed by calling
+ <seealso marker="logger#remove_handler-1">
+ <c>logger:remove_handler(Id)</c></seealso>. Logger calls
+ <c>HModule:removing_handler(Config)</c>, and removes the
+ handler's configuration from the configuration database.</p>
+ <p>When <seealso marker="logger#set_handler_config-2">
+ <c>logger:set_handler_config/2,3</c></seealso>
+ or <seealso marker="logger#update_handler_config/2">
+ <c>logger:update_handler_config/2,3</c></seealso> is called,
+ Logger
+ calls <c>HModule:changing_config(SetOrUpdate, OldConfig, NewConfig)</c>. If
+ this function returns <c>{ok,NewConfig1}</c>, Logger
+ writes <c>NewConfig1</c> to the configuration database.</p>
+ <p>When <seealso marker="logger#get_config-0">
+ <c>logger:get_config/0</c></seealso> or
+ <seealso marker="logger#get_handler_config-0">
+ <c>logger:get_handler_config/0,1</c></seealso> is called,
+ Logger calls <c>HModule:filter_config(Config)</c>. This function
+ must return the handler configuration where internal data is
+ removed.</p>
+
+ <p>A simple handler that prints to the terminal can be implemented
+ as follows:</p>
+ <code>
+-module(myhandler1).
+-export([log/2]).
+
+log(LogEvent, #{formatter := {FModule, FConfig}}) ->
+ io:put_chars(FModule:format(LogEvent, FConfig)).
+ </code>
+
+ <p>Notice that the above handler does not have any overload
+ protection, and all log events are printed directly from the
+ client process.</p>
+ <p>For information and examples of overload protection, please
+ refer to
+ section <seealso marker="#overload_protection">Protecting the
+ Handler from Overload</seealso>, and the implementation
+ of <seealso marker="logger_std_h"><c>logger_std_h</c></seealso>
+ and <seealso marker="logger_disk_log_h"><c>logger_disk_log_h</c>
+ </seealso>.</p>
+ <p>The following is a simpler example of a handler which logs to a
+ file through one single process:</p>
+ <code>
+-module(myhandler2).
+-export([adding_handler/1, removing_handler/1, log/2]).
+-export([init/1, handle_call/3, handle_cast/2, terminate/2]).
+
+adding_handler(Config) ->
+ MyConfig = maps:get(config,Config,#{file => "myhandler2.log"}),
+ {ok, Pid} = gen_server:start(?MODULE, MyConfig, []),
+ {ok, Config#{config => MyConfig#{pid => Pid}}}.
+
+removing_handler(#{config := #{pid := Pid}}) ->
+ gen_server:stop(Pid).
+
+log(LogEvent,#{config := #{pid := Pid}} = Config) ->
+ gen_server:cast(Pid, {log, LogEvent, Config}).
+
+init(#{file := File}) ->
+ {ok, Fd} = file:open(File, [append, {encoding, utf8}]),
+ {ok, #{file => File, fd => Fd}}.
+
+handle_call(_, _, State) ->
+ {reply, {error, bad_request}, State}.
+
+handle_cast({log, LogEvent, Config}, #{fd := Fd} = State) ->
+ do_log(Fd, LogEvent, Config),
+ {noreply, State}.
+
+terminate(_Reason, #{fd := Fd}) ->
+ _ = file:close(Fd),
+ ok.
+
+do_log(Fd, LogEvent, #{formatter := {FModule, FConfig}}) ->
+ String = FModule:format(LogEvent, FConfig),
+ io:put_chars(Fd, String).
+ </code>
+ </section>
+
+ <section>
+ <marker id="overload_protection"/>
+ <title>Protecting the Handler from Overload</title>
+ <p>The default handlers, <seealso marker="logger_std_h">
+ <c>logger_std_h</c></seealso> and <seealso marker="logger_disk_log_h">
+ <c>logger_disk_log_h</c></seealso>, feature an overload protection
+ mechanism, which makes it possible for the handlers to survive,
+ and stay responsive, during periods of high load (when huge
+ numbers of incoming log requests must be handled).
+ The mechanism works as follows:</p>
+
+ <section>
+ <title>Message Queue Length</title>
+ <p>The handler process keeps track of the length of its message
+ queue and takes some form of action when the current length exceeds a
+ configurable threshold. The purpose is to keep the handler in, or to
+ as quickly as possible get the handler into, a state where it can
+ keep up with the pace of incoming log events. The memory use of the
+ handler must never grow larger and larger, since that will eventually
+ cause the handler to crash. These three thresholds, with associated
+ actions, exist:</p>
+
+ <taglist>
+ <tag><c>sync_mode_qlen</c></tag>
+ <item>
+ <p>As long as the length of the message queue is lower than this
+ value, all log events are handled asynchronously. This means that
+ the client process sending the log event, by calling a log function
+ in the <seealso marker="logger_chapter#logger_api">Logger API</seealso>,
+ does not wait for a response from the handler but continues
+ executing immediately after the event is sent. It is not affected
+ by the time it takes the handler to print the event to the log
+ device. If the message queue grows larger than this value,
+ the handler starts handling log events synchronously instead,
+ meaning that the client process sending the event must wait for a
+ response. When the handler reduces the message queue to a
+ level below the <c>sync_mode_qlen</c> threshold, asynchronous
+ operation is resumed. The switch from asynchronous to synchronous
+ mode can slow down the logging tempo of one, or a few, busy senders,
+ but cannot protect the handler sufficiently in a situation of many
+ busy concurrent senders.</p>
+ <p>Defaults to <c>10</c> messages.</p>
+ </item>
+ <tag><c>drop_mode_qlen</c></tag>
+ <item>
+ <p>When the message queue grows larger than this threshold, the
+ handler switches to a mode in which it drops all new events that
+ senders want to log. Dropping an event in this mode means that the
+ call to the log function never results in a message being sent to
+ the handler, but the function returns without taking any action.
+ The handler keeps logging the events that are already in its message
+ queue, and when the length of the message queue is reduced to a level
+ below the threshold, synchronous or asynchronous mode is resumed.
+ Notice that when the handler activates or deactivates drop mode,
+ information about it is printed in the log.</p>
+ <p>Defaults to <c>200</c> messages.</p>
+ </item>
+ <tag><c>flush_qlen</c></tag>
+ <item>
+ <p>If the length of the message queue grows larger than this threshold,
+ a flush (delete) operation takes place. To flush events, the handler
+ discards the messages in the message queue by receiving them in a
+ loop without logging. Client processes waiting for a response from a
+ synchronous log request receive a reply from the handler indicating
+ that the request is dropped. The handler process increases its
+ priority during the flush loop to make sure that no new events
+ are received during the operation. Notice that after the flush operation
+ is performed, the handler prints information in the log about how many
+ events have been deleted.</p>
+ <p>Defaults to <c>1000</c> messages.</p>
+ </item>
+ </taglist>
+
+ <p>For the overload protection algorithm to work properly, it is
+ required that:</p>
+
+ <p><c>sync_mode_qlen =&lt; drop_mode_qlen =&lt; flush_qlen</c></p>
+
+ <p>and that:</p>
+
+ <p><c>drop_mode_qlen &gt; 1</c></p>
+
+ <p>To disable certain modes, do the following:</p>
+ <list>
+ <item>If <c>sync_mode_qlen</c> is set to <c>0</c>, all log events are handled
+ synchronously. That is, asynchronous logging is disabled.</item>
+ <item>If <c>sync_mode_qlen</c> is set to the same value as
+ <c>drop_mode_qlen</c>, synchronous mode is disabled. That is, the handler
+ always runs in asynchronous mode, unless dropping or flushing is invoked.</item>
+ <item>If <c>drop_mode_qlen</c> is set to the same value as <c>flush_qlen</c>,
+ drop mode is disabled and can never occur.</item>
+ </list>
+
+ <p>During high load scenarios, the length of the handler message queue
+ rarely grows in a linear and predictable way. Instead, whenever the
+ handler process is scheduled in, it can have an almost arbitrary number
+ of messages waiting in the message queue. It is for this reason that the overload
+ protection mechanism is focused on acting quickly, and quite drastically,
+ such as immediately dropping or flushing messages, when a large queue length
+ is detected.</p>
+
+ <p>The values of the previously listed thresholds can be specified by the user.
+ This way, a handler can be configured to, for example, not drop or flush
+ messages unless the message queue length of the handler process grows extremely
+ large. Notice that large amounts of memory can be required for the node under such
+ circumstances. Another example of user configuration is when, for performance
+ reasons, the client processes must never be blocked by synchronous log requests.
+ It is possible, perhaps, that dropping or flushing events is still acceptable, since
+ it does not affect the performance of the client processes sending the log events.</p>
+
+ <p>A configuration example:</p>
+ <code type="none">
+logger:add_handler(my_standard_h, logger_std_h,
+ #{config => #{file => "./system_info.log",
+ sync_mode_qlen => 100,
+ drop_mode_qlen => 1000,
+ flush_qlen => 2000}}).
+ </code>
+ </section>
+
+ <section>
+ <title>Controlling Bursts of Log Requests</title>
+ <p>Large bursts of log events - many events received by the handler
+ under a short period of time - can potentially cause problems, such as:</p>
+ <list>
+ <item>Log files grow very large, very quickly.</item>
+ <item>Circular logs wrap too quickly so that important data is overwritten.</item>
+ <item>Write buffers grow large, which slows down file sync operations.</item>
+ </list>
+
+ <p>For this reason, both built-in handlers offer the possibility to specify the
+ maximum number of events to be handled within a certain time frame.
+ With this burst control feature enabled, the handler can avoid choking the log with
+ massive amounts of printouts. The configuration parameters are:</p>
+ <taglist>
+ <tag><c>burst_limit_enable</c></tag>
+ <item>
+ <p>Value <c>true</c> enables burst control and <c>false</c> disables it.</p>
+ <p>Defaults to <c>true</c>.</p>
+ </item>
+ <tag><c>burst_limit_max_count</c></tag>
+ <item>
+ <p>This is the maximum number of events to handle within a
+ <c>burst_limit_window_time</c> time frame. After the limit is
+ reached, successive events are dropped until the end of the time frame.</p>
+ <p>Defaults to <c>500</c> events.</p>
+ </item>
+ <tag><c>burst_limit_window_time</c></tag>
+ <item>
+ <p>See the previous description of <c>burst_limit_max_count</c>.</p>
+ <p>Defaults to <c>1000</c> milliseconds.</p>
+ </item>
+ </taglist>
+
+ <p>A configuration example:</p>
+ <code type="none">
+logger:add_handler(my_disk_log_h, logger_disk_log_h,
+ #{config => #{file => "./my_disk_log",
+ burst_limit_enable => true,
+ burst_limit_max_count => 20,
+ burst_limit_window_time => 500}}).
+ </code>
+ </section>
+
+ <section>
+ <title>Terminating an Overloaded Handler</title>
+ <p>It is possible that a handler, even if it can successfully manage peaks
+ of high load without crashing, can build up a large message queue, or use a
+ large amount of memory. The overload protection mechanism includes an
+ automatic termination and restart feature for the purpose of guaranteeing
+ that a handler does not grow out of bounds. The feature is configured
+ with the following parameters:</p>
+ <taglist>
+ <tag><c>overload_kill_enable</c></tag>
+ <item>
+ <p>Value <c>true</c> enables the feature and <c>false</c> disables it.</p>
+ <p>Defaults to <c>false</c>.</p>
+ </item>
+ <tag><c>overload_kill_qlen</c></tag>
+ <item>
+ <p>This is the maximum allowed queue length. If the message queue grows
+ larger than this, the handler process is terminated.</p>
+ <p>Defaults to <c>20000</c> messages.</p>
+ </item>
+ <tag><c>overload_kill_mem_size</c></tag>
+ <item>
+ <p>This is the maximum memory size that the handler process is allowed to use.
+ If the handler grows larger than this, the process is terminated.</p>
+ <p>Defaults to <c>3000000</c> bytes.</p>
+ </item>
+ <tag><c>overload_kill_restart_after</c></tag>
+ <item>
+ <p>If the handler is terminated, it restarts automatically after a
+ delay specified in milliseconds. The value <c>infinity</c> prevents
+ restarts.</p>
+ <p>Defaults to <c>5000</c> milliseconds.</p>
+ </item>
+ </taglist>
+ <p>If the handler process is terminated because of overload, it prints
+ information about it in the log. It also prints information about when a
+ restart has taken place, and the handler is back in action.</p>
+ <note>
+ <p>The sizes of the log events affect the memory needs of the handler.
+ For information about how to limit the size of log events, see the
+ <seealso marker="logger_formatter"><c>logger_formatter(3)</c></seealso>
+ manual page.</p>
+ </note>
+ </section>
+ </section>
+
+ <section>
+ <marker id="proxy"/>
+ <title>Logger Proxy</title>
+ <p>The Logger proxy is an Erlang process which is part of the
+ Kernel application's supervision tree. During startup, the proxy
+ process registers itself as the <c>system_logger</c>, meaning
+ that log events produced by the emulator are sent to this
+ process.</p>
+ <p>When a log event is issued on a process which has its group
+ leader on a remote node, Logger automatically forwards the log
+ event to the group leader's node. To achieve this, it first
+ sends the log event as an Erlang message from the original
+ client process to the proxy on the local node, and the proxy in
+ turn forwards the event to the proxy on the remote node.</p>
+ <p>When receiving a log event, either from the emulator or from a
+ remote node, the proxy calls the Logger API to log the event.</p>
+ <p>The proxy process is overload protected in the same way as
+ described in
+ section <seealso marker="#overload_protection">Protecting the
+ Handler from Overload</seealso>, but with the following default
+ values:</p>
+ <code>
+ #{sync_mode_qlen => 500,
+ drop_mode_qlen => 1000,
+ flush_qlen => 5000,
+ burst_limit_enable => false,
+ overload_kill_enable => false}</code>
+ <p>For log events from the emulator, synchronous message passing
+ mode is not applicable, since all messages are passed
+ asynchronously by the emulator. Drop mode is achieved by setting
+ the <c>system_logger</c> to <c>undefined</c>, forcing the
+ emulator to drop events until it is set back to the proxy pid
+ again.</p>
+ <p>The proxy uses <seealso marker="erts:erlang#send_nosuspend/2">
+ <c>erlang:send_nosuspend/2</c></seealso> when sending log
+ events to a remote node. If the message could not be sent
+ without suspending the sender, it is dropped. This is to avoid
+ blocking the proxy process.</p>
+ </section>
+
+ <section>
+ <title>See Also</title>
+ <p>
+ <seealso marker="disk_log"><c>disk_log(3)</c></seealso>,
+ <seealso marker="erts:erlang"><c>erlang(3)</c></seealso>,
+ <seealso marker="error_logger"><c>error_logger(3)</c></seealso>,
+ <seealso marker="logger"><c>logger(3)</c></seealso>,
+ <seealso marker="logger_disk_log_h"><c>logger_disk_log_h(3)</c></seealso>,
+ <seealso marker="logger_filters"><c>logger_filters(3)</c></seealso>,
+ <seealso marker="logger_formatter"><c>logger_formatter(3)</c></seealso>,
+ <seealso marker="logger_std_h"><c>logger_std_h(3)</c></seealso>,
+ <seealso marker="sasl:sasl_app"><c>sasl(6)</c></seealso></p>
+ </section>
+</chapter>
diff --git a/lib/kernel/doc/src/logger_disk_log_h.xml b/lib/kernel/doc/src/logger_disk_log_h.xml
new file mode 100644
index 0000000000..aa577f3c62
--- /dev/null
+++ b/lib/kernel/doc/src/logger_disk_log_h.xml
@@ -0,0 +1,168 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2017</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>logger_disk_log_h</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev>A</rev>
+ <file>logger_disk_log_h.xml</file>
+ </header>
+ <module since="OTP 21.0">logger_disk_log_h</module>
+ <modulesummary>A disk_log based handler for Logger</modulesummary>
+
+ <description>
+ <p>This is a handler for Logger that offers circular
+ (wrapped) logs by using <seealso marker="disk_log"><c>disk_log</c></seealso>.
+ Multiple instances of this handler can be added to Logger, and each instance
+ prints to its own disk log file, created with the name and settings specified
+ in the handler configuration.</p>
+ <p>The default standard handler,
+ <seealso marker="logger_std_h"><c>logger_std_h</c></seealso>, can be
+ replaced by a disk_log handler at startup of the Kernel application.
+ See an example of this below.</p>
+ <p>The handler has an overload protection mechanism that keeps the handler
+ process and the Kernel application alive during high loads of log
+ events. How overload protection works, and how to configure it, is
+ described in the
+ <seealso marker="logger_chapter#overload_protection"><c>User's Guide</c>
+ </seealso>.</p>
+ <p>To add a new instance of the disk_log handler, use
+ <seealso marker="logger#add_handler-3"><c>logger:add_handler/3</c>
+ </seealso>. The handler configuration argument is a map which can contain
+ general configuration parameters, as documented in the
+ <seealso marker="logger_chapter#handler_configuration"><c>User's Guide</c>
+ </seealso>, and handler specific parameters. The specific data
+ is stored in a sub map with the key <c>config</c>, and can contain the
+ following parameters:</p>
+ <taglist>
+ <tag><c>file</c></tag>
+ <item>
+ <p>This is the full name of the disk log file. The option
+ corresponds to the <c>name</c> property in the
+ <seealso marker="disk_log#open-1"><c>dlog_option()</c></seealso>
+ datatype.</p>
+ <p>The value is set when the handler is added, and it cannot
+ be changed in runtime.</p>
+ <p>Defaults to the same name as the handler identity, in the
+ current directory.</p>
+ </item>
+ <tag><c>type</c></tag>
+ <item>
+ <p>This is the disk log type, <c>wrap</c> or <c>halt</c>. The option
+ corresponds to the <c>type</c> property in the
+ <seealso marker="disk_log#open-1"><c>dlog_option()</c></seealso>
+ datatype.</p>
+ <p>The value is set when the handler is added, and it cannot
+ be changed in runtime.</p>
+ <p>Defaults to <c>wrap</c>.</p>
+ </item>
+ <tag><c>max_no_files</c></tag>
+ <item>
+ <p>This is the maximum number of files that disk_log uses
+ for its circular logging. The option
+ corresponds to the <c>MaxNoFiles</c> element in the <c>size</c> property in the
+ <seealso marker="disk_log#open-1"><c>dlog_option()</c></seealso>
+ datatype.</p>
+ <p>The value is set when the handler is added, and it cannot
+ be changed in runtime.</p>
+ <p>Defaults to <c>10</c>.</p>
+ <p>The setting has no effect on a halt log.</p>
+ </item>
+ <tag><c>max_no_bytes</c></tag>
+ <item>
+ <p>This is the maximum number of bytes that is written to
+ a log file before disk_log proceeds with the next file in order, or
+ generates an error in case of a full halt log. The option
+ corresponds to the <c>MaxNoBytes</c> element in the <c>size</c> property in the
+ <seealso marker="disk_log#open-1"><c>dlog_option()</c></seealso>
+ datatype.</p>
+ <p>The value is set when the handler is added, and it cannot
+ be changed in runtime.</p>
+ <p>Defaults to <c>1048576</c> bytes for a wrap log, and
+ <c>infinity</c> for a halt log.</p>
+ </item>
+ <tag><c>filesync_repeat_interval</c></tag>
+ <item>
+ <p>This value, in milliseconds, specifies how often the handler does
+ a disk_log sync operation to write buffered data to disk. The handler attempts
+ the operation repeatedly, but only performs a new sync if something has
+ actually been logged.</p>
+ <p>Defaults to <c>5000</c> milliseconds.</p>
+ <p>If <c>no_repeat</c> is set as value, the repeated sync operation
+ is disabled. The user can also call the
+ <seealso marker="logger_disk_log_h#filesync-1"><c>filesync/1</c>
+ </seealso> function to perform a disk_log sync.</p>
+ </item>
+ </taglist>
+ <p>Other configuration parameters exist, to be used for customizing
+ the overload protection behaviour. The same parameters are used both in the
+ standard handler and the disk_log handler, and are documented in the
+ <seealso marker="logger_chapter#overload_protection"><c>User's Guide</c>
+ </seealso>.</p>
+ <p>Notice that when changing the configuration of the handler in runtime, the
+ disk_log options (<c>file</c>, <c>type</c>, <c>max_no_files</c>,
+ <c>max_no_bytes</c>) must not be modified.</p>
+ <p>Example of adding a disk_log handler:</p>
+ <code type="none">
+logger:add_handler(my_disk_log_h, logger_disk_log_h,
+ #{config => #{file => "./my_disk_log",
+ type => wrap,
+ max_no_files => 4,
+ max_no_bytes => 10000},
+ filesync_repeat_interval => 1000}}).
+ </code>
+ <p>To use the disk_log handler instead of the default standard
+ handler when starting an Erlang node, change the Kernel default logger to
+ use <c>logger_disk_log_h</c>. Example:</p>
+ <code type="none">
+erl -kernel logger '[{handler,default,logger_disk_log_h,
+ #{config => #{file => "./system_disk_log"}}}]'
+ </code>
+ </description>
+
+ <funcs>
+
+ <func>
+ <name name="filesync" arity="1" clause_i="1" since="OTP 21.0"/>
+ <fsummary>Writes buffered data to disk.</fsummary>
+ <desc>
+ <p>Write buffered data to disk.</p>
+ </desc>
+ </func>
+
+ </funcs>
+
+ <section>
+ <title>See Also</title>
+ <p><seealso marker="logger"><c>logger(3)</c></seealso>,
+ <seealso marker="logger_std_h"><c>logger_std_h(3)</c></seealso>,
+ <seealso marker="disk_log"><c>disk_log(3)</c></seealso></p>
+ </section>
+</erlref>
+
+
diff --git a/lib/kernel/doc/src/logger_filters.xml b/lib/kernel/doc/src/logger_filters.xml
new file mode 100644
index 0000000000..0a02342864
--- /dev/null
+++ b/lib/kernel/doc/src/logger_filters.xml
@@ -0,0 +1,254 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>logger_filters</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev>A</rev>
+ <file>logger_filters.xml</file>
+ </header>
+ <module since="OTP 21.0">logger_filters</module>
+ <modulesummary>Filters to use with Logger.</modulesummary>
+
+ <description>
+ <p>All functions exported from this module can be used as primary
+ or handler
+ filters. See <seealso marker="logger#add_primary_filter-2">
+ <c>logger:add_primary_filter/2</c></seealso>
+ and <seealso marker="logger#add_handler_filter-3">
+ <c>logger:add_handler_filter/3</c></seealso> for more information
+ about how filters are added.</p>
+ <p>Filters are removed with <seealso marker="logger#remove_primary_filter-1">
+ <c>logger:remove_primary_filter/1</c></seealso>
+ and <seealso marker="logger#remove_handler_filter-2">
+ <c>logger:remove_handler_filter/2</c></seealso>.</p>
+ </description>
+
+ <funcs>
+ <func>
+ <name name="domain" arity="2" since="OTP 21.0"/>
+ <fsummary>Filter log events based on the domain field in
+ metadata.</fsummary>
+ <desc>
+ <p>This filter provides a way of filtering log events based on a
+ <c>domain</c> field in <c>Metadata</c>. This field is
+ optional, and the purpose of using it is to group log events
+ from, for example, a specific functional area. This allows
+ filtering or other specialized treatment in a Logger
+ handler.</p>
+
+ <p>A domain field must be a list of atoms, creating smaller
+ and more specialized domains as the list grows longer. The
+ greatest domain is <c>[]</c>, which comprises all possible
+ domains.</p>
+
+ <p>For example, consider the following domains:</p>
+ <pre>
+D1 = [otp]
+D2 = [otp, sasl]</pre>
+
+ <p><c>D1</c> is the greatest of the two, and is said to be a
+ super-domain of <c>D2</c>. <c>D2</c> is a
+ sub-domain <c>D1</c>. Both <c>D1</c> and <c>D2</c> are
+ sub-domains of <c>[]</c>.</p>
+
+ <p>The above domains are used for logs originating from
+ Erlang/OTP. D1 specifies that the log event comes from
+ Erlang/OTP in general, and D2 indicates that the log event
+ is a so
+ called <seealso marker="logger_chapter#sasl_reports">SASL
+ report</seealso>.</p>
+
+ <p>The <c><anno>Extra</anno></c> parameter to
+ the <c>domain/2</c> function is specified when adding the
+ filter via <seealso marker="logger#add_primary_filter-2">
+ <c>logger:add_primary_filter/2</c></seealso>
+ or <seealso marker="logger#add_handler_filter-3">
+ <c>logger:add_handler_filter/3</c></seealso>.</p>
+
+ <p>The filter compares the value of the <c>domain</c> field in
+ the log event's metadata (<c>Domain</c>) against
+ <c><anno>MatchDomain</anno></c>. The filter matches if the
+ value of <c>Compare</c> is:</p>
+
+ <taglist>
+ <tag><c>sub</c></tag>
+ <item>
+ <p>and <c>Domain</c> is equal to or a sub-domain
+ of <c>MatchDomain</c>, that is, if <c>MatchDomain</c> is
+ a prefix of <c>Domain</c>.</p>
+ </item>
+ <tag><c>super</c></tag>
+ <item>
+ <p>and <c>Domain</c> is equal to or a super-domain
+ of <c>MatchDomain</c>, that is, if <c>Domain</c> is a
+ prefix of <c>MatchDomain</c>.</p>
+ </item>
+ <tag><c>equal</c></tag>
+ <item>
+ <p>and <c>Domain</c> is equal to <c>MatchDomain</c>.</p>
+ </item>
+ <tag><c>not_equal</c></tag>
+ <item>
+ <p>and <c>Domain</c> differs from <c>MatchDomain</c>, or
+ if there is no domain field in metadata.</p>
+ </item>
+ <tag><c>undefined</c></tag>
+ <item>
+ <p>and there is no domain field in metadata. In this
+ case <c><anno>MatchDomain</anno></c> must be set
+ to <c>[]</c>.</p>
+ </item>
+ </taglist>
+
+ <p>If the filter matches and <c><anno>Action</anno></c> is
+ <c>log</c>, the log event is allowed. If the filter matches
+ and <c><anno>Action</anno></c> is <c>stop</c>, the log event
+ is stopped.</p>
+
+ <p>If the filter does not match, it returns <c>ignore</c>,
+ meaning that other filters, or the value of the
+ configuration parameter <c>filter_default</c>, decide if the
+ event is allowed or not.</p>
+
+ <p>Log events that do not contain any domain field, match only
+ when <c><anno>Compare</anno></c> is equal
+ to <c>undefined</c> or <c>not_equal</c>.</p>
+
+ <p>Example: stop all events with domain <c>[otp,
+ sasl | _]</c></p>
+
+ <code>
+logger:set_handler_config(h1, filter_default, log). % this is the default
+Filter = {fun logger_filters:domain/2, {stop, sub, [otp, sasl]}}.
+logger:add_handler_filter(h1, no_sasl, Filter).
+ok</code>
+ </desc>
+ </func>
+
+ <func>
+ <name name="level" arity="2" since="OTP 21.0"/>
+ <fsummary>Filter log events based on the log level.</fsummary>
+ <desc>
+ <p>This filter provides a way of filtering log events based
+ on the log level. It matches log events by comparing the
+ log level with a specified <c>MatchLevel</c></p>
+
+ <p>The <c><anno>Extra</anno></c> parameter is specified when
+ adding the filter
+ via <seealso marker="logger#add_primary_filter-2">
+ <c>logger:add_primary_filter/2</c></seealso>
+ or <seealso marker="logger#add_handler_filter-3">
+ <c>logger:add_handler_filter/3</c></seealso>.</p>
+
+ <p>The filter compares the value of the event's log level
+ (<c>Level</c>) to <c><anno>MatchLevel</anno></c> by
+ calling <seealso marker="logger#compare_levels-2">
+ <c>logger:compare_levels(Level, MatchLevel)</c></seealso>.
+ The filter matches if the value
+ of <c><anno>Operator</anno></c> is:</p>
+
+ <taglist>
+ <tag><c>neq</c></tag>
+ <item><p>and the compare function returns <c>lt</c>
+ or <c>gt</c>.</p></item>
+ <tag><c>eq</c></tag>
+ <item><p>and the compare function returns <c>eq</c>.</p></item>
+ <tag><c>lt</c></tag>
+ <item><p>and the compare function returns <c>lt</c>.</p></item>
+ <tag><c>gt</c></tag>
+ <item><p>and the compare function returns <c>gt</c>.</p></item>
+ <tag><c>lteq</c></tag>
+ <item><p>and the compare function returns <c>lt</c>
+ or <c>eq</c>.</p></item>
+ <tag><c>gteq</c></tag>
+ <item><p>and the compare function returns <c>gt</c>
+ or <c>eq</c>.</p></item>
+ </taglist>
+
+ <p>If the filter matches and <c><anno>Action</anno></c> is
+ <c>log</c>, the log event is allowed. If the filter
+ matches and <c><anno>Action</anno></c> is <c>stop</c>, the
+ log event is stopped.</p>
+
+ <p>If the filter does not match, it returns <c>ignore</c>,
+ meaning that other filters, or the value of the
+ configuration parameter <c>filter_default</c>, will decide
+ if the event is allowed or not.</p>
+
+ <p>Example: only allow debug level log events</p>
+
+ <code>
+logger:set_handler_config(h1, filter_default, stop).
+Filter = {fun logger_filters:level/2, {log, eq, debug}}.
+logger:add_handler_filter(h1, debug_only, Filter).
+ok</code>
+ </desc>
+ </func>
+
+ <func>
+ <name name="progress" arity="2" since="OTP 21.0"/>
+ <fsummary>Filter progress reports from supervisor and application_controller.</fsummary>
+ <desc>
+ <p>This filter matches all progress reports
+ from <c>supervisor</c> and <c>application_controller</c>.</p>
+
+ <p>If <c><anno>Extra</anno></c> is <c>log</c>, the progress
+ reports are allowed. If <c><anno>Extra</anno></c>
+ is <c>stop</c>, the progress reports are stopped.</p>
+
+ <p>The filter returns <c>ignore</c> for all other log events.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="remote_gl" arity="2" since="OTP 21.0"/>
+ <fsummary>Filter events with group leader on remote node.</fsummary>
+ <desc>
+ <p>This filter matches all events originating from a process
+ that has its group leader on a remote node.</p>
+
+ <p>If <c><anno>Extra</anno></c> is <c>log</c>, the matching
+ events are allowed. If <c><anno>Extra</anno></c>
+ is <c>stop</c>, the matching events are stopped.</p>
+
+ <p>The filter returns <c>ignore</c> for all other log events.</p>
+ </desc>
+ </func>
+
+ </funcs>
+
+ <section>
+ <title>See Also</title>
+ <p>
+ <seealso marker="logger"><c>logger(3)</c></seealso>
+ </p>
+ </section>
+</erlref>
+
+
diff --git a/lib/kernel/doc/src/logger_formatter.xml b/lib/kernel/doc/src/logger_formatter.xml
new file mode 100644
index 0000000000..6dc83d24e1
--- /dev/null
+++ b/lib/kernel/doc/src/logger_formatter.xml
@@ -0,0 +1,354 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2017</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>logger_formatter</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev>A</rev>
+ <file>logger_formatter.xml</file>
+ </header>
+ <module since="OTP 21.0">logger_formatter</module>
+ <modulesummary>Default formatter for Logger.</modulesummary>
+
+ <description>
+ <p>Each Logger handler has a configured formatter specified as a
+ module and a configuration term. The purpose of the formatter is
+ to translate the log events to a final printable string
+ (<seealso marker="stdlib:unicode#type-chardata"><c>unicode:chardata()</c>
+ </seealso>) which can be written to the output device of the
+ handler. See
+ sections <seealso marker="logger_chapter#handlers">Handlers</seealso>
+ and <seealso marker="logger_chapter#formatters">Formatters</seealso>
+ in the Kernel User's Guide for more information.</p>
+ <p><c>logger_formatter</c> is the default formatter used by
+ Logger.</p>
+ </description>
+
+
+ <datatypes>
+ <datatype>
+ <name name="config"/>
+ <desc>
+ <p>The configuration term for <c>logger_formatter</c> is a
+ <seealso marker="stdlib:maps">map</seealso>, and the
+ following keys can be set as configuration parameters:</p>
+ <taglist>
+ <tag><marker id="chars_limit"/>
+ <c>chars_limit = integer() > 0 | unlimited</c></tag>
+ <item>
+ <p>A positive integer representing the value of the option
+ with the same name to be used when calling
+ <seealso marker="stdlib:io_lib#format-3">
+ <c>io_lib:format/3</c></seealso>.
+ This value limits the total number of characters printed
+ for each log event. Notice that this is a soft limit. For a
+ hard truncation limit, see option <c>max_size</c>.</p>
+ <p>Defaults to <c>unlimited</c>.</p>
+ </item>
+ <tag><marker id="depth"/><c>depth = integer() > 0 | unlimited</c></tag>
+ <item>
+ <p>A positive integer representing the maximum depth to
+ which terms shall be printed by this formatter. Format
+ strings passed to this formatter are rewritten. The
+ format controls ~p and ~w are replaced with ~P and ~W,
+ respectively, and the value is used as the depth
+ parameter. For details, see
+ <seealso marker="stdlib:io#format-2"><c>io:format/2,3</c></seealso>
+ in STDLIB.</p>
+ <p>Defaults to <c>unlimited</c>.</p>
+ </item>
+ <tag><c>legacy_header = boolean()</c></tag>
+ <item>
+ <p>If set to <c>true</c> a header field is added to
+ logger_formatter's part of <c>Metadata</c>. The value of
+ this field is a string similar to the header created by
+ the
+ old <seealso marker="error_logger"><c>error_logger</c></seealso>
+ event handlers. It can be included in the log event by
+ adding the list <c>[logger_formatter,header]</c> to the
+ template. See the description of
+ the <seealso marker="#type-template"><c>template()</c></seealso>
+ type for more information.</p>
+ <p>Defaults to <c>false</c>.</p>
+ </item>
+ <tag><marker id="max_size"/>
+ <c>max_size = integer() > 0 | unlimited</c></tag>
+ <item>
+ <p>A positive integer representing the absolute maximum size a
+ string returned from this formatter can have. If the
+ formatted string is longer, after possibly being limited
+ by <c>chars_limit</c> or <c>depth</c>, it is truncated.</p>
+ <p>Defaults to <c>unlimited</c>.</p>
+ </item>
+ <tag><c>report_cb = </c><seealso marker="logger#type-report_cb">
+ <c>logger:report_cb()</c></seealso></tag>
+ <item>
+ <p>A report callback is used by the formatter to transform
+ log messages on report form to a format string and
+ arguments. The report callback can be specified in the
+ metadata for the log event. If no report callback exists
+ in metadata, <c>logger_formatter</c> will
+ use <seealso marker="logger#format_report-1">
+ <c>logger:format_report/1</c></seealso> as default
+ callback.</p>
+ <p>If this configuration parameter is set, it replaces
+ both the default report callback, and any report
+ callback found in metadata. That is, all reports are
+ converted by this configured function.</p>
+ </item>
+ <tag><c>single_line = boolean()</c></tag>
+ <item>
+ <p>If set to <c>true</c>, each log event is printed as a
+ single line. To achieve this, <c>logger_formatter</c>
+ sets the field width to <c>0</c> for all <c>~p</c>
+ and <c>~P</c> control sequences in the format a string
+ (see <seealso marker="stdlib:io#format-2">
+ <c>io:format/2</c></seealso>), and replaces all
+ newlines in the message with <c>", "</c>. White spaces
+ following directly after newlines are removed. Notice
+ that newlines added by the <c>template</c> parameter are
+ not replaced.</p>
+ <p>Defaults to <c>true</c>.</p>
+ </item>
+ <tag><marker id="template"/>
+ <c>template = </c><seealso marker="#type-template"><c>template()</c>
+ </seealso></tag>
+ <item>
+ <p>The template describes how the formatted string is
+ composed by combining different data values from the log
+ event. See the description of
+ the <seealso marker="#type-template"><c>template()</c></seealso>
+ type for more information about this.</p>
+ </item>
+ <tag><c>time_designator = byte()</c></tag>
+ <item>
+ <p>Timestamps are formatted according to RFC3339, and the
+ time designator is the character used as date and time
+ separator.</p>
+ <p>Defaults to <c>$T</c>.</p>
+ <p>The value of this parameter is used as
+ the <c>time_designator</c> option
+ to <seealso marker="stdlib:calendar#system_time_to_rfc3339-2">
+ <c>calendar:system_time_to_rcf3339/2</c></seealso>.</p>
+ </item>
+ <tag><c>time_offset = integer() | [byte()]</c></tag>
+ <item>
+ <p>The time offset, either a string or an integer, to be
+ used when formatting the timestamp.</p>
+ <p>An empty string is interpreted as local time. The
+ values <c>"Z"</c>, <c>"z"</c> or <c>0</c> are
+ interpreted as Universal Coordinated Time (UTC).</p>
+ <p>Strings, other than <c>"Z"</c>, <c>"z"</c>,
+ or <c>""</c>, must be on the form <c>±[hh]:[mm]</c>, for
+ example <c>"-02:00"</c> or <c>"+00:00"</c>.</p>
+ <p>Integers must be in microseconds, meaning that the
+ offset <c>7200000000</c> is equivalent
+ to <c>"+02:00"</c>.</p>
+ <p>Defaults to an empty string, meaning that timestamps
+ are displayed in local time. However, for backwards
+ compatibility, if the SASL configuration
+ parameter <seealso marker="sasl:sasl_app#utc_log">
+ <c>utc_log</c></seealso><c>=true</c>, the default is
+ changed to <c>"Z"</c>, meaning that timestamps are displayed
+ in UTC.</p>
+ <p>The value of this parameter is used as
+ the <c>offset</c> option
+ to <seealso marker="stdlib:calendar#system_time_to_rfc3339-2">
+ <c>calendar:system_time_to_rcf3339/2</c></seealso>.</p>
+ </item>
+ </taglist>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="metakey"/>
+ <desc>
+ <p></p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="template"/>
+ <desc>
+ <p>The template is a list of atoms, atom lists, tuples and strings. The
+ atoms <c>level</c> or <c>msg</c>, are treated as
+ placeholders for the severity level and the log message,
+ respectively. Other atoms or atom lists are interpreted as
+ placeholders for metadata, where atoms are expected to match
+ top level keys, and atom lists represent paths to sub keys when
+ the metadata is a nested map. For example the
+ list <c>[key1,key2]</c> is replaced by the value of
+ the <c>key2</c> field in the nested map below. The
+ atom <c>key1</c> on its own is replaced by the complete
+ value of the <c>key1</c> field. The values are converted to
+ strings.</p>
+
+ <code>
+#{key1 => #{key2 => my_value,
+ ...}
+ ...}</code>
+
+ <p>Tuples in the template express if-exist tests for metadata
+ keys. For example, the following tuple says that
+ if <c>key1</c> exists in the metadata map,
+ print <c>"key1=Value"</c>, where <c>Value</c> is the value
+ that <c>key1</c> is associated with in the metadata map. If
+ <c>key1</c> does not exist, print nothing.</p>
+ <code>
+{key1, ["key1=",key1], []}</code>
+
+ <p>Strings in the template are printed literally.</p>
+ <p>The default value for the <c>template</c> configuration
+ parameter depends on the value of the <c>single_line</c>
+ and <c>legacy_header</c> configuration parameters as
+ follows.</p>
+
+ <p>The log event used in the examples is:</p>
+ <code>
+?LOG_ERROR("name: ~p~nexit_reason: ~p", [my_name, "It crashed"])</code>
+
+ <taglist>
+ <tag><c>legacy_header = true, single_line = false</c></tag>
+ <item>
+ <p>Default
+ template: <c>[[logger_formatter,header],"\n",msg,"\n"]</c></p>
+
+ <p>Example log entry:</p>
+ <code type="none">
+=ERROR REPORT==== 17-May-2018::18:30:19.453447 ===
+name: my_name
+exit_reason: "It crashed"</code>
+
+ <p>Notice that all eight levels can occur in the heading,
+ not only <c>ERROR</c>, <c>WARNING</c> or <c>INFO</c> as
+ <seealso marker="error_logger"><c>error_logger</c></seealso>
+ produces. And microseconds are added at the end of the
+ timestamp.</p>
+ </item>
+
+ <tag><c>legacy_header = true, single_line = true</c></tag>
+ <item>
+ <p>Default
+ template: <c>[[logger_formatter,header],"\n",msg,"\n"]</c></p>
+
+ <p>Notice that the template is here the same as
+ for <c>single_line=false</c>, but the resulting log entry
+ differs in that there is only one line after the
+ heading:</p>
+ <code type="none">
+=ERROR REPORT==== 17-May-2018::18:31:06.952665 ===
+name: my_name, exit_reason: "It crashed"</code>
+ </item>
+
+ <tag><c>legacy_header = false, single_line = true</c></tag>
+ <item>
+ <p>Default template: <c>[time," ",level,": ",msg,"\n"]</c></p>
+
+ <p>Example log entry:</p>
+ <code type="none">
+2018-05-17T18:31:31.152864+02:00 error: name: my_name, exit_reason: "It crashed"</code>
+ </item>
+
+ <tag><c>legacy_header = false, single_line = false</c></tag>
+ <item>
+ <p>Default template: <c>[time," ",level,":\n",msg,"\n"]</c></p>
+
+ <p>Example log entry:</p>
+ <code type="none">
+2018-05-17T18:32:20.105422+02:00 error:
+name: my_name
+exit_reason: "It crashed"</code>
+ </item>
+ </taglist>
+ </desc>
+ </datatype>
+ </datatypes>
+
+ <funcs>
+ <func>
+ <name name="check_config" arity="1" since="OTP 21.0"/>
+ <fsummary>Validates the given formatter configuration.</fsummary>
+ <desc>
+ <p>The function is called by Logger when the formatter
+ configuration for a handler is set or modified. It
+ returns <c>ok</c> if the configuration is valid,
+ and <c>{error,term()}</c> if it is faulty.</p>
+ <p>The following Logger API functions can trigger this callback:</p>
+ <list>
+ <item><seealso marker="logger#add_handler-3">
+ <c>logger:add_handler/3</c></seealso></item>
+ <item><seealso marker="logger#set_handler_config-2">
+ <c>logger:set_handler_config/2,3</c></seealso></item>
+ <item><seealso marker="logger#update_handler_config-2">
+ <c>logger:update_handler_config/2</c></seealso></item>
+ <item><seealso marker="logger#update_formatter_config-2">
+ <c>logger:update_formatter_config/2</c></seealso></item>
+ </list>
+ </desc>
+ </func>
+ <func>
+ <name name="format" arity="2" since="OTP 21.0"/>
+ <fsummary>Formats the given message.</fsummary>
+ <desc>
+ <p>This the formatter callback function to be called from
+ handlers. The log event is processed as follows:</p>
+ <list>
+ <item>If the message is on report form, it is converted to
+ <c>{Format,Args}</c> by calling the report callback. See
+ section <seealso marker="logger_chapter#log_message">Log
+ Message</seealso> in the Kernel User's Guide for more
+ information about report callbacks and valid forms of log
+ messages.</item>
+ <item>The message size is limited according to the values of
+ configuration parameters <seealso marker="#chars_limit">
+ <c>chars_limit</c></seealso>
+ and <seealso marker="#depth"><c>depth</c></seealso>.</item>
+ <item>The full log entry is composed according to
+ the <seealso marker="#template"><c>template</c></seealso>.</item>
+ <item>If the final string is too long, it is truncated
+ according to the value of configuration
+ parameter <seealso marker="#max_size"><c>max_size</c></seealso>.</item>
+ </list>
+ </desc>
+ </func>
+ </funcs>
+
+ <section>
+ <title>See Also</title>
+ <p>
+ <seealso marker="stdlib:calendar"><c>calendar(3)</c></seealso>,
+ <seealso marker="error_logger"><c>error_logger(3)</c></seealso>,
+ <seealso marker="stdlib:io"><c>io(3)</c></seealso>,
+ <seealso marker="stdlib:io_lib"><c>io_lib(3)</c></seealso>,
+ <seealso marker="logger"><c>logger(3)</c></seealso>,
+ <seealso marker="stdlib:maps"><c>maps(3)</c></seealso>,
+ <seealso marker="sasl:sasl_app"><c>sasl(6)</c></seealso>,
+ <seealso marker="stdlib:unicode"><c>unicode(3)</c></seealso>
+ </p>
+ </section>
+</erlref>
+
+
diff --git a/lib/kernel/doc/src/logger_std_h.xml b/lib/kernel/doc/src/logger_std_h.xml
new file mode 100644
index 0000000000..5ac4f58d12
--- /dev/null
+++ b/lib/kernel/doc/src/logger_std_h.xml
@@ -0,0 +1,217 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2017</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>logger_std_h</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev>A</rev>
+ <file>logger_std_h.xml</file>
+ </header>
+ <module since="OTP 21.0">logger_std_h</module>
+ <modulesummary>Standard handler for Logger.</modulesummary>
+
+ <description>
+ <p>This is the standard handler for Logger.
+ Multiple instances of this handler can be added to
+ Logger, and each instance prints logs to <c>standard_io</c>,
+ <c>standard_error</c>, or to file.</p>
+ <p>The handler has an overload protection mechanism that keeps the handler
+ process and the Kernel application alive during high loads of log
+ events. How overload protection works, and how to configure it, is
+ described in the
+ <seealso marker="logger_chapter#overload_protection"><c>User's Guide</c>
+ </seealso>.</p>
+ <p>To add a new instance of the standard handler, use
+ <seealso marker="logger#add_handler-3"><c>logger:add_handler/3</c>
+ </seealso>. The handler configuration argument is a map which can contain
+ general configuration parameters, as documented in the
+ <seealso marker="logger_chapter#handler_configuration"><c>User's Guide</c>
+ </seealso>, and handler specific parameters. The specific data
+ is stored in a sub map with the key <c>config</c>, and can contain the
+ following parameters:</p>
+ <taglist>
+ <tag><marker id="type"/><c>type = standard_io | standard_error | file</c></tag>
+ <item>
+ <p>Specifies the log destination.</p>
+ <p>The value is set when the handler is added, and it cannot
+ be changed in runtime.</p>
+ <p>Defaults to <c>standard_io</c>, unless
+ parameter <seealso marker="#file"><c>file</c></seealso> is
+ given, in which case it defaults to <c>file</c>.</p>
+ </item>
+ <tag><marker id="file"/><c>file = </c><seealso marker="file#type-filename"><c>file:filename()</c></seealso></tag>
+ <item>
+ <p>This specifies the name of the log file when the handler is
+ of type <c>file</c>.</p>
+ <p>The value is set when the handler is added, and it cannot
+ be changed in runtime.</p>
+ <p>Defaults to the same name as the handler identity, in the
+ current directory.</p>
+ </item>
+ <tag><marker id="modes"/><c>modes = [</c><seealso marker="file#type-mode"><c>file:mode()</c></seealso><c>]</c></tag>
+ <item>
+ <p>This specifies the file modes to use when opening the log
+ file,
+ see <seealso marker="file#open-2"><c>file:open/2</c></seealso>.
+ If <c>modes</c> are not specified, the default list used
+ is <c>[raw,append,delayed_write]</c>. If <c>modes</c> are
+ specified, the list replaces the default modes list with the
+ following adjustments:</p>
+ <list>
+ <item>
+ If <c>raw</c> is not found in the list, it is added.
+ </item>
+ <item>
+ If none of <c>write</c>, <c>append</c> or <c>exclusive</c> is
+ found in the list, <c>append</c> is added.</item>
+ <item>If none of <c>delayed_write</c>
+ or <c>{delayed_write,Size,Delay}</c> is found in the
+ list, <c>delayed_write</c> is added.</item>
+ </list>
+ <p>Log files are always UTF-8 encoded. The encoding cannot be
+ changed by setting the mode <c>{encoding,Encoding}</c>.</p>
+ <p>The value is set when the handler is added, and it cannot
+ be changed in runtime.</p>
+ <p>Defaults to <c>[raw,append,delayed_write]</c>.</p>
+ </item>
+ <tag><marker id="max_no_bytes"/><c>max_no_bytes = pos_integer() | infinity</c></tag>
+ <item>
+ <p>This parameter specifies if the log file should be rotated
+ or not. The value <c>infinity</c> means the log file will
+ grow indefinitely, while an integer value specifies at which
+ file size (bytes) the file is rotated.</p>
+ <p>Defaults to <c>infinity</c>.</p>
+ </item>
+ <tag><marker id="max_no_files"/><c>max_no_files = non_neg_integer()</c></tag>
+ <item>
+ <p>This parameter specifies the number of rotated log file
+ archives to keep. This has meaning only
+ if <seealso marker="#max_no_bytes"><c>max_no_bytes</c></seealso>
+ is set to an integer value.</p>
+ <p>The log archives are
+ named <c>FileName.0</c>, <c>FileName.1</c>,
+ ... <c>FileName.N</c>, where <c>FileName</c> is the name of
+ the current log file. <c>FileName.0</c> is the newest of the
+ archives. The maximum value for <c>N</c> is the value
+ of <c>max_no_files</c> minus 1.</p>
+ <p>Notice that setting this value to <c>0</c> does not turn of
+ rotation. It only specifies that no archives are kept.</p>
+ <p>Defaults to <c>0</c>.</p>
+ </item>
+ <tag><marker id="compress_on_rotate"/><c>compress_on_rotate = boolean()</c></tag>
+ <item>
+ <p>This parameter specifies if the rotated log file archives
+ shall be compressed or not. If set to <c>true</c>, all
+ archives are compressed with <c>gzip</c>, and renamed
+ to <c>FileName.N.gz</c></p>
+ <p><c>compress_on_rotate</c> has no meaning if <seealso
+ marker="#max_no_bytes"><c>max_no_bytes</c></seealso> has the
+ value <c>infinity</c>.</p>
+ <p>Defaults to <c>false</c>.</p>
+ </item>
+ <tag><marker id="file_check"/><c>file_check = non_neg_integer()</c></tag>
+ <item>
+ <p>When <c>logger_std_h</c> logs to a file, it reads the file
+ information of the log file prior to each write
+ operation. This is to make sure the file still exists and
+ has the same inode as when it was opened. This implies some
+ performance loss, but ensures that no log events are lost in
+ the case when the file has been removed or renamed by an
+ external actor.</p>
+ <p>In order to allow minimizing the performance loss, the
+ <c>file_check</c> parameter can be set to a positive integer
+ value, <c>N</c>. The handler will then skip reading the file
+ information prior to writing, as long as no more
+ than <c>N</c> milliseconds have passed since it was last
+ read.</p>
+ <p>Notice that the risk of loosing log events grows when
+ the <c>file_check</c> value grows.</p>
+ <p>Defaults to 0.</p>
+ </item>
+ <tag><c>filesync_repeat_interval = pos_integer() | no_repeat</c></tag>
+ <item>
+ <p>This value, in milliseconds, specifies how often the handler does
+ a file sync operation to write buffered data to disk. The handler attempts
+ the operation repeatedly, but only performs a new sync if something has
+ actually been logged.</p>
+ <p>If <c>no_repeat</c> is set as value, the repeated file sync operation
+ is disabled, and it is the operating system settings that determine
+ how quickly or slowly data is written to disk. The user can also call
+ the <seealso marker="logger_std_h#filesync-1"><c>filesync/1</c></seealso>
+ function to perform a file sync.</p>
+ <p>Defaults to <c>5000</c> milliseconds.</p>
+ </item>
+ </taglist>
+ <p>Other configuration parameters exist, to be used for customizing
+ the overload protection behaviour. The same parameters are used both in the
+ standard handler and the disk_log handler, and are documented in the
+ <seealso marker="logger_chapter#overload_protection"><c>User's Guide</c>
+ </seealso>.</p>
+ <p>Notice that if changing the configuration of the handler in
+ runtime, the <c>type</c>, <c>file</c>, or <c>modes</c> parameters
+ must not be modified.</p>
+ <p>Example of adding a standard handler:</p>
+ <code type="none">
+logger:add_handler(my_standard_h, logger_std_h,
+ #{config => #{file => "./system_info.log",
+ filesync_repeat_interval => 1000}}).
+ </code>
+ <p>To set the default handler, that starts initially with
+ the Kernel application, to log to file instead of <c>standard_io</c>,
+ change the Kernel default logger configuration. Example:</p>
+ <code type="none">
+erl -kernel logger '[{handler,default,logger_std_h,
+ #{config => #{file => "./log.log"}}}]'
+ </code>
+ <p>An example of how to replace the standard handler with a disk_log handler
+ at startup is found in the
+ <seealso marker="logger_disk_log_h"><c>logger_disk_log_h</c></seealso>
+ manual.</p>
+ </description>
+
+ <funcs>
+
+ <func>
+ <name name="filesync" arity="1" clause_i="1" since="OTP 21.0"/>
+ <fsummary>Writes buffered data to disk.</fsummary>
+ <desc>
+ <p>Write buffered data to disk.</p>
+ </desc>
+ </func>
+
+ </funcs>
+
+ <section>
+ <title>See Also</title>
+ <p><seealso marker="logger"><c>logger(3)</c></seealso>,
+ <seealso marker="logger_disk_log_h">
+ <c>logger_disk_log_h(3)</c></seealso></p>
+ </section>
+</erlref>
+
+
diff --git a/lib/kernel/doc/src/net_adm.xml b/lib/kernel/doc/src/net_adm.xml
index 6957a3b5e4..c3e1619f1b 100644
--- a/lib/kernel/doc/src/net_adm.xml
+++ b/lib/kernel/doc/src/net_adm.xml
@@ -28,7 +28,7 @@
<date>1996-09-10</date>
<rev>A</rev>
</header>
- <module>net_adm</module>
+ <module since="">net_adm</module>
<modulesummary>Various Erlang net administration routines.</modulesummary>
<description>
<p>This module contains various network utility functions.</p>
@@ -36,7 +36,7 @@
<funcs>
<func>
- <name name="dns_hostname" arity="1"/>
+ <name name="dns_hostname" arity="1" since=""/>
<fsummary>Official name of a host.</fsummary>
<desc>
<p>Returns the official name of <c><anno>Host</anno></c>, or
@@ -46,7 +46,7 @@
</func>
<func>
- <name name="host_file" arity="0"/>
+ <name name="host_file" arity="0" since=""/>
<fsummary>Read file <c>.hosts.erlang</c>.</fsummary>
<desc>
<p>Reads file <c>.hosts.erlang</c>, see section
@@ -58,7 +58,7 @@
</func>
<func>
- <name name="localhost" arity="0"/>
+ <name name="localhost" arity="0" since=""/>
<fsummary>Name of the local host.</fsummary>
<desc>
<p>Returns the name of the local host. If Erlang was started
@@ -68,8 +68,8 @@
</func>
<func>
- <name name="names" arity="0"/>
- <name name="names" arity="1"/>
+ <name name="names" arity="0" since=""/>
+ <name name="names" arity="1" since=""/>
<fsummary>Names of Erlang nodes at a host.</fsummary>
<desc>
<p>Similar to <c>epmd -names</c>, see
@@ -86,7 +86,7 @@
</func>
<func>
- <name name="ping" arity="1"/>
+ <name name="ping" arity="1" since=""/>
<fsummary>Set up a connection to a node.</fsummary>
<desc>
<p>Sets up a connection to <c><anno>Node</anno></c>. Returns
@@ -95,8 +95,8 @@
</func>
<func>
- <name name="world" arity="0"/>
- <name name="world" arity="1"/>
+ <name name="world" arity="0" since=""/>
+ <name name="world" arity="1" since=""/>
<fsummary>Lookup and connect to all nodes at all hosts in
<c>.hosts.erlang</c>.</fsummary>
<type name="verbosity"/>
@@ -117,8 +117,8 @@
</func>
<func>
- <name name="world_list" arity="1"/>
- <name name="world_list" arity="2"/>
+ <name name="world_list" arity="1" since=""/>
+ <name name="world_list" arity="2" since=""/>
<fsummary>Lookup and connect to all nodes at specified hosts.</fsummary>
<type name="verbosity"/>
<desc>
diff --git a/lib/kernel/doc/src/net_kernel.xml b/lib/kernel/doc/src/net_kernel.xml
index 0b94fc0fa6..419d3cad84 100644
--- a/lib/kernel/doc/src/net_kernel.xml
+++ b/lib/kernel/doc/src/net_kernel.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -28,7 +28,7 @@
<date>1996-09-10</date>
<rev>A</rev>
</header>
- <module>net_kernel</module>
+ <module since="">net_kernel</module>
<modulesummary>Erlang networking kernel.</modulesummary>
<description>
<p>The net kernel is a system process, registered as
@@ -56,7 +56,7 @@ $ <input>erl -sname foobar</input></pre>
<p>Normally, connections are established automatically when
another node is referenced. This functionality can be disabled
by setting Kernel configuration parameter
- <c>dist_auto_connect</c> to <c>false</c>, see
+ <c>dist_auto_connect</c> to <c>never</c>, see
<seealso marker="kernel_app"><c>kernel(6)</c></seealso>. In this case,
connections must be established explicitly by calling
<seealso marker="#connect_node/1"><c>connect_node/1</c></seealso>.</p>
@@ -81,7 +81,7 @@ $ <input>erl -sname foobar</input></pre>
<funcs>
<func>
- <name name="allow" arity="1"/>
+ <name name="allow" arity="1" since=""/>
<fsummary>Permit access to a specified set of nodes</fsummary>
<desc>
<p>Permits access to the specified set of nodes.</p>
@@ -98,17 +98,19 @@ $ <input>erl -sname foobar</input></pre>
</func>
<func>
- <name name="connect_node" arity="1"/>
+ <name name="connect_node" arity="1" since=""/>
<fsummary>Establish a connection to a node.</fsummary>
<desc>
<p>Establishes a connection to <c><anno>Node</anno></c>. Returns
- <c>true</c> if successful, <c>false</c> if not, and <c>ignored</c>
- if the local node is not alive.</p>
+ <c>true</c> if a connection was established or was already
+ established or if <c><anno>Node</anno></c> is the local node
+ itself. Returns <c>false</c> if the connection attempt failed, and
+ <c>ignored</c> if the local node is not alive.</p>
</desc>
</func>
<func>
- <name name="get_net_ticktime" arity="0"/>
+ <name name="get_net_ticktime" arity="0" since=""/>
<fsummary>Get <c>net_ticktime</c>.</fsummary>
<desc>
<p>Gets <c>net_ticktime</c> (see
@@ -129,7 +131,7 @@ $ <input>erl -sname foobar</input></pre>
</func>
<func>
- <name name="getopts" arity="2"/>
+ <name name="getopts" arity="2" since="OTP 19.1"/>
<fsummary>Get distribution socket options.</fsummary>
<desc>
<p>Get one or more options for the distribution socket
@@ -144,8 +146,8 @@ $ <input>erl -sname foobar</input></pre>
</func>
<func>
- <name name="monitor_nodes" arity="1"/>
- <name name="monitor_nodes" arity="2"/>
+ <name name="monitor_nodes" arity="1" since=""/>
+ <name name="monitor_nodes" arity="2" since=""/>
<fsummary>Subscribe to node status change messages.</fsummary>
<desc>
<p>The calling process subscribes or unsubscribes to node
@@ -230,7 +232,12 @@ $ <input>erl -sname foobar</input></pre>
<item>
<p>The tuple <c>{nodedown_reason, Reason}</c> is included in
<c>InfoList</c> in <c>nodedown</c> messages.</p>
- <p><c>Reason</c> can be any of the following:</p>
+ <p>
+ <c>Reason</c> can, depending on which
+ distribution module or process that is used be any term,
+ but for the standard TCP distribution module it is
+ any of the following:
+ </p>
<taglist>
<tag><c>connection_setup_failed</c></tag>
<item><p>The connection setup failed (after <c>nodeup</c>
@@ -260,8 +267,8 @@ $ <input>erl -sname foobar</input></pre>
</func>
<func>
- <name name="set_net_ticktime" arity="1"/>
- <name name="set_net_ticktime" arity="2"/>
+ <name name="set_net_ticktime" arity="1" since=""/>
+ <name name="set_net_ticktime" arity="2" since=""/>
<fsummary>Set <c>net_ticktime</c>.</fsummary>
<desc>
<p>Sets <c>net_ticktime</c> (see
@@ -317,7 +324,7 @@ $ <input>erl -sname foobar</input></pre>
</func>
<func>
- <name name="setopts" arity="2"/>
+ <name name="setopts" arity="2" since="OTP 19.1"/>
<fsummary>Set distribution socket options.</fsummary>
<desc>
<p>Set one or more options for distribution sockets.
@@ -338,9 +345,9 @@ $ <input>erl -sname foobar</input></pre>
</func>
<func>
- <name>start([Name]) -> {ok, pid()} | {error, Reason}</name>
- <name>start([Name, NameType]) -> {ok, pid()} | {error, Reason}</name>
- <name>start([Name, NameType, Ticktime]) -> {ok, pid()} | {error, Reason}</name>
+ <name since="">start([Name]) -> {ok, pid()} | {error, Reason}</name>
+ <name since="">start([Name, NameType]) -> {ok, pid()} | {error, Reason}</name>
+ <name since="">start([Name, NameType, Ticktime]) -> {ok, pid()} | {error, Reason}</name>
<fsummary>Turn an Erlang runtime system into a distributed node.</fsummary>
<type>
<v>Name = atom()</v>
@@ -357,7 +364,7 @@ $ <input>erl -sname foobar</input></pre>
</func>
<func>
- <name name="stop" arity="0"/>
+ <name name="stop" arity="0" since=""/>
<fsummary>Turn a node into a non-distributed Erlang runtime system.</fsummary>
<desc>
<p>Turns a distributed node into a non-distributed node. For
diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml
index 09844f1502..6f68a67174 100644
--- a/lib/kernel/doc/src/notes.xml
+++ b/lib/kernel/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,6 +31,875 @@
</header>
<p>This document describes the changes made to the Kernel application.</p>
+<section><title>Kernel 6.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix so that when multiple <c>-sname</c> or <c>-name</c>
+ are given to <c>erl</c> the first one is chosen. Before
+ this fix distribution was not started at all when
+ multiple name options were given.</p>
+ <p>
+ Own Id: OTP-15786 Aux Id: ERL-918 </p>
+ </item>
+ <item>
+ <p>
+ Fix <c>inet_res</c> configuration pointing to
+ non-existing files to work again. This was broken in
+ KERNEL-6.3 (OTP-21.3).</p>
+ <p>
+ Own Id: OTP-15806</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ A simple socket API is provided through the socket
+ module. This is a low level API that does *not* replace
+ gen_[tcp|udp|sctp]. It is intended to *eventually*
+ replace the inet driver, but not the high level
+ gen-modules (gen_tcp, gen_udp and gen_sctp). It also
+ provides a basic API that facilitates the implementation
+ of other protocols, that is TCP, UDP and SCTP. </p>
+ <p>
+ Known issues are; No support for the Windows OS
+ (currently).</p>
+ <p>
+ Own Id: OTP-14831</p>
+ </item>
+ <item>
+ <p>
+ Improved the documentation for the linger option.</p>
+ <p>
+ Own Id: OTP-15491 Aux Id: PR-2019 </p>
+ </item>
+ <item>
+ <p> Global no longer tries more than once when connecting
+ to other nodes. </p>
+ <p>
+ Own Id: OTP-15607 Aux Id: ERIERL-280 </p>
+ </item>
+ <item>
+ <p>
+ The dist messages EXIT, EXIT2 and MONITOR_DOWN have been
+ updated with new versions that send the reason term as
+ part of the payload of the message instead of as part of
+ the control message.</p>
+ <p>
+ The old versions are still present and can be used when
+ communicating with nodes that don't support the new
+ versions.</p>
+ <p>
+ Own Id: OTP-15611</p>
+ </item>
+ <item>
+ <p>
+ Kernel configuration parameter <c>start_distribution =
+ boolean()</c> is added. If set to <c>false</c>, the
+ system is started with all distribution functionality
+ disabled. Defaults to <c>true</c>.</p>
+ <p>
+ Own Id: OTP-15668 Aux Id: PR-2088 </p>
+ </item>
+ <item>
+ <p>
+ In OTP-21.3, a warning was introduced for duplicated
+ applications/keys in configuration. This warning would be
+ displayed both when the configuration was given as a file
+ on system start, and during runtime via
+ <c>application:set_env/1,2</c>.</p>
+ <p>
+ The warning is now changed to a <c>badarg</c> exception
+ in <c>application:set_env/1,2</c>. If the faulty
+ configuration is given in a configuration file on system
+ start, the startup will fail.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15692 Aux Id: PR-2170 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Kernel 6.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a performance regression when reading files
+ opened with the <c>compressed</c> flag.</p>
+ <p>
+ Own Id: OTP-15706 Aux Id: ERIERL-336 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Kernel 6.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ If for example the <c>/etc/hosts</c> did not come into
+ existence until after the kernel application had started,
+ its content was never read. This bug has now been
+ corrected.</p>
+ <p>
+ Own Id: OTP-14702 Aux Id: PR-2066 </p>
+ </item>
+ <item>
+ <p>
+ Fix bug where doing <c>seq_trace:reset_trace()</c> while
+ another process was doing a garbage collection could
+ cause the run-time system to segfault.</p>
+ <p>
+ Own Id: OTP-15490</p>
+ </item>
+ <item>
+ <p>
+ Fix <c>erl_epmd:port_please</c> spec to include
+ <c>atom()</c> and <c>string()</c>.</p>
+ <p>
+ Own Id: OTP-15557 Aux Id: PR-2117 </p>
+ </item>
+ <item>
+ <p>
+ The Logger handler logger_std_h now keeps track of the
+ inode of its log file in order to re-open the file if the
+ inode changes. This may happen, for instance, if the log
+ file is opened and saved by an editor.</p>
+ <p>
+ Own Id: OTP-15578 Aux Id: ERL-850 </p>
+ </item>
+ <item>
+ <p>
+ When user specific file modes are given to the logger
+ handler <c>logger_std_h</c>, they were earlier accepted
+ without any control. This is now changes, so Logger will
+ adjust the file modes as follows:</p>
+ <p>
+ - If <c>raw</c> is not found in the list, it is
+ added.<br/> - If none of <c>write</c>, <c>append</c> or
+ <c>exclusive</c> are found in the list, <c>append</c> is
+ added.<br/> - If none of <c>delayed_write</c> or
+ <c>{delayed_write,Size,Delay}</c> are found in the list,
+ <c>delayed_write</c> is added.</p>
+ <p>
+ Own Id: OTP-15602</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The standard logger handler, <c>logger_std_h</c>, now has
+ a new internal feature for log rotation. The rotation
+ scheme is as follows:</p>
+ <p>
+ The log file to which the handler currently writes always
+ has the same name, i.e. the name which is configured for
+ the handler. The archived files have the same name, but
+ with extension ".N", where N is an integer. The newest
+ archive has extension ".0", and the oldest archive has
+ the highest number. </p>
+ <p>
+ The size at which the log file is rotated, and the number
+ of archive files that are kept, is specified with the
+ handler specific configuration parameters
+ <c>max_no_bytes</c> and <c>max_no_files</c> respectively. </p>
+ <p>
+ Archives can be compressed, in which case they get a
+ ".gz" file extension after the integer. Compression is
+ specified with the handler specific configuration
+ parameter <c>compress_on_rotate</c>.</p>
+ <p>
+ Own Id: OTP-15479</p>
+ </item>
+ <item>
+ <p>
+ The new functions <c>logger:i/0</c> and <c>logger:i/1</c>
+ are added. These provide the same information as
+ <c>logger:get_config/0</c> and other
+ <c>logger:get_*_config</c> functions, but the information
+ is more logically sorted and more readable.</p>
+ <p>
+ Own Id: OTP-15600</p>
+ </item>
+ <item>
+ <p>
+ Logger is now protected against overload due to massive
+ amounts of log events from the emulator or from remote
+ nodes.</p>
+ <p>
+ Own Id: OTP-15601</p>
+ </item>
+ <item>
+ <p>
+ Logger now uses os:system_time/1 instead of
+ erlang:system_time/1 to generate log event timestamps.</p>
+ <p>
+ Own Id: OTP-15625</p>
+ </item>
+ <item>
+ <p>
+ Add functions <c>application:set_env/1,2</c> and
+ <c>application:set_env/2</c>. These take a list of
+ application configuration parameters, and the behaviour
+ is equivalent to calling <c>application:set_env/4</c>
+ individually for each application/key combination, except
+ it is more efficient.</p>
+ <p>
+ <c>set_env/1,2</c> warns about duplicated applications or
+ keys. The warning is also emitted during boot, if
+ applications or keys are duplicated within one
+ configuration file, e.g. sys.config.</p>
+ <p>
+ Own Id: OTP-15642 Aux Id: PR-2164 </p>
+ </item>
+ <item>
+ <p>
+ Handler specific configuration parameters for the
+ standard handler <c>logger_std_h</c> are changed to be
+ more intuitive and more similar to the disk_log handler.</p>
+ <p>
+ Earlier there was only one parameter, <c>type</c>, which
+ could have the values <c>standard_io</c>,
+ <c>standard_error</c>, <c>{file,FileName}</c> or
+ <c>{file,FileName,Modes}</c>.</p>
+ <p>
+ This is now changed, so the following parameters are
+ allowed:</p>
+ <p>
+ <c>type = standard_io | standard_error | file</c><br/>
+ <c>file = file:filename()</c><br/> <c>modes =
+ [file:mode()]</c></p>
+ <p>
+ All parameters are optional. <c>type</c> defaults to
+ <c>standard_io</c>, unless a file name is given, in which
+ case it defaults to <c>file</c>. If <c>type</c> is set to
+ <c>file</c>, the file name defaults to the same as the
+ handler id.</p>
+ <p>
+ The potential incompatibility is that
+ <c>logger:get_config/0</c> and
+ <c>logger:get_handler_config/1</c> now returns the new
+ parameters, even if the configuration was set with the
+ old variant, e.g. <c>#{type=>{file,FileName}}</c>.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15662</p>
+ </item>
+ <item>
+ <p>
+ The new configuration parameter <c>file_check</c> is
+ added to the Logger handler <c>logger_std_h</c>. This
+ parameter specifies how long (in milliseconds) the
+ handler may wait before checking if the log file still
+ exists and the inode is the same as when it was opened.</p>
+ <p>
+ The default value is 0, which means that this check is
+ done prior to each write operation. Setting a higher
+ number may improve performance, but adds the risk of
+ loosing log events.</p>
+ <p>
+ Own Id: OTP-15663</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Kernel 6.2.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Setting the <c>recbuf</c> size of an inet socket the
+ <c>buffer</c> is also automatically increased. Fix a bug
+ where the auto adjustment of inet buffer size would be
+ triggered even if an explicit inet buffer size had
+ already been set.</p>
+ <p>
+ Own Id: OTP-15651 Aux Id: ERIERL-304 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Kernel 6.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A new function, <c>logger:update_handler_config/3</c> is
+ added, and the handler callback <c>changing_config</c>
+ now has a new argument, <c>SetOrUpdate</c>, which
+ indicates if the configuration change comes from
+ <c>set_handler_config/2,3</c> or
+ <c>update_handler_config/2,3</c>.</p>
+ <p>
+ This allows the handler to consistently merge the new
+ configuration with the old (if the change comes from
+ <c>update_handler_config/2,3</c>) or with the default (if
+ the change comes from <c>set_handler_config/2,3</c>).</p>
+ <p>
+ The built-in handlers <c>logger_std_h</c> and
+ <c>logger_disk_log_h</c> are updated accordingly. A bug
+ which could cause inconsistency between the handlers'
+ internal state and the stored configuration is also
+ corrected.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15364</p>
+ </item>
+ <item>
+ <p>
+ Fix fallback when custom erl_epmd client does not
+ implement address_please.</p>
+ <p>
+ Own Id: OTP-15388 Aux Id: PR-1983 </p>
+ </item>
+ <item>
+ <p>
+ The logger ets table did not have the
+ <c>read_concurrency</c> option. This is now added.</p>
+ <p>
+ Own Id: OTP-15453 Aux Id: ERL-782 </p>
+ </item>
+ <item>
+ <p>
+ During system start, logger has a simple handler which
+ prints to stdout. After the kernel supervision is
+ started, this handler is removed and replaced by the
+ default handler. Due to a bug, logger earlier issued a
+ debug printout saying it received an unexpected message,
+ which was the EXIT message from the simple handler's
+ process. This is now corrected. The simple handler's
+ process now unlinks from the logger process before
+ terminating.</p>
+ <p>
+ Own Id: OTP-15466 Aux Id: ERL-788 </p>
+ </item>
+ <item>
+ <p>
+ The logger handler <c>logger_std_h</c> would not
+ re-create it's log file if it was removed. Due to this it
+ could not be used with tools like 'logrotate'. This is
+ now corrected.</p>
+ <p>
+ Own Id: OTP-15469</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ A function <c>inet:getifaddrs/1</c> that takes a list
+ with a namespace option has been added, for platforms
+ that support that feature, for example Linux (only?).</p>
+ <p>
+ Own Id: OTP-15121 Aux Id: ERIERL-189, PR-1974 </p>
+ </item>
+ <item>
+ <p>Added the <c>nopush</c> option for TCP sockets, which
+ corresponds to <c>TCP_NOPUSH</c> on *BSD and
+ <c>TCP_CORK</c> on Linux.</p>
+ <p>This is also used internally in <c>file:sendfile</c>
+ to reduce latency on subsequent send operations.</p>
+ <p>
+ Own Id: OTP-15357 Aux Id: ERL-698 </p>
+ </item>
+ <item>
+ <p>
+ Optimize handling of send_delay for tcp sockes to better
+ work with the new pollthread implementation introduced in
+ OTP-21.</p>
+ <p>
+ Own Id: OTP-15471 Aux Id: ERIERL-229 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Kernel 6.1.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix bug causing net_kernel process crash on connection
+ attempt from node with name identical to local node.</p>
+ <p>
+ Own Id: OTP-15438 Aux Id: ERL-781 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Kernel 6.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The values <c>all</c> and <c>none</c> are documented as
+ valid value for the Kernel configuration parameter
+ <c>logger_level</c>, but would cause a crash during node
+ start. This is now corrected.</p>
+ <p>
+ Own Id: OTP-15143</p>
+ </item>
+ <item>
+ <p>
+ Fix some potential buggy behavior in how ticks are sent
+ on inter node distribution connections. Tick is now sent
+ to c-node even if there are unsent buffered data, as
+ c-nodes need ticks in order to send reply ticks. The
+ amount of sent data was also calculated wrongly when
+ ticks were suppressed due to unsent buffered data.</p>
+ <p>
+ Own Id: OTP-15162 Aux Id: ERIERL-191 </p>
+ </item>
+ <item>
+ <p>
+ Non semantic change in dist_util.erl to silence dialyzer
+ warning.</p>
+ <p>
+ Own Id: OTP-15170</p>
+ </item>
+ <item>
+ <p>
+ Fixed <c>net_kernel:connect_node(node())</c> to return
+ <c>true</c> (and do nothing) as it always has before
+ OTP-21.0. Also documented this successful "self connect"
+ as the expected behavior.</p>
+ <p>
+ Own Id: OTP-15182 Aux Id: ERL-643 </p>
+ </item>
+ <item>
+ <p>
+ The single_line option on logger_formatter would in some
+ cases add an unwanted comma after the association arrows
+ in a map. This is now corrected.</p>
+ <p>
+ Own Id: OTP-15228</p>
+ </item>
+ <item>
+ <p>
+ Improved robustness of distribution connection setup. In
+ OTP-21.0 a truly asynchronous connection setup was
+ introduced. This is further improvement on that work to
+ make the emulator more robust and also be able to recover
+ in cases when involved Erlang processes misbehave.</p>
+ <p>
+ Own Id: OTP-15297 Aux Id: OTP-15279, OTP-15280 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ A new macro, <c>?LOG(Level,...)</c>, is added. This is
+ equivalent to the existing <c>?LOG_&lt;LEVEL&gt;(...)</c>
+ macros.</p>
+ <p>
+ A new variant of Logger report callback is added, which
+ takes an extra argument containing options for size
+ limiting and line breaks. Module <c>proc_lib</c> in
+ <c>STDLIB</c> uses this for crash reports.</p>
+ <p>
+ Logger configuration is now checked a bit more for
+ errors.</p>
+ <p>
+ Own Id: OTP-15132</p>
+ </item>
+ <item>
+ <p>
+ The socket options <c>recvtos</c>, <c>recvttl</c>,
+ <c>recvtclass</c> and <c>pktoptions</c> have been
+ implemented in the socket modules. See the documentation
+ for the <c>gen_tcp</c>, <c>gen_udp</c> and <c>inet</c>
+ modules. Note that support for these in the runtime
+ system is platform dependent. Especially for
+ <c>pktoptions</c> which is very Linux specific and
+ obsoleted by the RFCs that defined it.</p>
+ <p>
+ Own Id: OTP-15145 Aux Id: ERIERL-187 </p>
+ </item>
+ <item>
+ <p>
+ Add <c>logger:set_application_level/2</c> for setting the
+ logger level of all modules in one application.</p>
+ <p>
+ Own Id: OTP-15146</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Kernel 6.0.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed bug in <c>net_kernel</c> that could cause an
+ emulator crash if certain connection attempts failed. Bug
+ exists since kernel-6.0 (OTP-21.0).</p>
+ <p>
+ Own Id: OTP-15280 Aux Id: ERIERL-226, OTP-15279 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Kernel 6.0</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Clarify the documentation of <c>rpc:multicall/5</c>.
+ </p>
+ <p>
+ Own Id: OTP-10551</p>
+ </item>
+ <item>
+ <p>
+ The DNS resolver when getting econnrefused from a server
+ retained an invalid socket so look up towards the next
+ server(s) also failed.</p>
+ <p>
+ Own Id: OTP-13133 Aux Id: PR-1557 </p>
+ </item>
+ <item>
+ <p>
+ No resolver backend returns V4Mapped IPv6 addresses any
+ more. This was inconsistent before, some did, some did
+ not. To facilitate working with such addresses a new
+ function <c>inet:ipv4_mapped_ipv6_address/1</c> has been
+ added.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-13761 Aux Id: ERL-503 </p>
+ </item>
+ <item>
+ <p>
+ The type specifications for <c>file:posix/0</c> and
+ <c>inet:posix/0</c> have been updated according to which
+ errors file and socket operations should be able to
+ return.</p>
+ <p>
+ Own Id: OTP-14019 Aux Id: ERL-550 </p>
+ </item>
+ <item>
+ <p>
+ Fix name resolving in IPv6 only environments when doing
+ the initial distributed connection.</p>
+ <p>
+ Own Id: OTP-14501</p>
+ </item>
+ <item>
+ <p> File operations used to accept <seealso
+ marker="kernel:file#type-name_all">filenames</seealso>
+ containing null characters (integer value zero). This
+ caused the name to be truncated and in some cases
+ arguments to primitive operations to be mixed up.
+ Filenames containing null characters inside the filename
+ are now <em>rejected</em> and will cause primitive file
+ operations to fail. </p> <p> Also environment variable
+ operations used to accept <seealso
+ marker="kernel:os#type-env_var_name">names</seealso> and
+ <seealso
+ marker="kernel:os#type-env_var_value">values</seealso> of
+ environment variables containing null characters (integer
+ value zero). This caused operations to silently produce
+ erroneous results. Environment variable names and values
+ containing null characters inside the name or value are
+ now <em>rejected</em> and will cause environment variable
+ operations to fail. </p> <p>Primitive environment
+ variable operations also used to accept the <c>$=</c>
+ character in environment variable names causing various
+ problems. <c>$=</c> characters in environment variable
+ names are now also <em>rejected</em>. </p> <p>Also
+ <seealso
+ marker="kernel:os#cmd/1"><c>os:cmd/1</c></seealso> now
+ reject null characters inside its <seealso
+ marker="kernel:os#type-os_command">command</seealso>.
+ </p> <p><seealso
+ marker="erts:erlang#open_port/2"><c>erlang:open_port/2</c></seealso>
+ will also reject null characters inside the port name
+ from now on.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14543 Aux Id: ERL-370 </p>
+ </item>
+ <item>
+ <p><c>os:putenv</c> and <c>os:getenv</c> no longer access
+ the process environment directly and instead work on a
+ thread-safe emulation. The only observable difference is
+ that it's <em>not</em> kept in sync with libc
+ <c>getenv(3)</c> / <c>putenv(3)</c>, so those who relied
+ on that behavior in drivers or NIFs will need to add
+ manual synchronization.</p> <p>On Windows this means that
+ you can no longer resolve DLL dependencies by modifying
+ the <c>PATH</c> just before loading the driver/NIF. To
+ make this less of a problem, the emulator now adds the
+ target DLL's folder to the DLL search path.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14666</p>
+ </item>
+ <item>
+ <p>
+ Fixed connection tick toward primitive hidden nodes
+ (erl_interface) that could cause faulty tick timeout in
+ rare cases when payload data is sent to hidden node but
+ not received.</p>
+ <p>
+ Own Id: OTP-14681</p>
+ </item>
+ <item>
+ <p>
+ Make group react immediately on an EXIT-signal from shell
+ in e.g ssh.</p>
+ <p>
+ Own Id: OTP-14991 Aux Id: PR1705 </p>
+ </item>
+ <item>
+ <p>
+ Calls to <c>gen_tcp:send/2</c> on closed sockets now
+ returns <c>{error, closed}</c> instead of
+ <c>{error,enotconn}</c>.</p>
+ <p>
+ Own Id: OTP-15001</p>
+ </item>
+ <item>
+ <p>
+ The <c>included_applications</c> key are no longer
+ duplicated as application environment variable. Earlier,
+ the included applications could be read both with
+ <c>application:get[_all]_env(...)</c> and
+ <c>application:get[_all]_key(...)</c> functions. Now, it
+ can only be read with
+ <c>application:get[_all]_key(...)</c>.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15071</p>
+ </item>
+ <item>
+ <p>Owner and group changes through
+ <c>file:write_file_info</c>, <c>file:change_owner</c>,
+ and <c>file:change_group</c> will no longer report
+ success on permission errors.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15118</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>A new logging API is added to Erlang/OTP, see the
+ <seealso
+ marker="kernel:logger"><c>logger(3)</c></seealso> manual
+ page, and section <seealso
+ marker="kernel:logger_chapter">Logging</seealso> in the
+ Kernel User's Guide.</p>
+ <p>Calls to <c>error_logger</c> are automatically
+ redirected to the new API, and legacy error logger event
+ handlers can still be used. It is, however, recommended
+ to use the Logger API directly when writing new code.</p>
+ <p>Notice the following potential incompatibilities:</p>
+ <list> <item><p>Kernel configuration parameters
+ <c>error_logger</c> still works, but is overruled if the
+ default handler's output destination is configured with
+ Kernel configuration parameter <c>logger</c>.</p> <p>In
+ general, parameters for configuring error logger are
+ overwritten by new parameters for configuring
+ Logger.</p></item> <item><p>The concept of SASL error
+ logging is deprecated, meaning that by default the SASL
+ application does not affect which log events are
+ logged.</p> <p>By default, supervisor reports and crash
+ reports are logged by the default Logger handler started
+ by Kernel, and end up at the same destination (terminal
+ or file) as other standard log event from Erlang/OTP.</p>
+ <p>Progress reports are not logged by default, but can be
+ enabled by setting the primary log level to info, for
+ example with the Kernel configuration parameter
+ <c>logger_level</c>.</p> <p>To obtain backwards
+ compatibility with the SASL error logging functionality
+ from earlier releases, set Kernel configuration parameter
+ <c>logger_sasl_compatible</c> to <c>true</c>. This
+ prevents the default Logger handler from logging any
+ supervisor-, crash-, or progress reports. Instead, SASL
+ adds a separate Logger handler during application start,
+ which takes care of these log events. The SASL
+ configuration parameters <c>sasl_error_logger</c> and
+ <c>sasl_errlog_type</c> specify the destination (terminal
+ or file) and severity level to log for these
+ events.</p></item></list>
+ <p>
+ Since Logger is new in Erlang/OTP 21.0, we do reserve the
+ right to introduce changes to the Logger API and
+ functionality in patches following this release. These
+ changes might or might not be backwards compatible with
+ the initial version.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-13295</p>
+ </item>
+ <item>
+ <p>
+ The function <c>inet:i/0</c> has been documented.</p>
+ <p>
+ Own Id: OTP-13713 Aux Id: PR-1645 </p>
+ </item>
+ <item>
+ <p>
+ Typespecs for <c>netns</c> and <c>bind_to_device</c>
+ options have been added to <c>gen_tcp</c>, <c>gen_udp</c>
+ and <c>gen_sctp</c> functions.</p>
+ <p>
+ Own Id: OTP-14359 Aux Id: PR-1816 </p>
+ </item>
+ <item>
+ <p>
+ New functionality for implementation of alternative
+ carriers for the Erlang distribution has been introduced.
+ This mainly consists of support for usage of distribution
+ controller processes (previously only ports could be used
+ as distribution controllers). For more information see
+ <seealso marker="erts:alt_dist#distribution_module">ERTS
+ User's Guide ➜ How to implement an Alternative Carrier
+ for the Erlang Distribution ➜ Distribution
+ Module</seealso>.</p>
+ <p>
+ Own Id: OTP-14459</p>
+ </item>
+ <item>
+ <p><c>seq_trace</c> labels may now be any erlang
+ term.</p>
+ <p>
+ Own Id: OTP-14899</p>
+ </item>
+ <item>
+ <p>
+ The SSL distribution protocol <c>-proto inet_tls</c> has
+ stopped setting the SSL option
+ <c>server_name_indication</c>. New verify funs for client
+ and server in <c>inet_tls_dist</c> has been added, not
+ documented yet, that checks node name if present in peer
+ certificate. Usage is still also yet to be documented.</p>
+ <p>
+ Own Id: OTP-14969 Aux Id: OTP-14465, ERL-598 </p>
+ </item>
+ <item>
+ <p>
+ Changed timeout of <c>gen_server</c> calls to <c>auth</c>
+ server from default 5 seconds to <c>infinity</c>.</p>
+ <p>
+ Own Id: OTP-15009 Aux Id: ERL-601 </p>
+ </item>
+ <item>
+ <p>The callback module passed as <c>-epmd_module</c> to
+ erl has been expanded to be able to do name and port
+ resolving.</p> <p>Documentation has also been added in
+ the <seealso
+ marker="kernel:erl_epmd"><c>erl_epmd</c></seealso>
+ reference manual and ERTS User's Guide <seealso
+ marker="erts:alt_disco">How to Implement an Alternative
+ Service Discovery for Erlang Distribution</seealso>.</p>
+ <p>
+ Own Id: OTP-15086 Aux Id: PR-1694 </p>
+ </item>
+ <item>
+ <p>
+ Included config file specified with relative path in
+ sys.config are now first searched for relative to the
+ directory of sys.config itself. If not found, it is also
+ searched for relative to the current working directory.
+ The latter is for backwards compatibility.</p>
+ <p>
+ Own Id: OTP-15137 Aux Id: PR-1838 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Kernel 5.4.3.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Non semantic change in dist_util.erl to silence dialyzer
+ warning.</p>
+ <p>
+ Own Id: OTP-15170</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Kernel 5.4.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix some potential buggy behavior in how ticks are sent
+ on inter node distribution connections. Tick is now sent
+ to c-node even if there are unsent buffered data, as
+ c-nodes need ticks in order to send reply ticks. The
+ amount of sent data was calculated wrongly when ticks
+ where suppressed due to unsent buffered data.</p>
+ <p>
+ Own Id: OTP-15162 Aux Id: ERIERL-191 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Kernel 5.4.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/kernel/doc/src/os.xml b/lib/kernel/doc/src/os.xml
index 7ce2f54542..0500e4cfb3 100644
--- a/lib/kernel/doc/src/os.xml
+++ b/lib/kernel/doc/src/os.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2017</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>os</module>
+ <module since="">os</module>
<modulesummary>Operating system-specific functions.</modulesummary>
<description>
<p>The functions in this module are operating system-specific.
@@ -36,11 +36,85 @@
only run on a specific platform. On the other hand, with careful
use, these functions can be of help in enabling a program to run on
most platforms.</p>
+
+ <note>
+ <p>
+ File operations used to accept filenames containing
+ null characters (integer value zero). This caused
+ the name to be truncated and in some cases arguments
+ to primitive operations to be mixed up. Filenames
+ containing null characters inside the filename
+ are now <em>rejected</em> and will cause primitive
+ file operations to fail.
+ </p>
+ <p>
+ Also environment variable operations used to accept
+ names and values of environment variables containing
+ null characters (integer value zero). This caused
+ operations to silently produce erroneous results.
+ Environment variable names and values containing
+ null characters inside the name or value are now
+ <em>rejected</em> and will cause environment variable
+ operations to fail.
+ </p>
+ </note>
</description>
<datatypes>
<datatype>
+ <name name="env_var_name"/>
+ <desc>
+ <p>A string containing valid characters on the specific
+ OS for environment variable names using
+ <seealso marker="file#native_name_encoding/0"><c>file:native_name_encoding()</c></seealso>
+ encoding. Note that specifically null characters (integer
+ value zero) and <c>$=</c> characters are not allowed.
+ However, note that not all invalid characters necessarily
+ will cause the primitiv operations to fail, but may instead
+ produce invalid results.
+ </p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="env_var_value"/>
+ <desc>
+ <p>A string containing valid characters on the specific
+ OS for environment variable values using
+ <seealso marker="file#native_name_encoding/0"><c>file:native_name_encoding()</c></seealso>
+ encoding. Note that specifically null characters (integer
+ value zero) are not allowed. However, note that not all
+ invalid characters necessarily will cause the primitiv
+ operations to fail, but may instead produce invalid results.
+ </p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="env_var_name_value"/>
+ <desc>
+ <p>
+ Assuming that environment variables has been correctly
+ set, a strings containing valid characters on the specific
+ OS for environment variable names and values using
+ <seealso marker="file#native_name_encoding/0"><c>file:native_name_encoding()</c></seealso>
+ encoding. The first <c>$=</c> characters appearing in
+ the string separates environment variable name (on the
+ left) from environment variable value (on the right).
+ </p>
+ </desc>
+ </datatype>
+ <datatype>
<name name="os_command"/>
+ <desc>
+ <p>All characters needs to be valid characters on the
+ specific OS using
+ <seealso marker="file#native_name_encoding/0"><c>file:native_name_encoding()</c></seealso>
+ encoding. Note that specifically null characters (integer
+ value zero) are not allowed. However, note that not all
+ invalid characters not necessarily will cause
+ <seealso marker="#cmd/1"><c>os:cmd/1</c></seealso>
+ to fail, but may instead produce invalid results.
+ </p>
+ </desc>
</datatype>
<datatype>
<name name="os_command_opts"/>
@@ -60,13 +134,18 @@
<funcs>
<func>
- <name name="cmd" arity="1"/>
- <name name="cmd" arity="2"/>
+ <name name="cmd" arity="1" since=""/>
+ <name name="cmd" arity="2" since="OTP 20.2.3"/>
<fsummary>Execute a command in a shell of the target OS.</fsummary>
<desc>
<p>Executes <c><anno>Command</anno></c> in a command shell of the
- target OS, captures the standard output of the command,
+ target OS, captures the standard output of the command,
and returns this result as a string.</p>
+ <warning><p>Previous implementation used to allow all characters
+ as long as they were integer values greater than or equal to zero.
+ This sometimes lead to unwanted results since null characters
+ (integer value zero) often are interpreted as string termination. The
+ current implementation rejects these.</p></warning>
<p><em>Examples:</em></p>
<code type="none">
LsOut = os:cmd("ls"), % on unix platform
@@ -94,8 +173,8 @@ DirOut = os:cmd("dir"), % on Win32 platform</code>
</func>
<func>
- <name name="find_executable" arity="1"/>
- <name name="find_executable" arity="2"/>
+ <name name="find_executable" arity="1" since=""/>
+ <name name="find_executable" arity="2" since=""/>
<fsummary>Absolute filename of a program.</fsummary>
<desc>
<p>These two functions look up an executable program, with the
@@ -111,7 +190,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code>
</func>
<func>
- <name name="getenv" arity="0"/>
+ <name name="getenv" arity="0" since=""/>
<fsummary>List all environment variables.</fsummary>
<desc>
<p>Returns a list of all environment variables.
@@ -126,7 +205,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code>
</func>
<func>
- <name name="getenv" arity="1"/>
+ <name name="getenv" arity="1" since=""/>
<fsummary>Get the value of an environment variable.</fsummary>
<desc>
<p>Returns the <c><anno>Value</anno></c> of the environment variable
@@ -141,7 +220,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code>
</func>
<func>
- <name name="getenv" arity="2"/>
+ <name name="getenv" arity="2" since="OTP 18.0"/>
<fsummary>Get the value of an environment variable.</fsummary>
<desc>
<p>Returns the <c><anno>Value</anno></c> of the environment variable
@@ -156,7 +235,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code>
</func>
<func>
- <name name="getpid" arity="0"/>
+ <name name="getpid" arity="0" since=""/>
<fsummary>Return the process identifier of the emulator
process.</fsummary>
<desc>
@@ -172,7 +251,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code>
</func>
<func>
- <name name="putenv" arity="2"/>
+ <name name="putenv" arity="2" since=""/>
<fsummary>Set a new value for an environment variable.</fsummary>
<desc>
<p>Sets a new <c><anno>Value</anno></c> for environment variable
@@ -185,11 +264,20 @@ DirOut = os:cmd("dir"), % on Win32 platform</code>
<p>On Unix platforms, the environment is set using UTF-8 encoding
if Unicode filename translation is in effect. On Windows, the
environment is set using wide character interfaces.</p>
+ <note>
+ <p>
+ <c><anno>VarName</anno></c> is not allowed to contain
+ an <c>$=</c> character. Previous implementations used
+ to just let the <c>$=</c> character through which
+ silently caused erroneous results. Current implementation
+ will instead throw a <c>badarg</c> exception.
+ </p>
+ </note>
</desc>
</func>
<func>
- <name name="set_signal" arity="2"/>
+ <name name="set_signal" arity="2" since="OTP 20.0"/>
<fsummary>Enables or disables handling of OS signals.</fsummary>
<desc>
<p>Enables or disables OS signals.</p>
@@ -216,7 +304,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code>
</func>
<func>
- <name name="system_time" arity="0"/>
+ <name name="system_time" arity="0" since="OTP 18.0"/>
<fsummary>Current OS system time.</fsummary>
<desc>
<p>Returns the current
@@ -229,7 +317,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code>
</func>
<func>
- <name name="system_time" arity="1"/>
+ <name name="system_time" arity="1" since="OTP 18.0"/>
<fsummary>Current OS system time.</fsummary>
<desc>
<p>Returns the current
@@ -244,7 +332,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code>
</func>
<func>
- <name name="timestamp" arity="0"/>
+ <name name="timestamp" arity="0" since=""/>
<fsummary>Current OS system time on the <c>erlang:timestamp/0</c> format.</fsummary>
<type_desc variable="Timestamp">Timestamp = {MegaSecs, Secs, MicroSecs}</type_desc>
<desc>
@@ -285,7 +373,7 @@ calendar:now_to_universal_time(TS),
</func>
<func>
- <name name="perf_counter" arity="0"/>
+ <name name="perf_counter" arity="0" since="OTP 19.0"/>
<fsummary>Returns a performance counter</fsummary>
<desc>
<p>Returns the current performance counter value in <c>perf_counter</c>
@@ -295,7 +383,7 @@ calendar:now_to_universal_time(TS),
</desc>
</func>
<func>
- <name name="perf_counter" arity="1"/>
+ <name name="perf_counter" arity="1" since="OTP 19.0"/>
<fsummary>Returns a performance counter</fsummary>
<desc><p>Returns a performance counter that can be used as a very fast and
high resolution timestamp. This counter is read directly from the hardware or operating
@@ -309,7 +397,7 @@ calendar:now_to_universal_time(TS),
</desc>
</func>
<func>
- <name name="type" arity="0"/>
+ <name name="type" arity="0" since=""/>
<fsummary>Return the OS family and, in some cases, the OS name of the
current OS.</fsummary>
<desc>
@@ -329,7 +417,7 @@ calendar:now_to_universal_time(TS),
</func>
<func>
- <name name="unsetenv" arity="1"/>
+ <name name="unsetenv" arity="1" since="OTP R16B03"/>
<fsummary>Delete an environment variable.</fsummary>
<desc>
<p>Deletes the environment variable <c><anno>VarName</anno></c>.</p>
@@ -341,7 +429,7 @@ calendar:now_to_universal_time(TS),
</func>
<func>
- <name name="version" arity="0"/>
+ <name name="version" arity="0" since=""/>
<fsummary>Return the OS versions.</fsummary>
<desc>
<p>Returns the OS version.
diff --git a/lib/kernel/doc/src/part.xml b/lib/kernel/doc/src/part.xml
new file mode 100644
index 0000000000..fa7e92835f
--- /dev/null
+++ b/lib/kernel/doc/src/part.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE part SYSTEM "part.dtd">
+
+<part xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header>
+ <copyright>
+ <year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>Kernel User's Guide</title>
+ <prepared>OTP Team</prepared>
+ <docno></docno>
+ <date>2018-06-06</date>
+ <file>part.xml</file>
+ </header>
+ <description>
+ <p></p>
+ </description>
+ <xi:include href="introduction_chapter.xml"/>
+ <xi:include href="logger_chapter.xml"/>
+</part>
+
diff --git a/lib/kernel/doc/src/pg2.xml b/lib/kernel/doc/src/pg2.xml
index 0631b317b4..058d711756 100644
--- a/lib/kernel/doc/src/pg2.xml
+++ b/lib/kernel/doc/src/pg2.xml
@@ -32,7 +32,7 @@
<rev>A2</rev>
<file>pg2.xml</file>
</header>
- <module>pg2</module>
+ <module since="">pg2</module>
<modulesummary>Distributed named process groups.</modulesummary>
<description>
<p>This module implements process groups. Each message can be sent
@@ -66,7 +66,7 @@
<funcs>
<func>
- <name name="create" arity="1"/>
+ <name name="create" arity="1" since=""/>
<fsummary>Create a new, empty process group.</fsummary>
<desc>
<p>Creates a new, empty process group. The group is globally
@@ -75,7 +75,7 @@
</func>
<func>
- <name name="delete" arity="1"/>
+ <name name="delete" arity="1" since=""/>
<fsummary>Delete a process group.</fsummary>
<desc>
<p>Deletes a process group.</p>
@@ -83,7 +83,7 @@
</func>
<func>
- <name name="get_closest_pid" arity="1"/>
+ <name name="get_closest_pid" arity="1" since=""/>
<fsummary>Common dispatch function.</fsummary>
<desc>
<p>A useful dispatch function that can be used from
@@ -93,7 +93,7 @@
</func>
<func>
- <name name="get_local_members" arity="1"/>
+ <name name="get_local_members" arity="1" since=""/>
<fsummary>Return all local processes in a group.</fsummary>
<desc>
<p>Returns all processes running on the local node in the
@@ -104,7 +104,7 @@
</func>
<func>
- <name name="get_members" arity="1"/>
+ <name name="get_members" arity="1" since=""/>
<fsummary>Return all processes in a group.</fsummary>
<desc>
<p>Returns all processes in the group <c>Name</c>. This
@@ -114,7 +114,7 @@
</func>
<func>
- <name name="join" arity="2"/>
+ <name name="join" arity="2" since=""/>
<fsummary>Join a process to a group.</fsummary>
<desc>
<p>Joins the process <c>Pid</c> to the group <c>Name</c>.
@@ -124,7 +124,7 @@
</func>
<func>
- <name name="leave" arity="2"/>
+ <name name="leave" arity="2" since=""/>
<fsummary>Make a process leave a group.</fsummary>
<desc>
<p>Makes the process <c>Pid</c> leave the group <c>Name</c>.
@@ -134,8 +134,8 @@
</func>
<func>
- <name name="start" arity="0"/>
- <name name="start_link" arity="0"/>
+ <name name="start" arity="0" since=""/>
+ <name name="start_link" arity="0" since=""/>
<fsummary>Start the <c>pg2</c> server.</fsummary>
<desc>
<p>Starts the <c>pg2</c> server. Normally, the server does not need
@@ -149,7 +149,7 @@
</func>
<func>
- <name name="which_groups" arity="0"/>
+ <name name="which_groups" arity="0" since=""/>
<fsummary>Return a list of all known groups.</fsummary>
<desc>
<p>Returns a list of all known groups.</p>
diff --git a/lib/kernel/doc/src/ref_man.xml b/lib/kernel/doc/src/ref_man.xml
index 5cd77e0f6f..d3b947527f 100644
--- a/lib/kernel/doc/src/ref_man.xml
+++ b/lib/kernel/doc/src/ref_man.xml
@@ -4,7 +4,7 @@
<application xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,12 +32,15 @@
</description>
<xi:include href="kernel_app.xml"/>
+ <xi:include href="app.xml"/>
<xi:include href="application.xml"/>
<xi:include href="auth.xml"/>
<xi:include href="code.xml"/>
+ <xi:include href="config.xml"/>
<xi:include href="disk_log.xml"/>
<xi:include href="erl_boot_server.xml"/>
<xi:include href="erl_ddll.xml"/>
+ <xi:include href="erl_epmd.xml"/>
<xi:include href="erl_prim_loader_stub.xml"/>
<xi:include href="erlang_stub.xml"/>
<xi:include href="error_handler.xml"/>
@@ -52,6 +55,11 @@
<xi:include href="inet.xml"/>
<xi:include href="inet_res.xml"/>
<xi:include href="init_stub.xml"/>
+ <xi:include href="logger.xml"/>
+ <xi:include href="logger_filters.xml"/>
+ <xi:include href="logger_formatter.xml"/>
+ <xi:include href="logger_std_h.xml"/>
+ <xi:include href="logger_disk_log_h.xml"/>
<xi:include href="net_adm.xml"/>
<xi:include href="net_kernel.xml"/>
<xi:include href="os.xml"/>
@@ -61,6 +69,4 @@
<xi:include href="user.xml"/>
<xi:include href="wrap_log_reader.xml"/>
<xi:include href="zlib_stub.xml"/>
- <xi:include href="app.xml"/>
- <xi:include href="config.xml"/>
</application>
diff --git a/lib/kernel/doc/src/rpc.xml b/lib/kernel/doc/src/rpc.xml
index adec2d9520..c55454506e 100644
--- a/lib/kernel/doc/src/rpc.xml
+++ b/lib/kernel/doc/src/rpc.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -28,7 +28,7 @@
<date>1996-09-10</date>
<rev>A</rev>
</header>
- <module>rpc</module>
+ <module since="">rpc</module>
<modulesummary>Remote Procedure Call services.</modulesummary>
<description>
<p>This module contains services similar to Remote
@@ -51,7 +51,7 @@
<funcs>
<func>
- <name name="abcast" arity="2"/>
+ <name name="abcast" arity="2" since=""/>
<fsummary>Broadcast a message asynchronously to a registered process on
all nodes.</fsummary>
<desc>
@@ -61,7 +61,7 @@
</func>
<func>
- <name name="abcast" arity="3"/>
+ <name name="abcast" arity="3" since=""/>
<fsummary>Broadcast a message asynchronously to a registered process on
specific nodes.</fsummary>
<desc>
@@ -72,7 +72,7 @@
</func>
<func>
- <name name="async_call" arity="4"/>
+ <name name="async_call" arity="4" since=""/>
<fsummary>Evaluate a function call on a node, asynchronous
version.</fsummary>
<desc>
@@ -98,7 +98,7 @@
</func>
<func>
- <name name="block_call" arity="4"/>
+ <name name="block_call" arity="4" since=""/>
<fsummary>Evaluate a function call on a node in the RPC server's
context.</fsummary>
<desc>
@@ -115,7 +115,7 @@
</func>
<func>
- <name name="block_call" arity="5"/>
+ <name name="block_call" arity="5" since=""/>
<fsummary>Evaluate a function call on a node in the RPC server's
context.</fsummary>
<desc>
@@ -127,7 +127,7 @@
</func>
<func>
- <name name="call" arity="4"/>
+ <name name="call" arity="4" since=""/>
<fsummary>Evaluate a function call on a node.</fsummary>
<desc>
<p>Evaluates <c>apply(<anno>Module</anno>, <anno>Function</anno>,
@@ -138,7 +138,7 @@
</func>
<func>
- <name name="call" arity="5"/>
+ <name name="call" arity="5" since=""/>
<fsummary>Evaluate a function call on a node.</fsummary>
<desc>
<p>Evaluates <c>apply(<anno>Module</anno>, <anno>Function</anno>,
@@ -158,7 +158,7 @@
</func>
<func>
- <name name="cast" arity="4"/>
+ <name name="cast" arity="4" since=""/>
<fsummary>Run a function on a node ignoring the result.</fsummary>
<desc>
<p>Evaluates <c>apply(<anno>Module</anno>, <anno>Function</anno>,
@@ -171,7 +171,7 @@
</func>
<func>
- <name name="eval_everywhere" arity="3"/>
+ <name name="eval_everywhere" arity="3" since=""/>
<fsummary>Run a function on all nodes, ignoring the result.</fsummary>
<desc>
<p>Equivalent to <c>eval_everywhere([node()|nodes()],
@@ -181,7 +181,7 @@
</func>
<func>
- <name name="eval_everywhere" arity="4"/>
+ <name name="eval_everywhere" arity="4" since=""/>
<fsummary>Run a function on specific nodes, ignoring the
result.</fsummary>
<desc>
@@ -192,7 +192,7 @@
</func>
<func>
- <name name="multi_server_call" arity="2"/>
+ <name name="multi_server_call" arity="2" since=""/>
<fsummary>Interact with the servers on a number of nodes.</fsummary>
<desc>
<p>Equivalent to <c>multi_server_call([node()|nodes()],
@@ -201,7 +201,7 @@
</func>
<func>
- <name name="multi_server_call" arity="3"/>
+ <name name="multi_server_call" arity="3" since=""/>
<fsummary>Interact with the servers on a number of nodes.</fsummary>
<desc>
<p>Can be used when interacting with servers called
@@ -217,14 +217,14 @@
<list type="bulleted">
<item>A list of the nodes that do not exist</item>
<item>A list of the nodes where the server does not exist</item>
- <item>A list of the nodes where the server terminatd before sending
+ <item>A list of the nodes where the server terminated before sending
any reply.</item>
</list>
</desc>
</func>
<func>
- <name name="multicall" arity="3"/>
+ <name name="multicall" arity="3" since=""/>
<fsummary>Evaluate a function call on a number of nodes.</fsummary>
<desc>
<p>Equivalent to <c>multicall([node()|nodes()], <anno>Module</anno>,
@@ -233,7 +233,7 @@
</func>
<func>
- <name name="multicall" arity="4" clause_i="1"/>
+ <name name="multicall" arity="4" clause_i="1" since=""/>
<fsummary>Evaluate a function call on a number of nodes.</fsummary>
<desc>
<p>Equivalent to <c>multicall(<anno>Nodes</anno>, <anno>Module</anno>,
@@ -242,7 +242,7 @@
</func>
<func>
- <name name="multicall" arity="4" clause_i="2"/>
+ <name name="multicall" arity="4" clause_i="2" since=""/>
<fsummary>Evaluate a function call on a number of nodes.</fsummary>
<desc>
<p>Equivalent to <c>multicall([node()|nodes()], <anno>Module</anno>,
@@ -252,7 +252,7 @@
</func>
<func>
- <name name="multicall" arity="5"/>
+ <name name="multicall" arity="5" since=""/>
<fsummary>Evaluate a function call on a number of nodes.</fsummary>
<desc>
<p>In contrast to an RPC, a multicall is an RPC that is sent
@@ -268,8 +268,9 @@
on the specified nodes and collects the answers. It returns
<c>{<anno>ResL</anno>, <anno>BadNodes</anno>}</c>, where
<c><anno>BadNodes</anno></c> is a list
- of the nodes that terminated or timed out during computation,
- and <c><anno>ResL</anno></c> is a list of the return values.
+ of the nodes that do not exist,
+ and <c><anno>ResL</anno></c> is a list of the return values,
+ or <c>{badrpc, <anno>Reason</anno>}</c> for failing calls.
<c><anno>Timeout</anno></c> is a time (integer) in milliseconds, or
<c>infinity</c>.</p>
<p>The following example is useful when new object code is to
@@ -287,7 +288,7 @@
</func>
<func>
- <name name="nb_yield" arity="1"/>
+ <name name="nb_yield" arity="1" since=""/>
<fsummary>Deliver the result of evaluating a function call on a node
(non-blocking).</fsummary>
<desc>
@@ -296,7 +297,7 @@
</func>
<func>
- <name name="nb_yield" arity="2"/>
+ <name name="nb_yield" arity="2" since=""/>
<fsummary>Deliver the result of evaluating a function call on a node
(non-blocking).</fsummary>
<desc>
@@ -314,7 +315,7 @@
</func>
<func>
- <name name="parallel_eval" arity="1"/>
+ <name name="parallel_eval" arity="1" since=""/>
<fsummary>Evaluate many function calls on all nodes in
parallel.</fsummary>
<desc>
@@ -327,7 +328,7 @@
</func>
<func>
- <name name="pinfo" arity="1"/>
+ <name name="pinfo" arity="1" since=""/>
<fsummary>Information about a process.</fsummary>
<desc>
<p>Location transparent version of the BIF
@@ -336,8 +337,8 @@
</func>
<func>
- <name name="pinfo" arity="2" clause_i="1"/>
- <name name="pinfo" arity="2" clause_i="2"/>
+ <name name="pinfo" arity="2" clause_i="1" since=""/>
+ <name name="pinfo" arity="2" clause_i="2" since=""/>
<fsummary>Information about a process.</fsummary>
<desc>
<p>Location transparent version of the BIF
@@ -346,8 +347,8 @@
</func>
<func>
- <name name="pmap" arity="3"/>
- <fsummary>Parallell evaluation of mapping a function over a
+ <name name="pmap" arity="3" since=""/>
+ <fsummary>Parallel evaluation of mapping a function over a
list.</fsummary>
<desc>
<p>Evaluates <c>apply(<anno>Module</anno>, <anno>Function</anno>,
@@ -359,7 +360,7 @@
</func>
<func>
- <name name="sbcast" arity="2"/>
+ <name name="sbcast" arity="2" since=""/>
<fsummary>Broadcast a message synchronously to a registered process on
all nodes.</fsummary>
<desc>
@@ -369,7 +370,7 @@
</func>
<func>
- <name name="sbcast" arity="3"/>
+ <name name="sbcast" arity="3" since=""/>
<fsummary>Broadcast a message synchronously to a registered process on
specific nodes.</fsummary>
<desc>
@@ -390,7 +391,7 @@
</func>
<func>
- <name name="server_call" arity="4"/>
+ <name name="server_call" arity="4" since=""/>
<fsummary>Interact with a server on a node.</fsummary>
<desc>
<p>Can be used when interacting with a server called
@@ -409,7 +410,7 @@
</func>
<func>
- <name name="yield" arity="1"/>
+ <name name="yield" arity="1" since=""/>
<fsummary>Deliver the result of evaluating a function call on a node
(blocking).</fsummary>
<desc>
diff --git a/lib/kernel/doc/src/seq_trace.xml b/lib/kernel/doc/src/seq_trace.xml
index 197851021f..aa29223dd0 100644
--- a/lib/kernel/doc/src/seq_trace.xml
+++ b/lib/kernel/doc/src/seq_trace.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1998</year><year>2017</year>
+ <year>1998</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -28,7 +28,7 @@
<date>1998-04-16</date>
<rev>A</rev>
</header>
- <module>seq_trace</module>
+ <module since="">seq_trace</module>
<modulesummary>Sequential tracing of messages.</modulesummary>
<description>
<p>Sequential tracing makes it possible to trace all messages
@@ -51,7 +51,7 @@
</datatypes>
<funcs>
<func>
- <name name="set_token" arity="1"/>
+ <name name="set_token" arity="1" since=""/>
<fsummary>Set the trace token</fsummary>
<desc>
<p>Sets the trace token for the calling process to <c><anno>Token</anno></c>.
@@ -71,7 +71,7 @@ seq_trace:set_token(OldToken), % activate the trace token again
</desc>
</func>
<func>
- <name name="set_token" arity="2"/>
+ <name name="set_token" arity="2" since=""/>
<fsummary>Set a component of the trace token</fsummary>
<type name="component"/>
<type name="flag"/>
@@ -80,13 +80,18 @@ seq_trace:set_token(OldToken), % activate the trace token again
<p>Sets the individual <c><anno>Component</anno></c> of the trace token to
<c><anno>Val</anno></c>. Returns the previous value of the component.</p>
<taglist>
- <tag><c>set_token(label, <anno>Integer</anno>)</c></tag>
+ <tag><c>set_token(label, <anno>Label</anno>)</c></tag>
<item>
- <p>The <c>label</c> component is an integer which
+ <p>The <c>label</c> component is a term which
identifies all events belonging to the same sequential
trace. If several sequential traces can be active
simultaneously, <c>label</c> is used to identify
the separate traces. Default is 0.</p>
+ <warning>
+ <p>Labels were restricted to small signed integers (28 bits)
+ prior to OTP 21. The trace token will be silenty dropped if it
+ crosses over to a node that does not support the label.</p>
+ </warning>
</item>
<tag><c>set_token(serial, SerialValue)</c></tag>
<item>
@@ -153,7 +158,7 @@ seq_trace:set_token(OldToken), % activate the trace token again
</desc>
</func>
<func>
- <name name="get_token" arity="0"/>
+ <name name="get_token" arity="0" since=""/>
<fsummary>Return the value of the trace token</fsummary>
<desc>
<p>Returns the value of the trace token for the calling process.
@@ -164,7 +169,7 @@ seq_trace:set_token(OldToken), % activate the trace token again
</desc>
</func>
<func>
- <name name="get_token" arity="1"/>
+ <name name="get_token" arity="1" since=""/>
<fsummary>Return the value of a trace token component</fsummary>
<type name="component"/>
<type name="flag"/>
@@ -177,7 +182,7 @@ seq_trace:set_token(OldToken), % activate the trace token again
</desc>
</func>
<func>
- <name name="print" arity="1"/>
+ <name name="print" arity="1" since=""/>
<fsummary>Put the Erlang term <c>TraceInfo</c>into the sequential trace output</fsummary>
<desc>
<p>Puts the Erlang term <c><anno>TraceInfo</anno></c> into the sequential
@@ -187,7 +192,7 @@ seq_trace:set_token(OldToken), % activate the trace token again
</desc>
</func>
<func>
- <name name="print" arity="2"/>
+ <name name="print" arity="2" since=""/>
<fsummary>Put the Erlang term <c>TraceInfo</c>into the sequential trace output</fsummary>
<desc>
<p>Same as <c>print/1</c> with the additional condition that
@@ -196,7 +201,7 @@ seq_trace:set_token(OldToken), % activate the trace token again
</desc>
</func>
<func>
- <name name="reset_trace" arity="0"/>
+ <name name="reset_trace" arity="0" since=""/>
<fsummary>Stop all sequential tracing on the local node</fsummary>
<desc>
<p>Sets the trace token to empty for all processes on the
@@ -208,7 +213,7 @@ seq_trace:set_token(OldToken), % activate the trace token again
</desc>
</func>
<func>
- <name name="set_system_tracer" arity="1"/>
+ <name name="set_system_tracer" arity="1" since=""/>
<fsummary>Set the system tracer</fsummary>
<type name="tracer"/>
<desc>
@@ -222,7 +227,7 @@ seq_trace:set_token(OldToken), % activate the trace token again
</desc>
</func>
<func>
- <name name="get_system_tracer" arity="0"/>
+ <name name="get_system_tracer" arity="0" since=""/>
<fsummary>Return the pid() or port() of the current system tracer.</fsummary>
<type name="tracer"/>
<desc>
diff --git a/lib/kernel/doc/src/specs.xml b/lib/kernel/doc/src/specs.xml
index 29d52f23bb..b8c25ca53b 100644
--- a/lib/kernel/doc/src/specs.xml
+++ b/lib/kernel/doc/src/specs.xml
@@ -6,6 +6,7 @@
<xi:include href="../specs/specs_disk_log.xml"/>
<xi:include href="../specs/specs_erl_boot_server.xml"/>
<xi:include href="../specs/specs_erl_ddll.xml"/>
+ <xi:include href="../specs/specs_erl_epmd.xml"/>
<xi:include href="../specs/specs_erl_prim_loader_stub.xml"/>
<xi:include href="../specs/specs_erlang_stub.xml"/>
<xi:include href="../specs/specs_error_handler.xml"/>
@@ -20,6 +21,11 @@
<xi:include href="../specs/specs_inet.xml"/>
<xi:include href="../specs/specs_inet_res.xml"/>
<xi:include href="../specs/specs_init_stub.xml"/>
+ <xi:include href="../specs/specs_logger.xml"/>
+ <xi:include href="../specs/specs_logger_filters.xml"/>
+ <xi:include href="../specs/specs_logger_formatter.xml"/>
+ <xi:include href="../specs/specs_logger_std_h.xml"/>
+ <xi:include href="../specs/specs_logger_disk_log_h.xml"/>
<xi:include href="../specs/specs_net_adm.xml"/>
<xi:include href="../specs/specs_net_kernel.xml"/>
<xi:include href="../specs/specs_os.xml"/>
diff --git a/lib/kernel/doc/src/wrap_log_reader.xml b/lib/kernel/doc/src/wrap_log_reader.xml
index 7fb9c1c023..5f37e7ec5f 100644
--- a/lib/kernel/doc/src/wrap_log_reader.xml
+++ b/lib/kernel/doc/src/wrap_log_reader.xml
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>wrap_log_reader.sgml</file>
</header>
- <module>wrap_log_reader</module>
+ <module since="">wrap_log_reader</module>
<modulesummary>A service to read internally formatted wrap disk logs.
</modulesummary>
<description>
@@ -65,8 +65,8 @@
<funcs>
<func>
- <name name="chunk" arity="1"/>
- <name name="chunk" arity="2"/>
+ <name name="chunk" arity="1" since=""/>
+ <name name="chunk" arity="2" since=""/>
<fsummary>Read a chunk of objects written to a wrap log.</fsummary>
<type name="chunk_ret"/>
<desc>
@@ -105,7 +105,7 @@
</func>
<func>
- <name name="close" arity="1"/>
+ <name name="close" arity="1" since=""/>
<fsummary>Close a log.</fsummary>
<desc>
<p>Closes a log file properly.</p>
@@ -113,8 +113,8 @@
</func>
<func>
- <name name="open" arity="1"/>
- <name name="open" arity="2"/>
+ <name name="open" arity="1" since=""/>
+ <name name="open" arity="2" since=""/>
<fsummary>Open a log file.</fsummary>
<type name="open_ret"/>
<desc>
diff --git a/lib/kernel/examples/Makefile b/lib/kernel/examples/Makefile
index 26ec58f571..f86e662838 100644
--- a/lib/kernel/examples/Makefile
+++ b/lib/kernel/examples/Makefile
@@ -45,7 +45,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/kernel-$(KERNEL_VSN)/examples
# Pack and install the complete directory structure from
# here (CWD) and down, for all examples.
-EXAMPLES = uds_dist
+EXAMPLES = uds_dist gen_tcp_dist
release_spec:
$(INSTALL_DIR) "$(RELSYSDIR)"
diff --git a/lib/kernel/examples/gen_tcp_dist/Makefile b/lib/kernel/examples/gen_tcp_dist/Makefile
new file mode 100644
index 0000000000..0c916835ea
--- /dev/null
+++ b/lib/kernel/examples/gen_tcp_dist/Makefile
@@ -0,0 +1,18 @@
+RM=rm -f
+CP=cp
+EBIN=ebin
+ERLC=erlc
+ERLCFLAGS+= -W
+
+MODULES=gen_tcp_dist
+
+TARGET_FILES=$(MODULES:%=$(EBIN)/%.beam)
+
+opt: $(TARGET_FILES)
+
+$(EBIN)/%.beam: src/%.erl
+ $(ERLC) $(ERLCFLAGS) -o$(EBIN) $<
+
+clean:
+ $(RM) $(TARGET_FILES)
+
diff --git a/lib/cosEvent/example/.gitignore b/lib/kernel/examples/gen_tcp_dist/ebin/.gitignore
index e69de29bb2..e69de29bb2 100644
--- a/lib/cosEvent/example/.gitignore
+++ b/lib/kernel/examples/gen_tcp_dist/ebin/.gitignore
diff --git a/lib/kernel/examples/gen_tcp_dist/src/gen_tcp_dist.erl b/lib/kernel/examples/gen_tcp_dist/src/gen_tcp_dist.erl
new file mode 100644
index 0000000000..cda4c470f9
--- /dev/null
+++ b/lib/kernel/examples/gen_tcp_dist/src/gen_tcp_dist.erl
@@ -0,0 +1,788 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(gen_tcp_dist).
+
+%%
+%% This is an example of how to plug in an arbitrary distribution
+%% carrier for Erlang using distribution processes.
+%%
+%% This example uses gen_tcp for transportation of data, but
+%% you can use whatever underlying protocol you want as long
+%% as your implementation reliably delivers data chunks to the
+%% receiving VM in the order they were sent from the sending
+%% VM.
+%%
+%% This code is a rewrite of the lib/kernel/src/inet_tcp_dist.erl
+%% distribution impementation for TCP used by default. That
+%% implementation use distribution ports instead of distribution
+%% processes and is more efficient compared to this implementation.
+%% This since this implementation more or less gets the
+%% distribution processes in between the VM and the ports without
+%% any gain specific gain.
+%%
+
+-export([listen/1, accept/1, accept_connection/5,
+ setup/5, close/1, select/1, is_node_name/1]).
+
+%% Optional
+-export([setopts/2, getopts/2]).
+
+%% internal exports
+
+-export([dist_cntrlr_setup/1, dist_cntrlr_input_setup/3,
+ dist_cntrlr_tick_handler/1]).
+
+-export([accept_loop/2,do_accept/6,do_setup/6]).
+
+-import(error_logger,[error_msg/2]).
+
+-include_lib("kernel/include/net_address.hrl").
+
+-include_lib("kernel/include/dist.hrl").
+-include_lib("kernel/include/dist_util.hrl").
+
+%% ------------------------------------------------------------
+%% Select this protocol based on node name
+%% select(Node) => Bool
+%% ------------------------------------------------------------
+
+select(Node) ->
+ case split_node(atom_to_list(Node), $@, []) of
+ [_, Host] ->
+ case inet:getaddr(Host, inet) of
+ {ok,_} -> true;
+ _ -> false
+ end;
+ _ -> false
+ end.
+
+%% ------------------------------------------------------------
+%% Create the listen socket, i.e. the port that this erlang
+%% node is accessible through.
+%% ------------------------------------------------------------
+
+listen(Name) ->
+ case do_listen([binary, {active, false}, {packet,2}, {reuseaddr, true}]) of
+ {ok, Socket} ->
+ TcpAddress = get_tcp_address(Socket),
+ {_,Port} = TcpAddress#net_address.address,
+ ErlEpmd = net_kernel:epmd_module(),
+ case ErlEpmd:register_node(Name, Port) of
+ {ok, Creation} ->
+ {ok, {Socket, TcpAddress, Creation}};
+ Error ->
+ Error
+ end;
+ Error ->
+ Error
+ end.
+
+do_listen(Options) ->
+ {First,Last} = case application:get_env(kernel,inet_dist_listen_min) of
+ {ok,N} when is_integer(N) ->
+ case application:get_env(kernel,
+ inet_dist_listen_max) of
+ {ok,M} when is_integer(M) ->
+ {N,M};
+ _ ->
+ {N,N}
+ end;
+ _ ->
+ {0,0}
+ end,
+ do_listen(First, Last, listen_options([{backlog,128}|Options])).
+
+do_listen(First,Last,_) when First > Last ->
+ {error,eaddrinuse};
+do_listen(First,Last,Options) ->
+ case gen_tcp:listen(First, Options) of
+ {error, eaddrinuse} ->
+ do_listen(First+1,Last,Options);
+ Other ->
+ Other
+ end.
+
+listen_options(Opts0) ->
+ Opts1 =
+ case application:get_env(kernel, inet_dist_use_interface) of
+ {ok, Ip} ->
+ [{ip, Ip} | Opts0];
+ _ ->
+ Opts0
+ end,
+ case application:get_env(kernel, inet_dist_listen_options) of
+ {ok,ListenOpts} ->
+ ListenOpts ++ Opts1;
+ _ ->
+ Opts1
+ end.
+
+
+%% ------------------------------------------------------------
+%% Accepts new connection attempts from other Erlang nodes.
+%% ------------------------------------------------------------
+
+accept(Listen) ->
+ spawn_opt(?MODULE, accept_loop, [self(), Listen], [link, {priority, max}]).
+
+accept_loop(Kernel, Listen) ->
+ ?trace("~p~n",[{?MODULE, accept_loop, self()}]),
+ case gen_tcp:accept(Listen) of
+ {ok, Socket} ->
+ DistCtrl = spawn_dist_cntrlr(Socket),
+ ?trace("~p~n",[{?MODULE, accept_loop, accepted, Socket, DistCtrl, self()}]),
+ flush_controller(DistCtrl, Socket),
+ gen_tcp:controlling_process(Socket, DistCtrl),
+ flush_controller(DistCtrl, Socket),
+ Kernel ! {accept,self(),DistCtrl,inet,tcp},
+ receive
+ {Kernel, controller, Pid} ->
+ call_ctrlr(DistCtrl, {supervisor, Pid}),
+ Pid ! {self(), controller};
+ {Kernel, unsupported_protocol} ->
+ exit(unsupported_protocol)
+ end,
+ accept_loop(Kernel, Listen);
+ Error ->
+ exit(Error)
+ end.
+
+flush_controller(Pid, Socket) ->
+ receive
+ {tcp, Socket, Data} ->
+ Pid ! {tcp, Socket, Data},
+ flush_controller(Pid, Socket);
+ {tcp_closed, Socket} ->
+ Pid ! {tcp_closed, Socket},
+ flush_controller(Pid, Socket)
+ after 0 ->
+ ok
+ end.
+
+%% ------------------------------------------------------------
+%% Accepts a new connection attempt from another Erlang node.
+%% Performs the handshake with the other side.
+%% ------------------------------------------------------------
+
+accept_connection(AcceptPid, DistCtrl, MyNode, Allowed, SetupTime) ->
+ spawn_opt(?MODULE, do_accept,
+ [self(), AcceptPid, DistCtrl, MyNode, Allowed, SetupTime],
+ [link, {priority, max}]).
+
+do_accept(Kernel, AcceptPid, DistCtrl, MyNode, Allowed, SetupTime) ->
+ ?trace("~p~n",[{?MODULE, do_accept, self(), MyNode}]),
+ receive
+ {AcceptPid, controller} ->
+ Timer = dist_util:start_timer(SetupTime),
+ case check_ip(DistCtrl) of
+ true ->
+ HSData0 = hs_data_common(DistCtrl),
+ HSData = HSData0#hs_data{kernel_pid = Kernel,
+ this_node = MyNode,
+ socket = DistCtrl,
+ timer = Timer,
+ this_flags = 0,
+ allowed = Allowed},
+ dist_util:handshake_other_started(HSData);
+ {false,IP} ->
+ error_msg("** Connection attempt from "
+ "disallowed IP ~w ** ~n", [IP]),
+ ?shutdown(no_node)
+ end
+ end.
+
+%% we may not always want the nodelay behaviour
+%% for performance reasons
+
+nodelay() ->
+ case application:get_env(kernel, dist_nodelay) of
+ undefined ->
+ {nodelay, true};
+ {ok, true} ->
+ {nodelay, true};
+ {ok, false} ->
+ {nodelay, false};
+ _ ->
+ {nodelay, true}
+ end.
+
+%% ------------------------------------------------------------
+%% Setup a new connection to another Erlang node.
+%% Performs the handshake with the other side.
+%% ------------------------------------------------------------
+
+setup(Node, Type, MyNode, LongOrShortNames,SetupTime) ->
+ spawn_opt(?MODULE, do_setup,
+ [self(), Node, Type, MyNode, LongOrShortNames, SetupTime],
+ [link, {priority, max}]).
+
+do_setup(Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) ->
+ ?trace("~p~n",[{?MODULE, do_setup, self(), Node}]),
+ [Name, Address] = splitnode(Node, LongOrShortNames),
+ case inet:getaddr(Address, inet) of
+ {ok, Ip} ->
+ Timer = dist_util:start_timer(SetupTime),
+ ErlEpmd = net_kernel:epmd_module(),
+ case ErlEpmd:port_please(Name, Ip) of
+ {port, TcpPort, Version} ->
+ ?trace("port_please(~p) -> version ~p~n",
+ [Node,Version]),
+ dist_util:reset_timer(Timer),
+ case
+ gen_tcp:connect(
+ Ip, TcpPort,
+ connect_options([binary, {active, false}, {packet, 2}]))
+ of
+ {ok, Socket} ->
+ DistCtrl = spawn_dist_cntrlr(Socket),
+ call_ctrlr(DistCtrl, {supervisor, self()}),
+ flush_controller(DistCtrl, Socket),
+ gen_tcp:controlling_process(Socket, DistCtrl),
+ flush_controller(DistCtrl, Socket),
+ HSData0 = hs_data_common(DistCtrl),
+ HSData = HSData0#hs_data{kernel_pid = Kernel,
+ other_node = Node,
+ this_node = MyNode,
+ socket = DistCtrl,
+ timer = Timer,
+ this_flags = 0,
+ other_version = Version,
+ request_type = Type},
+ dist_util:handshake_we_started(HSData);
+ _ ->
+ %% Other Node may have closed since
+ %% port_please !
+ ?trace("other node (~p) "
+ "closed since port_please.~n",
+ [Node]),
+ ?shutdown(Node)
+ end;
+ _ ->
+ ?trace("port_please (~p) "
+ "failed.~n", [Node]),
+ ?shutdown(Node)
+ end;
+ _Other ->
+ ?trace("inet_getaddr(~p) "
+ "failed (~p).~n", [Node,_Other]),
+ ?shutdown(Node)
+ end.
+
+connect_options(Opts) ->
+ case application:get_env(kernel, inet_dist_connect_options) of
+ {ok,ConnectOpts} ->
+ ConnectOpts ++ Opts;
+ _ ->
+ Opts
+ end.
+
+%%
+%% Close a socket.
+%%
+close(Listen) ->
+ gen_tcp:close(Listen).
+
+
+%% If Node is illegal terminate the connection setup!!
+splitnode(Node, LongOrShortNames) ->
+ case split_node(atom_to_list(Node), $@, []) of
+ [Name|Tail] when Tail =/= [] ->
+ Host = lists:append(Tail),
+ case split_node(Host, $., []) of
+ [_] when LongOrShortNames =:= longnames ->
+ case inet:parse_address(Host) of
+ {ok, _} ->
+ [Name, Host];
+ _ ->
+ error_msg("** System running to use "
+ "fully qualified "
+ "hostnames **~n"
+ "** Hostname ~ts is illegal **~n",
+ [Host]),
+ ?shutdown(Node)
+ end;
+ L when length(L) > 1, LongOrShortNames =:= shortnames ->
+ error_msg("** System NOT running to use fully qualified "
+ "hostnames **~n"
+ "** Hostname ~ts is illegal **~n",
+ [Host]),
+ ?shutdown(Node);
+ _ ->
+ [Name, Host]
+ end;
+ [_] ->
+ error_msg("** Nodename ~p illegal, no '@' character **~n",
+ [Node]),
+ ?shutdown(Node);
+ _ ->
+ error_msg("** Nodename ~p illegal **~n", [Node]),
+ ?shutdown(Node)
+ end.
+
+split_node([Chr|T], Chr, Ack) -> [lists:reverse(Ack)|split_node(T, Chr, [])];
+split_node([H|T], Chr, Ack) -> split_node(T, Chr, [H|Ack]);
+split_node([], _, Ack) -> [lists:reverse(Ack)].
+
+%% ------------------------------------------------------------
+%% Fetch local information about a Socket.
+%% ------------------------------------------------------------
+get_tcp_address(Socket) ->
+ {ok, Address} = inet:sockname(Socket),
+ {ok, Host} = inet:gethostname(),
+ #net_address {
+ address = Address,
+ host = Host,
+ protocol = tcp,
+ family = inet
+ }.
+
+%% ------------------------------------------------------------
+%% Do only accept new connection attempts from nodes at our
+%% own LAN, if the check_ip environment parameter is true.
+%% ------------------------------------------------------------
+check_ip(DistCtrl) ->
+ case application:get_env(check_ip) of
+ {ok, true} ->
+ case get_ifs(DistCtrl) of
+ {ok, IFs, IP} ->
+ check_ip(IFs, IP);
+ _ ->
+ ?shutdown(no_node)
+ end;
+ _ ->
+ true
+ end.
+
+get_ifs(DistCtrl) ->
+ Socket = call_ctrlr(DistCtrl, socket),
+ case inet:peername(Socket) of
+ {ok, {IP, _}} ->
+ case inet:getif(Socket) of
+ {ok, IFs} -> {ok, IFs, IP};
+ Error -> Error
+ end;
+ Error ->
+ Error
+ end.
+
+check_ip([{OwnIP, _, Netmask}|IFs], PeerIP) ->
+ case {inet_tcp:mask(Netmask, PeerIP), inet_tcp:mask(Netmask, OwnIP)} of
+ {M, M} -> true;
+ _ -> check_ip(IFs, PeerIP)
+ end;
+check_ip([], PeerIP) ->
+ {false, PeerIP}.
+
+is_node_name(Node) when is_atom(Node) ->
+ case split_node(atom_to_list(Node), $@, []) of
+ [_, _Host] -> true;
+ _ -> false
+ end;
+is_node_name(_Node) ->
+ false.
+
+hs_data_common(DistCtrl) ->
+ TickHandler = call_ctrlr(DistCtrl, tick_handler),
+ Socket = call_ctrlr(DistCtrl, socket),
+ #hs_data{f_send = send_fun(),
+ f_recv = recv_fun(),
+ f_setopts_pre_nodeup = setopts_pre_nodeup_fun(),
+ f_setopts_post_nodeup = setopts_post_nodeup_fun(),
+ f_getll = getll_fun(),
+ f_handshake_complete = handshake_complete_fun(),
+ f_address = address_fun(),
+ mf_setopts = setopts_fun(DistCtrl, Socket),
+ mf_getopts = getopts_fun(DistCtrl, Socket),
+ mf_getstat = getstat_fun(DistCtrl, Socket),
+ mf_tick = tick_fun(DistCtrl, TickHandler)}.
+
+%%% ------------------------------------------------------------
+%%% Distribution controller processes
+%%% ------------------------------------------------------------
+
+%%
+%% There will be five parties working together when the
+%% connection is up:
+%% - The gen_tcp socket. Providing a tcp/ip connection
+%% to the other node.
+%% - The output handler. It will dispatch all outgoing
+%% traffic from the VM to the gen_tcp socket. This
+%% process is registered as distribution controller
+%% for this channel with the VM.
+%% - The input handler. It will dispatch all incoming
+%% traffic from the gen_tcp socket to the VM. This
+%% process is also the socket owner and receives
+%% incoming traffic using active-N.
+%% - The tick handler. Dispatches asynchronous tick
+%% requests to the socket. It executes on max priority
+%% since it is important to get ticks through to the
+%% other end.
+%% - The channel supervisor (provided by dist_util). It
+%% monitors traffic. Issue tick requests to the tick
+%% handler when no outgoing traffic is seen and bring
+%% the connection down if no incoming traffic is seen.
+%% This process also executes on max priority.
+%%
+%% These parties are linked togheter so should one
+%% of them fail, all of them are terminated and the
+%% connection is taken down.
+%%
+
+%% In order to avoid issues with lingering signal binaries
+%% we enable off-heap message queue data as well as fullsweep
+%% after 0. The fullsweeps will be cheap since we have more
+%% or less no live data.
+-define(DIST_CNTRL_COMMON_SPAWN_OPTS,
+ [{message_queue_data, off_heap},
+ {fullsweep_after, 0}]).
+
+tick_fun(DistCtrl, TickHandler) ->
+ fun (Ctrl) when Ctrl == DistCtrl ->
+ TickHandler ! tick
+ end.
+
+getstat_fun(DistCtrl, Socket) ->
+ fun (Ctrl) when Ctrl == DistCtrl ->
+ case inet:getstat(Socket, [recv_cnt, send_cnt, send_pend]) of
+ {ok, Stat} ->
+ split_stat(Stat,0,0,0);
+ Error ->
+ Error
+ end
+ end.
+
+split_stat([{recv_cnt, R}|Stat], _, W, P) ->
+ split_stat(Stat, R, W, P);
+split_stat([{send_cnt, W}|Stat], R, _, P) ->
+ split_stat(Stat, R, W, P);
+split_stat([{send_pend, P}|Stat], R, W, _) ->
+ split_stat(Stat, R, W, P);
+split_stat([], R, W, P) ->
+ {ok, R, W, P}.
+
+setopts_fun(DistCtrl, Socket) ->
+ fun (Ctrl, Opts) when Ctrl == DistCtrl ->
+ setopts(Socket, Opts)
+ end.
+
+getopts_fun(DistCtrl, Socket) ->
+ fun (Ctrl, Opts) when Ctrl == DistCtrl ->
+ getopts(Socket, Opts)
+ end.
+
+setopts(S, Opts) ->
+ case [Opt || {K,_}=Opt <- Opts,
+ K =:= active orelse K =:= deliver orelse K =:= packet] of
+ [] -> inet:setopts(S,Opts);
+ Opts1 -> {error, {badopts,Opts1}}
+ end.
+
+getopts(S, Opts) ->
+ inet:getopts(S, Opts).
+
+send_fun() ->
+ fun (Ctrlr, Packet) ->
+ call_ctrlr(Ctrlr, {send, Packet})
+ end.
+
+recv_fun() ->
+ fun (Ctrlr, Length, Timeout) ->
+ case call_ctrlr(Ctrlr, {recv, Length, Timeout}) of
+ {ok, Bin} when is_binary(Bin) ->
+ {ok, binary_to_list(Bin)};
+ Other ->
+ Other
+ end
+ end.
+
+getll_fun() ->
+ fun (Ctrlr) ->
+ call_ctrlr(Ctrlr, getll)
+ end.
+
+address_fun() ->
+ fun (Ctrlr, Node) ->
+ case call_ctrlr(Ctrlr, {address, Node}) of
+ {error, no_node} -> %% No '@' or more than one '@' in node name.
+ ?shutdown(no_node);
+ Res ->
+ Res
+ end
+ end.
+
+setopts_pre_nodeup_fun() ->
+ fun (Ctrlr) ->
+ call_ctrlr(Ctrlr, pre_nodeup)
+ end.
+
+setopts_post_nodeup_fun() ->
+ fun (Ctrlr) ->
+ call_ctrlr(Ctrlr, post_nodeup)
+ end.
+
+handshake_complete_fun() ->
+ fun (Ctrlr, Node, DHandle) ->
+ call_ctrlr(Ctrlr, {handshake_complete, Node, DHandle})
+ end.
+
+call_ctrlr(Ctrlr, Msg) ->
+ Ref = erlang:monitor(process, Ctrlr),
+ Ctrlr ! {Ref, self(), Msg},
+ receive
+ {Ref, Res} ->
+ erlang:demonitor(Ref, [flush]),
+ Res;
+ {'DOWN', Ref, process, Ctrlr, Reason} ->
+ exit({dist_controller_exit, Reason})
+ end.
+
+%%
+%% The tick handler process writes a tick to the
+%% socket when it receives a 'tick' message from
+%% the connection supervisor.
+%%
+%% We are not allowed to block the connection
+%% superviser when writing a tick and we also want
+%% the tick to go through even during a heavily
+%% loaded system. gen_tcp does not have a
+%% non-blocking send operation exposed in its API
+%% and we don't want to run the distribution
+%% controller under high priority. Therefore this
+%% sparate process with max prio that dispatches
+%% ticks.
+%%
+dist_cntrlr_tick_handler(Socket) ->
+ receive
+ tick ->
+ %% May block due to busy port...
+ sock_send(Socket, "");
+ _ ->
+ ok
+ end,
+ dist_cntrlr_tick_handler(Socket).
+
+spawn_dist_cntrlr(Socket) ->
+ spawn_opt(?MODULE, dist_cntrlr_setup, [Socket],
+ [{priority, max}] ++ ?DIST_CNTRL_COMMON_SPAWN_OPTS).
+
+dist_cntrlr_setup(Socket) ->
+ TickHandler = spawn_opt(?MODULE, dist_cntrlr_tick_handler,
+ [Socket],
+ [link, {priority, max}]
+ ++ ?DIST_CNTRL_COMMON_SPAWN_OPTS),
+ dist_cntrlr_setup_loop(Socket, TickHandler, undefined).
+
+%%
+%% During the handshake phase we loop in dist_cntrlr_setup().
+%% When the connection is up we spawn an input handler and
+%% continue as output handler.
+%%
+dist_cntrlr_setup_loop(Socket, TickHandler, Sup) ->
+ receive
+ {tcp_closed, Socket} ->
+ exit(connection_closed);
+
+ {Ref, From, {supervisor, Pid}} ->
+ Res = link(Pid),
+ From ! {Ref, Res},
+ dist_cntrlr_setup_loop(Socket, TickHandler, Pid);
+
+ {Ref, From, tick_handler} ->
+ From ! {Ref, TickHandler},
+ dist_cntrlr_setup_loop(Socket, TickHandler, Sup);
+
+ {Ref, From, socket} ->
+ From ! {Ref, Socket},
+ dist_cntrlr_setup_loop(Socket, TickHandler, Sup);
+
+ {Ref, From, {send, Packet}} ->
+ Res = gen_tcp:send(Socket, Packet),
+ From ! {Ref, Res},
+ dist_cntrlr_setup_loop(Socket, TickHandler, Sup);
+
+ {Ref, From, {recv, Length, Timeout}} ->
+ Res = gen_tcp:recv(Socket, Length, Timeout),
+ From ! {Ref, Res},
+ dist_cntrlr_setup_loop(Socket, TickHandler, Sup);
+
+ {Ref, From, getll} ->
+ From ! {Ref, {ok, self()}},
+ dist_cntrlr_setup_loop(Socket, TickHandler, Sup);
+
+ {Ref, From, {address, Node}} ->
+ Res = case inet:peername(Socket) of
+ {ok, Address} ->
+ case split_node(atom_to_list(Node), $@, []) of
+ [_,Host] ->
+ #net_address{address=Address,host=Host,
+ protocol=tcp, family=inet};
+ _ ->
+ {error, no_node}
+ end
+ end,
+ From ! {Ref, Res},
+ dist_cntrlr_setup_loop(Socket, TickHandler, Sup);
+
+ {Ref, From, pre_nodeup} ->
+ Res = inet:setopts(Socket,
+ [{active, false},
+ {packet, 4},
+ nodelay()]),
+ From ! {Ref, Res},
+ dist_cntrlr_setup_loop(Socket, TickHandler, Sup);
+
+ {Ref, From, post_nodeup} ->
+ Res = inet:setopts(Socket,
+ [{active, false},
+ {packet, 4},
+ nodelay()]),
+ From ! {Ref, Res},
+ dist_cntrlr_setup_loop(Socket, TickHandler, Sup);
+
+ {Ref, From, {handshake_complete, _Node, DHandle}} ->
+ From ! {Ref, ok},
+ %% Handshake complete! Begin dispatching traffic...
+
+ %% We use separate process for dispatching input. This
+ %% is not necessary, but it enables parallel execution
+ %% of independent work loads at the same time as it
+ %% simplifies the the implementation...
+ InputHandler = spawn_opt(?MODULE, dist_cntrlr_input_setup,
+ [DHandle, Socket, Sup],
+ [link] ++ ?DIST_CNTRL_COMMON_SPAWN_OPTS),
+
+ flush_controller(InputHandler, Socket),
+ gen_tcp:controlling_process(Socket, InputHandler),
+ flush_controller(InputHandler, Socket),
+
+ ok = erlang:dist_ctrl_input_handler(DHandle, InputHandler),
+
+ InputHandler ! DHandle,
+
+ %% From now on we execute on normal priority
+ process_flag(priority, normal),
+ erlang:dist_ctrl_get_data_notification(DHandle),
+ case init:get_argument(gen_tcp_dist_output_loop) of
+ error ->
+ dist_cntrlr_output_loop(DHandle, Socket);
+ {ok, [[ModStr, FuncStr]]} -> % For testing...
+ apply(list_to_atom(ModStr),
+ list_to_atom(FuncStr),
+ [DHandle, Socket])
+ end
+ end.
+
+%% We use active 10 for good throughput while still
+%% maintaining back-pressure if the input controller
+%% isn't able to handle all incoming messages...
+-define(ACTIVE_INPUT, 10).
+
+dist_cntrlr_input_setup(DHandle, Socket, Sup) ->
+ link(Sup),
+ %% Ensure we don't try to put data before registerd
+ %% as input handler...
+ receive
+ DHandle ->
+ dist_cntrlr_input_loop(DHandle, Socket, 0)
+ end.
+
+dist_cntrlr_input_loop(DHandle, Socket, N) when N =< ?ACTIVE_INPUT/2 ->
+ inet:setopts(Socket, [{active, ?ACTIVE_INPUT - N}]),
+ dist_cntrlr_input_loop(DHandle, Socket, ?ACTIVE_INPUT);
+dist_cntrlr_input_loop(DHandle, Socket, N) ->
+ receive
+ {tcp_closed, Socket} ->
+ %% Connection to remote node terminated...
+ exit(connection_closed);
+
+ {tcp, Socket, Data} ->
+ %% Incoming data from remote node...
+ try erlang:dist_ctrl_put_data(DHandle, Data)
+ catch _ : _ -> death_row()
+ end,
+ dist_cntrlr_input_loop(DHandle, Socket, N-1);
+
+ _ ->
+ %% Ignore...
+ dist_cntrlr_input_loop(DHandle, Socket, N)
+ end.
+
+dist_cntrlr_send_data(DHandle, Socket) ->
+ case erlang:dist_ctrl_get_data(DHandle) of
+ none ->
+ erlang:dist_ctrl_get_data_notification(DHandle);
+ Data ->
+ sock_send(Socket, Data),
+ dist_cntrlr_send_data(DHandle, Socket)
+ end.
+
+
+dist_cntrlr_output_loop(DHandle, Socket) ->
+ receive
+ dist_data ->
+ %% Outgoing data from this node...
+ try dist_cntrlr_send_data(DHandle, Socket)
+ catch _ : _ -> death_row()
+ end,
+ dist_cntrlr_output_loop(DHandle, Socket);
+
+ {send, From, Ref, Data} ->
+ %% This is for testing only!
+ %%
+ %% Needed by some OTP distribution
+ %% test suites...
+ sock_send(Socket, Data),
+ From ! {Ref, ok},
+ dist_cntrlr_output_loop(DHandle, Socket);
+
+ _ ->
+ %% Drop garbage message...
+ dist_cntrlr_output_loop(DHandle, Socket)
+
+ end.
+
+sock_send(Socket, Data) ->
+ try gen_tcp:send(Socket, Data) of
+ ok -> ok;
+ {error, Reason} -> death_row({send_error, Reason})
+ catch
+ Type : Reason -> death_row({send_error, {Type, Reason}})
+ end.
+
+death_row() ->
+ death_row(connection_closed).
+
+death_row(normal) ->
+ %% We do not want to exit with normal
+ %% exit reason since it wont bring down
+ %% linked processes...
+ death_row();
+death_row(Reason) ->
+ %% When the connection is on its way down operations
+ %% begin to fail. We catch the failures and call
+ %% this function waiting for termination. We should
+ %% be terminated by one of our links to the other
+ %% involved parties that began bringing the
+ %% connection down. By waiting for termination we
+ %% avoid altering the exit reason for the connection
+ %% teardown. We however limit the wait to 5 seconds
+ %% and bring down the connection ourselves if not
+ %% terminated...
+ receive after 5000 -> exit(Reason) end.
diff --git a/lib/kernel/include/dist.hrl b/lib/kernel/include/dist.hrl
index d6bccdf474..f06fc328d7 100644
--- a/lib/kernel/include/dist.hrl
+++ b/lib/kernel/include/dist.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -40,3 +40,11 @@
-define(DFLAG_UTF8_ATOMS, 16#10000).
-define(DFLAG_MAP_TAG, 16#20000).
-define(DFLAG_BIG_CREATION, 16#40000).
+-define(DFLAG_SEND_SENDER, 16#80000).
+-define(DFLAG_BIG_SEQTRACE_LABELS, 16#100000).
+%% -define(DFLAG_NO_MAGIC, 16#200000). %% Used internally only
+-define(DFLAG_EXIT_PAYLOAD, 16#400000).
+-define(DFLAG_FRAGMENTS, 16#800000).
+
+%% Also update dflag2str() in ../src/dist_util.erl
+%% when adding flags...
diff --git a/lib/kernel/include/dist_util.hrl b/lib/kernel/include/dist_util.hrl
index e3d2fe0eb6..56f775f060 100644
--- a/lib/kernel/include/dist_util.hrl
+++ b/lib/kernel/include/dist_util.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,9 +29,9 @@
-endif.
-ifdef(dist_trace).
--define(trace(Fmt,Args), io:format("~p ~p:~s",[erlang:timestamp(),node(),lists:flatten(io_lib:format(Fmt, Args))])).
+-define(trace(Fmt,Args), io:format("~p ~p:~s",[erlang:convert_time_unit(erlang:monotonic_time()-erlang:system_info(start_time), native, microsecond),node(),lists:flatten(io_lib:format(Fmt, Args))])).
% Use the one below for config-file (early boot) connection tracing
-%-define(trace(Fmt,Args), erlang:display([erlang:now(),node(),lists:flatten(io_lib:format(Fmt, Args))])).
+%-define(trace(Fmt,Args), erlang:display([erlang:convert_time_unit(erlang:monotonic_time()-erlang:system_info(start_time), native, microsecond),node(),lists:flatten(io_lib:format(Fmt, Args))])).
-define(trace_factor,8).
-else.
-define(trace(Fmt,Args), ok).
@@ -78,7 +78,13 @@
%% New in kernel-5.1 (OTP 19.1):
mf_setopts, %% netkernel:setopts on active connection
- mf_getopts %% netkernel:getopts on active connection
+ mf_getopts, %% netkernel:getopts on active connection
+
+ %% New in kernel-6.0 (OTP 21.0)
+ f_handshake_complete, %% Notify handshake complete
+ add_flags, %% dflags to add
+ reject_flags, %% dflags not to use (not all can be rejected)
+ require_flags %% dflags that are required
}).
diff --git a/lib/kernel/include/logger.hrl b/lib/kernel/include/logger.hrl
new file mode 100644
index 0000000000..b09977e0f2
--- /dev/null
+++ b/lib/kernel/include/logger.hrl
@@ -0,0 +1,53 @@
+-ifndef(LOGGER_HRL).
+-define(LOGGER_HRL,true).
+-define(LOG_EMERGENCY(A),?DO_LOG(emergency,[A])).
+-define(LOG_EMERGENCY(A,B),?DO_LOG(emergency,[A,B])).
+-define(LOG_EMERGENCY(A,B,C),?DO_LOG(emergency,[A,B,C])).
+
+-define(LOG_ALERT(A),?DO_LOG(alert,[A])).
+-define(LOG_ALERT(A,B),?DO_LOG(alert,[A,B])).
+-define(LOG_ALERT(A,B,C),?DO_LOG(alert,[A,B,C])).
+
+-define(LOG_CRITICAL(A),?DO_LOG(critical,[A])).
+-define(LOG_CRITICAL(A,B),?DO_LOG(critical,[A,B])).
+-define(LOG_CRITICAL(A,B,C),?DO_LOG(critical,[A,B,C])).
+
+-define(LOG_ERROR(A),?DO_LOG(error,[A])).
+-define(LOG_ERROR(A,B),?DO_LOG(error,[A,B])).
+-define(LOG_ERROR(A,B,C),?DO_LOG(error,[A,B,C])).
+
+-define(LOG_WARNING(A),?DO_LOG(warning,[A])).
+-define(LOG_WARNING(A,B),?DO_LOG(warning,[A,B])).
+-define(LOG_WARNING(A,B,C),?DO_LOG(warning,[A,B,C])).
+
+-define(LOG_NOTICE(A),?DO_LOG(notice,[A])).
+-define(LOG_NOTICE(A,B),?DO_LOG(notice,[A,B])).
+-define(LOG_NOTICE(A,B,C),?DO_LOG(notice,[A,B,C])).
+
+-define(LOG_INFO(A),?DO_LOG(info,[A])).
+-define(LOG_INFO(A,B),?DO_LOG(info,[A,B])).
+-define(LOG_INFO(A,B,C),?DO_LOG(info,[A,B,C])).
+
+-define(LOG_DEBUG(A),?DO_LOG(debug,[A])).
+-define(LOG_DEBUG(A,B),?DO_LOG(debug,[A,B])).
+-define(LOG_DEBUG(A,B,C),?DO_LOG(debug,[A,B,C])).
+
+-define(LOG(L,A),?DO_LOG(L,[A])).
+-define(LOG(L,A,B),?DO_LOG(L,[A,B])).
+-define(LOG(L,A,B,C),?DO_LOG(L,[A,B,C])).
+
+-define(LOCATION,#{mfa=>{?MODULE,?FUNCTION_NAME,?FUNCTION_ARITY},
+ line=>?LINE,
+ file=>?FILE}).
+
+%%%-----------------------------------------------------------------
+%%% Internal, i.e. not intended for direct use in code - use above
+%%% macros instead!
+-define(DO_LOG(Level,Args),
+ case logger:allow(Level,?MODULE) of
+ true ->
+ apply(logger,macro_log,[?LOCATION,Level|Args]);
+ false ->
+ ok
+ end).
+-endif.
diff --git a/lib/kernel/src/Makefile b/lib/kernel/src/Makefile
index 5946620f0f..fcb599859b 100644
--- a/lib/kernel/src/Makefile
+++ b/lib/kernel/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2017. All Rights Reserved.
+# Copyright Ericsson AB 1996-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -106,9 +106,23 @@ MODULES = \
inet_sctp \
kernel \
kernel_config \
+ kernel_refc \
local_udp \
local_tcp \
- net \
+ logger \
+ logger_backend \
+ logger_config \
+ logger_handler_watcher \
+ logger_std_h \
+ logger_disk_log_h \
+ logger_h_common \
+ logger_filters \
+ logger_formatter \
+ logger_olp \
+ logger_proxy \
+ logger_server \
+ logger_simple_h \
+ logger_sup \
net_adm \
net_kernel \
os \
@@ -120,17 +134,25 @@ MODULES = \
user \
user_drv \
user_sup \
+ raw_file_io \
+ raw_file_io_compressed \
+ raw_file_io_inflate \
+ raw_file_io_deflate \
+ raw_file_io_delayed \
+ raw_file_io_list \
+ raw_file_io_raw \
wrap_log_reader
HRL_FILES= ../include/file.hrl ../include/inet.hrl ../include/inet_sctp.hrl \
../include/dist.hrl ../include/dist_util.hrl \
- ../include/net_address.hrl
+ ../include/net_address.hrl ../include/logger.hrl
INTERNAL_HRL_FILES= application_master.hrl disk_log.hrl \
- erl_epmd.hrl hipe_ext_format.hrl \
+ erl_epmd.hrl file_int.hrl hipe_ext_format.hrl \
inet_dns.hrl inet_res.hrl \
inet_boot.hrl inet_config.hrl inet_int.hrl \
- inet_dns_record_adts.hrl
+ inet_dns_record_adts.hrl \
+ logger_internal.hrl logger_olp.hrl logger_h_common.hrl
ERL_FILES= $(MODULES:%=%.erl)
@@ -153,8 +175,10 @@ APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
ifeq ($(NATIVE_LIBS_ENABLED),yes)
ERL_COMPILE_FLAGS += +native
+else
+ERL_COMPILE_FLAGS += -Werror
endif
-ERL_COMPILE_FLAGS += -I../include -Werror
+ERL_COMPILE_FLAGS += -I../include
# ----------------------------------------------------
# Targets
@@ -215,7 +239,7 @@ release_docs_spec:
# Include dependencies -- list below added by Kostis Sagonas
-$(EBIN)/application_controller.beam: application_master.hrl
+$(EBIN)/application_controller.beam: application_master.hrl ../include/logger.hrl
$(EBIN)/application_master.beam: application_master.hrl
$(EBIN)/auth.beam: ../include/file.hrl
$(EBIN)/code.beam: ../include/file.hrl
@@ -226,7 +250,9 @@ $(EBIN)/disk_log_server.beam: disk_log.hrl
$(EBIN)/dist_util.beam: ../include/dist_util.hrl ../include/dist.hrl
$(EBIN)/erl_boot_server.beam: inet_boot.hrl
$(EBIN)/erl_epmd.beam: inet_int.hrl erl_epmd.hrl
-$(EBIN)/file.beam: ../include/file.hrl
+$(EBIN)/error_logger.beam: logger_internal.hrl ../include/logger.hrl
+$(EBIN)/file.beam: ../include/file.hrl file_int.hrl
+$(EBIN)/file_io_server.beam: ../include/file.hrl file_int.hrl
$(EBIN)/gen_tcp.beam: inet_int.hrl
$(EBIN)/gen_udp.beam: inet_int.hrl
$(EBIN)/gen_sctp.beam: ../include/inet_sctp.hrl
@@ -250,7 +276,26 @@ $(EBIN)/inet_udp.beam: inet_int.hrl
$(EBIN)/inet_sctp.beam: inet_int.hrl ../include/inet_sctp.hrl
$(EBIN)/local_udp.beam: inet_int.hrl
$(EBIN)/local_tcp.beam: inet_int.hrl
+$(EBIN)/logger.beam: logger_internal.hrl ../include/logger.hrl
+$(EBIN)/logger_backend.beam: logger_internal.hrl ../include/logger.hrl
+$(EBIN)/logger_config.beam: logger_internal.hrl ../include/logger.hrl
+$(EBIN)/logger_disk_log_h.beam: logger_h_common.hrl logger_internal.hrl ../include/logger.hrl ../include/file.hrl
+$(EBIN)/logger_filters.beam: logger_internal.hrl ../include/logger.hrl
+$(EBIN)/logger_formatter.beam: logger_internal.hrl ../include/logger.hrl
+$(EBIN)/logger_olp.beam: logger_olp.hrl logger_internal.hrl
+$(EBIN)/logger_proxy.beam: logger_internal.hrl
+$(EBIN)/logger_server.beam: logger_internal.hrl ../include/logger.hrl
+$(EBIN)/logger_simple_h.beam: logger_internal.hrl ../include/logger.hrl
+$(EBIN)/logger_std_h.beam: logger_h_common.hrl logger_internal.hrl ../include/logger.hrl ../include/file.hrl
+$(EBIN)/logger_h_common.beam: logger_h_common.hrl logger_internal.hrl ../include/logger.hrl
$(EBIN)/net_kernel.beam: ../include/net_address.hrl
$(EBIN)/os.beam: ../include/file.hrl
$(EBIN)/ram_file.beam: ../include/file.hrl
$(EBIN)/wrap_log_reader.beam: disk_log.hrl ../include/file.hrl
+$(EBIN)/raw_file_io.beam: ../include/file.hrl file_int.hrl
+$(EBIN)/raw_file_io_compressed.beam: ../include/file.hrl file_int.hrl
+$(EBIN)/raw_file_io_inflate.beam: ../include/file.hrl file_int.hrl
+$(EBIN)/raw_file_io_deflate.beam: ../include/file.hrl file_int.hrl
+$(EBIN)/raw_file_io_delayed.beam: ../include/file.hrl file_int.hrl
+$(EBIN)/raw_file_io_list.beam: ../include/file.hrl file_int.hrl
+$(EBIN)/raw_file_io_raw.beam: ../include/file.hrl file_int.hrl
diff --git a/lib/kernel/src/application.erl b/lib/kernel/src/application.erl
index bc6be2f8f5..5c2e981e4b 100644
--- a/lib/kernel/src/application.erl
+++ b/lib/kernel/src/application.erl
@@ -25,7 +25,7 @@
which_applications/0, which_applications/1,
loaded_applications/0, permit/2]).
-export([ensure_started/1, ensure_started/2]).
--export([set_env/3, set_env/4, unset_env/2, unset_env/3]).
+-export([set_env/1, set_env/2, set_env/3, set_env/4, unset_env/2, unset_env/3]).
-export([get_env/1, get_env/2, get_env/3, get_all_env/0, get_all_env/1]).
-export([get_key/1, get_key/2, get_all_key/0, get_all_key/1]).
-export([get_application/0, get_application/1, info/0]).
@@ -279,6 +279,26 @@ loaded_applications() ->
info() ->
application_controller:info().
+-spec set_env(Config) -> 'ok' when
+ Config :: [{Application, Env}],
+ Application :: atom(),
+ Env :: [{Par :: atom(), Val :: term()}].
+
+set_env(Config) when is_list(Config) ->
+ set_env(Config, []).
+
+-spec set_env(Config, Opts) -> 'ok' when
+ Config :: [{Application, Env}],
+ Application :: atom(),
+ Env :: [{Par :: atom(), Val :: term()}],
+ Opts :: [{timeout, timeout()} | {persistent, boolean()}].
+
+set_env(Config, Opts) when is_list(Config), is_list(Opts) ->
+ case application_controller:set_env(Config, Opts) of
+ ok -> ok;
+ {error, Msg} -> erlang:error({badarg, Msg}, [Config, Opts])
+ end.
+
-spec set_env(Application, Par, Val) -> 'ok' when
Application :: atom(),
Par :: atom(),
diff --git a/lib/kernel/src/application_controller.erl b/lib/kernel/src/application_controller.erl
index 3b642f5873..7715dca7c6 100644
--- a/lib/kernel/src/application_controller.erl
+++ b/lib/kernel/src/application_controller.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,7 +26,7 @@
control_application/1,
change_application_data/2, prep_config_change/0, config_change/1,
which_applications/0, which_applications/1,
- loaded_applications/0, info/0,
+ loaded_applications/0, info/0, set_env/2,
get_pid_env/2, get_env/2, get_pid_all_env/1, get_all_env/1,
get_pid_key/2, get_key/2, get_pid_all_key/1, get_all_key/1,
get_master/1, get_application/1, get_application_module/1,
@@ -44,6 +44,7 @@
keyfind/3, keydelete/3, keyreplace/4]).
-include("application_master.hrl").
+-include("logger.hrl").
-define(AC, ?MODULE). % Name of process
@@ -344,9 +345,6 @@ get_all_env(AppName) ->
map(fun([Key, Val]) -> {Key, Val} end,
ets:match(ac_tab, {{env, AppName, '$1'}, '$2'})).
-
-
-
get_pid_key(Master, Key) ->
case ets:match(ac_tab, {{application_master, '$1'}, Master}) of
[[AppName]] -> get_key(AppName, Key);
@@ -460,6 +458,15 @@ permit_application(ApplName, Flag) ->
{permit_application, ApplName, Flag},
infinity).
+set_env(Config, Opts) ->
+ case check_conf_data(Config) of
+ ok ->
+ Timeout = proplists:get_value(timeout, Opts, 5000),
+ gen_server:call(?AC, {set_env, Config, Opts}, Timeout);
+
+ {error, _} = Error ->
+ Error
+ end.
set_env(AppName, Key, Val) ->
gen_server:call(?AC, {set_env, AppName, Key, Val, []}).
@@ -527,19 +534,15 @@ check_conf_data([]) ->
check_conf_data(ConfData) when is_list(ConfData) ->
[Application | ConfDataRem] = ConfData,
case Application of
- {kernel, List} when is_list(List) ->
- case check_para_kernel(List) of
- ok ->
- check_conf_data(ConfDataRem);
- Error1 ->
- Error1
- end;
{AppName, List} when is_atom(AppName), is_list(List) ->
- case check_para(List, atom_to_list(AppName)) of
- ok ->
- check_conf_data(ConfDataRem);
- Error2 ->
- Error2
+ case lists:keymember(AppName, 1, ConfDataRem) of
+ true ->
+ {error, "duplicate application config: " ++ atom_to_list(AppName)};
+ false ->
+ case check_para(List, AppName) of
+ ok -> check_conf_data(ConfDataRem);
+ Error -> Error
+ end
end;
{AppName, List} when is_list(List) ->
ErrMsg = "application: "
@@ -552,36 +555,39 @@ check_conf_data(ConfData) when is_list(ConfData) ->
++ "; parameters must be a list",
{error, ErrMsg};
Else ->
- ErrMsg = "invalid application name: " ++
- lists:flatten(io_lib:format(" ~tp",[Else])),
+ ErrMsg = "invalid application config: "
+ ++ lists:flatten(io_lib:format("~tp",[Else])),
{error, ErrMsg}
end;
check_conf_data(_ConfData) ->
- {error, 'configuration must be a list ended by <dot><whitespace>'}.
-
+ {error, "configuration must be a list ended by <dot><whitespace>"}.
-%% Special check of distributed parameter for kernel
-check_para_kernel([]) ->
+
+check_para([], _AppName) ->
ok;
-check_para_kernel([{distributed, Apps} | ParaList]) when is_list(Apps) ->
- case check_distributed(Apps) of
- {error, _ErrorMsg} = Error ->
- Error;
- _ ->
- check_para_kernel(ParaList)
+check_para([{Para, Val} | ParaList], AppName) when is_atom(Para) ->
+ case lists:keymember(Para, 1, ParaList) of
+ true ->
+ ErrMsg = "application: " ++ atom_to_list(AppName)
+ ++ "; duplicate parameter: " ++ atom_to_list(Para),
+ {error, ErrMsg};
+ false ->
+ case check_para_value(Para, Val, AppName) of
+ ok -> check_para(ParaList, AppName);
+ {error, _} = Error -> Error
+ end
end;
-check_para_kernel([{distributed, _Apps} | _ParaList]) ->
- {error, "application: kernel; erroneous parameter: distributed"};
-check_para_kernel([{Para, _Val} | ParaList]) when is_atom(Para) ->
- check_para_kernel(ParaList);
-check_para_kernel([{Para, _Val} | _ParaList]) ->
- {error, "application: kernel; invalid parameter: " ++
+check_para([{Para, _Val} | _ParaList], AppName) ->
+ {error, "application: " ++ atom_to_list(AppName) ++ "; invalid parameter name: " ++
lists:flatten(io_lib:format("~tp",[Para]))};
-check_para_kernel(Else) ->
- {error, "application: kernel; invalid parameter list: " ++
+check_para([Else | _ParaList], AppName) ->
+ {error, "application: " ++ atom_to_list(AppName) ++ "; invalid parameter: " ++
lists:flatten(io_lib:format("~tp",[Else]))}.
-
+check_para_value(distributed, Apps, kernel) -> check_distributed(Apps);
+check_para_value(_Para, _Val, _AppName) -> ok.
+
+%% Special check of distributed parameter for kernel
check_distributed([]) ->
ok;
check_distributed([{App, List} | Apps]) when is_atom(App), is_list(List) ->
@@ -594,18 +600,6 @@ check_distributed(_Else) ->
{error, "application: kernel; erroneous parameter: distributed"}.
-check_para([], _AppName) ->
- ok;
-check_para([{Para, _Val} | ParaList], AppName) when is_atom(Para) ->
- check_para(ParaList, AppName);
-check_para([{Para, _Val} | _ParaList], AppName) ->
- {error, "application: " ++ AppName ++ "; invalid parameter: " ++
- lists:flatten(io_lib:format("~tp",[Para]))};
-check_para([Else | _ParaList], AppName) ->
- {error, "application: " ++ AppName ++ "; invalid parameter: " ++
- lists:flatten(io_lib:format("~tp",[Else]))}.
-
-
-type calls() :: 'info' | 'prep_config_change' | 'which_applications'
| {'config_change' | 'control_application' |
'load_application' | 'start_type' | 'stop_application' |
@@ -862,6 +856,16 @@ handle_call(which_applications, _From, S) ->
end, S#state.running),
{reply, Reply, S};
+handle_call({set_env, Config, Opts}, _From, S) ->
+ _ = [add_env(AppName, Env) || {AppName, Env} <- Config],
+
+ case proplists:get_value(persistent, Opts, false) of
+ true ->
+ {reply, ok, S#state{conf_data = merge_env(S#state.conf_data, Config)}};
+ false ->
+ {reply, ok, S}
+ end;
+
handle_call({set_env, AppName, Key, Val, Opts}, _From, S) ->
ets:insert(ac_tab, {{env, AppName, Key}, Val}),
case proplists:get_value(persistent, Opts, false) of
@@ -1271,9 +1275,7 @@ load(S, {ApplData, ApplEnv, IncApps, Descr, Id, Vsn, Apps}) ->
NewEnv = merge_app_env(ApplEnv, ConfEnv),
CmdLineEnv = get_cmd_env(Name),
NewEnv2 = merge_app_env(NewEnv, CmdLineEnv),
- NewEnv3 = keyreplaceadd(included_applications, 1, NewEnv2,
- {included_applications, IncApps}),
- add_env(Name, NewEnv3),
+ add_env(Name, NewEnv2),
Appl = #appl{name = Name, descr = Descr, id = Id, vsn = Vsn,
appl_data = ApplData, inc_apps = IncApps, apps = Apps},
ets:insert(ac_tab, {{loaded, Name}, Appl}),
@@ -1291,7 +1293,7 @@ load(S, {ApplData, ApplEnv, IncApps, Descr, Id, Vsn, Apps}) ->
{ok, NewS}.
unload(AppName, S) ->
- {ok, IncApps} = get_env(AppName, included_applications),
+ {ok, IncApps} = get_key(AppName, included_applications),
del_env(AppName),
ets:delete(ac_tab, {loaded, AppName}),
foldl(fun(App, S1) ->
@@ -1546,9 +1548,8 @@ do_change_apps(Applications, Config, OldAppls) ->
%% Report errors, but do not terminate
%% (backwards compatible behaviour)
lists:foreach(fun({error, {SysFName, Line, Str}}) ->
- Str2 = lists:flatten(io_lib:format("~tp: ~w: ~ts~n",
- [SysFName, Line, Str])),
- error_logger:format(Str2, [])
+ ?LOG_ERROR("~tp: ~w: ~ts~n",[SysFName, Line, Str],
+ #{error_logger=>#{tag=>error}})
end,
Errors),
@@ -1583,13 +1584,9 @@ do_change_appl({ok, {ApplData, Env, IncApps, Descr, Id, Vsn, Apps}},
CmdLineEnv = get_cmd_env(AppName),
NewEnv2 = merge_app_env(NewEnv1, CmdLineEnv),
- %% included_apps is made into an env parameter as well
- NewEnv3 = keyreplaceadd(included_applications, 1, NewEnv2,
- {included_applications, IncApps}),
-
%% Update ets table with new application env
del_env(AppName),
- add_env(AppName, NewEnv3),
+ add_env(AppName, NewEnv2),
OldAppl#appl{appl_data=ApplData,
descr=Descr,
@@ -1631,8 +1628,9 @@ make_term(Str) ->
end.
handle_make_term_error(Mod, Reason, Str) ->
- error_logger:format("application_controller: ~ts: ~ts~n",
- [Mod:format_error(Reason), Str]),
+ ?LOG_ERROR("application_controller: ~ts: ~ts~n",
+ [Mod:format_error(Reason), Str],
+ #{error_logger=>#{tag=>error}}),
throw({error, {bad_environment_value, Str}}).
get_env_i(Name, #state{conf_data = ConfData}) when is_list(ConfData) ->
@@ -1819,8 +1817,9 @@ check_conf() ->
%% Therefore read and merge contents.
if
BFName =:= "sys" ->
+ DName = filename:dirname(FName),
{ok, SysEnv, Errors} =
- check_conf_sys(NewEnv),
+ check_conf_sys(NewEnv, [], [], DName),
%% Report first error, if any, and
%% terminate
@@ -1842,20 +1841,31 @@ check_conf() ->
end.
check_conf_sys(Env) ->
- check_conf_sys(Env, [], []).
+ check_conf_sys(Env, [], [], []).
-check_conf_sys([File|T], SysEnv, Errors) when is_list(File) ->
+check_conf_sys([File|T], SysEnv, Errors, DName) when is_list(File),is_list(DName) ->
BFName = filename:basename(File, ".config"),
FName = filename:join(filename:dirname(File), BFName ++ ".config"),
- case load_file(FName) of
+ LName = case filename:pathtype(FName) of
+ relative when (DName =/= []) ->
+ % Check if relative to sys.config dir otherwise use legacy mode,
+ % i.e relative to cwd.
+ RName = filename:join(DName, FName),
+ case erl_prim_loader:read_file_info(RName) of
+ {ok, _} -> RName ;
+ error -> FName
+ end;
+ _ -> FName
+ end,
+ case load_file(LName) of
{ok, NewEnv} ->
- check_conf_sys(T, merge_env(SysEnv, NewEnv), Errors);
+ check_conf_sys(T, merge_env(SysEnv, NewEnv), Errors, DName);
{error, {Line, _Mod, Str}} ->
- check_conf_sys(T, SysEnv, [{error, {FName, Line, Str}}|Errors])
+ check_conf_sys(T, SysEnv, [{error, {LName, Line, Str}}|Errors], DName)
end;
-check_conf_sys([Tuple|T], SysEnv, Errors) ->
- check_conf_sys(T, merge_env(SysEnv, [Tuple]), Errors);
-check_conf_sys([], SysEnv, Errors) ->
+check_conf_sys([Tuple|T], SysEnv, Errors, DName) ->
+ check_conf_sys(T, merge_env(SysEnv, [Tuple]), Errors, DName);
+check_conf_sys([], SysEnv, Errors, _) ->
{ok, SysEnv, lists:reverse(Errors)}.
load_file(File) ->
@@ -1913,19 +1923,25 @@ config_error() ->
"configuration file must contain ONE list ended by <dot>"}}.
%%-----------------------------------------------------------------
-%% Info messages sent to error_logger
+%% Info messages sent to logger
%%-----------------------------------------------------------------
info_started(Name, Node) ->
- Rep = [{application, Name},
- {started_at, Node}],
- error_logger:info_report(progress, Rep).
+ ?LOG_INFO(#{label=>{application_controller,progress},
+ report=>[{application, Name},
+ {started_at, Node}]},
+ #{domain=>[otp,sasl],
+ report_cb=>fun logger:format_otp_report/1,
+ logger_formatter=>#{title=>"PROGRESS REPORT"},
+ error_logger=>#{tag=>info_report,type=>progress}}).
info_exited(Name, Reason, Type) ->
- Rep = [{application, Name},
- {exited, Reason},
- {type, Type}],
- error_logger:info_report(Rep).
-
+ ?LOG_NOTICE(#{label=>{application_controller,exit},
+ report=>[{application, Name},
+ {exited, Reason},
+ {type, Type}]},
+ #{domain=>[otp],
+ report_cb=>fun logger:format_otp_report/1,
+ error_logger=>#{tag=>info_report,type=>std_info}}).
%%-----------------------------------------------------------------
%% Reply to all processes waiting this application to be started.
@@ -2012,5 +2028,5 @@ to_string(Term) ->
true ->
Term;
false ->
- lists:flatten(io_lib:format("~134217728p", [Term]))
+ lists:flatten(io_lib:format("~0p", [Term]))
end.
diff --git a/lib/kernel/src/application_master.erl b/lib/kernel/src/application_master.erl
index 5da2b0b06c..8697143dfb 100644
--- a/lib/kernel/src/application_master.erl
+++ b/lib/kernel/src/application_master.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -118,6 +118,10 @@ init(Parent, Starter, ApplData, Type) ->
link(Parent),
process_flag(trap_exit, true),
OldGleader = group_leader(),
+ %% We become the group leader, but forward all I/O to OldGleader.
+ %% This is just a way to identify processes that belong to the
+ %% application. Used for example to find ourselves from any
+ %% process, or, reciprocally, to kill them all when we terminate.
group_leader(self(), self()),
%% Insert ourselves as master for the process. This ensures that
%% the processes in the application can use get_env/1 at startup.
diff --git a/lib/kernel/src/auth.erl b/lib/kernel/src/auth.erl
index 40feee6bf0..4d18daf9e4 100644
--- a/lib/kernel/src/auth.erl
+++ b/lib/kernel/src/auth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -107,7 +107,7 @@ get_cookie() ->
get_cookie(_Node) when node() =:= nonode@nohost ->
nocookie;
get_cookie(Node) ->
- gen_server:call(auth, {get_cookie, Node}).
+ gen_server:call(auth, {get_cookie, Node}, infinity).
-spec set_cookie(Cookie :: cookie()) -> 'true'.
@@ -119,12 +119,12 @@ set_cookie(Cookie) ->
set_cookie(_Node, _Cookie) when node() =:= nonode@nohost ->
erlang:error(distribution_not_started);
set_cookie(Node, Cookie) ->
- gen_server:call(auth, {set_cookie, Node, Cookie}).
+ gen_server:call(auth, {set_cookie, Node, Cookie}, infinity).
-spec sync_cookie() -> any().
sync_cookie() ->
- gen_server:call(auth, sync_cookie).
+ gen_server:call(auth, sync_cookie, infinity).
-spec print(Node :: node(), Format :: string(), Args :: [_]) -> 'ok'.
diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl
index 9969021a6c..7faef93609 100644
--- a/lib/kernel/src/code.erl
+++ b/lib/kernel/src/code.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -149,8 +149,11 @@ load_file(Mod) when is_atom(Mod) ->
-spec ensure_loaded(Module) -> {module, Module} | {error, What} when
Module :: module(),
What :: embedded | badfile | nofile | on_load_failure.
-ensure_loaded(Mod) when is_atom(Mod) ->
- call({ensure_loaded,Mod}).
+ensure_loaded(Mod) when is_atom(Mod) ->
+ case erlang:module_loaded(Mod) of
+ true -> {module, Mod};
+ false -> call({ensure_loaded,Mod})
+ end.
%% XXX File as an atom is allowed only for backwards compatibility.
-spec load_abs(Filename) -> load_ret() when
@@ -627,7 +630,7 @@ do_par_recv(N, Good, Bad) ->
call(Req) ->
code_server:call(Req).
--spec start_link() -> {'ok', pid()} | {'error', 'crash'}.
+-spec start_link() -> {'ok', pid()}.
start_link() ->
do_start().
diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl
index f5a890cb95..68e1205301 100644
--- a/lib/kernel/src/code_server.erl
+++ b/lib/kernel/src/code_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1434,14 +1434,26 @@ all_loaded(Db) ->
-spec error_msg(io:format(), [term()]) -> 'ok'.
error_msg(Format, Args) ->
- Msg = {notify,{error, group_leader(), {self(), Format, Args}}},
- error_logger ! Msg,
+ %% This is equal to calling logger:error/3 which we don't want to
+ %% do from code_server. We don't want to call logger:timestamp()
+ %% either.
+ logger ! {log,error,Format,Args,
+ #{pid=>self(),
+ gl=>group_leader(),
+ time=>os:system_time(microsecond),
+ error_logger=>#{tag=>error}}},
ok.
-spec info_msg(io:format(), [term()]) -> 'ok'.
info_msg(Format, Args) ->
- Msg = {notify,{info_msg, group_leader(), {self(), Format, Args}}},
- error_logger ! Msg,
+ %% This is equal to calling logger:info/3 which we don't want to
+ %% do from code_server. We don't want to call logger:timestamp()
+ %% either.
+ logger ! {log,info,Format,Args,
+ #{pid=>self(),
+ gl=>group_leader(),
+ time=>os:system_time(microsecond),
+ error_logger=>#{tag=>info_msg}}},
ok.
objfile_extension() ->
diff --git a/lib/kernel/src/disk_log_1.erl b/lib/kernel/src/disk_log_1.erl
index 93856aa7b3..41ef33c613 100644
--- a/lib/kernel/src/disk_log_1.erl
+++ b/lib/kernel/src/disk_log_1.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -630,7 +630,7 @@ is_head(Bin) when is_binary(Bin) ->
%% Writes MaxB bytes on each file.
%% Creates a file called Name.idx in the Dir. This
%% file contains the last written FileName as one byte, and
-%% follwing that, the sizes of each file (size 0 number of items).
+%% following that, the sizes of each file (size 0 number of items).
%% On startup, this file is read, and the next available
%% filename is used as first log file.
%% Reports can be browsed with Report Browser Tool (rb), or
diff --git a/lib/kernel/src/dist_util.erl b/lib/kernel/src/dist_util.erl
index b3507e5d13..09ed31f10c 100644
--- a/lib/kernel/src/dist_util.erl
+++ b/lib/kernel/src/dist_util.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -27,8 +27,10 @@
%%-compile(export_all).
-export([handshake_we_started/1, handshake_other_started/1,
+ strict_order_flags/0,
start_timer/1, setup_timer/2,
reset_timer/1, cancel_timer/1,
+ is_node_name/1, split_node/1, is_allowed/2,
shutdown/3, shutdown/4]).
-import(error_logger,[error_msg/2]).
@@ -74,22 +76,56 @@
ticked = 0
}).
-remove_flag(Flag, Flags) ->
- case Flags band Flag of
- 0 ->
- Flags;
- _ ->
- Flags - Flag
- end.
+dflag2str(?DFLAG_PUBLISHED) ->
+ "PUBLISHED";
+dflag2str(?DFLAG_ATOM_CACHE) ->
+ "ATOM_CACHE";
+dflag2str(?DFLAG_EXTENDED_REFERENCES) ->
+ "EXTENDED_REFERENCES";
+dflag2str(?DFLAG_DIST_MONITOR) ->
+ "DIST_MONITOR";
+dflag2str(?DFLAG_FUN_TAGS) ->
+ "FUN_TAGS";
+dflag2str(?DFLAG_DIST_MONITOR_NAME) ->
+ "DIST_MONITOR_NAME";
+dflag2str(?DFLAG_HIDDEN_ATOM_CACHE) ->
+ "HIDDEN_ATOM_CACHE";
+dflag2str(?DFLAG_NEW_FUN_TAGS) ->
+ "NEW_FUN_TAGS";
+dflag2str(?DFLAG_EXTENDED_PIDS_PORTS) ->
+ "EXTENDED_PIDS_PORTS";
+dflag2str(?DFLAG_EXPORT_PTR_TAG) ->
+ "EXPORT_PTR_TAG";
+dflag2str(?DFLAG_BIT_BINARIES) ->
+ "BIT_BINARIES";
+dflag2str(?DFLAG_NEW_FLOATS) ->
+ "NEW_FLOATS";
+dflag2str(?DFLAG_UNICODE_IO) ->
+ "UNICODE_IO";
+dflag2str(?DFLAG_DIST_HDR_ATOM_CACHE) ->
+ "DIST_HDR_ATOM_CACHE";
+dflag2str(?DFLAG_SMALL_ATOM_TAGS) ->
+ "SMALL_ATOM_TAGS";
+dflag2str(?DFLAG_UTF8_ATOMS) ->
+ "UTF8_ATOMS";
+dflag2str(?DFLAG_MAP_TAG) ->
+ "MAP_TAG";
+dflag2str(?DFLAG_BIG_CREATION) ->
+ "BIG_CREATION";
+dflag2str(?DFLAG_SEND_SENDER) ->
+ "SEND_SENDER";
+dflag2str(?DFLAG_BIG_SEQTRACE_LABELS) ->
+ "BIG_SEQTRACE_LABELS";
+dflag2str(?DFLAG_EXIT_PAYLOAD) ->
+ "EXIT_PAYLOAD";
+dflag2str(?DFLAG_FRAGMENTS) ->
+ "FRAGMENTS";
+dflag2str(_) ->
+ "UNKNOWN".
+
adjust_flags(ThisFlags, OtherFlags) ->
- case (?DFLAG_PUBLISHED band ThisFlags) band OtherFlags of
- 0 ->
- {remove_flag(?DFLAG_PUBLISHED, ThisFlags),
- remove_flag(?DFLAG_PUBLISHED, OtherFlags)};
- _ ->
- {ThisFlags, OtherFlags}
- end.
+ ThisFlags band OtherFlags.
publish_flag(hidden, _) ->
0;
@@ -101,38 +137,56 @@ publish_flag(_, OtherNode) ->
0
end.
-make_this_flags(RequestType, OtherNode) ->
- publish_flag(RequestType, OtherNode) bor
- %% The parenthesis below makes the compiler generate better code.
- (?DFLAG_EXPORT_PTR_TAG bor
- ?DFLAG_EXTENDED_PIDS_PORTS bor
- ?DFLAG_EXTENDED_REFERENCES bor
- ?DFLAG_DIST_MONITOR bor
- ?DFLAG_FUN_TAGS bor
- ?DFLAG_DIST_MONITOR_NAME bor
- ?DFLAG_HIDDEN_ATOM_CACHE bor
- ?DFLAG_NEW_FUN_TAGS bor
- ?DFLAG_BIT_BINARIES bor
- ?DFLAG_NEW_FLOATS bor
- ?DFLAG_UNICODE_IO bor
- ?DFLAG_DIST_HDR_ATOM_CACHE bor
- ?DFLAG_SMALL_ATOM_TAGS bor
- ?DFLAG_UTF8_ATOMS bor
- ?DFLAG_MAP_TAG bor
- ?DFLAG_BIG_CREATION).
-
-handshake_other_started(#hs_data{request_type=ReqType}=HSData0) ->
+
+%% Sync with dist.c
+-record(erts_dflags, {
+ default, % flags erts prefers
+ mandatory, % flags erts needs
+ addable, % flags local dist implementation is allowed to add
+ rejectable, % flags local dist implementation is allowed to reject
+ strict_order % flags for features needing strict order delivery
+}).
+
+-spec strict_order_flags() -> integer().
+strict_order_flags() ->
+ EDF = erts_internal:get_dflags(),
+ EDF#erts_dflags.strict_order.
+
+make_this_flags(RequestType, AddFlags, RejectFlags, OtherNode,
+ #erts_dflags{}=EDF) ->
+ case RejectFlags band (bnot EDF#erts_dflags.rejectable) of
+ 0 -> ok;
+ Rerror -> exit({"Rejecting non rejectable flags", Rerror})
+ end,
+ case AddFlags band (bnot EDF#erts_dflags.addable) of
+ 0 -> ok;
+ Aerror -> exit({"Adding non addable flags", Aerror})
+ end,
+ Flgs0 = EDF#erts_dflags.default,
+ Flgs1 = Flgs0 bor publish_flag(RequestType, OtherNode),
+ Flgs2 = Flgs1 bor AddFlags,
+ Flgs2 band (bnot RejectFlags).
+
+handshake_other_started(#hs_data{request_type=ReqType,
+ add_flags=AddFlgs0,
+ reject_flags=RejFlgs0,
+ require_flags=ReqFlgs0}=HSData0) ->
+ AddFlgs = convert_flags(AddFlgs0),
+ RejFlgs = convert_flags(RejFlgs0),
+ ReqFlgs = convert_flags(ReqFlgs0),
{PreOtherFlags,Node,Version} = recv_name(HSData0),
- PreThisFlags = make_this_flags(ReqType, Node),
- {ThisFlags, OtherFlags} = adjust_flags(PreThisFlags,
- PreOtherFlags),
- HSData = HSData0#hs_data{this_flags=ThisFlags,
- other_flags=OtherFlags,
+ EDF = erts_internal:get_dflags(),
+ PreThisFlags = make_this_flags(ReqType, AddFlgs, RejFlgs, Node, EDF),
+ ChosenFlags = adjust_flags(PreThisFlags, PreOtherFlags),
+ HSData = HSData0#hs_data{this_flags=ChosenFlags,
+ other_flags=ChosenFlags,
other_version=Version,
other_node=Node,
- other_started=true},
- check_dflags(HSData),
- is_allowed(HSData),
+ other_started=true,
+ add_flags=AddFlgs,
+ reject_flags=RejFlgs,
+ require_flags=ReqFlgs},
+ check_dflags(HSData, EDF),
?debug({"MD5 connection from ~p (V~p)~n",
[Node, HSData#hs_data.other_version]}),
mark_pending(HSData),
@@ -150,38 +204,16 @@ handshake_other_started(OldHsData) when element(1,OldHsData) =:= hs_data ->
%%
-%% check if connecting node is allowed to connect
-%% with allow-node-scheme
-%%
-is_allowed(#hs_data{other_node = Node,
- allowed = Allowed} = HSData) ->
- case lists:member(Node, Allowed) of
- false when Allowed =/= [] ->
- send_status(HSData, not_allowed),
- error_msg("** Connection attempt from "
- "disallowed node ~w ** ~n", [Node]),
- ?shutdown2(Node, {is_allowed, not_allowed});
- _ -> true
- end.
-
-%%
-%% Check that both nodes can handle the same types of extended
-%% node containers. If they can not, abort the connection.
+%% Check mandatory flags...
%%
check_dflags(#hs_data{other_node = Node,
other_flags = OtherFlags,
- other_started = OtherStarted} = HSData) ->
-
- Mandatory = [{?DFLAG_EXTENDED_REFERENCES, "EXTENDED_REFERENCES"},
- {?DFLAG_EXTENDED_PIDS_PORTS, "EXTENDED_PIDS_PORTS"},
- {?DFLAG_UTF8_ATOMS, "UTF8_ATOMS"}],
- Missing = lists:filtermap(fun({Bit, Str}) ->
- case Bit band OtherFlags of
- Bit -> false;
- 0 -> {true, Str}
- end
- end,
- Mandatory),
+ other_started = OtherStarted,
+ require_flags = RequiredFlags} = HSData,
+ #erts_dflags{}=EDF) ->
+
+ Mandatory = (EDF#erts_dflags.mandatory bor RequiredFlags),
+ Missing = check_mandatory(Mandatory, OtherFlags, []),
case Missing of
[] ->
ok;
@@ -201,6 +233,21 @@ check_dflags(#hs_data{other_node = Node,
?shutdown2(Node, {check_dflags_failed, Missing})
end.
+check_mandatory(0, _OtherFlags, Missing) ->
+ Missing;
+check_mandatory(Mandatory, OtherFlags, Missing) ->
+ Left = Mandatory band (Mandatory - 1), % clear lowest set bit
+ DFlag = Mandatory bxor Left, % only lowest set bit
+ NewMissing = case DFlag band OtherFlags of
+ 0 ->
+ %% Mandatory and missing...
+ [dflag2str(DFlag) | Missing];
+ _ ->
+ %% Mandatory and present...
+ Missing
+ end,
+ check_mandatory(Left, OtherFlags, NewMissing).
+
%% No nodedown will be sent if we fail before this process has
%% succeeded to mark the node as pending.
@@ -314,17 +361,27 @@ flush_down() ->
end.
handshake_we_started(#hs_data{request_type=ReqType,
- other_node=Node}=PreHSData) ->
- PreThisFlags = make_this_flags(ReqType, Node),
- HSData = PreHSData#hs_data{this_flags=PreThisFlags},
+ other_node=Node,
+ add_flags=AddFlgs0,
+ reject_flags=RejFlgs0,
+ require_flags=ReqFlgs0}=PreHSData) ->
+ AddFlgs = convert_flags(AddFlgs0),
+ RejFlgs = convert_flags(RejFlgs0),
+ ReqFlgs = convert_flags(ReqFlgs0),
+ EDF = erts_internal:get_dflags(),
+ PreThisFlags = make_this_flags(ReqType, AddFlgs, RejFlgs, Node, EDF),
+ HSData = PreHSData#hs_data{this_flags = PreThisFlags,
+ add_flags = AddFlgs,
+ reject_flags = RejFlgs,
+ require_flags = ReqFlgs},
send_name(HSData),
recv_status(HSData),
{PreOtherFlags,ChallengeA} = recv_challenge(HSData),
- {ThisFlags,OtherFlags} = adjust_flags(PreThisFlags, PreOtherFlags),
- NewHSData = HSData#hs_data{this_flags = ThisFlags,
- other_flags = OtherFlags,
+ ChosenFlags = adjust_flags(PreThisFlags, PreOtherFlags),
+ NewHSData = HSData#hs_data{this_flags = ChosenFlags,
+ other_flags = ChosenFlags,
other_started = false},
- check_dflags(NewHSData),
+ check_dflags(NewHSData, EDF),
MyChallenge = gen_challenge(),
{MyCookie,HisCookie} = get_cookies(Node),
send_challenge_reply(NewHSData,MyChallenge,
@@ -336,15 +393,16 @@ handshake_we_started(#hs_data{request_type=ReqType,
handshake_we_started(OldHsData) when element(1,OldHsData) =:= hs_data ->
handshake_we_started(convert_old_hsdata(OldHsData)).
-convert_old_hsdata({hs_data, KP, ON, TN, S, T, TF, A, OV, OF, OS, FS, FR,
- FS_PRE, FS_POST, FG, FA, MFT, MFG, RT}) ->
- #hs_data{
- kernel_pid = KP, other_node = ON, this_node = TN, socket = S, timer = T,
- this_flags = TF, allowed = A, other_version = OV, other_flags = OF,
- other_started = OS, f_send = FS, f_recv = FR, f_setopts_pre_nodeup = FS_PRE,
- f_setopts_post_nodeup = FS_POST, f_getll = FG, f_address = FA,
- mf_tick = MFT, mf_getstat = MFG, request_type = RT}.
+convert_old_hsdata(OldHsData) ->
+ OHSDL = tuple_to_list(OldHsData),
+ NoMissing = tuple_size(#hs_data{}) - tuple_size(OldHsData),
+ true = NoMissing > 0,
+ list_to_tuple(OHSDL ++ lists:duplicate(NoMissing, undefined)).
+convert_flags(Flags) when is_integer(Flags) ->
+ Flags;
+convert_flags(_Undefined) ->
+ 0.
%% --------------------------------------------------------------
%% The connection has been established.
@@ -359,15 +417,20 @@ connection(#hs_data{other_node = Node,
PType = publish_type(HSData#hs_data.other_flags),
case FPreNodeup(Socket) of
ok ->
- do_setnode(HSData), % Succeeds or exits the process.
+ DHandle = do_setnode(HSData), % Succeeds or exits the process.
Address = FAddress(Socket,Node),
mark_nodeup(HSData,Address),
case FPostNodeup(Socket) of
ok ->
+ case HSData#hs_data.f_handshake_complete of
+ undefined -> ok;
+ HsComplete -> HsComplete(Socket, Node, DHandle)
+ end,
con_loop({HSData#hs_data.kernel_pid,
Node,
Socket,
PType,
+ DHandle,
HSData#hs_data.mf_tick,
HSData#hs_data.mf_getstat,
HSData#hs_data.mf_setopts,
@@ -425,18 +488,16 @@ do_setnode(#hs_data{other_node = Node, socket = Socket,
[Node, Port, {publish_type(Flags),
'(', Flags, ')',
Version}]),
- case (catch
- erlang:setnode(Node, Port,
- {Flags, Version, '', ''})) of
- {'EXIT', {system_limit, _}} ->
+ try
+ erlang:setnode(Node, Port, {Flags, Version, '', ''})
+ catch
+ error:system_limit ->
error_msg("** Distribution system limit reached, "
"no table space left for node ~w ** ~n",
[Node]),
?shutdown(Node);
- {'EXIT', Other} ->
- exit(Other);
- _Else ->
- ok
+ error:Other:Stacktrace ->
+ exit({Other, Stacktrace})
end;
_ ->
error_msg("** Distribution connection error, "
@@ -468,7 +529,13 @@ mark_nodeup(#hs_data{kernel_pid = Kernel,
?shutdown(Node)
end.
-con_loop({Kernel, Node, Socket, Type, MFTick, MFGetstat, MFSetOpts, MFGetOpts}=ConData,
+getstat(DHandle, _Socket, undefined) ->
+ erlang:dist_get_stat(DHandle);
+getstat(_DHandle, Socket, MFGetstat) ->
+ MFGetstat(Socket).
+
+con_loop({Kernel, Node, Socket, Type, DHandle, MFTick, MFGetstat,
+ MFSetOpts, MFGetOpts}=ConData,
Tick) ->
receive
{tcp_closed, Socket} ->
@@ -476,15 +543,15 @@ con_loop({Kernel, Node, Socket, Type, MFTick, MFGetstat, MFSetOpts, MFGetOpts}=C
{Kernel, disconnect} ->
?shutdown2(Node, disconnected);
{Kernel, aux_tick} ->
- case MFGetstat(Socket) of
+ case getstat(DHandle, Socket, MFGetstat) of
{ok, _, _, PendWrite} ->
- send_tick(Socket, PendWrite, MFTick);
+ send_aux_tick(Type, Socket, PendWrite, MFTick);
_ ->
ignore_it
end,
con_loop(ConData, Tick);
{Kernel, tick} ->
- case send_tick(Socket, Tick, Type,
+ case send_tick(DHandle, Socket, Tick, Type,
MFTick, MFGetstat) of
{ok, NewTick} ->
con_loop(ConData, NewTick);
@@ -497,7 +564,7 @@ con_loop({Kernel, Node, Socket, Type, MFTick, MFGetstat, MFSetOpts, MFGetOpts}=C
?shutdown2(Node, send_net_tick_failed)
end;
{From, get_status} ->
- case MFGetstat(Socket) of
+ case getstat(DHandle, Socket, MFGetstat) of
{ok, Read, Write, _} ->
From ! {self(), get_status, {ok, Read, Write}},
con_loop(ConData, Tick);
@@ -564,33 +631,130 @@ send_challenge_ack(#hs_data{socket = Socket, f_send = FSend},
%% tcp_drv.c which used it to detect simultaneous connection
%% attempts).
%%
-recv_name(#hs_data{socket = Socket, f_recv = Recv}) ->
+recv_name(#hs_data{socket = Socket, f_recv = Recv} = HSData) ->
case Recv(Socket, 0, infinity) of
- {ok,Data} ->
- get_name(Data);
+ {ok,
+ [$n,VersionA, VersionB, Flag1, Flag2, Flag3, Flag4
+ | OtherNode] = Data} ->
+ case is_node_name(OtherNode) of
+ true ->
+ Flags = ?u32(Flag1, Flag2, Flag3, Flag4),
+ Version = ?u16(VersionA,VersionB),
+ is_allowed(HSData, Flags, OtherNode, Version);
+ false ->
+ ?shutdown(Data)
+ end;
_ ->
?shutdown(no_node)
end.
-get_name([$n,VersionA, VersionB, Flag1, Flag2, Flag3, Flag4 | OtherNode] = Data) ->
- case is_valid_name(OtherNode) of
+is_node_name(OtherNodeName) ->
+ case string:split(OtherNodeName, "@", all) of
+ [Name,Host] ->
+ (not string:is_empty(Name))
+ andalso (not string:is_empty(Host));
+ _ ->
+ false
+ end.
+
+split_node(Node) ->
+ Split = string:split(listify(Node), "@", all),
+ case Split of
+ [Name,Host] ->
+ case string:is_empty(Name) of
+ true ->
+ Split;
+ false ->
+ case string:is_empty(Host) of
+ true ->
+ {name,Name};
+ false ->
+ {node,Name,Host}
+ end
+ end;
+ [Host] ->
+ case string:is_empty(Host) of
+ true ->
+ Split;
+ false ->
+ {host,Host}
+ end
+ end.
+
+%% Check if connecting node is allowed to connect
+%% with allow-node-scheme. An empty allowed list
+%% allows all nodes.
+%%
+is_allowed(#hs_data{allowed = []}, Flags, Node, Version) ->
+ {Flags,list_to_atom(Node),Version};
+is_allowed(#hs_data{allowed = Allowed} = HSData, Flags, Node, Version) ->
+ case is_allowed(Node, Allowed) of
true ->
- {?u32(Flag1, Flag2, Flag3, Flag4), list_to_atom(OtherNode),
- ?u16(VersionA,VersionB)};
+ {Flags,list_to_atom(Node),Version};
false ->
- ?shutdown(Data)
- end;
-get_name(Data) ->
- ?shutdown(Data).
-
-is_valid_name(OtherNodeName) ->
- case string:lexemes(OtherNodeName,"@") of
- [_OtherNodeName,_OtherNodeHost] ->
- true;
- _else ->
- false
+ send_status(HSData#hs_data{other_node = Node}, not_allowed),
+ error_msg("** Connection attempt from "
+ "disallowed node ~s ** ~n", [Node]),
+ ?shutdown2(Node, {is_allowed, not_allowed})
+ end.
+
+%% The allowed list can contain node names, host names
+%% or names before '@', in atom or list form:
+%% [[email protected], "host.example.org", "node@"].
+%% An empty allowed list allows no nodes.
+%%
+%% Allow a node that matches any entry in the allowed list.
+%% Also allow allowed entries as node to match, not from
+%% this module; here the node has to be a valid name.
+%%
+is_allowed(_Node, []) ->
+ false;
+is_allowed(Node, [Node|_Allowed]) ->
+ %% Just an optimization
+ true;
+is_allowed(Node, [AllowedNode|Allowed]) ->
+ case split_node(AllowedNode) of
+ {node,AllowedName,AllowedHost} ->
+ %% Allowed node name
+ case split_node(Node) of
+ {node,AllowedName,AllowedHost} ->
+ true;
+ _ ->
+ is_allowed(Node, Allowed)
+ end;
+ {host,AllowedHost} ->
+ %% Allowed host name
+ case split_node(Node) of
+ {node,_,AllowedHost} ->
+ %% Matching Host part
+ true;
+ {host,AllowedHost} ->
+ %% Host matches Host
+ true;
+ _ ->
+ is_allowed(Node, Allowed)
+ end;
+ {name,AllowedName} ->
+ %% Allowed name before '@'
+ case split_node(Node) of
+ {node,AllowedName,_} ->
+ %% Matching Name part
+ true;
+ {name,AllowedName} ->
+ %% Name matches Name
+ true;
+ _ ->
+ is_allowed(Node, Allowed)
+ end;
+ _ ->
+ is_allowed(Node, Allowed)
end.
+listify(Atom) when is_atom(Atom) ->
+ atom_to_list(Atom);
+listify(Node) when is_list(Node) ->
+ Node.
+
publish_type(Flags) ->
case Flags band ?DFLAG_PUBLISHED of
0 ->
@@ -731,51 +895,57 @@ send_status(#hs_data{socket = Socket, other_node = Node,
%% The detection time interval is thus, by default, 45s < DT < 75s
-%% A HIDDEN node is always (if not a pending write) ticked if
-%% we haven't read anything as a hidden node only ticks when it receives
-%% a TICK !!
+%% A HIDDEN node is always ticked if we haven't read anything
+%% as a (primitive) hidden node only ticks when it receives a TICK !!
-send_tick(Socket, Tick, Type, MFTick, MFGetstat) ->
+send_tick(DHandle, Socket, Tick, Type, MFTick, MFGetstat) ->
#tick{tick = T0,
read = Read,
write = Write,
- ticked = Ticked} = Tick,
+ ticked = Ticked0} = Tick,
T = T0 + 1,
T1 = T rem 4,
- case MFGetstat(Socket) of
- {ok, Read, _, _} when Ticked =:= T ->
+ case getstat(DHandle, Socket, MFGetstat) of
+ {ok, Read, _, _} when Ticked0 =:= T ->
{error, not_responding};
- {ok, Read, W, Pend} when Type =:= hidden ->
- send_tick(Socket, Pend, MFTick),
- {ok, Tick#tick{write = W + 1,
- tick = T1}};
- {ok, Read, Write, Pend} ->
- send_tick(Socket, Pend, MFTick),
- {ok, Tick#tick{write = Write + 1,
- tick = T1}};
- {ok, R, Write, Pend} ->
- send_tick(Socket, Pend, MFTick),
- {ok, Tick#tick{write = Write + 1,
- read = R,
- tick = T1,
- ticked = T}};
- {ok, Read, W, _} ->
- {ok, Tick#tick{write = W,
- tick = T1}};
- {ok, R, W, _} ->
- {ok, Tick#tick{write = W,
- read = R,
- tick = T1,
- ticked = T}};
+
+ {ok, R, W1, Pend} ->
+ RDiff = R - Read,
+ W2 = case need_to_tick(Type, RDiff, W1-Write, Pend) of
+ true ->
+ MFTick(Socket),
+ W1 + 1;
+ false ->
+ W1
+ end,
+
+ Ticked1 = case RDiff of
+ 0 -> Ticked0;
+ _ -> T
+ end,
+
+ {ok, Tick#tick{write = W2,
+ tick = T1,
+ read = R,
+ ticked = Ticked1}};
+
Error ->
Error
end.
-send_tick(Socket, 0, MFTick) ->
- MFTick(Socket);
-send_tick(_, _Pend, _) ->
- %% Dont send tick if pending write.
- ok.
+need_to_tick(_, _, 0, 0) -> % nothing written and empty send queue
+ true;
+need_to_tick(_, _, 0, false) -> % nothing written and empty send queue
+ true;
+need_to_tick(hidden, 0, _, _) -> % nothing read from hidden
+ true;
+need_to_tick(_, _, _, _) ->
+ false.
+
+send_aux_tick(normal, _, Pend, _) when Pend /= false, Pend /= 0 ->
+ ok; %% Dont send tick if pending write.
+send_aux_tick(_Type, Socket, _Pend, MFTick) ->
+ MFTick(Socket).
%% ------------------------------------------------------------
%% Connection setup timeout timer.
diff --git a/lib/kernel/src/erl_boot_server.erl b/lib/kernel/src/erl_boot_server.erl
index 2578b74428..4ac945ce01 100644
--- a/lib/kernel/src/erl_boot_server.erl
+++ b/lib/kernel/src/erl_boot_server.erl
@@ -252,9 +252,9 @@ handle_info({udp, U, IP, Port, Data}, S0) ->
"~w is not a valid address ** ~n", [IP]),
{noreply,S0};
{true,_,_} ->
- case catch string:substr(Data, 1, length(?EBOOT_REQUEST)) of
+ case catch string:slice(Data, 0, length(?EBOOT_REQUEST)) of
?EBOOT_REQUEST ->
- Vsn = string:substr(Data, length(?EBOOT_REQUEST)+1, length(Data)),
+ Vsn = string:slice(Data, length(?EBOOT_REQUEST), length(Data)),
error_logger:error_msg("** Illegal boot server connection attempt: "
"client version is ~s ** ~n", [Vsn]);
_ ->
diff --git a/lib/kernel/src/erl_distribution.erl b/lib/kernel/src/erl_distribution.erl
index 0bec78e938..cdb2d2f1f6 100644
--- a/lib/kernel/src/erl_distribution.erl
+++ b/lib/kernel/src/erl_distribution.erl
@@ -21,6 +21,8 @@
-behaviour(supervisor).
+-include_lib("kernel/include/logger.hrl").
+
-export([start_link/0,start_link/2,init/1,start/1,stop/0]).
-define(DBG,erlang:display([?MODULE,?LINE])).
@@ -83,6 +85,10 @@ do_start_link([{Arg,Flag}|T]) ->
case init:get_argument(Arg) of
{ok,[[Name]]} ->
start_link([list_to_atom(Name),Flag|ticktime()], true);
+ {ok,[[Name]|_Rest]} ->
+ ?LOG_WARNING("Multiple -~p given to erl, using the first, ~p",
+ [Arg, Name]),
+ start_link([list_to_atom(Name),Flag|ticktime()], true);
_ ->
do_start_link(T)
end;
diff --git a/lib/kernel/src/erl_epmd.erl b/lib/kernel/src/erl_epmd.erl
index 7bc9e2ede3..7a14e2635c 100644
--- a/lib/kernel/src/erl_epmd.erl
+++ b/lib/kernel/src/erl_epmd.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,10 +29,20 @@
-define(port_please_failure2(Term), noop).
-endif.
+-ifndef(erlang_daemon_port).
+-define(erlang_daemon_port, 4369).
+-endif.
+-ifndef(epmd_dist_high).
+-define(epmd_dist_high, 4370).
+-endif.
+-ifndef(epmd_dist_low).
+-define(epmd_dist_low, 4370).
+-endif.
+
%% External exports
-export([start/0, start_link/0, stop/0, port_please/2,
port_please/3, names/0, names/1,
- register_node/2, register_node/3, open/0, open/1, open/2]).
+ register_node/2, register_node/3, address_please/3, open/0, open/1, open/2]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
@@ -53,7 +63,7 @@
start() ->
gen_server:start({local, erl_epmd}, ?MODULE, [], []).
-
+-spec start_link() -> {ok, pid()} | ignore | {error,term()}.
start_link() ->
gen_server:start_link({local, erl_epmd}, ?MODULE, [], []).
@@ -66,9 +76,22 @@ stop() ->
%% return {port, P, Version} | noport
%%
+-spec port_please(Name, Host) -> {ok, Port, Version} | noport when
+ Name :: atom() | string(),
+ Host :: atom() | string() | inet:ip_address(),
+ Port :: non_neg_integer(),
+ Version :: non_neg_integer().
+
port_please(Node, Host) ->
port_please(Node, Host, infinity).
+-spec port_please(Name, Host, Timeout) -> {ok, Port, Version} | noport when
+ Name :: atom() | string(),
+ Host :: atom() | string() | inet:ip_address(),
+ Timeout :: non_neg_integer() | infinity,
+ Port :: non_neg_integer(),
+ Version :: non_neg_integer().
+
port_please(Node,HostName, Timeout) when is_atom(HostName) ->
port_please1(Node,atom_to_list(HostName), Timeout);
port_please(Node,HostName, Timeout) when is_list(HostName) ->
@@ -79,17 +102,34 @@ port_please(Node, EpmdAddr, Timeout) ->
port_please1(Node,HostName, Timeout) ->
- case inet:gethostbyname(HostName, inet, Timeout) of
+ Family = case inet_db:res_option(inet6) of
+ true ->
+ inet6;
+ false ->
+ inet
+ end,
+ case inet:gethostbyname(HostName, Family, Timeout) of
{ok,{hostent, _Name, _ , _Af, _Size, [EpmdAddr | _]}} ->
get_port(Node, EpmdAddr, Timeout);
Else ->
Else
end.
+-spec names() -> {ok, [{Name, Port}]} | {error, Reason} when
+ Name :: string(),
+ Port :: non_neg_integer(),
+ Reason :: address | file:posix().
+
names() ->
{ok, H} = inet:gethostname(),
names(H).
+-spec names(Host) -> {ok, [{Name, Port}]} | {error, Reason} when
+ Host :: atom() | string() | inet:ip_address(),
+ Name :: string(),
+ Port :: non_neg_integer(),
+ Reason :: address | file:posix().
+
names(HostName) when is_atom(HostName); is_list(HostName) ->
case inet:gethostbyname(HostName) of
{ok,{hostent, _Name, _ , _Af, _Size, [EpmdAddr | _]}} ->
@@ -100,9 +140,22 @@ names(HostName) when is_atom(HostName); is_list(HostName) ->
names(EpmdAddr) ->
get_names(EpmdAddr).
+-spec register_node(Name, Port) -> Result when
+ Name :: string(),
+ Port :: non_neg_integer(),
+ Creation :: non_neg_integer(),
+ Result :: {ok, Creation} | {error, already_registered} | term().
register_node(Name, PortNo) ->
- register_node(Name, PortNo, inet).
+ register_node(Name, PortNo, inet).
+
+-spec register_node(Name, Port, Driver) -> Result when
+ Name :: string(),
+ Port :: non_neg_integer(),
+ Driver :: inet_tcp | inet6_tcp | inet | inet6,
+ Creation :: non_neg_integer(),
+ Result :: {ok, Creation} | {error, already_registered} | term().
+
register_node(Name, PortNo, inet_tcp) ->
register_node(Name, PortNo, inet);
register_node(Name, PortNo, inet6_tcp) ->
@@ -110,6 +163,17 @@ register_node(Name, PortNo, inet6_tcp) ->
register_node(Name, PortNo, Family) ->
gen_server:call(erl_epmd, {register, Name, PortNo, Family}, infinity).
+-spec address_please(Name, Host, AddressFamily) -> Success | {error, term()} when
+ Name :: string(),
+ Host :: string() | inet:ip_address(),
+ AddressFamily :: inet | inet6,
+ Port :: non_neg_integer(),
+ Version :: non_neg_integer(),
+ Success :: {ok, inet:ip_address()} | {ok, inet:ip_address(), Port, Version}.
+
+address_please(_Name, Host, AddressFamily) ->
+ inet:getaddr(Host, AddressFamily).
+
%%%----------------------------------------------------------------------
%%% Callback functions from gen_server
%%%----------------------------------------------------------------------
diff --git a/lib/kernel/src/erl_reply.erl b/lib/kernel/src/erl_reply.erl
index e1e046cbb4..e1c4ffe839 100644
--- a/lib/kernel/src/erl_reply.erl
+++ b/lib/kernel/src/erl_reply.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -42,7 +42,7 @@ reply(_) ->
%% convert ip number to tuple
ip_string_to_tuple(Ip) ->
- [Ip1,Ip2,Ip3,Ip4] = string:tokens(Ip,"."),
+ [Ip1,Ip2,Ip3,Ip4] = string:lexemes(Ip,"."),
{list_to_integer(Ip1),
list_to_integer(Ip2),
list_to_integer(Ip3),
diff --git a/lib/kernel/src/erl_signal_handler.erl b/lib/kernel/src/erl_signal_handler.erl
index 22f235d4e4..5be905d8ae 100644
--- a/lib/kernel/src/erl_signal_handler.erl
+++ b/lib/kernel/src/erl_signal_handler.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -19,12 +19,21 @@
-module(erl_signal_handler).
-behaviour(gen_event).
--export([init/1, format_status/2,
+-export([start/0, init/1, format_status/2,
handle_event/2, handle_call/2, handle_info/2,
terminate/2, code_change/3]).
-record(state,{}).
+start() ->
+ %% add signal handler
+ case whereis(erl_signal_server) of
+ %% in case of minimal mode
+ undefined -> ok;
+ _ ->
+ gen_event:add_handler(erl_signal_server, erl_signal_handler, [])
+ end.
+
init(_Args) ->
{ok, #state{}}.
diff --git a/lib/kernel/src/error_handler.erl b/lib/kernel/src/error_handler.erl
index 59ca8e690d..a89ef83261 100644
--- a/lib/kernel/src/error_handler.erl
+++ b/lib/kernel/src/error_handler.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -106,8 +106,8 @@ crash(M, F, A) ->
crash(Tuple) ->
try erlang:error(undef)
catch
- error:undef ->
- Stk = [Tuple|tl(erlang:get_stacktrace())],
+ error:undef:Stacktrace ->
+ Stk = [Tuple|tl(Stacktrace)],
erlang:raise(error, undef, Stk)
end.
diff --git a/lib/kernel/src/error_logger.erl b/lib/kernel/src/error_logger.erl
index 585507c545..e324be5290 100644
--- a/lib/kernel/src/error_logger.erl
+++ b/lib/kernel/src/error_logger.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -19,22 +19,23 @@
%%
-module(error_logger).
--export([start/0,start_link/0,format/2,error_msg/1,error_msg/2,error_report/1,
+-include("logger_internal.hrl").
+
+-export([start/0,start_link/0,stop/0,
+ format/2,error_msg/1,error_msg/2,error_report/1,
error_report/2,info_report/1,info_report/2,warning_report/1,
warning_report/2,error_info/1,
info_msg/1,info_msg/2,warning_msg/1,warning_msg/2,
- logfile/1,tty/1,swap_handler/1,
+ logfile/1,tty/1,
add_report_handler/1,add_report_handler/2,
- delete_report_handler/1]).
+ delete_report_handler/1,
+ which_report_handlers/0]).
--export([init/1,
- handle_event/2, handle_call/2, handle_info/2,
- terminate/2]).
+%% logger callbacks
+-export([adding_handler/1, removing_handler/1, log/2]).
-export([get_format_depth/0, limit_term/1]).
--define(buffer_size, 10).
-
%%-----------------------------------------------------------------
%% Types used in this file
%%-----------------------------------------------------------------
@@ -43,8 +44,6 @@
| 'info' | 'info_msg' | 'info_report'
| 'warning_msg' | 'warning_report'.
--type state() :: {non_neg_integer(), non_neg_integer(), [term()]}.
-
%%% BIF
-export([warning_map/0]).
@@ -59,26 +58,164 @@ warning_map() ->
%%-----------------------------------------------------------------
--spec start() -> {'ok', pid()} | {'error', any()}.
+%%%-----------------------------------------------------------------
+%%% Start the event manager process under logger_sup, which is part of
+%%% the kernel application's supervision tree.
+-spec start() -> 'ok' | {'error', any()}.
start() ->
- case gen_event:start({local, error_logger}) of
- {ok, Pid} ->
- simple_logger(?buffer_size),
- {ok, Pid};
- Error -> Error
+ case whereis(?MODULE) of
+ undefined ->
+ ErrorLogger =
+ #{id => ?MODULE,
+ start => {?MODULE, start_link, []},
+ restart => transient,
+ shutdown => 2000,
+ type => worker,
+ modules => dynamic},
+ case supervisor:start_child(logger_sup, ErrorLogger) of
+ {ok,Pid} ->
+ ok = logger_handler_watcher:register_handler(?MODULE,Pid);
+ Error ->
+ Error
+ end;
+ _ ->
+ ok
end.
+%%%-----------------------------------------------------------------
+%%% Start callback specified in child specification to supervisor, see start/0
-spec start_link() -> {'ok', pid()} | {'error', any()}.
start_link() ->
- case gen_event:start_link({local, error_logger}) of
- {ok, Pid} ->
- simple_logger(?buffer_size),
- {ok, Pid};
- Error -> Error
+ gen_event:start_link({local, ?MODULE},
+ [{spawn_opt,[{message_queue_data, off_heap}]}]).
+
+%%%-----------------------------------------------------------------
+%%% Stop the event manager
+-spec stop() -> ok.
+stop() ->
+ case whereis(?MODULE) of
+ undefined ->
+ ok;
+ _Pid ->
+ _ = gen_event:stop(?MODULE,{shutdown,stopped},infinity),
+ _ = supervisor:delete_child(logger_sup,?MODULE),
+ ok
+ end.
+
+%%%-----------------------------------------------------------------
+%%% Callbacks for logger
+-spec adding_handler(logger:handler_config()) ->
+ {ok,logger:handler_config()} | {error,term()}.
+adding_handler(#{id:=?MODULE}=Config) ->
+ case start() of
+ ok ->
+ {ok,Config};
+ Error ->
+ Error
end.
+-spec removing_handler(logger:handler_config()) -> ok.
+removing_handler(#{id:=?MODULE}) ->
+ stop(),
+ ok.
+
+-spec log(logger:log_event(),logger:handler_config()) -> ok.
+log(#{level:=Level,msg:=Msg,meta:=Meta},_Config) ->
+ do_log(Level,Msg,Meta).
+
+do_log(Level,{report,Msg},#{?MODULE:=#{tag:=Tag,type:=Type}}=Meta) ->
+ %% From error_logger:*_report/1,2, or logger call which added
+ %% error_logger data to obtain backwards compatibility with
+ %% error_logger:*_report/1,2
+ Report =
+ case Msg of
+ #{label:=_,report:=R} -> R;
+ _ -> Msg
+ end,
+ notify(Level,Tag,Type,Report,Meta);
+do_log(Level,{report,Msg},#{?MODULE:=#{tag:=Tag}}=Meta) ->
+ {Format,Args} =
+ case Msg of
+ #{label:=_,format:=F,args:=A} ->
+ %% From error_logger:*_msg/1,2.
+ %% In order to be backwards compatible with handling
+ %% of faulty parameters to error_logger:*_msg/1,2,
+ %% don't use report_cb here.
+ {F,A};
+ _ ->
+ %% From logger call which added error_logger data to
+ %% obtain backwards compatibility with error_logger:*_msg/1,2
+ case maps:get(report_cb,Meta,fun logger:format_report/1) of
+ RCBFun when is_function(RCBFun,1) ->
+ try RCBFun(Msg) of
+ {F,A} when is_list(F), is_list(A) ->
+ {F,A};
+ Other ->
+ {"REPORT_CB ERROR: ~tp; Returned: ~tp",[Msg,Other]}
+ catch C:R ->
+ {"REPORT_CB CRASH: ~tp; Reason: ~tp",[Msg,{C,R}]}
+ end;
+ RCBFun when is_function(RCBFun,2) ->
+ try RCBFun(Msg,#{depth=>get_format_depth(),
+ chars_limit=>unlimited,
+ single_line=>false}) of
+ Chardata when ?IS_STRING(Chardata) ->
+ {"~ts",[Chardata]};
+ Other ->
+ {"REPORT_CB ERROR: ~tp; Returned: ~tp",[Msg,Other]}
+ catch C:R ->
+ {"REPORT_CB CRASH: ~tp; Reason: ~tp",[Msg,{C,R}]}
+ end
+ end
+ end,
+ notify(Level,Tag,Format,Args,Meta);
+do_log(Level,{Format,Args},#{?MODULE:=#{tag:=Tag}}=Meta)
+ when is_list(Format), is_list(Args) ->
+ %% From logger call which added error_logger data to obtain
+ %% backwards compatibility with error_logger:*_msg/1,2
+ notify(Level,Tag,Format,Args,Meta);
+do_log(_Level,_Msg,_Meta) ->
+ %% Ignore the rest - i.e. to get backwards compatibility with
+ %% error_logger, you must use the error_logger API for logging.
+ %% Some modules within OTP go around this by adding an
+ %% error_logger field to its metadata. This is done only to allow
+ %% complete backwards compatibility for log events originating
+ %% from within OTP, while still using the new logger interface.
+ ok.
+
+-spec notify(logger:level(), msg_tag(), any(), any(), map()) -> 'ok'.
+notify(Level,Tag0,FormatOrType0,ArgsOrReport,#{pid:=Pid0,gl:=GL,?MODULE:=My}) ->
+ {Tag,FormatOrType} = maybe_map_warnings(Level,Tag0,FormatOrType0),
+ Pid = case maps:get(emulator,My,false) of
+ true -> emulator;
+ _ -> Pid0
+ end,
+ gen_event:notify(?MODULE,{Tag,GL,{Pid,FormatOrType,ArgsOrReport}}).
+
+%% For backwards compatibility with really old even handlers, check
+%% the warning map and update tag and type.
+maybe_map_warnings(warning,Tag,FormatOrType) ->
+ case error_logger:warning_map() of
+ warning ->
+ {Tag,FormatOrType};
+ Level ->
+ {fix_warning_tag(Level,Tag),fix_warning_type(Level,FormatOrType)}
+ end;
+maybe_map_warnings(_,Tag,FormatOrType) ->
+ {Tag,FormatOrType}.
+
+fix_warning_tag(error,warning_msg) -> error;
+fix_warning_tag(error,warning_report) -> error_report;
+fix_warning_tag(info,warning_msg) -> info_msg;
+fix_warning_tag(info,warning_report) -> info_report;
+fix_warning_tag(_,Tag) -> Tag.
+
+fix_warning_type(error,std_warning) -> std_error;
+fix_warning_type(info,std_warning) -> std_info;
+fix_warning_type(_,Type) -> Type.
+
%%-----------------------------------------------------------------
%% These two simple old functions generate events tagged 'error'
%% Used for simple messages; error or information.
@@ -95,14 +232,18 @@ error_msg(Format) ->
Data :: list().
error_msg(Format, Args) ->
- notify({error, group_leader(), {self(), Format, Args}}).
+ logger:log(error,
+ #{label=>{?MODULE,error_msg},
+ format=>Format,
+ args=>Args},
+ meta(error)).
-spec format(Format, Data) -> 'ok' when
Format :: string(),
Data :: list().
format(Format, Args) ->
- notify({error, group_leader(), {self(), Format, Args}}).
+ error_msg(Format, Args).
%%-----------------------------------------------------------------
%% This functions should be used for error reports. Events
@@ -124,7 +265,10 @@ error_report(Report) ->
Report :: report().
error_report(Type, Report) ->
- notify({error_report, group_leader(), {self(), Type, Report}}).
+ logger:log(error,
+ #{label=>{?MODULE,error_report},
+ report=>Report},
+ meta(error_report,Type)).
%%-----------------------------------------------------------------
%% This function should be used for warning reports.
@@ -146,25 +290,10 @@ warning_report(Report) ->
Report :: report().
warning_report(Type, Report) ->
- {Tag, NType} = case error_logger:warning_map() of
- info ->
- if
- Type =:= std_warning ->
- {info_report, std_info};
- true ->
- {info_report, Type}
- end;
- warning ->
- {warning_report, Type};
- error ->
- if
- Type =:= std_warning ->
- {error_report, std_error};
- true ->
- {error_report, Type}
- end
- end,
- notify({Tag, group_leader(), {self(), NType, Report}}).
+ logger:log(warning,
+ #{label=>{?MODULE,warning_report},
+ report=>Report},
+ meta(warning_report,Type)).
%%-----------------------------------------------------------------
%% This function provides similar functions as error_msg for
@@ -183,15 +312,11 @@ warning_msg(Format) ->
Data :: list().
warning_msg(Format, Args) ->
- Tag = case error_logger:warning_map() of
- warning ->
- warning_msg;
- info ->
- info_msg;
- error ->
- error
- end,
- notify({Tag, group_leader(), {self(), Format, Args}}).
+ logger:log(warning,
+ #{label=>{?MODULE,warning_msg},
+ format=>Format,
+ args=>Args},
+ meta(warning_msg)).
%%-----------------------------------------------------------------
%% This function should be used for information reports. Events
@@ -210,7 +335,10 @@ info_report(Report) ->
Report :: report().
info_report(Type, Report) ->
- notify({info_report, group_leader(), {self(), Type, Report}}).
+ logger:log(notice,
+ #{label=>{?MODULE,info_report},
+ report=>Report},
+ meta(info_report,Type)).
%%-----------------------------------------------------------------
%% This function provides similar functions as error_msg for
@@ -228,7 +356,11 @@ info_msg(Format) ->
Data :: list().
info_msg(Format, Args) ->
- notify({info_msg, group_leader(), {self(), Format, Args}}).
+ logger:log(notice,
+ #{label=>{?MODULE,info_msg},
+ format=>Format,
+ args=>Args},
+ meta(info_msg)).
%%-----------------------------------------------------------------
%% Used by the init process. Events are tagged 'info'.
@@ -236,38 +368,75 @@ info_msg(Format, Args) ->
-spec error_info(Error :: any()) -> 'ok'.
+%% unused?
error_info(Error) ->
- notify({info, group_leader(), {self(), Error, []}}).
-
--spec notify({msg_tag(), pid(), {pid(), any(), any()}}) -> 'ok'.
-
-notify(Msg) ->
- gen_event:notify(error_logger, Msg).
-
--type swap_handler_type() :: 'false' | 'silent' | 'tty' | {'logfile', string()}.
--spec swap_handler(Type :: swap_handler_type()) -> any().
-
-swap_handler(tty) ->
- R = gen_event:swap_handler(error_logger, {error_logger, swap},
- {error_logger_tty_h, []}),
- ok = simple_logger(),
- R;
-swap_handler({logfile, File}) ->
- R = gen_event:swap_handler(error_logger, {error_logger, swap},
- {error_logger_file_h, File}),
- ok = simple_logger(),
- R;
-swap_handler(silent) ->
- _ = gen_event:delete_handler(error_logger, error_logger, delete),
- ok = simple_logger();
-swap_handler(false) ->
- ok. % keep primitive event handler as-is
+ {Format,Args} =
+ case string_p(Error) of
+ true -> {Error,[]};
+ false -> {"~p",[Error]}
+ end,
+ MyMeta = #{tag=>info,type=>Error},
+ logger:log(notice, Format, Args, #{?MODULE=>MyMeta,domain=>[Error]}).
+
+%%-----------------------------------------------------------------
+%% Create metadata
+meta(Tag) ->
+ meta(Tag,undefined).
+meta(Tag,Type) ->
+ meta(Tag,Type,#{report_cb=>fun report_to_format/1}).
+meta(Tag,undefined,Meta0) ->
+ Meta0#{?MODULE=>#{tag=>Tag}};
+meta(Tag,Type,Meta0) ->
+ maybe_add_domain(Tag,Type,Meta0#{?MODULE=>#{tag=>Tag,type=>Type}}).
+
+%% This is to prevent events of non standard type from being printed
+%% with the standard logger. Similar to how error_logger_tty_h
+%% discards events of non standard type.
+maybe_add_domain(error_report,std_error,Meta) -> Meta;
+maybe_add_domain(info_report,std_info,Meta) -> Meta;
+maybe_add_domain(warning_report,std_warning,Meta) -> Meta;
+maybe_add_domain(_,Type,Meta) -> Meta#{domain=>[Type]}.
+
+%% -----------------------------------------------------------------
+%% Report formatting - i.e. Term => {Format,Args}
+%% This was earlier done in the event handler (error_logger_tty_h, etc)
+%% -----------------------------------------------------------------
+report_to_format(#{label:={?MODULE,_},
+ report:=Report}) when is_map(Report) ->
+ %% logger:format_otp_report does maps:to_list, and for backwards
+ %% compatibility reasons we don't want that.
+ {"~tp\n",[Report]};
+report_to_format(#{label:={?MODULE,_},
+ format:=Format,
+ args:=Args}) ->
+ %% This is not efficient, but needed for backwards compatibility
+ %% in giving faulty arguments to the *_msg functions.
+ try io_lib:scan_format(Format,Args) of
+ _ -> {Format,Args}
+ catch _:_ ->
+ {"ERROR: ~tp - ~tp",[Format,Args]}
+ end;
+report_to_format(Term) ->
+ logger:format_otp_report(Term).
+
+string_p(List) when is_list(List) ->
+ string_p1(lists:flatten(List));
+string_p(_) ->
+ false.
+string_p1([]) ->
+ false;
+string_p1(FlatList) ->
+ io_lib:printable_list(FlatList).
+
+%% -----------------------------------------------------------------
+%% Stuff directly related to the event manager
+%% -----------------------------------------------------------------
-spec add_report_handler(Handler) -> any() when
Handler :: module().
add_report_handler(Module) when is_atom(Module) ->
- gen_event:add_handler(error_logger, Module, []).
+ add_report_handler(Module, []).
-spec add_report_handler(Handler, Args) -> Result when
Handler :: module(),
@@ -275,24 +444,37 @@ add_report_handler(Module) when is_atom(Module) ->
Result :: gen_event:add_handler_ret().
add_report_handler(Module, Args) when is_atom(Module) ->
- gen_event:add_handler(error_logger, Module, Args).
+ _ = logger:add_handler(?MODULE,?MODULE,#{level=>info,filter_default=>log}),
+ gen_event:add_handler(?MODULE, Module, Args).
-spec delete_report_handler(Handler) -> Result when
Handler :: module(),
Result :: gen_event:del_handler_ret().
delete_report_handler(Module) when is_atom(Module) ->
- gen_event:delete_handler(error_logger, Module, []).
-
-%% Start the lowest level error_logger handler with Buffer.
-
-simple_logger(Buffer_size) when is_integer(Buffer_size) ->
- gen_event:add_handler(error_logger, error_logger, Buffer_size).
-
-%% Start the lowest level error_logger handler without Buffer.
+ case whereis(?MODULE) of
+ Pid when is_pid(Pid) ->
+ Return = gen_event:delete_handler(?MODULE, Module, []),
+ case gen_event:which_handlers(?MODULE) of
+ [] ->
+ %% Don't want a lot of logs here if it's not needed
+ _ = logger:remove_handler(?MODULE),
+ ok;
+ _ ->
+ ok
+ end,
+ Return;
+ _ ->
+ ok
+ end.
-simple_logger() ->
- gen_event:add_handler(error_logger, error_logger, []).
+which_report_handlers() ->
+ case whereis(?MODULE) of
+ Pid when is_pid(Pid) ->
+ gen_event:which_handlers(?MODULE);
+ undefined ->
+ []
+ end.
%% Log all errors to File for all eternity
@@ -308,26 +490,35 @@ simple_logger() ->
FilenameReason :: no_log_file.
logfile({open, File}) ->
- case lists:member(error_logger_file_h,
- gen_event:which_handlers(error_logger)) of
+ case lists:member(error_logger_file_h,which_report_handlers()) of
true ->
{error, allready_have_logfile};
_ ->
- gen_event:add_handler(error_logger, error_logger_file_h, File)
+ add_report_handler(error_logger_file_h, File)
end;
logfile(close) ->
- case gen_event:delete_handler(error_logger, error_logger_file_h, normal) of
- {error,Reason} ->
- {error,Reason};
- _ ->
- ok
+ case whereis(?MODULE) of
+ Pid when is_pid(Pid) ->
+ case gen_event:delete_handler(?MODULE, error_logger_file_h, normal) of
+ {error,Reason} ->
+ {error,Reason};
+ _ ->
+ ok
+ end;
+ _ ->
+ {error,module_not_found}
end;
logfile(filename) ->
- case gen_event:call(error_logger, error_logger_file_h, filename) of
- {error,_} ->
- {error, no_log_file};
- Val ->
- Val
+ case whereis(?MODULE) of
+ Pid when is_pid(Pid) ->
+ case gen_event:call(?MODULE, error_logger_file_h, filename) of
+ {error,_} ->
+ {error, no_log_file};
+ Val ->
+ Val
+ end;
+ _ ->
+ {error, no_log_file}
end.
%% Possibly turn off all tty printouts, maybe we only want the errors
@@ -337,194 +528,38 @@ logfile(filename) ->
Flag :: boolean().
tty(true) ->
- Hs = gen_event:which_handlers(error_logger),
- case lists:member(error_logger_tty_h, Hs) of
- false ->
- gen_event:add_handler(error_logger, error_logger_tty_h, []);
- true ->
- ignore
- end,
+ _ = case lists:member(error_logger_tty_h, which_report_handlers()) of
+ false ->
+ case logger:get_handler_config(default) of
+ {ok,#{module:=logger_std_h,config:=#{type:=standard_io}}} ->
+ logger:remove_handler_filter(default,
+ error_logger_tty_false);
+ _ ->
+ logger:add_handler(error_logger_tty_true,logger_std_h,
+ #{filter_default=>stop,
+ filters=>?DEFAULT_HANDLER_FILTERS(
+ [otp]),
+ formatter=>{?DEFAULT_FORMATTER,
+ ?DEFAULT_FORMAT_CONFIG},
+ config=>#{type=>standard_io}})
+ end;
+ true ->
+ ok
+ end,
ok;
tty(false) ->
- gen_event:delete_handler(error_logger, error_logger_tty_h, []),
+ delete_report_handler(error_logger_tty_h),
+ _ = logger:remove_handler(error_logger_tty_true),
+ _ = case logger:get_handler_config(default) of
+ {ok,#{module:=logger_std_h,config:=#{type:=standard_io}}} ->
+ logger:add_handler_filter(default,error_logger_tty_false,
+ {fun(_,_) -> stop end, ok});
+ _ ->
+ ok
+ end,
ok.
-
-%%% ---------------------------------------------------
-%%% This is the default error_logger handler.
-%%% ---------------------------------------------------
-
--spec init(term()) -> {'ok', state() | []}.
-
-init(Max) when is_integer(Max) ->
- {ok, {Max, 0, []}};
-%% This one is called if someone took over from us, and now wants to
-%% go back.
-init({go_back, _PostState}) ->
- {ok, {?buffer_size, 0, []}};
-init(_) ->
- %% The error logger process may receive a huge amount of
- %% messages. Make sure that they are stored off heap to
- %% avoid exessive GCs.
- process_flag(message_queue_data, off_heap),
- {ok, []}.
-
--spec handle_event(term(), state()) -> {'ok', state()}.
-
-handle_event({Type, GL, Msg}, State) when node(GL) =/= node() ->
- gen_event:notify({error_logger, node(GL)},{Type, GL, Msg}),
- %% handle_event2({Type, GL, Msg}, State); %% Shall we do something
- {ok, State}; %% at this node too ???
-handle_event({info_report, _, {_, Type, _}}, State) when Type =/= std_info ->
- {ok, State}; %% Ignore other info reports here
-handle_event(Event, State) ->
- handle_event2(Event, State).
-
--spec handle_info(term(), state()) -> {'ok', state()}.
-
-handle_info({emulator, GL, Chars}, State) when node(GL) =/= node() ->
- {error_logger, node(GL)} ! {emulator, GL, add_node(Chars,self())},
- {ok, State};
-handle_info({emulator, GL, Chars}, State) ->
- handle_event2({emulator, GL, Chars}, State);
-handle_info(_, State) ->
- {ok, State}.
-
--spec handle_call(term(), state()) -> {'ok', {'error', 'bad_query'}, state()}.
-
-handle_call(_Query, State) -> {ok, {error, bad_query}, State}.
-
--spec terminate(term(), state()) -> {'error_logger', [term()]}.
-
-terminate(swap, {_, 0, Buff}) ->
- {error_logger, Buff};
-terminate(swap, {_, Lost, Buff}) ->
- Myevent = {info, group_leader(), {self(), {lost_messages, Lost}, []}},
- {error_logger, [tag_event(Myevent)|Buff]};
-terminate(_, _) ->
- {error_logger, []}.
-
-handle_event2(Event, {1, Lost, Buff}) ->
- display(tag_event(Event)),
- {ok, {1, Lost+1, Buff}};
-handle_event2(Event, {N, Lost, Buff}) ->
- Tagged = tag_event(Event),
- display(Tagged),
- {ok, {N-1, Lost, [Tagged|Buff]}};
-handle_event2(_, State) ->
- {ok, State}.
-
-tag_event(Event) ->
- {erlang:localtime(), Event}.
-
-display({Tag,{error,_,{_,Format,Args}}}) ->
- display2(Tag,Format,Args);
-display({Tag,{error_report,_,{_,Type,Report}}}) ->
- display2(Tag,Type,Report);
-display({Tag,{info_report,_,{_,Type,Report}}}) ->
- display2(Tag,Type,Report);
-display({Tag,{info,_,{_,Error,_}}}) ->
- display2(Tag,Error,[]);
-display({Tag,{info_msg,_,{_,Format,Args}}}) ->
- display2(Tag,Format,Args);
-display({Tag,{warning_report,_,{_,Type,Report}}}) ->
- display2(Tag,Type,Report);
-display({Tag,{warning_msg,_,{_,Format,Args}}}) ->
- display2(Tag,Format,Args);
-display({Tag,{emulator,_,Chars}}) ->
- display2(Tag,Chars,[]).
-
-add_node(X, Pid) when is_atom(X) ->
- add_node(atom_to_list(X), Pid);
-add_node(X, Pid) ->
- lists:concat([X,"** at node ",node(Pid)," **~n"]).
-
-%% Can't do io_lib:format
-
-display2({{_Y,_Mo,_D},{_H,_Mi,_S}} = Date, F, A) ->
- display_date(Date),
- display3(string_p(F), F, A).
-
-display_date({{Y,Mo,D},{H,Mi,S}}) ->
- erlang:display_string(
- integer_to_list(Y) ++ "-" ++
- two_digits(Mo) ++ "-" ++
- two_digits(D) ++ " " ++
- two_digits(H) ++ ":" ++
- two_digits(Mi) ++ ":" ++
- two_digits(S) ++ " ").
-
-two_digits(N) when 0 =< N, N =< 9 ->
- [$0, $0 + N];
-two_digits(N) ->
- integer_to_list(N).
-
-display3(true, F, A) ->
- %% Format string with arguments
- erlang:display_string(F ++ "\n"),
- [begin
- erlang:display_string("\t"),
- erlang:display(Arg)
- end || Arg <- A],
- ok;
-display3(false, Atom, A) when is_atom(Atom) ->
- %% The widest atom seems to be 'supervisor_report' at 17.
- ColumnWidth = 20,
- AtomString = atom_to_list(Atom),
- AtomLength = length(AtomString),
- Padding = lists:duplicate(ColumnWidth - AtomLength, $\s),
- erlang:display_string(AtomString ++ Padding),
- display4(A);
-display3(_, F, A) ->
- erlang:display({F, A}).
-
-display4([A, []]) ->
- %% Not sure why crash reports look like this.
- display4(A);
-display4(A = [_|_]) ->
- case lists:all(fun({Key,_Value}) -> is_atom(Key); (_) -> false end, A) of
- true ->
- erlang:display_string("\n"),
- lists:foreach(
- fun({Key, Value}) ->
- erlang:display_string(
- " " ++
- atom_to_list(Key) ++
- ": "),
- erlang:display(Value)
- end, A);
- false ->
- erlang:display(A)
- end;
-display4(A) ->
- erlang:display(A).
-
-string_p([]) ->
- false;
-string_p(Term) ->
- string_p1(Term).
-
-string_p1([H|T]) when is_integer(H), H >= $\040, H =< $\176 ->
- string_p1(T);
-string_p1([H|T]) when is_integer(H), H >= 16#A0, H < 16#D800;
- is_integer(H), H > 16#DFFF, H < 16#FFFE;
- is_integer(H), H > 16#FFFF, H =< 16#10FFFF ->
- string_p1(T);
-string_p1([$\n|T]) -> string_p1(T);
-string_p1([$\r|T]) -> string_p1(T);
-string_p1([$\t|T]) -> string_p1(T);
-string_p1([$\v|T]) -> string_p1(T);
-string_p1([$\b|T]) -> string_p1(T);
-string_p1([$\f|T]) -> string_p1(T);
-string_p1([$\e|T]) -> string_p1(T);
-string_p1([H|T]) when is_list(H) ->
- case string_p1(H) of
- true -> string_p1(T);
- _ -> false
- end;
-string_p1([]) -> true;
-string_p1(_) -> false.
-
+%%%-----------------------------------------------------------------
-spec limit_term(term()) -> term().
limit_term(Term) ->
@@ -539,6 +574,8 @@ get_format_depth() ->
case application:get_env(kernel, error_logger_format_depth) of
{ok, Depth} when is_integer(Depth) ->
max(10, Depth);
+ {ok, unlimited} ->
+ unlimited;
undefined ->
unlimited
end.
diff --git a/lib/kernel/src/erts_debug.erl b/lib/kernel/src/erts_debug.erl
index 9662f8fa90..e6a30d0b92 100644
--- a/lib/kernel/src/erts_debug.erl
+++ b/lib/kernel/src/erts_debug.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,7 +21,7 @@
%% Low-level debugging support. EXPERIMENTAL!
--export([size/1,df/1,df/2,df/3,df/4,ic/1]).
+-export([size/1,df/1,df/2,df/3,dis_to_file/2,ic/1]).
%% This module contains the following *experimental* BIFs:
%% disassemble/1
@@ -32,11 +32,13 @@
%%% BIFs
-export([breakpoint/2, disassemble/1, display/1, dist_ext_to_term/2,
- dump_monitors/1, dump_links/1, flat_size/1,
- get_internal_state/1, instructions/0,
+ flat_size/1, get_internal_state/1, instructions/0,
+ interpreter_size/0,
map_info/1, same/2, set_internal_state/2,
size_shared/1, copy_shared/1, dirty_cpu/2, dirty_io/2, dirty/3,
- lcnt_control/1, lcnt_control/2, lcnt_collect/0, lcnt_clear/0]).
+ lcnt_control/1, lcnt_control/2, lcnt_collect/0, lcnt_clear/0,
+ lc_graph/0, lc_graph_to_dot/2, lc_graph_merge/2,
+ alloc_blocks_size/1]).
-spec breakpoint(MFA, Flag) -> non_neg_integer() when
MFA :: {Module :: module(),
@@ -70,18 +72,6 @@ display(_) ->
dist_ext_to_term(_, _) ->
erlang:nif_error(undef).
--spec dump_monitors(Id) -> true when
- Id :: pid() | atom().
-
-dump_monitors(_) ->
- erlang:nif_error(undef).
-
--spec dump_links(Id) -> true when
- Id :: pid() | port() | atom().
-
-dump_links(_) ->
- erlang:nif_error(undef).
-
-spec flat_size(Term) -> non_neg_integer() when
Term :: term().
@@ -129,6 +119,11 @@ get_internal_state(_) ->
instructions() ->
erlang:nif_error(undef).
+-spec interpreter_size() -> pos_integer().
+
+interpreter_size() ->
+ erlang:nif_error(undef).
+
-spec ic(F) -> Result when
F :: function(),
Result :: term().
@@ -347,55 +342,52 @@ is_term_seen(_, []) -> false.
-spec df(module()) -> df_ret().
df(Mod) when is_atom(Mod) ->
- df(lists:concat([Mod, ".dis"]), Mod).
-
--spec df(module(), atom()) -> df_ret();
- (file:io_device() | file:filename(), module()) -> df_ret().
-
-df(Mod, Func) when is_atom(Mod), is_atom(Func) ->
- df(lists:concat([Mod, "_", Func, ".dis"]), Mod, Func);
-df(Name, Mod) when is_atom(Mod) ->
try Mod:module_info(functions) of
Fs0 when is_list(Fs0) ->
+ Name = lists:concat([Mod, ".dis"]),
Fs = [{Mod,Func,Arity} || {Func,Arity} <- Fs0],
dff(Name, Fs)
catch _:_ -> {undef,Mod}
end.
+-spec df(module(), atom()) -> df_ret().
--spec df(module(), atom(), arity()) -> df_ret();
- (file:io_device() | file:filename(), module(), atom()) -> df_ret().
-
-df(Mod, Func, Arity) when is_atom(Mod), is_atom(Func), is_integer(Arity) ->
- df(lists:concat([Mod, "_", Func, "_", Arity, ".dis"]), Mod, Func, Arity);
-df(Name, Mod, Func) when is_atom(Mod), is_atom(Func) ->
+df(Mod, Func) when is_atom(Mod), is_atom(Func) ->
try Mod:module_info(functions) of
Fs0 when is_list(Fs0) ->
+ Name = lists:concat([Mod, "_", Func, ".dis"]),
Fs = [{Mod,Func1,Arity} || {Func1,Arity} <- Fs0, Func1 =:= Func],
dff(Name, Fs)
catch _:_ -> {undef,Mod}
end.
--spec df(file:io_device() | file:filename(), module(), atom(), arity()) -> df_ret().
-df(Name, Mod, Func, Arity) when is_atom(Mod), is_atom(Func), is_integer(Arity) ->
+-spec df(module(), atom(), arity()) -> df_ret().
+
+df(Mod, Func, Arity) when is_atom(Mod), is_atom(Func) ->
try Mod:module_info(functions) of
Fs0 when is_list(Fs0) ->
+ Name = lists:concat([Mod, "_", Func, "_", Arity, ".dis"]),
Fs = [{Mod,Func1,Arity1} || {Func1,Arity1} <- Fs0,
Func1 =:= Func, Arity1 =:= Arity],
dff(Name, Fs)
catch _:_ -> {undef,Mod}
end.
-dff(File, Fs) when is_pid(File), is_list(Fs) ->
- lists:foreach(fun(Mfa) ->
- disassemble_function(File, Mfa),
- io:nl(File)
- end, Fs);
-dff(Name, Fs) when is_list(Name) ->
- case file:open(Name, [write]) of
+-spec dis_to_file(module(), file:filename()) -> df_ret().
+
+dis_to_file(Mod, Name) when is_atom(Mod) ->
+ try Mod:module_info(functions) of
+ Fs0 when is_list(Fs0) ->
+ Fs = [{Mod,Func,Arity} || {Func,Arity} <- Fs0],
+ dff(Name, Fs)
+ catch _:_ -> {undef,Mod}
+ end.
+
+dff(Name, Fs) ->
+ case file:open(Name, [write,raw,delayed_write]) of
{ok,F} ->
try
- dff(F, Fs)
+ dff_1(F, Fs)
after
_ = file:close(F)
end;
@@ -403,12 +395,18 @@ dff(Name, Fs) when is_list(Name) ->
{error,{badopen,Reason}}
end.
+dff_1(File, Fs) ->
+ lists:foreach(fun(Mfa) ->
+ disassemble_function(File, Mfa),
+ file:write(File, "\n")
+ end, Fs).
+
disassemble_function(File, {_,_,_}=MFA) ->
cont_dis(File, erts_debug:disassemble(MFA), MFA).
cont_dis(_, false, _) -> ok;
cont_dis(File, {Addr,Str,MFA}, MFA) ->
- io:put_chars(File, binary_to_list(Str)),
+ ok = file:write(File, Str),
cont_dis(File, erts_debug:disassemble(Addr), MFA);
cont_dis(_, {_,_,_}, _) -> ok.
@@ -417,3 +415,145 @@ cont_dis(_, {_,_,_}, _) -> ok.
map_info(_) ->
erlang:nif_error(undef).
+
+%% Create file "lc_graph.<pid>" with all actual lock dependencies
+%% recorded so far by the VM.
+%% Needs debug VM or --enable-lock-checking config, returns 'notsup' otherwise.
+lc_graph() ->
+ erts_debug:set_internal_state(available_internal_state, true),
+ erts_debug:get_internal_state(lc_graph).
+
+%% Convert "lc_graph.<pid>" file to https://www.graphviz.org dot format.
+lc_graph_to_dot(OutFile, InFile) ->
+ {ok, [LL0]} = file:consult(InFile),
+
+ [{"NO LOCK",0} | LL] = LL0,
+ Map = maps:from_list([{Id, Name} || {Name, Id, _, _} <- LL]),
+
+ case file:open(OutFile, [exclusive]) of
+ {ok, Out} ->
+ ok = file:write(Out, "digraph G {\n"),
+
+ [dot_print_lock(Out, Lck, Map) || Lck <- LL],
+
+ ok = file:write(Out, "}\n"),
+ ok = file:close(Out);
+
+ {error,eexist} ->
+ {"File already exists", OutFile}
+ end.
+
+dot_print_lock(Out, {_Name, Id, Lst, _}, Map) ->
+ [dot_print_edge(Out, From, Id, Map) || From <- Lst],
+ ok.
+
+dot_print_edge(_, 0, _, _) ->
+ ignore; % "NO LOCK"
+dot_print_edge(Out, From, To, Map) ->
+ io:format(Out, "~p -> ~p;\n", [maps:get(From,Map), maps:get(To,Map)]).
+
+
+%% Merge several "lc_graph" files into one file.
+lc_graph_merge(OutFile, InFiles) ->
+ LLs = lists:map(fun(InFile) ->
+ {ok, [LL]} = file:consult(InFile),
+ LL
+ end,
+ InFiles),
+
+ Res = lists:foldl(fun(A, B) -> lcg_merge(A, B) end,
+ hd(LLs),
+ tl(LLs)),
+ case file:open(OutFile, [exclusive]) of
+ {ok, Out} ->
+ try
+ lcg_print(Out, Res)
+ after
+ file:close(Out)
+ end,
+ ok;
+ {error, eexist} ->
+ {"File already exists", OutFile}
+ end.
+
+lcg_merge(A, B) ->
+ lists:zipwith(fun(LA, LB) -> lcg_merge_locks(LA, LB) end,
+ A, B).
+
+lcg_merge_locks(L, L) ->
+ L;
+lcg_merge_locks({Name, Id, DA, IA}, {Name, Id, DB, IB}) ->
+ Direct = lists:umerge(DA, DB),
+ Indirect = lists:umerge(IA, IB),
+ {Name, Id, Direct, Indirect -- Direct}.
+
+
+lcg_print(Out, LL) ->
+ io:format(Out, "[", []),
+ lcg_print_locks(Out, LL),
+ io:format(Out, "].\n", []),
+ ok.
+
+lcg_print_locks(Out, [{_,_}=NoLock | Rest]) ->
+ io:format(Out, "~p,\n", [NoLock]),
+ lcg_print_locks(Out, Rest);
+lcg_print_locks(Out, [LastLock]) ->
+ io:format(Out, "~w", [LastLock]);
+lcg_print_locks(Out, [Lock | Rest]) ->
+ io:format(Out, "~w,\n", [Lock]),
+ lcg_print_locks(Out, Rest).
+
+
+%% Returns the amount of memory allocated by the given allocator type.
+-spec alloc_blocks_size(Type) -> non_neg_integer() | undefined when
+ Type :: atom().
+
+alloc_blocks_size(Type) ->
+ Allocs = erlang:system_info(alloc_util_allocators),
+ Sizes = erlang:system_info({allocator_sizes, Allocs}),
+ alloc_blocks_size_1(Sizes, Type, 0).
+
+alloc_blocks_size_1([], _Type, 0) ->
+ undefined;
+alloc_blocks_size_1([{_Type, false} | Rest], Type, Acc) ->
+ alloc_blocks_size_1(Rest, Type, Acc);
+alloc_blocks_size_1([{Type, Instances} | Rest], Type, Acc0) ->
+ F = fun ({instance, _, L}, Acc) ->
+ MBCSPool = case lists:keyfind(mbcs_pool, 1, L) of
+ {_, Pool} -> Pool;
+ false -> []
+ end,
+ {_,MBCS} = lists:keyfind(mbcs, 1, L),
+ {_,SBCS} = lists:keyfind(sbcs, 1, L),
+ Acc +
+ sum_block_sizes(MBCSPool) +
+ sum_block_sizes(MBCS) +
+ sum_block_sizes(SBCS)
+ end,
+ alloc_blocks_size_1(Rest, Type, lists:foldl(F, Acc0, Instances));
+alloc_blocks_size_1([{_Type, Instances} | Rest], Type, Acc0) ->
+ F = fun ({instance, _, L}, Acc) ->
+ Acc + sum_foreign_sizes(Type, L)
+ end,
+ alloc_blocks_size_1(Rest, Type, lists:foldl(F, Acc0, Instances));
+alloc_blocks_size_1([], _Type, Acc) ->
+ Acc.
+
+sum_foreign_sizes(Type, L) ->
+ case lists:keyfind(mbcs_pool, 1, L) of
+ {_,Pool} ->
+ {_,ForeignBlocks} = lists:keyfind(foreign_blocks, 1, Pool),
+ case lists:keyfind(Type, 1, ForeignBlocks) of
+ {_,TypeSizes} -> sum_block_sizes(TypeSizes);
+ false -> 0
+ end;
+ _ ->
+ 0
+ end.
+
+sum_block_sizes(Blocks) ->
+ lists:foldl(
+ fun({blocks_size, Sz,_,_}, Sz0) -> Sz0+Sz;
+ ({blocks_size, Sz}, Sz0) -> Sz0+Sz;
+ (_, Sz) -> Sz
+ end, 0, Blocks).
diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl
index 933f2d5f65..1d4e37196c 100644
--- a/lib/kernel/src/file.erl
+++ b/lib/kernel/src/file.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -69,10 +69,10 @@
%% Types that can be used from other modules -- alphabetically ordered.
-export_type([date_time/0, fd/0, file_info/0, filename/0, filename_all/0,
- io_device/0, name/0, name_all/0, posix/0]).
+ io_device/0, mode/0, name/0, name_all/0, posix/0]).
%%% Includes and defines
--include("file.hrl").
+-include("file_int.hrl").
-define(FILE_IO_SERVER_TABLE, file_io_servers).
@@ -101,14 +101,25 @@
-type deep_list() :: [char() | atom() | deep_list()].
-type name() :: string() | atom() | deep_list().
-type name_all() :: string() | atom() | deep_list() | (RawFilename :: binary()).
--type posix() :: 'eacces' | 'eagain' | 'ebadf' | 'ebusy' | 'edquot'
- | 'eexist' | 'efault' | 'efbig' | 'eintr' | 'einval'
- | 'eio' | 'eisdir' | 'eloop' | 'emfile' | 'emlink'
- | 'enametoolong'
- | 'enfile' | 'enodev' | 'enoent' | 'enomem' | 'enospc'
- | 'enotblk' | 'enotdir' | 'enotsup' | 'enxio' | 'eperm'
- | 'epipe' | 'erofs' | 'espipe' | 'esrch' | 'estale'
- | 'exdev'.
+-type posix() ::
+ 'eacces' | 'eagain' |
+ 'ebadf' | 'ebadmsg' | 'ebusy' |
+ 'edeadlk' | 'edeadlock' | 'edquot' |
+ 'eexist' |
+ 'efault' | 'efbig' | 'eftype' |
+ 'eintr' | 'einval' | 'eio' | 'eisdir' |
+ 'eloop' |
+ 'emfile' | 'emlink' | 'emultihop' |
+ 'enametoolong' | 'enfile' |
+ 'enobufs' | 'enodev' | 'enolck' | 'enolink' | 'enoent' |
+ 'enomem' | 'enospc' | 'enosr' | 'enostr' | 'enosys' |
+ 'enotblk' | 'enotdir' | 'enotsup' | 'enxio' |
+ 'eopnotsupp' | 'eoverflow' |
+ 'eperm' | 'epipe' |
+ 'erange' | 'erofs' |
+ 'espipe' | 'esrch' | 'estale' |
+ 'etxtbsy' |
+ 'exdev'.
-type date_time() :: calendar:datetime().
-type posix_file_advise() :: 'normal' | 'sequential' | 'random'
| 'no_reuse' | 'will_need' | 'dont_need'.
@@ -454,41 +465,23 @@ raw_write_file_info(Name, #file_info{} = Info) ->
Reason :: posix() | badarg | system_limit.
open(Item, ModeList) when is_list(ModeList) ->
- case lists:member(raw, ModeList) of
- %% Raw file, use ?PRIM_FILE to handle this file
- true ->
+ case {lists:member(raw, ModeList), lists:member(ram, ModeList)} of
+ {false, false} ->
+ %% File server file
Args = [file_name(Item) | ModeList],
case check_args(Args) of
ok ->
[FileName | _] = Args,
- %% We rely on the returned Handle (in {ok, Handle})
- %% being a pid() or a #file_descriptor{}
- ?PRIM_FILE:open(FileName, ModeList);
+ call(open, [FileName, ModeList]);
Error ->
Error
- end;
- false ->
- case lists:member(ram, ModeList) of
- %% RAM file, use ?RAM_FILE to handle this file
- true ->
- case check_args(ModeList) of
- ok ->
- ?RAM_FILE:open(Item, ModeList);
- Error ->
- Error
- end;
- %% File server file
- false ->
- Args = [file_name(Item) | ModeList],
- case check_args(Args) of
- ok ->
- [FileName | _] = Args,
- call(open, [FileName, ModeList]);
- Error ->
- Error
- end
- end
+ end;
+ {true, _Either} ->
+ raw_file_io:open(file_name(Item), ModeList);
+ {false, true} ->
+ ram_file:open(Item, ModeList)
end;
+
%% Old obsolete mode specification in atom or 2-tuple format
open(Item, Mode) ->
open(Item, mode_list(Mode)).
@@ -1254,15 +1247,18 @@ sendfile(File, _Sock, _Offet, _Bytes, _Opts) when is_pid(File) ->
sendfile(File, Sock, Offset, Bytes, []) ->
sendfile(File, Sock, Offset, Bytes, ?MAX_CHUNK_SIZE, [], [], []);
sendfile(File, Sock, Offset, Bytes, Opts) ->
- ChunkSize0 = proplists:get_value(chunk_size, Opts, ?MAX_CHUNK_SIZE),
- ChunkSize = if ChunkSize0 > ?MAX_CHUNK_SIZE ->
- ?MAX_CHUNK_SIZE;
- true -> ChunkSize0
- end,
- %% Support for headers, trailers and options has been removed because the
- %% Darwin and BSD API for using it does not play nice with
- %% non-blocking sockets. See unix_efile.c for more info.
- sendfile(File, Sock, Offset, Bytes, ChunkSize, [], [], Opts).
+ try proplists:get_value(chunk_size, Opts, ?MAX_CHUNK_SIZE) of
+ ChunkSize0 when is_integer(ChunkSize0) ->
+ ChunkSize = erlang:min(ChunkSize0, ?MAX_CHUNK_SIZE),
+ %% Support for headers, trailers and options has been removed
+ %% because the Darwin and BSD API for using it does not play nice
+ %% with non-blocking sockets. See unix_efile.c for more info.
+ sendfile(File, Sock, Offset, Bytes, ChunkSize, [], [], Opts);
+ _Other ->
+ {error, badarg}
+ catch
+ error:_ -> {error, badarg}
+ end.
%% sendfile/2
-spec sendfile(Filename, Socket) ->
@@ -1397,8 +1393,8 @@ eval_stream2({ok,Form,EndLine}, Fd, H, Last, E, Bs0) ->
try erl_eval:exprs(Form, Bs0) of
{value,V,Bs} ->
eval_stream(Fd, H, EndLine, {V}, E, Bs)
- catch Class:Reason ->
- Error = {EndLine,?MODULE,{Class,Reason,erlang:get_stacktrace()}},
+ catch Class:Reason:StackTrace ->
+ Error = {EndLine,?MODULE,{Class,Reason,StackTrace}},
eval_stream(Fd, H, EndLine, Last, [Error|E], Bs0)
end;
eval_stream2({error,What,EndLine}, Fd, H, Last, E, Bs) ->
diff --git a/lib/kernel/src/file_int.hrl b/lib/kernel/src/file_int.hrl
new file mode 100644
index 0000000000..bafc330c04
--- /dev/null
+++ b/lib/kernel/src/file_int.hrl
@@ -0,0 +1,33 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%% Internal definitions for the 'file' module and friends.
+%%
+
+-ifndef(FILE_INTERNAL_HRL_).
+-define(FILE_INTERNAL_HRL_, 1).
+
+-include("file.hrl").
+
+-define(CALL_FD(Fd, Method, Args),
+ apply(Fd#file_descriptor.module, Method, [Fd | Args])).
+
+-endif.
diff --git a/lib/kernel/src/file_io_server.erl b/lib/kernel/src/file_io_server.erl
index deb7b315b1..34d5497a4a 100644
--- a/lib/kernel/src/file_io_server.erl
+++ b/lib/kernel/src/file_io_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -28,7 +28,8 @@
-record(state, {handle,owner,mref,buf,read_mode,unic}).
--define(PRIM_FILE, prim_file).
+-include("file_int.hrl").
+
-define(READ_SIZE_LIST, 128).
-define(READ_SIZE_BINARY, (8*1024)).
@@ -67,8 +68,9 @@ do_start(Spawn, Owner, FileName, ModeList) ->
erlang:dt_restore_tag(Utag),
%% process_flag(trap_exit, true),
case parse_options(ModeList) of
- {ReadMode, UnicodeMode, Opts} ->
- case ?PRIM_FILE:open(FileName, Opts) of
+ {ReadMode, UnicodeMode, Opts0} ->
+ Opts = maybe_add_read_ahead(ReadMode, Opts0),
+ case raw_file_io:open(FileName, [raw | Opts]) of
{error, Reason} = Error ->
Self ! {Ref, Error},
exit(Reason);
@@ -157,6 +159,24 @@ valid_enc({utf32,little}) ->
valid_enc(_Other) ->
{error,badarg}.
+%% Add a small read_ahead buffer if the file is opened for reading
+%% only in list mode and no read_ahead is already given.
+maybe_add_read_ahead(binary, Opts) ->
+ Opts;
+maybe_add_read_ahead(list, Opts) ->
+ P = fun(read_ahead) -> true;
+ ({read_ahead,_}) -> true;
+ (append) -> true;
+ (exclusive) -> true;
+ (write) -> true;
+ (_) -> false
+ end,
+ case lists:any(P, Opts) of
+ false ->
+ [{read_ahead, 4096}|Opts];
+ true ->
+ Opts
+ end.
server_loop(#state{mref = Mref} = State) ->
receive
@@ -205,7 +225,7 @@ io_reply(From, ReplyAs, Reply) ->
file_request({advise,Offset,Length,Advise},
#state{handle=Handle}=State) ->
- case ?PRIM_FILE:advise(Handle, Offset, Length, Advise) of
+ case ?CALL_FD(Handle, advise, [Offset, Length, Advise]) of
{error,Reason}=Reply ->
{stop,Reason,Reply,State};
Reply ->
@@ -213,7 +233,7 @@ file_request({advise,Offset,Length,Advise},
end;
file_request({allocate, Offset, Length},
#state{handle = Handle} = State) ->
- Reply = ?PRIM_FILE:allocate(Handle, Offset, Length),
+ Reply = ?CALL_FD(Handle, allocate, [Offset, Length]),
{reply, Reply, State};
file_request({pread,At,Sz}, State)
when At =:= cur;
@@ -256,7 +276,7 @@ file_request({pwrite,At,Data},
end;
file_request(datasync,
#state{handle=Handle}=State) ->
- case ?PRIM_FILE:datasync(Handle) of
+ case ?CALL_FD(Handle, datasync, []) of
{error,Reason}=Reply ->
{stop,Reason,Reply,State};
Reply ->
@@ -264,7 +284,7 @@ file_request(datasync,
end;
file_request(sync,
#state{handle=Handle}=State) ->
- case ?PRIM_FILE:sync(Handle) of
+ case ?CALL_FD(Handle, sync, []) of
{error,Reason}=Reply ->
{stop,Reason,Reply,State};
Reply ->
@@ -272,7 +292,7 @@ file_request(sync,
end;
file_request(close,
#state{handle=Handle}=State) ->
- case ?PRIM_FILE:close(Handle) of
+ case ?CALL_FD(Handle, close, []) of
{error,Reason}=Reply ->
{stop,Reason,Reply,State#state{buf= <<>>}};
Reply ->
@@ -288,7 +308,7 @@ file_request({position,At},
end;
file_request(truncate,
#state{handle=Handle}=State) ->
- case ?PRIM_FILE:truncate(Handle) of
+ case ?CALL_FD(Handle, truncate, []) of
{error,Reason}=Reply ->
{stop,Reason,Reply,State#state{buf= <<>>}};
Reply ->
@@ -398,7 +418,7 @@ io_request_loop([Request|Tail],
%%
put_chars(Chars, latin1, #state{handle=Handle, unic=latin1}=State) ->
NewState = State#state{buf = <<>>},
- case ?PRIM_FILE:write(Handle, Chars) of
+ case ?CALL_FD(Handle, write, [Chars]) of
{error,Reason}=Reply ->
{stop,Reason,Reply,NewState};
Reply ->
@@ -408,7 +428,7 @@ put_chars(Chars, InEncoding, #state{handle=Handle, unic=OutEncoding}=State) ->
NewState = State#state{buf = <<>>},
case unicode:characters_to_binary(Chars,InEncoding,OutEncoding) of
Bin when is_binary(Bin) ->
- case ?PRIM_FILE:write(Handle, Bin) of
+ case ?CALL_FD(Handle, write, [Bin]) of
{error,Reason}=Reply ->
{stop,Reason,Reply,NewState};
Reply ->
@@ -422,7 +442,7 @@ put_chars(Chars, InEncoding, #state{handle=Handle, unic=OutEncoding}=State) ->
get_line(S, {<<>>, Cont}, OutEnc,
#state{handle=Handle, read_mode=Mode, unic=InEnc}=State) ->
- case ?PRIM_FILE:read(Handle, read_size(Mode)) of
+ case ?CALL_FD(Handle, read, [read_size(Mode)]) of
{ok,Bin} ->
get_line(S, convert_enc([Cont, Bin], InEnc, OutEnc), OutEnc, State);
eof ->
@@ -472,7 +492,7 @@ get_chars(N, OutEnc,#state{handle=Handle,buf=Buf,read_mode=ReadMode,unic=latin1}
BufSize = byte_size(Buf),
NeedSize = N-BufSize,
Size = erlang:max(NeedSize, ?READ_SIZE_BINARY),
- case ?PRIM_FILE:read(Handle, Size) of
+ case ?CALL_FD(Handle, read, [Size]) of
{ok, B} ->
if BufSize+byte_size(B) < N ->
std_reply(cat(Buf, B, ReadMode,latin1,OutEnc), State);
@@ -504,7 +524,7 @@ get_chars(N, OutEnc,#state{handle=Handle,buf=Buf,read_mode=ReadMode,unic=InEncod
%% Need more, Try to read 4*needed in bytes...
NeedSize = (N - BufCount) * 4,
Size = erlang:max(NeedSize, ?READ_SIZE_BINARY),
- case ?PRIM_FILE:read(Handle, Size) of
+ case ?CALL_FD(Handle, read, [Size]) of
{ok, B} ->
NewBuf = list_to_binary([Buf,B]),
{NewCount,NewSplit} = count_and_find(NewBuf,N,InEncoding),
@@ -544,7 +564,7 @@ get_chars(Mod, Func, XtraArg, OutEnc, #state{buf=Buf}=State) ->
get_chars_empty(Mod, Func, XtraArg, S, latin1,
#state{handle=Handle,read_mode=ReadMode, unic=latin1}=State) ->
- case ?PRIM_FILE:read(Handle, read_size(ReadMode)) of
+ case ?CALL_FD(Handle, read, [read_size(ReadMode)]) of
{ok,Bin} ->
get_chars_apply(Mod, Func, XtraArg, S, latin1, State, Bin);
eof ->
@@ -554,7 +574,7 @@ get_chars_empty(Mod, Func, XtraArg, S, latin1,
end;
get_chars_empty(Mod, Func, XtraArg, S, OutEnc,
#state{handle=Handle,read_mode=ReadMode}=State) ->
- case ?PRIM_FILE:read(Handle, read_size(ReadMode)) of
+ case ?CALL_FD(Handle, read, [read_size(ReadMode)]) of
{ok,Bin} ->
get_chars_apply(Mod, Func, XtraArg, S, OutEnc, State, Bin);
eof ->
@@ -564,7 +584,7 @@ get_chars_empty(Mod, Func, XtraArg, S, OutEnc,
end.
get_chars_notempty(Mod, Func, XtraArg, S, OutEnc,
#state{handle=Handle,read_mode=ReadMode,buf = B}=State) ->
- case ?PRIM_FILE:read(Handle, read_size(ReadMode)) of
+ case ?CALL_FD(Handle, read, [read_size(ReadMode)]) of
{ok,Bin} ->
get_chars_apply(Mod, Func, XtraArg, S, OutEnc, State, list_to_binary([B,Bin]));
eof ->
@@ -918,13 +938,10 @@ cbv({utf32,little},_) ->
%% Compensates ?PRIM_FILE:position/2 for the number of bytes
%% we have buffered
position(Handle, At, Buf) ->
- ?PRIM_FILE:position(
- Handle,
- case At of
- cur ->
- {cur, -byte_size(Buf)};
- {cur, Offs} ->
- {cur, Offs-byte_size(Buf)};
- _ ->
- At
- end).
+ SeekTo =
+ case At of
+ {cur, Offs} -> {cur, Offs-byte_size(Buf)};
+ cur -> {cur, -byte_size(Buf)};
+ _ -> At
+ end,
+ ?CALL_FD(Handle, position, [SeekTo]).
diff --git a/lib/kernel/src/file_server.erl b/lib/kernel/src/file_server.erl
index 6e8f64d932..29eaa23375 100644
--- a/lib/kernel/src/file_server.erl
+++ b/lib/kernel/src/file_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -63,7 +63,7 @@ stop() ->
%%% Callback functions from gen_server
%%%----------------------------------------------------------------------
--type state() :: port(). % Internal type
+-type state() :: term(). % Internal type
%%----------------------------------------------------------------------
%% Func: init/1
@@ -73,18 +73,12 @@ stop() ->
%% {stop, Reason}
%%----------------------------------------------------------------------
--spec init([]) -> {'ok', state()} | {'stop', term()}.
+-spec init([]) -> {'ok', state()}.
init([]) ->
process_flag(trap_exit, true),
- case ?PRIM_FILE:start() of
- {ok, Handle} ->
- ?FILE_IO_SERVER_TABLE =
- ets:new(?FILE_IO_SERVER_TABLE, [named_table]),
- {ok, Handle};
- {error, Reason} ->
- {stop, Reason}
- end.
+ ?FILE_IO_SERVER_TABLE = ets:new(?FILE_IO_SERVER_TABLE, [named_table]),
+ {ok, undefined}.
%%----------------------------------------------------------------------
%% Func: handle_call/3
@@ -101,7 +95,7 @@ init([]) ->
{'reply', 'eof' | 'ok' | {'error', term()} | {'ok', term()}, state()} |
{'stop', 'normal', 'stopped', state()}.
-handle_call({open, Name, ModeList}, {Pid, _Tag} = _From, Handle)
+handle_call({open, Name, ModeList}, {Pid, _Tag} = _From, State)
when is_list(ModeList) ->
Child = ?FILE_IO_SERVER:start_link(Pid, Name, ModeList),
case Child of
@@ -110,78 +104,78 @@ handle_call({open, Name, ModeList}, {Pid, _Tag} = _From, Handle)
_ ->
ok
end,
- {reply, Child, Handle};
+ {reply, Child, State};
-handle_call({open, _Name, _Mode}, _From, Handle) ->
- {reply, {error, einval}, Handle};
+handle_call({open, _Name, _Mode}, _From, State) ->
+ {reply, {error, einval}, State};
-handle_call({read_file, Name}, _From, Handle) ->
- {reply, ?PRIM_FILE:read_file(Name), Handle};
+handle_call({read_file, Name}, _From, State) ->
+ {reply, ?PRIM_FILE:read_file(Name), State};
-handle_call({write_file, Name, Bin}, _From, Handle) ->
- {reply, ?PRIM_FILE:write_file(Name, Bin), Handle};
+handle_call({write_file, Name, Bin}, _From, State) ->
+ {reply, ?PRIM_FILE:write_file(Name, Bin), State};
-handle_call({set_cwd, Name}, _From, Handle) ->
- {reply, ?PRIM_FILE:set_cwd(Handle, Name), Handle};
+handle_call({set_cwd, Name}, _From, State) ->
+ {reply, ?PRIM_FILE:set_cwd(Name), State};
-handle_call({delete, Name}, _From, Handle) ->
- {reply, ?PRIM_FILE:delete(Handle, Name), Handle};
+handle_call({delete, Name}, _From, State) ->
+ {reply, ?PRIM_FILE:delete(Name), State};
-handle_call({rename, Fr, To}, _From, Handle) ->
- {reply, ?PRIM_FILE:rename(Handle, Fr, To), Handle};
+handle_call({rename, Fr, To}, _From, State) ->
+ {reply, ?PRIM_FILE:rename(Fr, To), State};
-handle_call({make_dir, Name}, _From, Handle) ->
- {reply, ?PRIM_FILE:make_dir(Handle, Name), Handle};
+handle_call({make_dir, Name}, _From, State) ->
+ {reply, ?PRIM_FILE:make_dir(Name), State};
-handle_call({del_dir, Name}, _From, Handle) ->
- {reply, ?PRIM_FILE:del_dir(Handle, Name), Handle};
+handle_call({del_dir, Name}, _From, State) ->
+ {reply, ?PRIM_FILE:del_dir(Name), State};
-handle_call({list_dir, Name}, _From, Handle) ->
- {reply, ?PRIM_FILE:list_dir(Handle, Name), Handle};
-handle_call({list_dir_all, Name}, _From, Handle) ->
- {reply, ?PRIM_FILE:list_dir_all(Handle, Name), Handle};
+handle_call({list_dir, Name}, _From, State) ->
+ {reply, ?PRIM_FILE:list_dir(Name), State};
+handle_call({list_dir_all, Name}, _From, State) ->
+ {reply, ?PRIM_FILE:list_dir_all(Name), State};
-handle_call(get_cwd, _From, Handle) ->
- {reply, ?PRIM_FILE:get_cwd(Handle), Handle};
-handle_call({get_cwd}, _From, Handle) ->
- {reply, ?PRIM_FILE:get_cwd(Handle), Handle};
-handle_call({get_cwd, Name}, _From, Handle) ->
- {reply, ?PRIM_FILE:get_cwd(Handle, Name), Handle};
+handle_call(get_cwd, _From, State) ->
+ {reply, ?PRIM_FILE:get_cwd(), State};
+handle_call({get_cwd}, _From, State) ->
+ {reply, ?PRIM_FILE:get_cwd(), State};
+handle_call({get_cwd, Name}, _From, State) ->
+ {reply, ?PRIM_FILE:get_cwd(Name), State};
-handle_call({read_file_info, Name}, _From, Handle) ->
- {reply, ?PRIM_FILE:read_file_info(Handle, Name), Handle};
+handle_call({read_file_info, Name}, _From, State) ->
+ {reply, ?PRIM_FILE:read_file_info(Name), State};
-handle_call({read_file_info, Name, Opts}, _From, Handle) ->
- {reply, ?PRIM_FILE:read_file_info(Handle, Name, Opts), Handle};
+handle_call({read_file_info, Name, Opts}, _From, State) ->
+ {reply, ?PRIM_FILE:read_file_info(Name, Opts), State};
-handle_call({altname, Name}, _From, Handle) ->
- {reply, ?PRIM_FILE:altname(Handle, Name), Handle};
+handle_call({altname, Name}, _From, State) ->
+ {reply, ?PRIM_FILE:altname(Name), State};
-handle_call({write_file_info, Name, Info}, _From, Handle) ->
- {reply, ?PRIM_FILE:write_file_info(Handle, Name, Info), Handle};
+handle_call({write_file_info, Name, Info}, _From, State) ->
+ {reply, ?PRIM_FILE:write_file_info(Name, Info), State};
-handle_call({write_file_info, Name, Info, Opts}, _From, Handle) ->
- {reply, ?PRIM_FILE:write_file_info(Handle, Name, Info, Opts), Handle};
+handle_call({write_file_info, Name, Info, Opts}, _From, State) ->
+ {reply, ?PRIM_FILE:write_file_info(Name, Info, Opts), State};
-handle_call({read_link_info, Name}, _From, Handle) ->
- {reply, ?PRIM_FILE:read_link_info(Handle, Name), Handle};
+handle_call({read_link_info, Name}, _From, State) ->
+ {reply, ?PRIM_FILE:read_link_info(Name), State};
-handle_call({read_link_info, Name, Opts}, _From, Handle) ->
- {reply, ?PRIM_FILE:read_link_info(Handle, Name, Opts), Handle};
+handle_call({read_link_info, Name, Opts}, _From, State) ->
+ {reply, ?PRIM_FILE:read_link_info(Name, Opts), State};
-handle_call({read_link, Name}, _From, Handle) ->
- {reply, ?PRIM_FILE:read_link(Handle, Name), Handle};
-handle_call({read_link_all, Name}, _From, Handle) ->
- {reply, ?PRIM_FILE:read_link_all(Handle, Name), Handle};
+handle_call({read_link, Name}, _From, State) ->
+ {reply, ?PRIM_FILE:read_link(Name), State};
+handle_call({read_link_all, Name}, _From, State) ->
+ {reply, ?PRIM_FILE:read_link_all(Name), State};
-handle_call({make_link, Old, New}, _From, Handle) ->
- {reply, ?PRIM_FILE:make_link(Handle, Old, New), Handle};
+handle_call({make_link, Old, New}, _From, State) ->
+ {reply, ?PRIM_FILE:make_link(Old, New), State};
-handle_call({make_symlink, Old, New}, _From, Handle) ->
- {reply, ?PRIM_FILE:make_symlink(Handle, Old, New), Handle};
+handle_call({make_symlink, Old, New}, _From, State) ->
+ {reply, ?PRIM_FILE:make_symlink(Old, New), State};
handle_call({copy, SourceName, SourceOpts, DestName, DestOpts, Length},
- _From, Handle) ->
+ _From, State) ->
Reply =
case ?PRIM_FILE:open(SourceName, [read, binary | SourceOpts]) of
{ok, Source} ->
@@ -201,14 +195,14 @@ handle_call({copy, SourceName, SourceOpts, DestName, DestOpts, Length},
{error, _} = Error ->
Error
end,
- {reply, Reply, Handle};
+ {reply, Reply, State};
-handle_call(stop, _From, Handle) ->
- {stop, normal, stopped, Handle};
+handle_call(stop, _From, State) ->
+ {stop, normal, stopped, State};
-handle_call(Request, From, Handle) ->
+handle_call(Request, From, State) ->
error_logger:error_msg("handle_call(~tp, ~tp, _)", [Request, From]),
- {noreply, Handle}.
+ {noreply, State}.
%%----------------------------------------------------------------------
%% Func: handle_cast/2
@@ -231,16 +225,11 @@ handle_cast(Msg, State) ->
%%----------------------------------------------------------------------
-spec handle_info(term(), state()) ->
- {'noreply', state()} | {'stop', 'normal', state()}.
+ {'noreply', state()}.
-handle_info({'EXIT', Pid, _Reason}, Handle) when is_pid(Pid) ->
+handle_info({'EXIT', Pid, _Reason}, State) when is_pid(Pid) ->
ets:delete(?FILE_IO_SERVER_TABLE, Pid),
- {noreply, Handle};
-
-handle_info({'EXIT', Handle, _Reason}, Handle) ->
- error_logger:error_msg("Port controlling ~w terminated in ~w",
- [?FILE_SERVER, ?MODULE]),
- {stop, normal, Handle};
+ {noreply, State};
handle_info(Info, State) ->
error_logger:error_msg("handle_Info(~tp, _)", [Info]),
@@ -254,8 +243,8 @@ handle_info(Info, State) ->
-spec terminate(term(), state()) -> 'ok'.
-terminate(_Reason, Handle) ->
- ?PRIM_FILE:stop(Handle).
+terminate(_Reason, _State) ->
+ ok.
%%----------------------------------------------------------------------
%% Func: code_change/3
diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl
index a6aa0edd15..d893d44079 100644
--- a/lib/kernel/src/gen_sctp.erl
+++ b/lib/kernel/src/gen_sctp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -66,7 +66,12 @@
{sctp_set_peer_primary_addr, #sctp_setpeerprim{}} |
{sctp_status, #sctp_status{}} |
{sndbuf, non_neg_integer()} |
- {tos, non_neg_integer()}.
+ {tos, non_neg_integer()} |
+ {tclass, non_neg_integer()} |
+ {ttl, non_neg_integer()} |
+ {recvtos, boolean()} |
+ {recvtclass, boolean()} |
+ {recvttl, boolean()}.
-type option_name() ::
active |
buffer |
@@ -97,7 +102,12 @@
sctp_set_peer_primary_addr |
sctp_status |
sndbuf |
- tos.
+ tos |
+ tclass |
+ ttl |
+ recvtos |
+ recvtclass |
+ recvttl.
-type sctp_socket() :: port().
-export_type([assoc_id/0, option/0, option_name/0, sctp_socket/0]).
@@ -118,6 +128,8 @@ open() ->
| inet:address_family()
| {port,Port}
| {type,SockType}
+ | {netns, file:filename_all()}
+ | {bind_to_device, binary()}
| option(),
IP :: inet:ip_address() | any | loopback,
Port :: inet:port_number(),
@@ -363,7 +375,7 @@ send(S, AssocChange, Stream, Data) ->
Socket :: sctp_socket(),
FromIP :: inet:ip_address(),
FromPort :: inet:port_number(),
- AncData :: [#sctp_sndrcvinfo{}],
+ AncData :: [#sctp_sndrcvinfo{} | inet:ancillary_data()],
Data :: binary() | string() | #sctp_sndrcvinfo{}
| #sctp_assoc_change{} | #sctp_paddr_change{}
| #sctp_adaptation_event{},
@@ -380,7 +392,7 @@ recv(S) ->
Timeout :: timeout(),
FromIP :: inet:ip_address(),
FromPort :: inet:port_number(),
- AncData :: [#sctp_sndrcvinfo{}],
+ AncData :: [#sctp_sndrcvinfo{} | inet:ancillary_data()],
Data :: binary() | string() | #sctp_sndrcvinfo{}
| #sctp_assoc_change{} | #sctp_paddr_change{}
| #sctp_adaptation_event{},
diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl
index ac61dbc792..5d4764f8ff 100644
--- a/lib/kernel/src/gen_tcp.erl
+++ b/lib/kernel/src/gen_tcp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -62,7 +62,14 @@
{show_econnreset, boolean()} |
{sndbuf, non_neg_integer()} |
{tos, non_neg_integer()} |
+ {tclass, non_neg_integer()} |
+ {ttl, non_neg_integer()} |
+ {recvtos, boolean()} |
+ {recvtclass, boolean()} |
+ {recvttl, boolean()} |
{ipv6_v6only, boolean()}.
+-type pktoptions_value() ::
+ {pktoptions, inet:ancillary_data()}.
-type option_name() ::
active |
buffer |
@@ -81,6 +88,7 @@
nodelay |
packet |
packet_size |
+ pktoptions |
priority |
{raw,
Protocol :: non_neg_integer(),
@@ -94,6 +102,12 @@
show_econnreset |
sndbuf |
tos |
+ tclass |
+ ttl |
+ recvtos |
+ recvtclass |
+ recvttl |
+ pktoptions |
ipv6_v6only.
-type connect_option() ::
{ip, inet:socket_address()} |
@@ -102,6 +116,8 @@
inet:address_family() |
{port, inet:port_number()} |
{tcp_module, module()} |
+ {netns, file:filename_all()} |
+ {bind_to_device, binary()} |
option().
-type listen_option() ::
{ip, inet:socket_address()} |
@@ -111,11 +127,13 @@
{port, inet:port_number()} |
{backlog, B :: non_neg_integer()} |
{tcp_module, module()} |
+ {netns, file:filename_all()} |
+ {bind_to_device, binary()} |
option().
-type socket() :: port().
-export_type([option/0, option_name/0, connect_option/0, listen_option/0,
- socket/0]).
+ socket/0, pktoptions_value/0]).
%%
%% Connect a socket
@@ -138,7 +156,7 @@ connect(Address, Port, Opts) ->
Options :: [connect_option()],
Timeout :: timeout(),
Socket :: socket(),
- Reason :: inet:posix().
+ Reason :: timeout | inet:posix().
connect(Address, Port, Opts, Time) ->
Timer = inet:start_timer(Time),
@@ -202,7 +220,7 @@ listen(Port, Opts0) ->
-spec accept(ListenSocket) -> {ok, Socket} | {error, Reason} when
ListenSocket :: socket(),
Socket :: socket(),
- Reason :: closed | timeout | system_limit | inet:posix().
+ Reason :: closed | system_limit | inet:posix().
accept(S) ->
case inet_db:lookup_socket(S) of
@@ -294,7 +312,7 @@ recv(S, Length) when is_port(S) ->
Length :: non_neg_integer(),
Timeout :: timeout(),
Packet :: string() | binary() | HttpPacket,
- Reason :: closed | inet:posix(),
+ Reason :: closed | timeout | inet:posix(),
HttpPacket :: term().
recv(S, Length, Time) when is_port(S) ->
diff --git a/lib/kernel/src/gen_udp.erl b/lib/kernel/src/gen_udp.erl
index 3121544719..fad7b2f887 100644
--- a/lib/kernel/src/gen_udp.erl
+++ b/lib/kernel/src/gen_udp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -51,6 +51,11 @@
{reuseaddr, boolean()} |
{sndbuf, non_neg_integer()} |
{tos, non_neg_integer()} |
+ {tclass, non_neg_integer()} |
+ {ttl, non_neg_integer()} |
+ {recvtos, boolean()} |
+ {recvtclass, boolean()} |
+ {recvttl, boolean()} |
{ipv6_v6only, boolean()}.
-type option_name() ::
active |
@@ -76,6 +81,12 @@
reuseaddr |
sndbuf |
tos |
+ tclass |
+ ttl |
+ recvtos |
+ recvtclass |
+ recvttl |
+ pktoptions |
ipv6_v6only.
-type socket() :: port().
@@ -84,7 +95,7 @@
-spec open(Port) -> {ok, Socket} | {error, Reason} when
Port :: inet:port_number(),
Socket :: socket(),
- Reason :: inet:posix().
+ Reason :: system_limit | inet:posix().
open(Port) ->
open(Port, []).
@@ -97,9 +108,11 @@ open(Port) ->
| {ifaddr, inet:socket_address()}
| inet:address_family()
| {port, inet:port_number()}
+ | {netns, file:filename_all()}
+ | {bind_to_device, binary()}
| option(),
Socket :: socket(),
- Reason :: inet:posix().
+ Reason :: system_limit | inet:posix().
open(Port, Opts0) ->
{Mod, Opts} = inet:udp_module(Opts0),
@@ -145,11 +158,13 @@ send(S, Packet) when is_port(S) ->
end.
-spec recv(Socket, Length) ->
- {ok, {Address, Port, Packet}} | {error, Reason} when
+ {ok, RecvData} | {error, Reason} when
Socket :: socket(),
Length :: non_neg_integer(),
+ RecvData :: {Address, Port, Packet} | {Address, Port, AncData, Packet},
Address :: inet:ip_address() | inet:returned_non_ip_address(),
Port :: inet:port_number(),
+ AncData :: inet:ancillary_data(),
Packet :: string() | binary(),
Reason :: not_owner | inet:posix().
@@ -162,14 +177,16 @@ recv(S,Len) when is_port(S), is_integer(Len) ->
end.
-spec recv(Socket, Length, Timeout) ->
- {ok, {Address, Port, Packet}} | {error, Reason} when
+ {ok, RecvData} | {error, Reason} when
Socket :: socket(),
Length :: non_neg_integer(),
Timeout :: timeout(),
+ RecvData :: {Address, Port, Packet} | {Address, Port, AncData, Packet},
Address :: inet:ip_address() | inet:returned_non_ip_address(),
Port :: inet:port_number(),
+ AncData :: inet:ancillary_data(),
Packet :: string() | binary(),
- Reason :: not_owner | inet:posix().
+ Reason :: not_owner | timeout | inet:posix().
recv(S,Len,Time) when is_port(S) ->
case inet_db:lookup_socket(S) of
diff --git a/lib/kernel/src/global.erl b/lib/kernel/src/global.erl
index a38522eb5c..3875074d74 100644
--- a/lib/kernel/src/global.erl
+++ b/lib/kernel/src/global.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -50,10 +50,9 @@
%% This is for backward compatibility only; the functionality is broken.
-define(WARN_DUPLICATED_NAME, global_multi_name_action).
-%% Undocumented Kernel variable. Set this to 0 (zero) to get the old
-%% behaviour.
+%% Undocumented Kernel variable.
-define(N_CONNECT_RETRIES, global_connect_retries).
--define(DEFAULT_N_CONNECT_RETRIES, 5).
+-define(DEFAULT_N_CONNECT_RETRIES, 0).
%%% In certain places in the server, calling io:format hangs everything,
%%% so we'd better use erlang:display/1.
@@ -125,16 +124,12 @@
%%% There are also ETS tables used for bookkeeping of locks and names
%%% (the first position is the key):
%%%
-%%% global_locks (set): {ResourceId, LockRequesterId, [{Pid,RPid,ref()]}
+%%% global_locks (set): {ResourceId, LockRequesterId, [{Pid,ref()]}
%%% Pid is locking ResourceId, ref() is the monitor ref.
-%%% RPid =/= Pid if there is an extra process calling erlang:monitor().
-%%% global_names (set): {Name, Pid, Method, RPid, ref()}
+%%% global_names (set): {Name, Pid, Method, ref()}
%%% Registered names. ref() is the monitor ref.
-%%% RPid =/= Pid if there is an extra process calling erlang:monitor().
%%% global_names_ext (set): {Name, Pid, RegNode}
%%% External registered names (C-nodes).
-%%% (The RPid:s can be removed when/if erlang:monitor() returns before
-%%% trying to connect to the other node.)
%%%
%%% Helper tables:
%%% global_pid_names (bag): {Pid, Name} | {ref(), Name}
@@ -310,7 +305,7 @@ re_register_name(Name, Pid, Method0) when is_pid(Pid) ->
-spec registered_names() -> [Name] when
Name :: term().
registered_names() ->
- MS = ets:fun2ms(fun({Name,_Pid,_M,_RP,_R}) -> Name end),
+ MS = ets:fun2ms(fun({Name,_Pid,_M,_R}) -> Name end),
ets:select(global_names, MS).
%%-----------------------------------------------------------------
@@ -1235,7 +1230,7 @@ ins_name_ext(Name, Pid, Method, RegNode, FromPidOrNode, ExtraInfo, S0) ->
where(Name) ->
case ets:lookup(global_names, Name) of
- [{_Name, Pid, _Method, _RPid, _Ref}] ->
+ [{_Name, Pid, _Method, _Ref}] ->
if node(Pid) == node() ->
case is_process_alive(Pid) of
true -> Pid;
@@ -1272,10 +1267,10 @@ can_set_lock({ResourceId, LockRequesterId}) ->
end.
insert_lock({ResourceId, LockRequesterId}=Id, Pid, PidRefs, S) ->
- {RPid, Ref} = do_monitor(Pid),
+ Ref = erlang:monitor(process, Pid),
true = ets:insert(global_pid_ids, {Pid, ResourceId}),
true = ets:insert(global_pid_ids, {Ref, ResourceId}),
- Lock = {ResourceId, LockRequesterId, [{Pid,RPid,Ref} | PidRefs]},
+ Lock = {ResourceId, LockRequesterId, [{Pid,Ref} | PidRefs]},
true = ets:insert(global_locks, Lock),
trace_message(S, {ins_lock, node(Pid)}, [Id, Pid]).
@@ -1293,10 +1288,9 @@ handle_del_lock({ResourceId, LockReqId}, Pid, S0) ->
_ -> S0
end.
-remove_lock(ResourceId, LockRequesterId, Pid, [{Pid,RPid,Ref}], Down, S0) ->
+remove_lock(ResourceId, LockRequesterId, Pid, [{Pid,Ref}], Down, S0) ->
?trace({remove_lock_1, {id,ResourceId},{pid,Pid}}),
true = erlang:demonitor(Ref, [flush]),
- kill_monitor_proc(RPid, Pid),
true = ets:delete(global_locks, ResourceId),
true = ets:delete_object(global_pid_ids, {Pid, ResourceId}),
true = ets:delete_object(global_pid_ids, {Ref, ResourceId}),
@@ -1309,9 +1303,8 @@ remove_lock(ResourceId, LockRequesterId, Pid, [{Pid,RPid,Ref}], Down, S0) ->
remove_lock(ResourceId, LockRequesterId, Pid, PidRefs0, _Down, S) ->
?trace({remove_lock_2, {id,ResourceId},{pid,Pid}}),
PidRefs = case lists:keyfind(Pid, 1, PidRefs0) of
- {Pid, RPid, Ref} ->
+ {Pid, Ref} ->
true = erlang:demonitor(Ref, [flush]),
- kill_monitor_proc(RPid, Pid),
true = ets:delete_object(global_pid_ids,
{Ref, ResourceId}),
lists:keydelete(Pid, 1, PidRefs0);
@@ -1324,11 +1317,6 @@ remove_lock(ResourceId, LockRequesterId, Pid, PidRefs0, _Down, S) ->
trace_message(S, {rem_lock, node(Pid)},
[{ResourceId, LockRequesterId}, Pid]).
-kill_monitor_proc(Pid, Pid) ->
- ok;
-kill_monitor_proc(RPid, _Pid) ->
- exit(RPid, kill).
-
do_ops(Ops, ConnNode, Names_ext, ExtraInfo, S0) ->
?trace({do_ops, {ops,Ops}}),
@@ -1394,8 +1382,8 @@ sync_other(Node, N) ->
% exit(normal).
insert_global_name(Name, Pid, Method, FromPidOrNode, ExtraInfo, S) ->
- {RPid, Ref} = do_monitor(Pid),
- true = ets:insert(global_names, {Name, Pid, Method, RPid, Ref}),
+ Ref = erlang:monitor(process, Pid),
+ true = ets:insert(global_names, {Name, Pid, Method, Ref}),
true = ets:insert(global_pid_names, {Pid, Name}),
true = ets:insert(global_pid_names, {Ref, Name}),
case lock_still_set(FromPidOrNode, ExtraInfo, S) of
@@ -1437,7 +1425,7 @@ extra_info(Tag, ExtraInfo) ->
del_name(Ref, S) ->
NameL = [Name ||
{_, Name} <- ets:lookup(global_pid_names, Ref),
- {_, _Pid, _Method, _RPid, Ref1} <-
+ {_, _Pid, _Method, Ref1} <-
ets:lookup(global_names, Name),
Ref1 =:= Ref],
case NameL of
@@ -1450,24 +1438,23 @@ del_name(Ref, S) ->
%% Keeps the entry in global_names for whereis_name/1.
delete_global_name_keep_pid(Name, S) ->
case ets:lookup(global_names, Name) of
- [{Name, Pid, _Method, RPid, Ref}] ->
- delete_global_name2(Name, Pid, RPid, Ref, S);
+ [{Name, Pid, _Method, Ref}] ->
+ delete_global_name2(Name, Pid, Ref, S);
[] ->
S
end.
delete_global_name2(Name, S) ->
case ets:lookup(global_names, Name) of
- [{Name, Pid, _Method, RPid, Ref}] ->
+ [{Name, Pid, _Method, Ref}] ->
true = ets:delete(global_names, Name),
- delete_global_name2(Name, Pid, RPid, Ref, S);
+ delete_global_name2(Name, Pid, Ref, S);
[] ->
S
end.
-delete_global_name2(Name, Pid, RPid, Ref, S) ->
+delete_global_name2(Name, Pid, Ref, S) ->
true = erlang:demonitor(Ref, [flush]),
- kill_monitor_proc(RPid, Pid),
delete_global_name(Name, Pid),
?trace({delete_global_name,{item,Name},{pid,Pid}}),
true = ets:delete_object(global_pid_names, {Pid, Name}),
@@ -1929,9 +1916,9 @@ reset_node_state(Node) ->
%% from the same partition.
exchange_names([{Name, Pid, Method} | Tail], Node, Ops, Res) ->
case ets:lookup(global_names, Name) of
- [{Name, Pid, _Method, _RPid2, _Ref2}] ->
+ [{Name, Pid, _Method, _Ref2}] ->
exchange_names(Tail, Node, Ops, Res);
- [{Name, Pid2, Method2, _RPid2, _Ref2}] when node() < Node ->
+ [{Name, Pid2, Method2, _Ref2}] when node() < Node ->
%% Name clash! Add the result of resolving to Res(olved).
%% We know that node(Pid) =/= node(), so we don't
%% need to link/unlink to Pid.
@@ -1960,7 +1947,7 @@ exchange_names([{Name, Pid, Method} | Tail], Node, Ops, Res) ->
Op = {delete, Name},
exchange_names(Tail, Node, [Op | Ops], [Op | Res])
end;
- [{Name, _Pid2, _Method, _RPid, _Ref}] ->
+ [{Name, _Pid2, _Method, _Ref}] ->
%% The other node will solve the conflict.
exchange_names(Tail, Node, Ops, Res);
_ ->
@@ -2036,7 +2023,7 @@ pid_is_locking(Pid, PidRefs) ->
delete_lock(Ref, S0) ->
Locks = pid_locks(Ref),
F = fun({ResourceId, LockRequesterId, PidRefs}, S) ->
- {Pid, _RPid, Ref} = lists:keyfind(Ref, 3, PidRefs),
+ {Pid, Ref} = lists:keyfind(Ref, 2, PidRefs),
remove_lock(ResourceId, LockRequesterId, Pid, PidRefs, true, S)
end,
lists:foldl(F, S0, Locks).
@@ -2046,10 +2033,10 @@ pid_locks(Ref) ->
ets:lookup(global_locks, ResourceId)
end, ets:lookup(global_pid_ids, Ref)),
[Lock || Lock = {_Id, _Req, PidRefs} <- L,
- rpid_is_locking(Ref, PidRefs)].
+ ref_is_locking(Ref, PidRefs)].
-rpid_is_locking(Ref, PidRefs) ->
- lists:keyfind(Ref, 3, PidRefs) =/= false.
+ref_is_locking(Ref, PidRefs) ->
+ lists:keyfind(Ref, 2, PidRefs) =/= false.
handle_nodedown(Node, S) ->
%% DOWN signals from monitors have removed locks and registered names.
@@ -2062,7 +2049,7 @@ handle_nodedown(Node, S) ->
get_names() ->
ets:select(global_names,
- ets:fun2ms(fun({Name, Pid, Method, _RPid, _Ref}) ->
+ ets:fun2ms(fun({Name, Pid, Method, _Ref}) ->
{Name, Pid, Method}
end)).
@@ -2205,24 +2192,6 @@ unexpected_message(Message, What) ->
%%% Utilities
-%% When/if erlang:monitor() returns before trying to connect to the
-%% other node this function can be removed.
-do_monitor(Pid) ->
- case (node(Pid) =:= node()) orelse lists:member(node(Pid), nodes()) of
- true ->
- %% Assume the node is still up
- {Pid, erlang:monitor(process, Pid)};
- false ->
- F = fun() ->
- Ref = erlang:monitor(process, Pid),
- receive
- {'DOWN', Ref, process, Pid, _Info} ->
- exit(normal)
- end
- end,
- erlang:spawn_monitor(F)
- end.
-
intersection(_, []) ->
[];
intersection(L1, L2) ->
diff --git a/lib/kernel/src/group.erl b/lib/kernel/src/group.erl
index bf785959ff..5625ae6eb7 100644
--- a/lib/kernel/src/group.erl
+++ b/lib/kernel/src/group.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -114,7 +114,7 @@ server_loop(Drv, Shell, Buf0) ->
{io_request,From,ReplyAs,Req} when is_pid(From) ->
%% This io_request may cause a transition to a couple of
%% selective receive loops elsewhere in this module.
- Buf = io_request(Req, From, ReplyAs, Drv, Buf0),
+ Buf = io_request(Req, From, ReplyAs, Drv, Shell, Buf0),
server_loop(Drv, Shell, Buf);
{reply,{{From,ReplyAs},Reply}} ->
io_reply(From, ReplyAs, Reply),
@@ -135,7 +135,7 @@ server_loop(Drv, Shell, Buf0) ->
exit(R);
%% We want to throw away any term that we don't handle (standard
%% practice in receive loops), but not any {Drv,_} tuples which are
- %% handled in io_request/5.
+ %% handled in io_request/6.
NotDrvTuple when (not is_tuple(NotDrvTuple)) orelse
(tuple_size(NotDrvTuple) =/= 2) orelse
(element(1, NotDrvTuple) =/= Drv) ->
@@ -177,8 +177,8 @@ set_unicode_state(Drv,Bool) ->
end.
-io_request(Req, From, ReplyAs, Drv, Buf0) ->
- case io_request(Req, Drv, {From,ReplyAs}, Buf0) of
+io_request(Req, From, ReplyAs, Drv, Shell, Buf0) ->
+ case io_request(Req, Drv, Shell, {From,ReplyAs}, Buf0) of
{ok,Reply,Buf} ->
io_reply(From, ReplyAs, Reply),
Buf;
@@ -208,7 +208,7 @@ io_request(Req, From, ReplyAs, Drv, Buf0) ->
%%
%% These put requests have to be synchronous to the driver as otherwise
%% there is no guarantee that the data has actually been printed.
-io_request({put_chars,unicode,Chars}, Drv, From, Buf) ->
+io_request({put_chars,unicode,Chars}, Drv, _Shell, From, Buf) ->
case catch unicode:characters_to_binary(Chars,utf8) of
Binary when is_binary(Binary) ->
send_drv(Drv, {put_chars_sync, unicode, Binary, {From,ok}}),
@@ -216,7 +216,7 @@ io_request({put_chars,unicode,Chars}, Drv, From, Buf) ->
_ ->
{error,{error,{put_chars, unicode,Chars}},Buf}
end;
-io_request({put_chars,unicode,M,F,As}, Drv, From, Buf) ->
+io_request({put_chars,unicode,M,F,As}, Drv, _Shell, From, Buf) ->
case catch apply(M, F, As) of
Binary when is_binary(Binary) ->
send_drv(Drv, {put_chars_sync, unicode, Binary, {From,ok}}),
@@ -230,12 +230,12 @@ io_request({put_chars,unicode,M,F,As}, Drv, From, Buf) ->
{error,{error,F},Buf}
end
end;
-io_request({put_chars,latin1,Binary}, Drv, From, Buf) when is_binary(Binary) ->
+io_request({put_chars,latin1,Binary}, Drv, _Shell, From, Buf) when is_binary(Binary) ->
send_drv(Drv, {put_chars_sync, unicode,
unicode:characters_to_binary(Binary,latin1),
{From,ok}}),
{noreply,Buf};
-io_request({put_chars,latin1,Chars}, Drv, From, Buf) ->
+io_request({put_chars,latin1,Chars}, Drv, _Shell, From, Buf) ->
case catch unicode:characters_to_binary(Chars,latin1) of
Binary when is_binary(Binary) ->
send_drv(Drv, {put_chars_sync, unicode, Binary, {From,ok}}),
@@ -243,7 +243,7 @@ io_request({put_chars,latin1,Chars}, Drv, From, Buf) ->
_ ->
{error,{error,{put_chars,latin1,Chars}},Buf}
end;
-io_request({put_chars,latin1,M,F,As}, Drv, From, Buf) ->
+io_request({put_chars,latin1,M,F,As}, Drv, _Shell, From, Buf) ->
case catch apply(M, F, As) of
Binary when is_binary(Binary) ->
send_drv(Drv, {put_chars_sync, unicode,
@@ -260,30 +260,30 @@ io_request({put_chars,latin1,M,F,As}, Drv, From, Buf) ->
end
end;
-io_request({get_chars,Encoding,Prompt,N}, Drv, _From, Buf) ->
- get_chars(Prompt, io_lib, collect_chars, N, Drv, Buf, Encoding);
-io_request({get_line,Encoding,Prompt}, Drv, _From, Buf) ->
- get_chars(Prompt, io_lib, collect_line, [], Drv, Buf, Encoding);
-io_request({get_until,Encoding, Prompt,M,F,As}, Drv, _From, Buf) ->
- get_chars(Prompt, io_lib, get_until, {M,F,As}, Drv, Buf, Encoding);
-io_request({get_password,_Encoding},Drv,_From,Buf) ->
- get_password_chars(Drv, Buf);
-io_request({setopts,Opts}, Drv, _From, Buf) when is_list(Opts) ->
+io_request({get_chars,Encoding,Prompt,N}, Drv, Shell, _From, Buf) ->
+ get_chars_n(Prompt, io_lib, collect_chars, N, Drv, Shell, Buf, Encoding);
+io_request({get_line,Encoding,Prompt}, Drv, Shell, _From, Buf) ->
+ get_chars_line(Prompt, io_lib, collect_line, [], Drv, Shell, Buf, Encoding);
+io_request({get_until,Encoding, Prompt,M,F,As}, Drv, Shell, _From, Buf) ->
+ get_chars_line(Prompt, io_lib, get_until, {M,F,As}, Drv, Shell, Buf, Encoding);
+io_request({get_password,_Encoding},Drv,Shell,_From,Buf) ->
+ get_password_chars(Drv, Shell, Buf);
+io_request({setopts,Opts}, Drv, _Shell, _From, Buf) when is_list(Opts) ->
setopts(Opts, Drv, Buf);
-io_request(getopts, Drv, _From, Buf) ->
+io_request(getopts, Drv, _Shell, _From, Buf) ->
getopts(Drv, Buf);
-io_request({requests,Reqs}, Drv, From, Buf) ->
- io_requests(Reqs, {ok,ok,Buf}, From, Drv);
+io_request({requests,Reqs}, Drv, Shell, From, Buf) ->
+ io_requests(Reqs, {ok,ok,Buf}, From, Drv, Shell);
%% New in R12
-io_request({get_geometry,columns},Drv,_From,Buf) ->
+io_request({get_geometry,columns},Drv,_Shell,_From,Buf) ->
case get_tty_geometry(Drv) of
{W,_H} ->
{ok,W,Buf};
_ ->
{error,{error,enotsup},Buf}
end;
-io_request({get_geometry,rows},Drv,_From,Buf) ->
+io_request({get_geometry,rows},Drv,_Shell,_From,Buf) ->
case get_tty_geometry(Drv) of
{_W,H} ->
{ok,H,Buf};
@@ -292,40 +292,40 @@ io_request({get_geometry,rows},Drv,_From,Buf) ->
end;
%% BC with pre-R13
-io_request({put_chars,Chars}, Drv, From, Buf) ->
- io_request({put_chars,latin1,Chars}, Drv, From, Buf);
-io_request({put_chars,M,F,As}, Drv, From, Buf) ->
- io_request({put_chars,latin1,M,F,As}, Drv, From, Buf);
-io_request({get_chars,Prompt,N}, Drv, From, Buf) ->
- io_request({get_chars,latin1,Prompt,N}, Drv, From, Buf);
-io_request({get_line,Prompt}, Drv, From, Buf) ->
- io_request({get_line,latin1,Prompt}, Drv, From, Buf);
-io_request({get_until, Prompt,M,F,As}, Drv, From, Buf) ->
- io_request({get_until,latin1, Prompt,M,F,As}, Drv, From, Buf);
-io_request(get_password,Drv,From,Buf) ->
- io_request({get_password,latin1},Drv,From,Buf);
-
-
-
-io_request(_, _Drv, _From, Buf) ->
+io_request({put_chars,Chars}, Drv, Shell, From, Buf) ->
+ io_request({put_chars,latin1,Chars}, Drv, Shell, From, Buf);
+io_request({put_chars,M,F,As}, Drv, Shell, From, Buf) ->
+ io_request({put_chars,latin1,M,F,As}, Drv, Shell, From, Buf);
+io_request({get_chars,Prompt,N}, Drv, Shell, From, Buf) ->
+ io_request({get_chars,latin1,Prompt,N}, Drv, Shell, From, Buf);
+io_request({get_line,Prompt}, Drv, Shell, From, Buf) ->
+ io_request({get_line,latin1,Prompt}, Drv, Shell, From, Buf);
+io_request({get_until, Prompt,M,F,As}, Drv, Shell, From, Buf) ->
+ io_request({get_until,latin1, Prompt,M,F,As}, Drv, Shell, From, Buf);
+io_request(get_password,Drv,Shell,From,Buf) ->
+ io_request({get_password,latin1},Drv,Shell,From,Buf);
+
+
+
+io_request(_, _Drv, _Shell, _From, Buf) ->
{error,{error,request},Buf}.
-%% Status = io_requests(RequestList, PrevStat, From, Drv)
+%% Status = io_requests(RequestList, PrevStat, From, Drv, Shell)
%% Process a list of output requests as long as
%% the previous status is 'ok' or noreply.
%%
%% We use undefined as the From for all but the last request
%% in order to discards acknowledgements from those requests.
%%
-io_requests([R|Rs], {noreply,Buf}, From, Drv) ->
+io_requests([R|Rs], {noreply,Buf}, From, Drv, Shell) ->
ReqFrom = if Rs =:= [] -> From; true -> undefined end,
- io_requests(Rs, io_request(R, Drv, ReqFrom, Buf), From, Drv);
-io_requests([R|Rs], {ok,ok,Buf}, From, Drv) ->
+ io_requests(Rs, io_request(R, Drv, Shell, ReqFrom, Buf), From, Drv, Shell);
+io_requests([R|Rs], {ok,ok,Buf}, From, Drv, Shell) ->
ReqFrom = if Rs =:= [] -> From; true -> undefined end,
- io_requests(Rs, io_request(R, Drv, ReqFrom, Buf), From, Drv);
-io_requests([_|_], Error, _From, _Drv) ->
+ io_requests(Rs, io_request(R, Drv, Shell, ReqFrom, Buf), From, Drv, Shell);
+io_requests([_|_], Error, _From, _Drv, _Shell) ->
Error;
-io_requests([], Stat, _From, _) ->
+io_requests([], Stat, _From, _, _Shell) ->
Stat.
%% io_reply(From, ReplyAs, Reply)
@@ -333,7 +333,7 @@ io_requests([], Stat, _From, _) ->
%% The ACK contains the return value.
io_reply(undefined, _ReplyAs, _Reply) ->
- %% Ignore these replies as they are generated from io_requests/4.
+ %% Ignore these replies as they are generated from io_requests/5.
ok;
io_reply(From, ReplyAs, Reply) ->
From ! {io_reply,ReplyAs,Reply},
@@ -434,7 +434,7 @@ getopts(Drv,Buf) ->
{ok,[Exp,Echo,Bin,Uni],Buf}.
-%% get_chars(Prompt, Module, Function, XtraArgument, Drv, Buffer)
+%% get_chars_*(Prompt, Module, Function, XtraArgument, Drv, Buffer)
%% Gets characters from the input Drv until as the applied function
%% returns {stop,Result,Rest}. Does not block output until input has been
%% received.
@@ -442,8 +442,8 @@ getopts(Drv,Buf) ->
%% {Result,NewSaveBuffer}
%% {error,What,NewSaveBuffer}
-get_password_chars(Drv,Buf) ->
- case get_password_line(Buf, Drv) of
+get_password_chars(Drv,Shell,Buf) ->
+ case get_password_line(Buf, Drv, Shell) of
{done, Line, Buf1} ->
{ok, Line, Buf1};
interrupted ->
@@ -452,36 +452,62 @@ get_password_chars(Drv,Buf) ->
{exit, terminated}
end.
-get_chars(Prompt, M, F, Xa, Drv, Buf, Encoding) ->
+get_chars_n(Prompt, M, F, Xa, Drv, Shell, Buf, Encoding) ->
Pbs = prompt_bytes(Prompt, Encoding),
- get_chars_loop(Pbs, M, F, Xa, Drv, Buf, start, Encoding).
+ case get(echo) of
+ true ->
+ get_chars_loop(Pbs, M, F, Xa, Drv, Shell, Buf, start, Encoding);
+ false ->
+ get_chars_n_loop(Pbs, M, F, Xa, Drv, Shell, Buf, start, Encoding)
+ end.
+
+get_chars_line(Prompt, M, F, Xa, Drv, Shell, Buf, Encoding) ->
+ Pbs = prompt_bytes(Prompt, Encoding),
+ get_chars_loop(Pbs, M, F, Xa, Drv, Shell, Buf, start, Encoding).
-get_chars_loop(Pbs, M, F, Xa, Drv, Buf0, State, Encoding) ->
- Result = case get(echo) of
+get_chars_loop(Pbs, M, F, Xa, Drv, Shell, Buf0, State, Encoding) ->
+ Result = case get(echo) of
true ->
- get_line(Buf0, Pbs, Drv, Encoding);
+ get_line(Buf0, Pbs, Drv, Shell, Encoding);
false ->
% get_line_echo_off only deals with lists
% and does not need encoding...
- get_line_echo_off(Buf0, Pbs, Drv)
+ get_line_echo_off(Buf0, Pbs, Drv, Shell)
end,
case Result of
- {done,Line,Buf1} ->
- get_chars_apply(Pbs, M, F, Xa, Drv, Buf1, State, Line, Encoding);
+ {done,Line,Buf} ->
+ get_chars_apply(Pbs, M, F, Xa, Drv, Shell, Buf, State, Line, Encoding);
interrupted ->
{error,{error,interrupted},[]};
terminated ->
{exit,terminated}
end.
-get_chars_apply(Pbs, M, F, Xa, Drv, Buf, State0, Line, Encoding) ->
+get_chars_apply(Pbs, M, F, Xa, Drv, Shell, Buf, State0, Line, Encoding) ->
case catch M:F(State0, cast(Line,get(read_mode), Encoding), Encoding, Xa) of
- {stop,Result,Rest} ->
- {ok,Result,append(Rest, Buf, Encoding)};
- {'EXIT',_} ->
- {error,{error,err_func(M, F, Xa)},[]};
- State1 ->
- get_chars_loop(Pbs, M, F, Xa, Drv, Buf, State1, Encoding)
+ {stop,Result,Rest} ->
+ {ok,Result,append(Rest, Buf, Encoding)};
+ {'EXIT',_} ->
+ {error,{error,err_func(M, F, Xa)},[]};
+ State1 ->
+ get_chars_loop(Pbs, M, F, Xa, Drv, Shell, Buf, State1, Encoding)
+ end.
+
+get_chars_n_loop(Pbs, M, F, Xa, Drv, Shell, Buf0, State, Encoding) ->
+ try M:F(State, cast(Buf0, get(read_mode), Encoding), Encoding, Xa) of
+ {stop,Result,Rest} ->
+ {ok, Result, Rest};
+ State1 ->
+ case get_chars_echo_off(Pbs, Drv, Shell) of
+ interrupted ->
+ {error,{error,interrupted},[]};
+ terminated ->
+ {exit,terminated};
+ Buf ->
+ get_chars_n_loop(Pbs, M, F, Xa, Drv, Shell, Buf, State1, Encoding)
+ end
+ catch _:_ ->
+ {error,{error,err_func(M, F, Xa)},[]}
end.
%% Convert error code to make it look as before
@@ -497,24 +523,24 @@ err_func(_, F, _) ->
%% {done,LineChars,RestChars}
%% interrupted
-get_line(Chars, Pbs, Drv, Encoding) ->
+get_line(Chars, Pbs, Drv, Shell, Encoding) ->
{more_chars,Cont,Rs} = edlin:start(Pbs),
send_drv_reqs(Drv, Rs),
- get_line1(edlin:edit_line(Chars, Cont), Drv, new_stack(get(line_buffer)),
+ get_line1(edlin:edit_line(Chars, Cont), Drv, Shell, new_stack(get(line_buffer)),
Encoding).
-get_line1({done,Line,Rest,Rs}, Drv, Ls, _Encoding) ->
+get_line1({done,Line,Rest,Rs}, Drv, _Shell, Ls, _Encoding) ->
send_drv_reqs(Drv, Rs),
save_line_buffer(Line, get_lines(Ls)),
{done,Line,Rest};
-get_line1({undefined,{_A,Mode,Char},Cs,Cont,Rs}, Drv, Ls0, Encoding)
+get_line1({undefined,{_A,Mode,Char},Cs,Cont,Rs}, Drv, Shell, Ls0, Encoding)
when ((Mode =:= none) and (Char =:= $\^P))
or ((Mode =:= meta_left_sq_bracket) and (Char =:= $A)) ->
send_drv_reqs(Drv, Rs),
case up_stack(save_line(Ls0, edlin:current_line(Cont))) of
{none,_Ls} ->
send_drv(Drv, beep),
- get_line1(edlin:edit_line(Cs, Cont), Drv, Ls0, Encoding);
+ get_line1(edlin:edit_line(Cs, Cont), Drv, Shell, Ls0, Encoding);
{Lcs,Ls} ->
send_drv_reqs(Drv, edlin:erase_line(Cont)),
{more_chars,Ncont,Nrs} = edlin:start(edlin:prompt(Cont)),
@@ -522,16 +548,17 @@ get_line1({undefined,{_A,Mode,Char},Cs,Cont,Rs}, Drv, Ls0, Encoding)
get_line1(edlin:edit_line1(lists:sublist(Lcs, 1, length(Lcs)-1),
Ncont),
Drv,
+ Shell,
Ls, Encoding)
end;
-get_line1({undefined,{_A,Mode,Char},Cs,Cont,Rs}, Drv, Ls0, Encoding)
+get_line1({undefined,{_A,Mode,Char},Cs,Cont,Rs}, Drv, Shell, Ls0, Encoding)
when ((Mode =:= none) and (Char =:= $\^N))
or ((Mode =:= meta_left_sq_bracket) and (Char =:= $B)) ->
send_drv_reqs(Drv, Rs),
case down_stack(save_line(Ls0, edlin:current_line(Cont))) of
{none,_Ls} ->
send_drv(Drv, beep),
- get_line1(edlin:edit_line(Cs, Cont), Drv, Ls0, Encoding);
+ get_line1(edlin:edit_line(Cs, Cont), Drv, Shell, Ls0, Encoding);
{Lcs,Ls} ->
send_drv_reqs(Drv, edlin:erase_line(Cont)),
{more_chars,Ncont,Nrs} = edlin:start(edlin:prompt(Cont)),
@@ -539,6 +566,7 @@ get_line1({undefined,{_A,Mode,Char},Cs,Cont,Rs}, Drv, Ls0, Encoding)
get_line1(edlin:edit_line1(lists:sublist(Lcs, 1, length(Lcs)-1),
Ncont),
Drv,
+ Shell,
Ls, Encoding)
end;
%% ^R = backward search, ^S = forward search.
@@ -551,7 +579,7 @@ get_line1({undefined,{_A,Mode,Char},Cs,Cont,Rs}, Drv, Ls0, Encoding)
%% new modes: search, search_quit, search_found. These are added to
%% the regular ones (none, meta_left_sq_bracket) and handle special
%% cases of history search.
-get_line1({undefined,{_A,Mode,Char},Cs,Cont,Rs}, Drv, Ls, Encoding)
+get_line1({undefined,{_A,Mode,Char},Cs,Cont,Rs}, Drv, Shell, Ls, Encoding)
when ((Mode =:= none) and (Char =:= $\^R)) ->
send_drv_reqs(Drv, Rs),
%% drop current line, move to search mode. We store the current
@@ -561,8 +589,8 @@ get_line1({undefined,{_A,Mode,Char},Cs,Cont,Rs}, Drv, Ls, Encoding)
Pbs = prompt_bytes("(search)`': ", Encoding),
{more_chars,Ncont,Nrs} = edlin:start(Pbs, search),
send_drv_reqs(Drv, Nrs),
- get_line1(edlin:edit_line1(Cs, Ncont), Drv, Ls, Encoding);
-get_line1({expand, Before, Cs0, Cont,Rs}, Drv, Ls0, Encoding) ->
+ get_line1(edlin:edit_line1(Cs, Ncont), Drv, Shell, Ls, Encoding);
+get_line1({expand, Before, Cs0, Cont,Rs}, Drv, Shell, Ls0, Encoding) ->
send_drv_reqs(Drv, Rs),
ExpandFun = get(expand_fun),
{Found, Add, Matches} = ExpandFun(Before),
@@ -577,37 +605,37 @@ get_line1({expand, Before, Cs0, Cont,Rs}, Drv, Ls0, Encoding) ->
send_drv(Drv, {put_chars, unicode, unicode:characters_to_binary(MatchStr,unicode)}),
[$\^L | Cs1]
end,
- get_line1(edlin:edit_line(Cs, Cont), Drv, Ls0, Encoding);
-get_line1({undefined,_Char,Cs,Cont,Rs}, Drv, Ls, Encoding) ->
+ get_line1(edlin:edit_line(Cs, Cont), Drv, Shell, Ls0, Encoding);
+get_line1({undefined,_Char,Cs,Cont,Rs}, Drv, Shell, Ls, Encoding) ->
send_drv_reqs(Drv, Rs),
send_drv(Drv, beep),
- get_line1(edlin:edit_line(Cs, Cont), Drv, Ls, Encoding);
+ get_line1(edlin:edit_line(Cs, Cont), Drv, Shell, Ls, Encoding);
%% The search item was found and accepted (new line entered on the exact
%% result found)
-get_line1({_What,Cont={line,_Prompt,_Chars,search_found},Rs}, Drv, Ls0, Encoding) ->
+get_line1({_What,Cont={line,_Prompt,_Chars,search_found},Rs}, Drv, Shell, Ls0, Encoding) ->
Line = edlin:current_line(Cont),
%% this may create duplicate entries.
Ls = save_line(new_stack(get_lines(Ls0)), Line),
- get_line1({done, Line, "", Rs}, Drv, Ls, Encoding);
+ get_line1({done, Line, "", Rs}, Drv, Shell, Ls, Encoding);
%% The search mode has been exited, but the user wants to remain in line
%% editing mode wherever that was, but editing the search result.
-get_line1({What,Cont={line,_Prompt,_Chars,search_quit},Rs}, Drv, Ls, Encoding) ->
+get_line1({What,Cont={line,_Prompt,_Chars,search_quit},Rs}, Drv, Shell, Ls, Encoding) ->
Line = edlin:current_chars(Cont),
%% Load back the old prompt with the correct line number.
case get(search_quit_prompt) of
undefined -> % should not happen. Fallback.
LsFallback = save_line(new_stack(get_lines(Ls)), Line),
- get_line1({done, "\n", Line, Rs}, Drv, LsFallback, Encoding);
+ get_line1({done, "\n", Line, Rs}, Drv, Shell, LsFallback, Encoding);
Prompt -> % redraw the line and keep going with the same stack position
NCont = {line,Prompt,{lists:reverse(Line),[]},none},
send_drv_reqs(Drv, Rs),
send_drv_reqs(Drv, edlin:erase_line(Cont)),
send_drv_reqs(Drv, edlin:redraw_line(NCont)),
- get_line1({What, NCont ,[]}, Drv, pad_stack(Ls), Encoding)
+ get_line1({What, NCont ,[]}, Drv, Shell, pad_stack(Ls), Encoding)
end;
%% Search mode is entered.
get_line1({What,{line,Prompt,{RevCmd0,_Aft},search},Rs},
- Drv, Ls0, Encoding) ->
+ Drv, Shell, Ls0, Encoding) ->
send_drv_reqs(Drv, Rs),
%% Figure out search direction. ^S and ^R are returned through edlin
%% whenever we received a search while being already in search mode.
@@ -629,61 +657,90 @@ get_line1({What,{line,Prompt,{RevCmd0,_Aft},search},Rs},
{Ls2, {RevCmd, "': "++Line}}
end,
Cont = {line,Prompt,NewStack,search},
- more_data(What, Cont, Drv, Ls, Encoding);
-get_line1({What,Cont0,Rs}, Drv, Ls, Encoding) ->
+ more_data(What, Cont, Drv, Shell, Ls, Encoding);
+get_line1({What,Cont0,Rs}, Drv, Shell, Ls, Encoding) ->
send_drv_reqs(Drv, Rs),
- more_data(What, Cont0, Drv, Ls, Encoding).
+ more_data(What, Cont0, Drv, Shell, Ls, Encoding).
-more_data(What, Cont0, Drv, Ls, Encoding) ->
+more_data(What, Cont0, Drv, Shell, Ls, Encoding) ->
receive
{Drv,{data,Cs}} ->
- get_line1(edlin:edit_line(Cs, Cont0), Drv, Ls, Encoding);
+ get_line1(edlin:edit_line(Cs, Cont0), Drv, Shell, Ls, Encoding);
{Drv,eof} ->
- get_line1(edlin:edit_line(eof, Cont0), Drv, Ls, Encoding);
+ get_line1(edlin:edit_line(eof, Cont0), Drv, Shell, Ls, Encoding);
{io_request,From,ReplyAs,Req} when is_pid(From) ->
{more_chars,Cont,_More} = edlin:edit_line([], Cont0),
send_drv_reqs(Drv, edlin:erase_line(Cont)),
- io_request(Req, From, ReplyAs, Drv, []), %WRONG!!!
+ io_request(Req, From, ReplyAs, Drv, Shell, []), %WRONG!!!
send_drv_reqs(Drv, edlin:redraw_line(Cont)),
- get_line1({more_chars,Cont,[]}, Drv, Ls, Encoding);
+ get_line1({more_chars,Cont,[]}, Drv, Shell, Ls, Encoding);
{reply,{{From,ReplyAs},Reply}} ->
%% We take care of replies from puts here as well
io_reply(From, ReplyAs, Reply),
- more_data(What, Cont0, Drv, Ls, Encoding);
+ more_data(What, Cont0, Drv, Shell, Ls, Encoding);
{'EXIT',Drv,interrupt} ->
interrupted;
{'EXIT',Drv,_} ->
- terminated
+ terminated;
+ {'EXIT',Shell,R} ->
+ exit(R)
after
get_line_timeout(What)->
- get_line1(edlin:edit_line([], Cont0), Drv, Ls, Encoding)
+ get_line1(edlin:edit_line([], Cont0), Drv, Shell, Ls, Encoding)
end.
-get_line_echo_off(Chars, Pbs, Drv) ->
+get_line_echo_off(Chars, Pbs, Drv, Shell) ->
send_drv_reqs(Drv, [{put_chars, unicode,Pbs}]),
- get_line_echo_off1(edit_line(Chars,[]), Drv).
+ get_line_echo_off1(edit_line(Chars,[]), Drv, Shell).
-get_line_echo_off1({Chars,[]}, Drv) ->
+get_line_echo_off1({Chars,[]}, Drv, Shell) ->
receive
{Drv,{data,Cs}} ->
- get_line_echo_off1(edit_line(Cs, Chars), Drv);
+ get_line_echo_off1(edit_line(Cs, Chars), Drv, Shell);
{Drv,eof} ->
- get_line_echo_off1(edit_line(eof, Chars), Drv);
+ get_line_echo_off1(edit_line(eof, Chars), Drv, Shell);
{io_request,From,ReplyAs,Req} when is_pid(From) ->
- io_request(Req, From, ReplyAs, Drv, []),
- get_line_echo_off1({Chars,[]}, Drv);
+ io_request(Req, From, ReplyAs, Drv, Shell, []),
+ get_line_echo_off1({Chars,[]}, Drv, Shell);
{reply,{{From,ReplyAs},Reply}} when From =/= undefined ->
%% We take care of replies from puts here as well
io_reply(From, ReplyAs, Reply),
- get_line_echo_off1({Chars,[]},Drv);
+ get_line_echo_off1({Chars,[]},Drv, Shell);
{'EXIT',Drv,interrupt} ->
interrupted;
{'EXIT',Drv,_} ->
- terminated
+ terminated;
+ {'EXIT',Shell,R} ->
+ exit(R)
end;
-get_line_echo_off1({Chars,Rest}, _Drv) ->
+get_line_echo_off1({Chars,Rest}, _Drv, _Shell) ->
{done,lists:reverse(Chars),case Rest of done -> []; _ -> Rest end}.
+get_chars_echo_off(Pbs, Drv, Shell) ->
+ send_drv_reqs(Drv, [{put_chars, unicode,Pbs}]),
+ get_chars_echo_off1(Drv, Shell).
+
+get_chars_echo_off1(Drv, Shell) ->
+ receive
+ {Drv, {data, Cs}} ->
+ Cs;
+ {Drv, eof} ->
+ eof;
+ {io_request,From,ReplyAs,Req} when is_pid(From) ->
+ io_request(Req, From, ReplyAs, Drv, Shell, []),
+ get_chars_echo_off1(Drv, Shell);
+ {reply,{{From,ReplyAs},Reply}} when From =/= undefined ->
+ %% We take care of replies from puts here as well
+ io_reply(From, ReplyAs, Reply),
+ get_chars_echo_off1(Drv, Shell);
+ {'EXIT',Drv,interrupt} ->
+ interrupted;
+ {'EXIT',Drv,_} ->
+ terminated;
+ {'EXIT',Shell,R} ->
+ exit(R)
+ end.
+
%% We support line editing for the ICANON mode except the following
%% line editing characters, which already has another meaning in
%% echo-on mode (See Advanced Programming in the Unix Environment, 2nd ed,
@@ -793,9 +850,9 @@ search_up_stack(Stack, Substr) ->
case up_stack(Stack) of
{none,NewStack} -> {none,NewStack};
{L, NewStack} ->
- case string:str(L, Substr) of
- 0 -> search_up_stack(NewStack, Substr);
- _ -> {string:strip(L,right,$\n), NewStack}
+ case string:find(L, Substr) of
+ nomatch -> search_up_stack(NewStack, Substr);
+ _ -> {string:trim(L, trailing, "$\n"), NewStack}
end
end.
@@ -803,39 +860,41 @@ search_down_stack(Stack, Substr) ->
case down_stack(Stack) of
{none,NewStack} -> {none,NewStack};
{L, NewStack} ->
- case string:str(L, Substr) of
- 0 -> search_down_stack(NewStack, Substr);
- _ -> {string:strip(L,right,$\n), NewStack}
+ case string:find(L, Substr) of
+ nomatch -> search_down_stack(NewStack, Substr);
+ _ -> {string:trim(L, trailing, "$\n"), NewStack}
end
end.
%% This is get_line without line editing (except for backspace) and
%% without echo.
-get_password_line(Chars, Drv) ->
- get_password1(edit_password(Chars,[]),Drv).
+get_password_line(Chars, Drv, Shell) ->
+ get_password1(edit_password(Chars,[]),Drv,Shell).
-get_password1({Chars,[]}, Drv) ->
+get_password1({Chars,[]}, Drv, Shell) ->
receive
{Drv,{data,Cs}} ->
- get_password1(edit_password(Cs,Chars),Drv);
+ get_password1(edit_password(Cs,Chars),Drv,Shell);
{io_request,From,ReplyAs,Req} when is_pid(From) ->
%send_drv_reqs(Drv, [{delete_chars, -length(Pbs)}]),
- io_request(Req, From, ReplyAs, Drv, []), %WRONG!!!
+ io_request(Req, From, ReplyAs, Drv, Shell, []), %WRONG!!!
%% I guess the reason the above line is wrong is that Buf is
%% set to []. But do we expect anything but plain output?
- get_password1({Chars, []}, Drv);
+ get_password1({Chars, []}, Drv, Shell);
{reply,{{From,ReplyAs},Reply}} ->
%% We take care of replies from puts here as well
io_reply(From, ReplyAs, Reply),
- get_password1({Chars, []},Drv);
+ get_password1({Chars, []},Drv, Shell);
{'EXIT',Drv,interrupt} ->
interrupted;
{'EXIT',Drv,_} ->
- terminated
+ terminated;
+ {'EXIT',Shell,R} ->
+ exit(R)
end;
-get_password1({Chars,Rest},Drv) ->
+get_password1({Chars,Rest},Drv,_Shell) ->
send_drv_reqs(Drv,[{put_chars, unicode, "\n"}]),
{done,lists:reverse(Chars),case Rest of done -> []; _ -> Rest end}.
diff --git a/lib/kernel/src/hipe_unified_loader.erl b/lib/kernel/src/hipe_unified_loader.erl
index f8199fcf71..5704cc79c2 100644
--- a/lib/kernel/src/hipe_unified_loader.erl
+++ b/lib/kernel/src/hipe_unified_loader.erl
@@ -275,6 +275,7 @@ needs_trampolines(Architecture) ->
arm -> true;
powerpc -> true;
ppc64 -> true;
+ amd64 -> true;
_ -> false
end.
@@ -452,7 +453,7 @@ make_beam_stub(Mod, LoaderState, MD5, Beam, FunDefs, ClosuresToPatch) ->
%%========================================================================
%% Patching
%% @spec patch(refs(), BaseAddress::integer(), ConstAndZone::term(),
-%% FunDefs::term(), TrampolineMap::term()) -> 'ok'.
+%% FunDefs::term(), TrampolineMap::term()) -> 'ok'
%% @type refs()=[{RefType::integer(), Reflist::reflist()} | refs()]
%%
%% @type reflist()= [{Data::term(), Offsets::offests()}|reflist()]
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index dc20c21c77..9f22eb6aaa 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -34,7 +34,8 @@
ip/1, stats/0, options/0,
pushf/3, popf/1, close/1, gethostname/0, gethostname/1,
parse_ipv4_address/1, parse_ipv6_address/1, parse_ipv4strict_address/1,
- parse_ipv6strict_address/1, parse_address/1, parse_strict_address/1, ntoa/1]).
+ parse_ipv6strict_address/1, parse_address/1, parse_strict_address/1,
+ ntoa/1, ipv4_mapped_ipv6_address/1]).
-export([connect_options/2, listen_options/2, udp_options/2, sctp_options/2]).
-export([udp_module/1, tcp_module/1, tcp_module/2, sctp_module/1]).
@@ -72,10 +73,10 @@
%% timer interface
-export([start_timer/1, timeout/1, timeout/2, stop_timer/1]).
--export_type([address_family/0, hostent/0, hostname/0, ip4_address/0,
+-export_type([address_family/0, socket_protocol/0, hostent/0, hostname/0, ip4_address/0,
ip6_address/0, ip_address/0, port_number/0,
local_address/0, socket_address/0, returned_non_ip_address/0,
- socket_setopt/0, socket_getopt/0,
+ socket_setopt/0, socket_getopt/0, ancillary_data/0,
posix/0, socket/0, stat_option/0]).
%% imports
-import(lists, [append/1, duplicate/2, filter/2, foldl/3]).
@@ -104,7 +105,20 @@
{local, binary()} |
{unspec, <<>>} |
{undefined, any()}.
--type posix() :: exbadport | exbadseq | file:posix().
+-type posix() ::
+ 'eaddrinuse' | 'eaddrnotavail' | 'eafnosupport' | 'ealready' |
+ 'econnaborted' | 'econnrefused' | 'econnreset' |
+ 'edestaddrreq' |
+ 'ehostdown' | 'ehostunreach' |
+ 'einprogress' | 'eisconn' |
+ 'emsgsize' |
+ 'enetdown' | 'enetunreach' |
+ 'enopkg' | 'enoprotoopt' | 'enotconn' | 'enotty' | 'enotsock' |
+ 'eproto' | 'eprotonosupport' | 'eprototype' |
+ 'esocktnosupport' |
+ 'etimedout' |
+ 'ewouldblock' |
+ 'exbadport' | 'exbadseq' | file:posix().
-type socket() :: port().
-type socket_setopt() ::
@@ -140,6 +154,15 @@
'running' | 'multicast' | 'loopback']} |
{'hwaddr', ether_address()}.
+-type getifaddrs_ifopts() ::
+ [Ifopt :: {flags, Flags :: [up | broadcast | loopback |
+ pointtopoint | running | multicast]} |
+ {addr, Addr :: ip_address()} |
+ {netmask, Netmask :: ip_address()} |
+ {broadaddr, Broadaddr :: ip_address()} |
+ {dstaddr, Dstaddr :: ip_address()} |
+ {hwaddr, Hwaddr :: [byte()]}].
+
-type address_family() :: 'inet' | 'inet6' | 'local'.
-type socket_protocol() :: 'tcp' | 'udp' | 'sctp'.
-type socket_type() :: 'stream' | 'dgram' | 'seqpacket'.
@@ -149,6 +172,9 @@
'recv_cnt' | 'recv_max' | 'recv_avg' | 'recv_oct' | 'recv_dvi' |
'send_cnt' | 'send_max' | 'send_avg' | 'send_oct' | 'send_pend'.
+-type ancillary_data() ::
+ [ {'tos', byte()} | {'tclass', byte()} | {'ttl', byte()} ].
+
%%% ---------------------------------
-spec get_rc() -> [{Par :: atom(), Val :: any()} |
@@ -288,7 +314,7 @@ setopts(Socket, Opts) ->
{'ok', OptionValues} | {'error', posix()} when
Socket :: socket(),
Options :: [socket_getopt()],
- OptionValues :: [socket_setopt()].
+ OptionValues :: [socket_setopt() | gen_tcp:pktoptions_value()].
getopts(Socket, Opts) ->
case prim_inet:getopts(Socket, Opts) of
@@ -304,32 +330,32 @@ getopts(Socket, Opts) ->
Other
end.
--spec getifaddrs(Socket :: socket()) ->
- {'ok', [string()]} | {'error', posix()}.
-
+-spec getifaddrs(
+ [Option :: {netns, Namespace :: file:filename_all()}]
+ | socket()) ->
+ {'ok', [{Ifname :: string(),
+ Ifopts :: getifaddrs_ifopts()}]}
+ | {'error', posix()}.
+getifaddrs(Opts) when is_list(Opts) ->
+ withsocket(fun(S) -> prim_inet:getifaddrs(S) end, Opts);
getifaddrs(Socket) ->
prim_inet:getifaddrs(Socket).
--spec getifaddrs() -> {ok, Iflist} | {error, posix()} when
- Iflist :: [{Ifname,[Ifopt]}],
- Ifname :: string(),
- Ifopt :: {flags,[Flag]} | {addr,Addr} | {netmask,Netmask}
- | {broadaddr,Broadaddr} | {dstaddr,Dstaddr}
- | {hwaddr,Hwaddr},
- Flag :: up | broadcast | loopback | pointtopoint
- | running | multicast,
- Addr :: ip_address(),
- Netmask :: ip_address(),
- Broadaddr :: ip_address(),
- Dstaddr :: ip_address(),
- Hwaddr :: [byte()].
-
+-spec getifaddrs() ->
+ {'ok', [{Ifname :: string(),
+ Ifopts :: getifaddrs_ifopts()}]}
+ | {'error', posix()}.
getifaddrs() ->
withsocket(fun(S) -> prim_inet:getifaddrs(S) end).
--spec getiflist(Socket :: socket()) ->
- {'ok', [string()]} | {'error', posix()}.
+-spec getiflist(
+ [Option :: {netns, Namespace :: file:filename_all()}]
+ | socket()) ->
+ {'ok', [string()]} | {'error', posix()}.
+
+getiflist(Opts) when is_list(Opts) ->
+ withsocket(fun(S) -> prim_inet:getiflist(S) end, Opts);
getiflist(Socket) ->
prim_inet:getiflist(Socket).
@@ -346,11 +372,19 @@ getiflist() ->
ifget(Socket, Name, Opts) ->
prim_inet:ifget(Socket, Name, Opts).
--spec ifget(Name :: string() | atom(), Opts :: [if_getopt()]) ->
+-spec ifget(
+ Name :: string() | atom(),
+ Opts :: [if_getopt() |
+ {netns, Namespace :: file:filename_all()}]) ->
{'ok', [if_getopt_result()]} | {'error', posix()}.
ifget(Name, Opts) ->
- withsocket(fun(S) -> prim_inet:ifget(S, Name, Opts) end).
+ {NSOpts,IFOpts} =
+ lists:partition(
+ fun ({netns,_}) -> true;
+ (_) -> false
+ end, Opts),
+ withsocket(fun(S) -> prim_inet:ifget(S, Name, IFOpts) end, NSOpts).
-spec ifset(Socket :: socket(),
Name :: string() | atom(),
@@ -360,11 +394,19 @@ ifget(Name, Opts) ->
ifset(Socket, Name, Opts) ->
prim_inet:ifset(Socket, Name, Opts).
--spec ifset(Name :: string() | atom(), Opts :: [if_setopt()]) ->
+-spec ifset(
+ Name :: string() | atom(),
+ Opts :: [if_setopt() |
+ {netns, Namespace :: file:filename_all()}]) ->
'ok' | {'error', posix()}.
ifset(Name, Opts) ->
- withsocket(fun(S) -> prim_inet:ifset(S, Name, Opts) end).
+ {NSOpts,IFOpts} =
+ lists:partition(
+ fun ({netns,_}) -> true;
+ (_) -> false
+ end, Opts),
+ withsocket(fun(S) -> prim_inet:ifset(S, Name, IFOpts) end, NSOpts).
-spec getif() ->
{'ok', [{ip_address(), ip_address() | 'undefined', ip_address()}]} |
@@ -374,10 +416,14 @@ getif() ->
withsocket(fun(S) -> getif(S) end).
%% backwards compatible getif
--spec getif(Socket :: socket()) ->
+-spec getif(
+ [Option :: {netns, Namespace :: file:filename_all()}]
+ | socket()) ->
{'ok', [{ip_address(), ip_address() | 'undefined', ip_address()}]} |
{'error', posix()}.
+getif(Opts) when is_list(Opts) ->
+ withsocket(fun(S) -> getif(S) end, Opts);
getif(Socket) ->
case prim_inet:getiflist(Socket) of
{ok, IfList} ->
@@ -398,7 +444,10 @@ getif(Socket) ->
end.
withsocket(Fun) ->
- case inet_udp:open(0,[]) of
+ withsocket(Fun, []).
+%%
+withsocket(Fun, Opts) ->
+ case inet_udp:open(0, Opts) of
{ok,Socket} ->
Res = Fun(Socket),
inet_udp:close(Socket),
@@ -675,6 +724,14 @@ parse_address(Addr) ->
parse_strict_address(Addr) ->
inet_parse:strict_address(Addr).
+-spec ipv4_mapped_ipv6_address(ip_address()) -> ip_address().
+ipv4_mapped_ipv6_address({D1,D2,D3,D4})
+ when (D1 bor D2 bor D3 bor D4) < 256 ->
+ {0,0,0,0,0,16#ffff,(D1 bsl 8) bor D2,(D3 bsl 8) bor D4};
+ipv4_mapped_ipv6_address({D1,D2,D3,D4,D5,D6,D7,D8})
+ when (D1 bor D2 bor D3 bor D4 bor D5 bor D6 bor D7 bor D8) < 65536 ->
+ {D7 bsr 8,D7 band 255,D8 bsr 8,D8 band 255}.
+
%% Return a list of available options
options() ->
[
@@ -700,6 +757,7 @@ stats() ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
connect_options() ->
[tos, tclass, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay,
+ recvtos, recvtclass, ttl, recvttl,
header, active, packet, packet_size, buffer, mode, deliver, line_delimiter,
exit_on_close, high_watermark, low_watermark, high_msgq_watermark,
low_msgq_watermark, send_timeout, send_timeout_close, delay_send, raw,
@@ -768,6 +826,7 @@ con_add(Name, Val, #connect_opts{} = R, Opts, AllOpts) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
listen_options() ->
[tos, tclass, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay,
+ recvtos, recvtclass, ttl, recvttl,
header, active, packet, buffer, mode, deliver, backlog, ipv6_v6only,
exit_on_close, high_watermark, low_watermark, high_msgq_watermark,
low_msgq_watermark, send_timeout, send_timeout_close, delay_send,
@@ -848,7 +907,7 @@ tcp_module_1(Opts, Address) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
udp_options() ->
[tos, tclass, priority, reuseaddr, sndbuf, recbuf, header, active, buffer, mode,
- deliver, ipv6_v6only,
+ recvtos, recvtclass, ttl, recvttl, deliver, ipv6_v6only,
broadcast, dontroute, multicast_if, multicast_ttl, multicast_loop,
add_membership, drop_membership, read_packets,raw,
high_msgq_watermark, low_msgq_watermark, bind_to_device].
@@ -918,8 +977,10 @@ udp_module(Opts) ->
% (*) passing of open FDs ("fdopen") is not supported.
sctp_options() ->
[ % The following are generic inet options supported for SCTP sockets:
- mode, active, buffer, tos, tclass, priority, dontroute, reuseaddr, linger, sndbuf,
- recbuf, ipv6_v6only, high_msgq_watermark, low_msgq_watermark,
+ mode, active, buffer, tos, tclass, ttl,
+ priority, dontroute, reuseaddr, linger,
+ recvtos, recvtclass, recvttl,
+ sndbuf, recbuf, ipv6_v6only, high_msgq_watermark, low_msgq_watermark,
bind_to_device,
% Other options are SCTP-specific (though they may be similar to their
@@ -1244,9 +1305,7 @@ gethostbyname_string(Name, Type)
inet ->
inet_parse:ipv4_address(Name);
inet6 ->
- %% XXX should we really translate IPv4 addresses here
- %% even if we do not know if this host can do IPv6?
- inet_parse:ipv6_address(Name)
+ inet_parse:ipv6strict_address(Name)
end of
{ok,IP} ->
{ok,make_hostent(Name, [IP], [], Type)};
@@ -1452,11 +1511,14 @@ fdopen(Fd, Addr, Port, Opts, Protocol, Family, Type, Module) ->
%% socket stat
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-spec i() -> ok.
i() -> i(tcp), i(udp), i(sctp).
+-spec i(socket_protocol()) -> ok.
i(Proto) -> i(Proto, [port, module, recv, sent, owner,
local_address, foreign_address, state, type]).
+-spec i(socket_protocol(), [atom()]) -> ok.
i(tcp, Fs) ->
ii(tcp_sockets(), Fs, tcp);
i(udp, Fs) ->
diff --git a/lib/kernel/src/inet6_tcp.erl b/lib/kernel/src/inet6_tcp.erl
index a0d5d3df70..347b8b9a1b 100644
--- a/lib/kernel/src/inet6_tcp.erl
+++ b/lib/kernel/src/inet6_tcp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -167,7 +167,7 @@ listen(Port, Opts) ->
%% Accept
%%
accept(L) ->
- case prim_inet:accept(L) of
+ case prim_inet:accept(L, accept_family_opts()) of
{ok, S} ->
inet_db:register_socket(S, ?MODULE),
{ok,S};
@@ -175,13 +175,15 @@ accept(L) ->
end.
accept(L, Timeout) ->
- case prim_inet:accept(L, Timeout) of
+ case prim_inet:accept(L, Timeout, accept_family_opts()) of
{ok, S} ->
inet_db:register_socket(S, ?MODULE),
{ok,S};
Error -> Error
end.
+accept_family_opts() -> [tclass, recvtclass].
+
%%
%% Create a port/socket from a file descriptor
%%
diff --git a/lib/kernel/src/inet_config.erl b/lib/kernel/src/inet_config.erl
index 4bbc520449..e771461b65 100644
--- a/lib/kernel/src/inet_config.erl
+++ b/lib/kernel/src/inet_config.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -98,7 +98,7 @@ init() ->
{win32,WinType} ->
win32_load_from_registry(WinType);
_ ->
- error("can not read win32 system registry~n", [])
+ error("cannot read win32 system registry~n", [])
end
end, CfgFiles),
@@ -369,7 +369,7 @@ win32_load1(Reg,Type,HFileKey) ->
end.
win32_split_line(Line,nt) -> inet_parse:split_line(Line);
-win32_split_line(Line,windows) -> string:tokens(Line, ",").
+win32_split_line(Line,windows) -> string:lexemes(Line, ",").
win32_get_strings(Reg, Names) ->
win32_get_strings(Reg, Names, []).
diff --git a/lib/kernel/src/inet_db.erl b/lib/kernel/src/inet_db.erl
index 6cbb6ac2da..630ef5d2f7 100644
--- a/lib/kernel/src/inet_db.erl
+++ b/lib/kernel/src/inet_db.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1223,7 +1223,11 @@ handle_set_file(Option, Fname, TagTm, TagInfo, ParseFun, From,
{ok, B, _} -> B;
_ -> <<>>
end;
- _ -> <<>>
+ _ ->
+ ets:insert(Db, {TagInfo, undefined}),
+ TimeZero = - (?RES_FILE_UPDATE_TM + 1), % Early enough
+ ets:insert(Db, {TagTm, TimeZero}),
+ <<>>
end,
handle_set_file(ParseFun, Bin, From, State);
false -> {reply,error,State}
diff --git a/lib/kernel/src/inet_dns.erl b/lib/kernel/src/inet_dns.erl
index d5f982cc51..6c98d2aab7 100644
--- a/lib/kernel/src/inet_dns.erl
+++ b/lib/kernel/src/inet_dns.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@
-export([decode/1, encode/1]).
--import(lists, [reverse/1, reverse/2, nthtail/2]).
+-import(lists, [reverse/1]).
-include("inet_int.hrl").
-include("inet_dns.hrl").
@@ -473,7 +473,7 @@ decode_data(<<Order:16,Preference:16,Data0/binary>>, _, ?S_NAPTR, Buffer) ->
{Data2,Services} = decode_string(Data1),
{Data,Regexp} = decode_characters(Data2, utf8),
Replacement = decode_domain(Data, Buffer),
- {Order,Preference,string:to_lower(Flags),string:to_lower(Services),
+ {Order,Preference,string:lowercase(Flags),string:lowercase(Services),
Regexp,Replacement};
%% ?S_OPT falls through to default
decode_data(Data, _, ?S_TXT, _) ->
@@ -699,7 +699,7 @@ encode_labels(Bin, Comp0, Pos, [L|Ls]=Labels)
none ->
Comp = if Pos < (3 bsl 14) ->
%% Just in case - compression
- %% pointers can not reach further
+ %% pointers cannot reach further
gb_trees:insert(Labels, Pos, Comp0);
true -> Comp0
end,
diff --git a/lib/kernel/src/inet_hosts.erl b/lib/kernel/src/inet_hosts.erl
index 0bdf00ac30..fc653bf0d3 100644
--- a/lib/kernel/src/inet_hosts.erl
+++ b/lib/kernel/src/inet_hosts.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -72,9 +72,6 @@ gethostbyname(Name, Type, Byname, Byaddr) ->
gethostbyaddr({A,B,C,D}=IP) when ?ip(A,B,C,D) ->
gethostbyaddr(IP, inet);
-%% ipv4 only ipv6 address
-gethostbyaddr({0,0,0,0,0,16#ffff=F,G,H}) when ?ip6(0,0,0,0,0,F,G,H) ->
- gethostbyaddr({G bsr 8, G band 255, H bsr 8, H band 255});
gethostbyaddr({A,B,C,D,E,F,G,H}=IP) when ?ip6(A,B,C,D,E,F,G,H) ->
gethostbyaddr(IP, inet6);
gethostbyaddr(Addr) when is_list(Addr) ->
diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl
index bc5b67f7bf..f6525d7261 100644
--- a/lib/kernel/src/inet_int.hrl
+++ b/lib/kernel/src/inet_int.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -100,6 +100,8 @@
-define(TCP_REQ_RECV, 42).
-define(TCP_REQ_UNRECV, 43).
-define(TCP_REQ_SHUTDOWN, 44).
+-define(TCP_REQ_SENDFILE, 45).
+
%% UDP and SCTP requests
-define(PACKET_REQ_RECV, 60).
%%-define(SCTP_REQ_LISTEN, 61). MERGED
@@ -155,6 +157,12 @@
-define(INET_LOPT_LINE_DELIM, 40).
-define(INET_OPT_TCLASS, 41).
-define(INET_OPT_BIND_TO_DEVICE, 42).
+-define(INET_OPT_RECVTOS, 43).
+-define(INET_OPT_RECVTCLASS, 44).
+-define(INET_OPT_PKTOPTIONS, 45).
+-define(INET_OPT_TTL, 46).
+-define(INET_OPT_RECVTTL, 47).
+-define(TCP_OPT_NOPUSH, 48).
% Specific SCTP options: separate range:
-define(SCTP_OPT_RTOINFO, 100).
-define(SCTP_OPT_ASSOCINFO, 101).
@@ -319,6 +327,12 @@
[((X) bsr 24) band 16#ff, ((X) bsr 16) band 16#ff,
((X) bsr 8) band 16#ff, (X) band 16#ff]).
+-define(int64(X),
+ [((X) bsr 56) band 16#ff, ((X) bsr 48) band 16#ff,
+ ((X) bsr 40) band 16#ff, ((X) bsr 32) band 16#ff,
+ ((X) bsr 24) band 16#ff, ((X) bsr 16) band 16#ff,
+ ((X) bsr 8) band 16#ff, (X) band 16#ff]).
+
-define(intAID(X), % For SCTP AssocID
?int32(X)).
diff --git a/lib/kernel/src/inet_parse.erl b/lib/kernel/src/inet_parse.erl
index 29804dc50b..e9685c6554 100644
--- a/lib/kernel/src/inet_parse.erl
+++ b/lib/kernel/src/inet_parse.erl
@@ -95,7 +95,7 @@ hosts(Fname,File) ->
%% interface with a %if suffix. These kind of
%% addresses maybe need to be gracefully handled
%% throughout inet* and inet_drv.
- case string:tokens(Address, "%") of
+ case string:lexemes(Address, "%") of
[Addr,_] ->
{ok,_} = address(Addr),
skip;
@@ -407,7 +407,7 @@ is_dom1([C | Cs]) when C >= $a, C =< $z -> is_dom_ldh(Cs);
is_dom1([C | Cs]) when C >= $A, C =< $Z -> is_dom_ldh(Cs);
is_dom1([C | Cs]) when C >= $0, C =< $9 ->
case is_dom_ldh(Cs) of
- true -> is_dom2(string:tokens([C | Cs],"."));
+ true -> is_dom2(string:lexemes([C | Cs],"."));
false -> false
end;
is_dom1(_) -> false.
diff --git a/lib/kernel/src/inet_res.erl b/lib/kernel/src/inet_res.erl
index 90e49ddfdf..6454802b04 100644
--- a/lib/kernel/src/inet_res.erl
+++ b/lib/kernel/src/inet_res.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -349,9 +349,6 @@ gethostbyaddr_tm({A,B,C,D} = IP, Timer) when ?ip(A,B,C,D) ->
{ok, HEnt} -> {ok, HEnt};
_ -> res_gethostbyaddr(dn_in_addr_arpa(A,B,C,D), IP, Timer)
end;
-%% ipv4 only ipv6 address
-gethostbyaddr_tm({0,0,0,0,0,16#ffff,G,H},Timer) when is_integer(G+H) ->
- gethostbyaddr_tm({G div 256, G rem 256, H div 256, H rem 256},Timer);
gethostbyaddr_tm({A,B,C,D,E,F,G,H} = IP, Timer) when ?ip6(A,B,C,D,E,F,G,H) ->
inet_db:res_update_conf(),
case inet_db:gethostbyaddr(IP) of
@@ -431,28 +428,7 @@ gethostbyname(Name,Family,Timeout) ->
gethostbyname_tm(Name,inet,Timer) ->
getbyname_tm(Name,?S_A,Timer);
gethostbyname_tm(Name,inet6,Timer) ->
- case getbyname_tm(Name,?S_AAAA,Timer) of
- {ok,HEnt} -> {ok,HEnt};
- {error,nxdomain} ->
- case getbyname_tm(Name, ?S_A,Timer) of
- {ok, HEnt} ->
- %% rewrite to a ipv4 only ipv6 address
- {ok,
- HEnt#hostent {
- h_addrtype = inet6,
- h_length = 16,
- h_addr_list =
- lists:map(
- fun({A,B,C,D}) ->
- {0,0,0,0,0,16#ffff,A*256+B,C*256+D}
- end, HEnt#hostent.h_addr_list)
- }};
- Error ->
- Error
- end;
- Error ->
- Error
- end;
+ getbyname_tm(Name,?S_AAAA,Timer);
gethostbyname_tm(_Name, _Family, _Timer) ->
{error, einval}.
@@ -859,15 +835,17 @@ query_ns(S0, Id, Buffer, IP, Port, Timer, Retry, I,
{ok,S} ->
Timeout =
inet:timeout( (Tm * (1 bsl I)) div Retry, Timer),
- {S,
case query_udp(
S, Id, Buffer, IP, Port, Timeout, Verbose) of
{ok,#dns_rec{header=H}} when H#dns_header.tc ->
TcpTimeout = inet:timeout(Tm*5, Timer),
- query_tcp(
- TcpTimeout, Id, Buffer, IP, Port, Verbose);
- Reply -> Reply
- end};
+ {S, query_tcp(
+ TcpTimeout, Id, Buffer, IP, Port, Verbose)};
+ {error, econnrefused} = Err ->
+ ok = udp_close(S),
+ {#sock{}, Err};
+ Reply -> {S, Reply}
+ end;
Error ->
{S0,Error}
end
diff --git a/lib/kernel/src/inet_tcp.erl b/lib/kernel/src/inet_tcp.erl
index dac6b3119d..f1e3116856 100644
--- a/lib/kernel/src/inet_tcp.erl
+++ b/lib/kernel/src/inet_tcp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -164,7 +164,7 @@ listen(Port, Opts) ->
%% Accept
%%
accept(L) ->
- case prim_inet:accept(L) of
+ case prim_inet:accept(L, accept_family_opts()) of
{ok, S} ->
inet_db:register_socket(S, ?MODULE),
{ok,S};
@@ -172,13 +172,15 @@ accept(L) ->
end.
accept(L, Timeout) ->
- case prim_inet:accept(L, Timeout) of
+ case prim_inet:accept(L, Timeout, accept_family_opts()) of
{ok, S} ->
inet_db:register_socket(S, ?MODULE),
{ok,S};
Error -> Error
end.
+accept_family_opts() -> [tos, ttl, recvtos, recvttl].
+
%%
%% Create a port/socket from a file descriptor
%%
diff --git a/lib/kernel/src/inet_tcp_dist.erl b/lib/kernel/src/inet_tcp_dist.erl
index e3fdb1bb22..c5a114a9ef 100644
--- a/lib/kernel/src/inet_tcp_dist.erl
+++ b/lib/kernel/src/inet_tcp_dist.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -212,6 +212,7 @@ do_accept(Driver, Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
[{active, true},
{deliver, port},
{packet, 4},
+ binary,
nodelay()])
end,
f_getll = fun(S) ->
@@ -283,73 +284,22 @@ do_setup(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) ->
?trace("~p~n",[{inet_tcp_dist,self(),setup,Node}]),
[Name, Address] = splitnode(Driver, Node, LongOrShortNames),
AddressFamily = Driver:family(),
- case inet:getaddr(Address, AddressFamily) of
+ ErlEpmd = net_kernel:epmd_module(),
+ {ARMod, ARFun} = get_address_resolver(ErlEpmd),
+ Timer = dist_util:start_timer(SetupTime),
+ case ARMod:ARFun(Name, Address, AddressFamily) of
+ {ok, Ip, TcpPort, Version} ->
+ ?trace("address_please(~p) -> version ~p~n",
+ [Node,Version]),
+ do_setup_connect(Driver, Kernel, Node, Address, AddressFamily,
+ Ip, TcpPort, Version, Type, MyNode, Timer);
{ok, Ip} ->
- Timer = dist_util:start_timer(SetupTime),
- ErlEpmd = net_kernel:epmd_module(),
case ErlEpmd:port_please(Name, Ip) of
{port, TcpPort, Version} ->
?trace("port_please(~p) -> version ~p~n",
[Node,Version]),
- dist_util:reset_timer(Timer),
- case
- Driver:connect(
- Ip, TcpPort,
- connect_options([{active, false}, {packet, 2}]))
- of
- {ok, Socket} ->
- HSData = #hs_data{
- kernel_pid = Kernel,
- other_node = Node,
- this_node = MyNode,
- socket = Socket,
- timer = Timer,
- this_flags = 0,
- other_version = Version,
- f_send = fun Driver:send/2,
- f_recv = fun Driver:recv/3,
- f_setopts_pre_nodeup =
- fun(S) ->
- inet:setopts
- (S,
- [{active, false},
- {packet, 4},
- nodelay()])
- end,
- f_setopts_post_nodeup =
- fun(S) ->
- inet:setopts
- (S,
- [{active, true},
- {deliver, port},
- {packet, 4},
- nodelay()])
- end,
-
- f_getll = fun inet:getll/1,
- f_address =
- fun(_,_) ->
- #net_address{
- address = {Ip,TcpPort},
- host = Address,
- protocol = tcp,
- family = AddressFamily}
- end,
- mf_tick = fun(S) -> ?MODULE:tick(Driver, S) end,
- mf_getstat = fun ?MODULE:getstat/1,
- request_type = Type,
- mf_setopts = fun ?MODULE:setopts/2,
- mf_getopts = fun ?MODULE:getopts/2
- },
- dist_util:handshake_we_started(HSData);
- _ ->
- %% Other Node may have closed since
- %% port_please !
- ?trace("other node (~p) "
- "closed since port_please.~n",
- [Node]),
- ?shutdown(Node)
- end;
+ do_setup_connect(Driver, Kernel, Node, Address, AddressFamily,
+ Ip, TcpPort, Version, Type, MyNode, Timer);
_ ->
?trace("port_please (~p) "
"failed.~n", [Node]),
@@ -361,6 +311,71 @@ do_setup(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) ->
?shutdown(Node)
end.
+%%
+%% Actual setup of connection
+%%
+do_setup_connect(Driver, Kernel, Node, Address, AddressFamily,
+ Ip, TcpPort, Version, Type, MyNode, Timer) ->
+ dist_util:reset_timer(Timer),
+ case
+ Driver:connect(
+ Ip, TcpPort,
+ connect_options([{active, false}, {packet, 2}]))
+ of
+ {ok, Socket} ->
+ HSData = #hs_data{
+ kernel_pid = Kernel,
+ other_node = Node,
+ this_node = MyNode,
+ socket = Socket,
+ timer = Timer,
+ this_flags = 0,
+ other_version = Version,
+ f_send = fun Driver:send/2,
+ f_recv = fun Driver:recv/3,
+ f_setopts_pre_nodeup =
+ fun(S) ->
+ inet:setopts
+ (S,
+ [{active, false},
+ {packet, 4},
+ nodelay()])
+ end,
+ f_setopts_post_nodeup =
+ fun(S) ->
+ inet:setopts
+ (S,
+ [{active, true},
+ {deliver, port},
+ {packet, 4},
+ nodelay()])
+ end,
+
+ f_getll = fun inet:getll/1,
+ f_address =
+ fun(_,_) ->
+ #net_address{
+ address = {Ip,TcpPort},
+ host = Address,
+ protocol = tcp,
+ family = AddressFamily}
+ end,
+ mf_tick = fun(S) -> ?MODULE:tick(Driver, S) end,
+ mf_getstat = fun ?MODULE:getstat/1,
+ request_type = Type,
+ mf_setopts = fun ?MODULE:setopts/2,
+ mf_getopts = fun ?MODULE:getopts/2
+ },
+ dist_util:handshake_we_started(HSData);
+ _ ->
+ %% Other Node may have closed since
+ %% discovery !
+ ?trace("other node (~p) "
+ "closed since discovery (port_please).~n",
+ [Node]),
+ ?shutdown(Node)
+ end.
+
connect_options(Opts) ->
case application:get_env(kernel, inet_dist_connect_options) of
{ok,ConnectOpts} ->
@@ -430,6 +445,16 @@ get_tcp_address(Driver, Socket) ->
}.
%% ------------------------------------------------------------
+%% Determine if EPMD module supports address resolving. Default
+%% is to use inet:getaddr/2.
+%% ------------------------------------------------------------
+get_address_resolver(EpmdModule) ->
+ case erlang:function_exported(EpmdModule, address_please, 3) of
+ true -> {EpmdModule, address_please};
+ _ -> {erl_epmd, address_please}
+ end.
+
+%% ------------------------------------------------------------
%% Do only accept new connection attempts from nodes at our
%% own LAN, if the check_ip environment parameter is true.
%% ------------------------------------------------------------
diff --git a/lib/kernel/src/kernel.app.src b/lib/kernel/src/kernel.app.src
index 0eca6fef03..8fe6bdd1ca 100644
--- a/lib/kernel/src/kernel.app.src
+++ b/lib/kernel/src/kernel.app.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -57,9 +57,23 @@
inet_tcp_dist,
kernel,
kernel_config,
+ kernel_refc,
local_tcp,
local_udp,
- net,
+ logger,
+ logger_backend,
+ logger_config,
+ logger_disk_log_h,
+ logger_filters,
+ logger_formatter,
+ logger_h_common,
+ logger_handler_watcher,
+ logger_olp,
+ logger_proxy,
+ logger_server,
+ logger_simple_h,
+ logger_std_h,
+ logger_sup,
net_adm,
net_kernel,
os,
@@ -88,6 +102,13 @@
inet_udp,
inet_sctp,
pg2,
+ raw_file_io,
+ raw_file_io_compressed,
+ raw_file_io_deflate,
+ raw_file_io_delayed,
+ raw_file_io_inflate,
+ raw_file_io_list,
+ raw_file_io_raw,
seq_trace,
standard_error,
wrap_log_reader]},
@@ -107,7 +128,11 @@
heart,
init,
kernel_config,
+ kernel_refc,
kernel_sup,
+ logger,
+ logger_handler_watcher,
+ logger_sup,
net_kernel,
net_sup,
rex,
@@ -118,8 +143,10 @@
inet_db,
pg2]},
{applications, []},
- {env, [{error_logger, tty}]},
+ {env, [{logger_level, notice},
+ {logger_sasl_compatible, false}
+ ]},
{mod, {kernel, []}},
- {runtime_dependencies, ["erts-9.3", "stdlib-3.4", "sasl-3.0"]}
+ {runtime_dependencies, ["erts-10.2.5", "stdlib-3.5", "sasl-3.0"]}
]
}.
diff --git a/lib/kernel/src/kernel.appup.src b/lib/kernel/src/kernel.appup.src
index 4ee497bbbd..cd0397a98c 100644
--- a/lib/kernel/src/kernel.appup.src
+++ b/lib/kernel/src/kernel.appup.src
@@ -16,11 +16,38 @@
%% limitations under the License.
%%
%% %CopyrightEnd%
+%%
+%% We allow upgrade from, and downgrade to all previous
+%% versions from the following OTP releases:
+%% - OTP 21
+%% - OTP 22
+%%
+%% We also allow upgrade from, and downgrade to all
+%% versions that have branched off from the above
+%% stated previous versions.
+%%
{"%VSN%",
- %% Up from - max one major revision back
- [{<<"5\\.[0-3](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-19.*, OTP-20.0
- {<<"5\\.4(\\.[0-9]+)*">>,[restart_new_emulator]}], % OTP-20.1+
- %% Down to - max one major revision back
- [{<<"5\\.[0-3](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-19.*, OTP-20.0
- {<<"5\\.4(\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-20.1+
-}.
+ [{<<"^6\\.0$">>,[restart_new_emulator]},
+ {<<"^6\\.0\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^6\\.0\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^6\\.1$">>,[restart_new_emulator]},
+ {<<"^6\\.1\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^6\\.1\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^6\\.2$">>,[restart_new_emulator]},
+ {<<"^6\\.2\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^6\\.2\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^6\\.3$">>,[restart_new_emulator]},
+ {<<"^6\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^6\\.3\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}],
+ [{<<"^6\\.0$">>,[restart_new_emulator]},
+ {<<"^6\\.0\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^6\\.0\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^6\\.1$">>,[restart_new_emulator]},
+ {<<"^6\\.1\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^6\\.1\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^6\\.2$">>,[restart_new_emulator]},
+ {<<"^6\\.2\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^6\\.2\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^6\\.3$">>,[restart_new_emulator]},
+ {<<"^6\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^6\\.3\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}]}.
diff --git a/lib/kernel/src/kernel.erl b/lib/kernel/src/kernel.erl
index cba57088ec..bfa091a036 100644
--- a/lib/kernel/src/kernel.erl
+++ b/lib/kernel/src/kernel.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -30,24 +30,13 @@
%%% Callback functions for the kernel application.
%%%-----------------------------------------------------------------
start(_, []) ->
+ %% Setup the logger and configure the kernel logger environment
+ ok = logger:internal_init_logger(),
case supervisor:start_link({local, kernel_sup}, kernel, []) of
{ok, Pid} ->
- %% add signal handler
- case whereis(erl_signal_server) of
- %% in case of minimal mode
- undefined -> ok;
- _ ->
- ok = gen_event:add_handler(erl_signal_server, erl_signal_handler, [])
- end,
- %% add error handler
- Type = get_error_logger_type(),
- case error_logger:swap_handler(Type) of
- ok -> {ok, Pid, []};
- Error ->
- %% Not necessary since the node will crash anyway:
- exit(Pid, shutdown),
- Error
- end;
+ ok = erl_signal_handler:start(),
+ ok = logger:add_handlers(kernel),
+ {ok, Pid, []};
Error -> Error
end.
@@ -62,16 +51,6 @@ config_change(Changed, New, Removed) ->
do_global_groups_change(Changed, New, Removed),
ok.
-get_error_logger_type() ->
- case application:get_env(kernel, error_logger) of
- {ok, tty} -> tty;
- {ok, {file, File}} when is_list(File) -> {logfile, File};
- {ok, false} -> false;
- {ok, silent} -> silent;
- undefined -> tty; % default value
- {ok, Bad} -> exit({bad_config, {kernel, {error_logger, Bad}}})
- end.
-
%%%-----------------------------------------------------------------
%%% The process structure in kernel is as shown in the figure.
%%%
@@ -89,7 +68,7 @@ get_error_logger_type() ->
%%% auth, ...) ...)
%%%
%%% The rectangular boxes are supervisors. All supervisors except
-%%% for kernel_safe_sup terminates the enitre erlang node if any of
+%%% for kernel_safe_sup terminates the entire erlang node if any of
%%% their children dies. Any child that can't be restarted in case
%%% of failure must be placed under one of these supervisors. Any
%%% other child must be placed under safe_sup. These children may
@@ -111,6 +90,13 @@ init([]) ->
type => worker,
modules => [kernel_config]},
+ RefC = #{id => kernel_refc,
+ start => {kernel_refc, start_link, []},
+ restart => permanent,
+ shutdown => 2000,
+ type => worker,
+ modules => [kernel_refc]},
+
Code = #{id => code_server,
start => {code, start_link, []},
restart => permanent,
@@ -146,30 +132,24 @@ init([]) ->
type => supervisor,
modules => [?MODULE]},
+
+ LoggerSup = #{id => logger_sup,
+ start => {logger_sup, start_link, []},
+ restart => permanent,
+ shutdown => infinity,
+ type => supervisor,
+ modules => [logger_sup]},
+
case init:get_argument(mode) of
{ok, [["minimal"]]} ->
- {ok, {SupFlags, [Code, File, StdError, User, Config, SafeSup]}};
+ {ok, {SupFlags,
+ [Code, File, StdError, User, LoggerSup, Config, RefC, SafeSup]}};
_ ->
- Rpc = #{id => rex,
- start => {rpc, start_link, []},
- restart => permanent,
- shutdown => 2000,
- type => worker,
- modules => [rpc]},
-
- Global = #{id => global_name_server,
- start => {global, start_link, []},
- restart => permanent,
- shutdown => 2000,
- type => worker,
- modules => [global]},
-
- GlGroup = #{id => global_group,
- start => {global_group,start_link,[]},
- restart => permanent,
- shutdown => 2000,
- type => worker,
- modules => [global_group]},
+ DistChildren =
+ case application:get_env(kernel, start_distribution) of
+ {ok, false} -> [];
+ _ -> start_distribution()
+ end,
InetDb = #{id => inet_db,
start => {inet_db, start_link, []},
@@ -178,13 +158,6 @@ init([]) ->
type => worker,
modules => [inet_db]},
- NetSup = #{id => net_sup,
- start => {erl_distribution, start_link, []},
- restart => permanent,
- shutdown => infinity,
- type => supervisor,
- modules => [erl_distribution]},
-
SigSrv = #{id => erl_signal_server,
start => {gen_event, start_link, [{local, erl_signal_server}]},
restart => permanent,
@@ -192,14 +165,11 @@ init([]) ->
type => worker,
modules => dynamic},
- DistAC = start_dist_ac(),
-
Timer = start_timer(),
{ok, {SupFlags,
- [Code, Rpc, Global, InetDb | DistAC] ++
- [NetSup, GlGroup, File, SigSrv,
- StdError, User, Config, SafeSup] ++ Timer}}
+ [Code, InetDb | DistChildren] ++
+ [File, SigSrv, StdError, User, Config, RefC, SafeSup, LoggerSup] ++ Timer}}
end;
init(safe) ->
SupFlags = #{strategy => one_for_one,
@@ -218,6 +188,39 @@ init(safe) ->
{ok, {SupFlags, Boot ++ DiskLog ++ Pg2}}.
+start_distribution() ->
+ Rpc = #{id => rex,
+ start => {rpc, start_link, []},
+ restart => permanent,
+ shutdown => 2000,
+ type => worker,
+ modules => [rpc]},
+
+ Global = #{id => global_name_server,
+ start => {global, start_link, []},
+ restart => permanent,
+ shutdown => 2000,
+ type => worker,
+ modules => [global]},
+
+ DistAC = start_dist_ac(),
+
+ NetSup = #{id => net_sup,
+ start => {erl_distribution, start_link, []},
+ restart => permanent,
+ shutdown => infinity,
+ type => supervisor,
+ modules => [erl_distribution]},
+
+ GlGroup = #{id => global_group,
+ start => {global_group,start_link,[]},
+ restart => permanent,
+ shutdown => 2000,
+ type => worker,
+ modules => [global_group]},
+
+ [Rpc, Global | DistAC] ++ [NetSup, GlGroup].
+
start_dist_ac() ->
Spec = [#{id => dist_ac,
start => {dist_ac,start_link,[]},
diff --git a/lib/kernel/src/kernel_config.erl b/lib/kernel/src/kernel_config.erl
index 535083ef27..691a266c2d 100644
--- a/lib/kernel/src/kernel_config.erl
+++ b/lib/kernel/src/kernel_config.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -30,11 +30,8 @@
%%%-----------------------------------------------------------------
%%% This module implements a process that configures the kernel
%%% application.
-%%% Its purpose is that in the init phase add an error_logger
-%%% and when it dies (when the kernel application dies) deleting the
-%%% previously installed error_logger.
-%%% Also, this process waits for other nodes at startup, if
-%%% specified.
+%%% Its purpose is that in the init phase waits for other nodes at startup,
+%%% if specified.
%%%-----------------------------------------------------------------
start_link() -> gen_server:start_link(kernel_config, [], []).
diff --git a/lib/kernel/src/kernel_refc.erl b/lib/kernel/src/kernel_refc.erl
new file mode 100644
index 0000000000..8e04ff99d8
--- /dev/null
+++ b/lib/kernel/src/kernel_refc.erl
@@ -0,0 +1,139 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(kernel_refc).
+
+-behaviour(gen_server).
+
+%% External exports
+-export([start_link/0, scheduler_wall_time/1]).
+%% Internal exports
+-export([init/1, handle_info/2, terminate/2]).
+-export([handle_call/3, handle_cast/2, code_change/3]).
+
+%%%-----------------------------------------------------------------
+%%% This module implements a process that handles reference counters for
+%%% various erts or other kernel resources which needs reference counting.
+%%%
+%%% Should not be documented nor used directly by user applications.
+%%%-----------------------------------------------------------------
+start_link() ->
+ gen_server:start_link({local,kernel_refc}, kernel_refc, [], []).
+
+-spec scheduler_wall_time(boolean()) -> boolean().
+scheduler_wall_time(Bool) ->
+ gen_server:call(kernel_refc, {scheduler_wall_time, self(), Bool}, infinity).
+
+%%-----------------------------------------------------------------
+%% Callback functions from gen_server
+%%-----------------------------------------------------------------
+
+-spec init([]) -> {'ok', map()}.
+
+init([]) ->
+ resource(scheduler_wall_time, false),
+ {ok, #{scheduler_wall_time=>#{}}}.
+
+-spec handle_call(term(), term(), State) -> {'reply', term(), State}.
+handle_call({What, Who, false}, _From, State) ->
+ {Reply, Cnt} = do_stop(What, maps:get(What, State), Who),
+ {reply, Reply, State#{What:=Cnt}};
+handle_call({What, Who, true}, _From, State) ->
+ {Reply, Cnt} = do_start(What, maps:get(What, State), Who),
+ {reply, Reply, State#{What:=Cnt}};
+handle_call(_, _From, State) ->
+ {reply, badarg, State}.
+
+-spec handle_cast(term(), State) -> {'noreply', State}.
+handle_cast(_, State) ->
+ {noreply, State}.
+
+-spec handle_info(term(), State) -> {'noreply', State}.
+handle_info({'DOWN', _Ref, process, Pid, _}, State) ->
+ Cleanup = fun(Resource, Cnts) ->
+ cleanup(Resource, Cnts, Pid)
+ end,
+ {noreply, maps:map(Cleanup, State)};
+handle_info(_, State) ->
+ {noreply, State}.
+
+-spec terminate(term(), term()) -> 'ok'.
+terminate(_Reason, _State) ->
+ ok.
+
+-spec code_change(term(), State, term()) -> {'ok', State}.
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%%-----------------------------------------------------------------
+%% Internal functions
+%%-----------------------------------------------------------------
+
+do_start(Resource, Cnt, Pid) ->
+ case maps:get(Pid, Cnt, undefined) of
+ undefined ->
+ Ref = erlang:monitor(process, Pid),
+ case any(Cnt) of
+ true ->
+ {true, Cnt#{Pid=>{1, Ref}}};
+ false ->
+ resource(Resource, true),
+ {false, Cnt#{Pid=>{1, Ref}}}
+ end;
+ {N, Ref} ->
+ {true, Cnt#{Pid=>{N+1, Ref}}}
+ end.
+
+do_stop(Resource, Cnt0, Pid) ->
+ case maps:get(Pid, Cnt0, undefined) of
+ undefined ->
+ {any(Cnt0), Cnt0};
+ {1, Ref} ->
+ erlang:demonitor(Ref, [flush]),
+ Cnt = maps:remove(Pid, Cnt0),
+ case any(Cnt) of
+ true ->
+ {true, Cnt};
+ false ->
+ resource(Resource, false),
+ {true, Cnt}
+ end;
+ {N, Ref} ->
+ {true, Cnt0#{Pid=>{N-1, Ref}}}
+ end.
+
+cleanup(Resource, Cnt0, Pid) ->
+ case maps:is_key(Pid, Cnt0) of
+ true ->
+ Cnt = maps:remove(Pid, Cnt0),
+ case any(Cnt) of
+ true ->
+ Cnt;
+ false ->
+ resource(Resource, false),
+ Cnt
+ end;
+ false ->
+ Cnt0
+ end.
+
+any(Cnt) -> maps:size(Cnt) > 0.
+
+resource(scheduler_wall_time, Enable) ->
+ _ = erts_internal:scheduler_wall_time(Enable).
diff --git a/lib/kernel/src/logger.erl b/lib/kernel/src/logger.erl
new file mode 100644
index 0000000000..38bd2f481c
--- /dev/null
+++ b/lib/kernel/src/logger.erl
@@ -0,0 +1,1146 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(logger).
+
+%% Log interface
+-export([emergency/1,emergency/2,emergency/3,
+ alert/1,alert/2,alert/3,
+ critical/1,critical/2,critical/3,
+ error/1,error/2,error/3,
+ warning/1,warning/2,warning/3,
+ notice/1,notice/2,notice/3,
+ info/1,info/2,info/3,
+ debug/1,debug/2,debug/3]).
+-export([log/2,log/3,log/4]).
+
+%% Called by macro
+-export([allow/2,macro_log/3,macro_log/4,macro_log/5,add_default_metadata/1]).
+
+%% Configuration
+-export([add_handler/3, remove_handler/1,
+ add_primary_filter/2, add_handler_filter/3,
+ remove_primary_filter/1, remove_handler_filter/2,
+ set_module_level/2,
+ unset_module_level/1, unset_module_level/0,
+ set_application_level/2, unset_application_level/1,
+ get_module_level/0, get_module_level/1,
+ set_primary_config/1, set_primary_config/2,
+ set_handler_config/2, set_handler_config/3,
+ set_proxy_config/1,
+ update_primary_config/1,
+ update_handler_config/2, update_handler_config/3,
+ update_proxy_config/1,
+ update_formatter_config/2, update_formatter_config/3,
+ get_primary_config/0, get_handler_config/1,
+ get_handler_config/0, get_handler_ids/0, get_config/0,
+ get_proxy_config/0,
+ add_handlers/1]).
+
+%% Private configuration
+-export([internal_init_logger/0]).
+
+%% Misc
+-export([compare_levels/2]).
+-export([set_process_metadata/1, update_process_metadata/1,
+ unset_process_metadata/0, get_process_metadata/0]).
+-export([i/0, i/1]).
+-export([timestamp/0]).
+
+%% Basic report formatting
+-export([format_report/1, format_otp_report/1]).
+
+-export([internal_log/2,filter_stacktrace/2]).
+
+-include("logger_internal.hrl").
+-include("logger.hrl").
+
+%%%-----------------------------------------------------------------
+%%% Types
+-type log_event() :: #{level:=level(),
+ msg:={io:format(),[term()]} |
+ {report,report()} |
+ {string,unicode:chardata()},
+ meta:=metadata()}.
+-type level() :: emergency | alert | critical | error |
+ warning | notice | info | debug.
+-type report() :: map() | [{atom(),term()}].
+-type report_cb() :: fun((report()) -> {io:format(),[term()]}) |
+ fun((report(),report_cb_config()) -> unicode:chardata()).
+-type report_cb_config() :: #{depth := pos_integer() | unlimited,
+ chars_limit := pos_integer() | unlimited,
+ single_line := boolean()}.
+-type msg_fun() :: fun((term()) -> {io:format(),[term()]} |
+ report() |
+ unicode:chardata()).
+-type metadata() :: #{pid => pid(),
+ gl => pid(),
+ time => timestamp(),
+ mfa => {module(),atom(),non_neg_integer()},
+ file => file:filename(),
+ line => non_neg_integer(),
+ domain => [atom()],
+ report_cb => report_cb(),
+ atom() => term()}.
+-type location() :: #{mfa := {module(),atom(),non_neg_integer()},
+ file := file:filename(),
+ line := non_neg_integer()}.
+-type handler_id() :: atom().
+-type filter_id() :: atom().
+-type filter() :: {fun((log_event(),filter_arg()) ->
+ filter_return()),filter_arg()}.
+-type filter_arg() :: term().
+-type filter_return() :: stop | ignore | log_event().
+-type primary_config() :: #{level => level() | all | none,
+ filter_default => log | stop,
+ filters => [{filter_id(),filter()}]}.
+-type handler_config() :: #{id => handler_id(),
+ config => term(),
+ level => level() | all | none,
+ module => module(),
+ filter_default => log | stop,
+ filters => [{filter_id(),filter()}],
+ formatter => {module(),formatter_config()}}.
+-type timestamp() :: integer().
+-type formatter_config() :: #{atom() => term()}.
+
+-type config_handler() :: {handler, handler_id(), module(), handler_config()}.
+
+-type config_logger() :: [{handler,default,undefined} |
+ config_handler() |
+ {filters,log | stop,[{filter_id(),filter()}]} |
+ {module_level,level(),[module()]}].
+
+-type olp_config() :: #{sync_mode_qlen => non_neg_integer(),
+ drop_mode_qlen => pos_integer(),
+ flush_qlen => pos_integer(),
+ burst_limit_enable => boolean(),
+ burst_limit_max_count => pos_integer(),
+ burst_limit_window_time => pos_integer(),
+ overload_kill_enable => boolean(),
+ overload_kill_qlen => pos_integer(),
+ overload_kill_mem_size => pos_integer(),
+ overload_kill_restart_after =>
+ non_neg_integer() | infinity}.
+
+-export_type([log_event/0,
+ level/0,
+ report/0,
+ report_cb/0,
+ report_cb_config/0,
+ msg_fun/0,
+ metadata/0,
+ primary_config/0,
+ handler_config/0,
+ handler_id/0,
+ filter_id/0,
+ filter/0,
+ filter_arg/0,
+ filter_return/0,
+ config_handler/0,
+ formatter_config/0,
+ olp_config/0,
+ timestamp/0]).
+
+%%%-----------------------------------------------------------------
+%%% API
+emergency(X) ->
+ log(emergency,X).
+emergency(X,Y) ->
+ log(emergency,X,Y).
+emergency(X,Y,Z) ->
+ log(emergency,X,Y,Z).
+
+alert(X) ->
+ log(alert,X).
+alert(X,Y) ->
+ log(alert,X,Y).
+alert(X,Y,Z) ->
+ log(alert,X,Y,Z).
+
+critical(X) ->
+ log(critical,X).
+critical(X,Y) ->
+ log(critical,X,Y).
+critical(X,Y,Z) ->
+ log(critical,X,Y,Z).
+
+error(X) ->
+ log(error,X).
+error(X,Y) ->
+ log(error,X,Y).
+error(X,Y,Z) ->
+ log(error,X,Y,Z).
+
+warning(X) ->
+ log(warning,X).
+warning(X,Y) ->
+ log(warning,X,Y).
+warning(X,Y,Z) ->
+ log(warning,X,Y,Z).
+
+notice(X) ->
+ log(notice,X).
+notice(X,Y) ->
+ log(notice,X,Y).
+notice(X,Y,Z) ->
+ log(notice,X,Y,Z).
+
+info(X) ->
+ log(info,X).
+info(X,Y) ->
+ log(info,X,Y).
+info(X,Y,Z) ->
+ log(info,X,Y,Z).
+
+debug(X) ->
+ log(debug,X).
+debug(X,Y) ->
+ log(debug,X,Y).
+debug(X,Y,Z) ->
+ log(debug,X,Y,Z).
+
+-spec log(Level,StringOrReport) -> ok when
+ Level :: level(),
+ StringOrReport :: unicode:chardata() | report().
+log(Level, StringOrReport) ->
+ do_log(Level,StringOrReport,#{}).
+
+-spec log(Level,StringOrReport,Metadata) -> ok when
+ Level :: level(),
+ StringOrReport :: unicode:chardata() | report(),
+ Metadata :: metadata();
+ (Level,Format,Args) -> ok when
+ Level :: level(),
+ Format :: io:format(),
+ Args ::[term()];
+ (Level,Fun,FunArgs) -> ok when
+ Level :: level(),
+ Fun :: msg_fun(),
+ FunArgs :: term().
+log(Level, StringOrReport, Metadata)
+ when is_map(Metadata), not is_function(StringOrReport) ->
+ do_log(Level,StringOrReport,Metadata);
+log(Level, FunOrFormat, Args) ->
+ do_log(Level,{FunOrFormat,Args},#{}).
+
+-spec log(Level,Format, Args, Metadata) -> ok when
+ Level :: level(),
+ Format :: io:format(),
+ Args :: [term()],
+ Metadata :: metadata();
+ (Level,Fun,FunArgs,Metadata) -> ok when
+ Level :: level(),
+ Fun :: msg_fun(),
+ FunArgs :: term(),
+ Metadata :: metadata().
+log(Level, FunOrFormat, Args, Metadata) ->
+ do_log(Level,{FunOrFormat,Args},Metadata).
+
+-spec allow(Level,Module) -> boolean() when
+ Level :: level(),
+ Module :: module().
+allow(Level,Module) when ?IS_LEVEL(Level), is_atom(Module) ->
+ logger_config:allow(?LOGGER_TABLE,Level,Module).
+
+
+-spec macro_log(Location,Level,StringOrReport) -> ok when
+ Location :: location(),
+ Level :: level(),
+ StringOrReport :: unicode:chardata() | report().
+macro_log(Location,Level,StringOrReport) ->
+ log_allowed(Location,Level,StringOrReport,#{}).
+
+-spec macro_log(Location,Level,StringOrReport,Meta) -> ok when
+ Location :: location(),
+ Level :: level(),
+ StringOrReport :: unicode:chardata() | report(),
+ Meta :: metadata();
+ (Location,Level,Format,Args) -> ok when
+ Location :: location(),
+ Level :: level(),
+ Format :: io:format(),
+ Args ::[term()];
+ (Location,Level,Fun,FunArgs) -> ok when
+ Location :: location(),
+ Level :: level(),
+ Fun :: msg_fun(),
+ FunArgs :: term().
+macro_log(Location,Level,StringOrReport,Meta)
+ when is_map(Meta), not is_function(StringOrReport) ->
+ log_allowed(Location,Level,StringOrReport,Meta);
+macro_log(Location,Level,FunOrFormat,Args) ->
+ log_allowed(Location,Level,{FunOrFormat,Args},#{}).
+
+-spec macro_log(Location,Level,Format,Args,Meta) -> ok when
+ Location :: location(),
+ Level :: level(),
+ Format :: io:format(),
+ Args ::[term()],
+ Meta :: metadata();
+ (Location,Level,Fun,FunArgs,Meta) -> ok when
+ Location :: location(),
+ Level :: level(),
+ Fun :: msg_fun(),
+ FunArgs :: term(),
+ Meta :: metadata().
+macro_log(Location,Level,FunOrFormat,Args,Meta) ->
+ log_allowed(Location,Level,{FunOrFormat,Args},Meta).
+
+-spec format_otp_report(Report) -> FormatArgs when
+ Report :: report(),
+ FormatArgs :: {io:format(),[term()]}.
+format_otp_report(#{label:=_,report:=Report}) ->
+ format_report(Report);
+format_otp_report(Report) ->
+ format_report(Report).
+
+-spec format_report(Report) -> FormatArgs when
+ Report :: report(),
+ FormatArgs :: {io:format(),[term()]}.
+format_report(Report) when is_map(Report) ->
+ format_report(maps:to_list(Report));
+format_report(Report) when is_list(Report) ->
+ case lists:flatten(Report) of
+ [] ->
+ {"~tp",[[]]};
+ FlatList ->
+ case string_p1(FlatList) of
+ true ->
+ {"~ts",[FlatList]};
+ false ->
+ format_term_list(Report,[],[])
+ end
+ end;
+format_report(Report) ->
+ {"~tp",[Report]}.
+
+format_term_list([{Tag,Data}|T],Format,Args) ->
+ PorS = case string_p(Data) of
+ true -> "s";
+ false -> "p"
+ end,
+ format_term_list(T,[" ~tp: ~t"++PorS|Format],[Data,Tag|Args]);
+format_term_list([Data|T],Format,Args) ->
+ format_term_list(T,[" ~tp"|Format],[Data|Args]);
+format_term_list([],Format,Args) ->
+ {lists:flatten(lists:join($\n,lists:reverse(Format))),lists:reverse(Args)}.
+
+string_p(List) when is_list(List) ->
+ string_p1(lists:flatten(List));
+string_p(_) ->
+ false.
+
+string_p1([]) ->
+ false;
+string_p1(FlatList) ->
+ io_lib:printable_unicode_list(FlatList).
+
+internal_log(Level,Term) when is_atom(Level) ->
+ erlang:display_string("Logger - "++ atom_to_list(Level) ++ ": "),
+ erlang:display(Term).
+
+-spec timestamp() -> timestamp().
+timestamp() ->
+ os:system_time(microsecond).
+
+%%%-----------------------------------------------------------------
+%%% Configuration
+-spec add_primary_filter(FilterId,Filter) -> ok | {error,term()} when
+ FilterId :: filter_id(),
+ Filter :: filter().
+add_primary_filter(FilterId,Filter) ->
+ logger_server:add_filter(primary,{FilterId,Filter}).
+
+-spec add_handler_filter(HandlerId,FilterId,Filter) -> ok | {error,term()} when
+ HandlerId :: handler_id(),
+ FilterId :: filter_id(),
+ Filter :: filter().
+add_handler_filter(HandlerId,FilterId,Filter) ->
+ logger_server:add_filter(HandlerId,{FilterId,Filter}).
+
+
+-spec remove_primary_filter(FilterId) -> ok | {error,term()} when
+ FilterId :: filter_id().
+remove_primary_filter(FilterId) ->
+ logger_server:remove_filter(primary,FilterId).
+
+-spec remove_handler_filter(HandlerId,FilterId) -> ok | {error,term()} when
+ HandlerId :: handler_id(),
+ FilterId :: filter_id().
+remove_handler_filter(HandlerId,FilterId) ->
+ logger_server:remove_filter(HandlerId,FilterId).
+
+-spec add_handler(HandlerId,Module,Config) -> ok | {error,term()} when
+ HandlerId :: handler_id(),
+ Module :: module(),
+ Config :: handler_config().
+add_handler(HandlerId,Module,Config) ->
+ logger_server:add_handler(HandlerId,Module,Config).
+
+-spec remove_handler(HandlerId) -> ok | {error,term()} when
+ HandlerId :: handler_id().
+remove_handler(HandlerId) ->
+ logger_server:remove_handler(HandlerId).
+
+-spec set_primary_config(level,Level) -> ok | {error,term()} when
+ Level :: level() | all | none;
+ (filter_default,FilterDefault) -> ok | {error,term()} when
+ FilterDefault :: log | stop;
+ (filters,Filters) -> ok | {error,term()} when
+ Filters :: [{filter_id(),filter()}].
+set_primary_config(Key,Value) ->
+ logger_server:set_config(primary,Key,Value).
+
+-spec set_primary_config(Config) -> ok | {error,term()} when
+ Config :: primary_config().
+set_primary_config(Config) ->
+ logger_server:set_config(primary,Config).
+
+
+-spec set_handler_config(HandlerId,level,Level) -> Return when
+ HandlerId :: handler_id(),
+ Level :: level() | all | none,
+ Return :: ok | {error,term()};
+ (HandlerId,filter_default,FilterDefault) -> Return when
+ HandlerId :: handler_id(),
+ FilterDefault :: log | stop,
+ Return :: ok | {error,term()};
+ (HandlerId,filters,Filters) -> Return when
+ HandlerId :: handler_id(),
+ Filters :: [{filter_id(),filter()}],
+ Return :: ok | {error,term()};
+ (HandlerId,formatter,Formatter) -> Return when
+ HandlerId :: handler_id(),
+ Formatter :: {module(), formatter_config()},
+ Return :: ok | {error,term()};
+ (HandlerId,config,Config) -> Return when
+ HandlerId :: handler_id(),
+ Config :: term(),
+ Return :: ok | {error,term()}.
+set_handler_config(HandlerId,Key,Value) ->
+ logger_server:set_config(HandlerId,Key,Value).
+
+-spec set_handler_config(HandlerId,Config) -> ok | {error,term()} when
+ HandlerId :: handler_id(),
+ Config :: handler_config().
+set_handler_config(HandlerId,Config) ->
+ logger_server:set_config(HandlerId,Config).
+
+-spec set_proxy_config(Config) -> ok | {error,term()} when
+ Config :: olp_config().
+set_proxy_config(Config) ->
+ logger_server:set_config(proxy,Config).
+
+-spec update_primary_config(Config) -> ok | {error,term()} when
+ Config :: primary_config().
+update_primary_config(Config) ->
+ logger_server:update_config(primary,Config).
+
+-spec update_handler_config(HandlerId,level,Level) -> Return when
+ HandlerId :: handler_id(),
+ Level :: level() | all | none,
+ Return :: ok | {error,term()};
+ (HandlerId,filter_default,FilterDefault) -> Return when
+ HandlerId :: handler_id(),
+ FilterDefault :: log | stop,
+ Return :: ok | {error,term()};
+ (HandlerId,filters,Filters) -> Return when
+ HandlerId :: handler_id(),
+ Filters :: [{filter_id(),filter()}],
+ Return :: ok | {error,term()};
+ (HandlerId,formatter,Formatter) -> Return when
+ HandlerId :: handler_id(),
+ Formatter :: {module(), formatter_config()},
+ Return :: ok | {error,term()};
+ (HandlerId,config,Config) -> Return when
+ HandlerId :: handler_id(),
+ Config :: term(),
+ Return :: ok | {error,term()}.
+update_handler_config(HandlerId,Key,Value) ->
+ logger_server:update_config(HandlerId,Key,Value).
+
+-spec update_handler_config(HandlerId,Config) -> ok | {error,term()} when
+ HandlerId :: handler_id(),
+ Config :: handler_config().
+update_handler_config(HandlerId,Config) ->
+ logger_server:update_config(HandlerId,Config).
+
+-spec update_proxy_config(Config) -> ok | {error,term()} when
+ Config :: olp_config().
+update_proxy_config(Config) ->
+ logger_server:update_config(proxy,Config).
+
+-spec get_primary_config() -> Config when
+ Config :: primary_config().
+get_primary_config() ->
+ {ok,Config} = logger_config:get(?LOGGER_TABLE,primary),
+ maps:remove(handlers,Config).
+
+-spec get_handler_config(HandlerId) -> {ok,Config} | {error,term()} when
+ HandlerId :: handler_id(),
+ Config :: handler_config().
+get_handler_config(HandlerId) ->
+ case logger_config:get(?LOGGER_TABLE,HandlerId) of
+ {ok,#{module:=Module}=Config} ->
+ {ok,try Module:filter_config(Config)
+ catch _:_ -> Config
+ end};
+ Error ->
+ Error
+ end.
+
+-spec get_handler_config() -> [Config] when
+ Config :: handler_config().
+get_handler_config() ->
+ [begin
+ {ok,Config} = get_handler_config(HandlerId),
+ Config
+ end || HandlerId <- get_handler_ids()].
+
+-spec get_handler_ids() -> [HandlerId] when
+ HandlerId :: handler_id().
+get_handler_ids() ->
+ {ok,#{handlers:=HandlerIds}} = logger_config:get(?LOGGER_TABLE,primary),
+ HandlerIds.
+
+-spec get_proxy_config() -> Config when
+ Config :: olp_config().
+get_proxy_config() ->
+ {ok,Config} = logger_config:get(?LOGGER_TABLE,proxy),
+ Config.
+
+-spec update_formatter_config(HandlerId,FormatterConfig) ->
+ ok | {error,term()} when
+ HandlerId :: handler_id(),
+ FormatterConfig :: formatter_config().
+update_formatter_config(HandlerId,FormatterConfig) ->
+ logger_server:update_formatter_config(HandlerId,FormatterConfig).
+
+-spec update_formatter_config(HandlerId,Key,Value) ->
+ ok | {error,term()} when
+ HandlerId :: handler_id(),
+ Key :: atom(),
+ Value :: term().
+update_formatter_config(HandlerId,Key,Value) ->
+ logger_server:update_formatter_config(HandlerId,#{Key=>Value}).
+
+-spec set_module_level(Modules,Level) -> ok | {error,term()} when
+ Modules :: [module()] | module(),
+ Level :: level() | all | none.
+set_module_level(Module,Level) when is_atom(Module) ->
+ set_module_level([Module],Level);
+set_module_level(Modules,Level) ->
+ logger_server:set_module_level(Modules,Level).
+
+-spec unset_module_level(Modules) -> ok when
+ Modules :: [module()] | module().
+unset_module_level(Module) when is_atom(Module) ->
+ unset_module_level([Module]);
+unset_module_level(Modules) ->
+ logger_server:unset_module_level(Modules).
+
+-spec unset_module_level() -> ok.
+unset_module_level() ->
+ logger_server:unset_module_level().
+
+-spec set_application_level(Application,Level) -> ok | {error, not_loaded} when
+ Application :: atom(),
+ Level :: level() | all | none.
+set_application_level(App,Level) ->
+ case application:get_key(App, modules) of
+ {ok, Modules} ->
+ set_module_level(Modules, Level);
+ undefined ->
+ {error, {not_loaded, App}}
+ end.
+
+-spec unset_application_level(Application) -> ok | {error, not_loaded} when
+ Application :: atom().
+unset_application_level(App) ->
+ case application:get_key(App, modules) of
+ {ok, Modules} ->
+ unset_module_level(Modules);
+ undefined ->
+ {error, {not_loaded, App}}
+ end.
+
+-spec get_module_level(Modules) -> [{Module,Level}] when
+ Modules :: [Module] | Module,
+ Module :: module(),
+ Level :: level() | all | none.
+get_module_level(Module) when is_atom(Module) ->
+ get_module_level([Module]);
+get_module_level(Modules) when is_list(Modules) ->
+ [{M,L} || {M,L} <- get_module_level(),
+ lists:member(M,Modules)].
+
+-spec get_module_level() -> [{Module,Level}] when
+ Module :: module(),
+ Level :: level() | all | none.
+get_module_level() ->
+ logger_config:get_module_level(?LOGGER_TABLE).
+
+%%%-----------------------------------------------------------------
+%%% Misc
+-spec compare_levels(Level1,Level2) -> eq | gt | lt when
+ Level1 :: level(),
+ Level2 :: level().
+compare_levels(Level,Level) when ?IS_LEVEL(Level) ->
+ eq;
+compare_levels(Level1,Level2) when ?IS_LEVEL(Level1), ?IS_LEVEL(Level2) ->
+ Int1 = logger_config:level_to_int(Level1),
+ Int2 = logger_config:level_to_int(Level2),
+ if Int1 < Int2 -> gt;
+ true -> lt
+ end;
+compare_levels(Level1,Level2) ->
+ erlang:error(badarg,[Level1,Level2]).
+
+-spec set_process_metadata(Meta) -> ok when
+ Meta :: metadata().
+set_process_metadata(Meta) when is_map(Meta) ->
+ _ = put(?LOGGER_META_KEY,Meta),
+ ok;
+set_process_metadata(Meta) ->
+ erlang:error(badarg,[Meta]).
+
+-spec update_process_metadata(Meta) -> ok when
+ Meta :: metadata().
+update_process_metadata(Meta) when is_map(Meta) ->
+ case get_process_metadata() of
+ undefined ->
+ set_process_metadata(Meta);
+ Meta0 when is_map(Meta0) ->
+ set_process_metadata(maps:merge(Meta0,Meta)),
+ ok
+ end;
+update_process_metadata(Meta) ->
+ erlang:error(badarg,[Meta]).
+
+-spec get_process_metadata() -> Meta | undefined when
+ Meta :: metadata().
+get_process_metadata() ->
+ get(?LOGGER_META_KEY).
+
+-spec unset_process_metadata() -> ok.
+unset_process_metadata() ->
+ _ = erase(?LOGGER_META_KEY),
+ ok.
+
+-spec get_config() -> #{primary=>primary_config(),
+ handlers=>[handler_config()],
+ proxy=>olp_config(),
+ module_levels=>[{module(),level() | all | none}]}.
+get_config() ->
+ #{primary=>get_primary_config(),
+ handlers=>get_handler_config(),
+ proxy=>get_proxy_config(),
+ module_levels=>lists:keysort(1,get_module_level())}.
+
+-spec i() -> ok.
+i() ->
+ #{primary := Primary,
+ handlers := HandlerConfigs,
+ proxy := Proxy,
+ module_levels := Modules} = get_config(),
+ M = modifier(),
+ i_primary(Primary,M),
+ i_handlers(HandlerConfigs,M),
+ i_proxy(Proxy,M),
+ i_modules(Modules,M).
+
+-spec i(What) -> ok when
+ What :: primary | handlers | proxy | modules | handler_id().
+i(primary) ->
+ i_primary(get_primary_config(),modifier());
+i(handlers) ->
+ i_handlers(get_handler_config(),modifier());
+i(proxy) ->
+ i_proxy(get_proxy_config(),modifier());
+i(modules) ->
+ i_modules(get_module_level(),modifier());
+i(HandlerId) when is_atom(HandlerId) ->
+ case get_handler_config(HandlerId) of
+ {ok,HandlerConfig} ->
+ i_handlers([HandlerConfig],modifier());
+ Error ->
+ Error
+ end;
+i(What) ->
+ erlang:error(badarg,[What]).
+
+
+i_primary(#{level := Level,
+ filters := Filters,
+ filter_default := FilterDefault},
+ M) ->
+ io:format("Primary configuration: ~n",[]),
+ io:format(" Level: ~p~n",[Level]),
+ io:format(" Filter Default: ~p~n", [FilterDefault]),
+ io:format(" Filters: ~n", []),
+ print_filters(" ",Filters,M).
+
+i_handlers(HandlerConfigs,M) ->
+ io:format("Handler configuration: ~n", []),
+ print_handlers(HandlerConfigs,M).
+
+i_proxy(Proxy,M) ->
+ io:format("Proxy configuration: ~n", []),
+ print_custom(" ",Proxy,M).
+
+i_modules(Modules,M) ->
+ io:format("Level set per module: ~n", []),
+ print_module_levels(Modules,M).
+
+encoding() ->
+ case lists:keyfind(encoding, 1, io:getopts()) of
+ false -> latin1;
+ {encoding, Enc} -> Enc
+ end.
+
+modifier() ->
+ modifier(encoding()).
+
+modifier(latin1) -> "";
+modifier(_) -> "t".
+
+print_filters(Indent, {Id, {Fun, Arg}}, M) ->
+ io:format("~sId: ~"++M++"p~n"
+ "~s Fun: ~"++M++"p~n"
+ "~s Arg: ~"++M++"p~n",
+ [Indent, Id, Indent, Fun, Indent, Arg]);
+print_filters(Indent,[],_M) ->
+ io:format("~s(none)~n",[Indent]);
+print_filters(Indent,Filters,M) ->
+ [print_filters(Indent,Filter,M) || Filter <- Filters],
+ ok.
+
+print_handlers(#{id := Id,
+ module := Module,
+ level := Level,
+ filters := Filters, filter_default := FilterDefault,
+ formatter := {FormatterModule,FormatterConfig}} = Config, M) ->
+ io:format(" Id: ~"++M++"p~n"
+ " Module: ~p~n"
+ " Level: ~p~n"
+ " Formatter:~n"
+ " Module: ~p~n"
+ " Config:~n",
+ [Id, Module, Level, FormatterModule]),
+ print_custom(" ",FormatterConfig,M),
+ io:format(" Filter Default: ~p~n"
+ " Filters:~n",
+ [FilterDefault]),
+ print_filters(" ",Filters,M),
+ case maps:find(config,Config) of
+ {ok,HandlerConfig} ->
+ io:format(" Handler Config:~n"),
+ print_custom(" ",HandlerConfig,M);
+ error ->
+ ok
+ end,
+ MyKeys = [filter_default, filters, formatter, level, module, id, config],
+ case maps:without(MyKeys,Config) of
+ Empty when Empty==#{} ->
+ ok;
+ Unhandled ->
+ io:format(" Custom Config:~n"),
+ print_custom(" ",Unhandled,M)
+ end;
+print_handlers([], _M) ->
+ io:format(" (none)~n");
+print_handlers(HandlerConfigs, M) ->
+ [print_handlers(HandlerConfig, M) || HandlerConfig <- HandlerConfigs],
+ ok.
+
+print_custom(Indent, {Key, Value}, M) ->
+ io:format("~s~"++M++"p: ~"++M++"p~n",[Indent,Key,Value]);
+print_custom(Indent, Map, M) when is_map(Map) ->
+ print_custom(Indent,lists:keysort(1,maps:to_list(Map)), M);
+print_custom(Indent, List, M) when is_list(List), is_tuple(hd(List)) ->
+ [print_custom(Indent, X, M) || X <- List],
+ ok;
+print_custom(Indent, Value, M) ->
+ io:format("~s~"++M++"p~n",[Indent,Value]).
+
+print_module_levels({Module,Level},M) ->
+ io:format(" Module: ~"++M++"p~n"
+ " Level: ~p~n",
+ [Module,Level]);
+print_module_levels([],_M) ->
+ io:format(" (none)~n");
+print_module_levels(Modules,M) ->
+ [print_module_levels(Module,M) || Module <- Modules],
+ ok.
+
+-spec internal_init_logger() -> ok | {error,term()}.
+%% This function is responsible for config of the logger
+%% This is done before add_handlers because we want the
+%% logger settings to take effect before the kernel supervisor
+%% tree is started.
+internal_init_logger() ->
+ try
+ Env = get_logger_env(kernel),
+ check_logger_config(kernel,Env),
+ ok = logger:set_primary_config(level, get_logger_level()),
+ ok = logger:set_primary_config(filter_default,
+ get_primary_filter_default(Env)),
+
+ [case logger:add_primary_filter(Id, Filter) of
+ ok -> ok;
+ {error, Reason} -> throw(Reason)
+ end || {Id, Filter} <- get_primary_filters(Env)],
+
+ [case logger:set_module_level(Modules, Level) of
+ ok -> ok;
+ {error, Reason} -> throw(Reason)
+ end || {module_level, Level, Modules} <- Env],
+
+ case logger:set_handler_config(simple,filters,
+ get_default_handler_filters()) of
+ ok -> ok;
+ {error,{not_found,simple}} -> ok
+ end,
+
+ init_kernel_handlers(Env)
+ catch throw:Reason ->
+ ?LOG_ERROR("Invalid logger config: ~p", [Reason]),
+ {error, {bad_config, {kernel, Reason}}}
+ end.
+
+-spec init_kernel_handlers(config_logger()) -> ok | {error,term()}.
+%% Setup the kernel environment variables to be correct
+%% The actual handlers are started by a call to add_handlers.
+init_kernel_handlers(Env) ->
+ try
+ case get_logger_type(Env) of
+ {ok,silent} ->
+ ok = logger:remove_handler(simple);
+ {ok,false} ->
+ ok;
+ {ok,Type} ->
+ init_default_config(Type,Env)
+ end
+ catch throw:Reason ->
+ ?LOG_ERROR("Invalid default handler config: ~p", [Reason]),
+ {error, {bad_config, {kernel, Reason}}}
+ end.
+
+-spec add_handlers(Application) -> ok | {error,term()} when
+ Application :: atom();
+ (HandlerConfig) -> ok | {error,term()} when
+ HandlerConfig :: [config_handler()].
+%% This function is responsible for resolving the handler config
+%% and then starting the correct handlers. This is done after the
+%% kernel supervisor tree has been started as it needs the logger_sup.
+add_handlers(kernel) ->
+ Env = get_logger_env(kernel),
+ case get_proxy_opts(Env) of
+ undefined ->
+ add_handlers(kernel,Env);
+ Opts ->
+ case set_proxy_config(Opts) of
+ ok -> add_handlers(kernel,Env);
+ {error, Reason} -> {error,{bad_proxy_config,Reason}}
+ end
+ end;
+add_handlers(App) when is_atom(App) ->
+ add_handlers(App,get_logger_env(App));
+add_handlers(HandlerConfig) ->
+ add_handlers(application:get_application(),HandlerConfig).
+
+add_handlers(App,HandlerConfig) ->
+ try
+ check_logger_config(App,HandlerConfig),
+ DefaultAdded =
+ lists:foldl(
+ fun({handler, default = Id, Module, Config}, _)
+ when not is_map_key(filters, Config) ->
+ %% The default handler should have a couple of extra filters
+ %% set on it by default.
+ DefConfig = #{ filter_default => stop,
+ filters => get_default_handler_filters()},
+ setup_handler(Id, Module, maps:merge(DefConfig,Config)),
+ true;
+ ({handler, Id, Module, Config}, Default) ->
+ setup_handler(Id, Module, Config),
+ Default orelse Id == default;
+ (_,Default) -> Default
+ end, false, HandlerConfig),
+ %% If a default handler was added we try to remove the simple_logger
+ %% If the simple logger exists it will replay its log events
+ %% to the handler(s) added in the fold above.
+ [case logger:remove_handler(simple) of
+ ok -> ok;
+ {error,{not_found,simple}} -> ok
+ end || DefaultAdded],
+ ok
+ catch throw:Reason0 ->
+ Reason =
+ case App of
+ undefined -> Reason0;
+ _ -> {App,Reason0}
+ end,
+ ?LOG_ERROR("Invalid logger handler config: ~p", [Reason]),
+ {error, {bad_config, {handler, Reason}}}
+ end.
+
+setup_handler(Id, Module, Config) ->
+ case logger:add_handler(Id, Module, Config) of
+ ok -> ok;
+ {error, Reason} -> throw(Reason)
+ end.
+
+check_logger_config(_,[]) ->
+ ok;
+check_logger_config(App,[{handler,_,_,_}|Env]) ->
+ check_logger_config(App,Env);
+check_logger_config(kernel,[{handler,default,undefined}|Env]) ->
+ check_logger_config(kernel,Env);
+check_logger_config(kernel,[{filters,_,_}|Env]) ->
+ check_logger_config(kernel,Env);
+check_logger_config(kernel,[{module_level,_,_}|Env]) ->
+ check_logger_config(kernel,Env);
+check_logger_config(kernel,[{proxy,_}|Env]) ->
+ check_logger_config(kernel,Env);
+check_logger_config(_,Bad) ->
+ throw(Bad).
+
+-spec get_logger_type(config_logger()) ->
+ {ok, standard_io | false | silent |
+ {file, file:name_all()} |
+ {file, file:name_all(), [file:mode()]}}.
+get_logger_type(Env) ->
+ case application:get_env(kernel, error_logger) of
+ {ok, tty} ->
+ {ok, standard_io};
+ {ok, {file, File}} when is_list(File) ->
+ {ok, {file, File}};
+ {ok, false} ->
+ {ok, false};
+ {ok, silent} ->
+ {ok, silent};
+ undefined ->
+ case lists:member({handler,default,undefined}, Env) of
+ true ->
+ {ok, false};
+ false ->
+ {ok, standard_io} % default value
+ end;
+ {ok, Bad} ->
+ throw({error_logger, Bad})
+ end.
+
+get_logger_level() ->
+ case application:get_env(kernel,logger_level,info) of
+ Level when ?IS_LEVEL(Level); Level=:=all; Level=:=none ->
+ Level;
+ Level ->
+ throw({logger_level, Level})
+ end.
+
+get_primary_filter_default(Env) ->
+ case lists:keyfind(filters,1,Env) of
+ {filters,Default,_} ->
+ Default;
+ false ->
+ log
+ end.
+
+get_primary_filters(Env) ->
+ case [F || F={filters,_,_} <- Env] of
+ [{filters,_,Filters}] ->
+ case lists:all(fun({_,_}) -> true; (_) -> false end,Filters) of
+ true -> Filters;
+ false -> throw({invalid_filters,Filters})
+ end;
+ [] -> [];
+ _ -> throw({multiple_filters,Env})
+ end.
+
+get_proxy_opts(Env) ->
+ case [P || P={proxy,_} <- Env] of
+ [{proxy,Opts}] -> Opts;
+ [] -> undefined;
+ _ -> throw({multiple_proxies,Env})
+ end.
+
+%% This function looks at the kernel logger environment
+%% and updates it so that the correct logger is configured
+init_default_config(Type,Env) when Type==standard_io;
+ Type==standard_error;
+ element(1,Type)==file ->
+ DefaultFormatter = #{formatter=>{?DEFAULT_FORMATTER,?DEFAULT_FORMAT_CONFIG}},
+ DefaultConfig = DefaultFormatter#{config=>#{type=>Type}},
+ NewLoggerEnv =
+ case lists:keyfind(default, 2, Env) of
+ {handler, default, logger_std_h, Config} ->
+ %% Only want to add the logger_std_h config
+ %% if not configured by user AND the default
+ %% handler is still the logger_std_h.
+ lists:keyreplace(default, 2, Env,
+ {handler, default, logger_std_h,
+ maps:merge(DefaultConfig,Config)});
+ {handler, default, Module,Config} ->
+ %% Add default formatter. The point of this
+ %% is to get the expected formatter config
+ %% for the default handler, since this
+ %% differs from the default values that
+ %% logger_formatter itself adds.
+ lists:keyreplace(default, 2, Env,
+ {handler, default, Module,
+ maps:merge(DefaultFormatter,Config)});
+ _ ->
+ %% Nothing has been configured, use default
+ [{handler, default, logger_std_h, DefaultConfig} | Env]
+ end,
+ application:set_env(kernel, logger, NewLoggerEnv, [{timeout,infinity}]).
+
+get_default_handler_filters() ->
+ case application:get_env(kernel, logger_sasl_compatible, false) of
+ true ->
+ ?DEFAULT_HANDLER_FILTERS([otp]);
+ false ->
+ ?DEFAULT_HANDLER_FILTERS([otp,sasl])
+ end.
+
+get_logger_env(App) ->
+ application:get_env(App, logger, []).
+
+%%%-----------------------------------------------------------------
+%%% Internal
+do_log(Level,Msg,#{mfa:={Module,_,_}}=Meta) ->
+ case logger_config:allow(?LOGGER_TABLE,Level,Module) of
+ true ->
+ log_allowed(#{},Level,Msg,Meta);
+ false ->
+ ok
+ end;
+do_log(Level,Msg,Meta) ->
+ case logger_config:allow(?LOGGER_TABLE,Level) of
+ true ->
+ log_allowed(#{},Level,Msg,Meta);
+ false ->
+ ok
+ end.
+
+-spec log_allowed(Location,Level,Msg,Meta) -> ok when
+ Location :: location() | #{},
+ Level :: level(),
+ Msg :: {msg_fun(),term()} |
+ {io:format(),[term()]} |
+ report() |
+ unicode:chardata(),
+ Meta :: metadata().
+log_allowed(Location,Level,{Fun,FunArgs},Meta) when is_function(Fun,1) ->
+ try Fun(FunArgs) of
+ Msg={Format,Args} when is_list(Format), is_list(Args) ->
+ log_allowed(Location,Level,Msg,Meta);
+ Report when ?IS_REPORT(Report) ->
+ log_allowed(Location,Level,Report,Meta);
+ String when ?IS_STRING(String) ->
+ log_allowed(Location,Level,String,Meta);
+ Other ->
+ log_allowed(Location,Level,
+ {"LAZY_FUN ERROR: ~tp; Returned: ~tp",
+ [{Fun,FunArgs},Other]},
+ Meta)
+ catch C:R ->
+ log_allowed(Location,Level,
+ {"LAZY_FUN CRASH: ~tp; Reason: ~tp",
+ [{Fun,FunArgs},{C,R}]},
+ Meta)
+ end;
+log_allowed(Location,Level,Msg,Meta0) when is_map(Meta0) ->
+ %% Metadata priorities are:
+ %% Location (added in API macros) - will be overwritten by process
+ %% metadata (set by set_process_metadata/1), which in turn will be
+ %% overwritten by the metadata given as argument in the log call
+ %% (function or macro).
+ Meta = add_default_metadata(
+ maps:merge(Location,maps:merge(proc_meta(),Meta0))),
+ case node(maps:get(gl,Meta)) of
+ Node when Node=/=node() ->
+ log_remote(Node,Level,Msg,Meta);
+ _ ->
+ ok
+ end,
+ do_log_allowed(Level,Msg,Meta,tid()).
+
+do_log_allowed(Level,{Format,Args}=Msg,Meta,Tid)
+ when ?IS_LEVEL(Level),
+ is_list(Format),
+ is_list(Args),
+ is_map(Meta) ->
+ logger_backend:log_allowed(#{level=>Level,msg=>Msg,meta=>Meta},Tid);
+do_log_allowed(Level,Report,Meta,Tid)
+ when ?IS_LEVEL(Level),
+ ?IS_REPORT(Report),
+ is_map(Meta) ->
+ logger_backend:log_allowed(#{level=>Level,msg=>{report,Report},meta=>Meta},
+ Tid);
+do_log_allowed(Level,String,Meta,Tid)
+ when ?IS_LEVEL(Level),
+ ?IS_STRING(String),
+ is_map(Meta) ->
+ logger_backend:log_allowed(#{level=>Level,msg=>{string,String},meta=>Meta},
+ Tid).
+tid() ->
+ ets:whereis(?LOGGER_TABLE).
+
+log_remote(Node,Level,{Format,Args},Meta) ->
+ log_remote(Node,{log,Level,Format,Args,Meta});
+log_remote(Node,Level,Msg,Meta) ->
+ log_remote(Node,{log,Level,Msg,Meta}).
+
+log_remote(Node,Request) ->
+ logger_proxy:log({remote,Node,Request}),
+ ok.
+
+add_default_metadata(Meta) ->
+ add_default_metadata([pid,gl,time],Meta).
+
+add_default_metadata([Key|Keys],Meta) ->
+ case maps:is_key(Key,Meta) of
+ true ->
+ add_default_metadata(Keys,Meta);
+ false ->
+ add_default_metadata(Keys,Meta#{Key=>default(Key)})
+ end;
+add_default_metadata([],Meta) ->
+ Meta.
+
+proc_meta() ->
+ case get_process_metadata() of
+ ProcMeta when is_map(ProcMeta) -> ProcMeta;
+ _ -> #{}
+ end.
+
+default(pid) -> self();
+default(gl) -> group_leader();
+default(time) -> timestamp().
+
+%% Remove everything upto and including this module from the stacktrace
+filter_stacktrace(Module,[{Module,_,_,_}|_]) ->
+ [];
+filter_stacktrace(Module,[H|T]) ->
+ [H|filter_stacktrace(Module,T)];
+filter_stacktrace(_,[]) ->
+ [].
diff --git a/lib/kernel/src/logger_backend.erl b/lib/kernel/src/logger_backend.erl
new file mode 100644
index 0000000000..432c671afd
--- /dev/null
+++ b/lib/kernel/src/logger_backend.erl
@@ -0,0 +1,133 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(logger_backend).
+
+-export([log_allowed/2]).
+
+-include("logger_internal.hrl").
+
+-define(OWN_KEYS,[level,filters,filter_default,handlers]).
+
+%%%-----------------------------------------------------------------
+%%% The default logger backend
+log_allowed(Log, Tid) ->
+ {ok,Config} = logger_config:get(Tid,primary),
+ Filters = maps:get(filters,Config,[]),
+ case apply_filters(primary,Log,Filters,Config) of
+ stop ->
+ ok;
+ Log1 ->
+ Handlers = maps:get(handlers,Config,[]),
+ call_handlers(Log1,Handlers,Tid)
+ end,
+ ok.
+
+call_handlers(#{level:=Level}=Log,[Id|Handlers],Tid) ->
+ case logger_config:get(Tid,Id,Level) of
+ {ok,#{module:=Module}=Config} ->
+ Filters = maps:get(filters,Config,[]),
+ case apply_filters(Id,Log,Filters,Config) of
+ stop ->
+ ok;
+ Log1 ->
+ Config1 = maps:without(?OWN_KEYS,Config),
+ try Module:log(Log1,Config1)
+ catch C:R:S ->
+ case logger:remove_handler(Id) of
+ ok ->
+ logger:internal_log(
+ error,{removed_failing_handler,Id}),
+ ?LOG_INTERNAL(
+ debug,
+ [{logger,removed_failing_handler},
+ {handler,{Id,Module}},
+ {log_event,Log1},
+ {config,Config1},
+ {reason,{C,R,filter_stacktrace(S)}}]);
+ {error,{not_found,_}} ->
+ %% Probably already removed by other client
+ %% Don't report again
+ ok;
+ {error,Reason} ->
+ ?LOG_INTERNAL(
+ debug,
+ [{logger,remove_handler_failed},
+ {reason,Reason}])
+ end
+ end
+ end;
+ _ ->
+ ok
+ end,
+ call_handlers(Log,Handlers,Tid);
+call_handlers(_Log,[],_Tid) ->
+ ok.
+
+apply_filters(Owner,Log,Filters,Config) ->
+ case do_apply_filters(Owner,Log,Filters,ignore) of
+ stop ->
+ stop;
+ ignore ->
+ case maps:get(filter_default,Config) of
+ log ->
+ Log;
+ stop ->
+ stop
+ end;
+ Log1 ->
+ Log1
+ end.
+
+do_apply_filters(Owner,Log,[{_Id,{FilterFun,FilterArgs}}=Filter|Filters],State) ->
+ try FilterFun(Log,FilterArgs) of
+ stop ->
+ stop;
+ ignore ->
+ do_apply_filters(Owner,Log,Filters,State);
+ Log1=#{level:=Level,msg:=Msg,meta:=Meta}
+ when is_atom(Level), ?IS_MSG(Msg), is_map(Meta) ->
+ do_apply_filters(Owner,Log1,Filters,log);
+ Bad ->
+ handle_filter_failed(Filter,Owner,Log,{bad_return_value,Bad})
+ catch C:R:S ->
+ handle_filter_failed(Filter,Owner,Log,{C,R,filter_stacktrace(S)})
+ end;
+do_apply_filters(_Owner,_Log,[],ignore) ->
+ ignore;
+do_apply_filters(_Owner,Log,[],log) ->
+ Log.
+
+handle_filter_failed({Id,_}=Filter,Owner,Log,Reason) ->
+ case logger_server:remove_filter(Owner,Id) of
+ ok ->
+ logger:internal_log(error,{removed_failing_filter,Id}),
+ ?LOG_INTERNAL(debug,
+ [{logger,removed_failing_filter},
+ {filter,Filter},
+ {owner,Owner},
+ {log_event,Log},
+ {reason,Reason}]);
+ _ ->
+ ok
+ end,
+ ignore.
+
+filter_stacktrace(Stacktrace) ->
+ logger:filter_stacktrace(?MODULE,Stacktrace).
diff --git a/lib/kernel/src/logger_config.erl b/lib/kernel/src/logger_config.erl
new file mode 100644
index 0000000000..5024d20cfe
--- /dev/null
+++ b/lib/kernel/src/logger_config.erl
@@ -0,0 +1,160 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(logger_config).
+
+-export([new/1,delete/2,
+ exist/2,
+ allow/2,allow/3,
+ get/2, get/3,
+ create/3, set/3,
+ set_module_level/3,unset_module_level/2,
+ get_module_level/1,cache_module_level/2,
+ level_to_int/1]).
+
+-include("logger_internal.hrl").
+
+new(Name) ->
+ _ = ets:new(Name,[set,protected,named_table,
+ {read_concurrency,true},
+ {write_concurrency,true}]),
+ ets:whereis(Name).
+
+delete(Tid,Id) ->
+ ets:delete(Tid,table_key(Id)).
+
+allow(Tid,Level,Module) ->
+ LevelInt = level_to_int(Level),
+ case ets:lookup(Tid,Module) of
+ [{Module,{ModLevel,cached}}] when is_integer(ModLevel),
+ LevelInt =< ModLevel ->
+ true;
+ [{Module,ModLevel}] when is_integer(ModLevel),
+ LevelInt =< ModLevel ->
+ true;
+ [] ->
+ logger_server:cache_module_level(Module),
+ allow(Tid,Level);
+ _ ->
+ false
+ end.
+
+allow(Tid,Level) ->
+ GlobalLevelInt = ets:lookup_element(Tid,?PRIMARY_KEY,2),
+ level_to_int(Level) =< GlobalLevelInt.
+
+exist(Tid,What) ->
+ ets:member(Tid,table_key(What)).
+
+get(Tid,What) ->
+ case ets:lookup(Tid,table_key(What)) of
+ [{_,_,Config}] ->
+ {ok,Config};
+ [{_,Config}] when What=:=proxy ->
+ {ok,Config};
+ [] ->
+ {error,{not_found,What}}
+ end.
+
+get(Tid,What,Level) ->
+ MS = [{{table_key(What),'$1','$2'},
+ [{'>=','$1',level_to_int(Level)}],
+ ['$2']}],
+ case ets:select(Tid,MS) of
+ [] -> error;
+ [Data] -> {ok,Data}
+ end.
+
+create(Tid,proxy,Config) ->
+ ets:insert(Tid,{table_key(proxy),Config});
+create(Tid,What,Config) ->
+ LevelInt = level_to_int(maps:get(level,Config)),
+ ets:insert(Tid,{table_key(What),LevelInt,Config}).
+
+set(Tid,proxy,Config) ->
+ ets:insert(Tid,{table_key(proxy),Config}),
+ ok;
+set(Tid,What,Config) ->
+ LevelInt = level_to_int(maps:get(level,Config)),
+ %% Should do this only if the level has actually changed. Possibly
+ %% overwrite instead of delete?
+ case What of
+ primary ->
+ _ = ets:select_delete(Tid,[{{'_',{'$1',cached}},
+ [{'=/=','$1',LevelInt}],
+ [true]}]),
+ ok;
+ _ ->
+ ok
+ end,
+ ets:update_element(Tid,table_key(What),[{2,LevelInt},{3,Config}]),
+ ok.
+
+set_module_level(Tid,Modules,Level) ->
+ LevelInt = level_to_int(Level),
+ [ets:insert(Tid,{Module,LevelInt}) || Module <- Modules],
+ ok.
+
+%% should possibly overwrite instead of delete?
+unset_module_level(Tid,all) ->
+ MS = [{{'$1','$2'},[{is_atom,'$1'},{is_integer,'$2'}],[true]}],
+ _ = ets:select_delete(Tid,MS),
+ ok;
+unset_module_level(Tid,Modules) ->
+ [ets:delete(Tid,Module) || Module <- Modules],
+ ok.
+
+get_module_level(Tid) ->
+ MS = [{{'$1','$2'},[{is_atom,'$1'},{is_integer,'$2'}],[{{'$1','$2'}}]}],
+ Modules = ets:select(Tid,MS),
+ lists:sort([{M,int_to_level(L)} || {M,L} <- Modules]).
+
+cache_module_level(Tid,Module) ->
+ GlobalLevelInt = ets:lookup_element(Tid,?PRIMARY_KEY,2),
+ ets:insert_new(Tid,{Module,{GlobalLevelInt,cached}}),
+ ok.
+
+level_to_int(none) -> ?LOG_NONE;
+level_to_int(emergency) -> ?EMERGENCY;
+level_to_int(alert) -> ?ALERT;
+level_to_int(critical) -> ?CRITICAL;
+level_to_int(error) -> ?ERROR;
+level_to_int(warning) -> ?WARNING;
+level_to_int(notice) -> ?NOTICE;
+level_to_int(info) -> ?INFO;
+level_to_int(debug) -> ?DEBUG;
+level_to_int(all) -> ?LOG_ALL.
+
+int_to_level(?LOG_NONE) -> none;
+int_to_level(?EMERGENCY) -> emergency;
+int_to_level(?ALERT) -> alert;
+int_to_level(?CRITICAL) -> critical;
+int_to_level(?ERROR) -> error;
+int_to_level(?WARNING) -> warning;
+int_to_level(?NOTICE) -> notice;
+int_to_level(?INFO) -> info;
+int_to_level(?DEBUG) -> debug;
+int_to_level(?LOG_ALL) -> all.
+
+%%%-----------------------------------------------------------------
+%%% Internal
+
+table_key(proxy) -> ?PROXY_KEY;
+table_key(primary) -> ?PRIMARY_KEY;
+table_key(HandlerId) -> {?HANDLER_KEY,HandlerId}.
diff --git a/lib/kernel/src/logger_disk_log_h.erl b/lib/kernel/src/logger_disk_log_h.erl
new file mode 100644
index 0000000000..47b39da900
--- /dev/null
+++ b/lib/kernel/src/logger_disk_log_h.erl
@@ -0,0 +1,252 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(logger_disk_log_h).
+
+-include("logger.hrl").
+-include("logger_internal.hrl").
+-include("logger_h_common.hrl").
+
+%%% API
+-export([filesync/1]).
+
+%% logger_h_common callbacks
+-export([init/2, check_config/4, reset_state/2,
+ filesync/3, write/4, handle_info/3, terminate/3]).
+
+%% logger callbacks
+-export([log/2, adding_handler/1, removing_handler/1, changing_config/3,
+ filter_config/1]).
+
+%%%===================================================================
+%%% API
+%%%===================================================================
+
+%%%-----------------------------------------------------------------
+%%%
+-spec filesync(Name) -> ok | {error,Reason} when
+ Name :: atom(),
+ Reason :: handler_busy | {badarg,term()}.
+
+filesync(Name) ->
+ logger_h_common:filesync(?MODULE,Name).
+
+%%%===================================================================
+%%% logger callbacks
+%%%===================================================================
+
+%%%-----------------------------------------------------------------
+%%% Handler being added
+adding_handler(Config) ->
+ logger_h_common:adding_handler(Config).
+
+%%%-----------------------------------------------------------------
+%%% Updating handler config
+changing_config(SetOrUpdate, OldConfig, NewConfig) ->
+ logger_h_common:changing_config(SetOrUpdate, OldConfig, NewConfig).
+
+%%%-----------------------------------------------------------------
+%%% Handler being removed
+removing_handler(Config) ->
+ logger_h_common:removing_handler(Config).
+
+%%%-----------------------------------------------------------------
+%%% Log a string or report
+-spec log(LogEvent, Config) -> ok when
+ LogEvent :: logger:log_event(),
+ Config :: logger:handler_config().
+
+log(LogEvent, Config) ->
+ logger_h_common:log(LogEvent, Config).
+
+%%%-----------------------------------------------------------------
+%%% Remove internal fields from configuration
+filter_config(Config) ->
+ logger_h_common:filter_config(Config).
+
+%%%===================================================================
+%%% logger_h_common callbacks
+%%%===================================================================
+init(Name, #{file:=File,type:=Type,max_no_bytes:=MNB,max_no_files:=MNF}) ->
+ case open_disk_log(Name, File, Type, MNB, MNF) of
+ ok ->
+ {ok,#{log_opts => #{file => File,
+ type => Type,
+ max_no_bytes => MNB,
+ max_no_files => MNF},
+ prev_log_result => ok,
+ prev_sync_result => ok,
+ prev_disk_log_info => undefined}};
+ Error ->
+ Error
+ end.
+
+check_config(Name,set,undefined,HConfig0) ->
+ HConfig=merge_default_logopts(Name,maps:merge(get_default_config(),HConfig0)),
+ check_config(HConfig);
+check_config(_Name,SetOrUpdate,OldHConfig,NewHConfig0) ->
+ WriteOnce = maps:with([type,file,max_no_files,max_no_bytes],OldHConfig),
+ Default =
+ case SetOrUpdate of
+ set ->
+ %% Do not reset write-once fields to defaults
+ maps:merge(get_default_config(),WriteOnce);
+ update ->
+ OldHConfig
+ end,
+
+ NewHConfig = maps:merge(Default,NewHConfig0),
+
+ %% Fail if write-once fields are changed
+ case maps:with([type,file,max_no_files,max_no_bytes],NewHConfig) of
+ WriteOnce ->
+ check_config(NewHConfig);
+ Other ->
+ {Old,New} = logger_server:diff_maps(WriteOnce,Other),
+ {error,{illegal_config_change,?MODULE,Old,New}}
+ end.
+
+check_config(HConfig) ->
+ case check_h_config(maps:to_list(HConfig)) of
+ ok ->
+ {ok,HConfig};
+ {error,{Key,Value}} ->
+ {error,{invalid_config,?MODULE,#{Key=>Value}}}
+ end.
+
+check_h_config([{file,File}|Config]) when is_list(File) ->
+ check_h_config(Config);
+check_h_config([{max_no_files,undefined}|Config]) ->
+ check_h_config(Config);
+check_h_config([{max_no_files,N}|Config]) when is_integer(N), N>0 ->
+ check_h_config(Config);
+check_h_config([{max_no_bytes,infinity}|Config]) ->
+ check_h_config(Config);
+check_h_config([{max_no_bytes,N}|Config]) when is_integer(N), N>0 ->
+ check_h_config(Config);
+check_h_config([{type,Type}|Config]) when Type==wrap; Type==halt ->
+ check_h_config(Config);
+check_h_config([Other | _]) ->
+ {error,Other};
+check_h_config([]) ->
+ ok.
+
+get_default_config() ->
+ #{}.
+
+merge_default_logopts(Name, HConfig) ->
+ Type = maps:get(type, HConfig, wrap),
+ {DefaultNoFiles,DefaultNoBytes} =
+ case Type of
+ halt -> {undefined,infinity};
+ _wrap -> {10,1048576}
+ end,
+ {ok,Dir} = file:get_cwd(),
+ Defaults = #{file => filename:join(Dir,Name),
+ max_no_files => DefaultNoFiles,
+ max_no_bytes => DefaultNoBytes,
+ type => Type},
+ maps:merge(Defaults, HConfig).
+
+filesync(Name,_Mode,State) ->
+ Result = ?disk_log_sync(Name),
+ maybe_notify_error(Name, filesync, Result, prev_sync_result, State).
+
+write(Name, Mode, Bin, State) ->
+ Result = ?disk_log_write(Name, Mode, Bin),
+ maybe_notify_error(Name, log, Result, prev_log_result, State).
+
+reset_state(_Name, State) ->
+ State#{prev_log_result => ok,
+ prev_sync_result => ok,
+ prev_disk_log_info => undefined}.
+
+%% The disk log owner must handle status messages from disk_log.
+handle_info(Name, {disk_log, _Node, Log, Info={truncated,_NoLostItems}}, State) ->
+ maybe_notify_status(Name, Log, Info, prev_disk_log_info, State);
+handle_info(Name, {disk_log, _Node, Log, Info = {blocked_log,_Items}}, State) ->
+ maybe_notify_status(Name, Log, Info, prev_disk_log_info, State);
+handle_info(Name, {disk_log, _Node, Log, Info = full}, State) ->
+ maybe_notify_status(Name, Log, Info, prev_disk_log_info, State);
+handle_info(Name, {disk_log, _Node, Log, Info = {error_status,_Status}}, State) ->
+ maybe_notify_status(Name, Log, Info, prev_disk_log_info, State);
+handle_info(_, _, State) ->
+ State.
+
+terminate(Name, _Reason, _State) ->
+ _ = close_disk_log(Name, normal),
+ ok.
+
+%%%-----------------------------------------------------------------
+%%% Internal functions
+open_disk_log(Name, File, Type, MaxNoBytes, MaxNoFiles) ->
+ case filelib:ensure_dir(File) of
+ ok ->
+ Size =
+ if Type == halt -> MaxNoBytes;
+ Type == wrap -> {MaxNoBytes,MaxNoFiles}
+ end,
+ Opts = [{name, Name},
+ {file, File},
+ {size, Size},
+ {type, Type},
+ {linkto, self()},
+ {repair, false},
+ {format, external},
+ {notify, true},
+ {quiet, true},
+ {mode, read_write}],
+ case disk_log:open(Opts) of
+ {ok,Name} ->
+ ok;
+ Error = {error,_Reason} ->
+ Error
+ end;
+ Error ->
+ Error
+ end.
+
+close_disk_log(Name, _) ->
+ _ = ?disk_log_sync(Name),
+ _ = disk_log:lclose(Name),
+ ok.
+
+disk_log_write(Name, sync, Bin) ->
+ disk_log:blog(Name, Bin);
+disk_log_write(Name, async, Bin) ->
+ disk_log:balog(Name, Bin).
+
+%%%-----------------------------------------------------------------
+%%% Print error messages, but don't repeat the same message
+maybe_notify_error(Name, Op, Result, Key, #{log_opts:=LogOpts}=State) ->
+ {Result,error_notify_new({Name, Op, LogOpts, Result}, Result, Key, State)}.
+
+maybe_notify_status(Name, Log, Info, Key, State) ->
+ error_notify_new({disk_log, Name, Log, Info}, Info, Key, State).
+
+error_notify_new(Term, What, Key, State) ->
+ error_notify_new(What, maps:get(Key,State), Term),
+ State#{Key => What}.
+
+error_notify_new(ok,_Prev,_Term) ->
+ ok;
+error_notify_new(Same,Same,_Term) ->
+ ok;
+error_notify_new(_New,_Prev,Term) ->
+ logger_h_common:error_notify(Term).
diff --git a/lib/kernel/src/logger_filters.erl b/lib/kernel/src/logger_filters.erl
new file mode 100644
index 0000000000..0664c598e1
--- /dev/null
+++ b/lib/kernel/src/logger_filters.erl
@@ -0,0 +1,127 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(logger_filters).
+
+-export([domain/2,
+ level/2,
+ progress/2,
+ remote_gl/2]).
+
+-include("logger_internal.hrl").
+-define(IS_ACTION(A), (A==log orelse A==stop)).
+
+-spec domain(LogEvent,Extra) -> logger:filter_return() when
+ LogEvent :: logger:log_event(),
+ Extra :: {Action,Compare,MatchDomain},
+ Action :: log | stop,
+ Compare :: super | sub | equal | not_equal | undefined,
+ MatchDomain :: list(atom()).
+domain(#{meta:=Meta}=LogEvent,{Action,Compare,MatchDomain})
+ when ?IS_ACTION(Action) andalso
+ (Compare==super orelse
+ Compare==sub orelse
+ Compare==equal orelse
+ Compare==not_equal orelse
+ Compare==undefined) andalso
+ is_list(MatchDomain) ->
+ filter_domain(Compare,Meta,MatchDomain,on_match(Action,LogEvent));
+domain(LogEvent,Extra) ->
+ erlang:error(badarg,[LogEvent,Extra]).
+
+-spec level(LogEvent,Extra) -> logger:filter_return() when
+ LogEvent :: logger:log_event(),
+ Extra :: {Action,Operator,MatchLevel},
+ Action :: log | stop,
+ Operator :: neq | eq | lt | gt | lteq | gteq,
+ MatchLevel :: logger:level().
+level(#{level:=L1}=LogEvent,{Action,Op,L2})
+ when ?IS_ACTION(Action) andalso
+ (Op==neq orelse
+ Op==eq orelse
+ Op==lt orelse
+ Op==gt orelse
+ Op==lteq orelse
+ Op==gteq) andalso
+ ?IS_LEVEL(L2) ->
+ filter_level(Op,L1,L2,on_match(Action,LogEvent));
+level(LogEvent,Extra) ->
+ erlang:error(badarg,[LogEvent,Extra]).
+
+-spec progress(LogEvent,Extra) -> logger:filter_return() when
+ LogEvent :: logger:log_event(),
+ Extra :: log | stop.
+progress(LogEvent,Action) when ?IS_ACTION(Action) ->
+ filter_progress(LogEvent,on_match(Action,LogEvent));
+progress(LogEvent,Action) ->
+ erlang:error(badarg,[LogEvent,Action]).
+
+-spec remote_gl(LogEvent,Extra) -> logger:filter_return() when
+ LogEvent :: logger:log_event(),
+ Extra :: log | stop.
+remote_gl(LogEvent,Action) when ?IS_ACTION(Action) ->
+ filter_remote_gl(LogEvent,on_match(Action,LogEvent));
+remote_gl(LogEvent,Action) ->
+ erlang:error(badarg,[LogEvent,Action]).
+
+%%%-----------------------------------------------------------------
+%%% Internal
+filter_domain(super,#{domain:=Domain},MatchDomain,OnMatch) ->
+ is_prefix(Domain,MatchDomain,OnMatch);
+filter_domain(sub,#{domain:=Domain},MatchDomain,OnMatch) ->
+ is_prefix(MatchDomain,Domain,OnMatch);
+filter_domain(equal,#{domain:=Domain},Domain,OnMatch) ->
+ OnMatch;
+filter_domain(not_equal,#{domain:=Domain},MatchDomain,OnMatch)
+ when Domain=/=MatchDomain ->
+ OnMatch;
+filter_domain(Compare,Meta,_,OnMatch) ->
+ case maps:is_key(domain,Meta) of
+ false when Compare==undefined; Compare==not_equal -> OnMatch;
+ _ -> ignore
+ end.
+
+is_prefix(D1,D2,OnMatch) when is_list(D1), is_list(D2) ->
+ case lists:prefix(D1,D2) of
+ true -> OnMatch;
+ false -> ignore
+ end;
+is_prefix(_,_,_) ->
+ ignore.
+
+filter_level(Op,L1,L2,OnMatch) ->
+ case logger:compare_levels(L1,L2) of
+ eq when Op==eq; Op==lteq; Op==gteq -> OnMatch;
+ lt when Op==lt; Op==lteq; Op==neq -> OnMatch;
+ gt when Op==gt; Op==gteq; Op==neq -> OnMatch;
+ _ -> ignore
+ end.
+
+filter_progress(#{msg:={report,#{label:={_,progress}}}},OnMatch) ->
+ OnMatch;
+filter_progress(_,_) ->
+ ignore.
+
+filter_remote_gl(#{meta:=#{gl:=GL}},OnMatch) when node(GL)=/=node() ->
+ OnMatch;
+filter_remote_gl(_,_) ->
+ ignore.
+
+on_match(log,LogEvent) -> LogEvent;
+on_match(stop,_) -> stop.
diff --git a/lib/kernel/src/logger_formatter.erl b/lib/kernel/src/logger_formatter.erl
new file mode 100644
index 0000000000..8696adbd72
--- /dev/null
+++ b/lib/kernel/src/logger_formatter.erl
@@ -0,0 +1,563 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(logger_formatter).
+
+-export([format/2]).
+-export([check_config/1]).
+
+-include("logger_internal.hrl").
+
+%%%-----------------------------------------------------------------
+%%% Types
+-type config() :: #{chars_limit => pos_integer() | unlimited,
+ depth => pos_integer() | unlimited,
+ legacy_header => boolean(),
+ max_size => pos_integer() | unlimited,
+ report_cb => logger:report_cb(),
+ single_line => boolean(),
+ template => template(),
+ time_designator => byte(),
+ time_offset => integer() | [byte()]}.
+-type template() :: [metakey() | {metakey(),template(),template()} | string()].
+-type metakey() :: atom() | [atom()].
+
+%%%-----------------------------------------------------------------
+%%% API
+-spec format(LogEvent,Config) -> unicode:chardata() when
+ LogEvent :: logger:log_event(),
+ Config :: config().
+format(#{level:=Level,msg:=Msg0,meta:=Meta},Config0)
+ when is_map(Config0) ->
+ Config = add_default_config(Config0),
+ Meta1 = maybe_add_legacy_header(Level,Meta,Config),
+ Template = maps:get(template,Config),
+ {BT,AT0} = lists:splitwith(fun(msg) -> false; (_) -> true end, Template),
+ {DoMsg,AT} =
+ case AT0 of
+ [msg|Rest] -> {true,Rest};
+ _ ->{false,AT0}
+ end,
+ B = do_format(Level,Meta1,BT,Config),
+ A = do_format(Level,Meta1,AT,Config),
+ MsgStr =
+ if DoMsg ->
+ Config1 =
+ case maps:get(chars_limit,Config) of
+ unlimited ->
+ Config;
+ Size0 ->
+ Size =
+ case Size0 - io_lib:chars_length([B,A]) of
+ S when S>=0 -> S;
+ _ -> 0
+ end,
+ Config#{chars_limit=>Size}
+ end,
+ MsgStr0 = format_msg(Msg0,Meta1,Config1),
+ case maps:get(single_line,Config) of
+ true ->
+ %% Trim leading and trailing whitespaces, and replace
+ %% newlines with ", "
+ T = lists:reverse(
+ trim(
+ lists:reverse(
+ trim(MsgStr0,false)),true)),
+ re:replace(T,",?\r?\n\s*",", ",
+ [{return,list},global,unicode]);
+ _false ->
+ MsgStr0
+ end;
+ true ->
+ ""
+ end,
+ truncate(B,MsgStr,A,maps:get(max_size,Config)).
+
+trim([H|T],Rev) when H==$\s; H==$\r; H==$\n ->
+ trim(T,Rev);
+trim([H|T],false) when is_list(H) ->
+ case trim(H,false) of
+ [] ->
+ trim(T,false);
+ TrimmedH ->
+ [TrimmedH|T]
+ end;
+trim([H|T],true) when is_list(H) ->
+ case trim(lists:reverse(H),true) of
+ [] ->
+ trim(T,true);
+ TrimmedH ->
+ [lists:reverse(TrimmedH)|T]
+ end;
+trim(String,_) ->
+ String.
+
+do_format(Level,Data,[level|Format],Config) ->
+ [to_string(level,Level,Config)|do_format(Level,Data,Format,Config)];
+do_format(Level,Data,[{Key,IfExist,Else}|Format],Config) ->
+ String =
+ case value(Key,Data) of
+ {ok,Value} -> do_format(Level,Data#{Key=>Value},IfExist,Config);
+ error -> do_format(Level,Data,Else,Config)
+ end,
+ [String|do_format(Level,Data,Format,Config)];
+do_format(Level,Data,[Key|Format],Config)
+ when is_atom(Key) orelse
+ (is_list(Key) andalso is_atom(hd(Key))) ->
+ String =
+ case value(Key,Data) of
+ {ok,Value} -> to_string(Key,Value,Config);
+ error -> ""
+ end,
+ [String|do_format(Level,Data,Format,Config)];
+do_format(Level,Data,[Str|Format],Config) ->
+ [Str|do_format(Level,Data,Format,Config)];
+do_format(_Level,_Data,[],_Config) ->
+ [].
+
+value(Key,Meta) when is_map_key(Key,Meta) ->
+ {ok,maps:get(Key,Meta)};
+value([Key|Keys],Meta) when is_map_key(Key,Meta) ->
+ value(Keys,maps:get(Key,Meta));
+value([],Value) ->
+ {ok,Value};
+value(_,_) ->
+ error.
+
+to_string(time,Time,Config) ->
+ format_time(Time,Config);
+to_string(mfa,MFA,Config) ->
+ format_mfa(MFA,Config);
+to_string(_,Value,Config) ->
+ to_string(Value,Config).
+
+to_string(X,_) when is_atom(X) ->
+ atom_to_list(X);
+to_string(X,_) when is_integer(X) ->
+ integer_to_list(X);
+to_string(X,_) when is_pid(X) ->
+ pid_to_list(X);
+to_string(X,_) when is_reference(X) ->
+ ref_to_list(X);
+to_string(X,Config) when is_list(X) ->
+ case printable_list(lists:flatten(X)) of
+ true -> X;
+ _ -> io_lib:format(p(Config),[X])
+ end;
+to_string(X,Config) ->
+ io_lib:format(p(Config),[X]).
+
+printable_list([]) ->
+ false;
+printable_list(X) ->
+ io_lib:printable_list(X).
+
+format_msg({string,Chardata},Meta,Config) ->
+ format_msg({"~ts",[Chardata]},Meta,Config);
+format_msg({report,_}=Msg,Meta,#{report_cb:=Fun}=Config)
+ when is_function(Fun,1); is_function(Fun,2) ->
+ format_msg(Msg,Meta#{report_cb=>Fun},maps:remove(report_cb,Config));
+format_msg({report,Report},#{report_cb:=Fun}=Meta,Config) when is_function(Fun,1) ->
+ try Fun(Report) of
+ {Format,Args} when is_list(Format), is_list(Args) ->
+ format_msg({Format,Args},maps:remove(report_cb,Meta),Config);
+ Other ->
+ P = p(Config),
+ format_msg({"REPORT_CB/1 ERROR: "++P++"; Returned: "++P,
+ [Report,Other]},Meta,Config)
+ catch C:R:S ->
+ P = p(Config),
+ format_msg({"REPORT_CB/1 CRASH: "++P++"; Reason: "++P,
+ [Report,{C,R,logger:filter_stacktrace(?MODULE,S)}]},
+ Meta,Config)
+ end;
+format_msg({report,Report},#{report_cb:=Fun}=Meta,Config) when is_function(Fun,2) ->
+ try Fun(Report,maps:with([depth,chars_limit,single_line],Config)) of
+ Chardata when ?IS_STRING(Chardata) ->
+ try chardata_to_list(Chardata) % already size limited by report_cb
+ catch _:_ ->
+ P = p(Config),
+ format_msg({"REPORT_CB/2 ERROR: "++P++"; Returned: "++P,
+ [Report,Chardata]},Meta,Config)
+ end;
+ Other ->
+ P = p(Config),
+ format_msg({"REPORT_CB/2 ERROR: "++P++"; Returned: "++P,
+ [Report,Other]},Meta,Config)
+ catch C:R:S ->
+ P = p(Config),
+ format_msg({"REPORT_CB/2 CRASH: "++P++"; Reason: "++P,
+ [Report,{C,R,logger:filter_stacktrace(?MODULE,S)}]},
+ Meta,Config)
+ end;
+format_msg({report,Report},Meta,Config) ->
+ format_msg({report,Report},
+ Meta#{report_cb=>fun logger:format_report/1},
+ Config);
+format_msg(Msg,_Meta,#{depth:=Depth,chars_limit:=CharsLimit,
+ single_line:=Single}) ->
+ Opts = chars_limit_to_opts(CharsLimit),
+ format_msg(Msg, Depth, Opts, Single).
+
+chars_limit_to_opts(unlimited) -> [];
+chars_limit_to_opts(CharsLimit) -> [{chars_limit,CharsLimit}].
+
+format_msg({Format0,Args},Depth,Opts,Single) ->
+ try
+ Format1 = io_lib:scan_format(Format0, Args),
+ Format = reformat(Format1, Depth, Single),
+ io_lib:build_text(Format,Opts)
+ catch C:R:S ->
+ P = p(Single),
+ FormatError = "FORMAT ERROR: "++P++" - "++P,
+ case Format0 of
+ FormatError ->
+ %% already been here - avoid failing cyclically
+ erlang:raise(C,R,S);
+ _ ->
+ format_msg({FormatError,[Format0,Args]},Depth,Opts,Single)
+ end
+ end.
+
+reformat(Format,unlimited,false) ->
+ Format;
+reformat([#{control_char:=C}=M|T], Depth, true) when C =:= $p ->
+ [limit_depth(M#{width => 0}, Depth)|reformat(T, Depth, true)];
+reformat([#{control_char:=C}=M|T], Depth, true) when C =:= $P ->
+ [M#{width => 0}|reformat(T, Depth, true)];
+reformat([#{control_char:=C}=M|T], Depth, Single) when C =:= $p; C =:= $w ->
+ [limit_depth(M, Depth)|reformat(T, Depth, Single)];
+reformat([H|T], Depth, Single) ->
+ [H|reformat(T, Depth, Single)];
+reformat([], _, _) ->
+ [].
+
+limit_depth(M0, unlimited) ->
+ M0;
+limit_depth(#{control_char:=C0, args:=Args}=M0, Depth) ->
+ C = C0 - ($a - $A), %To uppercase.
+ M0#{control_char:=C,args:=Args++[Depth]}.
+
+chardata_to_list(Chardata) ->
+ case unicode:characters_to_list(Chardata,unicode) of
+ List when is_list(List) ->
+ List;
+ Error ->
+ throw(Error)
+ end.
+
+truncate(B,Msg,A,unlimited) ->
+ [B,Msg,A];
+truncate(B,Msg,A,Size) ->
+ String = [B,Msg,A],
+ Length = io_lib:chars_length(String),
+ if Length>Size ->
+ {Last,FlatString} =
+ case A of
+ [] ->
+ case Msg of
+ [] ->
+ {get_last(B),lists:flatten(B)};
+ _ ->
+ {get_last(Msg),lists:flatten([B,Msg])}
+ end;
+ _ ->
+ {get_last(A),lists:flatten(String)}
+ end,
+ case Last of
+ $\n->
+ lists:sublist(FlatString,1,Size-4)++"...\n";
+ _ ->
+ lists:sublist(FlatString,1,Size-3)++"..."
+ end;
+ true ->
+ String
+ end.
+
+get_last(L) ->
+ get_first(lists:reverse(L)).
+
+get_first([]) ->
+ error;
+get_first([C|_]) when is_integer(C) ->
+ C;
+get_first([L|Rest]) when is_list(L) ->
+ case get_last(L) of
+ error -> get_first(Rest);
+ First -> First
+ end.
+
+%% SysTime is the system time in microseconds
+format_time(SysTime,#{time_offset:=Offset,time_designator:=Des})
+ when is_integer(SysTime) ->
+ calendar:system_time_to_rfc3339(SysTime,[{unit,microsecond},
+ {offset,Offset},
+ {time_designator,Des}]).
+
+%% SysTime is the system time in microseconds
+timestamp_to_datetimemicro(SysTime,Config) when is_integer(SysTime) ->
+ Micro = SysTime rem 1000000,
+ Sec = SysTime div 1000000,
+ UniversalTime = erlang:posixtime_to_universaltime(Sec),
+ {{Date,Time},UtcStr} =
+ case offset_to_utc(maps:get(time_offset,Config)) of
+ true -> {UniversalTime,"UTC "};
+ _ -> {erlang:universaltime_to_localtime(UniversalTime),""}
+ end,
+ {Date,Time,Micro,UtcStr}.
+
+format_mfa({M,F,A},_) when is_atom(M), is_atom(F), is_integer(A) ->
+ atom_to_list(M)++":"++atom_to_list(F)++"/"++integer_to_list(A);
+format_mfa({M,F,A},Config) when is_atom(M), is_atom(F), is_list(A) ->
+ format_mfa({M,F,length(A)},Config);
+format_mfa(MFA,Config) ->
+ to_string(MFA,Config).
+
+maybe_add_legacy_header(Level,
+ #{time:=Timestamp}=Meta,
+ #{legacy_header:=true}=Config) ->
+ #{title:=Title}=MyMeta = add_legacy_title(Level,Meta,Config),
+ {{Y,Mo,D},{H,Mi,S},Micro,UtcStr} =
+ timestamp_to_datetimemicro(Timestamp,Config),
+ Header =
+ io_lib:format("=~ts==== ~w-~s-~4w::~2..0w:~2..0w:~2..0w.~6..0w ~s===",
+ [Title,D,month(Mo),Y,H,Mi,S,Micro,UtcStr]),
+ Meta#{?MODULE=>MyMeta#{header=>Header}};
+maybe_add_legacy_header(_,Meta,_) ->
+ Meta.
+
+add_legacy_title(_Level,#{?MODULE:=#{title:=_}=MyMeta},_) ->
+ MyMeta;
+add_legacy_title(Level,Meta,Config) ->
+ case maps:get(?MODULE,Meta,#{}) of
+ #{title:=_}=MyMeta ->
+ MyMeta;
+ MyMeta ->
+ TitleLevel =
+ case (Level=:=notice andalso maps:find(error_logger,Meta)) of
+ {ok,_} ->
+ maps:get(error_logger_notice_header,Config);
+ _ ->
+ Level
+ end,
+ Title = string:uppercase(atom_to_list(TitleLevel)) ++ " REPORT",
+ MyMeta#{title=>Title}
+ end.
+
+month(1) -> "Jan";
+month(2) -> "Feb";
+month(3) -> "Mar";
+month(4) -> "Apr";
+month(5) -> "May";
+month(6) -> "Jun";
+month(7) -> "Jul";
+month(8) -> "Aug";
+month(9) -> "Sep";
+month(10) -> "Oct";
+month(11) -> "Nov";
+month(12) -> "Dec".
+
+%% Ensure that all valid configuration parameters exist in the final
+%% configuration map
+add_default_config(Config0) ->
+ Default =
+ #{chars_limit=>unlimited,
+ error_logger_notice_header=>info,
+ legacy_header=>false,
+ single_line=>true,
+ time_designator=>$T},
+ MaxSize = get_max_size(maps:get(max_size,Config0,undefined)),
+ Depth = get_depth(maps:get(depth,Config0,undefined)),
+ Offset = get_offset(maps:get(time_offset,Config0,undefined)),
+ add_default_template(maps:merge(Default,Config0#{max_size=>MaxSize,
+ depth=>Depth,
+ time_offset=>Offset})).
+
+add_default_template(#{template:=_}=Config) ->
+ Config;
+add_default_template(Config) ->
+ Config#{template=>default_template(Config)}.
+
+default_template(#{legacy_header:=true}) ->
+ ?DEFAULT_FORMAT_TEMPLATE_HEADER;
+default_template(#{single_line:=true}) ->
+ ?DEFAULT_FORMAT_TEMPLATE_SINGLE;
+default_template(_) ->
+ ?DEFAULT_FORMAT_TEMPLATE.
+
+get_max_size(undefined) ->
+ unlimited;
+get_max_size(S) ->
+ max(10,S).
+
+get_depth(undefined) ->
+ error_logger:get_format_depth();
+get_depth(S) ->
+ max(5,S).
+
+get_offset(undefined) ->
+ utc_to_offset(get_utc_config());
+get_offset(Offset) ->
+ Offset.
+
+utc_to_offset(true) ->
+ "Z";
+utc_to_offset(false) ->
+ "".
+
+get_utc_config() ->
+ %% SASL utc_log overrides stdlib config - in order to have uniform
+ %% timestamps in log messages
+ case application:get_env(sasl, utc_log) of
+ {ok, Val} when is_boolean(Val) -> Val;
+ _ ->
+ case application:get_env(stdlib, utc_log) of
+ {ok, Val} when is_boolean(Val) -> Val;
+ _ -> false
+ end
+ end.
+
+offset_to_utc(Z) when Z=:=0; Z=:="z"; Z=:="Z" ->
+ true;
+offset_to_utc([$+|Tz]) ->
+ case io_lib:fread("~d:~d", Tz) of
+ {ok, [0, 0], []} ->
+ true;
+ _ ->
+ false
+ end;
+offset_to_utc(_) ->
+ false.
+
+-spec check_config(Config) -> ok | {error,term()} when
+ Config :: config().
+check_config(Config) when is_map(Config) ->
+ do_check_config(maps:to_list(Config));
+check_config(Config) ->
+ {error,{invalid_formatter_config,?MODULE,Config}}.
+
+do_check_config([{Type,L}|Config]) when Type == chars_limit;
+ Type == depth;
+ Type == max_size ->
+ case check_limit(L) of
+ ok -> do_check_config(Config);
+ error -> {error,{invalid_formatter_config,?MODULE,{Type,L}}}
+ end;
+do_check_config([{single_line,SL}|Config]) when is_boolean(SL) ->
+ do_check_config(Config);
+do_check_config([{legacy_header,LH}|Config]) when is_boolean(LH) ->
+ do_check_config(Config);
+do_check_config([{error_logger_notice_header,ELNH}|Config]) when ELNH == info;
+ ELNH == notice ->
+ do_check_config(Config);
+do_check_config([{report_cb,RCB}|Config]) when is_function(RCB,1);
+ is_function(RCB,2) ->
+ do_check_config(Config);
+do_check_config([{template,T}|Config]) ->
+ case check_template(T) of
+ ok -> do_check_config(Config);
+ error -> {error,{invalid_formatter_template,?MODULE,T}}
+ end;
+do_check_config([{time_offset,Offset}|Config]) ->
+ case check_offset(Offset) of
+ ok ->
+ do_check_config(Config);
+ error ->
+ {error,{invalid_formatter_config,?MODULE,{time_offset,Offset}}}
+ end;
+do_check_config([{time_designator,Char}|Config]) when Char>=0, Char=<255 ->
+ case io_lib:printable_latin1_list([Char]) of
+ true ->
+ do_check_config(Config);
+ false ->
+ {error,{invalid_formatter_config,?MODULE,{time_designator,Char}}}
+ end;
+do_check_config([C|_]) ->
+ {error,{invalid_formatter_config,?MODULE,C}};
+do_check_config([]) ->
+ ok.
+
+check_limit(L) when is_integer(L), L>0 ->
+ ok;
+check_limit(unlimited) ->
+ ok;
+check_limit(_) ->
+ error.
+
+check_template([Key|T]) when is_atom(Key) ->
+ check_template(T);
+check_template([Key|T]) when is_list(Key), is_atom(hd(Key)) ->
+ case lists:all(fun(X) when is_atom(X) -> true;
+ (_) -> false
+ end,
+ Key) of
+ true ->
+ check_template(T);
+ false ->
+ error
+ end;
+check_template([{Key,IfExist,Else}|T])
+ when is_atom(Key) orelse
+ (is_list(Key) andalso is_atom(hd(Key))) ->
+ case check_template(IfExist) of
+ ok ->
+ case check_template(Else) of
+ ok ->
+ check_template(T);
+ error ->
+ error
+ end;
+ error ->
+ error
+ end;
+check_template([Str|T]) when is_list(Str) ->
+ case io_lib:printable_unicode_list(Str) of
+ true -> check_template(T);
+ false -> error
+ end;
+check_template([]) ->
+ ok;
+check_template(_) ->
+ error.
+
+check_offset(I) when is_integer(I) ->
+ ok;
+check_offset(Tz) when Tz=:=""; Tz=:="Z"; Tz=:="z" ->
+ ok;
+check_offset([Sign|Tz]) when Sign=:=$+; Sign=:=$- ->
+ check_timezone(Tz);
+check_offset(_) ->
+ error.
+
+check_timezone(Tz) ->
+ try io_lib:fread("~d:~d", Tz) of
+ {ok, [_, _], []} ->
+ ok;
+ _ ->
+ error
+ catch _:_ ->
+ error
+ end.
+
+p(#{single_line:=Single}) ->
+ p(Single);
+p(true) ->
+ "~0tp";
+p(false) ->
+ "~tp".
diff --git a/lib/kernel/src/logger_h_common.erl b/lib/kernel/src/logger_h_common.erl
new file mode 100644
index 0000000000..16946ff97c
--- /dev/null
+++ b/lib/kernel/src/logger_h_common.erl
@@ -0,0 +1,463 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(logger_h_common).
+-behaviour(gen_server).
+
+-include("logger_h_common.hrl").
+-include("logger_internal.hrl").
+
+%% API
+-export([filesync/2]).
+
+%% logger_olp callbacks
+-export([init/1, handle_load/2, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3, notify/2, reset_state/1]).
+
+%% logger callbacks
+-export([log/2, adding_handler/1, removing_handler/1, changing_config/3,
+ filter_config/1]).
+
+%% Library functions for handlers
+-export([error_notify/1]).
+
+-define(OLP_KEYS,[sync_mode_qlen,
+ drop_mode_qlen,
+ flush_qlen,
+ burst_limit_enable,
+ burst_limit_max_count,
+ burst_limit_window_time,
+ overload_kill_enable,
+ overload_kill_qlen,
+ overload_kill_mem_size,
+ overload_kill_restart_after]).
+
+-define(COMMON_KEYS,[filesync_repeat_interval]).
+
+-define(READ_ONLY_KEYS,[olp]).
+
+%%%-----------------------------------------------------------------
+%%% API
+
+%% This function is called by the logger_sup supervisor
+filesync(Module, Name) ->
+ call(Module, Name, filesync).
+
+%%%-----------------------------------------------------------------
+%%% Handler being added
+adding_handler(#{id:=Name,module:=Module}=Config) ->
+ HConfig0 = maps:get(config, Config, #{}),
+ HandlerConfig0 = maps:without(?OLP_KEYS++?COMMON_KEYS,HConfig0),
+ case Module:check_config(Name,set,undefined,HandlerConfig0) of
+ {ok,HandlerConfig} ->
+ ModifiedCommon = maps:with(?COMMON_KEYS,HandlerConfig),
+ CommonConfig0 = maps:with(?COMMON_KEYS,HConfig0),
+ CommonConfig = maps:merge(
+ maps:merge(get_default_config(), CommonConfig0),
+ ModifiedCommon),
+ case check_config(CommonConfig) of
+ ok ->
+ HConfig = maps:merge(CommonConfig,HandlerConfig),
+ OlpOpts = maps:with(?OLP_KEYS,HConfig0),
+ start(OlpOpts, Config#{config => HConfig});
+ {error,Faulty} ->
+ {error,{invalid_config,Module,Faulty}}
+ end;
+ Error ->
+ Error
+ end.
+
+%%%-----------------------------------------------------------------
+%%% Handler being removed
+removing_handler(#{id:=Name, module:=Module, config:=#{olp:=Olp}}) ->
+ case whereis(?name_to_reg_name(Module,Name)) of
+ undefined ->
+ ok;
+ _Pid ->
+ %% We don't want to do supervisor:terminate_child here
+ %% since we need to distinguish this explicit stop from a
+ %% system termination in order to avoid circular attempts
+ %% at removing the handler (implying deadlocks and
+ %% timeouts).
+ %% And we don't need to do supervisor:delete_child, since
+ %% the restart type is temporary, which means that the
+ %% child specification is automatically removed from the
+ %% supervisor when the process dies.
+ _ = logger_olp:stop(Olp),
+ ok
+ end.
+
+%%%-----------------------------------------------------------------
+%%% Updating handler config
+changing_config(SetOrUpdate,
+ #{id:=Name,config:=OldHConfig,module:=Module},
+ NewConfig0) ->
+ NewHConfig0 = maps:get(config, NewConfig0, #{}),
+ NoHandlerKeys = ?OLP_KEYS++?COMMON_KEYS++?READ_ONLY_KEYS,
+ OldHandlerConfig = maps:without(NoHandlerKeys,OldHConfig),
+ NewHandlerConfig0 = maps:without(NoHandlerKeys,NewHConfig0),
+ case Module:check_config(Name, SetOrUpdate,
+ OldHandlerConfig,NewHandlerConfig0) of
+ {ok, NewHandlerConfig} ->
+ ModifiedCommon = maps:with(?COMMON_KEYS,NewHandlerConfig),
+ NewCommonConfig0 = maps:with(?COMMON_KEYS,NewHConfig0),
+ OldCommonConfig = maps:with(?COMMON_KEYS,OldHConfig),
+ CommonDefault =
+ case SetOrUpdate of
+ set ->
+ get_default_config();
+ update ->
+ OldCommonConfig
+ end,
+ NewCommonConfig = maps:merge(
+ maps:merge(CommonDefault,NewCommonConfig0),
+ ModifiedCommon),
+ case check_config(NewCommonConfig) of
+ ok ->
+ OlpDefault =
+ case SetOrUpdate of
+ set ->
+ logger_olp:get_default_opts();
+ update ->
+ maps:with(?OLP_KEYS,OldHConfig)
+ end,
+ Olp = maps:get(olp,OldHConfig),
+ NewOlpOpts = maps:merge(OlpDefault,
+ maps:with(?OLP_KEYS,NewHConfig0)),
+ case logger_olp:set_opts(Olp,NewOlpOpts) of
+ ok ->
+ logger_olp:cast(Olp, {config_changed,
+ NewCommonConfig,
+ NewHandlerConfig}),
+ ReadOnly = maps:with(?READ_ONLY_KEYS,OldHConfig),
+ NewHConfig =
+ maps:merge(
+ maps:merge(
+ maps:merge(NewCommonConfig,NewHandlerConfig),
+ ReadOnly),
+ NewOlpOpts),
+ NewConfig = NewConfig0#{config=>NewHConfig},
+ {ok,NewConfig};
+ Error ->
+ Error
+ end;
+ {error,Faulty} ->
+ {error,{invalid_config,Module,Faulty}}
+ end;
+ Error ->
+ Error
+ end.
+
+%%%-----------------------------------------------------------------
+%%% Log a string or report
+-spec log(LogEvent, Config) -> ok when
+ LogEvent :: logger:log_event(),
+ Config :: logger:handler_config().
+
+log(LogEvent, Config = #{config := #{olp:=Olp}}) ->
+ %% if the handler has crashed, we must drop this event
+ %% and hope the handler restarts so we can try again
+ true = is_process_alive(logger_olp:get_pid(Olp)),
+ Bin = log_to_binary(LogEvent, Config),
+ logger_olp:load(Olp,Bin).
+
+%%%-----------------------------------------------------------------
+%%% Remove internal fields from configuration
+filter_config(#{config:=HConfig}=Config) ->
+ Config#{config=>maps:without(?READ_ONLY_KEYS,HConfig)}.
+
+%%%-----------------------------------------------------------------
+%%% Start the handler process
+%%%
+%%% The process must always exist if the handler is registered with
+%%% logger (and must not exist if the handler is not registered).
+%%%
+%%% The handler process is linked to logger_sup, which is part of the
+%%% kernel application's supervision tree.
+start(OlpOpts0, #{id := Name, module:=Module, config:=HConfig} = Config0) ->
+ RegName = ?name_to_reg_name(Module,Name),
+ ChildSpec =
+ #{id => Name,
+ start => {logger_olp, start_link, [RegName,?MODULE,
+ Config0, OlpOpts0]},
+ restart => temporary,
+ shutdown => 2000,
+ type => worker,
+ modules => [?MODULE]},
+ case supervisor:start_child(logger_sup, ChildSpec) of
+ {ok,Pid,Olp} ->
+ ok = logger_handler_watcher:register_handler(Name,Pid),
+ OlpOpts = logger_olp:get_opts(Olp),
+ {ok,Config0#{config=>(maps:merge(HConfig,OlpOpts))#{olp=>Olp}}};
+ {error,{Reason,Ch}} when is_tuple(Ch), element(1,Ch)==child ->
+ {error,Reason};
+ Error ->
+ Error
+ end.
+
+%%%===================================================================
+%%% gen_server callbacks
+%%%===================================================================
+
+init(#{id := Name, module := Module, config := HConfig}) ->
+ process_flag(trap_exit, true),
+
+ ?init_test_hooks(),
+
+ case Module:init(Name, HConfig) of
+ {ok,HState} ->
+ %% Storing common config in state to avoid copying
+ %% (sending) the config data for each log message
+ CommonConfig = maps:with(?COMMON_KEYS,HConfig),
+ State = CommonConfig#{id => Name,
+ module => Module,
+ ctrl_sync_count =>
+ ?CONTROLLER_SYNC_INTERVAL,
+ last_op => sync,
+ handler_state => HState},
+ State1 = set_repeated_filesync(State),
+ {ok,State1};
+ Error ->
+ Error
+ end.
+
+%% This is the log event.
+handle_load(Bin, #{id:=Name,
+ module:=Module,
+ handler_state:=HandlerState,
+ ctrl_sync_count := CtrlSync}=State) ->
+ if CtrlSync==0 ->
+ {_,HS1} = Module:write(Name, sync, Bin, HandlerState),
+ State#{handler_state => HS1,
+ ctrl_sync_count => ?CONTROLLER_SYNC_INTERVAL,
+ last_op=>write};
+ true ->
+ {_,HS1} = Module:write(Name, async, Bin, HandlerState),
+ State#{handler_state => HS1,
+ ctrl_sync_count => CtrlSync-1,
+ last_op=>write}
+ end.
+
+handle_call(filesync, _From, State = #{id := Name,
+ module := Module,
+ handler_state := HandlerState}) ->
+ {Result,HandlerState1} = Module:filesync(Name,sync,HandlerState),
+ {reply, Result, State#{handler_state=>HandlerState1, last_op=>sync}}.
+
+%% If FILESYNC_REPEAT_INTERVAL is set to a millisec value, this
+%% clause gets called repeatedly by the handler. In order to
+%% guarantee that a filesync *always* happens after the last log
+%% event, the repeat operation must be active!
+handle_cast(repeated_filesync,State = #{filesync_repeat_interval := no_repeat}) ->
+ %% This clause handles a race condition which may occur when
+ %% config changes filesync_repeat_interval from an integer value
+ %% to no_repeat.
+ {noreply,State};
+handle_cast(repeated_filesync,
+ State = #{id := Name,
+ module := Module,
+ handler_state := HandlerState,
+ last_op := LastOp}) ->
+ State1 =
+ if LastOp == sync ->
+ State;
+ true ->
+ {_,HS} = Module:filesync(Name, async, HandlerState),
+ State#{handler_state => HS, last_op => sync}
+ end,
+ {noreply,set_repeated_filesync(State1)};
+handle_cast({config_changed, CommonConfig, HConfig},
+ State = #{id := Name,
+ module := Module,
+ handler_state := HandlerState,
+ filesync_repeat_interval := OldFSyncInt}) ->
+ State1 =
+ case maps:get(filesync_repeat_interval,CommonConfig) of
+ OldFSyncInt ->
+ State;
+ FSyncInt ->
+ set_repeated_filesync(
+ cancel_repeated_filesync(
+ State#{filesync_repeat_interval=>FSyncInt}))
+ end,
+ HS = try Module:config_changed(Name, HConfig, HandlerState)
+ catch error:undef -> HandlerState
+ end,
+ {noreply, State1#{handler_state => HS}}.
+
+handle_info(Info, #{id := Name, module := Module,
+ handler_state := HandlerState} = State) ->
+ {noreply,State#{handler_state => Module:handle_info(Name,Info,HandlerState)}}.
+
+terminate(overloaded=Reason, #{id:=Name}=State) ->
+ _ = log_handler_info(Name,"Handler ~p overloaded and stopping",[Name],State),
+ do_terminate(Reason,State),
+ ConfigResult = logger:get_handler_config(Name),
+ case ConfigResult of
+ {ok,#{module:=Module}=HConfig0} ->
+ spawn(fun() -> logger:remove_handler(Name) end),
+ HConfig = try Module:filter_config(HConfig0)
+ catch _:_ -> HConfig0
+ end,
+ {ok,fun() -> logger:add_handler(Name,Module,HConfig) end};
+ Error ->
+ error_notify({Name,restart_impossible,Error}),
+ Error
+ end;
+terminate(Reason, State) ->
+ do_terminate(Reason, State).
+
+do_terminate(Reason, State = #{id := Name,
+ module := Module,
+ handler_state := HandlerState}) ->
+ _ = cancel_repeated_filesync(State),
+ _ = Module:terminate(Name, Reason, HandlerState),
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+reset_state(#{id:=Name, module:=Module, handler_state:=HandlerState} = State) ->
+ State#{handler_state=>Module:reset_state(Name, HandlerState)}.
+
+%%%-----------------------------------------------------------------
+%%% Internal functions
+call(Module, Name, Op) when is_atom(Name) ->
+ case logger_olp:call(?name_to_reg_name(Module,Name), Op) of
+ {error,busy} -> {error,handler_busy};
+ Other -> Other
+ end;
+call(_, Name, Op) ->
+ {error,{badarg,{Op,[Name]}}}.
+
+notify({mode_change,Mode0,Mode1},#{id:=Name}=State) ->
+ log_handler_info(Name,"Handler ~p switched from ~p to ~p mode",
+ [Name,Mode0,Mode1], State);
+notify({flushed,Flushed},#{id:=Name}=State) ->
+ log_handler_info(Name, "Handler ~p flushed ~w log events",
+ [Name,Flushed], State);
+notify(restart,#{id:=Name}=State) ->
+ log_handler_info(Name, "Handler ~p restarted", [Name], State);
+notify(idle,#{id:=Name,module:=Module,handler_state:=HandlerState}=State) ->
+ {_,HS} = Module:filesync(Name,async,HandlerState),
+ State#{handler_state=>HS, last_op=>sync}.
+
+log_handler_info(Name, Format, Args, #{module:=Module,
+ handler_state:=HandlerState}=State) ->
+ Config =
+ case logger:get_handler_config(Name) of
+ {ok,Conf} -> Conf;
+ _ -> #{formatter=>{?DEFAULT_FORMATTER,?DEFAULT_FORMAT_CONFIG}}
+ end,
+ Meta = #{time=>logger:timestamp()},
+ Bin = log_to_binary(#{level => notice,
+ msg => {Format,Args},
+ meta => Meta}, Config),
+ {_,HS} = Module:write(Name, async, Bin, HandlerState),
+ State#{handler_state=>HS, last_op=>write}.
+
+%%%-----------------------------------------------------------------
+%%% Convert log data on any form to binary
+-spec log_to_binary(LogEvent,Config) -> LogString when
+ LogEvent :: logger:log_event(),
+ Config :: logger:handler_config(),
+ LogString :: binary().
+log_to_binary(#{msg:={report,_},meta:=#{report_cb:=_}}=Log,Config) ->
+ do_log_to_binary(Log,Config);
+log_to_binary(#{msg:={report,_},meta:=Meta}=Log,Config) ->
+ DefaultReportCb = fun logger:format_otp_report/1,
+ do_log_to_binary(Log#{meta=>Meta#{report_cb=>DefaultReportCb}},Config);
+log_to_binary(Log,Config) ->
+ do_log_to_binary(Log,Config).
+
+do_log_to_binary(Log,Config) ->
+ {Formatter,FormatterConfig} =
+ maps:get(formatter,Config,{?DEFAULT_FORMATTER,?DEFAULT_FORMAT_CONFIG}),
+ String = try_format(Log,Formatter,FormatterConfig),
+ try string_to_binary(String)
+ catch C2:R2:S2 ->
+ ?LOG_INTERNAL(debug,[{formatter_error,Formatter},
+ {config,FormatterConfig},
+ {log_event,Log},
+ {bad_return_value,String},
+ {catched,{C2,R2,S2}}]),
+ <<"FORMATTER ERROR: bad return value">>
+ end.
+
+try_format(Log,Formatter,FormatterConfig) ->
+ try Formatter:format(Log,FormatterConfig)
+ catch
+ C:R:S ->
+ ?LOG_INTERNAL(debug,[{formatter_crashed,Formatter},
+ {config,FormatterConfig},
+ {log_event,Log},
+ {reason,
+ {C,R,logger:filter_stacktrace(?MODULE,S)}}]),
+ case {?DEFAULT_FORMATTER,#{}} of
+ {Formatter,FormatterConfig} ->
+ "DEFAULT FORMATTER CRASHED";
+ {DefaultFormatter,DefaultConfig} ->
+ try_format(Log#{msg=>{"FORMATTER CRASH: ~tp",
+ [maps:get(msg,Log)]}},
+ DefaultFormatter,DefaultConfig)
+ end
+ end.
+
+string_to_binary(String) ->
+ case unicode:characters_to_binary(String) of
+ Binary when is_binary(Binary) ->
+ Binary;
+ Error ->
+ throw(Error)
+ end.
+
+%%%-----------------------------------------------------------------
+%%% Check that the configuration term is valid
+check_config(Config) when is_map(Config) ->
+ check_common_config(maps:to_list(Config)).
+
+check_common_config([{filesync_repeat_interval,NorA}|Config])
+ when is_integer(NorA); NorA == no_repeat ->
+ check_common_config(Config);
+check_common_config([{Key,Value}|_]) ->
+ {error,#{Key=>Value}};
+check_common_config([]) ->
+ ok.
+
+get_default_config() ->
+ #{filesync_repeat_interval => ?FILESYNC_REPEAT_INTERVAL}.
+
+set_repeated_filesync(#{filesync_repeat_interval:=FSyncInt} = State)
+ when is_integer(FSyncInt) ->
+ {ok,TRef} = timer:apply_after(FSyncInt, gen_server, cast,
+ [self(),repeated_filesync]),
+ State#{rep_sync_tref=>TRef};
+set_repeated_filesync(State) ->
+ State.
+
+cancel_repeated_filesync(State) ->
+ case maps:take(rep_sync_tref,State) of
+ {TRef,State1} ->
+ _ = timer:cancel(TRef),
+ State1;
+ error ->
+ State
+ end.
+error_notify(Term) ->
+ ?internal_log(error, Term).
diff --git a/lib/kernel/src/logger_h_common.hrl b/lib/kernel/src/logger_h_common.hrl
new file mode 100644
index 0000000000..004a61d9d9
--- /dev/null
+++ b/lib/kernel/src/logger_h_common.hrl
@@ -0,0 +1,127 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-2015. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%% The handler sends asynchronous write requests to the process
+%% controlling the i/o device, but every once in this interval
+%% will the write request be synchronous, so that the i/o device
+%% process doesn't get overloaded. This gives the handler time
+%% to keep up with its mailbox in overload situations, even if
+%% the i/o is slow.
+-define(CONTROLLER_SYNC_INTERVAL, 20).
+%% The handler will not perform a file sync operation if the
+%% mailbox size is greater than this number. This is to ensure
+%% the handler process doesn't get overloaded while waiting for
+%% an expensive file sync operation to finish.
+-define(FILESYNC_OK_QLEN, 2).
+%% Do a file/disk_log sync operation every integer() millisec
+%% (if necessary) or set to 'no_repeat' to only do file sync when
+%% the handler is idle. Note that file sync is not guaranteed to
+%% happen automatically if this operation is disabled.
+-define(FILESYNC_REPEAT_INTERVAL, 5000).
+%%-define(FILESYNC_REPEAT_INTERVAL, no_repeat).
+
+%% Default disk log option values
+-define(DISK_LOG_TYPE, wrap).
+-define(DISK_LOG_MAX_NO_FILES, 10).
+-define(DISK_LOG_MAX_NO_BYTES, 1048576).
+
+%%%-----------------------------------------------------------------
+%%% Utility macros
+
+-define(name_to_reg_name(MODULE,Name),
+ list_to_atom(lists:concat([MODULE,"_",Name]))).
+
+%%%-----------------------------------------------------------------
+%%% The test hook macros make it possible to observe and manipulate
+%%% internal handler functionality. When enabled, these macros will
+%%% slow down execution and therefore should not be include in code
+%%% to be officially released.
+
+%%-define(TEST_HOOKS, true).
+-ifdef(TEST_HOOKS).
+ -define(TEST_HOOKS_TAB, logger_h_test_hooks).
+
+ -define(init_test_hooks(),
+ _ = case ets:whereis(?TEST_HOOKS_TAB) of
+ undefined -> ets:new(?TEST_HOOKS_TAB, [named_table,public]);
+ _ -> ok
+ end,
+ ets:insert(?TEST_HOOKS_TAB, {internal_log,{logger,internal_log}}),
+ ets:insert(?TEST_HOOKS_TAB, {file_write,ok}),
+ ets:insert(?TEST_HOOKS_TAB, {file_datasync,ok}),
+ ets:insert(?TEST_HOOKS_TAB, {disk_log_write,ok}),
+ ets:insert(?TEST_HOOKS_TAB, {disk_log_sync,ok})).
+
+ -define(set_internal_log(MOD_FUNC),
+ ets:insert(?TEST_HOOKS_TAB, {internal_log,MOD_FUNC})).
+
+ -define(set_result(OPERATION, RESULT),
+ ets:insert(?TEST_HOOKS_TAB, {OPERATION,RESULT})).
+
+ -define(set_defaults(),
+ ets:insert(?TEST_HOOKS_TAB, {internal_log,{logger,internal_log}}),
+ ets:insert(?TEST_HOOKS_TAB, {file_write,ok}),
+ ets:insert(?TEST_HOOKS_TAB, {file_datasync,ok}),
+ ets:insert(?TEST_HOOKS_TAB, {disk_log_write,ok}),
+ ets:insert(?TEST_HOOKS_TAB, {disk_log_sync,ok})).
+
+ -define(internal_log(TYPE, TERM),
+ try ets:lookup(?TEST_HOOKS_TAB, internal_log) of
+ [{_,{LMOD,LFUNC}}] -> apply(LMOD, LFUNC, [TYPE,TERM]);
+ _ -> logger:internal_log(TYPE, TERM)
+ catch _:_ -> logger:internal_log(TYPE, TERM) end).
+
+ -define(file_write(DEVICE, DATA),
+ try ets:lookup(?TEST_HOOKS_TAB, file_write) of
+ [{_,ok}] -> file:write(DEVICE, DATA);
+ [{_,ERROR}] -> ERROR
+ catch _:_ -> file:write(DEVICE, DATA) end).
+
+ -define(file_datasync(DEVICE),
+ try ets:lookup(?TEST_HOOKS_TAB, file_datasync) of
+ [{_,ok}] -> file:datasync(DEVICE);
+ [{_,ERROR}] -> ERROR
+ catch _:_ -> file:datasync(DEVICE) end).
+
+ -define(disk_log_write(LOG, MODE, DATA),
+ try ets:lookup(?TEST_HOOKS_TAB, disk_log_write) of
+ [{_,ok}] -> disk_log_write(LOG, MODE, DATA);
+ [{_,ERROR}] -> ERROR
+ catch _:_ -> disk_log_write(LOG, MODE, DATA) end).
+
+ -define(disk_log_sync(LOG),
+ try ets:lookup(?TEST_HOOKS_TAB, disk_log_sync) of
+ [{_,ok}] -> disk_log:sync(LOG);
+ [{_,ERROR}] -> ERROR
+ catch _:_ -> disk_log:sync(LOG) end).
+
+
+-else. % DEFAULTS!
+ -define(TEST_HOOKS_TAB, undefined).
+ -define(init_test_hooks(), ok).
+ -define(set_internal_log(_MOD_FUNC), ok).
+ -define(set_result(_OPERATION, _RESULT), ok).
+ -define(set_defaults(), ok).
+ -define(internal_log(TYPE, TERM), logger:internal_log(TYPE, TERM)).
+ -define(file_write(DEVICE, DATA), file:write(DEVICE, DATA)).
+ -define(file_datasync(DEVICE), file:datasync(DEVICE)).
+ -define(disk_log_write(LOG, MODE, DATA), disk_log_write(LOG, MODE, DATA)).
+ -define(disk_log_sync(LOG), disk_log:sync(LOG)).
+-endif.
diff --git a/lib/kernel/src/logger_handler_watcher.erl b/lib/kernel/src/logger_handler_watcher.erl
new file mode 100644
index 0000000000..b75c74c643
--- /dev/null
+++ b/lib/kernel/src/logger_handler_watcher.erl
@@ -0,0 +1,113 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(logger_handler_watcher).
+
+-behaviour(gen_server).
+
+%% API
+-export([start_link/0]).
+-export([register_handler/2]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2]).
+
+-define(SERVER, ?MODULE).
+
+-record(state, {handlers}).
+
+%%%===================================================================
+%%% API
+%%%===================================================================
+
+-spec start_link() -> {ok, Pid :: pid()} |
+ {error, Error :: {already_started, pid()}} |
+ {error, Error :: term()} |
+ ignore.
+start_link() ->
+ gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
+
+-spec register_handler(Id::logger:handler_id(),Pid::pid()) -> ok.
+register_handler(Id,Pid) ->
+ gen_server:call(?SERVER,{register,Id,Pid}).
+
+%%%===================================================================
+%%% gen_server callbacks
+%%%===================================================================
+
+-spec init(Args :: term()) -> {ok, State :: term()} |
+ {ok, State :: term(), Timeout :: timeout()} |
+ {ok, State :: term(), hibernate} |
+ {stop, Reason :: term()} |
+ ignore.
+init([]) ->
+ process_flag(trap_exit, true),
+ {ok, #state{handlers=[]}}.
+
+-spec handle_call(Request :: term(), From :: {pid(), term()}, State :: term()) ->
+ {reply, Reply :: term(), NewState :: term()} |
+ {reply, Reply :: term(), NewState :: term(), Timeout :: timeout()} |
+ {reply, Reply :: term(), NewState :: term(), hibernate} |
+ {noreply, NewState :: term()} |
+ {noreply, NewState :: term(), Timeout :: timeout()} |
+ {noreply, NewState :: term(), hibernate} |
+ {stop, Reason :: term(), Reply :: term(), NewState :: term()} |
+ {stop, Reason :: term(), NewState :: term()}.
+handle_call({register,Id,Pid}, _From, #state{handlers=Hs}=State) ->
+ Ref = erlang:monitor(process,Pid),
+ Hs1 = lists:keystore(Id,1,Hs,{Id,Ref}),
+ {reply, ok, State#state{handlers=Hs1}}.
+
+-spec handle_cast(Request :: term(), State :: term()) ->
+ {noreply, NewState :: term()} |
+ {noreply, NewState :: term(), Timeout :: timeout()} |
+ {noreply, NewState :: term(), hibernate} |
+ {stop, Reason :: term(), NewState :: term()}.
+handle_cast(_Request, State) ->
+ {noreply, State}.
+
+-spec handle_info(Info :: timeout() | term(), State :: term()) ->
+ {noreply, NewState :: term()} |
+ {noreply, NewState :: term(), Timeout :: timeout()} |
+ {noreply, NewState :: term(), hibernate} |
+ {stop, Reason :: normal | term(), NewState :: term()}.
+handle_info({'DOWN',Ref,process,_,shutdown}, #state{handlers=Hs}=State) ->
+ case lists:keytake(Ref,2,Hs) of
+ {value,{Id,Ref},Hs1} ->
+ %% Probably terminated by supervisor. Remove the handler to avoid
+ %% error printouts due to failing handler.
+ _ = case logger:get_handler_config(Id) of
+ {ok,_} ->
+ logger:remove_handler(Id);
+ _ ->
+ ok
+ end,
+ {noreply,State#state{handlers=Hs1}};
+ false ->
+ {noreply, State}
+ end;
+handle_info({'DOWN',Ref,process,_,_OtherReason}, #state{handlers=Hs}=State) ->
+ {noreply,State#state{handlers=lists:keydelete(Ref,2,Hs)}};
+handle_info(_Other,State) ->
+ {noreply,State}.
+
+-spec terminate(Reason :: normal | shutdown | {shutdown, term()} | term(),
+ State :: term()) -> any().
+terminate(_Reason, _State) ->
+ ok.
diff --git a/lib/kernel/src/logger_internal.hrl b/lib/kernel/src/logger_internal.hrl
new file mode 100644
index 0000000000..e53922e5d3
--- /dev/null
+++ b/lib/kernel/src/logger_internal.hrl
@@ -0,0 +1,104 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-include_lib("kernel/include/logger.hrl").
+-define(LOGGER_TABLE,logger).
+-define(PROXY_KEY,'$proxy_config$').
+-define(PRIMARY_KEY,'$primary_config$').
+-define(HANDLER_KEY,'$handler_config$').
+-define(LOGGER_META_KEY,'$logger_metadata$').
+-define(STANDARD_HANDLER, default).
+-define(DEFAULT_HANDLER_FILTERS,?DEFAULT_HANDLER_FILTERS([otp])).
+-define(DEFAULT_HANDLER_FILTERS(Domain),
+ [{remote_gl,{fun logger_filters:remote_gl/2,stop}},
+ {domain,{fun logger_filters:domain/2,{log,super,Domain}}},
+ {no_domain,{fun logger_filters:domain/2,{log,undefined,[]}}}]).
+-define(DEFAULT_FORMATTER,logger_formatter).
+-define(DEFAULT_FORMAT_CONFIG,#{legacy_header=>true,
+ single_line=>false}).
+-define(DEFAULT_FORMAT_TEMPLATE_HEADER,
+ [[logger_formatter,header],"\n",msg,"\n"]).
+-define(DEFAULT_FORMAT_TEMPLATE_SINGLE,
+ [time," ",level,": ",msg,"\n"]).
+-define(DEFAULT_FORMAT_TEMPLATE,
+ [time," ",level,":\n",msg,"\n"]).
+
+-define(DEFAULT_LOGGER_CALL_TIMEOUT, infinity).
+
+-define(LOG_INTERNAL(Level,Report),?DO_LOG_INTERNAL(Level,[Report])).
+-define(LOG_INTERNAL(Level,Format,Args),?DO_LOG_INTERNAL(Level,[Format,Args])).
+-define(DO_LOG_INTERNAL(Level,Data),
+ case logger:allow(Level,?MODULE) of
+ true ->
+ %% Spawn this to avoid deadlocks
+ _ = spawn(logger,macro_log,[?LOCATION,Level|Data]++
+ [logger:add_default_metadata(#{})]),
+ ok;
+ false ->
+ ok
+ end).
+
+%%%-----------------------------------------------------------------
+%%% Levels
+%%% Using same as syslog
+-define(LEVELS,[none,
+ emergency,
+ alert,
+ critical,
+ error,
+ warning,
+ notice,
+ info,
+ debug,
+ all]).
+-define(LOG_NONE,-1).
+-define(EMERGENCY,0).
+-define(ALERT,1).
+-define(CRITICAL,2).
+-define(ERROR,3).
+-define(WARNING,4).
+-define(NOTICE,5).
+-define(INFO,6).
+-define(DEBUG,7).
+-define(LOG_ALL,10).
+
+-define(IS_LEVEL(L),
+ (L=:=emergency orelse
+ L=:=alert orelse
+ L=:=critical orelse
+ L=:=error orelse
+ L=:=warning orelse
+ L=:=notice orelse
+ L=:=info orelse
+ L=:=debug)).
+
+-define(IS_MSG(Msg),
+ ((is_tuple(Msg) andalso tuple_size(Msg)==2)
+ andalso
+ (is_list(element(1,Msg)) andalso is_list(element(2,Msg)))
+ orelse
+ (element(1,Msg)==report andalso ?IS_REPORT(element(2,Msg)))
+ orelse
+ (element(1,Msg)==string andalso ?IS_STRING(element(2,Msg))))).
+
+-define(IS_REPORT(Report),
+ (is_map(Report) orelse (is_list(Report) andalso is_tuple(hd(Report))))).
+
+-define(IS_STRING(String),
+ (is_list(String) orelse is_binary(String))).
diff --git a/lib/kernel/src/logger_olp.erl b/lib/kernel/src/logger_olp.erl
new file mode 100644
index 0000000000..8365383fe2
--- /dev/null
+++ b/lib/kernel/src/logger_olp.erl
@@ -0,0 +1,627 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(logger_olp).
+-behaviour(gen_server).
+
+-include("logger_olp.hrl").
+-include("logger_internal.hrl").
+
+%% API
+-export([start_link/4, load/2, info/1, reset/1, stop/1, restart/1,
+ set_opts/2, get_opts/1, get_default_opts/0, get_pid/1,
+ call/2, cast/2, get_ref/0, get_ref/1]).
+
+%% gen_server and proc_lib callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+-define(OPT_KEYS,[sync_mode_qlen,
+ drop_mode_qlen,
+ flush_qlen,
+ burst_limit_enable,
+ burst_limit_max_count,
+ burst_limit_window_time,
+ overload_kill_enable,
+ overload_kill_qlen,
+ overload_kill_mem_size,
+ overload_kill_restart_after]).
+
+-export_type([olp_ref/0, options/0]).
+
+-opaque olp_ref() :: {atom(),pid(),ets:tid()}.
+
+-type options() :: logger:olp_config().
+
+%%%-----------------------------------------------------------------
+%%% API
+
+-spec start_link(Name,Module,Args,Options) -> {ok,Pid,Olp} | {error,Reason} when
+ Name :: atom(),
+ Module :: module(),
+ Args :: term(),
+ Options :: options(),
+ Pid :: pid(),
+ Olp :: olp_ref(),
+ Reason :: term().
+start_link(Name,Module,Args,Options0) when is_map(Options0) ->
+ Options = maps:merge(get_default_opts(),Options0),
+ case check_opts(Options) of
+ ok ->
+ proc_lib:start_link(?MODULE,init,[[Name,Module,Args,Options]]);
+ Error ->
+ Error
+ end.
+
+-spec load(Olp, Msg) -> ok when
+ Olp :: olp_ref(),
+ Msg :: term().
+load({_Name,Pid,ModeRef},Msg) ->
+ %% If the process is getting overloaded, the message will be
+ %% synchronous instead of asynchronous (slows down the tempo of a
+ %% process causing much load). If the process is choked, drop mode
+ %% is set and no message is sent.
+ try ?get_mode(ModeRef) of
+ async ->
+ gen_server:cast(Pid, {'$olp_load',Msg});
+ sync ->
+ case call(Pid, {'$olp_load',Msg}) of
+ ok ->
+ ok;
+ _Other ->
+ %% dropped or {error,busy}
+ ?observe(_Name,{dropped,1}),
+ ok
+ end;
+ drop ->
+ ?observe(_Name,{dropped,1})
+ catch
+ %% if the ETS table doesn't exist (maybe because of a
+ %% process restart), we can only drop the event
+ _:_ -> ?observe(_Name,{dropped,1})
+ end,
+ ok.
+
+-spec info(Olp) -> map() | {error, busy} when
+ Olp :: atom() | pid() | olp_ref().
+info(Olp) ->
+ call(Olp, info).
+
+-spec reset(Olp) -> ok | {error, busy} when
+ Olp :: atom() | pid() | olp_ref().
+reset(Olp) ->
+ call(Olp, reset).
+
+-spec stop(Olp) -> ok when
+ Olp :: atom() | pid() | olp_ref().
+stop({_Name,Pid,_ModRef}) ->
+ stop(Pid);
+stop(Pid) ->
+ _ = gen_server:call(Pid, stop),
+ ok.
+
+-spec set_opts(Olp, Opts) -> ok | {error,term()} | {error, busy} when
+ Olp :: atom() | pid() | olp_ref(),
+ Opts :: options().
+set_opts(Olp, Opts) ->
+ call(Olp, {set_opts,Opts}).
+
+-spec get_opts(Olp) -> options() | {error, busy} when
+ Olp :: atom() | pid() | olp_ref().
+get_opts(Olp) ->
+ call(Olp, get_opts).
+
+-spec get_default_opts() -> options().
+get_default_opts() ->
+ #{sync_mode_qlen => ?SYNC_MODE_QLEN,
+ drop_mode_qlen => ?DROP_MODE_QLEN,
+ flush_qlen => ?FLUSH_QLEN,
+ burst_limit_enable => ?BURST_LIMIT_ENABLE,
+ burst_limit_max_count => ?BURST_LIMIT_MAX_COUNT,
+ burst_limit_window_time => ?BURST_LIMIT_WINDOW_TIME,
+ overload_kill_enable => ?OVERLOAD_KILL_ENABLE,
+ overload_kill_qlen => ?OVERLOAD_KILL_QLEN,
+ overload_kill_mem_size => ?OVERLOAD_KILL_MEM_SIZE,
+ overload_kill_restart_after => ?OVERLOAD_KILL_RESTART_AFTER}.
+
+-spec restart(fun(() -> any())) -> ok.
+restart(Fun) ->
+ Result =
+ try Fun()
+ catch C:R:S ->
+ {error,{restart_failed,Fun,C,R,S}}
+ end,
+ ?LOG_INTERNAL(debug,[{logger_olp,restart},
+ {result,Result}]),
+ ok.
+
+-spec get_ref() -> olp_ref().
+get_ref() ->
+ get(olp_ref).
+
+-spec get_ref(PidOrName) -> olp_ref() | {error, busy} when
+ PidOrName :: pid() | atom().
+get_ref(PidOrName) ->
+ call(PidOrName,get_ref).
+
+-spec get_pid(olp_ref()) -> pid().
+get_pid({_Name,Pid,_ModeRef}) ->
+ Pid.
+
+%%%===================================================================
+%%% gen_server callbacks
+%%%===================================================================
+
+init([Name,Module,Args,Options]) ->
+ register(Name, self()),
+ process_flag(message_queue_data, off_heap),
+
+ ?start_observation(Name),
+
+ try ets:new(Name, [public]) of
+ ModeRef ->
+ OlpRef = {Name,self(),ModeRef},
+ put(olp_ref,OlpRef),
+ try Module:init(Args) of
+ {ok,CBState} ->
+ ?set_mode(ModeRef, async),
+ T0 = ?timestamp(),
+ proc_lib:init_ack({ok,self(),OlpRef}),
+ %% Storing options in state to avoid copying
+ %% (sending) the option data with each message
+ State0 = ?merge_with_stats(
+ Options#{id => Name,
+ idle=> true,
+ module => Module,
+ mode_ref => ModeRef,
+ mode => async,
+ last_qlen => 0,
+ last_load_ts => T0,
+ burst_win_ts => T0,
+ burst_msg_count => 0,
+ cb_state => CBState}),
+ State = reset_restart_flag(State0),
+ gen_server:enter_loop(?MODULE, [], State);
+ Error ->
+ _ = ets:delete(ModeRef),
+ unregister(Name),
+ proc_lib:init_ack(Error)
+ catch
+ _:Error ->
+ _ = ets:delete(ModeRef),
+ unregister(Name),
+ proc_lib:init_ack(Error)
+ end
+ catch
+ _:Error ->
+ unregister(Name),
+ proc_lib:init_ack(Error)
+ end.
+
+%% This is the synchronous load event.
+handle_call({'$olp_load', Msg}, _From, State) ->
+ {Result,State1} = do_load(Msg, call, State#{idle=>false}),
+ %% Result == ok | dropped
+ reply_return(Result,State1);
+
+handle_call(get_ref,_From,#{id:=Name,mode_ref:=ModeRef}=State) ->
+ reply_return({Name,self(),ModeRef},State);
+
+handle_call({set_opts,Opts0},_From,State) ->
+ Opts = maps:merge(maps:with(?OPT_KEYS,State),Opts0),
+ case check_opts(Opts) of
+ ok ->
+ reply_return(ok, maps:merge(State,Opts));
+ Error ->
+ reply_return(Error, State)
+ end;
+
+handle_call(get_opts,_From,State) ->
+ reply_return(maps:with(?OPT_KEYS,State), State);
+
+handle_call(info, _From, State) ->
+ reply_return(State, State);
+
+handle_call(reset, _From, #{module:=Module,cb_state:=CBState}=State) ->
+ State1 = ?merge_with_stats(State),
+ CBState1 = try_callback_call(Module,reset_state,[CBState],CBState),
+ reply_return(ok, State1#{idle => true,
+ last_qlen => 0,
+ last_load_ts => ?timestamp(),
+ cb_state => CBState1});
+
+handle_call(stop, _From, State) ->
+ {stop, {shutdown,stopped}, ok, State};
+
+handle_call(Msg, From, #{module:=Module,cb_state:=CBState}=State) ->
+ case try_callback_call(Module,handle_call,[Msg, From, CBState]) of
+ {reply,Reply,CBState1} ->
+ reply_return(Reply,State#{cb_state=>CBState1});
+ {noreply,CBState1} ->
+ noreply_return(State#{cb_state=>CBState1});
+ {stop, Reason, Reply, CBState1} ->
+ {stop, Reason, Reply, State#{cb_state=>CBState1}};
+ {stop, Reason, CBState1} ->
+ {stop, Reason, State#{cb_state=>CBState1}}
+ end.
+
+%% This is the asynchronous load event.
+handle_cast({'$olp_load', Msg}, State) ->
+ {_Result,State1} = do_load(Msg, cast, State#{idle=>false}),
+ noreply_return(State1);
+
+handle_cast(Msg, #{module:=Module, cb_state:=CBState} = State) ->
+ case try_callback_call(Module,handle_cast,[Msg, CBState]) of
+ {noreply,CBState1} ->
+ noreply_return(State#{cb_state=>CBState1});
+ {stop, Reason, CBState1} ->
+ {stop, Reason, State#{cb_state=>CBState1}}
+ end.
+
+handle_info(timeout, #{mode_ref:=_ModeRef, mode:=Mode} = State) ->
+ State1 = notify(idle,State),
+ State2 = maybe_notify_mode_change(async,State1),
+ {noreply, State2#{idle => true,
+ mode => ?change_mode(_ModeRef, Mode, async),
+ burst_msg_count => 0}};
+handle_info(Msg, #{module := Module, cb_state := CBState} = State) ->
+ case try_callback_call(Module,handle_info,[Msg, CBState]) of
+ {noreply,CBState1} ->
+ noreply_return(State#{cb_state=>CBState1});
+ {stop, Reason, CBState1} ->
+ {stop, Reason, State#{cb_state=>CBState1}};
+ {load,CBState1} ->
+ {_,State1} = do_load(Msg, cast, State#{idle=>false,
+ cb_state=>CBState1}),
+ noreply_return(State1)
+ end.
+
+terminate({shutdown,{overloaded,_QLen,_Mem}},
+ #{id:=Name, module := Module, cb_state := CBState,
+ overload_kill_restart_after := RestartAfter} = State) ->
+ %% We're terminating because of an overload situation (see
+ %% kill_if_choked/3).
+ unregister(Name), %%!!!! to avoid error printout of callback crashed on stop
+ case try_callback_call(Module,terminate,[overloaded,CBState],ok) of
+ {ok,Fun} when is_function(Fun,0), is_integer(RestartAfter) ->
+ set_restart_flag(State),
+ _ = timer:apply_after(RestartAfter,?MODULE,restart,[Fun]),
+ ok;
+ _ ->
+ ok
+ end;
+terminate(Reason, #{id:=Name, module:=Module, cb_state:=CBState}) ->
+ _ = try_callback_call(Module,terminate,[Reason,CBState],ok),
+ unregister(Name),
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+
+%%%-----------------------------------------------------------------
+%%% Internal functions
+-spec call(Olp, term()) -> term() | {error,busy} when
+ Olp :: atom() | pid() | olp_ref().
+call({_Name, Pid, _ModeRef},Msg) ->
+ call(Pid, Msg);
+call(Server, Msg) ->
+ try
+ gen_server:call(Server, Msg)
+ catch
+ _:{timeout,_} -> {error,busy}
+ end.
+
+-spec cast(olp_ref(),term()) -> ok.
+cast({_Name, Pid, _ModeRef},Msg) ->
+ gen_server:cast(Pid, Msg).
+
+%% check for overload between every event (and set Mode to async,
+%% sync or drop accordingly), but never flush the whole mailbox
+%% before LogWindowSize events have been handled
+do_load(Msg, CallOrCast, State) ->
+ T1 = ?timestamp(),
+ State1 = ?update_time(T1,State),
+
+ %% check if the process is getting overloaded, or if it's
+ %% recovering from overload (the check must be done for each
+ %% event to react quickly to large bursts of events and
+ %% to ensure that the handler can never end up in drop mode
+ %% with an empty mailbox, which would stop operation)
+ {Mode1,QLen,Mem,State2} = check_load(State1),
+
+ %% kill the handler if it can't keep up with the load
+ kill_if_choked(QLen, Mem, State2),
+
+ if Mode1 == flush ->
+ flush(T1, State2);
+ true ->
+ handle_load(Mode1, T1, Msg, CallOrCast, State2)
+ end.
+
+%% this function is called by do_load/3 after an overload check
+%% has been performed, where QLen > FlushQLen
+flush(T1, State=#{id := _Name, mode := Mode, last_load_ts := _T0, mode_ref := ModeRef}) ->
+ %% flush load messages in the mailbox (a limited number in order
+ %% to not cause long delays)
+ NewFlushed = flush_load(?FLUSH_MAX_N),
+
+ %% write info in log about flushed messages
+ State1=notify({flushed,NewFlushed},State),
+
+ %% because of the receive loop when flushing messages, the
+ %% handler will be scheduled out often and the mailbox could
+ %% grow very large, so we'd better check the queue again here
+ {_,QLen1} = process_info(self(), message_queue_len),
+ ?observe(_Name,{max_qlen,QLen1}),
+
+ %% Add 1 for the current log event
+ ?observe(_Name,{flushed,NewFlushed+1}),
+
+ State2 = ?update_max_time(?diff_time(T1,_T0),State1),
+ State3 = ?update_max_qlen(QLen1,State2),
+ State4 = maybe_notify_mode_change(async,State3),
+ {dropped,?update_other(flushed,FLUSHED,NewFlushed,
+ State4#{mode => ?change_mode(ModeRef,Mode,async),
+ last_qlen => QLen1,
+ last_load_ts => T1})}.
+
+%% this function is called to actually handle the message
+handle_load(Mode, T1, Msg, _CallOrCast,
+ State = #{id := _Name,
+ module := Module,
+ cb_state := CBState,
+ last_qlen := LastQLen,
+ last_load_ts := _T0}) ->
+ %% check if we need to limit the number of writes
+ %% during a burst of log events
+ {DoWrite,State1} = limit_burst(State),
+
+ {Result,LastQLen1,CBState1} =
+ if DoWrite ->
+ ?observe(_Name,{_CallOrCast,1}),
+ CBS = try_callback_call(Module,handle_load,[Msg,CBState]),
+ {ok,element(2, process_info(self(), message_queue_len)),CBS};
+ true ->
+ ?observe(_Name,{flushed,1}),
+ {dropped,LastQLen,CBState}
+ end,
+ State2 = State1#{cb_state=>CBState1},
+
+ State3 = State2#{mode => Mode},
+ State4 = ?update_calls_or_casts(_CallOrCast,1,State3),
+ State5 = ?update_max_qlen(LastQLen1,State4),
+ State6 =
+ ?update_max_time(?diff_time(T1,_T0),
+ State5#{last_qlen := LastQLen1,
+ last_load_ts => T1}),
+ State7 = case Result of
+ ok ->
+ S = ?update_freq(T1,State6),
+ ?update_other(writes,WRITES,1,S);
+ _ ->
+ State6
+ end,
+ {Result,State7}.
+
+
+%%%-----------------------------------------------------------------
+%%% Check that the options are valid
+check_opts(Options) when is_map(Options) ->
+ case do_check_opts(maps:to_list(Options)) of
+ ok ->
+ case overload_levels_ok(Options) of
+ true ->
+ ok;
+ false ->
+ Faulty = maps:with([sync_mode_qlen,
+ drop_mode_qlen,
+ flush_qlen],Options),
+ {error,{invalid_olp_levels,Faulty}}
+ end;
+ {error,Key,Value} ->
+ {error,{invalid_olp_config,#{Key=>Value}}}
+ end.
+
+do_check_opts([{sync_mode_qlen,N}|Options]) when is_integer(N) ->
+ do_check_opts(Options);
+do_check_opts([{drop_mode_qlen,N}|Options]) when is_integer(N) ->
+ do_check_opts(Options);
+do_check_opts([{flush_qlen,N}|Options]) when is_integer(N) ->
+ do_check_opts(Options);
+do_check_opts([{burst_limit_enable,Bool}|Options]) when is_boolean(Bool) ->
+ do_check_opts(Options);
+do_check_opts([{burst_limit_max_count,N}|Options]) when is_integer(N) ->
+ do_check_opts(Options);
+do_check_opts([{burst_limit_window_time,N}|Options]) when is_integer(N) ->
+ do_check_opts(Options);
+do_check_opts([{overload_kill_enable,Bool}|Options]) when is_boolean(Bool) ->
+ do_check_opts(Options);
+do_check_opts([{overload_kill_qlen,N}|Options]) when is_integer(N) ->
+ do_check_opts(Options);
+do_check_opts([{overload_kill_mem_size,N}|Options]) when is_integer(N) ->
+ do_check_opts(Options);
+do_check_opts([{overload_kill_restart_after,NorA}|Options])
+ when is_integer(NorA); NorA == infinity ->
+ do_check_opts(Options);
+do_check_opts([{Key,Value}|_]) ->
+ {error,Key,Value};
+do_check_opts([]) ->
+ ok.
+
+set_restart_flag(#{id := Name, module := Module}) ->
+ Flag = list_to_atom(lists:concat([Module,"_",Name,"_restarting"])),
+ spawn(fun() ->
+ register(Flag, self()),
+ timer:sleep(infinity)
+ end),
+ ok.
+
+reset_restart_flag(#{id := Name, module := Module} = State) ->
+ Flag = list_to_atom(lists:concat([Module,"_",Name,"_restarting"])),
+ case whereis(Flag) of
+ undefined ->
+ State;
+ Pid ->
+ exit(Pid, kill),
+ notify(restart,State)
+ end.
+
+check_load(State = #{id:=_Name, mode_ref := ModeRef, mode := Mode,
+ sync_mode_qlen := SyncModeQLen,
+ drop_mode_qlen := DropModeQLen,
+ flush_qlen := FlushQLen}) ->
+ {_,Mem} = process_info(self(), memory),
+ ?observe(_Name,{max_mem,Mem}),
+ {_,QLen} = process_info(self(), message_queue_len),
+ ?observe(_Name,{max_qlen,QLen}),
+ %% When the handler process gets scheduled in, it's impossible
+ %% to predict the QLen. We could jump "up" arbitrarily from say
+ %% async to sync, async to drop, sync to flush, etc. However, when
+ %% the handler process manages the log events (without flushing),
+ %% one after the other, we will move "down" from drop to sync and
+ %% from sync to async. This way we don't risk getting stuck in
+ %% drop or sync mode with an empty mailbox.
+ {Mode1,_NewDrops,_NewFlushes} =
+ if
+ QLen >= FlushQLen ->
+ {flush, 0,1};
+ QLen >= DropModeQLen ->
+ %% Note that drop mode will force load messages to
+ %% be dropped on the client side (never sent to
+ %% the olp process).
+ IncDrops = if Mode == drop -> 0; true -> 1 end,
+ {?change_mode(ModeRef, Mode, drop), IncDrops,0};
+ QLen >= SyncModeQLen ->
+ {?change_mode(ModeRef, Mode, sync), 0,0};
+ true ->
+ {?change_mode(ModeRef, Mode, async), 0,0}
+ end,
+ State1 = ?update_other(drops,DROPS,_NewDrops,State),
+ State2 = ?update_max_qlen(QLen,State1),
+ State3 = ?update_max_mem(Mem,State2),
+ State4 = maybe_notify_mode_change(Mode1,State3),
+ {Mode1, QLen, Mem,
+ ?update_other(flushes,FLUSHES,_NewFlushes,
+ State4#{last_qlen => QLen})}.
+
+limit_burst(#{burst_limit_enable := false}=State) ->
+ {true,State};
+limit_burst(#{burst_win_ts := BurstWinT0,
+ burst_msg_count := BurstMsgCount,
+ burst_limit_window_time := BurstLimitWinTime,
+ burst_limit_max_count := BurstLimitMaxCnt} = State) ->
+ if (BurstMsgCount >= BurstLimitMaxCnt) ->
+ %% the limit for allowed messages has been reached
+ BurstWinT1 = ?timestamp(),
+ case ?diff_time(BurstWinT1,BurstWinT0) of
+ BurstCheckTime when BurstCheckTime < (BurstLimitWinTime*1000) ->
+ %% we're still within the burst time frame
+ {false,?update_other(burst_drops,BURSTS,1,State)};
+ _BurstCheckTime ->
+ %% burst time frame passed, reset counters
+ {true,State#{burst_win_ts => BurstWinT1,
+ burst_msg_count => 0}}
+ end;
+ true ->
+ %% the limit for allowed messages not yet reached
+ {true,State#{burst_win_ts => BurstWinT0,
+ burst_msg_count => BurstMsgCount+1}}
+ end.
+
+kill_if_choked(QLen, Mem, #{overload_kill_enable := KillIfOL,
+ overload_kill_qlen := OLKillQLen,
+ overload_kill_mem_size := OLKillMem}) ->
+ if KillIfOL andalso
+ ((QLen > OLKillQLen) orelse (Mem > OLKillMem)) ->
+ exit({shutdown,{overloaded,QLen,Mem}});
+ true ->
+ ok
+ end.
+
+flush_load(Limit) ->
+ process_flag(priority, high),
+ Flushed = flush_load(0, Limit),
+ process_flag(priority, normal),
+ Flushed.
+
+flush_load(Limit, Limit) ->
+ Limit;
+flush_load(N, Limit) ->
+ %% flush log events but leave other events, such as info, reset
+ %% and stop, so that these have a chance to be processed even
+ %% under heavy load
+ receive
+ {'$gen_cast',{'$olp_load',_}} ->
+ flush_load(N+1, Limit);
+ {'$gen_call',{Pid,MRef},{'$olp_load',_}} ->
+ Pid ! {MRef, dropped},
+ flush_load(N+1, Limit);
+ {log,_,_,_,_} ->
+ flush_load(N+1, Limit);
+ {log,_,_,_} ->
+ flush_load(N+1, Limit)
+ after
+ 0 -> N
+ end.
+
+overload_levels_ok(Options) ->
+ SMQL = maps:get(sync_mode_qlen, Options, ?SYNC_MODE_QLEN),
+ DMQL = maps:get(drop_mode_qlen, Options, ?DROP_MODE_QLEN),
+ FQL = maps:get(flush_qlen, Options, ?FLUSH_QLEN),
+ (DMQL > 1) andalso (SMQL =< DMQL) andalso (DMQL =< FQL).
+
+maybe_notify_mode_change(drop,#{mode:=Mode0}=State)
+ when Mode0=/=drop ->
+ notify({mode_change,Mode0,drop},State);
+maybe_notify_mode_change(Mode1,#{mode:=drop}=State)
+ when Mode1==async; Mode1==sync ->
+ notify({mode_change,drop,Mode1},State);
+maybe_notify_mode_change(_,State) ->
+ State.
+
+notify(Note,#{module:=Module,cb_state:=CBState}=State) ->
+ CBState1 = try_callback_call(Module,notify,[Note,CBState],CBState),
+ State#{cb_state=>CBState1}.
+
+try_callback_call(Module, Function, Args) ->
+ try_callback_call(Module, Function, Args, '$no_default_return').
+
+try_callback_call(Module, Function, Args, DefRet) ->
+ try apply(Module, Function, Args)
+ catch
+ throw:R -> R;
+ error:undef:S when DefRet=/='$no_default_return' ->
+ case S of
+ [{Module,Function,Args,_}|_] ->
+ DefRet;
+ _ ->
+ erlang:raise(error,undef,S)
+ end
+ end.
+
+noreply_return(#{idle:=true}=State) ->
+ {noreply,State};
+noreply_return(#{idle:=false}=State) ->
+ {noreply,State,?IDLE_DETECT_TIME}.
+
+reply_return(Reply,#{idle:=true}=State) ->
+ {reply,Reply,State};
+reply_return(Reply,#{idle:=false}=State) ->
+ {reply,Reply,State,?IDLE_DETECT_TIME}.
diff --git a/lib/kernel/src/logger_olp.hrl b/lib/kernel/src/logger_olp.hrl
new file mode 100644
index 0000000000..d68b5c048d
--- /dev/null
+++ b/lib/kernel/src/logger_olp.hrl
@@ -0,0 +1,185 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-2015. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%%-----------------------------------------------------------------
+%%% Overload protection configuration
+
+%%! *** NOTE ***
+%%! It's important that:
+%%! SYNC_MODE_QLEN =< DROP_MODE_QLEN =< FLUSH_QLEN
+%%! and that DROP_MODE_QLEN >= 2.
+%%! Otherwise the process could end up in drop mode with no new
+%%! log requests to process. This would cause all future requests
+%%! to be dropped (no switch to async mode would ever take place).
+
+%% This specifies the message_queue_len value where the log
+%% requests switch from asynchronous casts to synchronous calls.
+-define(SYNC_MODE_QLEN, 10).
+%% Above this message_queue_len, log requests will be dropped,
+%% i.e. no log requests get sent to the process.
+-define(DROP_MODE_QLEN, 200).
+%% Above this message_queue_len, the process will flush its mailbox
+%% and only leave this number of messages in it.
+-define(FLUSH_QLEN, 1000).
+
+%% Never flush more than this number of messages in one go, or the
+%% process will be unresponsive for seconds (keep this number as large
+%% as possible or the mailbox could grow large).
+-define(FLUSH_MAX_N, 5000).
+
+%% BURST_LIMIT_MAX_COUNT is the max number of log requests allowed
+%% to be written within a BURST_LIMIT_WINDOW_TIME time frame.
+-define(BURST_LIMIT_ENABLE, true).
+-define(BURST_LIMIT_MAX_COUNT, 500).
+-define(BURST_LIMIT_WINDOW_TIME, 1000).
+
+%% This enables/disables the feature to automatically terminate the
+%% process if it gets too loaded (and can't keep up).
+-define(OVERLOAD_KILL_ENABLE, false).
+%% If the message_queue_len goes above this size even after
+%% flushing has been performed, the process is terminated.
+-define(OVERLOAD_KILL_QLEN, 20000).
+%% If the memory usage exceeds this level, the process is terminated.
+-define(OVERLOAD_KILL_MEM_SIZE, 3000000).
+
+%% This is the default time to wait before restarting and accepting
+%% new requests. The value 'infinity' disables restarts.
+-define(OVERLOAD_KILL_RESTART_AFTER, 5000).
+
+%% This is the time in milliseconds after last load message received
+%% that we notify the callback about being idle.
+-define(IDLE_DETECT_TIME, 100).
+
+%%%-----------------------------------------------------------------
+%%% Overload protection macros
+
+-define(timestamp(), erlang:monotonic_time(microsecond)).
+
+-define(get_mode(Tid),
+ case ets:lookup(Tid, mode) of
+ [{mode,M}] -> M;
+ _ -> async
+ end).
+
+-define(set_mode(Tid, M),
+ begin ets:insert(Tid, {mode,M}), M end).
+
+-define(change_mode(Tid, M0, M1),
+ if M0 == M1 ->
+ M0;
+ true ->
+ ets:insert(Tid, {mode,M1}),
+ M1
+ end).
+
+-define(max(X1, X2),
+ if
+ X2 == undefined -> X1;
+ X2 > X1 -> X2;
+ true -> X1
+ end).
+
+-define(diff_time(OS_T1, OS_T0), OS_T1-OS_T0).
+
+%%%-----------------------------------------------------------------
+%%% These macros enable statistics counters in the state of the
+%%% process, which is useful for analysing the overload protection
+%%% behaviour. These counters should not be included in code to be
+%%% officially released (as some counters will grow very large over
+%%% time).
+
+%% -define(SAVE_STATS, true).
+-ifdef(SAVE_STATS).
+ -define(merge_with_stats(STATE),
+ begin
+ TIME = ?timestamp(),
+ STATE#{start => TIME, time => {TIME,0},
+ flushes => 0, flushed => 0, drops => 0,
+ burst_drops => 0, casts => 0, calls => 0,
+ writes => 0, max_qlen => 0, max_time => 0,
+ max_mem => 0, freq => {TIME,0,0}} end).
+
+ -define(update_max_qlen(QLEN, STATE),
+ begin #{max_qlen := QLEN0} = STATE,
+ STATE#{max_qlen => ?max(QLEN0,QLEN)} end).
+
+ -define(update_max_mem(MEM, STATE),
+ begin #{max_mem := MEM0} = STATE,
+ STATE#{max_mem => ?max(MEM0,MEM)} end).
+
+ -define(update_calls_or_casts(CALL_OR_CAST, INC, STATE),
+ case CALL_OR_CAST of
+ cast ->
+ #{casts := CASTS0} = STATE,
+ STATE#{casts => CASTS0+INC};
+ call ->
+ #{calls := CALLS0} = STATE,
+ STATE#{calls => CALLS0+INC}
+ end).
+
+ -define(update_max_time(TIME, STATE),
+ begin #{max_time := TIME0} = STATE,
+ STATE#{max_time => ?max(TIME0,TIME)} end).
+
+ -define(update_other(OTHER, VAR, INCVAL, STATE),
+ begin #{OTHER := VAR} = STATE,
+ STATE#{OTHER => VAR+INCVAL} end).
+
+ -define(update_freq(TIME,STATE),
+ begin
+ case STATE of
+ #{freq := {START, 49, _}} ->
+ STATE#{freq => {TIME, 0, trunc(1000000*50/(?diff_time(TIME,START)))}};
+ #{freq := {START, N, FREQ}} ->
+ STATE#{freq => {START, N+1, FREQ}}
+ end end).
+
+ -define(update_time(TIME,STATE),
+ begin #{start := START} = STATE,
+ STATE#{time => {TIME,trunc((?diff_time(TIME,START))/1000000)}} end).
+
+-else. % DEFAULT!
+ -define(merge_with_stats(STATE), STATE).
+ -define(update_max_qlen(_QLEN, STATE), STATE).
+ -define(update_max_mem(_MEM, STATE), STATE).
+ -define(update_calls_or_casts(_CALL_OR_CAST, _INC, STATE), STATE).
+ -define(update_max_time(_TIME, STATE), STATE).
+ -define(update_other(_OTHER, _VAR, _INCVAL, STATE), STATE).
+ -define(update_freq(_TIME, STATE), STATE).
+ -define(update_time(_TIME, STATE), STATE).
+-endif.
+
+%%%-----------------------------------------------------------------
+%%% These macros enable callbacks that make it possible to analyse the
+%%% overload protection behaviour from outside the process (including
+%%% dropped requests on the client side). An external callback module
+%%% (?OBSERVER_MOD) is required which is not part of the kernel
+%%% application. For this reason, these callbacks should not be
+%%% included in code to be officially released.
+
+%%-define(OBSERVER_MOD, logger_test).
+-ifdef(OBSERVER_MOD).
+ -define(start_observation(NAME), ?OBSERVER:start_observation(NAME)).
+ -define(observe(NAME,EVENT), ?OBSERVER:observe(NAME,EVENT)).
+
+-else. % DEFAULT!
+ -define(start_observation(_NAME), ok).
+ -define(observe(_NAME,_EVENT), ok).
+-endif.
diff --git a/lib/kernel/src/logger_proxy.erl b/lib/kernel/src/logger_proxy.erl
new file mode 100644
index 0000000000..24b293805c
--- /dev/null
+++ b/lib/kernel/src/logger_proxy.erl
@@ -0,0 +1,165 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(logger_proxy).
+
+%% API
+-export([start_link/0, restart/0, log/1, child_spec/0, get_default_config/0]).
+
+%% logger_olp callbacks
+-export([init/1, handle_load/2, handle_info/2, terminate/2,
+ notify/2]).
+
+-include("logger_internal.hrl").
+
+-define(SERVER,?MODULE).
+
+%%%-----------------------------------------------------------------
+%%% API
+-spec log(RemoteLog) -> ok when
+ RemoteLog :: {remote,node(),LogEvent},
+ LogEvent :: {log,Level,Format,Args,Meta} |
+ {log,Level,StringOrReport,Meta},
+ Level :: logger:level(),
+ Format :: io:format(),
+ Args :: list(term()),
+ StringOrReport :: unicode:chardata() | logger:report(),
+ Meta :: logger:metadata().
+log(RemoteLog) ->
+ Olp = persistent_term:get(?MODULE),
+ case logger_olp:get_pid(Olp) =:= self() of
+ true ->
+ %% This happens when the log event comes from the
+ %% emulator, and the group leader is on a remote node.
+ _ = handle_load(RemoteLog, no_state),
+ ok;
+ false ->
+ logger_olp:load(Olp, RemoteLog)
+ end.
+
+%% Called by supervisor
+-spec start_link() -> {ok,pid(),logger_olp:olp_ref()} | {error,term()}.
+start_link() ->
+ %% Notice that sync_mode is only used when logging to remote node,
+ %% i.e. when the log/2 API function is called.
+ %%
+ %% When receiving log events from the emulator or from a remote
+ %% node, the log event is sent as a message to this process, and
+ %% thus received directly in handle_info/2. This means that the
+ %% mode (async/sync/drop) is not read before the message is
+ %% sent. Thus sync mode is never entered, and drop mode is
+ %% implemented by setting the system_logger flag to undefined (see
+ %% notify/2)
+ %%
+ %% Burst limit is disabled, since this is only a proxy and we
+ %% don't want to limit bursts twice (here and in the handler).
+ logger_olp:start_link(?SERVER,?MODULE,[],logger:get_proxy_config()).
+
+%% Fun used for restarting this process after it has been killed due
+%% to overload (must set overload_kill_enable=>true in opts)
+restart() ->
+ case supervisor:start_child(logger_sup, child_spec()) of
+ {ok,_Pid,Olp} ->
+ {ok,Olp};
+ {error,{Reason,Ch}} when is_tuple(Ch), element(1,Ch)==child ->
+ {error,Reason};
+ Error ->
+ Error
+ end.
+
+%% Called internally and by logger_sup
+child_spec() ->
+ Name = ?SERVER,
+ #{id => Name,
+ start => {?MODULE, start_link, []},
+ restart => temporary,
+ shutdown => 2000,
+ type => worker,
+ modules => [?MODULE]}.
+
+get_default_config() ->
+ OlpDefault = logger_olp:get_default_opts(),
+ OlpDefault#{sync_mode_qlen=>500,
+ drop_mode_qlen=>1000,
+ flush_qlen=>5000,
+ burst_limit_enable=>false}.
+
+%%%===================================================================
+%%% gen_server callbacks
+%%%===================================================================
+
+init([]) ->
+ process_flag(trap_exit, true),
+ _ = erlang:system_flag(system_logger,self()),
+ persistent_term:put(?MODULE,logger_olp:get_ref()),
+ {ok,no_state}.
+
+%% Log event to send to the node where the group leader of it's client resides
+handle_load({remote,Node,Log},State) ->
+ %% If the connection is overloaded (send_nosuspend returns false),
+ %% we drop the message.
+ _ = erlang:send_nosuspend({?SERVER,Node},Log),
+ State;
+%% Log event to log on this node
+handle_load({log,Level,Format,Args,Meta},State) ->
+ try_log([Level,Format,Args,Meta]),
+ State;
+handle_load({log,Level,Report,Meta},State) ->
+ try_log([Level,Report,Meta]),
+ State.
+
+%% Log event sent to this process e.g. from the emulator - it is really load
+handle_info(Log,State) when is_tuple(Log), element(1,Log)==log ->
+ {load,State}.
+
+terminate(overloaded, _State) ->
+ _ = erlang:system_flag(system_logger,undefined),
+ {ok,fun ?MODULE:restart/0};
+terminate(_Reason, _State) ->
+ _ = erlang:system_flag(system_logger,whereis(logger)),
+ ok.
+
+notify({mode_change,Mode0,Mode1},State) ->
+ _ = if Mode1=:=drop -> % entering drop mode
+ erlang:system_flag(system_logger,undefined);
+ Mode0=:=drop -> % leaving drop mode
+ erlang:system_flag(system_logger,self());
+ true ->
+ ok
+ end,
+ ?LOG_INTERNAL(notice,"~w switched from ~w to ~w mode",[?MODULE,Mode0,Mode1]),
+ State;
+notify({flushed,Flushed},State) ->
+ ?LOG_INTERNAL(notice, "~w flushed ~w log events",[?MODULE,Flushed]),
+ State;
+notify(restart,State) ->
+ ?LOG_INTERNAL(notice, "~w restarted", [?MODULE]),
+ State;
+notify(_Note,State) ->
+ State.
+
+%%%-----------------------------------------------------------------
+%%% Internal functions
+try_log(Args) ->
+ try apply(logger,log,Args)
+ catch C:R:S ->
+ ?LOG_INTERNAL(debug,[{?MODULE,log_failed},
+ {log,Args},
+ {reason,{C,R,S}}])
+ end.
diff --git a/lib/kernel/src/logger_server.erl b/lib/kernel/src/logger_server.erl
new file mode 100644
index 0000000000..722246e82c
--- /dev/null
+++ b/lib/kernel/src/logger_server.erl
@@ -0,0 +1,617 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(logger_server).
+
+-behaviour(gen_server).
+
+%% API
+-export([start_link/0, add_handler/3, remove_handler/1,
+ add_filter/2, remove_filter/2,
+ set_module_level/2, unset_module_level/0,
+ unset_module_level/1, cache_module_level/1,
+ set_config/2, set_config/3,
+ update_config/2, update_config/3,
+ update_formatter_config/2]).
+
+%% Helper
+-export([diff_maps/2]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2]).
+
+-include("logger_internal.hrl").
+
+-define(SERVER, logger).
+-define(LOGGER_SERVER_TAG, '$logger_cb_process').
+
+-record(state, {tid, async_req, async_req_queue, remote_logger}).
+
+%%%===================================================================
+%%% API
+%%%===================================================================
+
+start_link() ->
+ gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
+
+add_handler(Id,Module,Config0) ->
+ try {check_id(Id),check_mod(Module)} of
+ {ok,ok} ->
+ case sanity_check(Id,Config0) of
+ ok ->
+ Default = default_config(Id,Module),
+ Config = maps:merge(Default,Config0),
+ call({add_handler,Id,Module,Config});
+ Error ->
+ Error
+ end
+ catch throw:Error ->
+ {error,Error}
+ end.
+
+remove_handler(HandlerId) ->
+ call({remove_handler,HandlerId}).
+
+add_filter(Owner,Filter) ->
+ case sanity_check(Owner,filters,[Filter]) of
+ ok -> call({add_filter,Owner,Filter});
+ Error -> Error
+ end.
+
+remove_filter(Owner,FilterId) ->
+ call({remove_filter,Owner,FilterId}).
+
+set_module_level(Modules,Level) when is_list(Modules) ->
+ case lists:all(fun(M) -> is_atom(M) end,Modules) of
+ true ->
+ case sanity_check(primary,level,Level) of
+ ok -> call({set_module_level,Modules,Level});
+ Error -> Error
+ end;
+ false ->
+ {error,{not_a_list_of_modules,Modules}}
+ end;
+set_module_level(Modules,_) ->
+ {error,{not_a_list_of_modules,Modules}}.
+
+unset_module_level() ->
+ call({unset_module_level,all}).
+
+unset_module_level(Modules) when is_list(Modules) ->
+ case lists:all(fun(M) -> is_atom(M) end,Modules) of
+ true ->
+ call({unset_module_level,Modules});
+ false ->
+ {error,{not_a_list_of_modules,Modules}}
+ end;
+unset_module_level(Modules) ->
+ {error,{not_a_list_of_modules,Modules}}.
+
+cache_module_level(Module) ->
+ gen_server:cast(?SERVER,{cache_module_level,Module}).
+
+set_config(Owner,Key,Value) ->
+ case sanity_check(Owner,Key,Value) of
+ ok ->
+ call({change_config,set,Owner,Key,Value});
+ Error ->
+ Error
+ end.
+
+set_config(Owner,Config) ->
+ case sanity_check(Owner,Config) of
+ ok ->
+ call({change_config,set,Owner,Config});
+ Error ->
+ Error
+ end.
+
+update_config(Owner,Key,Value) ->
+ case sanity_check(Owner,Key,Value) of
+ ok ->
+ call({change_config,update,Owner,Key,Value});
+ Error ->
+ Error
+ end.
+
+update_config(Owner, Config) ->
+ case sanity_check(Owner,Config) of
+ ok ->
+ call({change_config,update,Owner,Config});
+ Error ->
+ Error
+ end.
+
+update_formatter_config(HandlerId, FormatterConfig)
+ when is_map(FormatterConfig) ->
+ call({update_formatter_config,HandlerId,FormatterConfig});
+update_formatter_config(_HandlerId, FormatterConfig) ->
+ {error,{invalid_formatter_config,FormatterConfig}}.
+
+
+%%%===================================================================
+%%% gen_server callbacks
+%%%===================================================================
+
+init([]) ->
+ process_flag(trap_exit, true),
+ put(?LOGGER_SERVER_TAG,true),
+ Tid = logger_config:new(?LOGGER_TABLE),
+ %% Store initial proxy config. logger_proxy reads config from here at startup.
+ logger_config:create(Tid,proxy,logger_proxy:get_default_config()),
+ PrimaryConfig = maps:merge(default_config(primary),
+ #{handlers=>[simple]}),
+ logger_config:create(Tid,primary,PrimaryConfig),
+ SimpleConfig0 = maps:merge(default_config(simple,logger_simple_h),
+ #{filter_default=>stop,
+ filters=>?DEFAULT_HANDLER_FILTERS}),
+ %% If this fails, then the node should crash
+ {ok,SimpleConfig} = logger_simple_h:adding_handler(SimpleConfig0),
+ logger_config:create(Tid,simple,SimpleConfig),
+ {ok, #state{tid=Tid, async_req_queue = queue:new()}}.
+
+handle_call({add_handler,Id,Module,HConfig}, From, #state{tid=Tid}=State) ->
+ case logger_config:exist(Tid,Id) of
+ true ->
+ {reply,{error,{already_exist,Id}},State};
+ false ->
+ call_h_async(
+ fun() ->
+ %% inform the handler
+ call_h(Module,adding_handler,[HConfig],{ok,HConfig})
+ end,
+ fun({ok,HConfig1}) ->
+ %% We know that the call_h would have loaded the module
+ %% if it existed, so it is safe here to call function_exported
+ %% to find out if this is a valid handler
+ case erlang:function_exported(Module, log, 2) of
+ true ->
+ logger_config:create(Tid,Id,HConfig1),
+ {ok,Config} = logger_config:get(Tid,primary),
+ Handlers = maps:get(handlers,Config,[]),
+ logger_config:set(Tid,primary,
+ Config#{handlers=>[Id|Handlers]});
+ false ->
+ {error,{invalid_handler,
+ {function_not_exported,
+ {Module,log,2}}}}
+ end;
+ ({error,HReason}) ->
+ {error,{handler_not_added,HReason}}
+ end,From,State)
+ end;
+handle_call({remove_handler,HandlerId}, From, #state{tid=Tid}=State) ->
+ case logger_config:get(Tid,HandlerId) of
+ {ok,#{module:=Module}=HConfig} ->
+ {ok,Config} = logger_config:get(Tid,primary),
+ Handlers0 = maps:get(handlers,Config,[]),
+ Handlers = lists:delete(HandlerId,Handlers0),
+ call_h_async(
+ fun() ->
+ %% inform the handler
+ call_h(Module,removing_handler,[HConfig],ok)
+ end,
+ fun(_Res) ->
+ logger_config:set(Tid,primary,Config#{handlers=>Handlers}),
+ logger_config:delete(Tid,HandlerId),
+ ok
+ end,From,State);
+ _ ->
+ {reply,{error,{not_found,HandlerId}},State}
+ end;
+handle_call({add_filter,Id,Filter}, _From,#state{tid=Tid}=State) ->
+ Reply = do_add_filter(Tid,Id,Filter),
+ {reply,Reply,State};
+handle_call({remove_filter,Id,FilterId}, _From, #state{tid=Tid}=State) ->
+ Reply = do_remove_filter(Tid,Id,FilterId),
+ {reply,Reply,State};
+handle_call({change_config,SetOrUpd,proxy,Config0},_From,#state{tid=Tid}=State) ->
+ Default =
+ case SetOrUpd of
+ set ->
+ logger_proxy:get_default_config();
+ update ->
+ {ok,OldConfig} = logger_config:get(Tid,proxy),
+ OldConfig
+ end,
+ Config = maps:merge(Default,Config0),
+ Reply =
+ case logger_olp:set_opts(logger_proxy,Config) of
+ ok ->
+ logger_config:set(Tid,proxy,Config);
+ Error ->
+ Error
+ end,
+ {reply,Reply,State};
+handle_call({change_config,SetOrUpd,primary,Config0}, _From,
+ #state{tid=Tid}=State) ->
+ {ok,#{handlers:=Handlers}=OldConfig} = logger_config:get(Tid,primary),
+ Default =
+ case SetOrUpd of
+ set -> default_config(primary);
+ update -> OldConfig
+ end,
+ Config = maps:merge(Default,Config0),
+ Reply = logger_config:set(Tid,primary,Config#{handlers=>Handlers}),
+ {reply,Reply,State};
+handle_call({change_config,_SetOrUpd,primary,Key,Value}, _From,
+ #state{tid=Tid}=State) ->
+ {ok,OldConfig} = logger_config:get(Tid,primary),
+ Reply = logger_config:set(Tid,primary,OldConfig#{Key=>Value}),
+ {reply,Reply,State};
+handle_call({change_config,SetOrUpd,HandlerId,Config0}, From,
+ #state{tid=Tid}=State) ->
+ case logger_config:get(Tid,HandlerId) of
+ {ok,#{module:=Module}=OldConfig} ->
+ Default =
+ case SetOrUpd of
+ set -> default_config(HandlerId,Module);
+ update -> OldConfig
+ end,
+ Config = maps:merge(Default,Config0),
+ case check_config_change(OldConfig,Config) of
+ ok ->
+ call_h_async(
+ fun() ->
+ call_h(Module,changing_config,
+ [SetOrUpd,OldConfig,Config],
+ {ok,Config})
+ end,
+ fun({ok,Config1}) ->
+ logger_config:set(Tid,HandlerId,Config1);
+ (Error) ->
+ Error
+ end,From,State);
+ Error ->
+ {reply,Error,State}
+ end;
+ _ ->
+ {reply,{error,{not_found,HandlerId}},State}
+ end;
+handle_call({change_config,SetOrUpd,HandlerId,Key,Value}, From,
+ #state{tid=Tid}=State) ->
+ case logger_config:get(Tid,HandlerId) of
+ {ok,#{module:=Module}=OldConfig} ->
+ Config = OldConfig#{Key=>Value},
+ case check_config_change(OldConfig,Config) of
+ ok ->
+ call_h_async(
+ fun() ->
+ call_h(Module,changing_config,
+ [SetOrUpd,OldConfig,Config],
+ {ok,Config})
+ end,
+ fun({ok,Config1}) ->
+ logger_config:set(Tid,HandlerId,Config1);
+ (Error) ->
+ Error
+ end,From,State);
+ Error ->
+ {reply,Error,State}
+ end;
+ _ ->
+ {reply,{error,{not_found,HandlerId}},State}
+ end;
+handle_call({update_formatter_config,HandlerId,NewFConfig},_From,
+ #state{tid=Tid}=State) ->
+ Reply =
+ case logger_config:get(Tid,HandlerId) of
+ {ok,#{formatter:={FMod,OldFConfig}}=Config} ->
+ try
+ FConfig = maps:merge(OldFConfig,NewFConfig),
+ check_formatter({FMod,FConfig}),
+ logger_config:set(Tid,HandlerId,
+ Config#{formatter=>{FMod,FConfig}})
+ catch throw:Reason -> {error,Reason}
+ end;
+ _ ->
+ {error,{not_found,HandlerId}}
+ end,
+ {reply,Reply,State};
+handle_call({set_module_level,Modules,Level}, _From, #state{tid=Tid}=State) ->
+ Reply = logger_config:set_module_level(Tid,Modules,Level),
+ {reply,Reply,State};
+handle_call({unset_module_level,Modules}, _From, #state{tid=Tid}=State) ->
+ Reply = logger_config:unset_module_level(Tid,Modules),
+ {reply,Reply,State}.
+
+handle_cast({async_req_reply,_Ref,_Reply} = Reply,State) ->
+ call_h_reply(Reply,State);
+handle_cast({cache_module_level,Module}, #state{tid=Tid}=State) ->
+ logger_config:cache_module_level(Tid,Module),
+ {noreply, State}.
+
+%% Interface for those who can't call the API - e.g. the emulator, or
+%% places related to code loading.
+%%
+%% This can also be log events from remote nodes which are sent from
+%% logger.erl when the group leader of the client process is on a
+%% same node as the client process itself.
+handle_info({log,Level,Format,Args,Meta}, State) ->
+ logger:log(Level,Format,Args,Meta),
+ {noreply, State};
+handle_info({log,Level,Report,Meta}, State) ->
+ logger:log(Level,Report,Meta),
+ {noreply, State};
+handle_info({Ref,_Reply},State) when is_reference(Ref) ->
+ %% Assuming this is a timed-out gen_server reply - ignoring
+ {noreply, State};
+handle_info({'DOWN',_Ref,_Proc,_Pid,_Reason} = Down,State) ->
+ call_h_reply(Down,State);
+handle_info(Unexpected,State) when element(1,Unexpected) == 'EXIT' ->
+ %% The simple handler will send an 'EXIT' message when it is replaced
+ %% We may as well ignore all 'EXIT' messages that we get
+ ?LOG_INTERNAL(debug,
+ [{logger,got_unexpected_message},
+ {process,?SERVER},
+ {message,Unexpected}]),
+ {noreply,State};
+handle_info(Unexpected,State) ->
+ ?LOG_INTERNAL(info,
+ [{logger,got_unexpected_message},
+ {process,?SERVER},
+ {message,Unexpected}]),
+ {noreply,State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+%%%===================================================================
+%%% Internal functions
+%%%===================================================================
+call(Request) when is_tuple(Request) ->
+ Action = element(1,Request),
+ case get(?LOGGER_SERVER_TAG) of
+ true when
+ Action == add_handler; Action == remove_handler;
+ Action == add_filter; Action == remove_filter;
+ Action == change_config ->
+ {error,{attempting_syncronous_call_to_self,Request}};
+ _ ->
+ gen_server:call(?SERVER,Request,?DEFAULT_LOGGER_CALL_TIMEOUT)
+ end.
+
+
+do_add_filter(Tid,Id,{FId,_} = Filter) ->
+ case logger_config:get(Tid,Id) of
+ {ok,Config} ->
+ Filters = maps:get(filters,Config,[]),
+ case lists:keymember(FId,1,Filters) of
+ true ->
+ {error,{already_exist,FId}};
+ false ->
+ logger_config:set(Tid,Id,Config#{filters=>[Filter|Filters]})
+ end;
+ Error ->
+ Error
+ end.
+
+do_remove_filter(Tid,Id,FilterId) ->
+ case logger_config:get(Tid,Id) of
+ {ok,Config} ->
+ Filters0 = maps:get(filters,Config,[]),
+ case lists:keytake(FilterId,1,Filters0) of
+ {value,_,Filters} ->
+ logger_config:set(Tid,Id,Config#{filters=>Filters});
+ false ->
+ {error,{not_found,FilterId}}
+ end;
+ Error ->
+ Error
+ end.
+
+default_config(primary) ->
+ #{level=>notice,
+ filters=>[],
+ filter_default=>log};
+default_config(Id) ->
+ #{id=>Id,
+ level=>all,
+ filters=>[],
+ filter_default=>log,
+ formatter=>{?DEFAULT_FORMATTER,#{}}}.
+default_config(Id,Module) ->
+ (default_config(Id))#{module=>Module}.
+
+sanity_check(Owner,Key,Value) ->
+ sanity_check_1(Owner,[{Key,Value}]).
+
+sanity_check(Owner,Config) when is_map(Config) ->
+ sanity_check_1(Owner,maps:to_list(Config));
+sanity_check(_,Config) ->
+ {error,{invalid_config,Config}}.
+
+sanity_check_1(proxy,_Config) ->
+ ok; % Details are checked by logger_olp:set_opts/2
+sanity_check_1(Owner,Config) when is_list(Config) ->
+ try
+ Type = get_type(Owner),
+ check_config(Type,Config)
+ catch throw:Error -> {error,Error}
+ end.
+
+get_type(primary) ->
+ primary;
+get_type(Id) ->
+ check_id(Id),
+ handler.
+
+check_config(Owner,[{level,Level}|Config]) ->
+ check_level(Level),
+ check_config(Owner,Config);
+check_config(Owner,[{filters,Filters}|Config]) ->
+ check_filters(Filters),
+ check_config(Owner,Config);
+check_config(Owner,[{filter_default,FD}|Config]) ->
+ check_filter_default(FD),
+ check_config(Owner,Config);
+check_config(handler,[{formatter,Formatter}|Config]) ->
+ check_formatter(Formatter),
+ check_config(handler,Config);
+check_config(primary,[C|_]) ->
+ throw({invalid_primary_config,C});
+check_config(handler,[{_,_}|Config]) ->
+ %% Arbitrary config elements are allowed for handlers
+ check_config(handler,Config);
+check_config(_,[]) ->
+ ok.
+
+check_id(Id) when is_atom(Id) ->
+ ok;
+check_id(Id) ->
+ throw({invalid_id,Id}).
+
+check_mod(Mod) when is_atom(Mod) ->
+ ok;
+check_mod(Mod) ->
+ throw({invalid_module,Mod}).
+
+check_level(Level) ->
+ case lists:member(Level,?LEVELS) of
+ true ->
+ ok;
+ false ->
+ throw({invalid_level,Level})
+ end.
+
+check_filters([{Id,{Fun,_Args}}|Filters]) when is_atom(Id), is_function(Fun,2) ->
+ check_filters(Filters);
+check_filters([Filter|_]) ->
+ throw({invalid_filter,Filter});
+check_filters([]) ->
+ ok;
+check_filters(Filters) ->
+ throw({invalid_filters,Filters}).
+
+check_filter_default(FD) when FD==stop; FD==log ->
+ ok;
+check_filter_default(FD) ->
+ throw({invalid_filter_default,FD}).
+
+check_formatter({Mod,Config}) ->
+ check_mod(Mod),
+ try Mod:check_config(Config) of
+ ok -> ok;
+ {error,Error} -> throw(Error)
+ catch
+ C:R:S ->
+ case {C,R,S} of
+ {error,undef,[{Mod,check_config,[Config],_}|_]} ->
+ ok;
+ _ ->
+ throw({callback_crashed,
+ {C,R,logger:filter_stacktrace(?MODULE,S)}})
+ end
+ end;
+check_formatter(Formatter) ->
+ throw({invalid_formatter,Formatter}).
+
+%% When changing configuration for a handler, the id and module fields
+%% can not be changed.
+check_config_change(#{id:=Id,module:=Module},#{id:=Id,module:=Module}) ->
+ ok;
+check_config_change(OldConfig,NewConfig) ->
+ {Old,New} = logger_server:diff_maps(maps:with([id,module],OldConfig),
+ maps:with([id,module],NewConfig)),
+ {error,{illegal_config_change,Old,New}}.
+
+call_h(Module, Function, Args, DefRet) ->
+ %% Not calling code:ensure_loaded + erlang:function_exported here,
+ %% since in some rare terminal cases, the code_server might not
+ %% exist and we'll get a deadlock in removing the handler.
+ try apply(Module, Function, Args)
+ catch
+ C:R:S ->
+ case {C,R,S} of
+ {error,undef,[{Module,Function=changing_config,Args,_}|_]}
+ when length(Args)=:=3 ->
+ %% Backwards compatible call, if changing_config/3
+ %% did not exist.
+ call_h(Module, Function, tl(Args), DefRet);
+ {error,undef,[{Module,Function,Args,_}|_]} ->
+ DefRet;
+ _ ->
+ ST = logger:filter_stacktrace(?MODULE,S),
+ ?LOG_INTERNAL(error,
+ [{logger,callback_crashed},
+ {process,?SERVER},
+ {reason,{C,R,ST}}]),
+ {error,{callback_crashed,{C,R,ST}}}
+ end
+ end.
+
+%% There are all sort of API functions that can cause deadlocks if called
+%% from the handler callbacks. So we spawn a process that does the request
+%% for the logger_server. There are still APIs that will cause problems,
+%% namely logger:add_handler
+call_h_async(AsyncFun,PostFun,From,#state{ async_req = undefined } = State) ->
+ Parent = self(),
+ {Pid, Ref} = spawn_monitor(
+ fun() ->
+ put(?LOGGER_SERVER_TAG,true),
+ receive Ref -> Ref end,
+ gen_server:cast(Parent, {async_req_reply, Ref, AsyncFun()})
+ end),
+ Pid ! Ref,
+ {noreply,State#state{ async_req = {Ref,PostFun,From} }};
+call_h_async(AsyncFun,PostFun,From,#state{ async_req_queue = Q } = State) ->
+ {noreply,State#state{ async_req_queue = queue:in({AsyncFun,PostFun,From},Q) }}.
+
+call_h_reply({async_req_reply,Ref,Reply},
+ #state{ async_req = {Ref,PostFun,From}, async_req_queue = Q} = State) ->
+ erlang:demonitor(Ref,[flush]),
+ _ = gen_server:reply(From, PostFun(Reply)),
+ {Value,NewQ} = queue:out(Q),
+ NewState = State#state{ async_req = undefined,
+ async_req_queue = NewQ },
+ case Value of
+ {value,{AsyncFun,NPostFun,NFrom}} ->
+ call_h_async(AsyncFun,NPostFun,NFrom,NewState);
+ empty ->
+ {noreply,NewState}
+ end;
+call_h_reply({'DOWN',Ref,_Proc,Pid,Reason}, #state{ async_req = {Ref,_PostFun,_From}} = State) ->
+ %% This clause should only be triggered if someone explicitly sends an exit signal
+ %% to the spawned process. It is only here to make sure that the logger_server does
+ %% not deadlock if that happens.
+ ?LOG_INTERNAL(error,
+ [{logger,process_exited},
+ {process,Pid},
+ {reason,Reason}]),
+ call_h_reply(
+ {async_req_reply,Ref,{error,{logger_process_exited,Pid,Reason}}},
+ State);
+call_h_reply(Unexpected,State) ->
+ ?LOG_INTERNAL(info,
+ [{logger,got_unexpected_message},
+ {process,?SERVER},
+ {message,Unexpected}]),
+ {noreply,State}.
+
+%% Return two maps containing only the fields that differ.
+diff_maps(M1,M2) ->
+ diffs(lists:sort(maps:to_list(M1)),lists:sort(maps:to_list(M2)),#{},#{}).
+
+diffs([H|T1],[H|T2],D1,D2) ->
+ diffs(T1,T2,D1,D2);
+diffs([{K,V1}|T1],[{K,V2}|T2],D1,D2) ->
+ diffs(T1,T2,D1#{K=>V1},D2#{K=>V2});
+diffs([],[],D1,D2) ->
+ {D1,D2}.
diff --git a/lib/kernel/src/logger_simple_h.erl b/lib/kernel/src/logger_simple_h.erl
new file mode 100644
index 0000000000..a0d51dba25
--- /dev/null
+++ b/lib/kernel/src/logger_simple_h.erl
@@ -0,0 +1,215 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(logger_simple_h).
+
+-export([adding_handler/1, removing_handler/1, log/2]).
+
+%% This module implements a simple handler for logger. It is the
+%% default used during system start.
+
+%%%-----------------------------------------------------------------
+%%% Logger callback
+
+adding_handler(#{id:=simple}=Config) ->
+ Me = self(),
+ case whereis(?MODULE) of
+ undefined ->
+ {Pid,Ref} = spawn_opt(fun() -> init(Me) end,
+ [link,monitor,{message_queue_data,off_heap}]),
+ receive
+ {'DOWN',Ref,process,Pid,Reason} ->
+ {error,Reason};
+ {Pid,started} ->
+ erlang:demonitor(Ref),
+ {ok,Config}
+ end;
+ _ ->
+ {error,{handler_process_name_already_exists,?MODULE}}
+ end.
+
+removing_handler(#{id:=simple}) ->
+ case whereis(?MODULE) of
+ undefined ->
+ ok;
+ Pid ->
+ Ref = erlang:monitor(process,Pid),
+ Pid ! stop,
+ receive {'DOWN',Ref,process,Pid,_} ->
+ ok
+ end
+ end.
+
+log(#{meta:=#{error_logger:=#{tag:=info_report,type:=Type}}},_Config)
+ when Type=/=std_info ->
+ %% Skip info reports that are not 'std_info' (ref simple logger in
+ %% error_logger)
+ ok;
+log(#{msg:=_,meta:=#{time:=_}}=Log,_Config) ->
+ _ = case whereis(?MODULE) of
+ undefined ->
+ %% Is the node on the way down? Real emergency?
+ %% Log directly from client just to get it out
+ do_log(
+ #{level=>error,
+ msg=>{report,{error,simple_handler_process_dead}},
+ meta=>#{time=>logger:timestamp()}}),
+ do_log(Log);
+ _ ->
+ ?MODULE ! {log,Log}
+ end,
+ ok;
+log(_,_) ->
+ %% Unexpected log.
+ %% We don't want to crash the simple logger, so ignore this.
+ ok.
+
+%%%-----------------------------------------------------------------
+%%% Process
+init(Starter) ->
+ register(?MODULE,self()),
+ Starter ! {self(),started},
+ loop(#{buffer_size=>10,dropped=>0,buffer=>[]}).
+
+loop(Buffer) ->
+ receive
+ stop ->
+ %% We replay the logger messages of there is
+ %% a default handler when the simple handler
+ %% is removed.
+ case logger:get_handler_config(default) of
+ {ok, _} ->
+ replay_buffer(Buffer);
+ _ ->
+ ok
+ end,
+ %% Before stopping, we unlink the logger process to avoid
+ %% an unexpected EXIT message
+ unlink(whereis(logger)),
+ ok;
+ {log,#{msg:=_,meta:=#{time:=_}}=Log} ->
+ do_log(Log),
+ loop(update_buffer(Buffer,Log));
+ _ ->
+ %% Unexpected message - flush it!
+ loop(Buffer)
+ end.
+
+update_buffer(#{buffer_size:=0,dropped:=D}=Buffer,_Log) ->
+ Buffer#{dropped=>D+1};
+update_buffer(#{buffer_size:=S,buffer:=B}=Buffer,Log) ->
+ Buffer#{buffer_size=>S-1,buffer=>[Log|B]}.
+
+replay_buffer(#{ dropped := D, buffer := Buffer }) ->
+ lists:foreach(
+ fun F(#{msg := {Tag, Msg}} = L) when Tag =:= string; Tag =:= report ->
+ F(L#{ msg := Msg });
+ F(#{ level := Level, msg := Msg, meta := MD}) ->
+ logger:log(Level, Msg, MD)
+ end, lists:reverse(Buffer, drop_msg(D))).
+
+drop_msg(0) ->
+ [];
+drop_msg(N) ->
+ [#{level=>info,
+ msg=>{"Simple handler buffer full, dropped ~w messages",[N]},
+ meta=>#{time=>logger:timestamp()}}].
+
+%%%-----------------------------------------------------------------
+%%% Internal
+
+%% Can't do io_lib:format
+
+do_log(#{msg:={report,Report},
+ meta:=#{time:=T,error_logger:=#{type:=Type}}}) ->
+ display_date(T),
+ display_report(Type,Report);
+do_log(#{msg:=Msg,meta:=#{time:=T}}) ->
+ display_date(T),
+ display(Msg).
+
+display_date(Timestamp) when is_integer(Timestamp) ->
+ Micro = Timestamp rem 1000000,
+ Sec = Timestamp div 1000000,
+ {{Y,Mo,D},{H,Mi,S}} = erlang:universaltime_to_localtime(
+ erlang:posixtime_to_universaltime(Sec)),
+ erlang:display_string(
+ integer_to_list(Y) ++ "-" ++
+ pad(Mo,2) ++ "-" ++
+ pad(D,2) ++ " " ++
+ pad(H,2) ++ ":" ++
+ pad(Mi,2) ++ ":" ++
+ pad(S,2) ++ "." ++
+ pad(Micro,6) ++ " ").
+
+pad(Int,Size) when is_integer(Int) ->
+ pad(integer_to_list(Int),Size);
+pad(Str,Size) when length(Str)==Size ->
+ Str;
+pad(Str,Size) ->
+ pad([$0|Str],Size).
+
+display({string,Chardata}) ->
+ try unicode:characters_to_list(Chardata) of
+ String -> erlang:display_string(String), erlang:display_string("\n")
+ catch _:_ -> erlang:display(Chardata)
+ end;
+display({report,Report}) when is_map(Report) ->
+ display_report(maps:to_list(Report));
+display({report,Report}) ->
+ display_report(Report);
+display({F, A}) when is_list(F), is_list(A) ->
+ erlang:display_string(F ++ "\n"),
+ [begin
+ erlang:display_string("\t"),
+ erlang:display(Arg)
+ end || Arg <- A],
+ ok.
+
+display_report(Atom, A) when is_atom(Atom) ->
+ %% The widest atom seems to be 'supervisor_report' at 17.
+ ColumnWidth = 20,
+ AtomString = atom_to_list(Atom),
+ AtomLength = length(AtomString),
+ Padding = lists:duplicate(ColumnWidth - AtomLength, $\s),
+ erlang:display_string(AtomString ++ Padding),
+ display_report(A);
+display_report(F, A) ->
+ erlang:display({F, A}).
+
+display_report([A, []]) ->
+ %% Special case for crash reports when process has no links
+ display_report(A);
+display_report(A = [_|_]) ->
+ case lists:all(fun({Key,_Value}) -> is_atom(Key); (_) -> false end, A) of
+ true ->
+ erlang:display_string("\n"),
+ lists:foreach(
+ fun({Key, Value}) ->
+ erlang:display_string(
+ " " ++
+ atom_to_list(Key) ++
+ ": "),
+ erlang:display(Value)
+ end, A);
+ false ->
+ erlang:display(A)
+ end;
+display_report(A) ->
+ erlang:display(A).
diff --git a/lib/kernel/src/logger_std_h.erl b/lib/kernel/src/logger_std_h.erl
new file mode 100644
index 0000000000..c8f1acfca4
--- /dev/null
+++ b/lib/kernel/src/logger_std_h.erl
@@ -0,0 +1,643 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(logger_std_h).
+
+-include("logger.hrl").
+-include("logger_internal.hrl").
+-include("logger_h_common.hrl").
+
+-include_lib("kernel/include/file.hrl").
+
+%% API
+-export([filesync/1]).
+
+%% logger_h_common callbacks
+-export([init/2, check_config/4, config_changed/3, reset_state/2,
+ filesync/3, write/4, handle_info/3, terminate/3]).
+
+%% logger callbacks
+-export([log/2, adding_handler/1, removing_handler/1, changing_config/3,
+ filter_config/1]).
+
+-define(DEFAULT_CALL_TIMEOUT, 5000).
+
+%%%===================================================================
+%%% API
+%%%===================================================================
+
+%%%-----------------------------------------------------------------
+%%%
+-spec filesync(Name) -> ok | {error,Reason} when
+ Name :: atom(),
+ Reason :: handler_busy | {badarg,term()}.
+
+filesync(Name) ->
+ logger_h_common:filesync(?MODULE,Name).
+
+%%%===================================================================
+%%% logger callbacks - just forward to logger_h_common
+%%%===================================================================
+
+%%%-----------------------------------------------------------------
+%%% Handler being added
+-spec adding_handler(Config) -> {ok,Config} | {error,Reason} when
+ Config :: logger:handler_config(),
+ Reason :: term().
+
+adding_handler(Config) ->
+ logger_h_common:adding_handler(Config).
+
+%%%-----------------------------------------------------------------
+%%% Updating handler config
+-spec changing_config(SetOrUpdate, OldConfig, NewConfig) ->
+ {ok,Config} | {error,Reason} when
+ SetOrUpdate :: set | update,
+ OldConfig :: logger:handler_config(),
+ NewConfig :: logger:handler_config(),
+ Config :: logger:handler_config(),
+ Reason :: term().
+
+changing_config(SetOrUpdate, OldConfig, NewConfig) ->
+ logger_h_common:changing_config(SetOrUpdate, OldConfig, NewConfig).
+
+%%%-----------------------------------------------------------------
+%%% Handler being removed
+-spec removing_handler(Config) -> ok when
+ Config :: logger:handler_config().
+
+removing_handler(Config) ->
+ logger_h_common:removing_handler(Config).
+
+%%%-----------------------------------------------------------------
+%%% Log a string or report
+-spec log(LogEvent, Config) -> ok when
+ LogEvent :: logger:log_event(),
+ Config :: logger:handler_config().
+
+log(LogEvent, Config) ->
+ logger_h_common:log(LogEvent, Config).
+
+%%%-----------------------------------------------------------------
+%%% Remove internal fields from configuration
+-spec filter_config(Config) -> Config when
+ Config :: logger:handler_config().
+
+filter_config(Config) ->
+ logger_h_common:filter_config(Config).
+
+%%%===================================================================
+%%% logger_h_common callbacks
+%%%===================================================================
+init(Name, Config) ->
+ MyConfig = maps:with([type,file,modes,file_check,max_no_bytes,
+ max_no_files,compress_on_rotate],Config),
+ case file_ctrl_start(Name, MyConfig) of
+ {ok,FileCtrlPid} ->
+ {ok,MyConfig#{file_ctrl_pid=>FileCtrlPid}};
+ Error ->
+ Error
+ end.
+
+check_config(Name,set,undefined,NewHConfig) ->
+ check_h_config(merge_default_config(Name,normalize_config(NewHConfig)));
+check_config(Name,SetOrUpdate,OldHConfig,NewHConfig0) ->
+ WriteOnce = maps:with([type,file,modes],OldHConfig),
+ Default =
+ case SetOrUpdate of
+ set ->
+ %% Do not reset write-once fields to defaults
+ merge_default_config(Name,WriteOnce);
+ update ->
+ OldHConfig
+ end,
+
+ NewHConfig = maps:merge(Default, normalize_config(NewHConfig0)),
+
+ %% Fail if write-once fields are changed
+ case maps:with([type,file,modes],NewHConfig) of
+ WriteOnce ->
+ check_h_config(NewHConfig);
+ Other ->
+ {error,{illegal_config_change,?MODULE,WriteOnce,Other}}
+ end.
+
+check_h_config(HConfig) ->
+ case check_h_config(maps:get(type,HConfig),maps:to_list(HConfig)) of
+ ok ->
+ {ok,fix_file_opts(HConfig)};
+ {error,{Key,Value}} ->
+ {error,{invalid_config,?MODULE,#{Key=>Value}}}
+ end.
+
+check_h_config(Type,[{type,Type} | Config]) when Type =:= standard_io;
+ Type =:= standard_error;
+ Type =:= file ->
+ check_h_config(Type,Config);
+check_h_config(file,[{file,File} | Config]) when is_list(File) ->
+ check_h_config(file,Config);
+check_h_config(file,[{modes,Modes} | Config]) when is_list(Modes) ->
+ check_h_config(file,Config);
+check_h_config(file,[{max_no_bytes,Size} | Config])
+ when (is_integer(Size) andalso Size>0) orelse Size=:=infinity ->
+ check_h_config(file,Config);
+check_h_config(file,[{max_no_files,Num} | Config]) when is_integer(Num), Num>=0 ->
+ check_h_config(file,Config);
+check_h_config(file,[{compress_on_rotate,Bool} | Config]) when is_boolean(Bool) ->
+ check_h_config(file,Config);
+check_h_config(file,[{file_check,FileCheck} | Config])
+ when is_integer(FileCheck), FileCheck>=0 ->
+ check_h_config(file,Config);
+check_h_config(_Type,[Other | _]) ->
+ {error,Other};
+check_h_config(_Type,[]) ->
+ ok.
+
+normalize_config(#{type:={file,File}}=HConfig) ->
+ HConfig#{type=>file,file=>File};
+normalize_config(#{type:={file,File,Modes}}=HConfig) ->
+ HConfig#{type=>file,file=>File,modes=>Modes};
+normalize_config(HConfig) ->
+ HConfig.
+
+merge_default_config(Name,#{type:=Type}=HConfig) ->
+ merge_default_config(Name,Type,HConfig);
+merge_default_config(Name,#{file:=_}=HConfig) ->
+ merge_default_config(Name,file,HConfig);
+merge_default_config(Name,HConfig) ->
+ merge_default_config(Name,standard_io,HConfig).
+
+merge_default_config(Name,Type,HConfig) ->
+ maps:merge(get_default_config(Name,Type),HConfig).
+
+get_default_config(Name,file) ->
+ #{type => file,
+ file => atom_to_list(Name),
+ modes => [raw,append],
+ file_check => 0,
+ max_no_bytes => infinity,
+ max_no_files => 0,
+ compress_on_rotate => false};
+get_default_config(_Name,Type) ->
+ #{type => Type}.
+
+fix_file_opts(#{modes:=Modes}=HConfig) ->
+ HConfig#{modes=>fix_modes(Modes)};
+fix_file_opts(HConfig) ->
+ HConfig#{filesync_repeat_interval=>no_repeat}.
+
+fix_modes(Modes) ->
+ %% Ensure write|append|exclusive
+ Modes1 =
+ case [M || M <- Modes,
+ lists:member(M,[write,append,exclusive])] of
+ [] -> [append|Modes];
+ _ -> Modes
+ end,
+ %% Ensure raw
+ Modes2 =
+ case lists:member(raw,Modes) of
+ false -> [raw|Modes1];
+ true -> Modes1
+ end,
+ %% Ensure delayed_write
+ case lists:partition(fun(delayed_write) -> true;
+ ({delayed_write,_,_}) -> true;
+ (_) -> false
+ end, Modes2) of
+ {[],_} ->
+ [delayed_write|Modes2];
+ _ ->
+ Modes2
+ end.
+
+config_changed(_Name,
+ #{file_check:=FileCheck,
+ max_no_bytes:=Size,
+ max_no_files:=Count,
+ compress_on_rotate:=Compress},
+ #{file_check:=FileCheck,
+ max_no_bytes:=Size,
+ max_no_files:=Count,
+ compress_on_rotate:=Compress}=State) ->
+ State;
+config_changed(_Name,
+ #{file_check:=FileCheck,
+ max_no_bytes:=Size,
+ max_no_files:=Count,
+ compress_on_rotate:=Compress},
+ #{file_ctrl_pid := FileCtrlPid} = State) ->
+ FileCtrlPid ! {update_config,#{file_check=>FileCheck,
+ max_no_bytes=>Size,
+ max_no_files=>Count,
+ compress_on_rotate=>Compress}},
+ State#{file_check:=FileCheck,
+ max_no_bytes:=Size,
+ max_no_files:=Count,
+ compress_on_rotate:=Compress};
+config_changed(_Name,_NewHConfig,State) ->
+ State.
+
+filesync(_Name, SyncAsync, #{file_ctrl_pid := FileCtrlPid} = State) ->
+ Result = file_ctrl_filesync(SyncAsync, FileCtrlPid),
+ {Result,State}.
+
+write(_Name, SyncAsync, Bin, #{file_ctrl_pid:=FileCtrlPid} = State) ->
+ Result = file_write(SyncAsync, FileCtrlPid, Bin),
+ {Result,State}.
+
+reset_state(_Name, State) ->
+ State.
+
+handle_info(_Name, {'EXIT',Pid,Why}, #{file_ctrl_pid := Pid}=State) ->
+ %% file_ctrl_pid died, file error, terminate handler
+ exit({error,{write_failed,maps:with([type,file,modes],State),Why}});
+handle_info(_, _, State) ->
+ State.
+
+terminate(_Name, _Reason, #{file_ctrl_pid:=FWPid}) ->
+ case is_process_alive(FWPid) of
+ true ->
+ unlink(FWPid),
+ _ = file_ctrl_stop(FWPid),
+ MRef = erlang:monitor(process, FWPid),
+ receive
+ {'DOWN',MRef,_,_,_} ->
+ ok
+ after
+ ?DEFAULT_CALL_TIMEOUT ->
+ exit(FWPid, kill),
+ ok
+ end;
+ false ->
+ ok
+ end.
+
+%%%===================================================================
+%%% Internal functions
+%%%===================================================================
+
+%%%-----------------------------------------------------------------
+%%%
+open_log_file(HandlerName,#{type:=file,
+ file:=FileName,
+ modes:=Modes,
+ file_check:=FileCheck,
+ max_no_bytes:=Size,
+ max_no_files:=Count,
+ compress_on_rotate:=Compress}) ->
+ try
+ case filelib:ensure_dir(FileName) of
+ ok ->
+ case file:open(FileName, Modes) of
+ {ok, Fd} ->
+ {ok,#file_info{inode=INode}} =
+ file:read_file_info(FileName,[raw]),
+ UpdateModes = [append | Modes--[write,append,exclusive]],
+ State0 = #{handler_name=>HandlerName,
+ file_name=>FileName,
+ modes=>UpdateModes,
+ file_check=>FileCheck,
+ fd=>Fd,
+ inode=>INode,
+ last_check=>timestamp(),
+ synced=>false,
+ write_res=>ok,
+ sync_res=>ok},
+ State = update_rotation({Size,Count,Compress},State0),
+ {ok,State};
+ Error ->
+ Error
+ end;
+ Error ->
+ Error
+ end
+ catch
+ _:Reason -> {error,Reason}
+ end.
+
+close_log_file(#{fd:=Fd}) ->
+ _ = file:datasync(Fd),
+ _ = file:close(Fd),
+ ok;
+close_log_file(_) ->
+ ok.
+
+
+
+%%%-----------------------------------------------------------------
+%%% File control process
+
+file_ctrl_start(HandlerName, HConfig) ->
+ Starter = self(),
+ FileCtrlPid =
+ spawn_link(fun() ->
+ file_ctrl_init(HandlerName, HConfig, Starter)
+ end),
+ receive
+ {FileCtrlPid,ok} ->
+ {ok,FileCtrlPid};
+ {FileCtrlPid,Error} ->
+ Error
+ after
+ ?DEFAULT_CALL_TIMEOUT ->
+ {error,file_ctrl_process_not_started}
+ end.
+
+file_ctrl_stop(Pid) ->
+ Pid ! stop.
+
+file_write(async, Pid, Bin) ->
+ Pid ! {log,Bin},
+ ok;
+file_write(sync, Pid, Bin) ->
+ file_ctrl_call(Pid, {log,Bin}).
+
+file_ctrl_filesync(async, Pid) ->
+ Pid ! filesync,
+ ok;
+file_ctrl_filesync(sync, Pid) ->
+ file_ctrl_call(Pid, filesync).
+
+file_ctrl_call(Pid, Msg) ->
+ MRef = monitor(process, Pid),
+ Pid ! {Msg,{self(),MRef}},
+ receive
+ {MRef,Result} ->
+ demonitor(MRef, [flush]),
+ Result;
+ {'DOWN',MRef,_Type,_Object,Reason} ->
+ {error,Reason}
+ after
+ ?DEFAULT_CALL_TIMEOUT ->
+ {error,{no_response,Pid}}
+ end.
+
+file_ctrl_init(HandlerName,
+ #{type:=file,
+ file:=FileName} = HConfig,
+ Starter) ->
+ process_flag(message_queue_data, off_heap),
+ case open_log_file(HandlerName,HConfig) of
+ {ok,State} ->
+ Starter ! {self(),ok},
+ file_ctrl_loop(State);
+ {error,Reason} ->
+ Starter ! {self(),{error,{open_failed,FileName,Reason}}}
+ end;
+file_ctrl_init(HandlerName, #{type:=StdDev}, Starter) ->
+ Starter ! {self(),ok},
+ file_ctrl_loop(#{handler_name=>HandlerName,dev=>StdDev}).
+
+file_ctrl_loop(State) ->
+ receive
+ %% asynchronous event
+ {log,Bin} ->
+ State1 = write_to_dev(Bin,State),
+ file_ctrl_loop(State1);
+
+ %% synchronous event
+ {{log,Bin},{From,MRef}} ->
+ State1 = ensure_file(State),
+ State2 = write_to_dev(Bin,State1),
+ From ! {MRef,ok},
+ file_ctrl_loop(State2);
+
+ filesync ->
+ State1 = sync_dev(State),
+ file_ctrl_loop(State1);
+
+ {filesync,{From,MRef}} ->
+ State1 = ensure_file(State),
+ State2 = sync_dev(State1),
+ From ! {MRef,ok},
+ file_ctrl_loop(State2);
+
+ {update_config,#{file_check:=FileCheck,
+ max_no_bytes:=Size,
+ max_no_files:=Count,
+ compress_on_rotate:=Compress}} ->
+ State1 = update_rotation({Size,Count,Compress},State),
+ file_ctrl_loop(State1#{file_check=>FileCheck});
+
+ stop ->
+ close_log_file(State),
+ stopped
+ end.
+
+maybe_ensure_file(#{file_check:=0}=State) ->
+ ensure_file(State);
+maybe_ensure_file(#{last_check:=T0,file_check:=CheckInt}=State)
+ when is_integer(CheckInt) ->
+ T = timestamp(),
+ if T-T0 > CheckInt -> ensure_file(State);
+ true -> State
+ end;
+maybe_ensure_file(State) ->
+ State.
+
+%% In order to play well with tools like logrotate, we need to be able
+%% to re-create the file if it has disappeared (e.g. if rotated by
+%% logrotate)
+ensure_file(#{fd:=Fd0,inode:=INode0,file_name:=FileName,modes:=Modes}=State) ->
+ case file:read_file_info(FileName,[raw]) of
+ {ok,#file_info{inode=INode0}} ->
+ State#{last_check=>timestamp()};
+ _ ->
+ close_log_file(Fd0),
+ case file:open(FileName,Modes) of
+ {ok,Fd} ->
+ {ok,#file_info{inode=INode}} =
+ file:read_file_info(FileName,[raw]),
+ State#{fd=>Fd,inode=>INode,
+ last_check=>timestamp(),
+ synced=>true,sync_res=>ok};
+ Error ->
+ exit({could_not_reopen_file,Error})
+ end
+ end;
+ensure_file(State) ->
+ State.
+
+write_to_dev(Bin,#{dev:=DevName}=State) ->
+ io:put_chars(DevName, Bin),
+ State;
+write_to_dev(Bin, State) ->
+ State1 = #{fd:=Fd} = maybe_ensure_file(State),
+ Result = ?file_write(Fd, Bin),
+ State2 = maybe_rotate_file(Bin,State1),
+ maybe_notify_error(write,Result,State2),
+ State2#{synced=>false,write_res=>Result}.
+
+sync_dev(#{synced:=false}=State) ->
+ State1 = #{fd:=Fd} = maybe_ensure_file(State),
+ Result = ?file_datasync(Fd),
+ maybe_notify_error(filesync,Result,State1),
+ State1#{synced=>true,sync_res=>Result};
+sync_dev(State) ->
+ State.
+
+update_rotation({infinity,_,_},State) ->
+ maybe_remove_archives(0,State),
+ maps:remove(rotation,State);
+update_rotation({Size,Count,Compress},#{file_name:=FileName} = State) ->
+ maybe_remove_archives(Count,State),
+ {ok,#file_info{size=CurrSize}} = file:read_file_info(FileName,[raw]),
+ State1 = State#{rotation=>#{size=>Size,
+ count=>Count,
+ compress=>Compress,
+ curr_size=>CurrSize}},
+ maybe_update_compress(0,State1),
+ maybe_rotate_file(0,State1).
+
+maybe_remove_archives(Count,#{file_name:=FileName}=State) ->
+ Archive = rot_file_name(FileName,Count,false),
+ CompressedArchive = rot_file_name(FileName,Count,true),
+ case {file:read_file_info(Archive,[raw]),
+ file:read_file_info(CompressedArchive,[raw])} of
+ {{error,enoent},{error,enoent}} ->
+ ok;
+ _ ->
+ _ = file:delete(Archive),
+ _ = file:delete(CompressedArchive),
+ maybe_remove_archives(Count+1,State)
+ end.
+
+maybe_update_compress(Count,#{rotation:=#{count:=Count}}) ->
+ ok;
+maybe_update_compress(N,#{file_name:=FileName,
+ rotation:=#{compress:=Compress}}=State) ->
+ Archive = rot_file_name(FileName,N,not Compress),
+ case file:read_file_info(Archive,[raw]) of
+ {ok,_} when Compress ->
+ compress_file(Archive);
+ {ok,_} ->
+ decompress_file(Archive);
+ _ ->
+ ok
+ end,
+ maybe_update_compress(N+1,State).
+
+maybe_rotate_file(Bin,#{rotation:=_}=State) when is_binary(Bin) ->
+ maybe_rotate_file(byte_size(Bin),State);
+maybe_rotate_file(AddSize,#{rotation:=#{size:=RotSize,
+ curr_size:=CurrSize}=Rotation}=State) ->
+ NewSize = CurrSize + AddSize,
+ if NewSize>RotSize ->
+ rotate_file(State#{rotation=>Rotation#{curr_size=>NewSize}});
+ true ->
+ State#{rotation=>Rotation#{curr_size=>NewSize}}
+ end;
+maybe_rotate_file(_Bin,State) ->
+ State.
+
+rotate_file(#{fd:=Fd0,file_name:=FileName,modes:=Modes,rotation:=Rotation}=State) ->
+ State1 = sync_dev(State),
+ _ = file:close(Fd0),
+ _ = file:close(Fd0),
+ rotate_files(FileName,maps:get(count,Rotation),maps:get(compress,Rotation)),
+ case file:open(FileName,Modes) of
+ {ok,Fd} ->
+ {ok,#file_info{inode=INode}} = file:read_file_info(FileName,[raw]),
+ State1#{fd=>Fd,inode=>INode,rotation=>Rotation#{curr_size=>0}};
+ Error ->
+ exit({could_not_reopen_file,Error})
+ end.
+
+rotate_files(FileName,0,_Compress) ->
+ _ = file:delete(FileName),
+ ok;
+rotate_files(FileName,1,Compress) ->
+ FileName0 = FileName++".0",
+ _ = file:rename(FileName,FileName0),
+ if Compress -> compress_file(FileName0);
+ true -> ok
+ end,
+ ok;
+rotate_files(FileName,Count,Compress) ->
+ _ = file:rename(rot_file_name(FileName,Count-2,Compress),
+ rot_file_name(FileName,Count-1,Compress)),
+ rotate_files(FileName,Count-1,Compress).
+
+rot_file_name(FileName,Count,false) ->
+ FileName ++ "." ++ integer_to_list(Count);
+rot_file_name(FileName,Count,true) ->
+ rot_file_name(FileName,Count,false) ++ ".gz".
+
+compress_file(FileName) ->
+ {ok,In} = file:open(FileName,[read,binary]),
+ {ok,Out} = file:open(FileName++".gz",[write]),
+ Z = zlib:open(),
+ zlib:deflateInit(Z, default, deflated, 31, 8, default),
+ compress_data(Z,In,Out),
+ zlib:deflateEnd(Z),
+ zlib:close(Z),
+ _ = file:close(In),
+ _ = file:close(Out),
+ _ = file:delete(FileName),
+ ok.
+
+compress_data(Z,In,Out) ->
+ case file:read(In,100000) of
+ {ok,Data} ->
+ Compressed = zlib:deflate(Z, Data),
+ _ = file:write(Out,Compressed),
+ compress_data(Z,In,Out);
+ eof ->
+ Compressed = zlib:deflate(Z, <<>>, finish),
+ _ = file:write(Out,Compressed),
+ ok
+ end.
+
+decompress_file(FileName) ->
+ {ok,In} = file:open(FileName,[read,binary]),
+ {ok,Out} = file:open(filename:rootname(FileName,".gz"),[write]),
+ Z = zlib:open(),
+ zlib:inflateInit(Z, 31),
+ decompress_data(Z,In,Out),
+ zlib:inflateEnd(Z),
+ zlib:close(Z),
+ _ = file:close(In),
+ _ = file:close(Out),
+ _ = file:delete(FileName),
+ ok.
+
+decompress_data(Z,In,Out) ->
+ case file:read(In,1000) of
+ {ok,Data} ->
+ Decompressed = zlib:inflate(Z, Data),
+ _ = file:write(Out,Decompressed),
+ decompress_data(Z,In,Out);
+ eof ->
+ ok
+ end.
+
+maybe_notify_error(_Op, ok, _State) ->
+ ok;
+maybe_notify_error(Op, Result, #{write_res:=WR,sync_res:=SR})
+ when (Op==write andalso Result==WR) orelse
+ (Op==filesync andalso Result==SR) ->
+ %% don't report same error twice
+ ok;
+maybe_notify_error(Op, Error, #{handler_name:=HandlerName,file_name:=FileName}) ->
+ logger_h_common:error_notify({HandlerName,Op,FileName,Error}),
+ ok.
+
+timestamp() ->
+ erlang:monotonic_time(millisecond).
diff --git a/lib/kernel/src/logger_sup.erl b/lib/kernel/src/logger_sup.erl
new file mode 100644
index 0000000000..9ea8558a16
--- /dev/null
+++ b/lib/kernel/src/logger_sup.erl
@@ -0,0 +1,59 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(logger_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/0]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+-define(SERVER, ?MODULE).
+
+%%%===================================================================
+%%% API functions
+%%%===================================================================
+
+start_link() ->
+ supervisor:start_link({local, ?SERVER}, ?MODULE, []).
+
+%%%===================================================================
+%%% Supervisor callbacks
+%%%===================================================================
+
+init([]) ->
+
+ SupFlags = #{strategy => one_for_one,
+ intensity => 1,
+ period => 5},
+
+ Watcher = #{id => logger_handler_watcher,
+ start => {logger_handler_watcher, start_link, []},
+ shutdown => brutal_kill},
+
+ Proxy = logger_proxy:child_spec(),
+
+ {ok, {SupFlags, [Watcher,Proxy]}}.
+
+%%%===================================================================
+%%% Internal functions
+%%%===================================================================
diff --git a/lib/kernel/src/net.erl b/lib/kernel/src/net.erl
deleted file mode 100644
index 2d0ae2ed0c..0000000000
--- a/lib/kernel/src/net.erl
+++ /dev/null
@@ -1,40 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
--module(net).
-
-%% Various network functions, kept here for compatibility
-
--export([call/4,
- cast/4,
- broadcast/3,
- ping/1,
- relay/1,
- sleep/1]).
-
--deprecated(module).
-
-call(N,M,F,A) -> rpc:call(N,M,F,A).
-cast(N,M,F,A) -> rpc:cast(N,M,F,A).
-broadcast(M,F,A) -> rpc:eval_everywhere(M,F,A).
-ping(Node) -> net_adm:ping(Node).
-sleep(T) -> receive after T -> ok end.
-relay(X) -> slave:relay(X).
-
-
diff --git a/lib/kernel/src/net_kernel.erl b/lib/kernel/src/net_kernel.erl
index 7da89dd7cb..83d3b4b5e1 100644
--- a/lib/kernel/src/net_kernel.erl
+++ b/lib/kernel/src/net_kernel.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -53,7 +53,7 @@
%% Documented API functions.
--export([allow/1,
+-export([allow/1, allowed/0,
connect_node/1,
monitor_nodes/1,
monitor_nodes/2,
@@ -70,8 +70,8 @@
protocol_childspecs/0,
epmd_module/0]).
--export([connect/1, disconnect/1, hidden_connect/1, passive_cnct/1]).
--export([hidden_connect_node/1]). %% explicit connect
+-export([disconnect/1, passive_cnct/1]).
+-export([hidden_connect_node/1]).
-export([set_net_ticktime/1, set_net_ticktime/2, get_net_ticktime/0]).
-export([node_info/1, node_info/2, nodes_info/0,
@@ -122,6 +122,7 @@
-record(connection, {
node, %% remote node name
+ conn_id, %% Connection identity
state, %% pending | up | up_pending
owner, %% owner pid
pending_owner, %% possible new owner
@@ -170,6 +171,8 @@ kernel_apply(M,F,A) -> request({apply,M,F,A}).
Nodes :: [node()].
allow(Nodes) -> request({allow, Nodes}).
+allowed() -> request(allowed).
+
longnames() -> request(longnames).
-spec stop() -> ok | {error, Reason} when
@@ -221,8 +224,7 @@ get_net_ticktime() ->
Error :: error | {error, term()}.
monitor_nodes(Flag) ->
case catch process_flag(monitor_nodes, Flag) of
- true -> ok;
- false -> ok;
+ N when is_integer(N) -> ok;
_ -> mk_monitor_nodes_error(Flag, [])
end.
@@ -235,8 +237,7 @@ monitor_nodes(Flag) ->
Error :: error | {error, term()}.
monitor_nodes(Flag, Opts) ->
case catch process_flag({monitor_nodes, Opts}, Flag) of
- true -> ok;
- false -> ok;
+ N when is_integer(N) -> ok;
_ -> mk_monitor_nodes_error(Flag, Opts)
end.
@@ -247,14 +248,15 @@ ticktime_res(A) when is_atom(A) -> A.
%% Called though BIF's
-connect(Node) -> do_connect(Node, normal, false).
%%% Long timeout if blocked (== barred), only affects nodes with
%%% {dist_auto_connect, once} set.
-passive_cnct(Node) -> do_connect(Node, normal, true).
-disconnect(Node) -> request({disconnect, Node}).
+passive_cnct(Node) ->
+ case request({passive_cnct, Node}) of
+ ignored -> false;
+ Other -> Other
+ end.
-%% connect but not seen
-hidden_connect(Node) -> do_connect(Node, hidden, false).
+disconnect(Node) -> request({disconnect, Node}).
%% Should this node publish itself on Node?
publish_on_node(Node) when is_atom(Node) ->
@@ -272,67 +274,24 @@ connect_node(Node) when is_atom(Node) ->
hidden_connect_node(Node) when is_atom(Node) ->
request({connect, hidden, Node}).
-do_connect(Node, Type, WaitForBarred) -> %% Type = normal | hidden
- case catch ets:lookup(sys_dist, Node) of
- {'EXIT', _} ->
- ?connect_failure(Node,{table_missing, sys_dist}),
- false;
- [#barred_connection{}] ->
- case WaitForBarred of
- false ->
- false;
- true ->
- Pid = spawn(?MODULE,passive_connect_monitor,[self(),Node]),
- receive
- {Pid, true} ->
- %%io:format("Net Kernel: barred connection (~p) "
- %% "connected from other end.~n",[Node]),
- true;
- {Pid, false} ->
- ?connect_failure(Node,{barred_connection,
- ets:lookup(sys_dist, Node)}),
- %%io:format("Net Kernel: barred connection (~p) "
- %% "- failure.~n",[Node]),
- false
- end
- end;
- Else ->
- case application:get_env(kernel, dist_auto_connect) of
- {ok, never} ->
- ?connect_failure(Node,{dist_auto_connect,never}),
- false;
- % This might happen due to connection close
- % not beeing propagated to user space yet.
- % Save the day by just not connecting...
- {ok, once} when Else =/= [],
- (hd(Else))#connection.state =:= up ->
- ?connect_failure(Node,{barred_connection,
- ets:lookup(sys_dist, Node)}),
- false;
- _ ->
- request({connect, Type, Node})
- end
- end.
-passive_connect_monitor(Parent, Node) ->
+passive_connect_monitor(From, Node) ->
ok = monitor_nodes(true,[{node_type,all}]),
- case lists:member(Node,nodes([connected])) of
- true ->
- ok = monitor_nodes(false,[{node_type,all}]),
- Parent ! {self(),true};
- _ ->
- Ref = make_ref(),
- Tref = erlang:send_after(connecttime(),self(),Ref),
- receive
- Ref ->
- ok = monitor_nodes(false,[{node_type,all}]),
- Parent ! {self(), false};
- {nodeup,Node,_} ->
- ok = monitor_nodes(false,[{node_type,all}]),
- _ = erlang:cancel_timer(Tref),
- Parent ! {self(),true}
- end
- end.
+ Reply = case lists:member(Node,nodes([connected])) of
+ true ->
+ true;
+ _ ->
+ receive
+ {nodeup,Node,_} ->
+ true
+ after connecttime() ->
+ false
+ end
+ end,
+ ok = monitor_nodes(false,[{node_type,all}]),
+ {Pid, Tag} = From,
+ erlang:send(Pid, {Tag, Reply}).
+
%% If the net_kernel isn't running we ignore all requests to the
%% kernel, thus basically accepting them :-)
@@ -393,41 +352,140 @@ init({Name, LongOrShortNames, TickT, CleanHalt}) ->
{stop, Error}
end.
+do_auto_connect_1(Node, ConnId, From, State) ->
+ case ets:lookup(sys_dist, Node) of
+ [#barred_connection{}] ->
+ case ConnId of
+ passive_cnct ->
+ spawn(?MODULE,passive_connect_monitor,[From,Node]),
+ {noreply, State};
+ _ ->
+ erts_internal:abort_connection(Node, ConnId),
+ {reply, false, State}
+ end;
+
+ ConnLookup ->
+ do_auto_connect_2(Node, ConnId, From, State, ConnLookup)
+ end.
+
+do_auto_connect_2(Node, passive_cnct, From, State, ConnLookup) ->
+ try erts_internal:new_connection(Node) of
+ ConnId ->
+ do_auto_connect_2(Node, ConnId, From, State, ConnLookup)
+ catch
+ _:_ ->
+ error_logger:error_msg("~n** Cannot get connection id for node ~w~n",
+ [Node]),
+ {reply, false, State}
+ end;
+do_auto_connect_2(Node, ConnId, From, State, ConnLookup) ->
+ case ConnLookup of
+ [#connection{conn_id=ConnId, state = up}] ->
+ {reply, true, State};
+ [#connection{conn_id=ConnId, waiting=Waiting}=Conn] ->
+ case From of
+ noreply -> ok;
+ _ -> ets:insert(sys_dist, Conn#connection{waiting = [From|Waiting]})
+ end,
+ {noreply, State};
+
+ _ ->
+ case application:get_env(kernel, dist_auto_connect) of
+ {ok, never} ->
+ ?connect_failure(Node,{dist_auto_connect,never}),
+ erts_internal:abort_connection(Node, ConnId),
+ {reply, false, State};
+
+ %% This might happen due to connection close
+ %% not beeing propagated to user space yet.
+ %% Save the day by just not connecting...
+ {ok, once} when ConnLookup =/= [],
+ (hd(ConnLookup))#connection.state =:= up ->
+ ?connect_failure(Node,{barred_connection,
+ ets:lookup(sys_dist, Node)}),
+ erts_internal:abort_connection(Node, ConnId),
+ {reply, false, State};
+ _ ->
+ case setup(Node, ConnId, normal, From, State) of
+ {ok, SetupPid} ->
+ Owners = [{SetupPid, Node} | State#state.conn_owners],
+ {noreply,State#state{conn_owners=Owners}};
+ _Error ->
+ ?connect_failure(Node, {setup_call, failed, _Error}),
+ erts_internal:abort_connection(Node, ConnId),
+ {reply, false, State}
+ end
+ end
+ end.
+
+
+do_explicit_connect([#connection{conn_id = ConnId, state = up}], _, _, ConnId, _From, State) ->
+ {reply, true, State};
+do_explicit_connect([#connection{conn_id = ConnId}=Conn], _, _, ConnId, From, State)
+ when Conn#connection.state =:= pending;
+ Conn#connection.state =:= up_pending ->
+ Waiting = Conn#connection.waiting,
+ ets:insert(sys_dist, Conn#connection{waiting = [From|Waiting]}),
+ {noreply, State};
+do_explicit_connect([#barred_connection{}], Type, Node, ConnId, From , State) ->
+ %% Barred connection only affects auto_connect, ignore it.
+ do_explicit_connect([], Type, Node, ConnId, From , State);
+do_explicit_connect(_ConnLookup, Type, Node, ConnId, From , State) ->
+ case setup(Node,ConnId,Type,From,State) of
+ {ok, SetupPid} ->
+ Owners = [{SetupPid, Node} | State#state.conn_owners],
+ {noreply,State#state{conn_owners=Owners}};
+ _Error ->
+ ?connect_failure(Node, {setup_call, failed, _Error}),
+ {reply, false, State}
+ end.
+
%% ------------------------------------------------------------
%% handle_call.
%% ------------------------------------------------------------
%%
-%% Set up a connection to Node.
-%% The response is delayed until the connection is up and
-%% running.
+%% Passive auto-connect to Node.
+%% The response is delayed until the connection is up and running.
+%%
+handle_call({passive_cnct, Node}, From, State) when Node =:= node() ->
+ async_reply({reply, true, State}, From);
+handle_call({passive_cnct, Node}, From, State) ->
+ verbose({passive_cnct, Node}, 1, State),
+ R = do_auto_connect_1(Node, passive_cnct, From, State),
+ return_call(R, From);
+
+%%
+%% Explicit connect
+%% The response is delayed until the connection is up and running.
%%
handle_call({connect, _, Node}, From, State) when Node =:= node() ->
async_reply({reply, true, State}, From);
handle_call({connect, Type, Node}, From, State) ->
verbose({connect, Type, Node}, 1, State),
- case ets:lookup(sys_dist, Node) of
- [Conn] when Conn#connection.state =:= up ->
- async_reply({reply, true, State}, From);
- [Conn] when Conn#connection.state =:= pending ->
- Waiting = Conn#connection.waiting,
- ets:insert(sys_dist, Conn#connection{waiting = [From|Waiting]}),
- {noreply, State};
- [Conn] when Conn#connection.state =:= up_pending ->
- Waiting = Conn#connection.waiting,
- ets:insert(sys_dist, Conn#connection{waiting = [From|Waiting]}),
- {noreply, State};
- _ ->
- case setup(Node,Type,From,State) of
- {ok, SetupPid} ->
- Owners = [{SetupPid, Node} | State#state.conn_owners],
- {noreply,State#state{conn_owners=Owners}};
- _ ->
- ?connect_failure(Node, {setup_call, failed}),
- async_reply({reply, false, State}, From)
- end
- end;
+ ConnLookup = ets:lookup(sys_dist, Node),
+ R = try erts_internal:new_connection(Node) of
+ ConnId ->
+ R1 = do_explicit_connect(ConnLookup, Type, Node, ConnId, From, State),
+ case R1 of
+ {reply, true, _S} -> %% already connected
+ ok;
+ {noreply, _S} -> %% connection pending
+ ok;
+ {reply, false, _S} -> %% connection refused
+ erts_internal:abort_connection(Node, ConnId)
+ end,
+ R1
+
+ catch
+ _:_ ->
+ error_logger:error_msg("~n** Cannot get connection id for node ~w~n",
+ [Node]),
+ {reply, false, State}
+ end,
+ return_call(R, From);
+
%%
%% Close the connection to Node.
@@ -470,6 +528,9 @@ handle_call({allow, Nodes}, From, State) ->
async_reply({reply,error,State}, From)
end;
+handle_call(allowed, From, #state{allowed = Allowed} = State) ->
+ async_reply({reply,{ok,Allowed},State}, From);
+
%%
%% authentication, used by auth. Simply works as this:
%% if the message comes through, the other node IS authorized.
@@ -634,6 +695,25 @@ terminate(_Reason, State) ->
%% ------------------------------------------------------------
%%
+%% Asynchronous auto connect request
+%%
+handle_info({auto_connect,Node, DHandle}, State) ->
+ verbose({auto_connect, Node, DHandle}, 1, State),
+ ConnId = DHandle,
+ NewState =
+ case do_auto_connect_1(Node, ConnId, noreply, State) of
+ {noreply, S} -> %% Pending connection
+ S;
+
+ {reply, true, S} -> %% Already connected
+ S;
+
+ {reply, false, S} -> %% Connection refused
+ S
+ end,
+ {noreply, NewState};
+
+%%
%% accept a new connection.
%%
handle_info({accept,AcceptPid,Socket,Family,Proto}, State) ->
@@ -713,14 +793,24 @@ handle_info({AcceptPid, {accept_pending,MyNode,Node,Address,Type}}, State) ->
AcceptPid ! {self(), {accept_pending, already_pending}},
{noreply, State};
_ ->
- ets:insert(sys_dist, #connection{node = Node,
- state = pending,
- owner = AcceptPid,
- address = Address,
- type = Type}),
- AcceptPid ! {self(),{accept_pending,ok}},
- Owners = [{AcceptPid,Node} | State#state.conn_owners],
- {noreply, State#state{conn_owners = Owners}}
+ try erts_internal:new_connection(Node) of
+ ConnId ->
+ ets:insert(sys_dist, #connection{node = Node,
+ conn_id = ConnId,
+ state = pending,
+ owner = AcceptPid,
+ address = Address,
+ type = Type}),
+ AcceptPid ! {self(),{accept_pending,ok}},
+ Owners = [{AcceptPid,Node} | State#state.conn_owners],
+ {noreply, State#state{conn_owners = Owners}}
+ catch
+ _:_ ->
+ error_logger:error_msg("~n** Cannot get connection id for node ~w~n",
+ [Node]),
+ AcceptPid ! {self(),{accept_pending,nok_pending}},
+ {noreply, State}
+ end
end;
handle_info({SetupPid, {is_pending, Node}}, State) ->
@@ -906,6 +996,7 @@ pending_nodedown(Conn, Node, Type, State) ->
% Don't bar connections that have never been alive
%mark_sys_dist_nodedown(Node),
% - instead just delete the node:
+ erts_internal:abort_connection(Node, Conn#connection.conn_id),
ets:delete(sys_dist, Node),
reply_waiting(Node,Conn#connection.waiting, false),
case Type of
@@ -920,7 +1011,9 @@ up_pending_nodedown(Conn, Node, _Reason, _Type, State) ->
AcceptPid = Conn#connection.pending_owner,
Owners = State#state.conn_owners,
Pend = lists:keydelete(AcceptPid, 1, State#state.pend_owners),
+ erts_internal:abort_connection(Node, Conn#connection.conn_id),
Conn1 = Conn#connection { owner = AcceptPid,
+ conn_id = erts_internal:new_connection(Node),
pending_owner = undefined,
state = pending },
ets:insert(sys_dist, Conn1),
@@ -928,15 +1021,16 @@ up_pending_nodedown(Conn, Node, _Reason, _Type, State) ->
State#state{conn_owners = [{AcceptPid,Node}|Owners], pend_owners = Pend}.
-up_nodedown(_Conn, Node, _Reason, Type, State) ->
- mark_sys_dist_nodedown(Node),
+up_nodedown(Conn, Node, _Reason, Type, State) ->
+ mark_sys_dist_nodedown(Conn, Node),
case Type of
normal -> ?nodedown(Node, State);
_ -> ok
end,
State.
-mark_sys_dist_nodedown(Node) ->
+mark_sys_dist_nodedown(Conn, Node) ->
+ erts_internal:abort_connection(Node, Conn#connection.conn_id),
case application:get_env(kernel, dist_auto_connect) of
{ok, once} ->
ets:insert(sys_dist, #barred_connection{node = Node});
@@ -1032,14 +1126,22 @@ do_disconnect(Node, State) ->
{false, State}
end.
-
disconnect_pid(Pid, State) ->
exit(Pid, disconnect),
+
+ %% This code used to only use exit + recv 'EXIT' to sync,
+ %% but since OTP-22 links are no longer broken atomically
+ %% so the exit message below can arrive before any remaining
+ %% exit messages have killed the distribution port
+ Ref = erlang:monitor(process, Pid),
%% Sync wait for connection to die!!!
receive
- {'EXIT',Pid,Reason} ->
- {_,State1} = handle_exit(Pid, Reason, State),
- {true, State1}
+ {'DOWN',Ref,_,_,_} ->
+ receive
+ {'EXIT',Pid,Reason} ->
+ {_,State1} = handle_exit(Pid, Reason, State),
+ {true, State1}
+ end
end.
%%
@@ -1179,15 +1281,8 @@ spawn_func(_,{From,Tag},M,F,A,Gleader) ->
%% Set up connection to a new node.
%% -----------------------------------------------------------
-setup(Node,Type,From,State) ->
- Allowed = State#state.allowed,
- case lists:member(Node, Allowed) of
- false when Allowed =/= [] ->
- error_msg("** Connection attempt with "
- "disallowed node ~w ** ~n", [Node]),
- {error, bad_node};
- _ ->
- case select_mod(Node, State#state.listen) of
+setup(Node, ConnId, Type, From, State) ->
+ case setup_check(Node, State) of
{ok, L} ->
Mod = L#listen.module,
LAddr = L#listen.address,
@@ -1200,18 +1295,38 @@ setup(Node,Type,From,State) ->
Addr = LAddr#net_address {
address = undefined,
host = undefined },
+ Waiting = case From of
+ noreply -> [];
+ _ -> [From]
+ end,
ets:insert(sys_dist, #connection{node = Node,
+ conn_id = ConnId,
state = pending,
owner = Pid,
- waiting = [From],
+ waiting = Waiting,
address = Addr,
type = normal}),
{ok, Pid};
Error ->
Error
- end
end.
+setup_check(Node, State) ->
+ Allowed = State#state.allowed,
+ case lists:member(Node, Allowed) of
+ false when Allowed =/= [] ->
+ error_msg("** Connection attempt with "
+ "disallowed node ~w ** ~n", [Node]),
+ {error, bad_node};
+ _ ->
+ case select_mod(Node, State#state.listen) of
+ {ok, _L}=OK -> OK;
+ Error -> Error
+ end
+ end.
+
+
+
%%
%% Find a module that is willing to handle connection setup to Node
%%
@@ -1326,7 +1441,7 @@ validate_hostname([$@|HostPart] = Host) ->
end.
valid_name_head(Head) ->
- {ok, MP} = re:compile("^[0-9A-Za-z_\\-]*$", [unicode]),
+ {ok, MP} = re:compile("^[0-9A-Za-z_\\-]+$", [unicode]),
case re:run(Head, MP) of
{match, _} ->
true;
@@ -1652,6 +1767,11 @@ verbose(_, _, _) ->
getnode(P) when is_pid(P) -> node(P);
getnode(P) -> P.
+return_call({noreply, _State}=R, _From) ->
+ R;
+return_call(R, From) ->
+ async_reply(R, From).
+
async_reply({reply, Msg, State}, From) ->
async_gen_server_reply(From, Msg),
{noreply, State}.
@@ -1659,16 +1779,16 @@ async_reply({reply, Msg, State}, From) ->
async_gen_server_reply(From, Msg) ->
{Pid, Tag} = From,
M = {Tag, Msg},
- case catch erlang:send(Pid, M, [nosuspend, noconnect]) of
+ try erlang:send(Pid, M, [nosuspend, noconnect]) of
ok ->
ok;
nosuspend ->
_ = spawn(fun() -> catch erlang:send(Pid, M, [noconnect]) end),
ok;
noconnect ->
- ok; % The gen module takes care of this case.
- {'EXIT', _} ->
- ok
+ ok % The gen module takes care of this case.
+ catch
+ _:_ -> ok
end.
call_owner(Owner, Msg) ->
diff --git a/lib/kernel/src/os.erl b/lib/kernel/src/os.erl
index a4b4f798f9..29a26674ba 100644
--- a/lib/kernel/src/os.erl
+++ b/lib/kernel/src/os.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,41 +25,36 @@
-include("file.hrl").
+-export_type([env_var_name/0, env_var_value/0, env_var_name_value/0]).
+
+-export([getenv/0, getenv/1, getenv/2, putenv/2, unsetenv/1]).
+
%%% BIFs
--export([getenv/0, getenv/1, getenv/2, getpid/0,
- perf_counter/0, perf_counter/1,
- putenv/2, set_signal/2, system_time/0, system_time/1,
- timestamp/0, unsetenv/1]).
+-export([get_env_var/1, getpid/0, list_env_vars/0, perf_counter/0,
+ perf_counter/1, set_env_var/2, set_signal/2, system_time/0,
+ system_time/1, timestamp/0, unset_env_var/1]).
-type os_command() :: atom() | io_lib:chars().
-type os_command_opts() :: #{ max_size => non_neg_integer() | infinity }.
-export_type([os_command/0, os_command_opts/0]).
--spec getenv() -> [string()].
+-type env_var_name() :: nonempty_string().
-getenv() -> erlang:nif_error(undef).
+-type env_var_value() :: string().
--spec getenv(VarName) -> Value | false when
- VarName :: string(),
- Value :: string().
+-type env_var_name_value() :: nonempty_string().
-getenv(_) ->
+-spec list_env_vars() -> [{env_var_name(), env_var_value()}].
+list_env_vars() ->
erlang:nif_error(undef).
--spec getenv(VarName, DefaultValue) -> Value when
- VarName :: string(),
- DefaultValue :: string(),
- Value :: string().
-
-getenv(VarName, DefaultValue) ->
- case os:getenv(VarName) of
- false ->
- DefaultValue;
- Value ->
- Value
- end.
+-spec get_env_var(VarName) -> Value | false when
+ VarName :: env_var_name(),
+ Value :: env_var_value().
+get_env_var(_VarName) ->
+ erlang:nif_error(undef).
-spec getpid() -> Value when
Value :: string().
@@ -79,11 +74,10 @@ perf_counter() ->
perf_counter(Unit) ->
erlang:convert_time_unit(os:perf_counter(), perf_counter, Unit).
--spec putenv(VarName, Value) -> true when
- VarName :: string(),
- Value :: string().
-
-putenv(_, _) ->
+-spec set_env_var(VarName, Value) -> true when
+ VarName :: env_var_name(),
+ Value :: env_var_value().
+set_env_var(_, _) ->
erlang:nif_error(undef).
-spec system_time() -> integer().
@@ -103,10 +97,9 @@ system_time(_Unit) ->
timestamp() ->
erlang:nif_error(undef).
--spec unsetenv(VarName) -> true when
- VarName :: string().
-
-unsetenv(_) ->
+-spec unset_env_var(VarName) -> true when
+ VarName :: env_var_name().
+unset_env_var(_) ->
erlang:nif_error(undef).
-spec set_signal(Signal, Option) -> 'ok' when
@@ -120,6 +113,39 @@ set_signal(_Signal, _Option) ->
%%% End of BIFs
+-spec getenv() -> [env_var_name_value()].
+getenv() ->
+ [lists:flatten([Key, $=, Value]) || {Key, Value} <- os:list_env_vars() ].
+
+-spec getenv(VarName) -> Value | false when
+ VarName :: env_var_name(),
+ Value :: env_var_value().
+getenv(VarName) ->
+ os:get_env_var(VarName).
+
+-spec getenv(VarName, DefaultValue) -> Value when
+ VarName :: env_var_name(),
+ DefaultValue :: env_var_value(),
+ Value :: env_var_value().
+getenv(VarName, DefaultValue) ->
+ case os:getenv(VarName) of
+ false ->
+ DefaultValue;
+ Value ->
+ Value
+ end.
+
+-spec putenv(VarName, Value) -> true when
+ VarName :: env_var_name(),
+ Value :: env_var_value().
+putenv(VarName, Value) ->
+ os:set_env_var(VarName, Value).
+
+-spec unsetenv(VarName) -> true when
+ VarName :: env_var_name().
+unsetenv(VarName) ->
+ os:unset_env_var(VarName).
+
-spec type() -> {Osfamily, Osname} when
Osfamily :: unix | win32,
Osname :: atom().
@@ -183,7 +209,7 @@ verify_executable(Name0, [Ext|Rest], OrigExtensions) ->
end;
verify_executable(Name, [], OrigExtensions) when OrigExtensions =/= [""] -> %% Windows
%% Will only happen on windows, hence case insensitivity
- case can_be_full_name(string:to_lower(Name),OrigExtensions) of
+ case can_be_full_name(string:lowercase(Name),OrigExtensions) of
true ->
verify_executable(Name,[""],[""]);
_ ->
@@ -245,8 +271,7 @@ cmd(Cmd) ->
Command :: os_command(),
Options :: os_command_opts().
cmd(Cmd, Opts) ->
- validate(Cmd),
- {SpawnCmd, SpawnOpts, SpawnInput, Eot} = mk_cmd(os:type(), Cmd),
+ {SpawnCmd, SpawnOpts, SpawnInput, Eot} = mk_cmd(os:type(), validate(Cmd)),
Port = open_port({spawn, SpawnCmd}, [binary, stderr_to_stdout,
stream, in, hide | SpawnOpts]),
MonRef = erlang:monitor(port, Port),
@@ -266,8 +291,6 @@ mk_cmd({win32,Wtype}, Cmd) ->
{Cspec,_} -> lists:concat([Cspec," /c",Cmd])
end,
{Command, [], [], <<>>};
-mk_cmd(OsType,Cmd) when is_atom(Cmd) ->
- mk_cmd(OsType, atom_to_list(Cmd));
mk_cmd(_,Cmd) ->
%% Have to send command in like this in order to make sh commands like
%% cd and ulimit available
@@ -290,17 +313,33 @@ mk_cmd(_,Cmd) ->
<<$\^D>>}.
validate(Atom) when is_atom(Atom) ->
- ok;
+ validate(atom_to_list(Atom));
validate(List) when is_list(List) ->
- validate1(List).
+ case validate1(List) of
+ false ->
+ List;
+ true ->
+ %% Had zeros at end; remove them...
+ string:trim(List, trailing, [0])
+ end.
-validate1([C|Rest]) when is_integer(C) ->
+validate1([0|Rest]) ->
+ validate2(Rest);
+validate1([C|Rest]) when is_integer(C), C > 0 ->
validate1(Rest);
validate1([List|Rest]) when is_list(List) ->
- validate1(List),
- validate1(Rest);
+ validate1(List) or validate1(Rest);
validate1([]) ->
- ok.
+ false.
+
+%% Ensure that the rest is zero only...
+validate2([]) ->
+ true;
+validate2([0|Rest]) ->
+ validate2(Rest);
+validate2([List|Rest]) when is_list(List) ->
+ validate2(List),
+ validate2(Rest).
get_data(Port, MonRef, Eot, Sofar, Size, Max) ->
receive
diff --git a/lib/kernel/src/raw_file_io.erl b/lib/kernel/src/raw_file_io.erl
new file mode 100644
index 0000000000..e3c07c8f78
--- /dev/null
+++ b/lib/kernel/src/raw_file_io.erl
@@ -0,0 +1,75 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(raw_file_io).
+
+-export([open/2]).
+
+open(Filename, Modes) ->
+ %% Layers are applied in this order, and the listed modules will call this
+ %% function again as necessary. eg. a raw compressed delayed file in list
+ %% mode will walk through [_list -> _compressed -> _delayed -> _raw].
+ ModuleOrder = [{raw_file_io_list, fun match_list/1},
+ {raw_file_io_compressed, fun match_compressed/1},
+ {raw_file_io_delayed, fun match_delayed/1},
+ {raw_file_io_raw, fun match_raw/1}],
+ open_1(ModuleOrder, Filename, add_implicit_modes(Modes)).
+open_1([], _Filename, _Modes) ->
+ error(badarg);
+open_1([{Module, Match} | Rest], Filename, Modes) ->
+ case lists:any(Match, Modes) of
+ true ->
+ {Options, ChildModes} =
+ lists:partition(fun(Mode) -> Match(Mode) end, Modes),
+ Module:open_layer(Filename, ChildModes, Options);
+ false ->
+ open_1(Rest, Filename, Modes)
+ end.
+
+%% 'read' and 'list' mode are enabled unless disabled by another option, so
+%% we'll explicitly add them to avoid duplicating this logic in child layers.
+add_implicit_modes(Modes0) ->
+ Modes1 = add_unless_matched(Modes0, fun match_writable/1, read),
+ add_unless_matched(Modes1, fun match_binary/1, list).
+add_unless_matched(Modes, Match, Default) ->
+ case lists:any(Match, Modes) of
+ false -> [Default | Modes];
+ true -> Modes
+ end.
+
+match_list(list) -> true;
+match_list(_Other) -> false.
+
+match_compressed(compressed) -> true;
+match_compressed(_Other) -> false.
+
+match_delayed({delayed_write, _Size, _Timeout}) -> true;
+match_delayed(delayed_write) -> true;
+match_delayed(_Other) -> false.
+
+match_raw(raw) -> true;
+match_raw(_Other) -> false.
+
+match_writable(write) -> true;
+match_writable(append) -> true;
+match_writable(exclusive) -> true;
+match_writable(_Other) -> false.
+
+match_binary(binary) -> true;
+match_binary(_Other) -> false.
diff --git a/lib/kernel/src/raw_file_io_compressed.erl b/lib/kernel/src/raw_file_io_compressed.erl
new file mode 100644
index 0000000000..d5ab042d25
--- /dev/null
+++ b/lib/kernel/src/raw_file_io_compressed.erl
@@ -0,0 +1,134 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(raw_file_io_compressed).
+
+-export([close/1, sync/1, datasync/1, truncate/1, advise/4, allocate/3,
+ position/2, write/2, pwrite/2, pwrite/3,
+ read_line/1, read/2, pread/2, pread/3]).
+
+%% OTP internal.
+-export([ipread_s32bu_p32bu/3, sendfile/8]).
+
+-export([open_layer/3]).
+
+-include("file_int.hrl").
+
+open_layer(Filename, Modes, Options) ->
+ IsAppend = lists:member(append, Modes),
+ IsDeflate = lists:member(write, Modes),
+ IsInflate = lists:member(read, Modes),
+ if
+ IsDeflate, IsInflate; IsAppend ->
+ {error, einval};
+ IsDeflate, not IsInflate ->
+ start_server_module(raw_file_io_deflate, Filename, Modes, Options);
+ IsInflate ->
+ start_server_module(raw_file_io_inflate, Filename, Modes, Options)
+ end.
+
+start_server_module(Module, Filename, Modes, Options) ->
+ Secret = make_ref(),
+ case gen_statem:start(Module, {self(), Secret, Options}, []) of
+ {ok, Pid} -> open_next_layer(Pid, Secret, Filename, Modes);
+ Other -> Other
+ end.
+
+open_next_layer(Pid, Secret, Filename, Modes) ->
+ case gen_statem:call(Pid, {'$open', Secret, Filename, Modes}, infinity) of
+ ok ->
+ PublicFd = #file_descriptor{
+ module = raw_file_io_compressed, data = {self(), Pid} },
+ {ok, PublicFd};
+ Other -> Other
+ end.
+
+close(Fd) ->
+ wrap_call(Fd, [close]).
+
+sync(Fd) ->
+ wrap_call(Fd, [sync]).
+datasync(Fd) ->
+ wrap_call(Fd, [datasync]).
+
+truncate(Fd) ->
+ wrap_call(Fd, [truncate]).
+
+advise(Fd, Offset, Length, Advise) ->
+ wrap_call(Fd, [advise, Offset, Length, Advise]).
+allocate(Fd, Offset, Length) ->
+ wrap_call(Fd, [allocate, Offset, Length]).
+
+position(Fd, Mark) ->
+ wrap_call(Fd, [position, Mark]).
+
+write(Fd, IOData) ->
+ try
+ CompactedData = erlang:iolist_to_iovec(IOData),
+ wrap_call(Fd, [write, CompactedData])
+ catch
+ error:badarg -> {error, badarg}
+ end.
+
+pwrite(Fd, Offset, IOData) ->
+ try
+ CompactedData = erlang:iolist_to_iovec(IOData),
+ wrap_call(Fd, [pwrite, Offset, CompactedData])
+ catch
+ error:badarg -> {error, badarg}
+ end.
+pwrite(Fd, LocBytes) ->
+ try
+ CompactedLocBytes =
+ [ {Offset, erlang:iolist_to_iovec(IOData)} ||
+ {Offset, IOData} <- LocBytes ],
+ wrap_call(Fd, [pwrite, CompactedLocBytes])
+ catch
+ error:badarg -> {error, badarg}
+ end.
+
+read_line(Fd) ->
+ wrap_call(Fd, [read_line]).
+read(Fd, Size) ->
+ wrap_call(Fd, [read, Size]).
+pread(Fd, Offset, Size) ->
+ wrap_call(Fd, [pread, Offset, Size]).
+pread(Fd, LocNums) ->
+ wrap_call(Fd, [pread, LocNums]).
+
+ipread_s32bu_p32bu(Fd, Offset, MaxSize) ->
+ wrap_call(Fd, [ipread_s32bu_p32bu, Offset, MaxSize]).
+
+sendfile(_,_,_,_,_,_,_,_) ->
+ {error, enotsup}.
+
+wrap_call(Fd, Command) ->
+ {_Owner, Pid} = get_fd_data(Fd),
+ try gen_statem:call(Pid, Command, infinity) of
+ Result -> Result
+ catch
+ exit:{noproc, _StackTrace} -> {error, einval}
+ end.
+
+get_fd_data(#file_descriptor{ data = Data }) ->
+ {Owner, _ServerPid} = Data,
+ case self() of
+ Owner -> Data;
+ _ -> error(not_on_controlling_process)
+ end.
diff --git a/lib/kernel/src/raw_file_io_deflate.erl b/lib/kernel/src/raw_file_io_deflate.erl
new file mode 100644
index 0000000000..acfc546743
--- /dev/null
+++ b/lib/kernel/src/raw_file_io_deflate.erl
@@ -0,0 +1,159 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(raw_file_io_deflate).
+
+-behavior(gen_statem).
+
+-export([init/1, callback_mode/0, terminate/3]).
+-export([opening/3, opened/3]).
+
+-include("file_int.hrl").
+
+-define(GZIP_WBITS, 16 + 15).
+
+callback_mode() -> state_functions.
+
+init({Owner, Secret, [compressed]}) ->
+ Monitor = monitor(process, Owner),
+ Z = zlib:open(),
+ ok = zlib:deflateInit(Z, default, deflated, ?GZIP_WBITS, 8, default),
+ Data =
+ #{ owner => Owner,
+ monitor => Monitor,
+ secret => Secret,
+ position => 0,
+ zlib => Z },
+ {ok, opening, Data}.
+
+opening({call, From}, {'$open', Secret, Filename, Modes}, #{ secret := Secret } = Data) ->
+ case raw_file_io:open(Filename, Modes) of
+ {ok, PrivateFd} ->
+ NewData = Data#{ handle => PrivateFd },
+ {next_state, opened, NewData, [{reply, From, ok}]};
+ Other ->
+ {stop_and_reply, normal, [{reply, From, Other}]}
+ end;
+opening(_Event, _Contents, _Data) ->
+ {keep_state_and_data, [postpone]}.
+
+%%
+
+opened(info, {'DOWN', Monitor, process, _Owner, Reason}, #{ monitor := Monitor } = Data) ->
+ if
+ Reason =/= kill -> flush_deflate_state(Data);
+ Reason =:= kill -> ignored
+ end,
+ {stop, shutdown};
+
+opened(info, _Message, _Data) ->
+ keep_state_and_data;
+
+opened({call, {Owner, _Tag} = From}, [close], #{ owner := Owner } = Data) ->
+ #{ handle := PrivateFd } = Data,
+ Response =
+ case flush_deflate_state(Data) of
+ ok -> ?CALL_FD(PrivateFd, close, []);
+ Other -> Other
+ end,
+ {stop_and_reply, normal, [{reply, From, Response}]};
+
+opened({call, {Owner, _Tag} = From}, [position, Mark], #{ owner := Owner } = Data) ->
+ case position(Data, Mark) of
+ {ok, NewData, Result} ->
+ Response = {ok, Result},
+ {keep_state, NewData, [{reply, From, Response}]};
+ Other ->
+ {keep_state_and_data, [{reply, From, Other}]}
+ end;
+
+opened({call, {Owner, _Tag} = From}, [write, IOVec], #{ owner := Owner } = Data) ->
+ case write(Data, IOVec) of
+ {ok, NewData} -> {keep_state, NewData, [{reply, From, ok}]};
+ Other -> {keep_state_and_data, [{reply, From, Other}]}
+ end;
+
+opened({call, {Owner, _Tag} = From}, [read, _Size], #{ owner := Owner }) ->
+ Response = {error, ebadf},
+ {keep_state_and_data, [{reply, From, Response}]};
+
+opened({call, {Owner, _Tag} = From}, [read_line], #{ owner := Owner }) ->
+ Response = {error, ebadf},
+ {keep_state_and_data, [{reply, From, Response}]};
+
+opened({call, {Owner, _Tag} = From}, _Command, #{ owner := Owner }) ->
+ Response = {error, enotsup},
+ {keep_state_and_data, [{reply, From, Response}]};
+
+opened({call, _From}, _Command, _Data) ->
+ %% The client functions filter this out, so we'll crash if the user does
+ %% anything stupid on purpose.
+ {shutdown, protocol_violation};
+
+opened(_Event, _Request, _Data) ->
+ keep_state_and_data.
+
+write(Data, IOVec) ->
+ #{ handle := PrivateFd, position := Position, zlib := Z } = Data,
+ UncompressedSize = iolist_size(IOVec),
+ case ?CALL_FD(PrivateFd, write, [zlib:deflate(Z, IOVec)]) of
+ ok -> {ok, Data#{ position := (Position + UncompressedSize) }};
+ Other -> Other
+ end.
+
+%%
+%% We support "seeking" forward as long as it isn't relative to EOF.
+%%
+%% Seeking is a bit of a misnomer as it's really just compressing zeroes until
+%% we reach the desired point, but it has always behaved like this.
+%%
+
+position(Data, Mark) when is_atom(Mark) ->
+ position(Data, {Mark, 0});
+position(Data, Offset) when is_integer(Offset) ->
+ position(Data, {bof, Offset});
+position(Data, {bof, Offset}) when is_integer(Offset) ->
+ position_1(Data, Offset);
+position(Data, {cur, Offset}) when is_integer(Offset) ->
+ #{ position := Position } = Data,
+ position_1(Data, Position + Offset);
+position(_Data, {eof, Offset}) when is_integer(Offset) ->
+ {error, einval};
+position(_Data, _Any) ->
+ {error, badarg}.
+
+position_1(#{ position := Desired } = Data, Desired) ->
+ {ok, Data, Desired};
+position_1(#{ position := Current } = Data, Desired) when Current < Desired ->
+ BytesToWrite = min(Desired - Current, 4 bsl 20),
+ case write(Data, <<0:(BytesToWrite)/unit:8>>) of
+ {ok, NewData} -> position_1(NewData, Desired);
+ Other -> Other
+ end;
+position_1(#{ position := Current }, Desired) when Current > Desired ->
+ {error, einval}.
+
+flush_deflate_state(#{ handle := PrivateFd, zlib := Z }) ->
+ case ?CALL_FD(PrivateFd, write, [zlib:deflate(Z, [], finish)]) of
+ ok -> ok;
+ Other -> Other
+ end.
+
+terminate(_Reason, _State, _Data) ->
+ ok.
diff --git a/lib/kernel/src/raw_file_io_delayed.erl b/lib/kernel/src/raw_file_io_delayed.erl
new file mode 100644
index 0000000000..d2ad7550a1
--- /dev/null
+++ b/lib/kernel/src/raw_file_io_delayed.erl
@@ -0,0 +1,320 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(raw_file_io_delayed).
+
+-behavior(gen_statem).
+
+-export([close/1, sync/1, datasync/1, truncate/1, advise/4, allocate/3,
+ position/2, write/2, pwrite/2, pwrite/3,
+ read_line/1, read/2, pread/2, pread/3]).
+
+%% OTP internal.
+-export([ipread_s32bu_p32bu/3, sendfile/8]).
+
+-export([open_layer/3]).
+
+-export([init/1, callback_mode/0, terminate/3]).
+-export([opening/3, opened/3]).
+
+-include("file_int.hrl").
+
+open_layer(Filename, Modes, Options) ->
+ Secret = make_ref(),
+ case gen_statem:start(?MODULE, {self(), Secret, Options}, []) of
+ {ok, Pid} ->
+ gen_statem:call(Pid, {'$open', Secret, Filename, Modes}, infinity);
+ Other ->
+ Other
+ end.
+
+callback_mode() -> state_functions.
+
+init({Owner, Secret, Options}) ->
+ Monitor = monitor(process, Owner),
+ Defaults =
+ #{ owner => Owner,
+ monitor => Monitor,
+ secret => Secret,
+ timer => none,
+ pid => self(),
+ buffer => prim_buffer:new(),
+ delay_size => 64 bsl 10,
+ delay_time => 2000 },
+ Data = fill_delay_values(Defaults, Options),
+ {ok, opening, Data}.
+
+fill_delay_values(Data, []) ->
+ Data;
+fill_delay_values(Data, [{delayed_write, Size, Time} | Options]) ->
+ fill_delay_values(Data#{ delay_size => Size, delay_time => Time }, Options);
+fill_delay_values(Data, [_ | Options]) ->
+ fill_delay_values(Data, Options).
+
+opening({call, From}, {'$open', Secret, Filename, Modes}, #{ secret := Secret } = Data) ->
+ case raw_file_io:open(Filename, Modes) of
+ {ok, PrivateFd} ->
+ PublicData = maps:with([owner, buffer, delay_size, pid], Data),
+ PublicFd = #file_descriptor{ module = ?MODULE, data = PublicData },
+
+ NewData = Data#{ handle => PrivateFd },
+ Response = {ok, PublicFd},
+ {next_state, opened, NewData, [{reply, From, Response}]};
+ Other ->
+ {stop_and_reply, normal, [{reply, From, Other}]}
+ end;
+opening(_Event, _Contents, _Data) ->
+ {keep_state_and_data, [postpone]}.
+
+%%
+
+opened(info, {'$timed_out', Secret}, #{ secret := Secret } = Data) ->
+ %% If the user writes something at this exact moment, the flush will fail
+ %% and the timer won't reset on the next write since the buffer won't be
+ %% empty (Unless we collided on a flush). We therefore reset the timeout to
+ %% ensure that data won't sit idle for extended periods of time.
+ case try_flush_write_buffer(Data) of
+ busy -> gen_statem:cast(self(), '$reset_timeout');
+ ok -> ok
+ end,
+ {keep_state, Data#{ timer => none }, []};
+
+opened(info, {'DOWN', Monitor, process, _Owner, Reason}, #{ monitor := Monitor } = Data) ->
+ if
+ Reason =/= kill -> try_flush_write_buffer(Data);
+ Reason =:= kill -> ignored
+ end,
+ {stop, shutdown};
+
+opened(info, _Message, _Data) ->
+ keep_state_and_data;
+
+opened({call, {Owner, _Tag} = From}, [close], #{ owner := Owner } = Data) ->
+ case flush_write_buffer(Data) of
+ ok ->
+ #{ handle := PrivateFd } = Data,
+ Response = ?CALL_FD(PrivateFd, close, []),
+ {stop_and_reply, normal, [{reply, From, Response}]};
+ Other ->
+ {stop_and_reply, normal, [{reply, From, Other}]}
+ end;
+
+opened({call, {Owner, _Tag} = From}, '$wait', #{ owner := Owner }) ->
+ %% Used in write/2 to synchronize writes on lock conflicts.
+ {keep_state_and_data, [{reply, From, ok}]};
+
+opened({call, {Owner, _Tag} = From}, '$synchronous_flush', #{ owner := Owner } = Data) ->
+ cancel_flush_timeout(Data),
+ Response = flush_write_buffer(Data),
+ {keep_state_and_data, [{reply, From, Response}]};
+
+opened({call, {Owner, _Tag} = From}, Command, #{ owner := Owner } = Data) ->
+ Response =
+ case flush_write_buffer(Data) of
+ ok -> dispatch_command(Data, Command);
+ Other -> Other
+ end,
+ {keep_state_and_data, [{reply, From, Response}]};
+
+opened({call, _From}, _Command, _Data) ->
+ %% The client functions filter this out, so we'll crash if the user does
+ %% anything stupid on purpose.
+ {shutdown, protocol_violation};
+
+opened(cast, '$reset_timeout', #{ delay_time := Timeout, secret := Secret } = Data) ->
+ cancel_flush_timeout(Data),
+ Timer = erlang:send_after(Timeout, self(), {'$timed_out', Secret}),
+ {keep_state, Data#{ timer => Timer }, []};
+
+opened(cast, _Message, _Data) ->
+ {keep_state_and_data, []}.
+
+dispatch_command(Data, [Function | Args]) ->
+ #{ handle := Handle } = Data,
+ Module = Handle#file_descriptor.module,
+ apply(Module, Function, [Handle | Args]).
+
+cancel_flush_timeout(#{ timer := none }) ->
+ ok;
+cancel_flush_timeout(#{ timer := Timer }) ->
+ _ = erlang:cancel_timer(Timer, [{async, true}]),
+ ok.
+
+try_flush_write_buffer(#{ buffer := Buffer, handle := PrivateFd }) ->
+ case prim_buffer:try_lock(Buffer) of
+ acquired ->
+ flush_write_buffer_1(Buffer, PrivateFd),
+ prim_buffer:unlock(Buffer),
+ ok;
+ busy ->
+ busy
+ end.
+
+%% This is only safe to use when there is no chance of conflict with the owner
+%% process, or in other words, "during synchronous calls outside of the locked
+%% section of write/2"
+flush_write_buffer(#{ buffer := Buffer, handle := PrivateFd }) ->
+ acquired = prim_buffer:try_lock(Buffer),
+ Result = flush_write_buffer_1(Buffer, PrivateFd),
+ prim_buffer:unlock(Buffer),
+ Result.
+
+flush_write_buffer_1(Buffer, PrivateFd) ->
+ case prim_buffer:size(Buffer) of
+ Size when Size > 0 ->
+ ?CALL_FD(PrivateFd, write, [prim_buffer:read_iovec(Buffer, Size)]);
+ 0 ->
+ ok
+ end.
+
+terminate(_Reason, _State, _Data) ->
+ ok.
+
+%% Client functions
+
+write(Fd, IOData) ->
+ try
+ enqueue_write(Fd, erlang:iolist_to_iovec(IOData))
+ catch
+ error:badarg -> {error, badarg}
+ end.
+enqueue_write(_Fd, []) ->
+ ok;
+enqueue_write(Fd, IOVec) ->
+ %% get_fd_data will reject everyone except the process that opened the Fd,
+ %% so we can't race with anyone except the wrapper process.
+ #{ delay_size := DelaySize,
+ buffer := Buffer,
+ pid := Pid } = get_fd_data(Fd),
+ case prim_buffer:try_lock(Buffer) of
+ acquired ->
+ %% (The wrapper process will exit without flushing if we're killed
+ %% while holding the lock).
+ enqueue_write_locked(Pid, Buffer, DelaySize, IOVec);
+ busy ->
+ %% This can only happen while we're processing a timeout in the
+ %% wrapper process, so we perform a bogus call to get a completion
+ %% notification before trying again.
+ gen_statem:call(Pid, '$wait'),
+ enqueue_write(Fd, IOVec)
+ end.
+enqueue_write_locked(Pid, Buffer, DelaySize, IOVec) ->
+ %% The synchronous operations (write, forced flush) are safe since we're
+ %% running on the only process that can fill the buffer; a timeout being
+ %% processed just before $synchronous_flush will cause the flush to nop,
+ %% and a timeout sneaking in just before a synchronous write won't do
+ %% anything since the buffer is guaranteed to be empty at that point.
+ BufSize = prim_buffer:size(Buffer),
+ case is_iovec_smaller_than(IOVec, DelaySize - BufSize) of
+ true when BufSize > 0 ->
+ prim_buffer:write(Buffer, IOVec),
+ prim_buffer:unlock(Buffer);
+ true ->
+ prim_buffer:write(Buffer, IOVec),
+ prim_buffer:unlock(Buffer),
+ gen_statem:cast(Pid, '$reset_timeout');
+ false when BufSize > 0 ->
+ prim_buffer:write(Buffer, IOVec),
+ prim_buffer:unlock(Buffer),
+ gen_statem:call(Pid, '$synchronous_flush');
+ false ->
+ prim_buffer:unlock(Buffer),
+ gen_statem:call(Pid, [write, IOVec])
+ end.
+
+%% iolist_size/1 will always look through the entire list to get a precise
+%% amount, which is pretty inefficient since we only need to know whether we've
+%% hit the buffer threshold or not.
+%%
+%% We only handle the binary case since write/2 forcibly translates input to
+%% erlang:iovec().
+is_iovec_smaller_than(IOVec, Max) ->
+ is_iovec_smaller_than_1(IOVec, Max, 0).
+is_iovec_smaller_than_1(_IOVec, Max, Acc) when Acc >= Max ->
+ false;
+is_iovec_smaller_than_1([], _Max, _Acc) ->
+ true;
+is_iovec_smaller_than_1([Binary | Rest], Max, Acc) when is_binary(Binary) ->
+ is_iovec_smaller_than_1(Rest, Max, Acc + byte_size(Binary)).
+
+close(Fd) ->
+ wrap_call(Fd, [close]).
+
+sync(Fd) ->
+ wrap_call(Fd, [sync]).
+datasync(Fd) ->
+ wrap_call(Fd, [datasync]).
+
+truncate(Fd) ->
+ wrap_call(Fd, [truncate]).
+
+advise(Fd, Offset, Length, Advise) ->
+ wrap_call(Fd, [advise, Offset, Length, Advise]).
+allocate(Fd, Offset, Length) ->
+ wrap_call(Fd, [allocate, Offset, Length]).
+
+position(Fd, Mark) ->
+ wrap_call(Fd, [position, Mark]).
+
+pwrite(Fd, Offset, IOData) ->
+ try
+ CompactedData = erlang:iolist_to_iovec(IOData),
+ wrap_call(Fd, [pwrite, Offset, CompactedData])
+ catch
+ error:badarg -> {error, badarg}
+ end.
+pwrite(Fd, LocBytes) ->
+ try
+ CompactedLocBytes =
+ [ {Offset, erlang:iolist_to_iovec(IOData)} ||
+ {Offset, IOData} <- LocBytes ],
+ wrap_call(Fd, [pwrite, CompactedLocBytes])
+ catch
+ error:badarg -> {error, badarg}
+ end.
+
+read_line(Fd) ->
+ wrap_call(Fd, [read_line]).
+read(Fd, Size) ->
+ wrap_call(Fd, [read, Size]).
+pread(Fd, Offset, Size) ->
+ wrap_call(Fd, [pread, Offset, Size]).
+pread(Fd, LocNums) ->
+ wrap_call(Fd, [pread, LocNums]).
+
+ipread_s32bu_p32bu(Fd, Offset, MaxSize) ->
+ wrap_call(Fd, [ipread_s32bu_p32bu, Offset, MaxSize]).
+
+sendfile(_,_,_,_,_,_,_,_) ->
+ {error, enotsup}.
+
+wrap_call(Fd, Command) ->
+ #{ pid := Pid } = get_fd_data(Fd),
+ try gen_statem:call(Pid, Command, infinity) of
+ Result -> Result
+ catch
+ exit:{noproc, _StackTrace} -> {error, einval}
+ end.
+
+get_fd_data(#file_descriptor{ data = Data }) ->
+ #{ owner := Owner } = Data,
+ case self() of
+ Owner -> Data;
+ _ -> error(not_on_controlling_process)
+ end.
diff --git a/lib/kernel/src/raw_file_io_inflate.erl b/lib/kernel/src/raw_file_io_inflate.erl
new file mode 100644
index 0000000000..d3ed02dd03
--- /dev/null
+++ b/lib/kernel/src/raw_file_io_inflate.erl
@@ -0,0 +1,261 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(raw_file_io_inflate).
+
+-behavior(gen_statem).
+
+-export([init/1, callback_mode/0, terminate/3]).
+-export([opening/3, opened_gzip/3, opened_passthrough/3]).
+
+-include("file_int.hrl").
+
+-define(INFLATE_CHUNK_SIZE, (8 bsl 10)).
+-define(GZIP_WBITS, (16 + 15)).
+
+callback_mode() -> state_functions.
+
+init({Owner, Secret, [compressed]}) ->
+ Monitor = monitor(process, Owner),
+ %% We're using the undocumented inflateInit/3 to open the stream in
+ %% 'reset mode', which resets the inflate state at the end of every stream,
+ %% allowing us to read concatenated gzip files.
+ Z = zlib:open(),
+ ok = zlib:inflateInit(Z, ?GZIP_WBITS, reset),
+ Data =
+ #{ owner => Owner,
+ monitor => Monitor,
+ secret => Secret,
+ position => 0,
+ buffer => prim_buffer:new(),
+ zlib => Z },
+ {ok, opening, Data}.
+
+%% The old driver fell back to plain reads if the file didn't start with the
+%% magic gzip bytes.
+choose_decompression_state(PrivateFd) ->
+ State =
+ case ?CALL_FD(PrivateFd, read, [2]) of
+ {ok, <<16#1F, 16#8B>>} -> opened_gzip;
+ _Other -> opened_passthrough
+ end,
+ {ok, 0} = ?CALL_FD(PrivateFd, position, [0]),
+ State.
+
+opening({call, From}, {'$open', Secret, Filename, Modes}, #{ secret := Secret } = Data) ->
+ case raw_file_io:open(Filename, Modes) of
+ {ok, PrivateFd} ->
+ NextState = choose_decompression_state(PrivateFd),
+ NewData = Data#{ handle => PrivateFd },
+ {next_state, NextState, NewData, [{reply, From, ok}]};
+ Other ->
+ {stop_and_reply, normal, [{reply, From, Other}]}
+ end;
+opening(_Event, _Contents, _Data) ->
+ {keep_state_and_data, [postpone]}.
+
+internal_close(From, Data) ->
+ #{ handle := PrivateFd } = Data,
+ Response = ?CALL_FD(PrivateFd, close, []),
+ {stop_and_reply, normal, [{reply, From, Response}]}.
+
+opened_passthrough(info, {'DOWN', Monitor, process, _Owner, _Reason}, #{ monitor := Monitor }) ->
+ {stop, shutdown};
+
+opened_passthrough(info, _Message, _Data) ->
+ keep_state_and_data;
+
+opened_passthrough({call, {Owner, _Tag} = From}, [close], #{ owner := Owner } = Data) ->
+ internal_close(From, Data);
+
+opened_passthrough({call, {Owner, _Tag} = From}, [Method | Args], #{ owner := Owner } = Data) ->
+ #{ handle := PrivateFd } = Data,
+ Response = ?CALL_FD(PrivateFd, Method, Args),
+ {keep_state_and_data, [{reply, From, Response}]};
+
+opened_passthrough({call, _From}, _Command, _Data) ->
+ %% The client functions filter this out, so we'll crash if the user does
+ %% anything stupid on purpose.
+ {shutdown, protocol_violation};
+
+opened_passthrough(_Event, _Request, _Data) ->
+ keep_state_and_data.
+
+%%
+
+opened_gzip(info, {'DOWN', Monitor, process, _Owner, _Reason}, #{ monitor := Monitor }) ->
+ {stop, shutdown};
+
+opened_gzip(info, _Message, _Data) ->
+ keep_state_and_data;
+
+opened_gzip({call, {Owner, _Tag} = From}, [close], #{ owner := Owner } = Data) ->
+ internal_close(From, Data);
+
+opened_gzip({call, {Owner, _Tag} = From}, [position, Mark], #{ owner := Owner } = Data) ->
+ case position(Data, Mark) of
+ {ok, NewData, Result} ->
+ Response = {ok, Result},
+ {keep_state, NewData, [{reply, From, Response}]};
+ Other ->
+ {keep_state_and_data, [{reply, From, Other}]}
+ end;
+
+opened_gzip({call, {Owner, _Tag} = From}, [read, Size], #{ owner := Owner } = Data) ->
+ case read(Data, Size) of
+ {ok, NewData, Result} ->
+ Response = {ok, Result},
+ {keep_state, NewData, [{reply, From, Response}]};
+ Other ->
+ {keep_state_and_data, [{reply, From, Other}]}
+ end;
+
+opened_gzip({call, {Owner, _Tag} = From}, [read_line], #{ owner := Owner } = Data) ->
+ case read_line(Data) of
+ {ok, NewData, Result} ->
+ Response = {ok, Result},
+ {keep_state, NewData, [{reply, From, Response}]};
+ Other ->
+ {keep_state_and_data, [{reply, From, Other}]}
+ end;
+
+opened_gzip({call, {Owner, _Tag} = From}, [write, _IOData], #{ owner := Owner }) ->
+ Response = {error, ebadf},
+ {keep_state_and_data, [{reply, From, Response}]};
+
+opened_gzip({call, {Owner, _Tag} = From}, _Request, #{ owner := Owner }) ->
+ Response = {error, enotsup},
+ {keep_state_and_data, [{reply, From, Response}]};
+
+opened_gzip({call, _From}, _Request, _Data) ->
+ %% The client functions filter this out, so we'll crash if the user does
+ %% anything stupid on purpose.
+ {shutdown, protocol_violation};
+
+opened_gzip(_Event, _Request, _Data) ->
+ keep_state_and_data.
+
+%%
+
+read(#{ buffer := Buffer } = Data, Size) ->
+ try read_1(Data, Buffer, prim_buffer:size(Buffer), Size) of
+ Result -> Result
+ catch
+ error:badarg -> {error, badarg};
+ error:_ -> {error, eio}
+ end.
+read_1(Data, Buffer, BufferSize, ReadSize) when BufferSize >= ReadSize ->
+ #{ position := Position } = Data,
+ Decompressed = prim_buffer:read(Buffer, ReadSize),
+ {ok, Data#{ position => (Position + ReadSize) }, Decompressed};
+read_1(Data, Buffer, BufferSize, ReadSize) when BufferSize < ReadSize ->
+ #{ handle := PrivateFd } = Data,
+ case ?CALL_FD(PrivateFd, read, [?INFLATE_CHUNK_SIZE]) of
+ {ok, Compressed} ->
+ #{ zlib := Z } = Data,
+ Uncompressed = erlang:iolist_to_iovec(zlib:inflate(Z, Compressed)),
+ prim_buffer:write(Buffer, Uncompressed),
+ read_1(Data, Buffer, prim_buffer:size(Buffer), ReadSize);
+ eof when BufferSize > 0 ->
+ read_1(Data, Buffer, BufferSize, BufferSize);
+ Other ->
+ Other
+ end.
+
+read_line(#{ buffer := Buffer } = Data) ->
+ try read_line_1(Data, Buffer, prim_buffer:find_byte_index(Buffer, $\n)) of
+ {ok, NewData, Decompressed} -> {ok, NewData, Decompressed};
+ Other -> Other
+ catch
+ error:badarg -> {error, badarg};
+ error:_ -> {error, eio}
+ end.
+
+read_line_1(Data, Buffer, not_found) ->
+ #{ handle := PrivateFd, zlib := Z } = Data,
+ case ?CALL_FD(PrivateFd, read, [?INFLATE_CHUNK_SIZE]) of
+ {ok, Compressed} ->
+ Uncompressed = erlang:iolist_to_iovec(zlib:inflate(Z, Compressed)),
+ prim_buffer:write(Buffer, Uncompressed),
+ read_line_1(Data, Buffer, prim_buffer:find_byte_index(Buffer, $\n));
+ eof ->
+ case prim_buffer:size(Buffer) of
+ Size when Size > 0 -> {ok, prim_buffer:read(Buffer, Size)};
+ Size when Size =:= 0 -> eof
+ end;
+ Error ->
+ Error
+ end;
+read_line_1(Data, Buffer, {ok, LFIndex}) ->
+ %% Translate CRLF into just LF, completely ignoring which encoding is used,
+ %% but treat the file position as including CR.
+ #{ position := Position } = Data,
+ NewData = Data#{ position => (Position + LFIndex + 1) },
+ CRIndex = (LFIndex - 1),
+ TranslatedLine =
+ case prim_buffer:read(Buffer, LFIndex + 1) of
+ <<Line:CRIndex/binary, "\r\n">> -> <<Line/binary, "\n">>;
+ Line -> Line
+ end,
+ {ok, NewData, TranslatedLine}.
+
+%%
+%% We support seeking in both directions as long as it isn't relative to EOF.
+%%
+%% Seeking backwards is extremely inefficient since we have to seek to the very
+%% beginning and then decompress up to the desired point.
+%%
+
+position(Data, Mark) when is_atom(Mark) ->
+ position(Data, {Mark, 0});
+position(Data, Offset) when is_integer(Offset) ->
+ position(Data, {bof, Offset});
+position(Data, {bof, Offset}) when is_integer(Offset) ->
+ position_1(Data, Offset);
+position(Data, {cur, Offset}) when is_integer(Offset) ->
+ #{ position := Position } = Data,
+ position_1(Data, Position + Offset);
+position(_Data, {eof, Offset}) when is_integer(Offset) ->
+ {error, einval};
+position(_Data, _Other) ->
+ {error, badarg}.
+
+position_1(_Data, Desired) when Desired < 0 ->
+ {error, einval};
+position_1(#{ position := Desired } = Data, Desired) ->
+ {ok, Data, Desired};
+position_1(#{ position := Current } = Data, Desired) when Current < Desired ->
+ case read(Data, min(Desired - Current, ?INFLATE_CHUNK_SIZE)) of
+ {ok, NewData, _Data} -> position_1(NewData, Desired);
+ eof -> {ok, Data, Current};
+ Other -> Other
+ end;
+position_1(#{ position := Current } = Data, Desired) when Current > Desired ->
+ #{ handle := PrivateFd, buffer := Buffer, zlib := Z } = Data,
+ case ?CALL_FD(PrivateFd, position, [bof]) of
+ {ok, 0} ->
+ ok = zlib:inflateReset(Z),
+ prim_buffer:wipe(Buffer),
+ position_1(Data#{ position => 0 }, Desired);
+ Other ->
+ Other
+ end.
+
+terminate(_Reason, _State, _Data) ->
+ ok.
diff --git a/lib/kernel/src/raw_file_io_list.erl b/lib/kernel/src/raw_file_io_list.erl
new file mode 100644
index 0000000000..2e16e63f0e
--- /dev/null
+++ b/lib/kernel/src/raw_file_io_list.erl
@@ -0,0 +1,128 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(raw_file_io_list).
+
+-export([close/1, sync/1, datasync/1, truncate/1, advise/4, allocate/3,
+ position/2, write/2, pwrite/2, pwrite/3,
+ read_line/1, read/2, pread/2, pread/3]).
+
+%% OTP internal.
+-export([ipread_s32bu_p32bu/3, sendfile/8]).
+
+-export([open_layer/3]).
+
+-include("file_int.hrl").
+
+open_layer(Filename, Modes, [list]) ->
+ case raw_file_io:open(Filename, [binary | Modes]) of
+ {ok, PrivateFd} -> {ok, make_public_fd(PrivateFd, Modes)};
+ Other -> Other
+ end.
+
+%% We can skip wrapping the file if it's write-only since only read operations
+%% are affected by list mode. Since raw_file_io fills in all implicit options
+%% for us, all we need to do is check whether 'read' is among them.
+make_public_fd(PrivateFd, Modes) ->
+ case lists:member(read, Modes) of
+ true -> #file_descriptor{ module = ?MODULE, data = PrivateFd };
+ false -> PrivateFd
+ end.
+
+close(Fd) ->
+ PrivateFd = Fd#file_descriptor.data,
+ ?CALL_FD(PrivateFd, close, []).
+
+sync(Fd) ->
+ PrivateFd = Fd#file_descriptor.data,
+ ?CALL_FD(PrivateFd, sync, []).
+datasync(Fd) ->
+ PrivateFd = Fd#file_descriptor.data,
+ ?CALL_FD(PrivateFd, datasync, []).
+
+truncate(Fd) ->
+ PrivateFd = Fd#file_descriptor.data,
+ ?CALL_FD(PrivateFd, truncate, []).
+
+advise(Fd, Offset, Length, Advise) ->
+ PrivateFd = Fd#file_descriptor.data,
+ ?CALL_FD(PrivateFd, advise, [Offset, Length, Advise]).
+allocate(Fd, Offset, Length) ->
+ PrivateFd = Fd#file_descriptor.data,
+ ?CALL_FD(PrivateFd, allocate, [Offset, Length]).
+
+position(Fd, Mark) ->
+ PrivateFd = Fd#file_descriptor.data,
+ ?CALL_FD(PrivateFd, position, [Mark]).
+
+write(Fd, IOData) ->
+ PrivateFd = Fd#file_descriptor.data,
+ ?CALL_FD(PrivateFd, write, [IOData]).
+
+pwrite(Fd, Offset, IOData) ->
+ PrivateFd = Fd#file_descriptor.data,
+ ?CALL_FD(PrivateFd, pwrite, [Offset, IOData]).
+pwrite(Fd, LocBytes) ->
+ PrivateFd = Fd#file_descriptor.data,
+ ?CALL_FD(PrivateFd, pwrite, [LocBytes]).
+
+read_line(Fd) ->
+ PrivateFd = Fd#file_descriptor.data,
+ case ?CALL_FD(PrivateFd, read_line, []) of
+ {ok, Binary} -> {ok, binary_to_list(Binary)};
+ Other -> Other
+ end.
+read(Fd, Size) ->
+ PrivateFd = Fd#file_descriptor.data,
+ case ?CALL_FD(PrivateFd, read, [Size]) of
+ {ok, Binary} -> {ok, binary_to_list(Binary)};
+ Other -> Other
+ end.
+pread(Fd, Offset, Size) ->
+ PrivateFd = Fd#file_descriptor.data,
+ case ?CALL_FD(PrivateFd, pread, [Offset, Size]) of
+ {ok, Binary} -> {ok, binary_to_list(Binary)};
+ Other -> Other
+ end.
+pread(Fd, LocNums) ->
+ PrivateFd = Fd#file_descriptor.data,
+ case ?CALL_FD(PrivateFd, pread, [LocNums]) of
+ {ok, LocResults} ->
+ TranslatedResults =
+ [ case Result of
+ Result when is_binary(Result) -> binary_to_list(Result);
+ eof -> eof
+ end || Result <- LocResults ],
+ {ok, TranslatedResults};
+ Other -> Other
+ end.
+
+ipread_s32bu_p32bu(Fd, Offset, MaxSize) ->
+ PrivateFd = Fd#file_descriptor.data,
+ case ?CALL_FD(PrivateFd, ipread_s32bu_p32bu, [Offset, MaxSize]) of
+ {ok, {Size, Pointer, Binary}} when is_binary(Binary) ->
+ {ok, {Size, Pointer, binary_to_list(Binary)}};
+ Other ->
+ Other
+ end.
+
+sendfile(Fd, Dest, Offset, Bytes, ChunkSize, Headers, Trailers, Flags) ->
+ Args = [Dest, Offset, Bytes, ChunkSize, Headers, Trailers, Flags],
+ PrivateFd = Fd#file_descriptor.data,
+ ?CALL_FD(PrivateFd, sendfile, Args).
diff --git a/lib/kernel/src/raw_file_io_raw.erl b/lib/kernel/src/raw_file_io_raw.erl
new file mode 100644
index 0000000000..9a9fe78eb1
--- /dev/null
+++ b/lib/kernel/src/raw_file_io_raw.erl
@@ -0,0 +1,25 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(raw_file_io_raw).
+
+-export([open_layer/3]).
+
+open_layer(Filename, Modes, [raw]) ->
+ prim_file:open(Filename, [raw | Modes]).
diff --git a/lib/kernel/src/rpc.erl b/lib/kernel/src/rpc.erl
index 0e0b7dffa3..d197de942f 100644
--- a/lib/kernel/src/rpc.erl
+++ b/lib/kernel/src/rpc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -418,10 +418,7 @@ abcast(Name, Mess) ->
abcast([Node|Tail], Name, Mess) ->
Dest = {Name,Node},
- case catch erlang:send(Dest, Mess, [noconnect]) of
- noconnect -> spawn(erlang, send, [Dest,Mess]), ok;
- _ -> ok
- end,
+ try erlang:send(Dest, Mess) catch error:_ -> ok end,
abcast(Tail, Name, Mess);
abcast([], _,_) -> abcast.
@@ -498,7 +495,7 @@ start_monitor(Node, Name) ->
Module :: module(),
Function :: atom(),
Args :: [term()],
- ResL :: [term()],
+ ResL :: [Res :: term() | {'badrpc', Reason :: term()}],
BadNodes :: [node()].
multicall(M, F, A) ->
@@ -509,14 +506,14 @@ multicall(M, F, A) ->
Module :: module(),
Function :: atom(),
Args :: [term()],
- ResL :: [term()],
+ ResL :: [Res :: term() | {'badrpc', Reason :: term()}],
BadNodes :: [node()];
(Module, Function, Args, Timeout) -> {ResL, BadNodes} when
Module :: module(),
Function :: atom(),
Args :: [term()],
Timeout :: timeout(),
- ResL :: [term()],
+ ResL :: [Res :: term() | {'badrpc', Reason :: term()}],
BadNodes :: [node()].
multicall(Nodes, M, F, A) when is_list(Nodes) ->
@@ -531,7 +528,7 @@ multicall(M, F, A, Timeout) ->
Function :: atom(),
Args :: [term()],
Timeout :: timeout(),
- ResL :: [term()],
+ ResL :: [Res :: term() | {'badrpc', Reason :: term()}],
BadNodes :: [node()].
multicall(Nodes, M, F, A, infinity)
diff --git a/lib/kernel/src/seq_trace.erl b/lib/kernel/src/seq_trace.erl
index cc0c10909b..4f9d7b3e5c 100644
--- a/lib/kernel/src/seq_trace.erl
+++ b/lib/kernel/src/seq_trace.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -41,7 +41,7 @@
-type flag() :: 'send' | 'receive' | 'print' | 'timestamp' | 'monotonic_timestamp' | 'strict_monotonic_timestamp'.
-type component() :: 'label' | 'serial' | flag().
--type value() :: (Integer :: non_neg_integer())
+-type value() :: (Label :: term())
| {Previous :: non_neg_integer(),
Current :: non_neg_integer()}
| (Bool :: boolean()).
@@ -59,10 +59,6 @@ set_token({Flags,Label,Serial,_From,Lastcnt}) ->
F = decode_flags(Flags),
set_token2([{label,Label},{serial,{Lastcnt, Serial}} | F]).
-%% We limit the label type to always be a small integer because erl_interface
-%% expects that, the BIF can however "unofficially" handle atoms as well, and
-%% atoms can be used if only Erlang nodes are involved
-
-spec set_token(Component, Val) -> {Component, OldVal} when
Component :: component(),
Val :: value(),
@@ -102,7 +98,7 @@ print(Label, Term) ->
-spec reset_trace() -> 'true'.
reset_trace() ->
- erlang:system_flag(1, 0).
+ erlang:system_flag(reset_seq_trace, true).
%% reset_trace(Pid) -> % this might be a useful function too
diff --git a/lib/kernel/src/standard_error.erl b/lib/kernel/src/standard_error.erl
index 5d649e5f94..ef5b532960 100644
--- a/lib/kernel/src/standard_error.erl
+++ b/lib/kernel/src/standard_error.erl
@@ -27,7 +27,8 @@
-define(PROCNAME_SUP, standard_error_sup).
%% Defines for control ops
--define(CTRL_OP_GET_WINSIZE,100).
+-define(ERTS_TTYSL_DRV_CONTROL_MAGIC_NUMBER, 16#018b0900).
+-define(CTRL_OP_GET_WINSIZE, (100 + ?ERTS_TTYSL_DRV_CONTROL_MAGIC_NUMBER)).
%%
%% The basic server and start-up.
diff --git a/lib/kernel/src/user.erl b/lib/kernel/src/user.erl
index 872e63ab53..0c9e1ea303 100644
--- a/lib/kernel/src/user.erl
+++ b/lib/kernel/src/user.erl
@@ -28,7 +28,8 @@
-define(NAME, user).
%% Defines for control ops
--define(CTRL_OP_GET_WINSIZE,100).
+-define(ERTS_TTYSL_DRV_CONTROL_MAGIC_NUMBER, 16#018b0900).
+-define(CTRL_OP_GET_WINSIZE, (100 + ?ERTS_TTYSL_DRV_CONTROL_MAGIC_NUMBER)).
%%
%% The basic server and start-up.
diff --git a/lib/kernel/src/user_drv.erl b/lib/kernel/src/user_drv.erl
index 99ea4210bd..69ff8e7971 100644
--- a/lib/kernel/src/user_drv.erl
+++ b/lib/kernel/src/user_drv.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,9 +32,10 @@
-define(OP_BEEP,4).
-define(OP_PUTC_SYNC,5).
% Control op
--define(CTRL_OP_GET_WINSIZE,100).
--define(CTRL_OP_GET_UNICODE_STATE,101).
--define(CTRL_OP_SET_UNICODE_STATE,102).
+-define(ERTS_TTYSL_DRV_CONTROL_MAGIC_NUMBER, 16#018b0900).
+-define(CTRL_OP_GET_WINSIZE, (100 + ?ERTS_TTYSL_DRV_CONTROL_MAGIC_NUMBER)).
+-define(CTRL_OP_GET_UNICODE_STATE, (101 + ?ERTS_TTYSL_DRV_CONTROL_MAGIC_NUMBER)).
+-define(CTRL_OP_SET_UNICODE_STATE, (102 + ?ERTS_TTYSL_DRV_CONTROL_MAGIC_NUMBER)).
%% start()
%% start(ArgumentList)
@@ -119,7 +120,7 @@ server1(Iport, Oport, Shell) ->
{Curr,Shell1} =
case init:get_argument(remsh) of
{ok,[[Node]]} ->
- ANode = list_to_atom(Node),
+ ANode = list_to_atom(append_hostname(Node)),
RShell = {ANode,shell,start,[]},
RGr = group:start(self(), RShell, rem_sh_opts(ANode)),
{RGr,RShell};
@@ -138,6 +139,12 @@ server1(Iport, Oport, Shell) ->
%% Enter the server loop.
server_loop(Iport, Oport, Curr, User, Gr, {false, queue:new()}).
+append_hostname(Node) ->
+ case string:find(Node, "@") of
+ nomatch -> Node ++ string:find(atom_to_list(node()), "@");
+ _ -> Node
+ end.
+
rem_sh_opts(Node) ->
[{expand_fun,fun(B)-> rpc:call(Node,edlin_expand,expand,[B]) end}].
diff --git a/lib/kernel/test/Makefile b/lib/kernel/test/Makefile
index efe3a68531..6763a04d9f 100644
--- a/lib/kernel/test/Makefile
+++ b/lib/kernel/test/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -57,6 +57,7 @@ MODULES= \
prim_file_SUITE \
ram_file_SUITE \
gen_tcp_api_SUITE \
+ gen_tcp_dist \
gen_tcp_echo_SUITE \
gen_tcp_misc_SUITE \
gen_udp_SUITE \
@@ -70,6 +71,18 @@ MODULES= \
interactive_shell_SUITE \
init_SUITE \
kernel_config_SUITE \
+ logger_SUITE \
+ logger_disk_log_h_SUITE \
+ logger_env_var_SUITE \
+ logger_filters_SUITE \
+ logger_formatter_SUITE \
+ logger_legacy_SUITE \
+ logger_olp_SUITE \
+ logger_proxy_SUITE \
+ logger_simple_h_SUITE \
+ logger_std_h_SUITE \
+ logger_stress_SUITE \
+ logger_test_lib \
os_SUITE \
pg2_SUITE \
seq_trace_SUITE \
@@ -80,7 +93,8 @@ MODULES= \
loose_node \
sendfile_SUITE \
standard_error_SUITE \
- multi_load_SUITE
+ multi_load_SUITE \
+ zzz_SUITE
APP_FILES = \
appinc.app \
@@ -101,7 +115,7 @@ TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
INSTALL_PROGS= $(TARGET_FILES)
EMAKEFILE=Emakefile
-COVERFILE=kernel.cover
+COVERFILE=kernel.cover logger.cover
# ----------------------------------------------------
# Release directory specification
@@ -117,11 +131,17 @@ ERL_COMPILE_FLAGS +=
EBIN = .
+TARGETS = $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
-make_emakefile:
+gen_tcp_dist.erl: ../examples/gen_tcp_dist/src/gen_tcp_dist.erl
+ cp $< $@
+
+make_emakefile: $(ERL_FILES)
$(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) '*_SUITE_make' \
> $(EMAKEFILE)
$(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES) \
@@ -137,6 +157,9 @@ clean:
docs:
+targets: $(TARGETS)
+
+
# ----------------------------------------------------
# Release Target
# ----------------------------------------------------
@@ -148,7 +171,8 @@ release_tests_spec: make_emakefile
$(INSTALL_DIR) "$(RELSYSDIR)"
$(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)"
$(INSTALL_DATA) $(APP_FILES) "$(RELSYSDIR)"
- $(INSTALL_DATA) kernel.spec kernel_smoke.spec kernel_bench.spec \
+ $(INSTALL_DATA) \
+ kernel.spec kernel_smoke.spec kernel_bench.spec logger.spec \
$(EMAKEFILE) $(COVERFILE) "$(RELSYSDIR)"
chmod -R u+w "$(RELSYSDIR)"
@tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
diff --git a/lib/kernel/test/application_SUITE.erl b/lib/kernel/test/application_SUITE.erl
index 866043cfb4..1ab554db7c 100644
--- a/lib/kernel/test/application_SUITE.erl
+++ b/lib/kernel/test/application_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -31,13 +31,15 @@
otp_3002/1, otp_3184/1, otp_4066/1, otp_4227/1, otp_5363/1,
otp_5606/1,
start_phases/1, get_key/1, get_env/1,
+ set_env/1, set_env_persistent/1, set_env_errors/1,
permit_false_start_local/1, permit_false_start_dist/1, script_start/1,
nodedown_start/1, init2973/0, loop2973/0, loop5606/1]).
-export([config_change/1, persistent_env/1,
distr_changed_tc1/1, distr_changed_tc2/1,
ensure_started/1, ensure_all_started/1,
- shutdown_func/1, do_shutdown/1, shutdown_timeout/1, shutdown_deadlock/1]).
+ shutdown_func/1, do_shutdown/1, shutdown_timeout/1, shutdown_deadlock/1,
+ config_relative_paths/1]).
-define(TESTCASE, testcase_name).
-define(testcase, proplists:get_value(?TESTCASE, Config)).
@@ -54,8 +56,9 @@ all() ->
load_use_cache, ensure_started, {group, reported_bugs}, start_phases,
script_start, nodedown_start, permit_false_start_local,
permit_false_start_dist, get_key, get_env, ensure_all_started,
+ set_env, set_env_persistent, set_env_errors,
{group, distr_changed}, config_change, shutdown_func, shutdown_timeout,
- shutdown_deadlock,
+ shutdown_deadlock, config_relative_paths,
persistent_env].
groups() ->
@@ -1568,7 +1571,8 @@ loop5606(Pid) ->
%% Tests get_env/* functions.
get_env(Conf) when is_list(Conf) ->
- {ok, _} = application:get_env(kernel, error_logger),
+ ok = application:set_env(kernel, new_var, new_val),
+ {ok, new_val} = application:get_env(kernel, new_var),
undefined = application:get_env(undefined_app, a),
undefined = application:get_env(kernel, error_logger_xyz),
default = application:get_env(kernel, error_logger_xyz, default),
@@ -1602,8 +1606,7 @@ get_key(Conf) when is_list(Conf) ->
{ok, [{init, [kalle]}, {takeover, []}, {go, [sune]}]} =
rpc:call(Cp1, application, get_key, [appinc, start_phases]),
{ok, Env} = rpc:call(Cp1, application, get_key, [appinc ,env]),
- [{included_applications,[appinc1,appinc2]},
- {own2,val2},{own_env1,value1}] = lists:sort(Env),
+ [{own2,val2},{own_env1,value1}] = lists:sort(Env),
{ok, []} = rpc:call(Cp1, application, get_key, [appinc, modules]),
{ok, {application_starter, [ch_sup, {appinc, 41, 43}] }} =
rpc:call(Cp1, application, get_key, [appinc, mod]),
@@ -1624,8 +1627,7 @@ get_key(Conf) when is_list(Conf) ->
{mod, {application_starter, [ch_sup, {appinc, 41, 43}] }},
{start_phases, [{init, [kalle]}, {takeover, []}, {go, [sune]}]}]} =
rpc:call(Cp1, application, get_all_key, [appinc]),
- [{included_applications,[appinc1,appinc2]},
- {own2,val2},{own_env1,value1}] = lists:sort(Env),
+ [{own2,val2},{own_env1,value1}] = lists:sort(Env),
{ok, "Test of new app file, including appnew"} =
gen_server:call({global, {ch,41}}, {get_pid_key, description}),
@@ -1642,8 +1644,7 @@ get_key(Conf) when is_list(Conf) ->
{ok, [{init, [kalle]}, {takeover, []}, {go, [sune]}]} =
gen_server:call({global, {ch,41}}, {get_pid_key, start_phases}),
{ok, Env} = gen_server:call({global, {ch,41}}, {get_pid_key, env}),
- [{included_applications,[appinc1,appinc2]},
- {own2,val2},{own_env1,value1}] = lists:sort(Env),
+ [{own2,val2},{own_env1,value1}] = lists:sort(Env),
{ok, []} =
gen_server:call({global, {ch,41}}, {get_pid_key, modules}),
{ok, {application_starter, [ch_sup, {appinc, 41, 43}] }} =
@@ -1670,8 +1671,7 @@ get_key(Conf) when is_list(Conf) ->
{mod, {application_starter, [ch_sup, {appinc, 41, 43}] }},
{start_phases, [{init, [kalle]}, {takeover, []}, {go, [sune]}]}]} =
gen_server:call({global, {ch,41}}, get_pid_all_key),
- [{included_applications,[appinc1,appinc2]},
- {own2,val2},{own_env1,value1}] = lists:sort(Env),
+ [{own2,val2},{own_env1,value1}] = lists:sort(Env),
stop_node_nice(Cp1),
ok.
@@ -1946,6 +1946,94 @@ get_appls([_ | T], Res) ->
get_appls([], Res) ->
Res.
+%% Test set_env/1.
+set_env(Conf) when is_list(Conf) ->
+ ok = application:set_env([{appinc, [{own2, persist}, {not_in_app, persist}]},
+ {unknown_app, [{key, persist}]}]),
+
+ %% own_env1 and own2 are set in appinc
+ undefined = application:get_env(appinc, own_env1),
+ {ok, persist} = application:get_env(appinc, own2),
+ {ok, persist} = application:get_env(appinc, not_in_app),
+ {ok, persist} = application:get_env(unknown_app, key),
+
+ ok = application:load(appinc()),
+ {ok, value1} = application:get_env(appinc, own_env1),
+ {ok, val2} = application:get_env(appinc, own2),
+ {ok, persist} = application:get_env(appinc, not_in_app),
+ {ok, persist} = application:get_env(unknown_app, key),
+
+ %% On reload, values are lost
+ ok = application:unload(appinc),
+ ok = application:load(appinc()),
+ {ok, value1} = application:get_env(appinc, own_env1),
+ {ok, val2} = application:get_env(appinc, own2),
+ undefined = application:get_env(appinc, not_in_app),
+
+ %% Clean up
+ ok = application:unload(appinc).
+
+%% Test set_env/2 with persistent true.
+set_env_persistent(Conf) when is_list(Conf) ->
+ Opts = [{persistent, true}],
+ ok = application:set_env([{appinc, [{own2, persist}, {not_in_app, persist}]},
+ {unknown_app, [{key, persist}]}], Opts),
+
+ %% own_env1 and own2 are set in appinc
+ undefined = application:get_env(appinc, own_env1),
+ {ok, persist} = application:get_env(appinc, own2),
+ {ok, persist} = application:get_env(appinc, not_in_app),
+ {ok, persist} = application:get_env(unknown_app, key),
+
+ ok = application:load(appinc()),
+ {ok, value1} = application:get_env(appinc, own_env1),
+ {ok, persist} = application:get_env(appinc, own2),
+ {ok, persist} = application:get_env(appinc, not_in_app),
+ {ok, persist} = application:get_env(unknown_app, key),
+
+ %% On reload, values are not lost
+ ok = application:unload(appinc),
+ ok = application:load(appinc()),
+ {ok, value1} = application:get_env(appinc, own_env1),
+ {ok, persist} = application:get_env(appinc, own2),
+ {ok, persist} = application:get_env(appinc, not_in_app),
+
+ %% Clean up
+ ok = application:unload(appinc).
+
+set_env_errors(Conf) when is_list(Conf) ->
+ "application: 1; application name must be an atom" =
+ badarg_msg(fun() -> application:set_env([{1, []}]) end),
+
+ "application: foo; parameters must be a list" =
+ badarg_msg(fun() -> application:set_env([{foo, bar}]) end),
+
+ "invalid application config: foo_bar" =
+ badarg_msg(fun() -> application:set_env([foo_bar]) end),
+
+ "application: foo; invalid parameter name: 1" =
+ badarg_msg(fun() -> application:set_env([{foo, [{1, 2}]}]) end),
+
+ "application: foo; invalid parameter: config" =
+ badarg_msg(fun() -> application:set_env([{foo, [config]}]) end),
+
+ "application: kernel; erroneous parameter: distributed" =
+ badarg_msg(fun() -> application:set_env([{kernel, [{distributed, config}]}]) end),
+
+ "duplicate application config: foo" =
+ badarg_msg(fun() -> application:set_env([{foo, []}, {foo, []}]) end),
+
+ "application: foo; duplicate parameter: bar" =
+ badarg_msg(fun() -> application:set_env([{foo, [{bar, baz}, {bar, bat}]}]) end),
+
+ ok.
+
+badarg_msg(Fun) ->
+ try Fun() of
+ _ -> ct:fail(try_succeeded)
+ catch
+ error:{badarg, Msg} -> Msg
+ end.
%% Test set_env/4 and unset_env/3 with persistent true.
persistent_env(Conf) when is_list(Conf) ->
@@ -2078,6 +2166,42 @@ shutdown_deadlock(Config) when is_list(Config) ->
%%-----------------------------------------------------------------
+%% Relative paths in sys.config
+%%-----------------------------------------------------------------
+config_relative_paths(Config) ->
+ Dir = ?config(priv_dir,Config),
+ SubDir = filename:join(Dir,"subdir"),
+ Sys = filename:join(SubDir,"sys.config"),
+ ok = filelib:ensure_dir(Sys),
+ ok = file:write_file(Sys,"[\"../up.config\",\"current\"].\n"),
+
+ Up = filename:join(Dir,"up.config"),
+ ok = file:write_file(Up,"[{app1,[{key1,value}]}].\n"),
+
+ {ok,Cwd} = file:get_cwd(),
+ Current1 = filename:join(Cwd,"current.config"),
+ ok = file:write_file(Current1,"[{app1,[{key2,value1}]}].\n"),
+
+ N1 = list_to_atom(lists:concat([?FUNCTION_NAME,"_1"])),
+ {ok,Node1} = start_node(N1,filename:rootname(Sys)),
+ ok = rpc:call(Node1, application, load, [app1()]),
+ {ok, value} = rpc:call(Node1, application, get_env,[app1,key1]),
+ {ok, value1} = rpc:call(Node1, application, get_env,[app1,key2]),
+
+ Current2 = filename:join(SubDir,"current.config"),
+ ok = file:write_file(Current2,"[{app1,[{key2,value2}]}].\n"),
+
+ N2 = list_to_atom(lists:concat([?FUNCTION_NAME,"_2"])),
+ {ok, Node2} = start_node(N2,filename:rootname(Sys)),
+ ok = rpc:call(Node2, application, load, [app1()]),
+ {ok, value} = rpc:call(Node2, application, get_env,[app1,key1]),
+ {ok, value2} = rpc:call(Node2, application, get_env,[app1,key2]),
+
+ stop_node_nice([Node1,Node2]),
+
+ ok.
+
+%%-----------------------------------------------------------------
%% Utility functions
%%-----------------------------------------------------------------
app0() ->
diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl
index 569753155f..4f0847084f 100644
--- a/lib/kernel/test/code_SUITE.erl
+++ b/lib/kernel/test/code_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,8 +25,8 @@
-export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2]).
-export([set_path/1, get_path/1, add_path/1, add_paths/1, del_path/1,
replace_path/1, load_file/1, load_abs/1, ensure_loaded/1,
- delete/1, purge/1, purge_many_exits/1, soft_purge/1, is_loaded/1,
- all_loaded/1,
+ delete/1, purge/1, purge_many_exits/0, purge_many_exits/1,
+ soft_purge/1, is_loaded/1, all_loaded/1,
load_binary/1, dir_req/1, object_code/1, set_path_file/1,
upgrade/1,
sticky_dir/1, pa_pz_option/1, add_del_path/1,
@@ -55,7 +55,7 @@
suite() ->
[{ct_hooks,[ts_install_cth]},
- {timetrap,{minutes,5}}].
+ {timetrap,{seconds,30}}].
all() ->
[set_path, get_path, add_path, add_paths, del_path,
@@ -140,6 +140,11 @@ end_per_testcase(on_load_embedded, Config) ->
LinkName = proplists:get_value(link_name, Config),
_ = del_link(LinkName),
end_per_testcase(Config);
+end_per_testcase(upgrade, Config) ->
+ %% Make sure tracing is turned off even if the test times out.
+ erlang:trace_pattern({error_handler,undefined_function,3}, false, [global]),
+ erlang:trace(self(), false, [call]),
+ end_per_testcase(Config);
end_per_testcase(_Func, Config) ->
end_per_testcase(Config).
@@ -391,6 +396,9 @@ purge(Config) when is_list(Config) ->
process_flag(trap_exit, OldFlag),
ok.
+purge_many_exits() ->
+ [{timetrap, {minutes, 2}}].
+
purge_many_exits(Config) when is_list(Config) ->
OldFlag = process_flag(trap_exit, true),
@@ -525,7 +533,7 @@ upgrade(Config) ->
T = [beam, hipe],
[upgrade_do(DataDir, Client, T) || Client <- T],
- case hipe:llvm_support_available() of
+ case hipe:erllvm_is_supported() of
false -> ok;
true ->
T2 = [beam, hipe_llvm],
@@ -931,37 +939,34 @@ purge_stacktrace(Config) when is_list(Config) ->
code:purge(code_b_test),
try code_b_test:call(fun(b) -> ok end, a)
catch
- error:function_clause ->
+ error:function_clause:Stacktrace ->
code:load_file(code_b_test),
- case erlang:get_stacktrace() of
+ case Stacktrace of
[{?MODULE,_,[a],_},
{code_b_test,call,2,_},
{?MODULE,purge_stacktrace,1,_}|_] ->
- false = code:purge(code_b_test),
- [] = erlang:get_stacktrace()
+ false = code:purge(code_b_test)
end
end,
try code_b_test:call(nofun, 2)
catch
- error:function_clause ->
+ error:function_clause:Stacktrace2 ->
code:load_file(code_b_test),
- case erlang:get_stacktrace() of
+ case Stacktrace2 of
[{code_b_test,call,[nofun,2],_},
{?MODULE,purge_stacktrace,1,_}|_] ->
- false = code:purge(code_b_test),
- [] = erlang:get_stacktrace()
+ false = code:purge(code_b_test)
end
end,
Args = [erlang,error,[badarg]],
try code_b_test:call(erlang, error, [badarg,Args])
catch
- error:badarg ->
+ error:badarg:Stacktrace3 ->
code:load_file(code_b_test),
- case erlang:get_stacktrace() of
+ case Stacktrace3 of
[{code_b_test,call,Args,_},
{?MODULE,purge_stacktrace,1,_}|_] ->
- false = code:purge(code_b_test),
- [] = erlang:get_stacktrace()
+ false = code:purge(code_b_test)
end
end,
ok.
@@ -1024,6 +1029,13 @@ mult_lib_remove_prefix([H|T1], [H|T2]) ->
mult_lib_remove_prefix([$/|T], []) -> T.
bad_erl_libs(Config) when is_list(Config) ->
+ %% Preserve ERL_LIBS if set.
+ BadLibs0 = "/no/such/dir",
+ BadLibs =
+ case os:getenv("ERL_LIBS") of
+ false -> BadLibs0;
+ Libs -> BadLibs0 ++ ":" ++ Libs
+ end,
{ok,Node} =
test_server:start_node(bad_erl_libs, slave, []),
Code = rpc:call(Node,code,get_path,[]),
@@ -1031,10 +1043,9 @@ bad_erl_libs(Config) when is_list(Config) ->
{ok,Node2} =
test_server:start_node(bad_erl_libs, slave,
- [{args,"-env ERL_LIBS /no/such/dir"}]),
+ [{args,"-env ERL_LIBS " ++ BadLibs}]),
Code2 = rpc:call(Node,code,get_path,[]),
test_server:stop_node(Node2),
-
%% Test that code path is not affected by the faulty ERL_LIBS
Code = Code2,
@@ -1553,6 +1564,11 @@ on_load_update_code_1(3, Mod) ->
%% Test -on_load while trace feature 'on_load' is enabled (OTP-14612)
on_load_trace_on_load(Config) ->
+ %% 'on_load' enables tracing for all newly loaded modules, so we make a dry
+ %% run to ensure that ancillary modules like 'merl' won't be loaded during
+ %% the actual test.
+ on_load_update(Config),
+
Papa = self(),
Tracer = spawn_link(fun F() -> receive M -> Papa ! M end, F() end),
{tracer,[]} = erlang:trace_info(self(),tracer),
diff --git a/lib/kernel/test/disk_log_SUITE.erl b/lib/kernel/test/disk_log_SUITE.erl
index 12e2521939..9704c3b28c 100644
--- a/lib/kernel/test/disk_log_SUITE.erl
+++ b/lib/kernel/test/disk_log_SUITE.erl
@@ -89,8 +89,6 @@
dist_terminate/1, dist_accessible/1, dist_deadlock/1,
dist_open2/1, other_groups/1,
- evil/1,
-
otp_6278/1, otp_10131/1]).
-export([head_fun/1, hf/0, lserv/1,
@@ -123,7 +121,7 @@
[halt_int, wrap_int, halt_ext, wrap_ext, read_mode, head,
notif, new_idx_vsn, reopen, block, unblock, open, close,
error, chunk, truncate, many_users, info, change_size,
- change_attribute, distribution, evil, otp_6278, otp_10131]).
+ change_attribute, distribution, otp_6278, otp_10131]).
%% These test cases should be skipped if the VxWorks card is
%% configured without NFS cache.
@@ -149,7 +147,7 @@ all() ->
{group, open}, {group, close}, {group, error}, chunk,
truncate, many_users, {group, info},
{group, change_size}, change_attribute,
- {group, distribution}, evil, otp_6278, otp_10131].
+ {group, distribution}, otp_6278, otp_10131].
groups() ->
[{halt_int, [], [halt_int_inf, {group, halt_int_sz}]},
@@ -1752,7 +1750,7 @@ block_queue(Conf) when is_list(Conf) ->
true = [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f},{7,g},{8,h}] == Terms,
del(File, 2),
Q = qlen(),
- true = (P0 == pps()),
+ check_pps(P0),
ok.
%% OTP-4880. Blocked processes did not get disk_log_stopped message.
@@ -1784,7 +1782,7 @@ block_queue2(Conf) when is_list(Conf) ->
{ok,<<>>} = file:read_file(File ++ ".1"),
del(File, No),
Q = qlen(),
- true = (P0 == pps()),
+ check_pps(P0),
ok.
@@ -2121,7 +2119,7 @@ close_block(Conf) when is_list(Conf) ->
0 = sync_do(Pid2, users),
sync_do(Pid2, terminate),
{error, no_such_log} = disk_log:info(n),
- true = (P0 == pps()),
+ check_pps(P0),
%% Users terminate (no link...).
Pid3 = spawn_link(?MODULE, lserv, [n]),
@@ -2139,7 +2137,7 @@ close_block(Conf) when is_list(Conf) ->
disk_log:close(n),
disk_log:close(n),
{error, no_such_log} = disk_log:info(n),
- true = (P0 == pps()),
+ check_pps(P0),
%% Blocking owner terminates.
Pid5 = spawn_link(?MODULE, lserv, [n]),
@@ -2156,7 +2154,7 @@ close_block(Conf) when is_list(Conf) ->
1 = users(n),
ok = disk_log:close(n),
{error, no_such_log} = disk_log:info(n),
- true = (P0 == pps()),
+ check_pps(P0),
%% Blocking user terminates.
Pid6 = spawn_link(?MODULE, lserv, [n]),
@@ -2176,7 +2174,7 @@ close_block(Conf) when is_list(Conf) ->
1 = users(n),
ok = disk_log:close(n),
{error, no_such_log} = disk_log:info(n),
- true = (P0 == pps()),
+ check_pps(P0),
%% Blocking owner terminates.
Pid7 = spawn_link(?MODULE, lserv, [n]),
@@ -2194,7 +2192,7 @@ close_block(Conf) when is_list(Conf) ->
1 = users(n),
ok = disk_log:close(n),
{error, no_such_log} = disk_log:info(n),
- true = (P0 == pps()),
+ check_pps(P0),
%% Two owners, the blocking one terminates.
Pid8 = spawn_link(?MODULE, lserv, [n]),
@@ -2209,7 +2207,7 @@ close_block(Conf) when is_list(Conf) ->
0 = sync_do(Pid9, users),
sync_do(Pid9, terminate),
{error, no_such_log} = disk_log:info(n),
- true = (P0 == pps()),
+ check_pps(P0),
%% Blocking user closes.
Pid10 = spawn_link(?MODULE, lserv, [n]),
@@ -2227,7 +2225,7 @@ close_block(Conf) when is_list(Conf) ->
ok = disk_log:close(n),
sync_do(Pid10, terminate),
{error, no_such_log} = disk_log:info(n),
- true = (P0 == pps()),
+ check_pps(P0),
%% Blocking user unblocks and closes.
Pid11 = spawn_link(?MODULE, lserv, [n]),
@@ -2246,7 +2244,7 @@ close_block(Conf) when is_list(Conf) ->
ok = disk_log:close(n),
{error, no_such_log} = disk_log:info(n),
sync_do(Pid11, terminate),
- true = (P0 == pps()),
+ check_pps(P0),
%% Blocking owner closes.
Pid12 = spawn_link(?MODULE, lserv, [n]),
@@ -2265,7 +2263,7 @@ close_block(Conf) when is_list(Conf) ->
ok = disk_log:close(n),
{error, no_such_log} = disk_log:info(n),
sync_do(Pid12, terminate),
- true = (P0 == pps()),
+ check_pps(P0),
%% Blocking owner unblocks and closes.
Pid13 = spawn_link(?MODULE, lserv, [n]),
@@ -2285,7 +2283,7 @@ close_block(Conf) when is_list(Conf) ->
ok = disk_log:close(n),
{error, no_such_log} = disk_log:info(n),
sync_do(Pid13, terminate),
- true = (P0 == pps()),
+ check_pps(P0),
del(File, No), % cleanup
ok.
@@ -2489,7 +2487,7 @@ error_repair(Conf) when is_list(Conf) ->
P0 = pps(),
{error, {file_error, _, _}} =
disk_log:open([{name, n}, {file, File}, {type, wrap}, {size,{40,4}}]),
- true = (P0 == pps()),
+ check_pps(P0),
del(File, No),
ok = file:del_dir(Dir),
@@ -2508,7 +2506,7 @@ error_repair(Conf) when is_list(Conf) ->
disk_log:open([{name, n}, {file, File}, {type, wrap},
{format, internal}, {size, {40,No}}]),
ok = disk_log:close(n),
- true = (P1 == pps()),
+ check_pps(P1),
del(File, No),
receive {info_msg, _, "disk_log: repairing" ++ _, _} -> ok
after 1000 -> ct:fail(failed) end,
@@ -2526,7 +2524,7 @@ error_repair(Conf) when is_list(Conf) ->
disk_log:open([{name, n}, {file, File}, {type, wrap},
{format, internal}, {size, {4000,No}}]),
ok = disk_log:close(n),
- true = (P2 == pps()),
+ check_pps(P2),
del(File, No),
receive {info_msg, _, "disk_log: repairing" ++ _, _} -> ok
after 1000 -> ct:fail(failed) end,
@@ -2635,7 +2633,7 @@ error_log(Conf) when is_list(Conf) ->
{ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap},
{format, external},{size, {100, No}}]),
{error, {file_error, _, _}} = disk_log:truncate(n),
- true = (P0 == pps()),
+ check_pps(P0),
del(File, No),
%% OTP-4880.
@@ -2643,7 +2641,7 @@ error_log(Conf) when is_list(Conf) ->
{ok, n} = disk_log:open([{name, n}, {file, File}, {type, halt},
{format, external},{size, 100000}]),
{error, {file_error, _, eisdir}} = disk_log:reopen(n, LDir),
- true = (P0 == pps()),
+ check_pps(P0),
file:delete(File),
B = mk_bytes(60),
@@ -3005,7 +3003,7 @@ error_index(Conf) when is_list(Conf) ->
{error, {invalid_index_file, _}} = disk_log:open(Args),
del(File, No),
- true = (P0 == pps()),
+ check_pps(P0),
true = (Q == qlen()),
ok.
@@ -4438,7 +4436,7 @@ dist_open2(Conf) when is_list(Conf) ->
timer:sleep(500),
file:delete(File),
- true = (P0 == pps()),
+ check_pps(P0),
%% This time the first process has a naughty head_func. This test
%% does not add very much. Perhaps it should be removed. However,
@@ -4484,7 +4482,7 @@ dist_open2(Conf) when is_list(Conf) ->
timer:sleep(100),
{error, no_such_log} = disk_log:close(Log),
file:delete(File),
- true = (P0 == pps()),
+ check_pps(P0),
No = 2,
Log2 = n2,
@@ -4513,7 +4511,7 @@ dist_open2(Conf) when is_list(Conf) ->
file:delete(File2),
del(File, No),
- true = (P0 == pps()),
+ check_pps(P0),
R.
@@ -4558,7 +4556,7 @@ dist_open2_1(Conf, Delay) ->
{error, no_such_log} = disk_log:info(Log),
file:delete(File),
- true = (P0 == pps()),
+ check_pps(P0),
ok.
@@ -4615,7 +4613,7 @@ dist_open2_2(Conf, Delay) ->
{[{Node1,{repaired,_,_,_}}],[]}} -> ok
end,
- true = (P0 == pps()),
+ check_pps(P0),
stop_node(Node1),
file:delete(File),
ok.
@@ -4676,119 +4674,6 @@ other_groups(Conf) when is_list(Conf) ->
ok.
--define(MAX, ?MAX_FWRITE_CACHE). % as in disk_log_1.erl
-%% Evil cases such as closed file descriptor port.
-evil(Conf) when is_list(Conf) ->
- Dir = ?privdir(Conf),
- File = filename:join(Dir, "n.LOG"),
- Log = n,
-
- %% Not a very thorough test.
-
- ok = setup_evil_filled_cache_wrap(Log, Dir),
- {error, {file_error,_,einval}} = disk_log:log(Log, apa),
- ok = disk_log:close(Log),
-
- ok = setup_evil_filled_cache_halt(Log, Dir),
- {error, {file_error,_,einval}} = disk_log:truncate(Log, apa),
- ok = stop_evil(Log),
-
- %% White box test.
- file:delete(File),
- Ports0 = erlang:ports(),
- {ok, Log} = disk_log:open([{name,Log},{file,File},{type,halt},
- {size,?MAX+50},{format,external}]),
- [Fd] = erlang:ports() -- Ports0,
- {B,_} = x_mk_bytes(30),
- ok = disk_log:blog(Log, <<0:(?MAX-1)/unit:8>>),
- exit(Fd, kill),
- {error, {file_error,_,einval}} = disk_log:blog_terms(Log, [B,B]),
- ok= disk_log:close(Log),
- file:delete(File),
-
- ok = setup_evil_wrap(Log, Dir),
- {error, {file_error,_,einval}} = disk_log:close(Log),
-
- ok = setup_evil_wrap(Log, Dir),
- {error, {file_error,_,einval}} = disk_log:log(Log, apa),
- ok = stop_evil(Log),
-
- ok = setup_evil_halt(Log, Dir),
- {error, {file_error,_,einval}} = disk_log:log(Log, apa),
- ok = stop_evil(Log),
-
- ok = setup_evil_wrap(Log, Dir),
- {error, {file_error,_,einval}} = disk_log:reopen(Log, apa),
- {error, {file_error,_,einval}} = disk_log:reopen(Log, apa),
- ok = stop_evil(Log),
-
- ok = setup_evil_wrap(Log, Dir),
- {error, {file_error,_,einval}} = disk_log:reopen(Log, apa),
- ok = stop_evil(Log),
-
- ok = setup_evil_wrap(Log, Dir),
- {error, {file_error,_,einval}} = disk_log:inc_wrap_file(Log),
- ok = stop_evil(Log),
-
- ok = setup_evil_wrap(Log, Dir),
- {error, {file_error,_,einval}} = disk_log:chunk(Log, start),
- ok = stop_evil(Log),
-
- ok = setup_evil_wrap(Log, Dir),
- {error, {file_error,_,einval}} = disk_log:truncate(Log),
- ok = stop_evil(Log),
-
- ok = setup_evil_wrap(Log, Dir),
- {error, {file_error,_,einval}} = disk_log:chunk_step(Log, start, 1),
- ok = stop_evil(Log),
-
- io:format("messages: ~p~n", [erlang:process_info(self(), messages)]),
- del(File, 2),
- file:delete(File),
- ok.
-
-setup_evil_wrap(Log, Dir) ->
- setup_evil(Log, [{type,wrap},{size,{100,2}}], Dir).
-
-setup_evil_halt(Log, Dir) ->
- setup_evil(Log, [{type,halt},{size,10000}], Dir).
-
-setup_evil(Log, Args, Dir) ->
- File = filename:join(Dir, lists:concat([Log, ".LOG"])),
- file:delete(File),
- del(File, 2),
- ok = disk_log:start(),
- Ports0 = erlang:ports(),
- {ok, Log} = disk_log:open([{name,Log},{file,File} | Args]),
- [Fd] = erlang:ports() -- Ports0,
- exit(Fd, kill),
- ok = disk_log:log_terms(n, [<<0:10/unit:8>>]),
- timer:sleep(2500), % TIMEOUT in disk_log_1.erl is 2000
- ok.
-
-stop_evil(Log) ->
- {error, _} = disk_log:close(Log),
- ok.
-
-setup_evil_filled_cache_wrap(Log, Dir) ->
- setup_evil_filled_cache(Log, [{type,wrap},{size,{?MAX,2}}], Dir).
-
-setup_evil_filled_cache_halt(Log, Dir) ->
- setup_evil_filled_cache(Log, [{type,halt},{size,infinity}], Dir).
-
-%% The cache is filled, and the file descriptor port gone.
-setup_evil_filled_cache(Log, Args, Dir) ->
- File = filename:join(Dir, lists:concat([Log, ".LOG"])),
- file:delete(File),
- del(File, 2),
- ok = disk_log:start(),
- Ports0 = erlang:ports(),
- {ok, Log} = disk_log:open([{name,Log},{file,File} | Args]),
- [Fd] = erlang:ports() -- Ports0,
- ok = disk_log:log_terms(n, [<<0:?MAX/unit:8>>]),
- exit(Fd, kill),
- ok.
-
%% OTP-6278. open/1 creates no status or crash report.
otp_6278(Conf) when is_list(Conf) ->
Dir = ?privdir(Conf),
@@ -4906,10 +4791,59 @@ log(Name, N) ->
format_error(E) ->
lists:flatten(disk_log:format_error(E)).
+check_pps({Ports0,Procs0} = P0) ->
+ case pps() of
+ P0 ->
+ ok;
+ _ ->
+ timer:sleep(500),
+ case pps() of
+ P0 ->
+ ok;
+ {Ports1,Procs1} = P1 ->
+ case {Ports1 -- Ports0, Procs1 -- Procs0} of
+ {[], []} -> ok;
+ {PortsDiff,ProcsDiff} ->
+ io:format("failure, got ~p~n, expected ~p\n", [P1, P0]),
+ show("Old port", Ports0 -- Ports1),
+ show("New port", PortsDiff),
+ show("Old proc", Procs0 -- Procs1),
+ show("New proc", ProcsDiff),
+ ct:fail(failed)
+ end
+ end
+ end.
+
+show(_S, []) ->
+ ok;
+show(S, [{Pid, Name, InitCall}|Pids]) when is_pid(Pid) ->
+ io:format("~s: ~w (~w), ~w: ~p~n",
+ [S, Pid, proc_reg_name(Name), InitCall,
+ erlang:process_info(Pid)]),
+ show(S, Pids);
+show(S, [{Port, _}|Ports]) when is_port(Port)->
+ io:format("~s: ~w: ~p~n", [S, Port, erlang:port_info(Port)]),
+ show(S, Ports).
+
pps() ->
timer:sleep(100),
- {erlang:ports(), lists:filter(fun(P) -> erlang:is_process_alive(P) end,
- processes())}.
+ {port_list(), process_list()}.
+
+port_list() ->
+ [{P,safe_second_element(erlang:port_info(P, name))} ||
+ P <- erlang:ports()].
+
+process_list() ->
+ [{P,process_info(P, registered_name),
+ safe_second_element(process_info(P, initial_call))} ||
+ P <- processes(), erlang:is_process_alive(P)].
+
+proc_reg_name({registered_name, Name}) -> Name;
+proc_reg_name([]) -> no_reg_name.
+
+safe_second_element({_,Info}) -> Info;
+safe_second_element(Other) -> Other.
+
qlen() ->
{_, {_, N}} = lists:keysearch(message_queue_len, 1, process_info(self())),
diff --git a/lib/kernel/test/erl_distribution_SUITE.erl b/lib/kernel/test/erl_distribution_SUITE.erl
index e34b4d77d2..c3a022df0a 100644
--- a/lib/kernel/test/erl_distribution_SUITE.erl
+++ b/lib/kernel/test/erl_distribution_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
init_per_group/2,end_per_group/2]).
-export([tick/1, tick_change/1,
+ connect_node/1,
nodenames/1, hostnames/1,
illegal_nodenames/1, hidden_node/1,
setopts/1,
@@ -39,7 +40,8 @@
monitor_nodes_errors/1,
monitor_nodes_combinations/1,
monitor_nodes_cleanup/1,
- monitor_nodes_many/1]).
+ monitor_nodes_many/1,
+ dist_ctrl_proc_smoke/1]).
%% Performs the test at another node.
-export([get_socket_priorities/0,
@@ -51,7 +53,7 @@
-export([init_per_testcase/2, end_per_testcase/2]).
--export([start_node/2]).
+-export([dist_cntrlr_output_test/2]).
-export([pinger/1]).
@@ -66,10 +68,12 @@
suite() ->
[{ct_hooks,[ts_install_cth]},
- {timetrap,{minutes,4}}].
+ {timetrap,{minutes,12}}].
all() ->
- [tick, tick_change, nodenames, hostnames, illegal_nodenames,
+ [dist_ctrl_proc_smoke,
+ tick, tick_change, nodenames, hostnames, illegal_nodenames,
+ connect_node,
hidden_node, setopts,
table_waste, net_setuptime, inet_dist_options_options,
{group, monitor_nodes}].
@@ -87,6 +91,7 @@ init_per_suite(Config) ->
Config.
end_per_suite(_Config) ->
+ [slave:stop(N) || N <- nodes()],
ok.
init_per_group(_GroupName, Config) ->
@@ -106,11 +111,19 @@ init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) ->
end_per_testcase(_Func, _Config) ->
ok.
+connect_node(Config) when is_list(Config) ->
+ Connected = nodes(connected),
+ true = net_kernel:connect_node(node()),
+ Connected = nodes(connected),
+ ok.
+
tick(Config) when is_list(Config) ->
- PaDir = filename:dirname(code:which(erl_distribution_SUITE)),
+ run_dist_configs(fun tick/2, Config).
+tick(DCfg, _Config) ->
%% First check that the normal case is OK!
- {ok, Node} = start_node(dist_test, "-pa " ++ PaDir),
+ [Name1, Name2] = get_nodenames(2, dist_test),
+ {ok, Node} = start_node(DCfg, Name1),
rpc:call(Node, erl_distribution_SUITE, tick_cli_test, [node()]),
erlang:monitor_node(Node, true),
@@ -134,14 +147,12 @@ tick(Config) when is_list(Config) ->
%% Set the ticktime on the server node to 100 secs so the server
%% node doesn't tick the client node within the interval ...
- {ok, ServNode} = start_node(dist_test_server,
- "-kernel net_ticktime 100 "
- "-pa " ++ PaDir),
+ {ok, ServNode} = start_node(DCfg, Name2,
+ "-kernel net_ticktime 100"),
rpc:call(ServNode, erl_distribution_SUITE, tick_serv_test, [Node, node()]),
- {ok, _} = start_node(dist_test,
- "-kernel net_ticktime 12 "
- "-pa " ++ PaDir),
+ {ok, Node} = start_node(DCfg, Name1,
+ "-kernel net_ticktime 12"),
rpc:call(Node, erl_distribution_SUITE, tick_cli_test, [ServNode]),
spawn_link(erl_distribution_SUITE, keep_conn, [Node]),
@@ -171,6 +182,9 @@ tick(Config) when is_list(Config) ->
%% Checks that pinging nonexistyent nodes does not waste space in distribution table.
table_waste(Config) when is_list(Config) ->
+ run_dist_configs(fun table_waste/2, Config).
+
+table_waste(DCfg, _Config) ->
{ok, HName} = inet:gethostname(),
F = fun(0,_F) -> [];
(N,F) ->
@@ -180,7 +194,7 @@ table_waste(Config) when is_list(Config) ->
F(N-1,F)
end,
F(256,F),
- {ok, N} = start_node(erl_distribution_300,""),
+ {ok, N} = start_node(DCfg, erl_distribution_300),
stop_node(N),
ok.
@@ -191,6 +205,9 @@ nodenames(Config) when is_list(Config) ->
legal("a-1@b"),
legal("a_1@b"),
+ %% Test that giving two -sname works as it should
+ test_node("a_1@b", false, long_or_short() ++ "a_0@b"),
+
illegal("cdé@a"),
illegal("te欢st@a").
@@ -244,8 +261,11 @@ illegal(Name) ->
test_node(Name) ->
test_node(Name, false).
test_node(Name, Illigal) ->
- ProgName = atom_to_list(lib:progname()),
- Command = ProgName ++ " -noinput " ++ long_or_short() ++ Name ++
+ test_node(Name, Illigal, "").
+test_node(Name, Illigal, ExtraArgs) ->
+ ProgName = ct:get_progname(),
+ Command = ProgName ++ " -noinput " ++ ExtraArgs ++
+ long_or_short() ++ Name ++
" -eval \"net_adm:ping('" ++ atom_to_list(node()) ++ "')\"" ++
case Illigal of
true ->
@@ -286,13 +306,16 @@ gethostname() ->
%% Test that pinging an illegal nodename does not kill the node.
illegal_nodenames(Config) when is_list(Config) ->
- PaDir = filename:dirname(code:which(erl_distribution_SUITE)),
- {ok, Node}=start_node(illegal_nodenames, "-pa " ++ PaDir),
+ run_dist_configs(fun illegal_nodenames/2, Config).
+
+illegal_nodenames(DCfg, _Config) ->
+ {ok, Node}=start_node(DCfg, illegal_nodenames),
monitor_node(Node, true),
RPid=rpc:call(Node, erlang, spawn,
[?MODULE, pinger, [self()]]),
receive
{RPid, pinged} ->
+ monitor_node(Node, false),
ok;
{nodedown, Node} ->
ct:fail("Remote node died.")
@@ -309,22 +332,25 @@ pinger(Starter) ->
%% Test that you can set the net_setuptime properly.
net_setuptime(Config) when is_list(Config) ->
+ run_dist_configs(fun net_setuptime/2, Config).
+
+net_setuptime(DCfg, _Config) ->
+
%% In this test case, we reluctantly accept shorter times than the given
%% setup time, because the connection attempt can end in a
%% "Host unreachable" error before the timeout fires.
- Res0 = do_test_setuptime("2"),
+ Res0 = do_test_setuptime(DCfg, "2"),
io:format("Res0 = ~p", [Res0]),
true = (Res0 =< 4000),
- Res1 = do_test_setuptime("0.3"),
+ Res1 = do_test_setuptime(DCfg, "0.3"),
io:format("Res1 = ~p", [Res1]),
true = (Res1 =< 500),
ok.
-do_test_setuptime(Setuptime) when is_list(Setuptime) ->
- PaDir = filename:dirname(code:which(?MODULE)),
- {ok, Node} = start_node(dist_setuptime_test, "-pa " ++ PaDir ++
- " -kernel net_setuptime " ++ Setuptime),
+do_test_setuptime(DCfg, Setuptime) when is_list(Setuptime) ->
+ {ok, Node} = start_node(DCfg, dist_setuptime_test,
+ "-kernel net_setuptime " ++ Setuptime),
Res = rpc:call(Node,?MODULE,time_ping,[?DUMMY_NODE]),
stop_node(Node),
Res.
@@ -390,32 +416,36 @@ tick_cli_test1(Node) ->
end.
setopts(Config) when is_list(Config) ->
+ run_dist_configs(fun setopts/2, Config).
+
+setopts(DCfg, _Config) ->
register(setopts_regname, self()),
[N1,N2,N3,N4] = get_nodenames(4, setopts),
- {_N1F,Port1} = start_node_unconnected(N1, ?MODULE, run_remote_test,
+ {_N1F,Port1} = start_node_unconnected(DCfg, N1, ?MODULE, run_remote_test,
["setopts_do", atom_to_list(node()), "1", "ping"]),
0 = wait_for_port_exit(Port1),
- {_N2F,Port2} = start_node_unconnected(N2, ?MODULE, run_remote_test,
+ {_N2F,Port2} = start_node_unconnected(DCfg, N2, ?MODULE, run_remote_test,
["setopts_do", atom_to_list(node()), "2", "ping"]),
0 = wait_for_port_exit(Port2),
{ok, LSock} = gen_tcp:listen(0, [{packet,2}, {active,false}]),
{ok, LTcpPort} = inet:port(LSock),
- {N3F,Port3} = start_node_unconnected(N3, ?MODULE, run_remote_test,
+ {N3F,Port3} = start_node_unconnected(DCfg, N3, ?MODULE, run_remote_test,
["setopts_do", atom_to_list(node()),
"1", integer_to_list(LTcpPort)]),
wait_and_connect(LSock, N3F, Port3),
0 = wait_for_port_exit(Port3),
- {N4F,Port4} = start_node_unconnected(N4, ?MODULE, run_remote_test,
+ {N4F,Port4} = start_node_unconnected(DCfg, N4, ?MODULE, run_remote_test,
["setopts_do", atom_to_list(node()),
"2", integer_to_list(LTcpPort)]),
wait_and_connect(LSock, N4F, Port4),
0 = wait_for_port_exit(Port4),
+ unregister(setopts_regname),
ok.
wait_and_connect(LSock, NodeName, NodePort) ->
@@ -463,9 +493,9 @@ run_remote_test([FuncStr, TestNodeStr | Args]) ->
1
end
catch
- C:E ->
+ C:E:S ->
io:format("Node ~p got EXCEPTION ~p:~p\nat ~p\n",
- [node(), C, E, erlang:get_stacktrace()]),
+ [node(), C, E, S]),
2
end,
io:format("Node ~p doing halt(~p).\n",[node(), Status]),
@@ -509,9 +539,9 @@ opt_from_nr("2") -> {nodelay, false}.
change_val(true) -> false;
change_val(false) -> true.
-start_node_unconnected(Name, Mod, Func, Args) ->
+start_node_unconnected(DCfg, Name, Mod, Func, Args) ->
FullName = full_node_name(Name),
- CmdLine = mk_node_cmdline(Name,Mod,Func,Args),
+ CmdLine = mk_node_cmdline(DCfg, Name,Mod,Func,Args),
io:format("Starting node ~p: ~s~n", [FullName, CmdLine]),
case open_port({spawn, CmdLine}, [exit_status]) of
Port when is_port(Port) ->
@@ -525,7 +555,7 @@ full_node_name(PreName) ->
atom_to_list(node())),
list_to_atom(atom_to_list(PreName) ++ HostSuffix).
-mk_node_cmdline(Name,Mod,Func,Args) ->
+mk_node_cmdline(DCfg, Name,Mod,Func,Args) ->
Static = "-noinput",
Pa = filename:dirname(code:which(?MODULE)),
Prog = case catch init:get_argument(progname) of
@@ -542,6 +572,7 @@ mk_node_cmdline(Name,Mod,Func,Args) ->
Prog ++ " "
++ Static ++ " "
++ NameSw ++ " " ++ NameStr
+ ++ " " ++ DCfg
++ " -pa " ++ Pa
++ " -env ERL_CRASH_DUMP " ++ Pwd ++ "/erl_crash_dump." ++ NameStr
++ " -setcookie " ++ atom_to_list(erlang:get_cookie())
@@ -551,7 +582,9 @@ mk_node_cmdline(Name,Mod,Func,Args) ->
%% OTP-4255.
tick_change(Config) when is_list(Config) ->
- PaDir = filename:dirname(code:which(?MODULE)),
+ run_dist_configs(fun tick_change/2, Config).
+
+tick_change(DCfg, _Config) ->
[BN, CN] = get_nodenames(2, tick_change),
DefaultTT = net_kernel:get_net_ticktime(),
unchanged = net_kernel:set_net_ticktime(DefaultTT, 60),
@@ -568,14 +601,13 @@ tick_change(Config) when is_list(Config) ->
end,
wait_until(fun () -> 10 == net_kernel:get_net_ticktime() end),
- {ok, B} = start_node(BN, "-kernel net_ticktime 10 -pa " ++ PaDir),
- {ok, C} = start_node(CN, "-kernel net_ticktime 10 -hidden -pa "
- ++ PaDir),
+ {ok, B} = start_node(DCfg, BN, "-kernel net_ticktime 10"),
+ {ok, C} = start_node(DCfg, CN, "-kernel net_ticktime 10 -hidden"),
OTE = process_flag(trap_exit, true),
case catch begin
- run_tick_change_test(B, C, 10, 1, PaDir),
- run_tick_change_test(B, C, 1, 10, PaDir)
+ run_tick_change_test(DCfg, B, C, 10, 1),
+ run_tick_change_test(DCfg, B, C, 1, 10)
end of
{'EXIT', Reason} ->
stop_node(B),
@@ -617,7 +649,7 @@ wait_for_nodedowns(Tester, Ref) ->
end,
wait_for_nodedowns(Tester, Ref).
-run_tick_change_test(B, C, PrevTT, TT, PaDir) ->
+run_tick_change_test(DCfg, B, C, PrevTT, TT) ->
[DN, EN] = get_nodenames(2, tick_change),
Tester = self(),
@@ -631,8 +663,8 @@ run_tick_change_test(B, C, PrevTT, TT, PaDir) ->
wait_for_nodedowns(Tester, Ref)
end,
- {ok, D} = start_node(DN, "-kernel net_ticktime "
- ++ integer_to_list(PrevTT) ++ " -pa " ++ PaDir),
+ {ok, D} = start_node(DCfg, DN, "-kernel net_ticktime "
+ ++ integer_to_list(PrevTT)),
NMA = spawn_link(fun () -> MonitorNodes([B, C, D]) end),
NMB = spawn_link(B, fun () -> MonitorNodes([node(), C, D]) end),
@@ -665,8 +697,8 @@ run_tick_change_test(B, C, PrevTT, TT, PaDir) ->
sleep(7),
change_initiated = rpc:call(C,net_kernel,set_net_ticktime,[TT,10]),
- {ok, E} = start_node(EN, "-kernel net_ticktime "
- ++ integer_to_list(TT) ++ " -pa " ++ PaDir),
+ {ok, E} = start_node(DCfg, EN, "-kernel net_ticktime "
+ ++ integer_to_list(TT)),
NME = spawn_link(E, fun () -> MonitorNodes([node(), B, C, D]) end),
NMA2 = spawn_link(fun () -> MonitorNodes([E]) end),
NMB2 = spawn_link(B, fun () -> MonitorNodes([E]) end),
@@ -726,12 +758,13 @@ run_tick_change_test(B, C, PrevTT, TT, PaDir) ->
%%
%% Basic test of hidden node.
hidden_node(Config) when is_list(Config) ->
- PaDir = filename:dirname(code:which(?MODULE)),
- VArgs = "-pa " ++ PaDir,
- HArgs = "-hidden -pa " ++ PaDir,
- {ok, V} = start_node(visible_node, VArgs),
+ run_dist_configs(fun hidden_node/2, Config).
+
+hidden_node(DCfg, _Config) ->
+ HArgs = "-hidden",
+ {ok, V} = start_node(DCfg, visible_node),
VMN = start_monitor_nodes_proc(V),
- {ok, H} = start_node(hidden_node, HArgs),
+ {ok, H} = start_node(DCfg, hidden_node, HArgs),
%% Connect visible_node -> hidden_node
connect_nodes(V, H),
test_nodes(V, H),
@@ -739,9 +772,9 @@ hidden_node(Config) when is_list(Config) ->
sleep(5),
check_monitor_nodes_res(VMN, H),
stop_node(V),
- {ok, H} = start_node(hidden_node, HArgs),
+ {ok, H} = start_node(DCfg, hidden_node, HArgs),
HMN = start_monitor_nodes_proc(H),
- {ok, V} = start_node(visible_node, VArgs),
+ {ok, V} = start_node(DCfg, visible_node),
%% Connect hidden_node -> visible_node
connect_nodes(H, V),
test_nodes(V, H),
@@ -841,9 +874,9 @@ do_inet_dist_options_options(Prio) ->
"-kernel inet_dist_connect_options "++PriorityString++" "
"-kernel inet_dist_listen_options "++PriorityString,
{ok,Node1} =
- start_node(inet_dist_options_1, InetDistOptions),
+ start_node("", inet_dist_options_1, InetDistOptions),
{ok,Node2} =
- start_node(inet_dist_options_2, InetDistOptions),
+ start_node("", inet_dist_options_2, InetDistOptions),
%%
pong =
rpc:call(Node1, net_adm, ping, [Node2]),
@@ -876,6 +909,9 @@ get_socket_priorities() ->
%%
monitor_nodes_nodedown_reason(Config) when is_list(Config) ->
+ run_dist_configs(fun monitor_nodes_nodedown_reason/2, Config).
+
+monitor_nodes_nodedown_reason(DCfg, _Config) ->
MonNodeState = monitor_node_state(),
ok = net_kernel:monitor_nodes(true),
ok = net_kernel:monitor_nodes(true, [nodedown_reason]),
@@ -883,10 +919,10 @@ monitor_nodes_nodedown_reason(Config) when is_list(Config) ->
Names = get_numbered_nodenames(5, node),
[NN1, NN2, NN3, NN4, NN5] = Names,
- {ok, N1} = start_node(NN1),
- {ok, N2} = start_node(NN2),
- {ok, N3} = start_node(NN3),
- {ok, N4} = start_node(NN4, "-hidden"),
+ {ok, N1} = start_node(DCfg, NN1),
+ {ok, N2} = start_node(DCfg, NN2),
+ {ok, N3} = start_node(DCfg, NN3),
+ {ok, N4} = start_node(DCfg, NN4, "-hidden"),
receive {nodeup, N1} -> ok end,
receive {nodeup, N2} -> ok end,
@@ -916,7 +952,7 @@ monitor_nodes_nodedown_reason(Config) when is_list(Config) ->
ok = net_kernel:monitor_nodes(false, [nodedown_reason]),
- {ok, N5} = start_node(NN5),
+ {ok, N5} = start_node(DCfg, NN5),
stop_node(N5),
receive {nodeup, N5} -> ok end,
@@ -929,11 +965,14 @@ monitor_nodes_nodedown_reason(Config) when is_list(Config) ->
monitor_nodes_complex_nodedown_reason(Config) when is_list(Config) ->
+ run_dist_configs(fun monitor_nodes_complex_nodedown_reason/2, Config).
+
+monitor_nodes_complex_nodedown_reason(DCfg, _Config) ->
MonNodeState = monitor_node_state(),
Me = self(),
ok = net_kernel:monitor_nodes(true, [nodedown_reason]),
[Name] = get_nodenames(1, monitor_nodes_complex_nodedown_reason),
- {ok, Node} = start_node(Name, ""),
+ {ok, Node} = start_node(DCfg, Name, ""),
Pid = spawn(Node,
fun() ->
Me ! {stuff,
@@ -972,16 +1011,19 @@ monitor_nodes_complex_nodedown_reason(Config) when is_list(Config) ->
%%
monitor_nodes_node_type(Config) when is_list(Config) ->
+ run_dist_configs(fun monitor_nodes_node_type/2, Config).
+
+monitor_nodes_node_type(DCfg, _Config) ->
MonNodeState = monitor_node_state(),
ok = net_kernel:monitor_nodes(true),
ok = net_kernel:monitor_nodes(true, [{node_type, all}]),
Names = get_numbered_nodenames(9, node),
[NN1, NN2, NN3, NN4, NN5, NN6, NN7, NN8, NN9] = Names,
- {ok, N1} = start_node(NN1),
- {ok, N2} = start_node(NN2),
- {ok, N3} = start_node(NN3, "-hidden"),
- {ok, N4} = start_node(NN4, "-hidden"),
+ {ok, N1} = start_node(DCfg, NN1),
+ {ok, N2} = start_node(DCfg, NN2),
+ {ok, N3} = start_node(DCfg, NN3, "-hidden"),
+ {ok, N4} = start_node(DCfg, NN4, "-hidden"),
receive {nodeup, N1} -> ok end,
receive {nodeup, N2} -> ok end,
@@ -1005,15 +1047,15 @@ monitor_nodes_node_type(Config) when is_list(Config) ->
receive {nodedown, N4, [{node_type, hidden}]} -> ok end,
ok = net_kernel:monitor_nodes(false, [{node_type, all}]),
- {ok, N5} = start_node(NN5),
+ {ok, N5} = start_node(DCfg, NN5),
receive {nodeup, N5} -> ok end,
stop_node(N5),
receive {nodedown, N5} -> ok end,
ok = net_kernel:monitor_nodes(true, [{node_type, hidden}]),
- {ok, N6} = start_node(NN6),
- {ok, N7} = start_node(NN7, "-hidden"),
+ {ok, N6} = start_node(DCfg, NN6),
+ {ok, N7} = start_node(DCfg, NN7, "-hidden"),
receive {nodeup, N6} -> ok end,
@@ -1028,8 +1070,8 @@ monitor_nodes_node_type(Config) when is_list(Config) ->
ok = net_kernel:monitor_nodes(false, [{node_type, hidden}]),
ok = net_kernel:monitor_nodes(false),
- {ok, N8} = start_node(NN8),
- {ok, N9} = start_node(NN9, "-hidden"),
+ {ok, N8} = start_node(DCfg, NN8),
+ {ok, N9} = start_node(DCfg, NN9, "-hidden"),
receive {nodeup, N8, [{node_type, visible}]} -> ok end,
stop_node(N8),
@@ -1049,6 +1091,9 @@ monitor_nodes_node_type(Config) when is_list(Config) ->
%%
monitor_nodes_misc(Config) when is_list(Config) ->
+ run_dist_configs(fun monitor_nodes_misc/2, Config).
+
+monitor_nodes_misc(DCfg, _Config) ->
MonNodeState = monitor_node_state(),
ok = net_kernel:monitor_nodes(true),
ok = net_kernel:monitor_nodes(true, [{node_type, all}, nodedown_reason]),
@@ -1056,8 +1101,8 @@ monitor_nodes_misc(Config) when is_list(Config) ->
Names = get_numbered_nodenames(3, node),
[NN1, NN2, NN3] = Names,
- {ok, N1} = start_node(NN1),
- {ok, N2} = start_node(NN2, "-hidden"),
+ {ok, N1} = start_node(DCfg, NN1),
+ {ok, N2} = start_node(DCfg, NN2, "-hidden"),
receive {nodeup, N1} -> ok end,
@@ -1083,7 +1128,7 @@ monitor_nodes_misc(Config) when is_list(Config) ->
ok = net_kernel:monitor_nodes(false, [{node_type, all}, nodedown_reason]),
- {ok, N3} = start_node(NN3),
+ {ok, N3} = start_node(DCfg, NN3),
receive {nodeup, N3} -> ok end,
stop_node(N3),
receive {nodedown, N3} -> ok end,
@@ -1098,15 +1143,18 @@ monitor_nodes_misc(Config) when is_list(Config) ->
%% messages from Node and that {nodedown, Node} messages are
%% received after messages from Node.
monitor_nodes_otp_6481(Config) when is_list(Config) ->
+ run_dist_configs(fun monitor_nodes_otp_6481/2, Config).
+
+monitor_nodes_otp_6481(DCfg, Config) ->
io:format("Testing nodedown...~n"),
- monitor_nodes_otp_6481_test(Config, nodedown),
+ monitor_nodes_otp_6481_test(DCfg, Config, nodedown),
io:format("ok~n"),
io:format("Testing nodeup...~n"),
- monitor_nodes_otp_6481_test(Config, nodeup),
+ monitor_nodes_otp_6481_test(DCfg, Config, nodeup),
io:format("ok~n"),
ok.
-monitor_nodes_otp_6481_test(Config, TestType) when is_list(Config) ->
+monitor_nodes_otp_6481_test(DCfg, Config, TestType) when is_list(Config) ->
MonNodeState = monitor_node_state(),
NodeMsg = make_ref(),
Me = self(),
@@ -1144,19 +1192,18 @@ monitor_nodes_otp_6481_test(Config, TestType) when is_list(Config) ->
TestMonNodeState = monitor_node_state(),
%% io:format("~p~n", [TestMonNodeState]),
TestMonNodeState =
- MonNodeState
+ case TestType of
+ nodedown -> [];
+ nodeup -> [{self(), []}]
+ end
+ ++ lists:map(fun (_) -> {MN, []} end, Seq)
++ case TestType of
nodedown -> [{self(), []}];
nodeup -> []
end
- ++ lists:map(fun (_) -> {MN, []} end, Seq)
- ++ case TestType of
- nodedown -> [];
- nodeup -> [{self(), []}]
- end,
-
+ ++ MonNodeState,
- {ok, Node} = start_node(Name, "", this),
+ {ok, Node} = start_node(DCfg, Name, "", this),
receive {nodeup, Node} -> ok end,
RemotePid = spawn(Node,
@@ -1241,17 +1288,20 @@ monitor_nodes_errors(Config) when is_list(Config) ->
ok.
monitor_nodes_combinations(Config) when is_list(Config) ->
+ run_dist_configs(fun monitor_nodes_combinations/2, Config).
+
+monitor_nodes_combinations(DCfg, _Config) ->
MonNodeState = monitor_node_state(),
monitor_nodes_all_comb(true),
[VisibleName, HiddenName] = get_nodenames(2,
monitor_nodes_combinations),
- {ok, Visible} = start_node(VisibleName, ""),
+ {ok, Visible} = start_node(DCfg, VisibleName, ""),
receive_all_comb_nodeup_msgs(visible, Visible),
no_msgs(),
stop_node(Visible),
receive_all_comb_nodedown_msgs(visible, Visible, connection_closed),
no_msgs(),
- {ok, Hidden} = start_node(HiddenName, "-hidden"),
+ {ok, Hidden} = start_node(DCfg, HiddenName, "-hidden"),
receive_all_comb_nodeup_msgs(hidden, Hidden),
no_msgs(),
stop_node(Hidden),
@@ -1387,6 +1437,9 @@ monitor_nodes_cleanup(Config) when is_list(Config) ->
ok.
monitor_nodes_many(Config) when is_list(Config) ->
+ run_dist_configs(fun monitor_nodes_many/2, Config).
+
+monitor_nodes_many(DCfg, _Config) ->
MonNodeState = monitor_node_state(),
[Name] = get_nodenames(1, monitor_nodes_many),
%% We want to perform more than 2^16 net_kernel:monitor_nodes
@@ -1394,7 +1447,7 @@ monitor_nodes_many(Config) when is_list(Config) ->
No = (1 bsl 16) + 17,
repeat(fun () -> ok = net_kernel:monitor_nodes(true) end, No),
No = length(monitor_node_state()) - length(MonNodeState),
- {ok, Node} = start_node(Name),
+ {ok, Node} = start_node(DCfg, Name),
repeat(fun () -> receive {nodeup, Node} -> ok end end, No),
stop_node(Node),
repeat(fun () -> receive {nodedown, Node} -> ok end end, No),
@@ -1403,8 +1456,118 @@ monitor_nodes_many(Config) when is_list(Config) ->
MonNodeState = monitor_node_state(),
ok.
+dist_ctrl_proc_smoke(Config) when is_list(Config) ->
+ ThisNode = node(),
+ [Name1, Name2] = get_nodenames(2, dist_ctrl_proc_example_smoke),
+ GetSizeArg = " -gen_tcp_dist_output_loop "
+ ++ atom_to_list(?MODULE) ++ " "
+ ++ "dist_cntrlr_output_test",
+ {ok, Node1} = start_node("", Name1, "-proto_dist gen_tcp"),
+ {ok, Node2} = start_node("", Name2, "-proto_dist gen_tcp" ++ GetSizeArg),
+ pong = rpc:call(Node1, net_adm, ping, [Node2]),
+ NL1 = lists:sort([ThisNode, Node2]),
+ NL2 = lists:sort([ThisNode, Node1]),
+ NL1 = lists:sort(rpc:call(Node1, erlang, nodes, [])),
+ NL2 = lists:sort(rpc:call(Node2, erlang, nodes, [])),
+
+ %% Verify that we actually are executing the distribution
+ %% module we expect and also massage message passing over
+ %% it a bit...
+ Ps1 = rpc:call(Node1, erlang, processes, []),
+ try
+ lists:foreach(
+ fun (P) ->
+ case rpc:call(Node1, erlang, process_info, [P, current_stacktrace]) of
+ undefined ->
+ ok;
+ {current_stacktrace, StkTrace} ->
+ lists:foreach(fun ({gen_tcp_dist,
+ dist_cntrlr_output_loop,
+ 2, _}) ->
+ io:format("~p ~p~n", [P, StkTrace]),
+ throw(found_it);
+ (_) ->
+ ok
+ end, StkTrace)
+ end
+ end, Ps1),
+ exit({missing, dist_cntrlr_output_loop})
+ catch
+ throw:found_it -> ok
+ end,
+
+ Ps2 = rpc:call(Node2, erlang, processes, []),
+ try
+ lists:foreach(
+ fun (P) ->
+ case rpc:call(Node2, erlang, process_info, [P, current_stacktrace]) of
+ undefined ->
+ ok;
+ {current_stacktrace, StkTrace} ->
+ lists:foreach(fun ({erl_distribution_SUITE,
+ dist_cntrlr_output_loop,
+ 2, _}) ->
+ io:format("~p ~p~n", [P, StkTrace]),
+ throw(found_it);
+ (_) ->
+ ok
+ end, StkTrace)
+ end
+ end, Ps2),
+ exit({missing, dist_cntrlr_output_loop})
+ catch
+ throw:found_it -> ok
+ end,
+
+ stop_node(Node1),
+ stop_node(Node2),
+ ok.
+
%% Misc. functions
+run_dist_configs(Func, Config) ->
+ GetSizeArg = " -gen_tcp_dist_output_loop "
+ ++ atom_to_list(?MODULE) ++ " "
+ ++ "dist_cntrlr_output_test",
+ lists:map(fun ({DCfgName, DCfg}) ->
+ io:format("~n~n=== Running ~s configuration ===~n~n",
+ [DCfgName]),
+ Func(DCfg, Config)
+ end,
+ [{"default", ""},
+ {"gen_tcp_dist", "-proto_dist gen_tcp"},
+ {"gen_tcp_dist (get_size)", "-proto_dist gen_tcp" ++ GetSizeArg}]).
+
+dist_cntrlr_output_test(DHandle, Socket) ->
+ false = erlang:dist_ctrl_get_opt(DHandle, get_size),
+ false = erlang:dist_ctrl_set_opt(DHandle, get_size, true),
+ true = erlang:dist_ctrl_get_opt(DHandle, get_size),
+ true = erlang:dist_ctrl_set_opt(DHandle, get_size, false),
+ false = erlang:dist_ctrl_get_opt(DHandle, get_size),
+ false = erlang:dist_ctrl_set_opt(DHandle, get_size, true),
+ true = erlang:dist_ctrl_get_opt(DHandle, get_size),
+ dist_cntrlr_output_loop(DHandle, Socket).
+
+dist_cntrlr_send_data(DHandle, Socket) ->
+ case erlang:dist_ctrl_get_data(DHandle) of
+ none ->
+ erlang:dist_ctrl_get_data_notification(DHandle);
+ {Size, Data} ->
+ Size = erlang:iolist_size(Data),
+ ok = gen_tcp:send(Socket, Data),
+ dist_cntrlr_send_data(DHandle, Socket)
+ end.
+
+dist_cntrlr_output_loop(DHandle, Socket) ->
+ receive
+ dist_data ->
+ %% Outgoing data from this node...
+ dist_cntrlr_send_data(DHandle, Socket);
+ _ ->
+ ok %% Drop garbage message...
+ end,
+ dist_cntrlr_output_loop(DHandle, Socket).
+
monitor_node_state() ->
erts_debug:set_internal_state(available_internal_state, true),
MonitoringNodes = erts_debug:get_internal_state(monitoring_nodes),
@@ -1430,25 +1593,25 @@ print_my_messages() ->
sleep(T) -> receive after T * 1000 -> ok end.
-start_node(Name, Param, this) ->
+start_node(DCfg, Name, Param, this) ->
NewParam = Param ++ " -pa " ++ filename:dirname(code:which(?MODULE)),
test_server:start_node(Name, peer, [{args, NewParam}, {erl, [this]}]);
-start_node(Name, Param, "this") ->
- NewParam = Param ++ " -pa " ++ filename:dirname(code:which(?MODULE)),
+start_node(DCfg, Name, Param, "this") ->
+ NewParam = Param ++ " -pa " ++ filename:dirname(code:which(?MODULE)) ++ " " ++ DCfg,
test_server:start_node(Name, peer, [{args, NewParam}, {erl, [this]}]);
-start_node(Name, Param, Rel) when is_atom(Rel) ->
- NewParam = Param ++ " -pa " ++ filename:dirname(code:which(?MODULE)),
+start_node(DCfg, Name, Param, Rel) when is_atom(Rel) ->
+ NewParam = Param ++ " -pa " ++ filename:dirname(code:which(?MODULE)) ++ " " ++ DCfg,
test_server:start_node(Name, peer, [{args, NewParam}, {erl, [{release, atom_to_list(Rel)}]}]);
-start_node(Name, Param, Rel) when is_list(Rel) ->
- NewParam = Param ++ " -pa " ++ filename:dirname(code:which(?MODULE)),
+start_node(DCfg, Name, Param, Rel) when is_list(Rel) ->
+ NewParam = Param ++ " -pa " ++ filename:dirname(code:which(?MODULE)) ++ " " ++ DCfg,
test_server:start_node(Name, peer, [{args, NewParam}, {erl, [{release, Rel}]}]).
-start_node(Name, Param) ->
- NewParam = Param ++ " -pa " ++ filename:dirname(code:which(?MODULE)),
+start_node(DCfg, Name, Param) ->
+ NewParam = Param ++ " -pa " ++ filename:dirname(code:which(?MODULE)) ++ " " ++ DCfg,
test_server:start_node(Name, slave, [{args, NewParam}]).
-start_node(Name) ->
- start_node(Name, "").
+start_node(DCfg, Name) ->
+ start_node(DCfg, Name, "").
stop_node(Node) ->
test_server:stop_node(Node).
diff --git a/lib/kernel/test/erl_distribution_wb_SUITE.erl b/lib/kernel/test/erl_distribution_wb_SUITE.erl
index 03aaee56b7..8256444bdc 100644
--- a/lib/kernel/test/erl_distribution_wb_SUITE.erl
+++ b/lib/kernel/test/erl_distribution_wb_SUITE.erl
@@ -61,10 +61,13 @@
%% From R9 and forward extended references is compulsory
%% From R10 and forward extended pids and ports are compulsory
%% From R20 and forward UTF8 atoms are compulsory
+%% From R21 and forward NEW_FUN_TAGS is compulsory (no more tuple fallback {fun, ...})
-define(COMPULSORY_DFLAGS, (?DFLAG_EXTENDED_REFERENCES bor
?DFLAG_EXTENDED_PIDS_PORTS bor
- ?DFLAG_UTF8_ATOMS)).
+ ?DFLAG_UTF8_ATOMS bor
+ ?DFLAG_NEW_FUN_TAGS)).
+-define(PASS_THROUGH, $p).
-define(shutdown(X), exit(X)).
-define(int16(X), [((X) bsr 8) band 16#ff, (X) band 16#ff]).
@@ -674,15 +677,16 @@ build_rex_message(Cookie,OurName) ->
%% Receive a distribution message
recv_message(Socket) ->
case gen_tcp:recv(Socket, 0) of
+ {ok,[]} ->
+ recv_message(Socket); %% a tick, ignore
{ok,Data} ->
B0 = list_to_binary(Data),
- {_,B1} = erlang:split_binary(B0,1),
- Header = binary_to_term(B1),
- Siz = byte_size(term_to_binary(Header)),
- {_,B2} = erlang:split_binary(B1,Siz),
+ <<?PASS_THROUGH, B1/binary>> = B0,
+ {Header,Siz} = binary_to_term(B1,[used]),
+ <<_:Siz/binary,B2/binary>> = B1,
Message = case (catch binary_to_term(B2)) of
{'EXIT', _} ->
- could_not_digest_message;
+ {could_not_digest_message,B2};
Other ->
Other
end,
diff --git a/lib/kernel/test/erl_prim_loader_SUITE.erl b/lib/kernel/test/erl_prim_loader_SUITE.erl
index b6417210b9..16a127aa3e 100644
--- a/lib/kernel/test/erl_prim_loader_SUITE.erl
+++ b/lib/kernel/test/erl_prim_loader_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -33,6 +33,7 @@
primary_archive/1, virtual_dir_in_archive/1,
get_modules/1]).
+-define(PRIM_FILE, prim_file).
%%-----------------------------------------------------------------
%% Test suite for erl_prim_loader. (Most code is run during system start/stop.)
@@ -461,7 +462,7 @@ primary_archive(Config) when is_list(Config) ->
%% Set primary archive
ExpectedEbins = [Archive, DictDir ++ "/ebin", DummyDir ++ "/ebin"],
io:format("ExpectedEbins: ~p\n", [ExpectedEbins]),
- {ok, FileInfo} = prim_file:read_file_info(Archive),
+ {ok, FileInfo} = ?PRIM_FILE:read_file_info(Archive),
{ok, Ebins} = rpc:call(Node, erl_prim_loader, set_primary_archive,
[Archive, ArchiveBin, FileInfo,
fun escript:parse_file/1]),
diff --git a/lib/kernel/test/error_logger_SUITE.erl b/lib/kernel/test/error_logger_SUITE.erl
index 2d26a7246c..eab72e58a7 100644
--- a/lib/kernel/test/error_logger_SUITE.erl
+++ b/lib/kernel/test/error_logger_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,7 +32,8 @@
init_per_group/2,end_per_group/2,
off_heap/1,
error_report/1, info_report/1, error/1, info/1,
- emulator/1, tty/1, logfile/1, add/1, delete/1]).
+ emulator/1, via_logger_process/1, other_node/1,
+ tty/1, logfile/1, add/1, delete/1, format_depth/1]).
-export([generate_error/2]).
@@ -46,16 +47,20 @@ suite() ->
{timetrap,{minutes,1}}].
all() ->
- [off_heap, error_report, info_report, error, info, emulator, tty,
- logfile, add, delete].
+ [off_heap, error_report, info_report, error, info, emulator,
+ via_logger_process, other_node, tty, logfile, add, delete,
+ format_depth].
groups() ->
[].
init_per_suite(Config) ->
+ logger:add_handler(error_logger,error_logger,
+ #{level=>info,filter_default=>log}),
Config.
end_per_suite(_Config) ->
+ logger:remove_handler(error_logger),
ok.
init_per_group(_GroupName, Config) ->
@@ -226,6 +231,40 @@ generate_error(Error, Stack) ->
erlang:raise(error, Error, Stack).
%%-----------------------------------------------------------------
+
+via_logger_process(Config) ->
+ case os:type() of
+ {win32,_} ->
+ {skip,"Skip on windows - cant change file mode"};
+ _ ->
+ error_logger:add_report_handler(?MODULE, self()),
+ Dir = filename:join(?config(priv_dir,Config),"dummydir"),
+ Msg = "File operation error: eacces. Target: " ++
+ Dir ++ ". Function: list_dir. ",
+ ok = file:make_dir(Dir),
+ ok = file:change_mode(Dir,8#0222),
+ error = erl_prim_loader:list_dir(Dir),
+ ok = file:change_mode(Dir,8#0664),
+ _ = file:del_dir(Dir),
+ reported(error_report, std_error, Msg),
+ my_yes = error_logger:delete_report_handler(?MODULE),
+ ok
+ end.
+
+%%-----------------------------------------------------------------
+
+other_node(_Config) ->
+ error_logger:add_report_handler(?MODULE, self()),
+ {ok,Node} = test_server:start_node(?FUNCTION_NAME,slave,[]),
+ ok = rpc:call(Node,logger,add_handler,[error_logger,error_logger,
+ #{level=>info,filter_default=>log}]),
+ rpc:call(Node,error_logger,error_report,[hi_from_remote]),
+ reported(error_report,std_error,hi_from_remote),
+ test_server:stop_node(Node),
+ ok.
+
+
+%%-----------------------------------------------------------------
%% We don't enables or disables tty error logging here. We do not
%% want to interact with the test run.
%%-----------------------------------------------------------------
@@ -271,6 +310,21 @@ delete(Config) when is_list(Config) ->
ok.
%%-----------------------------------------------------------------
+
+format_depth(_Config) ->
+ ok = application:set_env(kernel,error_logger_format_depth,30),
+ 30 = error_logger:get_format_depth(),
+ ok = application:set_env(kernel,error_logger_format_depth,3),
+ 10 = error_logger:get_format_depth(),
+ ok = application:set_env(kernel,error_logger_format_depth,11),
+ 11 = error_logger:get_format_depth(),
+ ok = application:set_env(kernel,error_logger_format_depth,unlimited),
+ unlimited = error_logger:get_format_depth(),
+ ok = application:unset_env(kernel,error_logger_format_depth),
+ unlimited = error_logger:get_format_depth(),
+ ok.
+
+%%-----------------------------------------------------------------
%% Check that the report has been received.
%%-----------------------------------------------------------------
reported(Tag, Type, Report) ->
@@ -279,7 +333,7 @@ reported(Tag, Type, Report) ->
test_server:messages_get(),
ok
after 1000 ->
- ct:fail(no_report_received)
+ ct:fail({no_report_received,test_server:messages_get()})
end.
%%-----------------------------------------------------------------
diff --git a/lib/kernel/test/error_logger_warn_SUITE.erl b/lib/kernel/test/error_logger_warn_SUITE.erl
index a8087e11f9..8f1eb2ba0a 100644
--- a/lib/kernel/test/error_logger_warn_SUITE.erl
+++ b/lib/kernel/test/error_logger_warn_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -480,9 +480,12 @@ rb_utc() ->
UtcLog=case application:get_env(sasl,utc_log) of
{ok,true} ->
true;
- _AllOthers ->
+ {ok,false} ->
application:set_env(sasl,utc_log,true),
- false
+ false;
+ undefined ->
+ application:set_env(sasl,utc_log,true),
+ undefined
end,
application:start(sasl),
rb:start([{report_dir, rd()}]),
@@ -494,7 +497,12 @@ rb_utc() ->
Sum=one_rb_findstr([],"UTC"),
rb:stop(),
application:stop(sasl),
- application:set_env(sasl,utc_log,UtcLog),
+ case UtcLog of
+ undefined ->
+ application:unset_env(sasl,utc_log);
+ _ ->
+ application:set_env(sasl,utc_log,UtcLog)
+ end,
stop_node(Node),
ok.
diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl
index 119e1f24bb..3bc8e6e828 100644
--- a/lib/kernel/test/file_SUITE.erl
+++ b/lib/kernel/test/file_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -39,6 +39,8 @@
-define(FILE_FIN_PER_TESTCASE(Config), Config).
-endif.
+-define(PRIM_FILE, prim_file).
+
-module(?FILE_SUITE).
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
@@ -54,7 +56,8 @@
open1/1,
old_modes/1, new_modes/1, path_open/1, open_errors/1]).
-export([ file_info_basic_file/1, file_info_basic_directory/1,
- file_info_bad/1, file_info_times/1, file_write_file_info/1]).
+ file_info_bad/1, file_info_times/1, file_write_file_info/1,
+ file_wfi_helpers/1]).
-export([rename/1, access/1, truncate/1, datasync/1, sync/1,
read_write/1, pread_write/1, append/1, exclusive/1]).
-export([ e_delete/1, e_rename/1, e_make_dir/1, e_del_dir/1]).
@@ -97,6 +100,12 @@
-export([unicode_mode/1]).
+-export([volume_relative_paths/1,unc_paths/1]).
+
+-export([tiny_writes/1, tiny_writes_delayed/1,
+ large_writes/1, large_writes_delayed/1,
+ tiny_reads/1, tiny_reads_ahead/1]).
+
%% Debug exports
-export([create_file_slow/2, create_file/2, create_bin/2]).
-export([verify_file/2, verify_bin/3]).
@@ -107,6 +116,8 @@
-export([disc_free/1, memsize/0]).
-include_lib("common_test/include/ct.hrl").
+-include_lib("common_test/include/ct_event.hrl").
+
-include_lib("kernel/include/file.hrl").
-define(THROW_ERROR(RES), throw({fail, ?LINE, RES})).
@@ -118,13 +129,13 @@ suite() ->
all() ->
[unicode, altname, read_write_file, {group, dirs},
- {group, files}, delete, rename, names, {group, errors},
- {group, compression}, {group, links}, copy,
+ {group, files}, delete, rename, names, volume_relative_paths, unc_paths,
+ {group, errors}, {group, compression}, {group, links}, copy,
delayed_write, read_ahead, segment_read, segment_write,
ipread, pid2name, interleaved_read_write, otp_5814, otp_10852,
large_file, large_write, read_line_1, read_line_2, read_line_3,
read_line_4, standard_io, old_io_protocol,
- unicode_mode
+ unicode_mode, {group, bench}
].
groups() ->
@@ -142,7 +153,8 @@ groups() ->
{pos, [], [pos1, pos2, pos3]},
{file_info, [],
[file_info_basic_file, file_info_basic_directory,
- file_info_bad, file_info_times, file_write_file_info]},
+ file_info_bad, file_info_times, file_write_file_info,
+ file_wfi_helpers]},
{consult, [], [consult1, path_consult]},
{eval, [], [eval1, path_eval]},
{script, [], [script1, path_script]},
@@ -154,11 +166,19 @@ groups() ->
write_compressed, compress_errors, catenated_gzips,
compress_async_crash]},
{links, [],
- [make_link, read_link_info_for_non_link, symlinks]}].
+ [make_link, read_link_info_for_non_link, symlinks]},
+ {bench, [],
+ [tiny_writes, tiny_writes_delayed,
+ large_writes, large_writes_delayed,
+ tiny_reads, tiny_reads_ahead]}].
init_per_group(_GroupName, Config) ->
Config.
+end_per_group(bench, Config) ->
+ ScratchDir = proplists:get_value(priv_dir, Config),
+ file:delete(filename:join(ScratchDir, "benchmark_scratch_file")),
+ Config;
end_per_group(_GroupName, Config) ->
Config.
@@ -381,11 +401,11 @@ read_write_0(Str, {Func, ReadFun}, Options) ->
io:format("~p:~p: ~p ERROR: ~ts vs~n ~w~n - ~p~n",
[?MODULE, Line, Func, Str, ReadBytes, Options]),
exit({error, ?LINE});
- error:What ->
+ error:What:Stacktrace ->
io:format("~p:??: ~p ERROR: ~p from~n ~w~n ~p~n",
[?MODULE, Func, What, Str, Options]),
- io:format("\t~p~n", [erlang:get_stacktrace()]),
+ io:format("\t~p~n", [Stacktrace]),
exit({error, ?LINE})
end.
@@ -473,7 +493,7 @@ um_check_unicode(_Utf8Bin, {ok, _ListOrBin}, _, _UTF8_) ->
um_filename(Bin, Dir, Options) when is_binary(Bin) ->
um_filename(binary_to_list(Bin), Dir, Options);
um_filename(Str = [_|_], Dir, Options) ->
- Name = hd(string:tokens(Str, ":")),
+ Name = hd(string:lexemes(Str, ":")),
Enc = atom_to_list(proplists:get_value(encoding, Options, latin1)),
File = case lists:member(binary, Options) of
true ->
@@ -638,6 +658,10 @@ cur_dir_0(Config) when is_list(Config) ->
{ok,NewDirFiles} = ?FILE_MODULE:list_dir("."),
true = lists:member(UncommonName,NewDirFiles),
+ %% Ensure that we get the same result with a trailing slash; the
+ %% APIs used on Windows will choke on them if passed directly.
+ {ok,NewDirFiles} = ?FILE_MODULE:list_dir("./"),
+
%% Delete the directory and return to the old current directory
%% and check that the created file isn't there (too!)
expect({error, einval}, {error, eacces},
@@ -690,10 +714,15 @@ win_cur_dir_1(_Config) ->
%% Get the drive letter from the current directory,
%% and try to get current directory for that drive.
- [Drive,$:|_] = BaseDir,
- {ok,BaseDir} = ?FILE_MODULE:get_cwd([Drive,$:]),
+ [CurDrive,$:|_] = BaseDir,
+ {ok,BaseDir} = ?FILE_MODULE:get_cwd([CurDrive,$:]),
io:format("BaseDir = ~s\n", [BaseDir]),
+ %% We should error out on non-existent drives. Any reasonable system will
+ %% have at least one.
+ CurDirs = [?FILE_MODULE:get_cwd([Drive,$:]) || Drive <- lists:seq($A, $Z)],
+ lists:member({error,eaccess}, CurDirs),
+
%% Unfortunately, there is no way to move away from the
%% current drive as we can't use the "subst" command from
%% a SSH connection. We can't test any more.
@@ -831,7 +860,7 @@ no_untranslatable_names() ->
end.
start_node(Name, Args) ->
- [_,Host] = string:tokens(atom_to_list(node()), "@"),
+ [_,Host] = string:lexemes(atom_to_list(node()), "@"),
ct:log("Trying to start ~w@~s~n", [Name,Host]),
case test_server:start_node(Name, peer, [{args,Args}]) of
{error,Reason} ->
@@ -1019,6 +1048,23 @@ close(Config) when is_list(Config) ->
Val = ?FILE_MODULE:close(Fd1),
io:format("Second close gave: ~p",[Val]),
+ %% All operations on a closed raw file should EINVAL, even if they're not
+ %% supported on the current platform.
+ {ok,Fd2} = ?FILE_MODULE:open(Name, [read, write, raw]),
+ ok = ?FILE_MODULE:close(Fd2),
+
+ {error, einval} = ?FILE_MODULE:advise(Fd2, 5, 5, normal),
+ {error, einval} = ?FILE_MODULE:allocate(Fd2, 5, 5),
+ {error, einval} = ?FILE_MODULE:close(Fd2),
+ {error, einval} = ?FILE_MODULE:datasync(Fd2),
+ {error, einval} = ?FILE_MODULE:position(Fd2, 5),
+ {error, einval} = ?FILE_MODULE:pread(Fd2, 5, 1),
+ {error, einval} = ?FILE_MODULE:pwrite(Fd2, 5, "einval please"),
+ {error, einval} = ?FILE_MODULE:read(Fd2, 1),
+ {error, einval} = ?FILE_MODULE:sync(Fd2),
+ {error, einval} = ?FILE_MODULE:truncate(Fd2),
+ {error, einval} = ?FILE_MODULE:write(Fd2, "einval please"),
+
[] = flush(),
ok.
@@ -1132,8 +1178,8 @@ pread_write_test(File, Data) ->
end,
I = Size + 17,
ok = ?FILE_MODULE:pwrite(File, 0, Data),
- Res = ?FILE_MODULE:pread(File, 0, I),
- {ok, Data} = Res,
+ {ok, Data} = ?FILE_MODULE:pread(File, 0, I),
+ {ok, [Data]} = ?FILE_MODULE:pread(File, [{0, I}]),
eof = ?FILE_MODULE:pread(File, I, 1),
ok = ?FILE_MODULE:pwrite(File, [{0, Data}, {I, Data}]),
{ok, [Data, eof, Data]} =
@@ -1321,6 +1367,10 @@ file_info_basic_file(Config) when is_list(Config) ->
io:put_chars(Fd1, "foo bar"),
ok = ?FILE_MODULE:close(Fd1),
+ %% Don't crash the file server when passing incorrect arguments.
+ {error,badarg} = ?FILE_MODULE:read_file_info(Name, [{time, gurka}]),
+ {error,badarg} = ?FILE_MODULE:read_file_info([#{} | gaffel]),
+
%% Test that the file has the expected attributes.
%% The times are tricky, so we will save them to a separate test case.
{ok,FileInfo} = ?FILE_MODULE:read_file_info(Name),
@@ -1564,6 +1614,39 @@ file_write_file_info(Config) when is_list(Config) ->
[] = flush(),
ok.
+file_wfi_helpers(Config) when is_list(Config) ->
+ RootDir = get_good_directory(Config),
+ io:format("RootDir = ~p", [RootDir]),
+
+ Name = filename:join(RootDir,
+ atom_to_list(?MODULE) ++ "_wfi_helpers"),
+
+ ok = ?FILE_MODULE:write_file(Name, "hello again"),
+ NewTime = {{1997, 02, 15}, {13, 18, 20}},
+ ok = ?FILE_MODULE:change_time(Name, NewTime, NewTime),
+
+ {ok, #file_info{atime=NewActAtime, mtime=NewTime}} =
+ ?FILE_MODULE:read_file_info(Name),
+
+ NewFilteredAtime = filter_atime(NewTime, Config),
+ NewFilteredAtime = filter_atime(NewActAtime, Config),
+
+ %% Make the file unwritable
+ ok = ?FILE_MODULE:change_mode(Name, 8#400),
+ {error, eacces} = ?FILE_MODULE:write_file(Name, "hello again"),
+
+ %% ... and writable again
+ ok = ?FILE_MODULE:change_mode(Name, 8#600),
+ ok = ?FILE_MODULE:write_file(Name, "hello again"),
+
+ %% We have no idea which users will work, so all we can do is to check
+ %% that it returns enoent instead of crashing.
+ {error, enoent} = ?FILE_MODULE:change_group("bogus file name", 0),
+ {error, enoent} = ?FILE_MODULE:change_owner("bogus file name", 0),
+
+ [] = flush(),
+ ok.
+
%% Returns a directory on a file system that has correct file times.
get_good_directory(Config) ->
@@ -2044,13 +2127,22 @@ names(Config) when is_list(Config) ->
ok = ?FILE_MODULE:close(Fd2),
{ok,Fd3} = ?FILE_MODULE:open(Name3,read),
ok = ?FILE_MODULE:close(Fd3),
+
+ %% Now try the same on raw files.
+ {ok,Fd4} = ?FILE_MODULE:open(Name2, [read, raw]),
+ ok = ?FILE_MODULE:close(Fd4),
+ {ok,Fd4f} = ?FILE_MODULE:open(lists:flatten(Name2), [read, raw]),
+ ok = ?FILE_MODULE:close(Fd4f),
+ {ok,Fd5} = ?FILE_MODULE:open(Name3, [read, raw]),
+ ok = ?FILE_MODULE:close(Fd5),
+
case length(Name1) > 255 of
true ->
io:format("Path too long for an atom:\n\n~p\n", [Name1]);
false ->
Name4 = list_to_atom(Name1),
- {ok,Fd4} = ?FILE_MODULE:open(Name4,read),
- ok = ?FILE_MODULE:close(Fd4)
+ {ok,Fd6} = ?FILE_MODULE:open(Name4,read),
+ ok = ?FILE_MODULE:close(Fd6)
end,
%% Try some path names
@@ -2074,6 +2166,49 @@ names(Config) when is_list(Config) ->
[] = flush(),
ok.
+volume_relative_paths(Config) when is_list(Config) ->
+ case os:type() of
+ {win32, _} ->
+ {ok, [Drive, $: | _]} = file:get_cwd(),
+ %% Relative to current device root.
+ {ok, RootInfo} = file:read_file_info([Drive, $:, $/]),
+ {ok, RootInfo} = file:read_file_info("/"),
+ %% Relative to current device directory.
+ {ok, DirContents} = file:list_dir([Drive, $:]),
+ {ok, DirContents} = file:list_dir("."),
+ [] = flush(),
+ ok;
+ _ ->
+ {skip, "This test is Windows-specific."}
+ end.
+
+unc_paths(Config) when is_list(Config) ->
+ case os:type() of
+ {win32, _} ->
+ %% We assume administrative shares are set up and reachable, and we
+ %% settle for testing presence as some of the returned data is
+ %% different.
+ {ok, _} = file:read_file_info("C:\\Windows\\explorer.exe"),
+ {ok, _} = file:read_file_info("\\\\localhost\\c$\\Windows\\explorer.exe"),
+
+ {ok, Files} = file:list_dir("C:\\Windows\\"),
+ {ok, Files} = file:list_dir("\\\\localhost\\c$\\Windows\\"),
+
+ {ok, Cwd} = file:get_cwd(),
+
+ try
+ ok = file:set_cwd("\\\\localhost\\c$\\Windows\\"),
+ {ok, _} = file:read_file_info("explorer.exe")
+ after
+ file:set_cwd(Cwd)
+ end,
+
+ [] = flush(),
+ ok;
+ _ ->
+ {skip, "This test is Windows-specific."}
+ end.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -2102,13 +2237,14 @@ e_delete(Config) when is_list(Config) ->
case os:type() of
{win32, _} ->
%% Remove a character device.
- {error, eacces} = ?FILE_MODULE:delete("nul");
+ expect({error, eacces}, {error, einval},
+ ?FILE_MODULE:delete("nul"));
_ ->
?FILE_MODULE:write_file_info(
Base, #file_info {mode=0}),
{error, eacces} = ?FILE_MODULE:delete(Afile),
?FILE_MODULE:write_file_info(
- Base, #file_info {mode=8#600})
+ Base, #file_info {mode=8#700})
end,
[] = flush(),
@@ -2239,7 +2375,7 @@ e_make_dir(Config) when is_list(Config) ->
?FILE_MODULE:write_file_info(Base, #file_info {mode=0}),
{error, eacces} = ?FILE_MODULE:make_dir(filename:join(Base, "xxxx")),
?FILE_MODULE:write_file_info(
- Base, #file_info {mode=8#600})
+ Base, #file_info {mode=8#700})
end,
ok.
@@ -2285,7 +2421,7 @@ e_del_dir(Config) when is_list(Config) ->
ok = ?FILE_MODULE:make_dir(ADirectory),
?FILE_MODULE:write_file_info( Base, #file_info {mode=0}),
{error, eacces} = ?FILE_MODULE:del_dir(ADirectory),
- ?FILE_MODULE:write_file_info( Base, #file_info {mode=8#600})
+ ?FILE_MODULE:write_file_info( Base, #file_info {mode=8#700})
end,
[] = flush(),
ok.
@@ -2641,8 +2777,8 @@ altname(Config) when is_list(Config) ->
{skipped, "Altname not supported on this platform"};
{ok, "LONGAL~1"} ->
{ok, "A_FILE~1"} = ?FILE_MODULE:altname(Name),
- {ok, "C:/"} = ?FILE_MODULE:altname("C:/"),
- {ok, "C:\\"} = ?FILE_MODULE:altname("C:\\"),
+ {ok, "c:/"} = ?FILE_MODULE:altname("C:/"),
+ {ok, "c:/"} = ?FILE_MODULE:altname("C:\\"),
{error,enoent} = ?FILE_MODULE:altname(NonexName),
{ok, "short"} = ?FILE_MODULE:altname(ShortName),
ok
@@ -2923,20 +3059,22 @@ delayed_write(Config) when is_list(Config) ->
%%
%% Test caching and normal close of non-raw file
{ok, Fd1} =
- ?FILE_MODULE:open(File, [write, {delayed_write, Size+1, 2000}]),
+ ?FILE_MODULE:open(File, [write, {delayed_write, Size+1, 400}]),
ok = ?FILE_MODULE:write(Fd1, Data1),
- timer:sleep(1000), % Just in case the file system is slow
+ %% Wait for a reasonable amount of time to check whether the write was
+ %% practically instantaneous or actually delayed.
+ timer:sleep(100),
{ok, Fd2} = ?FILE_MODULE:open(File, [read]),
eof = ?FILE_MODULE:read(Fd2, 1),
ok = ?FILE_MODULE:write(Fd1, Data1), % Data flush on size
- timer:sleep(1000), % Just in case the file system is slow
+ timer:sleep(100),
{ok, Data1Data1} = ?FILE_MODULE:pread(Fd2, bof, 2*Size+1),
ok = ?FILE_MODULE:write(Fd1, Data1),
- timer:sleep(3000), % Wait until data flush on timeout
+ timer:sleep(500), % Wait until data flush on timeout
{ok, Data1Data1Data1} = ?FILE_MODULE:pread(Fd2, bof, 3*Size+1),
ok = ?FILE_MODULE:write(Fd1, Data1),
ok = ?FILE_MODULE:close(Fd1), % Data flush on close
- timer:sleep(1000), % Just in case the file system is slow
+ timer:sleep(100),
{ok, Data1Data1Data1Data1} = ?FILE_MODULE:pread(Fd2, bof, 4*Size+1),
ok = ?FILE_MODULE:close(Fd2),
%%
@@ -2970,7 +3108,7 @@ delayed_write(Config) when is_list(Config) ->
{'DOWN', Mref1, _, _, _} = Down1a ->
ct:fail(Down1a)
end,
- timer:sleep(1000), % Just in case the file system is slow
+ timer:sleep(100), % Just in case the file system is slow
{ok, Fd3} = ?FILE_MODULE:open(File, [read]),
eof = ?FILE_MODULE:read(Fd3, 1),
Child1 ! {Parent, continue, normal},
@@ -2980,7 +3118,7 @@ delayed_write(Config) when is_list(Config) ->
{'DOWN', Mref1, _, _, _} = Down1b ->
ct:fail(Down1b)
end,
- timer:sleep(1000), % Just in case the file system is slow
+ timer:sleep(100), % Just in case the file system is slow
{ok, Data1} = ?FILE_MODULE:pread(Fd3, bof, Size+1),
ok = ?FILE_MODULE:close(Fd3),
%%
@@ -2993,7 +3131,7 @@ delayed_write(Config) when is_list(Config) ->
{'DOWN', Mref2, _, _, _} = Down2a ->
ct:fail(Down2a)
end,
- timer:sleep(1000), % Just in case the file system is slow
+ timer:sleep(100), % Just in case the file system is slow
{ok, Fd4} = ?FILE_MODULE:open(File, [read]),
eof = ?FILE_MODULE:read(Fd4, 1),
Child2 ! {Parent, continue, kill},
@@ -3003,7 +3141,7 @@ delayed_write(Config) when is_list(Config) ->
{'DOWN', Mref2, _, _, _} = Down2b ->
ct:fail(Down2b)
end,
- timer:sleep(1000), % Just in case the file system is slow
+ timer:sleep(100), % Just in case the file system is slow
eof = ?FILE_MODULE:pread(Fd4, bof, 1),
ok = ?FILE_MODULE:close(Fd4),
%%
@@ -3095,6 +3233,16 @@ read_ahead(Config) when is_list(Config) ->
Data1Data2Data3 = Data1++Data2++Data3,
{ok, Data1Data2Data3} = ?FILE_MODULE:read(Fd5, 3*Size+1),
ok = ?FILE_MODULE:close(Fd5),
+
+ %% Ensure that a read that draws from both the buffer and the file won't
+ %% return anything wonky.
+ SplitData = << <<(I rem 256)>> || I <- lists:seq(1, 1024) >>,
+ file:write_file(File, SplitData),
+ {ok, Fd6} = ?FILE_MODULE:open(File, [raw, read, binary, {read_ahead, 256}]),
+ {ok, <<1>>} = file:read(Fd6, 1),
+ <<1, Shifted:512/binary, _Rest/binary>> = SplitData,
+ {ok, Shifted} = file:read(Fd6, 512),
+
%%
[] = flush(),
ok.
@@ -3596,19 +3744,33 @@ otp_10852(Config) when is_list(Config) ->
ok = rpc_call(Node, read_file, [B]),
ok = rpc_call(Node, make_link, [B,B]),
case rpc_call(Node, make_symlink, [B,B]) of
- ok -> ok;
- {error, E} when (E =:= enotsup) or (E =:= eperm) ->
- {win32,_} = os:type()
+ {error, eilseq} ->
+ %% Some versions of OS X refuse to create files with illegal names.
+ {unix,darwin} = os:type();
+ {error, eperm} ->
+ %% The test user might not have permission to create symlinks.
+ {win32,_} = os:type();
+ ok ->
+ ok
end,
ok = rpc_call(Node, delete, [B]),
- ok = rpc_call(Node, make_dir, [B]),
+ case rpc_call(Node, make_dir, [B]) of
+ {error, eilseq} ->
+ {unix,darwin} = os:type();
+ ok ->
+ ok
+ end,
ok = rpc_call(Node, del_dir, [B]),
- ok = rpc_call(Node, write_file, [B,B]),
- {ok, Fd} = rpc_call(Node, open, [B,[read]]),
- ok = rpc_call(Node, close, [Fd]),
- {ok,0} = rpc_call(Node, copy, [B,B]),
- {ok, Fd2, B} = rpc_call(Node, path_open, [["."], B, [read]]),
- ok = rpc_call(Node, close, [Fd2]),
+ case rpc_call(Node, write_file, [B,B]) of
+ {error, eilseq} ->
+ {unix,darwin} = os:type();
+ ok ->
+ {ok, Fd} = rpc_call(Node, open, [B,[read]]),
+ ok = rpc_call(Node, close, [Fd]),
+ {ok,0} = rpc_call(Node, copy, [B,B]),
+ {ok, Fd2, B} = rpc_call(Node, path_open, [["."], B, [read]]),
+ ok = rpc_call(Node, close, [Fd2])
+ end,
true = test_server:stop_node(Node),
ok.
@@ -3699,6 +3861,83 @@ do_large_write(Name) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Benchmarks
+%%
+%% Note that we only measure the time it takes to run the isolated file
+%% operations and that the actual test runtime can differ significantly,
+%% especially on the write side as the files need to be truncated before
+%% writing.
+
+large_writes(Config) when is_list(Config) ->
+ Modes = [raw, binary],
+ OpCount = 4096,
+ Data = <<0:(64 bsl 10)/unit:8>>,
+ run_write_benchmark(Config, Modes, OpCount, Data).
+
+large_writes_delayed(Config) when is_list(Config) ->
+ %% Each write is exactly as large as the delay buffer, causing the writes
+ %% to pass through each time, giving us a decent idea of how much overhead
+ %% delayed_write adds.
+ Modes = [raw, binary, {delayed_write, 64 bsl 10, 2000}],
+ OpCount = 4096,
+ Data = <<0:(64 bsl 10)/unit:8>>,
+ run_write_benchmark(Config, Modes, OpCount, Data).
+
+tiny_writes(Config) when is_list(Config) ->
+ Modes = [raw, binary],
+ OpCount = 512 bsl 10,
+ Data = <<0>>,
+ run_write_benchmark(Config, Modes, OpCount, Data).
+
+tiny_writes_delayed(Config) when is_list(Config) ->
+ Modes = [raw, binary, {delayed_write, 512 bsl 10, 2000}],
+ OpCount = 512 bsl 10,
+ Data = <<0>>,
+ run_write_benchmark(Config, Modes, OpCount, Data).
+
+%% The read benchmarks assume that "benchmark_scratch_file" has been filled by
+%% the write benchmarks.
+
+tiny_reads(Config) when is_list(Config) ->
+ Modes = [raw, binary],
+ OpCount = 512 bsl 10,
+ run_read_benchmark(Config, Modes, OpCount, 1).
+
+tiny_reads_ahead(Config) when is_list(Config) ->
+ Modes = [raw, binary, {read_ahead, 512 bsl 10}],
+ OpCount = 512 bsl 10,
+ run_read_benchmark(Config, Modes, OpCount, 1).
+
+run_write_benchmark(Config, Modes, OpCount, Data) ->
+ run_benchmark(Config, [write | Modes], OpCount, fun file:write/2, Data).
+
+run_read_benchmark(Config, Modes, OpCount, OpSize) ->
+ run_benchmark(Config, [read | Modes], OpCount, fun file:read/2, OpSize).
+
+run_benchmark(Config, Modes, OpCount, Fun, Arg) ->
+ ScratchDir = proplists:get_value(priv_dir, Config),
+ Path = filename:join(ScratchDir, "benchmark_scratch_file"),
+ {ok, Fd} = file:open(Path, Modes),
+ submit_throughput_results(Fun, [Fd, Arg], OpCount).
+
+submit_throughput_results(Fun, Args, Times) ->
+ MSecs = measure_repeated_file_op(Fun, Args, Times, millisecond),
+ IOPS = trunc(Times * (1000 / MSecs)),
+ ct_event:notify(#event{ name = benchmark_data, data = [{value,IOPS}] }),
+ {comment, io_lib:format("~p IOPS, ~p ms", [IOPS, trunc(MSecs)])}.
+
+measure_repeated_file_op(Fun, Args, Times, Unit) ->
+ Start = os:perf_counter(Unit),
+ repeated_apply(Fun, Args, Times),
+ os:perf_counter(Unit) - Start.
+
+repeated_apply(_F, _Args, Times) when Times =< 0 ->
+ ok;
+repeated_apply(F, Args, Times) ->
+ erlang:apply(F, Args),
+ repeated_apply(F, Args, Times - 1).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
response_analysis(Module, Function, Arguments) ->
@@ -3934,7 +4173,7 @@ read_line_create_files(TestData) ->
read_line_remove_files(TestData) ->
[ file:delete(File) || {_Function,File,_,_} <- TestData ].
-%% read_line with prim_file.
+%% read_line with ?PRIM_FILE.
read_line_1(Config) when is_list(Config) ->
PrivDir = proplists:get_value(priv_dir, Config),
All = read_line_testdata(PrivDir),
@@ -4103,9 +4342,9 @@ read_line_create7(Filename) ->
file:close(F).
read_line_all(Filename) ->
- {ok,F} = prim_file:open(Filename,[read,binary]),
+ {ok,F} = ?PRIM_FILE:open(Filename,[read,binary]),
X=read_rl_lines(F),
- prim_file:close(F),
+ ?PRIM_FILE:close(F),
Bin = list_to_binary([B || {ok,B} <- X]),
Bin = re:replace(list_to_binary([element(2,file:read_file(Filename))]),
"\r\n","\n",[global,{return,binary}]),
@@ -4138,7 +4377,7 @@ read_line_all4(Filename) ->
{length(X),Bin}.
read_rl_lines(F) ->
- case prim_file:read_line(F) of
+ case ?PRIM_FILE:read_line(F) of
eof ->
[];
{error,X} ->
@@ -4158,9 +4397,9 @@ read_rl_lines2(F) ->
end.
read_line_all_alternating(Filename) ->
- {ok,F} = prim_file:open(Filename,[read,binary]),
+ {ok,F} = ?PRIM_FILE:open(Filename,[read,binary]),
X=read_rl_lines(F,true),
- prim_file:close(F),
+ ?PRIM_FILE:close(F),
Bin = list_to_binary([B || {ok,B} <- X]),
Bin = re:replace(list_to_binary([element(2,file:read_file(Filename))]),
"\r\n","\n",[global,{return,binary}]),
@@ -4194,8 +4433,8 @@ read_line_all_alternating4(Filename) ->
read_rl_lines(F,Alternate) ->
case begin
case Alternate of
- true -> prim_file:read(F,1);
- false -> prim_file:read_line(F)
+ true -> ?PRIM_FILE:read(F,1);
+ false -> ?PRIM_FILE:read_line(F)
end
end of
eof ->
@@ -4275,15 +4514,18 @@ run_large_file_test(Config, Run, Name) ->
{{unix,sunos},OsVersion} when OsVersion < {5,5,1} ->
{skip,"Only supported on Win32, Unix or SunOS >= 5.5.1"};
{{unix,_},_} ->
- N = disc_free(proplists:get_value(priv_dir, Config)),
- io:format("Free disk: ~w KByte~n", [N]),
- if N < 5 * (1 bsl 20) ->
- %% Less than 5 GByte free
- {skip,"Less than 5 GByte free"};
- true ->
- do_run_large_file_test(Config, Run, Name)
- end;
- _ ->
+ case disc_free(proplists:get_value(priv_dir, Config)) of
+ error ->
+ {skip, "Failed to query disk space for priv_dir. "
+ "Is it on a remote file system?~n"};
+ N when N >= 5 * (1 bsl 20) ->
+ ct:pal("Free disk: ~w KByte~n", [N]),
+ do_run_large_file_test(Config, Run, Name);
+ N when N < 5 * (1 bsl 20) ->
+ ct:pal("Free disk: ~w KByte~n", [N]),
+ {skip,"Less than 5 GByte free"}
+ end;
+ _ ->
{skip,"Only supported on Win32, Unix or SunOS >= 5.5.1"}
end.
@@ -4317,12 +4559,18 @@ do_run_large_file_test(Config, Run, Name0) ->
disc_free(Path) ->
Data = disksup:get_disk_data(),
- {_,Tot,Perc} = hd(lists:filter(
- fun({P,_Size,_Full}) ->
- lists:prefix(filename:nativename(P),
- filename:nativename(Path))
- end, lists:reverse(lists:sort(Data)))),
- round(Tot * (1-(Perc/100))).
+
+ %% What partitions could Data be mounted on?
+ Partitions =
+ [D || {P, _Tot, _Perc}=D <- Data,
+ lists:prefix(filename:nativename(P), filename:nativename(Path))],
+
+ %% Sorting in descending order places the partition with the most specific
+ %% path first.
+ case lists:sort(fun erlang:'>='/2, Partitions) of
+ [{_,Tot, Perc} | _] -> round(Tot * (1-(Perc/100)));
+ [] -> error
+ end.
memsize() ->
{Tot,_Used,_} = memsup:get_memory_data(),
diff --git a/lib/kernel/test/file_name_SUITE.erl b/lib/kernel/test/file_name_SUITE.erl
index 899102c908..26cfd187c7 100644
--- a/lib/kernel/test/file_name_SUITE.erl
+++ b/lib/kernel/test/file_name_SUITE.erl
@@ -77,6 +77,7 @@
init_per_testcase/2, end_per_testcase/2]).
-export([normal/1,icky/1,very_icky/1,normalize/1,home_dir/1]).
+-define(PRIM_FILE, prim_file).
init_per_testcase(_Func, Config) ->
Config.
@@ -131,7 +132,7 @@ home_dir(Config) when is_list(Config) ->
os:putenv("HOME",NewHome),
{"HOME",Save};
_ ->
- rm_rf(prim_file,NewHome),
+ rm_rf(?PRIM_FILE,NewHome),
throw(unsupported_os)
end,
try
@@ -145,7 +146,7 @@ home_dir(Config) when is_list(Config) ->
_ ->
os:putenv(SaveOldName,SaveOldValue)
end,
- rm_rf(prim_file,NewHome)
+ rm_rf(?PRIM_FILE,NewHome)
end
catch
throw:need_unicode_mode ->
@@ -190,7 +191,7 @@ normal(Config) when is_list(Config) ->
try
Priv = proplists:get_value(priv_dir, Config),
file:set_cwd(Priv),
- ok = check_normal(prim_file),
+ ok = check_normal(?PRIM_FILE),
ok = check_normal(file),
%% If all is good, delete dir again (avoid hanging dir on windows)
rm_rf(file,"normal_dir"),
@@ -210,7 +211,7 @@ icky(Config) when is_list(Config) ->
try
Priv = proplists:get_value(priv_dir, Config),
file:set_cwd(Priv),
- ok = check_icky(prim_file),
+ ok = check_icky(?PRIM_FILE),
ok = check_icky(file),
%% If all is good, delete dir again (avoid hanging dir on windows)
rm_rf(file,"icky_dir"),
@@ -229,7 +230,7 @@ very_icky(Config) when is_list(Config) ->
try
Priv = proplists:get_value(priv_dir, Config),
file:set_cwd(Priv),
- case check_very_icky(prim_file) of
+ case check_very_icky(?PRIM_FILE) of
need_unicode_mode ->
{skipped,"VM needs to be started in Unicode filename mode"};
ok ->
@@ -292,17 +293,14 @@ check_normal(Mod) ->
ok
end,
[ begin
- {ok, FD} = Mod:open(Name,[read]),
- {ok, Content} = Mod:read(FD,1024),
- ok = file:close(FD)
- end || {regular,Name,Content} <- NormalDir ],
- [ begin
{ok, FD} = Mod:open(Name,[read,binary]),
BC = list_to_binary(Content),
{ok, BC} = Mod:read(FD,1024),
ok = file:close(FD)
end || {regular,Name,Content} <- NormalDir ],
+ {error, badarg} = Mod:rename("fil1\0tmp_fil2","tmp_fil1"),
Mod:rename("fil1","tmp_fil1"),
+ {error, badarg} = Mod:read_file("tmp_fil1\0.txt"),
{ok, <<"fil1">>} = Mod:read_file("tmp_fil1"),
{error,enoent} = Mod:read_file("fil1"),
Mod:rename("tmp_fil1","fil1"),
@@ -410,11 +408,6 @@ check_icky(Mod) ->
ok
end,
[ begin
- {ok, FD} = Mod:open(Name,[read]),
- {ok, Content} = Mod:read(FD,1024),
- ok = file:close(FD)
- end || {regular,Name,Content} <- IckyDir ],
- [ begin
{ok, FD} = Mod:open(Name,[read,binary]),
BC = list_to_binary([Content]),
{ok, BC} = Mod:read(FD,1024),
@@ -519,11 +512,6 @@ check_very_icky(Mod) ->
ok
end,
[ begin
- {ok, FD} = Mod:open(Name,[read]),
- {ok, Content} = Mod:read(FD,1024),
- ok = file:close(FD)
- end || {regular,Name,Content} <- VeryIckyDir ],
- [ begin
{ok, FD} = Mod:open(Name,[read,binary]),
BC = list_to_binary([Content]),
{ok, BC} = Mod:read(FD,1024),
@@ -644,10 +632,13 @@ make_icky_dir(Mod, IckyDirName) ->
hopeless_darwin() ->
case {os:type(),os:version()} of
- {{unix,darwin},{Major,_,_}} when Major < 9 ->
- true;
- _ ->
- false
+ {{unix,darwin},{Major,_,_}} ->
+ %% icky file names worked between 10 and 17, but started returning
+ %% EILSEQ in 18. The check against 18 is exact in case newer
+ %% versions of Darwin support them again.
+ Major < 9 orelse Major =:= 18;
+ _ ->
+ false
end.
make_very_icky_dir(Mod, DirName) ->
diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl
index 620ab235a0..e4c489bd10 100644
--- a/lib/kernel/test/gen_sctp_SUITE.erl
+++ b/lib/kernel/test/gen_sctp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1038,8 +1038,7 @@ do_from_other_process(Fun) ->
Result ->
Parent ! {Ref,Result}
catch
- Class:Reason ->
- Stacktrace = erlang:get_stacktrace(),
+ Class:Reason:Stacktrace ->
Parent ! {Ref,Class,Reason,Stacktrace}
end
end),
@@ -1460,11 +1459,11 @@ do_open_and_connect(ServerAddresses, AddressToConnectTo) ->
do_open_and_connect(ServerAddresses, AddressToConnectTo, Fun).
%%
do_open_and_connect(ServerAddresses, AddressToConnectTo, Fun) ->
- ServerFamily = get_family_by_addrs(ServerAddresses),
+ {ServerFamily, ServerOpts} = get_family_by_addrs(ServerAddresses),
io:format("Serving ~p addresses: ~p~n",
[ServerFamily, ServerAddresses]),
S1 = ok(gen_sctp:open(0, [{ip,Addr} || Addr <- ServerAddresses] ++
- [ServerFamily])),
+ [ServerFamily|ServerOpts])),
ok = gen_sctp:listen(S1, true),
P1 = ok(inet:port(S1)),
ClientFamily = get_family_by_addr(AddressToConnectTo),
@@ -1494,9 +1493,9 @@ do_open_and_connect(ServerAddresses, AddressToConnectTo, Fun) ->
%% If at least one of the addresses is an ipv6 address, return inet6, else inet.
get_family_by_addrs(Addresses) ->
case lists:usort([get_family_by_addr(Addr) || Addr <- Addresses]) of
- [inet, inet6] -> inet6;
- [inet] -> inet;
- [inet6] -> inet6
+ [inet, inet6] -> {inet6, [{ipv6_v6only, false}]};
+ [inet] -> {inet, []};
+ [inet6] -> {inet6, []}
end.
get_family_by_addr(Addr) when tuple_size(Addr) =:= 4 -> inet;
@@ -1617,8 +1616,7 @@ s_start(Socket, Timeout, Parent) ->
try
s_loop(Socket, Timeout, Parent, Handler, gb_trees:empty())
catch
- Class:Reason ->
- Stacktrace = erlang:get_stacktrace(),
+ Class:Reason:Stacktrace ->
io:format(?MODULE_STRING":socket exception ~w:~w at~n"
"~p.~n", [Class,Reason,Stacktrace]),
erlang:raise(Class, Reason, Stacktrace)
diff --git a/lib/kernel/test/gen_tcp_api_SUITE.erl b/lib/kernel/test/gen_tcp_api_SUITE.erl
index 12d22519ce..1be016444f 100644
--- a/lib/kernel/test/gen_tcp_api_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_api_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -605,9 +605,9 @@ ok({ok,V}) -> V;
ok(NotOk) ->
try throw(not_ok)
catch
- Thrown ->
+ throw:Thrown:Stacktrace ->
erlang:raise(
- error, {Thrown, NotOk}, tl(erlang:get_stacktrace()))
+ error, {Thrown, NotOk}, tl(Stacktrace))
end.
get_localaddr() ->
diff --git a/lib/kernel/test/gen_tcp_api_SUITE_data/gen_tcp_api_SUITE.c b/lib/kernel/test/gen_tcp_api_SUITE_data/gen_tcp_api_SUITE.c
index b91dca61d4..96938f9071 100644
--- a/lib/kernel/test/gen_tcp_api_SUITE_data/gen_tcp_api_SUITE.c
+++ b/lib/kernel/test/gen_tcp_api_SUITE_data/gen_tcp_api_SUITE.c
@@ -30,6 +30,7 @@
#define sock_close(s) closesocket(s)
#else
#include <sys/socket.h>
+#include <unistd.h>
#define sock_close(s) close(s)
#endif
diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl
index 331864b5de..edf30448c4 100644
--- a/lib/kernel/test/gen_tcp_misc_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -41,6 +41,7 @@
busy_send/1, busy_disconnect_passive/1, busy_disconnect_active/1,
fill_sendq/1, partial_recv_and_close/1,
partial_recv_and_close_2/1,partial_recv_and_close_3/1,so_priority/1,
+ recvtos/1, recvttl/1, recvtosttl/1, recvtclass/1,
%% Accept tests
primitive_accept/1,multi_accept_close_listen/1,accept_timeout/1,
accept_timeouts_in_order/1,accept_timeouts_in_order2/1,
@@ -51,7 +52,8 @@
several_accepts_in_one_go/1, accept_system_limit/1,
active_once_closed/1, send_timeout/1, send_timeout_active/1,
otp_7731/1, zombie_sockets/1, otp_7816/1, otp_8102/1,
- wrapping_oct/0, wrapping_oct/1, otp_9389/1, otp_13939/1]).
+ wrapping_oct/0, wrapping_oct/1, otp_9389/1, otp_13939/1,
+ otp_12242/1, delay_send_error/1]).
%% Internal exports.
-export([sender/3, not_owner/1, passive_sockets_server/2, priority_server/1,
@@ -83,7 +85,8 @@ all() ->
busy_disconnect_passive, busy_disconnect_active,
fill_sendq, partial_recv_and_close,
partial_recv_and_close_2, partial_recv_and_close_3,
- so_priority, primitive_accept,
+ so_priority, recvtos, recvttl, recvtosttl,
+ recvtclass, primitive_accept,
multi_accept_close_listen, accept_timeout,
accept_timeouts_in_order, accept_timeouts_in_order2,
accept_timeouts_in_order3, accept_timeouts_in_order4,
@@ -93,7 +96,8 @@ all() ->
killing_multi_acceptors2, several_accepts_in_one_go, accept_system_limit,
active_once_closed, send_timeout, send_timeout_active, otp_7731,
wrapping_oct,
- zombie_sockets, otp_7816, otp_8102, otp_9389].
+ zombie_sockets, otp_7816, otp_8102, otp_9389,
+ otp_12242, delay_send_error].
groups() ->
[].
@@ -1572,52 +1576,56 @@ fill_sendq(Config) when is_list(Config) ->
Master = self(),
Server =
spawn_link(fun () ->
- {ok,L} = gen_tcp:listen
- (0, [{active,false},binary,
- {reuseaddr,true},{packet,0}]),
+ {ok,L} = gen_tcp:listen(0, [{active,false},binary,
+ {reuseaddr,true},{packet,0}]),
{ok,Port} = inet:port(L),
Master ! {self(),client,
fill_sendq_client(Port, Master)},
fill_sendq_srv(L, Master)
end),
io:format("~p Server~n", [Server]),
- receive {Server,client,Client} ->
- io:format("~p Client~n", [Client]),
- receive {Server,reader,Reader} ->
- io:format("~p Reader~n", [Reader]),
- fill_sendq_loop(Server, Client, Reader)
+ receive
+ {Server,client,Client} ->
+ io:format("~p Client~n", [Client]),
+ receive
+ {Server,reader,Reader} ->
+ io:format("~p Reader~n", [Reader]),
+ fill_sendq_loop(Server, Client, Reader)
end
end.
fill_sendq_loop(Server, Client, Reader) ->
%% Master
%%
- receive {Server,send} ->
+ receive
+ {Server,send} ->
fill_sendq_loop(Server, Client, Reader)
after 2000 ->
%% Send queue full, sender blocked -> close client.
io:format("Send timeout, closing Client...~n", []),
Client ! {self(),close},
- receive {Server,[{error,closed}]} ->
- io:format("Got server closed.~n"),
- receive {Reader,[{error,closed}]} ->
- io:format
- ("Got reader closed.~n"),
- ok
- after 3000 ->
- ct:fail({timeout,{closed,reader}})
- end;
- {Reader,[{error,closed}]} ->
- io:format("Got reader closed.~n"),
- receive {Server,[{error,closed}]} ->
- io:format("Got server closed~n"),
- ok
- after 3000 ->
- ct:fail({timeout,{closed,server}})
- end
- after 3000 ->
- ct:fail({timeout,{closed,[server,reader]}})
- end
+ receive
+ {Server,[{error,closed}]} ->
+ io:format("Got server closed.~n"),
+ receive
+ {Reader,[{error,closed}]} ->
+ io:format("Got reader closed.~n"),
+ ok
+ after 3000 ->
+ ct:fail({timeout,{closed,reader}})
+ end;
+ {Reader,[{error,closed}]} ->
+ io:format("Got reader closed.~n"),
+ receive
+ {Server,[{error,closed}]} ->
+ io:format("Got server closed~n"),
+ ok
+ after 3000 ->
+ ct:fail({timeout,{closed,server}})
+ end
+ after 3000 ->
+ ct:fail({timeout,{closed,[server,reader]}})
+ end
end.
fill_sendq_srv(L, Master) ->
@@ -1910,6 +1918,264 @@ so_priority(Config) when is_list(Config) ->
end
end.
+
+
+%% IP_RECVTOS and IP_RECVTCLASS for IP_PKTOPTIONS
+%% does not seem to be implemented in Linux until kernel 3.1
+%%
+%% It seems pktoptions does not return valid values
+%% for IPv4 connect sockets. On the accept socket
+%% we get valid values, but on the connect socket we get
+%% the default values for TOS and TTL.
+%%
+%% Therefore the argument CheckConnect that enables
+%% checking the returned values for the connect socket.
+%% It is only used for recvtclass that is an IPv6 option
+%% and there we get valid values from both socket ends.
+
+recvtos(_Config) ->
+ test_pktoptions(
+ inet, [{recvtos,tos,96}],
+ fun recvtos_ok/2,
+ false).
+
+recvtosttl(_Config) ->
+ test_pktoptions(
+ inet, [{recvtos,tos,96},{recvttl,ttl,33}],
+ fun (OSType, OSVer) ->
+ recvtos_ok(OSType, OSVer) andalso recvttl_ok(OSType, OSVer)
+ end,
+ false).
+
+recvttl(_Config) ->
+ test_pktoptions(
+ inet, [{recvttl,ttl,33}],
+ fun recvttl_ok/2,
+ false).
+
+recvtclass(_Config) ->
+ {ok,IFs} = inet:getifaddrs(),
+ case
+ [Name ||
+ {Name,Opts} <- IFs,
+ lists:member({addr,{0,0,0,0,0,0,0,1}}, Opts)]
+ of
+ [_] ->
+ test_pktoptions(
+ inet6, [{recvtclass,tclass,224}],
+ fun recvtclass_ok/2,
+ true);
+ [] ->
+ {skip,{ipv6_not_supported,IFs}}
+ end.
+
+%% These version numbers are above the highest noted
+%% in daily tests where the test fails for a plausible reason,
+%% so skip on platforms of lower version, i.e they are future
+%% versions where it is possible that it might not fail.
+%%
+%% When machines with newer versions gets installed,
+%% if the test still fails for a plausible reason these
+%% version numbers simply should be increased.
+%% Or maybe we should change to only test on known good
+%% platforms - change {unix,_} to false?
+
+%% pktoptions is not supported for IPv4
+recvtos_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0});
+recvtos_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0});
+%% Using the option returns einval, so it is not implemented.
+recvtos_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {11,2,0});
+recvtos_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0});
+%% Does not return any value - not implemented for pktoptions
+recvtos_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {3,1,0});
+%%
+recvtos_ok({unix,_}, _) -> true;
+recvtos_ok(_, _) -> false.
+
+%% pktoptions is not supported for IPv4
+recvttl_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0});
+recvttl_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0});
+%% Using the option returns einval, so it is not implemented.
+recvttl_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {11,2,0});
+recvttl_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0});
+%% Does not return any value - not implemented for pktoptions
+recvttl_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {2,7,0});
+%%
+recvttl_ok({unix,_}, _) -> true;
+recvttl_ok(_, _) -> false.
+
+%% pktoptions is not supported for IPv6
+recvtclass_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0});
+recvtclass_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0});
+recvtclass_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0});
+%% Using the option returns einval, so it is not implemented.
+recvtclass_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {11,2,0});
+%% Does not return any value - not implemented for pktoptions
+recvtclass_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {3,1,0});
+%%
+recvtclass_ok({unix,_}, _) -> true;
+recvtclass_ok(_, _) -> false.
+
+semver_lt({X1,Y1,Z1}, {X2,Y2,Z2}) ->
+ if
+ X1 > X2 -> false;
+ X1 < X2 -> true;
+ Y1 > Y2 -> false;
+ Y1 < Y2 -> true;
+ Z1 > Z2 -> false;
+ Z1 < Z2 -> true;
+ true -> false
+ end;
+semver_lt(_, {_,_,_}) -> false.
+
+test_pktoptions(Family, Spec, OSFilter, CheckConnect) ->
+ OSType = os:type(),
+ OSVer = os:version(),
+ case OSFilter(OSType, OSVer) of
+ true ->
+ io:format("Os: ~p, ~p~n", [OSType,OSVer]),
+ test_pktoptions(Family, Spec, CheckConnect, OSType, OSVer);
+ false ->
+ {skip,{not_supported_for_os_version,{OSType,OSVer}}}
+ end.
+%%
+test_pktoptions(Family, Spec, CheckConnect, OSType, OSVer) ->
+ Timeout = 5000,
+ RecvOpts = [RecvOpt || {RecvOpt,_,_} <- Spec],
+ TrueRecvOpts = [{RecvOpt,true} || {RecvOpt,_,_} <- Spec],
+ FalseRecvOpts = [{RecvOpt,false} || {RecvOpt,_,_} <- Spec],
+ Opts = [Opt || {_,Opt,_} <- Spec],
+ OptsVals = [{Opt,Val} || {_,Opt,Val} <- Spec],
+ Address =
+ case Family of
+ inet ->
+ {127,0,0,1};
+ inet6 ->
+ {0,0,0,0,0,0,0,1}
+ end,
+ %%
+ %% Set RecvOpts on listen socket
+ {ok,L} =
+ gen_tcp:listen(
+ 0,
+ [Family,binary,{active,false},{send_timeout,Timeout}
+ |TrueRecvOpts]),
+ {ok,P} = inet:port(L),
+ {ok,TrueRecvOpts} = inet:getopts(L, RecvOpts),
+ {ok,OptsValsDefault} = inet:getopts(L, Opts),
+ %%
+ %% Set RecvOpts and Option values on connect socket
+ {ok,S2} =
+ gen_tcp:connect(
+ Address, P,
+ [Family,binary,{active,false},{send_timeout,Timeout}
+ |TrueRecvOpts ++ OptsVals],
+ Timeout),
+ {ok,TrueRecvOpts} = inet:getopts(S2, RecvOpts),
+ {ok,OptsVals} = inet:getopts(S2, Opts),
+ %%
+ %% Accept socket inherits the options from listen socket
+ {ok,S1} = gen_tcp:accept(L, Timeout),
+ {ok,TrueRecvOpts} = inet:getopts(S1, RecvOpts),
+ {ok,OptsValsDefault} = inet:getopts(S1, Opts),
+%%% %%
+%%% %% Handshake
+%%% ok = gen_tcp:send(S1, <<"hello">>),
+%%% {ok,<<"hello">>} = gen_tcp:recv(S2, 5, Timeout),
+%%% ok = gen_tcp:send(S2, <<"hi">>),
+%%% {ok,<<"hi">>} = gen_tcp:recv(S1, 2, Timeout),
+ %%
+ %% Verify returned remote options
+ VerifyRemOpts =
+ fun(S, Role) ->
+ case inet:getopts(S, [pktoptions]) of
+ {ok, [{pktoptions, PktOpts1}]} ->
+ PktOpts1;
+ {ok, UnexpOK1} ->
+ io:format("Unexpected OK (~w): "
+ "~n ~p"
+ "~n", [Role, UnexpOK1]),
+ exit({unexpected_getopts_ok,
+ Role,
+ Spec,
+ TrueRecvOpts,
+ OptsVals,
+ OptsValsDefault,
+ UnexpOK1});
+ {error, UnexpERR1} ->
+ io:format("Unexpected ERROR (~w): "
+ "~n ~p"
+ "~n", [Role, UnexpERR1]),
+ exit({unexpected_getopts_failure,
+ Role,
+ Spec,
+ TrueRecvOpts,
+ OptsVals,
+ OptsValsDefault,
+ UnexpERR1})
+ end
+ end,
+ OptsVals1 = VerifyRemOpts(S1, dest),
+ OptsVals2 = VerifyRemOpts(S2, orig),
+ %% {ok,[{pktoptions,OptsVals1}]} = inet:getopts(S1, [pktoptions]),
+ %% {ok,[{pktoptions,OptsVals2}]} = inet:getopts(S2, [pktoptions]),
+ (Result1 = sets_eq(OptsVals1, OptsVals))
+ orelse io:format(
+ "Accept differs: ~p neq ~p~n", [OptsVals1,OptsVals]),
+ (Result2 = sets_eq(OptsVals2, OptsValsDefault))
+ orelse io:format(
+ "Connect differs: ~p neq ~p~n",
+ [OptsVals2,OptsValsDefault]),
+ %%
+ ok = gen_tcp:close(S2),
+ ok = gen_tcp:close(S1),
+ %%
+ %%
+ %% Clear RecvOpts on listen socket and set Option values
+ ok = inet:setopts(L, FalseRecvOpts ++ OptsVals),
+ {ok,FalseRecvOpts} = inet:getopts(L, RecvOpts),
+ {ok,OptsVals} = inet:getopts(L, Opts),
+ %%
+ %% Set RecvOpts on connecting socket
+ %%
+ {ok,S4} =
+ gen_tcp:connect(
+ Address, P,
+ [Family,binary,{active,false},{send_timeout,Timeout}
+ |TrueRecvOpts],
+ Timeout),
+ {ok,TrueRecvOpts} = inet:getopts(S4, RecvOpts),
+ {ok,OptsValsDefault} = inet:getopts(S4, Opts),
+ %%
+ %% Accept socket inherits the options from listen socket
+ {ok,S3} = gen_tcp:accept(L, Timeout),
+ {ok,FalseRecvOpts} = inet:getopts(S3, RecvOpts),
+ {ok,OptsVals} = inet:getopts(S3, Opts),
+ %%
+ %% Verify returned remote options
+ {ok,[{pktoptions,[]}]} = inet:getopts(S3, [pktoptions]),
+ {ok,[{pktoptions,OptsVals4}]} = inet:getopts(S4, [pktoptions]),
+ (Result3 = sets_eq(OptsVals4, OptsVals))
+ orelse io:format(
+ "Accept2 differs: ~p neq ~p~n", [OptsVals4,OptsVals]),
+ %%
+ ok = gen_tcp:close(S4),
+ ok = gen_tcp:close(S3),
+ ok = gen_tcp:close(L),
+ (Result1 and ((not CheckConnect) or (Result2 and Result3)))
+ orelse
+ exit({failed,
+ [{OptsVals1,OptsVals4,OptsVals},
+ {OptsVals2,OptsValsDefault}],
+ {OSType,OSVer}}),
+%% exit({{OSType,OSVer},success}), % In search for the truth
+ ok.
+
+sets_eq(L1, L2) ->
+ lists:sort(L1) == lists:sort(L2).
+
+
+
%% Accept test utilities (suites are below)
millis() ->
@@ -2201,7 +2467,7 @@ wait_until_accepting(Proc,0) ->
exit({timeout_waiting_for_accepting,Proc});
wait_until_accepting(Proc,N) ->
case process_info(Proc,current_function) of
- {current_function,{prim_inet,accept0,2}} ->
+ {current_function,{prim_inet,accept0,3}} ->
case process_info(Proc,status) of
{status,waiting} ->
ok;
@@ -3052,3 +3318,172 @@ otp_13939(Config) when is_list(Config) ->
exit(Pid, normal),
ct:fail("Server process blocked on send.")
end.
+
+otp_12242(Config) when is_list(Config) ->
+ case os:type() of
+ {win32,_} ->
+ %% Even if we set sndbuf and recbuf to small sizes
+ %% Windows either happily accepts to send GBytes of data
+ %% in no time, so the second send below that is supposed
+ %% to time out just succedes, or the first send that
+ %% is supposed to fill the inet_drv I/O queue and
+ %% start waiting for when more data can be sent
+ %% instead sends all data but suffers a send
+ %% failure that closes the socket
+ {skipped,backpressure_broken_on_win32};
+ _ ->
+ %% Find the IPv4 address of an up and running interface
+ %% that is not loopback nor pointtopoint
+ {ok,IFList} = inet:getifaddrs(),
+ ct:pal("IFList ~p~n", [IFList]),
+ case
+ lists:flatten(
+ [lists:filtermap(
+ fun ({addr,Addr}) when tuple_size(Addr) =:= 4 ->
+ {true,Addr};
+ (_) ->
+ false
+ end, Opts)
+ || {_,Opts} <- IFList,
+ case lists:keyfind(flags, 1, Opts) of
+ {_,Flags} ->
+ lists:member(up, Flags)
+ andalso
+ lists:member(running, Flags)
+ andalso
+ not lists:member(loopback, Flags)
+ andalso
+ not lists:member(pointtopoint, Flags);
+ false ->
+ false
+ end])
+ of
+ [Addr|_] ->
+ otp_12242(Addr);
+ Other ->
+ {skipped,{no_external_address,Other}}
+ end
+ end;
+%%
+otp_12242(Addr) when tuple_size(Addr) =:= 4 ->
+ ct:timetrap(30000),
+ ct:pal("Using address ~p~n", [Addr]),
+ Bufsize = 16 * 1024,
+ Datasize = 128 * 1024 * 1024, % At least 1 s on GBit interface
+ Blob = binary:copy(<<$x>>, Datasize),
+ LOpts =
+ [{backlog,4},{reuseaddr,true},{ip,Addr},
+ binary,{active,false},
+ {recbuf,Bufsize},{sndbuf,Bufsize},{buffer,Bufsize}],
+ COpts =
+ [binary,{active,false},{ip,Addr},
+ {linger,{true,1}}, % 1 s
+ {send_timeout,500},
+ {recbuf,Bufsize},{sndbuf,Bufsize},{buffer,Bufsize}],
+ Dir = filename:dirname(code:which(?MODULE)),
+ {ok,ListenerNode} =
+ test_server:start_node(
+ ?UNIQ_NODE_NAME, slave, [{args,"-pa " ++ Dir}]),
+ Tester = self(),
+ Listener =
+ spawn(
+ ListenerNode,
+ fun () ->
+ {ok,L} = gen_tcp:listen(0, LOpts),
+ {ok,LPort} = inet:port(L),
+ Tester ! {self(),port,LPort},
+ {ok,A} = gen_tcp:accept(L),
+ ok = gen_tcp:close(L),
+ receive
+ {Tester,stop} ->
+ ok = gen_tcp:close(A)
+ end
+ end),
+ ListenerMref = monitor(process, Listener),
+ LPort = receive {Listener,port,P} -> P end,
+ {ok,C} = gen_tcp:connect(Addr, LPort, COpts, infinity),
+ {ok,ReadCOpts} = inet:getopts(C, [recbuf,sndbuf,buffer]),
+ ct:pal("ReadCOpts ~p~n", [ReadCOpts]),
+ %%
+ %% Fill the buffers
+ ct:pal("Sending ~p bytes~n", [Datasize]),
+ ok = gen_tcp:send(C, Blob),
+ ct:pal("Sent ~p bytes~n", [Datasize]),
+ %% Spawn the Closer,
+ %% try to ensure that the close call is in progress
+ %% before the owner proceeds with sending
+ Owner = self(),
+ {_Closer,CloserMref} =
+ spawn_opt(
+ fun () ->
+ Owner ! {tref, erlang:start_timer(50, Owner, closing)},
+ ct:pal("Calling gen_tcp:close(C)~n"),
+ try gen_tcp:close(C) of
+ Result ->
+ ct:pal("gen_tcp:close(C) -> ~p~n", [Result]),
+ ok = Result
+ catch
+ Class:Reason:Stacktrace ->
+ ct:pal(
+ "gen_tcp:close(C) >< ~p:~p~n ~p~n",
+ [Class,Reason,Stacktrace]),
+ erlang:raise(Class, Reason, Stacktrace)
+ end
+ end, [link,monitor]),
+ receive
+ {tref,Tref} ->
+ receive {timeout,Tref,_} -> ok end,
+ ct:pal("Sending ~p bytes again~n", [Datasize]),
+ %% Now should the close be in progress...
+ %% All buffers are full, remote end is not reading,
+ %% and the send timeout is 1 s so this will timeout:
+ {error,timeout} = gen_tcp:send(C, Blob),
+ ct:pal("Sending ~p bytes again timed out~n", [Datasize]),
+ ok = inet:setopts(C, [{send_timeout,10000}]),
+ %% There is a hidden timeout here. Port close is sampled
+ %% every 5 s by prim_inet:send_recv_reply.
+ %% Linger is 3 s so the Closer will finish this send:
+ ct:pal("Sending ~p bytes with 10 s timeout~n", [Datasize]),
+ {error,closed} = gen_tcp:send(C, Blob),
+ ct:pal("Sending ~p bytes with 10 s timeout was closed~n",
+ [Datasize]),
+ normal = wait(CloserMref),
+ ct:pal("The Closer has exited~n"),
+ Listener ! {Tester,stop},
+ receive {'DOWN',ListenerMref,_,_,_} -> ok end,
+ ct:pal("The Listener has exited~n"),
+ test_server:stop_node(ListenerNode),
+ ok
+ end.
+
+wait(Mref) ->
+ receive {'DOWN',Mref,_,_,Reason} -> Reason end.
+
+%% OTP-15536
+%% Test that send error works correctly for delay_send
+delay_send_error(_Config) ->
+ {ok, LS} = gen_tcp:listen(0, [{reuseaddr, true}, {packet, 1}, {active, false}]),
+ {ok,{{0,0,0,0},PortNum}}=inet:sockname(LS),
+ P = spawn_link(
+ fun() ->
+ {ok, S} = gen_tcp:accept(LS),
+ receive die -> gen_tcp:close(S) end
+ end),
+ erlang:monitor(process, P),
+ {ok, S} = gen_tcp:connect("localhost", PortNum,
+ [{packet, 1}, {active, false}, {delay_send, true}]),
+
+ %% Do a couple of sends first to see that it works
+ ok = gen_tcp:send(S, "hello"),
+ ok = gen_tcp:send(S, "hello"),
+ ok = gen_tcp:send(S, "hello"),
+
+ %% Make the receiver close
+ P ! die,
+ receive _Down -> ok end,
+
+ ok = gen_tcp:send(S, "hello"),
+ timer:sleep(500), %% Sleep in order for delay_send to have time to trigger
+
+ %% This used to result in a double free
+ {error, closed} = gen_tcp:send(S, "hello").
diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl
index aa616d43d6..af9985de45 100644
--- a/lib/kernel/test/gen_udp_SUITE.erl
+++ b/lib/kernel/test/gen_udp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -34,8 +34,9 @@
-export([init_per_testcase/2, end_per_testcase/2]).
-export([send_to_closed/1, active_n/1,
- buffer_size/1, binary_passive_recv/1, bad_address/1,
+ buffer_size/1, binary_passive_recv/1, max_buffer_size/1, bad_address/1,
read_packets/1, open_fd/1, connect/1, implicit_inet6/1,
+ recvtos/1, recvtosttl/1, recvttl/1, recvtclass/1,
local_basic/1, local_unbound/1,
local_fdopen/1, local_fdopen_unbound/1, local_abstract/1]).
@@ -44,9 +45,10 @@ suite() ->
{timetrap,{minutes,1}}].
all() ->
- [send_to_closed, buffer_size, binary_passive_recv,
+ [send_to_closed, buffer_size, binary_passive_recv, max_buffer_size,
bad_address, read_packets, open_fd, connect,
implicit_inet6, active_n,
+ recvtos, recvtosttl, recvttl, recvtclass,
{group, local}].
groups() ->
@@ -237,6 +239,14 @@ buffer_size_server_recv(Socket, IP, Port, Cnt) ->
end.
+%%-------------------------------------------------------------
+%% OTP-15206: Keep buffer small for udp
+%%-------------------------------------------------------------
+max_buffer_size(Config) when is_list(Config) ->
+ {ok, Socket} = gen_udp:open(0, [binary]),
+ ok = inet:setopts(Socket,[{recbuf, 1 bsl 20}]),
+ {ok, [{buffer, 65536}]} = inet:getopts(Socket,[buffer]),
+ gen_udp:close(Socket).
%%-------------------------------------------------------------
%% OTP-3823 gen_udp:recv does not return address in binary mode
@@ -288,58 +298,56 @@ bad_address(Config) when is_list(Config) ->
%%
%% Starts a slave node that on command sends a bunch of messages
%% to our UDP port. The receiving process just receives and
-%% ignores the incoming messages, but counts them.
-%% A tracing process traces the receiving process for
-%% 'receive' and scheduling events. From the trace,
-%% message contents is verified; and, how many messages
-%% are received per in/out scheduling, which should be
-%% the same as the read_packets parameter.
-%%
-%% What happens on the SMP emulator remains to be seen...
-%%
+%% ignores the incoming messages.
+%% A tracing process traces the receiving port for
+%% 'send' and scheduling events. From the trace,
+%% how many messages are received per in/out scheduling,
+%% which should never be more than the read_packet parameter.
%% OTP-6249 UDP option for number of packet reads.
read_packets(Config) when is_list(Config) ->
- case erlang:system_info(smp_support) of
- false ->
- read_packets_1();
- true ->
- %% We would need some new sort of tracing to test this
- %% option reliably in an SMP emulator.
- {skip,"SMP emulator"}
- end.
-
-read_packets_1() ->
N1 = 5,
- N2 = 7,
+ N2 = 1,
+ Msgs = 30000,
{ok,R} = gen_udp:open(0, [{read_packets,N1}]),
{ok,RP} = inet:port(R),
{ok,Node} = start_node(gen_udp_SUITE_read_packets),
Die = make_ref(),
- Loop = erlang:spawn_link(fun () -> infinite_loop(Die) end),
%%
- Msgs1 = [erlang:integer_to_list(M) || M <- lists:seq(1, N1*3)],
- [V1|_] = read_packets_test(R, RP, Msgs1, Node),
+ {V1, Trace1} = read_packets_test(R, RP, Msgs, Node),
{ok,[{read_packets,N1}]} = inet:getopts(R, [read_packets]),
%%
ok = inet:setopts(R, [{read_packets,N2}]),
- Msgs2 = [erlang:integer_to_list(M) || M <- lists:seq(1, N2*3)],
- [V2|_] = read_packets_test(R, RP, Msgs2, Node),
+ {V2, Trace2} = read_packets_test(R, RP, Msgs, Node),
{ok,[{read_packets,N2}]} = inet:getopts(R, [read_packets]),
%%
stop_node(Node),
- Mref = erlang:monitor(process, Loop),
- Loop ! Die,
- receive
- {'DOWN',Mref,_,_, normal} ->
- case {V1,V2} of
- {N1,N2} ->
- ok;
- _ when V1 =/= N1, V2 =/= N2 ->
- ok
- end
+ ct:log("N1=~p, V1=~p vs N2=~p, V2=~p",[N1,V1,N2,V2]),
+
+ dump_terms(Config, "trace1.terms", Trace2),
+ dump_terms(Config, "trace2.terms", Trace2),
+
+ %% Because of the inherit racy-ness of the feature it is
+ %% hard to test that it behaves correctly.
+ %% Right now (OTP 21) a port task takes 5% of the
+ %% allotted port task reductions to execute, so
+ %% the max number of executions a port is allowed to
+ %% do before being re-scheduled is N * 20
+
+ if
+ V1 > (N1 * 20) ->
+ ct:fail("Got ~p msgs, max was ~p", [V1, N1]);
+ V2 > (N2 * 20) ->
+ ct:fail("Got ~p msgs, max was ~p", [V2, N2]);
+ true ->
+ ok
end.
+dump_terms(Config, Name, Terms) ->
+ FName = filename:join(proplists:get_value(priv_dir, Config),Name),
+ file:write_file(FName, term_to_binary(Terms)),
+ ct:log("Logged terms to ~s",[FName]).
+
infinite_loop(Die) ->
receive
Die ->
@@ -350,7 +358,6 @@ infinite_loop(Die) ->
end.
read_packets_test(R, RP, Msgs, Node) ->
- Len = length(Msgs),
Receiver = self(),
Tracer =
spawn_link(
@@ -375,24 +382,24 @@ read_packets_test(R, RP, Msgs, Node) ->
[link,{priority,high}]),
receive
{Sender,{port,SP}} ->
- erlang:trace(self(), true,
- [running,'receive',{tracer,Tracer}]),
+ erlang:trace(R, true,
+ [running_ports,'send',{tracer,Tracer}]),
erlang:yield(),
Sender ! {Receiver,go},
- read_packets_recv(Len),
- erlang:trace(self(), false, [all]),
+ read_packets_recv(Msgs),
+ erlang:trace(R, false, [all]),
Tracer ! {Receiver,get_trace},
receive
{Tracer,{trace,Trace}} ->
- read_packets_verify(R, SP, Msgs, Trace)
+ {read_packets_verify(R, SP, Trace), Trace}
end
end.
-read_packets_send(S, RP, [Msg|Msgs]) ->
- ok = gen_udp:send(S, localhost, RP, Msg),
- read_packets_send(S, RP, Msgs);
-read_packets_send(_S, _RP, []) ->
- ok.
+read_packets_send(_S, _RP, 0) ->
+ ok;
+read_packets_send(S, RP, Msgs) ->
+ ok = gen_udp:send(S, localhost, RP, "UDP FLOOOOOOD"),
+ read_packets_send(S, RP, Msgs - 1).
read_packets_recv(0) ->
ok;
@@ -404,23 +411,24 @@ read_packets_recv(N) ->
timeout
end.
-read_packets_verify(R, SP, Msg, Trace) ->
- lists:reverse(
- lists:sort(read_packets_verify(R, SP, Msg, Trace, 0))).
-
-read_packets_verify(R, SP, Msgs, [{trace,Self,OutIn,_}|Trace], M)
- when Self =:= self(), OutIn =:= out;
- Self =:= self(), OutIn =:= in ->
- push(M, read_packets_verify(R, SP, Msgs, Trace, 0));
-read_packets_verify(R, SP, [Msg|Msgs],
- [{trace,Self,'receive',{udp,R,{127,0,0,1},SP,Msg}}
- |Trace], M)
+read_packets_verify(R, SP, Trace) ->
+ [Max | _] = Pkts = lists:reverse(lists:sort(read_packets_verify(R, SP, Trace, 0))),
+ ct:pal("~p",[lists:sublist(Pkts,10)]),
+ Max.
+
+read_packets_verify(R, SP, [{trace,R,OutIn,_}|Trace], M)
+ when OutIn =:= out; OutIn =:= in ->
+ push(M, read_packets_verify(R, SP, Trace, 0));
+read_packets_verify(R, SP, [{trace, R,'receive',timeout}|Trace], M) ->
+ push(M, read_packets_verify(R, SP, Trace, 0));
+read_packets_verify(R, SP,
+ [{trace,R,'send',{udp,R,{127,0,0,1},SP,_Msg}, Self} | Trace], M)
when Self =:= self() ->
- read_packets_verify(R, SP, Msgs, Trace, M+1);
-read_packets_verify(_R, _SP, [], [], M) ->
+ read_packets_verify(R, SP, Trace, M+1);
+read_packets_verify(_R, _SP, [], M) ->
push(M, []);
-read_packets_verify(_R, _SP, Msgs, Trace, M) ->
- ct:fail({read_packets_verify,mismatch,Msgs,Trace,M}).
+read_packets_verify(_R, _SP, Trace, M) ->
+ ct:fail({read_packets_verify,mismatch,Trace,M}).
push(0, Vs) ->
Vs;
@@ -566,6 +574,168 @@ active_n(Config) when is_list(Config) ->
ok.
+
+recvtos(_Config) ->
+ test_recv_opts(
+ inet, [{recvtos,tos,96}],
+ fun recvtos_ok/2).
+
+recvtosttl(_Config) ->
+ test_recv_opts(
+ inet, [{recvtos,tos,96},{recvttl,ttl,33}],
+ fun (OSType, OSVer) ->
+ recvtos_ok(OSType, OSVer) andalso recvttl_ok(OSType, OSVer)
+ end).
+
+recvttl(_Config) ->
+ test_recv_opts(
+ inet, [{recvttl,ttl,33}],
+ fun recvttl_ok/2).
+
+recvtclass(_Config) ->
+ {ok,IFs} = inet:getifaddrs(),
+ case
+ [Name ||
+ {Name,Opts} <- IFs,
+ lists:member({addr,{0,0,0,0,0,0,0,1}}, Opts)]
+ of
+ [_] ->
+ test_recv_opts(
+ inet6, [{recvtclass,tclass,224}],
+ fun recvtclass_ok/2);
+ [] ->
+ {skip,ipv6_not_supported,IFs}
+ end.
+
+%% These version numbers are just above the highest noted in daily tests
+%% where the test fails for a plausible reason, that is the lowest
+%% where we can expect that the test mighe succeed, so
+%% skip on platforms lower than this.
+%%
+%% On newer versions it might be fixed, but we'll see about that
+%% when machines with newer versions gets installed...
+%% If the test still fails for a plausible reason these
+%% version numbers simply should be increased.
+%% Or maybe we should change to only test on known good platforms?
+
+%% Using the option returns einval, so it is not implemented.
+recvtos_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {17,6,0});
+%% Using the option returns einval, so it is not implemented.
+recvtos_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0});
+%% Using the option returns einval, so it is not implemented.
+recvtos_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0});
+%%
+recvtos_ok({unix,_}, _) -> true;
+recvtos_ok(_, _) -> false.
+
+recvttl_ok({unix,_}, _) -> true;
+recvttl_ok(_, _) -> false.
+
+%% Using the option returns einval, so it is not implemented.
+recvtclass_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {9,9,0});
+recvtclass_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {2,6,11});
+%%
+recvtclass_ok({unix,_}, _) -> true;
+recvtclass_ok(_, _) -> false.
+
+semver_lt({X1,Y1,Z1}, {X2,Y2,Z2}) ->
+ if
+ X1 > X2 -> false;
+ X1 < X2 -> true;
+ Y1 > Y2 -> false;
+ Y1 < Y2 -> true;
+ Z1 > Z2 -> false;
+ Z1 < Z2 -> true;
+ true -> false
+ end;
+semver_lt(_, {_,_,_}) -> false.
+
+test_recv_opts(Family, Spec, OSFilter) ->
+ OSType = os:type(),
+ OSVer = os:version(),
+ case OSFilter(OSType, OSVer) of
+ true ->
+ io:format("Os: ~p, ~p~n", [OSType,OSVer]),
+ test_recv_opts(Family, Spec, OSType, OSVer);
+ false ->
+ {skip,{not_supported_for_os_version,{OSType,OSVer}}}
+ end.
+%%
+test_recv_opts(Family, Spec, _OSType, _OSVer) ->
+ Timeout = 5000,
+ RecvOpts = [RecvOpt || {RecvOpt,_,_} <- Spec],
+ TrueRecvOpts = [{RecvOpt,true} || {RecvOpt,_,_} <- Spec],
+ FalseRecvOpts = [{RecvOpt,false} || {RecvOpt,_,_} <- Spec],
+ Opts = [Opt || {_,Opt,_} <- Spec],
+ OptsVals = [{Opt,Val} || {_,Opt,Val} <- Spec],
+ TrueRecvOpts_OptsVals = TrueRecvOpts ++ OptsVals,
+ Addr =
+ case Family of
+ inet ->
+ {127,0,0,1};
+ inet6 ->
+ {0,0,0,0,0,0,0,1}
+ end,
+ %%
+ {ok,S1} =
+ gen_udp:open(0, [Family,binary,{active,false}|TrueRecvOpts]),
+ {ok,P1} = inet:port(S1),
+ {ok,TrueRecvOpts} = inet:getopts(S1, RecvOpts),
+ ok = inet:setopts(S1, FalseRecvOpts),
+ {ok,FalseRecvOpts} = inet:getopts(S1, RecvOpts),
+ ok = inet:setopts(S1, TrueRecvOpts_OptsVals),
+ {ok,TrueRecvOpts_OptsVals} = inet:getopts(S1, RecvOpts ++ Opts),
+ %%
+ {ok,S2} =
+ gen_udp:open(0, [Family,binary,{active,true}|FalseRecvOpts]),
+ {ok,P2} = inet:port(S2),
+ {ok,FalseRecvOpts_OptsVals2} = inet:getopts(S2, RecvOpts ++ Opts),
+ OptsVals2 = FalseRecvOpts_OptsVals2 -- FalseRecvOpts,
+ %%
+ ok = gen_udp:send(S2, Addr, P1, <<"abcde">>),
+ ok = gen_udp:send(S1, Addr, P2, <<"fghij">>),
+ {ok,{_,P2,OptsVals3,<<"abcde">>}} = gen_udp:recv(S1, 0, Timeout),
+ verify_sets_eq(OptsVals3, OptsVals2),
+ receive
+ {udp,S2,_,P1,<<"fghij">>} ->
+ ok;
+ Other1 ->
+ exit({unexpected,Other1})
+ after Timeout ->
+ exit(timeout)
+ end,
+ %%
+ ok = inet:setopts(S1, FalseRecvOpts),
+ {ok,FalseRecvOpts} = inet:getopts(S1, RecvOpts),
+ ok = inet:setopts(S2, TrueRecvOpts),
+ {ok,TrueRecvOpts} = inet:getopts(S2, RecvOpts),
+ %%
+ ok = gen_udp:send(S2, Addr, P1, <<"klmno">>),
+ ok = gen_udp:send(S1, Addr, P2, <<"pqrst">>),
+ {ok,{_,P2,<<"klmno">>}} = gen_udp:recv(S1, 0, Timeout),
+ receive
+ {udp,S2,_,P1,OptsVals4,<<"pqrst">>} ->
+ verify_sets_eq(OptsVals4, OptsVals);
+ Other2 ->
+ exit({unexpected,Other2})
+ after Timeout ->
+ exit(timeout)
+ end,
+ ok = gen_udp:close(S1),
+ ok = gen_udp:close(S2),
+%% exit({{OSType,OSVer},success}), % In search for the truth
+ ok.
+
+verify_sets_eq(L1, L2) ->
+ L = lists:sort(L1),
+ case lists:sort(L2) of
+ L ->
+ ok;
+ _ ->
+ exit({sets_neq,L1,L2})
+ end.
+
+
local_basic(_Config) ->
SFile = local_filename(server),
SAddr = {local,bin_filename(SFile)},
@@ -757,9 +927,9 @@ ok({ok,V}) -> V;
ok(NotOk) ->
try throw(not_ok)
catch
- Thrown ->
+ throw:Thrown:Stacktrace ->
erlang:raise(
- error, {Thrown, NotOk}, tl(erlang:get_stacktrace()))
+ error, {Thrown, NotOk}, tl(Stacktrace))
end.
diff --git a/lib/kernel/test/global_SUITE.erl b/lib/kernel/test/global_SUITE.erl
index 0e7b7adc47..8eab36e308 100644
--- a/lib/kernel/test/global_SUITE.erl
+++ b/lib/kernel/test/global_SUITE.erl
@@ -1383,7 +1383,7 @@ ring(Config) when is_list(Config) ->
rpc_cast(Cp8, ?MODULE, single_node, [Time, Cp7, Config]),
%% sleep to make the partitioned net ready
- ct:sleep(Time - msec()),
+ sleep(Time - msec()),
pong = net_adm:ping(Cp0),
pong = net_adm:ping(Cp1),
@@ -1466,7 +1466,7 @@ simple_ring(Config) when is_list(Config) ->
rpc_cast(Cp5, ?MODULE, single_node, [Time, Cp4, Config]),
%% sleep to make the partitioned net ready
- ct:sleep(Time - msec()),
+ sleep(Time - msec()),
pong = net_adm:ping(Cp0),
pong = net_adm:ping(Cp1),
@@ -1542,7 +1542,7 @@ line(Config) when is_list(Config) ->
rpc_cast(Cp8, ?MODULE, single_node, [Time, Cp7, Config]),
%% Sleep to make the partitioned net ready
- ct:sleep(Time - msec()),
+ sleep(Time - msec()),
pong = net_adm:ping(Cp0),
pong = net_adm:ping(Cp1),
@@ -1626,7 +1626,7 @@ simple_line(Config) when is_list(Config) ->
rpc_cast(Cp5, ?MODULE, single_node, [Time, Cp4, Config]),
%% sleep to make the partitioned net ready
- ct:sleep(Time - msec()),
+ sleep(Time - msec()),
pong = net_adm:ping(Cp0),
pong = net_adm:ping(Cp1),
@@ -3555,7 +3555,7 @@ single_node(Time, Node, Config) ->
lists:foreach(fun(N) -> _ = erlang:disconnect_node(N) end, nodes()),
?UNTIL(get_known(node()) =:= [node()]),
spawn(?MODULE, init_2, []),
- ct:sleep(Time - msec()),
+ sleep(Time - msec()),
net_adm:ping(Node).
init_2() ->
@@ -4009,13 +4009,6 @@ collect_nodes(N, Max) ->
[Node | collect_nodes(N+1, Max)]
end.
-only_element(_E, []) ->
- true;
-only_element(E, [E|R]) ->
- only_element(E, R);
-only_element(_E, _) ->
- false.
-
exit_p(Pid) ->
Ref = erlang:monitor(process, Pid),
Pid ! die,
@@ -4038,6 +4031,11 @@ wait_for_exit_fast(Pid) ->
ok
end.
+sleep(Time) when Time > 0 ->
+ ct:sleep(Time);
+sleep(_Time) ->
+ ok.
+
check_everywhere(Nodes, Name, Config) ->
?UNTIL(begin
case rpc:multicall(Nodes, global, whereis_name, [Name]) of
@@ -4162,10 +4160,10 @@ rpc_cast(Node, Module, Function, Args, File) ->
%% The emulator now ensures that the node has been removed from
%% nodes().
-rpc_disconnect_node(Node, DisconnectedNode, _Config) ->
- True = rpc:call(Node, erlang, disconnect_node, [DisconnectedNode]),
- False = lists:member(DisconnectedNode, rpc:call(Node, erlang, nodes, [])),
- {true, false} = {True, False}.
+rpc_disconnect_node(Node, DisconnectedNode, Config) ->
+ true = rpc:call(Node, erlang, disconnect_node, [DisconnectedNode]),
+ ?UNTIL
+ (not lists:member(DisconnectedNode, rpc:call(Node, erlang, nodes, []))).
%%%
%%% Utility
diff --git a/lib/kernel/test/heart_SUITE.erl b/lib/kernel/test/heart_SUITE.erl
index 45032faf6d..f5ca6d0e1d 100644
--- a/lib/kernel/test/heart_SUITE.erl
+++ b/lib/kernel/test/heart_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -168,7 +168,7 @@ reboot(Config) when is_list(Config) ->
{ok, Node} = start_check(slave, ?UNIQ_NODE_NAME),
ok = rpc:call(Node, heart, set_cmd,
- [atom_to_list(lib:progname()) ++
+ [ct:get_progname() ++
" -noshell -heart " ++ name(Node) ++ "&"]),
rpc:call(Node, init, reboot, []),
receive
@@ -203,7 +203,7 @@ node_start_immediately_after_crash_test(Config) when is_list(Config) ->
[{"ERL_CRASH_DUMP_SECONDS", "0"}]),
ok = rpc:call(Node, heart, set_cmd,
- [atom_to_list(lib:progname()) ++
+ [ct:get_progname() ++
" -noshell -heart " ++ name(Node) ++ "&"]),
Mod = exhaust_atoms,
@@ -254,7 +254,7 @@ node_start_soon_after_crash_test(Config) when is_list(Config) ->
[{"ERL_CRASH_DUMP_SECONDS", "10"}]),
ok = rpc:call(Node, heart, set_cmd,
- [atom_to_list(lib:progname()) ++
+ [ct:get_progname() ++
" -noshell -heart " ++ name(Node) ++ "&"]),
Mod = exhaust_atoms,
@@ -309,7 +309,7 @@ set_cmd(Config) when is_list(Config) ->
clear_cmd(Config) when is_list(Config) ->
{ok, Node} = start_check(slave, ?UNIQ_NODE_NAME),
ok = rpc:call(Node, heart, set_cmd,
- [atom_to_list(lib:progname()) ++
+ [ct:get_progname() ++
" -noshell -heart " ++ name(Node) ++ "&"]),
rpc:call(Node, init, reboot, []),
receive
@@ -346,9 +346,16 @@ clear_cmd(Config) when is_list(Config) ->
get_cmd(Config) when is_list(Config) ->
{ok, Node} = start_check(slave, ?UNIQ_NODE_NAME),
- Cmd = "test",
- ok = rpc:call(Node, heart, set_cmd, [Cmd]),
- {ok, Cmd} = rpc:call(Node, heart, get_cmd, []),
+
+ ShortCmd = "test",
+ ok = rpc:call(Node, heart, set_cmd, [ShortCmd]),
+ {ok, ShortCmd} = rpc:call(Node, heart, get_cmd, []),
+
+ %% This would hang prior to OTP-15024 being fixed.
+ LongCmd = [$a || _ <- lists:seq(1, 160)],
+ ok = rpc:call(Node, heart, set_cmd, [LongCmd]),
+ {ok, LongCmd} = rpc:call(Node, heart, get_cmd, []),
+
stop_node(Node),
ok.
diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl
index ba0d075ef2..44ec7e7076 100644
--- a/lib/kernel/test/inet_SUITE.erl
+++ b/lib/kernel/test/inet_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("kernel/include/inet.hrl").
+-include_lib("kernel/src/inet_res.hrl").
-include_lib("kernel/src/inet_dns.hrl").
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
@@ -34,13 +35,14 @@
ipv4_to_ipv6/0, ipv4_to_ipv6/1,
host_and_addr/0, host_and_addr/1,
t_gethostnative/1,
- gethostnative_parallell/1, cname_loop/1,
+ gethostnative_parallell/1, cname_loop/1, missing_hosts_reload/1,
gethostnative_soft_restart/0, gethostnative_soft_restart/1,
gethostnative_debug_level/0, gethostnative_debug_level/1,
lookup_bad_search_option/1,
getif/1,
getif_ifr_name_overflow/1,getservbyname_overflow/1, getifaddrs/1,
- parse_strict_address/1, simple_netns/1, simple_netns_open/1,
+ parse_strict_address/1, ipv4_mapped_ipv6_address/1,
+ simple_netns/1, simple_netns_open/1,
simple_bind_to_device/1, simple_bind_to_device_open/1]).
-export([get_hosts/1, get_ipv6_hosts/1, parse_hosts/1, parse_address/1,
@@ -55,7 +57,7 @@ all() ->
[t_gethostbyaddr, t_gethostbyname, t_getaddr,
t_gethostbyaddr_v6, t_gethostbyname_v6, t_getaddr_v6,
ipv4_to_ipv6, host_and_addr, {group, parse},
- t_gethostnative, gethostnative_parallell, cname_loop,
+ t_gethostnative, gethostnative_parallell, cname_loop, missing_hosts_reload,
gethostnative_debug_level, gethostnative_soft_restart,
lookup_bad_search_option,
getif, getif_ifr_name_overflow, getservbyname_overflow,
@@ -96,7 +98,7 @@ end_per_group(_GroupName, Config) ->
init_per_testcase(lookup_bad_search_option, Config) ->
Db = inet_db,
Key = res_lookup,
- %% The bad option can not enter through inet_db:set_lookup/1,
+ %% The bad option cannot enter through inet_db:set_lookup/1,
%% but through e.g .inetrc.
Prev = ets:lookup(Db, Key),
ets:delete(Db, Key),
@@ -667,6 +669,26 @@ parse_strict_address(Config) when is_list(Config) ->
{ok, {3089,3106,23603,50240,0,0,119,136}} =
inet:parse_strict_address("c11:0c22:5c33:c440::077:0088").
+ipv4_mapped_ipv6_address(Config) when is_list(Config) ->
+ {D1,D2,D3,D4} = IPv4Address =
+ {rand:uniform(256) - 1,
+ rand:uniform(256) - 1,
+ rand:uniform(256) - 1,
+ rand:uniform(256) - 1},
+ E7 = (D1 bsl 8) bor D2,
+ E8 = (D3 bsl 8) bor D4,
+ io:format("IPv4Address: ~p.~n", [IPv4Address]),
+ {0,0,0,0,0,65535,E7,E8} = inet:ipv4_mapped_ipv6_address(IPv4Address),
+ IPv6Address =
+ {rand:uniform(65536) - 1,
+ rand:uniform(65536) - 1,
+ rand:uniform(65536) - 1,
+ rand:uniform(65536) - 1,
+ rand:uniform(65536) - 1,
+ rand:uniform(65536) - 1, E7, E8},
+ IPv4Address = inet:ipv4_mapped_ipv6_address(IPv6Address),
+ ok.
+
t_gethostnative(Config) when is_list(Config) ->
%% this will result in 26 bytes sent which causes problem in Windows
%% if the port-program has not assured stdin to be read in BINARY mode
@@ -819,6 +841,32 @@ cname_loop(Config) when is_list(Config) ->
ok.
+%% Test that hosts file gets reloaded correctly in case when it
+% was missing during initial startup
+missing_hosts_reload(Config) when is_list(Config) ->
+ RootDir = proplists:get_value(priv_dir,Config),
+ HostsFile = filename:join(RootDir, atom_to_list(?MODULE) ++ ".hosts"),
+ InetRc = filename:join(RootDir, "inetrc"),
+ ok = file:write_file(InetRc, "{hosts_file, \"" ++ HostsFile ++ "\"}.\n"),
+ {error, enoent} = file:read_file_info(HostsFile),
+ % start a node
+ Pa = filename:dirname(code:which(?MODULE)),
+ {ok, TestNode} = test_server:start_node(?MODULE, slave,
+ [{args, "-pa " ++ Pa ++ " -kernel inetrc '\"" ++ InetRc ++ "\"'"}]),
+ % ensure it has our RC
+ Rc = rpc:call(TestNode, inet_db, get_rc, []),
+ {hosts_file, HostsFile} = lists:keyfind(hosts_file, 1, Rc),
+ % ensure it does not resolve
+ {error, nxdomain} = rpc:call(TestNode, inet_hosts, gethostbyname, ["somehost"]),
+ % write hosts file
+ ok = file:write_file(HostsFile, "1.2.3.4 somehost"),
+ % wait for cached timestamp to expire
+ timer:sleep(?RES_FILE_UPDATE_TM * 1000 + 100),
+ % ensure it DOES resolve
+ {ok,{hostent,"somehost",[],inet,4,[{1,2,3,4}]}} =
+ rpc:call(TestNode, inet_hosts, gethostbyname, ["somehost"]),
+ % cleanup
+ true = test_server:stop_node(TestNode).
%% These must be run in the whole suite since they need
%% the host list and require inet_gethost_native to be started.
@@ -1039,28 +1087,26 @@ getservbyname_overflow(Config) when is_list(Config) ->
getifaddrs(Config) when is_list (Config) ->
{ok,IfAddrs} = inet:getifaddrs(),
io:format("IfAddrs = ~p.~n", [IfAddrs]),
- case
- {os:type(),
- [If ||
- {If,Opts} <- IfAddrs,
- lists:keymember(hwaddr, 1, Opts)]} of
- {{unix,sunos},[]} -> ok;
- {OT,[]} ->
- ct:fail({should_have_hwaddr,OT});
- _ -> ok
+ case [If || {If,Opts} <- IfAddrs, lists:keymember(hwaddr, 1, Opts)] of
+ [] ->
+ case os:type() of
+ {unix,sunos} -> ok;
+ OT ->
+ ct:fail({should_have_hwaddr,OT})
+ end;
+ [_|_] -> ok
end,
- Addrs =
- [element(1, A) || A <- ifaddrs(IfAddrs)],
+ Addrs = ifaddrs(IfAddrs),
io:format("Addrs = ~p.~n", [Addrs]),
[check_addr(Addr) || Addr <- Addrs],
ok.
-check_addr({addr,Addr})
+check_addr(Addr)
when tuple_size(Addr) =:= 8,
element(1, Addr) band 16#FFC0 =:= 16#FE80 ->
io:format("Addr: ~p link local; SKIPPED!~n", [Addr]),
ok;
-check_addr({addr,Addr}) ->
+check_addr(Addr) ->
io:format("Addr: ~p.~n", [Addr]),
Ping = "ping",
Pong = "pong",
@@ -1076,78 +1122,86 @@ check_addr({addr,Addr}) ->
ok = gen_tcp:close(S2),
ok = gen_tcp:close(L).
--record(ifopts, {name,flags,addrs=[],hwaddr}).
-
-ifaddrs([]) -> [];
-ifaddrs([{If,Opts}|IOs]) ->
- #ifopts{flags=F} = Ifopts = check_ifopts(Opts, #ifopts{name=If}),
- case F of
- {flags,Flags} ->
- case lists:member(running, Flags) of
- true -> Ifopts#ifopts.addrs;
- false -> []
- end ++ ifaddrs(IOs);
- undefined ->
- ifaddrs(IOs)
+ifaddrs(IfOpts) ->
+ IfMap = collect_ifopts(IfOpts),
+ ChkFun =
+ fun Self({{_,Flags} = Key, Opts}, ok) ->
+ Broadcast = lists:member(broadcast, Flags),
+ P2P = lists:member(pointtopoint, Flags),
+ case Opts of
+ [{addr,_},{netmask,_},{broadaddr,_}|Os]
+ when Broadcast ->
+ Self({Key, Os}, ok);
+ [{addr,_},{netmask,_},{dstaddr,_}|Os]
+ when P2P ->
+ Self({Key, Os}, ok);
+ [{addr,_},{netmask,_}|Os] ->
+ Self({Key, Os}, ok);
+ [{hwaddr,_}|Os] ->
+ Self({Key, Os}, ok);
+ [] ->
+ ok
+ end
+ end,
+ fold_ifopts(ChkFun, ok, IfMap),
+ AddrsFun =
+ fun ({{_,Flags}, Opts}, Acc) ->
+ case
+ lists:member(running, Flags)
+ andalso (not lists:member(pointtopoint, Flags))
+ of
+ true ->
+ lists:reverse(
+ [Addr || {addr,Addr} <- Opts],
+ Acc);
+ false ->
+ Acc
+ end
+ end,
+ fold_ifopts(AddrsFun, [], IfMap).
+
+collect_ifopts(IfOpts) ->
+ collect_ifopts(IfOpts, #{}).
+%%
+collect_ifopts(IfOpts, IfMap) ->
+ case IfOpts of
+ [{If,[{flags,Flags}|Opts]}|IfOs] ->
+ Key = {If,Flags},
+ case maps:is_key(Key, IfMap) of
+ true ->
+ ct:fail({unexpected_ifopts,IfOpts,IfMap});
+ false ->
+ collect_ifopts(IfOs, IfMap, Opts, Key, [])
+ end;
+ [] ->
+ IfMap;
+ _ ->
+ ct:fail({unexpected_ifopts,IfOpts,IfMap})
+ end.
+%%
+collect_ifopts(IfOpts, IfMap, Opts, Key, R) ->
+ case Opts of
+ [{flags,_}|_] ->
+ {If,_} = Key,
+ collect_ifopts(
+ [{If,Opts}|IfOpts], maps:put(Key, lists:reverse(R), IfMap));
+ [OptVal|Os] ->
+ collect_ifopts(IfOpts, IfMap, Os, Key, [OptVal|R]);
+ [] ->
+ collect_ifopts(IfOpts, maps:put(Key, lists:reverse(R), IfMap))
end.
-check_ifopts([], #ifopts{flags=F,addrs=Raddrs}=Ifopts) ->
- Addrs = lists:reverse(Raddrs),
- R = Ifopts#ifopts{addrs=Addrs},
- io:format("~p.~n", [R]),
- %% See how we did...
- {flags,Flags} = F,
- case lists:member(broadcast, Flags) of
- true ->
- [case A of
- {{addr,_},{netmask,_},{broadaddr,_}} ->
- A;
- {{addr,T},{netmask,_}} when tuple_size(T) =:= 8 ->
- A
- end || A <- Addrs];
- false ->
- case lists:member(pointtopoint, Flags) of
- true ->
- [case A of
- {{addr,_},{netmask,_},{dstaddr,_}} ->
- A
- end || A <- Addrs];
- false ->
- [case A of
- {{addr,_},{netmask,_}} ->
- A
- end || A <- Addrs]
- end
- end,
- R;
-check_ifopts([{flags,_}=F|Opts], #ifopts{flags=undefined}=Ifopts) ->
- check_ifopts(Opts, Ifopts#ifopts{flags=F});
-check_ifopts([{flags,_}=F|Opts], #ifopts{flags=Flags}=Ifopts) ->
- case F of
- Flags ->
- check_ifopts(Opts, Ifopts);
- _ ->
- ct:fail({multiple_flags,F,Ifopts})
- end;
-check_ifopts(
- [{addr,_}=A,{netmask,_}=N,{dstaddr,_}=D|Opts],
- #ifopts{addrs=Addrs}=Ifopts) ->
- check_ifopts(Opts, Ifopts#ifopts{addrs=[{A,N,D}|Addrs]});
-check_ifopts(
- [{addr,_}=A,{netmask,_}=N,{broadaddr,_}=B|Opts],
- #ifopts{addrs=Addrs}=Ifopts) ->
- check_ifopts(Opts, Ifopts#ifopts{addrs=[{A,N,B}|Addrs]});
-check_ifopts(
- [{addr,_}=A,{netmask,_}=N|Opts],
- #ifopts{addrs=Addrs}=Ifopts) ->
- check_ifopts(Opts, Ifopts#ifopts{addrs=[{A,N}|Addrs]});
-check_ifopts([{addr,_}=A|Opts], #ifopts{addrs=Addrs}=Ifopts) ->
- check_ifopts(Opts, Ifopts#ifopts{addrs=[{A}|Addrs]});
-check_ifopts([{hwaddr,Hwaddr}=H|Opts], #ifopts{hwaddr=undefined}=Ifopts)
- when is_list(Hwaddr) ->
- check_ifopts(Opts, Ifopts#ifopts{hwaddr=H});
-check_ifopts([{hwaddr,_}=H|_], #ifopts{}=Ifopts) ->
- ct:fail({multiple_hwaddrs,H,Ifopts}).
+fold_ifopts(Fun, Acc, IfMap) ->
+ fold_ifopts(Fun, Acc, IfMap, maps:keys(IfMap)).
+%%
+fold_ifopts(Fun, Acc, IfMap, Keys) ->
+ case Keys of
+ [Key|Ks] ->
+ Opts = maps:get(Key, IfMap),
+ fold_ifopts(Fun, Fun({Key,Opts}, Acc), IfMap, Ks);
+ [] ->
+ Acc
+ end.
%% Works just like lists:member/2, except that any {127,_,_,_} tuple
%% matches any other {127,_,_,_}. We do this to handle Linux systems
diff --git a/lib/kernel/test/inet_res_SUITE.erl b/lib/kernel/test/inet_res_SUITE.erl
index 6691ad9c06..6b545fa414 100644
--- a/lib/kernel/test/inet_res_SUITE.erl
+++ b/lib/kernel/test/inet_res_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -46,15 +46,16 @@
%% a temporary local nameserver BIND 8 or 9 that must be installed
%% on your machine.
%%
-%% For example, on Ubuntu 14.04, as root:
+%% For example, on Ubuntu 16.04 / 18.04, as root:
%% apt-get install bind9
%% Now, that is not enough since Apparmor will not allow
%% the nameserver daemon /usr/sbin/named to read from the test directory.
%% Assuming that you run tests in /ldisk/daily_build, and still on
-%% Ubuntu 14.04, make /usr/apparmor.d/local/usr.sbin.named contain:
+%% Ubuntu 14.04, make /etc/apparmor.d/local/usr.sbin.named contain:
%% /ldisk/daily_build/** r,
%% And yes; the trailing comma must be there...
-
+%% And yes; create the file if it does not exist.
+%% And yes; restart the apparmor daemon using "service apparmor restart"
suite() ->
@@ -217,10 +218,10 @@ proxy_start(TC, {NS,P}) ->
spawn_link(
fun () ->
try proxy_start(TC, NS, P, Parent, Tag)
- catch C:X ->
+ catch C:X:Stacktrace ->
io:format(
"~w: ~w:~p ~p~n",
- [self(),C,X,erlang:get_stacktrace()])
+ [self(),C,X,Stacktrace])
end
end),
receive {started,Tag,Port} ->
@@ -531,7 +532,7 @@ edns0(Config) when is_list(Config) ->
case os:version() of
{M,V,_} when M < 5; M == 5, V =< 8 ->
%% In our test park only known platform
- %% with an DNS resolver that can not do
+ %% with an DNS resolver that cannot do
%% EDNS0.
{comment,"No EDNS0"}
end
diff --git a/lib/kernel/test/inet_sockopt_SUITE.erl b/lib/kernel/test/inet_sockopt_SUITE.erl
index ada9c2689c..27ff74e309 100644
--- a/lib/kernel/test/inet_sockopt_SUITE.erl
+++ b/lib/kernel/test/inet_sockopt_SUITE.erl
@@ -110,9 +110,14 @@ simple(Config) when is_list(Config) ->
{S1,S2} = create_socketpair(Opt, Opt),
{ok,Opt} = inet:getopts(S1,OptTags),
{ok,Opt} = inet:getopts(S2,OptTags),
- COpt = [{X,case X of nodelay -> false;_ -> Y end} || {X,Y} <- Opt],
+ NoPushOpt = case os:type() of
+ {unix, Osname} when Osname =:= linux; Osname =:= freebsd -> {nopush, true};
+ {_,_} -> {nopush, false}
+ end,
+ COpt = [{X,case X of nodelay -> false;_ -> Y end} || {X,Y} <- [NoPushOpt|Opt]],
+ COptTags = [X || {X,_} <- COpt],
inet:setopts(S1,COpt),
- {ok,COpt} = inet:getopts(S1,OptTags),
+ {ok,COpt} = inet:getopts(S1,COptTags),
{ok,Opt} = inet:getopts(S2,OptTags),
gen_tcp:close(S1),
gen_tcp:close(S2),
diff --git a/lib/kernel/test/init_SUITE.erl b/lib/kernel/test/init_SUITE.erl
index 2b59eb2bfe..a0154b2694 100644
--- a/lib/kernel/test/init_SUITE.erl
+++ b/lib/kernel/test/init_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -295,11 +295,11 @@ is_real_system(KernelVsn, StdlibVsn) ->
%% before restart.
%% ------------------------------------------------
many_restarts() ->
- [{timetrap,{minutes,8}}].
+ [{timetrap,{minutes,16}}].
many_restarts(Config) when is_list(Config) ->
{ok, Node} = loose_node:start(init_test, "", ?DEFAULT_TIMEOUT_SEC),
- loop_restart(50,Node,rpc:call(Node,erlang,whereis,[error_logger])),
+ loop_restart(50,Node,rpc:call(Node,erlang,whereis,[logger])),
loose_node:stop(Node),
ok.
@@ -315,14 +315,14 @@ loop_restart(N,Node,EHPid) ->
loose_node:stop(Node),
ct:fail(not_stopping)
end,
- ok = wait_for(30, Node, EHPid),
- loop_restart(N-1,Node,rpc:call(Node,erlang,whereis,[error_logger])).
+ ok = wait_for(60, Node, EHPid),
+ loop_restart(N-1,Node,rpc:call(Node,erlang,whereis,[logger])).
wait_for(0,Node,_) ->
loose_node:stop(Node),
error;
wait_for(N,Node,EHPid) ->
- case rpc:call(Node, erlang, whereis, [error_logger]) of
+ case rpc:call(Node, erlang, whereis, [logger]) of
Pid when is_pid(Pid), Pid =/= EHPid ->
%% erlang:display(ok),
ok;
@@ -365,7 +365,10 @@ restart(Config) when is_list(Config) ->
%% Ok, the node is up, now the real test test begins.
erlang:monitor_node(Node, true),
SysProcs0 = rpc:call(Node, ?MODULE, find_system_processes, []),
- [InitPid, PurgerPid, LitCollectorPid, DirtyCodePid] = SysProcs0,
+ io:format("SysProcs0=~p~n", [SysProcs0]),
+ [InitPid, PurgerPid, LitCollectorPid,
+ DirtySigNPid, DirtySigHPid, DirtySigMPid,
+ PrimFilePid] = SysProcs0,
InitPid = rpc:call(Node, erlang, whereis, [init]),
PurgerPid = rpc:call(Node, erlang, whereis, [erts_code_purger]),
Procs = rpc:call(Node, erlang, processes, []),
@@ -381,7 +384,10 @@ restart(Config) when is_list(Config) ->
ok = wait_restart(30, Node),
SysProcs1 = rpc:call(Node, ?MODULE, find_system_processes, []),
- [InitPid1, PurgerPid1, LitCollectorPid1, DirtyCodePid1] = SysProcs1,
+ io:format("SysProcs1=~p~n", [SysProcs1]),
+ [InitPid1, PurgerPid1, LitCollectorPid1,
+ DirtySigNPid1, DirtySigHPid1, DirtySigMPid1,
+ PrimFilePid1] = SysProcs1,
%% Still the same init process!
InitPid1 = rpc:call(Node, erlang, whereis, [init]),
@@ -394,20 +400,22 @@ restart(Config) when is_list(Config) ->
PurgerP = pid_to_list(PurgerPid1),
%% and same literal area collector process!
- case LitCollectorPid of
- undefined -> undefined = LitCollectorPid1;
- _ ->
- LitCollectorP = pid_to_list(LitCollectorPid),
- LitCollectorP = pid_to_list(LitCollectorPid1)
- end,
-
- %% and same dirty process code checker process!
- case DirtyCodePid of
- undefined -> undefined = DirtyCodePid1;
- _ ->
- DirtyCodeP = pid_to_list(DirtyCodePid),
- DirtyCodeP = pid_to_list(DirtyCodePid1)
- end,
+ LitCollectorP = pid_to_list(LitCollectorPid),
+ LitCollectorP = pid_to_list(LitCollectorPid1),
+
+ %% and same normal dirty signal handler process!
+ DirtySigNP = pid_to_list(DirtySigNPid),
+ DirtySigNP = pid_to_list(DirtySigNPid1),
+ %% and same high dirty signal handler process!
+ DirtySigHP = pid_to_list(DirtySigHPid),
+ DirtySigHP = pid_to_list(DirtySigHPid1),
+ %% and same max dirty signal handler process!
+ DirtySigMP = pid_to_list(DirtySigMPid),
+ DirtySigMP = pid_to_list(DirtySigMPid1),
+
+ %% and same prim_file helper process!
+ PrimFileP = pid_to_list(PrimFilePid),
+ PrimFileP = pid_to_list(PrimFilePid1),
NewProcs0 = rpc:call(Node, erlang, processes, []),
NewProcs = NewProcs0 -- SysProcs1,
@@ -433,7 +441,10 @@ restart(Config) when is_list(Config) ->
-record(sys_procs, {init,
code_purger,
literal_collector,
- dirty_proc_checker}).
+ dirty_sig_handler_normal,
+ dirty_sig_handler_high,
+ dirty_sig_handler_max,
+ prim_file}).
find_system_processes() ->
find_system_procs(processes(), #sys_procs{}).
@@ -442,21 +453,36 @@ find_system_procs([], SysProcs) ->
[SysProcs#sys_procs.init,
SysProcs#sys_procs.code_purger,
SysProcs#sys_procs.literal_collector,
- SysProcs#sys_procs.dirty_proc_checker];
+ SysProcs#sys_procs.dirty_sig_handler_normal,
+ SysProcs#sys_procs.dirty_sig_handler_high,
+ SysProcs#sys_procs.dirty_sig_handler_max,
+ SysProcs#sys_procs.prim_file];
find_system_procs([P|Ps], SysProcs) ->
- case process_info(P, initial_call) of
- {initial_call,{otp_ring0,start,2}} ->
+ case process_info(P, [initial_call, priority]) of
+ [{initial_call,{erl_init,start,2}},_] ->
undefined = SysProcs#sys_procs.init,
find_system_procs(Ps, SysProcs#sys_procs{init = P});
- {initial_call,{erts_code_purger,start,0}} ->
+ [{initial_call,{erts_code_purger,start,0}},_] ->
undefined = SysProcs#sys_procs.code_purger,
find_system_procs(Ps, SysProcs#sys_procs{code_purger = P});
- {initial_call,{erts_literal_area_collector,start,0}} ->
+ [{initial_call,{erts_literal_area_collector,start,0}},_] ->
undefined = SysProcs#sys_procs.literal_collector,
find_system_procs(Ps, SysProcs#sys_procs{literal_collector = P});
- {initial_call,{erts_dirty_process_code_checker,start,0}} ->
- undefined = SysProcs#sys_procs.dirty_proc_checker,
- find_system_procs(Ps, SysProcs#sys_procs{dirty_proc_checker = P});
+ [{initial_call,{erts_dirty_process_signal_handler,start,0}},
+ {priority,normal}] ->
+ undefined = SysProcs#sys_procs.dirty_sig_handler_normal,
+ find_system_procs(Ps, SysProcs#sys_procs{dirty_sig_handler_normal = P});
+ [{initial_call,{erts_dirty_process_signal_handler,start,0}},
+ {priority,high}] ->
+ undefined = SysProcs#sys_procs.dirty_sig_handler_high,
+ find_system_procs(Ps, SysProcs#sys_procs{dirty_sig_handler_high = P});
+ [{initial_call,{erts_dirty_process_signal_handler,start,0}},
+ {priority,max}] ->
+ undefined = SysProcs#sys_procs.dirty_sig_handler_max,
+ find_system_procs(Ps, SysProcs#sys_procs{dirty_sig_handler_max = P});
+ [{initial_call,{prim_file,start,0}},_] ->
+ undefined = SysProcs#sys_procs.prim_file,
+ find_system_procs(Ps, SysProcs#sys_procs{prim_file = P});
_ ->
find_system_procs(Ps, SysProcs)
end.
diff --git a/lib/kernel/test/kernel.spec b/lib/kernel/test/kernel.spec
index 62afc9f97b..eaa17f3a59 100644
--- a/lib/kernel/test/kernel.spec
+++ b/lib/kernel/test/kernel.spec
@@ -2,3 +2,4 @@
{config, "../test_server/ts.unix.config"}.
{suites,"../kernel_test", all}.
+{skip_suites,"../kernel_test",[logger_stress_SUITE],"Benchmarks only"}.
diff --git a/lib/kernel/test/kernel_SUITE.erl b/lib/kernel/test/kernel_SUITE.erl
index da56359294..3e5ed855b5 100644
--- a/lib/kernel/test/kernel_SUITE.erl
+++ b/lib/kernel/test/kernel_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -30,14 +30,14 @@
-export([init_per_testcase/2, end_per_testcase/2]).
%% Test cases must be exported.
--export([app_test/1, appup_test/1]).
+-export([app_test/1, appup_test/1, refc/1]).
suite() ->
[{ct_hooks,[ts_install_cth]},
{timetrap,{minutes,2}}].
all() ->
- [app_test, appup_test].
+ [app_test, appup_test, refc].
groups() ->
[].
@@ -163,3 +163,68 @@ check_appup([Vsn|Vsns],Instrs,Expected) ->
end;
check_appup([],_,_) ->
ok.
+
+%%% Check that refc module handles the counters as expected
+refc(_Config) ->
+ Enable = fun(Enable) -> erlang:system_flag(scheduler_wall_time, Enable) end,
+ IsOn = fun() -> undefined /= erlang:statistics(scheduler_wall_time) end,
+ Tester = self(),
+ Loop = fun Loop() ->
+ receive
+ die -> normal;
+ {apply, Bool} ->
+ Res = Enable(Bool),
+ Tester ! {self(), Res},
+ Loop()
+ end
+ end,
+
+ %% Counter should be 0
+ false = Enable(false),
+
+ false = Enable(true),
+ true = Enable(true),
+ true = Enable(false),
+ true = Enable(false),
+
+ %% Counter should be 0
+ false = IsOn(),
+
+ P1 = spawn_link(Loop),
+ P1 ! {apply, true},
+ receive {P1, R1} -> false = R1 end,
+
+ %% P1 has turned it on counter should be one
+ true = IsOn(),
+ true = Enable(true),
+ true = Enable(false),
+ true = IsOn(),
+
+ P1 ! {apply, false},
+ receive {P1, R2} -> true = R2 end,
+ false = IsOn(),
+
+ P1 ! {apply, true},
+ receive {P1, R3} -> false = R3 end,
+ true = IsOn(),
+ true = Enable(false),
+
+
+ P1 ! die,
+ timer:sleep(100),
+ false = IsOn(),
+ false = Enable(false),
+
+ P2 = spawn_link(Loop),
+ P2 ! {apply, true},
+ receive {P2, R4} -> false = R4 end,
+ true = IsOn(),
+ P2 ! {apply, true},
+ receive {P2, R5} -> true = R5 end,
+ true = IsOn(),
+
+ P2 ! die,
+ timer:sleep(100),
+ false = IsOn(),
+
+ ok.
diff --git a/lib/kernel/test/kernel_bench.spec b/lib/kernel/test/kernel_bench.spec
index 8de60dae31..898ceb59e0 100644
--- a/lib/kernel/test/kernel_bench.spec
+++ b/lib/kernel/test/kernel_bench.spec
@@ -1 +1,3 @@
{groups,"../kernel_test",zlib_SUITE,[bench]}.
+{groups,"../kernel_test",file_SUITE,[bench]}.
+{suites,"../kernel_test",[logger_stress_SUITE]}.
diff --git a/lib/kernel/test/kernel_config_SUITE.erl b/lib/kernel/test/kernel_config_SUITE.erl
index 9a4578917d..57c44c2498 100644
--- a/lib/kernel/test/kernel_config_SUITE.erl
+++ b/lib/kernel/test/kernel_config_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,7 +21,8 @@
-include_lib("common_test/include/ct.hrl").
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2, sync/1]).
+-export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
+ start_distribution_false/1, sync/1]).
-export([init_per_suite/1, end_per_suite/1]).
@@ -30,7 +31,7 @@ suite() ->
{timetrap,{minutes,2}}].
all() ->
- [sync].
+ [sync, start_distribution_false].
groups() ->
[].
@@ -59,12 +60,9 @@ from(H, [H | T]) -> T;
from(H, [_ | T]) -> from(H, T);
from(_, []) -> [].
-%%-----------------------------------------------------------------
-%% Test suite for sync_nodes. This is quite tricky.
-%%
+%% Test sync_nodes. This is quite tricky.
%% Should be started in a CC view with:
%% erl -sname XXX where XX not in [cp1, cp2]
-%%-----------------------------------------------------------------
sync(Conf) when is_list(Conf) ->
%% Write a config file
Dir = proplists:get_value(priv_dir,Conf),
@@ -76,7 +74,7 @@ sync(Conf) when is_list(Conf) ->
%% Reset wall_clock
{T1,_} = erlang:statistics(wall_clock),
io:format("~p~n", [{t1, T1}]),
- Command = lists:concat([lib:progname(),
+ Command = lists:append([ct:get_progname(),
" -detached -sname cp1 ",
"-config ", Config,
" -env ERL_CRASH_DUMP erl_crash_dump.cp1"]),
@@ -106,9 +104,18 @@ wait_for_node(Node) ->
_Other -> wait_for_node(Node)
end.
-
stop_node(Node) ->
M = list_to_atom(lists:concat([Node,
[$@],
from($@,atom_to_list(node()))])),
rpc:cast(M, erlang, halt, []).
+
+start_distribution_false(Config) when is_list(Config) ->
+ %% When distribution is disabled, -sname/-name has no effect
+ Str = os:cmd(ct:get_progname()
+ ++ " -kernel start_distribution false"
+ ++ " -sname no_distribution"
+ ++ " -eval \"erlang:display(node())\""
+ ++ " -noshell -s erlang halt"),
+ "'nonode@nohost'" ++ _ = Str,
+ ok.
diff --git a/lib/kernel/test/logger.cover b/lib/kernel/test/logger.cover
new file mode 100644
index 0000000000..9691aa295e
--- /dev/null
+++ b/lib/kernel/test/logger.cover
@@ -0,0 +1,17 @@
+%% -*- erlang -*-
+{incl_mods,[error_logger,
+ logger,
+ logger_backend,
+ logger_config,
+ logger_disk_log_h,
+ logger_filters,
+ logger_formatter,
+ logger_handler_watcher,
+ logger_h_common,
+ logger_olp,
+ logger_proxy,
+ logger_server,
+ logger_simple_h,
+ logger_std_h,
+ logger_sup]}.
+
diff --git a/lib/kernel/test/logger.spec b/lib/kernel/test/logger.spec
new file mode 100644
index 0000000000..3aec37951d
--- /dev/null
+++ b/lib/kernel/test/logger.spec
@@ -0,0 +1,13 @@
+%% -*-erlang-*-
+{suites,"../kernel_test", [error_logger_SUITE,
+ error_logger_warn_SUITE,
+ logger_SUITE,
+ logger_disk_log_h_SUITE,
+ logger_env_var_SUITE,
+ logger_filters_SUITE,
+ logger_formatter_SUITE,
+ logger_legacy_SUITE,
+ logger_olp_SUITE,
+ logger_proxy_SUITE,
+ logger_simple_h_SUITE,
+ logger_std_h_SUITE]}.
diff --git a/lib/kernel/test/logger_SUITE.erl b/lib/kernel/test/logger_SUITE.erl
new file mode 100644
index 0000000000..035e5d8974
--- /dev/null
+++ b/lib/kernel/test/logger_SUITE.erl
@@ -0,0 +1,1390 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(logger_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("kernel/include/logger.hrl").
+-include_lib("kernel/src/logger_internal.hrl").
+
+-define(str,"Log from "++atom_to_list(?FUNCTION_NAME)++
+ ":"++integer_to_list(?LINE)).
+-define(map_rep,#{function=>?FUNCTION_NAME, line=>?LINE}).
+-define(keyval_rep,[{function,?FUNCTION_NAME}, {line,?LINE}]).
+
+-define(MY_LOC(N),#{mfa=>{?MODULE,?FUNCTION_NAME,?FUNCTION_ARITY},
+ file=>?FILE, line=>?LINE-N}).
+
+-define(TRY(X), my_try(fun() -> X end)).
+
+
+suite() ->
+ [{timetrap,{seconds,30}},
+ {ct_hooks,[logger_test_lib]}].
+
+init_per_suite(Config) ->
+ case logger:get_handler_config(?STANDARD_HANDLER) of
+ {ok,StdH} ->
+ ok = logger:remove_handler(?STANDARD_HANDLER),
+ [{default_handler,StdH}|Config];
+ _ ->
+ Config
+ end.
+
+end_per_suite(Config) ->
+ case ?config(default_handler,Config) of
+ #{module:=HMod} = HConfig ->
+ ok = logger:add_handler(?STANDARD_HANDLER,HMod,HConfig);
+ _ ->
+ ok
+ end.
+
+init_per_group(_Group, Config) ->
+ Config.
+
+end_per_group(_Group, _Config) ->
+ ok.
+
+init_per_testcase(_TestCase, Config) ->
+ PC = logger:get_primary_config(),
+ [{logger_config,PC}|Config].
+
+end_per_testcase(Case, Config) ->
+ try apply(?MODULE,Case,[cleanup,Config])
+ catch error:undef -> ok
+ end,
+ ok.
+
+groups() ->
+ [].
+
+all() ->
+ [start_stop,
+ add_remove_handler,
+ multiple_handlers,
+ add_remove_filter,
+ change_config,
+ set_formatter,
+ log_no_levels,
+ log_all_levels_api,
+ macros,
+ set_level,
+ set_module_level,
+ set_application_level,
+ cache_module_level,
+ format_report,
+ filter_failed,
+ handler_failed,
+ config_sanity_check,
+ log_failed,
+ emulator,
+ via_logger_process,
+ other_node,
+ compare_levels,
+ process_metadata,
+ app_config,
+ kernel_config,
+ pretty_print].
+
+start_stop(_Config) ->
+ S = whereis(logger),
+ true = is_pid(S),
+ ok.
+
+add_remove_handler(_Config) ->
+ register(callback_receiver,self()),
+ Hs0 = logger:get_handler_config(),
+ {error,{not_found,h1}} = logger:get_handler_config(h1),
+ ok = logger:add_handler(h1,?MODULE,#{}),
+ [add] = test_server:messages_get(),
+ Hs = logger:get_handler_config(),
+ Hs0 = lists:filter(fun(#{id:=h1}) -> false; (_) -> true end, Hs),
+ {ok,#{module:=?MODULE,level:=all,filters:=[],filter_default:=log}} = %defaults
+ logger:get_handler_config(h1),
+ ok = logger:set_handler_config(h1,filter_default,stop),
+ [changing_config] = test_server:messages_get(),
+ ?LOG_NOTICE("hello",[]),
+ ok = check_no_log(),
+ ok = logger:set_handler_config(h1,filter_default,log),
+ [changing_config] = test_server:messages_get(),
+ {ok,#{filter_default:=log}} = logger:get_handler_config(h1),
+ ?LOG_NOTICE("hello",[]),
+ ok = check_logged(notice,"hello",[],?MY_LOC(1)),
+ ok = logger:remove_handler(h1),
+ [remove] = test_server:messages_get(),
+ Hs0 = logger:get_handler_config(),
+ {error,{not_found,h1}} = logger:get_handler_config(h1),
+ {error,{not_found,h1}} = logger:remove_handler(h1),
+ logger:notice("hello",[]),
+ ok = check_no_log(),
+ ok.
+
+add_remove_handler(cleanup,_Config) ->
+ logger:remove_handler(h1),
+ ok.
+
+multiple_handlers(_Config) ->
+ ok = logger:add_handler(h1,?MODULE,#{level=>notice,filter_default=>log}),
+ ok = logger:add_handler(h2,?MODULE,#{level=>error,filter_default=>log}),
+ ?LOG_ERROR("hello",[]),
+ ok = check_logged(error,"hello",[],?MY_LOC(1)),
+ ok = check_logged(error,"hello",[],?MY_LOC(2)),
+ ?LOG_NOTICE("hello",[]),
+ ok = check_logged(notice,"hello",[],?MY_LOC(1)),
+ ok = check_no_log(),
+ ok.
+
+multiple_handlers(cleanup,_Config) ->
+ logger:remove_handler(h1),
+ logger:remove_handler(h2),
+ ok.
+
+add_remove_filter(_Config) ->
+ ok = logger:add_handler(h1,?MODULE,#{level=>notice,filter_default=>log}),
+ LF = {fun(Log,_) -> Log#{level=>error} end, []},
+ ok = logger:add_primary_filter(lf,LF),
+ {error,{already_exist,lf}} = logger:add_primary_filter(lf,LF),
+ {error,{already_exist,lf}} = logger:add_primary_filter(lf,{fun(Log,_) ->
+ Log
+ end, []}),
+ ?LOG_NOTICE("hello",[]),
+ ok = check_logged(error,"hello",[],?MY_LOC(1)),
+ ok = check_no_log(),
+
+ ok = logger:add_handler(h2,?MODULE,#{level=>notice,filter_default=>log}),
+ HF = {fun(#{level:=error}=Log,_) ->
+ Log#{level=>mylevel};
+ (_,_) ->
+ ignore
+ end,
+ []},
+ ok = logger:add_handler_filter(h1,hf,HF),
+ {error,{already_exist,hf}} = logger:add_handler_filter(h1,hf,HF),
+ {error,{already_exist,hf}} = logger:add_handler_filter(h1,hf,{fun(Log,_) ->
+ Log
+ end, []}),
+ ?LOG_NOTICE("hello",[]),
+ ok = check_logged(mylevel,"hello",[],?MY_LOC(1)),
+ ok = check_logged(error,"hello",[],?MY_LOC(2)),
+
+ ok = logger:remove_primary_filter(lf),
+ {error,{not_found,lf}} = logger:remove_primary_filter(lf),
+
+ ?LOG_NOTICE("hello",[]),
+ ok = check_logged(notice,"hello",[],?MY_LOC(1)),
+ ok = check_logged(notice,"hello",[],?MY_LOC(2)),
+
+ ?LOG_ERROR("hello",[]),
+ ok = check_logged(mylevel,"hello",[],?MY_LOC(1)),
+ ok = check_logged(error,"hello",[],?MY_LOC(2)),
+
+ ok = logger:remove_handler_filter(h1,hf),
+ {error,{not_found,hf}} = logger:remove_handler_filter(h1,hf),
+ ?LOG_NOTICE("hello",[]),
+ ok = check_logged(notice,"hello",[],?MY_LOC(1)),
+ ok = check_logged(notice,"hello",[],?MY_LOC(2)),
+
+ ?LOG_ERROR("hello",[]),
+ ok = check_logged(error,"hello",[],?MY_LOC(1)),
+ ok = check_logged(error,"hello",[],?MY_LOC(2)),
+ ok.
+
+add_remove_filter(cleanup,_Config) ->
+ logger:remove_primary_filter(lf),
+ logger:remove_handler(h1),
+ logger:remove_handler(h2),
+ ok.
+
+change_config(_Config) ->
+ %% Overwrite handler config - check that defaults are added
+ {error,{not_found,h1}} = logger:set_handler_config(h1,#{}),
+ ok = logger:add_handler(h1,?MODULE,#{level=>notice,custom=>custom}),
+ {ok,#{module:=?MODULE,level:=notice,filter_default:=log,custom:=custom}} =
+ logger:get_handler_config(h1),
+ register(callback_receiver,self()),
+ ok = logger:set_handler_config(h1,#{filter_default=>stop}),
+ [changing_config] = test_server:messages_get(),
+ {ok,#{module:=?MODULE,level:=all,filter_default:=stop}=C2} =
+ logger:get_handler_config(h1),
+ false = maps:is_key(custom,C2),
+ {error,fail} = logger:set_handler_config(h1,#{conf_call=>fun() -> {error,fail} end}),
+ {error,{attempting_syncronous_call_to_self,_}} =
+ logger:set_handler_config(
+ h1,#{conf_call=>fun() -> logger:set_handler_config(?MODULE,#{}) end}),
+ ok =
+ logger:set_handler_config(
+ h1,#{conf_call=>fun() -> logger:set_module_level(?MODULE,debug) end}),
+ {ok,C2} = logger:get_handler_config(h1),
+
+ %% Change handler config: Single key
+ {error,fail} = logger:set_handler_config(h1,conf_call,fun() -> {error,fail} end),
+ ok = logger:set_handler_config(h1,custom,custom),
+ [changing_config] = test_server:messages_get(),
+ {ok,#{custom:=custom}=C3} = logger:get_handler_config(h1),
+ C2 = maps:remove(custom,C3),
+
+ %% Change handler config: Map
+ ok = logger:update_handler_config(h1,#{custom=>new_custom}),
+ [changing_config] = test_server:messages_get(),
+ {ok,C4} = logger:get_handler_config(h1),
+ C4 = C3#{custom:=new_custom},
+
+ %% Change handler config: Id and module can not be changed
+ {error,{illegal_config_change,Old,New}} =
+ logger:set_handler_config(h1,id,newid),
+ %% Check that only the faulty field is included in return
+ [{id,h1}] = maps:to_list(Old),
+ [{id,newid}] = maps:to_list(New),
+ %% Check that both fields are included when both are changed
+ {error,{illegal_config_change,
+ #{id:=h1,module:=?MODULE},
+ #{id:=newid,module:=newmodule}}} =
+ logger:set_handler_config(h1,#{id=>newid,module=>newmodule}),
+
+ %% Change primary config: Single key
+ PConfig0 = logger:get_primary_config(),
+ ok = logger:set_primary_config(level,warning),
+ PConfig1 = logger:get_primary_config(),
+ PConfig1 = PConfig0#{level:=warning},
+
+ %% Change primary config: Map
+ ok = logger:update_primary_config(#{level=>error}),
+ PConfig2 = logger:get_primary_config(),
+ PConfig2 = PConfig1#{level:=error},
+
+ %% Overwrite primary config - check that defaults are added
+ ok = logger:set_primary_config(#{filter_default=>stop}),
+ #{level:=notice,filters:=[],filter_default:=stop}=PC1 =
+ logger:get_primary_config(),
+ 3 = maps:size(PC1),
+ %% Check that internal 'handlers' field has not been changed
+ MS = [{{{?HANDLER_KEY,'$1'},'_','_'},[],['$1']}],
+ HIds1 = lists:sort(ets:select(?LOGGER_TABLE,MS)), % dirty, internal data
+ HIds2 = lists:sort(logger:get_handler_ids()),
+ HIds1 = HIds2,
+
+ %% Cleanup
+ ok = logger:set_primary_config(PConfig0),
+ [] = test_server:messages_get(),
+
+ ok.
+
+change_config(cleanup,Config) ->
+ logger:remove_handler(h1),
+ PC = ?config(logger_config,Config),
+ logger:set_primary_config(PC),
+ ok.
+
+set_formatter(_Config) ->
+ {error,{not_found,h1}}=logger:set_handler_config(h1,formatter,{?MODULE,[]}),
+ ok = logger:add_handler(h1,?MODULE,#{level=>notice,filter_default=>log}),
+ ok = logger:set_handler_config(h1,formatter,{?MODULE,[]}),
+ logger:notice("hello",[]),
+ receive
+ {_Log,#{formatter:={?MODULE,[]}}} ->
+ ok
+ after 500 ->
+ ct:fail({timeout,no_log,process_info(self(),messages)})
+ end,
+ ok.
+
+set_formatter(cleanup,_Config) ->
+ logger:remove_handler(h1),
+ ok.
+
+log_no_levels(_Config) ->
+ ok = logger:add_handler(h1,?MODULE,#{level=>all,filter_default=>log}),
+ logger:notice(M1=?map_rep),
+ ok = check_logged(notice,M1,#{}),
+
+ Levels = [emergency,alert,critical,error,warning,notice,info,debug],
+ ok = logger:set_primary_config(level,none),
+ [logger:Level(#{Level=>rep}) || Level <- Levels],
+ ok = check_no_log(),
+
+ ok = logger:set_primary_config(level,all),
+ M2 = ?map_rep,
+ ?LOG_NOTICE(M2),
+ ok = check_logged(notice,M2,#{}),
+
+ ok = logger:set_module_level(?MODULE,none),
+ ?LOG_EMERGENCY(?map_rep),
+ ?LOG_ALERT(?map_rep),
+ ?LOG_CRITICAL(?map_rep),
+ ?LOG_ERROR(?map_rep),
+ ?LOG_WARNING(?map_rep),
+ ?LOG_NOTICE(?map_rep),
+ ?LOG_INFO(?map_rep),
+ ?LOG_DEBUG(?map_rep),
+ ok = check_no_log(),
+
+ ok = logger:unset_module_level(?MODULE),
+ logger:notice(M3=?map_rep),
+ ok = check_logged(notice,M3,#{}),
+
+ ok = logger:set_handler_config(h1,level,none),
+ [logger:Level(#{Level=>rep}) || Level <- Levels],
+ ok = check_no_log(),
+
+ ok.
+log_no_levels(cleanup,_Config) ->
+ logger:remove_handler(h1),
+ logger:set_primary_config(level,notice),
+ logger:unset_module_level(?MODULE),
+ ok.
+
+log_all_levels_api(_Config) ->
+ ok = logger:set_primary_config(level,all),
+ ok = logger:add_handler(h1,?MODULE,#{level=>all,filter_default=>log}),
+ test_api(emergency),
+ test_api(alert),
+ test_api(critical),
+ test_api(error),
+ test_api(warning),
+ test_api(notice),
+ test_api(info),
+ test_api(debug),
+ test_log_function(emergency),
+ ok.
+
+log_all_levels_api(cleanup,_Config) ->
+ logger:remove_handler(h1),
+ logger:set_primary_config(level,notice),
+ ok.
+
+macros(_Config) ->
+ ok = logger:add_handler(h1,?MODULE,#{level=>all,filter_default=>log}),
+ test_macros(emergency),
+ test_log_macro(alert),
+ ok.
+
+macros(cleanup,_Config) ->
+ logger:remove_handler(h1),
+ logger:unset_module_level(?MODULE),
+ ok.
+
+set_level(_Config) ->
+ ok = logger:add_handler(h1,?MODULE,#{level=>all,filter_default=>log}),
+ logger:debug(?map_rep),
+ ok = check_no_log(),
+ logger:notice(M1=?map_rep),
+ ok = check_logged(notice,M1,#{}),
+ ok = logger:set_primary_config(level,debug),
+ logger:debug(M2=?map_rep),
+ ok = check_logged(debug,M2,#{}),
+ ok.
+
+set_level(cleanup,_Config) ->
+ logger:remove_handler(h1),
+ logger:set_primary_config(level,notice),
+ ok.
+
+set_module_level(_Config) ->
+ [] = logger:get_module_level([?MODULE,other]),
+ [] = logger:get_module_level(?MODULE),
+ [] = logger:get_module_level(),
+
+ ok = logger:add_handler(h1,?MODULE,#{level=>notice,filter_default=>log}),
+ {error,{invalid_level,bad}} = logger:set_module_level(?MODULE,bad),
+ {error,{not_a_list_of_modules,{bad}}} =
+ logger:set_module_level({bad},warning),
+ {error,{not_a_list_of_modules,[{bad}]}} =
+ logger:set_module_level([{bad}],warning),
+ ok = logger:set_module_level(?MODULE,warning),
+ [{?MODULE,warning}] = logger:get_module_level([?MODULE,other]),
+ [{?MODULE,warning}] = logger:get_module_level(?MODULE),
+ [{?MODULE,warning}] = logger:get_module_level(),
+ logger:notice(?map_rep,?MY_LOC(0)),
+ ok = check_no_log(),
+ logger:warning(M1=?map_rep,?MY_LOC(0)),
+ ok = check_logged(warning,M1,?MY_LOC(1)),
+ ok = logger:set_module_level(?MODULE,notice),
+ [{?MODULE,notice}] = logger:get_module_level([?MODULE,other]),
+ [{?MODULE,notice}] = logger:get_module_level(?MODULE),
+ [{?MODULE,notice}] = logger:get_module_level(),
+ logger:notice(M2=?map_rep,?MY_LOC(0)),
+ ok = check_logged(notice,M2,?MY_LOC(1)),
+
+ {error,{not_a_list_of_modules,{bad}}} = logger:unset_module_level({bad}),
+ {error,{not_a_list_of_modules,[{bad}]}} = logger:unset_module_level([{bad}]),
+ ok = logger:unset_module_level(?MODULE),
+ [] = logger:get_module_level([?MODULE,other]),
+ [] = logger:get_module_level(?MODULE),
+ [] = logger:get_module_level(),
+
+ ok = logger:set_module_level([m1,m2,m3],notice),
+ [{m1,notice},{m2,notice},{m3,notice}] = logger:get_module_level(),
+ ok = logger:unset_module_level(m2),
+ [{m1,notice},{m3,notice}] = logger:get_module_level(),
+ ok = logger:unset_module_level(),
+ [] = logger:get_module_level(),
+
+ ok.
+
+set_module_level(cleanup,_Config) ->
+ logger:remove_handler(h1),
+ logger:unset_module_level(?MODULE),
+ ok.
+
+set_application_level(_Config) ->
+
+ {error,{not_loaded,mnesia}} = logger:set_application_level(mnesia, warning),
+ {error,{not_loaded,mnesia}} = logger:unset_application_level(mnesia),
+
+ case application:load(mnesia) of
+ ok ->
+ {ok, Modules} = application:get_key(mnesia, modules),
+ [] = logger:get_module_level(Modules),
+
+ {error,{invalid_level,warn}} =
+ logger:set_application_level(mnesia, warn),
+
+ ok = logger:set_application_level(mnesia, debug),
+ DebugModules = lists:sort([{M,debug} || M <- Modules]),
+ DebugModules = lists:sort(logger:get_module_level(Modules)),
+
+ ok = logger:set_application_level(mnesia, warning),
+
+ WarnModules = lists:sort([{M,warning} || M <- Modules]),
+ WarnModules = lists:sort(logger:get_module_level(Modules)),
+
+ ok = logger:unset_application_level(mnesia),
+ [] = logger:get_module_level(Modules);
+ {error,{"no such file or directory","mnesia.app"}} ->
+ {skip, "Cannot load mnesia, does not exist"}
+ end.
+
+set_application_level(cleanup,_Config) ->
+ _ = logger:unset_application_level(mnesia),
+ _ = application:unload(mnesia),
+ ok.
+
+cache_module_level(_Config) ->
+ ok = logger:unset_module_level(?MODULE),
+ [] = ets:lookup(?LOGGER_TABLE,?MODULE), %dirty - add API in logger_config?
+ ?LOG_NOTICE(?map_rep),
+ %% Caching is done asynchronously, so wait a bit for the update
+ timer:sleep(100),
+ [_] = ets:lookup(?LOGGER_TABLE,?MODULE), %dirty - add API in logger_config?
+ ok = logger:unset_module_level(?MODULE),
+ [] = ets:lookup(?LOGGER_TABLE,?MODULE), %dirty - add API in logger_config?
+ ok.
+
+cache_module_level(cleanup,_Config) ->
+ logger:unset_module_level(?MODULE),
+ ok.
+
+format_report(_Config) ->
+ {"~ts",["string"]} = logger:format_report("string"),
+ {"~tp",[term]} = logger:format_report(term),
+ {"~tp",[[]]} = logger:format_report([]),
+ {" ~tp: ~tp",[key,value]} = logger:format_report([{key,value}]),
+ KeyVals = [{key1,value1},{key2,"value2"},{key3,[]}],
+ KeyValRes =
+ {" ~tp: ~tp\n ~tp: ~ts\n ~tp: ~tp",
+ [key1,value1,key2,"value2",key3,[]]} =
+ logger:format_report(KeyVals),
+ KeyValRes = logger:format_report(maps:from_list(KeyVals)),
+ KeyValRes = logger:format_otp_report(#{label=>{?MODULE,test},report=>KeyVals}),
+ {" ~tp: ~tp\n ~tp: ~tp",
+ [label,{?MODULE,test},report,KeyVals]} =
+ logger:format_report(#{label=>{?MODULE,test},report=>KeyVals}),
+
+ {" ~tp: ~tp\n ~tp",[key1,value1,term]} =
+ logger:format_report([{key1,value1},term]),
+
+ {" ~tp: ~tp\n ~tp",[key1,value1,[]]} =
+ logger:format_report([{key1,value1},[]]),
+
+ {"~tp",[[]]} = logger:format_report([[],[],[]]),
+
+ ok.
+
+filter_failed(_Config) ->
+ ok = logger:add_handler(h1,?MODULE,#{level=>notice,filter_default=>log}),
+
+ %% Logger filters
+ {error,{invalid_filter,_}} =
+ logger:add_primary_filter(lf,{fun(_) -> ok end,args}),
+ ok = logger:add_primary_filter(lf,
+ {fun(_,_) ->
+ erlang:error({badmatch,b})
+ end,
+ args}),
+ #{filters:=[_]} = logger:get_primary_config(),
+ ok = logger:notice(M1=?map_rep),
+ ok = check_logged(notice,M1,#{}),
+ {error,{not_found,lf}} = logger:remove_primary_filter(lf),
+
+ ok = logger:add_primary_filter(lf,{fun(_,_) -> faulty_return end,args}),
+ #{filters:=[_]} = logger:get_primary_config(),
+ ok = logger:notice(M2=?map_rep),
+ ok = check_logged(notice,M2,#{}),
+ {error,{not_found,lf}} = logger:remove_primary_filter(lf),
+
+ %% Handler filters
+ {error,{not_found,h0}} =
+ logger:add_handler_filter(h0,hf,{fun(_,_) -> ignore end,args}),
+ {error,{not_found,h0}} = logger:remove_handler_filter(h0,hf),
+ {error,{invalid_filter,_}} =
+ logger:add_handler_filter(h1,hf,{fun(_) -> ok end,args}),
+ ok = logger:add_handler_filter(h1,hf,
+ {fun(_,_) ->
+ erlang:error({badmatch,b})
+ end,
+ args}),
+ {ok,#{filters:=[_]}} = logger:get_handler_config(h1),
+ ok = logger:notice(M3=?map_rep),
+ ok = check_logged(notice,M3,#{}),
+ {error,{not_found,hf}} = logger:remove_handler_filter(h1,hf),
+
+ ok = logger:add_handler_filter(h1,hf,{fun(_,_) -> faulty_return end,args}),
+ {ok,#{filters:=[_]}} = logger:get_handler_config(h1),
+ ok = logger:notice(M4=?map_rep),
+ ok = check_logged(notice,M4,#{}),
+ {error,{not_found,hf}} = logger:remove_handler_filter(h1,hf),
+
+ ok.
+
+filter_failed(cleanup,_Config) ->
+ logger:remove_handler(h1),
+ ok.
+
+handler_failed(_Config) ->
+ register(callback_receiver,self()),
+ {error,{invalid_id,1}} = logger:add_handler(1,?MODULE,#{}),
+ {error,{invalid_module,"nomodule"}} = logger:add_handler(h1,"nomodule",#{}),
+ {error,{invalid_config,bad}} = logger:add_handler(h1,?MODULE,bad),
+ {error,{invalid_filters,false}} =
+ logger:add_handler(h1,?MODULE,#{filters=>false}),
+ {error,{invalid_filter_default,true}} =
+ logger:add_handler(h1,?MODULE,#{filter_default=>true}),
+ {error,{invalid_formatter,[]}} =
+ logger:add_handler(h1,?MODULE,#{formatter=>[]}),
+ {error,{invalid_handler,_}} = logger:add_handler(h1,nomodule,#{filter_default=>log}),
+ logger:notice(?map_rep),
+ check_no_log(),
+ H1 = logger:get_handler_config(),
+ false = lists:search(fun(#{id:=h1}) -> true; (_) -> false end,H1),
+ {error,{not_found,h1}} = logger:remove_handler(h1),
+
+ ok = logger:add_handler(h2,?MODULE,
+ #{filter_default => log,
+ log_call => fun() ->
+ erlang:error({badmatch,b})
+ end}),
+ {error,{already_exist,h2}} = logger:add_handler(h2,othermodule,#{}),
+ [add] = test_server:messages_get(),
+
+ logger:notice(?map_rep),
+ [remove] = test_server:messages_get(),
+ H2 = logger:get_handler_config(),
+ false = lists:search(fun(#{id:=h2}) -> true; (_) -> false end,H2),
+ {error,{not_found,h2}} = logger:remove_handler(h2),
+
+ CallAddHandler = fun() -> logger:add_handler(h2,?MODULE,#{}) end,
+ CrashHandler = fun() -> erlang:error({badmatch,b}) end,
+ KillHandler = fun() -> exit(self(), die) end,
+
+ {error,{handler_not_added,{attempting_syncronous_call_to_self,_}}} =
+ logger:add_handler(h1,?MODULE,#{add_call=>CallAddHandler}),
+ {error,{handler_not_added,{callback_crashed,_}}} =
+ logger:add_handler(h1,?MODULE,#{add_call=>CrashHandler}),
+ {error,{handler_not_added,{logger_process_exited,_,die}}} =
+ logger:add_handler(h1,?MODULE,#{add_call=>KillHandler}),
+
+ check_no_log(),
+ ok = logger:add_handler(h1,?MODULE,#{}),
+ {error,{attempting_syncronous_call_to_self,_}} =
+ logger:set_handler_config(h1,#{conf_call=>CallAddHandler}),
+ {error,{callback_crashed,_}} =
+ logger:set_handler_config(h1,#{conf_call=>CrashHandler}),
+ {error,{logger_process_exited,_,die}} =
+ logger:set_handler_config(h1,#{conf_call=>KillHandler}),
+
+ {error,{attempting_syncronous_call_to_self,_}} =
+ logger:set_handler_config(h1,conf_call,CallAddHandler),
+ {error,{callback_crashed,_}} =
+ logger:set_handler_config(h1,conf_call,CrashHandler),
+ {error,{logger_process_exited,_,die}} =
+ logger:set_handler_config(h1,conf_call,KillHandler),
+
+ ok = logger:remove_handler(h1),
+ [add,remove] = test_server:messages_get(),
+
+ check_no_log(),
+ ok = logger:add_handler(h1,?MODULE,#{rem_call=>CallAddHandler}),
+ ok = logger:remove_handler(h1),
+ ok = logger:add_handler(h1,?MODULE,#{rem_call=>CrashHandler}),
+ ok = logger:remove_handler(h1),
+ ok = logger:add_handler(h1,?MODULE,#{rem_call=>KillHandler}),
+ ok = logger:remove_handler(h1),
+ [add,add,add] = test_server:messages_get(),
+
+ ok.
+
+handler_failed(cleanup,_Config) ->
+ logger:remove_handler(h1),
+ logger:remove_handler(h2),
+ ok.
+
+config_sanity_check(_Config) ->
+ %% Primary config
+ {error,{invalid_config,bad}} = logger:set_primary_config(bad),
+ {error,{invalid_filter_default,bad}} =
+ logger:set_primary_config(filter_default,bad),
+ {error,{invalid_level,bad}} = logger:set_primary_config(level,bad),
+ {error,{invalid_filters,bad}} = logger:set_primary_config(filters,bad),
+ {error,{invalid_filter,bad}} = logger:set_primary_config(filters,[bad]),
+ {error,{invalid_filter,{_,_}}} =
+ logger:set_primary_config(filters,[{id,bad}]),
+ {error,{invalid_filter,{_,{_,_}}}} =
+ logger:set_primary_config(filters,[{id,{bad,args}}]),
+ {error,{invalid_filter,{_,{_,_}}}} =
+ logger:set_primary_config(filters,[{id,{fun() -> ok end,args}}]),
+ {error,{invalid_primary_config,{bad,bad}}} =
+ logger:set_primary_config(bad,bad),
+
+ %% Handler config
+ {error,{not_found,h1}} = logger:set_handler_config(h1,a,b),
+ ok = logger:add_handler(h1,?MODULE,#{}),
+ {error,{invalid_filter_default,bad}} =
+ logger:set_handler_config(h1,filter_default,bad),
+ {error,{invalid_level,bad}} = logger:set_handler_config(h1,level,bad),
+ {error,{invalid_filters,bad}} = logger:set_handler_config(h1,filters,bad),
+ {error,{invalid_filter,bad}} = logger:set_handler_config(h1,filters,[bad]),
+ {error,{invalid_filter,{_,_}}} =
+ logger:set_handler_config(h1,filters,[{id,bad}]),
+ {error,{invalid_filter,{_,{_,_}}}} =
+ logger:set_handler_config(h1,filters,[{id,{bad,args}}]),
+ {error,{invalid_filter,{_,{_,_}}}} =
+ logger:set_handler_config(h1,filters,[{id,{fun() -> ok end,args}}]),
+ {error,{invalid_formatter,bad}} =
+ logger:set_handler_config(h1,formatter,bad),
+ {error,{invalid_module,{bad}}} =
+ logger:set_handler_config(h1,formatter,{{bad},cfg}),
+ {error,{invalid_formatter_config,logger_formatter,bad}} =
+ logger:set_handler_config(h1,formatter,{logger_formatter,bad}),
+ {error,{invalid_formatter_config,logger_formatter,{bad,bad}}} =
+ logger:set_handler_config(h1,formatter,{logger_formatter,#{bad=>bad}}),
+ {error,{invalid_formatter_template,logger_formatter,bad}} =
+ logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{template=>bad}}),
+ {error,{invalid_formatter_template,logger_formatter,[1]}} =
+ logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{template=>[1]}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{template=>[]}}),
+ {error,{invalid_formatter_config,logger_formatter,{single_line,bad}}} =
+ logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{single_line=>bad}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{single_line=>true}}),
+ {error,{invalid_formatter_config,logger_formatter,{legacy_header,bad}}} =
+ logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{legacy_header=>bad}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{legacy_header=>true}}),
+ {error,{invalid_formatter_config,logger_formatter,{report_cb,bad}}} =
+ logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{report_cb=>bad}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{report_cb=>fun(R) ->
+ {"~p",[R]}
+ end}}),
+ {error,{invalid_formatter_config,logger_formatter,{chars_limit,bad}}} =
+ logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{chars_limit=>bad}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{chars_limit=>unlimited}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{chars_limit=>4}}),
+ {error,{invalid_formatter_config,logger_formatter,{depth,bad}}} =
+ logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{depth=>bad}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{depth=>unlimited}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{depth=>4}}),
+ {error,{invalid_formatter_config,logger_formatter,{max_size,bad}}} =
+ logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{max_size=>bad}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{max_size=>unlimited}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{max_size=>4}}),
+ ok = logger:set_handler_config(h1,formatter,{module,config}),
+ {error,{callback_crashed,{error,{badmatch,3},[{?MODULE,check_config,1,_}]}}} =
+ logger:set_handler_config(h1,formatter,{?MODULE,crash}),
+ ok = logger:set_handler_config(h1,custom,custom),
+
+ %% Old utc parameter is no longer allowed (replaced by time_offset)
+ {error,{invalid_formatter_config,logger_formatter,{utc,true}}} =
+ logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{utc=>true}}),
+ {error,{invalid_formatter_config,logger_formatter,{time_offset,bad}}} =
+ logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{time_offset=>bad}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{time_offset=>0}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{time_offset=>""}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{time_offset=>"Z"}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{time_offset=>"z"}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{time_offset=>"-0:0"}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{time_offset=>"+10:13"}}),
+
+ {error,{invalid_formatter_config,logger_formatter,{time_offset,"+0"}}} =
+ logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{time_offset=>"+0"}}),
+
+ {error,{invalid_formatter_config,logger_formatter,{time_designator,bad}}} =
+ logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{time_designator=>bad}}),
+ {error,{invalid_formatter_config,logger_formatter,{time_designator,"s"}}} =
+ logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{time_designator=>"s"}}),
+ {error,{invalid_formatter_config,logger_formatter,{time_designator,0}}} =
+ logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{time_designator=>0}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{time_designator=>$\s}}),
+ ok.
+
+config_sanity_check(cleanup,_Config) ->
+ logger:remove_handler(h1),
+ ok.
+
+log_failed(_Config) ->
+ ok = logger:add_handler(h1,?MODULE,#{level=>notice,filter_default=>log}),
+ {error,function_clause} = ?TRY(logger:log(bad,?map_rep)),
+ {error,function_clause} = ?TRY(logger:log(notice,?map_rep,bad)),
+ {error,function_clause} = ?TRY(logger:log(notice,fun() -> ?map_rep end,bad)),
+ {error,function_clause} = ?TRY(logger:log(notice,fun() -> ?map_rep end,bad,#{})),
+ {error,function_clause} = ?TRY(logger:log(notice,bad,bad,bad)),
+ {error,function_clause} = ?TRY(logger:log(notice,bad,bad,#{})),
+ check_no_log(),
+ ok = logger:log(notice,M1=?str,#{}),
+ check_logged(notice,M1,#{}),
+ ok = logger:log(notice,M2=?map_rep,#{}),
+ check_logged(notice,M2,#{}),
+ ok = logger:log(notice,M3=?keyval_rep,#{}),
+ check_logged(notice,M3,#{}),
+
+ %% Should we check report input more thoroughly?
+ ok = logger:log(notice,M4=?keyval_rep++[other,stuff,in,list],#{}),
+ check_logged(notice,M4,#{}),
+
+ %% This might break a handler since it is assumed to be a format
+ %% string and args, so it depends how the handler protects itself
+ %% against something like io_lib:format("ok","ok")
+ ok = logger:log(notice,"ok","ok",#{}),
+ check_logged(notice,"ok","ok",#{}),
+
+ ok.
+
+log_failed(cleanup,_Config) ->
+ logger:remove_handler(h1),
+ ok.
+
+emulator(_Config) ->
+ ok = logger:add_handler(h1,?MODULE,#{level=>notice,filter_default=>log,
+ tc_proc=>self()}),
+ Msg = "Error in process ~p on node ~p with exit value:~n~p~n",
+ Error = {badmatch,4},
+ Stack = [{module, function, 2, []}],
+ Pid = spawn(?MODULE, generate_error, [Error, Stack]),
+ check_logged(error, Msg, [Pid, node(), {Error, Stack}],
+ #{gl=>group_leader(),
+ error_logger=>#{tag=>error,emulator=>true}}),
+ ok.
+
+emulator(cleanup, _Config) ->
+ logger:remove_handler(h1),
+ ok.
+
+generate_error(Error, Stack) ->
+ erlang:raise(error, Error, Stack).
+
+via_logger_process(Config) ->
+ ok = logger:add_handler(h1,?MODULE,#{level=>notice,filter_default=>log,
+ tc_proc=>self()}),
+
+ %% Explicitly send a message to the logger process
+ %% This is used by code_server, erl_prim_loader, init, prim_file, ...
+ Msg = ?str,
+ logger ! {log,error,Msg,[],#{}},
+ check_logged(error, Msg, [], #{}),
+
+ case os:type() of
+ {win32,_} ->
+ %% Skip this part on windows - cant change file mode"
+ ok;
+ _ ->
+ %% This should trigger the same thing from erl_prim_loader
+ Dir = filename:join(?config(priv_dir,Config),"dummydir"),
+ ok = file:make_dir(Dir),
+ ok = file:change_mode(Dir,8#0222),
+ error = erl_prim_loader:list_dir(Dir),
+ check_logged(error,
+ #{report=>"File operation error: eacces. Target: " ++
+ Dir ++". Function: list_dir. "},
+ #{pid=>self(),
+ gl=>group_leader(),
+ error_logger=>#{tag=>error_report,
+ type=>std_error}}),
+ ok
+ end.
+
+via_logger_process(cleanup, Config) ->
+ Dir = filename:join(?config(priv_dir,Config),"dummydir"),
+ _ = file:change_mode(Dir,8#0664),
+ _ = file:del_dir(Dir),
+ logger:remove_handler(h1),
+ ok.
+
+other_node(_Config) ->
+ ok = logger:add_handler(h1,?MODULE,#{level=>notice,filter_default=>log,
+ tc_proc=>self()}),
+ {ok,Node} = test_server:start_node(?FUNCTION_NAME,slave,[]),
+ rpc:call(Node,logger,error,[Msg=?str,#{}]),
+ check_logged(error,Msg,#{}),
+ ok.
+
+other_node(cleanup,_Config) ->
+ Nodes = nodes(),
+ [test_server:stop_node(Node) || Node <- Nodes],
+ logger:remove_handler(h1),
+ ok.
+
+compare_levels(_Config) ->
+ Levels = [emergency,alert,critical,error,warning,notice,info,debug],
+ ok = compare(Levels),
+ {error,badarg} = ?TRY(logger:compare_levels(bad,bad)),
+ {error,badarg} = ?TRY(logger:compare_levels({bad},notice)),
+ {error,badarg} = ?TRY(logger:compare_levels(notice,"bad")),
+ ok.
+
+compare([L|Rest]) ->
+ eq = logger:compare_levels(L,L),
+ [gt = logger:compare_levels(L,L1) || L1 <- Rest],
+ [lt = logger:compare_levels(L1,L) || L1 <- Rest],
+ compare(Rest);
+compare([]) ->
+ ok.
+
+process_metadata(_Config) ->
+ undefined = logger:get_process_metadata(),
+ {error,badarg} = ?TRY(logger:set_process_metadata(bad)),
+ ok = logger:add_handler(h1,?MODULE,#{level=>notice,filter_default=>log}),
+ Time = logger:timestamp(),
+ ProcMeta = #{time=>Time,line=>0,custom=>proc},
+ ok = logger:set_process_metadata(ProcMeta),
+ S1 = ?str,
+ ?LOG_NOTICE(S1,#{custom=>macro}),
+ check_logged(notice,S1,#{time=>Time,line=>0,custom=>macro}),
+
+ Time2 = logger:timestamp(),
+ S2 = ?str,
+ ?LOG_NOTICE(S2,#{time=>Time2,line=>1,custom=>macro}),
+ check_logged(notice,S2,#{time=>Time2,line=>1,custom=>macro}),
+
+ logger:notice(S3=?str,#{custom=>func}),
+ check_logged(notice,S3,#{time=>Time,line=>0,custom=>func}),
+
+ ProcMeta = logger:get_process_metadata(),
+ ok = logger:update_process_metadata(#{custom=>changed,custom2=>added}),
+ Expected = ProcMeta#{custom:=changed,custom2=>added},
+ Expected = logger:get_process_metadata(),
+ ok = logger:unset_process_metadata(),
+ undefined = logger:get_process_metadata(),
+
+ ok = logger:update_process_metadata(#{custom=>added_again}),
+ {error,badarg} = ?TRY(logger:update_process_metadata(bad)),
+ #{custom:=added_again} = logger:get_process_metadata(),
+
+ ok.
+
+process_metadata(cleanup,_Config) ->
+ logger:remove_handler(h1),
+ ok.
+
+app_config(Config) ->
+ %% Start a node with default configuration
+ {ok,_,Node} = logger_test_lib:setup(Config,[]),
+
+ App1Name = app1,
+ App1 = {application, App1Name,
+ [{description, "Test of app with logger config"},
+ {applications, [kernel]}]},
+ ok = rpc:call(Node,application,load,[App1]),
+ ok = rpc:call(Node,application,set_env,
+ [App1Name,logger,[{handler,default,logger_std_h,#{}}]]),
+
+ %% Try to add an own default handler
+ {error,{bad_config,{handler,{app1,{already_exist,default}}}}} =
+ rpc:call(Node,logger,add_handlers,[App1Name]),
+
+ %% Add a different handler
+ ok = rpc:call(Node,application,set_env,[App1Name,logger,
+ [{handler,myh,logger_std_h,#{}}]]),
+ ok = rpc:call(Node,logger,add_handlers,[App1Name]),
+
+ {ok,#{filters:=DF}} = rpc:call(Node,logger,get_handler_config,[default]),
+ {ok,#{filters:=[]}} = rpc:call(Node,logger,get_handler_config,[myh]),
+
+ true = test_server:stop_node(Node),
+
+ %% Start a node with no default handler, then add an own default handler
+ {ok,#{handlers:=[#{id:=simple}]},Node} =
+ logger_test_lib:setup(Config,[{logger,[{handler,default,undefined}]}]),
+
+ ok = rpc:call(Node,application,load,[App1]),
+ ok = rpc:call(Node,application,set_env,
+ [App1Name,logger,[{handler,default,logger_std_h,#{}}]]),
+ ok = rpc:call(Node,logger,add_handlers,[App1Name]),
+
+ #{handlers:=[#{id:=default,filters:=DF}]} =
+ rpc:call(Node,logger,get_config,[]),
+
+ true = test_server:stop_node(Node),
+
+ %% Start a silent node, then add an own default handler
+ {ok,#{handlers:=[]},Node} =
+ logger_test_lib:setup(Config,[{error_logger,silent}]),
+
+ {error,{bad_config,{handler,[{some,bad,config}]}}} =
+ rpc:call(Node,logger,add_handlers,[[{some,bad,config}]]),
+ ok = rpc:call(Node,logger,add_handlers,
+ [[{handler,default,logger_std_h,#{}}]]),
+
+ #{handlers:=[#{id:=default,filters:=DF}]} =
+ rpc:call(Node,logger,get_config,[]),
+
+ ok.
+
+%% This test case is maintly to see code coverage. Note that
+%% logger_env_var_SUITE tests a lot of the same, and checks the
+%% functionality more thoroughly, but since it all happens at node
+%% start, it is not possible to see code coverage in that test.
+kernel_config(Config) ->
+ %% Start a node with simple handler only, then simulate kernel
+ %% start by calling internally exported
+ %% internal_init_logger(). This is to test all variants of kernel
+ %% config, including bad config, and see the code coverage.
+ {ok,#{handlers:=[#{id:=simple,filters:=DF}]}=LC,Node} =
+ logger_test_lib:setup(Config,[{error_logger,false}]),
+
+ %% Same once more, to get coverage
+ ok = rpc:call(Node,logger,internal_init_logger,[]),
+ ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ LC = rpc:call(Node,logger,get_config,[]),
+
+ %% This shall mean the same as above, but using 'logger' parameter
+ %% instead of 'error_logger'
+ ok = rpc:call(Node,application,unset_env,[kernel,error_logger]),
+ ok = rpc:call(Node,application,set_env,
+ [kernel,logger,[{handler,default,undefined}]]),
+ ok = rpc:call(Node,logger,internal_init_logger,[]),
+ ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ LC = rpc:call(Node,logger,get_config,[]),
+
+ %% Silent
+ ok = rpc:call(Node,application,unset_env,[kernel,logger]),
+ ok = rpc:call(Node,application,set_env,[kernel,error_logger,silent]),
+ ok = rpc:call(Node,logger,internal_init_logger,[]),
+ ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ #{primary:=#{filter_default:=log,filters:=[]},
+ handlers:=[],
+ module_levels:=[]} = rpc:call(Node,logger,get_config,[]),
+
+ %% Default
+ ok = rpc:call(Node,application,unset_env,[kernel,error_logger]),
+ ok = rpc:call(Node,application,unset_env,[kernel,logger]),
+ ok = rpc:call(Node,logger,internal_init_logger,[]),
+ ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ #{primary:=#{filter_default:=log,filters:=[]},
+ handlers:=[#{id:=default,filters:=DF,config:=#{type:=standard_io}}],
+ module_levels:=[]} = rpc:call(Node,logger,get_config,[]),
+
+ %% error_logger=tty (same as default)
+ ok = rpc:call(Node,logger,remove_handler,[default]),% so it can be added again
+ ok = rpc:call(Node,application,set_env,[kernel,error_logger,tty]),
+ ok = rpc:call(Node,application,unset_env,[kernel,logger]),
+ ok = rpc:call(Node,logger,internal_init_logger,[]),
+ ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ #{primary:=#{filter_default:=log,filters:=[]},
+ handlers:=[#{id:=default,filters:=DF,config:=#{type:=standard_io}}],
+ module_levels:=[]} = rpc:call(Node,logger,get_config,[]),
+
+ %% error_logger={file,File}
+ ok = rpc:call(Node,logger,remove_handler,[default]),% so it can be added again
+ F = filename:join(?config(priv_dir,Config),
+ atom_to_list(?FUNCTION_NAME)++".log"),
+ ok = rpc:call(Node,application,set_env,[kernel,error_logger,{file,F}]),
+ ok = rpc:call(Node,application,unset_env,[kernel,logger]),
+ ok = rpc:call(Node,logger,internal_init_logger,[]),
+ ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ #{primary:=#{filter_default:=log,filters:=[]},
+ handlers:=[#{id:=default,filters:=DF,
+ config:=#{type:=file,file:=F,modes:=Modes}}],
+ module_levels:=[]} = rpc:call(Node,logger,get_config,[]),
+ [append,delayed_write,raw] = lists:sort(Modes),
+
+
+ %% Same, but using 'logger' parameter instead of 'error_logger'
+ ok = rpc:call(Node,logger,remove_handler,[default]),% so it can be added again
+ ok = rpc:call(Node,application,unset_env,[kernel,error_logger]),
+ ok = rpc:call(Node,application,set_env,[kernel,logger,
+ [{handler,default,logger_std_h,
+ #{config=>#{type=>{file,F}}}}]]),
+ ok = rpc:call(Node,logger,internal_init_logger,[]),
+ ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ #{primary:=#{filter_default:=log,filters:=[]},
+ handlers:=[#{id:=default,filters:=DF,
+ config:=#{type:=file,file:=F,modes:=Modes}}],
+ module_levels:=[]} = rpc:call(Node,logger,get_config,[]),
+
+ %% Same, but with type={file,File,Modes}
+ ok = rpc:call(Node,logger,remove_handler,[default]),% so it can be added again
+ ok = rpc:call(Node,application,unset_env,[kernel,error_logger]),
+ M = [raw,write],
+ ok = rpc:call(Node,application,set_env,[kernel,logger,
+ [{handler,default,logger_std_h,
+ #{config=>#{type=>{file,F,M}}}}]]),
+ ok = rpc:call(Node,logger,internal_init_logger,[]),
+ ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ #{primary:=#{filter_default:=log,filters:=[]},
+ handlers:=[#{id:=default,filters:=DF,
+ config:=#{type:=file,file:=F,modes:=[delayed_write|M]}}],
+ module_levels:=[]} = rpc:call(Node,logger,get_config,[]),
+
+ %% Same, but with disk_log handler
+ ok = rpc:call(Node,logger,remove_handler,[default]),% so it can be added again
+ ok = rpc:call(Node,application,unset_env,[kernel,error_logger]),
+ ok = rpc:call(Node,application,set_env,[kernel,logger,
+ [{handler,default,logger_disk_log_h,
+ #{config=>#{file=>F}}}]]),
+ ok = rpc:call(Node,logger,internal_init_logger,[]),
+ ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ #{primary:=#{filter_default:=log,filters:=[]},
+ handlers:=[#{id:=default,filters:=DF,config:=#{file:=F}}],
+ module_levels:=[]} = rpc:call(Node,logger,get_config,[]),
+
+ %% Set primary filters and module level. No default handler.
+ ok = rpc:call(Node,logger,remove_handler,[default]),% so it can be added again
+ ok = rpc:call(Node,application,unset_env,[kernel,error_logger]),
+ ok = rpc:call(Node,application,set_env,
+ [kernel,logger,[{handler,default,undefined},
+ {filters,stop,[{f1,{fun(_,_) -> log end,ok}}]},
+ {module_level,debug,[?MODULE]}]]),
+ ok = rpc:call(Node,logger,internal_init_logger,[]),
+ ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ #{primary:=#{filter_default:=stop,filters:=[_]},
+ handlers:=[],
+ module_levels:=[{?MODULE,debug}]} = rpc:call(Node,logger,get_config,[]),
+
+ %% Bad config
+ ok = rpc:call(Node,application,unset_env,[kernel,logger]),
+
+ ok = rpc:call(Node,application,set_env,[kernel,error_logger,bad]),
+ {error,{bad_config,{kernel,{error_logger,bad}}}} =
+ rpc:call(Node,logger,internal_init_logger,[]),
+
+ ok = rpc:call(Node,application,unset_env,[kernel,error_logger]),
+ ok = rpc:call(Node,application,set_env,[kernel,logger_level,bad]),
+ {error,{bad_config,{kernel,{logger_level,bad}}}} =
+ rpc:call(Node,logger,internal_init_logger,[]),
+
+ ok = rpc:call(Node,application,unset_env,[kernel,logger_level]),
+ ok = rpc:call(Node,application,set_env,
+ [kernel,logger,[{filters,stop,[bad]}]]),
+ {error,{bad_config,{kernel,{invalid_filters,[bad]}}}} =
+ rpc:call(Node,logger,internal_init_logger,[]),
+
+ ok = rpc:call(Node,application,set_env,
+ [kernel,logger,[{filters,stop,[bad]}]]),
+ {error,{bad_config,{kernel,{invalid_filters,[bad]}}}} =
+ rpc:call(Node,logger,internal_init_logger,[]),
+
+ ok = rpc:call(Node,application,set_env,
+ [kernel,logger,[{filters,stop,[{f1,bad}]}]]),
+ {error,{bad_config,{kernel,{invalid_filter,{f1,bad}}}}} =
+ rpc:call(Node,logger,internal_init_logger,[]),
+
+ ok = rpc:call(Node,application,set_env,
+ [kernel,logger,MF=[{filters,stop,[]},{filters,log,[]}]]),
+ {error,{bad_config,{kernel,{multiple_filters,MF}}}} =
+ rpc:call(Node,logger,internal_init_logger,[]),
+
+ ok = rpc:call(Node,application,set_env,
+ [kernel,logger,[{module_level,bad,[?MODULE]}]]),
+ {error,{bad_config,{kernel,{invalid_level,bad}}}} =
+ rpc:call(Node,logger,internal_init_logger,[]),
+
+ ok.
+
+pretty_print(Config) ->
+ ok = logger:add_handler(?FUNCTION_NAME,logger_std_h,#{}),
+ ok = logger:set_module_level([module1,module2],debug),
+
+ ct:capture_start(),
+ logger:i(),
+ ct:capture_stop(),
+ I0 = ct:capture_get(),
+
+ ct:capture_start(),
+ logger:i(primary),
+ ct:capture_stop(),
+ IPrim = ct:capture_get(),
+
+ ct:capture_start(),
+ logger:i(handlers),
+ ct:capture_stop(),
+ IHs = ct:capture_get(),
+
+ ct:capture_start(),
+ logger:i(proxy),
+ ct:capture_stop(),
+ IProxy = ct:capture_get(),
+
+ ct:capture_start(),
+ logger:i(modules),
+ ct:capture_stop(),
+ IMs = ct:capture_get(),
+
+ I02 = lists:append([IPrim,IHs,IProxy,IMs]),
+ %% ct:log("~p~n",[I0]),
+ %% ct:log("~p~n",[I02]),
+ I0 = I02,
+
+ ct:capture_start(),
+ logger:i(handlers),
+ ct:capture_stop(),
+ IHs = ct:capture_get(),
+
+ Ids = logger:get_handler_ids(),
+ IHs2 =
+ lists:append(
+ [begin
+ ct:capture_start(),
+ logger:i(Id),
+ ct:capture_stop(),
+ [_|IH] = ct:capture_get(),
+ IH
+ end || Id <- Ids]),
+
+ %% ct:log("~p~n",[IHs]),
+ %% ct:log("~p~n",[["Handler configuration: \n"|IHs2]]),
+ IHs = ["Handler configuration: \n"|IHs2],
+ ok.
+
+%%%-----------------------------------------------------------------
+%%% Internal
+check_logged(Level,Format,Args,Meta) ->
+ do_check_logged(Level,{Format,Args},Meta).
+
+check_logged(Level,Msg,Meta) when ?IS_REPORT(Msg) ->
+ do_check_logged(Level,{report,Msg},Meta);
+check_logged(Level,Msg,Meta) when ?IS_STRING(Msg) ->
+ do_check_logged(Level,{string,Msg},Meta).
+
+do_check_logged(Level,Msg0,Meta0) ->
+ receive
+ {#{level:=Level,msg:=Msg,meta:=Meta},_} ->
+ check_msg(Msg0,Msg),
+ check_maps(Meta0,Meta,meta)
+ after 500 ->
+ ct:fail({timeout,no_log,process_info(self(),messages)})
+ end.
+
+check_no_log() ->
+ receive
+ X -> ct:fail({got_unexpected_log,X})
+ after 500 ->
+ ok
+ end.
+
+check_msg(Msg,Msg) ->
+ ok;
+check_msg({report,Expected},{report,Got}) when is_map(Expected), is_map(Got) ->
+ check_maps(Expected,Got,msg);
+check_msg(Expected,Got) ->
+ ct:fail({unexpected,msg,Expected,Got}).
+
+check_maps(Expected,Got,What) ->
+ case maps:merge(Got,Expected) of
+ Got ->
+ ok;
+ _ ->
+ ct:fail({unexpected,What,Expected,Got})
+ end.
+
+%% Handler
+adding_handler(#{add_call:=Fun}) ->
+ Fun();
+adding_handler(Config) ->
+ maybe_send(add),
+ {ok,Config}.
+
+removing_handler(#{rem_call:=Fun}) ->
+ Fun();
+removing_handler(_Config) ->
+ maybe_send(remove),
+ ok.
+changing_config(_Old,#{conf_call:=Fun}) ->
+ Fun();
+changing_config(_Old,Config) ->
+ maybe_send(changing_config),
+ {ok,Config}.
+
+maybe_send(Msg) ->
+ case whereis(callback_receiver) of
+ undefined -> ok;
+ Pid -> Pid ! Msg
+ end.
+
+log(_Log,#{log_call:=Fun}) ->
+ Fun();
+log(Log,Config) ->
+ TcProc = maps:get(tc_proc,Config,self()),
+ TcProc ! {Log,Config},
+ ok.
+
+test_api(Level) ->
+ logger:Level(#{Level=>rep}),
+ ok = check_logged(Level,#{Level=>rep},#{}),
+ logger:Level(#{Level=>rep},#{my=>meta}),
+ ok = check_logged(Level,#{Level=>rep},#{my=>meta}),
+ logger:Level("~w: ~w",[Level,fa]),
+ ok = check_logged(Level,"~w: ~w",[Level,fa],#{}),
+ logger:Level("~w: ~w ~w",[Level,fa,meta],#{my=>meta}),
+ ok = check_logged(Level,"~w: ~w ~w",[Level,fa,meta],#{my=>meta}),
+ logger:Level(fun(x) -> {"~w: ~w ~w",[Level,fun_to_fa,meta]} end,x,
+ #{my=>meta}),
+ ok = check_logged(Level,"~w: ~w ~w",[Level,fun_to_fa,meta],#{my=>meta}),
+ logger:Level(fun(x) -> #{Level=>fun_to_r,meta=>true} end,x,
+ #{my=>meta}),
+ ok = check_logged(Level,#{Level=>fun_to_r,meta=>true},#{my=>meta}),
+ logger:Level(fun(x) -> <<"fun_to_s">> end,x,#{}),
+ ok = check_logged(Level,<<"fun_to_s">>,#{}),
+ logger:Level(F1=fun(x) -> {fun_to_bad} end,x,#{}),
+ ok = check_logged(Level,"LAZY_FUN ERROR: ~tp; Returned: ~tp",
+ [{F1,x},{fun_to_bad}],#{}),
+ logger:Level(F2=fun(x) -> erlang:error(fun_that_crashes) end,x,#{}),
+ ok = check_logged(Level,"LAZY_FUN CRASH: ~tp; Reason: ~tp",
+ [{F2,x},{error,fun_that_crashes}],#{}),
+ ok.
+
+test_log_function(Level) ->
+ logger:log(Level,#{Level=>rep}),
+ ok = check_logged(Level,#{Level=>rep},#{}),
+ logger:log(Level,#{Level=>rep},#{my=>meta}),
+ ok = check_logged(Level,#{Level=>rep},#{my=>meta}),
+ logger:log(Level,"~w: ~w",[Level,fa]),
+ ok = check_logged(Level,"~w: ~w",[Level,fa],#{}),
+ logger:log(Level,"~w: ~w ~w",[Level,fa,meta],#{my=>meta}),
+ ok = check_logged(Level,"~w: ~w ~w",[Level,fa,meta],#{my=>meta}),
+ logger:log(Level,fun(x) -> {"~w: ~w ~w",[Level,fun_to_fa,meta]} end,
+ x, #{my=>meta}),
+ ok = check_logged(Level,"~w: ~w ~w",[Level,fun_to_fa,meta],#{my=>meta}),
+ logger:log(Level,fun(x) -> #{Level=>fun_to_r,meta=>true} end,
+ x, #{my=>meta}),
+ ok = check_logged(Level,#{Level=>fun_to_r,meta=>true},#{my=>meta}),
+ logger:log(Level,fun(x) -> <<"fun_to_s">> end,x,#{}),
+ ok = check_logged(Level,<<"fun_to_s">>,#{}),
+ logger:log(Level,F1=fun(x) -> {fun_to_bad} end,x,#{}),
+ ok = check_logged(Level,"LAZY_FUN ERROR: ~tp; Returned: ~tp",
+ [{F1,x},{fun_to_bad}],#{}),
+ logger:log(Level,F2=fun(x) -> erlang:error(fun_that_crashes) end,x,#{}),
+ ok = check_logged(Level,"LAZY_FUN CRASH: ~tp; Reason: ~tp",
+ [{F2,x},{error,fun_that_crashes}],#{}),
+ ok.
+
+test_macros(emergency=Level) ->
+ ?LOG_EMERGENCY(#{Level=>rep}),
+ ok = check_logged(Level,#{Level=>rep},?MY_LOC(1)),
+ ?LOG_EMERGENCY(#{Level=>rep},#{my=>meta}),
+ ok = check_logged(Level,#{Level=>rep},(?MY_LOC(1))#{my=>meta}),
+ ?LOG_EMERGENCY("~w: ~w",[Level,fa]),
+ ok = check_logged(Level,"~w: ~w",[Level,fa],?MY_LOC(1)),
+ ?LOG_EMERGENCY("~w: ~w ~w",[Level,fa,meta],#{my=>meta}),
+ ok = check_logged(Level,"~w: ~w ~w",[Level,fa,meta],(?MY_LOC(1))#{my=>meta}),
+ ?LOG_EMERGENCY(fun(x) -> {"~w: ~w ~w",[Level,fun_to_fa,meta]} end,
+ x, #{my=>meta}),
+ ok = check_logged(Level,"~w: ~w ~w",[Level,fun_to_fa,meta],
+ (?MY_LOC(3))#{my=>meta}),
+ ?LOG_EMERGENCY(fun(x) -> #{Level=>fun_to_r,meta=>true} end, x, #{my=>meta}),
+ ok = check_logged(Level,#{Level=>fun_to_r,meta=>true},
+ (?MY_LOC(2))#{my=>meta}),
+ ?LOG_EMERGENCY(fun(x) -> <<"fun_to_s">> end,x,#{}),
+ ok = check_logged(Level,<<"fun_to_s">>,?MY_LOC(1)),
+ F1=fun(x) -> {fun_to_bad} end,
+ ?LOG_EMERGENCY(F1,x,#{}),
+ ok = check_logged(Level,"LAZY_FUN ERROR: ~tp; Returned: ~tp",
+ [{F1,x},{fun_to_bad}],#{}),
+ F2=fun(x) -> erlang:error(fun_that_crashes) end,
+ ?LOG_EMERGENCY(F2,x,#{}),
+ ok = check_logged(Level,"LAZY_FUN CRASH: ~tp; Reason: ~tp",
+ [{F2,x},{error,fun_that_crashes}],#{}),
+ ok.
+
+test_log_macro(Level) ->
+ ?LOG(Level,#{Level=>rep}),
+ ok = check_logged(Level,#{Level=>rep},?MY_LOC(1)),
+ ?LOG(Level,#{Level=>rep},#{my=>meta}),
+ ok = check_logged(Level,#{Level=>rep},(?MY_LOC(1))#{my=>meta}),
+ ?LOG(Level,"~w: ~w",[Level,fa]),
+ ok = check_logged(Level,"~w: ~w",[Level,fa],?MY_LOC(1)),
+ ?LOG(Level,"~w: ~w ~w",[Level,fa,meta],#{my=>meta}),
+ ok = check_logged(Level,"~w: ~w ~w",[Level,fa,meta],(?MY_LOC(1))#{my=>meta}),
+ ?LOG(Level,fun(x) -> {"~w: ~w ~w",[Level,fun_to_fa,meta]} end,
+ x, #{my=>meta}),
+ ok = check_logged(Level,"~w: ~w ~w",[Level,fun_to_fa,meta],
+ (?MY_LOC(3))#{my=>meta}),
+ ?LOG(Level,fun(x) -> #{Level=>fun_to_r,meta=>true} end, x, #{my=>meta}),
+ ok = check_logged(Level,#{Level=>fun_to_r,meta=>true},
+ (?MY_LOC(2))#{my=>meta}),
+ ?LOG(Level,fun(x) -> <<"fun_to_s">> end,x,#{}),
+ ok = check_logged(Level,<<"fun_to_s">>,?MY_LOC(1)),
+ F1=fun(x) -> {fun_to_bad} end,
+ ?LOG(Level,F1,x,#{}),
+ ok = check_logged(Level,"LAZY_FUN ERROR: ~tp; Returned: ~tp",
+ [{F1,x},{fun_to_bad}],#{}),
+ F2=fun(x) -> erlang:error(fun_that_crashes) end,
+ ?LOG(Level,F2,x,#{}),
+ ok = check_logged(Level,"LAZY_FUN CRASH: ~tp; Reason: ~tp",
+ [{F2,x},{error,fun_that_crashes}],#{}),
+ ok.
+
+%%%-----------------------------------------------------------------
+%%% Called by macro ?TRY(X)
+my_try(Fun) ->
+ try Fun() catch C:R -> {C,R} end.
+
+check_config(crash) ->
+ erlang:error({badmatch,3});
+check_config(_) ->
+ ok.
diff --git a/lib/kernel/test/logger_disk_log_h_SUITE.erl b/lib/kernel/test/logger_disk_log_h_SUITE.erl
new file mode 100644
index 0000000000..36d98eaa25
--- /dev/null
+++ b/lib/kernel/test/logger_disk_log_h_SUITE.erl
@@ -0,0 +1,1668 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(logger_disk_log_h_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("kernel/include/logger.hrl").
+-include_lib("kernel/src/logger_internal.hrl").
+-include_lib("kernel/src/logger_olp.hrl").
+-include_lib("kernel/src/logger_h_common.hrl").
+-include_lib("stdlib/include/ms_transform.hrl").
+-include_lib("kernel/include/file.hrl").
+
+-define(check_no_log, [] = test_server:messages_get()).
+
+-define(check(Expected),
+ receive {log,Expected} ->
+ [] = test_server:messages_get()
+ after 1000 ->
+ ct:fail({report_not_received,
+ {line,?LINE},
+ {got,test_server:messages_get()}})
+ end).
+
+-define(msg,"Log from "++atom_to_list(?FUNCTION_NAME)++
+ ":"++integer_to_list(?LINE)).
+-define(bin(Msg), list_to_binary(Msg++"\n")).
+-define(log_no(File,N), lists:concat([File,".",N])).
+-define(domain,#{domain=>[?MODULE]}).
+
+suite() ->
+ [{timetrap,{seconds,30}},
+ {ct_hooks,[logger_test_lib]}].
+
+init_per_suite(Config) ->
+ timer:start(), % to avoid progress report
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(_Group, Config) ->
+ Config.
+
+end_per_group(_Group, _Config) ->
+ ok.
+
+init_per_testcase(TestHooksCase, Config) when
+ TestHooksCase == write_failure;
+ TestHooksCase == sync_failure ->
+ case (fun() -> ?TEST_HOOKS_TAB == undefined end)() of
+ true ->
+ {skip,"Define the TEST_HOOKS macro to run this test"};
+ false ->
+ ct:print("********** ~w **********", [TestHooksCase]),
+ Config
+ end;
+init_per_testcase(TestCase, Config) ->
+ ct:print("********** ~w **********", [TestCase]),
+ Config.
+
+end_per_testcase(Case, Config) ->
+ try apply(?MODULE,Case,[cleanup,Config])
+ catch error:undef -> ok
+ end,
+ ok.
+
+groups() ->
+ [].
+
+all() ->
+ [start_stop_handler,
+ create_log,
+ open_existing_log,
+ disk_log_opts,
+ default_formatter,
+ logging,
+ filter_config,
+ errors,
+ formatter_fail,
+ config_fail,
+ bad_input,
+ reconfig,
+ sync,
+ disk_log_full,
+ disk_log_wrap,
+ disk_log_events,
+ write_failure,
+ sync_failure,
+ op_switch_to_sync,
+ op_switch_to_drop,
+ op_switch_to_flush,
+ limit_burst_disabled,
+ limit_burst_enabled_one,
+ limit_burst_enabled_period,
+ kill_disabled,
+ qlen_kill_new,
+ %% qlen_kill_std,
+ mem_kill_new,
+ %% mem_kill_std,
+ restart_after,
+ handler_requests_under_load
+ ].
+
+start_stop_handler(_Config) ->
+ ok = logger:add_handler(?MODULE, logger_disk_log_h, #{}),
+ {error,{already_exist,?MODULE}} =
+ logger:add_handler(?MODULE, logger_disk_log_h, #{}),
+ true = is_pid(whereis(h_proc_name())),
+ ok = logger:remove_handler(?MODULE),
+ timer:sleep(500),
+ undefined = whereis(h_proc_name()).
+start_stop_handler(cleanup, _Config) ->
+ logger:remove_handler(?MODULE).
+
+create_log(Config) ->
+ PrivDir = ?config(priv_dir,Config),
+ %% test new handler
+ Name1 = list_to_atom(lists:concat([?FUNCTION_NAME,"_A"])),
+ LogFile1 = filename:join(PrivDir, Name1),
+ ok = start_and_add(Name1, #{filter_default=>stop,
+ filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
+ formatter=>{?MODULE,self()}},
+ #{file=>LogFile1}),
+ logger:notice("hello", ?domain),
+ logger_disk_log_h:filesync(Name1),
+ ct:pal("Checking contents of ~p", [?log_no(LogFile1,1)]),
+ try_read_file(?log_no(LogFile1,1), {ok,<<"hello\n">>}, 5000),
+
+ %% test second handler
+ Name2 = list_to_atom(lists:concat([?FUNCTION_NAME,"_B"])),
+ DLName = lists:concat([?FUNCTION_NAME,"_B_log"]),
+ LogFile2 = filename:join(PrivDir, DLName),
+ ok = start_and_add(Name2, #{filter_default=>stop,
+ filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
+ formatter=>{?MODULE,self()}},
+ #{file=>LogFile2}),
+ logger:notice("dummy", ?domain),
+ logger_disk_log_h:filesync(Name2),
+ ct:pal("Checking contents of ~p", [?log_no(LogFile2,1)]),
+ try_read_file(?log_no(LogFile2,1), {ok,<<"dummy\n">>}, 5000),
+
+ remove_and_stop(Name1),
+ remove_and_stop(Name2),
+ try_read_file(?log_no(LogFile1,1), {ok,<<"hello\ndummy\n">>}, 1),
+ try_read_file(?log_no(LogFile2,1), {ok,<<"dummy\n">>}, 5000),
+ ok.
+
+open_existing_log(Config) ->
+ PrivDir = ?config(priv_dir,Config),
+ %% test new handler
+ HName = ?FUNCTION_NAME,
+ DLName = lists:concat([?FUNCTION_NAME,"_log"]),
+ LogFile1 = filename:join(PrivDir, DLName),
+ ok = start_and_add(HName, #{filter_default=>stop,
+ filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
+ formatter=>{?MODULE,self()}},
+ #{file=>LogFile1}),
+ logger:notice("one", ?domain),
+ logger_disk_log_h:filesync(HName),
+ ct:pal("Checking contents of ~p", [?log_no(LogFile1,1)]),
+ try_read_file(?log_no(LogFile1,1), {ok,<<"one\n">>}, 5000),
+ logger:notice("two", ?domain),
+ ok = remove_and_stop(HName),
+ try_read_file(?log_no(LogFile1,1), {ok,<<"one\ntwo\n">>}, 5000),
+
+ logger:notice("two and a half", ?domain),
+
+ ok = start_and_add(HName, #{filter_default=>stop,
+ filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
+ formatter=>{?MODULE,self()}},
+ #{file=>LogFile1}),
+ logger:notice("three", ?domain),
+ logger_disk_log_h:filesync(HName),
+ try_read_file(?log_no(LogFile1,1), {ok,<<"one\ntwo\nthree\n">>}, 5000),
+ remove_and_stop(HName),
+ try_read_file(?log_no(LogFile1,1), {ok,<<"one\ntwo\nthree\n">>}, 5000).
+
+disk_log_opts(Config) ->
+ Get = fun(Key, PL) -> proplists:get_value(Key, PL) end,
+ PrivDir = ?config(priv_dir,Config),
+ WName = list_to_atom(lists:concat([?FUNCTION_NAME,"_W"])),
+ WFile = lists:concat([?FUNCTION_NAME,"_W_log"]),
+ Size = length("12345"),
+ ConfigW = #{filter_default=>stop,
+ filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
+ formatter => {?MODULE,no_nl}},
+ WFileFull = filename:join(PrivDir, WFile),
+ DLOptsW = #{file => WFileFull,
+ type => wrap,
+ max_no_bytes => Size,
+ max_no_files => 2},
+ ok = start_and_add(WName, ConfigW, DLOptsW),
+ WInfo1 = disk_log:info(WName),
+ ct:log("Fullname = ~s", [WFileFull]),
+ {WFileFull,wrap,{Size,2},1} = {Get(file,WInfo1),Get(type,WInfo1),
+ Get(size,WInfo1),Get(current_file,WInfo1)},
+ logger:notice("123", ?domain),
+ logger_disk_log_h:filesync(WName),
+ timer:sleep(500),
+ 1 = Get(current_file, disk_log:info(WName)),
+
+ logger:notice("45", ?domain),
+ logger_disk_log_h:filesync(WName),
+ timer:sleep(500),
+ 1 = Get(current_file, disk_log:info(WName)),
+
+ logger:notice("6", ?domain),
+ logger_disk_log_h:filesync(WName),
+ timer:sleep(500),
+ 2 = Get(current_file, disk_log:info(WName)),
+
+ logger:notice("7890", ?domain),
+ logger_disk_log_h:filesync(WName),
+ timer:sleep(500),
+ 2 = Get(current_file, disk_log:info(WName)),
+
+ HName1 = list_to_atom(lists:concat([?FUNCTION_NAME,"_H1"])),
+ HFile1 = lists:concat([?FUNCTION_NAME,"_H1_log"]),
+ ConfigH = #{filter_default=>stop,
+ filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
+ formatter => {?MODULE,no_nl}},
+ HFile1Full = filename:join(PrivDir, HFile1),
+ DLOptsH1 = #{file => HFile1Full,
+ type => halt},
+ ok = start_and_add(HName1, ConfigH, DLOptsH1),
+ HInfo1 = disk_log:info(HName1),
+ ct:log("Fullname = ~s", [HFile1Full]),
+ {HFile1Full,halt,infinity} = {Get(file,HInfo1),Get(type,HInfo1),
+ Get(size,HInfo1)},
+ logger:notice("12345", ?domain),
+ logger_disk_log_h:filesync(HName1),
+ timer:sleep(500),
+ 1 = Get(no_written_items, disk_log:info(HName1)),
+
+ HName2 = list_to_atom(lists:concat([?FUNCTION_NAME,"_H2"])),
+ HFile2 = lists:concat([?FUNCTION_NAME,"_H2_log"]),
+ HFile2Full = filename:join(PrivDir, HFile2),
+ DLOptsH2 = DLOptsH1#{file => HFile2Full,
+ max_no_bytes => 1000},
+ ok = start_and_add(HName2, ConfigH, DLOptsH2),
+ HInfo3 = disk_log:info(HName2),
+ ct:log("Fullname = ~s", [HFile2Full]),
+ {HFile2Full,halt,1000} = {Get(file,HInfo3),Get(type,HInfo3),
+ Get(size,HInfo3)},
+
+ remove_and_stop(WName),
+ remove_and_stop(HName1),
+ remove_and_stop(HName2),
+ ok.
+
+default_formatter(Config) ->
+ PrivDir = ?config(priv_dir,Config),
+ LogFile = filename:join(PrivDir,atom_to_list(?FUNCTION_NAME)),
+ HandlerConfig = #{config => #{file=>LogFile},
+ filter_default=>log},
+ ct:pal("Log: ~p", [LogFile]),
+ ok = logger:add_handler(?MODULE, logger_disk_log_h, HandlerConfig),
+ ok = logger:set_handler_config(?MODULE,formatter,
+ {?DEFAULT_FORMATTER,?DEFAULT_FORMAT_CONFIG}),
+ LogName = lists:concat([LogFile, ".1"]),
+ logger:notice("dummy"),
+ wait_until_written(LogName),
+ {ok,Bin} = file:read_file(LogName),
+ match = re:run(Bin, "=NOTICE REPORT====.*\ndummy", [{capture,none}]),
+ ok.
+default_formatter(cleanup, _Config) ->
+ logger:remove_handler(?MODULE).
+
+logging(Config) ->
+ PrivDir = ?config(priv_dir,Config),
+ %% test new handler
+ Name = list_to_atom(lists:concat([?FUNCTION_NAME,"_1"])),
+ LogFile = filename:join(PrivDir, Name),
+ ok = start_and_add(Name, #{filter_default=>log,
+ formatter=>{?MODULE,self()}},
+ #{file => LogFile}),
+ MsgFormatter = fun(Term) -> {"Term:~p",[Term]} end,
+ logger:notice([{x,y}], #{report_cb => MsgFormatter}),
+ logger:notice([{x,y}], #{}),
+ ct:pal("Checking contents of ~p", [?log_no(LogFile,1)]),
+ try_read_file(?log_no(LogFile,1), {ok,<<"Term:[{x,y}]\n x: y\n">>}, 5000).
+
+logging(cleanup, _Config) ->
+ Name = list_to_atom(lists:concat([?FUNCTION_NAME,"_1"])),
+ remove_and_stop(Name).
+
+filter_config(_Config) ->
+ ok = logger:add_handler(?MODULE,logger_disk_log_h,#{}),
+ {ok,#{config:=HConfig}=Config} = logger:get_handler_config(?MODULE),
+ HConfig = maps:without([olp],HConfig),
+
+ FakeFullHConfig = HConfig#{olp=>{regname,self(),erlang:make_ref()}},
+ #{config:=HConfig} =
+ logger_disk_log_h:filter_config(Config#{config=>FakeFullHConfig}),
+ ok.
+
+filter_config(cleanup,_Config) ->
+ logger:remove_handler(?MODULE),
+ ok.
+
+errors(Config) ->
+ PrivDir = ?config(priv_dir,Config),
+ Name1 = list_to_atom(lists:concat([?FUNCTION_NAME,"_1"])),
+ LogFile1 = filename:join(PrivDir,Name1),
+ HandlerConfig = #{config=>#{file=>LogFile1},
+ filter_default=>log,
+ formatter=>{?MODULE,self()}},
+ ok = logger:add_handler(Name1, logger_disk_log_h, HandlerConfig),
+ {error,{already_exist,Name1}} =
+ logger:add_handler(Name1, logger_disk_log_h, #{}),
+
+ %%! TODO:
+ %%! Check how bad log_opts are handled!
+
+ {error,{illegal_config_change,
+ logger_disk_log_h,
+ #{type:=wrap},
+ #{type:=halt}}} =
+ logger:update_handler_config(Name1,
+ config,
+ #{type=>halt,
+ file=>LogFile1}),
+
+ {error,{illegal_config_change,
+ logger_disk_log_h,
+ #{file:=LogFile1},
+ #{file:="newfilename"}}} =
+ logger:update_handler_config(Name1,
+ config,
+ #{file=>"newfilename"}),
+
+ %% Read-only fields may (accidentially) be included in the change,
+ %% but it won't take effect
+ {ok,C} = logger:get_handler_config(Name1),
+ ok = logger:set_handler_config(Name1,config,#{olp=>dummyvalue}),
+ {ok,C} = logger:get_handler_config(Name1),
+
+
+ ok = logger:remove_handler(Name1),
+ {error,{not_found,Name1}} = logger:remove_handler(Name1),
+ ok.
+
+errors(cleanup, _Config) ->
+ Name1 = list_to_atom(lists:concat([?FUNCTION_NAME,"_1"])),
+ _ = logger:remove_handler(Name1).
+
+formatter_fail(Config) ->
+ PrivDir = ?config(priv_dir,Config),
+ Name = ?FUNCTION_NAME,
+ LogFile = filename:join(PrivDir,Name),
+ ct:pal("Log = ~p", [LogFile]),
+ HandlerConfig = #{config => #{file=>LogFile},
+ filter_default=>stop,
+ filters=>?DEFAULT_HANDLER_FILTERS([?MODULE])},
+ %% no formatter!
+ logger:add_handler(Name, logger_disk_log_h, HandlerConfig),
+ Pid = whereis(h_proc_name(Name)),
+ true = is_pid(Pid),
+ H = logger:get_handler_ids(),
+ true = lists:member(Name,H),
+
+ %% Formatter is added automatically
+ {ok,#{formatter:={logger_formatter,_}}} = logger:get_handler_config(Name),
+ logger:notice(M1=?msg,?domain),
+ Got1 = try_match_file(?log_no(LogFile,1),"[0-9\\+\\-T:\\.]* notice: "++M1,5000),
+
+ ok = logger:set_handler_config(Name,formatter,{nonexistingmodule,#{}}),
+ logger:notice(M2=?msg,?domain),
+ Got2 = try_match_file(?log_no(LogFile,1),
+ escape(Got1)++"[0-9\\+\\-T:\\.]* notice: FORMATTER CRASH: .*"++M2,
+ 5000),
+
+ ok = logger:set_handler_config(Name,formatter,{?MODULE,crash}),
+ logger:notice(M3=?msg,?domain),
+ Got3 = try_match_file(?log_no(LogFile,1),
+ escape(Got2)++"[0-9\\+\\-T:\\.]* notice: FORMATTER CRASH: .*"++M3,
+ 5000),
+
+ ok = logger:set_handler_config(Name,formatter,{?MODULE,bad_return}),
+ logger:notice(?msg,?domain),
+ try_match_file(?log_no(LogFile,1),
+ escape(Got3)++"FORMATTER ERROR: bad return value",
+ 5000),
+
+ %% Check that handler is still alive and was never dead
+ Pid = whereis(h_proc_name(Name)),
+ H = logger:get_handler_ids(),
+ ok.
+
+formatter_fail(cleanup,_Config) ->
+ _ = logger:remove_handler(?FUNCTION_NAME),
+ ok.
+
+config_fail(_Config) ->
+ {error,{handler_not_added,{invalid_config,logger_disk_log_h,#{bad:=bad}}}} =
+ logger:add_handler(?MODULE,logger_disk_log_h,
+ #{config => #{bad => bad},
+ filter_default=>log,
+ formatter=>{?MODULE,self()}}),
+
+ {error,{handler_not_added,{invalid_olp_levels,#{drop_mode_qlen:=1}}}} =
+ logger:add_handler(?MODULE,logger_disk_log_h,
+ #{config => #{drop_mode_qlen=>1}}),
+ {error,{handler_not_added,{invalid_olp_levels,#{sync_mode_qlen:=43,
+ drop_mode_qlen:=42}}}} =
+ logger:add_handler(?MODULE,logger_disk_log_h,
+ #{config => #{sync_mode_qlen=>43,
+ drop_mode_qlen=>42}}),
+ {error,{handler_not_added,{invalid_olp_levels,#{drop_mode_qlen:=43,
+ flush_qlen:=42}}}} =
+ logger:add_handler(?MODULE,logger_disk_log_h,
+ #{config => #{drop_mode_qlen=>43,
+ flush_qlen=>42}}),
+
+ ok = logger:add_handler(?MODULE,logger_disk_log_h,
+ #{filter_default=>log,
+ formatter=>{?MODULE,self()}}),
+ %% can't change the disk log options for a log already in use
+ {error,{illegal_config_change,logger_disk_log_h,_,_}} =
+ logger:update_handler_config(?MODULE,config,
+ #{max_no_files=>2}),
+ %% incorrect values of OP params
+ {ok,#{config := HConfig}} = logger:get_handler_config(?MODULE),
+ {error,{invalid_olp_levels,_}} =
+ logger:update_handler_config(?MODULE,config,
+ HConfig#{sync_mode_qlen=>100,
+ flush_qlen=>99}),
+ %% invalid name of config parameter
+ {error,{invalid_config,logger_disk_log_h,#{filesync_rep_int:=2000}}} =
+ logger:update_handler_config(?MODULE, config,
+ HConfig#{filesync_rep_int => 2000}),
+ ok.
+config_fail(cleanup,_Config) ->
+ logger:remove_handler(?MODULE).
+
+bad_input(_Config) ->
+ {error,{badarg,{filesync,["BadType"]}}} =
+ logger_disk_log_h:filesync("BadType").
+
+reconfig(Config) ->
+ Dir = ?config(priv_dir,Config),
+ ok = logger:add_handler(?MODULE,
+ logger_disk_log_h,
+ #{filter_default=>log,
+ filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
+ formatter=>{?MODULE,self()}}),
+ #{%id := ?MODULE,
+ sync_mode_qlen := ?SYNC_MODE_QLEN,
+ drop_mode_qlen := ?DROP_MODE_QLEN,
+ flush_qlen := ?FLUSH_QLEN,
+ burst_limit_enable := ?BURST_LIMIT_ENABLE,
+ burst_limit_max_count := ?BURST_LIMIT_MAX_COUNT,
+ burst_limit_window_time := ?BURST_LIMIT_WINDOW_TIME,
+ overload_kill_enable := ?OVERLOAD_KILL_ENABLE,
+ overload_kill_qlen := ?OVERLOAD_KILL_QLEN,
+ overload_kill_mem_size := ?OVERLOAD_KILL_MEM_SIZE,
+ overload_kill_restart_after := ?OVERLOAD_KILL_RESTART_AFTER,
+ cb_state :=
+ #{handler_state :=
+ #{log_opts := #{type := ?DISK_LOG_TYPE,
+ max_no_files := ?DISK_LOG_MAX_NO_FILES,
+ max_no_bytes := ?DISK_LOG_MAX_NO_BYTES,
+ file := DiskLogFile}},
+ filesync_repeat_interval := ?FILESYNC_REPEAT_INTERVAL}} =
+ logger_olp:info(h_proc_name()),
+ {ok,#{config :=
+ #{sync_mode_qlen := ?SYNC_MODE_QLEN,
+ drop_mode_qlen := ?DROP_MODE_QLEN,
+ flush_qlen := ?FLUSH_QLEN,
+ burst_limit_enable := ?BURST_LIMIT_ENABLE,
+ burst_limit_max_count := ?BURST_LIMIT_MAX_COUNT,
+ burst_limit_window_time := ?BURST_LIMIT_WINDOW_TIME,
+ overload_kill_enable := ?OVERLOAD_KILL_ENABLE,
+ overload_kill_qlen := ?OVERLOAD_KILL_QLEN,
+ overload_kill_mem_size := ?OVERLOAD_KILL_MEM_SIZE,
+ overload_kill_restart_after := ?OVERLOAD_KILL_RESTART_AFTER,
+ filesync_repeat_interval := ?FILESYNC_REPEAT_INTERVAL,
+ file := DiskLogFile,
+ max_no_files := ?DISK_LOG_MAX_NO_FILES,
+ max_no_bytes := ?DISK_LOG_MAX_NO_BYTES,
+ type := wrap} = HConfig0}} =
+ logger:get_handler_config(?MODULE),
+
+ HConfig1 = HConfig0#{sync_mode_qlen => 1,
+ drop_mode_qlen => 2,
+ flush_qlen => 3,
+ burst_limit_enable => false,
+ burst_limit_max_count => 10,
+ burst_limit_window_time => 10,
+ overload_kill_enable => true,
+ overload_kill_qlen => 100000,
+ overload_kill_mem_size => 10000000,
+ overload_kill_restart_after => infinity,
+ filesync_repeat_interval => no_repeat},
+ ok = logger:set_handler_config(?MODULE, config, HConfig1),
+ #{%id := ?MODULE,
+ sync_mode_qlen := 1,
+ drop_mode_qlen := 2,
+ flush_qlen := 3,
+ burst_limit_enable := false,
+ burst_limit_max_count := 10,
+ burst_limit_window_time := 10,
+ overload_kill_enable := true,
+ overload_kill_qlen := 100000,
+ overload_kill_mem_size := 10000000,
+ overload_kill_restart_after := infinity,
+ cb_state := #{filesync_repeat_interval := no_repeat}} =
+ logger_olp:info(h_proc_name()),
+ {ok,#{config:=HConfig1}} = logger:get_handler_config(?MODULE),
+
+ ok = logger:update_handler_config(?MODULE, config,
+ #{flush_qlen => ?FLUSH_QLEN}),
+ {ok,#{config:=C1}} = logger:get_handler_config(?MODULE),
+ ct:log("C1: ~p",[C1]),
+ C1 = HConfig1#{flush_qlen => ?FLUSH_QLEN},
+
+ ok = logger:set_handler_config(?MODULE, config, #{sync_mode_qlen => 1}),
+ {ok,#{config:=C2}} = logger:get_handler_config(?MODULE),
+ ct:log("C2: ~p",[C2]),
+ C2 = HConfig0#{sync_mode_qlen => 1},
+
+ ok = logger:set_handler_config(?MODULE, config, #{drop_mode_qlen => 100}),
+ {ok,#{config:=C3}} = logger:get_handler_config(?MODULE),
+ ct:log("C3: ~p",[C3]),
+ C3 = HConfig0#{drop_mode_qlen => 100},
+
+ ok = logger:update_handler_config(?MODULE, config, #{sync_mode_qlen => 1}),
+ {ok,#{config:=C4}} = logger:get_handler_config(?MODULE),
+ ct:log("C4: ~p",[C4]),
+ C4 = HConfig0#{sync_mode_qlen => 1,
+ drop_mode_qlen => 100},
+
+ ok = logger:remove_handler(?MODULE),
+
+ File = filename:join(Dir, "logfile"),
+ ok = logger:add_handler(?MODULE,
+ logger_disk_log_h,
+ #{filter_default=>log,
+ filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
+ formatter=>{?MODULE,self()},
+ config=>
+ #{type => halt,
+ max_no_files => 1,
+ max_no_bytes => 1024,
+ file => File}}),
+ #{cb_state :=
+ #{handler_state :=
+ #{log_opts := #{type := halt,
+ max_no_files := 1,
+ max_no_bytes := 1024,
+ file := File}}}} =
+ logger_olp:info(h_proc_name()),
+ {ok,#{config :=
+ #{type := halt,
+ max_no_files := 1,
+ max_no_bytes := 1024,
+ file := File}=HaltHConfig} = Config2} =
+ logger:get_handler_config(?MODULE),
+
+ ok = logger:update_handler_config(?MODULE, level, notice),
+ {ok,C5} = logger:get_handler_config(?MODULE),
+ ct:log("C5: ~p",[C5]),
+ C5 = Config2#{level => notice},
+
+ ok = logger:set_handler_config(?MODULE, level, info),
+ {ok,C6} = logger:get_handler_config(?MODULE),
+ ct:log("C6: ~p",[C6]),
+ C6 = Config2#{level => info},
+
+ %% You are not allowed to actively set the write once fields
+ %% (type, max_no_files, max_no_bytes, file) in runtime.
+ {error, {illegal_config_change,_,_,_}} =
+ logger:set_handler_config(?MODULE,config,#{type=>wrap}),
+ {error, {illegal_config_change,_,_,_}} =
+ logger:set_handler_config(?MODULE,config,#{max_no_files=>2}),
+ {error, {illegal_config_change,_,_,_}} =
+ logger:set_handler_config(?MODULE,config,#{max_no_bytes=>2048}),
+ {error, {illegal_config_change,_,_,_}} =
+ logger:set_handler_config(?MODULE,config,#{file=>"otherfile.log"}),
+ {ok,C7} = logger:get_handler_config(?MODULE),
+ ct:log("C7: ~p",[C7]),
+ C7 = C6,
+
+ %% ... but if you don't specify the write once fields, then
+ %% set_handler_config shall NOT reset them to their default value
+ ok = logger:set_handler_config(?MODULE,config,#{sync_mode_qlen=>1}),
+ {ok,#{config:=C8}} = logger:get_handler_config(?MODULE),
+ ct:log("C8: ~p",[C8]),
+ C8 = HaltHConfig#{sync_mode_qlen=>1},
+ ok.
+
+reconfig(cleanup, _Config) ->
+ logger:remove_handler(?MODULE).
+
+sync(Config) ->
+ Dir = ?config(priv_dir,Config),
+ File = filename:join(Dir, ?FUNCTION_NAME),
+ Log = lists:concat([File,".1"]),
+ ok = logger:add_handler(?MODULE,
+ logger_disk_log_h,
+ #{config => #{file => File},
+ filter_default=>log,
+ filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
+ formatter=>{?MODULE,nl}}),
+
+ start_tracer([{logger_disk_log_h,disk_log_write,3},
+ {disk_log,sync,1}],
+ [{logger_disk_log_h,disk_log_write,<<"first\n">>},
+ {disk_log,sync}]),
+
+ logger:notice("first", ?domain),
+ %% wait for automatic disk_log_sync
+ check_tracer(?FILESYNC_REPEAT_INTERVAL*2),
+
+ %% check that if there's no repeated filesync active,
+ %% a disk_log_sync is still performed when handler goes idle
+ {ok,#{config := HConfig}} = logger:get_handler_config(?MODULE),
+ HConfig1 = HConfig#{filesync_repeat_interval => no_repeat},
+ ok = logger:update_handler_config(?MODULE, config, HConfig1),
+ no_repeat = maps:get(filesync_repeat_interval,
+ maps:get(cb_state,logger_olp:info(h_proc_name()))),
+
+ start_tracer([{logger_disk_log_h,disk_log_write,3},
+ {disk_log,sync,1}],
+ [{logger_disk_log_h,disk_log_write,<<"second\n">>},
+ {disk_log,sync},
+ {logger_disk_log_h,disk_log_write,<<"third\n">>},
+ {disk_log,sync}]),
+
+ logger:notice("second", ?domain),
+ timer:sleep(?IDLE_DETECT_TIME*2),
+ logger:notice("third", ?domain),
+ %% wait for automatic disk_log_sync
+ check_tracer(?IDLE_DETECT_TIME*2),
+
+ try_read_file(Log, {ok,<<"first\nsecond\nthird\n">>}, 1000),
+
+ %% switch repeated filesync on and verify that the looping works
+ SyncInt = 1000,
+ WaitT = 4500,
+ OneSync = {logger_h_common,handle_cast,repeated_filesync},
+ %% receive 1 repeated_filesync per sec
+ start_tracer([{{logger_h_common,handle_cast,2},
+ [{[repeated_filesync,'_'],[],[{message,{caller}}]}]}],
+ [OneSync || _ <- lists:seq(1, trunc(WaitT/SyncInt))]),
+
+ HConfig2 = HConfig#{filesync_repeat_interval => SyncInt},
+ ok = logger:update_handler_config(?MODULE, config, HConfig2),
+
+ SyncInt = maps:get(filesync_repeat_interval,
+ maps:get(cb_state,logger_olp:info(h_proc_name()))),
+ timer:sleep(WaitT),
+ HConfig3 = HConfig#{filesync_repeat_interval => no_repeat},
+ ok = logger:update_handler_config(?MODULE, config, HConfig3),
+ check_tracer(100),
+ ok.
+sync(cleanup,_Config) ->
+ dbg:stop_clear(),
+ logger:remove_handler(?MODULE).
+
+disk_log_wrap(Config) ->
+ Get = fun(Key, PL) -> proplists:get_value(Key, PL) end,
+ Dir = ?config(priv_dir,Config),
+ File = filename:join(Dir, ?FUNCTION_NAME),
+ ct:pal("Log = ~p", [File]),
+ MaxFiles = 3,
+ MaxBytes = 5,
+ ok = logger:add_handler(?MODULE,
+ logger_disk_log_h,
+ #{filter_default=>log,
+ filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
+ formatter=>{?MODULE,self()},
+ config=>
+ #{type => wrap,
+ max_no_files => MaxFiles,
+ max_no_bytes => MaxBytes,
+ file => File}}),
+ Info = disk_log:info(?MODULE),
+ {File,wrap,{MaxBytes,MaxFiles},1} =
+ {Get(file,Info),Get(type,Info),Get(size,Info),Get(current_file,Info)},
+ Tester = self(),
+ TraceFun = fun({trace,_,call,{Mod,Func,Details}}, Pid) ->
+ Pid ! {trace,Mod,Func,Details},
+ Pid
+ end,
+ {ok,_} = dbg:tracer(process, {TraceFun, Tester}),
+ {ok,_} = dbg:p(whereis(h_proc_name()), [c]),
+ {ok,_} = dbg:tp(logger_disk_log_h, handle_info, 3, []),
+
+ Text = [34 + rand:uniform(126-34) || _ <- lists:seq(1,MaxBytes)],
+ ct:pal("String = ~p (~w)", [Text, erts_debug:size(Text)]),
+ %% fill first file
+ lists:foreach(fun(N) ->
+ Log = lists:concat([File,".",N]),
+ logger:notice(Text, ?domain),
+ wait_until_written(Log),
+ ct:pal("N = ~w",
+ [N = Get(current_file,
+ disk_log:info(?MODULE))])
+ end, lists:seq(1,MaxFiles)),
+
+ %% wait for trace messages
+ timer:sleep(1000),
+ dbg:stop_clear(),
+ Received = lists:flatmap(fun({trace,_M,handle_info,
+ [_,{disk_log,_Node,_Name,What},_]}) ->
+ [{trace,What}];
+ ({log,_}) ->
+ []
+ end, test_server:messages_get()),
+ ct:pal("Trace =~n~p", [Received]),
+ Received = [{trace,{wrap,0}} || _ <- lists:seq(1,MaxFiles-1)],
+ ok.
+
+disk_log_wrap(cleanup,_Config) ->
+ dbg:stop_clear(),
+ logger:remove_handler(?MODULE).
+
+disk_log_full(Config) ->
+ Dir = ?config(priv_dir,Config),
+ File = filename:join(Dir, ?FUNCTION_NAME),
+ ct:pal("Log = ~p", [File]),
+ MaxBytes = 50,
+ ok = logger:add_handler(?MODULE,
+ logger_disk_log_h,
+ #{filter_default=>log,
+ filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
+ formatter=>{?MODULE,self()},
+ config=>
+ #{type => halt,
+ max_no_files => 1,
+ max_no_bytes => MaxBytes,
+ file => File}}),
+
+ Tester = self(),
+ TraceFun = fun({trace,_,call,{Mod,Func,Details}}, Pid) ->
+ Pid ! {trace,Mod,Func,Details},
+ Pid
+ end,
+ {ok,_} = dbg:tracer(process, {TraceFun, Tester}),
+ {ok,_} = dbg:p(whereis(h_proc_name()), [c]),
+ {ok,_} = dbg:tp(logger_disk_log_h, handle_info, 3, []),
+
+ NoOfChars = 5,
+ Text = [34 + rand:uniform(126-34) || _ <- lists:seq(1,NoOfChars)],
+ [logger:notice(Text, ?domain) || _ <- lists:seq(1,trunc(MaxBytes/NoOfChars)+1)],
+
+ %% wait for trace messages
+ timer:sleep(2000),
+ dbg:stop_clear(),
+ Received = lists:flatmap(fun({trace,_M,handle_info,
+ [_,{disk_log,_Node,_Name,What},_]}) ->
+ [{trace,What}];
+ ({log,_}) ->
+ []
+ end, test_server:messages_get()),
+ ct:pal("Trace =~n~p", [Received]),
+
+ %% The tail here could be an error_status notification, if the
+ %% last write was synchronous, but in most cases it will not be
+ [{trace,full}|_] = Received,
+ %% [{trace,full},
+ %% {trace,{error_status,{error,{full,_}}}}] = Received,
+ ok.
+disk_log_full(cleanup, _Config) ->
+ dbg:stop_clear(),
+ logger:remove_handler(?MODULE).
+
+disk_log_events(_Config) ->
+ Node = node(),
+ Log = ?MODULE,
+ ok = logger:add_handler(?MODULE,
+ logger_disk_log_h,
+ #{filter_default=>log,
+ filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
+ formatter=>{?MODULE,self()}}),
+
+ %% Events copied from disk_log API
+ Events =
+ [{disk_log, Node, Log, {wrap, 0}},
+ {disk_log, Node, Log, {truncated, 0}},
+ {disk_log, Node, Log, {read_only, 42}},
+ {disk_log, Node, Log, {blocked_log, 42}},
+ {disk_log, Node, Log, {format_external, 42}},
+ {disk_log, Node, Log, full},
+ {disk_log, Node, Log, {error_status, ok}}],
+
+ Tester = self(),
+ TraceFun = fun({trace,_,call,{Mod,Func,Details}}, Pid) ->
+ Pid ! {trace,Mod,Func,Details},
+ Pid
+ end,
+ {ok,_} = dbg:tracer(process, {TraceFun, Tester}),
+ {ok,_} = dbg:p(whereis(h_proc_name()), [c]),
+ {ok,_} = dbg:tp(logger_disk_log_h, handle_info, 3, []),
+
+ [whereis(h_proc_name()) ! E || E <- Events],
+ %% wait for trace messages
+ timer:sleep(2000),
+ dbg:stop_clear(),
+ Received = lists:map(fun({trace,_M,handle_info,
+ [_,Got,_]}) -> Got
+ end, test_server:messages_get()),
+ ct:pal("Trace =~n~p", [Received]),
+ NoOfEvents = length(Events),
+ NoOfEvents = length(Received),
+ lists:foreach(fun(Event) ->
+ true = lists:member(Event, Received)
+ end, Received),
+ ok.
+disk_log_events(cleanup, _Config) ->
+ dbg:stop_clear(),
+ logger:remove_handler(?MODULE).
+
+write_failure(Config) ->
+ Dir = ?config(priv_dir, Config),
+ File = filename:join(Dir, ?FUNCTION_NAME),
+ Log = lists:concat([File,".1"]),
+ ct:pal("Log = ~p", [Log]),
+
+ Node = start_h_on_new_node(Config, File),
+ false = (undefined == rpc:call(Node, ets, whereis, [?TEST_HOOKS_TAB])),
+ rpc:call(Node, ets, insert, [?TEST_HOOKS_TAB,{tester,self()}]),
+ rpc:call(Node, ?MODULE, set_internal_log, [?MODULE,internal_log]),
+ rpc:call(Node, ?MODULE, set_result, [disk_log_write,ok]),
+ HState = rpc:call(Node, logger_olp, info, [h_proc_name(?STANDARD_HANDLER)]),
+ LogOpts = maps:get(log_opts,
+ maps:get(handler_state,
+ maps:get(cb_state,HState))),
+ ct:pal("LogOpts = ~p", [LogOpts]),
+
+ %% ?check and ?check_no_log in this test only check for internal log events
+ ok = log_on_remote_node(Node, "Logged1"),
+ rpc:call(Node, logger_disk_log_h, filesync, [?STANDARD_HANDLER]),
+ ?check_no_log, % no internal log when write ok
+
+ SyncRepInt = case (fun() -> is_atom(?FILESYNC_REPEAT_INTERVAL) end)() of
+ true -> 5500;
+ false -> ?FILESYNC_REPEAT_INTERVAL + 500
+ end,
+
+ try_read_file(Log, {ok,<<"Logged1\n">>}, SyncRepInt),
+
+ rpc:call(Node, ?MODULE, set_result, [disk_log_write,{error,no_such_log}]),
+ ok = log_on_remote_node(Node, "Cause simple error printout"),
+
+ %% this should have caused an internal log
+ ?check({error,{?STANDARD_HANDLER,log,LogOpts,{error,no_such_log}}}),
+
+ ok = log_on_remote_node(Node, "No second error printout"),
+ ?check_no_log, % but don't log same error twice
+
+ rpc:call(Node, ?MODULE, set_result, [disk_log_write,
+ {error,{full,?STANDARD_HANDLER}}]),
+ ok = log_on_remote_node(Node, "Cause simple error printout"),
+ %% this was a different error, so it should be logged
+ ?check({error,{?STANDARD_HANDLER,log,LogOpts,
+ {error,{full,?STANDARD_HANDLER}}}}),
+
+ rpc:call(Node, ?MODULE, set_result, [disk_log_write,ok]),
+ ok = log_on_remote_node(Node, "Logged2"),
+ rpc:call(Node, logger_disk_log_h, filesync, [?STANDARD_HANDLER]),
+ ?check_no_log, % no internal log when write ok
+ try_read_file(Log, {ok,<<"Logged1\nLogged2\n">>}, SyncRepInt),
+ ok.
+write_failure(cleanup, _Config) ->
+ Nodes = nodes(),
+ [test_server:stop_node(Node) || Node <- Nodes].
+
+
+sync_failure(Config) ->
+ Dir = ?config(priv_dir, Config),
+ FileName = lists:concat([?MODULE,"_",?FUNCTION_NAME]),
+ File = filename:join(Dir, FileName),
+
+
+ Node = start_h_on_new_node(Config, File),
+ false = (undefined == rpc:call(Node, ets, whereis, [?TEST_HOOKS_TAB])),
+ rpc:call(Node, ets, insert, [?TEST_HOOKS_TAB,{tester,self()}]),
+ rpc:call(Node, ?MODULE, set_internal_log, [?MODULE,internal_log]),
+ rpc:call(Node, ?MODULE, set_result, [disk_log_sync,ok]),
+ HState = rpc:call(Node, logger_olp, info, [h_proc_name(?STANDARD_HANDLER)]),
+ LogOpts = maps:get(log_opts, maps:get(handler_state,
+ maps:get(cb_state,HState))),
+
+ SyncInt = 500,
+ ok = rpc:call(Node, logger, update_handler_config,
+ [?STANDARD_HANDLER, config,
+ #{filesync_repeat_interval => SyncInt}]),
+ Info = rpc:call(Node, logger_olp, info, [h_proc_name(?STANDARD_HANDLER)]),
+ SyncInt = maps:get(filesync_repeat_interval, maps:get(cb_state, Info)),
+
+ ok = log_on_remote_node(Node, "Logged1"),
+ ?check_no_log,
+
+ rpc:call(Node, ?MODULE, set_result, [disk_log_sync,{error,no_such_log}]),
+ ok = log_on_remote_node(Node, "Cause simple error printout"),
+
+ ?check({error,{?STANDARD_HANDLER,filesync,LogOpts,{error,no_such_log}}}),
+
+ ok = log_on_remote_node(Node, "No second error printout"),
+ ?check_no_log,
+
+ rpc:call(Node, ?MODULE, set_result,
+ [disk_log_sync,{error,{blocked_log,?STANDARD_HANDLER}}]),
+ ok = log_on_remote_node(Node, "Cause simple error printout"),
+ ?check({error,{?STANDARD_HANDLER,filesync,LogOpts,
+ {error,{blocked_log,?STANDARD_HANDLER}}}}),
+
+ rpc:call(Node, ?MODULE, set_result, [disk_log_sync,ok]),
+ ok = log_on_remote_node(Node, "Logged2"),
+ ?check_no_log,
+ ok.
+sync_failure(cleanup, _Config) ->
+ Nodes = nodes(),
+ [test_server:stop_node(Node) || Node <- Nodes].
+
+start_h_on_new_node(Config, File) ->
+ {ok,_,Node} =
+ logger_test_lib:setup(
+ Config,
+ [{logger,[{handler,default,logger_disk_log_h,
+ #{ config => #{ file => File }}}]}]),
+ ok = rpc:call(Node,logger,set_handler_config,[?STANDARD_HANDLER,formatter,
+ {?MODULE,nl}]),
+ Node.
+
+log_on_remote_node(Node,Msg) ->
+ _ = spawn_link(Node,
+ fun() -> erlang:group_leader(whereis(user),self()),
+ logger:notice(Msg)
+ end),
+ ok.
+
+%% functions for test hook macros to be called by rpc
+set_internal_log(_Mod, _Func) ->
+ ?set_internal_log({_Mod,_Func}).
+set_result(_Op, _Result) ->
+ ?set_result(_Op, _Result).
+set_defaults() ->
+ ?set_defaults().
+
+%% internal log function that sends the term to the test case process
+internal_log(Type, Term) ->
+ [{tester,Tester}] = ets:lookup(?TEST_HOOKS_TAB, tester),
+ Tester ! {log,{Type,Term}},
+ logger:internal_log(Type, Term),
+ ok.
+
+
+%%%-----------------------------------------------------------------
+%%% Overload protection tests
+
+op_switch_to_sync(Config) ->
+ {Log,HConfig,DLHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ NumOfReqs = 500,
+ NewHConfig =
+ HConfig#{config => DLHConfig#{sync_mode_qlen => 2,
+ drop_mode_qlen => NumOfReqs+1,
+ flush_qlen => 2*NumOfReqs,
+ burst_limit_enable => false}},
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
+ send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
+ Lines = count_lines(Log),
+ NumOfReqs = Lines,
+ ok = file_delete(Log),
+ ok.
+op_switch_to_sync(cleanup, _Config) ->
+ ok = stop_handler(?MODULE).
+
+op_switch_to_drop() ->
+ [{timetrap,{seconds,180}}].
+op_switch_to_drop(Config) ->
+ Test =
+ fun() ->
+ {Log,HConfig,DLHConfig} =
+ start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ NumOfReqs = 300,
+ Procs = 2,
+ Bursts = 10,
+ NewHConfig =
+ HConfig#{config =>
+ DLHConfig#{sync_mode_qlen => 1,
+ drop_mode_qlen => 2,
+ flush_qlen => Procs*NumOfReqs*Bursts,
+ burst_limit_enable => false}},
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
+ %% It sometimes happens that the handler either gets
+ %% the requests in a slow enough pace so that dropping
+ %% never occurs. Therefore, lets generate a number of
+ %% bursts to increase the chance of message buildup.
+ [send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, notice) ||
+ _ <- lists:seq(1, Bursts)],
+ Logged = count_lines(Log),
+ ok = stop_handler(?MODULE),
+ ct:pal("Number of messages dropped = ~w (~w)",
+ [Procs*NumOfReqs*Bursts-Logged,Procs*NumOfReqs*Bursts]),
+ true = (Logged < (Procs*NumOfReqs*Bursts)),
+ true = (Logged > 0),
+ _ = file_delete(Log),
+ ok
+ end,
+ %% As it's tricky to get the timing right in only one go, we perform the
+ %% test repeatedly, hoping that will generate a successful result.
+ case repeat_until_ok(Test, 10) of
+ {ok,{Failures,_Result}} ->
+ ct:log("Failed ~w times before success!", [Failures]);
+ {fails,Reason} ->
+ ct:fail(Reason)
+ end.
+op_switch_to_drop(cleanup, _Config) ->
+ _ = stop_handler(?MODULE).
+
+op_switch_to_flush() ->
+ [{timetrap,{minutes,3}}].
+op_switch_to_flush(Config) ->
+ Test =
+ fun() ->
+ {Log,HConfig,DLHConfig} =
+ start_handler(?MODULE, ?FUNCTION_NAME, Config),
+
+ %% NOTE: it's important that both async and sync
+ %% requests have been queued when the flush happens
+ %% (verify with coverage of flush_log_requests/2)
+
+ NewHConfig =
+ HConfig#{config =>
+ DLHConfig#{sync_mode_qlen => 2,
+ %% disable drop mode
+ drop_mode_qlen => 300,
+ flush_qlen => 300,
+ burst_limit_enable => false}},
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
+ NumOfReqs = 1500,
+ Procs = 10,
+ Bursts = 10,
+ %% It sometimes happens that the handler either gets
+ %% the requests in a slow enough pace so that flushing
+ %% never occurs, or it gets all messages at once,
+ %% causing all messages to get flushed (no dropping of
+ %% sync messages gets tested). Therefore, lets
+ %% generate a number of bursts to increase the chance
+ %% of message buildup in some random fashion.
+ [send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, notice) ||
+ _ <- lists:seq(1,Bursts)],
+ Logged = count_lines(Log),
+ ok= stop_handler(?MODULE),
+ ct:pal("Number of messages flushed/dropped = ~w (~w)",
+ [NumOfReqs*Procs*Bursts-Logged,NumOfReqs*Procs*Bursts]),
+ true = (Logged < (NumOfReqs*Procs*Bursts)),
+ true = (Logged > 0),
+ _ = file_delete(Log),
+ ok
+ end,
+ %% As it's tricky to get the timing right in only one go, we perform the
+ %% test repeatedly, hoping that will generate a successful result.
+ case repeat_until_ok(Test, 10) of
+ {ok,{Failures,_Result}} ->
+ ct:log("Failed ~w times before success!", [Failures]);
+ {fails,Reason} ->
+ ct:fail(Reason)
+ end.
+op_switch_to_flush(cleanup, _Config) ->
+ _ = stop_handler(?MODULE).
+
+
+limit_burst_disabled(Config) ->
+ {Log,HConfig,DLHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ NewHConfig =
+ HConfig#{config => DLHConfig#{burst_limit_enable => false,
+ burst_limit_max_count => 10,
+ burst_limit_window_time => 2000,
+ drop_mode_qlen => 200,
+ flush_qlen => 300}},
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
+ NumOfReqs = 100,
+ send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
+ Logged = count_lines(Log),
+ ct:pal("Number of messages logged = ~w", [Logged]),
+ NumOfReqs = Logged,
+ ok = file_delete(Log),
+ ok.
+limit_burst_disabled(cleanup, _Config) ->
+ ok = stop_handler(?MODULE).
+
+limit_burst_enabled_one(Config) ->
+ {Log,HConfig,DLHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ ReqLimit = 10,
+ NewHConfig =
+ HConfig#{config => DLHConfig#{burst_limit_enable => true,
+ burst_limit_max_count => ReqLimit,
+ burst_limit_window_time => 2000,
+ drop_mode_qlen => 200,
+ flush_qlen => 300}},
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
+ NumOfReqs = 100,
+ send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
+ Logged = count_lines(Log),
+ ct:pal("Number of messages logged = ~w", [Logged]),
+ ReqLimit = Logged,
+ ok = file_delete(Log),
+ ok.
+limit_burst_enabled_one(cleanup, _Config) ->
+ ok = stop_handler(?MODULE).
+
+limit_burst_enabled_period(Config) ->
+ {Log,HConfig,DLHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ ReqLimit = 10,
+ BurstTWin = 1000,
+ NewHConfig =
+ HConfig#{config => DLHConfig#{burst_limit_enable => true,
+ burst_limit_max_count => ReqLimit,
+ burst_limit_window_time => BurstTWin,
+ drop_mode_qlen => 20000,
+ flush_qlen => 20001}},
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
+
+ Windows = 3,
+ Sent = send_burst({t,BurstTWin*Windows}, seq, {chars,79}, notice),
+ Logged = count_lines(Log),
+ ct:pal("Number of messages sent = ~w~nNumber of messages logged = ~w",
+ [Sent,Logged]),
+ true = (Logged > (ReqLimit*Windows)) andalso
+ (Logged < (ReqLimit*(Windows+2))),
+ ok = file_delete(Log),
+ ok.
+limit_burst_enabled_period(cleanup, _Config) ->
+ ok = stop_handler(?MODULE).
+
+kill_disabled(Config) ->
+ {Log,HConfig,DLHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ NewHConfig =
+ HConfig#{config=>DLHConfig#{overload_kill_enable=>false,
+ overload_kill_qlen=>10,
+ overload_kill_mem_size=>100}},
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
+ NumOfReqs = 100,
+ send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
+ Logged = count_lines(Log),
+ ct:pal("Number of messages logged = ~w", [Logged]),
+ ok = file_delete(Log),
+ true = is_pid(whereis(h_proc_name())),
+ ok.
+kill_disabled(cleanup, _Config) ->
+ ok = stop_handler(?MODULE).
+
+qlen_kill_new(Config) ->
+ {Log,HConfig,DLHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ Pid0 = whereis(h_proc_name()),
+ {_,Mem0} = process_info(Pid0, memory),
+ RestartAfter = ?OVERLOAD_KILL_RESTART_AFTER,
+ NewHConfig =
+ HConfig#{config =>
+ DLHConfig#{overload_kill_enable=>true,
+ overload_kill_qlen=>10,
+ overload_kill_mem_size=>Mem0+50000,
+ overload_kill_restart_after=>RestartAfter}},
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
+ MRef = erlang:monitor(process, Pid0),
+ NumOfReqs = 100,
+ Procs = 4,
+ send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, notice),
+ %% send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
+ receive
+ {'DOWN', MRef, _, _, Info} ->
+ case Info of
+ {shutdown,{overloaded,QLen,Mem}} ->
+ ct:pal("Terminated with qlen = ~w, mem = ~w", [QLen,Mem]);
+ killed ->
+ ct:pal("Slow shutdown, handler process was killed!", [])
+ end,
+ file_delete(Log),
+ {ok,_} = wait_for_process_up(RestartAfter * 3),
+ ok
+ after
+ 5000 ->
+ Info = logger_olp:info(h_proc_name()),
+ ct:pal("Handler state = ~p", [Info]),
+ ct:fail("Handler not dead! It should not have survived this!")
+ end.
+qlen_kill_new(cleanup, _Config) ->
+ ok = stop_handler(?MODULE).
+
+mem_kill_new(Config) ->
+ {Log,HConfig,DLHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ Pid0 = whereis(h_proc_name()),
+ {_,Mem0} = process_info(Pid0, memory),
+ RestartAfter = ?OVERLOAD_KILL_RESTART_AFTER,
+ NewHConfig =
+ HConfig#{config =>
+ DLHConfig#{overload_kill_enable=>true,
+ overload_kill_qlen=>50000,
+ overload_kill_mem_size=>Mem0+500,
+ overload_kill_restart_after=>RestartAfter}},
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
+ MRef = erlang:monitor(process, Pid0),
+ NumOfReqs = 100,
+ Procs = 4,
+ send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, notice),
+ %% send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
+ receive
+ {'DOWN', MRef, _, _, Info} ->
+ case Info of
+ {shutdown,{overloaded,QLen,Mem}} ->
+ ct:pal("Terminated with qlen = ~w, mem = ~w", [QLen,Mem]);
+ killed ->
+ ct:pal("Slow shutdown, handler process was killed!", [])
+ end,
+ file_delete(Log),
+ {ok,_} = wait_for_process_up(RestartAfter * 3),
+ ok
+ after
+ 5000 ->
+ Info = logger_olp:info(h_proc_name()),
+ ct:pal("Handler state = ~p", [Info]),
+ ct:fail("Handler not dead! It should not have survived this!")
+ end.
+mem_kill_new(cleanup, _Config) ->
+ ok = stop_handler(?MODULE).
+
+restart_after() ->
+ [{timetrap,{minutes,2}}].
+restart_after(Config) ->
+ {Log,HConfig,DLHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ NewHConfig1 =
+ HConfig#{config=>DLHConfig#{overload_kill_enable=>true,
+ overload_kill_qlen=>4,
+ overload_kill_restart_after=>infinity}},
+ ok = logger:update_handler_config(?MODULE, NewHConfig1),
+ MRef1 = erlang:monitor(process, whereis(h_proc_name())),
+ %% kill handler
+ send_burst({n,100}, {spawn,5,0}, {chars,79}, notice),
+ receive
+ {'DOWN', MRef1, _, _, _Reason1} ->
+ file_delete(Log),
+ error = wait_for_process_up(?OVERLOAD_KILL_RESTART_AFTER * 3),
+ ok
+ after
+ 5000 ->
+ Info1 = logger_olp:info(h_proc_name()),
+ ct:pal("Handler state = ~p", [Info1]),
+ ct:fail("Handler not dead! It should not have survived this!")
+ end,
+
+ {Log,_,_} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ RestartAfter = ?OVERLOAD_KILL_RESTART_AFTER,
+ NewHConfig2 =
+ HConfig#{config=>DLHConfig#{overload_kill_enable=>true,
+ overload_kill_qlen=>4,
+ overload_kill_restart_after=>RestartAfter}},
+ ok = logger:update_handler_config(?MODULE, NewHConfig2),
+ Pid0 = whereis(h_proc_name()),
+ MRef2 = erlang:monitor(process, Pid0),
+ %% kill handler
+ send_burst({n,100}, {spawn,5,0}, {chars,79}, notice),
+ receive
+ {'DOWN', MRef2, _, _, _Reason2} ->
+ file_delete(Log),
+ {ok,Pid1} = wait_for_process_up(RestartAfter * 3),
+ false = (Pid1 == Pid0),
+ ok
+ after
+ 5000 ->
+ Info2 = logger_olp:info(h_proc_name()),
+ ct:pal("Handler state = ~p", [Info2]),
+ ct:fail("Handler not dead! It should not have survived this!")
+ end,
+ ok.
+restart_after(cleanup, _Config) ->
+ ok = stop_handler(?MODULE).
+
+%% send handler requests (sync, info, reset, change_config)
+%% during high load to verify that sync, dropping and flushing is
+%% handled correctly.
+handler_requests_under_load() ->
+ [{timetrap,{minutes,5}}].
+handler_requests_under_load(Config) ->
+ {Log,HConfig,DLHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ NewHConfig =
+ HConfig#{config => DLHConfig#{sync_mode_qlen => 2,
+ drop_mode_qlen => 1000,
+ flush_qlen => 2000,
+ burst_limit_enable => false}},
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
+ Pid = spawn_link(
+ fun() -> send_requests(1,[{logger_disk_log_h,filesync,[?MODULE],[]},
+ {logger_olp,info,[h_proc_name()],[]},
+ {logger_olp,reset,[h_proc_name()],[]},
+ {logger,update_handler_config,
+ [?MODULE, config,
+ #{overload_kill_enable => false}],
+ []}])
+ end),
+ Procs = 100,
+ Sent = Procs * send_burst({n,5000}, {spawn,Procs,10}, {chars,79}, notice),
+ Pid ! {self(),finish},
+ ReqResult = receive {Pid,Result} -> Result end,
+ Logged = count_lines(Log),
+ ct:pal("Number of messages sent = ~w~nNumber of messages logged = ~w",
+ [Sent,Logged]),
+ FindError = fun(Res) ->
+ [E || E <- Res,
+ is_tuple(E) andalso (element(1,E) == error)]
+ end,
+ Errors = [{Func,FindError(Res)} || {_,Func,_,Res} <- ReqResult],
+ NoOfReqs = lists:foldl(fun({_,_,_,Res}, N) -> N + length(Res) end,
+ 0, ReqResult),
+ ct:pal("~w requests made. Errors: ~n~p", [NoOfReqs,Errors]),
+ ok = file_delete(Log).
+handler_requests_under_load(cleanup, _Config) ->
+ ok = stop_handler(?MODULE).
+
+send_requests(TO, Reqs = [{Mod,Func,Args,Res}|Rs]) ->
+ receive
+ {From,finish} ->
+ From ! {self(),Reqs}
+ after
+ TO ->
+ Result = apply(Mod,Func,Args),
+ send_requests(TO, Rs ++ [{Mod,Func,Args,[Result|Res]}])
+ end.
+
+%%%-----------------------------------------------------------------
+%%%
+start_handler(Name, FuncName, Config) ->
+ Dir = ?config(priv_dir,Config),
+ File = filename:join(Dir, FuncName),
+ ct:pal("Logging to ~tp", [File]),
+ FullFile = lists:concat([File,".1"]),
+ _ = file_delete(FullFile),
+ ok = logger:add_handler(Name,
+ logger_disk_log_h,
+ #{config=>#{file => File,
+ max_no_files => 1,
+ max_no_bytes => 100000000},
+ filter_default=>log,
+ filters=>?DEFAULT_HANDLER_FILTERS([Name]),
+ formatter=>{?MODULE,op}}),
+ {ok,HConfig = #{config := DLHConfig}} = logger:get_handler_config(Name),
+ {FullFile,HConfig,DLHConfig}.
+
+stop_handler(Name) ->
+ ct:pal("Stopping handler ~p!", [Name]),
+ logger:remove_handler(Name).
+
+send_burst(NorT, Type, {chars,Sz}, Class) ->
+ Text = [34 + rand:uniform(126-34) || _ <- lists:seq(1,Sz)],
+ case NorT of
+ {n,N} ->
+ %% process_flag(priority, high),
+ send_n_burst(N, Type, Text, Class),
+ %% process_flag(priority, normal),
+ N;
+ {t,T} ->
+ ct:pal("Sending messages sequentially for ~w ms", [T]),
+ T0 = erlang:monotonic_time(millisecond),
+ send_t_burst(T0, T, Text, Class, 0)
+ end.
+
+send_n_burst(0, _, _Text, _Class) ->
+ ok;
+send_n_burst(N, seq, Text, Class) ->
+ ok = logger:Class(Text, ?domain),
+ send_n_burst(N-1, seq, Text, Class);
+send_n_burst(N, {spawn,Ps,TO}, Text, Class) ->
+ ct:pal("~w processes each sending ~w messages", [Ps,N]),
+ MRefs = [begin if TO == 0 -> ok; true -> timer:sleep(TO) end,
+ monitor(process,spawn_link(per_proc_fun(N,Text,Class,X)))
+ end || X <- lists:seq(1,Ps)],
+ lists:foreach(fun(MRef) ->
+ receive
+ {'DOWN', MRef, _, _, _} ->
+ ok
+ end
+ end, MRefs),
+ ct:pal("Message burst sent", []),
+ ok.
+
+send_t_burst(T0, T, Text, Class, N) ->
+ T1 = erlang:monotonic_time(millisecond),
+ if (T1-T0) > T ->
+ N;
+ true ->
+ ok = logger:Class(Text, ?domain),
+ send_t_burst(T0, T, Text, Class, N+1)
+ end.
+
+per_proc_fun(N,Text,Class,X) when X rem 2 == 0 ->
+ fun() ->
+ process_flag(priority,high),
+ send_n_burst(N, seq, Text, Class)
+ end;
+per_proc_fun(N,Text,Class,_) ->
+ fun() ->
+ send_n_burst(N, seq, Text, Class)
+ end.
+
+%%%-----------------------------------------------------------------
+%%% Formatter callback
+%%% Using this to send the formatted string back to the test case
+%%% process - so it can check for logged events.
+format(_,bad_return) ->
+ bad_return;
+format(_,crash) ->
+ erlang:error(formatter_crashed);
+format(#{msg:={report,R},meta:=#{report_cb:=Fun}}=Log,Config) ->
+ format(Log#{msg=>Fun(R)},Config);
+format(#{msg:={string,String0}},no_nl) ->
+ String = unicode:characters_to_list(String0),
+ String;
+format(#{msg:={string,String0}},nl) ->
+ String = unicode:characters_to_list(String0),
+ String++"\n";
+format(#{msg:={string,String0}},op) ->
+ String = unicode:characters_to_list(String0),
+ String++"\n";
+format(#{msg:={report,#{label:={supervisor,progress}}}},op) ->
+ "";
+format(#{msg:={report,#{label:={gen_server,terminate}}}},op) ->
+ "";
+format(#{msg:={report,#{label:={proc_lib,crash}}}},op) ->
+ "";
+format(#{msg:={F,A}},OpOrPid) when is_list(F), is_list(A) ->
+ String = lists:flatten(io_lib:format(F,A)),
+ if is_pid(OpOrPid) -> OpOrPid ! {log,String};
+ true -> ok
+ end,
+ String++"\n";
+format(#{msg:={string,String0}},Pid) ->
+ String = unicode:characters_to_list(String0),
+ Pid ! {log,String},
+ String++"\n";
+format(Msg,Tag) ->
+ Error = {unexpected_format,Msg,Tag},
+ erlang:display(Error),
+ exit(Error).
+
+start_and_add(Name, Config, LogOpts) ->
+ HConfig = maps:get(config, Config, #{}),
+ HConfig1 = maps:merge(HConfig, LogOpts),
+ Config1 = Config#{config=>HConfig1},
+ ct:pal("Adding handler ~w with: ~p", [Name,Config1]),
+ ok = logger:add_handler(Name, logger_disk_log_h, Config1),
+ Pid = whereis(h_proc_name(Name)),
+ true = is_pid(Pid),
+ Name = proplists:get_value(name, disk_log:info(Name)),
+ ok.
+
+remove_and_stop(Handler) ->
+ ok = logger:remove_handler(Handler),
+ timer:sleep(500),
+ undefined = whereis(h_proc_name(Handler)),
+ ok.
+
+try_read_file(FileName, Expected, Time) ->
+ try_read_file(FileName, Expected, Time, undefined).
+
+try_read_file(FileName, Expected, Time, _) when Time > 0 ->
+ case file:read_file(FileName) of
+ Expected ->
+ ok;
+ Error = {error,_Reason} ->
+ erlang:error(Error);
+ SomethingElse ->
+ ct:pal("try_read_file read unexpected: ~p~n", [SomethingElse]),
+ timer:sleep(500),
+ try_read_file(FileName, Expected, Time-500, SomethingElse)
+ end;
+
+try_read_file(_, _, _, Incorrect) ->
+ ct:pal("try_read_file got incorrect pattern: ~p~n", [Incorrect]),
+ erlang:error({error,not_matching_pattern,Incorrect}).
+
+try_match_file(FileName, Pattern, Time) ->
+ try_match_file(FileName, Pattern, Time, <<>>).
+
+try_match_file(FileName, Pattern, Time, _) when Time > 0 ->
+ case file:read_file(FileName) of
+ {ok, Bin} ->
+ case re:run(Bin,Pattern,[{capture,none}]) of
+ match ->
+ unicode:characters_to_list(Bin);
+ _ ->
+ timer:sleep(100),
+ try_match_file(FileName, Pattern, Time-100, Bin)
+ end;
+ Error ->
+ erlang:error(Error)
+ end;
+try_match_file(_,Pattern,_,Incorrect) ->
+ ct:pal("try_match_file did not match pattern: ~p~nGot: ~p~n",
+ [Pattern,Incorrect]),
+ erlang:error({error,not_matching_pattern,Pattern,Incorrect}).
+
+count_lines(File) ->
+ wait_until_written(File),
+ count_lines1(File).
+
+wait_until_written(File) ->
+ wait_until_written(File, -1).
+
+wait_until_written(File, Sz) ->
+ timer:sleep(2000),
+ case file:read_file_info(File) of
+ {ok,#file_info{size = Sz}} ->
+ timer:sleep(1000),
+ case file:read_file_info(File) of
+ {ok,#file_info{size = Sz}} ->
+ ok;
+ {ok,#file_info{size = Sz1}} ->
+ wait_until_written(File, Sz1)
+ end;
+ {ok,#file_info{size = Sz1}} ->
+ wait_until_written(File, Sz1)
+ end.
+
+count_lines1(File) ->
+ {_,Dev} = file:open(File, [read]),
+ Lines = count_lines2(Dev, 0),
+ file:close(Dev),
+ Lines.
+
+count_lines2(Dev, LC) ->
+ case file:read_line(Dev) of
+ {ok,"Handler logger_disk_log_h_SUITE " ++_} ->
+ %% Not counting handler info
+ count_lines2(Dev,LC);
+ {ok,_} ->
+ count_lines2(Dev,LC+1);
+ eof -> LC
+ end.
+
+repeat_until_ok(Fun, N) ->
+ repeat_until_ok(Fun, 0, N, undefined).
+
+repeat_until_ok(_Fun, Stop, Stop, Reason) ->
+ {fails,Reason};
+
+repeat_until_ok(Fun, C, Stop, FirstReason) ->
+ if C > 0 -> timer:sleep(5000);
+ true -> ok
+ end,
+ try Fun() of
+ Result ->
+ {ok,{C,Result}}
+ catch
+ _:Reason:Stack ->
+ ct:pal("Test fails: ~p (~p)~n", [Reason,hd(Stack)]),
+ if FirstReason == undefined ->
+ repeat_until_ok(Fun, C+1, Stop, {Reason,Stack});
+ true ->
+ repeat_until_ok(Fun, C+1, Stop, FirstReason)
+ end
+ end.
+
+start_tracer(Trace,Expected) ->
+ Pid = self(),
+ dbg:tracer(process,{fun tracer/2,{Pid,Expected}}),
+ dbg:p(h_proc_name(),[c]),
+ tpl(Trace),
+ ok.
+
+tpl([{M,F,A}|Trace]) ->
+ tpl([{{M,F,A},c}|Trace]);
+tpl([{{M,F,A},MS}|Trace]) ->
+ {ok,Match} = dbg:tpl(M,F,A,MS),
+ case lists:keyfind(matched,1,Match) of
+ {_,_,1} ->
+ ok;
+ _ ->
+ dbg:stop_clear(),
+ throw({skip,"Can't trace "++atom_to_list(M)++":"++
+ atom_to_list(F)++"/"++integer_to_list(A)})
+ end,
+ tpl(Trace);
+tpl([]) ->
+ ok.
+
+tracer({trace,_,call,{logger_h_common,handle_cast,[Op|_]},Caller},
+ {Pid,[{Mod,Func,Op}|Expected]}) ->
+ maybe_tracer_done(Pid,Expected,{Mod,Func,Op},Caller);
+tracer({trace,_,call,{Mod=logger_disk_log_h,Func=disk_log_write,[_,_,Data]},Caller}, {Pid,[{Mod,Func,Data}|Expected]}) ->
+ maybe_tracer_done(Pid,Expected,{Mod,Func,Data},Caller);
+tracer({trace,_,call,{Mod,Func,_},Caller}, {Pid,[{Mod,Func}|Expected]}) ->
+ maybe_tracer_done(Pid,Expected,{Mod,Func},Caller);
+tracer({trace,_,call,Call,Caller}, {Pid,Expected}) ->
+ ct:log("Tracer got unexpected: ~p~nCaller: ~p~nExpected: ~p~n",[Call,Caller,Expected]),
+ Pid ! {tracer_got_unexpected,Call,Expected},
+ {Pid,Expected}.
+
+maybe_tracer_done(Pid,[],Got,Caller) ->
+ ct:log("Tracer got: ~p~nCaller: ~p~n",[Got,Caller]),
+ Pid ! tracer_done;
+maybe_tracer_done(Pid,Expected,Got,Caller) ->
+ ct:log("Tracer got: ~p~nCaller: ~p~n",[Got,Caller]),
+ {Pid,Expected}.
+
+check_tracer(T) ->
+ receive
+ tracer_done ->
+ dbg:stop_clear(),
+ ok;
+ {tracer_got_unexpected,Got,Expected} ->
+ dbg:stop_clear(),
+ ct:fail({tracer_got_unexpected,Got,Expected})
+ after T ->
+ dbg:stop_clear(),
+ ct:fail({timeout,tracer})
+ end.
+
+escape([$+|Rest]) ->
+ [$\\,$+|escape(Rest)];
+escape([H|T]) ->
+ [H|escape(T)];
+escape([]) ->
+ [].
+
+h_proc_name() ->
+ h_proc_name(?MODULE).
+h_proc_name(Name) ->
+ list_to_atom(lists:concat([logger_disk_log_h,"_",Name])).
+
+wait_for_process_up(T) ->
+ wait_for_process_up(?MODULE, h_proc_name(), T).
+
+wait_for_process_up(Name, RegName, T) ->
+ N = (T div 500) + 1,
+ wait_for_process_up1(Name, RegName, N).
+
+wait_for_process_up1(_Name, _RegName, 0) ->
+ error;
+wait_for_process_up1(Name, RegName, N) ->
+ timer:sleep(500),
+ case whereis(RegName) of
+ Pid when is_pid(Pid) ->
+ case logger:get_handler_config(Name) of
+ {ok,_} ->
+ %% ct:pal("Process ~p up (~p tries left)",[Name,N]),
+ {ok,Pid};
+ _ ->
+ wait_for_process_up1(Name, RegName, N-1)
+ end;
+ undefined ->
+ %% ct:pal("Waiting for process ~p (~p tries left)",[Name,N]),
+ wait_for_process_up1(Name, RegName, N-1)
+ end.
+
+file_delete(Log) ->
+ file:delete(Log).
diff --git a/lib/kernel/test/logger_env_var_SUITE.erl b/lib/kernel/test/logger_env_var_SUITE.erl
new file mode 100644
index 0000000000..9d2ad11be8
--- /dev/null
+++ b/lib/kernel/test/logger_env_var_SUITE.erl
@@ -0,0 +1,697 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(logger_env_var_SUITE).
+
+-compile(export_all).
+
+-include_lib("kernel/include/logger.hrl").
+-include_lib("kernel/src/logger_internal.hrl").
+
+-import(logger_test_lib,[setup/2,log/3,sync_and_read/3]).
+
+suite() ->
+ [{timetrap,{seconds,60}},
+ {ct_hooks,[logger_test_lib]}].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+groups() ->
+ [{error_logger,[],[error_logger_tty,
+ error_logger_tty_sasl_compatible,
+ error_logger_false,
+ error_logger_false_progress,
+ error_logger_false_sasl_compatible,
+ error_logger_silent,
+ error_logger_silent_sasl_compatible,
+ error_logger_file]},
+ {logger,[],[logger_file,
+ logger_file_sasl_compatible,
+ logger_file_log_progress,
+ logger_file_no_filter,
+ logger_file_no_filter_level,
+ logger_file_formatter,
+ logger_filters,
+ logger_filters_stop,
+ logger_module_level,
+ logger_disk_log,
+ logger_disk_log_formatter,
+ logger_undefined,
+ logger_many_handlers_default_first,
+ logger_many_handlers_default_last,
+ logger_many_handlers_default_last_broken_filter,
+ logger_proxy
+ ]},
+ {bad,[],[bad_error_logger,
+ bad_level,
+ bad_sasl_compatibility]}].
+
+all() ->
+ [default,
+ default_sasl_compatible,
+ sasl_compatible_false,
+ sasl_compatible_false_no_progress,
+ sasl_compatible,
+ all_logger_level,
+ {group,bad},
+ {group,error_logger},
+ {group,logger}
+ ].
+
+default(Config) ->
+ {ok,#{primary:=P,handlers:=Hs,module_levels:=ML},_Node} = setup(Config,[]),
+ notice = maps:get(level,P),
+ #{module:=logger_std_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ all = maps:get(level,StdC),
+ StdFilters = maps:get(filters,StdC),
+ {domain,{_,{log,super,[otp,sasl]}}} = lists:keyfind(domain,1,StdFilters),
+ false = exists(simple,Hs),
+ false = exists(sasl,Hs),
+ [] = ML,
+ ok.
+
+default_sasl_compatible(Config) ->
+ {ok,#{primary:=P,handlers:=Hs,module_levels:=ML},_Node} =
+ setup(Config,[{logger_sasl_compatible,true}]),
+ info = maps:get(level,P),
+ #{module:=logger_std_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ all = maps:get(level,StdC),
+ StdFilters = maps:get(filters,StdC),
+ {domain,{_,{log,super,[otp]}}} = lists:keyfind(domain,1,StdFilters),
+ false = exists(simple,Hs),
+ true = exists(sasl,Hs),
+ [] = ML,
+ ok.
+
+error_logger_tty(Config) ->
+ {ok,#{primary:=P,handlers:=Hs,module_levels:=ML},_Node} =
+ setup(Config,[{error_logger,tty}]),
+ notice = maps:get(level,P),
+ #{module:=logger_std_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ all = maps:get(level,StdC),
+ StdFilters = maps:get(filters,StdC),
+ {domain,{_,{log,super,[otp,sasl]}}} = lists:keyfind(domain,1,StdFilters),
+ false = exists(simple,Hs),
+ false = exists(sasl,Hs),
+ [] = ML,
+ ok.
+
+error_logger_tty_sasl_compatible(Config) ->
+ {ok,#{primary:=P,handlers:=Hs,module_levels:=ML},_Node} =
+ setup(Config,
+ [{error_logger,tty},
+ {logger_sasl_compatible,true}]),
+ info = maps:get(level,P),
+ #{module:=logger_std_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ all = maps:get(level,StdC),
+ StdFilters = maps:get(filters,StdC),
+ {domain,{_,{log,super,[otp]}}} = lists:keyfind(domain,1,StdFilters),
+ false = exists(simple,Hs),
+ true = exists(sasl,Hs),
+ [] = ML,
+ ok.
+
+error_logger_false(Config) ->
+ {ok,#{handlers:=Hs,primary:=P,module_levels:=ML},_Node} =
+ setup(Config,
+ [{error_logger,false},
+ {logger_level,notice}]),
+ false = exists(?STANDARD_HANDLER,Hs),
+ #{module:=logger_simple_h} = SimpleC = find(simple,Hs),
+ all = maps:get(level,SimpleC),
+ notice = maps:get(level,P),
+ SimpleFilters = maps:get(filters,SimpleC),
+ {domain,{_,{log,super,[otp,sasl]}}} = lists:keyfind(domain,1,SimpleFilters),
+ false = exists(sasl,Hs),
+ [] = ML,
+ ok.
+
+error_logger_false_progress(Config) ->
+ {ok,#{handlers:=Hs,primary:=P,module_levels:=ML},_Node} =
+ setup(Config,
+ [{error_logger,false},
+ {logger_level,notice}]),
+ false = exists(?STANDARD_HANDLER,Hs),
+ #{module:=logger_simple_h} = SimpleC = find(simple,Hs),
+ all = maps:get(level,SimpleC),
+ notice = maps:get(level,P),
+ SimpleFilters = maps:get(filters,SimpleC),
+ {domain,{_,{log,super,[otp,sasl]}}} = lists:keyfind(domain,1,SimpleFilters),
+ false = exists(sasl,Hs),
+ [] = ML,
+ ok.
+
+error_logger_false_sasl_compatible(Config) ->
+ {ok,#{handlers:=Hs,primary:=P,module_levels:=ML},_Node} =
+ setup(Config,
+ [{error_logger,false},
+ {logger_level,notice},
+ {logger_sasl_compatible,true}]),
+ false = exists(?STANDARD_HANDLER,Hs),
+ #{module:=logger_simple_h} = SimpleC = find(simple,Hs),
+ all = maps:get(level,SimpleC),
+ info = maps:get(level,P),
+ SimpleFilters = maps:get(filters,SimpleC),
+ {domain,{_,{log,super,[otp]}}} = lists:keyfind(domain,1,SimpleFilters),
+ true = exists(sasl,Hs),
+ [] = ML,
+ ok.
+
+error_logger_silent(Config) ->
+ {ok,#{handlers:=Hs},_Node} = setup(Config,
+ [{error_logger,silent}]),
+ false = exists(?STANDARD_HANDLER,Hs),
+ false = exists(simple,Hs),
+ false = exists(sasl,Hs),
+ ok.
+
+error_logger_silent_sasl_compatible(Config) ->
+ {ok,#{handlers:=Hs},_Node} = setup(Config,
+ [{error_logger,silent},
+ {logger_sasl_compatible,true}]),
+ false = exists(?STANDARD_HANDLER,Hs),
+ false = exists(simple,Hs),
+ true = exists(sasl,Hs),
+ ok.
+
+
+error_logger_file(Config) ->
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,_,Node} = setup(Config,
+ [{error_logger,{file,Log}}]),
+ check_default_log(Node,Log,
+ file,% dest
+ 0),% progress in std logger
+ ok.
+
+
+logger_file(Config) ->
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,#{primary:=P,handlers:=Hs,module_levels:=ML},Node}
+ = setup(Config,
+ [{logger,
+ [{handler,?STANDARD_HANDLER,logger_std_h,
+ #{config=>#{type=>{file,Log}}}}]}]),
+ check_default_log(Node,Log,
+ file,% dest
+ 0),% progress in std logger
+
+ notice = maps:get(level,P),
+ #{module:=logger_std_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ all = maps:get(level,StdC),
+ StdFilters = maps:get(filters,StdC),
+ {domain,{_,{log,super,[otp,sasl]}}} = lists:keyfind(domain,1,StdFilters),
+ false = exists(simple,Hs),
+ false = exists(sasl,Hs),
+ [] = ML,
+ ok.
+
+logger_file_sasl_compatible(Config) ->
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,#{primary:=P,handlers:=Hs,module_levels:=ML},Node}
+ = setup(Config,
+ [{logger_sasl_compatible,true},
+ {logger,
+ [{handler,?STANDARD_HANDLER,logger_std_h,
+ #{config=>#{type=>{file,Log}}}}]}]),
+ check_default_log(Node,Log,
+ file,% dest
+ 0),% progress in std logger
+
+ info = maps:get(level,P),
+ #{module:=logger_std_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ all = maps:get(level,StdC),
+ StdFilters = maps:get(filters,StdC),
+ {domain,{_,{log,super,[otp]}}} = lists:keyfind(domain,1,StdFilters),
+ false = exists(simple,Hs),
+ true = exists(sasl,Hs),
+ [] = ML,
+ ok.
+
+logger_file_log_progress(Config) ->
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,#{primary:=P,handlers:=Hs,module_levels:=ML},Node}
+ = setup(Config,
+ [{logger_level,info},
+ {logger,
+ [{handler,?STANDARD_HANDLER,logger_std_h,
+ #{config=>#{type=>{file,Log}}}}]}]),
+ check_default_log(Node,Log,
+ file,% dest
+ 6,% progress in std logger
+ info),
+
+ info = maps:get(level,P),
+ #{module:=logger_std_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ all = maps:get(level,StdC),
+ StdFilters = maps:get(filters,StdC),
+ {domain,{_,{log,super,[otp,sasl]}}} = lists:keyfind(domain,1,StdFilters),
+ false = exists(simple,Hs),
+ false = exists(sasl,Hs),
+ [] = ML,
+ ok.
+
+logger_file_no_filter(Config) ->
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,#{handlers:=Hs},Node}
+ = setup(Config,
+ [{logger,
+ [{handler,?STANDARD_HANDLER,logger_std_h,
+ #{filter_default=>log,filters=>[],
+ config=>#{type=>{file,Log}}}}]}]),
+ check_default_log(Node,Log,
+ file,% dest
+ 6),% progress in std logger
+
+ #{module:=logger_std_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ all = maps:get(level,StdC),
+ [] = maps:get(filters,StdC),
+ false = exists(simple,Hs),
+ false = exists(sasl,Hs),
+
+ ok.
+
+logger_file_no_filter_level(Config) ->
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,#{handlers:=Hs},Node}
+ = setup(Config,
+ [{logger,
+ [{handler,?STANDARD_HANDLER,logger_std_h,
+ #{filters=>[],level=>error,
+ config=>#{type=>{file,Log}}}}]}]),
+ check_default_log(Node,Log,
+ file,% dest
+ 0,% progress in std logger
+ error),% level
+
+ #{module:=logger_std_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ error = maps:get(level,StdC),
+ [] = maps:get(filters,StdC),
+ false = exists(simple,Hs),
+ false = exists(sasl,Hs),
+
+ ok.
+
+logger_file_formatter(Config) ->
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,#{handlers:=Hs},Node}
+ = setup(Config,
+ [{logger,
+ [{handler,?STANDARD_HANDLER,logger_std_h,
+ #{filters=>[],
+ formatter=>{logger_formatter,#{}},
+ config=>#{type=>{file,Log}}}}]}]),
+ check_single_log(Node,Log,
+ file,% dest
+ 6),% progress in std logger
+
+ #{module:=logger_std_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ all = maps:get(level,StdC),
+ [] = maps:get(filters,StdC),
+ false = exists(simple,Hs),
+ false = exists(sasl,Hs),
+
+ ok.
+
+logger_filters(Config) ->
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,#{handlers:=Hs,primary:=P},Node}
+ = setup(Config,
+ [{logger_level,info},
+ {logger,
+ [{handler,?STANDARD_HANDLER,logger_std_h,
+ #{config=>#{type=>{file,Log}}}},
+ {filters,log,[{stop_progress,{fun logger_filters:progress/2,stop}}]}
+ ]}]),
+ check_default_log(Node,Log,
+ file,% dest
+ 0,% progress in std logger
+ info),
+
+ #{module:=logger_std_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ all = maps:get(level,StdC),
+ StdFilters = maps:get(filters,StdC),
+ {domain,{_,{log,super,[otp,sasl]}}} = lists:keyfind(domain,1,StdFilters),
+ false = exists(simple,Hs),
+ false = exists(sasl,Hs),
+ LoggerFilters = maps:get(filters,P),
+ true = lists:keymember(stop_progress,1,LoggerFilters),
+
+ ok.
+
+logger_filters_stop(Config) ->
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,#{handlers:=Hs,primary:=P},Node}
+ = setup(Config,
+ [{logger_level,info},
+ {logger,
+ [{handler,?STANDARD_HANDLER,logger_std_h,
+ #{filters=>[],
+ config=>#{type=>{file,Log}}}},
+ {filters,stop,[{log_error,{fun logger_filters:level/2,{log,gt,info}}}]}
+ ]}]),
+ check_default_log(Node,Log,
+ file,% dest
+ 0,% progress in std logger
+ info),
+
+ #{module:=logger_std_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ all = maps:get(level,StdC),
+ [] = maps:get(filters,StdC),
+ false = exists(simple,Hs),
+ false = exists(sasl,Hs),
+ LoggerFilters = maps:get(filters,P),
+ true = lists:keymember(log_error,1,LoggerFilters),
+
+ ok.
+
+logger_module_level(Config) ->
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,#{handlers:=Hs,module_levels:=ModuleLevels},Node}
+ = setup(Config,
+ [{logger_level,info},
+ {logger,
+ [{handler,?STANDARD_HANDLER,logger_std_h,
+ #{config=>#{type=>{file,Log}}}},
+ {module_level,error,[supervisor]}
+ ]}]),
+ check_default_log(Node,Log,
+ file,% dest
+ 3,% progress in std logger
+ info),
+
+ #{module:=logger_std_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ all = maps:get(level,StdC),
+ StdFilters = maps:get(filters,StdC),
+ {domain,{_,{log,super,[otp,sasl]}}} = lists:keyfind(domain,1,StdFilters),
+ false = exists(simple,Hs),
+ false = exists(sasl,Hs),
+ [{supervisor,error}] = ModuleLevels,
+ ok.
+
+logger_disk_log(Config) ->
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,#{handlers:=Hs},Node}
+ = setup(Config,
+ [{logger,
+ [{handler,?STANDARD_HANDLER,logger_disk_log_h,
+ #{config=>#{file=>Log}}}]}]),
+ check_default_log(Node,Log,
+ disk_log,% dest
+ 0),% progress in std logger
+
+ #{module:=logger_disk_log_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ all = maps:get(level,StdC),
+ StdFilters = maps:get(filters,StdC),
+ {domain,{_,{log,super,[otp,sasl]}}} = lists:keyfind(domain,1,StdFilters),
+ false = exists(simple,Hs),
+ false = exists(sasl,Hs),
+
+ ok.
+
+logger_disk_log_formatter(Config) ->
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,#{handlers:=Hs},Node}
+ = setup(Config,
+ [{logger,
+ [{handler,?STANDARD_HANDLER,logger_disk_log_h,
+ #{filters=>[],
+ formatter=>{logger_formatter,#{}},
+ config=>#{file=>Log}}}]}]),
+ check_single_log(Node,Log,
+ disk_log,% dest
+ 6),% progress in std logger
+
+ #{module:=logger_disk_log_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ all = maps:get(level,StdC),
+ [] = maps:get(filters,StdC),
+ false = exists(simple,Hs),
+ false = exists(sasl,Hs),
+
+ ok.
+
+logger_undefined(Config) ->
+ {ok,#{handlers:=Hs,primary:=P},_Node} =
+ setup(Config,[{logger,[{handler,?STANDARD_HANDLER,undefined}]}]),
+ false = exists(?STANDARD_HANDLER,Hs),
+ #{module:=logger_simple_h} = SimpleC = find(simple,Hs),
+ all = maps:get(level,SimpleC),
+ notice = maps:get(level,P),
+ SimpleFilters = maps:get(filters,SimpleC),
+ {domain,{_,{log,super,[otp,sasl]}}} = lists:keyfind(domain,1,SimpleFilters),
+ false = exists(sasl,Hs),
+ ok.
+
+
+%% Test that we can add multiple handlers with the default first
+logger_many_handlers_default_first(Config) ->
+ LogErr = file(Config,logger_many_handlers_default_first_error),
+ LogInfo = file(Config,logger_many_handlers_default_first_info),
+
+ logger_many_handlers(
+ Config,[{logger,
+ [{handler,?STANDARD_HANDLER,logger_std_h,
+ #{level=>error,
+ filters=>[],
+ formatter=>{logger_formatter,#{}},
+ config=>#{type=>{file,LogErr}}}
+ },
+ {handler,info,logger_std_h,
+ #{level=>info,
+ filters=>[{level,{fun logger_filters:level/2,{stop,gteq,error}}}],
+ config=>#{type=>{file,LogInfo}}}
+ }
+ ]},
+ {logger_level,info}], LogErr, LogInfo, 6).
+
+%% Test that we can add multiple handlers with the default last
+logger_many_handlers_default_last(Config) ->
+ LogErr = file(Config,logger_many_handlers_default_last_error),
+ LogInfo = file(Config,logger_many_handlers_default_last_info),
+ logger_many_handlers(
+ Config,[{logger,
+ [{handler,info,logger_std_h,
+ #{level=>info,
+ filters=>[{level,{fun logger_filters:level/2,{stop,gteq,error}}}],
+ config=>#{type=>{file,LogInfo}}}
+ },
+ {handler,?STANDARD_HANDLER,logger_std_h,
+ #{level=>error,
+ filters=>[],
+ formatter=>{logger_formatter,#{}},
+ config=>#{type=>{file,LogErr}}}
+ }
+ ]},
+ {logger_level,info}], LogErr, LogInfo, 7).
+
+%% Check that we can handle that an added logger has a broken filter
+%% This used to cause a deadlock.
+logger_many_handlers_default_last_broken_filter(Config) ->
+ LogErr = file(Config,logger_many_handlers_default_first_broken_filter_error),
+ LogInfo = file(Config,logger_many_handlers_default_first_broken_filter_info),
+
+ logger_many_handlers(
+ Config,[{logger,
+ [{handler,info,logger_std_h,
+ #{level=>info,
+ filters=>[{broken,{fun logger_filters:level/2,broken_state}},
+ {level,{fun logger_filters:level/2,{stop,gteq,error}}}],
+ config=>#{type=>{file,LogInfo}}}
+ },
+ {handler,?STANDARD_HANDLER,logger_std_h,
+ #{level=>error,
+ filters=>[],
+ formatter=>{logger_formatter,#{}},
+ config=>#{type=>{file,LogErr}}}
+ }
+ ]},
+ {logger_level,info}], LogErr, LogInfo, 7).
+
+logger_many_handlers(Config, Env, LogErr, LogInfo, NumProgress) ->
+ {ok,_,Node} = setup(Config,Env),
+ check_single_log(Node,LogErr,
+ file,% dest
+ 0,% progress in std logger
+ error), % level
+ ok = rpc:call(Node,logger_std_h,filesync,[info]),
+ {ok, Bin} = file:read_file(LogInfo),
+ ct:log("Log content:~n~s",[Bin]),
+ match(Bin,<<"info:">>,NumProgress,info,info),
+ match(Bin,<<"notice:">>,1,notice,info),
+ match(Bin,<<"alert:">>,0,alert,info),
+
+ ok.
+
+logger_proxy(Config) ->
+ %% assume current node runs with default settings
+ DefOpts = logger_olp:get_opts(logger_proxy),
+ {ok,_,Node} = setup(Config,
+ [{logger,[{proxy,#{sync_mode_qlen=>0,
+ drop_mode_qlen=>2}}]}]),
+ Expected = DefOpts#{sync_mode_qlen:=0,
+ drop_mode_qlen:=2},
+ Expected = rpc:call(Node,logger_olp,get_opts,[logger_proxy]),
+ Expected = rpc:call(Node,logger,get_proxy_config,[]),
+
+ ok.
+
+sasl_compatible_false(Config) ->
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,_,Node} = setup(Config,
+ [{error_logger,{file,Log}},
+ {logger_sasl_compatible,false},
+ {logger_level,info}]), % to get progress
+ check_default_log(Node,Log,
+ file,% dest
+ 6,% progress in std logger
+ info),
+ ok.
+
+sasl_compatible_false_no_progress(Config) ->
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,_,Node} = setup(Config,
+ [{error_logger,{file,Log}},
+ {logger_sasl_compatible,false}]),
+ check_default_log(Node,Log,
+ file,% dest
+ 0),% progress in std logger
+ ok.
+
+sasl_compatible(Config) ->
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,_,Node} = setup(Config,
+ [{error_logger,{file,Log}},
+ {sasl_compatible,true}]),
+ check_default_log(Node,Log,
+ file,% dest
+ 0),% progress in std logger
+ ok.
+
+all_logger_level(Config) ->
+ [all_logger_level(Config,Level) || Level <- [none,
+ emergency,
+ alert,
+ critical,
+ error,
+ warning,
+ notice,
+ info,
+ debug,
+ all]],
+ ok.
+
+all_logger_level(Config,Level) ->
+ {ok,#{primary:=#{level:=Level}},Node} = setup(Config,[{logger_level,Level}]),
+ true = test_server:stop_node(Node),
+ ok.
+
+bad_error_logger(Config) ->
+ error = setup(Config,[{error_logger,baddest}]).
+
+bad_level(Config) ->
+ error = setup(Config,[{logger_level,badlevel}]).
+
+bad_sasl_compatibility(Config) ->
+ error = setup(Config,[{logger_sasl_compatible,badcomp}]).
+
+%%%-----------------------------------------------------------------
+%%% Internal
+file(Config,Func) ->
+ filename:join(proplists:get_value(priv_dir,Config),
+ lists:concat([Func,".log"])).
+
+check_default_log(Node,Log,Dest,NumProgress) ->
+ check_default_log(Node,Log,Dest,NumProgress,notice).
+check_default_log(Node,Log,Dest,NumProgress,Level) ->
+
+ {ok,Bin1,Bin2} = check_log(Node,Log,Dest),
+
+ match(Bin1,<<"PROGRESS REPORT">>,NumProgress,info,Level),
+ match(Bin1,<<"ALERT REPORT">>,1,alert,Level),
+ match(Bin1,<<"INFO REPORT">>,0,notice,Level),
+ match(Bin1,<<"DEBUG REPORT">>,0,debug,Level),
+
+ match(Bin2,<<"INFO REPORT">>,1,notice,Level),
+ match(Bin2,<<"DEBUG REPORT">>,0,debug,Level),
+ ok.
+
+check_single_log(Node,Log,Dest,NumProgress) ->
+ check_single_log(Node,Log,Dest,NumProgress,notice).
+check_single_log(Node,Log,Dest,NumProgress,Level) ->
+
+ {ok,Bin1,Bin2} = check_log(Node,Log,Dest),
+
+ match(Bin1,<<"info:">>,NumProgress,info,Level),
+ match(Bin1,<<"alert:">>,1,alert,Level),
+ match(Bin1,<<"debug:">>,0,debug,Level),
+
+ match(Bin2,<<"info:">>,NumProgress+1,info,Level),
+ match(Bin2,<<"debug:">>,0,debug,Level),
+
+ ok.
+
+check_log(Node,Log,Dest) ->
+
+ ok = log(Node,alert,["dummy1"]),
+ ok = log(Node,debug,["dummy1"]),
+
+ %% Check that there are progress reports (supervisor and
+ %% application_controller) and an error report (the call above) in
+ %% the log. There should not be any info reports yet.
+ {ok,Bin1} = sync_and_read(Node,Dest,Log),
+ ct:log("Log content:~n~s",[Bin1]),
+
+ %% Then stop sasl and see that the info report from
+ %% application_controller is there
+ ok = rpc:call(Node,application,stop,[sasl]),
+ {ok,Bin2} = sync_and_read(Node,Dest,Log),
+ ct:log("Log content:~n~s",[Bin2]),
+ {ok,Bin1,Bin2}.
+
+match(Bin,Pattern,0,_,_) ->
+ nomatch = re:run(Bin,Pattern,[{capture,none}]);
+match(Bin,Pattern,N,LogLevel,ConfLevel) ->
+ case logger:compare_levels(LogLevel,ConfLevel) of
+ lt -> match(Bin,Pattern,0,LogLevel,ConfLevel);
+ _ ->
+ {match,M} = re:run(Bin,Pattern,[{capture,all},global]),
+ N = length(M)
+ end.
+
+find(Id,Handlers) ->
+ case lists:search(fun(#{id:=Id0}) when Id0=:=Id-> true;
+ (_) -> false end,
+ Handlers) of
+ {value,Config} ->
+ Config;
+ false ->
+ false
+ end.
+
+exists(Id,Handlers) ->
+ case find(Id,Handlers) of
+ false ->
+ false;
+ _ ->
+ true
+ end.
diff --git a/lib/kernel/test/logger_filters_SUITE.erl b/lib/kernel/test/logger_filters_SUITE.erl
new file mode 100644
index 0000000000..11cce8fd20
--- /dev/null
+++ b/lib/kernel/test/logger_filters_SUITE.erl
@@ -0,0 +1,227 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(logger_filters_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("kernel/include/logger.hrl").
+
+-define(ndlog,
+ #{level=>info,msg=>{"Line: ~p",[?LINE]},meta=>#{}}).
+-define(dlog(Domain),
+ #{level=>info,msg=>{"Line: ~p",[?LINE]},meta=>#{domain=>Domain}}).
+-define(llog(Level),
+ #{level=>Level,msg=>{"Line: ~p",[?LINE]},meta=>#{}}).
+-define(plog,
+ #{level=>info,
+ msg=>{report,#{label=>{?MODULE,progress}}},
+ meta=>#{line=>?LINE}}).
+-define(rlog(Node),
+ #{level=>info,
+ msg=>{"Line: ~p",[?LINE]},
+ meta=>#{gl=>rpc:call(Node,erlang,whereis,[user])}}).
+
+-define(TRY(X), my_try(fun() -> X end)).
+
+suite() ->
+ [{timetrap,{seconds,30}}].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(_Group, Config) ->
+ Config.
+
+end_per_group(_Group, _Config) ->
+ ok.
+
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+end_per_testcase(Case, Config) ->
+ try apply(?MODULE,Case,[cleanup,Config])
+ catch error:undef -> ok
+ end,
+ ok.
+
+groups() ->
+ [].
+
+all() ->
+ [domain,
+ level,
+ progress,
+ remote_gl].
+
+domain(_Config) ->
+ L1 = logger_filters:domain(L1=?dlog([]),{log,super,[]}),
+ stop = logger_filters:domain(?dlog([]),{stop,super,[]}),
+ L2 = logger_filters:domain(L2=?dlog([]),{log,sub,[]}),
+ stop = logger_filters:domain(?dlog([]),{stop,sub,[]}),
+ L3 = logger_filters:domain(L3=?dlog([]),{log,equal,[]}),
+ stop = logger_filters:domain(?dlog([]),{stop,equal,[]}),
+ ignore = logger_filters:domain(?dlog([]),{log,not_equal,[]}),
+ ignore = logger_filters:domain(?dlog([]),{stop,not_equal,[]}),
+ ignore = logger_filters:domain(?dlog([]),{log,undefined,[]}),
+ ignore = logger_filters:domain(?dlog([]),{stop,undefined,[]}),
+
+ L4 = logger_filters:domain(L4=?dlog([a]),{log,super,[a,b]}),
+ stop = logger_filters:domain(?dlog([a]),{stop,super,[a,b]}),
+ ignore = logger_filters:domain(?dlog([a]),{log,sub,[a,b]}),
+ ignore = logger_filters:domain(?dlog([a]),{stop,sub,[a,b]}),
+ ignore = logger_filters:domain(?dlog([a]),{log,equal,[a,b]}),
+ ignore = logger_filters:domain(?dlog([a]),{stop,equal,[a,b]}),
+ L5 = logger_filters:domain(L5=?dlog([a]),{log,not_equal,[a,b]}),
+ stop = logger_filters:domain(?dlog([a]),{stop,not_equal,[a,b]}),
+ ignore = logger_filters:domain(?dlog([a]),{log,undefined,[a,b]}),
+ ignore = logger_filters:domain(?dlog([a]),{stop,undefined,[a,b]}),
+
+ ignore = logger_filters:domain(?dlog([a,b]),{log,super,[a]}),
+ ignore = logger_filters:domain(?dlog([a,b]),{stop,super,[a]}),
+ L6 = logger_filters:domain(L6=?dlog([a,b]),{log,sub,[a]}),
+ stop = logger_filters:domain(?dlog([a,b]),{stop,sub,[a]}),
+ ignore = logger_filters:domain(?dlog([a,b]),{log,equal,[a]}),
+ ignore = logger_filters:domain(?dlog([a,b]),{stop,equal,[a]}),
+ L7 = logger_filters:domain(L7=?dlog([a,b]),{log,not_equal,[a]}),
+ stop = logger_filters:domain(?dlog([a,b]),{stop,not_equal,[a]}),
+ ignore = logger_filters:domain(?dlog([a,b]),{log,undefined,[a]}),
+ ignore = logger_filters:domain(?dlog([a,b]),{stop,undefined,[a]}),
+
+ ignore = logger_filters:domain(?ndlog,{log,super,[a]}),
+ ignore = logger_filters:domain(?ndlog,{stop,super,[a]}),
+ ignore = logger_filters:domain(?ndlog,{log,sub,[a]}),
+ ignore = logger_filters:domain(?ndlog,{stop,sub,[a]}),
+ ignore = logger_filters:domain(?ndlog,{log,equal,[a]}),
+ ignore = logger_filters:domain(?ndlog,{stop,equal,[a]}),
+ L8 = logger_filters:domain(L8=?ndlog,{log,not_equal,[a]}),
+ stop = logger_filters:domain(?ndlog,{stop,not_equal,[a]}),
+ L9 = logger_filters:domain(L9=?ndlog,{log,undefined,[a]}),
+ stop = logger_filters:domain(?ndlog,{stop,undefined,[a]}),
+
+ L10 = logger_filters:domain(L10=?dlog([a,b,c,d]),{log,super,[a,b,c,d]}),
+ stop = logger_filters:domain(?dlog([a,b,c,d]),{stop,super,[a,b,c,d]}),
+ L11 = logger_filters:domain(L11=?dlog([a,b,c,d]),{log,sub,[a,b,c,d]}),
+ stop = logger_filters:domain(?dlog([a,b,c,d]),{stop,sub,[a,b,c,d]}),
+ L12 = logger_filters:domain(L12=?dlog([a,b,c,d]),{log,equal,[a,b,c,d]}),
+ stop = logger_filters:domain(?dlog([a,b,c,d]),{stop,equal,[a,b,c,d]}),
+ ignore = logger_filters:domain(?dlog([a,b,c,d]),{log,not_equal,[a,b,c,d]}),
+ ignore = logger_filters:domain(?dlog([a,b,c,d]),{stop,not_equal,[a,b,c,d]}),
+ ignore = logger_filters:domain(?dlog([a,b,c,d]),{log,undefined,[a,b,c,d]}),
+ ignore = logger_filters:domain(?dlog([a,b,c,d]),{stop,undefined,[a,b,c,d]}),
+
+ %% A domain field in meta which is not a list is allowed by the
+ %% filter, but since MatchDomain is always a list of atoms, only
+ %% Action=not_equal can ever match.
+ ignore = logger_filters:domain(?dlog(dummy),{log,super,[a,b,c,d]}),
+ ignore = logger_filters:domain(?dlog(dummy),{stop,super,[a,b,c,d]}),
+ ignore = logger_filters:domain(?dlog(dummy),{log,sub,[a,b,c,d]}),
+ ignore = logger_filters:domain(?dlog(dummy),{stop,sub,[a,b,c,d]}),
+ ignore = logger_filters:domain(?dlog(dummy),{log,equal,[a,b,c,d]}),
+ ignore = logger_filters:domain(?dlog(dummy),{stop,equal,[a,b,c,d]}),
+ L13 = logger_filters:domain(L13=?dlog(dummy),{log,not_equal,[a,b,c,d]}),
+ stop = logger_filters:domain(?dlog(dummy),{stop,not_equal,[a,b,c,d]}),
+ ignore = logger_filters:domain(?dlog(dummy),{log,undefined,[a,b,c,d]}),
+ ignore = logger_filters:domain(?dlog(dummy),{stop,undefined,[a,b,c,d]}),
+
+ {error,badarg} = ?TRY(logger_filters:domain(?ndlog,bad)),
+ {error,badarg} = ?TRY(logger_filters:domain(?ndlog,{bad,super,[]})),
+ {error,badarg} = ?TRY(logger_filters:domain(?ndlog,{log,bad,[]})),
+ {error,badarg} = ?TRY(logger_filters:domain(?ndlog,{log,super,bad})),
+
+ ok.
+
+level(_Config) ->
+ ignore = logger_filters:level(?llog(info),{log,lt,info}),
+ ignore = logger_filters:level(?llog(info),{stop,lt,info}),
+ ignore = logger_filters:level(?llog(info),{log,gt,info}),
+ ignore = logger_filters:level(?llog(info),{stop,gt,info}),
+ L1 = logger_filters:level(L1=?llog(info),{log,lteq,info}),
+ stop = logger_filters:level(?llog(info),{stop,lteq,info}),
+ L2 = logger_filters:level(L2=?llog(info),{log,gteq,info}),
+ stop = logger_filters:level(?llog(info),{stop,gteq,info}),
+ L3 = logger_filters:level(L3=?llog(info),{log,eq,info}),
+ stop = logger_filters:level(?llog(info),{stop,eq,info}),
+ ignore = logger_filters:level(?llog(info),{log,neq,info}),
+ ignore = logger_filters:level(?llog(info),{stop,neq,info}),
+
+ ignore = logger_filters:level(?llog(error),{log,lt,info}),
+ ignore = logger_filters:level(?llog(error),{stop,lt,info}),
+ L4 = logger_filters:level(L4=?llog(error),{log,gt,info}),
+ stop = logger_filters:level(?llog(error),{stop,gt,info}),
+ ignore = logger_filters:level(?llog(error),{log,lteq,info}),
+ ignore = logger_filters:level(?llog(error),{stop,lteq,info}),
+ L5 = logger_filters:level(L5=?llog(error),{log,gteq,info}),
+ stop = logger_filters:level(?llog(error),{stop,gteq,info}),
+ ignore = logger_filters:level(?llog(error),{log,eq,info}),
+ ignore = logger_filters:level(?llog(error),{stop,eq,info}),
+ L6 = logger_filters:level(L6=?llog(error),{log,neq,info}),
+ stop = logger_filters:level(?llog(error),{stop,neq,info}),
+
+ L7 = logger_filters:level(L7=?llog(info),{log,lt,error}),
+ stop = logger_filters:level(?llog(info),{stop,lt,error}),
+ ignore = logger_filters:level(?llog(info),{log,gt,error}),
+ ignore = logger_filters:level(?llog(info),{stop,gt,error}),
+ L8 = logger_filters:level(L8=?llog(info),{log,lteq,error}),
+ stop = logger_filters:level(?llog(info),{stop,lteq,error}),
+ ignore = logger_filters:level(?llog(info),{log,gteq,error}),
+ ignore = logger_filters:level(?llog(info),{stop,gteq,error}),
+ ignore = logger_filters:level(?llog(info),{log,eq,error}),
+ ignore = logger_filters:level(?llog(info),{stop,eq,error}),
+ L9 = logger_filters:level(L9=?llog(info),{log,neq,error}),
+ stop = logger_filters:level(?llog(info),{stop,neq,error}),
+
+ {error,badarg} = ?TRY(logger_filters:level(?llog(info),bad)),
+ {error,badarg} = ?TRY(logger_filters:level(?llog(info),{bad,eq,info})),
+ {error,badarg} = ?TRY(logger_filters:level(?llog(info),{log,bad,info})),
+ {error,badarg} = ?TRY(logger_filters:level(?llog(info),{log,eq,bad})),
+
+ ok.
+
+progress(_Config) ->
+ L1 = logger_filters:progress(L1=?plog,log),
+ stop = logger_filters:progress(?plog,stop),
+ ignore = logger_filters:progress(?ndlog,log),
+ ignore = logger_filters:progress(?ndlog,stop),
+
+ {error,badarg} = ?TRY(logger_filters:progress(?plog,bad)),
+
+ ok.
+
+remote_gl(_Config) ->
+ {ok,Node} = test_server:start_node(?FUNCTION_NAME,slave,[]),
+ L1 = logger_filters:remote_gl(L1=?rlog(Node),log),
+ stop = logger_filters:remote_gl(?rlog(Node),stop),
+ ignore = logger_filters:remote_gl(?ndlog,log),
+ ignore = logger_filters:remote_gl(?ndlog,stop),
+
+ {error,badarg} = ?TRY(logger_filters:remote_gl(?rlog(Node),bad)),
+ ok.
+
+remote_gl(cleanup,_Config) ->
+ [test_server:stop_node(N) || N<-nodes()].
+
+%%%-----------------------------------------------------------------
+%%% Called by macro ?TRY(X)
+my_try(Fun) ->
+ try Fun() catch C:R -> {C,R} end.
diff --git a/lib/kernel/test/logger_formatter_SUITE.erl b/lib/kernel/test/logger_formatter_SUITE.erl
new file mode 100644
index 0000000000..83e3e6c40a
--- /dev/null
+++ b/lib/kernel/test/logger_formatter_SUITE.erl
@@ -0,0 +1,886 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(logger_formatter_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("kernel/include/logger.hrl").
+
+-define(TRY(X), my_try(fun() -> X end)).
+
+suite() ->
+ [{timetrap,{seconds,30}}].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(_Group, Config) ->
+ Config.
+
+end_per_group(_Group, _Config) ->
+ ok.
+
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+end_per_testcase(Case, Config) ->
+ try apply(?MODULE,Case,[cleanup,Config])
+ catch error:undef -> ok
+ end,
+ ok.
+
+groups() ->
+ [].
+
+all() ->
+ [default,
+ legacy_header,
+ error_logger_notice_header,
+ single_line,
+ template,
+ format_msg,
+ report_cb,
+ max_size,
+ depth,
+ chars_limit,
+ format_mfa,
+ format_time,
+ level_or_msg_in_meta,
+ faulty_log,
+ faulty_config,
+ faulty_msg,
+ check_config,
+ update_config].
+
+default(_Config) ->
+ String1 = format(info,{"~p",[term]},#{},#{}),
+ ct:log(String1),
+ [_DateTime,"info:","term\n"] = string:lexemes(String1," "),
+
+ Time = timestamp(),
+ ExpectedTimestamp = default_time_format(Time),
+ String2 = format(info,{"~p",[term]},#{time=>Time},#{}),
+ ct:log(String2),
+ " info: term\n" = string:prefix(String2,ExpectedTimestamp),
+ ok.
+
+legacy_header(_Config) ->
+ Time = timestamp(),
+ String1 = format(info,{"~p",[term]},#{time=>Time},#{legacy_header=>true,
+ single_line=>false}),
+ ct:log(String1),
+ "=INFO REPORT==== "++Rest = String1,
+ [Timestamp,"\nterm\n"] = string:lexemes(Rest," ="),
+ [D,M,Y,H,Min,S,Micro] = string:lexemes(Timestamp,"-:."),
+ integer(D,31),
+ integer(Y,2018,infinity),
+ integer(H,23),
+ integer(Min,59),
+ integer(S,59),
+ integer(Micro,999999),
+ true = lists:member(M,["Jan","Feb","Mar","Apr","May","Jun",
+ "Jul","Aug","Sep","Oct","Nov","Dec"]),
+
+ String2 = format(info,{"~p",[term]},#{time=>Time},#{legacy_header=>false,
+ single_line=>false}),
+ ct:log(String2),
+ ExpectedTimestamp = default_time_format(Time),
+ " info:\nterm\n" = string:prefix(String2,ExpectedTimestamp),
+
+ String3 = format(info,{"~p",[term]},#{time=>Time},#{legacy_header=>bad,
+ single_line=>false}),
+ ct:log(String3),
+ String3 = String2,
+
+ String4 = format(info,{"~p",[term]},#{time=>Time},
+ #{legacy_header=>true,
+ single_line=>true}), % <---ignored
+ ct:log(String4),
+ String4 = String1,
+
+ String5 = format(info,{"~p",[term]},#{}, % <--- no time
+ #{legacy_header=>true,
+ single_line=>false}),
+ ct:log(String5),
+ "=INFO REPORT==== "++_ = String5,
+ ok.
+
+error_logger_notice_header(_Config) ->
+ Meta1 = #{error_logger=>#{tag => info_report,type => std_info}},
+ String1 = format(notice,{"~p",[term]},Meta1,
+ #{legacy_header=>true,
+ error_logger_notice_header=>notice}),
+ ct:log(String1),
+ "=NOTICE REPORT==== "++_ = String1,
+
+ String2 = format(notice,{"~p",[term]},Meta1,
+ #{legacy_header=>true,
+ error_logger_notice_header=>info}),
+ ct:log(String2),
+ "=INFO REPORT==== "++_ = String2,
+
+ String3 = format(notice,{"~p",[term]},#{},
+ #{legacy_header=>true,
+ error_logger_notice_header=>notice}),
+ ct:log(String3),
+ "=NOTICE REPORT==== "++_ = String3,
+
+ String4 = format(notice,{"~p",[term]},#{},
+ #{legacy_header=>true,
+ error_logger_notice_header=>info}),
+ ct:log(String4),
+ "=NOTICE REPORT==== "++_ = String4,
+
+ ok.
+
+single_line(_Config) ->
+ Time = timestamp(),
+ ExpectedTimestamp = default_time_format(Time),
+ String1 = format(info,{"~p",[term]},#{time=>Time},#{single_line=>true}),
+ ct:log(String1),
+ " info: term\n" = string:prefix(String1,ExpectedTimestamp),
+
+ String2 = format(info,{"~p",[term]},#{time=>Time},#{single_line=>false}),
+ ct:log(String2),
+ " info:\nterm\n" = string:prefix(String2,ExpectedTimestamp),
+
+ String2 = format(info,{"~p",[term]},#{time=>Time},#{single_line=>bad}),
+
+
+ %% Test that no extra commas/spaces are added when removing
+ %% newlines, especially not after "=>" in a map association (as
+ %% was the case in OTP-21.0, when the only single_line adjustment
+ %% was done by regexp replacement of "\n" by ", ").
+ Prefix =
+ "Some characters to fill the line ------------------------------------- ",
+ String3 = format(info,{"~s~p~n~s~p~n",[Prefix,
+ lists:seq(1,10),
+ Prefix,
+ #{a=>map,with=>a,few=>accociations}]},
+ #{time=>Time},
+ #{single_line=>true}),
+ ct:log(String3),
+ match = re:run(String3,"\\[1,2,3,4,5,6,7,8,9,10\\]",[{capture,none}]),
+ match = re:run(String3,
+ "#{a => map,few => accociations,with => a}",
+ [{capture,none}]),
+
+ %% This part is added to make sure that the previous test made
+ %% sense, i.e. that there would actually be newlines inside the
+ %% list and map.
+ String4 = format(info,{"~s~p~n~s~p~n",[Prefix,
+ lists:seq(1,10),
+ Prefix,
+ #{a=>map,with=>a,few=>accociations}]},
+ #{time=>Time},
+ #{single_line=>false}),
+ ct:log(String4),
+ match = re:run(String4,"\\[1,2,3,\n",[global,{capture,none}]),
+ {match,Match4} = re:run(String4,"=>\n",[global,{capture,all}]),
+ 3 = length(Match4),
+
+ %% Test that big metadata fields do not get line breaks
+ String5 = format(info,"",
+ #{mymeta=>lists:seq(1,100)},
+ #{single_line=>true,template=>[mymeta,"\n"]}),
+ ct:log(String5),
+ [_] = string:lexemes(String5,"\n"),
+
+ %% Ensure that the previous test made sense, i.e. that the
+ %% metadata field does produce multiple lines if
+ %% single_line==false.
+ String6 = format(info,"",
+ #{mymeta=>lists:seq(1,100)},
+ #{single_line=>false,template=>[mymeta,"\n"]}),
+ ct:log(String6),
+ [_,_|_] = string:lexemes(String6,"\n"),
+
+ ok.
+
+template(_Config) ->
+ Time = timestamp(),
+
+ Template1 = [msg],
+ String1 = format(info,{"~p",[term]},#{time=>Time},#{template=>Template1}),
+ ct:log(String1),
+ "term" = String1,
+
+ Template2 = [msg,unknown],
+ String2 = format(info,{"~p",[term]},#{time=>Time},#{template=>Template2}),
+ ct:log(String2),
+ "term" = String2,
+
+ Template3 = ["string"],
+ String3 = format(info,{"~p",[term]},#{time=>Time},#{template=>Template3}),
+ ct:log(String3),
+ "string" = String3,
+
+ Template4 = ["string\nnewline"],
+ String4 = format(info,{"~p",[term]},#{time=>Time},#{template=>Template4,
+ single_line=>true}),
+ ct:log(String4),
+ "string\nnewline" = String4,
+
+ Template5 = [],
+ String5 = format(info,{"~p",[term]},#{time=>Time},#{template=>Template5}),
+ ct:log(String5),
+ "" = String5,
+
+ Ref6 = erlang:make_ref(),
+ Meta6 = #{atom=>some_atom,
+ integer=>632,
+ list=>[list,"string",4321,#{},{tuple}],
+ mfa=>{mod,func,0},
+ pid=>self(),
+ ref=>Ref6,
+ string=>"some string",
+ time=>Time,
+ tuple=>{1,atom,"list"},
+ nested=>#{subkey=>subvalue}},
+ Template6 = lists:join(";",lists:sort(maps:keys(maps:remove(nested,Meta6))) ++
+ [[nested,subkey]]),
+ String6 = format(info,{"~p",[term]},Meta6,#{template=>Template6,
+ single_line=>true}),
+ ct:log(String6),
+ SelfStr = pid_to_list(self()),
+ RefStr6 = ref_to_list(Ref6),
+ ListStr = "[list,\"string\",4321,#{},{tuple}]",
+ ExpectedTime6 = default_time_format(Time),
+ ["some_atom",
+ "632",
+ ListStr,
+ "mod:func/0",
+ SelfStr,
+ RefStr6,
+ "some string",
+ ExpectedTime6,
+ "{1,atom,\"list\"}",
+ "subvalue"] = string:lexemes(String6,";"),
+
+ Meta7 = #{time=>Time,
+ nested=>#{key1=>#{subkey1=>value1},
+ key2=>value2}},
+ Template7 = lists:join(";",[nested,
+ [nested,key1],
+ [nested,key1,subkey1],
+ [nested,key2],
+ [nested,key2,subkey2],
+ [nested,key3],
+ [nested,key3,subkey3]]),
+ String7 = format(info,{"~p",[term]},Meta7,#{template=>Template7,
+ single_line=>true}),
+ ct:log(String7),
+ [MultipleKeysStr7,
+ "#{subkey1 => value1}",
+ "value1",
+ "value2",
+ "",
+ "",
+ ""] = string:split(String7,";",all),
+ %% Order of keys is not fixed
+ case MultipleKeysStr7 of
+ "#{key2 => value2,key1 => #{subkey1 => value1}}" -> ok;
+ "#{key1 => #{subkey1 => value1},key2 => value2}" -> ok;
+ _ -> ct:fail({full_nested_map_unexpected,MultipleKeysStr7})
+ end,
+
+ Meta8 = #{time=>Time,
+ nested=>#{key1=>#{subkey1=>value1},
+ key2=>value2}},
+ Template8 =
+ lists:join(
+ ";",
+ [{nested,["exist:",nested],["noexist"]},
+ {[nested,key1],["exist:",[nested,key1]],["noexist"]},
+ {[nested,key1,subkey1],["exist:",[nested,key1,subkey1]],["noexist"]},
+ {[nested,key2],["exist:",[nested,key2]],["noexist"]},
+ {[nested,key2,subkey2],["exist:",[nested,key2,subkey2]],["noexist"]},
+ {[nested,key3],["exist:",[nested,key3]],["noexist"]},
+ {[nested,key3,subkey3],["exist:",[nested,key3,subkey3]],["noexist"]}]),
+ String8 = format(info,{"~p",[term]},Meta8,#{template=>Template8,
+ single_line=>true}),
+ ct:log(String8),
+ [MultipleKeysStr8,
+ "exist:#{subkey1 => value1}",
+ "exist:value1",
+ "exist:value2",
+ "noexist",
+ "noexist",
+ "noexist"] = string:split(String8,";",all),
+ %% Order of keys is not fixed
+ case MultipleKeysStr8 of
+ "exist:#{key2 => value2,key1 => #{subkey1 => value1}}" -> ok;
+ "exist:#{key1 => #{subkey1 => value1},key2 => value2}" -> ok;
+ _ -> ct:fail({full_nested_map_unexpected,MultipleKeysStr8})
+ end,
+
+ ok.
+
+format_msg(_Config) ->
+ Template = [msg],
+
+ String1 = format(info,{"~p",[term]},#{},#{template=>Template}),
+ ct:log(String1),
+ "term" = String1,
+
+ String2 = format(info,{"list",[term]},#{},#{template=>Template}),
+ ct:log(String2),
+ "FORMAT ERROR: \"list\" - [term]" = String2,
+
+ String3 = format(info,{report,term},#{},#{template=>Template}),
+ ct:log(String3),
+ "term" = String3,
+
+ String4 = format(info,{report,term},
+ #{report_cb=>fun(_)-> {"formatted",[]} end},
+ #{template=>Template}),
+ ct:log(String4),
+ "formatted" = String4,
+
+ String5 = format(info,{report,term},
+ #{report_cb=>fun(_)-> faulty_return end},
+ #{template=>Template}),
+ ct:log(String5),
+ "REPORT_CB/1 ERROR: term; Returned: faulty_return" = String5,
+
+ String6 = format(info,{report,term},
+ #{report_cb=>fun(_)-> erlang:error(fun_crashed) end},
+ #{template=>Template}),
+ ct:log(String6),
+ "REPORT_CB/1 CRASH: term; Reason: {error,fun_crashed,"++_ = String6,
+
+ String7 = format(info,{report,term},
+ #{report_cb=>fun(_,_)-> ['not',a,string] end},
+ #{template=>Template}),
+ ct:log(String7),
+ "REPORT_CB/2 ERROR: term; Returned: ['not',a,string]" = String7,
+
+ String8 = format(info,{report,term},
+ #{report_cb=>fun(_,_)-> faulty_return end},
+ #{template=>Template}),
+ ct:log(String8),
+ "REPORT_CB/2 ERROR: term; Returned: faulty_return" = String8,
+
+ String9 = format(info,{report,term},
+ #{report_cb=>fun(_,_)-> erlang:error(fun_crashed) end},
+ #{template=>Template}),
+ ct:log(String9),
+ "REPORT_CB/2 CRASH: term; Reason: {error,fun_crashed,"++_ = String9,
+
+ %% strings are not formatted
+ String10 = format(info,{string,"string"},
+ #{report_cb=>fun(_)-> {"formatted",[]} end},
+ #{template=>Template}),
+ ct:log(String10),
+ "string" = String10,
+
+ String11 = format(info,{string,['not',printable,list]},
+ #{report_cb=>fun(_)-> {"formatted",[]} end},
+ #{template=>Template}),
+ ct:log("~ts",[String11]), % avoiding ct_log crash
+ "FORMAT ERROR: \"~ts\" - [['not',printable,list]]" = String11,
+
+ String12 = format(info,{string,"string"},#{},#{template=>Template}),
+ ct:log(String12),
+ "string" = String12,
+
+ ok.
+
+report_cb(_Config) ->
+ Template = [msg],
+ MetaFun = fun(_) -> {"meta_rcb",[]} end,
+ ConfigFun = fun(_) -> {"config_rcb",[]} end,
+ "term" = format(info,{report,term},#{},#{template=>Template}),
+ "meta_rcb" =
+ format(info,{report,term},#{report_cb=>MetaFun},#{template=>Template}),
+ "config_rcb" =
+ format(info,{report,term},#{},#{template=>Template,
+ report_cb=>ConfigFun}),
+ "config_rcb" =
+ format(info,{report,term},#{report_cb=>MetaFun},#{template=>Template,
+ report_cb=>ConfigFun}),
+ ok.
+
+max_size(_Config) ->
+ Cfg = #{template=>[msg],
+ single_line=>false},
+ "12345678901234567890" =
+ format(info,{"12345678901234567890",[]},#{},Cfg),
+ %% application:set_env(kernel,logger_max_size,11),
+ %% "12345678901234567890" = % min value is 50, so this is not limited
+ %% format(info,{"12345678901234567890",[]},#{},Cfg),
+ %% "12345678901234567890123456789012345678901234567..." = % 50
+ %% format(info,
+ %% {"123456789012345678901234567890123456789012345678901234567890",
+ %% []},
+ %% #{},
+ %% Cfg),
+ %% application:set_env(kernel,logger_max_size,53),
+ %% "12345678901234567890123456789012345678901234567890..." = %53
+ %% format(info,
+ %% {"123456789012345678901234567890123456789012345678901234567890",
+ %% []},
+ %% #{},
+ %% Cfg),
+ "123456789012..." =
+ format(info,{"12345678901234567890",[]},#{},Cfg#{max_size=>15}),
+ "12345678901234567890" =
+ format(info,{"12345678901234567890",[]},#{},Cfg#{max_size=>unlimited}),
+ %% Check that one newline at the end of the line is kept (if it exists)
+ "12345678901...\n" =
+ format(info,{"12345678901234567890\n",[]},#{},Cfg#{max_size=>15}),
+ "12345678901...\n" =
+ format(info,{"12345678901234567890",[]},#{},Cfg#{template=>[msg,"\n"],
+ max_size=>15}),
+ ok.
+max_size(cleanup,_Config) ->
+ application:unset_env(kernel,logger_max_size),
+ ok.
+
+depth(_Config) ->
+ Template = [msg],
+ "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0]" =
+ format(info,
+ {"~p",[[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0]]},
+ #{},
+ #{template=>Template}),
+ application:set_env(kernel,error_logger_format_depth,11),
+ "[1,2,3,4,5,6,7,8,9,0|...]" =
+ format(info,
+ {"~p",[[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0]]},
+ #{},
+ #{template=>Template}),
+ "[1,2,3,4,5,6,7,8,9,0,1,2|...]" =
+ format(info,
+ {"~p",[[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0]]},
+ #{},
+ #{template=>Template,
+ depth=>13}),
+ "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0]" =
+ format(info,
+ {"~p",[[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0]]},
+ #{},
+ #{template=>Template,
+ depth=>unlimited}),
+ ok.
+depth(cleanup,_Config) ->
+ application:unset_env(kernel,error_logger_format_depth),
+ ok.
+
+chars_limit(_Config) ->
+ FA = {"LoL: ~p~nL: ~p~nMap: ~p~n",
+ [lists:duplicate(10,lists:seq(1,100)),
+ lists:seq(1,100),
+ maps:from_list(lists:zip(lists:seq(1,100),
+ lists:duplicate(100,value)))]},
+ Meta = #{time=>timestamp()},
+ Template = [time," - ", msg, "\n"],
+ FC = #{template=>Template,
+ depth=>unlimited,
+ max_size=>unlimited,
+ chars_limit=>unlimited,
+ single_line=>true},
+ CL1 = 80,
+ String1 = format(info,FA,Meta,FC#{chars_limit=>CL1}),
+ L1 = string:length(String1),
+ ct:log("String1: ~p~nLength1: ~p~n",[lists:flatten(String1),L1]),
+ true = L1 > CL1,
+ true = L1 < CL1 + 15,
+
+ String2 = format(info,FA,Meta,FC#{chars_limit=>CL1,depth=>10}),
+ L2 = string:length(String2),
+ ct:log("String2: ~p~nLength2: ~p~n",[lists:flatten(String2),L2]),
+ String2 = String1,
+
+ CL3 = 200,
+ String3 = format(info,FA,Meta,FC#{chars_limit=>CL3}),
+ L3 = string:length(String3),
+ ct:log("String3: ~p~nLength3: ~p~n",[lists:flatten(String3),L3]),
+ true = L3 > CL3,
+ true = L3 < CL3 + 15,
+
+ String4 = format(info,FA,Meta,FC#{chars_limit=>CL3,depth=>10}),
+ L4 = string:length(String4),
+ ct:log("String4: ~p~nLength4: ~p~n",[lists:flatten(String4),L4]),
+ true = L4 > CL3,
+ true = L4 < CL3 + 15,
+
+ %% Test that max_size truncates the string which is limited by
+ %% depth and chars_limit
+ MS5 = 150,
+ String5 = format(info,FA,Meta,FC#{chars_limit=>CL3,depth=>10,max_size=>MS5}),
+ L5 = string:length(String5),
+ ct:log("String5: ~p~nLength5: ~p~n",[String5,L5]),
+ L5 = MS5,
+ true = lists:prefix(lists:sublist(String5,L5-4),String4),
+
+ %% Test that chars_limit limits string also
+ Str = "123456789012345678901234567890123456789012345678901234567890123456789",
+ CL6 = 80,
+ String6 = format(info,{string,Str},Meta,FC#{chars_limit=>CL6}),
+ L6 = string:length(String6),
+ ct:log("String6: ~p~nLength6: ~p~n",[String6,L6]),
+ L6 = CL6,
+
+ ok.
+
+format_mfa(_Config) ->
+ Template = [mfa],
+
+ Meta1 = #{mfa=>{mod,func,0}},
+ String1 = format(info,{"~p",[term]},Meta1,#{template=>Template}),
+ ct:log(String1),
+ "mod:func/0" = String1,
+
+ Meta2 = #{mfa=>{mod,func,[]}},
+ String2 = format(info,{"~p",[term]},Meta2,#{template=>Template}),
+ ct:log(String2),
+ "mod:func/0" = String2,
+
+ Meta3 = #{mfa=>"mod:func/0"},
+ String3 = format(info,{"~p",[term]},Meta3,#{template=>Template}),
+ ct:log(String3),
+ "mod:func/0" = String3,
+
+ Meta4 = #{mfa=>othermfa},
+ String4 = format(info,{"~p",[term]},Meta4,#{template=>Template}),
+ ct:log(String4),
+ "othermfa" = String4,
+
+ ok.
+
+format_time(_Config) ->
+ Time = timestamp(),
+ Meta = #{time=>Time},
+ FC = #{template=>[time]},
+ Msg = {string,""},
+ ExpectedLocal = default_time_format(Time,false),
+ ExpectedUtc = default_time_format(Time,true),
+
+ %% default - local time
+ ExpectedLocal = format(info,Msg,Meta,FC),
+
+ %% time_offset config parameter to formatter
+ ExpectedLocal = format(info,Msg,Meta,FC#{time_offset=>""}),
+ ExpectedUtc = format(info,Msg,Meta,FC#{time_offset=>"Z"}),
+
+ %% stdlib utc_log works when time_offset parameter is not set
+ application:set_env(stdlib,utc_log,true),
+ ExpectedUtc = format(info,Msg,Meta,FC),
+
+ %% sasl utc_log overwrites stdlib utc_log
+ application:set_env(sasl,utc_log,false),
+ ExpectedLocal = format(info,Msg,Meta,FC),
+
+ %% sasl utc_log overwrites stdlib utc_log
+ application:set_env(sasl,utc_log,true),
+ application:set_env(stdlib,utc_log,false),
+ ExpectedUtc = format(info,Msg,Meta,FC),
+
+ %% time_offset config parameter to formatter
+ %% overwrites sasl and stdlib utc_log
+ application:set_env(sasl,utc_log,false),
+ ExpectedUtc = format(info,Msg,Meta,FC#{time_offset=>"Z"}),
+
+ %% time_offset config parameter to formatter
+ %% overwrites sasl and stdlib utc_log
+ application:set_env(sasl,utc_log,true),
+ application:set_env(stdlib,utc_log,true),
+ ExpectedLocal = format(info,Msg,Meta,FC#{time_offset=>""}),
+
+ %% time_designator config parameter to formatter
+ ExpectedLocalS = default_time_format(Time,false,$\s),
+ ExpectedUtcS = default_time_format(Time,true,$\s),
+
+ ExpectedLocalS = format(info,Msg,Meta,FC#{time_offset=>"",
+ time_designator=>$\s}),
+ ExpectedUtcS = format(info,Msg,Meta,FC#{time_offset=>"Z",
+ time_designator=>$\s}),
+
+ ok.
+
+format_time(cleanup,_Config) ->
+ application:unset_env(sasl,utc_log),
+ application:unset_env(stdlib,utc_log),
+ ok.
+
+level_or_msg_in_meta(_Config) ->
+ %% The template contains atoms to pick out values from meta,
+ %% or level/msg to add these from the log event. What if you have
+ %% a key named 'level' or 'msg' in meta and want to display
+ %% its value?
+ %% For now we simply ignore Meta on this and display the
+ %% actual level and msg from the log event.
+
+ Meta = #{level=>mylevel,
+ msg=>"metamsg"},
+ Template = [level,";",msg],
+ String = format(info,{"~p",[term]},Meta,#{template=>Template}),
+ ct:log(String),
+ "info;term" = String, % so mylevel and "metamsg" are ignored
+
+ ok.
+
+faulty_log(_Config) ->
+ %% Unexpected log (should be type logger:log_event()) - print error
+ {error,
+ function_clause,
+ {logger_formatter,format,[_,_],_}} =
+ ?TRY(logger_formatter:format(unexp_log,#{})),
+ ok.
+
+faulty_config(_Config) ->
+ {error,
+ function_clause,
+ {logger_formatter,format,[_,_],_}} =
+ ?TRY(logger_formatter:format(#{level=>info,
+ msg=>{"~p",[term]},
+ meta=>#{time=>timestamp()}},
+ unexp_config)),
+ ok.
+
+faulty_msg(_Config) ->
+ {error,
+ function_clause,
+ {logger_formatter,_,_,_}} =
+ ?TRY(logger_formatter:format(#{level=>info,
+ msg=>term,
+ meta=>#{time=>timestamp()}},
+ #{})),
+ ok.
+
+-define(cfgerr(X), {error,{invalid_formatter_config,logger_formatter,X}}).
+check_config(_Config) ->
+ ok = logger_formatter:check_config(#{}),
+ ?cfgerr(bad) = logger_formatter:check_config(bad),
+
+ C1 = #{chars_limit => 1,
+ depth => 1,
+ legacy_header => true,
+ error_logger_notice_header => info,
+ max_size => 1,
+ report_cb => fun(R) -> {"~p",[R]} end,
+ single_line => false,
+ template => [],
+ time_designator => $T,
+ time_offset => 0},
+ ok = logger_formatter:check_config(C1),
+
+ ok = logger_formatter:check_config(#{chars_limit => unlimited}),
+ ?cfgerr({chars_limit,bad}) =
+ logger_formatter:check_config(#{chars_limit => bad}),
+
+ ok = logger_formatter:check_config(#{depth => unlimited}),
+ ?cfgerr({depth,bad}) =
+ logger_formatter:check_config(#{depth => bad}),
+
+ ok = logger_formatter:check_config(#{legacy_header => false}),
+ ?cfgerr({legacy_header,bad}) =
+ logger_formatter:check_config(#{legacy_header => bad}),
+
+ ok = logger_formatter:check_config(#{error_logger_notice_header => notice}),
+ ?cfgerr({error_logger_notice_header,bad}) =
+ logger_formatter:check_config(#{error_logger_notice_header => bad}),
+
+ ok = logger_formatter:check_config(#{max_size => unlimited}),
+ ?cfgerr({max_size,bad}) =
+ logger_formatter:check_config(#{max_size => bad}),
+
+ ok =
+ logger_formatter:check_config(#{report_cb => fun(_,_) -> "" end}),
+ ?cfgerr({report_cb,F}) =
+ logger_formatter:check_config(#{report_cb => F=fun(_,_,_) -> {"",[]} end}),
+ ?cfgerr({report_cb,bad}) =
+ logger_formatter:check_config(#{report_cb => bad}),
+
+ ok = logger_formatter:check_config(#{single_line => true}),
+ ?cfgerr({single_line,bad}) =
+ logger_formatter:check_config(#{single_line => bad}),
+
+ Ts = [[key],
+ [[key1,key2]],
+ [{key,[key],[]}],
+ [{[key1,key2],[[key1,key2]],["noexist"]}],
+ ["string"]],
+ [begin
+ ct:log("check template: ~p",[T]),
+ ok = logger_formatter:check_config(#{template => T})
+ end
+ || T <- Ts],
+
+ ETs = [bad,
+ [{key,bad}],
+ [{key,[key],bad}],
+ [{key,[key],"bad"}],
+ "bad",
+ [[key,$a,$b,$c]],
+ [[$a,$b,$c,key]]],
+ [begin
+ ct:log("check template: ~p",[T]),
+ {error,{invalid_formatter_template,logger_formatter,T}} =
+ logger_formatter:check_config(#{template => T})
+ end
+ || T <- ETs],
+
+ ?cfgerr({time_designator,bad}) =
+ logger_formatter:check_config(#{time_designator => bad}),
+ ?cfgerr({time_designator,"b"}) =
+ logger_formatter:check_config(#{time_designator => "b"}),
+
+ ok = logger_formatter:check_config(#{time_offset => -1}),
+ ok = logger_formatter:check_config(#{time_offset => "+02:00"}),
+ ok = logger_formatter:check_config(#{time_offset => "-23:59"}),
+ ok = logger_formatter:check_config(#{time_offset => "+24:00"}),
+ ok = logger_formatter:check_config(#{time_offset => "-25:00"}),
+ ?cfgerr({time_offset,bad}) =
+ logger_formatter:check_config(#{time_offset => bad}),
+ ?cfgerr({time_offset,"02:00"}) =
+ logger_formatter:check_config(#{time_offset => "02:00"}),
+ ?cfgerr({time_offset,"+02"}) =
+ logger_formatter:check_config(#{time_offset => "+02"}),
+
+ ok.
+
+%% Test that formatter config can be changed, and that the default
+%% template is updated accordingly
+update_config(_Config) ->
+ {error,{not_found,?MODULE}} = logger:update_formatter_config(?MODULE,#{}),
+
+ logger:add_handler_filter(default,silence,{fun(_,_) -> stop end,ok}),
+ ok = logger:add_handler(?MODULE,?MODULE,#{}),
+ D = lists:seq(1,1000),
+ logger:notice("~p~n",[D]),
+ {Lines1,C1} = check_log(),
+ [ct:log(L) || L <- Lines1],
+ ct:log("~p",[C1]),
+ [Line1] = Lines1,
+ [_Time,"notice: "++D1] = string:split(Line1," "),
+ true = length(D1)>3000,
+ true = #{}==C1,
+
+ ok = logger:update_formatter_config(?MODULE,single_line,false),
+ logger:notice("~p~n",[D]),
+ {Lines2,C2} = check_log(),
+ [ct:log(L) || L <- Lines2],
+ ct:log("~p",[C2]),
+ true = length(Lines2)>50,
+ true = #{single_line=>false}==C2,
+
+ ok = logger:update_formatter_config(?MODULE,#{legacy_header=>true}),
+ logger:notice("~p~n",[D]),
+ {Lines3,C3} = check_log(),
+ [ct:log(L) || L <- Lines3],
+ ct:log("~p",[C3]),
+ ["=NOTICE REPORT==== "++_|D3] = Lines3,
+ true = length(D3)>50,
+ true = #{legacy_header=>true,single_line=>false}==C3,
+
+ ok = logger:update_formatter_config(?MODULE,single_line,true),
+ logger:notice("~p~n",[D]),
+ {Lines4,C4} = check_log(),
+ [ct:log(L) || L <- Lines4],
+ ct:log("~p",[C4]),
+ ["=NOTICE REPORT==== "++_,D4] = Lines4,
+ true = length(D4)>3000,
+ true = #{legacy_header=>true,single_line=>true}==C4,
+
+ %% Finally, check that error_logger_notice_header works, default=info
+ error_logger:info_msg("~p",[D]),
+ {Lines5,C5} = check_log(),
+ [ct:log(L) || L <- Lines5],
+ ct:log("~p",[C5]),
+ ["=INFO REPORT==== "++_,_D5] = Lines5,
+
+ ok=logger:update_formatter_config(?MODULE,error_logger_notice_header,notice),
+ error_logger:info_msg("~p",[D]),
+ {Lines6,C6} = check_log(),
+ [ct:log(L) || L <- Lines6],
+ ct:log("~p",[C6]),
+ ["=NOTICE REPORT==== "++_,_D6] = Lines6,
+
+ {error,{invalid_formatter_config,bad}} =
+ logger:update_formatter_config(?MODULE,bad),
+ {error,{invalid_formatter_config,logger_formatter,{depth,bad}}} =
+ logger:update_formatter_config(?MODULE,depth,bad),
+
+ ok.
+
+update_config(cleanup,_Config) ->
+ _ = logger:remove_handler(?MODULE),
+ _ = logger:remove_handler_filter(default,silence),
+ ok.
+
+%%%-----------------------------------------------------------------
+%%% Internal
+format(Level,Msg,Meta,Config) ->
+ format(#{level=>Level,msg=>Msg,meta=>add_time(Meta)},Config).
+
+format(Log,Config) ->
+ lists:flatten(logger_formatter:format(Log,Config)).
+
+default_time_format(Timestamp) ->
+ default_time_format(Timestamp,false).
+
+default_time_format(Timestamp,Utc) ->
+ default_time_format(Timestamp,Utc,$T).
+
+default_time_format(Timestamp,Utc,Sep) ->
+ Offset = if Utc -> "Z";
+ true -> ""
+ end,
+ calendar:system_time_to_rfc3339(Timestamp,[{unit,microsecond},
+ {time_designator,Sep},
+ {offset,Offset}]).
+
+integer(Str) ->
+ is_integer(list_to_integer(Str)).
+integer(Str,Max) ->
+ integer(Str,0,Max).
+integer(Str,Min,Max) ->
+ Int = list_to_integer(Str),
+ Int >= Min andalso Int =<Max.
+
+%%%-----------------------------------------------------------------
+%%% Called by macro ?TRY(X)
+my_try(Fun) ->
+ try Fun() catch C:R:S -> {C,R,hd(S)} end.
+
+timestamp() ->
+ logger:timestamp().
+
+%% necessary?
+add_time(#{time:=_}=Meta) ->
+ Meta;
+add_time(Meta) ->
+ Meta#{time=>timestamp()}.
+
+%%%-----------------------------------------------------------------
+%%% handler callback
+log(Log,#{formatter:={M,C}}) ->
+ put(log,{M:format(Log,C),C}),
+ ok.
+
+check_log() ->
+ {S,C} = erase(log),
+ {string:lexemes(S,"\n"),C}.
diff --git a/lib/kernel/test/logger_legacy_SUITE.erl b/lib/kernel/test/logger_legacy_SUITE.erl
new file mode 100644
index 0000000000..c3cab07d81
--- /dev/null
+++ b/lib/kernel/test/logger_legacy_SUITE.erl
@@ -0,0 +1,288 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(logger_legacy_SUITE).
+
+-compile(export_all).
+-compile({nowarn_deprecated_function,[{gen_fsm,start,3},
+ {gen_fsm,send_all_state_event,2}]}).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("kernel/include/logger.hrl").
+-include_lib("kernel/src/logger_internal.hrl").
+
+%%%-----------------------------------------------------------------
+%%% This test suite test that log events from within OTP can be
+%%% delivered to legacy error_logger event handlers on the same format
+%%% as before 'logger' was introduced.
+%%%
+%%% Before changing the expected format of any of the log events in
+%%% this suite, please make sure that the backwards incompatibility it
+%%% introduces is ok.
+%%% -----------------------------------------------------------------
+
+-define(check(Expected),
+ receive Expected ->
+ [] = test_server:messages_get()
+ after 1000 ->
+ ct:fail({report_not_received,
+ {line,?LINE},
+ {got,test_server:messages_get()}})
+ end).
+-define(check_no_flush(Expected),
+ receive Expected ->
+ ok
+ after 1000 ->
+ ct:fail({report_not_received,
+ {line,?LINE},
+ {got,test_server:messages_get()}})
+ end).
+
+suite() ->
+ [{timetrap,{seconds,30}}].
+
+init_per_suite(Config) ->
+ logger:add_handler(error_logger,error_logger,
+ #{level=>info,filter_default=>stop}),
+ Config.
+
+end_per_suite(_Config) ->
+ logger:remove_handler(error_logger),
+ ok.
+
+init_per_group(std, Config) ->
+ ok = logger:set_handler_config(
+ error_logger,filters,
+ [{domain,{fun logger_filters:domain/2,{log,super,[otp]}}}]),
+ Config;
+init_per_group(sasl, Config) ->
+ %% Since default level is notice, and progress reports are info,
+ %% we need to raise the global logger level to info in order to
+ %% receive these.
+ ok = logger:set_primary_config(level,info),
+ ok = logger:set_handler_config(
+ error_logger,filters,
+ [{domain,{fun logger_filters:domain/2,{log,super,[otp,sasl]}}}]),
+
+ %% cth_log_redirect checks if sasl is started before displaying
+ %% any sasl reports - so just to see the real sasl reports in tc
+ %% log:
+ {ok,Apps} = application:ensure_all_started(sasl),
+ [{stop_apps,Apps}|Config];
+init_per_group(_Group, Config) ->
+ Config.
+
+end_per_group(sasl, Config) ->
+ Apps = ?config(stop_apps,Config),
+ [application:stop(App) || App <- Apps],
+ ok = logger:set_primary_config(level,notice),
+ ok;
+end_per_group(_Group, _Config) ->
+ ok.
+
+init_per_testcase(_TestCase, Config) ->
+ error_logger:add_report_handler(?MODULE,{event_handler,self()}),
+ Config.
+
+end_per_testcase(Case, Config) ->
+ %% Using gen_event directly here, instead of
+ %% error_logger:delete_report_handler. This is to avoid
+ %% automatically stopping the error_logger process due to removing
+ %% the last handler.
+ gen_event:delete_handler(error_logger,?MODULE,[]),
+ try apply(?MODULE,Case,[cleanup,Config])
+ catch error:undef -> ok
+ end,
+ ok.
+
+groups() ->
+ [{std,[],[gen_server,
+ gen_event,
+ gen_fsm,
+ gen_statem]},
+ {sasl,[],[sasl_reports,
+ supervisor_handle_info]}].
+
+all() ->
+ [{group,std},
+ {group,sasl}].
+
+gen_server(_Config) ->
+ {ok,Pid} = gen_server:start(?MODULE,gen_server,[]),
+ Msg = fun() -> erlang:error({badmatch,b}) end,
+ Pid ! Msg,
+ ?check({warning_msg,"** Undefined handle_info in ~p"++_,[?MODULE,Msg]}),
+ ok = gen_server:cast(Pid,Msg),
+ ?check({error,"** Generic server ~tp terminating"++_,
+ [Pid,{'$gen_cast',Msg},gen_server,{{badmatch,b},_}]}).
+
+gen_event(_Config) ->
+ {ok,Pid} = gen_event:start(),
+ ok = gen_event:add_handler(Pid,?MODULE,gen_event),
+ Msg = fun() -> erlang:error({badmatch,b}) end,
+ Pid ! Msg,
+ ?check({warning_msg,"** Undefined handle_info in ~tp"++_,[?MODULE,Msg]}),
+ gen_event:notify(Pid,Msg),
+ ?check({error,"** gen_event handler ~p crashed."++_,
+ [?MODULE,Pid,Msg,gen_event,{{badmatch,b},_}]}).
+
+gen_fsm(_Config) ->
+ {ok,Pid} = gen_fsm:start(?MODULE,gen_fsm,[]),
+ Msg = fun() -> erlang:error({badmatch,b}) end,
+ Pid ! Msg,
+ ?check({warning_msg,"** Undefined handle_info in ~p"++_,[?MODULE,Msg]}),
+ gen_fsm:send_all_state_event(Pid,Msg),
+ ?check({error,"** State machine ~tp terminating"++_,
+ [Pid,Msg,mystate,gen_fsm,{{badmatch,b},_}]}).
+
+gen_statem(_Config) ->
+ {ok,Pid} = gen_statem:start(?MODULE,gen_statem,[]),
+ Msg = fun() -> erlang:error({badmatch,b}) end,
+ Pid ! Msg,
+ ?check({error,"** State machine ~tp terminating"++_,
+ [Pid,{info,Msg},{mystate,gen_statem},error,{badmatch,b}|_]}).
+
+sasl_reports(Config) ->
+ App = {application,?MODULE,[{description, ""},
+ {vsn, "1.0"},
+ {modules, [?MODULE]},
+ {registered, []},
+ {applications, []},
+ {mod, {?MODULE, []}}]},
+ AppStr = io_lib:format("~p.",[App]),
+ Dir = ?config(priv_dir,Config),
+ AppFile = filename:join(Dir,?MODULE_STRING++".app"),
+ ok = file:write_file(AppFile,AppStr),
+ true = code:add_patha(Dir),
+ ok = application:start(?MODULE),
+ SupName = sup_name(),
+ Pid = whereis(SupName),
+ [{ch,ChPid,_,_}] = supervisor:which_children(Pid),
+ Node = node(),
+ ?check_no_flush({info_report,progress,[{application,?MODULE},
+ {started_at,Node}]}),
+ ?check({info_report,progress,[{supervisor,{local,SupName}},
+ {started,[{pid,ChPid}|_]}]}),
+ ok = gen_server:cast(ChPid, fun() ->
+ spawn_link(fun() -> receive x->ok end end)
+ end),
+ Msg = fun() -> erlang:error({badmatch,b}) end,
+ ok = gen_server:cast(ChPid,Msg),
+ ?check_no_flush({error,"** Generic server ~tp terminating"++_,
+ [ChPid,{'$gen_cast',Msg},gen_server,{{badmatch,b},_}]}),
+ ?check_no_flush({error_report,crash_report,
+ [[{initial_call,_},
+ {pid,ChPid},
+ {registered_name,[]},
+ {error_info,{error,{badmatch,b},_}},
+ {ancestors,_},
+ {message_queue_len,_},
+ {messages,_},
+ {links,[Pid,Neighbour]},
+ {dictionary,_},
+ {trap_exit,_},
+ {status,_},
+ {heap_size,_},
+ {stack_size,_},
+ {reductions,_}],
+ [{neighbour,[{pid,Neighbour},
+ {registered_name,_},
+ {initial_call,_},
+ {current_function,_},
+ {ancestors,_},
+ {message_queue_len,_},
+ {links,[ChPid]},
+ {trap_exit,_},
+ {status,_},
+ {heap_size,_},
+ {stack_size,_},
+ {reductions,_},
+ {current_stacktrace,_}]}]]}),
+ ?check_no_flush({error_report,supervisor_report,
+ [{supervisor,{local,SupName}},
+ {errorContext,child_terminated},
+ {reason,{{badmatch,b},_}},
+ {offender,[{pid,ChPid}|_]}]}),
+ ?check({info_report,progress,[{supervisor,{local,SupName}},
+ {started,_}]}),
+
+ ok = application:stop(?MODULE),
+ ?check({info_report,std_info,[{application,?MODULE},
+ {exited,stopped},
+ {type,temporary}]}).
+
+sasl_reports(cleanup,_Config) ->
+ application:stop(?MODULE).
+
+supervisor_handle_info(_Config) ->
+ {ok,Pid} = supervisor:start_link({local,sup_name()},?MODULE,supervisor),
+ ?check({info_report,progress,[{supervisor,_},{started,_}]}),
+ Pid ! msg,
+ ?check({error,"Supervisor received unexpected message: ~tp~n",[msg]}).
+
+supervisor_handle_info(cleanup,_Config) ->
+ Pid = whereis(sup_name()),
+ unlink(Pid),
+ exit(Pid,shutdown).
+
+%%%-----------------------------------------------------------------
+%%% Callbacks for error_logger event handler, gen_server, gen_statem,
+%%% gen_fsm, gen_event, supervisor and application.
+start(_,_) ->
+ supervisor:start_link({local,sup_name()},?MODULE,supervisor).
+
+init(supervisor) ->
+ {ok,{#{},[#{id=>ch,start=>{gen_server,start_link,[?MODULE,gen_server,[]]}}]}};
+init(StateMachine) when StateMachine==gen_statem; StateMachine==gen_fsm ->
+ {ok,mystate,StateMachine};
+init(State) ->
+ {ok,State}.
+
+%% error_logger event handler
+handle_event({Tag,_Gl,{_Pid,Type,Report}},{_,Pid}=State) ->
+ Pid ! {Tag,Type,Report},
+ {ok,State};
+%% other gen_event
+handle_event(Fun,State) when is_function(Fun) ->
+ Fun(),
+ {next_state,State}.
+
+%% gen_fsm
+handle_event(Fun,State,Data) when is_function(Fun) ->
+ Fun(),
+ {next_state,State,Data}.
+
+%% gen_statem
+handle_event(info,Fun,State,Data) when is_function(Fun) ->
+ Fun(),
+ {next_state,State,Data}.
+
+%% gen_server
+handle_cast(Fun,State) when is_function(Fun) ->
+ Fun(),
+ {noreply,State}.
+
+%% gen_statem
+callback_mode() ->
+ handle_event_function.
+
+%%%-----------------------------------------------------------------
+%%% Internal
+sup_name() ->
+ list_to_atom(?MODULE_STRING++"_sup").
diff --git a/lib/kernel/test/logger_olp_SUITE.erl b/lib/kernel/test/logger_olp_SUITE.erl
new file mode 100644
index 0000000000..ea3eec89f5
--- /dev/null
+++ b/lib/kernel/test/logger_olp_SUITE.erl
@@ -0,0 +1,90 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(logger_olp_SUITE).
+
+-compile(export_all).
+
+-include_lib("kernel/src/logger_olp.hrl").
+
+suite() ->
+ [{timetrap,{seconds,30}}].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(_Group, Config) ->
+ Config.
+
+end_per_group(_Group, _Config) ->
+ ok.
+
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+end_per_testcase(Case, Config) ->
+ try apply(?MODULE,Case,[cleanup,Config])
+ catch error:undef -> ok
+ end,
+ ok.
+
+groups() ->
+ [].
+
+all() ->
+ [idle_timer].
+
+%%%-----------------------------------------------------------------
+%%% Test cases
+idle_timer(_Config) ->
+ {ok,_Pid,Olp} = logger_olp:start_link(?MODULE,?MODULE,self(),#{}),
+ [logger_olp:load(Olp,{msg,N}) || N<-lists:seq(1,3)],
+ timer:sleep(?IDLE_DETECT_TIME*2),
+ [{load,{msg,1}},
+ {load,{msg,2}},
+ {load,{msg,3}},
+ {notify,idle}] = test_server:messages_get(),
+ logger_olp:cast(Olp,hello),
+ timer:sleep(?IDLE_DETECT_TIME*2),
+ [{cast,hello}] = test_server:messages_get(),
+ ok.
+idle_timer(cleanup,_Config) ->
+ unlink(whereis(?MODULE)),
+ logger_olp:stop(?MODULE),
+ ok.
+
+%%%-----------------------------------------------------------------
+%%% Olp callbacks
+init(P) ->
+ {ok,P}.
+
+handle_load(M,P) ->
+ P ! {load,M},
+ P.
+
+handle_cast(M,P) ->
+ P ! {cast,M},
+ {noreply,P}.
+
+notify(N,P) ->
+ P ! {notify,N},
+ P.
diff --git a/lib/kernel/test/logger_proxy_SUITE.erl b/lib/kernel/test/logger_proxy_SUITE.erl
new file mode 100644
index 0000000000..777531e4ed
--- /dev/null
+++ b/lib/kernel/test/logger_proxy_SUITE.erl
@@ -0,0 +1,274 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(logger_proxy_SUITE).
+
+-compile(export_all).
+
+%% -include_lib("common_test/include/ct.hrl").
+%% -include_lib("kernel/include/logger.hrl").
+%% -include_lib("kernel/src/logger_internal.hrl").
+
+%% -define(str,"Log from "++atom_to_list(?FUNCTION_NAME)++
+%% ":"++integer_to_list(?LINE)).
+%% -define(map_rep,#{function=>?FUNCTION_NAME, line=>?LINE}).
+%% -define(keyval_rep,[{function,?FUNCTION_NAME}, {line,?LINE}]).
+
+%% -define(MY_LOC(N),#{mfa=>{?MODULE,?FUNCTION_NAME,?FUNCTION_ARITY},
+%% file=>?FILE, line=>?LINE-N}).
+
+%% -define(TRY(X), my_try(fun() -> X end)).
+
+
+-define(HNAME,list_to_atom(lists:concat([?MODULE,"_",?FUNCTION_NAME]))).
+-define(LOC,#{mfa=>{?MODULE,?FUNCTION_NAME,?FUNCTION_ARITY},line=>?LINE}).
+-define(ENSURE_TIME,5000).
+
+suite() ->
+ [{timetrap,{seconds,30}},
+ {ct_hooks,[logger_test_lib]}].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(_Group, Config) ->
+ Config.
+
+end_per_group(_Group, _Config) ->
+ ok.
+
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+end_per_testcase(Case, Config) ->
+ try apply(?MODULE,Case,[cleanup,Config])
+ catch error:undef -> ok
+ end,
+ ok.
+
+groups() ->
+ [].
+
+all() ->
+ [basic,
+ emulator,
+ remote,
+ remote_emulator,
+ config,
+ restart_after,
+ terminate].
+
+%%%-----------------------------------------------------------------
+%%% Test cases
+basic(_Config) ->
+ ok = logger:add_handler(?HNAME,?MODULE,#{config=>self()}),
+ logger_proxy ! {log,notice,"Log from: ~p; ~p",[?FUNCTION_NAME,?LINE],L1=?LOC},
+ ok = ensure(L1),
+ logger_proxy ! {log,notice,[{test_case,?FUNCTION_NAME},{line,?LINE}],L2=?LOC},
+ ok = ensure(L2),
+ logger_proxy:log({remote,node(),{log,notice,
+ "Log from: ~p; ~p",
+ [?FUNCTION_NAME,?LINE],
+ L3=?LOC}}),
+ ok = ensure(L3),
+ logger_proxy:log({remote,node(),{log,notice,
+ [{test_case,?FUNCTION_NAME},
+ {line,?LINE}],
+ L4=?LOC}}),
+ ok = ensure(L4),
+ ok.
+basic(cleanup,_Config) ->
+ ok = logger:remove_handler(?HNAME).
+
+emulator(_Config) ->
+ ok = logger:add_handler(?HNAME,?MODULE,#{config=>self()}),
+ Pid = spawn(fun() -> erlang:error(some_reason) end),
+ ok = ensure(#{pid=>Pid}),
+ ok.
+emulator(cleanup,_Config) ->
+ ok = logger:remove_handler(?HNAME).
+
+remote(Config) ->
+ {ok,_,Node} = logger_test_lib:setup(Config,[{logger,[{proxy,#{}}]}]),
+ ok = logger:add_handler(?HNAME,?MODULE,#{config=>self()}),
+ L1 = ?LOC, spawn(Node,fun() -> logger:notice("Log from ~p; ~p",[?FUNCTION_NAME,?LINE],L1) end),
+ ok = ensure(L1),
+ L2 = ?LOC, spawn(Node,fun() -> logger:notice([{test_case,?FUNCTION_NAME},{line,?LINE}],L2) end),
+ ok = ensure(L2),
+ ok.
+remote(cleanup,_Config) ->
+ ok = logger:remove_handler(?HNAME).
+
+remote_emulator(Config) ->
+ {ok,_,Node} = logger_test_lib:setup(Config,[{logger,[{proxy,#{}}]}]),
+ ok = logger:add_handler(?HNAME,?MODULE,#{config=>self()}),
+ Pid = spawn(Node,fun() -> erlang:error(some_reason) end),
+ ok = ensure(#{pid=>Pid}),
+ ok.
+remote_emulator(cleanup,_Config) ->
+ ok = logger:remove_handler(?HNAME).
+
+config(_Config) ->
+ C1 = #{sync_mode_qlen:=SQ,
+ drop_mode_qlen:=DQ} = logger:get_proxy_config(),
+ C1 = logger_olp:get_opts(logger_proxy),
+
+ %% Update the existing config with these two values
+ SQ1 = SQ+1,
+ DQ1 = DQ+1,
+ ok = logger:update_proxy_config(#{sync_mode_qlen=>SQ1,
+ drop_mode_qlen=>DQ1}),
+ C2 = logger:get_proxy_config(), % reads from ets table
+ C2 = logger_olp:get_opts(logger_proxy), % ensure consistency with process opts
+ C2 = C1#{sync_mode_qlen:=SQ1,
+ drop_mode_qlen:=DQ1},
+
+ %% Update the existing again with only one value
+ SQ2 = SQ+2,
+ ok = logger:update_proxy_config(#{sync_mode_qlen=>SQ2}),
+ C3 = logger:get_proxy_config(),
+ C3 = logger_olp:get_opts(logger_proxy),
+ C3 = C2#{sync_mode_qlen:=SQ2},
+
+ %% Set the config, i.e. merge with defaults
+ ok = logger:set_proxy_config(#{sync_mode_qlen=>SQ1}),
+ C4 = logger:get_proxy_config(),
+ C4 = logger_olp:get_opts(logger_proxy),
+ C4 = C1#{sync_mode_qlen:=SQ1},
+
+ %% Reset to default
+ ok = logger:set_proxy_config(#{}),
+ C5 = logger:get_proxy_config(),
+ C5 = logger_olp:get_opts(logger_proxy),
+ C5 = logger_proxy:get_default_config(),
+
+ %% Errors
+ {error,{invalid_olp_config,_}} =
+ logger:set_proxy_config(#{faulty_key=>1}),
+ {error,{invalid_olp_config,_}} =
+ logger:set_proxy_config(#{sync_mode_qlen=>infinity}),
+ {error,{invalid_config,[]}} = logger:set_proxy_config([]),
+
+ {error,{invalid_olp_config,_}} =
+ logger:update_proxy_config(#{faulty_key=>1}),
+ {error,{invalid_olp_config,_}} =
+ logger:update_proxy_config(#{sync_mode_qlen=>infinity}),
+ {error,{invalid_config,[]}} = logger:update_proxy_config([]),
+
+ C5 = logger:get_proxy_config(),
+ C5 = logger_olp:get_opts(logger_proxy),
+
+ ok.
+config(cleanup,_Config) ->
+ _ = logger:set_logger_proxy(logger_proxy:get_default_config()),
+ ok.
+
+restart_after(_Config) ->
+ Restart = 3000,
+ ok = logger:update_proxy_config(#{overload_kill_enable => true,
+ overload_kill_qlen => 10,
+ overload_kill_restart_after => Restart}),
+ Proxy = whereis(logger_proxy),
+ Proxy = erlang:system_info(system_logger),
+ ProxyConfig = logger:get_proxy_config(),
+ ProxyConfig = logger_olp:get_opts(logger_proxy),
+
+ Ref = erlang:monitor(process,Proxy),
+ spawn(fun() ->
+ [logger_proxy ! {log,debug,
+ [{test_case,?FUNCTION_NAME},
+ {line,?LINE}],
+ ?LOC} || _ <- lists:seq(1,100)]
+ end),
+ receive
+ {'DOWN',Ref,_,_,_Reason} ->
+ undefined = erlang:system_info(system_logger),
+ timer:sleep(Restart),
+ poll_restarted(10)
+ after 5000 ->
+ ct:fail(proxy_not_terminated)
+ end,
+
+ Proxy1 = whereis(logger_proxy),
+ Proxy1 = erlang:system_info(system_logger),
+ ProxyConfig = logger:get_proxy_config(),
+ ProxyConfig = logger_olp:get_opts(logger_proxy),
+
+ ok.
+restart_after(cleanup,_Config) ->
+ _ = logger:set_logger_proxy(logger_proxy:get_default_config()),
+ ok.
+
+%% Test that system_logger flag is set to logger process if
+%% logger_proxy terminates for other reason than overloaded.
+terminate(_Config) ->
+ Logger = whereis(logger),
+ Proxy = whereis(logger_proxy),
+ Proxy = erlang:system_info(system_logger),
+ ProxyConfig = logger:get_proxy_config(),
+ ProxyConfig = logger_olp:get_opts(logger_proxy),
+
+ Ref = erlang:monitor(process,Proxy),
+ ok = logger_olp:stop(Proxy),
+ receive
+ {'DOWN',Ref,_,_,_Reason} ->
+ Logger = erlang:system_info(system_logger),
+ logger_proxy:restart(),
+ poll_restarted(10)
+ after 5000 ->
+ ct:fail(proxy_not_terminated)
+ end,
+
+ Proxy1 = whereis(logger_proxy),
+ Proxy1 = erlang:system_info(system_logger),
+ ProxyConfig = logger:get_proxy_config(),
+ ProxyConfig = logger_olp:get_opts(logger_proxy),
+
+ ok.
+
+%%%-----------------------------------------------------------------
+%%% Internal functions
+
+poll_restarted(0) ->
+ ct:fail(proxy_not_restarted);
+poll_restarted(N) ->
+ timer:sleep(1000),
+ case whereis(logger_proxy) of
+ undefined ->
+ poll_restarted(N-1);
+ _Pid ->
+ ok
+ end.
+
+%% Logger handler callback
+log(#{meta:=Meta},#{config:=Pid}) ->
+ Pid ! {logged,Meta}.
+
+%% Check that the log from the logger callback function log/2 is received
+ensure(Match) ->
+ receive {logged,Meta} ->
+ case maps:with(maps:keys(Match),Meta) of
+ Match -> ok;
+ _NoMatch -> {error,Match,Meta,test_server:messages_get()}
+ end
+ after ?ENSURE_TIME -> {error,Match,test_server:messages_get()}
+ end.
diff --git a/lib/kernel/test/logger_simple_h_SUITE.erl b/lib/kernel/test/logger_simple_h_SUITE.erl
new file mode 100644
index 0000000000..e0ad792bdb
--- /dev/null
+++ b/lib/kernel/test/logger_simple_h_SUITE.erl
@@ -0,0 +1,209 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(logger_simple_h_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("kernel/include/logger.hrl").
+-include_lib("kernel/src/logger_internal.hrl").
+
+-import(logger_test_lib, [setup/2, log/3, sync_and_read/3]).
+
+-define(check_no_log,[] = test_server:messages_get()).
+-define(check(Expected),
+ receive {log,Expected} ->
+ [] = test_server:messages_get()
+ after 1000 ->
+ ct:fail({report_not_received,
+ {line,?LINE},
+ {expected,Expected},
+ {got,test_server:messages_get()}})
+ end).
+
+-define(str,"Log from "++atom_to_list(?FUNCTION_NAME)++
+ ":"++integer_to_list(?LINE)).
+-define(map_rep,#{function=>?FUNCTION_NAME, line=>?LINE}).
+-define(keyval_rep,[{function,?FUNCTION_NAME}, {line,?LINE}]).
+
+suite() ->
+ [{timetrap,{seconds,30}},
+ {ct_hooks, [logger_test_lib]}].
+
+init_per_suite(Config) ->
+ Hs0 = logger:get_handler_config(),
+ Hs = lists:keydelete(cth_log_redirect,1,Hs0),
+ [ok = logger:remove_handler(Id) || {Id,_,_} <- Hs],
+ Env = [{App,Key,application:get_env(App,Key)} ||
+ {App,Key} <- [{kernel,logger_level}]],
+ [{env,Env},{logger,Hs}|Config].
+
+end_per_suite(Config) ->
+ [application:set_env(App,Key,Val) || {App,Key,Val} <- ?config(env,Config)],
+ Hs = ?config(logger,Config),
+ [ok = logger:add_handler(Id,Mod,C) || {Id,Mod,C} <- Hs],
+ ok.
+
+init_per_group(_Group, Config) ->
+ Config.
+
+end_per_group(_Group, _Config) ->
+ ok.
+
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+end_per_testcase(Case, Config) ->
+ try apply(?MODULE,Case,[cleanup,Config])
+ catch error:undef -> ok
+ end,
+ ok.
+
+groups() ->
+ [].
+
+all() ->
+ [start_stop,
+ replace_default,
+ replace_file,
+ replace_disk_log
+ ].
+
+start_stop(_Config) ->
+ undefined = whereis(logger_simple_h),
+ register(logger_simple_h,self()),
+ {error,_} = logger:add_handler(simple,
+ logger_simple_h,
+ #{filter_default=>log}),
+ unregister(logger_simple_h),
+ ok = logger:add_handler(simple,logger_simple_h,#{filter_default=>log}),
+ Pid = whereis(logger_simple_h),
+ true = is_pid(Pid),
+ ok = logger:remove_handler(simple),
+ false = is_pid(whereis(logger_simple_h)),
+ ok.
+start_stop(cleanup,_Config) ->
+ logger:remove_handler(simple).
+
+%% This testcase just tests that it does not crash, the default handler prints
+%% to stdout which we cannot read from in a detached slave.
+replace_default(Config) ->
+
+ {ok, _, Node} = logger_test_lib:setup(Config, [{logger, [{handler, default, undefined}]}]),
+ log(Node, emergency, [?str]),
+ log(Node, alert, [?str,[]]),
+ log(Node, error, [?map_rep]),
+ log(Node, info, [?keyval_rep]),
+ log(Node, info, [?keyval_rep++[not_key_val]]),
+ rpc:call(Node, error_logger, error_report, [some_type,?map_rep]),
+ rpc:call(Node, error_logger, warning_report, ["some_type",?map_rep]),
+ log(Node, critical, [?str,[?keyval_rep]]),
+ log(Node, notice, [["fake",string,"line:",?LINE]]),
+
+ ok = rpc:call(Node, logger, add_handlers, [kernel]),
+
+ ok.
+
+replace_file(Config) ->
+
+ {ok, _, Node} = logger_test_lib:setup(Config, [{logger, [{handler, default, undefined}]}]),
+ log(Node, emergency, [M1=?str]),
+ log(Node, alert, [M2=?str,[]]),
+ log(Node, error, [?map_rep]),
+ log(Node, warning, [?keyval_rep]),
+ log(Node, warning, [?keyval_rep++[not_key_val]]),
+ log(Node, critical, [?str,[?keyval_rep]]),
+ log(Node, notice, [["fake",string,"line:",?LINE]]),
+
+ File = filename:join(proplists:get_value(priv_dir,Config),
+ atom_to_list(?FUNCTION_NAME)++".log"),
+
+ ok = rpc:call(Node, logger, add_handlers,
+ [[{handler, default, logger_std_h,
+ #{ config => #{ type => {file, File} },
+ formatter => {?DEFAULT_FORMATTER,?DEFAULT_FORMAT_CONFIG}}}]]),
+
+ {ok,Bin} = sync_and_read(Node, file, File),
+ Lines = [unicode:characters_to_list(L) ||
+ L <- binary:split(Bin,<<"\n">>,[global,trim])],
+ ["=EMERGENCY REPORT===="++_,
+ M1,
+ "=ALERT REPORT===="++_,
+ M2,
+ "=ERROR REPORT===="++_,
+ _,
+ _,
+ "=WARNING REPORT===="++_,
+ _,
+ _,
+ "=WARNING REPORT===="++_,
+ _,
+ _,
+ _,
+ "=CRITICAL REPORT===="++_,
+ _,
+ _,
+ "=NOTICE REPORT===="++_,
+ _
+ ] = Lines,
+ ok.
+
+replace_disk_log(Config) ->
+
+ {ok, _, Node} = logger_test_lib:setup(Config, [{logger, [{handler, default, undefined}]}]),
+ log(Node, emergency, [M1=?str]),
+ log(Node, alert, [M2=?str,[]]),
+ log(Node, error, [?map_rep]),
+ log(Node, warning, [?keyval_rep]),
+ log(Node, warning, [?keyval_rep++[not_key_val]]),
+ log(Node, critical, [?str,[?keyval_rep]]),
+ log(Node, notice, [["fake",string,"line:",?LINE]]),
+
+ File = filename:join(proplists:get_value(priv_dir,Config),
+ atom_to_list(?FUNCTION_NAME)++".log"),
+
+ ok = rpc:call(Node, logger, add_handlers,
+ [[{handler, default, logger_disk_log_h,
+ #{ config => #{ file => File },
+ formatter => {?DEFAULT_FORMATTER,?DEFAULT_FORMAT_CONFIG}}}]]),
+ {ok,Bin} = sync_and_read(Node, disk_log, File),
+ Lines = [unicode:characters_to_list(L) ||
+ L <- binary:split(Bin,<<"\n">>,[global,trim])],
+ ["=EMERGENCY REPORT===="++_,
+ M1,
+ "=ALERT REPORT===="++_,
+ M2,
+ "=ERROR REPORT===="++_,
+ _,
+ _,
+ "=WARNING REPORT===="++_,
+ _,
+ _,
+ "=WARNING REPORT===="++_,
+ _,
+ _,
+ _,
+ "=CRITICAL REPORT===="++_,
+ _,
+ _,
+ "=NOTICE REPORT===="++_,
+ _
+ ] = Lines,
+ ok.
diff --git a/lib/kernel/test/logger_std_h_SUITE.erl b/lib/kernel/test/logger_std_h_SUITE.erl
new file mode 100644
index 0000000000..16ab0e97fc
--- /dev/null
+++ b/lib/kernel/test/logger_std_h_SUITE.erl
@@ -0,0 +1,2135 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(logger_std_h_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("kernel/include/logger.hrl").
+-include_lib("kernel/src/logger_internal.hrl").
+-include_lib("kernel/src/logger_h_common.hrl").
+-include_lib("kernel/src/logger_olp.hrl").
+-include_lib("stdlib/include/ms_transform.hrl").
+-include_lib("kernel/include/file.hrl").
+
+-define(check_no_log,
+ begin
+ timer:sleep(?IDLE_DETECT_TIME*2),
+ [] = test_server:messages_get()
+ end).
+-define(check(Expected),
+ receive
+ {log,Expected} ->
+ [] = test_server:messages_get()
+ after 5000 ->
+ ct:fail({report_not_received,
+ {line,?LINE},
+ {expected,Expected},
+ {got,test_server:messages_get()}})
+ end).
+
+-define(msg,"Log from "++atom_to_list(?FUNCTION_NAME)++
+ ":"++integer_to_list(?LINE)).
+-define(bin(Msg), list_to_binary(Msg++"\n")).
+-define(domain,#{domain=>[?MODULE]}).
+
+suite() ->
+ [{timetrap,{seconds,30}},
+ {ct_hooks,[logger_test_lib]}].
+
+init_per_suite(Config) ->
+ timer:start(), % to avoid progress report
+ {ok,#{formatter:=OrigFormatter}} =
+ logger:get_handler_config(?STANDARD_HANDLER),
+ [{formatter,OrigFormatter}|Config].
+
+end_per_suite(Config) ->
+ {OrigMod,OrigConf} = proplists:get_value(formatter,Config),
+ logger:set_handler_config(?STANDARD_HANDLER,formatter,{OrigMod,OrigConf}),
+ ok.
+
+init_per_group(_Group, Config) ->
+ Config.
+
+end_per_group(_Group, _Config) ->
+ ok.
+
+init_per_testcase(reopen_changed_log=TC, Config) ->
+ case os:type() of
+ {win32,_} ->
+ {skip,"This test can only work with inodes, i.e. not on Windows"};
+ _ ->
+ ct:print("********** ~w **********", [TC]),
+ Config
+ end;
+init_per_testcase(TestHooksCase, Config) when
+ TestHooksCase == write_failure;
+ TestHooksCase == sync_failure ->
+ case (fun() -> ?TEST_HOOKS_TAB == undefined end)() of
+ true ->
+ {skip,"Define the TEST_HOOKS macro to run this test"};
+ false ->
+ ct:print("********** ~w **********", [TestHooksCase]),
+ Config
+ end;
+init_per_testcase(OPCase, Config) when
+ OPCase == qlen_kill_new;
+ OPCase == restart_after ->
+ case re:run(erlang:system_info(system_version),
+ "dirty-schedulers-TEST",
+ [{capture,none}]) of
+ match ->
+ {skip,"Overload protection test skipped on dirty-schedulers-TEST"};
+ nomatch ->
+ ct:print("********** ~w **********", [OPCase]),
+ Config
+ end;
+init_per_testcase(TestCase, Config) ->
+ ct:print("********** ~w **********", [TestCase]),
+ Config.
+
+end_per_testcase(Case, Config) ->
+ try apply(?MODULE,Case,[cleanup,Config])
+ catch error:undef -> ok
+ end,
+ ok.
+
+groups() ->
+ [].
+
+all() ->
+ [add_remove_instance_tty,
+ add_remove_instance_standard_io,
+ add_remove_instance_standard_error,
+ add_remove_instance_file1,
+ add_remove_instance_file2,
+ add_remove_instance_file3,
+ add_remove_instance_file4,
+ default_formatter,
+ filter_config,
+ errors,
+ formatter_fail,
+ config_fail,
+ crash_std_h_to_file,
+ crash_std_h_to_disk_log,
+ bad_input,
+ reconfig,
+ file_opts,
+ sync,
+ write_failure,
+ sync_failure,
+ op_switch_to_sync_file,
+ op_switch_to_sync_tty,
+ op_switch_to_drop_file,
+ op_switch_to_drop_tty,
+ op_switch_to_flush_file,
+ op_switch_to_flush_tty,
+ limit_burst_disabled,
+ limit_burst_enabled_one,
+ limit_burst_enabled_period,
+ kill_disabled,
+ qlen_kill_new,
+ qlen_kill_std,
+ mem_kill_new,
+ mem_kill_std,
+ restart_after,
+ handler_requests_under_load,
+ recreate_deleted_log,
+ reopen_changed_log,
+ rotate_size,
+ rotate_size_compressed,
+ rotate_size_reopen,
+ rotation_opts,
+ rotation_opts_restart_handler
+ ].
+
+add_remove_instance_tty(_Config) ->
+ {error,{handler_not_added,{invalid_config,logger_std_h,#{type:=tty}}}} =
+ logger:add_handler(?MODULE,logger_std_h,
+ #{config => #{type => tty},
+ filter_default=>log,
+ formatter=>{?MODULE,self()}}),
+ ok.
+
+add_remove_instance_standard_io(_Config) ->
+ add_remove_instance_nofile(standard_io).
+add_remove_instance_standard_io(cleanup,_Config) ->
+ logger_std_h_remove().
+
+add_remove_instance_standard_error(_Config) ->
+ add_remove_instance_nofile(standard_error).
+add_remove_instance_standard_error(cleanup,_Config) ->
+ logger_std_h_remove().
+
+add_remove_instance_file1(Config) ->
+ Dir = ?config(priv_dir,Config),
+ Log = filename:join(Dir,"stdlog1.txt"),
+ Type = {file,Log},
+ add_remove_instance_file(Log, Type).
+add_remove_instance_file1(cleanup,_Config) ->
+ logger_std_h_remove().
+
+add_remove_instance_file2(Config) ->
+ Dir = ?config(priv_dir,Config),
+ Log = filename:join(Dir,"stdlog2.txt"),
+ Type = {file,Log,[raw,append]},
+ add_remove_instance_file(Log, Type).
+add_remove_instance_file2(cleanup,_Config) ->
+ logger_std_h_remove().
+
+add_remove_instance_file3(_Config) ->
+ Log = atom_to_list(?MODULE),
+ StdHConfig = #{type=>file},
+ add_remove_instance_file(Log, StdHConfig).
+add_remove_instance_file3(cleanup,_Config) ->
+ logger_std_h_remove().
+
+add_remove_instance_file4(Config) ->
+ Dir = ?config(priv_dir,Config),
+ Log = filename:join(Dir,"stdlog4.txt"),
+ StdHConfig = #{file=>Log,modes=>[]},
+ add_remove_instance_file(Log, StdHConfig).
+add_remove_instance_file4(cleanup,_Config) ->
+ logger_std_h_remove().
+
+add_remove_instance_file(Log, Type) when not is_map(Type) ->
+ add_remove_instance_file(Log,#{type=>Type});
+add_remove_instance_file(Log, StdHConfig) when is_map(StdHConfig) ->
+ ok = logger:add_handler(?MODULE,
+ logger_std_h,
+ #{config => StdHConfig,
+ filter_default=>stop,
+ filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
+ formatter=>{?MODULE,self()}}),
+ Pid = whereis(h_proc_name()),
+ true = is_pid(Pid),
+ logger:notice(M1=?msg,?domain),
+ ?check(M1),
+ B1 = ?bin(M1),
+ try_read_file(Log, {ok,B1}, filesync_rep_int()),
+ ok = logger:remove_handler(?MODULE),
+ timer:sleep(500),
+ undefined = whereis(h_proc_name()),
+ logger:notice(?msg,?domain),
+ ?check_no_log,
+ try_read_file(Log, {ok,B1}, filesync_rep_int()),
+ ok.
+
+default_formatter(_Config) ->
+ ok = logger:set_handler_config(?STANDARD_HANDLER,formatter,
+ {?DEFAULT_FORMATTER,?DEFAULT_FORMAT_CONFIG}),
+ ct:capture_start(),
+ logger:notice(M1=?msg),
+ timer:sleep(100),
+ ct:capture_stop(),
+ [Msg] = ct:capture_get(),
+ match = re:run(Msg,"=NOTICE REPORT====.*\n"++M1,[{capture,none}]),
+ ok.
+
+filter_config(_Config) ->
+ ok = logger:add_handler(?MODULE,logger_std_h,#{}),
+ {ok,#{config:=HConfig}=Config} = logger:get_handler_config(?MODULE),
+ HConfig = maps:without([olp],HConfig),
+
+ FakeFullHConfig = HConfig#{olp=>{regname,self(),erlang:make_ref()}},
+ #{config:=HConfig} =
+ logger_std_h:filter_config(Config#{config=>FakeFullHConfig}),
+ ok.
+
+filter_config(cleanup,_Config) ->
+ logger:remove_handler(?MODULE),
+ ok.
+
+errors(Config) ->
+ Dir = ?config(priv_dir,Config),
+ Log = filename:join(Dir,?FUNCTION_NAME),
+
+ ok = logger:add_handler(?MODULE,logger_std_h,#{}),
+ {error,{already_exist,?MODULE}} =
+ logger:add_handler(?MODULE,logger_std_h,#{}),
+
+ {error,{not_found,no_such_name}} = logger:remove_handler(no_such_name),
+
+ ok = logger:remove_handler(?MODULE),
+ {error,{not_found,?MODULE}} = logger:remove_handler(?MODULE),
+
+ {error,
+ {handler_not_added,
+ {invalid_config,logger_std_h,#{type:=faulty_type}}}} =
+ logger:add_handler(?MODULE,logger_std_h,
+ #{config => #{type => faulty_type}}),
+
+ case os:type() of
+ {win32,_} ->
+ %% No use in testing file access on windows
+ ok;
+ _ ->
+ NoDir = lists:concat(["/",?MODULE,"_dir"]),
+ {error,
+ {handler_not_added,{open_failed,NoDir,eacces}}} =
+ logger:add_handler(myh2,logger_std_h,
+ #{config=>#{type=>{file,NoDir}}})
+ end,
+
+ {error,
+ {handler_not_added,
+ {invalid_config,logger_std_h,#{modes:=bad_file_opt}}}} =
+ logger:add_handler(myh3,logger_std_h,
+ #{config=>#{type=>{file,Log,bad_file_opt}}}),
+
+ ok = logger:notice(?msg).
+
+errors(cleanup,_Config) ->
+ logger:remove_handler(?MODULE).
+
+formatter_fail(Config) ->
+ Dir = ?config(priv_dir,Config),
+ Log = filename:join(Dir,?FUNCTION_NAME),
+
+ %% no formatter
+ ok = logger:add_handler(?MODULE,
+ logger_std_h,
+ #{config => #{type => {file,Log}},
+ filter_default=>stop,
+ filters=>?DEFAULT_HANDLER_FILTERS([?MODULE])}),
+ Pid = whereis(h_proc_name()),
+ true = is_pid(Pid),
+ H = logger:get_handler_ids(),
+ true = lists:member(?MODULE,H),
+
+ %% Formatter is added automatically
+ {ok,#{formatter:={logger_formatter,_}}} = logger:get_handler_config(?MODULE),
+ logger:notice(M1=?msg,?domain),
+ Got1 = try_match_file(Log,"[0-9\\+\\-T:\\.]* notice: "++M1,5000),
+
+ ok = logger:set_handler_config(?MODULE,formatter,{nonexistingmodule,#{}}),
+ logger:notice(M2=?msg,?domain),
+ Got2 = try_match_file(Log,
+ escape(Got1)++"[0-9\\+\\-T:\\.]* notice: FORMATTER CRASH: .*"++M2,
+ 5000),
+
+ ok = logger:set_handler_config(?MODULE,formatter,{?MODULE,crash}),
+ logger:notice(M3=?msg,?domain),
+ Got3 = try_match_file(Log,
+ escape(Got2)++"[0-9\\+\\-T:\\.]* notice: FORMATTER CRASH: .*"++M3,
+ 5000),
+
+ ok = logger:set_handler_config(?MODULE,formatter,{?MODULE,bad_return}),
+ logger:notice(?msg,?domain),
+ try_match_file(Log,
+ escape(Got3)++"FORMATTER ERROR: bad return value",
+ 5000),
+
+ %% Check that handler is still alive and was never dead
+ Pid = whereis(h_proc_name()),
+ H = logger:get_handler_ids(),
+
+ ok.
+
+formatter_fail(cleanup,_Config) ->
+ logger:remove_handler(?MODULE).
+
+config_fail(_Config) ->
+ {error,{handler_not_added,{invalid_config,logger_std_h,#{bad:=bad}}}} =
+ logger:add_handler(?MODULE,logger_std_h,
+ #{config => #{bad => bad},
+ filter_default=>log,
+ formatter=>{?MODULE,self()}}),
+ {error,{handler_not_added,{invalid_config,logger_std_h,
+ #{restart_type:=bad}}}} =
+ logger:add_handler(?MODULE,logger_std_h,
+ #{config => #{restart_type => bad},
+ filter_default=>log,
+ formatter=>{?MODULE,self()}}),
+ {error,{handler_not_added,{invalid_olp_levels,#{drop_mode_qlen:=1}}}} =
+ logger:add_handler(?MODULE,logger_std_h,
+ #{config => #{drop_mode_qlen=>1}}),
+ {error,{handler_not_added,{invalid_olp_levels,#{sync_mode_qlen:=43,
+ drop_mode_qlen:=42}}}} =
+ logger:add_handler(?MODULE,logger_std_h,
+ #{config => #{sync_mode_qlen=>43,
+ drop_mode_qlen=>42}}),
+ {error,{handler_not_added,{invalid_olp_levels,#{drop_mode_qlen:=43,
+ flush_qlen:=42}}}} =
+ logger:add_handler(?MODULE,logger_std_h,
+ #{config => #{drop_mode_qlen=>43,
+ flush_qlen=>42}}),
+
+ ok = logger:add_handler(?MODULE,logger_std_h,
+ #{filter_default=>log,
+ formatter=>{?MODULE,self()}}),
+ {error,{illegal_config_change,logger_std_h,#{type:=_},#{type:=_}}} =
+ logger:set_handler_config(?MODULE,config,
+ #{type=>{file,"file"}}),
+
+ {error,{invalid_olp_levels,_}} =
+ logger:set_handler_config(?MODULE,config,
+ #{sync_mode_qlen=>100,
+ flush_qlen=>99}),
+ {error,{invalid_config,logger_std_h,#{filesync_rep_int:=2000}}} =
+ logger:set_handler_config(?MODULE, config,
+ #{filesync_rep_int => 2000}),
+
+ %% Read-only fields may (accidentially) be included in the change,
+ %% but it won't take effect
+ {ok,C} = logger:get_handler_config(?MODULE),
+ ok = logger:set_handler_config(?MODULE,config,#{olp=>dummyvalue}),
+ {ok,C} = logger:get_handler_config(?MODULE),
+
+ ok.
+
+config_fail(cleanup,_Config) ->
+ logger:remove_handler(?MODULE).
+
+crash_std_h_to_file(Config) ->
+ Dir = ?config(priv_dir,Config),
+ Log = filename:join(Dir,lists:concat([?MODULE,"_",?FUNCTION_NAME,".log"])),
+ crash_std_h(Config,?FUNCTION_NAME,
+ [{handler,default,logger_std_h,
+ #{ config => #{ type => {file, Log} }}}],
+ file, Log).
+crash_std_h_to_file(cleanup,_Config) ->
+ crash_std_h(cleanup).
+
+crash_std_h_to_disk_log(Config) ->
+ Dir = ?config(priv_dir,Config),
+ Log = filename:join(Dir,lists:concat([?MODULE,"_",?FUNCTION_NAME,".log"])),
+ crash_std_h(Config,?FUNCTION_NAME,
+ [{handler,default,logger_disk_log_h,
+ #{ config => #{ file => Log }}}],
+ disk_log,Log).
+crash_std_h_to_disk_log(cleanup,_Config) ->
+ crash_std_h(cleanup).
+
+crash_std_h(Config,Func,Var,Type,Log) ->
+ Dir = ?config(priv_dir,Config),
+ SysConfig = filename:join(Dir,lists:concat([?MODULE,"_",Func,".config"])),
+ ok = file:write_file(SysConfig, io_lib:format("[{kernel,[{logger,~p}]}].",[Var])),
+ Pa = filename:dirname(code:which(?MODULE)),
+ Name = lists:concat([?MODULE,"_",Func]),
+ Args = lists:concat([" -config ",filename:rootname(SysConfig)," -pa ",Pa]),
+ ct:pal("Starting ~p with ~tp", [Name,Args]),
+ %% Start a node which prints kernel logs to the destination specified by Type
+ {ok,Node} = test_server:start_node(Name, peer, [{args, Args}]),
+ HProcName =
+ case Type of
+ file -> ?name_to_reg_name(logger_std_h,?STANDARD_HANDLER);
+ disk_log -> ?name_to_reg_name(logger_disk_log_h,?STANDARD_HANDLER)
+ end,
+ Pid = rpc:call(Node,erlang,whereis,[HProcName]),
+ ok = rpc:call(Node,logger,set_handler_config,[?STANDARD_HANDLER,formatter,
+ {?MODULE,self()}]),
+ ok = log_on_remote_node(Node,"dummy1"),
+ ?check("dummy1"),
+ {ok,Bin1} = sync_and_read(Node,Type,Log),
+ <<"dummy1\n">> = binary:part(Bin1,{byte_size(Bin1),-7}),
+
+ %% Kill the logger_std_h process
+ exit(Pid, kill),
+
+ %% Wait a bit, then check that it is gone
+ timer:sleep(2000),
+ undefined = rpc:call(Node,erlang,whereis,[HProcName]),
+
+ %% Check that file is not empty
+ {ok,Bin2} = sync_and_read(Node,Type,Log),
+ <<"dummy1\n">> = binary:part(Bin2,{byte_size(Bin2),-7}),
+ ok.
+
+%% Can not use rpc:call here, since the code would execute on a
+%% process with group_leader on this (the calling) node, and thus
+%% logger would send the log event to the logger process here instead
+%% of logging it itself.
+log_on_remote_node(Node,Msg) ->
+ Pid = self(),
+ _ = spawn_link(Node,
+ fun() -> erlang:group_leader(whereis(user),self()),
+ logger:notice(Msg),
+ Pid ! done
+ end),
+ receive done -> ok end,
+ ok.
+
+
+crash_std_h(cleanup) ->
+ Nodes = nodes(),
+ [test_server:stop_node(Node) || Node <- Nodes].
+
+sync_and_read(Node,disk_log,Log) ->
+ rpc:call(Node,logger_disk_log_h,filesync,[?STANDARD_HANDLER]),
+ case file:read_file(Log ++ ".1") of
+ {ok,<<>>} ->
+ timer:sleep(5000),
+ file:read_file(Log ++ ".1");
+ Ok ->
+ Ok
+ end;
+sync_and_read(Node,file,Log) ->
+ rpc:call(Node,logger_std_h,filesync,[?STANDARD_HANDLER]),
+ case file:read_file(Log) of
+ {ok,<<>>} ->
+ timer:sleep(5000),
+ file:read_file(Log);
+ Ok ->
+ Ok
+ end.
+
+bad_input(_Config) ->
+ {error,{badarg,{filesync,["BadType"]}}} = logger_std_h:filesync("BadType").
+
+reconfig(Config) ->
+ Dir = ?config(priv_dir,Config),
+ ok = logger:add_handler(?MODULE,
+ logger_std_h,
+ #{config => #{type => standard_io},
+ filter_default=>log,
+ filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
+ formatter=>{?MODULE,self()}}),
+ #{%id := ?MODULE,
+ cb_state:=#{handler_state := #{type := standard_io,
+ file_ctrl_pid := FileCtrlPid},
+ filesync_repeat_interval := no_repeat},
+ sync_mode_qlen := ?SYNC_MODE_QLEN,
+ drop_mode_qlen := ?DROP_MODE_QLEN,
+ flush_qlen := ?FLUSH_QLEN,
+ burst_limit_enable := ?BURST_LIMIT_ENABLE,
+ burst_limit_max_count := ?BURST_LIMIT_MAX_COUNT,
+ burst_limit_window_time := ?BURST_LIMIT_WINDOW_TIME,
+ overload_kill_enable := ?OVERLOAD_KILL_ENABLE,
+ overload_kill_qlen := ?OVERLOAD_KILL_QLEN,
+ overload_kill_mem_size := ?OVERLOAD_KILL_MEM_SIZE,
+ overload_kill_restart_after := ?OVERLOAD_KILL_RESTART_AFTER} =
+ logger_olp:info(h_proc_name()),
+
+ {ok,
+ #{config:=
+ #{type := standard_io,
+ sync_mode_qlen := ?SYNC_MODE_QLEN,
+ drop_mode_qlen := ?DROP_MODE_QLEN,
+ flush_qlen := ?FLUSH_QLEN,
+ burst_limit_enable := ?BURST_LIMIT_ENABLE,
+ burst_limit_max_count := ?BURST_LIMIT_MAX_COUNT,
+ burst_limit_window_time := ?BURST_LIMIT_WINDOW_TIME,
+ overload_kill_enable := ?OVERLOAD_KILL_ENABLE,
+ overload_kill_qlen := ?OVERLOAD_KILL_QLEN,
+ overload_kill_mem_size := ?OVERLOAD_KILL_MEM_SIZE,
+ overload_kill_restart_after := ?OVERLOAD_KILL_RESTART_AFTER,
+ filesync_repeat_interval := no_repeat} =
+ DefaultHConf}}
+ = logger:get_handler_config(?MODULE),
+
+ ok = logger:set_handler_config(?MODULE, config,
+ #{sync_mode_qlen => 1,
+ drop_mode_qlen => 2,
+ flush_qlen => 3,
+ burst_limit_enable => false,
+ burst_limit_max_count => 10,
+ burst_limit_window_time => 10,
+ overload_kill_enable => true,
+ overload_kill_qlen => 100000,
+ overload_kill_mem_size => 10000000,
+ overload_kill_restart_after => infinity,
+ filesync_repeat_interval => 5000}),
+ #{%id := ?MODULE,
+ cb_state := #{handler_state := #{type := standard_io,
+ file_ctrl_pid := FileCtrlPid},
+ filesync_repeat_interval := no_repeat},
+ sync_mode_qlen := 1,
+ drop_mode_qlen := 2,
+ flush_qlen := 3,
+ burst_limit_enable := false,
+ burst_limit_max_count := 10,
+ burst_limit_window_time := 10,
+ overload_kill_enable := true,
+ overload_kill_qlen := 100000,
+ overload_kill_mem_size := 10000000,
+ overload_kill_restart_after := infinity} = logger_olp:info(h_proc_name()),
+
+ {ok,#{config :=
+ #{type := standard_io,
+ sync_mode_qlen := 1,
+ drop_mode_qlen := 2,
+ flush_qlen := 3,
+ burst_limit_enable := false,
+ burst_limit_max_count := 10,
+ burst_limit_window_time := 10,
+ overload_kill_enable := true,
+ overload_kill_qlen := 100000,
+ overload_kill_mem_size := 10000000,
+ overload_kill_restart_after := infinity,
+ filesync_repeat_interval := no_repeat} = HConf}} =
+ logger:get_handler_config(?MODULE),
+
+ ok = logger:update_handler_config(?MODULE, config,
+ #{flush_qlen => ?FLUSH_QLEN}),
+ {ok,#{config:=C1}} = logger:get_handler_config(?MODULE),
+ ct:log("C1: ~p",[C1]),
+ C1 = HConf#{flush_qlen => ?FLUSH_QLEN},
+
+ ok = logger:set_handler_config(?MODULE, config, #{sync_mode_qlen => 1}),
+ {ok,#{config:=C2}} = logger:get_handler_config(?MODULE),
+ ct:log("C2: ~p",[C2]),
+ C2 = DefaultHConf#{sync_mode_qlen => 1},
+
+ ok = logger:set_handler_config(?MODULE, config, #{drop_mode_qlen => 100}),
+ {ok,#{config:=C3}} = logger:get_handler_config(?MODULE),
+ ct:log("C3: ~p",[C3]),
+ C3 = DefaultHConf#{drop_mode_qlen => 100},
+
+ ok = logger:update_handler_config(?MODULE, config, #{sync_mode_qlen => 1}),
+ {ok,#{config:=C4}} = logger:get_handler_config(?MODULE),
+ ct:log("C4: ~p",[C4]),
+ C4 = DefaultHConf#{sync_mode_qlen => 1,
+ drop_mode_qlen => 100},
+
+ ok = logger:remove_handler(?MODULE),
+
+ File = filename:join(Dir,lists:concat([?FUNCTION_NAME,".log"])),
+ ok = logger:add_handler(?MODULE,
+ logger_std_h,
+ #{config => #{type => {file,File}},
+ filter_default=>log,
+ filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
+ formatter=>{?MODULE,self()}}),
+
+ {ok,#{config:=#{filesync_repeat_interval:=FSI}=FileHConfig}} =
+ logger:get_handler_config(?MODULE),
+ ok = logger:update_handler_config(?MODULE,config,
+ #{filesync_repeat_interval=>FSI+2000}),
+ {ok,#{config:=C5}} = logger:get_handler_config(?MODULE),
+ ct:log("C5: ~p",[C5]),
+ C5 = FileHConfig#{filesync_repeat_interval=>FSI+2000},
+
+ %% You are not allowed to actively set 'type' in runtime, since
+ %% this is a write once field.
+ {error, {illegal_config_change,logger_std_h,_,_}} =
+ logger:set_handler_config(?MODULE,config,#{type=>standard_io}),
+ {ok,#{config:=C6}} = logger:get_handler_config(?MODULE),
+ ct:log("C6: ~p",[C6]),
+ C6 = C5,
+
+ %% ... but if you don't specify 'type', then set_handler_config shall
+ %% NOT reset it to its default value
+ ok = logger:set_handler_config(?MODULE,config,#{sync_mode_qlen=>1}),
+ {ok,#{config:=C7}} = logger:get_handler_config(?MODULE),
+ ct:log("C7: ~p",[C7]),
+ C7 = FileHConfig#{sync_mode_qlen=>1},
+ ok.
+
+reconfig(cleanup, _Config) ->
+ logger:remove_handler(?MODULE).
+
+
+file_opts(Config) ->
+ Dir = ?config(priv_dir,Config),
+ Log = filename:join(Dir, lists:concat([?FUNCTION_NAME,".log"])),
+ MissingOpts = [raw],
+ Type1 = {file,Log,MissingOpts},
+ ok = logger:add_handler(?MODULE, logger_std_h,
+ #{config => #{type => Type1}}),
+ {ok,#{config:=#{type:=file,file:=Log,modes:=Modes1}}} =
+ logger:get_handler_config(?MODULE),
+ [append,delayed_write,raw] = lists:sort(Modes1),
+ ok = logger:remove_handler(?MODULE),
+
+ OkFileOpts = [raw,append],
+ OkType = {file,Log,OkFileOpts},
+ ok = logger:add_handler(?MODULE,
+ logger_std_h,
+ #{config => #{type => OkType}, % old format
+ filter_default=>log,
+ filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
+ formatter=>{?MODULE,self()}}),
+
+ ModOpts = [delayed_write|OkFileOpts],
+ #{cb_state := #{handler_state := #{type:=file,
+ file:=Log,
+ modes:=ModOpts}}} =
+ logger_olp:info(h_proc_name()),
+ {ok,#{config := #{type:=file,
+ file:=Log,
+ modes:=ModOpts}}} = logger:get_handler_config(?MODULE),
+ ok = logger:remove_handler(?MODULE),
+
+ ok = logger:add_handler(?MODULE,
+ logger_std_h,
+ #{config => #{type => file,
+ file => Log,
+ modes => OkFileOpts}, % new format
+ filter_default=>log,
+ filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
+ formatter=>{?MODULE,self()}}),
+
+ #{cb_state := #{handler_state := #{type:=file,
+ file:=Log,
+ modes:=ModOpts}}} =
+ logger_olp:info(h_proc_name()),
+ {ok,#{config := #{type:=file,
+ file:=Log,
+ modes:=ModOpts}}} =
+ logger:get_handler_config(?MODULE),
+ logger:notice(M1=?msg,?domain),
+ ?check(M1),
+ B1 = ?bin(M1),
+ try_read_file(Log, {ok,B1}, filesync_rep_int()),
+ ok.
+file_opts(cleanup, _Config) ->
+ logger:remove_handler(?MODULE).
+
+
+sync(Config) ->
+ Dir = ?config(priv_dir,Config),
+ Log = filename:join(Dir, lists:concat([?FUNCTION_NAME,".log"])),
+ Type = {file,Log},
+ ok = logger:add_handler(?MODULE,
+ logger_std_h,
+ #{config => #{type => Type,
+ file_check => 10000},
+ filter_default=>log,
+ filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
+ formatter=>{?MODULE,nl}}),
+
+ %% check repeated filesync happens
+ start_tracer([{logger_std_h, write_to_dev, 2},
+ {file, datasync, 1}],
+ [{logger_std_h, write_to_dev, <<"first\n">>},
+ {file,datasync}]),
+
+ logger:notice("first", ?domain),
+ %% wait for automatic filesync
+ check_tracer(filesync_rep_int()*2),
+
+ %% check that explicit filesync is only done once
+ start_tracer([{logger_std_h, write_to_dev, 2},
+ {file, datasync, 1}],
+ [{logger_std_h, write_to_dev, <<"second\n">>},
+ {file,datasync},
+ {no_more,500}
+ ]),
+ logger:notice("second", ?domain),
+ %% do explicit sync
+ logger_std_h:filesync(?MODULE),
+ %% a second sync should be ignored
+ logger_std_h:filesync(?MODULE),
+ check_tracer(100),
+
+ %% check that if there's no repeated filesync active,
+ %% a filesync is still performed when handler goes idle
+ ok = logger:update_handler_config(?MODULE, config,
+ #{filesync_repeat_interval => no_repeat}),
+ no_repeat = maps:get(filesync_repeat_interval,
+ maps:get(cb_state, logger_olp:info(h_proc_name()))),
+ start_tracer([{logger_std_h, write_to_dev, 2},
+ {file, datasync, 1}],
+ [{logger_std_h, write_to_dev, <<"third\n">>},
+ {file,datasync},
+ {logger_std_h, write_to_dev, <<"fourth\n">>},
+ {file,datasync}]),
+ logger:notice("third", ?domain),
+ %% wait for automatic filesync
+ timer:sleep(?IDLE_DETECT_TIME*2),
+ logger:notice("fourth", ?domain),
+ %% wait for automatic filesync
+ check_tracer(?IDLE_DETECT_TIME*2),
+
+ %% switch repeated filesync on and verify that the looping works
+ SyncInt = 1000,
+ WaitT = 4500,
+ OneSync = {logger_h_common,handle_cast,repeated_filesync},
+ %% receive 1 repeated_filesync per sec
+ start_tracer([{{logger_h_common,handle_cast,2},
+ [{[repeated_filesync,'_'],[],[]}]}],
+ [OneSync || _ <- lists:seq(1, trunc(WaitT/SyncInt))]),
+
+ ok = logger:update_handler_config(?MODULE, config,
+ #{filesync_repeat_interval => SyncInt}),
+ SyncInt = maps:get(filesync_repeat_interval,
+ maps:get(cb_state,logger_olp:info(h_proc_name()))),
+ timer:sleep(WaitT),
+ ok = logger:update_handler_config(?MODULE, config,
+ #{filesync_repeat_interval => no_repeat}),
+ check_tracer(100),
+ ok.
+sync(cleanup, _Config) ->
+ dbg:stop_clear(),
+ logger:remove_handler(?MODULE).
+
+write_failure(Config) ->
+ Dir = ?config(priv_dir, Config),
+ File = lists:concat([?MODULE,"_",?FUNCTION_NAME,".log"]),
+ Log = filename:join(Dir, File),
+ Node = start_std_h_on_new_node(Config, Log),
+ false = (undefined == rpc:call(Node, ets, whereis, [?TEST_HOOKS_TAB])),
+ rpc:call(Node, ets, insert, [?TEST_HOOKS_TAB,{tester,self()}]),
+ rpc:call(Node, ?MODULE, set_internal_log, [?MODULE,internal_log]),
+ rpc:call(Node, ?MODULE, set_result, [file_write,ok]),
+
+ ok = log_on_remote_node(Node, "Logged1"),
+ rpc:call(Node, logger_std_h, filesync, [?STANDARD_HANDLER]),
+ ?check_no_log,
+ try_read_file(Log, {ok,<<"Logged1\n">>}, filesync_rep_int()),
+
+ rpc:call(Node, ?MODULE, set_result, [file_write,{error,terminated}]),
+ ok = log_on_remote_node(Node, "Cause simple error printout"),
+
+ ?check({error,{?STANDARD_HANDLER,write,Log,{error,terminated}}}),
+
+ ok = log_on_remote_node(Node, "No second error printout"),
+ ?check_no_log,
+
+ rpc:call(Node, ?MODULE, set_result, [file_write,{error,eacces}]),
+ ok = log_on_remote_node(Node, "Cause simple error printout"),
+ ?check({error,{?STANDARD_HANDLER,write,Log,{error,eacces}}}),
+
+ rpc:call(Node, ?MODULE, set_result, [file_write,ok]),
+ ok = log_on_remote_node(Node, "Logged2"),
+ rpc:call(Node, logger_std_h, filesync, [?STANDARD_HANDLER]),
+ ?check_no_log,
+ try_read_file(Log, {ok,<<"Logged1\nLogged2\n">>}, filesync_rep_int()),
+ ok.
+write_failure(cleanup, _Config) ->
+ Nodes = nodes(),
+ [test_server:stop_node(Node) || Node <- Nodes].
+
+sync_failure(Config) ->
+ Dir = ?config(priv_dir, Config),
+ File = lists:concat([?MODULE,"_",?FUNCTION_NAME,".log"]),
+ Log = filename:join(Dir, File),
+ Node = start_std_h_on_new_node(Config, Log),
+ false = (undefined == rpc:call(Node, ets, whereis, [?TEST_HOOKS_TAB])),
+ rpc:call(Node, ets, insert, [?TEST_HOOKS_TAB,{tester,self()}]),
+ rpc:call(Node, ?MODULE, set_internal_log, [?MODULE,internal_log]),
+ rpc:call(Node, ?MODULE, set_result, [file_datasync,ok]),
+
+ SyncInt = 500,
+ ok = rpc:call(Node, logger, update_handler_config,
+ [?STANDARD_HANDLER, config,
+ #{filesync_repeat_interval => SyncInt}]),
+
+ ok = log_on_remote_node(Node, "Logged1"),
+ ?check_no_log,
+
+ rpc:call(Node, ?MODULE, set_result, [file_datasync,{error,terminated}]),
+ ok = log_on_remote_node(Node, "Cause simple error printout"),
+
+ ?check({error,{?STANDARD_HANDLER,filesync,Log,{error,terminated}}}),
+
+ ok = log_on_remote_node(Node, "No second error printout"),
+ ?check_no_log,
+
+ rpc:call(Node, ?MODULE, set_result, [file_datasync,{error,eacces}]),
+ ok = log_on_remote_node(Node, "Cause simple error printout"),
+ ?check({error,{?STANDARD_HANDLER,filesync,Log,{error,eacces}}}),
+
+ rpc:call(Node, ?MODULE, set_result, [file_datasync,ok]),
+ ok = log_on_remote_node(Node, "Logged2"),
+ ?check_no_log,
+ ok.
+sync_failure(cleanup, _Config) ->
+ Nodes = nodes(),
+ [test_server:stop_node(Node) || Node <- Nodes].
+
+start_std_h_on_new_node(Config, Log) ->
+ {ok,_,Node} =
+ logger_test_lib:setup(
+ Config,
+ [{logger,[{handler,default,logger_std_h,
+ #{ config => #{ type => {file,Log}}}}]}]),
+ ok = rpc:call(Node,logger,set_handler_config,[?STANDARD_HANDLER,formatter,
+ {?MODULE,nl}]),
+ Node.
+
+%% functions for test hook macros to be called by rpc
+set_internal_log(_Mod, _Func) ->
+ ?set_internal_log({_Mod,_Func}).
+set_result(_Op, _Result) ->
+ ?set_result(_Op, _Result).
+set_defaults() ->
+ ?set_defaults().
+
+%% internal log function that sends the term to the test case process
+internal_log(Type, Term) ->
+ [{tester,Tester}] = ets:lookup(?TEST_HOOKS_TAB, tester),
+ Tester ! {log,{Type,Term}},
+ logger:internal_log(Type, Term),
+ ok.
+
+
+%%%-----------------------------------------------------------------
+%%% Overload protection tests
+
+op_switch_to_sync_file(Config) ->
+ {Log,HConfig,StdHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ NumOfReqs = 500,
+ NewHConfig =
+ HConfig#{config => StdHConfig#{sync_mode_qlen => 2,
+ drop_mode_qlen => NumOfReqs+1,
+ flush_qlen => 2*NumOfReqs,
+ burst_limit_enable => false}},
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
+ %% TRecvPid = start_op_trace(),
+ send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
+ Lines = count_lines(Log),
+ %% true = analyse_trace(TRecvPid,
+ %% fun(Events) -> find_mode(async,Events) end),
+ %% true = analyse_trace(TRecvPid,
+ %% fun(Events) -> find_mode(sync,Events) end),
+ %% true = analyse_trace(TRecvPid,
+ %% fun(Events) -> find_switch(async,sync,Events) end),
+ %% false = analyse_trace(TRecvPid,
+ %% fun(Events) -> find_mode(drop,Events) end),
+ %% false = analyse_trace(TRecvPid,
+ %% fun(Events) -> find_mode(flush,Events) end),
+ %% stop_op_trace(TRecvPid),
+ NumOfReqs = Lines,
+ ok = file_delete(Log),
+ ok.
+op_switch_to_sync_file(cleanup, _Config) ->
+ ok = stop_handler(?MODULE).
+
+op_switch_to_sync_tty(Config) ->
+ {HConfig,StdHConfig} = start_handler(?MODULE, standard_io, Config),
+ NumOfReqs = 500,
+ NewHConfig =
+ HConfig#{config => StdHConfig#{sync_mode_qlen => 3,
+ drop_mode_qlen => NumOfReqs+1,
+ flush_qlen => 2*NumOfReqs,
+ burst_limit_enable => false}},
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
+ send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
+ ok.
+op_switch_to_sync_tty(cleanup, _Config) ->
+ ok = stop_handler(?MODULE).
+
+op_switch_to_drop_file() ->
+ [{timetrap,{seconds,180}}].
+op_switch_to_drop_file(Config) ->
+ Test =
+ fun() ->
+ {Log,HConfig,StdHConfig} =
+ start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ NumOfReqs = 300,
+ Procs = 2,
+ Bursts = 10,
+ NewHConfig =
+ HConfig#{config =>
+ StdHConfig#{sync_mode_qlen => 1,
+ drop_mode_qlen => 2,
+ flush_qlen =>
+ Procs*NumOfReqs*Bursts,
+ burst_limit_enable => false}},
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
+ %% It sometimes happens that the handler gets the
+ %% requests in a slow enough pace so that dropping
+ %% never occurs. Therefore, lets generate a number of
+ %% bursts to increase the chance of message buildup.
+ [send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, notice) ||
+ _ <- lists:seq(1, Bursts)],
+ Logged = count_lines(Log),
+ ok = stop_handler(?MODULE),
+ ct:pal("Number of messages dropped = ~w (~w)",
+ [Procs*NumOfReqs*Bursts-Logged,Procs*NumOfReqs*Bursts]),
+ true = (Logged < (Procs*NumOfReqs*Bursts)),
+ true = (Logged > 0),
+ _ = file_delete(Log),
+ ok
+ end,
+ %% As it's tricky to get the timing right in only one go, we perform the
+ %% test repeatedly, hoping that will generate a successful result.
+ case repeat_until_ok(Test, 10) of
+ {ok,{Failures,_Result}} ->
+ ct:log("Failed ~w times before success!", [Failures]);
+ {fails,Reason} ->
+ ct:fail(Reason)
+ end.
+op_switch_to_drop_file(cleanup, _Config) ->
+ _ = stop_handler(?MODULE).
+
+op_switch_to_drop_tty(Config) ->
+ {HConfig,StdHConfig} = start_handler(?MODULE, standard_io, Config),
+ NumOfReqs = 300,
+ Procs = 2,
+ NewHConfig =
+ HConfig#{config => StdHConfig#{sync_mode_qlen => 1,
+ drop_mode_qlen => 2,
+ flush_qlen =>
+ Procs*NumOfReqs+1,
+ burst_limit_enable => false}},
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
+ send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, notice),
+ ok.
+op_switch_to_drop_tty(cleanup, _Config) ->
+ ok = stop_handler(?MODULE).
+
+op_switch_to_flush_file() ->
+ [{timetrap,{minutes,5}}].
+op_switch_to_flush_file(Config) ->
+ Test =
+ fun() ->
+ {Log,HConfig,StdHConfig} =
+ start_handler(?MODULE, ?FUNCTION_NAME, Config),
+
+ %% NOTE: it's important that both async and sync
+ %% requests have been queued when the flush happens
+ %% (verify with coverage of flush_log_requests/2)
+
+ NewHConfig =
+ HConfig#{config =>
+ StdHConfig#{sync_mode_qlen => 2,
+ %% disable drop mode
+ drop_mode_qlen => 300,
+ flush_qlen => 300,
+ burst_limit_enable => false}},
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
+ NumOfReqs = 1500,
+ Procs = 10,
+ Bursts = 10,
+ %% It sometimes happens that the handler either gets
+ %% the requests in a slow enough pace so that flushing
+ %% never occurs, or it gets all messages at once,
+ %% causing all messages to get flushed (no dropping of
+ %% sync messages gets tested). Therefore, lets
+ %% generate a number of bursts to increase the chance
+ %% of message buildup in some random fashion.
+ [send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, notice) ||
+ _ <- lists:seq(1,Bursts)],
+ Logged = count_lines(Log),
+ ok = stop_handler(?MODULE),
+ ct:pal("Number of messages flushed/dropped = ~w (~w)",
+ [NumOfReqs*Procs*Bursts-Logged,NumOfReqs*Procs*Bursts]),
+ true = (Logged < (NumOfReqs*Procs*Bursts)),
+ true = (Logged > 0),
+ _ = file_delete(Log),
+ ok
+ end,
+ %% As it's tricky to get the timing right in only one go, we perform the
+ %% test repeatedly, hoping that will generate a successful result.
+ case repeat_until_ok(Test, 10) of
+ {ok,{Failures,_Result}} ->
+ ct:log("Failed ~w times before success!", [Failures]);
+ {fails,Reason} ->
+ ct:fail(Reason)
+ end.
+op_switch_to_flush_file(cleanup, _Config) ->
+ _ = stop_handler(?MODULE).
+
+op_switch_to_flush_tty() ->
+ [{timetrap,{minutes,5}}].
+op_switch_to_flush_tty(Config) ->
+ {HConfig,StdHConfig} = start_handler(?MODULE, standard_io, Config),
+
+ %% it's important that both async and sync requests have been queued
+ %% when the flush happens (verify with coverage of flush_log_requests/2)
+
+ NewHConfig =
+ HConfig#{config => StdHConfig#{sync_mode_qlen => 2,
+ %% disable drop mode
+ drop_mode_qlen => 100,
+ flush_qlen => 100,
+ burst_limit_enable => false}},
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
+ NumOfReqs = 1000,
+ Procs = 100,
+ send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, notice),
+ ok.
+op_switch_to_flush_tty(cleanup, _Config) ->
+ ok = stop_handler(?MODULE).
+
+limit_burst_disabled(Config) ->
+ {Log,HConfig,StdHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ NewHConfig =
+ HConfig#{config => StdHConfig#{burst_limit_enable => false,
+ burst_limit_max_count => 10,
+ burst_limit_window_time => 2000,
+ drop_mode_qlen => 200,
+ flush_qlen => 300}},
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
+ NumOfReqs = 100,
+ send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
+ Logged = count_lines(Log),
+ ct:pal("Number of messages logged = ~w", [Logged]),
+ NumOfReqs = Logged,
+ ok = file_delete(Log),
+ ok.
+limit_burst_disabled(cleanup, _Config) ->
+ ok = stop_handler(?MODULE).
+
+limit_burst_enabled_one(Config) ->
+ {Log,HConfig,StdHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ ReqLimit = 10,
+ NewHConfig =
+ HConfig#{config => StdHConfig#{burst_limit_enable => true,
+ burst_limit_max_count => ReqLimit,
+ burst_limit_window_time => 2000,
+ drop_mode_qlen => 200,
+ flush_qlen => 300}},
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
+ NumOfReqs = 100,
+ send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
+ Logged = count_lines(Log),
+ ct:pal("Number of messages logged = ~w", [Logged]),
+ ReqLimit = Logged,
+ ok = file_delete(Log),
+ ok.
+limit_burst_enabled_one(cleanup, _Config) ->
+ ok = stop_handler(?MODULE).
+
+limit_burst_enabled_period(Config) ->
+ {Log,HConfig,StdHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ ReqLimit = 10,
+ BurstTWin = 1000,
+ NewHConfig =
+ HConfig#{config => StdHConfig#{burst_limit_enable => true,
+ burst_limit_max_count => ReqLimit,
+ burst_limit_window_time => BurstTWin,
+ drop_mode_qlen => 20000,
+ flush_qlen => 20001}},
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
+
+ Windows = 3,
+ Sent = send_burst({t,BurstTWin*Windows}, seq, {chars,79}, notice),
+ Logged = count_lines(Log),
+ ct:pal("Number of messages sent = ~w~nNumber of messages logged = ~w",
+ [Sent,Logged]),
+ true = (Logged > (ReqLimit*Windows)) andalso
+ (Logged < (ReqLimit*(Windows+2))),
+ ok = file_delete(Log),
+ ok.
+limit_burst_enabled_period(cleanup, _Config) ->
+ ok = stop_handler(?MODULE).
+
+kill_disabled(Config) ->
+ {Log,HConfig,StdHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ NewHConfig =
+ HConfig#{config=>StdHConfig#{overload_kill_enable=>false,
+ overload_kill_qlen=>10,
+ overload_kill_mem_size=>100}},
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
+ NumOfReqs = 100,
+ send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
+ Logged = count_lines(Log),
+ ct:pal("Number of messages logged = ~w", [Logged]),
+ ok = file_delete(Log),
+ true = is_pid(whereis(h_proc_name())),
+ ok.
+kill_disabled(cleanup, _Config) ->
+ ok = stop_handler(?MODULE).
+
+qlen_kill_new(Config) ->
+ {Log,HConfig,StdHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ Pid0 = whereis(h_proc_name()),
+ {_,Mem0} = process_info(Pid0, memory),
+ RestartAfter = ?OVERLOAD_KILL_RESTART_AFTER,
+ NewHConfig =
+ HConfig#{config=>StdHConfig#{overload_kill_enable=>true,
+ overload_kill_qlen=>10,
+ overload_kill_mem_size=>Mem0+50000,
+ overload_kill_restart_after=>RestartAfter}},
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
+ MRef = erlang:monitor(process, Pid0),
+ NumOfReqs = 100,
+ Procs = 4,
+ send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, notice),
+ %% send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
+ receive
+ {'DOWN', MRef, _, _, Info} ->
+ case Info of
+ {shutdown,{overloaded,QLen,Mem}} ->
+ ct:pal("Terminated with qlen = ~w, mem = ~w", [QLen,Mem]);
+ killed ->
+ ct:pal("Slow shutdown, handler process was killed!", [])
+ end,
+ file_delete(Log),
+ {ok,_} = wait_for_process_up(RestartAfter * 3),
+ ok
+ after
+ 5000 ->
+ Info = logger_olp:info(h_proc_name()),
+ ct:pal("Handler state = ~p", [Info]),
+ ct:fail("Handler not dead! It should not have survived this!")
+ end.
+qlen_kill_new(cleanup, _Config) ->
+ ok = stop_handler(?MODULE).
+
+%% choke the standard handler on remote node to verify the termination
+%% works as expected
+qlen_kill_std(_Config) ->
+ %%! HERE
+ %% Dir = ?config(priv_dir, Config),
+ %% File = lists:concat([?MODULE,"_",?FUNCTION_NAME,".log"]),
+ %% Log = filename:join(Dir, File),
+ %% Node = start_std_h_on_new_node(Config, ?FUNCTION_NAME, Log),
+ %% ok = rpc:call(Node, logger, update_handler_config,
+ %% [?STANDARD_HANDLER, config,
+ %% #{overload_kill_enable=>true,
+ %% overload_kill_qlen=>10,
+ %% overload_kill_mem_size=>100000}]),
+ {skip,"Not done yet"}.
+
+mem_kill_new(Config) ->
+ {Log,HConfig,StdHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ Pid0 = whereis(h_proc_name()),
+ {_,Mem0} = process_info(Pid0, memory),
+ RestartAfter = ?OVERLOAD_KILL_RESTART_AFTER,
+ NewHConfig =
+ HConfig#{config=>StdHConfig#{overload_kill_enable=>true,
+ overload_kill_qlen=>50000,
+ overload_kill_mem_size=>Mem0+500,
+ overload_kill_restart_after=>RestartAfter}},
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
+ MRef = erlang:monitor(process, Pid0),
+ NumOfReqs = 100,
+ Procs = 4,
+ send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, notice),
+ %% send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
+ receive
+ {'DOWN', MRef, _, _, Info} ->
+ case Info of
+ {shutdown,{overloaded,QLen,Mem}} ->
+ ct:pal("Terminated with qlen = ~w, mem = ~w", [QLen,Mem]);
+ killed ->
+ ct:pal("Slow shutdown, handler process was killed!", [])
+ end,
+ file_delete(Log),
+ {ok,_} = wait_for_process_up(RestartAfter * 3),
+ ok
+ after
+ 5000 ->
+ Info = logger_olp:info(h_proc_name()),
+ ct:pal("Handler state = ~p", [Info]),
+ ct:fail("Handler not dead! It should not have survived this!")
+ end.
+mem_kill_new(cleanup, _Config) ->
+ ok = stop_handler(?MODULE).
+
+%% choke the standard handler on remote node to verify the termination
+%% works as expected
+mem_kill_std(_Config) ->
+ {skip,"Not done yet"}.
+
+restart_after() ->
+ [{timetrap,{minutes,2}}].
+restart_after(Config) ->
+ {Log,HConfig,StdHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ NewHConfig1 =
+ HConfig#{config=>StdHConfig#{overload_kill_enable=>true,
+ overload_kill_qlen=>10,
+ overload_kill_restart_after=>infinity}},
+ ok = logger:update_handler_config(?MODULE, NewHConfig1),
+ MRef1 = erlang:monitor(process, whereis(h_proc_name())),
+ %% kill handler
+ send_burst({n,100}, {spawn,4,0}, {chars,79}, notice),
+ receive
+ {'DOWN', MRef1, _, _, _Reason1} ->
+ file_delete(Log),
+ error = wait_for_process_up(?OVERLOAD_KILL_RESTART_AFTER * 3),
+ ok
+ after
+ 5000 ->
+ Info1 = logger_olp:info(h_proc_name()),
+ ct:pal("Handler state = ~p", [Info1]),
+ ct:fail("Handler not dead! It should not have survived this!")
+ end,
+
+ {Log,_,_} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ RestartAfter = ?OVERLOAD_KILL_RESTART_AFTER,
+
+ NewHConfig2 =
+ HConfig#{config=>StdHConfig#{overload_kill_enable=>true,
+ overload_kill_qlen=>10,
+ overload_kill_restart_after=>RestartAfter}},
+ ok = logger:update_handler_config(?MODULE, NewHConfig2),
+ Pid0 = whereis(h_proc_name()),
+ MRef2 = erlang:monitor(process, Pid0),
+ %% kill handler
+ send_burst({n,100}, {spawn,4,0}, {chars,79}, notice),
+ receive
+ {'DOWN', MRef2, _, _, _Reason2} ->
+ file_delete(Log),
+ {ok,Pid1} = wait_for_process_up(RestartAfter * 3),
+ false = (Pid1 == Pid0),
+ ok
+ after
+ 5000 ->
+ Info2 = logger_olp:info(h_proc_name()),
+ ct:pal("Handler state = ~p", [Info2]),
+ ct:fail("Handler not dead! It should not have survived this!")
+ end,
+ ok.
+restart_after(cleanup, _Config) ->
+ ok = stop_handler(?MODULE).
+
+%% send handler requests (sync, info, reset, change_config)
+%% during high load to verify that sync, dropping and flushing is
+%% handled correctly.
+handler_requests_under_load() ->
+ [{timetrap,{minutes,3}}].
+handler_requests_under_load(Config) ->
+ {Log,HConfig,StdHConfig} =
+ start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ NewHConfig =
+ HConfig#{config => StdHConfig#{sync_mode_qlen => 2,
+ drop_mode_qlen => 1000,
+ flush_qlen => 2000,
+ burst_limit_enable => false}},
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
+ Pid = spawn_link(
+ fun() -> send_requests(1,[{logger_std_h,filesync,[?MODULE],[]},
+ {logger_olp,info,[h_proc_name()],[]},
+ {logger_olp,reset,[h_proc_name()],[]},
+ {logger,update_handler_config,
+ [?MODULE, config,
+ #{overload_kill_enable => false}],
+ []}])
+ end),
+ Sent = send_burst({t,10000}, seq, {chars,79}, notice),
+ Pid ! {self(),finish},
+ ReqResult = receive {Pid,Result} -> Result end,
+ Logged = count_lines(Log),
+ ct:pal("Number of messages sent = ~w~nNumber of messages logged = ~w",
+ [Sent,Logged]),
+ FindError = fun(Res) ->
+ [E || E <- Res,
+ is_tuple(E) andalso (element(1,E) == error)]
+ end,
+ Errors = [{Func,FindError(Res)} || {_,Func,_,Res} <- ReqResult],
+ NoOfReqs = lists:foldl(fun({_,_,_,Res}, N) -> N + length(Res) end,
+ 0, ReqResult),
+ ct:pal("~w requests made. Errors: ~n~p", [NoOfReqs,Errors]),
+ ok = file_delete(Log).
+handler_requests_under_load(cleanup, _Config) ->
+ ok = stop_handler(?MODULE).
+
+recreate_deleted_log(Config) ->
+ {Log,_HConfig,_StdHConfig} =
+ start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ logger:notice("first",?domain),
+ logger_std_h:filesync(?MODULE),
+ ok = file:rename(Log,Log++".old"),
+ logger:notice("second",?domain),
+ logger_std_h:filesync(?MODULE),
+ {ok,<<"first\n">>} = file:read_file(Log++".old"),
+ {ok,<<"second\n">>} = file:read_file(Log),
+ ok.
+recreate_deleted_log(cleanup, _Config) ->
+ ok = stop_handler(?MODULE).
+
+reopen_changed_log(Config) ->
+ {Log,_HConfig,_StdHConfig} =
+ start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ logger:notice("first",?domain),
+ logger_std_h:filesync(?MODULE),
+ ok = file:rename(Log,Log++".old"),
+ ok = file:write_file(Log,""),
+ logger:notice("second",?domain),
+ logger_std_h:filesync(?MODULE),
+ {ok,<<"first\n">>} = file:read_file(Log++".old"),
+ {ok,<<"second\n">>} = file:read_file(Log),
+ ok.
+reopen_changed_log(cleanup, _Config) ->
+ ok = stop_handler(?MODULE).
+
+rotate_size(Config) ->
+ {Log,_HConfig,_StdHConfig} =
+ start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ ok = logger:update_handler_config(?MODULE,#{config=>#{max_no_bytes=>1000,
+ max_no_files=>2}}),
+
+ Str = lists:duplicate(19,$a),
+ [logger:notice(Str,?domain) || _ <- lists:seq(1,50)],
+ logger_std_h:filesync(?MODULE),
+ {ok,#file_info{size=1000}} = file:read_file_info(Log),
+ {error,enoent} = file:read_file_info(Log++".0"),
+
+ logger:notice(Str,?domain),
+ logger_std_h:filesync(?MODULE),
+ {ok,#file_info{size=0}} = file:read_file_info(Log),
+ {ok,#file_info{size=1020}} = file:read_file_info(Log++".0"),
+ {error,enoent} = file:read_file_info(Log++".1"),
+
+ [logger:notice(Str,?domain) || _ <- lists:seq(1,51)],
+ logger_std_h:filesync(?MODULE),
+ {ok,#file_info{size=0}} = file:read_file_info(Log),
+ {ok,#file_info{size=1020}} = file:read_file_info(Log++".0"),
+ {ok,#file_info{size=1020}} = file:read_file_info(Log++".1"),
+ {error,enoent} = file:read_file_info(Log++".2"),
+
+ [logger:notice(Str,?domain) || _ <- lists:seq(1,50)],
+ logger_std_h:filesync(?MODULE),
+ {ok,#file_info{size=1000}} = file:read_file_info(Log),
+ {ok,#file_info{size=1020}} = file:read_file_info(Log++".0"),
+ {ok,#file_info{size=1020}} = file:read_file_info(Log++".1"),
+ {error,enoent} = file:read_file_info(Log++".2"),
+
+ logger:notice("bbbb",?domain),
+ logger_std_h:filesync(?MODULE),
+ {ok,#file_info{size=0}} = file:read_file_info(Log),
+ {ok,#file_info{size=1005}} = file:read_file_info(Log++".0"),
+ {ok,#file_info{size=1020}} = file:read_file_info(Log++".1"),
+ {error,enoent} = file:read_file_info(Log++".2"),
+
+ ok.
+rotate_size(cleanup,_Config) ->
+ ok = stop_handler(?MODULE).
+
+rotate_size_compressed(Config) ->
+ {Log,_HConfig,_StdHConfig} =
+ start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ ok = logger:update_handler_config(?MODULE,
+ #{config=>#{max_no_bytes=>1000,
+ max_no_files=>2,
+ compress_on_rotate=>true}}),
+ Str = lists:duplicate(19,$a),
+ [logger:notice(Str,?domain) || _ <- lists:seq(1,50)],
+ logger_std_h:filesync(?MODULE),
+ {ok,#file_info{size=1000}} = file:read_file_info(Log),
+ {error,enoent} = file:read_file_info(Log++".0"),
+ {error,enoent} = file:read_file_info(Log++".0.gz"),
+
+ logger:notice(Str,?domain),
+ logger_std_h:filesync(?MODULE),
+ {ok,#file_info{size=0}} = file:read_file_info(Log),
+ {error,enoent} = file:read_file_info(Log++".0"),
+ {ok,#file_info{size=35}} = file:read_file_info(Log++".0.gz"),
+ {error,enoent} = file:read_file_info(Log++".1"),
+ {error,enoent} = file:read_file_info(Log++".1.gz"),
+
+ [logger:notice(Str,?domain) || _ <- lists:seq(1,51)],
+ logger_std_h:filesync(?MODULE),
+ {ok,#file_info{size=0}} = file:read_file_info(Log),
+ {error,enoent} = file:read_file_info(Log++".0"),
+ {ok,#file_info{size=35}} = file:read_file_info(Log++".0.gz"),
+ {error,enoent} = file:read_file_info(Log++".1"),
+ {ok,#file_info{size=35}} = file:read_file_info(Log++".1.gz"),
+ {error,enoent} = file:read_file_info(Log++".2"),
+ {error,enoent} = file:read_file_info(Log++".2.gz"),
+
+ [logger:notice(Str,?domain) || _ <- lists:seq(1,50)],
+ logger_std_h:filesync(?MODULE),
+ {ok,#file_info{size=1000}} = file:read_file_info(Log),
+ {error,enoent} = file:read_file_info(Log++".0"),
+ {ok,#file_info{size=35}} = file:read_file_info(Log++".0.gz"),
+ {error,enoent} = file:read_file_info(Log++".1"),
+ {ok,#file_info{size=35}} = file:read_file_info(Log++".1.gz"),
+ {error,enoent} = file:read_file_info(Log++".2"),
+ {error,enoent} = file:read_file_info(Log++".2.gz"),
+
+ logger:notice("bbbb",?domain),
+ logger_std_h:filesync(?MODULE),
+ {ok,#file_info{size=0}} = file:read_file_info(Log),
+ {error,enoent} = file:read_file_info(Log++".0"),
+ {ok,#file_info{size=38}} = file:read_file_info(Log++".0.gz"),
+ {error,enoent} = file:read_file_info(Log++".1"),
+ {ok,#file_info{size=35}} = file:read_file_info(Log++".1.gz"),
+ {error,enoent} = file:read_file_info(Log++".2"),
+ {error,enoent} = file:read_file_info(Log++".2.gz"),
+
+ ok.
+rotate_size_compressed(cleanup,_Config) ->
+ ok = stop_handler(?MODULE).
+
+rotate_size_reopen(Config) ->
+ {Log,_HConfig,_StdHConfig} =
+ start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ ok = logger:update_handler_config(?MODULE,#{config=>#{max_no_bytes=>1000,
+ max_no_files=>2}}),
+
+ Str = lists:duplicate(19,$a),
+ [logger:notice(Str,?domain) || _ <- lists:seq(1,40)],
+ logger_std_h:filesync(?MODULE),
+ {ok,#file_info{size=800}} = file:read_file_info(Log),
+
+ {ok,HConfig} = logger:get_handler_config(?MODULE),
+ ok = logger:remove_handler(?MODULE),
+ ok = logger:add_handler(?MODULE,maps:get(module,HConfig),HConfig),
+ {ok,#file_info{size=800}} = file:read_file_info(Log),
+
+ [logger:notice(Str,?domain) || _ <- lists:seq(1,40)],
+ logger_std_h:filesync(?MODULE),
+ {ok,#file_info{size=580}} = file:read_file_info(Log),
+ {ok,#file_info{size=1020}} = file:read_file_info(Log++".0"),
+ ok.
+rotate_size_reopen(cleanup,_Config) ->
+ ok = stop_handler(?MODULE).
+
+rotation_opts(Config) ->
+ {Log,_HConfig,StdHConfig} =
+ start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ #{max_no_bytes:=infinity,
+ max_no_files:=0,
+ compress_on_rotate:=false} = StdHConfig,
+
+ %% Test bad rotation config
+ {error,{invalid_config,_,_}} =
+ logger:update_handler_config(?MODULE,config,#{max_no_bytes=>0}),
+ {error,{invalid_config,_,_}} =
+ logger:update_handler_config(?MODULE,config,#{max_no_files=>infinity}),
+ {error,{invalid_config,_,_}} =
+ logger:update_handler_config(?MODULE,config,
+ #{compress_on_rotate=>undefined}),
+
+
+ %% Test good rotation config - start with no rotation
+ Str = lists:duplicate(19,$a),
+ [logger:notice(Str,?domain) || _ <- lists:seq(1,10)],
+ logger_std_h:filesync(?MODULE),
+ {ok,#file_info{size=200}} = file:read_file_info(Log),
+ [] = filelib:wildcard(Log++".*"),
+
+ %% Turn on rotation, check that existing file is rotated since its
+ %% size exceeds max_no_bytes
+ ok = logger:update_handler_config(?MODULE,
+ config,
+ #{max_no_bytes=>100,
+ max_no_files=>2}),
+ timer:sleep(100), % give some time to execute config_changed
+ {ok,#file_info{size=0}} = file:read_file_info(Log),
+ Log0 = Log++".0",
+ {ok,#file_info{size=200}} = file:read_file_info(Log0),
+ [Log0] = filelib:wildcard(Log++".*"),
+
+ %% Fill all logs
+ [logger:notice(Str,?domain) || _ <- lists:seq(1,13)],
+ logger_std_h:filesync(?MODULE),
+ {ok,#file_info{size=20}} = file:read_file_info(Log),
+ {ok,#file_info{size=120}} = file:read_file_info(Log0),
+ {ok,#file_info{size=120}} = file:read_file_info(Log++".1"),
+ [_,_] = filelib:wildcard(Log++".*"),
+
+ %% Extend size and count and check that nothing changes with existing files
+ ok = logger:update_handler_config(?MODULE,
+ config,
+ #{max_no_bytes=>200,
+ max_no_files=>3}),
+ timer:sleep(100), % give some time to execute config_changed
+ {ok,#file_info{size=20}} = file:read_file_info(Log),
+ {ok,#file_info{size=120}} = file:read_file_info(Log0),
+ {ok,#file_info{size=120}} = file:read_file_info(Log++".1"),
+ [_,_] = filelib:wildcard(Log++".*"),
+
+ %% Add more log events and see that extended size and count works
+ [logger:notice(Str,?domain) || _ <- lists:seq(1,10)],
+ logger_std_h:filesync(?MODULE),
+ {ok,#file_info{size=0}} = file:read_file_info(Log),
+ {ok,#file_info{size=220}} = file:read_file_info(Log0),
+ {ok,#file_info{size=120}} = file:read_file_info(Log++".1"),
+ {ok,#file_info{size=120}} = file:read_file_info(Log++".2"),
+ [_,_,_] = filelib:wildcard(Log++".*"),
+
+ %% Reduce count and check that archive files that exceed the new
+ %% count are moved
+ ok = logger:update_handler_config(?MODULE,
+ config,
+ #{max_no_files=>1}),
+ timer:sleep(100), % give some time to execute config_changed
+ {ok,#file_info{size=0}} = file:read_file_info(Log),
+ {ok,#file_info{size=220}} = file:read_file_info(Log0),
+ [Log0] = filelib:wildcard(Log++".*"),
+
+ %% Extend size and count again, and turn on compression. Check
+ %% that archives are compressed
+ ok = logger:update_handler_config(?MODULE,
+ config,
+ #{max_no_bytes=>100,
+ max_no_files=>2,
+ compress_on_rotate=>true}),
+ timer:sleep(100), % give some time to execute config_changed
+ {ok,#file_info{size=0}} = file:read_file_info(Log),
+ Log0gz = Log0++".gz",
+ {ok,#file_info{size=29}} = file:read_file_info(Log0gz),
+ [Log0gz] = filelib:wildcard(Log++".*"),
+
+ %% Fill all logs
+ [logger:notice(Str,?domain) || _ <- lists:seq(1,13)],
+ logger_std_h:filesync(?MODULE),
+ {ok,#file_info{size=20}} = file:read_file_info(Log),
+ {ok,#file_info{size=29}} = file:read_file_info(Log0gz),
+ {ok,#file_info{size=29}} = file:read_file_info(Log++".1.gz"),
+ [_,_] = filelib:wildcard(Log++".*"),
+
+ %% Reduce count and turn off compression. Check that archives that
+ %% exceeds the new count are removed, and the rest are
+ %% uncompressed.
+ ok = logger:update_handler_config(?MODULE,
+ config,
+ #{max_no_files=>1,
+ compress_on_rotate=>false}),
+ timer:sleep(100), % give some time to execute config_changed
+ {ok,#file_info{size=20}} = file:read_file_info(Log),
+ {ok,#file_info{size=120}} = file:read_file_info(Log0),
+ [Log0] = filelib:wildcard(Log++".*"),
+
+ %% Check that config and handler state agree on the current rotation settings
+ {ok,#{config:=#{max_no_bytes:=100,
+ max_no_files:=1,
+ compress_on_rotate:=false}}} =
+ logger:get_handler_config(?MODULE),
+ #{cb_state:=#{handler_state:=#{max_no_bytes:=100,
+ max_no_files:=1,
+ compress_on_rotate:=false}}} =
+ logger_olp:info(h_proc_name()),
+ ok.
+rotation_opts(cleanup,_Config) ->
+ ok = stop_handler(?MODULE).
+
+rotation_opts_restart_handler(Config) ->
+ {Log,_HConfig,_StdHConfig} =
+ start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ ok = logger:update_handler_config(?MODULE,
+ config,
+ #{max_no_bytes=>100,
+ max_no_files=>2}),
+
+ %% Fill all logs
+ Str = lists:duplicate(19,$a),
+ [logger:notice(Str,?domain) || _ <- lists:seq(1,15)],
+ logger_std_h:filesync(?MODULE),
+ {ok,#file_info{size=60}} = file:read_file_info(Log),
+ {ok,#file_info{size=120}} = file:read_file_info(Log++".0"),
+ {ok,#file_info{size=120}} = file:read_file_info(Log++".1"),
+ [_,_] = filelib:wildcard(Log++".*"),
+
+ %% Stop/start handler and turn off rotation. Check that archives are removed.
+ {ok,#{config:=StdHConfig1}=HConfig1} = logger:get_handler_config(?MODULE),
+ ok = logger:remove_handler(?MODULE),
+ ok = logger:add_handler(
+ ?MODULE,logger_std_h,
+ HConfig1#{config=>StdHConfig1#{max_no_bytes=>infinity}}),
+ timer:sleep(100),
+ {ok,#file_info{size=60}} = file:read_file_info(Log),
+ [] = filelib:wildcard(Log++".*"),
+
+ %% Add some log events and check that file is no longer rotated.
+ [logger:notice(Str,?domain) || _ <- lists:seq(1,10)],
+ logger_std_h:filesync(?MODULE),
+ {ok,#file_info{size=260}} = file:read_file_info(Log),
+ [] = filelib:wildcard(Log++".*"),
+
+ %% Stop/start handler and trun on rotation. Check that file is rotated.
+ {ok,#{config:=StdHConfig2}=HConfig2} = logger:get_handler_config(?MODULE),
+ ok = logger:remove_handler(?MODULE),
+ ok = logger:add_handler(
+ ?MODULE,logger_std_h,
+ HConfig2#{config=>StdHConfig2#{max_no_bytes=>100,
+ max_no_files=>2}}),
+ timer:sleep(100),
+ {ok,#file_info{size=0}} = file:read_file_info(Log),
+ {ok,#file_info{size=260}} = file:read_file_info(Log++".0"),
+ [_] = filelib:wildcard(Log++".*"),
+
+ %% Fill all logs
+ [logger:notice(Str,?domain) || _ <- lists:seq(1,10)],
+ logger_std_h:filesync(?MODULE),
+ {ok,#file_info{size=80}} = file:read_file_info(Log),
+ {ok,#file_info{size=120}} = file:read_file_info(Log++".0"),
+ {ok,#file_info{size=260}} = file:read_file_info(Log++".1"),
+
+ %% Stop/start handler, reduce count and turn on compression. Check
+ %% that excess archives are removed, and the rest compressed.
+ {ok,#{config:=StdHConfig3}=HConfig3} = logger:get_handler_config(?MODULE),
+ ok = logger:remove_handler(?MODULE),
+ ok = logger:add_handler(
+ ?MODULE,logger_std_h,
+ HConfig3#{config=>StdHConfig3#{max_no_bytes=>75,
+ max_no_files=>1,
+ compress_on_rotate=>true}}),
+ timer:sleep(100),
+ {ok,#file_info{size=0}} = file:read_file_info(Log),
+ {ok,#file_info{size=29}} = file:read_file_info(Log++".0.gz"),
+ [_] = filelib:wildcard(Log++".*"),
+
+ %% Stop/start handler and turn off compression. Check that achives
+ %% are decompressed.
+ {ok,#{config:=StdHConfig4}=HConfig4} = logger:get_handler_config(?MODULE),
+ ok = logger:remove_handler(?MODULE),
+ ok = logger:add_handler(
+ ?MODULE,logger_std_h,
+ HConfig4#{config=>StdHConfig4#{compress_on_rotate=>false}}),
+ timer:sleep(100),
+ {ok,#file_info{size=0}} = file:read_file_info(Log),
+ {ok,#file_info{size=80}} = file:read_file_info(Log++".0"),
+ [_] = filelib:wildcard(Log++".*"),
+
+ ok.
+rotation_opts_restart_handler(cleanup,_Config) ->
+ ok = stop_handler(?MODULE).
+
+%%%-----------------------------------------------------------------
+%%%
+send_requests(TO, Reqs = [{Mod,Func,Args,Res}|Rs]) ->
+ receive
+ {From,finish} ->
+ From ! {self(),Reqs}
+ after
+ TO ->
+ Result = apply(Mod,Func,Args),
+ send_requests(TO, Rs ++ [{Mod,Func,Args,[Result|Res]}])
+ end.
+
+
+%%%-----------------------------------------------------------------
+%%%
+start_handler(Name, TTY, _Config) when TTY == standard_io;
+ TTY == standard_error->
+ ok = logger:add_handler(Name,
+ logger_std_h,
+ #{config => #{type => TTY},
+ filter_default=>stop,
+ filters=>filter_only_this_domain(Name),
+ formatter=>{?MODULE,op}}),
+ {ok,HConfig = #{config := StdHConfig}} = logger:get_handler_config(Name),
+ {HConfig,StdHConfig};
+
+start_handler(Name, FuncName, Config) ->
+ Dir = ?config(priv_dir,Config),
+ Log = filename:join(Dir, lists:concat([FuncName,".log"])),
+ ct:pal("Logging to ~tp", [Log]),
+ Type = {file,Log},
+ _ = file_delete(Log),
+ ok = logger:add_handler(Name,
+ logger_std_h,
+ #{config => #{type => Type},
+ filter_default=>stop,
+ filters=>filter_only_this_domain(Name),
+ formatter=>{?MODULE,op}}),
+ {ok,HConfig = #{config := StdHConfig}} = logger:get_handler_config(Name),
+ {Log,HConfig,StdHConfig}.
+
+filter_only_this_domain(Name) ->
+ [{remote_gl,{fun logger_filters:remote_gl/2,stop}},
+ {domain,{fun logger_filters:domain/2,{log,super,[Name]}}}].
+
+
+stop_handler(Name) ->
+ R = logger:remove_handler(Name),
+ ct:pal("Handler ~p stopped! Result: ~p", [Name,R]),
+ R.
+
+count_lines(File) ->
+ wait_until_written(File, -1),
+ count_lines1(File).
+
+wait_until_written(File, Sz) ->
+ timer:sleep(2000),
+ case file:read_file_info(File) of
+ {ok,#file_info{size = Sz}} ->
+ timer:sleep(1000),
+ case file:read_file_info(File) of
+ {ok,#file_info{size = Sz}} ->
+ ok;
+ {ok,#file_info{size = Sz1}} ->
+ wait_until_written(File, Sz1)
+ end;
+ {ok,#file_info{size = Sz1}} ->
+ wait_until_written(File, Sz1)
+ end.
+
+count_lines1(File) ->
+ {_,Dev} = file:open(File, [read]),
+ Lines = count_lines2(Dev, 0),
+ file:close(Dev),
+ Lines.
+
+count_lines2(Dev, LC) ->
+ case file:read_line(Dev) of
+ {ok,"Handler logger_std_h_SUITE " ++_} ->
+ %% Not counting handler info
+ count_lines2(Dev,LC);
+ {ok,_} ->
+ count_lines2(Dev,LC+1);
+ eof -> LC
+ end.
+
+send_burst(NorT, Type, {chars,Sz}, Class) ->
+ Text = [34 + rand:uniform(126-34) || _ <- lists:seq(1,Sz)],
+ case NorT of
+ {n,N} ->
+ %% process_flag(priority, high),
+ send_n_burst(N, Type, Text, Class),
+ %% process_flag(priority, normal),
+ N;
+ {t,T} ->
+ ct:pal("Sending messages sequentially for ~w ms", [T]),
+ T0 = erlang:monotonic_time(millisecond),
+ send_t_burst(T0, T, Text, Class, 0)
+ end.
+
+send_n_burst(0, _, _Text, _Class) ->
+ ok;
+send_n_burst(N, seq, Text, Class) ->
+ ok = logger:Class(Text, ?domain),
+ send_n_burst(N-1, seq, Text, Class);
+send_n_burst(N, {spawn,Ps,TO}, Text, Class) ->
+ ct:pal("~w processes each sending ~w messages", [Ps,N]),
+ MRefs = [begin if TO == 0 -> ok; true -> timer:sleep(TO) end,
+ monitor(process,spawn_link(per_proc_fun(N,Text,Class,X)))
+ end || X <- lists:seq(1,Ps)],
+ lists:foreach(fun(MRef) ->
+ receive
+ {'DOWN', MRef, _, _, _} ->
+ ok
+ end
+ end, MRefs),
+ ct:pal("Message burst sent", []),
+ ok.
+
+send_t_burst(T0, T, Text, Class, N) ->
+ T1 = erlang:monotonic_time(millisecond),
+ if (T1-T0) > T ->
+ N;
+ true ->
+ ok = logger:Class(Text, ?domain),
+ send_t_burst(T0, T, Text, Class, N+1)
+ end.
+
+per_proc_fun(N,Text,Class,X) when X rem 2 == 0 ->
+ fun() ->
+ process_flag(priority,high),
+ send_n_burst(N, seq, Text, Class)
+ end;
+per_proc_fun(N,Text,Class,_) ->
+ fun() ->
+ send_n_burst(N, seq, Text, Class)
+ end.
+
+%%%-----------------------------------------------------------------
+%%% Formatter callback
+%%% Using this to send the formatted string back to the test case
+%%% process - so it can check for logged events.
+format(_,bad_return) ->
+ bad_return;
+format(_,crash) ->
+ erlang:error(formatter_crashed);
+format(#{msg:={string,String0}},no_nl) ->
+ String = unicode:characters_to_list(String0),
+ String;
+format(#{msg:={string,String0}},nl) ->
+ String = unicode:characters_to_list(String0),
+ String++"\n";
+format(#{msg:={string,String0}},op) ->
+ String = unicode:characters_to_list(String0),
+ String++"\n";
+format(#{msg:={report,#{label:={supervisor,progress}}}},op) ->
+ "";
+format(#{msg:={report,#{label:={gen_server,terminate}}}},op) ->
+ "";
+format(#{msg:={report,#{label:={proc_lib,crash}}}},op) ->
+ "";
+format(#{msg:={F,A}},OpOrPid) when is_list(F), is_list(A) ->
+ String = lists:flatten(io_lib:format(F,A)),
+ if is_pid(OpOrPid) -> OpOrPid ! {log,String};
+ true -> ok
+ end,
+ String++"\n";
+format(#{msg:={string,String0}},Pid) ->
+ String = unicode:characters_to_list(String0),
+ Pid ! {log,String},
+ String++"\n".
+
+add_remove_instance_nofile(Type) ->
+ ok = logger:add_handler(?MODULE,logger_std_h,
+ #{config => #{type => Type},
+ filter_default=>stop,
+ filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
+ formatter=>{?MODULE,self()}}),
+ Pid = whereis(h_proc_name()),
+ true = is_pid(Pid),
+ group_leader(group_leader(),Pid), % to get printouts in test log
+ logger:notice(M1=?msg,?domain),
+ ?check(M1),
+ %% check that sync doesn't do damage even if not relevant
+ ok = logger_std_h:filesync(?MODULE),
+ ok = logger:remove_handler(?MODULE),
+ timer:sleep(500),
+ undefined = whereis(h_proc_name()),
+ logger:notice(?msg,?domain),
+ ?check_no_log,
+ ok.
+
+logger_std_h_remove() ->
+ logger:remove_handler(?MODULE).
+logger_std_h_remove(Id) ->
+ logger:remove_handler(Id).
+
+try_read_file(FileName, Expected, Time) when Time > 0 ->
+ case file:read_file(FileName) of
+ Expected ->
+ ok;
+ Error = {error,_Reason} ->
+ ct:pal("Can't read ~tp: ~tp", [FileName,Error]),
+ erlang:error(Error);
+ Got ->
+ ct:pal("try_read_file got ~tp", [Got]),
+ timer:sleep(500),
+ try_read_file(FileName, Expected, Time-500)
+ end;
+try_read_file(FileName, Expected, _) ->
+ ct:pal("Missing pattern ~tp in ~tp", [Expected,FileName]),
+ erlang:error({error,missing_expected_pattern}).
+
+try_match_file(FileName, Pattern, Time) ->
+ try_match_file(FileName, Pattern, Time, <<>>).
+
+try_match_file(FileName, Pattern, Time, _) when Time > 0 ->
+ case file:read_file(FileName) of
+ {ok, Bin} ->
+ case re:run(Bin,Pattern,[{capture,none}]) of
+ match ->
+ unicode:characters_to_list(Bin);
+ _ ->
+ timer:sleep(100),
+ try_match_file(FileName, Pattern, Time-100, Bin)
+ end;
+ Error ->
+ erlang:error(Error)
+ end;
+try_match_file(_,Pattern,_,Incorrect) ->
+ ct:pal("try_match_file did not match pattern: ~p~nGot: ~p~n",
+ [Pattern,Incorrect]),
+ erlang:error({error,not_matching_pattern,Pattern,Incorrect}).
+
+repeat_until_ok(Fun, N) ->
+ repeat_until_ok(Fun, 0, N, undefined).
+
+repeat_until_ok(_Fun, Stop, Stop, Reason) ->
+ {fails,Reason};
+
+repeat_until_ok(Fun, C, Stop, FirstReason) ->
+ if C > 0 -> timer:sleep(5000);
+ true -> ok
+ end,
+ try Fun() of
+ Result ->
+ {ok,{C,Result}}
+ catch
+ _:Reason:Stack ->
+ ct:pal("Test fails: ~p (~p)~n", [Reason,hd(Stack)]),
+ if FirstReason == undefined ->
+ repeat_until_ok(Fun, C+1, Stop, {Reason,Stack});
+ true ->
+ repeat_until_ok(Fun, C+1, Stop, FirstReason)
+ end
+ end.
+
+
+%%%-----------------------------------------------------------------
+%%%
+start_op_trace() ->
+ TraceFun = fun({trace,_,call,{_Mod,Func,Details}}, Pid) ->
+ Pid ! {trace_call,Func,Details},
+ Pid;
+ ({trace,_,return_from,{_Mod,Func,_},RetVal}, Pid) ->
+ Pid ! {trace_return,Func,RetVal},
+ Pid
+ end,
+ TRecvPid = spawn_link(fun() -> trace_receiver(5000) end),
+ {ok,_} = dbg:tracer(process, {TraceFun, TRecvPid}),
+
+ {ok,_} = dbg:p(whereis(h_proc_name()), [c]),
+ {ok,_} = dbg:p(self(), [c]),
+
+ MS1 = dbg:fun2ms(fun([_]) -> return_trace() end),
+ {ok,_} = dbg:tpl(logger_h_common, check_load, 1, MS1),
+
+ {ok,_} = dbg:tpl(logger_h_common, flush_log_requests, 2, []),
+
+ MS2 = dbg:fun2ms(fun([_,mode]) -> return_trace() end),
+ {ok,_} = dbg:tpl(ets, lookup, 2, MS2),
+
+ ct:pal("Tracing started!", []),
+ TRecvPid.
+
+stop_op_trace(TRecvPid) ->
+ dbg:stop_clear(),
+ unlink(TRecvPid),
+ exit(TRecvPid, kill),
+ ok.
+
+find_mode(flush, Events) ->
+ lists:any(fun({trace_call,flush_log_requests,[_,_]}) -> true;
+ (_) -> false
+ end, Events);
+find_mode(Mode, Events) ->
+ lists:keymember([{mode,Mode}], 3, Events).
+
+%% find_switch(_From, To, Events) ->
+%% try lists:foldl(fun({trace_return,check_load,{To,_,_,_}},
+%% {trace_call,check_load,[#{mode := From}]}) ->
+%% throw(match);
+%% (Event, _) ->
+%% Event
+%% end, undefined, Events) of
+%% _ -> false
+%% catch
+%% throw:match -> true
+%% end.
+
+analyse_trace(TRecvPid, TestFun) ->
+ TRecvPid ! {test,self(),TestFun},
+ receive
+ {result,TRecvPid,Result} ->
+ Result
+ after
+ 60000 ->
+ fails
+ end.
+
+trace_receiver(IdleT) ->
+ Msgs = receive_until_idle(IdleT, 5, []),
+ ct:pal("~w trace events generated", [length(Msgs)]),
+ analyse(Msgs).
+
+receive_until_idle(IdleT, WaitN, Msgs) ->
+ receive
+ Msg = {trace_call,_,_} ->
+ receive_until_idle(IdleT, 5, [Msg | Msgs]);
+ Msg = {trace_return,_,_} ->
+ receive_until_idle(IdleT, 5, [Msg | Msgs])
+ after
+ IdleT ->
+ if WaitN == 0 ->
+ Msgs;
+ true ->
+ receive_until_idle(IdleT, WaitN-1, Msgs)
+ end
+ end.
+
+analyse(Msgs) ->
+ receive
+ {test,From,TestFun} ->
+ From ! {result,self(),TestFun(Msgs)},
+ analyse(Msgs)
+ end.
+
+start_tracer(Trace,Expected) ->
+ Pid = self(),
+ FileCtrlPid = maps:get(file_ctrl_pid,
+ maps:get(handler_state,
+ maps:get(cb_state,
+ logger_olp:info(h_proc_name())))),
+ dbg:tracer(process,{fun tracer/2,{Pid,Expected}}),
+ dbg:p(whereis(h_proc_name()),[c]),
+ dbg:p(FileCtrlPid,[c]),
+ tpl(Trace),
+ ok.
+
+tpl([{M,F,A}|Trace]) ->
+ tpl([{{M,F,A},[]}|Trace]);
+tpl([{{M,F,A},MS}|Trace]) ->
+ {ok,Match} = dbg:tpl(M,F,A,MS),
+ case lists:keyfind(matched,1,Match) of
+ {_,_,1} ->
+ ok;
+ _ ->
+ dbg:stop_clear(),
+ throw({skip,"Can't trace "++atom_to_list(M)++":"++
+ atom_to_list(F)++"/"++integer_to_list(A)})
+ end,
+ tpl(Trace);
+tpl([]) ->
+ ok.
+
+tracer({trace,_,call,{logger_h_common,handle_cast,[Op|_]}},
+ {Pid,[{Mod,Func,Op}|Expected]}) ->
+ maybe_tracer_done(Pid,Expected,{Mod,Func,Op});
+tracer({trace,_,call,{Mod=logger_std_h,Func=write_to_dev,[Data,_]}},
+ {Pid,[{Mod,Func,Data}|Expected]}) ->
+ maybe_tracer_done(Pid,Expected,{Mod,Func,Data});
+tracer({trace,_,call,{Mod,Func,_}}, {Pid,[{Mod,Func}|Expected]}) ->
+ maybe_tracer_done(Pid,Expected,{Mod,Func});
+tracer({trace,_,call,Call}, {Pid,Expected}) ->
+ ct:log("Tracer got unexpected: ~p~nExpected: ~p~n",[Call,Expected]),
+ Pid ! {tracer_got_unexpected,Call,Expected},
+ {Pid,Expected}.
+
+maybe_tracer_done(Pid,[]=Expected,Got) ->
+ ct:log("Tracer got: ~p~n",[Got]),
+ Pid ! {tracer_done,0},
+ {Pid,Expected};
+maybe_tracer_done(Pid,[{no_more,T}]=Expected,Got) ->
+ ct:log("Tracer got: ~p~n",[Got]),
+ Pid ! {tracer_done,T},
+ {Pid,Expected};
+maybe_tracer_done(Pid,Expected,Got) ->
+ ct:log("Tracer got: ~p~n",[Got]),
+ {Pid,Expected}.
+
+check_tracer(T) ->
+ check_tracer(T,fun() -> ct:fail({timeout,tracer}) end).
+check_tracer(T,TimeoutFun) ->
+ receive
+ {tracer_done,Delay} ->
+ %% Possibly wait Delay ms to check that no unexpected
+ %% traces are received
+ check_tracer(Delay,fun() -> ok end);
+ {tracer_got_unexpected,Got,Expected} ->
+ dbg:stop_clear(),
+ ct:fail({tracer_got_unexpected,Got,Expected})
+ after T ->
+ dbg:stop_clear(),
+ TimeoutFun()
+ end.
+
+escape([$+|Rest]) ->
+ [$\\,$+|escape(Rest)];
+escape([H|T]) ->
+ [H|escape(T)];
+escape([]) ->
+ [].
+
+h_proc_name() ->
+ h_proc_name(?MODULE).
+h_proc_name(Name) ->
+ ?name_to_reg_name(logger_std_h,Name).
+
+wait_for_process_up(T) ->
+ wait_for_process_up(?MODULE, h_proc_name(), T).
+
+wait_for_process_up(Name, RegName, T) ->
+ N = (T div 500) + 1,
+ wait_for_process_up1(Name, RegName, N).
+
+wait_for_process_up1(_Name, _RegName, 0) ->
+ error;
+wait_for_process_up1(Name, RegName, N) ->
+ timer:sleep(500),
+ case whereis(RegName) of
+ Pid when is_pid(Pid) ->
+ case logger:get_handler_config(Name) of
+ {ok,_} ->
+ %% ct:pal("Process ~p up (~p tries left)",[Name,N]),
+ {ok,Pid};
+ _ ->
+ wait_for_process_up1(Name, RegName, N-1)
+ end;
+ undefined ->
+ %% ct:pal("Waiting for process ~p (~p tries left)",[Name,N]),
+ wait_for_process_up1(Name, RegName, N-1)
+ end.
+
+filesync_rep_int() ->
+ case (fun() -> is_atom(?FILESYNC_REPEAT_INTERVAL) end)() of
+ true -> 5500;
+ false -> ?FILESYNC_REPEAT_INTERVAL + 500
+ end.
+
+
+file_delete(Log) ->
+ file:delete(Log).
diff --git a/lib/kernel/test/logger_stress_SUITE.erl b/lib/kernel/test/logger_stress_SUITE.erl
new file mode 100644
index 0000000000..1a278fb1b2
--- /dev/null
+++ b/lib/kernel/test/logger_stress_SUITE.erl
@@ -0,0 +1,550 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(logger_stress_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct_event.hrl").
+-include_lib("kernel/include/logger.hrl").
+-include_lib("kernel/src/logger_h_common.hrl").
+
+-ifdef(SAVE_STATS).
+ -define(COLLECT_STATS(_All_,_Procs_),
+ ct:pal("~p",[stats(_All_,_Procs_)])).
+-else.
+ -define(COLLECT_STATS(_All_,_Procs__), ok).
+-endif.
+
+-define(TEST_DURATION,120). % seconds
+
+suite() ->
+ [{timetrap,{minutes,3}},
+ {ct_hooks,[logger_test_lib]}].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(_Group, Config) ->
+ Config.
+
+end_per_group(_Group, _Config) ->
+ ok.
+
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+end_per_testcase(Case, Config) ->
+ try apply(?MODULE,Case,[cleanup,Config])
+ catch error:undef -> ok
+ end,
+ ok.
+
+groups() ->
+ [].
+
+all() ->
+ [allow_events,
+ reject_events,
+ std_handler,
+ disk_log_handler,
+ std_handler_time,
+ std_handler_time_big,
+ disk_log_handler_time,
+ disk_log_handler_time_big,
+ emulator_events,
+ remote_events,
+ remote_to_disk_log,
+ remote_emulator_events,
+ remote_emulator_to_disk_log].
+
+%%%-----------------------------------------------------------------
+%%% Test cases
+%%%-----------------------------------------------------------------
+%% Time from log macro call to handler callback
+allow_events(Config) ->
+ {ok,_,Node} =
+ logger_test_lib:setup(Config,
+ [{logger,
+ [{handler,default,?MODULE,#{}}]},
+ {logger_level,notice}]),
+ N = 100000,
+ {T,_} = timer:tc(fun() -> rpc:call(Node,?MODULE,nlogs,[N]) end),
+ IOPS = N * 1000/T, % log events allowed per millisecond
+ ct_event:notify(#event{name = benchmark_data,
+ data = [{value,IOPS}]}),
+ {comment,io_lib:format("~.2f accepted events pr millisecond",
+ [IOPS])}.
+
+%% Time from log macro call to reject (log level)
+reject_events(Config) ->
+ {ok,_,Node} =
+ logger_test_lib:setup(Config,
+ [{logger,
+ [{handler,default,?MODULE,#{}}]},
+ {logger_level,error}]),
+ N = 1000000,
+ {T,_} = timer:tc(fun() -> rpc:call(Node,?MODULE,nlogs,[N]) end),
+ IOPS = N * 1000/T, % log events rejected per millisecond
+ ct_event:notify(#event{name = benchmark_data,
+ data = [{value,IOPS}]}),
+ {comment,io_lib:format("~.2f rejected events pr millisecond",
+ [IOPS])}.
+
+%% Cascading failure that produce gen_server and proc_lib reports -
+%% how many of the produced log events are actually written to a log
+%% with logger_std_h file handler.
+std_handler(Config) ->
+ {ok,_,Node} =
+ logger_test_lib:setup(Config,
+ [{logger,
+ [{handler,default,logger_std_h,
+ #{config=>#{type=>{file,"default.log"}}}}]}]),
+
+ cascade({Node,{logger_backend,log_allowed,2},[]},
+ {Node,{logger_std_h,write,4},[{default,logger_std_h_default}]},
+ fun otp_cascading/0).
+std_handler(cleanup,_Config) ->
+ _ = file:delete("default.log"),
+ ok.
+
+%% Disable overload protection and just print a lot - measure time.
+%% The IOPS reported is the number of log events written per millisecond.
+std_handler_time(Config) ->
+ measure_handler_time(logger_std_h,#{type=>{file,"default.log"}},Config).
+std_handler_time(cleanup,_Config) ->
+ _ = file:delete("default.log"),
+ ok.
+
+std_handler_time_big(Config) ->
+ measure_handler_time_big(logger_std_h,#{type=>{file,"default.log"}},Config).
+std_handler_time_big(cleanup,_Config) ->
+ _ = file:delete("default.log"),
+ ok.
+
+%% Cascading failure that produce gen_server and proc_lib reports -
+%% how many of the produced log events are actually written to a log
+%% with logger_disk_log_h wrap file handler.
+disk_log_handler(Config) ->
+ {ok,_,Node} =
+ logger_test_lib:setup(Config,
+ [{logger,
+ [{handler,default,logger_disk_log_h,#{}}]}]),
+ cascade({Node,{logger_backend,log_allowed,2},[]},
+ {Node,{logger_disk_log_h,write,4},
+ [{default,logger_disk_log_h_default}]},
+ fun otp_cascading/0).
+disk_log_handler(cleanup,_Config) ->
+ Files = filelib:wildcard("default.log.*"),
+ [_ = file:delete(F) || F <- Files],
+ ok.
+
+%% Disable overload protection and just print a lot - measure time.
+%% The IOPS reported is the number of log events written per millisecond.
+disk_log_handler_time(Config) ->
+ measure_handler_time(logger_disk_log_h,#{type=>halt},Config).
+disk_log_handler_time(cleanup,_Config) ->
+ _ = file:delete("default"),
+ ok.
+
+disk_log_handler_time_big(Config) ->
+ measure_handler_time_big(logger_disk_log_h,#{type=>halt},Config).
+disk_log_handler_time_big(cleanup,_Config) ->
+ _ = file:delete("default"),
+ ok.
+
+%% Cascading failure that produce log events from the emulator - how
+%% many of the produced log events pass through the proxy.
+emulator_events(Config) ->
+ {ok,_,Node} =
+ logger_test_lib:setup(Config,
+ [{logger,
+ [{handler,default,?MODULE,#{}}]}]),
+ cascade({Node,{?MODULE,producer,0},[]},
+ {Node,{?MODULE,log,2},[{proxy,logger_proxy}]},
+ fun em_cascading/0).
+
+%% Cascading failure that produce gen_server and proc_lib reports on
+%% remote node - how many of the produced log events pass through the
+%% proxy.
+remote_events(Config) ->
+ {ok,_,Node1} =
+ logger_test_lib:setup([{postfix,1}|Config],
+ [{logger,
+ [{handler,default,?MODULE,#{}}]}]),
+ {ok,_,Node2} =
+ logger_test_lib:setup([{postfix,2}|Config],[]),
+ cascade({Node2,{logger_backend,log_allowed,2},[{remote_proxy,logger_proxy}]},
+ {Node1,{?MODULE,log,2},[{local_proxy,logger_proxy}]},
+ fun otp_cascading/0).
+
+%% Cascading failure that produce gen_server and proc_lib reports on
+%% remote node - how many of the produced log events are actually
+%% written to a log with logger_disk_log_h wrap file handler.
+remote_to_disk_log(Config) ->
+ {ok,_,Node1} =
+ logger_test_lib:setup([{postfix,1}|Config],
+ [{logger,
+ [{handler,default,logger_disk_log_h,#{}}]}]),
+ {ok,_,Node2} =
+ logger_test_lib:setup([{postfix,2}|Config],[]),
+ cascade({Node2,{logger_backend,log_allowed,2},[{remote_proxy,logger_proxy}]},
+ {Node1,{logger_disk_log_h,write,4},
+ [{local_proxy,logger_proxy},
+ {local_default,logger_disk_log_h_default}]},
+ fun otp_cascading/0).
+remote_to_disk_log(cleanup,_Config) ->
+ Files = filelib:wildcard("default.log.*"),
+ [_ = file:delete(F) || F <- Files],
+ ok.
+
+%% Cascading failure that produce log events from the emulator on
+%% remote node - how many of the produced log events pass through the
+%% proxy.
+remote_emulator_events(Config) ->
+ {ok,_,Node1} =
+ logger_test_lib:setup([{postfix,1}|Config],
+ [{logger,
+ [{handler,default,?MODULE,#{}}]}]),
+ {ok,_,Node2} =
+ logger_test_lib:setup([{postfix,2}|Config],[]),
+ cascade({Node2,{?MODULE,producer,0},[{remote_proxy,logger_proxy}]},
+ {Node1,{?MODULE,log,2},[{local_proxy,logger_proxy}]},
+ fun em_cascading/0).
+
+%% Cascading failure that produce log events from the emulator on
+%% remote node - how many of the produced log events are actually
+%% written to a log with logger_disk_log_h wrap file handler.
+remote_emulator_to_disk_log(Config) ->
+ {ok,_,Node1} =
+ logger_test_lib:setup([{postfix,1}|Config],
+ [{logger,
+ [{handler,default,logger_disk_log_h,#{}}]}]),
+ {ok,_,Node2} =
+ logger_test_lib:setup([{postfix,2}|Config],[]),
+ cascade({Node2,{?MODULE,producer,0},[{remote_proxy,logger_proxy}]},
+ {Node1,{logger_disk_log_h,write,4},
+ [{local_proxy,logger_proxy},
+ {local_default,logger_disk_log_h_default}]},
+ fun em_cascading/0).
+remote_emulator_to_disk_log(cleanup,_Config) ->
+ Files = filelib:wildcard("default.log.*"),
+ [_ = file:delete(F) || F <- Files],
+ ok.
+
+%%%-----------------------------------------------------------------
+%%% Internal functions
+measure_handler_time(Module,HCfg,Config) ->
+ measure_handler_time(Module,100000,small_fa(),millisecond,HCfg,#{},Config).
+
+measure_handler_time_big(Module,HCfg,Config) ->
+ FCfg = #{chars_limit=>4096, max_size=>1024},
+ measure_handler_time(Module,100,big_fa(),second,HCfg,FCfg,Config).
+
+measure_handler_time(Module,N,FA,Unit,HCfg,FCfg,Config) ->
+ {ok,_,Node} =
+ logger_test_lib:setup(
+ Config,
+ [{logger,
+ [{handler,default,Module,
+ #{formatter => {logger_formatter,
+ maps:merge(#{legacy_header=>false,
+ single_line=>true},FCfg)},
+ config=>maps:merge(#{sync_mode_qlen => N+1,
+ drop_mode_qlen => N+1,
+ flush_qlen => N+1,
+ burst_limit_enable => false,
+ filesync_repeat_interval => no_repeat},
+ HCfg)}}]}]),
+ %% HPid = rpc:call(Node,erlang,whereis,[?name_to_reg_name(Module,default)]),
+ %% {links,[_,FCPid]} = rpc:call(Node,erlang,process_info,[HPid,links]),
+ T0 = erlang:monotonic_time(millisecond),
+ ok = rpc:call(Node,?MODULE,nlogs_wait,[N,FA,Module]),
+ %% ok = rpc:call(Node,fprof,apply,[fun ?MODULE:nlogs_wait/2,[N div 10,FA,Module],[{procs,[HPid,FCPid]}]]),
+ T1 = erlang:monotonic_time(millisecond),
+ T = T1-T0,
+ M = case Unit of
+ millisecond -> 1;
+ second -> 1000
+ end,
+ IOPS = M*N/T,
+ ct:pal("N: ~p~nT: ~p~nIOPS: ~.2f events pr ~w",[N,T,IOPS,Unit]),
+ %% Stats = rpc:call(Node,logger_olp,info,[?name_to_reg_name(Module,default)]),
+ %% ct:pal("Stats: ~p",[Stats]),
+ ct_event:notify(#event{name = benchmark_data,
+ data = [{value,IOPS}]}),
+ {comment,io_lib:format("~.2f events written pr ~w",[IOPS,Unit])}.
+
+nlogs_wait(N,{F,A},Module) ->
+ group_leader(whereis(user),self()),
+ [?LOG_NOTICE(F,A) || _ <- lists:seq(1,N)],
+ wait(Module).
+
+wait(Module) ->
+ case Module:filesync(default) of
+ {error,handler_busy} ->
+ wait(Module);
+ ok ->
+ ok
+ end.
+
+small_fa() ->
+ Str = "\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "[\\]^_`abcdefghijklmnopqr",
+ {"~ts",[Str]}.
+
+big_fa() ->
+ {"~p",[lists:duplicate(1048576,"a")]}.
+
+nlogs(N) ->
+ group_leader(whereis(user),self()),
+ Str = "\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "[\\]^_`abcdefghijklmnopqr",
+ [?LOG_NOTICE(Str) || _ <- lists:seq(1,N)],
+ ok.
+
+%% cascade(ProducerInfo,ConsumerInfo,TestFun)
+cascade({PNode,PMFA,_PStatProcs},{CNode,CMFA,_CStatProcs},TestFun) ->
+ Tab = ets:new(counter,[set,public]),
+ ets:insert(Tab,{producer,0}),
+ ets:insert(Tab,{consumer,0}),
+ dbg:tracer(process,{fun tracer/2,{Tab,PNode,CNode}}),
+ dbg:n(PNode),
+ dbg:n(CNode),
+ dbg:cn(node()),
+ dbg:p(all,[call,arity]),
+ dbg:tpl(PMFA,[]),
+ dbg:tpl(CMFA,[]),
+
+ Pid = rpc:call(CNode,?MODULE,wrap_test,[PNode,TestFun]),
+ MRef = erlang:monitor(process,Pid),
+ TO = ?TEST_DURATION*1000,
+ receive {'DOWN',MRef,_,_,Reason} ->
+ ct:fail({remote_pid_down,Reason})
+ after TO ->
+ All = ets:lookup_element(Tab,producer,2),
+ Written = ets:lookup_element(Tab,consumer,2),
+ dbg:stop_clear(),
+ ?COLLECT_STATS(All,
+ [{PNode,P,Id} || {Id,P} <- _PStatProcs] ++
+ [{CNode,P,Id} || {Id,P} <- _CStatProcs]),
+ Ratio = Written/All * 100,
+ ct_event:notify(#event{name = benchmark_data,
+ data = [{value,Ratio}]}),
+ {comment,io_lib:format("~p % (~p written, ~p produced)",
+ [round(Ratio),Written,All])}
+ end.
+
+wrap_test(Fun) ->
+ wrap_test(node(),Fun).
+wrap_test(Node,Fun) ->
+ reset(),
+ group_leader(whereis(user),self()),
+ rpc:call(Node,?MODULE,do_fun,[Fun]).
+
+do_fun(Fun) ->
+ reset(),
+ Fun().
+
+reset() ->
+ reset([logger_std_h_default, logger_disk_log_h_default, logger_proxy]).
+reset([P|Ps]) ->
+ is_pid(whereis(P)) andalso logger_olp:reset(P),
+ reset(Ps);
+reset([]) ->
+ ok.
+
+
+tracer({trace,_,call,{?MODULE,producer,_}},{Tab,_PNode,_CNode}=S) ->
+ ets:update_counter(Tab,producer,1),
+ S;
+tracer({trace,Pid,call,{logger_backend,log_allowed,_}},{Tab,PNode,_CNode}=S) when node(Pid)=:=PNode ->
+ ets:update_counter(Tab,producer,1),
+ S;
+tracer({trace,_,call,{?MODULE,log,_}},{Tab,_PNode,_CNode}=S) ->
+ ets:update_counter(Tab,consumer,1),
+ S;
+tracer({trace,_,call,{_,write,_}},{Tab,_PNode,_CNode}=S) ->
+ ets:update_counter(Tab,consumer,1),
+ S;
+tracer(_,S) ->
+ S.
+
+
+%%%-----------------------------------------------------------------
+%%% Collect statistics
+-define(STAT_KEYS,
+ [burst_drops,
+ calls,
+ casts,
+ drops,
+ flushed,
+ flushes,
+ freq,
+ last_qlen,
+ max_qlen,
+ time,
+ writes]).
+-define(EVENT_KEYS,
+ [calls,casts,flushed]).
+
+stats(All,Procs) ->
+ NI = [{Id,rpc:call(N,logger_olp,info,[P])} || {N,P,Id}<-Procs],
+ [{all,All}|[stats(Id,I,All) || {Id,I} <- NI]].
+
+stats(Id,Info,All) ->
+ S = maps:with(?STAT_KEYS,Info),
+ AllOnProc = lists:sum(maps:values(maps:with(?EVENT_KEYS,S))),
+ if All>0 ->
+ Writes = maps:get(writes,S),
+ {_,ActiveTime} = maps:get(time,S),
+ Rate = round(100*Writes/All),
+ RateOnProc =
+ if AllOnProc>0 ->
+ round(100*Writes/AllOnProc);
+ true ->
+ 0
+ end,
+ AvFreq =
+ if ActiveTime>0 ->
+ round(Writes/ActiveTime);
+ true ->
+ 0
+ end,
+ {Id,
+ {stats,S},
+ {rate,Rate},
+ {rate_on_proc,RateOnProc},
+ {av_freq,AvFreq}};
+ true ->
+ {Id,none}
+ end.
+
+%%%-----------------------------------------------------------------
+%%% Spawn a lot of processes that crash repeatedly, causing a lot of
+%%% error reports from the emulator.
+em_cascading() ->
+ spawn(fun() -> super() end).
+
+super() ->
+ process_flag(trap_exit,true),
+ spawn_link(fun server/0),
+ [spawn_link(fun client/0) || _<-lists:seq(1,10000)],
+ super_loop().
+
+super_loop() ->
+ receive
+ {'EXIT',_,server} ->
+ spawn_link(fun server/0),
+ super_loop();
+ {'EXIT',_,_} ->
+ _L = lists:sum(lists:seq(1,10000)),
+ spawn_link(fun client/0),
+ super_loop()
+ end.
+
+client() ->
+ receive
+ after 1 ->
+ case whereis(server) of
+ Pid when is_pid(Pid) ->
+ ok;
+ undefined ->
+ producer(),
+ erlang:error(some_exception)
+ end
+ end,
+ client().
+
+server() ->
+ register(server,self()),
+ receive
+ after 3000 ->
+ exit(server)
+ end.
+
+
+%%%-----------------------------------------------------------------
+%%% Create a supervisor tree with processes that crash repeatedly,
+%%% causing a lot of supervisor reports and crashreports
+otp_cascading() ->
+ {ok,Pid} = supervisor:start_link({local,otp_super}, ?MODULE, [otp_super]),
+ unlink(Pid),
+ Pid.
+
+otp_server_sup() ->
+ supervisor:start_link({local,otp_server_sup},?MODULE,[otp_server_sup]).
+
+otp_client_sup(N) ->
+ supervisor:start_link({local,otp_client_sup},?MODULE,[otp_client_sup,N]).
+
+otp_server() ->
+ gen_server:start_link({local,otp_server},?MODULE,[otp_server],[]).
+
+otp_client() ->
+ gen_server:start_link(?MODULE,[otp_client],[]).
+
+init([otp_super]) ->
+ {ok, {{one_for_one, 200, 10},
+ [{client_sup,
+ {?MODULE, otp_client_sup, [10000]},
+ permanent, 1000, supervisor, [?MODULE]},
+ {server_sup,
+ {?MODULE, otp_server_sup, []},
+ permanent, 1000, supervisor, [?MODULE]}
+ ]}};
+init([otp_server_sup]) ->
+ {ok, {{one_for_one, 2, 10},
+ [{server,
+ {?MODULE, otp_server, []},
+ permanent, 1000, worker, [?MODULE]}
+ ]}};
+init([otp_client_sup,N]) ->
+ spawn(fun() ->
+ [supervisor:start_child(otp_client_sup,[])
+ || _ <- lists:seq(1,N)]
+ end),
+ {ok, {{simple_one_for_one, N*10, 1},
+ [{client,
+ {?MODULE, otp_client, []},
+ permanent, 1000, worker, [?MODULE]}
+ ]}};
+init([otp_server]) ->
+ {ok, server, 10000};
+init([otp_client]) ->
+ {ok, client,1}.
+
+handle_info(timeout, client) ->
+ true = is_pid(whereis(otp_server)),
+ {noreply,client,1};
+handle_info(timeout, server) ->
+ exit(self(), some_error).
+
+%%%-----------------------------------------------------------------
+%%% Logger callbacks
+log(_LogEvent,_Config) ->
+ ok.
+
+%%%-----------------------------------------------------------------
+%%% Function to trace on for counting produced emulator messages
+producer() ->
+ ok.
diff --git a/lib/kernel/test/logger_test_lib.erl b/lib/kernel/test/logger_test_lib.erl
new file mode 100644
index 0000000000..be4bc427fb
--- /dev/null
+++ b/lib/kernel/test/logger_test_lib.erl
@@ -0,0 +1,88 @@
+%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(logger_test_lib).
+
+-include_lib("kernel/src/logger_internal.hrl").
+
+-export([setup/2, log/3, sync_and_read/3]).
+
+-export([init/2,
+ pre_init_per_suite/3, pre_init_per_testcase/4,
+ post_end_per_testcase/5, post_end_per_suite/3]).
+
+setup(Config,Vars) ->
+ Postfix = case proplists:get_value(postfix, Config) of
+ undefined -> "";
+ P -> ["_",P]
+ end,
+ FuncStr = lists:concat([proplists:get_value(suite, Config), "_",
+ proplists:get_value(tc, Config)|
+ Postfix]),
+ ConfigFileName = filename:join(proplists:get_value(priv_dir, Config), FuncStr),
+ file:write_file(ConfigFileName ++ ".config", io_lib:format("[{kernel, ~p}].",[Vars])),
+ Sname = lists:concat([proplists:get_value(tc,Config)|Postfix]),
+ case test_server:start_node(Sname, slave,
+ [{args, ["-pa ",filename:dirname(code:which(?MODULE)),
+ " -boot start_sasl -kernel start_timer true "
+ "-config ",ConfigFileName]}]) of
+ {ok, Node} ->
+ L = rpc:call(Node, logger, get_config, []),
+ ct:log("~p",[L]),
+ {ok, L, Node};
+ {error, Reason} ->
+ ct:log("Failed to start node: ~p",[Reason]),
+ error
+ end.
+
+log(Node, F, A) ->
+ log(Node, logger, F, A).
+log(Node, M, F, A) ->
+ MD = #{ gl => rpc:call(Node, erlang, whereis, [logger]) },
+ rpc:call(Node, M, F, A ++ [MD]).
+
+sync_and_read(Node,disk_log,Log) ->
+ rpc:call(Node,logger_disk_log_h,filesync,[?STANDARD_HANDLER]),
+ file:read_file(Log ++ ".1");
+sync_and_read(Node, file,Log) ->
+ ok = rpc:call(Node,logger_std_h,filesync,[?STANDARD_HANDLER]),
+ file:read_file(Log).
+
+
+init(_, _) ->
+ {ok, []}.
+
+pre_init_per_suite(_Suite, Config, State) ->
+ {[{nodes, nodes()} | Config], State}.
+
+pre_init_per_testcase(Suite, TC, Config, State) ->
+ cleanup(Config),
+ {[{suite, Suite}, {tc, TC} | Config], State}.
+
+post_end_per_testcase(_, _TC, Config, Res, State) ->
+ cleanup(Config),
+ {Res, State}.
+
+post_end_per_suite(_, Config, State) ->
+ cleanup(Config),
+ {Config, State}.
+
+cleanup(Config) ->
+ [test_server:stop_node(N) || N <- nodes(),
+ not lists:member(N, proplists:get_value(nodes, Config))].
diff --git a/lib/kernel/test/os_SUITE.erl b/lib/kernel/test/os_SUITE.erl
index a0bcde68db..710b9b115c 100644
--- a/lib/kernel/test/os_SUITE.erl
+++ b/lib/kernel/test/os_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -22,7 +22,8 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2]).
--export([space_in_cwd/1, quoting/1, cmd_unicode/1, space_in_name/1, bad_command/1,
+-export([space_in_cwd/1, quoting/1, cmd_unicode/1,
+ null_in_command/1, space_in_name/1, bad_command/1,
find_executable/1, unix_comment_in_command/1, deep_list_command/1,
large_output_command/1, background_command/0, background_command/1,
message_leak/1, close_stdin/0, close_stdin/1, max_size_command/1,
@@ -35,7 +36,8 @@ suite() ->
{timetrap,{minutes,1}}].
all() ->
- [space_in_cwd, quoting, cmd_unicode, space_in_name, bad_command,
+ [space_in_cwd, quoting, cmd_unicode, null_in_command,
+ space_in_name, bad_command,
find_executable, unix_comment_in_command, deep_list_command,
large_output_command, background_command, message_leak,
close_stdin, max_size_command, perf_counter_api].
@@ -126,6 +128,14 @@ cmd_unicode(Config) when is_list(Config) ->
[] = receive_all(),
ok.
+null_in_command(Config) ->
+ {Ok, Error} = case os:type() of
+ {win32,_} -> {"dir", "di\0r"};
+ _ -> {"ls", "l\0s"}
+ end,
+ true = is_list(try os:cmd(Ok) catch Class0:_ -> Class0 end),
+ error = try os:cmd(Error) catch Class1:_ -> Class1 end,
+ ok.
%% Test that program with a space in its name can be executed.
space_in_name(Config) when is_list(Config) ->
@@ -217,8 +227,8 @@ find_executable(Config) when is_list(Config) ->
DataDir = proplists:get_value(data_dir, Config),
%% Smoke test.
- case lib:progname() of
- erl ->
+ case ct:get_progname() of
+ "erl" ->
ErlPath = os:find_executable("erl"),
true = is_list(ErlPath),
true = filelib:is_regular(ErlPath);
@@ -378,7 +388,7 @@ comp(Expected, Got) ->
ct:fail(failed)
end.
-%% Like lib:nonl/1, but strips \r as well as \n.
+%% strips \n and \r\n from end of string
strip_nl([$\r, $\n]) -> [];
strip_nl([$\n]) -> [];
diff --git a/lib/kernel/test/pdict_SUITE.erl b/lib/kernel/test/pdict_SUITE.erl
index d105952df9..3685e51c10 100644
--- a/lib/kernel/test/pdict_SUITE.erl
+++ b/lib/kernel/test/pdict_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -33,6 +33,7 @@
init_per_group/2,end_per_group/2,
mixed/1,
literals/1,
+ destructive/1,
simple/1, complicated/1, heavy/1, simple_all_keys/1, info/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
-export([other_process/2]).
@@ -52,6 +53,7 @@ suite() ->
all() ->
[simple, complicated, heavy, simple_all_keys, info,
literals,
+ destructive,
mixed].
groups() ->
@@ -367,6 +369,36 @@ match_keys(All) ->
ok.
+%% Test destructive put optimization of immed values
+%% does not affect get/0 or process_info.
+destructive(_Config) ->
+ Keys = lists:seq(1,100),
+ [put(Key, 17) || Key <- Keys],
+ Get1 = get(),
+ {dictionary,PI1} = process_info(self(), dictionary),
+
+ [begin
+ {Key, 17} = lists:keyfind(Key, 1, Get1),
+ {Key, 17} = lists:keyfind(Key, 1, PI1)
+ end
+ || Key <- Keys],
+
+ [17 = put(Key, 42) || Key <- Keys], % Mutate
+
+ Get2 = get(),
+ {dictionary,PI2} = process_info(self(), dictionary),
+
+ [begin
+ {Key, 17} = lists:keyfind(Key, 1, Get1),
+ {Key, 17} = lists:keyfind(Key, 1, PI1),
+ {Key, 42} = lists:keyfind(Key, 1, Get2),
+ {Key, 42} = lists:keyfind(Key, 1, PI2)
+
+ end
+ || Key <- Keys],
+
+ ok.
+
%% Do random mixed put/erase to test grow/shrink
%% Written for a temporary bug in gc during shrink
mixed(_Config) ->
diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl
index e88d42788f..2f465a15bc 100644
--- a/lib/kernel/test/prim_file_SUITE.erl
+++ b/lib/kernel/test/prim_file_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,38 +21,23 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2, init_per_testcase/2, end_per_testcase/2,
read_write_file/1, free_memory/0]).
--export([cur_dir_0a/1, cur_dir_0b/1,
- cur_dir_1a/1, cur_dir_1b/1,
- make_del_dir_a/1, make_del_dir_b/1,
- pos1/1, pos2/1]).
--export([close/1,
- delete_a/1, delete_b/1]).
--export([ open1/1, modes/1]).
--export([
- file_info_basic_file_a/1, file_info_basic_file_b/1,
- file_info_basic_directory_a/1, file_info_basic_directory_b/1,
- file_info_bad_a/1, file_info_bad_b/1,
- file_info_times_a/1, file_info_times_b/1,
- file_write_file_info_a/1, file_write_file_info_b/1,
- file_read_file_info_opts/1, file_write_file_info_opts/1,
- file_write_read_file_info_opts/1
- ]).
--export([rename_a/1, rename_b/1,
- access/1, truncate/1, datasync/1, sync/1,
+-export([cur_dir_0/1, cur_dir_1/1,
+ make_del_dir/1, pos1/1, pos2/1]).
+-export([close/1, delete/1]).
+-export([open1/1, modes/1]).
+-export([file_info_basic_file/1, file_info_basic_directory/1, file_info_bad/1,
+ file_info_times/1, file_write_file_info/1,
+ file_read_file_info_opts/1, file_write_file_info_opts/1,
+ file_write_read_file_info_opts/1]).
+-export([rename/1, access/1, truncate/1, datasync/1, sync/1,
read_write/1, pread_write/1, append/1, exclusive/1]).
--export([ e_delete/1, e_rename/1, e_make_dir/1, e_del_dir/1]).
+-export([e_delete/1, e_rename/1, e_make_dir/1, e_del_dir/1]).
--export([ read_not_really_compressed/1,
- read_compressed/1, write_compressed/1,
- compress_errors/1]).
-
--export([
- make_link_a/1, make_link_b/1,
- read_link_info_for_non_link/1,
- symlinks_a/1, symlinks_b/1,
- list_dir_limit/1,
- list_dir_error/1,
- list_dir/1]).
+-export([make_link/1, read_link_info_for_non_link/1,
+ symlinks/1,
+ list_dir_limit/1,
+ list_dir_error/1,
+ list_dir/1]).
-export([advise/1]).
-export([large_write/1]).
@@ -67,29 +52,16 @@
-define(PRIM_FILE, prim_file).
-%% Calls ?PRIM_FILE:F with arguments A and an optional handle H
-%% as first argument, unless the handle is [], i.e no handle.
-%% This is a macro to give the compiler and thereby
-%% the cross reference tool the possibility to interprete
-%% the call, since M, F, A (or [H | A]) can all be known at
-%% compile time.
--define(PRIM_FILE_call(F, H, A),
- case H of
- [] -> apply(?PRIM_FILE, F, A);
- _ -> apply(?PRIM_FILE, F, [H | A])
- end).
-
suite() -> [].
all() ->
[read_write_file, {group, dirs}, {group, files},
- delete_a, delete_b, rename_a, rename_b, {group, errors},
- {group, compression}, {group, links}, list_dir_limit, list_dir].
+ delete, rename, {group, errors}, {group, links},
+ list_dir_limit, list_dir].
groups() ->
[{dirs, [],
- [make_del_dir_a, make_del_dir_b, cur_dir_0a, cur_dir_0b,
- cur_dir_1a, cur_dir_1b]},
+ [make_del_dir, cur_dir_0, cur_dir_1]},
{files, [],
[{group, open}, {group, pos}, {group, file_info},
truncate, sync, datasync, advise, large_write, allocate]},
@@ -98,22 +70,14 @@ groups() ->
append, exclusive]},
{pos, [], [pos1, pos2]},
{file_info, [],
- [file_info_basic_file_a, file_info_basic_file_b,
- file_info_basic_directory_a,
- file_info_basic_directory_b, file_info_bad_a,
- file_info_bad_b, file_info_times_a, file_info_times_b,
- file_write_file_info_a, file_write_file_info_b,
- file_read_file_info_opts, file_write_file_info_opts,
- file_write_read_file_info_opts
+ [file_info_basic_file,file_info_basic_directory, file_info_bad,
+ file_info_times, file_write_file_info, file_read_file_info_opts,
+ file_write_file_info_opts, file_write_read_file_info_opts
]},
{errors, [],
[e_delete, e_rename, e_make_dir, e_del_dir]},
- {compression, [],
- [read_compressed, read_not_really_compressed,
- write_compressed, compress_errors]},
{links, [],
- [make_link_a, make_link_b, read_link_info_for_non_link,
- symlinks_a, symlinks_b, list_dir_error]}].
+ [make_link, read_link_info_for_non_link, symlinks, list_dir_error]}].
init_per_testcase(large_write, Config) ->
{ok, Started} = application:ensure_all_started(os_mon),
@@ -246,39 +210,27 @@ read_write_file(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-make_del_dir_a(Config) when is_list(Config) ->
- make_del_dir(Config, [], "_a").
-
-make_del_dir_b(Config) when is_list(Config) ->
- {ok, Handle} = ?PRIM_FILE:start(),
- Result = make_del_dir(Config, Handle, "_b"),
- ok = ?PRIM_FILE:stop(Handle),
- %% Just to make sure the state of the server makes a difference
- {error, einval} = ?PRIM_FILE_call(get_cwd, Handle, []),
- Result.
-
-make_del_dir(Config, Handle, Suffix) ->
+make_del_dir(Config) when is_list(Config) ->
RootDir = proplists:get_value(priv_dir,Config),
NewDir = filename:join(RootDir,
atom_to_list(?MODULE)
- ++"_mk-dir"++Suffix),
- ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]),
- {error, eexist} = ?PRIM_FILE_call(make_dir, Handle, [NewDir]),
- ok = ?PRIM_FILE_call(del_dir, Handle, [NewDir]),
- {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [NewDir]),
+ ++"_mk-dir"),
+ ok = ?PRIM_FILE:make_dir(NewDir),
+ {error, eexist} = ?PRIM_FILE:make_dir(NewDir),
+ ok = ?PRIM_FILE:del_dir(NewDir),
+ {error, enoent} = ?PRIM_FILE:del_dir(NewDir),
%% Make sure we are not in a directory directly under test_server
%% as that would result in eacces errors when trying to delete '..',
%% because there are processes having that directory as current.
- ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]),
- {ok, CurrentDir} = ?PRIM_FILE_call(get_cwd, Handle, []),
+ ok = ?PRIM_FILE:make_dir(NewDir),
+ {ok, CurrentDir} = ?PRIM_FILE:get_cwd(),
case {os:type(), length(NewDir) >= 260 } of
{{win32,_}, true} ->
io:format("Skip set_cwd for windows path longer than 260 (MAX_PATH)\n", []),
io:format("\nNewDir = ~p\n", [NewDir]);
_ ->
- ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir])
+ ok = ?PRIM_FILE:set_cwd(NewDir)
end,
try
%% Check that we get an error when trying to create...
@@ -286,14 +238,14 @@ make_del_dir(Config, Handle, Suffix) ->
NewDir2 = filename:join(RootDir,
atom_to_list(?MODULE)
++"_mk-dir-noexist/foo"),
- {error, enoent} = ?PRIM_FILE_call(make_dir, Handle, [NewDir2]),
+ {error, enoent} = ?PRIM_FILE:make_dir(NewDir2),
%% a nameless directory
- {error, enoent} = ?PRIM_FILE_call(make_dir, Handle, [""]),
+ {error, enoent} = ?PRIM_FILE:make_dir(""),
%% a directory with illegal name
- {error, badarg} = ?PRIM_FILE_call(make_dir, Handle, ['mk-dir']),
+ {error, badarg} = ?PRIM_FILE:make_dir('mk-dir'),
%% a directory with illegal name, even if it's a (bad) list
- {error, badarg} = ?PRIM_FILE_call(make_dir, Handle, [[1,2,3,{}]]),
+ {error, badarg} = ?PRIM_FILE:make_dir([1,2,3,{}]),
%% Maybe this isn't an error, exactly, but worth mentioning anyway:
%% ok = ?PRIM_FILE:make_dir([$f,$o,$o,0,$b,$a,$r])),
@@ -306,125 +258,101 @@ make_del_dir(Config, Handle, Suffix) ->
%% Try deleting some bad directories
%% Deleting the parent directory to the current, sounds dangerous, huh?
%% Don't worry ;-) the parent directory should never be empty, right?
- case ?PRIM_FILE_call(del_dir, Handle, [".."]) of
+ case ?PRIM_FILE:del_dir("..") of
{error, eexist} -> ok;
{error, eacces} -> ok; %OpenBSD
{error, einval} -> ok %FreeBSD
end,
- {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [""]),
- {error, badarg} = ?PRIM_FILE_call(del_dir, Handle, [[3,2,1,{}]])
+ {error, enoent} = ?PRIM_FILE:del_dir(""),
+ {error, badarg} = ?PRIM_FILE:del_dir([3,2,1,{}])
after
- ok = ?PRIM_FILE_call(set_cwd, Handle, [CurrentDir])
+ ok = ?PRIM_FILE:set_cwd(CurrentDir)
end,
ok.
-cur_dir_0a(Config) when is_list(Config) ->
- cur_dir_0(Config, []).
-
-cur_dir_0b(Config) when is_list(Config) ->
- {ok, Handle} = ?PRIM_FILE:start(),
- Result = cur_dir_0(Config, Handle),
- ok = ?PRIM_FILE:stop(Handle),
- Result.
-
-cur_dir_0(Config, Handle) ->
+cur_dir_0(Config) when is_list(Config) ->
%% Find out the current dir, and cd to it ;-)
- {ok,BaseDir} = ?PRIM_FILE_call(get_cwd, Handle, []),
+ {ok,BaseDir} = ?PRIM_FILE:get_cwd(),
Dir1 = BaseDir ++ "", %% Check that it's a string
- ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1]),
- DirName = atom_to_list(?MODULE) ++
- case Handle of
- [] ->
- "_curdir";
- _ ->
- "_curdir_h"
- end,
+ ok = ?PRIM_FILE:set_cwd(Dir1),
+ DirName = atom_to_list(?MODULE) ++ "_curdir",
%% Make a new dir, and cd to that
RootDir = proplists:get_value(priv_dir,Config),
NewDir = filename:join(RootDir, DirName),
- ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]),
+ ok = ?PRIM_FILE:make_dir(NewDir),
case {os:type(), length(NewDir) >= 260} of
{{win32,_}, true} ->
io:format("Skip set_cwd for windows path longer than 260 (MAX_PATH):\n"),
io:format("\nNewDir = ~p\n", [NewDir]);
_ ->
io:format("cd to ~s",[NewDir]),
- ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]),
+ ok = ?PRIM_FILE:set_cwd(NewDir),
%% Create a file in the new current directory, and check that it
%% really is created there
UncommonName = "uncommon.fil",
{ok,Fd} = ?PRIM_FILE:open(UncommonName, [read, write]),
ok = ?PRIM_FILE:close(Fd),
- {ok,NewDirFiles} = ?PRIM_FILE_call(list_dir, Handle, ["."]),
+ {ok,NewDirFiles} = ?PRIM_FILE:list_dir("."),
true = lists:member(UncommonName,NewDirFiles),
%% Delete the directory and return to the old current directory
%% and check that the created file isn't there (too!)
expect({error, einval}, {error, eacces}, {error, eexist},
- ?PRIM_FILE_call(del_dir, Handle, [NewDir])),
- ?PRIM_FILE_call(delete, Handle, [UncommonName]),
- {ok,[]} = ?PRIM_FILE_call(list_dir, Handle, ["."]),
- ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1]),
+ ?PRIM_FILE:del_dir(NewDir)),
+ ?PRIM_FILE:delete(UncommonName),
+ {ok,[]} = ?PRIM_FILE:list_dir("."),
+ ok = ?PRIM_FILE:set_cwd(Dir1),
io:format("cd back to ~s",[Dir1]),
- ok = ?PRIM_FILE_call(del_dir, Handle, [NewDir]),
- {error, enoent} = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]),
- ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1]),
+ ok = ?PRIM_FILE:del_dir(NewDir),
+ {error, enoent} = ?PRIM_FILE:set_cwd(NewDir),
+ ok = ?PRIM_FILE:set_cwd(Dir1),
io:format("cd back to ~s",[Dir1]),
- {ok,OldDirFiles} = ?PRIM_FILE_call(list_dir, Handle, ["."]),
+ {ok,OldDirFiles} = ?PRIM_FILE:list_dir("."),
false = lists:member(UncommonName,OldDirFiles)
end,
%% Try doing some bad things
{error, badarg} =
- ?PRIM_FILE_call(set_cwd, Handle, [{foo,bar}]),
+ ?PRIM_FILE:set_cwd({foo,bar}),
{error, enoent} =
- ?PRIM_FILE_call(set_cwd, Handle, [""]),
+ ?PRIM_FILE:set_cwd(""),
{error, enoent} =
- ?PRIM_FILE_call(set_cwd, Handle, [".......a......"]),
+ ?PRIM_FILE:set_cwd(".......a......"),
{ok,BaseDir} =
- ?PRIM_FILE_call(get_cwd, Handle, []), %% Still there?
+ ?PRIM_FILE:get_cwd(), %% Still there?
%% On Windows, there should only be slashes, no backslashes,
%% in the return value of get_cwd().
%% (The test is harmless on Unix, because filenames usually
%% don't contain backslashes.)
- {ok, BaseDir} = ?PRIM_FILE_call(get_cwd, Handle, []),
+ {ok, BaseDir} = ?PRIM_FILE:get_cwd(),
false = lists:member($\\, BaseDir),
ok.
%% Tests ?PRIM_FILE:get_cwd/1.
-cur_dir_1a(Config) when is_list(Config) ->
- cur_dir_1(Config, []).
-
-cur_dir_1b(Config) when is_list(Config) ->
- {ok, Handle} = ?PRIM_FILE:start(),
- Result = cur_dir_1(Config, Handle),
- ok = ?PRIM_FILE:stop(Handle),
- Result.
-
-cur_dir_1(Config, Handle) ->
+cur_dir_1(Config) when is_list(Config) ->
case os:type() of
{win32, _} ->
- win_cur_dir_1(Config, Handle);
+ win_cur_dir_1(Config);
_ ->
{error, enotsup} =
- ?PRIM_FILE_call(get_cwd, Handle, ["d:"])
+ ?PRIM_FILE:get_cwd("d:")
end,
ok.
-win_cur_dir_1(_Config, Handle) ->
- {ok, BaseDir} = ?PRIM_FILE_call(get_cwd, Handle, []),
+win_cur_dir_1(_Config) ->
+ {ok, BaseDir} = ?PRIM_FILE:get_cwd(),
%% Get the drive letter from the current directory,
%% and try to get current directory for that drive.
[Drive, $:|_] = BaseDir,
- {ok, BaseDir} = ?PRIM_FILE_call(get_cwd, Handle, [[Drive, $:]]),
+ {ok, BaseDir} = ?PRIM_FILE:get_cwd([Drive, $:]),
io:format("BaseDir = ~s\n", [BaseDir]),
%% Unfortunately, there is no way to move away from the
@@ -446,12 +374,12 @@ open1(Config) when is_list(Config) ->
Name = filename:join(NewDir, "foo1.fil"),
{ok,Fd1} = ?PRIM_FILE:open(Name, [read, write]),
{ok,Fd2} = ?PRIM_FILE:open(Name, [read]),
- Str = "{a,tuple}.\n",
- Length = length(Str),
- ?PRIM_FILE:write(Fd1,Str),
+ Bin = list_to_binary("{a,tuple}.\n"),
+ Length = byte_size(Bin),
+ ?PRIM_FILE:write(Fd1,Bin),
{ok,0} = ?PRIM_FILE:position(Fd1,bof),
- {ok, Str} = ?PRIM_FILE:read(Fd1,Length),
- {ok, Str} = ?PRIM_FILE:read(Fd2,Length),
+ {ok, Bin} = ?PRIM_FILE:read(Fd1,Length),
+ {ok, Bin} = ?PRIM_FILE:read(Fd2,Length),
ok = ?PRIM_FILE:close(Fd2),
{ok,0} = ?PRIM_FILE:position(Fd1,bof),
ok = ?PRIM_FILE:truncate(Fd1),
@@ -471,13 +399,13 @@ modes(Config) when is_list(Config) ->
++"_open_modes"),
ok = ?PRIM_FILE:make_dir(NewDir),
Name1 = filename:join(NewDir, "foo1.fil"),
- Marker = "hello, world",
- Length = length(Marker),
+ Marker = <<"hello, world">>,
+ Length = byte_size(Marker),
%% write
{ok, Fd1} = ?PRIM_FILE:open(Name1, [write]),
ok = ?PRIM_FILE:write(Fd1, Marker),
- ok = ?PRIM_FILE:write(Fd1, ".\n"),
+ ok = ?PRIM_FILE:write(Fd1, <<".\n">>),
ok = ?PRIM_FILE:close(Fd1),
%% read
@@ -496,12 +424,6 @@ modes(Config) when is_list(Config) ->
{ok, Marker} = ?PRIM_FILE:read(Fd4, Length),
ok = ?PRIM_FILE:close(Fd4),
- %% read and binary
- BinaryMarker = list_to_binary(Marker),
- {ok, Fd5} = ?PRIM_FILE:open(Name1, [read, binary]),
- {ok, BinaryMarker} = ?PRIM_FILE:read(Fd5, Length),
- ok = ?PRIM_FILE:close(Fd5),
-
ok.
close(Config) when is_list(Config) ->
@@ -528,9 +450,9 @@ access(Config) when is_list(Config) ->
Name = filename:join(RootDir,
atom_to_list(?MODULE)
++"_access.fil"),
- Str = "ABCDEFGH",
+ Bin = <<"ABCDEFGH">>,
{ok,Fd1} = ?PRIM_FILE:open(Name, [write]),
- ?PRIM_FILE:write(Fd1,Str),
+ ?PRIM_FILE:write(Fd1,Bin),
ok = ?PRIM_FILE:close(Fd1),
%% Check that we can't write when in read only mode
{ok,Fd2} = ?PRIM_FILE:open(Name, [read]),
@@ -542,7 +464,7 @@ access(Config) when is_list(Config) ->
end,
ok = ?PRIM_FILE:close(Fd2),
{ok, Fd3} = ?PRIM_FILE:open(Name, [read]),
- {ok, Str} = ?PRIM_FILE:read(Fd3,length(Str)),
+ {ok, Bin} = ?PRIM_FILE:read(Fd3,byte_size(Bin)),
ok = ?PRIM_FILE:close(Fd3),
ok.
@@ -564,7 +486,7 @@ read_write(Config) when is_list(Config) ->
ok.
read_write_test(File) ->
- Marker = "hello, world",
+ Marker = <<"hello, world">>,
ok = ?PRIM_FILE:write(File, Marker),
{ok, 0} = ?PRIM_FILE:position(File, 0),
{ok, Marker} = ?PRIM_FILE:read(File, 100),
@@ -590,15 +512,15 @@ pread_write(Config) when is_list(Config) ->
ok.
pread_write_test(File) ->
- Marker = "hello, world",
- Len = length(Marker),
+ Marker = <<"hello, world">>,
+ Len = byte_size(Marker),
ok = ?PRIM_FILE:write(File, Marker),
{ok, Marker} = ?PRIM_FILE:pread(File, 0, 100),
eof = ?PRIM_FILE:pread(File, 100, 1),
ok = ?PRIM_FILE:pwrite(File, Len, Marker),
{ok, Marker} = ?PRIM_FILE:pread(File, Len, 100),
eof = ?PRIM_FILE:pread(File, 100, 1),
- MM = Marker ++ Marker,
+ MM = <<Marker/binary,Marker/binary>>,
{ok, MM} = ?PRIM_FILE:pread(File, 0, 100),
ok = ?PRIM_FILE:close(File),
ok.
@@ -655,24 +577,24 @@ pos1(Config) when is_list(Config) ->
atom_to_list(?MODULE)
++"_pos1.fil"),
{ok, Fd1} = ?PRIM_FILE:open(Name, [write]),
- ?PRIM_FILE:write(Fd1,"ABCDEFGH"),
+ ?PRIM_FILE:write(Fd1,<<"ABCDEFGH">>),
ok = ?PRIM_FILE:close(Fd1),
{ok, Fd2} = ?PRIM_FILE:open(Name, [read]),
%% Start pos is first char
io:format("Relative positions"),
- {ok, "A"} = ?PRIM_FILE:read(Fd2,1),
+ {ok, <<"A">>} = ?PRIM_FILE:read(Fd2,1),
{ok, 2} = ?PRIM_FILE:position(Fd2,{cur,1}),
- {ok, "C"} = ?PRIM_FILE:read(Fd2,1),
+ {ok, <<"C">>} = ?PRIM_FILE:read(Fd2,1),
{ok, 0} = ?PRIM_FILE:position(Fd2,{cur,-3}),
- {ok, "A"} = ?PRIM_FILE:read(Fd2,1),
+ {ok, <<"A">>} = ?PRIM_FILE:read(Fd2,1),
%% Backwards from first char should be an error
{ok,0} = ?PRIM_FILE:position(Fd2,{cur,-1}),
{error, einval} = ?PRIM_FILE:position(Fd2,{cur,-1}),
%% Reset position and move again
{ok, 0} = ?PRIM_FILE:position(Fd2,0),
{ok, 2} = ?PRIM_FILE:position(Fd2,{cur,2}),
- {ok, "C"} = ?PRIM_FILE:read(Fd2,1),
+ {ok, <<"C">>} = ?PRIM_FILE:read(Fd2,1),
%% Go a lot forwards
{ok, 13} = ?PRIM_FILE:position(Fd2,{cur,10}),
eof = ?PRIM_FILE:read(Fd2,1),
@@ -684,27 +606,27 @@ pos1(Config) when is_list(Config) ->
{ok, 8} = ?PRIM_FILE:position(Fd2,cur),
eof = ?PRIM_FILE:read(Fd2,1),
{ok, 7} = ?PRIM_FILE:position(Fd2,7),
- {ok, "H"} = ?PRIM_FILE:read(Fd2,1),
+ {ok, <<"H">>} = ?PRIM_FILE:read(Fd2,1),
{ok, 0} = ?PRIM_FILE:position(Fd2,0),
- {ok, "A"} = ?PRIM_FILE:read(Fd2,1),
+ {ok, <<"A">>} = ?PRIM_FILE:read(Fd2,1),
{ok, 3} = ?PRIM_FILE:position(Fd2,3),
- {ok, "D"} = ?PRIM_FILE:read(Fd2,1),
+ {ok, <<"D">>} = ?PRIM_FILE:read(Fd2,1),
{ok, 12} = ?PRIM_FILE:position(Fd2,12),
eof = ?PRIM_FILE:read(Fd2,1),
{ok, 3} = ?PRIM_FILE:position(Fd2,3),
- {ok, "D"} = ?PRIM_FILE:read(Fd2,1),
+ {ok, <<"D">>} = ?PRIM_FILE:read(Fd2,1),
%% Try the {bof,X} notation
{ok, 3} = ?PRIM_FILE:position(Fd2,{bof,3}),
- {ok, "D"} = ?PRIM_FILE:read(Fd2,1),
+ {ok, <<"D">>} = ?PRIM_FILE:read(Fd2,1),
%% Try eof positions
io:format("EOF positions"),
{ok, 8} = ?PRIM_FILE:position(Fd2,{eof,0}),
eof = ?PRIM_FILE:read(Fd2,1),
{ok, 7} = ?PRIM_FILE:position(Fd2,{eof,-1}),
- {ok, "H"} = ?PRIM_FILE:read(Fd2,1),
+ {ok, <<"H">>} = ?PRIM_FILE:read(Fd2,1),
{ok, 0} = ?PRIM_FILE:position(Fd2,{eof,-8}),
- {ok, "A"} = ?PRIM_FILE:read(Fd2,1),
+ {ok, <<"A">>} = ?PRIM_FILE:read(Fd2,1),
{error, einval} = ?PRIM_FILE:position(Fd2,{eof,-9}),
ok.
@@ -714,7 +636,7 @@ pos2(Config) when is_list(Config) ->
atom_to_list(?MODULE)
++"_pos2.fil"),
{ok,Fd1} = ?PRIM_FILE:open(Name, [write]),
- ?PRIM_FILE:write(Fd1,"ABCDEFGH"),
+ ?PRIM_FILE:write(Fd1,<<"ABCDEFGH">>),
ok = ?PRIM_FILE:close(Fd1),
{ok, Fd2} = ?PRIM_FILE:open(Name, [read]),
{error, einval} = ?PRIM_FILE:position(Fd2,-1),
@@ -722,35 +644,25 @@ pos2(Config) when is_list(Config) ->
%% Make sure that we still can search after an error.
{ok, 0} = ?PRIM_FILE:position(Fd2, 0),
{ok, 3} = ?PRIM_FILE:position(Fd2, {bof,3}),
- {ok, "D"} = ?PRIM_FILE:read(Fd2,1),
+ {ok, <<"D">>} = ?PRIM_FILE:read(Fd2,1),
io:format("DONE"),
ok.
-
-file_info_basic_file_a(Config) when is_list(Config) ->
- file_info_basic_file(Config, [], "_a").
-
-file_info_basic_file_b(Config) when is_list(Config) ->
- {ok, Handle} = ?PRIM_FILE:start(),
- Result = file_info_basic_file(Config, Handle, "_b"),
- ok = ?PRIM_FILE:stop(Handle),
- Result.
-
-file_info_basic_file(Config, Handle, Suffix) ->
+file_info_basic_file(Config) when is_list(Config) ->
RootDir = proplists:get_value(priv_dir, Config),
%% Create a short file.
Name = filename:join(RootDir,
atom_to_list(?MODULE)
- ++"_basic_test"++Suffix++".fil"),
+ ++"_basic_test"".fil"),
{ok,Fd1} = ?PRIM_FILE:open(Name, [write]),
?PRIM_FILE:write(Fd1, "foo bar"),
ok = ?PRIM_FILE:close(Fd1),
%% Test that the file has the expected attributes.
%% The times are tricky, so we will save them to a separate test case.
- {ok, FileInfo} = ?PRIM_FILE_call(read_file_info, Handle, [Name]),
+ {ok, FileInfo} = ?PRIM_FILE:read_file_info(Name),
#file_info{size = Size, type = Type, access = Access,
atime = AccessTime, mtime = ModifyTime} =
FileInfo,
@@ -768,39 +680,30 @@ file_info_basic_file(Config, Handle, Suffix) ->
ok.
-file_info_basic_directory_a(Config) when is_list(Config) ->
- file_info_basic_directory(Config, []).
-
-file_info_basic_directory_b(Config) when is_list(Config) ->
- {ok, Handle} = ?PRIM_FILE:start(),
- Result = file_info_basic_directory(Config, Handle),
- ok = ?PRIM_FILE:stop(Handle),
- Result.
-
-file_info_basic_directory(Config, Handle) ->
+file_info_basic_directory(Config) when is_list(Config) ->
%% Note: filename:join/1 removes any trailing slash,
%% which is essential for ?PRIM_FILE:read_file_info/1 to work on
%% platforms such as Windows95.
RootDir = filename:join([proplists:get_value(priv_dir, Config)]),
%% Test that the RootDir directory has the expected attributes.
- test_directory(RootDir, read_write, Handle),
+ test_directory(RootDir, read_write),
%% Note that on Windows file systems, "/" or "c:/" are *NOT* directories.
%% Therefore, test that ?PRIM_FILE:read_file_info/1 behaves
%% as if they were directories.
case os:type() of
{win32, _} ->
- test_directory("/", read_write, Handle),
- test_directory("c:/", read_write, Handle),
- test_directory("c:\\", read_write, Handle);
+ test_directory("/", read_write),
+ test_directory("c:/", read_write),
+ test_directory("c:\\", read_write);
_ ->
- test_directory("/", read, Handle)
+ test_directory("/", read)
end,
ok.
-test_directory(Name, ExpectedAccess, Handle) ->
- {ok, FileInfo} = ?PRIM_FILE_call(read_file_info, Handle, [Name]),
+test_directory(Name, ExpectedAccess) ->
+ {ok, FileInfo} = ?PRIM_FILE:read_file_info(Name),
#file_info{size = Size, type = Type, access = Access,
atime = AccessTime, mtime = ModifyTime} =
FileInfo,
@@ -824,45 +727,24 @@ all_integers([]) ->
%% Try something nonexistent.
-file_info_bad_a(Config) when is_list(Config) ->
- file_info_bad(Config, []).
-
-file_info_bad_b(Config) when is_list(Config) ->
- {ok, Handle} = ?PRIM_FILE:start(),
- Result = file_info_bad(Config, Handle),
- ok = ?PRIM_FILE:stop(Handle),
- Result.
-
-file_info_bad(Config, Handle) ->
+file_info_bad(Config) when is_list(Config) ->
RootDir = filename:join([proplists:get_value(priv_dir, Config)]),
- {error, enoent} =
- ?PRIM_FILE_call(
- read_file_info, Handle,
- [filename:join(RootDir,
- atom_to_list(?MODULE)++"_nonexistent")]),
+ NonExistent = filename:join(RootDir, atom_to_list(?MODULE)++"_nonexistent"),
+ {error, enoent} = ?PRIM_FILE:read_file_info(NonExistent),
ok.
%% Test that the file times behave as they should.
-file_info_times_a(Config) when is_list(Config) ->
- file_info_times(Config, [], "_a").
-
-file_info_times_b(Config) when is_list(Config) ->
- {ok, Handle} = ?PRIM_FILE:start(),
- Result = file_info_times(Config, Handle, "_b"),
- ok = ?PRIM_FILE:stop(Handle),
- Result.
-
-file_info_times(Config, Handle, Suffix) ->
+file_info_times(Config) when is_list(Config) ->
%% We have to try this twice, since if the test runs across the change
%% of a month the time diff calculations will fail. But it won't happen
%% if you run it twice in succession.
test_server:m_out_of_n(
1,2,
- fun() -> file_info_int(Config, Handle, Suffix) end),
+ fun() -> file_info_int(Config) end),
ok.
-file_info_int(Config, Handle, Suffix) ->
+file_info_int(Config) ->
%% Note: filename:join/1 removes any trailing slash,
%% which is essential for ?PRIM_FILE:read_file_info/1 to work on
%% platforms such as Windows95.
@@ -872,14 +754,14 @@ file_info_int(Config, Handle, Suffix) ->
Name = filename:join(RootDir,
atom_to_list(?MODULE)
- ++"_file_info"++Suffix++".fil"),
+ ++"_file_info.fil"),
{ok,Fd1} = ?PRIM_FILE:open(Name, [write]),
?PRIM_FILE:write(Fd1,"foo"),
%% check that the file got a modify date max a few seconds away from now
{ok, #file_info{type = regular,
atime = AccTime1, mtime = ModTime1}} =
- ?PRIM_FILE_call(read_file_info, Handle, [Name]),
+ ?PRIM_FILE:read_file_info(Name),
Now = erlang:localtime(),
io:format("Now ~p",[Now]),
io:format("Open file Acc ~p Mod ~p",[AccTime1,ModTime1]),
@@ -897,7 +779,7 @@ file_info_int(Config, Handle, Suffix) ->
ok = ?PRIM_FILE:close(Fd1),
{ok, #file_info{size = Size, type = regular, access = Access,
atime = AccTime2, mtime = ModTime2}} =
- ?PRIM_FILE_call(read_file_info, Handle, [Name]),
+ ?PRIM_FILE:read_file_info(Name),
io:format("Closed file Acc ~p Mod ~p",[AccTime2,ModTime2]),
true = time_dist(ModTime1, ModTime2) >= 0,
@@ -909,7 +791,7 @@ file_info_int(Config, Handle, Suffix) ->
{ok, #file_info{size = DSize, type = directory,
access = DAccess,
atime = AccTime3, mtime = ModTime3}} =
- ?PRIM_FILE_call(read_file_info, Handle, [RootDir]),
+ ?PRIM_FILE:read_file_info(RootDir),
%% this dir was modified only a few secs ago
io:format("Dir Acc ~p; Mod ~p; Now ~p",
[AccTime3, ModTime3, Now]),
@@ -936,16 +818,7 @@ filter_atime(Atime, Config) ->
%% Test the write_file_info/2 function.
-file_write_file_info_a(Config) when is_list(Config) ->
- file_write_file_info(Config, [], "_a").
-
-file_write_file_info_b(Config) when is_list(Config) ->
- {ok, Handle} = ?PRIM_FILE:start(),
- Result = file_write_file_info(Config, Handle, "_b"),
- ok = ?PRIM_FILE:stop(Handle),
- Result.
-
-file_write_file_info(Config, Handle, Suffix) ->
+file_write_file_info(Config) when is_list(Config) ->
RootDir = get_good_directory(Config),
io:format("RootDir = ~p", [RootDir]),
@@ -955,16 +828,16 @@ file_write_file_info(Config, Handle, Suffix) ->
Name = filename:join(RootDir,
atom_to_list(?MODULE)
- ++"_write_file_info_ro"++Suffix),
+ ++"_write_file_info_ro"),
ok = ?PRIM_FILE:write_file(Name, "hello"),
Time = {{1997, 01, 02}, {12, 35, 42}},
Info = #file_info{mode=8#400, atime=Time, mtime=Time, ctime=Time},
- ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, Info]),
+ ok = ?PRIM_FILE:write_file_info(Name, Info),
%% Read back the times.
{ok, ActualInfo} =
- ?PRIM_FILE_call(read_file_info, Handle, [Name]),
+ ?PRIM_FILE:read_file_info(Name),
#file_info{mode=_Mode, atime=ActAtime, mtime=Time,
ctime=ActCtime} = ActualInfo,
FilteredAtime = filter_atime(Time, Config),
@@ -980,14 +853,11 @@ file_write_file_info(Config, Handle, Suffix) ->
{error, eacces} = ?PRIM_FILE:write_file(Name, "hello again"),
%% Make the file writable again.
-
- ?PRIM_FILE_call(write_file_info, Handle,
- [Name, #file_info{mode=8#600}]),
+ ?PRIM_FILE:write_file_info(Name, #file_info{mode=8#600}),
ok = ?PRIM_FILE:write_file(Name, "hello again"),
%% And unwritable.
- ?PRIM_FILE_call(write_file_info, Handle,
- [Name, #file_info{mode=8#400}]),
+ ?PRIM_FILE:write_file_info(Name, #file_info{mode=8#400}),
{error, eacces} = ?PRIM_FILE:write_file(Name, "hello again"),
%% Write the times again.
@@ -995,9 +865,9 @@ file_write_file_info(Config, Handle, Suffix) ->
NewTime = {{1997, 02, 15}, {13, 18, 20}},
NewInfo = #file_info{atime=NewTime, mtime=NewTime, ctime=NewTime},
- ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, NewInfo]),
+ ok = ?PRIM_FILE:write_file_info(Name, NewInfo),
{ok, ActualInfo2} =
- ?PRIM_FILE_call(read_file_info, Handle, [Name]),
+ ?PRIM_FILE:read_file_info(Name),
#file_info{atime=NewActAtime, mtime=NewTime,
ctime=NewActCtime} = ActualInfo2,
NewFilteredAtime = filter_atime(NewTime, Config),
@@ -1012,14 +882,12 @@ file_write_file_info(Config, Handle, Suffix) ->
%% Make the file writeable again, so that we can remove the
%% test suites ... :-)
- ?PRIM_FILE_call(write_file_info, Handle,
- [Name, #file_info{mode=8#600}]),
+ ?PRIM_FILE:write_file_info(Name, #file_info{mode=8#600}),
ok.
%% Test the write_file_info/3 function.
file_write_file_info_opts(Config) when is_list(Config) ->
- {ok, Handle} = ?PRIM_FILE:start(),
RootDir = get_good_directory(Config),
io:format("RootDir = ~p", [RootDir]),
@@ -1028,7 +896,7 @@ file_write_file_info_opts(Config) when is_list(Config) ->
lists:foreach(fun
({FI, Opts}) ->
- ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, FI, Opts])
+ ok = ?PRIM_FILE:write_file_info(Name, FI, Opts)
end, [
{#file_info{ mode=8#600, atime = Time, mtime = Time, ctime = Time}, Opts} ||
Opts <- [[{time, posix}]],
@@ -1038,7 +906,7 @@ file_write_file_info_opts(Config) when is_list(Config) ->
%% REM: determine date range dependent on time_t = Uint32 | Sint32 | Sint64 | Uint64
%% Determine time_t on os:type()?
lists:foreach(fun ({FI, Opts}) ->
- ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, FI, Opts])
+ ok = ?PRIM_FILE:write_file_info(Name, FI, Opts)
end, [ {#file_info{ mode=8#400, atime = Time, mtime = Time, ctime = Time}, Opts} ||
Opts <- [[{time, universal}],[{time, local}]],
Time <- [
@@ -1050,11 +918,9 @@ file_write_file_info_opts(Config) when is_list(Config) ->
{{2037,2,3},{23,59,59}},
erlang:localtime()
]]),
- ok = ?PRIM_FILE:stop(Handle),
ok.
file_read_file_info_opts(Config) when is_list(Config) ->
- {ok, Handle} = ?PRIM_FILE:start(),
RootDir = get_good_directory(Config),
io:format("RootDir = ~p", [RootDir]),
@@ -1063,41 +929,38 @@ file_read_file_info_opts(Config) when is_list(Config) ->
lists:foreach(fun
(Opts) ->
- {ok,_} = ?PRIM_FILE_call(read_file_info, Handle, [Name, Opts])
+ {ok,_} = ?PRIM_FILE:read_file_info(Name, Opts)
end, [[{time, Type}] || Type <- [local, universal, posix]]),
- ok = ?PRIM_FILE:stop(Handle),
ok.
%% Test the write and read back *_file_info/3 functions.
file_write_read_file_info_opts(Config) when is_list(Config) ->
- {ok, Handle} = ?PRIM_FILE:start(),
RootDir = get_good_directory(Config),
io:format("RootDir = ~p", [RootDir]),
Name = filename:join(RootDir, atom_to_list(?MODULE) ++"_read_write_file_info_opts"),
ok = ?PRIM_FILE:write_file(Name, "hello_opts2"),
- ok = file_write_read_file_info_opts(Handle, Name, {{1989, 04, 28}, {19,30,22}}, [{time, local}]),
- ok = file_write_read_file_info_opts(Handle, Name, {{1989, 04, 28}, {19,30,22}}, [{time, universal}]),
+ ok = file_write_read_file_info_opts(Name, {{1989, 04, 28}, {19,30,22}}, [{time, local}]),
+ ok = file_write_read_file_info_opts(Name, {{1989, 04, 28}, {19,30,22}}, [{time, universal}]),
%% will not work on platforms with unsigned time_t
- %ok = file_write_read_file_info_opts(Handle, Name, {{1930, 04, 28}, {19,30,22}}, [{time, local}]),
- %ok = file_write_read_file_info_opts(Handle, Name, {{1930, 04, 28}, {19,30,22}}, [{time, universal}]),
- ok = file_write_read_file_info_opts(Handle, Name, 1, [{time, posix}]),
+ %ok = file_write_read_file_info_opts(Name, {{1930, 04, 28}, {19,30,22}}, [{time, local}]),
+ %ok = file_write_read_file_info_opts(Name, {{1930, 04, 28}, {19,30,22}}, [{time, universal}]),
+ ok = file_write_read_file_info_opts(Name, 1, [{time, posix}]),
%% will not work on platforms with unsigned time_t
- %ok = file_write_read_file_info_opts(Handle, Name, -1, [{time, posix}]),
- %ok = file_write_read_file_info_opts(Handle, Name, -300000, [{time, posix}]),
- ok = file_write_read_file_info_opts(Handle, Name, 300000, [{time, posix}]),
- ok = file_write_read_file_info_opts(Handle, Name, 0, [{time, posix}]),
+ %ok = file_write_read_file_info_opts(Name, -1, [{time, posix}]),
+ %ok = file_write_read_file_info_opts(Name, -300000, [{time, posix}]),
+ ok = file_write_read_file_info_opts(Name, 300000, [{time, posix}]),
+ ok = file_write_read_file_info_opts(Name, 0, [{time, posix}]),
- ok = ?PRIM_FILE:stop(Handle),
ok.
-file_write_read_file_info_opts(Handle, Name, Mtime, Opts) ->
- {ok, FI} = ?PRIM_FILE_call(read_file_info, Handle, [Name, Opts]),
+file_write_read_file_info_opts(Name, Mtime, Opts) ->
+ {ok, FI} = ?PRIM_FILE:read_file_info(Name, Opts),
FI2 = FI#file_info{ mtime = Mtime },
- ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, FI2, Opts]),
- {ok, FI3} = ?PRIM_FILE_call(read_file_info, Handle, [Name, Opts]),
+ ok = ?PRIM_FILE:write_file_info(Name, FI2, Opts),
+ {ok, FI3} = ?PRIM_FILE:read_file_info(Name, Opts),
io:format("Expecting mtime = ~p, got ~p~n", [FI2#file_info.mtime, FI3#file_info.mtime]),
FI2 = FI3,
ok.
@@ -1175,8 +1038,8 @@ advise(Config) when is_list(Config) ->
atom_to_list(?MODULE)
++"_advise.fil"),
- Line1 = "Hello\n",
- Line2 = "World!\n",
+ Line1 = <<"Hello\n">>,
+ Line2 = <<"World!\n">>,
{ok, Fd} = ?PRIM_FILE:open(Advise, [write]),
ok = ?PRIM_FILE:advise(Fd, 0, 0, normal),
@@ -1226,7 +1089,7 @@ advise(Config) when is_list(Config) ->
{ok, Fd9} = ?PRIM_FILE:open(Advise, [read]),
Offset = 0,
%% same as a 0 length in some implementations
- Length = length(Line1) + length(Line2),
+ Length = byte_size(Line1) + byte_size(Line2),
ok = ?PRIM_FILE:advise(Fd9, Offset, Length, sequential),
{ok, Line1} = ?PRIM_FILE:read_line(Fd9),
{ok, Line2} = ?PRIM_FILE:read_line(Fd9),
@@ -1250,23 +1113,18 @@ do_large_write(Name) ->
Chunk = <<0:ChunkSize/unit:8>>,
Data = zip_data(lists:duplicate(Chunks, Chunk), Interleave),
Size = Chunks * ChunkSize + Chunks, % 4 G + 32
- Wordsize = erlang:system_info(wordsize),
- case prim_file:write_file(Name, Data) of
- ok when Wordsize =:= 8 ->
- {ok,#file_info{size=Size}} = file:read_file_info(Name),
- {ok,Fd} = prim_file:open(Name, [read]),
- check_large_write(Fd, ChunkSize, 0, Interleave);
- {error,einval} when Wordsize =:= 4 ->
- ok
- end.
+ ok = ?PRIM_FILE:write_file(Name, Data),
+ {ok,#file_info{size=Size}} = file:read_file_info(Name),
+ {ok,Fd} = ?PRIM_FILE:open(Name, [read]),
+ check_large_write(Fd, ChunkSize, 0, Interleave).
check_large_write(Fd, ChunkSize, Pos, [X|Interleave]) ->
Pos1 = Pos + ChunkSize,
- {ok,Pos1} = prim_file:position(Fd, {cur,ChunkSize}),
- {ok,[X]} = prim_file:read(Fd, 1),
+ {ok,Pos1} = ?PRIM_FILE:position(Fd, {cur,ChunkSize}),
+ {ok,<<X>>} = ?PRIM_FILE:read(Fd, 1),
check_large_write(Fd, ChunkSize, Pos1+1, Interleave);
check_large_write(Fd, _, _, []) ->
- eof = prim_file:read(Fd, 1),
+ eof = ?PRIM_FILE:read(Fd, 1),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1338,71 +1196,53 @@ allocate_and_assert(Fd, Offset, Length) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-delete_a(Config) when is_list(Config) ->
- delete(Config, [], "_a").
-
-delete_b(Config) when is_list(Config) ->
- {ok, Handle} = ?PRIM_FILE:start(),
- Result = delete(Config, Handle, "_b"),
- ok = ?PRIM_FILE:stop(Handle),
- Result.
-
-delete(Config, Handle, Suffix) ->
+delete(Config) when is_list(Config) ->
RootDir = proplists:get_value(priv_dir,Config),
Name = filename:join(RootDir,
atom_to_list(?MODULE)
- ++"_delete"++Suffix++".fil"),
+ ++"_delete.fil"),
{ok, Fd1} = ?PRIM_FILE:open(Name, [write]),
?PRIM_FILE:write(Fd1,"ok.\n"),
ok = ?PRIM_FILE:close(Fd1),
%% Check that the file is readable
{ok, Fd2} = ?PRIM_FILE:open(Name, [read]),
ok = ?PRIM_FILE:close(Fd2),
- ok = ?PRIM_FILE_call(delete, Handle, [Name]),
+ ok = ?PRIM_FILE:delete(Name),
%% Check that the file is not readable anymore
{error, _} = ?PRIM_FILE:open(Name, [read]),
%% Try deleting a nonexistent file
- {error, enoent} = ?PRIM_FILE_call(delete, Handle, [Name]),
+ {error, enoent} = ?PRIM_FILE:delete(Name),
ok.
-rename_a(Config) when is_list(Config) ->
- rename(Config, [], "_a").
-
-rename_b(Config) when is_list(Config) ->
- {ok, Handle} = ?PRIM_FILE:start(),
- Result = rename(Config, Handle, "_b"),
- ok = ?PRIM_FILE:stop(Handle),
- Result.
-
-rename(Config, Handle, Suffix) ->
+rename(Config) when is_list(Config) ->
RootDir = proplists:get_value(priv_dir,Config),
- FileName1 = atom_to_list(?MODULE)++"_rename"++Suffix++".fil",
- FileName2 = atom_to_list(?MODULE)++"_rename"++Suffix++".ful",
+ FileName1 = atom_to_list(?MODULE)++"_rename.fil",
+ FileName2 = atom_to_list(?MODULE)++"_rename.ful",
Name1 = filename:join(RootDir, FileName1),
Name2 = filename:join(RootDir, FileName2),
{ok,Fd1} = ?PRIM_FILE:open(Name1, [write]),
ok = ?PRIM_FILE:close(Fd1),
%% Rename, and check that it really changed name
- ok = ?PRIM_FILE_call(rename, Handle, [Name1, Name2]),
+ ok = ?PRIM_FILE:rename(Name1, Name2),
{error, _} = ?PRIM_FILE:open(Name1, [read]),
{ok, Fd2} = ?PRIM_FILE:open(Name2, [read]),
ok = ?PRIM_FILE:close(Fd2),
%% Try renaming something to itself
- ok = ?PRIM_FILE_call(rename, Handle, [Name2, Name2]),
+ ok = ?PRIM_FILE:rename(Name2, Name2),
%% Try renaming something that doesn't exist
{error, enoent} =
- ?PRIM_FILE_call(rename, Handle, [Name1, Name2]),
+ ?PRIM_FILE:rename(Name1, Name2),
%% Try renaming to something else than a string
{error, badarg} =
- ?PRIM_FILE_call(rename, Handle, [Name1, foobar]),
+ ?PRIM_FILE:rename(Name1, foobar),
%% Move between directories
DirName1 = filename:join(RootDir,
atom_to_list(?MODULE)
- ++"_rename_dir"++Suffix),
+ ++"_rename_dir"),
DirName2 = filename:join(RootDir,
atom_to_list(?MODULE)
- ++"_second_rename_dir"++Suffix),
+ ++"_second_rename_dir"),
Name1foo = filename:join(DirName1, "foo.fil"),
Name2foo = filename:join(DirName2, "foo.fil"),
Name2bar = filename:join(DirName2, "bar.dir"),
@@ -1410,21 +1250,21 @@ rename(Config, Handle, Suffix) ->
%% The name has to include the full file name, path is not enough
expect(
{error, eexist}, {error, eisdir},
- ?PRIM_FILE_call(rename, Handle, [Name2, DirName1])),
+ ?PRIM_FILE:rename(Name2, DirName1)),
ok =
- ?PRIM_FILE_call(rename, Handle, [Name2, Name1foo]),
+ ?PRIM_FILE:rename(Name2, Name1foo),
%% Now rename the directory
- ok = ?PRIM_FILE_call(rename, Handle, [DirName1, DirName2]),
+ ok = ?PRIM_FILE:rename(DirName1, DirName2),
%% And check that the file is there now
{ok,Fd3} = ?PRIM_FILE:open(Name2foo, [read]),
ok = ?PRIM_FILE:close(Fd3),
%% Try some dirty things now: move the directory into itself
{error, Msg1} =
- ?PRIM_FILE_call(rename, Handle, [DirName2, Name2bar]),
+ ?PRIM_FILE:rename(DirName2, Name2bar),
io:format("Errmsg1: ~p",[Msg1]),
%% move dir into a file in itself
{error, Msg2} =
- ?PRIM_FILE_call(rename, Handle, [DirName2, Name2foo]),
+ ?PRIM_FILE:rename(DirName2, Name2foo),
io:format("Errmsg2: ~p",[Msg2]),
ok.
@@ -1460,13 +1300,14 @@ e_delete(Config) when is_list(Config) ->
case os:type() of
{win32, _} ->
%% Remove a character device.
- {error, eacces} = ?PRIM_FILE:delete("nul");
+ expect({error, eacces}, {error, einval},
+ ?PRIM_FILE:delete("nul"));
_ ->
?PRIM_FILE:write_file_info(
Base, #file_info {mode=0}),
{error, eacces} = ?PRIM_FILE:delete(Afile),
?PRIM_FILE:write_file_info(
- Base, #file_info {mode=8#600})
+ Base, #file_info {mode=8#700})
end,
ok.
@@ -1602,7 +1443,7 @@ e_make_dir(Config) when is_list(Config) ->
?PRIM_FILE:write_file_info(Base, #file_info {mode=0}),
{error, eacces} =
?PRIM_FILE:make_dir(filename:join(Base, "xxxx")),
- ?PRIM_FILE:write_file_info(Base, #file_info {mode=8#600})
+ ?PRIM_FILE:write_file_info(Base, #file_info {mode=8#700})
end,
ok.
@@ -1652,170 +1493,24 @@ e_del_dir(Config) when is_list(Config) ->
?PRIM_FILE:write_file_info(Base, #file_info {mode=0}),
{error, eacces} = ?PRIM_FILE:del_dir(ADirectory),
?PRIM_FILE:write_file_info(
- Base, #file_info {mode=8#600})
+ Base, #file_info {mode=8#700})
end,
ok.
-%% Trying reading and positioning from a compressed file.
-
-read_compressed(Config) when is_list(Config) ->
- Data = proplists:get_value(data_dir, Config),
- Real = filename:join(Data, "realmen.html.gz"),
- {ok, Fd} = ?PRIM_FILE:open(Real, [read, compressed]),
- try_read_file(Fd).
-
-%% Trying reading and positioning from an uncompressed file,
-%% but with the compressed flag given.
-
-read_not_really_compressed(Config) when is_list(Config) ->
- Data = proplists:get_value(data_dir, Config),
- Priv = proplists:get_value(priv_dir, Config),
-
- %% The file realmen.html might have got CRs added (by WinZip).
- %% Remove them, or the file positions will not be correct.
-
- Real = filename:join(Data, "realmen.html"),
- RealPriv = filename:join(Priv,
- atom_to_list(?MODULE)++"_realmen.html"),
- {ok, RealDataBin} = ?PRIM_FILE:read_file(Real),
- RealData = remove_crs(binary_to_list(RealDataBin), []),
- ok = ?PRIM_FILE:write_file(RealPriv, RealData),
- {ok, Fd} = ?PRIM_FILE:open(RealPriv, [read, compressed]),
- try_read_file(Fd).
-
-remove_crs([$\r|Rest], Result) ->
- remove_crs(Rest, Result);
-remove_crs([C|Rest], Result) ->
- remove_crs(Rest, [C|Result]);
-remove_crs([], Result) ->
- lists:reverse(Result).
-
-try_read_file(Fd) ->
- %% Seek to the current position (nothing should happen).
-
- {ok, 0} = ?PRIM_FILE:position(Fd, 0),
- {ok, 0} = ?PRIM_FILE:position(Fd, {cur, 0}),
-
- %% Read a few lines from a compressed file.
-
- ShouldBe = "<TITLE>Real Programmers Don't Use PASCAL</TITLE>\n",
- {ok, ShouldBe} = ?PRIM_FILE:read(Fd, length(ShouldBe)),
-
- %% Now seek forward.
-
- {ok, 381} = ?PRIM_FILE:position(Fd, 381),
- Back = "Back in the good old days -- the \"Golden Era\" " ++
- "of computers, it was\n",
- {ok, Back} = ?PRIM_FILE:read(Fd, length(Back)),
-
- %% Try to search forward relative to the current position.
-
- {ok, CurPos} = ?PRIM_FILE:position(Fd, {cur, 0}),
- RealPos = 4273,
- {ok, RealPos} = ?PRIM_FILE:position(Fd, {cur, RealPos-CurPos}),
- RealProg = "<LI> Real Programmers aren't afraid to use GOTOs.\n",
- {ok, RealProg} = ?PRIM_FILE:read(Fd, length(RealProg)),
-
- %% Seek backward.
-
- AfterTitle = length("<TITLE>"),
- {ok, AfterTitle} = ?PRIM_FILE:position(Fd, AfterTitle),
- Title = "Real Programmers Don't Use PASCAL</TITLE>\n",
- {ok, Title} = ?PRIM_FILE:read(Fd, length(Title)),
-
- %% Done.
-
- ?PRIM_FILE:close(Fd),
- ok.
-
-write_compressed(Config) when is_list(Config) ->
- Priv = proplists:get_value(priv_dir, Config),
- MyFile = filename:join(Priv,
- atom_to_list(?MODULE)++"_test.gz"),
-
- %% Write a file.
-
- {ok, Fd} = ?PRIM_FILE:open(MyFile, [write, compressed]),
- {ok, 0} = ?PRIM_FILE:position(Fd, 0),
- Prefix = "hello\n",
- End = "end\n",
- ok = ?PRIM_FILE:write(Fd, Prefix),
- {ok, 143} = ?PRIM_FILE:position(Fd, 143),
- ok = ?PRIM_FILE:write(Fd, End),
- ok = ?PRIM_FILE:close(Fd),
-
- %% Read the file and verify the contents.
-
- {ok, Fd1} = ?PRIM_FILE:open(MyFile, [read, compressed]),
- {ok, Prefix} = ?PRIM_FILE:read(Fd1, length(Prefix)),
- Second = lists:duplicate(143-length(Prefix), 0) ++ End,
- {ok, Second} = ?PRIM_FILE:read(Fd1, length(Second)),
- ok = ?PRIM_FILE:close(Fd1),
-
- %% Ensure that the file is compressed.
-
- TotalSize = 143 + length(End),
- case ?PRIM_FILE:read_file_info(MyFile) of
- {ok, #file_info{size=Size}} when Size < TotalSize ->
- ok;
- {ok, #file_info{size=Size}} when Size == TotalSize ->
- ct:fail(file_not_compressed)
- end,
-
- %% Write again to ensure that the file is truncated.
-
- {ok, Fd2} = ?PRIM_FILE:open(MyFile, [write, compressed]),
- NewString = "aaaaaaaaaaa",
- ok = ?PRIM_FILE:write(Fd2, NewString),
- ok = ?PRIM_FILE:close(Fd2),
- {ok, Fd3} = ?PRIM_FILE:open(MyFile, [read, compressed]),
- {ok, NewString} = ?PRIM_FILE:read(Fd3, 1024),
- ok = ?PRIM_FILE:close(Fd3),
-
- ok.
-
-compress_errors(Config) when is_list(Config) ->
- Data = proplists:get_value(data_dir, Config),
- {error, enoent} = ?PRIM_FILE:open("non_existing__",
- [compressed, read]),
- {error, einval} = ?PRIM_FILE:open("non_existing__",
- [compressed, read, write]),
-
- %% Read a corrupted .gz file.
-
- Corrupted = filename:join(Data, "corrupted.gz"),
- {ok, Fd} = ?PRIM_FILE:open(Corrupted, [read, compressed]),
- {error, eio} = ?PRIM_FILE:read(Fd, 100),
- ?PRIM_FILE:close(Fd),
-
- ok.
-
-
-%% Test creating a hard link.
-make_link_a(Config) when is_list(Config) ->
- make_link(Config, [], "_a").
-
-%% Test creating a hard link.
-make_link_b(Config) when is_list(Config) ->
- {ok, Handle} = ?PRIM_FILE:start(),
- Result = make_link(Config, Handle, "_b"),
- ok = ?PRIM_FILE:stop(Handle),
- Result.
-
-make_link(Config, Handle, Suffix) ->
+make_link(Config) when is_list(Config) ->
RootDir = proplists:get_value(priv_dir, Config),
NewDir = filename:join(RootDir,
atom_to_list(?MODULE)
- ++"_make_link"++Suffix),
- ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]),
+ ++"_make_link"),
+ ok = ?PRIM_FILE:make_dir(NewDir),
Name = filename:join(NewDir, "a_file"),
ok = ?PRIM_FILE:write_file(Name, "some contents\n"),
Alias = filename:join(NewDir, "an_alias"),
Result =
- case ?PRIM_FILE_call(make_link, Handle, [Name, Alias]) of
+ case ?PRIM_FILE:make_link(Name, Alias) of
{error, enotsup} ->
{skipped, "Links not supported on this platform"};
ok ->
@@ -1826,12 +1521,12 @@ make_link(Config, Handle, Suffix) ->
%% since they are not used on symbolic links.
{ok, Info} =
- ?PRIM_FILE_call(read_link_info, Handle, [Name]),
+ ?PRIM_FILE:read_link_info(Name),
{ok, Info} =
- ?PRIM_FILE_call(read_link_info, Handle, [Alias]),
+ ?PRIM_FILE:read_link_info(Alias),
#file_info{links = 2, type = regular} = Info,
{error, eexist} =
- ?PRIM_FILE_call(make_link, Handle, [Name, Alias]),
+ ?PRIM_FILE:make_link(Name, Alias),
ok
end,
@@ -1843,30 +1538,19 @@ read_link_info_for_non_link(Config) when is_list(Config) ->
{ok, #file_info{type=directory}} = ?PRIM_FILE:read_link_info("."),
ok.
-%% Test operations on symbolic links (for Unix).
-symlinks_a(Config) when is_list(Config) ->
- symlinks(Config, [], "_a").
-
-%% Test operations on symbolic links (for Unix).
-symlinks_b(Config) when is_list(Config) ->
- {ok, Handle} = ?PRIM_FILE:start(),
- Result = symlinks(Config, Handle, "_b"),
- ok = ?PRIM_FILE:stop(Handle),
- Result.
-
-symlinks(Config, Handle, Suffix) ->
+symlinks(Config) when is_list(Config) ->
RootDir = proplists:get_value(priv_dir, Config),
NewDir = filename:join(RootDir,
atom_to_list(?MODULE)
- ++"_make_symlink"++Suffix),
- ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]),
+ ++"_make_symlink"),
+ ok = ?PRIM_FILE:make_dir(NewDir),
Name = filename:join(NewDir, "a_plain_file"),
ok = ?PRIM_FILE:write_file(Name, "some stupid content\n"),
Alias = filename:join(NewDir, "a_symlink_alias"),
Result =
- case ?PRIM_FILE_call(make_symlink, Handle, [Name, Alias]) of
+ case ?PRIM_FILE:make_symlink(Name, Alias) of
{error, enotsup} ->
{skipped, "Links not supported on this platform"};
{error, eperm} ->
@@ -1874,20 +1558,20 @@ symlinks(Config, Handle, Suffix) ->
{skipped, "Windows user not privileged to create links"};
ok ->
{ok, Info1} =
- ?PRIM_FILE_call(read_file_info, Handle, [Name]),
+ ?PRIM_FILE:read_file_info(Name),
{ok, Info1} =
- ?PRIM_FILE_call(read_file_info, Handle, [Alias]),
+ ?PRIM_FILE:read_file_info(Alias),
{ok, Info1} =
- ?PRIM_FILE_call(read_link_info, Handle, [Name]),
+ ?PRIM_FILE:read_link_info(Name),
#file_info{links = 1, type = regular} = Info1,
{ok, Info2} =
- ?PRIM_FILE_call(read_link_info, Handle, [Alias]),
+ ?PRIM_FILE:read_link_info(Alias),
#file_info{links=1, type=symlink} = Info2,
{ok, Name} =
- ?PRIM_FILE_call(read_link, Handle, [Alias]),
+ ?PRIM_FILE:read_link(Alias),
{ok, Name} =
- ?PRIM_FILE_call(read_link_all, Handle, [Alias]),
+ ?PRIM_FILE:read_link_all(Alias),
%% If all is good, delete dir again (avoid hanging dir on windows)
rm_rf(?PRIM_FILE,NewDir),
ok
@@ -1907,10 +1591,9 @@ list_dir_limit(Config) when is_list(Config) ->
RootDir = proplists:get_value(priv_dir, Config),
NewDir = filename:join(RootDir,
atom_to_list(?MODULE)++"_list_dir_limit"),
- {ok, Handle1} = ?PRIM_FILE:start(),
- ok = ?PRIM_FILE_call(make_dir, Handle1, [NewDir]),
+ ok = ?PRIM_FILE:make_dir(NewDir),
Ref = erlang:start_timer(MaxTime*1000, self(), []),
- Result = list_dir_limit_loop(NewDir, Handle1, Ref, MaxNumber, 0),
+ Result = list_dir_limit_loop(NewDir, Ref, MaxNumber, 0),
Time = case erlang:cancel_timer(Ref) of
false -> MaxTime;
T -> MaxTime - (T div 1000)
@@ -1920,21 +1603,18 @@ list_dir_limit(Config) when is_list(Config) ->
{error, _Reason, N} -> N;
_ -> 0
end,
- {ok, Handle2} = ?PRIM_FILE:start(),
- list_dir_limit_cleanup(NewDir, Handle2, Number, 0),
- ok = ?PRIM_FILE:stop(Handle1),
- ok = ?PRIM_FILE:stop(Handle2),
+ list_dir_limit_cleanup(NewDir, Number, 0),
{ok, Number} = Result,
{comment,
"Created " ++ integer_to_list(Number) ++ " files in "
++ integer_to_list(Time) ++ " seconds."}.
-list_dir_limit_loop(Dir, Handle, _Ref, N, Cnt) when Cnt >= N ->
- list_dir_check(Dir, Handle, Cnt);
-list_dir_limit_loop(Dir, Handle, Ref, N, Cnt) ->
+list_dir_limit_loop(Dir, _Ref, N, Cnt) when Cnt >= N ->
+ list_dir_check(Dir, Cnt);
+list_dir_limit_loop(Dir, Ref, N, Cnt) ->
receive
{timeout, Ref, []} ->
- list_dir_check(Dir, Handle, Cnt)
+ list_dir_check(Dir, Cnt)
after 0 ->
Name = integer_to_list(Cnt),
case ?PRIM_FILE:write_file(filename:join(Dir, Name), Name) of
@@ -1942,23 +1622,23 @@ list_dir_limit_loop(Dir, Handle, Ref, N, Cnt) ->
Next = Cnt + 1,
case Cnt rem 100 of
0 ->
- case list_dir_check(Dir, Handle, Next) of
+ case list_dir_check(Dir, Next) of
{ok, Next} ->
list_dir_limit_loop(
- Dir, Handle, Ref, N, Next);
+ Dir, Ref, N, Next);
Other ->
Other
end;
_ ->
- list_dir_limit_loop(Dir, Handle, Ref, N, Next)
+ list_dir_limit_loop(Dir, Ref, N, Next)
end;
{error, Reason} ->
{error, Reason, Cnt}
end
end.
-list_dir_check(Dir, Handle, Cnt) ->
- case ?PRIM_FILE:list_dir(Handle, Dir) of
+list_dir_check(Dir, Cnt) ->
+ case ?PRIM_FILE:list_dir(Dir) of
{ok, ListDir} ->
case length(ListDir) of
Cnt ->
@@ -1975,18 +1655,18 @@ list_dir_check(Dir, Handle, Cnt) ->
%% Deletes N files while ignoring errors, then continues deleting
%% as long as they exist.
-list_dir_limit_cleanup(Dir, Handle, N, Cnt) when Cnt >= N ->
+list_dir_limit_cleanup(Dir, N, Cnt) when Cnt >= N ->
Name = integer_to_list(Cnt),
- case ?PRIM_FILE:delete(Handle, filename:join(Dir, Name)) of
+ case ?PRIM_FILE:delete(filename:join(Dir, Name)) of
ok ->
- list_dir_limit_cleanup(Dir, Handle, N, Cnt+1);
+ list_dir_limit_cleanup(Dir, N, Cnt+1);
_ ->
ok
end;
-list_dir_limit_cleanup(Dir, Handle, N, Cnt) ->
+list_dir_limit_cleanup(Dir, N, Cnt) ->
Name = integer_to_list(Cnt),
- ?PRIM_FILE:delete(Handle, filename:join(Dir, Name)),
- list_dir_limit_cleanup(Dir, Handle, N, Cnt+1).
+ ?PRIM_FILE:delete(filename:join(Dir, Name)),
+ list_dir_limit_cleanup(Dir, N, Cnt+1).
%%%
%%% Test list_dir() on a non-existing pathname.
@@ -1995,7 +1675,7 @@ list_dir_limit_cleanup(Dir, Handle, N, Cnt) ->
list_dir_error(Config) ->
Priv = proplists:get_value(priv_dir, Config),
NonExisting = filename:join(Priv, "non-existing-dir"),
- {error,enoent} = prim_file:list_dir(NonExisting),
+ {error,enoent} = ?PRIM_FILE:list_dir(NonExisting),
ok.
%%%
@@ -2063,7 +1743,7 @@ do_run_large_file_test(Config, Run, Name0) ->
{'DOWN',Mref,_,_,_} -> ok;
{Tester,done} -> ok
end,
- prim_file:delete(Name)
+ ?PRIM_FILE:delete(Name)
end),
%% Run the test case.
diff --git a/lib/kernel/test/sendfile_SUITE.erl b/lib/kernel/test/sendfile_SUITE.erl
index bfa564c32c..ad060aa05c 100644
--- a/lib/kernel/test/sendfile_SUITE.erl
+++ b/lib/kernel/test/sendfile_SUITE.erl
@@ -23,30 +23,41 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("kernel/include/file.hrl").
--compile(export_all).
-
-all() -> [{group,async_threads},
- {group,no_async_threads}].
-
-groups() ->
- [{async_threads,[],tcs()},
- {no_async_threads,[],tcs()}].
-
-tcs() ->
- [t_sendfile_small
- ,t_sendfile_big_all
- ,t_sendfile_big_size
- ,t_sendfile_many_small
- ,t_sendfile_partial
- ,t_sendfile_offset
- ,t_sendfile_sendafter
- ,t_sendfile_recvafter
- ,t_sendfile_recvafter_remoteclose
- ,t_sendfile_sendduring
- ,t_sendfile_recvduring
- ,t_sendfile_closeduring
- ,t_sendfile_crashduring
- ].
+-export([all/0, init_per_suite/1, end_per_suite/1, init_per_testcase/2]).
+
+-export([sendfile_server/2, sendfile_do_recv/2, init/1, handle_event/2]).
+
+-export(
+ [t_sendfile_small/1,
+ t_sendfile_big_all/1,
+ t_sendfile_big_size/1,
+ t_sendfile_many_small/1,
+ t_sendfile_partial/1,
+ t_sendfile_offset/1,
+ t_sendfile_sendafter/1,
+ t_sendfile_recvafter/1,
+ t_sendfile_recvafter_remoteclose/1,
+ t_sendfile_sendduring/1,
+ t_sendfile_recvduring/1,
+ t_sendfile_closeduring/1,
+ t_sendfile_crashduring/1,
+ t_sendfile_arguments/1]).
+
+all() ->
+ [t_sendfile_small,
+ t_sendfile_big_all,
+ t_sendfile_big_size,
+ t_sendfile_many_small,
+ t_sendfile_partial,
+ t_sendfile_offset,
+ t_sendfile_sendafter,
+ t_sendfile_recvafter,
+ t_sendfile_recvafter_remoteclose,
+ t_sendfile_sendduring,
+ t_sendfile_recvduring,
+ t_sendfile_closeduring,
+ t_sendfile_crashduring,
+ t_sendfile_arguments].
init_per_suite(Config) ->
case {os:type(),os:version()} of
@@ -72,28 +83,18 @@ init_per_suite(Config) ->
end_per_suite(Config) ->
file:delete(proplists:get_value(big_file, Config)).
-init_per_group(async_threads,Config) ->
- case erlang:system_info(thread_pool_size) of
- 0 ->
- {skip,"No async threads"};
- _ ->
- [{sendfile_opts,[{use_threads,true}]}|Config]
- end;
-init_per_group(no_async_threads,Config) ->
- [{sendfile_opts,[{use_threads,false}]}|Config].
-
-end_per_group(_,_Config) ->
- ok.
-
init_per_testcase(TC,Config) when TC == t_sendfile_recvduring;
TC == t_sendfile_sendduring ->
Filename = proplists:get_value(small_file, Config),
Send = fun(Sock) ->
{_Size, Data} = sendfile_file_info(Filename),
- {ok,D} = file:open(Filename, [raw,binary,read]),
- prim_file:sendfile(D, Sock, 0, 0, 0,
- [],[],[]),
+ {ok,Fd} = file:open(Filename, [raw,binary,read]),
+ %% Determine whether the driver has native support by
+ %% hitting the raw module directly; file:sendfile/5 will
+ %% land in the fallback if it doesn't.
+ RawModule = Fd#file_descriptor.module,
+ {ok, _Ignored} = RawModule:sendfile(Fd,Sock,0,0,0,[],[],[]),
Data
end,
@@ -105,9 +106,8 @@ init_per_testcase(TC,Config) when TC == t_sendfile_recvduring;
ct:log("Error: ~p",[Error]),
{skip,"Not supported"}
end;
-init_per_testcase(_Tc,Config) ->
- Config ++ [{sendfile_opts,[{use_threads,false}]}].
-
+init_per_testcase(_TC,Config) ->
+ Config.
t_sendfile_small(Config) when is_list(Config) ->
Filename = proplists:get_value(small_file, Config),
@@ -124,7 +124,7 @@ t_sendfile_small(Config) when is_list(Config) ->
t_sendfile_many_small(Config) when is_list(Config) ->
Filename = proplists:get_value(small_file, Config),
FileOpts = proplists:get_value(file_opts, Config, []),
- SendfileOpts = proplists:get_value(sendfile_opts, Config),
+ SendfileOpts = proplists:get_value(sendfile_opts, Config, []),
error_logger:add_report_handler(?MODULE,[self()]),
@@ -151,7 +151,7 @@ t_sendfile_many_small(Config) when is_list(Config) ->
t_sendfile_big_all(Config) when is_list(Config) ->
Filename = proplists:get_value(big_file, Config),
- SendfileOpts = proplists:get_value(sendfile_opts, Config),
+ SendfileOpts = proplists:get_value(sendfile_opts, Config, []),
Send = fun(Sock) ->
{ok, #file_info{size = Size}} =
@@ -165,7 +165,7 @@ t_sendfile_big_all(Config) when is_list(Config) ->
t_sendfile_big_size(Config) ->
Filename = proplists:get_value(big_file, Config),
FileOpts = proplists:get_value(file_opts, Config, []),
- SendfileOpts = proplists:get_value(sendfile_opts, Config),
+ SendfileOpts = proplists:get_value(sendfile_opts, Config, []),
SendAll = fun(Sock) ->
{ok, #file_info{size = Size}} =
@@ -180,7 +180,7 @@ t_sendfile_big_size(Config) ->
t_sendfile_partial(Config) ->
Filename = proplists:get_value(small_file, Config),
FileOpts = proplists:get_value(file_opts, Config, []),
- SendfileOpts = proplists:get_value(sendfile_opts, Config),
+ SendfileOpts = proplists:get_value(sendfile_opts, Config, []),
SendSingle = fun(Sock) ->
{_Size, <<Data:5/binary,_/binary>>} =
@@ -217,7 +217,7 @@ t_sendfile_partial(Config) ->
t_sendfile_offset(Config) ->
Filename = proplists:get_value(small_file, Config),
FileOpts = proplists:get_value(file_opts, Config, []),
- SendfileOpts = proplists:get_value(sendfile_opts, Config),
+ SendfileOpts = proplists:get_value(sendfile_opts, Config, []),
Send = fun(Sock) ->
{_Size, <<_:5/binary,Data:3/binary,_/binary>> = AllData} =
@@ -233,7 +233,7 @@ t_sendfile_offset(Config) ->
t_sendfile_sendafter(Config) ->
Filename = proplists:get_value(small_file, Config),
- SendfileOpts = proplists:get_value(sendfile_opts, Config),
+ SendfileOpts = proplists:get_value(sendfile_opts, Config, []),
Send = fun(Sock) ->
{Size, Data} = sendfile_file_info(Filename),
@@ -246,7 +246,7 @@ t_sendfile_sendafter(Config) ->
t_sendfile_recvafter(Config) ->
Filename = proplists:get_value(small_file, Config),
- SendfileOpts = proplists:get_value(sendfile_opts, Config),
+ SendfileOpts = proplists:get_value(sendfile_opts, Config, []),
Send = fun(Sock) ->
{Size, Data} = sendfile_file_info(Filename),
@@ -279,7 +279,7 @@ t_sendfile_recvafter_remoteclose(Config) ->
t_sendfile_sendduring(Config) ->
Filename = proplists:get_value(big_file, Config),
- SendfileOpts = proplists:get_value(sendfile_opts, Config),
+ SendfileOpts = proplists:get_value(sendfile_opts, Config, []),
Send = fun(Sock) ->
{ok, #file_info{size = Size}} =
@@ -296,7 +296,7 @@ t_sendfile_sendduring(Config) ->
t_sendfile_recvduring(Config) ->
Filename = proplists:get_value(big_file, Config),
- SendfileOpts = proplists:get_value(sendfile_opts, Config),
+ SendfileOpts = proplists:get_value(sendfile_opts, Config, []),
Send = fun(Sock) ->
{ok, #file_info{size = Size}} =
@@ -315,7 +315,7 @@ t_sendfile_recvduring(Config) ->
t_sendfile_closeduring(Config) ->
Filename = proplists:get_value(big_file, Config),
- SendfileOpts = proplists:get_value(sendfile_opts, Config),
+ SendfileOpts = proplists:get_value(sendfile_opts, Config, []),
Send = fun(Sock,SFServPid) ->
spawn_link(fun() ->
@@ -341,11 +341,25 @@ t_sendfile_closeduring(Config) ->
-1
end,
- ok = sendfile_send({127,0,0,1}, Send, 0).
+ ok = sendfile_send({127,0,0,1}, Send, 0, [{active,false}]),
+ [] = flush(),
+ ok = sendfile_send({127,0,0,1}, Send, 0, [{active,true}]),
+ [] = flush(),
+ ok.
+
+flush() ->
+ lists:reverse(flush([])).
+
+flush(Acc) ->
+ receive M ->
+ flush([M | Acc])
+ after 0 ->
+ Acc
+ end.
t_sendfile_crashduring(Config) ->
Filename = proplists:get_value(big_file, Config),
- SendfileOpts = proplists:get_value(sendfile_opts, Config),
+ SendfileOpts = proplists:get_value(sendfile_opts, Config, []),
error_logger:add_report_handler(?MODULE,[self()]),
@@ -373,18 +387,52 @@ t_sendfile_crashduring(Config) ->
end
end.
+t_sendfile_arguments(Config) ->
+ Filename = proplists:get_value(small_file, Config),
+
+ {ok, Listener} = gen_tcp:listen(0,
+ [{packet, 0}, {active, false}, {reuseaddr, true}]),
+ {ok, Port} = inet:port(Listener),
+
+ ErrorCheck =
+ fun(Reason, Offset, Length, Opts) ->
+ {ok, Sender} = gen_tcp:connect({127, 0, 0, 1}, Port,
+ [{packet, 0}, {active, false}]),
+ {ok, Receiver} = gen_tcp:accept(Listener),
+ {ok, Fd} = file:open(Filename, [read, raw]),
+ {error, Reason} = file:sendfile(Fd, Sender, Offset, Length, Opts),
+ gen_tcp:close(Receiver),
+ gen_tcp:close(Sender),
+ file:close(Fd)
+ end,
+
+ ErrorCheck(einval, -1, 0, []),
+ ErrorCheck(einval, 0, -1, []),
+ ErrorCheck(badarg, gurka, 0, []),
+ ErrorCheck(badarg, 0, gurka, []),
+ ErrorCheck(badarg, 0, 0, gurka),
+ ErrorCheck(badarg, 0, 0, [{chunk_size, gurka}]),
+
+ gen_tcp:close(Listener),
+
+ ok.
+
%% Generic sendfile server code
sendfile_send(Send) ->
sendfile_send({127,0,0,1},Send).
sendfile_send(Host, Send) ->
sendfile_send(Host, Send, []).
sendfile_send(Host, Send, Orig) ->
+ sendfile_send(Host, Send, Orig, [{active,false}]).
+
+sendfile_send(Host, Send, Orig, SockOpts) ->
+
SFServer = spawn_link(?MODULE, sendfile_server, [self(), Orig]),
receive
{server, Port} ->
- {ok, Sock} = gen_tcp:connect(Host, Port,
- [binary,{packet,0},
- {active,false}]),
+ Opts = [binary,{packet,0}|SockOpts],
+ io:format("connect with opts = ~p\n", [Opts]),
+ {ok, Sock} = gen_tcp:connect(Host, Port, Opts),
Data = case proplists:get_value(arity,erlang:fun_info(Send)) of
1 ->
Send(Sock);
diff --git a/lib/kernel/test/seq_trace_SUITE.erl b/lib/kernel/test/seq_trace_SUITE.erl
index be23a1933f..663f910751 100644
--- a/lib/kernel/test/seq_trace_SUITE.erl
+++ b/lib/kernel/test/seq_trace_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -19,13 +19,17 @@
%%
-module(seq_trace_SUITE).
+%% label_capability_mismatch needs to run a part of the test on an OTP 20 node.
+-compile(r20).
+
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2]).
-export([token_set_get/1, tracer_set_get/1, print/1,
send/1, distributed_send/1, recv/1, distributed_recv/1,
trace_exit/1, distributed_exit/1, call/1, port/1,
- match_set_seq_token/1, gc_seq_token/1]).
+ match_set_seq_token/1, gc_seq_token/1, label_capability_mismatch/1,
+ send_literal/1]).
%% internal exports
-export([simple_tracer/2, one_time_receiver/0, one_time_receiver/1,
@@ -44,10 +48,10 @@ suite() ->
{timetrap,{minutes,1}}].
all() ->
- [token_set_get, tracer_set_get, print, send,
+ [token_set_get, tracer_set_get, print, send, send_literal,
distributed_send, recv, distributed_recv, trace_exit,
distributed_exit, call, port, match_set_seq_token,
- gc_seq_token].
+ gc_seq_token, label_capability_mismatch].
groups() ->
[].
@@ -90,8 +94,8 @@ do_token_set_get(TsType) ->
%% Test that initial seq_trace is disabled
[] = seq_trace:get_token(),
%% Test setting and reading the different fields
- 0 = seq_trace:set_token(label,17),
- {label,17} = seq_trace:get_token(label),
+ 0 = seq_trace:set_token(label,{my_label,1}),
+ {label,{my_label,1}} = seq_trace:get_token(label),
false = seq_trace:set_token(print,true),
{print,true} = seq_trace:get_token(print),
false = seq_trace:set_token(send,true),
@@ -101,12 +105,12 @@ do_token_set_get(TsType) ->
false = seq_trace:set_token(TsType,true),
{TsType,true} = seq_trace:get_token(TsType),
%% Check the whole token
- {Flags,17,0,Self,0} = seq_trace:get_token(), % all flags are set
+ {Flags,{my_label,1},0,Self,0} = seq_trace:get_token(), % all flags are set
%% Test setting and reading the 'serial' field
{0,0} = seq_trace:set_token(serial,{3,5}),
{serial,{3,5}} = seq_trace:get_token(serial),
%% Check the whole token, test that a whole token can be set and get
- {Flags,17,5,Self,3} = seq_trace:get_token(),
+ {Flags,{my_label,1},5,Self,3} = seq_trace:get_token(),
seq_trace:set_token({Flags,19,7,Self,5}),
{Flags,19,7,Self,5} = seq_trace:get_token(),
%% Check that receive timeout does not reset token
@@ -158,21 +162,51 @@ do_print(TsType) ->
{0,{print,_,_,[],print3}, Ts1}] = stop_tracer(2),
check_ts(TsType, Ts0),
check_ts(TsType, Ts1).
-
+
send(Config) when is_list(Config) ->
lists:foreach(fun do_send/1, ?TIMESTAMP_MODES).
do_send(TsType) ->
+ do_send(TsType, send).
+
+do_send(TsType, Msg) ->
seq_trace:reset_trace(),
start_tracer(),
Receiver = spawn(?MODULE,one_time_receiver,[]),
+ Label = make_ref(),
+ seq_trace:set_token(label,Label),
set_token_flags([send, TsType]),
- Receiver ! send,
+ Receiver ! Msg,
Self = self(),
seq_trace:reset_trace(),
- [{0,{send,_,Self,Receiver,send}, Ts}] = stop_tracer(1),
+ [{Label,{send,_,Self,Receiver,Msg}, Ts}] = stop_tracer(1),
check_ts(TsType, Ts).
+%% This testcase tests that we do not segfault when we have a
+%% literal as the message and the message is copied onto the
+%% heap during a GC.
+send_literal(Config) when is_list(Config) ->
+ lists:foreach(fun do_send_literal/1,
+ [atom, make_ref(), ets:new(hej,[]), 1 bsl 64,
+ "gurka", {tuple,test,with,#{}}, #{}]).
+
+do_send_literal(Msg) ->
+ N = 10000,
+ seq_trace:reset_trace(),
+ start_tracer(),
+ Label = make_ref(),
+ seq_trace:set_token(label,Label),
+ set_token_flags([send, 'receive', no_timestamp]),
+ Receiver = spawn_link(fun() -> receive ok -> ok end end),
+ [Receiver ! Msg || _ <- lists:seq(1, N)],
+ erlang:garbage_collect(Receiver),
+ [Receiver ! Msg || _ <- lists:seq(1, N)],
+ erlang:garbage_collect(Receiver),
+ Self = self(),
+ seq_trace:reset_trace(),
+ [{Label,{send,_,Self,Receiver,Msg}, Ts} | _] = stop_tracer(N),
+ check_ts(no_timestamp, Ts).
+
distributed_send(Config) when is_list(Config) ->
lists:foreach(fun do_distributed_send/1, ?TIMESTAMP_MODES).
@@ -184,14 +218,19 @@ do_distributed_send(TsType) ->
seq_trace:reset_trace(),
start_tracer(),
Receiver = spawn(Node,?MODULE,one_time_receiver,[]),
+
+ %% Make sure complex labels survive the trip.
+ Label = make_ref(),
+ seq_trace:set_token(label,Label),
set_token_flags([send,TsType]),
+
Receiver ! send,
Self = self(),
seq_trace:reset_trace(),
stop_node(Node),
- [{0,{send,_,Self,Receiver,send}, Ts}] = stop_tracer(1),
+ [{Label,{send,_,Self,Receiver,send}, Ts}] = stop_tracer(1),
check_ts(TsType, Ts).
-
+
recv(Config) when is_list(Config) ->
lists:foreach(fun do_recv/1, ?TIMESTAMP_MODES).
@@ -220,7 +259,12 @@ do_distributed_recv(TsType) ->
seq_trace:reset_trace(),
rpc:call(Node,?MODULE,start_tracer,[]),
Receiver = spawn(Node,?MODULE,one_time_receiver,[]),
+
+ %% Make sure complex labels survive the trip.
+ Label = make_ref(),
+ seq_trace:set_token(label,Label),
set_token_flags(['receive',TsType]),
+
Receiver ! 'receive',
%% let the other process receive the message:
receive after 1 -> ok end,
@@ -229,7 +273,7 @@ do_distributed_recv(TsType) ->
Result = rpc:call(Node,?MODULE,stop_tracer,[1]),
stop_node(Node),
ok = io:format("~p~n",[Result]),
- [{0,{'receive',_,Self,Receiver,'receive'}, Ts}] = Result,
+ [{Label,{'receive',_,Self,Receiver,'receive'}, Ts}] = Result,
check_ts(TsType, Ts).
trace_exit(Config) when is_list(Config) ->
@@ -240,7 +284,12 @@ do_trace_exit(TsType) ->
start_tracer(),
Receiver = spawn_link(?MODULE, one_time_receiver, [exit]),
process_flag(trap_exit, true),
+
+ %% Make sure complex labels survive the trip.
+ Label = make_ref(),
+ seq_trace:set_token(label,Label),
set_token_flags([send, TsType]),
+
Receiver ! {before, exit},
%% let the other process receive the message:
receive
@@ -254,8 +303,8 @@ do_trace_exit(TsType) ->
Result = stop_tracer(2),
seq_trace:reset_trace(),
ok = io:format("~p~n", [Result]),
- [{0, {send, {0,1}, Self, Receiver, {before, exit}}, Ts0},
- {0, {send, {1,2}, Receiver, Self,
+ [{Label, {send, {0,1}, Self, Receiver, {before, exit}}, Ts0},
+ {Label, {send, {1,2}, Receiver, Self,
{'EXIT', Receiver, {exit, {before, exit}}}}, Ts1}] = Result,
check_ts(TsType, Ts0),
check_ts(TsType, Ts1).
@@ -291,6 +340,74 @@ do_distributed_exit(TsType) ->
{'EXIT', Receiver, {exit, {before, exit}}}}, Ts}] = Result,
check_ts(TsType, Ts).
+label_capability_mismatch(Config) when is_list(Config) ->
+ Releases = ["20_latest"],
+ Available = [Rel || Rel <- Releases, test_server:is_release_available(Rel)],
+ case Available of
+ [] -> {skipped, "No incompatible releases available"};
+ _ ->
+ lists:foreach(fun do_incompatible_labels/1, Available),
+ lists:foreach(fun do_compatible_labels/1, Available),
+ ok
+ end.
+
+do_incompatible_labels(Rel) ->
+ Cookie = atom_to_list(erlang:get_cookie()),
+ {ok, Node} = test_server:start_node(
+ list_to_atom(atom_to_list(?MODULE)++"_"++Rel), peer,
+ [{args, " -setcookie "++Cookie}, {erl, [{release, Rel}]}]),
+
+ {_,Dir} = code:is_loaded(?MODULE),
+ Mdir = filename:dirname(Dir),
+ true = rpc:call(Node,code,add_patha,[Mdir]),
+ seq_trace:reset_trace(),
+ true = is_pid(rpc:call(Node,?MODULE,start_tracer,[])),
+ Receiver = spawn(Node,?MODULE,one_time_receiver,[]),
+
+ %% This node does not support arbitrary labels, so it must fail with a
+ %% timeout as the token is dropped silently.
+ seq_trace:set_token(label,make_ref()),
+ seq_trace:set_token('receive',true),
+
+ Receiver ! 'receive',
+ %% let the other process receive the message:
+ receive after 10 -> ok end,
+ seq_trace:reset_trace(),
+
+ {error,timeout} = rpc:call(Node,?MODULE,stop_tracer,[1]),
+ stop_node(Node),
+ ok.
+
+do_compatible_labels(Rel) ->
+ Cookie = atom_to_list(erlang:get_cookie()),
+ {ok, Node} = test_server:start_node(
+ list_to_atom(atom_to_list(?MODULE)++"_"++Rel), peer,
+ [{args, " -setcookie "++Cookie}, {erl, [{release, Rel}]}]),
+
+ {_,Dir} = code:is_loaded(?MODULE),
+ Mdir = filename:dirname(Dir),
+ true = rpc:call(Node,code,add_patha,[Mdir]),
+ seq_trace:reset_trace(),
+ true = is_pid(rpc:call(Node,?MODULE,start_tracer,[])),
+ Receiver = spawn(Node,?MODULE,one_time_receiver,[]),
+
+ %% This node does not support arbitrary labels, but small integers should
+ %% still work.
+ Label = 1234,
+ seq_trace:set_token(label,Label),
+ seq_trace:set_token('receive',true),
+
+ Receiver ! 'receive',
+ %% let the other process receive the message:
+ receive after 10 -> ok end,
+ Self = self(),
+ seq_trace:reset_trace(),
+ Result = rpc:call(Node,?MODULE,stop_tracer,[1]),
+ stop_node(Node),
+ ok = io:format("~p~n",[Result]),
+ [{Label,{'receive',_,Self,Receiver,'receive'}, _}] = Result,
+ ok.
+
call(doc) ->
"Tests special forms {is_seq_trace} and {get_seq_token} "
"in trace match specs.";
@@ -698,6 +815,24 @@ do_shrink(N) ->
erlang:garbage_collect(),
do_shrink(N-1).
+%% Test that messages from a port does not clear the token
+port_clean_token(Config) when is_list(Config) ->
+ seq_trace:reset_trace(),
+ Label = make_ref(),
+ seq_trace:set_token(label, Label),
+ {label,Label} = seq_trace:get_token(label),
+
+ %% Create a port and get messages from it
+ %% We use os:cmd as a convenience as it does
+ %% open_port, port_command, port_close and receives replies.
+ %% Maybe it is not ideal to rely on the internal implementation
+ %% of os:cmd but it will have to do.
+ os:cmd("ls"),
+
+ %% Make sure that the seq_trace token is still there
+ {label,Label} = seq_trace:get_token(label),
+
+ ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/kernel/test/wrap_log_reader_SUITE.erl b/lib/kernel/test/wrap_log_reader_SUITE.erl
index 40a016aed0..59b088ca73 100644
--- a/lib/kernel/test/wrap_log_reader_SUITE.erl
+++ b/lib/kernel/test/wrap_log_reader_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -428,13 +428,14 @@ stop() ->
ok = wrap_log_test:stop(),
dl_wait().
-%% Give disk logs opened by 'logger' and 'wlt' time to close after
+%% Give disk logs opened by 'wlr_logger' and 'wlt' time to close after
%% receiving EXIT signals.
dl_wait() ->
case disk_log:accessible_logs() of
{[], []} ->
ok;
- _ ->
+ _X ->
+ erlang:display(_X),
timer:sleep(100),
dl_wait()
end.
@@ -507,27 +508,27 @@ add_ext(Name, Ext) ->
%% disk_log.
open(Log, File, Where) ->
- logger ! {open, self(), Log, File},
+ wlr_logger ! {open, self(), Log, File},
rec1(ok, Where).
open_ext(Log, File, Where) ->
- logger ! {open_ext, self(), Log, File},
+ wlr_logger ! {open_ext, self(), Log, File},
rec1(ok, Where).
close(Log) ->
- logger ! {close, self(), Log},
+ wlr_logger ! {close, self(), Log},
rec(ok, ?LINE).
sync(Log) ->
- logger ! {sync, self(), Log},
+ wlr_logger ! {sync, self(), Log},
rec(ok, ?LINE).
log_terms(File, Terms) ->
- logger ! {log_terms, self(), File, Terms},
+ wlr_logger ! {log_terms, self(), File, Terms},
rec(ok, ?LINE).
blog_terms(File, Terms) ->
- logger ! {blog_terms, self(), File, Terms},
+ wlr_logger ! {blog_terms, self(), File, Terms},
rec(ok, ?LINE).
rec1(M, Where) ->
diff --git a/lib/kernel/test/wrap_log_reader_SUITE_data/wrap_log_test.erl b/lib/kernel/test/wrap_log_reader_SUITE_data/wrap_log_test.erl
index 38449b6bb3..d2bac40192 100644
--- a/lib/kernel/test/wrap_log_reader_SUITE_data/wrap_log_test.erl
+++ b/lib/kernel/test/wrap_log_reader_SUITE_data/wrap_log_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -36,9 +36,9 @@
-endif.
init() ->
- spawn(fun() -> start(logger) end),
+ spawn(fun() -> start(wlr_logger) end),
spawn(fun() -> start2(wlt) end),
- wait_registered(logger),
+ wait_registered(wlr_logger),
wait_registered(wlt),
ok.
@@ -52,9 +52,9 @@ wait_registered(Name) ->
end.
stop() ->
- catch logger ! exit,
+ catch wlr_logger ! exit,
catch wlt ! exit,
- wait_unregistered(logger),
+ wait_unregistered(wlr_logger),
wait_unregistered(wlt),
ok.
@@ -82,47 +82,47 @@ loop() ->
{open, Pid, Name, File} ->
R = disk_log:open([{name, Name}, {type, wrap}, {file, File},
{size, {?fsize, ?fno}}]),
- ?format("logger: open ~p -> ~p~n", [Name, R]),
+ ?format("wlr_logger: open ~p -> ~p~n", [Name, R]),
Pid ! R,
loop();
{open_ext, Pid, Name, File} ->
R = disk_log:open([{name, Name}, {type, wrap}, {file, File},
{format, external}, {size, {?fsize, ?fno}}]),
- ?format("logger: open ~p -> ~p~n", [Name, R]),
+ ?format("wlr_logger: open ~p -> ~p~n", [Name, R]),
Pid ! R,
loop();
{close, Pid, Name} ->
R = disk_log:close(Name),
- ?format("logger: close ~p -> ~p~n", [Name, R]),
+ ?format("wlr_logger: close ~p -> ~p~n", [Name, R]),
Pid ! R,
loop();
{sync, Pid, Name} ->
R = disk_log:sync(Name),
- ?format("logger: sync ~p -> ~p~n", [Name, R]),
+ ?format("wlr_logger: sync ~p -> ~p~n", [Name, R]),
Pid ! R,
loop();
{log_terms, Pid, Name, Terms} ->
R = disk_log:log_terms(Name, Terms),
- ?format("logger: log_terms ~p -> ~p~n", [Name, R]),
+ ?format("wlr_logger: log_terms ~p -> ~p~n", [Name, R]),
Pid ! R,
loop();
{blog_terms, Pid, Name, Terms} ->
R = disk_log:blog_terms(Name, Terms),
- ?format("logger: blog_terms ~p -> ~p~n", [Name, R]),
+ ?format("wlr_logger: blog_terms ~p -> ~p~n", [Name, R]),
Pid ! R,
loop();
exit ->
- ?format("Stopping logger~n", []),
+ ?format("Stopping wlr_logger~n", []),
exit(normal);
_Else ->
- ?format("logger: ignored: ~p~n", [_Else]),
+ ?format("wlr_logger: ignored: ~p~n", [_Else]),
loop()
end.
diff --git a/lib/kernel/test/zlib_SUITE.erl b/lib/kernel/test/zlib_SUITE.erl
index 26602bdcda..52ae1b3ae6 100644
--- a/lib/kernel/test/zlib_SUITE.erl
+++ b/lib/kernel/test/zlib_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1061,32 +1061,27 @@ sub_heap_binaries(Config) when is_list(Config) ->
%% Check concurrent access to zlib driver.
smp(Config) ->
- case erlang:system_info(smp_support) of
- true ->
- NumOfProcs = lists:min([8,erlang:system_info(schedulers)]),
- io:format("smp starting ~p workers\n",[NumOfProcs]),
-
- %% Tests to run in parallel.
- Funcs =
- [zip_usage, gz_usage, compress_usage, dictionary_usage,
- crc, adler],
-
- %% We get all function arguments here to avoid repeated parallel
- %% file read access.
- UsageArgs =
- list_to_tuple([{F, ?MODULE:F({get_arg,Config})} || F <- Funcs]),
- Parent = self(),
-
- WorkerFun =
- fun() ->
- worker(rand:uniform(9999), UsageArgs, Parent)
- end,
-
- Pids = [spawn_link(WorkerFun) || _ <- lists:seq(1, NumOfProcs)],
- wait_pids(Pids);
- false ->
- {skipped,"No smp support"}
- end.
+ NumOfProcs = lists:min([8,erlang:system_info(schedulers)]),
+ io:format("smp starting ~p workers\n",[NumOfProcs]),
+
+ %% Tests to run in parallel.
+ Funcs =
+ [zip_usage, gz_usage, compress_usage, dictionary_usage,
+ crc, adler],
+
+ %% We get all function arguments here to avoid repeated parallel
+ %% file read access.
+ UsageArgs =
+ list_to_tuple([{F, ?MODULE:F({get_arg,Config})} || F <- Funcs]),
+ Parent = self(),
+
+ WorkerFun =
+ fun() ->
+ worker(rand:uniform(9999), UsageArgs, Parent)
+ end,
+
+ Pids = [spawn_link(WorkerFun) || _ <- lists:seq(1, NumOfProcs)],
+ wait_pids(Pids).
worker(Seed, FnATpl, Parent) ->
io:format("smp worker ~p, seed=~p~n",[self(),Seed]),
diff --git a/lib/kernel/test/zzz_SUITE.erl b/lib/kernel/test/zzz_SUITE.erl
new file mode 100644
index 0000000000..59c7fd7404
--- /dev/null
+++ b/lib/kernel/test/zzz_SUITE.erl
@@ -0,0 +1,37 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(zzz_SUITE).
+
+%% The sole purpose of this test suite is for things we want to run last
+%% before the VM terminates.
+
+-export([all/0]).
+
+-export([lc_graph/1]).
+
+
+all() ->
+ [lc_graph].
+
+lc_graph(_Config) ->
+ %% Create "lc_graph" file in current working dir
+ %% if lock checker is enabled.
+ erts_debug:lc_graph(),
+ ok.
diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk
index 60a1b0bff8..765e890157 100644
--- a/lib/kernel/vsn.mk
+++ b/lib/kernel/vsn.mk
@@ -1 +1 @@
-KERNEL_VSN = 5.4.3
+KERNEL_VSN = 6.4
diff --git a/lib/megaco/configure.in b/lib/megaco/configure.in
index eaa875d0a3..bae6144abe 100644
--- a/lib/megaco/configure.in
+++ b/lib/megaco/configure.in
@@ -22,10 +22,6 @@ dnl
dnl define([AC_CACHE_LOAD], )dnl
dnl define([AC_CACHE_SAVE], )dnl
-if test "x$no_recursion" != "xyes" -a "x$OVERRIDE_CONFIG_CACHE" = "x"; then
- # We do not want to use a common cache!
- cache_file=/dev/null
-fi
AC_INIT(vsn.mk)
@@ -42,11 +38,14 @@ else
host_os=win32
fi
-
dnl ----------------------------------------------------------------------
dnl Checks for programs.
dnl ----------------------------------------------------------------------
+AC_PROG_CC
+
+LM_WINDOWS_ENVIRONMENT
+
AC_DEFUN(ERL_REENTRANT_FLEX,
[flex_compile='$LEX -R -Pconftest -oconftest.c conftest.flex 1>&AC_FD_CC'
changequote(253, 273)dnl
@@ -188,111 +187,7 @@ CFLAGS="$CFLAGS $sanitizers"
LDFLAGS="$LDFLAGS $sanitizers"
])
-dnl
-dnl If ${ERL_TOP}/make/otp_ded.mk.in exists and contains DED_MK_VSN > 0,
-dnl every thing releted to compiling Dynamic Erlang Drivers can be found
-dnl in $(ERL_TOP)/make/$(TARGET)/ded.mk at compile time. If not, try to
-dnl figure these things out.
-dnl
-
-AC_MSG_CHECKING([for usable Dynamic Erlang Driver configuration])
-[
- ded_mk_in="${ERL_TOP}/make/otp_ded.mk.in"
- ded_mk_vsn=
- test -r "$ded_mk_in" &&
- ded_mk_vsn=`sed -n "s/^DED_MK_VSN[ ]*=[ ]*\(.*\)/\1/p" < "$ded_mk_in"`
- test "$ded_mk_vsn" != "" || ded_mk_vsn=0
-]
-
-if test $ded_mk_vsn -gt 0; then
-
-HAVE_USABLE_OTP_DED_MK=yes
-AC_MSG_RESULT([yes])
-
-CC=false
-AC_SUBST(CC)
-DED_LD=false
-AC_SUBST(DED_LD)
-
-else dnl --- begin no usable otp_ded.mk.in ---
-
-HAVE_USABLE_OTP_DED_MK=no
-AC_MSG_RESULT([no])
-
-dnl
-dnl C compiler (related) defs
-dnl
-
-AC_PROG_CC
-
-dnl
-dnl Flags to the C compiler
-dnl
-
-if test "X$host" = "Xwin32"; then
- DED_CFLAGS="$CFLAGS"
-else
- case $host_os in
- darwin*)
- CFLAGS="$CFLAGS -fno-common"
- ;;
- esac
-
- if test "x$GCC" = xyes; then
- DED_CFLAGS="$CFLAGS -fPIC $DED_CFLAGS"
- else
- DED_CFLAGS="$CFLAGS $DED_CFLAGS"
- fi
-fi
-
-dnl emulator includes needed
-DED_INCLUDES="-I${ERL_TOP}/erts/emulator/beam -I${ERL_TOP}/erts/include -I${ERL_TOP}/erts/include/$host -I${ERL_TOP}/erts/include/internal -I${ERL_TOP}/erts/include/internal/$host -I${ERL_TOP}/erts/emulator/sys/$ERLANG_OSTYPE"
-
-DED_THR_DEFS="-D_THREAD_SAFE -D_REENTRANT"
-
-case $host_os in
- win32)
- DED_LDFLAGS="-dll"
- ;;
- solaris2*|sysv4*)
- DED_LDFLAGS="-G"
- ;;
- aix4*)
- DED_LDFLAGS="-G -bnoentry -bexpall"
- ;;
- freebsd2*)
- # Non-ELF GNU linker
- DED_LDFLAGS="-Bshareable"
- ;;
- darwin*)
- # Mach-O linker, a shared lib and a loadable
- # object file is not the same thing.
- DED_LDFLAGS="-bundle -flat_namespace -undefined suppress"
- DED_LD="$CC"
- ;;
- *)
- # assume GNU linker and ELF
- DED_LDFLAGS="-shared"
- ;;
-esac
-
-AC_CHECK_PROGS(DED_LD, [$LD ld.sh])
-AC_CHECK_TOOL(DED_LD, ld, no_ld)
-if test "$DED_LD" = no_ld; then
- AC_MSG_ERROR([ld is required to build the flex scanner!])
-fi
-
-AC_MSG_CHECKING(for linker flags for loadable drivers)
-DED_LDFLAGS="$LDFLAGS $DED_LDFLAGS"
-AC_MSG_RESULT([$DED_LDFLAGS])
-
-fi dnl --- end no usable otp_ded.mk.in ---
-
-AC_SUBST(HAVE_USABLE_OTP_DED_MK)
-AC_SUBST(DED_CFLAGS)
-AC_SUBST(DED_INCLUDES)
-AC_SUBST(DED_THR_DEFS)
-AC_SUBST(DED_LDFLAGS)
+ERL_DED
AC_CHECK_PROG(PERL, perl, perl, no_perl)
if test "$PERL" = no_perl; then
diff --git a/lib/megaco/doc/src/Makefile b/lib/megaco/doc/src/Makefile
index 43704cddf4..5e085b60b0 100644
--- a/lib/megaco/doc/src/Makefile
+++ b/lib/megaco/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2000-2017. All Rights Reserved.
+# Copyright Ericsson AB 2000-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -114,6 +114,7 @@ clean_man:
clean_html:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
imgs: $(IMG_FILES:%=$(HTMLDIR)/%)
diff --git a/lib/megaco/doc/src/book.xml b/lib/megaco/doc/src/book.xml
index 9c304d6cae..06ff315de7 100644
--- a/lib/megaco/doc/src/book.xml
+++ b/lib/megaco/doc/src/book.xml
@@ -4,7 +4,7 @@
<book xmlns:xi="http://www.w3.org/2001/XInclude">
<header titlestyle="normal">
<copyright>
- <year>2000</year><year>2016</year>
+ <year>2000</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/megaco/doc/src/megaco.xml b/lib/megaco/doc/src/megaco.xml
index d4a7451bfc..c7bcdfcd6f 100644
--- a/lib/megaco/doc/src/megaco.xml
+++ b/lib/megaco/doc/src/megaco.xml
@@ -32,7 +32,7 @@
<rev>%VSN%</rev>
<file>megaco.xml</file>
</header>
- <module>megaco</module>
+ <module since="">megaco</module>
<modulesummary>Main API of the Megaco application</modulesummary>
<description>
<p>Interface module for the Megaco application</p>
@@ -135,7 +135,7 @@ megaco_incr_timer() = #megaco_incr_timer{}
<funcs>
<func>
- <name>start() -> ok | {error, Reason}</name>
+ <name since="">start() -> ok | {error, Reason}</name>
<fsummary>Starts the Megaco application</fsummary>
<type>
<v>Reason = term()</v>
@@ -153,7 +153,7 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>stop() -> ok | {error, Reason}</name>
+ <name since="">stop() -> ok | {error, Reason}</name>
<fsummary>Stops the Megaco application</fsummary>
<type>
<v>Reason = term()</v>
@@ -166,7 +166,7 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>start_user(UserMid, Config) -> ok | {error, Reason}</name>
+ <name since="">start_user(UserMid, Config) -> ok | {error, Reason}</name>
<fsummary>Initial configuration of a user</fsummary>
<type>
<v>UserMid = megaco_mid()</v>
@@ -188,7 +188,7 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>stop_user(UserMid) -> ok | {error, Reason}</name>
+ <name since="">stop_user(UserMid) -> ok | {error, Reason}</name>
<fsummary>Delete the configuration of a user</fsummary>
<type>
<v>UserMid = megaco_mid()</v>
@@ -203,8 +203,8 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>user_info(UserMid) -> [{Item, Value}]</name>
- <name>user_info(UserMid, Item) -> Value | exit(Reason)</name>
+ <name since="">user_info(UserMid) -> [{Item, Value}]</name>
+ <name since="">user_info(UserMid, Item) -> Value | exit(Reason)</name>
<fsummary>Lookup user information</fsummary>
<type>
<v>Handle = user_info_handle()</v>
@@ -703,7 +703,7 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>update_user_info(UserMid, Item, Value) -> ok | {error, Reason}</name>
+ <name since="">update_user_info(UserMid, Item, Value) -> ok | {error, Reason}</name>
<fsummary>Update information about a user</fsummary>
<type>
<v>UserMid = megaco_mid() </v>
@@ -721,8 +721,8 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>conn_info(ConnHandle) -> [{Item, Value}]</name>
- <name>conn_info(ConnHandle, Item) -> Value | exit(Reason)</name>
+ <name since="">conn_info(ConnHandle) -> [{Item, Value}]</name>
+ <name since="">conn_info(ConnHandle, Item) -> Value | exit(Reason)</name>
<fsummary>Lookup information about an active connection</fsummary>
<type>
<v>ConnHandle = #megaco_conn_handle{}</v>
@@ -1222,7 +1222,7 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>update_conn_info(ConnHandle, Item, Value) -> ok | {error, Reason}</name>
+ <name since="">update_conn_info(ConnHandle, Item, Value) -> ok | {error, Reason}</name>
<fsummary>Update information about an active connection</fsummary>
<type>
<v>ConnHandle = #megaco_conn_handle{}</v>
@@ -1241,8 +1241,8 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>system_info() -> [{Item, Value}] | exit(Reason)</name>
- <name>system_info(Item) -> Value | exit(Reason)</name>
+ <name since="">system_info() -> [{Item, Value}] | exit(Reason)</name>
+ <name since="">system_info(Item) -> Value | exit(Reason)</name>
<fsummary>Lookup system information</fsummary>
<type>
<v>Item = system_info_item()</v>
@@ -1289,7 +1289,7 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>info() -> Info</name>
+ <name since="">info() -> Info</name>
<fsummary>All the information of the application</fsummary>
<type>
<v>Info = [{Key, Value}]</v>
@@ -1311,8 +1311,8 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>connect(ReceiveHandle, RemoteMid, SendHandle, ControlPid) -> {ok, ConnHandle} | {error, Reason}</name>
- <name>connect(ReceiveHandle, RemoteMid, SendHandle, ControlPid, Extra) -> {ok, ConnHandle} | {error, Reason}</name>
+ <name since="">connect(ReceiveHandle, RemoteMid, SendHandle, ControlPid) -> {ok, ConnHandle} | {error, Reason}</name>
+ <name since="">connect(ReceiveHandle, RemoteMid, SendHandle, ControlPid, Extra) -> {ok, ConnHandle} | {error, Reason}</name>
<fsummary>Establish a "virtual" connection</fsummary>
<type>
<v>ReceiveHandle = #megaco_receive_handle{}</v>
@@ -1436,7 +1436,7 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>disconnect(ConnHandle, DiscoReason) -> ok | {error, ErrReason}</name>
+ <name since="">disconnect(ConnHandle, DiscoReason) -> ok | {error, ErrReason}</name>
<fsummary>Tear down a "virtual" connection</fsummary>
<type>
<v>ConnHandle = conn_handle()</v>
@@ -1454,7 +1454,7 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>call(ConnHandle, Actions, Options) -> {ProtocolVersion, UserReply}</name>
+ <name since="">call(ConnHandle, Actions, Options) -> {ProtocolVersion, UserReply}</name>
<fsummary>Sends one or more transaction request(s) and waits for the reply</fsummary>
<type>
<v>ConnHandle = conn_handle()</v>
@@ -1545,7 +1545,7 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>cast(ConnHandle, Actions, Options) -> ok | {error, Reason}</name>
+ <name since="">cast(ConnHandle, Actions, Options) -> ok | {error, Reason}</name>
<fsummary>Sends one or more transaction request(s) but does NOT wait for a reply</fsummary>
<type>
<v>ConnHandle = conn_handle()</v>
@@ -1582,7 +1582,7 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>encode_actions(ConnHandle, Actions, Options) -> {ok, BinOrBins} | {error, Reason}</name>
+ <name since="">encode_actions(ConnHandle, Actions, Options) -> {ok, BinOrBins} | {error, Reason}</name>
<fsummary>Encode action requests for one or more transaction request(s)</fsummary>
<type>
<v>ConnHandle = conn_handle()</v>
@@ -1607,9 +1607,9 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>token_tag2string(Tag) -> Result</name>
- <name>token_tag2string(Tag, EncoderMod) -> Result</name>
- <name>token_tag2string(Tag, EncoderMod, Version) -> Result</name>
+ <name since="">token_tag2string(Tag) -> Result</name>
+ <name since="">token_tag2string(Tag, EncoderMod) -> Result</name>
+ <name since="">token_tag2string(Tag, EncoderMod, Version) -> Result</name>
<fsummary>Convert a token tag to a string</fsummary>
<type>
<v>Tag = atom()</v>
@@ -1635,7 +1635,7 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>cancel(ConnHandle, CancelReason) -> ok | {error, ErrReason}</name>
+ <name since="">cancel(ConnHandle, CancelReason) -> ok | {error, ErrReason}</name>
<fsummary>Cancel all outstanding messages for this connection</fsummary>
<type>
<v>ConnHandle = conn_handle()</v>
@@ -1655,8 +1655,8 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>process_received_message(ReceiveHandle, ControlPid, SendHandle, BinMsg) -> ok</name>
- <name>process_received_message(ReceiveHandle, ControlPid, SendHandle, BinMsg, Extra) -> ok</name>
+ <name since="">process_received_message(ReceiveHandle, ControlPid, SendHandle, BinMsg) -> ok</name>
+ <name since="">process_received_message(ReceiveHandle, ControlPid, SendHandle, BinMsg, Extra) -> ok</name>
<fsummary>Process a received message</fsummary>
<type>
<v>ReceiveHandle = #megaco_receive_handle{}</v>
@@ -1755,8 +1755,8 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>receive_message(ReceiveHandle, ControlPid, SendHandle, BinMsg) -> ok</name>
- <name>receive_message(ReceiveHandle, ControlPid, SendHandle, BinMsg, Extra) -> ok</name>
+ <name since="">receive_message(ReceiveHandle, ControlPid, SendHandle, BinMsg) -> ok</name>
+ <name since="">receive_message(ReceiveHandle, ControlPid, SendHandle, BinMsg, Extra) -> ok</name>
<fsummary>Process a received message</fsummary>
<type>
<v>ReceiveHandle = #megaco_receive_handle{}</v>
@@ -1783,7 +1783,7 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>parse_digit_map(DigitMapBody) -> {ok, ParsedDigitMap} | {error, Reason}</name>
+ <name since="">parse_digit_map(DigitMapBody) -> {ok, ParsedDigitMap} | {error, Reason}</name>
<fsummary>Parses a digit map body</fsummary>
<type>
<v>DigitMapBody = string()</v>
@@ -1802,8 +1802,8 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>eval_digit_map(DigitMap) -> {ok, MatchResult} | {error, Reason}</name>
- <name>eval_digit_map(DigitMap, Timers) -> {ok, MatchResult} | {error, Reason}</name>
+ <name since="">eval_digit_map(DigitMap) -> {ok, MatchResult} | {error, Reason}</name>
+ <name since="">eval_digit_map(DigitMap, Timers) -> {ok, MatchResult} | {error, Reason}</name>
<fsummary>Collect digit map letters according to the digit map</fsummary>
<type>
<v>DigitMap = #'DigitMapValue'{} | parsed_digit_map()</v>
@@ -1839,7 +1839,7 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>report_digit_event(DigitMapEvalPid, Events) -> ok | {error, Reason}</name>
+ <name since="">report_digit_event(DigitMapEvalPid, Events) -> ok | {error, Reason}</name>
<fsummary>Send one or more events to the event collector process</fsummary>
<type>
<v>DigitMapEvalPid = pid()</v>
@@ -1866,7 +1866,7 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>test_digit_event(DigitMap, Events) -> {ok, Kind, Letters} | {error, Reason}</name>
+ <name since="">test_digit_event(DigitMap, Events) -> {ok, Kind, Letters} | {error, Reason}</name>
<fsummary>Feed digit map collector with events and return the result</fsummary>
<type>
<v>DigitMap = #'DigitMapValue'{} | parsed_digit_map()</v>
@@ -1900,7 +1900,7 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>encode_sdp(SDP) -> {ok, PP} | {error, Reason}</name>
+ <name since="">encode_sdp(SDP) -> {ok, PP} | {error, Reason}</name>
<fsummary>Encode an SDP construct</fsummary>
<type>
<v>SDP = sdp_property_parm() | sdp_property_group() | sdp_property_groups() | asn1_NOVALUE</v>
@@ -1929,7 +1929,7 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>decode_sdp(PP) -> {ok, SDP} | {error, Reason}</name>
+ <name since="">decode_sdp(PP) -> {ok, SDP} | {error, Reason}</name>
<fsummary>Decode an property parameter construct</fsummary>
<type>
<v>PP = property_parm() | property_group() | property_groups() | asn1_NOVALUE</v>
@@ -1969,7 +1969,7 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>get_sdp_record_from_PropertGroup(Type, PG) -> [sdp()]</name>
+ <name since="">get_sdp_record_from_PropertGroup(Type, PG) -> [sdp()]</name>
<fsummary>Get all sdp records of a certain type from a property group</fsummary>
<type>
<v>Type = v | c | m | o | a | b | t | r | z | k | s | i | u | e | p</v>
@@ -1986,8 +1986,8 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>versions1() -> {ok, VersionInfo} | {error, Reason}</name>
- <name>versions2() -> {ok, Info} | {error, Reason}</name>
+ <name since="">versions1() -> {ok, VersionInfo} | {error, Reason}</name>
+ <name since="">versions2() -> {ok, Info} | {error, Reason}</name>
<fsummary>Retreive various system and application info</fsummary>
<type>
<v>VersionInfo = [version_info()]</v>
@@ -2007,8 +2007,8 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>print_version_info() -> void()</name>
- <name>print_version_info(VersionInfo) -> void()</name>
+ <name since="">print_version_info() -> void()</name>
+ <name since="">print_version_info(VersionInfo) -> void()</name>
<fsummary>Formated print of result of the versions functions</fsummary>
<type>
<v>VersionInfo = [version_info()]</v>
@@ -2029,7 +2029,7 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>enable_trace(Level, Destination) -> void()</name>
+ <name since="">enable_trace(Level, Destination) -> void()</name>
<fsummary>Start megaco tracing</fsummary>
<type>
<v>Level = max | min | 0 &lt;= integer() &lt;= 100</v>
@@ -2057,7 +2057,7 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>disable_trace() -> void()</name>
+ <name since="">disable_trace() -> void()</name>
<fsummary>Stop megaco tracing</fsummary>
<desc>
<p>This function is used to stop megaco tracing.</p>
@@ -2065,7 +2065,7 @@ megaco_incr_timer() = #megaco_incr_timer{}
</desc>
</func>
<func>
- <name>set_trace(Level) -> void()</name>
+ <name since="">set_trace(Level) -> void()</name>
<fsummary>Change megaco trace level</fsummary>
<type>
<v>Level = max | min | 0 &lt;= integer() &lt;= 100</v>
@@ -2081,10 +2081,10 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>get_stats() -> {ok, TotalStats} | {error, Reason}</name>
- <name>get_stats(GlobalCounter) -> {ok, CounterStats} | {error, Reason}</name>
- <name>get_stats(ConnHandle) -> {ok, ConnHandleStats} | {error, Reason}</name>
- <name>get_stats(ConnHandle, Counter) -> {ok, integer()} | {error, Reason}</name>
+ <name since="">get_stats() -> {ok, TotalStats} | {error, Reason}</name>
+ <name since="">get_stats(GlobalCounter) -> {ok, CounterStats} | {error, Reason}</name>
+ <name since="">get_stats(ConnHandle) -> {ok, ConnHandleStats} | {error, Reason}</name>
+ <name since="">get_stats(ConnHandle, Counter) -> {ok, integer()} | {error, Reason}</name>
<fsummary></fsummary>
<type>
<v>TotalStats = [total_stats()]</v>
@@ -2110,8 +2110,8 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>reset_stats() -> void()</name>
- <name>reset_stats(ConnHandle) -> void()</name>
+ <name since="">reset_stats() -> void()</name>
+ <name since="">reset_stats(ConnHandle) -> void()</name>
<fsummary></fsummary>
<type>
<v>ConnHandle = conn_handle()</v>
@@ -2123,7 +2123,7 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>test_request(ConnHandle, Version, EncodingMod, EncodingConfig, Actions) -> {MegaMsg, EncodeRes}</name>
+ <name since="">test_request(ConnHandle, Version, EncodingMod, EncodingConfig, Actions) -> {MegaMsg, EncodeRes}</name>
<fsummary>Tests if the Actions argument is correct</fsummary>
<type>
<v>ConnHandle = conn_handle()</v>
@@ -2150,7 +2150,7 @@ megaco_incr_timer() = #megaco_incr_timer{}
</func>
<func>
- <name>test_reply(ConnHandle, Version, EncodingMod, EncodingConfig, Reply) -> {MegaMsg, EncodeRes}</name>
+ <name since="">test_reply(ConnHandle, Version, EncodingMod, EncodingConfig, Reply) -> {MegaMsg, EncodeRes}</name>
<fsummary>Tests if the Reply argument is correct</fsummary>
<type>
<v>ConnHandle = conn_handle()</v>
diff --git a/lib/megaco/doc/src/megaco_codec_meas.xml b/lib/megaco/doc/src/megaco_codec_meas.xml
index 13cc3eb834..5184fe392e 100644
--- a/lib/megaco/doc/src/megaco_codec_meas.xml
+++ b/lib/megaco/doc/src/megaco_codec_meas.xml
@@ -32,7 +32,7 @@
<rev>%VSN%</rev>
<file>megaco_codec_meas.xml</file>
</header>
- <module>megaco_codec_meas</module>
+ <module since="">megaco_codec_meas</module>
<modulesummary>This module implements a simple megaco codec measurement tool.</modulesummary>
<description>
<p>This module implements a simple megaco codec measurement tool.</p>
@@ -43,8 +43,8 @@
<funcs>
<func>
- <name>start() -> void()</name>
- <name>start(MessagePackage) -> void()</name>
+ <name since="">start() -> void()</name>
+ <name since="">start(MessagePackage) -> void()</name>
<fsummary></fsummary>
<type>
<v>MessagePackageRaw = message_package()</v>
diff --git a/lib/megaco/doc/src/megaco_codec_mstone1.xml b/lib/megaco/doc/src/megaco_codec_mstone1.xml
index 2ff959a648..507a790c71 100644
--- a/lib/megaco/doc/src/megaco_codec_mstone1.xml
+++ b/lib/megaco/doc/src/megaco_codec_mstone1.xml
@@ -32,7 +32,7 @@
<rev>%VSN%</rev>
<file>megaco_codec_mstone1.xml</file>
</header>
- <module>megaco_codec_mstone1</module>
+ <module since="">megaco_codec_mstone1</module>
<modulesummary>This module implements a simple megaco codec-based performance tool.</modulesummary>
<description>
<p>This module implements the <em>mstone1</em> tool,
@@ -44,9 +44,9 @@
<funcs>
<func>
- <name>start() -> void()</name>
- <name>start(MessagePackage) -> void()</name>
- <name>start(MessagePackage, Factor) -> void()</name>
+ <name since="">start() -> void()</name>
+ <name since="">start(MessagePackage) -> void()</name>
+ <name since="">start(MessagePackage, Factor) -> void()</name>
<fsummary></fsummary>
<type>
<v>MessagePackage = message_package()</v>
@@ -63,9 +63,9 @@
</func>
<func>
- <name>start_flex() -> void()</name>
- <name>start_flex(MessagePackage) -> void()</name>
- <name>start_flex(MessagePackage, Factor) -> void()</name>
+ <name since="">start_flex() -> void()</name>
+ <name since="">start_flex(MessagePackage) -> void()</name>
+ <name since="">start_flex(MessagePackage, Factor) -> void()</name>
<fsummary></fsummary>
<type>
<v>MessagePackage = message_package()</v>
@@ -83,9 +83,9 @@
</func>
<func>
- <name>start_only_drv() -> void()</name>
- <name>start_only_drv(MessagePackage) -> void()</name>
- <name>start_only_drv(MessagePackage, Factor) -> void()</name>
+ <name since="">start_only_drv() -> void()</name>
+ <name since="">start_only_drv(MessagePackage) -> void()</name>
+ <name since="">start_only_drv(MessagePackage, Factor) -> void()</name>
<fsummary></fsummary>
<type>
<v>MessagePackage = message_package()</v>
@@ -105,9 +105,9 @@
</func>
<func>
- <name>start_no_drv() -> void()</name>
- <name>start_no_drv(MessagePackage) -> void()</name>
- <name>start_no_drv(MessagePackage, Factor) -> void()</name>
+ <name since="">start_no_drv() -> void()</name>
+ <name since="">start_no_drv(MessagePackage) -> void()</name>
+ <name since="">start_no_drv(MessagePackage, Factor) -> void()</name>
<fsummary></fsummary>
<type>
<v>MessagePackage = message_package()</v>
diff --git a/lib/megaco/doc/src/megaco_codec_mstone2.xml b/lib/megaco/doc/src/megaco_codec_mstone2.xml
index 3da30d4f99..03990f5c3d 100644
--- a/lib/megaco/doc/src/megaco_codec_mstone2.xml
+++ b/lib/megaco/doc/src/megaco_codec_mstone2.xml
@@ -32,7 +32,7 @@
<rev>%VSN%</rev>
<file>megaco_codec_mstone2.xml</file>
</header>
- <module>megaco_codec_mstone2</module>
+ <module since="">megaco_codec_mstone2</module>
<modulesummary>This module implements a simple megaco codec-based performance tool.</modulesummary>
<description>
<p>This module implements the <em>mstone2</em> tool,
@@ -44,8 +44,8 @@
<funcs>
<func>
- <name>start() -> void()</name>
- <name>start(MessagePackage) -> void()</name>
+ <name since="">start() -> void()</name>
+ <name since="">start(MessagePackage) -> void()</name>
<fsummary></fsummary>
<type>
<v>MessagePackage = message_package()</v>
diff --git a/lib/megaco/doc/src/megaco_codec_transform.xml b/lib/megaco/doc/src/megaco_codec_transform.xml
index 26b83c3799..392868fdfa 100644
--- a/lib/megaco/doc/src/megaco_codec_transform.xml
+++ b/lib/megaco/doc/src/megaco_codec_transform.xml
@@ -32,7 +32,7 @@
<rev>%VSN%</rev>
<file>megaco_codec_transform.xml</file>
</header>
- <module>megaco_codec_transform</module>
+ <module since="">megaco_codec_transform</module>
<modulesummary>Megaco message transformation utility.</modulesummary>
<description>
@@ -45,8 +45,8 @@
<funcs>
<func>
- <name>export_messages() -> void()</name>
- <name>export_messages(MessagePackage) -> void()</name>
+ <name since="">export_messages() -> void()</name>
+ <name since="">export_messages(MessagePackage) -> void()</name>
<fsummary></fsummary>
<type>
<v>MessagePackage = atom()</v>
diff --git a/lib/megaco/doc/src/megaco_edist_compress.xml b/lib/megaco/doc/src/megaco_edist_compress.xml
index d5c7c7224d..16443e469c 100644
--- a/lib/megaco/doc/src/megaco_edist_compress.xml
+++ b/lib/megaco/doc/src/megaco_edist_compress.xml
@@ -32,7 +32,7 @@
<rev>%VSN%</rev>
<file>megaco_edist_compress.xml</file>
</header>
- <module>megaco_edist_compress</module>
+ <module since="">megaco_edist_compress</module>
<modulesummary>Megaco erlang dist compress behaviour.</modulesummary>
<description>
<p>The following functions should be exported from a
@@ -40,7 +40,7 @@
</description>
<funcs>
<func>
- <name>Module:encode(R, Version) -> T</name>
+ <name since="">Module:encode(R, Version) -> T</name>
<fsummary>Encode (compress) a megaco component.</fsummary>
<type>
<v>R = megaco_message() | transaction() | action_reply() | action_request() | command_request()</v>
@@ -53,7 +53,7 @@
</desc>
</func>
<func>
- <name>Module:decode(T, Version) -> R</name>
+ <name since="">Module:decode(T, Version) -> R</name>
<fsummary>Decode (decompress) a megaco component.</fsummary>
<type>
<v>T = term()</v>
diff --git a/lib/megaco/doc/src/megaco_encoder.xml b/lib/megaco/doc/src/megaco_encoder.xml
index 13c6ed324b..cc8270440b 100644
--- a/lib/megaco/doc/src/megaco_encoder.xml
+++ b/lib/megaco/doc/src/megaco_encoder.xml
@@ -32,7 +32,7 @@
<rev>%VSN%</rev>
<file>megaco_encoder.xml</file>
</header>
- <module>megaco_encoder</module>
+ <module since="">megaco_encoder</module>
<modulesummary>Megaco encoder behaviour.</modulesummary>
<description>
<p>The following functions should be exported from a
@@ -64,7 +64,7 @@ action_reply() = #'ActionReply'{}
<funcs>
<func>
- <name>Module:encode_message(EncodingConfig, Version, Message) -> {ok, Bin} | Error</name>
+ <name since="">Module:encode_message(EncodingConfig, Version, Message) -> {ok, Bin} | Error</name>
<fsummary>Encode a megaco message.</fsummary>
<type>
<v>EncodingConfig = list()</v>
@@ -81,7 +81,7 @@ action_reply() = #'ActionReply'{}
</func>
<func>
- <name>Module:decode_message(EncodingConfig, Version, Bin) -> {ok, Message} | Error</name>
+ <name since="">Module:decode_message(EncodingConfig, Version, Bin) -> {ok, Message} | Error</name>
<fsummary>Decode a megaco message.</fsummary>
<type>
<v>EncodingConfig = list()</v>
@@ -104,7 +104,7 @@ action_reply() = #'ActionReply'{}
</func>
<func>
- <name>Module:decode_mini_message(EncodingConfig, Version, Bin) -> {ok, Message} | Error</name>
+ <name since="">Module:decode_mini_message(EncodingConfig, Version, Bin) -> {ok, Message} | Error</name>
<fsummary>Perform a minimal decode of a megaco message.</fsummary>
<type>
<v>EncodingConfig = list()</v>
@@ -129,7 +129,7 @@ action_reply() = #'ActionReply'{}
</func>
<func>
- <name>Module:encode_transaction(EncodingConfig, Version, Transaction) -> OK | Error</name>
+ <name since="">Module:encode_transaction(EncodingConfig, Version, Transaction) -> OK | Error</name>
<fsummary>Encode a megaco transaction.</fsummary>
<type>
<v>EncodingConfig = list()</v>
@@ -155,7 +155,7 @@ action_reply() = #'ActionReply'{}
</func>
<func>
- <name>Module:encode_action_requests(EncodingConfig, Version, ARs) -> OK | Error</name>
+ <name since="">Module:encode_action_requests(EncodingConfig, Version, ARs) -> OK | Error</name>
<fsummary>Encode megaco action requests.</fsummary>
<type>
<v>EncodingConfig = list()</v>
@@ -181,7 +181,7 @@ action_reply() = #'ActionReply'{}
</func>
<func>
- <name>Module:encode_action_reply(EncodingConfig, Version, AR) -> OK | Error</name>
+ <name since="">Module:encode_action_reply(EncodingConfig, Version, AR) -> OK | Error</name>
<fsummary>Encode a megaco action reply.</fsummary>
<type>
<v>EncodingConfig = list()</v>
diff --git a/lib/megaco/doc/src/megaco_flex_scanner.xml b/lib/megaco/doc/src/megaco_flex_scanner.xml
index 0856f3f429..121a7fbcff 100644
--- a/lib/megaco/doc/src/megaco_flex_scanner.xml
+++ b/lib/megaco/doc/src/megaco_flex_scanner.xml
@@ -32,7 +32,7 @@
<rev>%VSN%</rev>
<file>megaco_flex_scanner.xml</file>
</header>
- <module>megaco_flex_scanner</module>
+ <module since="">megaco_flex_scanner</module>
<modulesummary>Interface module to the flex scanner linked in driver.</modulesummary>
<description>
<p>This module contains the public interface to the flex scanner
@@ -72,7 +72,7 @@ megaco_version() = integer() >= 1
<funcs>
<func>
- <name>start() -> {ok, PortOrPorts} | {error, Reason}</name>
+ <name since="">start() -> {ok, PortOrPorts} | {error, Reason}</name>
<fsummary></fsummary>
<type>
<v>PortOrPorts = megaco_ports()</v>
@@ -94,7 +94,7 @@ megaco_version() = integer() >= 1
</func>
<func>
- <name>stop(PortOrPorts) -> stopped</name>
+ <name since="">stop(PortOrPorts) -> stopped</name>
<fsummary></fsummary>
<type>
<v>PortOrPorts = megaco_ports()</v>
@@ -108,7 +108,7 @@ megaco_version() = integer() >= 1
</func>
<func>
- <name>is_reentrant_enabled() -> Boolean</name>
+ <name since="">is_reentrant_enabled() -> Boolean</name>
<fsummary></fsummary>
<type>
<v>Boolean = boolean()</v>
@@ -121,7 +121,7 @@ megaco_version() = integer() >= 1
</func>
<func>
- <name>is_scanner_port(Port, PortOrPorts) -> Boolean</name>
+ <name since="">is_scanner_port(Port, PortOrPorts) -> Boolean</name>
<fsummary></fsummary>
<type>
<v>Port = port()</v>
@@ -137,7 +137,7 @@ megaco_version() = integer() >= 1
</func>
<func>
- <name>scan(Binary, PortOrPorts) -> {ok, Tokens, Version, LatestLine} | {error, Reason, LatestLine} </name>
+ <name since="">scan(Binary, PortOrPorts) -> {ok, Tokens, Version, LatestLine} | {error, Reason, LatestLine} </name>
<fsummary></fsummary>
<type>
<v>Binary = binary()</v>
diff --git a/lib/megaco/doc/src/megaco_tcp.xml b/lib/megaco/doc/src/megaco_tcp.xml
index 77aee32f6c..63713b2c56 100644
--- a/lib/megaco/doc/src/megaco_tcp.xml
+++ b/lib/megaco/doc/src/megaco_tcp.xml
@@ -32,7 +32,7 @@
<rev>%VSN%</rev>
<file>megaco_tcp.xml</file>
</header>
- <module>megaco_tcp</module>
+ <module since="">megaco_tcp</module>
<modulesummary>Interface module to TPKT transport protocol for Megaco/H.248.</modulesummary>
<description>
<p>This module contains the public interface to the TPKT (TCP/IP) version
@@ -40,7 +40,7 @@
</description>
<funcs>
<func>
- <name>start_transport() -> {ok, TransportRef}</name>
+ <name since="">start_transport() -> {ok, TransportRef}</name>
<fsummary></fsummary>
<type>
<v>TransportRef = pid()</v>
@@ -51,7 +51,7 @@
</desc>
</func>
<func>
- <name>listen(TransportRef, ListenPortSpecList) -> ok</name>
+ <name since="">listen(TransportRef, ListenPortSpecList) -> ok</name>
<fsummary></fsummary>
<type>
<v>TransportRef = pid() | regname()</v>
@@ -65,7 +65,7 @@
</desc>
</func>
<func>
- <name>connect(TransportRef, OptionList) -> {ok, Handle, ControlPid} | {error, Reason}</name>
+ <name since="">connect(TransportRef, OptionList) -> {ok, Handle, ControlPid} | {error, Reason}</name>
<fsummary></fsummary>
<type>
<v>TransportRef = pid() | regname()</v>
@@ -86,7 +86,7 @@
</desc>
</func>
<func>
- <name>close(Handle) -> ok</name>
+ <name since="">close(Handle) -> ok</name>
<fsummary></fsummary>
<type>
<v>Handle = socket_handle()</v>
@@ -96,7 +96,7 @@
</desc>
</func>
<func>
- <name>socket(Handle) -> Socket</name>
+ <name since="">socket(Handle) -> Socket</name>
<fsummary></fsummary>
<type>
<v>Handle = socket_handle()</v>
@@ -109,7 +109,7 @@
</desc>
</func>
<func>
- <name>send_message(Handle, Message) -> ok</name>
+ <name since="">send_message(Handle, Message) -> ok</name>
<fsummary></fsummary>
<type>
<v>Handle = socket_handle()</v>
@@ -120,7 +120,7 @@
</desc>
</func>
<func>
- <name>block(Handle) -> ok</name>
+ <name since="">block(Handle) -> ok</name>
<fsummary></fsummary>
<type>
<v>Handle = socket_handle()</v>
@@ -130,7 +130,7 @@
</desc>
</func>
<func>
- <name>unblock(Handle) -> ok</name>
+ <name since="">unblock(Handle) -> ok</name>
<fsummary></fsummary>
<type>
<v>Handle = socket_handle()</v>
@@ -141,7 +141,7 @@
</desc>
</func>
<func>
- <name>upgrade_receive_handle(ControlPid) -> ok</name>
+ <name since="">upgrade_receive_handle(ControlPid) -> ok</name>
<fsummary></fsummary>
<type>
<v>ControlPid = pid()</v>
@@ -153,9 +153,9 @@
</desc>
</func>
<func>
- <name>get_stats() -> {ok, TotalStats} | {error, Reason}</name>
- <name>get_stats(SendHandle) -> {ok, SendHandleStats} | {error, Reason}</name>
- <name>get_stats(SendHandle, Counter) -> {ok, CounterStats} | {error, Reason}</name>
+ <name since="">get_stats() -> {ok, TotalStats} | {error, Reason}</name>
+ <name since="">get_stats(SendHandle) -> {ok, SendHandleStats} | {error, Reason}</name>
+ <name since="">get_stats(SendHandle, Counter) -> {ok, CounterStats} | {error, Reason}</name>
<fsummary></fsummary>
<type>
<v>TotalStats = [send_handle_stats()]</v>
@@ -173,8 +173,8 @@
</desc>
</func>
<func>
- <name>reset_stats() -> void()</name>
- <name>reset_stats(SendHandle) -> void()</name>
+ <name since="">reset_stats() -> void()</name>
+ <name since="">reset_stats(SendHandle) -> void()</name>
<fsummary></fsummary>
<type>
<v>SendHandle = send_handle()</v>
diff --git a/lib/megaco/doc/src/megaco_transport.xml b/lib/megaco/doc/src/megaco_transport.xml
index 3002e9b74e..ba8c794750 100644
--- a/lib/megaco/doc/src/megaco_transport.xml
+++ b/lib/megaco/doc/src/megaco_transport.xml
@@ -32,7 +32,7 @@
<rev>%VSN%</rev>
<file>megaco_transport.xml</file>
</header>
- <module>megaco_transport</module>
+ <module since="">megaco_transport</module>
<modulesummary>Megaco transport behaviour.</modulesummary>
<description>
<p>The following functions should be exported from a
@@ -54,8 +54,8 @@
</description>
<funcs>
<func>
- <name>Module:send_message(Handle, Msg) -> ok | {cancel, Reason} | Error</name>
- <name>Module:send_message(Handle, Msg, Resend) -> ok | {cancel, Reason} | Error</name>
+ <name since="">Module:send_message(Handle, Msg) -> ok | {cancel, Reason} | Error</name>
+ <name since="">Module:send_message(Handle, Msg, Resend) -> ok | {cancel, Reason} | Error</name>
<fsummary>Send a megaco message.</fsummary>
<type>
<v>Handle = term()</v>
@@ -99,7 +99,7 @@
</func>
<func>
- <name>Module:resend_message(Handle, Msg) -> ok | {cancel, Reason} | Error</name>
+ <name since="">Module:resend_message(Handle, Msg) -> ok | {cancel, Reason} | Error</name>
<fsummary>Re-send a megaco message.</fsummary>
<type>
<v>Handle = term()</v>
diff --git a/lib/megaco/doc/src/megaco_udp.xml b/lib/megaco/doc/src/megaco_udp.xml
index b2559c77d5..3d776c19b6 100644
--- a/lib/megaco/doc/src/megaco_udp.xml
+++ b/lib/megaco/doc/src/megaco_udp.xml
@@ -32,7 +32,7 @@
<rev>%VSN%</rev>
<file>megaco_udp.xml</file>
</header>
- <module>megaco_udp</module>
+ <module since="">megaco_udp</module>
<modulesummary>Interface module to UDP transport protocol for Megaco/H.248.</modulesummary>
<description>
<p>This module contains the public interface to the UDP/IP version
@@ -40,7 +40,7 @@
</description>
<funcs>
<func>
- <name>start_transport() -> {ok, TransportRef}</name>
+ <name since="">start_transport() -> {ok, TransportRef}</name>
<fsummary></fsummary>
<type>
<v>TransportRef = pid()</v>
@@ -51,7 +51,7 @@
</desc>
</func>
<func>
- <name>open(TransportRef, OptionList) -> {ok, Handle, ControlPid} | {error, Reason}</name>
+ <name since="">open(TransportRef, OptionList) -> {ok, Handle, ControlPid} | {error, Reason}</name>
<fsummary></fsummary>
<type>
<v>TransportRef = pid() | regname()</v>
@@ -73,7 +73,7 @@
</desc>
</func>
<func>
- <name>close(Handle, Msg) -> ok</name>
+ <name since="">close(Handle, Msg) -> ok</name>
<fsummary></fsummary>
<type>
<v>Handle = socket_handle()</v>
@@ -84,7 +84,7 @@
</desc>
</func>
<func>
- <name>socket(Handle) -> Socket</name>
+ <name since="">socket(Handle) -> Socket</name>
<fsummary></fsummary>
<type>
<v>Handle = socket_handle()</v>
@@ -97,7 +97,7 @@
</desc>
</func>
<func>
- <name>create_send_handle(Handle, Host, Port) -> send_handle()</name>
+ <name since="">create_send_handle(Handle, Host, Port) -> send_handle()</name>
<fsummary></fsummary>
<type>
<v>Handle = socket_handle()</v>
@@ -110,7 +110,7 @@
</desc>
</func>
<func>
- <name>send_message(SendHandle, Msg) -> ok</name>
+ <name since="">send_message(SendHandle, Msg) -> ok</name>
<fsummary></fsummary>
<type>
<v>SendHandle = send_handle()</v>
@@ -125,7 +125,7 @@
</desc>
</func>
<func>
- <name>block(Handle) -> ok</name>
+ <name since="">block(Handle) -> ok</name>
<fsummary></fsummary>
<type>
<v>Handle = socket_handle()</v>
@@ -135,7 +135,7 @@
</desc>
</func>
<func>
- <name>unblock(Handle) -> ok</name>
+ <name since="">unblock(Handle) -> ok</name>
<fsummary></fsummary>
<type>
<v>Handle = socket_handle()</v>
@@ -146,7 +146,7 @@
</desc>
</func>
<func>
- <name>upgrade_receive_handle(ControlPid, NewHandle) -> ok</name>
+ <name since="">upgrade_receive_handle(ControlPid, NewHandle) -> ok</name>
<fsummary></fsummary>
<type>
<v>ControlPid = pid()</v>
@@ -160,9 +160,9 @@
</desc>
</func>
<func>
- <name>get_stats() -> {ok, TotalStats} | {error, Reason}</name>
- <name>get_stats(SendHandle) -> {ok, SendHandleStats} | {error, Reason}</name>
- <name>get_stats(SendHandle, Counter) -> {ok, CounterStats} | {error, Reason}</name>
+ <name since="">get_stats() -> {ok, TotalStats} | {error, Reason}</name>
+ <name since="">get_stats(SendHandle) -> {ok, SendHandleStats} | {error, Reason}</name>
+ <name since="">get_stats(SendHandle, Counter) -> {ok, CounterStats} | {error, Reason}</name>
<fsummary></fsummary>
<type>
<v>TotalStats = [total_stats()]</v>
@@ -180,8 +180,8 @@
</desc>
</func>
<func>
- <name>reset_stats() -> void()</name>
- <name>reset_stats(SendHandle) -> void()</name>
+ <name since="">reset_stats() -> void()</name>
+ <name since="">reset_stats(SendHandle) -> void()</name>
<fsummary></fsummary>
<type>
<v>SendHandle = send_handle()</v>
diff --git a/lib/megaco/doc/src/megaco_user.xml b/lib/megaco/doc/src/megaco_user.xml
index 067be15fe0..198f2aa24c 100644
--- a/lib/megaco/doc/src/megaco_user.xml
+++ b/lib/megaco/doc/src/megaco_user.xml
@@ -32,7 +32,7 @@
<rev>%VSN%</rev>
<file>megaco_user.xml</file>
</header>
- <module>megaco_user</module>
+ <module since="">megaco_user</module>
<modulesummary>Callback module for users of the Megaco application</modulesummary>
<description>
<p>This module defines the callback behaviour of Megaco users. A
@@ -164,8 +164,8 @@ protocol_version() = integer() ]]></code>
<funcs>
<func>
- <name>handle_connect(ConnHandle, ProtocolVersion) -> ok | error | {error,ErrorDescr}</name>
- <name>handle_connect(ConnHandle, ProtocolVersion, Extra]) -> ok | error | {error,ErrorDescr}</name>
+ <name since="">handle_connect(ConnHandle, ProtocolVersion) -> ok | error | {error,ErrorDescr}</name>
+ <name since="">handle_connect(ConnHandle, ProtocolVersion, Extra]) -> ok | error | {error,ErrorDescr}</name>
<fsummary>Invoked when a new connection is established</fsummary>
<type>
<v>ConnHandle = conn_handle()</v>
@@ -202,7 +202,7 @@ protocol_version() = integer() ]]></code>
</func>
<func>
- <name>handle_disconnect(ConnHandle, ProtocolVersion, Reason) -> ok</name>
+ <name since="">handle_disconnect(ConnHandle, ProtocolVersion, Reason) -> ok</name>
<fsummary>Invoked when a connection is teared down</fsummary>
<type>
<v>ConnHandle = conn_handle()</v>
@@ -220,8 +220,8 @@ protocol_version() = integer() ]]></code>
</func>
<func>
- <name>handle_syntax_error(ReceiveHandle, ProtocolVersion, DefaultED) -> reply | {reply, ED} | no_reply | {no_reply, ED} </name>
- <name>handle_syntax_error(ReceiveHandle, ProtocolVersion, DefaultED, Extra) -> reply | {reply, ED} | no_reply | {no_reply, ED} </name>
+ <name since="">handle_syntax_error(ReceiveHandle, ProtocolVersion, DefaultED) -> reply | {reply, ED} | no_reply | {no_reply, ED} </name>
+ <name since="">handle_syntax_error(ReceiveHandle, ProtocolVersion, DefaultED, Extra) -> reply | {reply, ED} | no_reply | {no_reply, ED} </name>
<fsummary>Invoked when a received message had syntax errors</fsummary>
<type>
<v>ReceiveHandle = receive_handle()</v>
@@ -258,8 +258,8 @@ protocol_version() = integer() ]]></code>
</func>
<func>
- <name>handle_message_error(ConnHandle, ProtocolVersion, ErrorDescr) -> ok</name>
- <name>handle_message_error(ConnHandle, ProtocolVersion, ErrorDescr, Extra) -> ok</name>
+ <name since="">handle_message_error(ConnHandle, ProtocolVersion, ErrorDescr) -> ok</name>
+ <name since="">handle_message_error(ConnHandle, ProtocolVersion, ErrorDescr, Extra) -> ok</name>
<fsummary>Invoked when a received message just contains an error</fsummary>
<type>
<v>ConnHandle = conn_handle()</v>
@@ -291,8 +291,8 @@ protocol_version() = integer() ]]></code>
<!--
<func>
- <name>handle_segment_error(ConnHandle, ProtocolVersion, TransId, SegmentError) -> ok</name>
- <name>handle_segment_error(ConnHandle, ProtocolVersion, TransId, SegmentError, Extra) -> ok</name>
+ <name since="">handle_segment_error(ConnHandle, ProtocolVersion, TransId, SegmentError) -> ok</name>
+ <name since="">handle_segment_error(ConnHandle, ProtocolVersion, TransId, SegmentError, Extra) -> ok</name>
<fsummary>Invoked when a segment error has been detected</fsummary>
<type>
<v>ConnHandle = conn_handle()</v>
@@ -316,8 +316,8 @@ protocol_version() = integer() ]]></code>
-->
<func>
- <name>handle_trans_request(ConnHandle, ProtocolVersion, ActionRequests) -> pending() | reply() | ignore_trans_request</name>
- <name>handle_trans_request(ConnHandle, ProtocolVersion, ActionRequests, Extra) -> pending() | reply() | ignore_trans_request</name>
+ <name since="">handle_trans_request(ConnHandle, ProtocolVersion, ActionRequests) -> pending() | reply() | ignore_trans_request</name>
+ <name since="">handle_trans_request(ConnHandle, ProtocolVersion, ActionRequests, Extra) -> pending() | reply() | ignore_trans_request</name>
<fsummary>Invoked for each transaction request</fsummary>
<type>
<v>ConnHandle = conn_handle()</v>
@@ -420,8 +420,8 @@ protocol_version() = integer() ]]></code>
</func>
<func>
- <name>handle_trans_long_request(ConnHandle, ProtocolVersion, ReqData) -> reply()</name>
- <name>handle_trans_long_request(ConnHandle, ProtocolVersion, ReqData, Extra) -> reply()</name>
+ <name since="">handle_trans_long_request(ConnHandle, ProtocolVersion, ReqData) -> reply()</name>
+ <name since="">handle_trans_long_request(ConnHandle, ProtocolVersion, ReqData, Extra) -> reply()</name>
<fsummary>Optionally invoked for a time consuming transaction request</fsummary>
<type>
<v>ConnHandle = conn_handle()</v>
@@ -460,8 +460,8 @@ protocol_version() = integer() ]]></code>
</func>
<func>
- <name>handle_trans_reply(ConnHandle, ProtocolVersion, UserReply, ReplyData) -> ok</name>
- <name>handle_trans_reply(ConnHandle, ProtocolVersion, UserReply, ReplyData, Extra) -> ok</name>
+ <name since="">handle_trans_reply(ConnHandle, ProtocolVersion, UserReply, ReplyData) -> ok</name>
+ <name since="">handle_trans_reply(ConnHandle, ProtocolVersion, UserReply, ReplyData, Extra) -> ok</name>
<fsummary>Optionally invoked for a transaction reply</fsummary>
<type>
<v>ConnHandle = conn_handle()</v>
@@ -593,8 +593,8 @@ protocol_version() = integer() ]]></code>
</func>
<func>
- <name>handle_trans_ack(ConnHandle, ProtocolVersion, AckStatus, AckData) -> ok</name>
- <name>handle_trans_ack(ConnHandle, ProtocolVersion, AckStatus, AckData, Extra) -> ok</name>
+ <name since="">handle_trans_ack(ConnHandle, ProtocolVersion, AckStatus, AckData) -> ok</name>
+ <name since="">handle_trans_ack(ConnHandle, ProtocolVersion, AckStatus, AckData, Extra) -> ok</name>
<fsummary>Optionally invoked for a transaction acknowledgement</fsummary>
<type>
<v>ConnHandle = conn_handle()</v>
@@ -658,8 +658,8 @@ protocol_version() = integer() ]]></code>
</func>
<func>
- <name>handle_unexpected_trans(ConnHandle, ProtocolVersion, Trans) -> ok</name>
- <name>handle_unexpected_trans(ConnHandle, ProtocolVersion, Trans, Extra) -> ok</name>
+ <name since="">handle_unexpected_trans(ConnHandle, ProtocolVersion, Trans) -> ok</name>
+ <name since="">handle_unexpected_trans(ConnHandle, ProtocolVersion, Trans, Extra) -> ok</name>
<fsummary>Invoked when an unexpected message is received</fsummary>
<type>
<v>ConnHandle = conn_handle()</v>
@@ -685,8 +685,8 @@ protocol_version() = integer() ]]></code>
</func>
<func>
- <name>handle_trans_request_abort(ConnHandle, ProtocolVersion, TransNo, Pid) -> ok</name>
- <name>handle_trans_request_abort(ConnHandle, ProtocolVersion, TransNo, Pid, Extra) -> ok</name>
+ <name since="">handle_trans_request_abort(ConnHandle, ProtocolVersion, TransNo, Pid) -> ok</name>
+ <name since="">handle_trans_request_abort(ConnHandle, ProtocolVersion, TransNo, Pid, Extra) -> ok</name>
<fsummary>Invoked when an transaction request has been aborted</fsummary>
<type>
<v>ConnHandle = conn_handle()</v>
@@ -710,8 +710,8 @@ protocol_version() = integer() ]]></code>
</func>
<func>
- <name>handle_segment_reply(ConnHandle, ProtocolVersion, TransNo, SegNo, SegCompl) -> ok</name>
- <name>handle_segment_reply(ConnHandle, ProtocolVersion, TransNo, SegNo, SegCompl, Extra) -> ok</name>
+ <name since="">handle_segment_reply(ConnHandle, ProtocolVersion, TransNo, SegNo, SegCompl) -> ok</name>
+ <name since="">handle_segment_reply(ConnHandle, ProtocolVersion, TransNo, SegNo, SegCompl, Extra) -> ok</name>
<fsummary>Segment Reply Indication</fsummary>
<type>
<v>ConnHandle = conn_handle()</v>
diff --git a/lib/megaco/doc/src/notes.xml b/lib/megaco/doc/src/notes.xml
index 54e048a172..6f33ae390c 100644
--- a/lib/megaco/doc/src/notes.xml
+++ b/lib/megaco/doc/src/notes.xml
@@ -37,7 +37,45 @@
section is the version number of Megaco.</p>
- <section><title>Megaco 3.18.3</title>
+ <section><title>Megaco 3.18.5</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Minor updates to build system necessary due to move of
+ configuration of <c>crypto</c> application.</p>
+ <p>
+ Own Id: OTP-15262 Aux Id: OTP-15129 </p>
+ </item>
+ <item>
+ <p>
+ Minor adjustments made to build system for parallel
+ configure.</p>
+ <p>
+ Own Id: OTP-15340 Aux Id: OTP-14625 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Megaco 3.18.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Megaco 3.18.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/megaco/src/flex/Makefile.in b/lib/megaco/src/flex/Makefile.in
index c37ad4d702..26d2ddd44c 100644
--- a/lib/megaco/src/flex/Makefile.in
+++ b/lib/megaco/src/flex/Makefile.in
@@ -31,25 +31,6 @@ include ../../vsn.mk
VSN=$(MEGACO_VSN)
# ----------------------------------------------------
-# Dynamic Erlang Driver
-# ----------------------------------------------------
-HAVE_USABLE_OTP_DED_MK = @HAVE_USABLE_OTP_DED_MK@
-
-ifeq ($(HAVE_USABLE_OTP_DED_MK),yes)
-# otp_ded.mk will be used on R13B04 and later
-include $(ERL_TOP)/make/$(TARGET)/otp_ded.mk
-else
-# megacos configure provide the info instead
-DED_CC = @CC@
-DED__NOWARN_NOTHR_CFLAGS = @DED_CFLAGS@
-DED_THR_DEFS = @DED_THR_DEFS@
-DED_LD = @DED_LD@
-DED_LDFLAGS = @DED_LDFLAGS@
-DED_INCLUDES = @DED_INCLUDES@
-DED_EXT = so
-endif
-
-# ----------------------------------------------------
# The following variables differ on different systems, we set
# reasonable defaults, if something different is needed it should
# be set for that system only.
@@ -57,20 +38,19 @@ endif
FLEX_VSN = $(shell flex --version)
-TMP_CFLAGS = $(DED__NOWARN_NOTHR_CFLAGS) @OTP_EXTRA_FLAGS@
+TMP_CFLAGS = @DED_BASIC_CFLAGS@ @OTP_EXTRA_FLAGS@
ifeq ($(TYPE),valgrind)
CFLAGS = $(subst -O2, , $(TMP_CFLAGS)) -DVALGRIND
else
CFLAGS = $(TMP_CFLAGS)
endif
-CC = $(DED_CC)
-CFLAGS_MT = $(CFLAGS) $(DED_THR_DEFS)
-LD = $(DED_LD)
-LDFLAGS = $(DED_LDFLAGS)
+CC = @DED_CC@
+CFLAGS_MT = $(CFLAGS) @DED_THR_DEFS@
+LD = @DED_LD@
+LDFLAGS = @DED_LDFLAGS@
LEX = @LEX@
LEXLIB = @LEXLIB@
PERL = @PERL@
-ERLANG_OSTYPE = @ERLANG_OSTYPE@
# Shall we build the flex scanner or not.
# We assume that it does not exist on windows...
@@ -143,8 +123,8 @@ ifeq ($(findstring win32,$(TARGET)), win32)
FLEX_SCANNER_SO =
SOLIBS = $(FLEX_SCANNER_SO)
else
-FLEX_SCANNER_SO = $(LIBDIR)/$(STD_DRV).$(DED_EXT)
-FLEX_SCANNER_MT_SO = $(LIBDIR)/$(MT_DRV).$(DED_EXT)
+FLEX_SCANNER_SO = $(LIBDIR)/$(STD_DRV).@DED_EXT@
+FLEX_SCANNER_MT_SO = $(LIBDIR)/$(MT_DRV).@DED_EXT@
SOLIBS = $(FLEX_SCANNER_SO) $(FLEX_SCANNER_MT_SO)
endif
@@ -179,7 +159,7 @@ else
CFLAGS += -DMFS_FLEX_DEBUG=0
endif
-CFLAGS += $(DED_INCLUDES) -I$(ERL_TOP)/erts/$(TARGET) $(DRV_FLAGS) -funroll-loops -Wall
+CFLAGS += @DED_INCLUDE@ -I$(ERL_TOP)/erts/$(TARGET) $(DRV_FLAGS) -funroll-loops -Wall
#ifneq ($(FLEX_VSN),)
#CFLAGS += -DFLEX_VERSION="$(FLEX_VSN)"
@@ -398,10 +378,10 @@ $(OBJDIR)/$(MT_DRV).o: $(MT_DRV).c
# No need to link with -lfl as we have also defined %option noyywrap -
# and having -lfl doesn't work under Darwin for some reason. - Sean
-$(LIBDIR)/$(STD_DRV).$(DED_EXT): $(OBJDIR)/$(STD_DRV).o
+$(LIBDIR)/$(STD_DRV).@DED_EXT@: $(OBJDIR)/$(STD_DRV).o
$(V_colon)@echo "linking std driver:"
$(V_LD) $(LDFLAGS) -o $@ $<
-$(LIBDIR)/$(MT_DRV).$(DED_EXT): $(OBJDIR)/$(MT_DRV).o
+$(LIBDIR)/$(MT_DRV).@DED_EXT@: $(OBJDIR)/$(MT_DRV).o
$(V_colon)@echo "linking multi-threaded driver:"
$(V_LD) $(LDFLAGS) -o $@ $<
diff --git a/lib/megaco/vsn.mk b/lib/megaco/vsn.mk
index a4f7de7f07..843a3dccc5 100644
--- a/lib/megaco/vsn.mk
+++ b/lib/megaco/vsn.mk
@@ -19,6 +19,6 @@
# %CopyrightEnd%
APPLICATION = megaco
-MEGACO_VSN = 3.18.3
+MEGACO_VSN = 3.18.5
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(MEGACO_VSN)$(PRE_VSN)"
diff --git a/lib/mnesia/doc/src/Makefile b/lib/mnesia/doc/src/Makefile
index 82fcf66256..d9647fc081 100644
--- a/lib/mnesia/doc/src/Makefile
+++ b/lib/mnesia/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2017. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -49,16 +49,18 @@ XML_PART_FILES = \
XML_CHAPTER_FILES = \
Mnesia_chap1.xml \
Mnesia_overview.xml \
+ Mnesia_chap8.xml \
+ notes.xml
+
+XML_CHAPTER_GEN_FILES = \
Mnesia_chap2.xml \
Mnesia_chap3.xml \
Mnesia_chap4.xml \
Mnesia_chap5.xml \
Mnesia_chap7.xml \
- Mnesia_chap8.xml \
Mnesia_App_A.xml \
Mnesia_App_B.xml \
- Mnesia_App_C.xml \
- notes.xml
+ Mnesia_App_C.xml
BOOK_FILES = book.xml
@@ -66,6 +68,8 @@ XML_FILES = \
$(BOOK_FILES) $(XML_CHAPTER_FILES) \
$(XML_PART_FILES) $(XML_REF3_FILES) $(XML_APPLICATION_FILES)
+XML_GEN_FILES = $(XML_CHAPTER_GEN_FILES:%=$(XMLDIR)/%)
+
GIF_FILES = \
company.gif
@@ -114,6 +118,7 @@ html: gifs $(HTML_REF_MAN_FILE)
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/lib/mnesia/doc/src/Mnesia_chap2.xmlsrc b/lib/mnesia/doc/src/Mnesia_chap2.xmlsrc
index 914e0e509c..8135e14301 100644
--- a/lib/mnesia/doc/src/Mnesia_chap2.xmlsrc
+++ b/lib/mnesia/doc/src/Mnesia_chap2.xmlsrc
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/mnesia/doc/src/Mnesia_chap5.xmlsrc b/lib/mnesia/doc/src/Mnesia_chap5.xmlsrc
index 62759c624b..481e6651e6 100644
--- a/lib/mnesia/doc/src/Mnesia_chap5.xmlsrc
+++ b/lib/mnesia/doc/src/Mnesia_chap5.xmlsrc
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -226,8 +226,10 @@
not known beforehand, all fragments are searched for
matching records.</p>
<p>Notice that in <c>ordered_set</c> tables, the records
- are ordered per fragment, and the the order is undefined in
- results returned by <c>select</c> and <c>match_object</c>.</p>
+ are ordered per fragment, and the order is undefined in
+ results returned by <c>select</c> and <c>match_object</c>,
+ as well as <c>first</c>, <c>next</c>, <c>prev</c> and
+ <c>last</c>.</p>
<p>The following code illustrates how a <c>Mnesia</c> table is
converted to be a fragmented table and how more fragments
are added later:</p>
diff --git a/lib/mnesia/doc/src/company.erl b/lib/mnesia/doc/src/company.erl
index 5a3b122394..fc04aa77bf 100644
--- a/lib/mnesia/doc/src/company.erl
+++ b/lib/mnesia/doc/src/company.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/doc/src/company_o.erl b/lib/mnesia/doc/src/company_o.erl
index 650b6cdeca..b4b3638596 100644
--- a/lib/mnesia/doc/src/company_o.erl
+++ b/lib/mnesia/doc/src/company_o.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/doc/src/mnesia.xml b/lib/mnesia/doc/src/mnesia.xml
index 621b6047ee..11b0b8e987 100644
--- a/lib/mnesia/doc/src/mnesia.xml
+++ b/lib/mnesia/doc/src/mnesia.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file></file>
</header>
- <module>mnesia</module>
+ <module since="">mnesia</module>
<modulesummary>A distributed telecommunications DBMS</modulesummary>
<description>
@@ -183,7 +183,7 @@
<funcs>
<func>
- <name>abort(Reason) -> transaction abort</name>
+ <name since="">abort(Reason) -> transaction abort</name>
<fsummary>Terminates the current transaction.</fsummary>
<desc>
<p>Makes the transaction silently
@@ -195,7 +195,7 @@
</desc>
</func>
<func>
- <name>activate_checkpoint(Args) -> {ok,Name,Nodes} | {error,Reason}</name>
+ <name since="">activate_checkpoint(Args) -> {ok,Name,Nodes} | {error,Reason}</name>
<fsummary>Activates a checkpoint.</fsummary>
<desc>
<marker id="activate_checkpoint"></marker>
@@ -259,7 +259,7 @@
</desc>
</func>
<func>
- <name>activity(AccessContext, Fun [, Args]) -> ResultOfFun | exit(Reason)</name>
+ <name since="">activity(AccessContext, Fun [, Args]) -> ResultOfFun | exit(Reason)</name>
<fsummary>Executes <c>Fun</c> in <c>AccessContext</c>.</fsummary>
<desc>
<marker id="activity_2_3"></marker>
@@ -271,7 +271,7 @@
</desc>
</func>
<func>
- <name>activity(AccessContext, Fun, Args, AccessMod) -> ResultOfFun | exit(Reason)</name>
+ <name since="">activity(AccessContext, Fun, Args, AccessMod) -> ResultOfFun | exit(Reason)</name>
<fsummary>Executes <c>Fun</c> in <c>AccessContext</c>.</fsummary>
<desc>
<marker id="activity_4"></marker>
@@ -403,7 +403,7 @@
</desc>
</func>
<func>
- <name>add_table_copy(Tab, Node, Type) -> {aborted, R} | {atomic, ok}</name>
+ <name since="">add_table_copy(Tab, Node, Type) -> {aborted, R} | {atomic, ok}</name>
<fsummary>Copies a table to a remote node.</fsummary>
<desc>
<marker id="add_table_copy"></marker>
@@ -420,7 +420,7 @@ mnesia:add_table_copy(person, Node, disc_copies)</code>
</desc>
</func>
<func>
- <name>add_table_index(Tab, AttrName) -> {aborted, R} | {atomic, ok}</name>
+ <name since="">add_table_index(Tab, AttrName) -> {aborted, R} | {atomic, ok}</name>
<fsummary>Creates an index for a table.</fsummary>
<desc>
<marker id="add_table_index"></marker>
@@ -441,7 +441,7 @@ mnesia:add_table_index(person, age)</code>
</desc>
</func>
<func>
- <name>all_keys(Tab) -> KeyList | transaction abort</name>
+ <name since="">all_keys(Tab) -> KeyList | transaction abort</name>
<fsummary>Returns all keys in a table.</fsummary>
<desc>
<marker id="all_keys"></marker>
@@ -453,7 +453,7 @@ mnesia:add_table_index(person, age)</code>
</desc>
</func>
<func>
- <name>async_dirty(Fun, [, Args]) -> ResultOfFun | exit(Reason)</name>
+ <name since="">async_dirty(Fun, [, Args]) -> ResultOfFun | exit(Reason)</name>
<fsummary>Calls the <c>Fun</c> in a context that is not protected by a transaction.</fsummary>
<desc>
<marker id="async_dirty"></marker>
@@ -493,7 +493,7 @@ mnesia:add_table_index(person, age)</code>
</desc>
</func>
<func>
- <name>backup(Opaque [, BackupMod]) -> ok | {error,Reason}</name>
+ <name since="">backup(Opaque [, BackupMod]) -> ok | {error,Reason}</name>
<fsummary>Backs up all tables in the database.</fsummary>
<desc>
<marker id="backup"></marker>
@@ -505,7 +505,7 @@ mnesia:add_table_index(person, age)</code>
</desc>
</func>
<func>
- <name>backup_checkpoint(Name, Opaque [, BackupMod]) -> ok | {error,Reason}</name>
+ <name since="">backup_checkpoint(Name, Opaque [, BackupMod]) -> ok | {error,Reason}</name>
<fsummary>Backs up all tables in a checkpoint.</fsummary>
<desc>
<marker id="backup_checkpoint"></marker>
@@ -520,7 +520,7 @@ mnesia:add_table_index(person, age)</code>
</desc>
</func>
<func>
- <name>change_config(Config, Value) -> {error, Reason} | {ok, ReturnValue}</name>
+ <name since="">change_config(Config, Value) -> {error, Reason} | {ok, ReturnValue}</name>
<fsummary>Changes a configuration parameter.</fsummary>
<desc>
<marker id="change_config"></marker>
@@ -554,7 +554,7 @@ mnesia:add_table_index(person, age)</code>
</desc>
</func>
<func>
- <name>change_table_access_mode(Tab, AccessMode) -> {aborted, R} | {atomic, ok}</name>
+ <name since="">change_table_access_mode(Tab, AccessMode) -> {aborted, R} | {atomic, ok}</name>
<fsummary>Changes the access mode for the table.</fsummary>
<desc>
<marker id="change_table_access_mode"></marker>
@@ -568,7 +568,7 @@ mnesia:add_table_index(person, age)</code>
</desc>
</func>
<func>
- <name>change_table_copy_type(Tab, Node, To) -> {aborted, R} | {atomic, ok}</name>
+ <name since="">change_table_copy_type(Tab, Node, To) -> {aborted, R} | {atomic, ok}</name>
<fsummary>Changes the storage type of a table.</fsummary>
<desc>
<marker id="change_table_copy_type"></marker>
@@ -585,7 +585,7 @@ mnesia:change_table_copy_type(person, node(), disc_copies)</code>
</desc>
</func>
<func>
- <name>change_table_load_order(Tab, LoadOrder) -> {aborted, R} | {atomic, ok}</name>
+ <name since="">change_table_load_order(Tab, LoadOrder) -> {aborted, R} | {atomic, ok}</name>
<fsummary>Changes the load order priority for the table.</fsummary>
<desc>
<marker id="change_table_load_order"></marker>
@@ -595,7 +595,7 @@ mnesia:change_table_copy_type(person, node(), disc_copies)</code>
</desc>
</func>
<func>
- <name>change_table_majority(Tab, Majority) -> {aborted, R} | {atomic, ok}</name>
+ <name since="OTP R14B03">change_table_majority(Tab, Majority) -> {aborted, R} | {atomic, ok}</name>
<fsummary>Changes the majority check setting for the table.</fsummary>
<desc>
<p><c>Majority</c> must be a boolean. Default is <c>false</c>.
@@ -607,7 +607,7 @@ mnesia:change_table_copy_type(person, node(), disc_copies)</code>
</desc>
</func>
<func>
- <name>clear_table(Tab) -> {aborted, R} | {atomic, ok}</name>
+ <name since="">clear_table(Tab) -> {aborted, R} | {atomic, ok}</name>
<fsummary>Deletes all entries in a table.</fsummary>
<desc>
<marker id="clear_table"></marker>
@@ -615,7 +615,7 @@ mnesia:change_table_copy_type(person, node(), disc_copies)</code>
</desc>
</func>
<func>
- <name>create_schema(DiscNodes) -> ok | {error,Reason}</name>
+ <name since="">create_schema(DiscNodes) -> ok | {error,Reason}</name>
<fsummary>Creates a new schema on the specified nodes.</fsummary>
<desc>
<marker id="create_schema"></marker>
@@ -637,7 +637,7 @@ mnesia:change_table_copy_type(person, node(), disc_copies)</code>
</desc>
</func>
<func>
- <name>create_table(Name, TabDef) -> {atomic, ok} | {aborted, Reason}</name>
+ <name since="">create_table(Name, TabDef) -> {atomic, ok} | {aborted, Reason}</name>
<fsummary>Creates a Mnesia table called <c>Name</c>with properties as described by argument <c>TabDef</c>.</fsummary>
<desc>
<marker id="create_table"></marker>
@@ -799,7 +799,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>deactivate_checkpoint(Name) -> ok | {error, Reason}</name>
+ <name since="">deactivate_checkpoint(Name) -> ok | {error, Reason}</name>
<fsummary>Deactivates a checkpoint.</fsummary>
<desc>
<marker id="deactivate_checkpoint"></marker>
@@ -811,7 +811,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>del_table_copy(Tab, Node) -> {aborted, R} | {atomic, ok}</name>
+ <name since="">del_table_copy(Tab, Node) -> {aborted, R} | {atomic, ok}</name>
<fsummary>Deletes the replica of table <c>Tab</c> at node <c>Node</c>.</fsummary>
<desc>
<marker id="del_table_copy"></marker>
@@ -825,7 +825,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>del_table_index(Tab, AttrName) -> {aborted, R} | {atomic, ok}</name>
+ <name since="">del_table_index(Tab, AttrName) -> {aborted, R} | {atomic, ok}</name>
<fsummary>Deletes an index in a table.</fsummary>
<desc>
<marker id="del_table_index"></marker>
@@ -834,7 +834,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>delete({Tab, Key}) -> transaction abort | ok</name>
+ <name since="">delete({Tab, Key}) -> transaction abort | ok</name>
<fsummary>Deletes all records in table <c>Tab</c> with the key <c>Key</c>.</fsummary>
<desc>
<marker id="delete_2"></marker>
@@ -842,7 +842,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>delete(Tab, Key, LockKind) -> transaction abort | ok</name>
+ <name since="">delete(Tab, Key, LockKind) -> transaction abort | ok</name>
<fsummary>Deletes all records in table <c>Tab</c>with the key <c>Key</c>.</fsummary>
<desc>
<marker id="delete_3"></marker>
@@ -857,7 +857,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>delete_object(Record) -> transaction abort | ok</name>
+ <name since="">delete_object(Record) -> transaction abort | ok</name>
<fsummary>Delete a record.</fsummary>
<desc>
<marker id="delete_object_1"></marker>
@@ -866,7 +866,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>delete_object(Tab, Record, LockKind) -> transaction abort | ok</name>
+ <name since="">delete_object(Tab, Record, LockKind) -> transaction abort | ok</name>
<fsummary>Deletes a record.</fsummary>
<desc>
<marker id="delete_object_3"></marker>
@@ -883,7 +883,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>delete_schema(DiscNodes) -> ok | {error,Reason}</name>
+ <name since="">delete_schema(DiscNodes) -> ok | {error,Reason}</name>
<fsummary>Deletes the schema on the given nodes.</fsummary>
<desc>
<marker id="delete_schema"></marker>
@@ -904,7 +904,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>delete_table(Tab) -> {aborted, Reason} | {atomic, ok}</name>
+ <name since="">delete_table(Tab) -> {aborted, Reason} | {atomic, ok}</name>
<fsummary>Deletes permanently all replicas of table <c>Tab</c>.</fsummary>
<desc>
<marker id="delete_table"></marker>
@@ -912,7 +912,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>dirty_all_keys(Tab) -> KeyList | exit({aborted, Reason})</name>
+ <name since="">dirty_all_keys(Tab) -> KeyList | exit({aborted, Reason})</name>
<fsummary>Dirty search for all record keys in table.</fsummary>
<desc>
<marker id="delete_all_keys"></marker>
@@ -920,7 +920,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>dirty_delete({Tab, Key}) -> ok | exit({aborted, Reason})</name>
+ <name since="">dirty_delete({Tab, Key}) -> ok | exit({aborted, Reason})</name>
<fsummary>Dirty delete of a record.</fsummary>
<desc>
<marker id="dirty_delete"></marker>
@@ -928,14 +928,14 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>dirty_delete(Tab, Key) -> ok | exit({aborted, Reason})</name>
+ <name since="">dirty_delete(Tab, Key) -> ok | exit({aborted, Reason})</name>
<fsummary>Dirty delete of a record.</fsummary>
<desc>
<p>Dirty equivalent of the function <c>mnesia:delete/3</c>.</p>
</desc>
</func>
<func>
- <name>dirty_delete_object(Record)</name>
+ <name since="">dirty_delete_object(Record)</name>
<fsummary>Dirty delete of a record.</fsummary>
<desc>
<marker id="dirty_delete_object_1"></marker>
@@ -944,14 +944,14 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>dirty_delete_object(Tab, Record)</name>
+ <name since="">dirty_delete_object(Tab, Record)</name>
<fsummary>Dirty delete of a record.</fsummary>
<desc>
<p>Dirty equivalent of the function <c>mnesia:delete_object/3</c>.</p>
</desc>
</func>
<func>
- <name>dirty_first(Tab) -> Key | exit({aborted, Reason})</name>
+ <name since="">dirty_first(Tab) -> Key | exit({aborted, Reason})</name>
<fsummary>Returns the key for the first record in a table.</fsummary>
<desc>
<marker id="dirty_first"></marker>
@@ -967,7 +967,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>dirty_index_match_object(Pattern, Pos)</name>
+ <name since="">dirty_index_match_object(Pattern, Pos)</name>
<fsummary>Dirty pattern match using index.</fsummary>
<desc>
<marker id="dirty_index_match_object_2"></marker>
@@ -977,7 +977,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>dirty_index_match_object(Tab, Pattern, Pos)</name>
+ <name since="">dirty_index_match_object(Tab, Pattern, Pos)</name>
<fsummary>Dirty pattern match using index.</fsummary>
<desc>
<p>Dirty equivalent of the function
@@ -985,7 +985,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>dirty_index_read(Tab, SecondaryKey, Pos)</name>
+ <name since="">dirty_index_read(Tab, SecondaryKey, Pos)</name>
<fsummary>Dirty read using index.</fsummary>
<desc>
<marker id="dirty_index_read"></marker>
@@ -994,7 +994,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>dirty_last(Tab) -> Key | exit({aborted, Reason})</name>
+ <name since="">dirty_last(Tab) -> Key | exit({aborted, Reason})</name>
<fsummary>Returns the key for the last record in a table.</fsummary>
<desc>
<marker id="dirty_last"></marker>
@@ -1006,7 +1006,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>dirty_match_object(Pattern) -> RecordList | exit({aborted, Reason})</name>
+ <name since="">dirty_match_object(Pattern) -> RecordList | exit({aborted, Reason})</name>
<fsummary>Dirty pattern match pattern.</fsummary>
<desc>
<marker id="dirty_match_object_1"></marker>
@@ -1015,7 +1015,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>dirty_match_object(Tab, Pattern) -> RecordList | exit({aborted, Reason})</name>
+ <name since="">dirty_match_object(Tab, Pattern) -> RecordList | exit({aborted, Reason})</name>
<fsummary>Dirty pattern match pattern.</fsummary>
<desc>
<p>Dirty equivalent of the function
@@ -1023,7 +1023,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>dirty_next(Tab, Key) -> Key | exit({aborted, Reason})</name>
+ <name since="">dirty_next(Tab, Key) -> Key | exit({aborted, Reason})</name>
<fsummary>Return the next key in a table.</fsummary>
<desc>
<marker id="dirty_next"></marker>
@@ -1038,7 +1038,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>dirty_prev(Tab, Key) -> Key | exit({aborted, Reason})</name>
+ <name since="">dirty_prev(Tab, Key) -> Key | exit({aborted, Reason})</name>
<fsummary>Returns the previous key in a table.</fsummary>
<desc>
<marker id="dirty_prev"></marker>
@@ -1050,7 +1050,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>dirty_read({Tab, Key}) -> ValueList | exit({aborted, Reason}</name>
+ <name since="">dirty_read({Tab, Key}) -> ValueList | exit({aborted, Reason}</name>
<fsummary>Dirty read of records.</fsummary>
<desc>
<marker id="dirty_read"></marker>
@@ -1058,14 +1058,14 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>dirty_read(Tab, Key) -> ValueList | exit({aborted, Reason}</name>
+ <name since="">dirty_read(Tab, Key) -> ValueList | exit({aborted, Reason}</name>
<fsummary>Dirty read of records.</fsummary>
<desc>
<p>Dirty equivalent of the function <c>mnesia:read/3</c>.</p>
</desc>
</func>
<func>
- <name>dirty_select(Tab, MatchSpec) -> ValueList | exit({aborted, Reason}</name>
+ <name since="">dirty_select(Tab, MatchSpec) -> ValueList | exit({aborted, Reason}</name>
<fsummary>Dirty matches the objects in <c>Tab</c> against <c>MatchSpec</c>.</fsummary>
<desc>
<marker id="dirty_select"></marker>
@@ -1073,7 +1073,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>dirty_slot(Tab, Slot) -> RecordList | exit({aborted, Reason})</name>
+ <name since="">dirty_slot(Tab, Slot) -> RecordList | exit({aborted, Reason})</name>
<fsummary>Returns the list of records that are associated with <c>Slot</c> in a table.</fsummary>
<desc>
<marker id="dirty_slot"></marker>
@@ -1089,7 +1089,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>dirty_update_counter({Tab, Key}, Incr) -> NewVal | exit({aborted, Reason})</name>
+ <name since="">dirty_update_counter({Tab, Key}, Incr) -> NewVal | exit({aborted, Reason})</name>
<fsummary>Dirty update of a counter record.</fsummary>
<desc>
<marker id="dirty_update_counter"></marker>
@@ -1097,7 +1097,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>dirty_update_counter(Tab, Key, Incr) -> NewVal | exit({aborted, Reason})</name>
+ <name since="">dirty_update_counter(Tab, Key, Incr) -> NewVal | exit({aborted, Reason})</name>
<fsummary>Dirty update of a counter record.</fsummary>
<desc>
<p>Mnesia has no special counter records. However,
@@ -1126,7 +1126,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>dirty_write(Record) -> ok | exit({aborted, Reason})</name>
+ <name since="">dirty_write(Record) -> ok | exit({aborted, Reason})</name>
<fsummary>Dirty write of a record.</fsummary>
<desc>
<marker id="dirty_write_1"></marker>
@@ -1135,14 +1135,14 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>dirty_write(Tab, Record) -> ok | exit({aborted, Reason})</name>
+ <name since="">dirty_write(Tab, Record) -> ok | exit({aborted, Reason})</name>
<fsummary>Dirty write of a record.</fsummary>
<desc>
<p>Dirty equivalent of the function <c>mnesia:write/3</c>.</p>
</desc>
</func>
<func>
- <name>dump_log() -> dumped</name>
+ <name since="">dump_log() -> dumped</name>
<fsummary>Performs a user-initiated dump of the local log file.</fsummary>
<desc>
<marker id="dump_log"></marker>
@@ -1156,7 +1156,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>dump_tables(TabList) -> {atomic, ok} | {aborted, Reason}</name>
+ <name since="">dump_tables(TabList) -> {atomic, ok} | {aborted, Reason}</name>
<fsummary>Dumps all RAM tables to disc.</fsummary>
<desc>
<marker id="dump_tables"></marker>
@@ -1168,7 +1168,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>dump_to_textfile(Filename)</name>
+ <name since="">dump_to_textfile(Filename)</name>
<fsummary>Dumps local tables into a text file.</fsummary>
<desc>
<marker id="dump_to_textfile"></marker>
@@ -1181,7 +1181,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>error_description(Error) -> String</name>
+ <name since="">error_description(Error) -> String</name>
<fsummary>Returns a string describing a particular Mnesia error.</fsummary>
<desc>
<marker id="error_description"></marker>
@@ -1259,7 +1259,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>ets(Fun, [, Args]) -> ResultOfFun | exit(Reason)</name>
+ <name since="">ets(Fun, [, Args]) -> ResultOfFun | exit(Reason)</name>
<fsummary>Calls the <c>Fun</c> in a raw context that is not protected by a transaction.</fsummary>
<desc>
<marker id="ets"></marker>
@@ -1278,7 +1278,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>first(Tab) -> Key | transaction abort</name>
+ <name since="">first(Tab) -> Key | transaction abort</name>
<fsummary>Returns the key for the first record in a table.</fsummary>
<desc>
<marker id="first"></marker>
@@ -1293,7 +1293,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>foldl(Function, Acc, Table) -> NewAcc | transaction abort</name>
+ <name since="">foldl(Function, Acc, Table) -> NewAcc | transaction abort</name>
<fsummary>Calls <c>Function</c> for each record in <c>Table</c>.</fsummary>
<desc>
<marker id="foldl"></marker>
@@ -1306,7 +1306,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>foldr(Function, Acc, Table) -> NewAcc | transaction abort</name>
+ <name since="">foldr(Function, Acc, Table) -> NewAcc | transaction abort</name>
<fsummary>Calls <c>Function</c> for each record in <c>Table</c>.</fsummary>
<desc>
<marker id="foldr"></marker>
@@ -1317,7 +1317,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>force_load_table(Tab) -> yes | ErrorDescription</name>
+ <name since="">force_load_table(Tab) -> yes | ErrorDescription</name>
<fsummary>Forces a table to be loaded into the system.</fsummary>
<desc>
<marker id="force_load_table"></marker>
@@ -1335,7 +1335,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>index_match_object(Pattern, Pos) -> transaction abort | ObjList</name>
+ <name since="">index_match_object(Pattern, Pos) -> transaction abort | ObjList</name>
<fsummary>Matches records and uses index information.</fsummary>
<desc>
<marker id="index_match_object_2"></marker>
@@ -1345,7 +1345,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>index_match_object(Tab, Pattern, Pos, LockKind) -> transaction abort | ObjList</name>
+ <name since="">index_match_object(Tab, Pattern, Pos, LockKind) -> transaction abort | ObjList</name>
<fsummary>Matches records and uses index information.</fsummary>
<desc>
<marker id="index_match_object_4"></marker>
@@ -1377,7 +1377,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>index_read(Tab, SecondaryKey, Pos) -> transaction abort | RecordList</name>
+ <name since="">index_read(Tab, SecondaryKey, Pos) -> transaction abort | RecordList</name>
<fsummary>Reads records through index table.</fsummary>
<desc>
<marker id="index_read"></marker>
@@ -1397,7 +1397,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>info() -> ok</name>
+ <name since="">info() -> ok</name>
<fsummary>Prints system information on the terminal.</fsummary>
<desc>
<marker id="info"></marker>
@@ -1408,7 +1408,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>install_fallback(Opaque) -> ok | {error,Reason}</name>
+ <name since="">install_fallback(Opaque) -> ok | {error,Reason}</name>
<fsummary>Installs a backup as fallback.</fsummary>
<desc>
<marker id="install_fallback_1"></marker>
@@ -1417,7 +1417,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>install_fallback(Opaque), BackupMod) -> ok | {error,Reason}</name>
+ <name since="">install_fallback(Opaque), BackupMod) -> ok | {error,Reason}</name>
<fsummary>Installs a backup as fallback.</fsummary>
<desc>
<p>Calls <c>mnesia:install_fallback(Opaque, Args)</c>, where
@@ -1425,7 +1425,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>install_fallback(Opaque, Args) -> ok | {error,Reason}</name>
+ <name since="">install_fallback(Opaque, Args) -> ok | {error,Reason}</name>
<fsummary>Installs a backup as fallback.</fsummary>
<desc>
<p>Installs a backup as fallback. The fallback is used to
@@ -1483,7 +1483,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>is_transaction() -> boolean</name>
+ <name since="">is_transaction() -> boolean</name>
<fsummary>Checks if code is running in a transaction.</fsummary>
<desc>
<marker id="is_transaction"></marker>
@@ -1492,7 +1492,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>last(Tab) -> Key | transaction abort</name>
+ <name since="">last(Tab) -> Key | transaction abort</name>
<fsummary>Returns the key for the last record in a table.</fsummary>
<desc>
<p>Works exactly like
@@ -1503,7 +1503,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>load_textfile(Filename)</name>
+ <name since="">load_textfile(Filename)</name>
<fsummary>Loads tables from a text file.</fsummary>
<desc>
<marker id="load_textfile"></marker>
@@ -1516,7 +1516,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>lock(LockItem, LockKind) -> Nodes | ok | transaction abort</name>
+ <name since="">lock(LockItem, LockKind) -> Nodes | ok | transaction abort</name>
<fsummary>Explicit grab lock.</fsummary>
<desc>
<marker id="lock"></marker>
@@ -1605,7 +1605,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>match_object(Pattern) -> transaction abort | RecList</name>
+ <name since="">match_object(Pattern) -> transaction abort | RecList</name>
<fsummary>Matches <c>Pattern</c> for records.</fsummary>
<desc>
<marker id="match_object_1"></marker>
@@ -1614,7 +1614,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>match_object(Tab, Pattern, LockKind) -> transaction abort | RecList</name>
+ <name since="">match_object(Tab, Pattern, LockKind) -> transaction abort | RecList</name>
<fsummary>Matches <c>Pattern</c> for records.</fsummary>
<desc>
<marker id="match_object_3"></marker>
@@ -1639,7 +1639,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>move_table_copy(Tab, From, To) -> {aborted, Reason} | {atomic, ok}</name>
+ <name since="">move_table_copy(Tab, From, To) -> {aborted, Reason} | {atomic, ok}</name>
<fsummary>Moves the copy of table <c>Tab</c> from node <c>From</c> to node <c>To</c>.</fsummary>
<desc>
<marker id="move_table_copy"></marker>
@@ -1653,7 +1653,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>next(Tab, Key) -> Key | transaction abort</name>
+ <name since="">next(Tab, Key) -> Key | transaction abort</name>
<fsummary>Returns the next key in a table.</fsummary>
<desc>
<marker id="next"></marker>
@@ -1665,7 +1665,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>prev(Tab, Key) -> Key | transaction abort</name>
+ <name since="">prev(Tab, Key) -> Key | transaction abort</name>
<fsummary>Returns the previous key in a table.</fsummary>
<desc>
<p>Works exactly like
@@ -1676,7 +1676,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>read({Tab, Key}) -> transaction abort | RecordList</name>
+ <name since="">read({Tab, Key}) -> transaction abort | RecordList</name>
<fsummary>Reads records(s) with a given key.</fsummary>
<desc>
<marker id="read_2"></marker>
@@ -1684,14 +1684,14 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>read(Tab, Key) -> transaction abort | RecordList</name>
+ <name since="">read(Tab, Key) -> transaction abort | RecordList</name>
<fsummary>Reads records(s) with a given key.</fsummary>
<desc>
<p>Calls function <c>mnesia:read(Tab, Key, read)</c>.</p>
</desc>
</func>
<func>
- <name>read(Tab, Key, LockKind) -> transaction abort | RecordList</name>
+ <name since="">read(Tab, Key, LockKind) -> transaction abort | RecordList</name>
<fsummary>Reads records(s) with a given key.</fsummary>
<desc>
<marker id="read_3"></marker>
@@ -1716,7 +1716,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>read_lock_table(Tab) -> ok | transaction abort</name>
+ <name since="">read_lock_table(Tab) -> ok | transaction abort</name>
<fsummary>Sets a read lock on an entire table.</fsummary>
<desc>
<marker id="read_lock_table"></marker>
@@ -1725,7 +1725,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>report_event(Event) -> ok</name>
+ <name since="">report_event(Event) -> ok</name>
<fsummary>Reports a user event to the Mnesia event handler.</fsummary>
<desc>
<marker id="report_event"></marker>
@@ -1743,7 +1743,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>restore(Opaque, Args) -> {atomic, RestoredTabs} |{aborted, Reason}</name>
+ <name since="">restore(Opaque, Args) -> {atomic, RestoredTabs} |{aborted, Reason}</name>
<fsummary>Online restore of backup.</fsummary>
<desc>
<marker id="restore"></marker>
@@ -1803,7 +1803,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>s_delete({Tab, Key}) -> ok | transaction abort</name>
+ <name since="">s_delete({Tab, Key}) -> ok | transaction abort</name>
<fsummary>Sets sticky lock and delete records.</fsummary>
<desc>
<marker id="s_delete"></marker>
@@ -1812,7 +1812,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>s_delete_object(Record) -> ok | transaction abort</name>
+ <name since="">s_delete_object(Record) -> ok | transaction abort</name>
<fsummary>Sets sticky lock and delete record.</fsummary>
<desc>
<marker id="s_delete_object"></marker>
@@ -1822,7 +1822,7 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>s_write(Record) -> ok | transaction abort</name>
+ <name since="">s_write(Record) -> ok | transaction abort</name>
<fsummary>Writes <c>Record</c> and sets sticky lock.</fsummary>
<desc>
<marker id="s_write"></marker>
@@ -1832,21 +1832,21 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name>schema() -> ok</name>
+ <name since="">schema() -> ok</name>
<fsummary>Prints information about all table definitions on the terminal.</fsummary>
<desc>
<p>Prints information about all table definitions on the terminal.</p>
</desc>
</func>
<func>
- <name>schema(Tab) -> ok</name>
+ <name since="">schema(Tab) -> ok</name>
<fsummary>Prints information about one table definition on the terminal.</fsummary>
<desc>
<p>Prints information about one table definition on the terminal.</p>
</desc>
</func>
<func>
- <name>select(Tab, MatchSpec [, Lock]) -> transaction abort | [Object]</name>
+ <name since="">select(Tab, MatchSpec [, Lock]) -> transaction abort | [Object]</name>
<fsummary>Matches the objects in <c>Tab</c> against <c>MatchSpec</c>.</fsummary>
<desc>
<marker id="select_2_3"></marker>
@@ -1884,7 +1884,7 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code>
</desc>
</func>
<func>
- <name>select(Tab, MatchSpec, NObjects, Lock) -> transaction abort | {[Object],Cont} | '$end_of_table'</name>
+ <name since="">select(Tab, MatchSpec, NObjects, Lock) -> transaction abort | {[Object],Cont} | '$end_of_table'</name>
<fsummary>Matches the objects in <c>Tab</c> against <c>MatchSpec</c>.</fsummary>
<desc>
<marker id="select_4"></marker>
@@ -1907,7 +1907,7 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code>
</desc>
</func>
<func>
- <name>select(Cont) -> transaction abort | {[Object],Cont} | '$end_of_table'</name>
+ <name since="">select(Cont) -> transaction abort | {[Object],Cont} | '$end_of_table'</name>
<fsummary>Continues selecting objects.</fsummary>
<desc>
<p>Selects more objects with the match specification initiated
@@ -1919,7 +1919,7 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code>
</desc>
</func>
<func>
- <name>set_debug_level(Level) -> OldLevel</name>
+ <name since="">set_debug_level(Level) -> OldLevel</name>
<fsummary>Changes the internal debug level of Mnesia.</fsummary>
<desc>
<marker id="set_debug_level"></marker>
@@ -1930,7 +1930,7 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code>
</desc>
</func>
<func>
- <name>set_master_nodes(MasterNodes) -> ok | {error, Reason}</name>
+ <name since="">set_master_nodes(MasterNodes) -> ok | {error, Reason}</name>
<fsummary>Sets the master nodes for all tables.</fsummary>
<desc>
<marker id="set_master_nodes_1"></marker>
@@ -1943,7 +1943,7 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code>
</desc>
</func>
<func>
- <name>set_master_nodes(Tab, MasterNodes) -> ok | {error, Reason}</name>
+ <name since="">set_master_nodes(Tab, MasterNodes) -> ok | {error, Reason}</name>
<fsummary>Sets the master nodes for a table.</fsummary>
<desc>
<marker id="set_master_nodes_2"></marker>
@@ -1968,14 +1968,14 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code>
</desc>
</func>
<func>
- <name>snmp_close_table(Tab) -> {aborted, R} | {atomic, ok}</name>
+ <name since="">snmp_close_table(Tab) -> {aborted, R} | {atomic, ok}</name>
<fsummary>Removes the possibility for SNMP to manipulate the table.</fsummary>
<desc>
<p>Removes the possibility for SNMP to manipulate the table.</p>
</desc>
</func>
<func>
- <name>snmp_get_mnesia_key(Tab, RowIndex) -> {ok, Key} | undefined</name>
+ <name since="">snmp_get_mnesia_key(Tab, RowIndex) -> {ok, Key} | undefined</name>
<fsummary>Gets the corresponding Mnesia key from an SNMP index.</fsummary>
<type>
<v>Tab ::= atom()</v>
@@ -1990,7 +1990,7 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code>
</desc>
</func>
<func>
- <name>snmp_get_next_index(Tab, RowIndex) -> {ok, NextIndex} | endOfTable</name>
+ <name since="">snmp_get_next_index(Tab, RowIndex) -> {ok, NextIndex} | endOfTable</name>
<fsummary>Gets the index of the next lexicographical row.</fsummary>
<type>
<v>Tab ::= atom()</v>
@@ -2006,7 +2006,7 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code>
</desc>
</func>
<func>
- <name>snmp_get_row(Tab, RowIndex) -> {ok, Row} | undefined</name>
+ <name since="">snmp_get_row(Tab, RowIndex) -> {ok, Row} | undefined</name>
<fsummary>Retrieves a row indexed by an SNMP index.</fsummary>
<type>
<v>Tab ::= atom()</v>
@@ -2019,7 +2019,7 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code>
</desc>
</func>
<func>
- <name>snmp_open_table(Tab, SnmpStruct) -> {aborted, R} | {atomic, ok}</name>
+ <name since="">snmp_open_table(Tab, SnmpStruct) -> {aborted, R} | {atomic, ok}</name>
<fsummary>Organizes a Mnesia table as an SNMP table.</fsummary>
<type>
<v>Tab ::= atom()</v>
@@ -2073,10 +2073,17 @@ mnesia:create_table(employee,
</desc>
</func>
<func>
- <name>start() -> ok | {error, Reason}</name>
+ <name since="">start() -> ok | {error, Reason}</name>
<fsummary>Starts a local Mnesia system.</fsummary>
<desc>
<marker id="start"></marker>
+ <p>Mnesia startup is asynchronous. The function call
+ <c>mnesia:start()</c> returns the atom <c>ok</c> and then
+ starts to initialize the different tables. Depending on the
+ size of the database, this can take some time, and the
+ application programmer must wait for the tables that the
+ application needs before they can be used. This is achieved
+ by using the function <c>mnesia:wait_for_tables/2</c>.</p>
<p>The startup procedure for a set of Mnesia nodes is a
fairly complicated operation. A Mnesia system consists
of a set of nodes, with Mnesia started locally on all
@@ -2108,7 +2115,7 @@ mnesia:create_table(employee,
</desc>
</func>
<func>
- <name>stop() -> stopped</name>
+ <name since="">stop() -> stopped</name>
<fsummary>Stops Mnesia locally.</fsummary>
<desc>
<marker id="stop"></marker>
@@ -2117,7 +2124,7 @@ mnesia:create_table(employee,
</desc>
</func>
<func>
- <name>subscribe(EventCategory) -> {ok, Node} | {error, Reason}</name>
+ <name since="">subscribe(EventCategory) -> {ok, Node} | {error, Reason}</name>
<fsummary>Subscribes to events of type <c>EventCategory</c>.</fsummary>
<desc>
<marker id="subscribe"></marker>
@@ -2127,7 +2134,7 @@ mnesia:create_table(employee,
</desc>
</func>
<func>
- <name>sync_dirty(Fun, [, Args]) -> ResultOfFun | exit(Reason)</name>
+ <name since="">sync_dirty(Fun, [, Args]) -> ResultOfFun | exit(Reason)</name>
<fsummary>Calls the <c>Fun</c> in a context that is not protected by a transaction.</fsummary>
<desc>
<marker id="sync_dirty"></marker>
@@ -2143,7 +2150,7 @@ mnesia:create_table(employee,
</desc>
</func>
<func>
- <name>sync_log() -> ok | {error, Reason}</name>
+ <name since="OTP 17.0">sync_log() -> ok | {error, Reason}</name>
<fsummary>Performs a file sync of the local log file.</fsummary>
<desc>
<p>Ensures that the local transaction log file is synced to disk.
@@ -2153,7 +2160,7 @@ mnesia:create_table(employee,
</desc>
</func>
<func>
- <name>sync_transaction(Fun, [[, Args], Retries]) -> {aborted, Reason} | {atomic, ResultOfFun}</name>
+ <name since="">sync_transaction(Fun, [[, Args], Retries]) -> {aborted, Reason} | {atomic, ResultOfFun}</name>
<fsummary>Synchronously executes a transaction.</fsummary>
<desc>
<marker id="sync_transaction"></marker>
@@ -2166,7 +2173,7 @@ mnesia:create_table(employee,
</desc>
</func>
<func>
- <name>system_info(InfoKey) -> Info | exit({aborted, Reason})</name>
+ <name since="">system_info(InfoKey) -> Info | exit({aborted, Reason})</name>
<fsummary>Returns information about the Mnesia system.</fsummary>
<desc>
<marker id="system_info"></marker>
@@ -2353,7 +2360,7 @@ mnesia:create_table(employee,
</desc>
</func>
<func>
- <name>table(Tab [,[Option]]) -> QueryHandle</name>
+ <name since="">table(Tab [,[Option]]) -> QueryHandle</name>
<fsummary>Return a QLC query handle.</fsummary>
<desc>
<marker id="table"></marker>
@@ -2408,7 +2415,7 @@ mnesia:create_table(employee,
</desc>
</func>
<func>
- <name>table_info(Tab, InfoKey) -> Info | exit({aborted, Reason})</name>
+ <name since="">table_info(Tab, InfoKey) -> Info | exit({aborted, Reason})</name>
<fsummary>Returns local information about table.</fsummary>
<desc>
<marker id="table_info"></marker>
@@ -2560,7 +2567,7 @@ mnesia:create_table(employee,
</desc>
</func>
<func>
- <name>transaction(Fun [[, Args], Retries]) -> {aborted, Reason} | {atomic, ResultOfFun}</name>
+ <name since="">transaction(Fun [[, Args], Retries]) -> {aborted, Reason} | {atomic, ResultOfFun}</name>
<fsummary>Executes a transaction.</fsummary>
<desc>
<marker id="transaction"></marker>
@@ -2628,7 +2635,7 @@ raise(Name, Amount) ->
</desc>
</func>
<func>
- <name>transform_table(Tab, Fun, NewAttributeList, NewRecordName) -> {aborted, R} | {atomic, ok}</name>
+ <name since="">transform_table(Tab, Fun, NewAttributeList, NewRecordName) -> {aborted, R} | {atomic, ok}</name>
<fsummary>Changes format on all records in table <c>Tab</c>.</fsummary>
<desc>
<marker id="transform_table_4"></marker>
@@ -2649,7 +2656,7 @@ raise(Name, Amount) ->
</desc>
</func>
<func>
- <name>transform_table(Tab, Fun, NewAttributeList) -> {aborted, R} | {atomic, ok}</name>
+ <name since="">transform_table(Tab, Fun, NewAttributeList) -> {aborted, R} | {atomic, ok}</name>
<fsummary>Changes format on all records in table <c>Tab</c>.</fsummary>
<desc>
<p>Calls <c>mnesia:transform_table(Tab, Fun,
@@ -2658,7 +2665,7 @@ raise(Name, Amount) ->
</desc>
</func>
<func>
- <name>traverse_backup(Source, [SourceMod,] Target, [TargetMod,] Fun, Acc) -> {ok, LastAcc} | {error, Reason}</name>
+ <name since="">traverse_backup(Source, [SourceMod,] Target, [TargetMod,] Fun, Acc) -> {ok, LastAcc} | {error, Reason}</name>
<fsummary>Traversal of a backup.</fsummary>
<desc>
<marker id="traverse_backup"></marker>
@@ -2689,7 +2696,7 @@ raise(Name, Amount) ->
</desc>
</func>
<func>
- <name>uninstall_fallback() -> ok | {error,Reason}</name>
+ <name since="">uninstall_fallback() -> ok | {error,Reason}</name>
<fsummary>Uninstalls a fallback.</fsummary>
<desc>
<marker id="uninstall_fallback_0"></marker>
@@ -2698,7 +2705,7 @@ raise(Name, Amount) ->
</desc>
</func>
<func>
- <name>uninstall_fallback(Args) -> ok | {error,Reason}</name>
+ <name since="">uninstall_fallback(Args) -> ok | {error,Reason}</name>
<fsummary>Uninstalls a fallback.</fsummary>
<desc>
<p>Deinstalls a fallback before it
@@ -2725,7 +2732,7 @@ raise(Name, Amount) ->
</desc>
</func>
<func>
- <name>unsubscribe(EventCategory) -> {ok, Node} | {error, Reason}</name>
+ <name since="">unsubscribe(EventCategory) -> {ok, Node} | {error, Reason}</name>
<fsummary>Subscribes to events of type <c>EventCategory</c>.</fsummary>
<desc>
<marker id="unsubscribe"></marker>
@@ -2735,7 +2742,7 @@ raise(Name, Amount) ->
</desc>
</func>
<func>
- <name>wait_for_tables(TabList, Timeout) -> ok | {timeout, BadTabList} | {error, Reason}</name>
+ <name since="">wait_for_tables(TabList, Timeout) -> ok | {timeout, BadTabList} | {error, Reason}</name>
<fsummary>Waits for tables to be accessible.</fsummary>
<desc>
<marker id="wait_for_tables"></marker>
@@ -2746,7 +2753,7 @@ raise(Name, Amount) ->
</desc>
</func>
<func>
- <name>wread({Tab, Key}) -> transaction abort | RecordList</name>
+ <name since="">wread({Tab, Key}) -> transaction abort | RecordList</name>
<fsummary>Reads records with given key.</fsummary>
<desc>
<marker id="wread"></marker>
@@ -2754,7 +2761,7 @@ raise(Name, Amount) ->
</desc>
</func>
<func>
- <name>write(Record) -> transaction abort | ok</name>
+ <name since="">write(Record) -> transaction abort | ok</name>
<fsummary>Writes a record into the database.</fsummary>
<desc>
<marker id="write_1"></marker>
@@ -2763,7 +2770,7 @@ raise(Name, Amount) ->
</desc>
</func>
<func>
- <name>write(Tab, Record, LockKind) -> transaction abort | ok</name>
+ <name since="">write(Tab, Record, LockKind) -> transaction abort | ok</name>
<fsummary>Writes a record into the database.</fsummary>
<desc>
<marker id="write_3"></marker>
@@ -2779,7 +2786,7 @@ raise(Name, Amount) ->
</desc>
</func>
<func>
- <name>write_lock_table(Tab) -> ok | transaction abort</name>
+ <name since="">write_lock_table(Tab) -> ok | transaction abort</name>
<fsummary>Sets write lock on an entire table.</fsummary>
<desc>
<marker id="write_lock_table"></marker>
diff --git a/lib/mnesia/doc/src/mnesia_frag_hash.xml b/lib/mnesia/doc/src/mnesia_frag_hash.xml
index 51b32129b6..ccaba412d0 100644
--- a/lib/mnesia/doc/src/mnesia_frag_hash.xml
+++ b/lib/mnesia/doc/src/mnesia_frag_hash.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2002</year>
- <year>2016</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -34,7 +34,7 @@
<rev>A</rev>
<file>mnesia_frag_hash.sgml</file>
</header>
- <module>mnesia_frag_hash</module>
+ <module since="">mnesia_frag_hash</module>
<modulesummary>Defines mnesia_frag_hash callback behavior</modulesummary>
<description>
<p>This module defines a callback behavior for user-defined hash
@@ -50,7 +50,7 @@
<funcs>
<func>
- <name>init_state(Tab, State) -> NewState | abort(Reason)</name>
+ <name since="">init_state(Tab, State) -> NewState | abort(Reason)</name>
<fsummary>Initiates the hash state for a new table.</fsummary>
<type>
<v>Tab = atom()</v>
@@ -72,7 +72,7 @@
</desc>
</func>
<func>
- <name>add_frag(State) -> {NewState, IterFrags, AdditionalLockFrags} | abort(Reason)</name>
+ <name since="">add_frag(State) -> {NewState, IterFrags, AdditionalLockFrags} | abort(Reason)</name>
<fsummary>Starts when a new fragment is added to a fragmented table.</fsummary>
<type>
<v>State = term()</v>
@@ -100,7 +100,7 @@
</desc>
</func>
<func>
- <name>del_frag(State) -> {NewState, IterFrags, AdditionalLockFrags} | abort(Reason)</name>
+ <name since="">del_frag(State) -> {NewState, IterFrags, AdditionalLockFrags} | abort(Reason)</name>
<fsummary>Starts when a fragment is deleted from a fragmented table.</fsummary>
<type>
<v>State = term()</v>
@@ -127,10 +127,10 @@
</desc>
</func>
<func>
- <name>key_to_frag_number(State, Key) -> FragNum | abort(Reason)</name>
+ <name since="">key_to_frag_number(State, Key) -> FragNum | abort(Reason)</name>
<fsummary>Resolves the key of a record into a fragment number.</fsummary>
<type>
- <v>FragNum = integer()()</v>
+ <v>FragNum = integer()</v>
<v>Reason = term()</v>
</type>
<desc>
@@ -140,7 +140,7 @@
</desc>
</func>
<func>
- <name>match_spec_to_frag_numbers(State, MatchSpec) -> FragNums | abort(Reason)</name>
+ <name since="">match_spec_to_frag_numbers(State, MatchSpec) -> FragNums | abort(Reason)</name>
<fsummary>Resolves a <c>MatchSpec</c> into a list of fragment numbers.</fsummary>
<type>
<v>MatcSpec = ets_select_match_spec()</v>
diff --git a/lib/mnesia/doc/src/mnesia_registry.xml b/lib/mnesia/doc/src/mnesia_registry.xml
index a76f716981..18ddc4ab9e 100644
--- a/lib/mnesia/doc/src/mnesia_registry.xml
+++ b/lib/mnesia/doc/src/mnesia_registry.xml
@@ -34,7 +34,7 @@
<rev>A</rev>
<file>mnesia_registry.sgml</file>
</header>
- <module>mnesia_registry</module>
+ <module since="">mnesia_registry</module>
<modulesummary>Dump support for registries in erl_interface.</modulesummary>
<description>
<p>This module is usually part of the <c>erl_interface</c>
@@ -57,7 +57,7 @@
<funcs>
<func>
- <name>create_table(Tab) -> ok | exit(Reason)</name>
+ <name since="">create_table(Tab) -> ok | exit(Reason)</name>
<fsummary>Creates a registry table in Mnesia.</fsummary>
<desc>
<p>A wrapper function for <c>mnesia:create_table/2</c>,
@@ -73,7 +73,7 @@
</desc>
</func>
<func>
- <name>create_table(Tab, TabDef) -> ok | exit(Reason)</name>
+ <name since="">create_table(Tab, TabDef) -> ok | exit(Reason)</name>
<fsummary>Creates a customized registry table in Mnesia.</fsummary>
<desc>
<p>A wrapper function for <c>mnesia:create_table/2</c>,
diff --git a/lib/mnesia/doc/src/notes.xml b/lib/mnesia/doc/src/notes.xml
index ba94e913f5..2d38e4d01c 100644
--- a/lib/mnesia/doc/src/notes.xml
+++ b/lib/mnesia/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -39,7 +39,155 @@
thus constitutes one section in this document. The title of each
section is the version number of Mnesia.</p>
- <section><title>Mnesia 4.15.3</title>
+ <section><title>Mnesia 4.16</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Optimize mnesia:read/1 if data have been written in the
+ same transaction.</p>
+ <p>
+ Own Id: OTP-15550 Aux Id: PR-2029 </p>
+ </item>
+ <item>
+ <p>
+ Fixed bugs in table index plugin handling.</p>
+ <p>
+ Own Id: OTP-15689 Aux Id: PR-1695 ERL-556 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Optimized dumping of tables with plugin backends.</p>
+ <p>
+ Own Id: OTP-15588 Aux Id: PR-2102 </p>
+ </item>
+ <item>
+ <p>
+ Include stacktrace in exception if a dirty activity
+ errors, thus if user have matched on the error thrown it
+ may not match any more.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15804 Aux Id: PR-2216 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Mnesia 4.15.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Avoid overload warnings caused by a race condition.</p>
+ <p>
+ Own Id: OTP-15619 Aux Id: ERIERL-310 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Mnesia 4.15.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed type spec for <c>mnesia:change_config/2</c>.</p>
+ <p>
+ Own Id: OTP-15201 Aux Id: PR-1881 </p>
+ </item>
+ <item>
+ <p>
+ When master node is set do not force a load from
+ ram_copies replica when there are no available
+ disc_copies, since that would load an empty table. Wait
+ until a disk replica is available or until user
+ explicitly force_loads the table.</p>
+ <p>
+ Own Id: OTP-15221 Aux Id: ERIERL-217 </p>
+ </item>
+ <item>
+ <p>
+ Allow to add replicas even if all other replicas are down
+ when the other replicas are not stored on disk.</p>
+ <p>
+ Own Id: OTP-15226 Aux Id: ERIERL-221 </p>
+ </item>
+ <item>
+ <p>
+ Fixed <c>mnesia:delete_object/1</c> bug, where
+ delete_object was deleting the record if it was written
+ in the same transaction even if it was written to a
+ different value.</p>
+ <p>
+ Own Id: OTP-15231 Aux Id: PR-1858 </p>
+ </item>
+ <item>
+ <p>
+ Fixed a bug where the bag table index data was not
+ deleted when objects were deleted.</p>
+ <p>
+ Own Id: OTP-15243</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Mnesia 4.15.4</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> Calls to <c>erlang:get_stacktrace()</c> are removed.
+ </p>
+ <p>
+ Own Id: OTP-14861</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Mnesia 4.15.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ When master node is set do not force a load from
+ ram_copies replica when there are no available
+ disc_copies, since that would load an empty table. Wait
+ until a disk replica is available or until user
+ explicitly force_loads the table.</p>
+ <p>
+ Own Id: OTP-15221 Aux Id: ERIERL-217 </p>
+ </item>
+ <item>
+ <p>
+ Allow to add replicas even if all other replicas are down
+ when the other replicase are not stored on disk.</p>
+ <p>
+ Own Id: OTP-15226 Aux Id: ERIERL-221 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Mnesia 4.15.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
@@ -648,7 +796,7 @@
<p>
Returns the same value for
mnesia_loader:disc_load_table/2 as
- mnesia_loader:net_load_table/4 if a table copy can not be
+ mnesia_loader:net_load_table/4 if a table copy cannot be
found. (Thanks to Uwe Dauernheim)</p>
<p>
Own Id: OTP-10015</p>
diff --git a/lib/mnesia/examples/bench/README b/lib/mnesia/examples/bench/README
index 5d31b5ba25..b8209b19b8 100644
--- a/lib/mnesia/examples/bench/README
+++ b/lib/mnesia/examples/bench/README
@@ -46,7 +46,7 @@ you need to:
- put the $ERL_TOP/bin directory in your path on all nodes
- bind IP adresses to hostnames (e.g via DNS or /etc/hosts)
- - enable usage of rsh so it does not prompt for password
+ - enable usage of ssh so it does not prompt for password
If you cannot achieve this, it is possible to run the benchmark
anyway, but it requires more manual work to be done for each
@@ -141,7 +141,7 @@ statistics_detail
following atoms: normal, debug and debug2. debug enables a
finer grain of statistics to be reported, but since it requires
more counters, to be updated by the generator processes it may
- cause slightly worse benchmark performace figures than the brief
+ cause slightly worse benchmark performance figures than the brief
default case, that is normal. debug2 prints out the debug info
and formats it according to LMC's benchmark program.
@@ -160,7 +160,7 @@ n_fragments
Defines how many fragments each table should be divided in.
Default is 100. The fragments are evenly distributed over
- all table nodes. The group table not devided in fragments.
+ all table nodes. The group table not divided in fragments.
n_replicas
diff --git a/lib/mnesia/src/mnesia.erl b/lib/mnesia/src/mnesia.erl
index 1842769778..02bc884e36 100644
--- a/lib/mnesia/src/mnesia.erl
+++ b/lib/mnesia/src/mnesia.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -160,7 +160,7 @@
{'sync_transaction', Retries::non_neg_integer()}.
-type table() :: atom().
-type storage_type() :: 'ram_copies' | 'disc_copies' | 'disc_only_copies'.
--type index_attr() :: atom() | non_neg_integer().
+-type index_attr() :: atom() | non_neg_integer() | {atom()}.
-type write_locks() :: 'write' | 'sticky_write'.
-type read_locks() :: 'read'.
-type lock_kind() :: write_locks() | read_locks().
@@ -168,6 +168,9 @@
-type snmp_struct() :: [{atom(), snmp_type() | tuple_of(snmp_type())}].
-type snmp_type() :: 'fix_string' | 'string' | 'integer'.
-type tuple_of(_T) :: tuple().
+-type config_key() :: extra_db_nodes | dc_dump_limit.
+-type config_value() :: [node()] | number().
+-type config_result() :: {ok, config_value()} | {error, term()}.
-define(DEFAULT_ACCESS, ?MODULE).
@@ -177,8 +180,8 @@
%% Local function in order to avoid external function call
val(Var) ->
- case ?catch_val(Var) of
- {'EXIT', _} -> mnesia_lib:other_val(Var);
+ case ?catch_val_and_stack(Var) of
+ {'EXIT', Stacktrace} -> mnesia_lib:other_val(Var, Stacktrace);
Value -> Value
end.
@@ -278,7 +281,8 @@ stop() ->
Other -> Other
end.
--spec change_config(Config::atom(), Value::_) -> ok | {error, term()}.
+-spec change_config(Config::config_key(), Value::config_value()) ->
+ config_result().
change_config(extra_db_nodes, Ns) when is_list(Ns) ->
mnesia_controller:connect_nodes(Ns);
change_config(dc_dump_limit, N) when is_number(N), N > 0 ->
@@ -779,12 +783,16 @@ do_delete_object(Tid, Ts, Tab, Val, LockKind) ->
?ets_insert(Store, {Oid, Val, delete_object});
_ ->
case ?ets_match_object(Store, {Oid, '_', write}) of
- [] ->
- ?ets_match_delete(Store, {Oid, Val, '_'}),
- ?ets_insert(Store, {Oid, Val, delete_object});
- _ ->
- ?ets_delete(Store, Oid),
- ?ets_insert(Store, {Oid, Oid, delete})
+ [] ->
+ ?ets_match_delete(Store, {Oid, Val, '_'}),
+ ?ets_insert(Store, {Oid, Val, delete_object});
+ Ops ->
+ case lists:member({Oid, Val, write}, Ops) of
+ true ->
+ ?ets_delete(Store, Oid),
+ ?ets_insert(Store, {Oid, Oid, delete});
+ false -> ok
+ end
end
end,
ok;
@@ -830,18 +838,20 @@ read(Tid, Ts, Tab, Key, LockKind)
tid ->
Store = Ts#tidstore.store,
Oid = {Tab, Key},
- Objs =
- case LockKind of
- read ->
- mnesia_locker:rlock(Tid, Store, Oid);
- write ->
- mnesia_locker:rwlock(Tid, Store, Oid);
- sticky_write ->
- mnesia_locker:sticky_rwlock(Tid, Store, Oid);
- _ ->
- abort({bad_type, Tab, LockKind})
- end,
- add_written(?ets_lookup(Store, Oid), Tab, Objs);
+ ObjsFun =
+ fun() ->
+ case LockKind of
+ read ->
+ mnesia_locker:rlock(Tid, Store, Oid);
+ write ->
+ mnesia_locker:rwlock(Tid, Store, Oid);
+ sticky_write ->
+ mnesia_locker:sticky_rwlock(Tid, Store, Oid);
+ _ ->
+ abort({bad_type, Tab, LockKind})
+ end
+ end,
+ add_written(?ets_lookup(Store, Oid), Tab, ObjsFun, LockKind);
_Protocol ->
dirty_read(Tab, Key)
end;
@@ -1194,14 +1204,20 @@ add_previous(_Tid, Ts, _Type, Tab) ->
%% This routine fixes up the return value from read/1 so that
%% it is correct with respect to what this particular transaction
%% has already written, deleted .... etc
+%% The actual read from the table is not done if not needed due to local
+%% transaction context, and if so, no extra read lock is needed either.
-add_written([], _Tab, Objs) ->
- Objs; % standard normal fast case
-add_written(Written, Tab, Objs) ->
+add_written([], _Tab, ObjsFun, _LockKind) ->
+ ObjsFun(); % standard normal fast case
+add_written(Written, Tab, ObjsFun, LockKind) ->
case val({Tab, setorbag}) of
bag ->
- add_written_to_bag(Written, Objs, []);
+ add_written_to_bag(Written, ObjsFun(), []);
+ _ when LockKind == read;
+ LockKind == write ->
+ add_written_to_set(Written);
_ ->
+ _ = ObjsFun(), % Fall back to request new lock and read from source
add_written_to_set(Written)
end.
@@ -1261,6 +1277,14 @@ match_object(Tid, Ts, Tab, Pat, LockKind)
match_object(_Tid, _Ts, Tab, Pat, _LockKind) ->
abort({bad_type, Tab, Pat}).
+add_written_index(Store, Pos, Tab, Key, Objs) when is_integer(Pos) ->
+ Pat = setelement(Pos, val({Tab, wild_pattern}), Key),
+ add_written_match(Store, Pat, Tab, Objs);
+add_written_index(Store, Pos, Tab, Key, Objs) when is_tuple(Pos) ->
+ IxF = mnesia_index:index_vals_f(val({Tab, storage_type}), Tab, Pos),
+ Ops = find_ops(Store, Tab, '_'),
+ add_ix_match(Ops, Objs, IxF, Key, val({Tab, setorbag})).
+
add_written_match(S, Pat, Tab, Objs) ->
Ops = find_ops(S, Tab, Pat),
FixedRes = add_match(Ops, Objs, val({Tab, setorbag})),
@@ -1287,6 +1311,46 @@ add_match([{_Oid, Val, write}|R], Objs, bag) ->
add_match([{Oid, Val, write}|R], Objs, set) ->
add_match(R, [Val | deloid(Oid,Objs)],set).
+add_ix_match([], Objs, _IxF, _Key, _Type) ->
+ Objs;
+add_ix_match(Written, Objs, IxF, Key, ordered_set) ->
+ %% Must use keysort which is stable
+ add_ordered_match(lists:keysort(1, ix_filter_ops(IxF, Key, Written)), Objs, []);
+add_ix_match([{Oid, _, delete}|R], Objs, IxF, Key, Type) ->
+ add_ix_match(R, deloid(Oid, Objs), IxF, Key, Type);
+add_ix_match([{_Oid, Val, delete_object}|R], Objs, IxF, Key, Type) ->
+ case ix_match(Val, IxF, Key) of
+ true ->
+ add_ix_match(R, lists:delete(Val, Objs), IxF, Key, Type);
+ false ->
+ add_ix_match(R, Objs, IxF, Key, Type)
+ end;
+add_ix_match([{_Oid, Val, write}|R], Objs, IxF, Key, bag) ->
+ case ix_match(Val, IxF, Key) of
+ true ->
+ add_ix_match(R, [Val | lists:delete(Val, Objs)], IxF, Key, bag);
+ false ->
+ add_ix_match(R, Objs, IxF, Key, bag)
+ end;
+add_ix_match([{Oid, Val, write}|R], Objs, IxF, Key, set) ->
+ case ix_match(Val, IxF, Key) of
+ true ->
+ add_ix_match(R, [Val | deloid(Oid,Objs)],IxF,Key,set);
+ false ->
+ add_ix_match(R, Objs, IxF, Key, set)
+ end.
+
+ix_match(Val, IxF, Key) ->
+ lists:member(Key, IxF(Val)).
+
+ix_filter_ops(IxF, Key, Ops) ->
+ lists:filter(
+ fun({_Oid, Obj, write}) ->
+ ix_match(Obj, IxF, Key);
+ (_) ->
+ true
+ end, Ops).
+
%% For ordered_set only !!
add_ordered_match(Written = [{{_, Key}, _, _}|_], [Obj|Objs], Acc)
when Key > element(2, Obj) ->
@@ -1625,6 +1689,16 @@ index_match_object(Tid, Ts, Tab, Pat, Attr, LockKind)
dirty_index_match_object(Tab, Pat, Attr); % Should be optimized?
tid ->
case mnesia_schema:attr_tab_to_pos(Tab, Attr) of
+ {_} ->
+ case LockKind of
+ read ->
+ Store = Ts#tidstore.store,
+ mnesia_locker:rlock_table(Tid, Store, Tab),
+ Objs = dirty_match_object(Tab, Pat),
+ add_written_match(Store, Pat, Tab, Objs);
+ _ ->
+ abort({bad_type, Tab, LockKind})
+ end;
Pos when Pos =< tuple_size(Pat) ->
case LockKind of
read ->
@@ -1672,8 +1746,8 @@ index_read(Tid, Ts, Tab, Key, Attr, LockKind)
false ->
Store = Ts#tidstore.store,
Objs = mnesia_index:read(Tid, Store, Tab, Key, Pos),
- Pat = setelement(Pos, val({Tab, wild_pattern}), Key),
- add_written_match(Store, Pat, Tab, Objs);
+ add_written_index(
+ Ts#tidstore.store, Pos, Tab, Key, Objs);
true ->
abort({bad_type, Tab, Attr, Key})
end;
@@ -1809,7 +1883,7 @@ remote_dirty_match_object(Tab, Pat) ->
false ->
mnesia_lib:db_match_object(Tab, Pat);
true ->
- PosList = val({Tab, index}),
+ PosList = regular_indexes(Tab),
remote_dirty_match_object(Tab, Pat, PosList)
end.
@@ -1841,7 +1915,7 @@ remote_dirty_select(Tab, Spec) ->
false ->
mnesia_lib:db_select(Tab, Spec);
true ->
- PosList = val({Tab, index}),
+ PosList = regular_indexes(Tab),
remote_dirty_select(Tab, Spec, PosList)
end;
_ ->
@@ -1908,6 +1982,8 @@ dirty_index_match_object(Pat, _Attr) ->
dirty_index_match_object(Tab, Pat, Attr)
when is_atom(Tab), Tab /= schema, is_tuple(Pat), tuple_size(Pat) > 2 ->
case mnesia_schema:attr_tab_to_pos(Tab, Attr) of
+ {_} ->
+ dirty_match_object(Tab, Pat);
Pos when Pos =< tuple_size(Pat) ->
case has_var(element(2, Pat)) of
false ->
@@ -2682,7 +2758,7 @@ del_table_index(Tab, Ix) ->
-spec transform_table(Tab::table(), Fun, [Attr]) -> t_result(ok) when
Attr :: atom(),
- Fun:: fun((Record::tuple()) -> Transformed::tuple()).
+ Fun:: fun((Record::tuple()) -> Transformed::tuple()) | ignore.
transform_table(Tab, Fun, NewA) ->
try val({Tab, record_name}) of
OldRN -> mnesia_schema:transform_table(Tab, Fun, NewA, OldRN)
@@ -2693,7 +2769,7 @@ transform_table(Tab, Fun, NewA) ->
-spec transform_table(Tab::table(), Fun, [Attr], RecName) -> t_result(ok) when
RecName :: atom(),
Attr :: atom(),
- Fun:: fun((Record::tuple()) -> Transformed::tuple()).
+ Fun:: fun((Record::tuple()) -> Transformed::tuple()) | ignore.
transform_table(Tab, Fun, NewA, NewRN) ->
mnesia_schema:transform_table(Tab, Fun, NewA, NewRN).
@@ -3238,3 +3314,7 @@ put_activity_id(Activity) ->
mnesia_tm:put_activity_id(Activity).
put_activity_id(Activity,Fun) ->
mnesia_tm:put_activity_id(Activity,Fun).
+
+regular_indexes(Tab) ->
+ PosList = val({Tab, index}),
+ [P || P <- PosList, is_integer(P)].
diff --git a/lib/mnesia/src/mnesia.hrl b/lib/mnesia/src/mnesia.hrl
index da7e662288..fe48a6fe3d 100644
--- a/lib/mnesia/src/mnesia.hrl
+++ b/lib/mnesia/src/mnesia.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -47,6 +47,10 @@
-define(catch_val(Var), (try ?ets_lookup_element(mnesia_gvar, Var, 2)
catch error:_ -> {'EXIT', {badarg, []}} end)).
+-define(catch_val_and_stack(Var),
+ (try ?ets_lookup_element(mnesia_gvar, Var, 2)
+ catch error:_:_Stacktrace -> {'EXIT', _Stacktrace} end)).
+
%% It's important that counter is first, since we compare tid's
-record(tid,
diff --git a/lib/mnesia/src/mnesia_bup.erl b/lib/mnesia/src/mnesia_bup.erl
index 34f16f178b..e57fc5199d 100644
--- a/lib/mnesia/src/mnesia_bup.erl
+++ b/lib/mnesia/src/mnesia_bup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -90,9 +90,9 @@ iterate(Mod, Fun, Opaque, Acc) ->
catch throw:Err ->
close_read(R2),
Err;
- _:Reason ->
+ _:Reason:Stacktrace ->
close_read(R2),
- {error, {Reason, erlang:get_stacktrace()}}
+ {error, {Reason, Stacktrace}}
end
catch throw:{error,_} = Err ->
Err
@@ -198,9 +198,9 @@ do_read_schema_section(R) ->
try
{R3, RawSchema} = safe_apply(R2, read, [R2#restore.bup_data]),
do_read_schema_section(R3, verify_header(RawSchema), [])
- catch T:E ->
+ catch T:E:S ->
close_read(R2),
- erlang:raise(T,E,erlang:get_stacktrace())
+ erlang:raise(T,E,S)
end.
do_read_schema_section(R, {ok, B, C, []}, Acc) ->
diff --git a/lib/mnesia/src/mnesia_checkpoint.erl b/lib/mnesia/src/mnesia_checkpoint.erl
index 8112378ffd..3273d3d27e 100644
--- a/lib/mnesia/src/mnesia_checkpoint.erl
+++ b/lib/mnesia/src/mnesia_checkpoint.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017
+%% Copyright Ericsson AB 1996-2018
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1269,9 +1269,9 @@ system_code_change(Cp, _Module, _OldVsn, _Extra) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Local function in order to avoid external function call
val(Var) ->
- case ?catch_val(Var) of
- {'EXIT', _} -> mnesia_lib:other_val(Var);
- _VaLuE_ -> _VaLuE_
+ case ?catch_val_and_stack(Var) of
+ {'EXIT', Stacktrace} -> mnesia_lib:other_val(Var, Stacktrace);
+ Value -> Value
end.
-
diff --git a/lib/mnesia/src/mnesia_controller.erl b/lib/mnesia/src/mnesia_controller.erl
index 77013489b3..882de0d613 100644
--- a/lib/mnesia/src/mnesia_controller.erl
+++ b/lib/mnesia/src/mnesia_controller.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -185,9 +185,10 @@ max_loaders() ->
worker_res
}).
+%% Local function in order to avoid external function call
val(Var) ->
- case ?catch_val(Var) of
- {'EXIT', _} -> mnesia_lib:other_val(Var);
+ case ?catch_val_and_stack(Var) of
+ {'EXIT', Stacktrace} -> mnesia_lib:other_val(Var, Stacktrace);
Value -> Value
end.
@@ -771,22 +772,6 @@ handle_call({unannounce_add_table_copy, [Tab, Node], From}, ReplyTo, State) ->
noreply(State#state{early_msgs = [{call, Msg, undefined} | Msgs]})
end;
-handle_call({net_load, Tab, Cs}, From, State) ->
- State2 =
- case State#state.schema_is_merged of
- true ->
- Worker = #net_load{table = Tab,
- opt_reply_to = From,
- reason = {dumper,{add_table_copy, unknown}},
- cstruct = Cs
- },
- add_worker(Worker, State);
- false ->
- reply(From, {not_loaded, schema_not_merged}),
- State
- end,
- noreply(State2);
-
handle_call(Msg, From, State) when State#state.schema_is_merged /= true ->
%% Buffer early messages
Msgs = State#state.early_msgs,
@@ -1456,7 +1441,8 @@ orphan_tables([Tab | Tabs], Node, Ns, Local, Remote) ->
L = [Tab | Local],
orphan_tables(Tabs, Node, Ns, L, Remote);
Masters ->
- R = [{Tab, Masters} | Remote],
+ %% Do not disc_load table from RamCopyHolders
+ R = [{Tab, Masters -- RamCopyHolders} | Remote],
orphan_tables(Tabs, Node, Ns, Local, R)
end;
_ ->
@@ -2161,6 +2147,15 @@ load_table_fun(#net_load{cstruct=Cs, table=Tab, reason=Reason, opt_reply_to=Repl
{dumper,{add_table_copy,_}} -> true;
_ -> false
end,
+
+ OnlyRamCopies = case Cs of
+ #cstruct{disc_copies = DC,
+ disc_only_copies = DOC,
+ external_copies = Ext} ->
+ [] =:= (DC ++ (DOC ++ Ext)) -- [node()];
+ _ ->
+ false
+ end,
if
ReadNode == node() ->
%% Already loaded locally
@@ -2172,6 +2167,8 @@ load_table_fun(#net_load{cstruct=Cs, table=Tab, reason=Reason, opt_reply_to=Repl
end;
AccessMode == read_only, not AddTableCopy ->
fun() -> disc_load_table(Tab, Reason, ReplyTo) end;
+ Active =:= [], AddTableCopy, OnlyRamCopies ->
+ fun() -> disc_load_table(Tab, Reason, ReplyTo) end;
true ->
fun() ->
%% Either we cannot read the table yet
diff --git a/lib/mnesia/src/mnesia_dumper.erl b/lib/mnesia/src/mnesia_dumper.erl
index f0ed7aef4a..8ab11be2d3 100644
--- a/lib/mnesia/src/mnesia_dumper.erl
+++ b/lib/mnesia/src/mnesia_dumper.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -67,10 +67,10 @@ get_log_writes() ->
incr_log_writes() ->
Left = mnesia_lib:incr_counter(trans_log_writes_left, -1),
if
- Left > 0 ->
- ignore;
+ Left =:= 0 ->
+ adjust_log_writes(true);
true ->
- adjust_log_writes(true)
+ ignore
end.
adjust_log_writes(DoCast) ->
@@ -191,8 +191,7 @@ do_perform_dump(Cont, InPlace, InitBy, Regulator, OldVersion) ->
try insert_recs(Recs, InPlace, InitBy, Regulator, OldVersion) of
Version ->
do_perform_dump(C2, InPlace, InitBy, Regulator, Version)
- catch _:R when R =/= fatal ->
- ST = erlang:get_stacktrace(),
+ catch _:R:ST when R =/= fatal ->
Reason = {"Transaction log dump error: ~tp~n", [{R, ST}]},
close_files(InPlace, {error, Reason}, InitBy),
exit(Reason)
@@ -273,17 +272,12 @@ do_insert_rec(Tid, Rec, InPlace, InitBy, LogV) ->
end
end,
D = Rec#commit.disc_copies,
- ExtOps = commit_ext(Rec),
insert_ops(Tid, disc_copies, D, InPlace, InitBy, LogV),
- [insert_ops(Tid, Ext, Ops, InPlace, InitBy, LogV) ||
- {Ext, Ops} <- ExtOps,
- storage_semantics(Ext) == disc_copies],
+ insert_ext_ops(Tid, commit_ext(Rec), InPlace, InitBy),
case InitBy of
startup ->
DO = Rec#commit.disc_only_copies,
- insert_ops(Tid, disc_only_copies, DO, InPlace, InitBy, LogV),
- [insert_ops(Tid, Ext, Ops, InPlace, InitBy, LogV) ||
- {Ext, Ops} <- ExtOps, storage_semantics(Ext) == disc_only_copies];
+ insert_ops(Tid, disc_only_copies, DO, InPlace, InitBy, LogV);
_ ->
ignore
end.
@@ -291,11 +285,8 @@ do_insert_rec(Tid, Rec, InPlace, InitBy, LogV) ->
commit_ext(#commit{ext = []}) -> [];
commit_ext(#commit{ext = Ext}) ->
case lists:keyfind(ext_copies, 1, Ext) of
- {_, C} ->
- lists:foldl(fun({Ext0, Op}, D) ->
- orddict:append(Ext0, Op, D)
- end, orddict:new(), C);
- false -> []
+ {_, C} -> C;
+ false -> []
end.
update(_Tid, [], _DumperMode) ->
@@ -325,13 +316,27 @@ perform_update(Tid, SchemaOps, _DumperMode, _UseDir) ->
?eval_debug_fun({?MODULE, post_dump}, [InitBy]),
close_files(InPlace, ok, InitBy),
ok
- catch _:Reason when Reason =/= fatal ->
- ST = erlang:get_stacktrace(),
+ catch _:Reason:ST when Reason =/= fatal ->
Error = {error, {"Schema update error", {Reason, ST}}},
close_files(InPlace, Error, InitBy),
fatal("Schema update error ~tp ~tp", [{Reason,ST}, SchemaOps])
end.
+insert_ext_ops(Tid, ExtOps, InPlace, InitBy) ->
+ %% Note: ext ops cannot be part of pre-4.3 logs, so there's no need
+ %% to support the old operation order, as in `insert_ops'
+ lists:foreach(
+ fun ({Ext, Op}) ->
+ case storage_semantics(Ext) of
+ Semantics when Semantics == disc_copies;
+ Semantics == disc_only_copies, InitBy == startup ->
+ insert_op(Tid, Ext, Op, InPlace, InitBy);
+ _Other ->
+ ok
+ end
+ end,
+ ExtOps).
+
insert_ops(_Tid, _Storage, [], _InPlace, _InitBy, _) -> ok;
insert_ops(Tid, Storage, [Op], InPlace, InitBy, Ver) when Ver >= "4.3"->
insert_op(Tid, Storage, Op, InPlace, InitBy),
@@ -1471,8 +1476,9 @@ regulate(RegulatorPid) ->
{regulated, RegulatorPid} -> ok
end.
+%% Local function in order to avoid external function call
val(Var) ->
- case ?catch_val(Var) of
- {'EXIT', _} -> mnesia_lib:other_val(Var);
+ case ?catch_val_and_stack(Var) of
+ {'EXIT', Stacktrace} -> mnesia_lib:other_val(Var, Stacktrace);
Value -> Value
end.
diff --git a/lib/mnesia/src/mnesia_frag.erl b/lib/mnesia/src/mnesia_frag.erl
index c39f30e140..8f7dd321b0 100644
--- a/lib/mnesia/src/mnesia_frag.erl
+++ b/lib/mnesia/src/mnesia_frag.erl
@@ -1,7 +1,7 @@
%%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1157,9 +1157,10 @@ remove_node(Node, Cs) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Helpers
+%% Local function in order to avoid external function call
val(Var) ->
- case ?catch_val(Var) of
- {'EXIT', _} -> mnesia_lib:other_val(Var);
+ case ?catch_val_and_stack(Var) of
+ {'EXIT', Stacktrace} -> mnesia_lib:other_val(Var, Stacktrace);
Value -> Value
end.
diff --git a/lib/mnesia/src/mnesia_index.erl b/lib/mnesia/src/mnesia_index.erl
index d121bd01e9..6f1c21e3b9 100644
--- a/lib/mnesia/src/mnesia_index.erl
+++ b/lib/mnesia/src/mnesia_index.erl
@@ -1,8 +1,8 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
+%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
@@ -14,7 +14,7 @@
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
-%%
+%%
%% %CopyrightEnd%
%%
@@ -37,7 +37,7 @@
db_match_erase/2,
get_index_table/2,
get_index_table/3,
-
+
tab2filename/2,
init_index/2,
init_indecies/3,
@@ -45,6 +45,7 @@
del_transient/3,
del_index_table/3,
+ index_vals_f/3,
index_info/2,
ext_index_instances/1]).
@@ -60,9 +61,14 @@ read(Tid, Store, Tab, IxKey, Pos) ->
ResList = mnesia_locker:ixrlock(Tid, Store, Tab, IxKey, Pos),
%% Remove all tuples which don't include Ixkey, happens when Tab is a bag
case val({Tab, setorbag}) of
- bag ->
+ bag when is_integer(Pos) ->
mnesia_lib:key_search_all(IxKey, Pos, ResList);
- _ ->
+ bag when is_tuple(Pos) ->
+ TabStorage = val({Tab, storage_type}),
+ ValsF = index_vals_f(TabStorage, Tab, Pos),
+ [Obj || Obj <- ResList,
+ lists:member(IxKey, ValsF(Obj))];
+ _ ->
ResList
end.
@@ -136,7 +142,7 @@ del_object_index2([], _, _Storage, _Tab, _K, _Obj) -> ok;
del_object_index2([{{Pos, Type}, Ixt} | Tail], SoB, Storage, Tab, K, Obj) ->
ValsF = index_vals_f(Storage, Tab, Pos),
case SoB of
- bag ->
+ bag ->
del_object_bag(Type, ValsF, Tab, K, Obj, Ixt);
_ -> %% If set remove the tuple in index table
del_ixes(Type, Ixt, ValsF, Obj, K)
@@ -155,7 +161,7 @@ del_object_bag_([IxK|IxKs], Found, Type, Tab, Key, Obj, Ixt) ->
bag ->
db_match_erase(Ixt, {IxK, Key});
ordered ->
- db_erase(Ixt, {{IxK, Key}})
+ db_erase(Ixt, {IxK, Key})
end;
_ ->
ok
@@ -197,7 +203,7 @@ merge([], _, _, Ack) ->
realkeys(Tab, Pos, IxKey) ->
Index = get_index_table(Tab, Pos),
db_get(Index, IxKey). % a list on the form [{IxKey, RealKey1} , ....
-
+
dirty_select(Tab, Spec, Pos) when is_integer(Pos) ->
%% Assume that we are on the node where the replica is
%% Returns the records without applying the match spec
@@ -233,7 +239,7 @@ dirty_read2(Tab, IxKey, Pos) ->
end, Acc, mnesia_lib:db_get(Storage, Tab, K))
end, [], Keys)).
-pick_index([{{{Pfx,_},IxType}, Ixt}|_], _Tab, {_} = Pfx) ->
+pick_index([{{{Pfx,_,_},IxType}, Ixt}|_], _Tab, {_} = Pfx) ->
{IxType, Ixt};
pick_index([{{Pos,IxType}, Ixt}|_], _Tab, Pos) ->
{IxType, Ixt};
@@ -242,7 +248,7 @@ pick_index([_|T], Tab, Pos) ->
pick_index([], Tab, Pos) ->
mnesia:abort({no_exist, Tab, {index, Pos}}).
-
+
%%%%%%% Creation, Init and deletion routines for index tables
%% We can have several indexes on the same table
@@ -387,12 +393,12 @@ init_ext_index(Tab, Storage, Alias, Mod, [{Pos,Type} | Tail]) ->
create_fun(Cont, Tab, Pos) ->
IxF = index_vals_f(disc_only_copies, Tab, Pos),
fun(read) ->
- Data =
+ Data =
case Cont of
{start, KeysPerChunk} ->
mnesia_lib:db_init_chunk(
disc_only_copies, Tab, KeysPerChunk);
- '$end_of_table' ->
+ '$end_of_table' ->
'$end_of_table';
_Else ->
mnesia_lib:db_chunk(disc_only_copies, Cont)
@@ -462,7 +468,7 @@ add_index_info(Tab, SetOrBag, IxElem) ->
%% Check later if mnesia_tm is sensitive about the order
mnesia_lib:set({Tab, index_info}, IndexInfo),
mnesia_lib:set({Tab, index}, index_positions(IndexInfo)),
- mnesia_lib:set({Tab, commit_work},
+ mnesia_lib:set({Tab, commit_work},
mnesia_lib:sort_commit([IndexInfo | Commit]));
{value, Old} ->
%% We could check for consistency here
@@ -470,7 +476,7 @@ add_index_info(Tab, SetOrBag, IxElem) ->
mnesia_lib:set({Tab, index_info}, Index),
mnesia_lib:set({Tab, index}, index_positions(Index)),
NewC = lists:keyreplace(index, 1, Commit, Index),
- mnesia_lib:set({Tab, commit_work},
+ mnesia_lib:set({Tab, commit_work},
mnesia_lib:sort_commit(NewC))
end.
@@ -488,19 +494,19 @@ del_index_info(Tab, Pos) ->
element(1,P)=/=Pos
end,
Old#index.pos_list) of
- [] ->
+ [] ->
IndexInfo = index_info(Old#index.setorbag,[]),
mnesia_lib:set({Tab, index_info}, IndexInfo),
mnesia_lib:set({Tab, index}, index_positions(IndexInfo)),
NewC = lists:keydelete(index, 1, Commit),
- mnesia_lib:set({Tab, commit_work},
+ mnesia_lib:set({Tab, commit_work},
mnesia_lib:sort_commit(NewC));
New ->
Index = Old#index{pos_list = New},
mnesia_lib:set({Tab, index_info}, Index),
mnesia_lib:set({Tab, index}, index_positions(Index)),
NewC = lists:keyreplace(index, 1, Commit, Index),
- mnesia_lib:set({Tab, commit_work},
+ mnesia_lib:set({Tab, commit_work},
mnesia_lib:sort_commit(NewC))
end
end.
@@ -537,7 +543,7 @@ db_match_erase({{ext,_,_} = Ext, Ixt}, Pat) ->
mnesia_lib:db_match_erase(Ext, Ixt, Pat);
db_match_erase({dets, Ixt}, Pat) ->
ok = dets:match_delete(Ixt, Pat).
-
+
db_select({ram, Ixt}, Pat) ->
ets:select(Ixt, Pat);
db_select({{ext,_,_} = Ext, Ixt}, Pat) ->
@@ -545,7 +551,7 @@ db_select({{ext,_,_} = Ext, Ixt}, Pat) ->
db_select({dets, Ixt}, Pat) ->
dets:select(Ixt, Pat).
-
+
get_index_table(Tab, Pos) ->
get_index_table(Tab, val({Tab, storage_type}), Pos).
diff --git a/lib/mnesia/src/mnesia_late_loader.erl b/lib/mnesia/src/mnesia_late_loader.erl
index e4f8dcf2b9..45afda6e4b 100644
--- a/lib/mnesia/src/mnesia_late_loader.erl
+++ b/lib/mnesia/src/mnesia_late_loader.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/src/mnesia_lib.erl b/lib/mnesia/src/mnesia_lib.erl
index 53fdd76de8..6abc05fade 100644
--- a/lib/mnesia/src/mnesia_lib.erl
+++ b/lib/mnesia/src/mnesia_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -116,7 +116,7 @@
lock_table/1,
mkcore/1,
not_active_here/1,
- other_val/1,
+ other_val/2,
overload_read/0,
overload_read/1,
overload_set/2,
@@ -435,8 +435,8 @@ validate_record(Tab, Obj) ->
%%
val(Var) ->
- case ?catch_val(Var) of
- {'EXIT', _} -> other_val(Var);
+ case ?catch_val_and_stack(Var) of
+ {'EXIT', Stacktrace} -> other_val(Var, Stacktrace);
_VaLuE_ -> _VaLuE_
end.
@@ -446,9 +446,9 @@ set(Var, Val) ->
unset(Var) ->
?ets_delete(mnesia_gvar, Var).
-other_val(Var) ->
+other_val(Var, Stacktrace) ->
case other_val_1(Var) of
- error -> pr_other(Var);
+ error -> pr_other(Var, Stacktrace);
Val -> Val
end.
@@ -460,8 +460,8 @@ other_val_1(Var) ->
_ -> error
end.
--spec pr_other(_) -> no_return().
-pr_other(Var) ->
+-spec pr_other(_, _) -> no_return().
+pr_other(Var, Stacktrace) ->
Why =
case is_running() of
no -> {node_not_running, node()};
@@ -469,7 +469,7 @@ pr_other(Var) ->
end,
verbose("~p (~tp) val(mnesia_gvar, ~tw) -> ~p ~tp ~n",
[self(), process_info(self(), registered_name),
- Var, Why, erlang:get_stacktrace()]),
+ Var, Why, Stacktrace]),
mnesia:abort(Why).
%% Some functions for list valued variables
@@ -929,7 +929,7 @@ error_desc(no_transaction) -> "Operation not allowed outside transactions";
error_desc(combine_error) -> "Table options were ilegally combined";
error_desc(bad_index) -> "Index already exists or was out of bounds";
error_desc(already_exists) -> "Some schema option we try to set is already on";
-error_desc(index_exists)-> "Some ops can not be performed on tabs with index";
+error_desc(index_exists)-> "Some ops cannot be performed on tabs with index";
error_desc(no_exists)-> "Tried to perform op on non-existing (non alive) item";
error_desc(system_limit) -> "Some system_limit was exhausted";
error_desc(mnesia_down) -> "A transaction involving objects at some remote "
diff --git a/lib/mnesia/src/mnesia_loader.erl b/lib/mnesia/src/mnesia_loader.erl
index 4c6336cb73..2cdae0c906 100644
--- a/lib/mnesia/src/mnesia_loader.erl
+++ b/lib/mnesia/src/mnesia_loader.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -34,9 +34,10 @@
-include("mnesia.hrl").
+%% Local function in order to avoid external function call
val(Var) ->
- case ?catch_val(Var) of
- {'EXIT', _} -> mnesia_lib:other_val(Var);
+ case ?catch_val_and_stack(Var) of
+ {'EXIT', Stacktrace} -> mnesia_lib:other_val(Var, Stacktrace);
Value -> Value
end.
@@ -66,7 +67,7 @@ do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == disc_copies ->
EtsOpts = proplists:get_value(ets, StorageProps, []),
Args = [{keypos, 2}, public, named_table, Type | EtsOpts],
case Reason of
- {dumper, _} -> %% Resources already allocated
+ {dumper, DR} when is_atom(DR) -> %% Resources already allocated
ignore;
_ ->
mnesia_monitor:mktab(Tab, Args),
@@ -90,8 +91,8 @@ do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == ram_copies ->
EtsOpts = proplists:get_value(ets, StorageProps, []),
Args = [{keypos, 2}, public, named_table, Type | EtsOpts],
case Reason of
- {dumper, _} -> %% Resources allready allocated
- ignore;
+ {dumper, DR} when is_atom(DR) ->
+ ignore; %% Resources already allocated
_ ->
mnesia_monitor:mktab(Tab, Args),
Fname = mnesia_lib:tab2dcd(Tab),
@@ -130,7 +131,7 @@ do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == disc_only_copies -
{repair, mnesia_monitor:get_env(auto_repair)}
| DetsOpts],
case Reason of
- {dumper, _} ->
+ {dumper, DR} when is_atom(DR) ->
mnesia_index:init_index(Tab, Storage),
snmpify(Tab, Storage),
set({Tab, load_node}, node()),
@@ -535,7 +536,7 @@ init_table(Tab, _, Fun, _DetsInfo,_) ->
try
true = ets:init_table(Tab, Fun),
ok
- catch _:Else -> {Else, erlang:get_stacktrace()}
+ catch _:Else:Stacktrace -> {Else, Stacktrace}
end.
@@ -777,9 +778,9 @@ do_send_table(Pid, Tab, Storage, RemoteS) ->
throw:receiver_died ->
cleanup_tab_copier(Pid, Storage, Tab),
ok;
- error:Reason -> %% Prepare failed
+ error:Reason:Stacktrace -> %% Prepare failed
cleanup_tab_copier(Pid, Storage, Tab),
- {error, {tab_copier, Tab, {Reason, erlang:get_stacktrace()}}}
+ {error, {tab_copier, Tab, {Reason, Stacktrace}}}
after
unlink(whereis(mnesia_tm))
end.
diff --git a/lib/mnesia/src/mnesia_locker.erl b/lib/mnesia/src/mnesia_locker.erl
index 073b48abc0..f68626413e 100644
--- a/lib/mnesia/src/mnesia_locker.erl
+++ b/lib/mnesia/src/mnesia_locker.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -97,10 +97,11 @@ init(Parent) ->
end,
loop(#state{supervisor = Parent}).
+%% Local function in order to avoid external function call
val(Var) ->
- case ?catch_val(Var) of
- {'EXIT', _} -> mnesia_lib:other_val(Var);
- _VaLuE_ -> _VaLuE_
+ case ?catch_val_and_stack(Var) of
+ {'EXIT', Stacktrace} -> mnesia_lib:other_val(Var, Stacktrace);
+ Value -> Value
end.
reply(From, R) ->
diff --git a/lib/mnesia/src/mnesia_log.erl b/lib/mnesia/src/mnesia_log.erl
index a2de23a2a3..03411ace41 100644
--- a/lib/mnesia/src/mnesia_log.erl
+++ b/lib/mnesia/src/mnesia_log.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/src/mnesia_recover.erl b/lib/mnesia/src/mnesia_recover.erl
index d792070332..2ccea1ea6d 100644
--- a/lib/mnesia/src/mnesia_recover.erl
+++ b/lib/mnesia/src/mnesia_recover.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -177,10 +177,10 @@ disconnect(Node) ->
log_decision(D) ->
cast({log_decision, D}).
+%% Local function in order to avoid external function call
val(Var) ->
- case ?catch_val(Var) of
- {'EXIT', _Reason} ->
- mnesia_lib:other_val(Var);
+ case ?catch_val_and_stack(Var) of
+ {'EXIT', Stacktrace} -> mnesia_lib:other_val(Var, Stacktrace);
Value -> Value
end.
diff --git a/lib/mnesia/src/mnesia_schema.erl b/lib/mnesia/src/mnesia_schema.erl
index 71952af31c..ef38adca1e 100644
--- a/lib/mnesia/src/mnesia_schema.erl
+++ b/lib/mnesia/src/mnesia_schema.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -181,9 +181,10 @@ exit_on_error({error, Reason}) ->
exit_on_error(GoodRes) ->
GoodRes.
+%% Local function in order to avoid external function call
val(Var) ->
- case ?catch_val(Var) of
- {'EXIT', _} -> mnesia_lib:other_val(Var);
+ case ?catch_val_and_stack(Var) of
+ {'EXIT', Stacktrace} -> mnesia_lib:other_val(Var, Stacktrace);
Value -> Value
end.
@@ -2695,10 +2696,10 @@ prepare_op(_Tid, {op, transform, Fun, TabDef}, _WaitFor) ->
Objs ->
mnesia_lib:db_fixtable(Storage, Tab, false),
{true, Objs, mandatory}
- catch _:Reason ->
+ catch _:Reason:Stacktrace ->
mnesia_lib:db_fixtable(Storage, Tab, false),
mnesia_lib:important("Transform function failed: '~tp' in '~tp'",
- [Reason, erlang:get_stacktrace()]),
+ [Reason, Stacktrace]),
exit({"Bad transform function", Tab, Fun, node(), Reason})
end
end;
diff --git a/lib/mnesia/src/mnesia_subscr.erl b/lib/mnesia/src/mnesia_subscr.erl
index dfaa20d2d3..21a308cfb6 100644
--- a/lib/mnesia/src/mnesia_subscr.erl
+++ b/lib/mnesia/src/mnesia_subscr.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/src/mnesia_text.erl b/lib/mnesia/src/mnesia_text.erl
index 7d24d09472..cc21621ff4 100644
--- a/lib/mnesia/src/mnesia_text.erl
+++ b/lib/mnesia/src/mnesia_text.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/src/mnesia_tm.erl b/lib/mnesia/src/mnesia_tm.erl
index ebf580d09e..8b79fca1d7 100644
--- a/lib/mnesia/src/mnesia_tm.erl
+++ b/lib/mnesia/src/mnesia_tm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -121,10 +121,11 @@ init(Parent) ->
proc_lib:init_ack(Parent, {ok, self()}),
doit_loop(#state{supervisor = Parent}).
+%% Local function in order to avoid external function call
val(Var) ->
- case ?catch_val(Var) of
- {'EXIT', _} -> mnesia_lib:other_val(Var);
- _VaLuE_ -> _VaLuE_
+ case ?catch_val_and_stack(Var) of
+ {'EXIT', Stacktrace} -> mnesia_lib:other_val(Var, Stacktrace);
+ Value -> Value
end.
reply({From,Ref}, R) ->
@@ -597,9 +598,9 @@ recover_coordinator(Tid, Etabs) ->
false -> %% When killed before store havn't been copied to
ok %% to the new nested trans store.
end
- catch _:Reason ->
+ catch _:Reason:Stacktrace ->
dbg_out("Recovery of coordinator ~p failed: ~tp~n",
- [Tid, {Reason, erlang:get_stacktrace()}]),
+ [Tid, {Reason, Stacktrace}]),
Protocol = asym_trans,
tell_outcome(Tid, Protocol, node(), CheckNodes, TellNodes)
end,
@@ -742,8 +743,9 @@ non_transaction(OldState, Fun, Args, ActivityKind, Mod) ->
{aborted, Reason} -> mnesia:abort(Reason);
Res -> Res
catch
- throw:Throw -> throw(Throw);
- _:Reason -> exit(Reason)
+ throw:Throw -> throw(Throw);
+ error:Reason:ST -> exit({Reason, ST});
+ exit:Reason -> exit(Reason)
after
case OldState of
undefined -> erase(mnesia_activity_state);
@@ -825,8 +827,7 @@ execute_transaction(Fun, Args, Factor, Retries, Type) ->
catch throw:Value -> %% User called throw
Reason = {aborted, {throw, Value}},
return_abort(Fun, Args, Reason);
- error:Reason ->
- ST = erlang:get_stacktrace(),
+ error:Reason:ST ->
check_exit(Fun, Args, Factor, Retries, {Reason,ST}, Type);
_:Reason ->
check_exit(Fun, Args, Factor, Retries, Reason, Type)
@@ -1661,7 +1662,7 @@ commit_participant(Coord, Tid, Bin, C0, DiscNs, _RamNs) ->
?eval_debug_fun({?MODULE, commit_participant, pre}, [{tid, Tid}]),
try mnesia_schema:prepare_commit(Tid, C0, {part, Coord}) of
{Modified, C = #commit{}, DumperMode} ->
- %% If we can not find any local unclear decision
+ %% If we cannot find any local unclear decision
%% we should presume abort at startup recovery
case lists:member(node(), DiscNs) of
false ->
@@ -1796,14 +1797,13 @@ do_update(Tid, Storage, [Op | Ops], OldRes) ->
try do_update_op(Tid, Storage, Op) of
ok -> do_update(Tid, Storage, Ops, OldRes);
NewRes -> do_update(Tid, Storage, Ops, NewRes)
- catch _:Reason ->
+ catch _:Reason:ST ->
%% This may only happen when we recently have
%% deleted our local replica, changed storage_type
%% or transformed table
%% BUGBUG: Updates may be lost if storage_type is changed.
%% Determine actual storage type and try again.
%% BUGBUG: Updates may be lost if table is transformed.
- ST = erlang:get_stacktrace(),
verbose("do_update in ~w failed: ~tp -> {'EXIT', ~tp}~n",
[Tid, Op, {Reason, ST}]),
do_update(Tid, Storage, Ops, OldRes)
@@ -1914,11 +1914,10 @@ commit_clear([H|R], Tid, Storage, Tab, K, Obj)
do_snmp(_, []) -> ok;
do_snmp(Tid, [Head|Tail]) ->
try mnesia_snmp_hook:update(Head)
- catch _:Reason ->
+ catch _:Reason:ST ->
%% This should only happen when we recently have
%% deleted our local replica or recently deattached
%% the snmp table
- ST = erlang:get_stacktrace(),
verbose("do_snmp in ~w failed: ~tp -> {'EXIT', ~tp}~n",
[Tid, Head, {Reason, ST}])
end,
@@ -2212,7 +2211,7 @@ display_pid_info(Pid) ->
Other
end,
Reds = fetch(reductions, Info),
- LM = length(fetch(messages, Info)),
+ LM = fetch(message_queue_len, Info),
pformat(io_lib:format("~p", [Pid]),
io_lib:format("~tp", [Call]),
io_lib:format("~tp", [Curr]), Reds, LM)
diff --git a/lib/mnesia/test/Makefile b/lib/mnesia/test/Makefile
index 5b61b1af65..b43bc82801 100644
--- a/lib/mnesia/test/Makefile
+++ b/lib/mnesia/test/Makefile
@@ -53,7 +53,8 @@ MODULES= \
mnesia_measure_test \
mnesia_cost \
mnesia_dbn_meters \
- ext_test
+ ext_test \
+ mnesia_index_plugin_test
DocExamplesDir := ../doc/src/
diff --git a/lib/mnesia/test/README b/lib/mnesia/test/README
index e0ced7399d..30a0d2fd64 100644
--- a/lib/mnesia/test/README
+++ b/lib/mnesia/test/README
@@ -51,7 +51,7 @@ stated as test suite configuration parameters, but by default
the extra node names are generated. In this example the names
will be: a, a1 and a2. It is enough to start the first node
manually, the extra nodes will automatically be started if
-neccessary.
+necessary.
The attached UNIX shell script mt, does not work on all
platforms, but it may be used as a source for inspiration. It
@@ -63,7 +63,7 @@ test cases (i.e. test cases that encountered an error).
During development we want to be able to run the test cases
in the debugger. This demands a little bit of preparations:
- - Start the neccessary number of nodes (normally 3).
+ - Start the necessary number of nodes (normally 3).
This may either be done by running the mt script or
by starting the main node and then invoke mt:start_nodes()
to start the extra nodes with slave.
@@ -73,7 +73,7 @@ in the debugger. This demands a little bit of preparations:
- Load all files that needs to be interpreted. This is typically
all Mnesia files plus the test case. By invoking mnesia:ni()
- and mnesia:ni([TestModule]) the neccessary modules will be
+ and mnesia:ni([TestModule]) the necessary modules will be
loaded on all CONNECTED nodes.
The test case execution is supervised in order to ensure that no test
diff --git a/lib/mnesia/test/mnesia_SUITE.erl b/lib/mnesia/test/mnesia_SUITE.erl
index 279744dbb0..b41bf22efa 100644
--- a/lib/mnesia/test/mnesia_SUITE.erl
+++ b/lib/mnesia/test/mnesia_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -69,12 +69,13 @@ groups() ->
%% covered.
[{light, [],
[{group, install}, {group, nice}, {group, evil},
- {group, mnesia_frag_test, light}, {group, qlc},
+ {group, mnesia_frag_test, light}, {group, qlc}, {group, index_plugins},
{group, registry}, {group, config}, {group, examples}]},
{install, [], [{mnesia_install_test, all}]},
{nice, [], [{mnesia_nice_coverage_test, all}]},
{evil, [], [{mnesia_evil_coverage_test, all}]},
{qlc, [], [{mnesia_qlc_test, all}]},
+ {index_plugins, [], [{mnesia_index_plugin_test, all}]},
{registry, [], [{mnesia_registry_test, all}]},
{config, [], [{mnesia_config_test, all}]},
{examples, [], [{mnesia_examples_test, all}]},
diff --git a/lib/mnesia/test/mnesia_atomicity_test.erl b/lib/mnesia/test/mnesia_atomicity_test.erl
index 58a5dc1d40..4764f9e7c0 100644
--- a/lib/mnesia/test/mnesia_atomicity_test.erl
+++ b/lib/mnesia/test/mnesia_atomicity_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_bench_SUITE.erl b/lib/mnesia/test/mnesia_bench_SUITE.erl
index 5cc01867c4..8a225629e6 100644
--- a/lib/mnesia/test/mnesia_bench_SUITE.erl
+++ b/lib/mnesia/test/mnesia_bench_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_consistency_test.erl b/lib/mnesia/test/mnesia_consistency_test.erl
index 7a2678cee3..46bafaf65c 100644
--- a/lib/mnesia/test/mnesia_consistency_test.erl
+++ b/lib/mnesia/test/mnesia_consistency_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_cost.erl b/lib/mnesia/test/mnesia_cost.erl
index 4d0dd7b0ee..b5d5253147 100644
--- a/lib/mnesia/test/mnesia_cost.erl
+++ b/lib/mnesia/test/mnesia_cost.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_dirty_access_test.erl b/lib/mnesia/test/mnesia_dirty_access_test.erl
index 92124ebc65..984f43582c 100644
--- a/lib/mnesia/test/mnesia_dirty_access_test.erl
+++ b/lib/mnesia/test/mnesia_dirty_access_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -48,7 +48,7 @@
del_table_copy_1/1, del_table_copy_2/1, del_table_copy_3/1,
add_table_copy_1/1, add_table_copy_2/1, add_table_copy_3/1,
add_table_copy_4/1, move_table_copy_1/1, move_table_copy_2/1,
- move_table_copy_3/1, move_table_copy_4/1]).
+ move_table_copy_3/1, move_table_copy_4/1, dirty_error_stacktrace/1]).
-export([update_trans/3]).
@@ -64,7 +64,7 @@ all() ->
{group, dirty_update_counter}, {group, dirty_delete},
{group, dirty_delete_object},
{group, dirty_match_object}, {group, dirty_index},
- {group, dirty_iter}, {group, admin_tests}].
+ {group, dirty_iter}, {group, admin_tests}, dirty_error_stacktrace].
groups() ->
[{dirty_write, [],
@@ -114,6 +114,36 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Errors in dirty activity should have stacktrace
+dirty_error_stacktrace(Config) ->
+ %% Custom errors should have stacktrace
+ try
+ mnesia:async_dirty(fun() -> error(custom_error) end)
+ catch
+ exit:{custom_error, _} -> ok
+ end,
+
+ %% Undef error should have unknown module and function in the stacktrace
+ try
+ mnesia:async_dirty(fun() -> unknown_module:unknown_fun(arg) end)
+ catch
+ exit:{undef, [{unknown_module, unknown_fun, [arg], []} | _]} -> ok
+ end,
+
+ %% Exists don't have stacktrace
+ try
+ mnesia:async_dirty(fun() -> exit(custom_error) end)
+ catch
+ exit:custom_error -> ok
+ end,
+
+ %% Aborts don't have a stacktrace (unfortunately)
+ try
+ mnesia:async_dirty(fun() -> mnesia:abort(custom_abort) end)
+ catch
+ exit:{aborted, custom_abort} -> ok
+ end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Write records dirty
diff --git a/lib/mnesia/test/mnesia_durability_test.erl b/lib/mnesia/test/mnesia_durability_test.erl
index 2fac5cac82..ccbfdc9738 100644
--- a/lib/mnesia/test/mnesia_durability_test.erl
+++ b/lib/mnesia/test/mnesia_durability_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -46,6 +46,7 @@
master_nodes/1, starting_master_nodes/1,
master_on_non_local_tables/1,
remote_force_load_with_local_master_node/1,
+ master_node_with_ram_copy_2/1, master_node_with_ram_copy_3/1,
dump_ram_copies/1, dump_disc_copies/1, dump_disc_only/1]).
-include("mnesia_test_lib.hrl").
@@ -91,7 +92,8 @@ groups() ->
{load_tables_with_master_tables, [],
[master_nodes, starting_master_nodes,
master_on_non_local_tables,
- remote_force_load_with_local_master_node]},
+ remote_force_load_with_local_master_node,
+ master_node_with_ram_copy_2, master_node_with_ram_copy_3]},
{durability_of_dump_tables, [],
[dump_ram_copies, dump_disc_copies, dump_disc_only]}].
@@ -1165,6 +1167,107 @@ remote_force_load_with_local_master_node(Config) when is_list(Config) ->
?verify_mnesia(Nodes, []).
+master_node_with_ram_copy_2(Config) when is_list(Config) ->
+ [A, B] = Nodes = ?acquire_nodes(2, Config),
+ Tab = ?FUNCTION_NAME,
+ ?match({atomic,ok}, mnesia:create_table(Tab, [{disc_copies, [A]}, {ram_copies, [B]}])),
+ ?match({atomic,ok}, mnesia:sync_transaction(?SDwrite({Tab, 1, init}))),
+
+ %% Test that we don't load from ram_copies
+ ?match(stopped, rpc:call(A, mnesia, stop, [])),
+ ?match(stopped, rpc:call(B, mnesia, stop, [])),
+ ?match(ok, rpc:call(B, mnesia, start, [])),
+ ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 1000])),
+ ?match(ok, rpc:call(A, mnesia, start, [])),
+ ?match(ok, rpc:call(B, mnesia, wait_for_tables, [[Tab], 3000])),
+ ?match([{Tab, 1, init}], rpc:call(A, mnesia, dirty_read, [{Tab, 1}])),
+ ?match([{Tab, 1, init}], rpc:call(B, mnesia, dirty_read, [{Tab, 1}])),
+
+ %% Test that master_nodes set to ram_copy node require force_load
+ ?match(ok, rpc:call(A, mnesia, set_master_nodes, [[B]])),
+ ?match(stopped, rpc:call(A, mnesia, stop, [])),
+ ?match(stopped, rpc:call(B, mnesia, stop, [])),
+ ?match(ok, rpc:call(B, mnesia, start, [])),
+ ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 1000])),
+ ?match(ok, rpc:call(A, mnesia, start, [])),
+ ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 1000])),
+
+ ?match(yes, rpc:call(A, mnesia, force_load_table, [Tab])),
+ ?match(ok, rpc:call(A, mnesia, wait_for_tables, [[Tab], 1000])),
+ ?match(ok, rpc:call(B, mnesia, wait_for_tables, [[Tab], 1000])),
+ ?match([{Tab, 1, init}], rpc:call(A, mnesia, dirty_read, [{Tab, 1}])),
+ ?match([{Tab, 1, init}], rpc:call(B, mnesia, dirty_read, [{Tab, 1}])),
+
+ ?verify_mnesia(Nodes, []).
+
+
+master_node_with_ram_copy_3(Config) when is_list(Config) ->
+ [A, B, C] = Nodes = ?acquire_nodes(3, Config),
+ Tab = ?FUNCTION_NAME,
+ ?match({atomic,ok}, mnesia:create_table(Tab, [{disc_copies, [A,C]}, {ram_copies, [B]}])),
+ ?match({atomic,ok}, mnesia:sync_transaction(?SDwrite({Tab, 1, init}))),
+
+ %% Test that we don't load from ram_copies
+ ?match(stopped, rpc:call(A, mnesia, stop, [])),
+ ?match(stopped, rpc:call(C, mnesia, stop, [])),
+ ?match(stopped, rpc:call(B, mnesia, stop, [])),
+ ?match(ok, rpc:call(B, mnesia, start, [])),
+ ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 1000])),
+ ?match(ok, rpc:call(A, mnesia, start, [])),
+ ?match(ok, rpc:call(C, mnesia, start, [])),
+ ?match(ok, rpc:call(B, mnesia, wait_for_tables, [[Tab], 3000])),
+ ?match(ok, rpc:call(A, mnesia, wait_for_tables, [[Tab], 3000])),
+ ?match([{Tab, 1, init}], rpc:call(A, mnesia, dirty_read, [{Tab, 1}])),
+ ?match([{Tab, 1, init}], rpc:call(B, mnesia, dirty_read, [{Tab, 1}])),
+ ?match([{Tab, 1, init}], rpc:call(C, mnesia, dirty_read, [{Tab, 1}])),
+
+ %% Test that master_nodes set to ram_copy node will wait until loaded
+ ?match(ok, rpc:call(A, mnesia, set_master_nodes, [[B]])),
+ ?match(stopped, rpc:call(A, mnesia, stop, [])),
+ ?match({atomic,ok}, rpc:call(B, mnesia, sync_transaction, [?SDwrite({Tab, 1, update})])),
+ ?match(stopped, rpc:call(C, mnesia, stop, [])),
+ ?match({atomic,ok}, rpc:call(B, mnesia, sync_transaction, [?SDwrite({Tab, 1, ram_copies})])),
+ ?match(stopped, rpc:call(B, mnesia, stop, [])),
+ ?match(ok, rpc:call(B, mnesia, start, [])),
+ ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 500])),
+ ?match(ok, rpc:call(A, mnesia, start, [])),
+ ?match({timeout, [Tab]}, rpc:call(A, mnesia, wait_for_tables, [[Tab], 500])),
+ ?match(ok, rpc:call(C, mnesia, start, [])),
+ ?match(ok, rpc:call(B, mnesia, wait_for_tables, [[Tab], 3000])),
+ ?match(ok, rpc:call(A, mnesia, wait_for_tables, [[Tab], 3000])),
+ ?match([{Tab, 1, update}], rpc:call(A, mnesia, dirty_read, [{Tab, 1}])),
+ ?match([{Tab, 1, update}], rpc:call(B, mnesia, dirty_read, [{Tab, 1}])),
+ ?match([{Tab, 1, update}], rpc:call(C, mnesia, dirty_read, [{Tab, 1}])),
+
+ %% Test that master_nodes set to ram_copy node requires force load
+ ?match({atomic,ok}, mnesia:sync_transaction(?SDwrite({Tab, 1, init}))),
+ ?match(ok, rpc:call(A, mnesia, set_master_nodes, [[B]])),
+ ?match(ok, rpc:call(C, mnesia, set_master_nodes, [[B]])),
+
+ ?match(stopped, rpc:call(A, mnesia, stop, [])),
+ ?match({atomic,ok}, rpc:call(B, mnesia, sync_transaction, [?SDwrite({Tab, 1, update})])),
+ ?match(stopped, rpc:call(C, mnesia, stop, [])),
+ ?match({atomic,ok}, rpc:call(B, mnesia, sync_transaction, [?SDwrite({Tab, 1, ram_copies})])),
+ ?match(stopped, rpc:call(B, mnesia, stop, [])),
+ ?match(ok, rpc:call(B, mnesia, start, [])),
+ ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 500])),
+ ?match(ok, rpc:call(A, mnesia, start, [])),
+ ?match({timeout, [Tab]}, rpc:call(A, mnesia, wait_for_tables, [[Tab], 500])),
+ ?match(ok, rpc:call(C, mnesia, start, [])),
+ ?match({timeout, [Tab]}, rpc:call(A, mnesia, wait_for_tables, [[Tab], 500])),
+ ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 500])),
+ ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 500])),
+ ?match(yes, rpc:call(C, mnesia, force_load_table, [Tab])),
+
+ ?match(ok, rpc:call(A, mnesia, wait_for_tables, [[Tab], 3000])),
+ ?match(ok, rpc:call(B, mnesia, wait_for_tables, [[Tab], 3000])),
+ ?match(ok, rpc:call(C, mnesia, wait_for_tables, [[Tab], 3000])),
+ ?match([{Tab, 1, update}], rpc:call(A, mnesia, dirty_read, [{Tab, 1}])),
+ ?match([{Tab, 1, update}], rpc:call(B, mnesia, dirty_read, [{Tab, 1}])),
+ ?match([{Tab, 1, update}], rpc:call(C, mnesia, dirty_read, [{Tab, 1}])),
+
+ ?verify_mnesia(Nodes, []).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1415,7 +1518,7 @@ do_disc_durability(Config,CopyType) ->
[{Tab_bag, 22, a_2222}], [{Tab_bag, 33, a_3333}],
[{Tab_set, counter, 10}]]),
- timer:sleep(1000), %% Debugging strange msgs..
+ timer:sleep(500), %% Debugging strange msgs..
?log("Flushed ~p ~n", [mnesia_test_lib:flush()]),
?verify_mnesia(Nodes, []).
diff --git a/lib/mnesia/test/mnesia_evil_coverage_test.erl b/lib/mnesia/test/mnesia_evil_coverage_test.erl
index 074967469b..a451c8d0c8 100644
--- a/lib/mnesia/test/mnesia_evil_coverage_test.erl
+++ b/lib/mnesia/test/mnesia_evil_coverage_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -31,10 +31,11 @@
db_node_lifecycle/1, evil_delete_db_node/1, start_and_stop/1,
checkpoint/1, table_lifecycle/1, storage_options/1,
add_copy_conflict/1, add_copy_when_going_down/1,
+ add_copy_with_down/1,
replica_management/1, clear_table_during_load/1,
schema_availability/1, local_content/1,
replica_location/1, user_properties/1, unsupp_user_props/1,
- sorted_ets/1,
+ sorted_ets/1, index_cleanup/1,
change_table_access_mode/1, change_table_load_order/1,
set_master_nodes/1, offline_set_master_nodes/1,
dump_tables/1, dump_log/1, wait_for_tables/1, force_load_table/1,
@@ -48,7 +49,7 @@
record_name_dirty_access_disc_only/1,
record_name_dirty_access_xets/1]).
--export([info_check/8]).
+-export([info_check/8, index_size/1]).
-define(cleanup(N, Config),
mnesia_test_lib:prepare_test_case([{reload_appls, [mnesia]}],
@@ -65,13 +66,14 @@ all() ->
db_node_lifecycle, evil_delete_db_node, start_and_stop,
checkpoint, table_lifecycle, storage_options,
add_copy_conflict,
- add_copy_when_going_down, replica_management, clear_table_during_load,
+ add_copy_when_going_down, add_copy_with_down, replica_management,
+ clear_table_during_load,
schema_availability, local_content,
{group, table_access_modifications}, replica_location,
{group, table_sync}, user_properties, unsupp_user_props,
{group, record_name}, {group, snmp_access},
{group, subscriptions}, {group, iteration},
- {group, debug_support}, sorted_ets,
+ {group, debug_support}, sorted_ets, index_cleanup,
{mnesia_dirty_access_test, all},
{mnesia_trans_access_test, all},
{mnesia_evil_backup, all}].
@@ -732,6 +734,49 @@ add_copy_when_going_down(Config) ->
?match_receive({test,{aborted,_}}),
?verify_mnesia([Node2], []).
+add_copy_with_down(suite) -> [];
+add_copy_with_down(Config) ->
+ %% Allow add_table_copy() with ram_copies even all other replicas are down
+ Nodes = [Node1, Node2, Node3] = ?acquire_nodes(3, Config),
+ ?match({atomic, ok}, mnesia:create_table(a, [{ram_copies, [Node3]}, {disc_copies, [Node2]}])),
+ stopped = rpc:call(Node2, mnesia, stop, []),
+ stopped = rpc:call(Node3, mnesia, stop, []),
+ ?match({aborted, _}, mnesia:add_table_copy(a, Node1, ram_copies)),
+ ?match({aborted, _}, mnesia:del_table_copy(a, Node2)),
+ ok = rpc:call(Node3, mnesia, start, []),
+ ?match({aborted, _}, mnesia:add_table_copy(a, Node1, ram_copies)),
+ ?match([], mnesia_test_lib:start_mnesia([Node2], [a])),
+ ?match({atomic, ok}, mnesia:change_table_copy_type(a, Node2, ram_copies)),
+ stopped = rpc:call(Node2, mnesia, stop, []),
+ stopped = rpc:call(Node3, mnesia, stop, []),
+ ?match({atomic, ok}, mnesia:add_table_copy(a, Node1, ram_copies)),
+ ?match(ok, mnesia:dirty_write({a,1,1})),
+ ?match([], mnesia_test_lib:start_mnesia([Node2,Node3], [a])),
+ ?match([{a,1,1}], rpc:call(Node1, mnesia, dirty_read, [{a,1}])),
+ ?match([{a,1,1}], rpc:call(Node2, mnesia, dirty_read, [{a,1}])),
+ ?match([{a,1,1}], rpc:call(Node3, mnesia, dirty_read, [{a,1}])),
+
+ ?match({atomic, ok}, mnesia:del_table_copy(a, Node1)),
+ stopped = rpc:call(Node2, mnesia, stop, []),
+ stopped = rpc:call(Node3, mnesia, stop, []),
+ ?match({atomic, ok}, mnesia:add_table_copy(a, Node1, disc_copies)),
+ ?match(ok, mnesia:dirty_write({a,1,1})),
+ ?match([], mnesia_test_lib:start_mnesia([Node2,Node3], [a])),
+ ?match([{a,1,1}], rpc:call(Node1, mnesia, dirty_read, [{a,1}])),
+ ?match([{a,1,1}], rpc:call(Node2, mnesia, dirty_read, [{a,1}])),
+ ?match([{a,1,1}], rpc:call(Node3, mnesia, dirty_read, [{a,1}])),
+
+ ?match({atomic, ok}, mnesia:del_table_copy(a, Node1)),
+ stopped = rpc:call(Node2, mnesia, stop, []),
+ stopped = rpc:call(Node3, mnesia, stop, []),
+ ?match({atomic, ok}, mnesia:add_table_copy(a, Node1, disc_only_copies)),
+ ?match(ok, mnesia:dirty_write({a,1,1})),
+ ?match([], mnesia_test_lib:start_mnesia([Node2,Node3], [a])),
+ ?match([{a,1,1}], rpc:call(Node1, mnesia, dirty_read, [{a,1}])),
+ ?match([{a,1,1}], rpc:call(Node2, mnesia, dirty_read, [{a,1}])),
+ ?match([{a,1,1}], rpc:call(Node3, mnesia, dirty_read, [{a,1}])),
+
+ ?verify_mnesia(Nodes, []).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Add, drop and move replicas, change storage types
@@ -2514,3 +2559,55 @@ sorted_ets(Config) when is_list(Config) ->
?match({atomic, [{rec,1,1}, {rec,2,1}]}, mnesia:transaction(TestIt)).
+index_cleanup(Config) when is_list(Config) ->
+ [N1, N2] = All = ?acquire_nodes(2, Config),
+ ?match({atomic, ok}, mnesia:create_table(i_set, [{type, set}, {ram_copies, [N1]}, {index, [val]},
+ {disc_only_copies, [N2]}])),
+ ?match({atomic, ok}, mnesia:create_table(i_bag, [{type, bag}, {ram_copies, [N1]}, {index, [val]},
+ {disc_only_copies, [N2]}])),
+ ?match({atomic, ok}, mnesia:create_table(i_oset, [{type, ordered_set}, {ram_copies, [N1, N2]},
+ {index, [val]}])),
+
+ Tabs = [i_set, i_bag, i_oset],
+
+ Add = fun(Tab) ->
+ Write = fun(Tab) ->
+ Recs = [{Tab, N, N rem 5} || N <- lists:seq(1,10)],
+ [ok = mnesia:write(Rec) || Rec <- Recs],
+ Recs
+ end,
+ {atomic, Recs} = mnesia:sync_transaction(Write, [Tab]),
+ lists:sort(Recs)
+ end,
+
+ IRead = fun(Tab) ->
+ Read = fun(Tab) ->
+ [mnesia:index_read(Tab, N, val) || N <- lists:seq(0,4)]
+ end,
+ {atomic, Recs} = mnesia:transaction(Read, [Tab]),
+ lists:sort(lists:flatten(Recs))
+ end,
+
+ Delete = fun(Rec) ->
+ Del = fun() -> mnesia:delete_object(Rec) end,
+ {atomic, ok} = mnesia:sync_transaction(Del),
+ ok
+ end,
+
+
+ Recs = [Add(Tab) || Tab <- Tabs],
+ ?match(Recs, [IRead(Tab) || Tab <- Tabs]),
+ [Delete(Rec) || Rec <- lists:flatten(Recs)],
+
+ [?match({Tab,0}, {Tab,mnesia:table_info(Tab, size)}) || Tab <- Tabs],
+
+ [?match({Tab,Node,0, _}, rpc:call(Node, ?MODULE, index_size, [Tab]))
+ || Node <- All, Tab <- Tabs],
+ ?verify_mnesia(All, []).
+
+index_size(Tab) ->
+ %% White box testing
+ case mnesia:table_info(Tab, index_info) of
+ {index, _, [{_, {ram, Ref}}=Dbg]} -> {Tab, node(), ets:info(Ref, size), Dbg};
+ {index, _, [{_, {dets, Ref}}=Dbg]} -> {Tab, node(), dets:info(Ref, size), Dbg}
+ end.
diff --git a/lib/mnesia/test/mnesia_examples_test.erl b/lib/mnesia/test/mnesia_examples_test.erl
index f1259abf90..3bbb6e4d77 100644
--- a/lib/mnesia/test/mnesia_examples_test.erl
+++ b/lib/mnesia/test/mnesia_examples_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_frag_test.erl b/lib/mnesia/test/mnesia_frag_test.erl
index 7371792fda..7b37fcb684 100644
--- a/lib/mnesia/test/mnesia_frag_test.erl
+++ b/lib/mnesia/test/mnesia_frag_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_index_plugin_test.erl b/lib/mnesia/test/mnesia_index_plugin_test.erl
new file mode 100644
index 0000000000..44fe047c50
--- /dev/null
+++ b/lib/mnesia/test/mnesia_index_plugin_test.erl
@@ -0,0 +1,261 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+-module(mnesia_index_plugin_test).
+-author('[email protected]').
+
+-export([init_per_testcase/2, end_per_testcase/2,
+ init_per_group/2, end_per_group/2,
+ init_per_suite/1, end_per_suite/1,
+ all/0, groups/0]).
+
+-export([
+ add_rm_plugin/1,
+ tab_with_plugin_index/1,
+ tab_with_multiple_plugin_indexes/1,
+ ix_match_w_plugin/1,
+ ix_match_w_plugin_ordered/1,
+ ix_match_w_plugin_bag/1
+ ]).
+
+-export([ix_prefixes/3, % test plugin
+ ix_prefixes2/3]). % test plugin 2
+
+-include("mnesia_test_lib.hrl").
+
+init_per_suite(Conf) ->
+ Conf.
+
+end_per_suite(Conf) ->
+ Conf.
+
+init_per_testcase(Func, Conf) ->
+ mnesia_test_lib:init_per_testcase(Func, Conf).
+
+end_per_testcase(Func, Conf) ->
+ mnesia_test_lib:end_per_testcase(Func, Conf).
+
+all() ->
+ [add_rm_plugin,
+ tab_with_plugin_index,
+ tab_with_multiple_plugin_indexes,
+ ix_match_w_plugin,
+ ix_match_w_plugin_ordered,
+ ix_match_w_plugin_bag].
+
+groups() ->
+ [].
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+
+add_rm_plugin(suite) -> [];
+add_rm_plugin(Config) when is_list(Config) ->
+ [N1, N2] = Nodes = ?acquire_nodes(2, Config),
+ ok = add_plugin(),
+ ok = rpc_check_plugin(N1),
+ ok = rpc_check_plugin(N2),
+ ok = add_plugin2(),
+ ok = del_plugin(),
+ ok = del_plugin2(),
+ ok = add_plugin(),
+ ok = add_plugin2(),
+ ok = del_plugin(),
+ ok = del_plugin2(),
+ ?verify_mnesia(Nodes, []).
+
+-define(PLUGIN1, {{pfx},?MODULE,ix_prefixes}).
+-define(PLUGIN2, {{pfx2},?MODULE,ix_prefixes2}).
+
+add_plugin() ->
+ {atomic, ok} = mnesia_schema:add_index_plugin({pfx}, ?MODULE, ix_prefixes),
+ [?PLUGIN1] = mnesia_schema:index_plugins(),
+ ok.
+
+add_plugin2() ->
+ {atomic, ok} = mnesia_schema:add_index_plugin({pfx2}, ?MODULE, ix_prefixes2),
+ [?PLUGIN1, ?PLUGIN2] = lists:sort(mnesia_schema:index_plugins()),
+ ok.
+
+del_plugin() ->
+ {atomic, ok} = mnesia_schema:delete_index_plugin({pfx}),
+ [?PLUGIN2] = mnesia_schema:index_plugins(),
+ ok.
+
+del_plugin2() ->
+ {atomic, ok} = mnesia_schema:delete_index_plugin({pfx2}),
+ [] = mnesia_schema:index_plugins(),
+ ok.
+
+rpc_check_plugin(N) ->
+ [?PLUGIN1] =
+ rpc:call(N, mnesia_schema, index_plugins, []),
+ ok.
+
+tab_with_plugin_index(suite) -> [];
+tab_with_plugin_index(Config) when is_list(Config) ->
+ [_N1] = Nodes = ?acquire_nodes(1, Config),
+ ok = add_plugin(),
+ {atomic, ok} = mnesia:create_table(t, [{attributes, [k,v1,v2]},
+ {index, [{{pfx}, ordered},
+ {v1, ordered},
+ v2]}]),
+ [ok,ok,ok,ok] =
+ [mnesia:dirty_write({t, K, V1, V2})
+ || {K,V1,V2} <- [{1,a,"123"},
+ {2,b,"12345"},
+ {3,c,"6789"},
+ {4,d,nil}]],
+ [{t,1,a,"123"},{t,2,b,"12345"}] =
+ mnesia:dirty_index_read(t,<<"123">>,{pfx}),
+ [{t,3,c,"6789"}] =
+ mnesia:dirty_index_read(t,"6789",v2),
+ [{t,1,a,"123"}] =
+ mnesia:dirty_match_object({t,'_',a,"123"}),
+ [{t,1,a,"123"}] =
+ mnesia:dirty_select(t, [{ {t,'_',a,"123"}, [], ['$_']}]),
+ mnesia:dirty_delete(t,2),
+ [{t,1,a,"123"}] =
+ mnesia:dirty_index_read(t,<<"123">>,{pfx}),
+ ?verify_mnesia(Nodes, []).
+
+tab_with_multiple_plugin_indexes(suite) -> [];
+tab_with_multiple_plugin_indexes(Config) when is_list(Config) ->
+ [_N1] = Nodes = ?acquire_nodes(1, Config),
+ ok = add_plugin(),
+ ok = add_plugin2(),
+ {atomic, ok} =
+ mnesia:create_table(u, [{attributes, [k,v1,v2]},
+ {index, [{{pfx}, ordered},
+ {{pfx2}, ordered}]}]),
+ [ok,ok,ok,ok] =
+ [mnesia:dirty_write({u, K, V1, V2})
+ || {K,V1,V2} <- [{1,a,"123"},
+ {2,b,"12345"},
+ {3,c,"6789"},
+ {4,d,nil}]],
+ [{u,1,a,"123"},{u,2,b,"12345"}] =
+ mnesia:dirty_index_read(u,<<"123">>,{pfx}),
+ [{u,1,a,"123"},{u,2,b,"12345"}] =
+ mnesia:dirty_index_read(u,<<"321">>,{pfx2}),
+ ?verify_mnesia(Nodes, []).
+
+ix_match_w_plugin(suite) -> [];
+ix_match_w_plugin(Config) when is_list(Config) ->
+ [_N1] = Nodes = ?acquire_nodes(1, Config),
+ ok = add_plugin(),
+ {atomic, ok} = mnesia:create_table(im1, [{attributes, [k, v1, v2]},
+ {index, [{{pfx}, ordered},
+ {v1, ordered}]}]),
+ fill_and_test_index_match(im1, set),
+ ?verify_mnesia(Nodes, []).
+
+
+ix_match_w_plugin_ordered(suite) -> [];
+ix_match_w_plugin_ordered(Config) when is_list(Config) ->
+ [_N1] = Nodes = ?acquire_nodes(1, Config),
+ ok = add_plugin(),
+ {atomic, ok} = mnesia:create_table(im2, [{attributes, [k, v1, v2]},
+ {type, ordered_set},
+ {index, [{{pfx}, ordered},
+ {v1, ordered}]}]),
+ fill_and_test_index_match(im2, ordered_set),
+ ?verify_mnesia(Nodes, []).
+
+ix_match_w_plugin_bag(suite) -> [];
+ix_match_w_plugin_bag(Config) when is_list(Config) ->
+ [_N1] = Nodes = ?acquire_nodes(1, Config),
+ ok = add_plugin(),
+ {atomic, ok} = mnesia:create_table(im3, [{attributes, [k, v1, v2]},
+ {type, bag},
+ {index, [{{pfx}, ordered},
+ {v1, ordered}]}]),
+ fill_and_test_index_match(im3, bag),
+ ?verify_mnesia(Nodes, []).
+
+fill_and_test_index_match(Tab, Type) ->
+ [ok,ok,ok,ok,ok,ok,ok,ok,ok] =
+ [mnesia:dirty_write({Tab, K, V1, V2})
+ || {K,V1,V2} <- [{1,a,"123"},
+ {2,b,"12345"},
+ {3,c,"123"},
+ {4,d,nil},
+ {5,e,nil},
+ {6,f,nil},
+ {7,g,nil}, %% overwritten if not bag
+ {7,g,"234"},
+ {8,h,"123"}]],
+ mnesia:activity(
+ transaction,
+ fun() ->
+ ok = mnesia:write({Tab, 1, aa, "1234"}), %% replaces if not bag
+ ok = mnesia:delete({Tab, 2}),
+ ok = mnesia:delete({Tab, 4}),
+ ok = mnesia:write({Tab, 6, ff, nil}),
+ ok = mnesia:write({Tab, 7, gg, "123"}),
+ ok = mnesia:write({Tab, 100, x, nil}),
+ ok = mnesia:delete_object({Tab,3,c,"123"}),
+ ok = mnesia:delete_object({Tab,5,e,nil}),
+ Res = mnesia:index_read(Tab, <<"123">>, {pfx}),
+ SetRes = [{Tab,1,aa,"1234"}, {Tab,7,gg,"123"}, {Tab,8,h,"123"}],
+ case Type of
+ set ->
+ SetRes = lists:sort(Res);
+ ordered_set ->
+ SetRes = Res;
+ bag ->
+ [{Tab,1,a,"123"}, {Tab,1,aa,"1234"},
+ {Tab,7,gg,"123"}, {Tab,8,h,"123"}] = lists:sort(Res)
+ end
+ end).
+
+%% ============================================================
+%%
+ix_prefixes(_Tab, _Pos, Obj) ->
+ lists:foldl(
+ fun(V, Acc) when is_list(V) ->
+ try Pfxs = prefixes(list_to_binary(V)),
+ Pfxs ++ Acc
+ catch
+ error:_ ->
+ Acc
+ end;
+ (V, Acc) when is_binary(V) ->
+ Pfxs = prefixes(V),
+ Pfxs ++ Acc;
+ (_, Acc) ->
+ Acc
+ end, [], tl(tuple_to_list(Obj))).
+
+ix_prefixes2(Tab, Pos, Obj) ->
+ [rev(P) || P <- ix_prefixes(Tab, Pos, Obj)].
+
+rev(B) when is_binary(B) ->
+ list_to_binary(lists:reverse(binary_to_list(B))).
+
+prefixes(<<P:3/binary, _/binary>>) ->
+ [P];
+prefixes(_) ->
+ [].
diff --git a/lib/mnesia/test/mnesia_install_test.erl b/lib/mnesia/test/mnesia_install_test.erl
index 3f67396eb0..2aee5137c3 100644
--- a/lib/mnesia/test/mnesia_install_test.erl
+++ b/lib/mnesia/test/mnesia_install_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_isolation_test.erl b/lib/mnesia/test/mnesia_isolation_test.erl
index 1c3ea5ec92..49bcec14af 100644
--- a/lib/mnesia/test/mnesia_isolation_test.erl
+++ b/lib/mnesia/test/mnesia_isolation_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1563,7 +1563,8 @@ trans_update_visible_inside_trans(Config) when is_list(Config) ->
?match({atomic, ok}, mnesia:create_table([{name, Tab},
{ram_copies, [Node1]}])),
ValPos = 3,
- RecA = {Tab, a, 1},
+ RecA = {Tab, a, 1},
+ RecA2 = {Tab, a, 2},
PatA = {Tab, '$1', 1},
RecB = {Tab, b, 3},
PatB = {Tab, '$1', 3},
@@ -1598,6 +1599,14 @@ trans_update_visible_inside_trans(Config) when is_list(Config) ->
?match([], mnesia:index_read(Tab, 3, ValPos)),
%% delete_object
+ ?match(ok, mnesia:delete_object(RecA2)),
+ ?match([RecA], mnesia:read({Tab, a})),
+ ?match([RecA], mnesia:wread({Tab, a})),
+ ?match([RecA], mnesia:match_object(PatA)),
+ ?match([a], mnesia:all_keys(Tab)),
+ ?match([RecA], mnesia:index_match_object(PatA, ValPos)),
+ ?match([RecA], mnesia:index_read(Tab, 1, ValPos)),
+
?match(ok, mnesia:delete_object(RecA)),
?match([], mnesia:read({Tab, a})),
?match([], mnesia:wread({Tab, a})),
diff --git a/lib/mnesia/test/mnesia_majority_test.erl b/lib/mnesia/test/mnesia_majority_test.erl
index eb82617b60..aae27e069e 100644
--- a/lib/mnesia/test/mnesia_majority_test.erl
+++ b/lib/mnesia/test/mnesia_majority_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_measure_test.erl b/lib/mnesia/test/mnesia_measure_test.erl
index 4e63eaee22..8eb3590168 100644
--- a/lib/mnesia/test/mnesia_measure_test.erl
+++ b/lib/mnesia/test/mnesia_measure_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_nice_coverage_test.erl b/lib/mnesia/test/mnesia_nice_coverage_test.erl
index 7c96d6e6a0..f8c6b2ce20 100644
--- a/lib/mnesia/test/mnesia_nice_coverage_test.erl
+++ b/lib/mnesia/test/mnesia_nice_coverage_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_qlc_test.erl b/lib/mnesia/test/mnesia_qlc_test.erl
index 262a6b4abc..e66fd84995 100644
--- a/lib/mnesia/test/mnesia_qlc_test.erl
+++ b/lib/mnesia/test/mnesia_qlc_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_recovery_test.erl b/lib/mnesia/test/mnesia_recovery_test.erl
index 82d6e6ac6a..b5749408f8 100644
--- a/lib/mnesia/test/mnesia_recovery_test.erl
+++ b/lib/mnesia/test/mnesia_recovery_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -730,6 +730,7 @@ do_trans_loop2(Tab, Father) ->
do_trans_loop2(Tab, Father);
Else ->
?error("Transaction failed: ~p ~n", [Else]),
+ io:format("INFO: ~p~n",[erlang:process_info(self())]),
Father ! test_done,
exit(shutdown)
end.
diff --git a/lib/mnesia/test/mnesia_registry_test.erl b/lib/mnesia/test/mnesia_registry_test.erl
index 08157f1be3..c15b8e97af 100644
--- a/lib/mnesia/test/mnesia_registry_test.erl
+++ b/lib/mnesia/test/mnesia_registry_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_schema_recovery_test.erl b/lib/mnesia/test/mnesia_schema_recovery_test.erl
index 5e7627ca47..e4199758c1 100644
--- a/lib/mnesia/test/mnesia_schema_recovery_test.erl
+++ b/lib/mnesia/test/mnesia_schema_recovery_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_test_lib.erl b/lib/mnesia/test/mnesia_test_lib.erl
index 0fabdc7929..1cdac3cde6 100644
--- a/lib/mnesia/test/mnesia_test_lib.erl
+++ b/lib/mnesia/test/mnesia_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -470,9 +470,9 @@ get_suite(Mod, {group, Suite}) ->
{_, _, TCList} = lists:keyfind(Suite, 1, Groups),
TCList
catch
- _:Reason ->
+ _:Reason:Stacktrace ->
io:format("Not implemented ~p ~p (~p ~p)~n",
- [Mod,Suite,Reason, erlang:get_stacktrace()]),
+ [Mod,Suite,Reason,Stacktrace]),
'NYI'
end;
get_suite(Mod, all) ->
@@ -774,7 +774,7 @@ init_nodes([], _File, _Line) ->
%% Returns [Name, Host]
node_to_name_and_host(Node) ->
- string:tokens(atom_to_list(Node), [$@]).
+ string:lexemes(atom_to_list(Node), [$@]).
lookup_config(Key,Config) ->
case lists:keysearch(Key,1,Config) of
diff --git a/lib/mnesia/test/mnesia_test_lib.hrl b/lib/mnesia/test/mnesia_test_lib.hrl
index ba7eb10ea2..b8eeb5783f 100644
--- a/lib/mnesia/test/mnesia_test_lib.hrl
+++ b/lib/mnesia/test/mnesia_test_lib.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -55,25 +55,25 @@
?error("Not Matching Actual result was:~n ~p~n",[_AR_0]),
{fail,_AR_0}
catch
- exit:{aborted, _ER_1} when
+ exit:{aborted, _ER_1}:Stacktrace when
element(1, _ER_1) =:= node_not_running;
element(1, _ER_1) =:= bad_commit;
element(1, _ER_1) =:= cyclic ->
%% Need to re-raise these to restart transaction
- erlang:raise(exit, {aborted, _ER_1}, erlang:get_stacktrace());
- exit:_AR_1 ->
+ erlang:raise(exit, {aborted, _ER_1}, Stacktrace);
+ exit:_AR_1:Stacktrace ->
case fun(_AR_EXIT_) -> {'EXIT', _AR_EXIT_} end(_AR_1) of
_AR_2 = ExpectedRes ->
?verbose("ok, ~n Result as expected:~p~n",[_AR_2]),
{success,_AR_2};
_AR_2 ->
?error("Not Matching Actual result was:~n ~p~n ~p~n",
- [_AR_2, erlang:get_stacktrace()]),
+ [_AR_2, Stacktrace]),
{fail,_AR_2}
end;
- _T1_:_AR_1 ->
+ _T1_:_AR_1:Stacktrace ->
?error("Not Matching Actual result was:~n ~p~n ~p~n",
- [{_T1_,_AR_1}, erlang:get_stacktrace()]),
+ [{_T1_,_AR_1}, Stacktrace]),
{fail,{_T1_,_AR_1}}
end
end()).
diff --git a/lib/mnesia/test/mnesia_trans_access_test.erl b/lib/mnesia/test/mnesia_trans_access_test.erl
index c00a1ed51f..723a85fd2c 100644
--- a/lib/mnesia/test/mnesia_trans_access_test.erl
+++ b/lib/mnesia/test/mnesia_trans_access_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mt.erl b/lib/mnesia/test/mt.erl
index 5a981bf539..037d6adb38 100644
--- a/lib/mnesia/test/mt.erl
+++ b/lib/mnesia/test/mt.erl
@@ -67,6 +67,7 @@ alias(recovery) -> mnesia_recovery_test;
alias(registry) -> mnesia_registry_test;
alias(suite) -> mnesia_SUITE;
alias(trans) -> mnesia_trans_access_test;
+alias(ixp) -> mnesia_index_plugin_test;
alias(Other) -> Other.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/mnesia/vsn.mk b/lib/mnesia/vsn.mk
index 45f811846d..aa5d9adb6d 100644
--- a/lib/mnesia/vsn.mk
+++ b/lib/mnesia/vsn.mk
@@ -1 +1 @@
-MNESIA_VSN = 4.15.3
+MNESIA_VSN = 4.16
diff --git a/lib/observer/doc/src/Makefile b/lib/observer/doc/src/Makefile
index 11bfee1bdb..e843772f0b 100644
--- a/lib/observer/doc/src/Makefile
+++ b/lib/observer/doc/src/Makefile
@@ -105,6 +105,7 @@ html: gifs $(HTML_REF_MAN_FILE) $(ONLY_HTML_FILE:%=$(HTMLDIR)/%)
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN1DIR)/*
rm -f $(MAN3DIR)/*
rm -f $(MAN6DIR)/*
diff --git a/lib/observer/doc/src/crashdump.xml b/lib/observer/doc/src/crashdump.xml
index 48f944cbce..62c6ff1f25 100644
--- a/lib/observer/doc/src/crashdump.xml
+++ b/lib/observer/doc/src/crashdump.xml
@@ -34,7 +34,7 @@
<rev>PA1</rev>
<file>crashdump.xml</file>
</header>
- <module>crashdump_viewer</module>
+ <module since="">crashdump_viewer</module>
<modulesummary>A WxWidgets based tool for browsing Erlang
crashdumps.</modulesummary>
<description>
@@ -46,8 +46,8 @@
</description>
<funcs>
<func>
- <name>start() -> ok</name>
- <name>start(File) -> ok</name>
+ <name since="">start() -> ok</name>
+ <name since="OTP 17.0">start(File) -> ok</name>
<fsummary>Start the Crashdump Viewer.</fsummary>
<type>
<v>File = string()</v>
@@ -62,7 +62,7 @@
</desc>
</func>
<func>
- <name>stop() -> ok</name>
+ <name since="">stop() -> ok</name>
<fsummary>Terminate the Crashdump Viewer.</fsummary>
<desc>
<p>Terminates the Crashdump Viewer and closes
diff --git a/lib/observer/doc/src/etop.xml b/lib/observer/doc/src/etop.xml
index e7a83d0514..f0acc7b5d8 100644
--- a/lib/observer/doc/src/etop.xml
+++ b/lib/observer/doc/src/etop.xml
@@ -34,7 +34,7 @@
<rev></rev>
<file></file>
</header>
- <module>etop</module>
+ <module since="">etop</module>
<modulesummary>Erlang Top is a tool for presenting information about Erlang
processes similar to the information presented by "top" in UNIX.</modulesummary>
<description>
@@ -98,7 +98,7 @@
</description>
<funcs>
<func>
- <name>start() -> ok</name>
+ <name since="OTP R15B01">start() -> ok</name>
<fsummary>Start etop.</fsummary>
<desc>
<p>Starts <c>etop</c>.
@@ -106,7 +106,7 @@
</desc>
</func>
<func>
- <name>start(Options) -> ok</name>
+ <name since="OTP R15B01">start(Options) -> ok</name>
<fsummary>Start etop.</fsummary>
<type>
<v>Options = [Option]</v>
@@ -120,7 +120,7 @@
</desc>
</func>
<func>
- <name>help() -> ok</name>
+ <name since="OTP R15B01">help() -> ok</name>
<fsummary>Display the etop help.</fsummary>
<desc>
<p>Displays the help of <c>etop</c> and
@@ -128,7 +128,7 @@
</desc>
</func>
<func>
- <name>config(Key,Value) -> Result</name>
+ <name since="">config(Key,Value) -> Result</name>
<fsummary>Change the configuration of the tool.</fsummary>
<type>
<v>Result = ok | {error,Reason}</v>
@@ -142,7 +142,7 @@
</desc>
</func>
<func>
- <name>dump(File) -> Result</name>
+ <name since="">dump(File) -> Result</name>
<fsummary>Dump the current display to a file.</fsummary>
<type>
<v>Result = ok | {error,Reason}</v>
@@ -153,7 +153,7 @@
</desc>
</func>
<func>
- <name>stop() -> stop</name>
+ <name since="">stop() -> stop</name>
<fsummary>Terminate etop.</fsummary>
<desc>
<p>Terminates <c>etop</c>.</p>
diff --git a/lib/observer/doc/src/notes.xml b/lib/observer/doc/src/notes.xml
index c0b8309af6..f05e58dc21 100644
--- a/lib/observer/doc/src/notes.xml
+++ b/lib/observer/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,6 +32,143 @@
<p>This document describes the changes made to the Observer
application.</p>
+<section><title>Observer 2.9.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ All incorrect (that is, all) uses of "can not" has been
+ corrected to "cannot" in source code comments,
+ documentation, examples, and so on.</p>
+ <p>
+ Own Id: OTP-14282 Aux Id: PR-1891 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Observer 2.9</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Since Logger was introduced in OTP-21.0, menu choice
+ <em>Log &gt; Toggle Log View</em> in observer would cause
+ a crash unless an <c>error_logger</c> event handler was
+ explicitly installed. This is now corrected.</p>
+ <p>
+ Own Id: OTP-15553 Aux Id: ERL-848 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Since persistent_term was introduced, observer would
+ sometimes crash when expanding a term from a process
+ state. This is now corrected.</p>
+ <p>
+ Own Id: OTP-15493 Aux Id: ERL-810 </p>
+ </item>
+ <item>
+ <p>
+ Add <c>OBSERVER_SCALE</c> environment variable for HiDPI
+ support.</p>
+ <p>
+ Own Id: OTP-15586 Aux Id: PR-2105 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Observer 2.8.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Literals such as <c>#{"one"=>1}</c> dumped to a crash
+ dump would cause <c>crashdump_viewer</c> to crash.</p>
+ <p>
+ Own Id: OTP-15365 Aux Id: ERL-722 </p>
+ </item>
+ <item>
+ <p>
+ <c>crashdump_viewer</c> would sometimes crash when
+ processing a dump which was truncated in the
+ <c>literals</c> area. This is now corrected.</p>
+ <p>
+ Own Id: OTP-15377</p>
+ </item>
+ <item>
+ <p>
+ Since OTP-20.2, <c>crashdump_viewer</c> was very slow
+ when opening a crash dump with many processes. An
+ ets:select per process could be removed, which improved
+ the performance a lot.</p>
+ <p>
+ A bug when parsing heap data in a crashdump caused
+ <c>crashdump_viewer</c> to crash when multiple <c>Yc</c>
+ lines referenced the same reference counted binary. This
+ is now corrected.</p>
+ <p>
+ Own Id: OTP-15391</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Observer 2.8.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Observer 2.8</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Added possibility to garbage collect selected processes
+ and fixed a crash when the saved config file contained
+ bad data.</p>
+ <p>
+ Own Id: OTP-14993 Aux Id: PR-1666 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Use uri_string module instead of http_uri.</p>
+ <p>
+ Own Id: OTP-14902</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Observer 2.7</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/observer/doc/src/observer.xml b/lib/observer/doc/src/observer.xml
index 843be26ee1..7fb1dd044e 100644
--- a/lib/observer/doc/src/observer.xml
+++ b/lib/observer/doc/src/observer.xml
@@ -33,7 +33,7 @@
<rev>PA1</rev>
<file>observer.xml</file>
</header>
- <module>observer</module>
+ <module since="OTP R15B">observer</module>
<modulesummary>A GUI tool for observing an Erlang system.</modulesummary>
<description>
<p>Observer is a graphical tool for observing the characteristics of
@@ -48,7 +48,7 @@
</description>
<funcs>
<func>
- <name>start() -> ok</name>
+ <name since="OTP R15B">start() -> ok</name>
<fsummary>Start the Observer GUI.</fsummary>
<desc>
<p>Starts the Observer GUI.
diff --git a/lib/observer/doc/src/ttb.xml b/lib/observer/doc/src/ttb.xml
index 7cd15e15d3..fee95e0b21 100644
--- a/lib/observer/doc/src/ttb.xml
+++ b/lib/observer/doc/src/ttb.xml
@@ -33,7 +33,7 @@
<rev>PA1</rev>
<file>ttb.xml</file>
</header>
- <module>ttb</module>
+ <module since="">ttb</module>
<modulesummary>A base for building trace tools for distributed systems.</modulesummary>
<description>
<p>The Trace Tool Builder, <c>ttb</c>, is a base for building trace
@@ -44,7 +44,7 @@
</description>
<funcs>
<func>
- <name>start_trace(Nodes, Patterns, FlagSpec, Opts) -> Result</name>
+ <name since="OTP R15B">start_trace(Nodes, Patterns, FlagSpec, Opts) -> Result</name>
<fsummary>Start a trace port on each specified node.</fsummary>
<type>
<v>Result = see p/2</v>
@@ -76,7 +76,7 @@ ttb:p(all, call).</input></pre>
</func>
<func>
- <name>tracer() -> Result</name>
+ <name since="">tracer() -> Result</name>
<fsummary>Equivalent to tracer(node()).</fsummary>
<desc>
<p>Equivalent to <c>tracer(node())</c>.</p>
@@ -84,7 +84,7 @@ ttb:p(all, call).</input></pre>
</func>
<func>
- <name>tracer(Shortcut) -> Result</name>
+ <name since="">tracer(Shortcut) -> Result</name>
<fsummary>Handy shortcuts for common tracing settings.</fsummary>
<type>
<v>Shortcut = shell | dbg</v>
@@ -97,7 +97,7 @@ ttb:p(all, call).</input></pre>
</func>
<func>
- <name>tracer(Nodes) -> Result</name>
+ <name since="">tracer(Nodes) -> Result</name>
<fsummary>Equivalent to tracer(Nodes,[]).</fsummary>
<desc>
<p>Equivalent to <c>tracer(Nodes,[])</c>.</p>
@@ -105,7 +105,7 @@ ttb:p(all, call).</input></pre>
</func>
<func>
- <name>tracer(Nodes,Opts) -> Result</name>
+ <name since="">tracer(Nodes,Opts) -> Result</name>
<fsummary>Start a trace port on each specified node.</fsummary>
<type>
<v>Result = {ok, ActivatedNodes} | {error,Reason}</v>
@@ -243,7 +243,7 @@ ttb:p(all, call).</input></pre>
</func>
<func>
- <name>p(Item,Flags) -> Return</name>
+ <name since="">p(Item,Flags) -> Return</name>
<fsummary>Set the specified trace flags on the specified processes or ports.</fsummary>
<type>
<v>Return = {ok,[{Item,MatchDesc}]}</v>
@@ -277,7 +277,8 @@ ttb:p(all, call).</input></pre>
</func>
<func>
- <name>tp, tpl, tpe, ctp, ctpl, ctpg, ctpe</name>
+ <name since="">tp, tpl, ctp, ctpl, ctpg</name>
+ <name since="OTP 19.0">tpe, ctpe</name>
<fsummary>Set and clear trace patterns.</fsummary>
<desc>
<p>These functions are to be used with trace
@@ -338,7 +339,7 @@ ttb:p(all, call).</input></pre>
</func>
<func>
- <name>list_history() -> History</name>
+ <name since="">list_history() -> History</name>
<fsummary>Return all calls stored in history.</fsummary>
<type>
<v>History = [{N,Func,Args}]</v>
@@ -352,7 +353,7 @@ ttb:p(all, call).</input></pre>
</func>
<func>
- <name>run_history(N) -> ok | {error, Reason}</name>
+ <name since="">run_history(N) -> ok | {error, Reason}</name>
<fsummary>Execute one entry of the history.</fsummary>
<type>
<v>N = integer() | [integer()]</v>
@@ -364,7 +365,7 @@ ttb:p(all, call).</input></pre>
</func>
<func>
- <name>write_config(ConfigFile,Config)</name>
+ <name since="">write_config(ConfigFile,Config)</name>
<fsummary>Equivalent to write_config(ConfigFile,Config,[]).</fsummary>
<desc>
<p>Equivalent to <c>write_config(ConfigFile,Config,[])</c>.</p>
@@ -372,7 +373,7 @@ ttb:p(all, call).</input></pre>
</func>
<func>
- <name>write_config(ConfigFile,Config,Opts) -> ok | {error,Reason}</name>
+ <name since="">write_config(ConfigFile,Config,Opts) -> ok | {error,Reason}</name>
<fsummary>Create a configuration file.</fsummary>
<type>
<v>ConfigFile = string()</v>
@@ -405,7 +406,7 @@ ttb:p(all, call).</input></pre>
</func>
<func>
- <name>run_config(ConfigFile) -> ok | {error,Reason}</name>
+ <name since="">run_config(ConfigFile) -> ok | {error,Reason}</name>
<fsummary>Execute all entries in a configuration file.</fsummary>
<type>
<v>ConfigFile = string()</v>
@@ -418,7 +419,7 @@ ttb:p(all, call).</input></pre>
</func>
<func>
- <name>run_config(ConfigFile,NumList) -> ok | {error,Reason}</name>
+ <name since="">run_config(ConfigFile,NumList) -> ok | {error,Reason}</name>
<fsummary>Execute selected entries from a configuration file.</fsummary>
<type>
<v>ConfigFile = string()</v>
@@ -437,7 +438,7 @@ ttb:p(all, call).</input></pre>
</func>
<func>
- <name>list_config(ConfigFile) -> Config | {error,Reason}</name>
+ <name since="">list_config(ConfigFile) -> Config | {error,Reason}</name>
<fsummary>List all entries in a configuration file.</fsummary>
<type>
<v>ConfigFile = string()</v>
@@ -449,7 +450,7 @@ ttb:p(all, call).</input></pre>
</func>
<func>
- <name>write_trace_info(Key,Info) -> ok</name>
+ <name since="">write_trace_info(Key,Info) -> ok</name>
<fsummary>Write any information to file <c>.ti</c>.</fsummary>
<type>
<v>Key = term()</v>
@@ -465,7 +466,7 @@ ttb:p(all, call).</input></pre>
</func>
<func>
- <name>seq_trigger_ms() -> MatchSpec</name>
+ <name since="">seq_trigger_ms() -> MatchSpec</name>
<fsummary>Equivalent to seq_trigger_ms(all).</fsummary>
<desc>
<p>Equivalent to <c>seq_trigger_ms(all)</c>.</p>
@@ -473,7 +474,7 @@ ttb:p(all, call).</input></pre>
</func>
<func>
- <name>seq_trigger_ms(Flags) -> MatchSpec</name>
+ <name since="">seq_trigger_ms(Flags) -> MatchSpec</name>
<fsummary>Return a match_spec() which starts sequential tracing.</fsummary>
<type>
<v>MatchSpec = match_spec()</v>
@@ -521,7 +522,7 @@ ttb:p(all, call).</input></pre>
</func>
<func>
- <name>stop()</name>
+ <name since="">stop()</name>
<fsummary>Equivalent to stop([]).</fsummary>
<desc>
<p>Equivalent to <c>stop([])</c>.</p>
@@ -529,7 +530,7 @@ ttb:p(all, call).</input></pre>
</func>
<func>
- <name>stop(Opts) -> stopped | {stopped, Dir}</name>
+ <name since="">stop(Opts) -> stopped | {stopped, Dir}</name>
<fsummary>Stop tracing and fetch/format logs from all nodes.</fsummary>
<type>
<v>Opts = Opt | [Opt]</v>
@@ -573,7 +574,7 @@ ttb:p(all, call).</input></pre>
</func>
<func>
- <name>get_et_handler()</name>
+ <name since="OTP R15B">get_et_handler()</name>
<fsummary>Return the <c>et</c> handler.</fsummary>
<desc>
<p>Returns the <c>et</c> handler, which can be used with <c>format/2</c>
@@ -583,7 +584,7 @@ ttb:p(all, call).</input></pre>
</func>
<func>
- <name>format(File)</name>
+ <name since="">format(File)</name>
<fsummary>Equivalent to <c>format(File,[])</c>.</fsummary>
<desc>
<p>Equivalent to <c>format(File,[])</c>.</p>
@@ -591,7 +592,7 @@ ttb:p(all, call).</input></pre>
</func>
<func>
- <name>format(File,Options) -> ok | {error, Reason}</name>
+ <name since="">format(File,Options) -> ok | {error, Reason}</name>
<fsummary>Format a binary trace log.</fsummary>
<type>
<v>File = string() | [string()]</v>
diff --git a/lib/observer/include/etop.hrl b/lib/observer/include/etop.hrl
index f8d370450b..cda68422ab 100644
--- a/lib/observer/include/etop.hrl
+++ b/lib/observer/include/etop.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/Makefile b/lib/observer/src/Makefile
index ff2bcbdb99..f9f239db37 100644
--- a/lib/observer/src/Makefile
+++ b/lib/observer/src/Makefile
@@ -50,6 +50,7 @@ MODULES= \
cdv_mem_cb \
cdv_mod_cb \
cdv_multi_wx \
+ cdv_persistent_cb \
cdv_port_cb \
cdv_proc_cb \
cdv_sched_cb \
diff --git a/lib/observer/src/cdv_atom_cb.erl b/lib/observer/src/cdv_atom_cb.erl
index 86cdf2fd6d..87f613124c 100644
--- a/lib/observer/src/cdv_atom_cb.erl
+++ b/lib/observer/src/cdv_atom_cb.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/cdv_bin_cb.erl b/lib/observer/src/cdv_bin_cb.erl
index a4a542297c..91d33474c8 100644
--- a/lib/observer/src/cdv_bin_cb.erl
+++ b/lib/observer/src/cdv_bin_cb.erl
@@ -49,7 +49,7 @@ format_bin_fun(Format,Bin) ->
try io_lib:format(Format,[Bin]) of
Str -> plain_html(lists:flatten(Str))
catch error:badarg ->
- Warning = "This binary can not be formatted with " ++ Format,
+ Warning = "This binary cannot be formatted with " ++ Format,
observer_html_lib:warning(Warning)
end
end.
@@ -59,7 +59,7 @@ binary_to_term_fun(Bin) ->
try binary_to_term(Bin) of
Term -> plain_html(io_lib:format("~tp",[Term]))
catch error:badarg ->
- Warning = "This binary can not be converted to an Erlang term",
+ Warning = "This binary cannot be converted to an Erlang term",
observer_html_lib:warning(Warning)
end
end.
diff --git a/lib/observer/src/cdv_detail_wx.erl b/lib/observer/src/cdv_detail_wx.erl
index 6c4739042b..5e1137511a 100644
--- a/lib/observer/src/cdv_detail_wx.erl
+++ b/lib/observer/src/cdv_detail_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -84,8 +84,9 @@ destroy_progress(_) ->
ok.
init(Id,ParentFrame,Callback,App,Parent,{Title,Info,TW}) ->
+ Scale = observer_wx:get_scale(),
Frame=wxFrame:new(ParentFrame, ?wxID_ANY, [Title],
- [{style, ?wxDEFAULT_FRAME_STYLE}, {size, {850,600}}]),
+ [{style, ?wxDEFAULT_FRAME_STYLE}, {size, {Scale*850,Scale*600}}]),
MenuBar = wxMenuBar:new(),
create_menus(MenuBar),
wxFrame:setMenuBar(Frame, MenuBar),
diff --git a/lib/observer/src/cdv_dist_cb.erl b/lib/observer/src/cdv_dist_cb.erl
index 2b4c9f56d1..ad1eb6e73c 100644
--- a/lib/observer/src/cdv_dist_cb.erl
+++ b/lib/observer/src/cdv_dist_cb.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -78,7 +78,7 @@ init_gen_page(Parent, Info) ->
cdv_info_wx:start_link(Parent,{Fields,Info,[]}).
format({creations,Creations}) ->
- string:join([integer_to_list(C) || C <- Creations],",");
+ lists:flatten(lists:join(",",[integer_to_list(C) || C <- Creations]));
format(D) ->
D.
diff --git a/lib/observer/src/cdv_html_wx.erl b/lib/observer/src/cdv_html_wx.erl
index 4b43b6a840..8956173c93 100644
--- a/lib/observer/src/cdv_html_wx.erl
+++ b/lib/observer/src/cdv_html_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -33,13 +33,17 @@
{panel,
app, %% which tool is the user
expand_table,
- expand_wins=[]}).
+ expand_wins=[],
+ delayed_fetch,
+ trunc_warn=[]}).
start_link(ParentWin, Info) ->
wx_object:start_link(?MODULE, [ParentWin, Info], []).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+init([ParentWin, Callback]) when is_atom(Callback) ->
+ init(ParentWin, Callback);
init([ParentWin, {App, Fun}]) when is_function(Fun) ->
init([ParentWin, {App, Fun()}]);
init([ParentWin, {expand,HtmlText,Tab}]) ->
@@ -60,9 +64,29 @@ init(ParentWin, HtmlText, Tab, App) ->
wx_misc:endBusyCursor(),
{HtmlWin, #state{panel=HtmlWin,expand_table=Tab,app=App}}.
+init(ParentWin, Callback) ->
+ {HtmlWin, State} = init(ParentWin, "", undefined, cdv),
+ {HtmlWin, State#state{delayed_fetch=Callback}}.
+
%%%%%%%%%%%%%%%%%%%%%%% Callbacks %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+handle_info(active, #state{panel=HtmlWin,delayed_fetch=Callback}=State)
+ when Callback=/=undefined ->
+ observer_lib:display_progress_dialog(HtmlWin,
+ "Crashdump Viewer",
+ "Reading data"),
+ {{expand,HtmlText,Tab},TW} = Callback:get_info(),
+ observer_lib:sync_destroy_progress_dialog(),
+ wx_misc:beginBusyCursor(),
+ wxHtmlWindow:setPage(HtmlWin,HtmlText),
+ cdv_wx_set_status(State, TW),
+ wx_misc:endBusyCursor(),
+ {noreply, State#state{expand_table=Tab,
+ delayed_fetch=undefined,
+ trunc_warn=TW}};
+
handle_info(active, State) ->
+ cdv_wx_set_status(State, State#state.trunc_warn),
{noreply, State};
handle_info(Info, State) ->
@@ -94,21 +118,21 @@ handle_event(#wx{event=#wxHtmlLink{type=command_html_link_clicked,
case Target of
"#Binary?" ++ BinSpec ->
[{"offset",Off},{"size",Size},{"pos",Pos}] =
- httpd:parse_query(BinSpec),
+ uri_string:dissect_query(BinSpec),
Id = {cdv, {list_to_integer(Off),
list_to_integer(Size),
list_to_integer(Pos)}},
expand(Id,cdv_bin_cb,State);
"#OBSBinary?" ++ BinSpec ->
[{"key1",Preview},{"key2",Size},{"key3",Hash}] =
- httpd:parse_query(BinSpec),
+ uri_string:dissect_query(BinSpec),
Id = {obs, {Tab, {list_to_integer(Preview),
list_to_integer(Size),
list_to_integer(Hash)}}},
expand(Id,cdv_bin_cb,State);
"#Term?" ++ TermKeys ->
[{"key1",Key1},{"key2",Key2},{"key3",Key3}] =
- httpd:parse_query(TermKeys),
+ uri_string:dissect_query(TermKeys),
Id = {cdv, {Tab,{list_to_integer(Key1),
list_to_integer(Key2),
list_to_integer(Key3)}}},
@@ -140,3 +164,10 @@ expand(Id,Callback,#state{expand_wins=Opened0, app=App}=State) ->
Opened0
end,
State#state{expand_wins=Opened}.
+
+cdv_wx_set_status(#state{app = cdv}, Status) ->
+ %% this module is used by the observer when cdw_wx isn't started
+ %% only try to set status when used by cdv
+ cdv_wx:set_status(Status);
+cdv_wx_set_status(_, _) ->
+ ok.
diff --git a/lib/observer/src/cdv_info_wx.erl b/lib/observer/src/cdv_info_wx.erl
index 07c28610e2..0a23d4ae3f 100644
--- a/lib/observer/src/cdv_info_wx.erl
+++ b/lib/observer/src/cdv_info_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/cdv_mem_cb.erl b/lib/observer/src/cdv_mem_cb.erl
index abeddc7335..99ffdda765 100644
--- a/lib/observer/src/cdv_mem_cb.erl
+++ b/lib/observer/src/cdv_mem_cb.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -49,9 +49,7 @@ gen_mem_info_fields([]) ->
[].
upper(Key) ->
- string:join([string:to_upper([H]) ++ T ||
- [H|T] <- string:tokens(Key,"_")]," ").
-
+ lists:join(" ", [string:titlecase(Word) || Word <- string:split(Key, "_", all)]).
%%%-----------------------------------------------------------------
%%% Allocated areas page
diff --git a/lib/observer/src/cdv_multi_wx.erl b/lib/observer/src/cdv_multi_wx.erl
index 93f045b1da..79a44245aa 100644
--- a/lib/observer/src/cdv_multi_wx.erl
+++ b/lib/observer/src/cdv_multi_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/cdv_persistent_cb.erl b/lib/observer/src/cdv_persistent_cb.erl
new file mode 100644
index 0000000000..d5da18f7fc
--- /dev/null
+++ b/lib/observer/src/cdv_persistent_cb.erl
@@ -0,0 +1,32 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+
+-module(cdv_persistent_cb).
+
+-export([get_info/0]).
+
+-include_lib("wx/include/wx.hrl").
+
+get_info() ->
+ Tab = ets:new(pt_expand,[set,public]),
+ {ok,PT,TW} = crashdump_viewer:persistent_terms(),
+ {{expand,
+ observer_html_lib:expandable_term("Persistent Terms",PT,Tab),
+ Tab},
+ TW}.
diff --git a/lib/observer/src/cdv_port_cb.erl b/lib/observer/src/cdv_port_cb.erl
index 6bb8f07a74..cbd5f696a6 100644
--- a/lib/observer/src/cdv_port_cb.erl
+++ b/lib/observer/src/cdv_port_cb.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/cdv_proc_cb.erl b/lib/observer/src/cdv_proc_cb.erl
index 0ea23dd7cb..2497b4889e 100644
--- a/lib/observer/src/cdv_proc_cb.erl
+++ b/lib/observer/src/cdv_proc_cb.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/cdv_sched_cb.erl b/lib/observer/src/cdv_sched_cb.erl
index d2696a276f..a3695a9418 100644
--- a/lib/observer/src/cdv_sched_cb.erl
+++ b/lib/observer/src/cdv_sched_cb.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/cdv_table_wx.erl b/lib/observer/src/cdv_table_wx.erl
index ba23758ea6..0cad272262 100644
--- a/lib/observer/src/cdv_table_wx.erl
+++ b/lib/observer/src/cdv_table_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -50,11 +50,12 @@ init([ParentWin, {ColumnSpec,Info,TW}]) ->
end,
Grid = wxListCtrl:new(ParentWin, [{style, Style}]),
Li = wxListItem:new(),
+ Scale = observer_wx:get_scale(),
AddListEntry = fun({Name, Align, DefSize}, Col) ->
wxListItem:setText(Li, Name),
wxListItem:setAlign(Li, Align),
wxListCtrl:insertColumn(Grid, Col, Li),
- wxListCtrl:setColumnWidth(Grid, Col, DefSize),
+ wxListCtrl:setColumnWidth(Grid, Col, DefSize*Scale),
Col + 1
end,
lists:foldl(AddListEntry, 0, ColumnSpec),
diff --git a/lib/observer/src/cdv_term_cb.erl b/lib/observer/src/cdv_term_cb.erl
index bdcb13f22d..85da1d227a 100644
--- a/lib/observer/src/cdv_term_cb.erl
+++ b/lib/observer/src/cdv_term_cb.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -51,7 +51,7 @@ format_term_fun(Format,Term,Tab) ->
try io_lib:format(Format,[Term]) of
Str -> {expand, plain_html(Str), Tab}
catch error:badarg ->
- Warning = "This term can not be formatted with " ++ Format,
+ Warning = "This term cannot be formatted with " ++ Format,
observer_html_lib:warning(Warning)
after
observer_lib:report_progress({ok,stop_pulse})
diff --git a/lib/observer/src/cdv_virtual_list_wx.erl b/lib/observer/src/cdv_virtual_list_wx.erl
index 33c0c880b1..14877b7eab 100644
--- a/lib/observer/src/cdv_virtual_list_wx.erl
+++ b/lib/observer/src/cdv_virtual_list_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -132,11 +132,12 @@ create_list_box(Panel, Holder, Callback, Owner) ->
end}
]),
Li = wxListItem:new(),
+ Scale = observer_wx:get_scale(),
AddListEntry = fun({Name, Align, DefSize}, Col) ->
wxListItem:setText(Li, Name),
wxListItem:setAlign(Li, Align),
wxListCtrl:insertColumn(ListCtrl, Col, Li),
- wxListCtrl:setColumnWidth(ListCtrl, Col, DefSize),
+ wxListCtrl:setColumnWidth(ListCtrl, Col, DefSize*Scale),
Col + 1
end,
ListItems = Callback:col_spec(),
diff --git a/lib/observer/src/cdv_wx.erl b/lib/observer/src/cdv_wx.erl
index c3f36cd689..7100cc8790 100644
--- a/lib/observer/src/cdv_wx.erl
+++ b/lib/observer/src/cdv_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -51,6 +51,7 @@
-define(DIST_STR, "Nodes").
-define(MOD_STR, "Modules").
-define(MEM_STR, "Memory").
+-define(PERSISTENT_STR, "Persistent Terms").
-define(INT_STR, "Internal Tables").
%% Records
@@ -74,6 +75,7 @@
dist_panel,
mod_panel,
mem_panel,
+ persistent_panel,
int_panel,
active_tab
}).
@@ -99,8 +101,9 @@ init(File0) ->
{ok,CdvServer} = crashdump_viewer:start_link(),
catch wxSystemOptions:setOption("mac.listctrl.always_use_generic", 1),
+ Scale = observer_wx:get_scale(),
Frame = wxFrame:new(wx:null(), ?wxID_ANY, "Crashdump Viewer",
- [{size, {850, 600}}, {style, ?wxDEFAULT_FRAME_STYLE}]),
+ [{size, {Scale*850, Scale*600}}, {style, ?wxDEFAULT_FRAME_STYLE}]),
IconFile = filename:join(code:priv_dir(observer), "erlang_observer.png"),
Icon = wxIcon:new(IconFile, [{type,?wxBITMAP_TYPE_PNG}]),
wxFrame:setIcon(Frame, Icon),
@@ -130,8 +133,9 @@ init(File0) ->
{ok,File} ->
%% Set window title
T1 = "Crashdump Viewer: ",
+ FileLength = string:length(File),
Title =
- if length(File) > 70 ->
+ if FileLength > 70 ->
T1 ++ filename:basename(File);
true ->
T1 ++ File
@@ -192,6 +196,10 @@ setup(#state{frame=Frame, notebook=Notebook}=State) ->
%% Memory Panel
MemPanel = add_page(Notebook, ?MEM_STR, cdv_multi_wx, cdv_mem_cb),
+ %% Persistent Terms Panel
+ PersistentPanel = add_page(Notebook, ?PERSISTENT_STR,
+ cdv_html_wx, cdv_persistent_cb),
+
%% Memory Panel
IntPanel = add_page(Notebook, ?INT_STR, cdv_multi_wx, cdv_int_tab_cb),
@@ -214,6 +222,7 @@ setup(#state{frame=Frame, notebook=Notebook}=State) ->
dist_panel = DistPanel,
mod_panel = ModPanel,
mem_panel = MemPanel,
+ persistent_panel = PersistentPanel,
int_panel = IntPanel,
active_tab = GenPid
}}.
@@ -249,6 +258,7 @@ handle_event(#wx{id = ?wxID_OPEN,
State#state.dist_panel,
State#state.mod_panel,
State#state.mem_panel,
+ State#state.persistent_panel,
State#state.int_panel],
_ = [wx_object:call(Panel,new_dump) || Panel<-Panels],
wxNotebook:setSelection(State#state.notebook,0),
@@ -342,8 +352,8 @@ check_page_title(Notebook) ->
get_active_pid(#state{notebook=Notebook, gen_panel=Gen, pro_panel=Pro,
port_panel=Ports, ets_panel=Ets, timer_panel=Timers,
fun_panel=Funs, atom_panel=Atoms, dist_panel=Dist,
- mod_panel=Mods, mem_panel=Mem, int_panel=Int,
- sched_panel=Sched
+ mod_panel=Mods, mem_panel=Mem, persistent_panel=Persistent,
+ int_panel=Int, sched_panel=Sched
}) ->
Panel = case check_page_title(Notebook) of
?GEN_STR -> Gen;
@@ -357,6 +367,7 @@ get_active_pid(#state{notebook=Notebook, gen_panel=Gen, pro_panel=Pro,
?DIST_STR -> Dist;
?MOD_STR -> Mods;
?MEM_STR -> Mem;
+ ?PERSISTENT_STR -> Persistent;
?INT_STR -> Int
end,
wx_object:get_pid(Panel).
@@ -364,7 +375,7 @@ get_active_pid(#state{notebook=Notebook, gen_panel=Gen, pro_panel=Pro,
pid2panel(Pid, #state{gen_panel=Gen, pro_panel=Pro, port_panel=Ports,
ets_panel=Ets, timer_panel=Timers, fun_panel=Funs,
atom_panel=Atoms, dist_panel=Dist, mod_panel=Mods,
- mem_panel=Mem, int_panel=Int}) ->
+ mem_panel=Mem, persistent_panel=Persistent, int_panel=Int}) ->
case Pid of
Gen -> ?GEN_STR;
Pro -> ?PRO_STR;
@@ -376,6 +387,7 @@ pid2panel(Pid, #state{gen_panel=Gen, pro_panel=Pro, port_panel=Ports,
Dist -> ?DIST_STR;
Mods -> ?MOD_STR;
Mem -> ?MEM_STR;
+ ?PERSISTENT_STR -> Persistent;
Int -> ?INT_STR;
_ -> "unknown"
end.
@@ -428,8 +440,9 @@ do_load_dump(Frame,FileName) ->
ok ->
%% Set window title
T1 = "Crashdump Viewer: ",
+ FileLength = string:length(FileName),
Title =
- if length(FileName) > 70 ->
+ if FileLength > 70 ->
T1 ++ filename:basename(FileName);
true ->
T1 ++ FileName
@@ -446,10 +459,7 @@ maybe_warn_filename(FileName) ->
true ->
continue;
false ->
- DumpName = case os:getenv("ERL_CRASH_DUMP") of
- false -> filename:absname("erl_crash.dump");
- Name -> filename:absname(Name)
- end,
+ DumpName = filename:absname(os:getenv("ERL_CRASH_DUMP", "erl_crash.dump")),
case filename:absname(FileName) of
DumpName ->
Warning =
diff --git a/lib/observer/src/crashdump_viewer.erl b/lib/observer/src/crashdump_viewer.erl
index d2a175d52d..97bb344cbf 100644
--- a/lib/observer/src/crashdump_viewer.erl
+++ b/lib/observer/src/crashdump_viewer.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -74,6 +74,7 @@
loaded_modules/0,
loaded_mod_details/1,
memory/0,
+ persistent_terms/0,
allocated_areas/0,
allocator_info/0,
hash_tables/0,
@@ -139,6 +140,7 @@
-define(node,node).
-define(not_connected,not_connected).
-define(old_instr_data,old_instr_data).
+-define(persistent_terms,persistent_terms).
-define(port,port).
-define(proc,proc).
-define(proc_dictionary,proc_dictionary).
@@ -293,6 +295,8 @@ loaded_mod_details(Mod) ->
call({loaded_mod_details,Mod}).
memory() ->
call(memory).
+persistent_terms() ->
+ call(persistent_terms).
allocated_areas() ->
call(allocated_areas).
allocator_info() ->
@@ -471,6 +475,11 @@ handle_call(memory,_From,State=#state{file=File}) ->
Memory=memory(File),
TW = truncated_warning([?memory]),
{reply,{ok,Memory,TW},State};
+handle_call(persistent_terms,_From,State=#state{file=File,dump_vsn=DumpVsn}) ->
+ TW = truncated_warning([?persistent_terms,?literals]),
+ DecodeOpts = get_decode_opts(DumpVsn),
+ Terms = persistent_terms(File, DecodeOpts),
+ {reply,{ok,Terms,TW},State};
handle_call(allocated_areas,_From,State=#state{file=File}) ->
AllocatedAreas=allocated_areas(File),
TW = truncated_warning([?allocated_areas]),
@@ -580,9 +589,9 @@ truncated_here(Tag) ->
case get(truncated) of
true ->
case get(last_tag) of
- Tag -> % Tag == {TagType,Id}
+ {Tag,_Pos} -> % Tag == {TagType,Id}
true;
- {Tag,_Id} ->
+ {{Tag,_Id},_Pos} ->
true;
_LastTag ->
truncated_earlier(Tag)
@@ -837,8 +846,8 @@ do_read_file(File) ->
case check_dump_version(Id) of
{ok,DumpVsn} ->
reset_tables(),
- insert_index(Tag,Id,N1+1),
- put_last_tag(Tag,""),
+ insert_index(Tag,Id,Pos=N1+1),
+ put_last_tag(Tag,"",Pos),
DecodeOpts = get_decode_opts(DumpVsn),
indexify(Fd,DecodeOpts,Rest,N1),
end_progress(),
@@ -877,7 +886,7 @@ do_read_file(File) ->
end.
check_dump_version(Vsn) ->
- DumpVsn = [list_to_integer(L) || L<-string:tokens(Vsn,".")],
+ DumpVsn = [list_to_integer(L) || L<-string:lexemes(Vsn,".")],
if DumpVsn > ?max_dump_version ->
Info =
"This Crashdump Viewer is too old for the given "
@@ -906,23 +915,11 @@ indexify(Fd,DecodeOpts,Bin,N) ->
_ ->
insert_index(Tag,Id,NewPos)
end,
- case put_last_tag(Tag,Id) of
- {?proc_heap,LastId} ->
- [{_,LastPos}] = lookup_index(?proc_heap,LastId),
+ case put_last_tag(Tag,Id,NewPos) of
+ {{?proc_heap,LastId},LastPos} ->
ets:insert(cdv_heap_file_chars,{LastId,N+Start+1-LastPos});
- {?literals,[]} ->
- case get(truncated_reason) of
- undefined ->
- [{_,LastPos}] = lookup_index(?literals,[]),
- ets:insert(cdv_heap_file_chars,
- {literals,N+Start+1-LastPos});
- _ ->
- %% Literals are truncated. Make sure we never
- %% attempt to read in the literals. (Heaps that
- %% references literals will show markers for
- %% incomplete heaps, but will otherwise work.)
- delete_index(?literals, [])
- end;
+ {{?literals,[]},LastPos} ->
+ ets:insert(cdv_heap_file_chars,{literals,N+Start+1-LastPos});
_ -> ok
end,
indexify(Fd,DecodeOpts,Rest,N1);
@@ -964,10 +961,18 @@ tag(Fd,<<>>,N,Gat,Di,Now) ->
check_if_truncated() ->
case get(last_tag) of
- {?ende,_} ->
+ {{?ende,_},_} ->
put(truncated,false),
put(truncated_proc,false);
- TruncatedTag ->
+ {{?literals,[]},_} ->
+ put(truncated,true),
+ put(truncated_proc,false),
+ %% Literals are truncated. Make sure we never
+ %% attempt to read in the literals. (Heaps that
+ %% references literals will show markers for
+ %% incomplete heaps, but will otherwise work.)
+ delete_index(?literals, []);
+ {TruncatedTag,_} ->
put(truncated,true),
find_truncated_proc(TruncatedTag)
end.
@@ -975,7 +980,6 @@ check_if_truncated() ->
find_truncated_proc({Tag,_Id}) when Tag==?atoms;
Tag==?binary;
Tag==?instr_data;
- Tag==?literals;
Tag==?memory_status;
Tag==?memory_map ->
put(truncated_proc,false);
@@ -1444,15 +1448,7 @@ maybe_other_node2(Channel) ->
expand_memory(Fd,Pid,DumpVsn) ->
DecodeOpts = get_decode_opts(DumpVsn),
put(fd,Fd),
- Dict0 = case get(?literals) of
- undefined ->
- Literals = read_literals(Fd,DecodeOpts),
- put(?literals,Literals),
- put(fd,Fd),
- Literals;
- Literals ->
- Literals
- end,
+ Dict0 = get_literals(Fd,DecodeOpts),
Dict = read_heap(Fd,Pid,DecodeOpts,Dict0),
Expanded = {read_stack_dump(Fd,Pid,DecodeOpts,Dict),
read_messages(Fd,Pid,DecodeOpts,Dict),
@@ -1468,6 +1464,18 @@ expand_memory(Fd,Pid,DumpVsn) ->
end,
{Expanded,IncompleteWarning}.
+get_literals(Fd,DecodeOpts) ->
+ case get(?literals) of
+ undefined ->
+ OldFd = put(fd,Fd),
+ Literals = read_literals(Fd,DecodeOpts),
+ put(fd,OldFd),
+ put(?literals,Literals),
+ Literals;
+ Literals ->
+ Literals
+ end.
+
read_literals(Fd,DecodeOpts) ->
case lookup_index(?literals,[]) of
[{_,Start}] ->
@@ -1594,31 +1602,92 @@ read_heap(Fd,Pid,DecodeOpts,Dict0) ->
Dict0
end.
-read_heap(DecodeOpts,Dict0) ->
- %% This function is never called if the dump is truncated in {?proc_heap,Pid}
- case get(fd) of
- end_of_heap ->
+read_heap(DecodeOpts, Dict0) ->
+ %% This function is never called if the dump is truncated in
+ %% {?proc_heap,Pid}.
+ %%
+ %% It is not always possible to reconstruct the heap terms
+ %% in a single pass, especially if maps are involved.
+ %% See crashdump_helper:literal_map/0 for an example.
+ %%
+ %% Therefore, we need two passes. In the first pass
+ %% we collect all lines without parsing them, and in the
+ %% second pass we parse them.
+ %%
+ %% The first pass follows.
+
+ Lines0 = read_heap_lines(),
+
+ %% Save a map of all unprocessed lines so that deref_ptr() can
+ %% access any line when there are references to terms not yet
+ %% built.
+
+ LineMap = maps:from_list(Lines0),
+ put(line_map, LineMap),
+
+ %% Refc binaries (tag "Yc") must be processed before any sub
+ %% binaries (tag "Ys") referencing them, so we make sure to
+ %% process all the refc binaries first.
+ %%
+ %% The other lines can be processed in any order, but processing
+ %% them in the reverse order compared to how they are printed in
+ %% the crash dump seems to minimize the number of references to
+ %% terms that have not yet been built. That happens to be the
+ %% order of the line list as returned by read_heap_lines/0.
+
+ RefcBins = [Refc || {_,<<"Yc",_/binary>>}=Refc <- Lines0],
+ Lines = RefcBins ++ Lines0,
+
+ %% Second pass.
+
+ init_progress("Processing terms", map_size(LineMap)),
+ Dict = parse_heap_terms(Lines, DecodeOpts, Dict0),
+ erase(line_map),
+ end_progress(),
+ Dict.
+
+read_heap_lines() ->
+ read_heap_lines_1(get(fd), []).
+
+read_heap_lines_1(Fd, Acc) ->
+ case bytes(Fd) of
+ "=" ++ _next_tag ->
end_progress(),
- Dict0;
- Fd ->
- case bytes(Fd) of
- "=" ++ _next_tag ->
- end_progress(),
- put(fd, end_of_heap),
- Dict0;
- Line ->
- update_progress(length(Line)+1),
- Dict = parse(Line,DecodeOpts,Dict0),
- read_heap(DecodeOpts,Dict)
- end
+ put(fd, end_of_heap),
+ Acc;
+ Line0 ->
+ update_progress(length(Line0)+1),
+ {Addr,":"++Line1} = get_hex(Line0),
+
+ %% Reduce the memory consumption by converting the
+ %% line to a binary. Measurements show that it may also
+ %% be benefical for performance, too, because it makes the
+ %% garbage collections cheaper.
+
+ Line = list_to_binary(Line1),
+ read_heap_lines_1(Fd, [{Addr,Line}|Acc])
end.
-parse(Line0, DecodeOpts, Dict0) ->
- {Addr,":"++Line1} = get_hex(Line0),
- {_Term,Line,Dict} = parse_heap_term(Line1, Addr, DecodeOpts, Dict0),
- [] = skip_blanks(Line),
+parse_heap_terms([{Addr,Line0}|T], DecodeOpts, Dict0) ->
+ case gb_trees:is_defined(Addr, Dict0) of
+ true ->
+ %% Already parsed (by a recursive call from do_deref_ptr()
+ %% to parse_line()). Nothing to do.
+ parse_heap_terms(T, DecodeOpts, Dict0);
+ false ->
+ %% Parse this previously unparsed term.
+ Dict = parse_line(Addr, Line0, DecodeOpts, Dict0),
+ parse_heap_terms(T, DecodeOpts, Dict)
+ end;
+parse_heap_terms([], _DecodeOpts, Dict) ->
Dict.
+parse_line(Addr, Line0, DecodeOpts, Dict0) ->
+ update_progress(1),
+ Line1 = binary_to_list(Line0),
+ {_Term,Line,Dict} = parse_heap_term(Line1, Addr, DecodeOpts, Dict0),
+ [] = skip_blanks(Line), %Assertion.
+ Dict.
%%-----------------------------------------------------------------
%% Page with one port
@@ -1643,7 +1712,7 @@ get_ports(File) ->
%% Converting port string to tuple to secure correct sorting. This is
%% converted back in cdv_port_cb:format/1.
port_to_tuple("#Port<"++Port) ->
- [I1,I2] = string:tokens(Port,".>"),
+ [I1,I2] = string:lexemes(Port,".>"),
{list_to_integer(I1),list_to_integer(I2)}.
get_portinfo(Fd,Port) ->
@@ -1670,9 +1739,9 @@ get_portinfo(Fd,Port) ->
"Registered as" ->
get_portinfo(Fd,Port#port{name=string(Fd)});
"Monitors" ->
- Monitors0 = string:tokens(bytes(Fd),"()"),
+ Monitors0 = string:lexemes(bytes(Fd),"()"),
Monitors = [begin
- [Pid,Ref] = string:tokens(Mon,","),
+ [Pid,Ref] = string:lexemes(Mon,","),
{Pid,Pid++" ("++Ref++")"}
end || Mon <- Monitors0],
get_portinfo(Fd,Port#port{monitors=Monitors});
@@ -1746,7 +1815,7 @@ get_etsinfo(Fd,EtsTable = #ets_table{details=Ds},WS) ->
"Buckets" ->
%% A bug in erl_db_hash.c prints a space after the buckets
%% - need to strip the string to make list_to_integer/1 happy.
- Buckets = list_to_integer(string:strip(bytes(Fd))),
+ Buckets = list_to_integer(string:trim(bytes(Fd),both,"\s")),
get_etsinfo(Fd,EtsTable#ets_table{buckets=Buckets},WS);
"Objects" ->
get_etsinfo(Fd,EtsTable#ets_table{size=list_to_integer(bytes(Fd))},WS);
@@ -1764,7 +1833,9 @@ get_etsinfo(Fd,EtsTable = #ets_table{details=Ds},WS) ->
Val = bytes(Fd),
get_etsinfo(Fd,EtsTable#ets_table{details=Ds#{chain_min=>Val}},WS);
"Chain Length Avg" ->
- Val = try list_to_float(string:strip(bytes(Fd))) catch _:_ -> "-" end,
+ Val = try list_to_float(string:trim(bytes(Fd),both,"\s"))
+ catch _:_ -> "-"
+ end,
get_etsinfo(Fd,EtsTable#ets_table{details=Ds#{chain_avg=>Val}},WS);
"Chain Length Max" ->
Val = bytes(Fd),
@@ -1921,7 +1992,7 @@ get_nodeinfo(Fd,Nod) ->
Creations = lists:flatmap(fun(C) -> try [list_to_integer(C)]
catch error:badarg -> []
end
- end, string:tokens(bytes(Fd)," ")),
+ end, string:lexemes(bytes(Fd)," ")),
get_nodeinfo(Fd,Nod#nod{creation={creations,Creations}});
"Remote link" ->
Procs = bytes(Fd), % e.g. "<0.31.0> <4322.54.0>"
@@ -2140,6 +2211,56 @@ get_atom(Atom) when is_binary(Atom) ->
{Atom,nq}. % not quoted
%%-----------------------------------------------------------------
+%% Page with list of all persistent terms
+persistent_terms(File, DecodeOpts) ->
+ case lookup_index(?persistent_terms) of
+ [{_Id,Start}] ->
+ Fd = open(File),
+ pos_bof(Fd,Start),
+ Terms = get_persistent_terms(Fd),
+ Dict = get_literals(Fd,DecodeOpts),
+ parse_persistent_terms(Terms,DecodeOpts,Dict);
+ _ ->
+ []
+ end.
+
+parse_persistent_terms([[Name0,Val0]|Terms],DecodeOpts,Dict) ->
+ {Name,_,_} = parse_term(binary_to_list(Name0),DecodeOpts,Dict),
+ {Val,_,_} = parse_term(binary_to_list(Val0),DecodeOpts,Dict),
+ [{Name,Val}|parse_persistent_terms(Terms,DecodeOpts,Dict)];
+parse_persistent_terms([],_,_) -> [].
+
+get_persistent_terms(Fd) ->
+ case get_chunk(Fd) of
+ {ok,Bin} ->
+ get_persistent_terms(Fd,Bin,[]);
+ eof ->
+ []
+ end.
+
+
+%% Persistent_Terms are written one per line in the crash dump.
+get_persistent_terms(Fd,Bin,PersistentTerms) ->
+ Bins = binary:split(Bin,<<"\n">>,[global]),
+ get_persistent_terms1(Fd,Bins,PersistentTerms).
+
+get_persistent_terms1(_Fd,[<<"=",_/binary>>|_],PersistentTerms) ->
+ PersistentTerms;
+get_persistent_terms1(Fd,[LastBin],PersistentTerms) ->
+ case get_chunk(Fd) of
+ {ok,Bin0} ->
+ get_persistent_terms(Fd,<<LastBin/binary,Bin0/binary>>,PersistentTerms);
+ eof ->
+ [get_persistent_term(LastBin)|PersistentTerms]
+ end;
+get_persistent_terms1(Fd,[Bin|Bins],Persistent_Terms) ->
+ get_persistent_terms1(Fd,Bins,[get_persistent_term(Bin)|Persistent_Terms]).
+
+get_persistent_term(Bin) ->
+ binary:split(Bin,<<"|">>).
+
+
+%%-----------------------------------------------------------------
%% Page with memory information
memory(File) ->
case lookup_index(?memory) of
@@ -2359,7 +2480,7 @@ get_size_value(Key,Data) ->
%% and Value is the sum over all allocator instances of each type.
sort_allocator_types([{Name,Data}|Allocators],Acc,DoTotal) ->
Type =
- case string:tokens(Name,"[]") of
+ case string:lexemes(Name,"[]") of
[T,_Id] -> T;
[Name] -> Name;
Other -> Other
@@ -2744,12 +2865,12 @@ parse_heap_term("Yc"++Line0, Addr, DecodeOpts, D0) -> %Reference-counted binary.
SymbolicBin = {'#CDVBin',Start},
Term = cdvbin(Offset, Sz, SymbolicBin),
D1 = gb_trees:insert(Addr, Term, D0),
- D = gb_trees:insert(Binp, SymbolicBin, D1),
+ D = gb_trees:enter(Binp, SymbolicBin, D1),
{Term,Line,D};
[] ->
Term = '#CDVNonexistingBinary',
D1 = gb_trees:insert(Addr, Term, D0),
- D = gb_trees:insert(Binp, Term, D1),
+ D = gb_trees:enter(Binp, Term, D1),
{Term,Line,D}
end;
parse_heap_term("Ys"++Line0, Addr, DecodeOpts, D0) -> %Sub binary.
@@ -2761,12 +2882,17 @@ parse_heap_term("Ys"++Line0, Addr, DecodeOpts, D0) -> %Sub binary.
{Term,Line,D};
parse_heap_term("Mf"++Line0, Addr, DecodeOpts, D0) -> %Flatmap.
{Size,":"++Line1} = get_hex(Line0),
- {Keys,":"++Line2,D1} = parse_term(Line1, DecodeOpts, D0),
- {Values,Line,D2} = parse_tuple(Size, Line2, Addr,DecodeOpts, D1, []),
- Pairs = zip_tuples(tuple_size(Keys), Keys, Values, []),
- Map = maps:from_list(Pairs),
- D = gb_trees:update(Addr, Map, D2),
- {Map,Line,D};
+ case parse_term(Line1, DecodeOpts, D0) of
+ {Keys,":"++Line2,D1} when is_tuple(Keys) ->
+ {Values,Line,D2} = parse_tuple(Size, Line2, Addr,DecodeOpts, D1, []),
+ Pairs = zip_tuples(tuple_size(Keys), Keys, Values, []),
+ Map = maps:from_list(Pairs),
+ D = gb_trees:update(Addr, Map, D2),
+ {Map,Line,D};
+ {Incomplete,_Line,D1} ->
+ D = gb_trees:insert(Addr, Incomplete, D1),
+ {Incomplete,"",D}
+ end;
parse_heap_term("Mh"++Line0, Addr, DecodeOpts, D0) -> %Head node in a hashmap.
{MapSize,":"++Line1} = get_hex(Line0),
{N,":"++Line2} = get_hex(Line1),
@@ -2869,16 +2995,18 @@ parse_atom_translation_table(N, Line0, As) ->
deref_ptr(Ptr, Line, DecodeOpts, D) ->
- Lookup = fun(D0) ->
- gb_trees:lookup(Ptr, D0)
- end,
+ Lookup0 = fun(D0) ->
+ gb_trees:lookup(Ptr, D0)
+ end,
+ Lookup = wrap_line_map(Ptr, Lookup0),
do_deref_ptr(Lookup, Line, DecodeOpts, D).
deref_bin(Binp0, Offset, Sz, Line, DecodeOpts, D) ->
Binp = Binp0 bor DecodeOpts#dec_opts.bin_addr_adj,
- Lookup = fun(D0) ->
- lookup_binary(Binp, Offset, Sz, D0)
- end,
+ Lookup0 = fun(D0) ->
+ lookup_binary(Binp, Offset, Sz, D0)
+ end,
+ Lookup = wrap_line_map(Binp, Lookup0),
do_deref_ptr(Lookup, Line, DecodeOpts, D).
lookup_binary(Binp, Offset, Sz, D) ->
@@ -2897,26 +3025,36 @@ lookup_binary(Binp, Offset, Sz, D) ->
end
end.
+wrap_line_map(Ptr, Lookup) ->
+ wrap_line_map_1(get(line_map), Ptr, Lookup).
+
+wrap_line_map_1(#{}=LineMap, Ptr, Lookup) ->
+ fun(D) ->
+ case Lookup(D) of
+ {value,_}=Res ->
+ Res;
+ none ->
+ case LineMap of
+ #{Ptr:=Line} ->
+ {line,Ptr,Line};
+ #{} ->
+ none
+ end
+ end
+ end;
+wrap_line_map_1(undefined, _Ptr, Lookup) ->
+ Lookup.
+
do_deref_ptr(Lookup, Line, DecodeOpts, D0) ->
case Lookup(D0) of
{value,Term} ->
{Term,Line,D0};
none ->
- case get(fd) of
- end_of_heap ->
- put(incomplete_heap,true),
- {['#CDVIncompleteHeap'],Line,D0};
- Fd ->
- case bytes(Fd) of
- "="++_ ->
- put(fd, end_of_heap),
- do_deref_ptr(Lookup, Line, DecodeOpts, D0);
- L ->
- update_progress(length(L)+1),
- D = parse(L, DecodeOpts, D0),
- do_deref_ptr(Lookup, Line, DecodeOpts, D)
- end
- end
+ put(incomplete_heap, true),
+ {'#CDVIncompleteHeap',Line,D0};
+ {line,Addr,NewLine} ->
+ D = parse_line(Addr, NewLine, DecodeOpts, D0),
+ do_deref_ptr(Lookup, Line, DecodeOpts, D)
end.
get_hex(L) ->
@@ -3117,6 +3255,7 @@ tag_to_atom("literals") -> ?literals;
tag_to_atom("loaded_modules") -> ?loaded_modules;
tag_to_atom("memory") -> ?memory;
tag_to_atom("mod") -> ?mod;
+tag_to_atom("persistent_terms") -> ?persistent_terms;
tag_to_atom("no_distribution") -> ?no_distribution;
tag_to_atom("node") -> ?node;
tag_to_atom("not_connected") -> ?not_connected;
@@ -3136,13 +3275,13 @@ tag_to_atom(UnknownTag) ->
%%%-----------------------------------------------------------------
%%% Store last tag for use when truncated, and reason if aborted
-put_last_tag(?abort,Reason) ->
- %% Don't overwrite the real last tag, and make sure to return
- %% the previous last tag.
- put(truncated_reason,Reason),
- get(last_tag);
-put_last_tag(Tag,Id) ->
- put(last_tag,{Tag,Id}).
+put_last_tag(?abort,Reason,_Pos) ->
+ %% Don't overwrite the real last tag, and don't return it either,
+ %% since that would make the caller of this function believe that
+ %% the tag was complete.
+ put(truncated_reason,Reason);
+put_last_tag(Tag,Id,Pos) ->
+ put(last_tag,{{Tag,Id},Pos}).
%%%-----------------------------------------------------------------
%%% Fetch next chunk from crashdump file
diff --git a/lib/observer/src/crashdump_viewer.hrl b/lib/observer/src/crashdump_viewer.hrl
index 252e19379d..856e558e6c 100644
--- a/lib/observer/src/crashdump_viewer.hrl
+++ b/lib/observer/src/crashdump_viewer.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/etop_tr.erl b/lib/observer/src/etop_tr.erl
index 1e48fefca4..c7e62e8332 100644
--- a/lib/observer/src/etop_tr.erl
+++ b/lib/observer/src/etop_tr.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/multitrace.erl b/lib/observer/src/multitrace.erl
index 82aec05e0d..35b70c63a3 100644
--- a/lib/observer/src/multitrace.erl
+++ b/lib/observer/src/multitrace.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/observer.app.src b/lib/observer/src/observer.app.src
index f682e3dc7b..d48b846ad2 100644
--- a/lib/observer/src/observer.app.src
+++ b/lib/observer/src/observer.app.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -34,6 +34,7 @@
cdv_mem_cb,
cdv_mod_cb,
cdv_multi_wx,
+ cdv_persistent_cb,
cdv_port_cb,
cdv_proc_cb,
cdv_table_wx,
@@ -65,8 +66,7 @@
{registered, []},
{applications, [kernel, stdlib]},
{env, []},
- {runtime_dependencies, ["wx-1.2","stdlib-3.4","runtime_tools-1.8.14",
- "kernel-3.0","inets-5.10","et-1.5",
- "erts-7.0"]}]}.
+ {runtime_dependencies, ["wx-1.2","stdlib-3.5","runtime_tools-1.8.14",
+ "kernel-3.0","et-1.5","erts-7.0"]}]}.
diff --git a/lib/observer/src/observer_alloc_wx.erl b/lib/observer/src/observer_alloc_wx.erl
index 7f4b3dd484..da47a30fb1 100644
--- a/lib/observer/src/observer_alloc_wx.erl
+++ b/lib/observer/src/observer_alloc_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -79,8 +79,8 @@ init([Notebook, Parent, Config]) ->
max = #{}
}
}
- catch _:Err ->
- io:format("~p crashed ~tp: ~tp~n",[?MODULE, Err, erlang:get_stacktrace()]),
+ catch _:Err:Stacktrace ->
+ io:format("~p crashed ~tp: ~tp~n",[?MODULE, Err, Stacktrace]),
{stop, Err}
end.
@@ -282,11 +282,12 @@ create_mem_info(Parent) ->
Grid = wxListCtrl:new(Parent, [{style, Style}]),
Li = wxListItem:new(),
+ Scale = observer_wx:get_scale(),
AddListEntry = fun({Name, Align, DefSize}, Col) ->
wxListItem:setText(Li, Name),
wxListItem:setAlign(Li, Align),
wxListCtrl:insertColumn(Grid, Col, Li),
- wxListCtrl:setColumnWidth(Grid, Col, DefSize),
+ wxListCtrl:setColumnWidth(Grid, Col, DefSize*Scale),
Col + 1
end,
ListItems = [{"Allocator Type", ?wxLIST_FORMAT_LEFT, 200},
diff --git a/lib/observer/src/observer_app_wx.erl b/lib/observer/src/observer_app_wx.erl
index 2a481966da..8c3eef5411 100644
--- a/lib/observer/src/observer_app_wx.erl
+++ b/lib/observer/src/observer_app_wx.erl
@@ -117,16 +117,19 @@ init([Notebook, Parent, _Config]) ->
UseGC = haveGC(),
Version28 = ?wxMAJOR_VERSION =:= 2 andalso ?wxMINOR_VERSION =:= 8,
+ Scale = observer_wx:get_scale(),
Font = case os:type() of
{unix,_} when UseGC, Version28 ->
- wxFont:new(12,?wxFONTFAMILY_DECORATIVE,?wxFONTSTYLE_NORMAL,?wxFONTWEIGHT_NORMAL);
+ wxFont:new(Scale * 12,?wxFONTFAMILY_DECORATIVE,?wxFONTSTYLE_NORMAL,?wxFONTWEIGHT_NORMAL);
_ ->
- wxSystemSettings:getFont(?wxSYS_DEFAULT_GUI_FONT)
+ Font0 = wxSystemSettings:getFont(?wxSYS_DEFAULT_GUI_FONT),
+ wxFont:setPointSize(Font0, Scale * wxFont:getPointSize(Font0)),
+ Font0
end,
SelCol = wxSystemSettings:getColour(?wxSYS_COLOUR_HIGHLIGHT),
GreyBrush = wxBrush:new({230,230,240}),
SelBrush = wxBrush:new(SelCol),
- LinkPen = wxPen:new(SelCol, [{width, 2}]),
+ LinkPen = wxPen:new(SelCol, [{width, Scale * 2}]),
process_flag(trap_exit, true),
{Panel, #state{parent=Parent,
panel =Panel,
@@ -134,7 +137,7 @@ init([Notebook, Parent, _Config]) ->
app_w =DrawingArea,
usegc = UseGC,
paint=#paint{font = Font,
- pen = wxPen:new({80,80,80}, [{width, 2}]),
+ pen = wxPen:new({80,80,80}, [{width, Scale * 2}]),
brush= GreyBrush,
sel = SelBrush,
links= LinkPen
diff --git a/lib/observer/src/observer_html_lib.erl b/lib/observer/src/observer_html_lib.erl
index 22b4714d63..c67fa28c6d 100644
--- a/lib/observer/src/observer_html_lib.erl
+++ b/lib/observer/src/observer_html_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -62,7 +62,8 @@ expandable_term_body(Heading,[],_Tab) ->
"Dictionary" -> "No dictionary was found";
"ProcState" -> "Information could not be retrieved,"
" system messages may not be handled by this process.";
- "SaslLog" -> "No log entry was found"
+ "SaslLog" -> "No log entry was found";
+ "Persistent Terms" -> "No persistent terms were found"
end];
expandable_term_body(Heading,Expanded,Tab) ->
Attr = "BORDER=0 CELLPADDING=0 CELLSPACING=1 WIDTH=100%",
@@ -278,24 +279,24 @@ href_proc_port("['#CDVPort'"++T,Acc,LTB) ->
%% Port written by crashdump_viewer:parse_term(...)
{Port0,Rest} = split($],T),
PortStr=
- case string:tokens(Port0,",.|") of
+ case string:lexemes(Port0,",.|") of
[X,Y] ->
Port = "#Port&lt;"++X++"."++Y++"&gt;",
href(Port,Port);
Ns ->
- "#Port&lt;" ++ string:join(Ns,".") ++"...&gt;"
+ "#Port&lt;" ++ lists:join($.,Ns) ++"...&gt;"
end,
href_proc_port(Rest,[PortStr|Acc],LTB);
href_proc_port("['#CDVPid'"++T,Acc,LTB) ->
%% Pid written by crashdump_viewer:parse_term(...)
{Pid0,Rest} = split($],T),
PidStr =
- case string:tokens(Pid0,",.|") of
+ case string:lexemes(Pid0,",.|") of
[X,Y,Z] ->
Pid = "&lt;"++X++"."++Y++"."++Z++"&gt;",
href(Pid,Pid);
Ns ->
- "&lt;" ++ string:join(Ns,".") ++ "...&gt;"
+ "&lt;" ++ lists:join($.,Ns) ++ "...&gt;"
end,
href_proc_port(Rest,[PidStr|Acc],LTB);
href_proc_port("'#CDVIncompleteHeap'"++T,Acc,LTB)->
@@ -332,7 +333,7 @@ href_proc_port([],Acc,_) ->
href_proc_bin(From, T, Acc, LTB) ->
{OffsetSizePos,Rest} = split($],T),
BinStr =
- case string:tokens(OffsetSizePos,",.| \n") of
+ case string:lexemes(OffsetSizePos,",.| \n") of
[Offset,SizeStr,Pos] when From =:= cdv ->
Size = list_to_integer(SizeStr),
PreviewSize = min(Size,10),
diff --git a/lib/observer/src/observer_lib.erl b/lib/observer/src/observer_lib.erl
index 0470e785d9..7c68b0ebb6 100644
--- a/lib/observer/src/observer_lib.erl
+++ b/lib/observer/src/observer_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -513,7 +513,7 @@ create_box(Parent, Data) ->
link_entry(Panel,Value);
_ ->
Value = to_str(Value0),
- case string:sub_word(lists:sublist(Value, 80),1,$\n) of
+ case string:nth_lexeme(lists:sublist(Value, 80),1, [$\n]) of
Value ->
%% Short string, no newlines - show all
wxStaticText:new(Panel, ?wxID_ANY, Value);
@@ -682,7 +682,7 @@ parse_string(Str) ->
{error, {_SLine, SMod, SError}, _} ->
throw(io_lib:format("~ts", [SMod:format_error(SError)]))
end,
- case lib:extended_parse_term(Tokens) of
+ case erl_eval:extended_parse_term(Tokens) of
{error, {_PLine, PMod, PError}} ->
throw(io_lib:format("~ts", [PMod:format_error(PError)]));
Res -> Res
diff --git a/lib/observer/src/observer_perf_wx.erl b/lib/observer/src/observer_perf_wx.erl
index 5adfadb16e..79271addf2 100644
--- a/lib/observer/src/observer_perf_wx.erl
+++ b/lib/observer/src/observer_perf_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -86,8 +86,8 @@ init([Notebook, Parent, Config]) ->
secs=maps:get(secs, Config, ?DISP_SECONDS)}
},
{Panel, State0}
- catch _:Err ->
- io:format("~p crashed ~tp: ~tp~n",[?MODULE, Err, erlang:get_stacktrace()]),
+ catch _:Err:Stacktrace ->
+ io:format("~p crashed ~tp: ~tp~n",[?MODULE, Err, Stacktrace]),
{stop, Err}
end.
@@ -110,25 +110,26 @@ setup_graph_drawing(Panels) ->
_ = [Do(Panel) || Panel <- Panels],
UseGC = haveGC(),
Version28 = ?wxMAJOR_VERSION =:= 2 andalso ?wxMINOR_VERSION =:= 8,
+ Scale = observer_wx:get_scale(),
{Font, SmallFont}
= if UseGC, Version28 ->
%% Def font is really small when using Graphics contexts in 2.8
%% Hardcode it
- F = wxFont:new(12,?wxFONTFAMILY_DECORATIVE,?wxFONTSTYLE_NORMAL,?wxFONTWEIGHT_BOLD),
- SF = wxFont:new(10, ?wxFONTFAMILY_DECORATIVE, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_NORMAL),
+ F = wxFont:new(Scale * 12,?wxFONTFAMILY_DECORATIVE,?wxFONTSTYLE_NORMAL,?wxFONTWEIGHT_BOLD),
+ SF = wxFont:new(Scale * 10, ?wxFONTFAMILY_DECORATIVE, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_NORMAL),
{F, SF};
true ->
DefFont = wxSystemSettings:getFont(?wxSYS_DEFAULT_GUI_FONT),
DefSize = wxFont:getPointSize(DefFont),
DefFamily = wxFont:getFamily(DefFont),
- F = wxFont:new(DefSize-1, DefFamily, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_BOLD),
- SF = wxFont:new(DefSize-2, DefFamily, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_NORMAL),
+ F = wxFont:new(Scale * (DefSize-1), DefFamily, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_BOLD),
+ SF = wxFont:new(Scale * (DefSize-2), DefFamily, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_NORMAL),
{F, SF}
end,
- BlackPen = wxPen:new({0,0,0}, [{width, 1}]),
- Pens = [wxPen:new(Col, [{width, 1}, {style, ?wxSOLID}])
+ BlackPen = wxPen:new({0,0,0}, [{width, Scale}]),
+ Pens = [wxPen:new(Col, [{width, Scale}, {style, ?wxSOLID}])
|| Col <- tuple_to_list(colors())],
- DotPens = [wxPen:new(Col, [{width, 1}, {style, ?wxDOT}])
+ DotPens = [wxPen:new(Col, [{width, Scale}, {style, ?wxDOT}])
|| Col <- tuple_to_list(colors())],
#paint{usegc = UseGC,
font = Font,
diff --git a/lib/observer/src/observer_port_wx.erl b/lib/observer/src/observer_port_wx.erl
index f7ae07fb85..00cf1b5fba 100644
--- a/lib/observer/src/observer_port_wx.erl
+++ b/lib/observer/src/observer_port_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -96,11 +96,12 @@ init([Notebook, Parent, Config]) ->
wxListCtrl:setColumnWidth(Grid, Col, DefSize),
Col + 1
end,
- ListItems = [{"Id", ?wxLIST_FORMAT_LEFT, 150},
- {"Connected", ?wxLIST_FORMAT_LEFT, 150},
- {"Name", ?wxLIST_FORMAT_LEFT, 150},
- {"Controls", ?wxLIST_FORMAT_LEFT, 200},
- {"Slot", ?wxLIST_FORMAT_RIGHT, 50}],
+ Scale = observer_wx:get_scale(),
+ ListItems = [{"Id", ?wxLIST_FORMAT_LEFT, Scale*150},
+ {"Connected", ?wxLIST_FORMAT_LEFT, Scale*150},
+ {"Name", ?wxLIST_FORMAT_LEFT, Scale*150},
+ {"Controls", ?wxLIST_FORMAT_LEFT, Scale*200},
+ {"Slot", ?wxLIST_FORMAT_RIGHT, Scale*50}],
lists:foldl(AddListEntry, 0, ListItems),
wxListItem:destroy(Li),
@@ -461,10 +462,11 @@ display_port_info(Parent, PortRec, Opened) ->
do_display_port_info(Parent0, PortRec) ->
Parent = observer_lib:get_wx_parent(Parent0),
Title = "Port Info: " ++ PortRec#port.id_str,
+ Scale = observer_wx:get_scale(),
Frame = wxMiniFrame:new(Parent, ?wxID_ANY, Title,
[{style, ?wxSYSTEM_MENU bor ?wxCAPTION
bor ?wxCLOSE_BOX bor ?wxRESIZE_BORDER},
- {size,{600,400}}]),
+ {size,{Scale * 600, Scale * 400}}]),
ScrolledWin = wxScrolledWindow:new(Frame,[{style,?wxHSCROLL bor ?wxVSCROLL}]),
wxScrolledWindow:enableScrolling(ScrolledWin,true,true),
wxScrolledWindow:setScrollbars(ScrolledWin,20,20,0,0),
diff --git a/lib/observer/src/observer_pro_wx.erl b/lib/observer/src/observer_pro_wx.erl
index 1c40afba46..4ab4a78462 100644
--- a/lib/observer/src/observer_pro_wx.erl
+++ b/lib/observer/src/observer_pro_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -50,6 +50,7 @@
-define(ID_TRACE_NEW, 208).
-define(ID_TRACE_ALL, 209).
-define(ID_ACCUMULATE, 210).
+-define(ID_GARBAGE_COLLECT, 211).
-define(TRACE_PIDS_STR, "Trace selected process identifiers").
-define(TRACE_NAMES_STR, "Trace selected processes, "
@@ -147,11 +148,11 @@ create_list_box(Panel, Holder) ->
ListCtrl = wxListCtrl:new(Panel, [{style, Style},
{onGetItemText,
fun(_, Row, Col) ->
- call(Holder, {get_row, self(), Row, Col})
+ safe_call(Holder, {get_row, self(), Row, Col})
end},
{onGetItemAttr,
fun(_, Item) ->
- call(Holder, {get_attr, self(), Item})
+ safe_call(Holder, {get_attr, self(), Item})
end}
]),
Li = wxListItem:new(),
@@ -162,13 +163,14 @@ create_list_box(Panel, Holder) ->
wxListCtrl:setColumnWidth(ListCtrl, Col, DefSize),
Col + 1
end,
- ListItems = [{"Pid", ?wxLIST_FORMAT_CENTRE, 120},
- {"Name or Initial Func", ?wxLIST_FORMAT_LEFT, 200},
-%% {"Time", ?wxLIST_FORMAT_CENTRE, 50},
- {"Reds", ?wxLIST_FORMAT_RIGHT, 100},
- {"Memory", ?wxLIST_FORMAT_RIGHT, 100},
- {"MsgQ", ?wxLIST_FORMAT_RIGHT, 50},
- {"Current Function", ?wxLIST_FORMAT_LEFT, 200}],
+ Scale = observer_wx:get_scale(),
+ ListItems = [{"Pid", ?wxLIST_FORMAT_CENTRE, Scale*120},
+ {"Name or Initial Func", ?wxLIST_FORMAT_LEFT, Scale*200},
+%% {"Time", ?wxLIST_FORMAT_CENTRE, Scale*50},
+ {"Reds", ?wxLIST_FORMAT_RIGHT, Scale*100},
+ {"Memory", ?wxLIST_FORMAT_RIGHT, Scale*100},
+ {"MsgQ", ?wxLIST_FORMAT_RIGHT, Scale*50},
+ {"Current Function", ?wxLIST_FORMAT_LEFT, Scale*200}],
lists:foldl(AddListEntry, 0, ListItems),
wxListItem:destroy(Li),
@@ -208,17 +210,26 @@ start_procinfo(Pid, Frame, Opened) ->
Opened
end.
+
+safe_call(Holder, What) ->
+ case call(Holder, What, 2000) of
+ Res when is_atom(Res) -> "";
+ Res -> Res
+ end.
+
call(Holder, What) ->
+ call(Holder, What, infinity).
+
+call(Holder, What, TMO) ->
Ref = erlang:monitor(process, Holder),
Holder ! What,
receive
- {'DOWN', Ref, _, _, _} -> "";
+ {'DOWN', Ref, _, _, _} -> holder_dead;
{Holder, Res} ->
erlang:demonitor(Ref),
Res
- after 2000 ->
- io:format("Hanging call ~tp~n",[What]),
- ""
+ after TMO ->
+ timeout
end.
%%%%%%%%%%%%%%%%%%%%%%% Callbacks %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -269,7 +280,10 @@ code_change(_, _, State) ->
handle_call(get_config, _, #state{holder=Holder, timer=Timer}=State) ->
Conf = observer_lib:timer_config(Timer),
- Accum = call(Holder, {get_accum, self()}),
+ Accum = case safe_call(Holder, {get_accum, self()}) of
+ Bool when is_boolean(Bool) -> Bool;
+ _ -> false
+ end,
{reply, Conf#{acc=>Accum}, State};
handle_call(Msg, _From, State) ->
@@ -316,6 +330,9 @@ handle_event(#wx{id=?ID_KILL}, #state{right_clicked_pid=Pid, sel=Sel0}=State) ->
Sel = rm_selected(Pid,Sel0),
{noreply, State#state{sel=Sel}};
+handle_event(#wx{id=?ID_GARBAGE_COLLECT}, #state{sel={_, Pids}}=State) ->
+ _ = [rpc:call(node(Pid), erlang, garbage_collect, [Pid]) || Pid <- Pids],
+ {noreply, State};
handle_event(#wx{id=?ID_PROC},
#state{panel=Panel, right_clicked_pid=Pid, procinfo_menu_pids=Opened}=State) ->
@@ -370,6 +387,7 @@ handle_event(#wx{event=#wxList{type=command_list_item_right_click,
wxMenu:append(Menu, ?ID_TRACE_NAMES,
"Trace selected processes by name (all nodes)",
[{help, ?TRACE_NAMES_STR}]),
+ wxMenu:append(Menu, ?ID_GARBAGE_COLLECT, "Garbage collect processes"),
wxMenu:append(Menu, ?ID_KILL, "Kill process " ++ pid_to_list(P)),
wxWindow:popupMenu(Panel, Menu),
wxMenu:destroy(Menu),
@@ -465,7 +483,7 @@ init_table_holder(Parent, Accum0, Attrs) ->
Backend = spawn_link(node(), observer_backend, procs_info, [self()]),
Accum = case Accum0 of
true -> true;
- false -> []
+ _ -> []
end,
table_holder(#holder{parent=Parent,
info=array:new(),
diff --git a/lib/observer/src/observer_procinfo.erl b/lib/observer/src/observer_procinfo.erl
index 5bc17e2aee..bd5fed0951 100644
--- a/lib/observer/src/observer_procinfo.erl
+++ b/lib/observer/src/observer_procinfo.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -59,8 +59,9 @@ init([Pid, ParentFrame, Parent]) ->
{registered_name, Registered} -> io_lib:format("~tp (~p)",[Registered, Pid]);
undefined -> throw(process_undefined)
end,
+ Scale = observer_wx:get_scale(),
Frame=wxFrame:new(ParentFrame, ?wxID_ANY, [atom_to_list(node(Pid)), $:, Title],
- [{style, ?wxDEFAULT_FRAME_STYLE}, {size, {850,600}}]),
+ [{style, ?wxDEFAULT_FRAME_STYLE}, {size, {Scale * 850, Scale * 600}}]),
MenuBar = wxMenuBar:new(),
create_menus(MenuBar),
wxFrame:setMenuBar(Frame, MenuBar),
@@ -148,7 +149,7 @@ handle_event(#wx{event=#wxHtmlLink{linkInfo=#wxHtmlLinkInfo{href=Href}}},
observer ! {open_link, Href},
{noreply, State};
Callback ->
- [{"key1",Key1},{"key2",Key2},{"key3",Key3}] = httpd:parse_query(Rest),
+ [{"key1",Key1},{"key2",Key2},{"key3",Key3}] = uri_string:dissect_query(Rest),
Id = {obs, {T,{list_to_integer(Key1),
list_to_integer(Key2),
list_to_integer(Key3)}}},
@@ -245,12 +246,13 @@ init_dict_page(Parent, Pid, Table) ->
init_stack_page(Parent, Pid) ->
LCtrl = wxListCtrl:new(Parent, [{style, ?wxLC_REPORT bor ?wxLC_HRULES}]),
Li = wxListItem:new(),
+ Scale = observer_wx:get_scale(),
wxListItem:setText(Li, "Module:Function/Arg"),
wxListCtrl:insertColumn(LCtrl, 0, Li),
- wxListCtrl:setColumnWidth(LCtrl, 0, 300),
+ wxListCtrl:setColumnWidth(LCtrl, 0, Scale * 300),
wxListItem:setText(Li, "File:LineNumber"),
wxListCtrl:insertColumn(LCtrl, 1, Li),
- wxListCtrl:setColumnWidth(LCtrl, 1, 300),
+ wxListCtrl:setColumnWidth(LCtrl, 1, Scale * 300),
wxListItem:destroy(Li),
Update = fun() ->
case observer_wx:try_rpc(node(Pid), erlang, process_info,
@@ -456,7 +458,8 @@ local_pid_str(Pid) ->
global_pid_node_pref(Pid) ->
%% Global PID node prefix : X of <X.Y.Z>
- string:strip(string:sub_word(pid_to_list(Pid),1,$.),left,$<).
+ [NodePrefix|_] = string:lexemes(pid_to_list(Pid),"<."),
+ NodePrefix.
io_get_data(Pid) ->
Pid ! {self(), get_data_and_close},
diff --git a/lib/observer/src/observer_trace_wx.erl b/lib/observer/src/observer_trace_wx.erl
index 2c3b46a3a1..f458c8c34a 100644
--- a/lib/observer/src/observer_trace_wx.erl
+++ b/lib/observer/src/observer_trace_wx.erl
@@ -188,8 +188,9 @@ create_proc_port_view(Parent) ->
wxListCtrl:setColumnWidth(Procs, Col, DefSize),
Col + 1
end,
- ProcListItems = [{"Process Id", ?wxLIST_FORMAT_CENTER, 120},
- {"Trace Options", ?wxLIST_FORMAT_LEFT, 300}],
+ Scale = observer_wx:get_scale(),
+ ProcListItems = [{"Process Id", ?wxLIST_FORMAT_CENTER, Scale*120},
+ {"Trace Options", ?wxLIST_FORMAT_LEFT, Scale*300}],
lists:foldl(AddProc, 0, ProcListItems),
AddPort = fun({Name, Align, DefSize}, Col) ->
@@ -199,8 +200,8 @@ create_proc_port_view(Parent) ->
wxListCtrl:setColumnWidth(Ports, Col, DefSize),
Col + 1
end,
- PortListItems = [{"Port Id", ?wxLIST_FORMAT_CENTER, 120},
- {"Trace Options", ?wxLIST_FORMAT_LEFT, 300}],
+ PortListItems = [{"Port Id", ?wxLIST_FORMAT_CENTER, Scale*120},
+ {"Trace Options", ?wxLIST_FORMAT_LEFT, Scale*300}],
lists:foldl(AddPort, 0, PortListItems),
wxListItem:destroy(Li),
@@ -242,14 +243,15 @@ create_matchspec_view(Parent) ->
Funcs = wxListCtrl:new(Splitter, [{winid, ?FUNCS_WIN}, {style, Style}]),
Li = wxListItem:new(),
+ Scale = observer_wx:get_scale(),
wxListItem:setText(Li, "Modules"),
wxListCtrl:insertColumn(Modules, 0, Li),
wxListItem:setText(Li, "Functions"),
wxListCtrl:insertColumn(Funcs, 0, Li),
- wxListCtrl:setColumnWidth(Funcs, 0, 150),
+ wxListCtrl:setColumnWidth(Funcs, 0, Scale*150),
wxListItem:setText(Li, "Match Spec"),
wxListCtrl:insertColumn(Funcs, 1, Li),
- wxListCtrl:setColumnWidth(Funcs, 1, 300),
+ wxListCtrl:setColumnWidth(Funcs, 1, Scale*300),
wxListItem:destroy(Li),
wxSplitterWindow:setSashGravity(Splitter, 0.0),
@@ -969,7 +971,8 @@ output_file(true, true, Opts) ->
create_logwindow(_Parent, false) -> {false, false};
create_logwindow(Parent, true) ->
- LogWin = wxFrame:new(Parent, ?LOG_WIN, "Trace Log", [{size, {750, 800}}]),
+ Scale = observer_wx:get_scale(),
+ LogWin = wxFrame:new(Parent, ?LOG_WIN, "Trace Log", [{size, {750*Scale, 800*Scale}}]),
MB = wxMenuBar:new(),
File = wxMenu:new(),
wxMenu:append(File, ?LOG_CLEAR, "Clear Log\tCtrl-C"),
diff --git a/lib/observer/src/observer_traceoptions_wx.erl b/lib/observer/src/observer_traceoptions_wx.erl
index 4f46426cf6..514d55ff24 100644
--- a/lib/observer/src/observer_traceoptions_wx.erl
+++ b/lib/observer/src/observer_traceoptions_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -167,9 +167,10 @@ select_nodes(Parent, Nodes) ->
check_selector(Parent, Choices).
module_selector(Parent, Node) ->
+ Scale = observer_wx:get_scale(),
Dialog = wxDialog:new(Parent, ?wxID_ANY, "Select Module or Event",
[{style, ?wxDEFAULT_DIALOG_STYLE bor ?wxRESIZE_BORDER},
- {size, {400, 400}}]),
+ {size, {400*Scale, 400*Scale}}]),
Panel = wxPanel:new(Dialog),
PanelSz = wxBoxSizer:new(?wxVERTICAL),
MainSz = wxBoxSizer:new(?wxVERTICAL),
@@ -237,9 +238,10 @@ function_selector(Parent, Node, Module) ->
end.
check_selector(Parent, ParsedChoices) ->
+ Scale = observer_wx:get_scale(),
Dialog = wxDialog:new(Parent, ?wxID_ANY, "Trace Functions",
[{style, ?wxDEFAULT_DIALOG_STYLE bor ?wxRESIZE_BORDER},
- {size, {400, 400}}]),
+ {size, {400*Scale, 400*Scale}}]),
Panel = wxPanel:new(Dialog),
PanelSz = wxBoxSizer:new(?wxVERTICAL),
@@ -331,9 +333,10 @@ select_matchspec(Pid, Parent, AllMatchSpecs, Key) ->
{value,{Key,MSs0},Rest} -> {MSs0,Rest};
false -> {[],AllMatchSpecs}
end,
+ Scale = observer_wx:get_scale(),
Dialog = wxDialog:new(Parent, ?wxID_ANY, "Trace Match Specifications",
[{style, ?wxDEFAULT_DIALOG_STYLE bor ?wxRESIZE_BORDER},
- {size, {400, 400}}]),
+ {size, {400*Scale, 400*Scale}}]),
Panel = wxPanel:new(Dialog),
PanelSz = wxBoxSizer:new(?wxVERTICAL),
@@ -536,7 +539,7 @@ ms_from_string(Str) ->
{error, List} -> throw([[Error, $\n] || {_, Error} <- List])
end
catch error:_Reason ->
- %% io:format("Bad term: ~ts~n ~tp in ~tp~n", [Str, _Reason, erlang:get_stacktrace()]),
+ %% io:format("Bad term: ~ts~n ~tp in ~tp~n", [Str, _Reason, Stacktrace]),
throw("Invalid term")
end.
@@ -619,7 +622,7 @@ create_styled_txtctrl(Parent) ->
keyWords() ->
L = ["after","begin","case","try","cond","catch","andalso","orelse",
- "end","fun","if","let","of","query","receive","when","bnot","not",
+ "end","fun","if","let","of","receive","when","bnot","not",
"div","rem","band","and","bor","bxor","bsl","bsr","or","xor"],
lists:flatten([K ++ " " || K <- L] ++ [0]).
diff --git a/lib/observer/src/observer_tv_table.erl b/lib/observer/src/observer_tv_table.erl
index d6dcee2cda..7bd67a0f0b 100644
--- a/lib/observer/src/observer_tv_table.erl
+++ b/lib/observer/src/observer_tv_table.erl
@@ -99,7 +99,8 @@ init([Parent, Opts]) ->
ets -> "TV Ets: " ++ Title0;
mnesia -> "TV Mnesia: " ++ Title0
end,
- Frame = wxFrame:new(Parent, ?wxID_ANY, Title, [{size, {800, 600}}]),
+ Scale = observer_wx:get_scale(),
+ Frame = wxFrame:new(Parent, ?wxID_ANY, Title, [{size, {Scale * 800, Scale * 600}}]),
IconFile = filename:join(code:priv_dir(observer), "erlang_observer.png"),
Icon = wxIcon:new(IconFile, [{type,?wxBITMAP_TYPE_PNG}]),
wxFrame:setIcon(Frame, Icon),
diff --git a/lib/observer/src/observer_tv_wx.erl b/lib/observer/src/observer_tv_wx.erl
index 2e387f7e74..9743a6ed42 100644
--- a/lib/observer/src/observer_tv_wx.erl
+++ b/lib/observer/src/observer_tv_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -87,12 +87,13 @@ init([Notebook, Parent, Config]) ->
wxListCtrl:setColumnWidth(Grid, Col, DefSize),
Col + 1
end,
- ListItems = [{"Table Name", ?wxLIST_FORMAT_LEFT, 200},
- {"Objects", ?wxLIST_FORMAT_RIGHT, 100},
- {"Size (kB)", ?wxLIST_FORMAT_RIGHT, 100},
- {"Owner Pid", ?wxLIST_FORMAT_CENTER, 150},
- {"Owner Name", ?wxLIST_FORMAT_LEFT, 200},
- {"Table Id", ?wxLIST_FORMAT_LEFT, 250}
+ Scale = observer_wx:get_scale(),
+ ListItems = [{"Table Name", ?wxLIST_FORMAT_LEFT, Scale*200},
+ {"Objects", ?wxLIST_FORMAT_RIGHT, Scale*100},
+ {"Size (kB)", ?wxLIST_FORMAT_RIGHT, Scale*100},
+ {"Owner Pid", ?wxLIST_FORMAT_CENTER, Scale*150},
+ {"Owner Name", ?wxLIST_FORMAT_LEFT, Scale*200},
+ {"Table Id", ?wxLIST_FORMAT_LEFT, Scale*250}
],
lists:foldl(AddListEntry, 0, ListItems),
wxListItem:destroy(Li),
@@ -147,7 +148,7 @@ handle_event(#wx{event=#wxList{type=command_list_item_activated,
State=#state{holder=Holder, node=Node, opts=#opts{type=Type}, grid=Grid}) ->
case get_table(Holder, Index) of
#tab{protection=private} ->
- self() ! {error, "Table has 'private' protection and can not be read"};
+ self() ! {error, "Table has 'private' protection and cannot be read"};
#tab{}=Table ->
observer_tv_table:start_link(Grid, [{node,Node}, {type,Type}, {table,Table}]);
_ -> ignore
@@ -187,7 +188,7 @@ handle_event(#wx{id=?ID_SHOW_TABLE},
R when is_integer(R) ->
case get_table(Holder, R) of
#tab{protection=private} ->
- self() ! {error, "Table has 'private' protection and can not be read"};
+ self() ! {error, "Table has 'private' protection and cannot be read"};
#tab{}=Table ->
observer_tv_table:start_link(Grid, [{node,Node}, {type,Type}, {table,Table}]);
_ -> ignore
diff --git a/lib/observer/src/observer_wx.erl b/lib/observer/src/observer_wx.erl
index be93b1d5f1..de7d821030 100644
--- a/lib/observer/src/observer_wx.erl
+++ b/lib/observer/src/observer_wx.erl
@@ -22,7 +22,7 @@
-export([start/0, stop/0]).
-export([create_menus/2, get_attrib/1, get_tracer/0, get_active_node/0, get_menubar/0,
- set_status/1, create_txt_dialog/4, try_rpc/4, return_to_localnode/2]).
+ get_scale/0, set_status/1, create_txt_dialog/4, try_rpc/4, return_to_localnode/2]).
-export([init/1, handle_event/2, handle_cast/2, terminate/2, code_change/3,
handle_call/3, handle_info/2, check_page_title/1]).
@@ -91,14 +91,24 @@ get_active_node() ->
get_menubar() ->
wx_object:call(observer, get_menubar).
+get_scale() ->
+ ScaleStr = os:getenv("OBSERVER_SCALE", "1"),
+ try list_to_integer(ScaleStr) of
+ Scale when Scale < 1 -> 1;
+ Scale -> Scale
+ catch _:_ ->
+ 1
+ end.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
init(_Args) ->
register(observer, self()),
wx:new(),
catch wxSystemOptions:setOption("mac.listctrl.always_use_generic", 1),
+ Scale = get_scale(),
Frame = wxFrame:new(wx:null(), ?wxID_ANY, "Observer",
- [{size, {850, 600}}, {style, ?wxDEFAULT_FRAME_STYLE}]),
+ [{size, {Scale * 850, Scale * 600}}, {style, ?wxDEFAULT_FRAME_STYLE}]),
IconFile = filename:join(code:priv_dir(observer), "erlang_observer.png"),
Icon = wxIcon:new(IconFile, [{type,?wxBITMAP_TYPE_PNG}]),
wxFrame:setIcon(Frame, Icon),
@@ -732,7 +742,7 @@ get_nodes() ->
{Nodes, lists:reverse(Menues)}.
epmd_nodes(Names) ->
- [_, Host] = string:tokens(atom_to_list(node()),"@"),
+ [_, Host] = string:lexemes(atom_to_list(node()),"@"),
[list_to_atom(Name ++ [$@|Host]) || {Name, _} <- Names].
update_node_list(State = #state{menubar=MenuBar}) ->
@@ -771,7 +781,11 @@ ensure_sasl_started(Node) ->
ensure_mf_h_handler_used(Node) ->
%% is log_mf_h used ?
- Handlers = rpc:block_call(Node, gen_event, which_handlers, [error_logger]),
+ Handlers =
+ case rpc:block_call(Node, gen_event, which_handlers, [error_logger]) of
+ {badrpc,{'EXIT',noproc}} -> []; % OTP-21+ and no event handler exists
+ Hs -> Hs
+ end,
case lists:any(fun(L)-> L == log_mf_h end, Handlers) of
false -> throw("Error: log_mf_h handler not used in sasl."),
error;
@@ -806,7 +820,7 @@ is_rb_compatible(Node) ->
is_rb_server_running(Node, LogState) ->
%% If already started, somebody else may use it.
- %% We can not use it too, as far log file would be overriden. Not fair.
+ %% We cannot use it too, as far log file would be overriden. Not fair.
case rpc:block_call(Node, erlang, whereis, [rb_server]) of
Pid when is_pid(Pid), (LogState == false) ->
throw("Error: rb_server is already started and maybe used by someone.");
diff --git a/lib/observer/src/ttb.erl b/lib/observer/src/ttb.erl
index 940fdc9818..29a572d7fe 100644
--- a/lib/observer/src/ttb.erl
+++ b/lib/observer/src/ttb.erl
@@ -100,7 +100,7 @@ do_tracer(Clients,PI,Traci) ->
{ok, H} = inet:gethostname(),
H;
_ ->
- [_,H] = string:tokens(atom_to_list(N),"@"),
+ [_,H] = string:lexemes(atom_to_list(N),"@"),
H
end,
case catch dbg:tracer(N,port,dbg:trace_port(ip,IpPortSpec)) of
@@ -976,7 +976,7 @@ decode_filename(3,Bin,latin1) ->
File.
host(Node) ->
- [_name,Host] = string:tokens(atom_to_list(Node),"@"),
+ [_name,Host] = string:lexemes(atom_to_list(Node),"@"),
Host.
wait_for_fetch([]) ->
@@ -1064,7 +1064,7 @@ collect_files(Dirs) ->
lists:map(fun(Dir) ->
MetaFiles = filelib:wildcard(filename:join(Dir,"*.ti")),
lists:map(fun(M) ->
- Sub = string:left(M,length(M)-3),
+ Sub = filename:rootname(M,".ti"),
case filelib:is_file(Sub) of
true -> Sub;
false -> Sub++".*.wrp"
diff --git a/lib/observer/src/ttb_et.erl b/lib/observer/src/ttb_et.erl
index 1b828eebc0..f90a7f6dcf 100644
--- a/lib/observer/src/ttb_et.erl
+++ b/lib/observer/src/ttb_et.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/test/crashdump_helper.erl b/lib/observer/test/crashdump_helper.erl
index b5e94a893a..84ed99afa5 100644
--- a/lib/observer/test/crashdump_helper.erl
+++ b/lib/observer/test/crashdump_helper.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,8 +21,10 @@
-module(crashdump_helper).
-export([n1_proc/2,remote_proc/2,
dump_maps/0,create_maps/0,
- create_binaries/0,create_sub_binaries/1]).
--compile(r18).
+ create_binaries/0,create_sub_binaries/1,
+ dump_persistent_terms/0,
+ create_persistent_terms/0]).
+-compile(r20).
-include_lib("common_test/include/ct.hrl").
n1_proc(N2,Creator) ->
@@ -62,6 +64,7 @@ n1_proc(Creator,_N2,Pid2,Port2,_L) ->
put(ref,Ref),
put(pid,Pid),
put(bin,Bin),
+ put(proc_bins,create_proc_bins()),
put(bins,create_binaries()),
put(sub_bin,SubBin),
put(sub_bins,create_sub_binaries(get(bins))),
@@ -117,6 +120,23 @@ create_sub_binary(Bin, Start, LenSub) ->
<<_:Start/bytes,Sub:Len/bytes,_/bytes>> = Bin,
Sub.
+create_proc_bins() ->
+ Parent = self(),
+ Pid =
+ spawn(
+ fun() ->
+ %% Just reverse the list here, so this binary is not
+ %% confused with the one created in n1_proc/5 above,
+ %% which is used for testing truncation (see
+ %% crashdump_viewer_SUITE:truncate_dump_binary/1)
+ Bin = list_to_binary(lists:reverse(lists:seq(1, 255))),
+ <<A:65/bytes,B:65/bytes,C/bytes>> = Bin,
+ Parent ! {self(),{A,B,C}}
+ end),
+ receive
+ {Pid,ProcBins} -> ProcBins
+ end.
+
%%%
%%% Test dumping of maps. Dumping of maps only from OTP 20.2.
%%%
@@ -142,4 +162,46 @@ create_maps() ->
Map3 = lists:foldl(fun(I, A) ->
A#{I=>I*I}
end, Map2, lists:seq(-10, 0)),
- #{a=>Map0,b=>Map1,c=>Map2,d=>Map3,e=>#{}}.
+ #{a=>Map0,b=>Map1,c=>Map2,d=>Map3,e=>#{},literal=>literal_map()}.
+
+literal_map() ->
+ %% A literal map such as the one below will produce a heap dump
+ %% like this:
+ %%
+ %% Address1:t4:H<Address3>,H<Address4>,H<Address5>,H<Address6>
+ %% Address2:Mf4:H<Adress1>:I1,I2,I3,I4
+ %% Address3: ... % "one"
+ %% Address4: ... % "two"
+ %% Address5: ... % "three"
+ %% Address6: ... % "four"
+ %%
+ %% The map cannot be reconstructed in a single sequential pass.
+ %%
+ %% To reconstruct the map, first the string keys "one"
+ %% through "four" must be reconstructed, then the tuple at
+ %% Adress1, then the map at Address2.
+
+ #{"one"=>1,"two"=>2,"three"=>3,"four"=>4}.
+
+%%%
+%%% Test dumping of persistent terms (from OTP 21.2).
+%%%
+
+dump_persistent_terms() ->
+ Parent = self(),
+ F = fun() ->
+ register(aaaaaaaa_persistent_terms, self()),
+ put(pts, create_persistent_terms()),
+ Parent ! {self(),done},
+ receive _ -> ok end
+ end,
+ Pid = spawn_link(F),
+ receive
+ {Pid,done} ->
+ {ok,Pid}
+ end.
+
+create_persistent_terms() ->
+ persistent_term:put({?MODULE,first}, {pid,42.0}),
+ persistent_term:put({?MODULE,second}, [1,2,3]),
+ {persistent_term:get({?MODULE,first}),persistent_term:get({?MODULE,second})}.
diff --git a/lib/observer/test/crashdump_viewer_SUITE.erl b/lib/observer/test/crashdump_viewer_SUITE.erl
index 41ca3f3ce9..31cf7011d4 100644
--- a/lib/observer/test/crashdump_viewer_SUITE.erl
+++ b/lib/observer/test/crashdump_viewer_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -345,6 +345,7 @@ browse_file(File) ->
{ok,_AllocINfo,_AllocInfoTW} = crashdump_viewer:allocator_info(),
{ok,_HashTabs,_HashTabsTW} = crashdump_viewer:hash_tables(),
{ok,_IndexTabs,_IndexTabsTW} = crashdump_viewer:index_tables(),
+ {ok,_PTs,_PTsTW} = crashdump_viewer:persistent_terms(),
io:format(" info read",[]),
@@ -399,6 +400,13 @@ special(File,Procs) ->
crashdump_viewer:expand_binary({SOffset,SSize,SPos}),
io:format(" expand binary ok",[]),
+ ProcBins = proplists:get_value(proc_bins,Dict),
+ {['#CDVBin',0,65,ProcBin],
+ ['#CDVBin',65,65,ProcBin],
+ ['#CDVBin',130,125,ProcBin]} = ProcBins,
+ io:format(" ProcBins ok",[]),
+
+
Binaries = crashdump_helper:create_binaries(),
verify_binaries(Binaries, proplists:get_value(bins,Dict)),
io:format(" binaries ok",[]),
@@ -595,6 +603,22 @@ special(File,Procs) ->
Maps = proplists:get_value(maps,Dict),
io:format(" maps ok",[]),
ok;
+ ".persistent_terms" ->
+ %% I registered a process as aaaaaaaa_persistent_term in
+ %% the dump to make sure it will be the first in the list
+ %% when sorted on names.
+ [#proc{pid=Pid0,name=Name}|_Rest] = lists:keysort(#proc.name,Procs),
+ "aaaaaaaa_persistent_terms" = Name,
+ Pid = pid_to_list(Pid0),
+ {ok,ProcDetails=#proc{},[]} = crashdump_viewer:proc_details(Pid),
+ io:format(" process details ok",[]),
+
+ #proc{dict=Dict} = ProcDetails,
+ %% io:format("~p\n", [Dict]),
+ Pts = crashdump_helper:create_persistent_terms(),
+ Pts = proplists:get_value(pts,Dict),
+ io:format(" persistent terms ok",[]),
+ ok;
_ ->
ok
end,
@@ -674,14 +698,16 @@ do_create_dumps(DataDir,Rel) ->
end,
case Rel of
current ->
- CD3 = dump_with_args(DataDir,Rel,"instr","+Mim true"),
+ CD3 = dump_with_args(DataDir,Rel,"instr","+Muatags true"),
CD4 = dump_with_strange_module_name(DataDir,Rel,"strangemodname"),
CD5 = dump_with_size_limit_reached(DataDir,Rel,"trunc_bytes"),
CD6 = dump_with_unicode_atoms(DataDir,Rel,"unicode"),
CD7 = dump_with_maps(DataDir,Rel,"maps"),
+ CD8 = dump_with_persistent_terms(DataDir,Rel,"persistent_terms"),
TruncDumpMod = truncate_dump_mod(CD1),
TruncatedDumpsBinary = truncate_dump_binary(CD1),
- {[CD1,CD2,CD3,CD4,CD5,CD6,CD7,TruncDumpMod|TruncatedDumpsBinary],
+ {[CD1,CD2,CD3,CD4,CD5,CD6,CD7,CD8,
+ TruncDumpMod|TruncatedDumpsBinary],
DosDump};
_ ->
{[CD1,CD2], DosDump}
@@ -850,6 +876,16 @@ dump_with_maps(DataDir,Rel,DumpName) ->
?t:stop_node(n1),
CD.
+dump_with_persistent_terms(DataDir,Rel,DumpName) ->
+ Opt = rel_opt(Rel),
+ Pz = "-pz \"" ++ filename:dirname(code:which(?MODULE)) ++ "\"",
+ PzOpt = [{args,Pz}],
+ {ok,N1} = ?t:start_node(n1,peer,Opt ++ PzOpt),
+ {ok,_Pid} = rpc:call(N1,crashdump_helper,dump_persistent_terms,[]),
+ CD = dump(N1,DataDir,Rel,DumpName),
+ ?t:stop_node(n1),
+ CD.
+
dump(Node,DataDir,Rel,DumpName) ->
Crashdump = filename:join(DataDir, dump_prefix(Rel)++DumpName),
rpc:call(Node,os,putenv,["ERL_CRASH_DUMP",Crashdump]),
diff --git a/lib/observer/test/crashdump_viewer_SUITE_data/old_format.dump b/lib/observer/test/crashdump_viewer_SUITE_data/old_format.dump
index 2c8944fa9d..0b30fdf2f1 100644
--- a/lib/observer/test/crashdump_viewer_SUITE_data/old_format.dump
+++ b/lib/observer/test/crashdump_viewer_SUITE_data/old_format.dump
@@ -10,7 +10,7 @@ Compiled on Wed Dec 4 11:11:21 2002
Process Information
--------------------------------------------------
<0.0.0> Waiting. Registered as: init
-Spawned as: otp_ring0:start/2
+Spawned as: erl_init:start/2
Message buffer data: 4 words
Link list: [<0.5.0>,<0.4.0>,<0.2.0>]
Reductions 3125 stack+heap 610 old_heap_sz=233
@@ -68,7 +68,7 @@ y(3) [gen_event,<0.1.0>,<0.1.0>,{local,error_logger},[],[],[]]
Spawned as: proc_lib:init_p/5
Message buffer data: 4 words
Link list: [<0.7.0>,<0.0.0>]
-Dictionary: [{'$initial_call',{gen,init_it,[gen_server,<0.1.0>,<0.1.0>,{local,application_controller},application_controller,{application,kernel,[{description,"ERTS CXC 138 10"},{vsn,"2.6.3.15"},{id,[]},{modules,[application,application_controller,application_master,application_starter,auth,code,code_aux,code_server,code_server_int,dist_util,erl_boot_server,erl_distribution,erl_open_port,erl_prim_loader,erl_reply,erlang,error_handler,error_logger,file,global,global_group,global_search,group,heart,inet6_tcp,inet6_tcp_dist,inet6_udp,inet_config,inet_hosts,inet_gethost_native,inet_tcp_dist,otp_pre_init,init,kernel,kernel_config,net,net_adm,net_kernel,os,ram_file,rpc,user,user_drv,user_sup,disk_log,disk_log_1,disk_log_server,disk_log_sup,dist_ac,erl_atom_cache,erl_ddll,erl_epmd,erl_external,erts_debug,fixtable_server,gen_tcp,gen_udp,prim_inet,inet,inet_db,inet_dns,inet_parse,inet_res,inet_tcp,inet_udp,pg2,seq_trace,socks5,socks5_auth,socks5_tcp,socks5_udp,wrap_log_reader,otp_ring0]},{registered,[application_controller,erl_reply,auth,boot_server,code_server,disk_log_server,disk_log_sup,erl_prim_loader,error_logger,file_server,fixtable_server,global_group,global_name_server,heart,init,kernel_config,kernel_sup,net_kernel,net_sup,rex,user,os_server,ddll_server,erl_epmd,inet_db,pg2]},{applications,[]},{included_applications,[]},{env,[{error_logger,tty}]},{start_phases,undefined},{maxT,infinity},{maxP,infinity},{mod,{kernel,[]}}]},[]]}},{'$ancestors',[<0.1.0>]}]
+Dictionary: [{'$initial_call',{gen,init_it,[gen_server,<0.1.0>,<0.1.0>,{local,application_controller},application_controller,{application,kernel,[{description,"ERTS CXC 138 10"},{vsn,"2.6.3.15"},{id,[]},{modules,[application,application_controller,application_master,application_starter,auth,code,code_aux,code_server,code_server_int,dist_util,erl_boot_server,erl_distribution,erl_open_port,erl_prim_loader,erl_reply,erlang,error_handler,error_logger,file,global,global_group,global_search,group,heart,inet6_tcp,inet6_tcp_dist,inet6_udp,inet_config,inet_hosts,inet_gethost_native,inet_tcp_dist,otp_pre_init,init,kernel,kernel_config,net,net_adm,net_kernel,os,ram_file,rpc,user,user_drv,user_sup,disk_log,disk_log_1,disk_log_server,disk_log_sup,dist_ac,erl_atom_cache,erl_ddll,erl_epmd,erl_external,erts_debug,fixtable_server,gen_tcp,gen_udp,prim_inet,inet,inet_db,inet_dns,inet_parse,inet_res,inet_tcp,inet_udp,pg2,seq_trace,socks5,socks5_auth,socks5_tcp,socks5_udp,wrap_log_reader,erl_init]},{registered,[application_controller,erl_reply,auth,boot_server,code_server,disk_log_server,disk_log_sup,erl_prim_loader,error_logger,file_server,fixtable_server,global_group,global_name_server,heart,init,kernel_config,kernel_sup,net_kernel,net_sup,rex,user,os_server,ddll_server,erl_epmd,inet_db,pg2]},{applications,[]},{included_applications,[]},{env,[{error_logger,tty}]},{start_phases,undefined},{maxT,infinity},{maxP,infinity},{mod,{kernel,[]}}]},[]]}},{'$ancestors',[<0.1.0>]}]
Reductions 527 stack+heap 1597 old_heap_sz=0
Heap unused=833 OldHeap unused=0
Stack dump:
@@ -88,13 +88,13 @@ y(5) <0.1.0>
y(0) Catch 0x33480C (proc_lib:init_p/5 + 164)
y(1) gen
y(2) init_it
-y(3) [gen_server,<0.1.0>,<0.1.0>,{local,application_controller},application_controller,{application,kernel,[{description,"ERTS CXC 138 10"},{vsn,"2.6.3.15"},{id,[]},{modules,[application,application_controller,application_master,application_starter,auth,code,code_aux,code_server,code_server_int,dist_util,erl_boot_server,erl_distribution,erl_open_port,erl_prim_loader,erl_reply,erlang,error_handler,error_logger,file,global,global_group,global_search,group,heart,inet6_tcp,inet6_tcp_dist,inet6_udp,inet_config,inet_hosts,inet_gethost_native,inet_tcp_dist,otp_pre_init,init,kernel,kernel_config,net,net_adm,net_kernel,os,ram_file,rpc,user,user_drv,user_sup,disk_log,disk_log_1,disk_log_server,disk_log_sup,dist_ac,erl_atom_cache,erl_ddll,erl_epmd,erl_external,erts_debug,fixtable_server,gen_tcp,gen_udp,prim_inet,inet,inet_db,inet_dns,inet_parse,inet_res,inet_tcp,inet_udp,pg2,seq_trace,socks5,socks5_auth,socks5_tcp,socks5_udp,wrap_log_reader,otp_ring0]},{registered,[application_controller,erl_reply,auth,boot_server,code_server,disk_log_server,disk_log_sup,erl_prim_loader,error_logger,file_server,fixtable_server,global_group,global_name_server,heart,init,kernel_config,kernel_sup,net_kernel,net_sup,rex,user,os_server,ddll_server,erl_epmd,inet_db,pg2]},{applications,[]},{included_applications,[]},{env,[{error_logger,tty}]},{start_phases,undefined},{maxT,infinity},{maxP,infinity},{mod,{kernel,[]}}]},[]]
+y(3) [gen_server,<0.1.0>,<0.1.0>,{local,application_controller},application_controller,{application,kernel,[{description,"ERTS CXC 138 10"},{vsn,"2.6.3.15"},{id,[]},{modules,[application,application_controller,application_master,application_starter,auth,code,code_aux,code_server,code_server_int,dist_util,erl_boot_server,erl_distribution,erl_open_port,erl_prim_loader,erl_reply,erlang,error_handler,error_logger,file,global,global_group,global_search,group,heart,inet6_tcp,inet6_tcp_dist,inet6_udp,inet_config,inet_hosts,inet_gethost_native,inet_tcp_dist,otp_pre_init,init,kernel,kernel_config,net,net_adm,net_kernel,os,ram_file,rpc,user,user_drv,user_sup,disk_log,disk_log_1,disk_log_server,disk_log_sup,dist_ac,erl_atom_cache,erl_ddll,erl_epmd,erl_external,erts_debug,fixtable_server,gen_tcp,gen_udp,prim_inet,inet,inet_db,inet_dns,inet_parse,inet_res,inet_tcp,inet_udp,pg2,seq_trace,socks5,socks5_auth,socks5_tcp,socks5_udp,wrap_log_reader,erl_init]},{registered,[application_controller,erl_reply,auth,boot_server,code_server,disk_log_server,disk_log_sup,erl_prim_loader,error_logger,file_server,fixtable_server,global_group,global_name_server,heart,init,kernel_config,kernel_sup,net_kernel,net_sup,rex,user,os_server,ddll_server,erl_epmd,inet_db,pg2]},{applications,[]},{included_applications,[]},{env,[{error_logger,tty}]},{start_phases,undefined},{maxT,infinity},{maxP,infinity},{mod,{kernel,[]}}]},[]]
--------------------------------------------------
<0.7.0> Waiting.
Spawned as: proc_lib:init_p/5
Message buffer data: 0 words
Link list: [<0.8.0>,<0.5.0>]
-Dictionary: [{'$initial_call',{application_master,init,[<0.5.0>,<0.6.0>,{appl_data,kernel,[application_controller,erl_reply,auth,boot_server,code_server,disk_log_server,disk_log_sup,erl_prim_loader,error_logger,file_server,fixtable_server,global_group,global_name_server,heart,init,kernel_config,kernel_sup,net_kernel,net_sup,rex,user,os_server,ddll_server,erl_epmd,inet_db,pg2],undefined,{kernel,[]},[application,application_controller,application_master,application_starter,auth,code,code_aux,code_server,code_server_int,dist_util,erl_boot_server,erl_distribution,erl_open_port,erl_prim_loader,erl_reply,erlang,error_handler,error_logger,file,global,global_group,global_search,group,heart,inet6_tcp,inet6_tcp_dist,inet6_udp,inet_config,inet_hosts,inet_gethost_native,inet_tcp_dist,otp_pre_init,init,kernel,kernel_config,net,net_adm,net_kernel,os,ram_file,rpc,user,user_drv,user_sup,disk_log,disk_log_1,disk_log_server,disk_log_sup,dist_ac,erl_atom_cache,erl_ddll,erl_epmd,erl_external,erts_debug,fixtable_server,gen_tcp,gen_udp,prim_inet,inet,inet_db,inet_dns,inet_parse,inet_res,inet_tcp,inet_udp,pg2,seq_trace,socks5,socks5_auth,socks5_tcp,socks5_udp,wrap_log_reader,otp_ring0],[],infinity,infinity},normal]}},{'$ancestors',[<0.6.0>]}]
+Dictionary: [{'$initial_call',{application_master,init,[<0.5.0>,<0.6.0>,{appl_data,kernel,[application_controller,erl_reply,auth,boot_server,code_server,disk_log_server,disk_log_sup,erl_prim_loader,error_logger,file_server,fixtable_server,global_group,global_name_server,heart,init,kernel_config,kernel_sup,net_kernel,net_sup,rex,user,os_server,ddll_server,erl_epmd,inet_db,pg2],undefined,{kernel,[]},[application,application_controller,application_master,application_starter,auth,code,code_aux,code_server,code_server_int,dist_util,erl_boot_server,erl_distribution,erl_open_port,erl_prim_loader,erl_reply,erlang,error_handler,error_logger,file,global,global_group,global_search,group,heart,inet6_tcp,inet6_tcp_dist,inet6_udp,inet_config,inet_hosts,inet_gethost_native,inet_tcp_dist,otp_pre_init,init,kernel,kernel_config,net,net_adm,net_kernel,os,ram_file,rpc,user,user_drv,user_sup,disk_log,disk_log_1,disk_log_server,disk_log_sup,dist_ac,erl_atom_cache,erl_ddll,erl_epmd,erl_external,erts_debug,fixtable_server,gen_tcp,gen_udp,prim_inet,inet,inet_db,inet_dns,inet_parse,inet_res,inet_tcp,inet_udp,pg2,seq_trace,socks5,socks5_auth,socks5_tcp,socks5_udp,wrap_log_reader,erl_init],[],infinity,infinity},normal]}},{'$ancestors',[<0.6.0>]}]
Reductions 45 stack+heap 377 old_heap_sz=377
Heap unused=306 OldHeap unused=377
Stack dump:
@@ -103,14 +103,14 @@ cp = 0x33480c (proc_lib:init_p/5 + 164)
arity = 0
347174 Return addr 0x33480C (proc_lib:init_p/5 + 164)
-y(0) {state,<0.8.0>,{appl_data,kernel,[application_controller,erl_reply,auth,boot_server,code_server,disk_log_server,disk_log_sup,erl_prim_loader,error_logger,file_server,fixtable_server,global_group,global_name_server,heart,init,kernel_config,kernel_sup,net_kernel,net_sup,rex,user,os_server,ddll_server,erl_epmd,inet_db,pg2],undefined,{kernel,[]},[application,application_controller,application_master,application_starter,auth,code,code_aux,code_server,code_server_int,dist_util,erl_boot_server,erl_distribution,erl_open_port,erl_prim_loader,erl_reply,erlang,error_handler,error_logger,file,global,global_group,global_search,group,heart,inet6_tcp,inet6_tcp_dist,inet6_udp,inet_config,inet_hosts,inet_gethost_native,inet_tcp_dist,otp_pre_init,init,kernel,kernel_config,net,net_adm,net_kernel,os,ram_file,rpc,user,user_drv,user_sup,disk_log,disk_log_1,disk_log_server,disk_log_sup,dist_ac,erl_atom_cache,erl_ddll,erl_epmd,erl_external,erts_debug,fixtable_server,gen_tcp,gen_udp,prim_inet,inet,inet_db,inet_dns,inet_parse,inet_res,inet_tcp,inet_udp,pg2,seq_trace,socks5,socks5_auth,socks5_tcp,socks5_udp,wrap_log_reader,otp_ring0],[],infinity,infinity},[],0,<0.0.0>}
+y(0) {state,<0.8.0>,{appl_data,kernel,[application_controller,erl_reply,auth,boot_server,code_server,disk_log_server,disk_log_sup,erl_prim_loader,error_logger,file_server,fixtable_server,global_group,global_name_server,heart,init,kernel_config,kernel_sup,net_kernel,net_sup,rex,user,os_server,ddll_server,erl_epmd,inet_db,pg2],undefined,{kernel,[]},[application,application_controller,application_master,application_starter,auth,code,code_aux,code_server,code_server_int,dist_util,erl_boot_server,erl_distribution,erl_open_port,erl_prim_loader,erl_reply,erlang,error_handler,error_logger,file,global,global_group,global_search,group,heart,inet6_tcp,inet6_tcp_dist,inet6_udp,inet_config,inet_hosts,inet_gethost_native,inet_tcp_dist,otp_pre_init,init,kernel,kernel_config,net,net_adm,net_kernel,os,ram_file,rpc,user,user_drv,user_sup,disk_log,disk_log_1,disk_log_server,disk_log_sup,dist_ac,erl_atom_cache,erl_ddll,erl_epmd,erl_external,erts_debug,fixtable_server,gen_tcp,gen_udp,prim_inet,inet,inet_db,inet_dns,inet_parse,inet_res,inet_tcp,inet_udp,pg2,seq_trace,socks5,socks5_auth,socks5_tcp,socks5_udp,wrap_log_reader,erl_init],[],infinity,infinity},[],0,<0.0.0>}
y(1) <0.5.0>
347180 Return addr 0xFCEC8 (<terminate process normally>)
y(0) Catch 0x33480C (proc_lib:init_p/5 + 164)
y(1) application_master
y(2) init
-y(3) [<0.5.0>,<0.6.0>,{appl_data,kernel,[application_controller,erl_reply,auth,boot_server,code_server,disk_log_server,disk_log_sup,erl_prim_loader,error_logger,file_server,fixtable_server,global_group,global_name_server,heart,init,kernel_config,kernel_sup,net_kernel,net_sup,rex,user,os_server,ddll_server,erl_epmd,inet_db,pg2],undefined,{kernel,[]},[application,application_controller,application_master,application_starter,auth,code,code_aux,code_server,code_server_int,dist_util,erl_boot_server,erl_distribution,erl_open_port,erl_prim_loader,erl_reply,erlang,error_handler,error_logger,file,global,global_group,global_search,group,heart,inet6_tcp,inet6_tcp_dist,inet6_udp,inet_config,inet_hosts,inet_gethost_native,inet_tcp_dist,otp_pre_init,init,kernel,kernel_config,net,net_adm,net_kernel,os,ram_file,rpc,user,user_drv,user_sup,disk_log,disk_log_1,disk_log_server,disk_log_sup,dist_ac,erl_atom_cache,erl_ddll,erl_epmd,erl_external,erts_debug,fixtable_server,gen_tcp,gen_udp,prim_inet,inet,inet_db,inet_dns,inet_parse,inet_res,inet_tcp,inet_udp,pg2,seq_trace,socks5,socks5_auth,socks5_tcp,socks5_udp,wrap_log_reader,otp_ring0],[],infinity,infinity},normal]
+y(3) [<0.5.0>,<0.6.0>,{appl_data,kernel,[application_controller,erl_reply,auth,boot_server,code_server,disk_log_server,disk_log_sup,erl_prim_loader,error_logger,file_server,fixtable_server,global_group,global_name_server,heart,init,kernel_config,kernel_sup,net_kernel,net_sup,rex,user,os_server,ddll_server,erl_epmd,inet_db,pg2],undefined,{kernel,[]},[application,application_controller,application_master,application_starter,auth,code,code_aux,code_server,code_server_int,dist_util,erl_boot_server,erl_distribution,erl_open_port,erl_prim_loader,erl_reply,erlang,error_handler,error_logger,file,global,global_group,global_search,group,heart,inet6_tcp,inet6_tcp_dist,inet6_udp,inet_config,inet_hosts,inet_gethost_native,inet_tcp_dist,otp_pre_init,init,kernel,kernel_config,net,net_adm,net_kernel,os,ram_file,rpc,user,user_drv,user_sup,disk_log,disk_log_1,disk_log_server,disk_log_sup,dist_ac,erl_atom_cache,erl_ddll,erl_epmd,erl_external,erts_debug,fixtable_server,gen_tcp,gen_udp,prim_inet,inet,inet_db,inet_dns,inet_parse,inet_res,inet_tcp,inet_udp,pg2,seq_trace,socks5,socks5_auth,socks5_tcp,socks5_udp,wrap_log_reader,erl_init],[],infinity,infinity},normal]
--------------------------------------------------
<0.8.0> Waiting.
Spawned as: application_master:start_it/4
@@ -652,7 +652,7 @@ Not alive
Loaded Modules Information
--------------------------------------------------
-otp_ring0 448
+erl_init 448
init 28000
prim_inet 34800
erl_prim_loader 14187
@@ -1202,7 +1202,7 @@ udp_error
inet_async
inet_reply
empty_out_q
-otp_ring0
+erl_init
boot
init
run
@@ -1285,7 +1285,7 @@ sleep
start_prim_loader
erl_prim_loader
set_path
-'can not start loader'
+'cannot start loader'
add_to_kernel
prim_load_flags
'-loader'
@@ -1304,7 +1304,7 @@ path_flags
'-pz'
get_boot
not_found
-'can not get bootfile'
+'cannot get bootfile'
'bootfile format error'
get_file
script
@@ -1349,7 +1349,7 @@ extension
'-boot/1-fun-0-'
'-bs2ss/1-fun-0-'
'-bs2as/1-fun-0-'
-'can not load'
+'cannot load'
'unexpected command in bootfile'
prim_inet
open
@@ -3071,7 +3071,7 @@ change_group
change_time
master
start_slave
-'can not get remote filer '
+'cannot get remote filer '
start_relay
relay
'Port controlling ~w terminated in file_server'
diff --git a/lib/observer/test/observer_SUITE.erl b/lib/observer/test/observer_SUITE.erl
index fd4f93f662..7d54bb9b3b 100644
--- a/lib/observer/test/observer_SUITE.erl
+++ b/lib/observer/test/observer_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -41,7 +41,8 @@
%% Default timetrap timeout (set in init_per_testcase)
-define(default_timeout, ?t:minutes(2)).
-suite() -> [{ct_hooks,[ts_install_cth]}].
+suite() -> [{timetrap, {minutes, 5}},
+ {ct_hooks,[ts_install_cth]}].
all() ->
[app_file, appup_file, {group, gui}].
@@ -301,7 +302,7 @@ table_win(Config) when is_list(Config) ->
Notebook = setup_whitebox_testing(),
Parent = get_top_level_parent(Notebook),
TObj = observer_tv_table:start_link(Parent, [{node,node()}, {type,ets}, {table,#tab{name=foo, id=Table}}]),
- %% Modal can not test edit..
+ %% Modal cannot test edit..
%% TPid = wx_object:get_pid(TObj),
%% TPid ! #wx{event=#wxList{type=command_list_item_activated, itemIndex=12}},
timer:sleep(3000),
diff --git a/lib/observer/test/ttb_SUITE.erl b/lib/observer/test/ttb_SUITE.erl
index e8c2f9e37d..33133dd78d 100644
--- a/lib/observer/test/ttb_SUITE.erl
+++ b/lib/observer/test/ttb_SUITE.erl
@@ -2,7 +2,7 @@
%% %CopyrightBegin%
%%
%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -222,7 +222,7 @@ file_fetch(Config) when is_list(Config) ->
?line ?t:capture_stop(),
?line [StoreString] = ?t:capture_get(),
?line UploadDir =
- lists:last(string:tokens(lists:flatten(StoreString),"$ \n")),
+ lists:last(string:lexemes(lists:flatten(StoreString),"$ \n")),
%% check that files are no longer in original directories...
?line ok = check_gone(ThisDir,atom_to_list(Node)++"-file_fetch"),
@@ -1035,8 +1035,8 @@ logfile_name_in_fetch_dir(Config) when is_list(Config) ->
?line {ServerNode, ClientNode} = start_client_and_server(),
?line begin_trace(ServerNode, ClientNode, {local, ?FNAME}),
?line {_,Dir} = ttb:stop([return_fetch_dir]),
- ?line P1 = lists:nth(3, string:tokens(filename:basename(Dir), "_")),
- ?line P2 = hd(string:tokens(P1, "-")),
+ ?line P1 = lists:nth(3, string:lexemes(filename:basename(Dir), "_")),
+ ?line P2 = hd(string:lexemes(P1, "-")),
?line _File = P2.
logfile_name_in_fetch_dir(cleanup,_Config) ->
?line stop_client_and_server().
diff --git a/lib/observer/vsn.mk b/lib/observer/vsn.mk
index 74a6db768e..c16c43f942 100644
--- a/lib/observer/vsn.mk
+++ b/lib/observer/vsn.mk
@@ -1 +1 @@
-OBSERVER_VSN = 2.7
+OBSERVER_VSN = 2.9.1
diff --git a/lib/odbc/c_src/Makefile.in b/lib/odbc/c_src/Makefile.in
index 784e73c47e..294d832797 100644
--- a/lib/odbc/c_src/Makefile.in
+++ b/lib/odbc/c_src/Makefile.in
@@ -52,7 +52,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/odbc-$(VSN)
# Target Specs
# ----------------------------------------------------
EI_ROOT = $(ERL_TOP)/lib/erl_interface
-EI_INCLUDE = -I$(EI_ROOT)/include
+EI_INCLUDE = -I$(EI_ROOT)/include -I$(EI_ROOT)/include/$(TARGET)
ifeq ($(findstring win32,$(TARGET)),win32)
EI_LIB = -lerl_interface_md -lei_md
ENTRY_OBJ=$(ERL_TOP)/erts/obj/$(TARGET)/port_entry.o
diff --git a/lib/odbc/c_src/odbcserver.c b/lib/odbc/c_src/odbcserver.c
index 8c799f6ff1..fb4f61417e 100644
--- a/lib/odbc/c_src/odbcserver.c
+++ b/lib/odbc/c_src/odbcserver.c
@@ -2749,6 +2749,11 @@ static diagnos get_diagnos(SQLSMALLINT handleType, SQLHANDLE handle, Boolean ext
errmsg_buffer_size = errmsg_buffer_size - errmsg_size;
acc_errmsg_size = acc_errmsg_size + errmsg_size;
current_errmsg_pos = current_errmsg_pos + errmsg_size;
+ } else if(result == SQL_SUCCESS_WITH_INFO && errmsg_size >= errmsg_buffer_size) {
+ memcpy(diagnos.sqlState, current_sql_state, SQL_STATE_SIZE);
+ diagnos.nativeError = nativeError;
+ acc_errmsg_size = errmsg_buffer_size;
+ break;
} else {
break;
}
diff --git a/lib/odbc/configure.in b/lib/odbc/configure.in
index 2dec6e5abf..c5cf2786ca 100644
--- a/lib/odbc/configure.in
+++ b/lib/odbc/configure.in
@@ -21,12 +21,6 @@ dnl
dnl define([AC_CACHE_LOAD], )dnl
dnl define([AC_CACHE_SAVE], )dnl
-if test "x$no_recursion" != "xyes" -a "x$OVERRIDE_CONFIG_CACHE" = "x"; then
- # We do not want to use a common cache!
- cache_file=/dev/null
-fi
-
-
dnl Process this file with autoconf to produce a configure script.
AC_INIT(c_src/odbcserver.c)
diff --git a/lib/odbc/doc/src/Makefile b/lib/odbc/doc/src/Makefile
index b3f93a7e9c..a6311ceede 100644
--- a/lib/odbc/doc/src/Makefile
+++ b/lib/odbc/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2017. All Rights Reserved.
+# Copyright Ericsson AB 1999-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -101,6 +101,7 @@ html: gifs $(HTML_REF_MAN_FILE)
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/lib/odbc/doc/src/databases.xml b/lib/odbc/doc/src/databases.xml
index a060f87e46..614c327a46 100644
--- a/lib/odbc/doc/src/databases.xml
+++ b/lib/odbc/doc/src/databases.xml
@@ -65,7 +65,7 @@
<p>Another obstacle is that some drivers do not support scrollable
cursors which has the effect that the only way to traverse the
result set is sequentially, with next, from the first row to the
- last, and once you pass a row you can not go back. This means
+ last, and once you pass a row you cannot go back. This means
that some functions in the interface will not work together with
certain drivers. A similar problem is that not all drivers
support "row count" for select queries, hence resulting in that
diff --git a/lib/odbc/doc/src/error_handling.xml b/lib/odbc/doc/src/error_handling.xml
index 4c80cff12f..8d794d2c99 100644
--- a/lib/odbc/doc/src/error_handling.xml
+++ b/lib/odbc/doc/src/error_handling.xml
@@ -138,7 +138,7 @@
should be run through the erlang port was not compiled for
your platform.</item>
<item>Errors discovered by the ODBC driver - If calls to the
- ODBC-driver fails due to circumstances that can not be
+ ODBC-driver fails due to circumstances that cannot be
controlled by the Erlang ODBC application programmer, an
error string will be dug up from the driver. This string
will be the <c>Reason</c> in the <c>{error, Reason} </c>
diff --git a/lib/odbc/doc/src/getting_started.xml b/lib/odbc/doc/src/getting_started.xml
index f2ff8b8993..b27754ff22 100644
--- a/lib/odbc/doc/src/getting_started.xml
+++ b/lib/odbc/doc/src/getting_started.xml
@@ -50,7 +50,7 @@
and paths to appropriate values. This may differ a lot
between different os's, databases and ODBC drivers. This
is a configuration problem related to the third party product
- and hence we can not give you a standard solution in this guide.</item>
+ and hence we cannot give you a standard solution in this guide.</item>
<item>The Erlang ODBC application consists of both <c>Erlang</c>
and <c>C</c> code. The <c>C</c> code is delivered as a
precompiled executable for windows, solaris and linux (SLES10) in the commercial
diff --git a/lib/odbc/doc/src/notes.xml b/lib/odbc/doc/src/notes.xml
index 2aa55ca99c..8d708162e4 100644
--- a/lib/odbc/doc/src/notes.xml
+++ b/lib/odbc/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2016</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,7 +32,53 @@
<p>This document describes the changes made to the odbc application.
</p>
- <section><title>ODBC 2.12.1</title>
+ <section><title>ODBC 2.12.4</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Minor adjustments made to build system for parallel
+ configure.</p>
+ <p>
+ Own Id: OTP-15340 Aux Id: OTP-14625 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>ODBC 2.12.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Enhance error handling to avoid stack corruption</p>
+ <p>
+ Own Id: OTP-15667 Aux Id: ERL-808, PR-2065 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>ODBC 2.12.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>ODBC 2.12.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/odbc/doc/src/notes_history.xml b/lib/odbc/doc/src/notes_history.xml
index 22a92f67cd..d0c0a472e7 100644
--- a/lib/odbc/doc/src/notes_history.xml
+++ b/lib/odbc/doc/src/notes_history.xml
@@ -63,7 +63,7 @@
<list type="bulleted">
<item>
<p>The erlang odbc process will now die normally if a
- connection can not be established. No connection no
+ connection cannot be established. No connection no
process it is expected. And as the client has already
received the error message that would be the reason with
which the erlang process would be stopped, the supervisor
@@ -193,7 +193,7 @@
</item>
<item>
<p>The erlang odbc process will now die normally if a
- connection can not be established. No connection no
+ connection cannot be established. No connection no
process it is expected. And as the client has already
received the error message that would be the reason with
which the erlang process would be stopped, the supervisor
diff --git a/lib/odbc/doc/src/odbc.xml b/lib/odbc/doc/src/odbc.xml
index 4bb1f035f9..1a3063e6ce 100644
--- a/lib/odbc/doc/src/odbc.xml
+++ b/lib/odbc/doc/src/odbc.xml
@@ -29,7 +29,7 @@
<date></date>
<rev></rev>
</header>
- <module>odbc</module>
+ <module since="">odbc</module>
<modulesummary>Erlang ODBC application</modulesummary>
<description>
<p>This application provides an Erlang interface to communicate
@@ -130,8 +130,8 @@
</section>
<funcs>
<func>
- <name>commit(Ref, CommitMode) -></name>
- <name>commit(Ref, CommitMode, TimeOut) -> ok | {error, Reason} </name>
+ <name since="">commit(Ref, CommitMode) -></name>
+ <name since="">commit(Ref, CommitMode, TimeOut) -> ok | {error, Reason} </name>
<fsummary>Commits or rollbacks a transaction. </fsummary>
<type>
<v>Ref = connection_reference() </v>
@@ -145,7 +145,7 @@
</desc>
</func>
<func>
- <name>connect(ConnectStr, Options) -> {ok, Ref} | {error, Reason} </name>
+ <name since="">connect(ConnectStr, Options) -> {ok, Ref} | {error, Reason} </name>
<fsummary>Opens a connection to the database. </fsummary>
<type>
<v>ConnectStr = string()</v>
@@ -236,7 +236,7 @@
</desc>
</func>
<func>
- <name>disconnect(Ref) -> ok | {error, Reason} </name>
+ <name since="">disconnect(Ref) -> ok | {error, Reason} </name>
<fsummary>Closes a connection to a database. </fsummary>
<type>
<v>Ref = connection_reference()</v>
@@ -246,7 +246,7 @@
<p>Closes a connection to a database. This will also
terminate all processes that may have been spawned
when the connection was opened. This call will always succeed.
- If the connection can not be disconnected gracefully it will
+ If the connection cannot be disconnected gracefully it will
be brutally killed. However you may receive an error message
as result if you try to disconnect a connection started by another
process.
@@ -255,8 +255,8 @@
</desc>
</func>
<func>
- <name>describe_table(Ref, Table) -> </name>
- <name>describe_table(Ref, Table, Timeout) -> {ok, Description} | {error, Reason} </name>
+ <name since="">describe_table(Ref, Table) -> </name>
+ <name since="">describe_table(Ref, Table, Timeout) -> {ok, Description} | {error, Reason} </name>
<fsummary>Queries the database to find out the data types of the columns of the table <c>Table</c>. </fsummary>
<type>
<v>Ref = connection_reference()</v>
@@ -271,8 +271,8 @@
</desc>
</func>
<func>
- <name>first(Ref) -></name>
- <name>first(Ref, Timeout) -> {selected, ColNames, Rows} | {error, Reason} </name>
+ <name since="">first(Ref) -></name>
+ <name since="">first(Ref, Timeout) -> {selected, ColNames, Rows} | {error, Reason} </name>
<fsummary>Returns the first row of the result set and positions a cursor at this row.</fsummary>
<type>
<v>Ref = connection_reference()</v>
@@ -287,8 +287,8 @@
</desc>
</func>
<func>
- <name>last(Ref) -></name>
- <name>last(Ref, TimeOut) -> {selected, ColNames, Rows} | {error, Reason} </name>
+ <name since="">last(Ref) -></name>
+ <name since="">last(Ref, TimeOut) -> {selected, ColNames, Rows} | {error, Reason} </name>
<fsummary>Returns the last row of the result set and positions a cursor at this row. </fsummary>
<type>
<v>Ref = connection_reference()</v>
@@ -303,8 +303,8 @@
</desc>
</func>
<func>
- <name>next(Ref) -> </name>
- <name>next(Ref, TimeOut) -> {selected, ColNames, Rows} | {error, Reason} </name>
+ <name since="">next(Ref) -> </name>
+ <name since="">next(Ref, TimeOut) -> {selected, ColNames, Rows} | {error, Reason} </name>
<fsummary>Returns the next row of the result set relative the current cursor position and positions the cursor at this row. </fsummary>
<type>
<v>Ref = connection_reference()</v>
@@ -325,8 +325,8 @@
</desc>
</func>
<func>
- <name>param_query(Ref, SQLQuery, Params) -> </name>
- <name>param_query(Ref, SQLQuery, Params, TimeOut) -> ResultTuple | {error, Reason} </name>
+ <name since="">param_query(Ref, SQLQuery, Params) -> </name>
+ <name since="">param_query(Ref, SQLQuery, Params, TimeOut) -> ResultTuple | {error, Reason} </name>
<fsummary>Executes a parameterized SQL query.</fsummary>
<type>
<v>Ref = connection_reference()</v>
@@ -353,8 +353,8 @@
</desc>
</func>
<func>
- <name>prev(Ref) -> </name>
- <name>prev(ConnectionReference, TimeOut) -> {selected, ColNames, Rows} | {error, Reason} </name>
+ <name since="">prev(Ref) -> </name>
+ <name since="">prev(ConnectionReference, TimeOut) -> {selected, ColNames, Rows} | {error, Reason} </name>
<fsummary>Returns the previous row of the result set relative the current cursor position and positions the cursor at this row. </fsummary>
<type>
<v>Ref = connection_reference()</v>
@@ -371,8 +371,8 @@
</func>
<func>
- <name>start() -> </name>
- <name>start(Type) -> ok | {error, Reason}</name>
+ <name since="">start() -> </name>
+ <name since="">start(Type) -> ok | {error, Reason}</name>
<fsummary>Starts the odb application. </fsummary>
<type>
@@ -389,7 +389,7 @@
</func>
<func>
- <name>stop() -> ok </name>
+ <name since="">stop() -> ok </name>
<fsummary> Stops the odbc application.</fsummary>
<desc>
@@ -400,8 +400,8 @@
</func>
<func>
- <name>sql_query(Ref, SQLQuery) -> </name>
- <name>sql_query(Ref, SQLQuery, TimeOut) -> ResultTuple | [ResultTuple] |{error, Reason}</name>
+ <name since="">sql_query(Ref, SQLQuery) -> </name>
+ <name since="">sql_query(Ref, SQLQuery, TimeOut) -> ResultTuple | [ResultTuple] |{error, Reason}</name>
<fsummary>Executes a SQL query or a batch of SQL queries. If it is a SELECT query the result set is returned, on the format<c>{selected, ColNames, Rows}</c>. For other query types the tuple <c>{updated, NRows}</c>is returned, and for batched queries, if the driver supports them, this function can also return a list of result tuples.</fsummary>
<type>
<v>Ref = connection_reference()</v>
@@ -429,8 +429,8 @@
</desc>
</func>
<func>
- <name>select_count(Ref, SelectQuery) -> </name>
- <name>select_count(Ref, SelectQuery, TimeOut) -> {ok, NrRows} | {error, Reason} </name>
+ <name since="">select_count(Ref, SelectQuery) -> </name>
+ <name since="">select_count(Ref, SelectQuery, TimeOut) -> {ok, NrRows} | {error, Reason} </name>
<fsummary>Executes a SQL SELECT query and associates the result set with the connection. A cursor is positioned before the first row in the result set and the tuple <c>{ok, NrRows}</c>is returned. </fsummary>
<type>
<v>Ref = connection_reference()</v>
@@ -453,8 +453,8 @@
</desc>
</func>
<func>
- <name>select(Ref, Position, N) -></name>
- <name>select(Ref, Position, N, TimeOut) -> {selected, ColNames, Rows} | {error, Reason} </name>
+ <name since="">select(Ref, Position, N) -></name>
+ <name since="">select(Ref, Position, N, TimeOut) -> {selected, ColNames, Rows} | {error, Reason} </name>
<fsummary>Selects <c>N</c>consecutive rows of the result set.</fsummary>
<type>
<v>Ref = connection_reference()</v>
diff --git a/lib/odbc/test/odbc_connect_SUITE.erl b/lib/odbc/test/odbc_connect_SUITE.erl
index 261dfc6f20..94ca62b3fb 100644
--- a/lib/odbc/test/odbc_connect_SUITE.erl
+++ b/lib/odbc/test/odbc_connect_SUITE.erl
@@ -259,7 +259,7 @@ not_exist_db(_Config) ->
%%-------------------------------------------------------------------------
no_c_executable() ->
- [{doc,"Test what happens if the port-program can not be found"}].
+ [{doc,"Test what happens if the port-program cannot be found"}].
no_c_executable(_Config) ->
process_flag(trap_exit, true),
Dir = filename:nativename(filename:join(code:priv_dir(odbc),
diff --git a/lib/odbc/vsn.mk b/lib/odbc/vsn.mk
index 3f7677a71d..df6db09f2f 100644
--- a/lib/odbc/vsn.mk
+++ b/lib/odbc/vsn.mk
@@ -1 +1 @@
-ODBC_VSN = 2.12.1
+ODBC_VSN = 2.12.4
diff --git a/lib/orber/AUTHORS b/lib/orber/AUTHORS
deleted file mode 100644
index a77bdcf140..0000000000
--- a/lib/orber/AUTHORS
+++ /dev/null
@@ -1,8 +0,0 @@
-Original Authors:
-Lars Thorsen
-Per Danielsson
-Peter Lundell
-Niclas Eklund
-Babbis Xagorarakis
-
-Contributors:
diff --git a/lib/orber/COSS/CosNaming/CosNaming_BindingIterator_impl.erl b/lib/orber/COSS/CosNaming/CosNaming_BindingIterator_impl.erl
deleted file mode 100644
index 760c003f82..0000000000
--- a/lib/orber/COSS/CosNaming/CosNaming_BindingIterator_impl.erl
+++ /dev/null
@@ -1,94 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: CosNaming_BindingIterator_impl.erl
-%%
-%%-----------------------------------------------------------------
--module('CosNaming_BindingIterator_impl').
-
--include_lib("orber/include/corba.hrl").
--include("CosNaming.hrl").
--include("orber_cosnaming.hrl").
-
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([init/1, terminate/2, code_change/3]).
--export([next_one/1, next_n/2, destroy/1]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-%%-----------------------------------------------------------------
-%% External interface functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: init/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-init(State) ->
- {ok, State}.
-
-%%-----------------------------------------------------------------
-%% Func: terminate/2
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-terminate(_Reason, _State) ->
- ok.
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-next_one([]) ->
- NoBinding = #'CosNaming_Binding'{binding_name=[],
- binding_type=nobject},
- {reply, {false, NoBinding}, []};
-next_one([Binding]) ->
- {reply, {true, Binding}, []};
-next_one([Binding|Rest]) ->
- {reply, {true, Binding}, Rest}.
-
-next_n([], _) ->
- {reply, {false, []}, []};
-next_n(List, HowMany) ->
- {More, Acc, NewList} = split(List, HowMany, []),
- {reply, {More, Acc}, NewList}.
-
-split([], _, Acc) ->
- {false, Acc, []};
-split(Rest, 0, Acc) ->
- {true, Acc, Rest};
-split([H|T], N, Acc) ->
- split(T, N-1, [H|Acc]).
-
-
-destroy(OE_State) ->
- {stop, normal, ok, OE_State}.
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
diff --git a/lib/orber/COSS/CosNaming/CosNaming_NamingContextExt_impl.erl b/lib/orber/COSS/CosNaming/CosNaming_NamingContextExt_impl.erl
deleted file mode 100644
index 88049a509f..0000000000
--- a/lib/orber/COSS/CosNaming/CosNaming_NamingContextExt_impl.erl
+++ /dev/null
@@ -1,756 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2017. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: CosNaming_NamingContextExt_impl.erl
-%% Modified:
-%%
-%%-----------------------------------------------------------------
-%% README:
-%% (1)
-%%
-%%-----------------------------------------------------------------
--module('CosNaming_NamingContextExt_impl').
-
-%%----------------------------------------------------------------------
-%% Include files
-%%----------------------------------------------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
--include("CosNaming.hrl").
--include("CosNaming_NamingContext.hrl").
--include("CosNaming_NamingContextExt.hrl").
--include("orber_cosnaming.hrl").
-
-%%----------------------------------------------------------------------
-%% External exports
-%%----------------------------------------------------------------------
-%% Mandatory callbacks
--export([init/1,
- terminate/2,
- code_change/3]).
-
-%% Inherrit from CosNaming::NamingContext
--export([bind/4,
- rebind/4,
- bind_context/4,
- rebind_context/4,
- resolve/3,
- unbind/3,
- new_context/2,
- bind_new_context/3,
- list/3,
- destroy/2]).
-
-%% CosNaming::NamingContextExt
--export([to_string/3,
- to_name/3,
- to_url/4,
- resolve_str/3]).
-
-%%----------------------------------------------------------------------
-%% Internal exports
-%%----------------------------------------------------------------------
--export([dump/0,
- install/2]).
-
-%%----------------------------------------------------------------------
-%% Records
-%%----------------------------------------------------------------------
-
-%%----------------------------------------------------------------------
-%% Macros
-%%----------------------------------------------------------------------
-%% DEBUG INFO
--define(DEBUG_LEVEL, 5).
-
-%%======================================================================
-%% External functions
-%%======================================================================
-%%---------------------------------------------------------------------%
-%% Function : init/1
-%% Description: Initiates the server
-%% Returns : {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
-%%----------------------------------------------------------------------
-init([]) ->
- {ok, term_to_binary('undefined')};
-
-init(DBKey) ->
- _F = ?write_function(#orber_CosNaming{name_context=DBKey,
- nameindex=[]}),
- write_result(mnesia:transaction(_F)),
- {ok, DBKey}.
-
-%%---------------------------------------------------------------------%
-%% Function : terminate
-%% Description: Shutdown the server
-%% Returns : any (ignored by gen_server)
-%%----------------------------------------------------------------------
-terminate(_Reason, _State) ->
- ok.
-
-%%---------------------------------------------------------------------%
-%% Function : code_change
-%% Description: Convert process state when code is changed
-%% Returns : {ok, State}
-%%----------------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%---------------------------------------------------------------------%
-%% Function : install
-%% Arguments : Timeout - abort if timeout triggered.
-%% Options - mnesia options
-%% Description:
-%% Returns :
-%%----------------------------------------------------------------------
-install(Timeout, Options) ->
- %% Fetch a list of the defined tables to see if 'CosNaming' is defined.
- AllTabs = mnesia:system_info(tables),
- DB_tables_created =
- case lists:member('orber_CosNaming', AllTabs) of
- true ->
- case lists:member({local_content, true},
- Options) of
- true->
- mnesia:add_table_copy('orber_CosNaming',
- node(),
- ram_copies);
- _->
- mnesia:create_table('orber_CosNaming',[{attributes,
- record_info(fields,
- 'orber_CosNaming')}
- |Options])
- end;
- _ ->
- mnesia:create_table('orber_CosNaming',[{attributes,
- record_info(fields,
- 'orber_CosNaming')}
- |Options])
- end,
- Wait = mnesia:wait_for_tables(['orber_CosNaming'], Timeout),
- %% Check if any error has occured yet. If there are errors, return them.
-
- if
- DB_tables_created == {atomic, ok},
- Wait == ok ->
- _F = ?write_function(#orber_CosNaming{name_context=
- term_to_binary('undefined'),
- nameindex=[]}),
- write_result(mnesia:transaction(_F));
- true ->
- {error, [DB_tables_created, Wait]}
- end.
-
-
-%%----------------------------------------------------------------------
-%% Interface CosNaming::NamingContext
-%%----------------------------------------------------------------------
-%%----------------------------------------------------------------------
-%% Function : bind
-%% Arguments :
-%% Description:
-%% Returns :
-%%----------------------------------------------------------------------
-bind(OE_THIS, OE_State, [N], Obj) ->
- SubobjKey = corba:get_subobject_key(OE_THIS),
- _BF =
- fun() ->
- case mnesia:wread({orber_CosNaming, SubobjKey}) of
- [#orber_CosNaming{nameindex = X}] ->
- case lists:keysearch(N, 1, X) of
- {value, _} ->
- {'EXCEPTION', #'CosNaming_NamingContext_AlreadyBound'{}};
- false ->
- mnesia:write(#orber_CosNaming{name_context=SubobjKey,
- nameindex=[{N, nobject, Obj} | X]})
- end;
- Other ->
- orber:dbg("[~p] ~p:bind(~p, ~p);~n"
- "DB access returned ~p",
- [?LINE, ?MODULE, N, SubobjKey, Other], ?DEBUG_LEVEL),
- {'EXCEPTION', #'CosNaming_NamingContext_CannotProceed'{rest_of_name=[N],
- cxt=OE_THIS}}
- end
- end,
- case mnesia:transaction(_BF) of
- {atomic, {'EXCEPTION', E}} ->
- corba:raise(E);
- {atomic, ok} ->
- {reply, ok, OE_State};
- Other ->
- orber:dbg("[~p] ~p:bind(~p, ~p);~n"
- "DB transaction returned ~p",
- [?LINE, ?MODULE, N, SubobjKey, Other], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end;
-bind(OE_THIS, OE_State, [H|T], Obj) ->
- SubobjKey = corba:get_subobject_key(OE_THIS),
- _RF = ?read_function({orber_CosNaming, SubobjKey}),
- case orber_cosnaming_utils:query_result(mnesia:transaction(_RF)) of
- error ->
- corba:raise(#'CosNaming_NamingContext_CannotProceed'{rest_of_name=[H|T],
- cxt=OE_THIS});
- X ->
- case lists:keysearch(H, 1, X) of
- {value, {H, ncontext, NC}} when is_record(NC, 'IOP_IOR') ->
- {reply, 'CosNaming_NamingContext':bind(NC, T, Obj), OE_State};
- {value, {H, ncontext, NC}} ->
- bind(NC, OE_State, T, Obj);
- _ ->
- corba:raise(#'CosNaming_NamingContext_CannotProceed'
- {rest_of_name=[H|T], cxt=OE_THIS})
- end
- end;
-bind(_OE_THIS, _OE_State, [], _Obj) ->
- orber:dbg("[~p] CosNaming_NamingContextExt:bind();~n"
- "Invoked this operation with an empty list",
- [?LINE], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_YES}).
-
-%%----------------------------------------------------------------------
-%% Function : rebind
-%% Arguments :
-%% Description:
-%% Returns :
-%%----------------------------------------------------------------------
-rebind(OE_THIS, OE_State, [N], Obj) ->
- SubobjKey = corba:get_subobject_key(OE_THIS),
- _RBF =
- fun() ->
- case mnesia:wread({orber_CosNaming, SubobjKey}) of
- [#orber_CosNaming{nameindex = X}] ->
- KList =
- case lists:keysearch(N, 1, X) of
- {value, {N, _, _V}} ->
- lists:keyreplace(N, 1, X, {N, nobject, Obj});
- false ->
- [{N, nobject, Obj} | X]
- end,
- mnesia:write(#orber_CosNaming{name_context=SubobjKey,
- nameindex=KList});
- Other ->
- orber:dbg("[~p] ~p:rebind(~p, ~p);~n"
- "DB access returned ~p",
- [?LINE, ?MODULE, N, SubobjKey, Other], ?DEBUG_LEVEL),
- {'EXCEPTION', #'CosNaming_NamingContext_CannotProceed'{rest_of_name=[N],
- cxt=OE_THIS}}
- end
- end,
- case mnesia:transaction(_RBF) of
- {atomic, {'EXCEPTION', E}} ->
- corba:raise(E);
- {atomic, ok} ->
- {reply, ok, OE_State};
- Other ->
- orber:dbg("[~p] ~p:rebind(~p, ~p);~n"
- "DB transaction returned ~p",
- [?LINE, ?MODULE, N, SubobjKey, Other], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end;
-rebind(OE_THIS, OE_State, [H|T], Obj) ->
- SubobjKey = corba:get_subobject_key(OE_THIS),
- _RF = ?read_function({orber_CosNaming, SubobjKey}),
- case orber_cosnaming_utils:query_result(mnesia:transaction(_RF)) of
- error ->
- corba:raise(#'CosNaming_NamingContext_CannotProceed'{rest_of_name=[H|T],
- cxt=OE_THIS});
- X ->
- case lists:keysearch(H, 1, X) of
- {value, {H, ncontext, NC}} when is_record(NC, 'IOP_IOR') ->
- {reply, 'CosNaming_NamingContext':rebind(NC, T, Obj), OE_State};
- {value, {H, ncontext, NC}} ->
- rebind(NC, OE_State, T, Obj);
- _ ->
- corba:raise(#'CosNaming_NamingContext_CannotProceed'
- {rest_of_name=[H|T], cxt=OE_THIS})
- end
- end;
-rebind(_OE_THIS, _OE_State, [], _Obj) ->
- orber:dbg("[~p] CosNaming_NamingContextExt:rebind();~n"
- "Invoked this operation with an empty list",
- [?LINE], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_YES}).
-
-%%----------------------------------------------------------------------
-%% Function : bind_context
-%% Arguments :
-%% Description:
-%% Returns :
-%%----------------------------------------------------------------------
-bind_context(OE_THIS, OE_State, [N], Obj) ->
- SubobjKey = corba:get_subobject_key(OE_THIS),
- _BCF =
- fun() ->
- case mnesia:wread({orber_CosNaming, SubobjKey}) of
- [#orber_CosNaming{nameindex = X}] ->
- case lists:keysearch(N, 1, X) of
- {value, _} ->
- {'EXCEPTION', #'CosNaming_NamingContext_AlreadyBound'{}};
- false ->
- mnesia:write(#orber_CosNaming{name_context=SubobjKey,
- nameindex=
- [{N, ncontext, Obj} | X]})
- end;
- Other ->
- orber:dbg("[~p] ~p:bind_context(~p, ~p);~n"
- "DB access returned ~p",
- [?LINE, ?MODULE, N, SubobjKey, Other], ?DEBUG_LEVEL),
- {'EXCEPTION', #'CosNaming_NamingContext_CannotProceed'{rest_of_name=[N],
- cxt=OE_THIS}}
- end
- end,
- case mnesia:transaction(_BCF) of
- {atomic, {'EXCEPTION', E}} ->
- corba:raise(E);
- {atomic, ok} ->
- {reply, ok, OE_State};
- Other ->
- orber:dbg("[~p] ~p:bind_context(~p, ~p);~n"
- "DB transaction returned ~p",
- [?LINE, ?MODULE, N, SubobjKey, Other], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end;
-bind_context(OE_THIS, OE_State, [H|T], Obj) ->
- SubobjKey = corba:get_subobject_key(OE_THIS),
- _RF = ?read_function({orber_CosNaming, SubobjKey}),
- case orber_cosnaming_utils:query_result(mnesia:transaction(_RF)) of
- error ->
- corba:raise(#'CosNaming_NamingContext_CannotProceed'{rest_of_name=[H|T],
- cxt=OE_THIS});
- X ->
- case lists:keysearch(H, 1, X) of
- {value, {H, ncontext, NC}} when is_record(NC, 'IOP_IOR') ->
- {reply, 'CosNaming_NamingContext':bind_context(NC, T, Obj),
- OE_State};
- {value, {H, ncontext, NC}} ->
- bind_context(NC, OE_State, T, Obj);
- _ ->
- corba:raise(#'CosNaming_NamingContext_CannotProceed'
- {rest_of_name=[H|T], cxt=OE_THIS})
- end
- end;
-bind_context(_OE_THIS, _OE_State, [], _Obj) ->
- orber:dbg("[~p] CosNaming_NamingContextExt:bind_context();~n"
- "Invoked this operation with an empty list",
- [?LINE], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_YES}).
-
-%%----------------------------------------------------------------------
-%% Function : rebind_context
-%% Arguments :
-%% Description:
-%% Returns :
-%%----------------------------------------------------------------------
-rebind_context(OE_THIS, OE_State, [N], Obj) ->
- SubobjKey = corba:get_subobject_key(OE_THIS),
- _RBCF =
- fun() ->
- case mnesia:wread({orber_CosNaming, SubobjKey}) of
- [#orber_CosNaming{nameindex = X}] ->
- KList =
- case lists:keysearch(N, 1, X) of
- {value, {N, _, _V}} ->
- lists:keyreplace(N, 1, X, {N, ncontext, Obj});
- false ->
- [{N, ncontext, Obj} | X]
- end,
- mnesia:write(#orber_CosNaming{name_context=SubobjKey,
- nameindex= KList});
- Other ->
- orber:dbg("[~p] ~p:rebind_context(~p, ~p);~n"
- "DB access returned ~p",
- [?LINE, ?MODULE, N, SubobjKey, Other], ?DEBUG_LEVEL),
- {'EXCEPTION', #'CosNaming_NamingContext_CannotProceed'{rest_of_name=[N],
- cxt=OE_THIS}}
- end
- end,
- case mnesia:transaction(_RBCF) of
- {atomic, {'EXCEPTION', E}} ->
- corba:raise(E);
- {atomic, ok} ->
- {reply, ok, OE_State};
- Other ->
- orber:dbg("[~p] ~p:rebind_context(~p, ~p);~n"
- "DB transaction returned ~p",
- [?LINE, ?MODULE, N, SubobjKey, Other], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end;
-rebind_context(OE_THIS, OE_State, [H|T], Obj) ->
- SubobjKey = corba:get_subobject_key(OE_THIS),
- _RF = ?read_function({orber_CosNaming, SubobjKey}),
- case orber_cosnaming_utils:query_result(mnesia:transaction(_RF)) of
- error ->
- corba:raise(#'CosNaming_NamingContext_CannotProceed'{rest_of_name=[H|T],
- cxt=OE_THIS});
- X ->
- case lists:keysearch(H, 1, X) of
- {value, {H,ncontext, NC}} when is_record(NC, 'IOP_IOR') ->
- {reply, 'CosNaming_NamingContext':rebind_context(NC, T, Obj),
- OE_State};
- {value, {H,ncontext, NC}} ->
- rebind_context(NC, OE_State, T, Obj);
- _ ->
- corba:raise(#'CosNaming_NamingContext_CannotProceed'
- {rest_of_name=[H|T], cxt=OE_THIS})
- end
- end;
-rebind_context(_OE_THIS, _OE_State, [], _Obj) ->
- orber:dbg("[~p] CosNaming_NamingContextExt:rebind_context();~n"
- "Invoked this operation with an empty list",
- [?LINE], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_YES}).
-
-%%----------------------------------------------------------------------
-%% Function : resolve
-%% Arguments :
-%% Description:
-%% Returns :
-%%----------------------------------------------------------------------
-resolve(OE_THIS, OE_State, [N]) ->
- SubobjKey = corba:get_subobject_key(OE_THIS),
- _RF = ?read_function({orber_CosNaming, SubobjKey}),
- case orber_cosnaming_utils:query_result(mnesia:transaction(_RF)) of
- error ->
- corba:raise(#'CosNaming_NamingContext_CannotProceed'{rest_of_name=[N],
- cxt=OE_THIS});
- X ->
- case lists:keysearch(N, 1, X) of
- {value, {N, _, Value}} ->
- {reply, Value, OE_State};
- false ->
- corba:raise(#'CosNaming_NamingContext_NotFound'
- {rest_of_name=[N], why='not_object'})
- end
- end;
-resolve(OE_THIS, OE_State, [H|T]) ->
- SubobjKey = corba:get_subobject_key(OE_THIS),
- _RF = ?read_function({orber_CosNaming, SubobjKey}),
- case orber_cosnaming_utils:query_result(mnesia:transaction(_RF)) of
- error ->
- corba:raise(#'CosNaming_NamingContext_CannotProceed'{rest_of_name=[H|T],
- cxt=OE_THIS});
- X ->
- case lists:keysearch(H, 1, X) of
- {value, {H, ncontext, NC}} when is_record(NC, 'IOP_IOR') ->
- {reply, 'CosNaming_NamingContext':resolve(NC, T), OE_State};
- {value, {H, ncontext, NC}} ->
- resolve(NC, OE_State, T);
- _ ->
- corba:raise(#'CosNaming_NamingContext_CannotProceed'
- {rest_of_name=[H|T], cxt=OE_THIS})
- end
- end;
-resolve(_OE_THIS, _OE_State, []) ->
- orber:dbg("[~p] CosNaming_NamingContextExt:resolve();~n"
- "Invoked this operation with an empty list",
- [?LINE], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_YES}).
-
-%%----------------------------------------------------------------------
-%% Function : unbind
-%% Arguments :
-%% Description:
-%% Returns :
-%%----------------------------------------------------------------------
-unbind(OE_THIS, OE_State, [N]) ->
- SubobjKey = corba:get_subobject_key(OE_THIS),
- _UBF =
- fun() ->
- case mnesia:wread({orber_CosNaming, SubobjKey}) of
- [#orber_CosNaming{nameindex = X}] ->
- KList = lists:keydelete(N, 1, X),
- mnesia:write(#orber_CosNaming{name_context=SubobjKey,
- nameindex= KList});
- Other ->
- orber:dbg("[~p] ~p:unbind(~p, ~p);~n"
- "DB transaction returned ~p",
- [?LINE, ?MODULE, N, SubobjKey, Other], ?DEBUG_LEVEL),
- {'EXCEPTION', #'CosNaming_NamingContext_CannotProceed'{rest_of_name=[N],
- cxt=OE_THIS}}
- end
- end,
- case mnesia:transaction(_UBF) of
- {atomic, {'EXCEPTION', E}} ->
- corba:raise(E);
- {atomic, ok} ->
- {reply, ok, OE_State};
- Other ->
- orber:dbg("[~p] ~p:unbind(~p, ~p);~n"
- "DB transaction returned ~p",
- [?LINE, ?MODULE, N, SubobjKey, Other], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end;
-unbind(OE_THIS, OE_State, [H|T]) ->
- SubobjKey = corba:get_subobject_key(OE_THIS),
- _RF = ?read_function({orber_CosNaming, SubobjKey}),
- case orber_cosnaming_utils:query_result(mnesia:transaction(_RF)) of
- error ->
- corba:raise(#'CosNaming_NamingContext_CannotProceed'{rest_of_name=[H|T],
- cxt=OE_THIS});
- X ->
- case lists:keysearch(H, 1, X) of
- {value, {H, ncontext, NC}} when is_record(NC, 'IOP_IOR') ->
- {reply, 'CosNaming_NamingContext':unbind(NC, T), OE_State};
- {value, {H, ncontext, NC}} ->
- unbind(NC, OE_State, T);
- _ ->
- corba:raise(#'CosNaming_NamingContext_CannotProceed'
- {rest_of_name=[H|T], cxt=OE_THIS})
- end
- end;
-unbind(_OE_THIS, _OE_State, []) ->
- orber:dbg("[~p] CosNaming_NamingContextExt:unbind();~n"
- "Invoked this operation with an empty list",
- [?LINE], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_YES}).
-
-
-%%----------------------------------------------------------------------
-%% Function : new_context
-%% Arguments :
-%% Description:
-%% Returns :
-%%----------------------------------------------------------------------
-new_context(_OE_THIS, OE_State) ->
- DBKey = term_to_binary({{erlang:system_time(),
- erlang:unique_integer()},
- node()}),
- %% Create a record in the table and set the key to a newly
- {reply,
- 'CosNaming_NamingContextExt':oe_create(DBKey,
- [{pseudo, true}|?CREATE_OPTS]),
- OE_State}.
-
-%%----------------------------------------------------------------------
-%% Function : bind_new_context
-%% Arguments :
-%% Description:
-%% Returns :
-%%----------------------------------------------------------------------
-bind_new_context(OE_THIS, OE_State, N) ->
- DBKey = term_to_binary({{erlang:system_time(),
- erlang:unique_integer()},
- node()}),
- %% Create a record in the table and set the key to a newly
- %% generated objectkey.
- %%?PRINTDEBUG("bind_new_context"),
- NewCtx = 'CosNaming_NamingContextExt':oe_create(DBKey,
- [{pseudo, true}|?CREATE_OPTS]),
- %% Bind the created name context to a name
- case catch bind_context(OE_THIS, OE_State, N, NewCtx) of
- {'EXCEPTION', E} ->
- 'CosNaming_NamingContextExt':destroy(NewCtx),
- corba:raise(E);
- {reply, ok, _} ->
- {reply, NewCtx, OE_State}
- end.
-
-
-%%----------------------------------------------------------------------
-%% Function : list
-%% Arguments :
-%% Description:
-%% Returns :
-%%----------------------------------------------------------------------
-list(OE_THIS, OE_State, HowMany) ->
- SubobjKey = corba:get_subobject_key(OE_THIS),
- _RF = ?read_function({orber_CosNaming, SubobjKey}),
- case orber_cosnaming_utils:query_result(mnesia:transaction(_RF)) of
- error ->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO});
- X ->
- case convert_list(X, HowMany, 0, []) of
- {false, List} ->
- {reply, {ok, List, ?ORBER_NIL_OBJREF}, OE_State};
- {true, List, Rest} ->
- %% By setting HowMany to '-1' it will never match
- %% the Counter. Hence, the whole list will be transformed.
- {false, List2} = convert_list(Rest, -1, 0, []),
- BIterator = 'CosNaming_BindingIterator':
- oe_create(List2, ?CREATE_OPTS),
- {reply, {ok, List, BIterator}, OE_State}
- end
- end.
-
-convert_list([], _, _, Acc) ->
- {false, Acc};
-convert_list(Rest, Counter, Counter, Acc) ->
- {true, Acc, Rest};
-convert_list([{N, T, _O}|Rest], HowMany, Counter, Acc) ->
- convert_list(Rest, HowMany, Counter+1,
- [#'CosNaming_Binding'{binding_name=[N],
- binding_type=T}|Acc]).
-
-%%----------------------------------------------------------------------
-%% Function : destroy
-%% Arguments :
-%% Description:
-%% Returns :
-%%----------------------------------------------------------------------
-destroy(OE_THIS, OE_State) ->
- SubobjKey = corba:get_subobject_key(OE_THIS),
- try begin
- true = (byte_size(SubobjKey) < 20),
- undefined = binary_to_term(SubobjKey)
- end
- of
- _ ->
- corba:raise(#'NO_PERMISSION'{completion_status=?COMPLETED_NO})
- catch
- error:_ -> %% Not atom 'undefined', carry on...
- _DF =
- fun() ->
- case mnesia:wread({orber_CosNaming, SubobjKey}) of
- [#orber_CosNaming{nameindex = []}] ->
- mnesia:delete({orber_CosNaming, SubobjKey});
- Other when is_list(Other) ->
- orber:dbg("[~p] ~p:destroy(~p);~n"
- "DB access returned ~p",
- [?LINE, ?MODULE, SubobjKey, Other], ?DEBUG_LEVEL),
- {'EXCEPTION', #'CosNaming_NamingContext_NotEmpty'{}}
- end
- end,
- case mnesia:transaction(_DF) of
- {atomic, {'EXCEPTION', E}} ->
- corba:raise(E);
- {atomic, ok} ->
- {reply, ok, OE_State};
- Other ->
- orber:dbg("[~p] ~p:destroy(~p);~n"
- "DB transaction returned ~p",
- [?LINE, ?MODULE, SubobjKey, Other], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end
- end.
-
-%%----------------------------------------------------------------------
-%% Interface CosNaming::NamingContextExt
-%%----------------------------------------------------------------------
-%%----------------------------------------------------------------------
-%% Function : to_string
-%% Arguments : Name
-%% Description:
-%% Returns : StringName |
-%% {'EXCEPTION', NamingContext::InvalidName{}}
-%%----------------------------------------------------------------------
-to_string(_OE_This, OE_State, Name) ->
- {reply, orber_cosnaming_utils:name2string(Name), OE_State}.
-
-
-%%----------------------------------------------------------------------
-%% Function : to_name
-%% Arguments : StringName
-%% Description:
-%% Returns : Name |
-%% {'EXCEPTION', NamingContext::InvalidName{}}
-%%----------------------------------------------------------------------
-to_name(_OE_This, OE_State, StringName) ->
- {reply, orber_cosnaming_utils:string2name(StringName), OE_State}.
-
-
-%%----------------------------------------------------------------------
-%% Function : to_url
-%% Arguments : Address
-%% StringName
-%% Description:
-%% Returns : URLString |
-%% {'EXCEPTION', NamingContext::InvalidName{}}
-%% {'EXCEPTION', NamingContextExt::InvalidAddress{}}
-%%----------------------------------------------------------------------
-to_url(_, _, "", _) ->
- %% Empty address not allowed.
- corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{});
-to_url(_OE_This, OE_State, Address, "") ->
- %% Empty stringname => use corbaloc
- orber_cosnaming_utils:check_addresses(Address),
- {reply, "corbaloc:"++orber_cosnaming_utils:escape_string(Address), OE_State};
-to_url(_OE_This, OE_State, Address, StringName) ->
- %% Non-empty stringname => use corbaname
- orber_cosnaming_utils:check_addresses(Address),
- orber_cosnaming_utils:check_name(StringName),
- {reply,
- "corbaname:"++orber_cosnaming_utils:escape_string(Address)++"#"++
- orber_cosnaming_utils:escape_string(StringName),
- OE_State}.
-
-%%----------------------------------------------------------------------
-%% Function : resolve_str
-%% Arguments : StringName
-%% Description:
-%% Returns : Object |
-%% {'EXCEPTION', NamingContext::InvalidName{}}
-%% {'EXCEPTION', NamingContext::NotFound{why, rest_of_name}}
-%% {'EXCEPTION', NamingContext::CannotProceed{cxt, rest_of_name}}
-%%----------------------------------------------------------------------
-resolve_str(OE_This, OE_State, StringName) ->
- Name = orber_cosnaming_utils:string2name(StringName),
- resolve(OE_This, OE_State, Name).
-
-%%======================================================================
-%% Internal functions
-%%======================================================================
-%% Check a write transaction
-write_result({atomic,ok}) -> ok;
-write_result(_What) ->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}).
-
-
-%%----------------------------------------------------------------------
-%% Debugging functions
-%%----------------------------------------------------------------------
-dump() ->
- case catch mnesia:dirty_first('orber_CosNaming') of
- {'EXIT', R} ->
- io:format("Exited with ~p\n",[R]);
- Key ->
- dump_print(Key),
- dump_loop(Key)
- end.
-
-dump_loop(PreviousKey) ->
- case catch mnesia:dirty_next('orber_CosNaming', PreviousKey) of
- {'EXIT', R} ->
- io:format("Exited with ~p\n",[R]);
- '$end_of_table' ->
- ok;
- Key ->
- dump_print(Key),
- dump_loop(Key)
- end.
-
-dump_print(Key) ->
- case catch mnesia:dirty_read({'orber_CosNaming', Key}) of
- {'EXIT', R} ->
- io:format("Exited with ~p\n",[R]);
- [X] ->
- io:format("name_context: ~p\n-----------------------------\n"
- " nameindex structure\n-----------------------------\n~p\n\n",
- [binary_to_term(X#orber_CosNaming.name_context),
- X#orber_CosNaming.nameindex]);
- _ ->
- ok
- end.
-
-%%-------------------------- END OF MODULE -----------------------------
diff --git a/lib/orber/COSS/CosNaming/Makefile b/lib/orber/COSS/CosNaming/Makefile
deleted file mode 100644
index 108663396c..0000000000
--- a/lib/orber/COSS/CosNaming/Makefile
+++ /dev/null
@@ -1,153 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-EBIN=../../ebin
-
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../../vsn.mk
-VSN=$(ORBER_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/orber-$(VSN)
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-
-MODULES = \
- CosNaming_NamingContextExt_impl \
- CosNaming_BindingIterator_impl \
- lname \
- lname_component \
- orber_cosnaming_utils
-
-ERL_FILES = $(MODULES:%=%.erl)
-HRL_FILES = lname.hrl \
- orber_cosnaming.hrl
-GEN_ERL_FILES = \
- oe_cos_naming.erl \
- CosNaming_Name.erl \
- CosNaming_NamingContext.erl \
- CosNaming_BindingIterator.erl \
- CosNaming_NameComponent.erl \
- CosNaming_Binding.erl \
- CosNaming_BindingList.erl \
- CosNaming_NamingContext_NotFound.erl \
- CosNaming_NamingContext_AlreadyBound.erl \
- CosNaming_NamingContext_CannotProceed.erl \
- CosNaming_NamingContext_InvalidName.erl \
- CosNaming_NamingContext_NotEmpty.erl
-
-GEN_EXT_ERL_FILES = \
- oe_cos_naming_ext.erl \
- CosNaming_NamingContextExt.erl \
- CosNaming_NamingContextExt_InvalidAddress.erl
-
-GEN_HRL_FILES = \
- oe_cos_naming.hrl \
- CosNaming.hrl \
- CosNaming_NamingContext.hrl \
- CosNaming_BindingIterator.hrl
-
-GEN_EXT_HRL_FILES = \
- oe_cos_naming_ext.hrl \
- CosNaming_NamingContextExt.hrl
-
-GEN_FILES = $(GEN_ERL_FILES) $(GEN_HRL_FILES) \
- $(GEN_EXT_ERL_FILES) $(GEN_EXT_HRL_FILES)
-
-TARGET_FILES = \
- $(GEN_EXT_ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR)) \
- $(GEN_ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR)) \
- $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-
-IDL_FILE = cos_naming.idl \
- cos_naming_ext.idl
-
-APP_FILE =
-#APP_SRC = $(APP_FILE).src
-#APP_TARGET = $(EBIN)/$(APP_FILE)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_IDL_FLAGS += -pa $(ERL_TOP)/lib/orber/ebin
-# The -pa option is just used temporary until erlc can handle
-# includes from other directories than ../include .
-ERL_COMPILE_FLAGS += \
- $(ERL_IDL_FLAGS) \
- -I$(ERL_TOP)/lib/orber/include \
- +'{parse_transform,sys_pre_attributes}' \
- +'{attribute,insert,app_vsn,"orber_$(ORBER_VSN)"}'
-
-YRL_FLAGS =
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-opt: $(TARGET_FILES) $(APP_TARGET)
-
-debug:
- @${MAKE} TYPE=debug
-
-clean:
- rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) IDL-GENERATED
- rm -f errs core *~
-
-$(APP_TARGET): $(APP_SRC)
- $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $(APP_SRC) > $(APP_TARGET)
-
-docs:
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-IDL-GENERATED: cos_naming_ext.idl cos_naming.idl
- $(gen_verbose)erlc $(ERL_IDL_FLAGS) +'{this,"CosNaming::NamingContext"}' \
- +'{this,"CosNaming::NamingContextExt"}' cos_naming_ext.idl
- $(V_at)erlc $(ERL_IDL_FLAGS) +'{this,"CosNaming::NamingContext"}' cos_naming.idl
- $(V_at)>IDL-GENERATED
-
-$(GEN_FILES): IDL-GENERATED
-
-$(TARGET_FILES): IDL-GENERATED
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) "$(RELSYSDIR)/ebin"
- $(INSTALL_DIR) "$(RELSYSDIR)/COSS/CosNaming"
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(IDL_FILE) "$(RELSYSDIR)/COSS/CosNaming"
- $(INSTALL_DATA) $(GEN_FILES) "$(RELSYSDIR)/COSS/CosNaming"
-
-
-release_docs_spec:
-
diff --git a/lib/orber/COSS/CosNaming/cos_naming.idl b/lib/orber/COSS/CosNaming/cos_naming.idl
deleted file mode 100644
index 3cd6c99c23..0000000000
--- a/lib/orber/COSS/CosNaming/cos_naming.idl
+++ /dev/null
@@ -1,77 +0,0 @@
-// Naming Service v1.0 described in CORBAservices:
-// Common Object Services Specification, chapter 3
-// OMG IDL for CosNaming Module, p 3-6
-
-#pragma prefix "omg.org"
-
-module CosNaming
-{
- typedef string Istring;
- struct NameComponent {
- Istring id;
- Istring kind;
- };
-
- typedef sequence <NameComponent> Name;
-
- enum BindingType {nobject, ncontext};
-
- struct Binding {
- Name binding_name;
- BindingType binding_type;
- };
-
- typedef sequence <Binding> BindingList;
-
-
- interface BindingIterator;
- interface NamingContext;
-
- interface NamingContext {
-
- enum NotFoundReason { missing_node, not_context, not_object};
-
- exception NotFound {
- NotFoundReason why;
- Name rest_of_name;
- };
-
- exception CannotProceed {
- NamingContext cxt;
- Name rest_of_name;
- };
-
- exception InvalidName{};
- exception AlreadyBound {};
- exception NotEmpty{};
-
- void bind(in Name n, in Object obj)
- raises(NotFound, CannotProceed, InvalidName, AlreadyBound);
- void rebind(in Name n, in Object obj)
- raises(NotFound, CannotProceed, InvalidName);
- void bind_context(in Name n, in NamingContext nc)
- raises(NotFound, CannotProceed,InvalidName, AlreadyBound);
- void rebind_context(in Name n, in NamingContext nc)
- raises(NotFound, CannotProceed, InvalidName);
- Object resolve (in Name n)
- raises(NotFound, CannotProceed, InvalidName);
- void unbind(in Name n)
- raises(NotFound, CannotProceed, InvalidName);
- NamingContext new_context();
- NamingContext bind_new_context(in Name n)
- raises(NotFound, AlreadyBound, CannotProceed, InvalidName);
- void destroy( )
- raises(NotEmpty);
- void list (in unsigned long how_many,
- out BindingList bl,
- out BindingIterator bi);
- };
-
- interface BindingIterator {
- boolean next_one(out Binding b);
- boolean next_n(in unsigned long how_many,
- out BindingList bl);
- void destroy();
- };
-};
-
diff --git a/lib/orber/COSS/CosNaming/cos_naming_ext.idl b/lib/orber/COSS/CosNaming/cos_naming_ext.idl
deleted file mode 100644
index 8099a0005c..0000000000
--- a/lib/orber/COSS/CosNaming/cos_naming_ext.idl
+++ /dev/null
@@ -1,37 +0,0 @@
-// Naming Service v1.0 described in CORBAservices:
-// Common Object Services Specification, chapter 3
-// OMG IDL for CosNaming Module, p 3-6
-
-#ifndef _COSNAMINGEXT_IDL_
-#define _COSNAMINGEXT_IDL_
-
-
-#include<cos_naming.idl>
-
-#pragma prefix "omg.org"
-
-module CosNaming
-{
- interface NamingContextExt:NamingContext {
-
- typedef string StringName;
- typedef string Address;
- typedef string URLString;
-
- StringName to_string(in Name n)
- raises(InvalidName);
-
- Name to_name(in StringName sn)
- raises(InvalidName);
-
- exception InvalidAddress{};
-
- URLString to_url(in Address addr,in StringName sn)
- raises(InvalidAddress, InvalidName);
-
- Object resolve_str(in StringName n)
- raises(NotFound, CannotProceed, InvalidName);
- };
-};
-
-#endif//_COSNAMINGEXT_IDL_
diff --git a/lib/orber/COSS/CosNaming/lname.erl b/lib/orber/COSS/CosNaming/lname.erl
deleted file mode 100644
index 41f9f68d20..0000000000
--- a/lib/orber/COSS/CosNaming/lname.erl
+++ /dev/null
@@ -1,134 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: lname.erl
-%%-----------------------------------------------------------------
--module(lname).
-
--include_lib("orber/include/corba.hrl").
--include("CosNaming.hrl").
--include("lname.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([create/0, insert_component/3, get_component/2, delete_component/2,
- num_component/1, equal/2, less_than/2,
- to_idl_form/1, from_idl_form/1, check_name/1, new/1]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-%% DEBUG INFO
--define(DEBUG_LEVEL, 5).
-
-%%-----------------------------------------------------------------
-%% External interface functions
-%%-----------------------------------------------------------------
-create() ->
- [].
-
-insert_component(_, I, _) when I < 1->
- corba:raise(#'LName_NoComponent'{});
-insert_component([], I, _) when I > 1->
- corba:raise(#'LName_NoComponent'{});
-insert_component(Name, 1, Component) when is_record(Component,
- 'CosNaming_NameComponent') ->
- [Component |Name];
-insert_component([H|T], I, Component) when is_record(Component,
- 'CosNaming_NameComponent') ->
- [H |insert_component(T, I-1, Component)];
-insert_component(_, _, Component) ->
- orber:dbg("[~p] ~p:insert_component(~p); Not a NameComponent.~n",
- [?LINE, ?MODULE, Component], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-get_component(_, I) when I < 1->
- corba:raise(#'LName_NoComponent'{});
-get_component([], _) ->
- corba:raise(#'LName_NoComponent'{});
-get_component([H|_T], 1) ->
- H;
-get_component([_|T], I) ->
- get_component(T, I-1).
-
-delete_component(_, I) when I < 1->
- corba:raise(#'LName_NoComponent'{});
-delete_component([], _) ->
- corba:raise(#'LName_NoComponent'{});
-delete_component([_|T], 1) ->
- T;
-delete_component([H|T], I) ->
- [H | delete_component(T, I-1)].
-
-num_component(Name) ->
- num_component(Name, 0).
-
-equal(Name, N) ->
- N == Name.
-
-less_than(Name, N) ->
- Name < N.
-
-to_idl_form(Name) ->
- case check_name(Name) of
- false ->
- corba:raise(#'LName_InvalidName'{});
- true ->
- Name
- end.
-
-from_idl_form(Name) ->
- Name.
-
-%%destroy() -> % not needed in erlang
-%% ok.
-
-%%-----------------------------------------------------------------
-%% External Functions not in the CosNaming standard
-%%-----------------------------------------------------------------
-new([]) ->
- [];
-new([{Id, Kind} | List]) ->
- [lname_component:new(Id, Kind) | new(List)];
-new([Id |List]) when is_list(Id) ->
- [lname_component:new(Id) | new(List)].
-
-%%-----------------------------------------------------------------
-%% Internal Functions
-%%-----------------------------------------------------------------
-num_component([], N) ->
- N;
-num_component([_|T], N) ->
- num_component(T, N+1).
-
-check_name([]) ->
- true;
-check_name([H|T]) ->
- case catch lname_component:get_id(H) of
- {'EXCEPTION', _E} ->
- false;
- _ ->
- check_name(T)
- end.
diff --git a/lib/orber/COSS/CosNaming/lname.hrl b/lib/orber/COSS/CosNaming/lname.hrl
deleted file mode 100644
index 0c0eef86ab..0000000000
--- a/lib/orber/COSS/CosNaming/lname.hrl
+++ /dev/null
@@ -1,34 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: lname.hrl
-%%-----------------------------------------------------------------
-
-%% LName interface exceptions
--record('LName_NoComponent', {'OE_ID'="PIDL:LName/NoComponent:1.0"}).
--record('LName_InvalidName', {'OE_ID'="PIDL:LName/InvalidName:1.0"}).
-% This exception is not used in our implementation.
--record('LName_Overflow', {'OE_ID'="PIDL:LName/Overflow:1.0"}).
-
-%% LNameComponent interface exceptions
--record('LNameComponent_NotSet',
- {'OE_ID'="PIDL:LNameComponent/NotSet:1.0"}).
diff --git a/lib/orber/COSS/CosNaming/lname_component.erl b/lib/orber/COSS/CosNaming/lname_component.erl
deleted file mode 100644
index 4dead49a78..0000000000
--- a/lib/orber/COSS/CosNaming/lname_component.erl
+++ /dev/null
@@ -1,84 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: lname_component.erl
-%%-----------------------------------------------------------------
--module(lname_component).
-
--include_lib("orber/include/corba.hrl").
--include("lname.hrl").
--include("CosNaming.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([get_id/1, set_id/2, get_kind/1, set_kind/2, create/0, new/1, new/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-%%-----------------------------------------------------------------
-%% External interface functions
-%%-----------------------------------------------------------------
-create() ->
- #'CosNaming_NameComponent'{id="", kind=""}.
-
-get_id(NC) when is_record(NC, 'CosNaming_NameComponent'),
- NC#'CosNaming_NameComponent'.id == undefined ->
- corba:raise(#'LNameComponent_NotSet'{});
-get_id(NC) when is_record(NC, 'CosNaming_NameComponent'),
- NC#'CosNaming_NameComponent'.id == "" ->
- corba:raise(#'LNameComponent_NotSet'{});
-get_id(NC) when is_record(NC, 'CosNaming_NameComponent') ->
- NC#'CosNaming_NameComponent'.id.
-
-set_id(NC, Id) when is_record(NC, 'CosNaming_NameComponent') andalso is_list(Id)->
- NC#'CosNaming_NameComponent'{id=Id}.
-
-get_kind(NC) when is_record(NC, 'CosNaming_NameComponent') andalso
- NC#'CosNaming_NameComponent'.kind == undefined ->
- corba:raise(#'LNameComponent_NotSet'{});
-get_kind(NC) when is_record(NC, 'CosNaming_NameComponent') andalso
- NC#'CosNaming_NameComponent'.kind == "" ->
- corba:raise(#'LNameComponent_NotSet'{});
-get_kind(NC) when is_record(NC, 'CosNaming_NameComponent') ->
- NC#'CosNaming_NameComponent'.kind.
-
-set_kind(NC, Kind) when is_record(NC, 'CosNaming_NameComponent') andalso is_list(Kind) ->
- NC#'CosNaming_NameComponent'{kind=Kind}.
-
-%%destroy() -> % not needed in erlang
-%% true.
-
-%%-----------------------------------------------------------------
-%% External Functions not in the CosNaming standard
-%%-----------------------------------------------------------------
-new(Id) when is_list(Id) ->
- #'CosNaming_NameComponent'{id=Id, kind=""}.
-new(Id, Kind) when is_list(Id) andalso is_list(Kind) ->
- #'CosNaming_NameComponent'{id=Id, kind=Kind}.
-
-%%-----------------------------------------------------------------
-%% Internal Functions
-%%-----------------------------------------------------------------
diff --git a/lib/orber/COSS/CosNaming/orber_cosnaming.hrl b/lib/orber/COSS/CosNaming/orber_cosnaming.hrl
deleted file mode 100644
index 2950f7a11f..0000000000
--- a/lib/orber/COSS/CosNaming/orber_cosnaming.hrl
+++ /dev/null
@@ -1,64 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%--------------------------------------------------------------------
-
--ifndef(ORBER_COSNAMING_HRL).
--define(ORBER_COSNAMING_HRL, true).
-
-%%-----------------------------------------------------------------
-%% Mnesia Table definition record
-%%-----------------------------------------------------------------
--record('orber_CosNaming', {name_context, nameindex}).
-
-%%-----------------------------------------------------------------
-%% Macros
-%%-----------------------------------------------------------------
-
--define(CREATE_OPTS, [{no_security, orber:partial_security()}]).
-
-%%-define(dirty_query_context, true).
-
-%% This macro returns a read fun suitable for evaluation in a transaction
--define(read_function(Objkey),
- fun() ->
- mnesia:read(Objkey)
- end).
-
-%% This macro returns a write fun suitable for evaluation in a transaction
--define(write_function(R),
- fun() ->
- mnesia:write(R)
- end).
-
-%% This macro returns a delete fun suitable for evaluation in a transaction
--define(delete_function(R),
- fun() ->
- mnesia:delete(R)
- end).
-
--ifdef(dirty_query_context).
--define(query_check(Q_res), Q_res).
--else.
--define(query_check(Q_res), {atomic, Q_res}).
--endif.
-
--endif.
diff --git a/lib/orber/COSS/CosNaming/orber_cosnaming_utils.erl b/lib/orber/COSS/CosNaming/orber_cosnaming_utils.erl
deleted file mode 100644
index c21e46036b..0000000000
--- a/lib/orber/COSS/CosNaming/orber_cosnaming_utils.erl
+++ /dev/null
@@ -1,762 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: orber_cosnaming_utils.erl
-%% Modified:
-%%
-%%-----------------------------------------------------------------
--module(orber_cosnaming_utils).
-
--include("orber_cosnaming.hrl").
--include("CosNaming.hrl").
--include("CosNaming_NamingContext.hrl").
--include("CosNaming_NamingContextExt.hrl").
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([query_result/1]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([addresses/1, name/1,
- check_addresses/1, check_name/1,
- key/1, select_type/1, lookup/1, lookup/2,
- escape_string/1, unescape_string/1,
- name2string/1, string2name/1]).
-
-%%-----------------------------------------------------------------
-%% Records
-%%-----------------------------------------------------------------
-
-%%-----------------------------------------------------------------
-%% Defines
-%%-----------------------------------------------------------------
-%% DEFAULT VALUES:
-%%
-%% IIOP:
-%% - port: 2809
-%% - iiop version: 1.0
--define(DEF_VERS, {1,0}).
--define(DEF_PORT, 2809).
--define(DEF_KEY, "NameService").
--define(HTTP_DEF_PORT, 80).
-
-%% DEBUG INFO
--define(DEBUG_LEVEL, 5).
-
-%%-----------------------------------------------------------------
-%% External interface functions
-%%-----------------------------------------------------------------
-%% Check a read transaction
-query_result({atomic, Qres}) ->
- case Qres of
- [Hres] ->
- Hres#orber_CosNaming.nameindex;
- [Hres|Tres] ->
- orber:dbg("[~p] orber_cosnaming_utils:query_result(~p);~n"
- "Multiple Hits: ~p", [?LINE, Qres, [Hres|Tres]], ?DEBUG_LEVEL),
- error;
- [] ->
- orber:dbg("[~p] orber_cosnaming_utils:query_result();~n"
- "No hit", [?LINE], ?DEBUG_LEVEL),
- error;
- Other ->
- orber:dbg("[~p] orber_cosnaming_utils:query_result(~p);~n"
- "Mnesia Access Failed ~p", [?LINE, Qres, Other], ?DEBUG_LEVEL),
- error
- end;
-query_result({aborted, Qres}) ->
- orber:dbg("[~p] orber_cosnaming_utils:query_result(~p);~n"
- "Mnesia Access Aborted", [?LINE, Qres], ?DEBUG_LEVEL),
- error;
-query_result(What) ->
- orber:dbg("[~p] orber_cosnaming_utils:query_result(~p);~n"
- "Mnesia Access Failed", [?LINE, What], ?DEBUG_LEVEL),
- error.
-
-
-%%----------------------------------------------------------------------
-%% Function : check_addresses
-%% Arguments :
-%% Description:
-%% Returns :
-%%----------------------------------------------------------------------
-check_addresses(Str) ->
- {_, Rest2} = addresses(Str),
- case key(Rest2) of
- {_, []} ->
- ok;
- What ->
- orber:dbg("[~p] orber_cosnaming_utils:check_addresses(~p);~n"
- "Key ~p", [?LINE, Str, What], ?DEBUG_LEVEL),
- corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{})
- end.
-
-%%----------------------------------------------------------------------
-%% Function : check_name
-%% Arguments :
-%% Description:
-%% Returns :
-%%----------------------------------------------------------------------
-check_name(Str) ->
- name(Str).
-
-%%----------------------------------------------------------------------
-%% Function : select_type
-%% Arguments : A corbaloc/corbaname-string.
-%% Description:
-%% Returns : A tuple which contain data about what connection we want to use |
-%% {'EXCEPTION', #'CosNaming_NamingContextExt_InvalidAddress'{}}
-%%----------------------------------------------------------------------
-select_type([$c, $o, $r, $b, $a, $l, $o, $c, $:|Rest1]) ->
- {Addresses, Rest2} = addresses(Rest1),
- case key(Rest2) of
- {Key, []} ->
- {corbaloc, Addresses, Key};
- What ->
- orber:dbg("[~p] orber_cosnaming_utils:select_type(~p);~n"
- "Key ~p", [?LINE, Rest1, What], ?DEBUG_LEVEL),
- corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{})
- end;
-select_type([$c, $o, $r, $b, $a, $n, $a, $m, $e, $:|Rest1]) ->
- {Addresses, Rest2} = addresses(Rest1),
- {Key, Rest3} = key(Rest2),
- Name = name(Rest3),
- {corbaname, Addresses, Key, string2name(Name)};
-
-select_type([$f, $i, $l, $e, $:, $/ |Rest]) ->
- file(Rest);
-select_type([$f, $t, $p, $:, $/, $/ |Rest]) ->
- ftp(Rest);
-select_type([$h, $t, $t, $p, $:, $/, $/ |Rest]) ->
- http(Rest);
-
-select_type(What) ->
- orber:dbg("[~p] orber_cosnaming_utils:select_type(~p);~n"
- "Malformed or unsupported type.",
- [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{}).
-
-
-%%----------------------------------------------------------------------
-%% Function : addresses
-%% Arguments : A corbaloc string.
-%% Description:
-%% Returns : A list of addresses an the remaining part possibly containg
-%% a Key and a stringified Name
-%%----------------------------------------------------------------------
-addresses(Str) ->
- addresses(address(protocol, Str, [], []), []).
-
-addresses({false, rir, Rest}, []) ->
- {rir, Rest};
-addresses({false, Adr, Rest}, Addresses) ->
- {lists:reverse([Adr|Addresses]), Rest};
-addresses({true, Adr, Rest}, Addresses) ->
- addresses(address(protocol, Rest, [], []), [Adr|Addresses]).
-%% Which protocol.
-address(protocol, [$:|T], [], []) ->
- address(version, T, [], [iiop]);
-address(protocol, [$i, $i, $o, $p, $:|T], [], []) ->
- address(version, T, [], [iiop]);
-address(protocol, [$s,$s,$l, $i, $o, $p, $:|T], [], []) ->
- address(version, T, [], [ssliop]);
-address(protocol, [$r, $i, $r, $:|T], [], []) ->
- {false, rir, T};
-address(protocol, What, _, _) ->
- orber:dbg("[~p] orber_cosnaming_utils:address(~p);~n"
- "Malformed or unsupported protocol.",
- [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{});
-
-
-%% Parsed one address, no version found or port found.
-address(version, [$,|T], Acc, Previous) ->
- {true, lists:reverse([?DEF_PORT, lists:reverse(Acc), ?DEF_VERS|Previous]), T};
-address(version, [$/|T], Acc, Previous) ->
- {false, lists:reverse([?DEF_PORT, lists:reverse(Acc), ?DEF_VERS|Previous]), T};
-%% Found iiop version.
-address(version, [$@|T], Acc, Previous) ->
- case Acc of
- [Minor, $., Major] ->
- address(address, T, [], [{Major-$0, Minor-$0}|Previous]);
- What ->
- orber:dbg("[~p] orber_cosnaming_utils:address(~p);~n"
- "Malformed or unsupported version.",
- [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{})
- end;
-
-%% Found no iiop version, switch to ipv6.
-address(version, [$[|T], [], Previous) ->
- address(ipv6, T, [], [?DEF_VERS|Previous]);
-
-%% Found no iiop version, switch to port. In this case Acc contains the
-%% Host.
-address(version, [$:|T], Acc, Previous) ->
- address(port, T, [], [lists:reverse(Acc), ?DEF_VERS|Previous]);
-
-%% Found IPv6
-address(address, [$[|T], [], Previous) ->
- address(ipv6, T, [], Previous);
-
-%% Found port
-address(address, [$:|T], Acc, Previous) ->
- address(port, T, [], [lists:reverse(Acc)|Previous]);
-
-address(ipv6, [$]|T], Acc, Previous) ->
- address(address, T, Acc, Previous);
-
-%% Parsed one address, port not found.
-address(address, [$,|T], [], Previous) ->
- {true, lists:reverse([?DEF_PORT|Previous]), T};
-address(address, [$/|T], [], Previous) ->
- {false, lists:reverse([?DEF_PORT|Previous]), T};
-address(address, [$,|T], Acc, Previous) ->
- {true, lists:reverse([?DEF_PORT, lists:reverse(Acc)|Previous]), T};
-address(address, [$/|T], Acc, Previous) ->
- {false, lists:reverse([?DEF_PORT, lists:reverse(Acc)|Previous]), T};
-
-%% Parsed one address.
-address(port, [$/|T], Acc, Previous) ->
- case catch list_to_integer(lists:reverse(Acc)) of
- Port when is_integer(Port) ->
- {false, lists:reverse([Port|Previous]), T};
- What ->
- orber:dbg("[~p] orber_cosnaming_utils:address(~p);~n"
- "Malformed port.", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{})
- end;
-address(port, [$,|T], Acc, Previous) ->
- case catch list_to_integer(lists:reverse(Acc)) of
- Port when is_integer(Port) ->
- {true, lists:reverse([Port|Previous]), T};
- What ->
- orber:dbg("[~p] orber_cosnaming_utils:address(~p);~n"
- "Malformed port.", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{})
- end;
-
-%% EOS, check how far we have reached so far and add necessary default values.
-address(version, [], Acc, Previous) ->
- {false, lists:reverse([?DEF_PORT, lists:reverse(Acc), ?DEF_VERS|Previous]), []};
-address(port, [], [], Previous) ->
- {false, lists:reverse([?DEF_PORT|Previous]), []};
-address(port, [], Acc, Previous) ->
- case catch list_to_integer(lists:reverse(Acc)) of
- Port when is_integer(Port) ->
- {false, lists:reverse([Port|Previous]), []};
- What ->
- orber:dbg("[~p] orber_cosnaming_utils:address(~p);~n"
- "Malformed port.", [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{})
- end;
-address(address, [], [], Previous) ->
- {false, lists:reverse([?DEF_PORT|Previous]), []};
-address(address, [], Acc, Previous) ->
- {false, lists:reverse([?DEF_PORT, lists:reverse(Acc)|Previous]), []};
-
-address(Type, [H|T], Acc, Previous) ->
- address(Type, T, [H|Acc], Previous).
-
-%%----------------------------------------------------------------------
-%% Function : key
-%% Arguments : A string which contain a Key we want to use and, if defined,
-%% stringified NameComponent sequence.
-%% Description:
-%% Returns : The Key and the remaining part, i.e., a stringified
-%% NameComponent sequence.
-%%----------------------------------------------------------------------
-key(Str) ->
- key(Str, []).
-key([], []) ->
- {?DEF_KEY, []};
-key([], Acc) ->
- {lists:reverse(Acc), []};
-key([$#|T], []) ->
- {?DEF_KEY, T};
-key([$#|T], Acc) ->
- {lists:reverse(Acc), T};
-key([$/|T], []) ->
- key(T, []);
-key([H|T], Acc) ->
- key(T, [H|Acc]).
-
-%%----------------------------------------------------------------------
-%% Function : name
-%% Arguments : A string describing a NameComponent sequence.
-%% Description:
-%% Returns : The input string |
-%% {'EXCEPTION', #'CosNaming_NamingContext_InvalidName'{}}
-%%----------------------------------------------------------------------
-name(Str) ->
- name(Str, []).
-name([], Acc) ->
- lists:reverse(Acc);
-name([$., $/|_T], _) ->
- corba:raise(#'CosNaming_NamingContext_InvalidName'{});
-name([$/, $/|_T], _) ->
- corba:raise(#'CosNaming_NamingContext_InvalidName'{});
-name([$/|T], []) ->
- name(T, []);
-name([H|T], Acc) ->
- name(T, [H|Acc]).
-
-
-%%----------------------------------------------------------------------
-%% Function : file
-%% Arguments : A string describing connection parameters.
-%% Description:
-%% Returns : A tuple consisting of data extracted from the given string.
-%%----------------------------------------------------------------------
-file(File) ->
- {file, File}.
-
-%%----------------------------------------------------------------------
-%% Function : ftp
-%% Arguments : A string describing connection parameters.
-%% Description:
-%% Returns : A tuple consisting of data extracted from the given string.
-%%----------------------------------------------------------------------
-ftp(Address) ->
- %% Perhaps we should run some checks here?
- {ftp, Address}.
-
-%%----------------------------------------------------------------------
-%% Function : http
-%% Arguments : A string describing connection parameters.
-%% Description:
-%% Returns : A tuple consisting of data extracted from the given string.
-%%----------------------------------------------------------------------
-http(Address) ->
- case string:tokens(Address, ":") of
- [Host, Rest] ->
- %% At his stage we know that address contains a Port number.
- {Port, Key} = split_to_slash(Rest, []),
- case catch list_to_integer(Port) of
- PortInt when is_integer(PortInt) ->
- {http, Host, PortInt, Key};
- _ ->
- orber:dbg("[~p] orber_cosnaming_utils:http(~p);~n"
- "Malformed key; should be http://Host:Port/path/name.html~n"
- "or http://Host/path/name.html",
- [?LINE, Address], ?DEBUG_LEVEL),
- corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{})
- end;
- [Address] ->
- %% Use default port
- {Host, Key} = split_to_slash(Address, []),
- {http, Host, ?HTTP_DEF_PORT, Key};
- _What ->
- orber:dbg("[~p] orber_cosnaming_utils:http(~p);~n"
- "Malformed key; should be http://Host:Port/path/name.html~n"
- "or http://Host/path/name.html",
- [?LINE, Address], ?DEBUG_LEVEL),
- corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{})
- end.
-
-split_to_slash([], _Acc) ->
- orber:dbg("[~p] orber_cosnaming_utils:split_to_slash();~n"
- "No Key given Host:Port/Key.html", [?LINE], ?DEBUG_LEVEL),
- corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{});
-split_to_slash([$/|Rest], Acc) ->
- {lists:reverse(Acc), [$/|Rest]};
-split_to_slash([H|T], Acc) ->
- split_to_slash(T, [H|Acc]).
-
-%%----------------------------------------------------------------------
-%% Function : lookup
-%% Arguments : A tuple which contain data about what connection we want to use.
-%% Description:
-%% Returns : Object |
-%% {'EXCEPTION', E}
-%%----------------------------------------------------------------------
-lookup(Data) ->
- lookup(Data, []).
-
-lookup({corbaname, rir, _Key, []}, Ctx) ->
- %% If no object key supplied NameService is defined to be default.
- corba:resolve_initial_references("NameService", Ctx);
-lookup({corbaname, rir, Key, Name}, Ctx) ->
- NS = corba:resolve_initial_references(Key, Ctx),
- 'CosNaming_NamingContext':resolve(NS, Ctx, Name);
-
-lookup({corbaloc, rir, Key}, Ctx) ->
- corba:resolve_initial_references(Key, Ctx);
-
-lookup({corbaname, [], _Key, _Name}, _Ctx) ->
- corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{});
-lookup({corbaname, Addresses, Key, ""}, Ctx) ->
- %% Not Name-string defined, which is the same as corbaloc.
- lookup({corbaloc, Addresses, Key}, Ctx);
-lookup({corbaname, [[iiop, Vers, Host, Port]|Addresses], Key, Name}, Ctx) ->
- NS = iop_ior:create_external(Vers, key2id(Key), Host, Port, Key),
- case catch 'CosNaming_NamingContext':resolve(NS, Ctx, Name) of
- {'EXCEPTION', _} ->
- lookup({corbaname, Addresses, Key, Name}, Ctx);
- Obj ->
- Obj
- end;
-%%% Corbaname via SSL
-lookup({corbaname, [[ssliop, Vers, Host, Port]|Addresses], Key, Name}, Ctx) ->
- SSLComponent =
- #'IOP_TaggedComponent'{tag=?TAG_SSL_SEC_TRANS,
- component_data=#'SSLIOP_SSL'{target_supports = 2,
- target_requires = 2,
- port = Port}},
- NS = iop_ior:create_external(Vers, key2id(Key), Host, Port, Key, [SSLComponent]),
- case catch 'CosNaming_NamingContext':resolve(NS, Ctx, Name) of
- {'EXCEPTION', _} ->
- lookup({corbaname, Addresses, Key, Name}, Ctx);
- Obj ->
- Obj
- end;
-lookup({corbaname, [_|Addresses], Key, Name}, Ctx) ->
- lookup({corbaname, Addresses, Key, Name}, Ctx);
-
-lookup({corbaloc, [], _Key}, _Ctx) ->
- corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{});
-lookup({corbaloc, [[iiop, Vers, Host, Port]|Addresses], Key}, Ctx) ->
- ObjRef = iop_ior:create_external(Vers, key2id(Key), Host, Port, Key),
- OldVal = put(orber_forward_notify, true),
- case catch corba_object:non_existent(ObjRef, Ctx) of
- {location_forward, Result} ->
- put(orber_forward_notify, OldVal),
- Result;
- false ->
- put(orber_forward_notify, OldVal),
- ObjRef;
- true ->
- put(orber_forward_notify, OldVal),
- lookup({corbaloc, Addresses, Key}, Ctx);
- _ ->
- %% May be located on a version using '_not_existent'
- %% see CORBA2.3.1 page 15-34 try again.
- case catch corba_object:not_existent(ObjRef, Ctx) of
- {location_forward, Result} ->
- put(orber_forward_notify, OldVal),
- Result;
- false ->
- put(orber_forward_notify, OldVal),
- ObjRef;
- _ ->
- put(orber_forward_notify, OldVal),
- lookup({corbaloc, Addresses, Key}, Ctx)
- end
- end;
-
-%%% Corbaloc via SSL
-lookup({corbaloc, [[ssliop, Vers, Host, Port]|Addresses], Key}, Ctx) ->
- SSLComponent =
- #'IOP_TaggedComponent'{tag=?TAG_SSL_SEC_TRANS,
- component_data=#'SSLIOP_SSL'{target_supports = 2,
- target_requires = 2,
- port = Port}},
- ObjRef = iop_ior:create_external(Vers, key2id(Key), Host, Port, Key, [SSLComponent]),
- OldVal = put(orber_forward_notify, true),
-
- case catch corba_object:non_existent(ObjRef, Ctx) of
- {location_forward, Result} ->
- put(orber_forward_notify, OldVal),
- Result;
- false ->
- put(orber_forward_notify, OldVal),
- ObjRef;
- true ->
- put(orber_forward_notify, OldVal),
- lookup({corbaloc, Addresses, Key}, Ctx);
- _ ->
- %% May be located on a version using '_not_existent'
- %% see CORBA2.3.1 page 15-34 try again.
- case catch corba_object:not_existent(ObjRef, Ctx) of
- {location_forward, Result} ->
- put(orber_forward_notify, OldVal),
- Result;
- false ->
- put(orber_forward_notify, OldVal),
- ObjRef;
- _ ->
- put(orber_forward_notify, OldVal),
- lookup({corbaloc, Addresses, Key}, Ctx)
- end
- end;
-
-lookup({corbaloc, [_|Addresses], Key}, Ctx) ->
- lookup({corbaloc, Addresses, Key}, Ctx);
-
-
-lookup({file, File}, _Ctx) ->
- case file:read_file(File) of
- {ok, IOR} ->
- binary_to_list(IOR);
- {error, Reason} ->
- orber:dbg("[~p] orber_cosnaming_utils:lookup(~p);~n"
- "Failed to access file: ~p.",
- [?LINE, File, Reason], ?DEBUG_LEVEL),
- corba:raise(#'CosNaming_NamingContext_InvalidName'{})
- end;
-lookup({http, Host, Port, Key}, _Ctx) ->
- SetupTimeout = orber:iiop_setup_connection_timeout(),
- SendTimeout = orber:iiop_timeout(),
- {ok, Socket} = create_connection(Host, Port, SetupTimeout),
- Request = "GET " ++ Key ++ " HTTP/1.0\r\n\r\n",
- case gen_tcp:send(Socket, Request) of
- ok ->
- receive_msg(Socket, [], SendTimeout);
- {error, Reason} ->
- orber:dbg("[~p] orber_cosnaming_utils:lookup();~n"
- "Failed to send request: ~p.",
- [?LINE, Reason], ?DEBUG_LEVEL),
- corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO})
- end;
-lookup({ftp, _Address}, _Ctx) ->
- corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{});
-lookup(_, _Ctx) ->
- corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{}).
-
-
-receive_msg(Socket, Acc, Timeout) ->
- receive
- {tcp_closed, Socket} ->
- case re:split(Acc,"\r\n\r\n",[{return,list}]) of
- [_Header, Body] ->
- Body;
- What ->
- orber:dbg("[~p] orber_cosnaming_utils:receive_msg();~n"
- "HTTP server closed the connection before sending a complete reply: ~p.",
- [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO})
- end;
- {tcp, Socket, Response} ->
- receive_msg(Socket, Acc ++ Response, Timeout);
- {tcp_error, Socket, Reason} ->
- orber:dbg("[~p] orber_cosnaming_utils:receive_msg();~n"
- "connection failed: ~p.",
- [?LINE, Reason], ?DEBUG_LEVEL),
- gen_tcp:close(Socket),
- corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO})
- after Timeout ->
- gen_tcp:close(Socket),
- corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO})
- end.
-
-create_connection(Host, Port, Timeout) ->
- case gen_tcp:connect(Host,Port,[{packet,0},{reuseaddr,true}], Timeout) of
- {ok,Socket} ->
- {ok,Socket};
- Error ->
- orber:dbg("[~p] orber_cosnaming_utils:create_connection(~p, ~p, ~p);~n"
- "Reason: ~p",
- [?LINE, Host, Port, Timeout, Error], ?DEBUG_LEVEL),
- corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO})
- end.
-
-%%----------------------------------------------------------------------
-%% Function : key2id
-%% Arguments : An objectkey (e.g. NameService)
-%% Description:
-%% Returns : The associated IFR-id
-%%----------------------------------------------------------------------
-key2id(Key) ->
- %% We need this test to avoid returning an exit if an XX:typeID()
- %% fails (e.g. the module doesn't exist).
- case catch key2id_helper(Key) of
- {ok, Id} ->
- Id;
- _ ->
- ""
- end.
-
-
-key2id_helper("NameService") ->
- {ok, 'CosNaming_NamingContext':typeID()};
-key2id_helper("RootPOA") ->
- {ok, "IDL:omg.org/PortableServer/POA:1.0"};
-key2id_helper("POACurrent") ->
- {ok, "IDL:omg.org/PortableServer/Current:1.0"};
-key2id_helper("InterfaceRepository") ->
- {ok, "IDL:omg.org/CORBA/Repository:1.0"};
-key2id_helper("TradingService") ->
- {ok, "IDL:omg.org/CosTrading/Lookup:1.0"};
-key2id_helper("TransactionCurrent") ->
- {ok, "IDL:omg.org/CosTransactions/Current:1.0"};
-key2id_helper("DynAnyFactory") ->
- {ok, "IDL:omg.org/DynamicAny/DynAnyFactory:1.0"};
-key2id_helper("ORBPolicyManager") ->
- {ok, "IDL:omg.org/CORBA/PolicyManager:1.0"};
-key2id_helper("PolicyCurrent") ->
- {ok, "IDL:omg.org/CORBA/PolicyCurrent:1.0"};
-key2id_helper("NotificationService") ->
- {ok, "IDL:omg.org/CosNotifyChannelAdmin/EventChannelFactory:1.0"};
-key2id_helper("TypedNotificationService") ->
- {ok, "IDL:omg.org/CosTypedNotifyChannelAdmin::TypedEventChannelFactory:1.0"};
-key2id_helper("CodecFactory") ->
- {ok, "IDL:omg.org/IOP/CodecFactory:1.0"};
-key2id_helper("PICurrent") ->
- {ok, "IDL:omg.org/PortableInterceptors/Current:1.0"};
-%% Should we use SecurityLevel1 instead?? This key can be either.
-key2id_helper("SecurityCurrent") ->
- {ok, "IDL:omg.org/SecurityLevel2/Current:1.0"};
-%% Unknown - use the empty string. Might not work for all other ORB's but it's
-%% the only option we've got.
-key2id_helper(_) ->
- {ok, ""}.
-
-
-
-%%----------------------------------------------------------------------
-%% Function : name2string
-%% Arguments : A sequence of NameComponents
-%% Description:
-%% Returns : A string describing the sequence.
-%%----------------------------------------------------------------------
-name2string(Name) ->
- name2string(lists:reverse(Name), []).
-name2string([], Acc) ->
- lists:flatten(Acc);
-name2string([#'CosNaming_NameComponent'{id="", kind=""}], Acc) ->
- name2string([], [$.|Acc]);
-name2string([#'CosNaming_NameComponent'{id=ID, kind=""}], Acc) ->
- name2string([], [convert_reserved(ID)|Acc]);
-name2string([#'CosNaming_NameComponent'{id=ID, kind=Kind}], Acc) ->
- name2string([], [convert_reserved(ID), $., convert_reserved(Kind)|Acc]);
-name2string([#'CosNaming_NameComponent'{id="", kind=""}|T], Acc) ->
- name2string(T, [$/, $.|Acc]);
-name2string([#'CosNaming_NameComponent'{id=ID, kind=""}|T], Acc) ->
- name2string(T, [$/, convert_reserved(ID)|Acc]);
-name2string([#'CosNaming_NameComponent'{id=ID, kind=Kind}|T], Acc) ->
- name2string(T, [$/, convert_reserved(ID), $., convert_reserved(Kind)|Acc]);
-name2string(What, Acc) ->
- orber:dbg("[~p] orber_cosnaming_utils:name2string(~p)~n"
- "Malformed NameComponent: ~p",
- [?LINE, Acc, What], ?DEBUG_LEVEL),
- corba:raise(#'CosNaming_NamingContext_InvalidName'{}).
-
-%% '/' and '.' are reserved as separators but can be overridden by using '\'.
-convert_reserved([]) ->
- [];
-convert_reserved([$/|T]) ->
- [$\\, $/|convert_reserved(T)];
-convert_reserved([$.|T]) ->
- [$\\, $.|convert_reserved(T)];
-convert_reserved([$\\, H|T]) ->
- [$\\, H|convert_reserved(T)];
-convert_reserved([H|T]) ->
- [H|convert_reserved(T)].
-
-
-%%----------------------------------------------------------------------
-%% Function : string2name
-%% Arguments : A string describing a sequence of NameComponents.
-%% Description:
-%% Returns : A sequence of NameComponents
-%%----------------------------------------------------------------------
-string2name([]) ->
- [];
-string2name(Str) ->
- {NC, Rest} = get_NC(id, Str, [], []),
- [NC|string2name(Rest)].
-
-get_NC(id, [], ID, _Kind) ->
- {#'CosNaming_NameComponent'{id=lists:reverse(ID), kind=""}, []};
-get_NC(kind, [], ID, Kind) ->
- {#'CosNaming_NameComponent'{id=lists:reverse(ID), kind=lists:reverse(Kind)}, []};
-%% // is not allowed; must be /./
-get_NC(id, [$/|_T], [], _) ->
- orber:dbg("[~p] orber_cosnaming_utils:get_NC();~n"
- "'//' not allowed, use '/./'", [?LINE], ?DEBUG_LEVEL),
- corba:raise(#'CosNaming_NamingContext_InvalidName'{});
-get_NC(id, [$., $/|T], [], _) ->
- {#'CosNaming_NameComponent'{id="", kind=""}, T};
-%% End of this ID/Kind; in this case kind eq. "".
-get_NC(id, [$/|T], ID, _Kind) ->
- {#'CosNaming_NameComponent'{id=lists:reverse(ID), kind=""}, T};
-get_NC(kind, [$/|T], ID, Kind) ->
- {#'CosNaming_NameComponent'{id=lists:reverse(ID), kind=lists:reverse(Kind)}, T};
-%% ID exist but it's not allowed to write "id1./id2.kind2".
-get_NC(id, [$., $/|_T], _, _) ->
- orber:dbg("[~p] orber_cosnaming_utils:get_NC();~n"
- "'id1./id2.kind2' not allowed, use 'id1/id2.kind2'",
- [?LINE], ?DEBUG_LEVEL),
- corba:raise(#'CosNaming_NamingContext_InvalidName'{});
-get_NC(id, [$\\, $., H|T], ID, Kind) ->
- get_NC(id, T, [H, $.|ID], Kind);
-get_NC(id, [$\\, $/, H|T], ID, Kind) ->
- get_NC(id, T, [H, $/|ID], Kind);
-get_NC(kind, [$\\, $., H|T], ID, Kind) ->
- get_NC(kind, T, ID, [H|Kind]);
-get_NC(kind, [$\\, $/, H|T], ID, Kind) ->
- get_NC(kind, T, ID, [H|Kind]);
-get_NC(id, [$.|T], ID, Kind) ->
- get_NC(kind, T, ID, Kind);
-get_NC(id, [H|T], ID, Kind) ->
- get_NC(id, T, [H|ID], Kind);
-get_NC(kind, [H|T], ID, Kind) ->
- get_NC(kind, T, ID, [H|Kind]);
-get_NC(Type, Data, ID, Kind) ->
- orber:dbg("[~p] orber_cosnaming_utils:get_NC(~p, ~p, ~p, ~p);~n"
- "Unknown", [?LINE, Type, Data, ID, Kind], ?DEBUG_LEVEL),
- corba:raise(#'CosNaming_NamingContext_InvalidName'{}).
-
-
-%% Converts \< to '%3c'
-escape_string(Str) ->
- escape_string(Str, []).
-escape_string([], Acc) ->
- lists:reverse(Acc);
-escape_string([$\\, Char |T], Acc) ->
- escape_string(T, [code_character(16#0f band Char),
- code_character(16#0f band (Char bsr 4)),$%|Acc]);
-escape_string([Char|T], Acc) ->
- escape_string(T, [Char|Acc]).
-
-
-code_character(N) when N < 10 ->
- $0 + N;
-code_character(N) ->
- $a + (N - 10).
-
-%% Converts '%3c' to \<
-unescape_string(Str) ->
- unescape_string(Str, []).
-unescape_string([], Acc) ->
- lists:reverse(Acc);
-unescape_string([$%, H1, H2 |T], Acc) ->
- I1 = hex2int(H1),
- I2 = hex2int(H2),
- I = I1 * 16 + I2,
- unescape_string(T, [I, $\\|Acc]);
-unescape_string([H|T], Acc) ->
- unescape_string(T, [H|Acc]).
-
-hex2int(H) when H >= $a ->
- 10 + H - $a;
-hex2int(H) when H >= $A ->
- 10 + H -$A;
-hex2int(H) ->
- H - $0.
-
-%%-------------------------- END OF MODULE -----------------------------
diff --git a/lib/orber/Makefile b/lib/orber/Makefile
deleted file mode 100644
index 7db588f206..0000000000
--- a/lib/orber/Makefile
+++ /dev/null
@@ -1,42 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include vsn.mk
-VSN=$(ORBER_VSN)
-
-# ----------------------------------------------------
-# Common Macros
-# ----------------------------------------------------
-
-SUB_DIRECTORIES = COSS/CosNaming src java_src c_src examples doc/src priv
-
-SPECIAL_TARGETS =
-
-# ----------------------------------------------------
-# Default Subdir Targets
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_subdir.mk
-
diff --git a/lib/orber/c_src/InitialReference.cc b/lib/orber/c_src/InitialReference.cc
deleted file mode 100644
index 053f3c9c8e..0000000000
--- a/lib/orber/c_src/InitialReference.cc
+++ /dev/null
@@ -1,206 +0,0 @@
-/**
- *<copyright>
- * <year>1997-2007</year>
- * <holder>Ericsson AB, All Rights Reserved</holder>
- *</copyright>
- *<legalnotice>
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * The Initial Developer of the Original Code is Ericsson AB.
- *</legalnotice>
- */
-/**
- * InitialReference is a class which generates the INIT reference
- * which can be used by the InitialReferences interface.
- *
- * creation date: 1997-11-04
- */
-#include "InitialReference.hh"
-
-InitialReference::InitialReference()
-{
- host = 0;
- iorString = 0;
-};
-
-InitialReference::~InitialReference()
-{
- if(host){
- delete host;
- delete iorString;
- }
-};
-
- /**
- * Returns the stringified objectreference to the initial reference server
- */
-char* InitialReference::stringified_ior(char* newhost, int newport)
-{
- STRINGSTREAM iorByteString;
- STRINGSTREAM profileData;
-
- STRINGBUF *s;
- STRINGBUF *profileDataBuf;
- STRINGBUF *iorByteStringBuf;
- long profileDataLength = 0;
- char *str;
-
- // byte_order followed by ' {"", [{0, '
- // char iorBytesFirstPart[] = {0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0};
- char iorBytesFirstPart[48] = {0,0,0,0,0,0,0,32,73,68,76,58,79,114,98,101,114,47,73,110,105,116,105,97,108,82,101,102,101,114,101,110,99,101,115,58,49,46,48,0,0,0,0,1,0,0,0,0};
- // the objectkey "INIT
- char iorBytesLastPart[8] = {0,0,0,4,73,78,73,84};
-
- // Fix the ProfileData struct.
- char pdPrefix[4] = {0,1,0,0};
- char hsize[4];
- char profileDataLengthBytes[4];
- char portbytes[2];
- long hostLength = strlen(newhost);
-
-
- if(host)
- if(strcmp(newhost, host) == 0 && newport == port)
- return iorString;
- else {
- delete host;
- delete iorString;
- }
- host = new char[hostLength+1];
- memcpy(host, newhost, hostLength+1);
- port = newport;
-
- enc_ulong(hostLength + 1, hsize);
- enc_ushort(port, portbytes);
-
- profileDataBuf = profileData.rdbuf();
-
- profileDataBuf->sputn(pdPrefix, 4);
- profileDataBuf->sputn(hsize, 4);
- profileDataBuf->sputn(host, hostLength);
- profileDataBuf->sputc(0);
- profileDataLength = 4 + 4 + hostLength + 1;
-
- profileDataLength = align(profileDataBuf, profileDataLength, 2);
-
- profileDataBuf->sputn(portbytes, 2);
- profileDataLength += 2;
-
- profileDataLength = align(profileDataBuf, profileDataLength, 4);
-
- profileDataBuf->sputn(iorBytesLastPart, 8);
- profileDataLength += 8;
- //cout << "pd length: " << profileDataLength << "\n";
-
- enc_ulong(profileDataLength, profileDataLengthBytes);
-
- // Fix the whole IOR
-
- iorByteStringBuf = iorByteString.rdbuf();
-
- iorByteStringBuf->sputn(iorBytesFirstPart, 48);
- iorByteStringBuf->sputn(profileDataLengthBytes, 4);
-#ifdef HAVE_SSTREAM
- iorByteStringBuf->sputn(profileData.str().data(), profileDataLength);
-#else
- str = profileData.str();
- iorByteStringBuf->sputn(str, profileDataLength);
- delete str;
-#endif
-
- createIOR(iorByteString, 48 + 4 + profileDataLength);
-
- return iorString;
-}
-
-
-void InitialReference::enc_ushort(int s, char *byteArray)
-{
- byteArray[0] = (char) ((s >> 8) & 0xFF);
- byteArray[1] = (char) ((s >> 0) & 0xFF);
-
- return;
-}
-
-void InitialReference::enc_ulong(long l, char *byteArray)
-{
- byteArray[0] = (char) ((l >> 24) & 0xFF);
- byteArray[1] = (char) ((l >> 16) & 0xFF);
- byteArray[2] = (char) ((l >> 8) & 0xFF);
- byteArray[3] = (char) ((l >> 0) & 0xFF);
-
- return;
-}
-
-void InitialReference::createIOR(strstream& byte, long length)
-{
- STRINGBUF *stringbuf;
- STRINGSTREAM string;
-
- int i;
-#ifdef HAVE_SSTREAM
- const char *c;
- const char *bytestr = byte.str().c_str();
-#else
- char *c;
- char *bytestr = byte.str();
-#endif
- int b, n1, n2, c1, c2;
-
- stringbuf = string.rdbuf();
- stringbuf->sputn("IOR:",4);
-
- for(i = 0, c = bytestr; i < length; c++, i++)
- {
- b = *c;
- if(b<0) b+= 256;
- n1 = b / 16;
- n2 = b % 16;
- c1 = (n1 < 10) ? ('0' + n1) : ('a' + (n1 - 10));
- c2 = (n2 < 10) ? ('0' + n2) : ('a' + (n2 - 10));
-
- stringbuf->sputc(c1);
- stringbuf->sputc(c2);
-
- }
-
- stringbuf->sputc(0);
-
- delete bytestr;
-
-#ifdef HAVE_SSTREAM
- iorString = (char *)string.str().c_str();
-#else
- iorString = string.str();
-#endif
-
- return;
-}
-
-long InitialReference::align(STRINGBUF* sbuf, long currentLength,
- int alignment)
-{
- long length = currentLength;
-
- int remainder = alignment - (currentLength % alignment);
- if (remainder == alignment) return length;
-
- for (int i = 0; i < remainder; i++)
- {
- sbuf->sputc(0);
- length++;
- }
- return length;
-}
-
-
diff --git a/lib/orber/c_src/InitialReference.hh b/lib/orber/c_src/InitialReference.hh
deleted file mode 100644
index 79725522db..0000000000
--- a/lib/orber/c_src/InitialReference.hh
+++ /dev/null
@@ -1,60 +0,0 @@
-/**
- *<copyright>
- * <year>1997-2007</year>
- * <holder>Ericsson AB, All Rights Reserved</holder>
- *</copyright>
- *<legalnotice>
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * The Initial Developer of the Original Code is Ericsson AB.
- *</legalnotice>
- */
-/*
- * InitialReference is a class for creating an external IOR for the object
- * reference INIT.
- */
-#ifndef _INITIALREFERENCE_HH
-#define _INITIALREFERENCE_HH
-#include <stdio.h>
-#include <string.h>
-
-#if HAVE_SSTREAM
-#include <sstream>
-typedef std::stringstream STRINGSTREAM;
-typedef std::stringbuf STRINGBUF;
-#else
-#include <strstream.h>
-typedef strstream STRINGSTREAM;
-typedef strstreambuf STRINGBUF;
-#endif
-
-class InitialReference {
-private:
- char* iorString;
- char* host;
- int port;
-
- void enc_ushort(int s, char *byteArray);
- void enc_ulong(long l, char *byteArray);
- void createIOR(STRINGSTREAM& byte, long length);
- long align(STRINGBUF* sbuf, long currentLength, int alignment);
-
-public:
- InitialReference();
- ~InitialReference();
-
- char* stringified_ior(char* host, int port);
-
-};
-
-#endif
diff --git a/lib/orber/c_src/Makefile b/lib/orber/c_src/Makefile
deleted file mode 100644
index bad1d3ddb0..0000000000
--- a/lib/orber/c_src/Makefile
+++ /dev/null
@@ -1,24 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-# Invoke with GNU make or clearmake -C gnu.
-#
-
-include $(ERL_TOP)/make/run_make.mk
diff --git a/lib/orber/c_src/Makefile.in b/lib/orber/c_src/Makefile.in
deleted file mode 100644
index 980e780451..0000000000
--- a/lib/orber/c_src/Makefile.in
+++ /dev/null
@@ -1,100 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-CXX = @CXX@
-CC = @CC@
-LIBS = @LIBS@
-
-OBJDIR = ../priv/obj/$(TARGET)
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(ORBER_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/orber-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-CC_FILES = \
- InitialReference.cc
-
-HH_FILES = \
- InitialReference.hh
-
-ALL_CFLAGS = @CFLAGS@ @DEFS@ $(CFLAGS)
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug opt: $(OBJDIR) orber
-
-ifeq ($(findstring win32,$(TARGET)),win32)
-orber:
- $(V_colon)echo "Nothing to build on NT"
-else
-orber:
- $(V_colon)echo "Nothing to build"
-endif
-
-clean:
-
-docs:
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-$(OBJDIR):
- -mkdir -p $(OBJDIR)
-
-$(OBJDIR)/%.o: %.c
- $(V_CC) -c -o $@ $(ALL_CFLAGS) $<
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-ifeq ($(findstring win32,$(TARGET)),win32)
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/priv/src"
- $(INSTALL_DIR) "$(RELSYSDIR)/priv/include"
- $(INSTALL_PROGRAM) $(CC_FILES) "$(RELSYSDIR)/priv/src"
- $(INSTALL_PROGRAM) $(HH_FILES) "$(RELSYSDIR)/priv/include"
-else
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/priv/src"
- $(INSTALL_DIR) "$(RELSYSDIR)/priv/include"
- $(INSTALL_DATA) $(CC_FILES) "$(RELSYSDIR)/priv/src"
- $(INSTALL_DATA) $(HH_FILES) "$(RELSYSDIR)/priv/include"
-endif
-
-
-release_docs_spec:
diff --git a/lib/orber/c_src/main.cc b/lib/orber/c_src/main.cc
deleted file mode 100644
index 109aaf824a..0000000000
--- a/lib/orber/c_src/main.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- *<copyright>
- * <year>1997-2007</year>
- * <holder>Ericsson AB, All Rights Reserved</holder>
- *</copyright>
- *<legalnotice>
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * The Initial Developer of the Original Code is Ericsson AB.
- *</legalnotice>
- */
-
-#include "InitialReference.hh"
-
-main()
-{
- InitialReference ir;
-
- cout << ir.stringified_ior("fingolfin", 4001) << "\n";
-
-
-}
diff --git a/lib/orber/doc/etc/.gitignore b/lib/orber/doc/etc/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/orber/doc/etc/.gitignore
+++ /dev/null
diff --git a/lib/orber/doc/html/.gitignore b/lib/orber/doc/html/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/orber/doc/html/.gitignore
+++ /dev/null
diff --git a/lib/orber/doc/javadoc/.gitignore b/lib/orber/doc/javadoc/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/orber/doc/javadoc/.gitignore
+++ /dev/null
diff --git a/lib/orber/doc/man1/.gitignore b/lib/orber/doc/man1/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/orber/doc/man1/.gitignore
+++ /dev/null
diff --git a/lib/orber/doc/man3/.gitignore b/lib/orber/doc/man3/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/orber/doc/man3/.gitignore
+++ /dev/null
diff --git a/lib/orber/doc/pdf/.gitignore b/lib/orber/doc/pdf/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/orber/doc/pdf/.gitignore
+++ /dev/null
diff --git a/lib/orber/doc/src/CosNaming.xml b/lib/orber/doc/src/CosNaming.xml
deleted file mode 100644
index 251e721df1..0000000000
--- a/lib/orber/doc/src/CosNaming.xml
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1997</year><year>2017</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>CosNaming</title>
- <prepared></prepared>
- <docno></docno>
- <checked></checked>
- <date>1997-06-10</date>
- <rev>A</rev>
- </header>
- <module>CosNaming</module>
- <modulesummary>The CosNaming service is a collection of interfaces that together define the naming service.</modulesummary>
- <description>
- <p>The naming service provides the principal mechanism for clients to find
- objects in an ORB based world. The naming service provides an initial naming
- context that functions as the root context for all names. Given this context
- clients can navigate in the name space. </p>
- <p>Types that are declared on the CosNaming level are:</p>
- <code type="none"><![CDATA[
-typedef string Istring;
-struct NameComponent {
- Istring id;
- Istring kind;
-};
-
-typedef sequence <NameComponent> Name;
-
-enum BindingType {nobject, ncontext};
-
-struct Binding {
- Name binding_name;
- BindingType binding_type;
-};
-
-typedef sequence <Binding> BindingList;
- ]]></code>
- <p>To get access to the record definitions for the structs use:</p>
- <code>-include_lib("orber/COSS/CosNaming.hrl").</code>
- <p>Names are not an ORB object but the can be structured in components as seen by
- the definition above. There are no requirements on names so the service can support
- many different conventions and standards.</p>
- <p>There are two different interfaces supported in the service:</p>
- <list type="bulleted">
- <item>NamingContext</item>
- <item>BindingIterator</item>
- </list>
- </description>
-
-</erlref>
-
diff --git a/lib/orber/doc/src/CosNaming_BindingIterator.xml b/lib/orber/doc/src/CosNaming_BindingIterator.xml
deleted file mode 100644
index 69b0f42b22..0000000000
--- a/lib/orber/doc/src/CosNaming_BindingIterator.xml
+++ /dev/null
@@ -1,99 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1997</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosNaming_BindingIterator</title>
- <prepared></prepared>
- <docno></docno>
- <checked></checked>
- <date>1997-06-10</date>
- <rev>A</rev>
- </header>
- <module>CosNaming_BindingIterator</module>
- <modulesummary>This interface supports iteration over a name binding list.</modulesummary>
- <description>
- <p>This interface allows a client to iterate over the Bindinglist it has been
- initiated with.</p>
- <p>The type <c>NameComponent</c> used below is defined as:</p>
- <code type="none">
- -record('CosNaming_NameComponent', {id, kind=""}).
- </code>
- <p><c>id</c> and <c>kind</c> are strings. </p>
- <p>The type <c>Binding</c> used below is defined as:</p>
- <code type="none">
- -record('CosNaming_Binding', {binding_name, binding_type}).
- </code>
- <p><c>binding_name</c> is a <c>Name = [NameComponent]</c> and
- <c>binding_type</c> is an enum which
- has the values <c>nobject</c> and <c>ncontext</c>.</p>
- <p>Both these records are defined in the file <c>CosNaming.hrl</c> and it
- is included with:</p>
- <code type="none">
- -include_lib("orber/COSS/CosNaming/CosNaming.hrl").
- </code>
- </description>
- <funcs>
- <func>
- <name>next_one(BindinIterator) -> Return</name>
- <fsummary>Return a binding</fsummary>
- <type>
- <v>BindingIterator = #objref</v>
- <v>Return = {bool(), Binding}</v>
- </type>
- <desc>
- <p>This operation returns the next binding and a boolean. The latter
- is set to true if the binding is valid otherwise false. If the boolean
- is false there are no more bindings to retrieve.</p>
- </desc>
- </func>
- <func>
- <name>next_n(BindinIterator, HowMany) -> Return</name>
- <fsummary>Return a binding list</fsummary>
- <type>
- <v>BindingIterator = #objref</v>
- <v>HowMany = int()</v>
- <v>BindingList = [Binding]</v>
- <v>Return = {bool(), BindingList}</v>
- </type>
- <desc>
- <p>This operation returns a binding list with at most HowMany bindings.
- If there are no more bindings it returns false otherwise true.</p>
- </desc>
- </func>
- <func>
- <name>destroy(BindingIterator) -> Return</name>
- <fsummary>Destroy the iterator object</fsummary>
- <type>
- <v>BindingIterator = #objref</v>
- <v>Return = ok</v>
- </type>
- <desc>
- <p>This operation destroys the binding iterator.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/orber/doc/src/CosNaming_NamingContext.xml b/lib/orber/doc/src/CosNaming_NamingContext.xml
deleted file mode 100644
index 4c83e6a240..0000000000
--- a/lib/orber/doc/src/CosNaming_NamingContext.xml
+++ /dev/null
@@ -1,243 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1997</year><year>2017</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>CosNaming_NamingContext</title>
- <prepared></prepared>
- <docno></docno>
- <checked></checked>
- <date>1997-06-10</date>
- <rev>A</rev>
- </header>
- <module>CosNaming_NamingContext</module>
- <modulesummary>This interface supports different bind and access functions for names in a context.</modulesummary>
- <description>
- <p>This is the object that defines name scopes, names must be unique within a
- naming context. Objects may have multiple names and may exist in multiple
- naming contexts. Name context may be named in other contexts and cycles are
- permitted.</p>
- <p>The type <c>NameComponent</c> used below is defined as:</p>
- <code type="erl">-record('CosNaming_NameComponent', {id, kind=""}).</code>
- <p>where <c>id</c> and <c>kind</c> are strings. </p>
- <p>The type <c>Binding</c> used below is defined as:</p>
- <code type="erl">-record('CosNaming_Binding', {binding_name, binding_type}).</code>
- <p>where <c>binding_name</c> is a Name and <c>binding_type</c> is an enum which
- has the values <c>nobject</c> and <c>ncontext</c>.</p>
- <p>Both these records are defined in the file <c>CosNaming.hrl</c> and it
- is included with:</p>
- <code type="erl">-include_lib("orber/COSS/CosNaming/CosNaming.hrl").</code>
- <p>There are a number of exceptions that can be returned from functions in this
- interface.</p>
- <list type="bulleted">
- <item>
- <p>NotFound is defined as </p>
- <code type="erl">
--record('CosNaming_NamingContext_NotFound',
- {rest_of_name, why}).</code>
- </item>
- <item>
- <p>CannotProceed is defined as </p>
- <code type="erl">
--record('CosNaming_NamingContext_CannotProceed',
- {rest_of_name, cxt}).
- </code>
- </item>
- <item>
- <p>InvalidName is defined as </p>
- <code type="erl">
--record('CosNaming_NamingContext_InvalidName', {}).
- </code>
- </item>
- <item>
- <p>NotFound is defined as </p>
- <code type="erl">-record('CosNaming_NamingContext_NotFound', {}).</code>
- </item>
- <item>
- <p>AlreadyBound is defined as </p>
- <code type="erl">-record('CosNaming_NamingContext_AlreadyBound', {}).</code>
- </item>
- <item>
- <p>NotEmpty is defined as </p>
- <code type="erl">-record('CosNaming_NamingContext_NotEmpty', {}).</code>
- </item>
- </list>
- <p>These exceptions are defined in the file <c>CosNaming_NamingContext.hrl</c> and it
- is included with:</p>
- <code type="erl">
--include_lib("orber/COSS/CosNaming/CosNaming_NamingContext.hrl").
- </code>
- </description>
- <funcs>
- <func>
- <name>bind(NamingContext, Name, Object) -> Return</name>
- <fsummary>Bind a Name to an Object</fsummary>
- <type>
- <v>NameContext = #objref</v>
- <v>Name = [NameComponent]</v>
- <v>Object = #objref</v>
- <v>Return = ok</v>
- </type>
- <desc>
- <p>Creates a binding of a name and an object in the naming context.
- Naming contexts that are bound using <em>bind()</em> do not participate
- in name resolution.</p>
- </desc>
- </func>
- <func>
- <name>rebind(NamingContext, Name, Object) -> Return</name>
- <fsummary>Bind an Object to the Name even if the Name already is bound</fsummary>
- <type>
- <v>NamingContext = #objref</v>
- <v>Name = [NameComponent]</v>
- <v>Object = #objref</v>
- <v>Return = ok</v>
- </type>
- <desc>
- <p>Creates a binding of a name and an object in the naming context even
- if the name is already bound. Naming contexts that are bound using
- <em>rebind()</em> do not participate in name resolution.</p>
- </desc>
- </func>
- <func>
- <name>bind_context(NamingContext1, Name, NamingContex2) -> Return</name>
- <fsummary>Bind a Name to an NamingContext</fsummary>
- <type>
- <v>NamingContext1 = NamingContext2 =#objref</v>
- <v>Name = [NameComponent]</v>
- <v>Return = ok</v>
- </type>
- <desc>
- <p>The bind_context function creates a binding of a name and a naming context in
- the current context.
- Naming contexts that are bound using <em>bind_context()</em> participate
- in name resolution.</p>
- </desc>
- </func>
- <func>
- <name>rebind_context(NamingContext1, Name, NamingContex2) -> Return</name>
- <fsummary>Bind an NamingContext to the Name even if the Name already is bound</fsummary>
- <type>
- <v>NamingContext1 = NamingContext2 =#objref</v>
- <v>Name = [NameComponent]</v>
- <v>Return = ok</v>
- </type>
- <desc>
- <p>The rebind_context function creates a binding of a name and a naming context in
- the current context even if the name already is bound.
- Naming contexts that are bound using <em>rebind_context()</em> participate
- in name resolution.</p>
- </desc>
- </func>
- <func>
- <name>resolve(NamingContext, Name) -> Return</name>
- <fsummary>Retrieve an Object bound to Name</fsummary>
- <type>
- <v>NamingContext = #objref</v>
- <v>Name = [NameComponent]</v>
- <v>Return = Object</v>
- <v>Object = #objref</v>
- </type>
- <desc>
- <p>The resolve function is the way to retrieve an object bound to a name in
- the naming context. The given name must match exactly the bound name. The
- type of the object is not returned, clients are responsible for narrowing
- the object to the correct type.</p>
- </desc>
- </func>
- <func>
- <name>unbind(NamingContext, Name) -> Return</name>
- <fsummary>Remove the binding for a Name</fsummary>
- <type>
- <v>NamingContext = #objref</v>
- <v>Name = [NameComponent]</v>
- <v>Return = ok</v>
- </type>
- <desc>
- <p>The unbind operation removes a name binding from the naming context.</p>
- </desc>
- </func>
- <func>
- <name>new_context(NamingContext) -> Return</name>
- <fsummary>Create a new NamingContext</fsummary>
- <type>
- <v>NamingContext = #objref</v>
- <v>Return = #objref</v>
- </type>
- <desc>
- <p>The new_context operation creates a new naming context.</p>
- </desc>
- </func>
- <func>
- <name>bind_new_context(NamingContext, Name) -> Return</name>
- <fsummary>Create a new NamingContext and bind it to a Name</fsummary>
- <type>
- <v>NamingContext = #objref</v>
- <v>Name = [NameComponent]</v>
- <v>Return = #objref</v>
- </type>
- <desc>
- <p>The new_context operation creates a new naming context and binds it to
- Name in the current context.</p>
- </desc>
- </func>
- <func>
- <name>destroy(NamingContext) -> Return</name>
- <fsummary>Destroy a NamingContext</fsummary>
- <type>
- <v>NamingContext = #objref</v>
- <v>Return = ok</v>
- </type>
- <desc>
- <p>The destroy operation disposes the NamingContext object and removes it from the
- name server. The context must be empty e.g. not contain any bindings to be
- removed.</p>
- </desc>
- </func>
- <func>
- <name>list(NamingContext, HowMany) -> Return</name>
- <fsummary>List returns a all bindings in the context</fsummary>
- <type>
- <v>NamingContext = #objref</v>
- <v>HowMany = int()</v>
- <v>Return = {ok, BindingList, BindingIterator}</v>
- <v>BindingList = [Binding]</v>
- <v>BindingIterator = #objref</v>
- </type>
- <desc>
- <p>The list operation returns a BindingList with a number of bindings up-to
- HowMany from the context. It also returns a BindinIterator which can be used to
- step through the list. If the total number of existing bindings are less
- than, or equal to, the <c>HowMany</c> parameter a NIL object reference
- is returned.</p>
- <p></p>
- <note>
- <p>One must destroy the BindingIterator, unless it is a NIL object
- reference, by using 'BindingIterator':destroy(). Otherwise one can get
- dangling objects.</p>
- </note>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/orber/doc/src/CosNaming_NamingContextExt.xml b/lib/orber/doc/src/CosNaming_NamingContextExt.xml
deleted file mode 100644
index 2af3deadda..0000000000
--- a/lib/orber/doc/src/CosNaming_NamingContextExt.xml
+++ /dev/null
@@ -1,102 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2000</year><year>2017</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>CosNaming_NamingContextExt</title>
- <prepared></prepared>
- <docno></docno>
- <checked></checked>
- <date>2000-08-16</date>
- <rev>A</rev>
- </header>
- <module>CosNaming_NamingContextExt</module>
- <modulesummary>This interface contains operation for converting a Name sequence to a string and back.</modulesummary>
- <description>
- <p>To get access to the record definitions for the structures use: <br></br>
-</p>
- <code type="erl">
--include_lib("orber/COSS/CosNaming/CosNaming.hrl").
- </code>
- <p>This module also exports the functions described in:</p>
- <list type="bulleted">
- <item>
- <p><seealso marker="CosNaming_NamingContext">CosNaming_NamingContext</seealso></p>
- </item>
- </list>
- </description>
- <funcs>
- <func>
- <name>to_string(NamingContext, Name) -> Return</name>
- <fsummary>Stringify a <c>Name</c>sequence to a string</fsummary>
- <type>
- <v>NameContext = #objref</v>
- <v>Name = [NameComponent]</v>
- <v>Return = string() | {'EXCEPTION', NamingContext::InvalidName{}}</v>
- </type>
- <desc>
- <p>Stringifies a <c>Name</c> sequence to a string.</p>
- </desc>
- </func>
- <func>
- <name>to_name(NamingContext, NameString) -> Return</name>
- <fsummary>Convert a stringified <c>Name</c>to a <c>Name</c>sequence</fsummary>
- <type>
- <v>NameContext = #objref</v>
- <v>NameString = string()</v>
- <v>Return = [NameComponent] | {'EXCEPTION', NamingContext::InvalidName{}}</v>
- </type>
- <desc>
- <p>Converts a stringified <c>Name</c> to a <c>Name</c> sequence.</p>
- </desc>
- </func>
- <func>
- <name>to_url(NamingContext, AddressString, NameString) -> Return</name>
- <fsummary>Return an URL string constructed from the given Address and Name strings</fsummary>
- <type>
- <v>NameContext = #objref</v>
- <v>Address = NameString = string()</v>
- <v>Return = URLString | {'EXCEPTION', NamingContext::InvalidName{}} | {'EXCEPTION', NamingContextExt::InvalidAddress{}}</v>
- </type>
- <desc>
- <p>This operation takes a <c>corbaloc</c> string and a stringified <c>Name</c>
- sequence as input and returns a fully formed URL string.</p>
- </desc>
- </func>
- <func>
- <name>resolve_str(NamingContext, NameString) -> Return</name>
- <fsummary>Return the object associated, if any, with the given name string</fsummary>
- <type>
- <v>NameContext = #objref</v>
- <v>NameString = string()</v>
- <v>Return = #objref | {'EXCEPTION', NamingContext::InvalidName{}} | {'EXCEPTION', NamingContext::NotFound{why, rest_of_name}} | {'EXCEPTION', NamingContext::CannotProceed{cxt, rest_of_name}}</v>
- </type>
- <desc>
- <p>This operation takes a stringified <c>Name</c> sequence as input and
- returns the associated, if any, object.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/orber/doc/src/Makefile b/lib/orber/doc/src/Makefile
deleted file mode 100644
index c77345f12b..0000000000
--- a/lib/orber/doc/src/Makefile
+++ /dev/null
@@ -1,172 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1997-2017. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../../vsn.mk
-VSN=$(ORBER_VSN)
-APPLICATION=orber
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-XML_APPLICATION_FILES = ref_man.xml
-XML_REF3_FILES = \
- any.xml \
- corba.xml \
- corba_object.xml \
- orber.xml \
- CosNaming.xml \
- CosNaming_NamingContext.xml \
- CosNaming_NamingContextExt.xml \
- CosNaming_BindingIterator.xml \
- lname.xml \
- lname_component.xml \
- orber_ifr.xml \
- orber_tc.xml \
- Module_Interface.xml \
- interceptors.xml \
- fixed.xml \
- orber_diagnostics.xml \
- orber_acl.xml
-
-XML_PART_FILES = \
- part.xml
-
-XML_CHAPTER_FILES = \
- ch_contents.xml \
- ch_introduction.xml \
- ch_orber_kernel.xml \
- ch_ifr.xml \
- ch_install.xml \
- ch_idl_to_erlang_mapping.xml \
- ch_naming_service.xml \
- ch_stubs.xml \
- ch_security.xml \
- notes.xml \
- ch_exceptions.xml \
- ch_interceptors.xml \
- ch_orberweb.xml \
- ch_debugging.xml
-
-BOOK_FILES = book.xml
-
-XML_FILES = $(BOOK_FILES) $(XML_APPLICATION_FILES) $(XML_REF3_FILES) \
- $(XML_PART_FILES) $(XML_CHAPTER_FILES)
-
-TECHNICAL_DESCR_FILES =
-
-GIF_FILES = \
- name.gif \
- orbs.gif \
- theORB.gif \
- iiop.gif \
- dependent.gif \
- interceptor_operations.gif \
- menuframe.gif \
- dataframe1.gif \
- dataframe2.gif \
- dataframe3.gif \
- dataframe4.gif \
- dataframe5.gif \
- dataframe6.gif \
- dataframe7.gif \
- dataframe8.gif \
- firewall_nat.gif
-
-# ----------------------------------------------------
-
-INTERNAL_HTML_FILES = $(TECHNICAL_DESCR_FILES:%.xml=$(HTMLDIR)/%.html)
-
-HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \
- $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html) \
- $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html)
-
-INFO_FILE = ../../info
-EXTRA_FILES = \
- $(DEFAULT_GIF_FILES) \
- $(DEFAULT_HTML_FILES) \
- $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html)
-
-MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-
-HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
-
-TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-XML_FLAGS +=
-DVIPS_FLAGS +=
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-$(HTMLDIR)/%.gif: %.gif
- $(INSTALL_DATA) $< $@
-
-
-docs: pdf html man
-
-$(TOP_PDF_FILE): $(XML_FILES)
-
-pdf: $(TOP_PDF_FILE)
-
-html: gifs $(HTML_REF_MAN_FILE)
-
-clean clean_docs:
- rm -rf $(HTMLDIR)/*
- rm -f $(MAN3DIR)/*
- rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
- rm -f errs core *~
- rm -f $(JD_HTML) $(JD_PACK)
-
-man: $(MAN3_FILES)
-
-gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
-
-debug opt:
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_docs_spec: docs
- $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
- $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
- $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
- $(INSTALL_DATA) $(HTMLDIR)/* \
- "$(RELSYSDIR)/doc/html"
- $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
- $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
- $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
-
-release_spec:
diff --git a/lib/orber/doc/src/Module_Interface.xml b/lib/orber/doc/src/Module_Interface.xml
deleted file mode 100644
index a809bcf02f..0000000000
--- a/lib/orber/doc/src/Module_Interface.xml
+++ /dev/null
@@ -1,356 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1999</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>Module_Interface</title>
- <prepared></prepared>
- <docno></docno>
- <checked></checked>
- <date>1999-09-03</date>
- <rev>A</rev>
- </header>
- <module>Module_Interface</module>
- <modulesummary>Orber generated stubs/skeletons.</modulesummary>
- <description>
- <p>This module contains the stub/skeleton functions generated by IC.</p>
- <p>Starting a Orber server can be done in three ways:</p>
- <list type="bulleted">
- <item>Normal - when the server dies Orber forgets all knowledge of the server.</item>
- <item>Supervisor child - adding the configuration parameter <c>{sup_child, true}</c>
- the <c>oe_create_link/2</c> function returns <c>{ok, Pid, ObjRef}</c> which
- can be handled by the application <em>supervisor/stdlib-1.7</em> or later. </item>
- <item>Persistent object reference - adding the configuration parameters <c>{persistent, true}</c>
- and <c>{regname, {global, term()}}</c> Orber will remember the object reference until the
- server terminates with reason <em>normal</em> or <em>shutdown</em>. Hence,
- if the server is started as a <em>transient</em> supervisor child we do not
- receive a 'OBJECT_NOT_EXIST' exception when it has crashed and is being restarted.</item>
- </list>
- <p>The Orber stub can be used to start a <c>pseudo object</c>, which will create a non-server implementation.
- A pseudo object introduce some limitations:</p>
- <list type="bulleted">
- <item>The functions <c>oe_create_link/2</c> is equal to <c>oe_create/2</c>, i.e.,
- no link can or will be created.</item>
- <item>The <c>BIF:s self()</c> and <c>process_flag(trap_exit,true)</c> behaves incorrectly.</item>
- <item>The <c>IC</c> option <c>{{impl, "M::I"}, "other_impl"}</c> has no effect. The call-back
- functions must be implemented in a file called <c>M_I_impl.erl</c></item>
- <item>The <c>IC</c> option <c>from</c> has no effect. </item>
- <item>The call-back functions must be implemented as if the <c>IC</c> option
- <c>{this, "M::I"}</c> was used.</item>
- <item>Server <c>State</c> changes have no effect. The user can provide information via
- the <c>Env</c> start parameter and the State returned from <c>init/2</c> will be the State
- passed in following invocations.</item>
- <item>If a call-back function replies with the <c>Timeout</c> parameter set it have no effect.</item>
- <item>Operations defined as <c>oneway</c> are blocking until the operation replies.</item>
- <item>The option <c>{pseudo, true}</c> overrides all other start options.</item>
- <item>Only the functions, besides own definitions, <c>init/2</c> (called via oe_create*/2) and
- <c>terminate/2</c> (called via corba:dispose/1) must be implemented.</item>
- </list>
- <p>By adopting the rules for <c>pseudo</c> objects described above we can use <c>oe_create/2</c>
- to create <c>server</c> or <c>pseudo</c> objects, by excluding or including the
- option <c>{pseudo, true}</c>, without changing the call-back module.
- </p>
- <p>If you start a object without <c>{regname, RegName}</c> it can only be accessed through the returned object key.
- Started with a <c>{regname, RegName}</c> the name is registered locally or globally.
- </p>
- <warning>
- <p>To avoid flooding Orber with old object references start erlang using the flag
- <em>-orber objectkeys_gc_time Time</em>, which will remove all object references
- related to servers being dead for Time seconds. To avoid extra overhead, i.e., performing
- garbage collect if no persistent objects are started, the objectkeys_gc_time default value
- is <em>infinity</em>. For more information, see the orber and corba documentation.</p>
- </warning>
- </description>
- <funcs>
- <func>
- <name>Module_Interface:typeID() -> TypeId</name>
- <fsummary>Return the Type ID related to this stub/skeleton</fsummary>
- <type>
- <v>TypeId = string(), e.g., "IDL:Module/Interface:1.0"</v>
- </type>
- <desc>
- <p>Returns the Type ID related to this stub/skeleton</p>
- </desc>
- </func>
- <func>
- <name>Module_Interface:oe_create() -> ObjRef</name>
- <fsummary>Start a Orber server.</fsummary>
- <type>
- <v>ObjRef = #object reference</v>
- </type>
- <desc>
- <p>Start a Orber server.</p>
- </desc>
- </func>
- <func>
- <name>Module_Interface:oe_create_link() -> ObjRef</name>
- <fsummary>Start a linked Orber server.</fsummary>
- <type>
- <v>ObjRef = #object reference</v>
- </type>
- <desc>
- <p>Start a linked Orber server.</p>
- </desc>
- </func>
- <func>
- <name>Module_Interface:oe_create(Env) -> ObjRef</name>
- <fsummary>Start a Orber server.</fsummary>
- <type>
- <v>Env = term()</v>
- <v>ObjRef = #object reference</v>
- </type>
- <desc>
- <p>Start a Orber server passing Env to <c>init/1</c>.</p>
- </desc>
- </func>
- <func>
- <name>Module_Interface:oe_create_link(Env) -> ObjRef</name>
- <fsummary>Start a linked Orber server.</fsummary>
- <type>
- <v>Env = term()</v>
- <v>ObjRef = #object reference</v>
- </type>
- <desc>
- <p>Start a linked Orber server passing Env to <c>init/1</c>.</p>
- </desc>
- </func>
- <func>
- <name>Module_Interface:oe_create(Env, Options) -> ObjRef</name>
- <fsummary>Start a Orber stub/skeleton</fsummary>
- <type>
- <v>Env = term()</v>
- <v>ObjRef = #object reference</v>
- <v>Options = [{sup_child, false} | {persistent, Bool} | {regname, RegName} | {pseudo, Bool} | {local_typecheck, Bool} | {survive_exit, Bool} | {create_options, [CreateOpts]}]</v>
- <v>Bool = true | false</v>
- <v>RegName = {global, term()} | {local, atom()}</v>
- <v>CreateOpts = {debug, [Dbg]} | {timeout, Time}</v>
- <v>Dbg = trace | log | statistics | {log_to_file, FileName}</v>
- </type>
- <desc>
- <p>Start a Orber server passing Env to <c>init/1</c>.</p>
- <p>If the option <c>{pseudo, true}</c> is used, all other options are overridden.
- As default, this option is set to false.</p>
- <p>This function cannot be used for starting a server as supervisor child.
- If started as <c>persistent</c>, the options <c>[{persistent, true}, {regname, {global, term()}}]</c> must be used and
- Orber will only forget the object reference if it terminates with reason <em>normal</em> or <em>shutdown</em>.</p>
- <p>The option <c>{local_typecheck, boolean()}</c>, which overrides the
- <seealso marker="ch_install#flags">Local Typechecking</seealso>
- environment flag, turns on or off typechecking. If activated,
- parameters, replies and raised exceptions will be checked to ensure that
- the data is correct, when invoking operations on CORBA Objects within
- the same Orber domain. Due to the extra overhead, this option
- <em>MAY ONLY</em> be used during testing and development.</p>
- <p><c>{survive_exit, boolean()}</c> overrides the
- <seealso marker="ch_install#flags">EXIT Tolerance</seealso>
- environment flag. If activated, the server will not terminate, even though
- the call-back module returns EXIT.</p>
- <p><c>Time</c> specifies how long time, in milliseconds, the server is allowed to
- spend initializing. For more information about the <c>Dbg</c> options,
- see the <c>sys</c> module.</p>
- </desc>
- </func>
- <func>
- <name>Module_Interface:oe_create_link(Env, Options) -> Return</name>
- <fsummary>Start a Orber stub/skeleton</fsummary>
- <type>
- <v>Env = term()</v>
- <v>Return = ObjRef | {ok, Pid, ObjRef}</v>
- <v>ObjRef = #object reference</v>
- <v>Options = [{sup_child, Bool} | {persistent, Bool} | {regname, RegName} | {pseudo, Bool} | {local_typecheck, Bool} | {survive_exit, Bool} | {create_options, [CreateOpts]}]</v>
- <v>Bool = true | false</v>
- <v>RegName = {global, term()} | {local, atom()}</v>
- <v>CreateOpts = {debug, [Dbg]} | {timeout, Time}</v>
- <v>Dbg = trace | log | statistics | {log_to_file, FileName}</v>
- <v></v>
- <v></v>
- <v></v>
- </type>
- <desc>
- <p>Start a linked Orber server passing Env to <c>init/1</c>.</p>
- <p>If the option <c>{pseudo, true}</c> is used, all other options are overridden and no link will be created.
- As default, this option is set to false.</p>
- <p>This function can be used for starting a server as persistent or supervisor child. At the moment
- <c>[{persistent, true}, {regname, {global, term()}}]</c> must be used to start
- a server as persistent, i.e., if a server died and is in the process of being restarted
- a call to the server will not raise <c>'OBJECT_NOT_EXIST'</c> exception.
- Orber will only forget the object reference if it terminates with reason <em>normal</em> or <em>shutdown</em>,
- hence, the server must be started as <em>transient</em> (for more information see the
- supervisor documentation).</p>
- <p>The options <c>{local_typecheck, boolean()}</c> and <c>{survive_exit, boolean()}</c>
- behaves in the same way as for <c>oe_create/2</c>.</p>
- <p><c>Time</c> specifies how long time, in milliseconds, the server is allowed to
- spend initializing. For more information about the <c>Dbg</c> options,
- see the <c>sys</c> module.</p>
- </desc>
- </func>
- <func>
- <name>Module_Interface:own_functions(ObjRef, Arg1, ..., ArgN) -> Reply</name>
- <name>Module_Interface:own_functions(ObjRef, Options, Arg1, ..., ArgN) -> Reply</name>
- <fsummary>User defined function which is not a part of Orber</fsummary>
- <type>
- <v>ObjRef = #object reference</v>
- <v>Options = [Option] | Timeout</v>
- <v>Option = {timeout, Timeout} | {context, [Context]}</v>
- <v>Timeout = infinity | integer(milliseconds)</v>
- <v>Context = #'IOP_ServiceContext'{context_id = CtxId, context_data = CtxData}</v>
- <v>CtxId = ?ORBER_GENERIC_CTX_ID</v>
- <v>CtxData = {interface, Interface} | {userspecific, term()} | {configuration, Options}</v>
- <v>Interface = string()</v>
- <v>Options = [{Key, Value}]</v>
- <v>Key = ssl_client_verify | ssl_client_depth | ssl_client_certfile | ssl_client_cacertfile |
- ssl_client_password | ssl_client_keyfile | ssl_client_ciphers | ssl_client_cachetimeout</v>
- <v>Value = allowed value associated with the given key</v>
- <v>ArgX = specified in the IDL-code.</v>
- <v>Reply = specified in the IDL-code.</v>
- </type>
- <desc>
- <p>The default value for the <c>Timeout</c> option is <c>infinity</c>.
- IPv4 or IPv6 addresses are accepted as local Interface.</p>
- <p>The <em>configuration</em> context is used to override the global
- SSL client side
- <seealso marker="ch_install#config">configuration</seealso>.</p>
- <p>To gain access to <c>#'IOP_ServiceContext'{}</c> record and the
- <c>?ORBER_GENERIC_CTX_ID</c> macro, you must add
- <c>-include_lib("orber/include/corba.hrl").</c> to your module.</p>
- </desc>
- </func>
- </funcs>
-
- <section>
- <title>CALLBACK FUNCTIONS</title>
- <p>The following functions should be exported from a <c>CORBA</c>
- callback module. Note, a complete template of the call-back module can
- be generated automatically by compiling the IDL-file with the IC option
- <c>{be,erl_template}</c>. One should also add
- the same compile options, for example <c>this</c> or <c>from</c>,
- used when generating the stub/skeleton modules.</p>
- </section>
- <funcs>
- <func>
- <name>Module_Interface_impl:init(Env) -> CallReply</name>
- <fsummary>User defined function which is not a part of Orber</fsummary>
- <type>
- <v>Env = term()</v>
- <v>CallReply = {ok, State} | {ok, State, Timeout} | ignore | {stop, StopReason}</v>
- <v>State = term()</v>
- <v>Timeout = int() >= 0 | infinity</v>
- <v>StopReason = term()</v>
- </type>
- <desc>
- <p>Whenever a new server is started, <em>init/1</em> is the first function called in the specified call-back module.</p>
- </desc>
- </func>
- <func>
- <name>Module_Interface_impl:terminate(Reason, State) -> ok</name>
- <fsummary>User defined function which is not a part of Orber</fsummary>
- <type>
- <v>Reason = term()</v>
- <v>State = term()</v>
- </type>
- <desc>
- <p>This call-back function is called whenever the server is about to terminate.</p>
- </desc>
- </func>
- <func>
- <name>Module_Interface_impl:code_change(OldVsn, State, Extra) -> CallReply</name>
- <fsummary>User defined function which is not a part of Orber</fsummary>
- <type>
- <v>OldVsn = undefined | term()</v>
- <v>State = term()</v>
- <v>Extra = term()</v>
- <v>CallReply = {ok, NewState}</v>
- <v>NewState = term()</v>
- </type>
- <desc>
- <p>Update the internal <c>State</c>.</p>
- </desc>
- </func>
- <func>
- <name>Module_Interface_impl:handle_info(Info, State) -> CallReply</name>
- <fsummary>User defined function which is not a part of Orber</fsummary>
- <type>
- <v>Info = term()</v>
- <v>State = term()</v>
- <v>CallReply = {noreply, State} | {noreply, State, Timeout} | {stop, StopReason, State}</v>
- <v>Timeout = int() >= 0 | infinity</v>
- <v>StopReason = normal | shutdown | term()</v>
- </type>
- <desc>
- <p>If the configuration parameter <em>{{handle_info, "Module::Interface"}, true}</em>
- is passed to IC and <em>process_flag(trap_exit,true)</em> is set in the <em>init()</em>
- call-back this function must be exported. </p>
- <note>
- <p>To be able to handle the <c>Timeout</c> option in <c>CallReply</c> in the call-back
- module the configuration parameter <em>{{handle_info, "Module::Interface"}, true}</em> must
- be passed to IC. </p>
- </note>
- </desc>
- </func>
- <func>
- <name>Module_Interface_impl:own_functions(State, Arg1, ..., ArgN) -> CallReply</name>
- <name>Module_Interface_impl:own_functions(This, State, Arg1, ..., ArgN) -> CallReply</name>
- <name>Module_Interface_impl:own_functions(This, From, State, Arg1, ..., ArgN) -> ExtCallReply</name>
- <name>Module_Interface_impl:own_functions(From, State, Arg1, ..., ArgN) -> ExtCallReply</name>
- <fsummary>User defined function which is not a part of Orber</fsummary>
- <type>
- <v>This = the servers #object reference</v>
- <v>State = term()</v>
- <v>ArgX = specified in the IDL-code.</v>
- <v>CallReply = {reply, Reply, State} | {reply, Reply, State, Timeout} | {stop, StopReason, Reply, State} | {stop, StopReason, State} | corba:raise(Exception)</v>
- <v>ExtCallReply = CallReply | corba:reply(From, Reply), {noreply, State} | corba:reply(From, Reply), {noreply, State, Timeout}</v>
- <v>Reply = specified in the IDL-code.</v>
- <v>Timeout = int() >= 0 | infinity</v>
- <v>StopReason = normal | shutdown | term()</v>
- </type>
- <desc>
- <p>All two-way functions must return one of the listed replies or raise any of
- the exceptions listed in the IDL code (i.e. raises(...)).
- If the IC compile options <em>this</em> and/or <em>from</em> are used,
- the implementation must accept the <em>This</em> and/or <em>From</em>
- parameters.</p>
- </desc>
- </func>
- <func>
- <name>Module_Interface_impl:own_functions(State, Arg1, ..., ArgN) -> CastReply</name>
- <name>Module_Interface_impl:own_functions(This, State, Arg1, ..., ArgN) -> CastReply</name>
- <fsummary>User defined function which is not a part of Orber</fsummary>
- <type>
- <v>This = the servers #object reference</v>
- <v>State = term()</v>
- <v>CastReply = {noreply, State} | {noreply, State, Timeout} | {stop, StopReason, State}</v>
- <v>ArgX = specified in the IDL-code.</v>
- <v>Reply = specified in the IDL-code.</v>
- <v>Timeout = int() >= 0 | infinity</v>
- <v>StopReason = normal | shutdown | term()</v>
- </type>
- <desc>
- <p>All one-way functions must return one of the listed replies.
- If the IC compile option <em>this</em> is used,
- the implementation must accept the <em>This</em> parameter.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/orber/doc/src/Orber/InitialReference.java b/lib/orber/doc/src/Orber/InitialReference.java
deleted file mode 100644
index 35a8c2437b..0000000000
--- a/lib/orber/doc/src/Orber/InitialReference.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1997-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-/**
- * InitialReference is a class which generates the INIT reference
- * which can be used by the InitialReferences interface.
- */
-package Orber;
-
-public class InitialReference
-{
-
- /**
- * Constructor.
- */
- public InitialReference(){;}
-
- /**
- * Returns the stringified objectreference to the initial reference server
- */
- public String stringified_ior(String host, int port)
- {
- String iorByteString;
- String profileData;
- String iorString;
-
- // byte_order followed by ' {"", [{0, '
- // char iorBytesFirstPart[] = {0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0};
- char iorBytesFirstPart[] = {0,0,0,0,0,0,0,32,73,68,76,58,79,114,98,101,114,47,73,110,105,116,105,97,108,82,101,102,101,114,101,110,99,101,115,58,49,46,48,0,0,0,0,1,0,0,0,0};
- // the objectkey "INIT
- char iorBytesLastPart[] = {0,0,0,4,73,78,73,84};
-
- // Fix the ProfileData struct.
- char pdPrefix[] = {0,1,0,0};
- char nullbyte[] = {0};
- profileData = new String(pdPrefix) + enc_ulong(host.length() + 1) + host + new String(nullbyte);
- profileData = align(profileData, 2);
- profileData += enc_ushort(port);
- profileData = align(profileData, 4);
- profileData += new String(iorBytesLastPart);
- // Fix the whole IOR
- iorByteString = new String(iorBytesFirstPart) + enc_ulong(profileData.length()) +
- profileData;
-
- // System.out.print("Start[" + profileData.length() + "]");
- // System.out.print("[");
- // for(int x = 0; x < iorByteString.length(); x++)
- // {
- // System.out.print((int) iorByteString.charAt(x) + ",");
- // }
- // System.out.println("]");
-
- iorString = createIOR(iorByteString);
- // System.out.println(iorString);
- return iorString;
- }
-
-
- private String enc_ushort(int s)
- {
- char byteArray[] = {(char) ((s >>> 8) & 0xFF),
- (char) ((s >>> 0) & 0xFF)};
-
- return new String(byteArray);
- }
-
- private String enc_ulong(int l)
- {
- char byteArray[] = {(char) ((l >>> 24) & 0xFF),
- (char) ((l >>> 16) & 0xFF),
- (char) ((l >>> 8) & 0xFF),
- (char) ((l >>> 0) & 0xFF)};
-
- return new String(byteArray);
-
- }
-
- private String createIOR(String bytes)
- {
- int i;
- StringBuffer sb = new StringBuffer("IOR:");
-
- for(i = 0; i < bytes.length(); i++)
- {
- int b = bytes.charAt(i);
- if(b<0) b+= 256;
- int n1 = b / 16;
- int n2 = b % 16;
- int c1 = (n1 < 10) ? ('0' + n1) : ('a' + (n1 - 10));
- int c2 = (n2 < 10) ? ('0' + n2) : ('a' + (n2 - 10));
- sb.append((char)c1);
- sb.append((char)c2);
- }
-
- return sb.toString();
- }
-
- private String align(String buffer, int alignment)
- {
- String s = buffer;
- char nullbyte[] = {0};
-
- int remainder = alignment - (buffer.length() % alignment);
- if (remainder == alignment) return s;
-
- for (int i = 0; i < remainder; i++)
- {
- s += new String(nullbyte);
- }
- return s;
- }
-
-
-}
diff --git a/lib/orber/doc/src/Orber/Makefile b/lib/orber/doc/src/Orber/Makefile
deleted file mode 100644
index 16a3994499..0000000000
--- a/lib/orber/doc/src/Orber/Makefile
+++ /dev/null
@@ -1,71 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../../vsn.mk
-VSN=$(ORBER_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/orber-$(VSN)
-
-#
-# JAVA macros
-#
-JAVA_CLASSES = \
- InitialReference
-
-JAVA_FILES= $(JAVA_CLASSES:%=%.java)
-
-CLASSPATH = ../..
-
-# ----------------------------------------------------
-# Flags
-# ----------------------------------------------------
-JAVA_OPTIONS =
-
-# ----------------------------------------------------
-# Make Rules
-# ----------------------------------------------------
-
-debug opt:
-
-clean:
-
-docs:
-
-# ----------------------------------------------------
-# Release Targets
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/java_src/Orber
- $(INSTALL_DATA) $(JAVA_FILES) $(RELSYSDIR)/java_src/Orber
-
-release_docs_spec:
-
diff --git a/lib/orber/doc/src/any.xml b/lib/orber/doc/src/any.xml
deleted file mode 100644
index c94a2132d8..0000000000
--- a/lib/orber/doc/src/any.xml
+++ /dev/null
@@ -1,114 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1998</year><year>2017</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>any</title>
- <prepared></prepared>
- <docno></docno>
- <checked></checked>
- <date>1998-04-20</date>
- <rev>A</rev>
- </header>
- <module>any</module>
- <modulesummary>the corba any type</modulesummary>
- <description>
- <p>This module contains functions that gives an interface to the CORBA any type.</p>
- <p>Note that the <c>any</c> interface in orber does not contain a destroy
- function because the any type is represented as an Erlang record and
- therefor will be removed by the garbage collector when not in use.</p>
- <p>The type <c>TC</c> used below describes an IDL type and is a tuple according
- to the to the Erlang language mapping.</p>
- <p>The type <c>Any</c> used below is defined as:</p>
- <code type="erl">-record(any, {typecode, value}).</code>
- <p>where <c>typecode</c> is a TC tuple and <c>value</c> is an Erlang term of
- the type defined by the typecode field.</p>
- </description>
- <funcs>
- <func>
- <name>create() -> Result</name>
- <name>create(Typecode, Value) -> Result</name>
- <fsummary>Create an any record</fsummary>
- <type>
- <v>Typecode = TC</v>
- <v>Value = term()</v>
- <v>Result = Any</v>
- </type>
- <desc>
- <p>The create/0 function creates an empty any record and the create/2
- function creates an initialized record.</p>
- </desc>
- </func>
- <func>
- <name>set_typecode(A, Typecode) -> Result</name>
- <fsummary>Set the typecode field</fsummary>
- <type>
- <v>A = Any</v>
- <v>Typecode = TC</v>
- <v>Result = Any</v>
- </type>
- <desc>
- <p>This function sets the typecode of <em>A</em> and returns a
- new any record.</p>
- </desc>
- </func>
- <func>
- <name>get_typecode(A) -> Result</name>
- <fsummary>Fetch the typecode</fsummary>
- <type>
- <v>A = Any</v>
- <v>Result = TC</v>
- </type>
- <desc>
- <p>This function returns the typecode of <em>A</em>.</p>
- </desc>
- </func>
- <func>
- <name>set_value(A, Value) -> Result</name>
- <fsummary>Set the value field</fsummary>
- <type>
- <v>A = Any</v>
- <v>Value = term()</v>
- <v>Result = Any</v>
- </type>
- <desc>
- <p>This function sets the value of <em>A</em> and returns a
- new any record.</p>
- </desc>
- </func>
- <func>
- <name>get_value(A) -> Result</name>
- <fsummary>Fetch the value</fsummary>
- <type>
- <v>A = Any</v>
- <v>Result = term()</v>
- </type>
- <desc>
- <p>This function returns the value of <em>A</em>.
- </p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/orber/doc/src/book.xml b/lib/orber/doc/src/book.xml
deleted file mode 100644
index 81bd5a8f65..0000000000
--- a/lib/orber/doc/src/book.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE book SYSTEM "book.dtd">
-
-<book xmlns:xi="http://www.w3.org/2001/XInclude">
- <header titlestyle="normal">
- <copyright>
- <year>1997</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>orber</title>
- <prepared></prepared>
- <docno></docno>
- <date>1998-04-25</date>
- <rev>2.0</rev>
- </header>
- <insidecover>
- </insidecover>
- <pagetext>Orber</pagetext>
- <preamble>
- <contents level="2"></contents>
- </preamble>
- <parts lift="no">
- <xi:include href="part.xml"/>
- </parts>
- <applications>
- <xi:include href="ref_man.xml"/>
- </applications>
- <releasenotes>
- <xi:include href="notes.xml"/>
- </releasenotes>
- <listofterms></listofterms>
- <index></index>
-</book>
-
diff --git a/lib/orber/doc/src/ch_contents.xml b/lib/orber/doc/src/ch_contents.xml
deleted file mode 100644
index b783e63aee..0000000000
--- a/lib/orber/doc/src/ch_contents.xml
+++ /dev/null
@@ -1,173 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1999</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>The Orber Application</title>
- <prepared></prepared>
- <docno></docno>
- <date>1998-05-05</date>
- <rev>B</rev>
- <file>ch_contents.xml</file>
- </header>
-
- <section>
- <title>Content Overview</title>
- <p>The Orber documentation is divided into three sections:
- </p>
- <list type="bulleted">
- <item>
- <p>PART ONE - The User's Guide
- <br></br>
-Description of the Orber Application including IDL-to-Erlang
- language mapping, services and a small tutorial demonstrating
- the development of a simple service.</p>
- </item>
- <item>
- <p>PART TWO - Release Notes
- <br></br>
-A concise history of Orber.</p>
- </item>
- <item>
- <p>PART THREE - The Reference Manual
- <br></br>
- A quick reference guide, including a
- brief description, to all the functions available in Orber.</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Brief Description of the User's Guide</title>
- <p>The User's Guide contains the following parts:</p>
- <list type="bulleted">
- <item>
- <p>ORB kernel and IIOP support</p>
- </item>
- <item>
- <p>Interface Repository</p>
- </item>
- <item>
- <p>IDL to Erlang mapping</p>
- </item>
- <item>
- <p>CosNaming Service</p>
- </item>
- <item>
- <p>Resolving initial reference from Java or C++</p>
- </item>
- <item>
- <p>Tutorial - creating a simple service </p>
- </item>
- <item>
- <p>CORBA Exceptions </p>
- </item>
- <item>
- <p>Interceptors</p>
- </item>
- <item>
- <p>OrberWeb</p>
- </item>
- <item>
- <p>Debugging
- </p>
- </item>
- </list>
-
- <section>
- <title>ORB Kernel and IIOP Support</title>
- <p>The ORB kernel which has IIOP support will allow the creation
- of persistent server objects in Erlang. These objects can also
- be accessed via Erlang and Java environments. For the moment a
- Java enabled ORB is needed to generate Java from IDL to use
- Java server objects (this has been tested using OrbixWeb).</p>
- </section>
-
- <section>
- <title>Interface Repository</title>
- <p>The IFR is an interface repository used for some type-checking
- when coding/decoding IIOP. The IFR is capable of storing all
- interfaces and declarations of OMG IDL.</p>
- </section>
-
- <section>
- <title>IDL to Erlang Mapping</title>
- <p>The OMG IDL mapping for Erlang, which is necessary to access the
- functionality of Orber, is described, The mapping structure is
- included as the basic and the constructed OMG IDL types
- references, invocations and Erlang characteristics. An example is
- also provided.</p>
- </section>
-
- <section>
- <title>CosNaming Service</title>
- <p>Orber contains a CosNaming compliant service.</p>
- </section>
-
- <section>
- <title>Resolving Initial References from Java or C++</title>
- <p>A couple of classes are added to Orber to simplify initial
- reference access from Java or C++.
- </p>
- <p><em>Resolving initial reference from Java</em> <br></br>
- A class with only one method which returns an <term id="IOR"><termdef>Interoperable Object Reference</termdef></term>on the
- external string format to the INIT object (see "Interoperable
- Naming Service" specification).</p>
- <p><em>Resolving initial reference from C++</em> <br></br>
-
- A class (and header file) with only one method which returns
- an IOR on the external string format to the INIT object (see
- "Interoperable Naming Service" specification).</p>
- </section>
-
- <section>
- <title>Orber Stub/Skeleton</title>
- <p>An example which describes the API and behavior of Orber stubs and skeletons. </p>
- </section>
-
- <section>
- <title>CORBA Exceptions</title>
- <p>A listing of all system exceptions supported by Orber and how one should
- handle them. This chapter also describe how to generate user defined
- exceptions.</p>
- </section>
-
- <section>
- <title>Interceptors</title>
- <p>Descibes how to implement and activate interceptors.</p>
- </section>
-
- <section>
- <title>OrberWeb</title>
- <p>Offers the possibility to administrate and supervise Orber via a GUI.</p>
- </section>
-
- <section>
- <title>Debugging</title>
- <p>Describes how to use different tools when debugging and/or developing
- new applications using Orber. Also includes a FAQ, which deal with
- the most common mistakes when using Orber.
- </p>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/orber/doc/src/ch_debugging.xml b/lib/orber/doc/src/ch_debugging.xml
deleted file mode 100644
index debac4313e..0000000000
--- a/lib/orber/doc/src/ch_debugging.xml
+++ /dev/null
@@ -1,210 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2001</year><year>2017</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Debugging</title>
- <prepared></prepared>
- <docno></docno>
- <date>2001-11-29</date>
- <rev></rev>
- <file>ch_debugging.xml</file>
- </header>
-
- <section>
- <title>Tools and FAQ</title>
- <p>Persons who use Orber for the first time may find it hard to tell what goes
- wrong when trying to setup communication between an Orber-ORB and ORB:s supplied
- by another vendor or another Orber-ORB. The purpose of this chapter is to inform
- about the most common mistakes and what tools one can use to overcome these
- problems. </p>
-
- <section>
- <title>Tools</title>
- <p>To begin with, Orber can be configured to run in debug mode. There are four ways
- to set this parameter:</p>
- <list type="bulleted">
- <item><em>erl -orber orber_debug_level 10</em> - can be added to a start-script.</item>
- <item><em>corba:orb_init([{orber_debug_level, 10}])</em> - this operation must
- be invoked <em>before</em> starting Orber.</item>
- <item><em>orber:configure(orber_debug_level, 10)</em> - this operation can
- be invoked at any time.</item>
- <item><em>OrberWeb</em> - via the <c>Configuration</c> menu one can easily change
- the configuration. For more information, see the OrberWeb chapter in this
- User's Guide.</item>
- </list>
- <p>When Orber runs i debug mode, printouts will be generated if anything abnormal occurs
- (not necessarily an error). An error message typically looks like:</p>
- <code type="none">
-=ERROR REPORT==== 29-Nov-2001::14:09:55 ===
-=================== Orber =================
-[410] corba:common_create(orber_test_server, [{pseudo,truce}]);
-not a boolean(truce).
-===========================================
- </code>
- <p>In the example above, we tried to create an object with an incorrect option (i.e. should
- have been <c>{pseudo,true}</c>).</p>
- <p>If you are not able to solve the problem, you should include all generated reports when
- contacting support or using the erlang-questions mailing list.</p>
- <p>It is easy to forget to, for example, set all fields in a struct, which
- one may not discover when developing an application using Orber. When using
- a typed language, such faults would cause a compile time error. To avoid
- these mistakes, Orber allows the user to activate automatic typechecking
- of all local invocations of CORBA Objects. For this feature to be really
- useful, the user must create test suites which cover as much as
- possible. For example, invoking an operation with invalid or incorrect
- arguments should also be tested. This option can be activated for one object
- or all object via:</p>
- <list type="bulleted">
- <item><em>'MyModuyle_MyInterface':oe_create(Env, [{local_typecheck, true}])</em> -
- This approach will only activate, or deactivate, typechecking for
- the returned instance. Naturally, this option can also be passed
- to <c>oe_create_link/2</c>, <c>corba:create/4</c> and
- <c>corba:create_link/4</c>.</item>
- <item><em>erl -orber flags 2</em> - can be added to a start-script.
- All object invocations will be typechecked, unless overridden by the
- previous option.</item>
- <item><em>corba:orb_init([{flags, 16#0002}])</em> - this operation must
- be invoked <em>before</em> starting Orber. Behaves as the previous
- option.</item>
- </list>
- <p>If incorrect data is passed or returned, Orber uses the <c>error_logger</c>
- to generate logs, which can look like:</p>
- <code type="none">
-=ERROR REPORT==== 10-Jul-2002::12:36:09 ===
-========= Orber Typecheck Request =========
-Invoked......: MyModule_MyInterface:foo/1
-Typecode.....: [{tk_enum,"IDL:MyModule/enumerant:1.0",
- "enumerant",
- ["one","two"]}]
-Arguments....: [three]
-Result.......: {'EXCEPTION',{'MARSHAL',[],102,'COMPLETED_NO'}}
-===========================================
- </code>
- <p>Note, that the arity is equivalent to the IDL-file. In the example above,
- an undefined enumerant was used. In most cases, it is useful to set the
- configuration parameter <c>orber_debug_level 10</c> as well. Due to the
- extra overhead, this option <em>MAY ONLY</em> be used during testing and
- development.
- For more information, see also
- <seealso marker="ch_install#config">configuration settings</seealso>.</p>
- <p>It is also possible to trace all communication between an Orber-ORB and, for example,
- a Java-ORB, communicating via IIOP. All you need to do is to activate an
- <seealso marker="ch_interceptors">interceptor</seealso>. Normally, the users must
- implement the interceptor themselves, but for your convenience Orber includes three
- pre-compiled interceptors called <c>orber_iiop_tracer</c>,
- <c>orber_iiop_tracer_silent</c> and <c>orber_iiop_tracer_stealth</c>.</p>
- <warning>
- <p>Logging all traffic is <em>expensive</em>. Hence, only use the supplied
- interceptors during test and development.</p>
- </warning>
- <p>The <c>orber_iiop_tracer</c> and <c>orber_iiop_tracer_silent</c> interceptors
- uses the <c>error_logger</c> module to generate the logs. If the traffic
- is intense you probably want to write the reports to a log-file.
- This is done by, for example, invoking:</p>
- <code type="erl">
-erl> error_logger:tty(false).
-erl> error_logger:logfile({open, "/tmp/IIOPTrace"}).
- </code>
- <p>The <c>IIOPTrace</c> file will contain, if you use the <c>orber_iiop_tracer</c>
- interceptor, reports which looks like:</p>
- <code type="none">
-=INFO REPORT==== 13-Jul-2005::18:22:39 ===
-=============== new_out_connection =======
-Node : myNode@myHost
-From : 192.0.0.10:47987
-To : 192.0.0.20:4001
-==========================================
-
-=INFO REPORT==== 29-Nov-2001::15:26:28 ===
-=============== out_request ==============
-Connection: {"192.0.0.20",4001,"192.0.0.10",47987}
-Operation : resolve
-Parameters: [[{'CosNaming_NameComponent',
- "AIK","SwedishIcehockeyChampions"}]]
-Context : [{'IOP_ServiceContext',1,
- {'CONV_FRAME_CodeSetContext',65537,65801}}]
-==========================================
- </code>
- <p>The <c>orber_iiop_tracer_silent</c> will not log GIOP encoded data. To activate
- one the interceptors, you have two options:</p>
- <list type="bulleted">
- <item><em>erl -orber interceptors "{native,[orber_iiop_tracer]}"</em> - can be added to a start-script.</item>
- <item><em>corba:orb_init([{interceptors, {native, [orber_iiop_tracer_silent]}}])</em> - this operation must
- be invoked <em>before</em> starting Orber.</item>
- </list>
- <p>It is also possible to active and deactivate an interceptor during
- run-time, but this will only affect currently existing connections.
- For more information, consult Orber's Reference Manual regarding the
- operations <c>orber:activate_audit_trail/0/1</c> and
- <c>orber:activate_audit_trail/0/1.</c></p>
- </section>
-
- <section>
- <title>FAQ</title>
- <p><em>Q: When my client, typically written in C++ or Java, invoke narrow on an Orber object reference it fails?</em></p>
- <p>A: You must register your application in the IFR by invoking <c>oe_register()</c>.
- If the object was created by a COS-application, you must run install
- (e.g. <c>cosEventApp:install()</c>).</p>
- <p>A: Confirm, by consulting the IDL specifications, that the received object reference really
- inherit from the interface you are trying to narrow it to.</p>
- <br></br>
- <p><em>Q: I am trying to register my application in the IFR but it fails. Why?</em></p>
- <p>A: If one, or more, interface in your IDL-specification inherits from
- other interface(s), you must register them before registering your
- application. Note, this also apply when you inherit interfaces
- supported by a COS-application. Hence, they must be installed prior to
- registration of your application.</p>
- <br></br>
- <p><em>Q: I have a Orber client and server residing on two different Orber instances but I only get the 'OBJECT_NOT_EXIST' exception, even though I am sure that the object is still alive?</em></p>
- <p>A: If the two Orber-ORB's are not intended to be a part of multi-node ORB, make sure that the
- two Orber-ORB's have different <em>domain</em> names set (see
- <seealso marker="ch_install#config">configuration settings</seealso>). The easiest way
- to confirm this is to invoke <c>orber:info()</c> on each node.</p>
- <br></br>
- <p><em>Q: When I'm trying to install and/or start Orber it fails?</em></p>
- <p>A: Make sure that no other Orber-ORB is already running on the same node. If so,
- change the <c>iiop_port</c> configuration parameter (see
- <seealso marker="ch_install#config">configuration settings</seealso>).</p>
- <br></br>
- <p><em>Q: My Orber server is invoked via IIOP but Orber cannot marshal the reply?</em></p>
- <p>A: Consult your IDL file to confirm that your replies are of the correct
- type. If it is correct and the return type is, for example,
- a struct, make sure you have set every field in the struct. If
- you do not do that it will be set to the atom 'undefined', which
- most certainly is not correct.</p>
- <br></br>
- <p>A: Check that you handle <c>inout</c> and <c>out</c> parameters correctly
- (see the IDL specification). For example, a function which have one
- out-parameter and should return void, then your call-back module
- should return <c>{reply, {ok, OutParam}, State}</c>. Note, even though
- the return value is void (IDL) you must reply with ok.</p>
- <br></br>
- <p><em>Q: I cannot run Orber as a multi-node ORB?</em></p>
- <p>A: Make sure that the Erlang distribution have been started for each
- node and the <c>cookies</c> are correct. For more information,
- consult the <c>System Documentation</c></p>
- <br></br>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/orber/doc/src/ch_exceptions.xml b/lib/orber/doc/src/ch_exceptions.xml
deleted file mode 100644
index 17657d0d4a..0000000000
--- a/lib/orber/doc/src/ch_exceptions.xml
+++ /dev/null
@@ -1,238 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2001</year><year>2017</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>CORBA System and User Defined Exceptions</title>
- <prepared></prepared>
- <docno></docno>
- <date>2000-12-19</date>
- <rev></rev>
- <file>ch_exceptions.xml</file>
- </header>
-
- <section>
- <title>System Exceptions</title>
- <p><c>Orber</c>, or any other <c>ORB</c>, may raise a <c>System Exceptions</c>.
- These exceptions contain status- and minor-fields and may not appear in the
- operations raises exception IDL-definition.</p>
-
- <section>
- <title>Status Field</title>
- <p>The status field indicates if the request was completed or not and will be
- assigned one of the following Erlang atoms:</p>
- <table>
- <row>
- <cell align="center" valign="middle"><em>Status</em></cell>
- <cell align="center" valign="middle"><em>Description</em></cell>
- </row>
- <row>
- <cell align="left" valign="middle">'COMPLETED_YES'</cell>
- <cell align="left" valign="middle">The operation was invoked on the target object but an error occurred after the object replied. This occur, for example, if a server replies but Orber is not able to marshal and send the reply to the client ORB.</cell>
- </row>
- <row>
- <cell align="left" valign="middle">'COMPLETED_NO'</cell>
- <cell align="left" valign="middle">Orber failed to invoke the operation on the target object. This occur, for example, if the object no longer exists.</cell>
- </row>
- <row>
- <cell align="left" valign="middle">'COMPLETED_MAYBE'</cell>
- <cell align="left" valign="middle">Orber invoked the operation on the target object but an error occurred and it is impossible to decide if the request really reached the object or not.</cell>
- </row>
- <tcaption>System Exceptions Status</tcaption>
- </table>
- </section>
-
- <section>
- <title>Minor Field</title>
- <p>The minor field contains an integer (VMCID), which is related to a more
- specific reason why an invocation failed. The function
- <c>orber:exception_info/1</c> can be used to map the minor code to a string.
- Note, for VMCID:s not assigned by the OMG or Orber, the documentation
- for that particular ORB must be consulted.</p>
- </section>
-
- <section>
- <title>Supported System Exceptions</title>
- <p>The OMG CORBA specification defines the following exceptions:</p>
- <list type="bulleted">
- <item><em>'BAD_CONTEXT'</em> - if a request does not contain a correct
- context this exception is raised.</item>
- <item><em>'BAD_INV_ORDER'</em> - this exception indicates that operations
- has been invoked operations in the wrong order, which would cause,
- for example, a dead-lock.</item>
- <item><em>'BAD_OPERATION'</em> - raised if the target object exists, but
- that the invoked operation is not supported.</item>
- <item><em>'BAD_PARAM'</em> - is thrown if, for example, a parameter is out
- of range or otherwise considered illegal.</item>
- <item><em>'BAD_TYPECODE'</em> - if illegal type code is passed, for example,
- encapsulated in an any data type the <c>'BAD_TYPECODE'</c> exception
- will be raised.</item>
- <item><em>'BAD_QOS'</em> - raised whenever an object cannot support the
- required quality of service.</item>
- <item><em>'CODESET_INCOMPATIBLE'</em> - raised if two ORB's cannot
- communicate due to different representation of, for example,
- <c>char</c> and/or <c>wchar</c>.</item>
- <item><em>'COMM_FAILURE'</em> - raised if an ORB is unable to setup
- communication or it is lost while an operation is in progress.</item>
- <item><em>'DATA_CONVERSION'</em> - raised if an ORB cannot convert data
- received to the native representation. See also the
- <c>'CODESET_INCOMPATIBLE'</c> exception.</item>
- <item><em>'FREE_MEM'</em> - the ORB failed to free dynamic memory and
- failed.</item>
- <item><em>'IMP_LIMIT'</em> - an implementation limit was exceeded in the
- ORB at run time. A object factory may, for example, limit the
- number of object clients are allowed to create.</item>
- <item><em>'INTERNAL'</em> - an internal failure occurred in an ORB, which
- is unrecognized. You may consider contacting the ORB providers
- support.</item>
- <item><em>'INTF_REPOS'</em> - the ORB was not able to reach the interface
- repository, or some other failure relating to the interface
- repository is detected.</item>
- <item><em>'INITIALIZE'</em> - the ORB initialization failed due to, for
- example, network or configuration error.</item>
- <item><em>'INVALID_TRANSACTION'</em> - is raised if the request carried an
- invalid transaction context.</item>
- <item><em>'INV_FLAG'</em> - an invalid flag was passed to an operation,
- which caused, for example, a connection to be closed.</item>
- <item><em>'INV_IDENT'</em> - this exception indicates that an IDL
- identifier is incorrect.</item>
- <item><em>'INV_OBJREF'</em> - this exception is raised if an object
- reference is malformed or a nil reference (see
- also corba:create_nil_objref/0).</item>
- <item><em>'INV_POLICY'</em> - the invocation cannot be made due to an
- incompatibility between policy overrides that apply to the
- particular invocation.</item>
- <item><em>'MARSHAL'</em> - this exception may be raised by the client- or
- server-side when either ORB is unable to marshal/unmarshal requests or
- replies.</item>
- <item><em>'NO_IMPLEMENT'</em> - if the operation exists but no implementation
- exists, this exception is raised.</item>
- <item><em>'NO_MEMORY'</em> - the ORB has run out of memory.</item>
- <item><em>'NO_PERMISSION'</em> - the caller has insufficient privileges,
- such as, for example, bad <c>SSL</c> certificate.</item>
- <item><em>'NO_RESOURCES'</em> - a general platform resource limit
- exceeded.</item>
- <item><em>'NO_RESPONSE'</em> - no response available of a deferred
- synchronous request.</item>
- <item><em>'OBJ_ADAPTER'</em> - indicates administrative mismatch; the object
- adapter is not able to associate an object with the implementation
- repository.</item>
- <item><em>'OBJECT_NOT_EXIST'</em> - the object have been disposed or
- terminated; clients should remove all copies of the object reference
- and initiate desired recovery process.</item>
- <item><em>'PERSIST_STORE'</em> - the ORB was not able to establish a
- connection to its persistent storage or data contained in the
- the storage is corrupted.</item>
- <item><em>'REBIND'</em> - a request resulted in, for example, a
- <c>'LOCATION_FORWARD'</c> message; if the policies are incompatible
- this exception is raised.</item>
- <item><em>'TIMEOUT'</em> - raised if a request fail to complete within the
- given time-limit.</item>
- <item><em>'TRANSACTION_MODE'</em> - a transaction policy mismatch detected.</item>
- <item><em>'TRANSACTION_REQUIRED'</em> - a transaction is required for the
- invoked operation but the request contained no transaction context.</item>
- <item><em>'TRANSACTION_ROLLEDBACK'</em> - the transaction associated with
- the request has already been rolled back or will be.</item>
- <item><em>'TRANSACTION_UNAVAILABLE'</em> - no transaction context can be
- supplied since the ORB is unable to contact the Transaction
- Service.</item>
- <item><em>'TRANSIENT'</em> - the ORB could not determine the current status
- of an object since it could not be reached. The error may be
- temporary.</item>
- <item><em>'UNKNOWN'</em> - is thrown if an implementation throws a
- non-CORBA, or unrecognized, exception.</item>
- </list>
- </section>
- </section>
-
- <section>
- <title>User Defined Exceptions</title>
- <p>User exceptions is defined in IDL-files and is listed in operations raises
- exception listing. For example, if we have the following IDL code:</p>
- <code type="none">
-module MyModule {
-
- exception MyException {};
- exception MyExceptionMsg { string ExtraInfo; };
-
- interface MyInterface {
-
- void foo()
- raises(MyException);
-
- void bar()
- raises(MyException, MyExceptionMsg);
-
- void baz();
- };
-};
- </code>
- </section>
-
- <section>
- <title>Throwing Exceptions</title>
- <p>To be able to raise <c>MyException</c> or <c>MyExceptionMsg</c> exceptions,
- the generated <c>MyModule.hrl</c> must be included, and typical usage is:</p>
- <code type="erl">
--module('MyModule_MyInterface_impl').
--include("MyModule.hrl").
-
-bar(State) ->
- case TestingSomething of
- ok ->
- {reply, ok, State};
- {error, Reason} when list(Reason) ->
- corba:raise(#'MyModule_MyExceptionMsg'{'ExtraInfo' = Reason});
- error ->
- corba:raise(#'MyModule_MyException'{})
- end.
- </code>
- </section>
-
- <section>
- <title>Catching Exceptions</title>
- <p>Depending on which operation we invoke we must be able to handle:</p>
- <list type="bulleted">
- <item>foo - <c>MyException</c> or a system exception.</item>
- <item>bar - <c>MyException</c>, <c>MyExceptionMsg</c> or a system
- exception.</item>
- <item>baz - a system exception.</item>
- </list>
- <p>Catching and matching exceptions can bee done in different ways:</p>
- <code type="none">
- case catch 'MyModule_MyInterface':bar(MIReference) of
- ok ->
- %% The operation raised no exception.
- ok;
- {'EXCEPTION', #'MyModule_MyExceptionMsg'{'ExtraInfo' = Reason}} ->
- %% If we want to log the Reason we must extract 'ExtraInfo'.
- error_logger:error_msg("Operation 'bar' raised: ~p~n", [Reason]),
- ... do something ...;
- {'EXCEPTION', E} when record(E, 'OBJECT_NOT_EXIST') ->
- ... do something ...;
- {'EXCEPTION', E} ->
- ... do something ...
- end.
- </code>
- </section>
-</chapter>
-
diff --git a/lib/orber/doc/src/ch_idl_to_erlang_mapping.xml b/lib/orber/doc/src/ch_idl_to_erlang_mapping.xml
deleted file mode 100644
index eaa88f24f1..0000000000
--- a/lib/orber/doc/src/ch_idl_to_erlang_mapping.xml
+++ /dev/null
@@ -1,1504 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1997</year><year>2017</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>OMG IDL to Erlang Mapping</title>
- <prepared></prepared>
- <docno></docno>
- <date>1998-10-10</date>
- <rev></rev>
- <file>ch_idl_to_erlang_mapping.xml</file>
- </header>
-
- <section>
- <title>OMG IDL to Erlang Mapping - Overview</title>
- <p>The purpose of OMG IDL, <em>Interface Definition Language</em>, mapping
- is to act as translator between platforms and languages. An IDL
- specification is supposed to describe data types, object types etc.</p>
- <p>CORBA is independent of the programming language used to construct
- clients or implementations. In order to use the ORB, it is
- necessary for programmers to know how to access ORB functionality
- from their programming languages. It translates different IDL constructs
- to a specific programming language. This chapter
- describes the mapping of OMG IDL constructs to the Erlang programming
- language.</p>
- </section>
-
- <section>
- <title>OMG IDL Mapping Elements</title>
- <p>A complete language mapping will allow the programmer to have
- access to all ORB functionality in a way that is convenient for
- a specified programming language.
- </p>
- <p>All mapping must define the following elements:
- </p>
- <list type="bulleted">
- <item>All OMG IDL basic and constructed types</item>
- <item>References to constants defined in OMG IDL</item>
- <item>References to objects defined in OMG IDL</item>
- <item>Invocations of operations, including passing of
- parameters and receiving of results</item>
- <item>Exceptions, including what happens when an operation
- raises an exception and how the exception parameters are
- accessed</item>
- <item>Access to attributes</item>
- <item>Signatures for operations defined by the ORB, such as
- dynamic invocation interface, the object adapters etc.</item>
- <item>Scopes;
- OMG IDL has several levels of scopes, which are mapped to Erlang's
- two scopes.</item>
- </list>
- </section>
-
- <section>
- <title>Getting Started</title>
- <p>To begin with, we should decide which type of objects (i.e. servers) we
- need and if two, or more, should export the same functionality. Let us
- assume that we want to create a system for DB (database) access for different
- kind of users. For example, anyone with a valid password may extract
- data, but only a few may update the DB. Usually, an application
- is defined within a <c>module</c>, and all global datatypes are defined
- on the top-level. To begin with we create a module and the interfaces we
- need:</p>
- <code type="none">
-// DB IDL
-#ifndef _DB_IDL_
-#define _DB_IDL_
-// A module is simply a container
-module DB {
-
- // An interface maps to a CORBA::Object.
- interface CommonUser {
-
- };
-
- // Inherit the Consumer interface
- interface Administrator : CommonUser {
-
- };
-
- interface Access {
-
- };
-
-};
-#endif </code>
- <p>Since the <c>Administrator</c> should be able to do the same things as the
- <c>CommonUser</c>, the previous inherits from the latter. The <c>Access</c>
- interface will grant access to the DB.
- Now we are ready to define the functionality and data types we need. But, this
- requires that we know a little bit more about the OMG IDL.</p>
- <note>
- <p>The OMG defines a set of reserved case insensitive key-words, which may
- <em>NOT</em> be used as identifiers (e.g. module name). For more
- information, see
- <seealso marker="#key_words">Reserved Compiler Names and Keywords</seealso></p>
- </note>
- </section>
-
- <section>
- <title>Basic OMG IDL Types</title>
- <p>The OMG IDL mapping is strongly typed and, even if you have a good knowledge
- of CORBA types, it is essential to read carefully the following mapping to
- Erlang types.</p>
- <p>The mapping of basic types is straightforward. Note that the
- OMG IDL double type is mapped to an Erlang float which does not
- support the full double value range.</p>
- <table>
- <row>
- <cell align="left" valign="middle">OMG IDL type</cell>
- <cell align="left" valign="middle">Erlang type</cell>
- <cell align="left" valign="middle">Note</cell>
- </row>
- <row>
- <cell align="left" valign="middle">float</cell>
- <cell align="left" valign="middle">Erlang float</cell>
- <cell align="left" valign="middle"></cell>
- </row>
- <row>
- <cell align="left" valign="middle">double</cell>
- <cell align="left" valign="middle">Erlang float</cell>
- <cell align="left" valign="middle">value range not supported</cell>
- </row>
- <row>
- <cell align="left" valign="middle">short</cell>
- <cell align="left" valign="middle">Erlang integer</cell>
- <cell align="left" valign="middle">-2^15 .. 2^15-1</cell>
- </row>
- <row>
- <cell align="left" valign="middle">unsigned short</cell>
- <cell align="left" valign="middle">Erlang integer</cell>
- <cell align="left" valign="middle">0 .. 2^16-1</cell>
- </row>
- <row>
- <cell align="left" valign="middle">long</cell>
- <cell align="left" valign="middle">Erlang integer</cell>
- <cell align="left" valign="middle">-2^31 .. 2^31-1</cell>
- </row>
- <row>
- <cell align="left" valign="middle">unsigned long</cell>
- <cell align="left" valign="middle">Erlang integer</cell>
- <cell align="left" valign="middle">0 .. 2^32-1</cell>
- </row>
- <row>
- <cell align="left" valign="middle">long long</cell>
- <cell align="left" valign="middle">Erlang integer</cell>
- <cell align="left" valign="middle">-2^63 .. 2^63-1</cell>
- </row>
- <row>
- <cell align="left" valign="middle">unsigned long long</cell>
- <cell align="left" valign="middle">Erlang integer</cell>
- <cell align="left" valign="middle">0 .. 2^64-1</cell>
- </row>
- <row>
- <cell align="left" valign="middle">char</cell>
- <cell align="left" valign="middle">Erlang integer</cell>
- <cell align="left" valign="middle">ISO-8859-1</cell>
- </row>
- <row>
- <cell align="left" valign="middle">wchar</cell>
- <cell align="left" valign="middle">Erlang integer</cell>
- <cell align="left" valign="middle">UTF-16 (ISO-10646-1:1993)</cell>
- </row>
- <row>
- <cell align="left" valign="middle">boolean</cell>
- <cell align="left" valign="middle">Erlang atom</cell>
- <cell align="left" valign="middle">true/false</cell>
- </row>
- <row>
- <cell align="left" valign="middle">octet</cell>
- <cell align="left" valign="middle">Erlang integer</cell>
- <cell align="left" valign="middle"></cell>
- </row>
- <row>
- <cell align="left" valign="middle">any</cell>
- <cell align="left" valign="middle">Erlang record</cell>
- <cell align="left" valign="middle">#any{typecode, value}</cell>
- </row>
- <row>
- <cell align="left" valign="middle">long double</cell>
- <cell align="left" valign="middle">Not supported</cell>
- <cell align="left" valign="middle"></cell>
- </row>
- <row>
- <cell align="left" valign="middle">Object</cell>
- <cell align="left" valign="middle">Orber object reference</cell>
- <cell align="left" valign="middle">Internal Representation</cell>
- </row>
- <row>
- <cell align="left" valign="middle">void</cell>
- <cell align="left" valign="middle">Erlang atom</cell>
- <cell align="left" valign="middle">ok</cell>
- </row>
- <tcaption>OMG IDL basic types</tcaption>
- </table>
- <p>The <c>any</c> value is written as a record with the field typecode which
- contains the <term id="Type Code"><termdef>Type Code is a full definition of a type </termdef></term>representation,
- <seealso marker="#tk_values">see also the Type Code table</seealso>,
- and the value field itself.</p>
- <p>Functions with return type <c>void</c> will return the atom <c>ok</c>.</p>
- </section>
-
- <section>
- <title>Template OMG IDL Types and Complex Declarators</title>
- <p>Constructed types all have native mappings as shown in the table
- below.</p>
- <table>
- <row>
- <cell align="left" valign="middle"><em>Type</em></cell>
- <cell align="left" valign="middle"><em>IDL code</em></cell>
- <cell align="left" valign="middle"><em>Maps to</em></cell>
- <cell align="left" valign="middle"><em>Erlang code</em></cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>string</em></cell>
- <cell align="left" valign="middle">typedef string S; <br></br>
-void op(in S a);</cell>
- <cell align="left" valign="middle">Erlang string</cell>
- <cell align="left" valign="middle">ok = op(Obj, "Hello World"),</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>wstring</em></cell>
- <cell align="left" valign="middle">typedef wstring S; <br></br>
-void op(in S a);</cell>
- <cell align="left" valign="middle">Erlang list of Integers</cell>
- <cell align="left" valign="middle">ok = op(Obj, "Hello World"),</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>sequence</em></cell>
- <cell align="left" valign="middle">typedef sequence &lt;long, 3&gt; S; <br></br>
-void op(in S a);</cell>
- <cell align="left" valign="middle">Erlang list</cell>
- <cell align="left" valign="middle">ok = op(Obj, [1, 2, 3]),</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>array</em></cell>
- <cell align="left" valign="middle">typedef string S[2]; <br></br>
-void op(in S a);</cell>
- <cell align="left" valign="middle">Erlang tuple</cell>
- <cell align="left" valign="middle">ok = op(Obj, {"one", "two"}),</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>fixed</em></cell>
- <cell align="left" valign="middle">typedef fixed&lt;3,2> myFixed; <br></br>
-void op(in myFixed a);</cell>
- <cell align="left" valign="middle">Erlang tuple</cell>
- <cell align="left" valign="middle">MF = fixed:create(3, 2, 314), <br></br>
-ok = op(Obj, MF),</cell>
- </row>
- <tcaption>OMG IDL Template and Complex Declarators</tcaption>
- </table>
-
- <section>
- <title>String/WString Data Types</title>
- <p>A <c>string</c> consists of all possible 8-bit quantities except null.
- Most ORB:s uses, including Orber, the character set Latin-1 (ISO-8859-1).
- The <c>wstring</c> type is represented as a list of integers, where
- each integer represents a wide character. In this case Orber uses, as
- most other ORB:s, the UTF-16 (ISO-10646-1:1993) character set.</p>
- <p>When defining a a string or wstring they can be of limited length or
- null terminated:</p>
- <code type="none"><![CDATA[
-// Null terminated
-typedef string myString;
-typedef wstring myWString;
-// Maximum length 10
-typedef string<10> myString10;
-typedef wstring<10> myWString10;
- ]]></code>
- <p>If we want to define a char/string or wchar/wstring constant, we can
- use octal (\OOO - one, two or three octal digits),
- hexadecimal (\xHH - one or two hexadecimal digits) and unicode (\uHHHH -
- one, two, three or four hexadecimal digits.) representation as well.
- For example:</p>
- <code type="none">
-const string SwedensBestSoccerTeam = "\101" "\x49" "\u004B";
-const wstring SwedensBestHockeyTeam = L"\101\x49\u004B";
-const char aChar = '\u004B';
-const wchar aWchar = L'\u004C';
- </code>
- <p>Naturally, we can use <c>"Erlang"</c>, <c>L"Rocks"</c>, <c>'A'</c>
- and <c>L'A'</c> as well.</p>
- </section>
-
- <section>
- <title>Sequence Data Type</title>
- <p>A sequence can be defined to be of a maximum length or unbounded, and may
- contain Basic and Template types and scoped names:</p>
- <code type="none"><![CDATA[
-typedef sequence <short, 1> aShortSequence;
-typedef sequence <long> aLongSequence;
-typedef sequence <aLongSequence> anEvenLongerSequence;
- ]]></code>
- </section>
-
- <section>
- <title>Array Data Type</title>
- <p>Arrays are multidimensional, fixed-size arrays. The indices is language
- mapping specific, which is why one should not pass them as arguments
- to another ORB.</p>
- <code type="none">
-typedef long myMatrix[2][3];
- </code>
- </section>
-
- <section>
- <title>Fixed Data Type</title>
- <p>A Fixed Point literal consists of an integer part (decimal digits),
- decimal point and a fraction part (decimal digits),
- followed by a <c>D</c> or <c>d</c>. Either the integer part or the
- fraction part may be missing; the decimal point may be missing,
- but not d/D. The integer part must be a positive integer less than 32.
- The Fraction part must be a positive integer less than or equal to
- the Integer part.</p>
- <code type="none">
-const fixed myFixed1 = 3.14D;
-const fixed myFixed2 = .14D;
-const fixed myFixed3 = 0.14D;
-const fixed myFixed4 = 3.D;
-const fixed myFixed5 = 3D;
- </code>
- <p>It is also possible to use unary (+-) and binary (+-*/) operators:</p>
- <code type="none">
-const fixed myFixed6 = 3D + 0.14D;
-const fixed myFixed7 = -3.14D;
- </code>
- <p>The Fixed Point examples above are, so called, <em>anonymous</em>
- definitions. In later CORBA specifications these have been deprecated
- as function parameters or return values. Hence, we strongly recommend that
- you do not use them. Instead, you should use:</p>
- <code type="none"><![CDATA[
-typedef fixed<5,3> myFixed53;
-const myFixed53 myFixed53constant = 03.140d;
-typedef fixed<3,2> myFixed32;
-const myFixed32 myFixed32constant = 3.14d;
-
-myFixed53 foo(in myFixed32 MF); // OK
-void bar(in fixed<5,3> MF); // Illegal
- ]]></code>
- </section>
- <p>For more information, see <seealso marker="fixed">Fixed</seealso> in
- Orber's Reference Manual.</p>
- <p>Now we continue to work on our IDL specification. To begin with, we want
- to limit the size of the logon parameters (Id and password). Since the
- <c>UserID</c> and <c>Password</c> parameters, only will be used when
- invoking operations on the <c>Access</c> interface, we may choose to define
- them within the scope that interface. To keep it simple our DB will contain
- employee information. Hence, as the DB key we choose an integer
- (<c>EmployeeNo</c>).</p>
- <code type="none"><![CDATA[
-// DB IDL
-#ifndef _DB_IDL_
-#define _DB_IDL_
-module DB {
-
- typedef unsigned long EmployeeNo;
-
- interface CommonUser {
-
- any lookup(in EmployeeNo ENo);
-
- };
-
- interface Administrator : CommonUser {
-
- void delete(in EmployeeNo ENo);
-
- };
-
- interface Access {
-
- typedef string<10> UserID;
- typedef string<10> Password;
-
- CommonUser logon(in UserID ID, in Password PW);
-
- };
-
-};
-#endif ]]></code>
- <p>But what should, for example, the <c>lookup</c> operation return? One option
- is to use the <c>any</c> data type. But, depending on what kind of data it
- encapsulates, this datatype can be rather expensive to use. We might find a
- solution to our problems among the <c>Constructed</c> IDL types.</p>
- </section>
-
- <section>
- <title>Constructed OMG IDL Types</title>
- <p>Constructed types all have native mappings as shown in the table
- below.</p>
- <table>
- <row>
- <cell align="left" valign="middle"><em>Type</em></cell>
- <cell align="left" valign="middle"><em>IDL code</em></cell>
- <cell align="left" valign="middle"><em>Maps to</em></cell>
- <cell align="left" valign="middle"><em>Erlang code</em></cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>struct</em></cell>
- <cell align="left" valign="middle">struct myStruct { <br></br>
-long a; <br></br>
-short b; <br></br>
-}; <br></br>
-void op(in myStruct a);</cell>
- <cell align="left" valign="middle">Erlang record</cell>
- <cell align="left" valign="middle">ok = op(Obj, #'myStruct'{a=300, b=127}),</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>union</em></cell>
- <cell align="left" valign="middle">union myUnion switch(long) { <br></br>
-case 1: long a; <br></br>
-}; <br></br>
-void op(in myUnion a);</cell>
- <cell align="left" valign="middle">Erlang record</cell>
- <cell align="left" valign="middle">ok = op(Obj, #'myUnion'{label=1, value=66}),</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>enum</em></cell>
- <cell align="left" valign="middle">enum myEnum {one, two}; <br></br>
-void op(in myEnum a);</cell>
- <cell align="left" valign="middle">Erlang atom</cell>
- <cell align="left" valign="middle">ok = op(Obj, one),</cell>
- </row>
- <tcaption>OMG IDL constructed types</tcaption>
- </table>
-
- <section>
- <title>Struct Data Type</title>
- <p>A <c>struct</c> may have Basic, Template, Scoped Names and Constructed
- types as members. By using forward declaration we can define a recursive struct:</p>
- <code type="none"><![CDATA[
-struct myStruct; // Forward declaration
-typedef sequence<myStruct> myStructSeq;
-struct myStruct {
- myStructSeq chain;
-};
-
-// Deprecated definition (anonymous) not supported by IC
-struct myStruct {
- sequence<myStruct> chain;
-};
- ]]></code>
- </section>
-
- <section>
- <title>Enum Data Type</title>
- <p>The maximum number of identifiers which may defined in an enumeration
- is 2&sup3;&sup2;. The order in which the identifiers are named in the
- specification of an enumeration defines the relative order of the
- identifiers.</p>
- </section>
-
- <section>
- <title>Union Data Type</title>
- <p>A <c>union</c> may consist of:</p>
- <list type="bulleted">
- <item>Identifier</item>
- <item>Switch - may be an integer, char, boolean, enum or scoped name.</item>
- <item>Body - with or without a <c>default</c> case; may appear at
- most once.</item>
- </list>
- <p>A case label must match the defined type of the discriminator, and may only
- contain a default case if the values given in the non-default labels do
- not cover the entire range of the union's discriminant type. For example:</p>
- <code type="none">
-// Illegal default; all cases covered by
-// non-default cases.
-union BooleanUnion switch(boolean) {
- case TRUE: long TrueValue;
- case FALSE: long FalseValue;
- default: long DefaultValue;
-};
-// OK
-union BooleanUnion2 switch(boolean) {
- case TRUE: long TrueValue;
- default: long DefaultValue;
-};
- </code>
- <p>It is not necessary to list all possible values of the union discriminator
- in the body. Hence, the value of a union is the value of the discriminator
- and, in given order, one of the following:</p>
- <list type="ordered">
- <item>If the discriminator match a label, explicitly listed in a
- case statement, the value must be of the same type.</item>
- <item>If the union contains a default label, the value must match the
- type of the default label.</item>
- <item>No value. Orber then inserts the Erlang atom <c>undefined</c>
- in the value field when receiving a union from an external
- ORB.</item>
- </list>
- <p>The above can be summed up to:</p>
- <code type="none">
-// If the discriminator equals 1 or 2 the value
-// is a long. Otherwise, the atom undefined.
-union LongUnion switch(long) {
- case 1:
- case 2: long TrueValue;
-};
-// If the discriminator equals 1 or 2 the value
-// is a long. Otherwise, a boolean.
-union LongUnion2 switch(long) {
- case 1:
- case 2: long TrueValue;
- default: boolean DefaultValue;
-};
- </code>
- <p>In the same way as structs, unions can be recursive if forward
- declaration is used (anonymous types is deprecated and not supported):</p>
- <code type="none"><![CDATA[
-// Forward declaration
-union myUnion;
-typedef sequence<myUnion>myUnionSeq;
-union myUnion switch (long) {
- case 1 : myUnionSeq chain;
- default: boolean DefaultValue;
-};
- ]]></code>
-
- <note>
- <p>Recursive types (union and struct) require Light IFR. I.e. the
- IC option {light_ifr, true} is used and that Orber is configured in such a way that
- Light IFR is activated. Recursive TypeCode is currently not supported, which is
- why these cannot be encapsulated in an any data type.</p>
- </note>
-
- </section>
- <warning>
- <p>Every field in, for example, a struct must be initiated. Otherwise
- it will be set to the atom <c>undefined</c>, which Orber cannot
- encode when communicating via IIOP. In the example above, invoking
- the operation with #'myStruct'{a=300} will fail (equal to
- #'myStruct'{a=300, b=undefined})</p>
- </warning>
- <p>Now we can continue to work on our IDL specification. To begin with, we should
- determine the return value of the <c>lookup</c> operation. Since the <c>any</c>
- type can be rather expensive we can use a <c>struct</c> or a <c>union</c> instead.
- If we intend to return the same information about a employee every time we can
- use a struct. Let us assume that the DB contains the name, address, employee
- number and department.</p>
- <code type="none"><![CDATA[
-// DB IDL
-#ifndef _DB_IDL_
-#define _DB_IDL_
-module DB {
-
- typedef unsigned long EmployeeNo;
-
- enum Department {Department1, Department2};
-
- struct employee {
- EmployeeNo No;
- string Name;
- string Address;
- Department Dpt;
- };
-
- typedef employee EmployeeData;
-
- interface CommonUser {
-
- EmployeeData lookup(in EmployeeNo ENo);
-
- };
-
- interface Administrator : CommonUser {
-
- void delete(in EmployeeNo ENo);
-
- };
-
- interface Access {
-
- typedef string<10> UserID;
- typedef string<10> Password;
-
- // Since Administrator inherits from CommonUser
- // the returned Object can be of either type.
- CommonUser logon(in UserID ID, in Password PW);
-
- };
-
-};
-#endif ]]></code>
- <p>We can also define exceptions (i.e. not system exception) thrown by
- each interface. Since exceptions are thoroughly described in the chapter
- <seealso marker="ch_exceptions">System and User Defined Exceptions</seealso>,
- we choose not to. Hence, we are now ready to compile our IDL-file by
- invoking:</p>
- <pre>
-$ <input>erlc DB.idl</input>
- </pre>
- <p>or:</p>
- <pre>
-$ <input>erl</input>
-Erlang (BEAM) emulator version 5.1.1 [threads:0]
-
-Eshell V5.1.1 (abort with ^G)
-1> <input>ic:gen('DB').</input>
-ok
-2> <input>halt().</input>
- </pre>
- <p>The next step is to implement our servers. But, to be able to do that,
- we need to know how we can access data type definitions. For example,
- since a struct is mapped to an Erlang record we must include an hrl-file
- in our callback module.</p>
- </section>
-
- <section>
- <title>Scoped Names and Generated Files</title>
-
- <section>
- <title>Scoped Names</title>
- <p>Within a scope all identifiers must be unique. The following kinds of
- definitions form scopes in the OMG IDL:</p>
- <list type="bulleted">
- <item><em>module</em></item>
- <item><em>interface</em></item>
- <item><em>operation</em></item>
- <item><em>valuetype</em></item>
- <item><em>struct</em></item>
- <item><em>union</em></item>
- <item><em>exception</em></item>
- </list>
- <p>For example, since enumerants do not form a scope, the following IDL code
- is not valid:</p>
- <code type="none">
-module MyModule {
- // 'two' is not unique
- enum MyEnum {one, two};
- enum MyOtherEnum {two, three};
-};
- </code>
- <p>But, since Erlang only has two levels of scope, <em>module</em> and
- <em>function</em>, the OMG IDL scope is mapped as follows:</p>
- <list type="bulleted">
- <item><em>Function Scope</em> - used for constants, operations and attributes.</item>
- <item><em>Erlang Module Scope</em> - the Erlang module scope
- handles the remaining OMG IDL scopes.</item>
- </list>
- <p>An Erlang module, corresponding to an IDL global name, is derived by
- converting occurrences of "::" to underscore, and eliminating
- the leading "::". Hence, accessing <c>MyEnum</c> from another module, one
- use <c>MyModule::MyEnum</c></p>
- <p>For example, an operation <c>foo</c> defined in interface <c>I</c>, which
- is defined in module <c>M</c>, would be written in IDL as <c>M::I::foo</c>
- and as <c>'M_I':foo</c> in Erlang - <c>foo</c> is the function
- name and <c>'M_I'</c> is the name of the Erlang module. Applying this
- knowledge to a stripped version of the DB.idl gives:</p>
- <code type="none"><![CDATA[
-// DB IDL
-#ifndef _DB_IDL_
-#define _DB_IDL_
-// ++ topmost scope ++
-// IC generates oe_XX.erl and oe_XX.hrl.
-// XX is equal to the name of the IDL-file.
-// Tips: create one IDL-file for each top module
-// and give the file the same name (DB.idl).
-// The oe_XX.erl module is used to register data
-// in the IFR.
-module DB {
-
- // ++ Module scope ++
- // To access 'EmployeeNo' from another scope, use:
- // DB::EmployeeNo, DB::Access etc.
- typedef unsigned long EmployeeNo;
-
- enum Department {Department1, Department2};
-
- // Definitions of this struct is contained in:
- // DB.hrl
- // Access functions exported by:
- // DB_employee.erl
- struct employee {
- ... CUT ...
- };
-
- typedef employee EmployeeData;
-
- ... CUT ...
-
- // If this interface should inherit an interface
- // in another module (e.g. OtherModule) use:
- // interface Access : OtherModule::OtherInterface
- interface Access {
-
- // ++ interface scope ++
- // Types within this scope is accessible via:
- // DB::Access::UserID
- // The Stub/Skeleton for this interface is
- // placed in the module:
- // DB_Access.erl
- typedef string<10> UserID;
- typedef string<10> Password;
-
- // Since Administrator inherits from CommonUser
- // the returned Object can be of either type.
- // This operation is exported from:
- // DB_Access.erl
- CommonUser logon(in UserID ID, in Password PW);
-
- };
-
-};
-#endif ]]></code>
- <p>Using underscores in IDL names can lead to ambiguities
- due to the name mapping described above. It is advisable to
- avoid the use of underscores in identifiers. For example, the following
- definition would generate two structures named <c>x_y_z</c>.</p>
- <code type="none">
-module x {
-
- struct y_z {
- ...
- };
-
- interface y {
-
- struct z {
- ...
- };
- };
-};
- </code>
- </section>
-
- <section>
- <title>Generated Files</title>
- <p>Several files can be generated for each scope.</p>
- <list type="bulleted">
- <item>An Erlang source code file (<c>.erl</c>) is generated
- for top level scope as well as the Erlang header file.</item>
- <item>An Erlang header file (<c>.hrl</c>) will be generated for
- each scope. The header file will contain record definitions
- for all <c>struct</c>, <c>union</c> and <c>exception</c>
- types in that scope.</item>
- <item>Modules that contain at least one constant definition,
- will produce Erlang source code files (<c>.erl</c>).
- That Erlang file will contain constant functions for
- that scope.
- Modules that contain no constant definitions are considered
- empty and no code will be produced for them, but only for
- their included modules/interfaces.</item>
- <item>Interfaces will produce Erlang source code files (<c>.erl</c>),
- this code will contain all operation stub code and implementation
- functions.</item>
- <item>In addition to the scope-related files, an Erlang source file will
- be generated for each definition of the types <c>struct</c>,
- <c>union</c> and <c>exception</c> (these are the types that
- will be represented in Erlang as records).
- This file will contain special access functions for that record.</item>
- <item>The top level scope will produce two files, one header file
- (<c>.hrl</c>) and one Erlang source file (<c>.erl</c>).
- These files are named as the IDL file, prefixed with <c>oe_</c>.</item>
- </list>
- <p>After compiling DB.idl, the following files have been generated:</p>
- <list type="bulleted">
- <item><c>oe_DB.hrl</c> and <c>oe_DB.erl</c> for the top scope level.</item>
- <item><c>DB.hrl</c> for the module <c>DB</c>.</item>
- <item><c>DB_Access.hrl</c> and <c>DB_Access.erl</c> for the interface
- <c>DB_Access</c>.</item>
- <item><c>DB_CommonUser.hrl</c> and <c>DB_CommonUser.erl</c> for the interface
- <c>DB_CommonUser</c>.</item>
- <item><c>DB_Administrator.hrl</c> and <c>DB_Administrator.erl</c> for the interface
- <c>DB_Administrator</c>.</item>
- <item><c>DB_employee.erl</c> for the structure <c>employee</c> in module
- <c>DB</c>.</item>
- </list>
- <p>Since the <c>employee</c> struct is defined in the top level scope,
- the Erlang record definition is found in <c>DB.hrl</c>. IC also generates
- stubs/skeletons (e.g. <c>DB_CommonUser.erl</c>) and access functions for
- some datatypes (e.g. <c>DB_employee.erl</c>). How the stubs/skeletons are
- used is thoroughly described in
- <seealso marker="ch_stubs">Stubs/Skeletons</seealso> and
- <seealso marker="Module_Interface">Module_Interface</seealso>.</p>
- </section>
- </section>
-
- <section>
- <title>Typecode, Identity and Name Access Functions</title>
- <p>As mentioned in a previous section, <c>struct</c>, <c>union</c> and
- <c>exception</c> types yield record definitions and access code
- for that record.
- For <c>struct</c>, <c>union</c>, <c>exception</c>, <c>array</c> and
- <c>sequence</c> types, a special file is generated that holds access
- functions for <c>TypeCode</c>, <c>Identity</c> and <c>Name</c>.
- These functions are put in the file corresponding to the scope where
- they are defined. For example, the module <c>DB_employee.erl</c>,
- representing the <c>employee</c> struct, exports the following functions:</p>
- <list type="bulleted">
- <item>tc/0 - returns the type code for the struct.</item>
- <item>id/0 - returns the IFR identity of the struct. In this case
- the returned value is <c>"IDL:DB/employee:1.0"</c>, but
- if the struct was defined in the scope of <c>CommonUser</c>,
- the result would be <c>"IDL:DB/CommonUser/employee:1.0"</c>.
- However, the user usually do not need to know the Id, just
- which Erlang module contains the correct Id.</item>
- <item>name/0 - returns the scoped name of the struct. The <c>employee</c>
- struct name is <c>"DB_employee"</c>.</item>
- </list>
- <p><term id="Type Codes"><termdef>Type codes give a complete description of the type including all its components and structure.</termdef></term>are, for example, used in <seealso marker="any">Any</seealso> values.
- Hence, we can encapsulate the <c>employee</c> struct in an <c>any</c>
- type by:</p>
- <code type="erl">
-%% Erlang code
-....
-AnEmployee = #'DB_employee'{'No' = 1,
- 'Name' = "Adam Ivan Kendall",
- 'Address' = "Rasunda, Solna",
- 'Dpt' = 'Department1'},
-EmployeeTC = 'DB_employee':tc(),
-EmployeeAny = any:create(EmployeeTC, AnEmployee),
-....
- </code>
- <p>For more information, see the
- <seealso marker="#tk_values">Type Code listing</seealso>.</p>
- </section>
-
- <section>
- <title>References to Constants</title>
- <p>Constants are generated as Erlang functions, and are accessed by a
- single function call. The functions are put in the file
- corresponding to the scope where they are defined. There is no
- need for an object to be started to access a constant.</p>
- <p>Example:</p>
- <code type="none">
-// m.idl
-module m {
- const float pi = 3.14;
-
- interface i {
- const float pi = 3.1415;
- };
-};
- </code>
- <p>Since the two constants are defined in different scopes, the IDL code
- above is valid, but not necessarily a good approach. After compiling
- <c>m.idl</c>, the constant definitions can be extracted by invoking:</p>
- <pre>
-$ <input>erlc m.idl</input>
-$ <input>erlc m.erl</input>
-$ <input>erl</input>
-Erlang (BEAM) emulator version 5.1.1 [threads:0]
-
-Eshell V5.1.1 (abort with ^G)
-1> <input>m:pi().</input>
-3.14
-2> <input>m_i:pi().</input>
-3.1415
-3> <input>halt().</input>
- </pre>
- </section>
-
- <section>
- <title>References to Objects Defined in OMG IDL</title>
- <p>Objects are accessed by object references. An object reference
- is an opaque Erlang term created and maintained by the ORB.</p>
- <p>Objects are implemented by providing implementations for all
- operations and attributes of the Object, <seealso marker="#op_impl">see operation implementation</seealso>.</p>
- </section>
-
- <section>
- <title>Exceptions</title>
- <p>Exceptions are handled as Erlang catch and throws. Exceptions
- are translated to messages over an IIOP bridge but converted
- back to a throw on the receiving side. Object implementations
- that invoke operations on other objects must be aware of the
- possibility of a non-local return. This includes invocation of
- ORB and IFR services. See also the
- <seealso marker="ch_exceptions">Exceptions</seealso> section.</p>
- <p>Exception parameters are mapped as an Erlang record and accessed
- as such.</p>
- <p>An object implementation that raises an exception will use the
- <c>corba:raise/1</c> function, passing the exception record as
- parameter.</p>
- </section>
-
- <section>
- <title>Access to Attributes</title>
- <p>Attributes are accessed through their access functions. An
- attribute implicitly defines the <c>_get</c> and <c>_set</c>
- operations. These operations are handled in the same way as
- normal operations. The <c>_get</c> operation is defined as a <c>readonly</c>
- attribute.</p>
- <code type="none">
-readonly attribute long RAttribute;
-attribute long RWAttribute;
- </code>
- <p>The <c>RAttribute</c> requires that you implement, in your call-back module,
- <c>_get_RAttribute</c>. For the <c>RWAttribute</c> it is necessary to implement
- <c>_get_RWAttribute</c> and <c>_set_RWAttribute</c>.</p>
- </section>
-
- <section>
- <title>Invocations of Operations</title>
- <marker id="op_impl"></marker>
- <p>A standard Erlang <c>gen_server</c> behavior is used for
- object implementation. The <c>gen_server</c> state is then
- used as the object internal state. Implementation of the object
- function is achieved by implementing its methods and attribute operations.
- These functions will usually have the internal state as their first parameter,
- followed by any <c>in</c> and <c>inout</c> parameters. </p>
- <p>Do not confuse the
- object internal state with its object reference. The object internal state is
- an Erlang term which has a format defined by the user.</p>
- <note>
- <p>It is not always the case that the internal state will be the first parameter, as stubs can use their own object reference as the first parameter (see the IC documentation).</p>
- </note>
- <p>A function call will invoke an operation. The first
- parameter of the function should be the object reference and then
- all <c>in</c> and <c>inout</c> parameters follow in the same
- order as specified in the IDL specification. The result will be a return value
- unless the function has <c>inout</c> or <c>out</c> parameters specified;
- in which case, a tuple of the return value, followed by the parameters will
- be returned.</p>
- <p>Example:</p>
- <code type="none">
-// IDL
-module m {
- interface i {
- readonly attribute long RAttribute;
- attribute long RWAttribute;
- long foo(in short a);
- long bar(in char c, inout string s, out long count);
- void baz(out long Id);
- };
-};
- </code>
- <p>Is used in Erlang as :</p>
- <code type="none">
-%% Erlang code
-....
-Obj = ... %% get object reference
-RAttr = m_i:'_get_RAttribute'(Obj),
-RWAttr = m_i:'_get_RWAttribute'(Obj),
-ok = m_i:'_set_RWAttribute'(Obj, Long),
-R1 = m_i:foo(Obj, 55),
-{R2, S, Count} = m_i:bar(Obj, $a, "hello"),
-....
- </code>
- <p>Note how the <c>inout</c> parameter is passed <em>and</em>
- returned. There is no way to use a single occurrence of a
- variable for this in Erlang. Also note, that <c>ok</c>, Orber's
- representation of the IDL-type <c>void</c>, must be returned by
- <c>baz</c> and <c>'_set_RWAttribute'</c>.
- These operations can be implemented in the call-back module as:</p>
- <code type="erl">
-'_set_RWAttribute'(State, Long) ->
- {reply, ok, State}.
-
-'_get_RWAttribute'(State) ->
- {reply, Long, State}.
-
-'_get_RAttribute'(State) ->
- {reply, Long, State}.
-
-foo(State, AShort) ->
- {reply, ALong, State}.
-
-bar(State, AShort, AString) ->
- {reply, {ALong, "MyString", ALong}, State}.
-
-baz(State) ->
- {reply, {ok, AId}, State}.
- </code>
- <p>The operations may require more arguments (depends on IC options used). For
- more information, see <seealso marker="ch_stubs">Stubs/Skeletons</seealso>
- and <seealso marker="Module_Interface">Module_Interface</seealso>.</p>
- <warning>
- <p>A function can also be defined to be <c>oneway</c>, i.e.
- asynchronous. But, since the behavior of a oneway operation is not
- defined in the OMG specifications (i.e. the behavior can differ depending on
- which other ORB Orber is communicating with), one should avoid using it.</p>
- </warning>
- </section>
-
- <section>
- <title>Implementing the DB Application</title>
- <p>Now we are ready to implement the call-back modules. There are three modules
- we must create:</p>
- <list type="bulleted">
- <item>DB_Access_impl.erl</item>
- <item>DB_CommonUser_impl.erl</item>
- <item>DB_Administrator_impl.erl</item>
- </list>
- <p>An easy way to accomplish that, is to use the IC backend <c>erl_template</c>,
- which will generate a complete call-back module. One should also add
- the same compile options, for example <c>this</c> or <c>from</c>,
- used when generating the stub/skeleton modules:</p>
- <code type="none">
-$> erlc +"{be,erl_template}" DB.idl
- </code>
- <p>We begin with implementing the <c>DB_Access_impl.erl</c> module, which,
- if we used <c>erl_template</c>, will look like the following. All we need
- to do is to add the logic to the <c>logon</c> operation.</p>
- <code type="erl"><![CDATA[
-%%----------------------------------------------------------------------
-%% <LICENSE>
-%%
-%% $Id$
-%%
-%%----------------------------------------------------------------------
-%% Module : DB_Access_impl.erl
-%%
-%% Source : /home/user/example/DB.idl
-%%
-%% Description :
-%%
-%% Creation date: 2005-05-20
-%%
-%%----------------------------------------------------------------------
--module('DB_Access_impl').
-
--export([logon/3]).
-
-%%----------------------------------------------------------------------
-%% Internal Exports
-%%----------------------------------------------------------------------
--export([init/1,
- terminate/2,
- code_change/3,
- handle_info/2]).
-
-%%----------------------------------------------------------------------
-%% Include Files
-%%----------------------------------------------------------------------
-
-
-%%----------------------------------------------------------------------
-%% Macros
-%%----------------------------------------------------------------------
-
-
-%%----------------------------------------------------------------------
-%% Records
-%%----------------------------------------------------------------------
--record(state, {}).
-
-%%======================================================================
-%% API Functions
-%%======================================================================
-%%----------------------------------------------------------------------
-%% Function : logon/3
-%% Arguments : State - term()
-%% ID = String()
-%% PW = String()
-%% Returns : ReturnValue = OE_Reply
-%% OE_Reply = Object_Ref()
-%% Raises :
-%% Description:
-%%----------------------------------------------------------------------
-logon(State, ID, PW) ->
- %% Check if the ID/PW is valid and what
- %% type of user it is (Common or Administrator).
- OE_Reply
- = case check_user(ID, PW) of
- {ok, administrator} ->
- 'DB_Administrator':oe_create();
- {ok, common} ->
- 'DB_CommonUser':oe_create();
- error ->
- %% Here we should throw an exception
- corba:raise(....)
- end,
- {reply, OE_Reply, State}.
-
-%%======================================================================
-%% Internal Functions
-%%======================================================================
-%%----------------------------------------------------------------------
-%% Function : init/1
-%% Arguments : Env = term()
-%% Returns : {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
-%% Raises : -
-%% Description: Initiates the server
-%%----------------------------------------------------------------------
-init(_Env) ->
- {ok, #state{}}.
-
-
-%%----------------------------------------------------------------------
-%% Function : terminate/2
-%% Arguments : Reason = normal | shutdown | term()
-%% State = term()
-%% Returns : ok
-%% Raises : -
-%% Description: Invoked when the object is terminating.
-%%----------------------------------------------------------------------
-terminate(_Reason, _State) ->
- ok.
-
-
-%%----------------------------------------------------------------------
-%% Function : code_change/3
-%% Arguments : OldVsn = undefined | term()
-%% State = NewState = term()
-%% Extra = term()
-%% Returns : {ok, NewState}
-%% Raises : -
-%% Description: Invoked when the object should update its internal state
-%% due to code replacement.
-%%----------------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-
-%%----------------------------------------------------------------------
-%% Function : handle_info/2
-%% Arguments : Info = normal | shutdown | term()
-%% State = NewState = term()
-%% Returns : {noreply, NewState} |
-%% {noreply, NewState, Timeout} |
-%% {stop, Reason, NewState}
-%% Raises : -
-%% Description: Invoked when, for example, the server traps exits.
-%%----------------------------------------------------------------------
-handle_info(_Info, State) ->
- {noreply, State}.
- ]]></code>
- <p>Since <c>DB_Administrator</c> inherits from <c>DB_CommonUser</c>,
- we must implement <c>delete</c> in the <c>DB_Administrator_impl.erl</c>
- module, and <c>lookup</c> in <c>DB_Administrator_impl.erl</c><em>and</em><c>DB_CommonUser_impl.erl</c>. But wait, is that really necessary? Actually,
- it is not. We simple use the IC compile option <em>impl</em>:</p>
- <pre>
-$ <input>erlc +'{{impl, "DB::CommonUser"}, "DBUser_impl"}'\
- +'{{impl, "DB::Administrator"}, "DBUser_impl"}' DB.idl</input>
-$ <input>erlc *.erl</input>
- </pre>
- <p>Instead of creating, and not the least, maintaining two call-back modules,
- we only have to deal with <c>DBUser_impl.erl</c>. If we generated the
- templates, we simply rename <c>DB_Administrator_impl.erl</c> to
- <c>DBUser_impl.erl</c>. See also the
- <seealso marker="ch_exceptions">Exceptions</seealso> chapter.
- In the following example, only the implementation of the API functions
- are shown:</p>
- <code type="erl">
-%%======================================================================
-%% API Functions
-%%======================================================================
-%%----------------------------------------------------------------------
-%% Function : delete/2
-%% Arguments : State - term()
-%% ENo = unsigned_Long()
-%% Returns : ReturnValue = ok
-%% Raises :
-%% Description:
-%%----------------------------------------------------------------------
-delete(State, ENo) ->
- %% How we access the DB, for example mnesia, is not shown here.
- case delete_employee(No) of
- ok ->
- {reply, ok, State};
- error ->
- %% Here we should throw an exception if
- %% there is no match.
- corba:raise(....)
- end.
-
-%%----------------------------------------------------------------------
-%% Function : lookup/2
-%% Arguments : State - term()
-%% ENo = unsigned_Long()
-%% Returns : ReturnValue = OE_Reply
-%% OE_Reply = #'DB_employee'{No,Name,Address,Dpt}
-%% No = unsigned_Long()
-%% Name = String()
-%% Address = String()
-%% Dpt = Department
-%% Department = 'Department1' | 'Department2'
-%% Raises :
-%% Description:
-%%----------------------------------------------------------------------
-lookup(State, ENo) ->
- %% How we access the DB, for example mnesia, is not shown here.
- case lookup_employee(ENo) of
- %% We assume that we receive a 'DB_employee' struct
- {ok, Employee} ->
- OE_Reply = Employee,
- {reply, OE_Reply, State};
- error ->
- %% Here we should throw an exception if
- %% there is no match.
- corba:raise(....)
- end.
- </code>
- <p>After you have compiled both call-back modules, and implemented the missing
- functionality (e.g. lookup_employee/1), we can test our application:</p>
- <code type="none">
-%% Erlang code
-....
-%% Create an Access object
-Acc = 'DB_Access':oe_create(),
-
-%% Login is Common user and Administrator
-Adm = 'DB_Access':logon(A, "admin", "pw"),
-Com = 'DB_Access':logon(A, "comm", "pw"),
-
-%% Lookup existing employee
-Employee = 'DB_Administrator':lookup(Adm, 1),
-Employee = 'DB_CommonUser':lookup(Adm, 1),
-
-%% If we try the same using the DB_CommonUser interface
-%% it result in an exit since that operation is not exported.
-{'EXIT', _} = (catch 'DB_CommonUser':delete(Adm, 1)),
-
-%% Try to delete the employee via the CommonUser Object
-{'EXCEPTION', _} = (catch 'DB_Administrator':delete(Com, 1)),
-
-%% Invoke delete operation on the Administrator object
-ok = 'DB_Administrator':delete(Adm, 1),
-....
- </code>
- </section>
-
- <section>
- <title>Reserved Compiler Names and Keywords</title>
- <marker id="key_words"></marker>
- <p>The use of some names is strongly discouraged due to
- ambiguities. However, the use of some names is prohibited
- when using the Erlang mapping , as they are strictly reserved for IC.</p>
- <p>IC reserves all identifiers starting with <c>OE_</c> and <c>oe_</c>
- for internal use.</p>
- <p>Note also, that an identifier in IDL can contain alphabetic,
- digits and underscore characters, but the first character
- <em>must</em> be alphabetic.
- </p>
- <p>The OMG defines a set of reserved words, shown below, for use as keywords.
- These may <em>not</em> be used as, for example, identifiers. The keywords
- which are not in bold face was introduced in the OMG CORBA-3.0
- specification.</p>
- <table>
- <row>
- <cell align="left" valign="middle"><em>abstract</em></cell>
- <cell align="left" valign="middle"><em>exception</em></cell>
- <cell align="left" valign="middle"><em>inout</em></cell>
- <cell align="left" valign="middle">provides</cell>
- <cell align="left" valign="middle"><em>truncatable</em></cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>any</em></cell>
- <cell align="left" valign="middle">emits</cell>
- <cell align="left" valign="middle"><em>interface</em></cell>
- <cell align="left" valign="middle"><em>public</em></cell>
- <cell align="left" valign="middle"><em>typedef</em></cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>attribute</em></cell>
- <cell align="left" valign="middle"><em>enum</em></cell>
- <cell align="left" valign="middle"><em>local</em></cell>
- <cell align="left" valign="middle">publishes</cell>
- <cell align="left" valign="middle">typeid</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>boolean</em></cell>
- <cell align="left" valign="middle">eventtype</cell>
- <cell align="left" valign="middle"><em>long</em></cell>
- <cell align="left" valign="middle"><em>raises</em></cell>
- <cell align="left" valign="middle">typeprefix</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>case</em></cell>
- <cell align="left" valign="middle"><em>factory</em></cell>
- <cell align="left" valign="middle"><em>module</em></cell>
- <cell align="left" valign="middle"><em>readonly</em></cell>
- <cell align="left" valign="middle"><em>unsigned</em></cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>char</em></cell>
- <cell align="left" valign="middle"><em>FALSE</em></cell>
- <cell align="left" valign="middle">multiple</cell>
- <cell align="left" valign="middle">setraises</cell>
- <cell align="left" valign="middle"><em>union</em></cell>
- </row>
- <row>
- <cell align="left" valign="middle">component</cell>
- <cell align="left" valign="middle">finder</cell>
- <cell align="left" valign="middle"><em>native</em></cell>
- <cell align="left" valign="middle"><em>sequence</em></cell>
- <cell align="left" valign="middle">uses</cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>const</em></cell>
- <cell align="left" valign="middle"><em>fixed</em></cell>
- <cell align="left" valign="middle"><em>Object</em></cell>
- <cell align="left" valign="middle"><em>short</em></cell>
- <cell align="left" valign="middle"><em>ValueBase</em></cell>
- </row>
- <row>
- <cell align="left" valign="middle">consumes</cell>
- <cell align="left" valign="middle"><em>float</em></cell>
- <cell align="left" valign="middle"><em>octet</em></cell>
- <cell align="left" valign="middle"><em>string</em></cell>
- <cell align="left" valign="middle"><em>valuetype</em></cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>context</em></cell>
- <cell align="left" valign="middle">getraises</cell>
- <cell align="left" valign="middle"><em>oneway</em></cell>
- <cell align="left" valign="middle"><em>struct</em></cell>
- <cell align="left" valign="middle"><em>void</em></cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>custom</em></cell>
- <cell align="left" valign="middle">home</cell>
- <cell align="left" valign="middle"><em>out</em></cell>
- <cell align="left" valign="middle"><em>supports</em></cell>
- <cell align="left" valign="middle"><em>wchar</em></cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>default</em></cell>
- <cell align="left" valign="middle">import</cell>
- <cell align="left" valign="middle">primarykey</cell>
- <cell align="left" valign="middle"><em>switch</em></cell>
- <cell align="left" valign="middle"><em>wstring</em></cell>
- </row>
- <row>
- <cell align="left" valign="middle"><em>double</em></cell>
- <cell align="left" valign="middle"><em>in</em></cell>
- <cell align="left" valign="middle"><em>private</em></cell>
- <cell align="left" valign="middle"><em>TRUE</em></cell>
- <cell align="left" valign="middle"></cell>
- </row>
- <tcaption>OMG IDL keywords</tcaption>
- </table>
- <p>The keywords listed above must be written exactly as shown. Any usage
- of identifiers that collide with a keyword is illegal. For example,
- <em>long</em> is a valid keyword; <em>Long</em> and <em>LONG</em> are
- illegal as keywords and identifiers. But, since the OMG must be able
- to expand the IDL grammar, it is possible to use <em>Escaped Identifiers</em>. For example, it is not unlikely that <c>native</c>
- have been used in IDL-specifications as identifiers. One option is to
- change all occurrences to <c>myNative</c>. Usually, it is necessary
- to change programming language code that depends upon that IDL as well.
- Since Escaped Identifiers just disable type checking (i.e. if it is a reserved
- word or not) and leaves everything else unchanged, it is only necessary to
- update the IDL-specification. To escape an identifier, simply prefix it
- with <em>_</em>. The following IDL-code is illegal:</p>
- <code type="none">
-typedef string native;
-interface i {
- void foo(in native Arg);
- };
-};
- </code>
- <p>With Escaped Identifiers the code will look like:</p>
- <code type="none">
-typedef string _native;
-interface i {
- void foo(in _native Arg);
- };
-};
- </code>
- </section>
-
- <section>
- <title>Type Code Representation</title>
- <marker id="tk_values"></marker>
- <p>Type Codes are used in <c>any</c> values. To avoid mistakes, you should
- use access functions exported by the Data Types modules
- (e.g. struct, union etc) or the <seealso marker="orber_tc">orber_tc</seealso>
- module.</p>
- <table>
- <row>
- <cell align="left" valign="middle"><em>Type Code</em></cell>
- <cell align="left" valign="middle"><em>Example</em></cell>
- </row>
- <row>
- <cell align="left" valign="middle">tk_null</cell>
- <cell align="left" valign="middle"></cell>
- </row>
- <row>
- <cell align="left" valign="middle">tk_void</cell>
- <cell align="left" valign="middle"></cell>
- </row>
- <row>
- <cell align="left" valign="middle">tk_short</cell>
- <cell align="left" valign="middle"></cell>
- </row>
- <row>
- <cell align="left" valign="middle">tk_long</cell>
- <cell align="left" valign="middle"></cell>
- </row>
- <row>
- <cell align="left" valign="middle">tk_longlong</cell>
- <cell align="left" valign="middle"></cell>
- </row>
- <row>
- <cell align="left" valign="middle">tk_ushort</cell>
- <cell align="left" valign="middle"></cell>
- </row>
- <row>
- <cell align="left" valign="middle">tk_ulong</cell>
- <cell align="left" valign="middle"></cell>
- </row>
- <row>
- <cell align="left" valign="middle">tk_ulonglong</cell>
- <cell align="left" valign="middle"></cell>
- </row>
- <row>
- <cell align="left" valign="middle">tk_float</cell>
- <cell align="left" valign="middle"></cell>
- </row>
- <row>
- <cell align="left" valign="middle">tk_double</cell>
- <cell align="left" valign="middle"></cell>
- </row>
- <row>
- <cell align="left" valign="middle">tk_boolean</cell>
- <cell align="left" valign="middle"></cell>
- </row>
- <row>
- <cell align="left" valign="middle">tk_char</cell>
- <cell align="left" valign="middle"></cell>
- </row>
- <row>
- <cell align="left" valign="middle">tk_wchar</cell>
- <cell align="left" valign="middle"></cell>
- </row>
- <row>
- <cell align="left" valign="middle">tk_octet</cell>
- <cell align="left" valign="middle"></cell>
- </row>
- <row>
- <cell align="left" valign="middle">tk_any</cell>
- <cell align="left" valign="middle"></cell>
- </row>
- <row>
- <cell align="left" valign="middle">tk_TypeCode</cell>
- <cell align="left" valign="middle"></cell>
- </row>
- <row>
- <cell align="left" valign="middle">tk_Principal</cell>
- <cell align="left" valign="middle"></cell>
- </row>
- <row>
- <cell align="left" valign="middle">{tk_objref, IFRId, Name}</cell>
- <cell align="left" valign="middle">{tk_objref, "IDL:M1\I1:1.0", "I1"}</cell>
- </row>
- <row>
- <cell align="left" valign="middle">{tk_struct, IFRId, Name, [{ElemName, ElemTC}]}</cell>
- <cell align="left" valign="middle">{tk_struct, "IDL:M1\S1:1.0", "S1", [{"a", tk_long}, {"b", tk_char}]}</cell>
- </row>
- <row>
- <cell align="left" valign="middle">{tk_union, IFRId, Name, DiscrTC, DefaultNr, [{Label, ElemName, ElemTC}]} <br></br>
-Note: DefaultNr tells which of tuples in the case list that is default, or -1 if no default</cell>
- <cell align="left" valign="middle">{tk_union, "IDL:U1:1.0", "U1", tk_long, 1, [{1, "a", tk_long}, {default, "b", tk_char}]}</cell>
- </row>
- <row>
- <cell align="left" valign="middle">{tk_enum, IFRId, Name, [ElemName]}</cell>
- <cell align="left" valign="middle">{tk_enum, "IDL:E1:1.0", "E1", ["a1", "a2"]}</cell>
- </row>
- <row>
- <cell align="left" valign="middle">{tk_string, Length}</cell>
- <cell align="left" valign="middle">{tk_string, 5}</cell>
- </row>
- <row>
- <cell align="left" valign="middle">{tk_wstring, Length}</cell>
- <cell align="left" valign="middle">{tk_wstring, 7}</cell>
- </row>
- <row>
- <cell align="left" valign="middle">{tk_fixed, Digits, Scale}</cell>
- <cell align="left" valign="middle">{tk_fixed, 3, 2}</cell>
- </row>
- <row>
- <cell align="left" valign="middle">{tk_sequence, ElemTC, Length}</cell>
- <cell align="left" valign="middle">{tk_sequence, tk_long, 4}</cell>
- </row>
- <row>
- <cell align="left" valign="middle">{tk_array, ElemTC, Length}</cell>
- <cell align="left" valign="middle">{tk_array, tk_char, 9}</cell>
- </row>
- <row>
- <cell align="left" valign="middle">{tk_alias, IFRId, Name, TC}</cell>
- <cell align="left" valign="middle">{tk_alias, "IDL:T1:1.0", "T1", tk_short}</cell>
- </row>
- <row>
- <cell align="left" valign="middle">{tk_except, IFRId, Name, [{ElemName, ElemTC}]}</cell>
- <cell align="left" valign="middle">{tk_except, "IDL:Exc1:1.0", "Exc1", [{"a", tk_long}, {"b", {tk_string, 0}}]}</cell>
- </row>
- <tcaption>Type Code tuples</tcaption>
- </table>
- </section>
-</chapter>
-
diff --git a/lib/orber/doc/src/ch_ifr.xml b/lib/orber/doc/src/ch_ifr.xml
deleted file mode 100644
index 09302ab6cc..0000000000
--- a/lib/orber/doc/src/ch_ifr.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1999</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Interface Repository</title>
- <prepared></prepared>
- <docno></docno>
- <date>1998-10-10</date>
- <rev></rev>
- <file>ch_ifr.xml</file>
- </header>
-
- <section>
- <title>Interface Repository(IFR)</title>
- <p>The IFR is an interface repository built on the Mnesia
- application. Orber uses the IFR for some type-checking
- when coding/decoding IIOP. The IFR is capable of storing all
- interfaces and declarations of OMG IDL.
- </p>
- <p>The interface repository is mainly used for dynamical
- interfaces, and as none are currently supported this function
- is only really used for retrieving information about interfaces.</p>
- <p>Functions relating to the manipulation of the IFR including,
- initialization of the IFR, as well as, locating, creating and
- destroying initial references are detailed further in the Manual
- Pages.
- </p>
- </section>
-</chapter>
-
diff --git a/lib/orber/doc/src/ch_install.xml b/lib/orber/doc/src/ch_install.xml
deleted file mode 100644
index 65faa91ccf..0000000000
--- a/lib/orber/doc/src/ch_install.xml
+++ /dev/null
@@ -1,1001 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1997</year><year>2017</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Installing Orber</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>1998-09-28</date>
- <rev></rev>
- <file>ch_install.xml</file>
- </header>
-
- <section>
- <title>Installation Process </title>
- <p>This chapter describes how to install Orber in an Erlang
- Environment.</p>
-
- <section>
- <title>Preparation</title>
- <p>To begin with, you must decide if you want to run Orber as a:</p>
- <list type="bulleted">
- <item><em>Single node (non-distributed)</em> - all communication with other
- Orber instances and ORB's supplied by other vendors use the OMG
- GIOP protocol.</item>
- <item><em>Multi node (distributed)</em> - all Orber nodes, within the same
- <c>domain</c>, communicate via the Erlang distribution protocol.
- For all other Orber instances, i.e. not part of the same <c>domain</c>,
- and ORB's supplied by other vendors, the OMG GIOP protocol
- is used.</item>
- </list>
- <p>Which approach to use is highly implementation specific, but a few
- things you should consider:</p>
- <list type="bulleted">
- <item>All nodes within an Orber domain should have the same
- security level.</item>
- <item>If the capacity is greater than load (volume of traffic)
- a single-node Orber might be a good solution.</item>
- <item>In some cases the distributed system architecture requires a
- single-node <term id="Orber installation"><termdef>is the structure of the ORB or ORBs as defined during the install process is called the "installation".</termdef></term>.</item>
- <item>A multi-node Orber makes it possible to load balance
- and create a more fault tolerant system. The Objects
- can also have a uniform view if you use distributed
- Mnesia tables.</item>
- <item>Since the GIOP protocol creates a larger overhead than the
- Erlang distribution protocol, the performance will be better
- when communicating with Objects within the same Orber domain
- compared with inter ORB communication (GIOP).</item>
- </list>
- <p>You also have to decide if you want Orber to store internal data using
- <c>disc_copies</c> and/or <c>ram_copies</c>. Which storage type you should
- depends if/how you intend to use Mnesia in your application. If you
- intend to use <c>disc_copies</c> you must start with creating a Mnesia
- schema, which contain information about the location of the Erlang nodes
- where Orber is planned to be run. For more background information,
- see the Mnesia documentation.</p>
- <p>In some cases it is absolutely necessary to change the default configuration
- of Orber. For example, if two Orber-ORB's shall be able to communicate
- via GIOP, they must have a unique <c>domain</c> domain. Consult the
- <seealso marker="ch_install#config">configuration settings</seealso>
- section. If you encounter any problems; see the chapter about
- <em>Debugging</em> in this User's Guide.</p>
- </section>
-
- <section>
- <title>Jump Start Orber</title>
- <p>The easiest way to start Orber is to use <c>orber:jump_start(Port)</c>,
- which start a single-node ORB with (most likely) a unique
- domain (i.e. "IP-number:Port"). This function may only be used
- during development and testing. For any other situation, install and
- start Orber as described in the following sections.
- The listen port, i.e. iiop_port configuration parameter, is set to
- the supplied Port.</p>
- <warning>
- <p>How Orber is configured when using <c>orber:jump_start(Port)</c>
- may change at any time without warning. Hence, this operation must
- not be used in systems delivered to a customer.</p>
- </warning>
- </section>
-
- <section>
- <title>Install Single Node Orber</title>
- <p>Since a single node Orber communicate via the OMG GIOP protocol it is not
- necessary to start the Erlang distribution (i.e. using <c>-name/-sname</c>).</p>
- <p>If we use <c>ram_copies</c> there is no need for creating a disk based
- schema. Simply use:</p>
- <code type="erl">
-erl> mnesia:start().
-erl> corba:orb_init([{domain, "MyRAMSingleNodeORB"}]).
-erl> orber:install([node()], [{ifr_storage_type, ram_copies}]).
-erl> orber:start().
- </code>
- <p>If you installation requires <c>disc_copies</c> you must begin with
- creating a Mnesia schema. Otherwise, the installation is similar
- to a RAM installation:</p>
- <code type="erl">
-erl> mnesia:create_schema([node()]).
-erl> mnesia:start().
-erl> corba:orb_init([{domain, "MyDiskSingleNodeORB"}]).
-erl> orber:install([node()], [{ifr_storage_type, disc_copies},
- {nameservice_storage_type, disc_copies}]).
-erl> orber:start().
- </code>
- <p>You can still choose to store the IFR data as ram_copies, but then
- the data must be re-installed (i.e. invoke <c>orber:install/2</c>)
- if the node is restarted. Hence, since the IFR data is rather static
- you should use <c>disc_copies</c>. For more information see the
- <c>orber</c> section in the reference manual.</p>
- <p>If you do not need to change Orber's configuration you can skip
- <seealso marker="corba">orb_init/1</seealso>.
- But, you <em>should</em> at least set the IIOP timeout parameters.</p>
- </section>
-
- <section>
- <title>Install RAM Based Multi Node Orber</title>
- <p>Within a domain Orber uses the Erlang distribution protocol. Hence, you
- <em>must</em> start it first by, for example, using:</p>
- <code type="erl">
-hostA> erl -sname nodeA
- </code>
- <p>In this example, we assume that we want to use two nodes; <c>nodeA</c> and
- <c>nodeB</c>. Since Mnesia must know which other nodes should a part
- of the distribution we either need to add the Mnesia configuration
- parameter <c>extra_db_nodes</c> or use <c>mnesia:change_config/2</c>. To
- begin with, Mnesia must be started on all nodes before we can install
- Orber:</p>
- <code type="erl">
-nodeA@hostA> mnesia:start().
-nodeA@hostA> mnesia:change_config(extra_db_nodes,
- [nodeA@hostA, nodeB@hostB]).
- </code>
- <p>After that the above have been repeated on <c>nodeB</c> we must
- first make sure that both nodes will use the same domain name, then
- we can install Orber:</p>
- <code type="erl">
-nodeA@hostA> corba:orb_init([{domain, "MyRAMMultiNodeORB"}]).
-nodeA@hostA> orber:install([nodeA@hostA, nodeB@hostB],
- [{ifr_storage_type, ram_copies}]).
-nodeA@hostA> orber:start().
- </code>
- <p>Note that you can only invoke <c>orber:install/1/2</c> on one of the
- nodes. Now we can start Orber on the other node:</p>
- <code type="erl">
-nodeB@hostB> corba:orb_init([{domain, "MyRAMMultiNodeORB"}]).
-nodeB@hostB> orber:start().
- </code>
- </section>
-
- <section>
- <title>Install Disk Based Multi Node Orber</title>
- <p>As for RAM based multi-node Orber installations, the Erlang distribution
- must be started (e.g. erl -sname nodeA). The major difference is that
- when it is disk based a Mnesia schema must be created:</p>
- <code type="erl">
-nodeA@hostA> mnesia:create_schema([nodeA@hostA, nodeB@hostB]).
-nodeA@hostA> mnesia:start().
- </code>
- <p>In this example, we assume that we want to use two nodes; <c>nodeA</c> and
- <c>nodeB</c>. Since it is not possible to create a schema on more than
- one node. Hence, all we have to do is to start Mnesia (i.e. invoke
- <c>mnesia:start()</c>) on <c>nodeB</c>.</p>
- <p>After Mnesia have been started on all nodes, you must confirm that all
- nodes have the same domain name, then Orber is ready to be installed:</p>
- <code type="erl">
-nodeA@hostA> corba:orb_init([{domain, "MyDiskMultiNodeORB"}]).
-nodeA@hostA> orber:install([nodeA@hostA, nodeB@hostB],
- [{ifr_storage_type, disc_copies}]).
-nodeA@hostA> orber:start().
- </code>
- <p>Note that you can only invoke <c>orber:install/1/2</c> on one of the
- nodes. Now we can start Orber on the other node:</p>
- <code type="erl">
-nodeB@hostB> corba:orb_init([{domain, "MyDiskMultiNodeORB"}]).
-nodeB@hostB> orber:start().
- </code>
- </section>
-
- </section>
-
- <section>
- <title>Configuration</title>
- <marker id="config"></marker>
- <p>It is essential that one configure Orber properly, to avoid, for example,
- malicious attacks and automatically terminate IIOP connections no longer
- in use. An easy way to extract information about Orber's configuration
- parameters is to invoke the operation
- <seealso marker="orber">orber:info/1/2</seealso>.
- Orber offer the following configuration parameters:</p>
- <table>
- <row>
- <cell align="center" valign="middle"><em>Key</em></cell>
- <cell align="center" valign="middle"><em>Range</em></cell>
- <cell align="center" valign="middle"><em>Default</em></cell>
- </row>
- <row>
- <cell align="left" valign="middle">domain</cell>
- <cell align="left" valign="middle">string()</cell>
- <cell align="left" valign="middle">"ORBER"</cell>
- </row>
- <row>
- <cell align="left" valign="middle">iiop_port</cell>
- <cell align="left" valign="middle">integer() >= 0</cell>
- <cell align="left" valign="middle">4001</cell>
- </row>
- <row>
- <cell align="left" valign="middle">nat_iiop_port</cell>
- <cell align="left" valign="middle">integer() > 0 | {local, integer(), [{integer(), integer()}]}</cell>
- <cell align="left" valign="middle">The same as <c>iiop_port</c></cell>
- </row>
- <row>
- <cell align="left" valign="middle">iiop_out_ports</cell>
- <cell align="left" valign="middle">0 | {integer(),integer()}</cell>
- <cell align="left" valign="middle">0</cell>
- </row>
- <row>
- <cell align="left" valign="middle">iiop_out_ports_attempts</cell>
- <cell align="left" valign="middle">integer() > 0</cell>
- <cell align="left" valign="middle">1</cell>
- </row>
- <row>
- <cell align="left" valign="middle">iiop_out_ports_random</cell>
- <cell align="left" valign="middle">true | false</cell>
- <cell align="left" valign="middle">false</cell>
- </row>
- <row>
- <cell align="left" valign="middle">iiop_max_fragments</cell>
- <cell align="left" valign="middle">integer() > 0 | infinity</cell>
- <cell align="left" valign="middle">infinity</cell>
- </row>
- <row>
- <cell align="left" valign="middle">iiop_max_in_requests</cell>
- <cell align="left" valign="middle">integer() > 0 | infinity</cell>
- <cell align="left" valign="middle">infinity</cell>
- </row>
- <row>
- <cell align="left" valign="middle">iiop_max_in_connections</cell>
- <cell align="left" valign="middle">integer() > 0</cell>
- <cell align="left" valign="middle">infinity</cell>
- </row>
- <row>
- <cell align="left" valign="middle">iiop_backlog</cell>
- <cell align="left" valign="middle">integer() > 0</cell>
- <cell align="left" valign="middle">5</cell>
- </row>
- <row>
- <cell align="left" valign="middle">iiop_packet_size</cell>
- <cell align="left" valign="middle">integer() > 0 | infinity</cell>
- <cell align="left" valign="middle">infinity</cell>
- </row>
- <row>
- <cell align="left" valign="middle">ip_address</cell>
- <cell align="left" valign="middle">string() | {multiple, [string()]}</cell>
- <cell align="left" valign="middle">All interfaces</cell>
- </row>
- <row>
- <cell align="left" valign="middle">ip_address_local</cell>
- <cell align="left" valign="middle">string()</cell>
- <cell align="left" valign="middle">Defined by the underlying system</cell>
- </row>
- <row>
- <cell align="left" valign="middle">nat_ip_address</cell>
- <cell align="left" valign="middle">string() | {multiple, [string()]} | {local, string(), [{string(), string()}]}</cell>
- <cell align="left" valign="middle">The same as <c>ip_address</c></cell>
- </row>
- <row>
- <cell align="left" valign="middle">objectkeys_gc_time</cell>
- <cell align="left" valign="middle">integer() > 0 | infinity</cell>
- <cell align="left" valign="middle">infinity</cell>
- </row>
- <row>
- <cell align="left" valign="middle">giop_version</cell>
- <cell align="left" valign="middle">{1,0} | {1,1} | {1,2}</cell>
- <cell align="left" valign="middle">{1,1}</cell>
- </row>
- <row>
- <cell align="left" valign="middle">iiop_setup_connection_timeout</cell>
- <cell align="left" valign="middle">integer() > 0 | infinity</cell>
- <cell align="left" valign="middle">infinity</cell>
- </row>
- <row>
- <cell align="left" valign="middle">iiop_connection_timeout</cell>
- <cell align="left" valign="middle">integer() > 0 | infinity</cell>
- <cell align="left" valign="middle">infinity</cell>
- </row>
- <row>
- <cell align="left" valign="middle">iiop_in_connection_timeout</cell>
- <cell align="left" valign="middle">integer() > 0 | infinity</cell>
- <cell align="left" valign="middle">infinity</cell>
- </row>
- <row>
- <cell align="left" valign="middle">iiop_out_keepalive</cell>
- <cell align="left" valign="middle">true | false</cell>
- <cell align="left" valign="middle">false</cell>
- </row>
- <row>
- <cell align="left" valign="middle">iiop_in_keepalive</cell>
- <cell align="left" valign="middle">true | false</cell>
- <cell align="left" valign="middle">false</cell>
- </row>
- <row>
- <cell align="left" valign="middle">iiop_timeout</cell>
- <cell align="left" valign="middle">integer() > 0 | infinity</cell>
- <cell align="left" valign="middle">infinity</cell>
- </row>
- <row>
- <cell align="left" valign="middle">interceptors</cell>
- <cell align="left" valign="middle">{native, [atom()]}</cell>
- <cell align="left" valign="middle">-</cell>
- </row>
- <row>
- <cell align="left" valign="middle">local_interceptors</cell>
- <cell align="left" valign="middle">{native, [atom()]}</cell>
- <cell align="left" valign="middle">-</cell>
- </row>
- <row>
- <cell align="left" valign="middle">orbInitRef</cell>
- <cell align="left" valign="middle">[string()] | undefined</cell>
- <cell align="left" valign="middle">undefined</cell>
- </row>
- <row>
- <cell align="left" valign="middle">orbDefaultInitRef</cell>
- <cell align="left" valign="middle">string() | undefined</cell>
- <cell align="left" valign="middle">undefined</cell>
- </row>
- <row>
- <cell align="left" valign="middle">orber_debug_level</cell>
- <cell align="left" valign="middle">0 - 10</cell>
- <cell align="left" valign="middle">0</cell>
- </row>
- <row>
- <cell align="left" valign="middle">flags</cell>
- <cell align="left" valign="middle">integer() >= 0</cell>
- <cell align="left" valign="middle">0</cell>
- </row>
- <row>
- <cell align="left" valign="middle">iiop_acl</cell>
- <cell align="left" valign="middle">[{atom(), string()}] | [{atom(), string(), [string()]}]</cell>
- <cell align="left" valign="middle">[]</cell>
- </row>
- <row>
- <cell align="left" valign="middle">secure</cell>
- <cell align="left" valign="middle">no | ssl</cell>
- <cell align="left" valign="middle">no</cell>
- </row>
- <row>
- <cell align="left" valign="middle">ssl_generation</cell>
- <cell align="left" valign="middle">2 | 3</cell>
- <cell align="left" valign="middle">2</cell>
- </row>
- <row>
- <cell align="left" valign="middle">iiop_ssl_port</cell>
- <cell align="left" valign="middle">integer() >= 0</cell>
- <cell align="left" valign="middle">4002</cell>
- </row>
- <row>
- <cell align="left" valign="middle">iiop_ssl_accept_timeout</cell>
- <cell align="left" valign="middle">integer() > 0 | infinity</cell>
- <cell align="left" valign="middle">infinity</cell>
- </row>
- <row>
- <cell align="left" valign="middle">iiop_ssl_backlog</cell>
- <cell align="left" valign="middle">integer() > 0</cell>
- <cell align="left" valign="middle">5</cell>
- </row>
- <row>
- <cell align="left" valign="middle">iiop_ssl_ip_address_local</cell>
- <cell align="left" valign="middle">string()</cell>
- <cell align="left" valign="middle">Defined by the underlying system</cell>
- </row>
- <row>
- <cell align="left" valign="middle">nat_iiop_ssl_port</cell>
- <cell align="left" valign="middle">integer() > 0 | {local, integer(), [{integer(), integer()}]}</cell>
- <cell align="left" valign="middle">The same as <c>iiop_ssl_port</c></cell>
- </row>
- <row>
- <cell align="left" valign="middle">ssl_server_options</cell>
- <cell align="left" valign="middle">list()</cell>
- <cell align="left" valign="middle">See the <seealso marker="ssl:ssl">SSL application</seealso>
- for valid options.</cell>
- </row>
- <row>
- <cell align="left" valign="middle">ssl_client_options</cell>
- <cell align="left" valign="middle">list()</cell>
- <cell align="left" valign="middle">See the <seealso marker="ssl:ssl">SSL application</seealso>
- for valid options.</cell>
- </row>
- <row>
- <cell align="left" valign="middle">iiop_ssl_out_keepalive</cell>
- <cell align="left" valign="middle">true | false</cell>
- <cell align="left" valign="middle">false</cell>
- </row>
- <row>
- <cell align="left" valign="middle">iiop_ssl_in_keepalive</cell>
- <cell align="left" valign="middle">true | false</cell>
- <cell align="left" valign="middle">false</cell>
- </row>
- <tcaption>Orber Configuration Parameters</tcaption>
- </table>
- <br></br>
- <br></br>
- <p><em>Comments on the table 'Orber Configuration Parameters':</em></p>
- <taglist>
- <tag><em>domain</em></tag>
- <item>Since Orber domains, they are supposed to communicate via IIOP,
- <em>MUST</em> have unique names, communication will
- fail if two domains have the same name. The domain name <em>MAY NOT</em>
- contain <c>^G</c> (i.e. <c>\007</c>).</item>
- <tag><em>iiop_port</em></tag>
- <item>If set to 0 the OS will pick any vacant port.
- <br></br>
-<em>Note:</em>On a UNIX system it is preferable to
- have a IIOP port higher than 1023, since it is not recommended to
- run Erlang as a root user.</item>
- <tag><em>nat_iiop_port</em></tag>
- <item>The value is either an integer or <c>{local, DefaultNATPort, [{Port, NATPort}]}</c>. See also
- <seealso marker="ch_install#firewall">Firewall Configuration</seealso>.</item>
- <tag><em>iiop_out_ports</em></tag>
- <item>When set to 0 any available port will be used.
- If a range is specified, Orber will only
- use the local ports within the interval when trying to connect to
- another ORB (Orber acts as a client ORB). If all ports are in use
- communication will fail. Hence, it is <em>absolutely necessary</em> to
- set <c>iiop_connection_timeout</c> as well. Otherwise, connections
- no longer in use will block further communication. If one use, for
- example, <c>erl -orber iiop_out_ports "{5000,5020}"</c>, Orber
- will only use port 5000 to 5020 when connecting.
- If communicating via SSL, make sure you use a version that supports
- the local <c>{port, Port}</c> option. See also
- <seealso marker="ch_install#firewall">Firewall Configuration</seealso>.</item>
- <tag><em>iiop_out_ports_random</em></tag>
- <item>Requires that <c>iiop_out_ports</c> define a port range. If that is the
- case Orber will select a port randomly from that sequence.</item>
- <tag><em>iiop_out_ports_attempts</em></tag>
- <item>Requires that <c>iiop_out_ports</c> define a port range. If so Orber will
- accept a number of timeouts, defined by this parameter, when trying to connect
- to another ORB.</item>
- <tag><em>iiop_max_fragments</em></tag>
- <item>Limits the number of IIOP fragments allowed per request.</item>
- <tag><em>iiop_max_in_requests</em></tag>
- <item>Limits the number of concurrent incoming requests per incoming connection.</item>
- <tag><em>iiop_max_in_connections</em></tag>
- <item>Limits the number of concurrent incoming connections.</item>
- <tag><em>iiop_backlog</em></tag>
- <item>Defines the maximum length the queue of pending incoming
- connections may grow to.</item>
- <tag><em>iiop_packet_size</em></tag>
- <item>Defines the maximum size of incoming requests.
- If this limit is exceeded, the connection is closed.</item>
- <tag><em>ip_address</em></tag>
- <item>This option is used if orber only should
- listen on a specific ip interface on a multi-interface host or if
- exported IOR:s should contain multiple components. The value is
- the IPv4 or IPv6 address as a string or <c>{multiple, IPList}</c>.
- The latter requires that the object is available via the all IP addresses
- found in the list.</item>
- <tag><em>ip_address_local</em></tag>
- <item>This option defines the default local interface Orber will
- use when connecting to another ORB via IIOP, i.e., Orber act as the
- client side ORB. The value is a IPv4 or IPv6 address as a string.
- It is possible to override <c>ip_address_local</c> by defining
- <c>iiop_acl</c> or passing the Orber generic <c>interface</c> Context.
- If this option is not used, the underlying OS will choose which interface to
- use. For more information, see the
- <seealso marker="ch_install#interfaces">Interface Configuration</seealso>
- section.</item>
- <tag><em>nat_ip_address</em></tag>
- <item>The value is the ip address as
- a string (IPv4 or IPv6), <c>{multiple, IPList}</c> or
- <c>{local, DefaultNATIPAddress, [{IPAddress, NATIPAddress}]}</c>. See also
- <seealso marker="ch_install#firewall">Firewall Configuration</seealso>.</item>
- <tag><em>objectkeys_gc_time</em></tag>
- <item>This option should be set if objects are started
- using the option <c>{persistent, true}</c>.
- The value is <c>integer()</c> seconds.</item>
- <tag><em>giop_version</em></tag>
- <item>Defines the default GIOP protocol version.</item>
- <tag><em>iiop_setup_connection_timeout</em></tag>
- <item>The value is an integer (seconds) or the atom infinity.
- This option is only valid for client-side
- connections. If this option is set, attempts to connect to other ORB's
- will timeout after the given time limit. Note, if the time limit is large
- the TCP protocol may timeout before the supplied value.</item>
- <tag><em>iiop_connection_timeout</em></tag>
- <item>The value is an integer (timeout in seconds between 0 and 1000000)
- or the atom infinity. This option is only valid for client object
- connections, i.e., will have no effect on server connections. Setting this
- option will cause client connections to be terminated, if and only if,
- there are no pending requests. If there are a client still waiting for
- a reply, Orber will try again after the given seconds have passed. The main
- purpose for this option is to reduce the number of open connections; it is,
- for example, not necessary to keep a connection, only used once a day,
- open at all time.</item>
- <tag><em>iiop_in_connection_timeout</em></tag>
- <item>The same as for <c>iiop_connection_timeout</c>. The only difference is
- that this option only affects incoming connections (i.e. Orber act as
- server-side ORB).</item>
- <tag><em>iiop_out_keepalive</em></tag>
- <item>Enables periodic transmission on a connected socket, when no other
- data is being exchanged. If the other end does not respond, the
- connection is considered broken and will be terminated.
- When enabled the SO_KEEPALIVE socket level option is set.</item>
- <tag><em>iiop_in_keepalive</em></tag>
- <item>The same as for <c>iiop_out_keepalive</c>. The only difference is
- that this option only affects incoming connections.</item>
- <tag><em>iiop_timeout</em></tag>
- <item>The value is an integer (timeout in seconds between 0 and 1000000)
- or the atom infinity. This option is only valid on the client side.
- Setting this option, cause all intra-ORB requests to timeout and
- raise a system exception, e.g. <c>TIMEOUT</c>, if no replies are delivered
- within the given time limit.</item>
- <tag><em>interceptors</em></tag>
- <item>If one set this parameter, e.g.,
- <c>erl -orber interceptors "{native, ['myInterceptor']}"</c>,
- Orber will use the supplied interceptor(s) for all inter-ORB
- communication. <c>'myInterceptor'</c> is the module name of the
- interceptor. For more information, see the interceptor chapter
- in the User's Guide and the Reference Manual.</item>
- <tag><em>local_interceptors</em></tag>
- <item>If defined, its value will be
- used when activating local interceptors via
- <seealso marker="ch_install#flags">Orber Environment Flags</seealso>.
- If not defined, but the flag is set, Orber will use the value of
- the <c>interceptors</c> parameter.</item>
- <tag><em>orbInitRef</em></tag>
- <item>Setting this option, e.g.,
- <c>erl -orber orbInitRef [\"NameService=corbaloc::host.com/NameService\"]</c>,
- will alter the location from where <c>corba:resolve_initial_references(Key)</c>
- tries to find an object matching the given Key. The keys will also appear when
- invoking <c>corba:list_initial_services()</c>. This variable overrides
- <c>orbDefaultInitRef</c></item>
- <tag><em>orbDefaultInitRef</em></tag>
- <item>If a matching Key for <c>orbInitRef</c> is not
- found, and this variable is set, it determines the location from where
- <c>orber:resolve_initial_references(Key)</c> tries to find an object
- matching the given Key. Usage:
- <c>erl -orber orbDefaultInitRef \"corbaloc::host.com\"</c>.</item>
- <tag><em>orber_debug_level</em></tag>
- <item>The range is 0 to 10.
- Using level 10 is the most verbose configuration.
- This option will generate reports, using the <c>error_logger</c>,
- for abnormal situations. It is not recommended to use this option
- for delivered systems since some of the reports is not to be considered
- as errors. The main purpose is to assist during development.</item>
- <tag><em>flags</em></tag>
- <item>No flags are activated in the default case.
- The available configuration settings are described in
- <seealso marker="ch_install#flags">Orber Environment Flags</seealso>.</item>
- <tag><em>iiop_acl</em></tag>
- <item>This option must be activated by setting
- <seealso marker="ch_install#flags">Orber Environment Flags</seealso> parameter.
- The value of this parameter shall be a list of <c>[{Direction, Filter}]</c>
- and/or <c>[{Direction, Filter, [Interfaces]}]</c>. The <c>Direction</c>,
- <c>tcp_in</c>, <c>ssl_in</c>, <c>tcp_out</c> or <c>ssl_out</c>, determines if
- the Access Control List (ACL) applies to incoming or outgoing connections
- and IIOP or IIOP over SSL. The <c>Filter</c> uses a extended format of
- Classless Inter Domain Routing (CIDR). For example, <c>"123.123.123.10"</c> limits
- the connection to that particular host, while <c>"123.123.123.10/17"</c> allows
- connections to or from any host equal to the 17 most significant bits. Orber
- also allow the user to specify a certain port or port range, for example,
- <c>"123.123.123.10/17#4001"</c> and <c>"123.123.123.10/17#4001/5001"</c>
- respectively. IPv4 or none compressed IPv6 strings are accepted. <br></br>
-
- The list of <c>Interfaces</c>, IPv4 or IPv6 strings, may only contain
- <em>one</em> address for outgoing connections. For incoming connections,
- the <c>Interfaces</c> list may contain several IP strings. If set for
- outgoing connections, and access is granted, Orber will use that local
- interface when connecting to the server-side ORB. For incoming connections,
- the client-side ORB is required to use one of the listed interfaces locally.
- If it fail to do so, access will be denied. The module
- <seealso marker="orber_acl">orber_acl</seealso> provides operations for
- evaluating the access control for filters and addresses. See also the
- <seealso marker="ch_install#interfaces">Interface Configuration</seealso>
- and
- <seealso marker="ch_install#firewall">Firewall Configuration</seealso>
- chapters.</item>
- <tag><em>secure</em></tag>
- <item>Determines the security mode Orber will use, which is either
- <c>no</c> if it is an insecure domain or the type of security
- mechanism used. Currently, per default, Orber is compliant with
- <c>CSIv1</c> level 0, which means IIOP via SSL/TLS.
- The security chapter later in this manual describes how to get security
- in Orber and how the options are used.</item>
- <tag><em>ssl_generation</em></tag>
- <item>Defines which SSL version, i.e. available API, is installed. The
- default value, <c>2</c>, refers to SSL-3.1 or later, but earlier than SSL-4.0.
- If set to <c>3</c> SSL-4.0, or later, must be available. Currently it not possible
- to use <c>1</c>, it is only reserved for future use.</item>
- <tag><em>iiop_ssl_port</em></tag>
- <item>If set, the value must be an
- integer greater than zero and not equal to <em>iiop_port</em>.</item>
- <tag><em>iiop_ssl_accept_timeout</em></tag>
- <item>The value is an integer (timeout in seconds) or the atom infinity and
- determine how long the SSL handshake may take. This option should
- be set to avoid if a client never initiate the handshake.</item>
- <tag><em>iiop_ssl_backlog</em></tag>
- <item>Defines the maximum length the queue of pending incoming
- connections may grow to.</item>
- <tag><em>iiop_ssl_ip_address_local</em></tag>
- <item>This option defines the default local interface Orber will
- use when connecting to another ORB via IIOP SSL, i.e., Orber act as the
- client side ORB. The value is a IPv4 or IPv6 address as a string.
- It is possible to override <c>iiop_ssl_ip_address_local</c> by defining
- <c>iiop_acl</c> or passing the Orber generic <c>interface</c> Context.
- If this option is not used, the underlying OS will choose which interface to
- use. For more information, see the
- <seealso marker="ch_install#interfaces">Interface Configuration</seealso>
- section.</item>
- <tag><em>nat_iiop_ssl_port</em></tag>
- <item>If set, the value must be an integer greater than zero or
- <c>{local, DefaultNATPort, [{Port, NATPort}]}</c>. See also
- <seealso marker="ch_install#firewall">Firewall Configuration</seealso>.</item>
- <tag><em>ssl_server_options</em></tag>
- <item>A list of the SSL options when Orber is the server.
- In general it's just to remove the 'ssl_server_' prefix from the old options,
- i.e. <c>ssl_server_verify</c> will just be <c>verify</c> in this option list.
- See the <seealso marker="ssl:ssl">SSL application</seealso> for the correct list of possible
- options and their values.
- </item>
- <tag><em>ssl_client_options</em></tag>
- <item>A list of the SSL options when Orber is the client.
- In general it's just to remove the <c>ssl_client_</c> prefix from the old options,
- i.e. <c>ssl_client_depth</c> will just be <c>depth</c> in this option list.
- See the <seealso marker="ssl:ssl">SSL application</seealso> for the correct list of possible
- options and their values.
- </item>
- <tag><em>iiop_ssl_out_keepalive</em></tag>
- <item>Enables periodic transmission on a connected socket, when no other
- data is being exchanged. If the other end does not respond, the
- connection is considered broken and will be terminated.
- When enabled the SO_KEEPALIVE socket level option is set. Requires that
- the installed SSL version support the <em>keepalive</em> option
- and that the <em>ssl_generation</em> points to this version.</item>
- <tag><em>iiop_ssl_in_keepalive</em></tag>
- <item>The same as for <c>iiop_ssl_out_keepalive</c>. The only difference is
- that this option only affects incoming connections.</item>
- </taglist>
- <p>It is possible to invoke operations using the extra timeout parameter:</p>
- <pre>
-erl> module_interface:function(ObjRef, Timeout, ..Arguments..).
-erl> module_interface:function(ObjRef, [{timeout, Timeout}], ..Arguments..).
-erl> module_interface:function(ObjRef, ..Arguments..). </pre>
- <p>The extra Timeout argument will override the configuration parameter
- <c>iiop_timeout</c>. It is, however, not possible to use <c>infinity</c>
- to override the Timeout parameter. The Timeout option is also valid for
- objects which resides within the same <term id="Orber domain"><termdef>A domain containing several Erlang nodes, which are communicating by using the Erlang internal format. An Orber domain looks as one ORB from the environment.</termdef></term>.</p>
- <p>The <c>iiop_setup_connection_timeout</c>, <c>iiop_timeout</c>,
- <c>iiop_connection_timeout</c> and <c>iiop_in_connection_timeout</c>
- variables should be used. The specified values is implementation specific,
- i.e., WAN or LAN, but they should range from
- <c>iiop_setup_connection_timeout</c> to <c>iiop_connection_timeout</c>.</p>
- <p>To change these settings in the configuration file, the
- <c>-config</c> flag must be added to the erl command. See the
- Reference Manual
- <em>config(4)</em> for further information. The values can also
- be sent separately as
- options to the Erlang node when it is started, see the Reference
- Manual
- <em>erl(1)</em> for further information. </p>
-
- <section>
- <marker id="flags"></marker>
- <title>Orber Environment Flags</title>
- <p>The <c>Environment Flags</c> allows the user to activate debugging
- facilities or change Orber's behavior. The latter may result in that
- Orber is no longer compliant with the OMG standard, which may be necessary
- when communicating with a non-compliant ORB.</p>
- <table>
- <row>
- <cell align="left" valign="middle"><em>Hexadecimal Value</em></cell>
- <cell align="left" valign="middle"><em>OMG Compliant</em></cell>
- <cell align="left" valign="middle"><em>Description</em></cell>
- </row>
- <row>
- <cell align="left" valign="middle">0001</cell>
- <cell align="left" valign="middle">no</cell>
- <cell align="left" valign="middle">Exclude CodeSet Component</cell>
- </row>
- <row>
- <cell align="left" valign="middle">0002</cell>
- <cell align="left" valign="middle">yes</cell>
- <cell align="left" valign="middle">Local Typechecking</cell>
- </row>
- <row>
- <cell align="left" valign="middle">0004</cell>
- <cell align="left" valign="middle">yes</cell>
- <cell align="left" valign="middle">Use Host Name in IOR</cell>
- </row>
- <row>
- <cell align="left" valign="middle">0008</cell>
- <cell align="left" valign="middle">yes</cell>
- <cell align="left" valign="middle">Enable NAT</cell>
- </row>
- <row>
- <cell align="left" valign="middle">0020</cell>
- <cell align="left" valign="middle">yes</cell>
- <cell align="left" valign="middle">Local Interceptors</cell>
- </row>
- <row>
- <cell align="left" valign="middle">0080</cell>
- <cell align="left" valign="middle">yes</cell>
- <cell align="left" valign="middle">Light IFR</cell>
- </row>
- <row>
- <cell align="left" valign="middle">0100</cell>
- <cell align="left" valign="middle">yes</cell>
- <cell align="left" valign="middle">Use IPv6</cell>
- </row>
- <row>
- <cell align="left" valign="middle">0200</cell>
- <cell align="left" valign="middle">yes</cell>
- <cell align="left" valign="middle">EXIT Tolerance</cell>
- </row>
- <row>
- <cell align="left" valign="middle">0400</cell>
- <cell align="left" valign="middle">yes</cell>
- <cell align="left" valign="middle">Enable Incoming ACL</cell>
- </row>
- <row>
- <cell align="left" valign="middle">0800</cell>
- <cell align="left" valign="middle">yes</cell>
- <cell align="left" valign="middle">Enable Outgoing ACL</cell>
- </row>
- <row>
- <cell align="left" valign="middle">1000</cell>
- <cell align="left" valign="middle">yes</cell>
- <cell align="left" valign="middle">Use Current Interface in IOR</cell>
- </row>
- <tcaption>Orber Environment Flags</tcaption>
- </table>
- <p>Any combination of the flags above may be used and changes the
- behavior as follows:</p>
- <list type="bulleted">
- <item><em>Exclude CodeSet Component</em> - instruct Orber to exclude
- the CodeSet component in exported IOR:s. When activated, no
- negotiating regarding character and wide character conversions
- between the client and the server will occur. This flag will,
- most likely, cause problems if your IDL specification contains
- the data types wchar and/or wstring.</item>
- <item><em>Local Typechecking</em> -
- If activated, parameters, replies and raised exceptions
- will be checked to ensure that the data is correct. If an error
- occurs, the <c>error_logger</c> is used to generate reports.
- One <em>MAY NOT</em> use this option for delivered systems due
- to the extra overhead. Since this option activates typechecking
- for all objects generated on the target node, it is also possible
- to use the option <c>{local_typecheck, boolean()}</c>, when
- invoking <c>oe_create/2</c>, <c>oe_create_link/2</c>,
- <c>corba:create/4</c> or <c>corba:create_link/4</c>, to override
- the configuration parameter.</item>
- <item><em>Use Host Name in IOR</em> - normally Orber inserts the IP-number
- in IOR:s when they are exported. In some cases, this will cause
- the clients to open two connections instead of one.</item>
- <item><em>Enable NAT</em> - if this flag is set, it is possible to use
- the NAT (Network Address Translation) configuration parameters
- (<c>nat_iiop_port</c>, <c>nat_iiop_ssl_port</c> and
- <c>nat_ip_address</c>).</item>
- <item><em>Local Interceptors</em> - use interceptors for local
- invocations.</item>
- <item><em>Light IFR</em> - if the IFR is not explicitly used and this
- flag is set, Orber will use a minimal IFR to reduce memory usage
- and installation time.</item>
- <item><em>Use IPv6</em> - when this option is activated, Orber will use
- <c>IPv6</c> for inter-ORB communication.</item>
- <item><em>EXIT Tolerance</em> - servers will survive even though the
- call-back module caused an EXIT.</item>
- <item><em>Enable Incoming ACL</em> - activates access control for incoming
- connections.</item>
- <item><em>Enable Outgoing ACL</em> - activates access control for outgoing
- connections.</item>
- <item><em>Use Current Interface in IOR</em> - when set, Orber will add
- the interface the request came via to exported local IOR:s.</item>
- </list>
- <p>Invoking the operation
- <seealso marker="orber">orber:info/1/2</seealso> will display the currently
- set flags in a readable way.</p>
- </section>
- </section>
-
- <section>
- <title>Firewall Configuration</title>
- <marker id="firewall"></marker>
- <p>Firewalls are used to protect objects from clients in other networks or
- sub-networks, but also to restrict which hosts internal objects may connect to
- (i.e. <c>inbound protection</c> and <c>outbound protection</c>). A firewall
- can limit access based on:</p>
- <list type="bulleted">
- <item><em>Transport Level</em> - performs access control decisions based on
- address information in TCP headers.</item>
- <item><em>Application Level</em> - understands GIOP messages and the specific
- transport level inter-ORB Protocol supported e.g. IIOP.</item>
- </list>
- <p>This section describes how to configure a <c>Transport Level</c> firewall. It
- must have prior knowledge of the source to destination mappings, and
- conceptually has a configuration table containing tuples of the form:
- <c>({inhost:inport}, {outhost:outport})</c>. If there are no port restrictions
- it is rather easy to configure the firewall. Otherwise, we must consider the
- following alternatives:</p>
- <list type="bulleted">
- <item><em>Incoming Requests</em> - Orber only uses the port-numbers specified
- by the configuration parameters <em>iiop_port</em> and
- <em>iiop_ssl_port</em>. Other ORB's may use several ports but it should
- be possible to change this behavior. Consult the other ORBs
- documentation.</item>
- <item><em>Outgoing Requests</em> - Most ORB's, Orber included,
- ask the OS to supply a vacant local port when connecting to the
- server-side ORB. It is possible to change this behavior when using
- Orber (i.e. set the configuration parameter <em>iiop_out_ports</em>).</item>
- </list>
- <warning>
- <p>Using the option <c>iiop_out_ports</c> may result in that Orber runs out of
- valid ports numbers. For example, other applications may steal some of the
- ports or the number of concurrent outgoing connections to other ORBs may be
- higher than expected. To reduce, but not eliminate, the risk you should use
- <c>iiop_connection_timeout</c>.</p>
- </warning>
- <p>Firewall configuration example:</p>
- <pre>
-# "Plain" IIOP
-To: Orber-IPNo:(iiop_port) From: ORB-IPNo:X
-To: ORB-IPNo:Z From: Orber-IPNo:(iiop_out_ports | Any Port)
-
-# IIOP via SSL
-To: Orber-IPNo:(iiop_port) From: ORB-IPNo:X
-To: Orber-IPNo:(iiop_ssl_port) From: ORB-IPNo:Y
-To: ORB-IPNo:Z From: Orber-IPNo:(iiop_out_ports | Any Port)
- </pre>
- <p>If the communication take place via a
- <seealso marker="ch_install#firewall_nat">TCP Firewall with NAT</seealso>
- (Network Address Translation), we must activate this behavior and define
- the external address and/or ports.</p>
- <marker id="firewall_nat"></marker>
- <image file="firewall_nat.gif">
- <icaption>
-TCP Firewall With NAT</icaption>
- </image>
- <p>Using NAT makes it possible to use different host data for different network
- domains. This way we can share Internet Protocol address resources or
- obscure resources. To enable this feature the
- <seealso marker="ch_install#flags">Enable NAT</seealso> flag must be set and
- <c>nat_iiop_port</c>, <c>nat_iiop_ssl_port</c> and <c>nat_ip_address</c>
- configured, which maps to <c>iiop_port</c>, <c>iiop_ssl_port</c> and
- <c>ip_address</c> respectively. Hence, the firewall must be configured to
- translate the external to the internal representation correctly. If these NAT parameters
- are assigned a single port number or IP address, only those will be used when
- an IOR is exported to another ORB. When <c>ip_address</c> is set to
- <c>{multiple, [IPAddress]}</c>, <c>nat_ip_address</c> should be configured in the same
- way, so that each NAT IP address can be translated to a valid address by the firewall.
- If objects are supposed to be accessible via different interfaces and port, see also
- <seealso marker="ch_install#interfaces">Interface Configuration</seealso>,
- the options <c>{local, DefaultNATIPAddress, [{IPAddress, NATIPAddress}]}</c> and/or
- <c>{local, DefaultNATPort, [{Port, NATPort}]}</c> shall be used. The default NAT IP address
- and port, should be translated to the value of <c>ip_address_local</c> and the default
- listen port by the firewall. If the IP address and/or port is not found in the list,
- the default values will be inserted in the IOR. The firewall must be able to translate
- these correctly.</p>
- <p>If it is necessary to limit the access to an ORB within a secure network,
- but other applications running on the same host may not be blocked out,
- one can use a <em>Application Level</em> firewall or Orber Access Control
- List (ACL). The latter makes it possible for the user to define which hosts
- may communicate, either as server or client, with Orber. This is achieved by
- defining the configuration parameter
- <seealso marker="ch_install#config">iiop_acl</seealso>. The Classless Inter
- Domain Routing (CIDR) <c>Filter</c> determines which peer interfaces and
- ports the other ORB may use.</p>
- <table>
- <row>
- <cell align="left" valign="middle"><em>Filter</em></cell>
- <cell align="left" valign="middle"><em>Peer Interface(s)</em></cell>
- <cell align="left" valign="middle"><em>Peer Port(s)</em></cell>
- </row>
- <row>
- <cell align="left" valign="middle">"10.1.1.1"</cell>
- <cell align="left" valign="middle">10.1.1.1</cell>
- <cell align="left" valign="middle">any</cell>
- </row>
- <row>
- <cell align="left" valign="middle">"10.1.1.1/8"</cell>
- <cell align="left" valign="middle">10.0.0.0-10.255.255.255</cell>
- <cell align="left" valign="middle">any</cell>
- </row>
- <row>
- <cell align="left" valign="middle">"10.1.1.1/8#4001"</cell>
- <cell align="left" valign="middle">10.0.0.0-10.255.255.255</cell>
- <cell align="left" valign="middle">4001</cell>
- </row>
- <row>
- <cell align="left" valign="middle">"10.1.1.1/8#4001/5001"</cell>
- <cell align="left" valign="middle">10.0.0.0-10.255.255.255</cell>
- <cell align="left" valign="middle">4001-5001</cell>
- </row>
- <tcaption>Orber ACL Filters</tcaption>
- </table>
- <p>Orber ACL, also allows the user to define which local interface(s) may be used,
- but will not detect <c>spoofing</c>. The operation
- <seealso marker="orber_acl">orber_acl:match/2/3</seealso> makes it easy to
- verify whether access would be granted or not. For example, if Orber would
- be started with the ACL <c>[{tcp_out, "10.1.1.1/8#4001/5001"}]</c>, then
- <c>orber_acl:match/2</c> would behave as follows:</p>
- <code type="erl">
-erl> orber_acl:match({11,1,1,1}, tcp_out).
-false
-
-erl> orber_acl:match({10,1,1,1}, tcp_out).
-true
-
-erl> orber_acl:match({11,1,1,1}, tcp_out, true).
-{false,[],0}
-
-erl> orber_acl:match({10,1,1,1}, tcp_out, true).
-{true,[],{4001,5001}}
- </code>
- <p>Only if the returned boolean is true the extra return values makes a
- difference. In the example above, <c>{true,[],{4001,5001}}</c> means that
- Orber may connect to <c>"10.1.1.1"</c>, using any local interface,
- if the server-side ORB listens for incoming connect requests on a port
- within the range 4001-5001. Note, invoking the <c>orber_acl:match/2/3</c>
- operation, will not result in a connect attempt by Orber. The reason for
- this, is that this function may be used on a live node as well as in test
- environment. Hence, if a local interface is currently not available or no
- server-side ORB available via the given host/port(s), will not be detected
- by Orber.</p>
- </section>
-
- <section>
- <title>Interface Configuration</title>
- <marker id="interfaces"></marker>
- <p>In many cases it is sufficient to simply configure the underlying OS which
- local interfaces shall be used for all applications. But, in some cases
- it is required, due to, for example, the firewall configuration, that different
- local interfaces are used for different applications. Some times, it is even
- necessary to use a specific interface for a single CORBA object. This section
- describe how one can alter this in different ways.</p>
- <p>The default behavior is that Orber lets the OS configuration decide which interface
- will be added in IOR:s exported to another ORB and the local interface used
- when connecting to another ORB (Orber act as client side ORB). The latter can be
- overridden by setting the configuration parameters <c>iiop_ssl_ip_address_local</c>
- and/or <c>ip_address_local</c>, which will affect IIOP via SSL and IIOP
- respectively. These parameters can be overridden by using the Orber generic
- <c>interface</c> Context or defining an ACL (Access Control List). The latter
- always takes precedence if a local interface is included (e.g.
- <c>[{tcp_out, "10.0.0.0/8", ["10.0.0.1"]}]</c>). If the interface is excluded
- (e.g. <c>[{tcp_out, "10.0.0.0/8"}]</c>), the interface chosen will, in the following
- order, be determined by
- <c>#'IOP_ServiceContext'{}</c>, <c>ip_address_local/iiop_ssl_ip_address_local</c> or
- the configuration of the underlying system.</p>
- <p>Adding the interface context, for generated stubs/skeletons, is done in the
- following way:</p>
- <code type="erl">
-Ctx = #'IOP_ServiceContext'{context_id = ?ORBER_GENERIC_CTX_ID,
- context_data = {interface, "10.0.0.1"}},
-'CosNaming_NamingContext':resolve(NS, [{context, [Ctx]}], Name),
- </code>
- <p>It is also possible to add the context to
- <c>corba:string_to_object/2, corba:resolve_initial_references/2, corba:resolve_initial_references_remote/3, corba:list_initial_services_remote/2, corba_object:not_existent/2, corba_object:non_existent/2</c> and <c>corba_object:is_a/3</c>.
- The operations exported by <c>corba_object</c> are affected
- if the supplied IOR is external. The function <c>corba:string_to_object/2</c>
- might require the interface context if a <c>corbaloc</c> or a <c>corbaloc</c>
- string is passed (See the
- <seealso marker="ch_naming_service#interop_ns">INS</seealso> chapter),
- while <c>corba:resolve_initial_references_remote/3</c> and
- <c>corba:list_initial_services_remote/2</c> always connect to another ORB and
- it might be necessary to add the context.
- The remaining <c>corba</c> operations are affected if calls are re-directed
- by setting the <c>orbInitRef</c> and/or <c>orbDefaultInitRef</c> configuration
- parameters. For more information, see the Reference Manual for each module.</p>
- <p>Configuring which interface(s) that shall be used when exporting an IOR to
- another ORB, is determined by <c>nat_ip_address</c>, setting the flag
- <seealso marker="ch_install#flags">16#1000</seealso>
- and <c>ip_address</c>, in that order. Orber listens for incoming connections
- either via all interfaces or the interface defined by <c>ip_address</c>. It is
- also possible to add and remove extra listen interfaces by using
- <c>orber:add_listen_interface/2/3</c> and <c>orber:remove_listen_interface/1</c>.
- In this case one should set the 16#1000 flag and, if necessary, set the
- configuration parameters
- <c>{local, DefaultNATIPAddress, [{IPAddress, NATIPAddress}]}</c> and/or
- <c>{local, DefaultNATPort, [{Port, NATPort}]}</c>.</p>
- </section>
-</chapter>
-
diff --git a/lib/orber/doc/src/ch_interceptors.xml b/lib/orber/doc/src/ch_interceptors.xml
deleted file mode 100644
index 4a9f8e69ca..0000000000
--- a/lib/orber/doc/src/ch_interceptors.xml
+++ /dev/null
@@ -1,278 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2001</year><year>2017</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Orber Interceptors</title>
- <prepared>Nick</prepared>
- <docno></docno>
- <date>2001-08-16</date>
- <rev></rev>
- <file>ch_interceptors.xml</file>
- </header>
-
- <section>
- <title>Using Interceptors</title>
- <p>For Inter-ORB communication, e.g., via <c>IIOP</c>, it is possible
- to intercept requests and replies. To be able to use <c>Interceptors</c>
- Orber the configuration parameter <c>interceptors</c> must be defined.</p>
-
- <section>
- <title>Configure Orber to Use Interceptors</title>
- <p>The configuration parameter <c>interceptors</c> must be defined, e.g.,
- as command line option:</p>
- <code type="none">
-erl -orber interceptors "{native, ['myInterceptor']}"
- </code>
- <p>It is possible to use more than one interceptor; simply add them to the
- list and they will be invoked in the same order as they appear in the list.</p>
- <p>One can also active and deactivate an interceptor during
- run-time, but this will only affect currently existing connections.
- For more information, consult Orber's Reference Manual regarding the
- operations <c>orber:activate_audit_trail/0/1</c> and
- <c>orber:activate_audit_trail/0/1.</c></p>
- </section>
-
- <section>
- <title>Creating Interceptors</title>
- <p>Each supplied interceptor <em>must</em> export the following functions:</p>
- <list type="bulleted">
- <item><em>new_out_connection/3/5</em> - one of these operations is called when
- a client application calls an object residing on remote ORB.
- If an interceptor exports both versions, arity 3 and 5, which
- operation that will be invoked is Orber internal.</item>
- <item><em>new_in_connection/3/5</em> - one of these operations is invoked
- when a client side ORB tries to set up a connection to the target ORB.
- If an interceptor exports both versions, arity 3 and 5, which
- operation that will be invoked is Orber internal.</item>
- <item><em>out_request/6</em> - supplies all request data on the client side
- ORB.</item>
- <item><em>out_request_encoded/6</em> - similar to <c>out_request</c>
- but the request body is encode.</item>
- <item><em>in_request_encoded/6</em> - after a new request arrives at the
- target ORB the request data is passed to the interceptor in
- encoded format.</item>
- <item><em>in_request/6</em> - prior to invoking the operation on the
- target object, the interceptor <c>in_request</c> is called.</item>
- <item><em>out_reply/6</em> - after the target object replied the
- <c>out_reply</c> operation is called with the result of the object
- invocation.</item>
- <item><em>out_reply_encoded/6</em> - before sending a reply back to the
- client side ORB this operation is called with the result in
- encoded format.</item>
- <item><em>in_reply_encoded/6</em> - after the client side ORB receives
- a reply this function is called with the reply in encoded
- format.</item>
- <item><em>in_reply/6</em> - before delivering the reply to the client
- this operation is invoked.</item>
- <item><em>closed_in_connection/1</em> - when a connection is terminated
- on the client side this function is called.</item>
- <item><em>closed_out_connection/1</em> - if an outgoing connection is
- terminated this operation will be invoked.</item>
- </list>
- <p>The operations <c>new_out_connection</c>, <c>new_in_connection</c>,
- <c>closed_in_connection</c> and <c>closed_out_connection</c> operations
- are only invoked <em>once</em> per connection. The remaining operations
- are called, as shown below, for every Request/Reply to/from remote
- CORBA Objects.</p>
- <marker id="interceptor_operations"></marker>
- <image file="interceptor_operations.gif">
- <icaption>
-The Invocation Order of Interceptor Functions.</icaption>
- </image>
- </section>
- </section>
-
- <section>
- <title>Interceptor Example</title>
- <p>Assume we want to create a simple access service which purpose is to:</p>
- <list type="bulleted">
- <item>Only allow incoming request from ORB's residing on a certain set of
- nodes.</item>
- <item>Restrict the objects any client may invoke operations on.</item>
- <item>Only allow outgoing requests to call a limited set of external
- ORB's.</item>
- <item>Add a checksum to each binary request/reply body.</item>
- </list>
- <p>To restricts the access we use a <c>protected</c> and <c>named</c> ets-table
- holding all information. How the ets-table is initiated and maintained
- is implementation specific, but it contain
- <c>{Node, ObjectTable, ChecksumModule}</c> where <c>Node</c> is used as
- ets-key, <c>ObjectTable</c> is a reference to another ets-table in which
- we store which objects the clients are allowed to invoke operations on
- and <c>ChecksumModule</c> determines which module we should use to handle
- the checksums. </p>
- <code type="erl">
-new_in_connection(Arg, Host, Port) ->
- %% Since we only use one interceptor we do not care about the
- %% input Arg since it is set do undefined by Orber.
- case ets:lookup(in_access_table, Host) of
- [] ->
- %% We may want to log the Host/Port to see if someone tried
- %% to hack in to our system.
- exit("Access not granted");
- [{Host, ObjTable, ChecksumModule}] ->
- {ObjTable, ChecksumModule}
- end.
- </code>
- <p>The returned tuple, i.e., {ObjTable, ChecksumModule}, will be passed
- as the first argument whenever invoking one of the interceptor functions.
- Unless the connection attempt did not fail we are now ready for receiving
- requests from the client side ORB.</p>
- <p>When a new request comes in the first interceptor function to be invoked is
- <c>in_request_encoded</c>. We will remove the checksum from the coded
- request body in the following way:</p>
- <code type="erl">
-in_request_encoded({ObjTable, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) ->
- NewBin = ChecksumModule:remove_checksum(Bin),
- {NewBin, Extra}.
- </code>
- <p>If the checksum check fails the <c>ChecksumModule</c> should invoke exit/1.
- But if the check succeeded we are now ready to check if the client-ORB
- objects are allowed to invoke operations on the target object. Please note,
- it is possible to run both checks in <c>in_request_encoded</c>. Please
- note, the checksum calculation must be relatively fast to ensure a
- good throughput.</p>
- <p>If we want to we can restrict any clients to only use a subset of operations
- exported by a server:</p>
- <code type="erl">
-in_request({ObjTable, ChecksumModule}, ObjKey, Ctx, Op, Params, Extra) ->
- case ets:lookup(ObjTable, {ObjKey, Op}) of
- [] ->
- exit("Client tried to invoke illegal operation");
- [SomeData] ->
- {Params, Extra}
- end.
- </code>
- <p>At this point Orber are now ready to invoke the operation on the target
- object. Since we do not care about what the reply is the <c>out_reply</c>
- function do nothing, i.e.:</p>
- <code type="erl">
-out_reply(_, _, _, _, Reply, Extra) ->
- {Reply, Extra}.
- </code>
- <p>If the client side ORB expects a checksum to be added to the reply we
- add it by using:</p>
- <code type="erl">
-out_reply_encoded({ObjTable, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) ->
- NewBin = ChecksumModule:add_checksum(Bin),
- {NewBin, Extra}.
- </code>
- <warning>
- <p>If we manipulate the binary as above the behavior <em>must</em>
- be <c>Bin == remove_checksum(add_checksum(Bin))</c>.</p>
- </warning>
- <p>For outgoing requests the principle is the same. Hence, it is not further
- described here. The complete interceptor module would look like:</p>
- <code type="erl">
--module(myInterceptor).
-
-%% Interceptor functions.
--export([new_out_connection/3,
- new_in_connection/3,
- closed_in_connection/1,
- closed_out_connection/1,
- in_request_encoded/6,
- in_reply_encoded/6,
- out_reply_encoded/6,
- out_request_encoded/6,
- in_request/6,
- in_reply/6,
- out_reply/6,
- out_request/6]).
-
-new_in_connection(Arg, Host, Port) ->
- %% Since we only use one interceptor we do not care about the
- %% input Arg since it is set do undefined by Orber.
- case ets:lookup(in_access_table, Host) of
- [] ->
- %% We may want to log the Host/Port to see if someone tried
- %% to hack in to our system.
- exit("Access not granted");
- [{Host, ObjTable, ChecksumModule}] ->
- {ObjTable, ChecksumModule}
- end.
-
-new_out_connection(Arg, Host, Port) ->
- case ets:lookup(out_access_table, Host) of
- [] ->
- exit("Access not granted");
- [{Host, ObjTable, ChecksumModule}] ->
- {ObjTable, ChecksumModule}
- end.
-
-in_request_encoded({_, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) ->
- NewBin = ChecksumModule:remove_checksum(Bin),
- {NewBin, Extra}.
-
-in_request({ObjTable, _}, ObjKey, Ctx, Op, Params, Extra) ->
- case ets:lookup(ObjTable, {ObjKey, Op}) of
- [] ->
- exit("Client tried to invoke illegal operation");
- [SomeData] ->
- {Params, Extra}
- end.
-
-out_reply(_, _, _, _, Reply, Extra) ->
- {Reply, Extra}.
-
-out_reply_encoded({_, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) ->
- NewBin = ChecksumModule:add_checksum(Bin),
- {NewBin, Extra}.
-
-out_request({ObjTable, _}, ObjKey, Ctx, Op, Params, Extra) ->
- case ets:lookup(ObjTable, {ObjKey, Op}) of
- [] ->
- exit("Client tried to invoke illegal operation");
- [SomeData] ->
- {Params, Extra}
- end.
-
-out_request_encoded({_, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) ->
- NewBin = ChecksumModule:add_checksum(Bin),
- {NewBin, Extra}.
-
-in_reply_encoded({_, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) ->
- NewBin = ChecksumModule:remove_checksum(Bin),
- {NewBin, Extra}.
-
-in_reply(_, _, _, _, Reply, Extra) ->
- {Reply, Extra}.
-
-closed_in_connection(Arg) ->
- %% Nothing to clean up.
- Arg.
-
-closed_out_connection(Arg) ->
- %% Nothing to clean up.
- Arg.
- </code>
- <note>
- <p>One can also use interceptors for debugging purposes, e.g.,
- print which objects and operations are invoked with which arguments
- and the outcome of the operation. In conjunction with the configuration
- parameter <c>orber_debug_level</c> it is rather easy to find out what
- went wrong or just to log the traffic. </p>
- </note>
- </section>
-</chapter>
-
diff --git a/lib/orber/doc/src/ch_introduction.xml b/lib/orber/doc/src/ch_introduction.xml
deleted file mode 100644
index f04fedd0a7..0000000000
--- a/lib/orber/doc/src/ch_introduction.xml
+++ /dev/null
@@ -1,145 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1999</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Introduction to Orber</title>
- <prepared>Megan Lynch</prepared>
- <docno></docno>
- <date>1998-09-21</date>
- <rev></rev>
- <file>ch_introduction.xml</file>
- </header>
-
- <section>
- <title>Overview</title>
- <p>The Orber application is a CORBA compliant Object Request Brokers
- (ORB), which provides CORBA functionality in an Erlang
- environment. Essentially, the ORB channels communication or
- transactions between nodes in a
- heterogeneous environment.
- </p>
- <p><term id="CORBA"><termdef>Common Object Request Broker Architecture is a common communication standard developed by the OMG (Object Management Group)</termdef></term>(Common Object Request Broker
- Architecture) provides an interface definition language allowing
- efficient system integration and also supplies standard
- specifications for some services.
- </p>
- <p>The Orber application contains the following parts:</p>
- <list type="bulleted">
- <item>
- <p>ORB kernel and IIOP support</p>
- </item>
- <item>
- <p>Interface Repository</p>
- </item>
- <item>
- <p>Interface Definition Language Mapping for Erlang</p>
- </item>
- <item>
- <p>CosNaming Service</p>
- </item>
- </list>
-
- <section>
- <title>Benefits</title>
- <p>Orber provides CORBA functionality in an Erlang environment that enables:
- </p>
- <list type="bulleted">
- <item>
- <p><em>Platform interoperability and transparency</em></p>
- <p>Orber enables communication between
- OTP applications or Erlang environment applications and
- other platforms; for example, Windows NT, Solaris
- etc, allowing platform transparency. This is especially helpful in situations where there
- are many users with different platforms. For example,
- booking airline tickets would require the airline database
- and hundreds of travel agents (who may not have the same
- platform) to book seats on flights. </p>
- </item>
- <item>
- <p><em>Application level interoperability and transparency</em></p>
- <p>As Orber is a CORBA compliant application, its purpose is
- to provide interoperability and transparency on the application
- level.
- Orber simplifies the distributed system software by defining the
- environment as objects, which in effect, views
- everything as identical regardless of programming
- languages. <br></br>
- Previously, time-consuming programming was
- required to facilitate communication between different languages.
- However, with CORBA compliant Orber the Application
- Programmer is relieved of this task. This makes
- communication on an application level relatively transparent to the user.</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Purpose and Dependencies</title>
- <p>The system architecture and OTP dependencies of Orber are illustrated in figure 1 below:</p>
- <marker id="dependent"></marker>
- <image file="dependent.gif">
- <icaption>
-Figure 1: Orber Dependencies and Structure.</icaption>
- </image>
- <p>Orber is dependent on Mnesia (see the Mnesia
- documentation) - an Erlang database management application
- used to store object information.</p>
- <note>
- <p>Although Orber does not have a run-time
- application dependency to IC (an <term id="IDL"><termdef>Interface Definition Language - IDL is the OMG specified interface definition language, used to define the CORBA object interfaces.</termdef></term>compiler for
- Erlang), it is necessary when building
- services and applications. See the IC documentation for
- further details.</p>
- </note>
- <marker id="orbs"></marker>
- <image file="orbs.gif">
- <icaption>
-Figure 2: ORB interface between Java and Erlang Environment Nodes.</icaption>
- </image>
- <p>This simplified illustration in figure 2 demonstrates how Orber can facilitate communication in a heterogeneous environment. The Erlang Nodes running
- OTP and the other Node running applications written in Java can
- communicate via an <term id="ORB"><termdef>Object Request Broker - ORB open software bus architecture specified by the OMG which allows object components to communicate in a heterogeneous environment.</termdef></term>(Object Request Broker). Using
- Orber means that CORBA functions can be used to achieve this
- communication.
- </p>
- <p>For example, if one of the above nodes requests an object, it does not
- need to know if that object is located on the same, or
- different, Erlang or Java nodes. The ORB will channel the
- information creating platform and application transparency for
- the user.
- </p>
- </section>
-
- <section>
- <title>Prerequisites</title>
- <p>To fully understand the concepts presented in the
- documentation, it is recommended that the user is familiar
- with distributed programming and CORBA (Common Object Request
- Broker Architecture).
- </p>
- <p>Recommended reading includes <em>Open Telecom Platform Documentation Set</em> and <em>Concurrent Programming in Erlang</em>.
- </p>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/orber/doc/src/ch_naming_service.xml b/lib/orber/doc/src/ch_naming_service.xml
deleted file mode 100644
index 991402ae86..0000000000
--- a/lib/orber/doc/src/ch_naming_service.xml
+++ /dev/null
@@ -1,465 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1997</year><year>2017</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>CosNaming Service</title>
- <prepared></prepared>
- <docno></docno>
- <date>1998-10-10</date>
- <rev></rev>
- <file>ch_naming_service.xml</file>
- </header>
-
- <section>
- <title>Overview of the CosNaming Service</title>
- <p>The CosNaming Service is a service developed to help users and
- programmers identify objects by human readable names rather than by a
- reference. By binding a name to a naming context (another object), a
- contextual reference is formed. This is helpful when navigating in the
- object space. In addition, identifying objects by name allows you to evolve
- and/or relocate objects without client code modification.</p>
- <p>The CosNaming service has some concepts that are important:</p>
- <list type="bulleted">
- <item>
- <p><em>name binding</em> - a name to object association.</p>
- </item>
- <item>
- <p><em>naming context</em> - is an object that contains a set of
- name bindings in which each name is unique. Different names can be
- bound to the same object.
- </p>
- </item>
- <item>
- <p><em>to bind a name</em> - is to create a name binding in a given
- context.</p>
- </item>
- <item>
- <p><em>to resolve a name</em> - is to determine the object associated
- with the name in a given context.</p>
- </item>
- </list>
- <p>A name is always resolved in a context, there no absolute names exist.
- Because a context is like any other object, it can also be bound to
- a name
- in a naming context.
- This will result in a naming graph (a directed graph with notes and
- labeled edges). The graph allows more complex names to refer to an
- object. Given a context, you can use a sequence to reference an object.
- This sequence is henceforth referred to as <em>name</em> and the
- individual
- elements in the sequence as <em>name components</em>. All but the
- last name component are bound to naming contexts.
- </p>
- <p>The diagram in figure 1 illustrates how the Naming Service provides a
- contextual relationship between objects, NamingContexts and
- NameBindings to create an object locality, as the
- object itself, has no name.
- </p>
- <marker id="name"></marker>
- <image file="name.gif">
- <icaption>
-Figure 1: Contextual object relationships using the Naming Service.</icaption>
- </image>
- <p>The naming contexts provide a directory of contextual
- reference and naming for objects (an object can appear to
- have more than one name).
- </p>
- <p>In figure 1 the object to the right can either be
- called <c>alpha</c> from one context or <c>gamma</c> from another.
- </p>
- <p>The Naming Service has an initial naming context, which is shown
- in the diagram as the top-most object in the naming graph.
- It has two names <c>beta</c> and <c>epsilon</c>, which are bound to other
- naming contexts. The initial naming context is a well known location
- used to share a common name space between multiple programs.
- You can traverse the naming graph until you reach a name, which is
- bound to an object, which is not a naming context.
- </p>
- <p>We recommend reading <em>chapter 12, CORBA Fundamentals and Programming</em>, for detailed information regarding the
- Naming Service. </p>
- </section>
-
- <section>
- <title>The Basic Use-cases of the Naming Service</title>
- <p>The basic use-cases of the Naming Service are:
- </p>
- <list type="bulleted">
- <item>Fetch initial reference to the naming service.</item>
- <item>Creating a naming context.</item>
- <item>Binding and unbinding names to objects.</item>
- <item>Resolving a name to an object.</item>
- <item>Listing the bindings of a naming context.</item>
- <item>Destroying a naming context.</item>
- </list>
-
- <section>
- <title>Fetch Initial Reference to the Naming Service</title>
- <p>In order to use the naming service you have to fetch an
- initial reference to it. This is done with:</p>
- <code type="erl">
-NS = corba:resolve_initial_references("NameService").
- </code>
- <note>
- <p>NS in the other use-cases refers to this initial reference.</p>
- </note>
- </section>
-
- <section>
- <title>Creating a Naming Context</title>
- <p>There are two functions for creating a naming context.
- The first function, which only creates a naming context object is:</p>
- <code type="erl">
-NC = 'CosNaming_NamingContext':new_context(NS).
- </code>
- <p>The other function creates a naming context and binds it to a name in
- an already existing naming context (the initial context in this
- example):
- </p>
- <code type="erl">
-NC = 'CosNaming_NamingContext':bind_new_context(NS, lname:new(["new"])).
- </code>
- </section>
-
- <section>
- <title>Binding and Unbinding Names to Objects</title>
- <p>The following steps illustrate how to bind/unbind an object reference
- to/from a name. For the example below, assume that the NamingContexts
- in the path are already bound to the name <c>/workgroup/services</c>,
- and that reference to the services context are in the variable
- <c>Sc</c>.</p>
- <list type="ordered">
- <item>
- <p>Use the naming library functions to create a name</p>
- <code type="erl">
-Name = lname:new(["object"]).
- </code>
- </item>
- <item>
- <p>Use CosNaming::NamingContext::bind() to bind a name to an object</p>
- <code type="erl">
-'CosNaming_NamingContext':bind(Sc, Name, Object).
- </code>
- </item>
- <item>
- <p>Use CosNaming::NamingContext::unbind() to remove the NameBinding from an object</p>
- <code type="erl">
-'CosNaming_NamingContext':unbind(Sc, Name).
- </code>
- </item>
- </list>
- <note>
- <p>Objects can have more than one name, to indicate different paths to
- the same object.</p>
- </note>
- </section>
-
- <section>
- <title>Resolving a Name to an Object</title>
- <p>The following steps show how to retrieve the object reference to the service context
- above (/workgroup/services). </p>
- <list type="ordered">
- <item>
- <p>Use the naming library functions to create a name path:</p>
- <code type="erl">
-Name = lname:new(["workgroup", "services"]).
- </code>
- </item>
- <item>
- <p>Use CosNaming::NamingContext::resolve() to to resolve the name to an object</p>
- <code type="erl">
-Sc = 'CosNaming_NamingContext':resolve(NS, Name).
- </code>
- </item>
- </list>
- <p>An alternative is to use:</p>
- <code type="erl">
-Sc = corba:string_to_object("corbaname:rir:/NameService#workgroup/services/").
- </code>
- <p>The <c>corbaname</c> schema is described further in the Interoperable
- Naming Service section.</p>
- </section>
-
- <section>
- <title>Listing the Bindings in a NamingContext</title>
- <list type="ordered">
- <item>
- <p>Use CosNaming::NamingContext::list() to list all the bindings in a context</p>
- <p>The following code retrieves and lists up to 10 bindings from a context.</p>
- <code type="erl">
-{BList, BIterator} = 'CosNaming_NamingContext':list(Sc, 10).
-
-lists:foreach(fun({{Id, Kind},BindingType}) -> case BindingType of
- nobject ->
- io:format("id: %s, kind: %s, type: object~n", [Id, Kind]);
- _ ->
- io:format("id: %s, kind: %s, type: ncontext~n", [Id, Kind])
- end end,
- Blist).
- </code>
- </item>
- </list>
- <note>
- <p>Normally a <term id="BindingIterator"><termdef>The binding iterator (Like a book mark) indicates which objects have been read from the list.</termdef></term>is helpful in situations where you have a large number of objects
- in a list, as the programmer then can traverse it more easily.
- In Erlang it is not needed, because lists are easily handled in the
- language itself.</p>
- </note>
- <warning>
- <p>Remember that the BindingIterator (BIterator in the example) is an object and therefore
- <em>must be removed</em> otherwise dangling processes will occur.
- Use <c>CosNaming::BindingIterator::destroy()</c> to remove it.</p>
- </warning>
- <code type="erl">
-'CosNaming_NamingContext':destroy(BIterator).
- </code>
- </section>
-
- <section>
- <title>Destroying a Naming Context</title>
- <p>The naming contexts are persistent and must be explicitly removed.
- (they are also removed if all Orber nodes in the domain are stopped).</p>
- <list type="ordered">
- <item>
- <p>Use CosNaming::NamingContext::destroy() to remove a NamingContext</p>
- <code type="erl">
-'CosNaming_NamingContext':destroy(Sc).
- </code>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Interoperable Naming Service</title>
- <marker id="interop_ns"></marker>
- <p>The OMG specifies URL schemes, which represent a CORBA object and a CORBA object
- bound in a NamingContext, for resolving references from other ORB:s. As of today,
- three schemes are defined:</p>
- <list type="bulleted">
- <item>IOR</item>
- <item>corbaloc</item>
- <item>corbaname</item>
- </list>
-
- <section>
- <title>IOR</title>
- <p>A stringified IOR is a valid URL format but difficult for humans to handle
- through non-electronic means. This URL format does not depend on a specific
- Name Service and, thus, is robust and insulates the client from the encapsulated
- transport information and object key used to reference the object.</p>
- </section>
-
- <section>
- <title>corbaloc</title>
- <p>The notation of this scheme is similar to the more well known URL <c>HTTP</c>, and
- the full <c>corbaloc</c> BNF is:</p>
- <code type="none"><![CDATA[
-<corbaloc> = "corbaloc:"<obj_addr_list>["/"<key_string>]
-<obj_addr_list> = [<obj_addr>","]*<obj_addr>
-<obj_addr> = <prot_addr> | <future_prot_addr>
-<prot_addr> = <rir_prot_addr> | <iiop_prot_addr>
-<rir_prot_addr> = <rir_prot_token>":"
-<rir_prot_token> = rir
-<future_prot_addr> = <future_prot_id><future_prot_addr>
-<future_prot_id> = <future_prot_token>":"
-<iiop_prot_addr> = <iiop_id><iiop_addr>
-<iiop_id> = <iiop_default> | <iiop_prot_token>":"
-<iiop_default> = ":"
-<iiop_prot_token> = "iiop"
-<iiop_addr> = <version><host>[":"<port>]
-<host> = <DNS-style Host Name> | <ip_v4_address> | "["<ip_v6_address>"]"
-<version> = <major>"."<minor>"@" | empty_string
-<port> = number
-<major> = number
-<minor> = number
-<DNS-style Host Name> = string
-<ip_v4_address> = string
-<ip_v6_address> = string
-<key_string> = for example NameService
- ]]></code>
- <p>The <c>corbaloc</c> scheme consists of 3 parts:</p>
- <list type="bulleted">
- <item>Protocol - as of today <c>iiop</c> or <c>rir</c> is supported.
- Using <c>rir</c> means that we will resolve the given Key locally, i.e.,
- the same as using <c>corba:resolve_initial_references("NameService").</c></item>
- <item>IIOP address - this address can be divided into <c>Version</c>, <c>Host</c>
- and <c>Port</c>. If the version or port are left out they will be set to the default
- values <c>1.0</c> and <c>2809</c> respectively.</item>
- <item>KeyString - an object key, e.g., "NameService". If no Key is
- supplied the default value "NameService" will be used.</item>
- </list>
- <p>A <c>corbaloc</c> can be passed used together with
- <c>corba:string_to_object("corbaloc::[email protected]:4001/NameService")</c> or set as the
- configuration variables <c>orbInitilRef</c> or <c>orbDefaultInitilRef</c> and calling
- <c>corba:resolve_initial_references("NameService")</c>. For more information see the Orber
- installation chapter. <c>corbaloc</c> can also be used together with <c>corbaname</c>
- to gain an easy access to a Name Service.</p>
- <p>Currently, the OMG defines a set of reserved keys and the type of object,
- listed below, they should be associated with. The <c>NameService</c>
- key may <em>not</em> be changed in Orber. If you want to add one of the
- reserved keys as an initial service, simply use:</p>
- <code type="erl">
-1> Factory = cosNotificationApp:start_global_factory().
-2> corba:add_initial_service("NotificationService", Factory).
- </code>
- <p>This object can then be easily resolved by any other ORB, supporting
- the Interoperable Naming Service, by using:</p>
- <code type="erl">
-3> NF = corba:string_to_object("corbaloc::[email protected]:4001/NotificationService").
- </code>
- <table>
- <row>
- <cell align="center" valign="middle"><em>String Name</em></cell>
- <cell align="center" valign="middle"><em>Object Type</em></cell>
- </row>
- <row>
- <cell align="left" valign="middle">RootPOA</cell>
- <cell align="left" valign="middle">PortableServer::POA</cell>
- </row>
- <row>
- <cell align="left" valign="middle">POACurrent</cell>
- <cell align="left" valign="middle">PortableServer::Current</cell>
- </row>
- <row>
- <cell align="left" valign="middle">InterfaceRepository</cell>
- <cell align="left" valign="middle">CORBA::Repository</cell>
- </row>
- <row>
- <cell align="left" valign="middle">NameService</cell>
- <cell align="left" valign="middle">CosNaming::NamingContext</cell>
- </row>
- <row>
- <cell align="left" valign="middle">TradingService</cell>
- <cell align="left" valign="middle">CosTrading::Lookup</cell>
- </row>
- <row>
- <cell align="left" valign="middle">SecurityCurrent</cell>
- <cell align="left" valign="middle">SecurityLevel1::Current/SecurityLevel2::Current</cell>
- </row>
- <row>
- <cell align="left" valign="middle">TransactionCurrent</cell>
- <cell align="left" valign="middle">CosTransaction::Current</cell>
- </row>
- <row>
- <cell align="left" valign="middle">DynAnyFactory</cell>
- <cell align="left" valign="middle">DynamicAny::DynAnyFactory</cell>
- </row>
- <row>
- <cell align="left" valign="middle">ORBPolicyManager</cell>
- <cell align="left" valign="middle">CORBA::PolicyManager</cell>
- </row>
- <row>
- <cell align="left" valign="middle">PolicyCurrent</cell>
- <cell align="left" valign="middle">CORBA::PolicyCurrent</cell>
- </row>
- <row>
- <cell align="left" valign="middle">NotificationService</cell>
- <cell align="left" valign="middle">CosNotifyChannelAdmin::EventChannelFactory</cell>
- </row>
- <row>
- <cell align="left" valign="middle">TypedNotificationService</cell>
- <cell align="left" valign="middle">CosTypedNotifyChannelAdmin::TypedEventChannelFactory</cell>
- </row>
- <row>
- <cell align="left" valign="middle">CodecFactory</cell>
- <cell align="left" valign="middle">IOP::CodecFactory</cell>
- </row>
- <row>
- <cell align="left" valign="middle">PICurrent</cell>
- <cell align="left" valign="middle">PortableInterceptors::Current</cell>
- </row>
- <tcaption>Currently reserved key strings</tcaption>
- </table>
- </section>
-
- <section>
- <title>corbaname</title>
- <p>The <c>corbaname</c> URL scheme is an extension of the <c>corbaloc</c> scheme, and
- the full <c>corbaname</c> BNF is:</p>
- <code type="none"><![CDATA[
-<corbaname> = "corbaname:"<obj_addr_list>["/"<key_string>]["#"<string_name>]
-<obj_addr_list> = as described above.
-<key_string> = as described above.
- ]]></code>
- <p>The <c>string_name</c>, concatenated to the <c>corbaloc</c> string, identifies
- a binding in a naming context. A name component consists of two parts, i.e.,
- <c>id</c> and <c>kind</c>, which is represented as follows:</p>
- <table>
- <row>
- <cell align="center" valign="middle"><em>String Name</em></cell>
- <cell align="center" valign="middle"><em>Name Sequence</em></cell>
- <cell align="center" valign="middle"><em>Comment</em></cell>
- </row>
- <row>
- <cell align="left" valign="middle">"id1/./id3.kind3"</cell>
- <cell align="left" valign="middle">[{"id1",""},{"",""},{"id3","kind3"}]</cell>
- <cell align="left" valign="middle">The first component has no kind defined while the second component's both fields are empty.</cell>
- </row>
- <row>
- <cell align="left" valign="middle">"id1//id3.kind3"</cell>
- <cell align="left" valign="middle">ERROR</cell>
- <cell align="left" valign="middle">Not allowed, must insert a '.' between the '//'.</cell>
- </row>
- <row>
- <cell align="left" valign="middle">"id1.kind1/."</cell>
- <cell align="left" valign="middle">[{"id1","kind1"},{"",""}]</cell>
- <cell align="left" valign="middle">The first component's fields are both set while the second component's both fields are empty.</cell>
- </row>
- <row>
- <cell align="left" valign="middle">"id1.kind1/id2."</cell>
- <cell align="left" valign="middle">ERROR</cell>
- <cell align="left" valign="middle">An Id with a trailing '.' is not allowed.</cell>
- </row>
- <row>
- <cell align="left" valign="middle">"i\\/d1/i\\.d2"</cell>
- <cell align="left" valign="middle">[{"i/d1",""},{"i.d2",""}]</cell>
- <cell align="left" valign="middle">Since '.' and '/' are used to separate the components, these tokens must be escaped to be correctly converted.</cell>
- </row>
- <tcaption>Stringified Name representation</tcaption>
- </table>
- <p>After creating a stringified Name we can either use:</p>
- <code type="erl">
-NameStr = "org.erlang",
-NS = corba:resolve_initial_references("NameService"),
-Obj = 'CosNaming_NamingContextExt':resolve_str(NS, NameStr),
- </code>
- <p>or concatenate the Name String using:</p>
- <code type="erl">
-NameStr = "Swedish/Soccer/Champions",
-Address = "corbaname:iiop:[email protected]:2000/NameService",
-NS = corba:resolve_initial_references("NameService"),
-URLStr = 'CosNaming_NamingContextExt':to_url(NS, Address, NameStr),
-Obj = corba:string_to_object(URLStr),
- </code>
- <p>Using the first alternative, the configuration variables <c>orbInitilRef</c> and
- <c>orbDefaultInitilRef</c>, will determine which other ORB's or the local
- Name Service Orber will try to resolve the given string from. The second
- alternative allows us to override any settings of the configuration variables.</p>
- <p>The function <c>to_url/3</c> will perform any necessary escapes compliant with
- IETF/RFC 2396. US-ASCII alphanumeric characters and
- <c><![CDATA["," | "/" | ":" | "?" | "@" | "&" | "=" | "+" | "$" | ";" | "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"]]></c>
- are not escaped.</p>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/orber/doc/src/ch_orber_kernel.xml b/lib/orber/doc/src/ch_orber_kernel.xml
deleted file mode 100644
index 396e1360fd..0000000000
--- a/lib/orber/doc/src/ch_orber_kernel.xml
+++ /dev/null
@@ -1,103 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1999</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>The Orber Application</title>
- <prepared></prepared>
- <docno></docno>
- <date>1998-10-05</date>
- <rev></rev>
- <file>ch_orber_kernel.xml</file>
- </header>
-
- <section>
- <title>ORB Kernel and IIOP </title>
- <p>This chapter gives a brief overview of the ORB and its relation
- to objects in a distributed environment and the usage of Domains
- in Orber.
- Also Internet-Inter ORB Protocol (<term id="IIOP"><termdef>Internet-Inter ORB Protocol</termdef></term>) is discussed and how this
- protocol facilitates communication between ORBs to
- allow the accessory of persistent server objects in Erlang. </p>
- </section>
-
- <section>
- <title>The Object Request Broker (ORB)</title>
- <p>An ORB kernel can be best described as the middle-ware, which
- creates relationships between clients and servers, but is
- defined by its interfaces. This allows transparency for the
- user, as they do not have to be aware of where the requested
- object is located. Thus, the programmer can work with any other
- platform provided that an IDL mapping and interfaces exist.
- </p>
- <p>The IDL mapping which is described in a later chapter is the
- translator between other platforms, and languages. However, it
- is the ORB, which provides objects with a structure by which
- they can communicate with other objects.
- </p>
- <p>ORBs intercept and direct messages from one object, pass this
- message using IIOP to another ORB, which then directs the
- message to the indicated object.
- </p>
- <p>An ORB is the base on which interfaces, communication stubs
- and mapping can be built to enable communication between
- objects. Orber uses <term id="domains"><termdef>A domain allows a more efficient communication protocol to be used between objects not on the same node without the need of an ORB</termdef></term>to group objects of different nodes
- </p>
- <p>How the ORB provides communication is shown very simply in figure 1 below: </p>
- <marker id="theORB"></marker>
- <image file="theORB.gif">
- <icaption>
-Figure 1: How the Object Request Broker works.</icaption>
- </image>
- <p>The domain in Orber gives an extra aspect to the distributed object
- environment as each domain has one ORB, but it is distributed over
- a number of object in different nodes. The domain binds objects on
- nodes more closely than distributed objects in different domains. The
- advantage of a domain is that a faster communication exists between
- nodes and objects of the same domain. An internal communication protocol
- (other than IIOP) allows a
- more efficient communication between these objects. </p>
- <note>
- <p>Unlike objects, domains can only have one name
- so that no communication ambiguities exist between domains.</p>
- </note>
- </section>
-
- <section>
- <title>Internet Inter-Object Protocol (IIOP)</title>
- <p>IIOP is a communication protocol developed by the OMG to
- facilitate communication in a distributed object-oriented
- environment.
- </p>
- <p>Figure 2 below demonstrates how IIOP works between objects:</p>
- <marker id="iiop"></marker>
- <image file="iiop.gif">
- <icaption>
-Figure 2: IIOP communication between domains and objects.</icaption>
- </image>
- <note>
- <p>Within the Orber domains the objects communicate without
- using the IIOP. However, the user is unaware of the difference in protocols, as this difference is not visible. </p>
- </note>
- </section>
-</chapter>
-
diff --git a/lib/orber/doc/src/ch_orberweb.xml b/lib/orber/doc/src/ch_orberweb.xml
deleted file mode 100644
index c9dcc382e6..0000000000
--- a/lib/orber/doc/src/ch_orberweb.xml
+++ /dev/null
@@ -1,221 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2001</year><year>2017</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>OrberWeb</title>
- <prepared>Nick</prepared>
- <docno></docno>
- <date>2001-11-22</date>
- <rev></rev>
- <file>ch_orberweb.xml</file>
- </header>
-
- <section>
- <title>Using OrberWeb</title>
- <p><c>OrberWeb</c> is intended to make things easier when developing and
- testing applications using <c>Orber</c>. The user is able to interact
- with <c>Orber</c> via a GUI by using a web browser.</p>
- <p><c>OrberWeb</c> requires that the application <c>WebTool</c> is available and
- started on at least one node; if so <c>OrberWeb</c> can usually be used to
- to access <c>Orber</c> nodes supporting the Interoperable Naming
- Service. How to start OrberWeb is described in
- <seealso marker="ch_orberweb#startorberweb">Starting OrberWeb</seealso></p>
- <p>The <c>OrberWeb</c> GUI consists of a <em>Menu Frame</em> and a
- <em>Data Frames</em>.</p>
-
- <section>
- <title>The Menu Frame</title>
- <p>The menu frame consists of:</p>
- <list type="bulleted">
- <item><em>Node List</em> - which node to access.</item>
- <item><em>Configuration</em> - see how Orber on the current node is configured.</item>
- <item><em>Name Service</em> - browse the NameService and add/remove a Context/Object.</item>
- <item><em>IFR Types</em> - see which types are registered in IFR.</item>
- <item><em>Create Object</em> - create a new object and, possibly, store it in the NameService.</item>
- </list>
- <p></p>
- <marker id="menuframe"></marker>
- <image file="menuframe.gif">
- <icaption>The Menu Frame.</icaption>
- </image>
- <p>Which nodes we can access is determined by what is returned when invoking <c>[node()|nodes()]</c>.
- If you cannot see a desired node in the list, you have to call <c>net_adm:ping(Node)</c>.
- But this requires that the node is started with the distribution switched on
- (e.g. <c>erl -sname myNode</c>); this also goes for the node <c>OrberWeb</c> is running on.</p>
- </section>
-
- <section>
- <title>The Configuration Data Frame</title>
- <p>When accessing the <em>Configuration</em> page OrberWeb presents a table containing the
- <seealso marker="ch_install#config">configuration settings</seealso> for the target node.</p>
- <p></p>
- <marker id="dataframe3"></marker>
- <image file="dataframe3.gif">
- <icaption>Configuration Settings.</icaption>
- </image>
- <p>It is also possible to change those configuration parameters which can be changed when Orber
- is already started. The Key-Value pairs is given as a list of tuples, e.g.,
- <em>[{orber_debug_level, 5}, {iiop_timeout, 60}, {giop_version, {1,2}}]</em>. If one tries to update a parameter
- which may not be changed an error message will be displayed.</p>
- </section>
-
- <section>
- <title>The IFR Data Frame</title>
- <p>All types registered in the IFR (Interface Repository) which have an associated IFR-id
- can be viewed via the IFR Data Frame. This gives the user an easy way to confirm that
- all necessary IDL-specifications have been properly registered. All available types are
- listed when choosing <c>IFR Types</c> in the menu frame:</p>
- <p></p>
- <marker id="dataframe1"></marker>
- <image file="dataframe1.gif">
- <icaption>Select Type.</icaption>
- </image>
- <p>After selecting a type all definitions of that particular type will be displayed. If no such
- bindings exists the table will be empty.</p>
- <p>Since Orber adds definitions to the IFR when it is installed (e.g. CosNaming), not only
- types defined by the user will show up in the table. In the figure below you find the
- the NameService exceptions listed.</p>
- <p></p>
- <marker id="dataframe2"></marker>
- <image file="dataframe2.gif">
- <icaption>List Registered Exceptions.</icaption>
- </image>
- </section>
-
- <section>
- <title>The NameService Data Frame</title>
- <p>The NameService main purpose is to make possible to bind object references, which
- can client applications can resolve and invoke operations on. Initially, the NameService
- is empty. The most common scenario, is that user applications create Contexts and add objects
- in the NameService. OrberWeb allows the user to do the very same thing.</p>
- <p>When referencing an object or context you must use stringified NameComponents.
- For more information see the <seealso marker="ch_naming_service">Interoperable Naming Service</seealso>.
- In the following example we will use the string <em>org/erlang/TheObjectName</em>, where
- <em>org</em> and <em>erlang</em> will be contexts and <em>TheObjectName</em>
- the name the object will be bound to.</p>
- <p>Since the NameService is empty in the beginning, the only thing we can do is creating
- a new context. Simply write <em>org</em> in the input field and press <c>New Context</c>.
- If OrberWeb was able to create the context or not, is shown in the completion message.
- If successful, just press the <c>Go Back</c> button. Now, a link named <em>org</em> should
- be listed in the table. In the right column the context type is displayed. Contexts are
- associated with <em>ncontext</em> and objects with <em>nobject</em>.</p>
- <p></p>
- <marker id="dataframe5"></marker>
- <image file="dataframe5.gif">
- <icaption>Add a New Context.</icaption>
- </image>
- <p>To create the next level context (i.e. erlang), simply follow the link and repeat the procedure.
- If done correctly, a table containing the same data as the following figure should be the result
- if you follow the <em>erlang</em> link. Note, that the path is displayed in the yellow
- field.</p>
- <p></p>
- <p>If a context does not contain any sub-contexts or object bindings, it is possible to
- delete the context. If these requirements are met, a <c>Delete Context</c> button will appear.
- A completion status message will be displayed after deleting the context.</p>
- <p></p>
- <marker id="dataframe6"></marker>
- <image file="dataframe6.gif">
- <icaption>Delete Context.</icaption>
- </image>
- <p>Now it is possible to bind an object using the complete name string. To find out how this is
- done using OrberWeb see <seealso marker="ch_orberweb#create">Object Creation</seealso>.
- For now, we will just assume that an object have been created and bound as <em>TheObjectName</em>. </p>
- <p></p>
- <marker id="dataframe7"></marker>
- <image file="dataframe7.gif">
- <icaption>Object Stored in the NameService.</icaption>
- </image>
- <p>If you follow the <em>TheObjectName</em> link, data about the bound object will be
- presented. Note, depending on which type of object it is, the information given differs.
- It would, for example, not be possible to display a Pid for all types of objects since
- it might reside on a Java-ORB. In the figure below a CosNotification FilterFactory have
- been bound under the name <em>org/erlang/TheObjectName</em>.</p>
- <p></p>
- <marker id="dataframe8"></marker>
- <image file="dataframe8.gif">
- <icaption>Object Data.</icaption>
- </image>
- <p>OrberWeb also makes it possible to remove a binding and dispose the associated object.
- Pressing <em>Unbind</em> the binding will be removed but the object will still exist.
- But, if the <em>Unbind and Dispose</em> button is pressed, the binding will be removed
- and the object terminated.</p>
- </section>
-
- <section>
- <title>The Object Creation Data Frame</title>
- <marker id="create"></marker>
- <p>This part makes it possible to create a new object and, if wanted, store it the
- NameService.</p>
- <p></p>
- <marker id="dataframe4"></marker>
- <image file="dataframe4.gif">
- <icaption>Create a New Object.</icaption>
- </image>
- <list type="bulleted">
- <item><em>Module</em> - simply type the name of the module of the object type
- you want to create. If the module begins with a capital letter, we normally must
- write <c>'Module_Interface'</c>. But, when using OrberWeb, you shall <em>NOT</em>.
- Since we cannot create linked objects this is not an option.</item>
- <item><em>Arguments</em> - the supplied arguments must be written as a single Erlang term.
- That is, as a list or tuple containing other Erlang terms. The arguments will be
- passed to the <c>init</c> function of the object. It is, however, not possible
- to use Erlang records. If OrberWeb is not able to parse the arguments, an error message
- will be displayed. If left empty, an empty list will be passed.</item>
- <item><em>Options</em> - the options can be the ones listed under
- <seealso marker="Module_Interface">Module_Interface</seealso> in Orber's Reference manual.
- Hence, they are not further described here. But, as an example, in the figure above
- we started the object as globally registered. If no options supplied the object
- will be started as default.</item>
- <item><em>Name String</em> - if left empty the object will <em>not</em> be registered in the
- NameService. Hence, it is important that you can access the object in another way,
- otherwise a zombie process is created. In the previous section we used the name string
- <em>org/erlang/TheObjectName</em>. If we choose the same name here, the listed contexts
- (i.e. <em>org</em> and <em>erlang</em>) must be created <em>before</em> we can create
- and bind the object to <em>TheObjectName</em>. If this requirement is not met, OrberWeb
- cannot bind the object. Hence, the object will be terminated and an error message
- displayed.</item>
- <item><em>Operation to use</em> - which option choosed will determine the behavior of OrberWeb.
- If you choose <em>bind</em> and a binding already exists an error message will be
- displayed and the newly started object terminated. But if you choose <em>rebind</em>
- any existing binding will over-written.</item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Starting OrberWeb</title>
- <marker id="startorberweb"></marker>
- <p>You may choose to start OrberWeb on node, on which Orber is running or not. But
- the Erlang distribution must be started (e.g. by using -sname aNodeName). Now, all
- you have to do is to invoke:</p>
- <code type="none">
-erl> webtool:start().
-WebTool is available at http://localhost:8888/
-Or http://127.0.0.1:8888/
- </code>
- <p>Type one of the URL:s in your web-browser. If you want to access the WebTool application
- from different machine, just replace <c>localhost</c> with its name. For more information,
- see the WebTool documentation.</p>
- </section>
-</chapter>
-
diff --git a/lib/orber/doc/src/ch_security.xml b/lib/orber/doc/src/ch_security.xml
deleted file mode 100644
index 151e417079..0000000000
--- a/lib/orber/doc/src/ch_security.xml
+++ /dev/null
@@ -1,96 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1999</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>How to use security in Orber</title>
- <prepared></prepared>
- <docno></docno>
- <date>1999-09-01</date>
- <rev></rev>
- <file>ch_security.xml</file>
- </header>
-
- <section>
- <title>Security in Orber</title>
-
- <section>
- <title>Introduction</title>
- <p>Orber SSL provides authentication, privacy and integrity for your
- Erlang applications. Based on the Secure Sockets Layer protocol, the
- Orber SSL ensures that your Orber clients and servers can
- communicate securely over any network.
- This is done by tunneling IIOP through an SSL connection. To get
- the node secure you will also need to have a firewall which
- only lets through connections to certain ports.</p>
- </section>
-
- <section>
- <title>Enable Usage of Secure Connections</title>
- <p>To enable a secure Orber domain you have to set the configuration variable
- <em>secure</em> which currently only can have one of two values;
- <em>no</em> if no security for IIOP should be used and <em>ssl</em> if
- secure connections is needed (<em>ssl</em> is currently the only supported
- security mechanism).</p>
- <p>The default is no security.</p>
- </section>
-
- <section>
- <title>Configurations when Orber is Used on the Server Side</title>
- <p>There is a variable to conficure Orber's SSL behavior on the server side.</p>
- <list type="bulleted">
- <item><em>ssl_server_options</em> - which is a list of options to ssl.
- See the <seealso marker="ssl:ssl">SSL</seealso> application for further
- descriptions on these options.</item>
- </list>
- <p>There also exist an API function for accessing the value of this variable:</p>
- <list type="bulleted">
- <item>orber:ssl_server_options/0</item>
- </list>
- </section>
-
- <section>
- <title>Configurations when Orber is Used on the Client Side</title>
- <p>When the Orber enabled application is the client side in the secure connection the
- different configurations can be set per client process instead and not for the whole domain
- as for incoming calls.</p>
- <p>There is a variable to set default values for the domain but they can be changed
- per client process.</p>
- <list type="bulleted">
- <item><em>ssl_client_options</em> - which is a list of options to ssl.
- See the <seealso marker="ssl:ssl">SSL</seealso> application for further
- descriptions on these options.</item>
- </list>
- <p>There also exist two API functions for accessing and changing the values of this
- variable in the client processes.</p>
- <p>Access function:</p>
- <list type="bulleted">
- <item>orber:ssl_client_options/0</item>
- </list>
- <p>Modify function:</p>
- <list type="bulleted">
- <item>orber:set_ssl_client_options/1</item>
- </list>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/orber/doc/src/ch_stubs.xml b/lib/orber/doc/src/ch_stubs.xml
deleted file mode 100644
index 9290c127f9..0000000000
--- a/lib/orber/doc/src/ch_stubs.xml
+++ /dev/null
@@ -1,284 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1999</year><year>2017</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Orber Stubs/Skeletons</title>
- <prepared></prepared>
- <docno></docno>
- <date>1999-09-03</date>
- <rev>A</rev>
- <file>ch_stubs.xml</file>
- </header>
-
- <section>
- <title>Orber Stubs and Skeletons Description</title>
- <p>This example describes the API and behavior of Orber stubs and skeletons.
- </p>
-
- <section>
- <title>Server Start</title>
- <p>Orber servers can be started in several ways. The chosen start functions determines
- how the server can be accessed and its behavior.
- </p>
- <p>Using <c>Module_Interface:oe_create()</c> or <c>oe_create_link()</c>:
- </p>
- <list type="bulleted">
- <item>No initial data can be passed.</item>
- <item>Cannot be used as a supervisor child start function.</item>
- <item>Only accessible through the object reference returned by the start function.
- The object reference is no longer valid if the server dies and is restarted.</item>
- </list>
- <p>Using <c>Module_Interface:oe_create(Env)</c> or <c>oe_create_link(Env)</c>:</p>
- <list type="bulleted">
- <item>Initial data can be passed using <c>Env</c>.</item>
- <item>Cannot be used as a supervisor child start function.</item>
- <item>Only accessible through the object reference returned by the start function.
- The object reference is no longer valid if the server dies and is restarted.</item>
- </list>
- <p>Using <c>Module_Interface:oe_create(Env, Options)</c>:</p>
- <list type="bulleted">
- <item>Initial data can be passed using <c>Env</c>.</item>
- <item>Cannot be used as a supervisor child start function.</item>
- <item>Accessible through the object reference returned by the start function. If the option
- <c>{regname, RegName}</c> is used the object reference stays valid even if the
- server has been restarted.</item>
- <item>If the options <c>{persistent, true}</c> and <c>{regname, {global, Name}}</c> is used,
- the result from an object invocation will be the exception 'OBJECT_NOT_EXIST'
- only if the object has terminated with reason
- <c>normal</c> or <c>shutdown</c>. If the object is in the process of restarting, the result
- will be <c>{error, Reason}</c> or a system exception is raised.</item>
- <item>The option <c>{pseudo, true}</c> makes it possible to start create non-server objects.
- There are, however, some limitations, which are further described in the
- <c>Pseudo objects</c> section.</item>
- </list>
- <p>Using <c>Module_Interface:oe_create_link(Env, Options)</c>:</p>
- <list type="bulleted">
- <item>Initial data can be passed using <c>Env</c>.</item>
- <item>Can be used as a supervisor child start function if the option <c>{sup_child, true}</c> used.</item>
- <item>Accessible through the object reference returned by the start function. If the option
- <c>{regname, RegName}</c> is used the object reference stays valid even if the
- server has been restarted.</item>
- <item>If the options <c>{persistent, true}</c> and <c>{regname, {global, Name}}</c> is used,
- the result from an object invocation will be the exception 'OBJECT_NOT_EXIST'
- only if the object has terminated with reason
- <c>normal</c> or <c>shutdown</c>. If the object is in the process of restarting, the result
- will be <c>{error, Reason}</c> or a system exception is raised.</item>
- <item>For starting a server as a supervisor child you should use the options
- <c>[{persistent, true}, {regname, {global, Name}}, {sup_child, true}]</c> and of type <em>transient</em>.
- This configuration allows you to delegate restarts to the supervisor and still be able to
- use the same object reference and be able to see if the server is permanently terminated.
- Please note you must use <em>supervisor/stdlib-1.7</em> or later and that the it returns
- <c>{ok, Pid, Object}</c> instead of just <c>Object</c>.</item>
- <item>Using the option <c>{pseudo, true}</c> have the same effect as using
- <c>oe_create/2</c>.</item>
- </list>
- <warning>
- <p>To avoid flooding Orber with old object references start erlang using the flag
- <em>-orber objectkeys_gc_time Time</em>, which will remove all object references
- related to servers being dead for Time seconds. To avoid extra overhead, i.e., performing
- garbage collect if no persistent objects are started, the objectkeys_gc_time default value
- is <em>infinity</em>. For more information, see the orber and corba documentation.</p>
- </warning>
- <warning>
- <p>Orber still allow <c>oe_create(Env, {Type,RegName})</c> and <c>oe_create_link(Env, {Type,RegName})</c> to be used,
- but may not in future releases.</p>
- </warning>
- </section>
-
- <section>
- <title>Pseudo Objects</title>
- <p>This section describes Orber pseudo objects.
- </p>
- <p>The Orber stub can be used to start a <c>pseudo object</c>, which will create a non-server implementation.
- A pseudo object introduce some limitations:</p>
- <list type="bulleted">
- <item>The functions <c>oe_create_link/2</c> is equal to <c>oe_create/2</c>, i.e.,
- no link can or will be created.</item>
- <item>The <c>BIF:s self()</c> and <c>process_flag(trap_exit,true)</c> behaves incorrectly.</item>
- <item>The <c>IC</c> option <c>{{impl, "M::I"}, "other_impl"}</c> has no effect. The call-back
- functions must be implemented in a file called <c>M_I_impl.erl</c></item>
- <item>The call-back functions must be implemented as if the <c>IC</c> option
- <c>{this, "M::I"}</c> was used.</item>
- <item>The gen_server <c>State</c> changes have no effect. The user can provide information via
- the <c>Env</c> start parameter and the State returned from <c>init/2</c> will be the State
- passed in following invocations.</item>
- <item>The server reply <c>Timeout</c> has no effect.</item>
- <item>The compile option <c>from</c> has no effect.</item>
- <item>The option <c>{pseudo, true}</c> overrides all other start options.</item>
- <item>Only the functions, besides own definitions, <c>init/2</c> (called via oe_create*/2) and
- <c>terminate/2</c> (called via corba:dispose/1) must be implemented.</item>
- </list>
- <p>By adopting the rules for <c>pseudo</c> objects described above we can use <c>oe_create/2</c>
- to create <c>server</c> or <c>pseudo</c> objects, by excluding or including the
- option <c>{pseudo, true}</c>, without changing the call-back module.</p>
- <p>To create a pseudo object do the following:</p>
- <code type="none">
-fingolfin 127> erl
-Erlang (BEAM) emulator version 4.9
-
-Eshell V4.9 (abort with ^G)
-1> ic:gen(myDefinition, [{this, "MyModule::MyInterface"}]).
-Erlang IDL compiler version 20
-ok
-2> make:all().
-Recompile: oe_MyDefinition
-Recompile: MyModule_MyInterface
-Recompile: MyModule_MyInterface_impl
-up_to_date
-3> PseudoObj = MyModule_MyInterface:oe_create(Env, [{pseudo, true}]).
- </code>
- <p>The call-back functions must be implemented as <c>MyFunction(OE_THIS, State, Args)</c>,
- and called by <c>MyModule_MyInterface:MyFunction(PseudoObj, Args)</c>.</p>
- </section>
-
- <section>
- <title>Call-back Module</title>
- <p>This section provides an example of how a call-back module may be implemented.</p>
- <note>
- <p>Arguments and Replies are determined by the IDL-code and, hence, not
- further described here.</p>
- </note>
- <code type="erl">
-%%%-----------------------------------------------------------
-%%% File : Module_Interface_impl.erl
-%%% Author :
-%%% Purpose :
-%%% Created :
-%%%-----------------------------------------------------------
-
--module('Module_Interface_impl').
-
-%%--------------- INCLUDES -----------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib(".. ..").
-
-%%--------------- EXPORTS-------------------------------------
-%% Arity depends on IC configuration parameters and the IDL
-%% specification.
--export([own_function/X]).
-
-
-%%--------------- gen_server specific ------------------------
--export([init/1, terminate/2, code_change/3, handle_info/2]).
-
-%%------------------------------------------------------------
-%% function : server specific
-%%------------------------------------------------------------
-init(InitialData) ->
- %% 'trap_exit' optional (have no effect if pseudo object).
- process_flag(trap_exit,true),
-
- %%--- Possible replies ---
- %% Reply and await next request
- {ok, State}.
-
- %% Reply and if no more requests within Time the special
- %% timeout message should be handled in the
- %% Module_Interface_impl:handle_info/2 call-back function (use the
- %% IC option {{handle_info, "Module::Interface"}, true}).
- {ok, State, Timeout}
-
- %% Return ignore in order to inform the parent, especially if it is a
- %% supervisor, that the server, as an example, did not start in
- %% accordance with the configuration data.
- ignore
- %% If the initializing procedure fails, the reason
- %% is supplied as StopReason.
- {stop, StopReason}
-
-terminate(Reason, State) ->
- ok.
-
-code_change(OldVsn, State, Extra) ->
- {ok, NewState}.
-
-%% If use IC option {{handle_info, "Module::Interface"}, true}.
-%% (have no effect if pseudo object).
-handle_info(Info, State) ->
- %%--- Possible replies ---
- %% Await the next invocation.
- {noreply, State}.
- %% Stop with Reason.
- {stop, Reason, State}.
-
-%%--- two-way ------------------------------------------------
-%% If use IC option {this, "Module:Interface"}
-%% (Required for pseudo objects)
-own_function(This, State, .. Arguments ..) ->
-%% IC options this and from
-own_function(This, From, State, .. Arguments ..) ->
-%% IC option from
-own_function(From, State, .. Arguments ..) ->
- %% Send explicit reply to client.
- corba:reply(From, Reply),
- %%--- Possible replies ---
- {noreply, State}
- {noreply, State, Timeout}
-
-
-%% If not use IC option {this, "Module:Interface"}
-own_function(State, .. Arguments ..) ->
- %%--- Possible replies ---
- %% Reply and await next request
- {reply, Reply, State}
-
- %% Reply and if no more requests within Time the special
- %% timeout message should be handled in the
- %% Module_Interface_impl:handle_info/2 call-back function (use the
- %% IC option {{handle_info, "Module::Interface"}, true}).
- {reply, Reply, State, Timeout}
-
- %% Stop the server and send Reply to invoking object.
- {stop, StopReason, Reply, State}
-
- %% Stop the server and send no reply to invoking object.
- {stop, StopReason, State}
-
- %% Raise exception. Any changes to the internal State is lost.
- corba:raise(Exception).
-
-%%--- one-way ------------------------------------------------
-%% If use IC option {this, "Module:Interface"}
-%% (Required for pseudo objects)
-own_function(This, State, .. Arguments ..) ->
-
-%% If not use IC option {this, "Module:Interface"}
-own_function(State, .. Arguments ..) ->
- %%--- Possible results ---
- {noreply, State}
-
- %% Release and if no more requests within Time the special
- %% timeout message should be handled in the
- %% Module_Interface_impl:handle_info/2 call-back function (use the
- %% IC option {{handle_info, "Module::Interface"}, true}).
- {noreply, State, Timeout}
-
- %% Stop the server with StopReason.
- {stop, StopReason, State}
-
-%%--------------- END OF MODULE ------------------------------
- </code>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/orber/doc/src/corba.xml b/lib/orber/doc/src/corba.xml
deleted file mode 100644
index fbfb55f2f2..0000000000
--- a/lib/orber/doc/src/corba.xml
+++ /dev/null
@@ -1,454 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1997</year><year>2017</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>corba</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>1997-06-10</date>
- <rev>A</rev>
- </header>
- <module>corba</module>
- <modulesummary>The functions on CORBA module level</modulesummary>
- <description>
- <p>This module contains functions that are specified on the CORBA module
- level. It also contains some functions for creating and disposing
- objects.</p>
- </description>
- <funcs>
- <func>
- <name>create(Module, TypeID) -> Object</name>
- <name>create(Module, TypeID, Env) -> Object</name>
- <name>create(Module, TypeID, Env, Optons1) -> Object</name>
- <name>create_link(Module, TypeID) -> Object</name>
- <name>create_link(Module, TypeID, Env) -> Object</name>
- <name>create_link(Module, TypeID, Env, Options2) -> Reply</name>
- <fsummary>Create and start a new server object</fsummary>
- <type>
- <v>Module = atom()</v>
- <v>TypeID = string()</v>
- <v>Env = term()</v>
- <v>Options1 = [{persistent, Bool} | {regname, RegName} | {local_typecheck, Bool}]</v>
- <v>Options2 = [{sup_child, Bool} | {persistent, Bool} | {regname, RegName} | {pseudo, Bool} | {local_typecheck, Bool}]</v>
- <v>RegName = {local, atom()} | {global, term()}</v>
- <v>Reply = #objref | {ok, Pid, #objref}</v>
- <v>Bool = true | false</v>
- <v>Object = #objref</v>
- </type>
- <desc>
- <p>These functions start a new server object. If you start it
- without <em>RegName</em> it can only be accessed through the
- returned object key. Started with a <em>RegName</em> the name is
- registered locally or globally. </p>
- <p><em>TypeID</em> is the repository ID of the server object type and
- could for example look like "IDL:StackModule/Stack:1.0". </p>
- <p><em>Module</em> is the name of the interface API module. </p>
- <p><em>Env</em> is the arguments passed which will be passed to the
- implementations <em>init</em> call-back function.</p>
- <p>A server started with create/2, create/3 or create/4 does not care
- about the parent, which means that the parent is not handled
- explicitly in the generic process part. </p>
- <p>A server started with create_link2, create_link/3 or create_link/4
- is initially linked to the caller, the parent, and it will
- terminate whenever the parent process terminates, and with the same
- reason as the parent. If the server traps exits, the terminate/2
- call-back function is called in order to clean up before the
- termination. These functions should be used if the server is a
- worker in a supervision tree.</p>
- <p>If you use the option <c>{sup_child, true}</c> create_link/4 will return
- <c>{ok, Pid, #objref}</c>, otherwise <c>#objref</c>, and make it possible
- to start a server as a supervisor child (stdlib-1.7 or later).</p>
- <p>If you use the option <c>{persistent, true}</c> you also must use the option
- <c>{regname, {global, Name}}</c>. This combination makes it possible to tell
- the difference between a server permanently terminated or in the process of restarting.</p>
- <p>The option <c>{pseudo, true}</c>, allow us to create an object which is not a
- server. Using <c>{pseudo, true}</c> overrides all other start options.
- For more information see section <c>Module_Interface</c>.</p>
- <p>If a server is started using the option <c>{persistent, true}</c> the object key
- will not be removed unless it terminates with reason <em>normal</em> or <em>shutdown</em>.
- Hence, if persistent servers is used as supervisor children they should be <em>transient</em>
- and the <em>objectkeys_gc_time</em> should be modified (default equals <c>infinity</c>).</p>
- <p>The option <c>{local_typecheck, boolean()}</c>, which overrides the
- <seealso marker="ch_install#flags">Local Typechecking</seealso>
- environment flag, turns on or off typechecking. If activated,
- parameters, replies and raised exceptions will be checked to ensure that
- the data is correct, when invoking operations on CORBA Objects within
- the same Orber domain. Due to the extra overhead, this option
- <em>MAY ONLY</em> be used during testing and development.</p>
- <code type="none">
-Example:
-
- corba:create('StackModule_Stack', "IDL:StackModule/Stack:1.0", {10, test})
- </code>
- </desc>
- </func>
- <func>
- <name>dispose(Object) -> ok</name>
- <fsummary>Stop a server object</fsummary>
- <type>
- <v>Object = #objref</v>
- </type>
- <desc>
- <p>This function is used for terminating the execution of a
- server object. Invoking this operation on a NIL object reference,
- e.g., the return value of <c>corba:create_nil_objref/0</c>, always
- return ok. For valid object references, invoking this operation
- more than once, will result in a system exception.</p>
- </desc>
- </func>
- <func>
- <name>create_nil_objref() -> Object</name>
- <fsummary>Stop a server object</fsummary>
- <type>
- <v>Object = #objref representing NIL.</v>
- </type>
- <desc>
- <p>Creates an object reference that represents the NIL value.
- Attempts to invoke operations using the returned object reference
- will return a system exception.</p>
- </desc>
- </func>
- <func>
- <name>create_subobject_key(Object, Key) -> Result</name>
- <fsummary>Add an Erlang term to a private key field</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>Key = term()</v>
- <v>Result = #objref</v>
- </type>
- <desc>
- <p>This function is used to create a subobject in a server object.
- It can for example be useful when one wants unique access to
- separate rows in a mnesia or an ETS table. The <em>Result</em> is
- an object reference that will be seen as a unique reference to
- the outside world but will access the same server object where one
- can use the <em>get_subobject_key/1</em> function to get the private
- key value.</p>
- <p><em>Key</em> is stored in the object reference <em>Object</em>.
- If it is a binary it will be stored as is and otherwise it is
- converted to a binary before storage.</p>
- </desc>
- </func>
- <func>
- <name>get_subobject_key(Object) -> Result</name>
- <fsummary>Fetch the contents of the private key field</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>Result = #binary</v>
- </type>
- <desc>
- <p>This function is used to fetch a subobject key from the object
- reference <em>Object</em>. The result is a always a binary, if it
- was an Erlang term that was stored with <em>create_subobject_key/2</em>
- one can to do <em>binary_to_term/1</em> to get the real value. </p>
- </desc>
- </func>
- <func>
- <name>get_pid(Object) -> Result</name>
- <fsummary>Get the process id from an object key</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>Result = #pid | {error, Reason} | {'EXCEPTION',E}</v>
- </type>
- <desc>
- <p>This function is to get the process id from an object, which is a
- must when CORBA objects is started/handled in a supervisor tree.
- The function will throw exceptions if the key is not found or
- some other error occurs.</p>
- </desc>
- </func>
- <func>
- <name>raise(Exception)</name>
- <fsummary>Generate an Erlang throw</fsummary>
- <type>
- <v>Exception = record()</v>
- </type>
- <desc>
- <p>This function is used for raising corba exceptions as an
- Erlang user generated exit signal. It will throw the tuple
- <c>{'EXCEPTION', </c><em>Exception</em><c>}</c>.</p>
- </desc>
- </func>
- <func>
- <name>reply(To, Reply) -> true</name>
- <fsummary>Send explicit reply to client</fsummary>
- <type>
- <v>To = client reference</v>
- <v>Reply = IDL type</v>
- </type>
- <desc>
- <p>This function can be used by a CORBA object to explicitly send
- a reply to a client that invoked a two-way operation. If this operation
- is used, it is <em>not</em> possible to return a reply in the call-back
- module.
- <br></br>
-<em>To</em> must be the <em>From</em> argument provided to the
- callback function, which requires that the IC option <em>from</em>
- was used when compiling the IDL-file.</p>
- </desc>
- </func>
- <func>
- <name>resolve_initial_references(ObjectId) -> Object</name>
- <name>resolve_initial_references(ObjectId, Contexts) -> Object</name>
- <fsummary>Return the object reference for the given object id</fsummary>
- <type>
- <v>ObjectId = string()</v>
- <v>Contexts = [Context]</v>
- <v>Context = #'IOP_ServiceContext'{context_id = CtxId, context_data = CtxData}</v>
- <v>CtxId = ?ORBER_GENERIC_CTX_ID</v>
- <v>CtxData = {interface, Interface} | {userspecific, term()} | {configuration, Options}</v>
- <v>Interface = string()</v>
- <v>Options = [{Key, Value}]</v>
- <v>Key = ssl_client_options</v>
- <v>Value = allowed value associated with the given key</v>
- <v>Object = #objref</v>
- </type>
- <desc>
- <p>This function returns the object reference associated with the given
- object id. Initially, only <c>"NameService"</c> is available. To add or remove
- services use <c>add_initial_service/2</c> or <c>remove_initial_service/1</c>.</p>
- <p>The <em>configuration</em> context is used to override the global
- SSL client side
- <seealso marker="ch_install#config">configuration</seealso>.</p>
- </desc>
- </func>
- <func>
- <name>add_initial_service(ObjectId, Object) -> boolean()</name>
- <fsummary>Add a new initial service and associate it with the given id</fsummary>
- <type>
- <v>ObjectId = string()</v>
- <v>Object = #objref</v>
- </type>
- <desc>
- <p>This operation allows us to add initial services, which can be accessed by
- using <c>resolve_initial_references/1</c> or the <c>corbaloc</c> schema.
- If using an Id defined by the OMG, the given object must be of the
- correct type; for more information see the
- <seealso marker="ch_naming_service#interop_ns">Interoperable Naming Service</seealso>.
- Returns <c>false</c> if the given id already exists.</p>
- </desc>
- </func>
- <func>
- <name>remove_initial_service(ObjectId) -> boolean()</name>
- <fsummary>Remove association between the given id and service</fsummary>
- <type>
- <v>ObjectId = string()</v>
- </type>
- <desc>
- <p>If we don not want a certain service to be accessible, invoking this function
- will remove the association. Returns <c>true</c> if able to terminate the
- binding. If no such binding existed <c>false</c> is returned.</p>
- </desc>
- </func>
- <func>
- <name>list_initial_services() -> [ObjectId]</name>
- <fsummary>Return a list of supported object id's</fsummary>
- <type>
- <v>ObjectId = string()</v>
- </type>
- <desc>
- <p>This function returns a list of allowed object id's.</p>
- </desc>
- </func>
- <func>
- <name>resolve_initial_references_remote(ObjectId, Address) -> Object</name>
- <name>resolve_initial_references_remote(ObjectId, Address, Contexts) -> Object</name>
- <fsummary>Return the object reference for the given object id</fsummary>
- <type>
- <v>ObjectId = string()</v>
- <v>Address = [RemoteModifier]</v>
- <v>RemoteModifier = string()</v>
- <v>Contexts = [Context]</v>
- <v>Context = #'IOP_ServiceContext'{context_id = CtxId, context_data = CtxData}</v>
- <v>CtxId = ?ORBER_GENERIC_CTX_ID</v>
- <v>CtxData = {interface, Interface} | {userspecific, term()} | {configuration, Options}</v>
- <v>Interface = string()</v>
- <v>Options = [{Key, Value}]</v>
- <v>Key = ssl_client_options</v>
- <v>Value = allowed value associated with the given key</v>
- <v>Object = #objref</v>
- </type>
- <desc>
- <p>This function returns the object reference for the object id asked
- for.
- The remote modifier string has the following format:
- <c>"iiop://"&lt;host&gt;":"&lt;port&gt;</c> where <c>&lt;host&gt; = &lt;DNS hostname&gt; |
- &lt;IPv4 address&gt; | "["&lt;IPv6 address&gt;"]"</c>.
- </p>
- <p>The <em>configuration</em> context is used to override the global
- SSL client side
- <seealso marker="ch_install#config">configuration</seealso>.</p>
- <warning>
- <p>This operation is not supported by most ORB's. Hence, use
- <c>corba:string_to_object/1</c> instead.</p>
- </warning>
- </desc>
- </func>
- <func>
- <name>list_initial_services_remote(Address) -> [ObjectId]</name>
- <name>list_initial_services_remote(Address, Contexts) -> [ObjectId]</name>
- <fsummary>Return a list of supported object id's</fsummary>
- <type>
- <v>Address = [RemoteModifier]</v>
- <v>RemoteModifier = string()</v>
- <v>Contexts = [Context]</v>
- <v>Context = #'IOP_ServiceContext'{context_id = CtxId, context_data = CtxData}</v>
- <v>CtxId = ?ORBER_GENERIC_CTX_ID</v>
- <v>CtxData = {interface, Interface} | {userspecific, term()} | {configuration, Options}</v>
- <v>Interface = string()</v>
- <v>Options = [{Key, Value}]</v>
- <v>Key = ssl_client_options</v>
- <v>Value = allowed value associated with the given key</v>
- <v>ObjectId = string()</v>
- </type>
- <desc>
- <p>This function returns a list of allowed object id's.
- The remote modifier string has the following format:
- <c>"iiop://"&lt;host&gt;":"&lt;port&gt;</c> where <c>&lt;host&gt; = &lt;DNS hostname&gt; |
- &lt;IPv4 address&gt; | "["&lt;IPv6 address&gt;"]"</c>.
- </p>
- <p>The <em>configuration</em> context is used to override the global
- SSL client side
- <seealso marker="ch_install#config">configuration</seealso>.</p>
- <warning>
- <p>This operation is not supported by most ORB's. Hence, avoid
- using it.</p>
- </warning>
- </desc>
- </func>
- <func>
- <name>object_to_string(Object) -> IOR_string</name>
- <fsummary>Convert the object reference to the external string representation</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>IOR_string = string()</v>
- </type>
- <desc>
- <p>This function returns the object reference as the external string
- representation of an IOR.</p>
- </desc>
- </func>
- <func>
- <name>string_to_object(IOR_string) -> Object</name>
- <name>string_to_object(IOR_string, Contexts) -> Object</name>
- <fsummary>Convert the external string representation to an object reference</fsummary>
- <type>
- <v>IOR_string = string()</v>
- <v>Contexts = [Context]</v>
- <v>Context = #'IOP_ServiceContext'{context_id = CtxId, context_data = CtxData}</v>
- <v>CtxId = ?ORBER_GENERIC_CTX_ID</v>
- <v>CtxData = {interface, Interface} | {userspecific, term()} | {configuration, Options}</v>
- <v>Interface = string()</v>
- <v>Options = [{Key, Value}]</v>
- <v>Key = ssl_client_options</v>
- <v>Value = allowed value associated with the given key</v>
- <v>Object = #objref</v>
- </type>
- <desc>
- <p>This function takes a <c>corbaname</c>, <c>corbaloc</c> or an IOR on the
- external string representation and returns the object reference.</p>
- <p>To lookup the NameService reference, simply use:</p>
- <code>corbaloc:iiop:[email protected]:4001/NameService</code>
- <p>We can also resolve an object from the NameService by using:</p>
- <code>corbaname:iiop:[email protected]:4001/NameService#org/Erlang/MyObj</code>
- <p>To lookup the NameService reference with an IPv6 address, simply use:</p>
- <code>corbaloc:iiop:1.2@[FEC1:0:3:0:0312:44AF:FAB1:3D01]:4001/NameService</code>
- <p>For more information about <c>corbaname</c> and <c>corbaloc</c>, see
- the User's Guide (Interoperable Naming Service).</p>
- <p>The <em>configuration</em> context is used to override the global
- SSL client side
- <seealso marker="ch_install#config">configuration</seealso>.</p>
- <p>How to handle the interface context is further described in the User's Guide.</p>
- </desc>
- </func>
- <func>
- <name>print_object(Data [, Type]) -> ok | {'EXCEPTION', E} | {'EXIT', R} | string()</name>
- <fsummary>Print the supplied object</fsummary>
- <type>
- <v>Data = IOR_string | #objref (local or external) | corbaloc/corbaname string</v>
- <v>Type = IoDevice | error_report | {error_report, Reason} | info_msg | {info_msg, Comment} | string</v>
- <v>IoDevice = see the io-module</v>
- <v>Reason = Comment = string()</v>
- </type>
- <desc>
- <p>The object represented by the supplied data is dissected and presented
- in a more readable form. The Type parameter is optional; if not supplied
- standard output is used. For <c>error_report</c> and <c>info_msg</c>
- the <c>error_logger</c> module is used, with or without Reason or Comment.
- If the atom <c>string</c> is supplied this function will return a flat
- list. The <c>IoDevice</c> is passed to the operation <c>io:format/2</c>.</p>
- <p>If the supplied object is a local reference, the output is equivalent
- to an object exported from the node this function is invoked on.</p>
- </desc>
- </func>
- <func>
- <name>add_alternate_iiop_address(Object, Host, Port) -> NewObject | {'EXCEPTION', E}</name>
- <fsummary>Add ALTERNATE_IIOP_ADDRESS component to the supplied local object</fsummary>
- <type>
- <v>Object = NewObject = local #objref</v>
- <v>Host = string()</v>
- <v>Port = integer()</v>
- </type>
- <desc>
- <p>This operation creates a new instance of the supplied object
- containing an ALTERNATE_IIOP_ADDRESS component. Only the new instance
- contains the new component. When this object is passed to another
- ORB, which supports the ALTERNATE_IIOP_ADDRESS, requests will be routed
- to the alternate address if it is not possible to communicate with
- the main address.</p>
- <p>The ALTERNATE_IIOP_ADDRESS component requires that IIOP-1.2 is used.
- Hence, make sure both Orber and the other ORB is correctly configured.</p>
- <p></p>
- <note>
- <p>Make sure that the given <c>Object</c> is accessible via the
- alternate Host/port. For example, if the object is correctly started as
- <c>local</c> or <c>pseudo</c>, the object should be available on all
- nodes within a multi-node Orber installation. Since only one instance
- exists for other object types, it will not be possible to access it
- if the node it was started on terminates.</p>
- </note>
- </desc>
- </func>
- <func>
- <name>orb_init(KeyValueList) -> ok | {'EXIT', Reason}</name>
- <fsummary>Configure Orber before starting it</fsummary>
- <type>
- <v>KeyValueList = [{Key, Value}]</v>
- <v>Key = any key listed in the configuration chapter</v>
- <v>Value = allowed value associated with the given key</v>
- </type>
- <desc>
- <p>This function allows the user to configure Orber in, for example,
- an Erlang shell. Orber may <em>NOT</em> be started prior to invoking
- this operation. For more information, see
- <seealso marker="ch_install#config">configuration settings</seealso>
- in the User's Guide.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/orber/doc/src/corba_object.xml b/lib/orber/doc/src/corba_object.xml
deleted file mode 100644
index 09a4b0bc3c..0000000000
--- a/lib/orber/doc/src/corba_object.xml
+++ /dev/null
@@ -1,194 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1997</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>corba_object</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>1997-11-10</date>
- <rev>A</rev>
- </header>
- <module>corba_object</module>
- <modulesummary>The CORBA Object interface functions</modulesummary>
- <description>
- <p>This module contains the CORBA Object interface functions that can be
- called for all objects.</p>
- </description>
- <funcs>
- <func>
- <name>get_interface(Object) -> InterfaceDef</name>
- <fsummary>Fetch the interface description</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>InterfaceDef = term()</v>
- </type>
- <desc>
- <p>This function returns the full interface description for an object.</p>
- </desc>
- </func>
- <func>
- <name>is_nil(Object) -> boolean()</name>
- <fsummary>Return true, if the given object is a NIL object reference, otherwise false</fsummary>
- <type>
- <v>Object = #objref</v>
- </type>
- <desc>
- <p>This function checks if the object reference has a nil object value,
- which denotes no object. It is the reference that is tested and no
- object implementation is involved in the test. </p>
- </desc>
- </func>
- <func>
- <name>is_a(Object, Logical_type_id) -> Return</name>
- <name>is_a(Object, Logical_type_id, Contexts) -> Return</name>
- <fsummary>Return true if the target object is an, or inherit from, object of the given type</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>Logical_type_id = string()</v>
- <v>Contexts = [Context]</v>
- <v>Context = #'IOP_ServiceContext'{context_id = CtxId, context_data = CtxData}</v>
- <v>CtxId = ?ORBER_GENERIC_CTX_ID</v>
- <v>CtxData = {interface, Interface} | {userspecific, term()} | {configuration, Options}</v>
- <v>Interface = string()</v>
- <v>Options = [{Key, Value}]</v>
- <v>Key = ssl_client_options</v>
- <v>Value = allowed value associated with the given key</v>
- <v>Return = boolean() | {'EXCEPTION', E}</v>
- </type>
- <desc>
- <p>The <em>Logical_type_id</em> is a string that is a share type
- identifier (repository id). The function returns true if the object
- is an instance of that type or an ancestor of the "most derived"
- type of that object.</p>
- <p>The <em>configuration</em> context is used to override the global
- SSL client side
- <seealso marker="ch_install#config">configuration</seealso>.</p>
- <p>Note: Other ORB suppliers may not support this function completely
- according to the OMG specification. Thus, a <em>is_a</em> call may
- raise an exception or respond unpredictable if the Object is
- located on a remote node.</p>
- </desc>
- </func>
- <func>
- <name>is_remote(Object) -> boolean()</name>
- <fsummary>Determine whether or not an object reference is remote</fsummary>
- <type>
- <v>Object = #objref</v>
- </type>
- <desc>
- <p>This function returns true if an object reference is remote
- otherwise false. </p>
- </desc>
- </func>
- <func>
- <name>non_existent(Object) -> Return</name>
- <name>non_existent(Object, Contexts) -> Return</name>
- <fsummary>Return false if the target object do not exist, otherwise true</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>Contexts = [Context]</v>
- <v>Context = #'IOP_ServiceContext'{context_id = CtxId, context_data = CtxData}</v>
- <v>CtxId = ?ORBER_GENERIC_CTX_ID</v>
- <v>CtxData = {interface, Interface} | {userspecific, term()} | {configuration, Options}</v>
- <v>Interface = string()</v>
- <v>Options = [{Key, Value}]</v>
- <v>Key = ssl_client_options</v>
- <v>Value = allowed value associated with the given key</v>
- <v>Return = boolean() | {'EXCEPTION', E}</v>
- </type>
- <desc>
- <p>This function can be used to test if the object has been destroyed.
- It does this without invoking any application level code. The ORB
- returns true if it knows that the object is destroyed otherwise
- false.</p>
- <p>The <em>configuration</em> context is used to override the global
- SSL client side
- <seealso marker="ch_install#config">configuration</seealso>.</p>
- <p>Note: The OMG have specified two different operators, <c>_not_existent</c> (CORBA version 2.0 and 2.2) and
- <c>_non_existent</c> (CORBA version 2.3), to be used for this function. It is not mandatory to support
- both versions. Thus, a <em>non_existent</em> call may raise an exception or respond unpredictable
- if the Object is located on a remote node. Depending on which version, ORB:s you intend to
- communicate with supports, you can either use this function or <c>not_existent/1</c>.</p>
- </desc>
- </func>
- <func>
- <name>not_existent(Object) -> Return</name>
- <name>not_existent(Object, Contexts) -> Return</name>
- <fsummary>Return false if the target object do not exist, otherwise true</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>Contexts = [Context]</v>
- <v>Context = #'IOP_ServiceContext'{context_id = CtxId, context_data = CtxData}</v>
- <v>CtxId = ?ORBER_GENERIC_CTX_ID</v>
- <v>CtxData = {interface, Interface} | {userspecific, term()} | {configuration, Options}</v>
- <v>Interface = string()</v>
- <v>Options = [{Key, Value}]</v>
- <v>Key = ssl_client_options</v>
- <v>Value = allowed value associated with the given key</v>
- <v>Return = boolean() | {'EXCEPTION', E}</v>
- </type>
- <desc>
- <p>This function is implemented due to Interoperable purposes. Behaves as
- <c>non_existent</c> except the operator <c>_not_existent</c> is used when
- communicating with other ORB:s.</p>
- <p>The <em>configuration</em> context is used to override the global
- SSL client side
- <seealso marker="ch_install#config">configuration</seealso>.</p>
- </desc>
- </func>
- <func>
- <name>is_equivalent(Object, OtherObject) -> boolean()</name>
- <fsummary>Return true if the target object and the supplied object easily can be determined to be equal, otherwise false</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>OtherObject = #objref</v>
- </type>
- <desc>
- <p>This function is used to determine if two object references are
- equivalent so far the ORB easily can determine. It returns
- <em>true</em> if the target object reference is equal to the
- other object reference and <em>false</em> otherwise.</p>
- </desc>
- </func>
- <func>
- <name>hash(Object, Maximum) -> int()</name>
- <fsummary>Return a hash value based on the target object</fsummary>
- <type>
- <v>Object = #objref</v>
- <v>Maximum = int()</v>
- </type>
- <desc>
- <p>This function returns a hash value based on the object reference
- that not will change during the lifetime of the object.
- The <em>Maximum</em> parameter denotes the upper bound of the value.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/orber/doc/src/dataframe1.gif b/lib/orber/doc/src/dataframe1.gif
deleted file mode 100644
index 21bd0afbc5..0000000000
--- a/lib/orber/doc/src/dataframe1.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/dataframe2.gif b/lib/orber/doc/src/dataframe2.gif
deleted file mode 100644
index 26778932b4..0000000000
--- a/lib/orber/doc/src/dataframe2.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/dataframe3.gif b/lib/orber/doc/src/dataframe3.gif
deleted file mode 100644
index db8ffef7d1..0000000000
--- a/lib/orber/doc/src/dataframe3.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/dataframe4.gif b/lib/orber/doc/src/dataframe4.gif
deleted file mode 100644
index f64c7f3733..0000000000
--- a/lib/orber/doc/src/dataframe4.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/dataframe5.gif b/lib/orber/doc/src/dataframe5.gif
deleted file mode 100644
index 80e17945a2..0000000000
--- a/lib/orber/doc/src/dataframe5.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/dataframe6.gif b/lib/orber/doc/src/dataframe6.gif
deleted file mode 100644
index fb1c5d7827..0000000000
--- a/lib/orber/doc/src/dataframe6.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/dataframe7.gif b/lib/orber/doc/src/dataframe7.gif
deleted file mode 100644
index 1e18078f0a..0000000000
--- a/lib/orber/doc/src/dataframe7.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/dataframe8.gif b/lib/orber/doc/src/dataframe8.gif
deleted file mode 100644
index ef95c9a11f..0000000000
--- a/lib/orber/doc/src/dataframe8.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/dependent.gif b/lib/orber/doc/src/dependent.gif
deleted file mode 100644
index c65c427421..0000000000
--- a/lib/orber/doc/src/dependent.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/example_part.xml b/lib/orber/doc/src/example_part.xml
deleted file mode 100644
index 61c9524cc3..0000000000
--- a/lib/orber/doc/src/example_part.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE part SYSTEM "part.dtd">
-
-<part>
- <header>
- <copyright>
- <year>2002</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Service Implementation</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2002-06-25</date>
- <rev>A</rev>
- </header>
- <description>
- <p>This chapter describe how to implement Orber based CORBA services.</p>
- </description>
- <include file="ch_stubs"></include>
-</part>
-
diff --git a/lib/orber/doc/src/firewall_nat.gif b/lib/orber/doc/src/firewall_nat.gif
deleted file mode 100644
index 3a80aac724..0000000000
--- a/lib/orber/doc/src/firewall_nat.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/fixed.xml b/lib/orber/doc/src/fixed.xml
deleted file mode 100644
index ef4d1bd604..0000000000
--- a/lib/orber/doc/src/fixed.xml
+++ /dev/null
@@ -1,160 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2002</year><year>2017</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>fixed</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>2002-05-22</date>
- <rev>A</rev>
- </header>
- <module>fixed</module>
- <modulesummary>the corba fixed type</modulesummary>
- <description>
- <p>This module contains functions that gives an interface to the CORBA fixed type.</p>
- <p>The type <c>Fixed</c> used below is defined as:</p>
- <code type="erl">
--record(fixed, {digits, scale, value}).
- </code>
- <p>where <c>digits</c> is the total amount of digits it consists of and
- <c>scale</c> is the number of fractional digits. The <c>value</c> field
- contains the actual Fixed value represented as an integer. The limitations
- of each field are:</p>
- <list type="bulleted">
- <item>Digits - integer(), -1 > Digits &lt; 32</item>
- <item>Scale - integer(), -1 > Scale =&lt; Digits</item>
- <item>Value - integer(), range (31 digits): &plusmn;9999999999999999999999999999999</item>
- </list>
- <p>Since the Value part is represented by an integer, it is vital that the
- Digits and Scale values are correct. This also means that trailing zeros
- cannot be left out in some cases:</p>
- <list type="bulleted">
- <item>fixed&lt;5,3> eq. 03.140d eq. 3140</item>
- <item>fixed&lt;3,2> eq. 3.14d eq. 314</item>
- </list>
- <p>Leading zeros can be left out.</p>
- <p>For your convenience, this module exports functions which handle
- unary (<c>-</c>) and binary (<c>+-*/</c>) operations legal for the Fixed type.
- Since a unary <c>+</c> have no effect, this module do not export such a
- function. Any of the binary operations may cause an overflow (i.e. more than
- 31 significant digits; leading and trailing zeros are not considered
- significant). If this is the case, the Digit and Scale values are adjusted
- and the Value truncated (no rounding performed). This behavior is
- compliant with the OMG CORBA specification. Each binary operation have
- the following upper bounds:</p>
- <list type="bulleted">
- <item><em>Fixed1 + Fixed2</em> - <c><![CDATA[fixed<max(d1-s1,d2-s2) + max(s1,s2) + 1, max(s1,s2)>]]></c></item>
- <item><em>Fixed1 - Fixed2</em> - <c><![CDATA[fixed<max(d1-s1,d2-s2) + max(s1,s2) + 1, max(s1,s2)>]]></c></item>
- <item><em>Fixed1 * Fixed2</em> - <c><![CDATA[fixed<d1+d2, s1+s2>]]></c></item>
- <item><em>Fixed1 / Fixed2</em> - <c><![CDATA[fixed<(d1-s1+s2) + Sinf ,Sinf >]]></c></item>
- </list>
- <p>A quotient may have an arbitrary number of decimal places, which is
- denoted by a scale of Sinf.</p>
- </description>
- <funcs>
- <func>
- <name>create(Digits, Scale, Value) -> Result</name>
- <fsummary>Create a fixed type</fsummary>
- <type>
- <v>Result = Fixed Type | {'EXCEPTION', #'BAD_PARAM'{}}</v>
- </type>
- <desc>
- <p>This function creates a new instance of a <c>Fixed Type</c>. If
- the limitations is not fulfilled (e.g. overflow) an exception is
- raised.</p>
- </desc>
- </func>
- <func>
- <name>get_typecode(Fixed) -> Result</name>
- <fsummary>Create TypeCode representing the supplied fixed type</fsummary>
- <type>
- <v>Result = TypeCode | {'EXCEPTION', #'BAD_PARAM'{}}</v>
- </type>
- <desc>
- <p>Returns the TypeCode which represents the supplied Fixed type.
- If the parameter is not of the correct type, an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>add(Fixed1, Fixed2) -> Result</name>
- <fsummary>Add the supplied Fixed types</fsummary>
- <type>
- <v>Result = Fixed1 + Fixed2 | {'EXCEPTION', #'BAD_PARAM'{}}</v>
- </type>
- <desc>
- <p>Performs a Fixed type addition.
- If the parameters are not of the correct type, an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>subtract(Fixed1, Fixed2) -> Result</name>
- <fsummary>Subtract Fixed2 from Fixed1</fsummary>
- <type>
- <v>Result = Fixed1 - Fixed2 | {'EXCEPTION', #'BAD_PARAM'{}}</v>
- </type>
- <desc>
- <p>Performs a Fixed type subtraction.
- If the parameters are not of the correct type, an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>multiply(Fixed1, Fixed2) -> Result</name>
- <fsummary>Multiply Fixed1 with Fixed2</fsummary>
- <type>
- <v>Result = Fixed1 * Fixed2 | {'EXCEPTION', #'BAD_PARAM'{}}</v>
- </type>
- <desc>
- <p>Performs a Fixed type multiplication.
- If the parameters are not of the correct type, an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>divide(Fixed1, Fixed2) -> Result</name>
- <fsummary>Divide Fixed1 with Fixed2</fsummary>
- <type>
- <v>Result = Fixed1 / Fixed2 | {'EXCEPTION', #'BAD_PARAM'{}}</v>
- </type>
- <desc>
- <p>Performs a Fixed type division.
- If the parameters are not of the correct type, an exception is raised.</p>
- </desc>
- </func>
- <func>
- <name>unary_minus(Fixed) -> Result</name>
- <fsummary>Negate the supplied Fixed Type</fsummary>
- <type>
- <v>Result = -Fixed | {'EXCEPTION', #'BAD_PARAM'{}}</v>
- </type>
- <desc>
- <p>Negates the supplied Fixed type.
- If the parameter is not of the correct type, an exception is raised.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/orber/doc/src/ifr_notes.txt b/lib/orber/doc/src/ifr_notes.txt
deleted file mode 100644
index 54f79be8cd..0000000000
--- a/lib/orber/doc/src/ifr_notes.txt
+++ /dev/null
@@ -1,53 +0,0 @@
--*-Mode: Outline;-*-
-
-* Transactions.
- Transaction handling (or the use of mnesia:async_dirty) is not very
- good at error checking. Code to handle errors from transactions must
- be added. Right now it is not possible to mix atomic transactions
- with dirty 'transactions' (i.e. async_dirty) and still check the
- results consistently. This must be fixed if we are to read with
- async_dirty instead of transaction, since we still want to do all
- the writes with transaction and not async_dirty.
- (This point might be moot. Simple reads are now done with
- mnesia:dirty_read/1 outside of transactions).
-
-* Unresolved issues.
- There are some places in the source code marked with '***' where the
- code should be verified. It mostly concerns minor unresolved
- unclarities in the specification.
-
-** orber_ifr_contained.erl
- In move/4 there is a call to orber_ifr_contained:lookup_name/5. The
- third argument, Levels_to_search, is set to -1, which means search
- all contained objects. This is probably correct.
-
-** orber_ifr_interfacedef.erl
- The function describe_interface/1 describes the interface without
- its inherited interfaces. It is not clear whether this is correct or
- not. It is possible to get a description of the inherited interfaces
- by mapping describe_interface/1 on the list if interfaces returned
- by get_base_interfaces/1. Also, since the structs
- InterfaceDescription and FullInterfaceDescription both have a field
- named base_interfaces, it is possible to get a description of the
- inherited attributes by examining that field and applying a describe
- function.
-
-** orber_ifr_orb.erl
- create_union_tc/4 sets the fifth element in the typecode tuple to
- -1, meaning no default case.
-
-** orber_ifr_repository.erl
- The PrimitiveDef with kind pk_objref has an empty Id and an empty
- Name. This is perhaps not correct.
-
-** orber_ifr_typecode.erl
- None of the functions in this module are fully implemented and they
- should not be used.
-
-** orber_ifr_uniondef.erl
-*** '_set_members'/2
- What should the value of the discriminator-typecode be when updating
- the type attribute? (CORBA 2.0, p 6-20). For now we just leave it
- unchanged, but this is perhaps not the right thing to do.
-
-* Exceptions should give more information about the failure.
diff --git a/lib/orber/doc/src/iiop.gif b/lib/orber/doc/src/iiop.gif
deleted file mode 100644
index d2f2fd128c..0000000000
--- a/lib/orber/doc/src/iiop.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/images/GridBagEx.gif b/lib/orber/doc/src/images/GridBagEx.gif
deleted file mode 100644
index 16c326d88c..0000000000
--- a/lib/orber/doc/src/images/GridBagEx.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/images/OpenBookIcon.gif b/lib/orber/doc/src/images/OpenBookIcon.gif
deleted file mode 100644
index 86384f7733..0000000000
--- a/lib/orber/doc/src/images/OpenBookIcon.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/images/blue-ball-small.gif b/lib/orber/doc/src/images/blue-ball-small.gif
deleted file mode 100644
index d4c5cde5b0..0000000000
--- a/lib/orber/doc/src/images/blue-ball-small.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/images/blue-ball.gif b/lib/orber/doc/src/images/blue-ball.gif
deleted file mode 100644
index edc29b786c..0000000000
--- a/lib/orber/doc/src/images/blue-ball.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/images/class-index.gif b/lib/orber/doc/src/images/class-index.gif
deleted file mode 100644
index 7f276bcb24..0000000000
--- a/lib/orber/doc/src/images/class-index.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/images/constructor-index.gif b/lib/orber/doc/src/images/constructor-index.gif
deleted file mode 100644
index 435cac4238..0000000000
--- a/lib/orber/doc/src/images/constructor-index.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/images/constructors.gif b/lib/orber/doc/src/images/constructors.gif
deleted file mode 100644
index d1a6ae507c..0000000000
--- a/lib/orber/doc/src/images/constructors.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/images/cyan-ball-small.gif b/lib/orber/doc/src/images/cyan-ball-small.gif
deleted file mode 100644
index 7f74357443..0000000000
--- a/lib/orber/doc/src/images/cyan-ball-small.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/images/cyan-ball.gif b/lib/orber/doc/src/images/cyan-ball.gif
deleted file mode 100644
index 97ca1f2b6e..0000000000
--- a/lib/orber/doc/src/images/cyan-ball.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/images/error-index.gif b/lib/orber/doc/src/images/error-index.gif
deleted file mode 100644
index 22835ff8c6..0000000000
--- a/lib/orber/doc/src/images/error-index.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/images/exception-index.gif b/lib/orber/doc/src/images/exception-index.gif
deleted file mode 100644
index e3830d9c52..0000000000
--- a/lib/orber/doc/src/images/exception-index.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/images/green-ball-small.gif b/lib/orber/doc/src/images/green-ball-small.gif
deleted file mode 100644
index 17fea5b32b..0000000000
--- a/lib/orber/doc/src/images/green-ball-small.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/images/green-ball.gif b/lib/orber/doc/src/images/green-ball.gif
deleted file mode 100644
index 71e1b2ec2d..0000000000
--- a/lib/orber/doc/src/images/green-ball.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/images/interface-index.gif b/lib/orber/doc/src/images/interface-index.gif
deleted file mode 100644
index bf93dda9e3..0000000000
--- a/lib/orber/doc/src/images/interface-index.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/images/magenta-ball-small.gif b/lib/orber/doc/src/images/magenta-ball-small.gif
deleted file mode 100644
index bd0584b3c6..0000000000
--- a/lib/orber/doc/src/images/magenta-ball-small.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/images/magenta-ball.gif b/lib/orber/doc/src/images/magenta-ball.gif
deleted file mode 100644
index 5da03b84d2..0000000000
--- a/lib/orber/doc/src/images/magenta-ball.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/images/method-index.gif b/lib/orber/doc/src/images/method-index.gif
deleted file mode 100644
index a05e705116..0000000000
--- a/lib/orber/doc/src/images/method-index.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/images/methods.gif b/lib/orber/doc/src/images/methods.gif
deleted file mode 100644
index 949e01b8a3..0000000000
--- a/lib/orber/doc/src/images/methods.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/images/package-index.gif b/lib/orber/doc/src/images/package-index.gif
deleted file mode 100644
index f894d4210d..0000000000
--- a/lib/orber/doc/src/images/package-index.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/images/red-ball-small.gif b/lib/orber/doc/src/images/red-ball-small.gif
deleted file mode 100644
index f6b3c372ca..0000000000
--- a/lib/orber/doc/src/images/red-ball-small.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/images/red-ball.gif b/lib/orber/doc/src/images/red-ball.gif
deleted file mode 100644
index dca9296014..0000000000
--- a/lib/orber/doc/src/images/red-ball.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/images/variable-index.gif b/lib/orber/doc/src/images/variable-index.gif
deleted file mode 100644
index 65cc029e72..0000000000
--- a/lib/orber/doc/src/images/variable-index.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/images/variables.gif b/lib/orber/doc/src/images/variables.gif
deleted file mode 100644
index e8a735399a..0000000000
--- a/lib/orber/doc/src/images/variables.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/images/yellow-ball-small.gif b/lib/orber/doc/src/images/yellow-ball-small.gif
deleted file mode 100644
index 8e5f57cdfc..0000000000
--- a/lib/orber/doc/src/images/yellow-ball-small.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/images/yellow-ball.gif b/lib/orber/doc/src/images/yellow-ball.gif
deleted file mode 100644
index 2b8c0bb3d6..0000000000
--- a/lib/orber/doc/src/images/yellow-ball.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/interceptor_operations.gif b/lib/orber/doc/src/interceptor_operations.gif
deleted file mode 100644
index cd72f7fcb7..0000000000
--- a/lib/orber/doc/src/interceptor_operations.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/interceptors.xml b/lib/orber/doc/src/interceptors.xml
deleted file mode 100644
index 0aade8ffb4..0000000000
--- a/lib/orber/doc/src/interceptors.xml
+++ /dev/null
@@ -1,284 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2001</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>interceptors</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>1999-09-03</date>
- <rev>A</rev>
- </header>
- <module>interceptors</module>
- <modulesummary>Describe the functions which must be exported by any supplied Orber native interceptor.</modulesummary>
- <description>
- <p>This module contains the mandatory functions for user supplied native
- interceptors and their intended behavior. See also the User's Guide.</p>
- <warning>
- <p>Using <c>Interceptors</c> may reduce the through-put significantly
- if the supplied interceptors invoke expensive operations. Hence,
- one should always supply interceptors which cause as little overhead
- as possible.</p>
- </warning>
- <warning>
- <p>It is possible to alter the <c>Data</c>, <c>Bin</c> and <c>Args</c>
- parameter for the <c>in_reply</c> and <c>out_reply</c>,
- <c>in_reply_encoded</c>, <c>in_request_encoded</c>,
- <c>out_reply_encoded</c> and <c>out_request_encoded</c>,
- <c>in_request</c> and <c>out_request</c> respectively. But,
- if it is done incorrectly, the consequences can be serious.</p>
- </warning>
- <note>
- <p>The <c>Extra</c> parameter is set to 'undefined' by Orber when calling
- the first interceptor and may be set to any Erlang term. If an
- interceptor change this parameter it will be passed on to the next
- interceptor in the list uninterpreted.</p>
- </note>
- <note>
- <p>The <c>Ref</c> parameter is set to 'undefined' by Orber when calling
- <c>new_in_connection</c> or <c>new_out_connection</c> using
- the first interceptor. The user supplied interceptor may set <c>NewRef</c>
- to any Erlang term. If an interceptor change this parameter it will be
- passed on to the next interceptor in the list uninterpreted.</p>
- </note>
- </description>
- <funcs>
- <func>
- <name>new_in_connection(Ref, PeerHost, PeerPort) -> NewRef</name>
- <name>new_in_connection(Ref, PeerHost, PeerPort, SocketHost, SocketPort) -> NewRef</name>
- <fsummary>Invoke when a new client ORB wants to setup a connection</fsummary>
- <type>
- <v>Ref = term() | undefined</v>
- <v>PeerHost = SocketHost = string(), e.g., "myHost@myServer" or "192.0.0.10"</v>
- <v>PeerPort = SocketPort = integer()</v>
- <v>NewRef = term() | {'EXIT', Reason}</v>
- </type>
- <desc>
- <p>When a new connection is requested by a client side ORB this operation
- is invoked. If more than one interceptor is supplied, e.g.,
- <c>{native, ['myInterceptor1', 'myInterceptor2']}</c>, the return value
- from 'myInterceptor1' is passed to 'myInterceptor2' as <c>Ref</c>.
- Initially, Orber uses the atom 'undefined' as <c>Ref</c> parameter
- when calling the first interceptor. The return value from the last
- interceptor, in the example above 'myInterceptor2', is passed
- to all other functions exported by the interceptors. Hence,
- the <c>Ref</c> parameter can, for example, be used as a unique
- identifier to mnesia or ets where information/restrictions for
- this connection is stored.</p>
- <p>The PeerHost and PeerPort variables supplied data of
- the client ORB which requested a new connection. SocketHost
- and SocketPort are the local interface and port the client
- connected to.</p>
- <p>If, for some reason, we do not allow the client ORB to connect
- simply invoke <c>exit(Reason)</c>.</p>
- </desc>
- </func>
- <func>
- <name>new_out_connection(Ref, PeerHost, PeerPort) -> NewRef</name>
- <name>new_out_connection(Ref, PeerHost, PeerPort, SocketHost, SocketPort) -> NewRef</name>
- <fsummary>Invoke when setting up a new connection to a server side ORB</fsummary>
- <type>
- <v>Ref = term() | undefined</v>
- <v>PeerHost = SocketHost = string(), e.g., "myHost@myServer" or "192.0.0.10"</v>
- <v>PeerPort = SocketPort = integer()</v>
- <v>NewRef = term() | {'EXIT', Reason}</v>
- </type>
- <desc>
- <p>When a new connection is set up this function is invoked. Behaves
- just like <c>new_in_connection</c>; the only difference is that
- the PeerHost and PeerPort variables identifies the target ORB's bootstrap
- data and SocketHost and SocketPort are the local interface and port
- the client ORB connected via.</p>
- </desc>
- </func>
- <func>
- <name>closed_in_connection(Ref) -> NewRef</name>
- <fsummary>Invoke when an existing connection to a client side ORB have been terminated</fsummary>
- <type>
- <v>Ref = term()</v>
- <v>NewRef = term()</v>
- </type>
- <desc>
- <p>When an existing connection is terminated this operation is invoked.
- The main purpose of this function is to make it possible for a user
- to clean up all data associated with the associated connection.</p>
- <p>The input parameter <c>Ref</c> is the return value from
- <c>new_in_connection/3</c>.</p>
- </desc>
- </func>
- <func>
- <name>closed_out_connection(Ref) -> NewRef</name>
- <fsummary>Invoke when an existing connection to a server side ORB have been terminated</fsummary>
- <type>
- <v>Ref = term()</v>
- <v>NewRef = term()</v>
- </type>
- <desc>
- <p>When an existing connection is terminated this operation is invoked.
- The main purpose of this function is to make it possible for a user
- to clean up all data associated with the associated connection.</p>
- <p>The input parameter <c>Ref</c> is the return value from
- <c>new_out_connection/3</c>.</p>
- </desc>
- </func>
- <func>
- <name>in_reply(Ref, Obj, Ctx, Op, Data, Extra) -> Reply</name>
- <fsummary>Invoke when replies arrives at the client side ORB</fsummary>
- <type>
- <v>Ref = term()</v>
- <v>Obj = #objref</v>
- <v>Ctx = [#'IOP_ServiceContext'{}]</v>
- <v>Op = atom()</v>
- <v>Data = [Result, OutParameter1, ..., OutPramaterN]</v>
- <v>Reply = {NewData, NewExtra}</v>
- </type>
- <desc>
- <p>When replies are delivered from the server side ORB to the client side
- ORB this operation is invoked. The <c>Data</c> parameter is a list in which
- the first element is the return value value from the target object and
- the rest is a all parameters defined as <c>out</c> or <c>inout</c> in
- the IDL-specification.</p>
- </desc>
- </func>
- <func>
- <name>in_reply_encoded(Ref, Obj, Ctx, Op, Bin, Extra) -> Reply</name>
- <fsummary>Invoke when replies arrives at the client side ORB with undecoded reply body</fsummary>
- <type>
- <v>Ref = term()</v>
- <v>Obj = #objref</v>
- <v>Ctx = [#'IOP_ServiceContext'{}]</v>
- <v>Op = atom()</v>
- <v>Bin = #binary</v>
- <v>Reply = {NewBin, NewExtra}</v>
- </type>
- <desc>
- <p>When replies are delivered from the server side ORB to the client side
- ORB this operation is invoked. The <c>Bin</c> parameter is the reply
- body still uncoded.</p>
- </desc>
- </func>
- <func>
- <name>in_request(Ref, Obj, Ctx, Op, Args, Extra) -> Reply</name>
- <fsummary>Invoke when requests arrive at the server side ORB</fsummary>
- <type>
- <v>Ref = term()</v>
- <v>Obj = #objref</v>
- <v>Ctx = [#'IOP_ServiceContext'{}]</v>
- <v>Op = atom()</v>
- <v>Args = [Argument] - defined in the IDL-specification</v>
- <v>Reply = {NewArgs, NewExtra}</v>
- </type>
- <desc>
- <p>When a new request arrives at the server side ORB this operation is
- invoked.</p>
- </desc>
- </func>
- <func>
- <name>in_request_encoded(Ref, Obj, Ctx, Op, Bin, Extra) -> Reply</name>
- <fsummary>Invoke when requests arrive at the server side ORB with undecoded request body</fsummary>
- <type>
- <v>Ref = term()</v>
- <v>Obj = #objref</v>
- <v>Ctx = [#'IOP_ServiceContext'{}]</v>
- <v>Op = atom()</v>
- <v>Bin = #binary</v>
- <v>Reply = {NewBin, NewExtra}</v>
- </type>
- <desc>
- <p>When a new request arrives at the server side ORB this operation is
- invoked before decoding the request body.</p>
- </desc>
- </func>
- <func>
- <name>out_reply(Ref, Obj, Ctx, Op, Data, Extra) -> Reply</name>
- <fsummary>Invoke after the target object replied</fsummary>
- <type>
- <v>Ref = term()</v>
- <v>Obj = #objref</v>
- <v>Ctx = [#'IOP_ServiceContext'{}]</v>
- <v>Op = atom()</v>
- <v>Data = [Result, OutParameter1, ..., OutPramaterN]</v>
- <v>Reply = {NewData, NewExtra}</v>
- </type>
- <desc>
- <p>After the target object have been invoked this operation is invoked
- with the result. The <c>Data</c> parameter is a list in which
- the first element is the return value value from the target object and
- the rest is a all parameters defined as <c>out</c> or <c>inout</c> in
- the IDL-specification.</p>
- </desc>
- </func>
- <func>
- <name>out_reply_encoded(Ref, Obj, Ctx, Op, Bin, Extra) -> Reply</name>
- <fsummary>Invoke after the target object replied with the reply encoded</fsummary>
- <type>
- <v>Ref = term()</v>
- <v>Obj = #objref</v>
- <v>Ctx = [#'IOP_ServiceContext'{}]</v>
- <v>Op = atom()</v>
- <v>Bin = #binary</v>
- <v>Reply = {NewBin, NewExtra}</v>
- </type>
- <desc>
- <p>This operation is similar to <c>out_reply</c>; the only difference is
- that the reply body have been encoded.</p>
- </desc>
- </func>
- <func>
- <name>out_request(Ref, Obj, Ctx, Op, Args, Extra) -> Reply</name>
- <fsummary>Invoke on the client side ORB before encoding and sending the request</fsummary>
- <type>
- <v>Ref = term()</v>
- <v>Obj = #objref</v>
- <v>Ctx = [#'IOP_ServiceContext'{}]</v>
- <v>Op = atom()</v>
- <v>Args = [Argument] - defined in the IDL-specification</v>
- <v>Reply = {NewArgs, NewExtra}</v>
- </type>
- <desc>
- <p>Before a request is sent to the server side ORB, <c>out_request</c> is
- invoked.</p>
- </desc>
- </func>
- <func>
- <name>out_request_encoded(Ref, Obj, Ctx, Op, Bin, Extra) -> Reply</name>
- <fsummary>Invoke on the client side ORB before sending the request</fsummary>
- <type>
- <v>Ref = term()</v>
- <v>Obj = #objref</v>
- <v>Ctx = [#'IOP_ServiceContext'{}]</v>
- <v>Op = atom()</v>
- <v>Bin = #binary</v>
- <v>Reply = {NewBin, NewExtra}</v>
- </type>
- <desc>
- <p>This operation is similar to <c>out_request</c>; the only
- difference is that the request body have been encoded.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/orber/doc/src/intro_part.xml b/lib/orber/doc/src/intro_part.xml
deleted file mode 100644
index 7e5520e42e..0000000000
--- a/lib/orber/doc/src/intro_part.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE part SYSTEM "part.dtd">
-
-<part>
- <header>
- <copyright>
- <year>2002</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>Introduction to Orber and the IFR</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2002-06-25</date>
- <rev>A</rev>
- </header>
- <description>
- <p>This chapter contains an introduction to Orber and the IFR
- (Interface Repository).</p>
- </description>
- <include file="ch_introduction"></include>
- <include file="ch_orber_kernel"></include>
- <include file="ch_ifr"></include>
-</part>
-
diff --git a/lib/orber/doc/src/lname.xml b/lib/orber/doc/src/lname.xml
deleted file mode 100644
index c0c9be1a85..0000000000
--- a/lib/orber/doc/src/lname.xml
+++ /dev/null
@@ -1,166 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1997</year><year>2017</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>lname</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>1997-06-10</date>
- <rev>A</rev>
- </header>
- <module>lname</module>
- <modulesummary>Interface that supports the name pseudo-objects.</modulesummary>
- <description>
- <p>This interface is a part of the names library which is used to hide the
- representation of names. In Orbers Erlang mapping the pseudo-object names
- and the real IDL names have the same representation but it is desirable that
- the clients uses the names library so they will not be dependent of the representation.
- The lname interface supports handling of names e.g. adding and removing name
- components.</p>
- <p>Note that the lname interface in orber does not contain a destroy function because
- the Names are represented as standard Erlang lists and therefor will be removed
- by the garbage collector when not in use.</p>
- <p>The type <c>NameComponent</c> used below is defined as:</p>
- <code type="erl">
--record('CosNaming_NameComponent', {id, kind=""}).
- </code>
- <p><c>id</c> and <c>kind</c> are strings. </p>
- <p>The record is defined in the file <c>CosNaming.hrl</c> and it
- is included with:</p>
- <code type="erl">
--include_lib("orber/COSS/CosNaming/CosNaming.hrl").
- </code>
- </description>
- <funcs>
- <func>
- <name>create() -> Return</name>
- <fsummary>Create a new name</fsummary>
- <type>
- <v>Return = [NameComponent]</v>
- </type>
- <desc>
- <p>This function returns a new name.</p>
- </desc>
- </func>
- <func>
- <name>insert_component(Name, N, NameComponent) -> Return</name>
- <fsummary>Insert a new name component in a name</fsummary>
- <type>
- <v>Name = [NameComponent]</v>
- <v>N = int()</v>
- <v>Return = Name</v>
- </type>
- <desc>
- <p>This function returns a name where the new name component has been inserted as
- component <c>N</c> in Name.</p>
- </desc>
- </func>
- <func>
- <name>get_component(Name, N) -> Return</name>
- <fsummary>Get a name component from a name</fsummary>
- <type>
- <v>Name = [NameComponent]</v>
- <v>N = int()</v>
- <v>Return = NameComponent</v>
- </type>
- <desc>
- <p>This function returns the <c>N:th</c> name component in Name.</p>
- </desc>
- </func>
- <func>
- <name>delete_component(Name, N) -> Return</name>
- <fsummary>Delete a name component from a name</fsummary>
- <type>
- <v>Name = [NameComponent]</v>
- <v>N = int()</v>
- <v>Return = Name</v>
- </type>
- <desc>
- <p>This function deletes the <c>N:th</c> name component from Name and returns
- the new name.</p>
- </desc>
- </func>
- <func>
- <name>num_component(Name) -> Return</name>
- <fsummary>Count the number of name components in a name</fsummary>
- <type>
- <v>Name = [NameComponent]</v>
- <v>Return = int()</v>
- </type>
- <desc>
- <p>This function returns a the number of name components in Name.</p>
- </desc>
- </func>
- <func>
- <name>equal(Name1, Name2) -> Return</name>
- <fsummary>Test if two names are equal</fsummary>
- <type>
- <v>Name1 = Name2 = [NameComponent]</v>
- <v>Return = bool()</v>
- </type>
- <desc>
- <p>This function returns true if the two names are equal and false otherwise.</p>
- </desc>
- </func>
- <func>
- <name>less_than(Name1, Name2) -> Return</name>
- <fsummary>Test if one name is lesser than the other</fsummary>
- <type>
- <v>Name1 = Name2 = [NameComponent]</v>
- <v>Return = bool()</v>
- </type>
- <desc>
- <p>This function returns true if Name1 are lesser than Name2 and false otherwise.</p>
- </desc>
- </func>
- <func>
- <name>to_idl_form(Name) -> Return</name>
- <fsummary>Transform a pseudo name to an IDL name</fsummary>
- <type>
- <v>Name = [NameComponent]</v>
- <v>Return = Name</v>
- </type>
- <desc>
- <p>This function just checks if Name is a correct IDL name before returning it
- because the name representation is the same for pseudo and IDL names in orber.</p>
- </desc>
- </func>
- <func>
- <name>from_idl_form(Name) -> Return</name>
- <fsummary>Transform an IDL name to a pseudo name</fsummary>
- <type>
- <v>Name = [NameComponent]</v>
- <v>Return = Name</v>
- </type>
- <desc>
- <p>This function just returns the Name because the name representation is the
- same for pseudo and IDL names in orber.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/orber/doc/src/lname_component.xml b/lib/orber/doc/src/lname_component.xml
deleted file mode 100644
index 8b8001c0fb..0000000000
--- a/lib/orber/doc/src/lname_component.xml
+++ /dev/null
@@ -1,113 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1997</year><year>2017</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>lname_component</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>1997-06-10</date>
- <rev>A</rev>
- </header>
- <module>lname_component</module>
- <modulesummary>Interface that supports the name pseudo-objects.</modulesummary>
- <description>
- <p>This interface is a part of the name library, which is used to hide the
- representation of names. In Orbers Erlang mapping the pseudo-object names
- and the real IDL names have the same representation but it is desirable that
- the clients uses the names library so they will not be dependent of the representation.
- The lname_component interface supports handling of name components e.g. set and get
- of the struct members.</p>
- <p>Note that the lname_component interface in orber does not contain a destroy
- function because the NameComponents are represented as Erlang records and
- therefor will be removed by the garbage collector when not in use.</p>
- <p>The type <c>NameComponent</c> used below is defined as:</p>
- <code type="erl">
--record('CosNaming_NameComponent', {id, kind=""}).
- </code>
- <p><c>id</c> and <c>kind</c> are strings. </p>
- <p>The record is defined in the file <c>CosNaming.hrl</c> and it
- is included with:</p>
- <code type="erl">
--include_lib("orber/COSS/CosNaming/CosNaming.hrl").
- </code>
- </description>
- <funcs>
- <func>
- <name>create() -> Return</name>
- <fsummary>Create a new name component</fsummary>
- <type>
- <v>Return = NameComponent</v>
- </type>
- <desc>
- <p>This function returns a new name component.</p>
- </desc>
- </func>
- <func>
- <name>get_id(NameComponent) -> Return</name>
- <fsummary>Get the id field of a name component</fsummary>
- <type>
- <v>Return = string()</v>
- </type>
- <desc>
- <p>This function returns the id string of a name component.</p>
- </desc>
- </func>
- <func>
- <name>set_id(NameComponent, Id) -> Return</name>
- <fsummary>Set the id field of a name component</fsummary>
- <type>
- <v>Id = string()</v>
- <v>Return = NameComponent</v>
- </type>
- <desc>
- <p>This function sets the id string of a name component and returns the component.</p>
- </desc>
- </func>
- <func>
- <name>get_kind(NameComponent) -> Return</name>
- <fsummary>Get the kind field of a name component</fsummary>
- <type>
- <v>Return = string()</v>
- </type>
- <desc>
- <p>This function returns the id string of a name component.</p>
- </desc>
- </func>
- <func>
- <name>set_kind(NameComponent, Kind) -> Return</name>
- <fsummary>Set the kind field of a name component</fsummary>
- <type>
- <v>Kind = string()</v>
- <v>Return = NameComponent</v>
- </type>
- <desc>
- <p>This function sets the kind string of a name component and returns the component.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/orber/doc/src/menuframe.gif b/lib/orber/doc/src/menuframe.gif
deleted file mode 100644
index 57a437e6b0..0000000000
--- a/lib/orber/doc/src/menuframe.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/name.gif b/lib/orber/doc/src/name.gif
deleted file mode 100644
index d2df460092..0000000000
--- a/lib/orber/doc/src/name.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/notes.xml b/lib/orber/doc/src/notes.xml
deleted file mode 100644
index 35da4f73da..0000000000
--- a/lib/orber/doc/src/notes.xml
+++ /dev/null
@@ -1,860 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>1997</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Orber Release Notes</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>99-02-12</date>
- <rev>A</rev>
- <file>notes.xml</file>
- </header>
-
- <section><title>Orber 3.8.4</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> Removed all old unused files in the documentation.
- </p>
- <p>
- Own Id: OTP-14475 Aux Id: ERL-409, PR-1493 </p>
- </item>
- <item>
- <p> Removed the man warnings by using the code tag
- instead of c tag. </p>
- <p>
- Own Id: OTP-14673</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Orber 3.8.3</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Fix some dialyzer warnings</p>
- <p>
- Own Id: OTP-14006</p>
- </item>
- </list>
- </section>
-
- </section>
-
- <section><title>Orber 3.8.2</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Internal changes</p>
- <p>
- Own Id: OTP-13551</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Orber 3.8.1</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> Suppress Dialyzer warnings. </p>
- <p>
- Own Id: OTP-12862</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Orber 3.8</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> Remove the usage of erlang:now() from all Corba
- applications and use the new rand module instead of
- random. </p>
- <p>
- Own Id: OTP-12687</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Orber 3.7.1</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> Fixed problem with IPv6 addresses in Service Context
- when orber is default configured for IPv4. </p>
- <p>
- Own Id: OTP-12193</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Orber 3.7</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> The following functions have been corrected so they
- work properly with IPv6 addresses. </p> <list>
- <item><c>corba:resolve_initial_references_remote/2/3</c></item>
- <item><c>corba:list_initial_references_remote/1/2</c></item>
- <item><c>corba:string_to_object/1/2</c></item> </list>
- <p>
- Own Id: OTP-12016</p>
- </item>
- <item>
- <p> A couple of macros were malformed, missing commas:
- PROFILEBODY_1_1_TYPEDEF and PROFILEBODY_1_2_TYPEDEF.
- Thanks to Vlad Dumitrescu. </p>
- <p>
- Own Id: OTP-12062</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> It is now possible to add listen interfaces for IPv6
- when orber is default configured for IPv4 and the other
- way around. For more information, consult the User's
- Guide and the orber module Reference Manual. </p>
- <p>
- Own Id: OTP-12007</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Orber 3.6.27</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Some local implementations of removing the last element
- from a list are replaced by <c>lists:droplast/1</c>. Note
- that this requires at least <c>stdlib-2.0</c>, which is
- the stdlib version delivered in OTP 17.0. (Thanks to Hans
- Svensson)</p>
- <p>
- Own Id: OTP-11678</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Orber 3.6.26.1</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> Postscript files no longer needed for the generation
- of PDF files have been removed. </p>
- <p>
- Own Id: OTP-11016</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Orber 3.6.26</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Fix bug in corbaloc/corbaname over ssl.</p>
- <p>
- Own Id: OTP-10675</p>
- </item>
- </list>
- </section>
-
- </section>
-
- <section><title>Orber 3.6.25</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> Some examples overflowing the width of PDF pages have
- been corrected. </p>
- <p>
- Own Id: OTP-10665</p>
- </item>
- </list>
- </section>
-
- <section><title>Known Bugs and Problems</title>
- <list>
- <item>
- <p>
- Own Id: OTP-10675 Aux Id: seq12154
- </p>
- </item>
- </list>
- </section>
-</section>
-
-<section><title>Orber 3.6.24</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Fix number of arguments in orber dbg printout</p>
- <p>
- Own Id: OTP-9887</p>
- </item>
- <item>
- <p> The descriptions of <c>ssl_server_options</c> and
- <c>ssl_client_options</c> are corrected.<br/> Seq. Id:
- seq12018 </p>
- <p>
- Own Id: OTP-9966 Aux Id: OTP-9773 </p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Orber 3.6.23</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> Remove usage of ssl:seed/1 in orber test cases. </p>
- <p>
- Own Id: OTP-9728</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>Erlang/OTP can now be built using parallel make if you
- limit the number of jobs, for instance using '<c>make
- -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not
- work at the moment because of some missing
- dependencies.</p>
- <p>
- Own Id: OTP-9451</p>
- </item>
- <item>
- <p> The SSL option handling has been changed. There are
- now two new orber options <c>ssl_server_options</c> and
- <c>ssl_client_options</c> which takes a list of options
- to the socket. </p> <p> The old options are now
- deprecated and removed from the documentation but they
- can still be used for backward compatibility as long as
- the two new options not are used. </p> <p> If
- <c>ssl_server_options</c> and <c>ssl_client_options</c>
- contain an TCP option that <c>orber</c> needs to set to a
- specific value it will be skipped and a warning will be
- written to the error_log. </p>
- <p>
- Own Id: OTP-9773 Aux Id: seq11932 </p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Orber 3.6.22</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> XML files have been corrected. </p>
- <p>
- Own Id: OTP-9550 Aux Id: OTP-9541 </p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section>
- <title>Orber 3.6.21</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- Eliminated Dialyzer warnings.</p>
- <p>
- Own Id: OTP-9326 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Orber 3.6.20</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- Eliminated Dialyzer warnings when using exit or throw.</p>
- <p>
- Own Id: OTP-9050 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Orber 3.6.19</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- Partial support for recursive structs and unions.
- Only available for the erl_corba backend and requires
- that Light IFR is used. I.e. the IC option {light_ifr, true}
- and that Orber is configured in such a way that Light IFR
- is activated. Recursive TypeCode is currently not supported.</p>
- <p>
- Own Id: OTP-8868 Aux Id: seq11633</p>
- </item>
- </list>
- </section>
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>The SSL option {ssl_imp, old} was not used if ssl_generation was
- set to 2. Only R14B was affected by this.</p>
- <p>Own Id: OTP-8994 Aux Id: seq11747</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Orber 3.6.18</title>
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>A corbaloc http string could return an EXIT message, instead
- of a system exception, if the HTTP server closed the socket
- without returning a complete message. I.e. header and a body
- containing a stringified IOR.</p>
- <p>Own Id: OTP-8900 Aux Id: seq11704</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Orber 3.6.17</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- Eliminated warnings for auto-imported BIF clashes.</p>
- <p>
- Own Id: OTP-8840</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Orber 3.6.16</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- Test suites published.</p>
- <p>
- Own Id: OTP-8543O Aux Id:</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>Added missing trailing bracket to define in hrl-file.</p>
- <p>Own Id: OTP-8489 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Orber 3.6.15</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- Added the configuration parameters iiop_out_ports_attempts and
- iiop_out_ports_random.</p>
- <p>
- Own Id: OTP-8448 Aux Id: seq11498</p>
- </item>
- <item>
- <p>
- Removed obsolete SSL dependency.</p>
- <p>
- Own Id: OTP-8374 Aux Id:</p>
- </item>
- <item>
- <p>
- Removed the usage of the codeinclude tag in the documentation.</p>
- <p>
- Own Id: OTP-8409 Aux Id:</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>Removed superfluous VT in the documentation.</p>
- <p>Own Id: OTP-8353 Aux Id:</p>
- </item>
- <item>
- <p>Removed superfluous backslash in the documentation.</p>
- <p>Own Id: OTP-8354 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Orber 3.6.14</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>
- The documentation is now built with open source tools (xsltproc and fop)
- that exists on most platforms. One visible change is that the frames are removed.</p>
- <p>
- Own Id: OTP-8201 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Orber 3.6.13</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Obsolete guards, e.g. record vs is_record, has been changed
- to avoid compiler warnings.</p>
- <p>Own Id: OTP-7987</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Orber 3.6.12</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Only the source instance of InitialReference.java is now
- included. Users are adviced to use the Interoperable
- Naming Service (INS) instead. INS is a part of the OMG
- standard specification.</p>
- <p>*** POTENTIAL INCOMPATIBILITY ***</p>
- <p>Own Id: OTP-7906 Aux Id: seq11243</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Orber 3.6.11</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Updated file headers.</p>
- <p>Own Id: OTP-7837</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Orber 3.6.10</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Documentation source included in open source releases.</p>
- <p>Own Id: OTP-7595</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Orber 3.6.9</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Updated file headers.</p>
- <p>Own Id: OTP-7011</p>
- </item>
- <item>
- <p>Now compliant with the new behavior of stdlib.</p>
- <p>Own Id: OTP-7030 Aux Id: seq10827</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Orber 3.6.8</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>When a local port range has been defined (i.e. iiop_out_ports),
- Orber set the socket option reuseaddr to true and after one
- timed out connection attempt no other port in the given range
- is used for that particular connect attempt.</p>
- <p>Own Id: OTP-6844 Aux Id: </p>
- </item>
- <item>
- <p>Possible to override global SSL parameters when using
- local interfaces.</p>
- <p>Own Id: OTP-6869 Aux Id: seq10742</p>
- </item>
- </list>
- </section>
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>The parameter ssl_client_ciphers was used on the server side as well
- instead of ssl_server_ciphers.</p>
- <p>Own Id: OTP-6868 Aux Id:</p>
- </item>
- <item>
- <p>The configuration parameter iiop_max_in_requests was ignored, until
- the first incoming request arrived, if iiop_packet_size was set.</p>
- <p>Own Id: OTP-6912 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Orber 3.6.7</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>The documentation source has been converted from SGML to XML.</p>
- <p>Own Id: OTP-6754 Aux Id: </p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Orber 3.6.6</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>It is now possible to configure incoming connections which
- overrides some global configuration parameters. See
- orber:add_listen_interface/2/3.</p>
- <p>Own Id: OTP-6696 Aux Id: </p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Orber 3.6.5</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Removed some unused code.</p>
- <p>Own Id: OTP-6527 Aux Id: </p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Orber 3.6.4</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Orber can now be configured so that different NAT parameters
- can be specified for different interfaces.</p>
- <p>Own Id: OTP-6165 Aux Id: </p>
- </item>
- <item>
- <p>It is now possible to set the keepalive option for incoming
- and outgoing IIOP connections. For more information, see the
- Configuration chapter in the User's Guide.</p>
- <p>Own Id: OTP-6370 Aux Id: seq10532</p>
- </item>
- <item>
- <p>The new function orber:close_connection/1/2 allows a client
- to close connections to an object residing on a remote ORB.</p>
- <p>Own Id: OTP-6371 Aux Id: seq10532</p>
- </item>
- <item>
- <p>Orber now use the SSL two-phase accept strategy to avoid
- that new incoming connections via SSL are not blocked
- by a previous connect attempt that never initiated the
- SSL handshake. Note, the configuration parameter
- iiop_ssl_accept_timeout should be set (default infinity).
- For more information, see the Configuration chapter in the
- User's Guide. If Orber is started in secure mode, the
- installed SSL version must support ssl:ssl_accept/1/2 and
- ssl:transport_accept/1/2.</p>
- <p>Own Id: OTP-6372 Aux Id: seq10105</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>The operation orber_ifr:contents/2 could only handle dk_All.</p>
- <p>Own Id: OTP-6385 Aux Id:</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Orber 3.6.3</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>When installing Orber it is now possible to set the priority
- for Orber internal Mnesia tables. For more information, see the
- Reference Manual regarding orber:install/2.</p>
- <p>Own Id: OTP-5907 Aux Id: seq10156</p>
- </item>
- <item>
- <p>The operation corba_object:is_a/2/3 now only connect to a remote
- ORB if necessary (i.e. the target object inherits from objects
- associated with the given IFR id).</p>
- <p>Own Id: OTP-5908</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>The operation corba_object:is_remote/1 always returned
- true, which was introduced in orber-3.2.10.</p>
- <p>Own Id: OTP-5909</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Orber 3.6.2</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Native interceptors may now export new_in_connection and
- new_out_connection operations with arity 5. If this is the
- case, information about the local interface and port is
- passed to the interceptor. Orber's built in interceptors
- have been changed to include this information as well.</p>
- <p>Own Id: OTP-5671</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>In some cases, e.g. incorrect GIOP headers or a CancelRequest
- containing a non-existing RequestId, the incoming connection
- would be terminated.</p>
- <p>Own Id: OTP-5672 Aux Id: seq10037</p>
- </item>
- <item>
- <p>If combining the 'Use Current Interface in IOR' and
- 'Use IPv6' flags, exported IOR:s contained an incorrect
- host address.</p>
- <p>Own Id: OTP-5673</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Orber 3.6.1</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Reduced overhead when using outgoing ACL with a local interface
- defined.</p>
- <p>Own Id: OTP-5659</p>
- </item>
- <item>
- <p>Added guards to ensure that, when so required, a list
- of IOP_ServiceContext's is passed instead of, for example,
- just the context record.</p>
- <p>Own Id: OTP-5660</p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>The documentation referred to two different context definitions,
- the incorrect ServiceContext and the correct IOP_ServiceContext.
- The hrl file PATH/include/corba.hrl also contained the incorrect
- record definition. This has now been updated so that only
- IOP_ServiceContext is used and referred to.</p>
- <p>Own Id: OTP-5658</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Orber 3.6</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>It is now possible to define a Access Control List (ACL),
- which limits the host and ports Orber may connect to or
- accept connections from.</p>
- <p>Own Id: OTP-5567</p>
- </item>
- <item>
- <p>It is now possible to add, and remove, listen interfaces.
- For more information, consult the User's Guide and the
- orber module Reference Manual.</p>
- <p>Own Id: OTP-5568</p>
- </item>
- <item>
- <p>It is now possible to activate and deactivate Audit/Trail
- logging. One of the three built in interceptors will be used
- depending on the requested verbosity.</p>
- <p>Own Id: OTP-5569</p>
- </item>
- <item>
- <p>It is now possible to configure Orber to add the interface,
- to exported local IOR:s, a Request came via.</p>
- <p>Own Id: OTP-5570</p>
- </item>
- <item>
- <p>It is now possible to instruct Orber which local interface an outgoing Request
- shall be sent via. To accomplish this the Orber generic context must be
- added added to each invocation.</p>
- <p>Own Id: OTP-5571</p>
- </item>
- <item>
- <p>It is now possible to define a default local interface,
- which Orber will use when connecting to another ORB.</p>
- <p>Own Id: OTP-5583</p>
- </item>
- </list>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/orber/doc/src/orber.xml b/lib/orber/doc/src/orber.xml
deleted file mode 100644
index d8c6936515..0000000000
--- a/lib/orber/doc/src/orber.xml
+++ /dev/null
@@ -1,653 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1997</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>orber</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>1997-06-10</date>
- <rev>A</rev>
- </header>
- <module>orber</module>
- <modulesummary>The main module of the Orber application</modulesummary>
- <description>
- <p>This module contains the functions for starting and stopping the
- application. It also has some utility functions to get some of
- the configuration information from running application.</p>
- </description>
- <funcs>
- <func>
- <name>start() -> ok</name>
- <name>start(Type) -> ok</name>
- <fsummary>Start the Orber application</fsummary>
- <type>
- <v>Type = temporary | permanent</v>
- </type>
- <desc>
- <p>Starts the Orber application (it also starts mnesia if it is not running).
- Which <c>Type</c> parameter is supplied determines the behavior. If not
- supplied Orber is started as <c>temporary</c>.
- See the Reference Manual <em>application(3)</em> for further information. </p>
- </desc>
- </func>
- <func>
- <name>jump_start(Attributes) -> ok | {'EXIT', Reason}</name>
- <fsummary>Start the Orber application during tests</fsummary>
- <type>
- <v>Attributes = Port | Options</v>
- <v>Port = integer()</v>
- <v>Options = [{Key, Value}]</v>
- <v>Key = any key listed in the configuration chapter</v>
- <v>Value = allowed value associated with the given key</v>
- </type>
- <desc>
- <p>Installs and starts the Orber and the Mnesia applications with the configuration
- parameters <c>domain</c> and <c>iiop_port</c> set to <c>"IP-number:Port"</c>
- and the supplied Port respectively. Theses settings are in most cases
- sufficient to ensure that no clash with any other Orber instance occur.
- If this operation fails, check if the listen port (iiop_port) is already
- in use. This function <em>MAY ONLY</em> be used during development and
- tests; how Orber is configured when using this operation may change
- at any time without warning.</p>
- </desc>
- </func>
- <func>
- <name>stop() -> ok</name>
- <fsummary>Stop the Orber application</fsummary>
- <desc>
- <p>Stops the Orber application.</p>
- </desc>
- </func>
- <func>
- <name>info() -> ok</name>
- <name>info(IoType) -> ok | {'EXIT', Reason} | string()</name>
- <fsummary>Generate Info Report, which contain Orber's configuration settings</fsummary>
- <type>
- <v>IoType = info_msg | string | io | {io, IoDevice}</v>
- </type>
- <desc>
- <p>Generates an Info Report, which contain Orber's configuration settings.
- If no <c>IoType</c> is supplied, <c>info_msg</c> is used (see the
- error_logger documentation). When the atom string is supplied this
- function will return a flat list. For <c>io</c> and <c>{io, IoDevice}</c>,
- <c>io:format/1</c> and <c>io:format/3</c> is used respectively.</p>
- </desc>
- </func>
- <func>
- <name>exception_info(Exception) -> {ok, string()} | {error, Reason}</name>
- <fsummary>Return a printable string, which describes the supplied exception</fsummary>
- <desc>
- <p>Returns a printable string, which describes the supplied exception
- in greater detail. Note, this function is mainly intended for
- system exceptions.</p>
- </desc>
- </func>
- <func>
- <name>is_system_exception(Exception) -> true | false</name>
- <fsummary>Return true if the supplied exception is a system defined exception otherwise false</fsummary>
- <desc>
- <p>Returns true if the supplied exception is a system defined
- exception, otherwise false.</p>
- </desc>
- </func>
- <func>
- <name>get_tables() -> [Tables]</name>
- <fsummary>Get the Mnesia tables Orber uses.</fsummary>
- <desc>
- <p>Returns a list of the Orber specific Mnesia tables. This list is
- required to restore Mnesia if it has been partitioned.</p>
- </desc>
- </func>
- <func>
- <name>get_ORBInitRef() -> string() | undefined</name>
- <fsummary>Get the initial reference address.</fsummary>
- <desc>
- <p>This function returns undefined if we will resolve references locally,
- otherwise a string describing which host we will contact if the Key given
- to <c>corba:resolve_initial_references/1</c> matches the Key set
- in this configuration variable. For more information
- see the user's guide.</p>
- </desc>
- </func>
- <func>
- <name>get_ORBDefaultInitRef() -> string() | undefined</name>
- <fsummary>Get the initial reference address.</fsummary>
- <desc>
- <p>This function returns undefined if we will resolve references locally,
- otherwise a string describing which host, or hosts, from which we
- will try to resolve the Key given to
- <c>corba:resolve_initial_references/1</c>. For more information
- see the user's guide.</p>
- </desc>
- </func>
- <func>
- <name>domain() -> string()</name>
- <fsummary>Display the Orber domain name</fsummary>
- <desc>
- <p>This function returns the domain name of the current Orber domain
- as a string.</p>
- </desc>
- </func>
- <func>
- <name>iiop_port() -> int()</name>
- <fsummary>Display the IIOP port number</fsummary>
- <desc>
- <p>This function returns the port-number, which is used by the IIOP
- protocol. It can be configured by setting the application variable
- <em>iiop_port</em>, if it is not set it will have the default number
- 4001.</p>
- </desc>
- </func>
- <func>
- <name>iiop_out_ports() -> 0 | {Min, Max}</name>
- <fsummary>Display the ports Orber may use when connecting to another ORB</fsummary>
- <desc>
- <p>The return value of this operation is what the configuration
- parameter <seealso marker="ch_install#config">iiop_out_ports</seealso>
- has been set to.</p>
- </desc>
- </func>
-
- <func>
- <name>iiop_out_ports_random() -> true | false</name>
- <fsummary>Determine if Orber should select local ports randomly</fsummary>
- <desc>
- <p>Return the value of the configuration parameter
- <seealso marker="ch_install#config">iiop_out_ports_random</seealso>.</p>
- </desc>
- </func>
-
- <func>
- <name>iiop_out_ports_attempts() -> int()</name>
- <fsummary>Display if Orber should accept more than one timeout connecting to another ORB</fsummary>
- <desc>
- <p>Return the value of the configuration parameter
- <seealso marker="ch_install#config">iiop_out_ports_attempts</seealso>.</p>
- </desc>
- </func>
-
-
- <func>
- <name>iiop_ssl_port() -> int()</name>
- <fsummary>Display the IIOP port number used for secure connections</fsummary>
- <desc>
- <p>This function returns the port-number, which is used by the secure IIOP
- protocol. It can be configured by setting the application variable
- <em>iiop_ssl_port</em>, if it is not set it will have the default number
- 4002 if Orber is to configured to run in secure mode. Otherwise it returns -1.</p>
- </desc>
- </func>
- <func>
- <name>iiop_timeout() -> int() (milliseconds)</name>
- <fsummary>Display the IIOP timeout value</fsummary>
- <desc>
- <p>This function returns the timeout value after which outgoing IIOP requests terminate.
- It can be configured by setting the application variable
- <em>iiop_timeout TimeVal (seconds)</em>, if it is not set it will have the default value
- <em>infinity</em>. If a request times out a system exception, e.g.
- <em>TIMEOUT</em>, is raised.</p>
- <p>Note: the iiop_timeout configuration parameter (TimeVal) may only range between 0 and 1000000 seconds.
- Otherwise, the default value is used.</p>
- <p>Note: Earlier IC versions required that the compile option <c>{timeout,"module::interface"}</c>,
- was used, which allow the user to add an extra timeout parameter, e.g.,
- <c>module_interface:function(ObjRef, Timeout, ... Arguments ...)</c> or
- <c>module_interface:function(ObjRef, [{timeout, Timeout}], ... Arguments ...)</c>,
- instead of <c>module_interface:function(ObjRef, ... Arguments ...)</c>.
- This is no longer the case and if the extra Timeout is used,
- argument will override the configuration parameter <c>iiop_timeout</c>.
- It is, however, not possible
- to use <c>infinity</c> to override the Timeout parameter. The Timeout
- option is also valid for objects which resides within the same Orber domain.</p>
- </desc>
- </func>
- <func>
- <name>iiop_connection_timeout() -> int() (milliseconds)</name>
- <fsummary>Display the IIOP connection timeout value</fsummary>
- <desc>
- <p>This function returns the timeout value after which outgoing IIOP connections terminate.
- It can be configured by setting the application variable
- <em>iiop_connection_timeout TimeVal (seconds)</em>, if it is not set it will have the default value
- <em>infinity</em>. The connection will not be terminated if there are
- pending requests.</p>
- <p>Note: the iiop_connection_timeout configuration parameter (TimeVal) may only range between 0 and 1000000 seconds.
- Otherwise, the default value is used.</p>
- </desc>
- </func>
- <func>
- <name>iiop_connections() -> Result</name>
- <name>iiop_connections(Direction) -> Result</name>
- <fsummary>List all existing connections to/from other ORB's</fsummary>
- <type>
- <v>Direction = in | out | inout</v>
- <v>Result = [{Host, Port}] | [{Host, Port, Interface}] | {'EXIT',Reason}</v>
- <v>Host = string()</v>
- <v>Port = integer()</v>
- <v>Interface = string()</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>The list returned by this operation contain tuples of remote hosts/ports
- Orber is currently connected to. If no Direction is not supplied, both
- incoming and outgoing connections are included.</p>
- <p>If a specific local interface has been defined for the connection,
- this will be added to the returned tuple.</p>
- </desc>
- </func>
- <func>
- <name>iiop_connections_pending() -> Result</name>
- <fsummary>List all connections to another ORB currently being set up</fsummary>
- <type>
- <v>Result = [{Host, Port}] | [{Host, Port, Interface}] | {'EXIT',Reason}</v>
- <v>Host = string()</v>
- <v>Port = integer()</v>
- <v>Interface = string()</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>In some cases a connection attempt (i.e. trying to communicate with
- another ORB) may block due to a number of reasons. This operation
- allows the user to check if this is the case. The returned list
- contain tuples of remote hosts/ports. Normally, the list is empty.</p>
- <p>If a specific local interface has been defined for the connection,
- this will be added to the returned tuple.</p>
- </desc>
- </func>
- <func>
- <name>iiop_in_connection_timeout() -> int() (milliseconds)</name>
- <fsummary>Display the IIOP connection timeout value for incoming connections</fsummary>
- <desc>
- <p>This function returns the timeout value after which incoming IIOP
- connections terminate. It can be configured by setting the application
- variable <em>iiop_in_connection_timeout TimeVal (seconds)</em>, if it is
- not set it will have the default value <em>infinity</em>. The connection
- will not be terminated if there are pending requests.</p>
- <p>Note: the iiop_in_connection_timeout configuration parameter (TimeVal) may
- only range between 0 and 1000000 seconds. Otherwise, the default value is
- used.</p>
- </desc>
- </func>
- <func>
- <name>iiop_acl() -> Result</name>
- <fsummary>Return the ACL configuration</fsummary>
- <type>
- <v>Result = [{Direction, Filter}] | [{Direction, Filter, [Interface]}]</v>
- <v>Direction = tcp_in | ssl_in | tcp_out | ssl_out</v>
- <v>Filter = string()</v>
- <v>Interface = string()</v>
- </type>
- <desc>
- <p>Returns the ACL configuration. The <c>Filter</c> uses a extended format of
- Classless Inter Domain Routing (CIDR). For example, <c>"123.123.123.10"</c> limits
- the connection to that particular host, while <c>"123.123.123.10/17"</c> allows
- connections to or from any host equal to the 17 most significant bits. Orber
- also allow the user to specify a certain port or port range, for example,
- <c>"123.123.123.10/17#4001"</c> and <c>"123.123.123.10/17#4001/5001"</c>
- respectively. IPv4 or none compressed IPv6 strings are accepted. <br></br>
-
- The list of <c>Interfaces</c>, IPv4 or IPv6 strings, are currently only used
- for outgoing connections and may only contain <em>one</em> address. If set and
- access is granted, Orber will use that local interface when connecting to the
- other ORB. The module <seealso marker="orber_acl">orber_acl</seealso>
- provides operations for evaluating the access control for filters and addresses.</p>
- </desc>
- </func>
- <func>
- <name>activate_audit_trail() -> Result</name>
- <name>activate_audit_trail(Verbosity) -> Result</name>
- <fsummary>Activate IIOP audit/trail</fsummary>
- <type>
- <v>Verbosity = stealth | normal | verbose</v>
- <v>Result = ok | {error, Reason}</v>
- <v>Reason = string()</v>
- </type>
- <desc>
- <p>Activates audit/trail for all existing incoming and outgoing IIOP
- connections. The <c>Verbosity</c> parameter, <c>stealth</c>,
- <c>normal</c> or <c>verbose</c>, determines which of the built in
- interceptors is used (<c>orber_iiop_tracer_stealth</c>,
- <c>orber_iiop_tracer_silent</c> or <c>orber_iiop_tracer</c> respectively).
- If no verbosity level is supplied, then the <c>normal</c> will be used.</p>
- <p>In case Orber is configured to use other interceptors, the audit/trail
- interceptors will simply be added to that list.</p>
- </desc>
- </func>
- <func>
- <name>deactivate_audit_trail() -> Result</name>
- <fsummary>Deactivate IIOP audit/trail</fsummary>
- <type>
- <v>Result = ok | {error, Reason}</v>
- <v>Reason = string()</v>
- </type>
- <desc>
- <p>Deactivates audit/trail for all existing incoming and outgoing IIOP
- connections. In case Orber is configured to use other interceptors,
- those will still be used.</p>
- </desc>
- </func>
- <func>
- <name>add_listen_interface(IP, Type) -> Result</name>
- <name>add_listen_interface(IP, Type, Port) -> Result</name>
- <name>add_listen_interface(IP, Type, ConfigurationParameters) -> Result</name>
- <fsummary>Add a new listen process for incoming connection</fsummary>
- <type>
- <v>IP = string</v>
- <v>Type = normal | ssl</v>
- <v>Port = integer() > 0</v>
- <v>ConfigurationParameters = [{Key, Value}]</v>
- <v>Key = flags | ip_family | iiop_in_connection_timeout | iiop_max_fragments | iiop_max_in_requests | interceptors | iiop_port | iiop_ssl_port | ssl_server_options</v>
- <v>Value = as described in the User's Guide or below</v>
- <v>Result = {ok, Ref} | {error, Reason} | {'EXCEPTION', #'BAD_PARAM'{}}</v>
- <v>Ref = #Ref</v>
- <v>Reason = string()</v>
- </type>
- <desc>
- <p>Create a new process that handle requests for creating a new incoming
- IIOP connection via the given interface and port. If the latter is
- excluded, Orber will use the value of the <c>iiop_port</c> or
- <c>iiop_ssl_port</c> configuration parameters.
- The <c>Type</c> parameter determines if it is
- supposed to be IIOP or IIOP via SSL. If successful, the returned
- <c>#Ref</c> shall be passed to <c>orber:remove_listen_interface/1</c>
- when the connection shall be terminated.</p>
- <p>It is also possible to supply configuration parameters that override
- the global configuration. The <em>iiop_in_connection_timeout</em>,
- <em>iiop_max_fragments</em>, <em>iiop_max_in_requests</em> and
- <em>interceptors</em> parameters simply overrides the global
- counterparts (See the
- <seealso marker="ch_install#config">Configuration</seealso> chapter
- in the User's Guide).
- But for the following parameters there are a few restrictions:</p>
- <list type="bulleted">
- <item><em>flags</em> - currently it is only possible to override the global
- setting for the <c>Use Current Interface in IOR</c> and
- <c>Exclude CodeSet Component</c> flags.</item>
- <item><em>ip_family</em> - can be set to <c>inet</c> or <c>inet6</c> and is
- used to get a listen interface that uses another IP version than the default
- set with flags at startup.</item>
- <item><em>iiop_port</em> - requires that <c>Use Current Interface in IOR</c>
- is activated and the supplied <c>Type</c> is <c>normal</c>. If so,
- exported IOR:s will contain the IIOP port defined by this configuration
- parameter. Otherwise, the global setting will be used.</item>
- <item><em>iiop_ssl_port</em> - almost equivalent to <c>iiop_port</c>.
- The difference is that <c>Type</c> shall be <c>ssl</c> and that
- exported IOR:s will contain the IIOP via SSL port defined by this configuration
- parameter.</item>
- </list>
- <p>If it is not possible to add a listener based on the supplied interface
- and port, the error message is one of the ones described in <c>inet</c>
- and/or <c>ssl</c> documentation.</p>
- </desc>
- </func>
- <func>
- <name>remove_listen_interface(Ref) -> ok</name>
- <fsummary>Terminate listen process for incoming connection</fsummary>
- <type>
- <v>Ref = #Ref</v>
- </type>
- <desc>
- <p>Terminates the listen process, associated with the supplied <c>#Ref</c>,
- for incoming a connection. The Ref parameter is the return value from
- the <c>orber:add_listen_interface/2/3</c> operation. When terminating
- the connection, all associated requests will not deliver a reply to
- the clients.</p>
- </desc>
- </func>
- <func>
- <name>close_connection(Connection) -> Result</name>
- <name>close_connection(Connection, Interface) -> Result</name>
- <fsummary>Terminate outgoing connection(s)</fsummary>
- <type>
- <v>Connection = Object | [{Host, Port}]</v>
- <v>Object = #objref (external)</v>
- <v>Host = string()</v>
- <v>Port = string()</v>
- <v>Interface = string()</v>
- <v>Result = ok | {'EXCEPTION', #'BAD_PARAM'{}}</v>
- </type>
- <desc>
- <p>Will try to close all outgoing connections to the host/port combinations
- found in the supplied object reference or the given list of hosts/ports.
- If a <c>#'IOP_ServiceContext'{}</c> containing a local interface has been
- used when communicating with the remote object
- (see also <seealso marker="Module_Interface">Module_Interface</seealso>),
- that interface shall be passed as the second argument. Otherwise, connections
- via the default local interface, will be terminated.</p>
- <p></p>
- <note>
- <p>Since several clients maybe communicates via the same connection,
- they will be affected when invoking this operation. Other clients may
- re-create the connection by invoking an operation on the target object.</p>
- </note>
- </desc>
- </func>
- <func>
- <name>secure() -> no | ssl</name>
- <fsummary>Display the security mode Orber is running in</fsummary>
- <desc>
- <p>This function returns the security mode Orber is running in, which is either no if it is an
- insecure domain or the type of security mechanism used. For the moment the only security
- mechanism is ssl. This is configured by setting the application variable
- <em>secure</em>.</p>
- </desc>
- </func>
- <func>
- <name>ssl_server_options() -> list()</name>
- <fsummary>Display the SSL server options</fsummary>
- <desc>
- <p>This function returns the list of SSL options set for the Orber domain as server.
- This is configured by setting the application variable
- <em>ssl_server_options</em>.</p>
- </desc>
- </func>
- <func>
- <name>ssl_client_options() -> list()</name>
- <fsummary>Display the SSL client options</fsummary>
- <desc>
- <p>This function returns the list of SSL options used in outgoing calls in the current process.
- The default value is configured by setting the application variable
- <em>ssl_client_options</em>.</p>
- </desc>
- </func>
- <func>
- <name>set_ssl_client_options(Options) -> ok</name>
- <fsummary>Set the SSL options for the client</fsummary>
- <type>
- <v>Options = list()</v>
- </type>
- <desc>
- <p>This function takes a list of SSL options as parameter and sets
- it for the current process.</p>
- </desc>
- </func>
- <func>
- <name>objectkeys_gc_time() -> int() (seconds)</name>
- <fsummary>Display the Object Keys GC time value</fsummary>
- <desc>
- <p>This function returns the timeout value after which after which terminated object keys,
- related to servers started with the configuration parameter <c>{persistent, true}</c>,
- will be removed.
- It can be configured by setting the application variable <em>objectkeys_gc_time TimeVal (seconds)</em>,
- if it is not set it will have the default value <em>infinity</em>. </p>
- <p>Objects terminating with reason <em>normal</em> or <em>shutdown</em> are removed automatically.</p>
- <p>Note: the objectkeys_gc_time configuration parameter (TimeVal) may only range between 0 and 1000000 seconds.
- Otherwise, the default value is used.</p>
- </desc>
- </func>
- <func>
- <name>orber_nodes() -> RetVal</name>
- <fsummary>Displays which nodes that this orber domain consist of.</fsummary>
- <type>
- <v>RetVal = [node()]</v>
- </type>
- <desc>
- <p>This function returns the list of node names that this orber
- domain consists of. </p>
- </desc>
- </func>
- <func>
- <name>install(NodeList) -> ok</name>
- <name>install(NodeList, Options) -> ok</name>
- <fsummary>Install the Orber application</fsummary>
- <type>
- <v>NodeList = [node()]</v>
- <v>Options = [Option]</v>
- <v>Option = {install_timeout, Timeout} | {ifr_storage_type, TableType} | {nameservice_storage_type, TableType} | {initialreferences_storage_type, TableType} | {load_order, Priority}</v>
- <v>Timeout = infinity | integer()</v>
- <v>TableType = disc_copies | ram_copies</v>
- <v>Priority = integer()</v>
- </type>
- <desc>
- <p>This function installs all the necessary mnesia tables and
- load default data in some of them. If one or more Orber tables
- already exists the installation fails. The function
- <em>uninstall</em> may be used, if it is safe, i.e., no other
- application is running Orber.</p>
- <p>Preconditions:</p>
- <list type="bulleted">
- <item>a mnesia schema must exist before the installation</item>
- <item>mnesia is running on the other nodes if the new installation
- shall be a multi node domain</item>
- </list>
- <p>Mnesia will be started by the function if it is not already running on
- the installation node and if it was started it will be stopped
- afterwards.</p>
- <p>The options that can be sent to the installation program is:</p>
- <list type="bulleted">
- <item><c>{install_timeout, Timeout}</c> - this timeout is how long we
- will wait for the tables to be created. The Timeout value can be
- <em>infinity</em> or an integer number in milliseconds.
- Default is infinity.</item>
- <item><c>{ifr_storage_type, TableType}</c> - this option sets the
- type of tables used for the interface repository.
- The TableType can be disc_copies or ram_copies. Default is
- disc_copies.</item>
- <item><c>{initialreferences_storage_type, TableType}</c> - this option
- sets the type of table used for storing initial references.
- The TableType can be disc_copies or ram_copies. Default is
- ram_copies.</item>
- <item><c>{nameservice_storage_type, TableType}</c> - the default
- behavior of Orber is to install the NameService as ram_copies.
- This option makes it possible to change this to disc_copies. But
- the user should be aware of that if a node is restarted, all
- local object references stored in the NameService is not valid.
- Hence, you cannot switch to disc_copies and expect exactly the same
- behavior as before.</item>
- <item><c>{load_order, Priority}</c> - per default the priority is set to 0.
- Using this option it will change the priority of in which order
- Mnesia will load Orber internal tables. For more information,
- consult the Mnesia documentation.</item>
- </list>
- </desc>
- </func>
- <func>
- <name>uninstall() -> ok</name>
- <fsummary>Uninstall the Orber application</fsummary>
- <desc>
- <p>This function stops the Orber application, terminates all server
- objects and removes all Orber related mnesia tables.</p>
- <p>Note: Since other applications may be running on the same node
- using mnesia <em>uninstall</em> will not stop the mnesia application.</p>
- </desc>
- </func>
- <func>
- <name>add_node(Node, Options) -> RetVal</name>
- <fsummary>Add a new node to a group of Orber nodes.</fsummary>
- <type>
- <v>Node = node()</v>
- <v>Options = IFRStorageType | [KeyValue] </v>
- <v>IFRStorageType = StorageType</v>
- <v>StorageType = disc_copies | ram_copies</v>
- <v>KeyValue = {ifr_storage_type, StorageType} | {initialreferences_storage_type, StorageType} | {nameservice_storage_type, StorageType} | {type, Type} </v>
- <v>Type = temporary | permanent</v>
- <v>RetVal = ok | exit()</v>
- </type>
- <desc>
- <p>This function add given node to a existing Orber node group and starts
- Orber on the new node. <c>orber:add_node</c> is called from a member in the Orber
- node group.</p>
- <p>Preconditions for new node:</p>
- <list type="bulleted">
- <item>Erlang started on the new node using the option <c>-mnesia extra_db_nodes</c>, e.g.,
- <c>erl -sname new_node_name -mnesia extra_db_nodes ConnectToNodes_List</c></item>
- <item>The new node's <c>domain</c> name is the same for the nodes we want to connect to.</item>
- <item>Mnesia is running on the new node (no new schema created).</item>
- <item>If the new node will use <c>disc_copies</c> the schema type must be changed using:
- <c>mnesia:change_table_copy_type(schema, node(), disc_copies).</c></item>
- </list>
- <p>Orber will be started by the function on the new node.</p>
- <p>Fails if:</p>
- <list type="bulleted">
- <item>Orber already installed on given node.</item>
- <item>Mnesia not started as described above on the new node.</item>
- <item>Impossible to copy data in Mnesia tables to the new node.</item>
- <item>Not able to start Orber on the new node, due to, for example, the
- <c>iiop_port</c> is already in use.</item>
- </list>
- <p>The function do not remove already copied tables after a failure.
- Use <c>orber:remove_node</c> to remove these tables.</p>
- </desc>
- </func>
- <func>
- <name>remove_node(Node) -> RetVal</name>
- <fsummary>Removes a node from a group of Orber nodes.</fsummary>
- <type>
- <v>Node = node()</v>
- <v>RetVal = ok | exit()</v>
- </type>
- <desc>
- <p>This function removes given node from a Orber node group. The Mnesia
- application is not stopped.</p>
- </desc>
- </func>
- <func>
- <name>configure(Key, Value) -> ok | {'EXIT', Reason}</name>
- <fsummary>Change Orber configuration.</fsummary>
- <type>
- <v>Key = orbDefaultInitRef | orbInitRef | giop_version | iiop_timeout | iiop_connection_timeout | iiop_setup_connection_timeout | iiop_in_connection_timeout | objectkeys_gc_time | orber_debug_level</v>
- <v>Value = allowed value associated with the given key</v>
- </type>
- <desc>
- <p>This function allows the user to configure Orber in, for example,
- an Erlang shell. It is possible to invoke <c>configure</c> at any time
- the keys specified above.</p>
- <p>Any other key must be set before installing and starting Orber.</p>
- <p>Trying to change the configuration in any other way is <em>NOT</em>
- allowed since it may affect the behavior of Orber.</p>
- <p>For more information regarding allowed values, see
- <seealso marker="ch_install#config">configuration settings</seealso>
- in the User's Guide.</p>
- <p></p>
- <note>
- <p>Configuring the IIOP timeout values will not affect already
- existing connections. If you want a guaranteed uniform behavior, you
- must set these parameters from the start.</p>
- </note>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/orber/doc/src/orber_acl.xml b/lib/orber/doc/src/orber_acl.xml
deleted file mode 100644
index 5feda83ef6..0000000000
--- a/lib/orber/doc/src/orber_acl.xml
+++ /dev/null
@@ -1,107 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2005</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>orber_acl</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>2005-05-19</date>
- <rev>A</rev>
- </header>
- <module>orber_acl</module>
- <modulesummary>Orber ACL operations</modulesummary>
- <description>
- <p>This module contains functions intended for analyzing Access
- Control List (ACL) filters. The filters uses a extended format of
- Classless Inter Domain Routing (CIDR).
- For example, <c>"123.123.123.10"</c> limits
- the connection to that particular host, while <c>"123.123.123.10/17"</c> allows
- connections to or from any host equal to the 17 most significant bits. Orber
- also allow the user to specify a certain port or port range, for example,
- <c>"123.123.123.10/17#4001"</c> and <c>"123.123.123.10/17#4001/5001"</c>
- respectively. IPv4 or none compressed IPv6 strings are accepted.</p>
- </description>
- <funcs>
- <func>
- <name>match(IP, Direction) -> boolean()</name>
- <name>match(IP, Direction, GetInfo) -> Reply</name>
- <fsummary>Verify if the IP address versus the current configuration</fsummary>
- <type>
- <v>IP = tuple() | [integer()]</v>
- <v>Direction = tcp_in | ssl_in | tcp_out | ssl_out</v>
- <v>GetInfo = boolean()</v>
- <v>Reply = boolean() | {boolean(), [Interface], PortInfo}</v>
- <v>Interface = string()</v>
- <v>PortInfo = integer() | {integer(), integer()}</v>
- </type>
- <desc>
- <p>If <c>GetInfo</c> is not supplied or set to false, this operation returns
- a boolean which tells if the IPv4 or IPv6 address would pass the ACL
- filter, defined by the <c>iiop_acl</c> configuration parameter, or not.
- When <c>GetInfo</c> is set to true, a tuple which, besides the boolean
- that tells if access was granted, also include the defined
- interfaces and port(s). This operation requires that Orber is running and
- can be used on a live node to determine if Orber has been properly configured.</p>
- </desc>
- </func>
- <func>
- <name>verify(IP, Filter, Family) -> Reply</name>
- <fsummary>Verify if the IP address versus the Filter</fsummary>
- <type>
- <v>IP = string()</v>
- <v>Filter = string()</v>
- <v>Family = inet | inet6</v>
- <v>Reply = true | {false, From, To} | {error, string()}</v>
- <v>From = string()</v>
- <v>To = string()</v>
- </type>
- <desc>
- <p>This operation returns true if the IPv4 or IPv6 address would pass the
- supplied ACL. If that is not the case, a tuple containing the accepted range
- is returned. This operation should only be used for test purposes.</p>
- </desc>
- </func>
- <func>
- <name>range(Filter, Family) -> Reply</name>
- <fsummary>Get range of Filter</fsummary>
- <type>
- <v>Filter = string()</v>
- <v>Family = inet | inet6</v>
- <v>Reply = {ok, From, To} | {error, string()}</v>
- <v>From = string()</v>
- <v>To = string()</v>
- </type>
- <desc>
- <p>Returns the range of accepted IP addresses based on the supplied filter.
- This operation should only be used for test purposes.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/orber/doc/src/orber_diagnostics.xml b/lib/orber/doc/src/orber_diagnostics.xml
deleted file mode 100644
index 3aad304535..0000000000
--- a/lib/orber/doc/src/orber_diagnostics.xml
+++ /dev/null
@@ -1,81 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2003</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>orber_diagnostics</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>2003-04-17</date>
- <rev>A</rev>
- </header>
- <module>orber_diagnostics</module>
- <modulesummary>Diagnostics API for Orber</modulesummary>
- <description>
- <p>This module contains functions which makes it possible to run simple
- tests.</p>
- <p></p>
- <warning>
- <p>Functions exported by this module may only be used during
- test and development phase.</p>
- </warning>
- </description>
- <funcs>
- <func>
- <name>nameservice() -> Result</name>
- <name>nameservice(Flags) -> Result</name>
- <fsummary>Display all objects stored in the Name Service</fsummary>
- <type>
- <v>Flags = integer()</v>
- <v>Result = ok | {'EXCEPTION', E}</v>
- </type>
- <desc>
- <p>Displays all objects stored in the NameService. Existent checks are, per
- default, also performed on all local objects. This can also be activated
- for external objects by setting the flag <c>16#01</c>. The displayed
- information is the stringified Name described in
- <seealso marker="CosNaming_NamingContextExt">CosNaming_NamingContextExt</seealso>,
- non existent status (true | false | external | undefined) and the IFR-Id:</p>
- <code type="none">
-host/
-host/resources/
-host/resources/MyObj/ [false] IDL:MyMod/MyIntf:1.0 </code>
- </desc>
- </func>
- <func>
- <name>missing_modules() -> Count</name>
- <fsummary>Echo missing modules required by Orber</fsummary>
- <type>
- <v>Count = integer()</v>
- </type>
- <desc>
- <p>This operation list missing modules generated by IC and required by
- Orber. Requires that all API:s are registered in the IFR.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/orber/doc/src/orber_ifr.xml b/lib/orber/doc/src/orber_ifr.xml
deleted file mode 100644
index a667d7d9e4..0000000000
--- a/lib/orber/doc/src/orber_ifr.xml
+++ /dev/null
@@ -1,1035 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1997</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>orber_ifr</title>
- <prepared></prepared>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>1997-10-13</date>
- <rev>A</rev>
- </header>
- <module>orber_ifr</module>
- <modulesummary>The Interface Repository stores representations of IDL information</modulesummary>
- <description>
- <p>This module contains functions for managing the Interface
- Repository (IFR). This documentation should be used in conjunction
- with the documentation in chapter 6 of <term id="CORBA"></term>2.3.
- Whenever the term IFR object is used in this manual page, it
- refers to a pseudo object used only for interaction with the IFR
- rather than a CORBA object.</p>
- </description>
-
- <section>
- <title>Initialization of the IFR</title>
- <p>The following functions are used to initialize the Interface
- Repository and to obtain the initial reference to the
- repository.</p>
- </section>
- <funcs>
- <func>
- <name>init(Nodes,Timeout) -> ok</name>
- <fsummary>Intialize the IFR</fsummary>
- <type>
- <v>Nodes = list()</v>
- <v>Timeout = integer() | infinity</v>
- </type>
- <desc>
- <p>This function should be called to initialize the IFR. It
- creates the necessary mnesia-tables. A mnesia schema should
- exist, and mnesia must be running.</p>
- </desc>
- </func>
- <func>
- <name>find_repository() -> #IFR_Repository_objref</name>
- <fsummary>Find the IFR object reference for the Repository</fsummary>
- <desc>
- <p>Find the IFR object reference for the Repository. This
- reference should be used when adding objects to the IFR, and
- when extracting information from the IFR.
- The first time this function is called, it will create the
- repository and all the primitive definitions.</p>
- </desc>
- </func>
- </funcs>
-
- <section>
- <title>General methods</title>
- <p>The following functions are the methods of the IFR. The first
- argument is always an #IFR_objref, i.e. the IFR (pseudo)object
- on which to apply this method. These functions are useful when
- the type of IFR object is not know, but they are somewhat slower
- than the specific functions listed below which only accept a
- particular type of IFR object as the first argument.</p>
- </section>
- <funcs>
- <func>
- <name>get_def_kind(Objref) -> Return</name>
- <fsummary>Return the definition kind of the IFR object</fsummary>
- <type>
- <v>Objref = #IFR_objref</v>
- <v>Return = atom() (one of dk_none, dk_all, dk_Attribute, dk_Constant, dk_Exception, dk_Interface, dk_Module, dk_Operation, dk_Typedef, dk_Alias, dk_Struct, dk_Union, dk_Enum, dk_Primitive, dk_String, dk_Wstring, dk_Fixed, dk_Sequence, dk_Array, dk_Repository)</v>
- </type>
- <desc>
- <p>Objref is an IFR object of any kind. Returns the definition
- kind of the IFR object.</p>
- </desc>
- </func>
- <func>
- <name>destroy(Objref) -> Return</name>
- <fsummary>Destroy, except IRObject, Contained and Container, target object and its contents</fsummary>
- <type>
- <v>Objref = #IFR_object</v>
- <v>Return = tuple()</v>
- </type>
- <desc>
- <p>Objref is an IFR object of any kind except IRObject,
- Contained and Container. Destroys that object and its
- contents (if any). Returns whatever mnesia:transaction
- returns.</p>
- </desc>
- </func>
- <func>
- <name>get_id(Objref) -> Return</name>
- <fsummary>Return the target object's repository id</fsummary>
- <type>
- <v>Objref = #IFR_object</v>
- <v>Return = string()</v>
- </type>
- <desc>
- <p>Objref is an IFR object of any kind that inherits from
- Contained. Returns the repository id of that object.</p>
- </desc>
- </func>
- <func>
- <name>set_id(Objref,Id) -> ok</name>
- <fsummary>Set the target object's repository id</fsummary>
- <type>
- <v>Objref = #IFR_object</v>
- <v>Id = string()</v>
- </type>
- <desc>
- <p>Objref is an IFR object of any kind that inherits from
- Contained. Sets the repository id of that object.</p>
- </desc>
- </func>
- <func>
- <name>get_name(Objref) -> Return</name>
- <fsummary>Return the name of the target object</fsummary>
- <type>
- <v>Objref = #IFR_object</v>
- <v>Return = string()</v>
- </type>
- <desc>
- <p>Objref is an IFR object of any kind that inherits from
- Contained. Returns the name of that object.</p>
- </desc>
- </func>
- <func>
- <name>set_name(Objref,Name) -> ok</name>
- <fsummary>Set given name to target object</fsummary>
- <type>
- <v>Objref = #IFR_object</v>
- <v>Name = string()</v>
- </type>
- <desc>
- <p>Objref is an IFR object of any kind that inherits from
- Contained. Sets the name of that object.</p>
- </desc>
- </func>
- <func>
- <name>get_version(Objref) -> Return</name>
- <fsummary>Return the version of the target object</fsummary>
- <type>
- <v>Objref = #IFR_object</v>
- <v>Return = string()</v>
- </type>
- <desc>
- <p>Objref is an IFR object of any kind that inherits from
- Contained. Returns the version of that object.</p>
- </desc>
- </func>
- <func>
- <name>set_version(Objref,Version) -> ok</name>
- <fsummary>Set given version of the target object</fsummary>
- <type>
- <v>Objref = #IFR_object</v>
- <v>Version = string()</v>
- </type>
- <desc>
- <p>Objref is an IFR object of any kind that inherits from
- Contained. Sets the version of that object.</p>
- </desc>
- </func>
- <func>
- <name>get_defined_in(Objref) -> Return</name>
- <fsummary>Return the Container the target object is contained in</fsummary>
- <type>
- <v>Objref = #IFR_object</v>
- <v>Return = #IFR_Container_objref</v>
- </type>
- <desc>
- <p>Objref is an IFR object of any kind that inherits from
- Contained. Returns the Container object that the object is
- defined in.</p>
- </desc>
- </func>
- <func>
- <name>get_absolute_name(Objref) -> Return</name>
- <fsummary>Return the absolute name of the target object</fsummary>
- <type>
- <v>Objref = #IFR_object</v>
- <v>Return = string()</v>
- </type>
- <desc>
- <p>Objref is an IFR object of any kind that inherits from
- Contained. Returns the absolute (scoped) name of that
- object.</p>
- </desc>
- </func>
- <func>
- <name>get_containing_repository(Objref) -> Return</name>
- <fsummary>Get the most derived Contained object associated with the target object</fsummary>
- <type>
- <v>Objref = #IFR_object</v>
- <v>Return = #IFR_Repository_objref</v>
- </type>
- <desc>
- <p>Objref is an IFR object of any kind that inherits from
- Contained. Returns the Repository that is eventually reached
- by recursively following the object's defined_in attribute.</p>
- </desc>
- </func>
- <func>
- <name>describe(Objref) -> Return</name>
- <fsummary>Return a tuple which describe the target object</fsummary>
- <type>
- <v>Objref = #IFR_object</v>
- <v>Return = tuple() (a contained_description record) | {exception, _}</v>
- </type>
- <desc>
- <p>Objref is an IFR object of any kind that inherits from
- Contained. Returns a tuple describing the object.</p>
- </desc>
- </func>
- <func>
- <name>move(Objref,New_container,New_name,New_version) -> Return</name>
- <fsummary>Move the target object from its current location to given Container, name and version</fsummary>
- <type>
- <v>Objref = #IFR_objref</v>
- <v>New_container = #IFR_Container_objref</v>
- <v>New_name = string()</v>
- <v>New_version = string()</v>
- <v>Return = ok | {exception, _}</v>
- </type>
- <desc>
- <p>Objref is an IFR object of any kind that inherits from
- Contained. New_container is an IFR object of any kind that
- inherits from Container. Removes Objref from its current
- Container, and adds it to New_container. The name attribute
- is changed to New_name and the version attribute is changed
- to New_version.</p>
- </desc>
- </func>
- <func>
- <name>lookup(Objref,Search_name) -> Return</name>
- <fsummary>Return the IFR object identified by the given name</fsummary>
- <type>
- <v>Objref = #IFR_objref</v>
- <v>Search_name = string()</v>
- <v>Return = #IFR_object</v>
- </type>
- <desc>
- <p>Objref is an IFR object of any kind that inherits from
- Container. Returns an IFR object identified by search_name
- (a scoped name).</p>
- </desc>
- </func>
- <func>
- <name>contents(Objref,Limit_type,Exclude_inherited) -> Return</name>
- <fsummary>Return the content of the target object limited by the given constraints</fsummary>
- <type>
- <v>Objref = #IFR_objref</v>
- <v>Limit_type = atom() (one of dk_none, dk_all, dk_Attribute, dk_Constant, dk_Exception, dk_Interface, dk_Module, dk_Operation, dk_Typedef, dk_Alias, dk_Struct, dk_Union, dk_Enum, dk_Primitive, dk_String, dk_Wstring, dk_Fixed, dk_Sequence, dk_Array, dk_Repository)</v>
- <v>Exclude_inherited = atom() (true or false)</v>
- <v>Return = list() (a list of IFR#_objects)</v>
- </type>
- <desc>
- <p>Objref is an IFR object of any kind that inherits from
- Container. Returns the contents of that IFR object.</p>
- </desc>
- </func>
- <func>
- <name>lookup_name(Objref,Search_name,Levels_to_search, Limit_type, Exclude_inherited) -> Return</name>
- <fsummary>Return a list of IFR objects matching the given name</fsummary>
- <type>
- <v>Objref = #IFR_objref</v>
- <v>Search_name = string()</v>
- <v>Levels_to_search = integer()</v>
- <v>Limit_type = atom() (one of dk_none, dk_all, dk_Attribute, dk_Constant, dk_Exception, dk_Interface, dk_Module, dk_Operation, dk_Typedef, dk_Alias, dk_Struct, dk_Union, dk_Enum, dk_Primitive, dk_String, dk_Wstring, dk_Fixed, dk_Sequence, dk_Array, dk_Repository)</v>
- <v>Exclude_inherited = atom() (true or false)</v>
- <v>Return = list() (a list of #IFR_objects)</v>
- </type>
- <desc>
- <p>Objref is an IFR object of any kind that inherits from
- Container. Returns a list of #IFR_objects with an id
- matching Search_name.</p>
- </desc>
- </func>
- <func>
- <name>describe_contents(Objref, Limit_type, Exclude_inherited, Max_returned_objs) -> Return</name>
- <fsummary>Return a list of descriptions of the IFR objects contained by the target Container object</fsummary>
- <type>
- <v>Objref = #IFR_objref</v>
- <v>Limit_type = atom() (one of dk_none, dk_all, dk_Attribute, dk_Constant, dk_Exception, dk_Interface, dk_Module, dk_Operation, dk_Typedef, dk_Alias, dk_Struct, dk_Union, dk_Enum, dk_Primitive, dk_String, dk_Wstring, dk_Fixed, dk_Sequence, dk_Array, dk_Repository)</v>
- <v>Exclude_inherited = atom() (true or false)</v>
- <v>Return = list() (a list of tuples (contained_description records) | {exception, _}</v>
- </type>
- <desc>
- <p>Objref is an IFR object of any kind that inherits from
- Container. Returns a list of descriptions of the IFR objects
- in this Container's contents.</p>
- </desc>
- </func>
- <func>
- <name>create_module(Objref,Id,Name,Version) -> Return</name>
- <fsummary>Create an IFR object of given type</fsummary>
- <type>
- <v>Objref = #IFR_objref</v>
- <v>Id = string()</v>
- <v>Name = string()</v>
- <v>Version = string()</v>
- <v>Return = #IFR_ModuleDef_objref</v>
- </type>
- <desc>
- <p>Objref is an IFR object of any kind that inherits from
- Container. Creates an IFR object of the type ModuleDef.</p>
- </desc>
- </func>
- <func>
- <name>create_constant(Objref,Id,Name,Version,Type,Value) -> Return</name>
- <fsummary>Create a ConstantDef IFR object</fsummary>
- <type>
- <v>Objref = #IFR_objref</v>
- <v>Id = string()</v>
- <v>Name = string()</v>
- <v>Version = string()</v>
- <v>Type = #IFR_IDLType_objref</v>
- <v>Value = any()</v>
- <v>Return = #IFR_ConstantDef_objref</v>
- </type>
- <desc>
- <p>Objref is an IFR object of any kind that inherits from
- Container. Creates an IFR object of the type ConstantDef.</p>
- </desc>
- </func>
- <func>
- <name>create_struct(Objref,Id,Name,Version,Members) -> Return</name>
- <fsummary>Create a StructDef IFR object</fsummary>
- <type>
- <v>Objref = #IFR_objref</v>
- <v>Id = string()</v>
- <v>Name = string()</v>
- <v>Version = string()</v>
- <v>Members = list() (list of structmember records)</v>
- <v>Return = #IFR_StructDef_objref</v>
- </type>
- <desc>
- <p>Objref is an IFR object of any kind that inherits from
- Container. Creates an IFR object of the type StructDef.</p>
- </desc>
- </func>
- <func>
- <name>create_union(Objref,Id,Name,Version,Discriminator_type,Members) -> Return</name>
- <fsummary>Create a UnionDef IFR object</fsummary>
- <type>
- <v>Objref = #IFR_objref</v>
- <v>Id = string()</v>
- <v>Name = string()</v>
- <v>Version = string()</v>
- <v>Discriminator_type = #IFR_IDLType_Objref</v>
- <v>Members = list() (list of unionmember records)</v>
- <v>Return = #IFR_UnionDef_objref</v>
- </type>
- <desc>
- <p>Objref is an IFR object of any kind that inherits from
- Container. Creates an IFR object of the type UnionDef.</p>
- </desc>
- </func>
- <func>
- <name>create_enum(Objref,Id,Name,Version,Members) -> Return</name>
- <fsummary>Create a EnumDef IFR object</fsummary>
- <type>
- <v>Objref = #IFR_objref</v>
- <v>Id = string()</v>
- <v>Name = string()</v>
- <v>Version = string()</v>
- <v>Members = list() (list of strings)</v>
- <v>Return = #IFR_EnumDef_objref</v>
- </type>
- <desc>
- <p>Objref is an IFR object of any kind that inherits from
- Container. Creates an IFR object of the type EnumDef.</p>
- </desc>
- </func>
- <func>
- <name>create_alias(Objref,Id,Name,Version,Original_type) -> Return</name>
- <fsummary>Create a AliasDef IFR object</fsummary>
- <type>
- <v>Objref = #IFR_objref</v>
- <v>Id = string()</v>
- <v>Name = string()</v>
- <v>Version = string()</v>
- <v>Original_type = #IFR_IDLType_Objref</v>
- <v>Return = #IFR_AliasDef_objref</v>
- </type>
- <desc>
- <p>Objref is an IFR object of any kind that inherits from
- Container. Creates an IFR object of the type AliasDef.</p>
- </desc>
- </func>
- <func>
- <name>create_interface(Objref,Id,Name,Version,Base_interfaces) -> Return</name>
- <fsummary>Create a InterfaceDef IFR object</fsummary>
- <type>
- <v>Objref = #IFR_objref</v>
- <v>Id = string()</v>
- <v>Name = string()</v>
- <v>Version = string()</v>
- <v>Base_interfaces = list() (a list of IFR_InterfaceDef_objrefs that this interface inherits from</v>
- <v>Return = #IFR_InterfaceDef_objref</v>
- </type>
- <desc>
- <p>Objref is an IFR object of any kind that inherits from
- Container. Creates an IFR object of the type InterfaceDef.</p>
- </desc>
- </func>
- <func>
- <name>create_exception(Objref,Id,Name,Version,Members) -> Return</name>
- <fsummary>Create a ExceptionDef IFR object</fsummary>
- <type>
- <v>Objref = #IFR_objref</v>
- <v>Id = string()</v>
- <v>Name = string()</v>
- <v>Version = string()</v>
- <v>Members = list() (list of structmember records)</v>
- <v>Return = #IFR_ExceptionDef_objref</v>
- </type>
- <desc>
- <p>Objref is an IFR object of any kind that inherits from
- Container. Creates an IFR object of the type ExceptionDef.</p>
- </desc>
- </func>
- <func>
- <name>get_type(Objref) -> Return</name>
- <fsummary>Return the typecode of the target object</fsummary>
- <type>
- <v>Objref = #IFR_objref</v>
- <v>Return = tuple() (a typecode tuple)</v>
- </type>
- <desc>
- <p>Objref is an IFR object of any kind that inherits from
- IDLType or an IFR object of the kind ConstantDef,
- ExceptionDef or AttributeDef. Returns the typecode of the
- IFR object.</p>
- </desc>
- </func>
- <func>
- <name>lookup_id(Objref,Search_id) -> Return</name>
- <fsummary>Return the IFR object matching the given id</fsummary>
- <type>
- <v>Objref = #IFR_Repository_objref</v>
- <v>Search_id = string()</v>
- <v>Return = #IFR_objref</v>
- </type>
- <desc>
- <p>Returns an IFR object matching the Search_id.</p>
- </desc>
- </func>
- <func>
- <name>get_primitive(Objref,Kind) -> Return</name>
- <fsummary>Return a PrimitiveDef of the specified kind</fsummary>
- <type>
- <v>Objref = #IFR_Repository_objref</v>
- <v>Kind = atom() (one of pk_null, pk_void, pk_short, pk_long, pk_ushort, pk_ulong, pk_float, pk_double, pk_boolean, pk_char, pk_octet, pk_any, pk_TypeCode, pk_Principal, pk_string, pk_wstring, pk_fixed, pk_objref)</v>
- <v>Return = #IFR_PrimitiveDef_objref</v>
- </type>
- <desc>
- <p>Returns a PrimitiveDef of the specified kind.</p>
- </desc>
- </func>
- <func>
- <name>create_string(Objref,Bound) -> Return</name>
- <fsummary>Create an IFR objref of the type StringDef</fsummary>
- <type>
- <v>Objref = #IFR_Repository_objref</v>
- <v>Bound = integer() (unsigned long /= 0)</v>
- <v>Return = #IFR_StringDef_objref</v>
- </type>
- <desc>
- <p>Creates an IFR objref of the type StringDef.</p>
- </desc>
- </func>
- <func>
- <name>create_wstring(Objref,Bound) -> Return</name>
- <fsummary>Create an IFR objref of the type WstringDef</fsummary>
- <type>
- <v>Objref = #IFR_Repository_objref</v>
- <v>Bound = integer() (unsigned long /= 0)</v>
- <v>Return = #IFR_WstringDef_objref</v>
- </type>
- <desc>
- <p>Creates an IFR objref of the type WstringDef.</p>
- </desc>
- </func>
- <func>
- <name>create_fixed(Objref,Digits,Scale) -> Return</name>
- <fsummary>Create an IFR objref of the type FixedDef</fsummary>
- <type>
- <v>Objref = #IFR_Repository_objref</v>
- <v>Digits = Scale = integer()</v>
- <v>Return = #IFR_FixedDef_objref</v>
- </type>
- <desc>
- <p>Creates an IFR objref of the type FixedDef.</p>
- </desc>
- </func>
- <func>
- <name>create_sequence(Objref,Bound,Element_type) -> Return</name>
- <fsummary>Create an IFR objref of the type SequenceDef</fsummary>
- <type>
- <v>Objref = #IFR_Repository_objref</v>
- <v>Bound = integer() (unsigned long)</v>
- <v>Element_type = #IFR_IDLType_objref</v>
- <v>Return = #IFR_SequenceDef_objref</v>
- </type>
- <desc>
- <p>Creates an IFR objref of the type SequenceDef.</p>
- </desc>
- </func>
- <func>
- <name>create_array(Objref,Length,Element_type) -> Return</name>
- <fsummary>Create an IFR objref of the type ArrayDef</fsummary>
- <type>
- <v>Objref = #IFR_Repository_objref</v>
- <v>Bound = integer() (unsigned long)</v>
- <v>Element_type = #IFR_IDLType_objref</v>
- <v>Return = #IFR_ArrayDef_objref</v>
- </type>
- <desc>
- <p>Creates an IFR objref of the type ArrayDef.</p>
- </desc>
- </func>
- <func>
- <name>create_idltype(Objref,Typecode) -> Return</name>
- <fsummary>Create an IFR objref of the type IDLType</fsummary>
- <type>
- <v>Objref = #IFR_Repository_objref</v>
- <v>Typecode = tuple() (a typecode tuple)</v>
- <v>Return = #IFR_IDLType_objref</v>
- </type>
- <desc>
- <p>Creates an IFR objref of the type IDLType.</p>
- </desc>
- </func>
- <func>
- <name>get_type_def(Objref) -> Return</name>
- <fsummary>Return an IFR object of the type IDLType describing the type of the target object</fsummary>
- <type>
- <v>Objref = #IFR_objref</v>
- <v>Return = #IFR_IDLType_objref</v>
- </type>
- <desc>
- <p>Objref is an IFR object of the kind ConstantDef or
- AttributeDef. Returns an IFR object of the type IDLType
- describing the type of the IFR object.</p>
- </desc>
- </func>
- <func>
- <name>set_type_def(Objref,TypeDef) -> Return</name>
- <fsummary>Set given TypeDef of the target object</fsummary>
- <type>
- <v>Objref = #IFR_objref</v>
- <v>TypeDef = #IFR_IDLType_objref</v>
- <v>Return = ok | {exception, _}</v>
- </type>
- <desc>
- <p>Objref is an IFR object of the kind ConstantDef or
- AttributeDef. Sets the type_def of the IFR Object.</p>
- </desc>
- </func>
- <func>
- <name>get_value(Objref) -> Return</name>
- <fsummary>Return the value attribute of the target ConstantDef object</fsummary>
- <type>
- <v>Objref = #IFR_ConstantDef_objref</v>
- <v>Return = any()</v>
- </type>
- <desc>
- <p>Returns the value attribute of an IFR Object of the type ConstantDef.</p>
- </desc>
- </func>
- <func>
- <name>set_value(Objref,Value) -> Return</name>
- <fsummary>Set the value attribute of the target ConstantDef object</fsummary>
- <type>
- <v>Objref = #IFR_ConstantDef_objref</v>
- <v>Value = any()</v>
- <v>Return = ok | {exception, _}</v>
- </type>
- <desc>
- <p>Sets the value attribute of an IFR Object of the type ConstantDef.</p>
- </desc>
- </func>
- <func>
- <name>get_members(Objref) -> Return</name>
- <fsummary>Return the members of the target object</fsummary>
- <type>
- <v>Objref = #IFR_objref</v>
- <v>Return = list()</v>
- </type>
- <desc>
- <p>Objref is an IFR object the kind StructDef, UnionDef,
- EnumDef or ExceptionDef.
- For StructDef, UnionDef and ExceptionDef: Returns a list of
- structmember records that are the constituent parts of the
- object.
- For EnumDef: Returns a list of strings describing the
- enumerations.</p>
- </desc>
- </func>
- <func>
- <name>set_members(Objref,Members) -> Return</name>
- <fsummary>Set the members attribute of the target object</fsummary>
- <type>
- <v>Objref = #IFR_objref</v>
- <v>Members = list()</v>
- <v>Return = ok | {exception, _}</v>
- </type>
- <desc>
- <p>Objref is an IFR object the kind StructDef, UnionDef,
- EnumDef or ExceptionDef.
- For StructDef, UnionDef and ExceptionDef: Members is a list
- of structmember records.
- For EnumDef: Members is a list of strings describing the
- enumerations.
- Sets the members attribute, which are the constituent parts of the
- exception.</p>
- </desc>
- </func>
- <func>
- <name>get_discriminator_type(Objref) -> Return</name>
- <fsummary>Get the discriminator typecode of the target object</fsummary>
- <type>
- <v>Objref = #IFR_UnionDef_objref</v>
- <v>Return = tuple() (a typecode tuple)</v>
- </type>
- <desc>
- <p>Returns the discriminator typecode of an IFR object of the type
- UnionDef.</p>
- </desc>
- </func>
- <func>
- <name>get_discriminator_type_def(Objref) -> Return</name>
- <fsummary>Return IDLType object describing the discriminator type of the target object</fsummary>
- <type>
- <v>Objref = #IFR_UnionDef_objref</v>
- <v>Return = #IFR_IDLType_objref</v>
- </type>
- <desc>
- <p>Returns an IFR object of the type IDLType describing the
- discriminator type of an IFR object of the type UnionDef.</p>
- </desc>
- </func>
- <func>
- <name>set_discriminator_type_def(Objref,TypeDef) -> Return</name>
- <fsummary>Set the attribute discriminator_type_def for the target object to the given TypeDef</fsummary>
- <type>
- <v>Objref = #IFR_UnionDef_objref</v>
- <v>Return = #IFR_IDLType_objref</v>
- </type>
- <desc>
- <p>Sets the attribute discriminator_type_def, an IFR object of
- the type IDLType describing the discriminator type of an IFR
- object of the type UnionDef.</p>
- </desc>
- </func>
- <func>
- <name>get_original_type_def(Objref) -> Return</name>
- <fsummary>Return an IFR object of the type IDLType describing the original type</fsummary>
- <type>
- <v>Objref = #IFR_AliasDef_objref</v>
- <v>Return = #IFR_IDLType_objref</v>
- </type>
- <desc>
- <p>Returns an IFR object of the type IDLType describing the
- original type.</p>
- </desc>
- </func>
- <func>
- <name>set_original_type_def(Objref,TypeDef) -> Return</name>
- <fsummary>Set the original_type_def attribute which describes the original type</fsummary>
- <type>
- <v>Objref = #IFR_AliasDef_objref</v>
- <v>Typedef = #IFR_IDLType_objref</v>
- <v>Return = ok | {exception, _}</v>
- </type>
- <desc>
- <p>Sets the original_type_def attribute which describes the
- original type.</p>
- </desc>
- </func>
- <func>
- <name>get_kind(Objref) -> Return</name>
- <fsummary>Return an atom describing the primitive type</fsummary>
- <type>
- <v>Objref = #IFR_PrimitiveDef_objref</v>
- <v>Return = atom()</v>
- </type>
- <desc>
- <p>Returns an atom describing the primitive type (See CORBA 2.0
- p 6-21).</p>
- </desc>
- </func>
- <func>
- <name>get_bound(Objref) -> Return</name>
- <fsummary>Get the maximum size of the target object</fsummary>
- <type>
- <v>Objref = #IFR_objref</v>
- <v>Return = integer (unsigned long)</v>
- </type>
- <desc>
- <p>Objref is an IFR object the kind StringDef or SequenceDef.
- For StringDef: returns the maximum number of characters in
- the string.
- For SequenceDef: Returns the maximum number of elements in
- the sequence. Zero indicates an unbounded sequence.</p>
- </desc>
- </func>
- <func>
- <name>set_bound(Objref,Bound) -> Return</name>
- <fsummary>Set the maximum size of the target object</fsummary>
- <type>
- <v>Objref = #IFR_objref</v>
- <v>Bound = integer (unsigned long)</v>
- <v>Return = ok | {exception, _}</v>
- </type>
- <desc>
- <p>Objref is an IFR object the kind StringDef or SequenceDef.
- For StringDef: Sets the maximum number of characters in the
- string. Bound must not be zero.
- For SequenceDef: Sets the maximum number of elements in the
- sequence. Zero indicates an unbounded sequence.</p>
- </desc>
- </func>
- <func>
- <name>get_element_type(Objref) -> Return</name>
- <fsummary>Return the typecode of the elements in the IFR object</fsummary>
- <type>
- <v>Objref = #IFR_objref</v>
- <v>Return = tuple() (a typecode tuple)</v>
- </type>
- <desc>
- <p>Objref is an IFR object the kind SequenceDef or ArrayDef.
- Returns the typecode of the elements in the IFR object.</p>
- </desc>
- </func>
- <func>
- <name>get_element_type_def(Objref) -> Return</name>
- <fsummary>Return an IFR object of the type IDLType describing the type of the elements in Objref</fsummary>
- <type>
- <v>Objref = #IFR_objref</v>
- <v>Return = #IFR_IDLType_objref</v>
- </type>
- <desc>
- <p>Objref is an IFR object the kind SequenceDef or ArrayDef.
- Returns an IFR object of the type IDLType describing the
- type of the elements in Objref.</p>
- </desc>
- </func>
- <func>
- <name>set_element_type_def(Objref,TypeDef) -> Return</name>
- <fsummary>Set the element_type_def attribute of the target object to the given TypeDef</fsummary>
- <type>
- <v>Objref = #IFR_objref</v>
- <v>TypeDef = #IFR_IDLType_objref</v>
- <v>Return = ok | {exception, _}</v>
- </type>
- <desc>
- <p>Objref is an IFR object the kind SequenceDef or ArrayDef.
- Sets the element_type_def attribute, an IFR object of the
- type IDLType describing the type of the elements in Objref.</p>
- </desc>
- </func>
- <func>
- <name>get_length(Objref) -> Return</name>
- <fsummary>Return the number of elements in the array</fsummary>
- <type>
- <v>Objref = #IFR_ArrayDef_objref</v>
- <v>Return = integer() (unsigned long)</v>
- </type>
- <desc>
- <p>Returns the number of elements in the array.</p>
- </desc>
- </func>
- <func>
- <name>set_length(Objref,Length) -> Return</name>
- <fsummary>Set the number of elements in the array</fsummary>
- <type>
- <v>Objref = #IFR_ArrayDef_objref</v>
- <v>Length = integer() (unsigned long)</v>
- </type>
- <desc>
- <p>Sets the number of elements in the array.</p>
- </desc>
- </func>
- <func>
- <name>get_mode(Objref) -> Return</name>
- <fsummary>Get the mode of the target object (AttributeDef or OperationDef)</fsummary>
- <type>
- <v>Objref = #IFR_objref</v>
- <v>Return = atom()</v>
- </type>
- <desc>
- <p>Objref is an IFR object the kind AttributeDef or OperationDef.
- For AttributeDef: Return is an atom ('ATTR_NORMAL' or
- 'ATTR_READONLY') specifying the read/write access for this
- attribute.
- For OperationDef: Return is an atom ('OP_NORMAL' or
- 'OP_ONEWAY') specifying the mode of the operation.</p>
- </desc>
- </func>
- <func>
- <name>set_mode(Objref,Mode) -> Return</name>
- <fsummary>Set the mode of the target object (AttributeDef or OperationDef) to the given mode</fsummary>
- <type>
- <v>Objref = #IFR_objref</v>
- <v>Mode = atom()</v>
- <v>Return = ok | {exception, _}</v>
- </type>
- <desc>
- <p>Objref is an IFR object the kind AttributeDef or OperationDef.
- For AttributeDef: Sets the read/write access for this
- attribute. Mode is an atom ('ATTR_NORMAL' or
- 'ATTR_READONLY').
- For OperationDef: Sets the mode of the operation. Mode is an
- atom ('OP_NORMAL' or 'OP_ONEWAY').</p>
- </desc>
- </func>
- <func>
- <name>get_result(Objref) -> Return</name>
- <fsummary>Return typecode describing the type of the value returned by the operation</fsummary>
- <type>
- <v>Objref = #IFR_OperationDef_objref</v>
- <v>Return = tuple() (a typecode tuple)</v>
- </type>
- <desc>
- <p>Returns a typecode describing the type of the value returned by the
- operation.</p>
- </desc>
- </func>
- <func>
- <name>get_result_def(Objref) -> Return</name>
- <fsummary>Return an IFR object of the type IDLType describing the type of the result</fsummary>
- <type>
- <v>Objref = #IFR_OperationDef_objref</v>
- <v>Return = #IFR_IDLType_objref</v>
- </type>
- <desc>
- <p>Returns an IFR object of the type IDLType describing the type of the
- result.</p>
- </desc>
- </func>
- <func>
- <name>set_result_def(Objref,ResultDef) -> Return</name>
- <fsummary>Set the type_def attribute of the target object to the given ResultDef</fsummary>
- <type>
- <v>Objref = #IFR_OperationDef_objref</v>
- <v>ResultDef = #IFR_IDLType_objref</v>
- <v>Return = ok | {exception, _}</v>
- </type>
- <desc>
- <p>Sets the type_def attribute, an IFR Object of the type IDLType
- describing the result.</p>
- </desc>
- </func>
- <func>
- <name>get_params(Objref) -> Return</name>
- <fsummary>Return a list of parameter description records describing the parameters of the target OperationDef</fsummary>
- <type>
- <v>Objref = #IFR_OperationDef_objref</v>
- <v>Return = list() (list of parameter description records)</v>
- </type>
- <desc>
- <p>Returns a list of parameter description records, which describes the
- parameters of the OperationDef.</p>
- </desc>
- </func>
- <func>
- <name>set_params(Objref,Params) -> Return</name>
- <fsummary>Set the params attribute of the target object to the given parameter description records</fsummary>
- <type>
- <v>Objref = #IFR_OperationDef_objref</v>
- <v>Params = list() (list of parameter description records)</v>
- <v>Return = ok | {exception, _}</v>
- </type>
- <desc>
- <p>Sets the params attribute, a list of parameter description records.</p>
- </desc>
- </func>
- <func>
- <name>get_contexts(Objref) -> Return</name>
- <fsummary>Return a list of context identifiers for the operation</fsummary>
- <type>
- <v>Objref = #IFR_OperationDef_objref</v>
- <v>Return = list() (list of strings)</v>
- </type>
- <desc>
- <p>Returns a list of context identifiers for the operation.</p>
- </desc>
- </func>
- <func>
- <name>set_contexts(Objref,Contexts) -> Return</name>
- <fsummary>Set the context attribute for the operation</fsummary>
- <type>
- <v>Objref = #IFR_OperationDef_objref</v>
- <v>Contexts = list() (list of strings)</v>
- <v>Return = ok | {exception, _}</v>
- </type>
- <desc>
- <p>Sets the context attribute for the operation.</p>
- </desc>
- </func>
- <func>
- <name>get_exceptions(Objref) -> Return</name>
- <fsummary>Return a list of exception types that can be raised by the target object</fsummary>
- <type>
- <v>Objref = #IFR_OperationDef_objref</v>
- <v>Return = list() (list of #IFR_ExceptionDef_objrefs)</v>
- </type>
- <desc>
- <p>Returns a list of exception types that can be raised by this
- operation.</p>
- </desc>
- </func>
- <func>
- <name>set_exceptions(Objref,Exceptions) -> Return</name>
- <fsummary>Set the exceptions attribute for the target object</fsummary>
- <type>
- <v>Objref = #IFR_OperationDef_objref</v>
- <v>Exceptions = list() (list of #IFR_ExceptionDef_objrefs)</v>
- <v>Return = ok | {exception, _}</v>
- </type>
- <desc>
- <p>Sets the exceptions attribute for this operation.</p>
- </desc>
- </func>
- <func>
- <name>get_base_interfaces(Objref) -> Return</name>
- <fsummary>Return a list of InterfaceDefs from which the target InterfaceDef object inherit</fsummary>
- <type>
- <v>Objref = #IFR_InterfaceDef_objref</v>
- <v>Return = list() (list of #IFR_InterfaceDef_objrefs)</v>
- </type>
- <desc>
- <p>Returns a list of InterfaceDefs from which this InterfaceDef inherits.</p>
- </desc>
- </func>
- <func>
- <name>set_base_interfaces(Objref,BaseInterfaces) -> Return</name>
- <fsummary>Set the BaseInterfaces attribute</fsummary>
- <type>
- <v>Objref = #IFR_InterfaceDef_objref</v>
- <v>BaseInterfaces = list() (list of #IFR_InterfaceDef_objrefs)</v>
- <v>Return = ok | {exception, _}</v>
- </type>
- <desc>
- <p>Sets the BaseInterfaces attribute.</p>
- </desc>
- </func>
- <func>
- <name>is_a(Objref,Interface_id) -> Return</name>
- <fsummary>Return a boolean if the target InterfaceDef match or inherit from the given id</fsummary>
- <type>
- <v>Objref = #IFR_InterfaceDef_objref</v>
- <v>Interface_id = #IFR_InterfaceDef_objref</v>
- <v>Return = atom() (true or false)</v>
- </type>
- <desc>
- <p>Returns true if the InterfaceDef either is identical to or
- inherits from Interface_id.</p>
- </desc>
- </func>
- <func>
- <name>describe_interface(Objref) -> Return</name>
- <fsummary>Return a full inter face description record describing the InterfaceDef</fsummary>
- <type>
- <v>Objref = #IFR_InterfaceDef_objref</v>
- <v>Return = tuple() (a fullinterfacedescription record)</v>
- </type>
- <desc>
- <p>Returns a full inter face description record describing the InterfaceDef.</p>
- </desc>
- </func>
- <func>
- <name>create_attribute(Objref,Id,Name,Version,Type,Mode) -> Return</name>
- <fsummary>Create an IFR object of the type AttributeDef contained in the target InterfaceDef object</fsummary>
- <type>
- <v>Objref = #IFR_InterfaceDef_objref</v>
- <v>Id = string()</v>
- <v>Name = string()</v>
- <v>Version = string()</v>
- <v>Type = #IFR_IDLType_objref</v>
- <v>Mode = atom() ('ATTR_NORMAL' or 'ATTR_READONLY')</v>
- <v>Return = #IFR_AttributeDef_objref</v>
- </type>
- <desc>
- <p>Creates an IFR object of the type AttributeDef contained in this
- InterfaceDef.</p>
- </desc>
- </func>
- <func>
- <name>create_operation(Objref,Id,Name,Version,Result,Mode,Params, Exceptions,Contexts) -> Return</name>
- <fsummary>Create an IFR object of the type OperationDef contained in the target InterfaceDef object</fsummary>
- <type>
- <v>Objref = #IFR_InterfaceDef_objref</v>
- <v>Id = string()</v>
- <v>Name = string()</v>
- <v>Version = string()</v>
- <v>Result = #IFR_IDLType_objref</v>
- <v>Mode = atom() ('OP_NORMAL' or 'OP_ONEWAY')</v>
- <v>Params = list() (list of parameter description records)</v>
- <v>Exceptions = list() (list of #IFR_ExceptionDef_objrefs)</v>
- <v>Contexts = list() (list of strings)</v>
- <v>Return = #IFR_OperationDef_objref</v>
- </type>
- <desc>
- <p>Creates an IFR object of the type OperationDef contained in this
- InterfaceDef.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/orber/doc/src/orber_tc.xml b/lib/orber/doc/src/orber_tc.xml
deleted file mode 100644
index 0cab8a5e4b..0000000000
--- a/lib/orber/doc/src/orber_tc.xml
+++ /dev/null
@@ -1,259 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1998</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>orber_tc</title>
- <prepared>Lars Thors&eacute;n</prepared>
- <responsible>Lars Thors&eacute;n</responsible>
- <docno></docno>
- <approved>Lars Thors&eacute;n</approved>
- <checked></checked>
- <date>1998-04-20</date>
- <rev>A</rev>
- </header>
- <module>orber_tc</module>
- <modulesummary>Help functions for IDL typecodes</modulesummary>
- <description>
- <p>This module contains some functions that gives support in creating
- IDL typecodes that can be used in for example the any types typecode field.
- For the simple types it is meaningless to use this API but the functions exist
- to get the interface complete.</p>
- <p>The type <c>TC</c> used below describes an IDL type and is a tuple according
- to the to the Erlang language mapping.</p>
- </description>
- <funcs>
- <func>
- <name>null() -> TC</name>
- <name>void() -> TC</name>
- <name>short() -> TC</name>
- <name>unsigned_short() -> TC</name>
- <name>long() -> TC</name>
- <name>unsigned_long() -> TC</name>
- <name>long_long() -> TC</name>
- <name>unsigned_long_long() -> TC</name>
- <name>wchar() -> TC</name>
- <name>float() -> TC</name>
- <name>double() -> TC</name>
- <name>boolean() -> TC</name>
- <name>char() -> TC</name>
- <name>octet() -> TC</name>
- <name>any() -> TC</name>
- <name>typecode() -> TC</name>
- <name>principal() -> TC</name>
- <fsummary>Return the IDL typecode</fsummary>
- <desc>
- <p>These functions return the IDL typecodes for simple types.</p>
- </desc>
- </func>
- <func>
- <name>object_reference(Id, Name) -> TC</name>
- <fsummary>Return the object_reference IDL typecode</fsummary>
- <type>
- <v>Id = string()</v>
- <d>the repository ID</d>
- <v>Name = string()</v>
- <d>the type name of the object</d>
- </type>
- <desc>
- <p>Function returns the IDL typecode for object_reference.</p>
- </desc>
- </func>
- <func>
- <name>struct(Id, Name, ElementList) -> TC</name>
- <fsummary>Return the struct IDL typecode</fsummary>
- <type>
- <v>Id = string()</v>
- <d>the repository ID</d>
- <v>Name = string()</v>
- <d>the type name of the struct</d>
- <v>ElementList = [{MemberName, TC}]</v>
- <d>a list of the struct elements</d>
- <v>MemberName = string()</v>
- <d>the element name</d>
- </type>
- <desc>
- <p>Function returns the IDL typecode for struct.</p>
- </desc>
- </func>
- <func>
- <name>union(Id, Name, DiscrTC, Default, ElementList) -> TC</name>
- <fsummary>Return the union IDL typecode</fsummary>
- <type>
- <v>Id = string()</v>
- <d>the repository ID</d>
- <v>Name = string()</v>
- <d>the type name of the union</d>
- <v>DiscrTC = TC</v>
- <d>the typecode for the unions discriminant</d>
- <v>Default = integer()</v>
- <d>a value that indicates which tuple in the element list that is default (value &lt; 0 means no default)</d>
- <v>ElementList = [{Label, MemberName, TC}]</v>
- <d>a list of the union elements</d>
- <v>Label = term()</v>
- <d>the label value should be of the <em>DiscrTC</em>type</d>
- <v>MemberName = string()</v>
- <d>the element name</d>
- </type>
- <desc>
- <p>Function returns the IDL typecode for union.</p>
- </desc>
- </func>
- <func>
- <name>enum(Id, Name, ElementList) -> TC</name>
- <fsummary>Return the enum IDL typecode</fsummary>
- <type>
- <v>Id = string()</v>
- <d>the repository ID</d>
- <v>Name = string()</v>
- <d>the type name of the enum</d>
- <v>ElementList = [MemberName]</v>
- <d>a list of the enums elements</d>
- <v>MemberName = string()</v>
- <d>the element name</d>
- </type>
- <desc>
- <p>Function returns the IDL typecode for enum.</p>
- </desc>
- </func>
- <func>
- <name>string(Length) -> TC</name>
- <fsummary>Return the string IDL typecode</fsummary>
- <type>
- <v>Length = integer()</v>
- <d>the length of the string (0 means unbounded)</d>
- </type>
- <desc>
- <p>Function returns the IDL typecode for string.</p>
- </desc>
- </func>
- <func>
- <name>wstring(Length) -> TC</name>
- <fsummary>Return the wstring IDL typecode</fsummary>
- <type>
- <v>Length = integer()</v>
- <d>the length of the wstring (0 means unbounded)</d>
- </type>
- <desc>
- <p>Function returns the IDL typecode for wstring.</p>
- </desc>
- </func>
- <func>
- <name>fixed(Digits, Scale) -> TC</name>
- <fsummary>Return the fixed IDL typecode</fsummary>
- <type>
- <v>Digits = Scale = integer()</v>
- <d>the digits and scale parameters of a Fixed type</d>
- </type>
- <desc>
- <p>Function returns the IDL typecode for fixed.</p>
- </desc>
- </func>
- <func>
- <name>sequence(ElemTC, Length) -> TC</name>
- <fsummary>Return the sequence IDL typecode</fsummary>
- <type>
- <v>ElemTC = TC</v>
- <d>the typecode for the sequence elements</d>
- <v>Length = integer()</v>
- <d>the length of the sequence (0 means unbounded)</d>
- </type>
- <desc>
- <p>Function returns the IDL typecode for sequence.</p>
- </desc>
- </func>
- <func>
- <name>array(ElemTC, Length) -> TC</name>
- <fsummary>Return the array IDL typecode</fsummary>
- <type>
- <v>ElemTC = TC</v>
- <d>the typecode for the array elements</d>
- <v>Length = integer()</v>
- <d>the length of the array</d>
- </type>
- <desc>
- <p>Function returns the IDL typecode for array.</p>
- </desc>
- </func>
- <func>
- <name>alias(Id, Name, AliasTC) -> TC</name>
- <fsummary>Return the alias IDL typecode</fsummary>
- <type>
- <v>Id = string()</v>
- <d>the repository ID</d>
- <v>Name = string()</v>
- <d>the type name of the alias</d>
- <v>AliasTC = TC</v>
- <d>the typecode for the type which the alias refer to</d>
- </type>
- <desc>
- <p>Function returns the IDL typecode for alias.</p>
- </desc>
- </func>
- <func>
- <name>exception(Id, Name, ElementList) -> TC</name>
- <fsummary>Return the exception IDL typecode</fsummary>
- <type>
- <v>Id = string()</v>
- <d>the repository ID</d>
- <v>Name = string()</v>
- <d>the type name of the exception</d>
- <v>ElementList = [{MemberName, TC}]</v>
- <d>a list of the exception elements</d>
- <v>MemberName = string()</v>
- <d>the element name</d>
- </type>
- <desc>
- <p>Function returns the IDL typecode for exception.</p>
- </desc>
- </func>
- <func>
- <name>get_tc(Object) -> TC</name>
- <name>get_tc(Id) -> TC</name>
- <fsummary>Fetch typecode</fsummary>
- <type>
- <v>Object = record()</v>
- <d>an IDL specified struct, union or exception</d>
- <v>Id = string()</v>
- <d>the repository ID</d>
- </type>
- <desc>
- <p>If the get_tc/1 gets a record that is and IDL specified
- struct, union or exception as a parameter it returns the
- typecode.</p>
- <p>If the parameter is a repository ID it uses the Interface Repository
- to get the typecode.</p>
- </desc>
- </func>
- <func>
- <name>check_tc(TC) -> boolean()</name>
- <fsummary>Check syntax of an IDL typecode</fsummary>
- <desc>
- <p>Function checks the syntax of an IDL typecode.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/orber/doc/src/orbs.gif b/lib/orber/doc/src/orbs.gif
deleted file mode 100644
index 47f2c85441..0000000000
--- a/lib/orber/doc/src/orbs.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/part.xml b/lib/orber/doc/src/part.xml
deleted file mode 100644
index ef84b8c05a..0000000000
--- a/lib/orber/doc/src/part.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE part SYSTEM "part.dtd">
-
-<part xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>1997</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Orber User's Guide</title>
- <prepared></prepared>
- <docno></docno>
- <date>1998-04-26</date>
- <rev>2.2</rev>
- </header>
- <description>
- <p>The <em>Orber</em> application is an Erlang implementation of a
- CORBA Object Request Broker.</p>
- </description>
- <xi:include href="ch_contents.xml"/>
- <xi:include href="ch_introduction.xml"/>
- <xi:include href="ch_orber_kernel.xml"/>
- <xi:include href="ch_ifr.xml"/>
- <xi:include href="ch_install.xml"/>
- <xi:include href="ch_idl_to_erlang_mapping.xml"/>
- <xi:include href="ch_naming_service.xml"/>
- <xi:include href="ch_security.xml"/>
- <xi:include href="ch_stubs.xml"/>
- <xi:include href="ch_exceptions.xml"/>
- <xi:include href="ch_interceptors.xml"/>
- <xi:include href="ch_orberweb.xml"/>
- <xi:include href="ch_debugging.xml"/>
-</part>
-
diff --git a/lib/orber/doc/src/ref_man.xml b/lib/orber/doc/src/ref_man.xml
deleted file mode 100644
index 6fa409538d..0000000000
--- a/lib/orber/doc/src/ref_man.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE application SYSTEM "application.dtd">
-
-<application xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>1997</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Orber Reference Manual</title>
- <prepared></prepared>
- <docno></docno>
- <date>1998-05-05</date>
- <rev>2.0</rev>
- </header>
- <description>
- <p>The <em>Orber</em> application is an Erlang implementation of a
- CORBA Object Request Broker.</p>
- </description>
- <xi:include href="any.xml"/>
- <xi:include href="fixed.xml"/>
- <xi:include href="corba.xml"/>
- <xi:include href="corba_object.xml"/>
- <xi:include href="orber.xml"/>
- <xi:include href="orber_ifr.xml"/>
- <xi:include href="orber_tc.xml"/>
- <xi:include href="orber_acl.xml"/>
- <xi:include href="CosNaming.xml"/>
- <xi:include href="CosNaming_NamingContext.xml"/>
- <xi:include href="CosNaming_NamingContextExt.xml"/>
- <xi:include href="CosNaming_BindingIterator.xml"/>
- <xi:include href="lname.xml"/>
- <xi:include href="lname_component.xml"/>
- <xi:include href="Module_Interface.xml"/>
- <xi:include href="interceptors.xml"/>
- <xi:include href="orber_diagnostics.xml"/>
-</application>
-
diff --git a/lib/orber/doc/src/theORB.gif b/lib/orber/doc/src/theORB.gif
deleted file mode 100644
index 976672b8df..0000000000
--- a/lib/orber/doc/src/theORB.gif
+++ /dev/null
Binary files differ
diff --git a/lib/orber/doc/src/tools_debugging_part.xml b/lib/orber/doc/src/tools_debugging_part.xml
deleted file mode 100644
index 94af44833c..0000000000
--- a/lib/orber/doc/src/tools_debugging_part.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE part SYSTEM "part.dtd">
-
-<part>
- <header>
- <copyright>
- <year>2002</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>Tools, Debugging and FAQ</title>
- <prepared>Niclas Eklund</prepared>
- <docno></docno>
- <date>2002-06-25</date>
- <rev>A</rev>
- </header>
- <description>
- <p>This chapter describe the available tools and debugging facilities for Orber.
- Also contain a FAQ listing of the most common mistakes.</p>
- </description>
- <include file="ch_orberweb"></include>
- <include file="ch_debugging"></include>
-</part>
-
diff --git a/lib/orber/ebin/.gitignore b/lib/orber/ebin/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/orber/ebin/.gitignore
+++ /dev/null
diff --git a/lib/orber/examples/Makefile b/lib/orber/examples/Makefile
deleted file mode 100644
index bf1ff13707..0000000000
--- a/lib/orber/examples/Makefile
+++ /dev/null
@@ -1,42 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(ORBER_VSN)
-
-# ----------------------------------------------------
-# Common Macros
-# ----------------------------------------------------
-
-SUB_DIRECTORIES = Stack
-
-SPECIAL_TARGETS =
-
-# ----------------------------------------------------
-# Default Subdir Targets
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_subdir.mk
-
diff --git a/lib/orber/examples/Stack/InitialReferences.idl b/lib/orber/examples/Stack/InitialReferences.idl
deleted file mode 100644
index 7c1dddc7c4..0000000000
--- a/lib/orber/examples/Stack/InitialReferences.idl
+++ /dev/null
@@ -1,12 +0,0 @@
-typedef string ObjectId;
-typedef sequence <ObjectId> ObjectIdList;
-
-module Orber {
-interface InitialReferences {
-
- Object get(in ObjectId id);
-
- ObjectIdList list();
-
-};
-};
diff --git a/lib/orber/examples/Stack/Makefile b/lib/orber/examples/Stack/Makefile
deleted file mode 100644
index 5348c624e3..0000000000
--- a/lib/orber/examples/Stack/Makefile
+++ /dev/null
@@ -1,128 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-
-EBIN= ../../ebin
-
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../../vsn.mk
-VSN=$(ORBER_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/orber-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-
-IDL_FILES = \
- stack.idl \
- InitialReferences.idl
-
-GEN_ERL_MODULES = \
- oe_stack \
- StackModule_Stack \
- StackModule_StackFactory \
- StackModule_EmptyStack
-
-MODULES= \
- StackModule_Stack_impl \
- StackModule_StackFactory_impl \
- stack_factory \
- stack_client
-
-GEN_HRL_FILES = \
- oe_stack.hrl \
- StackModule.hrl \
- StackModule_Stack.hrl \
- StackModule_StackFactory.hrl
-
-HRL_FILES=
-
-ERL_FILES= $(MODULES:%=%.erl)
-
-GEN_FILES = $(GEN_ERL_MODULES:%=%.erl) $(GEN_HRL_FILES)
-
-JAVA_CLASSES = \
- StackClient
-
-JAVA_FILES= $(JAVA_CLASSES:%=%.java)
-CLASS_FILES= $(JAVA_CLASSES:%=%.class)
-
-TARGET_FILES = \
- $(GEN_ERL_MODULES:%=$(EBIN)/%.$(EMULATOR)) \
- $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-
-TEST_TARGET_FILES =
-
-CPP_FILES = StackClient.cc
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_IDL_FLAGS += -pa $(ERL_TOP)/lib/orber/ebin -pa $(ERL_TOP)/lib/ic/ebin
-# The -pa option is just used temporary until erlc can handle
-# includes from other directories than ../include .
-ERL_COMPILE_FLAGS += \
- $(ERL_IDL_FLAGS) \
- -pa $(ERL_TOP)/lib/orber -I$(ERL_TOP)/lib/orber
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-debug opt: $(TARGET_FILES)
-
-clean:
- rm -f $(TARGET_FILES) $(GEN_ERL_MODULES:%=%.erl) $(GEN_HRL_FILES) $(CLASS_FILES) IDL-GENERATED
- rm -f errs core *~
-
-docs:
-
-test: $(TEST_TARGET_FILES)
-
-IDL-GENERATED: stack.idl
- $(gen_verbose)erlc $(ERL_IDL_FLAGS) stack.idl
- $(V_at)>IDL-GENERATED
-
-$(GEN_FILES): IDL-GENERATED
-
-$(TARGET_FILES): IDL-GENERATED
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/examples/Stack"
- $(INSTALL_DATA) $(ERL_FILES) $(JAVA_FILES) $(CPP_FILES) $(IDL_FILES) "$(RELSYSDIR)/examples/Stack"
-
-
-release_docs_spec:
-
-
diff --git a/lib/orber/examples/Stack/StackClient.cc b/lib/orber/examples/Stack/StackClient.cc
deleted file mode 100644
index 4d393390c4..0000000000
--- a/lib/orber/examples/Stack/StackClient.cc
+++ /dev/null
@@ -1,97 +0,0 @@
-/**
- * <copyright>
- * <year>2000-2007</year>
- * <holder>Ericsson AB, All Rights Reserved</holder>
- *</copyright>
- *<legalnotice>
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * The Initial Developer of the Original Code is Ericsson AB.
- *</legalnotice>
- */
-/**
- * This module gives an example how it is possible to setup a connection
- * Orbix3.0.1 and Orber3.0.2
- */
-
-
-#define USE_IIOP
-
-#include <iostream.h>
-#include <stdio.h>
-#include <fstream.h>
-#include <stdlib.h>
-
-#include "NamingService.hh"
-#include "InitialReference.hh"
-#include "InitialReferences.hh"
-#include "stack.hh"
-
-
-int main(int argc, char** argv) {
-
- CORBA::Object_ptr nsRef, initRef, objRef;
- InitialReference init;
- Orber::InitialReferences_var initp;
- CosNaming::NamingContext_var Ns;
- CosNaming::NameComponent nc;
- CosNaming::Name_var name;
- StackModule::StackFactory_var stackFac;
- StackModule::Stack_var stack;
-
- if (argc < 3) {
- cout << "usage: " << argv[0] << " <hostname>" << " <srvport>" << endl;
- exit (-1);
- }
-
- string srvHost = argv[1];
- long srvPort = atoi(argv[2]);
-
- cout << "Using host: " << srvHost << " Port: " << srvPort << endl;
-
- try
- {
- // Create Initial reference (objectkey "INIT").
- const string s = init.stringified_ior(srvHost, srvPort);
- initRef = CORBA::Orbix.string_to_object(s);
- initp = Orber::InitialReferences::_narrow(initRef);
- nsRef = initp->get("NameService");
- Ns = CosNaming::NamingContext::_narrow(nsRef);
-
- // Create a name component.
- name = new CosNaming::Name(1);
- name->length(1);
- name[0].id = CORBA::string_dup("StackFactory");
- name[0].kind = CORBA::string_dup("");
-
- // Look up the Object in the NamingService.
- objRef = Ns->resolve(name);
- stackFac = StackModule::StackFactory::_narrow(objRef);
- stack = stackFac->create_stack();
-
- // push & pop
- stack->push(8);
- stack->push(7);
- stack->push(6);
- cout << "Stack: " << stack->pop()
- << " " << stack->pop()
- << " " << stack->pop() << endl;
-
- } catch(...) {
- cerr << "call failed" << endl;
- cerr << "Unexpected exception " << endl;
- exit(1);
- }
- cout << "Completed successfully" << endl;
- return 0;
-}
diff --git a/lib/orber/examples/Stack/StackClient.java b/lib/orber/examples/Stack/StackClient.java
deleted file mode 100644
index 55e967a330..0000000000
--- a/lib/orber/examples/Stack/StackClient.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1997-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-/*
- * Stack example.
- */
-
-package StackModule;
-import org.omg.CORBA.*;
-import org.omg.CORBA.SystemException;
-import org.omg.CORBA.ORB.*;
-
-public class StackClient
-{
- public static void main(String args[])
- {
- org.omg.CORBA.Object objRef;
- StackFactory sfRef = null;
- Stack sRef = null;
- // The argument can look like
- // "corbaname::host:4001/#StackFactory"
- String corbaName = new String(args[0]);
- try{
- ORB orb = ORB.init(args, null);
-
- objRef = orb.string_to_object(corbaName);
- sfRef = StackFactoryHelper.narrow(objRef);
- sRef = sfRef.create_stack();
-
- sRef.push(4);
- sRef.push(7);
- sRef.push(1);
- sRef.push(1);
-
- try{
- System.out.println(sRef.pop());
- System.out.println(sRef.pop());
- System.out.println(sRef.pop());
- System.out.println(sRef.pop());
- // The following operation shall
- // return an EmptyStack exception
- System.out.println(sRef.pop());
- }
- catch(EmptyStack es) {
- System.out.println("Empty stack");
- };
-
- sfRef.destroy_stack(sRef);
- }
- catch(SystemException se)
- {
- System.out.println("Unexpected exception: " + se.toString());
- return;
- }
- }
-}
diff --git a/lib/orber/examples/Stack/StackModule_StackFactory_impl.erl b/lib/orber/examples/Stack/StackModule_StackFactory_impl.erl
deleted file mode 100644
index 76e449971f..0000000000
--- a/lib/orber/examples/Stack/StackModule_StackFactory_impl.erl
+++ /dev/null
@@ -1,41 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% StackModule_StackFactory_impl example file.
-
--module('StackModule_StackFactory_impl').
--include_lib("orber/include/corba.hrl").
--export([create_stack/1, destroy_stack/2, init/1, terminate/2]).
-
-
-init(_Env) ->
- {ok, []}.
-
-terminate(_From, _Reason) ->
- ok.
-
-create_stack(State) ->
- %% Just a create we don't want a link.
- {reply, 'StackModule_Stack':oe_create(), State}.
-
-destroy_stack(State, Stack) ->
- {reply, corba:dispose(Stack), State}.
diff --git a/lib/orber/examples/Stack/StackModule_Stack_impl.erl b/lib/orber/examples/Stack/StackModule_Stack_impl.erl
deleted file mode 100644
index ff4dc90829..0000000000
--- a/lib/orber/examples/Stack/StackModule_Stack_impl.erl
+++ /dev/null
@@ -1,47 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% StackModule_Stack_impl example file.
-
--module('StackModule_Stack_impl').
--include_lib("orber/include/corba.hrl").
--include("StackModule.hrl").
--export([pop/1, push/2, empty/1, init/1, terminate/2]).
-
-
-init(_Env) ->
- {ok, []}.
-
-terminate(_From, _Reason) ->
- ok.
-
-push(Stack, Val) ->
- {reply, ok, [Val | Stack]}.
-
-pop([Val | Stack]) ->
- {reply, Val, Stack};
-pop([]) ->
- corba:raise(#'StackModule_EmptyStack'{}).
-
-empty(_) ->
- {reply, ok, []}.
-
diff --git a/lib/orber/examples/Stack/stack.idl b/lib/orber/examples/Stack/stack.idl
deleted file mode 100644
index f21f93917b..0000000000
--- a/lib/orber/examples/Stack/stack.idl
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef _STACK_IDL
-#define _STACK_IDL
-
-module StackModule {
-
- exception EmptyStack {};
-
- interface Stack {
-
- long pop() raises(StackModule::EmptyStack);
-
- void push(in long value);
-
- void empty();
-
- };
-
- interface StackFactory {
-
- StackModule::Stack create_stack();
- void destroy_stack(in StackModule::Stack s);
-
- };
-
-};
-
-#endif
diff --git a/lib/orber/examples/Stack/stack_client.erl b/lib/orber/examples/Stack/stack_client.erl
deleted file mode 100644
index 6e32195b1b..0000000000
--- a/lib/orber/examples/Stack/stack_client.erl
+++ /dev/null
@@ -1,56 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% stack_client example file.
-
--module('stack_client').
-
--export([run/0]).
-
-
-run() ->
- case catch corba:string_to_object("corbaname:rir:/NameService#StackFactory") of
- {'EXCEPTION', _E} ->
- io:format("The stack factory server is not registered~n",[]);
- SF ->
- %% Create the stack
- SS = 'StackModule_StackFactory':create_stack(SF),
-
- 'StackModule_Stack':push(SS, 4),
- 'StackModule_Stack':push(SS, 7),
- 'StackModule_Stack':push(SS, 1),
- 'StackModule_Stack':push(SS, 1),
- Res = 'StackModule_Stack':pop(SS),
- io:format("~w~n", [Res]),
- Res1 = 'StackModule_Stack':pop(SS),
- io:format("~w~n", [Res1]),
- Res2 = 'StackModule_Stack':pop(SS),
- io:format("~w~n", [Res2]),
- Res3 = 'StackModule_Stack':pop(SS),
- io:format("~w~n", [Res3]),
-
- %% Remove the stack
- 'StackModule_StackFactory':destroy_stack(SF, SS)
-
- end.
-
-
diff --git a/lib/orber/examples/Stack/stack_factory.erl b/lib/orber/examples/Stack/stack_factory.erl
deleted file mode 100644
index b5b455ae5a..0000000000
--- a/lib/orber/examples/Stack/stack_factory.erl
+++ /dev/null
@@ -1,38 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% stack_factory example file.
-
--module('stack_factory').
--include_lib("orber/include/corba.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming.hrl").
--include_lib("orber/COSS/CosNaming/lname.hrl").
-
--export([start/0]).
-
-start() ->
- SFok = 'StackModule_StackFactory':oe_create(),
- NS = corba:resolve_initial_references("NameService"),
- NC = lname_component:set_id(lname_component:create(), "StackFactory"),
- N = lname:insert_component(lname:create(), 1, NC),
- 'CosNaming_NamingContext':bind(NS, N, SFok).
-
diff --git a/lib/orber/include/corba.hrl b/lib/orber/include/corba.hrl
deleted file mode 100644
index fb1c2a5a94..0000000000
--- a/lib/orber/include/corba.hrl
+++ /dev/null
@@ -1,149 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%------------------------------------------------------------
-%% File: corba.hrl
-%%
-%% Description:
-%% Standard header file for the Orber Erlang CORBA environment
-%%
-%%-----------------------------------------------------------------
--ifndef(corba_hrl).
--define(corba_hrl, true).
-
-%%
-%% Implementation repository record (not used and can therefor be changed)
-%%
--record(orb_ImplDef, {node, module, typename, start=start, args=[[]], pid}).
-
-%%
-%% Any record
-%%
--record(any, {typecode, value}).
-
-%%
-%% Any record
-%%
--record(fixed, {digits, scale, value}).
-
-%%
-%% Service context record
-%%
--record('IOP_ServiceContext', {context_id, context_data}).
-
-%%
-%% Exception recod for the resolve initial reference functions
-%%
--record('InvalidName', {'OE_ID'="IDL:omg.org/CORBA/ORB/InvalidName:1.0"}).
-
-%% Orber OMG assigned TAG's
-%% Service Context IDs 0x45524904 - 0x45524907 ("ERI\x04" - "ERI\x07")
-%% Component IDs 0x45524904 - 0x45524907 ("ERI\x04" - "ERI\x07")
-%% ORB type IDs 0x45524904 - 0x45524907 ("ERI\x04" - "ERI\x07")
--define(ORBER_ORB_TYPE_1, 16#45524904).
-%-define(ORBER_ORB_TYPE_2, 16#45524905).
-%-define(ORBER_ORB_TYPE_3, 16#45524906).
-%-define(ORBER_ORB_TYPE_4, 16#45524907).
-
-%-define(ORBER_COMPONENT_1, 16#45524904).
-%-define(ORBER_COMPONENT_2, 16#45524905).
-%-define(ORBER_COMPONENT_3, 16#45524906).
-%-define(ORBER_COMPONENT_4, 16#45524907).
-
--define(ORBER_GENERIC_CTX_ID, 16#45524904).
-%-define(ORBER_SERVICE_CTX_2, 16#45524905).
-%-define(ORBER_SERVICE_CTX_3, 16#45524906).
-%-define(ORBER_SERVICE_CTX_4, 16#45524907).
-
-%%
-%% System exceptions
-%%
-
-%% VMCID
-%% VMCID base assigned to OMG
--define(CORBA_OMGVMCID, 16#4f4d0000).
-
-%% Orber's VMCID base - "ER\x00\x00" - "ER\x0f\xff".
-%% Range 16#45520000 -> 16#45520fff
--define(ORBER_VMCID, 16#45520000).
-
-%% Some other Vendors VMCID bases.
--define(IONA_VMCID_1, 16#4f4f0000).
--define(IONA_VMCID_2, 16#49540000).
--define(SUN_VMCID, 16#53550000).
--define(BORLAND_VMCID, 16#56420000).
--define(TAO_VMCID, 16#54410000).
--define(PRISMTECH_VMCID,16#50540000).
-
--define(ex_body, {'OE_ID'="", minor=?ORBER_VMCID, completion_status}).
-
--record('UNKNOWN', ?ex_body).
--record('BAD_PARAM', ?ex_body).
--record('NO_MEMORY', ?ex_body).
--record('IMP_LIMIT', ?ex_body).
--record('COMM_FAILURE', ?ex_body).
--record('INV_OBJREF', ?ex_body).
--record('NO_PERMISSION', ?ex_body).
--record('INTERNAL', ?ex_body).
--record('MARSHAL', ?ex_body).
--record('INITIALIZE', ?ex_body).
--record('NO_IMPLEMENT', ?ex_body).
--record('BAD_TYPECODE', ?ex_body).
--record('BAD_OPERATION', ?ex_body).
--record('NO_RESOURCES', ?ex_body).
--record('NO_RESPONSE', ?ex_body).
--record('PERSIST_STORE', ?ex_body).
--record('BAD_INV_ORDER', ?ex_body).
--record('TRANSIENT', ?ex_body).
--record('FREE_MEM', ?ex_body).
--record('INV_IDENT', ?ex_body).
--record('INV_FLAG', ?ex_body).
--record('INTF_REPOS', ?ex_body).
--record('BAD_CONTEXT', ?ex_body).
--record('OBJ_ADAPTER', ?ex_body).
--record('DATA_CONVERSION', ?ex_body).
--record('OBJECT_NOT_EXIST', ?ex_body).
--record('TRANSACTION_REQUIRED', ?ex_body).
--record('TRANSACTION_ROLLEDBACK', ?ex_body).
--record('INVALID_TRANSACTION', ?ex_body).
--record('INV_POLICY', ?ex_body).
--record('CODESET_INCOMPATIBLE', ?ex_body).
--record('REBIND', ?ex_body).
--record('TIMEOUT', ?ex_body).
--record('TRANSACTION_UNAVAILABLE', ?ex_body).
--record('TRANSACTION_MODE', ?ex_body).
--record('BAD_QOS', ?ex_body).
-
-%% Defines for the enum exception_type (is also used for reply_status)
--define(NO_EXCEPTION, 'no_exception').
--define(USER_EXCEPTION, 'user_exception').
--define(SYSTEM_EXCEPTION, 'system_exception').
-
-%% Defines for the enum completion_status.
--define(COMPLETED_YES, 'COMPLETED_YES').
--define(COMPLETED_NO, 'COMPLETED_NO').
--define(COMPLETED_MAYBE, 'COMPLETED_MAYBE').
-
-
--undef(ex_body).
-
-
--endif.
diff --git a/lib/orber/include/ifr_types.hrl b/lib/orber/include/ifr_types.hrl
deleted file mode 100644
index ceb8bbe885..0000000000
--- a/lib/orber/include/ifr_types.hrl
+++ /dev/null
@@ -1,73 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : ifr_types.hrl
-%% Purpose : Record definitions for structs used in the interface repository
-%%----------------------------------------------------------------------
-
-
-%%%----------------------------------------------------------------------
-%%% *********************************************************************
-%%% * *
-%%% * PLEASE NOTE *
-%%% * *
-%%% * If a record is removed or added in this file, select/2 in *
-%%% * orber_ifr.erl _MUST_ be updated accordingly. *
-%%% * *
-%%% *********************************************************************
-%%%----------------------------------------------------------------------
-
--record(contained_description, {kind, value}).
-
--record(structmember, {name, type, type_def}).
-
--record(unionmember, {name, label, type, type_def}).
-
--record(container_description, {contained_object, kind, value}).
-
--record(moduledescription, {name, id, defined_in, version}).
-
--record(constantdescription, {name, id, defined_in, version, type, value}).
-
--record(typedescription, {name, id, defined_in, version, type}).
-
--define(make_typedescription(Obj,Object_type),
- #typedescription{name = Obj#Object_type.name,
- id = Obj#Object_type.id,
- defined_in = Obj#Object_type.defined_in,
- version = Obj#Object_type.version,
- type = Obj#Object_type.type}).
-
--record(exceptiondescription, {name, id, defined_in, version, type}).
-
--record(attributedescription, {name, id, defined_in, version, type, mode}).
-
--record(parameterdescription, {name, type, type_def, mode}).
-
--record(operationdescription, {name, id, defined_in, version, result, mode,
- contexts, parameters, exceptions}).
-
--record(fullinterfacedescription, {name, id, defined_in, version, operations,
- attributes, base_interfaces, type}).
-
--record(interfacedescription, {name, id, defined_in, version,
- base_interfaces}).
diff --git a/lib/orber/include/orber_pi.hrl b/lib/orber/include/orber_pi.hrl
deleted file mode 100644
index 7d1fa1edf2..0000000000
--- a/lib/orber/include/orber_pi.hrl
+++ /dev/null
@@ -1,77 +0,0 @@
-%%----------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_pi.hrl
-%% Purpose :
-%%----------------------------------------------------------------------
-
-%%=============== CONSTANTS ==================================
-%%-------- PortableInterceptor::Interceptor (local) ----------
-%% Reply Status
--define('PortableInterceptor_SUCCESSFUL', 0).
--define('PortableInterceptor_SYSTEM_EXCEPTION', 1).
--define('PortableInterceptor_USER_EXCEPTION', 2).
--define('PortableInterceptor_LOCATION_FORWARD', 3).
--define('PortableInterceptor_LOCATION_FORWARD_PERMANENT', 4).
--define('PortableInterceptor_TRANSPORT_RETRY', 5).
-
-
-%%=============== EXCEPTIONS =================================
-%%-------- PortableInterceptor::Interceptor (local) ----------
-%% forward eq. CORBA::Object, premanent eq. boolean
--record('PortableInterceptor_ForwardRequest', {'OE_ID'="local", forward, permanent}).
--record('PortableInterceptor_InvalidSlot', {'OE_ID'="local"}).
-
-%%--------------- IOP_N::Codec (local) -----------------------
--record('IOP_N_Codec_InvalidTypeForEncoding', {'OE_ID'="local"}).
--record('IOP_N_Codec_FormatMismatch', {'OE_ID'="local"}).
--record('IOP_N_Codec_TypeMismatch', {'OE_ID'="local"}).
-
-%%--------------- IOP_N (Module level) -----------------------
--define('IOP_N_ENCODING_CDR_ENCAPS', 0).
-
-%%--------------- IOP_N::CodecFactory (Module level) ---------
--record('IOP_N_CodecFactory_UnknownEncoding', {'OE_ID'="local"}).
-
-%%--------------- IOP_N::ORBInitInfo (Module level) ----------
-%% name eq. string()
--record('PortableInterceptor_ORBInitInfo_DuplicateName', {'OE_ID'="local", name}).
--record('PortableInterceptor_ORBInitInfo_InvalidName', {'OE_ID'="local"}).
-
-
-%%=============== DATA STRUCTURES ============================
-%%--------------- IOP_N (Module level) -----------------------
--record('IOP_N_Encoding',
- {format, %% Currently only 'IOP_N_ENCODING_CDR_ENCAPS' allowed.
- major_version, %% 1 only
- minor_version}). %% 0,1 or 2
-
-
-%%--------------- Dynamic (Module level) ---------------------
-%% argument eq. #any{},
-%% mode eq. CORBA::ParameterMode - PARAM_IN, PARAM_OUT, PARAM_INOUT.
--record('Dynamic_Parameter',
- {argument,
- mode}).
-
-%%--------------- END OF MODULE ------------------------------
-
diff --git a/lib/orber/info b/lib/orber/info
deleted file mode 100644
index c92ea38dd8..0000000000
--- a/lib/orber/info
+++ /dev/null
@@ -1,2 +0,0 @@
-group: orb
-short: A CORBA Object Request Broker
diff --git a/lib/orber/java_src/Makefile b/lib/orber/java_src/Makefile
deleted file mode 100644
index d8a8843d00..0000000000
--- a/lib/orber/java_src/Makefile
+++ /dev/null
@@ -1,42 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(ORBER_VSN)
-
-# ----------------------------------------------------
-# Common Macros
-# ----------------------------------------------------
-
-SUB_DIRECTORIES = Orber
-
-SPECIAL_TARGETS =
-
-# ----------------------------------------------------
-# Default Subdir Targets
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_subdir.mk
-
diff --git a/lib/orber/java_src/Orber/InitialReference.java b/lib/orber/java_src/Orber/InitialReference.java
deleted file mode 100644
index 35a8c2437b..0000000000
--- a/lib/orber/java_src/Orber/InitialReference.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1997-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- *
- */
-/**
- * InitialReference is a class which generates the INIT reference
- * which can be used by the InitialReferences interface.
- */
-package Orber;
-
-public class InitialReference
-{
-
- /**
- * Constructor.
- */
- public InitialReference(){;}
-
- /**
- * Returns the stringified objectreference to the initial reference server
- */
- public String stringified_ior(String host, int port)
- {
- String iorByteString;
- String profileData;
- String iorString;
-
- // byte_order followed by ' {"", [{0, '
- // char iorBytesFirstPart[] = {0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0};
- char iorBytesFirstPart[] = {0,0,0,0,0,0,0,32,73,68,76,58,79,114,98,101,114,47,73,110,105,116,105,97,108,82,101,102,101,114,101,110,99,101,115,58,49,46,48,0,0,0,0,1,0,0,0,0};
- // the objectkey "INIT
- char iorBytesLastPart[] = {0,0,0,4,73,78,73,84};
-
- // Fix the ProfileData struct.
- char pdPrefix[] = {0,1,0,0};
- char nullbyte[] = {0};
- profileData = new String(pdPrefix) + enc_ulong(host.length() + 1) + host + new String(nullbyte);
- profileData = align(profileData, 2);
- profileData += enc_ushort(port);
- profileData = align(profileData, 4);
- profileData += new String(iorBytesLastPart);
- // Fix the whole IOR
- iorByteString = new String(iorBytesFirstPart) + enc_ulong(profileData.length()) +
- profileData;
-
- // System.out.print("Start[" + profileData.length() + "]");
- // System.out.print("[");
- // for(int x = 0; x < iorByteString.length(); x++)
- // {
- // System.out.print((int) iorByteString.charAt(x) + ",");
- // }
- // System.out.println("]");
-
- iorString = createIOR(iorByteString);
- // System.out.println(iorString);
- return iorString;
- }
-
-
- private String enc_ushort(int s)
- {
- char byteArray[] = {(char) ((s >>> 8) & 0xFF),
- (char) ((s >>> 0) & 0xFF)};
-
- return new String(byteArray);
- }
-
- private String enc_ulong(int l)
- {
- char byteArray[] = {(char) ((l >>> 24) & 0xFF),
- (char) ((l >>> 16) & 0xFF),
- (char) ((l >>> 8) & 0xFF),
- (char) ((l >>> 0) & 0xFF)};
-
- return new String(byteArray);
-
- }
-
- private String createIOR(String bytes)
- {
- int i;
- StringBuffer sb = new StringBuffer("IOR:");
-
- for(i = 0; i < bytes.length(); i++)
- {
- int b = bytes.charAt(i);
- if(b<0) b+= 256;
- int n1 = b / 16;
- int n2 = b % 16;
- int c1 = (n1 < 10) ? ('0' + n1) : ('a' + (n1 - 10));
- int c2 = (n2 < 10) ? ('0' + n2) : ('a' + (n2 - 10));
- sb.append((char)c1);
- sb.append((char)c2);
- }
-
- return sb.toString();
- }
-
- private String align(String buffer, int alignment)
- {
- String s = buffer;
- char nullbyte[] = {0};
-
- int remainder = alignment - (buffer.length() % alignment);
- if (remainder == alignment) return s;
-
- for (int i = 0; i < remainder; i++)
- {
- s += new String(nullbyte);
- }
- return s;
- }
-
-
-}
diff --git a/lib/orber/java_src/Orber/Makefile b/lib/orber/java_src/Orber/Makefile
deleted file mode 100644
index 3414fb2e76..0000000000
--- a/lib/orber/java_src/Orber/Makefile
+++ /dev/null
@@ -1,71 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../../vsn.mk
-VSN=$(ORBER_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/orber-$(VSN)
-
-#
-# JAVA macros
-#
-JAVA_CLASSES = \
- InitialReference
-
-JAVA_FILES= $(JAVA_CLASSES:%=%.java)
-
-CLASSPATH = ../..
-
-# ----------------------------------------------------
-# Flags
-# ----------------------------------------------------
-JAVA_OPTIONS =
-
-# ----------------------------------------------------
-# Make Rules
-# ----------------------------------------------------
-
-debug opt:
-
-clean:
-
-docs:
-
-# ----------------------------------------------------
-# Release Targets
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/java_src/Orber"
- $(INSTALL_DATA) $(JAVA_FILES) "$(RELSYSDIR)/java_src/Orber"
-
-release_docs_spec:
-
diff --git a/lib/orber/prebuild.skip b/lib/orber/prebuild.skip
deleted file mode 100644
index d6c7895b9c..0000000000
--- a/lib/orber/prebuild.skip
+++ /dev/null
@@ -1,5 +0,0 @@
-priv
-src/PKIXAttributeCertificate.asn1db
-src/PKIX1Explicit88.asn1db
-src/OrberCSIv2.asn1db
-src/PKIX1Implicit88.asn1db
diff --git a/lib/orber/priv/Makefile b/lib/orber/priv/Makefile
deleted file mode 100644
index 268c16c4c7..0000000000
--- a/lib/orber/priv/Makefile
+++ /dev/null
@@ -1,67 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2001-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-include ../vsn.mk
-VSN = $(ORBER_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/orber-$(VSN)
-
-#
-# Macros
-#
-HELP_FILES = \
- orber_help.txt
-
-HTML_FILES = \
- orber.tool \
- blank.html \
- info_frames.html \
- main_frame.html \
- start_info.html
-
-#
-# Rules
-#
-
-debug opt:
-
-docs:
-
-clean:
-
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/priv"
- $(INSTALL_DATA) $(HELP_FILES) $(HTML_FILES) "$(RELSYSDIR)/priv"
-
-release_docs_spec:
-
-
diff --git a/lib/orber/priv/Orber/.gitignore b/lib/orber/priv/Orber/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/orber/priv/Orber/.gitignore
+++ /dev/null
diff --git a/lib/orber/priv/bin/.gitignore b/lib/orber/priv/bin/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/orber/priv/bin/.gitignore
+++ /dev/null
diff --git a/lib/orber/priv/blank.html b/lib/orber/priv/blank.html
deleted file mode 100644
index 44e86908a0..0000000000
--- a/lib/orber/priv/blank.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<HTML>
-<HEAD></HEAD>
-<BODY BGCOLOR="#FFFFFF">
-&nbsp;
-</BODY>
-</HTML> \ No newline at end of file
diff --git a/lib/orber/priv/info_frames.html b/lib/orber/priv/info_frames.html
deleted file mode 100644
index 75456a67a4..0000000000
--- a/lib/orber/priv/info_frames.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<HTML>
-<HEAD>
-<TITLE>OrberWeb</TITLE>
-</HEAD>
-<FRAMESET ROWS="85%,15%" BORDER="0">
-<FRAME NAME="main" SRC="./start_info.html">
-<FRAME NAME="proc_data" SRC="./blank.html">
-</FRAMESET>
-</HTML> \ No newline at end of file
diff --git a/lib/orber/priv/main_frame.html b/lib/orber/priv/main_frame.html
deleted file mode 100644
index 056a92812e..0000000000
--- a/lib/orber/priv/main_frame.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<HTML>
-<HEAD>
-<TITLE>OrberWeb</TITLE>
-</HEAD>
-<FRAMESET COLS="15%,85%" >
- <FRAME NAME="left" SRC="/orber_erl/orber_web_server/menu">
- <FRAME NAME="main" SRC="./info_frames.html">
-</FRAMESET>
-</HTML> \ No newline at end of file
diff --git a/lib/orber/priv/obj/.gitignore b/lib/orber/priv/obj/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/orber/priv/obj/.gitignore
+++ /dev/null
diff --git a/lib/orber/priv/orber.tool b/lib/orber/priv/orber.tool
deleted file mode 100644
index 910a7d7e45..0000000000
--- a/lib/orber/priv/orber.tool
+++ /dev/null
@@ -1,2 +0,0 @@
-{version,"1.2"}.
-[{config_func,{orber_web_server,config_data,[]}}].
diff --git a/lib/orber/priv/orber_help.txt b/lib/orber/priv/orber_help.txt
deleted file mode 100644
index a6580dc30a..0000000000
--- a/lib/orber/priv/orber_help.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
- Help for the Orber administration tool
- --------------------------------------
-
-
-
-
-
- The purpose of this tool is to supply an easy way to
- access Orber nodes and via a GUI explore:
- - NameService
- - Configuration settings
- - Interface Repository
-
- All nodes that are known to this tool is shown in the node
- window, normally this is all Erlang nodes visible with the
- [node()|nodes()] commands.
-
-
-The Node window
----------------
-
- The node window monitor nodes.
-
-
-Technical Detail
-----------------
-
- Trouble shooting
- ----------------
-
- Q. Why doesn't all my nodes show up in the node window?
-
- A. Are the nodes visible with the [node()|nodes()] commands
- in the shell? If not you must do net:ping(NodeName) to add
- nodes to the Erlang distribution.
-
- Q. When trying to access a node I get no valid response?
-
- A. Make sure that Orber is running on the node.
diff --git a/lib/orber/priv/start_info.html b/lib/orber/priv/start_info.html
deleted file mode 100644
index 0ad521c90a..0000000000
--- a/lib/orber/priv/start_info.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<HTML>
-<HEAD>
-</HEAD>
-<BODY BGCOLOR="#FFFFFF">
-<TABLE WIDTH=100% HEIGHT=100%>
-<TR VALIGN="middle">
-<TD ALIGN="center">
-
-<TABLE WIDTH="60%">
-<TR>
-<TD ALIGN="center">
-<FONT SIZE=6>Welcome to the Web based Orber Admin Tool
-</FONT></TD>
-</TR>
-
-<TR>
-<TD><BR><BR><BR><BR>
-</TD>
-</TR>
-
-<TR>
-<TD ALIGN="center">&nbsp;
-</TD>
-</TR>
-</TABLE>
-
-</TD>
-</TR>
-</TABLE>
-</BODY>
-</HTML> \ No newline at end of file
diff --git a/lib/orber/src/CORBA.idl b/lib/orber/src/CORBA.idl
deleted file mode 100644
index 3cd8790f49..0000000000
--- a/lib/orber/src/CORBA.idl
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef _CORBA_IDL
-#define _CORBA_IDL
-
-#pragma prefix "omg.org"
-
-//******************************************************************
-//
-//Policy Object:
-//
-//******************************************************************
-
-module CORBA {
-
- // Policy typedefs
- typedef unsigned long PolicyType;
- typedef string Identifier;
- typedef string ScopedName;
- typedef string RepositoryId;
-
-};
-
-#endif
diff --git a/lib/orber/src/Makefile b/lib/orber/src/Makefile
deleted file mode 100644
index 7fec29a000..0000000000
--- a/lib/orber/src/Makefile
+++ /dev/null
@@ -1,263 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/orber-$(ORBER_VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-
-MODULES= \
- orber \
- corba \
- corba_boa \
- corba_object \
- any \
- iop_ior \
- orber_tc \
- orber_typedefs \
- orber_request_number \
- orber_objectkeys \
- orber_initial_references \
- cdrlib \
- cdr_encode \
- cdr_decode \
- orber_iiop \
- orber_iiop_net \
- orber_iiop_net_accept \
- orber_iiop_insup \
- orber_iiop_inproxy \
- orber_iiop_inrequest \
- orber_iiop_pm \
- orber_iiop_outsup \
- orber_iiop_outproxy \
- orber_iiop_socketsup \
- orber_socket \
- orber_ifr \
- orber_ifr_aliasdef \
- orber_ifr_arraydef \
- orber_ifr_attributedef \
- orber_ifr_constantdef \
- orber_ifr_contained \
- orber_ifr_container \
- orber_ifr_enumdef \
- orber_ifr_exceptiondef \
- orber_ifr_idltype \
- orber_ifr_interfacedef \
- orber_ifr_irobject \
- orber_ifr_moduledef \
- orber_ifr_operationdef \
- orber_ifr_orb \
- orber_ifr_primitivedef \
- orber_ifr_repository \
- orber_ifr_sequencedef \
- orber_ifr_stringdef \
- orber_ifr_wstringdef \
- orber_ifr_structdef \
- orber_ifr_typecode \
- orber_ifr_typedef \
- orber_ifr_uniondef \
- orber_ifr_fixeddef \
- orber_ifr_utils \
- OrberApp_IFR_impl \
- orber_pi \
- orber_web \
- orber_web_server \
- orber_iiop_tracer \
- orber_iiop_tracer_silent \
- orber_iiop_tracer_stealth \
- fixed \
- orber_exceptions \
- orber_diagnostics \
- orber_acl \
- orber_env \
- orber_tb
-
-ASN_MODULES = OrberCSIv2
-ASN_SET = $(ASN_MODULES:%=%.set.asn)
-ASN_ASNS = $(ASN_MODULES:%=%.asn1)
-GEN_ASN_ERL = $(ASN_MODULES:%=%.erl)
-GEN_ASN_HRL = $(ASN_MODULES:%=%.hrl)
-GEN_ASN_DBS = $(ASN_MODULES:%=%.asn1db)
-GEN_ASN_TABLES = $(ASN_MODULES:%=%.table)
-
-PKIX_FILES = \
- OrberCSIv2.asn1 \
- PKIXAttributeCertificate.asn1 \
- PKIX1Explicit88.asn1 \
- PKIX1Algorithms88.asn1 \
- PKIX1Implicit88.asn1 \
- OrberCSIv2.set.asn
-
-EXTERNAL_HRL_FILES= ../include/corba.hrl \
- ../include/ifr_types.hrl \
- ../include/orber_pi.hrl
-
-INTERNAL_HRL_FILES = \
- orber_iiop.hrl \
- ifr_objects.hrl \
- orber_ifr.hrl
-
-ERL_FILES= $(MODULES:%=%.erl)
-
-GEN_ERL_FILES1 = \
- oe_erlang.erl \
- erlang_pid.erl \
- erlang_port.erl \
- erlang_ref.erl \
- erlang_binary.erl
-
-GEN_ERL_FILES2 = \
- oe_CORBA.erl
-
-GEN_ERL_FILES3 = \
- oe_OrberIFR.erl \
- OrberApp_IFR.erl
-
-GEN_ERL_FILES = $(GEN_ERL_FILES1) $(GEN_ERL_FILES2) \
- $(GEN_ERL_FILES3) \
-# $(GEN_ASN_ERL)
-
-GEN_HRL_FILES1 = \
- oe_erlang.hrl \
- erlang.hrl
-
-GEN_HRL_FILES2 = \
- CORBA.hrl \
- oe_CORBA.hrl
-
-GEN_HRL_FILES3 = \
- OrberApp_IFR.hrl \
- oe_OrberIFR.hrl \
- OrberApp.hrl
-
-GEN_HRL_FILES_EXT = $(GEN_HRL_FILES1)
-
-GEN_HRL_FILES_LOC = $(GEN_HRL_FILES2) $(GEN_HRL_FILES3) \
-# $(GEN_ASN_HRL)
-
-
-GEN_FILES = \
- $(GEN_ERL_FILES) \
- $(GEN_HRL_FILES_LOC) \
- $(GEN_HRL_FILES_EXT) \
-# $(GEN_ASN_DBS) \
-# $(GEN_ASN_TABLES)
-
-TARGET_FILES = \
- $(GEN_ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR)) \
- $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-
-APPUP_FILE = orber.appup
-APPUP_SRC = $(APPUP_FILE).src
-APPUP_TARGET = $(EBIN)/$(APPUP_FILE)
-
-APP_FILE = orber.app
-APP_SRC = $(APP_FILE).src
-APP_TARGET = $(EBIN)/$(APP_FILE)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_IDL_FLAGS += -pa $(ERL_TOP)/lib/orber/ebin
-# The -pa option is just used temporary until erlc can handle
-# includes from other directories than ../include .
-ERL_COMPILE_FLAGS += $(ERL_IDL_FLAGS) \
- -I$(ERL_TOP)/lib/orber/include \
- +'{parse_transform,sys_pre_attributes}' \
- +'{attribute,insert,app_vsn,"orber_$(ORBER_VSN)"}'
-
-ASN_FLAGS = -bber +der +compact_bit_string +nowarn_unused_record
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-debug:
- @${MAKE} TYPE=debug opt
-
-opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
-
-clean:
- rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET) IDL-GENERATED
- rm -f errs core *~
-
-$(APP_TARGET): $(APP_SRC) ../vsn.mk
- $(vsn_verbose)sed -e 's;%VSN%;$(ORBER_VSN);' $< > $@
-
-$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- $(vsn_verbose)sed -e 's;%VSN%;$(ORBER_VSN);' $< > $@
-
-docs:
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-IDL-GENERATED: $(ERL_TOP)/lib/ic/include/erlang.idl CORBA.idl OrberIFR.idl
- $(gen_verbose)erlc $(ERL_IDL_FLAGS) $(ERL_TOP)/lib/ic/include/erlang.idl
- $(V_at)erlc $(ERL_IDL_FLAGS) CORBA.idl
- $(V_at)erlc $(ERL_IDL_FLAGS) +'{this,"Orber::IFR"}' OrberIFR.idl
- $(V_at)>IDL-GENERATED
-
-$(GEN_ERL_FILES): IDL-GENERATED
-$(TARGET_FILES): IDL-GENERATED
-
-$(GEN_ASN_ERL) $(GEN_ASN_HRL): OrberCSIv2.asn1 OrberCSIv2.set.asn
- $(asn_verbose)erlc $(ERL_COMPILE_FLAGS) $(ASN_FLAGS) +'{inline,"OrberCSIv2"}' OrberCSIv2.set.asn
- $(V_at)rm -f $(GEN_ASN_ERL:%.erl=%.beam)
-
-# erlc $(ERL_COMPILE_FLAGS) $(ASN_FLAGS) OrberCSIv2.asn1 ;\
-# erlc $(GEN_ASN_ERL)
-# Use the following when we safely can inline the ASN1 runtime code.
-# Requires igor (part of syntax_tools (introduced in R10B
-# erlc $(ERL_COMPILE_FLAGS) $(ASN_FLAGS) +'{inline,"OrberCSIv2"}' OrberCSIv2.set.asn ; \
-
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
- $(INSTALL_DIR) "$(RELSYSDIR)/src"
- $(INSTALL_DATA) $(ERL_FILES) $(YRL_FILE) $(GEN_HRL_FILES_LOC) $(INTERNAL_HRL_FILES) "$(RELSYSDIR)/src"
- $(INSTALL_DIR) "$(RELSYSDIR)/include"
- $(INSTALL_DATA) $(EXTERNAL_HRL_FILES) $(GEN_HRL_FILES_EXT) "$(RELSYSDIR)/include"
-
-
-release_docs_spec:
-
-
diff --git a/lib/orber/src/OrberApp_IFR_impl.erl b/lib/orber/src/OrberApp_IFR_impl.erl
deleted file mode 100644
index 069f4ad17a..0000000000
--- a/lib/orber/src/OrberApp_IFR_impl.erl
+++ /dev/null
@@ -1,102 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File : OrberApp_IFR_impl.erl
-%% Purpose :
-%%-----------------------------------------------------------------
-
--module('OrberApp_IFR_impl').
-
-%%--------------- INCLUDES -----------------------------------
--include_lib("orber/src/orber_iiop.hrl").
--include_lib("orber/include/ifr_types.hrl").
--include_lib("orber/include/corba.hrl").
-
-%%--------------- IMPORTS ------------------------------------
-
-%%--------------- EXPORTS ------------------------------------
-%% External
--export([get_absolute_name/3, get_user_exception_type/3]).
-
-%%--------------- gen_server specific exports ----------------
--export([init/1, terminate/2, code_change/3]).
-
-%%--------------- LOCAL DEFINITIONS --------------------------
--define(DEBUG_LEVEL, 6).
-
-
-init(State) ->
- {ok, State}.
-terminate(_Reason, _State) ->
- ok.
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%-----------------------------------------------------------
-%%------- Exported external functions -----------------------
-%%-----------------------------------------------------------
-%%----------------------------------------------------------%
-%% function : get_absolute_name
-%% Arguments: TypeID - string()
-%% Returns : Fully scooped name - string()
-%%-----------------------------------------------------------
-
-get_absolute_name(_OE_THIS, _State, []) ->
- orber:dbg("[~p] OrberApp_IFR_impl:get_absolute_name(); no TypeID supplied.",
- [?LINE], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 11), completion_status=?COMPLETED_MAYBE});
-
-get_absolute_name(_OE_THIS, State, TypeID) ->
- Rep = orber_ifr:find_repository(),
- Key = orber_ifr:'Repository_lookup_id'(Rep, TypeID),
- [$:, $: |N] = orber_ifr:'Contained__get_absolute_name'(Key),
- {reply, change_colons_to_underscore(N, []), State}.
-
-change_colons_to_underscore([$:, $: | T], Acc) ->
- change_colons_to_underscore(T, [$_ |Acc]);
-change_colons_to_underscore([H |T], Acc) ->
- change_colons_to_underscore(T, [H |Acc]);
-change_colons_to_underscore([], Acc) ->
- lists:reverse(Acc).
-
-%%----------------------------------------------------------%
-%% function : get_user_exception_type
-%% Arguments: TypeID - string()
-%% Returns : Fully scooped name - string()
-%%-----------------------------------------------------------
-
-get_user_exception_type(_OE_THIS, _State, []) ->
- orber:dbg("[~p] OrberApp_IFR_impl:get_user_exception_type(); no TypeID supplied.",
- [?LINE], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 11), completion_status=?COMPLETED_MAYBE});
-
-get_user_exception_type(_OE_THIS, State, TypeId) ->
- Rep = orber_ifr:find_repository(),
- ExceptionDef = orber_ifr:'Repository_lookup_id'(Rep, TypeId),
- ContainedDescr = orber_ifr_exceptiondef:describe(ExceptionDef),
- ExceptionDescr = ContainedDescr#contained_description.value,
- {reply, ExceptionDescr#exceptiondescription.type, State}.
-
-
-%%--------------- LOCAL FUNCTIONS ----------------------------
-%%--------------- MISC FUNCTIONS, E.G. DEBUGGING -------------
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/orber/src/OrberCSIv2.asn1 b/lib/orber/src/OrberCSIv2.asn1
deleted file mode 100644
index d776ce2b47..0000000000
--- a/lib/orber/src/OrberCSIv2.asn1
+++ /dev/null
@@ -1,45 +0,0 @@
-OrberCSIv2 DEFINITIONS ::=
-
-BEGIN
-
- IMPORTS
-
- -- IMPORTed module OIDs MAY change if [PKIXPROF] changes
- -- PKIX1Explicit88 Certificate Extensions
- Certificate
- FROM PKIX1Explicit88 {iso(1) identified-organization(3)
- dod(6) internet(1) security(5) mechanisms(5)
- pkix(7) id-mod(0) id-pkix1-explicit-88(1)}
- -- PKIXAttributeCertificate
- AttributeCertificate
- FROM PKIXAttributeCertificate {iso(1) identified-organization(3) dod(6)
- internet(1) security(5) mechanisms(5) pkix(7) id-mod(0)
- id-mod-attribute-cert(12)};
-
-
-
- -- Authorization Token
- -- AttributeCertificate - [IETF ID PKIXAC].
- -- Certificate - [IETF RFC 2459].
-
- VerifyingCertChain ::= SEQUENCE OF Certificate
-
- AttributeCertChain ::= SEQUENCE {
- attributeCert AttributeCertificate,
- certificateChain VerifyingCertChain
- }
-
-
- -- The ASN.1 encoding of identity tokens of this type is defined
- -- as follows (ITTX509CertChain):
- CertificateChain ::= SEQUENCE SIZE (1..MAX) OF Certificate
-
-
- -- The object identifier allocated for the GSSUP mechanism is defined as follows:
- -- GSS Exported Name Object Form for GSSUP Mechanism
- gssup-mechanism OBJECT IDENTIFIER ::= { iso-itu-t (2) international-organization (23) omg (130) security (1) authentication (1) gssup-mechanism (1) }
-
- -- Scoped-Username GSS Name Form
- scoped-username OBJECT IDENTIFIER ::= { iso-itu-t (2) international-organization (23) omg (130) security (1) naming (2) scoped-username(1) }
-
-END
diff --git a/lib/orber/src/OrberCSIv2.set.asn b/lib/orber/src/OrberCSIv2.set.asn
deleted file mode 100644
index 11fbcc167f..0000000000
--- a/lib/orber/src/OrberCSIv2.set.asn
+++ /dev/null
@@ -1,5 +0,0 @@
-OrberCSIv2.asn1
-PKIXAttributeCertificate.asn1
-PKIX1Explicit88.asn1
-PKIX1Algorithms88.asn1
-PKIX1Implicit88.asn1
diff --git a/lib/orber/src/OrberIFR.idl b/lib/orber/src/OrberIFR.idl
deleted file mode 100644
index 6d53217658..0000000000
--- a/lib/orber/src/OrberIFR.idl
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef _ORBER_IFR_IDL
-#define _ORBER_IFR_IDL
-
-module OrberApp
-{
- interface IFR {
- string get_absolute_name(in string TypeID);
- CORBA::TypeCode get_user_exception_type(in string TypeID);
- };
-};
-
-#endif
diff --git a/lib/orber/src/PKIX1Algorithms88.asn1 b/lib/orber/src/PKIX1Algorithms88.asn1
deleted file mode 100644
index e78de69b0e..0000000000
--- a/lib/orber/src/PKIX1Algorithms88.asn1
+++ /dev/null
@@ -1,274 +0,0 @@
- PKIX1Algorithms88 { iso(1) identified-organization(3) dod(6)
- internet(1) security(5) mechanisms(5) pkix(7) id-mod(0)
- id-mod-pkix1-algorithms(17) }
-
- DEFINITIONS EXPLICIT TAGS ::= BEGIN
-
- -- EXPORTS All;
-
- -- IMPORTS NONE;
-
- --
- -- One-way Hash Functions
- --
-
- md2 OBJECT IDENTIFIER ::= {
- iso(1) member-body(2) us(840) rsadsi(113549)
- digestAlgorithm(2) 2 }
-
- md5 OBJECT IDENTIFIER ::= {
- iso(1) member-body(2) us(840) rsadsi(113549)
- digestAlgorithm(2) 5 }
-
- id-sha1 OBJECT IDENTIFIER ::= {
- iso(1) identified-organization(3) oiw(14) secsig(3)
- algorithms(2) 26 }
-
- --
- -- DSA Keys and Signatures
- --
-
- -- OID for DSA public key
-
- id-dsa OBJECT IDENTIFIER ::= {
- iso(1) member-body(2) us(840) x9-57(10040) x9algorithm(4) 1 }
-
- -- encoding for DSA public key
-
- DSAPublicKey ::= INTEGER -- public key, y
-
- Dss-Parms ::= SEQUENCE {
- p INTEGER,
- q INTEGER,
- g INTEGER }
-
- -- OID for DSA signature generated with SHA-1 hash
-
- id-dsa-with-sha1 OBJECT IDENTIFIER ::= {
- iso(1) member-body(2) us(840) x9-57 (10040) x9algorithm(4) 3 }
-
- -- encoding for DSA signature generated with SHA-1 hash
-
- Dss-Sig-Value ::= SEQUENCE {
- r INTEGER,
- s INTEGER }
-
- --
- -- RSA Keys and Signatures
- --
-
- -- arc for RSA public key and RSA signature OIDs
-
- pkcs-1 OBJECT IDENTIFIER ::= {
- iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }
-
- -- OID for RSA public keys
-
- rsaEncryption OBJECT IDENTIFIER ::= { pkcs-1 1 }
-
- -- OID for RSA signature generated with MD2 hash
-
- md2WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 2 }
-
- -- OID for RSA signature generated with MD5 hash
-
- md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 }
-
- -- OID for RSA signature generated with SHA-1 hash
-
- sha1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 }
-
- -- encoding for RSA public key
-
- RSAPublicKey ::= SEQUENCE {
- modulus INTEGER, -- n
- publicExponent INTEGER } -- e
-
- --
- -- Diffie-Hellman Keys
- --
-
- dhpublicnumber OBJECT IDENTIFIER ::= {
- iso(1) member-body(2) us(840) ansi-x942(10046)
- number-type(2) 1 }
-
- -- encoding for DSA public key
-
- DHPublicKey ::= INTEGER -- public key, y = g^x mod p
-
- DomainParameters ::= SEQUENCE {
- p INTEGER, -- odd prime, p=jq +1
- g INTEGER, -- generator, g
- q INTEGER, -- factor of p-1
- j INTEGER OPTIONAL, -- subgroup factor, j>= 2
- validationParms ValidationParms OPTIONAL }
-
- ValidationParms ::= SEQUENCE {
- seed BIT STRING,
- pgenCounter INTEGER }
-
- --
- -- KEA Keys
- --
-
- id-keyExchangeAlgorithm OBJECT IDENTIFIER ::=
- { 2 16 840 1 101 2 1 1 22 }
-
- KEA-Parms-Id ::= OCTET STRING
-
- --
- -- Elliptic Curve Keys, Signatures, and Curves
- --
-
- ansi-X9-62 OBJECT IDENTIFIER ::= {
- iso(1) member-body(2) us(840) 10045 }
-
- FieldID ::= SEQUENCE { -- Finite field
- fieldType OBJECT IDENTIFIER,
- parameters ANY DEFINED BY fieldType }
-
- -- Arc for ECDSA signature OIDS
-
- id-ecSigType OBJECT IDENTIFIER ::= { ansi-X9-62 signatures(4) }
-
- -- OID for ECDSA signatures with SHA-1
-
- ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { id-ecSigType 1 }
-
- -- OID for an elliptic curve signature
- -- format for the value of an ECDSA signature value
-
- ECDSA-Sig-Value ::= SEQUENCE {
- r INTEGER,
- s INTEGER }
-
- -- recognized field type OIDs are defined in the following arc
-
- id-fieldType OBJECT IDENTIFIER ::= { ansi-X9-62 fieldType(1) }
-
- -- where fieldType is prime-field, the parameters are of type Prime-p
-
- prime-field OBJECT IDENTIFIER ::= { id-fieldType 1 }
-
- Prime-p ::= INTEGER -- Finite field F(p), where p is an odd prime
-
- -- where fieldType is characteristic-two-field, the parameters are
- -- of type Characteristic-two
-
- characteristic-two-field OBJECT IDENTIFIER ::= { id-fieldType 2 }
-
- Characteristic-two ::= SEQUENCE {
- m INTEGER, -- Field size 2^m
- basis OBJECT IDENTIFIER,
- parameters ANY DEFINED BY basis }
-
- -- recognized basis type OIDs are defined in the following arc
-
- id-characteristic-two-basis OBJECT IDENTIFIER ::= {
- characteristic-two-field basisType(3) }
-
- -- gnbasis is identified by OID gnBasis and indicates
- -- parameters are NULL
-
- gnBasis OBJECT IDENTIFIER ::= { id-characteristic-two-basis 1 }
-
- -- parameters for this basis are NULL
-
- -- trinomial basis is identified by OID tpBasis and indicates
- -- parameters of type Pentanomial
-
- tpBasis OBJECT IDENTIFIER ::= { id-characteristic-two-basis 2 }
-
- -- Trinomial basis representation of F2^m
- -- Integer k for reduction polynomial xm + xk + 1
-
- Trinomial ::= INTEGER
-
- -- for pentanomial basis is identified by OID ppBasis and indicates
- -- parameters of type Pentanomial
-
- ppBasis OBJECT IDENTIFIER ::= { id-characteristic-two-basis 3 }
-
- -- Pentanomial basis representation of F2^m
- -- reduction polynomial integers k1, k2, k3
- -- f(x) = x**m + x**k3 + x**k2 + x**k1 + 1
-
- Pentanomial ::= SEQUENCE {
- k1 INTEGER,
- k2 INTEGER,
- k3 INTEGER }
-
- -- The object identifiers gnBasis, tpBasis and ppBasis name
- -- three kinds of basis for characteristic-two finite fields
-
- FieldElement ::= OCTET STRING -- Finite field element
-
- ECPoint ::= OCTET STRING -- Elliptic curve point
-
- -- Elliptic Curve parameters may be specified explicitly,
- -- specified implicitly through a "named curve", or
- -- inherited from the CA
-
- EcpkParameters ::= CHOICE {
- ecParameters ECParameters,
- namedCurve OBJECT IDENTIFIER,
- implicitlyCA NULL }
-
- ECParameters ::= SEQUENCE { -- Elliptic curve parameters
- version ECPVer,
- fieldID FieldID,
- curve Curve,
- base ECPoint, -- Base point G
- order INTEGER, -- Order n of the base point
- cofactor INTEGER OPTIONAL } -- The integer h = #E(Fq)/n
-
- ECPVer ::= INTEGER {ecpVer1(1)}
-
- Curve ::= SEQUENCE {
- a FieldElement, -- Elliptic curve coefficient a
- b FieldElement, -- Elliptic curve coefficient b
- seed BIT STRING OPTIONAL }
-
- id-publicKeyType OBJECT IDENTIFIER ::= { ansi-X9-62 keyType(2) }
-
- id-ecPublicKey OBJECT IDENTIFIER ::= { id-publicKeyType 1 }
-
- -- Named Elliptic Curves in ANSI X9.62.
-
- ellipticCurve OBJECT IDENTIFIER ::= { ansi-X9-62 curves(3) }
-
- c-TwoCurve OBJECT IDENTIFIER ::= {
- ellipticCurve characteristicTwo(0) }
-
- c2pnb163v1 OBJECT IDENTIFIER ::= { c-TwoCurve 1 }
- c2pnb163v2 OBJECT IDENTIFIER ::= { c-TwoCurve 2 }
- c2pnb163v3 OBJECT IDENTIFIER ::= { c-TwoCurve 3 }
- c2pnb176w1 OBJECT IDENTIFIER ::= { c-TwoCurve 4 }
- c2tnb191v1 OBJECT IDENTIFIER ::= { c-TwoCurve 5 }
- c2tnb191v2 OBJECT IDENTIFIER ::= { c-TwoCurve 6 }
- c2tnb191v3 OBJECT IDENTIFIER ::= { c-TwoCurve 7 }
- c2onb191v4 OBJECT IDENTIFIER ::= { c-TwoCurve 8 }
- c2onb191v5 OBJECT IDENTIFIER ::= { c-TwoCurve 9 }
- c2pnb208w1 OBJECT IDENTIFIER ::= { c-TwoCurve 10 }
- c2tnb239v1 OBJECT IDENTIFIER ::= { c-TwoCurve 11 }
- c2tnb239v2 OBJECT IDENTIFIER ::= { c-TwoCurve 12 }
- c2tnb239v3 OBJECT IDENTIFIER ::= { c-TwoCurve 13 }
- c2onb239v4 OBJECT IDENTIFIER ::= { c-TwoCurve 14 }
- c2onb239v5 OBJECT IDENTIFIER ::= { c-TwoCurve 15 }
- c2pnb272w1 OBJECT IDENTIFIER ::= { c-TwoCurve 16 }
- c2pnb304w1 OBJECT IDENTIFIER ::= { c-TwoCurve 17 }
- c2tnb359v1 OBJECT IDENTIFIER ::= { c-TwoCurve 18 }
- c2pnb368w1 OBJECT IDENTIFIER ::= { c-TwoCurve 19 }
- c2tnb431r1 OBJECT IDENTIFIER ::= { c-TwoCurve 20 }
-
- primeCurve OBJECT IDENTIFIER ::= { ellipticCurve prime(1) }
-
- prime192v1 OBJECT IDENTIFIER ::= { primeCurve 1 }
- prime192v2 OBJECT IDENTIFIER ::= { primeCurve 2 }
- prime192v3 OBJECT IDENTIFIER ::= { primeCurve 3 }
- prime239v1 OBJECT IDENTIFIER ::= { primeCurve 4 }
- prime239v2 OBJECT IDENTIFIER ::= { primeCurve 5 }
- prime239v3 OBJECT IDENTIFIER ::= { primeCurve 6 }
- prime256v1 OBJECT IDENTIFIER ::= { primeCurve 7 }
-
- END
diff --git a/lib/orber/src/PKIX1Explicit88.asn1 b/lib/orber/src/PKIX1Explicit88.asn1
deleted file mode 100644
index 9b8068fed0..0000000000
--- a/lib/orber/src/PKIX1Explicit88.asn1
+++ /dev/null
@@ -1,619 +0,0 @@
-PKIX1Explicit88 { iso(1) identified-organization(3) dod(6) internet(1)
- security(5) mechanisms(5) pkix(7) id-mod(0) id-pkix1-explicit(18) }
-
-DEFINITIONS EXPLICIT TAGS ::=
-
-BEGIN
-
--- EXPORTS ALL --
-
--- IMPORTS NONE --
-
--- UNIVERSAL Types defined in 1993 and 1998 ASN.1
--- and required by this specification
-
--- UniversalString ::= [UNIVERSAL 28] IMPLICIT OCTET STRING
- -- UniversalString is defined in ASN.1:1993
-
--- BMPString ::= [UNIVERSAL 30] IMPLICIT OCTET STRING
- -- BMPString is the subtype of UniversalString and models
- -- the Basic Multilingual Plane of ISO/IEC/ITU 10646-1
-
--- UTF8String ::= [UNIVERSAL 12] IMPLICIT OCTET STRING
- -- The content of this type conforms to RFC 2279.
-
--- PKIX specific OIDs
-
-id-pkix OBJECT IDENTIFIER ::=
- { iso(1) identified-organization(3) dod(6) internet(1)
- security(5) mechanisms(5) pkix(7) }
-
--- PKIX arcs
-
-id-pe OBJECT IDENTIFIER ::= { id-pkix 1 }
- -- arc for private certificate extensions
-id-qt OBJECT IDENTIFIER ::= { id-pkix 2 }
- -- arc for policy qualifier types
-id-kp OBJECT IDENTIFIER ::= { id-pkix 3 }
- -- arc for extended key purpose OIDS
-id-ad OBJECT IDENTIFIER ::= { id-pkix 48 }
- -- arc for access descriptors
-
--- policyQualifierIds for Internet policy qualifiers
-
-id-qt-cps OBJECT IDENTIFIER ::= { id-qt 1 }
- -- OID for CPS qualifier
-id-qt-unotice OBJECT IDENTIFIER ::= { id-qt 2 }
- -- OID for user notice qualifier
-
--- access descriptor definitions
-
-id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 }
-id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 }
-id-ad-timeStamping OBJECT IDENTIFIER ::= { id-ad 3 }
-id-ad-caRepository OBJECT IDENTIFIER ::= { id-ad 5 }
-
--- attribute data types
-
-Attribute ::= SEQUENCE {
- type AttributeType,
- values SET OF AttributeValue }
- -- at least one value is required
-
-AttributeType ::= OBJECT IDENTIFIER
-
-AttributeValue ::= ANY
-
-AttributeTypeAndValue ::= SEQUENCE {
- type AttributeType,
- value AttributeValue }
-
--- suggested naming attributes: Definition of the following
--- information object set may be augmented to meet local
--- requirements. Note that deleting members of the set may
--- prevent interoperability with conforming implementations.
--- presented in pairs: the AttributeType followed by the
--- type definition for the corresponding AttributeValue
---Arc for standard naming attributes
-id-at OBJECT IDENTIFIER ::= { joint-iso-ccitt(2) ds(5) 4 }
-
--- Naming attributes of type X520name
-
-id-at-name AttributeType ::= { id-at 41 }
-id-at-surname AttributeType ::= { id-at 4 }
-id-at-givenName AttributeType ::= { id-at 42 }
-id-at-initials AttributeType ::= { id-at 43 }
-id-at-generationQualifier AttributeType ::= { id-at 44 }
-
-X520name ::= CHOICE {
- teletexString TeletexString (SIZE (1..ub-name)),
- printableString PrintableString (SIZE (1..ub-name)),
- universalString UniversalString (SIZE (1..ub-name)),
- utf8String UTF8String (SIZE (1..ub-name)),
- bmpString BMPString (SIZE (1..ub-name)) }
-
--- Naming attributes of type X520CommonName
-
-id-at-commonName AttributeType ::= { id-at 3 }
-
-X520CommonName ::= CHOICE {
- teletexString TeletexString (SIZE (1..ub-common-name)),
- printableString PrintableString (SIZE (1..ub-common-name)),
- universalString UniversalString (SIZE (1..ub-common-name)),
- utf8String UTF8String (SIZE (1..ub-common-name)),
- bmpString BMPString (SIZE (1..ub-common-name)) }
-
--- Naming attributes of type X520LocalityName
-
-id-at-localityName AttributeType ::= { id-at 7 }
-
-X520LocalityName ::= CHOICE {
- teletexString TeletexString (SIZE (1..ub-locality-name)),
- printableString PrintableString (SIZE (1..ub-locality-name)),
- universalString UniversalString (SIZE (1..ub-locality-name)),
- utf8String UTF8String (SIZE (1..ub-locality-name)),
- bmpString BMPString (SIZE (1..ub-locality-name)) }
-
--- Naming attributes of type X520StateOrProvinceName
-
-id-at-stateOrProvinceName AttributeType ::= { id-at 8 }
-
-X520StateOrProvinceName ::= CHOICE {
- teletexString TeletexString (SIZE (1..ub-state-name)),
- printableString PrintableString (SIZE (1..ub-state-name)),
- universalString UniversalString (SIZE (1..ub-state-name)),
- utf8String UTF8String (SIZE (1..ub-state-name)),
- bmpString BMPString (SIZE(1..ub-state-name)) }
-
--- Naming attributes of type X520OrganizationName
-
-id-at-organizationName AttributeType ::= { id-at 10 }
-
-X520OrganizationName ::= CHOICE {
- teletexString TeletexString
- (SIZE (1..ub-organization-name)),
- printableString PrintableString
- (SIZE (1..ub-organization-name)),
- universalString UniversalString
- (SIZE (1..ub-organization-name)),
- utf8String UTF8String
- (SIZE (1..ub-organization-name)),
- bmpString BMPString
- (SIZE (1..ub-organization-name)) }
-
--- Naming attributes of type X520OrganizationalUnitName
-
-id-at-organizationalUnitName AttributeType ::= { id-at 11 }
-
-X520OrganizationalUnitName ::= CHOICE {
- teletexString TeletexString
- (SIZE (1..ub-organizational-unit-name)),
- printableString PrintableString
- (SIZE (1..ub-organizational-unit-name)),
- universalString UniversalString
- (SIZE (1..ub-organizational-unit-name)),
- utf8String UTF8String
- (SIZE (1..ub-organizational-unit-name)),
- bmpString BMPString
- (SIZE (1..ub-organizational-unit-name)) }
-
--- Naming attributes of type X520Title
-
-id-at-title AttributeType ::= { id-at 12 }
-
-X520Title ::= CHOICE {
- teletexString TeletexString (SIZE (1..ub-title)),
- printableString PrintableString (SIZE (1..ub-title)),
- universalString UniversalString (SIZE (1..ub-title)),
- utf8String UTF8String (SIZE (1..ub-title)),
- bmpString BMPString (SIZE (1..ub-title)) }
-
--- Naming attributes of type X520dnQualifier
-
-id-at-dnQualifier AttributeType ::= { id-at 46 }
-
-X520dnQualifier ::= PrintableString
-
--- Naming attributes of type X520countryName (digraph from IS 3166)
-
-id-at-countryName AttributeType ::= { id-at 6 }
-
-X520countryName ::= PrintableString (SIZE (2))
-
--- Naming attributes of type X520SerialNumber
-
-id-at-serialNumber AttributeType ::= { id-at 5 }
-
-X520SerialNumber ::= PrintableString (SIZE (1..ub-serial-number))
-
--- Naming attributes of type X520Pseudonym
-
-id-at-pseudonym AttributeType ::= { id-at 65 }
-
-X520Pseudonym ::= CHOICE {
- teletexString TeletexString (SIZE (1..ub-pseudonym)),
- printableString PrintableString (SIZE (1..ub-pseudonym)),
- universalString UniversalString (SIZE (1..ub-pseudonym)),
- utf8String UTF8String (SIZE (1..ub-pseudonym)),
- bmpString BMPString (SIZE (1..ub-pseudonym)) }
-
--- Naming attributes of type DomainComponent (from RFC 2247)
-
-id-domainComponent AttributeType ::=
- { 0 9 2342 19200300 100 1 25 }
-
-DomainComponent ::= IA5String
-
--- Legacy attributes
-
-pkcs-9 OBJECT IDENTIFIER ::=
- { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 }
-
-id-emailAddress AttributeType ::= { pkcs-9 1 }
-
-EmailAddress ::= IA5String (SIZE (1..ub-emailaddress-length))
-
--- naming data types --
-
-Name ::= CHOICE { -- only one possibility for now --
- rdnSequence RDNSequence }
-
-RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
-
-DistinguishedName ::= RDNSequence
-
-RelativeDistinguishedName ::=
- SET SIZE (1 .. MAX) OF AttributeTypeAndValue
-
--- Directory string type --
-
-DirectoryString ::= CHOICE {
- teletexString TeletexString (SIZE (1..MAX)),
- printableString PrintableString (SIZE (1..MAX)),
- universalString UniversalString (SIZE (1..MAX)),
- utf8String UTF8String (SIZE (1..MAX)),
- bmpString BMPString (SIZE (1..MAX)) }
-
--- certificate and CRL specific structures begin here
-
-Certificate ::= SEQUENCE {
- tbsCertificate TBSCertificate,
- signatureAlgorithm AlgorithmIdentifier,
- signature BIT STRING }
-
-TBSCertificate ::= SEQUENCE {
- version [0] Version DEFAULT v1,
- serialNumber CertificateSerialNumber,
- signature AlgorithmIdentifier,
- issuer Name,
- validity Validity,
- subject Name,
- subjectPublicKeyInfo SubjectPublicKeyInfo,
- issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
- -- If present, version MUST be v2 or v3
- subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
- -- If present, version MUST be v2 or v3
- extensions [3] Extensions OPTIONAL
- -- If present, version MUST be v3 -- }
-
-Version ::= INTEGER { v1(0), v2(1), v3(2) }
-
-CertificateSerialNumber ::= INTEGER
-
-Validity ::= SEQUENCE {
- notBefore Time,
- notAfter Time }
-
-Time ::= CHOICE {
- utcTime UTCTime,
- generalTime GeneralizedTime }
-
-UniqueIdentifier ::= BIT STRING
-
-SubjectPublicKeyInfo ::= SEQUENCE {
- algorithm AlgorithmIdentifier,
- subjectPublicKey BIT STRING }
-
-Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
-
-Extension ::= SEQUENCE {
- extnID OBJECT IDENTIFIER,
- critical BOOLEAN DEFAULT FALSE,
- extnValue OCTET STRING }
-
--- CRL structures
-
-CertificateList ::= SEQUENCE {
- tbsCertList TBSCertList,
- signatureAlgorithm AlgorithmIdentifier,
- signature BIT STRING }
-
-TBSCertList ::= SEQUENCE {
- version Version OPTIONAL,
- -- if present, MUST be v2
- signature AlgorithmIdentifier,
- issuer Name,
- thisUpdate Time,
- nextUpdate Time OPTIONAL,
- revokedCertificates SEQUENCE OF SEQUENCE {
- userCertificate CertificateSerialNumber,
- revocationDate Time,
- crlEntryExtensions Extensions OPTIONAL
- -- if present, MUST be v2
- } OPTIONAL,
- crlExtensions [0] Extensions OPTIONAL }
- -- if present, MUST be v2
-
--- Version, Time, CertificateSerialNumber, and Extensions were
--- defined earlier for use in the certificate structure
-
-AlgorithmIdentifier ::= SEQUENCE {
- algorithm OBJECT IDENTIFIER,
- parameters ANY DEFINED BY algorithm OPTIONAL }
- -- contains a value of the type
- -- registered for use with the
- -- algorithm object identifier value
-
--- X.400 address syntax starts here
-
-ORAddress ::= SEQUENCE {
- built-in-standard-attributes BuiltInStandardAttributes,
- built-in-domain-defined-attributes
- BuiltInDomainDefinedAttributes OPTIONAL,
- -- see also teletex-domain-defined-attributes
- extension-attributes ExtensionAttributes OPTIONAL }
-
--- Built-in Standard Attributes
-
-BuiltInStandardAttributes ::= SEQUENCE {
- country-name CountryName OPTIONAL,
- administration-domain-name AdministrationDomainName OPTIONAL,
- network-address [0] IMPLICIT NetworkAddress OPTIONAL,
- -- see also extended-network-address
- terminal-identifier [1] IMPLICIT TerminalIdentifier OPTIONAL,
- private-domain-name [2] PrivateDomainName OPTIONAL,
- organization-name [3] IMPLICIT OrganizationName OPTIONAL,
- -- see also teletex-organization-name
- numeric-user-identifier [4] IMPLICIT NumericUserIdentifier
- OPTIONAL,
- personal-name [5] IMPLICIT PersonalName OPTIONAL,
- -- see also teletex-personal-name
- organizational-unit-names [6] IMPLICIT OrganizationalUnitNames
- OPTIONAL }
- -- see also teletex-organizational-unit-names
-
-CountryName ::= [APPLICATION 1] CHOICE {
- x121-dcc-code NumericString
- (SIZE (ub-country-name-numeric-length)),
- iso-3166-alpha2-code PrintableString
- (SIZE (ub-country-name-alpha-length)) }
-
-AdministrationDomainName ::= [APPLICATION 2] CHOICE {
- numeric NumericString (SIZE (0..ub-domain-name-length)),
- printable PrintableString (SIZE (0..ub-domain-name-length)) }
-
-NetworkAddress ::= X121Address -- see also extended-network-address
-
-X121Address ::= NumericString (SIZE (1..ub-x121-address-length))
-
-TerminalIdentifier ::= PrintableString (SIZE
-(1..ub-terminal-id-length))
-
-PrivateDomainName ::= CHOICE {
- numeric NumericString (SIZE (1..ub-domain-name-length)),
- printable PrintableString (SIZE (1..ub-domain-name-length)) }
-
-OrganizationName ::= PrintableString
- (SIZE (1..ub-organization-name-length))
- -- see also teletex-organization-name
-
-NumericUserIdentifier ::= NumericString
- (SIZE (1..ub-numeric-user-id-length))
-
-PersonalName ::= SET {
- surname [0] IMPLICIT PrintableString
- (SIZE (1..ub-surname-length)),
- given-name [1] IMPLICIT PrintableString
- (SIZE (1..ub-given-name-length)) OPTIONAL,
- initials [2] IMPLICIT PrintableString
- (SIZE (1..ub-initials-length)) OPTIONAL,
- generation-qualifier [3] IMPLICIT PrintableString
- (SIZE (1..ub-generation-qualifier-length))
- OPTIONAL }
- -- see also teletex-personal-name
-
-OrganizationalUnitNames ::= SEQUENCE SIZE (1..ub-organizational-units)
- OF OrganizationalUnitName
- -- see also teletex-organizational-unit-names
-
-OrganizationalUnitName ::= PrintableString (SIZE
- (1..ub-organizational-unit-name-length))
-
--- Built-in Domain-defined Attributes
-
-BuiltInDomainDefinedAttributes ::= SEQUENCE SIZE
- (1..ub-domain-defined-attributes) OF
- BuiltInDomainDefinedAttribute
-
-BuiltInDomainDefinedAttribute ::= SEQUENCE {
- type PrintableString (SIZE
- (1..ub-domain-defined-attribute-type-length)),
- value PrintableString (SIZE
- (1..ub-domain-defined-attribute-value-length)) }
-
--- Extension Attributes
-
-ExtensionAttributes ::= SET SIZE (1..ub-extension-attributes) OF
- ExtensionAttribute
-
-ExtensionAttribute ::= SEQUENCE {
- extension-attribute-type [0] IMPLICIT INTEGER
- (0..ub-extension-attributes),
- extension-attribute-value [1]
- ANY DEFINED BY extension-attribute-type }
-
--- Extension types and attribute values
-
-common-name INTEGER ::= 1
-
-CommonName ::= PrintableString (SIZE (1..ub-common-name-length))
-
-teletex-common-name INTEGER ::= 2
-
-TeletexCommonName ::= TeletexString (SIZE (1..ub-common-name-length))
-
-teletex-organization-name INTEGER ::= 3
-
-TeletexOrganizationName ::=
- TeletexString (SIZE (1..ub-organization-name-length))
-
-teletex-personal-name INTEGER ::= 4
-
-TeletexPersonalName ::= SET {
- surname [0] IMPLICIT TeletexString
- (SIZE (1..ub-surname-length)),
- given-name [1] IMPLICIT TeletexString
- (SIZE (1..ub-given-name-length)) OPTIONAL,
- initials [2] IMPLICIT TeletexString
- (SIZE (1..ub-initials-length)) OPTIONAL,
- generation-qualifier [3] IMPLICIT TeletexString
- (SIZE (1..ub-generation-qualifier-length))
- OPTIONAL }
-
-teletex-organizational-unit-names INTEGER ::= 5
-
-TeletexOrganizationalUnitNames ::= SEQUENCE SIZE
- (1..ub-organizational-units) OF TeletexOrganizationalUnitName
-
-TeletexOrganizationalUnitName ::= TeletexString
- (SIZE (1..ub-organizational-unit-name-length))
-
-pds-name INTEGER ::= 7
-
-PDSName ::= PrintableString (SIZE (1..ub-pds-name-length))
-
-physical-delivery-country-name INTEGER ::= 8
-
-PhysicalDeliveryCountryName ::= CHOICE {
- x121-dcc-code NumericString (SIZE
-(ub-country-name-numeric-length)),
- iso-3166-alpha2-code PrintableString
- (SIZE (ub-country-name-alpha-length)) }
-
-postal-code INTEGER ::= 9
-
-PostalCode ::= CHOICE {
- numeric-code NumericString (SIZE (1..ub-postal-code-length)),
- printable-code PrintableString (SIZE (1..ub-postal-code-length)) }
-
-physical-delivery-office-name INTEGER ::= 10
-
-PhysicalDeliveryOfficeName ::= PDSParameter
-
-physical-delivery-office-number INTEGER ::= 11
-
-PhysicalDeliveryOfficeNumber ::= PDSParameter
-
-extension-OR-address-components INTEGER ::= 12
-
-ExtensionORAddressComponents ::= PDSParameter
-
-physical-delivery-personal-name INTEGER ::= 13
-
-PhysicalDeliveryPersonalName ::= PDSParameter
-
-physical-delivery-organization-name INTEGER ::= 14
-
-PhysicalDeliveryOrganizationName ::= PDSParameter
-
-extension-physical-delivery-address-components INTEGER ::= 15
-
-ExtensionPhysicalDeliveryAddressComponents ::= PDSParameter
-
-unformatted-postal-address INTEGER ::= 16
-
-UnformattedPostalAddress ::= SET {
- printable-address SEQUENCE SIZE (1..ub-pds-physical-address-lines)
- OF PrintableString (SIZE (1..ub-pds-parameter-length))
- OPTIONAL,
- teletex-string TeletexString
- (SIZE (1..ub-unformatted-address-length)) OPTIONAL }
-
-street-address INTEGER ::= 17
-
-StreetAddress ::= PDSParameter
-
-post-office-box-address INTEGER ::= 18
-
-PostOfficeBoxAddress ::= PDSParameter
-
-poste-restante-address INTEGER ::= 19
-
-PosteRestanteAddress ::= PDSParameter
-
-unique-postal-name INTEGER ::= 20
-
-UniquePostalName ::= PDSParameter
-
-local-postal-attributes INTEGER ::= 21
-
-LocalPostalAttributes ::= PDSParameter
-
-PDSParameter ::= SET {
- printable-string PrintableString
- (SIZE(1..ub-pds-parameter-length)) OPTIONAL,
- teletex-string TeletexString
- (SIZE(1..ub-pds-parameter-length)) OPTIONAL }
-
-extended-network-address INTEGER ::= 22
-
-ExtendedNetworkAddress ::= CHOICE {
- e163-4-address SEQUENCE {
- number [0] IMPLICIT NumericString
- (SIZE (1..ub-e163-4-number-length)),
- sub-address [1] IMPLICIT NumericString
- (SIZE (1..ub-e163-4-sub-address-length))
- OPTIONAL },
- psap-address [0] IMPLICIT PresentationAddress }
-
-PresentationAddress ::= SEQUENCE {
- pSelector [0] EXPLICIT OCTET STRING OPTIONAL,
- sSelector [1] EXPLICIT OCTET STRING OPTIONAL,
- tSelector [2] EXPLICIT OCTET STRING OPTIONAL,
- nAddresses [3] EXPLICIT SET SIZE (1..MAX) OF OCTET STRING }
-
-terminal-type INTEGER ::= 23
-
-TerminalType ::= INTEGER {
- telex (3),
- teletex (4),
- g3-facsimile (5),
- g4-facsimile (6),
- ia5-terminal (7),
- videotex (8) } (0..ub-integer-options)
-
--- Extension Domain-defined Attributes
-
-teletex-domain-defined-attributes INTEGER ::= 6
-
-TeletexDomainDefinedAttributes ::= SEQUENCE SIZE
- (1..ub-domain-defined-attributes) OF TeletexDomainDefinedAttribute
-
-TeletexDomainDefinedAttribute ::= SEQUENCE {
- type TeletexString
- (SIZE (1..ub-domain-defined-attribute-type-length)),
- value TeletexString
- (SIZE (1..ub-domain-defined-attribute-value-length)) }
-
--- specifications of Upper Bounds MUST be regarded as mandatory
--- from Annex B of ITU-T X.411 Reference Definition of MTS Parameter
--- Upper Bounds
-
--- Upper Bounds
-ub-name INTEGER ::= 32768
-ub-common-name INTEGER ::= 64
-ub-locality-name INTEGER ::= 128
-ub-state-name INTEGER ::= 128
-ub-organization-name INTEGER ::= 64
-ub-organizational-unit-name INTEGER ::= 64
-ub-title INTEGER ::= 64
-ub-serial-number INTEGER ::= 64
-ub-match INTEGER ::= 128
-ub-emailaddress-length INTEGER ::= 128
-ub-common-name-length INTEGER ::= 64
-ub-country-name-alpha-length INTEGER ::= 2
-ub-country-name-numeric-length INTEGER ::= 3
-ub-domain-defined-attributes INTEGER ::= 4
-ub-domain-defined-attribute-type-length INTEGER ::= 8
-ub-domain-defined-attribute-value-length INTEGER ::= 128
-ub-domain-name-length INTEGER ::= 16
-ub-extension-attributes INTEGER ::= 256
-ub-e163-4-number-length INTEGER ::= 15
-ub-e163-4-sub-address-length INTEGER ::= 40
-ub-generation-qualifier-length INTEGER ::= 3
-ub-given-name-length INTEGER ::= 16
-ub-initials-length INTEGER ::= 5
-ub-integer-options INTEGER ::= 256
-ub-numeric-user-id-length INTEGER ::= 32
-ub-organization-name-length INTEGER ::= 64
-ub-organizational-unit-name-length INTEGER ::= 32
-ub-organizational-units INTEGER ::= 4
-ub-pds-name-length INTEGER ::= 16
-ub-pds-parameter-length INTEGER ::= 30
-ub-pds-physical-address-lines INTEGER ::= 6
-ub-postal-code-length INTEGER ::= 16
-ub-pseudonym INTEGER ::= 128
-ub-surname-length INTEGER ::= 40
-ub-terminal-id-length INTEGER ::= 24
-ub-unformatted-address-length INTEGER ::= 180
-ub-x121-address-length INTEGER ::= 16
-
--- Note - upper bounds on string types, such as TeletexString, are
--- measured in characters. Excepting PrintableString or IA5String, a
--- significantly greater number of octets will be required to hold
--- such a value. As a minimum, 16 octets, or twice the specified
--- upper bound, whichever is the larger, should be allowed for
--- TeletexString. For UTF8String or UniversalString at least four
--- times the upper bound should be allowed.
-
-END
diff --git a/lib/orber/src/PKIX1Implicit88.asn1 b/lib/orber/src/PKIX1Implicit88.asn1
deleted file mode 100644
index ced270baf6..0000000000
--- a/lib/orber/src/PKIX1Implicit88.asn1
+++ /dev/null
@@ -1,349 +0,0 @@
-PKIX1Implicit88 { iso(1) identified-organization(3) dod(6) internet(1)
- security(5) mechanisms(5) pkix(7) id-mod(0) id-pkix1-implicit(19) }
-
-DEFINITIONS IMPLICIT TAGS ::=
-
-BEGIN
-
--- EXPORTS ALL --
-
-IMPORTS
- id-pe, id-kp, id-qt-unotice, id-qt-cps,
- -- delete following line if "new" types are supported --
- -- BMPString,
- -- UTF8String, end "new" types --
- ORAddress, Name, RelativeDistinguishedName,
- CertificateSerialNumber, Attribute, DirectoryString
- FROM PKIX1Explicit88 { iso(1) identified-organization(3)
- dod(6) internet(1) security(5) mechanisms(5) pkix(7)
- id-mod(0) id-pkix1-explicit(18) };
-
-
--- ISO arc for standard certificate and CRL extensions
-
-id-ce OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) ds(5) 29}
-
--- authority key identifier OID and syntax
-
-id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 35 }
-
-AuthorityKeyIdentifier ::= SEQUENCE {
- keyIdentifier [0] KeyIdentifier OPTIONAL,
- authorityCertIssuer [1] GeneralNames OPTIONAL,
- authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }
- -- authorityCertIssuer and authorityCertSerialNumber MUST both
- -- be present or both be absent
-
-KeyIdentifier ::= OCTET STRING
-
--- subject key identifier OID and syntax
-
-id-ce-subjectKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 14 }
-
-SubjectKeyIdentifier ::= KeyIdentifier
-
--- key usage extension OID and syntax
-
-id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 }
-
-KeyUsage ::= BIT STRING {
- digitalSignature (0),
- nonRepudiation (1),
- keyEncipherment (2),
- dataEncipherment (3),
- keyAgreement (4),
- keyCertSign (5),
- cRLSign (6),
- encipherOnly (7),
- decipherOnly (8) }
-
--- private key usage period extension OID and syntax
-
-id-ce-privateKeyUsagePeriod OBJECT IDENTIFIER ::= { id-ce 16 }
-
-PrivateKeyUsagePeriod ::= SEQUENCE {
- notBefore [0] GeneralizedTime OPTIONAL,
- notAfter [1] GeneralizedTime OPTIONAL }
- -- either notBefore or notAfter MUST be present
-
--- certificate policies extension OID and syntax
-
-id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 }
-
-anyPolicy OBJECT IDENTIFIER ::= { id-ce-certificatePolicies 0 }
-
-CertificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
-
-PolicyInformation ::= SEQUENCE {
- policyIdentifier CertPolicyId,
- policyQualifiers SEQUENCE SIZE (1..MAX) OF
- PolicyQualifierInfo OPTIONAL }
-
-CertPolicyId ::= OBJECT IDENTIFIER
-
-PolicyQualifierInfo ::= SEQUENCE {
- policyQualifierId PolicyQualifierId,
- qualifier ANY DEFINED BY policyQualifierId }
-
--- Implementations that recognize additional policy qualifiers MUST
--- augment the following definition for PolicyQualifierId
-
-PolicyQualifierId ::=
- OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice )
-
--- CPS pointer qualifier
-
-CPSuri ::= IA5String
-
--- user notice qualifier
-
-UserNotice ::= SEQUENCE {
- noticeRef NoticeReference OPTIONAL,
- explicitText DisplayText OPTIONAL}
-
-NoticeReference ::= SEQUENCE {
- organization DisplayText,
- noticeNumbers SEQUENCE OF INTEGER }
-
-DisplayText ::= CHOICE {
- ia5String IA5String (SIZE (1..200)),
- visibleString VisibleString (SIZE (1..200)),
- bmpString BMPString (SIZE (1..200)),
- utf8String UTF8String (SIZE (1..200)) }
-
--- policy mapping extension OID and syntax
-
-id-ce-policyMappings OBJECT IDENTIFIER ::= { id-ce 33 }
-
-PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE {
- issuerDomainPolicy CertPolicyId,
- subjectDomainPolicy CertPolicyId }
-
--- subject alternative name extension OID and syntax
-
-id-ce-subjectAltName OBJECT IDENTIFIER ::= { id-ce 17 }
-
-SubjectAltName ::= GeneralNames
-
-GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
-
-GeneralName ::= CHOICE {
- otherName [0] AnotherName,
- rfc822Name [1] IA5String,
- dNSName [2] IA5String,
- x400Address [3] ORAddress,
- directoryName [4] Name,
- ediPartyName [5] EDIPartyName,
- uniformResourceIdentifier [6] IA5String,
- iPAddress [7] OCTET STRING,
- registeredID [8] OBJECT IDENTIFIER }
-
--- AnotherName replaces OTHER-NAME ::= TYPE-IDENTIFIER, as
--- TYPE-IDENTIFIER is not supported in the '88 ASN.1 syntax
-
-AnotherName ::= SEQUENCE {
- type-id OBJECT IDENTIFIER,
- value [0] EXPLICIT ANY DEFINED BY type-id }
-
-EDIPartyName ::= SEQUENCE {
- nameAssigner [0] DirectoryString OPTIONAL,
- partyName [1] DirectoryString }
-
--- issuer alternative name extension OID and syntax
-
-id-ce-issuerAltName OBJECT IDENTIFIER ::= { id-ce 18 }
-
-IssuerAltName ::= GeneralNames
-
-id-ce-subjectDirectoryAttributes OBJECT IDENTIFIER ::= { id-ce 9 }
-
-SubjectDirectoryAttributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
-
--- basic constraints extension OID and syntax
-
-id-ce-basicConstraints OBJECT IDENTIFIER ::= { id-ce 19 }
-
-BasicConstraints ::= SEQUENCE {
- cA BOOLEAN DEFAULT FALSE,
- pathLenConstraint INTEGER (0..MAX) OPTIONAL }
-
--- name constraints extension OID and syntax
-
-id-ce-nameConstraints OBJECT IDENTIFIER ::= { id-ce 30 }
-
-NameConstraints ::= SEQUENCE {
- permittedSubtrees [0] GeneralSubtrees OPTIONAL,
- excludedSubtrees [1] GeneralSubtrees OPTIONAL }
-
-GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
-
-GeneralSubtree ::= SEQUENCE {
- base GeneralName,
- minimum [0] BaseDistance DEFAULT 0,
- maximum [1] BaseDistance OPTIONAL }
-
-BaseDistance ::= INTEGER (0..MAX)
-
--- policy constraints extension OID and syntax
-
-id-ce-policyConstraints OBJECT IDENTIFIER ::= { id-ce 36 }
-
-PolicyConstraints ::= SEQUENCE {
- requireExplicitPolicy [0] SkipCerts OPTIONAL,
- inhibitPolicyMapping [1] SkipCerts OPTIONAL }
-
-SkipCerts ::= INTEGER (0..MAX)
-
--- CRL distribution points extension OID and syntax
-
-id-ce-cRLDistributionPoints OBJECT IDENTIFIER ::= {id-ce 31}
-
-CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
-
-DistributionPoint ::= SEQUENCE {
- distributionPoint [0] DistributionPointName OPTIONAL,
- reasons [1] ReasonFlags OPTIONAL,
- cRLIssuer [2] GeneralNames OPTIONAL }
-
-DistributionPointName ::= CHOICE {
- fullName [0] GeneralNames,
- nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
-
-ReasonFlags ::= BIT STRING {
- unused (0),
- keyCompromise (1),
- cACompromise (2),
- affiliationChanged (3),
- superseded (4),
- cessationOfOperation (5),
- certificateHold (6),
- privilegeWithdrawn (7),
- aACompromise (8) }
-
--- extended key usage extension OID and syntax
-
-id-ce-extKeyUsage OBJECT IDENTIFIER ::= {id-ce 37}
-
-ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
-
-
-KeyPurposeId ::= OBJECT IDENTIFIER
-
--- permit unspecified key uses
-
-anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 }
-
--- extended key purpose OIDs
-
-id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 }
-id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 }
-id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 }
-id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 }
-id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 }
-id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 }
-
--- inhibit any policy OID and syntax
-
-id-ce-inhibitAnyPolicy OBJECT IDENTIFIER ::= { id-ce 54 }
-
-InhibitAnyPolicy ::= SkipCerts
-
--- freshest (delta)CRL extension OID and syntax
-
-id-ce-freshestCRL OBJECT IDENTIFIER ::= { id-ce 46 }
-
-FreshestCRL ::= CRLDistributionPoints
-
--- authority info access
-
-id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }
-
-AuthorityInfoAccessSyntax ::=
- SEQUENCE SIZE (1..MAX) OF AccessDescription
-
-AccessDescription ::= SEQUENCE {
- accessMethod OBJECT IDENTIFIER,
- accessLocation GeneralName }
-
--- subject info access
-
-id-pe-subjectInfoAccess OBJECT IDENTIFIER ::= { id-pe 11 }
-
-SubjectInfoAccessSyntax ::=
- SEQUENCE SIZE (1..MAX) OF AccessDescription
-
--- CRL number extension OID and syntax
-
-id-ce-cRLNumber OBJECT IDENTIFIER ::= { id-ce 20 }
-
-CRLNumber ::= INTEGER (0..MAX)
-
--- issuing distribution point extension OID and syntax
-
-id-ce-issuingDistributionPoint OBJECT IDENTIFIER ::= { id-ce 28 }
-
-IssuingDistributionPoint ::= SEQUENCE {
- distributionPoint [0] DistributionPointName OPTIONAL,
- onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE,
- onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE,
- onlySomeReasons [3] ReasonFlags OPTIONAL,
- indirectCRL [4] BOOLEAN DEFAULT FALSE,
- onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE }
-
-id-ce-deltaCRLIndicator OBJECT IDENTIFIER ::= { id-ce 27 }
-
-BaseCRLNumber ::= CRLNumber
-
--- CRL reasons extension OID and syntax
-
-id-ce-cRLReasons OBJECT IDENTIFIER ::= { id-ce 21 }
-
-CRLReason ::= ENUMERATED {
- unspecified (0),
- keyCompromise (1),
- cACompromise (2),
- affiliationChanged (3),
- superseded (4),
- cessationOfOperation (5),
- certificateHold (6),
- removeFromCRL (8),
- privilegeWithdrawn (9),
- aACompromise (10) }
-
--- certificate issuer CRL entry extension OID and syntax
-
-id-ce-certificateIssuer OBJECT IDENTIFIER ::= { id-ce 29 }
-
-CertificateIssuer ::= GeneralNames
-
--- hold instruction extension OID and syntax
-
-id-ce-holdInstructionCode OBJECT IDENTIFIER ::= { id-ce 23 }
-
-HoldInstructionCode ::= OBJECT IDENTIFIER
-
--- ANSI x9 holdinstructions
-
--- ANSI x9 arc holdinstruction arc
-
-holdInstruction OBJECT IDENTIFIER ::=
- {joint-iso-itu-t(2) member-body(2) us(840) x9cm(10040) 2}
-
--- ANSI X9 holdinstructions referenced by this standard
-
-id-holdinstruction-none OBJECT IDENTIFIER ::=
- {holdInstruction 1} -- deprecated
-
-id-holdinstruction-callissuer OBJECT IDENTIFIER ::=
- {holdInstruction 2}
-
-id-holdinstruction-reject OBJECT IDENTIFIER ::=
- {holdInstruction 3}
-
--- invalidity date CRL entry extension OID and syntax
-
-id-ce-invalidityDate OBJECT IDENTIFIER ::= { id-ce 24 }
-
-InvalidityDate ::= GeneralizedTime
-
-END
diff --git a/lib/orber/src/PKIXAttributeCertificate.asn1 b/lib/orber/src/PKIXAttributeCertificate.asn1
deleted file mode 100644
index 7d93e6b37e..0000000000
--- a/lib/orber/src/PKIXAttributeCertificate.asn1
+++ /dev/null
@@ -1,189 +0,0 @@
- PKIXAttributeCertificate {iso(1) identified-organization(3) dod(6)
- internet(1) security(5) mechanisms(5) pkix(7) id-mod(0)
- id-mod-attribute-cert(12)}
-
- DEFINITIONS IMPLICIT TAGS ::=
-
- BEGIN
-
- -- EXPORTS ALL --
-
- IMPORTS
-
- -- IMPORTed module OIDs MAY change if [PKIXPROF] changes
- -- PKIX Certificate Extensions
- Attribute, AlgorithmIdentifier, CertificateSerialNumber,
- Extensions, UniqueIdentifier,
- id-pkix, id-pe, id-kp, id-ad, id-at
- FROM PKIX1Explicit88 {iso(1) identified-organization(3)
- dod(6) internet(1) security(5) mechanisms(5)
- pkix(7) id-mod(0) id-pkix1-explicit-88(1)}
-
- GeneralName, GeneralNames, id-ce
- FROM PKIX1Implicit88 {iso(1) identified-organization(3)
- dod(6) internet(1) security(5) mechanisms(5)
- pkix(7) id-mod(0) id-pkix1-implicit-88(2)} ;
-
- id-pe-ac-auditIdentity OBJECT IDENTIFIER ::= { id-pe 4 }
- id-pe-aaControls OBJECT IDENTIFIER ::= { id-pe 6 }
- id-pe-ac-proxying OBJECT IDENTIFIER ::= { id-pe 10 }
- id-ce-targetInformation OBJECT IDENTIFIER ::= { id-ce 55 }
-
- id-aca OBJECT IDENTIFIER ::= { id-pkix 10 }
- id-aca-authenticationInfo OBJECT IDENTIFIER ::= { id-aca 1 }
- id-aca-accessIdentity OBJECT IDENTIFIER ::= { id-aca 2 }
- id-aca-chargingIdentity OBJECT IDENTIFIER ::= { id-aca 3 }
- id-aca-group OBJECT IDENTIFIER ::= { id-aca 4 }
- -- { id-aca 5 } is reserved
- id-aca-encAttrs OBJECT IDENTIFIER ::= { id-aca 6 }
-
- id-at-role OBJECT IDENTIFIER ::= { id-at 72}
- id-at-clearance OBJECT IDENTIFIER ::=
- { joint-iso-ccitt(2) ds(5) module(1)
- selected-attribute-types(5) clearance (55) }
-
- -- Uncomment this if using a 1988 level ASN.1 compiler
- -- UTF8String ::= [UNIVERSAL 12] IMPLICIT OCTET STRING
-
- AttributeCertificate ::= SEQUENCE {
- acinfo AttributeCertificateInfo,
- signatureAlgorithm AlgorithmIdentifier,
- signatureValue BIT STRING
- }
-
- AttributeCertificateInfo ::= SEQUENCE {
- version AttCertVersion, -- version is v2
- holder Holder,
- issuer AttCertIssuer,
- signature AlgorithmIdentifier,
- serialNumber CertificateSerialNumber,
- attrCertValidityPeriod AttCertValidityPeriod,
- attributes SEQUENCE OF Attribute,
- issuerUniqueID UniqueIdentifier OPTIONAL,
- extensions Extensions OPTIONAL
- }
-
- AttCertVersion ::= INTEGER { v2(1) }
-
- Holder ::= SEQUENCE {
- baseCertificateID [0] IssuerSerial OPTIONAL,
- -- the issuer and serial number of
- -- the holder's Public Key Certificate
- entityName [1] GeneralNames OPTIONAL,
- -- the name of the claimant or role
- objectDigestInfo [2] ObjectDigestInfo OPTIONAL
- -- used to directly authenticate the
- -- holder, for example, an executable
- }
-
- ObjectDigestInfo ::= SEQUENCE {
- digestedObjectType ENUMERATED {
- publicKey (0),
- publicKeyCert (1),
- otherObjectTypes (2) },
- -- otherObjectTypes MUST NOT
- -- MUST NOT be used in this profile
- otherObjectTypeID OBJECT IDENTIFIER OPTIONAL,
- digestAlgorithm AlgorithmIdentifier,
- objectDigest BIT STRING
- }
-
- AttCertIssuer ::= CHOICE {
- v1Form GeneralNames, -- MUST NOT be used in this
- -- profile
- v2Form [0] V2Form -- v2 only
- }
-
- V2Form ::= SEQUENCE {
- issuerName GeneralNames OPTIONAL,
- baseCertificateID [0] IssuerSerial OPTIONAL,
- objectDigestInfo [1] ObjectDigestInfo OPTIONAL
- -- issuerName MUST be present in this profile
- -- baseCertificateID and objectDigestInfo MUST
- -- NOT be present in this profile
- }
-
- IssuerSerial ::= SEQUENCE {
- issuer GeneralNames,
- serial CertificateSerialNumber,
- issuerUID UniqueIdentifier OPTIONAL
- }
-
- AttCertValidityPeriod ::= SEQUENCE {
- notBeforeTime GeneralizedTime,
- notAfterTime GeneralizedTime
- }
-
- Targets ::= SEQUENCE OF Target
-
- Target ::= CHOICE {
- targetName [0] GeneralName,
- targetGroup [1] GeneralName,
- targetCert [2] TargetCert
- }
-
- TargetCert ::= SEQUENCE {
- targetCertificate IssuerSerial,
- targetName GeneralName OPTIONAL,
- certDigestInfo ObjectDigestInfo OPTIONAL
- }
-
- IetfAttrSyntax ::= SEQUENCE {
- policyAuthority[0] GeneralNames OPTIONAL,
- values SEQUENCE OF CHOICE {
- octets OCTET STRING,
- oid OBJECT IDENTIFIER,
- string UTF8String
- }
- }
-
- SvceAuthInfo ::= SEQUENCE {
- service GeneralName,
- ident GeneralName,
- authInfo OCTET STRING OPTIONAL
- }
-
- RoleSyntax ::= SEQUENCE {
- roleAuthority [0] GeneralNames OPTIONAL,
- roleName [1] GeneralName
- }
-
- Clearance ::= SEQUENCE {
- policyId [0] OBJECT IDENTIFIER,
- classList [1] ClassList DEFAULT {unclassified},
- securityCategories
- [2] SET OF SecurityCategory OPTIONAL
- }
-
- ClassList ::= BIT STRING {
- unmarked (0),
- unclassified (1),
- restricted (2),
- confidential (3),
- secret (4),
- topSecret (5)
- }
-
- SecurityCategory ::= SEQUENCE {
- type [0] IMPLICIT OBJECT IDENTIFIER,
- value [1] ANY DEFINED BY type
- }
-
- AAControls ::= SEQUENCE {
- pathLenConstraint INTEGER (0..MAX) OPTIONAL,
- permittedAttrs [0] AttrSpec OPTIONAL,
- excludedAttrs [1] AttrSpec OPTIONAL,
- permitUnSpecified BOOLEAN DEFAULT TRUE
- }
-
- AttrSpec::= SEQUENCE OF OBJECT IDENTIFIER
-
- ACClearAttrs ::= SEQUENCE {
- acIssuer GeneralName,
- acSerial INTEGER,
- attrs SEQUENCE OF Attribute
- }
-
- ProxyInfo ::= SEQUENCE OF Targets
-
- END
diff --git a/lib/orber/src/any.erl b/lib/orber/src/any.erl
deleted file mode 100644
index ec7c3ba83a..0000000000
--- a/lib/orber/src/any.erl
+++ /dev/null
@@ -1,74 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: any.erl
-%% Description:
-%% This file conatins the interface for the any type
-%%
-%%-----------------------------------------------------------------
--module(any).
-
--include_lib("orber/include/corba.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([create/0, create/2,
- set_typecode/2, get_typecode/1,
- set_value/2, get_value/1]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-%%-----------------------------------------------------------------
-%% External functions
-%%-----------------------------------------------------------------
-create() ->
- #any{}.
-
-create(TC, V) ->
- case orber_tc:check_tc(TC) of
- true ->
- #any{typecode=TC, value=V};
- false ->
- corba:raise(#'BAD_TYPECODE'{completion_status=?COMPLETED_NO})
- end.
-
-set_typecode(Any, TC) ->
- case orber_tc:check_tc(TC) of
- true ->
- Any#any{typecode=TC};
- false ->
- corba:raise(#'BAD_TYPECODE'{completion_status=?COMPLETED_NO})
- end.
-
-get_typecode(Any) ->
- Any#any.typecode.
-
-set_value(Any, V) ->
- Any#any{value=V}.
-
-get_value(Any) ->
- Any#any.value.
-
diff --git a/lib/orber/src/cdr_decode.erl b/lib/orber/src/cdr_decode.erl
deleted file mode 100644
index fd021988c9..0000000000
--- a/lib/orber/src/cdr_decode.erl
+++ /dev/null
@@ -1,1536 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2015. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: cdr_decode.erl
-%%
-%% Description:
-%% This file contains all decoding functions for the CDR
-%% format.
-%%
-%%-----------------------------------------------------------------
--module(cdr_decode).
-
--include_lib("orber/src/orber_iiop.hrl").
--include_lib("orber/include/ifr_types.hrl").
--include_lib("orber/include/corba.hrl").
-
--include_lib("orber/src/ifr_objects.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([dec_giop_message_header/1, dec_reply_header/4,
- dec_reply_body/6, dec_locate_reply_header/4,
- dec_locate_reply_body/5, dec_message_header/3, dec_request_body/6,
- dec_octet_sequence_bin/6, dec_message/2, peek_request_id/2]).
-
-%%-----------------------------------------------------------------
-%% Functions which only are exported for the testcases.
-%%-----------------------------------------------------------------
--export([dec_type/5, dec_byte_order/1, dec_system_exception/4, dec_user_exception/4,
- dec_byte_order_list/1]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
-
-%%-----------------------------------------------------------------
-%% Macros
-%%-----------------------------------------------------------------
--define(DEBUG_LEVEL, 9).
-
--define(ODD(N), (N rem 2) == 1).
-
-%%-----------------------------------------------------------------
-%% Func: dec_message/3
-%% Args:
-%% TypeCodes - is the type_codes of the return value and out parameters
-%% when one decodes a reply.
-%% Bytes - is the the message as a byte sequence.
-%% Returns:
-%% A tupple which contains the decoded message,
-%% {ok, Header, Parameters, TypeCodes}.
-%%-----------------------------------------------------------------
-dec_message(TypeCodes, Bytes) ->
- Message = dec_giop_message_header(Bytes),
- case Message#giop_message.message_type of
- ?GIOP_MSG_REQUEST ->
- {Version, ReqHdr, Rest, Len, ByteOrder} =
- dec_request_header(Message#giop_message.giop_version,
- Message#giop_message.message, ?GIOP_HEADER_SIZE,
- Message#giop_message.byte_order, Bytes),
- dec_request_body(Version, ReqHdr, Rest, Len, ByteOrder, Bytes);
- ?GIOP_MSG_REPLY ->
- dec_reply(Message#giop_message.giop_version,
- TypeCodes, Message#giop_message.message, ?GIOP_HEADER_SIZE,
- Message#giop_message.byte_order);
- ?GIOP_MSG_CANCEL_REQUEST ->
- dec_cancel_request(Message#giop_message.giop_version,
- Message#giop_message.message, ?GIOP_HEADER_SIZE,
- Message#giop_message.byte_order);
- ?GIOP_MSG_LOCATE_REQUEST ->
- dec_locate_request(Message#giop_message.giop_version,
- Message#giop_message.message, ?GIOP_HEADER_SIZE,
- Message#giop_message.byte_order);
- ?GIOP_MSG_LOCATE_REPLY ->
- dec_locate_reply(Message#giop_message.giop_version,
- Message#giop_message.message, ?GIOP_HEADER_SIZE,
- Message#giop_message.byte_order);
- ?GIOP_MSG_CLOSE_CONNECTION ->
- 'close_connection';
- ?GIOP_MSG_MESSAGE_ERROR ->
- 'message_error';
- ?GIOP_MSG_FRAGMENT ->
- dec_fragment_header(Message#giop_message.giop_version,
- Message#giop_message.message, ?GIOP_HEADER_SIZE,
- Message#giop_message.byte_order, Bytes)
- end.
-
-%%-----------------------------------------------------------------
-%% Func: dec_giop_message_header/1
-%% Args:
-%% Bytes - is the the message as a byte sequence.
-%% Returns:
-%% A giop_message record.
-%%-----------------------------------------------------------------
-%% Magic|Version|BO| Type | Size | Body
-dec_giop_message_header(<<"GIOP",1:8,0:8,1:8,MessType:8,
- MessSize:32/little-unsigned-integer,Message/binary>>) ->
- #giop_message{magic = "GIOP", giop_version = {1,0},
- byte_order = little, message_type = MessType,
- message_size = MessSize, message = Message};
-dec_giop_message_header(<<"GIOP",1:8,0:8,0:8,MessType:8,
- MessSize:32/big-unsigned-integer,Message/binary>>) ->
- #giop_message{magic = "GIOP", giop_version = {1,0},
- byte_order = big, message_type = MessType,
- message_size = MessSize, message = Message};
-dec_giop_message_header(<<"GIOP",1:8,Minor:8,Flags:8,MessType:8,
- MessSize:32/little-unsigned-integer,Message/binary>>) when
- ((Flags band 16#01) == 16#01) ->
- #giop_message{magic = "GIOP", giop_version = {1,Minor},
- byte_order = little, fragments = ((Flags band 16#02) == 16#02),
- message_type = MessType, message_size = MessSize, message = Message};
-dec_giop_message_header(<<"GIOP",1:8,Minor:8,Flags:8,MessType:8,
- MessSize:32/big-unsigned-integer,Message/binary>>) ->
- #giop_message{magic = "GIOP", giop_version = {1,Minor},
- byte_order = big, fragments = ((Flags band 16#02) == 16#02),
- message_type = MessType, message_size = MessSize, message = Message};
-dec_giop_message_header(<<Hdr:?GIOP_HEADER_SIZE/binary, _Body/binary>>) ->
- orber:dbg("[~p] cdr_decode:dec_giop_message_header(~p);~n"
- "Orber cannot decode the GIOP-header.", [?LINE, Hdr], ?DEBUG_LEVEL),
- exit(message_error);
-dec_giop_message_header(Other) ->
- orber:dbg("[~p] cdr_decode:dec_giop_message_header(~p);~n"
- "Orber cannot decode the GIOP-header.", [?LINE, Other], ?DEBUG_LEVEL),
- exit(message_error).
-
-
-peek_request_id(big, <<ReqId:32/big-unsigned-integer,_/binary>>) ->
- ReqId;
-peek_request_id(little, <<ReqId:32/little-unsigned-integer,_/binary>>) ->
- ReqId.
-
-%%-----------------------------------------------------------------
-%% Func: dec_message_header/2
-%% Args:
-%% Header - #giop_message{}
-%% Bytes - is the the message body as a byte sequence.
-%% Returns:
-%%-----------------------------------------------------------------
-dec_message_header(TypeCodes, Message, Bytes) ->
- case Message#giop_message.message_type of
- ?GIOP_MSG_REQUEST ->
- dec_request_header(Message#giop_message.giop_version,
- Message#giop_message.message, ?GIOP_HEADER_SIZE,
- Message#giop_message.byte_order, Bytes);
- ?GIOP_MSG_REPLY ->
- dec_reply(Message#giop_message.giop_version,
- TypeCodes, Message#giop_message.message, ?GIOP_HEADER_SIZE,
- Message#giop_message.byte_order);
- ?GIOP_MSG_CANCEL_REQUEST ->
- dec_cancel_request(Message#giop_message.giop_version,
- Message#giop_message.message, ?GIOP_HEADER_SIZE,
- Message#giop_message.byte_order);
- ?GIOP_MSG_LOCATE_REQUEST ->
- dec_locate_request(Message#giop_message.giop_version,
- Message#giop_message.message, ?GIOP_HEADER_SIZE,
- Message#giop_message.byte_order);
- ?GIOP_MSG_LOCATE_REPLY ->
- dec_locate_reply(Message#giop_message.giop_version,
- Message#giop_message.message, ?GIOP_HEADER_SIZE,
- Message#giop_message.byte_order);
- ?GIOP_MSG_CLOSE_CONNECTION ->
- 'close_connection';
- ?GIOP_MSG_MESSAGE_ERROR ->
- 'message_error';
- ?GIOP_MSG_FRAGMENT ->
- dec_fragment_header(Message#giop_message.giop_version,
- Message#giop_message.message, ?GIOP_HEADER_SIZE,
- Message#giop_message.byte_order, Bytes)
- end.
-
-
-%%-----------------------------------------------------------------
-%% Func: dec_byte_order/1
-%% Args:
-%% The message as a byte sequence.
-%% Returns:
-%% A tuple {Endianness, Rest} where Endianness is big or little.
-%% Rest is the remaining message byte sequence.
-%%-----------------------------------------------------------------
-dec_byte_order(<<0:8,T/binary>>) ->
- {big, T};
-dec_byte_order(<<1:8,T/binary>>) ->
- {little, T}.
-
-%%-----------------------------------------------------------------
-%% Func: dec_byte_order_list/1
-%% Args:
-%% The message as a byte sequence.
-%% Returns:
-%% A tuple {Endianness, Rest} where Endianness is big or little.
-%% Rest is the remaining message byte sequence.
-%%-----------------------------------------------------------------
-dec_byte_order_list([0|T]) ->
- {big, T};
-dec_byte_order_list([1|T]) ->
- {little, T}.
-
-%%-----------------------------------------------------------------
-%% Func : dec_response_flags
-%% Args :
-%% Returns : boolean
-%%-----------------------------------------------------------------
-%% FIX ME!! Not correct flag handling.
-dec_response_flags(_Version, <<0:8, Rest/binary>>, Len) ->
- {false, Rest, Len+1};
-dec_response_flags(_Version, <<1:8, Rest/binary>>, Len) ->
- {true_oneway, Rest, Len+1};
-dec_response_flags(_Version, <<3:8, Rest/binary>>, Len) ->
- {true, Rest, Len+1};
-dec_response_flags(_Version, <<X:8, Rest/binary>>, Len) ->
- %% Not only the Response flag is set, test which.
- if
- %% Since the 6 most significant bits are unused we'll accept this for now.
- ((X band 16#03) == 16#03) ->
- {true, Rest, Len+1};
- ((X band 16#01) == 16#01) ->
- {true_oneway, Rest, Len+1};
- true ->
- {false, Rest, Len+1}
- end.
-
-%%-----------------------------------------------------------------
-%% Func : dec_target_addr
-%% Args : Octet
-%% Returns : boolean
-%%-----------------------------------------------------------------
-dec_target_addr(Version, Message, Len, ByteOrder, RequestId, Type) ->
- case dec_type(?TARGETADDRESS, Version, Message, Len, ByteOrder, [], 0) of
- {#'GIOP_TargetAddress'{label = ?GIOP_KeyAddr, value = KeyAddr}, Rest3, Len3, C} ->
- {dec_target_key(KeyAddr, RequestId, Version, Type), Rest3, Len3, C};
- {#'GIOP_TargetAddress'{label = ?GIOP_ProfileAddr,
- value = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP,
- profile_data=PA}},
- Rest3, Len3, C} ->
- {dec_target_key(PA, RequestId, Version, Type), Rest3, Len3, C};
- {#'GIOP_TargetAddress'{label = ?GIOP_ReferenceAddr,
- value = #'GIOP_IORAddressingInfo'{
- selected_profile_index = _PI,
- ior = IOR}}, Rest3, Len3, C} ->
- {dec_target_key(iop_ior:get_objkey(IOR), RequestId, Version, Type),
- Rest3, Len3, C};
- Other ->
- orber:dbg("[~p] cdr_decode:dec_target_addr(~p);~n"
- "Unsupported TargetAddress.", [?LINE, Other], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 12), completion_status=?COMPLETED_MAYBE})
- end.
-
-%%-----------------------------------------------------------------
-%% Func : dec_target_key
-%% Args : Octet
-%% Returns : boolean
-%%-----------------------------------------------------------------
-dec_target_key(Key, RequestId, Version, Type) ->
- %% The Type argument is used as an identifier of which operation it is.
- %% We need it to be able to tell the difference if it's, for example,
- %% a request or locate-request.
- case corba:string_to_objkey_local(Key) of
- {location_forward, Object} ->
- throw({Type, Object, RequestId, Version, Key});
- ObjRef ->
- ObjRef
- end.
-
-%%-----------------------------------------------------------------
-%% Func: dec_request_header/3
-%% Args:
-%% Message - The message
-%% Len0 - Number of bytes already read.
-%% ByteOrder - little or big
-%% Returns:
-%%-----------------------------------------------------------------
-dec_request_header(Version, Message, Len0, ByteOrder, _Buffer) when Version == {1,2} ->
- {Request_id, Rest1, Len1, _} = dec_type('tk_ulong', Version, Message, Len0,
- ByteOrder, [], 0),
- {ResponseFlags, Rest2, Len2} = dec_response_flags(Version, Rest1, Len1),
- {_, Rest2b, Len2b, _} = dec_type({'tk_array', 'tk_octet', 3}, Version, Rest2, Len2, ByteOrder, [], 0),
- {Object_key, Rest3, Len3, _} = dec_target_addr(Version, Rest2b, Len2b, ByteOrder, Request_id,
- 'location_forward'),
- {Operation, Rest4, Len4, _} = dec_type({'tk_string', 0}, Version, Rest3, Len3, ByteOrder, [], 0),
- {Context, Rest5, Len5} = dec_service_context(Version, Rest4, Len4, ByteOrder),
- {Version, #request_header{service_context=Context,
- request_id=Request_id,
- response_expected=ResponseFlags,
- object_key=Object_key,
- operation=list_to_atom(Operation),
- requesting_principal=""}, Rest5, Len5, ByteOrder};
-dec_request_header(Version, Message, Len0, ByteOrder, _Buffer) ->
- {Context, Rest1, Len1} = dec_service_context(Version, Message, Len0, ByteOrder),
- {Request_id, Rest2, Len2, _} = dec_type('tk_ulong', Version, Rest1, Len1, ByteOrder, [], 0),
- {Response_expected, Rest3, Len3, _} = dec_type('tk_boolean', Version, Rest2, Len2,
- ByteOrder, [], 0),
- {ObjKey, Rest4, Len4, _} = dec_type({'tk_sequence', 'tk_octet', 0}, Version, Rest3,
- Len3, ByteOrder, [], 0),
- Object_key = dec_target_key(ObjKey, Request_id, Version, 'location_forward'),
- {Operation, Rest5, Len5, _} = dec_type({'tk_string', 0}, Version, Rest4, Len4, ByteOrder, [], 0),
- {Principal, Rest, Len, _} = dec_type({'tk_string', 0}, Version, Rest5,Len5, ByteOrder, [], 0),
- {Version, #request_header{service_context=Context,
- request_id=Request_id,
- response_expected=Response_expected,
- object_key=Object_key,
- operation=list_to_atom(Operation),
- requesting_principal=Principal}, Rest, Len, ByteOrder}.
-
-
-%%-----------------------------------------------------------------
-%% Func: dec_service_context/4
-%% Args: Version - e.g. 1.2
-%% Message - The message
-%% Len - Number of bytes already read.
-%% ByteOrder - little or big
-%% Returns:
-%%-----------------------------------------------------------------
-dec_service_context(Version, Message, Len, ByteOrder) ->
- {Context, Rest, Len1} = dec_type(?IOP_SERVICECONTEXT, Version, Message,
- Len, ByteOrder),
- {dec_used_contexts(Version, Context, []), Rest, Len1}.
-
-dec_used_contexts(_Version, [], Ctxs) ->
- Ctxs;
-dec_used_contexts({1,0}, [#'IOP_ServiceContext'{context_id=?IOP_CodeSets}|T], Ctxs) ->
- %% Not supported by 1.0, drop it.
- dec_used_contexts({1,0}, T, Ctxs);
-dec_used_contexts(Version, [#'IOP_ServiceContext'{context_id=?IOP_CodeSets,
- context_data = Bytes}|T], Ctxs) ->
- {ByteOrder, Rest} = dec_byte_order(list_to_binary(Bytes)),
- {CodeCtx, _, _} = dec_type(?CONV_FRAME_CODESETCONTEXT, Version,
- Rest, 1, ByteOrder),
- dec_used_contexts(Version, T,
- [#'IOP_ServiceContext'{context_id=?IOP_CodeSets,
- context_data = CodeCtx}|Ctxs]);
-dec_used_contexts(Version, [#'IOP_ServiceContext'{context_id=?IOP_BI_DIR_IIOP,
- context_data = Bytes}|T], Ctxs) ->
- {ByteOrder, Rest} = dec_byte_order(list_to_binary(Bytes)),
- {BiDirCtx, _, _} = dec_type(?IIOP_BIDIRIIOPSERVICECONTEXT, Version,
- Rest, 1, ByteOrder),
- dec_used_contexts(Version, T,
- [#'IOP_ServiceContext'{context_id=?IOP_BI_DIR_IIOP,
- context_data = BiDirCtx}|Ctxs]);
-dec_used_contexts(Version, [#'IOP_ServiceContext'{context_id=?IOP_FT_REQUEST,
- context_data = Bytes}|T], Ctxs) ->
- {ByteOrder, Rest} = dec_byte_order(list_to_binary(Bytes)),
- {Ctx, _, _} = dec_type(?FT_FTRequestServiceContext, Version,
- Rest, 1, ByteOrder),
- dec_used_contexts(Version, T,
- [#'IOP_ServiceContext'{context_id=?IOP_FT_REQUEST,
- context_data = Ctx}|Ctxs]);
-dec_used_contexts(Version, [#'IOP_ServiceContext'{context_id=?IOP_FT_GROUP_VERSION,
- context_data = Bytes}|T], Ctxs) ->
- {ByteOrder, Rest} = dec_byte_order(list_to_binary(Bytes)),
- {Ctx, _, _} = dec_type(?FT_FTGroupVersionServiceContext, Version,
- Rest, 1, ByteOrder),
- dec_used_contexts(Version, T,
- [#'IOP_ServiceContext'{context_id=?IOP_FT_GROUP_VERSION,
- context_data = Ctx}|Ctxs]);
-dec_used_contexts(Version, [#'IOP_ServiceContext'{context_id=?IOP_SecurityAttributeService,
- context_data = Bytes}|T], Ctxs) ->
- {ByteOrder, Rest} = dec_byte_order(list_to_binary(Bytes)),
- {Ctx, _, _} = dec_type(?CSI_SASContextBody, Version,
- Rest, 1, ByteOrder),
- dec_used_contexts(Version, T,
- [#'IOP_ServiceContext'{context_id=?IOP_SecurityAttributeService,
- context_data = Ctx}|Ctxs]);
-dec_used_contexts(Version, [#'IOP_ServiceContext'{context_id=?ORBER_GENERIC_CTX_ID,
- context_data = Bytes}|T], Ctxs) ->
- {ByteOrder, Rest} = dec_byte_order(list_to_binary(Bytes)),
- {Ctx, _, _} = dec_type(?ORBER_GENERIC_CTX, Version,
- Rest, 1, ByteOrder),
- dec_used_contexts(Version, T,
- [#'IOP_ServiceContext'{context_id=?ORBER_GENERIC_CTX_ID,
- context_data = binary_to_term(list_to_binary(Ctx))}|Ctxs]);
-dec_used_contexts(Version, [H|T], Ctxs) ->
- dec_used_contexts(Version, T, [H|Ctxs]).
-
-%%-----------------------------------------------------------------
-%% Func: dec_request_body
-%% Args: Version - e.g. 1.2
-%% Returns:
-%%-----------------------------------------------------------------
-dec_request_body(Version, ReqHdr, Rest, Len, ByteOrder, Buffer) ->
- {Parameters, TypeCodes, _} =
- dec_request_body(Version, ReqHdr#request_header.object_key,
- ReqHdr#request_header.operation,
- Rest, Len, ByteOrder, Buffer, Len),
- {Version, ReqHdr, Parameters, TypeCodes}.
-
-dec_request_body(Version, Object_key, Operation, Body, Len, ByteOrder, Buffer, Counter)
- when Version == {1,2} ->
- case orber_typedefs:get_op_def(Object_key, Operation) of
- {RetType, [], OutParameters} ->
- {[], {RetType, [], OutParameters}, Len};
- {RetType, InParameters, OutParameters} ->
- {Rest, Len1, NewC} = dec_align(Body, Len, 8, Counter),
- {Parameters, Len2} = dec_parameters(Version, InParameters, Rest, Len1,
- ByteOrder, Buffer, NewC),
- {Parameters, {RetType, InParameters, OutParameters}, Len2}
- end;
-dec_request_body(Version, Object_key, Operation, Body, Len, ByteOrder, Buffer, Counter) ->
- {RetType, InParameters, OutParameters} =
- orber_typedefs:get_op_def(Object_key, Operation),
- {Parameters, Len1} = dec_parameters(Version, InParameters, Body, Len, ByteOrder, Buffer, Counter),
- {Parameters, {RetType, InParameters, OutParameters}, Len1}.
-
-dec_parameters(_, [], _, Len, _, _, _) ->
- {[], Len};
-dec_parameters(Version, [P1 |InParList], Body, Len, ByteOrder, Buffer, Counter) ->
- {Object, Rest, Len1, NewCounter} = dec_type(P1, Version, Body, Len, ByteOrder, Buffer, Counter),
- {List, Len2} = dec_parameters(Version, InParList, Rest, Len1, ByteOrder, Buffer, NewCounter),
- {[Object | List], Len2}.
-
-%%-----------------------------------------------------------------
-%% Func: dec_reply/5
-%% Args:
-%% Message - The message
-%% Len0 - Number of bytes already read.
-%% ByteOrder - little or big
-%% Returns:
-%% A tuple {ReplyHeader, Result} where ReplyHeader is a
-%% reply_header record and Result the decode result.
-%%-----------------------------------------------------------------
-dec_reply(Version, TypeCodes, Message, Len0, ByteOrder) ->
- {ReplyHeader, Rest, Len} = dec_reply_header(Version, Message, Len0, ByteOrder),
- {Result, Par} =
- case ReplyHeader#reply_header.reply_status of
- 'no_exception' ->
- {R, P, _} = dec_reply_body(Version, TypeCodes, Rest, Len, ByteOrder, Message),
- {R, P};
- 'system_exception' ->
- {R, _} = dec_system_exception(Version, Rest, Len, ByteOrder),
- {R, []};
- 'user_exception' ->
- {R, _} = dec_user_exception(Version, Rest, Len, ByteOrder),
- {R, []};
- 'location_forward' ->
- {R, _, _} = dec_reply_body(Version, {{'tk_objref', "", ""}, [],[]},
- Rest, Len, ByteOrder, Message),
- {R, []};
- %% This is deprecated in later version than CORBA-2.3.1. We'll leave it for
- %% now.
- 'location_forward_perm' ->
- {R, _, _} = dec_reply_body(Version, {{'tk_objref', "", ""}, [],[]},
- Rest, Len, ByteOrder, Message),
- {R, []};
- 'needs_addressing_mode' ->
- {R, _, _} = dec_reply_body(Version, {'tk_short', [],[]},
- Rest, Len, ByteOrder, Message),
- {R, []}
- end,
- {ReplyHeader, Result, Par}.
-
-
-%% ## NEW IIOP 1.2 ##
-dec_reply_header(Version, Message, Len0, ByteOrder) when Version == {1,2} ->
- {Request_id, Rest1, Len1} = dec_type('tk_ulong', Version, Message, Len0, ByteOrder),
- {ReplyStatus, Rest2, Len2} = dec_reply_status(Version, Rest1, Len1, ByteOrder),
- {Context, Rest, Len3} = dec_service_context(Version, Rest2, Len2, ByteOrder),
- {#reply_header{service_context=Context, request_id=Request_id, reply_status=ReplyStatus},
- Rest, Len3};
-
-dec_reply_header(Version, Message, Len0, ByteOrder) ->
- {Context, Rest1, Len1} = dec_service_context(Version, Message, Len0, ByteOrder),
- {Request_id, Rest2, Len2} = dec_type('tk_ulong', Version, Rest1, Len1, ByteOrder),
- {ReplyStatus, Rest, Len3} = dec_reply_status(Version, Rest2, Len2, ByteOrder),
- {#reply_header{service_context=Context, request_id=Request_id, reply_status=ReplyStatus},
- Rest, Len3}.
-
-dec_reply_status(Version, Status, Len, ByteOrder) ->
- {L, Rest, Len1}= dec_type('tk_ulong', Version, Status, Len, ByteOrder),
- {dec_giop_reply_status_type(L), Rest, Len1}.
-
-dec_reply_body(_, {'tk_void', _, []}, <<>>, Len, _, _) ->
- %% This case is mainly to be able to avoid removing non-existent alignment for
- %% IIOP-1.2 messages if the body should be empty, i.e., void return value and
- %% no out parameters.
- {ok, [], Len};
-dec_reply_body(Version, {RetType, _InParameters, OutParameters}, Body, Len,
- ByteOrder, Bytes) when Version == {1,2} ->
- {Rest, Len1, Counter} = dec_align(Body, Len, 8, Len),
- {Result, Rest2, Len2, C} = dec_type(RetType, Version, Rest, Len1, ByteOrder, Bytes, Counter),
- {Par, Len3} = dec_parameters(Version, OutParameters, Rest2, Len2, ByteOrder, Bytes, C),
- {Result, Par, Len3};
-dec_reply_body(Version, {RetType, _InParameters, OutParameters}, Body, Len, ByteOrder, Bytes) ->
- {Result, Rest, Len1, C} = dec_type(RetType, Version, Body, Len, ByteOrder, Bytes, Len),
- {Par, Len2} = dec_parameters(Version, OutParameters, Rest, Len1, ByteOrder, Bytes, C),
- {Result, Par, Len2}.
-
-
-%%-----------------------------------------------------------------
-%% Func: dec_cancel_request/3
-%% Args:
-%% Message - The message
-%% Len - Number of bytes already read.
-%% ByteOrder - little or big
-%% Returns:
-%% A cancel_request_header record.
-%%-----------------------------------------------------------------
-dec_cancel_request(Version, Message, Len, ByteOrder) ->
- {Request_id, _, _} = dec_type('tk_ulong', Version, Message, Len, ByteOrder),
- #cancel_request_header{request_id=Request_id}.
-
-%%-----------------------------------------------------------------
-%% Func: dec_locate_request/3
-%% Args:
-%% Message - The message
-%% Len - Number of bytes already read.
-%% ByteOrder - little or big
-%% Returns:
-%% A locate_request_header record.
-%%-----------------------------------------------------------------
-%% ## NEW IIOP 1.2 ##
-dec_locate_request(Version, Message, Len, ByteOrder) when Version == {1,2} ->
- {Request_id, Rest, Len1} = dec_type('tk_ulong', Version, Message, Len, ByteOrder),
- {Object_key, _, _, _} = dec_target_addr(Version, Rest, Len1, ByteOrder, Request_id,
- 'object_forward'),
- {Version, #locate_request_header{request_id=Request_id, object_key=Object_key}};
-dec_locate_request(Version, Message, Len, ByteOrder) ->
- {Request_id, Rest, Len1} = dec_type('tk_ulong', Version, Message, Len, ByteOrder),
- {ObjKey, _, _} = dec_type({'tk_sequence', 'tk_octet', 0}, Version, Rest,
- Len1, ByteOrder),
- Object_key = dec_target_key(ObjKey, Request_id, Version, 'object_forward'),
- {Version, #locate_request_header{request_id=Request_id, object_key=Object_key}}.
-
-
-%%-----------------------------------------------------------------
-%% Func: dec_locate_reply/3
-%% Args:
-%% Message - The message
-%% Len - Number of bytes already read.
-%% ByteOrder - little or big
-%% Returns:
-%% A locate_reply_header record.
-%%-----------------------------------------------------------------
-dec_locate_reply(Version, Message, Len, ByteOrder) ->
- {ReplyHeader, Rest1, Len1} = dec_locate_reply_header(Version, Message, Len, ByteOrder),
- {ReplyHeader, dec_locate_reply_body(Version, ReplyHeader#locate_reply_header.locate_status, Rest1,
- Len1, ByteOrder)}.
-
-dec_locate_reply_header(Version, Message, Len, ByteOrder) ->
- {Request_id, Rest1, Len1} = dec_type('tk_ulong', Version, Message, Len, ByteOrder),
- {Locate_status, Rest2, Len2} = dec_locate_status(Version, Rest1, Len1, ByteOrder),
- {#locate_reply_header{request_id=Request_id, locate_status=Locate_status}, Rest2, Len2}.
-
-dec_locate_reply_body(Version, LocateStatus, Rest, Len, ByteOrder) when Version == {1,2} ->
- %% In CORBA-2.3.1 the LocateReply body didn't align the body (8-octet
- %% boundry) for IIOP-1.2. This have been changed in CORBA-2.4 and
- %% changed back in CORBA-2.6. Hence, we should not change this.
- case LocateStatus of
- 'object_forward' ->
- {ObjRef, _, _, _} = dec_objref(Version, Rest, Len, ByteOrder),
- ObjRef;
- 'object_forward_perm' ->
- %% This is deprecated in later version than CORBA-2.3.1. We'll leave it for
- %% now.
- {ObjRef, _, _, _} = dec_objref(Version, Rest, Len, ByteOrder),
- ObjRef;
- 'loc_system_exception' ->
- %% This should be updated but since 'dec_system_exception' removes
- %% alignment, which the LocateReplyBody don't have, for 1.2 we
- %% pretend it's 1.1 for now.
- {SysExc, _} = dec_system_exception({1,1}, Rest, Len, ByteOrder),
- corba:raise(SysExc);
- 'loc_needs_addressing_mode' ->
- %% Not supported.
- [];
- _ ->
- []
- end;
-dec_locate_reply_body(Version, LocateStatus, Rest, Len, ByteOrder) ->
- case LocateStatus of
- 'object_forward' ->
- {ObjRef, _, _, _} = dec_objref(Version, Rest, Len, ByteOrder),
- ObjRef;
- _ ->
- []
- end.
-
-dec_locate_status(Version, Bytes, Len, ByteOrder) ->
- {L, Rest, Len1} = dec_type('tk_ulong', Version, Bytes, Len, ByteOrder),
- {dec_giop_locate_status_type(L), Rest, Len1}.
-
-
-%%-----------------------------------------------------------------
-%% Func: dec_fragment_header/5
-%% Args:
-%% Message - The message
-%% Len0 - Number of bytes already read.
-%% ByteOrder - little or big
-%% Returns:
-%%-----------------------------------------------------------------
-dec_fragment_header(Version, Message, Len0, ByteOrder, _Buffer) when Version == {1,2} ->
- {RequestId, Rest1, Len1, _} = dec_type('tk_ulong', Version, Message, Len0,
- ByteOrder, [], 0),
- {Version, #fragment_header{request_id=RequestId}, Rest1, Len1, ByteOrder};
-dec_fragment_header(Version, _Message, _Len0, _ByteOrder, _Buffer) ->
- %% The FragmentHeader is IIOP-1.2 specific. Hence, do nothing here.
- orber:dbg("[~p] cdr_decode:dec_fragment_header(~p)~n"
- "Orber only supports fragmented messages for IIOP-1.2.",
- [?LINE, Version], ?DEBUG_LEVEL),
- exit(message_error).
-% {Version, #fragment_header{}, Message, Len0, ByteOrder}.
-
-%%-----------------------------------------------------------------
-%% Func: dec_giop_reply_status_type
-%% Args:
-%% An integer status code
-%% Returns:
-%% An atom which is the reply status
-%%-----------------------------------------------------------------
-dec_giop_reply_status_type(0) ->
- 'no_exception';
-dec_giop_reply_status_type(1) ->
- 'user_exception';
-dec_giop_reply_status_type(2) ->
- 'system_exception';
-dec_giop_reply_status_type(3) ->
- 'location_forward';
-%% ## IIOP-1.2 ##
-dec_giop_reply_status_type(4) ->
- 'location_forward_perm';
-dec_giop_reply_status_type(5) ->
- 'needs_addressing_mode'.
-
-%%-----------------------------------------------------------------
-%% Func: dec_giop_locate_status_type
-%% Args:
-%% An integer status code
-%% Returns:
-%% An atom which is the reply status
-%%-----------------------------------------------------------------
-dec_giop_locate_status_type(0) ->
- 'unknown_object';
-dec_giop_locate_status_type(1) ->
- 'object_here';
-dec_giop_locate_status_type(2) ->
- 'object_forward';
-%% ## IIOP-1.2 ##
-dec_giop_locate_status_type(3) ->
- 'object_forward_perm';
-dec_giop_locate_status_type(4) ->
- 'loc_system_exception';
-dec_giop_locate_status_type(5) ->
- 'loc_needs_addressing_mode'.
-
-
-%%-----------------------------------------------------------------
-%% Func: dec_type/5
-%%-----------------------------------------------------------------
-dec_type(Type, Version, Bytes, Len, ByteOrder) ->
- {Val, Rest, Len2, _} =
- dec_type(Type, Version, Bytes, Len, ByteOrder, [], 0),
- {Val, Rest, Len2}.
-
-dec_type('tk_null', _Version, Bytes, Len, _, _, C) ->
- {'null', Bytes, Len, C};
-dec_type('tk_void', _Version, Bytes, Len, _, _, C) ->
- {'ok', Bytes, Len, C};
-dec_type('tk_short', _Version, Bytes, Len, ByteOrder, _, C) ->
- {Rest, Len1, NewC} = dec_align(Bytes, Len, 2, C),
- {Short, Rest1} = cdrlib:dec_short(ByteOrder, Rest),
- {Short, Rest1, Len1 + 2, NewC+2};
-dec_type('tk_long', _Version, Bytes, Len, ByteOrder, _, C) ->
- {Rest, Len1, NewC} = dec_align(Bytes, Len, 4, C),
- {Long, Rest1} = cdrlib:dec_long(ByteOrder, Rest),
- {Long, Rest1, Len1 + 4, NewC+4};
-dec_type('tk_longlong', _Version, Bytes, Len, ByteOrder, _, C) ->
- {Rest, Len1, NewC} = dec_align(Bytes, Len, 8, C),
- {Long, Rest1} = cdrlib:dec_longlong(ByteOrder, Rest),
- {Long, Rest1, Len1 + 8, NewC+8};
-dec_type('tk_ushort', _Version, Bytes, Len, ByteOrder, _, C) ->
- {Rest, Len1, NewC} = dec_align(Bytes, Len, 2, C),
- {Short, Rest1} = cdrlib:dec_unsigned_short(ByteOrder, Rest),
- {Short, Rest1, Len1 + 2, NewC+2};
-dec_type('tk_ulong', _Version, Bytes, Len, ByteOrder, _, C) ->
- {Rest, Len1, NewC} = dec_align(Bytes, Len, 4, C),
- {Long, Rest1} = cdrlib:dec_unsigned_long(ByteOrder, Rest),
- {Long, Rest1, Len1 + 4, NewC+4};
-dec_type('tk_ulonglong', _Version, Bytes, Len, ByteOrder, _, C) ->
- {Rest, Len1, NewC} = dec_align(Bytes, Len, 8, C),
- {Long, Rest1} = cdrlib:dec_unsigned_longlong(ByteOrder, Rest),
- {Long, Rest1, Len1 + 8, NewC+8};
-dec_type('tk_float', _Version, Bytes, Len, ByteOrder, _, C) ->
- {Rest, Len1, NewC} = dec_align(Bytes, Len, 4, C),
- {Float, Rest1} = cdrlib:dec_float(ByteOrder, Rest),
- {Float, Rest1, Len1 + 4, NewC+4};
-dec_type('tk_double', _Version, Bytes, Len, ByteOrder, _, C) ->
- {Rest, Len1, NewC} = dec_align(Bytes, Len, 8, C),
- {Double, Rest1} = cdrlib:dec_double(ByteOrder, Rest),
- {Double, Rest1, Len1 + 8, NewC+8};
-dec_type('tk_boolean', _Version, Bytes, Len, _, _, C) ->
- {Bool, Rest} = cdrlib:dec_bool(Bytes),
- {Bool, Rest, Len + 1, C+1};
-dec_type('tk_char', _Version, Bytes, Len, _, _, C) ->
- {Char, Rest} = cdrlib:dec_char(Bytes),
- {Char, Rest, Len + 1, C+1};
-dec_type('tk_wchar', {1,2}, Bytes, Len, _ByteOrder, _, C) ->
- %% For IIOP-1.2 a wchar is almost encoded the same way as an octet-sequence.
- %% The only difference is that the length-value is an octet as well.
- case cdrlib:dec_octet(Bytes) of
- {2, Rest1} ->
- %% Currently we only allow 2-bytes wchar.
- {WChar, Rest2} = cdrlib:dec_unsigned_short(big, Rest1),
- {WChar, Rest2, Len+3, C+3};
- {What, _} ->
- orber:dbg("[~p] cdr_decode:dec_type(~p); unsupported wchar",
- [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'DATA_CONVERSION'{completion_status=?COMPLETED_NO})
- end;
-%% For 1.1 the wchar is limited to the use of two-octet fixed-length encoding.
-dec_type('tk_wchar', _Version, Bytes, Len, ByteOrder, _, C) ->
- {Rest, Len1, NewC} = dec_align(Bytes, Len, 2, C),
- {WChar, Rest2} = cdrlib:dec_unsigned_short(ByteOrder, Rest),
- {WChar, Rest2, Len1 + 2, NewC+2};
-dec_type('tk_octet', _Version, Bytes, Len, _, _, C) ->
- {Octet, Rest} = cdrlib:dec_octet(Bytes),
- {Octet, Rest, Len + 1, C+1};
-dec_type('tk_any', Version, Bytes, Len, ByteOrder, Buff, C) ->
- {TypeCode, Rest1, Len1, NewC} = dec_type('tk_TypeCode', Version, Bytes, Len, ByteOrder, Buff, C),
- {Value, Rest2, Len2, NewC2} = dec_type(TypeCode, Version, Rest1, Len1, ByteOrder, Buff, NewC),
- {#any{typecode=TypeCode, value=Value}, Rest2, Len2, NewC2};
-dec_type('tk_TypeCode', Version, Bytes, Len, ByteOrder, Buff, C) ->
- dec_type_code(Version, Bytes, Len, ByteOrder, Buff, C);
-dec_type('tk_Principal', Version, Bytes, Len, ByteOrder, Buff, C) ->
- dec_sequence(Version, Bytes, 'tk_octet', Len, ByteOrder, Buff, C);
-dec_type({'tk_objref', _IFRId, _Name}, Version, Bytes, Len, ByteOrder, Buff, C) ->
- dec_objref(Version, Bytes, Len, ByteOrder, Buff, C);
-dec_type({'tk_struct', IFRId, Name, ElementList}, Version, Bytes, Len, ByteOrder, Buff, C) ->
- dec_struct(Version, IFRId, Name, ElementList, Bytes, Len, ByteOrder, Buff, C);
-dec_type({'tk_union', IFRId, Name, DiscrTC, Default, ElementList},
- Version, Bytes, Len, ByteOrder, Buff, C) ->
- dec_union(Version, IFRId, Name, DiscrTC, Default, ElementList, Bytes, Len, ByteOrder, Buff, C);
-dec_type({'tk_enum', _IFRId, _Name, ElementList}, _Version, Bytes, Len, ByteOrder, _, C) ->
- {Rest, Len1, NewC} = dec_align(Bytes, Len, 4, C),
- {Enum, Rest1} = cdrlib:dec_enum(ByteOrder, ElementList, Rest),
- {Enum, Rest1, Len1 + 4, NewC+4};
-dec_type({'tk_string', _MaxLength}, Version, Bytes, Len, ByteOrder, Buff, C) ->
- dec_string(Version, Bytes, Len, ByteOrder, Buff, C);
-dec_type({'tk_wstring', _MaxLength}, Version, Bytes, Len, ByteOrder, Buff, C) ->
- dec_wstring(Version, Bytes, Len, ByteOrder, Buff, C);
-dec_type({'tk_sequence', ElemTC, _MaxLength}, Version, Bytes, Len, ByteOrder, Buff, C) ->
- dec_sequence(Version, Bytes, ElemTC, Len, ByteOrder, Buff, C);
-dec_type({'tk_array', ElemTC, Size}, Version, Bytes, Len, ByteOrder, Buff, C) ->
- dec_array(Version, Bytes, Size, ElemTC, Len, ByteOrder, Buff, C);
-dec_type({'tk_alias', _IFRId, _Name, TC}, Version, Bytes, Len, ByteOrder, Buff, C) ->
- dec_type(TC, Version, Bytes, Len, ByteOrder, Buff, C);
-%dec_type({'tk_except', IFRId, Name, ElementList}, Version, Bytes, Len, ByteOrder) ->
-dec_type({'tk_fixed', Digits, Scale}, _Version, Bytes, Len, _ByteOrder, _Buff, C) ->
- dec_fixed(Digits, Scale, Bytes, Len, C);
-dec_type(Type, _, _, _, _, _, _) ->
- orber:dbg("[~p] cdr_decode:dec_type(~p)~n"
- "Incorrect TypeCode or unsupported type.",
- [?LINE, Type], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 13), completion_status=?COMPLETED_MAYBE}).
-
-stringify_enum({tk_enum,_,_,_}, Label) ->
- atom_to_list(Label);
-stringify_enum(_, Label) ->
- Label.
-
-%%-----------------------------------------------------------------
-%% Func: dec_fixed
-%%-----------------------------------------------------------------
-%% Digits eq. total number of digits.
-%% Scale eq. position of the decimal point.
-%% E.g. fixed<5,2> - "123.45"
-%% E.g. fixed<4,2> - "12.34"
-%% These are encoded as:
-%% ## <5,2> ## ## <4,2> ##
-%% 1,2 0,1 eq. 1 octet
-%% 3,4 2,3
-%% 5,0xC 4,0xC
-%%
-%% Each number is encoded as a half-octet. Note, for <4,2> a zero is
-%% added first to to be able to create "even" octets.
-dec_fixed(0, 0, Bytes, Len, C) ->
- {#fixed{digits = 0, scale = 0, value = ""}, Bytes, Len, C};
-dec_fixed(Digits, Scale, Bytes, Len, C) ->
- case ?ODD(Digits) of
- true ->
- {Fixed, Bytes2, Len2, C2, Sign} = dec_fixed_2(Digits, Scale, Bytes, Len, C),
- case Sign of
- ?FIXED_POSITIVE ->
- {#fixed{digits = Digits, scale = Scale,
- value = list_to_integer(Fixed)}, Bytes2, Len2, C2};
- ?FIXED_NEGATIVE ->
- {#fixed{digits = Digits, scale = Scale,
- value = -list_to_integer(Fixed)}, Bytes2, Len2, C2}
- end;
- false ->
- %% If the length (of fixed) is even a zero is added first.
- %% Subtract that we've read 1 digit.
- <<0:4,D2:4,T/binary>> = Bytes,
- {Fixed, Bytes2, Len2, C2, Sign} = dec_fixed_2(Digits-1, Scale, T, Len+1, C+1),
- case Sign of
- ?FIXED_POSITIVE ->
- {#fixed{digits = Digits, scale = Scale,
- value = list_to_integer([D2+48|Fixed])}, Bytes2, Len2, C2};
- ?FIXED_NEGATIVE ->
- {#fixed{digits = Digits, scale = Scale,
- value = -list_to_integer([D2+48|Fixed])}, Bytes2, Len2, C2}
- end
- end.
-
-dec_fixed_2(1, _Scale, <<D1:4,?FIXED_POSITIVE:4,T/binary>>, Len, C) ->
- {[D1+48], T, Len+1, C+1, ?FIXED_POSITIVE};
-dec_fixed_2(1, _Scale, <<D1:4,?FIXED_NEGATIVE:4,T/binary>>, Len, C) ->
- {[D1+48], T, Len+1, C+1, ?FIXED_NEGATIVE};
-dec_fixed_2(Digits, Scale, _Bytes, _Len, _C) when Digits =< 0 ->
- orber:dbg("[~p] cdr_decode:dec_fixed_2(~p, ~p)~n"
- "Malformed fixed type.", [?LINE, Digits, Scale], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 14), completion_status=?COMPLETED_MAYBE});
-dec_fixed_2(Digits, Scale, <<>>, _Len, _C) ->
- orber:dbg("[~p] cdr_decode:dec_fixed_2(~p, ~p)~n"
- "The fixed type received was to short.",
- [?LINE, Digits, Scale], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 14), completion_status=?COMPLETED_MAYBE});
-dec_fixed_2(Digits, Scale, <<D1:4,D2:4,T/binary>>, Len, C) ->
- {Seq, Rest2, Len2, NewC2, Sign} = dec_fixed_2(Digits-2, Scale, T, Len+1, C+1),
- {[D1+48, D2+48 | Seq], Rest2, Len2, NewC2, Sign}.
-
-%%-----------------------------------------------------------------
-%% Func: dec_sequence/7 and dec_sequence/8
-%%-----------------------------------------------------------------
-dec_sequence(_Version, Message, 'tk_octet', Len, ByteOrder, _Buff, C) ->
- {Rest, Len1, NewC} = dec_align(Message, Len, 4, C),
- {Size, Rest1} = cdrlib:dec_unsigned_long(ByteOrder, Rest),
- <<OctetSeq:Size/binary, Rest2/binary>> = Rest1,
- {binary_to_list(OctetSeq), Rest2, Len1+4+Size, NewC+4+Size};
-dec_sequence(_Version, Message, 'tk_char', Len, ByteOrder, _Buff, C) ->
- {Rest, Len1, NewC} = dec_align(Message, Len, 4, C),
- {Size, Rest1} = cdrlib:dec_unsigned_long(ByteOrder, Rest),
- <<OctetSeq:Size/binary, Rest2/binary>> = Rest1,
- {binary_to_list(OctetSeq), Rest2, Len1+4+Size, NewC+4+Size};
-%% We test if it's a sequence of struct's or unions. By doing this we only
-%% have to look up the IFR-ID once instead of N times (N eq length of sequence).
-dec_sequence(Version, Message, {'tk_struct', IFRId, ShortName, ElementList},
- Len, ByteOrder, Buff, C) when IFRId /= "", ShortName /= "" ->
- {Rest, Len1, NewC} = dec_align(Message, Len, 4, C),
- {Size, Rest1} = cdrlib:dec_unsigned_long(ByteOrder, Rest),
- case IFRId of
- ?SYSTEM_TYPE ->
- dec_sequence_struct(Version, Rest1, Size, ElementList, Len1 + 4,
- ByteOrder, Buff, NewC+4, ShortName);
- _ ->
- Name = ifrid_to_name(IFRId, ?IFR_StructDef),
- dec_sequence_struct(Version, Rest1, Size, ElementList, Len1 + 4,
- ByteOrder, Buff, NewC+4, Name)
- end;
-dec_sequence(Version, Message,
- {'tk_union', ?SYSTEM_TYPE, TCName, DiscrTC, Default, ElementList},
- Len, ByteOrder, Buff, C) ->
- {Rest, Len1, NewC} = dec_align(Message, Len, 4, C),
- {Size, Rest1} = cdrlib:dec_unsigned_long(ByteOrder, Rest),
- dec_sequence_union(Version, Rest1, Size, DiscrTC, Default, ElementList, Len1 + 4,
- ByteOrder, Buff, NewC+4, TCName);
-dec_sequence(Version, Message,
- {'tk_union', IFRId, _TCName, DiscrTC, Default, ElementList},
- Len, ByteOrder, Buff, C) ->
- {Rest, Len1, NewC} = dec_align(Message, Len, 4, C),
- {Size, Rest1} = cdrlib:dec_unsigned_long(ByteOrder, Rest),
- Name = ifrid_to_name(IFRId, ?IFR_UnionDef),
- dec_sequence_union(Version, Rest1, Size, DiscrTC, Default, ElementList, Len1 + 4,
- ByteOrder, Buff, NewC+4, Name);
-dec_sequence(Version, Message, TypeCode, Len, ByteOrder, Buff, C) ->
- {Rest, Len1, NewC} = dec_align(Message, Len, 4, C),
- {Size, Rest1} = cdrlib:dec_unsigned_long(ByteOrder, Rest),
- dec_sequence(Version, Rest1, Size, TypeCode, Len1 + 4, ByteOrder, Buff, NewC+4).
-
-
-dec_sequence(_, Message, 0, _Type, Len, _ByteOrder, _Buff, C) ->
- {[], Message, Len, C};
-dec_sequence(Version, Message, N, Type, Len, ByteOrder, Buff, C) ->
- {Object, Rest1, Len1, NewC} = dec_type(Type, Version, Message, Len, ByteOrder, Buff, C),
- {Seq, Rest2, Len2, NewC2} = dec_sequence(Version, Rest1, N - 1, Type, Len1, ByteOrder, Buff, NewC),
- {[Object | Seq], Rest2, Len2, NewC2}.
-
-dec_sequence_struct(_, Message, 0, _Type, Len, _ByteOrder, _Buff, C, _Name) ->
- {[], Message, Len, C};
-dec_sequence_struct(Version, Message, N, TypeCodeList, Len, ByteOrder, Buff, C, Name) ->
- {Struct, Rest1, Len1, NewC} = dec_struct1(Version, TypeCodeList, Message, Len, ByteOrder, Buff, C),
- {Seq, Rest2, Len2, NewC2} = dec_sequence_struct(Version, Rest1, N - 1, TypeCodeList, Len1, ByteOrder,
- Buff, NewC, Name),
- {[list_to_tuple([Name |Struct]) | Seq], Rest2, Len2, NewC2}.
-
-
-dec_sequence_union(_, Message, 0, _DiscrTC, _Default, _ElementList,
- Len, _ByteOrder, _Buff, C, _Name) ->
- {[], Message, Len, C};
-dec_sequence_union(Version, Message, N, DiscrTC, Default, ElementList,
- Len, ByteOrder, Buff, C, Name) when is_list(ElementList) ->
-
- {Label, Rest1, Len1, NewC} = dec_type(DiscrTC, Version, Message, Len, ByteOrder, Buff, C),
- Result = dec_union(Version, stringify_enum(DiscrTC, Label), ElementList, Default,
- Rest1, Len1, ByteOrder, Buff, NewC),
- {Value, Rest2, Len2, NewC3} = case Result of
- {default, R, L, NewC2} ->
- dec_union(Version, default, ElementList, Default,
- R, L, ByteOrder, Buff, NewC2);
- X ->
- X
- end,
- {Seq, Rest3, Len3, NewC4} = dec_sequence_union(Version, Rest2, N - 1,
- DiscrTC, Default, ElementList,
- Len2, ByteOrder,
- Buff, NewC3, Name),
- {[{Name, Label, Value} | Seq], Rest3, Len3, NewC4};
-dec_sequence_union(Version, Message, N, _DiscrTC, _Default, Module,
- Len, ByteOrder, Buff, C, Name) when is_atom(Module) ->
- case catch Module:tc() of
- {tk_union, _, _, DiscrTC, Default, ElementList} ->
- dec_sequence_union(Version, Message, N, DiscrTC, Default, ElementList,
- Len, ByteOrder, Buff, C, Name);
- What ->
- orber:dbg("[~p] ~p:dec_sequence_union(~p). Union module doesn't exist or incorrect.",
- [?LINE, ?MODULE, What], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE})
- end.
-
-
-
-%% A special case; when something is encapsulated (i.e. sent as octet-sequence)
-%% we sometimes don not want the result to be converted to a list.
-dec_octet_sequence_bin(_Version, Message, Len, ByteOrder, _Buff, C) ->
- {Rest, Len1, NewC} = dec_align(Message, Len, 4, C),
- {Size, Rest1} = cdrlib:dec_unsigned_long(ByteOrder, Rest),
- <<OctetSeq:Size/binary, Rest2/binary>> = Rest1,
- {OctetSeq, Rest2, Len1+4+Size, NewC+4+Size}.
-
-%%-----------------------------------------------------------------
-%% Func: dec_array/5
-%%-----------------------------------------------------------------
-dec_array(Version, Message, Size, TypeCode, Len, ByteOrder, Buff, C) ->
- {Seq, Rest1, Len1, NewC} = dec_sequence(Version, Message, Size, TypeCode, Len,
- ByteOrder, Buff, C),
- {list_to_tuple(Seq), Rest1, Len1, NewC}.
-
-
-%%-----------------------------------------------------------------
-%% Func: dec_string/4
-%%-----------------------------------------------------------------
-dec_string(_Version, Message, Len, ByteOrder, _Buff, C) ->
- {Rest, Len1, NewC} = dec_align(Message, Len, 4, C),
- {Size, Rest1} = cdrlib:dec_unsigned_long(ByteOrder, Rest),
- if
- Size > 0 ->
- DataSize = Size-1,
- <<String:DataSize/binary, _Null:1/binary, Rest2/binary>> = Rest1,
- {binary_to_list(String), Rest2, Len1+4+Size, NewC+4+Size};
- true ->
- {"", Rest1, Len1 + 4, NewC+4}
- end.
-
-%%-----------------------------------------------------------------
-%% Func: dec_string/4
-%%-----------------------------------------------------------------
-dec_wstring({1,2}, Message, Len, ByteOrder, Buff, C) ->
- {Rest, Len1, NewC} = dec_align(Message, Len, 4, C),
- {Octets, Rest1} = cdrlib:dec_unsigned_long(ByteOrder, Rest),
- if
- Octets == 0 ->
- {"", Rest1, Len1 + 4, NewC+4};
- Octets > 0 ->
- Size = round(Octets/2),
- {String, Rest2, Len2, NewC2} =
- dec_sequence({1,2}, Rest1, Size, 'tk_ushort',
- Len1 + 4, big, Buff, NewC+4),
- {String, Rest2, Len2, NewC2};
- true ->
- orber:dbg("[~p] cdr_decode:dec_wstring(~p);",
- [?LINE, Rest1], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_NO})
- end;
-dec_wstring(Version, Message, Len, ByteOrder, Buff, C) ->
- {Rest, Len1, NewC} = dec_align(Message, Len, 4, C),
- {Size, Rest1} = cdrlib:dec_unsigned_long(ByteOrder, Rest),
- if
- Size > 0 ->
- {String, Rest2, Len2, NewC2} = dec_sequence(Version, Rest1, Size - 1, 'tk_wchar',
- Len1 + 4, ByteOrder, Buff, NewC+4),
- %% Remove the NULL character.
- {_, Rest3} = cdrlib:dec_unsigned_short(ByteOrder, Rest2),
- {String, Rest3, Len2 + 2, NewC2+2};
- Size == 0 ->
- {"", Rest1, Len1 + 4, NewC+4};
- true ->
- orber:dbg("[~p] cdr_decode:dec_wstring(~p);",
- [?LINE, Rest1], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_NO})
- end.
-
-
-%%-----------------------------------------------------------------
-%% Func: dec_union/9
-%%-----------------------------------------------------------------
-%% ## NEW IIOP 1.2 ##
-dec_union(Version, ?SYSTEM_TYPE, Name, DiscrTC, Default, ElementList, Bytes,
- Len, ByteOrder, Buff, C) ->
- {Label, Rest1, Len1, NewC} = dec_type(DiscrTC, Version, Bytes, Len, ByteOrder, Buff, C),
- {Value, Rest2, Len2, NewC3} = dec_union(Version, Label, ElementList, Default,
- Rest1, Len1, ByteOrder, Buff, NewC),
- {{Name, Label, Value}, Rest2, Len2, NewC3};
-
-
-dec_union(Version, IFRId, _, DiscrTC, Default, ElementList, Bytes, Len,
- ByteOrder, Buff, C) when is_list(ElementList) ->
- {Label, Rest1, Len1, NewC} = dec_type(DiscrTC, Version, Bytes, Len, ByteOrder, Buff, C),
- Result = dec_union(Version, stringify_enum(DiscrTC, Label), ElementList, Default,
- Rest1, Len1, ByteOrder, Buff, NewC),
- {Value, Rest2, Len2, NewC3} = case Result of
- {default, R, L, NewC2} ->
- dec_union(Version, default, ElementList, Default,
- R, L, ByteOrder, Buff, NewC2);
- X ->
- X
- end,
- Name = ifrid_to_name(IFRId, ?IFR_UnionDef),
- {{Name, Label, Value}, Rest2, Len2, NewC3};
-dec_union(Version, IFRId, _, _DiscrTC, _Default, Module, Bytes, Len,
- ByteOrder, Buff, C) when is_atom(Module) ->
- case catch Module:tc() of
- {tk_union, _, Name, DiscrTC, Default, ElementList} ->
- dec_union(Version, IFRId, Name, DiscrTC, Default, ElementList, Bytes, Len,
- ByteOrder, Buff, C);
- What ->
- orber:dbg("[~p] ~p:dec_union(~p). Union module doesn't exist or incorrect.",
- [?LINE, ?MODULE, What], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE})
- end.
-
-
-
-dec_union(_, _, [], Default, Message, Len, _, _Buff, C) when Default < 0 ->
- {undefined, Message, Len, C};
-dec_union(_, _, [], _Default, Message, Len, _, _Buff, C) ->
- {default, Message, Len, C};
-dec_union(Version, Label, [{Label, _Name, Type}|_List], _Default, Message, Len, ByteOrder, Buff, C) ->
- dec_type(Type, Version, Message, Len, ByteOrder, Buff, C);
-dec_union(Version, Label, [_H|List], Default, Message, Len, ByteOrder, Buff, C) ->
- dec_union(Version, Label, List, Default, Message, Len, ByteOrder, Buff, C).
-
-%%-----------------------------------------------------------------
-%% Func: dec_struct/7
-%%-----------------------------------------------------------------
-dec_struct(Version, "", "", TypeCodeList, Message, Len, ByteOrder, Buff, C) ->
- {Struct, Rest, Len1, NewC} = dec_struct1(Version, TypeCodeList, Message, Len, ByteOrder, Buff, C),
- {list_to_tuple(Struct), Rest, Len1, NewC};
-dec_struct(Version, [], Name, TypeCodeList, Message, Len, ByteOrder, Buff, C) ->
- %% This case is used when communicating with ORB:s which don't supply the IFRId
- %% field in struct type codes (used in any)
- {Struct, Rest, Len1, NewC} = dec_struct1(Version, TypeCodeList, Message, Len, ByteOrder, Buff, C),
- {list_to_tuple([list_to_atom(Name) |Struct]), Rest, Len1, NewC};
-dec_struct(Version, ?SYSTEM_TYPE, ShortName, TypeCodeList, Message, Len, ByteOrder, Buff, C) ->
- {Struct, Rest, Len1, NewC} = dec_struct1(Version, TypeCodeList, Message, Len, ByteOrder, Buff, C),
- {list_to_tuple([ShortName |Struct]), Rest, Len1, NewC};
-dec_struct(Version, IFRId, _ShortName, TypeCodeList, Message, Len, ByteOrder, Buff, C) ->
- Name = ifrid_to_name(IFRId, ?IFR_StructDef),
- {Struct, Rest, Len1, NewC} = dec_struct1(Version, TypeCodeList, Message, Len, ByteOrder, Buff, C),
- {list_to_tuple([Name |Struct]), Rest, Len1, NewC}.
-
-dec_struct1(_, [], Message, Len, _ByteOrder, _, C) ->
- {[], Message, Len, C};
-dec_struct1(Version, [{_ElemName, ElemType} | TypeCodeList], Message, Len, ByteOrder, Buff, C) ->
- {Element, Rest, Len1, NewC} = dec_type(ElemType, Version, Message, Len, ByteOrder, Buff, C),
- {Struct, Rest1, Len2, NewC2} = dec_struct1(Version, TypeCodeList, Rest, Len1, ByteOrder, Buff, NewC),
- {[Element |Struct], Rest1, Len2, NewC2};
-dec_struct1(Version, Module, Message, Len, ByteOrder, Buff, C) ->
- case catch Module:tc() of
- {tk_struct, _, _, TypeCodeList} ->
- dec_struct1(Version, TypeCodeList, Message, Len, ByteOrder, Buff, C);
- What ->
- orber:dbg("[~p] ~p:dec_struct1(~p). Struct module doesn't exist or incorrect.",
- [?LINE, ?MODULE, What], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE})
- end.
-
-ifrid_to_name([], Type) ->
- orber:dbg("[~p] ~p:ifrid_to_name([], ~p). No Id supplied.",
- [?LINE, ?MODULE, Type], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?CORBA_OMGVMCID bor 11),
- completion_status=?COMPLETED_MAYBE});
-ifrid_to_name(Id, Type) ->
- case orber:light_ifr() of
- true ->
- orber_ifr:get_module(Id, Type);
- false ->
- case catch ifrid_to_name_helper(Id, Type) of
- {'EXCEPTION', E} ->
- corba:raise(E);
- {'EXIT',{aborted,{no_exists,_}}} ->
- case orber:get_lightweight_nodes() of
- false ->
- orber:dbg("[~p] cdr_decode:ifrid_to_name(~p, ~p). IFRid not found.",
- [?LINE, Id, Type], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE});
- Nodes ->
- L = length(Nodes),
- IFR = get_ifr_node(Nodes, rand:uniform(L), L),
- list_to_atom('OrberApp_IFR':get_absolute_name(IFR, Id))
- end;
- {'EXIT', Other} ->
- orber:dbg("[~p] cdr_decode:ifrid_to_name(~p). Unknown: ~p",
- [?LINE, Id, Other], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE});
- Name ->
- list_to_atom(Name)
- end
- end.
-
-ifrid_to_name_helper(Id, ?IFR_UnionDef) ->
- case mnesia:dirty_index_read(ir_UnionDef, Id, #ir_UnionDef.id) of
- [#ir_UnionDef{absolute_name = [$:,$:|N]}] ->
- change_colons_to_underscore(N, []);
- Other ->
- orber:dbg("[~p] cdr_decode:ifrid_to_name(~p). IFR Id not found: ~p",
- [?LINE, Id, Other], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 9),
- completion_status=?COMPLETED_MAYBE})
- end;
-ifrid_to_name_helper(Id, ?IFR_StructDef) ->
- case mnesia:dirty_index_read(ir_StructDef, Id, #ir_StructDef.id) of
- [#ir_StructDef{absolute_name = [$:,$:|N]}] ->
- change_colons_to_underscore(N, []);
- Other ->
- orber:dbg("[~p] cdr_decode:ifrid_to_name(~p). IFR Id not found: ~p",
- [?LINE, Id, Other], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 10),
- completion_status=?COMPLETED_MAYBE})
- end;
-ifrid_to_name_helper(Id, ?IFR_ExceptionDef) ->
- case mnesia:dirty_index_read(ir_ExceptionDef, Id, #ir_ExceptionDef.id) of
- [#ir_ExceptionDef{absolute_name = [$:,$:|N]}] ->
- change_colons_to_underscore(N, []);
- Other ->
- orber:dbg("[~p] cdr_decode:ifrid_to_name(~p). IFR Id not found: ~p",
- [?LINE, Id, Other], ?DEBUG_LEVEL),
- corba:raise(#'UNKNOWN'{minor=(?CORBA_OMGVMCID bor 1),
- completion_status=?COMPLETED_MAYBE})
- end.
-
-change_colons_to_underscore([$:, $: | T], Acc) ->
- change_colons_to_underscore(T, [$_ |Acc]);
-change_colons_to_underscore([H |T], Acc) ->
- change_colons_to_underscore(T, [H |Acc]);
-change_colons_to_underscore([], Acc) ->
- lists:reverse(Acc).
-
-get_ifr_node([], _, _) ->
- %% Were not able to contact any of the given nodes.
- orber:dbg("[~p] cdr_decode:get_ifr_node([]). No Node available.",
- [?LINE], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{minor=(?ORBER_VMCID bor 1), completion_status=?COMPLETED_MAYBE});
-get_ifr_node(Nodes, N, L) ->
- Node = lists:nth(N, Nodes),
- case catch corba:resolve_initial_references_remote("OrberIFR", [Node]) of
- IFR when is_record(IFR, 'IOP_IOR') ->
- IFR;
- _ ->
- %% Not able to commincate with the node. Try next one.
- NewL = L-1,
- get_ifr_node(lists:delete(Node, Nodes), rand:uniform(NewL), NewL)
- end.
-
-
-%%-----------------------------------------------------------------
-%% Func: dec_objref/4
-%%-----------------------------------------------------------------
-dec_objref(Version, Message, Len, ByteOrder) ->
- dec_objref(Version, Message, Len, ByteOrder, [], 0).
-dec_objref(Version, Message, Len, ByteOrder, _Buff, C) ->
- {IOR, Rest, Length} = iop_ior:decode(Version, Message, Len, ByteOrder),
- {IOR, Rest, Length, C+Length-Len}.
-
-%%-----------------------------------------------------------------
-%% Func: dec_system_exception/4 and dec_user_exception/4
-%%-----------------------------------------------------------------
-dec_system_exception(Version, Message, Len, ByteOrder) when Version == {1,2} ->
- {Rest0, Len0, _Counter} = dec_align(Message, Len, 8, Len),
- {TypeId, Rest1, Len1} = dec_type({'tk_string', 0}, Version, Rest0, Len0, ByteOrder),
- Name = orber_exceptions:get_name(TypeId, ?SYSTEM_EXCEPTION),
- {Struct, _Rest2, Len2} =
- dec_exception_1(Version, [{"minor",'tk_ulong'},
- {"completed",
- {'tk_enum', "", "completion_status",
- ["COMPLETED_YES", "COMPLETED_NO",
- "COMPLETED_MAYBE"]}}],
- Rest1, Len1, ByteOrder),
- {list_to_tuple([Name, "" |Struct]), Len2};
-dec_system_exception(Version, Message, Len, ByteOrder) ->
- {TypeId, Rest1, Len1} = dec_type({'tk_string', 0}, Version, Message, Len, ByteOrder),
- Name = orber_exceptions:get_name(TypeId, ?SYSTEM_EXCEPTION),
- {Struct, _Rest2, Len2} =
- dec_exception_1(Version, [{"minor",'tk_ulong'},
- {"completed",
- {'tk_enum', "", "completion_status",
- ["COMPLETED_YES", "COMPLETED_NO",
- "COMPLETED_MAYBE"]}}],
- Rest1, Len1, ByteOrder),
- {list_to_tuple([Name, "" |Struct]), Len2}.
-
-dec_user_exception(Version, Message, Len, ByteOrder) when Version == {1,2} ->
- {Rest0, Len0, _Counter} = dec_align(Message, Len, 8, Len),
- {TypeId, Rest1, Len1} = dec_type({'tk_string', 0}, Version, Rest0, Len0, ByteOrder),
- Name = ifrid_to_name(TypeId, ?IFR_ExceptionDef),
- {'tk_except', _, _, ElementList} = get_user_exception_type(TypeId),
- {Struct, _Rest2, Len2} = dec_exception_1(Version, ElementList, Rest1, Len1,
- ByteOrder),
- {list_to_tuple([Name, TypeId |Struct]), Len2};
-dec_user_exception(Version, Message, Len, ByteOrder) ->
- {TypeId, Rest1, Len1} = dec_type({'tk_string', 0}, Version, Message, Len, ByteOrder),
- Name = ifrid_to_name(TypeId, ?IFR_ExceptionDef),
- {'tk_except', _, _, ElementList} = get_user_exception_type(TypeId),
- {Struct, _Rest2, Len2} = dec_exception_1(Version, ElementList, Rest1, Len1,
- ByteOrder),
- {list_to_tuple([Name, TypeId |Struct]), Len2}.
-
-dec_exception_1(_, [], Message, Len, _ByteOrder) ->
- {[], Message, Len};
-dec_exception_1(Version, [{_ElemName, ElemType} | ElementList], Message,
- Len, ByteOrder) ->
- {Element, Rest, Len1} = dec_type(ElemType, Version, Message, Len, ByteOrder),
- {Struct, Rest1, Len2} = dec_exception_1(Version, ElementList, Rest, Len1,
- ByteOrder),
- {[Element |Struct], Rest1, Len2}.
-
-
-get_user_exception_type(TypeId) ->
- case orber:light_ifr() of
- true ->
- orber_ifr:get_tc(TypeId, ?IFR_ExceptionDef);
- false ->
- case orber:get_lightweight_nodes() of
- false ->
- case mnesia:dirty_index_read(ir_ExceptionDef, TypeId,
- #ir_ExceptionDef.id) of
- [ExcDef] when is_record(ExcDef, ir_ExceptionDef) ->
- ExcDef#ir_ExceptionDef.type;
- Other ->
- orber:dbg("[~p] cdr_decode:get_user_exception_type(~p). IFR Id not found: ~p",
- [?LINE, TypeId, Other], ?DEBUG_LEVEL),
- corba:raise(#'UNKNOWN'{minor=(?CORBA_OMGVMCID bor 1),
- completion_status=?COMPLETED_MAYBE})
- end;
- Nodes ->
- L = length(Nodes),
- IFR = get_ifr_node(Nodes, rand:uniform(L), L),
- 'OrberApp_IFR':get_user_exception_type(IFR, TypeId)
- end
- end.
-
-%%-----------------------------------------------------------------
-%% Func: dec_type_code/4
-%%-----------------------------------------------------------------
-dec_type_code(Version, Message, Len, ByteOrder, Buff, C) ->
- {TypeNo, Message1, Len1, NewC} = dec_type('tk_ulong', Version, Message, Len, ByteOrder, Buff, C),
- TC = dec_type_code(TypeNo, Version, Message1, Len1, ByteOrder, Buff, NewC),
- erase(orber_indirection),
- TC.
-
-%%-----------------------------------------------------------------
-%% Func: dec_type_code/5
-%%-----------------------------------------------------------------
-dec_type_code(0, _, Message, Len, _, _, C) ->
- {'tk_null', Message, Len, C};
-dec_type_code(1, _, Message, Len, _, _, C) ->
- {'tk_void', Message, Len, C};
-dec_type_code(2, _, Message, Len, _, _, C) ->
- {'tk_short', Message, Len, C};
-dec_type_code(3, _, Message, Len, _, _, C) ->
- {'tk_long', Message, Len, C};
-dec_type_code(23, _, Message, Len, _, _, C) ->
- {'tk_longlong', Message, Len, C};
-dec_type_code(25, _, Message, Len, _, _, C) ->
- {'tk_longdouble', Message, Len, C};
-dec_type_code(4, _, Message, Len, _, _, C) ->
- {'tk_ushort', Message, Len, C};
-dec_type_code(5, _, Message, Len, _, _, C) ->
- {'tk_ulong', Message, Len, C};
-dec_type_code(24, _, Message, Len, _, _, C) ->
- {'tk_ulonglong', Message, Len, C};
-dec_type_code(6, _, Message, Len, _, _, C) ->
- {'tk_float', Message, Len, C};
-dec_type_code(7, _, Message, Len, _, _, C) ->
- {'tk_double', Message, Len, C};
-dec_type_code(8, _, Message, Len, _, _, C) ->
- {'tk_boolean', Message, Len, C};
-dec_type_code(9, _, Message, Len, _, _, C) ->
- {'tk_char', Message, Len, C};
-dec_type_code(26, _, Message, Len, _, _, C) ->
- {'tk_wchar', Message, Len, C};
-dec_type_code(10, _, Message, Len, _, _, C) ->
- {'tk_octet', Message, Len, C};
-dec_type_code(11, _, Message, Len, _, _, C) ->
- {'tk_any', Message, Len, C};
-dec_type_code(12, _, Message, Len, _, _, C) ->
- {'tk_TypeCode', Message, Len, C};
-dec_type_code(13, _, Message, Len, _, _, C) ->
- {'tk_Principal', Message, Len, C};
-dec_type_code(14, Version, Message, Len, ByteOrder, Buff, C) ->
- {ComplexParams, Message1, Len1, Ex} = decode_complex_tc_parameters(Version, Message, Len, ByteOrder),
- %% Decode marshalled parameters, eg get the byteorder first
- {ByteOrder1, Rest1} = dec_byte_order(ComplexParams),
- {{RepId, Name}, <<>>, _Len2, NewC} =
- dec_type({'tk_struct', "", "", [{"repository ID", {'tk_string', 0}},
- {"name", {'tk_string', 0}}]},
- Version, Rest1, 1, ByteOrder1, Buff, C+1+Ex),
- {{'tk_objref', RepId, Name}, Message1, Len1, NewC};
-dec_type_code(15, Version, Message, Len, ByteOrder, Buff, C) ->
- {ComplexParams, Message1, Len1, Ex} = decode_complex_tc_parameters(Version, Message, Len, ByteOrder),
- %% Decode marshalled parameters, eg get the byteorder first
- {ByteOrder1, Rest1} = dec_byte_order(ComplexParams),
- {{RepId, Name, ElementList}, <<>>, _Len2, NewC} =
- dec_type({'tk_struct', "", "",
- [{"repository ID", {'tk_string', 0}},
- {"name", {'tk_string', 0}},
- {"element list",
- {'tk_sequence', {'tk_struct', "","",
- [{"member name", {'tk_string', 0}},
- {"member type", 'tk_TypeCode'}]},
- 0}}]},
- Version, Rest1, 1, ByteOrder1, Buff, C+1+Ex),
- {{'tk_struct', RepId, Name, ElementList}, Message1, Len1, NewC};
-dec_type_code(16, Version, Message, Len, ByteOrder, Buff, C) ->
- {ComplexParams, Message1, Len1, Ex} = decode_complex_tc_parameters(Version, Message, Len, ByteOrder),
- %% Decode marshalled parameters, eg get the byteorder first
- {ByteOrder1, Rest1} = dec_byte_order(ComplexParams),
- {{RepId, Name, DiscrTC, Default}, Rest2, RestLen2, NewC} =
- dec_type({'tk_struct', "", "",
- [{"repository ID", {'tk_string', 0}},
- {"name", {'tk_string', 0}},
- {"discriminant type", 'tk_TypeCode'},
- {"default used", 'tk_long'}]},
- Version, Rest1, 1, ByteOrder1, Buff, C+1+Ex),
- {ElementList, <<>>, _RestLen3, NewC2} =
- dec_type({'tk_sequence', {'tk_struct', "","",
- [{"label value", DiscrTC},
- {"member name", {'tk_string', 0}},
- {"member type", 'tk_TypeCode'}]}, 0},
- Version, Rest2, RestLen2, ByteOrder1, Buff, NewC),
- NewElementList =
- case check_enum(DiscrTC) of
- true ->
- lists:map(fun({L,N,T}) -> {atom_to_list(L),N,T} end, ElementList);
- false ->
- ElementList
- end,
- {{'tk_union', RepId, Name, DiscrTC, Default, NewElementList}, Message1, Len1, NewC2};
-dec_type_code(17, Version, Message, Len, ByteOrder, Buff, C) ->
- {ComplexParams, Message1, Len1, Ex} = decode_complex_tc_parameters(Version, Message, Len, ByteOrder),
- %% Decode marshalled parameters, eg get the byteorder first
- {ByteOrder1, Rest1} = dec_byte_order(ComplexParams),
- {{RepId, Name, ElementList}, <<>>, _Len2, NewC} =
- dec_type({'tk_struct', "", "",
- [{"repository ID", {'tk_string', 0}},
- {"name", {'tk_string', 0}},
- {"element list",
- {'tk_sequence', {'tk_string', 0}, 0}}]},
- Version, Rest1, 1, ByteOrder1, Buff, C+1+Ex),
- {{'tk_enum', RepId, Name, ElementList}, Message1, Len1, NewC};
-dec_type_code(18, Version, Message, Len, ByteOrder, Buff, C) ->
- {MaxLength, Message1, Len1, NewC} =
- dec_type('tk_ulong', Version, Message, Len, ByteOrder, Buff, C),
- {{'tk_string', MaxLength}, Message1, Len1, NewC};
-dec_type_code(19, Version, Message, Len, ByteOrder, Buff, C) ->
- {ComplexParams, Message1, Len1, Ex} = decode_complex_tc_parameters(Version, Message, Len, ByteOrder),
- %% Decode marshalled parameters, eg get the byteorder first
- {ByteOrder1, Rest1} = dec_byte_order(ComplexParams),
- {{ElemTC, MaxLength}, <<>>, _Len2, NewC} =
- dec_type({'tk_struct', "", "", [{"element type", 'tk_TypeCode'},
- {"max length", 'tk_ulong'}]},
- Version, Rest1, 1, ByteOrder1, Buff, C+1+Ex),
- {{'tk_sequence', ElemTC, MaxLength}, Message1, Len1, NewC};
-dec_type_code(20, Version, Message, Len, ByteOrder, Buff, C) ->
- {ComplexParams, Message1, Len1, Ex} = decode_complex_tc_parameters(Version, Message, Len, ByteOrder),
- %% Decode marshalled parameters, eg get the byteorder first
- {ByteOrder1, Rest1} = dec_byte_order(ComplexParams),
- {{ElemTC, Length}, <<>>, _Len2, NewC} =
- dec_type({'tk_struct', "", "", [{"element type", 'tk_TypeCode'},
- {"length", 'tk_ulong'}]},
- Version, Rest1, 1, ByteOrder1, Buff, C+1+Ex),
- {{'tk_array', ElemTC, Length}, Message1, Len1, NewC};
-dec_type_code(21, Version, Message, Len, ByteOrder, Buff, C) ->
- {ComplexParams, Message1, Len1, Ex} = decode_complex_tc_parameters(Version, Message, Len, ByteOrder),
- %% Decode marshalled parameters, eg ge a byteorder first
- {ByteOrder1, Rest1} = dec_byte_order(ComplexParams),
- {{RepId, Name, TC}, <<>>, _Len2, NewC} =
- dec_type({'tk_struct', "", "", [{"repository ID", {'tk_string', 0}},
- {"name", {'tk_string', 0}},
- {"TypeCode", 'tk_TypeCode'}]},
- Version, Rest1, 1, ByteOrder1, Buff, C+1+Ex),
- {{'tk_alias', RepId, Name, TC}, Message1, Len1, NewC};
-dec_type_code(22, Version, Message, Len, ByteOrder, Buff, C) ->
- {ComplexParams, Message1, Len1, Ex} = decode_complex_tc_parameters(Version, Message, Len, ByteOrder),
- %% Decode marshalled parameters, eg get the byteorder first
- {ByteOrder1, Rest1} = dec_byte_order(ComplexParams),
- {{RepId, Name, ElementList}, <<>>, _Len2, NewC} =
- dec_type({'tk_struct', "", "",
- [{"repository ID", {'tk_string', 0}},
- {"name", {'tk_string', 0}},
- {"element list",
- {'tk_sequence', {'tk_struct', "","",
- [{"member name", {'tk_string', 0}},
- {"member type", 'tk_TypeCode'}]},
- 0}}]},
- Version, Rest1, 1, ByteOrder1, Buff, C+1+Ex),
- {{'tk_except', RepId, Name, ElementList}, Message1, Len1, NewC};
-dec_type_code(27, Version, Message, Len, ByteOrder, Buff, C) ->
- {MaxLength, Message1, Len1, NewC} =
- dec_type('tk_ulong', Version, Message, Len, ByteOrder, Buff, C),
- {{'tk_wstring', MaxLength}, Message1, Len1, NewC};
-dec_type_code(28, Version, Message, Len, ByteOrder, Buff, C) ->
- {Digits, Message1, Len1, C1} =
- dec_type('tk_ushort', Version, Message, Len, ByteOrder, Buff, C),
- {Scale, Message2, Len2, C2} =
- dec_type('tk_short', Version, Message1, Len1, ByteOrder, Buff, C1),
- {{'tk_fixed', Digits, Scale}, Message2, Len2, C2};
-dec_type_code(29, Version, Message, Len, ByteOrder, Buff, C) ->
- {ComplexParams, Message1, Len1, Ex} = decode_complex_tc_parameters(Version, Message, Len, ByteOrder),
- {ByteOrder1, Rest1} = dec_byte_order(ComplexParams),
- {{RepId, Name, ValueModifier, TC, ElementList}, <<>>, _Len2, NewC} =
- dec_type({'tk_struct', "", "", [{"repository ID", {'tk_string', 0}},
- {"name", {'tk_string', 0}},
- {"ValueModifier", 'tk_short'},
- {"TypeCode", 'tk_TypeCode'},
- {"element list",
- {'tk_sequence',
- {'tk_struct', "","",
- [{"member name", {'tk_string', 0}},
- {"member type", 'tk_TypeCode'},
- {"Visibility", 'tk_short'}]},
- 0}}]},
- Version, Rest1, 1, ByteOrder1, Buff, C+1+Ex),
- {{'tk_value', RepId, Name, ValueModifier, TC, ElementList}, Message1, Len1, NewC};
-dec_type_code(30, Version, Message, Len, ByteOrder, Buff, C) ->
- {ComplexParams, Message1, Len1, Ex} = decode_complex_tc_parameters(Version, Message, Len, ByteOrder),
- {ByteOrder1, Rest1} = dec_byte_order(ComplexParams),
- {{RepId, Name, TC}, <<>>, _Len2, NewC} =
- dec_type({'tk_struct', "", "", [{"repository ID", {'tk_string', 0}},
- {"name", {'tk_string', 0}},
- {"TypeCode", 'tk_TypeCode'}]},
- Version, Rest1, 1, ByteOrder1, Buff, C+1+Ex),
- {{'tk_value_box', RepId, Name, TC}, Message1, Len1, NewC};
-dec_type_code(31, Version, Message, Len, ByteOrder, Buff, C) ->
- {ComplexParams, Message1, Len1, Ex} = decode_complex_tc_parameters(Version, Message, Len, ByteOrder),
- {ByteOrder1, Rest1} = dec_byte_order(ComplexParams),
- {{RepId, Name}, <<>>, _Len2, NewC} =
- dec_type({'tk_struct', "", "", [{"repository ID", {'tk_string', 0}},
- {"name", {'tk_string', 0}}]},
- Version, Rest1, 1, ByteOrder1, Buff, C+1+Ex),
- {{'tk_native', RepId, Name}, Message1, Len1, NewC};
-dec_type_code(32, Version, Message, Len, ByteOrder, Buff, C) ->
- {ComplexParams, Message1, Len1, Ex} = decode_complex_tc_parameters(Version, Message, Len, ByteOrder),
- {ByteOrder1, Rest1} = dec_byte_order(ComplexParams),
- {{RepId, Name}, <<>>, _Len2, NewC} =
- dec_type({'tk_struct', "", "", [{"RepositoryId", {'tk_string', 0}},
- {"name", {'tk_string', 0}}]},
- Version, Rest1, 1, ByteOrder1, Buff, C+1+Ex),
- {{'tk_abstract_interface', RepId, Name}, Message1, Len1, NewC};
-dec_type_code(33, Version, Message, Len, ByteOrder, Buff, C) ->
- {ComplexParams, Message1, Len1, Ex} = decode_complex_tc_parameters(Version, Message, Len, ByteOrder),
- {ByteOrder1, Rest1} = dec_byte_order(ComplexParams),
- {{RepId, Name}, <<>>, _Len2, NewC} =
- dec_type({'tk_struct', "", "", [{"RepositoryId", {'tk_string', 0}},
- {"name", {'tk_string', 0}}]},
- Version, Rest1, 1, ByteOrder1, Buff, C+1+Ex),
- {{'tk_local_interface', RepId, Name}, Message1, Len1, NewC};
-dec_type_code(16#ffffffff, Version, Message, Len, ByteOrder, Buff, C) ->
- {Indirection, Message1, Len1, NewC} =
- dec_type('tk_long', Version, Message, Len, ByteOrder, Buff, C),
- Position = C+Indirection,
- case put(orber_indirection, Position) of
- Position ->
-%% {{'none', Indirection}, Message1, Len1, NewC};
- %% Recursive TypeCode. Break the loop.
- orber:dbg("[~p] cdr_decode:dec_type_code(~p); Recursive TC not supported.",
- [?LINE,Position], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_NO});
- _ ->
- <<_:Position/binary, SubBuff/binary>> = Buff,
- {TC, _, _, _} = dec_type_code(Version, SubBuff, Position, ByteOrder, Buff, Position),
- {TC, Message1, Len1, NewC}
- end;
-dec_type_code(Type, _, _, _, _, _, _) ->
- orber:dbg("[~p] cdr_decode:dec_type_code(~p); No match.",
- [?LINE, Type], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 8), completion_status=?COMPLETED_MAYBE}).
-
-check_enum({'tk_enum', _, _, _}) ->
- true;
-check_enum(_) ->
- false.
-
-
-decode_complex_tc_parameters(_Version, Message, Len, ByteOrder) ->
- {Rest, Len1, NewC} = dec_align(Message, Len, 4, 0),
- {Size, Rest1} = cdrlib:dec_unsigned_long(ByteOrder, Rest),
- <<OctetSeq:Size/binary, Rest2/binary>> = Rest1,
- {OctetSeq, Rest2, Len1+4+Size, NewC+4}.
-
-%%-----------------------------------------------------------------
-%% Func: dec_align/3
-%% Args:
-%% R - The byte sequence that shall be aligned.
-%% Len - The number of bytes read so far.
-%% Alignment - The alignment as an integer (for example: 2,4,8).
-%% Returns:
-%% An aligned byte sequence.
-%%-----------------------------------------------------------------
-dec_align(R, Len, Alignment, C) ->
- Rem = Len rem Alignment,
- if Rem == 0 ->
- {R, Len, C};
- true ->
- Diff = Alignment - Rem,
- <<_:Diff/binary,Rest/binary>> = R,
- {Rest, Len + Diff, C + Diff}
- end.
-
-%%---------------- EOF MODULE ----------------------------------------
diff --git a/lib/orber/src/cdr_encode.erl b/lib/orber/src/cdr_encode.erl
deleted file mode 100644
index 2c42d5bd7e..0000000000
--- a/lib/orber/src/cdr_encode.erl
+++ /dev/null
@@ -1,1172 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: cdr_encode.erl
-%%
-%% Description:
-%% This file contains all encoding functions for the CDR
-%% format.
-%%
-%%-----------------------------------------------------------------
--module(cdr_encode).
-
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([enc_giop_msg_type/1,
- enc_request/1, enc_request_split/1,
- enc_reply/1, enc_reply_split/1,
- enc_type/3, enc_type/5,
- enc_cancel_request/1,
- enc_locate_request/1,
- enc_locate_reply/1,
- enc_close_connection/1,
- enc_message_error/1,
- enc_fragment/1,
- enc_giop_message_header/5,
- validate_request_body/1,
- validate_reply_body/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-%%-----------------------------------------------------------------
-%% Macros
-%%-----------------------------------------------------------------
--define(DEBUG_LEVEL, 9).
-
--define(ODD(N), (N rem 2) == 1).
-
-%%-----------------------------------------------------------------
-%% External functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: enc_giop_message_header/5
-%%-----------------------------------------------------------------
-%% The header size is known so we know that the size will be aligned.
-%% MessSize already includes the header length.
-%%-----------------------------------------------------------------
-enc_giop_message_header(#giop_env{version = {Major,Minor}}, MessType,
- _Flags, MessSize, Message) ->
- Type = enc_giop_msg_type(MessType),
- %% The Flag handling must be fixed, i.e., it's not correct to only use '0'.
- %% If IIOP-1.0 a boolean (FALSE == 0), otherwise, IIOP-1.1 or 1.2,
- %% an octet. The octet bits represents:
- %% * The least significant the byteorder (0 eq. big-endian)
- %% * The second least significant indicates if the message is fragmented.
- %% If set to 0 it's not fragmented.
- %% * The most significant 6 bits are reserved. Hence, must be set to 0.
- %% Since we currently don't support fragmented messages and we always
- %% encode using big-endian it's ok to use '0' for now.
- list_to_binary([ <<"GIOP",Major:8,Minor:8,0:8,
- Type:8,MessSize:32/big-unsigned-integer>> | Message]).
-
-enc_byte_order(Env, Message) ->
- enc_type('tk_boolean', Env, 'false', Message, 0).
-
-%%-----------------------------------------------------------------
-%% Func: enc_parameters/2
-%%-----------------------------------------------------------------
-enc_parameters(_, [], [], Message, Len) ->
- {Message, Len};
-enc_parameters(_, [], P, _, _) ->
- orber:dbg("[~p] cdr_encode:encode_parameters(~p); to many parameters.",
- [?LINE, P], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 17), completion_status=?COMPLETED_MAYBE});
-enc_parameters(_, _, [], TC, _) ->
- orber:dbg("[~p] cdr_encode:encode_parameters(~p); to few parameters.",
- [?LINE, TC], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 17), completion_status=?COMPLETED_MAYBE});
-enc_parameters(Env, [PT1 |TypeList], [ P1 | Parameters], Message, Len) ->
- {Message1, Len1} = enc_type(PT1, Env, P1, Message, Len),
- enc_parameters(Env, TypeList, Parameters, Message1, Len1).
-
-%%-----------------------------------------------------------------
-%% Func: enc_request/8
-%%-----------------------------------------------------------------
-%% ## NEW IIOP 1.2 ##
-enc_request(#giop_env{version = {1,2}} = Env) ->
- Flags = 1, %% LTH Not correct, just placeholder
- {Message, Len} = enc_request_id(Env, [], ?GIOP_HEADER_SIZE),
- {Message1, Len1} = enc_response_flags(Env, Message, Len),
- {Message2, Len2} = enc_reserved(Env, {0,0,0}, Message1, Len1),
- {Message3, Len3} = enc_target_address(Env, Message2, Len2),
- {Message4, Len4} = enc_operation(Env, Message3, Len3),
- {Message5, Len5} = enc_service_context(Env, Message4, Len4),
- {Message6, Len6} = enc_request_body(Env, Message5, Len5),
- enc_giop_message_header(Env, 'request', Flags, Len6 - ?GIOP_HEADER_SIZE,
- lists:reverse(Message6));
-enc_request(#giop_env{version = Version} = Env) ->
- Flags = 1, %% LTH Not correct, just placeholder
- {Message0, Len0} = enc_service_context(Env, [], ?GIOP_HEADER_SIZE),
- {Message, Len} = enc_request_id(Env, Message0, Len0),
- {Message1, Len1} = enc_response(Env, Message, Len),
- {Message1b, Len1b} =
- if
- Version /= {1,0} ->
- enc_reserved(Env, {0,0,0}, Message1, Len1);
- true ->
- {Message1, Len1}
- end,
- {Message2, Len2} = enc_object_key(Env, Message1b, Len1b),
- {Message3, Len3} = enc_operation(Env, Message2, Len2),
- {Message4, Len4} = enc_principal(Env, Message3, Len3),
- {Message5, Len5} = enc_request_body(Env, Message4, Len4),
- enc_giop_message_header(Env, 'request', Flags, Len5 - ?GIOP_HEADER_SIZE,
- lists:reverse(Message5)).
-
-%% ## NEW IIOP 1.2 ##
-enc_request_split(#giop_env{version = {1,2}} = Env) ->
- Flags = 1, %% LTH Not correct, just placeholder
- {Message, Len} = enc_request_id(Env, [], ?GIOP_HEADER_SIZE),
- {Message1, Len1} = enc_response_flags(Env, Message, Len),
- {Message2, Len2} = enc_reserved(Env, {0,0,0}, Message1, Len1),
- {Message3, Len3} = enc_target_address(Env, Message2, Len2),
- {Message4, Len4} = enc_operation(Env, Message3, Len3),
- {Message5, Len5} = enc_service_context(Env, Message4, Len4),
- {Body, Len6} = enc_request_body(Env, [], Len5),
- {lists:reverse(Message5), list_to_binary(lists:reverse(Body)),
- Len5 - ?GIOP_HEADER_SIZE, Len6-Len5, Flags};
-enc_request_split(#giop_env{version = Version} = Env) ->
- Flags = 1, %% LTH Not correct, just placeholder
- {Message0, Len0} = enc_service_context(Env, [], ?GIOP_HEADER_SIZE),
- {Message, Len} = enc_request_id(Env, Message0, Len0),
- {Message1, Len1} = enc_response(Env, Message, Len),
- {Message1b, Len1b} =
- if
- Version /= {1,0} ->
- enc_reserved(Env, {0,0,0}, Message1, Len1);
- true ->
- {Message1, Len1}
- end,
- {Message2, Len2} = enc_object_key(Env, Message1b, Len1b),
- {Message3, Len3} = enc_operation(Env, Message2, Len2),
- {Message4, Len4} = enc_principal(Env, Message3, Len3),
- {Body, Len5} = enc_request_body(Env, [], Len4),
- {lists:reverse(Message4), list_to_binary(lists:reverse(Body)),
- Len4 - ?GIOP_HEADER_SIZE, Len5-Len4, Flags}.
-
-enc_principal(Env, Mess, Len) ->
- enc_type({'tk_string', 0}, Env, atom_to_list(node()), Mess, Len).
-
-enc_operation(Env, Mess, Len) ->
- enc_type({'tk_string', 0}, Env, atom_to_list(Env#giop_env.op), Mess, Len).
-
-enc_object_key(Env, Mess, Len) ->
- enc_type({'tk_sequence', 'tk_octet', 0}, Env, Env#giop_env.objkey, Mess, Len).
-
-enc_reserved(Env, Reserved, Mess, Len) ->
- enc_type({'tk_array', 'tk_octet', 3}, Env, Reserved, Mess, Len).
-
-enc_response(Env, Mess, Len) ->
- enc_type('tk_boolean', Env, Env#giop_env.response_expected, Mess, Len).
-
-enc_request_id(Env, Mess, Len) ->
- enc_type('tk_ulong', Env, Env#giop_env.request_id, Mess, Len).
-
-enc_service_context(Env, Message, Len) ->
- Ctxs = enc_used_contexts(Env, Env#giop_env.ctx, []),
- enc_type(?IOP_SERVICECONTEXT, Env, Ctxs, Message, Len).
-
-enc_used_contexts(_Env, [], Message) ->
- Message;
-enc_used_contexts(#giop_env{version = {1, 0}} = Env,
- [#'IOP_ServiceContext'{context_id=?IOP_CodeSets}|T], Ctxs) ->
- %% Not supported by 1.0, drop it.
- enc_used_contexts(Env, T, Ctxs);
-enc_used_contexts(Env, [#'IOP_ServiceContext'{context_id=?IOP_CodeSets,
- context_data = CodeSetCtx}|T],
- Ctxs) ->
- %% Encode ByteOrder
- {Bytes0, Len0} = cdr_encode:enc_type('tk_octet', Env, 0, [], 0),
- {Bytes1, _Len1} = enc_type(?CONV_FRAME_CODESETCONTEXT, Env, CodeSetCtx,
- Bytes0, Len0),
- Bytes = list_to_binary(lists:reverse(Bytes1)),
- enc_used_contexts(Env, T,
- [#'IOP_ServiceContext'{context_id=?IOP_CodeSets,
- context_data = Bytes}|Ctxs]);
-enc_used_contexts(Env, [#'IOP_ServiceContext'{context_id=?IOP_BI_DIR_IIOP,
- context_data = BiDirCtx}|T],
- Ctxs) ->
- %% Encode ByteOrder
- {Bytes0, Len0} = cdr_encode:enc_type('tk_octet', Env, 0, [], 0),
- {Bytes1, _Len1} = enc_type(?IIOP_BIDIRIIOPSERVICECONTEXT, Env, BiDirCtx,
- Bytes0, Len0),
- Bytes = list_to_binary(lists:reverse(Bytes1)),
- enc_used_contexts(Env, T,
- [#'IOP_ServiceContext'{context_id=?IOP_BI_DIR_IIOP,
- context_data = Bytes}|Ctxs]);
-enc_used_contexts(Env, [#'IOP_ServiceContext'{context_id=?IOP_FT_REQUEST,
- context_data = Ctx}|T],
- Ctxs) ->
- %% Encode ByteOrder
- {Bytes0, Len0} = cdr_encode:enc_type('tk_octet', Env, 0, [], 0),
- {Bytes1, _Len1} = enc_type(?FT_FTRequestServiceContext, Env, Ctx,
- Bytes0, Len0),
- Bytes = list_to_binary(lists:reverse(Bytes1)),
- enc_used_contexts(Env, T,
- [#'IOP_ServiceContext'{context_id=?IOP_FT_REQUEST,
- context_data = Bytes}|Ctxs]);
-enc_used_contexts(Env, [#'IOP_ServiceContext'{context_id=?IOP_FT_GROUP_VERSION,
- context_data = Ctx}|T],
- Ctxs) ->
- %% Encode ByteOrder
- {Bytes0, Len0} = cdr_encode:enc_type('tk_octet', Env, 0, [], 0),
- {Bytes1, _Len1} = enc_type(?FT_FTGroupVersionServiceContext, Env, Ctx,
- Bytes0, Len0),
- Bytes = list_to_binary(lists:reverse(Bytes1)),
- enc_used_contexts(Env, T,
- [#'IOP_ServiceContext'{context_id=?IOP_FT_GROUP_VERSION,
- context_data = Bytes}|Ctxs]);
-enc_used_contexts(Env, [#'IOP_ServiceContext'{context_id=?IOP_SecurityAttributeService,
- context_data = Ctx}|T],
- Ctxs) ->
- %% Encode ByteOrder
- {Bytes0, Len0} = cdr_encode:enc_type('tk_octet', Env, 0, [], 0),
- {Bytes1, _Len1} = enc_type(?CSI_SASContextBody, Env, Ctx,
- Bytes0, Len0),
- Bytes = list_to_binary(lists:reverse(Bytes1)),
- enc_used_contexts(Env, T,
- [#'IOP_ServiceContext'{context_id=?IOP_SecurityAttributeService,
- context_data = Bytes}|Ctxs]);
-enc_used_contexts(Env, [#'IOP_ServiceContext'{context_id=?ORBER_GENERIC_CTX_ID,
- context_data = {interface, _I}}|T],
- Ctxs) ->
- %% This shall not be forwarded.
- enc_used_contexts(Env, T, Ctxs);
-enc_used_contexts(Env, [#'IOP_ServiceContext'{context_id=?ORBER_GENERIC_CTX_ID,
- context_data = {configuration, _O}}|T],
- Ctxs) ->
- %% This shall not be forwarded.
- enc_used_contexts(Env, T, Ctxs);
-enc_used_contexts(Env, [#'IOP_ServiceContext'{context_id=?ORBER_GENERIC_CTX_ID,
- context_data = Ctx}|T],
- Ctxs) ->
- %% Encode ByteOrder
- {Bytes0, Len0} = cdr_encode:enc_type('tk_octet', Env, 0, [], 0),
- {Bytes1, _Len1} = enc_type(?ORBER_GENERIC_CTX, Env,
- binary_to_list(term_to_binary(Ctx)),
- Bytes0, Len0),
- Bytes = list_to_binary(lists:reverse(Bytes1)),
- enc_used_contexts(Env, T,
- [#'IOP_ServiceContext'{context_id=?ORBER_GENERIC_CTX_ID,
- context_data = Bytes}|Ctxs]);
-enc_used_contexts(Env, [H|T], Ctxs) ->
- enc_used_contexts(Env, T, [H|Ctxs]).
-
-%% ## NEW IIOP 1.2 ##
-enc_target_address(#giop_env{objkey = TargetAddr} = Env, Mess, Len)
- when is_record(TargetAddr, 'GIOP_TargetAddress') ->
- enc_type(?TARGETADDRESS, Env, TargetAddr, Mess, Len);
-enc_target_address(#giop_env{objkey = IORInfo} = Env, Mess, Len)
- when is_record(IORInfo, 'GIOP_IORAddressingInfo') ->
- enc_type(?TARGETADDRESS, Env, #'GIOP_TargetAddress'{label = ?GIOP_ReferenceAddr,
- value = IORInfo},
- Mess, Len);
-enc_target_address(#giop_env{objkey = TP} = Env, Mess, Len)
- when is_record(TP, 'IOP_TaggedProfile') ->
- enc_type(?TARGETADDRESS, Env, #'GIOP_TargetAddress'{label = ?GIOP_ProfileAddr,
- value = TP},
- Mess, Len);
-enc_target_address(#giop_env{objkey = ObjKey} = Env, Mess, Len) ->
- enc_type(?TARGETADDRESS, Env, #'GIOP_TargetAddress'{label = ?GIOP_KeyAddr,
- value = ObjKey},
- Mess, Len).
-
-%% FIX ME!! This is temporary, not proper flag handling.
-enc_response_flags(#giop_env{response_expected = true} = Env, Mess, Len) ->
- enc_type('tk_octet', Env, 3, Mess, Len);
-enc_response_flags(#giop_env{response_expected = false} = Env, Mess, Len) ->
- enc_type('tk_octet', Env, 0, Mess, Len).
-
-%%-----------------------------------------------------------------
-%% Func: enc_request_body/5
-%%-----------------------------------------------------------------
-enc_request_body(#giop_env{tc = {_, [], _}}, Message, Len) ->
- %% This case is used to avoid adding alignment even though no body will be added.
- {Message, Len};
-enc_request_body(#giop_env{version = {1,2},
- tc = {_RetType, InParameters, _OutParameters},
- parameters = Parameters} = Env,
- Message, Len) ->
- {Message1, Len1} = enc_align(Message, Len, 8),
- enc_parameters(Env, InParameters, Parameters, Message1, Len1);
-enc_request_body(#giop_env{tc = {_RetType, InParameters, _OutParameters},
- parameters = Parameters} = Env,
- Message, Len) ->
- enc_parameters(Env, InParameters, Parameters, Message, Len).
-
-%%-----------------------------------------------------------------
-%% Func: validate_request_body/1
-%%-----------------------------------------------------------------
-validate_request_body(#giop_env{tc = {_RetType, InParameters, _OutParameters},
- parameters = Parameters} = Env) ->
- enc_parameters(Env, InParameters, Parameters, [], 0).
-
-%%-----------------------------------------------------------------
-%% Func: enc_reply/6
-%%-----------------------------------------------------------------
-%% ## NEW IIOP 1.2 ##
-enc_reply(#giop_env{version = {1,2}} = Env) ->
- Flags = 1, %% LTH Not correct, just placeholder
- {Message, Len} = enc_request_id(Env, [], ?GIOP_HEADER_SIZE),
- {Message1, Len1} = enc_reply_status(Env, Message, Len),
- {Message2, Len2} = enc_service_context(Env, Message1, Len1),
- {Message3, Len3} = enc_reply_body(Env, Message2, Len2),
- enc_giop_message_header(Env, 'reply', Flags, Len3 - ?GIOP_HEADER_SIZE,
- lists:reverse(Message3));
-enc_reply(Env) ->
- Flags = 1, %% LTH Not correct, just placeholder
- {Message, Len} = enc_service_context(Env, [], ?GIOP_HEADER_SIZE),
- {Message1, Len1} = enc_request_id(Env, Message, Len),
- {Message2, Len2} = enc_reply_status(Env, Message1, Len1),
- {Message3, Len3} = enc_reply_body(Env, Message2, Len2),
- enc_giop_message_header(Env, 'reply', Flags, Len3 - ?GIOP_HEADER_SIZE,
- lists:reverse(Message3)).
-
-%% ## NEW IIOP 1.2 ##
-enc_reply_split(#giop_env{version = {1,2}} = Env) ->
- Flags = 1, %% LTH Not correct, just placeholder
- {Message, Len0} = enc_request_id(Env, [], ?GIOP_HEADER_SIZE),
- {Message1, Len1} = enc_reply_status(Env, Message, Len0),
- {Message2, Len2} = enc_service_context(Env, Message1, Len1),
- {Body, Len} = enc_reply_body(Env, [], Len2),
- {lists:reverse(Message2), list_to_binary(lists:reverse(Body)),
- Len2 - ?GIOP_HEADER_SIZE, Len-Len2, Flags};
-enc_reply_split(Env) ->
- Flags = 1, %% LTH Not correct, just placeholder
- {Message, Len0} = enc_service_context(Env, [], ?GIOP_HEADER_SIZE),
- {Message1, Len1} = enc_request_id(Env, Message, Len0),
- {Message2, Len2} = enc_reply_status(Env, Message1, Len1),
- {Body, Len} = enc_reply_body(Env, [], Len2),
- {lists:reverse(Message2), list_to_binary(lists:reverse(Body)),
- Len2 - ?GIOP_HEADER_SIZE, Len-Len2, Flags}.
-
-enc_reply_status(Env, Mess, Len) ->
- L = enc_giop_reply_status_type(Env#giop_env.reply_status),
- enc_type('tk_ulong', Env, L, Mess, Len).
-
-%%-----------------------------------------------------------------
-%% Func: enc_reply_body/6
-%%-----------------------------------------------------------------
-enc_reply_body(#giop_env{tc = {'tk_void', _, []}, result = ok,
- parameters = []}, Message, Len) ->
- %% This case is mainly to be able to avoid adding alignment for
- %% IIOP-1.2 messages if the body should be empty, i.e., void return value and
- %% no out parameters.
- {Message, Len};
-enc_reply_body(#giop_env{version = {1,2},
- tc = {RetType, _InParameters, OutParameters},
- parameters = Parameters, result = Result} = Env,
- Message, Len) ->
- {Message1, Len1} = enc_align(Message, Len, 8),
- {Message2, Len2} = enc_type(RetType, Env, Result, Message1, Len1),
- enc_parameters(Env, OutParameters, Parameters, Message2, Len2);
-enc_reply_body(#giop_env{tc = {RetType, _InParameters, OutParameters},
- parameters = Parameters, result = Result} = Env,
- Message, Len) ->
- {Message1, Len1} = enc_type(RetType, Env, Result, Message, Len),
- enc_parameters(Env, OutParameters, Parameters, Message1, Len1).
-
-
-%%-----------------------------------------------------------------
-%% Func: validate_reply_body/3
-%%-----------------------------------------------------------------
-validate_reply_body(Env, {'EXCEPTION', Exception}) ->
- {TypeOfException, ExceptionTypeCode, NewExc} =
- orber_exceptions:get_def(Exception),
- {'tk_except', TypeOfException, ExceptionTypeCode,
- (catch enc_reply_body(Env#giop_env{tc = {ExceptionTypeCode, [], []},
- result = NewExc, parameters = []}, [], 0))};
-validate_reply_body(#giop_env{tc = {_RetType, _InParameters, []}} = Env, Reply) ->
- enc_reply_body(Env#giop_env{result = Reply}, [], 0);
-validate_reply_body(Env, Reply) when is_tuple(Reply) ->
- [Result|Parameters] = tuple_to_list(Reply),
- enc_reply_body(Env#giop_env{result = Result, parameters = Parameters}, [], 0);
-validate_reply_body(Env, Reply) ->
- enc_reply_body(Env#giop_env{result = Reply}, [], 0).
-
-%%-----------------------------------------------------------------
-%% Func: enc_cancel_request/2
-%%-----------------------------------------------------------------
-enc_cancel_request(Env) ->
- Flags = 1, %% LTH Not correct, just placeholder
- {Message, Len} = enc_request_id(Env, [], ?GIOP_HEADER_SIZE),
- enc_giop_message_header(Env, 'cancel_request', Flags, Len - ?GIOP_HEADER_SIZE,
- lists:reverse(Message)).
-
-%%-----------------------------------------------------------------
-%% Func: enc_locate_request/3
-%%-----------------------------------------------------------------
-%% ## NEW IIOP 1.2 ##
-enc_locate_request(#giop_env{version = {1,2}} = Env) ->
- Flags = 1, %% LTH Not correct, just placeholder
- {Message, Len} = enc_request_id(Env, [], ?GIOP_HEADER_SIZE),
- {Message1, Len1} = enc_target_address(Env, Message, Len),
- enc_giop_message_header(Env, 'locate_request', Flags, Len1-?GIOP_HEADER_SIZE,
- lists:reverse(Message1));
-enc_locate_request(Env) ->
- Flags = 1, %% LTH Not correct, just placeholder
- {Message, Len} = enc_request_id(Env, [], ?GIOP_HEADER_SIZE),
- {Message1, Len1} = enc_object_key(Env, Message, Len),
- enc_giop_message_header(Env, 'locate_request', Flags, Len1-?GIOP_HEADER_SIZE,
- lists:reverse(Message1)).
-
-%%-----------------------------------------------------------------
-%% Func: enc_locate_reply
-%%-----------------------------------------------------------------
-%% No forward etc. Just encode the status.
-enc_locate_reply(#giop_env{tc = undefined} = Env) ->
- Flags = 1, %% LTH Not correct, just placeholder
- {Message, Len} = enc_request_id(Env, [], ?GIOP_HEADER_SIZE),
- {Message1, Len1} = enc_locate_status(Env, Message, Len),
- enc_giop_message_header(Env, 'locate_reply', Flags, Len1 - ?GIOP_HEADER_SIZE,
- lists:reverse(Message1));
-enc_locate_reply(Env) ->
- Flags = 1, %% LTH Not correct, just placeholder
- {Message, Len} = enc_request_id(Env, [], ?GIOP_HEADER_SIZE),
- {Message1, Len1} = enc_locate_status(Env, Message, Len),
- {Message2, Len2} = enc_locate_reply_body(Env, Message1, Len1),
- enc_giop_message_header(Env, 'locate_reply', Flags, Len2 - ?GIOP_HEADER_SIZE,
- lists:reverse(Message2)).
-
-enc_locate_reply_body(#giop_env{tc = TC, result = Data} = Env, Message, Len) ->
- %% In CORBA-2.3.1 the LocateReply body didn't align the body (8-octet
- %% boundry) for IIOP-1.2. This have been changed in later specs.
- %% Un-comment the line below when we want to be CORBA-2.4 compliant.
- %% But in CORB-2.6 this was changed once again (i.e. no alignment).
- %% The best solution is to keep it as is.
- enc_type(TC, Env, Data, Message, Len).
-
-enc_locate_status(Env, Mess, Len) ->
- L = enc_giop_locate_status_type(Env#giop_env.reply_status),
- enc_type('tk_ulong', Env, L, Mess, Len).
-%%-----------------------------------------------------------------
-%% Func: enc_close_connection/1
-%%-----------------------------------------------------------------
-enc_close_connection(Env) ->
- Flags = 1, %% LTH Not correct, just placeholder
- enc_giop_message_header(Env, 'close_connection', Flags, 0, []).
-
-%%-----------------------------------------------------------------
-%% Func: enc_message_error/1
-%%-----------------------------------------------------------------
-enc_message_error(Env) ->
- Flags = 1, %% LTH Not correct, just placeholder
- enc_giop_message_header(Env, 'message_error', Flags, 0, []).
-
-%%-----------------------------------------------------------------
-%% Func: enc_fragment/1
-%%-----------------------------------------------------------------
-enc_fragment(Env) ->
- Flags = 1, %% LTH Not correct, just placeholder
- enc_giop_message_header(Env, 'fragment', Flags, 0, []).
-
-%%-----------------------------------------------------------------
-%% Func: enc_giop_msg_type
-%% Args: An integer message type code
-%% Returns: An atom which is the message type code name
-%%-----------------------------------------------------------------
-enc_giop_msg_type('request') ->
- 0;
-enc_giop_msg_type('reply') ->
- 1;
-enc_giop_msg_type('cancel_request') ->
- 2;
-enc_giop_msg_type('locate_request') ->
- 3;
-enc_giop_msg_type('locate_reply') ->
- 4;
-enc_giop_msg_type('close_connection') ->
- 5;
-enc_giop_msg_type('message_error') ->
- 6;
-enc_giop_msg_type('fragment') ->
- 7.
-
-
-%%-----------------------------------------------------------------
-%% Func: enc_giop_reply_status_type
-%% Args: An atom which is the reply status
-%% Returns: An integer status code
-%%-----------------------------------------------------------------
-enc_giop_reply_status_type(?NO_EXCEPTION) ->
- 0;
-enc_giop_reply_status_type(?USER_EXCEPTION) ->
- 1;
-enc_giop_reply_status_type(?SYSTEM_EXCEPTION) ->
- 2;
-enc_giop_reply_status_type('location_forward') ->
- 3;
-%% ## NEW IIOP 1.2 ##
-enc_giop_reply_status_type('location_forward_perm') ->
- 4;
-enc_giop_reply_status_type('needs_addressing_mode') ->
- 5.
-
-%%-----------------------------------------------------------------
-%% Func: enc_giop_locate_status_type
-%% Args: An integer status code
-%% Returns: An atom which is the reply status
-%%-----------------------------------------------------------------
-enc_giop_locate_status_type('unknown_object') ->
- 0;
-enc_giop_locate_status_type('object_here') ->
- 1;
-enc_giop_locate_status_type('object_forward') ->
- 2;
-%% ## NEW IIOP 1.2 ##
-enc_giop_locate_status_type('object_forward_perm') ->
- 3;
-enc_giop_locate_status_type('loc_system_exception') ->
- 4;
-enc_giop_locate_status_type('loc_needs_addressing_mode') ->
- 5.
-
-%%-----------------------------------------------------------------
-%% Func: enc_type/3
-%%-----------------------------------------------------------------
-enc_type(Env, TypeCode, Value) ->
- {Bytes, _Len} = enc_type(TypeCode, Env, Value, [], 0),
- list_to_binary(lists:reverse(Bytes)).
-
-%%-----------------------------------------------------------------
-%% Func: enc_type/5
-%%-----------------------------------------------------------------
-enc_type('tk_null', _Env, null, Bytes, Len) ->
- {Bytes, Len};
-enc_type('tk_void', _Env, ok, Bytes, Len) ->
- {Bytes, Len};
-enc_type('tk_short', _Env, Value, Bytes, Len) ->
- {Rest, Len1} = enc_align(Bytes, Len, 2),
- {cdrlib:enc_short(Value, Rest), Len1 + 2};
-enc_type('tk_long', _Env, Value, Bytes, Len) ->
- {Rest, Len1} = enc_align(Bytes, Len, 4),
- {cdrlib:enc_long(Value, Rest ), Len1 + 4};
-enc_type('tk_longlong', _Env, Value, Bytes, Len) ->
- {Rest, Len1} = enc_align(Bytes, Len, 8),
- {cdrlib:enc_longlong(Value, Rest ), Len1 + 8};
-enc_type('tk_ushort', _Env, Value, Bytes, Len) ->
- {Rest, Len1} = enc_align(Bytes, Len, 2),
- {cdrlib:enc_unsigned_short(Value, Rest), Len1 + 2};
-enc_type('tk_ulong', _Env, Value, Bytes, Len) ->
- {Rest, Len1} = enc_align(Bytes, Len, 4),
- {cdrlib:enc_unsigned_long(Value, Rest), Len1 + 4};
-enc_type('tk_ulonglong', _Env, Value, Bytes, Len) ->
- {Rest, Len1} = enc_align(Bytes, Len, 8),
- {cdrlib:enc_unsigned_longlong(Value, Rest), Len1 + 8};
-enc_type('tk_float', _Env, Value, Bytes, Len) ->
- {Rest, Len1} = enc_align(Bytes, Len, 4),
- {cdrlib:enc_float(Value, Rest), Len1 + 4};
-enc_type('tk_double', _Env, Value, Bytes, Len) ->
- {Rest, Len1} = enc_align(Bytes, Len, 8),
- {cdrlib:enc_double(Value, Rest), Len1 + 8};
-enc_type('tk_boolean', _Env, Value, Bytes, Len) ->
- {cdrlib:enc_bool(Value, Bytes), Len + 1};
-enc_type('tk_char', _Env, Value, Bytes, Len) ->
- {cdrlib:enc_char(Value, Bytes), Len + 1};
-%% The wchar decoding can be 1, 2 or 4 bytes but for now we only accept 2.
-enc_type('tk_wchar', #giop_env{version = {1,2}}, Value, Bytes, Len) ->
- Bytes1 = cdrlib:enc_octet(2, Bytes),
- {cdrlib:enc_unsigned_short(Value, Bytes1), Len + 3};
-enc_type('tk_wchar', _Env, Value, Bytes, Len) ->
- {Rest, Len1} = enc_align(Bytes, Len, 2),
- {cdrlib:enc_unsigned_short(Value, Rest), Len1 + 2};
-enc_type('tk_octet', _Env, Value, Bytes, Len) ->
- {cdrlib:enc_octet(Value, Bytes), Len + 1};
-enc_type('tk_any', Env, Any, Bytes, Len) when is_record(Any, any) ->
- {Rest, Len1} = enc_type('tk_TypeCode', Env, Any#any.typecode, Bytes, Len),
- enc_type(Any#any.typecode, Env, Any#any.value, Rest, Len1);
-enc_type('tk_TypeCode', Env, Value, Bytes, Len) ->
- enc_type_code(Value, Env, Bytes, Len);
-enc_type('tk_Principal', Env, Value, Bytes, Len) ->
- %% Set MaxLength no 0 (i.e. unlimited).
- enc_sequence(Env, Value, 0, 'tk_octet', Bytes, Len);
-enc_type({'tk_objref', _IFRId, Name}, Env, Value, Bytes, Len) ->
- enc_objref(Env, Name,Value, Bytes, Len);
-enc_type({'tk_struct', _IFRId, _Name, ElementList}, Env, Value, Bytes, Len) ->
- enc_struct(Env, Value, ElementList, Bytes, Len);
-enc_type({'tk_union', _IFRId, _Name, DiscrTC, Default, ElementList},
- Env, Value, Bytes, Len) ->
- enc_union(Env, Value, DiscrTC, Default, ElementList, Bytes, Len);
-enc_type({'tk_enum', _IFRId, _Name, ElementList}, _Env, Value, Bytes, Len) ->
- {Rest, Len1} = enc_align(Bytes, Len, 4),
- {cdrlib:enc_enum(atom_to_list(Value), ElementList, Rest), Len1 + 4};
-enc_type({'tk_string', MaxLength}, Env, Value, Bytes, Len) ->
- enc_string(Env, Value, MaxLength, Bytes, Len);
-enc_type({'tk_wstring', MaxLength}, Env, Value, Bytes, Len) ->
- enc_wstring(Env, Value, MaxLength, Bytes, Len);
-enc_type({'tk_sequence', ElemTC, MaxLength}, Env, Value, Bytes, Len) ->
- enc_sequence(Env, Value, MaxLength, ElemTC, Bytes, Len);
-enc_type({'tk_array', ElemTC, Size}, Env, Value, Bytes, Len) ->
- enc_array(Env, Value, Size, ElemTC, Bytes, Len);
-enc_type({'tk_alias', _IFRId, _Name, TC}, Env, Value, Bytes, Len) ->
- enc_type(TC, Env, Value, Bytes, Len);
-enc_type({'tk_except', IFRId, Name, ElementList}, Env, Value, Bytes, Len) ->
- enc_exception(Env, Name, IFRId, Value, ElementList, Bytes, Len);
-enc_type({'tk_fixed', Digits, Scale}, Env, Value, Bytes, Len) ->
- enc_fixed(Env, Digits, Scale, Value, Bytes, Len);
-enc_type(Type, _, Value, _, _) ->
- orber:dbg("[~p] cdr_encode:type(~p, ~p)~n"
- "Incorrect TypeCode or unsupported type.",
- [?LINE, Type, Value], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 13), completion_status=?COMPLETED_MAYBE}).
-
-
-
-
-%%-----------------------------------------------------------------
-%% Func: enc_fixed
-%%-----------------------------------------------------------------
-%% Digits eq. total number of digits.
-%% Scale eq. position of the decimal point.
-%% E.g. fixed<5,2> - "123.45" eq. #fixed{digits = 5, scale = 2, value = 12345}
-%% E.g. fixed<4,2> - "12.34" eq. #fixed{digits = 4, scale = 2, value = 1234}
-%% These are encoded as:
-%% ## <5,2> ## ## <4,2> ##
-%% 1,2 0,1 eq. 1 octet
-%% 3,4 2,3
-%% 5,0xC 4,0xC
-%%
-%% Each number is encoded as a half-octet. Note, for <4,2> a zero is
-%% added first to to be able to create "even" octets.
-enc_fixed(Env, Digits, Scale,
- #fixed{digits = Digits, scale = Scale, value = Value}, Bytes, Len)
- when is_integer(Value) andalso is_integer(Digits) andalso is_integer(Scale)
- andalso Digits < 32 andalso Digits >= Scale ->
- %% This isn't very efficient and we should improve it before supporting it
- %% officially.
- Odd = ?ODD(Digits),
- case integer_to_list(Value) of
- [$-|ValueList] when Odd == true ->
- Padded = lists:duplicate((Digits-length(ValueList)), 0) ++ ValueList,
- enc_fixed_2(Env, Digits, Scale, Padded,
- Bytes, Len, ?FIXED_NEGATIVE);
- [$-|ValueList] ->
- Padded = lists:duplicate((Digits-length(ValueList)), 0) ++ ValueList,
- enc_fixed_2(Env, Digits, Scale, [0|Padded],
- Bytes, Len, ?FIXED_NEGATIVE);
- ValueList when Odd == true ->
- Padded = lists:duplicate((Digits-length(ValueList)), 0) ++ ValueList,
- enc_fixed_2(Env, Digits, Scale, Padded,
- Bytes, Len, ?FIXED_POSITIVE);
- ValueList ->
- Padded = lists:duplicate((Digits-length(ValueList)), 0) ++ ValueList,
- enc_fixed_2(Env, Digits, Scale, [0|Padded],
- Bytes, Len, ?FIXED_POSITIVE)
- end;
-enc_fixed(_Env, Digits, Scale, Fixed, _Bytes, _Len) ->
- orber:dbg("[~p] cdr_encode:enc_fixed(~p, ~p, ~p)~n"
- "The supplied fixed type incorrect. Check that the 'digits' and 'scale' field~n"
- "match the definition in the IDL-specification. The value field must be~n"
- "a list of Digits length.",
- [?LINE, Digits, Scale, Fixed], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE}).
-
-enc_fixed_2(_Env, _Digits, _Scale, [D1], Bytes, Len, Sign) ->
- {[<<D1:4,Sign:4>>|Bytes], Len+1};
-enc_fixed_2(Env, Digits, Scale, [D1, D2|Ds], Bytes, Len, Sign) ->
- %% We could convert the ASCII-value to digit values but the bit-syntax will
- %% truncate it correctly.
- enc_fixed_2(Env, Digits, Scale, Ds, [<<D1:4,D2:4>> | Bytes], Len+1, Sign);
-enc_fixed_2(_Env, Digits, Scale, Value, _Bytes, _Len, Sign) ->
- orber:dbg("[~p] cdr_encode:enc_fixed_2(~p, ~p, ~p, ~p)~n"
- "The supplied fixed type incorrect. Most likely the 'digits' field don't match the~n"
- "supplied value. Hence, check that the value is correct.",
- [?LINE, Digits, Scale, Value, Sign], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE}).
-
-
-
-%%-----------------------------------------------------------------
-%% Func: enc_sequence/5
-%%-----------------------------------------------------------------
-%% This is a special case used when encoding encapsualted data, i.e., contained
-%% in an octet-sequence.
-enc_sequence(_Env, Sequence, MaxLength, 'tk_octet', Bytes, Len)
- when is_binary(Sequence) ->
- {ByteSequence, Len1} = enc_align(Bytes, Len, 4),
- Size = size(Sequence),
- if
- Size > MaxLength, MaxLength > 0 ->
- orber:dbg("[~p] cdr_encode:enc_sequnce(~p, ~p). Sequence exceeds max.",
- [?LINE, Sequence, MaxLength], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 19),
- completion_status=?COMPLETED_MAYBE});
- true ->
- ByteSequence1 = cdrlib:enc_unsigned_long(Size, ByteSequence),
- {[Sequence |ByteSequence1], Len1 + 4 + Size}
- end;
-enc_sequence(Env, Sequence, MaxLength, TypeCode, Bytes, Len) ->
- Length = length(Sequence),
- if
- Length > MaxLength, MaxLength > 0 ->
- orber:dbg("[~p] cdr_encode:enc_sequnce(~p, ~p). Sequence exceeds max.",
- [?LINE, Sequence, MaxLength], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 19),
- completion_status=?COMPLETED_MAYBE});
- true ->
- {ByteSequence, Len1} = enc_align(Bytes, Len, 4),
- ByteSequence1 = cdrlib:enc_unsigned_long(Length, ByteSequence),
- enc_sequence1(Env, Sequence, TypeCode, ByteSequence1, Len1 + 4)
- end.
-
-%%-----------------------------------------------------------------
-%% Func: enc_sequence1/4
-%%-----------------------------------------------------------------
-enc_sequence1(_Env, [], _TypeCode, Bytes, Len) ->
- {Bytes, Len};
-enc_sequence1(_Env, CharSeq, 'tk_char', Bytes, Len) ->
- {[list_to_binary(CharSeq) |Bytes], Len + length(CharSeq)};
-enc_sequence1(_Env, OctetSeq, 'tk_octet', Bytes, Len) ->
- {[list_to_binary(OctetSeq) |Bytes], Len + length(OctetSeq)};
-enc_sequence1(Env, [Object| Rest], TypeCode, Bytes, Len) ->
- {ByteSequence, Len1} = enc_type(TypeCode, Env, Object, Bytes, Len),
- enc_sequence1(Env, Rest, TypeCode, ByteSequence, Len1).
-
-%%-----------------------------------------------------------------
-%% Func: enc_array/4
-%%-----------------------------------------------------------------
-enc_array(Env, Array, Size, TypeCode, Bytes, Len) when size(Array) == Size ->
- Sequence = tuple_to_list(Array),
- enc_sequence1(Env, Sequence, TypeCode, Bytes, Len);
-enc_array(_,Array, Size, _, _, _) ->
- orber:dbg("[~p] cdr_encode:enc_array(~p, ~p). Incorrect size.",
- [?LINE, Array, Size], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 15), completion_status=?COMPLETED_MAYBE}).
-
-%%-----------------------------------------------------------------
-%% Func: enc_string/4
-%%-----------------------------------------------------------------
-enc_string(_Env, String, MaxLength, Bytes, Len) ->
- StrLen = length(String),
- if
- StrLen > MaxLength, MaxLength > 0 ->
- orber:dbg("[~p] cdr_encode:enc_string(~p, ~p). String exceeds max.",
- [?LINE, String, MaxLength], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 16),
- completion_status=?COMPLETED_MAYBE});
- true ->
- {ByteSequence, Len1} = enc_align(Bytes, Len, 4),
- ByteSequence1 = cdrlib:enc_unsigned_long(StrLen + 1, ByteSequence),
- {cdrlib:enc_octet(0, [String | ByteSequence1]), Len1 + StrLen + 5}
- end.
-
-
-%%-----------------------------------------------------------------
-%% Func: enc_wstring/4
-%%-----------------------------------------------------------------
-enc_wstring(#giop_env{version = {1,2}} = Env, String, MaxLength, Bytes, Len) ->
- %% Encode the length of the string (ulong).
- {Bytes1, Len1} = enc_align(Bytes, Len, 4),
- %% For IIOP-1.2 the length is the total number of octets. Hence, since the wchar's
- %% we accepts is encoded as <<255, 255>> the total size is 2*length of the list.
- ListLen = length(String),
- if
- ListLen > MaxLength, MaxLength > 0 ->
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 16),
- completion_status=?COMPLETED_MAYBE});
- true ->
- StrLen = ListLen * 2,
- Bytes2 = cdrlib:enc_unsigned_long(StrLen, Bytes1),
- %% For IIOP-1.2 no terminating null character is used.
- enc_sequence1(Env, String, 'tk_ushort', Bytes2, Len1+4)
- end;
-enc_wstring(Env, String, MaxLength, Bytes, Len) ->
- %% Encode the length of the string (ulong).
- {Bytes1, Len1} = enc_align(Bytes, Len, 4),
- ListLen = length(String),
- if
- ListLen > MaxLength, MaxLength > 0 ->
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 16),
- completion_status=?COMPLETED_MAYBE});
- true ->
- StrLen = ListLen + 1,
- Bytes2 = cdrlib:enc_unsigned_long(StrLen, Bytes1),
- {Bytes3, Len3} = enc_sequence1(Env, String, 'tk_wchar', Bytes2, Len1+4),
- %% The terminating null character is also a wchar.
- {cdrlib:enc_unsigned_short(0, Bytes3), Len3+2}
- end.
-
-
-%%-----------------------------------------------------------------
-%% Func: enc_union/5
-%%-----------------------------------------------------------------
-enc_union(Env, {_, Label, Value}, DiscrTC, Default, TypeCodeList,
- Bytes, Len) when is_list(TypeCodeList) ->
- {ByteSequence, Len1} = enc_type(DiscrTC, Env, Label, Bytes, Len),
- Label2 = stringify_enum(DiscrTC,Label),
- enc_union2(Env, {Label2, Value},TypeCodeList, Default,
- ByteSequence, Len1, undefined);
-enc_union(Env, Value, _DiscrTC, _Default, Module, Bytes, Len) when is_atom(Module) ->
- case catch Module:tc() of
- {tk_union, _, _, DiscrTC, Default, ElementList} ->
- enc_union(Env, Value, DiscrTC, Default, ElementList, Bytes, Len);
- What ->
- orber:dbg("[~p] ~p:enc_union(~p). Union module doesn't exist or incorrect.",
- [?LINE, ?MODULE, What], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE})
- end.
-
-enc_union2(_Env, _What, [], Default, Bytes, Len, _) when Default < 0 ->
- {Bytes, Len};
-enc_union2(Env, {_, Value}, [], _Default, Bytes, Len, Type) ->
- enc_type(Type, Env, Value, Bytes, Len);
-enc_union2(Env, {Label,Value} ,[{Label, _Name, Type} |_List],
- _Default, Bytes, Len, _) ->
- enc_type(Type, Env, Value, Bytes, Len);
-enc_union2(Env, Union ,[{default, _Name, Type} |List], Default, Bytes, Len, _) ->
- enc_union2(Env, Union, List, Default, Bytes, Len, Type);
-enc_union2(Env, Union,[_ | List], Default, Bytes, Len, DefaultType) ->
- enc_union2(Env, Union, List, Default, Bytes, Len, DefaultType).
-
-stringify_enum({tk_enum, _,_,_}, Label) ->
- atom_to_list(Label);
-stringify_enum(_, Label) ->
- Label.
-%%-----------------------------------------------------------------
-%% Func: enc_struct/4
-%%-----------------------------------------------------------------
-enc_struct(Env, Struct, TypeCodeList, Bytes, Len) when is_list(TypeCodeList) ->
- [_Name | StructList] = tuple_to_list(Struct),
- enc_struct1(Env, StructList, TypeCodeList, Bytes, Len);
-enc_struct(Env, Struct, Module, Bytes, Len) ->
- [Module | StructList] = tuple_to_list(Struct),
- case catch Module:tc() of
- {tk_struct, _, _, TypeCodeList} ->
- enc_struct1(Env, StructList, TypeCodeList, Bytes, Len);
- What ->
- orber:dbg("[~p] ~p:enc_struct([], ~p). Struct module doesn't exist or incorrect.",
- [?LINE, ?MODULE, What], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE})
- end.
-
-enc_struct1(_Env, [], [], Bytes, Len) ->
- {Bytes, Len};
-enc_struct1(Env, [Object | Rest], [{_ElemName, ElemType} | TypeCodeList], Bytes,
- Len) ->
- {ByteSequence, Len1} = enc_type(ElemType, Env, Object, Bytes, Len),
- enc_struct1(Env, Rest, TypeCodeList, ByteSequence, Len1).
-
-%%-----------------------------------------------------------------
-%% Func: enc_objref/4
-%%-----------------------------------------------------------------
-enc_objref(Env, _Name, Value, Bytes, Len) ->
- iop_ior:code(Env, Value, Bytes, Len).
-
-%%-----------------------------------------------------------------
-%% Func: enc_exception/5
-%%-----------------------------------------------------------------
-enc_exception(Env, _Name, IFRId, Value, ElementList, Bytes, Len) ->
- [_Name1, _TypeId | Args] = tuple_to_list(Value),
- {Bytes1, Len1} = enc_type({'tk_string', 0}, Env, IFRId , Bytes, Len),
- enc_exception_1(Env, Args, ElementList, Bytes1, Len1).
-
-enc_exception_1(_Env, [], [], Bytes, Len) ->
- {Bytes, Len};
-enc_exception_1(Env, [Arg |Args], [{_ElemName, ElemType} |ElementList],
- Bytes, Len) ->
- {Bytes1, Len1} = enc_type(ElemType, Env, Arg, Bytes, Len),
- enc_exception_1(Env, Args, ElementList, Bytes1, Len1).
-
-
-%%-----------------------------------------------------------------
-%% Func: enc_type_code/3
-%%-----------------------------------------------------------------
-enc_type_code('tk_null', Env, Message, Len) ->
- enc_type('tk_ulong', Env, 0, Message, Len);
-enc_type_code('tk_void', Env, Message, Len) ->
- enc_type('tk_ulong', Env, 1, Message, Len);
-enc_type_code('tk_short', Env, Message, Len) ->
- enc_type('tk_ulong', Env, 2, Message, Len);
-enc_type_code('tk_long', Env, Message, Len) ->
- enc_type('tk_ulong', Env, 3, Message, Len);
-enc_type_code('tk_longlong', Env, Message, Len) ->
- enc_type('tk_ulong', Env, 23, Message, Len);
-enc_type_code('tk_longdouble', Env, Message, Len) ->
- enc_type('tk_ulong', Env, 25, Message, Len);
-enc_type_code('tk_ushort', Env, Message, Len) ->
- enc_type('tk_ulong', Env, 4, Message, Len);
-enc_type_code('tk_ulong', Env, Message, Len) ->
- enc_type('tk_ulong', Env, 5, Message, Len);
-enc_type_code('tk_ulonglong', Env, Message, Len) ->
- enc_type('tk_ulong', Env, 24, Message, Len);
-enc_type_code('tk_float', Env, Message, Len) ->
- enc_type('tk_ulong', Env, 6, Message, Len);
-enc_type_code('tk_double', Env, Message, Len) ->
- enc_type('tk_ulong', Env, 7, Message, Len);
-enc_type_code('tk_boolean', Env, Message, Len) ->
- enc_type('tk_ulong', Env, 8, Message, Len);
-enc_type_code('tk_char', Env, Message, Len) ->
- enc_type('tk_ulong', Env, 9, Message, Len);
-enc_type_code('tk_wchar', Env, Message, Len) ->
- enc_type('tk_ulong', Env, 26, Message, Len);
-enc_type_code('tk_octet', Env, Message, Len) ->
- enc_type('tk_ulong', Env, 10, Message, Len);
-enc_type_code('tk_any', Env, Message, Len) ->
- enc_type('tk_ulong', Env, 11, Message, Len);
-enc_type_code('tk_TypeCode', Env, Message, Len) ->
- enc_type('tk_ulong', Env, 12, Message, Len);
-enc_type_code('tk_Principal', Env, Message, Len) ->
- enc_type('tk_ulong', Env, 13, Message, Len);
-enc_type_code({'tk_objref', RepId, Name}, Env, Message, Len) ->
- {Message1, Len1} = enc_type('tk_ulong', Env, 14, Message, Len),
- {Message2, _} = enc_byte_order(Env, []),
- {ComplexParams, Len2} = enc_type({'tk_struct', "", "", [{"repository ID", {'tk_string', 0}},
- {"name", {'tk_string', 0}}]},
- Env,
- {"", RepId, Name},
- Message2, 1),
- encode_complex_tc_paramters(lists:reverse(ComplexParams), Len2, Message1, Len1);
-enc_type_code({'tk_struct', RepId, SimpleName, ElementList}, Env, Message, Len) ->
- %% Using SimpleName should be enough (and we avoid some overhead).
- %% Name = ifrid_to_name(RepId),
- {Message1, Len1} = enc_type('tk_ulong', Env, 15, Message, Len),
- {Message2, _} = enc_byte_order(Env, []),
- {ComplexParams, Len2} = enc_type({'tk_struct', "", "", [{"repository ID", {'tk_string', 0}},
- {"name", {'tk_string', 0}},
- {"element list",
- {'tk_sequence', {'tk_struct', "","",
- [{"member name", {'tk_string', 0}},
- {"member type", 'tk_TypeCode'}]},
- 0}}]},
- Env,
- {"", RepId, SimpleName,
- lists:map(fun({N,T}) -> {"",N,T} end, ElementList)},
- Message2, 1),
- encode_complex_tc_paramters(lists:reverse(ComplexParams), Len2, Message1, Len1);
-enc_type_code({'tk_union', RepId, Name, DiscrTC, Default, ElementList},
- Env, Message, Len) ->
- NewElementList =
- case check_enum(DiscrTC) of
- true ->
- lists:map(fun({L,N,T}) -> {"",list_to_atom(L),N,T} end, ElementList);
- false ->
- lists:map(fun({L,N,T}) -> {"",L,N,T} end, ElementList)
- end,
- {Message1, Len1} = enc_type('tk_ulong', Env, 16, Message, Len),
- {Message2, _} = enc_byte_order(Env, []),
- {ComplexParams, Len2} = enc_type({'tk_struct', "", "", [{"repository ID", {'tk_string', 0}},
- {"name", {'tk_string', 0}},
- {"discriminant type", 'tk_TypeCode'},
- {"default used", 'tk_long'},
- {"element list",
- {'tk_sequence', {'tk_struct', "","",
- [{"label value", DiscrTC},
- {"member name", {'tk_string', 0}},
- {"member type", 'tk_TypeCode'}]},
- 0}}]},
- Env,
- {"", RepId, Name, DiscrTC, Default, NewElementList},
- Message2, 1),
- encode_complex_tc_paramters(lists:reverse(ComplexParams), Len2, Message1, Len1);
-enc_type_code({'tk_enum', RepId, Name, ElementList}, Env, Message, Len) ->
- {Message1, Len1} = enc_type('tk_ulong', Env, 17, Message, Len),
- {Message2, _} = enc_byte_order(Env, []),
- {ComplexParams, Len2} = enc_type({'tk_struct', "", "", [{"repository ID", {'tk_string', 0}},
- {"name", {'tk_string', 0}},
- {"element list",
- {'tk_sequence', {'tk_string', 0}, 0}}]},
- Env,
- {"", RepId, Name, ElementList},
- Message2, 1),
- encode_complex_tc_paramters(lists:reverse(ComplexParams), Len2, Message1, Len1);
-enc_type_code({'tk_string', MaxLength}, Env, Message, Len) ->
- enc_type({'tk_struct', "", "", [{"TCKind", 'tk_ulong'},
- {"max length", 'tk_ulong'}]},
- Env,
- {"", 18, MaxLength},
- Message, Len);
-enc_type_code({'tk_wstring', MaxLength}, Env, Message, Len) ->
- enc_type({'tk_struct', "", "", [{"TCKind", 'tk_ulong'},
- {"max length", 'tk_ulong'}]},
- Env,
- {"", 27, MaxLength},
- Message, Len);
-enc_type_code({'tk_sequence', ElemTC, MaxLength}, Env, Message, Len) ->
- {Message1, Len1} = enc_type('tk_ulong', Env, 19, Message, Len),
- {Message2, _} = enc_byte_order(Env, []),
- {ComplexParams, Len2} = enc_type({'tk_struct', "", "", [{"element type", 'tk_TypeCode'},
- {"max length", 'tk_ulong'}]},
- Env,
- {"", ElemTC, MaxLength},
- Message2, 1),
- encode_complex_tc_paramters(lists:reverse(ComplexParams), Len2, Message1, Len1);
-enc_type_code({'tk_array', ElemTC, Length}, Env, Message, Len) ->
- {Message1, Len1} = enc_type('tk_ulong', Env, 20, Message, Len),
- {Message2, _} = enc_byte_order(Env, []),
- {ComplexParams, Len2} = enc_type({'tk_struct', "", "", [{"element type", 'tk_TypeCode'},
- {"length", 'tk_ulong'}]},
- Env,
- {"", ElemTC, Length},
- Message2, 1),
- encode_complex_tc_paramters(lists:reverse(ComplexParams), Len2, Message1, Len1);
-enc_type_code({'tk_alias', RepId, Name, TC}, Env, Message, Len) ->
- {Message1, Len1} = enc_type('tk_ulong', Env, 21, Message, Len),
- {Message2, _} = enc_byte_order(Env, []),
- {ComplexParams, Len2} = enc_type({'tk_struct', "", "", [{"repository ID", {'tk_string', 0}},
- {"name", {'tk_string', 0}},
- {"TypeCode", 'tk_TypeCode'}]},
- Env,
- {"", RepId, Name, TC},
- Message2, 1),
- encode_complex_tc_paramters(lists:reverse(ComplexParams), Len2, Message1, Len1);
-enc_type_code({'tk_except', RepId, Name, ElementList}, Env, Message, Len) ->
- {Message1, Len1} = enc_type('tk_ulong', Env, 22, Message, Len),
- {Message2, _} = enc_byte_order(Env, []),
- {ComplexParams, Len2} = enc_type({'tk_struct', "", "", [{"repository ID", {'tk_string', 0}},
- {"name", {'tk_string', 0}},
- {"element list",
- {'tk_sequence',
- {'tk_struct', "", "",
- [{"member name", {'tk_string', 0}},
- {"member type", 'tk_TypeCode'}]}, 0}}]},
- Env,
- {"", RepId, Name,
- lists:map(fun({N,T}) -> {"",N,T} end, ElementList)},
- Message2, 1),
- encode_complex_tc_paramters(lists:reverse(ComplexParams), Len2, Message1, Len1);
-enc_type_code({'tk_fixed', Digits, Scale}, Env, Message, Len) ->
- enc_type({'tk_struct', "", "", [{"TCKind", 'tk_ulong'},
- {"digits", 'tk_ushort'},
- {"scale", 'tk_short'}]},
- Env,
- {"", 28, Digits, Scale},
- Message, Len);
-enc_type_code({'tk_value', RepId, Name, ValueModifier, TC, ElementList}, Env, Message, Len) ->
- {Message1, Len1} = enc_type('tk_ulong', Env, 29, Message, Len),
- {Message2, _} = enc_byte_order(Env, []),
- {ComplexParams, Len2} = enc_type({'tk_struct', "", "",
- [{"repository ID", {'tk_string', 0}},
- {"name", {'tk_string', 0}},
- {"ValueModifier", 'tk_short'},
- {"TypeCode", 'tk_TypeCode'},
- {"element list",
- {'tk_sequence',
- {'tk_struct', "","",
- [{"member name", {'tk_string', 0}},
- {"member type", 'tk_TypeCode'},
- {"Visibility", 'tk_short'}]},
- 0}}]},
- Env,
- {"", RepId, Name, ValueModifier, TC,
- lists:map(fun({N,T,V}) -> {"",N,T,V} end, ElementList)},
- Message2, 1),
- encode_complex_tc_paramters(lists:reverse(ComplexParams), Len2, Message1, Len1);
-enc_type_code({'tk_value_box', RepId, Name, TC}, Env, Message, Len) ->
- {Message1, Len1} = enc_type('tk_ulong', Env, 30, Message, Len),
- {Message2, _} = enc_byte_order(Env, []),
- {ComplexParams, Len2} = enc_type({'tk_struct', "", "",
- [{"repository ID", {'tk_string', 0}},
- {"name", {'tk_string', 0}},
- {"TypeCode", 'tk_TypeCode'}]},
- Env,
- {"", RepId, Name, TC},
- Message2, 1),
- encode_complex_tc_paramters(lists:reverse(ComplexParams), Len2, Message1, Len1);
-enc_type_code({'tk_native', RepId, Name}, Env, Message, Len) ->
- {Message1, Len1} = enc_type('tk_ulong', Env, 31, Message, Len),
- {Message2, _} = enc_byte_order(Env, []),
- {ComplexParams, Len2} = enc_type({'tk_struct', "", "",
- [{"repository ID", {'tk_string', 0}},
- {"name", {'tk_string', 0}}]},
- Env,
- {"", RepId, Name},
- Message2, 1),
- encode_complex_tc_paramters(lists:reverse(ComplexParams), Len2, Message1, Len1);
-enc_type_code({'tk_abstract_interface', RepId, Name}, Env, Message, Len) ->
- {Message1, Len1} = enc_type('tk_ulong', Env, 32, Message, Len),
- {Message2, _} = enc_byte_order(Env, []),
- {ComplexParams, Len2} = enc_type({'tk_struct', "", "",
- [{"RepositoryId", {'tk_string', 0}},
- {"name", {'tk_string', 0}}]},
- Env,
- {"", RepId, Name},
- Message2, 1),
- encode_complex_tc_paramters(lists:reverse(ComplexParams), Len2, Message1, Len1);
-enc_type_code({'tk_local_interface', RepId, Name}, Env, Message, Len) ->
- {Message1, Len1} = enc_type('tk_ulong', Env, 33, Message, Len),
- {Message2, _} = enc_byte_order(Env, []),
- {ComplexParams, Len2} = enc_type({'tk_struct', "", "",
- [{"RepositoryId", {'tk_string', 0}},
- {"name", {'tk_string', 0}}]},
- Env,
- {"", RepId, Name},
- Message2, 1),
- encode_complex_tc_paramters(lists:reverse(ComplexParams), Len2, Message1, Len1);
-enc_type_code({'none', Indirection}, Env, Message, Len) -> %% placeholder
- enc_type({'tk_struct', "", "", [{"TCKind", 'tk_ulong'},
- {"indirection", 'tk_long'}]},
- Env,
- {"", 16#ffffffff, Indirection},
- Message, Len);
-enc_type_code(Type, _, _, _) ->
- orber:dbg("[~p] cdr_encode:enc_type_code(~p); No match.",
- [?LINE, Type], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 7), completion_status=?COMPLETED_MAYBE}).
-
-check_enum({'tk_enum', _, _, _}) ->
- true;
-check_enum(_) ->
- false.
-
-encode_complex_tc_paramters(Value, ValueLength, Message, Len) ->
- {Message1, _Len1} = enc_align(Message, Len, 4),
- Message2 = cdrlib:enc_unsigned_long(ValueLength, Message1),
- {[Value |Message2], Len+ValueLength+4}.
-
-%%-----------------------------------------------------------------
-%% Func: enc_align/1
-%%-----------------------------------------------------------------
-enc_align(R, Len, Alignment) ->
- Rem = Len rem Alignment,
- if Rem == 0 ->
- {R, Len};
- true ->
- Diff = Alignment - Rem,
- {add_bytes(R, Diff), Len + Diff}
- end.
-
-add_bytes(R, 0) ->
- R;
-add_bytes(R, 1) ->
- [<<16#01:8>> | R];
-add_bytes(R, 2) ->
- [<<16#02:8, 16#02:8>> | R];
-add_bytes(R, 3) ->
- [<<16#03:8, 16#03:8, 16#03:8>> | R];
-add_bytes(R, 4) ->
- [<<16#04:8, 16#04:8, 16#04:8, 16#04:8>> | R];
-add_bytes(R, 5) ->
- [<<16#05:8, 16#05:8, 16#05:8, 16#05:8, 16#05:8>> | R];
-add_bytes(R, 6) ->
- [<<16#06:8, 16#06:8, 16#06:8, 16#06:8, 16#06:8, 16#06:8>> | R];
-add_bytes(R, 7) ->
- [<<16#07:8, 16#07:8, 16#07:8, 16#07:8, 16#07:8, 16#07:8, 16#07:8>> | R];
-add_bytes(R,N) ->
- add_bytes([<<16#08:8>> | R], N - 1).
-
diff --git a/lib/orber/src/cdrlib.erl b/lib/orber/src/cdrlib.erl
deleted file mode 100644
index a181681382..0000000000
--- a/lib/orber/src/cdrlib.erl
+++ /dev/null
@@ -1,415 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: cdrlib.erl
-%%
-%% Description:
-%% CDR basic type encode/decode functions
-%%
-%%-----------------------------------------------------------------
--module(cdrlib).
-
--include_lib("orber/include/corba.hrl").
--include("orber_iiop.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([ %% IIOP 1.0 -
- enc_short/2, dec_short/2,
- enc_unsigned_short/2, dec_unsigned_short/2,
- enc_long/2, dec_long/2,
- enc_unsigned_long/2, dec_unsigned_long/2,
- enc_bool/2, dec_bool/1,
- enc_float/2, dec_float/2,
- enc_double/2, dec_double/2,
- enc_char/2, dec_char/1,
- enc_octet/2, dec_octet/1,
- enc_enum/3, dec_enum/3,
- %% IIOP 1.1 -
- enc_longlong/2, dec_longlong/2,
- enc_unsigned_longlong/2, dec_unsigned_longlong/2
- %%enc_longdouble/2, dec_longdouble/2
- %%enc_fixed/4, dec_fixed/2
- ]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-%%-----------------------------------------------------------------
-%% Macros
-%%-----------------------------------------------------------------
--define(DEBUG_LEVEL, 10).
-
-%%-----------------------------------------------------------------
-%% short
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: enc_short/2
-%%-----------------------------------------------------------------
-enc_short(X, Message) when is_integer(X) andalso X >= ?SHORTMIN andalso X =< ?SHORTMAX ->
- [<<X:16/big-signed-integer>> | Message];
-enc_short(X, _Message) when is_integer(X) ->
- orber:dbg("[~p] cdrlib:enc_short(~p); Out of range.", [?LINE, X], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 1), completion_status=?COMPLETED_NO});
-enc_short(X, _Message) ->
- orber:dbg("[~p] cdrlib:enc_short(~p); not integer.", [?LINE, X], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 2), completion_status=?COMPLETED_NO}).
-
-%%-----------------------------------------------------------------
-%% Func: dec_short/2
-%%-----------------------------------------------------------------
-dec_short(big, <<Short:16/big-signed-integer,Rest/binary>>) ->
- {Short, Rest};
-dec_short(little, <<Short:16/little-signed-integer,Rest/binary>>) ->
- {Short, Rest}.
-
-%%-----------------------------------------------------------------
-%% unsigned short
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: enc_unsigned_short/2
-%%-----------------------------------------------------------------
-enc_unsigned_short(X, Message) when is_integer(X) andalso X >= ?USHORTMIN andalso X =< ?USHORTMAX ->
- [<<X:16/big-unsigned-integer>> | Message];
-enc_unsigned_short(X, _Message) when is_integer(X) ->
- orber:dbg("[~p] cdrlib:enc_unsigned_short(~p); Out of range.",
- [?LINE, X], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 1), completion_status=?COMPLETED_NO});
-enc_unsigned_short(X, _Message) ->
- orber:dbg("[~p] cdrlib:enc_unsigned_short(~p); not integer >= 0",
- [?LINE, X], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 2), completion_status=?COMPLETED_NO}).
-
-%%-----------------------------------------------------------------
-%% Func: dec_unsigned_short/2
-%%-----------------------------------------------------------------
-dec_unsigned_short(big, <<UShort:16/big-unsigned-integer,Rest/binary>>) ->
- {UShort, Rest};
-dec_unsigned_short(little, <<UShort:16/little-unsigned-integer,Rest/binary>>) ->
- {UShort, Rest}.
-
-%%-----------------------------------------------------------------
-%% long
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: enc_long/2
-%%-----------------------------------------------------------------
-enc_long(X, Message) when is_integer(X) andalso X >= ?LONGMIN andalso X =< ?LONGMAX ->
- [<<X:32/big-signed-integer>> | Message];
-enc_long(X, _Message) when is_integer(X) ->
- orber:dbg("[~p] cdrlib:enc_long(~p); Out of range.",[?LINE, X], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 1), completion_status=?COMPLETED_NO});
-enc_long(X, _Message) ->
- orber:dbg("[~p] cdrlib:enc_long(~p); not integer.",
- [?LINE, X], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 2), completion_status=?COMPLETED_NO}).
-
-%%-----------------------------------------------------------------
-%% Func: dec_long/2
-%%-----------------------------------------------------------------
-dec_long(big, <<Long:32/big-signed-integer,Rest/binary>>) ->
- {Long, Rest};
-dec_long(little, <<Long:32/little-signed-integer,Rest/binary>>) ->
- {Long, Rest}.
-
-%%-----------------------------------------------------------------
-%% unsigned_long
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: enc_unsigned_long/2
-%%-----------------------------------------------------------------
-enc_unsigned_long(X, Message) when is_integer(X) andalso X >= ?ULONGMIN andalso X =< ?ULONGMAX ->
- [<<X:32/big-unsigned-integer>> | Message];
-enc_unsigned_long(X, _Message) when is_integer(X) ->
- orber:dbg("[~p] cdrlib:enc_unsigned_long(~p); Out of range.",
- [?LINE, X], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 1), completion_status=?COMPLETED_NO});
-enc_unsigned_long(X, _Message) ->
- orber:dbg("[~p] cdrlib:enc_unsigned_long(~p); not integer >=0 ",
- [?LINE, X], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 2), completion_status=?COMPLETED_NO}).
-
-%%-----------------------------------------------------------------
-%% Func: dec_unsigned_long/2
-%%-----------------------------------------------------------------
-dec_unsigned_long(big, <<ULong:32/big-unsigned-integer,Rest/binary>>) ->
- {ULong, Rest};
-dec_unsigned_long(little, <<ULong:32/little-unsigned-integer,Rest/binary>>) ->
- {ULong, Rest}.
-
-%%-----------------------------------------------------------------
-%% boolean
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: enc_bool/2
-%%-----------------------------------------------------------------
-enc_bool(true, Message) -> [<<1:8>>| Message];
-enc_bool(false, Message) -> [<<0:8>>| Message];
-enc_bool(X, _Message) ->
- orber:dbg("[~p] cdrlib:enc_bool(~p); Must be 'true' or 'false'",
- [?LINE, X], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 3), completion_status=?COMPLETED_NO}).
-
-%%-----------------------------------------------------------------
-%% Func: dec_bool/1
-%%-----------------------------------------------------------------
-dec_bool(<<1:8,Rest/binary>>) -> {true, Rest};
-dec_bool(<<0:8,Rest/binary>>) -> {false, Rest};
-dec_bool(<<X:8,_Rest/binary>>) ->
- orber:dbg("[~p] cdrlib:dec_bool(~p); Not a boolean (1 or 0).",
- [?LINE, X], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 3), completion_status=?COMPLETED_NO}).
-
-
-%%-----------------------------------------------------------------
-%% Func: enc_float/2
-%%-----------------------------------------------------------------
-enc_float(X, Message) when is_number(X) ->
- [<<X:32/big-float>> | Message];
-enc_float(X, _Message) ->
- orber:dbg("[~p] cdrlib:enc_float(~p); not a number.", [?LINE, X], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 4), completion_status=?COMPLETED_NO}).
-
-%%-----------------------------------------------------------------
-%% Func: dec_float/2
-%%-----------------------------------------------------------------
-dec_float(big, <<Float:32/big-float,Rest/binary>>) ->
- {Float, Rest};
-dec_float(little, <<Float:32/little-float,Rest/binary>>) ->
- {Float, Rest}.
-
-%%-----------------------------------------------------------------
-%% Func: enc_double/2
-%%-----------------------------------------------------------------
-enc_double(X, Message) when is_number(X) ->
- [<<X:64/big-float>> | Message];
-enc_double(X, _Message) ->
- orber:dbg("[~p] cdrlib:enc_double(~p); not a number.", [?LINE, X], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 4), completion_status=?COMPLETED_NO}).
-
-%%-----------------------------------------------------------------
-%% Func: dec_double/2
-%%-----------------------------------------------------------------
-dec_double(big, <<Double:64/big-float,Rest/binary>>) ->
- {Double, Rest};
-dec_double(little, <<Double:64/little-float,Rest/binary>>) ->
- {Double, Rest}.
-
-%%-----------------------------------------------------------------
-%% char
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: enc_char/2
-%%-----------------------------------------------------------------
-enc_char(X, Message) when is_integer(X) andalso X =< 255, X >= 0 ->
- [<<X:8>> | Message];
-enc_char(X,_) ->
- orber:dbg("[~p] cdrlib:enc_char(~p); not a char.", [?LINE, X], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 6),completion_status=?COMPLETED_NO}).
-
-%%-----------------------------------------------------------------
-%% Func: dec_char/1
-%%-----------------------------------------------------------------
-dec_char(<<Char:8,Rest/binary>>) ->
- {Char, Rest}.
-
-%%-----------------------------------------------------------------
-%% octet
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: enc_octet/2
-%%-----------------------------------------------------------------
-enc_octet(X, Message) when is_integer(X) andalso X =< 255, X >= 0 ->
- [<<X:8/big-unsigned-integer>> | Message];
-enc_octet(X, _Message) ->
- orber:dbg("[~p] cdrlib:enc_octet(~p); not an octet.", [?LINE, X], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 6),completion_status=?COMPLETED_NO}).
-
-%%-----------------------------------------------------------------
-%% Func: dec_octet/1
-%%-----------------------------------------------------------------
-dec_octet(<<Octet:8/big-unsigned-integer,Rest/binary>>) ->
- {Octet, Rest}.
-
-%%-----------------------------------------------------------------
-%% enum
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: enc_enum/3
-%%-----------------------------------------------------------------
-enc_enum(Enum, ElemList, Message) ->
- Val = getEnumValue(ElemList,Enum, 0),
- enc_unsigned_long(Val, Message).
-
-getEnumValue([],Enum, _) ->
- orber:dbg("[~p] cdrlib:enc_enum/enc_r_enum(~p); not exist.",
- [?LINE, Enum], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 5),
- completion_status=?COMPLETED_NO});
-getEnumValue([Enum|_List], Enum, N) ->
- N;
-getEnumValue([_ |List], Enum, N) ->
- getEnumValue(List, Enum, N + 1).
-
-%%-----------------------------------------------------------------
-%% Func: dec_enum/2
-%%-----------------------------------------------------------------
-dec_enum(ByteOrder, ElemList, Message) ->
- {N, Rest} = dec_unsigned_long(ByteOrder, Message),
- case catch lists:nth(N + 1, ElemList) of
- {'EXIT', _} ->
- orber:dbg("[~p] cdrlib:dec_enum(~p, ~p); not defined.",
- [?LINE, N, ElemList], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 5),
- completion_status=?COMPLETED_NO});
- X ->
- {list_to_atom(X), Rest}
- end.
-
-
-%%-----------------------------------------------------------------
-%% IIOP 1.1 -
-%%-----------------------------------------------------------------
-
-%%-----------------------------------------------------------------
-%% longlong
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: enc_longlong/2
-%%-----------------------------------------------------------------
-enc_longlong(X, Message) when is_integer(X) andalso X >= ?LONGLONGMIN andalso X =< ?LONGLONGMAX ->
- [<<X:64/big-signed-integer>> | Message];
-enc_longlong(X, _Message) when is_integer(X) ->
- orber:dbg("[~p] cdrlib:enc_longlong(~p); Out of range.",
- [?LINE, X], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 1), completion_status=?COMPLETED_NO});
-enc_longlong(X, _Message) ->
- orber:dbg("[~p] cdrlib:enc_longlong(~p); not integer.",
- [?LINE, X], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 2), completion_status=?COMPLETED_NO}).
-
-%%-----------------------------------------------------------------
-%% Func: dec_longlong/2
-%%-----------------------------------------------------------------
-dec_longlong(big, <<LongLong:64/big-signed-integer,Rest/binary>>) ->
- {LongLong, Rest};
-dec_longlong(little, <<LongLong:64/little-signed-integer,Rest/binary>>) ->
- {LongLong, Rest}.
-
-%%-----------------------------------------------------------------
-%% Func: enc_unsigned_longlong/2
-%%-----------------------------------------------------------------
-enc_unsigned_longlong(X, Message) when is_integer(X) andalso X >= ?ULONGLONGMIN andalso X =< ?ULONGLONGMAX ->
- [<<X:64/big-unsigned-integer>> | Message];
-enc_unsigned_longlong(X, _Message) when is_integer(X) ->
- orber:dbg("[~p] cdrlib:enc_unsigned_longlong(~p); Out of range.",
- [?LINE, X], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 1), completion_status=?COMPLETED_NO});
-enc_unsigned_longlong(X, _Message) ->
- orber:dbg("[~p] cdrlib:enc_unsigned_longlong(~p); not integer >= 0.",
- [?LINE, X], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 2), completion_status=?COMPLETED_NO}).
-
-%%-----------------------------------------------------------------
-%% Func: dec_unsigned_longlong/2
-%%-----------------------------------------------------------------
-dec_unsigned_longlong(big, <<ULongLong:64/big-unsigned-integer,Rest/binary>>) ->
- {ULongLong, Rest};
-dec_unsigned_longlong(little, <<ULongLong:64/little-unsigned-integer,Rest/binary>>) ->
- {ULongLong, Rest}.
-
-%%%-----------------------------------------------------------------
-%%% long double [S=1 | E=15 | F=112]
-%%% X = (-1)^S * 2^(E-16383) * 1.F
-%%%-----------------------------------------------------------------
-%-define(LONGDOUBLE_BASE, 16#10000000000000000000000000000).
-%-define(LONGDOUBLE_BIAS, 16383).
-%%%-----------------------------------------------------------------
-%%% Func: enc_longdouble/2
-%%%-----------------------------------------------------------------
-%enc_longdouble(X, Message) when number(X) ->
-% {S, E, F} = enc_ieee(X, ?LONGDOUBLE_BASE, ?LONGDOUBLE_BIAS),
-% [ (S bsl 7) bor ((E bsr 8) band 16#7f),
-% E band 16#ff,
-% (F bsr 104) band 16#ff,
-% (F bsr 96) band 16#ff,
-% (F bsr 88) band 16#ff,
-% (F bsr 80) band 16#ff,
-% (F bsr 72) band 16#ff,
-% (F bsr 64) band 16#ff,
-% (F bsr 56) band 16#ff,
-% (F bsr 48) band 16#ff,
-% (F bsr 40) band 16#ff,
-% (F bsr 32) band 16#ff,
-% (F bsr 24) band 16#ff,
-% (F bsr 16) band 16#ff,
-% (F bsr 8) band 16#ff,
-% F band 16#ff | Message];
-%enc_longdouble(X, Message) ->
-% corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 4), completion_status=?COMPLETED_NO}).
-
-%%%-----------------------------------------------------------------
-%%% Func: dec_longdouble/2
-%%%-----------------------------------------------------------------
-%dec_longdouble([X15,X14,X13,X12,X11,X10,X9,X8,X7,X6,X5,X4,X3,X2,X1,X0 | R], big) ->
-
-% E = (X15 band 16#7f) bsl 8 + X14,
-
-% F = (X13 bsl 104) + (X12 bsl 96) +
-% (X11 bsl 88) + (X10 bsl 80) + (X9 bsl 72) +
-% (X8 bsl 64) + (X7 bsl 56) + (X6 bsl 48) +
-% (X5 bsl 40) + (X4 bsl 32) + (X3 bsl 24) +
-% (X2 bsl 16) + (X1 bsl 8) + X0,
-
-% if
-% E == 0, F == 0 ->
-% { 0.0, R};
-% X15 >= 16#80 ->
-% { - math:pow(2, E-?LONGDOUBLE_BIAS) * (1 + F / ?LONGDOUBLE_BASE), R};
-% true ->
-% { math:pow(2, E-?LONGDOUBLE_BIAS) * (1 + F / ?LONGDOUBLE_BASE), R}
-% end;
-%dec_longdouble([X15,X14,X13,X12,X11,X10,X9,X8,X7,X6,X5,X4,X3,X2,X1,X0 | R], little) ->
-
-% E = (X0 band 16#7f) bsl 8 + X1,
-
-% F =
-% (X2 bsl 104) + (X3 bsl 96) +
-% (X4 bsl 88) + (X5 bsl 80) + (X6 bsl 72) +
-% (X7 bsl 64) + (X8 bsl 56) + (X9 bsl 48) +
-% (X10 bsl 40) + (X11 bsl 32) + (X12 bsl 24) +
-% (X13 bsl 16) + (X14 bsl 8) + X15,
-
-% if
-% E == 0, F == 0 ->
-% { 0.0, R};
-% X0 >= 16#80 ->
-% { - math:pow(2, E-?DOUBLE_BIAS) * (1 + F / ?DOUBLE_BASE), R};
-% true ->
-% { math:pow(2, E-?DOUBLE_BIAS) * (1 + F / ?DOUBLE_BASE), R}
-% end.
-
-%%------------------ END OF MODULE -----------------------------------
-
diff --git a/lib/orber/src/corba.erl b/lib/orber/src/corba.erl
deleted file mode 100644
index 23ce01ffc3..0000000000
--- a/lib/orber/src/corba.erl
+++ /dev/null
@@ -1,2206 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%--------------------------------------------------------------------
-%% File: corba.erl
-%%
-%% Description:
-%% This file contains the CORBA::ORB interface plus some
-%% Orber specific functions.
-%%-----------------------------------------------------------------
--module(corba).
-
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
-
-%%-----------------------------------------------------------------
-%% Standard interface CORBA
-%%-----------------------------------------------------------------
--export([orb_init/1, orb_init/2]).
-%%-----------------------------------------------------------------
-%% Standard interface CORBA::ORB
-%%-----------------------------------------------------------------
--export([%create_list/2,
- %create_operation_list/2,
- %% get_default_context/1,
- %% 'BOA_init/2,
- resolve_initial_references/1,
- resolve_initial_references/2,
- resolve_initial_references_local/1,
- list_initial_services/0,
- add_initial_service/2,
- remove_initial_service/1,
- resolve_initial_references_remote/2,
- resolve_initial_references_remote/3,
- list_initial_services_remote/1,
- list_initial_services_remote/2,
- object_to_string/1, object_to_string/2,
- object_to_string/3, object_to_string/4,
- string_to_object/1,
- string_to_object/2]).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([create/2,
- create/3,
- create/4,
- create_link/2,
- create_link/3,
- create_link/4,
- create_remote/3,
- create_remote/5,
- create_link_remote/3,
- create_link_remote/5,
- create_nil_objref/0,
- dispose/1,
- create_subobject_key/2,
- get_subobject_key/1,
- get_pid/1,
- raise/1, raise_with_state/2,
- print_object/1,
- print_object/2,
- add_alternate_iiop_address/3,
- add_FTGroup_component/4,
- add_FTPrimary_component/1,
- call_internal/10]).
-
-%%-----------------------------------------------------------------
-%% Internal (inside orber implementation) exports
-%%-----------------------------------------------------------------
--export([call/4, call/5, reply/2,
- cast/4, cast/5, locate/1, locate/2, locate/3,
- request_from_iiop/6,
- common_create/5,
- mk_objkey/4,
- mk_light_objkey/2,
- objkey_to_string/1,
- string_to_objkey/1,
- string_to_objkey_local/1,
- call_relay/3,
- cast_relay/2,
- handle_init/2,
- handle_terminate/3,
- handle_info/3,
- handle_code_change/4,
- handle_call/7,
- handle_call/10,
- handle_cast/9,
- handle_cast/6,
- get_implicit_context/1]).
-
-%%-----------------------------------------------------------------
-%% Internal definitions
-%%-----------------------------------------------------------------
--define(DEBUG_LEVEL, 5).
-
--record(is, {flags = 0}).
-
-%% Defines possible configuration parameters a user can add when
-%% creating new CORBA objects.
--record(options, {sup_child = false,
- persistent = false,
- regname = [],
- pseudo = false,
- object_flags = ?ORB_INIT_FLAGS,
- object_flags_set = ?ORB_INIT_FLAGS,
- create_options = [],
- passive = false,
- group_id = 0,
- internal_state}).
-
--record(extra, {timeout = infinity,
- context = []}).
-
-
-%%--------------------------------------------------------------------
-%% FT stuff
-%%--------------------------------------------------------------------
--define(IDL_MODULES, [oe_TimeBase,
- oe_CosEventComm,
- oe_CosEventChannelAdmin,
- oe_CosNotification,
- oe_CosNotifyComm,
- oe_CosNotifyFilter,
- oe_GIOP]).
-
--define(groupid_to_table(Integer),
- list_to_atom("ft_" ++ integer_to_list(Integer))).
-
--define(RM_TABLE_SPEC,
- [{attributes, record_info(fields, ft_replication_manager)}]).
--define(RO_TABLE_SPEC,
- [{attributes, record_info(fields, ft_replicated_object)}]).
--define(RR_TABLE_SPEC,
- [{attributes, record_info(fields, ft_reply_retention)}]).
-
-%% how long we're allowed to wait for database tables to be available.
--define(TABLE_TIMEOUT, infinite).
-
-%-record(rm_state, {default_options, type_options, node_port_ips}).
-
-%-record(node_port_ip, {node, port, ip}).
-
--record(ft_replication_manager, {object_group_id,
- type_id,
- primary,
- iogr,
- ref_version,
- options}).
-
--record(ft_replicated_object, {group_id, state}).
--record(ft_reply_retention, {retention_id, reply}).
-
-%-record(ft_properties, {replications_style,
-% membership_style,
-% consistency_style,
-% initial_number_replicas,
-% minimum_number_replicas}).
-
-% one should change things work with stdlib:proplist and clean up the mess.
-%-record(ft_criteria, {ft_properties,
-% object_location,
-% object_init,
-% object_impl}).
-
-%%------------------------------------------------------------
-%%
-%% Implementation of CORBA CORBA::ORB interfaces
-%%
-%%------------------------------------------------------------
-
-%%create_list(Count) ->
-%% corba_nvlist:create_list(Count).
-
-%%create_operation_list(OpDef) ->
-%% corba_nvlist:create_operation_list(OpDef).
-
-orb_init(KeyValueList) ->
- orb_init(KeyValueList, "ORBER").
-
-orb_init([], _Name) ->
- ok;
-orb_init(KeyValueList, _Name) ->
- orber:multi_configure(KeyValueList).
-
-%%-----------------------------------------------------------------
-%% Initial reference handling
-%%-----------------------------------------------------------------
-resolve_initial_references(ObjectId) ->
- resolve_initial_references(ObjectId, []).
-resolve_initial_references(ObjectId, Ctx) ->
- case use_local_host(ObjectId) of
- true ->
- orber_initial_references:get(ObjectId);
- Ref ->
- string_to_object(Ref, Ctx)
- end.
-
-resolve_initial_references_local(ObjectId) ->
- orber_initial_references:get(ObjectId).
-
-list_initial_services() ->
- Local = orber_initial_references:list(),
- case orber:get_ORBInitRef() of
- undefined ->
- Local;
- InitRef ->
- orber_tb:unique(Local ++ get_prefixes(InitRef, []))
- end.
-
-get_prefixes([], Acc) ->
- Acc;
-%% A list of ORBInitRef's
-get_prefixes([H|T], Acc) when is_list(H) ->
- [Key|_] = string:tokens(H, "="),
- get_prefixes(T, [Key|Acc]);
-%% A single ORBInitRef
-get_prefixes(InitRef, _Acc) when is_list(InitRef) ->
- [Key|_] = string:tokens(InitRef, "="),
- [Key];
-get_prefixes(What, _) ->
- orber:dbg("[~p] corba:get_prefixes(~p);~nMalformed argument?",
- [?LINE, What], ?DEBUG_LEVEL),
- raise(#'BAD_PARAM'{completion_status = ?COMPLETED_NO}).
-
-
-use_local_host(ObjectId) ->
- case orber:get_ORBInitRef() of
- undefined ->
- case orber:get_ORBDefaultInitRef() of
- undefined ->
- true;
- DefRef ->
- DefRef++"/"++ObjectId
- end;
- InitRef ->
- case check_prefixes(InitRef, ObjectId) of
- false ->
- case orber:get_ORBDefaultInitRef() of
- undefined ->
- true;
- DefRef ->
- DefRef++"/"++ObjectId
- end;
- UseRef ->
- strip_junk(UseRef)
- end
- end.
-
-
-check_prefixes([], _) ->
- false;
-%% A list of ORBInitRef's
-check_prefixes([H|T], ObjectId) when is_list(H) ->
- case prefix(ObjectId, H) of
- false ->
- check_prefixes(T, ObjectId);
- UseRef ->
- UseRef
- end;
-%% A single ORBInitRef
-check_prefixes(InitRef, ObjectId) when is_list(InitRef) ->
- case prefix(ObjectId, InitRef) of
- false ->
- false;
- UseRef ->
- UseRef
- end;
-check_prefixes(What,_) ->
- orber:dbg("[~p] corba:check_prefixes(~p);~nMalformed argument?",
- [?LINE, What], ?DEBUG_LEVEL),
- raise(#'BAD_PARAM'{completion_status = ?COMPLETED_NO}).
-
-
-%% Valid is, for example, "NameService = corbaloc::host/NameService".
-%% Hence, we must remove ' ' and '='.
-strip_junk([32|T]) ->
- strip_junk(T);
-strip_junk([$=|T]) ->
- strip_junk(T);
-strip_junk(Ref) ->
- Ref.
-
-add_initial_service(ObjectId, ObjectRef) ->
- orber_initial_references:add(ObjectId, ObjectRef).
-
-remove_initial_service(ObjectId) ->
- orber_initial_references:remove(ObjectId).
-
-resolve_initial_references_remote(ObjectId, Address) ->
- resolve_initial_references_remote(ObjectId, Address, []).
-
-resolve_initial_references_remote(_ObjectId, [], _Ctx) ->
- raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO});
-resolve_initial_references_remote(ObjectId, [RemoteModifier| Rest], Ctx)
- when is_list(RemoteModifier) ->
- case parse_remote_modifier(RemoteModifier) of
- {error, _} ->
- resolve_initial_references_remote(ObjectId, Rest, Ctx);
- {ok, Host, Port} ->
- IOR = iop_ior:create_external(orber:giop_version(), "",
- Host, list_to_integer(Port), "INIT"),
- %% We know it's an external referens. Hence, no need to check.
- {_, Key} = iop_ior:get_key(IOR),
- orber_iiop:request(Key, 'get', [ObjectId],
- {{'tk_objref', 12, "object"},
- [{'tk_string', 0}],
- []}, 'true', infinity, IOR, Ctx)
- end.
-
-list_initial_services_remote(Address) ->
- list_initial_services_remote(Address, []).
-
-list_initial_services_remote([], _Ctx) ->
- raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO});
-list_initial_services_remote([RemoteModifier| Rest], Ctx) when is_list(RemoteModifier) ->
- case parse_remote_modifier(RemoteModifier) of
- {error, _} ->
- resolve_initial_references_remote(Rest, Ctx);
- {ok, Host, Port} ->
- IOR = iop_ior:create_external(orber:giop_version(), "",
- Host, list_to_integer(Port), "INIT"),
- %% We know it's an external referens. Hence, no need to check.
- {_, Key} = iop_ior:get_key(IOR),
- orber_iiop:request(Key, 'list', [],
- {{'tk_sequence', {'tk_string',0},0},
- [], []}, 'true', infinity, IOR, Ctx)
- end;
-list_initial_services_remote(_, _) ->
- raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-
-parse_remote_modifier("iiop://" ++ Rest) ->
- parse_host_version(Rest);
-parse_remote_modifier(_RemoteModifier) ->
- {error, not_supported}.
-
-parse_host_version("[" ++ Rest) ->
- parse_ipv6(Rest, []);
-parse_host_version(Rest) ->
- parse_ipv4_or_dnsname(Rest, []).
-
-
-parse_ipv4_or_dnsname([$: |Rest], Acc) ->
- {ok, lists:reverse(Acc), Rest};
-parse_ipv4_or_dnsname([C |Rest], Acc) ->
- parse_ipv4_or_dnsname(Rest, [C |Acc]).
-
-parse_ipv6("]:" ++ Rest, Acc) ->
- {ok, lists:reverse(Acc), Rest};
-parse_ipv6([C |Rest], Acc) ->
- parse_ipv6(Rest, [C |Acc]).
-
-
-%%-----------------------------------------------------------------
-%% Objectreference convertions
-%%-----------------------------------------------------------------
-object_to_string(Object) ->
- iop_ior:string_code(Object).
-
-object_to_string(Object, [H|_] = Hosts) when is_list(H) ->
- iop_ior:string_code(Object, Hosts);
-object_to_string(_Object, _Hosts) ->
- raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-object_to_string(Object, [H|_] = Hosts, Port) when is_list(H) andalso
- is_integer(Port) ->
- iop_ior:string_code(Object, Hosts, Port);
-object_to_string(_Object, _Hosts, _Port) ->
- raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-object_to_string(Object, [H|_] = Hosts, Port, SSLPort) when is_list(H) andalso
- is_integer(Port) andalso
- is_integer(SSLPort)->
- iop_ior:string_code(Object, Hosts, Port, SSLPort);
-object_to_string(_Object, _Hosts, _Port, _SSLPort) ->
- raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-
-string_to_object(IORString) ->
- string_to_object(IORString, []).
-
-string_to_object(IORString, Ctx) when is_list(Ctx) ->
- case lists:prefix("IOR", IORString) of
- true ->
- {ObjRef, _, _} = iop_ior:string_decode(IORString),
- ObjRef;
- _ ->
- %% CORBA-2.4 allows both IOR and ior prefix.
- case lists:prefix("ior", IORString) of
- true ->
- {ObjRef, _, _} = iop_ior:string_decode(IORString),
- ObjRef;
- _ ->
- Data = orber_cosnaming_utils:select_type(IORString),
- case orber_cosnaming_utils:lookup(Data, Ctx) of
- String when is_list(String) ->
- {Obj, _, _} = iop_ior:string_decode(String),
- Obj;
- ObjRef ->
- ObjRef
- end
- end
- end;
-string_to_object(IORString, Ctx) ->
- orber:dbg("[~p] corba:string_to_object(~p, ~p);~n"
- "Failed to supply a context list.",
- [?LINE, IORString, Ctx], ?DEBUG_LEVEL),
- raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%------------------------------------------------------------
-%%
-%% Implementation of NON-standard functions
-%%
-%%------------------------------------------------------------
-create(Module, TypeID) ->
- create(Module, TypeID, []).
-
-create(Module, TypeID, Env) ->
- common_create(Module, TypeID, Env, [], 'start').
-
-create(Module, TypeID, Env, {Type, RegName}) ->
- common_create(Module, TypeID, Env, [{regname, {Type, RegName}}], 'start');
-create(Module, TypeID, Env, Options) ->
- common_create(Module, TypeID, Env, Options, 'start').
-
-
-create_link(Module, TypeID) ->
- create_link(Module, TypeID, []).
-
-create_link(Module, TypeID, Env) ->
- common_create(Module, TypeID, Env, [], 'start_link').
-
-create_link(Module, TypeID, Env, {Type, RegName}) ->
- common_create(Module, TypeID, Env, [{regname, {Type, RegName}}], 'start_link');
-create_link(Module, TypeID, Env, Options) ->
- common_create(Module, TypeID, Env, Options, 'start_link').
-
-
-create_remote(Node, Module, TypeID) ->
- create_remote(Node, Module, TypeID, []).
-
-create_remote(Node, Module, TypeID, Env) ->
- common_create_remote(Node, Module, TypeID, Env, [], 'start').
-
-create_remote(Node, Module, TypeID, Env, {Type, RegName}) ->
- common_create_remote(Node, Module, TypeID, Env, [{regname, {Type, RegName}}], 'start');
-create_remote(Node, Module, TypeID, Env, Options) ->
- common_create_remote(Node, Module, TypeID, Env, Options, 'start').
-
-
-create_link_remote(Node, Module, TypeID) ->
- create_link_remote(Node, Module, TypeID, []).
-
-create_link_remote(Node, Module, TypeID, Env) ->
- common_create_remote(Node, Module, TypeID, Env, [], 'start_link').
-
-create_link_remote(Node, Module, TypeID, Env, {Type, RegName}) ->
- common_create_remote(Node, Module, TypeID, Env, [{regname, {Type, RegName}}], 'start_link');
-create_link_remote(Node, Module, TypeID, Env, Options) ->
- common_create_remote(Node, Module, TypeID, Env, Options, 'start_link').
-
-common_create_remote(Node, Module, TypeID, Env, {Type, RegName}, StartMethod) ->
- common_create_remote(Node, Module, TypeID, Env, [{regname, {Type, RegName}}], StartMethod);
-common_create_remote(Node, Module, TypeID, Env, Options, StartMethod) ->
- case node_check(Node) of
- true ->
- rpc:call(Node, corba, common_create, [Module, TypeID, Env, Options, StartMethod]);
- _ ->
- orber:dbg("[~p] corba:common_create_remote(~p);~n"
- "Node not in current domain.", [?LINE, Node], ?DEBUG_LEVEL),
- raise(#'OBJ_ADAPTER'{completion_status=?COMPLETED_NO})
- end.
-
-node_check(Node) ->
- lists:member(Node,orber:orber_nodes()).
-
-common_create(Module, _TypeID, Env, Options, StartMethod) when is_list(Options) ->
- Opt = evaluate_options(Options, #options{}),
- case Opt#options.regname of
- [] ->
- ok;
- {'local', Atom} when is_atom(Atom) andalso Opt#options.persistent == false ->
- ok;
- {'global', _} ->
- ok;
- Why ->
- orber:dbg("[~p] corba:common_create(~p, ~p);~n"
- "Bad name type or combination(~p).",
- [?LINE, Module, Options, Why], ?DEBUG_LEVEL),
- raise(#'BAD_PARAM'{minor=(?ORBER_VMCID bor 1),
- completion_status=?COMPLETED_NO})
- end,
- case Opt of
- #options{pseudo = false, passive = false} ->
- case gen_server:StartMethod(Module, {Opt#options.object_flags, Env},
- Opt#options.create_options) of
- {ok, Pid} ->
- case catch mk_objkey(Module, Pid, Opt#options.regname,
- Opt#options.persistent,
- Opt#options.object_flags) of
- {'EXCEPTION', E} ->
- %% This branch is only used if we couldn't register
- %% our new objectkey due to an internal error in orber.
- gen_server:call(Pid, stop),
- raise(E);
- {'EXIT', _} ->
- %% This branch takes care of exit values
- %% which aren't expected (due to bug).
- gen_server:call(Pid, stop),
- raise(#'BAD_PARAM'{minor=(?ORBER_VMCID bor 1),
- completion_status=?COMPLETED_NO});
- Objkey when Opt#options.sup_child == true ->
- {ok, Pid, Objkey};
- Objkey ->
- Objkey
- end;
- X ->
- X
- end;
- #options{pseudo = true, passive = false} ->
- ModuleImpl = list_to_atom(lists:concat([Module, '_impl'])),
- case ModuleImpl:init(Env) of
- {ok, State} ->
- create_subobject_key(mk_pseudo_objkey(Module, ModuleImpl,
- Opt#options.object_flags),
- State);
- {ok, State,_} ->
- create_subobject_key(mk_pseudo_objkey(Module, ModuleImpl,
- Opt#options.object_flags),
- State);
- Reason ->
- orber:dbg("[~p] corba:common_create(~p);~n"
- "'init' function incorrect(~p).",
- [?LINE, ModuleImpl, Reason], ?DEBUG_LEVEL),
- raise(#'BAD_PARAM'{minor=(?ORBER_VMCID bor 1),
- completion_status=?COMPLETED_NO})
- end;
- #options{pseudo = false, passive = true} ->
- ModuleImpl = list_to_atom(lists:concat([Module, '_impl'])),
- create_subobject_key(mk_passive_objkey(Module, ModuleImpl,
- Opt#options.object_flags),
- ?groupid_to_table(Opt#options.group_id));
- What ->
- orber:dbg("[~p] corba:common_create(~p, ~p);~n"
- "not a boolean(~p).",
- [?LINE, Module, Options, What], ?DEBUG_LEVEL),
- raise(#'BAD_PARAM'{minor=(?ORBER_VMCID bor 1),
- completion_status=?COMPLETED_NO})
- end.
-
-%%----------------------------------------------------------------------
-%% Function : dispose
-%% Arguments : Object
-%% Returns :
-%% Description: Terminate the object represented by the supplied reference.
-%%----------------------------------------------------------------------
-dispose(?ORBER_NIL_OBJREF) ->
- ok;
-dispose(Obj) ->
- corba_boa:dispose(Obj).
-
-%%----------------------------------------------------------------------
-%% Function : create_nil_objref
-%% Arguments : -
-%% Returns : A NIL object reference
-%% Description:
-%%----------------------------------------------------------------------
-create_nil_objref() ->
- ?ORBER_NIL_OBJREF.
-
-%%----------------------------------------------------------------------
-%% Function : create_subobject_key
-%% Arguments : A local object reference and an Erlang term().
-%% Returns : A new instance of the supplied reference with the
-%% sub-object field changed to the given value.
-%% Description: Initially, this field is set to 'undefined'
-%%----------------------------------------------------------------------
-create_subobject_key(Objkey, B) when is_binary(B) ->
- iop_ior:set_privfield(Objkey, B);
-create_subobject_key(Objkey, T) ->
- create_subobject_key(Objkey, term_to_binary(T)).
-
-%%----------------------------------------------------------------------
-%% Function : get_subobject_key
-%% Arguments : A local object reference
-%% Returns : Erlang term().
-%% Description: Return the value set by using create_subobject_key/2
-%%----------------------------------------------------------------------
-get_subobject_key(Objkey) ->
- iop_ior:get_privfield(Objkey).
-
-%%----------------------------------------------------------------------
-%% Function : get_pid
-%% Arguments : A local object reference
-%% Returns : If the object is local and is associated with a pid, this
-%% pid is returned. Otherwise, external- or pseudo-object,
-%% an exception is raised.
-%% Description:
-%%----------------------------------------------------------------------
-get_pid(Objkey) ->
- case iop_ior:get_key(Objkey) of
- {'internal', Key, _, _, _} ->
- orber_objectkeys:get_pid(Key);
- {'internal_registered', Key, _, _, _} when is_atom(Key) ->
- case whereis(Key) of
- undefined ->
- raise(#'OBJECT_NOT_EXIST'{completion_status=?COMPLETED_NO});
- Pid ->
- Pid
- end;
- R ->
- orber:dbg("[~p] corba:get_pid(~p);~n"
- "Probably a pseudo- or external object(~p).",
- [?LINE, Objkey, R], ?DEBUG_LEVEL),
- raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO})
- end.
-
-%%----------------------------------------------------------------------
-%% Function : raise
-%% Arguments : Local exception representation.
-%% Returns : Throws the exception.
-%% Description:
-%%----------------------------------------------------------------------
-%% To avoid dialyzer warnings due to the use of exit/throw.
--spec raise(term()) -> no_return().
-raise(E) ->
- throw({'EXCEPTION', E}).
-
-%%----------------------------------------------------------------------
-%% Function : raise_with_state
-%% Arguments : Local exception representation.
-%% Returns : Throws the exception.
-%% Description:
-%%----------------------------------------------------------------------
-%% To avoid dialyzer warnings due to the use of exit/throw.
--spec raise_with_state(term(), term()) -> no_return().
-raise_with_state(E, State) ->
- throw({reply, {'EXCEPTION', E}, State}).
-
-%%----------------------------------------------------------------------
-%% Function : reply
-%% Arguments : To - pid
-%% Reply - Erlang term().
-%% Returns :
-%% Description: Used to reply to the invoker but still be able
-%% to do some more work in the callback module.
-%%----------------------------------------------------------------------
-reply(To, Reply) ->
- gen_server:reply(To, Reply).
-
-%%----------------------------------------------------------------------
-%% Function : print_object
-%% Arguments : An object represented as one of the following:
-%% - local (tuple)
-%% - IOR
-%% - stringified IOR
-%% - corbaloc- or corbaname-schema
-%% IoDevice - the same as the io-module defines.
-%% Returns :
-%% Description: Prints the object's components and profiles.
-%%----------------------------------------------------------------------
-print_object(Object) ->
- iop_ior:print(Object).
-print_object(Object, IoDevice) ->
- iop_ior:print(IoDevice, Object).
-
-%%----------------------------------------------------------------------
-%% Function : add_alternate_iiop_address
-%% Arguments : Local object (tuple or IOR).
-%% IP - IP-string
-%% Port - integer().
-%% Returns : A local IOR with a TAG_ALTERNATE_IIOP_ADDRESS component.
-%% Description:
-%%----------------------------------------------------------------------
-add_alternate_iiop_address(Obj, Host, Port) when is_list(Host) andalso is_integer(Port) ->
- TC = #'IOP_TaggedComponent'{tag = ?TAG_ALTERNATE_IIOP_ADDRESS,
- component_data = #'ALTERNATE_IIOP_ADDRESS'{
- 'HostID' = Host,
- 'Port' = Port}},
- iop_ior:add_component(Obj, TC);
-add_alternate_iiop_address(_, Host, Port) ->
- orber:dbg("[~p] corba:add_alternate_iiop_address(~p, ~p);~n"
- "Incorrect argument(s). Host must be IP-string and Port an integer.",
- [?LINE, Host, Port], ?DEBUG_LEVEL),
- raise(#'BAD_PARAM'{completion_status = ?COMPLETED_NO}).
-
-
-%%----------------------------------------------------------------------
-%% Function : add_FTGroup_component
-%% Arguments : Local object (tuple or IOR).
-%% FTDomain - FT Domain. String().
-%% GroupID - Replicated object group's id. Integer(). (ulonglong)
-%% GroupVer - Object group's version number. Integer(). (ulong)
-%% Returns : A local IOR with one TAG_FT_GROUP component.
-%% Description:
-%%----------------------------------------------------------------------
-add_FTGroup_component(Obj, FTDomain, GroupID, GroupVer)
- when is_list(FTDomain) andalso is_integer(GroupID) andalso is_integer(GroupVer) andalso
- GroupID >= ?ULONGLONGMIN andalso GroupID =< ?ULONGLONGMAX andalso
- GroupVer >= ?ULONGMIN andalso GroupVer =< ?ULONGMAX ->
- TC = #'IOP_TaggedComponent'{tag = ?TAG_FT_GROUP,
- component_data = #'FT_TagFTGroupTaggedComponent'{
- version = #'GIOP_Version'{major = 1, minor = 0},
- ft_domain_id = FTDomain,
- object_group_id = GroupID,
- object_group_ref_version = GroupVer}},
- iop_ior:add_component(Obj, TC);
-add_FTGroup_component(_Obj, FTDomain, GroupID, GroupVer) ->
- orber:dbg("[~p] corba:add_FTGroup_component(~p, ~p, ~p);~n"
- "Incorrect argument(s).",
- [?LINE, FTDomain, GroupID, GroupVer], ?DEBUG_LEVEL),
- raise(#'BAD_PARAM'{completion_status = ?COMPLETED_NO}).
-
-
-%%----------------------------------------------------------------------
-%% Function : add_FTPrimary_component
-%% Arguments : Local object (tuple or IOR).
-%% Returns : A local IOR with one TAG_FT_PRIMARY component.
-%% Description:
-%%----------------------------------------------------------------------
-add_FTPrimary_component(Obj) ->
- TC = #'IOP_TaggedComponent'{
- tag=?TAG_FT_PRIMARY,
- component_data=#'FT_TagFTPrimaryTaggedComponent'{primary = true}},
- iop_ior:add_component(Obj, TC).
-
-
-%%-----------------------------------------------------------------
-%% Generic functions for accessing the call-back modules (i.e. X_impl.erl).
-%% These functions are invoked by the generated stubs.
-%%-----------------------------------------------------------------
-handle_init(M, {Flags, Env}) ->
- case M:init(Env) of
- {ok, State} ->
- {ok, {#is{flags = Flags}, State}};
- {ok,State,Timeout} ->
- {ok, {#is{flags = Flags}, State}, Timeout};
- Other ->
- %% E.g. ignore | {stop, Reason}
- Other
- end.
-
-
-handle_terminate(M, Reason, {_InternalState, State}) ->
- catch (M:terminate(Reason, State)).
-
-handle_info(M, Info, {InternalState, State}) ->
- case catch M:handle_info(Info, State) of
- {noreply,NewState} ->
- {noreply, {InternalState, NewState}};
- {noreply, NewState, Timeout} ->
- {noreply, {InternalState, NewState}, Timeout};
- {stop, Reason, NewState} ->
- {stop, Reason, {InternalState, NewState}};
- {'EXIT', Why} ->
- handle_exit(InternalState, State, Why, true,
- {M, handle_info}, [Info, State])
- end.
-
-handle_code_change(M, OldVsn, {InternalState, State}, Extra) ->
- {ok, NewState} = M:code_change(OldVsn, State, Extra),
- {ok, {InternalState, NewState}}.
-
-
-%% This function handles call Pre- & Post-conditions.
-handle_call(M, F, A, {InternalState, State}, Ctx, This, From,
- PreData, PostData, Stub) ->
- CArgs = call_state(A, State, This, From),
- case catch invoke_precond(PreData, Stub, F, CArgs) of
- {'EXIT', Why} ->
- handle_exit(InternalState, State, Why, false, PreData, [Stub, F, CArgs]);
- {'EXCEPTION', E} ->
- {reply, {'EXCEPTION', E}, {InternalState, State}};
- ok ->
- Result = handle_call2(M, F, CArgs, InternalState, State, Ctx),
- case catch invoke_postcond(PostData, Stub, F, CArgs, Result) of
- {'EXIT', Why} ->
- handle_exit(InternalState, State, Why, false, PostData, A);
- {'EXCEPTION', E} ->
- {reply, {'EXCEPTION', E}, {InternalState, State}};
- ok ->
- Result
- end
- end.
-
-
-invoke_precond(false, _, _, _) ->
- ok;
-invoke_precond({CondM, CondF}, Stub, F, CArgs) ->
- CondM:CondF(Stub, F, CArgs).
-
-%% We must remove the Internal State before invoking post-cond.
-invoke_postcond(false, _, _, _, _) ->
- ok;
-invoke_postcond({CondM, CondF}, Stub, F, CArgs, {reply, Reply, {_, NS}}) ->
- CondM:CondF(Stub, F, CArgs, {reply, Reply, NS});
-invoke_postcond({CondM, CondF}, Stub, F, CArgs, {reply, Reply, {_, NS}, Timeout}) ->
- CondM:CondF(Stub, F, CArgs, {reply, Reply, NS, Timeout});
-invoke_postcond({CondM, CondF}, Stub, F, CArgs, {stop, Reason, Reply, {_, NS}}) ->
- CondM:CondF(Stub, F, CArgs, {stop, Reason, Reply, NS});
-invoke_postcond({CondM, CondF}, Stub, F, CArgs, {stop, Reason, {_, NS}}) ->
- CondM:CondF(Stub, F, CArgs, {stop, Reason, NS});
-invoke_postcond({CondM, CondF}, Stub, F, CArgs, {noreply,{_, NS}}) ->
- CondM:CondF(Stub, F, CArgs, {noreply,NS});
-invoke_postcond({CondM, CondF}, Stub, F, CArgs, {noreply,{_, NS}, Timeout}) ->
- CondM:CondF(Stub, F, CArgs, {noreply, NS, Timeout});
-invoke_postcond({CondM, CondF}, Stub, F, CArgs, Result) ->
- CondM:CondF(Stub, F, CArgs, Result).
-
-
-handle_call(M, F, A, {InternalState, State}, Ctx, This, From) ->
- handle_call2(M, F, call_state(A, State, This, From), InternalState, State, Ctx).
-
-handle_call2(M, F, A, InternalState, State, []) ->
- case catch apply(M, F, A) of
- {reply, Reply, NewState} ->
- {reply, add_context(Reply), {InternalState, NewState}};
- {reply, Reply, NewState, Timeout} ->
- {reply, add_context(Reply), {InternalState, NewState}, Timeout};
- {stop, Reason, Reply, NewState} ->
- {stop, Reason, add_context(Reply), {InternalState, NewState}};
- {stop, Reason, NewState} ->
- {stop, Reason, {InternalState, NewState}};
- {noreply,NewState} ->
- {noreply,{InternalState, NewState}};
- {noreply,NewState,Timeout} ->
- {noreply,{InternalState, NewState},Timeout};
- {'EXIT', Reason} ->
- handle_exit(InternalState, State, Reason, false, {M, F}, A);
- {'EXCEPTION', E} ->
- {reply, add_context({'EXCEPTION', E}), {InternalState, State}};
- {Reply, NewState} ->
- {reply, add_context(Reply), {InternalState, NewState}}
- end;
-handle_call2(M, F, A, InternalState, State, Ctx) ->
- %% Set the new Context.
- put(oe_server_in_context, Ctx),
- case catch apply(M, F, A) of
- {reply, Reply, NewState} ->
- put(oe_server_in_context, undefined),
- {reply, add_context(Reply), {InternalState, NewState}};
- {reply, Reply, NewState, Timeout} ->
- put(oe_server_in_context, undefined),
- {reply, add_context(Reply), {InternalState, NewState}, Timeout};
- {stop, Reason, Reply, NewState} ->
- {stop, Reason, add_context(Reply), {InternalState, NewState}};
- {stop, Reason, NewState} ->
- {stop, Reason, {InternalState, NewState}};
- {noreply,NewState} ->
- put(oe_server_in_context, undefined),
- {noreply, {InternalState, NewState}};
- {noreply, {InternalState, NewState}, Timeout} ->
- put(oe_server_in_context, undefined),
- {noreply, {InternalState, NewState},Timeout};
- {'EXIT', Reason} ->
- handle_exit(InternalState, State, Reason, false, {M, F}, A);
- {'EXCEPTION', E} ->
- put(oe_server_in_context, undefined),
- {reply, add_context({'EXCEPTION', E}), {InternalState, State}};
- {Reply, NewState} ->
- put(oe_server_in_context, undefined),
- {reply, add_context(Reply), {InternalState, NewState}}
- end.
-
-call_state(A, State, false, false) ->
- [State|A];
-call_state(A, State, false, From) ->
- [From, State|A];
-call_state(A, State, This, false) ->
- [This, State|A];
-call_state(A, State, This, From) ->
- [This, From, State|A].
-
-cast_state(A, State, false) ->
- [State|A];
-cast_state(A, State, This) ->
- [This, State|A].
-
-add_context(Reply) ->
- %% Reset oe_server_out_context
- case put(oe_server_out_context, undefined) of
- undefined ->
- Reply;
- _OutCtx ->
- %% The previous value wasn't 'undefined', which means that
- %% the server supplied a return context.
- Reply
- end.
-
-
-%% This function handles call Pre- & Post-conditions.
-handle_cast(M, F, A, {InternalState, State}, Ctx, This, PreData, PostData, Stub) ->
- CArgs = cast_state(A, State, This),
- case catch invoke_precond(PreData, Stub, F, CArgs) of
- {'EXIT', Why} ->
- handle_exit(InternalState, State, Why, true, PreData, [Stub, F, CArgs]);
- {'EXCEPTION', _} ->
- {noreply, {InternalState, State}};
- ok ->
- Result = handle_cast2(M, F, CArgs, InternalState, State, Ctx),
- case catch invoke_postcond(PostData, Stub, F, CArgs, Result) of
- {'EXIT', Why} ->
- handle_exit(InternalState, State, Why, true, PostData, A);
- {'EXCEPTION', _} ->
- {noreply, {InternalState, State}};
- ok ->
- Result
- end
- end.
-
-
-handle_cast(M, F, A, {InternalState, State}, Ctx, This) ->
- handle_cast2(M, F, cast_state(A, State, This), InternalState, State, Ctx).
-
-handle_cast2(M, F, A, InternalState, State, []) ->
- case catch apply(M, F, A) of
- {noreply, NewState} ->
- {noreply, {InternalState, NewState}};
- {noreply, NewState, Timeout} ->
- {noreply, {InternalState, NewState}, Timeout};
- {stop, Reason, NewState} ->
- {stop, Reason, {InternalState, NewState}};
- {'EXCEPTION', _} ->
- {noreply, {InternalState, State}};
- {'EXIT', Reason} ->
- handle_exit(InternalState, State, Reason, true, {M, F}, A);
- NewState ->
- {noreply, {InternalState, NewState}}
- end;
-handle_cast2(M, F, A, InternalState, State, Ctx) ->
- put(oe_server_in_context, Ctx),
- case catch apply(M, F, A) of
- {noreply, NewState} ->
- put(oe_server_in_context, undefined),
- {noreply, {InternalState, NewState}};
- {noreply, NewState, Timeout} ->
- put(oe_server_in_context, undefined),
- {noreply, {InternalState, NewState}, Timeout};
- {stop, Reason, NewState} ->
- {stop, Reason, {InternalState, NewState}};
- {'EXCEPTION', _} ->
- put(oe_server_in_context, undefined),
- {noreply, {InternalState, State}};
- {'EXIT', Reason} ->
- handle_exit(InternalState, State, Reason, true, {M, F}, A);
- NewState ->
- put(oe_server_in_context, undefined),
- {noreply, {InternalState, NewState}}
- end.
-
-handle_exit(InternalState, State, {undef, [{M, F, _, _}|_]} = Reason,
- OnewayOp, {M, F}, A) ->
- case catch check_exports(M:module_info(exports), F) of
- {'EXIT',{undef,_}} ->
- %% No such module.
- orber:dbg("~p.beam doesn't exist.~n"
- "Check IC compile options (e.g. 'impl') and that the~n"
- "beam-file is load-able.",
- [M], ?DEBUG_LEVEL),
- reply_after_exit(InternalState, State, Reason, OnewayOp,
- #'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 1),
- completion_status=?COMPLETED_MAYBE});
- "" ->
- orber:dbg("~p:~p/~p doesn't exist.~n"
- "Check spelling, export-attributes etc",
- [M, F, length(A)], ?DEBUG_LEVEL),
- reply_after_exit(InternalState, State, Reason, OnewayOp,
- #'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 2),
- completion_status=?COMPLETED_MAYBE});
- Exports when is_list(Exports) ->
- orber:dbg("~p:~p/~p doesn't exist.~n"
- "~p:~p~s do exists.~nCheck export-attributes etc",
- [M, F, length(A), M, F, Exports], ?DEBUG_LEVEL),
- reply_after_exit(InternalState, State, Reason, OnewayOp,
- #'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 3),
- completion_status=?COMPLETED_MAYBE});
- _ ->
- %% Should never happen
- reply_after_exit(InternalState, State, Reason, OnewayOp,
- #'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 4),
- completion_status=?COMPLETED_MAYBE})
- end;
-handle_exit(InternalState, State, {undef, [{M2, F2, A2, _}|_]} = Reason,
- OnewayOp, {M, F}, A) ->
- case catch check_exports(M2:module_info(exports), F2) of
- {'EXIT',{undef,_}} ->
- %% No such module.
- orber:dbg("~p.beam doesn't exist.~n"
- "~p:~p/~p invoked an operation on the module above.~n"
- "Check IC compile options and that the beam-file is load-able.",
- [M2, M, F, length(A)], ?DEBUG_LEVEL),
- reply_after_exit(InternalState, State, Reason, OnewayOp,
- #'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 5),
- completion_status=?COMPLETED_MAYBE});
- "" ->
- orber:dbg("~p:~p/~p doesn't exist.~n"
- "~p:~p/~p invoked the operation above~n"
- "Check spelling, export-attributes etc",
- [M2, F2, length(A2), M, F, length(A)], ?DEBUG_LEVEL),
- reply_after_exit(InternalState, State, Reason, OnewayOp,
- #'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 6),
- completion_status=?COMPLETED_MAYBE});
- Exports when is_list(Exports) ->
- orber:dbg("~p:~p/~p doesn't exist.~n"
- "~p:~p~s do exist(s).~nCheck export-attributes etc~n"
- "~p:~p/~p invoked the operation above~n",
- [M2, F2, length(A2), M2, F2, Exports, M, F, length(A)], ?DEBUG_LEVEL),
- reply_after_exit(InternalState, State, Reason, OnewayOp,
- #'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 7),
- completion_status=?COMPLETED_MAYBE});
- _ ->
- %% Should never happen
- reply_after_exit(InternalState, State, Reason, OnewayOp,
- #'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 4),
- completion_status=?COMPLETED_MAYBE})
- end;
-%% Misc errors. We separate between direct and in-direct errors. Due to different
-%% notation we must separate between different cases.
-handle_exit(InternalState, State, {{case_clause,_}, [{M, F, _}|_]} = Reason,
- OnewayOp, {M, F}, A) ->
- orber:dbg("~p:~p/~p contains a 'case_clause' error.",
- [M, F, length(A)], ?DEBUG_LEVEL),
- reply_after_exit(InternalState, State, Reason, OnewayOp,
- #'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 8),
- completion_status=?COMPLETED_MAYBE});
-handle_exit(InternalState, State, {Reason, [{M, F, _}|_]}, OnewayOp, {M, F}, A) ->
- orber:dbg("~p:~p/~p contains a '~p' error.",
- [M, F, length(A), Reason], ?DEBUG_LEVEL),
- reply_after_exit(InternalState, State, Reason, OnewayOp,
- #'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 8),
- completion_status=?COMPLETED_MAYBE});
-handle_exit(InternalState, State, {function_clause, [{M2, F2, A2}|_]} = Reason,
- OnewayOp, {M, F}, A) ->
- orber:dbg("~p:~p/~p contains a 'function_clause' error.~n"
- "Invoked via the operation:~n"
- "~p:~p/~p",
- [M2, F2, length(A2), M, F, length(A)], ?DEBUG_LEVEL),
- reply_after_exit(InternalState, State, Reason, OnewayOp,
- #'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 9),
- completion_status=?COMPLETED_MAYBE});
-handle_exit(InternalState, State, {{case_clause,_}, [{M2, F2, A2}|_]} = Reason,
- OnewayOp, {M, F}, A) ->
- orber:dbg("~p:~p/~p contains a 'case_clause' error.~n"
- "Invoked via the operation:~n"
- "~p:~p/~p",
- [M2, F2, A2, M, F, length(A)], ?DEBUG_LEVEL),
- reply_after_exit(InternalState, State, Reason, OnewayOp,
- #'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 9),
- completion_status=?COMPLETED_MAYBE});
-handle_exit(InternalState, State, {Reason, [{M2, F2, A2}|_]} = Reason,
- OnewayOp, {M, F}, A) ->
- orber:dbg("~p:~p/~p contains a '~p' error.~n"
- "Invoked via the operation:~n"
- "~p:~p/~p",
- [M2, F2, A2, Reason, M, F, length(A)], ?DEBUG_LEVEL),
- reply_after_exit(InternalState, State, Reason, OnewayOp,
- #'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 9),
- completion_status=?COMPLETED_MAYBE});
-handle_exit(InternalState, State, Reason, OnewayOp, {M, F}, A) ->
- orber:dbg("~p:~p(~p) ->~n"
- " {EXIT, ~p}~n",
- [M, F, A, Reason], ?DEBUG_LEVEL),
- reply_after_exit(InternalState, State, Reason, OnewayOp,
- #'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 10),
- completion_status=?COMPLETED_MAYBE}).
-
-
-reply_after_exit(#is{flags = Flags} = InternalState, State,
- Reason, OnewayOp, Exc) ->
- case ?ORB_FLAG_TEST(Flags, ?ORB_SURVIVE_EXIT) of
- false ->
- exit(Reason);
- true when OnewayOp == false ->
- put(oe_server_in_context, undefined),
- {reply, {'EXCEPTION', Exc}, {InternalState, State}};
- true ->
- %% One-way operation. Cannot return exception.
- put(oe_server_in_context, undefined),
- {noreply, {InternalState, State}}
- end.
-
-
-check_exports(Exports, Op) ->
- check_exports(Exports, Op, []).
-
-check_exports([], _, Acc) ->
- Acc;
-check_exports([{Op, Arity}|Rest], Op, Acc) ->
- check_exports(Rest, Op, Acc ++ "/" ++ integer_to_list(Arity));
-check_exports([_|Rest], Op, Acc) ->
- check_exports(Rest, Op, Acc).
-
-
-%%-----------------------------------------------------------------
-%% Corba:call - the function for reqests
-%%-----------------------------------------------------------------
-call(Obj, Func, Args, TypesOrMod) ->
- call_helper(Obj, Func, Args, TypesOrMod, infinity, []).
-
-call(Obj, Func, Args, TypesOrMod, [{context, Ctx}]) ->
- call_helper(Obj, Func, Args, TypesOrMod, infinity, Ctx);
-call(Obj, Func, Args, TypesOrMod, [{timeout, Timeout}]) ->
- call_helper(Obj, Func, Args, TypesOrMod, Timeout, []);
-call(Obj, Func, Args, TypesOrMod, Extra) when is_list(Extra) ->
- ExtraData = extract_extra_data(Extra, #extra{}),
- call_helper(Obj, Func, Args, TypesOrMod, ExtraData#extra.timeout,
- ExtraData#extra.context);
-call(Obj, Func, Args, TypesOrMod, Timeout) ->
- call_helper(Obj, Func, Args, TypesOrMod, Timeout, []).
-
-call_helper(Obj, Func, Args, TypesOrMod, Timeout, InCtx) ->
- Ctx = get_implicit_context(InCtx),
- case iop_ior:get_key(Obj) of
- {'internal', Key, _, Flags, Mod} ->
- Pid = orber_objectkeys:get_pid(Key),
- call_internal(Pid, Obj, Func, Args, TypesOrMod,
- ?ORB_FLAG_TEST(Flags, ?ORB_TYPECHECK),
- ?ORB_FLAG_TEST(Flags, ?ORB_USE_PI), Mod, Timeout, Ctx);
- {'internal_registered', Key, _, Flags, Mod} ->
- call_internal(Key, Obj, Func, Args, TypesOrMod,
- ?ORB_FLAG_TEST(Flags, ?ORB_TYPECHECK),
- ?ORB_FLAG_TEST(Flags, ?ORB_USE_PI), Mod, Timeout, Ctx);
- {'external', Key} when is_atom(TypesOrMod) ->
- case catch TypesOrMod:oe_tc(Func) of
- {'EXIT', What} ->
- orber:dbg("[~p] corba:call_helper(~p);~n"
- "The call-back module does not exist or"
- " incorrect IC-version used.~nReason: ~p",
- [?LINE, TypesOrMod, What], ?DEBUG_LEVEL),
- raise(#'TRANSIENT'{minor=(?ORBER_VMCID bor 7),
- completion_status=?COMPLETED_NO});
- undefined ->
- raise(#'BAD_OPERATION'{minor = (?ORBER_VMCID bor 4),
- completion_status=?COMPLETED_NO});
- Types ->
- orber_iiop:request(Key, Func, Args, Types, 'true', Timeout, Obj, Ctx)
- end;
- {'external', Key} ->
- orber_iiop:request(Key, Func, Args, TypesOrMod, 'true', Timeout, Obj, Ctx)
- end.
-
-get_implicit_context([]) ->
- case get(oe_server_in_context) of
- undefined ->
- [];
- ImplCtx ->
- ImplCtx
- end;
-get_implicit_context(Ctx) ->
- case get(oe_server_in_context) of
- undefined ->
- Ctx;
- ImplCtx ->
- %% Both defined. An explicit interface context overrides
- %% an implicit.
- case check_for_interface_ctx(Ctx) of
- false ->
- ImplCtx;
- true ->
- remove_interface_ctx(ImplCtx, Ctx)
- end
- end.
-
-check_for_interface_ctx([]) ->
- false;
-check_for_interface_ctx([#'IOP_ServiceContext'
- {context_id=?ORBER_GENERIC_CTX_ID,
- context_data = {interface, _I}}|_]) ->
- true;
-check_for_interface_ctx([_|T]) ->
- check_for_interface_ctx(T).
-
-remove_interface_ctx([], Acc) ->
- Acc;
-remove_interface_ctx([#'IOP_ServiceContext'
- {context_id=?ORBER_GENERIC_CTX_ID,
- context_data = {interface, _I}}|T], Acc) ->
- remove_interface_ctx(T, Acc);
-remove_interface_ctx([H|T], Acc) ->
- remove_interface_ctx(T, [H|Acc]).
-
-
-extract_extra_data([], ED) ->
- ED;
-extract_extra_data([{context, Ctx}|T], ED) ->
- extract_extra_data(T, ED#extra{context = Ctx});
-extract_extra_data([{timeout, Timeout}|T], ED) ->
- extract_extra_data(T, ED#extra{timeout = Timeout}).
-
-call_internal(Pid, Obj, Func, Args, Types, Check, PI, Mod, Timeout, Ctx)
- when is_pid(Pid) andalso node(Pid) == node() ->
- invoke_pi_request(PI, Obj, Ctx, Func, Args),
- typecheck_request(Check, Args, Types, Func),
- case catch gen_server:call(Pid, {Obj, Ctx, Func, Args}, Timeout) of
- {'EXCEPTION', E} ->
- invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', E}),
- typecheck_reply(Check, {'EXCEPTION', E}, Mod, Func),
- raise(E);
- {'EXIT',{timeout, _}} ->
- Exc = #'TIMEOUT'{completion_status=?COMPLETED_MAYBE},
- invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', Exc}),
- raise(Exc);
- {'EXIT',R} ->
- orber:dbg("[~p] corba:call_internal(~p, ~p, ~p);~ncall exit(~p).",
- [?LINE, Func, Args, Types, R], ?DEBUG_LEVEL),
- Exc = #'TRANSIENT'{minor=(?ORBER_VMCID bor 4),
- completion_status=?COMPLETED_NO},
- invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', Exc}),
- raise(Exc);
- Res ->
- invoke_pi_reply(PI, Obj, Ctx, Func, Res),
- typecheck_reply(Check, Res, Types, Func),
- Res
- end;
-call_internal(Pid, Obj, Func, Args, Types, Check, PI,
- _Mod, Timeout, Ctx) when is_pid(Pid) ->
- typecheck_request(Check, Args, Types, Func),
- case catch rpc:call(node(Pid), corba, call_relay,
- [Pid, {Obj, Ctx, Func, Args}, Timeout]) of
- {'EXCEPTION', E} ->
- invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', E}),
- typecheck_reply(Check, {'EXCEPTION', E}, Types, Func),
- raise(E);
- {badrpc, {'EXIT',R}} ->
- orber:dbg("[~p] corba:call_internal(~p, ~p, ~p);~ncall exit(~p).",
- [?LINE, Func, Args, Types, R], ?DEBUG_LEVEL),
- Exc = #'TRANSIENT'{minor=(?ORBER_VMCID bor 3),
- completion_status=?COMPLETED_MAYBE},
- invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', Exc}),
- raise(Exc);
- {badrpc,nodedown} ->
- orber:dbg("[~p] corba:call_internal(~p, ~p, ~p);~nNode ~p down.",
- [?LINE, Func, Args, Types, node(Pid)], ?DEBUG_LEVEL),
- Exc = #'TRANSIENT'{minor=(?ORBER_VMCID bor 2),
- completion_status=?COMPLETED_NO},
- invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', Exc}),
- raise(Exc);
- {badrpc, Reason} ->
- orber:dbg("[~p] corba:call_internal(~p, ~p, ~p);~n"
- "Unable to invoke operation due to: ~p",
- [?LINE, Func, Args, Types, Reason], ?DEBUG_LEVEL),
- Exc = #'TRANSIENT'{minor=(?ORBER_VMCID bor 5),
- completion_status=?COMPLETED_MAYBE},
- invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', Exc}),
- raise(Exc);
- Res ->
- invoke_pi_reply(PI, Obj, Ctx, Func, Res),
- typecheck_reply(Check, Res, Types, Func),
- Res
- end;
-
-%% This case handles if the reference is created as a Pseudo object.
-%% Just call apply/3.
-call_internal({pseudo, Module}, Obj, Func, Args, Types, Check, PI,
- _Mod, _Timeout, Ctx) ->
- OldCtx = put(oe_server_in_context, Ctx),
- invoke_pi_request(PI, Obj, Ctx, Func, Args),
- typecheck_request(Check, Args, Types, Func),
- State = binary_to_term(get_subobject_key(Obj)),
- case catch apply(Module, Func, [Obj, State|Args]) of
- {noreply, _} ->
- put(oe_server_in_context, OldCtx),
- ok;
- {noreply, _, _} ->
- put(oe_server_in_context, OldCtx),
- ok;
- {reply, Reply, _} ->
- put(oe_server_in_context, OldCtx),
- invoke_pi_reply(PI, Obj, Ctx, Func, Reply),
- typecheck_reply(Check, Reply, Types, Func),
- Reply;
- {reply, Reply, _, _} ->
- put(oe_server_in_context, OldCtx),
- invoke_pi_reply(PI, Obj, Ctx, Func, Reply),
- typecheck_reply(Check, Reply, Types, Func),
- Reply;
- {stop, _, Reply, _} ->
- put(oe_server_in_context, OldCtx),
- invoke_pi_reply(PI, Obj, Ctx, Func, Reply),
- typecheck_reply(Check, Reply, Types, Func),
- Reply;
- {stop, _, _} ->
- put(oe_server_in_context, OldCtx),
- ok;
- {'EXCEPTION', E} ->
- put(oe_server_in_context, OldCtx),
- invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', E}),
- typecheck_reply(Check, {'EXCEPTION', E}, Types, Func),
- raise(E);
- {'EXIT', What} ->
- put(oe_server_in_context, OldCtx),
- orber:dbg("[~p] corba:call_internal(~p, ~p, ~p);~n"
- "Pseudo object exit(~p).",
- [?LINE, Func, Args, Types, What], ?DEBUG_LEVEL),
- Exc = #'TRANSIENT'{minor=(?ORBER_VMCID bor 4),
- completion_status=?COMPLETED_MAYBE},
- invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', Exc}),
- raise(Exc);
- Unknown ->
- put(oe_server_in_context, OldCtx),
- orber:dbg("[~p] corba:call_internal(~p, ~p, ~p);~n"
- "Pseudo object failed due to bad return value (~p).",
- [?LINE, Func, Args, Types, Unknown], ?DEBUG_LEVEL),
- Exc = #'TRANSIENT'{minor=(?ORBER_VMCID bor 6),
- completion_status=?COMPLETED_MAYBE},
- invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', Exc}),
- raise(Exc)
- end;
-call_internal({passive, Module}, Obj, Func, Args, Types, Check, PI,
- Mod, Timeout, Ctx) ->
- invoke_pi_request(PI, Obj, Ctx, Func, Args),
- typecheck_request(Check, Args, Types, Func),
- GroupID = binary_to_term(get_subobject_key(Obj)),
- Transaction =
- fun() ->
- ObjectGroup = read_object_group(GroupID),
- call_primary_protected(ObjectGroup, Module, Obj,
- Func, Args, GroupID,
- get_FTRequestCtx(Ctx))
- end,
- case mnesia:transaction(Transaction) of
- {atomic, Reply} ->
- %% this check should be inside transaction so that
- %% failing typecheck_reply would result in transaction
- %% abortion. Or not. call_internal(Registered...) does not
- %% cancel the state transition even if the result isn't type compliant.
- %% So, we do likewise.
- typecheck_reply(Check, Reply, Mod, Func),
- Reply;
- {aborted, {not_primary, Primary, _}} ->
- FTRequestCtx = mk_FTRequestCtx(10000000),
- case rpc:call(Primary, corba, call_internal,
- [{passive, Module}, Obj, Func, Args,
- Types, Check, PI, Mod, Timeout,
- [FTRequestCtx|Ctx]]) of
- {badrpc, Reason} ->
- orber:dbg("[~p] corba:call_passive(~p, ~p, ~p); ~n"
- " badrpc(~p).",
- [?LINE, Func, Args, Types, Reason],?DEBUG_LEVEL),
- raise(#'TRANSIENT'{minor=0,
- completion_status=?COMPLETED_MAYBE});
- %% one should keep trying request_duration_policy_value -time.
- {'EXCEPTION', E} ->
- invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', E}),
- raise(E);
- Reply ->
- %% is this typecheck_reply neccessary? The check is made
- %% on the remote node...
- invoke_pi_reply(PI, Obj, Ctx, Func, Reply),
- typecheck_reply(Check, Reply, Mod, Func),
- Reply
- %% generate RetentionID's and call Primary node with flag that tells
- %% the node not to escalate rpc call's to next node if the primary
- %% has changed again.
- %% raise({not_primary, Primary});
- end;
- {aborted, {throw, {'EXCEPTION', E}}} ->
- invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', E}),
- typecheck_reply(Check, {'EXCEPTION', E}, Mod, Func),
- raise(E);
- {aborted, {'EXIT', What}} ->
- orber:dbg("[~p] corba:call_passive(~p, ~p, ~p); " ++
- "Passive object exit(~p).",
- [?LINE, Func, Args, Types, What], ?DEBUG_LEVEL),
- Exc = #'TRANSIENT'{minor=(?ORBER_VMCID bor 4),
- completion_status=?COMPLETED_MAYBE},
- invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', Exc}),
- raise(Exc);
- {aborted, Unknown} ->
- orber:dbg("[~p] corba:call_passive(~p, ~p, ~p); " ++
- "Passive object failed due to bad return value (~p).",
- [?LINE, Func, Args, Types, Unknown], ?DEBUG_LEVEL),
- Exc = #'TRANSIENT'{minor=(?ORBER_VMCID bor 6),
- completion_status=?COMPLETED_MAYBE},
- invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', Exc}),
- raise(Exc)
- end;
-call_internal(Registered, Obj, Func, Args, Types, Check, PI,
- _Mod, Timeout, Ctx) when is_atom(Registered)->
- invoke_pi_request(PI, Obj, Ctx, Func, Args),
- typecheck_request(Check, Args, Types, Func),
- case whereis(Registered) of
- undefined ->
- Exc = #'OBJECT_NOT_EXIST'{completion_status=?COMPLETED_NO},
- invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', Exc}),
- raise(Exc);
- P ->
- case catch gen_server:call(P, {Obj, Ctx, Func, Args}, Timeout) of
- {'EXCEPTION', E} ->
- invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', E}),
- typecheck_reply(Check, {'EXCEPTION', E}, Types, Func),
- raise(E);
- {'EXIT',{timeout, _}} ->
- Exc = #'TIMEOUT'{completion_status=?COMPLETED_MAYBE},
- invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', Exc}),
- raise(Exc);
- {'EXIT',R} ->
- orber:dbg("[~p] corba:call_internal(~p, ~p, ~p).~n"
- "call exit(~p).",
- [?LINE, Func, Args, Types, R], ?DEBUG_LEVEL),
- Exc = #'TRANSIENT'{minor=(?ORBER_VMCID bor 5),
- completion_status=?COMPLETED_MAYBE},
- invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', Exc}),
- raise(Exc);
- Res ->
- invoke_pi_reply(PI, Obj, Ctx, Func, Res),
- typecheck_reply(Check, Res, Types, Func),
- Res
- end
- end.
-
-invoke_pi_request(false, _Obj, _Ctx, _Func, _Args) ->
- ok;
-invoke_pi_request(_, Obj, Ctx, Func, Args) ->
- case orber:get_cached_interceptors() of
- {native, PIs} ->
- orber_pi:out_request(PIs, Obj, Ctx, Func, "localhost", Args);
- _ ->
- ok
- end.
-
-invoke_pi_reply(false, _Obj, _Ctx, _Func, _Res) ->
- ok;
-invoke_pi_reply(_, Obj, Ctx, Func, Res) ->
- case orber:get_cached_interceptors() of
- {native, PIs} ->
- orber_pi:in_reply(PIs, Obj, Ctx, Func, "localhost", Res);
- _ ->
- ok
- end.
-
-typecheck_request(false, _, _, _) ->
- ok;
-typecheck_request(true, Args, Mod, Func) when is_atom(Mod) ->
- case catch Mod:oe_tc(Func) of
- undefined ->
- raise(#'BAD_OPERATION'{minor = (?ORBER_VMCID bor 4),
- completion_status=?COMPLETED_NO});
- {'EXIT', What} ->
- orber:dbg("[~p] corba:typecheck_request(~p, ~p, ~p);~n"
- "The call-back module does not exist or incorrect"
- "IC-version used.~nReason: ~p",
- [?LINE, Mod, Func, Args, What], ?DEBUG_LEVEL),
- raise(#'TRANSIENT'{minor=(?ORBER_VMCID bor 7),
- completion_status=?COMPLETED_NO});
- Types ->
- typecheck_request_helper(Types, Args, Mod, Func)
- end;
-typecheck_request(true, Args, Types, Func) ->
- typecheck_request_helper(Types, Args, Types, Func).
-
-typecheck_request_helper(Types, Args, Mod, Func) ->
- case catch cdr_encode:validate_request_body(
- #giop_env{version = {1,2}, tc = Types, parameters = Args,
- host = orber:host(), iiop_port = orber:iiop_port(),
- iiop_ssl_port = orber:iiop_ssl_port(),
- domain = orber:domain(),
- partial_security = orber:partial_security(),
- flags = orber:get_flags()}) of
- {'EXCEPTION', E} ->
- {_, TC, _} = Types,
- error_logger:error_msg("========= Orber Typecheck Request =========~n"
- "Invoked......: ~p:~p/~p~n"
- "Typecode.....: ~p~n"
- "Arguments....: ~p~n"
- "Result.......: ~p~n"
- "===========================================~n",
- [Mod, Func, length(TC), TC, Args, {'EXCEPTION', E}]),
- raise(E);
- {'EXIT',R} ->
- {_, TC, _} = Types,
- error_logger:error_msg("========= Orber Typecheck Request =========~n"
- "Invoked......: ~p:~p/~p~n"
- "Typecode.....: ~p~n"
- "Arguments....: ~p~n"
- "Result.......: ~p~n"
- "===========================================~n",
- [Mod, Func, length(TC), TC, Args, {'EXIT',R}]),
- raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE});
- _ ->
- ok
- end.
-
-typecheck_reply(true, Args, Mod, Func) when is_atom(Mod) ->
- case catch Mod:oe_tc(Func) of
- undefined ->
- raise(#'BAD_OPERATION'{minor = (?ORBER_VMCID bor 4),
- completion_status=?COMPLETED_NO});
- {'EXIT', What} ->
- orber:dbg("[~p] corba:typecheck_reply(~p, ~p, ~p);~n"
- "The call-back module does not exist or incorrect"
- " IC-version used.~nReason: ~p",
- [?LINE, Mod, Func, Args, What], ?DEBUG_LEVEL),
- raise(#'TRANSIENT'{minor=(?ORBER_VMCID bor 7),
- completion_status=?COMPLETED_NO});
- Types ->
- typecheck_reply_helper(Types, Args, Mod, Func)
- end;
-typecheck_reply(true, Args, Types, Func) ->
- typecheck_reply_helper(Types, Args, Types, Func);
-typecheck_reply(_, _, _, _) ->
- ok.
-
-typecheck_reply_helper(Types, Args, Mod, Func) ->
- case catch cdr_encode:validate_reply_body(
- #giop_env{version = {1,2}, tc = Types,
- host = orber:host(), iiop_port = orber:iiop_port(),
- iiop_ssl_port = orber:iiop_ssl_port(),
- domain = orber:domain(),
- partial_security = orber:partial_security(),
- flags = orber:get_flags()}, Args) of
- {'tk_except', ExcType, ExcTC, {'EXCEPTION', E}} ->
- {_, TC, _} = Types,
- error_logger:error_msg("========== Orber Typecheck Reply ==========~n"
- "Invoked........: ~p:~p/~p~n"
- "Exception Type.: ~p~n"
- "Typecode.......: ~p~n"
- "Raised.........: ~p~n"
- "Result.........: ~p~n"
- "===========================================~n",
- [Mod, Func, length(TC), ExcType, ExcTC, Args, {'EXCEPTION', E}]),
- raise(E);
- {'EXCEPTION', E} ->
- {RetType, TC, OutParams} = Types,
- error_logger:error_msg("========== Orber Typecheck Reply ==========~n"
- "Invoked......: ~p:~p/~p~n"
- "Typecode.....: ~p~n"
- "Reply........: ~p~n"
- "Result.......: ~p~n"
- "===========================================~n",
- [Mod, Func, length(TC), [RetType | OutParams], Args, {'EXCEPTION', E}]),
- raise(E);
- {'tk_except', ExcType, ExcTC, {'EXIT',R}} ->
- {_, TC, _} = Types,
- error_logger:error_msg("========== Orber Typecheck Reply ==========~n"
- "Invoked........: ~p:~p/~p~n"
- "Exception Type.: ~p~n"
- "Typecode.......: ~p~n"
- "Raised.........: ~p~n"
- "Result.........: ~p~n"
- "===========================================~n",
- [Mod, Func, length(TC), ExcType, ExcTC, Args, {'EXIT',R}]),
- raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE});
- {'EXIT',R} ->
- {RetType, TC, OutParams} = Types,
- error_logger:error_msg("========== Orber Typecheck Reply ==========~n"
- "Invoked........: ~p:~p/~p~n"
- "Typecode.......: ~p~n"
- "Reply..........: ~p~n"
- "Result.........: ~p~n"
- "===========================================~n",
- [Mod, Func, length(TC), [RetType | OutParams], Args, {'EXIT',R}]),
- raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE});
- _ ->
- ok
- end.
-
-call_relay(Pid, Data, Timeout) ->
- case whereis(orber_objkeyserver) of
- undefined ->
- raise(#'TRANSIENT'{minor=(?ORBER_VMCID bor 1), completion_status=?COMPLETED_MAYBE});
- _ ->
- case catch gen_server:call(Pid, Data, Timeout) of
- {'EXCEPTION', E} ->
- raise(E);
- {'EXIT',{timeout, _}} ->
- raise(#'TIMEOUT'{completion_status=?COMPLETED_MAYBE});
- {'EXIT',R} ->
- orber:dbg("[~p] corba:call_internal(~p);~n"
- "call exit(~p).", [?LINE, Data, R], ?DEBUG_LEVEL),
- exit(R);
- Res ->
- Res
- end
- end.
-
-%%-----------------------------------------------------------------
-%% Corba:cast - the function for ONEWAY requests
-%%-----------------------------------------------------------------
-cast(Obj, Func, Args, TypesOrMod) ->
- cast_helper(Obj, Func, Args, TypesOrMod, []).
-
-cast(Obj, Func, Args, TypesOrMod, [{context, Ctx}]) ->
- cast_helper(Obj, Func, Args, TypesOrMod, Ctx).
-
-cast_helper(Obj, Func, Args, TypesOrMod, InCtx) ->
- Ctx = get_implicit_context(InCtx),
- case iop_ior:get_key(Obj) of
- {'internal', Key, _, Flags, Mod} ->
- Pid = orber_objectkeys:get_pid(Key),
- cast_internal(Pid, Obj, Func, Args, TypesOrMod,
- ?ORB_FLAG_TEST(Flags, ?ORB_TYPECHECK),
- ?ORB_FLAG_TEST(Flags, ?ORB_USE_PI), Mod, Ctx);
- {'internal_registered', Key, _, Flags, Mod} ->
- cast_internal(Key, Obj, Func, Args, TypesOrMod,
- ?ORB_FLAG_TEST(Flags, ?ORB_TYPECHECK),
- ?ORB_FLAG_TEST(Flags, ?ORB_USE_PI), Mod, Ctx);
- {'external', Key} when is_atom(TypesOrMod) ->
- case catch TypesOrMod:oe_tc(Func) of
- {'EXIT', What} ->
- orber:dbg("[~p] corba:cast_helper(~p);~n"
- "The call-back module does not exist or incorrect"
- " IC-version used.~nReason: ~p",
- [?LINE, TypesOrMod, What], ?DEBUG_LEVEL),
- raise(#'TRANSIENT'{minor=(?ORBER_VMCID bor 7),
- completion_status=?COMPLETED_NO});
- undefined ->
- raise(#'BAD_OPERATION'{minor = (?ORBER_VMCID bor 4),
- completion_status=?COMPLETED_NO});
- Types ->
- orber_iiop:request(Key, Func, Args, Types, 'false', infinity,
- Obj, Ctx)
- end;
- {'external', Key} ->
- orber_iiop:request(Key, Func, Args, TypesOrMod, 'false', infinity,
- Obj, Ctx)
- end.
-
-cast_internal(Pid, Obj, Func, Args, Types, Check, PI, _Mod, Ctx)
- when is_pid(Pid) andalso node(Pid) == node() ->
- invoke_pi_request(PI, Obj, Ctx, Func, Args),
- typecheck_request(Check, Args, Types, Func),
- catch gen_server:cast(Pid, {Obj, Ctx, Func, Args}),
- ok;
-cast_internal(Pid, Obj, Func, Args, Types, Check, PI, Mod, Ctx) when is_pid(Pid) ->
- invoke_pi_request(PI, Obj, Ctx, Func, Args),
- typecheck_request(Check, Args, Types, Func),
- case catch rpc:call(node(Pid), corba, cast_relay, [Pid, {Obj, Ctx, Func, Args}]) of
- {'EXCEPTION', E} ->
- typecheck_reply(Check, {'EXCEPTION', E}, Mod, Func),
- raise(E);
- {badrpc, {'EXIT', _R}} ->
- raise(#'TRANSIENT'{minor=(?ORBER_VMCID bor 3),
- completion_status=?COMPLETED_MAYBE});
- {badrpc,nodedown} ->
- orber:dbg("[~p] corba:cast_internal(~p, ~p, ~p);~nNode ~p down.",
- [?LINE, Func, Args, Types, node(Pid)], ?DEBUG_LEVEL),
- raise(#'TRANSIENT'{minor=(?ORBER_VMCID bor 2),
- completion_status=?COMPLETED_NO});
- Other ->
- orber:dbg("[~p] corba:cast_internal(~p, ~p, ~p);~n"
- "Communication with node: ~p failed with reason: ~p.",
- [?LINE, Func, Args, Types, node(Pid), Other], ?DEBUG_LEVEL),
- raise(#'TRANSIENT'{minor=(?ORBER_VMCID bor 5),
- completion_status=?COMPLETED_MAYBE})
- end;
-
-%% This case handles if the reference is created as a Pseudo object.
-%% Just call apply/3.
-cast_internal({pseudo, Module}, Obj, Func, Args, Types, Check, PI, _Mod, Ctx) ->
- OldCtx = put(oe_server_in_context, Ctx),
- invoke_pi_request(PI, Obj, Ctx, Func, Args),
- typecheck_request(Check, Args, Types, Func),
- State = binary_to_term(get_subobject_key(Obj)),
- catch apply(Module, Func, [Obj, State|Args]),
- put(oe_server_in_context, OldCtx),
- ok;
-cast_internal(Registered, Obj, Func, Args, Types, Check, PI, _Mod, Ctx) ->
- invoke_pi_request(PI, Obj, Ctx, Func, Args),
- typecheck_request(Check, Args, Types, Func),
- case whereis(Registered) of
- undefined ->
- raise(#'OBJECT_NOT_EXIST'{completion_status=?COMPLETED_NO});
- P ->
- gen_server:cast(P, {Obj, Ctx, Func, Args})
- end.
-
-cast_relay(Pid, Data) ->
- case whereis(orber_objkeyserver) of
- undefined ->
- raise(#'TRANSIENT'{minor=(?ORBER_VMCID bor 1),
- completion_status=?COMPLETED_NO});
- _ ->
- gen_server:cast(Pid, Data)
- end.
-
-%%-----------------------------------------------------------------
-%% Corba:locate - this function is for the moment just used for tests
-%%-----------------------------------------------------------------
-locate(Obj) ->
- locate(Obj, infinity, []).
-
-locate(Obj, Timeout) ->
- locate(Obj, Timeout, []).
-
-locate(Obj, Timeout, Ctx) ->
- case iop_ior:get_key(Obj) of
- {'external', Key} ->
- orber_iiop:locate(Key, Timeout, Obj, Ctx);
- _ ->
- orber_objectkeys:check(iop_ior:get_objkey(Obj))
- end.
-
-%%-----------------------------------------------------------------
-%% Incomming request from iiop
-%%-----------------------------------------------------------------
-%% Operations which do not allow object invokation.
-request_from_iiop(Obj, '_is_a', [Args], _, _, _) ->
- catch corba_object:is_a(Obj, Args);
-%% First the OMG specified this operation to be '_not_existent' and then
-%% changed it to '_non_existent' without suggesting that both must be supported.
-%% See CORBA2.3.1 page 15-34, Minor revision 2.3.1: October 1999
-request_from_iiop(Obj, '_not_existent', _, _, _, _) ->
- catch corba_object:non_existent(Obj);
-request_from_iiop(Obj, '_non_existent', _, _, _, _) ->
- catch corba_object:non_existent(Obj);
-request_from_iiop(_, '_FT_HB', _, _, _, _) ->
- ok;
-
-%% "Ordinary" operations.
-request_from_iiop({Mod, _, _, _, _, _}, oe_get_interface,
- _, _, _, _ServiceCtx) when is_atom(Mod) ->
- case catch Mod:oe_get_interface() of
- {'EXIT', What} ->
- orber:dbg("[~p] corba:request_from_iiop(~p);~n"
- "The call-back module does not exist or"
- " incorrect IC-version used.~nReason: ~p",
- [?LINE, Mod, What], ?DEBUG_LEVEL),
- {'EXCEPTION', #'TRANSIENT'{minor=(?ORBER_VMCID bor 7),
- completion_status=?COMPLETED_NO}};
- undefined ->
- {'EXCEPTION', #'BAD_OPERATION'{minor = (?ORBER_VMCID bor 4),
- completion_status='COMPLETED_NO'}};
- Interface ->
- Interface
- end;
-request_from_iiop({_Mod, pseudo, Module, _UserDef, _OrberDef, _Flags} = ObjRef,
- Func, Args, Types, ResponseExpected, _ServiceCtx) ->
- State = binary_to_term(get_subobject_key(ObjRef)),
- case ResponseExpected of
- true ->
- case catch apply(Module, Func, [ObjRef, State|Args]) of
- {noreply, _} ->
- ok;
- {noreply, _, _} ->
- ok;
- {reply, Reply, _} ->
- Reply;
- {reply, Reply, _, _} ->
- Reply;
- {stop, _, Reply, _} ->
- Reply;
- {stop, _, _} ->
- ok;
- {'EXCEPTION', E} ->
- {'EXCEPTION', E};
- {'EXIT', {undef, _}} ->
- orber:dbg("[~p] corba:request_from_iiop(~p, ~p, ~p);~n"
- "The call-back module does not exist.",
- [?LINE, Func, Args, Types], ?DEBUG_LEVEL),
- {'EXCEPTION', #'TRANSIENT'{minor=(?ORBER_VMCID bor 4),
- completion_status=?COMPLETED_NO}};
- {'EXIT', What} ->
- orber:dbg("[~p] corba:request_from_iiop(~p, ~p, ~p);~n"
- "Pseudo object exit(~p).~n"
- "The call-back module probably contain an error.",
- [?LINE, Func, Args, Types, What], ?DEBUG_LEVEL),
- {'EXCEPTION', #'TRANSIENT'{minor=(?ORBER_VMCID bor 4),
- completion_status=?COMPLETED_MAYBE}};
- Unknown ->
- orber:dbg("[~p] corba:request_from_iiop(~p, ~p, ~p);~n"
- "Pseudo object failed(~p);~n"
- "Confirm that the return value is correct"
- " (e.g. {reply, Reply, State})",
- [?LINE, Func, Args, Types, Unknown], ?DEBUG_LEVEL),
- {'EXCEPTION', #'TRANSIENT'{minor=(?ORBER_VMCID bor 6),
- completion_status=?COMPLETED_MAYBE}}
- end;
- false ->
- catch apply(Module, Func, [ObjRef, State|Args]),
- ok;
- true_oneway ->
- catch apply(Module, Func, [ObjRef, State|Args]),
- ok
- end;
-% FOR PASSIVE REPLICATION! (Response IS expected --- one way semantics doesn't
-% really mix with intentions to be consistent & fault tolerant.)
-request_from_iiop({_Mod, passive, Module, _UserDef, _OrberDef, _Flags} = ObjRef,
- Func, Args, Types, true, Ctx) ->
- GroupID = binary_to_term(get_subobject_key(ObjRef)),
- FTGroupVersionCtx = get_FTGroupVersionCtx(Ctx),
- Transaction =
- fun() ->
- ObjectGroup = read_object_group(GroupID),
- check_version_context(ObjectGroup,
- FTGroupVersionCtx),
- call_primary_protected(ObjectGroup,
- Module,
- ObjRef,
- Func,
- Args,
- GroupID,
- get_FTRequestCtx(Ctx))
- end,
- case mnesia:transaction(Transaction) of
- {atomic, Reply} ->
- Reply;
- {aborted, {too_old_reference, IOGR}} ->
- {oe_location_forward_perm, IOGR};
- {aborted, {not_primary, _Primary, IOGR}} ->
- case FTGroupVersionCtx of
- [] ->
- {oe_location_forward_perm, IOGR};
- _ ->
- {'EXCEPTION', #'TRANSIENT'{minor = 0,
- completion_status = ?COMPLETED_NO}}
- end;
- {aborted, {throw, {'EXCEPTION', E}}} ->
- {'EXCEPTION', E};
- {aborted, {'EXIT', What}} ->
- orber:dbg("[~p] corba:call_passive(~p, ~p, ~p);~n"
- "Passive object exit(~p).",
- [?LINE, Func, Args, Types, What], ?DEBUG_LEVEL),
- {'EXCEPTION', #'TRANSIENT'{minor = 0,
- completion_status=?COMPLETED_MAYBE}};
- {aborted, Unknown} ->
- orber:dbg("[~p] corba:call_passive(~p, ~p, ~p);~n"
- "Passive object failed due to bad return value (~p).",
- [?LINE, Func, Args, Types, Unknown], ?DEBUG_LEVEL),
- {'EXCEPTION', #'TRANSIENT'{minor = 0,
- completion_status=?COMPLETED_MAYBE}}
- end;
-request_from_iiop({_Mod, _Type, Key, _UserDef, _OrberDef, _Flags} = ObjRef,
- Func, Args, Types, true, _ServiceCtx) ->
- case catch gen_server:call(convert_key_to_pid(Key),
- {ObjRef, [], Func, Args}, infinity) of
- {'EXIT', What} ->
- orber:dbg("[~p] corba:request_from_iiop(~p, ~p, ~p);~n"
- "gen_server:call exit: ~p",
- [?LINE, Func, Args, Types, What], ?DEBUG_LEVEL),
- {'EXCEPTION', #'TRANSIENT'{minor=(?ORBER_VMCID bor 4),
- completion_status=?COMPLETED_MAYBE}};
- Result ->
- Result
- end;
-request_from_iiop({_Mod, _Type, Key, _UserDef, _OrberDef, _Flags} = ObjRef,
- Func, Args, Types, _, _ServiceCtx) ->
- case catch gen_server:cast(convert_key_to_pid(Key),
- {ObjRef, [], Func, Args}) of
- {'EXIT', What} ->
- orber:dbg("[~p] corba:request_from_iiop(~p, ~p, ~p);~n"
- "gen_server:cast exit: ~p",
- [?LINE, Func, Args, Types, What], ?DEBUG_LEVEL),
- {'EXCEPTION', #'TRANSIENT'{minor=(?ORBER_VMCID bor 4),
- completion_status=?COMPLETED_MAYBE}};
- Result ->
- Result
- end.
-
-%%------------------------------------------------------------
-%% Internal stuff
-%%------------------------------------------------------------
-
-convert_key_to_pid(Key) when is_binary(Key) ->
- orber_objectkeys:get_pid(Key);
-convert_key_to_pid(Name) when is_atom(Name) ->
- Name.
-
-mk_objkey(Mod, Pid, RegName, Persistent) ->
- mk_objkey(Mod, Pid, RegName, Persistent, 0).
-
-mk_objkey(Mod, Pid, [], _, Flags) when is_pid(Pid) ->
- Key = make_objkey(),
- case orber_objectkeys:register(Key, Pid, false) of
- ok ->
- {Mod, 'key', Key, term_to_binary(undefined), 0, Flags};
- R ->
- orber:dbg("[~p] corba:mk_objkey(~p);~n"
- "unable to store key(~p).", [?LINE, Mod, R], ?DEBUG_LEVEL),
- raise(#'INTERNAL'{minor=(?ORBER_VMCID bor 2), completion_status=?COMPLETED_NO})
- end;
-mk_objkey(Mod, Pid, {'global', RegName}, Persitent, Flags) when is_pid(Pid) ->
- Key = term_to_binary(RegName),
- case orber_objectkeys:register(Key, Pid, Persitent) of
- ok ->
- {Mod, 'key', Key, term_to_binary(undefined), 0, Flags};
- R ->
- orber:dbg("[~p] corba:mk_objkey(~p, ~p);~n"
- "unable to store key(~p).",
- [?LINE, Mod, RegName, R], ?DEBUG_LEVEL),
- raise(#'INTERNAL'{minor=(?ORBER_VMCID bor 2), completion_status=?COMPLETED_NO})
- end;
-mk_objkey(Mod, Pid, {'local', RegName}, Persistent, Flags) when is_pid(Pid) andalso is_atom(RegName) ->
- register(RegName, Pid),
- Key = make_objkey(),
- case orber_objectkeys:register(Key, Pid, Persistent) of
- ok ->
- {Mod, 'registered', RegName, term_to_binary(undefined), 0, Flags};
- R ->
- orber:dbg("[~p] corba:mk_objkey(~p, ~p);~n"
- "unable to store key(~p).",
- [?LINE, Mod, RegName, R], ?DEBUG_LEVEL),
- raise(#'INTERNAL'{minor=(?ORBER_VMCID bor 2), completion_status=?COMPLETED_NO})
- end.
-
-
-mk_light_objkey(Mod, RegName) ->
- {Mod, 'registered', RegName, term_to_binary(undefined), 0, 0}.
-
-mk_pseudo_objkey(Mod, Module, Flags) ->
- {Mod, 'pseudo', Module, term_to_binary(undefined), 0, Flags}.
-
-mk_passive_objkey(Mod, Module, Flags) ->
- {Mod, 'passive', Module, term_to_binary(undefined), 0, Flags}.
-
-make_objkey() ->
- term_to_binary({{erlang:system_time(),
- erlang:unique_integer()},
- node()}).
-
-objkey_to_string({_Mod, 'registered', 'orber_init', _UserDef, _OrberDef, _Flags}) ->
- "INIT";
-objkey_to_string({Mod, Type, Key, UserDef, OrberDef, Flags}) ->
- orber:domain() ++ [ 7 | binary_to_list(term_to_binary({Mod, Type, Key, UserDef, OrberDef, Flags}))];
-objkey_to_string(External_object_key) ->
- External_object_key.
-
-string_to_objkey("INIT") ->
- {orber_initial_references, 'registered', 'orber_init', term_to_binary(undefined), 0, 0};
-string_to_objkey(String) ->
- case prefix(orber:domain(), String) of
- [7 | Rest] ->
- binary_to_term(list_to_binary(Rest));
- _ ->
- String
- end.
-%% This function may only be used when we know it's a local reference (i.e. target
-%% key in a request; IOR's passed as argument or reply doesn't qualify)!
-string_to_objkey_local("INIT") ->
- {orber_initial_references, 'registered', 'orber_init', term_to_binary(undefined), 0, 0};
-string_to_objkey_local(String) ->
- case prefix(orber:domain(), String) of
- [7 | Rest] ->
- binary_to_term(list_to_binary(Rest));
- _ ->
- case resolve_initial_references(String) of
- ?ORBER_NIL_OBJREF ->
- orber:dbg("[~p] corba:string_to_objkey_local(~p);~n"
- "Invalid ObjektKey.", [?LINE, String], ?DEBUG_LEVEL),
- ?ORBER_NIL_OBJREF;
- Object ->
- {location_forward, Object}
- end
- end.
-
-prefix([], L2) ->
- L2;
-prefix([E |L1], [E | L2]) ->
- prefix(L1, L2);
-prefix(_, _) ->
- false.
-
-
-evaluate_options([], Options) ->
- GlobalFlags = orber:get_flags(),
- Options2 = check_flag(Options, ?ORB_TYPECHECK,
- ?ORB_ENV_LOCAL_TYPECHECKING, GlobalFlags),
- Options3 = check_flag(Options2, ?ORB_USE_PI, ?ORB_ENV_USE_PI, GlobalFlags),
- check_flag(Options3, ?ORB_SURVIVE_EXIT, ?ORB_ENV_SURVIVE_EXIT, GlobalFlags);
-%% Pseudo or not.
-evaluate_options([{pseudo, false}|Rest], Options) ->
- evaluate_options(Rest, Options);
-evaluate_options([{pseudo, true}|Rest], #options{passive = false} = Options) ->
- evaluate_options(Rest, Options#options{pseudo = true});
-%% FT stuff
-evaluate_options([{passive, true}|Rest], #options{pseudo = false} = Options) ->
- evaluate_options(Rest, Options#options{passive = true});
-evaluate_options([{group_id, ID}|Rest], Options) when is_integer(ID) ->
- evaluate_options(Rest, Options#options{group_id = ID});
-%% Options accepted by gen_server (e.g. dbg).
-evaluate_options([{create_options, COpt}|Rest], Options) when is_list(COpt) ->
- evaluate_options(Rest, Options#options{create_options = COpt});
-%% When starting object as supervisor child.
-evaluate_options([{sup_child, false}|Rest], Options) ->
- evaluate_options(Rest, Options);
-evaluate_options([{sup_child, true}|Rest], Options) ->
- evaluate_options(Rest, Options#options{sup_child = true});
-%% Persistent object-key
-evaluate_options([{persistent, false}|Rest], Options) ->
- evaluate_options(Rest, Options);
-evaluate_options([{persistent, true}|Rest], Options) ->
- evaluate_options(Rest, Options#options{persistent = true});
-evaluate_options([{regname, []}|Rest], Options) ->
- evaluate_options(Rest, Options);
-evaluate_options([{regname, Name}|Rest], Options) ->
- evaluate_options(Rest, Options#options{regname = Name});
-evaluate_options([{survive_exit, false}|Rest],
- #options{object_flags_set = FlagsSet} = Options) ->
- %% This option overrides a global setting.
- evaluate_options(Rest, Options#options{object_flags_set =
- (?ORB_SURVIVE_EXIT bor FlagsSet)});
-evaluate_options([{survive_exit, true}|Rest],
- #options{object_flags = Flags,
- object_flags_set = FlagsSet} = Options) ->
- evaluate_options(Rest, Options#options{object_flags =
- (?ORB_SURVIVE_EXIT bor Flags),
- object_flags_set =
- (?ORB_SURVIVE_EXIT bor FlagsSet)});
-evaluate_options([{local_typecheck, false}|Rest],
- #options{object_flags_set = FlagsSet} = Options) ->
- %% This option overrides a global setting.
- evaluate_options(Rest, Options#options{object_flags_set =
- (?ORB_TYPECHECK bor FlagsSet)});
-evaluate_options([{local_typecheck, true}|Rest],
- #options{object_flags = Flags,
- object_flags_set = FlagsSet} = Options) ->
- evaluate_options(Rest, Options#options{object_flags = (?ORB_TYPECHECK bor Flags),
- object_flags_set =
- (?ORB_TYPECHECK bor FlagsSet)});
-evaluate_options([{local_interceptors, false}|Rest],
- #options{object_flags_set = FlagsSet} = Options) ->
- %% This option overrides a global setting.
- evaluate_options(Rest, Options#options{object_flags_set =
- (?ORB_USE_PI bor FlagsSet)});
-evaluate_options([{local_interceptors, true}|Rest],
- #options{object_flags = Flags,
- object_flags_set = FlagsSet} = Options) ->
- evaluate_options(Rest, Options#options{object_flags = (?ORB_USE_PI bor Flags),
- object_flags_set =
- (?ORB_USE_PI bor FlagsSet)});
-%% Temporary option.
-evaluate_options([{no_security, true}|Rest],
- #options{object_flags = Flags} = Options) ->
- %% We do not allow this option to be set globally.
- evaluate_options(Rest, Options#options{object_flags = (?ORB_NO_SECURITY bor Flags)});
-evaluate_options([{no_security, false}|Rest], Options) ->
- %% We do not allow this option to be set globally.
- evaluate_options(Rest, Options);
-evaluate_options([{Key, Value}|_], _) ->
- orber:dbg("[~p] corba:evaluate_options(~p, ~p);~n"
- "Option not recognized, illegal value or combination.~n"
- "Allowed settings:~n"
- "survive_exit.......: boolean()~n"
- "sup_child..........: boolean()~n"
- "persistent.........: boolean()~n"
- "pseudo.............: boolean()~n"
- "local_typecheck....: boolean()~n"
- "local_interceptors.: boolean()~n"
- "regname............: {local, atom()} | {global, term()}",
- [?LINE, Key, Value], ?DEBUG_LEVEL),
- raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-check_flag(#options{object_flags = Flags,
- object_flags_set = FlagsSet} = Options, Flag,
- FlagConstant, GlobalFlags) ->
- %% Option activated/deactived by a supplied option.
- case ?ORB_FLAG_TEST(FlagsSet, Flag) of
- true ->
- Options;
- false ->
- %% Not the above. Globally defined?
- case ?ORB_FLAG_TEST(GlobalFlags, FlagConstant) of
- true ->
- Options#options{object_flags = (Flag bor Flags)};
- false ->
- Options
- end
- end.
-
-%%%%%%%%%%%%%%%%% FOR PASSIVE REPLICATION!
-% Note should be called inside transaction. Does not catch exceptions.
-% let's not allow corba:reply from transaction... (no {noreply, ...} messages)
-% should the object be able to stop itself by returning {stop, ...}?
-% how about corba:dispose then? Deleting table representing object group and
-% corresponding entry in ft_replication_manager -table might just do the job?
-% No {stop, ...} messages for now
-% Exceptions falls through. They are expected to be caught by transaction in a
-% form of {aborted, {throw, {'EXCEPTION', ...}}}
-call_passive(Module, Obj, Func, Args, GroupID) ->
- [Record] = mnesia:read(ft_replicated_object, GroupID, sticky_write),
- State = Record#ft_replicated_object.state,
-
- case apply(Module, Func, [Obj, State|Args]) of
- {reply, Reply, NewState} ->
- {Reply, NewState};
- {reply, Reply, NewState, _} ->
- {Reply, NewState}
- end,
- mnesia:write(ft_replicated_object,
- #ft_replicated_object{group_id = GroupID, state = NewState},
- sticky_write),
- Reply.
-
-
-
-% FTRequestCtx protected object call
-% One should protect agains aged reply. If expirations_time is reached and
-% request is retransmitted, one might return BAD_CONTEXT -exception!
-call_RQprotected(Module, Obj, Func, Args, GroupID, RQCtx) ->
- case mnesia:read(ft_reply_retention, RQCtx, sticky_write) of
- % fresh request
- [] ->
- Reply = call_passive(Module, Obj, Func, Args, GroupID),
- mnesia:write(ft_reply_retention,
- #ft_reply_retention{retention_id= RQCtx,reply= Reply},
- sticky_write),
- Reply;
- % retransmitted request
- [#ft_reply_retention{reply = Reply}] ->
- Reply
- end.
-
-
-
-% call_primary_protected. Protects agains calling non-primary node.
-% normal case, without FTRequest Service Context
-call_primary_protected(#ft_replication_manager{primary = Primary},
- Module,
- Obj,
- Func,
- Args,
- GroupID,
- []) when Primary == node() ->
- call_passive(Module, Obj, Func, Args, GroupID);
-% normal case, with FTRequest Service Context
-call_primary_protected(#ft_replication_manager{primary = Primary},
- Module,
- Obj,
- Func,
- Args,
- GroupID,
- RetentionID) when Primary == node() ->
- call_RQprotected(Module, Obj, Func, Args, GroupID, RetentionID);
-% case where primary resides in another node
-call_primary_protected(#ft_replication_manager{primary = Primary,
- iogr = IOGR},
- _Module, _Obj, _Func, _Args, _GroupID, _) ->
- mnesia:abort({not_primary, Primary, IOGR}).
-
-
-
-% no context
-check_version_context(_, []) ->
- ok;
-% client's IOGR is current.
-check_version_context(#ft_replication_manager{ref_version = CurrentVer},
- GroupVer) when CurrentVer == GroupVer ->
- ok;
-% client's IOGR is old.
-check_version_context(#ft_replication_manager{ref_version = CurrentVer,
- iogr = IOGR},
- GroupVer) when CurrentVer > GroupVer ->
- mnesia:abort({too_old_reference, IOGR});
-% client's IOGR is too new!
-check_version_context(#ft_replication_manager{ref_version = CurrentVer},
- GroupVer) when CurrentVer < GroupVer ->
- raise(#'INV_OBJREF'{completion_status = ?COMPLETED_NO}).
-
-
-
-read_object_group(GroupID) ->
- case mnesia:read({ft_replication_manager, GroupID}) of
- [] ->
- raise(#'OBJECT_NOT_EXIST'{completion_status = ?COMPLETED_NO});
- [ObjectGroup] ->
- ObjectGroup
- end.
-
-
-
-mk_FTRequestCtx(Expiration_time) ->
- #'FT_FTRequestServiceContext'{
- client_id = atom_to_list(node()),
- retention_id = orber_request_number:get(),
- expiration_time = Expiration_time}.
-
-
-
-get_FTRequestCtx([#'FT_FTRequestServiceContext'
- {client_id = Client_ID, retention_id = Retention_ID,
- expiration_time = Expiration_time}|_Ctxs]) ->
- {Client_ID, Retention_ID, Expiration_time};
-get_FTRequestCtx([]) ->
- [];
-get_FTRequestCtx([_Ctx|Ctxs]) ->
- get_FTRequestCtx(Ctxs).
-
-
-
-get_FTGroupVersionCtx([#'FT_FTGroupVersionServiceContext'
- {object_group_ref_version = Version}|_Ctxs]) ->
- Version;
-get_FTGroupVersionCtx([]) ->
- [];
-get_FTGroupVersionCtx([_Ctx|Ctxs]) ->
- get_FTGroupVersionCtx(Ctxs).
-
diff --git a/lib/orber/src/corba_boa.erl b/lib/orber/src/corba_boa.erl
deleted file mode 100644
index 12b063a5db..0000000000
--- a/lib/orber/src/corba_boa.erl
+++ /dev/null
@@ -1,135 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: corba_boa.erl
-%%
-%% Description:
-%% This file contains the CORBA::BOA interface
-%%
-%%-----------------------------------------------------------------
--module(corba_boa).
-
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([%create/3,
- dispose/1,
- get_id/1]).
-% change_implementation/2,
-% set_exception/3,
-% impl_is_ready/1,
-% deactivate_impl/1,
-% obj_is_ready/2,
-% deactivate_obj/1,
-% get_principal/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-%%-----------------------------------------------------------------
-%% Macros
-%%-----------------------------------------------------------------
--define(DEBUG_LEVEL, 5).
-
-%%-----------------------------------------------------------------
-%% External functions
-%%-----------------------------------------------------------------
-%create(Id, Interface, Implementation) ->
-% corba:create(Implementation#orb_ImplDef.module,
-% Interface#fullinterfacedescription.id).
-
-dispose(Object) ->
- case binary_to_term(iop_ior:get_privfield(Object)) of
- undefined ->
- case catch iop_ior:get_key(Object) of
- {'internal', Key, _, _, _} ->
- case orber_objectkeys:get_pid(Key) of
- {error, Reason} ->
- orber:dbg("[~p] corba_boa:dispose(~p); object not found(~p)",
- [?LINE, Object, Reason], ?DEBUG_LEVEL),
- corba:raise(#'TRANSIENT'{completion_status=?COMPLETED_NO});
- Pid ->
- gen_server:call(Pid, stop)
- end;
- {'internal_registered', Key, _, _, _} ->
- case Key of
- {pseudo, Module} ->
- Module:terminate(normal, undefined),
- ok;
- _ ->
- case whereis(Key) of
- undefined ->
- corba:raise(#'OBJECT_NOT_EXIST'{completion_status=?COMPLETED_NO});
- Pid ->
- gen_server:call(Pid, stop)
- end
- end;
- {'external', _} ->
- orber:dbg("[~p] corba_boa:dispose(~p); external object.",
- [?LINE, Object], ?DEBUG_LEVEL),
- %% Must be fixed !!!!!!!!
- corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO})
- end;
- Other ->
- case iop_ior:get_key(Object) of
- {_, {pseudo, Module}, _, _, _} ->
- Module:terminate(normal, Other),
- ok;
- Why ->
- orber:dbg("[~p] corba_boa:dispose(~p); probably subobject key set(~p)",
- [?LINE, Object, Why], ?DEBUG_LEVEL),
- corba:raise(#'NO_PERMISSION'{completion_status=?COMPLETED_NO})
- end
- end.
-
-get_id(Object) ->
- iop_ior:get_objkey(Object).
-
-%change_implementation(Object, ImplementationDef) ->
-% ok.
-
-%get_principal(Object, Env) ->
-% ok.
-
-%set_exception(Major, Id, Param) ->
-% ok.
-
-%impl_is_ready(ImplementationDef) ->
-% ok.
-
-%deactivate_impl(ImplementationDef) ->
-% ok.
-
-%obj_is_ready(Object, ImplementationDef) ->
-% ok.
-
-%deactivate_obj(Object) ->
-% ok.
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
diff --git a/lib/orber/src/corba_nvlist.erl b/lib/orber/src/corba_nvlist.erl
deleted file mode 100644
index 4a1361842b..0000000000
--- a/lib/orber/src/corba_nvlist.erl
+++ /dev/null
@@ -1,98 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: corba_nvlist.erl
-%% Description:
-%% This file contains the CORBA::NVList handling
-%%
-%%-----------------------------------------------------------------
--module(corba_nvlist).
-
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
-
-%%-----------------------------------------------------------------
-%% Standard interface CORBA::NVList
-%%-----------------------------------------------------------------
--export([add_item/6,
- free/1,
- free_memory/1,
- get_count/1]).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([create_list/1,
- create_operation_list/1]).
-
-%%------------------------------------------------------------
-%% Implementation of standard interface CORBA::NVList
-%%------------------------------------------------------------
-add_item(List, Id, TC, Value, Len, ArgFlags) ->
- {ok, List}.
-
-free(List) ->
- ok.
-
-free_memory(List) ->
- ok.
-
-get_count(List) ->
- {ok, 0}.
-
-%%------------------------------------------------------------
-%% Implementation of extra functions which creates NVList:s
-%% theese ae used by the standard functions with the same name
-%% in the CORBA::ORB interface
-%%------------------------------------------------------------
-
-create_list(Count) ->
- {ok, create_list_2(Count, [])}.
-
-create_list_2(0, Acc) ->
- Acc;
-create_list_2(N, Acc) ->
- create_list_2(N-1, [[] | Acc]).
-
-create_operation_list(OpDef) ->
- OpArgList = OpDef,
- {ok, create_operation_list_2(OpArgList, [])}.
-
-create_operation_list_2([], Acc) ->
- Acc;
-create_operation_list_2([OpArg | OpArgList], Acc) ->
- Rec = parse_oparg_def(OpArg),
- create_operation_list_2(OpArgList, [Rec | Acc]).
-
-parse_oparg_def(OpArg) ->
- OpArg.
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/orber/src/corba_object.erl b/lib/orber/src/corba_object.erl
deleted file mode 100644
index bf31226067..0000000000
--- a/lib/orber/src/corba_object.erl
+++ /dev/null
@@ -1,221 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: corba_object.erl
-%%
-%% Description:
-%% This file contains the CORBA::Object interface
-%%
-%%-----------------------------------------------------------------
--module(corba_object).
-
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
--include_lib("orber/src/ifr_objects.hrl").
-
-%%-----------------------------------------------------------------
-%% Standard interface CORBA::Object
-%%-----------------------------------------------------------------
--export([get_interface/1,
- is_nil/1,
- is_a/2,
- is_a/3,
- is_remote/1,
- non_existent/1,
- non_existent/2,
- not_existent/1,
- not_existent/2,
- is_equivalent/2,
- hash/2,
- create_request/6]).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([]).
-
-%%-----------------------------------------------------------------
-%% Macros
-%%-----------------------------------------------------------------
--define(DEBUG_LEVEL, 5).
-
-%%------------------------------------------------------------
-%% Implementation of standard interface
-%%------------------------------------------------------------
-get_interface(Obj) ->
- case orber_env:light_ifr() of
- false ->
- TypeId = iop_ior:get_typeID(Obj),
- case mnesia:dirty_index_read(ir_InterfaceDef, TypeId, #ir_InterfaceDef.id) of
- %% If all we get is an empty list there are no such
- %% object registered in the IFR.
- [] ->
- orber:dbg("[~p] corba_object:get_interface(~p); TypeID ~p not found in IFR.",
- [?LINE, Obj, TypeId], ?DEBUG_LEVEL),
- corba:raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO});
- [#ir_InterfaceDef{ir_Internal_ID=Ref}] ->
- orber_ifr_interfacedef:describe_interface({ir_InterfaceDef, Ref})
- end;
- true ->
- case catch iop_ior:get_key(Obj) of
- {'external', _Key} ->
- orber:dbg("[~p] corba_object:get_interface(~p); Invalid object reference.",
- [?LINE, Obj], ?DEBUG_LEVEL),
- corba:raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO});
- {_Local, _Key, _, _, Module} ->
- case catch Module:oe_get_interface() of
- {'EXIT', What} ->
- orber:dbg("[~p] corba_object:get_interface(~p);~n"
- "The call-back module does not exist or incorrect IC-version used.~n"
- "Reason: ~p", [?LINE, Module, What], ?DEBUG_LEVEL),
- corba:raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO});
- InterfaceDesc ->
- InterfaceDesc
- end
- end
- end.
-
-
-is_nil(Object) when is_record(Object, 'IOP_IOR') ->
- iop_ior:check_nil(Object);
-is_nil({I,T,K,P,O,F}) ->
- iop_ior:check_nil({I,T,K,P,O,F});
-is_nil(Obj) ->
- orber:dbg("[~p] corba_object:is_nil(~p); Invalid object reference.",
- [?LINE, Obj], ?DEBUG_LEVEL),
- corba:raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO}).
-
-is_a(Obj, Logical_type_id) ->
- is_a(Obj, Logical_type_id, []).
-
-is_a(?ORBER_NIL_OBJREF, _, _Ctx) ->
- false;
-is_a(#'IOP_IOR'{type_id = Logical_type_id}, Logical_type_id, _Ctx) ->
- true;
-is_a(Obj, Logical_type_id, Ctx) when is_list(Ctx) ->
- case catch iop_ior:get_key(Obj) of
- {'external', Key} ->
- orber_iiop:request(Key, '_is_a', [Logical_type_id],
- {orber_tc:boolean(),[orber_tc:string(0)],[]},
- true, infinity, Obj, corba:get_implicit_context(Ctx));
- {_Local, _Key, _, _, Module} ->
- case catch Module:oe_is_a(Logical_type_id) of
- {'EXIT', What} ->
- orber:dbg("[~p] corba_object:is_a(~p);~n"
- "The call-back module does not exist or incorrect IC-version used.~n"
- "Reason: ~p", [?LINE, Module, What], ?DEBUG_LEVEL),
- corba:raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO});
- Boolean ->
- Boolean
- end;
- _ ->
- orber:dbg("[~p] corba_object:is_a(~p, ~p); Invalid object reference.",
- [?LINE, Obj, Logical_type_id], ?DEBUG_LEVEL),
- corba:raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO})
- end;
-is_a(Obj, Logical_type_id, Ctx) ->
- orber:dbg("[~p] corba_object:is_a(~p, ~p, ~p);~n"
- "Failed to supply a context list.",
- [?LINE, Obj, Logical_type_id, Ctx], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-
-non_existent(Obj) ->
- non_existent(Obj, []).
-
-non_existent(?ORBER_NIL_OBJREF, _Ctx) ->
- true;
-non_existent(Obj, Ctx) ->
- existent_helper(Obj, '_non_existent', Ctx).
-
-not_existent(Obj) ->
- not_existent(Obj, []).
-
-not_existent(?ORBER_NIL_OBJREF, _Ctx) ->
- true;
-not_existent(Obj, Ctx) ->
- existent_helper(Obj, '_not_existent', Ctx).
-
-
-existent_helper(Obj, Op, Ctx) when is_list(Ctx) ->
- case catch iop_ior:get_key(Obj) of
- {'internal', Key, _, _, _} ->
- case catch orber_objectkeys:get_pid(Key) of
- {'EXCEPTION', E} when is_record(E,'OBJECT_NOT_EXIST') ->
- true;
- {'EXCEPTION', X} ->
- corba:raise(X);
- {'EXIT', R} ->
- orber:dbg("[~p] corba_object:non_existent(~p); exit(~p).",
- [?LINE, Obj, R], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO});
- _ ->
- false
- end;
- {'internal_registered', Key, _, _, _} ->
- case Key of
- {pseudo, _} ->
- false;
- _->
- case whereis(Key) of
- undefined ->
- true;
- _P ->
- false
- end
- end;
- {'external', Key} ->
- orber_iiop:request(Key, Op, [],
- {orber_tc:boolean(), [],[]}, 'true',
- infinity, Obj, corba:get_implicit_context(Ctx));
- true ->
- false
- end;
-existent_helper(Obj, Op, Ctx) ->
- orber:dbg("[~p] corba_object:existent_helper(~p, ~p, ~p);~n"
- "Failed to supply a context list.",
- [?LINE, Obj, Op, Ctx], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-
-is_remote(Obj) ->
- case catch iop_ior:get_key(Obj) of
- {'external', _} ->
- true;
- _ ->
- false
- end.
-
-
-is_equivalent(Obj, Obj) ->
- true;
-is_equivalent({I,T,K,P,_,_}, {I,T,K,P,_,_}) ->
- true;
-is_equivalent(_, _) ->
- false.
-
-hash(Obj, Maximum) ->
- erlang:phash(iop_ior:get_key(Obj), Maximum).
-
-
-create_request(_Obj, _Ctx, _Op, _ArgList, NamedValueResult, _ReqFlags) ->
- {ok, NamedValueResult, []}.
diff --git a/lib/orber/src/fixed.erl b/lib/orber/src/fixed.erl
deleted file mode 100644
index 8d6239991d..0000000000
--- a/lib/orber/src/fixed.erl
+++ /dev/null
@@ -1,306 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%--------------------------------------------------------------------
-%% File : fixed.erl
-%% Purpose :
-%%--------------------------------------------------------------------
-
--module(fixed).
-
--include_lib("orber/include/corba.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([create/3, add/2, subtract/2, divide/2, multiply/2, unary_minus/1,
- get_typecode/1]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-%%-----------------------------------------------------------------
-%% Definitions
-%%-----------------------------------------------------------------
--define(get_max(__X, __Y), if __X > __Y -> __X; true -> __Y end).
--define(get_min(__X, __Y), if __X > __Y -> __Y; true -> __X end).
-
--define(BASE, 100000000000000000000000000000000).
--define(FIXED_MAX, 9999999999999999999999999999999).
--define(FIXED_MIN, -9999999999999999999999999999999).
-
--define(DEBUG_LEVEL, 5).
-
-%%-----------------------------------------------------------------
-%% External functions
-%%-----------------------------------------------------------------
-create(Digits, Scale, Value) when is_integer(Digits) andalso Digits >= 0 andalso Digits < 32 andalso
- is_integer(Scale) andalso Scale >= 0 andalso Digits >= Scale andalso
- is_integer(Value) andalso Value =< ?FIXED_MAX andalso
- Value >= ?FIXED_MIN ->
- case count_digits(abs(Value)) of
- Dig when Dig =< Digits ->
- #fixed{digits = Digits, scale = Scale, value = Value};
- Overflow ->
- orber:dbg("[~p] fixed:create(~p, ~p, ~p).~n"
- "The Value exceeds the Digits limit: ~p, ~p",
- [?LINE, Digits, Scale, Value, Digits, Overflow], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO})
- end;
-create(Digits, Scale, Value) ->
- orber:dbg("[~p] fixed:add(~p, ~p, ~p).~n"
- "At least one of the supplied arguments is incorrect.~n"
- "Digits and Scale must be a positive integer with the following~n"
- "limits:~n"
- " * 0 =< Digits < 32~n"
- " * Digits >= Scale~n"
- " * Value range +/- 9999999999999999999999999999999",
- [?LINE, Digits, Scale, Value], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-
-get_typecode(#fixed{digits = Digits, scale = Scale}) ->
- {tk_fixed, Digits, Scale};
-get_typecode(Other) ->
- orber:dbg("[~p] fixed:get_typecode(~p).
-The supplied argument is not a Fixed Type.", [?LINE, Other], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-add(#fixed{digits = D1, scale = S1, value = V1},
- #fixed{digits = D2, scale = S2, value = V2}) ->
- Scale = ?get_max(S1, S2),
- Digits = ?get_max((D1-S1), (D2-S2)) + Scale +1,
- %% We must normalize the values before adding. Why?
- %% 4.23 and 5.2 are represented as 423 and 52. To be able to get the
- %% correct result we must add 4230 and 5200 == 9430.
- {PV1, PV2} = normalize(S1, V1, S2, V2),
- check_fixed_overflow(#fixed{digits = Digits,
- scale = Scale,
- value = (PV1 + PV2)});
-add(F1, F2) ->
- orber:dbg("[~p] fixed:add(~p, ~p).~n"
- "At least one of the supplied arguments is not a Fixed Type.",
- [?LINE, F1, F2], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-
-subtract(#fixed{digits = D1, scale = S1, value = V1},
- #fixed{digits = D2, scale = S2, value = V2}) ->
- Scale = ?get_max(S1, S2),
- Digits = ?get_max((D1-S1), (D2-S2)) + Scale +1,
- {PV1, PV2} = normalize(S1, V1, S2, V2),
- check_fixed_overflow(#fixed{digits = Digits,
- scale = Scale,
- value = (PV1 - PV2)});
-subtract(F1, F2) ->
- orber:dbg("[~p] fixed:subtract(~p, ~p).~n"
- "At least one of the supplied arguments is not a Fixed Type.",
- [?LINE, F1, F2], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-divide(#fixed{digits = D1, scale = S1, value = V1},
- #fixed{digits = _D2, scale = S2, value = V2}) ->
- {PV1, PV2} = normalize(S1, V1, S2, V2),
- DigitsMin = (D1-S1+S2),
- R1 = (PV1 div PV2),
- R2 = (R1*?BASE + (PV1 rem PV2) * (?BASE div PV2)),
- {Result2, Sinf} = delete_zeros_value(R2, 0, R1),
- check_fixed_overflow(#fixed{digits = DigitsMin + Sinf, scale = Sinf,
- value = Result2});
-divide(F1, F2) ->
- orber:dbg("[~p] fixed:divide(~p, ~p).~n"
- "At least one of the supplied arguments is not a Fixed Type.",
- [?LINE, F1, F2], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-
-multiply(#fixed{digits = D1, scale = S1, value = V1},
- #fixed{digits = D2, scale = S2, value = V2}) ->
- check_fixed_overflow(#fixed{digits = (D1+D2),
- scale = (S1+S2),
- value = V1*V2});
-multiply(F1, F2) ->
- orber:dbg("[~p] fixed:multiply(~p, ~p).~n"
- "At least one of the supplied arguments is not a Fixed Type.",
- [?LINE, F1, F2], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-unary_minus(Fixed) when is_record(Fixed, fixed) ->
- Fixed#fixed{value = -(Fixed#fixed.value)};
-unary_minus(Fixed) ->
- orber:dbg("[~p] fixed:unary_minus(~p).~n"
- "The supplied argument is not a Fixed Type.",
- [?LINE, Fixed], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-%% Pretty?! No, but since we now the upper-limit this is the fastest way
-%% to calculate 10^x
-power(0) -> 1;
-power(1) -> 10;
-power(2) -> 100;
-power(3) -> 1000;
-power(4) -> 10000;
-power(5) -> 100000;
-power(6) -> 1000000;
-power(7) -> 10000000;
-power(8) -> 100000000;
-power(9) -> 1000000000;
-power(10) -> 10000000000;
-power(11) -> 100000000000;
-power(12) -> 1000000000000;
-power(13) -> 10000000000000;
-power(14) -> 100000000000000;
-power(15) -> 1000000000000000;
-power(16) -> 10000000000000000;
-power(17) -> 100000000000000000;
-power(18) -> 1000000000000000000;
-power(19) -> 10000000000000000000;
-power(20) -> 100000000000000000000;
-power(21) -> 1000000000000000000000;
-power(22) -> 10000000000000000000000;
-power(23) -> 100000000000000000000000;
-power(24) -> 1000000000000000000000000;
-power(25) -> 10000000000000000000000000;
-power(26) -> 100000000000000000000000000;
-power(27) -> 1000000000000000000000000000;
-power(28) -> 10000000000000000000000000000;
-power(29) -> 100000000000000000000000000000;
-power(30) -> 1000000000000000000000000000000;
-power(31) -> 10000000000000000000000000000000;
-power(_) -> 10000000000000000000000000000000.
-
-
-
-%% If the result of an operation (+, -, * or /) causes overflow we use this
-%% operation. However, since these calculations are performed during compiletime,
-%% shouldn't the IDL-specification be changed to not cause overflow?! But, since
-%% the OMG standard allows this we must support it.
-check_fixed_overflow(#fixed{digits = Digits, scale = Scale, value = Value}) ->
- case count_digits(abs(Value)) of
- overflow ->
- {N, NewVal} = cut_overflow(0, Value),
- if
- N > Scale ->
- #fixed{digits = 31, scale = 0, value = NewVal};
- true ->
- NewScale = Scale - N,
- {NewVal2, Removed} = delete_zeros(NewVal, NewScale),
- #fixed{digits = 31, scale = NewScale-Removed, value = NewVal2}
- end;
- Count when Count > Digits ->
- Diff = Count-Digits,
- if
- Diff > Scale ->
- #fixed{digits = Digits, scale = 0,
- value = (Value div power(Diff))};
- true ->
- NewScale = Scale-Diff,
- {NewVal, Removed} = delete_zeros((Value div power(Diff)), NewScale),
- #fixed{digits = Digits-Removed,
- scale = NewScale-Removed,
- value = NewVal}
- end;
- Count ->
- {NewVal, Removed} = delete_zeros(Value, Scale),
- #fixed{digits = Count-Removed, scale = Scale-Removed, value = NewVal}
- end.
-
-%% This function see to that the values are of the same baase.
-normalize(S, V1, S, V2) ->
- {V1, V2};
-normalize(S1, V1, S2, V2) when S1 > S2 ->
- {V1, V2*power(S1-S2)};
-normalize(S1, V1, S2, V2) ->
- {V1*power(S2-S1), V2}.
-
-%% If we have access to the integer part of the fixed type we use this
-%% operation to remove all trailing zeros. If we know the scale, length of
-%% fraction part, we can use delete_zeros as well. But, after a division
-%% it's hard to know the scale and we don't need to calcluate the integer part.
-delete_zeros_value(0, N, _) ->
- {0, 32-N};
-delete_zeros_value(X, N, M) when X > M, (X rem 10) == 0 ->
- delete_zeros_value((X div 10), N+1, M);
-delete_zeros_value(X, N, _) ->
- {X, 32-N}.
-
-%% If we know the exact scale of a fixed type we can use this operation to
-%% remove all trailing zeros.
-delete_zeros(0, _) ->
- {0,0};
-delete_zeros(X, Max) ->
- delete_zeros(X, 0, Max).
-delete_zeros(X, Max, Max) ->
- {X, Max};
-delete_zeros(X, N, Max) when (X rem 10) == 0 ->
- delete_zeros((X div 10), N+1, Max);
-delete_zeros(X, N, _) ->
- {X, N}.
-
-cut_overflow(N, X) when X > ?FIXED_MAX ->
- cut_overflow(N+1, (X div 10));
-cut_overflow(N, X) ->
- {N, X}.
-
-%% A fast way to check the size of a fixed data type.
-count_digits(X) when X > ?FIXED_MAX -> overflow;
-count_digits(X) when X >= 1000000000000000000000000000000 -> 31;
-count_digits(X) when X >= 100000000000000000000000000000 -> 30;
-count_digits(X) when X >= 10000000000000000000000000000 -> 29;
-count_digits(X) when X >= 1000000000000000000000000000 -> 28;
-count_digits(X) when X >= 100000000000000000000000000 -> 27;
-count_digits(X) when X >= 10000000000000000000000000 -> 26;
-count_digits(X) when X >= 1000000000000000000000000 -> 25;
-count_digits(X) when X >= 100000000000000000000000 -> 24;
-count_digits(X) when X >= 10000000000000000000000 -> 23;
-count_digits(X) when X >= 1000000000000000000000 -> 22;
-count_digits(X) when X >= 100000000000000000000 -> 21;
-count_digits(X) when X >= 10000000000000000000 -> 20;
-count_digits(X) when X >= 1000000000000000000 -> 19;
-count_digits(X) when X >= 100000000000000000 -> 18;
-count_digits(X) when X >= 10000000000000000 -> 17;
-count_digits(X) when X >= 1000000000000000 -> 16;
-count_digits(X) when X >= 100000000000000 -> 15;
-count_digits(X) when X >= 10000000000000 -> 14;
-count_digits(X) when X >= 1000000000000 -> 13;
-count_digits(X) when X >= 100000000000 -> 12;
-count_digits(X) when X >= 10000000000 -> 11;
-count_digits(X) when X >= 1000000000 -> 10;
-count_digits(X) when X >= 100000000 -> 9;
-count_digits(X) when X >= 10000000 -> 8;
-count_digits(X) when X >= 1000000 -> 7;
-count_digits(X) when X >= 100000 -> 6;
-count_digits(X) when X >= 10000 -> 5;
-count_digits(X) when X >= 1000 -> 4;
-count_digits(X) when X >= 100 -> 3;
-count_digits(X) when X >= 10 -> 2;
-count_digits(_X) -> 1.
-
-%%-----------------------------------------------------------------
-%%------------- END OF MODULE -------------------------------------
-%%-----------------------------------------------------------------
diff --git a/lib/orber/src/ifr_objects.hrl b/lib/orber/src/ifr_objects.hrl
deleted file mode 100644
index 3feedbc652..0000000000
--- a/lib/orber/src/ifr_objects.hrl
+++ /dev/null
@@ -1,422 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%%----------------------------------------------------------------------
-%%% File : ir_objects.hrl
-%%% Purpose : Record definitions for the IR DB
-%%%----------------------------------------------------------------------
-
-%%%----------------------------------------------------------------------
-%%% *********************************************************************
-%%% * *
-%%% * PLEASE NOTE *
-%%% * *
-%%% * If a record is removed or added in this file, the corresponding *
-%%% * database initialization code _MUST_ be updated accordingly. *
-%%% * *
-%%% * The initialization code is defined in a macro in this file. *
-%%% * *
-%%% * Also remember to update select/2 in orber_ifr.erl when adding *
-%%% * or deleting a record in this file. *
-%%% * *
-%%% *********************************************************************
-%%%----------------------------------------------------------------------
-
-%% Interface objects
-
-%% There are eight interface objects in an interface repository:
-%% Repository, ModuleDef, InterfaceDef, AttributeDef, OperationDef,
-%% TypedefDef, ConstantDef and ExceptionDef (CORBA V2.0, page 6-5/6).
-
-% The other objects defined here are used to build the above objects
-% (CORBA V2.0, page 6-7).
-
-% Object references are stored as mnesia object IDs, i.e. a tuple with
-% the table name and the ir_Internal_ID.
-
-% Inheritance strategy. We incorporate the inherited object into the
-% inheriting object. The record element 'inherited_objects' is a list
-% of objects that "this" object inherits from (i.e. full object
-% records and not object references).
-
-% The record element 'ir_Internal_ID' is a tag that uniquely
-% identifies a record. See the function orber_ifr:unique().
-
- % IRObject, page 6-9
--record(ir_IRObject, {ir_Internal_ID,def_kind}).
-
- % Contained, page 6-9
--record(ir_Contained, {ir_Internal_ID, %[IRObject]
- def_kind, %from IRObject
- id,
- name,
- version,
- defined_in,
- absolute_name,
- containing_repository}).
-
- % Container, page 6-10
--record(ir_Container, {ir_Internal_ID, %[IRObject]
- def_kind, %from IRObject
- contents}).
-
- % IDLType, page 6-15
--record(ir_IDLType, {ir_Internal_ID, %[IRObject]
- def_kind, %from IRObject
- type}).
-
- % Repository, page 6-16
--record(ir_Repository, {ir_Internal_ID, %[Container]
- def_kind, %from IRObject
- contents, %from Container
- primitivedefs}).
-
- % ModuleDef, page 6-17
--record(ir_ModuleDef, {ir_Internal_ID, %[Container,Contained]
- def_kind, %from IRObject
- contents, %from Container
- id, %from Contained
- name, %from Contained
- version, %from Contained
- defined_in, %from Contained
- absolute_name, %from Contained
- containing_repository %from Contained
- }).
-
- % ConstantDef, page 6-17
--record(ir_ConstantDef, {ir_Internal_ID, %[Contained]
- def_kind, %from IRObject
- id, %from Contained
- name, %from Contained
- version, %from Contained
- defined_in, %from Contained
- absolute_name, %from Contained
- containing_repository, %from Contained
- type,
- type_def,
- value}).
-
- % TypedefDef, page 6-18
--record(ir_TypedefDef, {ir_Internal_ID, %[Contained,IDLType]
- def_kind, %from IRObject
- id, %from Contained
- name, %from Contained
- version, %from Contained
- defined_in, %from Contained
- absolute_name, %from Contained
- containing_repository, %from Contained
- type %from IDLType
- }).
-
- % StructDef, page 6-19
--record(ir_StructDef, {ir_Internal_ID, %[TypedefDef]
- def_kind, %from IRObject
- id, %from Contained
- name, %from Contained
- version, %from Contained
- defined_in, %from Contained
- absolute_name, %from Contained
- containing_repository, %from Contained
- type, %from IDLType
- members}).
-
- % UnionDef, page 6-19
--record(ir_UnionDef, {ir_Internal_ID, %[TypedefDef]
- def_kind, %from IRObject
- id, %from Contained
- name, %from Contained
- version, %from Contained
- defined_in, %from Contained
- absolute_name, %from Contained
- containing_repository, %from Contained
- type, %from IDLType
- discriminator_type,
- discriminator_type_def,
- members}).
-
- % EnumDef, page 6-20
--record(ir_EnumDef, {ir_Internal_ID, %[TypedefDef]
- def_kind, %from IRObject
- id, %from Contained
- name, %from Contained
- version, %from Contained
- defined_in, %from Contained
- absolute_name, %from Contained
- containing_repository, %from Contained
- type, %from IDLType
- members}).
-
- % AliasDef, page 6-21
--record(ir_AliasDef, {ir_Internal_ID, %[TypedefDef]
- def_kind, %from IRObject
- id, %from Contained
- name, %from Contained
- version, %from Contained
- defined_in, %from Contained
- absolute_name, %from Contained
- containing_repository, %from Contained
- type, %from IDLType
- original_type_def}).
-
- % PrimitiveDef, page 6-21
--record(ir_PrimitiveDef, {ir_Internal_ID, %[IDLType]
- def_kind, %from IRObject
- type, %from IDLType
- kind}).
-
- % StringDef, page 6-22
--record(ir_StringDef, {ir_Internal_ID, %[IDLType]
- def_kind, %from IRObject
- type, %from IDLType
- bound}).
-
--record(ir_WstringDef, {ir_Internal_ID, %[IDLType]
- def_kind, %from IRObject
- type, %from IDLType
- bound}).
-
- % SequenceDef, page 6-22
--record(ir_SequenceDef, {ir_Internal_ID, %[IDLType]
- def_kind, %from IRObject
- type, %from IDLType
- bound,
- element_type,
- element_type_def}).
-
- % ArrayDef, page 6-23
--record(ir_ArrayDef, {ir_Internal_ID, %[IDLType]
- def_kind, %from IRObject
- type, %from IDLType
- length,
- element_type,
- element_type_def}).
-
- % ExceptionDef, page 6-23
--record(ir_ExceptionDef, {ir_Internal_ID, %[Contained]
- def_kind, %from IRObject
- id, %from Contained
- name, %from Contained
- version, %from Contained
- defined_in, %from Contained
- absolute_name, %from Contained
- containing_repository, %from Contained
- type,
- members}).
-
- % AttributeDef, page 6-24
--record(ir_AttributeDef, {ir_Internal_ID, %[Contained]
- def_kind, %from IRObject
- id, %from Contained
- name, %from Contained
- version, %from Contained
- defined_in, %from Contained
- absolute_name, %from Contained
- containing_repository, %from Contained
- type,
- type_def,
- mode}).
-
- % OperationDef, page 6-25
--record(ir_OperationDef, {ir_Internal_ID, %[Contained]
- def_kind, %from IRObject
- id, %from Contained
- name, %from Contained
- version, %from Contained
- defined_in, %from Contained
- absolute_name, %from Contained
- containing_repository, %from Contained
- result,
- result_def,
- params,
- mode,
- contexts,
- exceptions}).
-
- % InterfaceDef, page 6-27
--record(ir_InterfaceDef, {ir_Internal_ID, %[Container,Contained,IDLType]
- def_kind, %from IRObject
- contents, %from Container
- id, %from Contained
- name, %from Contained
- version, %from Contained
- defined_in, %from Contained
- absolute_name, %from Contained
- containing_repository, %from Contained
- type, %from IDLType
- base_interfaces}).
-
- % TypeCode, page 6-33
-
--record(ir_FixedDef, {ir_Internal_ID, %[IDLType]
- def_kind, %from IRObject
- type, %from IDLType
- digits,
- scale}).
-
-
-% TypeCodes cannot be defined as records, since each type code has a
-% quite unique structure depending on the type. The old TypeCode
-% record definition is left here as a comment in case we want to
-% change back to the old style.
-
-%% ir_TypeCode does not have a field ir_Internal_ID. TypeCodes are
-%% never explicitly written to the database as separate DB-records.
-%% TypeCodes are stored as full records whenever they are used in an
-%% IFR-object.
-%%-record(ir_TypeCode, {kind,
-%% parameter_list}).
-
- % ORB, page 6-39
--record(ir_ORB, {ir_Internal_ID, % *** Do we need any attributes
- dummy}). % for this table? ORB is a pseudo-
- % object so perhaps the table is
- % unnecessary?
-
--record(orber_light_ifr, {id, %% IFR-id
- module,
- type,
- base_id}).
-
--define(IFR_ModuleDef, 0).
--define(IFR_ConstantDef, 1).
--define(IFR_StructDef, 2).
--define(IFR_UnionDef, 3).
--define(IFR_EnumDef, 4).
--define(IFR_AliasDef, 5).
--define(IFR_InterfaceDef, 6).
--define(IFR_ExceptionDef, 7).
-
-
-%%%----------------------------------------------------------------------
-%%% 'ifr_object_list' is used by other modules. Do NOT remove or rename
-%%% this list!
-%%% An addition or deletion of a record above must be duplicated here in
-%%% this list and in the macro 'ifr_record_tuple_list' below.
--define(ifr_object_list, [ir_ModuleDef,
- ir_Contained,
- ir_AttributeDef,
- ir_Repository,
- ir_OperationDef,
- ir_InterfaceDef,
- ir_TypedefDef,
- ir_Container,
- ir_EnumDef,
- ir_UnionDef,
- ir_StringDef,
- ir_WstringDef,
- ir_ORB,
- ir_IDLType,
- ir_ExceptionDef,
- ir_IRObject,
- ir_PrimitiveDef,
- ir_ArrayDef,
- ir_AliasDef,
- ir_ConstantDef,
- ir_StructDef,
- ir_SequenceDef,
- ir_FixedDef]).
-
--define(ifr_light_object_list, [orber_light_ifr]).
-
--define(cr_fun_tuple(Table, Options),
- {Table,
- fun() ->
- case mnesia:create_table(Table,[{attributes,
- record_info(fields,
- Table)}]++Options)of
- {atomic,ok} ->
- ok;
- R ->
- R
- end
- end}
- ).
-
--define(cr_fun_tuple_local(Table, IFR_storage_type),
- {Table,
- fun() ->
- case mnesia:add_table_copy(Table,node(), IFR_storage_type)of
- {atomic,ok} ->
- ok;
- R ->
- R
- end
- end}
- ).
-
--define(ifr_record_tuple_list(Options),
- [?cr_fun_tuple(ir_IRObject, Options),
- ?cr_fun_tuple(ir_Contained, [{index, [#ir_Contained.id]}|Options]),
- ?cr_fun_tuple(ir_Container, Options),
- ?cr_fun_tuple(ir_IDLType, Options),
- ?cr_fun_tuple(ir_Repository, Options),
- ?cr_fun_tuple(ir_ModuleDef, [{index, [#ir_ModuleDef.id]}|Options]),
- ?cr_fun_tuple(ir_ConstantDef, [{index, [#ir_ConstantDef.id]}|Options]),
- ?cr_fun_tuple(ir_TypedefDef, [{index, [#ir_TypedefDef.id]}|Options]),
- ?cr_fun_tuple(ir_StructDef, [{index, [#ir_StructDef.id]}|Options]),
- ?cr_fun_tuple(ir_UnionDef, [{index, [#ir_UnionDef.id]}|Options]),
- ?cr_fun_tuple(ir_EnumDef, [{index, [#ir_EnumDef.id]}|Options]),
- ?cr_fun_tuple(ir_AliasDef, [{index, [#ir_AliasDef.id]}|Options]),
- ?cr_fun_tuple(ir_PrimitiveDef, Options),
- ?cr_fun_tuple(ir_StringDef, Options),
- ?cr_fun_tuple(ir_WstringDef, Options),
- ?cr_fun_tuple(ir_SequenceDef, Options),
- ?cr_fun_tuple(ir_ArrayDef, Options),
- ?cr_fun_tuple(ir_ExceptionDef, [{index, [#ir_ExceptionDef.id]}|Options]),
- ?cr_fun_tuple(ir_AttributeDef, [{index, [#ir_AttributeDef.id]}|Options]),
- ?cr_fun_tuple(ir_OperationDef, [{index, [#ir_OperationDef.id]}|Options]),
- ?cr_fun_tuple(ir_InterfaceDef, [{index, [#ir_InterfaceDef.id]}| Options]),
-% ?cr_fun_tuple(ir_TypeCode, Options),
- ?cr_fun_tuple(ir_ORB, Options),
- ?cr_fun_tuple(ir_FixedDef, Options)]).
-
--define(ifr_light_record_tuple_list(Options),
- [?cr_fun_tuple(orber_light_ifr, Options)]).
-
-
--define(ifr_record_tuple_list_local(IFR_storage_type),
- [?cr_fun_tuple_local(ir_IRObject, IFR_storage_type),
- ?cr_fun_tuple_local(ir_Contained, IFR_storage_type),
- ?cr_fun_tuple_local(ir_Container, IFR_storage_type),
- ?cr_fun_tuple_local(ir_IDLType, IFR_storage_type),
- ?cr_fun_tuple_local(ir_Repository, IFR_storage_type),
- ?cr_fun_tuple_local(ir_ModuleDef, IFR_storage_type),
- ?cr_fun_tuple_local(ir_ConstantDef, IFR_storage_type),
- ?cr_fun_tuple_local(ir_TypedefDef, IFR_storage_type),
- ?cr_fun_tuple_local(ir_StructDef, IFR_storage_type),
- ?cr_fun_tuple_local(ir_UnionDef, IFR_storage_type),
- ?cr_fun_tuple_local(ir_EnumDef, IFR_storage_type),
- ?cr_fun_tuple_local(ir_AliasDef, IFR_storage_type),
- ?cr_fun_tuple_local(ir_PrimitiveDef, IFR_storage_type),
- ?cr_fun_tuple_local(ir_StringDef, IFR_storage_type),
- ?cr_fun_tuple_local(ir_WstringDef, IFR_storage_type),
- ?cr_fun_tuple_local(ir_SequenceDef, IFR_storage_type),
- ?cr_fun_tuple_local(ir_ArrayDef, IFR_storage_type),
- ?cr_fun_tuple_local(ir_ExceptionDef, IFR_storage_type),
- ?cr_fun_tuple_local(ir_AttributeDef, IFR_storage_type),
- ?cr_fun_tuple_local(ir_OperationDef, IFR_storage_type),
- ?cr_fun_tuple_local(ir_InterfaceDef, IFR_storage_type),
-% ?cr_fun_tuple_local(ir_TypeCode, IFR_storage_type),
- ?cr_fun_tuple_local(ir_ORB, IFR_storage_type),
- ?cr_fun_tuple_local(ir_FixedDef, IFR_storage_type)]).
-
--define(ifr_light_record_tuple_list_local(IFR_storage_type),
- [?cr_fun_tuple_local(orber_light_ifr, IFR_storage_type)]).
diff --git a/lib/orber/src/iop_ior.erl b/lib/orber/src/iop_ior.erl
deleted file mode 100644
index a78a6b96e5..0000000000
--- a/lib/orber/src/iop_ior.erl
+++ /dev/null
@@ -1,1717 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: iop_ior.erl
-%% Description:
-%% This file contains the IOP::IOR handling
-%%
-%%-----------------------------------------------------------------
--module(iop_ior).
-
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([code/4, decode/4, string_decode/1,
- string_code/1, string_code/2, string_code/3, string_code/4,
- get_key/1, get_key/2, get_typeID/1, create/9,
- get_objkey/1, check_nil/1, get_privfield/1, set_privfield/2,
- get_orbfield/1, set_orbfield/2,
- get_flagfield/1, set_flagfield/2,
- create_external/5, create_external/6, print/1, print/2,
- get_alt_addr/1, add_component/2, get_peerdata/1]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
-
-%%-----------------------------------------------------------------
-%% Macros
-%%-----------------------------------------------------------------
--define(DEBUG_LEVEL, 6).
-
-
-%%-----------------------------------------------------------------
-%% External interface functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: create/5/6
-%%-----------------------------------------------------------------
-%% There are a few restrictions if a certain IIOP-version may contain certain components
-%% and contexts The ones we currently, and the ones we perhaps will, support is:
-%%
-%% Feature 1.0 1.1 1.2
-%% TransactionService Service Context yes yes yes
-%% CodeSets Service Context yes yes
-%% Object by Value Service Context yes
-%% Bi-Directional IIOP Service Context yes
-%% IOR components in IIOP profile yes yes
-%% TAG_ORB_TYPE yes yes
-%% TAG_CODE_SETS yes yes
-%% TAG_ALTERNATE_IIOP_ADDRESS yes
-%% TAG_SSL_SEC_TRANS yes yes
-%% Extended IDL data types yes yes
-%% Bi-Directional GIOP Features yes
-%% Value types and Abstract Interfaces yes
-%%
-%% CSIv2:
-%% A target that supports unprotected IIOP invocations shall specify in the
-%% corresponding TAG_INTERNET_IOP profile a nonzero port number at which the
-%% target will accept unprotected invocations.9 A target that supports only
-%% protected IIOP invocations shall specify a port number of 0 (zero) in the
-%% corresponding TAG_INTERNET_IOP profile.
-%%-----------------------------------------------------------------
-create({1, 0}, TypeID, Hosts, IIOPPort, _, Objkey, _, _, _) ->
- Template = #'IIOP_ProfileBody_1_0'{iiop_version =
- #'IIOP_Version'{major=1, minor=0},
- port = IIOPPort,
- object_key = Objkey},
- #'IOP_IOR'{type_id=TypeID,
- profiles=duplicate_1_0_profiles(Hosts, Template, [])};
-create({1, Minor}, TypeID, Hosts, IIOPPort, -1, Objkey, MC, _, _) ->
- Template = #'IIOP_ProfileBody_1_1'{iiop_version =
- #'IIOP_Version'{major=1, minor=Minor},
- port = IIOPPort,
- object_key = Objkey,
- components = MC},
- #'IOP_IOR'{type_id=TypeID,
- profiles=duplicate_1_1_profiles(Hosts, Template, [])};
-
-create({1, Minor}, TypeID, Hosts, IIOPPort, SSLPort, Objkey, MC, Flags, EnvFlags) ->
- V=#'IIOP_Version'{major=1, minor=Minor},
- UseCSIv2 = ?ORB_FLAG_TEST(EnvFlags, ?ORB_ENV_USE_CSIV2),
- Template =
- case ?ORB_FLAG_TEST(Flags, ?ORB_NO_SECURITY) of
- true ->
- #'IIOP_ProfileBody_1_1'{iiop_version = V,
- port = IIOPPort,
- object_key = Objkey,
- components = MC};
- false when UseCSIv2 == false ->
- #'IIOP_ProfileBody_1_1'{iiop_version=V,
- port=IIOPPort,
- object_key=Objkey,
- components= [#'IOP_TaggedComponent'
- {tag=?TAG_SSL_SEC_TRANS,
- component_data=#'SSLIOP_SSL'{target_supports = 2,
- target_requires = 2,
- port = SSLPort}}|MC]};
- false when UseCSIv2 == true ->
- #'IIOP_ProfileBody_1_1'
- {iiop_version=V,
- port=0,
- object_key=Objkey,
- components= [#'IOP_TaggedComponent'
- {tag = ?TAG_CSI_SEC_MECH_LIST,
- component_data =
- #'CSIIOP_CompoundSecMechList'
- {stateful = false,
- mechanism_list =
- [#'CSIIOP_CompoundSecMech'
- {target_requires = 6,
- transport_mech =
- #'IOP_TaggedComponent'
- {tag=?TAG_TLS_SEC_TRANS,
- component_data=#'CSIIOP_TLS_SEC_TRANS'
- {target_supports = 7,
- target_requires = 8,
- addresses =
- [#'CSIIOP_TransportAddress'{host_name = "Host",
- port = SSLPort}]}},
- as_context_mech =
- #'CSIIOP_AS_ContextSec'
- {target_supports = 9, target_requires = 10,
- client_authentication_mech = [1, 255],
- target_name = [2,255]},
- sas_context_mech =
- #'CSIIOP_SAS_ContextSec'
- {target_supports = 11, target_requires = 12,
- privilege_authorities =
- [#'CSIIOP_ServiceConfiguration'
- {syntax = ?ULONGMAX,
- name = [3,255]}],
- supported_naming_mechanisms = [[4,255],[5,255]],
- supported_identity_types = ?ULONGMAX}}]}}|MC]}
- end,
- #'IOP_IOR'{type_id=TypeID,
- profiles=duplicate_1_1_profiles(Hosts, Template, [])};
-create(Version, TypeID, Host, IIOPPort, SSLPort, Objkey, MC, _, _) ->
- orber:dbg("[~p] iop_ior:create(~p, ~p, ~p, ~p, ~p, ~p, ~p);~n"
- "Unsupported IIOP-version.",
- [?LINE, Version, TypeID, Host, IIOPPort, SSLPort, Objkey, MC],
- ?DEBUG_LEVEL),
- corba:raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO}).
-
-
-
-
-duplicate_1_1_profiles([], _, Profiles) ->
- Profiles;
-duplicate_1_1_profiles([H|T], Template, Profiles) ->
- duplicate_1_1_profiles(T, Template,
- [#'IOP_TaggedProfile'
- {tag=?TAG_INTERNET_IOP,
- profile_data =
- Template#'IIOP_ProfileBody_1_1'{host = H}}|Profiles]).
-
-duplicate_1_0_profiles([], _, Profiles) ->
- Profiles;
-duplicate_1_0_profiles([H|T], Template, Profiles) ->
- duplicate_1_0_profiles(T, Template,
- [#'IOP_TaggedProfile'
- {tag=?TAG_INTERNET_IOP,
- profile_data =
- Template#'IIOP_ProfileBody_1_0'{host = H}}|Profiles]).
-
-
-%%-----------------------------------------------------------------
-%% Func: create_external/5/6
-%%-----------------------------------------------------------------
-create_external(Version, TypeID, Host, IIOP_port, Objkey) ->
- create_external(Version, TypeID, Host, IIOP_port, Objkey, []).
-create_external({1, 0}, TypeID, Host, IIOP_port, Objkey, _MC) ->
- V=#'IIOP_Version'{major=1,
- minor=0},
- PB=#'IIOP_ProfileBody_1_0'{iiop_version=V,
- host=Host,
- port=IIOP_port,
- object_key=Objkey},
- #'IOP_IOR'{type_id=TypeID, profiles=[#'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP,
- profile_data=PB}]};
-create_external({1, 1}, TypeID, Host, IIOP_port, Objkey, Components) ->
- V=#'IIOP_Version'{major=1,
- minor=1},
- PB=#'IIOP_ProfileBody_1_1'{iiop_version=V,
- host=Host,
- port=IIOP_port,
- object_key=Objkey,
- components=Components},
- #'IOP_IOR'{type_id=TypeID,
- profiles=[#'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP,
- profile_data=PB}]};
-create_external({1, 2}, TypeID, Host, IIOP_port, Objkey, Components) ->
- V=#'IIOP_Version'{major=1,
- minor=2},
- PB=#'IIOP_ProfileBody_1_1'{iiop_version=V,
- host=Host,
- port=IIOP_port,
- object_key=Objkey,
- components=Components},
- #'IOP_IOR'{type_id=TypeID,
- profiles=[#'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP,
- profile_data=PB}]};
-create_external(Version, TypeID, Host, IIOP_port, Objkey, MC) ->
- orber:dbg("[~p] iop_ior:create_external(~p, ~p, ~p, ~p, ~p, ~p);~n"
- "Unsupported IIOP-version.",
- [?LINE, Version, TypeID, Host, IIOP_port, Objkey, MC], ?DEBUG_LEVEL),
- corba:raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO}).
-
-%%-----------------------------------------------------------------
-%% Func: get_peerdata/1
-%%-----------------------------------------------------------------
-%% Probably an external IOR.
-get_peerdata(#'IOP_IOR'{} = IOR) ->
- get_peerdata(get_key(IOR), IOR, [], []);
-%% Local object reference.
-get_peerdata(_) ->
- [].
-
-%% "Plain" TCP/IP.
-get_peerdata({'external', {Host, Port, _InitObjkey, Index, TaggedProfile,
- #host_data{protocol = normal,
- csiv2_mech = undefined}}},
- IOR, Acc, Indexes) ->
- Alts = get_alt_addr(TaggedProfile),
- get_peerdata(get_key(IOR, [Index|Indexes]), IOR, [{Host, Port}|Alts] ++ Acc,
- [Index|Indexes]);
-%% "Plain" SSL
-get_peerdata({'external', {Host, _Port, _InitObjkey, Index, TaggedProfile,
- #host_data{protocol = ssl,
- ssl_data = #'SSLIOP_SSL'{port = Port},
- csiv2_mech = undefined}}},
- IOR, Acc, Indexes) ->
- Alts = get_alt_addr(TaggedProfile),
- get_peerdata(get_key(IOR, [Index|Indexes]), IOR, [{Host, Port}|Alts] ++ Acc,
- [Index|Indexes]);
-%% TEMPORARY FIX TO SKIP CSIv2 DATA.
-get_peerdata({'external', {Host, _Port, _InitObjkey, Index, TaggedProfile,
- #host_data{protocol = ssl,
- ssl_data = #'SSLIOP_SSL'{port = Port}}}},
- IOR, Acc, Indexes) ->
- Alts = get_alt_addr(TaggedProfile),
- get_peerdata(get_key(IOR, [Index|Indexes]), IOR, [{Host, Port}|Alts] ++ Acc,
- [Index|Indexes]);
-%% CSIv2 over SSL (TAG_TLS_SEC_TRANS) using the SAS protocol. Note port must equal 0.
-get_peerdata({'external',
- {_Host, 0, _InitObjkey, Index, TaggedProfile,
- #host_data{protocol = ssl,
- csiv2_mech =
- #'CSIIOP_CompoundSecMech'{target_requires = _TR} = _Mech,
- csiv2_addresses = Addresses}}},
- IOR, Acc, Indexes) ->
- Alts = get_alt_addr(TaggedProfile),
- get_peerdata(get_key(IOR, [Index|Indexes]), IOR, Addresses ++ Alts ++ Acc,
- [Index|Indexes]);
-%% CSIv2 over SSL (TAG_NULL_TAG) using the SAS protocol.
-get_peerdata({'external',
- {Host, _Port, _InitObjkey, Index, TaggedProfile,
- #host_data{protocol = ssl,
- ssl_data = #'SSLIOP_SSL'{port = Port},
- csiv2_mech = Mech}}},
- IOR, Acc, Indexes) when is_record(Mech, 'CSIIOP_CompoundSecMech') ->
- Alts = get_alt_addr(TaggedProfile),
- get_peerdata(get_key(IOR, [Index|Indexes]), IOR, [{Host, Port}|Alts] ++ Acc,
- [Index|Indexes]);
-%% CSIv2 over TCP (TAG_NULL_TAG) using the SAS protocol.
-get_peerdata({'external',
- {Host, Port, _InitObjkey, Index, TaggedProfile,
- #host_data{protocol = normal,
- csiv2_mech = Mech}}},
- IOR, Acc, Indexes) when is_record(Mech, 'CSIIOP_CompoundSecMech') ->
- Alts = get_alt_addr(TaggedProfile),
- get_peerdata(get_key(IOR, [Index|Indexes]), IOR, [{Host, Port}|Alts] ++ Acc,
- [Index|Indexes]);
-get_peerdata(undefined, _IOR, Acc, _Indexes) ->
- Acc;
-%% Local object reference.
-get_peerdata(_, _, _, _) ->
- [].
-
-%%-----------------------------------------------------------------
-%% Func: get_key/1
-%%-----------------------------------------------------------------
-get_key(#'IOP_IOR'{profiles=P}) ->
- get_key_1(P, false, 0, undefined, #host_data{});
-get_key({Module, Type, Key, _UserDef, OrberDef, Flags}) ->
- if
- is_binary(Key) ->
- {'internal', Key, OrberDef, Flags, Module};
- Type == pseudo ->
- {'internal_registered', {pseudo, Key}, OrberDef, Flags, Module};
- is_atom(Key) ->
- {'internal_registered', Key, OrberDef, Flags, Module}
- end;
-get_key(What) ->
- orber:dbg("[~p] iop_ior:get_key(~p); Invalid IOR",
- [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO}).
-
-
-get_key(#'IOP_IOR'{profiles=P}, Exclude) ->
- get_key_1(P, true, 0, Exclude, #host_data{});
-get_key(What, _Exclude) ->
- orber:dbg("[~p] iop_ior:get_key(~p); Invalid IOR",
- [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO}).
-
-
-get_key_1([], false, _, _, _) ->
- orber:dbg("[~p] iop_ior:get_key_1([]); bad object reference, profile not found.",
- [?LINE], ?DEBUG_LEVEL),
- corba:raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO});
-get_key_1([], true, _, _, _) ->
- undefined;
-%%--------- Local IIOP-1.0 Profile ---------
-get_key_1([#'IOP_TaggedProfile'
- {tag=?TAG_INTERNET_IOP,
- profile_data=#'IIOP_ProfileBody_1_0'
- {object_key={Module, Type, Key, _UserDef, OrberDef, Flags}}}|_],
- _Retry, _Counter, _Exclude, _HD) ->
- if
- is_binary(Key) ->
- {'internal', Key, OrberDef, Flags, Module};
- Type == pseudo ->
- {'internal_registered', {pseudo, Key}, OrberDef, Flags, Module};
- is_atom(Key) ->
- {'internal_registered', Key, OrberDef, Flags, Module}
- end;
-%%--------- Local IIOP-1.1 & IIOP-1.2 Profiles ---------
-get_key_1([#'IOP_TaggedProfile'
- {tag=?TAG_INTERNET_IOP,
- profile_data=#'IIOP_ProfileBody_1_1'
- {object_key={Module, Type, Key, _UserDef, OrberDef, Flags}}}|_],
- _Retry, _Counter, _Exclude, _HD) ->
- if
- is_binary(Key) ->
- {'internal', Key, OrberDef, Flags, Module};
- Type == pseudo ->
- {'internal_registered', {pseudo, Key}, OrberDef, Flags, Module};
- Type == passive ->
- %% CHECK FOR PRIMARY COMPONENT & GROUPID! Better yet, do not.
- %% This is internal key and is supposed to be well formed.
- %% Also, internal keys are not searched for primary member or
- %% groupid in the component-section of IOR. ObjectKey will tell
- %% GroupID and database read transaction will tell primary member.
- {'internal_registered', {passive, Key}, OrberDef, Flags, Module};
- is_atom(Key) ->
- {'internal_registered', Key, OrberDef, Flags, Module}
- end;
-%%--------- External IIOP-1.0 Profile ---------
-get_key_1([#'IOP_TaggedProfile'
- {tag=?TAG_INTERNET_IOP,
- profile_data=#'IIOP_ProfileBody_1_0'
- {host = Host, port = Port, object_key= ObjectKey}} = TP|P],
- _Retry, Counter, Exclude, HD) when Exclude == undefined ->
- %% This case is "necessary" if an ORB adds several IIOP-profiles since,
- %% for example, wchar isn't supported for 1.0.
- case get_key_1(P, true, Counter+1, Exclude, HD) of
- undefined ->
- %% We now it's IIOP-1.0 and it doesn't contain any
- %% components. Hence, no need to check for it.
- {'external', {Host, Port, ObjectKey, Counter, TP,
- HD#host_data{version = {1,0}}}};
- LaterVersion ->
- LaterVersion
- end;
-get_key_1([#'IOP_TaggedProfile'
- {tag=?TAG_INTERNET_IOP,
- profile_data=#'IIOP_ProfileBody_1_0'
- {host = Host, port = Port, object_key= ObjectKey}} = TP|P],
- Retry, Counter, Exclude, HD) ->
- case lists:member(Counter, Exclude) of
- true ->
- get_key_1(P, Retry, Counter+1, Exclude, HD);
- false ->
- %% This case is "necessary" if an ORB adds several IIOP-profiles since,
- %% for example, wchar isn't supported for 1.0.
- case get_key_1(P, true, Counter+1, Exclude, HD) of
- undefined ->
- {'external', {Host, Port, ObjectKey, Counter, TP,
- HD#host_data{version = {1,0}}}};
- LaterVersion ->
- LaterVersion
- end
- end;
-%%--------- External IIOP-1.1 & IIOP-1.2 Profiles ---------
-get_key_1([#'IOP_TaggedProfile'
- {tag=?TAG_INTERNET_IOP,
- profile_data=#'IIOP_ProfileBody_1_1'
- {iiop_version = #'IIOP_Version'{major=Major, minor=Minor},
- host = Host, port = Port, object_key= ObjectKey,
- components = Components}} = TP|P],
- Retry, Counter, Exclude, HD) when Exclude == undefined ->
- case check_components(Components, Port, HD#host_data{version = {Major,Minor}}) of
- #host_data{csiv2_mech = undefined} when Port == 0 ->
- get_key_1(P, Retry, Counter+1, Exclude, HD);
- NewHD ->
- {'external', {Host, Port, ObjectKey, Counter, TP, NewHD}}
- end;
-get_key_1([#'IOP_TaggedProfile'
- {tag=?TAG_INTERNET_IOP,
- profile_data=#'IIOP_ProfileBody_1_1'
- {iiop_version = #'IIOP_Version'{major=Major, minor=Minor},
- host = Host, port = Port, object_key= ObjectKey,
- components = Components}} = TP|P],
- Retry, Counter, Exclude, HD) ->
- case lists:member(Counter, Exclude) of
- true ->
- get_key_1(P, Retry, Counter+1, Exclude, HD);
- false ->
- case check_components(Components, Port,
- HD#host_data{version = {Major,Minor}}) of
- #host_data{csiv2_mech = undefined} when Port == 0 ->
- get_key_1(P, Retry, Counter+1, Exclude, HD);
- NewHD ->
- {'external', {Host, Port, ObjectKey, Counter, TP, NewHD}}
- end
- end;
-get_key_1([_ | P], Retry, Counter, Exclude, HD) ->
- get_key_1(P, Retry, Counter+1, Exclude, HD).
-
-check_components([], _, HostData) ->
- HostData;
-check_components([#'IOP_TaggedComponent'{tag=?TAG_SSL_SEC_TRANS,
- component_data=SSLStruct}|Rest],
- Port, HostData) when is_record(SSLStruct, 'SSLIOP_SSL') ->
- check_components(Rest, Port, HostData#host_data{protocol = ssl,
- ssl_data = SSLStruct});
-%% CSIv2 Components
-check_components([#'IOP_TaggedComponent'{tag=?TAG_CSI_SEC_MECH_LIST,
- component_data=Data}|Rest],
- Port, HostData) when is_record(Data, 'CSIIOP_CompoundSecMechList') ->
- case check_sec_mech(Data#'CSIIOP_CompoundSecMechList'.mechanism_list, Port) of
- undefined ->
- check_components(Rest, Port, HostData);
- {ok, Protocol, Mech, Addresses} ->
- check_components(Rest, Port,
- HostData#host_data
- {protocol = Protocol,
- csiv2_mech = Mech,
- csiv2_statefull = Data#'CSIIOP_CompoundSecMechList'.stateful,
- csiv2_addresses = Addresses});
- {ok, Mech} ->
- check_components(Rest, Port,
- HostData#host_data
- {csiv2_mech = Mech,
- csiv2_statefull = Data#'CSIIOP_CompoundSecMechList'.stateful})
- end;
-%% FT Components
-check_components([#'IOP_TaggedComponent'
- {tag=?TAG_FT_HEARTBEAT_ENABLED,
- component_data=
- #'FT_TagFTHeartbeatEnabledTaggedComponent'
- {heartbeat_enabled = Boolean}}|Rest],
- Port, HostData) ->
- check_components(Rest, Port, HostData#host_data{ft_heartbeat = Boolean});
-check_components([#'IOP_TaggedComponent'
- {tag=?TAG_FT_PRIMARY,
- component_data=
- #'FT_TagFTPrimaryTaggedComponent'{primary = Boolean}}|Rest],
- Port, HostData) ->
- check_components(Rest, Port, HostData#host_data{ft_primary = Boolean});
-check_components([#'IOP_TaggedComponent'
- {tag=?TAG_FT_GROUP,
- component_data=#'FT_TagFTGroupTaggedComponent'
- {version = #'GIOP_Version'{major = 1, minor = 0},
- ft_domain_id = FTDomain,
- object_group_id = GroupID,
- object_group_ref_version = GroupVer}}|Rest],
- Port, HostData) ->
- check_components(Rest, Port, HostData#host_data{ft_domain = FTDomain,
- ft_group = GroupID,
- ft_ref_version = GroupVer});
-%% CodeSets Component
-check_components([#'IOP_TaggedComponent'{tag=?TAG_CODE_SETS,
- component_data=#'CONV_FRAME_CodeSetComponentInfo'
- {'ForCharData' = Char,
- 'ForWcharData' = Wchar}}|Rest],
- Port, HostData) ->
- CharData = check_char_codeset(Char),
- WcharData = check_wchar_codeset(Wchar),
- check_components(Rest, Port, HostData#host_data{charset = CharData,
- wcharset = WcharData});
-%% Not used
-check_components([_ | Rest], Port, HostData) ->
- check_components(Rest, Port, HostData).
-
-check_sec_mech([], _) ->
- undefined;
-%% Not supported yet.
-%check_sec_mech([#'CSIIOP_CompoundSecMech'
-% {target_requires = TR,
-% transport_mech=
-% #'IOP_TaggedComponent'{tag=?TAG_SECIOP_SEC_TRANS}} = Mech|_],
-% Port) ->
-% {ok, seciop, Mech};
-check_sec_mech([#'CSIIOP_CompoundSecMech'
- {target_requires = TR,
- transport_mech=
- #'IOP_TaggedComponent'{tag = ?TAG_TLS_SEC_TRANS,
- component_data = CD}} = Mech|_], _Port)
- when TR =< ?CSIv2_MAX_TARGET_REQUIRES ->
- {ok, ssl, Mech, extract_host_port(CD#'CSIIOP_TLS_SEC_TRANS'.addresses, [])};
-%% The TAG_NULL_TAG component shall be used in the 'transport_mech' field to
-%% indicate that a mechanism does not implement security functionality at the
-%% transport layer.
-%% If the port field in TAG_INTERNET_IOP equals 0 we must find a TAG_TLS_SEC_TRANS
-%% or TAG_SECIOP_SEC_TRANS mechanism.
-check_sec_mech([#'CSIIOP_CompoundSecMech'
- {transport_mech=
- #'IOP_TaggedComponent'{tag = ?TAG_NULL_TAG}}|Rest], 0) ->
- check_sec_mech(Rest, 0);
-check_sec_mech([#'CSIIOP_CompoundSecMech'
- {target_requires = TR,
- transport_mech=
- #'IOP_TaggedComponent'{tag = ?TAG_NULL_TAG}} = Mech|_], _Port)
- when TR =< ?CSIv2_MAX_TARGET_REQUIRES ->
- {ok, Mech};
-%% Unrecognized or the peer requires more than we support.
-check_sec_mech([_ | Rest], Port) ->
- check_sec_mech(Rest, Port).
-
-extract_host_port([], Acc) ->
- Acc;
-extract_host_port([#'CSIIOP_TransportAddress'{host_name = Host,
- port = Port}|Rest], Acc) ->
- extract_host_port(Rest, [{Host, Port}|Acc]).
-
-
-check_char_codeset(#'CONV_FRAME_CodeSetComponent'{native_code_set=?ISO8859_1_ID}) ->
- ?ISO8859_1_ID;
-check_char_codeset(#'CONV_FRAME_CodeSetComponent'{native_code_set=?ISO646_IRV_ID}) ->
- ?ISO646_IRV_ID;
-check_char_codeset(#'CONV_FRAME_CodeSetComponent'{conversion_code_sets=Converters}) ->
- %% Since the list of Converters usually is very short (0 or 1 element) we
- %% can use lists:member.
- case lists:member(?ISO8859_1_ID, Converters) of
- true ->
- ?ISO8859_1_ID;
- false ->
- %% Since we are 100% sure strings will be (e.g. IFR-ids) used we
- %% can raise an exception at this point.
- orber:dbg("[~p] iop_ior:check_char_codeset(~p);~n"
- "Orber cannot communicate with this ORB.~n"
- "It doesn't support a Char CodeSet known to Orber.",
- [?LINE, Converters], ?DEBUG_LEVEL),
- corba:raise(#'INV_OBJREF'{completion_status = ?COMPLETED_NO})
- end.
-
-check_wchar_codeset(#'CONV_FRAME_CodeSetComponent'{native_code_set=?UTF_16_ID}) ->
- ?UTF_16_ID;
-check_wchar_codeset(#'CONV_FRAME_CodeSetComponent'{native_code_set=?UCS_2_ID}) ->
- ?UCS_2_ID;
-check_wchar_codeset(#'CONV_FRAME_CodeSetComponent'{conversion_code_sets=Converters}) ->
- case lists:member(?UTF_16_ID, Converters) of
- true ->
- ?UTF_16_ID;
- false ->
- %% We should not raise an exception here since we do not know if
- %% wchar/wstring is used.
- ?UTF_16_ID
-% ?UNSUPPORTED_WCHAR
- end.
-
-
-%%-----------------------------------------------------------------
-%% Func: add_component/2
-%%-----------------------------------------------------------------
-add_component(Objref, Component) when is_record(Objref, 'IOP_IOR') ->
- add_component_ior(Objref, Component);
-add_component(Objref, Component) ->
- add_component_local(Objref, Component, orber:giop_version()).
-
-add_component_local(_, Component, {1,0}) ->
- orber:dbg("[~p] iop_ior:add_component(~p);~n"
- "IIOP-1.0 objects cannot contain any components.",
- [?LINE, Component], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status = ?COMPLETED_NO});
-add_component_local(_, #'IOP_TaggedComponent'{tag = ?TAG_ALTERNATE_IIOP_ADDRESS}
- = Component, {1,1}) ->
- orber:dbg("[~p] iop_ior:add_component(~p);~n"
- "IIOP-1.1 objects may not contain ALTERNATE_IIOP_ADDRESS components.",
- [?LINE, Component], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status = ?COMPLETED_NO});
-add_component_local({Mod, Type, Key, UserDef, OrberDef, Flags}, Component, Version) ->
- EnvFlags = orber:get_flags(),
- MC = case ?ORB_FLAG_TEST(EnvFlags, ?ORB_ENV_EXCLUDE_CODESET_COMPONENT) of
- true ->
- [Component];
- false ->
- [#'IOP_TaggedComponent'{tag=?TAG_CODE_SETS,
- component_data=?DEFAULT_CODESETS},
- Component]
- end,
- case ?ORB_FLAG_TEST(EnvFlags, ?ORB_ENV_ENABLE_NAT) of
- false ->
- create(Version, Mod:typeID(), orber:host(), orber:iiop_port(),
- orber:iiop_ssl_port(),
- {Mod, Type, Key, UserDef, OrberDef, Flags},
- MC, Flags, EnvFlags);
- true ->
- create(Version, Mod:typeID(), orber:nat_host(),
- orber:nat_iiop_port(), orber:nat_iiop_ssl_port(),
- {Mod, Type, Key, UserDef, OrberDef, Flags},
- MC, Flags, EnvFlags)
-
- end.
-
-add_component_ior(#'IOP_IOR'{profiles=P} = IOR, Component) ->
- case add_component_ior_helper(P, Component, false, []) of
- {false, _} ->
- orber:dbg("[~p] iop_ior:add_component_ior(~p);~n"
- "The IOR do not contain a valid IIOP-version for the supplied component.",
- [?LINE, Component], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status = ?COMPLETED_NO});
- {_, NewProfiles} ->
- IOR#'IOP_IOR'{profiles=NewProfiles}
- end.
-
-add_component_ior_helper([], _Component, Status, Acc) ->
- {Status, Acc};
-add_component_ior_helper([#'IOP_TaggedProfile'
- {tag=?TAG_INTERNET_IOP,
- profile_data=#'IIOP_ProfileBody_1_1'
- {iiop_version= #'IIOP_Version'{minor=1}}}|T],
- #'IOP_TaggedComponent'{tag = ?TAG_ALTERNATE_IIOP_ADDRESS}
- = Component, Status, Acc) ->
- %% 'ALTERNATE_IIOP_ADDRESS' may only be added to IIOP-1.2 IOR's.
- add_component_ior_helper(T, Component, Status, Acc);
-add_component_ior_helper([#'IOP_TaggedProfile'
- {tag=?TAG_INTERNET_IOP,
- profile_data=#'IIOP_ProfileBody_1_1'
- {object_key=Objkey,
- components=Components} = PB} = H|T],
- Component, _Status, Acc) when is_tuple(Objkey) ->
- %% The objectkey must be a tuple if it's a local object. We cannot(!!) add components
- %% to an external IOR.
- add_component_ior_helper(T, Component, true,
- [H#'IOP_TaggedProfile'
- {profile_data=PB#'IIOP_ProfileBody_1_1'
- {components = [Component|Components]}}|Acc]);
-add_component_ior_helper([_|T], Component, Status, Acc) ->
- add_component_ior_helper(T, Component, Status, Acc).
-
-%%-----------------------------------------------------------------
-%% Func: get_alt_addr/1
-%%-----------------------------------------------------------------
-%% TAG_ALTERNATE_IIOP_ADDRESS may only occur in IIOP-1.2 IOR's.
-get_alt_addr(#'IOP_TaggedProfile'
- {tag=?TAG_INTERNET_IOP,
- profile_data=#'IIOP_ProfileBody_1_1'{iiop_version=
- #'IIOP_Version'{minor=2},
- components=Components}}) ->
- get_alt_addr_helper(Components, []);
-get_alt_addr(_) ->
- [].
-
-get_alt_addr_helper([], Acc) -> Acc;
-get_alt_addr_helper([#'IOP_TaggedComponent'{tag=?TAG_ALTERNATE_IIOP_ADDRESS,
- component_data=#'ALTERNATE_IIOP_ADDRESS'
- {'HostID'=Host, 'Port'=Port}}|T], Acc) ->
- get_alt_addr_helper(T, [{Host, Port}|Acc]);
-get_alt_addr_helper([_|T], Acc) ->
- get_alt_addr_helper(T, Acc).
-
-%%-----------------------------------------------------------------
-%% Func: get_typeID/1
-%%-----------------------------------------------------------------
-get_typeID(#'IOP_IOR'{type_id=TypeID}) ->
- TypeID;
-get_typeID({Mod, _Type, _Key, _UserDef, _OrberDef, _Flags}) ->
- Mod:typeID().
-
-%%-----------------------------------------------------------------
-%% Func: get_objkey/1
-%%-----------------------------------------------------------------
-get_objkey(#'IOP_IOR'{profiles=P}) ->
- get_objkey_1(P);
-get_objkey({Id, Type, Key, UserDef, OrberDef, Flags}) ->
- {Id, Type, Key, UserDef, OrberDef, Flags}.
-
-get_objkey_1([]) ->
- orber:dbg("[~p] iop_ior:get_objkey_1([]); bad object key, profile not found.",
- [?LINE], ?DEBUG_LEVEL),
- corba:raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO});
-get_objkey_1([#'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB} |_]) ->
- [_, _, _, _, ObjectKey | _] = tuple_to_list(PB),
- ObjectKey;
-get_objkey_1([_ | P]) ->
- get_objkey_1(P).
-
-%%-----------------------------------------------------------------
-%% Func: get_privfield/1
-%%-----------------------------------------------------------------
-get_privfield(#'IOP_IOR'{profiles=P}) ->
- get_privfield_1(P);
-get_privfield({_Id, _Type, _Key, UserDef, _OrberDef, _Flags}) ->
- UserDef.
-
-get_privfield_1([]) ->
- orber:dbg("[~p] iop_ior:get_privfield_1([]); bad object key, profile not found.",
- [?LINE], ?DEBUG_LEVEL),
- corba:raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO});
-get_privfield_1([#'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB}|_]) ->
- [_, _, _, _, ObjectKey | _] = tuple_to_list(PB),
- case ObjectKey of
- {_Id, _Type, _Key, UserDef, _OrberDef, _Flags} ->
- UserDef;
- _ ->
- orber:dbg("[~p] iop_ior:get_privfield_1(~p); bad object key.",
- [?LINE, ObjectKey], ?DEBUG_LEVEL),
- corba:raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO})
- end;
-get_privfield_1([_| P]) ->
- get_privfield_1(P).
-
-%%-----------------------------------------------------------------
-%% Func: set_privfield/2
-%%-----------------------------------------------------------------
-set_privfield(#'IOP_IOR'{type_id=Id, profiles=P}, UserData) ->
- #'IOP_IOR'{type_id=Id, profiles=set_privfield_1(P, UserData)};
-set_privfield({Id, Type, Key, _, OrberDef, Flags}, UserData) ->
- {Id, Type, Key, UserData, OrberDef, Flags}.
-
-set_privfield_1([], _) ->
- orber:dbg("[~p] iop_ior:set_privfield_1([]); bad object key, profile not found or external object.",
- [?LINE], ?DEBUG_LEVEL),
- corba:raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO});
-set_privfield_1([#'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB}|P], UserData) ->
- [RecName, Version, Host, IIOP_port, ObjectKey | Rest] = tuple_to_list(PB),
- case ObjectKey of
- {Id, Type, Key, _, OrberDef, Flags} ->
- [#'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP,
- profile_data=list_to_tuple([RecName,
- Version, Host,
- IIOP_port,
- {Id, Type, Key, UserData, OrberDef, Flags}|
- Rest])} |
- set_privfield_1(P, UserData)];
- _ ->
- [#'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB} | set_privfield_1(P, UserData)]
- end;
-set_privfield_1([PB| P], UserData) ->
- [PB | set_privfield_1(P, UserData)].
-
-%%-----------------------------------------------------------------
-%% Func: get_orbfield/1
-%%-----------------------------------------------------------------
-get_orbfield(#'IOP_IOR'{profiles=P}) ->
- get_orbfield_1(P);
-get_orbfield({_Id, _Type, _Key, _UserDef, OrberDef, _Flags}) ->
- OrberDef.
-
-get_orbfield_1([]) ->
- orber:dbg("[~p] iop_ior:get_orbfield_1([]);~n"
- "bad object key, profile not found.", [?LINE], ?DEBUG_LEVEL),
- corba:raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO});
-get_orbfield_1([#'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB}|_]) ->
- [_, _, _, _, ObjectKey | _] = tuple_to_list(PB),
- case ObjectKey of
- {_Id, _Type, _Key, _UserDef, OrberDef, _Flags} ->
- OrberDef;
- _ ->
- orber:dbg("[~p] iop_ior:get_orbfield_1(~p);~n"
- "bad object key.", [?LINE, ObjectKey], ?DEBUG_LEVEL),
- corba:raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO})
- end;
-get_orbfield_1([_| P]) ->
- get_orbfield_1(P).
-
-%%-----------------------------------------------------------------
-%% Func: set_orbfield/2
-%%-----------------------------------------------------------------
-set_orbfield(#'IOP_IOR'{type_id=Id, profiles=P}, OrberDef) ->
- #'IOP_IOR'{type_id=Id, profiles=set_orbfield_1(P, OrberDef)};
-set_orbfield({Id, Type, Key, Priv, _, Flags}, OrberDef) ->
- {Id, Type, Key, Priv, OrberDef, Flags}.
-
-set_orbfield_1([], _) ->
- orber:dbg("[~p] iop_ior:set_orbfield_1([]);~n"
- "bad object key, profile not found or external object.",
- [?LINE], ?DEBUG_LEVEL),
- corba:raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO});
-set_orbfield_1([#'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB}| P], OrberDef) ->
- [RecName, Version, Host, IIOP_port, ObjectKey | Rest] = tuple_to_list(PB),
- case ObjectKey of
- {Id, Type, Key, Priv, _, Flags} ->
- [#'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP,
- profile_data=list_to_tuple([RecName,
- Version, Host,
- IIOP_port,
- {Id, Type, Key, Priv, OrberDef, Flags}|
- Rest])} |
- set_orbfield_1(P, OrberDef)];
- _ ->
- [#'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB} | set_orbfield_1(P, OrberDef)]
- end;
-set_orbfield_1([PB| P], OrberDef) ->
- [PB | set_orbfield_1(P, OrberDef)].
-
-%%-----------------------------------------------------------------
-%% Func: get_flagfield/1
-%%-----------------------------------------------------------------
-get_flagfield(#'IOP_IOR'{profiles=P}) ->
- get_flagfield_1(P);
-get_flagfield({_Id, _Type, _Key, _UserDef, _OrberDef, Flags}) ->
- Flags.
-
-get_flagfield_1([]) ->
- orber:dbg("[~p] iop_ior:get_flagfield_1([]); bad object key, profile not found.",
- [?LINE], ?DEBUG_LEVEL),
- corba:raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO});
-get_flagfield_1([#'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB}|_]) ->
- [_, _, _, _, ObjectKey | _] = tuple_to_list(PB),
- case ObjectKey of
- {_Id, _Type, _Key, _UserDef, _OrberDef, Flags} ->
- Flags;
- _ ->
- orber:dbg("[~p] iop_ior:get_flagfield_1(~p); bad object key.",
- [?LINE, ObjectKey], ?DEBUG_LEVEL),
- corba:raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO})
- end;
-get_flagfield_1([_| P]) ->
- get_flagfield_1(P).
-
-%%-----------------------------------------------------------------
-%% Func: set_flagfield/2
-%%-----------------------------------------------------------------
-set_flagfield(#'IOP_IOR'{type_id=Id, profiles=P}, Flags) ->
- #'IOP_IOR'{type_id=Id, profiles=set_flagfield_1(P, Flags)};
-set_flagfield({Id, Type, Key, Priv, OrberDef, _}, Flags) ->
- {Id, Type, Key, Priv, OrberDef, Flags}.
-
-set_flagfield_1([], _) ->
- orber:dbg("[~p] iop_ior:set_flagfield_1([]); bad object key, profile not found or external object.",
- [?LINE], ?DEBUG_LEVEL),
- corba:raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO});
-set_flagfield_1([#'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB}| P], Flags) ->
- [RecName, Version, Host, IIOP_port, ObjectKey | Rest] = tuple_to_list(PB),
- case ObjectKey of
- {Id, Type, Key, Priv, OrberDef, _} ->
- [#'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP,
- profile_data=list_to_tuple([RecName,
- Version, Host,
- IIOP_port,
- {Id, Type, Key, Priv, OrberDef, Flags}|
- Rest])} |
- set_flagfield_1(P, Flags)];
- _ ->
- [#'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB} | set_flagfield_1(P, Flags)]
- end;
-set_flagfield_1([PB| P], Flags) ->
- [PB | set_flagfield_1(P, Flags)].
-
-%%-----------------------------------------------------------------
-%% Func: check_nil/1
-%%-----------------------------------------------------------------
-check_nil(#'IOP_IOR'{type_id="", profiles=[]}) ->
- true;
-check_nil({Id, _, _, _, _, _}) when is_atom(Id) ->
- false;
-check_nil({Id, _, _, _, _, _}) ->
- case binary_to_list(Id) of
- "" ->
- true;
- _ ->
- false
- end;
-check_nil(_) ->
- false.
-
-
-
-%%----------------------------------------------------------------------
-%% Function : print
-%% Arguments : An object represented as one of the following:
-%% - local (tuple)
-%% - IOR
-%% - stringified IOR
-%% - corbaloc- or corbaname-schema
-%% IoDevice - the same as the io-module defines.
-%% Returns :
-%% Description: Prints the object's components.
-%%----------------------------------------------------------------------
-print(Object) ->
- print(undefined, Object).
-print(IoDevice, #'IOP_IOR'{type_id="", profiles=[]}) ->
- print_it(IoDevice,
- "================== IOR ====================~n"
- "NIL Object Reference.~n"
- "================== END ====================~n");
-print(IoDevice, IORStr) when is_list(IORStr) ->
- IOR = corba:string_to_object(IORStr),
- print_helper(IoDevice, IOR);
-print(IoDevice, IOR) when is_record(IOR, 'IOP_IOR') ->
- print_helper(IoDevice, IOR);
-print(IoDevice, {Mod, Type, Key, UserDef, OrberDef, Flags}) ->
- EnvFlags = orber:get_flags(),
- MC = case ?ORB_FLAG_TEST(EnvFlags, ?ORB_ENV_EXCLUDE_CODESET_COMPONENT) of
- true ->
- [];
- false ->
- [#'IOP_TaggedComponent'{tag=?TAG_CODE_SETS,
- component_data=?DEFAULT_CODESETS}]
- end,
- IOR = case ?ORB_FLAG_TEST(EnvFlags, ?ORB_ENV_ENABLE_NAT) of
- false ->
- create(orber:giop_version(), Mod:typeID(), orber:host(),
- orber:iiop_port(), orber:iiop_ssl_port(),
- {Mod, Type, Key, UserDef, OrberDef, Flags},
- MC, Flags, EnvFlags);
- true ->
- create(orber:giop_version(), Mod:typeID(), orber:nat_host(),
- orber:nat_iiop_port(), orber:nat_iiop_ssl_port(),
- {Mod, Type, Key, UserDef, OrberDef, Flags},
- MC, Flags, EnvFlags)
-
- end,
- print_helper(IoDevice, IOR);
-print(_, _) ->
- exit("Bad parameter").
-
-print_helper(IoDevice, #'IOP_IOR'{type_id=TypeID, profiles=Profs}) ->
- Data = io_lib:format("================== IOR ====================~n"
- "------------------ IFR ID -----------------~n~s~n",
- [TypeID]),
- NewData = print_profiles(Profs, []),
- print_it(IoDevice, lists:flatten([Data|NewData])).
-
-print_profiles([], Acc) ->
- lists:flatten([Acc | io_lib:format("================== END ====================~n", [])]);
-print_profiles([#'IOP_TaggedProfile'
- {tag=?TAG_INTERNET_IOP,
- profile_data = #'IIOP_ProfileBody_1_0'{iiop_version=
- #'IIOP_Version'{major=Major,
- minor=Minor},
- host=Host, port=Port,
- object_key=Objkey}}|T], Acc) ->
- Profile = io_lib:format("~n------------------ IIOP Profile -----------~n"
- "Version.............: ~p.~p~n"
- "Host................: ~s~n"
- "Port................: ~p~n",
- [Major, Minor, Host, Port]),
- ObjKeyStr = print_objkey(Objkey),
- print_profiles(T, [Profile, ObjKeyStr | Acc]);
-print_profiles([#'IOP_TaggedProfile'
- {tag=?TAG_INTERNET_IOP,
- profile_data = #'IIOP_ProfileBody_1_1'{iiop_version=
- #'IIOP_Version'{major=Major,
- minor=Minor},
- host=Host,
- port=Port,
- object_key=Objkey,
- components=Components}}|T], Acc) ->
- Profile = io_lib:format("~n------------------ IIOP Profile -----------~n"
- "Version.............: ~p.~p~n"
- "Host................: ~s~n"
- "Port................: ~p~n",
- [Major, Minor, Host, Port]),
- ComponentsStr = print_components(Components, []),
- ObjKeyStr = print_objkey(Objkey),
- print_profiles(T, [Profile, ObjKeyStr, ComponentsStr |Acc]);
-print_profiles([#'IOP_TaggedProfile'{tag=?TAG_MULTIPLE_COMPONENTS,
- profile_data = Components}|T], Acc) ->
- MComp = io_lib:format("~n------------------ Multiple Components ----~n", []),
- ComponentsStr = print_components(Components, []),
- print_profiles(T, [MComp, ComponentsStr | Acc]);
-print_profiles([#'IOP_TaggedProfile'{tag=?TAG_SCCP_IOP,
- profile_data = _Data}|T], Acc) ->
- SCCP = io_lib:format("~n------------------ SCCP IOP ---------------~n", []),
- print_profiles(T, [SCCP | Acc]);
-print_profiles([#'IOP_TaggedProfile'{tag=Tag,
- profile_data = Data}|T], Acc) ->
- TAG = io_lib:format("~n------------------ TAG ~p -----------------~n"
- "Data................: ~p~n", [Tag, Data]),
- print_profiles(T, [TAG|Acc]).
-
-print_components([], Data) -> lists:flatten(lists:reverse(Data));
-print_components([#'IOP_TaggedComponent'{tag=?TAG_ORB_TYPE,
- component_data=ORB}|T], Data) ->
- OType = io_lib:format(" TAG_ORB_TYPE~n"
- "ORB Type............: ~p~n", [ORB]),
- print_components(T, [OType | Data]);
-print_components([#'IOP_TaggedComponent'{tag=?TAG_CODE_SETS,
- component_data=
- #'CONV_FRAME_CodeSetComponentInfo'
- {'ForCharData' = Char,
- 'ForWcharData' = Wchar}}|T], Data) ->
- CharSet = io_lib:format(" TAG_CODE_SETS~n"
- "Native Char.........: ~p~n"
- "Char Conversion.....: ~p~n"
- "Native Wchar........: ~p~n"
- "Wchar Conversion....: ~p~n",
- [Char#'CONV_FRAME_CodeSetComponent'.native_code_set,
- Char#'CONV_FRAME_CodeSetComponent'.conversion_code_sets,
- Wchar#'CONV_FRAME_CodeSetComponent'.native_code_set,
- Wchar#'CONV_FRAME_CodeSetComponent'.conversion_code_sets]),
- print_components(T, [CharSet | Data]);
-print_components([#'IOP_TaggedComponent'{tag=?TAG_ALTERNATE_IIOP_ADDRESS,
- component_data=#'ALTERNATE_IIOP_ADDRESS'
- {'HostID'=Host, 'Port'=Port}}|T], Data) ->
- AltAddr = io_lib:format(" TAG_ALTERNATE_IIOP_ADDRESS~n"
- "Alternate Address...: ~s:~p~n", [Host, Port]),
- print_components(T, [AltAddr | Data]);
-print_components([#'IOP_TaggedComponent'{tag=?TAG_SSL_SEC_TRANS,
- component_data=#'SSLIOP_SSL'
- {target_supports=Supports,
- target_requires=Requires,
- port=Port}}|T], Data) ->
- SSL = io_lib:format(" TAG_SSL_SEC_TRANS~n"
- "SSL Port............: ~p~n"
- "SSL Requires........: ~p~n"
- "SSL Supports........: ~p~n", [Port, Requires, Supports]),
- print_components(T, [SSL | Data]);
-%% Fault Tolerant Components
-print_components([#'IOP_TaggedComponent'{tag=?TAG_FT_GROUP,
- component_data=#'FT_TagFTGroupTaggedComponent'
- {version = Version,
- ft_domain_id = DomainId,
- object_group_id = ObjectGroupId,
- object_group_ref_version = ObjGrRefVer}}|T], Data) ->
- Comp = io_lib:format(" TAG_FT_GROUP~n"
- "Version.............: ~p~n"
- "Domain Id...........: ~p~n"
- "Obj Group Id........: ~p~n"
- "Obj Group Ref Ver...: ~p~n",
- [Version, DomainId, ObjectGroupId, ObjGrRefVer]),
- print_components(T, [Comp | Data]);
-print_components([#'IOP_TaggedComponent'{tag=?TAG_FT_PRIMARY,
- component_data=#'FT_TagFTPrimaryTaggedComponent'
- {primary = Primary}}|T], Data) ->
- Comp = io_lib:format(" TAG_FT_PRIMARY~n"
- "Primary.............: ~p~n", [Primary]),
- print_components(T, [Comp | Data]);
-print_components([#'IOP_TaggedComponent'{tag=?TAG_FT_HEARTBEAT_ENABLED,
- component_data=#'FT_TagFTHeartbeatEnabledTaggedComponent'
- {heartbeat_enabled = HBE}}|T], Data) ->
- Comp = io_lib:format(" TAG_FT_HEARTBEAT_ENABLED~n"
- "Heart Beat Enabled..: ~p~n", [HBE]),
- print_components(T, [Comp | Data]);
-%% Security - CSIIOP
-print_components([#'IOP_TaggedComponent'{tag=?TAG_CSI_SEC_MECH_LIST,
- component_data=#'CSIIOP_CompoundSecMechList'
- {stateful=Stateful,
- mechanism_list = MechList}}|T], Data) ->
- Comp = io_lib:format(" TAG_CSI_SEC_MECH_LIST~n"
- "Stateful............: ~p~n"
- "Mechanisms..........: ~p~n", [Stateful, MechList]),
- print_components(T, [Comp | Data]);
-print_components([#'IOP_TaggedComponent'{tag=?TAG_TLS_SEC_TRANS,
- component_data=#'CSIIOP_TLS_SEC_TRANS'
- {target_supports = TargetS,
- target_requires = TargetR,
- addresses = Addresses}}|T], Data) ->
- Comp = io_lib:format(" TAG_TLS_SEC_TRANS~n"
- "Target Supports.....: ~p~n"
- "Target Requires.....: ~p~n"
- "Addresses...........: ~p~n",
- [TargetS, TargetR, Addresses]),
- print_components(T, [Comp | Data]);
-print_components([#'IOP_TaggedComponent'{tag=?TAG_SECIOP_SEC_TRANS,
- component_data=#'CSIIOP_SECIOP_SEC_TRANS'
- {target_supports = TargetS,
- target_requires = TargetR,
- mech_oid = MechOID,
- target_name = TargetName,
- addresses = Addresses}}|T], Data) ->
- Comp = io_lib:format(" TAG_SECIOP_SEC_TRANS~n"
- "Target Supports.....: ~p~n"
- "Target Requires.....: ~p~n"
- "Mechanism OID.......: ~p~n"
- "Target Name.........: ~p~n"
- "Addresses...........: ~p~n",
- [TargetS, TargetR, MechOID, TargetName, Addresses]),
- print_components(T, [Comp | Data]);
-%% Unused components.
-print_components([#'IOP_TaggedComponent'{tag=TAG,
- component_data=CData}|T], Data) ->
- Unused = io_lib:format("Unused Component....: ~s~n", [match_tag(TAG)]),
- Octets = print_octets(CData, [], 1, []),
- print_components(T, [lists:flatten([Unused | Octets])| Data]).
-
-
-print_objkey(Objkey) when is_tuple(Objkey) ->
- io_lib:format("Local Object........:~n~p~n", [Objkey]);
-print_objkey(Objkey) ->
- Hdr = io_lib:format("External Object.....: ~n", []),
- Octets = print_octets(Objkey, [], 1, []),
- lists:flatten([Hdr | Octets]).
-
-print_octets([], [], _, Data) ->
- lists:reverse(Data);
-print_octets([], Acc, C, Data) ->
- Filling = lists:duplicate((4*(9-C)), 32),
- FData = io_lib:format("~s", [Filling]),
- Rest = io_lib:format(" ~p~n", [lists:reverse(Acc)]),
- [lists:reverse(Data), FData | Rest];
-print_octets([H|T], Acc, 8, Data) when H > 31 , H < 127 ->
- D1 = io_lib:format("~4w", [H]),
- D2 = io_lib:format(" ~p~n", [lists:reverse([H|Acc])]),
- print_octets(T, [], 1, [D2, D1 | Data]);
-print_octets([H|T], Acc, 1, Data) when H > 31 , H < 127 ->
- D1 = io_lib:format("~3w", [H]),
- print_octets(T, [H|Acc], 2, [D1 | Data]);
-print_octets([H|T], Acc, C, Data) when H > 31 , H < 127 ->
- D1 = io_lib:format("~4w", [H]),
- print_octets(T, [H|Acc], C+1, [D1 | Data]);
-print_octets([H|T], Acc, 8, Data) ->
- D1 = io_lib:format("~4w", [H]),
- D2 = io_lib:format(" ~p~n", [lists:reverse([$.|Acc])]),
- print_octets(T, [], 1, [D2, D1 | Data]);
-print_octets([H|T], Acc, 1, Data) ->
- D1 = io_lib:format("~3w", [H]),
- print_octets(T, [$.|Acc], 2, [D1|Data]);
-print_octets([H|T], Acc, C, Data) ->
- D1 = io_lib:format("~4w", [H]),
- print_octets(T, [$.|Acc], C+1, [D1|Data]).
-
-print_it(undefined, Data) ->
- io:format(Data);
-print_it(error_report, Data) ->
- error_logger:error_report(Data);
-print_it(info_msg, Data) ->
- error_logger:info_msg(Data);
-print_it(string, Data) ->
- lists:flatten(Data);
-print_it({error_report, Msg}, Data) ->
- error_logger:error_report(io_lib:format("================== Reason =================~n~s~n~s",
- [Msg, Data]));
-print_it({info_msg, Msg}, Data) ->
- error_logger:info_msg(io_lib:format("================== Comment ================~n~s~n~s",
- [Msg, Data]));
-print_it(IoDevice, Data) ->
- io:format(IoDevice, Data, []).
-
-match_tag(?TAG_ORB_TYPE) -> ?TAG_ORB_TYPE_STR;
-match_tag(?TAG_CODE_SETS) -> ?TAG_CODE_SETS_STR;
-match_tag(?TAG_POLICIES) -> ?TAG_POLICIES_STR;
-match_tag(?TAG_ALTERNATE_IIOP_ADDRESS) -> ?TAG_ALTERNATE_IIOP_ADDRESS_STR;
-match_tag(?TAG_COMPLETE_OBJECT_KEY) -> ?TAG_COMPLETE_OBJECT_KEY_STR;
-match_tag(?TAG_ENDPOINT_ID_POSITION) -> ?TAG_ENDPOINT_ID_POSITION_STR;
-match_tag(?TAG_LOCATION_POLICY) -> ?TAG_LOCATION_POLICY_STR;
-match_tag(?TAG_ASSOCIATION_OPTIONS) -> ?TAG_ASSOCIATION_OPTIONS_STR;
-match_tag(?TAG_SEC_NAME) -> ?TAG_SEC_NAME_STR;
-match_tag(?TAG_SPKM_1_SEC_MECH) -> ?TAG_SPKM_1_SEC_MECH_STR;
-match_tag(?TAG_SPKM_2_SEC_MECH) -> ?TAG_SPKM_2_SEC_MECH_STR;
-match_tag(?TAG_KerberosV5_SEC_MECH) -> ?TAG_KerberosV5_SEC_MECH_STR;
-match_tag(?TAG_CSI_ECMA_Secret_SEC_MECH) -> ?TAG_CSI_ECMA_Secret_SEC_MECH_STR;
-match_tag(?TAG_CSI_ECMA_Hybrid_SEC_MECH) -> ?TAG_CSI_ECMA_Hybrid_SEC_MECH_STR;
-match_tag(?TAG_SSL_SEC_TRANS) -> ?TAG_SSL_SEC_TRANS_STR;
-match_tag(?TAG_CSI_ECMA_Public_SEC_MECH) -> ?TAG_CSI_ECMA_Public_SEC_MECH_STR;
-match_tag(?TAG_GENERIC_SEC_MECH) -> ?TAG_GENERIC_SEC_MECH_STR;
-match_tag(?TAG_FIREWALL_TRANS) -> ?TAG_FIREWALL_TRANS_STR;
-match_tag(?TAG_SCCP_CONTACT_INFO) -> ?TAG_SCCP_CONTACT_INFO_STR;
-match_tag(?TAG_JAVA_CODEBASE) -> ?TAG_JAVA_CODEBASE_STR;
-match_tag(?TAG_TRANSACTION_POLICY) -> ?TAG_TRANSACTION_POLICY_STR;
-match_tag(?TAG_FT_GROUP) -> ?TAG_FT_GROUP_STR;
-match_tag(?TAG_FT_PRIMARY) -> ?TAG_FT_PRIMARY_STR;
-match_tag(?TAG_FT_HEARTBEAT_ENABLED) -> ?TAG_FT_HEARTBEAT_ENABLED_STR;
-match_tag(?TAG_MESSAGE_ROUTERS) -> ?TAG_MESSAGE_ROUTERS_STR;
-match_tag(?TAG_OTS_POLICY) -> ?TAG_OTS_POLICY_STR;
-match_tag(?TAG_INV_POLICY) -> ?TAG_INV_POLICY_STR;
-match_tag(?TAG_CSI_SEC_MECH_LIST) -> ?TAG_CSI_SEC_MECH_LIST_STR;
-match_tag(?TAG_NULL_TAG) -> ?TAG_NULL_TAG_STR;
-match_tag(?TAG_SECIOP_SEC_TRANS) -> ?TAG_SECIOP_SEC_TRANS_STR;
-match_tag(?TAG_TLS_SEC_TRANS) -> ?TAG_TLS_SEC_TRANS_STR;
-match_tag(?TAG_DCE_STRING_BINDING) -> ?TAG_DCE_STRING_BINDING_STR;
-match_tag(?TAG_DCE_BINDING_NAME) -> ?TAG_DCE_BINDING_NAME_STR;
-match_tag(?TAG_DCE_NO_PIPES) -> ?TAG_DCE_NO_PIPES_STR;
-match_tag(?TAG_DCE_SEC_MECH) -> ?TAG_DCE_SEC_MECH_STR;
-match_tag(?TAG_INET_SEC_TRANS) -> ?TAG_INET_SEC_TRANS_STR;
-match_tag(Tag) -> integer_to_list(Tag).
-
-%%-----------------------------------------------------------------
-%% Func: string_code/1
-%%-----------------------------------------------------------------
-string_code(IOR) ->
- Flags = orber:get_flags(),
- case ?ORB_FLAG_TEST(Flags, ?ORB_ENV_ENABLE_NAT) of
- false ->
- string_code(IOR, Flags, orber:host(),
- orber:iiop_port(), orber:iiop_ssl_port());
- true ->
- string_code(IOR, Flags, orber:nat_host(),
- orber:nat_iiop_port(), orber:nat_iiop_ssl_port())
- end.
-
-string_code(IOR, Host) ->
- Flags = orber:get_flags(),
- case ?ORB_FLAG_TEST(Flags, ?ORB_ENV_ENABLE_NAT) of
- false ->
- string_code(IOR, Flags, Host,
- orber:iiop_port(), orber:iiop_ssl_port());
- true ->
- string_code(IOR, Flags, Host,
- orber:nat_iiop_port(), orber:nat_iiop_ssl_port())
- end.
-
-string_code(IOR, Host, Port) ->
- Flags = orber:get_flags(),
- case ?ORB_FLAG_TEST(Flags, ?ORB_ENV_ENABLE_NAT) of
- false ->
- string_code(IOR, Flags, Host, Port, orber:iiop_ssl_port());
- true ->
- string_code(IOR, Flags, Host, Port, orber:nat_iiop_ssl_port())
- end.
-
-string_code(IOR, Host, Port, SSLPort) ->
- string_code(IOR, orber:get_flags(), Host, Port, SSLPort).
-
-string_code(IOR, Flags, IP, Port, SSLPort) ->
- Env = #giop_env{version = orber:giop_version(),
- flags = Flags, host = IP, iiop_port = Port,
- iiop_ssl_port = SSLPort, domain = orber:domain(),
- partial_security = orber:partial_security()},
- {IorByteSeq0, Length0} = cdr_encode:enc_type('tk_octet', Env, 0, [], 0),
- {IorByteSeq, _} = code(Env, IOR, IorByteSeq0, Length0),
- IorByteSeq1 = binary_to_list(list_to_binary(lists:reverse(IorByteSeq))),
- IorHexSeq = bytestring_to_hexstring(IorByteSeq1),
- [$I,$O,$R,$: | IorHexSeq].
-
-%%-----------------------------------------------------------------
-%% Func: code/3
-%%-----------------------------------------------------------------
-code(#giop_env{version = Version} = Env, #'IOP_IOR'{type_id=TypeId, profiles=Profiles}, Bytes, Len) ->
- ProfileSeq =code_profile_datas(Version, Profiles),
- %% Byte order
- cdr_encode:enc_type(?IOR_TYPEDEF,
- Env,
- #'IOP_IOR'{type_id=TypeId, profiles=ProfileSeq},
- Bytes, Len);
-%% No Local Interface supplied. Use configuration parameters.
-code(#giop_env{version = Version, host = 0, flags = EnvFlags} = Env,
- {Mod, Type, Key, UserDef, OrberDef, Flags}, Bytes, Len) ->
- MC = case ?ORB_FLAG_TEST(EnvFlags, ?ORB_ENV_EXCLUDE_CODESET_COMPONENT) of
- true ->
- [];
- false ->
- [#'IOP_TaggedComponent'{tag=?TAG_CODE_SETS,
- component_data=?DEFAULT_CODESETS}]
- end,
- IOR = case ?ORB_FLAG_TEST(EnvFlags, ?ORB_ENV_ENABLE_NAT) of
- false ->
- create(Version, Mod:typeID(), orber_env:host(),
- orber_env:iiop_port(), orber_env:iiop_ssl_port(),
- {Mod, Type, Key, UserDef, OrberDef, Flags},
- MC, Flags, EnvFlags);
- true ->
- create(Version, Mod:typeID(), orber_env:nat_host(),
- orber_env:nat_iiop_port(), orber_env:nat_iiop_ssl_port(),
- {Mod, Type, Key, UserDef, OrberDef, Flags},
- MC, Flags, EnvFlags)
-
- end,
- code(Env, IOR, Bytes, Len);
-code(#giop_env{version = Version, host = Host, iiop_port = IIOPort,
- iiop_ssl_port = SSLPort, flags = EnvFlags} = Env,
- {Mod, Type, Key, UserDef, OrberDef, Flags}, Bytes, Len) ->
- MC = case ?ORB_FLAG_TEST(EnvFlags, ?ORB_ENV_EXCLUDE_CODESET_COMPONENT) of
- true ->
- [];
- false ->
- [#'IOP_TaggedComponent'{tag=?TAG_CODE_SETS,
- component_data=?DEFAULT_CODESETS}]
- end,
- IOR = case ?ORB_FLAG_TEST(EnvFlags, ?ORB_ENV_ENABLE_NAT) of
- false ->
- create(Version, Mod:typeID(), Host, check_port(IIOPort, normal),
- check_port(SSLPort, ssl),
- {Mod, Type, Key, UserDef, OrberDef, Flags},
- MC, Flags, EnvFlags);
- true ->
- create(Version, Mod:typeID(), orber_env:nat_host(Host),
- orber_env:nat_iiop_port(check_port(IIOPort, normal)),
- orber_env:nat_iiop_ssl_port(check_port(SSLPort, ssl)),
- {Mod, Type, Key, UserDef, OrberDef, Flags},
- MC, Flags, EnvFlags)
- end,
- code(Env, IOR, Bytes, Len).
-
-check_port(Port, _Type) when is_integer(Port) ->
- Port;
-check_port(_, normal) ->
- orber:iiop_port();
-check_port(_, ssl) ->
- orber:iiop_ssl_port().
-
-code_profile_datas(_, []) ->
- [];
-code_profile_datas(Version, [#'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=P} | Profiles]) ->
- NewBytes = list_to_binary(code_profile_data(Version, P)),
- [#'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=NewBytes} |
- code_profile_datas(Version, Profiles)];
-%% Multiple Components
-code_profile_datas(Version, [#'IOP_TaggedProfile'{tag=?TAG_MULTIPLE_COMPONENTS,
- profile_data=P} | Profiles]) ->
- Comps= code_comp(Version, P, []),
- {Bytes, Length} = cdr_encode:enc_type('tk_octet', Version, 0, [], 0),
- {Bytes1, _Length1} = cdr_encode:enc_type(?IOP_TAGGEDCOMPONENT_SEQ, Version, Comps, Bytes, Length),
- Profs = binary_to_list(list_to_binary(lists:reverse(Bytes1))),
- [#'IOP_TaggedProfile'{tag=?TAG_MULTIPLE_COMPONENTS,
- profile_data=Profs}| code_profile_datas(Version, Profiles)];
-code_profile_datas(Version, [#'IOP_TaggedProfile'{tag=N, profile_data=P} | Profiles]) ->
- [#'IOP_TaggedProfile'{tag=N, profile_data=P} | code_profile_datas(Version, Profiles)];
-code_profile_datas(_, Data) ->
- orber:dbg("[~p] iop_ior:code_profile_datas(~p); unsupported TaggedProfile.",
- [?LINE, Data], ?DEBUG_LEVEL),
- corba:raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO}).
-
-code_profile_data(Version, ProfileData) ->
- [RecTag, V, H, P, O |Rest] = tuple_to_list(ProfileData),
- {Bytes, Length} = cdr_encode:enc_type('tk_octet', Version, 0, [], 0),
- {Bytes1, Length1} = cdr_encode:enc_type(?IIOP_VERSION, Version, V, Bytes, Length),
- {Bytes2, Length2} = cdr_encode:enc_type({'tk_string', 0}, Version,
- H, Bytes1, Length1),
- {Bytes3, Length3} = cdr_encode:enc_type('tk_ushort', Version, P, Bytes2, Length2),
- {Bytes4, Length4} = cdr_encode:enc_type({'tk_sequence', 'tk_octet', 0}, Version,
- corba:objkey_to_string(O), Bytes3, Length3),
- {Bytes5, _Length5} = code_profile_data_1(Version, RecTag, Rest, Bytes4, Length4),
- Bytes6 = lists:reverse(Bytes5),
- lists:flatten(Bytes6).
-
-code_profile_data_1(_Version, 'IIOP_ProfileBody_1_0', [], Bytes, Length) ->
- {Bytes, Length};
-code_profile_data_1(Version, 'IIOP_ProfileBody_1_1', [TaggedComponentSeq], Bytes, Length) ->
- Comps = code_comp(Version, TaggedComponentSeq, []),
- cdr_encode:enc_type(?IOP_TAGGEDCOMPONENT_SEQ, Version, Comps, Bytes, Length);
-code_profile_data_1(_,V,S,_,_) ->
- orber:dbg("[~p] iop_ior:code_profile_datas(~p, ~p); probably unsupported IIOP-version",
- [?LINE, V, S], ?DEBUG_LEVEL),
- corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO}).
-
-code_comp(_Version, [], CompData) ->
- CompData;
-code_comp(Version, [#'IOP_TaggedComponent'{tag=?TAG_CODE_SETS,
- component_data=CodeSet}|Comps], CompData) ->
- {Bytes0, Len0} = cdr_encode:enc_type('tk_octet', Version, 0, [], 0),
- {Bytes1, _Len1} = cdr_encode:enc_type(?CONV_FRAME_CODESETCOMPONENTINFO, Version,
- CodeSet, Bytes0, Len0),
- Bytes = binary_to_list(list_to_binary(lists:reverse(Bytes1))),
- code_comp(Version, Comps, [#'IOP_TaggedComponent'{tag=?TAG_CODE_SETS,
- component_data=Bytes}|CompData]);
-code_comp(Version, [#'IOP_TaggedComponent'{tag=?TAG_ORB_TYPE,
- component_data=ORBType}|Comps], CompData) ->
- {Bytes0, Len0} = cdr_encode:enc_type('tk_octet', Version, 0, [], 0),
- {Bytes1, _Len1} = cdr_encode:enc_type(?ORB_TYPE, Version,
- ORBType, Bytes0, Len0),
- Bytes = binary_to_list(list_to_binary(lists:reverse(Bytes1))),
- code_comp(Version, Comps, [#'IOP_TaggedComponent'{tag=?TAG_ORB_TYPE,
- component_data=Bytes}|CompData]);
-code_comp(Version, [#'IOP_TaggedComponent'{tag=?TAG_ALTERNATE_IIOP_ADDRESS,
- component_data=AltAddr}|Comps], CompData) ->
- {Bytes0, Len0} = cdr_encode:enc_type('tk_octet', Version, 0, [], 0),
- {Bytes1, _Len1} = cdr_encode:enc_type(?ALTERNATE_IIOP_ADDRESS, Version,
- AltAddr, Bytes0, Len0),
- Bytes = binary_to_list(list_to_binary(lists:reverse(Bytes1))),
- code_comp(Version, Comps, [#'IOP_TaggedComponent'{tag=?TAG_ALTERNATE_IIOP_ADDRESS,
- component_data=Bytes}|CompData]);
-code_comp(Version, [#'IOP_TaggedComponent'{tag=?TAG_SSL_SEC_TRANS,
- component_data=SSLStruct}|Comps], CompData) ->
- {Bytes0, Len0} = cdr_encode:enc_type('tk_octet', Version, 0, [], 0),
- {Bytes1, _Len1} = cdr_encode:enc_type(?SSLIOP_SSL, Version,
- SSLStruct, Bytes0, Len0),
- Bytes = binary_to_list(list_to_binary(lists:reverse(Bytes1))),
- code_comp(Version, Comps, [#'IOP_TaggedComponent'{tag=?TAG_SSL_SEC_TRANS,
- component_data=Bytes}|CompData]);
-%% Fault Tolerant Components
-code_comp(Version, [#'IOP_TaggedComponent'{tag=?TAG_FT_GROUP,
- component_data=Data}|Comps], CompData) ->
- {Bytes0, Len0} = cdr_encode:enc_type('tk_octet', Version, 0, [], 0),
- {Bytes1, _Len1} = cdr_encode:enc_type(?FT_TagFTGroupTaggedComponent, Version,
- Data, Bytes0, Len0),
- Bytes = binary_to_list(list_to_binary(lists:reverse(Bytes1))),
- code_comp(Version, Comps, [#'IOP_TaggedComponent'{tag=?TAG_FT_GROUP,
- component_data=Bytes}|CompData]);
-code_comp(Version, [#'IOP_TaggedComponent'{tag=?TAG_FT_PRIMARY,
- component_data=Data}|Comps], CompData) ->
- {Bytes0, Len0} = cdr_encode:enc_type('tk_octet', Version, 0, [], 0),
- {Bytes1, _Len1} = cdr_encode:enc_type(?FT_TagFTPrimaryTaggedComponent, Version,
- Data, Bytes0, Len0),
- Bytes = binary_to_list(list_to_binary(lists:reverse(Bytes1))),
- code_comp(Version, Comps, [#'IOP_TaggedComponent'{tag=?TAG_FT_PRIMARY,
- component_data=Bytes}|CompData]);
-code_comp(Version, [#'IOP_TaggedComponent'{tag=?TAG_FT_HEARTBEAT_ENABLED,
- component_data=Data}|Comps], CompData) ->
- {Bytes0, Len0} = cdr_encode:enc_type('tk_octet', Version, 0, [], 0),
- {Bytes1, _Len1} = cdr_encode:enc_type(?FT_TagFTHeartbeatEnabledTaggedComponent, Version,
- Data, Bytes0, Len0),
- Bytes = binary_to_list(list_to_binary(lists:reverse(Bytes1))),
- code_comp(Version, Comps, [#'IOP_TaggedComponent'{tag=?TAG_FT_HEARTBEAT_ENABLED,
- component_data=Bytes}|CompData]);
-%% Security - CSIIOP
-code_comp(Version, [#'IOP_TaggedComponent'{tag=?TAG_CSI_SEC_MECH_LIST,
- component_data=Data}|Comps], CompData) ->
- NewData = Data#'CSIIOP_CompoundSecMechList'
- {mechanism_list = code_sec_mech(Version,
- Data#'CSIIOP_CompoundSecMechList'.mechanism_list,
- [])},
- {Bytes0, Len0} = cdr_encode:enc_type('tk_octet', Version, 0, [], 0),
- {Bytes1, _Len1} = cdr_encode:enc_type(?CSIIOP_CompoundSecMechList, Version,
- NewData, Bytes0, Len0),
- Bytes = binary_to_list(list_to_binary(lists:reverse(Bytes1))),
- code_comp(Version, Comps, [#'IOP_TaggedComponent'{tag=?TAG_CSI_SEC_MECH_LIST,
- component_data=Bytes}|CompData]);
-code_comp(Version, [#'IOP_TaggedComponent'{tag=?TAG_TLS_SEC_TRANS,
- component_data=Data}|Comps],
- CompData) ->
- {Bytes0, Len0} = cdr_encode:enc_type('tk_octet', Version, 0, [], 0),
- {Bytes1, _Len1} = cdr_encode:enc_type(?CSIIOP_TLS_SEC_TRANS, Version,
- Data, Bytes0, Len0),
- Bytes = binary_to_list(list_to_binary(lists:reverse(Bytes1))),
- code_comp(Version, Comps, [#'IOP_TaggedComponent'{tag=?TAG_TLS_SEC_TRANS,
- component_data=Bytes}|CompData]);
-code_comp(Version, [#'IOP_TaggedComponent'{tag=?TAG_SECIOP_SEC_TRANS,
- component_data=Data}|Comps], CompData) ->
- {Bytes0, Len0} = cdr_encode:enc_type('tk_octet', Version, 0, [], 0),
- {Bytes1, _Len1} = cdr_encode:enc_type(?CSIIOP_SECIOP_SEC_TRANS, Version,
- Data, Bytes0, Len0),
- Bytes = binary_to_list(list_to_binary(lists:reverse(Bytes1))),
- code_comp(Version, Comps, [#'IOP_TaggedComponent'{tag=?TAG_SECIOP_SEC_TRANS,
- component_data=Bytes}|CompData]);
-code_comp(Version, [#'IOP_TaggedComponent'{tag=?TAG_NULL_TAG}|Comps], CompData) ->
- %% The body of the TAG_NULL_TAG component is a sequence of octets of
- %% length 0.
- {Bytes0, Len0} = cdr_encode:enc_type('tk_octet', Version, 0, [], 0),
- {Bytes1, _Len1} = cdr_encode:enc_type({'tk_sequence', 'tk_octet', 0}, Version,
- [], Bytes0, Len0),
- Bytes = binary_to_list(list_to_binary(lists:reverse(Bytes1))),
- code_comp(Version, Comps, [#'IOP_TaggedComponent'{tag=?TAG_NULL_TAG,
- component_data=Bytes}|CompData]);
-%% Unsupported/not used component.
-code_comp(Version, [C|Comps], CompData) ->
- code_comp(Version, Comps, [C|CompData]).
-
-
-code_sec_mech(_, [], Acc) ->
- %% We must preserver the order!!
- lists:reverse(Acc);
-code_sec_mech(Version, [#'CSIIOP_CompoundSecMech'{transport_mech = TagComp} = CSM|T],
- Acc) ->
- [EncTagComp] = code_comp(Version, [TagComp], []),
- code_sec_mech(Version, T, [CSM#'CSIIOP_CompoundSecMech'
- {transport_mech = EncTagComp}|Acc]).
-
-
-%%-----------------------------------------------------------------
-%% Func: string_decode/1
-%%-----------------------------------------------------------------
-string_decode([$I,$O,$R,$: | IorHexSeq]) ->
- Version = orber:giop_version(),
- IorByteSeq = list_to_binary(hexstring_to_bytestring(IorHexSeq)),
- {ByteOrder, IorRest} = cdr_decode:dec_byte_order(IorByteSeq),
- decode(Version, IorRest, 1, ByteOrder);
-string_decode([$i,$o,$r,$: | IorHexSeq]) ->
- Version = orber:giop_version(),
- IorByteSeq = list_to_binary(hexstring_to_bytestring(IorHexSeq)),
- {ByteOrder, IorRest} = cdr_decode:dec_byte_order(IorByteSeq),
- decode(Version, IorRest, 1, ByteOrder);
-string_decode(What) ->
- orber:dbg("[~p] iop_ior:string_decode(~p); Should be IOR:.. or ior:..",
- [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%-----------------------------------------------------------------
-%% Func: decode/3
-%%-----------------------------------------------------------------
-decode(Version, IorByteSeq, Len, ByteOrder) ->
- {#'IOP_IOR'{type_id=TypeId, profiles=Profiles}, Rest, Length} =
- cdr_decode:dec_type(?IOR_TYPEDEF, Version, IorByteSeq, Len, ByteOrder),
- L = decode_profiles(Version, Profiles),
- {#'IOP_IOR'{type_id=TypeId, profiles=L}, Rest, Length}.
-
-decode_profiles(_, []) ->
- [];
-decode_profiles(Version, [P | Profiles]) ->
- Struct = decode_profile(Version, P),
- L = decode_profiles(Version, Profiles),
- [Struct | L].
-
-decode_profile(Version, #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=ProfileData}) ->
- {ByteOrder, Rest} = cdr_decode:dec_byte_order(list_to_binary(ProfileData)),
- Length = 1,
- {V, Rest1, Length1} = cdr_decode:dec_type(?IIOP_VERSION, Version, Rest, Length,
- ByteOrder),
- {H, Rest2, Length2} = cdr_decode:dec_type({'tk_string', 0}, Version, Rest1, Length1,
- ByteOrder),
- {P, Rest3, Length3} = cdr_decode:dec_type('tk_ushort', Version, Rest2, Length2,
- ByteOrder),
- {ObjKey, Rest4, Length4} = cdr_decode:dec_type({'tk_sequence', 'tk_octet', 0},
- Version, Rest3, Length3,
- ByteOrder),
- Struct = decode_profile_1(V, H, P, ObjKey, Version, Rest4, Length4, ByteOrder),
- #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=Struct};
-%% Multiple Components
-decode_profile(Version, #'IOP_TaggedProfile'{tag=?TAG_MULTIPLE_COMPONENTS,
- profile_data=ProfileData}) ->
- {ByteOrder, Rest} = cdr_decode:dec_byte_order(list_to_binary(ProfileData)),
- {Components, <<>>, _Length1} =cdr_decode:dec_type(?IOP_TAGGEDCOMPONENT_SEQ, Version, Rest, 1, ByteOrder),
- CompData = decode_comp(Version, Components, []),
- #'IOP_TaggedProfile'{tag=?TAG_MULTIPLE_COMPONENTS, profile_data=CompData};
-decode_profile(_, #'IOP_TaggedProfile'{tag=N, profile_data=ProfileData}) ->
- #'IOP_TaggedProfile'{tag=N, profile_data=ProfileData};
-decode_profile(_, Data) ->
- orber:dbg("[~p] iop_ior:decode_profile(~p); unsupported TaggedProfile.",
- [?LINE, Data], ?DEBUG_LEVEL),
- corba:raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO}).
-
-decode_profile_1(#'IIOP_Version'{major=1, minor=0}, H, P, ObjKey, _Version, _Rest, _Length, _ByteOrder) ->
- #'IIOP_ProfileBody_1_0'{iiop_version=#'IIOP_Version'{major=1,
- minor=0},
- host=H, port=P,
- object_key=corba:string_to_objkey(ObjKey)};
-decode_profile_1(#'IIOP_Version'{major=1, minor=1}, H, P, ObjKey, Version, Rest, Length, ByteOrder) ->
- {Components, <<>>, _Length1} =cdr_decode:dec_type(?IOP_TAGGEDCOMPONENT_SEQ, Version, Rest, Length, ByteOrder),
- CompData = decode_comp(Version, Components, []),
- #'IIOP_ProfileBody_1_1'{iiop_version=#'IIOP_Version'{major=1,
- minor=1},
- host=H, port=P,
- object_key=corba:string_to_objkey(ObjKey),
- components=CompData};
-decode_profile_1(#'IIOP_Version'{major=1, minor=2}, H, P, ObjKey, Version, Rest, Length, ByteOrder) ->
- {Components, <<>>, _Length1} =cdr_decode:dec_type(?IOP_TAGGEDCOMPONENT_SEQ, Version, Rest, Length, ByteOrder),
- CompData = decode_comp(Version, Components, []),
- #'IIOP_ProfileBody_1_1'{iiop_version=#'IIOP_Version'{major=1,
- minor=2},
- host=H, port=P,
- object_key=corba:string_to_objkey(ObjKey),
- components=CompData};
-decode_profile_1(V, _, _, _, _, _, _,_) ->
- orber:dbg("[~p] iop_ior:decode_profile_1(~p); probably unsupported IIOP-version.",
- [?LINE, V], ?DEBUG_LEVEL),
- corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO}).
-
-decode_comp(_Version, [], Components) ->
- Components;
-decode_comp(Version, [#'IOP_TaggedComponent'{tag=?TAG_CODE_SETS,
- component_data=Bytes}|Comps],
- Components) ->
- {ByteOrder, Rest} = cdr_decode:dec_byte_order(list_to_binary(Bytes)),
- {CodeSet, _, _} = cdr_decode:dec_type(?CONV_FRAME_CODESETCOMPONENTINFO,
- Version, Rest, 1, ByteOrder),
- decode_comp(Version, Comps,
- [#'IOP_TaggedComponent'{tag=?TAG_CODE_SETS,
- component_data=CodeSet}|Components]);
-decode_comp(Version, [#'IOP_TaggedComponent'{tag=?TAG_ORB_TYPE,
- component_data=Bytes}|Comps],
- Components) ->
- {ByteOrder, Rest} = cdr_decode:dec_byte_order(list_to_binary(Bytes)),
- {ORBType, _, _} = cdr_decode:dec_type(?ORB_TYPE,
- Version, Rest, 1, ByteOrder),
- decode_comp(Version, Comps,
- [#'IOP_TaggedComponent'{tag=?TAG_ORB_TYPE,
- component_data=ORBType}|Components]);
-decode_comp(Version, [#'IOP_TaggedComponent'{tag=?TAG_ALTERNATE_IIOP_ADDRESS,
- component_data=Bytes}|Comps],
- Components) ->
- {ByteOrder, Rest} = cdr_decode:dec_byte_order(list_to_binary(Bytes)),
- {AltIIOP, _, _} = cdr_decode:dec_type(?ALTERNATE_IIOP_ADDRESS,
- Version, Rest, 1, ByteOrder),
- decode_comp(Version, Comps,
- [#'IOP_TaggedComponent'{tag=?TAG_ALTERNATE_IIOP_ADDRESS,
- component_data=AltIIOP}|Components]);
-decode_comp(Version, [#'IOP_TaggedComponent'{tag=?TAG_SSL_SEC_TRANS,
- component_data=Data}|Comps], Components) ->
- {ByteOrder, R} = cdr_decode:dec_byte_order(list_to_binary(Data)),
- {SSLStruct, _Rest1, _Length1} = cdr_decode:dec_type(?SSLIOP_SSL, Version, R, 1,
- ByteOrder),
- decode_comp(Version, Comps,
- [#'IOP_TaggedComponent'{tag=?TAG_SSL_SEC_TRANS,
- component_data=SSLStruct}|Components]);
-%% Fault Tolerant Components
-decode_comp(Version, [#'IOP_TaggedComponent'{tag=?TAG_FT_GROUP,
- component_data=Data}|Comps], Components) ->
- {ByteOrder, R} = cdr_decode:dec_byte_order(list_to_binary(Data)),
- {DecodedData, _Rest1, _Length1} = cdr_decode:dec_type(?FT_TagFTGroupTaggedComponent, Version, R, 1,
- ByteOrder),
- decode_comp(Version, Comps,
- [#'IOP_TaggedComponent'{tag=?TAG_FT_GROUP,
- component_data=DecodedData}|Components]);
-decode_comp(Version, [#'IOP_TaggedComponent'{tag=?TAG_FT_PRIMARY,
- component_data=Data}|Comps], Components) ->
- {ByteOrder, R} = cdr_decode:dec_byte_order(list_to_binary(Data)),
- {DecodedData, _Rest1, _Length1} = cdr_decode:dec_type(?FT_TagFTPrimaryTaggedComponent, Version, R, 1,
- ByteOrder),
- decode_comp(Version, Comps,
- [#'IOP_TaggedComponent'{tag=?TAG_FT_PRIMARY,
- component_data=DecodedData}|Components]);
-decode_comp(Version, [#'IOP_TaggedComponent'{tag=?TAG_FT_HEARTBEAT_ENABLED,
- component_data=Data}|Comps], Components) ->
- {ByteOrder, R} = cdr_decode:dec_byte_order(list_to_binary(Data)),
- {DecodedData, _Rest1, _Length1} = cdr_decode:dec_type(?FT_TagFTHeartbeatEnabledTaggedComponent, Version, R, 1,
- ByteOrder),
- decode_comp(Version, Comps,
- [#'IOP_TaggedComponent'{tag=?TAG_FT_HEARTBEAT_ENABLED,
- component_data=DecodedData}|Components]);
-%% Security - CSIIOP
-decode_comp(Version, [#'IOP_TaggedComponent'{tag=?TAG_CSI_SEC_MECH_LIST,
- component_data=Data}|Comps], Components) ->
- {ByteOrder, R} = cdr_decode:dec_byte_order(list_to_binary(Data)),
- {DecodedData, _Rest1, _Length1} = cdr_decode:dec_type(?CSIIOP_CompoundSecMechList, Version, R, 1,
- ByteOrder),
- NewDecodedData = DecodedData#'CSIIOP_CompoundSecMechList'
- {mechanism_list = decode_sec_mech(Version,
- DecodedData#'CSIIOP_CompoundSecMechList'.mechanism_list,
- [])},
- decode_comp(Version, Comps,
- [#'IOP_TaggedComponent'{tag=?TAG_CSI_SEC_MECH_LIST,
- component_data=NewDecodedData}|Components]);
-decode_comp(Version, [#'IOP_TaggedComponent'{tag=?TAG_TLS_SEC_TRANS,
- component_data=Data}|Comps], Components) ->
- {ByteOrder, R} = cdr_decode:dec_byte_order(list_to_binary(Data)),
- {DecodedData, _Rest1, _Length1} = cdr_decode:dec_type(?CSIIOP_TLS_SEC_TRANS, Version, R, 1,
- ByteOrder),
- decode_comp(Version, Comps,
- [#'IOP_TaggedComponent'{tag=?TAG_TLS_SEC_TRANS,
- component_data=DecodedData}|Components]);
-decode_comp(Version, [#'IOP_TaggedComponent'{tag=?TAG_SECIOP_SEC_TRANS,
- component_data=Data}|Comps], Components) ->
- {ByteOrder, R} = cdr_decode:dec_byte_order(list_to_binary(Data)),
- {DecodedData, _Rest1, _Length1} = cdr_decode:dec_type(?CSIIOP_SECIOP_SEC_TRANS, Version, R, 1,
- ByteOrder),
- decode_comp(Version, Comps,
- [#'IOP_TaggedComponent'{tag=?TAG_SECIOP_SEC_TRANS,
- component_data=DecodedData}|Components]);
-decode_comp(Version, [#'IOP_TaggedComponent'{tag=?TAG_NULL_TAG,
- component_data=_Data}|Comps], Components) ->
- %% The body of the TAG_NULL_TAG component is a sequence of octets of
- %% length 0.
- decode_comp(Version, Comps,
- [#'IOP_TaggedComponent'{tag=?TAG_NULL_TAG,
- component_data=[]}|Components]);
-
-decode_comp(Version, [C|Comps], Components) ->
- %% Not used but we cannot discard it.
- decode_comp(Version, Comps, [C|Components]).
-
-
-decode_sec_mech(_Version, [], Acc) ->
- %% We must preserver the order!!
- lists:reverse(Acc);
-decode_sec_mech(Version, [#'CSIIOP_CompoundSecMech'{transport_mech = TagComp} = CSM|T],
- Acc) ->
- [DecTagComp] = decode_comp(Version, [TagComp], []),
- decode_sec_mech(Version, T, [CSM#'CSIIOP_CompoundSecMech'
- {transport_mech = DecTagComp}|Acc]).
-
-
-%%-----------------------------------------------------------------
-%% Func: hexstring_to_bytestring/1
-%%-----------------------------------------------------------------
-hexstring_to_bytestring(HexString) ->
- ByteString = hexstring_to_bytestring(HexString, []),
- lists:reverse(ByteString).
-
-hexstring_to_bytestring([], Acc) ->
- Acc;
-hexstring_to_bytestring([H1, H2 |Rest], Acc) ->
- I1 = hex_to_int(H1),
- I2 = hex_to_int(H2),
- I = I1 * 16 + I2,
- Acc2 = cdrlib:enc_octet(I, Acc),
- hexstring_to_bytestring(Rest, Acc2).
-
-
-hex_to_int(H) when H >= $a ->
- 10 + H - $a;
-hex_to_int(H) when H >= $A ->
- 10 + H -$A;
-hex_to_int(H) ->
- H - $0.
-%%-----------------------------------------------------------------
-%% Func: bytestring_to_hexstring/1
-%% Args: A byte string
-%% Returns: A list of hexadecimal digits (onebyte will be represented as
-%% two hexadecimal digits).
-%%-----------------------------------------------------------------
-bytestring_to_hexstring(ByteString) ->
- HexString = bytestring_to_hexstring(ByteString, []),
- lists:reverse(HexString).
-
-bytestring_to_hexstring([], Acc) ->
- Acc;
-bytestring_to_hexstring([B |Rest], Acc) ->
- [C1, C2] = int_to_hex(B),
- bytestring_to_hexstring(Rest,[C2, C1| Acc]).
-
-int_to_hex(B) when B < 256, B >= 0 ->
- N1 = B div 16,
- N2 = B rem 16,
- [code_character(N1),
- code_character(N2)].
-
-code_character(N) when N < 10 ->
- $0 + N;
-code_character(N) ->
- $a + (N - 10).
-
diff --git a/lib/orber/src/orber.app.src b/lib/orber/src/orber.app.src
deleted file mode 100644
index 217c1b247f..0000000000
--- a/lib/orber/src/orber.app.src
+++ /dev/null
@@ -1,111 +0,0 @@
-{application, orber,
- [{description, "The Erlang ORB application"},
- {vsn, "%VSN%"},
- {modules,
- [
- 'CosNaming_Binding',
- 'CosNaming_BindingIterator',
- 'CosNaming_BindingList',
- 'CosNaming_BindingIterator_impl',
- 'CosNaming_Name',
- 'CosNaming_NameComponent',
- 'CosNaming_NamingContext',
- 'CosNaming_NamingContext_AlreadyBound',
- 'CosNaming_NamingContext_CannotProceed',
- 'CosNaming_NamingContext_InvalidName',
- 'CosNaming_NamingContext_NotEmpty',
- 'CosNaming_NamingContext_NotFound',
- 'CosNaming_NamingContextExt',
- 'CosNaming_NamingContextExt_impl',
- 'CosNaming_NamingContextExt_InvalidAddress',
- 'OrberApp_IFR',
- 'OrberApp_IFR_impl',
- 'oe_OrberIFR',
- 'any',
- 'cdr_decode',
- 'cdr_encode',
- 'cdrlib',
- 'corba',
- 'corba_boa',
- 'corba_object',
- 'erlang_pid',
- 'erlang_port',
- 'erlang_ref',
- 'erlang_binary',
- 'iop_ior',
- 'lname',
- 'lname_component',
- 'oe_CORBA',
- 'oe_cos_naming',
- 'oe_cos_naming_ext',
- 'oe_erlang',
- 'orber',
- 'orber_cosnaming_utils',
- 'orber_ifr',
- 'orber_ifr_aliasdef',
- 'orber_ifr_arraydef',
- 'orber_ifr_attributedef',
- 'orber_ifr_constantdef',
- 'orber_ifr_contained',
- 'orber_ifr_container',
- 'orber_ifr_enumdef',
- 'orber_ifr_exceptiondef',
- 'orber_ifr_idltype',
- 'orber_ifr_interfacedef',
- 'orber_ifr_irobject',
- 'orber_ifr_moduledef',
- 'orber_ifr_operationdef',
- 'orber_ifr_orb',
- 'orber_ifr_primitivedef',
- 'orber_ifr_repository',
- 'orber_ifr_sequencedef',
- 'orber_ifr_stringdef',
- 'orber_ifr_wstringdef',
- 'orber_ifr_structdef',
- 'orber_ifr_typecode',
- 'orber_ifr_typedef',
- 'orber_ifr_uniondef',
- 'orber_ifr_fixeddef',
- 'orber_ifr_utils',
- 'orber_iiop',
- 'orber_iiop_inproxy',
- 'orber_iiop_inrequest',
- 'orber_iiop_insup',
- 'orber_iiop_net',
- 'orber_iiop_net_accept',
- 'orber_iiop_outproxy',
- 'orber_iiop_outsup',
- 'orber_iiop_pm',
- 'orber_iiop_socketsup',
- 'orber_initial_references',
- 'orber_pi',
- 'orber_objectkeys',
- 'orber_request_number',
- 'orber_socket',
- 'orber_tc',
- 'orber_typedefs',
- 'orber_web',
- 'orber_web_server',
- 'orber_iiop_tracer',
- 'orber_iiop_tracer_silent',
- 'orber_iiop_tracer_stealth',
- 'fixed',
- 'orber_exceptions',
- 'orber_diagnostics',
- 'orber_acl',
- 'orber_tb',
- 'orber_env'
- ]
- },
- {registered, [orber_sup, orber_iiop_sup, orber_iiop_net, orber_iiop_outsup,
- orber_iiop_insup, orber_init, orber_reqno,
- orber_objkeyserver, orber_iiop_socketsup,
- orber_iiop_pm, orber_env]},
- {applications, [stdlib, kernel, mnesia]},
- {env, []},
- {mod, {orber, []}},
- {runtime_dependencies, ["stdlib-2.5","ssl-5.3.4","mnesia-4.12","kernel-3.0",
- "inets-5.10","erts-7.0"]}
-]}.
-
-
diff --git a/lib/orber/src/orber.appup.src b/lib/orber/src/orber.appup.src
deleted file mode 100644
index 6c3b2833b7..0000000000
--- a/lib/orber/src/orber.appup.src
+++ /dev/null
@@ -1,7 +0,0 @@
-{"%VSN%",
- [
- ],
- [
- ]
-}.
-
diff --git a/lib/orber/src/orber.erl b/lib/orber/src/orber.erl
deleted file mode 100644
index f5e2429f5d..0000000000
--- a/lib/orber/src/orber.erl
+++ /dev/null
@@ -1,1238 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: orber.erl
-%%
-%% Description:
-%% This file contains the Orber application interface
-%%
-%%-----------------------------------------------------------------
--module(orber).
-
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
--include_lib("orber/src/ifr_objects.hrl").
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([start/0, start/1, stop/0, install/1, install/2, orber_nodes/0, iiop_port/0,
- domain/0, iiop_ssl_port/0, iiop_out_ports/0, iiop_out_ports_random/0,
- iiop_out_ports_attempts/0,
- ssl_server_options/0, ssl_client_options/0, set_ssl_client_options/1,
- ssl_server_certfile/0, ssl_client_certfile/0, set_ssl_client_certfile/1,
- ssl_server_verify/0, ssl_client_verify/0, set_ssl_client_verify/1,
- ssl_server_depth/0, ssl_client_depth/0, set_ssl_client_depth/1,
- ssl_server_cacertfile/0,ssl_client_cacertfile/0, set_ssl_client_cacertfile/1,
- ssl_client_keyfile/0, ssl_client_password/0, ssl_server_keyfile/0, ssl_server_password/0,
- ssl_client_ciphers/0, ssl_server_ciphers/0, ssl_client_cachetimeout/0, ssl_server_cachetimeout/0,
- uninstall/0, giop_version/0, info/0, info/1, is_running/0, add_node/2,
- remove_node/1, iiop_timeout/0, iiop_connection_timeout/0,
- iiop_setup_connection_timeout/0, objectkeys_gc_time/0,
- is_lightweight/0, get_lightweight_nodes/0,
- start_lightweight/0, start_lightweight/1,
- get_ORBDefaultInitRef/0, get_ORBInitRef/0,
- get_interceptors/0, get_local_interceptors/0,
- get_cached_interceptors/0, set_interceptors/1,
- jump_start/0, jump_start/1, jump_stop/0,
- iiop_connections/0, iiop_connections/1, iiop_connections_pending/0,
- typechecking/0,
- exclude_codeset_ctx/0, exclude_codeset_component/0, bidir_context/0, use_FT/0,
- use_CSIv2/0, get_flags/0, secure/0, multi_jump_start/1, multi_jump_start/2,
- multi_jump_start/3, get_tables/0, iiop_in_connection_timeout/0,
- partial_security/0, nat_iiop_ssl_port/0, nat_iiop_port/0, ip_version/0,
- light_ifr/0, iiop_max_in_requests/0, iiop_max_in_connections/0,
- iiop_max_fragments/0, iiop_backlog/0, iiop_ssl_backlog/0,
- find_sockname_by_peername/2, find_peername_by_sockname/2, iiop_acl/0,
- add_listen_interface/2, add_listen_interface/3, remove_listen_interface/1,
- reconfigure_out_connections/1,
- reconfigure_out_connection/3, reconfigure_out_connection/4,
- reconfigure_in_connections/1, reconfigure_in_connection/2,
- activate_audit_trail/0, activate_audit_trail/1, deactivate_audit_trail/0,
- iiop_ssl_ip_address_local/0, ip_address_local/0,
- close_connection/1, close_connection/2, is_system_exception/1,
- exception_info/1]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([nat_host/0, host/0, ip_address_variable_defined/0, start/2, init/1,
- get_debug_level/0, debug_level_print/3, dbg/3, error/3,
- configure/2, configure_override/2, multi_configure/1,
- mjs/1, mjs/2, js/0, js/1]).
-
-%%-----------------------------------------------------------------
-%% Internal definitions
-%%-----------------------------------------------------------------
-%% Defines possible configuration parameters a user can add when,
-%% for example, installing Orber.
--record(options, {ifr_storage_type = disc_copies,
- install_timeout = infinity,
- local_content = false,
- nameservice_storage_type = ram_copies,
- initialreferences_storage_type = ram_copies,
- type = temporary,
- load_order = 0}).
-
--define(ORBER_TABS, [orber_CosNaming, orber_objkeys, orber_references]).
-
--define(DEBUG_LEVEL, 5).
-
--define(FORMAT(_F, _A), lists:flatten(io_lib:format(_F, _A))).
--define(EFORMAT(_F, _A), exit(lists:flatten(io_lib:format(_F, _A)))).
-
-
-%%-----------------------------------------------------------------
-%% External interface functions
-%%-----------------------------------------------------------------
-
-jump_stop() ->
- stop(),
- uninstall(),
- mnesia:stop().
-
-js() ->
- application:load(orber),
- jump_start([{iiop_port, iiop_port()},
- {interceptors, {native, [orber_iiop_tracer_silent]}},
- {orber_debug_level, 10},
- {flags, (?ORB_ENV_LOCAL_TYPECHECKING bor get_flags())}]).
-
-js(Port) when is_integer(Port) ->
- application:load(orber),
- jump_start([{iiop_port, Port},
- {interceptors, {native, [orber_iiop_tracer_silent]}},
- {orber_debug_level, 10},
- {flags, (?ORB_ENV_LOCAL_TYPECHECKING bor get_flags())}]).
-
-jump_start() ->
- application:load(orber),
- jump_start([{iiop_port, iiop_port()}]).
-
-
-jump_start(Port) when is_integer(Port) ->
- application:load(orber),
- jump_start([{iiop_port, Port}]);
-jump_start(Options) when is_list(Options) ->
- application:load(orber),
- mnesia:start(),
- Port = case lists:keysearch(iiop_port, 1, Options) of
- {value, {iiop_port, Value}} ->
- Value;
- _ ->
- iiop_port()
- end,
- corba:orb_init([{iiop_port, Port}|Options]),
- install([node()], [{ifr_storage_type, ram_copies}]),
- start(),
- %% We need to use this operation if Port == 0 to see what the OS
- %% assigned.
- NewPort = orber_env:iiop_port(),
- Domain = orber_env:ip_address() ++ [$:|integer_to_list(NewPort)],
- orber_env:configure_override(domain, Domain),
- info();
-jump_start(Options) ->
- exit({error, Options}).
-
-
-mjs(Nodes) ->
- application:load(orber),
- multi_js_helper(Nodes, iiop_port(),
- [{interceptors, {native, [orber_iiop_tracer_silent]}},
- {orber_debug_level, 10},
- {flags, (?ORB_ENV_LOCAL_TYPECHECKING bor get_flags())}]).
-
-mjs(Nodes, Port) ->
- application:load(orber),
- multi_js_helper(Nodes, Port,
- [{interceptors, {native, [orber_iiop_tracer_silent]}},
- {orber_debug_level, 10},
- {flags, (?ORB_ENV_LOCAL_TYPECHECKING bor get_flags())}]).
-
-
-multi_jump_start(Nodes) ->
- application:load(orber),
- multi_js_helper(Nodes, iiop_port(), []).
-
-multi_jump_start(Nodes, Port) ->
- multi_js_helper(Nodes, Port, []).
-
-multi_jump_start(Nodes, Port, Options) ->
- multi_js_helper(Nodes, Port, Options).
-
-multi_js_helper(Nodes, Port, InitOptions) when is_list(Nodes) andalso
- is_integer(Port) andalso
- is_list(InitOptions) ->
- %% We MUST delete the option iiop_port.
- Options = lists:keydelete(iiop_port, 1, InitOptions),
- case node() of
- nonode@nohost ->
- {error, "The distribution is not started"};
- _ ->
- mnesia:start(),
- corba:orb_init([{iiop_port, Port}|Options]),
- install([node()], [{ifr_storage_type, ram_copies}]),
- start(),
- NewPort = orber_env:iiop_port(),
- Domain = orber_env:ip_address() ++ [$:|integer_to_list(NewPort)],
- orber_env:configure_override(domain, Domain),
- case jump_start_slaves(Nodes, NewPort,
- [{domain, Domain}|Options], [], []) of
- {ok, NodeData} ->
- info(),
- {ok, [{node(), NewPort}|NodeData]};
- Other ->
- Other
- end
- end.
-
-jump_start_slaves([], _, _, [], NodeData) ->
- rpc:multicall([node() | nodes()], global, sync, []),
- {ok, NodeData};
-jump_start_slaves([], _, _, Errors, _) ->
- {error, Errors};
-jump_start_slaves([{Host, N}|T], Port, Options, Errors, NodeData) ->
- case create_nodes(Host, N, Port, Options, Errors, NodeData) of
- {ok, NewNodeData} ->
- jump_start_slaves(T, Port, Options, Errors, NewNodeData);
- {error, NewErrors} ->
- jump_start_slaves(T, Port, Options, NewErrors, NodeData)
- end;
-jump_start_slaves([Host|T], Port, Options, Errors, NodeData) ->
- case catch create_node(Host, Port+1, Options) of
- {ok, NewNode} ->
- jump_start_slaves(T, Port, Options, Errors, [{NewNode, Port+1}|NodeData]);
- {error, Reason} ->
- jump_start_slaves(T, Port, Options, [{Host, Port, Reason}|Errors],
- NodeData);
- Other ->
- jump_start_slaves(T, Port, Options, [{Host, Port, Other}|Errors],
- NodeData)
- end.
-
-create_nodes(_, 0, _, _, [], NodeData) ->
- {ok, NodeData};
-create_nodes(_, 0, _, _, Errors, _) ->
- {error, Errors};
-create_nodes(Host, N, Port, Options, Errors, NodeData) ->
- case catch create_node(Host, Port+N, Options) of
- {ok, NewNode} ->
- create_nodes(Host, N-1, Port, Options, Errors,
- [{NewNode, Port+N}|NodeData]);
- {error, Reason} ->
- create_nodes(Host, N-1, Port, Options,
- [{Host, Port+N, Reason}|Errors], NodeData);
- Other ->
- create_nodes(Host, N-1, Port, Options,
- [{Host, Port+N, Other}|Errors], NodeData)
- end.
-
-
-create_node(Host, Port, Options) ->
- case slave:start_link(Host, list_to_atom(integer_to_list(Port))) of
- {ok, NewNode} ->
- case net_adm:ping(NewNode) of
- pong ->
- ok = rpc:call(NewNode, mnesia, start, []),
- {ok,_} = rpc:call(NewNode, mnesia, change_config, [extra_db_nodes, [node()]]),
- ok = rpc:call(NewNode, corba, orb_init, [[{iiop_port, Port}|Options]]),
- ok = rpc:call(NewNode, orber, add_node, [NewNode, ram_copies]),
- {ok, NewNode};
- _ ->
- {error, "net_adm:ping(Node) failed"}
- end;
- {error, Reason} ->
- {error, Reason}
- end.
-
-
-start() ->
- start(temporary).
-
-start(Type) when Type == permanent; Type == temporary ->
- application:start(mnesia),
- TableTest = test_tables(),
- case lists:member(not_member, TableTest) of
- true ->
- exit({error,"Orber Mnesia Table(s) missing. Orber not properly installed."});
- _->
- try_starting(Type)
- end.
-
-start_lightweight() ->
- application:start(orber).
-
-start_lightweight(Nodes) when is_list(Nodes) ->
- configure(lightweight, Nodes),
- application:set_env(orber, lightweight, Nodes),
- application:start(orber);
-start_lightweight(_) ->
- exit({error,"Argument not correct; must be a list of nodes."}).
-
-stop() ->
- application:stop(orber).
-
-
-get_tables() ->
- case light_ifr() of
- false ->
- ?ifr_object_list++?ORBER_TABS;
- true ->
- ?ifr_light_object_list ++?ORBER_TABS
- end.
-
-iiop_port() ->
- orber_env:iiop_port().
-
-nat_iiop_port() ->
- orber_env:nat_iiop_port().
-
-iiop_out_ports() ->
- orber_env:iiop_out_ports().
-
-iiop_out_ports_random() ->
- orber_env:iiop_out_ports_random().
-
-iiop_out_ports_attempts() ->
- orber_env:iiop_out_ports_attempts().
-
-orber_nodes() ->
- case catch mnesia:table_info(orber_objkeys,ram_copies) of
- Nodes when is_list(Nodes) ->
- Nodes;
- _ ->
- [node()]
- end.
-
-domain() ->
- orber_env:domain().
-
-
-ip_address_variable_defined() ->
- orber_env:ip_address_variable_defined().
-
-
-nat_host() ->
- orber_env:nat_host().
-
-host() ->
- orber_env:host().
-
-giop_version() ->
- orber_env:giop_version().
-
-iiop_timeout() ->
- orber_env:iiop_timeout().
-
-iiop_connection_timeout() ->
- orber_env:iiop_connection_timeout().
-
-iiop_setup_connection_timeout() ->
- orber_env:iiop_setup_connection_timeout().
-
-iiop_in_connection_timeout() ->
- orber_env:iiop_in_connection_timeout().
-
-find_peername_by_sockname(Host, Port) ->
- orber_iiop_net:sockname2peername(Host, Port) ++
- orber_iiop_pm:sockname2peername(Host, Port).
-
-find_sockname_by_peername(Host, Port) ->
- orber_iiop_net:peername2sockname(Host, Port) ++
- orber_iiop_pm:peername2sockname(Host, Port).
-
-%%----------------------------------------------------------------------
-%% Function : iiop_connections
-%% Arguments : Direction - in | out | inout
-%% Returns : Connections - [{Host, Port}] | [{Host, Port, Interface}]
-%% Host - string
-%% Port - integer
-%% Interface - string
-%% Raises :
-%% Description: List existing in- and/or out-bound connections.
-%%----------------------------------------------------------------------
-iiop_connections() ->
- iiop_connections(inout).
-
-iiop_connections(inout) ->
- orber_iiop_pm:list_existing_connections() ++ orber_iiop_net:connections();
-iiop_connections(in) ->
- orber_iiop_net:connections();
-iiop_connections(out) ->
- orber_iiop_pm:list_existing_connections().
-
-%%----------------------------------------------------------------------
-%% Function : close_connection
-%% Arguments : ObjRef - #'IOP_IOR'{} | [{Host, Port}] |
-%% Interface - string (optional)
-%% Host - string
-%% Port - integer
-%% Returns : ok | {'EXCEPTION', #'BAD_PARAM'{}}
-%% Raises :
-%% Description: Close outgoing connections.
-%%----------------------------------------------------------------------
-close_connection(ObjRef) ->
- close_connection(ObjRef, 0).
-
-close_connection(ObjRef, Interface) when is_record(ObjRef, 'IOP_IOR') ->
- case iop_ior:get_peerdata(ObjRef) of
- [] ->
- ok;
- PeerData ->
- orber_iiop_pm:close_connection(PeerData, Interface)
- end;
-close_connection(PeerData, Interface) when is_list(PeerData) ->
- orber_iiop_pm:close_connection(PeerData, Interface);
-close_connection(What, Interface) ->
- orber:dbg("[~p] orber:close_connection(~p, ~p);~n"
- "Incorrect type of arguments.",
- [?LINE, What, Interface], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------------------
-%% Function : iiop_connections_pending
-%% Arguments : -
-%% Returns : Connections - [{Host, Port}]
-%% Host - string
-%% Port - integer
-%% Raises :
-%% Description: List outbound connections that are being setup. Usefull
-%% when suspecting firewall problems.
-%%----------------------------------------------------------------------
-iiop_connections_pending() ->
- orber_iiop_pm:list_setup_connections().
-
-
-iiop_max_fragments() ->
- orber_env:iiop_max_fragments().
-
-iiop_max_in_requests() ->
- orber_env:iiop_max_in_requests().
-
-iiop_max_in_connections() ->
- orber_env:iiop_max_in_connections().
-
-iiop_backlog() ->
- orber_env:iiop_backlog().
-
-iiop_acl() ->
- orber_env:iiop_acl().
-
-ip_address_local() ->
- orber_env:ip_address_local().
-
-get_flags() ->
- orber_env:get_flags().
-
-typechecking() ->
- orber_env:typechecking().
-
-exclude_codeset_ctx() ->
- orber_env:exclude_codeset_ctx().
-
-exclude_codeset_component() ->
- orber_env:exclude_codeset_component().
-
-partial_security() ->
- orber_env:partial_security().
-
-use_CSIv2() ->
- orber_env:use_CSIv2().
-
-use_FT() ->
- orber_env:use_FT().
-
-ip_version() ->
- orber_env:ip_version().
-
-light_ifr() ->
- orber_env:light_ifr().
-
-bidir_context() ->
- orber_env:bidir_context().
-
-objectkeys_gc_time() ->
- orber_env:objectkeys_gc_time().
-
-
-%%-----------------------------------------------------------------
-%% CosNaming::NamingContextExt operations
-%%-----------------------------------------------------------------
-get_ORBInitRef() ->
- orber_env:get_ORBInitRef().
-
-get_ORBDefaultInitRef() ->
- orber_env:get_ORBDefaultInitRef().
-
-
-%%-----------------------------------------------------------------
-%% Interceptor opertaions (see orber_pi.erl)
-%%-----------------------------------------------------------------
-get_interceptors() ->
- orber_env:get_interceptors().
-
-get_local_interceptors() ->
- orber_env:get_local_interceptors().
-
-get_cached_interceptors() ->
- orber_env:get_cached_interceptors().
-
-set_interceptors(Val) ->
- orber_env:set_interceptors(Val).
-
-
-%%-----------------------------------------------------------------
-%% Light weight Orber operations
-%%-----------------------------------------------------------------
-is_lightweight() ->
- orber_env:is_lightweight().
-
-get_lightweight_nodes() ->
- orber_env:get_lightweight_nodes().
-
-%%-----------------------------------------------------------------
-%% Security access operations (SSL)
-%%-----------------------------------------------------------------
-secure() ->
- orber_env:secure().
-
-iiop_ssl_backlog() ->
- orber_env:iiop_ssl_backlog().
-
-iiop_ssl_ip_address_local() ->
- orber_env:iiop_ssl_ip_address_local().
-
-iiop_ssl_port() ->
- orber_env:iiop_ssl_port().
-
-nat_iiop_ssl_port() ->
- orber_env:nat_iiop_ssl_port().
-
-ssl_server_options() ->
- orber_env:ssl_server_options().
-
-ssl_client_options() ->
- orber_env:ssl_client_options().
-
-set_ssl_client_options(Value) ->
- orber_env:set_ssl_client_options(Value).
-
-ssl_server_certfile() ->
- orber_env:ssl_server_certfile().
-
-ssl_client_certfile() ->
- orber_env:ssl_client_certfile().
-
-set_ssl_client_certfile(Value) ->
- orber_env:set_ssl_client_certfile(Value).
-
-ssl_server_verify() ->
- orber_env:ssl_server_verify().
-
-ssl_client_verify() ->
- orber_env:ssl_client_verify().
-
-set_ssl_client_verify(Value) ->
- orber_env:set_ssl_client_verify(Value).
-
-ssl_server_depth() ->
- orber_env:ssl_server_depth().
-
-ssl_client_depth() ->
- orber_env:ssl_client_depth().
-
-set_ssl_client_depth(Value) ->
- orber_env:set_ssl_client_depth(Value).
-
-ssl_server_cacertfile() ->
- orber_env:ssl_server_cacertfile().
-
-ssl_client_cacertfile() ->
- orber_env:ssl_client_cacertfile().
-
-set_ssl_client_cacertfile(Value) ->
- orber_env:set_ssl_client_cacertfile(Value).
-
-ssl_client_password() ->
- orber_env:ssl_client_password().
-
-ssl_server_password() ->
- orber_env:ssl_server_password().
-
-ssl_client_keyfile() ->
- orber_env:ssl_client_keyfile().
-
-ssl_server_keyfile() ->
- orber_env:ssl_server_keyfile().
-
-ssl_client_ciphers() ->
- orber_env:ssl_client_ciphers().
-
-ssl_server_ciphers() ->
- orber_env:ssl_server_ciphers().
-
-ssl_client_cachetimeout() ->
- orber_env:ssl_client_cachetimeout().
-
-ssl_server_cachetimeout() ->
- orber_env:ssl_server_cachetimeout().
-
-%%----------------------------------------------------------------------
-%% Function : activate_audit_trail
-%% Arguments : Verbosity - stealth | normal | verbose
-%% Returns : -
-%% Raises :
-%% Description: Activate the appropriate interceptor for the requested direction(s).
-%%----------------------------------------------------------------------
-activate_audit_trail() ->
- activate_audit_trail(normal).
-
-activate_audit_trail(stealth) ->
- do_activate(orber_iiop_tracer_stealth);
-activate_audit_trail(verbose) ->
- do_activate(orber_iiop_tracer);
-activate_audit_trail(_) ->
- do_activate(orber_iiop_tracer_silent).
-
-do_activate(Interceptor) ->
- Options =
- case orber_env:get_interceptors() of
- {native, PIs} ->
- [{interceptors,
- {native, [Interceptor|remove_built_in_interceptors(PIs, [])]}}];
- _ ->
- [{interceptors, {native, [Interceptor]}}]
- end,
- reconfigure_in_connections(Options),
- reconfigure_out_connections(Options).
-
-remove_built_in_interceptors([orber_iiop_tracer_stealth|T], Acc) ->
- remove_built_in_interceptors(T, Acc);
-remove_built_in_interceptors([orber_iiop_tracer|T], Acc) ->
- remove_built_in_interceptors(T, Acc);
-remove_built_in_interceptors([orber_iiop_tracer_silent|T], Acc) ->
- remove_built_in_interceptors(T, Acc);
-remove_built_in_interceptors([H|T], Acc) ->
- remove_built_in_interceptors(T, [H|Acc]);
-remove_built_in_interceptors([], Acc) ->
- %% We must use the same order as defined by the interceptors parameter
- lists:reverse(Acc).
-
-%%----------------------------------------------------------------------
-%% Function : deactivate_audit_trail
-%% Arguments : -
-%% Returns : -
-%% Raises :
-%% Description: Dectivate interceptors for the requested direction(s).
-%%----------------------------------------------------------------------
-deactivate_audit_trail() ->
- Options
- = case orber_env:get_interceptors() of
- {native, PIs} ->
- [{interceptors, {native, PIs}}];
- _ ->
- [{interceptors, false}]
- end,
- reconfigure_in_connections(Options),
- reconfigure_out_connections(Options).
-
-%%----------------------------------------------------------------------
-%% Function : add_listen_interface
-%% Arguments : IP - string
-%% Type - normal | ssl
-%% Port - integer > 0
-%% Options - [{Key, Value}]
-%% Key - atom() valid configuration parameter
-%% Value - a valid value for the given Key
-%% Returns : #Ref
-%% Raises :
-%% Description: Add a new listen process, which will accept new incoming
-%% connections.
-%%----------------------------------------------------------------------
-add_listen_interface(IP, normal) ->
- orber_iiop_net:add(IP, normal, [{iiop_port, orber_env:iiop_port()}]);
-add_listen_interface(IP, ssl) ->
- orber_iiop_net:add(IP, ssl, [{iiop_ssl_port, orber_env:iiop_ssl_port()}]).
-
-add_listen_interface(IP, normal, Port) when is_integer(Port) andalso Port > 0 ->
- orber_iiop_net:add(IP, normal, [{iiop_port, Port}]);
-add_listen_interface(IP, ssl, Port) when is_integer(Port) andalso Port > 0 ->
- orber_iiop_net:add(IP, ssl, [{iiop_ssl_port, Port}]);
-add_listen_interface(IP, Type, Options) when is_list(Options) ->
- orber_iiop_net:add(IP, Type, Options);
-add_listen_interface(IP, Type, Port) when is_integer(Port) ->
- orber:dbg("[~p] orber:add_listen_interface(~p, ~p, ~p);~n"
- "The port number must be greater than 0.",
- [?LINE, IP, Type, Port], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO});
-add_listen_interface(IP, Type, Extra) ->
- orber:dbg("[~p] orber:add_listen_interface(~p, ~p, ~p);~n"
- "Incorrect argument(s).",
- [?LINE, IP, Type, Extra], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%----------------------------------------------------------------------
-%% Function : remove_listen_interface
-%% Arguments : Ref - #Ref
-%% Returns : #Ref
-%% Raises :
-%% Description: Terminate the listen process and all related inproxies
-%% associated with the supplied reference.
-%%----------------------------------------------------------------------
-remove_listen_interface(Ref) ->
- orber_iiop_net:remove(Ref).
-
-%%----------------------------------------------------------------------
-%% Function : reconfigure_out_connections
-%% Arguments : Options - see corba:orb_init
-%% Returns : ok | {error, Reason}
-%% Raises :
-%% Description: Reconfigure the behavior of all outgoing IIOP connections.
-%%----------------------------------------------------------------------
-reconfigure_out_connections(Options) ->
- orber_iiop_pm:reconfigure(Options).
-
-%%----------------------------------------------------------------------
-%% Function : reconfigure_out_connections
-%% Arguments : Options - see corba:orb_init
-%% Host - string()
-%% Port - integer()
-%% Interface - string
-%% Returns : ok | {error, Reason}
-%% Raises :
-%% Description: Reconfigure the behavior of all outgoing connections.
-%%----------------------------------------------------------------------
-reconfigure_out_connection(Options, Host, Port) ->
- orber_iiop_pm:reconfigure(Options, Host, Port).
-reconfigure_out_connection(Options, Host, Port, Interface) ->
- orber_iiop_pm:reconfigure(Options, Host, Port, Interface).
-
-%%----------------------------------------------------------------------
-%% Function : reconfigure_in_connections
-%% Arguments : Options - see corba:orb_init
-%% Returns : ok | {error, Reason}
-%% Raises :
-%% Description: Reconfigure the behavior of all incoming IIOP connections.
-%%----------------------------------------------------------------------
-reconfigure_in_connections(Options) ->
- orber_iiop_net:reconfigure(Options).
-
-%%----------------------------------------------------------------------
-%% Function : reconfigure_in_connections
-%% Arguments : Options - see corba:orb_init
-%% Ref - The #Ref returned by add_listen_interface/2/3
-%% Returns : ok | {error, Reason}
-%% Raises :
-%% Description: Reconfigure the behavior of all incoming IIOP connections.
-%%----------------------------------------------------------------------
-reconfigure_in_connection(Options, Ref) ->
- orber_iiop_net:reconfigure(Options, Ref).
-
-
-%%-----------------------------------------------------------------
-%% Configuration settings
-%%-----------------------------------------------------------------
-info() ->
- orber_env:info().
-
-info(IoDevice) ->
- orber_env:info(IoDevice).
-
-%%-----------------------------------------------------------------
-%% EXCEPTION mapping
-%%-----------------------------------------------------------------
-exception_info(Exc) ->
- orber_exceptions:dissect(Exc).
-
-is_system_exception(Exc) ->
- orber_exceptions:is_system_exception(Exc).
-
-%%-----------------------------------------------------------------
-%% Installation interface functions
-%%-----------------------------------------------------------------
-install(Nodes) ->
- install(Nodes, []).
-
-install([], Options) ->
- install([node()], Options);
-install(Nodes, Options) when is_list(Nodes) andalso is_list(Options)->
- case orber_tb:is_running() of
- false ->
- application:load(orber),
- case mnesia:system_info(is_running) of
- no ->
- application:start(mnesia),
- Outcome = install_orber(Nodes, Options),
- application:stop(mnesia),
- Outcome;
- yes ->
- install_orber(Nodes, Options)
- end;
- _ ->
- exit({error, "Orber is already running on this node."})
- end.
-
-
-
-install_orber(Nodes, Options) ->
- #options{ifr_storage_type = IFRType, install_timeout = Timeout,
- local_content = LocalContent, nameservice_storage_type = NSType,
- initialreferences_storage_type = InitType,
- load_order = LoadOrder}
- = check_options(Options, #options{}),
- MnesiaOptions = [{local_content, LocalContent},
- {load_order, LoadOrder}],
- TableTest = test_tables(),
- case lists:member(is_member, TableTest) of
- true ->
- case LocalContent of
- true ->
- orber_ifr:initialize(Timeout, {localCopy,IFRType},
- light_ifr());
- _->
- exit("Orber Mnesia Table(s) already exist. Cannot install Orber.")
- end;
- _ ->
- orber_ifr:initialize(Timeout, [{IFRType, Nodes} |MnesiaOptions],
- light_ifr())
- end,
- orber_objectkeys:install(Timeout, [{ram_copies, Nodes} |MnesiaOptions]),
- 'CosNaming_NamingContextExt_impl':install(Timeout, [{NSType, Nodes} |MnesiaOptions]),
- orber_initial_references:install(Timeout, [{InitType, Nodes} |MnesiaOptions]),
- oe_cos_naming:oe_register(),
- oe_cos_naming_ext:oe_register(),
- oe_erlang:oe_register(),
- oe_OrberIFR:oe_register(),
- oe_CORBA:oe_register(),
- case NSType of
- ram_copies ->
- case mnesia:dump_tables(['orber_CosNaming']) of
- {atomic, ok} ->
- ok;
- {aborted, {has_no_disc,_}} ->
- ok;
- {aborted, Reason} ->
- ?EFORMAT("Unable to dump mnesia tables: ~p", [Reason])
- end;
- _ ->
- ok
- end.
-
-check_options([], Options) ->
- Options;
-check_options([{ifr_storage_type, Type}|T], Options)
- when Type == disc_copies; Type == ram_copies ->
- check_options(T, Options#options{ifr_storage_type = Type});
-check_options([{nameservice_storage_type, Type}|T], Options)
- when Type == disc_copies; Type == ram_copies ->
- check_options(T, Options#options{nameservice_storage_type = Type});
-check_options([{initialreferences_storage_type, Type}|T], Options)
- when Type == disc_copies; Type == ram_copies ->
- check_options(T, Options#options{initialreferences_storage_type = Type});
-check_options([{install_timeout, Timeout}|T], Options)
- when Timeout == infinity orelse is_integer(Timeout) ->
- check_options(T, Options#options{install_timeout = Timeout});
-check_options([{local_content, Bool}|T], Options)
- when Bool == true; Bool == false ->
- check_options(T, Options#options{local_content = Bool});
-check_options([{type, Type}|T], Options)
- when Type == temporary; Type == permanent ->
- check_options(T, Options#options{type = Type});
-check_options([{load_order, LoadOrder}|T], Options)
- when is_integer(LoadOrder) ->
- check_options(T, Options#options{load_order = LoadOrder});
-check_options([H|_], _) ->
- ?EFORMAT("Option unknown or incorrect value: ~w", [H]).
-
-
-
-try_starting(Type) ->
- case application:start(orber, Type) of
- ok ->
- case partial_security() of
- true ->
- error_logger:warning_msg(
- "=================== Orber =================~n"
- "*******************************************~n"
- "**** WARNING - WARNING - WARNING **********~n"
- "**** WARNING - WARNING - WARNING **********~n"
- "**** WARNING - WARNING - WARNING **********~n"
- "**** WARNING - WARNING - WARNING **********~n"
- "*******************************************~n"
- " ORBER STARTED WITH AN INSECURE OPTION:~n"
- " ~n"
- " {flags, ~p}~n"
- " ~n"
- " THIS OPTION MAY ONLY BE USED DURING TESTS~n"
- " ~n"
- "===========================================~n",
- [?ORB_ENV_PARTIAL_SECURITY]),
- ok;
- false ->
- ok
- end;
- {error,{already_started,orber}} ->
- {error,{already_started,orber}};
- Reason ->
- dbg("[~p] orber:try_starting(~p) failed: ~n~p",
- [?LINE, Type, Reason], ?DEBUG_LEVEL),
- {error, "Unable to start Orber. Is the listen port vacant?"}
- end.
-
-test_tables() ->
- AllTabs = mnesia:system_info(tables),
- lists:map(fun(Tab) ->
- case lists:member(Tab,AllTabs) of
- false ->
- not_member;
- _ ->
- is_member
- end
- end,
- get_tables()).
-
-%%-----------------------------------------------------------------
-%% UnInstallation interface functions
-%%-----------------------------------------------------------------
-uninstall() ->
- orber_objectkeys:stop_all(),
- application:stop(orber),
- delete_orber_tables(get_tables()).
-
-delete_orber_tables([]) -> ok;
-delete_orber_tables([Tab1|Rest]) ->
- mnesia:delete_table(Tab1),
- delete_orber_tables(Rest).
-
-%%-----------------------------------------------------------------
-%% Add and remove node interface functions
-%%-----------------------------------------------------------------
-add_node(Node, StorageType) when is_atom(Node) andalso is_atom(StorageType) ->
- add_node(Node, [{ifr_storage_type, StorageType}]);
-add_node(Node, OptionList) when is_atom(Node) andalso is_list(OptionList) ->
- case rpc:call(Node, mnesia, system_info, [is_running]) of
- {badrpc, Reason} ->
- ?EFORMAT("Node ~p do not respond. add_node/2 failed: ~p",
- [Node, Reason]);
- yes ->
- case rpc:call(Node, orber, is_running, []) of
- false ->
- %% We need to "load" orber to make sure that
- %% application environment variables is loaded.
- rpc:call(Node, application, load, [orber]),
- Options = check_options(OptionList, #options{}),
- case rpc:call(Node, orber, light_ifr, []) of
- false ->
- copy_tables(?ifr_object_list, Node, Options);
- true ->
- copy_tables(?ifr_light_object_list, Node, Options)
- end;
- true ->
- ?EFORMAT("Orber is already running on ~p. add_node failed.",
- [Node]);
- Reason ->
- ?EFORMAT("Unable to reach node ~p. add_node/1 failed: ~p",
- [Node, Reason])
- end;
- no ->
- ?EFORMAT("Mnesia not running on node ~p. add_node/2 failed.",
- [Node]);
- starting ->
- ?EFORMAT("Mnesia not fully started on node ~p. add_node/2 failed.",
- [Node]);
- stopping ->
- ?EFORMAT("Mnesia stopping on node ~p. add_node/2 failed.", [Node])
- end.
-
-%% We have to copy the tables in two steps, i.e., orber tables should be ram_copies
-%% while the user may choose to install the rest as disc_copies.
-copy_tables([], Node, Options) ->
- copy_orber_tables(?ORBER_TABS, Node, Options);
-copy_tables([T1|Trest], Node, Options) ->
- case mnesia:add_table_copy(T1, Node, Options#options.ifr_storage_type) of
- {atomic, ok} ->
- copy_tables(Trest, Node, Options);
- {aborted, Reason} ->
- ?EFORMAT("orber:add_node/2 failed: ~p. Unable to copy IFR table(s): ~p",
- [mnesia:error_description(Reason), [T1|Trest]])
- end.
-
-copy_orber_tables([], Node, Options) ->
- case rpc:call(Node, application, start, [orber, Options#options.type]) of
- ok ->
- ok;
- Reason ->
- ?EFORMAT("All tables installed but failed to start orber on node ~p: ~p",
- [Node, Reason])
- end;
-copy_orber_tables([orber_CosNaming|TTail], Node, Options) ->
- case mnesia:add_table_copy(orber_CosNaming, Node,
- Options#options.nameservice_storage_type) of
- {atomic, ok} ->
- copy_orber_tables(TTail, Node, Options);
- {aborted, Reason} ->
- ?EFORMAT("orber:add_node/2 failed: ~p. Unable to copy system table(s): ~p",
- [mnesia:error_description(Reason), [orber_CosNaming|TTail]])
- end;
-copy_orber_tables([orber_references|TTail], Node, Options) ->
- case mnesia:add_table_copy(orber_references, Node,
- Options#options.initialreferences_storage_type) of
- {atomic, ok} ->
- copy_orber_tables(TTail, Node, Options);
- {aborted, Reason} ->
- ?EFORMAT("orber:add_node/2 failed: ~p. Unable to copy system table(s): ~p",
- [mnesia:error_description(Reason), [orber_references|TTail]])
- end;
-copy_orber_tables([THead|TTail], Node, Options) ->
- case mnesia:add_table_copy(THead, Node, ram_copies) of
- {atomic, ok} ->
- copy_orber_tables(TTail, Node, Options);
- {aborted, Reason} ->
- ?EFORMAT("orber:add_node/2 failed: ~p. Unable to copy system table(s): ~p",
- [mnesia:error_description(Reason), [THead|TTail]])
- end.
-
-remove_node(Node) when is_atom(Node) ->
- case rpc:call(Node, mnesia, system_info, [is_running]) of
- yes ->
- case rpc:call(Node, orber, is_running, []) of
- true ->
- rpc:call(Node, orber, stop, []),
- remove_tables(get_tables(), Node);
- false ->
- remove_tables(get_tables(), Node);
- Reason ->
- ?EFORMAT("Unable to reach node: ~p. remove_node/1 failed: ~p",
- [Node, Reason])
- end;
- no ->
- case rpc:call(Node, mnesia, start, []) of
- ok ->
- remove_tables(get_tables(), Node),
- rpc:call(Node, mnesia, stop, []);
- Reason ->
- ?EFORMAT("Unable to reach node: ~p. remove_node/1 failed: ~p",
- [Node, Reason])
- end;
- Reason ->
- ?EFORMAT("Problem with ~p. remove_node/1 failed: ~p", [Node, Reason])
- end.
-
-
-remove_tables(Tables, Node) ->
- case remove_tables(Tables, Node, []) of
- ok ->
- ok;
- {error, Node, Failed} ->
- ?EFORMAT("orber:remove_node(~p) failed. Unable to remove table(s): ~p",
- [Node, Failed])
- end.
-
-remove_tables([], _, []) ->
- ok;
-remove_tables([], Node, Failed) ->
- {error, Node, Failed};
-remove_tables([T1|Trest], Node, Failed) ->
- case mnesia:del_table_copy(T1, Node) of
- {atomic, ok} ->
- remove_tables(Trest, Node, Failed);
- {aborted, Reason} ->
- remove_tables(Trest, Node, [{T1, Reason}|Failed])
- end.
-
-%%-----------------------------------------------------------------
-%% Internal interface functions
-%%-----------------------------------------------------------------
-%%----------------------------------------------------------------------
-%% Function : is_running
-%% Arguments :
-%% Returns :
-%% Raises :
-%% Description:
-%%----------------------------------------------------------------------
-is_running() ->
- orber_tb:is_running().
-
-%%----------------------------------------------------------------------
-%% Function : check_giop
-%% Arguments :
-%% Returns :
-%% Raises :
-%% Description:
-%%----------------------------------------------------------------------
-check_giop_version() ->
- case giop_version() of
- {1,0} ->
- ok;
- {1,1} ->
- ok;
- {1,2} ->
- ok;
- X ->
- X
- end.
-
-%%----------------------------------------------------------------------
-%% Function : dbg
-%% Arguments :
-%% Returns :
-%% Raises :
-%% Description: Note, dbg replaces debug_level_print.
-%%
-%% The following levels are used (0-10):
-%% 10: cdrlib.erl
-%% 9: cdr_encode.erl cdr_decode.erl orber_ifr.erl orber_pi.erl
-%% 8: orber_iiop_outrequest.erl orber_iiop_inrequest.erl
-%% 7: orber_iiop_outproxy.erl orber_iiop_inproxy.erl
-%% 6: iop_ior.erl, orber_objectkeys.erl, Orber_IFR_impl.erl orber_socket.erl
-%% 5: corba.erl, corba_boa.erl, corba_object.erl
-%% 4: Reserved for Cos-services!
-%% 3: Reserved for Cos-services!
-%% 2: Reserved for client applications!
-%% 1: Reserved for client applications!
-%% 0: No logging!
-%%
-%% A higher value will result in a finer granularity.
-%%----------------------------------------------------------------------
-get_debug_level() ->
- orber_env:get_debug_level().
-
-debug_level_print(Format, Data, RequestedLevel) ->
- dbg(Format, Data, RequestedLevel).
-
-dbg(Format, Data, RequestedLevel) ->
- case orber_env:get_debug_level() of
- 0 ->
- ok;
- Level when is_integer(Level) andalso Level >= RequestedLevel ->
- if
- RequestedLevel > 4 ->
- %% Use catch if incorrect format used somewhere.
- catch error_logger:error_msg("=================== Orber =================~n"++
- Format++
- "~n===========================================~n",
- Data);
- RequestedLevel > 2 ->
- %% Use catch if incorrect format used somewhere.
- catch error_logger:error_msg("=========== Orber COS Application =========~n"++
- Format++
- "~n===========================================~n",
- Data);
- true ->
- %% Use catch if incorrect format used somewhere.
- catch error_logger:error_msg("========== Orber Client Application =======~n"++
- Format++
- "~n===========================================~n",
- Data)
- end,
- ok;
- _ ->
- ok
- end.
-
-error(Format, Data, RequestedLevel) ->
- if
- RequestedLevel > 4 ->
- %% Use catch if incorrect format used somewhere.
- catch error_logger:error_msg("=================== Orber =================~n"++
- Format++
- "~n===========================================~n",
- Data);
- RequestedLevel > 2 ->
- %% Use catch if incorrect format used somewhere.
- catch error_logger:error_msg("=========== Orber COS Application =========~n"++
- Format++
- "~n===========================================~n",
- Data);
- true ->
- %% Use catch if incorrect format used somewhere.
- catch error_logger:error_msg("========== Orber Client Application =======~n"++
- Format++
- "~n===========================================~n",
- Data)
- end,
- ok.
-
-configure(Key, Value) ->
- orber_env:configure(Key, Value, check).
-
-configure_override(Key, Value) ->
- orber_env:configure(Key, Value, loaded).
-
-multi_configure(KeyValueList) ->
- orber_env:multi_configure(KeyValueList).
-
-
-%%-----------------------------------------------------------------
-%% Server functions
-%%-----------------------------------------------------------------
-start(_, _) ->
- supervisor:start_link({local, orber_sup}, orber, orb_init).
-
-init(orb_init) ->
- case check_giop_version() of
- ok ->
- case is_lightweight() of
- true ->
- SupFlags = {one_for_one, 5, 1000},
- ChildSpec = [
- {orber_iiop_sup, {orber_iiop, start_sup, [[]]},
- permanent,
- 10000, supervisor, [orber_iiop]},
- {orber_reqno, {orber_request_number, start,
- [[]]},
- permanent,
- 10000, worker, [orber_request_number]}
- ],
- {ok, {SupFlags, ChildSpec}};
- false ->
- case orber_tb:wait_for_tables(get_tables()) of
- ok ->
- orber_objectkeys:remove_old_keys(),
- SupFlags = {one_for_one, 5, 1000},
- ChildSpec = [
- {orber_iiop_sup, {orber_iiop, start_sup, [[]]},
- permanent,
- 10000, supervisor, [orber_iiop]},
- {orber_init, {orber_initial_references, start,
- [[]]},
- permanent,
- 10000, worker, [orber_initial_references]},
- {orber_reqno, {orber_request_number, start,
- [[]]},
- permanent,
- 10000, worker, [orber_request_number]},
- {orber_objkeyserver, {orber_objectkeys, start,
- [[orber_nodes(), 0]]},
- permanent,
- 10000, worker, [orber_objectkeys]},
- {orber_env, {orber_env, start, [[]]},
- permanent, 10000, worker, [orber_env]}
- ],
- {ok, {SupFlags, ChildSpec}};
- StopReason ->
- {stop, StopReason}
- end
- end;
- X ->
- {stop, ?FORMAT("GIOP ~p not an implemeted version", [X])}
- end.
-
diff --git a/lib/orber/src/orber_acl.erl b/lib/orber/src/orber_acl.erl
deleted file mode 100644
index 55d84afbab..0000000000
--- a/lib/orber/src/orber_acl.erl
+++ /dev/null
@@ -1,397 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: orber_acl.erl
-%%
-%% Description:
-%% Handling ACL's (Access Control Lists).
-%%
-%% Creation date: 040723
-%%
-%%-----------------------------------------------------------------
--module(orber_acl).
-
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([init_acl/1, init_acl/2, clear_acl/0,
- match/2, match/3, verify/3, range/1, range/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--define(ACL_DB, orber_acl_db).
-
--define(DEBUG_LEVEL, 5).
--define(CONTINUE, -1).
--define(STOP, -2).
-
--define(FORMAT(_F, _A), {error, lists:flatten(io_lib:format(_F, _A))}).
--define(EFORMAT(_F, _A), exit(lists:flatten(io_lib:format(_F, _A)))).
-
-%%-----------------------------------------------------------------
-%% Record Definitions
-%%-----------------------------------------------------------------
--record(acl, {key, bits = ?CONTINUE, mask, interfaces = [],
- ports = 0, flags = 0}).
-
-%%-----------------------------------------------------------------
-%% External functions
-%%-----------------------------------------------------------------
-
-%%-----------------------------------------------------------------
-%% function : verify/1
-%% Arguments: IP - string()
-%% Filter - string() see init_acl
-%% Family - inet | inet6
-%% Returns : boolean()
-%% Exception:
-%% Effect :
-%%-----------------------------------------------------------------
-verify(IP, Filter, Family) ->
- DB = ets:new(orber_temporary_acl_table_created_by_user,
- [set, public, {keypos, 2}]),
- Result =
- case catch verify_helper(IP, Filter, Family, DB) of
- true ->
- true;
- {ok, Low, High} ->
- {false, Low, High};
- What ->
- {error, ?FORMAT("Uknown Error: ~p\n", [What])}
- end,
- ets:delete(DB),
- Result.
-
-verify_helper(IP, Filter, Family, DB) ->
- init_acl([{tcp_in, Filter}], Family, DB),
- {ok, IPTuple} = inet:getaddr(IP, Family),
- case match_helper(tuple_to_list(IPTuple), tcp_in, DB, false, tcp_in) of
- true ->
- true;
- false ->
- range(Filter, Family)
- end.
-
-%%-----------------------------------------------------------------
-%% function : range/1/2
-%% Arguments: Filter - string(). See init_acl
-%% Family - inet | inet6
-%% Returns : {ok, From, To}
-%% From - To - string()
-%% Exception:
-%% Effect :
-%%-----------------------------------------------------------------
-range(Filter) ->
- range(Filter, inet).
-
-range(Filter, inet) ->
- range_safe(Filter, inet, ".", 16#FF, "255", 8, "~p.", "~p", 3);
-range(Filter, Family) ->
- range_safe(Filter, Family, ":", 16#FFFF, "FFFF", 16, "~.16B:", "~.16B", 7).
-
-range_safe(Filter, Family, Separator, Max, MaxStr, N, F1, F2, X) ->
- case catch range_helper(Filter, Family, Separator, Max, MaxStr, N, F1, F2, X) of
- {ok, Low, High} ->
- {ok, Low, High};
- {'EXIT',{format,Why}} ->
- {error, ?FORMAT("Unable to format string: ~p\n", [Why])};
- {'EXIT', E} ->
- {error, ?FORMAT("Exit: ~p\n", [E])};
- What ->
- {error, ?FORMAT("Unknown Error: ~p\n", [What])}
- end.
-
-range_helper(Filter, Family, Separator, Max, MaxStr, N, F1, F2, X) ->
- {MaskStr, Bits, _Ports} = tokenize(Filter, Family),
- {ok, MaskTuple} = inet:getaddr(MaskStr, Family),
- NoOfFull = Bits div N,
- Mask = get_mask(N, (Bits rem N)),
- case split(NoOfFull, tuple_to_list(MaskTuple)) of
- {Full, [Partial|_DontCare]} ->
- Beginning = pp(Full, [], F1),
- MiddleLow = io_lib:format(F2, [(Mask band Partial) + ((Mask bxor Max) band 0)]),
- MiddleHigh = io_lib:format(F2, [(Mask band Partial) + ((Mask bxor Max) band Max)]),
- EndLow = lists:duplicate((X-NoOfFull), Separator ++ "0"),
- EndHigh = lists:duplicate((X-NoOfFull), Separator ++ MaxStr),
- Low = lists:flatten([Beginning, MiddleLow, EndLow]),
- High = lists:flatten([Beginning, MiddleHigh, EndHigh]),
- {ok, Low, High};
- {Full, []} ->
- Address = lists:flatten(pp(Full, [], F1)),
- {ok, Address, Address}
- end.
-
-pp([], Acc, _) ->
- Acc;
-pp([H|T], Acc, Format) ->
- pp(T, Acc ++ io_lib:format(Format, [H]), Format).
-
-split(N, List) when is_integer(N) andalso N >= 0 andalso is_list(List) ->
- case split(N, List, []) of
- Fault when is_atom(Fault) ->
- erlang:error(Fault, [N,List]);
- Result ->
- Result
- end;
-split(N, List) ->
- erlang:error(badarg, [N,List]).
-
-split(0, L, R) ->
- {lists:reverse(R, []), L};
-split(N, [H|T], R) ->
- split(N-1, T, [H|R]);
-split(_, [], _) ->
- badarg.
-
-
-%%-----------------------------------------------------------------
-%% function : clear_acl/0
-%% Arguments: -
-%% Returns :
-%% Exception:
-%% Effect :
-%%-----------------------------------------------------------------
-clear_acl() ->
- clear_acl(?ACL_DB).
-clear_acl(DB) ->
- (catch ets:delete(DB)),
- ok.
-
-%%-----------------------------------------------------------------
-%% function : init_acl/1/2
-%% Arguments: Filters - [{Direction, Filter}] | [{Direction, Filter, [Interfaces]}]
-%% Direction - tcp_in | ssl_in | tcp_out | ssl_out
-%% Filter - string(). Examples:
-%% * "123.456.789.10" - match against all bits.
-%% * "123.456.789.10/17" - match against the 17 most significant bits.
-%% * "123.456.789.10/17#4001" - as above but only allow port 4001
-%% * "123.456.789.10/17#4001/5001" - as above but only allow port 4001-5001
-%% Family - inet | inet6
-%% Returns : ok | {'EXCEPTION', E}
-%% Exception: 'BAD_PARAM'
-%% Effect :
-%%-----------------------------------------------------------------
-init_acl(Filters) ->
- DB = ets:new(?ACL_DB, [set, public, named_table, {keypos, 2}]),
- case ?ORB_FLAG_TEST(orber:get_flags(), ?ORB_ENV_USE_IPV6) of
- false ->
- init_acl(Filters, inet, DB);
- true ->
- init_acl(Filters, inet6, DB)
- end.
-
-init_acl(Filters, Family) ->
- DB = ets:new(?ACL_DB, [set, public, named_table, {keypos, 2}]),
- init_acl(Filters, Family, DB).
-
-init_acl([], _, DB) ->
- {ok, DB};
-init_acl([Data|T], Family, DB) ->
- {Direction, Filter, Interfaces} =
- case Data of
- {D, F, I} ->
- {D, F, I};
- {D, F} ->
- {D, F, []}
- end,
- {MaskStr, Bits, Ports} = tokenize(Filter, Family),
- case inet:getaddr(MaskStr, Family) of
- {ok, Addr} when size(Addr) == 4 ->
- create_mask(tuple_to_list(Addr), Bits div 8,
- get_mask8((Bits rem 8)), DB, Direction, Interfaces, Ports),
- init_acl(T, Family, DB);
- {ok, Addr} ->
- create_mask(tuple_to_list(Addr), Bits div 16,
- get_mask16((Bits rem 16)), DB, Direction, Interfaces, Ports),
- init_acl(T, Family, DB)
- end.
-
-create_mask(List, Div, Mask, DB, Direction, Interfaces, Ports) ->
- case split(Div, List) of
- {[], [Partial|_DontCare]} ->
- %% Less than 8/16 bits (depends on family).
- add_parts([], Direction, (Partial band Mask), Mask, DB,
- Interfaces, Ports);
- {Full, [Partial|_DontCare]} ->
- add_parts(Full, Direction, (Partial band Mask), Mask, DB,
- Interfaces, Ports);
- {Full, []} ->
- %% 32 bits.
- add_parts(Full, Direction, ?STOP, Mask, DB, Interfaces, Ports)
- end.
-
-add_parts([], Parent, Bits, Mask, DB, Interfaces, Ports) ->
- ets:insert(DB, #acl{key = Parent, bits = Bits,
- mask = Mask, interfaces = Interfaces, ports = Ports});
-add_parts([H|T], Parent, Bits, Mask, DB, Interfaces, Ports) ->
- Key = {Parent, H},
- ets:insert(DB, #acl{key = Key}),
- add_parts(T, Key, Bits, Mask, DB, Interfaces, Ports).
-
-
-%%-----------------------------------------------------------------
-%% function : match/1/2
-%% Arguments: IP - tuple() | [integer()]
-%% Direction - tcp_in | ssl_in | tcp_out | ssl_out
-%% All - boolean()
-%% Returns :
-%% Exception:
-%% Effect :
-%%-----------------------------------------------------------------
-match(IPTuple, Direction) when is_tuple(IPTuple) ->
- match_helper(tuple_to_list(IPTuple), Direction, ?ACL_DB, false, Direction);
-match(IPList, Direction) ->
- match_helper(IPList, Direction, ?ACL_DB, false, Direction).
-
-match(IPTuple, Direction, All) when is_tuple(IPTuple) ->
- match_helper(tuple_to_list(IPTuple), Direction, ?ACL_DB, All, Direction);
-match(IPList, Direction, All) ->
- match_helper(IPList, Direction, ?ACL_DB, All, Direction).
-
-match_helper([], _, _, false, _) -> false;
-match_helper([], _, _, true, _) -> {false, [], 0};
-match_helper([H|T], Parent, DB, All, Direction) ->
- case ets:lookup(DB, {Parent, H}) of
- [#acl{bits = ?CONTINUE}] ->
- match_helper(T, {Parent, H}, DB, All, Direction);
- [#acl{bits = ?STOP}] when All == false ->
- true;
- [#acl{bits = ?STOP, interfaces = I, ports = Ports}] ->
- {true, I, Ports};
- [#acl{bits = Bits, mask = Mask}] when All == false ->
- Bits == (hd(T) band Mask);
- [#acl{bits = Bits, mask = Mask, interfaces = I, ports = Ports}] ->
- {Bits == (hd(T) band Mask), I, Ports};
- _ ->
- %% Less than 8/16 significant bits (depends on family).
- %% Should we even allow this?
- case ets:lookup(DB, Direction) of
- [#acl{bits = Bits, mask = Mask}] when is_integer(Bits) andalso
- All == false ->
- Bits == (H band Mask);
- [#acl{bits = Bits, mask = Mask,
- interfaces = I, ports = Ports}] when is_integer(Bits) ->
- {Bits == (H band Mask), I, Ports};
- _ when All == false ->
- false;
- _ ->
- {false, [], 0}
- end
- end.
-
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% function : tokenize/1
-%% Arguments: Filter - string(). Examples:
-%% * "123.456.789.10" - match against all.
-%% * "123.456.789.10/17" - match against the 17 most significant bits.
-%% * "123.456.789.10/17#4001" - as above but only allow port 4001
-%% * "123.456.789.10/17#4001/5001" - as above but only allow port 4001-5001
-%% Family - inet | inet6
-%% Returns : {MaskStr, Bits, Ports}
-%% MaskStr - string()
-%% Bits - integer()
-%% Ports - integer() | {integer(), integer()}
-%% Exception:
-%% Effect :
-%%-----------------------------------------------------------------
-tokenize(Filter, Family) ->
- case string:tokens(Filter, "/#") of
- [MaskStr] when Family == inet ->
- {MaskStr, 32, 0};
- [MaskStr] when Family == inet6 ->
- {MaskStr, 128, 0};
- [MaskStr, BitString] ->
- {MaskStr, list_to_integer(BitString), 0};
- [MaskStr, BitString, Port] ->
- {MaskStr, list_to_integer(BitString), list_to_integer(Port)};
- [MaskStr, BitString, MinPort, MaxPort] ->
- {MaskStr, list_to_integer(BitString),
- {list_to_integer(MinPort), list_to_integer(MaxPort)}};
- What ->
- ?EFORMAT("Invalid Filter: ~p\nReason: ~p\n", [Filter, What])
- end.
-
-
-%%-----------------------------------------------------------------
-%% function : get_mask/2
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%-----------------------------------------------------------------
-get_mask(8, Bits) ->
- get_mask8(Bits);
-get_mask(16, Bits) ->
- get_mask16(Bits).
-
-%%-----------------------------------------------------------------
-%% function : get_mask8/1
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%-----------------------------------------------------------------
-get_mask8(0) -> 2#00000000;
-get_mask8(1) -> 2#10000000;
-get_mask8(2) -> 2#11000000;
-get_mask8(3) -> 2#11100000;
-get_mask8(4) -> 2#11110000;
-get_mask8(5) -> 2#11111000;
-get_mask8(6) -> 2#11111100;
-get_mask8(7) -> 2#11111110.
-
-%%-----------------------------------------------------------------
-%% function : get_mask16/1
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%-----------------------------------------------------------------
-get_mask16(0) -> 2#0000000000000000;
-get_mask16(1) -> 2#1000000000000000;
-get_mask16(2) -> 2#1100000000000000;
-get_mask16(3) -> 2#1110000000000000;
-get_mask16(4) -> 2#1111000000000000;
-get_mask16(5) -> 2#1111100000000000;
-get_mask16(6) -> 2#1111110000000000;
-get_mask16(7) -> 2#1111111000000000;
-get_mask16(8) -> 2#1111111100000000;
-get_mask16(9) -> 2#1111111110000000;
-get_mask16(10) -> 2#1111111111000000;
-get_mask16(11) -> 2#1111111111100000;
-get_mask16(12) -> 2#1111111111110000;
-get_mask16(13) -> 2#1111111111111000;
-get_mask16(14) -> 2#1111111111111100;
-get_mask16(15) -> 2#1111111111111110.
-
-
-%%-----------------------------------------------------------------
-%%------------- END OF MODULE -------------------------------------
-%%-----------------------------------------------------------------
diff --git a/lib/orber/src/orber_diagnostics.erl b/lib/orber/src/orber_diagnostics.erl
deleted file mode 100644
index 18d28fcf35..0000000000
--- a/lib/orber/src/orber_diagnostics.erl
+++ /dev/null
@@ -1,241 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: orber_diagnostics.erl
-%%
-%% Description:
-%%
-%%-----------------------------------------------------------------
-
--module(orber_diagnostics).
-
-
-%%-----------------------------------------------------------------
-%% Includes
-%%-----------------------------------------------------------------
--include_lib("orber/src/orber_iiop.hrl").
--include_lib("orber/src/ifr_objects.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming_NamingContext.hrl").
--include_lib("orber/COSS/CosNaming/orber_cosnaming.hrl").
-
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([nameservice/0, nameservice/1,
- objectkeys/0,
- missing_modules/0]).
-
-%%-----------------------------------------------------------------
-%% Internal Exports
-%%-----------------------------------------------------------------
--export([]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
-
-%%-----------------------------------------------------------------
-%% Macros
-%%-----------------------------------------------------------------
--define(DEBUG_LEVEL, 5).
-
--define(DIAGNOSTICS_PING_EXTERNAL, 16#01).
-
-%%-----------------------------------------------------------------
-%% Function : missing_modules
-%% Args : -
-%% Returns :
-%%-----------------------------------------------------------------
-missing_modules() ->
- List =
- case orber:light_ifr() of
- false ->
- Unions = mnesia:dirty_select(ir_UnionDef,
- [{#ir_UnionDef{absolute_name='$1',
- _='_'},
- [], ['$1']}]),
- Structs = mnesia:dirty_select(ir_StructDef,
- [{#ir_StructDef{absolute_name='$1',
- _='_'},
- [], ['$1']}]),
- Exc = mnesia:dirty_select(ir_ExceptionDef,
- [{#ir_ExceptionDef{absolute_name='$1',
- _='_'},
- [], ['$1']}]),
- Interface = mnesia:dirty_select(ir_InterfaceDef,
- [{#ir_InterfaceDef{absolute_name='$1',
- _='_'},
- [], ['$1']}]),
- Acc1 = create_module_names(Unions, [], ?IFR_UnionDef),
- Acc2 = create_module_names(Structs, Acc1, ?IFR_StructDef),
- Acc3 = create_module_names(Exc, Acc2, ?IFR_ExceptionDef),
- create_module_names(Interface, Acc3, ?IFR_InterfaceDef);
- true ->
- mnesia:dirty_select(orber_light_ifr,
- [{#orber_light_ifr{module='$1',
- type='$2', _='_'},
- [{'=/=', '$2', ?IFR_ModuleDef},
- {'=/=', '$2', ?IFR_ConstantDef},
- {'=/=', '$2', ?IFR_AliasDef},
- {'=/=', '$2', ?IFR_EnumDef}], ['$$']}])
- end,
- io:format("Need to check for ~p modules.~n", [length(List)]),
- Count = missing_modules_helper(List, 0),
- io:format("Check completed. ~p missing modules.~n", [Count]),
- Count.
-
-create_module_names([], Acc, _) ->
- Acc;
-create_module_names([[$:,$:|N]|T], Acc, Type) ->
- create_module_names(T, [[change_colons_to_underscore(N, []), Type]|Acc], Type).
-
-change_colons_to_underscore([$:, $: | T], Acc) ->
- change_colons_to_underscore(T, [$_ |Acc]);
-change_colons_to_underscore([H |T], Acc) ->
- change_colons_to_underscore(T, [H |Acc]);
-change_colons_to_underscore([], Acc) ->
- list_to_atom(lists:reverse(Acc)).
-
-missing_modules_helper([], ErrorsFound) ->
- ErrorsFound;
-missing_modules_helper([[Mod, Type]|T], ErrorsFound) when Type == ?IFR_StructDef;
- Type == ?IFR_UnionDef;
- Type == ?IFR_ExceptionDef ->
- case catch Mod:tc() of
- {'EXIT', _} ->
- io:format("Missing (~s): ~p~n", [type2str(Type), Mod]),
- missing_modules_helper(T, ErrorsFound + 1);
- _ ->
- missing_modules_helper(T, ErrorsFound)
- end;
-missing_modules_helper([[Mod, Type]|T], ErrorsFound) when Type == ?IFR_InterfaceDef ->
- case catch Mod:oe_get_interface() of
- {'EXIT', {undef,[{Mod, _, _, _}|_]}} ->
- io:format("Missing (Interface): ~p~n", [Mod]),
- missing_modules_helper(T, ErrorsFound + 1);
- {'EXIT', {undef,[{OtherMod, _, _, _}|_]}} ->
- io:format("Missing (Inherited by the ~p Interface): ~p~n",
- [Mod, OtherMod]),
- missing_modules_helper(T, ErrorsFound + 1);
- _ ->
- missing_modules_helper(T, ErrorsFound)
- end;
-missing_modules_helper([_|T], ErrorsFound) ->
- missing_modules_helper(T, ErrorsFound).
-
-type2str(?IFR_StructDef) ->
- "Struct";
-type2str(?IFR_UnionDef) ->
- "Union";
-type2str(?IFR_ExceptionDef) ->
- "Exception".
-
-
-%%-----------------------------------------------------------------
-%% Function : nameservice
-%% Args : - | integer()
-%% Returns :
-%%-----------------------------------------------------------------
-nameservice() ->
- nameservice(0).
-
-nameservice(Flags) ->
- case catch ns(?ORB_FLAG_TEST(Flags, ?DIAGNOSTICS_PING_EXTERNAL)) of
- ok ->
- ok;
- {'EXCEPTION', E} ->
- orber:dbg("[~p] orber_diagnostics:nameservice(~p);~n"
- "Reason: ~p", [?LINE, Flags, E], ?DEBUG_LEVEL),
- corba:raise(E);
- What ->
- orber:dbg("[~p] orber_diagnostics:nameservice(~p);~n"
- "Reason: ~p", [?LINE, Flags, What], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-ns(Ping) ->
- NS = corba:resolve_initial_references("NameService"),
- display_names(NS, "", Ping).
-
-
-display_names(NS, Prefix, Ping) ->
- {ok, [], Iter} = 'CosNaming_NamingContextExt':list(NS, 0),
- More = not corba_object:is_nil(Iter),
- iter_names(NS, Prefix, Iter, More, Ping).
-
-iter_names(_NS, _Prefix, Iter, false, _) ->
- destroy_iter(Iter);
-iter_names(NS, Prefix, Iter, true, Ping) ->
- {More, #'CosNaming_Binding'{binding_name = Name, binding_type = Type}} =
- 'CosNaming_BindingIterator':next_one(Iter),
- Fun = fun(#'CosNaming_NameComponent'{id = Id, kind = Kind}, Acc) ->
- case Kind of
- "" -> Acc ++ Id ++ "/";
- _ -> Acc ++ Id ++ "." ++ Kind ++ "/"
- end
- end,
- Prefix2 = lists:foldl(Fun, Prefix, Name),
- if
- More == false ->
- ignore;
- Type == nobject ->
- Object = 'CosNaming_NamingContext':resolve(NS, Name),
- Status =
- case corba_object:is_remote(Object) of
- false ->
- corba_object:non_existent(Object);
- _ when Ping == true ->
- case catch corba_object:non_existent(Object) of
- Boolean when is_atom(Boolean) ->
- Boolean;
- _Other ->
- undefined
- end;
- _ ->
- external
- end,
- io:format("~s [~p] ~s\n",
- [Prefix2, Status, iop_ior:get_typeID(Object)]);
- Type == ncontext ->
- Context = 'CosNaming_NamingContext':resolve(NS, Name),
- io:format("~s\n", [Prefix2]),
- display_names(Context, Prefix2, Ping)
- end,
- iter_names(NS, Prefix, Iter, More, Ping).
-
-destroy_iter(Iter) ->
- case corba_object:is_nil(Iter) of
- false ->
- 'CosNaming_BindingIterator':destroy(Iter),
- ok;
- true ->
- ok
- end.
-
-objectkeys() ->
- ok.
-
-
-
-%%---------------- END OF MODULE ----------------------------------
diff --git a/lib/orber/src/orber_env.erl b/lib/orber/src/orber_env.erl
deleted file mode 100644
index 3000af6cd3..0000000000
--- a/lib/orber/src/orber_env.erl
+++ /dev/null
@@ -1,1545 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: orber_env.erl
-%%
-%% Description:
-%% Handling environment parameters for Orber.
-%%
-%% Creation date: 040723
-%%
-%%-----------------------------------------------------------------
--module(orber_env).
-
--behaviour(gen_server).
-
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([start/1, configure/2, configure/3, configure_override/2,
- multi_configure/1, get_env/1, set_env/2, get_keys/0, env/1,
- info/0, info/1]).
-
--export([iiop_acl/0, iiop_port/0, nat_iiop_port/0, nat_iiop_port/1, iiop_out_ports/0,
- domain/0, ip_address_variable_defined/0, nat_host/0, nat_host/1, host/0,
- ip_address/0, ip_address/1, giop_version/0, iiop_timeout/0, iiop_out_ports_random/0,
- iiop_connection_timeout/0, iiop_setup_connection_timeout/0, iiop_out_ports_attempts/0,
- iiop_in_connection_timeout/0, iiop_max_fragments/0, iiop_max_in_requests/0,
- iiop_max_in_connections/0, iiop_backlog/0, objectkeys_gc_time/0,
- get_ORBInitRef/0, get_ORBDefaultInitRef/0, get_interceptors/0,
- get_local_interceptors/0, get_cached_interceptors/0,
- set_interceptors/1, is_lightweight/0, get_lightweight_nodes/0, secure/0,
- iiop_ssl_backlog/0, iiop_ssl_port/0, nat_iiop_ssl_port/0, nat_iiop_ssl_port/1,
- ssl_server_options/0, ssl_client_options/0, set_ssl_client_options/1,
- ssl_server_certfile/0, ssl_client_certfile/0, set_ssl_client_certfile/1,
- ssl_server_verify/0, ssl_client_verify/0, set_ssl_client_verify/1,
- ssl_server_depth/0, ssl_client_depth/0, set_ssl_client_depth/1,
- ssl_server_cacertfile/0, ssl_client_cacertfile/0,
- set_ssl_client_cacertfile/1, ssl_client_password/0,
- ssl_server_password/0, ssl_client_keyfile/0, ssl_server_keyfile/0,
- ssl_client_ciphers/0, ssl_server_ciphers/0, ssl_client_cachetimeout/0,
- ssl_server_cachetimeout/0,
- get_flags/0, typechecking/0,
- exclude_codeset_ctx/0, exclude_codeset_component/0, partial_security/0,
- use_CSIv2/0, use_FT/0, ip_version/0, light_ifr/0, bidir_context/0,
- get_debug_level/0, getaddrstr/2, addr2str/1, iiop_packet_size/0,
- iiop_ssl_ip_address_local/0, ip_address_local/0, iiop_in_keepalive/0,
- iiop_out_keepalive/0, iiop_ssl_in_keepalive/0, iiop_ssl_out_keepalive/0,
- iiop_ssl_accept_timeout/0, ssl_generation/0]).
-
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([init/1, terminate/2, handle_call/3]).
--export([handle_cast/2, handle_info/2, code_change/3]).
-
-%%-----------------------------------------------------------------
-%% Record Definitions Etc.
-%%-----------------------------------------------------------------
--define(DEBUG_LEVEL, 5).
-
--define(FORMAT(_F, _A), {error, lists:flatten(io_lib:format(_F, _A))}).
--define(EFORMAT(_F, _A), exit(lists:flatten(io_lib:format(_F, _A)))).
-
--define(ENV_DB, orber_env_db).
-
--define(ENV_KEYS,
- [flags, iiop_port, nat_iiop_port, iiop_out_ports, domain, ip_address,
- nat_ip_address, giop_version, iiop_timeout, iiop_connection_timeout,
- iiop_setup_connection_timeout, iiop_in_connection_timeout, iiop_acl,
- iiop_max_fragments, iiop_max_in_requests, iiop_max_in_connections,
- iiop_backlog, objectkeys_gc_time, orbInitRef, orbDefaultInitRef,
- interceptors, local_interceptors, lightweight, ip_address_local,
- secure, iiop_ssl_ip_address_local, iiop_ssl_backlog,
- iiop_ssl_port, nat_iiop_ssl_port, ssl_server_certfile,
- ssl_client_certfile, ssl_server_verify, ssl_client_verify, ssl_server_depth,
- ssl_client_depth, ssl_server_cacertfile, ssl_client_cacertfile,
- ssl_client_password, ssl_server_password, ssl_client_keyfile,
- ssl_server_keyfile, ssl_client_ciphers, ssl_server_ciphers,
- ssl_client_cachetimeout, ssl_server_cachetimeout, orber_debug_level,
- iiop_packet_size, iiop_in_keepalive, iiop_out_keepalive,
- iiop_ssl_in_keepalive, iiop_ssl_out_keepalive, iiop_ssl_accept_timeout,
- ssl_server_options, ssl_client_options]).
-
-%% The 'flags' parameter must be first in the list.
-%-define(ENV_KEYS,
-% [{flags, ?ORB_ENV_INIT_FLAGS}, {iiop_port, 4001}, nat_iiop_port,
-% {iiop_out_ports, 0}, {domain, "ORBER"}, ip_address, nat_ip_address,
-% {giop_version, {1, 1}}, {iiop_timeout, infinity},
-% {iiop_connection_timeout, infinity}, {iiop_setup_connection_timeout, infinity},
-% {iiop_in_connection_timeout, infinity}, {iiop_acl, []},
-% {iiop_max_fragments, infinity}, {iiop_max_in_requests, infinity},
-% {iiop_max_in_connections, infinity}, {iiop_backlog, 5},
-% {objectkeys_gc_time, infinity},
-% {orbInitRef, undefined}, {orbDefaultInitRef, undefined},
-% {interceptors, false}, {local_interceptors, false}, {lightweight, false},
-% {secure, no}, {iiop_ssl_backlog, 5}, {iiop_ssl_port, 4002},
-% nat_iiop_ssl_port, {ssl_server_certfile, []}, {ssl_client_certfile, []},
-% {ssl_server_verify, 0}, {ssl_client_verify, 0}, {ssl_server_depth, 1},
-% {ssl_client_depth, 1}, {ssl_server_cacertfile, []},
-% {ssl_client_cacertfile, []}, {ssl_client_password, []},
-% {ssl_server_password, []}, {ssl_client_keyfile, []},
-% {ssl_server_keyfile, []}, {ssl_client_ciphers, []},
-% {ssl_server_ciphers, []}, {ssl_client_cachetimeout, infinity},
-% {ssl_server_cachetimeout, infinity}, {orber_debug_level, 0}]).
-
--record(parameters, {key, value, flags = 0}).
-
--record(env, {acl, parameters, flags = 0}).
-
-
-%%-----------------------------------------------------------------
-%% External functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% function :
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%-----------------------------------------------------------------
-start(Opts) ->
- gen_server:start_link({local, orber_env}, ?MODULE, Opts, []).
-
-%%-----------------------------------------------------------------
-%% function : get_keys
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%-----------------------------------------------------------------
-get_keys() ->
- ?ENV_KEYS.
-
-%%-----------------------------------------------------------------
-%% function : get_env
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%-----------------------------------------------------------------
-get_env(Key) when is_atom(Key) ->
- case catch ets:lookup(?ENV_DB, Key) of
- [#parameters{value = Val}] ->
- {ok, Val};
- _ ->
- undefined
- end.
-
-%%-----------------------------------------------------------------
-%% function : get_env
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%-----------------------------------------------------------------
-set_env(Key, Value) when is_atom(Key) ->
- case catch ets:insert(?ENV_DB, #parameters{key = Key, value = Value}) of
- true ->
- ok;
- _ ->
- undefined
- end.
-
-
-%%-----------------------------------------------------------------
-%% function : info
-%% Arguments: IoDervice - info_msg | string | io | {io, Dev}
-%% Returns :
-%% Exception:
-%% Effect :
-%%-----------------------------------------------------------------
-info() ->
- info(info_msg).
-
-info(IoDevice) ->
- Info =
- case orber_tb:is_running() of
- true ->
- Info1 = create_main_info(),
- Info2 = create_flag_info(Info1),
- create_security_info(secure(), Info2);
- _ ->
- lists:flatten(
- io_lib:format("======= Orber Execution Environment ======~n"
- " *** Orber is not running ***~n"
- "==========================================~n",
- []))
- end,
- case IoDevice of
- info_msg ->
- error_logger:info_msg(Info);
- string ->
- Info;
- io ->
- io:format("~s", [Info]);
- {io, Dev} ->
- io:format(Dev, "~s", [Info]);
- _ ->
- exit("Bad parameter")
- end.
-
-create_main_info() ->
- {Major, Minor} = giop_version(),
- {orber, _, OrberVsn} = lists:keyfind(orber, 1, application:loaded_applications()),
- [io_lib:format("======= Orber Execution Environment ======~n"
- "Orber version.................: ~s~n"
- "Orber domain..................: ~s~n"
- "IIOP port number..............: ~p~n"
- "IIOP NAT port number..........: ~p~n"
- "Interface(s)..................: ~p~n"
- "Interface(s) NAT..............: ~p~n"
- "Local Interface (default).....: ~p~n"
- "Nodes in domain...............: ~p~n"
- "GIOP version (default)........: ~p.~p~n"
- "IIOP out timeout..............: ~p msec~n"
- "IIOP out connection timeout...: ~p msec~n"
- "IIOP setup connection timeout.: ~p msec~n"
- "IIOP out ports................: ~p~n"
- "IIOP out ports attempts.......: ~p~n"
- "IIOP out ports random.........: ~p~n"
- "IIOP out connections..........: ~p~n"
- "IIOP out connections (pending): ~p~n"
- "IIOP out keepalive............: ~p~n"
- "IIOP in connections...........: ~p~n"
- "IIOP in connection timeout....: ~p msec~n"
- "IIOP in keepalive.............: ~p~n"
- "IIOP max fragments............: ~p~n"
- "IIOP max in requests..........: ~p~n"
- "IIOP max in connections.......: ~p~n"
- "IIOP backlog..................: ~p~n"
- "IIOP ACL......................: ~p~n"
- "IIOP maximum packet size......: ~p~n"
- "Object Keys GC interval.......: ~p~n"
- "Using Interceptors............: ~p~n"
- "Using Local Interceptors......: ~p~n"
- "Debug Level...................: ~p~n"
- "orbInitRef....................: ~p~n"
- "orbDefaultInitRef.............: ~p~n",
- [OrberVsn, domain(), iiop_port(), nat_iiop_port(), host(),
- nat_host(), ip_address_local(),
- orber:orber_nodes(), Major, Minor,
- iiop_timeout(), iiop_connection_timeout(),
- iiop_setup_connection_timeout(), iiop_out_ports(),
- iiop_out_ports_attempts(), iiop_out_ports_random(),
- orber:iiop_connections(out), orber:iiop_connections_pending(),
- iiop_out_keepalive(), orber:iiop_connections(in),
- iiop_in_connection_timeout(), iiop_in_keepalive(),
- iiop_max_fragments(), iiop_max_in_requests(),
- iiop_max_in_connections(), iiop_backlog(), iiop_acl(),
- iiop_packet_size(), objectkeys_gc_time(), get_interceptors(),
- get_local_interceptors(), get_debug_level(), get_ORBInitRef(),
- get_ORBDefaultInitRef()])].
-
-create_flag_info(Info) ->
- case get_flags() of
- ?ORB_ENV_INIT_FLAGS ->
- [Info, "System Flags Set..............: -\n"];
- Flags ->
- FlagData = check_flags(?ORB_ENV_FLAGS, Flags, []),
- [Info, "System Flags Set..............: \n", FlagData, "\n"]
- end.
-
-check_flags([], _, Acc) ->
- Acc;
-check_flags([{Flag, Txt}|T], Flags, Acc) when ?ORB_FLAG_TEST(Flags, Flag) ->
- check_flags(T, Flags, [" - ", Txt, "\n"|Acc]);
-check_flags([_|T], Flags, Acc) ->
- check_flags(T, Flags, Acc).
-
-
-create_security_info(no, Info) ->
- lists:flatten([Info, "=========================================\n"]);
-create_security_info(ssl, Info) ->
- lists:flatten([Info,
- io_lib:format("ORB security..................: ssl~n"
- "SSL generation................: ~p~n"
- "SSL IIOP in keepalive.........: ~p~n"
- "SSL IIOP out keepalive........: ~p~n"
- "SSL IIOP port number..........: ~p~n"
- "SSL IIOP NAT port number......: ~p~n"
- "SSL IIOP accept timeout.......: ~p~n"
- "SSL IIOP backlog..............: ~p~n"
- "SSL IIOP Local Interface......: ~p~n"
- "SSL server options............: ~p~n"
- "SSL server certfile...........: ~p~n"
- "SSL server verification type..: ~p~n"
- "SSL server verification depth.: ~p~n"
- "SSL server cacertfile.........: ~p~n"
- "SSL server keyfile............: ~p~n"
- "SSL server password...........: ~p~n"
- "SSL server ciphers............: ~p~n"
- "SSL server cachetimeout.......: ~p~n"
- "SSL client options............: ~p~n"
- "SSL client certfile...........: ~p~n"
- "SSL client verification type..: ~p~n"
- "SSL client verification depth.: ~p~n"
- "SSL client cacertfile.........: ~p~n"
- "SSL client keyfile............: ~p~n"
- "SSL client password...........: ~p~n"
- "SSL client ciphers............: ~p~n"
- "SSL client cachetimeout.......: ~p~n"
- "=========================================~n",
- [ssl_generation(), iiop_ssl_port(),
- iiop_ssl_in_keepalive(), iiop_ssl_out_keepalive(),
- nat_iiop_ssl_port(), iiop_ssl_accept_timeout(),
- iiop_ssl_backlog(), iiop_ssl_ip_address_local(),
- ssl_server_options(),
- ssl_server_certfile(), ssl_server_verify(),
- ssl_server_depth(), ssl_server_cacertfile(),
- ssl_server_keyfile(), ssl_server_password(),
- ssl_server_ciphers(), ssl_server_cachetimeout(),
- ssl_client_options(),
- ssl_client_certfile(), ssl_client_verify(),
- ssl_client_depth(), ssl_client_cacertfile(),
- ssl_client_keyfile(), ssl_client_password(),
- ssl_client_ciphers(), ssl_client_cachetimeout()])]).
-
-
-%%-----------------------------------------------------------------
-%% function : iiop_acl
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%-----------------------------------------------------------------
-iiop_acl() ->
- case application:get_env(orber, iiop_acl) of
- {ok, ACL} when is_list(ACL) ->
- ACL;
- _ ->
- []
- end.
-
-iiop_packet_size() ->
- case application:get_env(orber, iiop_packet_size) of
- {ok, Max} when is_integer(Max) andalso Max > 0 ->
- Max;
- _ ->
- infinity
- end.
-
-
-iiop_port() ->
- case application:get_env(orber, iiop_port) of
- {ok, Port} when is_integer(Port) andalso Port >= 0 ->
- Port;
- _ ->
- 4001
- end.
-
-nat_iiop_port() ->
- case application:get_env(orber, nat_iiop_port) of
- {ok, Port} when is_integer(Port) andalso Port > 0 ->
- Port;
- {ok, {local, Default, _NATList}} ->
- Default;
- _ ->
- iiop_port()
- end.
-
-nat_iiop_port(LocalPort) ->
- case application:get_env(orber, nat_iiop_port) of
- {ok, Port} when is_integer(Port) andalso Port > 0 ->
- Port;
- {ok, {local, Default, NATList}} ->
- orber_tb:keysearch(LocalPort, NATList, Default);
- _ ->
- iiop_port()
- end.
-
-iiop_out_ports() ->
- case application:get_env(orber, iiop_out_ports) of
- {ok, {Min, Max}} when is_integer(Min) andalso is_integer(Max) andalso Min =< Max ->
- {Min, Max};
- {ok, {Max, Min}} when is_integer(Min) andalso is_integer(Max) andalso Min < Max ->
- {Min, Max};
- _ ->
- 0
- end.
-
-iiop_out_ports_random() ->
- case application:get_env(orber, iiop_out_ports_random) of
- {ok, true} ->
- true;
- _ ->
- false
- end.
-
-iiop_out_ports_attempts() ->
- case application:get_env(orber, iiop_out_ports_attempts) of
- {ok, No} when is_integer(No) andalso No > 0 ->
- No;
- _ ->
- 1
- end.
-
-
-domain() ->
- case application:get_env(orber, domain) of
- {ok, Domain} when is_list(Domain) ->
- Domain;
- {ok, Domain} when is_atom(Domain) ->
- atom_to_list(Domain);
- _ ->
- "ORBER"
- end.
-
-ip_address_variable_defined() ->
- case application:get_env(orber, ip_address) of
- undefined ->
- false;
- {ok,{multiple, _}} ->
- false;
- _ ->
- [Host] = host(),
- Host
- end.
-
-nat_host() ->
- case application:get_env(orber, nat_ip_address) of
- {ok,I} when is_list(I) ->
- [I];
- {ok,{multiple, [I|_] = IList}} when is_list(I) ->
- IList;
- {ok,{local, Default, _NATList}} ->
- [Default];
- _ ->
- host()
- end.
-
-nat_host([Host]) ->
- case application:get_env(orber, nat_ip_address) of
- {ok,I} when is_list(I) ->
- [I];
- {ok,{multiple, [I|_] = IList}} when is_list(I) ->
- IList;
- {ok,{local, Default, NATList}} ->
- [orber_tb:keysearch(Host, NATList, Default)];
- _ ->
- host()
- end.
-
-
-host() ->
- case application:get_env(orber, ip_address) of
- {ok,I} when is_list(I) ->
- [I];
- {ok,{multiple, [I|_] = IList}} when is_list(I) ->
- IList;
- %% IPv4. For IPv6 we only accept a string, but we must support this format
- %% for IPv4
- {ok, {A1, A2, A3, A4}} when is_integer(A1+A2+A3+A4) ->
- [integer_to_list(A1) ++ "." ++ integer_to_list(A2) ++ "." ++ integer_to_list(A3)
- ++ "." ++ integer_to_list(A4)];
- _ ->
- Flags = get_flags(),
- case ?ORB_FLAG_TEST(Flags, ?ORB_ENV_HOSTNAME_IN_IOR) of
- true ->
- {ok, Hostname} = inet:gethostname(),
- [Hostname];
- _ ->
- case ?ORB_FLAG_TEST(Flags, ?ORB_ENV_USE_IPV6) of
- false ->
- [ip_address(inet)];
- true ->
- [ip_address(inet6)]
- end
- end
- end.
-
-ip_address_local() ->
- case application:get_env(orber, ip_address_local) of
- {ok,I} when is_list(I) ->
- [I];
- _ ->
- []
- end.
-
-
-ip_address() ->
- ip_address(ip_version()).
-
-ip_address(inet) ->
- {ok, Hostname} = inet:gethostname(),
- {ok, {A1, A2, A3, A4}} = inet:getaddr(Hostname, inet),
- integer_to_list(A1) ++ "." ++ integer_to_list(A2) ++ "." ++ integer_to_list(A3)
- ++ "." ++ integer_to_list(A4);
-ip_address(inet6) ->
- {ok, Hostname} = inet:gethostname(),
- {ok, {A1, A2, A3, A4, A5, A6, A7, A8}} = inet:getaddr(Hostname, inet6),
- int16_to_hex(A1) ++ ":" ++int16_to_hex(A2) ++ ":" ++
- int16_to_hex(A3) ++ ":" ++ int16_to_hex(A4) ++ ":" ++
- int16_to_hex(A5) ++ ":" ++ int16_to_hex(A6) ++ ":" ++
- int16_to_hex(A7) ++ ":" ++ int16_to_hex(A8).
-
-getaddrstr(Hostname, inet) ->
- {ok, {A1, A2, A3, A4}} = inet:getaddr(Hostname, inet),
- integer_to_list(A1) ++ "." ++ integer_to_list(A2) ++ "." ++ integer_to_list(A3)
- ++ "." ++ integer_to_list(A4);
-getaddrstr(Hostname, inet6) ->
- {ok, {A1, A2, A3, A4, A5, A6, A7, A8}} = inet:getaddr(Hostname, inet6),
- int16_to_hex(A1) ++ ":" ++int16_to_hex(A2) ++ ":" ++
- int16_to_hex(A3) ++ ":" ++ int16_to_hex(A4) ++ ":" ++
- int16_to_hex(A5) ++ ":" ++ int16_to_hex(A6) ++ ":" ++
- int16_to_hex(A7) ++ ":" ++ int16_to_hex(A8).
-
-addr2str({A1, A2, A3, A4}) ->
- integer_to_list(A1) ++ "." ++ integer_to_list(A2) ++ "." ++ integer_to_list(A3)
- ++ "." ++ integer_to_list(A4);
-addr2str({A1, A2, A3, A4, A5, A6, A7, A8}) ->
- int16_to_hex(A1) ++ ":" ++int16_to_hex(A2) ++ ":" ++
- int16_to_hex(A3) ++ ":" ++ int16_to_hex(A4) ++ ":" ++
- int16_to_hex(A5) ++ ":" ++ int16_to_hex(A6) ++ ":" ++
- int16_to_hex(A7) ++ ":" ++ int16_to_hex(A8).
-
-
-int16_to_hex(0) ->
- [$0];
-int16_to_hex(I) ->
- N1 = ((I bsr 8) band 16#ff),
- N2 = (I band 16#ff),
- [code_character(N1 div 16), code_character(N1 rem 16),
- code_character(N2 div 16), code_character(N2 rem 16)].
-
-code_character(N) when N < 10 ->
- $0 + N;
-code_character(N) ->
- $A + (N - 10).
-
-giop_version() ->
- case application:get_env(orber, giop_version) of
- {ok, {Major, Minor}} ->
- {Major, Minor};
- _ ->
- {1, 1}
- end.
-
-iiop_timeout() ->
- case application:get_env(orber, iiop_timeout) of
- {ok, Int} when is_integer(Int) ->
- if
- Int > 1000000 ->
- error_logger:error_msg("Orber 'iiop_timeout' badly configured.~n"
- "Time to large (>1000000 sec), swithed to 'infinity'~n"),
- infinity;
- true ->
- %% Convert to msec.
- Int*1000
- end;
- _ ->
- infinity
- end.
-
-iiop_connection_timeout() ->
- case application:get_env(orber, iiop_connection_timeout) of
- {ok, Int} when is_integer(Int) ->
- if
- Int > 1000000 ->
- error_logger:error_msg("Orber 'iiop_connection_timeout' badly configured.~n"
- "Time to large (>1000000 sec), swithed to 'infinity'~n"),
- infinity;
- true ->
- %% Convert to msec.
- Int*1000
- end;
- _ ->
- infinity
- end.
-
-iiop_setup_connection_timeout() ->
- case application:get_env(orber, iiop_setup_connection_timeout) of
- {ok, Int} when is_integer(Int) ->
- %% Convert to msec.
- Int*1000;
- _ ->
- infinity
- end.
-
-iiop_in_connection_timeout() ->
- case application:get_env(orber, iiop_in_connection_timeout) of
- {ok, Int} when is_integer(Int) ->
- if
- Int > 1000000 ->
- error_logger:error_msg("Orber 'iiop_connection_timeout' badly configured.~n"
- "Time to large (>1000000 sec), swithed to 'infinity'~n"),
- infinity;
- true ->
- %% Convert to msec.
- Int*1000
- end;
- _ ->
- infinity
- end.
-
-iiop_max_fragments() ->
- case application:get_env(orber, iiop_max_fragments) of
- {ok, Max} when is_integer(Max) andalso Max > 0 ->
- Max;
- _ ->
- infinity
- end.
-
-iiop_max_in_requests() ->
- case application:get_env(orber, iiop_max_in_requests) of
- {ok, Max} when is_integer(Max) andalso Max > 0 ->
- Max;
- _ ->
- infinity
- end.
-
-iiop_max_in_connections() ->
- case application:get_env(orber, iiop_max_in_connections) of
- {ok, Max} when is_integer(Max) andalso Max > 0 ->
- Max;
- _ ->
- infinity
- end.
-
-iiop_backlog() ->
- case application:get_env(orber, iiop_backlog) of
- {ok, Int} when is_integer(Int) andalso Int >= 0 ->
- Int;
- _ ->
- 5
- end.
-
-iiop_in_keepalive() ->
- case application:get_env(orber, iiop_in_keepalive) of
- {ok, true} ->
- true;
- _ ->
- false
- end.
-
-iiop_out_keepalive() ->
- case application:get_env(orber, iiop_out_keepalive) of
- {ok, true} ->
- true;
- _ ->
- false
- end.
-
-
-
-get_flags() ->
- case get(oe_orber_flags) of
- undefined ->
- case application:get_env(orber, flags) of
- undefined ->
- put(oe_orber_flags, ?ORB_ENV_INIT_FLAGS),
- ?ORB_ENV_INIT_FLAGS;
- {ok, Flags} ->
- put(oe_orber_flags, Flags),
- Flags
- end;
- Flags when is_integer(Flags) ->
- Flags
- end.
-
-typechecking() ->
- ?ORB_FLAG_TEST(get_flags(), ?ORB_ENV_LOCAL_TYPECHECKING).
-
-exclude_codeset_ctx() ->
- ?ORB_FLAG_TEST(get_flags(), ?ORB_ENV_EXCLUDE_CODESET_CTX).
-
-exclude_codeset_component() ->
- ?ORB_FLAG_TEST(get_flags(), ?ORB_ENV_EXCLUDE_CODESET_COMPONENT).
-
-partial_security() ->
- ?ORB_FLAG_TEST(get_flags(), ?ORB_ENV_PARTIAL_SECURITY).
-
-use_CSIv2() ->
- ?ORB_FLAG_TEST(get_flags(), ?ORB_ENV_USE_CSIV2).
-
-use_FT() ->
- ?ORB_FLAG_TEST(get_flags(), ?ORB_ENV_USE_FT).
-
-ip_version() ->
- case ?ORB_FLAG_TEST(get_flags(), ?ORB_ENV_USE_IPV6) of
- false ->
- inet;
- true ->
- inet6
- end.
-
-light_ifr() ->
- ?ORB_FLAG_TEST(get_flags(), ?ORB_ENV_LIGHT_IFR).
-
-bidir_context() ->
- Flags = get_flags(),
- if
- ?ORB_FLAG_TEST(Flags, ?ORB_ENV_USE_BI_DIR_IIOP) ->
- [#'IOP_ServiceContext'
- {context_id=?IOP_BI_DIR_IIOP,
- context_data =
- #'IIOP_BiDirIIOPServiceContext'{listen_points =
- [#'IIOP_ListenPoint'{host=host(),
- port=iiop_port()}]}}];
- true ->
- []
- end.
-
-objectkeys_gc_time() ->
- case application:get_env(orber, objectkeys_gc_time) of
- {ok, Int} when is_integer(Int) ->
- if
- Int > 1000000 ->
- error_logger:error_msg("Orber 'objectkeys_gc_time' badly configured.~n"
- "Time to large (>1000000 sec), swithed to 'infinity'~n"),
- infinity;
- true ->
- Int
- end;
- _ ->
- infinity
- end.
-
-get_ORBInitRef() ->
- case application:get_env(orber, orbInitRef) of
- {ok, Ref} when is_list(Ref) ->
- Ref;
- _ ->
- undefined
- end.
-
-get_ORBDefaultInitRef() ->
- case application:get_env(orber, orbDefaultInitRef) of
- {ok, Ref} when is_list(Ref) ->
- Ref;
- _ ->
- undefined
- end.
-
-get_debug_level() ->
- case application:get_env(orber, orber_debug_level) of
- {ok, Level} when is_integer(Level) ->
- Level;
- _ ->
- 0
- end.
-
-
-%%-----------------------------------------------------------------
-%% Interceptor opertaions (see orber_pi.erl)
-%%-----------------------------------------------------------------
-get_interceptors() ->
- case application:get_env(orber, interceptors) of
- {ok, {native, PIs}} when is_list(PIs) ->
- {native, PIs};
- {ok, {portable, PIs}} when is_list(PIs) ->
- {portable, PIs};
- _ ->
- false
- end.
-
-get_local_interceptors() ->
- case application:get_env(orber, local_interceptors) of
- {ok, {native, PIs}} when is_list(PIs) ->
- {native, PIs};
- {ok, {portable, PIs}} when is_list(PIs) ->
- {portable, PIs};
- _ ->
- false
- end.
-
-
-get_cached_interceptors() ->
- case get(oe_orber_interceptor_cache) of
- undefined ->
- PIs = case application:get_env(orber, local_interceptors) of
- {ok, {native, LPIs}} when is_list(LPIs) ->
- {native, LPIs};
- {ok, {portable, LPIs}} when is_list(LPIs) ->
- {portable, LPIs};
- _ ->
- get_interceptors()
- end,
- put(oe_orber_interceptor_cache, PIs),
- PIs;
- PIs ->
- PIs
- end.
-
-
-set_interceptors({Type, InterceptorList}) when is_list(InterceptorList) ->
- configure(interceptors, {Type, InterceptorList});
-set_interceptors(_) ->
- exit({error, "Usage: {Type, ModuleList}"}).
-
-
-%%-----------------------------------------------------------------
-%% Light weight Orber operations
-%%-----------------------------------------------------------------
-is_lightweight() ->
- case application:get_env(orber, lightweight) of
- {ok, L} when is_list(L) ->
- true;
- _ ->
- false
- end.
-get_lightweight_nodes() ->
- case application:get_env(orber, lightweight) of
- {ok, L} when is_list(L) ->
- L;
- _ ->
- false
- end.
-
-
-%%-----------------------------------------------------------------
-%% Security access operations (SSL)
-%%-----------------------------------------------------------------
-secure() ->
- case application:get_env(orber, secure) of
- {ok, V} ->
- V;
- _ ->
- no
- end.
-
-ssl_generation() ->
- case application:get_env(orber, ssl_generation) of
- {ok, V} ->
- V;
- _ ->
- 2
- end.
-
-iiop_ssl_ip_address_local() ->
- case application:get_env(orber, iiop_ssl_ip_address_local) of
- {ok,I} when is_list(I) ->
- [I];
- _ ->
- []
- end.
-
-iiop_ssl_backlog() ->
- case application:get_env(orber, iiop_ssl_backlog) of
- {ok, Int} when is_integer(Int), Int >= 0 ->
- Int;
- _ ->
- 5
- end.
-
-iiop_ssl_in_keepalive() ->
- case application:get_env(orber, iiop_ssl_in_keepalive) of
- {ok, true} ->
- true;
- _ ->
- false
- end.
-
-iiop_ssl_out_keepalive() ->
- case application:get_env(orber, iiop_ssl_out_keepalive) of
- {ok, true} ->
- true;
- _ ->
- false
- end.
-
-iiop_ssl_accept_timeout() ->
- case application:get_env(orber, iiop_ssl_accept_timeout) of
- {ok, N} when is_integer(N) ->
- N * 1000;
- _ ->
- infinity
- end.
-
-iiop_ssl_port() ->
- case application:get_env(orber, secure) of
- {ok, ssl} ->
- case application:get_env(orber, iiop_ssl_port) of
- {ok, Port} when is_integer(Port) ->
- Port;
- _ ->
- 4002
- end;
- _ ->
- -1
- end.
-
-nat_iiop_ssl_port() ->
- case application:get_env(orber, secure) of
- {ok, ssl} ->
- case application:get_env(orber, nat_iiop_ssl_port) of
- {ok, Port} when is_integer(Port) andalso Port > 0 ->
- Port;
- {ok, {local, Default, _NATList}} ->
- Default;
- _ ->
- iiop_ssl_port()
- end;
- _ ->
- -1
- end.
-
-nat_iiop_ssl_port(LocalPort) ->
- case application:get_env(orber, secure) of
- {ok, ssl} ->
- case application:get_env(orber, nat_iiop_ssl_port) of
- {ok, Port} when is_integer(Port) andalso Port > 0 ->
- Port;
- {ok, {local, Default, NATList}} ->
- orber_tb:keysearch(LocalPort, NATList, Default);
- _ ->
- iiop_ssl_port()
- end;
- _ ->
- -1
- end.
-
-ssl_server_options() ->
- case application:get_env(orber, ssl_server_options) of
- {ok, V1} when is_list(V1) ->
- V1;
- _ ->
- []
- end.
-
-ssl_client_options() ->
- case application:get_env(orber, ssl_client_options) of
- {ok, V1} when is_list(V1) ->
- V1;
- _ ->
- []
- end.
-
-check_ssl_opts(Value) ->
- check_ssl_opts(Value, []).
-check_ssl_opts([], []) ->
- ok;
-check_ssl_opts([], Acc) ->
- {error, Acc};
-check_ssl_opts([{active, _} |T], Acc) ->
- check_ssl_opts(T, [active |Acc]);
-check_ssl_opts([{packet, _} |T], Acc) ->
- check_ssl_opts(T, [packet |Acc]);
-check_ssl_opts([{mode, _} |T], Acc) ->
- check_ssl_opts(T, [mode |Acc]);
-check_ssl_opts([list |T], Acc) ->
- check_ssl_opts(T, [list |Acc]);
-check_ssl_opts([binary |T], Acc) ->
- check_ssl_opts(T, [binary |Acc]);
-check_ssl_opts([_ |T], Acc) ->
- check_ssl_opts(T, Acc).
-
-set_ssl_client_options(Value) when is_list(Value) ->
- case check_ssl_opts(Value) of
- ok ->
- ok;
- {error, List} ->
- exit(lists:flatten(
- io_lib:format("TCP options ~p is not allowed in set_ssl_client_options()",
- [List])))
- end,
- put(ssl_client_options, Value), ok.
-
-ssl_server_certfile() ->
- case application:get_env(orber, ssl_server_certfile) of
- {ok, V1} when is_list(V1) ->
- V1;
- {ok, V2} when is_atom(V2) ->
- atom_to_list(V2);
- _ ->
- []
- end.
-
-ssl_client_certfile() ->
- case get(ssl_client_certfile) of
- undefined ->
- case application:get_env(orber, ssl_client_certfile) of
- {ok, V1} when is_list(V1) ->
- V1;
- {ok, V2} when is_atom(V2) ->
- atom_to_list(V2);
- _ ->
- []
- end;
- V ->
- V
- end.
-
-set_ssl_client_certfile(Value) when is_list(Value) ->
- put(ssl_client_certfile, Value).
-
-ssl_server_verify() ->
- Verify = case application:get_env(orber, ssl_server_verify) of
- {ok, V} when is_integer(V) ->
- V;
- _ ->
- 0
- end,
- if
- Verify =< 2, Verify >= 0 ->
- Verify;
- true ->
- 0
- end.
-
-ssl_client_verify() ->
- Verify = case get(ssl_client_verify) of
- undefined ->
- case application:get_env(orber, ssl_client_verify) of
- {ok, V1} when is_integer(V1) ->
- V1;
- _ ->
- 0
- end;
- V2 ->
- V2
- end,
- if
- Verify =< 2, Verify >= 0 ->
- Verify;
- true ->
- 0
- end.
-
-set_ssl_client_verify(Value) when is_integer(Value) andalso Value =< 2 andalso Value >= 0 ->
- put(ssl_client_verify, Value), ok.
-
-ssl_server_depth() ->
- case application:get_env(orber, ssl_server_depth) of
- {ok, V1} when is_integer(V1) ->
- V1;
- _ ->
- 1
- end.
-
-ssl_client_depth() ->
- case get(ssl_client_depth) of
- undefined ->
- case application:get_env(orber, ssl_client_depth) of
- {ok, V1} when is_integer(V1) ->
- V1;
- _ ->
- 1
- end;
- V2 ->
- V2
- end.
-
-set_ssl_client_depth(Value) when is_integer(Value) ->
- put(ssl_client_depth, Value), ok.
-
-
-
-ssl_server_cacertfile() ->
- case application:get_env(orber, ssl_server_cacertfile) of
- {ok, V1} when is_list(V1) ->
- V1;
- {ok, V2} when is_atom(V2) ->
- atom_to_list(V2);
- _ ->
- []
- end.
-
-ssl_client_cacertfile() ->
- case get(ssl_client_cacertfile) of
- undefined ->
- case application:get_env(orber, ssl_client_cacertfile) of
- {ok, V1} when is_list(V1) ->
- V1;
- {ok, V2} when is_atom(V2) ->
- atom_to_list(V2);
- _ ->
- []
- end;
- V3 ->
- V3
- end.
-
-set_ssl_client_cacertfile(Value) when is_list(Value) ->
- put(ssl_client_cacertfile, Value), ok.
-
-
-ssl_client_password() ->
- case application:get_env(orber, ssl_client_password) of
- {ok, V1} when is_list(V1) ->
- V1;
- _ ->
- []
- end.
-
-ssl_server_password() ->
- case application:get_env(orber, ssl_server_password) of
- {ok, V1} when is_list(V1) ->
- V1;
- _ ->
- []
- end.
-
-ssl_client_keyfile() ->
- case application:get_env(orber, ssl_client_keyfile) of
- {ok, V1} when is_list(V1) ->
- V1;
- _ ->
- []
- end.
-
-ssl_server_keyfile() ->
- case application:get_env(orber, ssl_server_keyfile) of
- {ok, V1} when is_list(V1) ->
- V1;
- _ ->
- []
- end.
-
-ssl_client_ciphers() ->
- case application:get_env(orber, ssl_client_ciphers) of
- {ok, V1} when is_list(V1) ->
- V1;
- _ ->
- []
- end.
-
-ssl_server_ciphers() ->
- case application:get_env(orber, ssl_server_ciphers) of
- {ok, V1} when is_list(V1) ->
- V1;
- _ ->
- []
- end.
-
-ssl_client_cachetimeout() ->
- case application:get_env(orber, ssl_client_cachetimeout) of
- {ok, V1} when is_integer(V1) ->
- V1;
- _ ->
- infinity
- end.
-
-ssl_server_cachetimeout() ->
- case application:get_env(orber, ssl_server_cachetimeout) of
- {ok, V1} when is_integer(V1) ->
- V1;
- _ ->
- infinity
- end.
-
-%%-----------------------------------------------------------------
-%% function : configure
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%-----------------------------------------------------------------
-configure(Key, Value) when is_atom(Key) ->
- configure(Key, Value, check);
-configure(Key, _) ->
- ?EFORMAT("Given key (~p) not an atom.", [Key]).
-
-configure_override(Key, Value) when is_atom(Key) ->
- configure(Key, Value, loaded);
-configure_override(Key, _) ->
- ?EFORMAT("Given key (~p) not an atom.", [Key]).
-
-%%-----------------------------------------------------------------
-%% function : multi_configure
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%-----------------------------------------------------------------
-multi_configure(KeyValueList) when is_list(KeyValueList) ->
- case orber_tb:is_loaded() of
- false ->
- application:load(orber),
- multi_configure_helper(KeyValueList, loaded);
- true ->
- case orber_tb:is_running() of
- false ->
- multi_configure_helper(KeyValueList, loaded);
- true ->
- multi_configure_helper(KeyValueList, running)
- end
- end;
-multi_configure(KeyValueList) ->
- ?EFORMAT("Given configuration parameters not a Key-Value-pair list: ~p",
- [KeyValueList]).
-
-multi_configure_helper([], _) ->
- ok;
-multi_configure_helper([{Key, Value}|T], Status) ->
- configure(Key, Value, Status),
- multi_configure_helper(T, Status);
-multi_configure_helper([What|_], _) ->
- ?EFORMAT("Incorrect configuration parameters supplied: ~p", [What]).
-
-
-%%------ Keys we can update at any time -----
-%% Initial Services References
-configure(orbDefaultInitRef, String, Status) when is_list(String) ->
- do_configure(orbDefaultInitRef, String, Status);
-configure(orbDefaultInitRef, undefined, Status) ->
- do_configure(orbDefaultInitRef, undefined, Status);
-configure(orbInitRef, String, Status) when is_list(String) ->
- do_configure(orbInitRef, String, Status);
-configure(orbInitRef, undefined, Status) ->
- do_configure(orbInitRef, undefined, Status);
-%% IIOP-version
-configure(giop_version, {1, 0}, Status) ->
- do_configure(giop_version, {1, 0}, Status);
-configure(giop_version, {1, 1}, Status) ->
- do_configure(giop_version, {1, 1}, Status);
-configure(giop_version, {1, 2}, Status) ->
- do_configure(giop_version, {1, 2}, Status);
-%% configure 'iiop_timout' will only have effect on new requests.
-configure(iiop_timeout, infinity, Status) ->
- do_configure(iiop_timeout, infinity, Status);
-configure(iiop_timeout, Value, Status) when is_integer(Value) andalso Value =< 1000000 ->
- do_configure(iiop_timeout, Value, Status);
-%% Backlog
-configure(iiop_backlog, Value, Status) when is_integer(Value) andalso Value >= 0 ->
- do_configure(iiop_backlog, Value, Status);
-%% configure 'iiop_in_keepalive' will only have effect on new connections.
-configure(iiop_in_keepalive, true, Status) ->
- do_configure(iiop_in_keepalive, true, Status);
-configure(iiop_in_keepalive, false, Status) ->
- do_configure(iiop_in_keepalive, false, Status);
-%% configure 'iiop_out_keepalive' will only have effect on new connections.
-configure(iiop_out_keepalive, true, Status) ->
- do_configure(iiop_out_keepalive, true, Status);
-configure(iiop_out_keepalive, false, Status) ->
- do_configure(iiop_out_keepalive, false, Status);
-%% configure 'iiop_connection_timout' will only have effect on new connections.
-configure(iiop_connection_timeout, infinity, Status) ->
- do_configure(iiop_connection_timeout, infinity, Status);
-configure(iiop_connection_timeout, Value, Status) when is_integer(Value) andalso Value =< 1000000 ->
- do_configure(iiop_connection_timeout, Value, Status);
-%% configure 'iiop_in_connection_timout' will only have effect on new connections.
-configure(iiop_in_connection_timeout, infinity, Status) ->
- do_configure(iiop_in_connection_timeout, infinity, Status);
-configure(iiop_in_connection_timeout, Value, Status) when is_integer(Value) andalso Value =< 1000000 ->
- do_configure(iiop_in_connection_timeout, Value, Status);
-%% configure 'iiop_setup_connection_timeout' will only have effect on new connections.
-configure(iiop_setup_connection_timeout, infinity, Status) ->
- do_configure(iiop_setup_connection_timeout, infinity, Status);
-configure(iiop_setup_connection_timeout, Value, Status) when is_integer(Value) ->
- do_configure(iiop_setup_connection_timeout, Value, Status);
-%% configure 'iiop_max_fragments' will only have effect on new connections.
-configure(iiop_max_fragments, infinity, Status) ->
- do_configure(iiop_max_fragments, infinity, Status);
-configure(iiop_max_fragments, Value, Status) when is_integer(Value) andalso Value > 0 ->
- do_configure(iiop_max_fragments, Value, Status);
-%% configure 'iiop_max_in_requests' will only have effect on new connections.
-configure(iiop_max_in_requests, infinity, Status) ->
- do_configure(iiop_max_in_requests, infinity, Status);
-configure(iiop_max_in_requests, Value, Status) when is_integer(Value) andalso Value > 0 ->
- do_configure(iiop_max_in_requests, Value, Status);
-%% configure 'iiop_max_in_connections' will only have effect on new connections.
-configure(iiop_max_in_connections, infinity, Status) ->
- do_configure(iiop_max_in_connections, infinity, Status);
-configure(iiop_max_in_connections, Value, Status) when is_integer(Value) andalso Value > 0 ->
- do_configure(iiop_max_in_connections, Value, Status);
-%% Garbage Collect the object keys DB.
-configure(objectkeys_gc_time, infinity, Status) ->
- do_configure(objectkeys_gc_time, infinity, Status);
-configure(objectkeys_gc_time, Value, Status) when is_integer(Value) andalso Value =< 1000000 ->
- do_configure(objectkeys_gc_time, Value, Status);
-%% Orber debug printouts
-configure(orber_debug_level, Value, Status) when is_integer(Value) ->
- do_configure(orber_debug_level, Value, Status);
-
-%%------ Keys we cannot change if Orber is running -----
-%% Set the listen port
-configure(iiop_port, Value, Status) when is_integer(Value) ->
- do_safe_configure(iiop_port, Value, Status);
-%% Set the NAT listen port
-configure(nat_iiop_port, Value, Status) when is_integer(Value) andalso Value > 0 ->
- do_safe_configure(nat_iiop_port, Value, Status);
-configure(nat_iiop_port, {local, Value1, Value2}, Status) when is_integer(Value1) andalso
- Value1 > 0 andalso
- is_list(Value2) ->
- do_safe_configure(nat_iiop_port, {local, Value1, Value2}, Status);
-%% Set Maximum Packet Size
-configure(iiop_packet_size, Max, Status) when is_integer(Max) andalso Max > 0 ->
- do_safe_configure(iiop_packet_size, Max, Status);
-%% IIOP interceptors
-configure(interceptors, Value, Status) when is_tuple(Value) ->
- do_safe_configure(interceptors, Value, Status);
-%% Local interceptors
-configure(local_interceptors, Value, Status) when is_tuple(Value) ->
- do_safe_configure(local_interceptors, Value, Status);
-%% Orber Domain
-configure(domain, Value, Status) when is_list(Value) ->
- do_safe_configure(domain, Value, Status);
-%% Set the IP-address we should use
-configure(ip_address, Value, Status) when is_list(Value) ->
- do_safe_configure(ip_address, Value, Status);
-configure(ip_address, {multiple, Value}, Status) when is_list(Value) ->
- do_safe_configure(ip_address, {multiple, Value}, Status);
-configure(ip_address_local, Value, Status) when is_list(Value) ->
- do_safe_configure(ip_address_local, Value, Status);
-%% Set the NAT IP-address we should use
-configure(nat_ip_address, Value, Status) when is_list(Value) ->
- do_safe_configure(nat_ip_address, Value, Status);
-configure(nat_ip_address, {multiple, Value}, Status) when is_list(Value) ->
- do_safe_configure(nat_ip_address, {multiple, Value}, Status);
-configure(nat_ip_address, {local, Value1, Value2}, Status) when is_list(Value1) andalso
- is_list(Value2) ->
- do_safe_configure(nat_ip_address, {local, Value1, Value2}, Status);
-%% Set the range of ports we may use on this machine when connecting to a server.
-configure(iiop_out_ports, {Min, Max}, Status) when is_integer(Min) andalso is_integer(Max) ->
- do_safe_configure(iiop_out_ports, {Min, Max}, Status);
-configure(iiop_out_ports_attempts, Max, Status) when is_integer(Max) andalso Max > 0 ->
- do_safe_configure(iiop_out_ports_attempts, Max, Status);
-configure(iiop_out_ports_random, true, Status) ->
- do_safe_configure(iiop_out_ports_random, true, Status);
-configure(iiop_out_ports_random, false, Status) ->
- do_safe_configure(iiop_out_ports_random, false, Status);
-%% Set the lightweight option.
-configure(lightweight, Value, Status) when is_list(Value) ->
- do_safe_configure(lightweight, Value, Status);
-%% Configre the System Flags
-configure(flags, Value, Status) when is_integer(Value) ->
- do_safe_configure(flags, Value, Status);
-%% Configre the ACL
-configure(iiop_acl, Value, Status) when is_list(Value) ->
- do_safe_configure(iiop_acl, Value, Status);
-
-%% SSL settings
-%% configure 'iiop_in_keepalive' will only have effect on new connections.
-configure(iiop_ssl_in_keepalive, true, Status) ->
- do_configure(iiop_ssl_in_keepalive, true, Status);
-configure(iiop_ssl_in_keepalive, false, Status) ->
- do_configure(iiop_ssl_in_keepalive, false, Status);
-%% configure 'iiop_ssl_out_keepalive' will only have effect on new connections.
-configure(iiop_ssl_out_keepalive, true, Status) ->
- do_configure(iiop_ssl_out_keepalive, true, Status);
-configure(iiop_ssl_out_keepalive, false, Status) ->
- do_configure(iiop_ssl_out_keepalive, false, Status);
-configure(iiop_ssl_accept_timeout, infinity, Status) ->
- do_configure(iiop_ssl_accept_timeout, infinity, Status);
-configure(iiop_ssl_accept_timeout, Value, Status) when is_integer(Value) andalso Value >= 0 ->
- do_configure(iiop_ssl_accept_timeout, Value, Status);
-configure(ssl_generation, Generation, Status) when is_integer(Generation) andalso Generation >= 2 ->
- do_safe_configure(ssl_generation, Generation, Status);
-configure(secure, ssl, Status) ->
- do_safe_configure(secure, ssl, Status);
-configure(iiop_ssl_ip_address_local, Value, Status) when is_list(Value) ->
- do_safe_configure(iiop_ssl_ip_address_local, Value, Status);
-configure(iiop_ssl_backlog, Value, Status) when is_integer(Value) andalso Value >= 0 ->
- do_safe_configure(iiop_ssl_backlog, Value, Status);
-configure(nat_iiop_ssl_port, Value, Status) when is_integer(Value) andalso Value > 0 ->
- do_safe_configure(nat_iiop_ssl_port, Value, Status);
-configure(nat_iiop_ssl_port, {local, Value1, Value2}, Status) when is_integer(Value1) andalso
- Value1 > 0 andalso
- is_list(Value2) ->
- do_safe_configure(nat_iiop_ssl_port, {local, Value1, Value2}, Status);
-configure(iiop_ssl_port, Value, Status) when is_integer(Value) ->
- do_safe_configure(iiop_ssl_port, Value, Status);
-
-%% New SSL options
-configure(ssl_server_options, Value, Status) when is_list(Value) ->
- do_safe_configure(ssl_server_options, Value, Status);
-configure(ssl_client_options, Value, Status) when is_list(Value) ->
- do_safe_configure(ssl_client_options, Value, Status);
-
-%% Old SSL options
-configure(ssl_server_certfile, Value, Status) when is_list(Value) ->
- do_safe_configure(ssl_server_certfile, Value, Status);
-configure(ssl_server_certfile, Value, Status) when is_atom(Value) ->
- do_safe_configure(ssl_server_certfile, atom_to_list(Value), Status);
-configure(ssl_client_certfile, Value, Status) when is_list(Value) ->
- do_safe_configure(ssl_client_certfile, Value, Status);
-configure(ssl_client_certfile, Value, Status) when is_atom(Value) ->
- do_safe_configure(ssl_client_certfile, atom_to_list(Value), Status);
-configure(ssl_server_verify, Value, Status) when is_integer(Value) ->
- do_safe_configure(ssl_server_verify, Value, Status);
-configure(ssl_client_verify, Value, Status) when is_integer(Value) ->
- do_safe_configure(ssl_client_verify, Value, Status);
-configure(ssl_server_depth, Value, Status) when is_integer(Value) ->
- do_safe_configure(ssl_server_depth, Value, Status);
-configure(ssl_client_depth, Value, Status) when is_integer(Value) ->
- do_safe_configure(ssl_client_depth, Value, Status);
-configure(ssl_server_cacertfile, Value, Status) when is_list(Value) ->
- do_safe_configure(ssl_server_cacertfile, Value, Status);
-configure(ssl_server_cacertfile, Value, Status) when is_atom(Value) ->
- do_safe_configure(ssl_server_cacertfile, atom_to_list(Value), Status);
-configure(ssl_client_cacertfile, Value, Status) when is_list(Value) ->
- do_safe_configure(ssl_client_cacertfile, Value, Status);
-configure(ssl_client_cacertfile, Value, Status) when is_atom(Value) ->
- do_safe_configure(ssl_client_cacertfile, atom_to_list(Value), Status);
-configure(ssl_client_password, Value, Status) when is_list(Value) ->
- do_safe_configure(ssl_client_password, Value, Status);
-configure(ssl_client_password, Value, Status) when is_atom(Value) ->
- do_safe_configure(ssl_client_password, atom_to_list(Value), Status);
-configure(ssl_client_keyfile, Value, Status) when is_list(Value) ->
- do_safe_configure(ssl_client_keyfile, Value, Status);
-configure(ssl_client_keyfile, Value, Status) when is_atom(Value) ->
- do_safe_configure(ssl_client_keyfile, atom_to_list(Value), Status);
-configure(ssl_server_password, Value, Status) when is_list(Value) ->
- do_safe_configure(ssl_server_password, Value, Status);
-configure(ssl_client_password, Value, Status) when is_atom(Value) ->
- do_safe_configure(ssl_server_password, atom_to_list(Value), Status);
-configure(ssl_server_keyfile, Value, Status) when is_list(Value) ->
- do_safe_configure(ssl_server_keyfile, Value, Status);
-configure(ssl_server_keyfile, Value, Status) when is_atom(Value) ->
- do_safe_configure(ssl_server_keyfile, atom_to_list(Value), Status);
-configure(ssl_server_ciphers, Value, Status) when is_list(Value) ->
- do_safe_configure(ssl_server_ciphers, Value, Status);
-configure(ssl_server_ciphers, Value, Status) when is_atom(Value) ->
- do_safe_configure(ssl_server_ciphers, atom_to_list(Value), Status);
-configure(ssl_client_ciphers, Value, Status) when is_list(Value) ->
- do_safe_configure(ssl_client_ciphers, Value, Status);
-configure(ssl_client_ciphers, Value, Status) when is_atom(Value) ->
- do_safe_configure(ssl_client_ciphers, atom_to_list(Value), Status);
-configure(ssl_client_cachetimeout, Value, Status) when is_integer(Value) andalso Value > 0 ->
- do_safe_configure(ssl_client_cachetimeout, Value, Status);
-configure(ssl_server_cachetimeout, Value, Status) when is_integer(Value) andalso Value > 0 ->
- do_safe_configure(ssl_server_cachetimeout, Value, Status);
-
-configure(Key, Value, _) ->
- ?EFORMAT("Bad configuration parameter: {~p, ~p}", [Key, Value]).
-
-%% This function may be used as long as it is safe to change a value at any time.
-do_configure(Key, Value, check) ->
- case orber_tb:is_loaded() of
- false ->
- application:load(orber),
- application:set_env(orber, Key, Value);
- true ->
- application:set_env(orber, Key, Value)
- end;
-do_configure(Key, Value, _) ->
- application:set_env(orber, Key, Value).
-
-%% This function MUST(!!) be used when we cannot change a value if Orber is running.
-do_safe_configure(_, _, running) ->
- exit("Orber already running, the given key may not be updated!");
-do_safe_configure(Key, Value, check) ->
- case orber_tb:is_loaded() of
- false ->
- application:load(orber),
- application:set_env(orber, Key, Value);
- true ->
- case orber_tb:is_running() of
- false ->
- application:set_env(orber, Key, Value);
- true ->
- ?EFORMAT("Orber already running. {~p, ~p} may not be updated!",
- [Key, Value])
- end
- end;
-do_safe_configure(Key, Value, loaded) ->
- application:set_env(orber, Key, Value).
-
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Server functions
-%%-----------------------------------------------------------------
-init(_Opts) ->
- {ok, #env{acl = orber_acl:init_acl(iiop_acl()),
- parameters = init_env()}}.
-
-terminate(_Reason, _State) ->
- ok.
-
-handle_call(_, _From, State) ->
- {reply, ok, State}.
-
-handle_cast(_, State) ->
- {noreply, State}.
-
-handle_info(_, State) ->
- {noreply, State}.
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%-----------------------------------------------------------------
-%% function : env
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect : Used when Key always exists (Default Value)
-%%-----------------------------------------------------------------
-env(Key) ->
- [#parameters{value = Val}] = ets:lookup(?ENV_DB, Key),
- Val.
-
-%%-----------------------------------------------------------------
-%% function : init_env
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%-----------------------------------------------------------------
-init_env() ->
- application:load(orber),
- DB = ets:new(?ENV_DB, [set, public, named_table, {keypos, 2}]),
-% init_env(?ENV_KEYS),
- DB.
-
-%init_env([{H,D}|T]) ->
-% case application:get_env(orber, H) of
-% {ok, V} ->
-% ets:insert(?ENV_DB, #parameters{key = H, value = V, flags = 0}),
-% init_env(T);
-% _ ->
-% ets:insert(?ENV_DB, #parameters{key = H, value = D, flags = 0}),
-% init_env(T)
-% end;
-%init_env([H|T]) ->
-% case application:get_env(orber, H) of
-% {ok, V} ->
-% ets:insert(?ENV_DB, #parameters{key = H, value = V, flags = 0}),
-% init_env(T);
-% _ ->
-% ets:insert(?ENV_DB, #parameters{key = H, value = undefined, flags = 0}),
-% init_env(T)
-% end;
-%init_env([]) ->
-% ok.
-
-%%-----------------------------------------------------------------
-%%------------- END OF MODULE -------------------------------------
-%%-----------------------------------------------------------------
diff --git a/lib/orber/src/orber_exceptions.erl b/lib/orber/src/orber_exceptions.erl
deleted file mode 100644
index 2519775eb3..0000000000
--- a/lib/orber/src/orber_exceptions.erl
+++ /dev/null
@@ -1,718 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: orber_exceptions.erl
-%%
-%% Description:
-%%
-%%-----------------------------------------------------------------
-
--module(orber_exceptions).
-
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
--include_lib("orber/src/ifr_objects.hrl").
--include_lib("orber/include/ifr_types.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([dissect/1,
- get_def/1,
- get_name/2,
- type/1,
- is_system_exception/1]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export(['UNKNOWN'/1,
- 'BAD_PARAM'/1,
- 'NO_MEMORY'/1,
- 'IMP_LIMIT'/1,
- 'COMM_FAILURE'/1,
- 'INV_OBJREF'/1,
- 'NO_PERMISSION'/1,
- 'INTERNAL'/1,
- 'MARSHAL'/1,
- 'INITIALIZE'/1,
- 'NO_IMPLEMENT'/1,
- 'BAD_TYPECODE'/1,
- 'BAD_OPERATION'/1,
- 'NO_RESOURCES'/1,
- 'NO_RESPONSE'/1,
- 'PERSIST_STORE'/1,
- 'BAD_INV_ORDER'/1,
- 'TRANSIENT'/1,
- 'FREE_MEM'/1,
- 'INV_IDENT'/1,
- 'INV_FLAG'/1,
- 'INTF_REPOS'/1,
- 'BAD_CONTEXT'/1,
- 'OBJ_ADAPTER'/1,
- 'DATA_CONVERSION'/1,
- 'OBJECT_NOT_EXIST'/1,
- 'TRANSACTION_REQUIRED'/1,
- 'TRANSACTION_ROLLEDBACK'/1,
- 'INVALID_TRANSACTION'/1,
- 'INV_POLICY'/1,
- 'CODESET_INCOMPATIBLE'/1,
- 'REBIND'/1,
- 'TIMEOUT'/1,
- 'TRANSACTION_UNAVAILABLE'/1,
- 'TRANSACTION_MODE'/1,
- 'BAD_QOS'/1]).
-
-
--define(DEBUG_LEVEL, 5).
-
-%%-----------------------------------------------------------------
-%% Function : is_system_exception
-%% Arguments : Exception - record()
-%% Returns : true | false
-%% Raises :
-%% Description: Check if CORBA system exception or user defined
-%%-----------------------------------------------------------------
-is_system_exception({'EXCEPTION', E}) ->
- is_system_exception(E);
-is_system_exception(E) when is_tuple(E) ->
- ?SYSTEM_EXCEPTION == type(element(1, E));
-is_system_exception(_E) ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%-----------------------------------------------------------------
-%% Function : type
-%% Arguments : ExceptionName - atom()
-%% Returns : ?SYSTEM_EXCEPTION | ?USER_EXCEPTION
-%% Raises :
-%% Description: Check if CORBA system exception or user defined
-%%-----------------------------------------------------------------
-type('UNKNOWN') -> ?SYSTEM_EXCEPTION;
-type('BAD_PARAM') -> ?SYSTEM_EXCEPTION;
-type('NO_MEMORY') -> ?SYSTEM_EXCEPTION;
-type('IMP_LIMIT') -> ?SYSTEM_EXCEPTION;
-type('COMM_FAILURE') -> ?SYSTEM_EXCEPTION;
-type('INV_OBJREF') -> ?SYSTEM_EXCEPTION;
-type('NO_PERMISSION') -> ?SYSTEM_EXCEPTION;
-type('INTERNAL') -> ?SYSTEM_EXCEPTION;
-type('MARSHAL') -> ?SYSTEM_EXCEPTION;
-type('INITIALIZE') -> ?SYSTEM_EXCEPTION;
-type('NO_IMPLEMENT') -> ?SYSTEM_EXCEPTION;
-type('BAD_TYPECODE') -> ?SYSTEM_EXCEPTION;
-type('BAD_OPERATION') -> ?SYSTEM_EXCEPTION;
-type('NO_RESOURCES') -> ?SYSTEM_EXCEPTION;
-type('NO_RESPONSE') -> ?SYSTEM_EXCEPTION;
-type('PERSIST_STORE') -> ?SYSTEM_EXCEPTION;
-type('BAD_INV_ORDER') -> ?SYSTEM_EXCEPTION;
-type('TRANSIENT') -> ?SYSTEM_EXCEPTION;
-type('FREE_MEM') -> ?SYSTEM_EXCEPTION;
-type('INV_IDENT') -> ?SYSTEM_EXCEPTION;
-type('INV_FLAG') -> ?SYSTEM_EXCEPTION;
-type('INTF_REPOS') -> ?SYSTEM_EXCEPTION;
-type('BAD_CONTEXT') -> ?SYSTEM_EXCEPTION;
-type('OBJ_ADAPTER') -> ?SYSTEM_EXCEPTION;
-type('DATA_CONVERSION') -> ?SYSTEM_EXCEPTION;
-type('OBJECT_NOT_EXIST') -> ?SYSTEM_EXCEPTION;
-type('TRANSACTION_REQUIRED') -> ?SYSTEM_EXCEPTION;
-type('TRANSACTION_ROLLEDBACK') -> ?SYSTEM_EXCEPTION;
-type('INVALID_TRANSACTION') -> ?SYSTEM_EXCEPTION;
-type('INV_POLICY') -> ?SYSTEM_EXCEPTION;
-type('CODESET_INCOMPATIBLE') -> ?SYSTEM_EXCEPTION;
-type('REBIND') -> ?SYSTEM_EXCEPTION;
-type('TIMEOUT') -> ?SYSTEM_EXCEPTION;
-type('TRANSACTION_UNAVAILABLE') -> ?SYSTEM_EXCEPTION;
-type('TRANSACTION_MODE') -> ?SYSTEM_EXCEPTION;
-type('BAD_QOS') -> ?SYSTEM_EXCEPTION;
-type(_) -> ?USER_EXCEPTION.
-
-%%-----------------------------------------------------------------
-%% Function : get_def
-%% Arguments : Exception - record()
-%% Returns : {Type, TypeCode, Exc}
-%% Raises :
-%% Description: Returns the TC for the supplied exception
-%%-----------------------------------------------------------------
-get_def(Exception) ->
- [Exc, TypeId | _] = tuple_to_list(Exception),
- case type(Exc) of
- ?SYSTEM_EXCEPTION ->
- {?SYSTEM_EXCEPTION, get_system_exception_def(Exc), Exception};
- ?USER_EXCEPTION ->
- case orber:light_ifr() of
- true ->
- case catch orber_ifr:get_tc(TypeId, ?IFR_ExceptionDef) of
- {'EXCEPTION', NewExc} ->
- {?SYSTEM_EXCEPTION,
- get_system_exception_def(NewExc),
- NewExc};
- TC ->
- {?USER_EXCEPTION, TC, Exception}
- end;
- false ->
- case mnesia:dirty_index_read(ir_ExceptionDef, TypeId,
- #ir_ExceptionDef.id) of
- [ExcDef] when is_record(ExcDef, ir_ExceptionDef) ->
- {?USER_EXCEPTION,
- ExcDef#ir_ExceptionDef.type,
- Exception};
- Other ->
- orber:dbg("[~p] ~p:get_user_exception_type(~p).~n"
- "IFR Id not found: ~p",
- [?LINE, ?MODULE, TypeId, Other], ?DEBUG_LEVEL),
- NewExc = #'UNKNOWN'{minor=(?CORBA_OMGVMCID bor 1),
- completion_status=?COMPLETED_MAYBE},
- {?SYSTEM_EXCEPTION,
- get_system_exception_def(NewExc),
- NewExc}
- end
- end
- end.
-
-%%-----------------------------------------------------------------
-%% Function : get_name
-%% Arguments : TypeId - string()
-%% Type - ?SYSTEM_EXCEPTION ( | ?USER_EXCEPTION)
-%% Returns : ExceptionName - atom()
-%% Raises : #'UNKNOWN'{}
-%% Description: Extract exception name
-%%-----------------------------------------------------------------
-get_name(TypeId, ?SYSTEM_EXCEPTION) ->
- ExcName =
- case string:tokens(TypeId, ":/") of
- [_IDL, _OMGORG, _CORBA, Name, _Version] when is_list(Name) ->
- list_to_atom(Name);
- [_IDL, _CORBA, Name, _Version] when is_list(Name) ->
- %% We should remove this case but we keep it for now due to backward
- %% compatible reasons.
- list_to_atom(Name);
- Other ->
- %% The CORBA-spec states that this exception should be raised if
- %% it's a system exception we do not support.
- orber:dbg("[~p] ~p:get_system_exception_name(~p).~n"
- "Unknown System Exception: ~p",
- [?LINE, ?MODULE, TypeId, Other], ?DEBUG_LEVEL),
- corba:raise(#'UNKNOWN'{minor=(?CORBA_OMGVMCID bor 2),
- completion_status=?COMPLETED_MAYBE})
- end,
- case type(ExcName) of
- ?SYSTEM_EXCEPTION ->
- ExcName;
- What ->
- orber:dbg("[~p] ~p:get_system_exception_name(~p).~n"
- "Unknown System Exception: ~p",
- [?LINE, ?MODULE, TypeId, What], ?DEBUG_LEVEL),
- corba:raise(#'UNKNOWN'{minor=(?CORBA_OMGVMCID bor 2),
- completion_status=?COMPLETED_MAYBE})
- end.
-
-
-%%-----------------------------------------------------------------
-%% Generate system exception TypeCode
-%%-----------------------------------------------------------------
-get_system_exception_def(ExcName) when is_atom(ExcName) ->
- Name = atom_to_list(ExcName),
- {'tk_except', "IDL:omg.org/CORBA/" ++ Name ++ ":1.0", Name,
- [{"minor",'tk_ulong'},
- {"completed",
- {'tk_enum', "", "completion_status",
- ["COMPLETED_YES", "COMPLETED_NO",
- "COMPLETED_MAYBE"]}}]};
-get_system_exception_def(Exc) ->
- get_system_exception_def(element(1, Exc)).
-
-
-%%-----------------------------------------------------------------
-%% Mapping minor codes to a printable string.
-%%-----------------------------------------------------------------
-dissect({'EXCEPTION', Exc}) ->
- dissect(Exc);
-dissect(Exception) when is_tuple(Exception) ->
- [Exc, TypeId | _] = tuple_to_list(Exception),
- case type(Exc) of
- ?USER_EXCEPTION ->
- {ok, lists:flatten(io_lib:format("~n------------- EXCEPTION INFO --------------
-User Defined Exception.: ~p
-IFR Id.................: ~s
--------------------------------------------~n", [Exc, TypeId]))};
- ?SYSTEM_EXCEPTION ->
- case map_exc(Exception) of
- {ok, String} ->
- {ok, lists:flatten(String)};
- {error, Reason} ->
- {error, Reason}
- end
- end;
-dissect(_What) ->
- {error, "Not a correct exception supplied to orber_exceptions:dissect/1"}.
-
-map_exc({Name, _, Minor, Status}) when is_integer(Minor) ->
- case lookup_vendor(Minor) of
- {true, Vendor, VMCID} ->
- case catch ?MODULE:Name(Minor) of
- MinorInfo when is_list(MinorInfo) ->
- {ok, io_lib:format("~n------------- EXCEPTION INFO --------------
-Vendor.....: ~s
-VMCID......: ~s
-Exception..: ~p
-Status.....: ~p
-Minor Code.: ~p
-Info.......: ~s
--------------------------------------------~n",
- [Vendor, VMCID, Name, Status, (Minor band 16#fff), MinorInfo])};
- _ ->
- {ok, io_lib:format("~n------------- EXCEPTION INFO --------------
-Vendor.....: ~s
-VMCID......: ~s
-Exception..: ~p
-Status.....: ~p
-Minor Code.: ~p
-Info.......: -
-------------------------------------~n", [Vendor, VMCID, Name, Status, (Minor band 16#fff)])}
- end;
- {false, Vendor, VMCID} ->
- {ok, io_lib:format("~n------------- EXCEPTION INFO --------------
-Vendor.....: ~s
-VMCID......: ~s
-Exception..: ~p
-Status.....: ~p
-Minor Code.: ~p
-Info.......: -
--------------------------------------------~n", [Vendor, VMCID, Name, Status, (Minor band 16#fff)])}
- end;
-map_exc(_) ->
- {error, "Not a correct exception supplied to orber_exceptions:map_exc/1"}.
-
-lookup_vendor(Minor) when (?ORBER_VMCID bxor Minor) < 16#0fff ->
- {true, "Orber", "0x45520000"};
-lookup_vendor(Minor) when (?CORBA_OMGVMCID bxor Minor) < 16#0fff ->
- {true, "OMG", "0x4f4d0000"};
-lookup_vendor(Minor) when (?IONA_VMCID_1 bxor Minor) < 16#0fff ->
- {false, "IONA", "0x4f4f0000"};
-lookup_vendor(Minor) when (?IONA_VMCID_2 bxor Minor) < 16#0fff ->
- {false, "IONA", "0x49540000"};
-lookup_vendor(Minor) when (?SUN_VMCID bxor Minor) < 16#0fff ->
- {false, "SUN", "0x53550000"};
-lookup_vendor(Minor) when (?BORLAND_VMCID bxor Minor) < 16#0fff ->
- {false, "Borland", "0x56420000"};
-lookup_vendor(Minor) when (?TAO_VMCID bxor Minor) < 16#0fff ->
- {false, "TAO", "0x54410000"};
-lookup_vendor(Minor) when (?PRISMTECH_VMCID bxor Minor) < 16#0fff ->
- {false, "PrismTech", "0x50540000"};
-lookup_vendor(Minor) when is_integer(Minor), Minor =< ?ULONGMAX ->
- {false, "undefined", extract_VMCID(Minor)};
-lookup_vendor(Minor) when is_integer(Minor), Minor =< ?ULONGMAX ->
- {false, "Unknown", "Unable to extract it"}.
-
-extract_VMCID(Int) ->
- int_to_hex_str(3, ((Int bsr 8) band 16#fffff0), ["00"]).
-
-int_to_hex_str(0, _, Acc) ->
- lists:flatten(["0x" | Acc]);
-int_to_hex_str(N, Int, Acc) ->
- int_to_hex_str(N-1, (Int bsr 8), [int_to_hex((16#ff band Int))|Acc]).
-
-int_to_hex(B) when B < 256, B >= 0 ->
- N1 = B div 16,
- N2 = B rem 16,
- [code_character(N1),
- code_character(N2)].
-code_character(N) when N < 10 ->
- $0 + N;
-code_character(N) ->
- $a + (N - 10).
-
-
-%% The following functions all maps to a system exception.
-%% UNKNOWN - OMG
-'UNKNOWN'(?CORBA_OMGVMCID bor 1) -> "Unlisted user exception received
-by client";
-'UNKNOWN'(?CORBA_OMGVMCID bor 2) -> "Non-standard System Exception
-not supported";
-%% UNKNOWN - Orber
-'UNKNOWN'(?ORBER_VMCID bor 1) -> "Missing beam-file. Unable to extract TC.";
-'UNKNOWN'(_) -> "-".
-
-
-%% BAD_PARAM - OMG
-'BAD_PARAM'(?CORBA_OMGVMCID bor 1) -> "Failure to register, unregister, or
-lookup value factory";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 2) -> "RID already defined in IFR";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 3) -> "Name already used in the context in IFR";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 4) -> "Target is not a valid container";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 5) -> "Name clash in inherited context";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 6) -> "Incorrect type for abstract interface";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 7) -> "string_to_object conversion failed
-due to bad scheme name";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 8) -> "string_to_object conversion failed
-due to bad address";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 9) -> "string_to_object conversion failed
-due to bad bad schema specific part";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 10) -> "string_to_object conversion failed
-due to non specific reason";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 11) -> "Attempt to derive abstract interface
-from non-abstract base interface
-in the Interface Repository";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 12) -> "Attempt to let a ValueDef support
-more than one non-abstract interface
-in the Interface Repository";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 13) -> "Attempt to use an incomplete
-TypeCode as a parameter";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 14) -> "Invalid object id passed to
-POA::create_reference_by_id";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 15) -> "Bad name argument in TypeCode operation";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 16) -> "Bad RepositoryId argument in TypeCode
-operation";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 17) -> "Invalid member name in TypeCode operation";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 18) -> "Duplicate label value in create_union_tc";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 19) -> "Incompatible TypeCode of label and
-discriminator in create_union_tc";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 20) -> "Supplied discriminator type illegitimate
-in create_union_tc";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 21) -> "Any passed to ServerRequest::set_exception
-does not contain an exception";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 22) -> "Unlisted user exception passed to
-ServerRequest::set_exception";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 23) -> "wchar transmission code set not
-in service context";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 24) -> "Service context is not in OMG-defined range";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 25) -> "Enum value out of range";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 26) -> "Invalid service context Id in portable
-interceptor";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 27) -> "Attempt to call register_initial_reference
-with a null Object";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 28) -> "Invalid component Id in
-portable interceptor";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 29) -> "Invalid profile Id in portable
-interceptor";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 30) -> "Two or more Policy objects with the
-same PolicyType value supplied to
-Object::set_policy_overrides or
-PolicyManager::set_policy_overrides";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 31) -> "Attempt to define a oneway
-operation with non-void result,
-out or inout parameters or user
-exceptions";
-'BAD_PARAM'(?CORBA_OMGVMCID bor 32) -> "DII asked to create request
-for an implicit operation";
-%% BAD_PARAM - Orber
-'BAD_PARAM'(?ORBER_VMCID bor 1) -> "Bad return value from the objects
-init-function (create phase) or invalid
-options suuplied";
-'BAD_PARAM'(_) -> "-".
-
-%% NO_MEMORY - OMG
-'NO_MEMORY'(_) -> "-".
-
-%% IMP_LIMIT - OMG
-'IMP_LIMIT'(?CORBA_OMGVMCID bor 1) -> "Unable to use any profile in IOR";
-%% IMP_LIMIT - Orber
-'IMP_LIMIT'(?ORBER_VMCID bor 1) -> "All ports assigned to the configuration
-parameter 'iiop_out_ports' are in use";
-'IMP_LIMIT'(_) -> "-".
-
-%% COMM_FAILURE - OMG
-%% COMM_FAILURE - Orber
-'COMM_FAILURE'(?ORBER_VMCID bor 1) -> "Unable to connect to another ORB -
-probably inactive";
-'COMM_FAILURE'(?ORBER_VMCID bor 2) -> "Unable to connect to another ORB -
-interceptor(s) rejected it or behaves
-badly";
-'COMM_FAILURE'(?ORBER_VMCID bor 3) -> "Request terminated by another process";
-'COMM_FAILURE'(?ORBER_VMCID bor 4) -> "Unable to connect to another ORB - timed out";
-'COMM_FAILURE'(_) -> "-".
-
-%% INV_OBJREF - OMG
-'INV_OBJREF'(?CORBA_OMGVMCID bor 1) -> "wchar Code Set support not specified";
-'INV_OBJREF'(?CORBA_OMGVMCID bor 2) -> "Codeset component required for type using wchar or wstring data";
-'INV_OBJREF'(_) -> "-".
-
-%% NO_PERMISSION - OMG
-'NO_PERMISSION'(_) -> "-".
-
-%% INTERNAL - OMG
-%% INTERNAL - Orber
-'INTERNAL'(?ORBER_VMCID bor 1) -> "Unable to connect to an Orber installation";
-'INTERNAL'(?ORBER_VMCID bor 2) -> "Failed to register internal objectkey in the database";
-'INTERNAL'(_) -> "-".
-
-%% MARSHAL - OMG
-'MARSHAL'(?CORBA_OMGVMCID bor 1) -> "Unable to locate value factory";
-'MARSHAL'(?CORBA_OMGVMCID bor 2) -> "ServerRequest::set_result called
-before ServerRequest::ctx when the
-operation IDL contains a context
-clause";
-'MARSHAL'(?CORBA_OMGVMCID bor 3) -> "NVList passed to
-ServerRequest::arguments does not
-describe all parameters passed
-by client";
-'MARSHAL'(?CORBA_OMGVMCID bor 4) -> "Attempt to marshal Local object";
-'MARSHAL'(?CORBA_OMGVMCID bor 5) -> "wchar or wstring data erroneosly
-sent by client over GIOP 1.0
-connection";
-'MARSHAL'(?CORBA_OMGVMCID bor 6) -> "wchar or wstring data erroneously
-returned by server over GIOP 1.0
-connection";
-%% MARSHAL - Orber
-'MARSHAL'(?ORBER_VMCID bor 1) -> "Integer overflow";
-'MARSHAL'(?ORBER_VMCID bor 2) -> "Passed a non-integer,
-when it must be an integer";
-'MARSHAL'(?ORBER_VMCID bor 3) -> "Incorrect boolean";
-'MARSHAL'(?ORBER_VMCID bor 4) -> "Passed a non-number,
-when it must be a float, double
-or long double";
-'MARSHAL'(?ORBER_VMCID bor 5) -> "Bad enumerant - does not exist";
-'MARSHAL'(?ORBER_VMCID bor 6) -> "Passed something else but character
-or octet";
-'MARSHAL'(?ORBER_VMCID bor 7) -> "Unable to marshal the supplied
-typecode";
-'MARSHAL'(?ORBER_VMCID bor 8) -> "Unable to un-marshal the supplied
-typecode";
-'MARSHAL'(?ORBER_VMCID bor 9) -> "Union IFR-id does not exist";
-'MARSHAL'(?ORBER_VMCID bor 10) -> "Struct IFR-id does not exist";
-'MARSHAL'(?ORBER_VMCID bor 11) -> "Empty string supplied as IFR-id";
-'MARSHAL'(?ORBER_VMCID bor 12) -> "Unable to decode target address";
-'MARSHAL'(?ORBER_VMCID bor 13) -> "Incorrect TypeCode or unsupported
-data type";
-'MARSHAL'(?ORBER_VMCID bor 14) -> "The Fixed type does not match the
-defined digits/scale parameters";
-'MARSHAL'(?ORBER_VMCID bor 15) -> "The supplied array is to long or to short";
-'MARSHAL'(?ORBER_VMCID bor 16) -> "String/Wstring exceeds maximum length";
-'MARSHAL'(?ORBER_VMCID bor 17) -> "To few or to many parameters supplied";
-'MARSHAL'(?ORBER_VMCID bor 18) -> "Unable to decode message header";
-'MARSHAL'(?ORBER_VMCID bor 19) -> "Sequnce exceeds maximum length";
-'MARSHAL'(_) -> "-".
-
-%% INITIALIZE - OMG
-'INITIALIZE'(_) -> "-".
-
-%% NO_IMPLEMENT - OMG
-'NO_IMPLEMENT'(?CORBA_OMGVMCID bor 1) -> "Missing local value implementation";
-'NO_IMPLEMENT'(?CORBA_OMGVMCID bor 2) -> "Incompatible value implementation version";
-'NO_IMPLEMENT'(?CORBA_OMGVMCID bor 3) -> "Unable to use any profile in IOR";
-'NO_IMPLEMENT'(?CORBA_OMGVMCID bor 4) -> "Attempt to use DII on Local object";
-'NO_IMPLEMENT'(_) -> "-".
-
-
-%% BAD_TYPECODE - OMG
-'BAD_TYPECODE'(?CORBA_OMGVMCID bor 1) -> "Attempt to marshal incomplete
-TypeCode";
-'BAD_TYPECODE'(?CORBA_OMGVMCID bor 2) -> "Member type code illegitimate
-in TypeCode operation";
-'BAD_TYPECODE'(_) -> "-".
-
-%% BAD_OPERATION - OMG
-'BAD_OPERATION'(?CORBA_OMGVMCID bor 1) -> "ServantManager returned wrong
-servant type";
-%% BAD_OPERATION - Orber
-'BAD_OPERATION'(?ORBER_VMCID bor 1) -> "Incorrect instance type for this
-operation";
-'BAD_OPERATION'(?ORBER_VMCID bor 2) -> "Incorrect instance type for this
-operation (one-way)";
-'BAD_OPERATION'(?ORBER_VMCID bor 3) -> "The IC option 'handle_info' was
-not used when compiling the stub";
-'BAD_OPERATION'(?ORBER_VMCID bor 4) -> "Incorrect instance type for the
-invoked operation (two- or one-way)";
-'BAD_OPERATION'(_) -> "-".
-
-%% NO_RESOURCES - OMG
-'NO_RESOURCES'(?CORBA_OMGVMCID bor 1) -> "Portable Interceptor operation
-not supported in this binding";
-'NO_RESOURCES'(_) -> "-".
-
-%% NO_RESPONSE - OMG
-'NO_RESPONSE'(_) -> "-".
-
-%% PERSIST_STORE - OMG
-'PERSIST_STORE'(_) -> "-".
-
-%% BAD_INV_ORDER - OMG
-'BAD_INV_ORDER'(?CORBA_OMGVMCID bor 1) -> "Dependency exists in IFR preventing
-destruction of this object";
-'BAD_INV_ORDER'(?CORBA_OMGVMCID bor 2) -> "Attempt to destroy indestructible
-objects in IFR";
-'BAD_INV_ORDER'(?CORBA_OMGVMCID bor 3) -> "Operation would deadlock";
-'BAD_INV_ORDER'(?CORBA_OMGVMCID bor 4) -> "ORB has shutdown";
-'BAD_INV_ORDER'(?CORBA_OMGVMCID bor 5) -> "Attempt to invoke send or invoke
-operation of the same Request object
-more than once";
-'BAD_INV_ORDER'(?CORBA_OMGVMCID bor 6) -> "Attempt to set a servant manager
-after one has already been set";
-'BAD_INV_ORDER'(?CORBA_OMGVMCID bor 7) -> "ServerRequest::arguments called more
-than once or after a call to
-ServerRequest:: set_exception";
-'BAD_INV_ORDER'(?CORBA_OMGVMCID bor 8) -> "ServerRequest::ctx called more than
-once or before ServerRequest::arguments or
-after ServerRequest::ctx, ServerRequest::set_result
-or ServerRequest::set_exception";
-'BAD_INV_ORDER'(?CORBA_OMGVMCID bor 9) -> "ServerRequest::set_result called more
-than once or before ServerRequest::arguments
-or after ServerRequest::set_result or
-ServerRequest::set_exception";
-'BAD_INV_ORDER'(?CORBA_OMGVMCID bor 10) -> "Attempt to send a DII request after
-it was sent previously";
-'BAD_INV_ORDER'(?CORBA_OMGVMCID bor 11) -> "Attempt to poll a DII request or to
-retrieve its result before the request
-was sent";
-'BAD_INV_ORDER'(?CORBA_OMGVMCID bor 12) -> "Attempt to poll a DII request or to
-retrieve its result after the result
-was retrieved previously";
-'BAD_INV_ORDER'(?CORBA_OMGVMCID bor 13) -> "Attempt to poll a synchronous DII
-request or to retrieve results from
-a synchronous DII request";
-'BAD_INV_ORDER'(?CORBA_OMGVMCID bor 14) -> "Invalid portable interceptor call";
-'BAD_INV_ORDER'(?CORBA_OMGVMCID bor 15) -> "Service context add failed in portable
-interceptor because a service context
-with the given id already exists";
-'BAD_INV_ORDER'(?CORBA_OMGVMCID bor 16) -> "Registration of PolicyFactory failed
-because a factory already exists for
-the given PolicyType";
-'BAD_INV_ORDER'(?CORBA_OMGVMCID bor 17) -> "POA cannot create POAs while undergoing
-destruction";
-'BAD_INV_ORDER'(_) -> "-".
-
-%% TRANSIENT - OMG
-'TRANSIENT'(?CORBA_OMGVMCID bor 1) -> "Request discarded because of resource
-exhaustion in POA, or because POA
-is in discarding state";
-'TRANSIENT'(?CORBA_OMGVMCID bor 2) -> "No usable profile in IOR";
-'TRANSIENT'(?CORBA_OMGVMCID bor 3) -> "Request cancelled";
-'TRANSIENT'(?CORBA_OMGVMCID bor 4) -> "POA destroyed";
-%% TRANSIENT - Orber
-'TRANSIENT'(?ORBER_VMCID bor 1) -> "Orber is being restarted, or should be,
-on one node in the multi-node Orber
-installation";
-'TRANSIENT'(?ORBER_VMCID bor 2) -> "The node the target object resides on
-is down (multi-node Orber installation)";
-'TRANSIENT'(?ORBER_VMCID bor 3) -> "Received EXIT when invoking an operation
-on an object residing on another
-node in a multi-node Orber installation";
-'TRANSIENT'(?ORBER_VMCID bor 4) -> "Received EXIT when invoking an operation
-on a local object";
-'TRANSIENT'(?ORBER_VMCID bor 5) -> "Received unknown reply when invoking an
-operation on an object residing on
-another node in a multi-node Orber
-installation";
-'TRANSIENT'(?ORBER_VMCID bor 6) -> "Received unknown reply when invoking an
-operation on a local object";
-'TRANSIENT'(?ORBER_VMCID bor 7) -> "Either the stub/skeleton does not exist or an
-incorrect IC-version was used, which does not generate
-the oe_tc/1 or oe_get_interface/1 functions";
-'TRANSIENT'(_) -> "-".
-
-%% FREE_MEM - OMG
-'FREE_MEM'(_) -> "-".
-
-%% INV_IDENT - OMG
-'INV_IDENT'(_) -> "-".
-
-%% INV_FLAG - OMG
-'INV_FLAG'(_) -> "-".
-
-%% INTF_REPOS - OMG
-'INTF_REPOS'(?CORBA_OMGVMCID bor 1) -> "Interface Repository not available";
-'INTF_REPOS'(?CORBA_OMGVMCID bor 2) -> "No entry for requested interface in
-Interface Repository";
-'INTF_REPOS'(_) -> "-".
-
-%% BAD_CONTEXT - OMG
-'BAD_CONTEXT'(_) -> "-".
-
-%% OBJ_ADAPTER - OMG
-'OBJ_ADAPTER'(?CORBA_OMGVMCID bor 1) -> "System exception in
-AdapterActivator::unknown_adapter";
-'OBJ_ADAPTER'(?CORBA_OMGVMCID bor 2) -> "Servant not found [ServantManager]";
-'OBJ_ADAPTER'(?CORBA_OMGVMCID bor 3) -> "No default servant available [POA policy]";
-'OBJ_ADAPTER'(?CORBA_OMGVMCID bor 4) -> "No servant manager available [POA Policy]";
-'OBJ_ADAPTER'(?CORBA_OMGVMCID bor 5) -> "Violation of POA policy by
-ServantActivator::incarnate";
-'OBJ_ADAPTER'(?CORBA_OMGVMCID bor 6) -> "Exception in
-PortableInterceptor::IORInterceptor.components_established";
-%% OBJ_ADAPTER - Orber
-'OBJ_ADAPTER'(?ORBER_VMCID bor 1) -> "Call-back module does not exist";
-'OBJ_ADAPTER'(?ORBER_VMCID bor 2) -> "Missing function or incorrect arity in
-call-back module";
-'OBJ_ADAPTER'(?ORBER_VMCID bor 3) -> "Function exported but arity incorrect";
-'OBJ_ADAPTER'(?ORBER_VMCID bor 4) -> "Unknown error. Call-back module generated
-EXIT";
-'OBJ_ADAPTER'(?ORBER_VMCID bor 5) -> "Call-back module invoked operation on a
-non-existing module";
-'OBJ_ADAPTER'(?ORBER_VMCID bor 6) -> "Missing function or incorrect arity in
-a module invoked via the call-back module";
-'OBJ_ADAPTER'(?ORBER_VMCID bor 7) -> "Function exported but arity incorrect in
-a module invoked via the call-back module";
-'OBJ_ADAPTER'(?ORBER_VMCID bor 8) -> "Call-back module contains a function_clause,
-case_clause or badarith error";
-'OBJ_ADAPTER'(?ORBER_VMCID bor 9) -> "Call-back module invoked operation exported
-by another module which contains a function_clause, case_clause or badarith error";
-'OBJ_ADAPTER'(?ORBER_VMCID bor 10) -> "Unknown EXIT returned by call-back module";
-'OBJ_ADAPTER'(_) -> "-".
-
-%% DATA_CONVERSION - OMG
-'DATA_CONVERSION'(?CORBA_OMGVMCID bor 1) -> "Character does not map to negotiated
-transmission code set";
-'DATA_CONVERSION'(_) -> "-".
-
-%% OBJECT_NOT_EXIST - OMG
-'OBJECT_NOT_EXIST'(?CORBA_OMGVMCID bor 1) -> "Attempt to pass an unactivated
-(unregistered) value as an object reference";
-'OBJECT_NOT_EXIST'(?CORBA_OMGVMCID bor 2) -> "Failed to create or locate Object
-Adapter";
-'OBJECT_NOT_EXIST'(?CORBA_OMGVMCID bor 3) -> "Biomolecular Sequence Analysis
-Service is no longer available";
-'OBJECT_NOT_EXIST'(?CORBA_OMGVMCID bor 4) -> "Object Adapter inactive";
-'OBJECT_NOT_EXIST'(_) -> "-".
-
-%% TRANSACTION_REQUIRED - OMG
-'TRANSACTION_REQUIRED'(_) -> "-".
-
-%% TRANSACTION_ROLLEDBACK - OMG
-'TRANSACTION_ROLLEDBACK'(_) -> "-".
-
-%% INVALID_TRANSACTION - OMG
-'INVALID_TRANSACTION'(_) -> "-".
-
-%% INV_POLICY - OMG
-'INV_POLICY'(?CORBA_OMGVMCID bor 1) -> "Unable to reconcile IOR specified
-policy with effective policy override";
-'INV_POLICY'(?CORBA_OMGVMCID bor 2) -> "Invalid PolicyType";
-'INV_POLICY'(?CORBA_OMGVMCID bor 3) -> "No PolicyFactory has been registered
-for the given PolicyType";
-'INV_POLICY'(_) -> "-".
-
-%% CODESET_INCOMPATIBLE - OMG
-'CODESET_INCOMPATIBLE'(_) -> "-".
-
-%% REBIND - OMG
-'REBIND'(_) -> "-".
-
-%% TIMEOUT - OMG
-'TIMEOUT'(_) -> "-".
-
-%% TRANSACTION_UNAVAILABLE - OMG
-'TRANSACTION_UNAVAILABLE'(_) -> "-".
-
-%% TRANSACTION_MODE - OMG
-'TRANSACTION_MODE'(_) -> "-".
-
-%% BAD_QOS - OMG
-'BAD_QOS'(_) -> "-".
-
diff --git a/lib/orber/src/orber_ifr.erl b/lib/orber/src/orber_ifr.erl
deleted file mode 100644
index 70e0cb3fca..0000000000
--- a/lib/orber/src/orber_ifr.erl
+++ /dev/null
@@ -1,1820 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : corba_ir_impl.erl
-%% Purpose : Interface Repository for CORBA
-%%----------------------------------------------------------------------
-
-%%% NOTES:
-%%%
-%%% For details about known deficiencies in this CORBA IFR
-%%% implementation, see the file ../doc/src/notes.txt.
-%%%
-
--module(orber_ifr).
-
--export([
-%%% Public interfaces:
- init/2,
- find_repository/0,
- 'IRObject__get_def_kind'/1,
- %%'IRObject_destroy'/1,
- 'Contained__get_def_kind'/1,
- %%'Contained_destroy'/1,
- 'Contained__get_id'/1,
- 'Contained__set_id'/2,
- 'Contained__get_name'/1,
- 'Contained__set_name'/2,
- 'Contained__get_version'/1,
- 'Contained__set_version'/2,
- 'Contained__get_defined_in'/1,
- 'Contained__get_absolute_name'/1,
- 'Contained__get_containing_repository'/1,
- 'Contained_describe'/1,
- 'Contained_move'/4,
- 'Container__get_def_kind'/1,
- 'Container_destroy'/1,
- 'Container_lookup'/2,
- 'Container_contents'/3,
- 'Container_lookup_name'/5,
- 'Container_describe_contents'/4,
- 'Container_create_module'/4,
- 'Container_create_constant'/6,
- 'Container_create_struct'/5,
- 'Container_create_union'/6,
- 'Container_create_enum'/5,
- 'Container_create_alias'/5,
- 'Container_create_interface'/5,
- 'Container_create_exception'/5,
- 'IDLType__get_def_kind'/1,
- 'IDLType_destroy'/1,
- 'IDLType__get_type'/1,
- 'Repository__get_def_kind'/1,
- 'Repository_destroy'/1,
- 'Repository_lookup'/2,
- 'Repository_contents'/3,
- 'Repository_lookup_name'/5,
- 'Repository_describe_contents'/4,
- 'Repository_create_module'/4,
- 'Repository_create_constant'/6,
- 'Repository_create_struct'/5,
- 'Repository_create_union'/6,
- 'Repository_create_enum'/5,
- 'Repository_create_alias'/5,
- 'Repository_create_interface'/5,
- 'Repository_create_exception'/5,
- 'Repository_lookup_id'/2,
- 'Repository_get_primitive'/2,
- 'Repository_create_string'/2,
- 'Repository_create_wstring'/2,
- 'Repository_create_sequence'/3,
- 'Repository_create_array'/3,
- 'Repository_create_idltype'/2, %not in CORBA 2.0
- 'ModuleDef__get_def_kind'/1,
- 'ModuleDef_destroy'/1,
- 'ModuleDef_lookup'/2,
- 'ModuleDef_contents'/3,
- 'ModuleDef_lookup_name'/5,
- 'ModuleDef_describe_contents'/4,
- 'ModuleDef_create_module'/4,
- 'ModuleDef_create_constant'/6,
- 'ModuleDef_create_struct'/5,
- 'ModuleDef_create_union'/6,
- 'ModuleDef_create_enum'/5,
- 'ModuleDef_create_alias'/5,
- 'ModuleDef_create_interface'/5,
- 'ModuleDef_create_exception'/5,
- 'ModuleDef__get_id'/1,
- 'ModuleDef__set_id'/2,
- 'ModuleDef__get_name'/1,
- 'ModuleDef__set_name'/2,
- 'ModuleDef__get_version'/1,
- 'ModuleDef__set_version'/2,
- 'ModuleDef__get_defined_in'/1,
- 'ModuleDef__get_absolute_name'/1,
- 'ModuleDef__get_containing_repository'/1,
- 'ModuleDef_describe'/1,
- 'ModuleDef_move'/4,
- 'ConstantDef__get_def_kind'/1,
- 'ConstantDef_destroy'/1,
- 'ConstantDef__get_id'/1,
- 'ConstantDef__set_id'/2,
- 'ConstantDef__get_name'/1,
- 'ConstantDef__set_name'/2,
- 'ConstantDef__get_version'/1,
- 'ConstantDef__set_version'/2,
- 'ConstantDef__get_defined_in'/1,
- 'ConstantDef__get_absolute_name'/1,
- 'ConstantDef__get_containing_repository'/1,
- 'ConstantDef_describe'/1,
- 'ConstantDef_move'/4,
- 'ConstantDef__get_type'/1,
- 'ConstantDef__get_type_def'/1,
- 'ConstantDef__set_type_def'/2,
- 'ConstantDef__get_value'/1,
- 'ConstantDef__set_value'/2,
- 'TypedefDef__get_def_kind'/1,
- 'TypedefDef_destroy'/1,
- 'TypedefDef__get_id'/1,
- 'TypedefDef__set_id'/2,
- 'TypedefDef__get_name'/1,
- 'TypedefDef__set_name'/2,
- 'TypedefDef__get_version'/1,
- 'TypedefDef__set_version'/2,
- 'TypedefDef__get_defined_in'/1,
- 'TypedefDef__get_absolute_name'/1,
- 'TypedefDef__get_containing_repository'/1,
- 'TypedefDef_describe'/1,
- 'TypedefDef_move'/4,
- 'TypedefDef__get_type'/1,
- 'StructDef__get_def_kind'/1,
- 'StructDef_destroy'/1,
- 'StructDef__get_id'/1,
- 'StructDef__set_id'/2,
- 'StructDef__get_name'/1,
- 'StructDef__set_name'/2,
- 'StructDef__get_version'/1,
- 'StructDef__set_version'/2,
- 'StructDef__get_defined_in'/1,
- 'StructDef__get_absolute_name'/1,
- 'StructDef__get_containing_repository'/1,
- 'StructDef_describe'/1,
- 'StructDef_move'/4,
- 'StructDef__get_type'/1,
- 'StructDef__get_members'/1,
- 'StructDef__set_members'/2,
- 'UnionDef__get_def_kind'/1,
- 'UnionDef_destroy'/1,
- 'UnionDef__get_id'/1,
- 'UnionDef__set_id'/2,
- 'UnionDef__get_name'/1,
- 'UnionDef__set_name'/2,
- 'UnionDef__get_version'/1,
- 'UnionDef__set_version'/2,
- 'UnionDef__get_defined_in'/1,
- 'UnionDef__get_absolute_name'/1,
- 'UnionDef__get_containing_repository'/1,
- 'UnionDef_describe'/1,
- 'UnionDef_move'/4,
- 'UnionDef__get_type'/1,
- 'UnionDef__get_discriminator_type'/1,
- 'UnionDef__get_discriminator_type_def'/1,
- 'UnionDef__set_discriminator_type_def'/2,
- 'UnionDef__get_members'/1,
- 'UnionDef__set_members'/2,
- 'EnumDef__get_def_kind'/1,
- 'EnumDef_destroy'/1,
- 'EnumDef__get_id'/1,
- 'EnumDef__set_id'/2,
- 'EnumDef__get_name'/1,
- 'EnumDef__set_name'/2,
- 'EnumDef__get_version'/1,
- 'EnumDef__set_version'/2,
- 'EnumDef__get_defined_in'/1,
- 'EnumDef__get_absolute_name'/1,
- 'EnumDef__get_containing_repository'/1,
- 'EnumDef_describe'/1,
- 'EnumDef_move'/4,
- 'EnumDef__get_type'/1,
- 'EnumDef__get_members'/1,
- 'EnumDef__set_members'/2,
- 'AliasDef__get_def_kind'/1,
- 'AliasDef_destroy'/1,
- 'AliasDef__get_id'/1,
- 'AliasDef__set_id'/2,
- 'AliasDef__get_name'/1,
- 'AliasDef__set_name'/2,
- 'AliasDef__get_version'/1,
- 'AliasDef__set_version'/2,
- 'AliasDef__get_defined_in'/1,
- 'AliasDef__get_absolute_name'/1,
- 'AliasDef__get_containing_repository'/1,
- 'AliasDef_describe'/1,
- 'AliasDef_move'/4,
- 'AliasDef__get_type'/1,
- 'AliasDef__get_original_type_def'/1,
- 'AliasDef__set_original_type_def'/2,
- 'PrimitiveDef__get_def_kind'/1,
- 'PrimitiveDef_destroy'/1,
- 'PrimitiveDef__get_type'/1,
- 'PrimitiveDef__get_kind'/1,
- 'StringDef__get_def_kind'/1,
- 'StringDef_destroy'/1,
- 'StringDef__get_type'/1,
- 'StringDef__get_bound'/1,
- 'StringDef__set_bound'/2,
- 'WstringDef__get_def_kind'/1,
- 'WstringDef_destroy'/1,
- 'WstringDef__get_type'/1,
- 'WstringDef__get_bound'/1,
- 'WstringDef__set_bound'/2,
- 'FixedDef__get_def_kind'/1,
- 'FixedDef_destroy'/1,
- 'FixedDef__get_type'/1,
- 'FixedDef__get_digits'/1,
- 'FixedDef__set_digits'/2,
- 'FixedDef__get_scale'/1,
- 'FixedDef__set_scale'/2,
- 'SequenceDef__get_def_kind'/1,
- 'SequenceDef_destroy'/1,
- 'SequenceDef__get_type'/1,
- 'SequenceDef__get_bound'/1,
- 'SequenceDef__set_bound'/2,
- 'SequenceDef__get_element_type'/1,
- 'SequenceDef__get_element_type_def'/1,
- 'SequenceDef__set_element_type_def'/2,
- 'ArrayDef__get_def_kind'/1,
- 'ArrayDef_destroy'/1,
- 'ArrayDef__get_type'/1,
- 'ArrayDef__get_length'/1,
- 'ArrayDef__set_length'/2,
- 'ArrayDef__get_element_type'/1,
- 'ArrayDef__get_element_type_def'/1,
- 'ArrayDef__set_element_type_def'/2,
- 'ExceptionDef__get_def_kind'/1,
- 'ExceptionDef_destroy'/1,
- 'ExceptionDef__get_id'/1,
- 'ExceptionDef__set_id'/2,
- 'ExceptionDef__get_name'/1,
- 'ExceptionDef__set_name'/2,
- 'ExceptionDef__get_version'/1,
- 'ExceptionDef__set_version'/2,
- 'ExceptionDef__get_defined_in'/1,
- 'ExceptionDef__get_absolute_name'/1,
- 'ExceptionDef__get_containing_repository'/1,
- 'ExceptionDef_describe'/1,
- 'ExceptionDef_move'/4,
- 'ExceptionDef__get_type'/1,
- 'ExceptionDef__get_members'/1,
- 'ExceptionDef__set_members'/2,
- 'AttributeDef__get_def_kind'/1,
- 'AttributeDef_destroy'/1,
- 'AttributeDef__get_id'/1,
- 'AttributeDef__set_id'/2,
- 'AttributeDef__get_name'/1,
- 'AttributeDef__set_name'/2,
- 'AttributeDef__get_version'/1,
- 'AttributeDef__set_version'/2,
- 'AttributeDef__get_defined_in'/1,
- 'AttributeDef__get_absolute_name'/1,
- 'AttributeDef__get_containing_repository'/1,
- 'AttributeDef_describe'/1,
- 'AttributeDef_move'/4,
- 'AttributeDef__get_type'/1,
- 'AttributeDef__get_type_def'/1,
- 'AttributeDef__set_type_def'/2,
- 'AttributeDef__get_mode'/1,
- 'AttributeDef__set_mode'/2,
- 'OperationDef__get_def_kind'/1,
- 'OperationDef_destroy'/1,
- 'OperationDef__get_id'/1,
- 'OperationDef__set_id'/2,
- 'OperationDef__get_name'/1,
- 'OperationDef__set_name'/2,
- 'OperationDef__get_version'/1,
- 'OperationDef__set_version'/2,
- 'OperationDef__get_defined_in'/1,
- 'OperationDef__get_absolute_name'/1,
- 'OperationDef__get_containing_repository'/1,
- 'OperationDef_describe'/1,
- 'OperationDef_move'/4,
- 'OperationDef__get_result'/1,
- 'OperationDef__get_result_def'/1,
- 'OperationDef__set_result_def'/2,
- 'OperationDef__get_params'/1,
- 'OperationDef__set_params'/2,
- 'OperationDef__get_mode'/1,
- 'OperationDef__set_mode'/2,
- 'OperationDef__get_contexts'/1,
- 'OperationDef__set_contexts'/2,
- 'OperationDef__get_exceptions'/1,
- 'OperationDef__set_exceptions'/2,
- 'InterfaceDef__get_def_kind'/1,
- 'InterfaceDef_destroy'/1,
- 'InterfaceDef_lookup'/2,
- 'InterfaceDef_contents'/3,
- 'InterfaceDef_lookup_name'/5,
- 'InterfaceDef_describe_contents'/4,
- 'InterfaceDef_create_module'/4,
- 'InterfaceDef_create_constant'/6,
- 'InterfaceDef_create_struct'/5,
- 'InterfaceDef_create_union'/6,
- 'InterfaceDef_create_enum'/5,
- 'InterfaceDef_create_alias'/5,
- 'InterfaceDef_create_interface'/5,
- 'InterfaceDef_create_exception'/5,
- 'InterfaceDef__get_id'/1,
- 'InterfaceDef__set_id'/2,
- 'InterfaceDef__get_name'/1,
- 'InterfaceDef__set_name'/2,
- 'InterfaceDef__get_version'/1,
- 'InterfaceDef__set_version'/2,
- 'InterfaceDef__get_defined_in'/1,
- 'InterfaceDef__get_absolute_name'/1,
- 'InterfaceDef__get_containing_repository'/1,
- 'InterfaceDef_describe'/1,
- 'InterfaceDef_move'/4,
- 'InterfaceDef__get_type'/1,
- 'InterfaceDef__get_base_interfaces'/1,
- 'InterfaceDef__set_base_interfaces'/2,
- 'InterfaceDef_is_a'/2,
- 'InterfaceDef_describe_interface'/1,
- 'InterfaceDef_create_attribute'/6,
- 'InterfaceDef_create_operation'/9,
- %%'TypeCode_equal'/2,
- %%'TypeCode_kind'/1,
- %%'TypeCode_id'/1,
- %%'TypeCode_name'/1,
- %%'TypeCode_member_count'/1,
- %%'TypeCode_member_name'/2,
- %%'TypeCode_member_type'/2,
- %%'TypeCode_member_label'/2,
- %%'TypeCode_discriminator_type'/1,
- %%'TypeCode_default_index'/1,
- %%'TypeCode_length'/1,
- %%'TypeCode_content_type'/1,
- %%'TypeCode_param_count'/1,
- %%'TypeCode_parameter'/2,
- 'ORB_create_struct_tc'/3,
- 'ORB_create_union_tc'/4,
- 'ORB_create_enum_tc'/3,
- 'ORB_create_alias_tc'/3,
- 'ORB_create_exception_tc'/3,
- 'ORB_create_interface_tc'/2,
- 'ORB_create_string_tc'/1,
- 'ORB_create_wstring_tc'/1,
- 'ORB_create_sequence_tc'/2,
- 'ORB_create_recursive_sequence_tc'/2,
- 'ORB_create_array_tc'/2,
-%%% "Methods" of the IFR "objects"
- get_def_kind/1,
- destroy/1,
- get_id/1,
- set_id/2,
- get_name/1,
- set_name/2,
- get_version/1,
- set_version/2,
- get_defined_in/1,
- get_absolute_name/1,
- get_containing_repository/1,
- describe/1,
- move/4,
- lookup/2,
- contents/3,
- lookup_name/5,
- describe_contents/4,
- create_module/4,
- create_constant/6,
- create_struct/5,
- create_union/6,
- create_enum/5,
- create_alias/5,
- create_interface/5,
- create_exception/5,
- get_type/1,
- lookup_id/2,
- get_primitive/2,
- create_string/2,
- create_wstring/2,
- create_sequence/3,
- create_array/3,
- create_idltype/2, %not in CORBA 2.0
- create_fixed/3,
- get_type_def/1,
- set_type_def/2,
- get_value/1,
- set_value/2,
- get_members/1,
- set_members/2,
- get_discriminator_type/1,
- get_discriminator_type_def/1,
- set_discriminator_type_def/2,
- get_original_type_def/1,
- set_original_type_def/2,
- get_kind/1,
- get_bound/1,
- set_bound/2,
- get_element_type/1,
- get_element_type_def/1,
- set_element_type_def/2,
- get_length/1,
- set_length/2,
- get_mode/1,
- set_mode/2,
- get_result/1,
- get_result_def/1,
- set_result_def/2,
- get_params/1,
- set_params/2,
- get_contexts/1,
- set_contexts/2,
- get_exceptions/1,
- set_exceptions/2,
- get_base_interfaces/1,
- set_base_interfaces/2,
- is_a/2,
- describe_interface/1,
- create_attribute/6,
- create_operation/9
- ]).
-
-%% Light IFR operations
--export([initialize/3,
- get_module/2,
- get_tc/2,
- add_module/3, add_module/4,
- add_constant/3, add_constant/4,
- add_struct/3, add_struct/4,
- add_union/3, add_union/4,
- add_enum/3, add_enum/4,
- add_alias/3, add_alias/4,
- add_interface/3, add_interface/4,
- add_exception/3, add_exception/4,
- remove/2,
- add_items/3]).
-
-
--include_lib("orber/include/corba.hrl").
--include("orber_ifr.hrl").
--include("ifr_objects.hrl").
-
-%%======================================================================
-%% Public interfaces to the IFR
-%%======================================================================
-%%=================== Light IFR operations =============================
-%%----------------------------------------------------------------------
-%% Function : get_module
-%% Arguments : Id - string()
-%% Type - ?IFR_ModuleDef | ?IFR_ConstantDef | ?IFR_StructDef |
-%% ?IFR_UnionDef | ?IFR_EnumDef | ?IFR_AliasDef |
-%% ?IFR_InterfaceDef | ?IFR_ExceptionDef
-%% Returns : Module - atom() | {'EXCEPTION', E}
-%% Raises : #'MARSHAL'{}
-%% Description:
-%%----------------------------------------------------------------------
-get_module(Id, Type) ->
- case mnesia:dirty_read(orber_light_ifr, Id) of
- [#orber_light_ifr{module = Module, type = Type}] ->
- Module;
- What ->
- orber:dbg("[~p] ~p:get_module(~p, ~p).~n"
- "Id doesn't exist, mismatch Id vs Type or DB error: ~p",
- [?LINE, ?MODULE, Id, Type, What], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE})
- end.
-
-
-%%----------------------------------------------------------------------
-%% Function : get_tc
-%% Arguments : Id - string()
-%% Type - ?IFR_ModuleDef | ?IFR_ConstantDef | ?IFR_StructDef |
-%% ?IFR_UnionDef | ?IFR_EnumDef | ?IFR_AliasDef |
-%% ?IFR_InterfaceDef | ?IFR_ExceptionDef
-%% Returns : Module - atom() | {'EXCEPTION', E}
-%% Raises : #'MARSHAL'{}
-%% Description: This function may *only* return correct TypeCode or raise
-%% a system exception!!
-%%----------------------------------------------------------------------
-get_tc(Id, Type) ->
- case catch mnesia:dirty_read(orber_light_ifr, Id) of
- [#orber_light_ifr{module = Module, type = Type}] ->
- case catch Module:tc() of
- {'EXIT', Reason} ->
- case Reason of
- {undef,[{Module, tc,[],_}|_]} ->
- orber:dbg("[~p] ~p:get_tc(~p);~nMissing ~p:tc()~n",
- [?LINE, ?MODULE, Id, Module], ?DEBUG_LEVEL),
- corba:raise(#'UNKNOWN'{minor=(?ORBER_VMCID bor 1),
- completion_status=?COMPLETED_MAYBE});
- _ ->
- orber:dbg("[~p] ~p:get_tc(~p, ~p);~nEXIT reason: ~p~n",
- [?LINE, ?MODULE, Id, Module, Reason],
- ?DEBUG_LEVEL),
- corba:raise(#'UNKNOWN'{minor=(?CORBA_OMGVMCID bor 1),
- completion_status=?COMPLETED_MAYBE})
- end;
- TC ->
- TC
- end;
- What when Type == ?IFR_ExceptionDef ->
- orber:dbg("[~p] ~p:get_tc(~p, ExceptionDef);~nUnknown: ~p~n",
- [?LINE, ?MODULE, Id, What], ?DEBUG_LEVEL),
- corba:raise(#'UNKNOWN'{completion_status=?COMPLETED_MAYBE});
- What ->
- orber:dbg("[~p] ~p:get_tc(~p, ~p);~nUnknown: ~p~n",
- [?LINE, ?MODULE, Id, Type, What], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE})
- end.
-
-%%----------------------------------------------------------------------
-%% Function : initialize
-%% Arguments : Timeout - integer() | infinity
-%% Options - [{Key, Value}]
-%% LightIFR - true | false
-%% Returns : ok | {'EXCEPTION', E}
-%% Raises : #'INTF_REPOS'{}
-%% Description:
-%%----------------------------------------------------------------------
-initialize(Timeout, Options, LightIFR) ->
- orber_ifr_utils:init_DB(Timeout, Options, LightIFR).
-
-%%----------------------------------------------------------------------
-%% Function : add_X
-%% Arguments : Id - string()
-%% Module - atom()
-%% BaseId - string()
-%% Returns :
-%% Raises :
-%% Description:
-%%----------------------------------------------------------------------
-add_module(Id, Module, BaseId) ->
- add_it(Id, Module, BaseId, ?IFR_ModuleDef, false).
-add_module(Id, Module, BaseId, Transaction) ->
- add_it(Id, Module, BaseId, ?IFR_ModuleDef, Transaction).
-
-add_constant(Id, Module, BaseId) ->
- add_it(Id, Module, BaseId, ?IFR_ConstantDef, false).
-add_constant(Id, Module, BaseId, Transaction) ->
- add_it(Id, Module, BaseId, ?IFR_ConstantDef, Transaction).
-
-add_struct(Id, Module, BaseId) ->
- add_it(Id, Module, BaseId, ?IFR_StructDef, false).
-add_struct(Id, Module, BaseId, Transaction) ->
- add_it(Id, Module, BaseId, ?IFR_StructDef, Transaction).
-
-add_union(Id, Module, BaseId) ->
- add_it(Id, Module, BaseId, ?IFR_UnionDef, false).
-add_union(Id, Module, BaseId, Transaction) ->
- add_it(Id, Module, BaseId, ?IFR_UnionDef, Transaction).
-
-add_enum(Id, Module, BaseId) ->
- add_it(Id, Module, BaseId, ?IFR_EnumDef, false).
-add_enum(Id, Module, BaseId, Transaction) ->
- add_it(Id, Module, BaseId, ?IFR_EnumDef, Transaction).
-
-add_alias(Id, Module, BaseId) ->
- add_it(Id, Module, BaseId, ?IFR_AliasDef, false).
-add_alias(Id, Module, BaseId, Transaction) ->
- add_it(Id, Module, BaseId, ?IFR_AliasDef, Transaction).
-
-add_interface(Id, Module, BaseId) ->
- add_it(Id, Module, BaseId, ?IFR_InterfaceDef, false).
-add_interface(Id, Module, BaseId, Transaction) ->
- add_it(Id, Module, BaseId, ?IFR_InterfaceDef, Transaction).
-
-add_exception(Id, Module, BaseId) ->
- add_it(Id, Module, BaseId, ?IFR_ExceptionDef, false).
-add_exception(Id, Module, BaseId, Transaction) ->
- add_it(Id, Module, BaseId, ?IFR_ExceptionDef, Transaction).
-
-
-%%----------------------------------------------------------------------
-%% Function : add_it
-%% Arguments : Id - string()
-%% Module - atom()
-%% BaseId - string()
-%% Type - ?IFR_ModuleDef | ?IFR_ConstantDef | ?IFR_StructDef |
-%% ?IFR_UnionDef | ?IFR_EnumDef | ?IFR_AliasDef |
-%% ?IFR_InterfaceDef | ?IFR_ExceptionDef
-%% Transaction - true | false
-%% Returns :
-%% Raises :
-%% Description:
-%%----------------------------------------------------------------------
-add_it(Id, Module, BaseId, Type, true) ->
- F = fun() ->
- D = #orber_light_ifr{id = Id, module = Module,
- type = Type, base_id = BaseId},
- mnesia:write(D)
- end,
- case mnesia:transaction(F) of
- {aborted, Reason} ->
- orber:dbg("[~p] orber_ifr:add_it(~p). aborted:~n~p~n",
- [?LINE, Id, Reason], ?DEBUG_LEVEL),
- corba:raise(#'INTF_REPOS'{completion_status=?COMPLETED_NO});
- {atomic, _} ->
- ok
- end;
-add_it(Id, Module, BaseId, Type, false) ->
- D = #orber_light_ifr{id = Id, module = Module,
- type = Type, base_id = BaseId},
- mnesia:write(D).
-
-%%----------------------------------------------------------------------
-%% Function : remove
-%% Arguments : BaseId - atom()
-%% Options - [KeyValue]
-%% KeyValue - {storage, mnesia | ets}
-%% Returns :
-%% Raises :
-%% Description:
-%%----------------------------------------------------------------------
-remove(ContainerId, _Options) ->
- F = fun() ->
- MatchHead = #orber_light_ifr{id = '$1', base_id = ContainerId, _='_'},
- Result = '$1',
- IdList = mnesia:select(orber_light_ifr,
- [{MatchHead, [], [Result]}],
- write),
- lists:foreach(fun(RefId) ->
- mnesia:delete({orber_light_ifr, RefId})
- end, IdList)
- end,
- case mnesia:transaction(F) of
- {aborted, Reason} ->
- orber:dbg("[~p] orber_ifr:remove(~p). aborted:~n~p~n",
- [?LINE, ContainerId, Reason], ?DEBUG_LEVEL),
- corba:raise(#'INTF_REPOS'{completion_status=?COMPLETED_NO});
- {atomic, _} ->
- ok
- end.
-
-%%----------------------------------------------------------------------
-%% Function : add_items
-%% Arguments : ContainerId - atom()
-%% Options - [KeyValue]
-%% KeyValue - {storage, mnesia | ets}
-%% Items - [{Id, Module, Type}]
-%% Id - string()
-%% Module - atom()
-%% Type - struct | except | union | interface
-%% Returns :
-%% Raises :
-%% Description:
-%%----------------------------------------------------------------------
-add_items(ContainerId, _Options, Items) ->
- F = fun() ->
- mnesia:write_lock_table(orber_light_ifr),
- add_items_helper(Items, ContainerId)
- end,
- case mnesia:transaction(F) of
- {aborted, Reason} ->
- orber:dbg("[~p] orber_ifr:add_items(~p). aborted:~n~p~n",
- [?LINE, ContainerId, Reason], ?DEBUG_LEVEL),
- corba:raise(#'INTF_REPOS'{completion_status=?COMPLETED_NO});
- {atomic, _} ->
- ok
- end.
-
-add_items_helper([{Id, Module, struct}|T], ContainerId) ->
- add_it(Id, Module, ContainerId, ?IFR_StructDef, false),
- add_items_helper(T, ContainerId);
-add_items_helper([{Id, Module, interface}|T], ContainerId) ->
- add_it(Id, Module, ContainerId, ?IFR_InterfaceDef, false),
- add_items_helper(T, ContainerId);
-add_items_helper([{Id, Module, except}|T], ContainerId) ->
- add_it(Id, Module, ContainerId, ?IFR_ExceptionDef, false),
- add_items_helper(T, ContainerId);
-add_items_helper([{Id, Module, union}|T], ContainerId) ->
- add_it(Id, Module, ContainerId, ?IFR_UnionDef, false),
- add_items_helper(T, ContainerId);
-add_items_helper([ok], _) ->
- ok.
-
-
-%%=================== End Light IFR operations =========================
-
-%% Initialize the database
-init(Nodes, Timeout) when is_atom(Timeout) orelse is_integer(Timeout) ->
- orber_ifr_utils:init_DB(Timeout, [{disc_copies, Nodes}]);
-init(Timeout, Nodes) ->
- orber_ifr_utils:init_DB(Timeout, [{disc_copies, Nodes}]).
-
-
-%%% Find the repository
-find_repository() ->
- orber_ifr_utils:create_repository().
-
-'IRObject__get_def_kind'(Objref) ->
- orber_ifr_irobject:'_get_def_kind'(Objref).
-%%'IRObject_destroy'(Objref) ->
-%% orber_ifr_irobject:destroy(Objref).
-
-'Contained__get_def_kind'(Objref) ->
- orber_ifr_contained:'_get_def_kind'(Objref).
-%%'Contained_destroy'(Objref) ->
-%% orber_ifr_contained:destroy(Objref).
-'Contained__get_id'(Objref) ->
- orber_ifr_contained:'_get_id'(Objref).
-'Contained__set_id'(Objref,Id) ->
- orber_ifr_contained:'_set_id'(Objref,Id).
-'Contained__get_name'(Objref) ->
- orber_ifr_contained:'_get_name'(Objref).
-'Contained__set_name'(Objref,Name) ->
- orber_ifr_contained:'_set_name'(Objref,Name).
-'Contained__get_version'(Objref) ->
- orber_ifr_contained:'_get_version'(Objref).
-'Contained__set_version'(Objref,Version) ->
- orber_ifr_contained:'_set_version'(Objref,Version).
-'Contained__get_defined_in'(Objref) ->
- orber_ifr_contained:'_get_defined_in'(Objref).
-'Contained__get_absolute_name'(Objref) ->
- orber_ifr_contained:'_get_absolute_name'(Objref).
-'Contained__get_containing_repository'(Objref) ->
- orber_ifr_contained:'_get_containing_repository'(Objref).
-'Contained_describe'(Objref) ->
- orber_ifr_contained:describe(Objref).
-'Contained_move'(Objref,New_container,New_name,New_version) ->
- orber_ifr_contained:move(Objref,New_container,New_name,New_version).
-
-'Container__get_def_kind'(Objref) ->
- orber_ifr_container:'_get_def_kind'(Objref).
-'Container_destroy'(Objref) ->
- orber_ifr_container:destroy(Objref).
-'Container_lookup'(Objref,Search_name) ->
- orber_ifr_container:lookup(Objref,Search_name).
-'Container_contents'(Objref,Limit_type,Exclude_inherited) ->
- orber_ifr_container:contents(Objref,Limit_type,Exclude_inherited).
-'Container_lookup_name'(Objref,Search_name,Levels_to_search,Limit_type,
- Exclude_inherited) ->
- orber_ifr_container:lookup_name(Objref,Search_name,Levels_to_search,Limit_type,
- Exclude_inherited).
-'Container_describe_contents'(Objref,Limit_type,Exclude_inherited,
- Max_returned_objs) ->
- orber_ifr_container:describe_contents(Objref,Limit_type,Exclude_inherited,
- Max_returned_objs).
-'Container_create_module'(Objref,Id,Name,Version) ->
- orber_ifr_container:create_module(Objref,Id,Name,Version).
-'Container_create_constant'(Objref,Id,Name,Version,Type,Value) ->
- orber_ifr_container:create_constant(Objref,Id,Name,Version,Type,Value).
-'Container_create_struct'(Objref,Id,Name,Version,Members) ->
- orber_ifr_container:create_struct(Objref,Id,Name,Version,Members).
-'Container_create_union'(Objref,Id,Name,Version,Discriminator_type,Members) ->
- orber_ifr_container:create_union(Objref,Id,Name,Version,Discriminator_type,
- Members).
-'Container_create_enum'(Objref,Id,Name,Version,Members) ->
- orber_ifr_container:create_enum(Objref,Id,Name,Version,Members).
-'Container_create_alias'(Objref,Id,Name,Version,Original_type) ->
- orber_ifr_container:create_alias(Objref,Id,Name,Version,Original_type).
-'Container_create_interface'(Objref,Id,Name,Version,Base_interfaces) ->
- orber_ifr_container:create_interface(Objref,Id,Name,Version,Base_interfaces).
-'Container_create_exception'(Objref,Id,Name,Version,Members) ->
- orber_ifr_container:create_exception(Objref,Id,Name,Version,Members).
-
-'IDLType__get_def_kind'(Objref) ->
- orber_ifr_idltype:'_get_def_kind'(Objref).
-'IDLType_destroy'(Objref) ->
- orber_ifr_idltype:destroy(Objref).
-'IDLType__get_type'(Objref) ->
- orber_ifr_idltype:'_get_type'(Objref).
-
-'Repository__get_def_kind'(Objref) ->
- orber_ifr_repository:'_get_def_kind'(Objref).
--spec 'Repository_destroy'(_) -> no_return().
-'Repository_destroy'(Objref) ->
- orber_ifr_repository:destroy(Objref).
-'Repository_lookup'(Objref,Search_name) ->
- orber_ifr_repository:lookup(Objref,Search_name).
-'Repository_contents'(Objref,Limit_type,Exclude_inherited) ->
- orber_ifr_repository:contents(Objref,Limit_type,Exclude_inherited).
-'Repository_lookup_name'(Objref,Search_name,Levels_to_search,Limit_type,
- Exclude_inherited) ->
- orber_ifr_repository:lookup_name(Objref,Search_name,Levels_to_search,Limit_type,
- Exclude_inherited).
-'Repository_describe_contents'(Objref,Limit_type,Exclude_inherited,
- Max_returned_objs) ->
- orber_ifr_repository:describe_contents(Objref,Limit_type,Exclude_inherited,
- Max_returned_objs).
-'Repository_create_module'(Objref,Id,Name,Version) ->
- orber_ifr_repository:create_module(Objref,Id,Name,Version).
-'Repository_create_constant'(Objref,Id,Name,Version,Type,Value) ->
- orber_ifr_repository:create_constant(Objref,Id,Name,Version,Type,Value).
-'Repository_create_struct'(Objref,Id,Name,Version,Members) ->
- orber_ifr_repository:create_struct(Objref,Id,Name,Version,Members).
-'Repository_create_union'(Objref,Id,Name,Version,Discriminator_type,Members) ->
- orber_ifr_repository:create_union(Objref,Id,Name,Version,Discriminator_type,
- Members).
-'Repository_create_enum'(Objref,Id,Name,Version,Members) ->
- orber_ifr_repository:create_enum(Objref,Id,Name,Version,Members).
-'Repository_create_alias'(Objref,Id,Name,Version,Original_type) ->
- orber_ifr_repository:create_alias(Objref,Id,Name,Version,Original_type).
-'Repository_create_interface'(Objref,Id,Name,Version,Base_interfaces) ->
- orber_ifr_repository:create_interface(Objref,Id,Name,Version,Base_interfaces).
-'Repository_create_exception'(Objref,Id,Name,Version,Members) ->
- orber_ifr_repository:create_exception(Objref,Id,Name,Version,Members).
-'Repository_lookup_id'(Objref,Search_id) ->
- lookup_id(Objref,Search_id).
-'Repository_get_primitive'(Objref,Kind) ->
- orber_ifr_repository:get_primitive(Objref,Kind).
-'Repository_create_string'(Objref,Bound) ->
- orber_ifr_repository:create_string(Objref,Bound).
-'Repository_create_wstring'(Objref,Bound) ->
- orber_ifr_repository:create_wstring(Objref,Bound).
-'Repository_create_sequence'(Objref,Bound,Element_type) ->
- orber_ifr_repository:create_sequence(Objref,Bound,Element_type).
-'Repository_create_array'(Objref,Length,Element_type) ->
- orber_ifr_repository:create_array(Objref,Length,Element_type).
-'Repository_create_idltype'(Objref,Typecode) ->
- orber_ifr_repository:create_idltype(Objref,Typecode).
-
-'ModuleDef__get_def_kind'(Objref) ->
- orber_ifr_moduledef:'_get_def_kind'(Objref).
-'ModuleDef_destroy'(Objref) ->
- orber_ifr_moduledef:destroy(Objref).
-'ModuleDef_lookup'(Objref,Search_name) ->
- orber_ifr_moduledef:lookup(Objref,Search_name).
-'ModuleDef_contents'(Objref,Limit_type,Exclude_inherited) ->
- orber_ifr_moduledef:contents(Objref,Limit_type,Exclude_inherited).
-'ModuleDef_lookup_name'(Objref,Search_name,Levels_to_search,Limit_type,
- Exclude_inherited) ->
- orber_ifr_moduledef:lookup_name(Objref,Search_name,Levels_to_search,Limit_type,
- Exclude_inherited).
-'ModuleDef_describe_contents'(Objref,Limit_type,Exclude_inherited,
- Max_returned_objs) ->
- orber_ifr_moduledef:describe_contents(Objref,Limit_type,Exclude_inherited,
- Max_returned_objs).
-'ModuleDef_create_module'(Objref,Id,Name,Version) ->
- orber_ifr_moduledef:create_module(Objref,Id,Name,Version).
-'ModuleDef_create_constant'(Objref,Id,Name,Version,Type,Value) ->
- orber_ifr_moduledef:create_constant(Objref,Id,Name,Version,Type,Value).
-'ModuleDef_create_struct'(Objref,Id,Name,Version,Members) ->
- orber_ifr_moduledef:create_struct(Objref,Id,Name,Version,Members).
-'ModuleDef_create_union'(Objref,Id,Name,Version,Discriminator_type,Members) ->
- orber_ifr_moduledef:create_union(Objref,Id,Name,Version,Discriminator_type,
- Members).
-'ModuleDef_create_enum'(Objref,Id,Name,Version,Members) ->
- orber_ifr_moduledef:create_enum(Objref,Id,Name,Version,Members).
-'ModuleDef_create_alias'(Objref,Id,Name,Version,Original_type) ->
- orber_ifr_moduledef:create_alias(Objref,Id,Name,Version,Original_type).
-'ModuleDef_create_interface'(Objref,Id,Name,Version,Base_interfaces) ->
- orber_ifr_moduledef:create_interface(Objref,Id,Name,Version,Base_interfaces).
-'ModuleDef_create_exception'(Objref,Id,Name,Version,Members) ->
- orber_ifr_moduledef:create_exception(Objref,Id,Name,Version,Members).
-'ModuleDef__get_id'(Objref) ->
- orber_ifr_moduledef:'_get_id'(Objref).
-'ModuleDef__set_id'(Objref,Id) ->
- orber_ifr_moduledef:'_set_id'(Objref,Id).
-'ModuleDef__get_name'(Objref) ->
- orber_ifr_moduledef:'_get_name'(Objref).
-'ModuleDef__set_name'(Objref,Name) ->
- orber_ifr_moduledef:'_set_name'(Objref,Name).
-'ModuleDef__get_version'(Objref) ->
- orber_ifr_moduledef:'_get_version'(Objref).
-'ModuleDef__set_version'(Objref,Version) ->
- orber_ifr_moduledef:'_set_version'(Objref,Version).
-'ModuleDef__get_defined_in'(Objref) ->
- orber_ifr_moduledef:'_get_defined_in'(Objref).
-'ModuleDef__get_absolute_name'(Objref) ->
- orber_ifr_moduledef:'_get_absolute_name'(Objref).
-'ModuleDef__get_containing_repository'(Objref) ->
- orber_ifr_moduledef:'_get_containing_repository'(Objref).
-'ModuleDef_describe'(Objref) ->
- orber_ifr_moduledef:describe(Objref).
-'ModuleDef_move'(Objref,New_container,New_name,New_version) ->
- orber_ifr_moduledef:move(Objref,New_container,New_name,New_version).
-
-'ConstantDef__get_def_kind'(Objref) ->
- orber_ifr_constantdef:'_get_def_kind'(Objref).
-'ConstantDef_destroy'(Objref) ->
- orber_ifr_constantdef:destroy(Objref).
-'ConstantDef__get_id'(Objref) ->
- orber_ifr_constantdef:'_get_id'(Objref).
-'ConstantDef__set_id'(Objref,Id) ->
- orber_ifr_constantdef:'_set_id'(Objref,Id).
-'ConstantDef__get_name'(Objref) ->
- orber_ifr_constantdef:'_get_name'(Objref).
-'ConstantDef__set_name'(Objref,Name) ->
- orber_ifr_constantdef:'_set_name'(Objref,Name).
-'ConstantDef__get_version'(Objref) ->
- orber_ifr_constantdef:'_get_version'(Objref).
-'ConstantDef__set_version'(Objref,Version) ->
- orber_ifr_constantdef:'_set_version'(Objref,Version).
-'ConstantDef__get_defined_in'(Objref) ->
- orber_ifr_constantdef:'_get_defined_in'(Objref).
-'ConstantDef__get_absolute_name'(Objref) ->
- orber_ifr_constantdef:'_get_absolute_name'(Objref).
-'ConstantDef__get_containing_repository'(Objref) ->
- orber_ifr_constantdef:'_get_containing_repository'(Objref).
-'ConstantDef_describe'(Objref) ->
- orber_ifr_constantdef:describe(Objref).
-'ConstantDef_move'(Objref,New_container,New_name,New_version) ->
- orber_ifr_constantdef:move(Objref,New_container,New_name,New_version).
-'ConstantDef__get_type'(Objref) ->
- orber_ifr_constantdef:'_get_type'(Objref).
-'ConstantDef__get_type_def'(Objref) ->
- orber_ifr_constantdef:'_get_type_def'(Objref).
-'ConstantDef__set_type_def'(Objref,TypeDef) ->
- orber_ifr_constantdef:'_set_type_def'(Objref,TypeDef).
-'ConstantDef__get_value'(Objref) ->
- orber_ifr_constantdef:'_get_value'(Objref).
-'ConstantDef__set_value'(Objref,Value) ->
- orber_ifr_constantdef:'_set_value'(Objref,Value).
-
-'TypedefDef__get_def_kind'(Objref) ->
- orber_ifr_typedef:'_get_def_kind'(Objref).
-'TypedefDef_destroy'(Objref) ->
- orber_ifr_typedef:destroy(Objref).
-'TypedefDef__get_id'(Objref) ->
- orber_ifr_typedef:'_get_id'(Objref).
-'TypedefDef__set_id'(Objref,Id) ->
- orber_ifr_typedef:'_set_id'(Objref,Id).
-'TypedefDef__get_name'(Objref) ->
- orber_ifr_typedef:'_get_name'(Objref).
-'TypedefDef__set_name'(Objref,Name) ->
- orber_ifr_typedef:'_set_name'(Objref,Name).
-'TypedefDef__get_version'(Objref) ->
- orber_ifr_typedef:'_get_version'(Objref).
-'TypedefDef__set_version'(Objref,Version) ->
- orber_ifr_typedef:'_set_version'(Objref,Version).
-'TypedefDef__get_defined_in'(Objref) ->
- orber_ifr_typedef:'_get_defined_in'(Objref).
-'TypedefDef__get_absolute_name'(Objref) ->
- orber_ifr_typedef:'_get_absolute_name'(Objref).
-'TypedefDef__get_containing_repository'(Objref) ->
- orber_ifr_typedef:'_get_containing_repository'(Objref).
-'TypedefDef_describe'(Objref) ->
- orber_ifr_typedef:describe(Objref).
-'TypedefDef_move'(Objref,New_container,New_name,New_version) ->
- orber_ifr_typedef:move(Objref,New_container,New_name,New_version).
-'TypedefDef__get_type'(Objref) ->
- orber_ifr_typedef:'_get_type'(Objref).
-
-'StructDef__get_def_kind'(Objref) ->
- orber_ifr_structdef:'_get_def_kind'(Objref).
-'StructDef_destroy'(Objref) ->
- orber_ifr_structdef:destroy(Objref).
-'StructDef__get_id'(Objref) ->
- orber_ifr_structdef:'_get_id'(Objref).
-'StructDef__set_id'(Objref,Id) ->
- orber_ifr_structdef:'_set_id'(Objref,Id).
-'StructDef__get_name'(Objref) ->
- orber_ifr_structdef:'_get_name'(Objref).
-'StructDef__set_name'(Objref,Name) ->
- orber_ifr_structdef:'_set_name'(Objref,Name).
-'StructDef__get_version'(Objref) ->
- orber_ifr_structdef:'_get_version'(Objref).
-'StructDef__set_version'(Objref,Version) ->
- orber_ifr_structdef:'_set_version'(Objref,Version).
-'StructDef__get_defined_in'(Objref) ->
- orber_ifr_structdef:'_get_defined_in'(Objref).
-'StructDef__get_absolute_name'(Objref) ->
- orber_ifr_structdef:'_get_absolute_name'(Objref).
-'StructDef__get_containing_repository'(Objref) ->
- orber_ifr_structdef:'_get_containing_repository'(Objref).
-'StructDef_describe'(Objref) ->
- orber_ifr_structdef:describe(Objref).
-'StructDef_move'(Objref,New_container,New_name,New_version) ->
- orber_ifr_structdef:move(Objref,New_container,New_name,New_version).
-'StructDef__get_type'(Objref) ->
- orber_ifr_structdef:'_get_type'(Objref).
-'StructDef__get_members'(Objref) ->
- orber_ifr_structdef:'_get_members'(Objref).
-'StructDef__set_members'(Objref,Members) ->
- orber_ifr_structdef:'_set_members'(Objref,Members).
-
-'UnionDef__get_def_kind'(Objref) ->
- orber_ifr_uniondef:'_get_def_kind'(Objref).
-'UnionDef_destroy'(Objref) ->
- orber_ifr_uniondef:destroy(Objref).
-'UnionDef__get_id'(Objref) ->
- orber_ifr_uniondef:'_get_id'(Objref).
-'UnionDef__set_id'(Objref,Id) ->
- orber_ifr_uniondef:'_set_id'(Objref,Id).
-'UnionDef__get_name'(Objref) ->
- orber_ifr_uniondef:'_get_name'(Objref).
-'UnionDef__set_name'(Objref,Name) ->
- orber_ifr_uniondef:'_set_name'(Objref,Name).
-'UnionDef__get_version'(Objref) ->
- orber_ifr_uniondef:'_get_version'(Objref).
-'UnionDef__set_version'(Objref,Version) ->
- orber_ifr_uniondef:'_set_version'(Objref,Version).
-'UnionDef__get_defined_in'(Objref) ->
- orber_ifr_uniondef:'_get_defined_in'(Objref).
-'UnionDef__get_absolute_name'(Objref) ->
- orber_ifr_uniondef:'_get_absolute_name'(Objref).
-'UnionDef__get_containing_repository'(Objref) ->
- orber_ifr_uniondef:'_get_containing_repository'(Objref).
-'UnionDef_describe'(Objref) ->
- orber_ifr_uniondef:describe(Objref).
-'UnionDef_move'(Objref,New_container,New_name,New_version) ->
- orber_ifr_uniondef:move(Objref,New_container,New_name,New_version).
-'UnionDef__get_type'(Objref) ->
- orber_ifr_uniondef:'_get_type'(Objref).
-'UnionDef__get_discriminator_type'(Objref) ->
- orber_ifr_uniondef:'_get_discriminator_type'(Objref).
-'UnionDef__get_discriminator_type_def'(Objref) ->
- orber_ifr_uniondef:'_get_discriminator_type_def'(Objref).
-'UnionDef__set_discriminator_type_def'(Objref,TypeDef) ->
- orber_ifr_uniondef:'_set_discriminator_type_def'(Objref,TypeDef).
-'UnionDef__get_members'(Objref) ->
- orber_ifr_uniondef:'_get_members'(Objref).
-'UnionDef__set_members'(Objref,Members) ->
- orber_ifr_uniondef:'_set_members'(Objref,Members).
-
-'EnumDef__get_def_kind'(Objref) ->
- orber_ifr_enumdef:'_get_def_kind'(Objref).
-'EnumDef_destroy'(Objref) ->
- orber_ifr_enumdef:destroy(Objref).
-'EnumDef__get_id'(Objref) ->
- orber_ifr_enumdef:'_get_id'(Objref).
-'EnumDef__set_id'(Objref,Id) ->
- orber_ifr_enumdef:'_set_id'(Objref,Id).
-'EnumDef__get_name'(Objref) ->
- orber_ifr_enumdef:'_get_name'(Objref).
-'EnumDef__set_name'(Objref,Name) ->
- orber_ifr_enumdef:'_set_name'(Objref,Name).
-'EnumDef__get_version'(Objref) ->
- orber_ifr_enumdef:'_get_version'(Objref).
-'EnumDef__set_version'(Objref,Version) ->
- orber_ifr_enumdef:'_set_version'(Objref,Version).
-'EnumDef__get_defined_in'(Objref) ->
- orber_ifr_enumdef:'_get_defined_in'(Objref).
-'EnumDef__get_absolute_name'(Objref) ->
- orber_ifr_enumdef:'_get_absolute_name'(Objref).
-'EnumDef__get_containing_repository'(Objref) ->
- orber_ifr_enumdef:'_get_containing_repository'(Objref).
-'EnumDef_describe'(Objref) ->
- orber_ifr_enumdef:describe(Objref).
-'EnumDef_move'(Objref,New_container,New_name,New_version) ->
- orber_ifr_enumdef:move(Objref,New_container,New_name,New_version).
-'EnumDef__get_type'(Objref) ->
- orber_ifr_enumdef:'_get_type'(Objref).
-'EnumDef__get_members'(Objref) ->
- orber_ifr_enumdef:'_get_members'(Objref).
-'EnumDef__set_members'(Objref,Members) ->
- orber_ifr_enumdef:'_set_members'(Objref,Members).
-
-'AliasDef__get_def_kind'(Objref) ->
- orber_ifr_aliasdef:'_get_def_kind'(Objref).
-'AliasDef_destroy'(Objref) ->
- orber_ifr_aliasdef:destroy(Objref).
-'AliasDef__get_id'(Objref) ->
- orber_ifr_aliasdef:'_get_id'(Objref).
-'AliasDef__set_id'(Objref,Id) ->
- orber_ifr_aliasdef:'_set_id'(Objref,Id).
-'AliasDef__get_name'(Objref) ->
- orber_ifr_aliasdef:'_get_name'(Objref).
-'AliasDef__set_name'(Objref,Name) ->
- orber_ifr_aliasdef:'_set_name'(Objref,Name).
-'AliasDef__get_version'(Objref) ->
- orber_ifr_aliasdef:'_get_version'(Objref).
-'AliasDef__set_version'(Objref,Version) ->
- orber_ifr_aliasdef:'_set_version'(Objref,Version).
-'AliasDef__get_defined_in'(Objref) ->
- orber_ifr_aliasdef:'_get_defined_in'(Objref).
-'AliasDef__get_absolute_name'(Objref) ->
- orber_ifr_aliasdef:'_get_absolute_name'(Objref).
-'AliasDef__get_containing_repository'(Objref) ->
- orber_ifr_aliasdef:'_get_containing_repository'(Objref).
-'AliasDef_describe'(Objref) ->
- orber_ifr_aliasdef:describe(Objref).
-'AliasDef_move'(Objref,New_container,New_name,New_version) ->
- orber_ifr_aliasdef:move(Objref,New_container,New_name,New_version).
-'AliasDef__get_type'(Objref) ->
- orber_ifr_aliasdef:'_get_type'(Objref).
-'AliasDef__get_original_type_def'(Objref) ->
- orber_ifr_aliasdef:'_get_original_type_def'(Objref).
-'AliasDef__set_original_type_def'(Objref,TypeDef) ->
- orber_ifr_aliasdef:'_set_original_type_def'(Objref,TypeDef).
-
-'PrimitiveDef__get_def_kind'(Objref) ->
- orber_ifr_primitivedef:'_get_def_kind'(Objref).
-'PrimitiveDef_destroy'(Objref) ->
- orber_ifr_primitivedef:destroy(Objref).
-'PrimitiveDef__get_type'(Objref) ->
- orber_ifr_primitivedef:'_get_type'(Objref).
-'PrimitiveDef__get_kind'(Objref) ->
- orber_ifr_primitivedef:'_get_kind'(Objref).
-
-'StringDef__get_def_kind'(Objref) ->
- orber_ifr_stringdef:'_get_def_kind'(Objref).
-'StringDef_destroy'(Objref) ->
- orber_ifr_stringdef:destroy(Objref).
-'StringDef__get_type'(Objref) ->
- orber_ifr_stringdef:'_get_type'(Objref).
-'StringDef__get_bound'(Objref) ->
- orber_ifr_stringdef:'_get_bound'(Objref).
-'StringDef__set_bound'(Objref,Bound) ->
- orber_ifr_stringdef:'_set_bound'(Objref,Bound).
-
-'WstringDef__get_def_kind'(Objref) ->
- orber_ifr_wstringdef:'_get_def_kind'(Objref).
-'WstringDef_destroy'(Objref) ->
- orber_ifr_wstringdef:destroy(Objref).
-'WstringDef__get_type'(Objref) ->
- orber_ifr_wstringdef:'_get_type'(Objref).
-'WstringDef__get_bound'(Objref) ->
- orber_ifr_wstringdef:'_get_bound'(Objref).
-'WstringDef__set_bound'(Objref,Bound) ->
- orber_ifr_wstringdef:'_set_bound'(Objref,Bound).
-
-'FixedDef__get_def_kind'(Objref) ->
- orber_ifr_fixeddef:'_get_def_kind'(Objref).
-'FixedDef_destroy'(Objref) ->
- orber_ifr_fixeddef:destroy(Objref).
-'FixedDef__get_type'(Objref) ->
- orber_ifr_fixeddef:'_get_type'(Objref).
-'FixedDef__get_digits'(Objref) ->
- orber_ifr_fixeddef:'_get_digits'(Objref).
-'FixedDef__set_digits'(Objref,Digits) ->
- orber_ifr_fixeddef:'_set_digits'(Objref,Digits).
-'FixedDef__get_scale'(Objref) ->
- orber_ifr_fixeddef:'_get_scale'(Objref).
-'FixedDef__set_scale'(Objref,Scale) ->
- orber_ifr_fixeddef:'_set_scale'(Objref,Scale).
-
-'SequenceDef__get_def_kind'(Objref) ->
- orber_ifr_sequencedef:'_get_def_kind'(Objref).
-'SequenceDef_destroy'(Objref) ->
- orber_ifr_sequencedef:destroy(Objref).
-'SequenceDef__get_type'(Objref) ->
- orber_ifr_sequencedef:'_get_type'(Objref).
-'SequenceDef__get_bound'(Objref) ->
- orber_ifr_sequencedef:'_get_bound'(Objref).
-'SequenceDef__set_bound'(Objref,Bound) ->
- orber_ifr_sequencedef:'_set_bound'(Objref,Bound).
-'SequenceDef__get_element_type'(Objref) ->
- orber_ifr_sequencedef:'_get_element_type'(Objref).
-'SequenceDef__get_element_type_def'(Objref) ->
- orber_ifr_sequencedef:'_get_element_type_def'(Objref).
-'SequenceDef__set_element_type_def'(Objref,TypeDef) ->
- orber_ifr_sequencedef:'_set_element_type_def'(Objref,TypeDef).
-
-'ArrayDef__get_def_kind'(Objref) ->
- orber_ifr_arraydef:'_get_def_kind'(Objref).
-'ArrayDef_destroy'(Objref) ->
- orber_ifr_arraydef:destroy(Objref).
-'ArrayDef__get_type'(Objref) ->
- orber_ifr_arraydef:'_get_type'(Objref).
-'ArrayDef__get_length'(Objref) ->
- orber_ifr_arraydef:'_get_length'(Objref).
-'ArrayDef__set_length'(Objref,Length) ->
- orber_ifr_arraydef:'_set_length'(Objref,Length).
-'ArrayDef__get_element_type'(Objref) ->
- orber_ifr_arraydef:'_get_element_type'(Objref).
-'ArrayDef__get_element_type_def'(Objref) ->
- orber_ifr_arraydef:'_get_element_type_def'(Objref).
-'ArrayDef__set_element_type_def'(Objref,TypeDef) ->
- orber_ifr_arraydef:'_set_element_type_def'(Objref,TypeDef).
-
-'ExceptionDef__get_def_kind'(Objref) ->
- orber_ifr_exceptiondef:'_get_def_kind'(Objref).
-'ExceptionDef_destroy'(Objref) ->
- orber_ifr_exceptiondef:destroy(Objref).
-'ExceptionDef__get_id'(Objref) ->
- orber_ifr_exceptiondef:'_get_id'(Objref).
-'ExceptionDef__set_id'(Objref,Id) ->
- orber_ifr_exceptiondef:'_set_id'(Objref,Id).
-'ExceptionDef__get_name'(Objref) ->
- orber_ifr_exceptiondef:'_get_name'(Objref).
-'ExceptionDef__set_name'(Objref,Name) ->
- orber_ifr_exceptiondef:'_set_name'(Objref,Name).
-'ExceptionDef__get_version'(Objref) ->
- orber_ifr_exceptiondef:'_get_version'(Objref).
-'ExceptionDef__set_version'(Objref,Version) ->
- orber_ifr_exceptiondef:'_set_version'(Objref,Version).
-'ExceptionDef__get_defined_in'(Objref) ->
- orber_ifr_exceptiondef:'_get_defined_in'(Objref).
-'ExceptionDef__get_absolute_name'(Objref) ->
- orber_ifr_exceptiondef:'_get_absolute_name'(Objref).
-'ExceptionDef__get_containing_repository'(Objref) ->
- orber_ifr_exceptiondef:'_get_containing_repository'(Objref).
-'ExceptionDef_describe'(Objref) ->
- orber_ifr_exceptiondef:describe(Objref).
-'ExceptionDef_move'(Objref,New_container,New_name,New_version) ->
- orber_ifr_exceptiondef:move(Objref,New_container,New_name,New_version).
-'ExceptionDef__get_type'(Objref) ->
- orber_ifr_exceptiondef:'_get_type'(Objref).
-'ExceptionDef__get_members'(Objref) ->
- orber_ifr_exceptiondef:'_get_members'(Objref).
-'ExceptionDef__set_members'(Objref,Members) ->
- orber_ifr_exceptiondef:'_set_members'(Objref,Members).
-
-'AttributeDef__get_def_kind'(Objref) ->
- orber_ifr_attributedef:'_get_def_kind'(Objref).
-'AttributeDef_destroy'(Objref) ->
- orber_ifr_attributedef:destroy(Objref).
-'AttributeDef__get_id'(Objref) ->
- orber_ifr_attributedef:'_get_id'(Objref).
-'AttributeDef__set_id'(Objref,Id) ->
- orber_ifr_attributedef:'_set_id'(Objref,Id).
-'AttributeDef__get_name'(Objref) ->
- orber_ifr_attributedef:'_get_name'(Objref).
-'AttributeDef__set_name'(Objref,Name) ->
- orber_ifr_attributedef:'_set_name'(Objref,Name).
-'AttributeDef__get_version'(Objref) ->
- orber_ifr_attributedef:'_get_version'(Objref).
-'AttributeDef__set_version'(Objref,Version) ->
- orber_ifr_attributedef:'_set_version'(Objref,Version).
-'AttributeDef__get_defined_in'(Objref) ->
- orber_ifr_attributedef:'_get_defined_in'(Objref).
-'AttributeDef__get_absolute_name'(Objref) ->
- orber_ifr_attributedef:'_get_absolute_name'(Objref).
-'AttributeDef__get_containing_repository'(Objref) ->
- orber_ifr_attributedef:'_get_containing_repository'(Objref).
-'AttributeDef_describe'(Objref) ->
- orber_ifr_attributedef:describe(Objref).
-'AttributeDef_move'(Objref,New_container,New_name,New_version) ->
- orber_ifr_attributedef:move(Objref,New_container,New_name,New_version).
-'AttributeDef__get_type'(Objref) ->
- orber_ifr_attributedef:'_get_type'(Objref).
-'AttributeDef__get_type_def'(Objref) ->
- orber_ifr_attributedef:'_get_type_def'(Objref).
-'AttributeDef__set_type_def'(Objref,TypeDef) ->
- orber_ifr_attributedef:'_set_type_def'(Objref,TypeDef).
-'AttributeDef__get_mode'(Objref) ->
- orber_ifr_attributedef:'_get_mode'(Objref).
-'AttributeDef__set_mode'(Objref,Mode) ->
- orber_ifr_attributedef:'_set_mode'(Objref,Mode).
-
-'OperationDef__get_def_kind'(Objref) ->
- orber_ifr_operationdef:'_get_def_kind'(Objref).
-'OperationDef_destroy'(Objref) ->
- orber_ifr_operationdef:destroy(Objref).
-'OperationDef__get_id'(Objref) ->
- orber_ifr_operationdef:'_get_id'(Objref).
-'OperationDef__set_id'(Objref,Id) ->
- orber_ifr_operationdef:'_set_id'(Objref,Id).
-'OperationDef__get_name'(Objref) ->
- orber_ifr_operationdef:'_get_name'(Objref).
-'OperationDef__set_name'(Objref,Name) ->
- orber_ifr_operationdef:'_set_name'(Objref,Name).
-'OperationDef__get_version'(Objref) ->
- orber_ifr_operationdef:'_get_version'(Objref).
-'OperationDef__set_version'(Objref,Version) ->
- orber_ifr_operationdef:'_set_version'(Objref,Version).
-'OperationDef__get_defined_in'(Objref) ->
- orber_ifr_operationdef:'_get_defined_in'(Objref).
-'OperationDef__get_absolute_name'(Objref) ->
- orber_ifr_operationdef:'_get_absolute_name'(Objref).
-'OperationDef__get_containing_repository'(Objref) ->
- orber_ifr_operationdef:'_get_containing_repository'(Objref).
-'OperationDef_describe'(Objref) ->
- orber_ifr_operationdef:describe(Objref).
-'OperationDef_move'(Objref,New_container,New_name,New_version) ->
- orber_ifr_operationdef:move(Objref,New_container,New_name,New_version).
-'OperationDef__get_result'(Objref) ->
- orber_ifr_operationdef:'_get_result'(Objref).
-'OperationDef__get_result_def'(Objref) ->
- orber_ifr_operationdef:'_get_result_def'(Objref).
-'OperationDef__set_result_def'(Objref,ResultDef) ->
- orber_ifr_operationdef:'_set_result_def'(Objref,ResultDef).
-'OperationDef__get_params'(Objref) ->
- orber_ifr_operationdef:'_get_params'(Objref).
-'OperationDef__set_params'(Objref,Params) ->
- orber_ifr_operationdef:'_set_params'(Objref,Params).
-'OperationDef__get_mode'(Objref) ->
- orber_ifr_operationdef:'_get_mode'(Objref).
-'OperationDef__set_mode'(Objref,Mode) ->
- orber_ifr_operationdef:'_set_mode'(Objref,Mode).
-'OperationDef__get_contexts'(Objref) ->
- orber_ifr_operationdef:'_get_contexts'(Objref).
-'OperationDef__set_contexts'(Objref,Contexts) ->
- orber_ifr_operationdef:'_set_contexts'(Objref,Contexts).
-'OperationDef__get_exceptions'(Objref) ->
- orber_ifr_operationdef:'_get_exceptions'(Objref).
-'OperationDef__set_exceptions'(Objref,Exceptions) ->
- orber_ifr_operationdef:'_set_exceptions'(Objref,Exceptions).
-
-'InterfaceDef__get_def_kind'(Objref) ->
- orber_ifr_interfacedef:'_get_def_kind'(Objref).
-'InterfaceDef_destroy'(Objref) ->
- orber_ifr_interfacedef:destroy(Objref).
-'InterfaceDef_lookup'(Objref,Search_name) ->
- orber_ifr_interfacedef:lookup(Objref,Search_name).
-'InterfaceDef_contents'(Objref,Limit_type,Exclude_inherited) ->
- orber_ifr_interfacedef:contents(Objref,Limit_type,Exclude_inherited).
-'InterfaceDef_lookup_name'(Objref,Search_name,Levels_to_search,Limit_type,
- Exclude_inherited) ->
- orber_ifr_interfacedef:lookup_name(Objref,Search_name,Levels_to_search,Limit_type,
- Exclude_inherited).
-'InterfaceDef_describe_contents'(Objref,Limit_type,Exclude_inherited,
- Max_returned_objs) ->
- orber_ifr_interfacedef:describe_contents(Objref,Limit_type,Exclude_inherited,
- Max_returned_objs).
-'InterfaceDef_create_module'(Objref,Id,Name,Version) ->
- orber_ifr_interfacedef:create_module(Objref,Id,Name,Version).
-'InterfaceDef_create_constant'(Objref,Id,Name,Version,Type,Value) ->
- orber_ifr_interfacedef:create_constant(Objref,Id,Name,Version,Type,Value).
-'InterfaceDef_create_struct'(Objref,Id,Name,Version,Members) ->
- orber_ifr_interfacedef:create_struct(Objref,Id,Name,Version,Members).
-'InterfaceDef_create_union'(Objref,Id,Name,Version,Discriminator_type,
- Members) ->
- orber_ifr_interfacedef:create_union(Objref,Id,Name,Version,Discriminator_type,
- Members).
-'InterfaceDef_create_enum'(Objref,Id,Name,Version,Members) ->
- orber_ifr_interfacedef:create_enum(Objref,Id,Name,Version,Members).
-'InterfaceDef_create_alias'(Objref,Id,Name,Version,Original_type) ->
- orber_ifr_interfacedef:create_alias(Objref,Id,Name,Version,Original_type).
-'InterfaceDef_create_interface'(Objref,Id,Name,Version,Base_interfaces) ->
- orber_ifr_interfacedef:create_interface(Objref,Id,Name,Version,Base_interfaces).
-'InterfaceDef_create_exception'(Objref,Id,Name,Version,Members) ->
- orber_ifr_interfacedef:create_exception(Objref,Id,Name,Version,Members).
-'InterfaceDef__get_id'(Objref) ->
- orber_ifr_interfacedef:'_get_id'(Objref).
-'InterfaceDef__set_id'(Objref,Id) ->
- orber_ifr_interfacedef:'_set_id'(Objref,Id).
-'InterfaceDef__get_name'(Objref) ->
- orber_ifr_interfacedef:'_get_name'(Objref).
-'InterfaceDef__set_name'(Objref,Name) ->
- orber_ifr_interfacedef:'_set_name'(Objref,Name).
-'InterfaceDef__get_version'(Objref) ->
- orber_ifr_interfacedef:'_get_version'(Objref).
-'InterfaceDef__set_version'(Objref,Version) ->
- orber_ifr_interfacedef:'_set_version'(Objref,Version).
-'InterfaceDef__get_defined_in'(Objref) ->
- orber_ifr_interfacedef:'_get_defined_in'(Objref).
-'InterfaceDef__get_absolute_name'(Objref) ->
- orber_ifr_interfacedef:'_get_absolute_name'(Objref).
-'InterfaceDef__get_containing_repository'(Objref) ->
- orber_ifr_interfacedef:'_get_containing_repository'(Objref).
-'InterfaceDef_describe'(Objref) ->
- orber_ifr_interfacedef:describe(Objref).
-'InterfaceDef_move'(Objref,New_container,New_name,New_version) ->
- orber_ifr_interfacedef:move(Objref,New_container,New_name,New_version).
-'InterfaceDef__get_type'(Objref) ->
- orber_ifr_interfacedef:'_get_type'(Objref).
-'InterfaceDef__get_base_interfaces'(Objref) ->
- orber_ifr_interfacedef:'_get_base_interfaces'(Objref).
-'InterfaceDef__set_base_interfaces'(Objref,BaseInterfaces) ->
- orber_ifr_interfacedef:'_set_base_interfaces'(Objref,BaseInterfaces).
-'InterfaceDef_is_a'(Objref,Interface_id) ->
- orber_ifr_interfacedef:is_a(Objref,Interface_id).
-'InterfaceDef_describe_interface'(Objref) ->
- orber_ifr_interfacedef:describe_interface(Objref).
-'InterfaceDef_create_attribute'(Objref,Id,Name,Version,Type,Mode) ->
- orber_ifr_interfacedef:create_attribute(Objref,Id,Name,Version,Type,Mode).
-'InterfaceDef_create_operation'(Objref,Id,Name,Version,Result,Mode,Params,
- Exceptions,Contexts) ->
- orber_ifr_interfacedef:create_operation(Objref,Id,Name,Version,Result,Mode,
- Params,Exceptions,Contexts).
-
-%%'TypeCode_equal'(Objref,Tc) ->
-%% orber_ifr_typecode:equal(Objref,Tc).
-%%'TypeCode_kind'(Objref) ->
-%% orber_ifr_typecode:kind(Objref).
-%%'TypeCode_id'(Objref) ->
-%% orber_ifr_typecode:id(Objref).
-%%'TypeCode_name'(Objref) ->
-%% orber_ifr_typecode:name(Objref).
-%%'TypeCode_member_count'(Objref) ->
-%% orber_ifr_typecode:member_count(Objref).
-%%'TypeCode_member_name'(Objref,Index) ->
-%% orber_ifr_typecode:member_name(Objref,Index).
-%%'TypeCode_member_type'(Objref,Index) ->
-%% orber_ifr_typecode:member_type(Objref,Index).
-%%'TypeCode_member_label'(Objref,Index) ->
-%% orber_ifr_typecode:member_label(Objref,Index).
-%%'TypeCode_discriminator_type'(Objref) ->
-%% orber_ifr_typecode:discriminator_type(Objref).
-%%'TypeCode_default_index'(Objref) ->
-%% orber_ifr_typecode:default_index(Objref).
-%%'TypeCode_length'(Objref) ->
-%% orber_ifr_typecode:length(Objref).
-%%'TypeCode_content_type'(Objref) ->
-%% orber_ifr_typecode:content_type(Objref).
-%%'TypeCode_param_count'(Objref) ->
-%% orber_ifr_typecode:param_count(Objref).
-%%'TypeCode_parameter'(Objref,Index) ->
-%% orber_ifr_typecode:parameter(Objref,Index).
-
-'ORB_create_struct_tc'(Id,Name,Members) ->
- orber_ifr_orb:create_struct_tc(Id,Name,Members).
-'ORB_create_union_tc'(Id,Name,Discriminator_type,Members) ->
- orber_ifr_orb:create_union_tc(Id,Name,Discriminator_type,Members).
-'ORB_create_enum_tc'(Id,Name,Members) ->
- orber_ifr_orb:create_enum_tc(Id,Name,Members).
-'ORB_create_alias_tc'(Id,Name,Original_type) ->
- orber_ifr_orb:create_alias_tc(Id,Name,Original_type).
-'ORB_create_exception_tc'(Id,Name,Members) ->
- orber_ifr_orb:create_exception_tc(Id,Name,Members).
-'ORB_create_interface_tc'(Id,Name) ->
- orber_ifr_orb:create_interface_tc(Id,Name).
-'ORB_create_string_tc'(Bound) ->
- orber_ifr_orb:create_string_tc(Bound).
-'ORB_create_wstring_tc'(Bound) ->
- orber_ifr_orb:create_wstring_tc(Bound).
-'ORB_create_sequence_tc'(Bound,Element_type) ->
- orber_ifr_orb:create_sequence_tc(Bound,Element_type).
--spec 'ORB_create_recursive_sequence_tc'(_,_) -> no_return().
-'ORB_create_recursive_sequence_tc'(Bound,Offset) ->
- orber_ifr_orb:create_recursive_sequence_tc(Bound,Offset).
-'ORB_create_array_tc'(Length,Element_type) ->
- orber_ifr_orb:create_array_tc(Length,Element_type).
-
-%%%---------------------------------------------------------------
-%%% "Methods" of the IFR "objects"
-
-get_def_kind(Objref) ->
- Mod = obj2mod(Objref),
- Mod:'_get_def_kind'(Objref).
-
-%% Light IFR Operations
-destroy(#orber_light_ifr_ref{data = #lightdata{id = Id}}) ->
- F = fun() ->
- MatchHead = #orber_light_ifr{id = '$1', base_id = Id, _='_'},
- Result = '$1',
- IdList = mnesia:select(orber_light_ifr,
- [{MatchHead, [], [Result]}],
- write),
- lists:foreach(fun(RefId) ->
- mnesia:delete({orber_light_ifr, RefId})
- end, IdList)
- end,
- case mnesia:transaction(F) of
- {aborted, _} ->
- exit({"FAILED TO DELETE:", Id});
- {atomic, _} ->
- ok
- end;
-destroy(Objref) ->
- %% Destroying an ir_IRObject, ir_Contained or ir_Container directly
- %% is not allowed
- Mod = obj2mod(Objref),
- Mod:destroy(Objref).
-
-%%%---------------------------------------------------------------
-%%%
-
-get_id(Objref) ->
- Mod = obj2mod(Objref),
- Mod:'_get_id'(Objref).
-
-set_id(Objref,Id) ->
- Mod = obj2mod(Objref),
- Mod:'_set_id'(Objref,Id).
-
-get_name(Objref) ->
- Mod = obj2mod(Objref),
- Mod:'_get_name'(Objref).
-
-set_name(Objref,Name) ->
- Mod = obj2mod(Objref),
- Mod:'_set_name'(Objref,Name).
-
-get_version(Objref) ->
- Mod = obj2mod(Objref),
- Mod:'_get_version'(Objref).
-
-set_version(Objref,Version) ->
- Mod = obj2mod(Objref),
- Mod:'_set_version'(Objref,Version).
-
-get_defined_in(Objref) ->
- Mod = obj2mod(Objref),
- Mod:'_get_defined_in'(Objref).
-
-get_absolute_name(Objref) ->
- Mod = obj2mod(Objref),
- Mod: '_get_absolute_name'(Objref).
-
-get_containing_repository(Objref) ->
- Mod = obj2mod(Objref),
- Mod:'_get_containing_repository'(Objref).
-
-describe(Objref) ->
- Mod = obj2mod(Objref),
- Mod:describe(Objref).
-
-move(Objref,New_container,New_name,New_version) ->
- Mod = obj2mod(Objref),
- Mod:move(Objref,New_container,New_name,New_version).
-
-%%%---------------------------------------------------------------
-%%%
-
-lookup(Objref,Search_name) ->
- Mod = obj2mod(Objref),
- Mod:lookup(Objref,Search_name).
-
-%% Light IFR Operation
-contents(#orber_light_ifr_ref{data = #lightdata{id = _Id}},
- _Limit_type, _Exclude_inherited) ->
- [];
-contents(Objref,Limit_type,Exclude_inherited) ->
- Mod = obj2mod(Objref),
- Mod:contents(Objref,Limit_type,Exclude_inherited).
-
-lookup_name(Objref,Search_name,Levels_to_search,Limit_type,Exclude_inherited) ->
- Mod = obj2mod(Objref),
- Mod:lookup_name(Objref,Search_name,Levels_to_search,Limit_type,Exclude_inherited).
-
-
-describe_contents(Objref,Limit_type,Exclude_inherited,Max_returned_objs) ->
- Mod = obj2mod(Objref),
- Mod:describe_contents(Objref,Limit_type,Exclude_inherited,Max_returned_objs).
-
-create_module(Objref,Id,Name,Version) ->
- Mod = obj2mod(Objref),
- Mod:create_module(Objref,Id,Name,Version).
-
-create_constant(Objref,Id,Name,Version,Type,Value) ->
- Mod = obj2mod(Objref),
- Mod:create_constant(Objref,Id,Name,Version,Type,Value).
-
-create_struct(Objref,Id,Name,Version,Members) ->
- Mod = obj2mod(Objref),
- Mod:create_struct(Objref,Id,Name,Version,Members).
-
-create_union(Objref,Id,Name,Version,Discriminator_type,Members) ->
- Mod = obj2mod(Objref),
- Mod:create_union(Objref,Id,Name,Version,Discriminator_type,Members).
-
-create_enum(Objref,Id,Name,Version,Members) ->
- Mod = obj2mod(Objref),
- Mod:create_enum(Objref,Id,Name,Version,Members).
-
-create_alias(Objref,Id,Name,Version,Original_type) ->
- Mod = obj2mod(Objref),
- Mod:create_alias(Objref,Id,Name,Version,Original_type).
-
-create_interface(Objref,Id,Name,Version,Base_interfaces) ->
- Mod = obj2mod(Objref),
- Mod:create_interface(Objref,Id,Name,Version,Base_interfaces).
-
-create_exception(Objref,Id,Name,Version,Members) ->
- Mod = obj2mod(Objref),
- Mod:create_exception(Objref,Id,Name,Version,Members).
-
-%%%---------------------------------------------------------------
-%%%
-
-get_type(Objref) ->
- Mod = obj2mod(Objref),
- Mod:'_get_type'(Objref).
-
-%%%---------------------------------------------------------------
-%%%
-
-%% This list should contain the data in most-likely-to-be-accessed-order.
--define(INDEXED_TABLE_LIST, [{ir_ExceptionDef, #ir_ExceptionDef.id},
- {ir_InterfaceDef, #ir_InterfaceDef.id},
- {ir_ModuleDef, #ir_ModuleDef.id},
- {ir_StructDef, #ir_StructDef.id},
- {ir_UnionDef, #ir_UnionDef.id},
- {ir_AliasDef, #ir_AliasDef.id},
- {ir_TypedefDef, #ir_TypedefDef.id},
- {ir_ConstantDef, #ir_ConstantDef.id},
- {ir_EnumDef, #ir_EnumDef.id},
- {ir_AttributeDef, #ir_AttributeDef.id},
- {ir_Contained, #ir_Contained.id},
- {ir_OperationDef, #ir_OperationDef.id}]).
-
-
-lookup_id(#orber_light_ifr_ref{}, Id) ->
- case mnesia:dirty_read(orber_light_ifr, Id) of
- [] ->
- [];
- [#orber_light_ifr{module = Mod}] ->
- #orber_light_ifr_ref{data = #lightdata{scope = atom_to_list(Mod),
- id = Id}}
- end;
-lookup_id(_Objref,Id) ->
- %% We used the operation below before but it's very expensive.
- %% orber_ifr_repository:lookup_id(Objref,Id)
- lookup_id_helper(?INDEXED_TABLE_LIST, Id).
-
-lookup_id_helper([], _) ->
- [];
-lookup_id_helper([{Tab, IdNum}|T], Id) ->
- case mnesia:dirty_index_read(Tab, Id, IdNum) of
- [] ->
- lookup_id_helper(T, Id);
- [FoundIt] ->
- {Tab, element(2, FoundIt)}
- end.
-
-get_primitive(Objref,Kind) ->
- orber_ifr_repository:get_primitive(Objref,Kind).
-
-create_string(Objref,Bound) ->
- orber_ifr_repository:create_string(Objref,Bound).
-
-create_wstring(Objref,Bound) ->
- orber_ifr_repository:create_wstring(Objref,Bound).
-
-create_sequence(Objref,Bound,Element_type) ->
- orber_ifr_repository:create_sequence(Objref,Bound,Element_type).
-
-create_array(Objref,Length,Element_type) ->
- orber_ifr_repository:create_array(Objref,Length,Element_type).
-
-create_idltype(Objref,Typecode) -> %not in CORBA 2.0
- orber_ifr_repository:create_idltype(Objref,Typecode).
-
-create_fixed(Objref, Digits, Scale) ->
- orber_ifr_repository:create_fixed(Objref, Digits, Scale).
-
-%%%---------------------------------------------------------------
-%%%
-
-get_type_def(Objref) ->
- Mod = obj2mod(Objref),
- Mod:'_get_type_def'(Objref).
-
-set_type_def(Objref,TypeDef) ->
- Mod = obj2mod(Objref),
- Mod:'_set_type_def'(Objref,TypeDef).
-
-get_value(Objref) ->
- orber_ifr_constantdef:'_get_value'(Objref).
-
-set_value(Objref,Value) ->
- orber_ifr_constantdef: '_set_value'(Objref,Value).
-
-%%%---------------------------------------------------------------
-%%%
-
-get_members(Objref) ->
- Mod = obj2mod(Objref),
- Mod:'_get_members'(Objref).
-
-set_members(Objref,Members) ->
- Mod = obj2mod(Objref),
- Mod:'_set_members'(Objref,Members).
-
-%%%---------------------------------------------------------------
-%%%
-
-get_discriminator_type(Objref) ->
- orber_ifr_uniondef:'_get_discriminator_type'(Objref).
-
-get_discriminator_type_def(Objref) ->
- orber_ifr_uniondef:'_get_discriminator_type_def'(Objref).
-
-set_discriminator_type_def(Objref,TypeDef) ->
- orber_ifr_uniondef:'_set_discriminator_type_def'(Objref,TypeDef).
-
-%%%---------------------------------------------------------------
-%%%
-
-get_original_type_def(Objref) ->
- orber_ifr_aliasdef:'_get_original_type_def'(Objref).
-
-set_original_type_def(Objref,TypeDef) ->
- orber_ifr_aliasdef:'_set_original_type_def'(Objref,TypeDef).
-
-%%%---------------------------------------------------------------
-%%%
-
-get_kind(Objref) ->
- orber_ifr_primitivedef:'_get_kind'(Objref).
-
-%%%---------------------------------------------------------------
-%%%
-
-get_bound(Objref) ->
- Mod = obj2mod(Objref),
- Mod:'_get_bound'(Objref).
-
-set_bound(Objref,Bound) ->
- Mod = obj2mod(Objref),
- Mod:'_set_bound'(Objref,Bound).
-
-%%%---------------------------------------------------------------
-%%%
-
-get_element_type(Objref) ->
- Mod = obj2mod(Objref),
- Mod:'_get_element_type'(Objref).
-
-get_element_type_def(Objref) ->
- Mod = obj2mod(Objref),
- Mod:'_get_element_type_def'(Objref).
-
-set_element_type_def(Objref,TypeDef) ->
- Mod = obj2mod(Objref),
- Mod:'_set_element_type_def'(Objref,TypeDef).
-
-%%%---------------------------------------------------------------
-%%%
-
-get_length(Objref) ->
- orber_ifr_arraydef:'_get_length'(Objref).
-
-set_length(Objref,Length) ->
- orber_ifr_arraydef:'_set_length'(Objref,Length).
-
-%%%---------------------------------------------------------------
-%%%
-
-get_mode(Objref) ->
- Mod = obj2mod(Objref),
- Mod:'_get_mode'(Objref).
-
-set_mode(Objref,Mode) ->
- Mod = obj2mod(Objref),
- Mod:'_set_mode'(Objref,Mode).
-
-%%%---------------------------------------------------------------
-%%%
-
-get_result(Objref) ->
- orber_ifr_operationdef:'_get_result'(Objref).
-
-get_result_def(Objref) ->
- orber_ifr_operationdef:'_get_result_def'(Objref).
-
-set_result_def(Objref,ResultDef) ->
- orber_ifr_operationdef:'_set_result_def'(Objref,ResultDef).
-
-get_params(Objref) ->
- orber_ifr_operationdef:'_get_params'(Objref).
-
-set_params(Objref,Params) ->
- orber_ifr_operationdef:'_set_params'(Objref,Params).
-
-get_contexts(Objref) ->
- orber_ifr_operationdef:'_get_contexts'(Objref).
-
-set_contexts(Objref,Contexts) ->
- orber_ifr_operationdef:'_set_contexts'(Objref,Contexts).
-
-get_exceptions(Objref) ->
- orber_ifr_operationdef:'_get_exceptions'(Objref).
-
-set_exceptions(Objref,Exceptions) ->
- orber_ifr_operationdef:'_set_exceptions'(Objref,Exceptions).
-
-%%%---------------------------------------------------------------
-%%%
-
-get_base_interfaces(Objref) ->
- orber_ifr_interfacedef:'_get_base_interfaces'(Objref).
-
-set_base_interfaces(Objref,BaseInterfaces) ->
- orber_ifr_interfacedef:'_set_base_interfaces'(Objref,BaseInterfaces).
-
-is_a(Objref,Interface_id) ->
- orber_ifr_interfacedef:is_a(Objref,Interface_id).
-
-describe_interface(Objref) ->
- orber_ifr_interfacedef:describe_interface(Objref).
-
-create_attribute(Objref,Id,Name,Version,Type,Mode) ->
- orber_ifr_interfacedef:create_attribute(Objref,Id,Name,Version,Type,Mode).
-
-create_operation(Objref,Id,Name,Version,Result,Mode,Params,Exceptions,Contexts) ->
- orber_ifr_interfacedef:create_operation(Objref,Id,Name,Version,Result,Mode,
- Params,Exceptions,Contexts).
-
-obj2mod({ir_IRObject, _}) ->
- orber_ifr_irobject;
-obj2mod({ir_Contained, _}) ->
- orber_ifr_contained;
-obj2mod({ir_Container, _}) ->
- orber_ifr_container;
-obj2mod({ir_IDLType, _}) ->
- orber_ifr_idltype;
-obj2mod({ir_Repository, _}) ->
- orber_ifr_repository;
-obj2mod({ir_ModuleDef, _}) ->
- orber_ifr_moduledef;
-obj2mod({ir_ConstantDef, _}) ->
- orber_ifr_constantdef;
-obj2mod({ir_TypedefDef, _}) ->
- orber_ifr_typedef;
-obj2mod({ir_StructDef, _}) ->
- orber_ifr_structdef;
-obj2mod({ir_UnionDef, _}) ->
- orber_ifr_uniondef;
-obj2mod({ir_EnumDef, _}) ->
- orber_ifr_enumdef;
-obj2mod({ir_AliasDef, _}) ->
- orber_ifr_aliasdef;
-obj2mod({ir_PrimitiveDef, _}) ->
- orber_ifr_primitivedef;
-obj2mod({ir_StringDef, _}) ->
- orber_ifr_stringdef;
-obj2mod({ir_WstringDef, _}) ->
- orber_ifr_wstringdef;
-obj2mod({ir_SequenceDef, _}) ->
- orber_ifr_sequencedef;
-obj2mod({ir_ArrayDef, _}) ->
- orber_ifr_arraydef;
-obj2mod({ir_ExceptionDef, _}) ->
- orber_ifr_exceptiondef;
-obj2mod({ir_AttributeDef, _}) ->
- orber_ifr_attributedef;
-obj2mod({ir_OperationDef, _}) ->
- orber_ifr_operationdef;
-obj2mod({ir_InterfaceDef, _}) ->
- orber_ifr_interfacedef;
-obj2mod({ir_FixedDef, _}) ->
- orber_ifr_fidxeddef;
-obj2mod(Obj) ->
- orber:dbg("[~p] orber_ifr:obj2mod(~p); unknown.",
- [?LINE, Obj], ?DEBUG_LEVEL),
- corba:raise(#'INTF_REPOS'{completion_status=?COMPLETED_NO}).
-
-
diff --git a/lib/orber/src/orber_ifr.hrl b/lib/orber/src/orber_ifr.hrl
deleted file mode 100644
index 10634f58c0..0000000000
--- a/lib/orber/src/orber_ifr.hrl
+++ /dev/null
@@ -1,35 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_ifr.hrl
-%% Purpose : Macros for the Interface Repository
-%%----------------------------------------------------------------------
-
-
--record(lightdata, {scope, id}).
--record(orber_light_ifr_ref, {data}).
-
-%% "Type" checking
--define(tcheck(Type, Thing), when Type == Thing ; Thing == orber_light_ifr_ref).
-
--define(DEBUG_LEVEL, 9).
-
diff --git a/lib/orber/src/orber_ifr_aliasdef.erl b/lib/orber/src/orber_ifr_aliasdef.erl
deleted file mode 100644
index 04a92be5e3..0000000000
--- a/lib/orber/src/orber_ifr_aliasdef.erl
+++ /dev/null
@@ -1,135 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_ifr_aliasdef.erl
-%% Purpose : Code for Aliasdef
-%%----------------------------------------------------------------------
-
--module(orber_ifr_aliasdef).
-
--export(['_get_def_kind'/1,
- destroy/1,
- cleanup_for_destroy/1, %not in CORBA 2.0
- '_get_id'/1,
- '_set_id'/2,
- '_get_name'/1,
- '_set_name'/2,
- '_get_version'/1,
- '_set_version'/2,
- '_get_defined_in'/1,
- '_get_absolute_name'/1,
- '_get_containing_repository'/1,
- describe/1,
- move/4,
- '_get_type'/1,
- '_get_original_type_def'/1,
- '_set_original_type_def'/2
- ]).
-
--import(orber_ifr_utils,[get_field/2,
- get_object/1,
- set_object/1
- ]).
-
--include("orber_ifr.hrl").
--include("ifr_objects.hrl").
-
-%%%======================================================================
-%%% AliasDef (TypedefDef(Contained(IRObject), IDLType(IRObject)))
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IRObject
-
-'_get_def_kind'({ObjType, ObjID}) ?tcheck(ir_AliasDef, ObjType) ->
- orber_ifr_irobject:'_get_def_kind'({ObjType,ObjID}).
-
-destroy({ObjType, ObjID}) ?tcheck(ir_AliasDef, ObjType) ->
- F = fun() -> ObjList = cleanup_for_destroy({ObjType, ObjID}),
- orber_ifr_irobject:destroy([{ObjType,ObjID} | ObjList])
- end,
- orber_ifr_utils:ifr_transaction_write(F).
-
-cleanup_for_destroy({ObjType,ObjID}) ?tcheck(ir_AliasDef, ObjType) ->
- orber_ifr_idltype:cleanup_for_destroy(
- '_get_original_type_def'({ObjType,ObjID})) ++
- orber_ifr_typedef:cleanup_for_destroy({ObjType,ObjID}).
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from Contained
-
-'_get_id'({ObjType, ObjID}) ?tcheck(ir_AliasDef, ObjType) ->
- orber_ifr_contained:'_get_id'({ObjType,ObjID}).
-
-'_set_id'({ObjType, ObjID}, EO_Value) ?tcheck(ir_AliasDef, ObjType) ->
- orber_ifr_contained:'_set_id'({ObjType,ObjID},EO_Value).
-
-'_get_name'({ObjType, ObjID}) ?tcheck(ir_AliasDef, ObjType) ->
- orber_ifr_contained:'_get_name'({ObjType,ObjID}).
-
-'_set_name'({ObjType, ObjID}, EO_Value) ?tcheck(ir_AliasDef, ObjType) ->
- orber_ifr_contained:'_set_name'({ObjType,ObjID}, EO_Value).
-
-'_get_version'({ObjType, ObjID}) ?tcheck(ir_AliasDef, ObjType) ->
- orber_ifr_contained:'_get_version'({ObjType,ObjID}).
-
-'_set_version'({ObjType, ObjID}, EO_Value) ?tcheck(ir_AliasDef, ObjType) ->
- orber_ifr_contained:'_set_version'({ObjType,ObjID},EO_Value).
-
-'_get_defined_in'({ObjType, ObjID}) ?tcheck(ir_AliasDef, ObjType) ->
- orber_ifr_contained:'_get_defined_in'({ObjType,ObjID}).
-
-'_get_absolute_name'({ObjType, ObjID}) ?tcheck(ir_AliasDef,ObjType) ->
- orber_ifr_contained:'_get_absolute_name'({ObjType,ObjID}).
-
-'_get_containing_repository'({ObjType, ObjID}) ?tcheck(ir_AliasDef, ObjType) ->
- orber_ifr_contained:'_get_containing_repository'({ObjType,ObjID}).
-
-describe({ObjType, ObjID}) ?tcheck(ir_AliasDef, ObjType) ->
- orber_ifr_contained:describe({ObjType,ObjID}).
-
-move({ObjType, ObjID}, New_container, New_name, New_version)
- ?tcheck(ir_AliasDef, ObjType) ->
- orber_ifr_contained:move({ObjType,ObjID},New_container,New_name,
- New_version).
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IDLType
-
-'_get_type'({ObjType, ObjID}) ?tcheck(ir_AliasDef, ObjType) ->
- orber_ifr_idltype:'_get_type'({ObjType, ObjID}).
-
-%%%----------------------------------------------------------------------
-%%% Non-inherited interfaces
-
-'_get_original_type_def'({ObjType, ObjID})
- ?tcheck(ir_AliasDef, ObjType) ->
- get_field({ObjType,ObjID},original_type_def).
-
-'_set_original_type_def'({ObjType, ObjID}, EO_Value)
- ?tcheck(ir_AliasDef, ObjType) ->
- AliasDef = get_object({ObjType, ObjID}),
- New_AliasDef = AliasDef#ir_AliasDef{type = {tk_alias,
- AliasDef#ir_AliasDef.id,
- AliasDef#ir_AliasDef.name,
- EO_Value#ir_IDLType.type},
- original_type_def = EO_Value},
- set_object(New_AliasDef).
diff --git a/lib/orber/src/orber_ifr_arraydef.erl b/lib/orber/src/orber_ifr_arraydef.erl
deleted file mode 100644
index 1513914a08..0000000000
--- a/lib/orber/src/orber_ifr_arraydef.erl
+++ /dev/null
@@ -1,104 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_ifr_arraydef.erl
-%% Purpose : Code for Arraydef
-%%----------------------------------------------------------------------
-
--module(orber_ifr_arraydef).
-
--export(['_get_def_kind'/1,
- destroy/1,
- cleanup_for_destroy/1, %not in CORBA 2.0
- '_get_type'/1,
- '_get_length'/1,
- '_set_length'/2,
- '_get_element_type'/1,
- '_get_element_type_def'/1,
- '_set_element_type_def'/2
- ]).
-
--import(orber_ifr_utils,[get_field/2,
- get_object/1,
- set_object/1
- ]).
-
--include("orber_ifr.hrl").
--include("ifr_objects.hrl").
-
-%%%======================================================================
-%%% ArrayDef (IDLType(IRObject))
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IRObject
-
-'_get_def_kind'({ObjType, ObjID}) ?tcheck(ir_ArrayDef, ObjType) ->
- orber_ifr_irobject:'_get_def_kind'({ObjType,ObjID}).
-
-destroy({ObjType, ObjID}) ?tcheck(ir_ArrayDef, ObjType) ->
- F = fun() -> ObjList = cleanup_for_destroy({ObjType, ObjID}),
- orber_ifr_irobject:destroy([{ObjType,ObjID} | ObjList])
- end,
- orber_ifr_utils:ifr_transaction_write(F).
-
-cleanup_for_destroy({ObjType,ObjID}) ?tcheck(ir_ArrayDef, ObjType) ->
- orber_ifr_idltype:cleanup_for_destroy(
- '_get_element_type_def'({ObjType,ObjID})) ++
- orber_ifr_idltype:cleanup_for_destroy({ObjType,ObjID}).
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IDLType
-
-'_get_type'({ObjType, ObjID}) ?tcheck(ir_ArrayDef, ObjType) ->
- orber_ifr_idltype:'_get_type'({ObjType, ObjID}).
-
-%%%----------------------------------------------------------------------
-%%% Non-inherited interfaces
-
-'_get_length'({ObjType, ObjID}) ?tcheck(ir_ArrayDef, ObjType) ->
- get_field({ObjType,ObjID},length).
-
-'_set_length'({ObjType, ObjID}, EO_Value) ?tcheck(ir_ArrayDef, ObjType) ->
- ArrayDef = get_object({ObjType, ObjID}),
- New_ArrayDef =
- ArrayDef#ir_ArrayDef{type = {tk_array,
- ArrayDef#ir_ArrayDef.type,
- ArrayDef#ir_ArrayDef.length},
- length = EO_Value},
- set_object(New_ArrayDef).
-
-'_get_element_type'({ObjType, ObjID}) ?tcheck(ir_ArrayDef, ObjType) ->
- get_field({ObjType,ObjID},element_type).
-
-'_get_element_type_def'({ObjType, ObjID}) ?tcheck(ir_ArrayDef, ObjType) ->
- get_field({ObjType,ObjID},element_type_def).
-
-'_set_element_type_def'({ObjType, ObjID}, EO_Value)
- ?tcheck(ir_ArrayDef, ObjType) ->
- ArrayDef = get_object({ObjType, ObjID}),
- New_type = {tk_array,
- EO_Value#ir_IDLType.type,
- ArrayDef#ir_ArrayDef.length},
- New_ArrayDef = ArrayDef#ir_ArrayDef{type = New_type,
- element_type = New_type,
- element_type_def = EO_Value},
- set_object(New_ArrayDef).
diff --git a/lib/orber/src/orber_ifr_attributedef.erl b/lib/orber/src/orber_ifr_attributedef.erl
deleted file mode 100644
index bf7d1d2b63..0000000000
--- a/lib/orber/src/orber_ifr_attributedef.erl
+++ /dev/null
@@ -1,138 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_ifr_attributedef.erl
-%% Purpose : Code for Attributedef
-%%----------------------------------------------------------------------
-
--module(orber_ifr_attributedef).
-
--export(['_get_def_kind'/1,
- destroy/1,
- cleanup_for_destroy/1, %not in CORBA 2.0
- '_get_id'/1,
- '_set_id'/2,
- '_get_name'/1,
- '_set_name'/2,
- '_get_version'/1,
- '_set_version'/2,
- '_get_defined_in'/1,
- '_get_absolute_name'/1,
- '_get_containing_repository'/1,
- describe/1,
- move/4,
- '_get_type'/1,
- '_get_type_def'/1,
- '_set_type_def'/2,
- '_get_mode'/1,
- '_set_mode'/2
- ]).
-
--import(orber_ifr_utils,[get_field/2,
- set_field/3,
- get_object/1,
- set_object/1
- ]).
-
--include("orber_ifr.hrl").
--include("ifr_objects.hrl").
-
-%%%----------------------------------------------------------------------
-%% AttributeDef (Contained(IRObject))
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IRObject
-
-'_get_def_kind'({ObjType, ObjID}) ?tcheck(ir_AttributeDef, ObjType) ->
- orber_ifr_irobject:'_get_def_kind'({ObjType,ObjID}).
-
-destroy({ObjType, ObjID}) ?tcheck(ir_AttributeDef, ObjType) ->
- F = fun() -> ObjList = cleanup_for_destroy({ObjType, ObjID}),
- orber_ifr_irobject:destroy([{ObjType,ObjID} | ObjList])
- end,
- orber_ifr_utils:ifr_transaction_write(F).
-
-cleanup_for_destroy({ObjType,ObjID}) ?tcheck(ir_AttributeDef, ObjType) ->
- orber_ifr_idltype:cleanup_for_destroy(
- orber_ifr_idltype:'_get_type_def'({ObjType,ObjID})) ++
- orber_ifr_contained:cleanup_for_destroy({ObjType,ObjID}).
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from Contained
-
-'_get_id'({ObjType, ObjID}) ?tcheck(ir_AttributeDef, ObjType) ->
- orber_ifr_contained:'_get_id'({ObjType,ObjID}).
-
-'_set_id'({ObjType, ObjID}, EO_Value) ?tcheck(ir_AttributeDef, ObjType) ->
- orber_ifr_contained:'_set_id'({ObjType,ObjID},EO_Value).
-
-'_get_name'({ObjType, ObjID}) ?tcheck(ir_AttributeDef, ObjType) ->
- orber_ifr_contained:'_get_name'({ObjType,ObjID}).
-
-'_set_name'({ObjType, ObjID}, EO_Value) ?tcheck(ir_AttributeDef, ObjType) ->
- orber_ifr_contained:'_set_name'({ObjType,ObjID}, EO_Value).
-
-'_get_version'({ObjType, ObjID}) ?tcheck(ir_AttributeDef, ObjType) ->
- orber_ifr_contained:'_get_version'({ObjType,ObjID}).
-
-'_set_version'({ObjType, ObjID}, EO_Value) ?tcheck(ir_AttributeDef, ObjType) ->
- orber_ifr_contained:'_set_version'({ObjType,ObjID},EO_Value).
-
-'_get_defined_in'({ObjType, ObjID}) ?tcheck(ir_AttributeDef, ObjType) ->
- orber_ifr_contained:'_get_defined_in'({ObjType,ObjID}).
-
-'_get_absolute_name'({ObjType, ObjID}) ?tcheck(ir_AttributeDef, ObjType) ->
- orber_ifr_contained:'_get_absolute_name'({ObjType,ObjID}).
-
-'_get_containing_repository'({ObjType, ObjID})
- ?tcheck(ir_AttributeDef, ObjType) ->
- orber_ifr_contained:'_get_containing_repository'({ObjType,ObjID}).
-
-describe({ObjType, ObjID}) ?tcheck(ir_AttributeDef, ObjType) ->
- orber_ifr_contained:describe({ObjType,ObjID}).
-
-move({ObjType, ObjID}, New_container, New_name, New_version)
- ?tcheck(ir_AttributeDef, ObjType) ->
- orber_ifr_contained:move({ObjType,ObjID},New_container,New_name,
- New_version).
-
-%%%----------------------------------------------------------------------
-%%% Non-inherited interfaces
-
-'_get_type'({ObjType, ObjID}) ?tcheck(ir_AttributeDef, ObjType) ->
- get_field({ObjType,ObjID},type).
-
-'_get_type_def'({ObjType, ObjID}) ?tcheck(ir_AttributeDef, ObjType) ->
- get_field({ObjType,ObjID},type_def).
-
-'_set_type_def'({ObjType, ObjID},EO_Value) ?tcheck(ir_AttributeDef, ObjType) ->
- AttributeDef = get_object({ObjType, ObjID}),
- New_AttributeDef =
- AttributeDef#ir_AttributeDef{type = EO_Value#ir_IDLType.type,
- type_def = EO_Value},
- set_object(New_AttributeDef).
-
-'_get_mode'({ObjType, ObjID}) ?tcheck(ir_AttributeDef, ObjType) ->
- get_field({ObjType,ObjID},mode).
-
-'_set_mode'({ObjType, ObjID}, EO_Value) ?tcheck(ir_AttributeDef, ObjType) ->
- set_field({ObjType,ObjID}, mode, EO_Value).
diff --git a/lib/orber/src/orber_ifr_constantdef.erl b/lib/orber/src/orber_ifr_constantdef.erl
deleted file mode 100644
index b9d4393177..0000000000
--- a/lib/orber/src/orber_ifr_constantdef.erl
+++ /dev/null
@@ -1,148 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_ifr_constantdef.erl
-%% Purpose : Code for Constantdef
-%%----------------------------------------------------------------------
-
--module(orber_ifr_constantdef).
-
--export(['_get_def_kind'/1,
- destroy/1,
- cleanup_for_destroy/1, %not in CORBA 2.0
- '_get_id'/1,
- '_set_id'/2,
- '_get_name'/1,
- '_set_name'/2,
- '_get_version'/1,
- '_set_version'/2,
- '_get_defined_in'/1,
- '_get_absolute_name'/1,
- '_get_containing_repository'/1,
- describe/1,
- move/4,
- '_get_type'/1,
- '_get_type_def'/1,
- '_set_type_def'/2,
- '_get_value'/1,
- '_set_value'/2
- ]).
-
--import(orber_ifr_utils,[get_field/2,
- set_field/3,
- get_object/1,
- set_object/1
- ]).
-
--include_lib("orber/include/corba.hrl").
--include("orber_ifr.hrl").
--include("ifr_objects.hrl").
-
-%%%======================================================================
-%%% ConstantDef (Contained(IRObject))
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IRObject
-
-'_get_def_kind'({ObjType,ObjID}) ?tcheck(ir_ConstantDef,ObjType) ->
- orber_ifr_irobject:'_get_def_kind'({ObjType, ObjID}).
-
-destroy({ObjType, ObjID}) ?tcheck(ir_ConstantDef, ObjType) ->
- F = fun() -> ObjList = cleanup_for_destroy({ObjType,ObjID}),
- orber_ifr_irobject:destroy([{ObjType,ObjID} | ObjList])
- end,
- orber_ifr_utils:ifr_transaction_write(F).
-
-cleanup_for_destroy({ObjType,ObjID}) ?tcheck(ir_ConstantDef, ObjType) ->
- orber_ifr_idltype:cleanup_for_destroy(
- '_get_type_def'({ObjType,ObjID})) ++
- orber_ifr_contained:cleanup_for_destroy({ObjType,ObjID}).
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from Contained
-
-'_get_id'({ObjType, ObjID}) ?tcheck(ir_ConstantDef, ObjType) ->
- orber_ifr_contained:'_get_id'({ObjType,ObjID}).
-
-'_set_id'({ObjType, ObjID}, EO_Value) ?tcheck(ir_ConstantDef, ObjType) ->
- orber_ifr_contained:'_set_id'({ObjType,ObjID},EO_Value).
-
-'_get_name'({ObjType, ObjID}) ?tcheck(ir_ConstantDef, ObjType) ->
- orber_ifr_contained:'_get_name'({ObjType,ObjID}).
-
-'_set_name'({ObjType, ObjID}, EO_Value) ?tcheck(ir_ConstantDef, ObjType) ->
- orber_ifr_contained:'_set_name'({ObjType,ObjID}, EO_Value).
-
-'_get_version'({ObjType, ObjID}) ?tcheck(ir_ConstantDef,ObjType) ->
- orber_ifr_contained:'_get_version'({ObjType,ObjID}).
-
-'_set_version'({ObjType, ObjID}, EO_Value) ?tcheck(ir_ConstantDef, ObjType) ->
- orber_ifr_contained:'_set_version'({ObjType,ObjID},EO_Value).
-
-'_get_defined_in'({ObjType, ObjID}) ?tcheck(ir_ConstantDef, ObjType) ->
- orber_ifr_contained:'_get_defined_in'({ObjType,ObjID}).
-
-'_get_absolute_name'({ObjType, ObjID}) ?tcheck(ir_ConstantDef, ObjType) ->
- orber_ifr_contained:'_get_absolute_name'({ObjType,ObjID}).
-
-'_get_containing_repository'({ObjType, ObjID})
- ?tcheck(ir_ConstantDef, ObjType) ->
- orber_ifr_contained:'_get_containing_repository'({ObjType,ObjID}).
-
-describe({ObjType, ObjID}) ?tcheck(ir_ConstantDef, ObjType) ->
- orber_ifr_contained:describe({ObjType,ObjID}).
- %
-move({ObjType, ObjID}, New_container, New_name, New_version)
- ?tcheck(ir_ConstantDef, ObjType) ->
- orber_ifr_contained:move({ObjType,ObjID},New_container,New_name,
- New_version).
-
-%%%----------------------------------------------------------------------
-%%% Non-inherited interfaces
-
-'_get_type'({ObjType, ObjID}) ?tcheck(ir_ConstantDef, ObjType) ->
- get_field({ObjType,ObjID},type).
-
-'_get_type_def'({ObjType,ObjID}) ?tcheck(ir_ConstantDef,ObjType) ->
- get_field({ObjType,ObjID},type_def).
-
-'_set_type_def'({ObjType, ObjID}, EO_Value) ?tcheck(ir_ConstantDef, ObjType) ->
- ConstantDef = get_object({ObjType, ObjID}),
- New_ConstantDef = ConstantDef#ir_ConstantDef{type=EO_Value#ir_IDLType.type,
- type_def = EO_Value},
- set_object(New_ConstantDef).
-
-'_get_value'({ObjType, ObjID}) ?tcheck(ir_ConstantDef, ObjType) ->
- get_field({ObjType,ObjID},value).
-
-'_set_value'({ObjType, ObjID}, EO_Value) ?tcheck(ir_ConstantDef, ObjType) ->
- Typecode = get_field({ObjType,ObjID},type),
- {Value_typecode, _} = EO_Value,
- case Value_typecode == Typecode of
- true ->
- set_field({ObjType, ObjID}, value, EO_Value);
- false ->
- orber:dbg("[~p] ~p:destroy(~p, ~p, ~p);~n"
- "Wrong typecode in set_value.~n",
- [?LINE, ?MODULE, ObjType, ObjID, EO_Value], ?DEBUG_LEVEL),
- corba:raise(#'INTF_REPOS'{completion_status=?COMPLETED_NO})
- end.
diff --git a/lib/orber/src/orber_ifr_contained.erl b/lib/orber/src/orber_ifr_contained.erl
deleted file mode 100644
index 2a67fa98fd..0000000000
--- a/lib/orber/src/orber_ifr_contained.erl
+++ /dev/null
@@ -1,248 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_ifr_contained.erl
-%% Purpose : Code for Contained
-%%----------------------------------------------------------------------
-
--module(orber_ifr_contained).
-
--export(['_get_def_kind'/1,
- destroy/1,
- cleanup_for_destroy/1, %not in CORBA 2.0
- '_get_id'/1,
- '_set_id'/2,
- '_get_name'/1,
- '_set_name'/2,
- '_get_version'/1,
- '_set_version'/2,
- '_get_defined_in'/1,
- '_get_absolute_name'/1,
- '_get_containing_repository'/1,
- describe/1,
- describe/2, %not in CORBA 2.0
- move/4
- ]).
-
--import(orber_ifr_utils,[get_object/1,
- get_field/2,
- set_field/3,
- construct/3,
- select/2,
- write_result/1,
- ifr_transaction_read_write/1
- ]).
-
--include("orber_ifr.hrl").
--include("ifr_objects.hrl").
--include_lib("orber/include/ifr_types.hrl").
--include_lib("orber/include/corba.hrl").
-
-%%%======================================================================
-%%% Contained (IRObject)
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IRObject
-
-'_get_def_kind'({ObjType,ObjID}) ->
- orber_ifr_irobject:'_get_def_kind'({ObjType,ObjID}).
-
-%%% Note, that the destroy function is meant to be called within a
-%%% transaction called in the destroy function of an object which
-%%% inherits from Contained. A Contained should only be destroyed by
-%%% destroying the object that inherits from a Contained. An attempt
-%%% to call this function in user code will result in unpredictable
-%%% results.
-
-%%% Don't type check the object reference. We need to be able to
-%%% handle several types of objects that inherit from Contained.
-
-destroy(Contained_objref) ->
- ObjList = cleanup_for_destroy(Contained_objref),
- orber_ifr_irobject:destroy([Contained_objref | ObjList]).
-
-cleanup_for_destroy(Contained_objref) ->
- Defined_in = '_get_defined_in'(Contained_objref),
- [Container_obj] = mnesia:read(Defined_in),
- New_container_obj =
- construct(Container_obj,contents,
- lists:filter(fun(X) -> X /= Contained_objref end,
- select(Container_obj,contents))),
- [fun() -> mnesia:write(New_container_obj) end].
-
-%%%----------------------------------------------------------------------
-%%% Non-inherited interfaces
-
-'_get_id'({ObjType,ObjID}) ->
- get_field({ObjType,ObjID},id).
-
-'_set_id'({ObjType,ObjID}, EO_Value) ->
- set_field({ObjType, ObjID}, id, EO_Value).
-
-'_get_name'({ObjType,ObjID}) ->
- get_field({ObjType,ObjID},name).
-
-'_set_name'({ObjType,ObjID}, EO_Value) ->
- set_field({ObjType, ObjID}, name, EO_Value).
-
-'_get_version'({ObjType,ObjID}) ->
- get_field({ObjType,ObjID},version).
-
-'_set_version'({ObjType,ObjID}, EO_Value) ->
- set_field({ObjType, ObjID}, version, EO_Value).
-
-'_get_defined_in'({ObjType,ObjID}) ->
- get_field({ObjType,ObjID},defined_in).
-
-'_get_absolute_name'({ObjType,ObjID}) ->
- get_field({ObjType,ObjID},absolute_name).
-
-'_get_containing_repository'({ObjType,ObjID}) ->
- get_field({ObjType,ObjID},containing_repository).
-
-describe(ObjRef) ->
- Def_kind = '_get_def_kind'(ObjRef),
- Object = get_object(ObjRef),
- describe(Object,Def_kind).
-
-describe(Object,Def_kind) ->
- Value =
- case Def_kind of
- dk_Module ->
- #moduledescription{name = Object#ir_ModuleDef.name,
- id = Object#ir_ModuleDef.id,
- defined_in = Object#ir_ModuleDef.defined_in,
- version = Object#ir_ModuleDef.version};
- dk_Constant ->
- #constantdescription{name = Object#ir_ConstantDef.name,
- id = Object#ir_ConstantDef.id,
- defined_in =
- Object#ir_ConstantDef.defined_in,
- version = Object#ir_ConstantDef.version,
- type = Object#ir_ConstantDef.type,
- value = Object#ir_ConstantDef.value};
- dk_Typedef ->
- #typedescription{name = Object#ir_TypedefDef.name,
- id = Object#ir_TypedefDef.id,
- defined_in = Object#ir_TypedefDef.defined_in,
- version = Object#ir_TypedefDef.version,
- type = Object#ir_TypedefDef.type};
- dk_Struct ->
- ?make_typedescription(Object,ir_StructDef);
- dk_Union ->
- ?make_typedescription(Object,ir_UnionDef);
- dk_Enum ->
- ?make_typedescription(Object,ir_EnumDef);
- dk_Alias ->
- ?make_typedescription(Object,ir_AliasDef);
- dk_Exception ->
- #exceptiondescription{name = Object#ir_ExceptionDef.name,
- id = Object#ir_ExceptionDef.id,
- defined_in =
- Object#ir_ExceptionDef.defined_in,
- version = Object#ir_ExceptionDef.version,
- type = Object#ir_ExceptionDef.type};
- dk_Attribute ->
- #attributedescription{name = Object#ir_AttributeDef.name,
- id = Object#ir_AttributeDef.id,
- defined_in =
- Object#ir_AttributeDef.defined_in,
- version = Object#ir_AttributeDef.version,
- type = Object#ir_AttributeDef.type,
- mode = Object#ir_AttributeDef.mode};
- dk_Operation ->
- #operationdescription{name = Object#ir_OperationDef.name,
- id = Object#ir_OperationDef.id,
- defined_in =
- Object#ir_OperationDef.defined_in,
- version = Object#ir_OperationDef.version,
- result = Object#ir_OperationDef.result,
- mode = Object#ir_OperationDef.mode,
- contexts =
- Object#ir_OperationDef.contexts,
- parameters =
- Object#ir_OperationDef.params,
- exceptions =
- Object#ir_OperationDef.exceptions};
- dk_Interface ->
- #interfacedescription{name = Object#ir_InterfaceDef.name,
- id = Object#ir_InterfaceDef.id,
- defined_in =
- Object#ir_InterfaceDef.defined_in,
- version = Object#ir_InterfaceDef.version,
- base_interfaces =
- Object#ir_InterfaceDef.base_interfaces};
- _ ->
- undefined
- end,
- #contained_description{kind=Def_kind, value=Value}.
-
-move({ObjType,ObjID},{NewContainerType,NewContainerID},New_name,New_version) ->
- Move_OK =
- ('_get_containing_repository'({NewContainerType,NewContainerID}) ==
- '_get_containing_repository'({ObjType,ObjID}))
- and
- case NewContainerType of
- ir_Repository ->
- lists:member(ObjType,[ir_ConstantDef,ir_TypedefDef,
- ir_ExceptionDef,ir_InterfaceDef,
- ir_ModuleDef]);
- ir_ModuleDef ->
- lists:member(ObjType,[ir_ConstantDef,ir_TypedefDef,
- ir_ExceptionDef,ir_ModuleDef,
- ir_InterfaceDef]);
- ir_InterfaceDef ->
- lists:member(ObjType,[ir_ConstantDef,ir_TypedefDef,
- ir_ExceptionDef,ir_AttributeDef,
- ir_OperationDef]);
- _ ->
- false
- end
- and
- (orber_ifr_container:lookup_name({NewContainerType,NewContainerID},
- New_name, -1, % *** -1?
- dk_All, false) == []),
- move(Move_OK,{ObjType,ObjID},{NewContainerType,NewContainerID},New_name,
- New_version).
-
-move(true, Contained_objref, New_container, New_name, New_version) ->
- F = fun() -> Defined_in = '_get_defined_in'(Contained_objref),
- [Old_container_obj] = mnesia:read(Defined_in),
- New_old_container_obj =
- construct(Old_container_obj,contents,
- lists:filter(fun(X) -> X /= Contained_objref
- end, select(Old_container_obj,
- contents))),
- [New_container_obj] = mnesia:read(New_container),
- Contents = orber_ifr_container:contents(New_container, dk_All,
- true),
- New_new_container_obj =
- construct(construct(construct(New_container_obj, contents,
- [Contained_objref | Contents]),
- name,New_name),version,New_version),
- mnesia:write(New_old_container_obj),
- mnesia:write(New_new_container_obj)
- end,
- write_result(ifr_transaction_read_write(F));
-
-move(false, _Contained_objref, _New_container, _New_name, _New_version) ->
- corba:raise(#'INTF_REPOS'{completion_status=?COMPLETED_NO}).
diff --git a/lib/orber/src/orber_ifr_container.erl b/lib/orber/src/orber_ifr_container.erl
deleted file mode 100644
index e085985bc4..0000000000
--- a/lib/orber/src/orber_ifr_container.erl
+++ /dev/null
@@ -1,464 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_ifr_container.erl
-%% Purpose : Code for Container
-%%----------------------------------------------------------------------
-
--module(orber_ifr_container).
-
--export(['_get_def_kind'/1,
- destroy/1,
- cleanup_for_destroy/1, %not in CORBA 2.0
- lookup/2,
- contents/3,
- lookup_name/5,
- describe_contents/4,
- make_absolute_name/2, %not in CORBA 2.0
- make_containing_repository/1, %not in CORBA 2.0
- add_to_container/5, %not in CORBA 2.0
- create_module/4,
- create_constant/6,
- create_struct/5,
- create_union/6,
- create_enum/5,
- create_alias/5,
- create_interface/5,
- create_exception/5
- ]).
-
--import(orber_ifr_utils,[get_field/2,select/2,construct/3,makeref/1,unique/0]).
--import(lists,[map/2,filter/2,flatten/1,sublist/2]).
-
--include_lib("orber/include/corba.hrl").
--include("orber_ifr.hrl").
--include("ifr_objects.hrl").
--include_lib("orber/include/ifr_types.hrl").
-
-%%%======================================================================
-%%% Container (IRObject)
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IRObject
-
-'_get_def_kind'(ObjRef) ->
- orber_ifr_irobject:'_get_def_kind'(ObjRef).
-
-%%% Note, that the destroy function is meant to be called within a
-%%% transaction called in the destroy function of an object which
-%%% inherits from Container. A Container should only be destroyed by
-%%% destroying the object that inherits from a Container. An attempt
-%%% to call this function in user code will result in unpredictable
-%%% results.
-
-%%% Don't type check the object reference. We need to be able to handle several
-%%% types of objects that inherit from Container.
-
-destroy(Container_objref) ->
- ObjList = cleanup_for_destroy(Container_objref),
- orber_ifr_irobject:destroy([Container_objref | ObjList]).
-
-cleanup_for_destroy(Container_objref) ->
- Contents = get_field(Container_objref, contents),
- map(fun destroy_thing/1, Contents) ++ Contents.
-
-%%% Destroy objects which inherit from Contained, i.e. objects that populate
-%%% the contents list of a Container.
-
-destroy_thing({ObjType,ObjID}) when ObjType == ir_ModuleDef ->
- orber_ifr_moduledef:cleanup_for_destroy({ObjType,ObjID});
-destroy_thing({ObjType,ObjID}) when ObjType == ir_ConstantDef ->
- orber_ifr_constantdef:cleanup_for_destroy({ObjType,ObjID});
-destroy_thing({ObjType,ObjID}) when ObjType == ir_TypedefDef ->
- orber_ifr_typedef:cleanup_for_destroy({ObjType,ObjID});
-destroy_thing({ObjType,ObjID}) when ObjType == ir_StructDef ->
- orber_ifr_structdef:cleanup_for_destroy({ObjType,ObjID});
-destroy_thing({ObjType,ObjID}) when ObjType == ir_UnionDef ->
- orber_ifr_uniondef:cleanup_for_destroy({ObjType,ObjID});
-destroy_thing({ObjType,ObjID}) when ObjType == ir_EnumDef ->
- orber_ifr_enumdef:cleanup_for_destroy({ObjType,ObjID});
-destroy_thing({ObjType,ObjID}) when ObjType == ir_AliasDef ->
- orber_ifr_aliasdef:cleanup_for_destroy({ObjType,ObjID});
-destroy_thing({ObjType,ObjID}) when ObjType == ir_ExceptionDef ->
- orber_ifr_exceptiondef:cleanup_for_destroy({ObjType,ObjID});
-destroy_thing({ObjType,ObjID}) when ObjType == ir_AttributeDef ->
- orber_ifr_attributedef:cleanup_for_destroy({ObjType,ObjID});
-destroy_thing({ObjType,ObjID}) when ObjType == ir_OperationDef ->
- orber_ifr_operationdef:cleanup_for_destroy({ObjType,ObjID});
-destroy_thing({ObjType,ObjID}) when ObjType == ir_InterfaceDef ->
- orber_ifr_interfacedef:cleanup_for_destroy({ObjType,ObjID});
-destroy_thing({_ObjType,_ObjID}) ->
- %% Unknown object in Container contents.
- true.
-
-%%%----------------------------------------------------------------------
-%%% Non-inherited interfaces
-lookup(ObjRef, Search_name) ->
- Contents = contents(ObjRef, dk_All, false),
-
- %% We now have the contents (a list of object references).
- %% Let's find all objects with the correct name.
-
- case filter(fun({Type,ID}) ->
- orber_ifr_contained:'_get_absolute_name'({Type,ID}) ==
- Search_name
- end,
- Contents) of
- [Obj] ->
- Obj;
- X ->
- X
- end.
-
-
-contents(ObjRef, Limit_type, Exclude_inherited) ->
- Contents =
- flatten(get_field(ObjRef, contents) ++
- inherited_contents(ObjRef,Exclude_inherited)),
- AllContents =
- Contents ++
- flatten(subcontents(Limit_type,Contents)),
- limit_contents(Limit_type,AllContents).
-
-
-subcontents(_,[]) -> [];
-subcontents(Limit_type,Contents) ->
- map(fun(ObjRef) -> contents(ObjRef,Limit_type) end, Contents).
-
-contents({ir_Repository,ObjID},Limit_type) ->
- orber_ifr_repository:contents({ir_Repository,ObjID},Limit_type,false);
-contents({ir_ModuleDef,ObjID},Limit_type) ->
- orber_ifr_moduledef:contents({ir_ModuleDef,ObjID},Limit_type,false);
-contents({ir_InterfaceDef,ObjID},Limit_type) ->
- orber_ifr_interfacedef:contents({ir_InterfaceDef,ObjID},Limit_type,false);
-contents(_,_) -> [].
-
-limit_contents(dk_All,Contents) -> Contents;
-limit_contents(Limit_type,Contents) ->
- filter(fun(Obj_Ref) -> '_get_def_kind'(Obj_Ref) == Limit_type end,
- Contents).
-
-
-lookup_name(ObjRef, Search_name, Levels_to_search,
- Limit_type, Exclude_inherited) ->
- Contents = get_field(ObjRef, contents),
- AllContents = Contents ++ inherited_contents(ObjRef, Exclude_inherited),
- lookup_name(AllContents, Search_name, Levels_to_search, Limit_type).
-
-inherited_contents({ir_InterfaceDef,ObjID}, false) ->
- map(fun(ObjRef) -> get_field(ObjRef,contents) end,
- orber_ifr_interfacedef:'_get_base_interfaces'({ir_InterfaceDef,ObjID}));
-inherited_contents(_, false) -> [];
-inherited_contents(_, true) -> [].
-
-lookup_name(Contents, Search_name, Level, Limit_type) ->
- filter(fun(X) ->
- (orber_ifr_contained:'_get_id'(X) == Search_name)
- and
- ('_get_def_kind'(X) == Limit_type)
- end, Contents) ++
- sublookup_name(Contents, Search_name, Level - 1, Limit_type).
-
-sublookup_name([],_,_,_) -> [];
-sublookup_name(_,_,0,_) -> [];
-sublookup_name(Contents, Search_name, Level, Limit_type) ->
- map(fun(X) ->
- Conts = subcontents(X),
- lookup_name(Conts, Search_name, Level - 1, Limit_type)
- end, Contents).
-
-subcontents({ir_Repository,ObjID}) ->
- get_field({ir_Repository,ObjID}, contents);
-subcontents({ir_ModuleDefObjType,ObjID}) ->
- get_field({ir_ModuleDef,ObjID}, contents);
-subcontents({ir_InterfaceDef,ObjID}) ->
- get_field({ir_InterfaceDef,ObjID}, contents);
-subcontents(_) -> [].
-
-describe_contents(ObjRef, Limit_type, Exclude_inherited,
- Max_returned_objs) ->
- Limited_contents = contents(ObjRef,Limit_type,Exclude_inherited),
- describe_contents(Limited_contents, Max_returned_objs, []).
-
-describe_contents(_, 0, Acc) ->
- Acc;
-describe_contents([], _Max_returned_objs, Acc) ->
- Acc;
-describe_contents([H|T], Max_returned_objs, Acc) ->
- Desc = orber_ifr_contained:describe(H),
- describe_contents(T, Max_returned_objs-1, [Desc|Acc]).
-
-
-%% This is a kludge. Se p. 6-11 in CORBA 2.0.
-make_absolute_name({ObjType,ObjID}, Name) ->
- case ObjType of
- ir_Repository ->
- "::" ++ Name;
- _ ->
- orber_ifr_contained:'_get_absolute_name'({ObjType,ObjID}) ++
- "::" ++ Name
- end.
-
-%% This is a kludge. Se p. 6-15 in CORBA 2.0.
-make_containing_repository({ObjType,ObjID}) ->
- case ObjType of
- ir_Repository ->
- {ir_Repository,ObjID};
- _ ->
- orber_ifr_contained:'_get_containing_repository'({ObjType, ObjID})
- end.
-
-add_to_container(ContainerRef,Object, Id, Table, Index) ->
- F = fun() ->
- [Container_obj] = mnesia:wread(ContainerRef),
- case mnesia:index_read(Table, Id, Index) of
- [] ->
- ObjectRef = makeref(Object),
- New_container_obj =
- construct(Container_obj,contents,
- [ObjectRef | select(Container_obj,contents)]),
- mnesia:write(New_container_obj),
- mnesia:write(Object);
- _ ->
- mnesia:abort("duplicate")
- end
- end,
- case mnesia:transaction(F) of
- {aborted, "duplicate"} ->
- %% Must keep the misspelled word (must match IC generated code).
- exit({allready_registered, Id});
- {aborted, Reason} ->
- orber:dbg("[~p] orber_ifr_container:add_to_container(~p). aborted:~n~p~n",
- [?LINE, Id, Reason], ?DEBUG_LEVEL),
- corba:raise(#'INTF_REPOS'{completion_status=?COMPLETED_NO});
- {atomic, _} ->
- ok
- end.
-
-add_to_light(#orber_light_ifr_ref{data = Data} = LRef, Id, Type, Name) ->
- BaseId = get_base_id(Data#lightdata.id, Id),
- NewScope = scoped_name(Data#lightdata.scope, Name, Type),
- F = fun() ->
- D = #orber_light_ifr{id = Id,
- module = list_to_atom(NewScope),
- type = Type, base_id = BaseId},
- mnesia:write(D)
- end,
- case mnesia:transaction(F) of
- {aborted, Reason} ->
- orber:dbg("[~p] orber_ifr_container:add_to_light(~p). aborted:~n~p~n",
- [?LINE, Id, Reason], ?DEBUG_LEVEL),
- corba:raise(#'INTF_REPOS'{completion_status=?COMPLETED_NO});
- {atomic, _} ->
- LRef#orber_light_ifr_ref{data = Data#lightdata{scope = NewScope,
- id = BaseId}}
- end.
-
-get_base_id("", Id) ->
- Id;
-get_base_id(Id, _) ->
- Id.
-
-scoped_name("", Name, _) ->
- Name;
-scoped_name(Scope, _, ?IFR_ConstantDef) ->
- Scope;
-scoped_name(Scope, Name, _) ->
- Scope ++ "_" ++ Name.
-
-create_module(#orber_light_ifr_ref{} = LRef, Id, Name, _Version) ->
- add_to_light(LRef, Id, ?IFR_ModuleDef, Name);
-create_module(ObjRef, Id, Name, Version) ->
- New_module = #ir_ModuleDef{ir_Internal_ID = unique(),
- def_kind = dk_Module,
- contents = [],
- id = Id,
- name = Name,
- version = Version,
- defined_in = ObjRef,
- absolute_name =
- make_absolute_name(ObjRef, Name),
- containing_repository =
- make_containing_repository(ObjRef)},
- add_to_container(ObjRef,New_module, Id, ir_ModuleDef, #ir_ModuleDef.id),
- makeref(New_module).
-
-create_constant(#orber_light_ifr_ref{} = LRef, Id, Name, _Version, _Type, _Value) ->
- add_to_light(LRef, Id, ?IFR_ConstantDef, Name);
-create_constant(ObjRef, Id, Name, Version, Type, Value) ->
- IDL_typecode = get_field(Type,type),
- {Typecode, _} = Value,
- case IDL_typecode == Typecode of
- false ->
- orber:dbg("[~p] ~p:create_constant(~p, ~p, ~p, ~p, ~p, ~p);~n"
- "Wrong type.~n",
- [?LINE, ?MODULE, ObjRef, Id, Name, Version, Type, Value],
- ?DEBUG_LEVEL),
- corba:raise(#'INTF_REPOS'{completion_status=?COMPLETED_NO});
- true ->
- New_constant = #ir_ConstantDef{ir_Internal_ID = unique(),
- def_kind = dk_Constant,
- id = Id,
- name = Name,
- version = Version,
- defined_in = ObjRef,
- absolute_name =
- make_absolute_name(ObjRef, Name),
- containing_repository =
- make_containing_repository(ObjRef),
- type = get_field(Type,type),
- type_def = Type,
- value = Value},
- add_to_container(ObjRef,New_constant,
- Id, ir_ConstantDef, #ir_ConstantDef.id),
- makeref(New_constant)
- end.
-
-create_struct(#orber_light_ifr_ref{} = LRef, Id, Name, _Version, _Members) ->
- add_to_light(LRef, Id, ?IFR_StructDef, Name);
-create_struct(ObjRef, Id, Name, Version, Members) ->
- New_struct = #ir_StructDef{ir_Internal_ID = unique(),
- def_kind = dk_Struct,
- id = Id,
- name = Name,
- version = Version,
- defined_in = ObjRef,
- absolute_name =
- make_absolute_name(ObjRef, Name),
- containing_repository =
- make_containing_repository(ObjRef),
- type = {tk_struct, Id, Name,
- map(fun(#structmember{name=MemName,
- type=Type}) ->
- {MemName,Type} end,
- Members)},
- members = Members},
- add_to_container(ObjRef, New_struct, Id, ir_StructDef, #ir_StructDef.id),
- makeref(New_struct).
-
-create_union(#orber_light_ifr_ref{} = LRef, Id, Name, _Version,
- _Discriminator_type, _Members) ->
- add_to_light(LRef, Id, ?IFR_UnionDef, Name);
-create_union(ObjRef, Id, Name, Version,
- Discriminator_type, Members) ->
- Discriminator_type_code = get_field(Discriminator_type, type),
- New_union = #ir_UnionDef{ir_Internal_ID = unique(),
- def_kind = dk_Union,
- id = Id,
- name = Name,
- version = Version,
- defined_in = ObjRef,
- absolute_name =
- make_absolute_name(ObjRef, Name),
- containing_repository =
- make_containing_repository(ObjRef),
- type = {tk_union, Id, Name,
- Discriminator_type_code, -1,
- map(fun(#unionmember{name=MemName,
- label=Label,
- type=Type}) ->
- {Label,MemName,Type} end,
- Members)},
- discriminator_type = Discriminator_type_code,
- discriminator_type_def = Discriminator_type,
- members = Members},
- add_to_container(ObjRef, New_union, Id, ir_UnionDef, #ir_UnionDef.id),
- makeref(New_union).
-
-create_enum(#orber_light_ifr_ref{} = LRef, Id, Name, _Version, _Members) ->
- add_to_light(LRef, Id, ?IFR_EnumDef, Name);
-create_enum(ObjRef, Id, Name, Version, Members) ->
- New_enum = #ir_EnumDef{ir_Internal_ID = unique(),
- def_kind = dk_Enum,
- id = Id,
- name = Name,
- version = Version,
- defined_in = ObjRef,
- absolute_name =
- make_absolute_name(ObjRef, Name),
- containing_repository =
- make_containing_repository(ObjRef),
- type = {tk_enum, Id, Name, Members},
- members = Members},
- add_to_container(ObjRef, New_enum, Id, ir_EnumDef, #ir_EnumDef.id),
- makeref(New_enum).
-
-create_alias(#orber_light_ifr_ref{} = LRef, Id, Name, _Version, _Original_type) ->
- add_to_light(LRef, Id, ?IFR_AliasDef, Name);
-create_alias(ObjRef, Id, Name, Version, Original_type) ->
- New_alias = #ir_AliasDef{ir_Internal_ID = unique(),
- def_kind = dk_Alias,
- id = Id,
- name = Name,
- version = Version,
- defined_in = ObjRef,
- absolute_name =
- make_absolute_name(ObjRef, Name),
- containing_repository =
- make_containing_repository(ObjRef),
- type = {tk_alias, Id, Name,
- get_field(Original_type,type)},
- original_type_def = Original_type},
- add_to_container(ObjRef, New_alias, Id, ir_AliasDef, #ir_AliasDef.id),
- makeref(New_alias).
-
-create_interface(#orber_light_ifr_ref{} = LRef, Id, Name, _Version, _Base_interfaces) ->
- add_to_light(LRef, Id, ?IFR_InterfaceDef, Name);
-create_interface(ObjRef, Id, Name, Version, Base_interfaces) ->
- New_interface = #ir_InterfaceDef{ir_Internal_ID = unique(),
- def_kind = dk_Interface,
- contents = [],
- id = Id,
- name = Name,
- version = Version,
- defined_in = ObjRef,
- absolute_name =
- make_absolute_name(ObjRef,Name),
- containing_repository =
- make_containing_repository(ObjRef),
- type = {tk_objref, Id, Name},
- base_interfaces = Base_interfaces},
- add_to_container(ObjRef, New_interface, Id, ir_InterfaceDef, #ir_InterfaceDef.id),
- makeref(New_interface).
-
-create_exception(#orber_light_ifr_ref{} = LRef, Id, Name, _Version, _Members) ->
- add_to_light(LRef, Id, ?IFR_ExceptionDef, Name);
-create_exception(ObjRef, Id, Name, Version, Members) ->
- New_exception = #ir_ExceptionDef{ir_Internal_ID = unique(),
- def_kind = dk_Exception,
- id = Id,
- name = Name,
- version = Version,
- defined_in = ObjRef,
- absolute_name =
- make_absolute_name(ObjRef,Name),
- containing_repository =
- make_containing_repository(ObjRef),
- type = {tk_except, Id, Name,
- map(fun(#structmember{name=MemName,
- type=Type})
- ->
- {MemName,Type} end,
- Members)},
- members = Members},
- add_to_container(ObjRef, New_exception, Id, ir_ExceptionDef, #ir_ExceptionDef.id),
- makeref(New_exception).
diff --git a/lib/orber/src/orber_ifr_enumdef.erl b/lib/orber/src/orber_ifr_enumdef.erl
deleted file mode 100644
index b1820046bb..0000000000
--- a/lib/orber/src/orber_ifr_enumdef.erl
+++ /dev/null
@@ -1,130 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_ifr_enumdef.erl
-%% Purpose : Code for Enumdef
-%%----------------------------------------------------------------------
-
--module(orber_ifr_enumdef).
-
--export(['_get_def_kind'/1,
- destroy/1,
- cleanup_for_destroy/1, %not in CORBA 2.0
- '_get_id'/1,
- '_set_id'/2,
- '_get_name'/1,
- '_set_name'/2,
- '_get_version'/1,
- '_set_version'/2,
- '_get_defined_in'/1,
- '_get_absolute_name'/1,
- '_get_containing_repository'/1,
- describe/1,
- move/4,
- '_get_type'/1,
- '_get_members'/1,
- '_set_members'/2
- ]).
-
--import(orber_ifr_utils,[get_field/2,
- get_object/1,
- set_object/1
- ]).
-
--include("orber_ifr.hrl").
--include("ifr_objects.hrl").
-
-%%%======================================================================
-%%% EnumDef (TypedefDef(Contained(IRObject), IDLType(IRObject)))
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IRObject
-
-'_get_def_kind'({ObjType, ObjID}) ?tcheck(ir_EnumDef, ObjType) ->
- orber_ifr_irobject:'_get_def_kind'({ObjType,ObjID}).
-
-destroy({ObjType, ObjID}) ?tcheck(ir_EnumDef, ObjType) ->
- F = fun() -> ObjList = cleanup_for_destroy({ObjType, ObjID}),
- orber_ifr_irobject:destroy([{ObjType, ObjID} | ObjList])
- end,
- orber_ifr_utils:ifr_transaction_write(F).
-
-cleanup_for_destroy({ObjType,ObjID}) ?tcheck(ir_EnumDef, ObjType) ->
- orber_ifr_typedef:cleanup_for_destroy({ObjType,ObjID}).
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from Contained
-
-'_get_id'({ObjType, ObjID}) ?tcheck(ir_EnumDef, ObjType) ->
- orber_ifr_contained:'_get_id'({ObjType,ObjID}).
-
-'_set_id'({ObjType, ObjID}, EO_Value) ?tcheck(ir_EnumDef, ObjType) ->
- orber_ifr_contained:'_set_id'({ObjType,ObjID},EO_Value).
-
-'_get_name'({ObjType, ObjID}) ?tcheck(ir_EnumDef, ObjType) ->
- orber_ifr_contained:'_get_name'({ObjType,ObjID}).
-
-'_set_name'({ObjType, ObjID}, EO_Value) ?tcheck(ir_EnumDef, ObjType) ->
- orber_ifr_contained:'_set_name'({ObjType,ObjID}, EO_Value).
-
-'_get_version'({ObjType, ObjID}) ?tcheck(ir_EnumDef, ObjType) ->
- orber_ifr_contained:'_get_version'({ObjType,ObjID}).
-
-'_set_version'({ObjType, ObjID}, EO_Value) ?tcheck(ir_EnumDef, ObjType) ->
- orber_ifr_contained:'_set_version'({ObjType,ObjID},EO_Value).
-
-'_get_defined_in'({ObjType, ObjID}) ?tcheck(ir_EnumDef, ObjType) ->
- orber_ifr_contained:'_get_defined_in'({ObjType,ObjID}).
-
-'_get_absolute_name'({ObjType, ObjID}) ?tcheck(ir_EnumDef, ObjType) ->
- orber_ifr_contained:'_get_absolute_name'({ObjType,ObjID}).
-
-'_get_containing_repository'({ObjType, ObjID}) ?tcheck(ir_EnumDef, ObjType) ->
- orber_ifr_contained:'_get_containing_repository'({ObjType,ObjID}).
-
-describe({ObjType, ObjID}) ?tcheck(ir_EnumDef, ObjType) ->
- orber_ifr_contained:describe({ObjType,ObjID}).
-
-move({ObjType, ObjID}, New_container, New_name, New_version)
- ?tcheck(ir_EnumDef, ObjType) ->
- orber_ifr_contained:move({ObjType,ObjID},New_container,New_name,New_version).
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IDLType
-
-'_get_type'({ObjType, ObjID}) ?tcheck(ir_EnumDef, ObjType) ->
- orber_ifr_idltype:'_get_type'({ObjType, ObjID}).
-
-%%%----------------------------------------------------------------------
-%%% Non-inherited interfaces
-
-'_get_members'({ObjType, ObjID}) ?tcheck(ir_EnumDef, ObjType) ->
- get_field({ObjType,ObjID},members).
-
-'_set_members'({ObjType, ObjID}, EO_Value) ?tcheck(ir_EnumDef, ObjType) ->
- EnumDef = get_object({ObjType, ObjID}),
- New_EnumDef = EnumDef#ir_EnumDef{type = {tk_enum,
- EnumDef#ir_EnumDef.id,
- EnumDef#ir_EnumDef.name,
- EO_Value},
- members = EO_Value},
- set_object(New_EnumDef).
diff --git a/lib/orber/src/orber_ifr_exceptiondef.erl b/lib/orber/src/orber_ifr_exceptiondef.erl
deleted file mode 100644
index a9e477f01a..0000000000
--- a/lib/orber/src/orber_ifr_exceptiondef.erl
+++ /dev/null
@@ -1,145 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_ifr_exceptiondef.erl
-%% Purpose : Code for Exceptiondef
-%%----------------------------------------------------------------------
-
--module(orber_ifr_exceptiondef).
-
--export(['_get_def_kind'/1,
- destroy/1,
- cleanup_for_destroy/1, %not in CORBA 2.0
- '_get_id'/1,
- '_set_id'/2,
- '_get_name'/1,
- '_set_name'/2,
- '_get_version'/1,
- '_set_version'/2,
- '_get_defined_in'/1,
- '_get_absolute_name'/1,
- '_get_containing_repository'/1,
- describe/1,
- %%lookup_id/1, %not in CORBA 2.0
- move/4,
- '_get_type'/1,
- '_get_members'/1,
- '_set_members'/2
- ]).
-
--import(orber_ifr_utils,[get_field/2,
- get_object/1,
- set_object/1
- ]).
--import(lists,[map/2]).
-
--include("orber_ifr.hrl").
--include("ifr_objects.hrl").
--include_lib("orber/include/ifr_types.hrl").
-
-%%%======================================================================
-%%% ExceptionDef (Contained(IRObject))
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IRObject
-
-'_get_def_kind'({ObjType, ObjID}) ?tcheck(ir_ExceptionDef, ObjType) ->
- orber_ifr_irobject:'_get_def_kind'({ObjType,ObjID}).
-
-destroy({ObjType, ObjID}) ?tcheck(ir_ExceptionDef, ObjType) ->
- F = fun() -> ObjList = cleanup_for_destroy({ObjType, ObjID}),
- orber_ifr_irobject:destroy([{ObjType,ObjID} | ObjList])
- end,
- orber_ifr_utils:ifr_transaction_write(F).
-
-cleanup_for_destroy({ObjType,ObjID}) ?tcheck(ir_ExceptionDef, ObjType) ->
- lists:map(fun(X) -> orber_ifr_idltype:cleanup_for_destroy(
- X#structmember.type_def)
- end,
- '_get_members'({ObjType, ObjID})) ++
- orber_ifr_contained:cleanup_for_destroy({ObjType,ObjID}).
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from Contained
-
-'_get_id'({ObjType, ObjID}) ?tcheck(ir_ExceptionDef, ObjType) ->
- orber_ifr_contained:'_get_id'({ObjType,ObjID}).
-
-'_set_id'({ObjType, ObjID}, EO_Value) ?tcheck(ir_ExceptionDef, ObjType) ->
- orber_ifr_contained:'_set_id'({ObjType,ObjID},EO_Value).
-
-'_get_name'({ObjType, ObjID}) ?tcheck(ir_ExceptionDef, ObjType) ->
- orber_ifr_contained:'_get_name'({ObjType,ObjID}).
-
-'_set_name'({ObjType, ObjID}, EO_Value) ?tcheck(ir_ExceptionDef, ObjType) ->
- orber_ifr_contained:'_set_name'({ObjType,ObjID}, EO_Value).
-
-'_get_version'({ObjType, ObjID}) ?tcheck(ir_ExceptionDef, ObjType) ->
- orber_ifr_contained:'_get_version'({ObjType,ObjID}).
-
-'_set_version'({ObjType, ObjID}, EO_Value) ?tcheck(ir_ExceptionDef, ObjType) ->
- orber_ifr_contained:'_set_version'({ObjType,ObjID},EO_Value).
-
-'_get_defined_in'({ObjType, ObjID}) ?tcheck(ir_ExceptionDef, ObjType) ->
- orber_ifr_contained:'_get_defined_in'({ObjType,ObjID}).
-
-'_get_absolute_name'({ObjType, ObjID}) ?tcheck(ir_ExceptionDef, ObjType) ->
- orber_ifr_contained:'_get_absolute_name'({ObjType,ObjID}).
-
-'_get_containing_repository'({ObjType, ObjID})
- ?tcheck(ir_ExceptionDef, ObjType) ->
- orber_ifr_contained:'_get_containing_repository'({ObjType,ObjID}).
-
-describe({ObjType, ObjID}) ?tcheck(ir_ExceptionDef, ObjType) ->
- orber_ifr_contained:describe({ObjType,ObjID}).
-
-move({ObjType, ObjID}, New_container, New_name, New_version)
- ?tcheck(ir_ExceptionDef, ObjType) ->
- orber_ifr_contained:move({ObjType,ObjID},New_container,New_name,
- New_version).
-
-%%%----------------------------------------------------------------------
-%%% Non-inherited interfaces
-
-'_get_type'({ObjType, ObjID}) ?tcheck(ir_ExceptionDef, ObjType) ->
- get_field({ObjType,ObjID},type).
-
-'_get_members'({ObjType, ObjID}) ?tcheck(ir_ExceptionDef, ObjType) ->
- get_field({ObjType,ObjID},members).
-
-'_set_members'({ObjType, ObjID}, EO_Value) ?tcheck(ir_ExceptionDef, ObjType) ->
- ExceptionDef = get_object({ObjType, ObjID}),
- Members=map(fun(Exceptionmember) ->
- Exceptionmember#structmember{type=tk_void}
- end, EO_Value),
- New_ExceptionDef =
- ExceptionDef#ir_ExceptionDef{type =
- {tk_except,
- ExceptionDef#ir_ExceptionDef.id,
- ExceptionDef#ir_ExceptionDef.name,
- map(fun(#structmember{name=Name,
- type=Type}) ->
- {Name,Type}
- end,
- EO_Value)},
- members=Members},
- set_object(New_ExceptionDef).
diff --git a/lib/orber/src/orber_ifr_fixeddef.erl b/lib/orber/src/orber_ifr_fixeddef.erl
deleted file mode 100644
index fc1b354af0..0000000000
--- a/lib/orber/src/orber_ifr_fixeddef.erl
+++ /dev/null
@@ -1,80 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_ifr_fixeddef.erl
-%% Description :
-%%
-%%----------------------------------------------------------------------
--module(orber_ifr_fixeddef).
-
--export(['_get_def_kind'/1,
- destroy/1,
- cleanup_for_destroy/1, %not in CORBA 2.0
- '_get_type'/1,
- '_get_digits'/1,
- '_set_digits'/2,
- '_get_scale'/1,
- '_set_scale'/2]).
-
--import(orber_ifr_utils, [get_field/2,
- set_field/3]).
-
--include("orber_ifr.hrl").
-
-%%%======================================================================
-%%% FixedDef (IDLType(IRObject))
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IRObject
-
-'_get_def_kind'({ObjType,ObjID}) ?tcheck(ir_FixedDef, ObjType) ->
- orber_ifr_irobject:'_get_def_kind'({ObjType,ObjID}).
-
-destroy({ObjType, ObjID}) ?tcheck(ir_FixedDef, ObjType) ->
- F = fun() -> ObjList = cleanup_for_destroy({ObjType, ObjID}),
- orber_ifr_irobject:destroy([{ObjType,ObjID} | ObjList])
- end,
- orber_ifr_utils:ifr_transaction_write(F).
-
-cleanup_for_destroy({ObjType,ObjID}) ?tcheck(ir_FixedDef, ObjType) ->
- orber_ifr_idltype:cleanup_for_destroy({ObjType,ObjID}).
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IDLType
-
-'_get_type'({ObjType, ObjID}) ?tcheck(ir_FixedDef, ObjType) ->
- orber_ifr_idltype:'_get_type'({ObjType, ObjID}).
-
-%%%----------------------------------------------------------------------
-%%% Non-inherited interfaces
-
-'_get_digits'({ObjType, ObjID}) ?tcheck(ir_FixedDef, ObjType) ->
- get_field({ObjType,ObjID},digits).
-'_get_scale'({ObjType, ObjID}) ?tcheck(ir_FixedDef, ObjType) ->
- get_field({ObjType,ObjID},scale).
-
-'_set_digits'({ObjType, ObjID}, EO_Value)
- ?tcheck(ir_FixedDef, ObjType) ->
- set_field({ObjType, ObjID}, digits, EO_Value).
-'_set_scale'({ObjType, ObjID}, EO_Value)
- ?tcheck(ir_FixedDef, ObjType) ->
- set_field({ObjType, ObjID}, scale, EO_Value).
diff --git a/lib/orber/src/orber_ifr_idltype.erl b/lib/orber/src/orber_ifr_idltype.erl
deleted file mode 100644
index 44ab86c41a..0000000000
--- a/lib/orber/src/orber_ifr_idltype.erl
+++ /dev/null
@@ -1,75 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_ifr_idltype.erl
-%% Purpose : Code for Idltype
-%%----------------------------------------------------------------------
-
--module(orber_ifr_idltype).
-
--export(['_get_def_kind'/1,
- destroy/1,
- cleanup_for_destroy/1, %not in CORBA 2.0
- '_get_type'/1,
- '_get_type_def'/1
- ]).
-
--import(orber_ifr_utils,[get_field/2]).
-
--include("orber_ifr.hrl").
--include("ifr_objects.hrl").
-
-%%%======================================================================
-%%% IDLType (IRObject)
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IRObject
-
-'_get_def_kind'({ObjType, ObjID}) ?tcheck(ir_IDLType, ObjType) ->
- orber_ifr_irobject:'_get_def_kind'({ObjType, ObjID}).
-
-%%% Don't type check the object reference. We need to be able to
-%%% handle several types of objects that inherit from IDLType.
-
-destroy(IDLType_objref) ->
- F = fun() -> ObjList = cleanup_for_destroy(IDLType_objref),
- orber_ifr_irobject:destroy(ObjList)
- end,
- orber_ifr_utils:ifr_transaction_write(F).
-
-cleanup_for_destroy(IDLType_objref) ->
- [IDLType_objref].
-
-%%%----------------------------------------------------------------------
-%%% Non-inherited interfaces
-
-%% What is this ? You cannot check this for ir_IDLType here !
-%% ( an object type cannot be both .... )
-%%'_get_type'({ObjType,ObjID}) ?tcheck(ir_IDLType, ObjType) ->
-%% get_field({ObjType,ObjID},type).
-
-
-'_get_type'({ObjType,ObjID}) ->
- get_field({ObjType,ObjID},type).
-
-'_get_type_def'({ObjType,ObjID}) ->
- get_field({ObjType,ObjID},type_def).
diff --git a/lib/orber/src/orber_ifr_interfacedef.erl b/lib/orber/src/orber_ifr_interfacedef.erl
deleted file mode 100644
index 1195f1eff6..0000000000
--- a/lib/orber/src/orber_ifr_interfacedef.erl
+++ /dev/null
@@ -1,340 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_ifr_interfacedef.erl
-%% Purpose : Code for Interfacedef
-%%----------------------------------------------------------------------
-
--module(orber_ifr_interfacedef).
-
--export(['_get_def_kind'/1,
- destroy/1,
- cleanup_for_destroy/1, %not in CORBA 2.0
- lookup/2,
- contents/3,
- lookup_name/5,
- describe_contents/4,
- create_module/4,
- create_constant/6,
- create_struct/5,
- create_union/6,
- create_enum/5,
- create_alias/5,
- create_interface/5,
- create_exception/5,
- '_get_id'/1,
- '_set_id'/2,
- '_get_name'/1,
- '_set_name'/2,
- '_get_version'/1,
- '_set_version'/2,
- '_get_defined_in'/1,
- '_get_absolute_name'/1,
- '_get_containing_repository'/1,
- describe/1,
- move/4,
- '_get_type'/1,
- '_get_base_interfaces'/1,
- '_set_base_interfaces'/2,
- is_a/2,
- describe_interface/1,
- create_attribute/6,
- create_operation/9
- ]).
-
--import(orber_ifr_utils,[get_object/1,
- get_field/2,
- set_field/3,
- select/2,
- makeref/1,
- unique/0
- ]).
--import(orber_ifr_container,[make_absolute_name/2,
- make_containing_repository/1
- ]).
-
--include("orber_ifr.hrl").
--include("ifr_objects.hrl").
--include_lib("orber/include/ifr_types.hrl").
-
-
-%%%======================================================================
-%%% InterfaceDef (Container(IRObject), Contained(IRObject), IDLType(IRObject))
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IRObject
-
-'_get_def_kind'({ObjType, ObjID}) ?tcheck(ir_InterfaceDef, ObjType) ->
- orber_ifr_irobject:'_get_def_kind'({ObjType,ObjID}).
-
-destroy({ObjType, ObjID}) ?tcheck(ir_InterfaceDef, ObjType) ->
- F = fun() -> ObjList = cleanup_for_destroy({ObjType,ObjID}),
- orber_ifr_irobject:destroy([{ObjType,ObjID} | ObjList])
- end,
- orber_ifr_utils:ifr_transaction_write(F).
-
-cleanup_for_destroy({ObjType,ObjID}) ?tcheck(ir_InterfaceDef, ObjType) ->
- orber_ifr_contained:cleanup_for_destroy({ObjType,ObjID}) ++
- orber_ifr_container:cleanup_for_destroy({ObjType,ObjID}) ++
- orber_ifr_idltype:cleanup_for_destroy({ObjType,ObjID}).
-
-
-%% BUG ! You can't remove inherited !!!!!
-%%cleanup_for_destroy({ObjType,ObjID}) ?tcheck(ir_InterfaceDef, ObjType) ->
-%% lists:map(fun(X) -> cleanup_for_destroy(X) end,
-%% '_get_base_interfaces'({ObjType,ObjID})) ++ <<<<<<<<<< Here
-%% orber_ifr_contained:cleanup_for_destroy({ObjType,ObjID}) ++
-%% orber_ifr_container:cleanup_for_destroy({ObjType,ObjID}) ++
-%% orber_ifr_idltype:cleanup_for_destroy({ObjType,ObjID}).
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from Container
-
-lookup({ObjType, ObjID}, Search_name) ?tcheck(ir_InterfaceDef, ObjType) ->
- orber_ifr_container:lookup({ObjType,ObjID}, Search_name).
-
-contents({ObjType, ObjID}, Limit_type, Exclude_inherited)
- ?tcheck(ir_InterfaceDef, ObjType) ->
- orber_ifr_container:contents({ObjType,ObjID},Limit_type,Exclude_inherited).
-
-lookup_name({ObjType, ObjID}, Search_name, Levels_to_search, Limit_type,
- Exclude_inherited) ?tcheck(ir_InterfaceDef, ObjType) ->
- orber_ifr_container:lookup_name({ObjType,ObjID}, Search_name,
- Levels_to_search, Limit_type,
- Exclude_inherited).
-
-describe_contents({ObjType, ObjID}, Limit_type, Exclude_inherited,
- Max_returned_objs) ?tcheck(ir_InterfaceDef, ObjType) ->
- orber_ifr_container:describe_contents({ObjType,ObjID}, Limit_type,
- Exclude_inherited,
- Max_returned_objs).
-
-create_module({ObjType, ObjID}, Id, Name, Version)
- ?tcheck(ir_InterfaceDef, ObjType) ->
- orber_ifr_container:create_module({ObjType, ObjID}, Id, Name, Version).
-
-create_constant({ObjType, ObjID}, Id, Name, Version, Type, Value)
- ?tcheck(ir_InterfaceDef, ObjType) ->
- orber_ifr_container:create_constant({ObjType, ObjID}, Id, Name, Version,
- Type, Value).
-
-create_struct({ObjType, ObjID}, Id, Name, Version, Members)
- ?tcheck(ir_InterfaceDef, ObjType) ->
- orber_ifr_container:create_struct({ObjType,ObjID},Id,Name,Version,Members).
-
-create_union({ObjType, ObjID}, Id, Name, Version, Discriminator_type, Members)
- ?tcheck(ir_InterfaceDef, ObjType) ->
- orber_ifr_container:create_union({ObjType, ObjID}, Id, Name, Version,
- Discriminator_type, Members).
-
-create_enum({ObjType, ObjID}, Id, Name, Version, Members)
- ?tcheck(ir_InterfaceDef, ObjType) ->
- orber_ifr_container:create_enum({ObjType, ObjID},Id,Name,Version,Members).
-
-create_alias({ObjType, ObjID}, Id, Name, Version, Original_type)
- ?tcheck(ir_InterfaceDef, ObjType) ->
- orber_ifr_container:create_alias({ObjType, ObjID}, Id, Name, Version,
- Original_type).
-
-create_interface({ObjType, ObjID}, Id, Name, Version, Base_interfaces)
- ?tcheck(ir_InterfaceDef, ObjType) ->
- orber_ifr_container:create_interface({ObjType, ObjID}, Id, Name, Version,
- Base_interfaces).
-
-create_exception({ObjType, ObjID}, Id, Name, Version, Members)
- ?tcheck(ir_InterfaceDef, ObjType) ->
- orber_ifr_container:create_exception({ObjType, ObjID}, Id, Name, Version,
- Members).
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from Contained
-
-'_get_id'({ObjType, ObjID}) ?tcheck(ir_InterfaceDef, ObjType) ->
- orber_ifr_contained:'_get_id'({ObjType,ObjID}).
-
-'_set_id'({ObjType, ObjID}, EO_Value) ?tcheck(ir_InterfaceDef, ObjType) ->
- orber_ifr_contained:'_set_id'({ObjType,ObjID},EO_Value).
-
-'_get_name'({ObjType, ObjID}) ?tcheck(ir_InterfaceDef, ObjType) ->
- orber_ifr_contained:'_get_name'({ObjType,ObjID}).
-
-'_set_name'({ObjType, ObjID}, EO_Value) ?tcheck(ir_InterfaceDef, ObjType) ->
- orber_ifr_contained:'_set_name'({ObjType,ObjID}, EO_Value).
-
-'_get_version'({ObjType, ObjID}) ?tcheck(ir_InterfaceDef, ObjType) ->
- orber_ifr_contained:'_get_version'({ObjType,ObjID}).
-
-'_set_version'({ObjType, ObjID}, EO_Value) ?tcheck(ir_InterfaceDef, ObjType) ->
- orber_ifr_contained:'_set_version'({ObjType,ObjID},EO_Value).
-
-'_get_defined_in'({ObjType, ObjID}) ?tcheck(ir_InterfaceDef, ObjType) ->
- orber_ifr_contained:'_get_defined_in'({ObjType,ObjID}).
-
-'_get_absolute_name'({ObjType, ObjID}) ?tcheck(ir_InterfaceDef, ObjType) ->
- orber_ifr_contained:'_get_absolute_name'({ObjType,ObjID}).
-
-'_get_containing_repository'({ObjType, ObjID})
- ?tcheck(ir_InterfaceDef, ObjType) ->
- orber_ifr_contained:'_get_containing_repository'({ObjType,ObjID}).
-
-describe({ObjType, ObjID}) ?tcheck(ir_InterfaceDef, ObjType) ->
- orber_ifr_contained:describe({ObjType,ObjID}).
-
-move({ObjType, ObjID}, New_container, New_name, New_version)
- ?tcheck(ir_InterfaceDef, ObjType) ->
- orber_ifr_contained:move({ObjType,ObjID},New_container,New_name,
- New_version).
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IDLType
-
-'_get_type'({ObjType, ObjID}) ?tcheck(ir_InterfaceDef, ObjType) ->
- orber_ifr_idltype:'_get_type'({ObjType, ObjID}).
-
-%%%----------------------------------------------------------------------
-%%% Non-inherited interfaces
-
-'_get_base_interfaces'({ObjType,ObjID}) ?tcheck(ir_InterfaceDef, ObjType) ->
- get_field({ObjType,ObjID},base_interfaces).
-
-'_set_base_interfaces'({ObjType, ObjID}, EO_Value)
- ?tcheck(ir_InterfaceDef, ObjType) ->
- set_field({ObjType,ObjID}, base_interfaces, EO_Value).
-
-
-
-is_a({ObjType, ObjID}, Interface_id) ?tcheck(ir_InterfaceDef, ObjType) ->
- Base_interfaces = '_get_base_interfaces'({ObjType, ObjID}),
- lists:any(fun(X) ->
- case catch orber_ifr_contained:'_get_id'(X) of
- Interface_id ->
- 'true';
- _ ->
- 'false'
- end
- end,
- Base_interfaces).
-
-describe_interface({ObjType, ObjID}) ?tcheck(ir_InterfaceDef, ObjType) ->
-
-%%% *** Should we exclude the inherited operations here? Probably not,
-%%% but I'm not sure at all.
-
-%%% OpContents = orber_ifr_container:contents({ObjType,ObjID}, dk_Operation,
-%%% true),
-
- %% If it is OK to set Exclude_inherited to true (as in the above
- %% code which is commented out), the following code is faster than
- %% calling the contents/3 above. Otherwise we have to rethink
- %% this.
-
- Object = get_object({ObjType, ObjID}),
-
-%%% Contents = select(Object, contents),
- %% This is faster:
- Contents = Object#ir_InterfaceDef.contents,
-
- ContentsObjects = lists:map(fun(ObjRef) ->
- get_object(ObjRef)
- end,
- Contents),
- OpContents = lists:filter(fun(Obj) ->
- select(Obj,def_kind) == dk_Operation
- end,
- ContentsObjects),
-
- Ops = lists:map(fun(Obj) ->
- orber_ifr_contained:describe(Obj,dk_Operation)
- end, OpContents),
-
-%%% *** See the comment above on the Exclude_inherited parameter, and
-%%% the circumstances when not to use contents/3.
-
-%%% AttrContents = orber_ifr_container:contents({ObjType,ObjID}, dk_Attribute,
-%%% true),
-
- AttrContents = lists:filter(fun(Obj) ->
- select(Obj,def_kind) == dk_Attribute
- end,
- ContentsObjects),
- Attrs = lists:map(fun(Obj) ->
- orber_ifr_contained:describe(Obj,dk_Attribute)
- end, AttrContents),
-
- #fullinterfacedescription{name = Object#ir_InterfaceDef.name,
- id = Object#ir_InterfaceDef.id,
- defined_in = Object#ir_InterfaceDef.defined_in,
- version = Object#ir_InterfaceDef.version,
- operations = Ops,
- attributes = Attrs,
- base_interfaces =
- Object#ir_InterfaceDef.base_interfaces,
- type = Object#ir_InterfaceDef.type
- }.
-
-create_attribute(#orber_light_ifr_ref{} = LRef, _Id, _Name, _Version, _Type, _Mode) ->
- LRef;
-create_attribute({ObjType, ObjID}, Id, Name, Version, Type, Mode)
- ?tcheck(ir_InterfaceDef, ObjType) ->
- New_attribute = #ir_AttributeDef{ir_Internal_ID = unique(),
- def_kind = dk_Attribute,
- id = Id,
- name = Name,
- version = Version,
- defined_in = {ObjType, ObjID},
- absolute_name =
- make_absolute_name({ObjType,ObjID}, Name),
- containing_repository =
- make_containing_repository({ObjType,ObjID}),
- type = get_field(Type,type),
- type_def = Type,
- mode = Mode},
- orber_ifr_container:add_to_container({ObjType,ObjID}, New_attribute,
- Id, ir_AttributeDef,
- #ir_AttributeDef.id),
- makeref(New_attribute).
-
-create_operation(#orber_light_ifr_ref{} = LRef, _Id, _Name, _Version, _Result,
- _Mode, _Params, _Exceptions, _Contexts) ->
- LRef;
-create_operation({ObjType, ObjID}, Id, Name, Version, Result, Mode, Params,
- Exceptions, Contexts) ?tcheck(ir_InterfaceDef, ObjType) ->
- New_operation = #ir_OperationDef{ir_Internal_ID = unique(),
- def_kind = dk_Operation,
- id = Id,
- name = Name,
- version = Version,
- defined_in = {ObjType, ObjID},
- absolute_name =
- make_absolute_name({ObjType,ObjID}, Name),
- containing_repository =
- make_containing_repository({ObjType,ObjID}),
- result = get_field(Result,type),
- result_def = Result,
- mode = Mode,
- params = Params,
- exceptions = Exceptions,
- contexts = Contexts},
- orber_ifr_container:add_to_container({ObjType,ObjID}, New_operation,
- Id, ir_OperationDef,
- #ir_OperationDef.id),
- makeref(New_operation).
diff --git a/lib/orber/src/orber_ifr_irobject.erl b/lib/orber/src/orber_ifr_irobject.erl
deleted file mode 100644
index 1111f00f81..0000000000
--- a/lib/orber/src/orber_ifr_irobject.erl
+++ /dev/null
@@ -1,73 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_ifr_irobject.erl
-%% Purpose : Code for IRObject
-%%----------------------------------------------------------------------
-
--module(orber_ifr_irobject).
-
--export(['_get_def_kind'/1,
- destroy/1
- ]).
-
--import(orber_ifr_utils,[get_field/2]).
-
--include("orber_ifr.hrl").
--include_lib("orber/include/corba.hrl").
-
-%%%======================================================================
-%%% IRObject
-
-'_get_def_kind'({ObjType,ObjID}) ->
- get_field({ObjType,ObjID},def_kind).
-
-%%% Note, that the destroy function is meant to be called within a
-%%% transaction called in the destroy function of an object which
-%%% inherits from IRObject. An IRObject should only be destroyed by
-%%% destroying the object that inherits from an IRObject. An attempt
-%%% to call this function in user code will result in unpredictable
-%%% results.
-
-%%% Don't type check the object reference. We need to be able to
-%%% handle several types of objects that inherit from IRObject.
-
-destroy(L) when is_list(L) ->
- destroy2(lists:reverse(L)).
-
-destroy2([Things_HD | Things_TL]) ->
- destroy2(Things_HD),
- destroy2(Things_TL);
-
-destroy2([]) ->
- ok;
-destroy2(F) when is_function(F) ->
- F();
-destroy2(Thing) when is_tuple(Thing) ->
- mnesia:delete(Thing),
- ok;
-destroy2(Thing) ->
- orber:dbg("[~p] ~p:destroy2(~p);~n"
- "Strange argument for destroy.~n",
- [?LINE, ?MODULE, Thing], ?DEBUG_LEVEL),
- corba:raise(#'INTF_REPOS'{completion_status=?COMPLETED_NO}).
-
diff --git a/lib/orber/src/orber_ifr_moduledef.erl b/lib/orber/src/orber_ifr_moduledef.erl
deleted file mode 100644
index add0feb31a..0000000000
--- a/lib/orber/src/orber_ifr_moduledef.erl
+++ /dev/null
@@ -1,184 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_ifr_moduledef.erl
-%% Purpose : Code for Moduledef
-%%----------------------------------------------------------------------
-
--module(orber_ifr_moduledef).
-
--export(['_get_def_kind'/1,
- destroy/1,
- cleanup_for_destroy/1, %not in CORBA 2.0
- lookup/2,
- contents/3,
- lookup_name/5,
- describe_contents/4,
- create_module/4,
- create_constant/6,
- create_struct/5,
- create_union/6,
- create_enum/5,
- create_alias/5,
- create_interface/5,
- create_exception/5,
- '_get_id'/1,
- '_set_id'/2,
- '_get_name'/1,
- '_set_name'/2,
- '_get_version'/1,
- '_set_version'/2,
- '_get_defined_in'/1,
- '_get_absolute_name'/1,
- '_get_containing_repository'/1,
- describe/1,
- move/4
- ]).
-
--include("orber_ifr.hrl").
-
-%%%======================================================================
-%%% ModuleDef (Container(IRObject), Contained(IRObject))
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IRObject
-
-'_get_def_kind'({ObjType, ObjID}) ?tcheck(ir_ModuleDef, ObjType) ->
- orber_ifr_irobject:'_get_def_kind'({ObjType, ObjID}).
-
-destroy({ObjType, ObjID}) ?tcheck(ir_ModuleDef, ObjType) ->
- F = fun() -> '_clean'({ObjType, ObjID}) end,
- orber_ifr_utils:ifr_transaction_write(F).
-
-'_clean'(ObjRef) ->
- ObjList = cleanup_for_destroy(ObjRef),
- orber_ifr_irobject:destroy([ObjRef | ObjList]).
-
-
-cleanup_for_destroy({ObjType,ObjID}) ?tcheck(ir_ModuleDef, ObjType) ->
- orber_ifr_container:cleanup_for_destroy({ObjType,ObjID}) ++
- orber_ifr_contained:cleanup_for_destroy({ObjType,ObjID}).
-
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from Container
-
-lookup({ObjType, ObjID}, Search_name) ?tcheck(ir_ModuleDef, ObjType) ->
- orber_ifr_container:lookup({ObjType, ObjID}, Search_name).
-
-contents({ObjType, ObjID}, Limit_type, Exclude_inherited)
- ?tcheck(ir_ModuleDef, ObjType)->
- orber_ifr_container:contents({ObjType, ObjID},Limit_type,
- Exclude_inherited).
-
-lookup_name({ObjType, ObjID}, Search_name, Levels_to_search, Limit_type,
- Exclude_inherited)
- ?tcheck(ir_ModuleDef, ObjType) ->
- orber_ifr_container:lookup_name({ObjType,ObjID}, Search_name,
- Levels_to_search, Limit_type,
- Exclude_inherited).
-
-describe_contents({ObjType, ObjID}, Limit_type, Exclude_inherited,
- Max_returned_objs)
- ?tcheck(ir_ModuleDef, ObjType) ->
- orber_ifr_container:describe_contents({ObjType, ObjID}, Limit_type,
- Exclude_inherited,Max_returned_objs).
-
-create_module({ObjType, ObjID}, Id, Name, Version)
- ?tcheck(ir_ModuleDef, ObjType) ->
- orber_ifr_container:create_module({ObjType, ObjID}, Id, Name, Version).
-
-create_constant({ObjType, ObjID}, Id, Name, Version, Type, Value)
- ?tcheck(ir_ModuleDef, ObjType) ->
- orber_ifr_container:create_constant({ObjType, ObjID}, Id, Name, Version,
- Type, Value).
-
-create_struct({ObjType, ObjID}, Id, Name, Version, Members)
- ?tcheck(ir_ModuleDef, ObjType) ->
- orber_ifr_container:create_struct({ObjType,ObjID},Id,Name,Version,Members).
-
-create_union({ObjType, ObjID}, Id, Name, Version, Discriminator_type, Members)
- ?tcheck(ir_ModuleDef, ObjType) ->
- orber_ifr_container:create_union({ObjType, ObjID}, Id, Name, Version,
- Discriminator_type, Members).
-
-create_enum({ObjType, ObjID}, Id, Name, Version, Members)
- ?tcheck(ir_ModuleDef, ObjType) ->
- orber_ifr_container:create_enum({ObjType, ObjID},Id,Name,Version,Members).
-
-create_alias({ObjType, ObjID}, Id, Name, Version, Original_type)
- ?tcheck(ir_ModuleDef, ObjType) ->
- orber_ifr_container:create_alias({ObjType, ObjID}, Id, Name, Version,
- Original_type).
-
-create_interface({ObjType, ObjID}, Id, Name, Version, Base_interfaces)
- ?tcheck(ir_ModuleDef, ObjType) ->
- orber_ifr_container:create_interface({ObjType, ObjID}, Id, Name, Version,
- Base_interfaces).
-
-create_exception({ObjType, ObjID}, Id, Name, Version, Members)
- ?tcheck(ir_ModuleDef, ObjType) ->
- orber_ifr_container:create_exception({ObjType, ObjID}, Id, Name, Version,
- Members).
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from Contained
-
-'_get_id'({ObjType, ObjID}) ?tcheck(ir_ModuleDef, ObjType) ->
- orber_ifr_contained:'_get_id'({ObjType,ObjID}).
-
-'_set_id'({ObjType,ObjID},EO_Value) ?tcheck(ir_ModuleDef,ObjType) ->
- orber_ifr_contained:'_set_id'({ObjType,ObjID},EO_Value).
-
-'_get_name'({ObjType, ObjID}) ?tcheck(ir_ModuleDef, ObjType) ->
- orber_ifr_contained:'_get_name'({ObjType,ObjID}).
-
-'_set_name'({ObjType, ObjID}, EO_Value) ?tcheck(ir_ModuleDef, ObjType) ->
- orber_ifr_contained:'_set_name'({ObjType,ObjID}, EO_Value).
-
-'_get_version'({ObjType, ObjID}) ?tcheck(ir_ModuleDef, ObjType) ->
- orber_ifr_contained:'_get_version'({ObjType,ObjID}).
-
-'_set_version'({ObjType, ObjID}, EO_Value) ?tcheck(ir_ModuleDef, ObjType) ->
- orber_ifr_contained:'_set_version'({ObjType,ObjID},EO_Value).
-
-'_get_defined_in'({ObjType, ObjID}) ?tcheck(ir_ModuleDef, ObjType) ->
- orber_ifr_contained:'_get_defined_in'({ObjType,ObjID}).
-
-'_get_absolute_name'({ObjType, ObjID}) ?tcheck(ir_ModuleDef, ObjType) ->
- orber_ifr_contained:'_get_absolute_name'({ObjType,ObjID}).
-
-'_get_containing_repository'({ObjType, ObjID}) ?tcheck(ir_ModuleDef,ObjType) ->
- orber_ifr_contained:'_get_containing_repository'({ObjType,ObjID}).
-
-describe({ObjType, ObjID}) ?tcheck(ir_ModuleDef, ObjType) ->
- orber_ifr_contained:describe({ObjType,ObjID}).
-
-move({ObjType, ObjID}, New_container, New_name, New_version)
- ?tcheck(ir_ModuleDef, ObjType) ->
- orber_ifr_contained:move({ObjType,ObjID},New_container,New_name,
- New_version).
-
-%%%----------------------------------------------------------------------
-%%% Non-inherited interfaces
-
-%%% none %%
diff --git a/lib/orber/src/orber_ifr_operationdef.erl b/lib/orber/src/orber_ifr_operationdef.erl
deleted file mode 100644
index 4bc368487c..0000000000
--- a/lib/orber/src/orber_ifr_operationdef.erl
+++ /dev/null
@@ -1,192 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_ifr_operationdef.erl
-%% Purpose : Code for Operationdef
-%%----------------------------------------------------------------------
-
--module(orber_ifr_operationdef).
-
--export(['_get_def_kind'/1,
- destroy/1,
- cleanup_for_destroy/1, %not in CORBA 2.0
- '_get_id'/1,
- '_set_id'/2,
- '_get_name'/1,
- '_set_name'/2,
- '_get_version'/1,
- '_set_version'/2,
- '_get_defined_in'/1,
- '_get_absolute_name'/1,
- '_get_containing_repository'/1,
- describe/1,
- move/4,
- '_get_result'/1,
- '_get_result_def'/1,
- '_set_result_def'/2,
- '_get_params'/1,
- '_set_params'/2,
- '_get_mode'/1,
- '_set_mode'/2,
- '_get_contexts'/1,
- '_set_contexts'/2,
- '_get_exceptions'/1,
- '_set_exceptions'/2
- ]).
-
--import(orber_ifr_utils,[get_field/2,
- set_field/3,
- get_object/1,
- set_object/1
- ]).
-
--include("orber_ifr.hrl").
--include("ifr_objects.hrl").
--include_lib("orber/include/ifr_types.hrl").
--include_lib("orber/include/corba.hrl").
-
-%%%======================================================================
-%%% OperationDef (Contained(IRObject))
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IRObject
-
-'_get_def_kind'({ObjType, ObjID}) ?tcheck(ir_OperationDef, ObjType) ->
- orber_ifr_irobject:'_get_def_kind'({ObjType,ObjID}).
-
-destroy({ObjType, ObjID}) ?tcheck(ir_OperationDef, ObjType) ->
- F = fun() -> ObjList = cleanup_for_destroy({ObjType, ObjID}),
- orber_ifr_irobject:destroy([{ObjType,ObjID} | ObjList])
- end,
- orber_ifr_utils:ifr_transaction_write(F).
-
-cleanup_for_destroy({ObjType,ObjID}) ?tcheck(ir_OperationDef, ObjType) ->
- lists:map(fun(X) -> Idl = X#parameterdescription.type_def,
- orber_ifr_idltype:cleanup_for_destroy(Idl)
- end,
- '_get_params'({ObjType,ObjID})) ++
- orber_ifr_idltype:cleanup_for_destroy('_get_result_def'({ObjType,
- ObjID})) ++
- orber_ifr_contained:cleanup_for_destroy({ObjType,ObjID}).
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from Contained
-
-'_get_id'({ObjType, ObjID}) ?tcheck(ir_OperationDef, ObjType) ->
- orber_ifr_contained:'_get_id'({ObjType,ObjID}).
-
-'_set_id'({ObjType, ObjID}, EO_Value) ?tcheck(ir_OperationDef, ObjType) ->
- orber_ifr_contained:'_set_id'({ObjType,ObjID},EO_Value).
-
-'_get_name'({ObjType, ObjID}) ?tcheck(ir_OperationDef, ObjType) ->
- orber_ifr_contained:'_get_name'({ObjType,ObjID}).
-
-'_set_name'({ObjType, ObjID}, EO_Value) ?tcheck(ir_OperationDef, ObjType) ->
- orber_ifr_contained:'_set_name'({ObjType,ObjID}, EO_Value).
-
-'_get_version'({ObjType, ObjID}) ?tcheck(ir_OperationDef, ObjType) ->
- orber_ifr_contained:'_get_version'({ObjType,ObjID}).
-
-'_set_version'({ObjType, ObjID}, EO_Value) ?tcheck(ir_OperationDef, ObjType) ->
- orber_ifr_contained:'_set_version'({ObjType,ObjID},EO_Value).
-
-'_get_defined_in'({ObjType, ObjID}) ?tcheck(ir_OperationDef, ObjType) ->
- orber_ifr_contained:'_get_defined_in'({ObjType,ObjID}).
-
-'_get_absolute_name'({ObjType, ObjID}) ?tcheck(ir_OperationDef, ObjType) ->
- orber_ifr_contained:'_get_absolute_name'({ObjType,ObjID}).
-
-'_get_containing_repository'({ObjType, ObjID}) ?tcheck(ir_OperationDef, ObjType) ->
- orber_ifr_contained:'_get_containing_repository'({ObjType,ObjID}).
-
-describe({ObjType, ObjID}) ?tcheck(ir_OperationDef, ObjType) ->
- orber_ifr_contained:describe({ObjType,ObjID}).
-
-move({ObjType, ObjID}, New_container, New_name, New_version)
- ?tcheck(ir_OperationDef, ObjType) ->
- orber_ifr_contained:move({ObjType,ObjID},New_container,New_name,New_version).
-
-%%%----------------------------------------------------------------------
-%%% Non-inherited interfaces
-
-'_get_result'({ObjType, ObjID})
- ?tcheck(ir_OperationDef, ObjType) ->
- get_field({ObjType,ObjID},result).
-
-'_get_result_def'({ObjType, ObjID})
- ?tcheck(ir_OperationDef, ObjType) ->
- get_field({ObjType,ObjID},result_def).
-
-'_set_result_def'({ObjType, ObjID}, EO_Value)
- ?tcheck(ir_OperationDef, ObjType) ->
- OperationDef = get_object({ObjType, ObjID}),
- New_OperationDef =
- OperationDef#ir_OperationDef{result = EO_Value#ir_IDLType.type,
- result_def = EO_Value},
- set_object(New_OperationDef).
-
-'_get_params'({ObjType,ObjID}) ?tcheck(ir_OperationDef,ObjType) ->
- get_field({ObjType,ObjID},params).
-
-'_set_params'({ObjType, ObjID}, EO_Value)
- ?tcheck(ir_OperationDef, ObjType) ->
- set_field({ObjType,ObjID}, params, EO_Value).
-
-'_get_mode'({ObjType, ObjID}) ?tcheck(ir_OperationDef, ObjType) ->
- get_field({ObjType,ObjID},mode).
-
-'_set_mode'({ObjType, ObjID}, EO_Value) ?tcheck(ir_OperationDef, ObjType) ->
- OperationDef = get_object({ObjType, ObjID}),
- Set_OK = case EO_Value of
- 'OP_ONEWAY' ->
- (OperationDef#ir_OperationDef.result == tk_void)
- and
- lists:foldl(fun(#parameterdescription{mode=Mode},AccIn) ->
- (Mode == 'PARAM_IN') and AccIn
- end,
- true,OperationDef#ir_OperationDef.params);
- _ ->
- true
- end,
- set_mode(Set_OK,{ObjType,ObjID},EO_Value).
-
-set_mode(true,Objref,EO_Value) ->
- set_field(Objref,mode,EO_Value);
-set_mode(false, Objref, EO_Value) ->
- orber:dbg("[~p] ~p:destroy(~p, ~p);~n"
- "Illegal '_set_mode'.~n",
- [?LINE, ?MODULE, Objref, EO_Value], ?DEBUG_LEVEL),
- corba:raise(#'INTF_REPOS'{completion_status=?COMPLETED_NO}).
-
-'_get_contexts'({ObjType, ObjID}) ?tcheck(ir_OperationDef, ObjType) ->
- get_field({ObjType,ObjID},contexts).
-
-'_set_contexts'({ObjType, ObjID}, EO_Value)
- ?tcheck(ir_OperationDef, ObjType) ->
- set_field({ObjType,ObjID}, contexts, EO_Value).
-
-'_get_exceptions'({ObjType, ObjID}) ?tcheck(ir_OperationDef, ObjType) ->
- get_field({ObjType,ObjID},exceptions).
-
-'_set_exceptions'({ObjType, ObjID}, EO_Value)
- ?tcheck(ir_OperationDef, ObjType) ->
- set_field({ObjType,ObjID}, exceptions, EO_Value).
diff --git a/lib/orber/src/orber_ifr_orb.erl b/lib/orber/src/orber_ifr_orb.erl
deleted file mode 100644
index 3969bbf37a..0000000000
--- a/lib/orber/src/orber_ifr_orb.erl
+++ /dev/null
@@ -1,100 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_ifr_orb.erl
-%% Purpose : Code for Orb
-%%----------------------------------------------------------------------
-
--module(orber_ifr_orb).
-
--export([create_struct_tc/3,
- create_union_tc/4,
- create_enum_tc/3,
- create_alias_tc/3,
- create_exception_tc/3,
- create_interface_tc/2,
- create_string_tc/1,
- create_wstring_tc/1,
- create_sequence_tc/2,
- create_recursive_sequence_tc/2,
- create_array_tc/2
- ]).
-
-
--include("orber_ifr.hrl").
--include_lib("orber/include/ifr_types.hrl").
--include_lib("orber/include/corba.hrl").
-
-%%%======================================================================
-%%% ORB
-
-%%%----------------------------------------------------------------------
-%%% Inherited interfaces
-
-%% none %%
-
-%%%----------------------------------------------------------------------
-%%% Non-inherited interfaces
-
-create_struct_tc(Id, Name, Members) ->
- {tk_struct,Id,Name,lists:map(fun(#structmember{name=MemName,type=Type}) ->
- {MemName,Type} end,
- Members)}.
-
-create_union_tc(Id, Name, Discriminator_type, Members) ->
- {tk_union, Id, Name, Discriminator_type, -1, % *** is -1 correct???
- lists:map(fun(#unionmember{name=MemName, label=Label, type=Type}) ->
- {Label,MemName,Type} end,
- Members)}.
-
-create_enum_tc(Id, Name, Members) ->
- {tk_enum, Id, Name, Members}.
-
-create_alias_tc(Id, Name, Original_type) ->
- {tk_alias, Id, Name, orber_ifr_utils:get_field(Original_type,type)}.
-
-create_exception_tc(Id, Name, Members) ->
- {tk_except,Id,Name,lists:map(fun(#structmember{name=MemName,type=Type}) ->
- {MemName,Type} end,
- Members)}.
-
-create_interface_tc(Id, Name) ->
- {tk_objref, Id, Name}.
-
-create_string_tc(Bound) ->
- {tk_string, Bound}.
-
-create_wstring_tc(Bound) ->
- {tk_wstring, Bound}.
-
-create_sequence_tc(Bound, Element_type) ->
- {tk_sequence,Element_type,Bound}.
-
--spec create_recursive_sequence_tc(_, _) -> no_return().
-create_recursive_sequence_tc(Bound, Offset) ->
- orber:dbg("[~p] ~p:create_recursive_sequence_tc(~p, ~p);~n"
- "Create_recursive_sequence is not implemented.~n",
- [?LINE, ?MODULE, Bound, Offset], ?DEBUG_LEVEL),
- corba:raise(#'INTF_REPOS'{completion_status=?COMPLETED_NO}).
-
-create_array_tc(Length, Element_type) ->
- {tk_array, Element_type, Length}.
diff --git a/lib/orber/src/orber_ifr_primitivedef.erl b/lib/orber/src/orber_ifr_primitivedef.erl
deleted file mode 100644
index bf91bc87bb..0000000000
--- a/lib/orber/src/orber_ifr_primitivedef.erl
+++ /dev/null
@@ -1,70 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_ifr_primitivedef.erl
-%% Purpose : Code for Primitivedef
-%%----------------------------------------------------------------------
-
--module(orber_ifr_primitivedef).
-
--export(['_get_def_kind'/1,
- destroy/1,
- cleanup_for_destroy/1, %not in CORBA 2.0
- '_get_type'/1,
- '_get_kind'/1
- ]).
-
--import(orber_ifr_utils,[get_field/2
- ]).
-
--include("orber_ifr.hrl").
-
-%%%======================================================================
-%%% PrimitiveDef (IDLType(IRObject))
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IRObject
-
-'_get_def_kind'({ObjType, ObjID}) ?tcheck(ir_PrimitiveDef, ObjType) ->
- orber_ifr_irobject:'_get_def_kind'({ObjType,ObjID}).
-
-destroy({ObjType, ObjID}) ?tcheck(ir_PrimitiveDef, ObjType) ->
- F = fun() -> ObjList = cleanup_for_destroy({ObjType, ObjID}),
- orber_ifr_irobject:destroy([{ObjType,ObjID} | ObjList])
- end,
- orber_ifr_utils:ifr_transaction_write(F).
-
-cleanup_for_destroy({ObjType,ObjID}) ?tcheck(ir_PrimitiveDef, ObjType) ->
- orber_ifr_idltype:cleanup_for_destroy({ObjType,ObjID}).
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IDLType
-
-'_get_type'({ObjType, ObjID}) ?tcheck(ir_PrimitiveDef, ObjType) ->
- orber_ifr_idltype:'_get_type'({ObjType, ObjID}).
-
-%%%----------------------------------------------------------------------
-%%% Non-inherited interfaces
-
-'_get_kind'({ObjType, ObjID}) ?tcheck(ir_PrimitiveDef, ObjType) ->
- get_field({ObjType,ObjID},kind).
-
diff --git a/lib/orber/src/orber_ifr_repository.erl b/lib/orber/src/orber_ifr_repository.erl
deleted file mode 100644
index 8d52573e53..0000000000
--- a/lib/orber/src/orber_ifr_repository.erl
+++ /dev/null
@@ -1,288 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_ifr_repository.erl
-%% Purpose : Code for Repository
-%%----------------------------------------------------------------------
-
--module(orber_ifr_repository).
-
--export(['_get_def_kind'/1,
- destroy/1,
- lookup/2,
- contents/3,
- lookup_name/5,
- describe_contents/4,
- create_module/4,
- create_constant/6,
- create_struct/5,
- create_union/6,
- create_enum/5,
- create_alias/5,
- create_interface/5,
- create_exception/5,
- lookup_id/2,
- get_primitive/2,
- create_string/2,
- create_wstring/2,
- create_fixed/3,
- create_sequence/3,
- create_array/3,
- create_idltype/2, %not in CORBA 2.0
- create_primitivedef/1, %not in CORBA 2.0
- create_primitivedef/2 %not in CORBA 2.0
- ]).
-
-
--include("orber_ifr.hrl").
--include("ifr_objects.hrl").
--include_lib("orber/include/corba.hrl").
-
-%%%======================================================================
-%%% Repository (Container (IRObject))
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IRObject
-
-'_get_def_kind'({ObjType, ObjID}) ?tcheck(ir_Repository, ObjType) ->
- orber_ifr_irobject:'_get_def_kind'({ObjType, ObjID}).
-
--spec destroy(_) -> no_return().
-destroy({ObjType, ObjID}) ?tcheck(ir_Repository, ObjType) ->
- orber:dbg("[~p] ~p:destroy(~p, ~p);~n"
- "Destroying a repository is an error.~n",
- [?LINE, ?MODULE, ObjType, ObjID], ?DEBUG_LEVEL),
- corba:raise(#'INTF_REPOS'{completion_status=?COMPLETED_NO}).
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from Container
-
-lookup({ObjType,ObjID}, Search_name) ?tcheck(ir_Repository, ObjType) ->
- orber_ifr_container:lookup({ObjType, ObjID}, Search_name).
-
-contents({ObjType,ObjID}, Limit_type, Exclude_inherited)
- ?tcheck(ir_Repository, ObjType) ->
- orber_ifr_container:contents({ObjType,ObjID},Limit_type,Exclude_inherited).
-
-lookup_name({ObjType,ObjID}, Search_name, Levels_to_search, Limit_type,
- Exclude_inherited) ?tcheck(ir_Repository, ObjType) ->
- orber_ifr_container:lookup_name({ObjType, ObjID}, Search_name,
- Levels_to_search, Limit_type,
- Exclude_inherited).
-
-describe_contents({ObjType,ObjID}, Limit_type, Exclude_inherited,
- Max_returned_objs) ?tcheck(ir_Repository, ObjType) ->
- orber_ifr_container:describe_contents({ObjType, ObjID}, Limit_type,
- Exclude_inherited,Max_returned_objs).
-
-create_module({ObjType,ObjID}, Id, Name, Version)
- ?tcheck(ir_Repository, ObjType) ->
- orber_ifr_container:create_module({ObjType,ObjID}, Id, Name, Version).
-
-create_constant({ObjType,ObjID}, Id, Name, Version, Type, Value)
- ?tcheck(ir_Repository, ObjType) ->
- orber_ifr_container:create_constant({ObjType,ObjID}, Id, Name, Version,
- Type, Value).
-
-create_struct({ObjType,ObjID}, Id, Name, Version, Members)
- ?tcheck(ir_Repository, ObjType) ->
- orber_ifr_container:create_struct({ObjType,ObjID}, Id, Name, Version,
- Members).
-
-create_union({ObjType,ObjID}, Id, Name, Version, Discriminator_type, Members)
- ?tcheck(ir_Repository, ObjType) ->
- orber_ifr_container:create_union({ObjType,ObjID}, Id, Name, Version,
- Discriminator_type, Members).
-
-create_enum({ObjType,ObjID}, Id, Name, Version, Members)
- ?tcheck(ir_Repository, ObjType) ->
- orber_ifr_container:create_enum({ObjType,ObjID},Id,Name,Version,Members).
-
-create_alias({ObjType,ObjID}, Id, Name, Version, Original_type)
- ?tcheck(ir_Repository, ObjType) ->
- orber_ifr_container:create_alias({ObjType,ObjID}, Id, Name, Version,
- Original_type).
-
-create_interface({ObjType,ObjID}, Id, Name, Version, Base_interfaces)
- ?tcheck(ir_Repository, ObjType) ->
- orber_ifr_container:create_interface({ObjType,ObjID}, Id, Name, Version,
- Base_interfaces).
-
-create_exception({ObjType, ObjID}, Id, Name, Version, Members)
- ?tcheck(ir_Repository, ObjType) ->
- orber_ifr_container:create_exception({ObjType, ObjID}, Id, Name, Version,
- Members).
-
-%%%----------------------------------------------------------------------
-%%% Non-inherited interfaces
-
-lookup_id({ObjType,ObjID}, Search_id) ?tcheck(ir_Repository, ObjType) ->
- Contents = orber_ifr_container:contents({ObjType, ObjID}, dk_All, false),
- case lists:filter(fun(X) -> orber_ifr_contained:'_get_id'(X) == Search_id
- end, Contents) of
- [] ->
- [];
- [ObjRef] ->
- ObjRef;
- [H|T] ->
- %% This case is just a safety-guard; orber_ifr_container:contents
- %% sometimes return duplicates due to inheritance.
- case lists:any(fun(X) -> X =/= H end, T) of
- false ->
- H;
- true ->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end
- end.
-
-get_primitive({ObjType,ObjID}, Kind) ?tcheck(ir_Repository, ObjType) ->
- Primitivedefs = orber_ifr_utils:get_field({ObjType,ObjID}, primitivedefs),
- lists:filter(fun(X) -> orber_ifr_primitivedef:'_get_kind'(X) == Kind end,
- Primitivedefs).
-
-%% It is probably incorrect to add the anonymous typedefs (string,
-%% sequence and array) to the field primitivdefs in the Repository.
-%% It is probably also not correct to add them to the contents field.
-%% Perhaps it is necessary to add another field in the ir_Repository
-%% record for anonymous typedefs? Then again, perhaps it is not
-%% necessary to keep the anonymous typedefs anywhere? According to
-%% the specification it is the callers responsibility to destroy the
-%% anonymous typedef if it is not successfully used.
-
-create_string({ObjType,_ObjID}, Bound) ?tcheck(ir_Repository, ObjType) ->
- New_string = #ir_StringDef{ir_Internal_ID = orber_ifr_utils:unique(),
- def_kind = dk_String,
- type = {tk_string, Bound},
- bound = Bound},
- orber_ifr_utils:makeref(New_string).
-
-create_wstring({ObjType,_ObjID}, Bound) ?tcheck(ir_Repository, ObjType) ->
- NewWstring = #ir_WstringDef{ir_Internal_ID = orber_ifr_utils:unique(),
- def_kind = dk_Wstring,
- type = {tk_wstring, Bound},
- bound = Bound},
- orber_ifr_utils:makeref(NewWstring).
-
-create_fixed({ObjType,_ObjID}, Digits, Scale) ?tcheck(ir_Repository, ObjType) ->
- NewFixed = #ir_FixedDef{ir_Internal_ID = orber_ifr_utils:unique(),
- def_kind = dk_Fixed,
- type = {tk_fixed, Digits, Scale},
- digits = Digits,
- scale = Scale},
- orber_ifr_utils:makeref(NewFixed).
-
-create_sequence({ObjType,_ObjID}, Bound, Element_type)
- ?tcheck(ir_Repository, ObjType) ->
- Element_typecode = orber_ifr_utils:get_field(Element_type, type),
- New_sequence = #ir_SequenceDef{ir_Internal_ID = orber_ifr_utils:unique(),
- def_kind = dk_Sequence,
- type = {tk_sequence,Element_typecode,Bound},
- bound = Bound,
- element_type = Element_typecode,
- element_type_def = Element_type},
- orber_ifr_utils:makeref(New_sequence).
-
-create_array({ObjType,_ObjID}, Length, Element_type)
- ?tcheck(ir_Repository, ObjType) ->
- Element_typecode = orber_ifr_utils:get_field(Element_type, type),
- New_array = #ir_ArrayDef{ir_Internal_ID = orber_ifr_utils:unique(),
- def_kind = dk_Array,
- type = {tk_array, Element_typecode, Length},
- length = Length,
- element_type = Element_typecode,
- element_type_def = Element_type},
- orber_ifr_utils:makeref(New_array).
-
-%%%----------------------------------------------------------------------
-%%% Extra interfaces (not in the IDL-spec for the IFR).
-
-create_idltype(#orber_light_ifr_ref{} = LRef, _Typecode) ->
- LRef;
-create_idltype({ObjType,_ObjID}, Typecode) ?tcheck(ir_Repository, ObjType) ->
- New_idltype = #ir_IDLType{ir_Internal_ID = orber_ifr_utils:unique(),
- def_kind = dk_none,
- type=Typecode},
- orber_ifr_utils:set_object(New_idltype),
- orber_ifr_utils:makeref(New_idltype).
-
-create_primitivedef(Pkind) ->
- create_primitivedef(Pkind, true).
-create_primitivedef(Pkind, Transaction) ->
- Typecode = case Pkind of
- pk_void ->
- tk_void;
- pk_short ->
- tk_short;
- pk_long ->
- tk_long;
- pk_longlong ->
- tk_longlong;
- pk_ushort ->
- tk_ushort;
- pk_ulong ->
- tk_ulong;
- pk_ulonglong ->
- tk_ulonglong;
- pk_float ->
- tk_float;
- pk_double ->
- tk_double;
- pk_boolean ->
- tk_boolean;
- pk_char ->
- tk_char;
- pk_wchar ->
- tk_wchar;
- pk_fixed ->
- tk_fixed;
- pk_octet ->
- tk_octet;
- pk_any ->
- tk_any;
- pk_TypeCode ->
- tk_TypeCode;
- pk_Principal ->
- tk_Principal;
- pk_string ->
- orber_ifr_orb:create_string_tc(0);
- pk_wstring ->
- orber_ifr_orb:create_wstring_tc(0);
- pk_objref ->
- %%*** what should the Id and Name be here?
- orber_ifr_orb:create_interface_tc("", "");
- _ ->
- orber:dbg("[~p] ~p:destroy(~p);~n"
- "Illegal primitivekin.~n",
- [?LINE, ?MODULE, Pkind], ?DEBUG_LEVEL),
- corba:raise(#'INTF_REPOS'{completion_status=?COMPLETED_NO})
- end,
- New_primitivedef = #ir_PrimitiveDef{ir_Internal_ID = orber_ifr_utils:unique(),
- def_kind = dk_Primitive,
- type = Typecode,
- kind = Pkind},
- case Transaction of
- true ->
- orber_ifr_utils:set_object(New_primitivedef);
- false ->
- mnesia:write(New_primitivedef)
- end,
- orber_ifr_utils:makeref(New_primitivedef).
diff --git a/lib/orber/src/orber_ifr_sequencedef.erl b/lib/orber/src/orber_ifr_sequencedef.erl
deleted file mode 100644
index f3a9806828..0000000000
--- a/lib/orber/src/orber_ifr_sequencedef.erl
+++ /dev/null
@@ -1,104 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_ifr_sequencedef.erl
-%% Purpose : Code for Sequencedef
-%%----------------------------------------------------------------------
-
--module(orber_ifr_sequencedef).
-
--export(['_get_def_kind'/1,
- destroy/1,
- cleanup_for_destroy/1, %not in CORBA 2.0
- '_get_type'/1,
- '_get_bound'/1,
- '_set_bound'/2,
- '_get_element_type'/1,
- '_get_element_type_def'/1,
- '_set_element_type_def'/2
- ]).
-
--import(orber_ifr_utils,[get_field/2,
- get_object/1,
- set_object/1
- ]).
-
--include("orber_ifr.hrl").
--include("ifr_objects.hrl").
-
-%%%======================================================================
-%%% SequenceDef (IDLType(IRObject))
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IRObject
-
-'_get_def_kind'({ObjType,ObjID}) ?tcheck(ir_SequenceDef,ObjType) ->
- orber_ifr_irobject:'_get_def_kind'({ObjType,ObjID}).
-
-destroy({ObjType, ObjID}) ?tcheck(ir_SequenceDef, ObjType) ->
- F = fun() -> ObjList = cleanup_for_destroy({ObjType, ObjID}),
- orber_ifr_irobject:destroy([{ObjType,ObjID} | ObjList])
- end,
- orber_ifr_utils:ifr_transaction_write(F).
-
-cleanup_for_destroy({ObjType,ObjID}) ?tcheck(ir_SequenceDef, ObjType) ->
- orber_ifr_idltype:cleanup_for_destroy(
- '_get_element_type_def'({ObjType,ObjID})) ++
- orber_ifr_idltype:cleanup_for_destroy({ObjType,ObjID}).
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IDLType
-
-'_get_type'({ObjType, ObjID}) ?tcheck(ir_SequenceDef, ObjType) ->
- orber_ifr_idltype:'_get_type'({ObjType, ObjID}).
-
-%%%----------------------------------------------------------------------
-%%% Non-inherited interfaces
-
-'_get_bound'({ObjType, ObjID}) ?tcheck(ir_SequenceDef, ObjType) ->
- get_field({ObjType,ObjID},bound).
-
-'_set_bound'({ObjType, ObjID}, EO_Value) ?tcheck(ir_SequenceDef, ObjType) ->
- SequenceDef = get_object({ObjType, ObjID}),
- New_SequenceDef =
- SequenceDef#ir_SequenceDef{type = {tk_sequence,
- SequenceDef#ir_SequenceDef.type,
- SequenceDef#ir_SequenceDef.bound},
- bound = EO_Value},
- set_object(New_SequenceDef).
-
-'_get_element_type'({ObjType, ObjID}) ?tcheck(ir_SequenceDef, ObjType) ->
- get_field({ObjType,ObjID},element_type).
-
-'_get_element_type_def'({ObjType, ObjID}) ?tcheck(ir_SequenceDef, ObjType) ->
- get_field({ObjType,ObjID},element_type_def).
-
-'_set_element_type_def'({ObjType, ObjID}, EO_Value)
- ?tcheck(ir_SequenceDef, ObjType) ->
- SequenceDef = get_object({ObjType, ObjID}),
- New_type = {tk_sequence,
- EO_Value#ir_IDLType.type,
- SequenceDef#ir_SequenceDef.bound},
- New_SequenceDef = SequenceDef#ir_SequenceDef{type = New_type,
- element_type = New_type,
- element_type_def = EO_Value},
- set_object(New_SequenceDef).
diff --git a/lib/orber/src/orber_ifr_stringdef.erl b/lib/orber/src/orber_ifr_stringdef.erl
deleted file mode 100644
index b206a218c1..0000000000
--- a/lib/orber/src/orber_ifr_stringdef.erl
+++ /dev/null
@@ -1,75 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_ifr_stringdef.erl
-%% Purpose : Code for Stringdef
-%%----------------------------------------------------------------------
-
--module(orber_ifr_stringdef).
-
--export(['_get_def_kind'/1,
- destroy/1,
- cleanup_for_destroy/1, %not in CORBA 2.0
- '_get_type'/1,
- '_get_bound'/1,
- '_set_bound'/2
- ]).
-
--import(orber_ifr_utils,[get_field/2,
- set_field/3
- ]).
-
--include("orber_ifr.hrl").
-
-%%%======================================================================
-%%% StringDef (IDLType(IRObject))
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IRObject
-
-'_get_def_kind'({ObjType,ObjID}) ?tcheck(ir_StringDef, ObjType) ->
- orber_ifr_irobject:'_get_def_kind'({ObjType,ObjID}).
-
-destroy({ObjType, ObjID}) ?tcheck(ir_StringDef, ObjType) ->
- F = fun() -> ObjList = cleanup_for_destroy({ObjType, ObjID}),
- orber_ifr_irobject:destroy([{ObjType,ObjID} | ObjList])
- end,
- orber_ifr_utils:ifr_transaction_write(F).
-
-cleanup_for_destroy({ObjType,ObjID}) ?tcheck(ir_StringDef, ObjType) ->
- orber_ifr_idltype:cleanup_for_destroy({ObjType,ObjID}).
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IDLType
-
-'_get_type'({ObjType, ObjID}) ?tcheck(ir_StringDef, ObjType) ->
- orber_ifr_idltype:'_get_type'({ObjType, ObjID}).
-
-%%%----------------------------------------------------------------------
-%%% Non-inherited interfaces
-
-'_get_bound'({ObjType, ObjID}) ?tcheck(ir_StringDef, ObjType) ->
- get_field({ObjType,ObjID},bound).
-
-'_set_bound'({ObjType, ObjID}, EO_Value)
- ?tcheck(ir_StringDef, ObjType) ->
- set_field({ObjType, ObjID}, bound, EO_Value).
diff --git a/lib/orber/src/orber_ifr_structdef.erl b/lib/orber/src/orber_ifr_structdef.erl
deleted file mode 100644
index 3a9cde353e..0000000000
--- a/lib/orber/src/orber_ifr_structdef.erl
+++ /dev/null
@@ -1,156 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_ifr_structdef.erl
-%% Purpose : Code for Structdef
-%%----------------------------------------------------------------------
-
--module(orber_ifr_structdef).
-
--export(['_get_def_kind'/1,
- destroy/1,
- cleanup_for_destroy/1, %not in CORBA 2.0
- '_get_id'/1,
- '_set_id'/2,
- '_get_name'/1,
- '_set_name'/2,
- '_get_version'/1,
- '_set_version'/2,
- '_get_defined_in'/1,
- '_get_absolute_name'/1,
- '_get_containing_repository'/1,
- describe/1,
- move/4,
- '_get_type'/1,
- '_get_members'/1,
- '_set_members'/2
- ]).
-
--import(orber_ifr_utils,[get_field/2,get_object/1,set_object/1]).
--import(lists,[map/2]).
-
--include("orber_ifr.hrl").
--include("ifr_objects.hrl").
--include_lib("orber/include/ifr_types.hrl").
-
-%%%======================================================================
-%%% StructDef (TypedefDef(Contained(IRObject), IDLType(IRObject)))
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IRObject
-
-'_get_def_kind'({ObjType, ObjID}) ?tcheck(ir_StructDef, ObjType) ->
- orber_ifr_irobject:'_get_def_kind'({ObjType,ObjID}).
-
-destroy({ObjType, ObjID}) ?tcheck(ir_StructDef, ObjType) ->
- F = fun() -> ObjList = cleanup_for_destroy({ObjType, ObjID}),
- orber_ifr_irobject:destroy([{ObjType, ObjID} | ObjList])
- end,
- orber_ifr_utils:ifr_transaction_write(F).
-
-cleanup_for_destroy({ObjType,ObjID}) ?tcheck(ir_StructDef, ObjType) ->
- map(fun(X) -> orber_ifr_idltype:cleanup_for_destroy(
- X#structmember.type_def)
- end,
- '_get_members'({ObjType, ObjID})
- ) ++
- orber_ifr_typedef:cleanup_for_destroy({ObjType,ObjID}).
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from Contained
-
-'_get_id'({ObjType, ObjID}) ?tcheck(ir_StructDef, ObjType) ->
- orber_ifr_contained:'_get_id'({ObjType,ObjID}).
-
-'_set_id'({ObjType, ObjID},EO_Value) ?tcheck(ir_StructDef,ObjType) ->
- orber_ifr_contained:'_set_id'({ObjType,ObjID},EO_Value).
-
-'_get_name'({ObjType, ObjID}) ?tcheck(ir_StructDef, ObjType) ->
- orber_ifr_contained:'_get_name'({ObjType,ObjID}).
-
-'_set_name'({ObjType, ObjID}, EO_Value) ?tcheck(ir_StructDef, ObjType) ->
- orber_ifr_contained:'_set_name'({ObjType,ObjID}, EO_Value).
-
-'_get_version'({ObjType, ObjID}) ?tcheck(ir_StructDef, ObjType) ->
- orber_ifr_contained:'_get_version'({ObjType,ObjID}).
-
-'_set_version'({ObjType, ObjID}, EO_Value) ?tcheck(ir_StructDef, ObjType) ->
- orber_ifr_contained:'_set_version'({ObjType,ObjID},EO_Value).
-
-'_get_defined_in'({ObjType, ObjID}) ?tcheck(ir_StructDef, ObjType) ->
- orber_ifr_contained:'_get_defined_in'({ObjType,ObjID}).
-
-'_get_absolute_name'({ObjType, ObjID}) ?tcheck(ir_StructDef, ObjType) ->
- orber_ifr_contained:'_get_absolute_name'({ObjType,ObjID}).
-
-'_get_containing_repository'({ObjType, ObjID}) ?tcheck(ir_StructDef,ObjType) ->
- orber_ifr_contained:'_get_containing_repository'({ObjType,ObjID}).
-
-describe({ObjType, ObjID}) ?tcheck(ir_StructDef, ObjType) ->
- orber_ifr_contained:describe({ObjType,ObjID}).
-
-move({ObjType, ObjID}, New_container, New_name, New_version)
- ?tcheck(ir_StructDef, ObjType) ->
- orber_ifr_contained:move({ObjType,ObjID},New_container,New_name,
- New_version).
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IDLType
-
-'_get_type'({ObjType, ObjID}) ?tcheck(ir_StructDef, ObjType) ->
- orber_ifr_idltype:'_get_type'({ObjType, ObjID}).
-
-%%%----------------------------------------------------------------------
-%%% Non-inherited interfaces
-
-'_get_members'({ObjType, ObjID}) ?tcheck(ir_StructDef, ObjType) ->
- get_field({ObjType,ObjID},members).
-
-'_set_members'({ObjType, ObjID}, EO_Value) ?tcheck(ir_StructDef, ObjType) ->
- StructDef = get_object({ObjType, ObjID}),
- Members = map(fun(Structmember) -> Structmember#structmember{type=tk_void}
- end, EO_Value),
- New_StructDef =
- StructDef#ir_StructDef{type =
- {tk_struct,
- StructDef#ir_StructDef.id,
- StructDef#ir_StructDef.name,
- map(fun(#structmember{name=Name,type=Type}) ->
- {Name,Type}
- end,
- EO_Value)},
- members=Members},
- set_object(New_StructDef).
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/orber/src/orber_ifr_typecode.erl b/lib/orber/src/orber_ifr_typecode.erl
deleted file mode 100644
index 52263be719..0000000000
--- a/lib/orber/src/orber_ifr_typecode.erl
+++ /dev/null
@@ -1,108 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_ifr_typecode.erl
-%% Purpose : Code for Typecode
-%%----------------------------------------------------------------------
-
-%%% NOTE:
-%%% Only make_typcode is for real here. All of the TypeCode interfaces
-%%% specified in the IDL specification needs to be implemented.
-%%%
-
--module(orber_ifr_typecode).
-
--export([
- equal/2,
- kind/1,
- id/1,
- name/1,
- member_count/1,
- member_name/2,
- member_type/2,
- member_label/2,
- discriminator_type/1,
- default_index/1,
- '_length'/1,
- content_type/1,
- param_count/1,
- parameter/2
- ]).
-
--import(orber_ifr_utils,[get_field/2]).
-
--include("orber_ifr.hrl").
--include("ifr_objects.hrl").
--include_lib("orber/include/corba.hrl").
-
-
-
-%%%----------------------------------------------------------------------
-%%% Inherited interfaces
-
-%% none %%
-
-%%%----------------------------------------------------------------------
-%%% Non-inherited interfaces
-
-equal({ObjType, ObjID}, {Tc_ObjType, Tc_ObjID})
-?tcheck(ir_TypeCode, ObjType) ->
- get_field({ObjType,ObjID},kind) == get_field({Tc_ObjType,Tc_ObjID},kind).
-
-kind({ObjType, ObjID}) ->
- {ok, {ObjType, ObjID}}.
-
-id({ObjType, ObjID}) ->
- {ok, {ObjType, ObjID}}.
-
-name({ObjType, ObjID}) ->
- {ok, {ObjType, ObjID}}.
-
-member_count({ObjType, ObjID}) ->
- {ok, {ObjType, ObjID}}.
-
-member_name({ObjType, ObjID}, _Index) ->
- {ok, {ObjType, ObjID}}.
-
-member_type({ObjType, ObjID}, _Index) ->
- {ok, {ObjType, ObjID}}.
-
-member_label({ObjType, ObjID}, _Index) ->
- {ok, {ObjType, ObjID}}.
-
-discriminator_type({ObjType, ObjID}) ->
- {ok, {ObjType, ObjID}}.
-
-default_index({ObjType, ObjID}) ->
- {ok, {ObjType, ObjID}}.
-
-'_length'({ObjType, ObjID}) ->
- {ok, {ObjType, ObjID}}.
-
-content_type({ObjType, ObjID}) ->
- {ok, {ObjType, ObjID}}.
-
-param_count({ObjType, ObjID}) ->
- {ok, {ObjType, ObjID}}.
-
-parameter({ObjType, ObjID}, _Index) ->
- {ok, {ObjType, ObjID}}.
diff --git a/lib/orber/src/orber_ifr_typedef.erl b/lib/orber/src/orber_ifr_typedef.erl
deleted file mode 100644
index 3441d7e7af..0000000000
--- a/lib/orber/src/orber_ifr_typedef.erl
+++ /dev/null
@@ -1,125 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_ifr_typedef.erl
-%% Purpose : Code for Typedef
-%%----------------------------------------------------------------------
-
--module(orber_ifr_typedef).
-
--export(['_get_def_kind'/1,
- destroy/1,
- cleanup_for_destroy/1, %not in CORBA 2.0
- '_get_id'/1,
- '_set_id'/2,
- '_get_name'/1,
- '_set_name'/2,
- '_get_version'/1,
- '_set_version'/2,
- '_get_defined_in'/1,
- '_get_absolute_name'/1,
- '_get_containing_repository'/1,
- describe/1,
- move/4,
- '_get_type'/1
- ]).
-
-
--include("orber_ifr.hrl").
-
-%%%======================================================================
-%%% TypedefDef (Contained(IRObject), IDLType(IRObject))
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IRObject
-
-'_get_def_kind'({ObjType, ObjID}) ->
- orber_ifr_irobject:'_get_def_kind'({ObjType, ObjID}).
-
-%%% Note, that the destroy function is meant to be called within a
-%%% transaction called in the destroy function of an object which
-%%% inherits from TypedefDef. A TypedefDef should only be destroyed by
-%%% destroying the object that inherits from a TypedefDef. An attempt
-%%% to call this function in user code will result in unpredictable
-%%% results.
-
-%%% Don't type check the object reference. We need to be able to
-%%% handle several types of objects that inherit from TypedefDef.
-
-destroy(TypedefDef_objref) ->
- F = fun() -> ObjList = cleanup_for_destroy(TypedefDef_objref),
- orber_ifr_irobject:destroy([TypedefDef_objref | ObjList])
- end,
- orber_ifr_utils:ifr_transaction_write(F).
-
-cleanup_for_destroy(TypedefDef_objref) ->
- orber_ifr_contained:cleanup_for_destroy(TypedefDef_objref) ++
- orber_ifr_idltype:cleanup_for_destroy(TypedefDef_objref).
-
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from Contained
-
-'_get_id'({ObjType, ObjID}) ->
- orber_ifr_contained:'_get_id'({ObjType,ObjID}).
-
-'_set_id'({ObjType, ObjID}, EO_Value) ->
- orber_ifr_contained:'_set_id'({ObjType,ObjID},EO_Value).
-
-'_get_name'({ObjType, ObjID}) ->
- orber_ifr_contained:'_get_name'({ObjType,ObjID}).
-
-'_set_name'({ObjType, ObjID}, EO_Value) ->
- orber_ifr_contained:'_set_name'({ObjType,ObjID}, EO_Value).
-
-'_get_version'({ObjType, ObjID}) ->
- orber_ifr_contained:'_get_version'({ObjType,ObjID}).
-
-'_set_version'({ObjType, ObjID}, EO_Value) ->
- orber_ifr_contained:'_set_version'({ObjType,ObjID},EO_Value).
-
-'_get_defined_in'({ObjType,ObjID}) ->
- orber_ifr_contained:'_get_defined_in'({ObjType,ObjID}).
-
-'_get_absolute_name'({ObjType, ObjID}) ->
- orber_ifr_contained:'_get_absolute_name'({ObjType,ObjID}).
-
-'_get_containing_repository'({ObjType,ObjID}) ->
- orber_ifr_contained:'_get_containing_repository'({ObjType,ObjID}).
-
-describe({ObjType, ObjID}) ->
- orber_ifr_contained:describe({ObjType,ObjID}).
-
-move({ObjType, ObjID}, New_container, New_name, New_version) ->
- orber_ifr_contained:move({ObjType,ObjID},New_container,New_name,
- New_version).
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IDLType
-
-'_get_type'({ObjType, ObjID}) ->
- orber_ifr_idltype:'_get_type'({ObjType, ObjID}).
-
-%%%----------------------------------------------------------------------
-%%% Non-inherited interfaces
-
-%%% none %%
diff --git a/lib/orber/src/orber_ifr_uniondef.erl b/lib/orber/src/orber_ifr_uniondef.erl
deleted file mode 100644
index 64d55ee581..0000000000
--- a/lib/orber/src/orber_ifr_uniondef.erl
+++ /dev/null
@@ -1,176 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_ifr_uniondef.erl
-%% Purpose : Code for Uniondef
-%%----------------------------------------------------------------------
-
--module(orber_ifr_uniondef).
-
--export(['_get_def_kind'/1,
- destroy/1,
- cleanup_for_destroy/1, %not in CORBA 2.0
- '_get_id'/1,
- '_set_id'/2,
- '_get_name'/1,
- '_set_name'/2,
- '_get_version'/1,
- '_set_version'/2,
- '_get_defined_in'/1,
- '_get_absolute_name'/1,
- '_get_containing_repository'/1,
- describe/1,
- move/4,
- '_get_type'/1,
- '_get_discriminator_type'/1,
- '_get_discriminator_type_def'/1,
- '_set_discriminator_type_def'/2,
- '_get_members'/1,
- '_set_members'/2
- ]).
-
--import(orber_ifr_utils,[get_field/2,
- get_object/1,
- set_object/1
- ]).
-
--import(lists,[map/2]).
-
--include("orber_ifr.hrl").
--include("ifr_objects.hrl").
--include_lib("orber/include/ifr_types.hrl").
-
-%%%======================================================================
-%%% UnionDef (TypedefDef(Contained(IRObject), IDLType(IRObject)))
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IRObject
-
-'_get_def_kind'({ObjType, ObjID}) ?tcheck(ir_UnionDef, ObjType) ->
- orber_ifr_irobject:'_get_def_kind'({ObjType, ObjID}).
-
-destroy({ObjType, ObjID}) ?tcheck(ir_UnionDef, ObjType) ->
- F = fun() -> ObjList = cleanup_for_destroy({ObjType, ObjID}),
- orber_ifr_irobject:destroy([{ObjType, ObjID} | ObjList])
- end,
- orber_ifr_utils:ifr_transaction_write(F).
-
-cleanup_for_destroy({ObjType,ObjID}) ?tcheck(ir_UnionDef, ObjType) ->
- map(fun(X) -> orber_ifr_idltype:cleanup_for_destroy(
- X#unionmember.type_def)
- end,
- '_get_members'({ObjType, ObjID})
- ) ++
- orber_ifr_idltype:cleanup_for_destroy(
- '_get_discriminator_type_def'({ObjType,ObjID})) ++
- orber_ifr_typedef:cleanup_for_destroy({ObjType,ObjID}).
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from Contained
-
-'_get_id'({ObjType, ObjID}) ?tcheck(ir_UnionDef, ObjType) ->
- orber_ifr_contained:'_get_id'({ObjType,ObjID}).
-
-'_set_id'({ObjType, ObjID}, EO_Value) ?tcheck(ir_UnionDef, ObjType) ->
- orber_ifr_contained:'_set_id'({ObjType,ObjID},EO_Value).
-
-'_get_name'({ObjType, ObjID}) ?tcheck(ir_UnionDef, ObjType) ->
- orber_ifr_contained:'_get_name'({ObjType,ObjID}).
-
-'_set_name'({ObjType,ObjID},EO_Value) ?tcheck(ir_UnionDef,ObjType) ->
- orber_ifr_contained:'_set_name'({ObjType,ObjID}, EO_Value).
-
-'_get_version'({ObjType, ObjID}) ?tcheck(ir_UnionDef, ObjType) ->
- orber_ifr_contained:'_get_version'({ObjType,ObjID}).
-
-'_set_version'({ObjType, ObjID}, EO_Value) ?tcheck(ir_UnionDef, ObjType) ->
- orber_ifr_contained:'_set_version'({ObjType,ObjID},EO_Value).
-
-'_get_defined_in'({ObjType, ObjID}) ?tcheck(ir_UnionDef, ObjType) ->
- orber_ifr_contained:'_get_defined_in'({ObjType,ObjID}).
-
-'_get_absolute_name'({ObjType, ObjID}) ?tcheck(ir_UnionDef,ObjType) ->
- orber_ifr_contained:'_get_absolute_name'({ObjType,ObjID}).
-
-'_get_containing_repository'({ObjType, ObjID}) ?tcheck(ir_UnionDef, ObjType) ->
- orber_ifr_contained:'_get_containing_repository'({ObjType,ObjID}).
-
-describe({ObjType, ObjID}) ?tcheck(ir_UnionDef, ObjType) ->
- orber_ifr_contained:describe({ObjType,ObjID}).
-
-move({ObjType, ObjID}, New_container, New_name, New_version)
- ?tcheck(ir_UnionDef, ObjType) ->
- orber_ifr_contained:move({ObjType,ObjID}, New_container, New_name,
- New_version).
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IDLType
-
-'_get_type'({ObjType, ObjID}) ?tcheck(ir_UnionDef, ObjType) ->
- orber_ifr_idltype:'_get_type'({ObjType, ObjID}).
-
-%%%----------------------------------------------------------------------
-%%% Non-inherited interfaces
-
-'_get_discriminator_type'({ObjType, ObjID}) ?tcheck(ir_UnionDef, ObjType) ->
- get_field({ObjType,ObjID},discriminator_type).
-
-'_get_discriminator_type_def'({ObjType, ObjID}) ?tcheck(ir_UnionDef,ObjType) ->
- get_field({ObjType,ObjID},discriminator_type_def).
-
-'_set_discriminator_type_def'({ObjType, ObjID}, EO_Value)
- ?tcheck(ir_UnionDef, ObjType) ->
- UnionDef = get_object({ObjType, ObjID}),
- NewUnionDef = UnionDef#ir_UnionDef{type = EO_Value#ir_IDLType.type,
- discriminator_type =
- EO_Value#ir_IDLType.type,
- discriminator_type_def = EO_Value},
- set_object(NewUnionDef).
-
-'_get_members'({ObjType, ObjID}) ?tcheck(ir_UnionDef, ObjType) ->
- get_field({ObjType,ObjID},members).
-
-%%% *** What should the value of the discriminator-typecode be when
-%%% updating the type attribute? (CORBA 2.0, p 6-20). For now we just
-%%% leave it unchanged, but this is perhaps not the right thing to do.
-
--define(discr_tc(TC),element(4,TC)).
--define(default(TC),element(5,TC)).
-
-'_set_members'({ObjType, ObjID}, EO_Value) ?tcheck(ir_UnionDef, ObjType) ->
- UnionDef = get_object({ObjType, ObjID}),
- Members=map(fun(Unionmember) -> Unionmember#unionmember{type=tk_void} end,
- EO_Value),
- NewUnionDef = UnionDef#ir_UnionDef{type =
- {tk_union,
- UnionDef#ir_UnionDef.id,
- UnionDef#ir_UnionDef.name,
- ?discr_tc(UnionDef#ir_UnionDef.type),
- ?default(UnionDef#ir_UnionDef.type),
- map(fun(#unionmember{name=Name,
- label=Label,
- type=Type}) ->
- {Label,Name,Type}
- end,
- EO_Value)},
- members = Members},
- set_object(NewUnionDef).
diff --git a/lib/orber/src/orber_ifr_utils.erl b/lib/orber/src/orber_ifr_utils.erl
deleted file mode 100644
index 95a1d504bc..0000000000
--- a/lib/orber/src/orber_ifr_utils.erl
+++ /dev/null
@@ -1,437 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2015. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_ifr_utils.erl
-%% Purpose : Common function for the Interface Repository
-%%----------------------------------------------------------------------
-
--module(orber_ifr_utils).
-
--export([
- select/2,
- index/2,
- construct/3,
- get_object/1,
- set_object/1,
- get_field/2,
- set_field/3,
- write_result/1,
- read_result/1,
- ifr_transaction_read/1,
- ifr_transaction_write/1,
- ifr_transaction_read_write/1,
- makeref/1,
- unique/0,
- existence_check/2,
- existence_check/3,
- create_repository/0,
- init_DB/2, init_DB/3
- ]).
-
--include_lib("orber/include/corba.hrl").
--include("orber_ifr.hrl").
--include("ifr_objects.hrl").
-
-
-%%======================================================================
-%% Internal stuff
-
-%%----------------------------------------------------------------------
-%% Make a record selection.
-%%
-%% This code *must* be amended whenever a new record is added in the
-%% files ifr_objects.hrl or ../include/ifr_types.hrl
-
-select(Record,Field) when is_record(Record,ir_IRObject) ->
- select(Record,record_info(fields,ir_IRObject),Field);
-select(Record,Field) when is_record(Record,ir_Contained) ->
- select(Record,record_info(fields,ir_Contained),Field);
-select(Record,Field) when is_record(Record,ir_Container) ->
- select(Record,record_info(fields,ir_Container),Field);
-select(Record,Field) when is_record(Record,ir_IDLType) ->
- select(Record,record_info(fields,ir_IDLType),Field);
-select(Record,Field) when is_record(Record,ir_Repository) ->
- select(Record,record_info(fields,ir_Repository),Field);
-select(Record,Field) when is_record(Record,ir_ModuleDef) ->
- select(Record,record_info(fields,ir_ModuleDef),Field);
-select(Record,Field) when is_record(Record,ir_ConstantDef) ->
- select(Record,record_info(fields,ir_ConstantDef),Field);
-select(Record,Field) when is_record(Record,ir_TypedefDef) ->
- select(Record,record_info(fields,ir_TypedefDef),Field);
-select(Record,Field) when is_record(Record,ir_StructDef) ->
- select(Record,record_info(fields,ir_StructDef),Field);
-select(Record,Field) when is_record(Record,ir_UnionDef) ->
- select(Record,record_info(fields,ir_UnionDef),Field);
-select(Record,Field) when is_record(Record,ir_EnumDef) ->
- select(Record,record_info(fields,ir_EnumDef),Field);
-select(Record,Field) when is_record(Record,ir_AliasDef) ->
- select(Record,record_info(fields,ir_AliasDef),Field);
-select(Record,Field) when is_record(Record,ir_PrimitiveDef) ->
- select(Record,record_info(fields,ir_PrimitiveDef),Field);
-select(Record,Field) when is_record(Record,ir_StringDef) ->
- select(Record,record_info(fields,ir_StringDef),Field);
-select(Record,Field) when is_record(Record,ir_WstringDef) ->
- select(Record,record_info(fields,ir_WstringDef),Field);
-select(Record,Field) when is_record(Record,ir_SequenceDef) ->
- select(Record,record_info(fields,ir_SequenceDef),Field);
-select(Record,Field) when is_record(Record,ir_ArrayDef) ->
- select(Record,record_info(fields,ir_ArrayDef),Field);
-select(Record,Field) when is_record(Record,ir_ExceptionDef) ->
- select(Record,record_info(fields,ir_ExceptionDef),Field);
-select(Record,Field) when is_record(Record,ir_AttributeDef) ->
- select(Record,record_info(fields,ir_AttributeDef),Field);
-select(Record,Field) when is_record(Record,ir_OperationDef) ->
- select(Record,record_info(fields,ir_OperationDef),Field);
-select(Record,Field) when is_record(Record,ir_InterfaceDef) ->
- select(Record,record_info(fields,ir_InterfaceDef),Field);
-select(Record,Field) when is_record(Record,ir_FixedDef) ->
- select(Record,record_info(fields,ir_FixedDef),Field);
-select([],_) -> [];
-select(Record,Field) ->
- orber:dbg("[~p] orber_ifr_utils:select(~p, ~p);~n"
- "Unknown Record Type~n", [?LINE, Record,Field], ?DEBUG_LEVEL),
- corba:raise(#'INTF_REPOS'{completion_status=?COMPLETED_NO}).
-
--define(ELEMENT_OFFSET, 2).
-
-select(Record,Fields,Field) ->
- Index = index(Fields,Field),
- element(?ELEMENT_OFFSET + Index, Record).
-
-index(List,Element) ->
- index(List,Element,0).
-
-index([H|_T],Element,Index) when H == Element ->
- Index;
-index([_H|T],Element,Index) ->
- index(T,Element,Index+1);
-index([],Element,Index) ->
- orber:dbg("[~p] orber_ifr_utils:index(~p, ~p);~n"
- "Index error.~n", [?LINE, Element, Index], ?DEBUG_LEVEL),
- corba:raise(#'INTF_REPOS'{completion_status=?COMPLETED_NO}).
-
-%%%----------------------------------------------------------------------
-%%% Construct a record.
-%%%
-%%% This code *must* be amended whenever a new record is added in the
-%%% files ifr_objects.hrl or ../include/ifr_types.hrl
-
-construct(Record,Field,Value) when is_record(Record,ir_IRObject) ->
- construct(Record,record_info(fields,ir_IRObject),Field,Value);
-construct(Record,Field,Value) when is_record(Record,ir_Contained) ->
- construct(Record,record_info(fields,ir_Contained),Field,Value);
-construct(Record,Field,Value) when is_record(Record,ir_Container) ->
- construct(Record,record_info(fields,ir_Container),Field,Value);
-construct(Record,Field,Value) when is_record(Record,ir_IDLType) ->
- construct(Record,record_info(fields,ir_IDLType),Field,Value);
-construct(Record,Field,Value) when is_record(Record,ir_Repository) ->
- construct(Record,record_info(fields,ir_Repository),Field,Value);
-construct(Record,Field,Value) when is_record(Record,ir_ModuleDef) ->
- construct(Record,record_info(fields,ir_ModuleDef),Field,Value);
-construct(Record,Field,Value) when is_record(Record,ir_ConstantDef) ->
- construct(Record,record_info(fields,ir_ConstantDef),Field,Value);
-construct(Record,Field,Value) when is_record(Record,ir_TypedefDef) ->
- construct(Record,record_info(fields,ir_TypedefDef),Field,Value);
-construct(Record,Field,Value) when is_record(Record,ir_StructDef) ->
- construct(Record,record_info(fields,ir_StructDef),Field,Value);
-construct(Record,Field,Value) when is_record(Record,ir_UnionDef) ->
- construct(Record,record_info(fields,ir_UnionDef),Field,Value);
-construct(Record,Field,Value) when is_record(Record,ir_EnumDef) ->
- construct(Record,record_info(fields,ir_EnumDef),Field,Value);
-construct(Record,Field,Value) when is_record(Record,ir_AliasDef) ->
- construct(Record,record_info(fields,ir_AliasDef),Field,Value);
-construct(Record,Field,Value) when is_record(Record,ir_PrimitiveDef) ->
- construct(Record,record_info(fields,ir_PrimitiveDef),Field,Value);
-construct(Record,Field,Value) when is_record(Record,ir_StringDef) ->
- construct(Record,record_info(fields,ir_StringDef),Field,Value);
-construct(Record,Field,Value) when is_record(Record,ir_WstringDef) ->
- construct(Record,record_info(fields,ir_WstringDef),Field,Value);
-construct(Record,Field,Value) when is_record(Record,ir_SequenceDef) ->
- construct(Record,record_info(fields,ir_SequenceDef),Field,Value);
-construct(Record,Field,Value) when is_record(Record,ir_ArrayDef) ->
- construct(Record,record_info(fields,ir_ArrayDef),Field,Value);
-construct(Record,Field,Value) when is_record(Record,ir_ExceptionDef) ->
- construct(Record,record_info(fields,ir_ExceptionDef),Field,Value);
-construct(Record,Field,Value) when is_record(Record,ir_AttributeDef) ->
- construct(Record,record_info(fields,ir_AttributeDef),Field,Value);
-construct(Record,Field,Value) when is_record(Record,ir_OperationDef) ->
- construct(Record,record_info(fields,ir_OperationDef),Field,Value);
-construct(Record,Field,Value) when is_record(Record,ir_InterfaceDef) ->
- construct(Record,record_info(fields,ir_InterfaceDef),Field,Value);
-construct(Record,Field,Value) when is_record(Record,ir_FixedDef) ->
- construct(Record,record_info(fields,ir_FixedDef),Field,Value);
-construct(Record,Field,Value) ->
- orber:dbg("[~p] orber_ifr_utils:construct(~p, ~p, ~p);~n"
- "Unknown Record Type~n",
- [?LINE, Record,Field,Value], ?DEBUG_LEVEL),
- corba:raise(#'INTF_REPOS'{completion_status=?COMPLETED_NO}).
-
-construct(Record,Fields,Field,Value) ->
- Index = index(Fields,Field),
- setelement(?ELEMENT_OFFSET + Index,Record,Value).
-
-%%%----------------------------------------------------------------------
-%%% Read an object from the database
-
-get_object(Objref) ->
-%%% Use mnesia:dirty_read/1. It is much faster than doing a transaction.
- case mnesia:dirty_read(Objref) of
- [Res] ->
- Res;
- [] ->
- [];
- Other ->
- orber:dbg("[~p] orber_ifr_utils:get_object(~p);~n",
- [?LINE, Other], ?DEBUG_LEVEL),
- corba:raise(#'INTF_REPOS'{completion_status=?COMPLETED_NO})
- end.
-%%% This is the old code, with a transaction. We might have to revert back
-%%% to this at some future time...
-%% _F = ?read_function(Objref),
-%% read_result(ifr_transaction_read(_F)).
-
-%%%----------------------------------------------------------------------
-%%% Write an object to the database
-
-set_object(Object) ->
- _F = fun() -> mnesia:write(Object) end,
- write_result(ifr_transaction_write(_F)).
-
-%%%----------------------------------------------------------------------
-%%% Get the value of a field in a record in the DB
-
-get_field(Objref,FieldName) ->
- Object = get_object(Objref),
- select(Object,FieldName).
-
-%%%----------------------------------------------------------------------
-%%% Atomically set the value of a field in a record in the DB
-
-set_field(Objref,FieldName,Value) ->
- _F = fun() -> Object = get_object(Objref),
- New_object = construct(Object,FieldName,Value),
- mnesia:write(New_object)
- end,
- write_result(ifr_transaction_write(_F)).
-
-
-%%%----------------------------------------------------------------------
-%%% Check a write transaction
-
-write_result({atomic,ok}) -> ok;
-write_result(Wres) ->
- orber:dbg("[~p] orber_ifr_utils:write_result(~p);~n",
- [?LINE, Wres], ?DEBUG_LEVEL),
- corba:raise(#'INTF_REPOS'{completion_status=?COMPLETED_NO}).
-
-%%%----------------------------------------------------------------------
-%%% Extract the data from a read
-
-read_result({atomic,[Qres]}) -> Qres;
-read_result({atomic,[]}) -> [];
-read_result(Qres) ->
- orber:dbg("[~p] orber_ifr_utils:read_result(~p);~n",
- [?LINE, Qres], ?DEBUG_LEVEL),
- corba:raise(#'INTF_REPOS'{completion_status=?COMPLETED_NO}).
-
-%%%----------------------------------------------------------------------
-%%% Execute a transaction or a dirty read/write.
-%%%
-%%% Since nested transctions will upgrade the inner activity to the
-%%% same kind as the outer, we cannot use the check the result in the
-%%% above simplistic manner. Therefore we will not mix transaction
-%%% with async_dirty (or any of the other transaction-like
-%%% activities). A rather extensive rewrite of the query extraction
-%%% code must be done first.
-
-ifr_transaction_read(Fun) -> % read synchronously
- Tr = mnesia:transaction(Fun),
- {atomic, _} = Tr,
- Tr.
-ifr_transaction_write(Fun) -> % write synchronously
- Tr = mnesia:transaction(Fun),
- {atomic, _} = Tr,
- Tr.
-ifr_transaction_read_write(Fun) -> % write synchronously
- Tr = mnesia:transaction(Fun),
- {atomic, _} = Tr,
- Tr.
-
-%%%----------------------------------------------------------------------
-%%% Make an object reference from an object
-
-makeref(Obj) ->
- [ObjType, ObjID | _] = tuple_to_list(Obj),
- {ObjType, ObjID}.
-
-%%%----------------------------------------------------------------------
-%%% Make a unique tag.
-%%%
-%%% The call to term_to_binary is made to hide the representation of the
-%%% unique tag. I do this because the tuple generated takes a lot of space
-%%% when I dump the database. A binary is simply printed as #Bin, which
-%%% is much less obtrusive.
-
-unique() -> term_to_binary({node(), {erlang:system_time(),
- erlang:unique_integer()}}).
-
-%%%----------------------------------------------------------------------
-%%% Check for an existing object with the Id of the object which is
-%%% about to be created.
-
-existence_check({ObjType, ObjID}, Id) ->
- Rep = case ObjType of
- ir_Repository ->
- {ObjType, ObjID};
- _ ->
- orber_ifr_contained:'_get_containing_repository'({ObjType,
- ObjID})
- end,
- case orber_ifr_repository:lookup_id(Rep, Id) of
- [] ->
- ok;
- What ->
- orber:dbg("[~p] orber_ifr_utils:existence_check(~p, ~p, ~p);~n"
- "Name clash(?): ~p",
- [?LINE, ObjType, ObjID, Id, What], ?DEBUG_LEVEL),
- corba:raise(#'INTF_REPOS'{completion_status=?COMPLETED_NO})
- end.
-
-existence_check(Id, Tab, FieldNum) ->
- case mnesia:dirty_index_read(Tab, Id, FieldNum) of
- [] ->
- ok;
- What ->
- orber:dbg("[~p] orber_ifr_utils:existence_check(~p, ~p, ~p);~n"
- "Name clash(?): ~p",
- [?LINE, Id, Tab, FieldNum, What], ?DEBUG_LEVEL),
- corba:raise(#'INTF_REPOS'{completion_status=?COMPLETED_NO})
- end.
-
-%%======================================================================
-%% Database initialization
-
-init_DB(Timeout, Options) ->
- init_DB(Timeout, Options, false).
-
-init_DB(Timeout, Options, LightIFR) ->
- Func = case Options of
- {localCopy, IFR_storage_type} when LightIFR == true ->
- ?ifr_light_record_tuple_list_local(IFR_storage_type);
- {localCopy, IFR_storage_type} ->
- ?ifr_record_tuple_list_local(IFR_storage_type);
- _ when LightIFR == true ->
- ?ifr_light_record_tuple_list(Options);
- _ ->
- ?ifr_record_tuple_list(Options)
- end,
- create_tables(Func),
- Wait = wait_for_tables(LightIFR, Timeout),
- db_error_check([Wait],"Database table waiting failed.").
-
-wait_for_tables(true, Timeout) ->
- mnesia:wait_for_tables(?ifr_light_object_list, Timeout);
-wait_for_tables(_, Timeout) ->
- mnesia:wait_for_tables(?ifr_object_list, Timeout).
-
-db_error_check(Checkval,_Message) ->
- case lists:any(fun(X) -> X/= ok end, Checkval) of
- true ->
- corba:raise(#'INTF_REPOS'{completion_status=?COMPLETED_NO});
- false ->
- ok
- end.
-
-create_tables([{T,F}|Rest]) ->
- case F() of
- ok ->
- create_tables2(Rest);
- {aborted,{already_exists,_}} ->
- exit({error, "Orber Mnesia Table(s) already exist. Cannot install Orber."});
- Reason ->
- orber:dbg("[~p] orber_ifr_utils:create_tables(~p);~n"
- "Failed to create the Mnesia table.~n"
- "Reason: ~p", [?LINE, T, Reason], ?DEBUG_LEVEL),
- exit({error, "Unable to create Mnesia Table"})
- end.
-
-create_tables2([]) ->
- ok;
-create_tables2([{T,F}|Rest]) ->
- case F() of
- ok ->
- create_tables2(Rest);
- Reason ->
- orber:dbg("[~p] orber_ifr_utils:create_tables2(~p);~n"
- "Failed to create the Mnesia table.~n"
- "Reason: ~p", [?LINE, T, Reason], ?DEBUG_LEVEL),
- corba:raise(#'INTF_REPOS'{completion_status=?COMPLETED_NO})
- end.
-
-
-%%%----------------------------------------------------------------------
-%%% Create an interface repository. This function should only be called
-%%% once, after the database has been set up and initialized.
-
-create_repository() ->
- case orber:light_ifr() of
- true ->
- #orber_light_ifr_ref{data = #lightdata{scope = "",
- id = ""}};
- false ->
- _R = fun() ->
- Pat = mnesia:table_info(ir_Repository, wild_pattern),
- case [X#ir_Repository.ir_Internal_ID ||
- X <- mnesia:match_object(Pat)] of
- [] ->
- PrimitiveDefs = create_primitivedefs(),
- New = #ir_Repository{ir_Internal_ID = unique(),
- def_kind = dk_Repository,
- contents = [],
- primitivedefs = PrimitiveDefs},
- mnesia:write(New),
- {ir_Repository,New#ir_Repository.ir_Internal_ID};
- [Rep_ID] ->
- {ir_Repository,Rep_ID};
- Error ->
- mnesia:abort(Error)
- end
- end,
- case mnesia:transaction(_R) of
- {atomic, RepRef} ->
- RepRef;
- {aborted, Error} ->
- orber:dbg("[~p] orber_ifr_utils:create_repository() failed;~n"
- "Reason: ~p", [?LINE, Error], ?DEBUG_LEVEL),
- corba:raise(#'INTF_REPOS'{completion_status=?COMPLETED_NO})
- end
- end.
-
-create_primitivedefs() ->
- lists:map(fun(Pk) ->
- orber_ifr_repository:create_primitivedef(Pk, false)
- end,
- [pk_void,pk_short,pk_long,pk_longlong,pk_ulonglong,pk_ushort,pk_ulong,
- pk_float,pk_double,pk_boolean,pk_char,pk_wchar,pk_octet,pk_any,
- pk_TypeCode,pk_Principal,pk_string,pk_wstring,pk_objref]).
-
-
diff --git a/lib/orber/src/orber_ifr_wstringdef.erl b/lib/orber/src/orber_ifr_wstringdef.erl
deleted file mode 100644
index 2ff7d84c7a..0000000000
--- a/lib/orber/src/orber_ifr_wstringdef.erl
+++ /dev/null
@@ -1,73 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_ifr_wstringdef.erl
-%% Description :
-%%
-%%----------------------------------------------------------------------
--module(orber_ifr_wstringdef).
-
--export(['_get_def_kind'/1,
- destroy/1,
- cleanup_for_destroy/1, %not in CORBA 2.0
- '_get_type'/1,
- '_get_bound'/1,
- '_set_bound'/2]).
-
--import(orber_ifr_utils, [get_field/2,
- set_field/3]).
-
--include("orber_ifr.hrl").
-
-%%%======================================================================
-%%% WstringDef (IDLType(IRObject))
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IRObject
-
-'_get_def_kind'({ObjType,ObjID}) ?tcheck(ir_WstringDef, ObjType) ->
- orber_ifr_irobject:'_get_def_kind'({ObjType,ObjID}).
-
-destroy({ObjType, ObjID}) ?tcheck(ir_WstringDef, ObjType) ->
- F = fun() -> ObjList = cleanup_for_destroy({ObjType, ObjID}),
- orber_ifr_irobject:destroy([{ObjType,ObjID} | ObjList])
- end,
- orber_ifr_utils:ifr_transaction_write(F).
-
-cleanup_for_destroy({ObjType,ObjID}) ?tcheck(ir_WstringDef, ObjType) ->
- orber_ifr_idltype:cleanup_for_destroy({ObjType,ObjID}).
-
-%%%----------------------------------------------------------------------
-%%% Interfaces inherited from IDLType
-
-'_get_type'({ObjType, ObjID}) ?tcheck(ir_WstringDef, ObjType) ->
- orber_ifr_idltype:'_get_type'({ObjType, ObjID}).
-
-%%%----------------------------------------------------------------------
-%%% Non-inherited interfaces
-
-'_get_bound'({ObjType, ObjID}) ?tcheck(ir_WstringDef, ObjType) ->
- get_field({ObjType,ObjID},bound).
-
-'_set_bound'({ObjType, ObjID}, EO_Value)
- ?tcheck(ir_WstringDef, ObjType) ->
- set_field({ObjType, ObjID}, bound, EO_Value).
diff --git a/lib/orber/src/orber_iiop.erl b/lib/orber/src/orber_iiop.erl
deleted file mode 100644
index 8cb39c7365..0000000000
--- a/lib/orber/src/orber_iiop.erl
+++ /dev/null
@@ -1,551 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: orber_iiop.erl
-%% Description:
-%% This file contains the interface to the iiop operations
-%%
-%%-----------------------------------------------------------------
--module(orber_iiop).
-
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
-
--behaviour(supervisor).
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([start_sup/1, request/8, locate/4]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([init/1, terminate/2, handle_call/3]).
-
-%%-----------------------------------------------------------------
-%% Internal defines
-%%-----------------------------------------------------------------
--define(DEBUG_LEVEL, 7).
-
-
-%%-----------------------------------------------------------------
-%% External interface functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: start_sup/1
-%%-----------------------------------------------------------------
-start_sup(Opts) ->
- supervisor:start_link({local, orber_iiop_sup}, ?MODULE,
- {orber_iiop_sup, Opts}).
-
-%%%-----------------------------------------------------------------
-%%% Func: connect/1
-%%%-----------------------------------------------------------------
-%connect(OrbName) ->
-% orber_iiop_net:connect(OrbName).
-
-%%%-----------------------------------------------------------------
-%%% Func: request/5
-%%%-----------------------------------------------------------------
-request({Host, Port, InitObjkey, Index, TaggedProfile, HostData},
- Op, Parameters, TypeCodes, ResponseExpected, Timeout, IOR, UserCtx) ->
- {{Proxy, SysCtx, Interceptors, LocalInterface}, ObjKey, Version} =
- connect(Host, Port, InitObjkey, Timeout, [Index], HostData,
- TaggedProfile, IOR, UserCtx),
- Ctx = add_user_context(SysCtx, UserCtx),
- RequestId = orber_request_number:get(),
- Env = #giop_env{interceptors = Interceptors, type = out,
- flags = orber_env:get_flags(), host = LocalInterface,
- version = Version, ctx = Ctx, request_id = RequestId, op = Op,
- parameters = Parameters, tc = TypeCodes, objkey = ObjKey,
- response_expected = ResponseExpected},
- Message = encode_request(Env),
- case catch orber_iiop_outproxy:request(Proxy, ResponseExpected, Timeout,
- Message, RequestId) of
- {'EXCEPTION', MsgExc} ->
- corba:raise(MsgExc);
- _ when ResponseExpected == false ->
- ok;
- {reply, ReplyHeader, Rest, Len, ByteOrder, Bytes} ->
- case catch decode_reply_body(Interceptors, ObjKey, Op, ReplyHeader,
- Version, TypeCodes, Rest, Len, ByteOrder,
- Bytes) of
- {'EXCEPTION', DecodeException} ->
- %% We cannot log this exception since it may be a correct exception.
- corba:raise(DecodeException);
- {'EXIT', message_error} ->
- orber:dbg("[~p] orber_iiop:request(reply, ~p, ~p, ~p)~n"
- "Got exit(message_error)",
- [?LINE, Rest, Version, TypeCodes], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE});
- {'EXIT', Why} ->
- orber:dbg("[~p] orber_iiop:request(reply, ~p, ~p, ~p)~n"
- "Got exit(~p)",
- [?LINE, Rest, Version, TypeCodes, Why], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE});
- 'message_error' ->
- orber:dbg("[~p] orber_iiop:request(reply, ~p, ~p, ~p);~n"
- "Got message_error",
- [?LINE, Rest, Version, TypeCodes], ?DEBUG_LEVEL),
- %% Perhaps a resend should be done when a message error occurs
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE});
- {Result, Par} ->
- %% Check request id
- case ReplyHeader#reply_header.reply_status of
- 'no_exception' ->
- case Par of
- [] ->
- Result;
- _ ->
- list_to_tuple([Result | Par])
- end;
- 'system_exception' ->
- corba:raise(Result);
- 'user_exception' ->
- corba:raise(Result);
- 'location_forward' ->
- case get(orber_forward_notify) of
- true ->
- {location_forward, Result};
- _ ->
- case catch corba:call(Result, Op, Parameters,
- TypeCodes,
- [{timeout, Timeout},
- {context, UserCtx}]) of
- {'EXCEPTION', E} ->
- corba:raise(E);
- {'EXIT', Reason} ->
- orber:dbg("[~p] orber_iiop:request(reply, ~p, ~p, ~p)~n"
- "location_forward resulted in exit(~p)",
- [?LINE, Rest, Version, TypeCodes, Reason], ?DEBUG_LEVEL),
- corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO});
- NewResult ->
- NewResult
- end
- end;
- 'location_forward_perm' ->
- %% We should notify the client in this case.
- case get(orber_forward_notify) of
- true ->
- {location_forward, Result};
- _ ->
- case catch corba:call(Result, Op, Parameters,
- TypeCodes,
- [{timeout, Timeout},
- {context, UserCtx}]) of
- {'EXCEPTION', E} ->
- corba:raise(E);
- {'EXIT', Reason} ->
- orber:dbg("[~p] orber_iiop:request(reply, ~p, ~p, ~p)~n"
- "location_forward_perm resulted in exit(~p)",
- [?LINE, Rest, Version, TypeCodes, Reason], ?DEBUG_LEVEL),
- corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO});
- NewResult ->
- NewResult
- end
- end;
- 'needs_addressing_mode' ->
- orber:dbg("[~p] orber_iiop:request(reply, ~p, ~p, ~p)~n"
- "needs_addressing_mode not supported.",
- [?LINE, Rest, Version, TypeCodes], ?DEBUG_LEVEL),
- corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO})
- end
- end;
- What ->
- orber:dbg("[~p] orber_iiop:request(reply, ~p, ~p, ~p)~n"
- "outproxy-request: ~p", [?LINE, Message, Version, TypeCodes, What], ?DEBUG_LEVEL),
- corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO})
- end.
-
--dialyzer({no_improper_lists, encode_request/1}).
-encode_request(#giop_env{interceptors = false} = Env) ->
- case catch cdr_encode:enc_request(Env) of
- {'EXCEPTION', Exc} ->
- orber:dbg("[~p] orber_iiop:request(~p)~n"
- "Got exception(~p)",
- [?LINE, Env, Exc], ?DEBUG_LEVEL),
- corba:raise(Exc);
- {'EXIT', R} ->
- orber:dbg("[~p] orber_iiop:request:( ~p )~n"
- "Got exit(~p)",
- [?LINE, Env, R], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_NO});
- Msg ->
- Msg
- end;
-encode_request(#giop_env{interceptors = {native, Ref, PIs},
- objkey = ObjKey, ctx = Ctx, op = Op,
- parameters = Params} = Env) ->
- Parameters = orber_pi:out_request(PIs, ObjKey, Ctx, Op, Ref, Params),
- case catch cdr_encode:enc_request_split(Env) of
- {'EXCEPTION', Exc} ->
- orber:dbg("[~p] orber_iiop:request( ~p, ~p); exception(~p)",
- [?LINE, Env, Parameters, Exc], ?DEBUG_LEVEL),
- corba:raise(Exc);
- {'EXIT', R} ->
- orber:dbg("[~p] orber_iiop:request:( ~p, ~p); got exit(~p)",
- [?LINE, Env, Parameters, R], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_NO});
- {Hdr, Body, HdrLen, _, Flags} ->
- NewBody = orber_pi:out_request_enc(PIs, ObjKey, Ctx, Op, Ref, Body),
- cdr_encode:enc_giop_message_header(Env, 'request', Flags,
- HdrLen+size(NewBody),
- [Hdr|NewBody])
- end;
-encode_request(Env) ->
- case catch cdr_encode:enc_request(Env) of
- {'EXCEPTION', Exc} ->
- orber:dbg("[~p] orber_iiop:request( ~p ); exception(~p)",
- [?LINE, Env, Exc], ?DEBUG_LEVEL),
- corba:raise(Exc);
- {'EXIT', R} ->
- orber:dbg("[~p] orber_iiop:request:( ~p ); got exit(~p)",
- [?LINE, Env, R], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_NO});
- Msg ->
- Msg
- end.
-
-%%-----------------------------------------------------------------
-%% Func: locate/1
-%%-----------------------------------------------------------------
-locate({Host, Port, InitObjkey, Index, TaggedProfile, HostData},
- Timeout, IOR, UserCtx) ->
- {{Proxy, _Ctx, _Interceptors, LocalInterface}, ObjKey, Version} =
- connect(Host, Port, InitObjkey, Timeout, [Index], HostData,
- TaggedProfile, IOR, UserCtx),
- RequestId = orber_request_number:get(),
- Env = #giop_env{version = Version, objkey = ObjKey, request_id = RequestId,
- flags = orber_env:get_flags(), host = LocalInterface},
- Result =
- case catch cdr_encode:enc_locate_request(Env) of
- {'EXCEPTION', EncE} ->
- orber:dbg("[~p] orber_iiop:locate(~p); exception(~p)",
- [?LINE, ObjKey, EncE], ?DEBUG_LEVEL),
- corba:raise(EncE);
- {'EXIT', EncR} ->
- orber:dbg("[~p] orber_iiop:locate(~p); exit(~p)",
- [?LINE, ObjKey, EncR], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_NO});
- Request ->
- (catch orber_iiop_outproxy:request(Proxy, true, Timeout,
- Request, RequestId))
- end,
- case Result of
- {'EXCEPTION', MsgExc} ->
- corba:raise(MsgExc);
- {locate_reply, ReplyHeader, Rest, Len, ByteOrder} ->
- case catch cdr_decode:dec_locate_reply_body(Version,
- ReplyHeader#locate_reply_header.locate_status,
- Rest, Len, ByteOrder) of
- {'EXCEPTION', DecodeException} ->
- orber:dbg("[~p] orber_iiop:locate(locate_reply, ~p, ~p); exception(~p)",
- [?LINE, Rest, Version, DecodeException], ?DEBUG_LEVEL),
- corba:raise(DecodeException);
- {'EXIT', message_error} ->
- orber:dbg("[~p] orber_iiop:locate(locate_reply, ~p, ~p); exit(message_error)",
- [?LINE, Rest, Version], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE});
- {'EXIT', R} ->
- orber:dbg("[~p] orber_iiop:locate(locate_reply, ~p, ~p); exit(~p)",
- [?LINE, Rest, Version, R], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE});
- [] ->
- ReplyHeader#locate_reply_header.locate_status;
- ObjRef ->
- {ReplyHeader#locate_reply_header.locate_status, ObjRef}
- end;
- Other ->
- orber:dbg("[~p] orber_iiop:locate(~p); exit(~p)",
- [?LINE, ObjKey, Other], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_NO})
- end.
-
-%%%-----------------------------------------------------------------
-%%% Func: cancel/1
-%%%-----------------------------------------------------------------
-%cancel(X) ->
-% ok.
-
-%%%-----------------------------------------------------------------
-%%% Func: message_error/1
-%%%-----------------------------------------------------------------
-%message_error(X) ->
-% ok.
-
-%%-----------------------------------------------------------------
-%% Server functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: init/1
-%%-----------------------------------------------------------------
-init({orber_iiop_sup, Opts}) ->
- IIOP_port = orber:iiop_port(),
- SSL_port = orber:iiop_ssl_port(),
- SupFlags = {one_for_one, 5, 1000}, %Max 5 restarts in 1 second
- PortList = if
- SSL_port > -1 ->
- [{port, ssl, SSL_port}];
- true ->
- []
- end,
- ChildSpec =
- case orber:is_lightweight() of
- true ->
- [
- {orber_iiop_outsup, {orber_iiop_outsup, start,
- [sup, Opts]},
- permanent, 10000, supervisor, [orber_iiop_outsup]},
- {orber_iiop_pm, {orber_iiop_pm, start,
- [Opts]},
- permanent, 10000, worker, [orber_iiop_pm]}
- ];
- false ->
- [{orber_iiop_outsup, {orber_iiop_outsup, start,
- [sup, Opts]},
- permanent, 10000, supervisor, [orber_iiop_outsup]},
- {orber_iiop_pm, {orber_iiop_pm, start,
- [Opts]},
- permanent, 10000, worker, [orber_iiop_pm]},
- {orber_iiop_insup, {orber_iiop_insup, start,
- [sup, Opts]},
- permanent, 10000, supervisor, [orber_iiop_insup]},
- {orber_iiop_socketsup, {orber_iiop_socketsup, start,
- [sup, Opts]},
- permanent, 10000, supervisor, [orber_iiop_socketsup]},
- {orber_iiop_net, {orber_iiop_net, start,
- [[{port, normal, IIOP_port} | PortList]]},
- permanent, 10000, worker, [orber_iiop_net]}]
- end,
- {ok, {SupFlags, ChildSpec}}.
-
-
-
-
-
-%%-----------------------------------------------------------------
-%% Func: terminate/2
-%%-----------------------------------------------------------------
-terminate(_Reason, _State) ->
- ok.
-
-%%-----------------------------------------------------------------
-%% Func: handle_call/3
-%%-----------------------------------------------------------------
-handle_call(_Req, _From, State) ->
- {reply, ok, State}.
-
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-add_user_context([], UserCtx) -> UserCtx;
-add_user_context(SysCtx, []) -> SysCtx;
-add_user_context(SysCtx, UserCtx) -> SysCtx ++ UserCtx.
-
-decode_reply_body(false, _ObjKey, _Op, ReplyHeader, Version, TypeCodes,
- Rest, Len, ByteOrder, Bytes) ->
- case ReplyHeader#reply_header.reply_status of
- 'no_exception' ->
- {R, P, _} = cdr_decode:dec_reply_body(Version, TypeCodes, Rest, Len, ByteOrder, Bytes),
- {R, P};
- 'system_exception' ->
- {R, _} = cdr_decode:dec_system_exception(Version, Rest, Len, ByteOrder),
- {R, []};
- 'user_exception' ->
- {R, _} = cdr_decode:dec_user_exception(Version, Rest, Len, ByteOrder),
- {R, []};
- 'location_forward' ->
- {R, _, _} = cdr_decode:dec_reply_body(Version, {{'tk_objref', "", ""}, [],[]},
- Rest, Len, ByteOrder, Bytes),
- {R, []};
- 'location_forward_perm' ->
- {R, _, _} = cdr_decode:dec_reply_body(Version, {{'tk_objref', "", ""}, [],[]},
- Rest, Len, ByteOrder, Bytes),
- {R, []};
- 'needs_addressing_mode' ->
- {R, _, _} = cdr_decode:dec_reply_body(Version, {'tk_short', [],[]},
- Rest, Len, ByteOrder, Bytes),
- {R, []}
- end;
-decode_reply_body(Interceptors, ObjKey, Op, ReplyHeader, Version, TypeCodes,
- RestIn, Len, ByteOrder, Bytes) ->
- Rest =
- case Interceptors of
- {portable, _PIs} ->
- RestIn;
- {native, Ref, PIs} ->
- orber_pi:in_reply_enc(PIs, ObjKey,
- ReplyHeader#reply_header.service_context,
- Op, Ref, RestIn)
- end,
- Reply =
- case ReplyHeader#reply_header.reply_status of
- 'no_exception' ->
- {R, P, _} = cdr_decode:dec_reply_body(Version, TypeCodes, Rest, Len, ByteOrder, Bytes),
- {R, P};
- 'system_exception' ->
- {R, _} = cdr_decode:dec_system_exception(Version, Rest, Len, ByteOrder),
- {R, []};
- 'user_exception' ->
- {R, _} = cdr_decode:dec_user_exception(Version, Rest, Len, ByteOrder),
- {R, []};
- 'location_forward' ->
- {R, _, _} = cdr_decode:dec_reply_body(Version, {{'tk_objref', "", ""}, [],[]},
- Rest, Len, ByteOrder, Bytes),
- {R, []};
- 'location_forward_perm' ->
- {R, _, _} = cdr_decode:dec_reply_body(Version, {{'tk_objref', "", ""}, [],[]},
- Rest, Len, ByteOrder, Bytes),
- {R, []};
- 'needs_addressing_mode' ->
- {R, _, _} = cdr_decode:dec_reply_body(Version, {'tk_short', [],[]},
- Rest, Len, ByteOrder, Bytes),
- {R, []}
- end,
- case Interceptors of
- {portable, _PI} ->
- Reply;
- {native, Refs, PI} ->
- orber_pi:in_reply(PI, ObjKey,
- ReplyHeader#reply_header.service_context,
- Op, Refs, Reply)
- end.
-
-%% "Plain" TCP/IP.
-connect(Host, Port, Objkey, Timeout, Index,
- #host_data{protocol = normal, csiv2_mech = undefined} = HostData,
- TaggedProfile, IOR, Ctx) ->
- connect2([{Host, Port}], Objkey, Timeout, Index, HostData,
- TaggedProfile, IOR, Ctx);
-%% "Plain" SSL
-connect(Host, _, Objkey, Timeout, Index,
- #host_data{protocol = ssl,
- ssl_data = #'SSLIOP_SSL'{port = Port},
- csiv2_mech = undefined} = HostData,
- TaggedProfile, IOR, Ctx) ->
- connect2([{Host, Port}], Objkey, Timeout, Index, HostData,
- TaggedProfile, IOR, Ctx);
-%% TEMPORARY FIX TO AVOID RUNNING CSIv2.
-connect(Host, _, Objkey, Timeout, Index,
- #host_data{protocol = ssl,
- ssl_data = #'SSLIOP_SSL'{port = Port}} = HostData,
- TaggedProfile, IOR, Ctx) ->
- connect2([{Host, Port}], Objkey, Timeout, Index, HostData,
- TaggedProfile, IOR, Ctx);
-%% CSIv2 over SSL (TAG_TLS_SEC_TRANS) using the SAS protocol. Note port must equal 0.
-connect(_Host, 0, Objkey, Timeout, Index,
- #host_data{protocol = ssl,
- csiv2_mech =
- #'CSIIOP_CompoundSecMech'{target_requires = _TR} = _Mech,
- csiv2_addresses = Addresses} = HostData,
- TaggedProfile, IOR, Ctx) ->
- NewCtx = [#'IOP_ServiceContext'
- {context_id=?IOP_SecurityAttributeService,
- context_data = #'CSI_SASContextBody'
- {label = ?CSI_MsgType_MTEstablishContext,
- value = #'CSI_EstablishContext'
- {client_context_id = 0, %% Always 0 when stateless.
- authorization_token =
- [#'CSI_AuthorizationElement'{the_element = []}],
- identity_token =
- #'CSI_IdentityToken'{label = ?CSI_IdentityTokenType_ITTAbsent,
- value = true},
- client_authentication_token = []}}}|Ctx],
- connect2(Addresses, Objkey, Timeout, Index, HostData,
- TaggedProfile, IOR, NewCtx);
-%% CSIv2 over SSL (TAG_NULL_TAG) using the SAS protocol.
-connect(Host, _, Objkey, Timeout, Index,
- #host_data{protocol = ssl,
- ssl_data = #'SSLIOP_SSL'{port = Port},
- csiv2_mech = Mech} = HostData,
- TaggedProfile, IOR, Ctx) when is_record(Mech, 'CSIIOP_CompoundSecMech') ->
- connect2([{Host, Port}], Objkey, Timeout, Index, HostData,
- TaggedProfile, IOR, Ctx);
-%% CSIv2 over TCP (TAG_NULL_TAG) using the SAS protocol.
-connect(Host, Port, Objkey, Timeout, Index,
- #host_data{protocol = normal,
- csiv2_mech = Mech} = HostData,
- TaggedProfile, IOR, Ctx) when is_record(Mech, 'CSIIOP_CompoundSecMech') ->
- connect2([{Host, Port}], Objkey, Timeout, Index, HostData,
- TaggedProfile, IOR, Ctx);
-connect(_Host, _Port, _Objkey, _Timeout, _Index, HostData, _TaggedProfile,
- IOR, _Ctx) ->
- orber:dbg("[~p] orber_iiop:connect(~p)~n"
- "Unable to use the supplied IOR.~n"
- "Connection Data: ~p", [?LINE, IOR, HostData], ?DEBUG_LEVEL),
- corba:raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO}).
-
-
-
-connect2(HostPort, Objkey, Timeout, Index, HostData, TaggedProfile, IOR, Ctx) ->
- case try_connect(HostPort, HostData#host_data.protocol, Timeout, HostData, Ctx) of
- error ->
- Alts = iop_ior:get_alt_addr(TaggedProfile),
- case try_connect(Alts, HostData#host_data.protocol, Timeout, HostData, Ctx) of
- error ->
- case iop_ior:get_key(IOR, Index) of
- undefined ->
- corba:raise(#'COMM_FAILURE'{completion_status = ?COMPLETED_NO});
- {'external', {NewHost, NewPort, NewObjkey, NewIndex,
- NewTaggedProfile, NewHostData}} ->
- connect(NewHost, NewPort, NewObjkey, Timeout, [NewIndex|Index],
- NewHostData, NewTaggedProfile, IOR, Ctx);
- _What ->
- orber:dbg("[~p] orber_iiop:connect2(~p)~n"
- "Illegal IOR; contains a mixture of local and external profiles.",
- [?LINE, IOR], ?DEBUG_LEVEL),
- corba:raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO})
- end;
- X ->
- {X, Objkey, HostData#host_data.version}
- end;
- X ->
- {X, Objkey, HostData#host_data.version}
- end.
-
-try_connect([], _, _, _, _) ->
- error;
-try_connect([{Host, Port}|T], SocketType, Timeout, HostData, Ctx) ->
- case catch orber_iiop_pm:connect(Host, Port, SocketType, Timeout,
- HostData#host_data.charset,
- HostData#host_data.wcharset, Ctx) of
- {ok, P, Ctx2, Int, Interface} ->
- {P, Ctx2, Int, Interface};
- {'EXCEPTION', #'BAD_CONTEXT'{} = CtxExc} ->
- orber:dbg("[~p] orber_iiop:try_connect(~p, ~p) failed~n",
- [?LINE, Host, Port], ?DEBUG_LEVEL),
- corba:raise(CtxExc);
- {'EXCEPTION', _PMExc} ->
- try_connect(T, SocketType, Timeout, HostData, Ctx);
- {'EXIT',{timeout,_}} ->
- orber:dbg("[~p] orber_iiop:try_connect(~p, ~p, ~p)~n"
- "Connect attempt timed out",
- [?LINE, Host, Port, Timeout], ?DEBUG_LEVEL),
- try_connect(T, SocketType, Timeout, HostData, Ctx);
- {'EXIT', What} ->
- orber:dbg("[~p] orber_iiop:try_connect(~p, ~p, ~p)~n"
- "Connect attempt resulted in: ~p",
- [?LINE, Host, Port, Timeout, What], ?DEBUG_LEVEL),
- try_connect(T, SocketType, Timeout, HostData, Ctx)
- end.
-
diff --git a/lib/orber/src/orber_iiop.hrl b/lib/orber/src/orber_iiop.hrl
deleted file mode 100644
index ec502b6f09..0000000000
--- a/lib/orber/src/orber_iiop.hrl
+++ /dev/null
@@ -1,1016 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File: orber_iiop.hrl
-%%
-%%----------------------------------------------------------------------
--ifndef(orber_iiop_hrl).
--define(orber_iiop_hrl, true).
-
--include_lib("orber/include/corba.hrl").
-
-%% The identifiers which indicates if a fixed value has a negative or
-%% positive scale.
--define(FIXED_NEGATIVE, 13).
--define(FIXED_POSITIVE, 12).
-
-%% Used instead of IFR-id's in TypeCode definitions for internal data types.
--define(SYSTEM_TYPE, 0).
-
-%% Major version of GIOP protocol which are supported
--define(GIOP_MAJOR, 1).
-
-%% Minor version of GIOP protocol which are supported
--define(GIOP_MINOR, 0).
-
-%% Major version of IIOP protocol which are supported
--define(IIOP_MAJOR, 1).
-
-%% Minor version of IIOP protocol which are supported
--define(IIOP_MINOR, 0).
-
-%% Fragment flags for the flags bitfield in GIOP message headers
--define(GIOP_BYTE_ORDER_MSB, 0).
--define(GIOP_BYTE_ORDER_LSB, 1).
-
-%% Fragment flags for the flags bitfield in GIOP message headers
--define(GIOP_MORE_FRAGMENTS_FALSE, 0).
--define(GIOP_MORE_FRAGMENTS_TRUE, 1).
-
-%% GIOP Message Types
--define(GIOP_MSG_REQUEST, 0).
--define(GIOP_MSG_REPLY, 1).
--define(GIOP_MSG_CANCEL_REQUEST, 2).
--define(GIOP_MSG_LOCATE_REQUEST, 3).
--define(GIOP_MSG_LOCATE_REPLY, 4).
--define(GIOP_MSG_CLOSE_CONNECTION, 5).
--define(GIOP_MSG_MESSAGE_ERROR, 6).
--define(GIOP_MSG_FRAGMENT, 7).
-
-%% PROFILE_ID's
--define(TAG_INTERNET_IOP, 0).
--define(TAG_MULTIPLE_COMPONENTS, 1).
--define(TAG_SCCP_IOP, 2).
-
-
-%% COMPONENT_ID's
--define(TAG_ORB_TYPE, 0).
--define(TAG_CODE_SETS, 1).
--define(TAG_POLICIES, 2).
--define(TAG_ALTERNATE_IIOP_ADDRESS, 3).
--define(TAG_COMPLETE_OBJECT_KEY, 5).
--define(TAG_ENDPOINT_ID_POSITION, 6).
--define(TAG_LOCATION_POLICY, 12).
--define(TAG_ASSOCIATION_OPTIONS, 13).
--define(TAG_SEC_NAME, 14).
--define(TAG_SPKM_1_SEC_MECH, 15).
--define(TAG_SPKM_2_SEC_MECH, 16).
--define(TAG_KerberosV5_SEC_MECH, 17).
--define(TAG_CSI_ECMA_Secret_SEC_MECH, 18).
--define(TAG_CSI_ECMA_Hybrid_SEC_MECH, 19).
--define(TAG_SSL_SEC_TRANS, 20).
--define(TAG_CSI_ECMA_Public_SEC_MECH, 21).
--define(TAG_GENERIC_SEC_MECH, 22).
--define(TAG_FIREWALL_TRANS, 23).
--define(TAG_SCCP_CONTACT_INFO, 24).
--define(TAG_JAVA_CODEBASE, 25).
--define(TAG_TRANSACTION_POLICY, 26).
--define(TAG_FT_GROUP, 27).
--define(TAG_FT_PRIMARY, 28).
--define(TAG_FT_HEARTBEAT_ENABLED, 29).
--define(TAG_MESSAGE_ROUTERS, 30).
--define(TAG_OTS_POLICY, 31).
--define(TAG_INV_POLICY, 32).
--define(TAG_CSI_SEC_MECH_LIST, 33).
--define(TAG_NULL_TAG, 34).
--define(TAG_SECIOP_SEC_TRANS, 35).
--define(TAG_TLS_SEC_TRANS, 36).
--define(TAG_DCE_STRING_BINDING, 100).
--define(TAG_DCE_BINDING_NAME, 101).
--define(TAG_DCE_NO_PIPES, 102).
--define(TAG_DCE_SEC_MECH, 103).
--define(TAG_INET_SEC_TRANS, 123).
-
-%% COMPONENT_ID strings
--define(TAG_ORB_TYPE_STR, "TAG_ORB_TYPE").
--define(TAG_CODE_SETS_STR, "TAG_CODE_SETS").
--define(TAG_POLICIES_STR, "TAG_POLICIES").
--define(TAG_ALTERNATE_IIOP_ADDRESS_STR, "TAG_ALTERNATE_IIOP_ADDRESS").
--define(TAG_COMPLETE_OBJECT_KEY_STR, "TAG_COMPLETE_OBJECT_KEY").
--define(TAG_ENDPOINT_ID_POSITION_STR, "TAG_ENDPOINT_ID_POSITION").
--define(TAG_LOCATION_POLICY_STR, "TAG_LOCATION_POLICY").
--define(TAG_ASSOCIATION_OPTIONS_STR, "TAG_ASSOCIATION_OPTIONS").
--define(TAG_SEC_NAME_STR, "TAG_SEC_NAME").
--define(TAG_SPKM_1_SEC_MECH_STR, "TAG_SPKM_1_SEC_MECH").
--define(TAG_SPKM_2_SEC_MECH_STR, "TAG_SPKM_2_SEC_MECH").
--define(TAG_KerberosV5_SEC_MECH_STR, "TAG_KerberosV5_SEC_MECH").
--define(TAG_CSI_ECMA_Secret_SEC_MECH_STR, "TAG_CSI_ECMA_Secret_SEC_MECH").
--define(TAG_CSI_ECMA_Hybrid_SEC_MECH_STR, "TAG_CSI_ECMA_Hybrid_SEC_MECH").
--define(TAG_SSL_SEC_TRANS_STR, "TAG_SSL_SEC_TRANS").
--define(TAG_CSI_ECMA_Public_SEC_MECH_STR, "(TAG_CSI_ECMA_Public_SEC_MECH").
--define(TAG_GENERIC_SEC_MECH_STR, "TAG_GENERIC_SEC_MECH").
--define(TAG_FIREWALL_TRANS_STR, "TAG_FIREWALL_TRANS").
--define(TAG_SCCP_CONTACT_INFO_STR, "TAG_SCCP_CONTACT_INFO").
--define(TAG_JAVA_CODEBASE_STR, "TAG_JAVA_CODEBASE").
--define(TAG_TRANSACTION_POLICY_STR, "TAG_TRANSACTION_POLICY").
--define(TAG_FT_GROUP_STR, "TAG_FT_GROUP").
--define(TAG_FT_PRIMARY_STR, "TAG_FT_PRIMARY").
--define(TAG_FT_HEARTBEAT_ENABLED_STR, "TAG_FT_HEARTBEAT_ENABLED").
--define(TAG_MESSAGE_ROUTERS_STR, "TAG_MESSAGE_ROUTERS").
--define(TAG_OTS_POLICY_STR, "TAG_OTS_POLICY").
--define(TAG_INV_POLICY_STR, "TAG_INV_POLICY").
--define(TAG_CSI_SEC_MECH_LIST_STR, "TAG_CSI_SEC_MECH_LIST").
--define(TAG_NULL_TAG_STR, "TAG_NULL_TAG").
--define(TAG_SECIOP_SEC_TRANS_STR, "TAG_SECIOP_SEC_TRANS").
--define(TAG_TLS_SEC_TRANS_STR, "TAG_TLS_SEC_TRANS").
--define(TAG_DCE_STRING_BINDING_STR, "TAG_DCE_STRING_BINDING").
--define(TAG_DCE_BINDING_NAME_STR, "TAG_DCE_BINDING_NAME").
--define(TAG_DCE_NO_PIPES_STR, "TAG_DCE_NO_PIPES").
--define(TAG_DCE_SEC_MECH_STR, "TAG_DCE_SEC_MECH").
--define(TAG_INET_SEC_TRANS_STR, "TAG_INET_SEC_TRANS").
-
-%% GIOP header size
--define(GIOP_HEADER_SIZE, 12).
-
-%% CODESET's we support.
-%% Latin-1. This CodeSet is default if no information exists in the IOR.
--define(ISO8859_1_ID, 16#00010001).
-
-%% UTF-16, UCS Transformation Format 16-bit form
--define(UTF_16_ID, 16#00010109).
-
-%% X/Open UTF-8; UCS Transformation Format 8 (UTF-8)
--define(UTF_8_ID, 16#05010001).
-
-%% The limited UTF-16 without the surrogate mechanism is called UCS-2.
-%% The two-byte subset which is identical with the original Unicode.
-%% UCS-2, Level 1. Used by JDK-1.3 as native wchar.
--define(UCS_2_ID, 16#00010100).
-
-%% ISO 646:1991 IRV (International Reference Version).
-%% Used by JavaIDL as Native Char (JDK-1.3). A.k.a PCS.
--define(ISO646_IRV_ID, 16#00010020).
-
-%% Fallback is *not* the same thing as default!!
--define(FALLBACK_CHAR, 16#05010001).
--define(FALLBACK_WCHAR, 16#00010109).
-
-%% This is used when the wchar codeset is unknown.
--define(UNSUPPORTED_WCHAR, 0).
-
-%% Integer limits
--define(SHORTMIN, -32768).
--define(SHORTMAX, 32767).
--define(USHORTMIN, 0).
--define(USHORTMAX, 65535).
--define(LONGMIN, -2147483648).
--define(LONGMAX, 2147483647).
--define(ULONGMIN, 0).
--define(ULONGMAX, 4294967295).
--define(LONGLONGMIN, -9223372036854775808).
--define(LONGLONGMAX, 9223372036854775807).
--define(ULONGLONGMIN, 0).
--define(ULONGLONGMAX, 18446744073709551615).
-
-
--define(ORBER_GENERIC_CTX, {'tk_sequence', 'tk_octet', 0}).
-
-
-%%----------------------------------------------------------------------
-%% GIOP Message Header
-%%
-%% magic: identifies the GIOP message headers, array of four characters.
-%% giop_version: contains the version number of the giop protocol being
-%% used in the message.
-%% byte_order: indicating the byte order being used in subsequent
-%% elements of the message.
-%% 0 - big-endian byte ordering, 1 - little-endian byte ordering
-%% fragments: true if more fragments follow, otherwise false.
-%% message_type: indicating the type of the message
-%% message_size: gives the length of the message following the message
-%% headerin octets.
-%%----------------------------------------------------------------------
--record(giop_message, {magic,
- giop_version,
- byte_order,
- fragments = false,
- message_type,
- message_size,
- message}).
-
-
-
-%%----------------------------------------------------------------------
-%% Request Message Header
-%%
-%% service_context: contains ORB service data being passed from client to server.
-%% (IOP::ServiceContextList)
-%% request_id: id used to assosciate reply messages with request messages.
-%% response_expected: true if the request is expected to have a reply message.
-%% object_key: identifies the object wich is the target of the invocation.
-%% operation: contains the name of the operation being invoked.
-%% requesting_principal: contains a value that identifying the requesting
-%% principal.
-%%----------------------------------------------------------------------
--record(request_header, {service_context, request_id, response_expected, object_key, operation, requesting_principal}).
-
-
-
-%%----------------------------------------------------------------------
-%% Reply Message Header
-%%
-%% service_context: contains ORB service data being passed from client to server.
-%% (IOP::ServiceContextList)
-%% request_id: id used to assosciate reply messages with request messages.
-%% reply_status: indicates the completion status of the request
-%%----------------------------------------------------------------------
--record(reply_header, {service_context, request_id, reply_status}).
-
-
-
-%%----------------------------------------------------------------------
-%% Cancel Request Message Header
-%%
-%% request_id: id used to assosciate reply messages with request messages.
-%%----------------------------------------------------------------------
--record(cancel_request_header, {request_id}).
-
-
-
-%%----------------------------------------------------------------------
-%% Locate Request Message Header
-%%
-%% request_id: id used to assosciate reply messages with request messages.
-%% object_key: identifies the object being located (octet sequence).
-%%----------------------------------------------------------------------
--record(locate_request_header, {request_id, object_key}).
-
-
-
-%%----------------------------------------------------------------------
-%% Locate Reply Message Header
-%%
-%% request_id: id used to assosciate reply messages with request messages.
-%% locate_status: indicates the completion status of the locate request
-%%----------------------------------------------------------------------
--record(locate_reply_header, {request_id, locate_status}).
-
-
-
-%%----------------------------------------------------------------------
-%% Profile Body
-%%
-%% iiop_version: describes the version of IIOP that the agent at the
-%% specified address is prepared to receive.
-%% host: identifies the internet host to which the GIOP messages
-%% for the specified object may be sent.
-%% port: contains the TCP?IP port number where the target agnet is listening
-%% for connection requests.
-%% object_key: is an opaque value supplied by the agent producing the IOR.
-%%----------------------------------------------------------------------
--record(profile_body, {iiop_version,host,port,object_key}).
-
-%%----------------------------------------------------------------------
-%% Version
-%%
-%% major: major version number of iiop protocol
-%% minor: minor version number of iiop protocol.
-%%
-%% When an agnet generates profiles specifying a particular version,
-%% it must be able to accept messages complying with the specified
-%% version or any porevious minor version.
-%%----------------------------------------------------------------------
--record(version, {major,minor}).
-
-%%----------------------------------------------------------------------
-%% Fragment Message Header
-%%
-%% request_id:
-%%----------------------------------------------------------------------
--record(fragment_header, {request_id}).
-
-
-%%----------------------------------------------------------------------
-%% ORB_FLAGS macros. Used in the local object references {_,_,_,_,_,Flags}.
-%%
-%%----------------------------------------------------------------------
-
-%% Definition of flag positions:
--define(ORB_SEC_ATTRIBUTES, 16#01).
--define(ORB_CONTEXT, 16#02).
--define(ORB_TYPECHECK, 16#04).
--define(ORB_NO_SECURITY, 16#08).
--define(ORB_SURVIVE_EXIT, 16#10).
--define(ORB_USE_PI, 16#20).
-
--define(ORB_INIT_FLAGS, 16#00).
-
-%%----------------------------------------------------------------------
-%% Flags used as configuration parameters (application env).
-%%
-%%----------------------------------------------------------------------
--define(ORB_ENV_EXCLUDE_CODESET_COMPONENT, 16#01). %% FIXED!!
--define(ORB_ENV_LOCAL_TYPECHECKING, 16#02). %% FIXED!!
--define(ORB_ENV_HOSTNAME_IN_IOR, 16#04). %% FIXED!!
--define(ORB_ENV_ENABLE_NAT, 16#08). %% FIXED!!
--define(ORB_ENV_PARTIAL_SECURITY, 16#10). %% FIXED FOR NOW!! INTERNAL
--define(ORB_ENV_USE_PI, 16#20). %% FIXED!!
--define(ORB_ENV_USE_FT, 16#40). %% WILL PROBABLY BE FIXED!!
--define(ORB_ENV_LIGHT_IFR, 16#80). %% FIXED!!
--define(ORB_ENV_USE_IPV6, 16#100). %% FIXED!!
--define(ORB_ENV_SURVIVE_EXIT, 16#200). %% FIXED!!
--define(ORB_ENV_USE_ACL_INCOMING, 16#400). %% FIXED!!
--define(ORB_ENV_USE_ACL_OUTGOING, 16#800). %% FIXED!!
--define(ORB_ENV_LOCAL_INTERFACE, 16#1000). %% FIXED!!
-
--define(ORB_ENV_USE_BI_DIR_IIOP, 16#2000). %% CAN BE CHANGED
--define(ORB_ENV_USE_CSIV2, 16#4000). %% CAN BE CHANGED
--define(ORB_ENV_EXCLUDE_CODESET_CTX, 16#8000). %% CAN BE CHANGED
-
-
--define(ORB_ENV_INIT_FLAGS, 16#00).
-
--define(ORB_ENV_FLAGS,
- [{?ORB_ENV_EXCLUDE_CODESET_CTX, "Exclude CodeSet Ctx"},
- {?ORB_ENV_LOCAL_TYPECHECKING, "Local Typechecking"},
- {?ORB_ENV_HOSTNAME_IN_IOR, "Use Hostname in IOR"},
- {?ORB_ENV_EXCLUDE_CODESET_COMPONENT, "Exclude CodeSet Component"},
- {?ORB_ENV_ENABLE_NAT, "NAT Enabled"},
- {?ORB_ENV_USE_CSIV2, "CSIv2 Activated"},
- {?ORB_ENV_USE_FT, "Fault Tolerance Activated"},
- {?ORB_ENV_USE_IPV6, "IPv6 Activated"},
- {?ORB_ENV_SURVIVE_EXIT, "EXIT Tolerance Activated"},
- {?ORB_ENV_USE_PI, "Local Interceptors"},
- {?ORB_ENV_LIGHT_IFR, "Light IFR"},
- {?ORB_ENV_USE_BI_DIR_IIOP, "Use BiDirIIOP"},
- {?ORB_ENV_USE_ACL_INCOMING, "Use ACL for Incoming Connections"},
- {?ORB_ENV_USE_ACL_OUTGOING, "Use ACL for Outgoing Connections"},
- {?ORB_ENV_LOCAL_INTERFACE, "Use the Proxy Interface in Exported IOR:s"}]).
-
-
-%%----------------------------------------------------------------------
-%% Definition of flag operations
-%%
-%%----------------------------------------------------------------------
-%% USAGE: Boolean = ?ORB_FLAG_TEST(Flags, ?ORB_SEC_ATTRIBUTES)
--define(ORB_FLAG_TEST(_F1, _I1), ((_F1 band _I1) == _I1)).
-
-%% USAGE: NewFlags = ?ORB_SET_TRUE(Flags, ?ORB_CONTEXT)
--define(ORB_SET_TRUE(_F2, _I2), (_I2 bor _F2)).
-
-%% USAGE: NewFlags = ?ORB_SET_FALSE(Flags, ?ORB_CONTEXT)
--define(ORB_SET_FALSE(_F3, _I3), ((_I3 bxor 16#ff) band _F3)).
-
-%% USAGE: NewFlags = ?ORB_SET_FALSE_LIST(Flags, [?ORB_SEC_ATTRIBUTES, ?ORB_SOME])
--define(ORB_SET_FALSE_LIST(_F4, _IList1),
- lists:foldl(fun(_I4, _F5) ->
- ((_I4 bxor 16#ff) band _F5)
- end,
- _F4, _IList1)).
-
-%% USAGE: NewFlags = ?ORB_SET_TRUE_LIST(Flags, [?ORB_SEC_ATTRIBUTES, ?ORB_SOME])
--define(ORB_SET_TRUE_LIST(_F6, _IList2),
- lists:foldl(fun(_I6, _F7) ->
- (_I6 bor _F7)
- end,
- _F6, _IList2)).
-
-%% USAGE: Boolean = ?ORB_FLAG_TEST_LIST(Flags, [?ORB_CONTEXT, ?ORB_THING])
--define(ORB_FLAG_TEST_LIST(_F8, _IList3),
- lists:all(fun(_I7) ->
- ((_F8 band _I7) == _I7)
- end,
- _IList3)).
-
-%%----------------------------------------------------------------------
-%% IOR
-%%
-%%----------------------------------------------------------------------
--record('IOP_IOR', {type_id, profiles}).
--record('IOP_TaggedProfile', {tag, profile_data}).
--record('IIOP_ProfileBody_1_0', {iiop_version,
- host,
- port,
- object_key}).
--record('IIOP_ProfileBody_1_1', {iiop_version,
- host,
- port,
- object_key,
- components}).
-
--record('GIOP_Version', {major, minor}).
-
--record('IIOP_Version', {major, minor}).
-
--record('SSLIOP_SSL', {target_supports, target_requires, port}).
-
--record('IOP_TaggedComponent', {tag, component_data}).
-
--record('GIOP_TargetAddress', {label, value}).
-
--record('GIOP_IORAddressingInfo', {selected_profile_index, ior}).
-
-
-%%
-%% Nil object reference
-%%
--define(ORBER_NIL_OBJREF, #'IOP_IOR' {type_id = "", profiles = []}).
-
--define(IOR_TYPEDEF, {'tk_struct', ?SYSTEM_TYPE, 'IOP_IOR',
- [{"type_id", {'tk_string', 0}},
- {"profiles", {'tk_sequence', {'tk_struct', ?SYSTEM_TYPE,
- 'IOP_TaggedProfile',
- [{"tag", 'tk_ulong'},
- {"profile_data",
- {'tk_sequence', 'tk_octet', 0}}]}, 0}}]}).
-
--define(GIOP_VERSION, {'tk_struct', ?SYSTEM_TYPE, 'GIOP_Version',
- [{"major", 'tk_octet'},
- {"minor", 'tk_octet'}]}).
-
--define(IIOP_VERSION, {'tk_struct', ?SYSTEM_TYPE, 'IIOP_Version',
- [{"major vsn", 'tk_octet'},
- {"minor vsn", 'tk_octet'}]}).
--define(IOP_TAGGEDCOMPONENT, {'tk_struct', ?SYSTEM_TYPE,
- 'IOP_TaggedComponent',
- [{"tag", 'tk_ulong'},
- {"component_data",
- {'tk_sequence',
- 'tk_octet', 0}}]}).
--define(IOP_TAGGEDCOMPONENT_SEQ, {'tk_sequence', ?IOP_TAGGEDCOMPONENT, 0}).
-
--define(PROFILEBODY_1_0_TYPEDEF, {'tk_struct', ?SYSTEM_TYPE, 'IIOP_ProfileBody_1_0',
- [{"iiop_version", ?IIOP_VERSION },
- {"host", {'tk_string', 0}},
- {"port", 'tk_ushort'},
- {"object_key", {'tk_sequence', 'tk_octet', 0}}]}).
-
--define(PROFILEBODY_1_1_TYPEDEF, {'tk_struct', ?SYSTEM_TYPE, 'IIOP_ProfileBody_1_1',
- [{"iiop_version",?IIOP_VERSION },
- {"host", {'tk_string', 0}},
- {"port", 'tk_ushort'},
- {"object_key", {'tk_sequence', 'tk_octet', 0}},
- {"components", ?IOP_TAGGEDCOMPONENT_SEQ}]}).
-
--define(PROFILEBODY_1_2_TYPEDEF, {'tk_struct', ?SYSTEM_TYPE, 'IIOP_ProfileBody_1_1',
- [{"iiop_version",?IIOP_VERSION },
- {"host", {'tk_string', 0}},
- {"port", 'tk_ushort'},
- {"object_key", {'tk_sequence', 'tk_octet', 0}},
- {"components", ?IOP_TAGGEDCOMPONENT_SEQ}]}).
-
--define(SSLIOP_SSL, {'tk_struct', ?SYSTEM_TYPE, 'SSLIOP_SSL',
- [{"target_supports", 'tk_ushort'},
- {"target_requires", 'tk_ushort'},
- {"port", 'tk_ushort'}]}).
-
--define(GIOP_KeyAddr, 0).
--define(GIOP_ProfileAddr, 1).
--define(GIOP_ReferenceAddr, 2).
-
--define(TARGETADDRESS, {'tk_union', ?SYSTEM_TYPE, 'GIOP_TargetAddress', 'tk_short', -1,
- [{?GIOP_KeyAddr, "object_key", {'tk_sequence', 'tk_octet', 0}},
- {?GIOP_ProfileAddr, "profile", {'tk_struct', ?SYSTEM_TYPE,
- 'IOP_TaggedProfile',
- [{"tag", 'tk_ulong'},
- {"profile_data",
- {'tk_sequence', 'tk_octet', 0}}]}},
- {?GIOP_ReferenceAddr, "ior", {'tk_struct', ?SYSTEM_TYPE,
- 'GIOP_IORAddressingInfo',
- [{"selected_profile_index", 'tk_ulong'},
- {"ior", ?IOR_TYPEDEF}]}}]}).
-
-% Zero or more instances of the TAG_ALTERNATE_IIOP_ADDRESS component type
-% may be included in a version 1.2 TAG_INTERNET_IOP Profile.
--record('ALTERNATE_IIOP_ADDRESS', {'HostID', 'Port'}).
--define(ALTERNATE_IIOP_ADDRESS, {'tk_struct', ?SYSTEM_TYPE,
- 'ALTERNATE_IIOP_ADDRESS',
- [{"HostID", {'tk_string', 0}},
- {"Port", 'tk_ushort'}]}).
-% The TAG_ORB_TYPE component can appear at most once in any IOR profile. For
-% profiles supporting IIOP 1.1 or greater, it is optionally present.
--define(ORB_TYPE, 'tk_ulong').
-
--record('CONV_FRAME_CodeSetComponent', {native_code_set, conversion_code_sets}).
--record('CONV_FRAME_CodeSetComponentInfo', {'ForCharData', 'ForWcharData'}).
--define(CONV_FRAME_CODESETCOMPONENT, {'tk_struct', ?SYSTEM_TYPE,
- 'CONV_FRAME_CodeSetComponent',
- [{"native_code_set", 'tk_ulong'},
- {"conversion_code_sets",
- {'tk_sequence', 'tk_ulong', 0}}]}).
--define(CONV_FRAME_CODESETCOMPONENTINFO, {'tk_struct', ?SYSTEM_TYPE,
- 'CONV_FRAME_CodeSetComponentInfo',
- [{"ForCharData",
- ?CONV_FRAME_CODESETCOMPONENT},
- {"ForWcharData",
- ?CONV_FRAME_CODESETCOMPONENT}]}).
-
-
-
-
--define(DEFAULT_FOR_CHAR, #'CONV_FRAME_CodeSetComponent'{native_code_set=?ISO8859_1_ID,
- conversion_code_sets=[]}).
--define(DEFAULT_FOR_WCHAR, #'CONV_FRAME_CodeSetComponent'{native_code_set=?UTF_16_ID,
- conversion_code_sets=[]}).
--define(DEFAULT_CODESETS,
- #'CONV_FRAME_CodeSetComponentInfo'{'ForCharData' = ?DEFAULT_FOR_CHAR,
- 'ForWcharData' = ?DEFAULT_FOR_WCHAR}).
-
-%% Fragmentation - IIOP-1.1 & 1.2
--record('GIOP_FragmentHeader_1_2', {request_id}).
-
--define(GIOP_FragmentHeader_1_2, {'tk_struct', ?SYSTEM_TYPE,
- 'GIOP_FragmentHeader_1_2',
- [{"request_id", 'tk_ulong'}]}).
-
-%%------ MISC Definitions -------
-%% TimeBase::TimeT (TimeBase.idl) is defined as
-%% typedef unsigned long long TimeT;
--define(TimeBase_TimeT, 'tk_ulonglong').
-
-%%------ Fault Tolerant Definitions -------
-
-%% Specification for Interoperable Object Group References
--define(FT_FTDomainId, {'tk_string', 0}).
--define(FT_ObjectGroupId, 'tk_ulonglong').
--define(FT_ObjectGroupRefVersion, 'tk_ulong').
-%% A GIOP::Version of 1.0 indicates that the implementation is compliant
-%% with the CORBA-2.6 specification.
-%% tag = TAG_FT_GROUP
--record('FT_TagFTGroupTaggedComponent', {version = #'GIOP_Version'{major = 1,
- minor = 0},
- ft_domain_id, object_group_id,
- object_group_ref_version}).
--define(FT_TagFTGroupTaggedComponent, {'tk_struct', ?SYSTEM_TYPE, 'FT_TagFTGroupTaggedComponent',
- [{"version", ?GIOP_VERSION},
- {"ft_domain_id", ?FT_FTDomainId},
- {"object_group_id", ?FT_ObjectGroupId},
- {"object_group_ref_version", ?FT_ObjectGroupRefVersion}]}).
-
-%% tag = TAG_FT_PRIMARY;
--record('FT_TagFTPrimaryTaggedComponent', {primary}).
--define(FT_TagFTPrimaryTaggedComponent, {'tk_struct', ?SYSTEM_TYPE, 'FT_TagFTPrimaryTaggedComponent',
- [{"primary", 'tk_boolean'}]}).
-
-
-%% Specification for Most Recent Object Group Reference
-%% context_id = FT_GROUP_VERSION;
--record('FT_FTGroupVersionServiceContext', {object_group_ref_version}).
--define(FT_FTGroupVersionServiceContext, {'tk_struct', ?SYSTEM_TYPE, 'FT_FTGroupVersionServiceContext',
- [{"object_group_ref_version", ?FT_ObjectGroupRefVersion}]}).
-
-%% Specification for Transparent Reinvocation
--define(FT_PolicyType_REQUEST_DURATION_POLICY, 47).
-
-%% context_id = FT_REQUEST
--record('FT_FTRequestServiceContext', {client_id, retention_id, expiration_time}).
--define(FT_FTRequestServiceContext, {'tk_struct', ?SYSTEM_TYPE, 'FT_FTRequestServiceContext',
- [{"client_id", {'tk_string', 0}},
- {"retention_id", 'tk_long'},
- {"expiration_time", ?TimeBase_TimeT}]}).
-
-%% Specification for Transport Heartbeats
--define(FT_PolicyType_HEARTBEAT_POLICY, 48).
--define(FT_PolicyType_HEARTBEAT_ENABLED_POLICY, 49).
-
-%% tag = TAG_FT_HEARTBEAT_ENABLED;
--record('FT_TagFTHeartbeatEnabledTaggedComponent', {heartbeat_enabled}).
--define(FT_TagFTHeartbeatEnabledTaggedComponent, {'tk_struct', ?SYSTEM_TYPE, 'FT_TagFTHeartbeatEnabledTaggedComponent',
- [{"heartbeat_enabled", 'tk_boolean'}]}).
-
-
-%%------ CSI stuff - required by the SAS protocol. -------
-%% This constant defines the current level we support.
--define(CSIv2_MAX_TARGET_REQUIRES, 16#488).
-
-%% NOTE! The OMG VMCID is incorrect in the SAS specification, should be
-%% OMGVMCID = 0x4f4d0000;
--define(CSI_OMGVMCID, ?CORBA_OMGVMCID).
-
-%% ASN.1 Encoding of an OBJECT IDENTIFIER
--define(CSI_OID, {'tk_sequence', 'tk_octet', 0}).
--define(CSI_OIDList, {'tk_sequence', ?CSI_OID, 0}).
-
-%% An X509CertificateChain contains an ASN.1 BER encoded SEQUENCE
-%% [1..MAX] OF X.509 certificates encapsulated in a sequence of octets. The
-%% subject:s certificate shall come first in the list. Each following
-%% certificate shall directly certify the one preceding it. The ASN.1
-%% representation of Certificate is as defined in [IETF RFC 2459].
--define(CSI_X509CertificateChain, {'tk_sequence', 'tk_octet', 0}).
-
-%% an X.501 type name or Distinguished Name encapsulated in a sequence of
-%% octets containing the ASN.1 encoding.
--define(CSI_X501DistinguishedName, {'tk_sequence', 'tk_octet', 0}).
-
-%% UTF-8 Encoding of String
--define(CSI_UTF8String, {'tk_sequence', 'tk_octet', 0}).
-
-%% A sequence of octets containing a GSStoken. Initial context tokens are
-%% ASN.1 encoded as defined in [IETF RFC 2743] Section 3.1,
-%% "Mechanism-Independent token Format", pp. 81-82. Initial context tokens
-%% contain an ASN.1 tag followed by a token length, a mechanism identifier,
-%% and a mechanism-specific token (i.e. a GSSUP::InitialContextToken). The
-%% encoding of all other GSS tokens (e.g. error tokens and final context
-%% tokens) is mechanism dependent.
--define(CSI_GSSToken, {'tk_sequence', 'tk_octet', 0}).
-
-%% An encoding of a GSS Mechanism-Independent Exported Name Object as
-%% defined in [IETF RFC 2743] Section 3.2, "GSS Mechanism-Independent
-%% Exported Name Object Format," p. 84.
--define(CSI_GSS_NT_ExportedName, {'tk_sequence', 'tk_octet', 0}).
--define(CSI_GSS_NT_ExportedNameList, {'tk_sequence', ?CSI_GSS_NT_ExportedName, 0}).
-
-%% The MsgType enumeration defines the complete set of service context
-%% message types used by the CSI context management protocols, including
-%% those message types pertaining only to the stateful application of the
-%% protocols (to insure proper alignment of the identifiers between
-%% stateless and stateful implementations). Specifically, the
-%% MTMessageInContext is not sent by stateless clients (although it may
-%% be received by stateless targets).
--define(CSI_MsgType, 'tk_short').
--define(CSI_MsgType_MTEstablishContext, 0).
--define(CSI_MsgType_MTCompleteEstablishContext, 1).
--define(CSI_MsgType_MTContextError, 4).
--define(CSI_MsgType_MTMessageInContext, 5).
-
-%% The ContextId type is used carry session identifiers. A stateless
-%% application of the service context protocol is indicated by a session
-%% identifier value of 0.
--define(CSI_ContextId, 'tk_ulonglong').
-
-%% The AuthorizationElementType defines the contents and encoding of
-%% the_element field of the AuthorizationElement.
-%% The high order 20-bits of each AuthorizationElementType constant
-%% shall contain the Vendor Minor Codeset ID (VMCID) of the
-%% organization that defined the element type. The low order 12 bits
-%% shall contain the organization-scoped element type identifier. The
-%% high-order 20 bits of all element types defined by the OMG shall
-%% contain the VMCID allocated to the OMG (that is, 0x4F4D0).
--define(CSI_AuthorizationElementType, 'tk_ulong').
-
-%% An AuthorizationElementType of X509AttributeCertChain indicates that
-%% the_element field of the AuthorizationElement contains an ASN.1 BER
-%% SEQUENCE composed of an (X.509) AttributeCertificate followed by a
-%% SEQUENCE OF (X.509) Certificate. The two-part SEQUENCE is encapsulated
-%% in an octet stream. The chain of identity certificates is provided
-%% to certify the attribute certificate. Each certificate in the chain
-%% shall directly certify the one preceding it. The first certificate
-%% in the chain shall certify the attribute certificate. The ASN.1
-%% representation of (X.509) Certificate is as defined in [IETF RFC 2459].
-%% The ASN.1 representation of (X.509) AtributeCertificate is as defined
-%% in [IETF ID PKIXAC].
--define(CSI_X509AttributeCertChain, (?CSI_OMGVMCID bor 1)).
--define(CSI_AuthorizationElementContents, {'tk_sequence', 'tk_octet', 0}).
-
-%% The AuthorizationElement contains one element of an authorization token.
-%% Each element of an authorization token is logically a PAC.
-%% The AuthorizationToken is made up of a sequence of AuthorizationElements
-%% --- NOTE ---
-%% OMG only defines 'CSI_X509AttributeCertChain' so we use it as default value.
--record('CSI_AuthorizationElement', {the_type = ?CSI_X509AttributeCertChain,
- the_element = []}).
--define(CSIIOP_AuthorizationElement, {'tk_struct', ?SYSTEM_TYPE, 'CSI_AuthorizationElement',
- [{"the_type", ?CSI_AuthorizationElementType},
- {"the_element", ?CSI_AuthorizationElementContents}]}).
--define(CSI_AuthorizationToken, {'tk_sequence', ?CSIIOP_AuthorizationElement, 0}).
-
-%% Additional standard identity token types shall only be defined by the
-%% OMG. All IdentityTokenType constants shall be a power of 2.
--define(CSI_IdentityTokenType, 'tk_ulong').
--define(CSI_IdentityTokenType_ITTAbsent, 0).
--define(CSI_IdentityTokenType_ITTAnonymous, 1).
--define(CSI_IdentityTokenType_ITTPrincipalName, 2).
--define(CSI_IdentityTokenType_ITTX509CertChain, 4).
--define(CSI_IdentityTokenType_ITTDistinguishedName, 8).
-
--define(CSI_IdentityExtension, {'tk_sequence', 'tk_octet', 0}).
--record('CSI_IdentityToken', {label, value}).
--define(CSI_IdentityToken,
- {'tk_union', ?SYSTEM_TYPE, 'CSI_IdentityToken',
- ?CSI_IdentityTokenType, 5,
- [{?CSI_IdentityTokenType_ITTAbsent, "absent", 'tk_boolean'},
- {?CSI_IdentityTokenType_ITTAnonymous, "anonymous", 'tk_boolean'},
- {?CSI_IdentityTokenType_ITTPrincipalName, "principal_name", ?CSI_GSS_NT_ExportedName},
- {?CSI_IdentityTokenType_ITTX509CertChain, "certificate_chain", ?CSI_X509CertificateChain},
- {?CSI_IdentityTokenType_ITTDistinguishedName, "dn", ?CSI_X501DistinguishedName},
- {default, "id", ?CSI_IdentityExtension}]}).
-
--record('CSI_EstablishContext', {client_context_id, authorization_token,
- identity_token, client_authentication_token}).
--define(CSI_EstablishContext, {'tk_struct', ?SYSTEM_TYPE, 'CSI_EstablishContext',
- [{"client_context_id", ?CSI_ContextId},
- {"authorization_token", ?CSI_AuthorizationToken},
- {"identity_token", ?CSI_IdentityToken},
- {"client_authentication_token", ?CSI_GSSToken}]}).
-
--record('CSI_CompleteEstablishContext', {client_context_id, context_stateful,
- final_context_token}).
--define(CSI_CompleteEstablishContext, {'tk_struct', ?SYSTEM_TYPE, 'CSI_CompleteEstablishContext',
- [{"client_context_id", ?CSI_ContextId},
- {"context_stateful", 'tk_boolean'},
- {"final_context_token", ?CSI_GSSToken}]}).
-
--record('CSI_ContextError', {client_context_id, major_status,
- minor_status, error_token}).
--define(CSI_ContextError, {'tk_struct', ?SYSTEM_TYPE, 'CSI_ContextError',
- [{"client_context_id", ?CSI_ContextId},
- {"major_status", 'tk_long'},
- {"minor_status", 'tk_long'},
- {"error_token", ?CSI_GSSToken}]}).
-
-% Not sent by stateless clients. If received by a stateless server, a
-% ContextError message should be returned, indicating the session does
-% not exist.
--record('CSI_MessageInContext', {client_context_id, discard_context}).
--define(CSI_MessageInContext, {'tk_struct', ?SYSTEM_TYPE, 'CSI_MessageInContext',
- [{"client_context_id", ?CSI_ContextId},
- {"discard_context", 'tk_boolean'}]}).
-
--record('CSI_SASContextBody', {label, value}).
--define(CSI_SASContextBody,
- {'tk_union', ?SYSTEM_TYPE, 'CSI_SASContextBody', ?CSI_MsgType, -1,
- [{?CSI_MsgType_MTEstablishContext, "establish_msg", ?CSI_EstablishContext},
- {?CSI_MsgType_MTCompleteEstablishContext, "complete_msg", ?CSI_CompleteEstablishContext},
- {?CSI_MsgType_MTContextError, "error_msg", ?CSI_ContextError},
- {?CSI_MsgType_MTMessageInContext, "in_context_msg", ?CSI_MessageInContext}]}).
-
-%% The following type represents the string representation of an ASN.1
-%% OBJECT IDENTIFIER (OID). OIDs are represented by the string "oid:"
-%% followed by the integer base 10 representation of the OID separated
-%% by dots. For example, the OID corresponding to the OMG is represented
-%% as: "oid:2.23.130"
--define(CSI_StringOID, {'tk_string', 0}).
-
-
-%% The GSS Object Identifier for the KRB5 mechanism is:
-%% { iso(1) member-body(2) United States(840) mit(113554) infosys(1)
-%% gssapi(2) krb5(2) }
-%% Type ?CSI_StringOID
--define(CSI_KRB5MechOID, "oid:1.2.840.113554.1.2.2").
-
-%% The GSS Object Identifier for name objects of the Mechanism-independent
-%% Exported Name Object type is:
-%% { iso(1) org(3) dod(6) internet(1) security(5) nametypes(6)
-%% gss-api-exported-name(4) }
-%% Type ?CSI_StringOID
--define(CSI_GSS_NT_Export_Name_OID, "oid:1.3.6.1.5.6.4").
-
-%% The GSS Object Identifier for the scoped-username name form is:
-%% { iso-itu-t (2) international-organization (23) omg (130) security (1)
-%% naming (2) scoped-username(1) }
-%% Type ?CSI_StringOID
--define(CSI_GSS_NT_Scoped_Username_OID, "oid:2.23.130.1.2.1").
-
-%%------ GSSUP stuff - required by the SAS protocol. -------
-%% The GSS Object Identifier allocated for the username/password mechanism is defined
-%% below.
-%% { iso-itu-t (2) international-organization (23) omg (130)
-%% security (1) authentication (1) gssup-mechanism (1) }
-%% Type ?CSI_StringOID
--define(GSSUP_GSSUPMechOID, "oid:2.23.130.1.1.1").
-
-%% The following structure defines the inner contents of the
-%% username password initial context token. This structure is
-%% CDR encapsulated and appended at the end of the
-%% username/password GSS (initial context) Token.
--record('GSSUP_InitialContextToken', {username, password, target_name}).
--define(GSSUP_InitialContextToken, {'tk_struct', ?SYSTEM_TYPE, 'GSSUP_InitialContextToken',
- [{"username", ?CSI_UTF8String},
- {"password", ?CSI_UTF8String},
- {"target_name", ?CSI_GSS_NT_ExportedName}]}).
-
--define(GSSUP_ErrorCode, 'tk_ulong').
-
-%% GSSUP Mechanism-Specific Error Token
--record('GSSUP_ErrorToken', {error_code}).
--define(GSSUP_ErrorToken, {'tk_struct', ?SYSTEM_TYPE, 'GSSUP_ErrorToken',
- [{"error_code", ?GSSUP_ErrorCode}]}).
-
-%% The context validator has chosen not to reveal the GSSUP
-%% specific cause of the failure.
-%% Type ?GSSUP_ErrorCode
--define(GSSUP_GSS_UP_S_G_UNSPECIFIED, 1).
-
-%% The user identified in the username field of the
-%% GSSUP::InitialContextToken is unknown to the target.
-%% Type ?GSSUP_ErrorCode
--define(GSSUP_GSS_UP_S_G_NOUSER, 2).
-
-%% The password supplied in the GSSUP::InitialContextToken was
-%% incorrect.
-%% Type ?GSSUP_ErrorCode
--define(GSSUP_GSS_UP_S_G_BAD_PASSWORD, 3).
-
-%% The target_name supplied in the GSSUP::InitialContextToken does
-%% not match a target_name in a mechanism definition of the target.
-%% Type ?GSSUP_ErrorCode
--define(GSSUP_GSS_UP_S_G_BAD_TARGET, 4).
-
-
-%%----- CSIIOP stuff - required by the SAS protocol. -----
-
-% AssociationOptions
--define(CSIIOP_AssociationOptions, 'tk_ushort').
-%% AssociationOptions - constant definitions
--define(CSIIOP_AssociationOptions_NoProtection, 1).
--define(CSIIOP_AssociationOptions_Integrity, 2).
--define(CSIIOP_AssociationOptions_Confidentiality, 4).
--define(CSIIOP_AssociationOptions_DetectReplay, 8).
--define(CSIIOP_AssociationOptions_DetectMisordering, 16).
--define(CSIIOP_AssociationOptions_EstablishTrustInTarget, 32).
--define(CSIIOP_AssociationOptions_EstablishTrustInClient, 64).
--define(CSIIOP_AssociationOptions_NoDelegation, 128).
--define(CSIIOP_AssociationOptions_SimpleDelegation, 256).
--define(CSIIOP_AssociationOptions_CompositeDelegation, 512).
--define(CSIIOP_AssociationOptions_IdentityAssertion, 1024).
--define(CSIIOP_AssociationOptions_DelegationByClient, 2048).
-
-%% The high order 20-bits of each ServiceConfigurationSyntax constant
-%% shall contain the Vendor Minor Codeset ID (VMCID) of the
-%% organization that defined the syntax. The low order 12 bits shall
-%% contain the organization-scoped syntax identifier. The high-order 20
-%% bits of all syntaxes defined by the OMG shall contain the VMCID
-%% allocated to the OMG (that is, 0x4F4D0).
-%% NOTE! The OMG VMCID is incorrect in the SAS specification, should be
-%% OMGVMCID = 0x4f4d0000;
--define(CSIIOP_ServiceConfigurationSyntax, 'tk_ulong').
--define(CSIIOP_ServiceConfigurationSyntax_SCS_GeneralNames, (?CSI_OMGVMCID bor 0)).
--define(CSIIOP_ServiceConfigurationSyntax_SCS_GSSExportedName, (?CSI_OMGVMCID bor 1)).
-
--define(CSIIOP_ServiceSpecificName, {'tk_sequence', 'tk_octet', 0}).
-
-%% The name field of the ServiceConfiguration structure identifies a
-%% privilege authority in the format identified in the syntax field. If the
-%% syntax is SCS_GeneralNames, the name field contains an ASN.1 (BER)
-%% SEQUENCE [1..MAX] OF GeneralName, as defined by the type GeneralNames in
-%% [IETF RFC 2459]. If the syntax is SCS_GSSExportedName, the name field
-%% contains a GSS exported name encoded according to the rules in
-%% [IETF RFC 2743] Section 3.2, "Mechanism-Independent Exported Name
-%% Object Format," p. 84 (CORBA-2.6)
--record('CSIIOP_ServiceConfiguration', {syntax, name}).
--define(CSIIOP_ServiceConfiguration, {'tk_struct', ?SYSTEM_TYPE, 'CSIIOP_ServiceConfiguration',
- [{"syntax", ?CSIIOP_ServiceConfigurationSyntax},
- {"name", ?CSIIOP_ServiceSpecificName}]}).
--define(CSIIOP_ServiceConfigurationList, {'tk_sequence', ?CSIIOP_ServiceConfiguration, 0}).
-
-%% The body of the TAG_NULL_TAG component is a sequence of octets of
-%% length 0.
-
-%% type used to define AS layer functionality within a compound mechanism
-%% definition
--record('CSIIOP_AS_ContextSec', {target_supports = 0, target_requires = 0,
- client_authentication_mech, target_name}).
--define(CSIIOP_AS_ContextSec, {'tk_struct', ?SYSTEM_TYPE, 'CSIIOP_AS_ContextSec',
- [{"target_supports", ?CSIIOP_AssociationOptions},
- {"target_requires", ?CSIIOP_AssociationOptions},
- {"client_authentication_mech", ?CSI_OID},
- {"target_name", ?CSI_GSS_NT_ExportedName}]}).
-
-%% type used to define SAS layer functionality within a compound mechanism
-%% definition
--record('CSIIOP_SAS_ContextSec', {target_supports = 0, target_requires = 0,
- privilege_authorities,
- supported_naming_mechanisms,
- supported_identity_types}).
--define(CSIIOP_SAS_ContextSec, {'tk_struct', ?SYSTEM_TYPE, 'CSIIOP_SAS_ContextSec',
- [{"target_supports", ?CSIIOP_AssociationOptions},
- {"target_requires", ?CSIIOP_AssociationOptions},
- {"privilege_authorities", ?CSIIOP_ServiceConfigurationList},
- {"supported_naming_mechanisms", ?CSI_OIDList},
- {"supported_identity_types", ?CSI_IdentityTokenType}]}).
-
-%% Type used in the body of a TAG_CSI_SEC_MECH_LIST component to describe a
-%% compound mechanism
--record('CSIIOP_CompoundSecMech', {target_requires = 0, transport_mech,
- as_context_mech, sas_context_mech}).
--define(CSIIOP_CompoundSecMech, {'tk_struct', ?SYSTEM_TYPE, 'CSIIOP_CompoundSecMech',
- [{"target_requires", ?CSIIOP_AssociationOptions},
- {"transport_mech", ?IOP_TAGGEDCOMPONENT},
- {"as_context_mech", ?CSIIOP_AS_ContextSec},
- {"sas_context_mech", ?CSIIOP_SAS_ContextSec}]}).
--define(CSIIOP_CompoundSecMechanisms, {'tk_sequence', ?CSIIOP_CompoundSecMech, 0}).
-
-%% type corresponding to the body of a TAG_CSI_SEC_MECH_LIST component
--record('CSIIOP_CompoundSecMechList', {stateful = false, mechanism_list}).
--define(CSIIOP_CompoundSecMechList, {'tk_struct', ?SYSTEM_TYPE, 'CSIIOP_CompoundSecMechList',
- [{"stateful", 'tk_boolean'},
- {"mechanism_list", ?CSIIOP_CompoundSecMechanisms}]}).
-%% CSIIOP::TransportAddress
--record('CSIIOP_TransportAddress', {host_name, port}).
--define(CSIIOP_TransportAddress, {'tk_struct', ?SYSTEM_TYPE, 'CSIIOP_TransportAddress',
- [{"host_name", {'tk_string', 0}},
- {"port", 'tk_ushort'}]}).
--define(CSIIOP_TransportAddressList, {'tk_sequence', ?CSIIOP_TransportAddress, 0}).
-
-%% Tagged component (TAG_TLS_SEC_TRANS) for configuring TLS/SSL as a CSIv2
-%% transport mechanism.
--record('CSIIOP_TLS_SEC_TRANS', {target_supports, target_requires, addresses}).
--define(CSIIOP_TLS_SEC_TRANS, {'tk_struct', ?SYSTEM_TYPE, 'CSIIOP_TLS_SEC_TRANS',
- [{"target_supports", ?CSIIOP_AssociationOptions},
- {"target_requires", ?CSIIOP_AssociationOptions},
- {"addresses", ?CSIIOP_TransportAddressList}]}).
-
-%% Tagged component (TAG_SECIOP_SEC_TRANS) for configuring SECIOP as a CSIv2
-%% transport mechanism
--record('CSIIOP_SECIOP_SEC_TRANS', {target_supports = 0, target_requires = 0, mech_oid,
- target_name, addresses}).
--define(CSIIOP_SECIOP_SEC_TRANS, {'tk_struct', ?SYSTEM_TYPE, 'CSIIOP_SECIOP_SEC_TRANS',
- [{"target_supports", ?CSIIOP_AssociationOptions},
- {"target_requires", ?CSIIOP_AssociationOptions},
- {"mech_oid", ?CSI_OID},
- {"target_name", ?CSI_GSS_NT_ExportedName},
- {"addresses", ?CSIIOP_TransportAddressList}]}).
-
-
-%%-- ServiceContext ID's ------------
-%% Describes what type of context included, i.e.,
-%% typedef unsigned long ServiceId;
-%% struct ServiceContext {
-%% ServiceId context_id;
-%% sequence <octet> context_data;
-%% };
-
-%% The record is defined in include/corba.hrl.
-%%-record('IOP_ServiceContext', {context_id, context_data}).
--define(IOP_SERVICECONTEXT, {'tk_sequence',
- {'tk_struct', ?SYSTEM_TYPE, 'IOP_ServiceContext',
- [{"context_id", 'tk_ulong'},
- {"context_data",
- {'tk_sequence', 'tk_octet', 0}}]}, 0}).
-
--record('CONV_FRAME_CodeSetContext', {char_data, wchar_data}).
--define(CONV_FRAME_CODESETCONTEXT, {'tk_struct', ?SYSTEM_TYPE, 'CONV_FRAME_CodeSetContext',
- [{"char_data", 'tk_ulong'},
- {"wchar_data", 'tk_ulong'}]}).
-
-
--record('IIOP_ListenPoint', {host, port}).
--define(IIOP_LISTENPOINT, {'tk_struct', ?SYSTEM_TYPE, 'IIOP_ListenPoint',
- [{"host", {'tk_string', 0}},
- {"port", 'tk_ushort'}]}).
-
--record('IIOP_BiDirIIOPServiceContext', {listen_points}).
--define(IIOP_BIDIRIIOPSERVICECONTEXT,
- {'tk_struct', ?SYSTEM_TYPE, 'IIOP_BiDirIIOPServiceContext',
- [{"listen_points", {'tk_sequence', ?IIOP_LISTENPOINT, 0}}]}).
-
--define(IOP_TransactionService, 0).
--define(IOP_CodeSets, 1).
--define(IOP_ChainBypassCheck, 2).
--define(IOP_ChainBypassInfo, 3).
--define(IOP_LogicalThreadId, 4).
--define(IOP_BI_DIR_IIOP, 5).
--define(IOP_SendingContextRunTime, 6).
--define(IOP_INVOCATION_POLICIES, 7).
--define(IOP_FORWARDED_IDENTITY, 8).
--define(IOP_UnknownExceptionInfo, 9).
--define(IOP_RTCorbaPriority, 10).
--define(IOP_RTCorbaPriorityRange, 11).
--define(IOP_FT_GROUP_VERSION, 12).
--define(IOP_FT_REQUEST, 13).
--define(IOP_ExceptionDetailMessage, 14).
--define(IOP_SecurityAttributeService, 15).
-
-
-
-%%----------------------------------------------------------------------
-%% host_data
-%%----------------------------------------------------------------------
--record(host_data, {protocol = normal, ssl_data, version, csiv2_mech,
- csiv2_statefull = false, csiv2_addresses = [],
- charset = ?ISO8859_1_ID, wcharset = ?UTF_16_ID,
- ft_heartbeat = false, ft_primary = false, ft_domain,
- ft_group, ft_ref_version}).
-
-%%----------------------------------------------------------------------
-%% giop_env
-%%----------------------------------------------------------------------
--record(giop_env, {interceptors, type, version, bytes, ctx = [],
- request_id, op, parameters = [], tc, response_expected,
- objkey, reply_status, result, flags, host, iiop_port,
- iiop_ssl_port, domain, partial_security}).
-
--endif.
-
-%%----------------------------------------------------------------------
-%% END OF MODULE
-%%----------------------------------------------------------------------
diff --git a/lib/orber/src/orber_iiop_inproxy.erl b/lib/orber/src/orber_iiop_inproxy.erl
deleted file mode 100644
index b595586f84..0000000000
--- a/lib/orber/src/orber_iiop_inproxy.erl
+++ /dev/null
@@ -1,399 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: orber_iiop_inproxy.erl
-%%
-%% Description:
-%% This file contains the IIOP "proxy" for incomming connections
-%%
-%%-----------------------------------------------------------------
--module(orber_iiop_inproxy).
-
--behaviour(gen_server).
-
--include_lib("orber/src/orber_iiop.hrl").
--include_lib("orber/include/corba.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([start/0, start/1]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([init/1, handle_call/3, handle_cast/2, handle_info/2,
- code_change/3, terminate/2, post_accept/3, stop/1]).
-
-%%-----------------------------------------------------------------
-%% Macros
-%%-----------------------------------------------------------------
--define(DEBUG_LEVEL, 7).
-
--record(state, {stype, socket, db, timeout, max_fragments,
- max_requests, request_counter = 1, giop_env, peer}).
-
-%%-----------------------------------------------------------------
-%% External interface functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: start/0
-%%-----------------------------------------------------------------
-start() ->
- ignore.
-
-%%-----------------------------------------------------------------
-%% Func: start/1
-%%-----------------------------------------------------------------
-start(Opts) ->
- gen_server:start_link(orber_iiop_inproxy, Opts, []).
-
-post_accept(Pid, ssl, Socket) ->
- (catch gen_server:cast(Pid, {post_accept, ssl, Socket})),
- ok;
-post_accept(_, _, _) ->
- ok.
-
-%%-----------------------------------------------------------------
-%% Internal interface functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: stop/1
-%%-----------------------------------------------------------------
-stop(Pid) ->
- gen_server:cast(Pid, stop).
-
-%%-----------------------------------------------------------------
-%% Server functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: init/1
-%%-----------------------------------------------------------------
-init({connect, Type, Socket, Ref, Options}) ->
- process_flag(trap_exit, true),
- Flags = orber_tb:keysearch(flags, Options, orber_env:get_flags()),
- {Address, Port} = PeerData = orber_socket:peerdata(Type, Socket),
- {LAddress, LPort} = LocalData = orber_socket:sockdata(Type, Socket),
- case {?ORB_FLAG_TEST(Flags, ?ORB_ENV_LOCAL_INTERFACE), LPort} of
- {true, 0} ->
- orber_tb:info("Unable to lookup the local address and port number.~n"
- "Closing the incoming connection.", []),
- ignore;
- _ ->
- orber_iiop_net:add_connection(Socket, Type, PeerData, LocalData, Ref),
- Interceptors =
- case orber_tb:keysearch(interceptors, Options,
- orber_env:get_interceptors()) of
- {native, PIs} ->
- {native, orber_pi:new_in_connection(PIs, Address, Port,
- LAddress, LPort), PIs};
- Other ->
- Other
- end,
- Env =
- case ?ORB_FLAG_TEST(Flags, ?ORB_ENV_LOCAL_INTERFACE) of
- true when Type == ssl ->
- #giop_env{interceptors = Interceptors,
- flags = Flags, host = [LAddress],
- iiop_port =
- orber_tb:keysearch(iiop_port, Options,
- orber_env:iiop_port()),
- iiop_ssl_port = LPort,
- domain = orber:domain(),
- partial_security = orber:partial_security()};
- true ->
- #giop_env{interceptors = Interceptors,
- flags = Flags, host = [LAddress],
- iiop_port = LPort,
- iiop_ssl_port =
- orber_tb:keysearch(iiop_ssl_port, Options,
- orber_env:iiop_ssl_port()),
- domain = orber:domain(),
- partial_security = orber:partial_security()};
- false ->
- case ?ORB_FLAG_TEST(Flags, ?ORB_ENV_ENABLE_NAT) of
- false ->
- #giop_env{interceptors = Interceptors,
- flags = Flags, host = orber:host(),
- iiop_port = orber:iiop_port(),
- iiop_ssl_port = orber:iiop_ssl_port(),
- domain = orber:domain(),
- partial_security = orber:partial_security()};
- true ->
- #giop_env{interceptors = Interceptors,
- flags = Flags,
- host =
- orber_tb:keysearch(nat_ip_address, Options,
- orber_env:nat_host()),
- iiop_port =
- orber_tb:keysearch(nat_iiop_port, Options,
- orber_env:nat_iiop_port()),
- iiop_ssl_port =
- orber_tb:keysearch(nat_iiop_ssl_port, Options,
- orber_env:nat_iiop_ssl_port()),
- domain = orber:domain(),
- partial_security = orber:partial_security()}
- end
- end,
- Timeout = orber_tb:keysearch(iiop_in_connection_timeout, Options,
- orber_env:iiop_in_connection_timeout()),
- MaxFrags = orber_tb:keysearch(iiop_max_fragments, Options,
- orber_env:iiop_max_fragments()),
- MaxRequests = orber_tb:keysearch(iiop_max_in_requests, Options,
- orber_env:iiop_max_in_requests()),
- {ok, #state{stype = Type,
- socket = Socket,
- db = ets:new(orber_incoming_requests, [set]),
- timeout = Timeout,
- max_fragments = MaxFrags,
- max_requests = MaxRequests,
- giop_env = Env, peer = PeerData}, Timeout}
- end.
-
-
-%%-----------------------------------------------------------------
-%% Func: terminate/2
-%%-----------------------------------------------------------------
-%% We may want to kill all proxies before terminating, but the best
-%% option should be to let the requests complete (especially for one-way
-%% functions it's a better alternative.
-terminate(_Reason, #state{db = IncRequests, giop_env = Env}) ->
- ets:delete(IncRequests),
- case Env#giop_env.interceptors of
- false ->
- ok;
- {native, Ref, PIs} ->
- orber_pi:closed_in_connection(PIs, Ref);
- {_Type, _PIs} ->
- ok
- end.
-
-%%-----------------------------------------------------------------
-%% Func: handle_call/3
-%%-----------------------------------------------------------------
-handle_call(stop, _From, State) ->
- {stop, normal, ok, State};
-handle_call(_, _, State) ->
- {noreply, State, State#state.timeout}.
-
-%%-----------------------------------------------------------------
-%% Func: handle_cast/2
-%%-----------------------------------------------------------------
-handle_cast({post_accept, Type, Socket}, State) ->
- Timeout = orber_env:iiop_ssl_accept_timeout(),
- case catch orber_socket:post_accept(Type, Socket, Timeout) of
- ok ->
- {noreply, State};
- _Failed ->
- orber_socket:close(Type, Socket),
- {stop, normal, State}
- end;
-handle_cast(stop, State) ->
- {stop, normal, State};
-handle_cast(_, State) ->
- {noreply, State, State#state.timeout}.
-
-%%-----------------------------------------------------------------
-%% Func: handle_info/2
-%%-----------------------------------------------------------------
-%% Normal invocation
-handle_info({tcp, Socket, Bytes}, State) ->
- handle_msg(normal, Socket, Bytes, State);
-handle_info({ssl, Socket, Bytes}, State) ->
- handle_msg(ssl, Socket, Bytes, State);
-%% Errors, closed connection
-handle_info({tcp_closed, _Socket}, State) ->
- {stop, normal, State};
-handle_info({tcp_error, _Socket, _Reason}, State) ->
- {stop, normal, State};
-handle_info({ssl_closed, _Socket}, State) ->
- {stop, normal, State};
-handle_info({ssl_error, _Socket, _Reason}, State) ->
- {stop, normal, State};
-%% Servant termination.
-handle_info({'EXIT', Pid, normal}, State) ->
- ets:delete(State#state.db, Pid),
- {noreply, decrease_counter(State), State#state.timeout};
-handle_info({message_error, _Pid, ReqId}, State) ->
- ets:delete(State#state.db, ReqId),
- {noreply, State, State#state.timeout};
-handle_info(timeout, State) ->
- case ets:info(State#state.db, size) of
- 0 ->
- %% No pending requests, close the connection.
- {stop, normal, State};
- _Amount ->
- %% Still pending request, cannot close the connection.
- {noreply, State, State#state.timeout}
- end;
-handle_info({reconfigure, Options}, State) ->
- {noreply, update_state(State, Options), State#state.timeout};
-handle_info(_X,State) ->
- {noreply, State, State#state.timeout}.
-
-handle_msg(Type, Socket, Bytes, #state{stype = Type, socket = Socket,
- giop_env = Env} = State) ->
- case catch cdr_decode:dec_giop_message_header(Bytes) of
- %% Only when using IIOP-1.2 may the client send this message.
- %% Introduced in CORBA-2.6
- #giop_message{message_type = ?GIOP_MSG_CLOSE_CONNECTION,
- giop_version = {1,2}} ->
- {stop, normal, State};
- #giop_message{message_type = ?GIOP_MSG_CLOSE_CONNECTION} ->
- {noreply, State, State#state.timeout};
- #giop_message{message_type = ?GIOP_MSG_CANCEL_REQUEST} = GIOPHdr ->
- ReqId = cdr_decode:peek_request_id(GIOPHdr#giop_message.byte_order,
- GIOPHdr#giop_message.message),
- case ets:lookup(State#state.db, ReqId) of
- [{RId, PPid}] ->
- ets:delete(State#state.db, RId),
- PPid ! {self(), cancel_request_header};
- [] ->
- send_msg_error(Type, Socket, Bytes,
- Env#giop_env{version =
- GIOPHdr#giop_message.giop_version},
- "No such request id")
- end,
- {noreply, State, State#state.timeout};
- %% A fragment; we must have received a Request or LocateRequest
- %% with fragment-flag set to true.
- %% We need to decode the header to get the request-id.
- #giop_message{message_type = ?GIOP_MSG_FRAGMENT,
- giop_version = {1,2}} = GIOPHdr ->
- ReqId = cdr_decode:peek_request_id(GIOPHdr#giop_message.byte_order,
- GIOPHdr#giop_message.message),
- case ets:lookup(State#state.db, ReqId) of
- [{_RId, PPid}] when GIOPHdr#giop_message.fragments == true ->
- PPid ! {self(), GIOPHdr};
- [{RId, PPid}] ->
- ets:delete(State#state.db, RId),
- PPid ! {self(), GIOPHdr};
- [] ->
- send_msg_error(Type, Socket, Bytes,
- Env#giop_env{version =
- GIOPHdr#giop_message.giop_version},
- "No such fragment id")
- end,
- {noreply, State, State#state.timeout};
- %% Must be a Request or LocateRequest which have been fragmented.
- %% We need to decode the header to get the request-id.
- #giop_message{fragments = true,
- giop_version = {1,2}} = GIOPHdr ->
- ReqId = cdr_decode:peek_request_id(GIOPHdr#giop_message.byte_order,
- GIOPHdr#giop_message.message),
- Pid =
- orber_iiop_inrequest:
- start_fragment_collector(GIOPHdr, Bytes,
- Type, Socket,
- ReqId, self(),
- State#state.max_fragments,
- Env#giop_env{version = {1,2},
- request_id = ReqId}),
- ets:insert(State#state.db, {Pid, ReqId}),
- ets:insert(State#state.db, {ReqId, Pid}),
- {noreply, increase_counter(State), State#state.timeout};
- GIOPHdr when is_record(GIOPHdr, giop_message) ->
- Pid = orber_iiop_inrequest:start(GIOPHdr, Bytes, Type, Socket,
- Env#giop_env{version =
- GIOPHdr#giop_message.giop_version}),
- ets:insert(State#state.db, {Pid, undefined}),
- {noreply, increase_counter(State), State#state.timeout};
- {'EXIT', message_error} ->
- send_msg_error(Type, Socket, Bytes,
- Env#giop_env{version = orber_env:giop_version()},
- "Unable to decode the GIOP-header"),
- {noreply, State, State#state.timeout}
- end;
-handle_msg(Type, _, Bytes, State) ->
- orber:dbg("[~p] orber_iiop_inproxy:handle_msg(~p);~n"
- "Received a message from a socket of a different type.~n"
- "Should be ~p but was ~p.",
- [?LINE, Bytes, State#state.stype, Type], ?DEBUG_LEVEL),
- {noreply, State, State#state.timeout}.
-
-send_msg_error(Type, Socket, Data, Env, Msg) ->
- orber:dbg("[~p] orber_iiop_inproxy:handle_msg(~p); ~p.",
- [?LINE, Data, Msg], ?DEBUG_LEVEL),
- Reply = cdr_encode:enc_message_error(Env),
- orber_socket:write(Type, Socket, Reply).
-
-increase_counter(#state{max_requests = infinity} = State) ->
- State;
-increase_counter(#state{max_requests = Max,
- request_counter = Counter} = State) when Max > Counter ->
- orber_socket:setopts(State#state.stype, State#state.socket, [{active, once}]),
- State#state{request_counter = Counter + 1};
-increase_counter(State) ->
- State#state{request_counter = State#state.request_counter + 1}.
-
-decrease_counter(#state{max_requests = infinity} = State) ->
- State;
-decrease_counter(#state{max_requests = Max,
- request_counter = Counter} = State) when Max =< Counter ->
- orber_socket:setopts(State#state.stype, State#state.socket, [{active, once}]),
- State#state{request_counter = Counter - 1};
-decrease_counter(State) ->
- State#state{request_counter = State#state.request_counter - 1}.
-
-update_state(#state{giop_env = Env} = State,
- [{interceptors, false}|Options]) ->
- update_state(State#state{giop_env =
- Env#giop_env{interceptors = false}}, Options);
-update_state(#state{giop_env = #giop_env{interceptors = false, host = [SH],
- iiop_port = SP} = Env,
- peer = {PH, PP}, stype = normal} = State,
- [{interceptors, {native, LPIs}}|Options]) ->
- %% No Interceptor(s). Add the same Ref used by the built in interceptors.
- update_state(State#state{giop_env =
- Env#giop_env{interceptors =
- {native, {PH, PP, SH, SP}, LPIs}}},
- Options);
-update_state(#state{giop_env = #giop_env{interceptors = false, host = [SH],
- iiop_ssl_port = SP} = Env,
- peer = {PH, PP}, stype = ssl} = State,
- [{interceptors, {native, LPIs}}|Options]) ->
- %% No Interceptor(s). Add the same Ref used by the built in interceptors.
- update_state(State#state{giop_env =
- Env#giop_env{interceptors =
- {native, {PH, PP, SH, SP}, LPIs}}},
- Options);
-update_state(#state{giop_env = #giop_env{interceptors = {native, Ref, _}} = Env} =
- State,
- [{interceptors, {native, LPIs}}|Options]) ->
- %% Interceptor(s) already in use. We must use the same Ref as before.
- update_state(State#state{giop_env =
- Env#giop_env{interceptors = {native, Ref, LPIs}}},
- Options);
-update_state(State, [H|T]) ->
- orber:dbg("[~p] orber_iiop_inproxy:update_state(~p, ~p)~n"
- "Couldn't change the state.",
- [?LINE, H, State], ?DEBUG_LEVEL),
- update_state(State, T);
-update_state(State, []) ->
- State.
-
-%%-----------------------------------------------------------------
-%% Func: code_change/3
-%%-----------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
diff --git a/lib/orber/src/orber_iiop_inrequest.erl b/lib/orber/src/orber_iiop_inrequest.erl
deleted file mode 100644
index 9d84b63398..0000000000
--- a/lib/orber/src/orber_iiop_inrequest.erl
+++ /dev/null
@@ -1,541 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%--------------------------------------------------------------------
-%% File: orber_iiop_inrequest.erl
-%%
-%% Description:
-%% This file contains the handling of incomming requests
-%%
-%%-----------------------------------------------------------------
--module(orber_iiop_inrequest).
-
--include_lib("orber/src/orber_iiop.hrl").
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/orber_pi.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([start/5, start_fragment_collector/8]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([handle_message/5, fragment_collector/8]).
-
-%%-----------------------------------------------------------------
-%% Macros
-%%-----------------------------------------------------------------
--define(DEBUG_LEVEL, 8).
-
-
-%%-----------------------------------------------------------------
-%% External interface functions
-%%-----------------------------------------------------------------
-start(GIOPHdr, Message, Type, Socket, Env) ->
- spawn_link(orber_iiop_inrequest, handle_message,
- [GIOPHdr, Message, Type, Socket, Env]).
-
-start_fragment_collector(GIOPHdr, Message, Type, Socket, ReqId, Proxy, MaxFrags, Env) ->
- spawn_link(orber_iiop_inrequest, fragment_collector,
- [GIOPHdr, Message, Type, Socket, ReqId, Proxy, MaxFrags, Env]).
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-
-%%-----------------------------------------------------------------
-%% Func: fragment_collector/4
-%%-----------------------------------------------------------------
-fragment_collector(GIOPHdr, Bytes, SocketType, Socket, ReqId, Proxy, MaxFrags, Env) ->
- case catch collect(Proxy, [], GIOPHdr#giop_message.byte_order, ReqId,
- MaxFrags, 0) of
- {ok, Buffer} ->
- NewGIOP = GIOPHdr#giop_message
- {message = list_to_binary([GIOPHdr#giop_message.message|Buffer])},
- %% NOTE, the third argument to dec_message_header must be complete
- %% message (i.e. AllBytes), otherwise we cannot handle indirection.
- case handle_message(NewGIOP, list_to_binary([Bytes| Buffer]),
- SocketType, Socket, Env) of
- message_error ->
- Proxy ! {message_error, self(), ReqId},
- ok;
- _ ->
- ok
- end;
- ok ->
- ok;
- {'EXCEPTION', E} ->
- Proxy ! {message_error, self(), ReqId},
- Reply = marshal_exception(Env, ReqId, E, enc_reply),
- orber_socket:write(SocketType, Socket, Reply)
- end.
-
-
-
-collect(_Proxy, _Buffer, _ByteOrder, _ReqId, MaxFrags, MaxFrags) ->
- orber:dbg("[~p] ~p:collect(~p)~nMax fragments limit reached.",
- [?LINE, ?MODULE, MaxFrags], ?DEBUG_LEVEL),
- {'EXCEPTION', #'IMP_LIMIT'{completion_status=?COMPLETED_NO}};
-collect(Proxy, Buffer, ByteOrder, ReqId, MaxFrags, FragCounter) ->
- receive
- {Proxy, #giop_message{byte_order = ByteOrder,
- message = Message,
- fragments = true} = GIOPHdr} ->
- {_, #fragment_header{request_id=ReqId}, FragBody, _, _} =
- cdr_decode:dec_message_header(null, GIOPHdr, Message),
- collect(Proxy, [FragBody | Buffer], ByteOrder, ReqId,
- MaxFrags, FragCounter+1);
- {Proxy, #giop_message{byte_order = ByteOrder,
- message = Message,
- fragments = false} = GIOPHdr} ->
- {_, #fragment_header{request_id=ReqId}, FragBody, _, _} =
- cdr_decode:dec_message_header(null, GIOPHdr, Message),
- {ok, lists:reverse([FragBody | Buffer])};
- {Proxy, GIOPHdr, _Data, _} ->
- orber:dbg("[~p] orber_iiop_inrequest:collect(~p, ~p)~n"
- "Incorrect Fragment. Might be different byteorder.",
- [?LINE, ByteOrder, GIOPHdr], ?DEBUG_LEVEL),
- {'EXCEPTION', #'MARSHAL'{completion_status=?COMPLETED_NO}};
- {Proxy, cancel_request_header} ->
- ok;
- Other ->
- orber:dbg("[~p] ~p:collect(~p)~n"
- "Unable to collect all fragments: ~p",
- [?LINE, ?MODULE, Buffer, Other], ?DEBUG_LEVEL),
- {'EXCEPTION', #'MARSHAL'{completion_status=?COMPLETED_NO}}
- end.
-
-
-%%-----------------------------------------------------------------
-%% Func: handle_message/4
-%%-----------------------------------------------------------------
-handle_message(GIOPHdr, Message, SocketType, Socket, Env) ->
- %% Warning. We shouldn't set the flags like this here. But, for now, we'll
- %% do it due to performance reasons.
- put(oe_orber_flags, Env#giop_env.flags),
- case catch cdr_decode:dec_message_header(null, GIOPHdr, Message) of
- Hdr when is_record(Hdr, cancel_request_header) ->
- %% We just skips this message for the moment, the standard require that
- %% the client handles the reply anyway.
- message_error;
- {location_forward, Object, ReqId, Version, OldObj} ->
- Reply = call_interceptors_out(Env#giop_env{version = Version},
- ReqId, [Object], OldObj,
- 'location_forward',
- "location_forward",
- {{'tk_objref', "", ""}, [],[]}),
- orber_socket:write(SocketType, Socket, Reply);
- {object_forward, Object, ReqId, Version, _OldObj} ->
- Reply = handle_locate_request(Env#giop_env{version = Version},
- {object_forward, Object, ReqId}),
- orber_socket:write(SocketType, Socket, Reply);
- {Version, Hdr} when is_record(Hdr, locate_request_header) ->
- Reply = handle_locate_request(Env#giop_env{version = Version}, Hdr),
- orber_socket:write(SocketType, Socket, Reply);
- {Version, ReqHdr, Rest, Len, ByteOrder} when is_record(ReqHdr, request_header) ->
- handle_request(Env#giop_env{version = Version}, ReqHdr, Rest, Len,
- ByteOrder, SocketType, Socket, Message);
- Other ->
- %% This cluase takes care of all erranous messages.
- orber:dbg("[~p] orber_iiop_inrequest:handle_message(~p)~n"
- "Decoding Msg Header failed: ~p",
- [?LINE, Message, Other], ?DEBUG_LEVEL),
- Reply = cdr_encode:enc_message_error(Env),
- orber_socket:write(SocketType, Socket, Reply),
- message_error
- end.
-
-
-send_reply(oneway, _SocketType, _Socket) ->
- ok;
-send_reply(Reply, SocketType, Socket) ->
- orber_socket:write(SocketType, Socket, Reply).
-
-%%-----------------------------------------------------------------
-%% Func: handle_request
-%%-----------------------------------------------------------------
-handle_request(#giop_env{interceptors = false} = Env, ReqHdr, Rest, Len, ByteOrder,
- SocketType, Socket, Message) ->
- NewEnv = check_context(ReqHdr#request_header.service_context, [], Env),
- case decode_body(NewEnv, ReqHdr, Rest, Len, ByteOrder, Message, enc_reply) of
- {error, E} ->
- orber_socket:write(SocketType, Socket, E);
- {NewEnv2, Hdr, Par, TypeCodes} ->
- Result = invoke_request(Hdr, Par, SocketType, TypeCodes, Env),
- Reply = evaluate(NewEnv2, Hdr, Result, TypeCodes,
- enc_reply, 'no_exception'),
- send_reply(Reply, SocketType, Socket)
- end;
-handle_request(Env, ReqHdr, Rest, Len, ByteOrder, SocketType, Socket, Message) ->
- NewEnv = check_context(ReqHdr#request_header.service_context, [], Env),
- case catch call_interceptors(SocketType, NewEnv, ReqHdr,
- Rest, Len, ByteOrder, Message) of
- {error, E} ->
- %% Failed to decode body.
- orber_socket:write(SocketType, Socket, E);
- {'EXCEPTION', Exc} ->
- orber:dbg("[~p] orber_iiop_inrequest:handle_message(~p)~n"
- "Invoking the interceptors resulted in: ~p",
- [?LINE, Message, Exc], ?DEBUG_LEVEL),
- Reply = marshal_exception(NewEnv,
- ReqHdr#request_header.request_id,
- Exc, enc_reply),
- orber_socket:write(SocketType, Socket, Reply);
- {'EXIT', R} ->
- orber:dbg("[~p] orber_iiop_inrequest:handle_message(~p)~n"
- "Invoking the interceptors resulted in: ~p",
- [?LINE, ReqHdr, R], ?DEBUG_LEVEL),
- Reply = marshal_exception(NewEnv,
- ReqHdr#request_header.request_id,
- #'MARSHAL'{completion_status=?COMPLETED_MAYBE},
- enc_reply),
- orber_socket:write(SocketType, Socket, Reply);
- Reply ->
- send_reply(Reply, SocketType, Socket)
- end.
-
-check_context([], [], Env) ->
- Env;
-check_context([], Acc, Env) ->
- Env#giop_env{ctx = Acc};
-check_context([#'CSI_SASContextBody'
- {label = ?CSI_MsgType_MTEstablishContext,
- value = #'CSI_EstablishContext'
- {client_context_id = _Id,
- authorization_token = _AuthToken,
- identity_token = _IdToken,
- client_authentication_token = _CAuthToken}}|Rest], Acc, Env) ->
- check_context(Rest, [#'IOP_ServiceContext'
- {context_id=?IOP_SecurityAttributeService,
- context_data = #'CSI_SASContextBody'
- {label = ?CSI_MsgType_MTCompleteEstablishContext,
- value = #'CSI_CompleteEstablishContext'
- {client_context_id = 0,
- context_stateful = false,
- final_context_token = [0,255]}}}|Acc], Env);
-check_context([_|Rest], Acc, Env) ->
- check_context(Rest, Acc, Env).
-
-
-%%-----------------------------------------------------------------
-%% Func: call_interceptors
-%%-----------------------------------------------------------------
--dialyzer({no_improper_lists, call_interceptors/7}).
-call_interceptors(SocketType, #giop_env{interceptors = {native, Ref, PIs},
- ctx = Ctx} = Env,
- ReqHdr, Rest, Len, ByteOrder, Msg) ->
- NewRest = orber_pi:in_request_enc(PIs, ReqHdr, Ref, Rest),
- case decode_body(Env, ReqHdr, NewRest, Len, ByteOrder, Msg, enc_reply) of
- {NewEnv, Hdr, Par, TypeCodes} ->
- NewPar = orber_pi:in_request(PIs, ReqHdr, Ref, Par),
- ResultInv = invoke_request(Hdr, NewPar, SocketType, TypeCodes, NewEnv),
- Result = orber_pi:out_reply(PIs, ReqHdr, Ref, ResultInv, Ctx),
-
- case evaluate(NewEnv, ReqHdr, Result, TypeCodes, enc_reply_split,
- 'no_exception') of
- {ReplyHdr, Reply, HdrL, _BodyL, Flags} ->
- NewReply = orber_pi:out_reply_enc(PIs, ReqHdr, Ref, Reply, Ctx),
- MessSize = HdrL+size(NewReply),
- cdr_encode:enc_giop_message_header(NewEnv, 'reply', Flags,
- MessSize, [ReplyHdr|NewReply]);
- Other ->
- Other
- end;
- Other ->
- Other
- end;
-call_interceptors(SocketType, #giop_env{interceptors = {portable, _PIs}} = Env,
- ReqHdr, Rest, Len, ByteOrder, Msg) ->
- case decode_body(Env, ReqHdr, Rest, Len, ByteOrder, Msg, enc_reply) of
- {NewEnv, Hdr, Par, TypeCodes} ->
- Result = invoke_request(Hdr, Par, SocketType, TypeCodes, NewEnv),
- evaluate(NewEnv, ReqHdr, Result, TypeCodes, enc_reply, 'no_exception');
- Other ->
- Other
- end.
-
-%%-----------------------------------------------------------------
-%% Func: call_interceptors_out
-%%-----------------------------------------------------------------
--dialyzer({no_improper_lists, call_interceptors_out/7}).
-call_interceptors_out(#giop_env{interceptors = {native, Ref, PIs}, ctx = Ctx} = Env,
- ReqId, Result, Obj, Type, Operation, TypeCodes) ->
- ReqHdr = #request_header{object_key = Obj,
- service_context = Ctx,
- response_expected = true,
- request_id = ReqId,
- operation = Operation},
- NewResult = (catch orber_pi:out_reply(PIs, ReqHdr, Ref, Result, Ctx)),
- {ReplyHdr, Reply, HdrL, _BodyL, Flags} =
- evaluate(Env, ReqHdr, NewResult, TypeCodes, enc_reply_split, Type),
- NewReply =
- case catch orber_pi:out_reply_enc(PIs, ReqHdr, Ref, Reply, Ctx) of
- {'EXCEPTION', Exception} ->
- %% Since evaluate don't need TypeCodes or Status no need to supply
- %% them.
- evaluate(Env, ReqHdr, {'EXCEPTION', Exception}, undefined,
- enc_reply_split, undefined);
- {'EXIT', E} ->
- orber:dbg("[~p] orber_iiop_inrequest:handle_location_forward(~p)~n"
- "Resulted in exit: ~p", [?LINE, PIs, E], ?DEBUG_LEVEL),
- marshal_exception(Env, ReqId,
- #'MARSHAL'{completion_status=?COMPLETED_NO},
- enc_reply);
- R ->
- R
- end,
- MessSize = HdrL+size(NewReply),
- cdr_encode:enc_giop_message_header(Env, 'reply', Flags, MessSize,
- [ReplyHdr|NewReply]);
-call_interceptors_out(#giop_env{interceptors = {portable, _PIs}} = Env,
- ReqId, Result, _Obj, Type, _, TypeCodes) ->
- Hdr = #request_header{response_expected = true,
- request_id = ReqId},
- evaluate(Env, Hdr, Result, TypeCodes, enc_reply, Type);
-call_interceptors_out(Env, ReqId, Result, _Obj, Type, _, TypeCodes) ->
- Hdr = #request_header{response_expected = true,
- request_id = ReqId},
- evaluate(Env, Hdr, Result, TypeCodes, enc_reply, Type).
-
-
-%%-----------------------------------------------------------------
-%% Func: decode_body/2
-%%-----------------------------------------------------------------
-decode_body(#giop_env{version = Version} = Env, ReqHdr, Rest, Len,
- ByteOrder, Message, Func) ->
- case catch cdr_decode:dec_request_body(Version, ReqHdr, Rest, Len,
- ByteOrder, Message) of
- {NewVersion, ReqHdr, Par, TypeCodes} ->
- {Env#giop_env{version = NewVersion}, ReqHdr, Par, TypeCodes};
- {'EXCEPTION', E} ->
- orber:dbg("[~p] orber_iiop_inrequest:decode_body(~p, ~p)~n"
- "Failed decoding request body: ~p",
- [?LINE, ReqHdr, Message, E], ?DEBUG_LEVEL),
- {error, marshal_exception(Env, ReqHdr#request_header.request_id,
- E, Func)};
- Other ->
- %% This cluase takes care of all erranous messages.
- orber:dbg("[~p] orber_iiop_inrequest:decode_body(~p, ~p)~n"
- "Failed decoding request body: ~p",
- [?LINE, ReqHdr, Message, Other], ?DEBUG_LEVEL),
- {error, marshal_exception(Env, ReqHdr#request_header.request_id,
- #'MARSHAL'{completion_status=?COMPLETED_NO},
- Func)}
- end.
-
-
-%%-----------------------------------------------------------------
-%% Func: handle_locate_request/2
-%%-----------------------------------------------------------------
-handle_locate_request(Env, {object_forward, Object, ReqId}) ->
- case catch cdr_encode:enc_locate_reply(
- Env#giop_env{request_id = ReqId,
- tc = {'tk_objref', "", ""},
- result = Object,
- reply_status = 'object_forward'}) of
- {'EXCEPTION', Exception} ->
- orber:dbg("[~p] orber_iiop_inrequest:handle_locate_request(object_forward)~n"
- "Raised the exception: ~p", [?LINE, Exception], ?DEBUG_LEVEL),
- marshal_locate_exception(Env, ReqId, Exception);
- {'EXIT', E} ->
- orber:dbg("[~p] orber_iiop_inrequest:handle_locate_request(object_forward)~n"
- "Resulted in exit: ~p", [?LINE, E], ?DEBUG_LEVEL),
- marshal_locate_exception(Env, ReqId,
- #'MARSHAL'{completion_status=?COMPLETED_NO});
- R ->
- R
- end;
-handle_locate_request(Env, Hdr) ->
- Location = orber_objectkeys:check(Hdr#locate_request_header.object_key),
- case catch cdr_encode:enc_locate_reply(
- Env#giop_env{request_id = Hdr#locate_request_header.request_id,
- reply_status = Location}) of
- {'EXCEPTION', Exception} ->
- orber:dbg("[~p] orber_iiop_inrequest:handle_locate_request(~p)~n"
- "Raised the exception: ~p",
- [?LINE, Location, Exception], ?DEBUG_LEVEL),
- marshal_locate_exception(Env, Hdr#locate_request_header.request_id, Exception);
- {'EXIT', E} ->
- orber:dbg("[~p] orber_iiop_inrequest:handle_locate_request(~p)~n"
- "Resulted in exit: ~p", [?LINE, Location, E], ?DEBUG_LEVEL),
- marshal_locate_exception(Env, Hdr#locate_request_header.request_id,
- #'MARSHAL'{completion_status=?COMPLETED_NO});
- R ->
- R
- end.
-
-%%-----------------------------------------------------------------
-%% Func: invoke_request/2
-%%-----------------------------------------------------------------
-invoke_request(Hdr, Par, normal, TypeCodes, #giop_env{iiop_ssl_port = SSLPort,
- partial_security = PartialSec}) ->
- Result =
- case SSLPort of
- -1 ->
- corba:request_from_iiop(Hdr#request_header.object_key,
- Hdr#request_header.operation,
- Par, [], Hdr#request_header.response_expected,
- Hdr#request_header.service_context);
- _ ->
- case Hdr#request_header.object_key of
- {_,registered,orber_init,_,_,_} ->
- corba:request_from_iiop(Hdr#request_header.object_key,
- Hdr#request_header.operation,
- Par, [],
- Hdr#request_header.response_expected,
- Hdr#request_header.service_context);
- {_,_,_,_,_,Flags} when PartialSec == true,
- ?ORB_FLAG_TEST(Flags, ?ORB_NO_SECURITY) == true ->
- corba:request_from_iiop(Hdr#request_header.object_key,
- Hdr#request_header.operation,
- Par, [],
- Hdr#request_header.response_expected,
- Hdr#request_header.service_context);
- _ ->
- orber:dbg("[~p] orber_iiop_inrequest:invoke_request(~p)~n"
- "SSL do not permit",
- [?LINE, Hdr#request_header.object_key], ?DEBUG_LEVEL),
- {'EXCEPTION', #'NO_PERMISSION'{completion_status=?COMPLETED_NO}}
- end
- end,
- result_to_list(Result, TypeCodes);
-invoke_request(Hdr, Par, ssl, TypeCodes, _) ->
- Result = corba:request_from_iiop(Hdr#request_header.object_key,
- Hdr#request_header.operation,
- Par, [], Hdr#request_header.response_expected,
- Hdr#request_header.service_context),
- result_to_list(Result, TypeCodes).
-
-%%-----------------------------------------------------------------
-%% Func: evaluate/4
-%%-----------------------------------------------------------------
-evaluate(_, Hdr,_,_,_,_) when Hdr#request_header.response_expected == 'false' ->
- oneway;
-evaluate(Env, Hdr, _, _, Func, _)
- when Hdr#request_header.response_expected == 'true_oneway' ->
- %% Special case which only occurs when using IIOP-1.2
- cdr_encode:Func(Env#giop_env{request_id = Hdr#request_header.request_id,
- reply_status = 'no_exception',
- tc = {tk_null,[],[]}, result = null});
-evaluate(Env, Hdr, {'EXCEPTION', Exc}, _, Func, _) ->
- %% The exception can be user defined. Hence, we must check the result.
- case catch marshal_exception(Env, Hdr#request_header.request_id, Exc, Func) of
- {'EXCEPTION', Exception} ->
- orber:dbg("[~p] orber_iiop_inrequest:evaluate(~p)~n"
- "Encoding (reply) exception: ~p",
- [?LINE, Hdr, Exception], ?DEBUG_LEVEL),
- marshal_exception(Env, Hdr#request_header.request_id, Exception, Func);
- {'EXIT', E} ->
- orber:dbg("[~p] orber_iiop_inrequest:evaluate(~p)~n"
- "Encode (reply) resulted in: ~p",
- [?LINE, Hdr, E], ?DEBUG_LEVEL),
- marshal_exception(Env, Hdr#request_header.request_id,
- #'MARSHAL'{completion_status=?COMPLETED_YES}, Func);
- R ->
- R
- end;
-evaluate(#giop_env{version = {1,2}} = Env, Hdr, {'location_forward_perm', NewIOR}, _,
- Func, _)->
- case catch cdr_encode:Func(#giop_env{version = {1,2},
- request_id = Hdr#request_header.request_id,
- reply_status = 'location_forward_perm',
- tc = {{'tk_objref', "", ""}, [],[]},
- result = NewIOR}) of
- {'EXCEPTION', Exception} ->
- orber:dbg("[~p] orber_iiop_inrequest:evaluate(~p) " ++
- "Encoding (reply) exception: ~p",
- [?LINE, Hdr, Exception], ?DEBUG_LEVEL),
- marshal_exception(Env, Hdr#request_header.request_id, Exception, Func);
- {'EXIT', E} ->
- orber:dbg("[~p] orber_iiop_inrequest:evaluate(~p) " ++
- "Encode (reply) resulted in: ~p",
- [?LINE, Hdr, E], ?DEBUG_LEVEL),
- marshal_exception(Env, Hdr#request_header.request_id,
- #'MARSHAL'{completion_status=?COMPLETED_YES}, Func);
- R ->
- R
- end;
-evaluate(Env, Hdr, [Res |OutPar], TypeCodes, Func, Type) ->
- case catch cdr_encode:Func(Env#giop_env{request_id = Hdr#request_header.request_id,
- reply_status = Type,
- tc = TypeCodes, result = Res,
- parameters = OutPar}) of
- {'EXCEPTION', Exception} ->
- orber:dbg("[~p] orber_iiop_inrequest:evaluate(~p, ~p, ~p)~n"
- "Encode exception: ~p",
- [?LINE, Hdr, Res, OutPar, Exception], ?DEBUG_LEVEL),
- marshal_exception(Env, Hdr#request_header.request_id, Exception, Func);
- {'EXIT', E} ->
- orber:dbg("[~p] orber_iiop_inrequest:evaluate(~p, ~p, ~p)~n"
- "Encode exit: ~p",
- [?LINE, Hdr, Res, OutPar, E], ?DEBUG_LEVEL),
- marshal_exception(Env, Hdr#request_header.request_id,
- #'MARSHAL'{completion_status=?COMPLETED_YES}, Func);
- R ->
- R
- end;
-evaluate(Env, Hdr, What, TypeCodes, Func, _) ->
- orber:dbg("[~p] orber_iiop_inrequest:evaluate(~p)~n"
- "Bad reply: ~p~n"
- "Should be: ~p~n"
- "GIOP Env : ~p", [?LINE, Hdr, What, TypeCodes, Env], ?DEBUG_LEVEL),
- marshal_exception(Env, Hdr#request_header.request_id,
- #'INTERNAL'{completion_status=?COMPLETED_MAYBE}, Func).
-
-%%-----------------------------------------------------------------
-%% Utility Functions
-%%-----------------------------------------------------------------
-result_to_list({'oe_location_forward_perm', NewIOR}, _) ->
- {'location_forward_perm', NewIOR};
-result_to_list({'EXCEPTION', E}, _) ->
- {'EXCEPTION', E};
-result_to_list(Result, {_TkRes, _, []}) ->
- [Result];
-result_to_list(Result, {_TkRes, _, _TkOut}) ->
- tuple_to_list(Result).
-
-marshal_exception(Env, Id, Exception, Func) ->
- {TypeOfException, ExceptionTypeCode, NewExc} =
- orber_exceptions:get_def(Exception),
- cdr_encode:Func(Env#giop_env{request_id = Id,
- reply_status = TypeOfException,
- tc = {ExceptionTypeCode, [], []},
- result = NewExc}).
-
-marshal_locate_exception(#giop_env{version = {1,2}} = Env, Id, Exception) ->
- case orber_exceptions:get_def(Exception) of
- {?SYSTEM_EXCEPTION, ExceptionTypeCode, NewExc} ->
- cdr_encode:enc_locate_reply(
- Env#giop_env{request_id = Id,
- reply_status = 'loc_system_exception',
- tc = ExceptionTypeCode, result = NewExc});
- _ ->
- %% This case is impossible (i.e. Orber only throws system
- %% exceptions). But to be on the safe side...
- marshal_locate_exception(Env, Id, #'MARSHAL'
- {completion_status=?COMPLETED_YES})
- end;
-marshal_locate_exception(Env, _Id, _Exception) ->
- %% There is no way to define an exception for IIOP-1.0/1.1 in a
- %% locate_reply.
- cdr_encode:enc_message_error(Env).
diff --git a/lib/orber/src/orber_iiop_insup.erl b/lib/orber/src/orber_iiop_insup.erl
deleted file mode 100644
index 2885cf06c0..0000000000
--- a/lib/orber/src/orber_iiop_insup.erl
+++ /dev/null
@@ -1,86 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: orber_iiop_insup.erl
-%%
-%% Description:
-%% This file contains the IIOP communication supervisor which
-%% holds all active "in proxies"
-%%
-%%-----------------------------------------------------------------
--module(orber_iiop_insup).
-
--behaviour(supervisor).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([start/2, start_connection/4]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([init/1, terminate/2]).
-
-%%-----------------------------------------------------------------
-%% External interface functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: start/2
-%%-----------------------------------------------------------------
-start(sup, Opts) ->
- supervisor:start_link({local, orber_iiop_insup}, orber_iiop_insup,
- {sup, Opts});
-start(_A1, _A2) ->
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Server functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: init/1
-%%-----------------------------------------------------------------
-init({sup, _Opts}) ->
- SupFlags = {simple_one_for_one, 500, 100},
- ChildSpec = [
- {name1, {orber_iiop_inproxy, start, []}, temporary,
- 10000, worker, [orber_iiop_inproxy]}
- ],
- {ok, {SupFlags, ChildSpec}};
-init(_Opts) ->
- {ok, []}.
-
-
-%%-----------------------------------------------------------------
-%% Func: terminate/1
-%%-----------------------------------------------------------------
-terminate(_Reason, _State) ->
- ok.
-
-%%-----------------------------------------------------------------
-%% Func: start_connection/2
-%%-----------------------------------------------------------------
-start_connection(Type, Socket, Ref, ProxyOptions) ->
- supervisor:start_child(orber_iiop_insup, [{connect, Type, Socket,
- Ref, ProxyOptions}]).
-
diff --git a/lib/orber/src/orber_iiop_net.erl b/lib/orber/src/orber_iiop_net.erl
deleted file mode 100644
index e7f54891a2..0000000000
--- a/lib/orber/src/orber_iiop_net.erl
+++ /dev/null
@@ -1,511 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: orber_iiop_net.erl
-%%
-%% Description:
-%% This file contains the IIOP communication server
-%%
-%%-----------------------------------------------------------------
--module(orber_iiop_net).
-
--behaviour(gen_server).
-
--include_lib("orber/src/orber_iiop.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([start/1, connect/5, connections/0,
- sockname2peername/2, peername2sockname/2,
- add_connection/5,
- add/3, remove/1, reconfigure/1, reconfigure/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([init/1, terminate/2, handle_call/3,
- handle_cast/2, handle_info/2, code_change/3]).
-
-%%-----------------------------------------------------------------
-%% Server state record and definitions
-%%-----------------------------------------------------------------
--define(CONNECTION_DB, orber_iiop_net_db).
-
--record(state, {ports=[], max_connections, db, counter = 1, queue}).
-
--record(connection, {pid, socket, type, peerdata, localdata, ref = 0}).
-
--record(listen, {pid, socket, port, type, ref = 0, options, proxy_options = []}).
-
-%%-----------------------------------------------------------------
-%% External interface functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: start/1
-%%-----------------------------------------------------------------
-start(Opts) ->
- gen_server:start_link({local, orber_iiop_net}, orber_iiop_net, Opts, []).
-
-add(IP, normal, Options) ->
- Port = orber_tb:keysearch(iiop_port, Options, orber_env:iiop_port()),
- gen_server:call(orber_iiop_net, {add, IP, normal, Port, Options}, infinity);
-add(IP, ssl, Options) ->
- Port = orber_tb:keysearch(iiop_ssl_port, Options, orber_env:iiop_ssl_port()),
- gen_server:call(orber_iiop_net, {add, IP, ssl, Port, Options}, infinity).
-
-remove(Ref) ->
- gen_server:call(orber_iiop_net, {remove, Ref}, infinity).
-
-reconfigure(Options) ->
- lists:foreach(fun(P) ->
- P ! {reconfigure, Options}
- end,
- do_select([{#connection{pid = '$1', _='_'},
- [], ['$1']}])).
-
-reconfigure(Options, Ref) ->
- case do_select([{#connection{ref = Ref, pid = '$1', _='_'},
- [], ['$1']}]) of
- [Pid] when is_pid(Pid) ->
- Pid ! {reconfigure, Options},
- ok;
- _ ->
- {error, "No proxy matched the supplied reference"}
- end.
-
-connect(Type, S, AcceptPid, Ref, ProxyOptions) ->
- gen_server:call(orber_iiop_net, {connect, Type, S, AcceptPid,
- Ref, ProxyOptions}, infinity).
-
-connections() ->
- do_select([{#connection{peerdata = '$1', _='_'}, [], ['$1']}]).
-
-sockname2peername(SockHost, SockPort) ->
- do_select([{#connection{peerdata = '$1',
- localdata = {match_type(SockHost),
- match_type(SockPort)},
- _='_'}, [], ['$1']}]).
-
-
-peername2sockname(PeerHost, PeerPort) ->
- do_select([{#connection{peerdata = {match_type(PeerHost),
- match_type(PeerPort)},
- localdata = '$1',
- _='_'}, [], ['$1']}]).
-
-do_select(Pattern) ->
- case catch ets:select(?CONNECTION_DB, Pattern) of
- {'EXIT', _What} ->
- [];
- Result ->
- Result
- end.
-
-match_type(0) ->
- %% Wildcard port number
- '_';
-match_type("") ->
- %% Wildcard host
- '_';
-match_type(Key) ->
- %% Wildcard not used.
- Key.
-
-add_connection(Socket, Type, PeerData, LocalData, Ref) ->
- ets:insert(?CONNECTION_DB, #connection{pid = self(), socket = Socket,
- type = Type, peerdata = PeerData,
- localdata = LocalData, ref = Ref}).
-
-%%-----------------------------------------------------------------
-%% Server functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: init/1
-%%-----------------------------------------------------------------
-init(Options) ->
- process_flag(trap_exit, true),
- {ok, parse_options(Options,
- #state{max_connections = orber:iiop_max_in_connections(),
- db = ets:new(?CONNECTION_DB, [set, public,
- named_table,
- {keypos, 2}]),
- queue = queue:new()})}.
-
-%%-----------------------------------------------------------------
-%% Func: terminate/1
-%%-----------------------------------------------------------------
-terminate(_Reason, _State) ->
- ok.
-
-%%-----------------------------------------------------------------
-%% Func: get_options/2
-%%-----------------------------------------------------------------
-get_options(normal, _Options) ->
- [];
-get_options(ssl, Options) ->
- SSLOpts =
- case orber_tb:keysearch(ssl_server_options, Options,
- orber_env:ssl_server_options()) of
- [] ->
- Verify = orber_tb:keysearch(ssl_server_verify, Options,
- orber_env:ssl_server_verify()),
- Depth = orber_tb:keysearch(ssl_server_depth, Options,
- orber_env:ssl_server_depth()),
- Cert = orber_tb:keysearch(ssl_server_certfile, Options,
- orber_env:ssl_server_certfile()),
- CaCert = orber_tb:keysearch(ssl_server_cacertfile, Options,
- orber_env:ssl_server_cacertfile()),
- Pwd = orber_tb:keysearch(ssl_server_password, Options,
- orber_env:ssl_server_password()),
- Key = orber_tb:keysearch(ssl_server_keyfile, Options,
- orber_env:ssl_server_keyfile()),
- Ciphers = orber_tb:keysearch(ssl_server_ciphers, Options,
- orber_env:ssl_server_ciphers()),
- Timeout = orber_tb:keysearch(ssl_server_cachetimeout, Options,
- orber_env:ssl_server_cachetimeout()),
- KeepAlive = orber_tb:keysearch(ssl_server_cachetimeout, Options,
- orber_env:iiop_ssl_in_keepalive()),
- [{verify, Verify},
- {depth, Depth},
- {certfile, Cert},
- {cacertfile, CaCert},
- {password, Pwd},
- {keyfile, Key},
- {ciphers, Ciphers},
- {cachetimeout, Timeout},
- {keepalive, KeepAlive}];
- Opts ->
- case orber_tb:check_illegal_tcp_options(Opts) of
- ok ->
- check_old_ssl_server_options(Options),
- Opts;
- {error, IllegalOpts} ->
- error_logger:error_report([{application, orber},
- "TCP options not allowed to set on a connection",
- IllegalOpts]),
- error("Illegal TCP option")
- end
- end,
- ssl_server_extra_options(SSLOpts, []).
-
-%%-----------------------------------------------------------------
-%% Func: parse_options/2
-%%-----------------------------------------------------------------
-parse_options([{port, Type, Port} | Rest], State) ->
- Options = get_options(Type, []),
- Family = orber_env:ip_version(),
- IPFamilyOptions =
- case Family of
- inet -> [inet];
- inet6 -> [inet6, {ipv6_v6only, true}]
- end,
- Options2 =
- case orber_env:ip_address_variable_defined() of
- false ->
- IPFamilyOptions ++ Options;
- Host ->
- {ok, IP} = inet:getaddr(Host, Family),
- IPFamilyOptions ++ [{ip, IP} |Options]
- end,
-
- {ok, Listen, NewPort} = orber_socket:listen(Type, Port, Options2, true),
- {ok, Pid} = orber_iiop_socketsup:start_accept(Type, Listen, 0),
- link(Pid),
- ets:insert(?CONNECTION_DB, #listen{pid = Pid, socket = Listen,
- port = NewPort, type = Type,
- options = Options2}),
- parse_options(Rest, State);
-parse_options([], State) ->
- State.
-
-ssl_server_extra_options([], Acc) ->
- Acc;
-ssl_server_extra_options([{_Type, []}|T], Acc) ->
- ssl_server_extra_options(T, Acc);
-ssl_server_extra_options([{_Type, infinity}|T], Acc) ->
- ssl_server_extra_options(T, Acc);
-ssl_server_extra_options([{Type, Value}|T], Acc) ->
- ssl_server_extra_options(T, [{Type, Value}|Acc]).
-
-filter_options([], Acc) ->
- Acc;
-filter_options([{verify, _}|T], Acc) ->
- filter_options(T, Acc);
-filter_options([{depth, _}|T], Acc) ->
- filter_options(T, Acc);
-filter_options([{certfile, _}|T], Acc) ->
- filter_options(T, Acc);
-filter_options([{cacertfile, _}|T], Acc) ->
- filter_options(T, Acc);
-filter_options([{password, _}|T], Acc) ->
- filter_options(T, Acc);
-filter_options([{keyfile, _}|T], Acc) ->
- filter_options(T, Acc);
-filter_options([{ciphers, _}|T], Acc) ->
- filter_options(T, Acc);
-filter_options([{cachetimeout, _}|T], Acc) ->
- filter_options(T, Acc);
-filter_options([H|T], Acc) ->
- filter_options(T, [H|Acc]).
-
-%%-----------------------------------------------------------------
-%% Func: handle_call/3
-%%-----------------------------------------------------------------
-handle_call({remove, Ref}, _From, State) ->
- case do_select([{#listen{ref = Ref, pid = '$1', socket = '$2',
- type = '$3', _='_'}, [], [{{'$1', '$2', '$3'}}]}]) of
- [{Pid, Listen, Type}|_] when is_pid(Pid) ->
- unlink(Pid),
- ets:delete(?CONNECTION_DB, Pid),
- %% Just close the listen socket. Will cause the accept processs
- %% to terminate.
- orber_socket:close(Type, Listen),
- stop_proxies(do_select([{#connection{ref = Ref, pid = '$1', _='_'},
- [], ['$1']}])),
- {reply, ok,
- State#state{queue =
- from_list(
- lists:keydelete(Pid, 1,
- queue:to_list(State#state.queue)))}};
- _ ->
- {reply, ok, State}
- end;
-handle_call({add, IP, Type, Port, AllOptions}, _From, State) ->
- Family = orber_tb:keysearch(ip_family, AllOptions, orber_env:ip_version()),
- IPFamilyOptions =
- case Family of
- inet -> [inet];
- inet6 -> [inet6, {ipv6_v6only, true}]
- end,
- case inet:getaddr(IP, Family) of
- {ok, IPTuple} ->
- try
- Options = IPFamilyOptions ++ [{ip, IPTuple} |get_options(Type, AllOptions)],
- Ref = make_ref(),
- ProxyOptions = filter_options(AllOptions, []),
- case orber_socket:listen(Type, Port, Options, false) of
- {ok, Listen, NewPort} ->
- {ok, Pid} = orber_iiop_socketsup:start_accept(Type, Listen, Ref,
- ProxyOptions),
- link(Pid),
- ets:insert(?CONNECTION_DB, #listen{pid = Pid,
- socket = Listen,
- port = NewPort,
- type = Type, ref = Ref,
- options = Options,
- proxy_options = ProxyOptions}),
- {reply, {ok, Ref}, State};
- Error ->
- {reply, Error, State}
- end
- catch
- error:Reason ->
- {reply, {error, Reason}, State}
- end;
- Other ->
- {reply, Other, State}
- end;
-handle_call({connect, Type, Socket, _AcceptPid, AccepRef, ProxyOptions}, _From, State)
- when State#state.max_connections == infinity;
- State#state.max_connections > State#state.counter ->
- case catch access_allowed(Type, Socket, Type) of
- true ->
- case orber_iiop_insup:start_connection(Type, Socket,
- AccepRef, ProxyOptions) of
- {ok, Pid} when is_pid(Pid) ->
- link(Pid),
- {reply, {ok, Pid, true}, update_counter(State, 1)};
- Other ->
- {reply, Other, State}
- end;
- _ ->
- {H, P} = orber_socket:peerdata(Type, Socket),
- orber_tb:info("Blocked connect attempt from ~s - ~p", [H, P]),
- {reply, denied, State}
- end;
-handle_call({connect, Type, Socket, AcceptPid, AccepRef, ProxyOptions}, _From,
- #state{queue = Q} = State) ->
- case catch access_allowed(Type, Socket, Type) of
- true ->
- case orber_iiop_insup:start_connection(Type, Socket,
- AccepRef, ProxyOptions) of
- {ok, Pid} when is_pid(Pid) ->
- link(Pid),
- Ref = erlang:make_ref(),
- {reply, {ok, Pid, Ref},
- update_counter(State#state{queue =
- queue:in({AcceptPid, Ref}, Q)}, 1)};
- Other ->
- {reply, Other, State}
- end;
- _ ->
- {H, P} = orber_socket:peerdata(Type, Socket),
- orber_tb:info("Blocked connect attempt from ~s - ~p", [H, P]),
- {reply, denied, State}
- end;
-handle_call(_, _, State) ->
- {noreply, State}.
-
-stop_proxies([H|T]) ->
- catch orber_iiop_inproxy:stop(H),
- stop_proxies(T);
-stop_proxies([]) ->
- ok.
-
-access_allowed(Type, Socket, Type) ->
- Flags = orber:get_flags(),
- case ?ORB_FLAG_TEST(Flags, ?ORB_ENV_USE_ACL_INCOMING) of
- false ->
- true;
- true ->
- SearchFor =
- case Type of
- normal ->
- tcp_in;
- ssl ->
- ssl_in
- end,
- {ok, {Host, Port}} = orber_socket:peername(Type, Socket),
- case orber_acl:match(Host, SearchFor, true) of
- {true, [], 0} ->
- true;
- {true, [], Port} ->
- true;
- {true, [], {Min, Max}} when Port >= Min, Port =< Max ->
- true;
- {true, Interfaces, 0} ->
- get_sockethost(Type, Socket),
- lists:member(get_sockethost(Type, Socket), Interfaces);
- {true, Interfaces, Port} ->
- lists:member(get_sockethost(Type, Socket), Interfaces);
- {true, Interfaces, {Min, Max}} when Port >= Min, Port =< Max ->
- lists:member(get_sockethost(Type, Socket), Interfaces);
- _ ->
- false
- end
- end.
-
-get_sockethost(Type, Socket) ->
- case orber_socket:peername(Type, Socket) of
- {ok, {Addr, _Port}} ->
- orber_env:addr2str(Addr);
- _ ->
- false
- end.
-
-%%------------------------------------------------------------
-%% Standard gen_server cast handle
-%%------------------------------------------------------------
-handle_cast(_, State) ->
- {noreply, State}.
-
-%%------------------------------------------------------------
-%% Standard gen_server handles
-%%------------------------------------------------------------
-handle_info({'EXIT', Pid, _Reason}, State) when is_pid(Pid) ->
- case ets:lookup(?CONNECTION_DB, Pid) of
- [#listen{pid = Pid, socket = Listen, port = Port, type = Type,
- ref = Ref, options = Options, proxy_options = POpts}] ->
- ets:delete(?CONNECTION_DB, Pid),
- unlink(Pid),
- {ok, NewPid} = orber_iiop_socketsup:start_accept(Type, Listen,
- Ref, POpts),
- link(NewPid),
- ets:insert(?CONNECTION_DB, #listen{pid = NewPid, socket = Listen,
- port = Port, type = Type,
- ref = Ref, options = Options,
- proxy_options = POpts}),
- %% Remove the connection if it's in the queue.
- {noreply,
- State#state{queue =
- from_list(
- lists:keydelete(Pid, 1,
- queue:to_list(State#state.queue)))}};
- [#connection{pid = Pid}] ->
- ets:delete(?CONNECTION_DB, Pid),
- unlink(Pid),
- case queue:out(State#state.queue) of
- {empty, _} ->
- {noreply, update_counter(State, -1)};
- {{value, {AcceptPid, Ref}}, Q} ->
- AcceptPid ! {Ref, ok},
- {noreply, update_counter(State#state{queue = Q}, -1)}
- end;
- [] ->
- {noreply, State}
- end;
-handle_info(_, State) ->
- {noreply, State}.
-
-from_list(List) ->
- from_list(List, queue:new()).
-
-from_list([], Q) ->
- Q;
-from_list([H|T], Q) ->
- NewQ = queue:in(H, Q),
- from_list(T, NewQ).
-
-
-%%-----------------------------------------------------------------
-%% Func: code_change/3
-%%-----------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%-----------------------------------------------------------------
-%% Internal Functions
-%%-----------------------------------------------------------------
-update_counter(#state{max_connections = infinity} = State, _) ->
- State;
-update_counter(State, Value) ->
- State#state{counter = State#state.counter + Value}.
-
-
-check_old_ssl_server_options(Options) ->
- try
- 0 = orber_tb:keysearch(ssl_server_verify, Options,
- orber_env:ssl_server_verify()),
- 1 = orber_tb:keysearch(ssl_server_depth, Options,
- orber_env:ssl_server_depth()),
- [] = orber_tb:keysearch(ssl_server_certfile, Options,
- orber_env:ssl_server_certfile()),
- [] = orber_tb:keysearch(ssl_server_cacertfile, Options,
- orber_env:ssl_server_cacertfile()),
- [] = orber_tb:keysearch(ssl_server_password, Options,
- orber_env:ssl_server_password()),
- [] = orber_tb:keysearch(ssl_server_keyfile, Options,
- orber_env:ssl_server_keyfile()),
- [] = orber_tb:keysearch(ssl_server_ciphers, Options,
- orber_env:ssl_server_ciphers()),
- infinity = orber_tb:keysearch(ssl_server_cachetimeout, Options,
- orber_env:ssl_server_cachetimeout()),
- false = orber_tb:keysearch(iiop_ssl_in_keepalive, Options,
- orber_env:iiop_ssl_in_keepalive())
- catch
- _:_ ->
- io:format("hej\n",[]),
- error_logger:warning_report([{application, orber},
- "Ignoring deprecated ssl server options used together with the ssl_server_options"])
- end.
-
diff --git a/lib/orber/src/orber_iiop_net_accept.erl b/lib/orber/src/orber_iiop_net_accept.erl
deleted file mode 100644
index 2a53d55cea..0000000000
--- a/lib/orber/src/orber_iiop_net_accept.erl
+++ /dev/null
@@ -1,95 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: orber_iiop_net_accept.erl
-%%
-%% Description:
-%% This file contains the process which are waiting in accept for new
-%% connections.
-%%
-%%
-%%-----------------------------------------------------------------
--module(orber_iiop_net_accept).
-
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([start/4]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([net_accept/5]).
-
-%%-----------------------------------------------------------------
-%% External interface functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: start/2
-%%-----------------------------------------------------------------
-start(Type, Listen, Ref, ProxyOptions) ->
- Pid = proc_lib:spawn_link(?MODULE, net_accept,
- [Type, Listen, self(), Ref, ProxyOptions]),
- {ok, Pid}.
-
-%%-----------------------------------------------------------------
-%% Internal Functions
-%%-----------------------------------------------------------------
-
-%%-----------------------------------------------------------------
-%% Func: net_accept/3
-%%-----------------------------------------------------------------
-net_accept(Type, ListenFd, Parent, Ref, ProxyOptions) ->
- case catch orber_socket:accept(Type, ListenFd) of
- {'EXCEPTION', _E} ->
- ok;
- S ->
- case orber_iiop_net:connect(Type, S, self(), Ref, ProxyOptions) of
- {ok, Pid, ReadyToGo} ->
- case orber_socket:controlling_process(Type, S, Pid) of
- ok ->
- orber_iiop_inproxy:post_accept(Pid, Type, S);
- _Reason ->
- orber_socket:close(Type, S),
- gen_server:cast(Pid, stop),
- orber_socket:clear(Type, S)
- end,
- ready_to_go(ReadyToGo);
- denied ->
- orber_socket:close(Type, S),
- orber_socket:clear(Type, S);
- _ ->
- orber_socket:close(Type, S),
- orber_socket:clear(Type, S)
- end,
- net_accept(Type, ListenFd, Parent, Ref, ProxyOptions)
- end.
-
-ready_to_go(true) ->
- ok;
-ready_to_go(Ref) ->
- receive
- {Ref, ok} ->
- ok
- end.
-
diff --git a/lib/orber/src/orber_iiop_outproxy.erl b/lib/orber/src/orber_iiop_outproxy.erl
deleted file mode 100644
index 1406a1ad56..0000000000
--- a/lib/orber/src/orber_iiop_outproxy.erl
+++ /dev/null
@@ -1,511 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: orber_iiop_outproxy.erl
-%%
-%% Description:
-%% This file contains the IIOP "proxy" for outgoing connections
-%%
-%%
-%%-----------------------------------------------------------------
--module(orber_iiop_outproxy).
-
--behaviour(gen_server).
-
--include_lib("orber/src/orber_iiop.hrl").
--include_lib("orber/include/corba.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([start/0, start/1, request/5, cancel/2, cancel/3]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([init/1, handle_call/3, handle_cast/2, handle_info/2,
- code_change/3, terminate/2, stop/2, stop/1, checkheaders/1]).
-
-%%-----------------------------------------------------------------
-%% Macros/Defines
-%%-----------------------------------------------------------------
--define(DEBUG_LEVEL, 7).
-
--record(state, {stype, socket, db, timeout, client_timeout, host, port, parent,
- error_reason = {'EXCEPTION', #'COMM_FAILURE'
- {completion_status=?COMPLETED_MAYBE}}}).
-
-%%-----------------------------------------------------------------
-%% External interface functions
-%%-----------------------------------------------------------------
-start() ->
- ignore.
-
-start(Opts) ->
- gen_server:start_link(orber_iiop_outproxy, Opts, []).
-
-request(Pid, true, Timeout, Msg, RequestId) ->
- %% Why not simply use gen_server:call? We must be able to receive
- %% more than one reply (i.e. fragmented messages).
- MRef = erlang:monitor(process, Pid),
- gen_server:cast(Pid, {request, Timeout, Msg, RequestId, self(), MRef}),
- receive
- {MRef, Reply} ->
- erlang:demonitor(MRef, [flush]),
- Reply;
- {'DOWN', MRef, _, Pid, _Reason} when is_pid(Pid) ->
- receive
- %% Clear EXIT message from queue
- {'EXIT', _Pid, _What} ->
- corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_MAYBE})
- after 0 ->
- corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_MAYBE})
- end;
- {fragmented, GIOPHdr, Bytes, RequestId, MRef} ->
- collect_fragments(GIOPHdr, [], Bytes, Pid, RequestId, MRef)
- end;
-request(Pid, _, _, Msg, _RequestId) ->
- %% No response expected
- gen_server:cast(Pid, {oneway_request, Msg}).
-
-cancel(Pid, RequestId) ->
- gen_server:cast(Pid, {cancel, RequestId}).
-
-cancel(Pid, RequestId, MRef) ->
- gen_server:cast(Pid, {cancel, RequestId, MRef, self()}).
-
-%%-----------------------------------------------------------------
-%% Internal interface functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: stop/2
-%%-----------------------------------------------------------------
-stop(Pid, Timeout) ->
- gen_server:call(Pid, stop, Timeout).
-stop(Pid) ->
- gen_server:cast(Pid, stop).
-
-
-%%-----------------------------------------------------------------
-%% Server functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: init/1
-%%-----------------------------------------------------------------
-init({connect, Host, Port, SocketType, SocketOptions, Parent, Key, NewKey}) ->
- process_flag(trap_exit, true),
- case catch orber_socket:connect(SocketType, Host, Port,
- orber_socket:get_ip_family_opts(Host) ++ SocketOptions) of
- {'EXCEPTION', _E} ->
- ignore;
- %% We used to reply the below but since this would generate a CRASH REPORT
- %% if '-boot start_sasl' used. Due to a request to change this behaviour
- %% we did.
- %% {stop, {'EXCEPTION', E}};
- Socket ->
- SockData = orber_socket:sockdata(SocketType, Socket),
- orber_iiop_pm:add_connection(Key, NewKey, SockData),
- Timeout = orber:iiop_connection_timeout(),
- {ok, #state{stype = SocketType, socket = Socket,
- db = ets:new(orber_outgoing_requests, [set]),
- timeout = Timeout, client_timeout = orber:iiop_timeout(),
- host = Host, port = Port, parent = Parent}, Timeout}
- end.
-
-%%-----------------------------------------------------------------
-%% Func: terminate/2
-%%-----------------------------------------------------------------
-terminate(_Reason, #state{db = OutRequests, error_reason = ER}) ->
- %% Kill all proxies and delete table before terminating
- notify_clients(OutRequests, ets:first(OutRequests), ER),
- ets:delete(OutRequests),
- ok.
-
-notify_clients(_, '$end_of_table', _ER) ->
- ok;
-notify_clients(OutRequests, Key, ER) ->
- case ets:lookup(OutRequests, Key) of
- [{_, Pid, TRef, MRef}] ->
- cancel_timer(TRef),
- Pid ! {MRef, ER},
- notify_clients(OutRequests, ets:next(OutRequests, Key), ER)
- end.
-
-%%-----------------------------------------------------------------
-%% Func: handle_call/3
-%%-----------------------------------------------------------------
-handle_call(stop, _From, State) ->
- {stop, normal, ok, State};
-handle_call(X, From, State) ->
- orber:dbg("[~p] orber_iiop_outproxy:handle_call(~p);~n"
- "Un-recognized call from ~p", [?LINE, X, From], ?DEBUG_LEVEL),
- {noreply, State, State#state.timeout}.
-
-%%-----------------------------------------------------------------
-%% Func: handle_cast/2
-%%-----------------------------------------------------------------
-handle_cast({request, Timeout, Msg, RequestId, From, MRef},
- #state{client_timeout = DefaultTimeout} = State) ->
- orber_socket:write(State#state.stype, State#state.socket, Msg),
- true = ets:insert(State#state.db, {RequestId, From,
- start_timer(Timeout, DefaultTimeout, RequestId),
- MRef}),
- {noreply, State, State#state.timeout};
-handle_cast({oneway_request, Msg}, State) ->
- orber_socket:write(State#state.stype, State#state.socket, Msg),
- {noreply, State, State#state.timeout};
-handle_cast({cancel, ReqId}, State) ->
- case ets:lookup(State#state.db, ReqId) of
- [{ReqId, _From, TRef, _MRef}] ->
- cancel_timer(TRef),
- ets:delete(State#state.db, ReqId),
- orber:dbg("[~p] orber_iiop_outproxy:handle_info(~p);~n"
- "Request cancelled", [?LINE, State], ?DEBUG_LEVEL),
- {noreply, State, State#state.timeout};
- _ ->
- {noreply, State, State#state.timeout}
- end;
-handle_cast({cancel, ReqId, MRef, From}, State) ->
- case ets:lookup(State#state.db, ReqId) of
- [{ReqId, From, TRef, MRef}] ->
- cancel_timer(TRef),
- ets:delete(State#state.db, ReqId),
- From ! {MRef, ReqId, cancelled},
- orber:dbg("[~p] orber_iiop_outproxy:handle_info(~p);
-Request cancelled", [?LINE, State], ?DEBUG_LEVEL),
- {noreply, State, State#state.timeout};
- _ ->
- From ! {MRef, ReqId, cancelled},
- {noreply, State, State#state.timeout}
- end;
-handle_cast(stop, State) ->
- {stop, normal, State};
-handle_cast(X, State) ->
- orber:dbg("[~p] orber_iiop_outproxy:handle_cast(~p);
-Un-recognized cast.", [?LINE, X], ?DEBUG_LEVEL),
- {noreply, State, State#state.timeout}.
-
-%%-----------------------------------------------------------------
-%% Func: handle_info/2
-%%-----------------------------------------------------------------
-handle_info({tcp, _Socket, Bytes}, State) ->
- handle_reply(Bytes, State);
-handle_info({ssl, _Socket, Bytes}, State) ->
- handle_reply(Bytes, State);
-handle_info({tcp_closed, _Socket}, State) ->
- {stop, normal, State};
-handle_info({ssl_closed, _Socket}, State) ->
- {stop, normal, State};
-handle_info({tcp_error, Socket, Reason}, #state{socket = Socket, host = Host,
- port = Port} = State) ->
- orber:error("[~p] IIOP proxy received the TCP error message: ~p~n"
- "The server-side ORB is located at '~p:~p'~n"
- "See the gen_tcp/inet documentation for more information.",
- [?LINE, Reason, Host, Port], ?DEBUG_LEVEL),
- {stop, normal, State};
-handle_info({ssl_error, Socket, Reason}, #state{socket = Socket, host = Host,
- port = Port} = State) ->
- orber:error("[~p] IIOP proxy received the SSL error message: ~p~n"
- "The server-side ORB is located at '~p:~p'~n"
- "See the SSL-application documentation for more information.",
- [?LINE, Reason, Host, Port], ?DEBUG_LEVEL),
- {stop, normal, State};
-handle_info({timeout, _TRef, ReqId}, State) ->
- case ets:lookup(State#state.db, ReqId) of
- [{ReqId, Pid, _, MRef}] ->
- ets:delete(State#state.db, ReqId),
- Pid ! {MRef, {'EXCEPTION', #'TIMEOUT'{completion_status=?COMPLETED_MAYBE}}},
- orber:dbg("[~p] orber_iiop_outproxy:handle_info(~p, ~p);~n"
- "Request timed out",
- [?LINE, State#state.host, State#state.port], ?DEBUG_LEVEL),
- {noreply, State, State#state.timeout};
- _ ->
- {noreply, State, State#state.timeout}
- end;
-handle_info(stop, State) ->
- {stop, normal, State};
-handle_info(timeout, State) ->
- case ets:info(State#state.db, size) of
- 0 ->
- orber:dbg("[~p] orber_iiop_outproxy:handle_info(~p, ~p);~n"
- "Outgoing connection timed out after ~p msec",
- [?LINE, State#state.host, State#state.port,
- State#state.timeout], ?DEBUG_LEVEL),
- {stop, normal, State};
- _Amount ->
- %% Still pending request, cannot close the connection.
- {noreply, State, State#state.timeout}
- end;
-handle_info({'EXIT', Parent, Reason}, #state{parent = Parent} = State) ->
- orber:dbg("[~p] orber_iiop_outproxy:handle_info(~p);~nParent terminated.",
- [?LINE, Reason], ?DEBUG_LEVEL),
- {stop, normal, State};
-handle_info({reconfigure, _Options}, State) ->
- %% Currently there are no parameters that can be changed.
- {noreply, State, State#state.timeout};
-handle_info(X, State) ->
- orber:dbg("[~p] orber_iiop_outproxy:handle_info(~p);~nUn-recognized info.",
- [?LINE, X], ?DEBUG_LEVEL),
- {noreply, State, State#state.timeout}.
-
-
-handle_reply(Bytes, State) ->
- %% Check IIOP headers and fetch request id
- case catch checkheaders(cdr_decode:dec_giop_message_header(Bytes)) of
- {'reply', ReplyHeader, Rest, Len, ByteOrder} ->
- case ets:lookup(State#state.db, ReplyHeader#reply_header.request_id) of
- [{_, Pid, TRef, MRef}] ->
- %% Send reply to the correct request process
- cancel_timer(TRef),
- Pid ! {MRef, {reply, ReplyHeader, Rest, Len, ByteOrder, Bytes}},
- ets:delete(State#state.db, ReplyHeader#reply_header.request_id),
- {noreply, State, State#state.timeout};
- _ ->
- {noreply, State, State#state.timeout}
- end;
- {'locate_reply', LocateReplyHeader, LocateRest, LocateLen, LocateByteOrder} ->
- case ets:lookup(State#state.db,
- LocateReplyHeader#locate_reply_header.request_id) of
- [{_, Pid, TRef, MRef}] ->
- %% Send reply to the correct request process
- cancel_timer(TRef),
- Pid ! {MRef, {locate_reply, LocateReplyHeader,
- LocateRest, LocateLen, LocateByteOrder}},
- ets:delete(State#state.db,
- LocateReplyHeader#locate_reply_header.request_id),
- {noreply, State, State#state.timeout};
- _ ->
- {noreply, State, State#state.timeout}
- end;
- {fragment, GIOPHdr, ReqId, false} ->
- %% Last fragment, cancel timer and remove from DB.
- case ets:lookup(State#state.db, ReqId) of
- [{_, Pid, TRef, MRef}] ->
- cancel_timer(TRef),
- Pid ! {fragment, GIOPHdr, ReqId, MRef},
- ets:delete(State#state.db, ReqId),
- {noreply, State, State#state.timeout};
- _ ->
- %% Probably cancelled
- {noreply, State, State#state.timeout}
- end;
- {fragment, GIOPHdr, ReqId, _} ->
- %% More fragments expected
- case ets:lookup(State#state.db, ReqId) of
- [{_, Pid, _, MRef}] ->
- Pid ! {fragment, GIOPHdr, ReqId, MRef},
- {noreply, State, State#state.timeout};
- _ ->
- %% Probably cancelled
- {noreply, State, State#state.timeout}
- end;
- {fragmented, GIOPHdr, ReqId} ->
- %% This the initial message (i.e. a LocateReply or Reply).
- case ets:lookup(State#state.db, ReqId) of
- [{_, Pid, _TRef, MRef}] ->
- Pid ! {fragmented, GIOPHdr, Bytes, ReqId, MRef},
- {noreply, State, State#state.timeout};
- _ ->
- {noreply, State, State#state.timeout}
- end;
- {'EXCEPTION', DecodeException} ->
- orber:dbg("[~p] orber_iiop_outproxy:handle_reply(~p); decode exception(~p).",
- [?LINE, Bytes, DecodeException], ?DEBUG_LEVEL),
- {noreply, State, State#state.timeout};
- {'EXIT', message_error} ->
- orber:dbg("[~p] orber_iiop_outproxy:handle_reply(~p); message error.",
- [?LINE, Bytes], ?DEBUG_LEVEL),
- ME = cdr_encode:enc_message_error(#giop_env{version =
- orber:giop_version()}),
- orber_socket:write(State#state.stype, State#state.socket, ME),
- {noreply, State, State#state.timeout};
- {'EXIT', R} ->
- orber:dbg("[~p] orber_iiop_outproxy:handle_reply(~p); got exit(~p)",
- [?LINE, Bytes, R], ?DEBUG_LEVEL),
- {noreply, State, State#state.timeout};
- close_connection ->
- orber:dbg("[~p] orber_iiop_outproxy:handle_reply();
-The Server-side ORB closed the connection.", [?LINE], ?DEBUG_LEVEL),
- {stop, normal, State};
- {error, no_reply} ->
- {noreply, State, State#state.timeout};
- X ->
- orber:dbg("[~p] orber_iiop_outproxy:handle_reply(~p); message error(~p).",
- [?LINE, Bytes, X], ?DEBUG_LEVEL),
- {noreply, State, State#state.timeout}
- end.
-
-
-%%-----------------------------------------------------------------
-%% Func: code_change/3
-%%-----------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-checkheaders(#giop_message{message_type = ?GIOP_MSG_CLOSE_CONNECTION}) ->
- close_connection;
-checkheaders(#giop_message{message_type = ?GIOP_MSG_FRAGMENT,
- giop_version = {1,2},
- fragments = MoreFrag} = GIOPHdr) ->
- %% A fragment; we must have received a Request or LocateRequest
- %% with fragment-flag set to true.
- %% We need to decode the header to get the request-id.
- ReqId = cdr_decode:peek_request_id(GIOPHdr#giop_message.byte_order,
- GIOPHdr#giop_message.message),
- {fragment, GIOPHdr, ReqId, MoreFrag};
-checkheaders(#giop_message{fragments = true,
- giop_version = {1,2}} = GIOPHdr) ->
- %% Must be a Reply or LocateReply which have been fragmented.
- %% We need to decode the header to get the request-id.
- ReqId = cdr_decode:peek_request_id(GIOPHdr#giop_message.byte_order,
- GIOPHdr#giop_message.message),
- {fragmented, GIOPHdr, ReqId};
-checkheaders(#giop_message{fragments = false,
- message_type = ?GIOP_MSG_REPLY} = GIOPHdr) ->
- {ReplyHeader, Rest, Len} =
- cdr_decode:dec_reply_header(GIOPHdr#giop_message.giop_version,
- GIOPHdr#giop_message.message,
- ?GIOP_HEADER_SIZE,
- GIOPHdr#giop_message.byte_order),
- {'reply', ReplyHeader, Rest, Len, GIOPHdr#giop_message.byte_order};
-checkheaders(#giop_message{fragments = false,
- message_type = ?GIOP_MSG_LOCATE_REPLY} = GIOPHdr) ->
- {LocateReplyHeader, Rest, Len} =
- cdr_decode:dec_locate_reply_header(GIOPHdr#giop_message.giop_version,
- GIOPHdr#giop_message.message,
- ?GIOP_HEADER_SIZE,
- GIOPHdr#giop_message.byte_order),
- {'locate_reply', LocateReplyHeader, Rest, Len, GIOPHdr#giop_message.byte_order};
-checkheaders(What) ->
- orber:dbg("[~p] orber_iiop_outproxy:checkheaders(~p)
-Un-recognized GIOP header.", [?LINE, What], ?DEBUG_LEVEL),
- {error, no_reply}.
-
-
-cancel_timer(infinity) ->
- ok;
-cancel_timer(TRef) ->
- erlang:cancel_timer(TRef).
-
-start_timer(infinity, infinity, _) ->
- infinity;
-start_timer(infinity, Timeout, RequestId) ->
- erlang:start_timer(Timeout, self(), RequestId);
-start_timer(Timeout, _, RequestId) ->
- erlang:start_timer(Timeout, self(), RequestId).
-
-
-
-collect_fragments(GIOPHdr1, InBuffer, Bytes, Proxy, RequestId, MRef) ->
- receive
- %% There are more framents to come; just collect this message and wait for
- %% the rest.
- {fragment, #giop_message{byte_order = _ByteOrder,
- message = Message,
- fragments = true} = GIOPHdr2, RequestId, MRef} ->
- case catch cdr_decode:dec_message_header(null, GIOPHdr2, Message) of
- {_, #fragment_header{}, FragBody, _, _} ->
- collect_fragments(GIOPHdr1, [FragBody|InBuffer],
- Bytes, Proxy, RequestId, MRef);
- Other ->
- cancel(Proxy, RequestId, MRef),
- clear_queue(Proxy, RequestId, MRef),
- orber:dbg("[~p] orber_iiop:collect_fragments(~p)",
- [?LINE, Other], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 18),
- completion_status=?COMPLETED_YES})
- end;
- %% This is the last fragment. Now we can but together the fragments, decode
- %% the reply and send it to the client.
- {fragment, #giop_message{byte_order = ByteOrder,
- message = Message} = GIOPHdr2, RequestId, MRef} ->
- erlang:demonitor(MRef, [flush]),
- case catch cdr_decode:dec_message_header(null, GIOPHdr2, Message) of
- {_, #fragment_header{}, FragBody, _, _} ->
- %% This buffer is all the fragments concatenated.
- Buffer = lists:reverse([FragBody|InBuffer]),
-
- %% Create a GIOP-message which is exactly as if hadn't been fragmented.
- NewGIOP = GIOPHdr1#giop_message
- {message = list_to_binary([GIOPHdr1#giop_message.message|Buffer]),
- fragments = false},
- case checkheaders(NewGIOP) of
- {'reply', ReplyHeader, Rest, Len, ByteOrder} ->
- %% We must keep create a copy of all bytes, as if the
- %% message wasn't fragmented, to be able handle TypeCode
- %% indirection.
- {'reply', ReplyHeader, Rest, Len, ByteOrder,
- list_to_binary([Bytes|Buffer])};
- {'locate_reply', ReplyHdr, Rest, Len, ByteOrder} ->
- {'locate_reply', ReplyHdr, Rest, Len, ByteOrder};
- Error ->
- orber:dbg("[~p] orber_iiop:collect_fragments(~p, ~p);
-Unable to decode Reply or LocateReply header",[?LINE, NewGIOP, Error], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 18),
- completion_status=?COMPLETED_YES})
- end;
- Other ->
- orber:dbg("[~p] orber_iiop:collect_fragments(~p);",
- [?LINE, Other], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 18),
- completion_status=?COMPLETED_YES})
- end;
- {MRef, {'EXCEPTION', E}} ->
- orber:dbg("[~p] orber_iiop:collect_fragments(~p);",
- [?LINE, E], ?DEBUG_LEVEL),
- erlang:demonitor(MRef, [flush]),
- corba:raise(E);
- {'DOWN', MRef, _, Proxy, Reason} when is_pid(Proxy) ->
- orber:dbg("[~p] orber_iiop:collect_fragments(~p);~n"
- "Monitor generated a DOWN message.",
- [?LINE, Reason], ?DEBUG_LEVEL),
- receive
- %% Clear EXIT message from queue
- {'EXIT', _Proxy, _What} ->
- corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_MAYBE})
- after 0 ->
- corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_MAYBE})
- end
- end.
-
-clear_queue(Proxy, RequestId, MRef) ->
- receive
- {fragment, _, RequestId, MRef} ->
- clear_queue(Proxy, RequestId, MRef);
- {MRef, RequestId, cancelled} ->
- %% This is the last message that the proxy will send
- %% after we've cancelled the request.
- erlang:demonitor(MRef, [flush]),
- ok;
- {'DOWN', MRef, _, Proxy, _Reason} ->
- %% The proxy terminated. Clear EXIT message from queue
- receive
- {'EXIT', Proxy, _What} ->
- ok
- after 0 ->
- ok
- end
- end.
-
diff --git a/lib/orber/src/orber_iiop_outsup.erl b/lib/orber/src/orber_iiop_outsup.erl
deleted file mode 100644
index f3627e01a0..0000000000
--- a/lib/orber/src/orber_iiop_outsup.erl
+++ /dev/null
@@ -1,88 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: orber_iiop_outsup.erl
-%%
-%% Description:
-%% This file contains the outgoing IIOP communication supervisor which
-%% holds all active "proxies"
-%%
-%%-----------------------------------------------------------------
--module(orber_iiop_outsup).
-
--behaviour(supervisor).
-
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([start/2, connect/7]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([init/1, terminate/2]).
-
-%%-----------------------------------------------------------------
-%% External interface functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: start/2
-%%-----------------------------------------------------------------
-start(sup, Opts) ->
- supervisor:start_link({local, orber_iiop_outsup}, orber_iiop_outsup,
- {sup, Opts});
-start(_A1, _A2) ->
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Server functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: init/1
-%%-----------------------------------------------------------------
-init({sup, _Opts}) ->
- SupFlags = {simple_one_for_one, 500, 100},
- ChildSpec = [
- {name2, {orber_iiop_outproxy, start, []}, temporary,
- 10000, worker, [orber_iiop_outproxy]}
- ],
- {ok, {SupFlags, ChildSpec}};
-init(_Opts) ->
- {ok, []}.
-
-
-%%-----------------------------------------------------------------
-%% Func: terminate/1
-%%-----------------------------------------------------------------
-terminate(_Reason, _State) ->
- ok.
-
-%%-----------------------------------------------------------------
-%% Func: connect/6
-%%-----------------------------------------------------------------
-connect(Host, Port, SocketType, SocketOptions, Parent, Key, NewKey) ->
- supervisor:start_child(orber_iiop_outsup,
- [{connect, Host, Port, SocketType,
- SocketOptions, Parent, Key, NewKey}]).
-
diff --git a/lib/orber/src/orber_iiop_pm.erl b/lib/orber/src/orber_iiop_pm.erl
deleted file mode 100644
index 72084227aa..0000000000
--- a/lib/orber/src/orber_iiop_pm.erl
+++ /dev/null
@@ -1,894 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: orber_iiop_pm.erl
-%% Description:
-%% This file contains the mapping of addresses on the format {Host, Port}
-%% to a proxy pid.
-%%
-%%-----------------------------------------------------------------
--module(orber_iiop_pm).
-
--behaviour(gen_server).
-
--include_lib("orber/src/orber_iiop.hrl").
--include_lib("orber/include/corba.hrl").
--include_lib("kernel/include/inet.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([start/0, start/1]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([connect/7,
- close_connection/1, close_connection/2,
- list_existing_connections/0,
- list_setup_connections/0,
- list_all_connections/0,
- init/1, handle_call/3, handle_cast/2, handle_info/2,
- code_change/3, terminate/2, stop/0, setup_connection/8,
- reconfigure/1, reconfigure/3, reconfigure/4, add_connection/3,
- sockname2peername/2, peername2sockname/2]).
-
-%%-----------------------------------------------------------------
-%% Macros/Defines
-%%-----------------------------------------------------------------
--define(DEBUG_LEVEL, 7).
-
--define(PM_CONNECTION_DB, orber_iiop_pm_db).
-
--record(state, {connections, queue}).
-
--record(connection, {hp, child, interceptors, slave,
- flags = 0, alias = 0, socketdata = {"Unavailable", 0}}).
-
-%%-----------------------------------------------------------------
-%% External interface functions
-%%-----------------------------------------------------------------
-start() ->
- ignore.
-start(Opts) ->
- gen_server:start_link({local, 'orber_iiop_pm'}, ?MODULE, Opts, []).
-
-
-connect(Host, Port, SocketType, Timeout, Chars, Wchars, Ctx)
- when SocketType == normal ->
- Key = create_key(Host, Port, Ctx),
- case ets:lookup(?PM_CONNECTION_DB, Key) of
- [#connection{child = connecting}] ->
- gen_server:call(orber_iiop_pm, {connect, Host, Port, SocketType,
- [], Chars, Wchars, Key}, Timeout);
- [] ->
- gen_server:call(orber_iiop_pm, {connect, Host, Port, SocketType,
- [], Chars, Wchars, Key}, Timeout);
- [#connection{hp = {_, _, 0}, child = P, interceptors = I}] ->
- {ok, P, [], I, 0};
- [#connection{hp = {_, _, Interface}, child = P, interceptors = I}] ->
- {ok, P, [], I, [Interface]}
- end;
-connect(Host, Port, SocketType, Timeout, Chars, Wchars, Ctx)
- when SocketType == ssl ->
- Key = create_key(Host, Port, Ctx),
- case ets:lookup(?PM_CONNECTION_DB, Key) of
- [#connection{child = connecting}] ->
- SocketOptions = get_ssl_socket_options(Ctx),
- gen_server:call(orber_iiop_pm, {connect, Host, Port, SocketType,
- SocketOptions, Chars, Wchars, Key},
- Timeout);
- [] ->
- SocketOptions = get_ssl_socket_options(Ctx),
- gen_server:call(orber_iiop_pm, {connect, Host, Port, SocketType,
- SocketOptions, Chars, Wchars, Key},
- Timeout);
- [#connection{hp = {_, _, 0}, child = P, interceptors = I}] ->
- {ok, P, [], I, 0};
- [#connection{hp = {_, _, Interface}, child = P, interceptors = I}] ->
- {ok, P, [], I, [Interface]}
- end.
-
-get_ssl_socket_options([]) ->
- SSLOpts =
- case orber_env:ssl_client_options() of
- [] ->
- [{verify, orber_env:ssl_client_verify()},
- {depth, orber_env:ssl_client_depth()},
- {certfile, orber_env:ssl_client_certfile()},
- {cacertfile, orber_env:ssl_client_cacertfile()},
- {password, orber_env:ssl_client_password()},
- {keyfile, orber_env:ssl_client_keyfile()},
- {ciphers, orber_env:ssl_client_ciphers()},
- {cachetimeout, orber_env:ssl_client_cachetimeout()},
- {keepalive, orber_env:iiop_ssl_out_keepalive()}];
- Opts ->
- case orber_tb:check_illegal_tcp_options(Opts) of
- ok ->
- check_old_ssl_client_options([]),
- Opts;
- {error, IllegalOpts} ->
- error_logger:error_report([{application, orber},
- "TCP options not allowed to set on a connection",
- IllegalOpts]),
- error("Illegal TCP option")
- end
- end,
- ssl_client_extra_options(SSLOpts, []);
-get_ssl_socket_options([#'IOP_ServiceContext'
- {context_id=?ORBER_GENERIC_CTX_ID,
- context_data = {configuration, Options}}|_]) ->
- SSLOpts =
- case orber_tb:keysearch(ssl_client_options, Options,
- orber_env:ssl_client_options()) of
- [] ->
- Verify = orber_tb:keysearch(ssl_client_verify, Options,
- orber_env:ssl_client_verify()),
- Depth = orber_tb:keysearch(ssl_client_depth, Options,
- orber_env:ssl_client_depth()),
- Cert = orber_tb:keysearch(ssl_client_certfile, Options,
- orber_env:ssl_client_certfile()),
- CaCert = orber_tb:keysearch(ssl_client_cacertfile, Options,
- orber_env:ssl_client_cacertfile()),
- Pwd = orber_tb:keysearch(ssl_client_password, Options,
- orber_env:ssl_client_password()),
- Key = orber_tb:keysearch(ssl_client_keyfile, Options,
- orber_env:ssl_client_keyfile()),
- Ciphers = orber_tb:keysearch(ssl_client_ciphers, Options,
- orber_env:ssl_client_ciphers()),
- Timeout = orber_tb:keysearch(ssl_client_cachetimeout, Options,
- orber_env:ssl_client_cachetimeout()),
- KeepAlive = orber_tb:keysearch(ssl_server_cachetimeout, Options,
- orber_env:iiop_ssl_out_keepalive()),
- [{verify, Verify},
- {depth, Depth},
- {certfile, Cert},
- {cacertfile, CaCert},
- {password, Pwd},
- {keyfile, Key},
- {ciphers, Ciphers},
- {cachetimeout, Timeout},
- {keepalive, KeepAlive}];
- Opts ->
- case orber_tb:check_illegal_tcp_options(Opts) of
- ok ->
- check_old_ssl_client_options(Options),
- Opts;
- {error, IllegalOpts} ->
- error_logger:error_report([{application, orber},
- "TCP options not allowed to set on a connection",
- IllegalOpts]),
- error("Illegal TCP option")
- end
- end,
- ssl_client_extra_options(SSLOpts, []);
-get_ssl_socket_options([_|T]) ->
- get_ssl_socket_options(T).
-
-
-ssl_client_extra_options([], Acc) ->
- Acc;
-ssl_client_extra_options([{_Type, []}|T], Acc) ->
- ssl_client_extra_options(T, Acc);
-ssl_client_extra_options([{_Type, infinity}|T], Acc) ->
- ssl_client_extra_options(T, Acc);
-ssl_client_extra_options([{Type, Value}|T], Acc) ->
- ssl_client_extra_options(T, [{Type, Value}|Acc]).
-
-add_connection(Key, Key, SockData) ->
- case ets:lookup(?PM_CONNECTION_DB, Key) of
- [Connection] ->
- ets:insert(?PM_CONNECTION_DB,
- Connection#connection{socketdata = SockData});
- [] ->
- ets:insert(?PM_CONNECTION_DB,
- #connection{hp= Key, child = connecting,
- socketdata = SockData})
- end;
-add_connection(Key, NewKey, SockData) ->
- add_connection(Key, Key, SockData),
- add_connection(NewKey, NewKey, SockData).
-
-get_socket_data(Key) ->
- case ets:lookup(?PM_CONNECTION_DB, Key) of
- [#connection{socketdata = SockData}] ->
- SockData;
- _ ->
- {"Unable to extract socket information", 0}
- end.
-
-sockname2peername(SockHost, SockPort) ->
- orber_tb:unique(
- do_select([{#connection{hp = {'$1', '$2', '_'},
- socketdata = {match_type(SockHost),
- match_type(SockPort)},
- _='_'}, [], [{{'$1', '$2'}}]}])).
-
-
-peername2sockname(PeerHost, PeerPort) ->
- orber_tb:unique(
- do_select([{#connection{hp = {match_type(PeerHost),
- match_type(PeerPort),
- '_'},
- socketdata = '$1',
- _='_'}, [], ['$1']}])).
-
-match_type(0) ->
- %% Wildcard port number
- '_';
-match_type("") ->
- %% Wildcard host
- '_';
-match_type(Key) ->
- %% Wildcard not used.
- Key.
-
-create_key(Host, Port, []) ->
- {Host, Port, 0};
-create_key(Host, Port,
- [#'IOP_ServiceContext'
- {context_id=?ORBER_GENERIC_CTX_ID,
- context_data = {interface, Interface}}|_]) when is_list(Interface) ->
- {Host, Port, Interface};
-create_key(Host, Port,
- [#'IOP_ServiceContext'
- {context_id=?ORBER_GENERIC_CTX_ID,
- context_data = {interface, Interface}}|_]) ->
- orber:dbg("[~p] orber_iiop_pm:create_key(~p, ~p);~n"
- "The supplied interface must be a string.",
- [?LINE, Host, Port, Interface], ?DEBUG_LEVEL),
- corba:raise(#'BAD_CONTEXT'{completion_status=?COMPLETED_NO});
-create_key(Host, Port, [_|T]) ->
- create_key(Host, Port, T).
-
-reconfigure(Options) ->
- {Local, Proxy} = check_options(Options, [], []),
- reconfigure_local(Local),
- reconfigure_proxy(Proxy).
-
-
-reconfigure(Options, Host, Port) ->
- reconfigure(Options, Host, Port, 0).
-reconfigure(Options, Host, Port, Interface) ->
- case ets:lookup(?PM_CONNECTION_DB, {Host, Port, Interface}) of
- [#connection{child = P}] when is_pid(P) ->
- case check_options(Options, [], []) of
- {[], Proxy} ->
- reconfigure_proxy(Proxy, [P]);
- {Local, Proxy} ->
- reconfigure_proxy(Proxy, [P]),
- gen_server:call(orber_iiop_pm, {reconfigure, Local,
- Host, Port, Interface}, infinity)
- end;
- _ ->
- {error, "No proxy matched the supplied reference"}
- end.
-
-reconfigure_local([]) ->
- ok;
-reconfigure_local(Options) ->
- gen_server:call(orber_iiop_pm, {reconfigure, Options}, infinity).
-
-reconfigure_proxy([]) ->
- ok;
-reconfigure_proxy(Options) ->
- reconfigure_proxy(Options, do_select([{#connection{child = '$1', _='_'},
- [], ['$1']}])).
-
-reconfigure_proxy(Options, [Pid|T]) ->
- Pid ! {reconfigure, Options},
- reconfigure_proxy(Options, T);
-reconfigure_proxy(_Options, []) ->
- ok.
-
-
-check_options([{interceptors, false}|Options], Local, Proxy) ->
- check_options(Options, [{interceptors, false}|Local], Proxy);
-check_options([{interceptors, {native, LPIs}}|Options], Local, Proxy) ->
- check_options(Options, [{interceptors, {native, LPIs}}|Local], Proxy);
-check_options([{fake, option}|Options], Local, Proxy) ->
- check_options(Options, Local, [{fake, option}|Proxy]);
-check_options([_|Options], Local, Proxy) ->
- check_options(Options, Local, Proxy);
-check_options([], Local, Proxy) ->
- {Local, Proxy}.
-
-
-close_connection(PeerData) ->
- close_connection(PeerData, 0).
-
-close_connection(PeerData, Interface) ->
- gen_server:call(orber_iiop_pm, {disconnect, PeerData, Interface}, infinity).
-
-
-list_existing_connections() ->
- transform(
- lists:sort(
- do_select([{#connection{hp = {'$2','$3','$4'}, child = '$1', _='_'},
- [{is_pid, '$1'}], [{{'$1', '$2','$3','$4'}}]}])), []).
-
-list_setup_connections() ->
- transform(
- lists:sort(
- do_select([{#connection{hp = {'$1','$2','$3'}, child = connecting, _='_'}, [],
- [{{'$1','$2','$3'}}]}])), []).
-
-list_all_connections() ->
- transform(
- lists:sort(
- do_select([{#connection{hp = {'$2','$3','$4'}, child = '$1', _='_'}, [],
- [{{'$1','$2','$3', '$4'}}]}])), []).
-
-%% Since the connections interface can be 0 or an ip-address we want to
-%% transform those containing 0.
-transform([{C, H, P, 0}, {C, H, P, I}|T], Acc) ->
- %% ACL defined interface. Drop the anonymous one.
- transform(T, [{H, P, I}|Acc]);
-transform([{_C, H, P, 0}|T], Acc) ->
- %% No interface supplied. Drop the 0.
- transform(T, [{H, P}|Acc]);
-transform([{_C, H, P, I}|T], Acc) ->
- %% Interface supplied. Keep it.
- transform(T, [{H, P, I}|Acc]);
-transform([{H,P,0}|T], Acc) ->
- transform(T, [{H,P}|Acc]);
-transform([{H,P,I}|T], Acc) ->
- transform(T, [{H,P,I}|Acc]);
-transform([H|T], Acc) ->
- transform(T, [H|Acc]);
-transform([], Acc) ->
- Acc.
-
-do_select(Pattern) ->
- case catch ets:select(?PM_CONNECTION_DB, Pattern) of
- {'EXIT', _What} ->
- [];
- Result ->
- Result
- end.
-
-%%-----------------------------------------------------------------
-%% Internal interface functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: stop/0 (Only used for test purpose !!!!!!)
-%%-----------------------------------------------------------------
-stop() ->
- gen_server:call(orber_iiop_pm, stop).
-
-%%-----------------------------------------------------------------
-%% Server functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: init/1
-%%-----------------------------------------------------------------
-init(_Opts) ->
- process_flag(trap_exit, true),
- {ok, #state{connections = ets:new(orber_iiop_pm_db,
- [{keypos, 2}, set, public, named_table]),
- queue = ets:new(orber_iiop_pm_queue, [bag])}}.
-
-%%-----------------------------------------------------------------
-%% Func: terminate/2
-%%-----------------------------------------------------------------
-terminate(_Reason, #state{queue = Q}) ->
- %% Kill all proxies and close table before terminating
- stop_all_proxies(ets:first(?PM_CONNECTION_DB)),
- ets:delete(?PM_CONNECTION_DB),
- ets:delete(Q),
- ok.
-
-stop_all_proxies('$end_of_table') ->
- ok;
-stop_all_proxies(Key) ->
- case ets:lookup(?PM_CONNECTION_DB, Key) of
- [] ->
- ok;
- [#connection{child = connecting, interceptors = I}] ->
- invoke_connection_closed(I);
- [#connection{child = P, interceptors = I}] ->
- invoke_connection_closed(I),
- catch orber_iiop_outproxy:stop(P)
- end,
- stop_all_proxies(ets:next(?PM_CONNECTION_DB, Key)).
-
-%%-----------------------------------------------------------------
-%% Func: handle_call/3
-%%-----------------------------------------------------------------
-handle_call({connect, Host, Port, SocketType, SocketOptions, Chars, Wchars, Key},
- From, State) ->
- case ets:lookup(?PM_CONNECTION_DB, Key) of
- [#connection{child = connecting}] ->
- %% Another client already requested a connection to the given host/port.
- %% Just add this client to the queue.
- ets:insert(State#state.queue, {Key, From}),
- {noreply, State};
- [#connection{hp = {_,_,0}, child = P, interceptors = I}] ->
- %% This case will occur if the PortMapper completed a connection
- %% between the client's ets:lookup and receiving this request.
- {reply, {ok, P, [], I, 0}, State};
- [#connection{hp = {_,_,Intf}, child = P, interceptors = I}] ->
- %% This case will occur if the PortMapper completed a connection
- %% between the client's ets:lookup and receiving this request.
- {reply, {ok, P, [], I, [Intf]}, State};
- [] ->
- %% The first time a connection is requested to the given host/port.
- case catch spawn_link(?MODULE, setup_connection,
- [self(), Host, Port, SocketType,
- SocketOptions, Chars, Wchars, Key]) of
- Slave when is_pid(Slave) ->
- ets:insert(?PM_CONNECTION_DB,
- #connection{hp = Key, child = connecting,
- interceptors = false, slave = Slave}),
- ets:insert(State#state.queue, {Key, From}),
- {noreply, State};
- What ->
- orber:dbg("[~p] orber_iiop_pm:handle_call(connect);~n"
- "Unable to invoke setup_connection due to: ~n~p~n",
- [?LINE, What], ?DEBUG_LEVEL),
- {reply,
- {'EXCEPTION', #'INTERNAL'{completion_status=?COMPLETED_NO}},
- State}
- end
- end;
-handle_call({disconnect, PeerData, Interface}, _From, State) ->
- {reply, do_disconnect(PeerData, Interface, State), State};
-handle_call({reconfigure, Options, Host, Port, Interface},
- _From, State) ->
- case ets:lookup(?PM_CONNECTION_DB, {Host, Port, Interface}) of
- [] ->
- {reply, {error, "No proxy matched the supplied reference"}, State};
- [Connection] ->
- NewConnection = update_connection(Connection, Options),
- ets:insert(?PM_CONNECTION_DB, NewConnection),
- {reply, ok, State}
- end;
-handle_call({reconfigure, Options}, _From, State) ->
- case catch update_db(ets:first(?PM_CONNECTION_DB), Options) of
- ok ->
- {reply, ok, State};
- _What ->
- {reply, {error, "Unable to change configuration"}, State}
- end;
-handle_call(stop, _From, State) ->
- {stop, normal, ok, State};
-handle_call(_, _, State) ->
- {noreply, State}.
-
-update_db('$end_of_table', _) ->
- ok;
-update_db(Key, Options) ->
- [Connection] = ets:lookup(?PM_CONNECTION_DB, Key),
- NewConnection = update_connection(Connection, Options),
- ets:insert(?PM_CONNECTION_DB, NewConnection),
- update_db(ets:next(?PM_CONNECTION_DB, Key), Options).
-
-
-update_connection(Connection, [{interceptors, false}|Options]) ->
- update_connection(Connection#connection{interceptors = false}, Options);
-update_connection(#connection{interceptors = false,
- hp = {PH, PP, _},
- socketdata = {SH, SP}} = Connection,
- [{interceptors, {native, LPIs}}|Options]) ->
- %% No Interceptor(s). Add the same Ref used by the built in interceptors.
- update_connection(Connection#connection{interceptors =
- {native, {PH, PP, SH, SP}, LPIs}},
- Options);
-update_connection(#connection{interceptors = {native, Ref, _}} = Connection,
- [{interceptors, {native, LPIs}}|Options]) ->
- %% Interceptor(s) already in use. We must use the same Ref as before.
- update_connection(Connection#connection{interceptors =
- {native, Ref, LPIs}},
- Options);
-update_connection(Connection, [H|T]) ->
- orber:dbg("[~p] orber_iiop_pm:update_connection(~p, ~p)~n"
- "Unable to update the connection.~n",
- [?LINE, Connection, H], ?DEBUG_LEVEL),
- update_connection(Connection, T);
-update_connection(Connection, []) ->
- Connection.
-
-do_disconnect([], _Interface, _State) ->
- ok;
-do_disconnect([{Host, Port}|T], Interface, State) ->
- case ets:lookup(?PM_CONNECTION_DB, {Host, Port, Interface}) of
- [] ->
- ok;
- [#connection{child = connecting, interceptors = I}] ->
- ets:delete(?PM_CONNECTION_DB, {Host, Port, Interface}),
- Exc = {'EXCEPTION',#'INTERNAL'{completion_status = ?COMPLETED_NO}},
- send_reply_to_queue(ets:lookup(State#state.queue,
- {Host, Port, Interface}), Exc),
- ets:delete(State#state.queue, {Host, Port, Interface}),
- invoke_connection_closed(I);
- [#connection{child = P, interceptors = I}] ->
- unlink(P),
- catch orber_iiop_outproxy:stop(P),
- ets:delete(?PM_CONNECTION_DB, {Host, Port, Interface}),
- invoke_connection_closed(I)
- end,
- do_disconnect(T, Interface, State).
-
-%%-----------------------------------------------------------------
-%% Func: handle_cast/2
-%%-----------------------------------------------------------------
-handle_cast(stop, State) ->
- {stop, normal, State};
-handle_cast(_, State) ->
- {noreply, State}.
-
-%%-----------------------------------------------------------------
-%% Func: handle_info/2
-%%-----------------------------------------------------------------
-%% Trapping exits
-handle_info({'EXIT', Pid, Reason}, State) ->
- %% Check the most common scenario first, i.e., a proxy terminates.
- case ets:match_object(?PM_CONNECTION_DB, #connection{child = Pid, _='_'}) of
- [#connection{hp = K, interceptors = I}] ->
- ets:delete(?PM_CONNECTION_DB, K),
- invoke_connection_closed(I),
- {noreply, State};
- [#connection{hp = K, interceptors = I}, #connection{hp = K2}] ->
- ets:delete(?PM_CONNECTION_DB, K),
- ets:delete(?PM_CONNECTION_DB, K2),
- invoke_connection_closed(I),
- {noreply, State};
- [] when Reason == normal ->
- %% This might have been a spawned 'setup_connection' which terminated
- %% after sucessfully setting up a new connection.
- {noreply, State};
- [] ->
- %% Wasn't a proxy. Hence, we must test if it was a spawned
- %% 'setup_connection' that failed.
- case ets:match_object(?PM_CONNECTION_DB, #connection{slave = Pid, _='_'}) of
- [#connection{hp = K, child = connecting, interceptors = I}] ->
- ets:delete(?PM_CONNECTION_DB, K),
- invoke_connection_closed(I),
- Exc = {'EXCEPTION',#'INTERNAL'{completion_status = ?COMPLETED_NO}},
- send_reply_to_queue(ets:lookup(State#state.queue, K), Exc),
- ets:delete(State#state.queue, K),
- orber:dbg("[~p] orber_iiop_pm:handle_info(setup_failed ~p);~n"
- "It was not possible to create a connection to the"
- " given host/port.",
- [?LINE, K], ?DEBUG_LEVEL),
- {noreply, State};
- [#connection{hp = K, child = connecting, interceptors = I},
- #connection{hp = K2}] ->
- ets:delete(?PM_CONNECTION_DB, K),
- ets:delete(?PM_CONNECTION_DB, K2),
- invoke_connection_closed(I),
- Exc = {'EXCEPTION',#'INTERNAL'{completion_status = ?COMPLETED_NO}},
- send_reply_to_queue(ets:lookup(State#state.queue, K), Exc),
- ets:delete(State#state.queue, K),
- orber:dbg("[~p] orber_iiop_pm:handle_info(setup_failed ~p);~n"
- "It was not possible to create a connection to the"
- " given host/port.",
- [?LINE, K], ?DEBUG_LEVEL),
- {noreply, State};
- _ ->
- {noreply, State}
- end
- end;
-handle_info({setup_failed, {Host, Port, _} = Key, Key, Exc}, State) ->
- %% Deletet the data from the connection DB first to avoid clients from
- %% trying to access it again.
- ets:delete(?PM_CONNECTION_DB, Key),
- %% Now we can send whatever exception received.
- send_reply_to_queue(ets:lookup(State#state.queue, Key), Exc),
- ets:delete(State#state.queue, Key),
- orber:dbg("[~p] orber_iiop_pm:handle_info(setup_failed ~p ~p);~n"
- "It was not possible to create a connection to the given host/port.",
- [?LINE, Host, Port], ?DEBUG_LEVEL),
- {noreply, State};
-handle_info({setup_failed, {Host, Port, _} = Key, NewKey, Exc}, State) ->
- %% Deletet the data from the connection DB first to avoid clients from
- %% trying to access it again.
- ets:delete(?PM_CONNECTION_DB, Key),
- ets:delete(?PM_CONNECTION_DB, NewKey),
- %% Now we can send whatever exception received.
- send_reply_to_queue(ets:lookup(State#state.queue, Key), Exc),
- ets:delete(State#state.queue, Key),
- orber:dbg("[~p] orber_iiop_pm:handle_info(setup_failed ~p ~p);~n"
- "It was not possible to create a connection to the given host/port.",
- [?LINE, Host, Port], ?DEBUG_LEVEL),
- {noreply, State};
-handle_info({setup_successfull, Key, Key, {Child, Ctx, Int}}, State) ->
- %% Create a link to the proxy and store it in the connection DB.
- link(Child),
- case ets:lookup(?PM_CONNECTION_DB, Key) of
- [Connection] ->
- ets:insert(?PM_CONNECTION_DB,
- Connection#connection{hp = Key, child = Child,
- interceptors = Int,
- slave = undefined});
- [] ->
- ets:insert(?PM_CONNECTION_DB,
- #connection{hp = Key, child = Child,
- interceptors = Int,
- slave = undefined})
- end,
- %% Send the Proxy reference to all waiting clients.
- case Key of
- {_, _, 0} ->
- send_reply_to_queue(ets:lookup(State#state.queue, Key),
- {ok, Child, Ctx, Int, 0});
- {_, _, Interface} ->
- send_reply_to_queue(ets:lookup(State#state.queue, Key),
- {ok, Child, Ctx, Int, [Interface]})
- end,
- %% Reset the queue.
- ets:delete(State#state.queue, Key),
- {noreply, State};
-handle_info({setup_successfull, Key, NewKey, {Child, Ctx, Int}}, State) ->
- %% Create a link to the proxy and store it in the connection DB.
- link(Child),
- case ets:lookup(?PM_CONNECTION_DB, NewKey) of
- [Connection] ->
- ets:insert(?PM_CONNECTION_DB,
- Connection#connection{hp = NewKey, child = Child,
- interceptors = Int,
- slave = undefined});
- [] ->
- ets:insert(?PM_CONNECTION_DB,
- #connection{hp = NewKey, child = Child,
- interceptors = Int,
- slave = undefined})
- end,
- case ets:lookup(?PM_CONNECTION_DB, Key) of
- [Connection2] ->
- ets:insert(?PM_CONNECTION_DB,
- Connection2#connection{hp = Key, child = Child,
- interceptors = Int,
- slave = undefined});
- [] ->
- ets:insert(?PM_CONNECTION_DB,
- #connection{hp = Key, child = Child,
- interceptors = Int,
- slave = undefined})
- end,
- %% Send the Proxy reference to all waiting clients.
- case NewKey of
- {_, _, 0} ->
- send_reply_to_queue(ets:lookup(State#state.queue, Key),
- {ok, Child, Ctx, Int, 0});
- {_, _, Interface} ->
- send_reply_to_queue(ets:lookup(State#state.queue, Key),
- {ok, Child, Ctx, Int, [Interface]})
- end,
- %% Reset the queue.
- ets:delete(State#state.queue, Key),
- {noreply, State};
-handle_info(_, State) ->
- {noreply, State}.
-
-
-send_reply_to_queue([], _) ->
- ok;
-send_reply_to_queue([{_, Client}|T], Reply) ->
- gen_server:reply(Client, Reply),
- send_reply_to_queue(T, Reply).
-
-%%-----------------------------------------------------------------
-%% Func: code_change/3
-%%-----------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-setup_connection(PMPid, Host, Port, SocketType, SocketOptions, Chars, Wchars, Key) ->
- case catch access_allowed(Host, Port, SocketType, Key) of
- ok ->
- do_setup_connection(PMPid, Host, Port, SocketType, SocketOptions,
- Chars, Wchars, Key, Key);
- {ok, Interface} ->
- do_setup_connection(PMPid, Host, Port, SocketType,
- [{ip, Interface}|SocketOptions],
- Chars, Wchars, Key, Key);
- {ok, Interface, NewKey} ->
- do_setup_connection(PMPid, Host, Port, SocketType,
- [{ip, Interface}|SocketOptions],
- Chars, Wchars, Key, NewKey);
- false ->
- orber_tb:info("Blocked connect attempt to ~s - ~p", [Host, Port]),
- PMPid ! {setup_failed, Key, Key,
- {'EXCEPTION', #'NO_PERMISSION'{completion_status=?COMPLETED_NO}}},
- ok;
- Reason ->
- orber:dbg("[~p] orber_iiop_pm:handle_call(connect ~p ~p); failed~n"
- "Reason: ~p",
- [?LINE, Host, Port, Reason], ?DEBUG_LEVEL),
- PMPid ! {setup_failed, Key, Key,
- {'EXCEPTION', #'COMM_FAILURE'{completion_status=?COMPLETED_NO}}},
- ok
- end.
-
-
-do_setup_connection(PMPid, Host, Port, SocketType, SocketOptions, Chars,
- Wchars, Key, NewKey) ->
- case catch orber_iiop_outsup:connect(Host, Port, SocketType,
- SocketOptions, PMPid, Key, NewKey) of
- {error, {'EXCEPTION', E}} ->
- orber:dbg("[~p] orber_iiop_pm:handle_call(connect ~p ~p);~n"
- "Raised Exc: ~p",
- [?LINE, Host, Port, E], ?DEBUG_LEVEL),
- PMPid ! {setup_failed, Key, NewKey, {'EXCEPTION', E}},
- ok;
- {error, Reason} ->
- orber:dbg("[~p] orber_iiop_pm:handle_call(connect ~p ~p);~n"
- "Got EXIT: ~p",
- [?LINE, Host, Port, Reason], ?DEBUG_LEVEL),
- PMPid ! {setup_failed, Key, NewKey,
- {'EXCEPTION', #'INTERNAL'{completion_status=?COMPLETED_NO}}},
- ok;
- {ok, undefined} ->
- orber:dbg("[~p] orber_iiop_pm:handle_call(connect ~p ~p);~n"
- "Probably no listener on the given Node/Port or timedout.",
- [?LINE, Host, Port], ?DEBUG_LEVEL),
- PMPid ! {setup_failed, Key, NewKey,
- {'EXCEPTION', #'COMM_FAILURE'{minor=(?ORBER_VMCID bor 1),
- completion_status=?COMPLETED_NO}}},
- ok;
- {ok, Child} ->
- case init_interceptors(Host, Port, get_socket_data(Key)) of
- {'EXCEPTION', E} ->
- PMPid ! {setup_failed, Key, NewKey, {'EXCEPTION', E}},
- ok;
- Interceptors ->
- BiDirCtx = orber:bidir_context(),
- Ctx = case orber:exclude_codeset_ctx() of
- true ->
- BiDirCtx;
- _ ->
- CodeSetCtx =
- #'CONV_FRAME_CodeSetContext'
- {char_data = Chars,
- wchar_data = Wchars},
- [#'IOP_ServiceContext'
- {context_id=?IOP_CodeSets,
- context_data = CodeSetCtx} | BiDirCtx]
- end,
- PMPid ! {setup_successfull, Key, NewKey,
- {Child, Ctx, Interceptors}},
- ok
- end
- end.
-
-access_allowed(Host, Port, Type, {_,_,UserInterface}) ->
- Flags = orber:get_flags(),
- case ?ORB_FLAG_TEST(Flags, ?ORB_ENV_USE_ACL_OUTGOING) of
- false when UserInterface == 0 ->
- get_local_interface(Type);
- false ->
- inet:getaddr(UserInterface, get_ip_family(UserInterface));
- true ->
- SearchFor =
- case Type of
- normal ->
- tcp_out;
- ssl ->
- ssl_out
- end,
- {ok, Ip} = inet:getaddr(Host, get_ip_family(Host)),
- case orber_acl:match(Ip, SearchFor, true) of
- {true, [], 0} ->
- get_local_interface(Type);
- {true, [], Port} ->
- get_local_interface(Type);
- {true, [], {Min, Max}} when Port >= Min, Port =< Max ->
- get_local_interface(Type);
- {true, [Interface], 0} ->
- {ok, NewIp} = inet:getaddr(Interface, get_ip_family(Interface)),
- {ok, NewIp, {Host, Port, 0}};
- {true, [Interface], Port} ->
-
- {ok, NewIp} = inet:getaddr(Interface, get_ip_family(Interface)),
- {ok, NewIp, {Host, Port, 0}};
- {true, [Interface], {Min, Max}} when Port >= Min, Port =< Max ->
-
- {ok, NewIp} = inet:getaddr(Interface, get_ip_family(Interface)),
- {ok, NewIp, {Host, Port, 0}};
- _ ->
- false
- end
- end.
-
-get_local_interface(normal) ->
- case orber_env:ip_address_local() of
- [] ->
- ok;
- [Interface] ->
- inet:getaddr(Interface, get_ip_family(Interface))
- end;
-get_local_interface(ssl) ->
- case orber_env:iiop_ssl_ip_address_local() of
- [] ->
- ok;
- [Interface] ->
- inet:getaddr(Interface, get_ip_family(Interface))
- end.
-
-get_ip_family(Addr) ->
- [Family] = orber_socket:get_ip_family_opts(Addr),
- Family.
-
-invoke_connection_closed(false) ->
- ok;
-invoke_connection_closed({native, Ref, PIs}) ->
- (catch orber_pi:closed_out_connection(PIs, Ref));
-invoke_connection_closed({_Type, _PIs}) ->
- ok.
-
-
-init_interceptors(Host, Port, {SHost, SPort}) ->
- case orber:get_interceptors() of
- {native, PIs} ->
- case catch orber_pi:new_out_connection(PIs, Host, Port, SHost, SPort) of
- {'EXIT', R} ->
- orber:dbg("[~p] orber_iiop_pm:init_interceptors(~p); Got Exit: ~p.~n"
- "One or more Interceptor incorrect or undefined?",
- [?LINE, PIs, R], ?DEBUG_LEVEL),
- {'EXCEPTION', #'COMM_FAILURE'{minor=(?ORBER_VMCID bor 2),
- completion_status=?COMPLETED_NO}};
- IntRef ->
- {native, IntRef, PIs}
- end;
- Other ->
- %% Either 'false' or {Type, PIs}.
- Other
- end.
-
-
-check_old_ssl_client_options(Options) ->
- try
- 0 = orber_tb:keysearch(ssl_client_verify, Options,
- orber_env:ssl_client_verify()),
- 1 = orber_tb:keysearch(ssl_client_depth, Options,
- orber_env:ssl_client_depth()),
- [] = orber_tb:keysearch(ssl_client_certfile, Options,
- orber_env:ssl_client_certfile()),
- [] = orber_tb:keysearch(ssl_client_cacertfile, Options,
- orber_env:ssl_client_cacertfile()),
- [] = orber_tb:keysearch(ssl_client_password, Options,
- orber_env:ssl_client_password()),
- [] = orber_tb:keysearch(ssl_client_keyfile, Options,
- orber_env:ssl_client_keyfile()),
- [] = orber_tb:keysearch(ssl_client_ciphers, Options,
- orber_env:ssl_client_ciphers()),
- infinity = orber_tb:keysearch(ssl_client_cachetimeout, Options,
- orber_env:ssl_client_cachetimeout()),
- false = orber_tb:keysearch(iiop_ssl_out_keepalive, Options,
- orber_env:iiop_ssl_out_keepalive())
-
- catch
- _:_ ->
- error_logger:warning_report([{application, orber},
- "Ignoring deprecated ssl client options used together with the ssl_client_options"])
- end.
-
-
-
-
-%%-----------------------------------------------------------------
-%% END OF MODULE
-%%-----------------------------------------------------------------
diff --git a/lib/orber/src/orber_iiop_socketsup.erl b/lib/orber/src/orber_iiop_socketsup.erl
deleted file mode 100644
index 43b5444c82..0000000000
--- a/lib/orber/src/orber_iiop_socketsup.erl
+++ /dev/null
@@ -1,86 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: orber_iiop_socketsup.erl
-%% Description:
-%% This file contains the supervisor for the socket accept processes.
-%%
-%%-----------------------------------------------------------------
--module(orber_iiop_socketsup).
-
--behaviour(supervisor).
-
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([start/2, start_accept/3, start_accept/4]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([init/1, terminate/2]).
-
-%%-----------------------------------------------------------------
-%% External interface functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: start/2
-%%-----------------------------------------------------------------
-start(sup, Opts) ->
- supervisor:start_link({local, orber_iiop_socketsup}, orber_iiop_socketsup,
- {sup, Opts});
-start(_A1, _A2) ->
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Server functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: init/1
-%%-----------------------------------------------------------------
-init({sup, _Opts}) ->
- SupFlags = {simple_one_for_one, 500, 100},
- ChildSpec = [
- {name3, {orber_iiop_net_accept, start, []}, temporary,
- 10000, worker, [orber_iiop_net_accept]}
- ],
- {ok, {SupFlags, ChildSpec}};
-init(_Opts) ->
- {ok, []}.
-
-
-%%-----------------------------------------------------------------
-%% Func: terminate/2
-%%-----------------------------------------------------------------
-terminate(_Reason, _State) ->
- ok.
-
-%%-----------------------------------------------------------------
-%% Func: start_connection/1
-%%-----------------------------------------------------------------
-start_accept(Type, Listen, Ref) ->
- start_accept(Type, Listen, Ref, []).
-start_accept(Type, Listen, Ref, ProxyOptions) ->
- supervisor:start_child(orber_iiop_socketsup, [Type, Listen, Ref, ProxyOptions]).
-
diff --git a/lib/orber/src/orber_iiop_tracer.erl b/lib/orber/src/orber_iiop_tracer.erl
deleted file mode 100644
index 8d6cd2e8b8..0000000000
--- a/lib/orber/src/orber_iiop_tracer.erl
+++ /dev/null
@@ -1,232 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%--------------------------------------------------------------------
-%% File : orber_iiop_tracer.erl
-%% Purpose : Use for debugging only.
-%%--------------------------------------------------------------------
-
--module(orber_iiop_tracer).
-
-
-
-
-
-%% Interceptor functions.
--export([new_out_connection/5,
- new_in_connection/5,
- closed_in_connection/1,
- closed_out_connection/1,
- in_request_encoded/6,
- in_reply_encoded/6,
- out_reply_encoded/6,
- out_request_encoded/6,
- in_request/6,
- in_reply/6,
- out_reply/6,
- out_request/6]).
-
-
-%%--------------- INTERCEPTOR FUNCTIONS ----------------------
-%%------------------------------------------------------------
-%% function : new_in_connection
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-new_in_connection(_Arg, PHost, PPort, SHost, SPort) ->
- error_logger:info_msg("=============== new_in_connection ========~n"
- "Node : ~p~n"
- "From : ~s:~p~n"
- "To : ~s:~p~n"
- "==========================================~n",
- [node(), PHost, PPort, SHost, SPort]),
- {PHost, PPort, SHost, SPort}.
-
-%%------------------------------------------------------------
-%% function : new_out_connection
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-new_out_connection(_Arg, PHost, PPort, SHost, SPort) ->
- error_logger:info_msg("=============== new_out_connection =======~n"
- "Node : ~p~n"
- "From : ~s:~p~n"
- "To : ~s:~p~n"
- "==========================================~n",
- [node(), SHost, SPort, PHost, PPort]),
- {PHost, PPort, SHost, SPort}.
-
-%%------------------------------------------------------------
-%% function : closed_in_connection
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-closed_in_connection(Arg) ->
- error_logger:info_msg("=============== closed_in_connection =====~n"
- "Node : ~p~n"
- "Connection: ~p~n"
- "==========================================~n",
- [node(), Arg]),
- Arg.
-
-%%------------------------------------------------------------
-%% function : closed_out_connection
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-closed_out_connection(Arg) ->
- error_logger:info_msg("=============== closed_out_connection ====~n"
- "Node : ~p~n"
- "Connection: ~p~n"
- "==========================================~n",
- [node(), Arg]),
- Arg.
-
-%%------------------------------------------------------------
-%% function : in_request_encoded
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-in_request_encoded(Ref, _ObjKey, Ctx, Op, Bin, Args) ->
- error_logger:info_msg("=============== in_request_encoded =======~n"
- "Connection: ~p~n"
- "Operation : ~p~n"
- "Body : ~p~n"
- "Context : ~p~n"
- "==========================================~n",
- [Ref, Op, Bin, Ctx]),
- {Bin, Args}.
-
-%%------------------------------------------------------------
-%% function : in_reply_encoded
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-in_reply_encoded(Ref, _ObjKey, Ctx, Op, Bin, Args) ->
- error_logger:info_msg("============== in_reply_encoded ==========~n"
- "Connection: ~p~n"
- "Operation : ~p~n"
- "Body : ~p~n"
- "Context : ~p~n"
- "==========================================~n",
- [Ref, Op, Bin, Ctx]),
- {Bin, Args}.
-
-%%------------------------------------------------------------
-%% function : out_reply_encoded
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-out_reply_encoded(Ref, ObjKey, Ctx, Op, Bin, Args) ->
- error_logger:info_msg("============== out_reply_encoded =========~n"
- "Connection: ~p~n"
- "Operation : ~p~n"
- "Body : ~p~n"
- "Context : ~p~n"
- "Object : ~p~n"
- "==========================================~n",
- [Ref, Op, Bin, Ctx, ObjKey]),
- {Bin, Args}.
-
-%%------------------------------------------------------------
-%% function : out_request_encoded
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-out_request_encoded(Ref, _ObjKey, Ctx, Op, Bin, Args) ->
- error_logger:info_msg("============== out_request_encoded =======~n"
- "Connection: ~p~n"
- "Operation : ~p~n"
- "Body : ~p~n"
- "Context : ~p~n"
- "==========================================~n",
- [Ref, Op, Bin, Ctx]),
- {Bin, Args}.
-
-%%------------------------------------------------------------
-%% function : in_request
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-in_request(Ref, ObjKey, Ctx, Op, Params, Args) ->
- error_logger:info_msg("=============== in_request ===============~n"
- "Connection: ~p~n"
- "Operation : ~p~n"
- "Parameters: ~p~n"
- "Context : ~p~n"
- "Object : ~p~n"
- "==========================================~n",
- [Ref, Op, Params, Ctx, ObjKey]),
- {Params, Args}.
-
-%%------------------------------------------------------------
-%% function : in_reply
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-in_reply(Ref, _ObjKey, Ctx, Op, Reply, Args) ->
- error_logger:info_msg("=============== in_reply =================~n"
- "Connection: ~p~n"
- "Operation : ~p~n"
- "Reply : ~p~n"
- "Context : ~p~n"
- "==========================================~n",
- [Ref, Op, Reply, Ctx]),
- {Reply, Args}.
-
-%%------------------------------------------------------------
-%% function : out_reply
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-out_reply(Ref, ObjKey, Ctx, Op, Reply, Args) ->
- error_logger:info_msg("=============== out_reply ================~n"
- "Connection: ~p~n"
- "Operation : ~p~n"
- "Reply : ~p~n"
- "Context : ~p~n"
- "Object : ~p~n"
- "==========================================~n",
- [Ref, Op, Reply, Ctx, ObjKey]),
- {Reply, Args}.
-
-%%------------------------------------------------------------
-%% function : out_request
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-out_request(Ref, _ObjKey, Ctx, Op, Params, Args) ->
- error_logger:info_msg("=============== out_request ==============~n"
- "Connection: ~p~n"
- "Operation : ~p~n"
- "Parameters: ~p~n"
- "Context : ~p~n"
- "==========================================~n",
- [Ref, Op, Params, Ctx]),
- {Params, Args}.
-
-
-
-
-%%======================================================================
-%% END OF MODULE
-%%======================================================================
-
diff --git a/lib/orber/src/orber_iiop_tracer_silent.erl b/lib/orber/src/orber_iiop_tracer_silent.erl
deleted file mode 100644
index 659de0acee..0000000000
--- a/lib/orber/src/orber_iiop_tracer_silent.erl
+++ /dev/null
@@ -1,191 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%--------------------------------------------------------------------
-%% File : orber_iiop_tracer_silent.erl
-%% Purpose : Use for debugging only.
-%%--------------------------------------------------------------------
-
--module(orber_iiop_tracer_silent).
-
-
-%% Interceptor functions.
--export([new_out_connection/5,
- new_in_connection/5,
- closed_in_connection/1,
- closed_out_connection/1,
- in_request_encoded/6,
- in_reply_encoded/6,
- out_reply_encoded/6,
- out_request_encoded/6,
- in_request/6,
- in_reply/6,
- out_reply/6,
- out_request/6]).
-
-
-%%--------------- INTERCEPTOR FUNCTIONS ----------------------
-%%------------------------------------------------------------
-%% function : new_in_connection
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-new_in_connection(_Arg, PHost, PPort, SHost, SPort) ->
- error_logger:info_msg("=============== new_in_connection ========~n"
- "Node : ~p~n"
- "From : ~s:~p~n"
- "To : ~s:~p~n"
- "==========================================~n",
- [node(), PHost, PPort, SHost, SPort]),
- {PHost, PPort, SHost, SPort}.
-
-%%------------------------------------------------------------
-%% function : new_out_connection
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-new_out_connection(_Arg, PHost, PPort, SHost, SPort) ->
- error_logger:info_msg("=============== new_out_connection =======~n"
- "Node : ~p~n"
- "From : ~s:~p~n"
- "To : ~s:~p~n"
- "==========================================~n",
- [node(), SHost, SPort, PHost, PPort]),
- {PHost, PPort, SHost, SPort}.
-
-%%------------------------------------------------------------
-%% function : closed_in_connection
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-closed_in_connection(Arg) ->
- error_logger:info_msg("=============== closed_in_connection =====~n"
- "Node : ~p~n"
- "Connection: ~p~n"
- "==========================================~n",
- [node(), Arg]),
- Arg.
-
-%%------------------------------------------------------------
-%% function : closed_out_connection
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-closed_out_connection(Arg) ->
- error_logger:info_msg("=============== closed_out_connection ====~n"
- "Node : ~p~n"
- "Connection: ~p~n"
- "==========================================~n",
- [node(), Arg]),
- Arg.
-
-%%------------------------------------------------------------
-%% function : in_request_encoded
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-in_request_encoded(_Ref, _ObjKey, _Ctx, _Op, Bin, Args) ->
- {Bin, Args}.
-
-%%------------------------------------------------------------
-%% function : in_reply_encoded
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-in_reply_encoded(_Ref, _ObjKey, _Ctx, _Op, Bin, Args) ->
- {Bin, Args}.
-
-%%------------------------------------------------------------
-%% function : out_reply_encoded
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-out_reply_encoded(_Ref, _ObjKey, _Ctx, _Op, Bin, Args) ->
- {Bin, Args}.
-
-%%------------------------------------------------------------
-%% function : out_request_encoded
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-out_request_encoded(_Ref, _ObjKey, _Ctx, _Op, Bin, Args) ->
- {Bin, Args}.
-
-%%------------------------------------------------------------
-%% function : in_request
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-in_request(Ref, _ObjKey, _Ctx, Op, Params, Args) ->
- error_logger:info_msg("=============== in_request ===============~n"
- "Connection: ~p~n"
- "Operation : ~p~n"
- "Parameters: ~p~n"
- "==========================================~n",
- [Ref, Op, Params]),
- {Params, Args}.
-
-%%------------------------------------------------------------
-%% function : in_reply
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-in_reply(Ref, _ObjKey, _Ctx, Op, Reply, Args) ->
- error_logger:info_msg("=============== in_reply =================~n"
- "Connection: ~p~n"
- "Operation : ~p~n"
- "Reply : ~p~n"
- "==========================================~n",
- [Ref, Op, Reply]),
- {Reply, Args}.
-
-%%------------------------------------------------------------
-%% function : out_reply
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-out_reply(Ref, _ObjKey, _Ctx, Op, Reply, Args) ->
- error_logger:info_msg("=============== out_reply ================~n"
- "Connection: ~p~n"
- "Operation : ~p~n"
- "Reply : ~p~n"
- "==========================================~n",
- [Ref, Op, Reply]),
- {Reply, Args}.
-
-%%------------------------------------------------------------
-%% function : out_request
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-out_request(Ref, _ObjKey, _Ctx, Op, Params, Args) ->
- error_logger:info_msg("=============== out_request ==============~n"
- "Connection: ~p~n"
- "Operation : ~p~n"
- "Parameters: ~p~n"
- "==========================================~n",
- [Ref, Op, Params]),
- {Params, Args}.
-
-%%======================================================================
-%% END OF MODULE
-%%======================================================================
-
diff --git a/lib/orber/src/orber_iiop_tracer_stealth.erl b/lib/orber/src/orber_iiop_tracer_stealth.erl
deleted file mode 100644
index 8eaa945d3f..0000000000
--- a/lib/orber/src/orber_iiop_tracer_stealth.erl
+++ /dev/null
@@ -1,187 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%--------------------------------------------------------------------
-%% File : orber_iiop_tracer_stealth.erl
-%% Purpose : Use for debugging only.
-%%--------------------------------------------------------------------
-
--module(orber_iiop_tracer_stealth).
-
-
-%% Interceptor functions.
--export([new_out_connection/5,
- new_in_connection/5,
- closed_in_connection/1,
- closed_out_connection/1,
- in_request_encoded/6,
- in_reply_encoded/6,
- out_reply_encoded/6,
- out_request_encoded/6,
- in_request/6,
- in_reply/6,
- out_reply/6,
- out_request/6]).
-
-
-%%--------------- INTERCEPTOR FUNCTIONS ----------------------
-%%------------------------------------------------------------
-%% function : new_in_connection
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-new_in_connection(_Arg, PHost, PPort, SHost, SPort) ->
- error_logger:info_msg("=============== new_in_connection ========~n"
- "Node : ~p~n"
- "From : ~s:~p~n"
- "To : ~s:~p~n"
- "==========================================~n",
- [node(), PHost, PPort, SHost, SPort]),
- {PHost, PPort, SHost, SPort}.
-
-%%------------------------------------------------------------
-%% function : new_out_connection
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-new_out_connection(_Arg, PHost, PPort, SHost, SPort) ->
- error_logger:info_msg("=============== new_out_connection =======~n"
- "Node : ~p~n"
- "From : ~s:~p~n"
- "To : ~s:~p~n"
- "==========================================~n",
- [node(), SHost, SPort, PHost, PPort]),
- {PHost, PPort, SHost, SPort}.
-
-%%------------------------------------------------------------
-%% function : closed_in_connection
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-closed_in_connection(Arg) ->
- error_logger:info_msg("=============== closed_in_connection =====~n"
- "Node : ~p~n"
- "Connection: ~p~n"
- "==========================================~n",
- [node(), Arg]),
- Arg.
-
-%%------------------------------------------------------------
-%% function : closed_out_connection
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-closed_out_connection(Arg) ->
- error_logger:info_msg("=============== closed_out_connection ====~n"
- "Node : ~p~n"
- "Connection: ~p~n"
- "==========================================~n",
- [node(), Arg]),
- Arg.
-
-%%------------------------------------------------------------
-%% function : in_request_encoded
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-in_request_encoded(_Ref, _ObjKey, _Ctx, _Op, Bin, Args) ->
- {Bin, Args}.
-
-%%------------------------------------------------------------
-%% function : in_reply_encoded
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-in_reply_encoded(_Ref, _ObjKey, _Ctx, _Op, Bin, Args) ->
- {Bin, Args}.
-
-%%------------------------------------------------------------
-%% function : out_reply_encoded
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-out_reply_encoded(_Ref, _ObjKey, _Ctx, _Op, Bin, Args) ->
- {Bin, Args}.
-
-%%------------------------------------------------------------
-%% function : out_request_encoded
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-out_request_encoded(_Ref, _ObjKey, _Ctx, _Op, Bin, Args) ->
- {Bin, Args}.
-
-%%------------------------------------------------------------
-%% function : in_request
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-in_request(Ref, _ObjKey, _Ctx, Op, Params, Args) ->
- error_logger:info_msg("=============== in_request ===============~n"
- "Connection: ~p~n"
- "Operation : ~p~n"
- "==========================================~n",
- [Ref, Op]),
- {Params, Args}.
-
-%%------------------------------------------------------------
-%% function : in_reply
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-in_reply(Ref, _ObjKey, _Ctx, Op, Reply, Args) ->
- error_logger:info_msg("=============== in_reply =================~n"
- "Connection: ~p~n"
- "Operation : ~p~n"
- "==========================================~n",
- [Ref, Op]),
- {Reply, Args}.
-
-%%------------------------------------------------------------
-%% function : out_reply
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-out_reply(Ref, _ObjKey, _Ctx, Op, Reply, Args) ->
- error_logger:info_msg("=============== out_reply ================~n"
- "Connection: ~p~n"
- "Operation : ~p~n"
- "==========================================~n",
- [Ref, Op]),
- {Reply, Args}.
-
-%%------------------------------------------------------------
-%% function : out_request
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-out_request(Ref, _ObjKey, _Ctx, Op, Params, Args) ->
- error_logger:info_msg("=============== out_request ==============~n"
- "Connection: ~p~n"
- "Operation : ~p~n"
- "==========================================~n",
- [Ref, Op]),
- {Params, Args}.
-
-%%======================================================================
-%% END OF MODULE
-%%======================================================================
-
diff --git a/lib/orber/src/orber_initial_references.erl b/lib/orber/src/orber_initial_references.erl
deleted file mode 100644
index 9140563881..0000000000
--- a/lib/orber/src/orber_initial_references.erl
+++ /dev/null
@@ -1,328 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: orber_initial_references.erl
-%%
-%% Description:
-%% This file contains the CORBA::InitialReferences interface
-%%
-%%-----------------------------------------------------------------
--module(orber_initial_references).
-
--behaviour(gen_server).
-
--include_lib("orber/include/corba.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([start/1, shutdown/1, init/1,
- terminate/2, handle_call/3, code_change/3,
- get/2, list/1, add/3, remove/2,
- get/1, list/0, add/2, remove/1,
- typeID/0, install/2, oe_is_a/1, oe_tc/1, oe_get_interface/0]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([handle_cast/2, handle_info/2]).
-
-%%-----------------------------------------------------------------
-%% Mnesia Table definition record
-%%-----------------------------------------------------------------
--record(orber_references, {key, objref, type}).
-
--define(DEBUG_LEVEL, 6).
-
-%%-----------------------------------------------------------------
-%% External interface functions
-%%-----------------------------------------------------------------
-start(Env) ->
- gen_server:start_link({local, 'orber_init'}, ?MODULE, Env, []).
-
-shutdown(EO_this) ->
- gen_server:call(EO_this, stop).
-
-
-install(Timeout, Options) ->
- AllTabs = mnesia:system_info(tables),
- DB_Result = case lists:member(orber_references, AllTabs) of
- true ->
- case lists:member({local_content, true},
- Options) of
- true->
- mnesia:add_table_copy(orber_references,
- node(),
- ram_copies);
- _ ->
- mnesia:create_table(orber_references,
- [{attributes,
- record_info(fields,
- orber_references)}
- |Options])
- end;
- _ ->
- mnesia:create_table(orber_references,
- [{attributes,
- record_info(fields,
- orber_references)}
- |Options])
- end,
-
- Wait = mnesia:wait_for_tables([orber_references], Timeout),
- %% Check if any error has occurred yet. If there are errors, return them.
- if
- DB_Result == {atomic, ok},
- Wait == ok ->
- ok;
- true ->
- {error, {DB_Result, Wait}}
- end.
-
-
-%%-----------------------------------------------------------------
-%% InitialReferences Interface
-%%-----------------------------------------------------------------
-'get'(Id) ->
- case read(Id) of
- {'EXCEPTION', E} ->
- corba:raise(E);
- Result ->
- Result
- end.
-
-list() ->
- case list_keys() of
- {'EXCEPTION', E} ->
- corba:raise(E);
- Result ->
- Result
- end.
-
-
-add(Id, ObjRef) ->
- case write(Id, ObjRef, external) of
- {'EXCEPTION', E} ->
- corba:raise(E);
- Result ->
- Result
- end.
-
-
-remove(Id) ->
- case delete(Id) of
- {'EXCEPTION', E} ->
- corba:raise(E);
- Result ->
- Result
- end.
-
-
-'get'(EO_this, Id) ->
- corba:call(EO_this, 'get', [Id], ?MODULE).
-
-list(EO_this) ->
- corba:call(EO_this, 'list', [], ?MODULE).
-
-add(EO_this, Id, ObjRef) ->
- corba:call(EO_this, 'add', [Id, ObjRef], ?MODULE).
-
-remove(EO_this, Id) ->
- corba:call(EO_this, 'remove', [Id], ?MODULE).
-
-typeID() ->
- "IDL:Orber/InitialReferences:1.0".
-
-oe_is_a("IDL:Orber/InitialReferences:1.0") ->
- true;
-oe_is_a(_) ->
- false.
-
-%%-----------------------------------------------------------------
-%% Internal interface functions
-%%-----------------------------------------------------------------
-init([]) ->
- case mnesia:wait_for_tables(['orber_references'], infinity) of
- ok ->
- NSObjKey = 'CosNaming_NamingContextExt':oe_create([], [{pseudo, true},
- {no_security, orber:partial_security()}]),
- rewrite("NameService", NSObjKey),
- ErlIfr = 'OrberApp_IFR':oe_create([], [{pseudo, true}]),
- rewrite("OrberIFR", ErlIfr),
- {ok, []};
- StopReason ->
- {stop, StopReason}
- end.
-
-terminate(_Reason, _State) ->
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Handle incomming calls
-handle_call({_EO_this, _OE_Context, 'get', [Id]}, _From, State) ->
- {'reply', read(Id), State};
-handle_call({_EO_this, _OE_Context, 'list', []}, _From, State) ->
- {'reply', list_keys(), State};
-
-handle_call({_EO_this, _OE_Context, 'add', [Id, ObjectRef]}, _From, State) ->
- {'reply', write(Id, ObjectRef, external), State};
-
-handle_call({_EO_this, _OE_Context, 'remove', [Id]}, _From, State) ->
- {'reply', delete(Id), State};
-handle_call('stop', _From, State) ->
- {'stop', normal, 'ok', State};
-handle_call(_Req, _From,State) ->
- {'reply', {'ok', 'nil', 'nil'}, State}.
-
-oe_tc(get) ->
- {{'tk_objref', 12, "object"}, [{'tk_string', 0}], []};
-oe_tc(list) ->
- {{'tk_sequence',{'tk_string', 0}, 0}, [], []};
-oe_tc(add) ->
- {'tk_boolean', [{'tk_string', 0}, {'tk_objref', 12, "object"}], []};
-oe_tc(remove) ->
- {'tk_boolean', [{'tk_string', 0}], []};
-oe_tc(_) ->
- undefined.
-
-oe_get_interface() ->
- [{"get", oe_tc(get)},
- {"list", oe_tc(list)},
- {"add", oe_tc(add)}].
-
-
-%%-----------------------------------------------------------------
-%% Standard gen_server cast handle
-%%-----------------------------------------------------------------
-handle_cast(_, State) ->
- {noreply, State}.
-
-
-%%-----------------------------------------------------------------
-%% Standard gen_server handles
-%%-----------------------------------------------------------------
-handle_info(_, State) ->
- {noreply, State}.
-
-%%-----------------------------------------------------------------
-%% Func: code_change/3
-%%-----------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-read(Key) ->
- case mnesia:dirty_read({orber_references, Key}) of
- [] ->
- corba:create_nil_objref();
- [#orber_references{objref = ObjRef}] ->
- ObjRef;
- What ->
- orber:dbg("[~p] orber_initial_references:lookup(~p);~n"
- "Failed to read from DB: ~p",
- [?LINE, Key, What], ?DEBUG_LEVEL),
- {'EXCEPTION', #'INTERNAL'{completion_status=?COMPLETED_NO}}
- end.
-
-write(Key, ObjRef, Type) ->
- _WF = fun() ->
- case mnesia:wread({orber_references, Key}) of
- [] ->
- %% No key exists. Ok to register.
- mnesia:write(#orber_references{key=Key, objref = ObjRef,
- type=Type});
- [X] ->
- orber:dbg("[~p] orber_initial_references:write(~p);~n"
- "Already bound to: ~p",
- [?LINE, Key, X], ?DEBUG_LEVEL),
- false;
- Why ->
- %% Something else occured.
- orber:dbg("[~p] orber_initial_references:write(~p);~n"
- "Error reading from DB (~p)", [?LINE, Key, Why], ?DEBUG_LEVEL),
- mnesia:abort({'EXCEPTION', #'INTERNAL'{completion_status=?COMPLETED_NO}})
- end
- end,
- case mnesia:transaction(_WF) of
- {atomic, ok} ->
- true;
- {atomic, Result} ->
- Result;
- {aborted, Reason} ->
- Reason
- end.
-
-rewrite(Key, ObjRef) ->
- rewrite(Key, ObjRef, internal).
-rewrite(Key, ObjRef, Type) ->
- _WF = fun() ->
- mnesia:write(#orber_references{key=Key, objref = ObjRef, type=Type})
- end,
- case mnesia:transaction(_WF) of
- {atomic, ok} ->
- true;
- {aborted, Reason} ->
- orber:dbg("[~p] orber_initial_references:rewrite(~p);~n"
- "Error over writing in DB (~p)",
- [?LINE, Key, Reason], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-
-delete(Key) ->
- _DF = fun() ->
- case mnesia:read({orber_references, Key}) of
- [] ->
- %% No key exists.
- orber:dbg("[~p] orber_initial_references:delete(~p);~n"
- "Does not exist.", [?LINE, Key], ?DEBUG_LEVEL),
- false;
- [_X] ->
- mnesia:delete({orber_references, Key});
- Why ->
- %% Something else occured.
- orber:dbg("[~p] orber_initial_references:delete(~p);~n"
- "Error reading from DB (~p)",
- [?LINE, Key, Why], ?DEBUG_LEVEL),
- mnesia:abort({'EXCEPTION', #'INTERNAL'{completion_status=?COMPLETED_NO}})
- end
- end,
- case mnesia:transaction(_DF) of
- {atomic, ok} ->
- true;
- {atomic, Result} ->
- Result;
- {aborted, Reason} ->
- Reason
- end.
-
-list_keys() ->
- _LF = fun() -> mnesia:all_keys(orber_references) end,
- case mnesia:transaction(_LF) of
- {atomic, Result} ->
- %% We do not want OrberIFR to exported, remove it.
- lists:delete("OrberIFR", Result);
- {aborted, Reason} ->
- orber:dbg("[~p] orber_initial_references:list_keys();~n"
- "Error reading from DB (~p)", [?LINE, Reason], ?DEBUG_LEVEL),
- {'EXCEPTION', #'INTERNAL'{completion_status=?COMPLETED_NO}}
- end.
diff --git a/lib/orber/src/orber_interceptors.erl b/lib/orber/src/orber_interceptors.erl
deleted file mode 100644
index 4bfb2ae9a5..0000000000
--- a/lib/orber/src/orber_interceptors.erl
+++ /dev/null
@@ -1,154 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: orber_interceptors.erl
-%%
-%% Description:
-%% This file contains the code for calling interceptors
-%%
-%%-----------------------------------------------------------------
--module(orber_interceptors).
-
--include_lib("orber/include/corba.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([call_send_message_interceptors/2, call_receive_message_interceptors/1,
- call_request_interceptors/2]).
--export([push_system_message_interceptor/2, pop_system_message_interceptor/1,
- create_interceptor_table/0]).
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-
-%%-----------------------------------------------------------------
-%% External interface functions
-%%-----------------------------------------------------------------
-call_receive_message_interceptors(Bytes) ->
- case getInMessageInterceptors() of
- [] ->
- Bytes;
- Interceptors ->
- apply_message_interceptors(Interceptors, receive_message, corba:create_nil_objref(),
- lists:flatten(Bytes))
- end.
-call_send_message_interceptors(ObjRef, Bytes) ->
- case getOutMessageInterceptors() of
- [] ->
- Bytes;
- Interceptors ->
- apply_message_interceptors(Interceptors, send_message, ObjRef, lists:flatten(Bytes))
- end.
-
-
-call_request_interceptors(in, Bytes) ->
- case getInRequestInterceptors() of
- [] ->
- Bytes;
- Interceptors ->
- Bytes
- end;
-call_request_interceptors(out, Bytes) ->
- case getOutRequestInterceptors() of
- [] ->
- Bytes;
- Interceptors ->
- Bytes
- end.
-
-create_interceptor_table() ->
- %% Should be replicated mnesia
- ets:new(orber_interceptors, [protected, named_table, set]),
- ets:insert(orber_interceptors, {message_in_interceptors, []}),
- ets:insert(orber_interceptors, {message_out_interceptors, []}).
-
-push_system_message_interceptor(in, Mod) ->
- case ets:lookup(orber_interceptors, message_in_interceptors) of
- [{_, Interceptors}] ->
- ets:insert(orber_interceptors, {message_in_interceptors, [Mod | Interceptors]});
- _ ->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end;
-push_system_message_interceptor(out, Mod) ->
- case ets:lookup(orber_interceptors, message_out_interceptors) of
- [{_, Interceptors}] ->
- ets:insert(orber_interceptors, {message_out_interceptors, Interceptors ++ [Mod]});
- _ ->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-pop_system_message_interceptor(in) ->
- case ets:lookup(orber_interceptors, message_in_interceptors) of
- [{_, []}] ->
- ok;
- [{_, [_ | Interceptors]}] ->
- ets:insert(orber_interceptors, {message_in_interceptors, Interceptors});
- _ ->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end;
-pop_system_message_interceptor(out) ->
- case ets:lookup(orber_interceptors, message_out_interceptors) of
- [{_, []}] ->
- ok;
- [{_, Interceptors}] ->
- ets:insert(orber_interceptors, {message_out_interceptors, lists:droplast(Interceptors)});
- _ ->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-getInMessageInterceptors() ->
- case ets:lookup(orber_interceptors, message_in_interceptors) of
- [{_, Interceptors}] ->
- Interceptors;
- _ ->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-getOutMessageInterceptors() ->
- case ets:lookup(orber_interceptors, message_out_interceptors) of
- [{_, Interceptors}] ->
- Interceptors;
- _ ->
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
- end.
-
-
-getInRequestInterceptors() ->
- [].
-
-getOutRequestInterceptors() ->
- [].
-
-
-apply_message_interceptors([], F, ObjRef, Bytes) ->
- Bytes;
-apply_message_interceptors([M | Rest], F, ObjRef, Bytes) ->
- apply_message_interceptors(Rest, F, ObjRef, apply(M, F, [ObjRef, Bytes])).
-
diff --git a/lib/orber/src/orber_objectkeys.erl b/lib/orber/src/orber_objectkeys.erl
deleted file mode 100644
index 12ed1a2f85..0000000000
--- a/lib/orber/src/orber_objectkeys.erl
+++ /dev/null
@@ -1,571 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: orber_objectkeys.erl
-%%
-%% Description:
-%% This file contains the object keyserver in Orber
-%%
-%%-----------------------------------------------------------------
--module(orber_objectkeys).
-
--behaviour(gen_server).
-
--include_lib("orber/include/corba.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([start/1, stop/0, stop_all/0, get_pid/1, is_persistent/1,
- register/2, register/3, delete/1, create_schema/1, check/1,
- remove_old_keys/0]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([init/1, terminate/2, install/2, handle_call/3, handle_info/2, code_change/3]).
--export([handle_cast/2, dump/0, get_key_from_pid/1, gc/1]).
-
-%%-----------------------------------------------------------------
-%% Mnesia Table definition record
-%%-----------------------------------------------------------------
--record(orber_objkeys, {object_key, pid, persistent=false, timestamp}).
-
-%%-----------------------------------------------------------------
-%% Macros
-%%-----------------------------------------------------------------
--define(dirty_query_context, true).
-
-%% This macro returns a read fun suitable for evaluation in a transaction
--define(read_function(Objkey),
- fun() ->
- mnesia:dirty_read(Objkey)
- end).
-
-%% This macro returns a write fun suitable for evaluation in a transaction
--define(write_function(R),
- fun() ->
- mnesia:dirty_write(R)
- end).
-
-%% This macro returns a delete fun suitable for evaluation in a transaction
--define(delete_function(R),
- fun() ->
- mnesia:delete(R)
- end).
-
-%% Use this fun inside a transaction to get a list of all keys.
--define(match_function(),
- fun() ->
- mnesia:match_object({orber_objkeys, '_', '_','_','_'})
- end).
-
--ifdef(dirty_query_context).
--define(query_check(Q_res), Q_res).
--else.
--define(query_check(Q_res), {atomic, Q_res}).
--endif.
-
-
--define(CHECK_EXCEPTION(Res), case Res of
- {'EXCEPTION', E} ->
- corba:raise(E);
- R ->
- R
- end).
-
--define(DEBUG_LEVEL, 6).
-
-
-
-%%-----------------------------------------------------------------
-%% Debugging function
-%%-----------------------------------------------------------------
-dump() ->
- case catch mnesia:dirty_first('orber_objkeys') of
- {'EXIT', R} ->
- io:format("Exited with ~p\n",[R]);
- Key ->
- dump_print(Key),
- dump_loop(Key)
- end.
-
-dump_loop(PreviousKey) ->
- case catch mnesia:dirty_next('orber_objkeys', PreviousKey) of
- {'EXIT', R} ->
- io:format("Exited with ~p\n",[R]);
- '$end_of_table' ->
- ok;
- Key ->
- dump_print(Key),
- dump_loop(Key)
- end.
-
-dump_print(Key) ->
- case catch mnesia:dirty_read({'orber_objkeys', Key}) of
- {'EXIT', R} ->
- io:format("Exited with ~p\n",[R]);
- [X] ->
- io:format("object_key: ~p, pid: ~p, persistent: ~p, timestamp: ~p\n",
- [binary_to_term(X#orber_objkeys.object_key),
- X#orber_objkeys.pid,
- X#orber_objkeys.persistent,
- X#orber_objkeys.timestamp]);
- _ ->
- ok
- end.
-
-
-%%-----------------------------------------------------------------
-%% External interface functions
-%%-----------------------------------------------------------------
-start(Opts) ->
- gen_server:start_link({local, orber_objkeyserver}, orber_objectkeys, Opts, []).
-
-stop() ->
- gen_server:call(orber_objkeyserver, stop, infinity).
-
-remove_old_keys() ->
- %% This function may ONLY be used when restarting a crashed node.
- %% We must remove all objects started with {global, "name"} otherwise
- %% we cannot restart the node using the same name.
- Fun = fun() ->
- Node = node(),
- mnesia:write_lock_table(orber_objkeys),
- Objects = mnesia:match_object(orber_objkeys,
- mnesia:table_info(orber_objkeys,
- wild_pattern),
- read),
- lists:foreach(fun(Obj) ->
- case node(Obj#orber_objkeys.pid) of
- Node ->
- mnesia:delete({orber_objkeys,
- Obj#orber_objkeys.object_key});
- _->
- ok
- end
- end,
- Objects),
- ok
- end,
- write_result(mnesia:transaction(Fun)).
-
-stop_and_remove_local(Reason) ->
- %% This function may ONLY be used when this server terminates with reason
- %% normal or shutdown.
- Fun = fun() ->
- Node = node(),
- mnesia:write_lock_table(orber_objkeys),
- Objects = mnesia:match_object(orber_objkeys,
- mnesia:table_info(orber_objkeys,
- wild_pattern),
- read),
- lists:foreach(fun(Obj) ->
- case node(Obj#orber_objkeys.pid) of
- Node ->
- exit(Obj#orber_objkeys.pid, Reason),
- mnesia:delete({orber_objkeys,
- Obj#orber_objkeys.object_key});
- _->
- ok
- end
- end,
- Objects),
- ok
- end,
- write_result(mnesia:transaction(Fun)).
-
-stop_all() ->
- Fun = ?match_function(),
- case mnesia:transaction(Fun) of
- {atomic, Objects} ->
- lists:foreach(fun(Obj) ->
- gen_server:call(Obj#orber_objkeys.pid,
- stop, infinity)
- end,
- Objects);
- R ->
- R
- end.
-
-get_pid(Objkey) ->
- case catch ets:lookup_element(orber_objkeys, Objkey, 3) of
- Pid when is_pid(Pid) ->
- Pid;
- dead ->
- {error, "unable to contact object"};
- _ ->
- %% This call is necessary if a persistent object have died
- %% and the objectkey server is currently updating the Pid
- %% to equal 'dead'. Without this case 'OBJECT_NOT_EXIST'
- %% would be raised which is uncorrect if the object is
- %% persistent.
- ?CHECK_EXCEPTION(gen_server:call(orber_objkeyserver,
- {get_pid, Objkey},
- infinity))
- end.
-
-is_persistent(Pid) when is_pid(Pid) ->
- case catch get_key_from_pid(Pid) of
- {'EXCEPTION', _} ->
- corba:raise(#'OBJECT_NOT_EXIST'{completion_status=?COMPLETED_NO});
- Key ->
- is_persistent(Key)
- end;
-is_persistent(Objkey) ->
- case catch ets:lookup_element(orber_objkeys, Objkey, 4) of
- {'EXIT', _R} ->
- corba:raise(#'OBJECT_NOT_EXIST'{completion_status=?COMPLETED_NO});
- Boolean ->
- Boolean
- end.
-
-
-gc(Sec) when is_integer(Sec) ->
- Fun = fun() ->
- mnesia:write_lock_table(orber_objkeys),
- Objects = mnesia:match_object({orber_objkeys, '_', dead, true,'_'}),
- lists:foreach(fun(Obj) ->
- case timetest(Sec, Obj#orber_objkeys.timestamp) of
- true ->
- mnesia:delete({orber_objkeys,
- Obj#orber_objkeys.object_key});
- _->
- ok
- end
- end,
- Objects),
- ok
- end,
- write_result(mnesia:transaction(Fun)).
-
-register(Objkey, Pid) ->
- 'register'(Objkey, Pid, false).
-
-register(Objkey, Pid, Type) when is_pid(Pid) ->
- ?CHECK_EXCEPTION(gen_server:call(orber_objkeyserver,
- {register, Objkey, Pid, Type},
- infinity));
-register(Objkey, Pid, Type) ->
- orber:dbg("[~p] orber_objectkeys:register(~p, ~p); Not a Pid ~p",
- [?LINE, Objkey, Type, Pid], ?DEBUG_LEVEL),
- corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}).
-
-delete(Objkey) ->
- ?CHECK_EXCEPTION(gen_server:call(orber_objkeyserver,
- {delete, Objkey}, infinity)).
-
-check(Objkey) ->
- ?CHECK_EXCEPTION(gen_server:call(orber_objkeyserver,
- {check, Objkey}, infinity)).
-
-%%-----------------------------------------------------------------
-%% Server functions
-%%-----------------------------------------------------------------
-init(_Env) ->
- case mnesia:wait_for_tables(['orber_objkeys'], infinity) of
- ok ->
- process_flag(trap_exit, true),
- start_gc_timer(orber:objectkeys_gc_time());
- StopReason ->
- {stop, StopReason}
- end.
-
-terminate(shutdown, _State) ->
- stop_and_remove_local(shutdown),
- ok;
-terminate(normal, _State) ->
- stop_and_remove_local(normal),
- ok;
-terminate(_Reason, _State) ->
- ok.
-
-start_gc_timer(infinity) ->
- {ok, []};
-start_gc_timer(Time) ->
- timer:start(),
- case timer:send_after(timer:seconds(Time),
- orber_objkeyserver, {oe_gc, Time}) of
- {ok, _} ->
- {ok, []};
- StopReason ->
- {stop, StopReason}
- end.
-
-install(Timeout, Options) ->
- %% check if there already exists a database. If not, create one.
- %% DB_initialized = perhaps_create_schema(Nodelist),
- %% check if mnesia is running. If not, start mnesia.
- perhaps_start_mnesia(),
-
- %% Do we have a complete set of IFR tables? If not, create them.
- AllTabs = mnesia:system_info(tables),
-
- DB_Result = case lists:member(orber_objkeys, AllTabs) of
- true ->
- case lists:member({local_content, true},
- Options) of
- true->
- mnesia:add_table_copy(orber_objkeys,
- node(),
- ram_copies);
- _ ->
- mnesia:create_table(orber_objkeys,
- [{attributes,
- record_info(fields,
- orber_objkeys)}
- |Options])
- end;
- _ ->
- mnesia:create_table(orber_objkeys,
- [{attributes,
- record_info(fields,
- orber_objkeys)}
- |Options])
- end,
-
- Wait = mnesia:wait_for_tables([orber_objkeys], Timeout),
- %% Check if any error has occurred yet. If there are errors, return them.
- if
- DB_Result == {atomic, ok},
- Wait == ok ->
- ok;
- true ->
- {error, {DB_Result, Wait}}
- end.
-
-%%-----------------------------------------------------------------
-%% Func: handle_call/3
-%%
-%% Comment:
-%% In objectkey gen_server all exceptions are tupples and corba:raise
-%% may not be used. It is too time consuming to add catches in every
-%% function before returning. On the client side there is a case which
-%% maps every tupple on the format {'exception', E} to corba:raise(E).
-%%-----------------------------------------------------------------
-handle_call(stop, _From, State) ->
- {stop, normal, [], State};
-handle_call({get, Objkey}, _From, State) ->
- R = query_result(mnesia:dirty_read({orber_objkeys, Objkey})),
- {reply, R, State};
-
-handle_call({register, Objkey, Pid, Type}, _From, State) ->
- _WF = fun() ->
- case mnesia:wread({orber_objkeys, Objkey}) of
- [] ->
- %% No key exists. Ok to register.
- mnesia:write(#orber_objkeys{object_key=Objkey, pid=Pid,
- persistent=Type,
- timestamp=erlang:monotonic_time(seconds)});
- [X] when X#orber_objkeys.persistent==true,
- X#orber_objkeys.pid == dead ->
- %% A persistent object is being restarted. Update Pid & time.
- mnesia:write(X#orber_objkeys{pid=Pid, timestamp=erlang:monotonic_time(seconds)});
- [X] when is_pid(X#orber_objkeys.pid) ->
- %% Object exists, i.e., trying to create an object with
- %% the same name.
- orber:dbg("[~p] orber_objectkeys:register(~p, ~p); Object already exists.",
- [?LINE, Objkey, Type], ?DEBUG_LEVEL),
- {'EXCEPTION', #'BAD_PARAM'{completion_status=?COMPLETED_NO}};
- Why ->
- %% Something else occured.
- orber:dbg("[~p] orber_objectkeys:register(~p, ~p); error reading from DB(~p)",
- [?LINE, Objkey, Type, Why], ?DEBUG_LEVEL),
- {'EXCEPTION', #'INTERNAL'{completion_status=?COMPLETED_NO}}
- end
- end,
- R = write_result(mnesia:transaction(_WF)),
- if
- R == ok andalso is_pid(Pid) ->
- link(Pid);
- true ->
- true
- end,
- {reply, R, State};
-
-handle_call({delete, Objkey}, _From, State) ->
- ?query_check(Qres) = mnesia:dirty_read({orber_objkeys, Objkey}),
- case Qres of
- [] ->
- true;
- [X] when is_pid(X#orber_objkeys.pid) ->
- unlink(X#orber_objkeys.pid);
- _ ->
- true
- end,
- _F = ?delete_function({orber_objkeys, Objkey}),
- R = write_result(mnesia:transaction(_F)),
- {reply, R, State};
-
-handle_call({get_pid, Objkey}, _From, State) ->
- _F = fun() ->
- mnesia:read({orber_objkeys, Objkey})
- end,
- case mnesia:transaction(_F) of
- {atomic, [X]} when is_pid(X#orber_objkeys.pid) ->
- {reply, X#orber_objkeys.pid, State};
- {atomic, [X]} when X#orber_objkeys.pid == dead ->
- {reply,
- {'EXCEPTION', #'TRANSIENT'{completion_status=?COMPLETED_NO}},
- State};
- _Res ->
- {reply,
- {'EXCEPTION', #'OBJECT_NOT_EXIST'{completion_status=?COMPLETED_NO}},
- State}
- end;
-handle_call({check, {_, 'key', Objkey, _, _, _}}, _From, State) ->
- ?query_check(Qres) = mnesia:dirty_read({orber_objkeys, Objkey}),
- case Qres of
- [_X] ->
- {reply, 'object_here', State};
- _ ->
- {reply, 'unknown_object', State}
- end;
-handle_call({check, {_, 'registered', Objkey, _, _, _}}, _From, State) ->
- case whereis(Objkey) of
- undefined ->
- case catch ets:lookup_element(orber_objkeys, Objkey, 4) of
- true ->
- {reply, 'object_here', State};
- _->
- {reply, 'unknown_object', State}
- end;
- _ ->
- {reply, 'object_here', State}
- end;
-handle_call({check, {_, 'pseudo', Module, _, _, _}}, _From, State) ->
- case code:is_loaded(Module) of
- false ->
- {reply, 'unknown_object', State};
- _ ->
- {reply, 'object_here', State}
- end;
-
-handle_call({check, "INIT"}, _From, State) ->
- {reply, 'object_here', State};
-handle_call({check, _}, _From, State) ->
- {reply, 'unknown_object', State}.
-
-
-handle_info({'EXIT', Pid, Reason}, State) when is_pid(Pid) ->
- _WF = fun() ->
- case mnesia:match_object({orber_objkeys, '_', Pid,'_','_'}) of
- [] ->
- ok;
- [X] when X#orber_objkeys.persistent==false ->
- mnesia:delete({orber_objkeys, X#orber_objkeys.object_key});
- [X] when is_pid(X#orber_objkeys.pid) andalso
- X#orber_objkeys.persistent==true andalso
- Reason /= normal andalso
- Reason /= shutdown ->
- mnesia:write(X#orber_objkeys{pid=dead,
- timestamp=erlang:monotonic_time(seconds)});
- [X] when X#orber_objkeys.persistent==true ->
- mnesia:delete({orber_objkeys, X#orber_objkeys.object_key});
- _->
- ok
- end
- end,
- case write_result(mnesia:transaction(_WF)) of
- ok ->
- unlink(Pid);
- _->
- true
- end,
- {noreply, State};
-
-handle_info({oe_gc, Secs}, State) ->
- catch gc(Secs),
- {noreply, State}.
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%-----------------------------------------------------------------
-%% Internal Functions
-%%-----------------------------------------------------------------
-
-timetest(S, TimeStamp) ->
- TimeStamp+S < erlang:monotonic_time(seconds).
-
-get_key_from_pid(Pid) ->
- case mnesia:dirty_match_object({orber_objkeys, '_', Pid,'_','_'}) of
- [Keys] ->
- Keys#orber_objkeys.object_key;
- _ ->
- corba:raise(#'OBJECT_NOT_EXIST'{completion_status=?COMPLETED_NO})
- end.
-
-%remove_keys([], _) ->
-% ok;
-%remove_keys([H|T], R) when H#orber_objkeys.persistent==false ->
-% _F = ?delete_function({orber_objkeys, H#orber_objkeys.object_key}),
-% write_result(mnesia:transaction(_F)),
-% remove_keys(T, R).
-
-%%-----------------------------------------------------------------
-%% Check a read transaction
-query_result(?query_check(Qres)) ->
- case Qres of
- [Hres] ->
- Hres#orber_objkeys.pid;
- [] ->
- {'EXCEPTION', #'OBJECT_NOT_EXIST'{completion_status=?COMPLETED_NO}};
- Other ->
- orber:dbg("[~p] orber_objectkeys:query_result(); DB lookup failed(~p)",
- [?LINE, Other], ?DEBUG_LEVEL),
- {'EXCEPTION', #'INTERNAL'{completion_status=?COMPLETED_NO}}
- end.
-
-%%-----------------------------------------------------------------
-%% Check a write transaction
-write_result({atomic,ok}) -> ok;
-write_result(Foo) ->
- orber:dbg("[~p] orber_objectkeys:query_result(); DB write failed(~p)",
- [?LINE, Foo], ?DEBUG_LEVEL),
- {'EXCEPTION', #'INTERNAL'{completion_status=?COMPLETED_NO}}.
-
-
-create_schema(Nodes) ->
- case mnesia:system_info(use_dir) of
- false ->
- mnesia:create_schema(Nodes);
- _ ->
- ok
- end.
-
-perhaps_start_mnesia() ->
- case mnesia:system_info(is_running) of
- no ->
- mnesia:start();
- _ ->
- ok
- end.
-
-
-%%------------------------------------------------------------
-%% Standard gen_server cast handle
-%%
-handle_cast(_, State) ->
- {noreply, State}.
-
-
diff --git a/lib/orber/src/orber_pi.erl b/lib/orber/src/orber_pi.erl
deleted file mode 100644
index 19bb7af6c0..0000000000
--- a/lib/orber/src/orber_pi.erl
+++ /dev/null
@@ -1,1213 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_pi.erl
-%% Purpose :
-%% Comments:
-%% * Each Interceptor is represented by Module where
-%% Module - refers to a module which must export the functions:
-%% (1) receive_request
-%% (2) send_other
-%% (3) receive_service_contexts
-%% (4) send_reply
-%% (5) send_exception
-%% (6) send_request
-%% (7) send_poll
-%% (8) receive_reply
-%% (9) receive_exception
-%% (10) receive_other
-%% or
-%% (11) new_out_connection
-%% (12) new_in_connection
-%% (13) in_request
-%% (14) out_reply
-%% (15) out_request
-%% (16) in_reply
-%%
-%% Functions (1) - (10) for Portable and (11) - (16) for
-%% Native Interceptors.
-%%
-%%----------------------------------------------------------------------
-
--module(orber_pi).
-
-%%--------------- INCLUDES -----------------------------------
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
--include_lib("orber/include/orber_pi.hrl").
--include_lib("orber/src/orber_iiop.hrl").
-
-%%--------------- EXPORTS-------------------------------------
-%% API external
--export([%% Native Intercepotors API
- new_out_connection/5,
- new_in_connection/5,
- closed_in_connection/2,
- closed_out_connection/2,
- in_request_enc/4,
- out_reply_enc/5,
- out_request_enc/6,
- in_reply_enc/6,
- in_request/4,
- out_reply/5,
- out_request/6,
- in_reply/6,
- %% Portable Interceptors
- server_start_receive/7,
- server_start_send/2,
- client_receive/2,
- client_send/2,
- codefactory_create_codec/1,
- codec_encode/2,
- codec_encode_value/2,
- codec_decode/2,
- codec_decode_value/3,
- %% RequestInfo
- '_get_request_id'/1,
- '_get_operation'/1,
- '_get_arguments'/1,
- '_get_exceptions'/1,
- '_get_contexts'/1,
- '_get_operation_context'/1,
- '_get_result'/1,
- '_get_response_expected'/1,
- '_get_sync_scope'/1,
- '_get_reply_status'/1,
- '_get_forward_reference'/1,
- get_slot/2,
- get_request_service_context/2,
- get_reply_service_context/2,
- %% ClientRequestInfo (inherrits RequestInfo)
- '_get_target'/1,
- '_get_effective_target'/1,
- '_get_effective_profile'/1,
- '_get_received_exception'/1,
- '_get_received_exception_id'/1,
- get_effective_component/2,
- get_effective_components/2,
- get_request_policy/2,
- add_request_service_policy/3,
- %% ServerRequestInfo (inherrits RequestInfo)
- '_get_sending_exception'/1,
- '_get_object_id'/1,
- '_get_adapter_id'/1,
- '_get_target_most_derived_interface'/1,
- get_server_policy/2,
- set_slot/3,
- target_is_a/2,
- add_reply_service_context/3]).
-
-%%=============== DATA STRUCTURES ============================
-%%--------------- ClientRequestInfo --------------------------
--record('ClientRequestInfo',
- {request_id,
- operation,
- arguments,
- exceptions,
- contexts,
- operation_context,
- result,
- response_expected,
- sync_scope = 'SYNC_NONE',
- reply_status,
- forward_reference,
- endian,
- target,
- effective_target,
- effective_profile,
- received_exception,
- received_exception_id}).
-
--define(createInitCRI(_ReqID, _Op, _Args, _Ctxs, _OpCtx, _RespExp, _Target,
- _ETarget, _EProf),
- #'ClientRequestInfo'{request_id = _ReqID,
- operation = _Op,
- arguments = _Args,
- contexts = _Ctxs,
- operation_context = _OpCtx,
- response_expected = _RespExp,
- target = _Target,
- effective_target = _ETarget,
- effective_profile = _EProf}).
-
-
-%%--------------- ServerRequestInfo --------------------------
--record('ServerRequestInfo',
- {request_id,
- operation,
- arguments,
- exceptions,
- contexts,
- operation_context,
- result,
- response_expected,
- sync_scope = 'SYNC_NONE',
- reply_status,
- forward_reference,
- endian,
- sending_exception,
- object_id,
- adapter_id,
- target_most_derived_interface}).
-
--define(createInitSRI(_ReqID, _Op, _RespExp),
- #'ServerRequestInfo'{request_id = _ReqID,
- operation = _Op,
- response_expected = _RespExp}).
-
-
-%%--------------- DEFINES ------------------------------------
--define(DEBUG_LEVEL, 9).
-
--define(EFORMAT(_F, _A), exit(lists:flatten(io_lib:format(_F, _A)))).
-
-%%------------------------------------------------------------
-%%------------- NATIVE INTERCEPTOR FUNCTIONS------------------
-%%------------------------------------------------------------
-%% function : new_in_connection
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-new_in_connection(PIs, Host, Port, SHost, SPort) ->
- case catch new_in_connection(PIs, undefined, Host, Port, SHost, SPort) of
- {'EXIT', R} ->
- orber:dbg("[~p] orber_pi:new_in_connection(~p); exit(~p)",
- [?LINE, PIs, R], ?DEBUG_LEVEL),
- ?EFORMAT("Supplied Interceptors unable to create a valid new_in_connection"
- "Reason: ~p", [{'EXIT', R}]);
- {'EXCEPTION', E} ->
- orber:dbg("[~p] orber_pi:new_in_connection(~p); exception(~p)",
- [?LINE, PIs, E], ?DEBUG_LEVEL),
- ?EFORMAT("Supplied Interceptors unable to create a valid new_in_connection"
- "Reason: ~p", [{'EXCEPTION', E}]);
- Ref ->
- Ref
- end.
-
-new_in_connection([], Ref, _, _, _, _) ->
- Ref;
-new_in_connection([Mod|T], Ref, Host, Port, SHost, SPort) ->
- case get_arity(Mod, new_in_connection) of
- 5 ->
- NewRef = Mod:new_in_connection(Ref, Host, Port, SHost, SPort),
- new_in_connection(T, NewRef, Host, Port, SHost, SPort);
- 3 ->
- NewRef = Mod:new_in_connection(Ref, Host, Port),
- new_in_connection(T, NewRef, Host, Port, SHost, SPort)
- end.
-
-get_arity(Mod, Func) ->
- get_arity(Mod, Func, true).
-get_arity(Mod, Func, Retry) ->
- case erlang:function_exported(Mod, Func, 5) of
- true ->
- 5;
- false ->
- case erlang:function_exported(Mod, Func, 3) of
- true ->
- 3;
- false when Retry == true ->
- {module, _} = code:ensure_loaded(Mod),
- get_arity(Mod, Func, false);
- false ->
- exit("Unable to load interceptor")
- end
- end.
-
-%%------------------------------------------------------------
-%% function : closed_in_connection
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-closed_in_connection(PIs, Ref) ->
- case catch closed_in_connection_helper(PIs, Ref) of
- {'EXIT', R} ->
- orber:dbg("[~p] orber_pi:closed_in_connection(~p, ~p); exit(~p)",
- [?LINE, PIs, Ref, R], ?DEBUG_LEVEL),
- ok;
- {'EXCEPTION', E} ->
- orber:dbg("[~p] orber_pi:closed_in_connection(~p, ~p); exception(~p)",
- [?LINE, PIs, Ref, E], ?DEBUG_LEVEL),
- ok;
- _ ->
- ok
- end.
-
-closed_in_connection_helper([], _Ref) ->
- ok;
-closed_in_connection_helper([Mod|T], Ref) ->
- NewRef = Mod:closed_in_connection(Ref),
- closed_in_connection_helper(T, NewRef).
-
-
-%%------------------------------------------------------------
-%% function : new_out_connection
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-new_out_connection(PIs, Host, Port, SHost, SPort) ->
- case catch new_out_connection(PIs, undefined, Host, Port, SHost, SPort) of
- {'EXIT', R} ->
- orber:dbg("[~p] orber_pi:new_out_connection(~p); exit(~p)",
- [?LINE, PIs, R], ?DEBUG_LEVEL),
- ?EFORMAT("Supplied Interceptors unable to create a valid new_out_connection"
- "Reason: ~p", [{'EXIT', R}]);
- {'EXCEPTION', E} ->
- orber:dbg("[~p] orber_pi:new_out_connection(~p); exception(~p)",
- [?LINE, PIs, E], ?DEBUG_LEVEL),
- ?EFORMAT("Supplied Interceptors unable to create a valid new_out_connection"
- "Reason: ~p", [{'EXCEPTION', E}]);
- Ref ->
- Ref
- end.
-
-new_out_connection([], Ref, _, _, _, _) ->
- Ref;
-new_out_connection([Mod|T], Ref, Host, Port, SHost, SPort) ->
- case get_arity(Mod, new_out_connection) of
- 5 ->
- NewRef = Mod:new_out_connection(Ref, Host, Port, SHost, SPort),
- new_out_connection(T, NewRef, Host, Port, SHost, SPort);
- 3 ->
- NewRef = Mod:new_out_connection(Ref, Host, Port),
- new_out_connection(T, NewRef, Host, Port, SHost, SPort)
- end.
-
-%%------------------------------------------------------------
-%% function : closed_out_connection
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-closed_out_connection(PIs, Ref) ->
- case catch closed_out_connection_helper(PIs, Ref) of
- {'EXIT', R} ->
- orber:dbg("[~p] orber_pi:closed_out_connection(~p); exit(~p)",
- [?LINE, PIs, R], ?DEBUG_LEVEL),
- ok;
- {'EXCEPTION', E} ->
- orber:dbg("[~p] orber_pi:closed_out_connection(~p); exception(~p)",
- [?LINE, PIs, E], ?DEBUG_LEVEL),
- ok;
- _ ->
- ok
- end.
-
-closed_out_connection_helper([], _Ref) ->
- ok;
-closed_out_connection_helper([Mod|T], Ref) ->
- NewRef = Mod:closed_out_connection(Ref),
- closed_out_connection_helper(T, NewRef).
-
-%%------------------------------------------------------------
-%% function : in_request_enc
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect : Intercepts an incoming request (server-side).
-%%------------------------------------------------------------
-in_request_enc(PIs, ReqHdr, Ref, Msg) ->
- case catch in_request_enc(PIs, ReqHdr, Ref, Msg, undefined) of
- {'EXIT', R} ->
- orber:dbg("[~p] orber_pi:in_request_enc(~p, ~p, ~p); exit(~p)",
- [?LINE, PIs, Ref, Msg, R], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_NO});
- {'EXCEPTION', E} ->
- orber:dbg("[~p] orber_pi:in_request_enc(~p, ~p, ~p); exception(~p)",
- [?LINE, PIs, Ref, Msg, E], ?DEBUG_LEVEL),
- corba:raise(E);
- NewMsg ->
- NewMsg
- end.
-
-in_request_enc([], _, _, Msg, _) ->
- Msg;
-in_request_enc([Mod|T], ReqHdr, Ref, Msg, Args) ->
- {NewMsg, NewArgs} = Mod:in_request_encoded(Ref, ReqHdr#request_header.object_key,
- ReqHdr#request_header.service_context,
- ReqHdr#request_header.operation,
- Msg, Args),
- in_request_enc(T, ReqHdr, Ref, NewMsg, NewArgs).
-
-%%------------------------------------------------------------
-%% function : in_request
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect : Intercepts an incoming request (server-side).
-%%------------------------------------------------------------
-in_request(PIs, ReqHdr, Ref, Msg) ->
- case catch in_request(PIs, ReqHdr, Ref, Msg, undefined) of
- {'EXIT', R} ->
- orber:dbg("[~p] orber_pi:in_request(~p, ~p, ~p); exit(~p)",
- [?LINE, PIs, Ref, Msg, R], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_NO});
- {'EXCEPTION', E} ->
- orber:dbg("[~p] orber_pi:in_request(~p, ~p, ~p); exception(~p)",
- [?LINE, PIs, Ref, Msg, E], ?DEBUG_LEVEL),
- corba:raise(E);
- NewMsg ->
- NewMsg
- end.
-
-in_request([], _, _, Msg, _) ->
- Msg;
-in_request([Mod|T], ReqHdr, Ref, Msg, Args) ->
- {NewMsg, NewArgs} = Mod:in_request(Ref, ReqHdr#request_header.object_key,
- ReqHdr#request_header.service_context,
- ReqHdr#request_header.operation,
- Msg, Args),
- in_request(T, ReqHdr, Ref, NewMsg, NewArgs).
-
-%%------------------------------------------------------------
-%% function : out_reply_enc
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect : Intercept an outgoing reply (server-side).
-%%------------------------------------------------------------
-out_reply_enc(PIs, ReqHdr, Ref, Msg, Ctx) ->
- case catch out_reply_enc(PIs, ReqHdr, Ref, Msg, undefined, Ctx) of
- {'EXIT', R} ->
- orber:dbg("[~p] orber_pi:out_reply_enc(~p, ~p, ~p); exit(~p)",
- [?LINE, PIs, Ref, Msg, R], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE});
- {'EXCEPTION', E} ->
- orber:dbg("[~p] orber_pi:out_reply_enc(~p, ~p, ~p); exception(~p)",
- [?LINE, PIs, Ref, Msg, E], ?DEBUG_LEVEL),
- corba:raise(E);
- NewMsg ->
- NewMsg
- end.
-out_reply_enc([], _, _, Msg, _, _) ->
- Msg;
-out_reply_enc([Mod|T], ReqHdr, Ref, Msg, Args, Ctx) ->
- {NewMsg, NewArgs} = Mod:out_reply_encoded(Ref, ReqHdr#request_header.object_key,
- Ctx, %% Out Context.
- ReqHdr#request_header.operation,
- Msg, Args),
- out_reply_enc(T, ReqHdr, Ref, NewMsg, NewArgs, Ctx).
-
-
-%%------------------------------------------------------------
-%% function : out_reply
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect : Intercept an outgoing reply (server-side).
-%%------------------------------------------------------------
-out_reply(PIs, ReqHdr, Ref, Msg, Ctx) ->
- case catch out_reply(PIs, ReqHdr, Ref, Msg, undefined, Ctx) of
- {'EXIT', R} ->
- orber:dbg("[~p] orber_pi:out_reply(~p, ~p, ~p); exit(~p)",
- [?LINE, PIs, Ref, Msg, R], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE});
- NewMsg ->
- NewMsg
- end.
-out_reply([], _, _, Msg, _, _) ->
- Msg;
-out_reply([Mod|T], ReqHdr, Ref, Msg, Args, Ctx) ->
- {NewMsg, NewArgs} = Mod:out_reply(Ref, ReqHdr#request_header.object_key,
- Ctx, %% Out Context.
- ReqHdr#request_header.operation,
- Msg, Args),
- out_reply(T, ReqHdr, Ref, NewMsg, NewArgs, Ctx).
-
-
-%%------------------------------------------------------------
-%% function : out_request_enc
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect : Intercept an outgoing request (client-side).
-%%------------------------------------------------------------
-out_request_enc(PIs, ObjKey, Ctx, Op, Ref, Msg) ->
- case catch out_request_enc(PIs, ObjKey, Ctx, Op, Ref, Msg, undefined) of
- {'EXIT', R} ->
- orber:dbg("[~p] orber_pi:out_request_enc(~p, ~p, ~p); exit(~p)",
- [?LINE, PIs, Ref, Msg, R], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_NO});
- {'EXCEPTION', E} ->
- orber:dbg("[~p] orber_pi:out_request_enc(~p, ~p, ~p); exception(~p)",
- [?LINE, PIs, Ref, Msg, E], ?DEBUG_LEVEL),
- corba:raise(E);
- NewMsg ->
- NewMsg
- end.
-
-out_request_enc([], _, _, _, _, Msg, _) ->
- Msg;
-out_request_enc([Mod|T], ObjKey, Ctx, Op, Ref, Msg, Args) ->
- {NewMsg, NewArgs} = Mod:out_request_encoded(Ref, ObjKey, Ctx, Op, Msg, Args),
- out_request_enc(T, ObjKey, Ctx, Op, Ref, NewMsg, NewArgs).
-
-
-%%------------------------------------------------------------
-%% function : out_request
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect : Intercept an outgoing request (client-side).
-%%------------------------------------------------------------
-out_request(PIs, ObjKey, Ctx, Op, Ref, Msg) ->
- case catch out_request(PIs, ObjKey, Ctx, Op, Ref, Msg, undefined) of
- {'EXIT', R} ->
- orber:dbg("[~p] orber_pi:out_request(~p, ~p, ~p); exit(~p)",
- [?LINE, PIs, Ref, Msg, R], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_NO});
- {'EXCEPTION', E} ->
- orber:dbg("[~p] orber_pi:out_request(~p, ~p, ~p); exception(~p)",
- [?LINE, PIs, Ref, Msg, E], ?DEBUG_LEVEL),
- corba:raise(E);
- NewMsg ->
- NewMsg
- end.
-
-out_request([], _, _, _, _, Msg, _) ->
- Msg;
-out_request([Mod|T], ObjKey, Ctx, Op, Ref, Msg, Args) ->
- {NewMsg, NewArgs} = Mod:out_request(Ref, ObjKey, Ctx, Op, Msg, Args),
- out_request(T, ObjKey, Ctx, Op, Ref, NewMsg, NewArgs).
-
-
-%%------------------------------------------------------------
-%% function :in_reply_enc
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect : Intercept an incoming reply (client-side)
-%%------------------------------------------------------------
-in_reply_enc(PIs, ObjKey, Ctx, Op, Ref, Msg) ->
- case catch in_reply_enc(PIs, ObjKey, Ctx, Op, Ref, Msg, undefined) of
- {'EXIT', R} ->
- orber:dbg("[~p] orber_pi:in_reply_enc(~p, ~p, ~p); exit(~p)",
- [?LINE, PIs, Ref, Msg, R], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE});
- {'EXCEPTION', E} ->
- orber:dbg("[~p] orber_pi:in_reply_enc(~p, ~p, ~p); exception(~p)",
- [?LINE, PIs, Ref, Msg, E], ?DEBUG_LEVEL),
- corba:raise(E);
- NewMsg ->
- NewMsg
- end.
-
-in_reply_enc([], _, _, _, _, Msg, _) ->
- Msg;
-in_reply_enc([Mod|T], ObjKey, Ctx, Op, Ref, Msg, Args) ->
- {NewMsg, NewArgs} = Mod:in_reply_encoded(Ref, ObjKey, Ctx, Op, Msg, Args),
- in_reply_enc(T, ObjKey, Ctx, Op, Ref, NewMsg, NewArgs).
-
-%%------------------------------------------------------------
-%% function :in_reply
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect : Intercept an incoming reply (client-side)
-%%------------------------------------------------------------
-in_reply(PIs, ObjKey, Ctx, Op, Ref, Msg) ->
- case catch in_reply(PIs, ObjKey, Ctx, Op, Ref, Msg, undefined) of
- {'EXIT', R} ->
- orber:dbg("[~p] orber_pi:in_reply(~p, ~p, ~p); exit(~p)",
- [?LINE, PIs, Ref, Msg, R], ?DEBUG_LEVEL),
- corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE});
- NewMsg ->
- NewMsg
- end.
-
-in_reply([], _, _, _, _, Msg, _) ->
- Msg;
-in_reply([Mod|T], ObjKey, Ctx, Op, Ref, Msg, Args) ->
- {NewMsg, NewArgs} = Mod:in_reply(Ref, ObjKey, Ctx, Op, Msg, Args),
- in_reply(T, ObjKey, Ctx, Op, Ref, NewMsg, NewArgs).
-
-
-
-
-%%------------------------------------------------------------
-%%------------- CODEC FUNCTIONS ------------------------------
-%%------------------------------------------------------------
-%% function : codefactory_create_codec
-%% Arguments: #IOP_N_Encoding{}
-%% Returns : CodecRef
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-codefactory_create_codec(#'IOP_N_Encoding'{format = 'IOP_N_ENCODING_CDR_ENCAPS',
- major_version = Major,
- minor_version = Minor})
- when is_integer(Major) andalso is_integer(Minor) ->
- {Major, Minor};
-codefactory_create_codec(_) ->
- corba:raise(#'IOP_N_CodecFactory_UnknownEncoding'{}).
-
-%%------------------------------------------------------------
-%% function : codec_encode
-%% Arguments: Version - GIOP version
-%% Any - #any{}
-%% Returns : CORBA::OctetSeq
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-codec_encode(Version, Any) when is_record(Any, any) ->
- %% Encode ByteOrder
- {Bytes, Len} = cdr_encode:enc_type('tk_octet', Version, 0, [], 0),
- {Bytes2, _Len2} = cdr_encode:enc_type('tk_any', Version, Any, Bytes, Len),
- list_to_binary(lists:reverse(Bytes2));
-codec_encode(_Version, _Any) ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%------------------------------------------------------------
-%% function : codec_encode_value
-%% Arguments: Version - GIOP version
-%% Any - #any{}
-%% Returns : CORBA::OctetSeq
-%% Exception:
-%% Effect : Encode the Any#any.value only.
-%%------------------------------------------------------------
-codec_encode_value(Version, #any{typecode = TC, value = Val}) ->
- %% Encode ByteOrder
- {Bytes, Len} = cdr_encode:enc_type('tk_octet', Version, 0, [], 0),
- {Bytes2, _Len2} = cdr_encode:enc_type(TC, Version, Val, Bytes, Len),
- list_to_binary(lists:reverse(Bytes2));
-codec_encode_value(_Version, _NotAnAny) ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%------------------------------------------------------------
-%% function : codec_decode
-%% Arguments: Version - GIOP version
-%% Bytes - CORBA::OctetSeq
-%% Returns : Any - #any{}
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-codec_decode(Version, Bytes) when is_binary(Bytes) ->
- {ByteOrder, Rest} = cdr_decode:dec_byte_order(Bytes),
- case catch cdr_decode:dec_type('tk_any', Version, Rest, 0, ByteOrder) of
- {Any, [], _} ->
- Any;
- _->
- corba:raise(#'IOP_N_Codec_FormatMismatch'{})
- end;
-codec_decode(_Version, _Any) ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-%%------------------------------------------------------------
-%% function : codec_decode_value
-%% Arguments: Version - GIOP version
-%% Bytes - CORBA::OctetSeq
-%% TypeCode - CORBA::TypeCode
-%% Returns : Any - #any{}
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-codec_decode_value(Version, Bytes, TypeCode) when is_binary(Bytes) ->
- {ByteOrder, Rest} = cdr_decode:dec_byte_order(Bytes),
- case catch cdr_decode:dec_type(TypeCode, Version, Rest, 0, ByteOrder) of
- {Val, [], _} ->
- #any{typecode = TypeCode, value = Val};
- _->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO})
- end;
-codec_decode_value(_Version, _Bytes, _TypeCode) ->
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
-
-
-%%------------------------------------------------------------
-%%------------- SERVER SIDE FUNCTIONS ------------------------
-%%------------------------------------------------------------
-%% To make a long story short, you find an conceptual description
-%% of how, and in which order, the different functions is
-%% supposed to be invoked.
-%%
-%%request_from_iiop(Bytes) ->
-%% Reply =
-%% case receive_service_contexts(ServerRequestInfo) of
-%% SYSTEM EXC ->
-%% send_exception(..);
-%% ForwardRequest EXC ->
-%% send_other(..);
-%% NoEXC ->
-%% case receive_request(..) of
-%% SYSTEM EXC ->
-%% send_exception(..);
-%% ForwardRequest EXC ->
-%% send_other(..);
-%% No EXC ->
-%% InvokeServer
-%% end
-%% end,
-%% case Reply of
-%% EXC ->
-%% send_exception(..);
-%% No EXC, Normal Reply ->
-%% case send_reply(..) of
-%% SYSTEM EXC ->
-%% send_exception(..);
-%% ForwardRequest EXC ->
-%% send_other(..);
-%% No Exc ->
-%% Done
-%% end;
-%% No EXC, LOCATION_FORWARD ->
-%% send_other(..)
-%% end.
-%%
-%%
-%%------------------------------------------------------------
-%% function : server_start_receive
-%% Arguments: Msg - #giop_message{}
-%% PIs - a list of Interceptors (see 'Comments' in the module header)
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-server_start_receive(PIs, Version, ReqHdr, Rest, Len, ByteOrder, Msg) ->
- cdr_decode:dec_request_body(Version, ReqHdr, Rest, Len, ByteOrder, Msg),
- SRI = ?createInitSRI(ReqHdr#request_header.request_id,
- ReqHdr#request_header.operation,
- ReqHdr#request_header.response_expected),
- server_receive(receive_service_contexts, SRI, PIs, [], PIs).
-
-server_receive(receive_service_contexts, SRI, [], _Acc, PIs) ->
- server_receive(receive_request, SRI, PIs, [], PIs);
-server_receive(receive_service_contexts, SRI, [H|T], Acc, PIs) ->
- case catch receive_service_contexts(SRI, H) of
- {'EXCEPTION', #'PortableInterceptor_ForwardRequest'{forward=_Obj,
- permanent=_Bool}} ->
- server_send(send_other, SRI, Acc, [], PIs);
- {'EXCEPTION', _E} ->
- server_send(send_exception, SRI, Acc, [], PIs);
- _ ->
- server_receive(receive_service_contexts, SRI, T, Acc, PIs)
- end;
-server_receive(receive_request, SRI, [], _Acc, _PIs) ->
- %% Done with receive interceptors, now we can call the server.
- SRI;
-server_receive(receive_request, SRI, [H|T], Acc, PIs) ->
- case catch receive_request(SRI, H) of
- {'EXCEPTION', #'PortableInterceptor_ForwardRequest'{forward=_Obj,
- permanent=_Bool}} ->
- server_send(send_other, SRI, Acc, [], PIs);
- {'EXCEPTION', _E} ->
- server_send(send_exception, SRI, Acc, [], PIs);
- _ ->
- server_receive(receive_request, SRI, T, Acc, PIs)
- end.
-
-
-%%------------------------------------------------------------
-%% function : server_start_send
-%% Arguments: SRI - ServerRequestInfo
-%% PIs - a list of Interceptors (see 'Comments' in the module header)
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-server_start_send(PIs, SRI) ->
- case SRI#'ServerRequestInfo'.reply_status of
- 'PortableInterceptor_SUCCESSFUL' ->
- server_send(send_reply, SRI, PIs, [], PIs);
- 'PortableInterceptor_SYSTEM_EXCEPTION' ->
- server_send(send_exception, SRI, PIs, [], PIs);
- 'PortableInterceptor_USER_EXCEPTION' ->
- server_send(send_exception, SRI, PIs, [], PIs);
- _ ->
- server_send(send_other, SRI, PIs, [], PIs)
- end.
-
-server_send(_, SRI, [], _Acc, _PIs) ->
- %% Done
- SRI;
-server_send(send_exception, SRI, [H|T], Acc, PIs) ->
- case catch send_exception(SRI, H) of
- {'EXCEPTION', #'PortableInterceptor_ForwardRequest'{forward=_Obj,
- permanent=_Bool}} ->
- server_send(send_other, SRI, Acc, [], PIs);
- {'EXCEPTION', _E} ->
- server_send(send_exception, SRI, Acc, [], PIs);
- _ ->
- server_send(send_exception, SRI, T, Acc, PIs)
- end;
-server_send(send_other, SRI, [H|T], Acc, PIs) ->
- case catch send_other(SRI, H) of
- {'EXCEPTION', #'PortableInterceptor_ForwardRequest'{forward=_Obj,
- permanent=_Bool}} ->
- server_send(send_other, SRI, T, Acc, PIs);
- {'EXCEPTION', _E} ->
- server_send(send_exception, SRI, T, Acc, PIs);
- _ ->
- server_send(send_other, SRI, T, Acc, PIs)
- end;
-server_send(send_reply, SRI, [H|T], Acc, PIs) ->
- case catch send_reply(SRI, H) of
- {'EXCEPTION', _E} ->
- server_send(send_exception, SRI, T, Acc, PIs);
- _ ->
- server_send(send_reply, SRI, T, Acc, PIs)
- end.
-
-receive_request(SRI, Mod) ->
- apply(Mod, receive_request, [SRI]).
-
-send_other(SRI, Mod) ->
- apply(Mod, send_other, [SRI]).
-
-receive_service_contexts(SRI, Mod) ->
- apply(Mod, receive_service_contexts, [SRI]).
-
-send_reply(SRI, Mod) ->
- apply(Mod, send_reply, [SRI]).
-
-send_exception(SRI, Mod) ->
- apply(Mod, send_exception, [SRI]).
-
-
-%%------------------------------------------------------------
-%%------------- CLIENT SIDE FUNCTIONS ------------------------
-%%------------------------------------------------------------
-%% To make a long story short, you find an conceptual description
-%% of how, and in which order, the different functions is
-%% supposed to be invoked.
-%%
-%%request(Data) ->
-%% Reply =
-%% case send_request(CRI) of
-%% SYSTEM EXC ->
-%% receive_exception(..);
-%% ForwardRequest EXC ->
-%% receive_other(..);
-%% NoEXC ->
-%% IIOP-send
-%% end,
-%% case Reply of
-%% EXC ->
-%% receive_exception(..); May raise system exc => receive_other(..);
-%% No EXC, Normal Reply ->
-%% receive_reply(..) May raise system exc => receive_exception(..);
-%% Non-normal reply (e.g. LOCATION_FORWARD) ->
-%% receive_other(..) May raise system exc => receive_exception(..);
-%% end.
-%%------------------------------------------------------------
-%% function : client_send
-%% Arguments: CRI - ClientRequestInfo
-%% PIs - a list of Interceptors (see 'Comments' in the module header)
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-
-client_send(CRI, PIs) ->
- client_send(send_request, CRI, PIs, [], PIs).
-
-client_send(send_request, CRI, [], _, _) ->
- CRI;
-client_send(send_request, CRI, [H|T], Acc, PIs) ->
- case catch send_request(CRI, H) of
- {'EXCEPTION', #'PortableInterceptor_ForwardRequest'{forward=_Obj,
- permanent=_Bool}} ->
- client_receive(receive_other, CRI, T, [], PIs);
- {'EXCEPTION', _E} ->
- client_receive(receive_exception, CRI, Acc, [], PIs);
- _ ->
- client_send(send_request, CRI, T, Acc, PIs)
- end.
-
-
-
-%%------------------------------------------------------------
-%% function : client_receive
-%% Arguments: CRI - ClientRequestInfo
-%% PIs - a list of Interceptors (see 'Comments' in the module header)
-%% Returns :
-%% Exception:
-%% Effect :
-%%------------------------------------------------------------
-
-client_receive(CRI, PIs) ->
- case CRI#'ClientRequestInfo'.reply_status of
- 'PortableInterceptor_SUCCESSFUL' ->
- client_receive(receive_reply, CRI, PIs, [], PIs);
- 'PortableInterceptor_SYSTEM_EXCEPTION' ->
- client_receive(receive_exception, CRI, PIs, [], PIs);
- 'PortableInterceptor_USER_EXCEPTION' ->
- client_receive(receive_exception, CRI, PIs, [], PIs);
- _ ->
- client_receive(receive_other, CRI, PIs, [], PIs)
- end.
-
-client_receive(_, CRI, [], _, _) ->
- %% Done
- CRI;
-client_receive(receive_reply, CRI, [H|T], Acc, PIs) ->
- case catch receive_reply(CRI, H) of
- {'EXCEPTION', _E} ->
- client_receive(receive_exception, CRI, T, [H|Acc], PIs);
- _ ->
- client_receive(receive_reply, CRI, T, [H|Acc], PIs)
- end;
-client_receive(receive_exception, CRI, [H|T], Acc, PIs) ->
- case catch receive_exception(CRI, H) of
- {'EXCEPTION', #'PortableInterceptor_ForwardRequest'{forward=_Obj,
- permanent=_Bool}} ->
- client_receive(receive_other, CRI, T, [], PIs);
- {'EXCEPTION', _E} ->
- client_receive(receive_exception, CRI, T, [H|Acc], PIs);
- _ ->
- client_receive(receive_exception, CRI, T, [H|Acc], PIs)
- end;
-client_receive(receive_other, CRI, [H|T], Acc, PIs) ->
- case catch receive_other(CRI, H) of
- {'EXCEPTION', #'PortableInterceptor_ForwardRequest'{forward=_Obj,
- permanent=_Bool}} ->
- client_receive(receive_other, CRI, T, [], PIs);
- {'EXCEPTION', _E} ->
- client_receive(receive_exception, CRI, T, [H|Acc], PIs);
- _ ->
- client_receive(receive_other, CRI, T, [H|Acc], PIs)
- end.
-
-
-
-send_request(CRI, Mod) ->
- apply(Mod, send_request, [CRI]).
-
-receive_reply(CRI, Mod) ->
- apply(Mod, receive_reply, [CRI]).
-
-receive_other(CRI, Mod) ->
- apply(Mod, receive_other, [CRI]).
-
-receive_exception(CRI, Mod) ->
- apply(Mod, receive_exception, [CRI]).
-
-%%------------------------------------------------------------
-%% Functions for retrieving info from RequestInfo
-%% ServerRequestInfo and ClientRequestInfo. The ones matching
-%% both ServerRequestInfo and ClientRequestInfo eq. RequestInfo.
-%% Note, RequestInfo is inherrited by the others.
-%%------------------------------------------------------------
-%%-----------------------------------------------------------%
-%% function : _get_request_id
-%% Arguments: ClientRequestInfo or ServerRequestInfo
-%% Returns : ulong()
-%%------------------------------------------------------------
-'_get_request_id'(#'ClientRequestInfo'{request_id = ID}) ->
- ID;
-'_get_request_id'(#'ServerRequestInfo'{request_id = ID}) ->
- ID.
-
-%%-----------------------------------------------------------%
-%% function : _get_operation
-%% Arguments: ClientRequestInfo or ServerRequestInfo
-%% Returns : string()
-%%------------------------------------------------------------
-'_get_operation'(#'ClientRequestInfo'{operation = Op}) ->
- Op;
-'_get_operation'(#'ServerRequestInfo'{operation = Op}) ->
- Op.
-
-%%-----------------------------------------------------------%
-%% function : _get_arguments
-%% Arguments: ClientRequestInfo or ServerRequestInfo
-%% Returns : A list of #'Dynamic_Parameter'{}
-%%------------------------------------------------------------
-'_get_arguments'(#'ClientRequestInfo'{arguments = Args}) ->
- Args;
-'_get_arguments'(#'ServerRequestInfo'{arguments = Args}) ->
- Args.
-
-%%-----------------------------------------------------------%
-%% function : _get_exceptions
-%% Arguments: ClientRequestInfo or ServerRequestInfo
-%% Returns : A list of CORBA::TypeCode
-%%------------------------------------------------------------
-'_get_exceptions'(#'ClientRequestInfo'{exceptions = Exc}) ->
- Exc;
-'_get_exceptions'(#'ServerRequestInfo'{exceptions = Exc}) ->
- Exc.
-
-%%-----------------------------------------------------------%
-%% function : _get_contexts
-%% Arguments: ClientRequestInfo or ServerRequestInfo
-%% Returns : A list of CORBA::StringSeq
-%%------------------------------------------------------------
-'_get_contexts'(#'ClientRequestInfo'{contexts = Ctx}) ->
- Ctx;
-'_get_contexts'(#'ServerRequestInfo'{contexts = Ctx}) ->
- Ctx.
-
-%%-----------------------------------------------------------%
-%% function : _get_operation_context
-%% Arguments: ClientRequestInfo or ServerRequestInfo
-%% Returns : A list of CORBA::StringSeq
-%%------------------------------------------------------------
-'_get_operation_context'(#'ClientRequestInfo'{operation_context = OpCtx}) ->
- OpCtx;
-'_get_operation_context'(#'ServerRequestInfo'{operation_context = OpCtx}) ->
- OpCtx.
-
-%%-----------------------------------------------------------%
-%% function : _get_result
-%% Arguments: ClientRequestInfo or ServerRequestInfo
-%% Returns : #any{}
-%%------------------------------------------------------------
-'_get_result'(#'ClientRequestInfo'{result = Res}) ->
- Res;
-'_get_result'(#'ServerRequestInfo'{result = Res}) ->
- Res.
-
-%%-----------------------------------------------------------%
-%% function : _get_response_expected
-%% Arguments: ClientRequestInfo or ServerRequestInfo
-%% Returns : boolean()
-%%------------------------------------------------------------
-'_get_response_expected'(#'ClientRequestInfo'{response_expected = Bool}) ->
- Bool;
-'_get_response_expected'(#'ServerRequestInfo'{response_expected = Bool}) ->
- Bool.
-
-%%-----------------------------------------------------------%
-%% function : _get_sync_scope
-%% Arguments: ClientRequestInfo or ServerRequestInfo
-%% Returns : Messaging::SyncScoope ('SYNC_NONE', 'SYNC_WITH_TRANSPORT',
-%% 'SYNC_WITH_SERVER', 'SYNC_WITH_TARGET')
-%%------------------------------------------------------------
-'_get_sync_scope'(#'ClientRequestInfo'{sync_scope = SS}) ->
- SS;
-'_get_sync_scope'(#'ServerRequestInfo'{sync_scope = SS}) ->
- SS.
-
-%%-----------------------------------------------------------%
-%% function : _get_reply_status
-%% Arguments: ClientRequestInfo or ServerRequestInfo
-%% Returns : ReplyStatus (short), defined in orber_pi.hrl
-%%------------------------------------------------------------
-'_get_reply_status'(#'ClientRequestInfo'{reply_status = RS}) ->
- RS;
-'_get_reply_status'(#'ServerRequestInfo'{reply_status = RS}) ->
- RS.
-
-%%-----------------------------------------------------------%
-%% function : _get_forward_reference
-%% Arguments: ClientRequestInfo or ServerRequestInfo
-%% Returns : Object
-%%------------------------------------------------------------
-'_get_forward_reference'(#'ClientRequestInfo'{forward_reference = FR}) ->
- FR;
-'_get_forward_reference'(#'ServerRequestInfo'{forward_reference = FR}) ->
- FR.
-
-%%------------------------------------------------------------
-%% function : get_slot
-%% Arguments: ClientRequestInfo or ServerRequestInfo
-%% SlotId - ulong()
-%% Returns : {'EXCEPTION', #'PortableInterceptor_InvalidSlot'{}}
-%%------------------------------------------------------------
--spec get_slot(_, _) -> no_return().
-get_slot(_XRI, _SlotId) ->
- corba:raise(#'PortableInterceptor_InvalidSlot'{}).
-
-%%------------------------------------------------------------
-%% function : get_request_service_context
-%% Arguments: ClientRequestInfo or ServerRequestInfo
-%% ServiceId - IOP::ServiceId (defined in orber_iiop.hrl)
-%% Returns : IOP::ServiceContext
-%%------------------------------------------------------------
-get_request_service_context(#'ClientRequestInfo'{contexts = Ctx}, _ServiceId) ->
- Ctx;
-get_request_service_context(#'ServerRequestInfo'{contexts = Ctx}, _ServiceId) ->
- Ctx.
-
-%%------------------------------------------------------------
-%% function : get_reply_service_context
-%% Arguments: ClientRequestInfo or ServerRequestInfo
-%% ServiceId - IOP::ServiceId (defined in orber_iiop.hrl)
-%% Returns : IOP::ServiceContext
-%%------------------------------------------------------------
-get_reply_service_context(#'ClientRequestInfo'{contexts = Ctx}, _ServiceId) ->
- Ctx;
-get_reply_service_context(#'ServerRequestInfo'{contexts = Ctx}, _ServiceId) ->
- Ctx.
-
-%%------------------------------------------------------------
-%%-------------- ClientRequestInfo only ----------------------
-%%-----------------------------------------------------------%
-%% function : _get_target
-%% Arguments: ClientRequestInfo
-%% Returns : Object
-%%------------------------------------------------------------
-'_get_target'(#'ClientRequestInfo'{target = Target}) ->
- Target.
-
-%%-----------------------------------------------------------%
-%% function : _get_effective_target
-%% Arguments: ClientRequestInfo
-%% Returns : Object
-%%------------------------------------------------------------
-'_get_effective_target'(#'ClientRequestInfo'{effective_target = ET}) ->
- ET.
-
-%%-----------------------------------------------------------%
-%% function : _get_effective_profile
-%% Arguments: ClientRequestInfo
-%% Returns : IOP:TaggedProfile
-%%------------------------------------------------------------
-'_get_effective_profile'(#'ClientRequestInfo'{effective_profile = EP}) ->
- EP.
-
-%%-----------------------------------------------------------%
-%% function : _get_received_exception
-%% Arguments: ClientRequestInfo
-%% Returns : #any{}
-%%------------------------------------------------------------
-'_get_received_exception'(#'ClientRequestInfo'{received_exception = RE}) ->
- RE.
-
-%%-----------------------------------------------------------%
-%% function : _get_received_exception
-%% Arguments: ClientRequestInfo
-%% Returns : CORBA::RepositoryId
-%%------------------------------------------------------------
-'_get_received_exception_id'(#'ClientRequestInfo'{received_exception_id = REId}) ->
- REId.
-
-%%------------------------------------------------------------
-%% function : get_effective_component
-%% Arguments: ClientRequestInfo
-%% Returns : IOR::TaggedComponent
-%%------------------------------------------------------------
-get_effective_component(#'ClientRequestInfo'{target = Target}, _Id) ->
- Target.
-
-%%------------------------------------------------------------
-%% function : get_effective_components
-%% Arguments: ClientRequestInfo
-%% Id -IOP::ComponentId (ulong())
-%% Returns : IOP_N::TaggedComponentSeq
-%%------------------------------------------------------------
-get_effective_components(#'ClientRequestInfo'{target = Target}, _Id) ->
- Target.
-
-%%------------------------------------------------------------
-%% function : get_request_policy
-%% Arguments: ClientRequestInfo
-%% Type - CORBA::PolicyType
-%% Returns : IOP_N::TaggedComponentSeq
-%%------------------------------------------------------------
-get_request_policy(#'ClientRequestInfo'{target = Target}, _Type) ->
- Target.
-
-%%------------------------------------------------------------
-%% function : add_request_service_context
-%% Arguments: ClientRequestInfo
-%% Ctx - IOP::ServiceContext
-%% Replace - boolean()
-%% Returns : -
-%%------------------------------------------------------------
-add_request_service_policy(#'ClientRequestInfo'{target = _Target},
- _Ctx, _Replace) ->
- ok.
-
-%%------------------------------------------------------------
-%%-------------- ServerRequestInfo only ----------------------
-%%-----------------------------------------------------------%
-%% function : _get_sending_exception
-%% Arguments: ServerRequestInfo
-%% Returns : #any{}
-%%------------------------------------------------------------
-'_get_sending_exception'(#'ServerRequestInfo'{sending_exception = Exc}) ->
- Exc.
-
-%%-----------------------------------------------------------%
-%% function : _get_object_id
-%% Arguments: ServerRequestInfo
-%% Returns : CORBA::OctetSeq
-%%------------------------------------------------------------
-'_get_object_id'(#'ServerRequestInfo'{object_id = OI}) ->
- OI.
-
-%%-----------------------------------------------------------%
-%% function : _get_adapter_id
-%% Arguments: ServerRequestInfo
-%% Returns : CORBA::OctetSeq
-%%------------------------------------------------------------
-'_get_adapter_id'(#'ServerRequestInfo'{adapter_id = AI}) ->
- AI.
-
-%%-----------------------------------------------------------%
-%% function : _get_target_most_derived_interface
-%% Arguments: ServerRequestInfo
-%% Returns : CORBA::RepositoryId
-%%------------------------------------------------------------
-'_get_target_most_derived_interface'(#'ServerRequestInfo'
- {target_most_derived_interface = TMDI}) ->
- TMDI.
-
-%%------------------------------------------------------------
-%% function : get_server_policy
-%% Arguments: ServerRequestInfo
-%% PolicyType - CORBA::PolicyType
-%% Returns : CORBA::Policy
-%%------------------------------------------------------------
-get_server_policy(#'ServerRequestInfo'{contexts = Ctxs}, _PolicyType) ->
- Ctxs.
-
-%%------------------------------------------------------------
-%% function : set_slot
-%% Arguments: ServerRequestInfo
-%% SlotId - ulong()
-%% Data - #any{}
-%% Returns : {'EXCEPTION', #'PortableInterceptor_InvalidSlot'{}}
-%%------------------------------------------------------------
--spec set_slot(_, _, _) -> no_return().
-set_slot(_SRI, _SlotId, _Data) ->
- corba:raise(#'PortableInterceptor_InvalidSlot'{}).
-
-%%-----------------------------------------------------------%
-%% function : target_is_a
-%% Arguments: ServerRequestInfo
-%% IFRId - CORBA::RepositoryId
-%% Returns : boolean()
-%%------------------------------------------------------------
-target_is_a(#'ServerRequestInfo'{object_id = ObjId}, IFRId) ->
- corba_object:is_a(ObjId, IFRId).
-
-%%------------------------------------------------------------
-%% function : add_reply_service_context
-%% Arguments: ServerRequestInfo
-%% Ctx - IOP::ServiceContext
-%% Replace - boolean()
-%% Returns : -
-%%------------------------------------------------------------
-add_reply_service_context(#'ServerRequestInfo'{contexts = Ctxs}, _Ctx, _Replace) ->
- Ctxs.
-
-
-%%--------------- END OF MODULE ------------------------------
diff --git a/lib/orber/src/orber_request_number.erl b/lib/orber/src/orber_request_number.erl
deleted file mode 100644
index 755b999c13..0000000000
--- a/lib/orber/src/orber_request_number.erl
+++ /dev/null
@@ -1,83 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: orber_request_number.erl
-%%
-%% Description:
-%% This file contains the request number server in Orber
-%%
-%%-----------------------------------------------------------------
--module(orber_request_number).
-
--behaviour(gen_server).
-
--include_lib("orber/src/orber_iiop.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([start/1, get/0, reset/0]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([init/1, terminate/2, handle_call/3]).
--export([handle_cast/2, handle_info/2, code_change/3]).
-
-%%-----------------------------------------------------------------
-%% External interface functions
-%%-----------------------------------------------------------------
-start(Opts) ->
- gen_server:start_link({local, orber_reqno}, orber_request_number, Opts, []).
-
-get() ->
- gen_server:call(orber_reqno, get, infinity).
-
-reset() ->
- gen_server:call(orber_reqno, reset, infinity).
-
-%%-----------------------------------------------------------------
-%% Server functions
-%%-----------------------------------------------------------------
-init(_Opts) ->
- {ok, 0}.
-
-terminate(_Reason, _State) ->
- ok.
-%% Max is ulong 0 .. 2^32-1
-handle_call(get, _From, State) when State < ?ULONGMAX ->
- {reply, State, State+1};
-handle_call(get, _From, _State) ->
- {reply, ?ULONGMAX, 0};
-handle_call(reset, _From, _State) ->
- {reply, ok, 0}.
-
-handle_cast(_, State) ->
- {noreply, State}.
-
-handle_info(_, State) ->
- {noreply, State}.
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-
diff --git a/lib/orber/src/orber_socket.erl b/lib/orber/src/orber_socket.erl
deleted file mode 100644
index 9b39dad928..0000000000
--- a/lib/orber/src/orber_socket.erl
+++ /dev/null
@@ -1,530 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2015. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: orber_socket.erl
-%%
-%% Description:
-%% This file contains a standard interface to the sockets to handle the differences
-%% between the implementations used.
-%%
-%%-----------------------------------------------------------------
--module(orber_socket).
-
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
-
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([start/0, connect/4, listen/3, listen/4, accept/2, accept/3, write/3,
- controlling_process/3, close/2, peername/2, sockname/2,
- peerdata/2, peercert/2, sockdata/2, setopts/3,
- clear/2, shutdown/3, post_accept/2, post_accept/3,
- get_ip_family_opts/1]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-%%-----------------------------------------------------------------
-%% Internal defines
-%%-----------------------------------------------------------------
--define(DEBUG_LEVEL, 6).
-
-%%-----------------------------------------------------------------
-%% External functions
-%%-----------------------------------------------------------------
-start() ->
- inet_db:start().
-
-%%-----------------------------------------------------------------
-%% Invoke the required setopts (i.e., inet or ssl)
-setopts(normal, Socket, Opts) ->
- inet:setopts(Socket, Opts);
-setopts(ssl, Socket, Opts) ->
- ssl:setopts(Socket, Opts).
-
-%%-----------------------------------------------------------------
-%% Connect to IIOP Port at Host in CDR mode, in order to
-%% establish a connection.
-%%
-connect(Type, Host, Port, Options) ->
- Timeout = orber:iiop_setup_connection_timeout(),
- Generation = orber_env:ssl_generation(),
- Options1 = check_options(Type, Options, Generation),
- Options2 =
- case Type of
- normal ->
- [{keepalive, orber_env:iiop_out_keepalive()}|Options1];
- _ ->
- Options1
- end,
- case orber:iiop_out_ports() of
- {Min, Max} when Type == normal ->
- multi_connect(get_port_sequence(Min, Max), orber_env:iiop_out_ports_attempts(),
- Type, Host, Port, [binary, {reuseaddr, true},
- {packet,cdr}| Options2], Timeout);
- {Min, Max} when Generation > 2 ->
- multi_connect(get_port_sequence(Min, Max), orber_env:iiop_out_ports_attempts(),
- Type, Host, Port, [binary, {reuseaddr, true},
- {packet,cdr}| Options2], Timeout);
- {Min, Max} ->
- %% reuseaddr not available for older SSL versions
- multi_connect(get_port_sequence(Min, Max), orber_env:iiop_out_ports_attempts(),
- Type, Host, Port, [binary, {packet,cdr}| Options2], Timeout);
- _ ->
- connect(Type, Host, Port, [binary, {packet,cdr}| Options2], Timeout)
- end.
-
-connect(normal, Host, Port, Options, Timeout) ->
- case catch gen_tcp:connect(Host, Port, Options, Timeout) of
- {ok, Socket} ->
- Socket;
- {error, timeout} ->
- orber:dbg("[~p] orber_socket:connect(normal, ~p, ~p, ~p);~n"
- "Timeout after ~p msec.",
- [?LINE, Host, Port, Options, Timeout], ?DEBUG_LEVEL),
- corba:raise(#'COMM_FAILURE'{minor=(?ORBER_VMCID bor 4),
- completion_status=?COMPLETED_NO});
- Error ->
- orber:dbg("[~p] orber_socket:connect(normal, ~p, ~p, ~p);~n"
- "Failed with reason: ~p",
- [?LINE, Host, Port, Options, Error], ?DEBUG_LEVEL),
- corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO})
- end;
-connect(ssl, Host, Port, Options, Timeout) ->
- case catch ssl:connect(Host, Port, Options, Timeout) of
- {ok, Socket} ->
- Socket;
- {error, timeout} ->
- orber:dbg("[~p] orber_socket:connect(ssl, ~p, ~p, ~p);~n"
- "Timeout after ~p msec.",
- [?LINE, Host, Port, Options, Timeout], ?DEBUG_LEVEL),
- corba:raise(#'COMM_FAILURE'{minor=(?ORBER_VMCID bor 4),
- completion_status=?COMPLETED_NO});
- Error ->
- orber:dbg("[~p] orber_socket:connect(ssl, ~p, ~p, ~p);~n"
- "Failed with reason: ~p",
- [?LINE, Host, Port, Options, Error], ?DEBUG_LEVEL),
- corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO})
- end.
-
-multi_connect([], _Retries, Type, Host, Port, Options, _) ->
- orber:dbg("[~p] orber_socket:multi_connect(~p, ~p, ~p, ~p);~n"
- "Unable to use any of the sockets defined by 'iiop_out_ports'.~n"
- "Either all ports are in use or to many connections already exists.",
- [?LINE, Type, Host, Port, Options], ?DEBUG_LEVEL),
- corba:raise(#'IMP_LIMIT'{minor=(?ORBER_VMCID bor 1), completion_status=?COMPLETED_NO});
-multi_connect([CurrentPort|Rest], Retries, normal, Host, Port, Options, Timeout) ->
- case catch gen_tcp:connect(Host, Port, [{port, CurrentPort}|Options], Timeout) of
- {ok, Socket} ->
- Socket;
- {error, timeout} when Retries =< 1 ->
- orber:dbg("[~p] orber_socket:multi_connect(normal, ~p, ~p, ~p);~n"
- "Timeout after ~p msec.",
- [?LINE, Host, Port, [{port, CurrentPort}|Options],
- Timeout], ?DEBUG_LEVEL),
- corba:raise(#'COMM_FAILURE'{minor=(?ORBER_VMCID bor 4),
- completion_status=?COMPLETED_NO});
- _ ->
- multi_connect(Rest, Retries - 1, normal, Host, Port, Options, Timeout)
- end;
-multi_connect([CurrentPort|Rest], Retries, ssl, Host, Port, Options, Timeout) ->
- case catch ssl:connect(Host, Port, [{port, CurrentPort}|Options], Timeout) of
- {ok, Socket} ->
- Socket;
- {error, timeout} when Retries =< 1 ->
- orber:dbg("[~p] orber_socket:multi_connect(ssl, ~p, ~p, ~p);~n"
- "Timeout after ~p msec.",
- [?LINE, Host, Port, [{port, CurrentPort}|Options],
- Timeout], ?DEBUG_LEVEL),
- corba:raise(#'COMM_FAILURE'{minor=(?ORBER_VMCID bor 4),
- completion_status=?COMPLETED_NO});
- _ ->
- multi_connect(Rest, Retries - 1, ssl, Host, Port, Options, Timeout)
- end.
-
-
-get_port_sequence(Min, Max) ->
- case orber_env:iiop_out_ports_random() of
- true ->
- Seq = lists:seq(Min, Max),
- random_sequence((Max - Min) + 1, Seq, []);
- _ ->
- lists:seq(Min, Max)
- end.
-
-random_sequence(0, _, Acc) ->
- Acc;
-random_sequence(Length, Seq, Acc) ->
- Nth = rand:uniform(Length),
- Value = lists:nth(Nth, Seq),
- NewSeq = lists:delete(Value, Seq),
- random_sequence(Length-1, NewSeq, [Value|Acc]).
-
-%%-----------------------------------------------------------------
-%% Create a listen socket at Port in CDR mode for
-%% data connection.
-%%
-listen(Type, Port, Options) ->
- listen(Type, Port, Options, true).
-
-listen(normal, Port, Options, Exception) ->
- Options1 = check_options(normal, Options, 0),
- Backlog = orber:iiop_backlog(),
- Keepalive = orber_env:iiop_in_keepalive(),
- Options2 = case orber:iiop_max_in_requests() of
- infinity ->
- Options1;
- _MaxRequests ->
- [{active, once}|Options1]
- end,
- Options3 = case orber_env:iiop_packet_size() of
- infinity ->
- Options2;
- MaxSize ->
- [{packet_size, MaxSize}|Options2]
- end,
- Options4 = [binary, {packet,cdr}, {keepalive, Keepalive},
- {reuseaddr,true}, {backlog, Backlog} |
- Options3],
-
- case catch gen_tcp:listen(Port, Options4) of
- {ok, ListenSocket} ->
- {ok, ListenSocket, check_port(Port, normal, ListenSocket)};
- {error, Reason} when Exception == false ->
- {error, Reason};
- {error, eaddrinuse} ->
- orber:dbg("[~p] orber_socket:listen(normal, ~p, ~p);~n"
- "Looks like the listen port is already in use.~n"
- "Check if another Orber is started~n"
- "on the same node and uses the same listen port (iiop_port). But it may also~n"
- "be used by any other application; confirm with 'netstat'.",
- [?LINE, Port, Options4], ?DEBUG_LEVEL),
- corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO});
- Error ->
- orber:dbg("[~p] orber_socket:listen(normal, ~p, ~p);~n"
- "Failed with reason: ~p",
- [?LINE, Port, Options4, Error], ?DEBUG_LEVEL),
- corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO})
- end;
-listen(ssl, Port, Options, Exception) ->
- Backlog = orber:iiop_ssl_backlog(),
- Generation = orber_env:ssl_generation(),
- Options1 = check_options(ssl, Options, Generation),
- Options2 = case orber:iiop_max_in_requests() of
- infinity ->
- Options1;
- _MaxRequests ->
- [{active, once}|Options1]
- end,
- Options3 = case orber_env:iiop_packet_size() of
- infinity ->
- Options2;
- MaxSize ->
- [{packet_size, MaxSize}|Options2]
- end,
- Options4 = if
- Generation > 2 ->
- [{reuseaddr, true} |Options3];
- true ->
- Options3
- end,
- Options5 = [binary, {packet,cdr}, {backlog, Backlog} | Options4],
- case catch ssl:listen(Port, Options5) of
- {ok, ListenSocket} ->
- {ok, ListenSocket, check_port(Port, ssl, ListenSocket)};
- {error, Reason} when Exception == false ->
- {error, Reason};
- {error, eaddrinuse} ->
- orber:dbg("[~p] orber_socket:listen(ssl, ~p, ~p);~n"
- "Looks like the listen port is already in use. Check if~n"
- "another Orber is started on the same node and uses the~n"
- "same listen port (iiop_port). But it may also~n"
- "be used by any other application; confirm with 'netstat'.",
- [?LINE, Port, Options5], ?DEBUG_LEVEL),
- corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO});
- Error ->
- orber:dbg("[~p] orber_socket:listen(ssl, ~p, ~p);~n"
- "Failed with reason: ~p",
- [?LINE, Port, Options5, Error], ?DEBUG_LEVEL),
- corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO})
- end.
-
-%%-----------------------------------------------------------------
-%% Wait in accept on the socket
-%%
-accept(Type, ListenSocket) ->
- accept(Type, ListenSocket, infinity).
-
-accept(normal, ListenSocket, _Timeout) ->
- case catch gen_tcp:accept(ListenSocket) of
- {ok, S} ->
- S;
- Error ->
- orber:dbg("[~p] orber_socket:accept(normal, ~p);~n"
- "Failed with reason: ~p",
- [?LINE, ListenSocket, Error], ?DEBUG_LEVEL),
- corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO})
- end;
-accept(ssl, ListenSocket, Timeout) ->
- case catch ssl:transport_accept(ListenSocket, Timeout) of
- {ok, S} ->
- S;
- Error ->
- orber:dbg("[~p] orber_socket:accept(ssl, ~p);~n"
- "Failed with reason: ~p",
- [?LINE, ListenSocket, Error], ?DEBUG_LEVEL),
- corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO})
- end.
-
-post_accept(Type, Socket) ->
- post_accept(Type, Socket, infinity).
-
-post_accept(normal, _Socket, _Timeout) ->
- ok;
-post_accept(ssl, Socket, Timeout) ->
- case catch ssl:ssl_accept(Socket, Timeout) of
- ok ->
- ok;
- Error ->
- orber:dbg("[~p] orber_socket:post_accept(ssl, ~p);~n"
- "Failed with reason: ~p",
- [?LINE, Socket, Error], ?DEBUG_LEVEL),
- corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO})
- end.
-
-
-%%-----------------------------------------------------------------
-%% Close the socket
-%%
-close(normal, Socket) ->
- (catch gen_tcp:close(Socket));
-close(ssl, Socket) ->
- (catch ssl:close(Socket)).
-
-%%-----------------------------------------------------------------
-%% Write to socket
-%%
-write(normal, Socket, Bytes) ->
- gen_tcp:send(Socket, Bytes);
-write(ssl, Socket, Bytes) ->
- ssl:send(Socket, Bytes).
-
-%%-----------------------------------------------------------------
-%% Change the controlling process for the socket
-%%
-controlling_process(normal, Socket, Pid) ->
- gen_tcp:controlling_process(Socket, Pid);
-controlling_process(ssl, Socket, Pid) ->
- ssl:controlling_process(Socket, Pid).
-
-%%-----------------------------------------------------------------
-%% Get peername
-%%
-peername(normal, Socket) ->
- inet:peername(Socket);
-peername(ssl, Socket) ->
- ssl:peername(Socket).
-
-%%-----------------------------------------------------------------
-%% Get peercert
-%%
-peercert(ssl, Socket) ->
- ssl:peercert(Socket);
-peercert(Type, _Socket) ->
- orber:dbg("[~p] orber_socket:peercert(~p);~n"
- "Only available for SSL sockets.",
- [?LINE, Type], ?DEBUG_LEVEL),
- {error, ebadsocket}.
-
-%%-----------------------------------------------------------------
-%% Get peerdata
-%%
-peerdata(normal, Socket) ->
- create_data(inet:peername(Socket));
-peerdata(ssl, Socket) ->
- create_data(ssl:peername(Socket)).
-
-%%-----------------------------------------------------------------
-%% Get sockname
-%%
-sockname(normal, Socket) ->
- inet:sockname(Socket);
-sockname(ssl, Socket) ->
- ssl:sockname(Socket).
-
-%%-----------------------------------------------------------------
-%% Get sockdata
-%%
-sockdata(normal, Socket) ->
- create_data(inet:sockname(Socket));
-sockdata(ssl, Socket) ->
- create_data(ssl:sockname(Socket)).
-
-
-create_data({ok, {Addr, Port}}) ->
- {orber_env:addr2str(Addr), Port};
-create_data(What) ->
- orber:dbg("[~p] orber_socket:peername() or orber_socket:sockname();~n"
- "Failed with reason: ~p", [?LINE, What], ?DEBUG_LEVEL),
- {"Unable to lookup peer- or sockname", 0}.
-
-
-%%-----------------------------------------------------------------
-%% Shutdown Connection
-%% How = read | write | read_write
-shutdown(normal, Socket, How) ->
- gen_tcp:shutdown(Socket, How);
-shutdown(ssl, Socket, How) ->
- Generation = orber_env:ssl_generation(),
- if
- Generation > 2 ->
- ssl:shutdown(Socket, How);
- How == read_write ->
- %% Older versions of SSL do no support shutdown.
- %% For now we'll use this solution instead.
- close(ssl, Socket);
- true ->
- {error, undefined}
- end.
-
-%%-----------------------------------------------------------------
-%% Remove Messages from queue
-%%
-clear(normal, Socket) ->
- tcp_clear(Socket);
-clear(ssl, Socket) ->
- ssl_clear(Socket).
-
-
-
-%% Inet also checks for the following messages:
-%% * {S, {data, Data}}
-%% * {inet_async, S, Ref, Status},
-%% * {inet_reply, S, Status}
-%% SSL doesn't.
-tcp_clear(Socket) ->
- receive
- {tcp, Socket, _Data} ->
- tcp_clear(Socket);
- {tcp_closed, Socket} ->
- tcp_clear(Socket);
- {tcp_error, Socket, _Reason} ->
- tcp_clear(Socket)
- after 0 ->
- ok
- end.
-
-ssl_clear(Socket) ->
- receive
- {ssl, Socket, _Data} ->
- ssl_clear(Socket);
- {ssl_closed, Socket} ->
- ssl_clear(Socket);
- {ssl_error, Socket, _Reason} ->
- ssl_clear(Socket)
- after 0 ->
- ok
- end.
-
-
-
-%%-----------------------------------------------------------------
-%% Check Port. If the user supplies 0 we pick any vacant port. But then
-%% we must change the associated environment variable
-check_port(0, normal, Socket) ->
- case inet:port(Socket) of
- {ok, Port} ->
- orber:configure_override(iiop_port, Port),
- Port;
- What ->
- orber:dbg("[~p] orber_socket:check_port(~p);~n"
- "Unable to extract the port number via inet:port/1~n",
- [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO})
- end;
-check_port(0, ssl, Socket) ->
- case ssl:sockname(Socket) of
- {ok, {_Address, Port}} ->
- orber:configure_override(iiop_ssl_port, Port),
- Port;
- What ->
- orber:dbg("[~p] orber_socket:check_port(~p);~n"
- "Unable to extract the port number via ssl:sockname/1~n",
- [?LINE, What], ?DEBUG_LEVEL),
- corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO})
- end;
-check_port(Port, _, _) ->
- Port.
-
-%%-----------------------------------------------------------------
-%% Check Options.
-check_options(normal, Options, _Generation) ->
- Options;
-check_options(ssl, Options, Generation) ->
- if
- Generation > 2 ->
- [{ssl_imp, new}|Options];
- true ->
- [{ssl_imp, old}|Options]
- end.
-
-
-%%-----------------------------------------------------------------
-%% Check IP Family.
-get_ip_family_opts(Host) ->
- case inet:parse_address(Host) of
- {ok, {_,_,_,_}} ->
- [inet];
- {ok, {_,_,_,_,_,_,_,_}} ->
- [inet6];
- {error, einval} ->
- check_family_for_name(Host, orber_env:ip_version())
- end.
-
-check_family_for_name(Host, inet) ->
- case inet:getaddr(Host, inet) of
- {ok, _Address} ->
- [inet];
- {error, _} ->
- case inet:getaddr(Host, inet6) of
- {ok, _Address} ->
- [inet6];
- {error, _} ->
- [inet]
- end
- end;
-check_family_for_name(Host, inet6) ->
- case inet:getaddr(Host, inet6) of
- {ok, _Address} ->
- [inet6];
- {error, _} ->
- case inet:getaddr(Host, inet) of
- {ok, _Address} ->
- [inet];
- {error, _} ->
- [inet6]
- end
- end.
-
diff --git a/lib/orber/src/orber_tb.erl b/lib/orber/src/orber_tb.erl
deleted file mode 100644
index 6a758330cd..0000000000
--- a/lib/orber/src/orber_tb.erl
+++ /dev/null
@@ -1,222 +0,0 @@
-%%----------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File: orber_tb.erl
-%%
-%% Description:
-%% Handling MISC functions.
-%%
-%% Creation date: 040723
-%%
-%%----------------------------------------------------------------------
--module(orber_tb).
-
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
-
-%%----------------------------------------------------------------------
-%% External exports
-%%----------------------------------------------------------------------
-%% Avoid warning for local function error/2 clashing with autoimported BIF.
--compile({no_auto_import,[error/2]}).
--export([wait_for_tables/1, wait_for_tables/2, wait_for_tables/3,
- is_loaded/0, is_loaded/1, is_running/0, is_running/1,
- info/2, error/2, unique/1, keysearch/2, keysearch/3,
- check_illegal_tcp_options/1]).
-
-%%----------------------------------------------------------------------
-%% Internal exports
-%%----------------------------------------------------------------------
--define(DEBUG_LEVEL, 5).
-
--define(FORMAT(_F, _A), {error, lists:flatten(io_lib:format(_F, _A))}).
--define(EFORMAT(_F, _A), exit(lists:flatten(io_lib:format(_F, _A)))).
-
-%%----------------------------------------------------------------------
-%% Record Definitions
-%%----------------------------------------------------------------------
-
-%%----------------------------------------------------------------------
-%% External functions
-%%----------------------------------------------------------------------
-%%----------------------------------------------------------------------
-%% Function : is_loaded/is_running
-%% Arguments :
-%% Returns :
-%% Raises :
-%% Description:
-%%----------------------------------------------------------------------
-is_loaded() ->
- is_loaded(orber).
-is_loaded(Appl) ->
- find_application(application:loaded_applications(), Appl).
-
-is_running() ->
- is_running(orber).
-is_running(Appl) ->
- find_application(application:which_applications(), Appl).
-
-find_application([], _) ->
- false;
-find_application([{Appl, _, _} |_], Appl) ->
- true;
-find_application([_ |As], Appl) ->
- find_application(As, Appl).
-
-%%----------------------------------------------------------------------
-%% function : keysearch/2/3
-%% Arguments: KeyValue - [{Key, Value}]
-%% Key - term()
-%% Value - term()
-%% Default - term()
-%% Returns : Value | Default
-%% Exception:
-%% Effect :
-%%----------------------------------------------------------------------
-keysearch(Key, KeyValue) ->
- keysearch(Key, KeyValue, undefined).
-keysearch(Key, KeyValue, Default) ->
- case lists:keysearch(Key, 1, KeyValue) of
- {value, {Key, Value}} ->
- Value;
- _ ->
- Default
- end.
-
-%%----------------------------------------------------------------------
-%% function : wait_for_tables/1
-%% Arguments: Tables - list of mnesia tables
-%% Timeout - integer (no point in allowing infinity)
-%% Attempts - integer > 0 How many times should we try
-%% Returns :
-%% Exception:
-%% Effect :
-%%----------------------------------------------------------------------
-wait_for_tables(Tables) ->
- wait_for_tables(Tables, 30000, -1).
-wait_for_tables(Tables, Timeout) ->
- wait_for_tables(Tables, Timeout, -1).
-wait_for_tables(Tables, _Timeout, 0) ->
- error("Mnesia failed to load the some or all of the following"
- "tables:~n~p", [Tables]),
- {error, "The requested Mnesia tables not yet available."};
-wait_for_tables(Tables, Timeout, Attempts) ->
- case mnesia:wait_for_tables(Tables, Timeout) of
- ok ->
- ok;
- {timeout, BadTabList} ->
- info("Mnesia hasn't loaded the following tables (~p msec):~n~p",
- [Timeout, BadTabList]),
- wait_for_tables(BadTabList, Timeout, Attempts-1);
- {error, Reason} ->
- error("Mnesia failed to load the some or all of the following"
- "tables:~n~p", [Tables]),
- {error, Reason}
- end.
-
-%%----------------------------------------------------------------------
-%% function : unique/1
-%% Arguments: List - [term()]
-%% Returns : [term()]
-%% Exception:
-%% Effect : Remove all duplicates from the list.
-%%----------------------------------------------------------------------
-unique([]) -> [];
-unique(List) ->
- Sorted = lists:sort(List),
- unique(hd(Sorted),
- tl(Sorted), []).
-
-unique(A, [A|R], Acc) ->
- unique(A, R, Acc);
-unique(A, [B|R], Acc) ->
- unique(B, R, [A|Acc]);
-unique(A, [], Acc) ->
- lists:reverse([A|Acc]).
-
-
-%%----------------------------------------------------------------------
-%% function : info/2
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%----------------------------------------------------------------------
-info(Format, Args) ->
- catch error_logger:info_msg("=================== Orber =================~n"++
- Format++
- "~n===========================================~n",
- Args).
-
-%%----------------------------------------------------------------------
-%% function : error/2
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%----------------------------------------------------------------------
-error(Format, Args) ->
- catch error_logger:error_msg("=================== Orber =================~n"++
- Format++
- "~n===========================================~n",
- Args).
-
-
-
-
-
-%%----------------------------------------------------------------------
-%% function : check_illegal_tcp_options/1
-%% Arguments:
-%% Returns :
-%% Exception:
-%% Effect :
-%%----------------------------------------------------------------------
-check_illegal_tcp_options(Options) ->
- check_illegal_tcp_options(Options, []).
-
-check_illegal_tcp_options([],[]) ->
- ok;
-check_illegal_tcp_options([],IllegalOpts) ->
- {error, IllegalOpts};
-check_illegal_tcp_options([{active, V} |T], IllegalOpts) ->
- check_illegal_tcp_options(T,[{active, V} |IllegalOpts]);
-check_illegal_tcp_options([{packet, V} |T], IllegalOpts) ->
- check_illegal_tcp_options(T,[{packet, V} |IllegalOpts]);
-check_illegal_tcp_options([{mode, V} |T], IllegalOpts) ->
- check_illegal_tcp_options(T,[{mode, V} |IllegalOpts]);
-check_illegal_tcp_options([list |T], IllegalOpts) ->
- check_illegal_tcp_options(T,[list |IllegalOpts]);
-check_illegal_tcp_options([binary |T], IllegalOpts) ->
- check_illegal_tcp_options(T,[binary |IllegalOpts]);
-check_illegal_tcp_options([{reuseaddr, V} |T], IllegalOpts) ->
- check_illegal_tcp_options(T,[{reuseaddr, V} |IllegalOpts]);
-check_illegal_tcp_options([_H|T], IllegalOpts) ->
- check_illegal_tcp_options(T, IllegalOpts).
-
-%%----------------------------------------------------------------------
-%% Internal functions
-%%----------------------------------------------------------------------
-
-%%----------------------------------------------------------------------
-%%------------- END OF MODULE ------------------------------------------
-%%----------------------------------------------------------------------
diff --git a/lib/orber/src/orber_tc.erl b/lib/orber/src/orber_tc.erl
deleted file mode 100644
index 9a8a9259ed..0000000000
--- a/lib/orber/src/orber_tc.erl
+++ /dev/null
@@ -1,284 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: orber_tc.erl
-%% Description:
-%% This file contains utility functions to create TypeCodes
-%%
-%%-----------------------------------------------------------------
--module(orber_tc).
-
--include_lib("orber/include/ifr_types.hrl").
--include_lib("orber/include/corba.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([null/0, void/0, short/0, unsigned_short/0,
- long/0, longdouble/0, unsigned_long/0, long_long/0,
- unsigned_long_long/0, float/0, double/0,
- boolean/0, char/0, wchar/0, octet/0, any/0,
- typecode/0, principal/0,
- object_reference/2, struct/3,
- union/5, enum/3,
- string/1, wstring/1, sequence/2, array/2, alias/3,
- exception/3, fixed/2, value/5, value_box/3, native/2, abstract_interface/2,
- get_tc/1, check_tc/1]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-%%-----------------------------------------------------------------
-%% External interface functions
-%%-----------------------------------------------------------------
-
-%%-----------------------------------------------------------------
-%% Macros
-%%-----------------------------------------------------------------
--define(DEBUG_LEVEL, 5).
-
-%%-----------------------------------------------------------------
-%% A number of function which can be used to create TypeCodes
-null() ->
- tk_null.
-void() ->
- tk_void.
-short() ->
- tk_short.
-unsigned_short() ->
- tk_ushort.
-long() ->
- tk_long.
-unsigned_long() ->
- tk_ulong.
-long_long() ->
- tk_longlong.
-unsigned_long_long() ->
- tk_ulonglong.
-float() ->
- tk_float.
-double() ->
- tk_double.
-longdouble() ->
- tk_longdouble.
-
-boolean() ->
- tk_boolean.
-char() ->
- tk_char.
-wchar() ->
- tk_wchar.
-octet() ->
- tk_octet.
-any() ->
- tk_any.
-typecode() ->
- tk_TypeCode.
-principal() ->
- tk_Principal.
-
-object_reference(Id, Name) ->
- {tk_objref, Id, Name}.
-
-struct(Id, Name, ElementList) ->
- {tk_struct, Id, Name, ElementList}.
-
-union(Id, Name, DiscrTC, Default, ElementList) ->
- {tk_union, Id, Name, DiscrTC, Default, ElementList}.
-
-enum(Id, Name, ElementList) ->
- {tk_enum, Id, Name, ElementList}.
-
-string(Length) ->
- {tk_string, Length}.
-
-wstring(Length) ->
- {tk_wstring, Length}.
-
-sequence(ElemTC, Length) ->
- {tk_sequence, ElemTC, Length}.
-
-array(ElemTC, Length) ->
- {tk_array, ElemTC, Length}.
-
-alias(Id, Name, TC) ->
- {tk_alias, Id, Name, TC}.
-
-exception(Id, Name, ElementList) ->
- {tk_except, Id, Name, ElementList}.
-
-fixed(Digits, Scale) ->
- {tk_fixed, Digits, Scale}.
-
-value(RepId, Name, ValueModifier, TC, ElementList) ->
- {tk_value, RepId, Name, ValueModifier, TC, ElementList}.
-
-value_box(RepId, Name, TC) ->
- {tk_value_box, RepId, Name, TC}.
-
-native(RepId, Name) ->
- {tk_native, RepId, Name}.
-
-abstract_interface(RepId, Name) ->
- {tk_abstract_interface, RepId, Name}.
-
-
-%%-----------------------------------------------------------------
-%% Get TypeCode (can be used for constructed types like structs,
-%% unions and exceptions)
-%%
-get_tc(T) when is_tuple(T) ->
- Type = element(1, T),
- case catch Type:tc() of
- {'EXIT', R} ->
- orber:dbg("[~p] ~p:get_tc(~p); Exit: ~p",
- [?LINE, ?MODULE, T, R], ?DEBUG_LEVEL),
- corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO});
- X ->
- X
- end;
-%% This call can be used if one have the IFR id and wants a typecode.
-get_tc(IFRId) when is_list(IFRId) ->
- Rep = orber_ifr:find_repository(),
- Def = orber_ifr:lookup_id(Rep, IFRId),
- Descr = orber_ifr:describe(Def),
- TypeDescr = Descr#contained_description.value,
- TypeDescr#typedescription.type.
-
-
-%%-----------------------------------------------------------------
-%% Check TypeCode format
-%%
-check_tc('tk_null') -> true;
-check_tc('tk_void') -> true;
-check_tc('tk_short') -> true;
-check_tc('tk_ushort') -> true;
-check_tc('tk_long') -> true;
-check_tc('tk_ulong') -> true;
-check_tc('tk_longlong') -> true;
-check_tc('tk_ulonglong') -> true;
-check_tc('tk_float') -> true;
-check_tc('tk_double') -> true;
-check_tc('tk_longdouble') -> true;
-check_tc('tk_boolean') -> true;
-check_tc('tk_char') -> true;
-check_tc('tk_wchar') -> true;
-check_tc('tk_octet') -> true;
-check_tc('tk_any') -> true;
-check_tc('tk_TypeCode') -> true;
-check_tc('tk_Principal') -> true;
-check_tc({'tk_objref', RepId, Name}) when is_list(RepId) andalso
- is_list(Name) -> true;
-check_tc({'tk_struct', RepId, Name, ElementList}) when is_list(RepId) andalso
- is_list(Name) ->
- Fun = fun(X) ->
- case X of
- {MemberName, MemberTC} when is_list(MemberName) ->
- check_tc(MemberTC);
- _ ->
- false
- end
- end,
- lists:all(Fun, ElementList);
-check_tc({'tk_union', RepId, Name, DiscrTC,
- Default, ElementList}) when is_list(RepId) andalso
- is_list(Name) andalso
- is_integer(Default) ->
- case check_tc(DiscrTC) of
- false ->
- false;
- true ->
- Fun = fun(X) ->
- case X of
- {_, MemberName, MemberTC} when
- is_list(MemberName) ->
- check_tc(MemberTC);
- _ ->
- false
- end
- end,
- lists:all(Fun, ElementList)
- end;
-check_tc({'tk_enum', RepId, Name, ElementList}) when is_list(RepId) andalso
- is_list(Name) ->
- Fun = fun(X) ->
- if
- is_list(X) ->
- true;
- true ->
- false
- end
- end,
- lists:all(Fun, ElementList);
-check_tc({'tk_string', MaxLength}) when is_integer(MaxLength) -> true;
-check_tc({'tk_wstring', MaxLength}) when is_integer(MaxLength) -> true;
-check_tc({'tk_fixed', Digits, Scale}) when is_integer(Digits) andalso
- is_integer(Scale) -> true;
-check_tc({'tk_sequence', ElemTC, MaxLength}) when is_integer(MaxLength) ->
- check_tc(ElemTC);
-check_tc({'tk_array', ElemTC, Length}) when is_integer(Length) ->
- check_tc(ElemTC);
-check_tc({'tk_alias', RepId, Name, TC}) when is_list(RepId) andalso
- is_list(Name) ->
- check_tc(TC);
-check_tc({'tk_except', RepId, Name, ElementList}) when is_list(RepId) andalso
- is_list(Name) ->
- Fun = fun(X) ->
- case X of
- {MemberName, TC} when is_list(MemberName) ->
- check_tc(TC);
- _ ->
- false
- end
- end,
- lists:all(Fun, ElementList);
-check_tc({'tk_value', RepId, Name, ValueModifier,
- TC, ElementList}) when is_list(RepId) andalso
- is_list(Name) andalso
- is_integer(ValueModifier) ->
- case check_tc(TC) of
- false ->
- false;
- true ->
- Fun = fun(X) ->
- case X of
- {MemberName, MemberTC, Visibility} when
- is_list(MemberName) andalso is_integer(Visibility) ->
- check_tc(MemberTC);
- _ ->
- false
- end
- end,
- lists:all(Fun, ElementList)
- end;
-check_tc({'tk_value_box', RepId, Name, TC}) when is_list(RepId) andalso
- is_list(Name) ->
- check_tc(TC);
-check_tc({'tk_native', RepId, Name}) when is_list(RepId) andalso
- is_list(Name) -> true;
-check_tc({'tk_abstract_interface', RepId, Name}) when is_list(RepId) andalso
- is_list(Name) -> true;
-check_tc({'none', Indirection}) when is_integer(Indirection) -> true;
-check_tc(_) -> false.
-
diff --git a/lib/orber/src/orber_typedefs.erl b/lib/orber/src/orber_typedefs.erl
deleted file mode 100644
index 30c03974c2..0000000000
--- a/lib/orber/src/orber_typedefs.erl
+++ /dev/null
@@ -1,83 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File: orber_typedefs.erl
-%% Description:
-%% This file contains some functions for internal typedef checking
-%%
-%%-----------------------------------------------------------------
--module(orber_typedefs).
-
--include("orber_iiop.hrl").
--include_lib("orber/include/corba.hrl").
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([get_op_def/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
--define(DEBUG_LEVEL, 5).
-
-%%-----------------------------------------------------------------
-%% External interface functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: get_op_def/2
-%%
-get_op_def(_Objkey, '_is_a') ->
- {orber_tc:boolean(),[orber_tc:string(0)],[]};
-%% First the OMG specified this operation to be '_not_existent' and then
-%% changed it to '_non_existent' without suggesting that both must be supported.
-%% See CORBA2.3.1 page 15-34, Minor revision 2.3.1: October 1999
-get_op_def(_Objkey, '_not_existent') ->
- {orber_tc:boolean(),[],[]};
-get_op_def(_Objkey, '_non_existent') ->
- {orber_tc:boolean(),[],[]};
-%% Defined in the Fault Tolerant section of the CORBA specification.
-get_op_def(_Objkey, '_FT_HB') ->
- {orber_tc:void(),[],[]};
-get_op_def(Objkey, Op) ->
- case catch iop_ior:get_key(Objkey) of
- {_Local, _Key, _, _, Module} ->
- case catch Module:oe_tc(Op) of
- {'EXIT', What} ->
- orber:dbg("[~p] orber_typedefs:get_op_def(~p);~n"
- "The call-back module does not exist or incorrect~n"
- "IC-version used. Reason:~n~p",
- [?LINE, Module, What], ?DEBUG_LEVEL),
- corba:raise(#'TRANSIENT'{minor=(?ORBER_VMCID bor 7),
- completion_status=?COMPLETED_NO});
- undefined ->
- corba:raise(#'BAD_OPERATION'{minor = (?ORBER_VMCID bor 4),
- completion_status=?COMPLETED_NO});
- TC ->
- TC
- end;
- _ ->
- corba:raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO})
- end.
-
diff --git a/lib/orber/src/orber_web.erl b/lib/orber/src/orber_web.erl
deleted file mode 100644
index cc24b2cb19..0000000000
--- a/lib/orber/src/orber_web.erl
+++ /dev/null
@@ -1,864 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_web.erl
-%% Purpose :
-%%----------------------------------------------------------------------
-
--module(orber_web).
-
--export([menu/2,
- configure/2,
- info/2,
- nameservice/2,
- ifr_select/2,
- ifr_data/2,
- create/2,
- delete_ctx/2,
- add_ctx/2,
- delete_obj/2]).
-
-%%----------------------------------------------------------------------
-%%-------------- Defines & Includes ------------------------------------
-%%----------------------------------------------------------------------
-
--include("ifr_objects.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming_NamingContext.hrl").
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
-
--define(DEBUG_LEVEL, 5).
-
--define(INFO_DATA,
- [{iiop_timeout, "IIOP Request Timeout"},
- {iiop_connection_timeout, "IIOP Connection Timeout"},
- {iiop_setup_connection_timeout, "IIOP Setup Connection Timeout"},
- {iiop_port, "IIOP Port"},
- {domain, "Orber Domain"},
- {orber_nodes, "Nodes in Domain"},
- {giop_version, "Default GIOP Version"},
- {objectkeys_gc_time, "Objectkeys GC"},
- {get_interceptors, "Using Interceptors"},
- {get_debug_level, "Debug Level"},
- {get_ORBInitRef, "ORBInitRef"},
- {get_ORBDefaultInitRef, "ORBDefaultInitRef"}]).
-
--define(IFR_DATA, [{"ir_ModuleDef", "Modules"},
- {"ir_InterfaceDef", "Interfaces"},
- {"ir_StructDef", "Structs"},
- {"ir_UnionDef", "Unions"},
- {"ir_ExceptionDef", "Exceptions"},
- {"ir_ConstantDef", "Constants"},
- {"ir_EnumDef", "Enumerants"},
- {"ir_AliasDef", "Aliases"},
- {"ir_AttributeDef", "Attributes"},
- {"ir_OperationDef", "Operations"},
- {"ir_Contained", "Contained"},
- {"ir_TypedefDef", "Typedef"}]).
-
-
-%%----------------------------------------------------------------------
-%%-------------- External API ------------------------------------------
-%%----------------------------------------------------------------------
-%% Function : create
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-create(_Env, [{"node",NodeStr}]) ->
- Node = list_to_atom(NodeStr),
- is_running(Node, NodeStr),
- ["<BODY BGCOLOR=\"#FFFFFF\">
- <TABLE border=0 BGCOLOR=\"#FFFFFF\">
- <TD ALIGN=\"center\" COLSPAN=2><FONT SIZE=6>Create a New Object</FONT></TD></TR>
- <TR><TD><FORM METHOD=\"POST\" ACTION=\"./create\">
- <TR><TD><INPUT TYPE=\"HIDDEN\" NAME=\"node\" VALUE=\"", NodeStr, "\">
- <TR><TD><B>Module</B></TD><TD><INPUT TYPE=\"TEXT\" SIZE=\"50\" NAME=\"module\" VALUE=\"\"></TD></TR>
- <TR><TD><B>Arguments</B></TD><TD><INPUT TYPE=\"TEXT\" SIZE=\"50\" NAME=\"arguments\"></TD></TR>
- <TR><TD><B>Options</B></TD><TD><INPUT TYPE=\"TEXT\" SIZE=\"50\" NAME=\"options\"></TD></TR>
- <TR><TD><B>Name String</B></TD><TD><INPUT TYPE=\"TEXT\" SIZE=\"50\" NAME=\"namestr\"></TD></TR>
- <TR><TD><B>Operation to use</B></TD>
- <TD><B>&nbsp;&nbsp;&nbsp;<INPUT type=\"radio\" name=\"bind\" value=\"bind\" CHECKED=\"true\">Bind</B>
- <B>&nbsp;&nbsp;&nbsp;<INPUT type=\"radio\" name=\"bind\" value=\"rebind\">Rebind</B></TD></TR>
- <TR><TD ALIGN=\"center\" COLSPAN=2><INPUT TYPE=\"SUBMIT\" VALUE=\"Create it\"></FORM></TD></TR></TABLE>"];
-create(_Env, [{"node",NodeStr}, {"module", ModStr}, {"arguments",ArgsStr},
- {"options",OptionsStr}, {"namestr", Name}, {"bind", How}]) ->
- Node = list_to_atom(NodeStr),
- Mod = list_to_atom(ModStr),
- Args = parse_data(ArgsStr),
- Options = parse_data(OptionsStr),
- case catch rpc:call(Node, Mod, oe_create, [Args, [{sup_child, true}|Options]]) of
- {ok, Pid, Object} ->
- case catch bind(Node, Object, Name, How) of
- {ok, IOR} ->
- ["<BODY BGCOLOR=\"#FFFFFF\"><BR><B>Successfully created the object:</B><BR><BR>", IOR];
- {ok, IOR, Path} ->
- ["<BODY BGCOLOR=\"#FFFFFF\"><BR><B>Successfully created and stored the object as: \"",
- Path, "\" (", pid_to_list(Pid), ")</B><BR><BR>", IOR];
- What ->
- rpc:call(Node, corba, dispose, [Object]),
- orber:dbg("[~p] orber_web:create(~p, ~p, ~p, ~p, ~p);
-Unable to bind object: ~p", [?LINE, Node, Mod, Args, Options, Name, What], ?DEBUG_LEVEL),
- ["<BODY BGCOLOR=\"#FFFFFF\">Unable to bind object in the NameService using: ", Name]
- end;
- Object when element(2, Object) == pseudo ->
- case catch bind(Node, Object, Name, How) of
- {ok, IOR} ->
- ["<BODY BGCOLOR=\"#FFFFFF\"><BR><B>Successfully created the object:</B><BR><BR>", IOR];
- {ok, IOR, _} ->
- ["<BODY BGCOLOR=\"#FFFFFF\"><BR><B>Successfully created and stored the object as :\"", Name, "\"</B><BR><BR>", IOR];
- What ->
- rpc:call(Node, corba, dispose, [Object]),
- orber:dbg("[~p] orber_web:create(~p, ~p, ~p, ~p, ~p);
-Unable to bind object: ~p", [?LINE, Node, Mod, Args, Options, Name, What], ?DEBUG_LEVEL),
- ["<BODY BGCOLOR=\"#FFFFFF\">Unable to bind object in the NameService using: ", Name]
- end;
- What->
- orber:dbg("[~p] orber_web:create(~p, ~p, ~p, ~p, ~p);
-Unable to create object: ~p", [?LINE, Node, Mod, Args, Options, Name, What], ?DEBUG_LEVEL),
- ["<BODY BGCOLOR=\"#FFFFFF\">Unable to create the object."]
- end.
-
-bind(Node, Obj, "", _) ->
- IOR = rpc:call(Node, corba, object_to_string, [Obj]),
- {ok, IOR};
-bind(Node, Obj, NameStr, How) ->
- NS = check(rpc:call(Node, corba, resolve_initial_references, ["NameService"])),
- Name = check(rpc:call(Node, 'CosNaming_NamingContextExt', to_name, [NS, NameStr])),
- case How of
- "bind" ->
- check(rpc:call(Node, 'CosNaming_NamingContext', bind, [NS, Name, Obj])),
- IOR = rpc:call(Node, corba, object_to_string, [Obj]),
- {ok, IOR, NameStr};
- "rebind" ->
- check(rpc:call(Node, 'CosNaming_NamingContext', rebind, [NS, Name, Obj])),
- IOR = rpc:call(Node, corba, object_to_string, [Obj]),
- {ok, IOR, NameStr}
- end.
-
-
-%%----------------------------------------------------------------------
-%% Function : delete_ctx
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-delete_ctx(_Env, [{"node",NodeStr}, {"context", Ref}]) ->
- Node = list_to_atom(NodeStr),
- {Ctx, NS} = remote_resolve(Node, Ref),
- Name = check(rpc:call(Node, 'CosNaming_NamingContextExt', to_name, [NS, Ref])),
- check(rpc:call(Node, 'CosNaming_NamingContextExt', unbind, [NS, Name])),
- check(rpc:call(Node, 'CosNaming_NamingContextExt', destroy, [Ctx])),
- ["<BODY BGCOLOR=\"#FFFFFF\">
- <TABLE BORDER=0><TR BGCOLOR=\"#FFFFFF\"><TD ALIGN=\"center\" COLSPAN=1>
- <FONT SIZE=6>Successfully deleted the Context: ", Ref, "</FONT>\n
- </TD></TR></TABLE>
- <FORM Name=goback><INPUT TYPE=\"button\" onClick=javascript:history.go(-2) VALUE=\"Go Back\">\n</FORM>"].
-
-%%----------------------------------------------------------------------
-%% Function : add_ctx
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-add_ctx(_Env, [{"node",_NodeStr}, {"context", "root"}, {"id", ""}]) ->
- ["<BODY BGCOLOR=\"#FFFFFF\">
- <TABLE BORDER=0><TR BGCOLOR=\"#FFFFFF\"><TD ALIGN=\"center\" COLSPAN=1>
- <FONT SIZE=4>You must supply a NameString such as:<BR>
- See also 'Interoperable Naming Service' in the User's Guide.</FONT>\n
- </TD></TR></TABLE>
- <FORM Name=goback><INPUT TYPE=\"button\" onClick=javascript:history.go(-1) VALUE=\"Go Back\">\n</FORM>"];
-add_ctx(_Env, [{"node",NodeStr}, {"context", "root"}, {"id", Id}]) ->
- Node = list_to_atom(NodeStr),
- NS = check(rpc:call(Node, corba, resolve_initial_references, ["NameService"])),
- Name = check(rpc:call(Node, 'CosNaming_NamingContextExt', to_name, [NS, Id])),
- check(rpc:call(Node, 'CosNaming_NamingContextExt', bind_new_context, [NS, Name])),
- ["<BODY BGCOLOR=\"#FFFFFF\">
- <TABLE BORDER=0><TR BGCOLOR=\"#FFFFFF\"><TD ALIGN=\"center\" COLSPAN=1>
- <FONT SIZE=6>Successfully bound the new Context: ", Id, "</FONT>\n
- </TD></TR></TABLE>
- <FORM Name=goback><INPUT TYPE=\"button\" onClick=javascript:history.go(-1) VALUE=\"Go Back\">\n</FORM>"];
-add_ctx(_Env, [{"node",NodeStr}, {"context", Ref}, {"id", Id}]) ->
- NameStr = Ref ++ "/" ++ Id,
- Node = list_to_atom(NodeStr),
- NS = check(rpc:call(Node, corba, resolve_initial_references, ["NameService"])),
- Name = check(rpc:call(Node, 'CosNaming_NamingContextExt', to_name, [NS, NameStr])),
- check(rpc:call(Node, 'CosNaming_NamingContextExt', bind_new_context, [NS, Name])),
- ["<BODY BGCOLOR=\"#FFFFFF\">
- <TABLE BORDER=0><TR BGCOLOR=\"#FFFFFF\"><TD ALIGN=\"center\" COLSPAN=1>
- <FONT SIZE=6>Successfully bound the new Context: ", NameStr, "</FONT>\n
- </TD></TR></TABLE>
- <FORM Name=goback><INPUT TYPE=\"button\" onClick=javascript:history.go(-1) VALUE=\"Go Back\">\n</FORM>"].
-
-%%----------------------------------------------------------------------
-%% Function : delete_obj
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-delete_obj(_Env, [{"node",NodeStr}, {"context", Ref}, {"action", "unbind"}]) ->
- Node = list_to_atom(NodeStr),
- NS = check(rpc:call(Node, corba, resolve_initial_references, ["NameService"])),
- Name = check(rpc:call(Node, 'CosNaming_NamingContextExt', to_name, [NS, Ref])),
- check(rpc:call(Node, 'CosNaming_NamingContextExt', unbind, [NS, Name])),
- ["<BODY BGCOLOR=\"#FFFFFF\">
- <TABLE BORDER=0><TR BGCOLOR=\"#FFFFFF\"><TD ALIGN=\"center\" COLSPAN=1>
- <FONT SIZE=6>Successfully unbound the Object: ", Ref, "</FONT>\n
- </TD></TR></TABLE>
- <FORM Name=goback><INPUT TYPE=\"button\" onClick=javascript:history.go(-2) VALUE=\"Go Back\">\n</FORM>"];
-delete_obj(_Env, [{"node",NodeStr}, {"context", Ref}, {"action", "both"}]) ->
- Node = list_to_atom(NodeStr),
- {Obj, NS} = remote_resolve(Node, Ref),
- check(rpc:call(Node, corba, dispose, [Obj])),
- Name = check(rpc:call(Node, 'CosNaming_NamingContextExt', to_name, [NS, Ref])),
- check(rpc:call(Node, 'CosNaming_NamingContextExt', unbind, [NS, Name])),
- ["<BODY BGCOLOR=\"#FFFFFF\">
- <TABLE BORDER=0><TR BGCOLOR=\"#FFFFFF\"><TD ALIGN=\"center\" COLSPAN=1>
- <FONT SIZE=6>Successfully disposed an unbound the Object: ", Ref, "</FONT>\n
- </TD></TR></TABLE>
- <FORM Name=goback><INPUT TYPE=\"button\" onClick=javascript:history.go(-2) VALUE=\"Go Back\">\n</FORM>"].
-
-
-
-%%----------------------------------------------------------------------
-%% Function : nameservice
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-nameservice(_Env, [{"node",NodeStr}, {"context", "root"}]) ->
- Node = list_to_atom(NodeStr),
- is_running(Node, NodeStr),
- Object = check(rpc:call(Node, corba, resolve_initial_references, ["NameService"])),
- Prefix = "<TR><TD><A HREF=\"./nameservice?node=" ++ NodeStr ++ "&context=",
- case catch create_context_list(Node, NodeStr, Prefix, Object, "root") of
- {ok, Data} ->
- ["<BODY BGCOLOR=\"#FFFFFF\">
- <TABLE BORDER=0><TR BGCOLOR=\"#FFFFFF\"><TD ALIGN=\"center\" COLSPAN=2>
- <FONT SIZE=6>NameService</FONT>\n
- </TD></TR><TR BGCOLOR=\"#FFFF00\"><TD ALIGN=\"center\" COLSPAN=2>
- <FONT SIZE=4>Root Context</FONT>\n
- </TD></TR>", Data,
- "<TR><TD><FORM Name=addctx METHOD=\"POST\" ACTION=\"./add_ctx\">
- <INPUT TYPE=\"HIDDEN\" NAME=\"node\" VALUE=\"", NodeStr, "\">
- <INPUT TYPE=\"HIDDEN\" NAME=\"context\" VALUE=\"root\">
- <INPUT TYPE=\"TEXT\" SIZE=\"20\" NAME=\"id\"></TD>
- <TD><INPUT TYPE=\"SUBMIT\" VALUE=\"New Context\"></TD></FORM></TR></TABLE>"];
- Why ->
- orber:dbg("[~p] orber_web:nameservice(~p, root);
-Unable to create context list: ~p", [?LINE, NodeStr, Why], ?DEBUG_LEVEL),
- throw({error, "<BODY BGCOLOR=\"#FFFFFF\">Unable to create a look up the Root Context data"})
- end;
-nameservice(_Env, [{"node",NodeStr}, {"context", Ref}]) ->
- Node = list_to_atom(NodeStr),
- {Object, _NS} = remote_resolve(Node, Ref),
- Prefix = "<TR><TD><A HREF=\"./nameservice?node=" ++ NodeStr ++ "&context="++Ref++"/",
- case catch create_context_list(Node, NodeStr, Prefix, Object, Ref) of
- {ok, Data} ->
- ["<BODY BGCOLOR=\"#FFFFFF\">
- <TABLE BORDER=0><TR BGCOLOR=\"#FFFFFF\"><TD ALIGN=\"center\" COLSPAN=2>
- <FONT SIZE=6>NameService</FONT></TD></TR>
- <TR BGCOLOR=\"#FFFF00\"><TD ALIGN=\"center\" COLSPAN=2>
- <FONT SIZE=4>", Ref, "</FONT></TD></TR>", Data,
- "<TR><TD><FORM Name=addctx METHOD=\"POST\" ACTION=\"./add_ctx\">
- <INPUT TYPE=\"HIDDEN\" NAME=\"node\" VALUE=\"", NodeStr, "\">
- <INPUT TYPE=\"HIDDEN\" NAME=\"context\" VALUE=\"", Ref, "\">
- <INPUT TYPE=\"TEXT\" SIZE=\"20\" NAME=\"id\"></TD>
- <TD><INPUT TYPE=\"SUBMIT\" VALUE=\"New Context\"></TD></FORM></TR>
- </TABLE>
- <FORM Name=goback><INPUT TYPE=\"button\" onClick=javascript:history.go(-1) VALUE=\"Go Back\"></FORM></TD>"];
- Why ->
- orber:dbg("[~p] orber_web:nameservice(~p, ~p);
-Unable to create context list: ~p", [?LINE, NodeStr, Ref, Why], ?DEBUG_LEVEL),
- throw({error, ["<BODY BGCOLOR=\"#FFFFFF\">Unable to look up the Context: ", Ref,
- "<BR><BR>If You just deleted it, use the 'Go Back' button next time."]})
- end;
-nameservice(_Env, [{"node",NodeStr}, {"context", Ref}, {"object", Obj}]) ->
- case catch create_object_data(NodeStr, Ref, Obj) of
- {ok, Data} ->
- Data;
- Why ->
- orber:dbg("[~p] orber_web:nameservice(~p, ~p, ~p);
-Unable to create data for object: ~p", [?LINE, NodeStr, Ref, Obj, Why], ?DEBUG_LEVEL),
- throw({error, ["<BODY BGCOLOR=\"#FFFFFF\">Unable to look up the Object stored as: ", Ref,
- "<BR><BR>If You just unbound it, use the 'Go Back' button next time."]})
- end.
-
-create_context_list(Node, NodeStr, Prefix, Object, Ref) ->
- case check(rpc:call(Node, 'CosNaming_NamingContext', list, [Object, 100])) of
- {ok, [], BI} when Ref == "root" ->
- catch rpc:call(Node, 'CosNaming_BindingIterator', destroy, [BI]),
- {ok, "<TR><TD ALIGN=\"center\" COLSPAN=2><FONT SIZE=3><B>EMPTY<B></FONT></TD></TR>"};
- {ok, [], BI} ->
- catch rpc:call(Node, 'CosNaming_BindingIterator', destroy, [BI]),
- {ok, "<TR><TD ALIGN=\"center\"><FONT SIZE=3><B>EMPTY<B></FONT></TD>
- <TD ALIGN=\"center\"><FORM Name=deletectx METHOD=\"POST\" ACTION=\"./delete_ctx\">
- <INPUT TYPE=\"HIDDEN\" NAME=\"node\" VALUE=\"" ++ NodeStr ++ "\">
- <INPUT TYPE=\"HIDDEN\" NAME=\"context\" VALUE=\"" ++ Ref ++ "\">
- <INPUT TYPE=\"SUBMIT\" VALUE=\"Delete Context\"></FORM></TD></TR>"};
- {ok, BL, BI} when length(BL) < 100 ->
- catch rpc:call(Node, 'CosNaming_BindingIterator', destroy, [BI]),
- {ok, convert_contexts(BL, [], Prefix, Object, Node)};
- {ok, BL, BI} ->
- Data = convert_contexts(BL, [], Prefix, Object, Node),
- {ok, create_context_list_helper(Node, BI, Data, Object, Prefix)}
- end.
-
-create_context_list_helper(Node, BI, Acc, Ctx, Prefix) ->
- case check(rpc:call(Node, 'CosNaming_BindingIterator', next_n, [BI, 100])) of
- {true, BL} ->
- NewAcc = convert_contexts(BL, Acc, Prefix, Ctx, Node),
- create_context_list_helper(Node, BI, NewAcc, Ctx, Prefix);
- {false, BL} ->
- catch rpc:call(Node, 'CosNaming_BindingIterator', destroy, [BI]),
- convert_contexts(BL, Acc, Prefix, Ctx, Node)
- end.
-
-convert_contexts([], Acc, _Prefix, _Ctx, _Node) ->
- Acc;
-convert_contexts([#'CosNaming_Binding'{binding_name = Name,
- binding_type = ncontext}|T],
- Acc, Prefix, Ctx, Node) ->
- NameStr = check(rpc:call(Node, 'CosNaming_NamingContextExt', to_string, [Ctx, Name])),
- convert_contexts(T, [Prefix, NameStr, "\" TARGET=main><B>", NameStr, "</B></A></TD><TD><B>ncontext</B></TD></TR>"|Acc],
- Prefix, Ctx, Node);
-convert_contexts([#'CosNaming_Binding'{binding_name = Name,
- binding_type = nobject}|T],
- Acc, Prefix, Ctx, Node) ->
- NameStr = check(rpc:call(Node, 'CosNaming_NamingContextExt', to_string, [Ctx, Name])),
- convert_contexts(T, [Prefix, NameStr, "&object=o \" TARGET=main><B>", NameStr, "</B></A></TD><TD><B>nobject</B></A></TD></TR>"|Acc],
- Prefix, Ctx, Node).
-
-
-create_object_data(NodeStr, Ref, _Obj) ->
- Node = list_to_atom(NodeStr),
- {Object, _NS} = remote_resolve(Node, Ref),
- LongIORStr = check(rpc:call(Node, corba, object_to_string, [Object])),
- IFRId = check(rpc:call(Node, iop_ior, get_typeID, [Object])),
- Exists = check(rpc:call(Node, corba_object, non_existent, [Object])),
- IORStr = split_IOR(1, LongIORStr, []),
- {Data, External}
- = case rpc:call(Node, iop_ior, get_key, [Object]) of
- {external, {Host, Port, _OK, _, _, #host_data{version = {Ma, Mi}}}} ->
- {[{"IFR Id", IFRId},
- {"Stored As", Ref},
- {"External Object", "true"},
- {"Non Existent", atom_to_list(Exists)},
- {"Host", Host},
- {"Port", integer_to_list(Port)},
- {"IIOP Version", integer_to_list(Ma) ++"."++ integer_to_list(Mi)},
- {"IOR String", IORStr}], true};
- {'internal', _Key, _, _, _} ->
- Pid = check(rpc:call(Node, corba, get_pid, [Object])),
- Interface = check(rpc:call(Node, corba, request_from_iiop,
- [Object, oe_get_interface, false, false, false, []])),
- InterfaceData = parse_interface(Interface, []),
- {[{"IFR Id", IFRId},
- {"Stored As", Ref},
- {"External Object", "false"},
- {"Non Existent", atom_to_list(Exists)},
- {"Pid", pid_to_list(Pid)},
- {"IOR String", IORStr}|InterfaceData], false};
- {'internal_registered', {pseudo, Key}, _, _, _} ->
- Interface = check(rpc:call(Node, corba, request_from_iiop,
- [Object, oe_get_interface, false, false, false, []])),
- InterfaceData = parse_interface(Interface, []),
- {[{"IFR Id", IFRId},
- {"Stored As", Ref},
- {"External Object", "false"},
- {"Non Existent", atom_to_list(Exists)},
- {"Pseudo Object", atom_to_list(Key)},
- {"IOR", IORStr}|InterfaceData], false};
- {'internal_registered', Key, _, _, _} ->
- Pid = check(rpc:call(Node, corba, get_pid, [Object])),
- Interface = check(rpc:call(Node, corba, request_from_iiop,
- [Object, oe_get_interface, false, false, false, []])),
- InterfaceData = parse_interface(Interface, []),
- {[{"IFR Id", IFRId},
- {"Stored As", Ref},
- {"External Object", "false"},
- {"Non Existent", atom_to_list(Exists)},
- {"Locally Registered", atom_to_list(Key)},
- {"Pid", pid_to_list(Pid)},
- {"IOR String", IORStr}|InterfaceData], false}
- end,
- Buttons = case {Exists, External} of
- {false, false} ->
- ["<TABLE BORDER=0><TR BGCOLOR=\"#FFFFFF\"><TD ALIGN=\"center\">
- <TD><FORM Name=goback><INPUT TYPE=\"button\" onClick=javascript:history.go(-1) VALUE=\"Go Back\"></FORM></TD>
-
- <TD ALIGN=\"center\"><FORM Name=unbindobj METHOD=\"POST\" ACTION=\"./delete_obj\">
- <INPUT TYPE=\"HIDDEN\" NAME=\"node\" VALUE=\"", NodeStr, "\">
- <INPUT TYPE=\"HIDDEN\" NAME=\"context\" VALUE=\"", Ref, "\">
- <INPUT TYPE=\"HIDDEN\" NAME=\"action\" VALUE=\"unbind\">
- <INPUT TYPE=\"SUBMIT\" VALUE=\"Unbind\"></FORM></TD>
- <TD ALIGN=\"center\"><FORM Name=unbinddeletobj METHOD=\"POST\" ACTION=\"./delete_obj\">
- <INPUT TYPE=\"HIDDEN\" NAME=\"node\" VALUE=\"", NodeStr, "\">
- <INPUT TYPE=\"HIDDEN\" NAME=\"context\" VALUE=\"", Ref, "\">
- <INPUT TYPE=\"HIDDEN\" NAME=\"action\" VALUE=\"both\">
- <INPUT TYPE=\"SUBMIT\" VALUE=\"Unbind & Dispose\"></FORM></TD></TR></TABLE>"];
- _ ->
- ["<TABLE BORDER=0><TR BGCOLOR=\"#FFFFFF\"><TD ALIGN=\"center\">
- <TD><FORM Name=goback><INPUT TYPE=\"button\" onClick=javascript:history.go(-1) VALUE=\"Go Back\"></FORM></TD>
- <TD ALIGN=\"center\"><FORM Name=unbindobj METHOD=\"POST\" ACTION=\"./delete_obj\">
- <INPUT TYPE=\"HIDDEN\" NAME=\"node\" VALUE=\"", NodeStr, "\">
- <INPUT TYPE=\"HIDDEN\" NAME=\"context\" VALUE=\"", Ref, "\">
- <INPUT TYPE=\"HIDDEN\" NAME=\"action\" VALUE=\"unbind\">
- <INPUT TYPE=\"SUBMIT\" VALUE=\"Unbind\"></FORM></TD></TR></TABLE>"]
- end,
- {ok, ["<BODY BGCOLOR=\"#FFFFFF\">",
- simple_table("2", "NameService", [{"Key", "Value"}|Data]),
- Buttons]}.
-
-parse_interface([], [{_, Op}|Acc]) ->
- [{"Operations", Op}|Acc];
-parse_interface([], []) ->
- [{"Operations", "-"}];
-parse_interface([{Operation,{_,Args,_}}|T], Acc) ->
- parse_interface(T, [{"", Operation ++ "/" ++ integer_to_list(length(Args))}|Acc]).
-
-
-split_IOR(_, [], Acc) ->
- lists:reverse(Acc);
-split_IOR(50, Str, Acc) ->
- split_IOR(1, Str, ["<BR>"|Acc]);
-split_IOR(N, [H|T], Acc) ->
- split_IOR(N+1, T, [H|Acc]).
-
-
-
-%%----------------------------------------------------------------------
-%% Function : configure
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-configure(_Env, [{"node",NodeStr}, {"data", DataStr}]) ->
- Node = list_to_atom(NodeStr),
- Data = parse_data(DataStr),
- case catch rpc:call(Node, orber, multi_configure, [Data]) of
- ok ->
- "<BODY BGCOLOR=\"#FFFFFF\">Configuration successfull.";
- Why ->
- orber:dbg("[~p] orber_web:configure(~p, ~p);
-Unable to change configuration due to: ~p", [?LINE, NodeStr, DataStr, Why], ?DEBUG_LEVEL),
- "<BODY BGCOLOR=\"#FFFFFF\">Unable to change the configuration.<BR>
- Check the spelling and/or if it is possible to update all the keys if Orber is started."
- end.
-
-
-%%----------------------------------------------------------------------
-%% Function : ifr_select
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-ifr_select(_Env, [{"node",NodeStr}]) ->
- Node = list_to_atom(NodeStr),
- is_running(Node, NodeStr),
- ["<BODY BGCOLOR=\"#FFFFFF\">
- <TABLE BORDER=0><TR BGCOLOR=\"#FFFFFF\"><TD ALIGN=\"center\" COLSPAN=1>
- <FONT SIZE=6>Interface Repository</FONT>
- </TD></TR>", create_ifr_table(?IFR_DATA, NodeStr, []), "</TABLE>"].
-
-%%----------------------------------------------------------------------
-%% Function : ifr_data
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-ifr_data(_Env, [{"node",NodeStr}, {"table", TableStr}]) ->
- Node = list_to_atom(NodeStr),
- Table = list_to_atom(TableStr),
- WildPattern = get_wild_pattern(Table, Node),
- Records = check(rpc:call(Node, mnesia, dirty_match_object, [WildPattern])),
- Data = extract_ids(Records, []),
- ["<BODY BGCOLOR=\"#FFFFFF\">",
- simple_table("1", "Interface Repository", [TableStr|Data]),
- "<FORM Name=goback><INPUT TYPE=\"button\" onClick=javascript:history.go(-1) VALUE=\"Go Back\"></FORM>"].
-
-extract_ids([], Acc) ->
- lists:sort(Acc);
-extract_ids([#ir_ModuleDef{id=Id}|T], Acc) ->
- extract_ids(T, [Id|Acc]);
-extract_ids([#ir_InterfaceDef{id=Id}|T], Acc) ->
- extract_ids(T, [Id|Acc]);
-extract_ids([#ir_StructDef{id=Id}|T], Acc) ->
- extract_ids(T, [Id|Acc]);
-extract_ids([#ir_UnionDef{id=Id}|T], Acc) ->
- extract_ids(T, [Id|Acc]);
-extract_ids([#ir_ExceptionDef{id=Id}|T], Acc) ->
- extract_ids(T, [Id|Acc]);
-extract_ids([#ir_ConstantDef{id=Id}|T], Acc) ->
- extract_ids(T, [Id|Acc]);
-extract_ids([#ir_EnumDef{id=Id}|T], Acc) ->
- extract_ids(T, [Id|Acc]);
-extract_ids([#ir_AliasDef{id=Id}|T], Acc) ->
- extract_ids(T, [Id|Acc]);
-extract_ids([#ir_AttributeDef{id=Id}|T], Acc) ->
- extract_ids(T, [Id|Acc]);
-extract_ids([#ir_OperationDef{id=Id}|T], Acc) ->
- extract_ids(T, [Id|Acc]);
-extract_ids([#ir_Contained{id=Id}|T], Acc) ->
- extract_ids(T, [Id|Acc]);
-extract_ids([#ir_TypedefDef{id=Id}|T], Acc) ->
- extract_ids(T, [Id|Acc]).
-
-get_wild_pattern(ir_ModuleDef, Node) ->
- P = check(rpc:call(Node, mnesia, table_info, [ir_ModuleDef, wild_pattern])),
- P#ir_ModuleDef{id='$1'};
-get_wild_pattern(ir_InterfaceDef, Node) ->
- P = check(rpc:call(Node, mnesia, table_info, [ir_InterfaceDef, wild_pattern])),
- P#ir_InterfaceDef{id='$1'};
-get_wild_pattern(ir_StructDef, Node) ->
- P = check(rpc:call(Node, mnesia, table_info, [ir_StructDef, wild_pattern])),
- P#ir_StructDef{id='$1'};
-get_wild_pattern(ir_UnionDef, Node) ->
- P = check(rpc:call(Node, mnesia, table_info, [ir_UnionDef, wild_pattern])),
- P#ir_UnionDef{id='$1'};
-get_wild_pattern(ir_ExceptionDef, Node) ->
- P = check(rpc:call(Node, mnesia, table_info, [ir_ExceptionDef, wild_pattern])),
- P#ir_ExceptionDef{id='$1'};
-get_wild_pattern(ir_ConstantDef, Node) ->
- P = check(rpc:call(Node, mnesia, table_info, [ir_ConstantDef, wild_pattern])),
- P#ir_ConstantDef{id='$1'};
-get_wild_pattern(ir_EnumDef, Node) ->
- P = check(rpc:call(Node, mnesia, table_info, [ir_EnumDef, wild_pattern])),
- P#ir_EnumDef{id='$1'};
-get_wild_pattern(ir_AliasDef, Node) ->
- P = check(rpc:call(Node, mnesia, table_info, [ir_AliasDef, wild_pattern])),
- P#ir_AliasDef{id='$1'};
-get_wild_pattern(ir_AttributeDef, Node) ->
- P = check(rpc:call(Node, mnesia, table_info, [ir_AttributeDef, wild_pattern])),
- P#ir_AttributeDef{id='$1'};
-get_wild_pattern(ir_OperationDef, Node) ->
- P = check(rpc:call(Node, mnesia, table_info, [ir_OperationDef, wild_pattern])),
- P#ir_OperationDef{id='$1'};
-get_wild_pattern(ir_Contained, Node) ->
- P = check(rpc:call(Node, mnesia, table_info, [ir_Contained, wild_pattern])),
- P#ir_Contained{id='$1'};
-get_wild_pattern(ir_TypedefDef, Node) ->
- P = check(rpc:call(Node, mnesia, table_info, [ir_TypedefDef, wild_pattern])),
- P#ir_TypedefDef{id='$1'}.
-
-create_ifr_table([], _Node, Result) ->
- lists:append(lists:reverse(Result));
-create_ifr_table([{Table,Desc}|Rest], Node, Result) ->
- create_ifr_table(Rest, Node,
- ["<TR><TD><A HREF=\"./ifr_data?node=" ++ Node ++
- "&table="++Table++"\" TARGET=main><B>" ++ Desc ++"</B></A></TD></TR>"|Result]).
-
-
-%%----------------------------------------------------------------------
-%% Function : info
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-info(_Env, [{"node",NodeStr}]) ->
- Node = list_to_atom(NodeStr),
- is_running(Node, NodeStr),
- Data = create_info_data(?INFO_DATA, Node, []),
- ["<BODY BGCOLOR=\"#FFFFFF\">",
- simple_table("2", "Configuration", [{"Key", "Value"}|Data],
- ["<TR><TD><FORM METHOD=\"POST\" ACTION=\"./configure\">
- <INPUT TYPE=\"HIDDEN\" NAME=\"node\" VALUE=\"", NodeStr, "\">
- <INPUT TYPE=\"TEXT\" SIZE=\"35\" NAME=\"data\" VALUE=\"[{Key, Value}]\">
- </TD><TD><INPUT TYPE=\"SUBMIT\" VALUE=\"Change it\"></TD></FORM></TR>"])].
-
-
-create_info_data([], _Node, Result) ->
- lists:reverse(Result);
-create_info_data([{Func,Desc}|Rest], Node, Result) ->
- Data = convert_type(check(rpc:call(Node, orber, Func, []))),
- create_info_data(Rest, Node, [{Desc, Data}|Result]).
-
-convert_type(Data) when is_integer(Data) ->
- integer_to_list(Data);
-convert_type(Data) when is_atom(Data) ->
- atom_to_list(Data);
-convert_type(Data) when is_float(Data) ->
- float_to_list(Data);
-convert_type(Data) when is_pid(Data) ->
- pid_to_list(Data);
-convert_type(Data) when is_port(Data) ->
- erlang:port_to_list(Data);
-convert_type(Data) when is_tuple(Data) ->
- io_lib:write(Data);
-convert_type([]) ->
- [];
-convert_type(Data) when is_list(Data) ->
- case io_lib:printable_list(Data) of
- true->
- Data;
- _->
- io_lib:write(Data)
- end;
-convert_type(_Data) ->
- [].
-
-
-%%----------------------------------------------------------------------
-%% Function : menu
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-menu(_Env, Args)->
- ["<BODY BGCOLOR=\"#FFFFFF\">", node_selections_javascripts(), node_body(Args, [node()|nodes()])].
-
-menu_title()->
- " <TABLE WIDTH=\"100%\" BORDER=\"0\">
- <TR><TD ALIGN=\"center\"><FONT SIZE=5>Menu</FONT></TD></TR>
- </TABLE>\n".
-
-
-node_body([], Nodes)->
- Node = node(),
- [node_selections_javascripts(), node_selection(Node, Nodes), menu_title(),
- menu_options(atom_to_list(Node))];
-node_body([{"node",Node}|_], Nodes)->
- [node_selections_javascripts(), node_selection(list_to_atom(Node), Nodes), menu_title(),
- menu_options(Node)];
-node_body([_|Rest], Nodes) ->
- node_body(Rest, Nodes).
-
-
-
-%%----------------------------------------------------------------------
-%% Function : node_selections_javascripts
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-node_selections_javascripts()->
- "<SCRIPT>
- function node_selected()
- {
- parent.frames.main.location=\"/orber/start_info.html\"
- window.location =\"./menu?node=\" + " ++
- "document.node_selection.nodes[document.node_selection.nodes.selectedIndex].value;
- }
- </SCRIPT>".
-
-
-
-%%----------------------------------------------------------------------
-%% Function : node_selection
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-node_selection(Node, Nodes)->
- ["<FORM ACTION=\"./node_info\" NAME=node_selection>\n
- <TABLE WIDTH=\"100%\" BORDER=\"0\">\n
- <TR><TD ALIGN=\"center\">\n
- <SELECT NAME=nodes onChange=\"node_selected()\">\n",
- print_nodes(Node, Nodes),
- "</SELECT>\n
- </TD></TR>\n
- </TABLE>\n
- </FORM>"].
-
-%%----------------------------------------------------------------------
-%% Function : print_nodes
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-print_nodes(Node,Nodes)->
- print_nodes_helper([Node|lists:delete(Node,Nodes)]).
-
-print_nodes_helper([])->
- [];
-print_nodes_helper([Node|Rest])->
- NodeStr = atom_to_list(Node),
- ["<OPTION value=\"", NodeStr, "\">", NodeStr, "\n" | print_nodes_helper(Rest)].
-
-%%----------------------------------------------------------------------
-%% Function : print_nodes
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-menu_options(Node)->
- ["<UL><LI><A HREF=\"./info?node=", Node, "\" TARGET=main><B>Configuration</B></A></UL>",
- "<UL><LI><A HREF=\"./nameservice?node=", Node, "&context=root\" TARGET=main><B>Name Service</B></A></UL>",
- "<UL><LI><A HREF=\"./ifr_select?node=", Node, "\" TARGET=main><B>IFR Types</B></A></UL>",
- "<UL><LI><A HREF=\"./create?node=", Node, "\" TARGET=main><B>Create Object</B></A></UL>",
- "<FORM Name=reload><INPUT TYPE=\"button\" onClick=\"node_selected()\" VALUE=\"Reload\">\n</FORM>",
- "<!--<A HREF=\"../../orber/application_help.html\" TARGET=main>Help</A>-->"].
-
-%%----------------------------------------------------------------------
-%%----------------- MISC Functions -------------------------------------
-%%----------------------------------------------------------------------
-%% Function : simple_table
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-simple_table(Cols, Title, Data) ->
- ["<TABLE BORDER=0><TR BGCOLOR=\"#FFFFFF\"><TD ALIGN=\"center\" COLSPAN=",
- Cols, "><FONT SIZE=6>", Title, "</FONT>\n</TD></TR>", add_data(Data), "</TABLE>"].
-
-simple_table(Cols, Title, Data, Extra) ->
- ["<TABLE BORDER=0><TR BGCOLOR=\"#FFFFFF\"><TD ALIGN=\"center\" COLSPAN=",
- Cols, "><FONT SIZE=6>", Title, "</FONT>\n</TD></TR>", add_data(Data),
- Extra, "</TABLE>"].
-
-
-% Temporarily removed to avoid a silly dialyzer warning
-%add_data([]) ->
-% "";
-add_data([{C1, C2, C3, C4}|T]) ->
- add_data(T, ["<TR BGCOLOR=\"#FFFF00\"><TD><B>" ++ C1 ++ "</B></TD><TD><B>"
- ++ C2 ++ "</B></TD><TD><B>" ++ C3 ++ "</B></TD><TD><B>"
- ++ C4 ++ "</B></TD></TR>"]);
-add_data([{C1, C2, C3}|T]) ->
- add_data(T, ["<TR BGCOLOR=\"#FFFF00\"><TD><B>" ++ C1 ++ "</B></TD><TD><B>"
- ++ C2 ++ "</B></TD><TD><B>" ++ C3 ++ "</B></TD></TR>"]);
-add_data([{C1, C2}|T]) ->
- add_data(T, ["<TR BGCOLOR=\"#FFFF00\"><TD><B>" ++ C1 ++ "</B></TD><TD><B>"
- ++ C2 ++ "</B></TD></TR>"]);
-add_data([C1|T]) ->
- add_data(T, ["<TR BGCOLOR=\"#FFFF00\"><TD><B>" ++ C1 ++ "</B></TD></TR>"]).
-
-
-add_data([], Acc) ->
- lists:reverse(Acc);
-add_data([{C1, C2, C3, C4}|T], Acc) ->
- add_data(T, ["<TR><TD><B>"++C1++"</B></TD><TD>"++C2++"</TD><TD>"
- ++C3++"</TD><TD>"++C4++"</TD></TR>"|Acc]);
-add_data([{C1, C2, C3}|T], Acc) ->
- add_data(T, ["<TR><TD><B>"++C1++"</B></TD><TD>"++C2++"</TD><TD>"
- ++C3++"</TD></TR>"|Acc]);
-add_data([{C1, C2}|T], Acc) ->
- add_data(T, ["<TR><TD><B>"++C1++"</B></TD><TD>"++C2++"</TD></TR>"|Acc]);
-add_data([C1|T], Acc) ->
- add_data(T, ["<TR><TD>"++C1++"</TD></TR>"|Acc]).
-
-%%----------------------------------------------------------------------
-%% Function : check
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-check(Data) ->
- check(Data, "").
-
-check({badrpc, {'EXCEPTION', E}}, Comment) ->
- EList = atom_to_list(element(1, E)),
- throw({error, ["<BODY BGCOLOR=\"#FFFFFF\">Got the exception: ", EList, "<BR><BR>", Comment]});
-check({badrpc,{'EXIT',{undef,_}}}, Comment) ->
- throw({error, ["<BODY BGCOLOR=\"#FFFFFF\">Tried to invoke undefined module or operation.<BR><BR>", Comment]});
-check({badrpc,nodedown}, Comment) ->
- throw({error, ["<BODY BGCOLOR=\"#FFFFFF\">Node down - unable to complete the requested operation.<BR><BR>", Comment]});
-check({badrpc, {'EXIT', _R}}, Comment) ->
- throw({error, ["<BODY BGCOLOR=\"#FFFFFF\">Invoking the requested operation resulted in an EXIT.<BR><BR>", Comment]});
-check({badrpc, {'EXIT', _R1, _R2}}, Comment) ->
- throw({error, ["<BODY BGCOLOR=\"#FFFFFF\">Invoking the requested operation resulted in an EXIT.<BR><BR>", Comment]});
-check({'EXCEPTION', E}, Comment) ->
- EList = atom_to_list(element(1, E)),
- throw({error, ["<BODY BGCOLOR=\"#FFFFFF\">Got the exception: ", EList, "<BR><BR>", Comment]});
-check({'EXIT',{undef,_}}, Comment) ->
- throw({error, ["<BODY BGCOLOR=\"#FFFFFF\">Tried to invoke operation using undefined module or operation.<BR><BR>", Comment]});
-check({'EXIT', _R}, Comment) ->
- throw({error, ["<BODY BGCOLOR=\"#FFFFFF\">Invoking the requested operation resulted in an EXIT.<BR><BR>", Comment]});
-check({'EXIT', _R1, _R2}, Comment) ->
- throw({error, ["<BODY BGCOLOR=\"#FFFFFF\">Invoking the requested operation resulted in an EXIT.<BR><BR>", Comment]});
-check(Reply, _) ->
- Reply.
-
-
-%%----------------------------------------------------------------------
-%% Function : is_running
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-is_running(Node, NodeStr) ->
- case rpc:call(Node, application, which_applications, []) of
- {badrpc, _} ->
- throw(["<BODY BGCOLOR=\"#FFFFFF\">
- <TABLE BORDER=0><TR BGCOLOR=\"#FFFFFF\"><TD ALIGN=\"center\" COLSPAN=1>
- <FONT SIZE=6>Orber not started on node: ", NodeStr, "</FONT>
- </TD></TR></TABLE>"]);
- Apps ->
- is_running2(Apps, NodeStr)
- end.
-
-is_running2([], NodeStr) ->
- throw(["<BODY BGCOLOR=\"#FFFFFF\">
- <TABLE BORDER=0><TR BGCOLOR=\"#FFFFFF\"><TD ALIGN=\"center\" COLSPAN=1>
- <FONT SIZE=6>Orber not started on node: ", NodeStr, "</FONT>
- </TD></TR></TABLE>"]);
-is_running2([{orber, _, _} |_], _) ->
- true;
-is_running2([_ |As], NodeStr) ->
- is_running2(As, NodeStr).
-
-
-%%----------------------------------------------------------------------
-%% Function : parse_data
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-parse_data([])->
- [];
-parse_data(Options)->
- case erl_scan:string(Options ++ ".") of
- {ok,Tokens,_Line} ->
- case erl_parse:parse_term(Tokens) of
- {ok,X}->
- X;
- Why ->
- orber:dbg("[~p] orber_web:parse_data(~p);
-erl_parse:parse_term failed.
-Malformed data: ~p", [?LINE, Options, Why], ?DEBUG_LEVEL),
- throw({error, ["<BODY BGCOLOR=\"#FFFFFF\">Unable to parse supplied data: ",
- Options]})
- end;
- Why ->
- orber:dbg("[~p] orber_web:parse_data(~p);
-erl_scan:string failed.
-Malformed data: ~p", [?LINE, Options, Why], ?DEBUG_LEVEL),
- throw({error, ["<BODY BGCOLOR=\"#FFFFFF\">Unable to parse supplied data: ", Options]})
- end.
-
-%%----------------------------------------------------------------------
-%% Function : remote_resolve
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-remote_resolve(Node, Ref) ->
- NS = check(rpc:call(Node, corba, resolve_initial_references, ["NameService"]),
- "Failed to resolve initial refrence (NameService)"),
- case rpc:call(Node, 'CosNaming_NamingContextExt', resolve_str, [NS, Ref]) of
- {'EXCEPTION', E} when is_record(E, 'CosNaming_NamingContext_NotFound') ->
- throw({ok, ["<BODY BGCOLOR=\"#FFFFFF\">Unable to look up the Object: ", Ref,
- "<BR><BR>Reason: CosNaming_NamingContext_NotFound",
- "<BR><BR>If You just deleted it, use the 'Go Back' button next time."]});
- {'EXCEPTION', E} when is_record(E, 'CosNaming_NamingContext_CannotProceed') ->
- throw({ok, ["<BODY BGCOLOR=\"#FFFFFF\">Unable to look up the Object: ", Ref,
- "<BR><BR>Reason: CosNaming_NamingContext_CannotProceed",
- "<BR><BR>If You just deleted it, use the 'Go Back' button next time."]});
- {badrpc, {'EXCEPTION', E}} when is_record(E, 'CosNaming_NamingContext_NotFound') ->
- throw({ok, ["<BODY BGCOLOR=\"#FFFFFF\">Unable to look up the Object: ", Ref,
- "<BR><BR>Reason: CosNaming_NamingContext_NotFound",
- "<BR><BR>If You just deleted it, use the 'Go Back' button next time."]});
- {badrpc, {'EXCEPTION', E}} when is_record(E, 'CosNaming_NamingContext_CannotProceed') ->
- throw({ok, ["<BODY BGCOLOR=\"#FFFFFF\">Unable to look up the Object: ", Ref,
- "<BR><BR>Reason: CosNaming_NamingContext_CannotProceed",
- "<BR><BR>If You just deleted it, use the 'Go Back' button next time."]});
- FoundObj ->
- {FoundObj, NS}
- end.
-
-
-
-%%----------------------------------------------------------------------
-%% END OF MODULE
-%%----------------------------------------------------------------------
diff --git a/lib/orber/src/orber_web_server.erl b/lib/orber/src/orber_web_server.erl
deleted file mode 100644
index 3506894df2..0000000000
--- a/lib/orber/src/orber_web_server.erl
+++ /dev/null
@@ -1,190 +0,0 @@
-%%----------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2015. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_web_server.erl
-%% Purpose :
-%%----------------------------------------------------------------------
-
--module(orber_web_server).
-
--behaviour(gen_server).
-
--export([init/1,handle_call/3,handle_cast/2,handle_info/2]).
--export([terminate/2,code_change/3]).
--export([start/0,stop/0,start_link/0]).
-
--export([config_data/0, menu/2, configure/2, info/2, nameservice/2,
- default_selection/2, ifr_select/2, ifr_data/2, create/2,
- delete_ctx/2, add_ctx/2, delete_obj/2, flash_msg/2]).
-
-%%----------------------------------------------------------------------
-%%-------------- Defines & Includes ------------------------------------
-%%----------------------------------------------------------------------
--define(HTML_HEADER,
- "Cache-Control:no-cache\r\nPragma:no-cache\r\nExpires:Thu, 01 Dec 1994 16:00:00 GMT\r\nContent-type: text/html\r\n\r\n<HTML BGCOLOR=\"#FFFFFF\">\n<HEAD>\n<TITLE>Orber O&D</TITLE>\n</HEAD>\n").
-
-
--define(HTML_END, "</BODY></HTML>").
-
--define(DEBUG_LEVEL, 5).
-
--record(state, {}).
--include("ifr_objects.hrl").
-
-%%----------------------------------------------------------------------
-%%-------------- External API ------------------------------------------
-%%----------------------------------------------------------------------
-%% Function : start/start_link/stop
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-start_link()->
- gen_server:start_link({local,?MODULE},?MODULE,[],[]).
-start()->
- gen_server:start({local,?MODULE},?MODULE,[],[]).
-stop()->
- gen_server:call(?MODULE,stop,1000).
-
-%%----------------------------------------------------------------------
-%% Function : config_data
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-config_data()->
- {orber,[{web_data,{"OrberWeb","/orber/main_frame.html"}},
- {alias,{"/orber", code:priv_dir(orber)}},
- {start,{child,{{local,?MODULE},{?MODULE,start_link,[]},
- permanent,100,worker,[?MODULE]}}},
- {alias,{erl_alias,"/orber_erl",[orber_web_server]}}
- ]}.
-
-
-menu(Env,Input) ->
- Args = httpd:parse_query(Input),
- [?HTML_HEADER, gen_server:call(?MODULE, {menu, Env, Args}), ?HTML_END].
-
-configure(Env,Input) ->
- Args = httpd:parse_query(Input),
- [?HTML_HEADER, gen_server:call(?MODULE, {configure, Env, Args}), ?HTML_END].
-
-nameservice(Env,Input) ->
- Args = httpd:parse_query(Input),
- [?HTML_HEADER, gen_server:call(?MODULE, {nameservice, Env, Args}), ?HTML_END].
-
-info(Env,Input) ->
- Args = httpd:parse_query(Input),
- [?HTML_HEADER, gen_server:call(?MODULE, {info, Env, Args}), ?HTML_END].
-
-default_selection(Env,Input) ->
- Args = httpd:parse_query(Input),
- [?HTML_HEADER, gen_server:call(?MODULE, {default_selection, Env, Args}), ?HTML_END].
-
-flash_msg(Env, Input) ->
- Args = httpd:parse_query(Input),
- [?HTML_HEADER, gen_server:call(?MODULE, {nameservice, Env, Args}), ?HTML_END].
-
-ifr_select(Env, Input) ->
- Args = httpd:parse_query(Input),
- [?HTML_HEADER, gen_server:call(?MODULE, {ifr_select, Env, Args}), ?HTML_END].
-
-ifr_data(Env, Input) ->
- Args = httpd:parse_query(Input),
- [?HTML_HEADER, gen_server:call(?MODULE, {ifr_data, Env, Args}), ?HTML_END].
-
-create(Env, Input) ->
- Args = httpd:parse_query(Input),
- [?HTML_HEADER, gen_server:call(?MODULE, {create, Env, Args}), ?HTML_END].
-
-delete_ctx(Env, Input) ->
- Args = httpd:parse_query(Input),
- [?HTML_HEADER, gen_server:call(?MODULE, {delete_ctx, Env, Args}), ?HTML_END].
-
-add_ctx(Env, Input) ->
- Args = httpd:parse_query(Input),
- [?HTML_HEADER, gen_server:call(?MODULE, {add_ctx, Env, Args}), ?HTML_END].
-
-delete_obj(Env, Input) ->
- Args = httpd:parse_query(Input),
- [?HTML_HEADER, gen_server:call(?MODULE, {delete_obj, Env, Args}), ?HTML_END].
-
-%%----------------------------------------------------------------------
-%%-------------- Callback Functions ------------------------------------
-%%----------------------------------------------------------------------
-%% Function : MISC gen_server specific callback functions
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-init(_Arg)->
- {ok, #state{}}.
-
-terminate(_,_State)->
- ok.
-
-handle_cast(_,State)->
- {noreply,State}.
-
-handle_info(_,State)->
- {noreply,State}.
-
-code_change(_Old_vsn,State,_Extra)->
- {ok,State}.
-
-%%----------------------------------------------------------------------
-%% Function : handle_call
-%% Returns :
-%% Description:
-%%----------------------------------------------------------------------
-handle_call({Function, Env, Args}, _From, State)->
- case catch orber_web:Function(Env, Args) of
- {'EXIT', R} ->
- orber:dbg("[~p] orber_web:~p(~p);~nEXIT: ~p",
- [?LINE, Function, Args, R], ?DEBUG_LEVEL),
- {reply, "<BODY BGCOLOR=\"#FFFFFF\">Internal Error", State};
- {'EXIT', R1, R2} ->
- orber:dbg("[~p] orber_web:~p(~p);~nEXIT: ~p~n~p",
- [?LINE, Function, Args, R1, R2], ?DEBUG_LEVEL),
- {reply, "<BODY BGCOLOR=\"#FFFFFF\">Internal Error", State};
- {badrpc, Why} ->
- orber:dbg("[~p] orber_web:~p(~p);~nbadrpc: ~p",
- [?LINE, Function, Args, Why], ?DEBUG_LEVEL),
- {reply, "<BODY BGCOLOR=\"#FFFFFF\">Internal Error", State};
- {'EXCEPTION', E} ->
- orber:dbg("[~p] orber_web:~p(~p);~nEXCEPTION: ~p",
- [?LINE, Function, Args, E], ?DEBUG_LEVEL),
- {reply, "<BODY BGCOLOR=\"#FFFFFF\">Internal Error", State};
- {error, Data} ->
- orber:dbg("[~p] orber_web:~p(~p); ~nReason: ~p",
- [?LINE, Function, Args, Data], ?DEBUG_LEVEL),
- {reply, Data, State};
- Reply ->
- {reply, Reply, State}
- end;
-handle_call(stop, _From, State)->
- {stop, normal, ok, State};
-handle_call(What, _From, State)->
- orber:dbg("[~p] orber_web_server:handle_call(~p);",
- [?LINE, What], ?DEBUG_LEVEL),
- {reply, "<BODY BGCOLOR=\"#FFFFFF\"><FONT SIZE=6>Unknown Request</FONT>", State}.
-
-%%----------------------------------------------------------------------
-%% END OF MODULE
-%%----------------------------------------------------------------------
diff --git a/lib/orber/test/Makefile b/lib/orber/test/Makefile
deleted file mode 100644
index 782ee2730b..0000000000
--- a/lib/orber/test/Makefile
+++ /dev/null
@@ -1,220 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(ORBER_VSN)
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/orber_test
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-TEST_SPEC_FILE = orber.spec
-COVER_FILE = orber.cover
-
-
-IDL_FILES = \
- orber_test.idl \
- iiop_test.idl \
- orber_test_server.idl
-
-IDLOUTDIR = idl_output
-
-MODULES = \
- cdrcoding_11_SUITE \
- cdrcoding_10_SUITE \
- cdrcoding_12_SUITE \
- cdrlib_SUITE \
- corba_SUITE \
- iop_ior_11_SUITE \
- iop_ior_10_SUITE \
- iop_ior_12_SUITE \
- iiop_module_do_test_impl \
- iiop_module_test_impl \
- lname_SUITE \
- naming_context_SUITE \
- orber_SUITE \
- orber_test_server_impl \
- orber_test_timeout_server_impl \
- orber_test_lib \
- csiv2_SUITE \
- multi_ORB_SUITE \
- data_types_SUITE \
- tc_SUITE \
- generated_SUITE \
- orber_web_SUITE \
- interceptors_SUITE \
- orber_acl_SUITE \
- orber_firewall_ipv4_in_SUITE \
- orber_firewall_ipv6_in_SUITE \
- orber_firewall_ipv4_out_SUITE \
- orber_firewall_ipv6_out_SUITE \
- orber_nat_SUITE \
- ip_v4v6_interop_SUITE
-
-GEN_MOD_ORBER = \
- oe_orber_test \
- Module_Except1 \
- Module_Except2 \
- Module_Except3 \
- Module_Except4 \
- Module_HEADER \
- Module_I1 \
- Module_I2 \
- Module_Struct0 \
- Module_Struct1 \
- Module_Struct2 \
- Module_Union \
- Module_Union1 \
- Module_Union2
-
-GEN_HRL_ORBER = \
- oe_orber_test.hrl \
- Module.hrl \
- Module_I1.hrl \
- Module_I2.hrl
-
-GEN_MOD_IIOP = \
- oe_iiop_test \
- iiop_module_Except1 \
- iiop_module_Struct1 \
- iiop_module_Union1 \
- iiop_module_do_test \
- iiop_module_test \
- iiop_module_test_retval
-
-GEN_HRL_IIOP = \
- oe_iiop_test.hrl \
- iiop_module.hrl \
- iiop_module_do_test.hrl \
- iiop_module_test.hrl
-
-GEN_MOD_TEST_SERVER = \
- oe_orber_test_server \
- orber_test_server \
- orber_test_server_ComplexUserDefinedException \
- orber_test_server_UserDefinedException \
- orber_test_server_struc \
- orber_test_server_uni \
- orber_test_server_uni_d \
- orber_test_timeout_server \
- orber_parent_inherrit \
- orber_test_server_rec_struct \
- orber_test_server_rec_struct_seq \
- orber_test_server_rec_union \
- orber_test_server_rec_union_seq
-
-GEN_HRL_TEST_SERVER = \
- oe_orber_test_server.hrl \
- orber_test_server.hrl \
- orber_test_timeout_server.hrl
-
-GEN_MODULES = $(GEN_MOD_ORBER) $(GEN_MOD_IIOP) \
- $(GEN_MOD_TEST_SERVER)
-
-ERL_FILES = $(MODULES:%=%.erl)
-
-HRL_FILES =
-
-GEN_HRL_FILES = $(GEN_HRL_ORBER) $(GEN_HRL_IIOP) \
- $(GEN_HRL_TEST_SERVER)
-
-GEN_FILES = \
- $(GEN_HRL_FILES:%=$(IDLOUTDIR)/%) \
- $(GEN_MODULES:%=$(IDLOUTDIR)/%.erl)
-
-GEN_TARGET_FILES = $(GEN_MODULES:%=$(IDLOUTDIR)/%.$(EMULATOR))
-
-SUITE_TARGET_FILES = $(MODULES:%=%.$(EMULATOR))
-
-TARGET_FILES = \
- $(GEN_TARGET_FILES) \
- $(SUITE_TARGET_FILES)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_IDL_FLAGS += -pa $(ERL_TOP)/lib/orber/ebin -pa $(ERL_TOP)/lib/ic/ebin
-
-ERL_COMPILE_FLAGS += $(ERL_IDL_FLAGS) \
- -pa $(ERL_TOP)/lib/ic/ebin \
- -pa $(ERL_TOP)/lib/orber/ebin \
- -I$(ERL_TOP)/lib/orber \
- -I$(ERL_TOP)/lib/orber/test/$(IDLOUTDIR)
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-tests debug opt: $(TARGET_FILES)
-
-clean:
- rm -f idl_output/*
- rm -f $(TARGET_FILES)
- rm -f errs core *~
- rm IDL-GENERATED
-
-
-docs:
-
-# ----------------------------------------------------
-# Special Targets
-# ----------------------------------------------------
-
-IDL-GENERATED: orber_test.idl iiop_test.idl orber_test_server.idl
- erlc $(ERL_IDL_FLAGS) -o$(IDLOUTDIR) orber_test.idl
- erlc $(ERL_IDL_FLAGS) -o$(IDLOUTDIR) \
- +'{preproc_flags,"-I../COSS/CosNaming"}' iiop_test.idl
- erlc $(ERL_IDL_FLAGS) -o$(IDLOUTDIR) \
- +'{cfgfile,"orber_test_server.cfg"}' orber_test_server.idl
- >IDL-GENERATED
-
-$(GEN_FILES): IDL-GENERATED
-
-$(TARGET_FILES): IDL-GENERATED
-
-# ----------------------------------------------------
-# Release Targets
-# ----------------------------------------------------
-# We don't copy generated intermediate erlang and hrl files
-
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec:
-
-release_docs_spec:
-
-release_tests_spec: tests
- $(INSTALL_DIR) "$(RELSYSDIR)"
- $(INSTALL_DATA) $(IDL_FILES) $(TEST_SPEC_FILE) $(COVER_FILE) \
- $(ERL_FILES) "$(RELSYSDIR)"
- $(INSTALL_DATA) $(SUITE_TARGET_FILES) "$(RELSYSDIR)"
- chmod -R u+w "$(RELSYSDIR)"
- $(INSTALL_DIR) "$(RELSYSDIR)/$(IDLOUTDIR)"
- $(INSTALL_DATA) $(GEN_TARGET_FILES) $(GEN_FILES) \
- "$(RELSYSDIR)/$(IDLOUTDIR)"
-
diff --git a/lib/orber/test/cdrcoding_10_SUITE.erl b/lib/orber/test/cdrcoding_10_SUITE.erl
deleted file mode 100644
index 24de589615..0000000000
--- a/lib/orber/test/cdrcoding_10_SUITE.erl
+++ /dev/null
@@ -1,587 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%%
-%% Description:
-%% Test suite for the CDR encode/decode functions
-%%
-%%-----------------------------------------------------------------
--module(cdrcoding_10_SUITE).
-
--include("idl_output/Module.hrl").
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
-
--define(default_timeout, test_server:minutes(20)).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--compile(export_all).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- cases().
-
-groups() ->
- [{types, [],
- [do_register, null_type, void_type, principal_type,
- objref_type, struct_type, union_type, string_type,
- array_type, any_type, typecode_type, alias_type,
- exception_type, do_unregister]}].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-cases() ->
- [{group, types}, reply, cancel_request,
- close_connection, message_error].
-%% request, locate_request, locate_reply].
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-
-init_per_testcase(_Case, Config) ->
- Path = code:which(?MODULE),
- code:add_pathz(filename:join(filename:dirname(Path), "idl_output")),
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- Path = code:which(?MODULE),
- code:del_path(filename:join(filename:dirname(Path), "idl_output")),
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-init_per_suite(Config) when is_list(Config) ->
- orber:jump_start(0),
- if
- is_list(Config) ->
- Config;
- true ->
- exit("Config not a list")
- end.
-
-end_per_suite(Config) when is_list(Config) ->
- orber:jump_stop(),
- Config.
-
-%%-----------------------------------------------------------------
-%% Test Case: type encoding tests
-%% Description: Just testing the complex types, the others are
-%% tested in the cdrlib SUITE.
-%%-----------------------------------------------------------------
-%types(Config) when list(Config) ->
-% 'oe_orber_test':'oe_register'(),
-% null_type(),
-% void_type(),
-% principal_type(),
-% objref_type(),
-% struct_type(),
-% union_type(),
-% string_type(),
-% array_type(),
-% any_type(),
-% typecode_type(),
-% alias_type(),
-% exception_type(),
-% 'oe_orber_test':'oe_unregister'(),
-% ok.
-
-do_register(Config) when is_list(Config) ->
- io:format("Pwd: ~p, mod: ~p~n",[c:pwd(), c:m('oe_orber_test')]),
- 'oe_orber_test':'oe_register'(),
- ok.
-
-do_unregister(Config) when is_list(Config) ->
- 'oe_orber_test':'oe_unregister'(),
- ok.
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: null
-%%-----------------------------------------------------------------
-null_type(Config) when is_list(Config) ->
- B = cdr_encode:enc_type(#giop_env{version = {1, 0}}, 'tk_null', 'null'),
- {'null', <<>>, _} = cdr_decode:dec_type('tk_null', {1, 0}, B, 0, big),
- ok.
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: void
-%%-----------------------------------------------------------------
-void_type(Config) when is_list(Config) ->
- B = cdr_encode:enc_type(#giop_env{version = {1, 0}}, 'tk_void', 'ok'),
- {'ok', <<>>, _} = cdr_decode:dec_type('tk_void', {1, 0}, B, 0, big),
- ok.
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: principal
-%%-----------------------------------------------------------------
-principal_type(Config) when is_list(Config) ->
- B0 = cdr_encode:enc_type(#giop_env{version = {1, 0}}, 'tk_Principal', "principal"),
- {"principal", <<>>, _} = cdr_decode:dec_type('tk_Principal', {1, 0}, B0, 0, big),
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 0}}, 'tk_Principal', ""),
- {"", <<>>, _} = cdr_decode:dec_type('tk_Principal', {1, 0}, B1, 0, big),
- B2 = cdr_encode:enc_type(#giop_env{version = {1, 0}}, 'tk_Principal', "principal"),
- {"principal", <<>>, _} =
- cdr_decode:dec_type('tk_Principal', {1, 0}, B2, 0, big),
- ok.
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: object reference
-%%-----------------------------------------------------------------
-version() -> #'IIOP_Version'{major=1,minor=0}.
-
-objref(0) ->
- PB = #'IIOP_ProfileBody_1_0'{iiop_version=version(),
- host="my.hostname.org",
- port=4040,
- object_key="ExternalKey: which is an arbitary octet sequence"},
- TP = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB},
- #'IOP_IOR'{type_id="IDL:Module/Interface:1.0", profiles=[TP]};
-objref(1) ->
- K = corba_fake_mk_objkey("IDL:Module/Interface:1.0", key,
- list_to_pid("<0.100.0>")),
- PB = #'IIOP_ProfileBody_1_0'{iiop_version=version(),
- host="my.hostname.org",
- port=4040,
- object_key=K},
- TP = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB},
- #'IOP_IOR'{type_id="IDL:Module/Interface:1.0", profiles=[TP]};
-objref(2) ->
- K = corba_fake_mk_objkey("IDL:Module/Interface:1.0", registered,
- list_to_atom("orber_nameservice")),
- PB = #'IIOP_ProfileBody_1_0'{iiop_version=version(),
- host="my.hostname.org",
- port=4040,
- object_key=K},
- TP = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB},
- #'IOP_IOR'{type_id="IDL:Module/Interface:1.0", profiles=[TP]}.
-
-objref_type(Config) when is_list(Config) ->
- T = {'tk_objref', "IDL:Module/Interface:1.0", "Interface"},
- Objref0 = objref(0),
- B0 = cdr_encode:enc_type(#giop_env{version = {1, 0}}, T, Objref0),
- {Objref0, <<>>, _} = cdr_decode:dec_type(T, {1, 0}, B0, 0, big),
- Objref1 = objref(1),
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 0}}, T, Objref1),
- {Objref1, <<>>, _} = cdr_decode:dec_type(T, {1, 0}, B1, 0, big),
- Objref2 = objref(2),
- B2 = cdr_encode:enc_type(#giop_env{version = {1, 0}}, T, Objref2),
- {Objref2, <<>>, _} = cdr_decode:dec_type(T, {1, 0}, B2, 0, big),
- ok.
-
-
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: struct
-%%-----------------------------------------------------------------
-struct_type(Config) when is_list(Config) ->
- T0 = {'tk_struct',"IDL:Module/Struct0:1.0", "Module_Struct0",
- [{"long", 'tk_long'}, {"short", 'tk_short'}, {"character", 'tk_char'}]},
- S0 = #'Module_Struct0'{l=-4711, s=17, c=$a},
- B0 = cdr_encode:enc_type({1, 0}, T0, S0),
- {S0, <<>>, _} = cdr_decode:dec_type(T0, {1, 0}, B0, 0, big),
-
- T1 = {'tk_struct', "IDL:Module/Struct1:1.0", "Module_Struct1",
- [{"string", {'tk_string', 0}}, {"ushort", 'tk_ushort'}, {"ulong", 'tk_ulong'}]},
- S1 = #'Module_Struct1'{s="Hi !!!!", us=17, ul=4711},
- B1 = cdr_encode:enc_type({1, 0}, T1, S1),
- {S1, <<>>, _} = cdr_decode:dec_type(T1, {1, 0}, B1, 0, big),
-
- T2 = {'tk_struct', "IDL:Module/Struct2:1.0", "Module_Struct2",
- [{"long_sequence", {'tk_sequence', 'tk_long', 0}},
- {"enum", {'tk_enum', "IDL:Module/Enum:1.0", "Module_Enum", ["horse", "pig", "cow"]}},
- {"octet", 'tk_octet'}]},
- S2 = #'Module_Struct2'{long_sequence=[4711, 350000, 0, -3030, -600000], e=cow, o=$X},
- B2 = cdr_encode:enc_type({1, 0}, T2, S2),
- {S2, <<>>, _} = cdr_decode:dec_type(T2, {1, 0}, B2, 0, big),
- ok.
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: union
-%%-----------------------------------------------------------------
-union_type(Config) when is_list(Config) ->
- T0 = {'tk_union', "IDL:Module/Union:1.0", "Union", 'tk_short', 2,
- [{0, "First", 'tk_short'},
- {1, "Second", {'tk_string', 0}},
- {2, "Third", 'tk_char'}]},
- S0 = #'Module_Union'{label=1, value="Foo Bar !"},
- B0 = cdr_encode:enc_type({1, 0}, T0, S0),
- {S0, <<>>, _} = cdr_decode:dec_type(T0, {1, 0}, B0, 0, big),
- S1 = #'Module_Union'{label=0, value=-17},
- B1 = cdr_encode:enc_type({1, 0}, T0, S1),
- {S1, <<>>, _} = cdr_decode:dec_type(T0, {1, 0}, B1, 0, big),
- S2 = #'Module_Union'{label=2, value=$X},
- B2 = cdr_encode:enc_type({1, 0}, T0, S2),
- {S2, <<>>, _} = cdr_decode:dec_type(T0, {1, 0}, B2, 0, big),
- T1 = {'tk_union', "IDL:Module/Union1:1.0", "Union1",
- {'tk_enum', "IDL:Module/Enum:1.0",
- "Module_Enum", ["horse", "pig", "cow"]}, "pig",
- [{"horse", "First", 'tk_ushort'},
- {"pig", "Second", {'tk_sequence', {'tk_string', 0}, 0}},
- {"cow", "Third", {'tk_enum', "IDL:Module/Enum1:1.0",
- "Module_Enum1", ["orange", "banana", "apple"]}}]},
- S3 = #'Module_Union1'{label=pig, value=["Foo", "Bar", "!"]},
- B3 = cdr_encode:enc_type({1, 0}, T1, S3),
- {S3, <<>>, _} = cdr_decode:dec_type(T1, {1, 0}, B3, 0, big),
- S4 = #'Module_Union1'{label=cow, value=apple},
- B4 = cdr_encode:enc_type({1, 0}, T1, S4),
- {S4, <<>>, _} = cdr_decode:dec_type(T1, {1, 0}, B4, 0, big),
- S5 = #'Module_Union1'{label=horse, value=17},
- B5 = cdr_encode:enc_type({1, 0}, T1, S5),
- {S5, <<>>, _} = cdr_decode:dec_type(T1, {1, 0}, B5, 0, big),
- T2 = {'tk_union', "IDL:Module/Union2:1.0", "Union2",
- {'tk_enum', "IDL:Module/Enum:1.0",
- "Module_Enum", ["horse", "pig", "cow"]}, "pig",
- [{"horse", "First", {'tk_array', 'tk_long', 3}},
- {"pig", "Second",
- {'tk_union', "IDL:Module/Union:1.0", "Union", 'tk_short', 2,
- [{0, "First", 'tk_short'},
- {1, "Second", {'tk_string', 0}},
- {2, "Third", 'tk_char'}]}},
- {"cow", "Third", {'tk_union', "IDL:Module/Union1:1.0", "Union1",
- {'tk_enum', "IDL:Module/Enum:1.0",
- "Module_Enum", ["horse", "pig", "cow"]}, "pig",
- [{"horse", "First", 'tk_ushort'},
- {"pig", "Second", {'tk_sequence',
- {'tk_string', 0}, 0}},
- {"cow", "Third", {'tk_enum',
- "IDL:Module/Enum1:1.0",
- "Module_Enum1",
- ["orange", "banana",
- "apple"]}}]}}]},
- S6 = #'Module_Union2'{label=pig, value=#'Module_Union'{label=0, value=-17}},
- B6 = cdr_encode:enc_type({1, 0}, T2, S6),
- {S6, <<>>, _} = cdr_decode:dec_type(T2, {1, 0}, B6, 0, big),
- S7 = #'Module_Union2'{label=cow, value=#'Module_Union1'{label=pig,
- value=["Foo", "Bar", "!"]}},
- B7 = cdr_encode:enc_type({1, 0}, T2, S7),
- {S7, <<>>, _} = cdr_decode:dec_type(T2, {1, 0}, B7, 0, big),
- S8 = #'Module_Union2'{label=horse, value={-17, 1234567890, -987654321}},
- B8 = cdr_encode:enc_type({1, 0}, T2, S8),
- {S8, <<>>, _} = cdr_decode:dec_type(T2, {1, 0}, B8, 0, big),
- ok.
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: string
-%%-----------------------------------------------------------------
-string_type(Config) when is_list(Config) ->
- S0 = "Foo Bar ???",
- B0 = cdr_encode:enc_type({1, 0}, {'tk_string', 0}, S0),
- {S0, <<>>, _} = cdr_decode:dec_type({'tk_string', 0}, {1, 0}, B0, 0, big),
- S1 = "Yes, Foo Bar !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! more than 5000 characters",
- B1 = cdr_encode:enc_type({1, 0}, {'tk_string', 0}, S1),
- {S1, <<>>, _} = cdr_decode:dec_type({'tk_string', 0}, {1, 0}, B1, 0, big),
- S2 = "",
- B2 = cdr_encode:enc_type({1, 0}, {'tk_string', 0}, S2),
- {S2, <<>>, _} = cdr_decode:dec_type({'tk_string', 0}, {1, 0}, B2, 0, big),
- S3 = "\0",
- B3 = cdr_encode:enc_type({1, 0}, {'tk_string', 0}, S3),
- {S3, <<>>, _} = cdr_decode:dec_type({'tk_string', 0}, {1, 0}, B3, 0, big),
- S4 = "~n",
- B4 = cdr_encode:enc_type({1, 0}, {'tk_string', 0}, S4),
- {S4, <<>>, _} = cdr_decode:dec_type({'tk_string', 0}, {1, 0}, B4, 0, big),
- ok.
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: array
-%%-----------------------------------------------------------------
-array_type(Config) when is_list(Config) ->
- T0 = {'tk_array', 'tk_long', 5},
- S0 = {-100, 0, 30000, -900100900, 123456789},
- B0 = cdr_encode:enc_type(#giop_env{version = {1, 0}}, T0, S0),
- {S0, <<>>, _} = cdr_decode:dec_type(T0, {1, 0}, B0, 0, big),
- T1 = {'tk_array', {'tk_enum', "IDL:Module/Enum:1.0", "Module_Enum", ["horse", "pig", "cow"]}, 2},
- S1 = {pig, cow},
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 0}}, T1, S1),
- {S1, <<>>, _} = cdr_decode:dec_type(T1, {1, 0}, B1, 0, big),
- T2 = {'tk_array', {'tk_union', "IDL:Module/Union:1.0", "Union",
- {'tk_enum', "IDL:Module/Enum:1.0", "Module_Enum", ["horse", "pig", "cow"]}, "pig",
- [{"horse", "First", 'tk_ushort'},
- {"pig", "Second", {'tk_sequence', {'tk_string', 0}, 0}},
- {"cow", "Third", {'tk_enum', "IDL:Module/Enum1:1.0",
- "Module_Enum1", ["orange", "banana", "apple"]}}]}, 2},
- S2 = {#'Module_Union'{label=cow, value=banana}, #'Module_Union'{label=pig, value=["This", "is", "a", "test", ""]}},
- B2 = cdr_encode:enc_type(#giop_env{version = {1, 0}}, T2, S2),
- {S2, <<>>, _} = cdr_decode:dec_type(T2, {1, 0}, B2, 0, big),
- T3 = {'tk_array', {'tk_objref', "IDL:Module/Interface:1.0", "Interface"}, 3},
- S3 = {objref(0), objref(1), objref(2)},
- B3 = cdr_encode:enc_type(#giop_env{version = {1, 0}}, T3, S3),
- {S3, <<>>, _} = cdr_decode:dec_type(T3, {1, 0}, B3, 0, big),
- ok.
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: TypeCode
-%%-----------------------------------------------------------------
-any_type(Config) when is_list(Config) ->
- T = 'tk_any',
- TC = {'tk_struct', "IDL:Module/Struct2:1.0", "Module_Struct2",
- [{"long_sequence", {'tk_sequence', 'tk_long', 0}},
- {"enum", {'tk_enum', "IDL:Module/Enum:1.0", "Module_Enum",
- ["horse", "pig", "cow"]}},
- {"octet", 'tk_octet'}]},
- S = #'Module_Struct2'{long_sequence=[4711, 350000, 0, -3030, -600000],
- e=cow, o=$X},
- Any = #any{typecode=TC,value=S},
- B = cdr_encode:enc_type(#giop_env{version = {1, 0}}, T,Any),
- {Any, <<>>, _} = cdr_decode:dec_type(T, {1, 0}, B, 0, big),
- TC1 = {'tk_array', {'tk_union', "IDL:Module/Union:1.0", "Union",
- {'tk_enum', "IDL:Module/Enum:1.0", "Module_Enum",
- ["horse", "pig", "cow"]}, 1,
- [{"horse", "First", 'tk_ushort'},
- {"pig", "Second", {'tk_sequence', {'tk_string', 0}, 0}},
- {"cow", "Third", {'tk_enum', "IDL:Module/Enum1:1.0",
- "Module_Enum1", ["orange", "banana",
- "apple"]}}]},2},
- S1 = {#'Module_Union'{label=cow, value=banana}, #'Module_Union'{label=pig, value=["This", "is", "a", "test", ""]}},
- Any1 = #any{typecode=TC1,value=S1},
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 0}}, T,Any1),
- {Any1, <<>>, _} = cdr_decode:dec_type(T, {1, 0}, B1, 0, big),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: TypeCode
-%%-----------------------------------------------------------------
-typecode_type(Config) when is_list(Config) ->
- T = 'tk_TypeCode',
- TC = {'tk_array', {'tk_union', "IDL:Module/Union:1.0", "Union",
- {'tk_enum', "IDL:Module/Enum:1.0", "Module_Enum",
- ["horse", "pig", "cow"]}, 1,
- [{"horse", "First", 'tk_ushort'},
- {"pig", "Second", {'tk_sequence', {'tk_string', 0}, 0}},
- {"cow", "Third", {'tk_enum', "IDL:Module/Enum1:1.0",
- "Module_Enum1", ["orange", "banana",
- "apple"]}}]}, 10},
- B = cdr_encode:enc_type(#giop_env{version = {1, 0}}, T,TC),
- {TC, <<>>, _} = cdr_decode:dec_type(T, {1, 0}, B, 0, big),
- TC1 = {'tk_union', "IDL:Module/Union2:1.0", "Union2",
- {'tk_enum', "IDL:Module/Enum:1.0",
- "Module_Enum", ["horse", "pig", "cow"]}, 2,
- [{"horse", "First", 'tk_long'},
- {"pig", "Second",
- {'tk_union', "IDL:Module/Union:1.0", "Union", 'tk_short', 2,
- [{0, "First", 'tk_short'},
- {1, "Second", {'tk_string', 0}},
- {2, "Third", 'tk_char'}]}},
- {"cow", "Third", {'tk_union', "IDL:Module/Union1:1.0", "Union1",
- {'tk_enum', "IDL:Module/Enum:1.0",
- "Module_Enum", ["horse", "pig", "cow"]}, 2,
- [{"horse", "First", 'tk_ushort'},
- {"pig", "Second", {'tk_sequence',
- {'tk_string', 0}, 0}},
- {"cow", "Third", {'tk_enum',
- "IDL:Module/Enum1:1.0",
- "Module_Enum1",
- ["orange", "banana",
- "apple"]}}]}}]},
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 0}}, T, TC1),
- {TC1, <<>>, _} = cdr_decode:dec_type(T, {1, 0}, B1, 0, big),
- ok.
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: TypeCode
-%%-----------------------------------------------------------------
-alias_type(Config) when is_list(Config) ->
- T = {'tk_alias', "IDL:Module/Alias:1.0", "Alias",
- {'tk_struct', "IDL:Module/Struct2:1.0", "Module_Struct2",
- [{"long_sequence", {'tk_sequence', 'tk_long', 0}},
- {"enum", {'tk_enum', "IDL:Module/Enum:1.0", "Module_Enum",
- ["horse", "pig", "cow"]}},
- {"octet", 'tk_octet'}]}},
- S = #'Module_Struct2'{long_sequence=[4711, 350000, 0, -3030, -600000],
- e=cow, o=$X},
- B = cdr_encode:enc_type(#giop_env{version = {1, 0}}, T,S),
- {S, <<>>, _} = cdr_decode:dec_type(T, {1, 0}, B, 0, big),
- T1 = {'tk_alias', "IDL:Module/Alias1:1.0", "Alias1",
- {'tk_sequence', {'tk_union', "IDL:Module/Union:1.0", "Union",
- {'tk_enum', "IDL:Module/Enum:1.0", "Module_Enum",
- ["horse", "pig", "cow"]}, 2,
- [{"horse", "First", 'tk_ushort'},
- {"pig", "Second", {'tk_sequence', {'tk_string', 0}, 0}},
- {"cow", "Third", {'tk_enum', "IDL:Module/Enum1:1.0",
- "Module_Enum1", ["orange", "banana",
- "apple"]}}]},0}},
- S1 = [#'Module_Union'{label=cow, value=banana}, #'Module_Union'{label=pig, value=["This", "is", "a", "test", ""]}],
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 0}}, T1, S1),
- {S1, <<>>, _} = cdr_decode:dec_type(T1, {1, 0}, B1, 0, big),
- ok.
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: exception
-%%-----------------------------------------------------------------
-exception_type(Config) when is_list(Config) ->
- system_exceptions(),
- user_exceptions(),
- ok.
-
-system_exceptions() ->
- E = #'UNKNOWN'{completion_status=?COMPLETED_YES},
- {system_exception, T, E} = orber_exceptions:get_def(E),
- B = cdr_encode:enc_type(#giop_env{version = {1, 0}}, T,E),
- {E, _} = cdr_decode:dec_system_exception({1, 0}, B, 0, big),
- E1 = #'INV_OBJREF'{completion_status=?COMPLETED_NO},
- {system_exception, T1, E1} = orber_exceptions:get_def(E1),
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 0}}, T1,E1),
- {E1, _} = cdr_decode:dec_system_exception({1, 0}, B1, 0, big),
- E2 = #'BAD_OPERATION'{completion_status=?COMPLETED_NO},
- {system_exception, T2, E2} = orber_exceptions:get_def(E2),
- B2 = cdr_encode:enc_type(#giop_env{version = {1, 0}}, T2,E2),
- {E2, _} = cdr_decode:dec_system_exception({1, 0}, B2, 0, big),
- E3 = #'INTF_REPOS'{completion_status=?COMPLETED_MAYBE},
- {system_exception, T3, E3} = orber_exceptions:get_def(E3),
- B3 = cdr_encode:enc_type(#giop_env{version = {1, 0}}, T3,E3),
- {E3, _} = cdr_decode:dec_system_exception({1, 0}, B3, 0, big),
- ok.
-
-user_exceptions() ->
- E = #'Module_Except1'{rest_of_name=["I","am","testing","exceptions"], why="Error"},
- {user_exception, T, E} = orber_exceptions:get_def(E),
- B = cdr_encode:enc_type(#giop_env{version = {1, 0}}, T, E),
- {E, _} = cdr_decode:dec_user_exception({1, 0}, B, 0, big),
- E1 = #'Module_Except2'{e=banana,
- s=#'Module_Struct2'{long_sequence=[12,-4040,
- 1234567898],
- e=horse,
- o=$a}},
- {user_exception, T1, E1} = orber_exceptions:get_def(E1),
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 0}}, T1, E1),
- {E1, _} = cdr_decode:dec_user_exception({1, 0}, B1, 0, big),
- E2 = #'Module_Except3'{u=#'Module_Union1'{label=pig,value=["high","and","low"]},s=1313, o=objref(0)},
- {user_exception, T2, E2} = orber_exceptions:get_def(E2),
- B2 = cdr_encode:enc_type(#giop_env{version = {1, 0}}, T2, E2),
- {E2, _} = cdr_decode:dec_user_exception({1, 0}, B2, 0, big),
- E3 = #'Module_Except4'{},
- {user_exception, T3, E3} = orber_exceptions:get_def(E3),
- B3 = cdr_encode:enc_type(#giop_env{version = {1, 0}}, T3, E3),
- {E3, _} = cdr_decode:dec_user_exception({1, 0}, B3, 0, big),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: request encoding test
-%% Description: Precondition the stack must be started so the
-%% objectkey is valid.
-%%-----------------------------------------------------------------
-%request(_) ->
-% exit(not_implemented).
-
-%%-----------------------------------------------------------------
-%% Test Case: reply encoding test
-%% Description:
-%%-----------------------------------------------------------------
-reply(Config) when is_list(Config) ->
- R = #reply_header{service_context=[], request_id=1,
- reply_status='no_exception'},
- B = cdr_encode:enc_reply(
- #giop_env{version = {1, 0}, request_id = 1,
- reply_status = 'no_exception',
- tc = {'tk_long', [], [{'tk_sequence',
- {'tk_string', 0}, 0}]},
- result = 1200, parameters = [["foo","Bar"]],
- ctx = []}),
- {R, 1200, [["foo","Bar"]]} =
- cdr_decode:dec_message({'tk_long', [], [{'tk_sequence', {'tk_string', 0},0}]},
- B),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: cancel_request encoding test
-%% Description:
-%%-----------------------------------------------------------------
-cancel_request(Config) when is_list(Config) ->
- R = #cancel_request_header{request_id=1},
- B = cdr_encode:enc_cancel_request(#giop_env{version = {1, 0},
- request_id = 1}),
- R = cdr_decode:dec_message([], B),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: locate_request encoding test
-%% Description:
-%%-----------------------------------------------------------------
-locate_request(Config) when is_list(Config) ->
- io:format("Function not imlpemented yet"),
- exit(not_implemented).
-
-%%-----------------------------------------------------------------
-%% Test Case: locate_reply encoding test
-%% Description:
-%%-----------------------------------------------------------------
-locate_reply(Config) when is_list(Config) ->
- io:format("Function not imlpemented yet"),
- exit(not_implemented).
-
-%%-----------------------------------------------------------------
-%% Test Case: close_connection encoding test
-%% Description:
-%%-----------------------------------------------------------------
-close_connection(Config) when is_list(Config) ->
- B = cdr_encode:enc_close_connection(#giop_env{version = {1, 0}}),
- 'close_connection' = cdr_decode:dec_message([], B),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: message_error encoding test
-%% Description:
-%%-----------------------------------------------------------------
-message_error(Config) when is_list(Config) ->
- B = cdr_encode:enc_message_error(#giop_env{version = {1, 0}}),
- 'message_error' = cdr_decode:dec_message([], B),
- ok.
-
-
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-corba_fake_mk_objkey(Id, 'key', Pid) when is_pid(Pid) ->
- Key = make_objkey(),
- {list_to_binary(Id), 'key', Key, term_to_binary(undefined),
- term_to_binary(undefined), term_to_binary(undefined)};
-corba_fake_mk_objkey(Id, 'key', RegName) when is_atom(RegName) ->
- Key = term_to_binary(RegName),
- {list_to_binary(Id), 'key', Key, term_to_binary(undefined),
- term_to_binary(undefined), term_to_binary(undefined)};
-corba_fake_mk_objkey(Id, 'registered', RegName) when is_atom(RegName) ->
- {list_to_binary(Id), 'registered', RegName, term_to_binary(undefined),
- term_to_binary(undefined), term_to_binary(undefined)}.
-
-make_objkey() ->
- term_to_binary({{erlang:system_time(),
- erlang:unique_integer()},
- node()}).
diff --git a/lib/orber/test/cdrcoding_11_SUITE.erl b/lib/orber/test/cdrcoding_11_SUITE.erl
deleted file mode 100644
index ff5d2852d6..0000000000
--- a/lib/orber/test/cdrcoding_11_SUITE.erl
+++ /dev/null
@@ -1,587 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%%
-%% Description:
-%% Test suite for the CDR encode/decode functions
-%%
-%%-----------------------------------------------------------------
--module(cdrcoding_11_SUITE).
-
-
--include("idl_output/Module.hrl").
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
-
--define(default_timeout, test_server:minutes(5)).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--compile(export_all).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- cases().
-
-groups() ->
- [{types, [],
- [do_register, null_type, void_type, principal_type,
- objref_type, struct_type, union_type, string_type,
- array_type, any_type, typecode_type, alias_type,
- exception_type, do_unregister]}].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-cases() ->
- [{group, types}, reply, cancel_request,
- close_connection, message_error].
-%% request, locate_request, locate_reply].
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-
-init_per_testcase(_Case, Config) ->
- Path = code:which(?MODULE),
- code:add_pathz(filename:join(filename:dirname(Path), "idl_output")),
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- Path = code:which(?MODULE),
- code:del_path(filename:join(filename:dirname(Path), "idl_output")),
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-init_per_suite(Config) when is_list(Config) ->
- orber:jump_start(0),
- if
- is_list(Config) ->
- Config;
- true ->
- exit("Config not a list")
- end.
-
-end_per_suite(Config) when is_list(Config) ->
- orber:jump_stop(),
- Config.
-
-%%-----------------------------------------------------------------
-%% Test Case: type encoding tests
-%% Description: Just testing the complex types, the others are
-%% tested in the cdrlib SUITE.
-%%-----------------------------------------------------------------
-%types(Config) when list(Config) ->
-% 'oe_orber_test':'oe_register'(),
-% null_type(),
-% void_type(),
-% principal_type(),
-% objref_type(),
-% struct_type(),
-% union_type(),
-% string_type(),
-% array_type(),
-% any_type(),
-% typecode_type(),
-% alias_type(),
-% exception_type(),
-% 'oe_orber_test':'oe_unregister'(),
-% ok.
-
-do_register(Config) when is_list(Config) ->
- 'oe_orber_test':'oe_register'(),
- ok.
-
-do_unregister(Config) when is_list(Config) ->
- 'oe_orber_test':'oe_unregister'(),
- ok.
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: null
-%%-----------------------------------------------------------------
-null_type(Config) when is_list(Config) ->
- B = cdr_encode:enc_type(#giop_env{version = {1, 1}}, 'tk_null', 'null'),
- {'null', <<>>, _} = cdr_decode:dec_type('tk_null', {1, 1}, B, 0, big),
- ok.
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: void
-%%-----------------------------------------------------------------
-void_type(Config) when is_list(Config) ->
- B = cdr_encode:enc_type(#giop_env{version = {1, 1}}, 'tk_void', 'ok'),
- {'ok', <<>>, _} = cdr_decode:dec_type('tk_void', {1, 1}, B, 0, big),
- ok.
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: principal
-%%-----------------------------------------------------------------
-principal_type(Config) when is_list(Config) ->
- B0 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, 'tk_Principal', "principal"),
- {"principal", <<>>, _} = cdr_decode:dec_type('tk_Principal', {1, 1}, B0, 0, big),
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, 'tk_Principal', ""),
- {"", <<>>, _} = cdr_decode:dec_type('tk_Principal', {1, 1}, B1, 0, big),
- B2 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, 'tk_Principal', "principal"),
- {"principal", <<>>, _} =
- cdr_decode:dec_type('tk_Principal', {1, 1}, B2, 0, big),
- ok.
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: object reference
-%%-----------------------------------------------------------------
-version() -> #'IIOP_Version'{major=1,minor=1}.
-
-objref(0) ->
- PB = #'IIOP_ProfileBody_1_1'{iiop_version=version(),
- host="my.hostname.org",
- port=4040,
- object_key="ExternalKey: which is an arbitary octet sequence",
- components=[]},
- TP = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB},
- #'IOP_IOR'{type_id="IDL:Module/Interface:1.0", profiles=[TP]};
-objref(1) ->
- K = corba_fake_mk_objkey("IDL:Module/Interface:1.0", key,
- list_to_pid("<0.100.0>")),
- PB = #'IIOP_ProfileBody_1_1'{iiop_version=version(),
- host="my.hostname.org",
- port=4040,
- object_key=K, components=[]},
- TP = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB},
- #'IOP_IOR'{type_id="IDL:Module/Interface:1.0", profiles=[TP]};
-objref(2) ->
- K = corba_fake_mk_objkey("IDL:Module/Interface:1.0", registered,
- list_to_atom("orber_nameservice")),
- PB = #'IIOP_ProfileBody_1_1'{iiop_version=version(),
- host="my.hostname.org",
- port=4040,
- object_key=K, components=[]},
- TP = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB},
- #'IOP_IOR'{type_id="IDL:Module/Interface:1.0", profiles=[TP]}.
-
-objref_type(Config) when is_list(Config) ->
- T = {'tk_objref', "IDL:Module/Interface:1.0", "Interface"},
- Objref0 = objref(0),
- B0 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T, Objref0),
- {Objref0, <<>>, _} = cdr_decode:dec_type(T, {1, 1}, B0, 0, big),
- Objref1 = objref(1),
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T, Objref1),
- {Objref1, <<>>, _} = cdr_decode:dec_type(T, {1, 1}, B1, 0, big),
- Objref2 = objref(2),
- B2 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T, Objref2),
- {Objref2, <<>>, _} = cdr_decode:dec_type(T, {1, 1}, B2, 0, big),
- ok.
-
-
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: struct
-%%-----------------------------------------------------------------
-struct_type(Config) when is_list(Config) ->
- T0 = {'tk_struct',"IDL:Module/Struct0:1.0", "Module_Struct0",
- [{"long", 'tk_long'}, {"short", 'tk_short'}, {"character", 'tk_char'}]},
- S0 = #'Module_Struct0'{l=-4711, s=17, c=$a},
- B0 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T0, S0),
- {S0, <<>>, _} = cdr_decode:dec_type(T0, {1, 1}, B0, 0, big),
-
- T1 = {'tk_struct', "IDL:Module/Struct1:1.0", "Module_Struct1",
- [{"string", {'tk_string', 0}}, {"ushort", 'tk_ushort'}, {"ulong", 'tk_ulong'}]},
- S1 = #'Module_Struct1'{s="Hi !!!!", us=17, ul=4711},
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T1, S1),
- {S1, <<>>, _} = cdr_decode:dec_type(T1, {1, 1}, B1, 0, big),
-
- T2 = {'tk_struct', "IDL:Module/Struct2:1.0", "Module_Struct2",
- [{"long_sequence", {'tk_sequence', 'tk_long', 0}},
- {"enum", {'tk_enum', "IDL:Module/Enum:1.0", "Module_Enum", ["horse", "pig", "cow"]}},
- {"octet", 'tk_octet'}]},
- S2 = #'Module_Struct2'{long_sequence=[4711, 350000, 0, -3030, -600000], e=cow, o=$X},
- B2 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T2, S2),
- {S2, <<>>, _} = cdr_decode:dec_type(T2, {1, 1}, B2, 0, big),
- ok.
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: union
-%%-----------------------------------------------------------------
-union_type(Config) when is_list(Config) ->
- T0 = {'tk_union', "IDL:Module/Union:1.0", "Union", 'tk_short', 2,
- [{0, "First", 'tk_short'},
- {1, "Second", {'tk_string', 0}},
- {2, "Third", 'tk_char'}]},
- S0 = #'Module_Union'{label=1, value="Foo Bar !"},
- B0 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T0, S0),
- {S0, <<>>, _} = cdr_decode:dec_type(T0, {1, 1}, B0, 0, big),
- S1 = #'Module_Union'{label=0, value=-17},
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T0, S1),
- {S1, <<>>, _} = cdr_decode:dec_type(T0, {1, 1}, B1, 0, big),
- S2 = #'Module_Union'{label=2, value=$X},
- B2 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T0, S2),
- {S2, <<>>, _} = cdr_decode:dec_type(T0, {1, 1}, B2, 0, big),
- T1 = {'tk_union', "IDL:Module/Union1:1.0", "Union1",
- {'tk_enum', "IDL:Module/Enum:1.0",
- "Module_Enum", ["horse", "pig", "cow"]}, "pig",
- [{"horse", "First", 'tk_ushort'},
- {"pig", "Second", {'tk_sequence', {'tk_string', 0}, 0}},
- {"cow", "Third", {'tk_enum', "IDL:Module/Enum1:1.0",
- "Module_Enum1", ["orange", "banana", "apple"]}}]},
- S3 = #'Module_Union1'{label=pig, value=["Foo", "Bar", "!"]},
- B3 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T1, S3),
- {S3, <<>>, _} = cdr_decode:dec_type(T1, {1, 1}, B3, 0, big),
- S4 = #'Module_Union1'{label=cow, value=apple},
- B4 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T1, S4),
- {S4, <<>>, _} = cdr_decode:dec_type(T1, {1, 1}, B4, 0, big),
- S5 = #'Module_Union1'{label=horse, value=17},
- B5 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T1, S5),
- {S5, <<>>, _} = cdr_decode:dec_type(T1, {1, 1}, B5, 0, big),
- T2 = {'tk_union', "IDL:Module/Union2:1.0", "Union2",
- {'tk_enum', "IDL:Module/Enum:1.0",
- "Module_Enum", ["horse", "pig", "cow"]}, "pig",
- [{"horse", "First", {'tk_array', 'tk_long', 3}},
- {"pig", "Second",
- {'tk_union', "IDL:Module/Union:1.0", "Union", 'tk_short', 2,
- [{0, "First", 'tk_short'},
- {1, "Second", {'tk_string', 0}},
- {2, "Third", 'tk_char'}]}},
- {"cow", "Third", {'tk_union', "IDL:Module/Union1:1.0", "Union1",
- {'tk_enum', "IDL:Module/Enum:1.0",
- "Module_Enum", ["horse", "pig", "cow"]}, "pig",
- [{"horse", "First", 'tk_ushort'},
- {"pig", "Second", {'tk_sequence',
- {'tk_string', 0}, 0}},
- {"cow", "Third", {'tk_enum',
- "IDL:Module/Enum1:1.0",
- "Module_Enum1",
- ["orange", "banana",
- "apple"]}}]}}]},
- S6 = #'Module_Union2'{label=pig, value=#'Module_Union'{label=0, value=-17}},
- B6 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T2, S6),
- {S6, <<>>, _} = cdr_decode:dec_type(T2, {1, 1}, B6, 0, big),
- S7 = #'Module_Union2'{label=cow, value=#'Module_Union1'{label=pig,
- value=["Foo", "Bar", "!"]}},
- B7 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T2, S7),
- {S7, <<>>, _} = cdr_decode:dec_type(T2, {1, 1}, B7, 0, big),
- S8 = #'Module_Union2'{label=horse, value={-17, 1234567890, -987654321}},
- B8 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T2, S8),
- {S8, <<>>, _} = cdr_decode:dec_type(T2, {1, 1}, B8, 0, big),
- ok.
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: string
-%%-----------------------------------------------------------------
-string_type(Config) when is_list(Config) ->
- S0 = "Foo Bar ???",
- B0 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, {'tk_string', 0}, S0),
- {S0, <<>>, _} = cdr_decode:dec_type({'tk_string', 0}, {1, 1}, B0, 0, big),
- S1 = "Yes, Foo Bar !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! more than 5000 characters",
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, {'tk_string', 0}, S1),
- {S1, <<>>, _} = cdr_decode:dec_type({'tk_string', 0}, {1, 1}, B1, 0, big),
- S2 = "",
- B2 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, {'tk_string', 0}, S2),
- {S2, <<>>, _} = cdr_decode:dec_type({'tk_string', 0}, {1, 1}, B2, 0, big),
- S3 = "\0",
- B3 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, {'tk_string', 0}, S3),
- {S3, <<>>, _} = cdr_decode:dec_type({'tk_string', 0}, {1, 1}, B3, 0, big),
- S4 = "~n",
- B4 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, {'tk_string', 0}, S4),
- {S4, <<>>, _} = cdr_decode:dec_type({'tk_string', 0}, {1, 1}, B4, 0, big),
- ok.
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: array
-%%-----------------------------------------------------------------
-array_type(Config) when is_list(Config) ->
- T0 = {'tk_array', 'tk_long', 5},
- S0 = {-100, 0, 30000, -900100900, 123456789},
- B0 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T0, S0),
- {S0, <<>>, _} = cdr_decode:dec_type(T0, {1, 1}, B0, 0, big),
- T1 = {'tk_array', {'tk_enum', "IDL:Module/Enum:1.0", "Module_Enum", ["horse", "pig", "cow"]}, 2},
- S1 = {pig, cow},
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T1, S1),
- {S1, <<>>, _} = cdr_decode:dec_type(T1, {1, 1}, B1, 0, big),
- T2 = {'tk_array', {'tk_union', "IDL:Module/Union:1.0", "Union",
- {'tk_enum', "IDL:Module/Enum:1.0", "Module_Enum", ["horse", "pig", "cow"]}, "pig",
- [{"horse", "First", 'tk_ushort'},
- {"pig", "Second", {'tk_sequence', {'tk_string', 0}, 0}},
- {"cow", "Third", {'tk_enum', "IDL:Module/Enum1:1.0",
- "Module_Enum1", ["orange", "banana", "apple"]}}]}, 2},
- S2 = {#'Module_Union'{label=cow, value=banana}, #'Module_Union'{label=pig, value=["This", "is", "a", "test", ""]}},
- B2 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T2, S2),
- {S2, <<>>, _} = cdr_decode:dec_type(T2, {1, 1}, B2, 0, big),
- T3 = {'tk_array', {'tk_objref', "IDL:Module/Interface:1.0", "Interface"}, 3},
- S3 = {objref(0), objref(1), objref(2)},
- B3 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T3, S3),
- {S3, <<>>, _} = cdr_decode:dec_type(T3, {1, 1}, B3, 0, big),
- ok.
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: TypeCode
-%%-----------------------------------------------------------------
-any_type(Config) when is_list(Config) ->
- T = 'tk_any',
- TC = {'tk_struct', "IDL:Module/Struct2:1.0", "Module_Struct2",
- [{"long_sequence", {'tk_sequence', 'tk_long', 0}},
- {"enum", {'tk_enum', "IDL:Module/Enum:1.0", "Module_Enum",
- ["horse", "pig", "cow"]}},
- {"octet", 'tk_octet'}]},
- S = #'Module_Struct2'{long_sequence=[4711, 350000, 0, -3030, -600000],
- e=cow, o=$X},
- Any = #any{typecode=TC,value=S},
- B = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T,Any),
- {Any, <<>>, _} = cdr_decode:dec_type(T, {1, 1}, B, 0, big),
- TC1 = {'tk_array', {'tk_union', "IDL:Module/Union:1.0", "Union",
- {'tk_enum', "IDL:Module/Enum:1.0", "Module_Enum",
- ["horse", "pig", "cow"]}, 1,
- [{"horse", "First", 'tk_ushort'},
- {"pig", "Second", {'tk_sequence', {'tk_string', 0}, 0}},
- {"cow", "Third", {'tk_enum', "IDL:Module/Enum1:1.0",
- "Module_Enum1", ["orange", "banana",
- "apple"]}}]},2},
- S1 = {#'Module_Union'{label=cow, value=banana}, #'Module_Union'{label=pig, value=["This", "is", "a", "test", ""]}},
- Any1 = #any{typecode=TC1,value=S1},
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T,Any1),
- {Any1, <<>>, _} = cdr_decode:dec_type(T, {1, 1}, B1, 0, big),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: TypeCode
-%%-----------------------------------------------------------------
-typecode_type(Config) when is_list(Config) ->
- T = 'tk_TypeCode',
- TC = {'tk_array', {'tk_union', "IDL:Module/Union:1.0", "Union",
- {'tk_enum', "IDL:Module/Enum:1.0", "Module_Enum",
- ["horse", "pig", "cow"]}, 1,
- [{"horse", "First", 'tk_ushort'},
- {"pig", "Second", {'tk_sequence', {'tk_string', 0}, 0}},
- {"cow", "Third", {'tk_enum', "IDL:Module/Enum1:1.0",
- "Module_Enum1", ["orange", "banana",
- "apple"]}}]}, 10},
- B = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T,TC),
- {TC, <<>>, _} = cdr_decode:dec_type(T, {1, 1}, B, 0, big),
- TC1 = {'tk_union', "IDL:Module/Union2:1.0", "Union2",
- {'tk_enum', "IDL:Module/Enum:1.0",
- "Module_Enum", ["horse", "pig", "cow"]}, 2,
- [{"horse", "First", 'tk_long'},
- {"pig", "Second",
- {'tk_union', "IDL:Module/Union:1.0", "Union", 'tk_short', 2,
- [{0, "First", 'tk_short'},
- {1, "Second", {'tk_string', 0}},
- {2, "Third", 'tk_char'}]}},
- {"cow", "Third", {'tk_union', "IDL:Module/Union1:1.0", "Union1",
- {'tk_enum', "IDL:Module/Enum:1.0",
- "Module_Enum", ["horse", "pig", "cow"]}, 2,
- [{"horse", "First", 'tk_ushort'},
- {"pig", "Second", {'tk_sequence',
- {'tk_string', 0}, 0}},
- {"cow", "Third", {'tk_enum',
- "IDL:Module/Enum1:1.0",
- "Module_Enum1",
- ["orange", "banana",
- "apple"]}}]}}]},
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T, TC1),
- {TC1, <<>>, _} = cdr_decode:dec_type(T, {1, 1}, B1, 0, big),
- ok.
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: TypeCode
-%%-----------------------------------------------------------------
-alias_type(Config) when is_list(Config) ->
- T = {'tk_alias', "IDL:Module/Alias:1.0", "Alias",
- {'tk_struct', "IDL:Module/Struct2:1.0", "Module_Struct2",
- [{"long_sequence", {'tk_sequence', 'tk_long', 0}},
- {"enum", {'tk_enum', "IDL:Module/Enum:1.0", "Module_Enum",
- ["horse", "pig", "cow"]}},
- {"octet", 'tk_octet'}]}},
- S = #'Module_Struct2'{long_sequence=[4711, 350000, 0, -3030, -600000],
- e=cow, o=$X},
- B = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T,S),
- {S, <<>>, _} = cdr_decode:dec_type(T, {1, 1}, B, 0, big),
- T1 = {'tk_alias', "IDL:Module/Alias1:1.0", "Alias1",
- {'tk_sequence', {'tk_union', "IDL:Module/Union:1.0", "Union",
- {'tk_enum', "IDL:Module/Enum:1.0", "Module_Enum",
- ["horse", "pig", "cow"]}, 2,
- [{"horse", "First", 'tk_ushort'},
- {"pig", "Second", {'tk_sequence', {'tk_string', 0}, 0}},
- {"cow", "Third", {'tk_enum', "IDL:Module/Enum1:1.0",
- "Module_Enum1", ["orange", "banana",
- "apple"]}}]},0}},
- S1 = [#'Module_Union'{label=cow, value=banana}, #'Module_Union'{label=pig, value=["This", "is", "a", "test", ""]}],
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T1, S1),
- {S1, <<>>, _} = cdr_decode:dec_type(T1, {1, 1}, B1, 0, big),
- ok.
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: exception
-%%-----------------------------------------------------------------
-exception_type(Config) when is_list(Config) ->
- system_exceptions(),
- user_exceptions(),
- ok.
-
-system_exceptions() ->
- E = #'UNKNOWN'{completion_status=?COMPLETED_YES},
- {system_exception, T, E} = orber_exceptions:get_def(E),
- B = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T,E),
- {E, _} = cdr_decode:dec_system_exception({1, 1}, B, 0, big),
- E1 = #'INV_OBJREF'{completion_status=?COMPLETED_NO},
- {system_exception, T1, E1} = orber_exceptions:get_def(E1),
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T1,E1),
- {E1, _} = cdr_decode:dec_system_exception({1, 1}, B1, 0, big),
- E2 = #'BAD_OPERATION'{completion_status=?COMPLETED_NO},
- {system_exception, T2, E2} = orber_exceptions:get_def(E2),
- B2 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T2,E2),
- {E2, _} = cdr_decode:dec_system_exception({1, 1}, B2, 0, big),
- E3 = #'INTF_REPOS'{completion_status=?COMPLETED_MAYBE},
- {system_exception, T3, E3} = orber_exceptions:get_def(E3),
- B3 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T3,E3),
- {E3, _} = cdr_decode:dec_system_exception({1, 1}, B3, 0, big),
- ok.
-
-user_exceptions() ->
- E = #'Module_Except1'{rest_of_name=["I","am","testing","exceptions"], why="Error"},
- {user_exception, T, E} = orber_exceptions:get_def(E),
- B = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T, E),
- {E, _} = cdr_decode:dec_user_exception({1, 1}, B, 0, big),
- E1 = #'Module_Except2'{e=banana,
- s=#'Module_Struct2'{long_sequence=[12,-4040,
- 1234567898],
- e=horse,
- o=$a}},
- {user_exception, T1, E1} = orber_exceptions:get_def(E1),
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T1, E1),
- {E1, _} = cdr_decode:dec_user_exception({1, 1}, B1, 0, big),
- E2 = #'Module_Except3'{u=#'Module_Union1'{label=pig,value=["high","and","low"]},s=1313, o=objref(0)},
- {user_exception, T2, E2} = orber_exceptions:get_def(E2),
- B2 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T2, E2),
- {E2, _} = cdr_decode:dec_user_exception({1, 1}, B2, 0, big),
- E3 = #'Module_Except4'{},
- {user_exception, T3, E3} = orber_exceptions:get_def(E3),
- B3 = cdr_encode:enc_type(#giop_env{version = {1, 1}}, T3, E3),
- {E3, _} = cdr_decode:dec_user_exception({1, 1}, B3, 0, big),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: request encoding test
-%% Description: Precondition the stack must be started so the
-%% objectkey is valid.
-%%-----------------------------------------------------------------
-%request(_) ->
-% exit(not_implemented).
-
-%%-----------------------------------------------------------------
-%% Test Case: reply encoding test
-%% Description:
-%%-----------------------------------------------------------------
-reply(Config) when is_list(Config) ->
- R = #reply_header{service_context=[], request_id=1,
- reply_status='no_exception'},
- B = cdr_encode:enc_reply(#giop_env{version = {1, 1}, request_id = 1,
- reply_status = 'no_exception',
- tc = {'tk_long', [], [{'tk_sequence',
- {'tk_string', 0}, 0}]},
- result = 1200, parameters = [["foo","Bar"]],
- ctx = []}),
- {R, 1200, [["foo","Bar"]]} =
- cdr_decode:dec_message({'tk_long', [], [{'tk_sequence', {'tk_string', 0},0}]},
- B),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: cancel_request encoding test
-%% Description:
-%%-----------------------------------------------------------------
-cancel_request(Config) when is_list(Config) ->
- R = #cancel_request_header{request_id=1},
- B = cdr_encode:enc_cancel_request(#giop_env{version = {1, 1},
- request_id = 1}),
- R = cdr_decode:dec_message([], B),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: locate_request encoding test
-%% Description:
-%%-----------------------------------------------------------------
-locate_request(Config) when is_list(Config) ->
- io:format("Function not imlpemented yet"),
- exit(not_implemented).
-
-%%-----------------------------------------------------------------
-%% Test Case: locate_reply encoding test
-%% Description:
-%%-----------------------------------------------------------------
-locate_reply(Config) when is_list(Config) ->
- io:format("Function not imlpemented yet"),
- exit(not_implemented).
-
-%%-----------------------------------------------------------------
-%% Test Case: close_connection encoding test
-%% Description:
-%%-----------------------------------------------------------------
-close_connection(Config) when is_list(Config) ->
- B = cdr_encode:enc_close_connection(#giop_env{version = {1, 1}}),
- 'close_connection' = cdr_decode:dec_message([], B),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: message_error encoding test
-%% Description:
-%%-----------------------------------------------------------------
-message_error(Config) when is_list(Config) ->
- B = cdr_encode:enc_message_error(#giop_env{version = {1, 1}}),
- 'message_error' = cdr_decode:dec_message([], B),
- ok.
-
-
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-corba_fake_mk_objkey(Id, 'key', Pid) when is_pid(Pid) ->
- Key = make_objkey(),
- {list_to_binary(Id), 'key', Key, term_to_binary(undefined),
- term_to_binary(undefined), term_to_binary(undefined)};
-corba_fake_mk_objkey(Id, 'key', RegName) when is_atom(RegName) ->
- Key = term_to_binary(RegName),
- {list_to_binary(Id), 'key', Key, term_to_binary(undefined),
- term_to_binary(undefined), term_to_binary(undefined)};
-corba_fake_mk_objkey(Id, 'registered', RegName) when is_atom(RegName) ->
- {list_to_binary(Id), 'registered', RegName, term_to_binary(undefined),
- term_to_binary(undefined), term_to_binary(undefined)}.
-
-make_objkey() ->
- term_to_binary({{erlang:system_time(),
- erlang:unique_integer()},
- node()}).
diff --git a/lib/orber/test/cdrcoding_12_SUITE.erl b/lib/orber/test/cdrcoding_12_SUITE.erl
deleted file mode 100644
index 13178b7774..0000000000
--- a/lib/orber/test/cdrcoding_12_SUITE.erl
+++ /dev/null
@@ -1,575 +0,0 @@
-%%----------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%%
-%% Description:
-%% Test suite for the CDR encode/decode functions
-%%
-%%-----------------------------------------------------------------
-
--module(cdrcoding_12_SUITE).
-
--include("idl_output/Module.hrl").
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
-
--define(default_timeout, test_server:minutes(5)).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--compile(export_all).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- cases().
-
-groups() ->
- [{types, [],
- [do_register, null_type, void_type, principal_type,
- objref_type, struct_type, union_type, string_type,
- array_type, any_type, typecode_type, alias_type,
- exception_type, do_unregister]}].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-cases() ->
- [{group, types}, reply, cancel_request,
- close_connection, message_error].
-%% request, locate_request, locate_reply].
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-
-init_per_testcase(_Case, Config) ->
- Path = code:which(?MODULE),
- code:add_pathz(filename:join(filename:dirname(Path), "idl_output")),
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- Path = code:which(?MODULE),
- code:del_path(filename:join(filename:dirname(Path), "idl_output")),
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-init_per_suite(Config) when is_list(Config) ->
- orber:jump_start(0),
- if
- is_list(Config) ->
- Config;
- true ->
- exit("Config not a list")
- end.
-
-end_per_suite(Config) when is_list(Config) ->
- orber:jump_stop(),
- Config.
-
-%%-----------------------------------------------------------------
-%% Test Case: type encoding tests
-%% Description: Just testing the complex types, the others are
-%% tested in the cdrlib SUITE.
-%%-----------------------------------------------------------------
-
-do_register(Config) when is_list(Config) ->
- 'oe_orber_test':'oe_register'(),
- ok.
-
-do_unregister(Config) when is_list(Config) ->
- 'oe_orber_test':'oe_unregister'(),
- ok.
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: null
-%%-----------------------------------------------------------------
-null_type(Config) when is_list(Config) ->
- B = cdr_encode:enc_type(#giop_env{version = {1, 2}}, 'tk_null', 'null'),
- {'null', <<>>, _} = cdr_decode:dec_type('tk_null', {1, 2}, B, 0, big),
- ok.
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: void
-%%-----------------------------------------------------------------
-void_type(Config) when is_list(Config) ->
- B = cdr_encode:enc_type(#giop_env{version = {1, 2}}, 'tk_void', 'ok'),
- {'ok', <<>>, _} = cdr_decode:dec_type('tk_void', {1, 2}, B, 0, big),
- ok.
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: principal
-%%-----------------------------------------------------------------
-principal_type(Config) when is_list(Config) ->
- B0 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, 'tk_Principal', "principal"),
- {"principal", <<>>, _} = cdr_decode:dec_type('tk_Principal', {1, 2}, B0, 0, big),
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, 'tk_Principal', ""),
- {"", <<>>, _} = cdr_decode:dec_type('tk_Principal', {1, 2}, B1, 0, big),
- B2 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, 'tk_Principal', "principal"),
- {"principal", <<>>, _} =
- cdr_decode:dec_type('tk_Principal', {1, 2}, B2, 0, big),
- ok.
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: object reference
-%%-----------------------------------------------------------------
-version() -> #'IIOP_Version'{major=1,minor=2}.
-
-objref(0) ->
- PB = #'IIOP_ProfileBody_1_1'{iiop_version=version(),
- host="my.hostname.org",
- port=4040,
- object_key="ExternalKey: which is an arbitary octet sequence",
- components=[]},
- TP = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB},
- #'IOP_IOR'{type_id="IDL:Module/Interface:1.0", profiles=[TP]};
-objref(1) ->
- K = corba_fake_mk_objkey("IDL:Module/Interface:1.0", key,
- list_to_pid("<0.100.0>")),
- PB = #'IIOP_ProfileBody_1_1'{iiop_version=version(),
- host="my.hostname.org",
- port=4040,
- object_key=K, components=[]},
- TP = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB},
- #'IOP_IOR'{type_id="IDL:Module/Interface:1.0", profiles=[TP]};
-objref(2) ->
- K = corba_fake_mk_objkey("IDL:Module/Interface:1.0", registered,
- list_to_atom("orber_nameservice")),
- PB = #'IIOP_ProfileBody_1_1'{iiop_version=version(),
- host="my.hostname.org",
- port=4040,
- object_key=K, components=[]},
- TP = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB},
- #'IOP_IOR'{type_id="IDL:Module/Interface:1.0", profiles=[TP]}.
-
-objref_type(Config) when is_list(Config) ->
- T = {'tk_objref', "IDL:Module/Interface:1.0", "Interface"},
- Objref0 = objref(0),
- B0 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T, Objref0),
- {Objref0, <<>>, _} = cdr_decode:dec_type(T, {1, 2}, B0, 0, big),
- Objref1 = objref(1),
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T, Objref1),
- {Objref1, <<>>, _} = cdr_decode:dec_type(T, {1, 2}, B1, 0, big),
- Objref2 = objref(2),
- B2 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T, Objref2),
- {Objref2, <<>>, _} = cdr_decode:dec_type(T, {1, 2}, B2, 0, big),
- ok.
-
-
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: struct
-%%-----------------------------------------------------------------
-struct_type(Config) when is_list(Config) ->
- T0 = {'tk_struct',"IDL:Module/Struct0:1.0", "Module_Struct0",
- [{"long", 'tk_long'}, {"short", 'tk_short'}, {"character", 'tk_char'}]},
- S0 = #'Module_Struct0'{l=-4711, s=17, c=$a},
- B0 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T0, S0),
- {S0, <<>>, _} = cdr_decode:dec_type(T0, {1, 2}, B0, 0, big),
-
- T1 = {'tk_struct', "IDL:Module/Struct1:1.0", "Module_Struct1",
- [{"string", {'tk_string', 0}}, {"ushort", 'tk_ushort'}, {"ulong", 'tk_ulong'}]},
- S1 = #'Module_Struct1'{s="Hi !!!!", us=17, ul=4711},
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T1, S1),
- {S1, <<>>, _} = cdr_decode:dec_type(T1, {1, 2}, B1, 0, big),
-
- T2 = {'tk_struct', "IDL:Module/Struct2:1.0", "Module_Struct2",
- [{"long_sequence", {'tk_sequence', 'tk_long', 0}},
- {"enum", {'tk_enum', "IDL:Module/Enum:1.0", "Module_Enum", ["horse", "pig", "cow"]}},
- {"octet", 'tk_octet'}]},
- S2 = #'Module_Struct2'{long_sequence=[4711, 350000, 0, -3030, -600000], e=cow, o=$X},
- B2 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T2, S2),
- {S2, <<>>, _} = cdr_decode:dec_type(T2, {1, 2}, B2, 0, big),
- ok.
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: union
-%%-----------------------------------------------------------------
-union_type(Config) when is_list(Config) ->
- T0 = {'tk_union', "IDL:Module/Union:1.0", "Union", 'tk_short', 2,
- [{0, "First", 'tk_short'},
- {1, "Second", {'tk_string', 0}},
- {2, "Third", 'tk_char'}]},
- S0 = #'Module_Union'{label=1, value="Foo Bar !"},
- B0 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T0, S0),
- {S0, <<>>, _} = cdr_decode:dec_type(T0, {1, 2}, B0, 0, big),
- S1 = #'Module_Union'{label=0, value=-17},
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T0, S1),
- {S1, <<>>, _} = cdr_decode:dec_type(T0, {1, 2}, B1, 0, big),
- S2 = #'Module_Union'{label=2, value=$X},
- B2 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T0, S2),
- {S2, <<>>, _} = cdr_decode:dec_type(T0, {1, 2}, B2, 0, big),
- T1 = {'tk_union', "IDL:Module/Union1:1.0", "Union1",
- {'tk_enum', "IDL:Module/Enum:1.0",
- "Module_Enum", ["horse", "pig", "cow"]}, "pig",
- [{"horse", "First", 'tk_ushort'},
- {"pig", "Second", {'tk_sequence', {'tk_string', 0}, 0}},
- {"cow", "Third", {'tk_enum', "IDL:Module/Enum1:1.0",
- "Module_Enum1", ["orange", "banana", "apple"]}}]},
- S3 = #'Module_Union1'{label=pig, value=["Foo", "Bar", "!"]},
- B3 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T1, S3),
- {S3, <<>>, _} = cdr_decode:dec_type(T1, {1, 2}, B3, 0, big),
- S4 = #'Module_Union1'{label=cow, value=apple},
- B4 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T1, S4),
- {S4, <<>>, _} = cdr_decode:dec_type(T1, {1, 2}, B4, 0, big),
- S5 = #'Module_Union1'{label=horse, value=17},
- B5 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T1, S5),
- {S5, <<>>, _} = cdr_decode:dec_type(T1, {1, 2}, B5, 0, big),
- T2 = {'tk_union', "IDL:Module/Union2:1.0", "Union2",
- {'tk_enum', "IDL:Module/Enum:1.0",
- "Module_Enum", ["horse", "pig", "cow"]}, "pig",
- [{"horse", "First", {'tk_array', 'tk_long', 3}},
- {"pig", "Second",
- {'tk_union', "IDL:Module/Union:1.0", "Union", 'tk_short', 2,
- [{0, "First", 'tk_short'},
- {1, "Second", {'tk_string', 0}},
- {2, "Third", 'tk_char'}]}},
- {"cow", "Third", {'tk_union', "IDL:Module/Union1:1.0", "Union1",
- {'tk_enum', "IDL:Module/Enum:1.0",
- "Module_Enum", ["horse", "pig", "cow"]}, "pig",
- [{"horse", "First", 'tk_ushort'},
- {"pig", "Second", {'tk_sequence',
- {'tk_string', 0}, 0}},
- {"cow", "Third", {'tk_enum',
- "IDL:Module/Enum1:1.0",
- "Module_Enum1",
- ["orange", "banana",
- "apple"]}}]}}]},
- S6 = #'Module_Union2'{label=pig, value=#'Module_Union'{label=0, value=-17}},
- B6 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T2, S6),
- {S6, <<>>, _} = cdr_decode:dec_type(T2, {1, 2}, B6, 0, big),
- S7 = #'Module_Union2'{label=cow, value=#'Module_Union1'{label=pig,
- value=["Foo", "Bar", "!"]}},
- B7 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T2, S7),
- {S7, <<>>, _} = cdr_decode:dec_type(T2, {1, 2}, B7, 0, big),
- S8 = #'Module_Union2'{label=horse, value={-17, 1234567890, -987654321}},
- B8 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T2, S8),
- {S8, <<>>, _} = cdr_decode:dec_type(T2, {1, 2}, B8, 0, big),
- ok.
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: string
-%%-----------------------------------------------------------------
-string_type(Config) when is_list(Config) ->
- S0 = "Foo Bar ???",
- B0 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, {'tk_string', 0}, S0),
- {S0, <<>>, _} = cdr_decode:dec_type({'tk_string', 0}, {1, 2}, B0, 0, big),
- S1 = "Yes, Foo Bar !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! more than 5000 characters",
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, {'tk_string', 0}, S1),
- {S1, <<>>, _} = cdr_decode:dec_type({'tk_string', 0}, {1, 2}, B1, 0, big),
- S2 = "",
- B2 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, {'tk_string', 0}, S2),
- {S2, <<>>, _} = cdr_decode:dec_type({'tk_string', 0}, {1, 2}, B2, 0, big),
- S3 = "\0",
- B3 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, {'tk_string', 0}, S3),
- {S3, <<>>, _} = cdr_decode:dec_type({'tk_string', 0}, {1, 2}, B3, 0, big),
- S4 = "~n",
- B4 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, {'tk_string', 0}, S4),
- {S4, <<>>, _} = cdr_decode:dec_type({'tk_string', 0}, {1, 2}, B4, 0, big),
- ok.
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: array
-%%-----------------------------------------------------------------
-array_type(Config) when is_list(Config) ->
- T0 = {'tk_array', 'tk_long', 5},
- S0 = {-100, 0, 30000, -900100900, 123456789},
- B0 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T0, S0),
- {S0, <<>>, _} = cdr_decode:dec_type(T0, {1, 2}, B0, 0, big),
- T1 = {'tk_array', {'tk_enum', "IDL:Module/Enum:1.0", "Module_Enum", ["horse", "pig", "cow"]}, 2},
- S1 = {pig, cow},
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T1, S1),
- {S1, <<>>, _} = cdr_decode:dec_type(T1, {1, 2}, B1, 0, big),
- T2 = {'tk_array', {'tk_union', "IDL:Module/Union:1.0", "Union",
- {'tk_enum', "IDL:Module/Enum:1.0", "Module_Enum", ["horse", "pig", "cow"]}, "pig",
- [{"horse", "First", 'tk_ushort'},
- {"pig", "Second", {'tk_sequence', {'tk_string', 0}, 0}},
- {"cow", "Third", {'tk_enum', "IDL:Module/Enum1:1.0",
- "Module_Enum1", ["orange", "banana", "apple"]}}]}, 2},
- S2 = {#'Module_Union'{label=cow, value=banana}, #'Module_Union'{label=pig, value=["This", "is", "a", "test", ""]}},
- B2 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T2, S2),
- {S2, <<>>, _} = cdr_decode:dec_type(T2, {1, 2}, B2, 0, big),
- T3 = {'tk_array', {'tk_objref', "IDL:Module/Interface:1.0", "Interface"}, 3},
- S3 = {objref(0), objref(1), objref(2)},
- B3 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T3, S3),
- {S3, <<>>, _} = cdr_decode:dec_type(T3, {1, 2}, B3, 0, big),
- ok.
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: TypeCode
-%%-----------------------------------------------------------------
-any_type(Config) when is_list(Config) ->
- T = 'tk_any',
- TC = {'tk_struct', "IDL:Module/Struct2:1.0", "Module_Struct2",
- [{"long_sequence", {'tk_sequence', 'tk_long', 0}},
- {"enum", {'tk_enum', "IDL:Module/Enum:1.0", "Module_Enum",
- ["horse", "pig", "cow"]}},
- {"octet", 'tk_octet'}]},
- S = #'Module_Struct2'{long_sequence=[4711, 350000, 0, -3030, -600000],
- e=cow, o=$X},
- Any = #any{typecode=TC,value=S},
- B = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T,Any),
- {Any, <<>>, _} = cdr_decode:dec_type(T, {1, 2}, B, 0, big),
- TC1 = {'tk_array', {'tk_union', "IDL:Module/Union:1.0", "Union",
- {'tk_enum', "IDL:Module/Enum:1.0", "Module_Enum",
- ["horse", "pig", "cow"]}, 1,
- [{"horse", "First", 'tk_ushort'},
- {"pig", "Second", {'tk_sequence', {'tk_string', 0}, 0}},
- {"cow", "Third", {'tk_enum', "IDL:Module/Enum1:1.0",
- "Module_Enum1", ["orange", "banana",
- "apple"]}}]},2},
- S1 = {#'Module_Union'{label=cow, value=banana}, #'Module_Union'{label=pig, value=["This", "is", "a", "test", ""]}},
- Any1 = #any{typecode=TC1,value=S1},
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T,Any1),
- {Any1, <<>>, _} = cdr_decode:dec_type(T, {1, 2}, B1, 0, big),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: TypeCode
-%%-----------------------------------------------------------------
-typecode_type(Config) when is_list(Config) ->
- T = 'tk_TypeCode',
- TC = {'tk_array', {'tk_union', "IDL:Module/Union:1.0", "Union",
- {'tk_enum', "IDL:Module/Enum:1.0", "Module_Enum",
- ["horse", "pig", "cow"]}, 1,
- [{"horse", "First", 'tk_ushort'},
- {"pig", "Second", {'tk_sequence', {'tk_string', 0}, 0}},
- {"cow", "Third", {'tk_enum', "IDL:Module/Enum1:1.0",
- "Module_Enum1", ["orange", "banana",
- "apple"]}}]}, 10},
- B = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T,TC),
- {TC, <<>>, _} = cdr_decode:dec_type(T, {1, 2}, B, 0, big),
- TC1 = {'tk_union', "IDL:Module/Union2:1.0", "Union2",
- {'tk_enum', "IDL:Module/Enum:1.0",
- "Module_Enum", ["horse", "pig", "cow"]}, 2,
- [{"horse", "First", 'tk_long'},
- {"pig", "Second",
- {'tk_union', "IDL:Module/Union:1.0", "Union", 'tk_short', 2,
- [{0, "First", 'tk_short'},
- {1, "Second", {'tk_string', 0}},
- {2, "Third", 'tk_char'}]}},
- {"cow", "Third", {'tk_union', "IDL:Module/Union1:1.0", "Union1",
- {'tk_enum', "IDL:Module/Enum:1.0",
- "Module_Enum", ["horse", "pig", "cow"]}, 2,
- [{"horse", "First", 'tk_ushort'},
- {"pig", "Second", {'tk_sequence',
- {'tk_string', 0}, 0}},
- {"cow", "Third", {'tk_enum',
- "IDL:Module/Enum1:1.0",
- "Module_Enum1",
- ["orange", "banana",
- "apple"]}}]}}]},
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T, TC1),
- {TC1, <<>>, _} = cdr_decode:dec_type(T, {1, 2}, B1, 0, big),
- ok.
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: TypeCode
-%%-----------------------------------------------------------------
-alias_type(Config) when is_list(Config) ->
- T = {'tk_alias', "IDL:Module/Alias:1.0", "Alias",
- {'tk_struct', "IDL:Module/Struct2:1.0", "Module_Struct2",
- [{"long_sequence", {'tk_sequence', 'tk_long', 0}},
- {"enum", {'tk_enum', "IDL:Module/Enum:1.0", "Module_Enum",
- ["horse", "pig", "cow"]}},
- {"octet", 'tk_octet'}]}},
- S = #'Module_Struct2'{long_sequence=[4711, 350000, 0, -3030, -600000],
- e=cow, o=$X},
- B = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T,S),
- {S, <<>>, _} = cdr_decode:dec_type(T, {1, 2}, B, 0, big),
- T1 = {'tk_alias', "IDL:Module/Alias1:1.0", "Alias1",
- {'tk_sequence', {'tk_union', "IDL:Module/Union:1.0", "Union",
- {'tk_enum', "IDL:Module/Enum:1.0", "Module_Enum",
- ["horse", "pig", "cow"]}, 2,
- [{"horse", "First", 'tk_ushort'},
- {"pig", "Second", {'tk_sequence', {'tk_string', 0}, 0}},
- {"cow", "Third", {'tk_enum', "IDL:Module/Enum1:1.0",
- "Module_Enum1", ["orange", "banana",
- "apple"]}}]},0}},
- S1 = [#'Module_Union'{label=cow, value=banana}, #'Module_Union'{label=pig, value=["This", "is", "a", "test", ""]}],
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T1, S1),
- {S1, <<>>, _} = cdr_decode:dec_type(T1, {1, 2}, B1, 0, big),
- ok.
-
-%%-----------------------------------------------------------------
-%% Encode/decode test of type: exception
-%%-----------------------------------------------------------------
-exception_type(Config) when is_list(Config) ->
- system_exceptions(),
- user_exceptions(),
- ok.
-
-system_exceptions() ->
- E = #'UNKNOWN'{completion_status=?COMPLETED_YES},
- {system_exception, T, E} = orber_exceptions:get_def(E),
- B = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T,E),
- {E, _} = cdr_decode:dec_system_exception({1, 2}, B, 0, big),
- E1 = #'INV_OBJREF'{completion_status=?COMPLETED_NO},
- {system_exception, T1, E1} = orber_exceptions:get_def(E1),
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T1,E1),
- {E1, _} = cdr_decode:dec_system_exception({1, 2}, B1, 0, big),
- E2 = #'BAD_OPERATION'{completion_status=?COMPLETED_NO},
- {system_exception, T2, E2} = orber_exceptions:get_def(E2),
- B2 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T2,E2),
- {E2, _} = cdr_decode:dec_system_exception({1, 2}, B2, 0, big),
- E3 = #'INTF_REPOS'{completion_status=?COMPLETED_MAYBE},
- {system_exception, T3, E3} = orber_exceptions:get_def(E3),
- B3 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T3,E3),
- {E3, _} = cdr_decode:dec_system_exception({1, 2}, B3, 0, big),
- ok.
-
-user_exceptions() ->
- E = #'Module_Except1'{rest_of_name=["I","am","testing","exceptions"], why="Error"},
- {user_exception, T, E} = orber_exceptions:get_def(E),
- B = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T, E),
- {E, _} = cdr_decode:dec_user_exception({1, 2}, B, 0, big),
- E1 = #'Module_Except2'{e=banana,
- s=#'Module_Struct2'{long_sequence=[12,-4040,
- 1234567898],
- e=horse,
- o=$a}},
- {user_exception, T1, E1} = orber_exceptions:get_def(E1),
- B1 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T1, E1),
- {E1, _} = cdr_decode:dec_user_exception({1, 2}, B1, 0, big),
- E2 = #'Module_Except3'{u=#'Module_Union1'{label=pig,value=["high","and","low"]},s=1313, o=objref(0)},
- {user_exception, T2, E2} = orber_exceptions:get_def(E2),
- B2 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T2, E2),
- {E2, _} = cdr_decode:dec_user_exception({1, 2}, B2, 0, big),
- E3 = #'Module_Except4'{},
- {user_exception, T3, E3} = orber_exceptions:get_def(E3),
- B3 = cdr_encode:enc_type(#giop_env{version = {1, 2}}, T3, E3),
- {E3, _} = cdr_decode:dec_user_exception({1, 2}, B3, 0, big),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: request encoding test
-%% Description: Precondition the stack must be started so the
-%% objectkey is valid.
-%%-----------------------------------------------------------------
-%request(_) ->
-% exit(not_implemented).
-
-%%-----------------------------------------------------------------
-%% Test Case: reply encoding test
-%% Description:
-%%-----------------------------------------------------------------
-reply(Config) when is_list(Config) ->
- R = #reply_header{service_context=[], request_id=1,
- reply_status='no_exception'},
- B = cdr_encode:enc_reply(#giop_env{version = {1, 2}, request_id = 1,
- reply_status = 'no_exception',
- tc = {'tk_long', [], [{'tk_sequence',
- {'tk_string', 0}, 0}]},
- result = 1200,
- parameters = [["foo","Bar"]],
- ctx = []}),
-
- {R, 1200, [["foo","Bar"]]} =
- cdr_decode:dec_message({'tk_long', [], [{'tk_sequence', {'tk_string', 0},0}]},
- B),
-
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: cancel_request encoding test
-%% Description:
-%%-----------------------------------------------------------------
-cancel_request(Config) when is_list(Config) ->
- R = #cancel_request_header{request_id=1},
- B = cdr_encode:enc_cancel_request(#giop_env{version = {1, 2},
- request_id = 1}),
- R = cdr_decode:dec_message([], B),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: locate_request encoding test
-%% Description:
-%%-----------------------------------------------------------------
-locate_request(Config) when is_list(Config) ->
- io:format("Function not imlpemented yet"),
- exit(not_implemented).
-
-%%-----------------------------------------------------------------
-%% Test Case: locate_reply encoding test
-%% Description:
-%%-----------------------------------------------------------------
-locate_reply(Config) when is_list(Config) ->
- io:format("Function not imlpemented yet"),
- exit(not_implemented).
-
-%%-----------------------------------------------------------------
-%% Test Case: close_connection encoding test
-%% Description:
-%%-----------------------------------------------------------------
-close_connection(Config) when is_list(Config) ->
- B = cdr_encode:enc_close_connection(#giop_env{version = {1, 2}}),
- 'close_connection' = cdr_decode:dec_message([], B),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: message_error encoding test
-%% Description:
-%%-----------------------------------------------------------------
-message_error(Config) when is_list(Config) ->
- B = cdr_encode:enc_message_error(#giop_env{version = {1, 2}}),
- 'message_error' = cdr_decode:dec_message([], B),
- ok.
-
-
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-corba_fake_mk_objkey(Id, 'key', Pid) when is_pid(Pid) ->
- Key = make_objkey(),
- {list_to_binary(Id), 'key', Key, term_to_binary(undefined),
- term_to_binary(undefined), term_to_binary(undefined)};
-corba_fake_mk_objkey(Id, 'key', RegName) when is_atom(RegName) ->
- Key = term_to_binary(RegName),
- {list_to_binary(Id), 'key', Key, term_to_binary(undefined),
- term_to_binary(undefined), term_to_binary(undefined)};
-corba_fake_mk_objkey(Id, 'registered', RegName) when is_atom(RegName) ->
- {list_to_binary(Id), 'registered', RegName, term_to_binary(undefined),
- term_to_binary(undefined), term_to_binary(undefined)}.
-
-make_objkey() ->
- term_to_binary({{erlang:system_time(),
- erlang:unique_integer()},
- node()}).
diff --git a/lib/orber/test/cdrlib_SUITE.erl b/lib/orber/test/cdrlib_SUITE.erl
deleted file mode 100644
index 93adc861c5..0000000000
--- a/lib/orber/test/cdrlib_SUITE.erl
+++ /dev/null
@@ -1,479 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%%
-%% Description:
-%% Test suite for the CDR basic type encode/decode functions
-%%
-%%-----------------------------------------------------------------
--module(cdrlib_SUITE).
-
--include_lib("common_test/include/ct.hrl").
-
--define(default_timeout, test_server:minutes(3)).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--compile(export_all).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [short, ushort, long, ulong, longlong, ulonglong,
- boolean, character, octet, float, double, enum].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-
-init_per_testcase(_Case, Config) ->
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: short integer test
-%% Description:
-%%-----------------------------------------------------------------
-short(_) ->
- short_big_loop([-32768, -4040, -1, 0, 4040, 32767]),
- short_little_loop([-32768, -4040, -1, 0, 4040, 32767]),
- bad_short().
-
-short_big_loop([]) ->
- ok;
-short_big_loop([X |List]) ->
- [CodedType] = cdrlib:enc_short(X, []),
- {X, <<>>} = cdrlib:dec_short(big, CodedType),
- short_big_loop(List),
- ok.
-
-short_little_loop([]) ->
- ok;
-short_little_loop([X |List]) ->
- CodedType = enc_short_little(X, []),
- {X, <<>>} = cdrlib:dec_short(little, CodedType),
- short_little_loop(List),
- ok.
-
-enc_short_little(X, Message) ->
- list_to_binary([(X) band 16#ff, ((X) bsr 8) band 16#ff | Message]).
-
-bad_short() ->
- {'EXCEPTION', _} = (catch cdrlib:enc_short('atom', [])),
- [CodedType] = cdrlib:enc_char($a, []),
- {'EXIT', _} = (catch cdrlib:dec_short(big, CodedType)),
- ok.
-%%-----------------------------------------------------------------
-%% Test Case: unsigned short integer test
-%% Description:
-%%-----------------------------------------------------------------
-ushort(_) ->
- ushort_big_loop([0, 4040, 65535]),
- ushort_little_loop([0, 4040, 65535]),
- bad_ushort().
-
-ushort_big_loop([]) ->
- ok;
-ushort_big_loop([X |List]) ->
- [CodedType] = cdrlib:enc_unsigned_short(X, []),
- {X, <<>>} = cdrlib:dec_unsigned_short(big, CodedType),
- ushort_big_loop(List),
- ok.
-
-ushort_little_loop([]) ->
- ok;
-ushort_little_loop([X |List]) ->
- CodedType = enc_ushort_little(X, []),
- {X, <<>>} = cdrlib:dec_unsigned_short(little, CodedType),
- ushort_little_loop(List),
- ok.
-
-enc_ushort_little(X, Message) ->
- list_to_binary([(X) band 16#ff, ((X) bsr 8) band 16#ff | Message]).
-
-bad_ushort() ->
- ok.
-%%-----------------------------------------------------------------
-%% Test Case: long integer test
-%% Description:
-%%-----------------------------------------------------------------
-long(_) ->
- long_big_loop([-2147483648, -40404040, -32768, -4040, -1,
- 0, 4040, 32767, 40404040, 2147483647]),
- long_little_loop([-2147483648, -40404040, -32768, -4040, -1,
- 0, 4040, 32767, 40404040, 2147483647]),
- bad_long().
-
-
-long_big_loop([]) ->
- ok;
-long_big_loop([X |List]) ->
- [CodedType] = cdrlib:enc_long(X, []),
- {X, <<>>} = cdrlib:dec_long(big, CodedType),
- long_big_loop(List),
- ok.
-
-long_little_loop([]) ->
- ok;
-long_little_loop([X |List]) ->
- CodedType = enc_long_little(X, []),
- {X, <<>>} = cdrlib:dec_long(little, CodedType),
- long_little_loop(List),
- ok.
-
-enc_long_little(X, Message) ->
- list_to_binary([(X) band 16#ff, ((X) bsr 8) band 16#ff, ((X) bsr 16) band 16#ff,
- ((X) bsr 24) band 16#ff | Message]).
-
-bad_long() ->
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: unsigned long integer test
-%% Description:
-%%-----------------------------------------------------------------
-ulong(_) ->
- ulong_big_loop([0, 4040, 65535, 40404040, 2147483647, 4294967295]),
- ulong_little_loop([0, 4040, 65535, 40404040, 2147483647, 4294967295]),
- bad_ulong().
-
-
-ulong_big_loop([]) ->
- ok;
-ulong_big_loop([X |List]) ->
- [CodedType] = cdrlib:enc_unsigned_long(X, []),
- {X, <<>>} = cdrlib:dec_unsigned_long(big, CodedType),
- ulong_big_loop(List),
- ok.
-
-ulong_little_loop([]) ->
- ok;
-ulong_little_loop([X |List]) ->
- CodedType = enc_ulong_little(X, []),
- {X, <<>>} = cdrlib:dec_unsigned_long(little, CodedType),
- ulong_little_loop(List),
- ok.
-
-enc_ulong_little(X, Message) ->
- list_to_binary([(X) band 16#ff, ((X) bsr 8) band 16#ff, ((X) bsr 16) band 16#ff,
- ((X) bsr 24) band 16#ff | Message]).
-
-
-bad_ulong() ->
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: long integer test
-%% Description:
-%%-----------------------------------------------------------------
-longlong(_) ->
- longlong_big_loop([-2147483648, -40404040, -32768, -4040, -1,
- 0, 4040, 32767, 40404040, 2147483647]),
- longlong_little_loop([-2147483648, -40404040, -32768, -4040, -1,
- 0, 4040, 32767, 40404040, 2147483647]),
- bad_longlong().
-
-
-longlong_big_loop([]) ->
- ok;
-longlong_big_loop([X |List]) ->
- [CodedType] = cdrlib:enc_longlong(X, []),
- {X, <<>>} = cdrlib:dec_longlong(big, CodedType),
- longlong_big_loop(List),
- ok.
-
-longlong_little_loop([]) ->
- ok;
-longlong_little_loop([X |List]) ->
- CodedType = enc_longlong_little(X, []),
- {X, <<>>} = cdrlib:dec_longlong(little, CodedType),
- longlong_little_loop(List),
- ok.
-
-enc_longlong_little(X, Message) ->
- list_to_binary([(X) band 16#ff, ((X) bsr 8) band 16#ff, ((X) bsr 16) band 16#ff,
- ((X) bsr 24) band 16#ff, ((X) bsr 32) band 16#ff, ((X) bsr 40) band 16#ff,
- ((X) bsr 48) band 16#ff, ((X) bsr 56) band 16#ff | Message]).
-
-bad_longlong() ->
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: unsigned long integer test
-%% Description:
-%%-----------------------------------------------------------------
-ulonglong(_) ->
- ulonglong_big_loop([0, 4040, 65535, 40404040, 2147483647, 4294967295]),
- ulonglong_little_loop([0, 4040, 65535, 40404040, 2147483647, 4294967295]),
- bad_ulonglong().
-
-
-ulonglong_big_loop([]) ->
- ok;
-ulonglong_big_loop([X |List]) ->
- [CodedType] = cdrlib:enc_unsigned_longlong(X, []),
- {X, <<>>} = cdrlib:dec_unsigned_longlong(big, CodedType),
- ulonglong_big_loop(List),
- ok.
-
-ulonglong_little_loop([]) ->
- ok;
-ulonglong_little_loop([X |List]) ->
- CodedType = enc_ulonglong_little(X, []),
- {X, <<>>} = cdrlib:dec_unsigned_longlong(little, CodedType),
- ulonglong_little_loop(List),
- ok.
-
-enc_ulonglong_little(X, Message) ->
- list_to_binary([(X) band 16#ff, ((X) bsr 8) band 16#ff, ((X) bsr 16) band 16#ff,
- ((X) bsr 24) band 16#ff, ((X) bsr 32) band 16#ff, ((X) bsr 40) band 16#ff,
- ((X) bsr 48) band 16#ff, ((X) bsr 56) band 16#ff | Message]).
-
-bad_ulonglong() ->
- ok.
-
-
-
-%%-----------------------------------------------------------------
-%% Test Case: boolean test
-%% Description:
-%%-----------------------------------------------------------------
-boolean(_) ->
- [CodedTrue] = cdrlib:enc_bool('true', []),
- {'true', <<>>} = cdrlib:dec_bool(CodedTrue),
- [CodedFalse] = cdrlib:enc_bool('false', []),
- {'false', <<>>} = cdrlib:dec_bool(CodedFalse),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: character test
-%% Description:
-%%-----------------------------------------------------------------
-character(_) ->
- [Coded_0] = cdrlib:enc_char($0, []),
- {$0, <<>>} = cdrlib:dec_char(Coded_0),
- [Coded_a] = cdrlib:enc_char($a, []),
- {$a, <<>>} = cdrlib:dec_char(Coded_a),
- [Coded_Z] = cdrlib:enc_char($Z, []),
- {$Z, <<>>} = cdrlib:dec_char(Coded_Z),
- [Coded_dollar] = cdrlib:enc_char($$, []),
- {$$, <<>>} = cdrlib:dec_char(Coded_dollar),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: octet test
-%% Description:
-%%-----------------------------------------------------------------
-octet(_) ->
- [Coded_ff] = cdrlib:enc_octet(16#ff, []),
- {16#ff, <<>>} = cdrlib:dec_octet(Coded_ff),
- [Coded_00] = cdrlib:enc_octet(16#00, []),
- {16#00, <<>>} = cdrlib:dec_octet(Coded_00),
- [Coded_5a] = cdrlib:enc_octet(16#5a, []),
- {16#5a, <<>>} = cdrlib:dec_octet(Coded_5a),
- [Coded_48] = cdrlib:enc_octet(16#48, []),
- {16#48, <<>>} = cdrlib:dec_octet(Coded_48),
- ok.
-
-
-
-%%-----------------------------------------------------------------
-%% Test Case: float test
-%% Description:
-%%-----------------------------------------------------------------
-float(_) ->
- G = 16#7fffff / 16#800000 + 1.0,
- H1 = math:pow(2, 127),
- H2 = math:pow(2, -126),
- float_big_loop([-H1 * G, -H1 * 1.0, -H2 * G, -H2 * 1.0,
- -4040.313131, -3.141592, 0.0, 3.141592, 4040.313131,
- H1 * G, H1 * 1.0, H2 * G, H2 * 1.0]),
- float_little_loop([-H1 * G, -H1 * 1.0, -H2 * G, -H2 * 1.0,
- -4040.313131, -3.141592, 0.0, 3.141592, 4040.313131,
- H1 * G, H1 * 1.0, H2 * G, H2 * 1.0]),
- ok.
-
-float_big_loop([]) ->
- ok;
-float_big_loop([X |List]) ->
- [CodedType] = cdrlib:enc_float(X, []),
- {Y, <<>>} = cdrlib:dec_float(big, CodedType),
- float_comp(X,Y),
- float_big_loop(List),
- ok.
-
-float_little_loop([]) ->
- ok;
-float_little_loop([X |List]) ->
- [CodedType] = enc_float_little(X, []),
- {Y, <<>>} = cdrlib:dec_float(little, CodedType),
- float_comp(X,Y),
- float_little_loop(List),
- ok.
-
-float_comp(X,Y) when X == 0.0, Y == 0.0 ->
- ok;
-float_comp(X,Y) ->
- Div = abs(Y) / abs(X),
- %% io:format("~p~n", [float_to_list(Div)]),
- true = (Div < 1.0000001),
- true = (Div > 0.9999999),
- ok.
-
-enc_float_little(X, Message) ->
- [ <<X:32/little-float>> | Message].
-
-%%-----------------------------------------------------------------
-%% Test Case: double test
-%% Description:
-%%-----------------------------------------------------------------
-double(_) ->
- F = 16#0fffffffffffff / 16#10000000000000 + 1.0,
- E1 = math:pow(2, 1023),
- E2 = math:pow(2, -1022),
- G = 16#7fffff / 16#800000 + 1.0,
- H1 = math:pow(2, 128),
- H2 = math:pow(2, -127),
- double_big_loop([-E1 * F, -E1 * 1.0, -E2 * F, -E2 * 1.0,
- -H1 * G, -H1 * 1.0, -H2 * G, -H2 * 1.0,
- -4040.313131, -3.141592, 0.0, 3.141592, 4040.313131,
- H1 * G, H1 * 1.0, H2 * G, H2 * 1.0,
- E1 * F, E1 * 1.0, E2 * F, E2 * 1.0]),
- double_little_loop([-E1 * F, -E1 * 1.0, -E2 * F, -E2 * 1.0,
- -H1 * G, -H1 * 1.0, -H2 * G, -H2 * 1.0,
- -4040.313131, -3.141592, 0.0, 3.141592, 4040.313131,
- H1 * G, H1 * 1.0, H2 * G, H2 * 1.0,
- E1 * F, E1 * 1.0, E2 * F, E2 * 1.0]),
- ok.
-
-double_big_loop([]) ->
- ok;
-double_big_loop([X |List]) ->
- [CodedType] = cdrlib:enc_double(X, []),
- {Y, <<>>} = cdrlib:dec_double(big, CodedType),
- double_comp(X,Y),
- double_big_loop(List),
- ok.
-
-double_little_loop([]) ->
- ok;
-double_little_loop([X |List]) ->
- [CodedType] = enc_double_little(X, []),
- {Y, <<>>} = cdrlib:dec_double(little, CodedType),
- double_comp(X,Y),
- double_little_loop(List),
- ok.
-
-enc_double_little(X, Message) ->
- [ <<X:64/little-float>> | Message].
-
-double_comp(X,Y) when X == 0.0, Y == 0.0 ->
- ok;
-double_comp(X,Y) ->
- Div = abs(Y) / abs(X),
- %% io:format("~p~n", [float_to_list(Div)]),
- true = (Div < 1.00000000000001),
- true = (Div > 0.99999999999999),
- ok.
-
-double_should_be_ok(_) ->
- F = 16#0fffffffffffff / 16#10000000000000 + 1.0,
- E1 = math:pow(2, 1024), % erlang can't handle this.
- E2 = math:pow(2, -1023),
- double_big_loop([-E1 * F, -E1 * 1.0, -E2 * F, -E2 * 1.0,
- E1 * F, E1 * 1.0, E2 * F, E2 * 1.0]),
- double_little_loop([-E1 * F, -E1 * 1.0, -E2 * F, -E2 * 1.0,
- E1 * F, E1 * 1.0, E2 * F, E2 * 1.0]),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: enum test
-%% Description:
-%%-----------------------------------------------------------------
-enum(_) ->
- enum_big(),
- enum_little(),
- ok.
-
-enum_big() ->
- [Coded_a] = cdrlib:enc_enum(a,[a,b,c],[]),
- {a, <<>>} = cdrlib:dec_enum(big, ["a","b","c"], Coded_a),
- [Coded_b] = cdrlib:enc_enum(b,[a,b,c],[]),
- {b, <<>>} = cdrlib:dec_enum(big, ["a","b","c"], Coded_b),
- [Coded_c] = cdrlib:enc_enum(c,[a,b,c],[]),
- {c, <<>>} = cdrlib:dec_enum(big, ["a","b","c"], Coded_c),
- ok.
-
-enum_little() ->
- Coded_a = enc_r_enum(a,[a,b,c],[]),
- {a, <<>>} = cdrlib:dec_enum(little, ["a","b","c"], Coded_a),
- Coded_b = enc_r_enum(b,[a,b,c],[]),
- {b, <<>>} = cdrlib:dec_enum(little, ["a","b","c"], Coded_b),
- Coded_c = enc_r_enum(c,[a,b,c],[]),
- {c, <<>>} = cdrlib:dec_enum(little, ["a","b","c"], Coded_c),
- ok.
-
-enc_r_enum(Enum, ElemList, Message) ->
- Val = getEnumValue(ElemList,Enum, 0),
- enc_r_unsigned_long(Val, Message).
-
-getEnumValue([Enum |_List], Enum, N) ->
- N;
-getEnumValue([_ |List], Enum, N) ->
- getEnumValue(List, Enum, N + 1).
-
-enc_r_unsigned_long(X, Message) ->
- list_to_binary([(X) band 16#ff, ((X) bsr 8) band 16#ff,
- ((X) bsr 16) band 16#ff, ((X) bsr 24) band 16#ff | Message]).
diff --git a/lib/orber/test/corba_SUITE.erl b/lib/orber/test/corba_SUITE.erl
deleted file mode 100644
index 22bb8dd2f9..0000000000
--- a/lib/orber/test/corba_SUITE.erl
+++ /dev/null
@@ -1,897 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%%
-%% Description:
-%% Test suite for corba/boa/object/orber API functions
-%%
-%%-----------------------------------------------------------------
--module(corba_SUITE).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/include/corba.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming.hrl").
--include_lib("orber/src/orber_iiop.hrl").
-
-
--define(default_timeout, test_server:minutes(5)).
-
--define(match(ExpectedRes,Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- io:format("------ CORRECT RESULT ------~n~p~n",
- [AcTuAlReS]),
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~nRESULT: ~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([pseudo_calls/2, pseudo_casts/2]).
--compile(export_all).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- cases().
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-cases() ->
- [exception_info_api, corba_api, object_api, orber_api,
- orber_objectkeys_api, orber_pseudo_objects,
- callback_ok_api, callback_arity_api,
- callback_module_api, callback_function_api,
- callback_precond_api, callback_postcond_api,
- callback_exit_api, callback_badarith_api,
- callback_case_clause_api, callback_function_clause_api].
-
-%% boa_api, request, locate_request, locate_reply].
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-
-init_per_testcase(_Case, Config) ->
- Path = code:which(?MODULE),
- code:add_pathz(filename:join(filename:dirname(Path), "idl_output")),
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- Path = code:which(?MODULE),
- code:del_path(filename:join(filename:dirname(Path), "idl_output")),
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-init_per_suite(Config) ->
- corba:orb_init([{orber_debug_level, 10}, {giop_version, {1,2}},
- {iiop_port, 0}]),
- mnesia:delete_schema([node()]),
- mnesia:create_schema([node()]),
- orber:install([node()]),
- application:start(mnesia),
- application:start(orber),
- if
- is_list(Config) ->
- Config;
- true ->
- exit("Config not a list")
- end.
-
-end_per_suite(Config) ->
- application:stop(orber),
- application:stop(mnesia),
- mnesia:delete_schema([node()]),
- Config.
-
-%%-----------------------------------------------------------------
-%% API tests for pseudo interface CORBA
-%%-----------------------------------------------------------------
-corba_api(_) ->
- NIL = corba:create_nil_objref(),
- ok = corba:dispose(NIL),
- NS = corba:resolve_initial_references("NameService"),
- List = corba:list_initial_services(),
- ["NameService"] = List,
- NSstring = corba:object_to_string(NS),
- NS1 = corba:string_to_object(NSstring),
- NSstring = corba:object_to_string(NS1),
- true = corba:add_initial_service("MyData", NS),
- NS = corba:resolve_initial_references("MyData"),
- [_,_] = corba:list_initial_services(),
- false = corba:remove_initial_service("Wrong"),
- NIL = corba:resolve_initial_references("Wrong"),
- NS = corba:string_to_object("corbaloc:rir:/MyData"),
- true = corba:remove_initial_service("MyData"),
- ["NameService"] = corba:list_initial_services(),
-
- %% This is a collection of different stringified IOR:s (correct & incorrect)
- %% which we use to test IOR encode/decode.
- IOR1 = ?match({'IOP_IOR',_,_}, corba:string_to_object("IOR:000303030000000d49444c3a746573743a312e3000030303000000040000000000000100000102010000000a3132372e302e302e31009d610000002dabacab3131303432343836383731005f526f6f74504f4100414c4c5f504f410000cafebabe3e2316570000000003030300000002000000210000007800010202000000010040020200000022000000080003030300000000004000400000000806066781020101010000001b0401000806066781020101010000000b40616469726f6e2e636f6d010400000000000000000000020000000806066781020101010000000b06092a864886f712010202010000000f000000010000002c00030303000100010000000400010020000101090001010005010001000101090000000200010100050100010000000000000184000102010000000a3132372e302e302e310000000000002dabacab3131303432343836383731005f526f6f74504f4100414c4c5f504f410000cafebabe3e231657000000000303030000000300000021000000ec000102020000000200060202000000240000001c0001006600060202000000010000000a3132372e302e302e31009d600000000000000000000000000400000000000000000000020000000806066781020101010000000b06092a864886f712010202010000000f00460202000000240000001c0001006600060202000000010000000a3132372e302e302e31009d62004000400000000806066781020101010000001b0401000806066781020101010000000b40616469726f6e2e636f6d010400000000000000000000020000000806066781020101010000000b06092a864886f712010202010000000f00000014000000080001006600069d5e000000010000002c000303030001000100000004000100200001010900010100050100010001010900000002000101000501000100000000000000dc000102010000000a3132372e302e302e31009d5f0000002dabacab3131303432343836383731005f526f6f74504f4100414c4c5f504f410000cafebabe3e23165700000000030303000000020000002100000054000102020000000100000202000000220000000800030303000000000000000000000000000000000400000000000000000000020000000806066781020101010000000b06092a864886f712010202010000000f000000010000002c00030303000100010000000400010020000101090001010005010001000101090000000200010100050100010000000000000080000102010000000a3132372e302e302e31009d5d0000002dabacab3131303432343836383731005f526f6f74504f4100414c4c5f504f410000cafebabe3e2316570000000003030300000001000000010000002c0003030300010001000000040001002000010109000101000501000100010109000000020001010005010001")),
- IOR2 = ?match({'IOP_IOR',_,_}, corba:string_to_object("IOR:000303030000000d49444c3a746573743a312e30000303030000000100000000000000e0000102010000000a3132372e302e302e31009d5f00000034abacab3131303432343836383731005f526f6f74504f410049494f505f43534976325f504f410000cafebabe3e23165700000000000000020000002100000054000102020000000100000202000000220000000800030303000000000000000000000000000000000400000000000000000000020000000806066781020101010000000b06092a864886f712010202010000000f000000010000002c0003030300010001000000040001002000010109000101000501000100010109000000020001010005010001")),
- IOR3 = ?match({'IOP_IOR',_,_}, corba:string_to_object("IOR:000303030000000d49444c3a746573743a312e3000030303000000010000000000000108000102010000000a3132372e302e302e31009d6100000037abacab3131303432343836383731005f526f6f74504f410049494f505f43534976325f55505f504f410000cafebabe3e231657000000000100000002000000210000007800010202000000010040020200000022000000080003030300000000004000400000000806066781020101010000001b0401000806066781020101010000000b40616469726f6e2e636f6d010400000000000000000000020000000806066781020101010000000b06092a864886f712010202010000000f000000010000002c0003030300010001000000040001002000010109000101000501000100010109000000020001010005010001")),
- IOR4 = ?match({'IOP_IOR',_,_}, corba:string_to_object("IOR:000303030000000d49444c3a746573743a312e3000030303000000010000000000000080000102010000000a3132372e302e302e31009d5d0000002eabacab3131303432343836383731005f526f6f74504f410049494f505f504f410000cafebabe3e23165700000000020200000001000000010000002c0003030300010001000000040001002000010109000101000501000100010109000000020001010005010001")),
- IOR5 = ?match({'IOP_IOR',_,_}, corba:string_to_object("IOR:000303030000000d49444c3a746573743a312e30000303030000000100000000000000fc000102010000000a3132372e302e302e3100000000000033abacab3131303432343836383731005f526f6f74504f4100544c535f43534976325f504f410000cafebabe3e231657000000000100000002000000210000007000010202000000010006020200000024000000220001006600060202000000010000000f3132382e3233302e3230382e353500019d6000000000020200000000000000000400000000000000000000020000000806066781020101010000000b06092a864886f712010202010000000f000000010000002c0003030300010001000000040001002000010109000101000501000100010109000000020001010005010001")),
- IOR6 = ?match({'IOP_IOR',_,_}, corba:string_to_object("IOR:000303030000000d49444c3a746573743a312e3000030303000000010000000000000124000102010000000a3132372e302e302e3100000000000036abacab3131303432343836383731005f526f6f74504f4100544c535f43534976325f55505f504f410000cafebabe3e23165700000000020200000002000000210000009400010202000000010046020200000024000000220001006600060202000000010000000f3132382e3233302e3230382e353500019d620040004002020000000806066781020101010000001b0401000806066781020101010000000b40616469726f6e2e636f6d010400000000000000000000020000000806066781020101010000000b06092a864886f712010202010000000f000000010000002c0003030300010001000000040001002000010109000101000501000100010109000000020001010005010001")),
- IOR7 = ?match({'IOP_IOR',_,_}, corba:string_to_object("IOR:000303030000000d49444c3a746573743a312e3000030303000000010000000000000090000102010000000a3132372e302e302e310000000000002dabacab3131303432343836383731005f526f6f74504f4100544c535f504f410000cafebabe3e231657000000000303030000000200000014000000080001006600069d5e000000010000002c0003030300010001000000040001002000010109000101000501000100010109000000020001010005010001")),
- IOR1 = corba:string_to_object(corba:object_to_string(IOR1)),
- IOR2 = corba:string_to_object(corba:object_to_string(IOR2)),
- IOR3 = corba:string_to_object(corba:object_to_string(IOR3)),
- IOR4 = corba:string_to_object(corba:object_to_string(IOR4)),
- IOR5 = corba:string_to_object(corba:object_to_string(IOR5)),
- IOR6 = corba:string_to_object(corba:object_to_string(IOR6)),
- IOR7 = corba:string_to_object(corba:object_to_string(IOR7)),
- ?match(ok, corba:print_object(IOR1)),
- ?match(ok, corba:print_object(IOR2)),
- ?match(ok, corba:print_object(IOR3)),
- ?match(ok, corba:print_object(IOR4)),
- ?match(ok, corba:print_object(IOR5)),
- ?match(ok, corba:print_object(IOR6)),
- ?match(ok, corba:print_object(IOR7)),
- ?match(ok, corba:print_object("IOR:000303030000000d49444c3a746573743a312e300003030300000002000000000000003000010001000000136d792e686f73742e65726c616e672e6f72670001801a02020000000c424f410a00000a0000070a010000000100000024000303030000000100000001000000140003030300010001000000000001010900000000")),
- [IP] = ?match([_], orber:host()),
- ?match(#'IOP_IOR'{profiles=[#'IOP_TaggedProfile'
- {tag=?TAG_INTERNET_IOP,
- profile_data=#'IIOP_ProfileBody_1_1'
- {host = IP}}]},
- corba:string_to_object(corba:object_to_string(NS))),
- ?match(#'IOP_IOR'{profiles=[#'IOP_TaggedProfile'
- {tag=?TAG_INTERNET_IOP,
- profile_data=#'IIOP_ProfileBody_1_1'
- {host = "127.0.0.1"}}]},
- corba:string_to_object(corba:object_to_string(NS, ["127.0.0.1"]))),
- ?match(#'IOP_IOR'{profiles=[#'IOP_TaggedProfile'
- {tag=?TAG_INTERNET_IOP,
- profile_data=#'IIOP_ProfileBody_1_1'
- {host = "127.0.0.1", port = 5468}}]},
- corba:string_to_object(corba:object_to_string(NS, ["127.0.0.1"],
- 5468))),
- ok.
-
-%%-----------------------------------------------------------------
-%% API tests for interface BOA
-%%-----------------------------------------------------------------
-boa_api(_) ->
- ok.
-
-%%-----------------------------------------------------------------
-%% API tests for interface OBJECT
-%%-----------------------------------------------------------------
-object_api(_) ->
- oe_orber_test_server:oe_register(),
- EC = orber_test_server:oe_create(),
- NS = corba:resolve_initial_references("NameService"),
- %% testing corba_object:is_a(Obj, IFRID) locally.
- orber_test_lib:corba_object_tests(EC, NS),
-
- ?match(false, corba_object:non_existent(NS)),
-
- corba:dispose(EC),
- oe_orber_test_server:oe_unregister(),
- ok.
-
-%%-----------------------------------------------------------------
-%% API tests for orbers main module
-%%-----------------------------------------------------------------
-orber_api(_) ->
- ok = orber:uninstall(),
- orber:install([node()]),
- application:start(orber),
- NodeList = orber:orber_nodes(),
- NL = node(),
- [NL] = NodeList,
- ok.
-
-%%-----------------------------------------------------------------
-%% API tests for exception mapping
-%%-----------------------------------------------------------------
-exception_info_api(_) ->
- {ok, S1} = orber:exception_info({'EXCEPTION',{'MARSHAL',[],1163001858,'COMPLETED_NO'}}),
- {ok, S2} = orber:exception_info({'EXCEPTION',{'MARSHAL',[],1330446337,'COMPLETED_NO'}}),
- {ok, S3} = orber:exception_info({'EXCEPTION',{'MARSHAL',[],1398079490,'COMPLETED_NO'}}),
- {ok, S4} = orber:exception_info({'EXCEPTION',{'MARSHAL',[],1347813377,'COMPLETED_NO'}}),
- {ok, S5} = orber:exception_info({'EXCEPTION', {'CosNaming_NamingContext_InvalidName',"IDL:omg.org/CosNaming/NamingContext/InvalidName:1.0"}}),
- error_logger:info_msg("~s", [S1]),
- error_logger:info_msg("~s", [S2]),
- error_logger:info_msg("~s", [S3]),
- error_logger:info_msg("~s", [S4]),
- error_logger:info_msg("~s", [S5]),
- ok.
-
-%%-----------------------------------------------------------------
-%% API tests for orbers pseudo objects.
-%%-----------------------------------------------------------------
-orber_pseudo_objects(_) ->
- oe_orber_test_server:oe_register(),
- Obj1=(catch orber_test_server:oe_create(state,[{pseudo,true},
- {local_typecheck, true}])),
- ?match({_,pseudo,orber_test_server_impl, _,_, _}, Obj1),
- Obj2=(catch orber_test_server:oe_create([],[{pseudo, truce}])),
- ?match({'EXCEPTION',{'BAD_PARAM',[],_,'COMPLETED_NO'}}, Obj2),
- spawn(?MODULE, pseudo_calls, [20, Obj1]),
- ?match({ok, 10000}, orber_test_server:pseudo_call_delay(Obj1, 10000)),
- spawn(?MODULE, pseudo_casts, [20, Obj1]),
- ?match(ok, orber_test_server:pseudo_cast_delay(Obj1, 10000)),
-
- ?match('object_here', corba:locate(Obj1)),
-
- NS = corba:resolve_initial_references("NameService"),
-
- orber_test_lib:corba_object_tests(Obj1, NS),
-
- ?match("IDL:omg.org/orber_test/server:1.0",orber_test_server:typeID()),
-
- %% Test if exceptions are handled properly.
- ?match({'EXCEPTION',{'BAD_QOS',_,_,_}},
- orber_test_server:pseudo_call_raise_exc(Obj1, 1)),
- ?match({'EXCEPTION',{'BAD_QOS',_,_,_}},
- orber_test_server:pseudo_call_raise_exc(Obj1, 2)),
-
- %% Test if exit is handled properly.
- ?match({'EXCEPTION',{'TRANSIENT',_,_,_}},
- orber_test_server:stop_brutal(Obj1)),
-
- orber_test_lib:test_coding(Obj1, true),
-
- %% possible to use subobject key?
- ?match(state, binary_to_term(corba:get_subobject_key(Obj1))),
-
- ?match({'EXCEPTION',{'INV_OBJREF',[],_,'COMPLETED_NO'}},
- corba:get_pid(Obj1)),
- ?match(false, corba_object:non_existent(Obj1)),
-
- ?match(ok, corba:dispose(Obj1)),
-
- ?match(false, corba_object:non_existent(Obj1)),
-
- %% Try if it's possible to stringify and recover the object reference.
- IOR_string = (catch corba:object_to_string(Obj1)),
- Obj3 =(catch corba:string_to_object(IOR_string)),
- ?match(IOR_string, corba:object_to_string(Obj3)),
-
- Obj4=(catch orber_test_server:oe_create(undefined,[{pseudo,true}])),
- ?match(ok, corba:dispose(Obj4)),
- oe_orber_test_server:oe_unregister(),
- ok.
-
-%%-----------------------------------------------------------------
-%% API tests for orbers objectkeys server.
-%%-----------------------------------------------------------------
-orber_objectkeys_api(_) ->
- Obj0=(catch orber_test_server:oe_create([], [{sup_child, true}])),
- Obj1=(catch orber_test_server:oe_create([], [{persistent, true},
- {regname, {local,obj1}}])),
- Obj2=(catch orber_test_server:oe_create([], [{persistent, true},
- {regname, {global,{obj2, 12345}}}])),
-
- %% Obj0 is supposed to be a child started by a supervisor (r6) which
- %% handles not only {ok, Pid} but also {ok,Pid, Returnvalue}. In our
- %% case the Returnvalue is an ObjectRef.
- ?match({ok,_,{_,key,_, _,_, _}}, Obj0),
- {ok,_,Obj0Ref} = Obj0,
- corba:dispose(Obj0Ref),
-
- %% Only 'global' servers are at the moment allowed to be persistent.
- ?match({'EXCEPTION',{'BAD_PARAM',[],_,'COMPLETED_NO'}}, Obj1),
-
- %% We created a persistent object successfully.
- ?match({_,key,_,_,_, _}, Obj2),
-
- %% Get key and Pid
- {_,_,Key,_,_, _} = Obj2,
- PID=(catch orber_objectkeys:get_pid(Key)),
-
- %% Use the two different ways to look up if the server is persistent.
- ?match(true, orber_objectkeys:is_persistent(Key)),
- ?match(true, orber_objectkeys:is_persistent(PID)),
-
- %% Create servers using every possible way.
- O1=(catch orber_test_server:oe_create()),
- O2=(catch orber_test_server:oe_create_link()),
- O3=(catch orber_test_server:oe_create([])),
- O4=(catch orber_test_server:oe_create_link([])),
- %% NOTE!!! Next four lines requires that we still support RegName instead of
- %% only OptionList as the second argument to oe_create*/2. Remove these when that
- %% is no longer the case.
- O5=(catch orber_test_server:oe_create([], {'local', o5})),
- O6=(catch orber_test_server:oe_create([], {'global', {o6, obj}})),
- O7=(catch orber_test_server:oe_create_link([], {'local', o7})),
- O8=(catch orber_test_server:oe_create_link([], {'global', {o8, obj}})),
-
- %% Test if all the object references are correct.
- ?match({_,key,_,_,_, _}, O1),
- ?match({_,key,_,_,_, _}, O2),
- ?match({_,key,_,_,_, _}, O3),
- ?match({_,key,_,_,_, _}, O4),
- ?match({_, registered, o5, _,_, _}, O5),
- ?match({_,key,_,_,_, _}, O6),
- ?match({_, registered, o7, _,_, _}, O7),
- ?match({_,key,_,_,_, _}, O8),
-
- %% Test if persistent.
- {_,_,Key1,_,_, _} = O1,
- PID1=(catch orber_objectkeys:get_pid(Key1)),
- ?match(false, orber_objectkeys:is_persistent(Key1)),
- ?match(false, orber_objectkeys:is_persistent(PID1)),
-
- %% all the servers are alive(?!).
- ?match(false, corba_object:non_existent(O1)),
- ?match(false, corba_object:non_existent(O2)),
- ?match(false, corba_object:non_existent(O3)),
- ?match(false, corba_object:non_existent(O4)),
- ?match(false, corba_object:non_existent(O5)),
- ?match(false, corba_object:non_existent(O6)),
- ?match(false, corba_object:non_existent(O7)),
- ?match(false, corba_object:non_existent(O8)),
- ?match(false, corba_object:non_existent(Obj2)),
-
- %% Does locate work?
- ?match('object_here', corba:locate(O1)),
- ?match('object_here', corba:locate(O2)),
- ?match('object_here', corba:locate(O3)),
- ?match('object_here', corba:locate(O4)),
- ?match('object_here', corba:locate(O5)),
- ?match('object_here', corba:locate(O6)),
- ?match('object_here', corba:locate(O7)),
- ?match('object_here', corba:locate(O8)),
- ?match('object_here', corba:locate(Obj2)),
-
- %% Terminate all servers with reason 'normal'.
- catch corba:dispose(O1),
- catch corba:dispose(O2),
- catch corba:dispose(O3),
- catch corba:dispose(O4),
- catch corba:dispose(O5),
- catch corba:dispose(O6),
- catch corba:dispose(O7),
- catch corba:dispose(O8),
- catch corba:dispose(Obj2),
-
-
- %% To make sure that orber_objectkeys-server is able to
- %% clean up we wait.
- timer:sleep(2000),
-
- %% all the servers are dead(?!). If one of these test-cases
- %% fails the only error can be that we didn't sleep long enough, i.e.,
- %% try a longer timeout. If still fails something is wrong.
- ?match(true, corba_object:non_existent(O1)),
- ?match(true, corba_object:non_existent(O2)),
- ?match(true, corba_object:non_existent(O3)),
- ?match(true, corba_object:non_existent(O4)),
- ?match(true, corba_object:non_existent(O5)),
- ?match(true, corba_object:non_existent(O6)),
- ?match(true, corba_object:non_existent(O7)),
- ?match(true, corba_object:non_existent(O8)),
- ?match(true, corba_object:non_existent(Obj2)),
-
- %% Create a new persistent server.
- Obj3=(catch orber_test_server:oe_create([],
- [{persistent, true},
- {regname, {global,{obj2, 12345}}}])),
-
- %% OK?!
- ?match({_,key,_,_,_, _}, Obj3),
-
- %% Try to create a server with the same name (naturally it fails).
- ?match({'EXCEPTION',{'INTERNAL',[],_,'COMPLETED_NO'}},
- orber_test_server:oe_create([],
- [{persistent, true},
- {regname, {global,{obj2, 12345}}}])),
- %% Try to remove all 'dead' servers. No server should be removed.
- orber_objectkeys:gc(0),
-
- %% Kill object brutal, i.e., not with reason 'normal' or 'shutdown'.
- P3 = corba:get_pid(Obj3),
- exit(P3, kill),
-
- {_,_,Key3,_,_, _} = Obj3,
-
- %% Give time to clean up.
- timer:sleep(2000),
- ?match({'EXCEPTION',{'TRANSIENT',[],_,'COMPLETED_NO'}},
- gen_server:call(orber_objkeyserver,
- {get_pid, Key3},
- infinity)),
-
- ?match(false,corba_object:non_existent(Obj3)),
-
- %% Run gc wit a "huge" time-limit. Will not erase the dead object.
- orber_objectkeys:gc(10000),
- ?match(false,corba_object:non_existent(Obj3)),
-
- %% Run gc with minimum time-limit. Will erase the dead object.
- orber_objectkeys:gc(0),
- ?match(true,corba_object:non_existent(Obj3)),
-
- %% Create a new persistent server.
- Obj4=(catch orber_test_server:oe_create([],
- [{persistent, true},
- {regname, {global,{obj2, 12345}}}])),
-
- %% OK?!
- ?match({_,key,_,_,_, _}, Obj4),
- %% Kill object brutal, i.e., not with reason 'normal' or 'shutdown'.
- P4 = corba:get_pid(Obj4),
- exit(P4, kill),
-
- %% Give time to clean up.
- timer:sleep(2000),
-% ?match({'EXCEPTION',{'COMM_FAILURE',[],0,'COMPLETED_NO'}},
- ?match({error, _},
- corba:get_pid(Obj4)),
-
- ?match(false,corba_object:non_existent(Obj4)),
-
- %% Restart the object.
- Obj5=(catch orber_test_server:oe_create([],
- [{persistent, true},
- {regname, {global,{obj2, 12345}}}])),
- %% OK?!
- ?match({_,key,_,_,_, _}, Obj5),
-
- %% Run gc with minimum time-limit.
- orber_objectkeys:gc(0),
- ?match(false,corba_object:non_existent(Obj5)),
- corba:dispose(Obj5),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% API tests for callback functions
-%%-----------------------------------------------------------------
--define(DO_EXIT_FLAG, 0).
--define(NO_EXIT_FLAG, 16#10).
-
--define(DO_EXIT, {is, 0}).
--define(NO_EXIT, {is, 16#10}).
-
-
-
-%% Successful callback API tests
-callback_ok_api(_) ->
- %% Init
- ?match({ok, {?DO_EXIT, state}}, corba:handle_init(?MODULE, {?DO_EXIT_FLAG, state})),
- %% Terminate
- ?match(ok, corba:handle_terminate(?MODULE, "reason", {?DO_EXIT, state})),
- %% Handle_call
- ?match({reply,ok,{?DO_EXIT,state}},
- corba:handle_call(?MODULE, foo, [],
- {?DO_EXIT, state}, [], false, false)),
- %% Handle_cast
- ?match({noreply, {?DO_EXIT,state}},
- corba:handle_cast(?MODULE, foo_1w, [],
- {?DO_EXIT, state}, [], false)),
- %% Handle_call precond/postcond
- ?match({reply, ok, {?DO_EXIT, state}},
- corba:handle_call(?MODULE, foo, [],
- {?DO_EXIT, state}, [], false, false, {?MODULE, precond},
- {?MODULE, postcond}, ?MODULE)),
- %% Handle_cast precond/postcond
- ?match({noreply, {?DO_EXIT, state}},
- corba:handle_cast(?MODULE, foo_1w, [],
- {?DO_EXIT, state}, [], false, {?MODULE, precond},
- {?MODULE, postcond}, ?MODULE)),
- %% Handle_info
- ?match({noreply, {?DO_EXIT, state}},
- corba:handle_info(?MODULE, "info", {?DO_EXIT, state})),
- ok.
-
-%% Callback arity API tests
-callback_arity_api(_) ->
- %% Handle_call - stay-alive == false
- ?match({'EXIT', {undef,_}},
- corba:handle_call(?MODULE, foo, [to, many, arguments],
- {?DO_EXIT, state}, [], false, false)),
- %% Handle_call - stay-alive == true
- ?match({reply, {'EXCEPTION', #'OBJ_ADAPTER'{}}, _},
- corba:handle_call(?MODULE, foo, [to, many, arguments],
- {?NO_EXIT, state}, [], false, false)),
- %% Handle_call - stay-alive == false
- ?match({'EXIT', _},
- corba:handle_call(?MODULE, foo, [],
- {?DO_EXIT, arity}, [], false, false)),
- %% Handle_call - stay-alive == true
- ?match({reply, {'EXCEPTION', #'OBJ_ADAPTER'{}}, _},
- corba:handle_call(?MODULE, foo, [],
- {?NO_EXIT, arity}, [], false, false)),
- %% Handle_cast - stay-alive == false
- ?match({'EXIT', {undef,_}},
- corba:handle_cast(?MODULE, foo_1w, [to, many, arguments],
- {?DO_EXIT, state}, [], false)),
- %% Handle_cast - stay-alive == true
- ?match({noreply, {?NO_EXIT, state}},
- corba:handle_cast(?MODULE, foo_1w, [to, many, arguments],
- {?NO_EXIT, state}, [], false)),
- %% Handle_cast - stay-alive == false
- ?match({'EXIT', _},
- corba:handle_cast(?MODULE, foo_1w, [],
- {?DO_EXIT, arity}, [], false)),
- %% Handle_cast - stay-alive == true
- ?match({noreply, {?NO_EXIT, arity}},
- corba:handle_cast(?MODULE, foo_1w, [],
- {?NO_EXIT, arity}, [], false)),
- %% Handle_info - stay-alive == false
- ?match({'EXIT', _},
- corba:handle_info(?MODULE, "info", {?DO_EXIT, arity})),
-
- %% Handle_info - stay-alive == true
- ?match({noreply, {?NO_EXIT, arity}},
- corba:handle_info(?MODULE, "info", {?NO_EXIT, arity})),
- ok.
-
-%% Module callback API tests
-callback_module_api(_) ->
- %% Handle_call - stay-alive == false
- ?match({'EXIT', {undef,_}},
- corba:handle_call(wrong_mod, foo, [],
- {?DO_EXIT, state}, [], false, false)),
- %% Handle_call - stay-alive == true
- ?match({reply, {'EXCEPTION', #'OBJ_ADAPTER'{}}, _},
- corba:handle_call(wrong_mod, foo, [],
- {?NO_EXIT, state}, [], false, false)),
- %% Handle_cast - stay-alive == false
- ?match({'EXIT', {undef,_}},
- corba:handle_cast(wrong_mod, foo_1w, [],
- {?DO_EXIT, state}, [], false)),
- %% Handle_cast - stay-alive == true
- ?match({noreply, {?NO_EXIT, state}},
- corba:handle_cast(wrong_mod, foo_1w, [],
- {?NO_EXIT, state}, [], false)),
- %% Handle_info - stay-alive == false.
- ?match({'EXIT', _},
- corba:handle_info(wrong_mod, "info", {?DO_EXIT, state})),
-
- %% Handle_info - stay-alive == true.
- ?match({noreply, {?NO_EXIT, state}},
- corba:handle_info(wrong_mod, "info", {?NO_EXIT, state})),
- ok.
-
-%% Function callback API tests
-callback_function_api(_) ->
- %% Handle_call - stay-alive == false
- ?match({'EXIT', {undef,_}},
- corba:handle_call(?MODULE, bad_function, [],
- {?DO_EXIT, state}, [], false, false)),
- %% Handle_call - stay-alive == true
- ?match({reply, {'EXCEPTION', #'OBJ_ADAPTER'{}}, _},
- corba:handle_call(?MODULE, bad_function, [],
- {?NO_EXIT, state}, [], false, false)),
- %% Handle_cast - stay-alive == false
- ?match({'EXIT', {undef,_}},
- corba:handle_cast(?MODULE, bad_function, [],
- {?DO_EXIT, state}, [], false)),
- %% Handle_cast - stay-alive == true
- ?match({noreply, {?NO_EXIT, state}},
- corba:handle_cast(?MODULE, bad_function, [],
- {?NO_EXIT, state}, [], false)),
- %% Handle_info - stay-alive == false. Note, we cannot use ?MODULE here.
- ?match({'EXIT', _},
- corba:handle_info(corba, "info", {?DO_EXIT, state})),
-
- %% Handle_info - stay-alive == true. Note, we cannot use ?MODULE here.
- ?match({noreply, {?NO_EXIT, state}},
- corba:handle_info(corba, "info", {?NO_EXIT, state})),
- ok.
-
-%% Precond callback API tests
-callback_precond_api(_) ->
- %% Handle_call - stay-alive == false
- ?match({'EXIT', _},
- corba:handle_call(?MODULE, foo, [],
- {?DO_EXIT, state}, [], false, false, {wrong_mod, precond},
- {?MODULE, postcond}, ?MODULE)),
- %% Handle_call - stay-alive == false
- ?match({'EXIT', _},
- corba:handle_call(?MODULE, foo, [],
- {?DO_EXIT, state}, [], false, false, {?MODULE, bad_precond},
- {?MODULE, postcond}, ?MODULE)),
- %% Handle_call - stay-alive == true
- ?match({reply, {'EXCEPTION', #'OBJ_ADAPTER'{}},_},
- corba:handle_call(?MODULE, foo, [],
- {?NO_EXIT, state}, [], false, false, {wrong_mod, precond},
- {?MODULE, postcond}, ?MODULE)),
- %% Handle_call - stay-alive == true
- ?match({reply, {'EXCEPTION', #'OBJ_ADAPTER'{}},_},
- corba:handle_call(?MODULE, foo, [],
- {?NO_EXIT, state}, [], false, false, {?MODULE, bad_precond},
- {?MODULE, postcond}, ?MODULE)),
- %% Handle_cast - stay-alive == false
- ?match({'EXIT', _},
- corba:handle_cast(?MODULE, foo_1w, [],
- {?DO_EXIT, state}, [], false, {wrong_mod, precond},
- {?MODULE, postcond}, ?MODULE)),
- %% Handle_cast - stay-alive == false
- ?match({'EXIT', _},
- corba:handle_cast(?MODULE, foo_1w, [],
- {?DO_EXIT, state}, [], false, {?MODULE, bad_precond},
- {?MODULE, postcond}, ?MODULE)),
- %% Handle_cast - stay-alive == true
- ?match({noreply, {?NO_EXIT, state}},
- corba:handle_cast(?MODULE, foo_1w, [],
- {?NO_EXIT, state}, [], false, {wrong_mod, precond},
- {?MODULE, postcond}, ?MODULE)),
- %% Handle_cast - stay-alive == true
- ?match({noreply, {?NO_EXIT, state}},
- corba:handle_cast(?MODULE, foo_1w, [],
- {?NO_EXIT, state}, [], false, {?MODULE, bad_precond},
- {?MODULE, postcond}, ?MODULE)),
- ok.
-
-
-%% Postcond callback API tests
-callback_postcond_api(_) ->
- %% Handle_call - stay-alive == false
- ?match({'EXIT', _},
- corba:handle_call(?MODULE, foo, [],
- {?DO_EXIT, state}, [], false, false, {?MODULE, precond},
- {wrong_mod, postcond}, ?MODULE)),
- %% Handle_call - stay-alive == false
- ?match({'EXIT', _},
- corba:handle_call(?MODULE, foo, [],
- {?DO_EXIT, state}, [], false, false, {?MODULE, precond},
- {?MODULE, bad_postcond}, ?MODULE)),
- %% Handle_call - stay-alive == true
- ?match({reply, {'EXCEPTION', #'OBJ_ADAPTER'{}},_},
- corba:handle_call(?MODULE, foo, [],
- {?NO_EXIT, state}, [], false, false, {?MODULE, precond},
- {wrong_mod, postcond}, ?MODULE)),
- %% Handle_call - stay-alive == true
- ?match({reply, {'EXCEPTION', #'OBJ_ADAPTER'{}},_},
- corba:handle_call(?MODULE, foo, [],
- {?NO_EXIT, state}, [], false, false, {?MODULE, precond},
- {?MODULE, bad_postcond}, ?MODULE)),
- %% Handle_cast - stay-alive == false
- ?match({'EXIT', _},
- corba:handle_cast(?MODULE, foo_1w, [],
- {?DO_EXIT, state}, [], false, {?MODULE, precond},
- {wrong_mod, postcond}, ?MODULE)),
- %% Handle_cast - stay-alive == false
- ?match({'EXIT', _},
- corba:handle_cast(?MODULE, foo_1w, [],
- {?DO_EXIT, state}, [], false, {?MODULE, precond},
- {?MODULE, bad_postcond}, ?MODULE)),
- %% Handle_cast - stay-alive == true
- ?match({noreply, {?NO_EXIT, state}},
- corba:handle_cast(?MODULE, foo_1w, [],
- {?NO_EXIT, state}, [], false, {?MODULE, precond},
- {wrong_mod, postcond}, ?MODULE)),
- %% Handle_cast - stay-alive == true
- ?match({noreply, {?NO_EXIT, state}},
- corba:handle_cast(?MODULE, foo_1w, [],
- {?NO_EXIT, state}, [], false, {?MODULE, precond},
- {?MODULE, bad_postcond}, ?MODULE)),
- ok.
-
-
-%% Callback exit API tests
-callback_exit_api(_) ->
- %% Handle_call - stay-alive == false
- ?match({'EXIT', _},
- corba:handle_call(?MODULE, foo, [],
- {?DO_EXIT, exit}, [], false, false)),
- %% Handle_call - stay-alive == true
- ?match({reply, {'EXCEPTION', #'OBJ_ADAPTER'{}}, _},
- corba:handle_call(?MODULE, foo, [],
- {?NO_EXIT, exit}, [], false, false)),
- %% Handle_cast - stay-alive == false
- ?match({'EXIT', _},
- corba:handle_cast(?MODULE, foo_1w, [],
- {?DO_EXIT, exit}, [], false)),
- %% Handle_cast - stay-alive == true
- ?match({noreply, {?NO_EXIT, exit}},
- corba:handle_cast(?MODULE, foo_1w, [],
- {?NO_EXIT, exit}, [], false)),
- %% Handle_info - stay-alive == false
- ?match({'EXIT', _},
- corba:handle_info(?MODULE, "info", {?DO_EXIT, exit})),
-
- %% Handle_info - stay-alive == true
- ?match({noreply, {?NO_EXIT, exit}},
- corba:handle_info(?MODULE, "info", {?NO_EXIT, exit})),
- ok.
-
-
-%% Callback badarith API tests
-callback_badarith_api(_) ->
- %% Handle_call - stay-alive == false
- ?match({'EXIT', _},
- corba:handle_call(?MODULE, foo, [],
- {?DO_EXIT, badarith}, [], false, false)),
- %% Handle_call - stay-alive == true
- ?match({reply, {'EXCEPTION', #'OBJ_ADAPTER'{}},_},
- corba:handle_call(?MODULE, foo, [],
- {?NO_EXIT, badarith}, [], false, false)),
- %% Handle_cast - stay-alive == false
- ?match({'EXIT', _},
- corba:handle_cast(?MODULE, foo_1w, [],
- {?DO_EXIT, badarith}, [], false)),
- %% Handle_cast - stay-alive == true
- ?match({noreply, {?NO_EXIT, badarith}},
- corba:handle_cast(?MODULE, foo_1w, [],
- {?NO_EXIT, badarith}, [], false)),
- %% Handle_info - stay-alive == false
- ?match({'EXIT', _},
- corba:handle_info(?MODULE, "info", {?DO_EXIT, badarith})),
-
- %% Handle_info - stay-alive == true
- ?match({noreply, {?NO_EXIT, badarith}},
- corba:handle_info(?MODULE, "info", {?NO_EXIT, badarith})),
- ok.
-
-%% Callback case_clause API tests
-callback_case_clause_api(_) ->
- %% Handle_call - stay-alive == false
- ?match({'EXIT', _},
- corba:handle_call(?MODULE, foo, [],
- {?DO_EXIT, case_clause}, [], false, false)),
- %% Handle_call - stay-alive == true
- ?match({reply, {'EXCEPTION', #'OBJ_ADAPTER'{}}, _},
- corba:handle_call(?MODULE, foo, [],
- {?NO_EXIT, case_clause}, [], false, false)),
- %% Handle_cast - stay-alive == false
- ?match({'EXIT', _},
- corba:handle_cast(?MODULE, foo_1w, [],
- {?DO_EXIT, case_clause}, [], false)),
- %% Handle_cast - stay-alive == true
- ?match({noreply, {?NO_EXIT, case_clause}},
- corba:handle_cast(?MODULE, foo_1w, [],
- {?NO_EXIT, case_clause}, [], false)),
- %% Handle_info - stay-alive == false
- ?match({'EXIT', _},
- corba:handle_info(?MODULE, "info", {?DO_EXIT, case_clause})),
-
- %% Handle_info - stay-alive == true
- ?match({noreply, {?NO_EXIT, case_clause}},
- corba:handle_info(?MODULE, "info", {?NO_EXIT, case_clause})),
- ok.
-
-%% Callback function_clause API tests
-callback_function_clause_api(_) ->
- %% Handle_call - stay-alive == false
- ?match({'EXIT', _},
- corba:handle_call(?MODULE, foo, [],
- {?DO_EXIT, function_clause}, [], false, false)),
- %% Handle_call - stay-alive == true
- ?match({reply, {'EXCEPTION', #'OBJ_ADAPTER'{}}, _},
- corba:handle_call(?MODULE, foo, [],
- {?NO_EXIT, function_clause}, [], false, false)),
- %% Handle_cast - stay-alive == false
- ?match({'EXIT', _},
- corba:handle_cast(?MODULE, foo_1w, [],
- {?DO_EXIT, function_clause}, [], false)),
- %% Handle_cast - stay-alive == true
- ?match({noreply, {?NO_EXIT, function_clause}},
- corba:handle_cast(?MODULE, foo_1w, [],
- {?NO_EXIT, function_clause}, [], false)),
- %% Handle_info - stay-alive == false
- ?match({'EXIT', _},
- corba:handle_info(?MODULE, "info", {?DO_EXIT, function_clause})),
- %% Handle_info - stay-alive == true
- ?match({noreply, {?NO_EXIT, function_clause}},
- corba:handle_info(?MODULE, "info", {?NO_EXIT, function_clause})),
- ok.
-
-%% Faked mandatory operations
-init(State) ->
- evaluate_state(State),
- {ok, State}.
-terminate(_Reason, State) ->
- evaluate_state(State),
- ok.
-
-code_change(_OldVsn, State, _Extra) ->
- evaluate_state(State),
- {ok, State}.
-handle_call(_,_, State) ->
- evaluate_state(State),
- {noreply, State}.
-handle_cast(_, State) ->
- evaluate_state(State),
- {noreply, State}.
-handle_info(_Info, State) ->
- evaluate_state(State),
- {noreply, State}.
-
-foo(State) ->
- evaluate_state(State),
- {reply, ok, State}.
-foo(State, _Arg) ->
- evaluate_state(State),
- {reply, ok, State}.
-
-foo_1w(State) ->
- evaluate_state(State),
- {noreply, State}.
-foo_1w(State, _Arg) ->
- evaluate_state(State),
- {noreply, State}.
-
-precond(_Module, _Function, _Args) ->
- ok.
-
-postcond(_Module, _Function, _Args, _Result) ->
- ok.
-
-evaluate_state(exit) ->
- exit("exit on purpose");
-evaluate_state(badarith) ->
- 10 * atom;
-evaluate_state(case_clause) ->
- case 10 of
- false ->
- ok
- end;
-evaluate_state(module) ->
- non_existing_module:bar();
-evaluate_state(function) ->
- ?MODULE:non_existing_function();
-evaluate_state(arity) ->
- ?MODULE:foo(to, many, arguments);
-evaluate_state(function_clause) ->
- evaluate_state(incorrect_state);
-evaluate_state(state) ->
- ok.
-
-%%-----------------------------------------------------------------
-%% Local functions.
-%%-----------------------------------------------------------------
-
-pseudo_calls(0, _) ->
- ok;
-pseudo_calls(Times, Obj) ->
- orber_test_server:pseudo_call(Obj),
- New = Times - 1,
- pseudo_calls(New, Obj).
-pseudo_casts(0, _) ->
- ok;
-pseudo_casts(Times, Obj) ->
- orber_test_server:pseudo_cast(Obj),
- New = Times - 1,
- pseudo_casts(New, Obj).
diff --git a/lib/orber/test/csiv2_SUITE.erl b/lib/orber/test/csiv2_SUITE.erl
deleted file mode 100644
index 7844060582..0000000000
--- a/lib/orber/test/csiv2_SUITE.erl
+++ /dev/null
@@ -1,889 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(csiv2_SUITE).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/include/corba.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming.hrl").
--include_lib("orber/src/orber_iiop.hrl").
--include_lib("orber/src/ifr_objects.hrl").
--include("idl_output/orber_test_server.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming_NamingContextExt.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming_NamingContext.hrl").
-%%-include_lib("orber/src/OrberCSIv2.hrl").
-
--define(default_timeout, test_server:minutes(5)).
-
--define(match(ExpectedRes,Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- io:format("------ CORRECT RESULT ------~n~p~n",
- [AcTuAlReS]),
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~nRESULT: ~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
--define(REQUEST_ID, 0).
-
--define(REPLY_FRAG_1, <<71,73,79,80,1,2,2,1,0,0,0,41,0,0,0,?REQUEST_ID,0,0,0,0,0,0,0,1,78,69,79,0,0,0,0,2,0,10,0,0,0,0,0,0,0,0,0,18,0,0,0,0,0,0,0,4,49>>).
-%% The fragments are identical for requests and replies.
--define(FRAG_2, <<71,73,79,80,1,2,2,7,0,0,0,5,0,0,0,?REQUEST_ID,50>>).
--define(FRAG_3, <<71,73,79,80,1,2,2,7,0,0,0,5,0,0,0,?REQUEST_ID,51>>).
--define(FRAG_4, <<71,73,79,80,1,2,0,7,0,0,0,5,0,0,0,?REQUEST_ID,0>>).
-
-%% Should X509 DER generated by, for example, OpenSSL
--define(X509DER,
- <<42>>).
-
-%% Should X509 PEM generated by, for example, OpenSSL
--define(X509PEM,
- <<42>>).
-
-%% IOR exported by VB (CSIv2 activated).
--define(VB_IOR,
- #'IOP_IOR'
- {type_id = "IDL:omg.org/CosNotifyComm/SequencePushConsumer:1.0",
- profiles =
- [#'IOP_TaggedProfile'
- {tag = ?TAG_INTERNET_IOP,
- profile_data =
- #'IIOP_ProfileBody_1_1'{
- iiop_version = #'IIOP_Version'{major = 1,
- minor = 2},
- host = "127.0.0.1",
- port = 0,
- object_key = [0,86,66,1,0,0,0,24,47,70,77,65,95,67,73,82,80,77,65,78,95,80,79,65,95,83,69,67,85,82,69,0,0,0,0,4,0,0,4,186,0,0,2,10,81,218,65,185],
- components =
- [#'IOP_TaggedComponent'{tag = ?TAG_SSL_SEC_TRANS,
- component_data = #'SSLIOP_SSL'{
- target_supports = 102,
- target_requires = 66,
- port = 49934}},
- #'IOP_TaggedComponent'{tag = ?TAG_CSI_SEC_MECH_LIST,
- component_data =
- #'CSIIOP_CompoundSecMechList'{stateful = true,
- mechanism_list =
- [#'CSIIOP_CompoundSecMech'
- {target_requires = 66,
- transport_mech = #'IOP_TaggedComponent'{
- tag = ?TAG_TLS_SEC_TRANS,
- component_data =
- #'CSIIOP_TLS_SEC_TRANS'{
- target_supports = 102,
- target_requires = 66,
- addresses =
- [#'CSIIOP_TransportAddress'
- {host_name = "127.0.0.1",
- port = 49934}]}},
- as_context_mech =
- #'CSIIOP_AS_ContextSec'{
- target_supports = 0,
- target_requires = 0,
- client_authentication_mech = [],
- target_name = []},
- sas_context_mech =
- #'CSIIOP_SAS_ContextSec'{
- target_supports = 1024,
- target_requires = 0,
- privilege_authorities =
- [#'CSIIOP_ServiceConfiguration'
- {syntax = 1447174401,
- name = "Borland"}],
- supported_naming_mechanisms = [[6,
- 6,
- 103,
- 129,
- 2,
- 1,
- 1,
- 1]],
- supported_identity_types = 15}}]}},
- #'IOP_TaggedComponent'
- {tag = ?TAG_CODE_SETS,
- component_data =
- #'CONV_FRAME_CodeSetComponentInfo'{'ForCharData' =
- #'CONV_FRAME_CodeSetComponent'{
- native_code_set = 65537,
- conversion_code_sets = [83951617]},
- 'ForWcharData' =
- #'CONV_FRAME_CodeSetComponent'{
- native_code_set = 65801,
- conversion_code_sets = []}}},
- #'IOP_TaggedComponent'{tag = ?TAG_ORB_TYPE,
- component_data = 1447645952},
- #'IOP_TaggedComponent'{tag = 1447645955,
- component_data = [0,5,7,1,127]}]}}]}).
-
-%% Common basic types
--define(OID, {2,23,130,1,1,1}).
-
--define(OCTET_STR, [1,2,3,4]).
-
--define(BIT_STR, [0,1,0,1,1]).
-
--define(BOOLEAN, false).
-
--define(ANY, [19,5,111,116,112,67,65]).
-
--ifdef(false).
-%% PKIX1Explicit88
--define(AlgorithmIdentifier,
- #'AlgorithmIdentifier'{algorithm = ?OID,
- parameters = ?ANY}).
-
--define(Validity, #'Validity'{notBefore = {utcTime, "19820102070533.8"},
- notAfter = {generalTime, "19820102070533.8"}}).
-
--define(SubjectPublicKeyInfo,
- #'SubjectPublicKeyInfo'{algorithm = ?AlgorithmIdentifier,
- subjectPublicKey = ?BIT_STR}).
-
--define(AttributeTypeAndValue,
- #'AttributeTypeAndValue'{type = ?OID,
- value = <<19,11,69,114,105,99,115,115,111,110,32,65,66>>}).
-
--define(RelativeDistinguishedName, [?AttributeTypeAndValue]).
-
--define(RDNSequence, [?RelativeDistinguishedName]).
-
--define(Name, {rdnSequence, ?RDNSequence}).
-
--define(Version, v3).
-
--define(CertificateSerialNumber, 1).
-
--define(UniqueIdentifier, ?BIT_STR).
-
--define(Extension, #'Extension'{extnID = ?OID,
- critical = ?BOOLEAN,
- extnValue = ?OCTET_STR}).
-
--define(Extensions, [?Extension]).
-
--define(TBSCertificate,
- #'TBSCertificate'{version = ?Version,
- serialNumber = ?CertificateSerialNumber,
- signature = ?AlgorithmIdentifier,
- issuer = ?Name,
- validity = ?Validity,
- subject = ?Name,
- subjectPublicKeyInfo = ?SubjectPublicKeyInfo,
- issuerUniqueID = ?UniqueIdentifier,
- subjectUniqueID = ?UniqueIdentifier,
- extensions = ?Extensions}).
-
--define(Certificate, #'Certificate'{tbsCertificate = ?TBSCertificate,
- signatureAlgorithm = ?AlgorithmIdentifier,
- signature = ?BIT_STR}).
-
-%% PKIX1Implicit88
-
--define(GeneralName, {registeredID, ?OID}).
-
--define(GeneralNames, [?GeneralName]).
-
-%% PKIXAttributeCertificate
--define(AttCertValidityPeriod,
- #'AttCertValidityPeriod'{notBeforeTime = "19820102070533.8",
- notAfterTime = "19820102070533.8"}).
-
-
--define(Attribute, #'Attribute'{type = ?OID,
- values = []}).
-
--define(Attributes, [?Attribute]).
-
--define(IssuerSerial, #'IssuerSerial'{issuer = ?GeneralNames,
- serial = ?CertificateSerialNumber,
- issuerUID = ?UniqueIdentifier}).
-
--define(DigestedObjectType, publicKey). %% Enum
-
--define(ObjectDigestInfo,
- #'ObjectDigestInfo'{digestedObjectType = ?DigestedObjectType,
- otherObjectTypeID = ?OID,
- digestAlgorithm = ?AlgorithmIdentifier,
- objectDigest = ?BIT_STR}).
-
--define(V2Form, #'V2Form'{issuerName = ?GeneralNames,
- baseCertificateID = ?IssuerSerial,
- objectDigestInfo = ?ObjectDigestInfo}).
-
--define(AttCertVersion, v2).
-
--define(Holder, #'Holder'{baseCertificateID = ?IssuerSerial,
- entityName = ?GeneralNames,
- objectDigestInfo = ?ObjectDigestInfo}).
-
--define(AttCertIssuer, {v2Form, ?V2Form}).
-
--define(AttributeCertificateInfo,
- #'AttributeCertificateInfo'{version = ?AttCertVersion,
- holder = ?Holder,
- issuer = ?AttCertIssuer,
- signature = ?AlgorithmIdentifier,
- serialNumber = ?CertificateSerialNumber,
- attrCertValidityPeriod = ?AttCertValidityPeriod,
- attributes = ?Attributes,
- issuerUniqueID = ?UniqueIdentifier,
- extensions = ?Extensions}).
-
--define(AttributeCertificate,
- #'AttributeCertificate'{acinfo = ?AttributeCertificateInfo,
- signatureAlgorithm = ?AlgorithmIdentifier,
- signatureValue = ?BIT_STR}).
-
-
-%% OrberCSIv2
--define(AttributeCertChain,
- #'AttributeCertChain'{attributeCert = ?AttributeCertificate,
- certificateChain = ?CertificateChain}).
-
--define(CertificateChain, [?Certificate]).
-
--define(VerifyingCertChain, [?Certificate]).
-
--endif.
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2, cases/0,
- init_per_suite/1, end_per_suite/1,
- init_per_testcase/2, end_per_testcase/2,
-% code_CertificateChain_api/1,
-% code_AttributeCertChain_api/1,
-% code_VerifyingCertChain_api/1,
-% code_AttributeCertificate_api/1,
-% code_Certificate_api/1,
-% code_TBSCertificate_api/1,
-% code_CertificateSerialNumber_api/1,
-% code_Version_api/1,
-% code_AlgorithmIdentifier_api/1,
-% code_Name_api/1,
-% code_RDNSequence_api/1,
-% code_RelativeDistinguishedName_api/1,
-% code_AttributeTypeAndValue_api/1,
-% code_Attribute_api/1,
-% code_Validity_api/1,
-% code_SubjectPublicKeyInfo_api/1,
-% code_UniqueIdentifier_api/1,
-% code_Extensions_api/1,
-% code_Extension_api/1,
-% code_AttributeCertificateInfo_api/1,
-% code_AttCertVersion_api/1,
-% code_Holder_api/1,
-% code_AttCertIssuer_api/1,
-% code_AttCertValidityPeriod_api/1,
-% code_V2Form_api/1,
-% code_IssuerSerial_api/1,
-% code_ObjectDigestInfo_api/1,
-% code_OpenSSL509_api/1,
- ssl_server_peercert_api/1,
- ssl_client_peercert_api/1]).
-
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([fake_server_ORB/5]).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- cases().
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%% NOTE - the fragment test cases must bu first since we explicitly set a request
-%% id. Otherwise, the request-id counter would be increased and we cannot know
-%% what it is.
-cases() ->
- [ssl_server_peercert_api, ssl_client_peercert_api].
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-
-init_per_testcase(_Case, Config) ->
- Path = code:which(?MODULE),
- code:add_pathz(filename:join(filename:dirname(Path), "idl_output")),
- Dog=test_server:timetrap(?default_timeout),
- orber:jump_start(0),
- oe_orber_test_server:oe_register(),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- oe_orber_test_server:oe_unregister(),
- orber:jump_stop(),
- Path = code:which(?MODULE),
- code:del_path(filename:join(filename:dirname(Path), "idl_output")),
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-init_per_suite(Config) ->
- try crypto:start() of
- ok ->
- case orber_test_lib:ssl_version() of
- no_ssl ->
- {skip, "SSL is not installed!"};
- _ ->
- Config
- end
- catch _:_ ->
- {skip, "Crypto did not start"}
- end.
-
-end_per_suite(Config) ->
- application:stop(crypto),
- Config.
-
-%%-----------------------------------------------------------------
-%% API tests for ORB to ORB, no security
-%%-----------------------------------------------------------------
-
-
-%%-----------------------------------------------------------------
-%% Encode and decode ASN.1 X509
-%%-----------------------------------------------------------------
-
--ifdef(false).
-%% OrberCSIv2
-%%-----------------------------------------------------------------
-%% Code CertificateChain
-code_CertificateChain_api(_Config) ->
- {ok, Enc} =
- ?match({ok, _},
- 'OrberCSIv2':encode('CertificateChain', ?CertificateChain)),
- ?match({ok, [#'Certificate'{}]},
- 'OrberCSIv2':decode('CertificateChain', list_to_binary(Enc))),
- ok.
-
-%% Code AttributeCertChain
-code_AttributeCertChain_api(_Config) ->
- {ok, Enc} =
- ?match({ok, _},
- 'OrberCSIv2':encode('AttributeCertChain', ?AttributeCertChain)),
- ?match({ok, #'AttributeCertChain'{}},
- 'OrberCSIv2':decode('AttributeCertChain', list_to_binary(Enc))),
- ok.
-
-%% Code VerifyingCertChain
-code_VerifyingCertChain_api(_Config) ->
- {ok, Enc} =
- ?match({ok, _},
- 'OrberCSIv2':encode('VerifyingCertChain', ?VerifyingCertChain)),
- ?match({ok, [#'Certificate'{}]},
- 'OrberCSIv2':decode('VerifyingCertChain', list_to_binary(Enc))),
- ok.
-
-%% PKIXAttributeCertificate
-%%-----------------------------------------------------------------
-%% Code AttributeCertificate
-code_AttributeCertificate_api(_Config) ->
- {ok, Enc} =
- ?match({ok, _},
- 'OrberCSIv2':encode('AttributeCertificate', ?AttributeCertificate)),
- ?match({ok, #'AttributeCertificate'{}},
- 'OrberCSIv2':decode('AttributeCertificate', list_to_binary(Enc))),
- ok.
-
-%% Code AttributeCertificateInfo
-code_AttributeCertificateInfo_api(_Config) ->
- {ok, Enc} =
- ?match({ok, _},
- 'OrberCSIv2':encode('AttributeCertificateInfo', ?AttributeCertificateInfo)),
- ?match({ok, #'AttributeCertificateInfo'{}},
- 'OrberCSIv2':decode('AttributeCertificateInfo', list_to_binary(Enc))),
- ok.
-
-%% Code AttCertVersion
-code_AttCertVersion_api(_Config) ->
- {ok, Enc} =
- ?match({ok, _},
- 'OrberCSIv2':encode('AttCertVersion', ?AttCertVersion)),
- ?match({ok, ?AttCertVersion},
- 'OrberCSIv2':decode('AttCertVersion', list_to_binary(Enc))),
- ok.
-
-%% Code Holder
-code_Holder_api(_Config) ->
- {ok, Enc} =
- ?match({ok, _},
- 'OrberCSIv2':encode('Holder', ?Holder)),
- ?match({ok, #'Holder'{}},
- 'OrberCSIv2':decode('Holder', list_to_binary(Enc))),
- ok.
-
-%% Code AttCertIssuer
-code_AttCertIssuer_api(_Config) ->
- {ok, Enc} =
- ?match({ok, _},
- 'OrberCSIv2':encode('AttCertIssuer', ?AttCertIssuer)),
- ?match({ok, {v2Form, _}},
- 'OrberCSIv2':decode('AttCertIssuer', list_to_binary(Enc))),
- ok.
-
-%% Code AttCertValidityPeriod
-code_AttCertValidityPeriod_api(_Config) ->
- {ok, Enc} =
- ?match({ok, _}, 'OrberCSIv2':encode('AttCertValidityPeriod', ?AttCertValidityPeriod)),
- ?match({ok, #'AttCertValidityPeriod'{}},
- 'OrberCSIv2':decode('AttCertValidityPeriod', list_to_binary(Enc))),
- ok.
-
-%% Code V2Form
-code_V2Form_api(_Config) ->
- {ok, Enc} =
- ?match({ok, _},
- 'OrberCSIv2':encode('V2Form', ?V2Form)),
- ?match({ok, #'V2Form'{}},
- 'OrberCSIv2':decode('V2Form', list_to_binary(Enc))),
- ok.
-
-%% Code IssuerSerial
-code_IssuerSerial_api(_Config) ->
- {ok, Enc} =
- ?match({ok, _},
- 'OrberCSIv2':encode('IssuerSerial', ?IssuerSerial)),
- ?match({ok, #'IssuerSerial'{}},
- 'OrberCSIv2':decode('IssuerSerial', list_to_binary(Enc))),
- ok.
-
-%% Code ObjectDigestInfo
-code_ObjectDigestInfo_api(_Config) ->
- {ok, Enc} =
- ?match({ok, _},
- 'OrberCSIv2':encode('ObjectDigestInfo', ?ObjectDigestInfo)),
- ?match({ok, #'ObjectDigestInfo'{}},
- 'OrberCSIv2':decode('ObjectDigestInfo', list_to_binary(Enc))),
- ok.
-
-%% PKIX1Explicit88
-%%-----------------------------------------------------------------
-%% Code Certificate
-code_Certificate_api(_Config) ->
- {ok, Enc} =
- ?match({ok, _},
- 'OrberCSIv2':encode('Certificate', ?Certificate)),
- ?match({ok, #'Certificate'{}},
- 'OrberCSIv2':decode('Certificate', list_to_binary(Enc))),
- ok.
-
-%% Code TBSCertificate
-code_TBSCertificate_api(_Config) ->
- {ok, Enc} =
- ?match({ok, _},
- 'OrberCSIv2':encode('TBSCertificate', ?TBSCertificate)),
- ?match({ok, #'TBSCertificate'{}},
- 'OrberCSIv2':decode('TBSCertificate', list_to_binary(Enc))),
- ok.
-
-%% Code CertificateSerialNumber"];
-code_CertificateSerialNumber_api(_Config) ->
- {ok, Enc} =
- ?match({ok, _},
- 'OrberCSIv2':encode('CertificateSerialNumber', ?CertificateSerialNumber)),
- ?match({ok, ?CertificateSerialNumber},
- 'OrberCSIv2':decode('CertificateSerialNumber', list_to_binary(Enc))),
- ok.
-
-%% Code Version
-code_Version_api(_Config) ->
- {ok, Enc} =
- ?match({ok, _}, 'OrberCSIv2':encode('Version', ?Version)),
- ?match({ok, ?Version}, 'OrberCSIv2':decode('Version', list_to_binary(Enc))),
- ok.
-
-%% Code AlgorithmIdentifier
-code_AlgorithmIdentifier_api(_Config) ->
- {ok, Enc} =
- ?match({ok, _}, 'OrberCSIv2':encode('AlgorithmIdentifier', ?AlgorithmIdentifier)),
- ?match({ok, #'AlgorithmIdentifier'{}},
- 'OrberCSIv2':decode('AlgorithmIdentifier', list_to_binary(Enc))),
- ok.
-
-%% Code Name
-code_Name_api(_Config) ->
- {ok, Enc} =
- ?match({ok, _}, 'OrberCSIv2':encode('Name', ?Name)),
- ?match({ok, {rdnSequence,_}},
- 'OrberCSIv2':decode('Name', list_to_binary(Enc))),
- ok.
-
-%% Code RDNSequence
-code_RDNSequence_api(_Config) ->
- {ok, Enc} =
- ?match({ok, _}, 'OrberCSIv2':encode('RDNSequence', ?RDNSequence)),
- ?match({ok, [[#'AttributeTypeAndValue'{}]]},
- 'OrberCSIv2':decode('RDNSequence', list_to_binary(Enc))),
- ok.
-
-%% Code RelativeDistinguishedName
-code_RelativeDistinguishedName_api(_Config) ->
- {ok, Enc} =
- ?match({ok, _}, 'OrberCSIv2':encode('RelativeDistinguishedName', ?RelativeDistinguishedName)),
- ?match({ok, [#'AttributeTypeAndValue'{}]},
- 'OrberCSIv2':decode('RelativeDistinguishedName', list_to_binary(Enc))),
- ok.
-
-%% Code AttributeTypeAndValue
-code_AttributeTypeAndValue_api(_Config) ->
- {ok, Enc} =
- ?match({ok, _}, 'OrberCSIv2':encode('AttributeTypeAndValue', ?AttributeTypeAndValue)),
- ?match({ok, #'AttributeTypeAndValue'{}},
- 'OrberCSIv2':decode('AttributeTypeAndValue', list_to_binary(Enc))),
- ok.
-
-%% Code Attribute"];
-code_Attribute_api(_Config) ->
- {ok, Enc} =
- ?match({ok, _}, 'OrberCSIv2':encode('Attribute', ?Attribute)),
- ?match({ok, #'Attribute'{}},
- 'OrberCSIv2':decode('Attribute', list_to_binary(Enc))),
- ok.
-
-%% Code Validity
-code_Validity_api(_Config) ->
- {ok, Enc} =
- ?match({ok, _}, 'OrberCSIv2':encode('Validity', ?Validity)),
- ?match({ok, #'Validity'{}},
- 'OrberCSIv2':decode('Validity', list_to_binary(Enc))),
- ok.
-
-%% Code SubjectPublicKeyInfo
-code_SubjectPublicKeyInfo_api(_Config) ->
- {ok, Enc} =
- ?match({ok, _}, 'OrberCSIv2':encode('SubjectPublicKeyInfo', ?SubjectPublicKeyInfo)),
- ?match({ok, #'SubjectPublicKeyInfo'{}},
- 'OrberCSIv2':decode('SubjectPublicKeyInfo', list_to_binary(Enc))),
- ok.
-
-%% Code UniqueIdentifier
-code_UniqueIdentifier_api(_Config) ->
- {ok, Enc} =
- ?match({ok, _}, 'OrberCSIv2':encode('UniqueIdentifier', ?UniqueIdentifier)),
- ?match({ok, _}, 'OrberCSIv2':decode('UniqueIdentifier', list_to_binary(Enc))),
- ok.
-
-%% Code Extensions
-code_Extensions_api(_Config) ->
- {ok, Enc} =
- ?match({ok, _}, 'OrberCSIv2':encode('Extensions', ?Extensions)),
- ?match({ok, [#'Extension'{}]},
- 'OrberCSIv2':decode('Extensions', list_to_binary(Enc))),
- ok.
-
-%% Code Extension
-code_Extension_api(_Config) ->
- {ok, Enc} =
- ?match({ok, _}, 'OrberCSIv2':encode('Extension', ?Extension)),
- ?match({ok, #'Extension'{}},
- 'OrberCSIv2':decode('Extension', list_to_binary(Enc))),
- ok.
-
-%% OpenSSL generated x509 Certificate
-%%-----------------------------------------------------------------
-%% Code OpenSSL generated x509 Certificate
-code_OpenSSL509_api(_Config) ->
- {ok, Cert} =
- ?match({ok, #'Certificate'{}},
- 'OrberCSIv2':decode('Certificate', ?X509DER)),
- AttrCertChain = #'AttributeCertChain'{attributeCert = ?AttributeCertificate,
- certificateChain = [Cert]},
- {ok, EAttrCertChain} =
- ?match({ok, _}, 'OrberCSIv2':encode('AttributeCertChain', AttrCertChain)),
- ?match({ok, #'AttributeCertChain'{}},
- 'OrberCSIv2':decode('AttributeCertChain', list_to_binary(EAttrCertChain))),
- ok.
-
--endif.
-
-%%-----------------------------------------------------------------
-%% Test ssl:peercert
-%%-----------------------------------------------------------------
-%% Test ssl:peercert (server side)
-ssl_server_peercert_api(_Config) ->
- Options = orber_test_lib:get_options(iiop_ssl, server,
- 2, [{iiop_ssl_port, 0}]),
- {ok, ServerNode, ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node(Options)),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_ssl_port, []),
- SSLOptions = orber_test_lib:get_options(ssl, client),
- {ok, Socket} =
- ?match({ok, _}, fake_client_ORB(ssl, ServerHost, ServerPort, SSLOptions)),
- {ok, _PeerCert} = ?match({ok, _}, orber_socket:peercert(ssl, Socket)),
- %% ?match({ok, {rdnSequence, _}}, orber_socket:peercert(ssl, Socket, [pkix, subject])),
- %% ?match({ok, {rdnSequence, _}}, orber_socket:peercert(ssl, Socket, [ssl, subject])),
- % ?match({ok, #'Certificate'{}},
- % 'OrberCSIv2':decode('Certificate', PeerCert)),
- destroy_fake_ORB(ssl, Socket),
- ok.
-
-%% Test ssl:peercert (client side)
-ssl_client_peercert_api(_Config) ->
- Options = orber_test_lib:get_options(iiop_ssl, client,
- 2, [{iiop_ssl_port, 0}]),
- {ok, ClientNode, _ClientHost} =
- ?match({ok,_,_}, orber_test_lib:js_node(Options)),
- crypto:start(),
- ssl:start(),
- SSLOptions = orber_test_lib:get_options(ssl, server),
- {ok, LSock} = ?match({ok, _}, ssl:listen(0, SSLOptions)),
- {ok, {_Address, LPort}} = ?match({ok, {_, _}}, ssl:sockname(LSock)),
- IOR = ?match({'IOP_IOR',_,_},
- iop_ior:create_external({1, 2}, "IDL:FAKE:1.0",
- "localhost", 6004, "FAKE",
- [#'IOP_TaggedComponent'
- {tag=?TAG_SSL_SEC_TRANS,
- component_data=#'SSLIOP_SSL'
- {target_supports = 2,
- target_requires = 2,
- port = LPort}}])),
- spawn(orber_test_lib, remote_apply,
- [ClientNode, corba_object, non_existent, [IOR]]),
- {ok, Socket} = ?match({ok, _}, ssl:transport_accept(LSock)),
- ?match(ok, ssl:ssl_accept(Socket)),
-
- {ok, _PeerCert} = ?match({ok, _}, orber_socket:peercert(ssl, Socket)),
- %% ?match({ok, {rdnSequence, _}}, orber_socket:peercert(ssl, Socket, [pkix, subject])),
- %% ?match({ok, {rdnSequence, _}}, orber_socket:peercert(ssl, Socket, [ssl, subject])),
- % ?match({ok, #'Certificate'{}},
- % 'OrberCSIv2':decode('Certificate', PeerCert)),
- ssl:close(Socket),
- ssl:close(LSock),
- ssl:stop(),
- ok.
-
-%%-----------------------------------------------------------------
-%% Local functions.
-%%-----------------------------------------------------------------
--ifdef(false).
-%% Not used yet.
-context_test(Obj) ->
- IDToken1 = #'CSI_IdentityToken'{label = ?CSI_IdentityTokenType_ITTAbsent,
- value = true},
- IDToken2 = #'CSI_IdentityToken'{label = ?CSI_IdentityTokenType_ITTAnonymous,
- value = false},
- IDToken3 = #'CSI_IdentityToken'{label = ?CSI_IdentityTokenType_ITTPrincipalName,
- value = [0,255]},
- IDToken4 = #'CSI_IdentityToken'{label = ?CSI_IdentityTokenType_ITTX509CertChain,
- value = [1,255]},
- IDToken5 = #'CSI_IdentityToken'{label = ?CSI_IdentityTokenType_ITTDistinguishedName,
- value = [2,255]},
- IDToken6 = #'CSI_IdentityToken'{label = ?ULONGMAX,
- value = [3,255]},
-
- MTEstablishContext1 = #'CSI_SASContextBody'
- {label = ?CSI_MsgType_MTEstablishContext,
- value = #'CSI_EstablishContext'{client_context_id = ?ULONGLONGMAX,
- authorization_token =
- [#'CSI_AuthorizationElement'
- {the_type = ?ULONGMAX,
- the_element = [0,255]}],
- identity_token = IDToken1,
- client_authentication_token = [1, 255]}},
- MTEstablishContext2 = #'CSI_SASContextBody'
- {label = ?CSI_MsgType_MTEstablishContext,
- value = #'CSI_EstablishContext'{client_context_id = ?ULONGLONGMAX,
- authorization_token =
- [#'CSI_AuthorizationElement'
- {the_type = ?ULONGMAX,
- the_element = [0,255]}],
- identity_token = IDToken2,
- client_authentication_token = [1, 255]}},
- MTEstablishContext3 = #'CSI_SASContextBody'
- {label = ?CSI_MsgType_MTEstablishContext,
- value = #'CSI_EstablishContext'{client_context_id = ?ULONGLONGMAX,
- authorization_token =
- [#'CSI_AuthorizationElement'
- {the_type = ?ULONGMAX,
- the_element = [0,255]}],
- identity_token = IDToken3,
- client_authentication_token = [1, 255]}},
- MTEstablishContext4 = #'CSI_SASContextBody'
- {label = ?CSI_MsgType_MTEstablishContext,
- value = #'CSI_EstablishContext'{client_context_id = ?ULONGLONGMAX,
- authorization_token =
- [#'CSI_AuthorizationElement'
- {the_type = ?ULONGMAX,
- the_element = [0,255]}],
- identity_token = IDToken4,
- client_authentication_token = [1, 255]}},
- MTEstablishContext5 = #'CSI_SASContextBody'
- {label = ?CSI_MsgType_MTEstablishContext,
- value = #'CSI_EstablishContext'{client_context_id = ?ULONGLONGMAX,
- authorization_token =
- [#'CSI_AuthorizationElement'
- {the_type = ?ULONGMAX,
- the_element = [0,255]}],
- identity_token = IDToken5,
- client_authentication_token = [1, 255]}},
- MTEstablishContext6 = #'CSI_SASContextBody'
- {label = ?CSI_MsgType_MTEstablishContext,
- value = #'CSI_EstablishContext'{client_context_id = ?ULONGLONGMAX,
- authorization_token =
- [#'CSI_AuthorizationElement'
- {the_type = ?ULONGMAX,
- the_element = [0,255]}],
- identity_token = IDToken6,
- client_authentication_token = [1, 255]}},
- MTCompleteEstablishContext = #'CSI_SASContextBody'
- {label = ?CSI_MsgType_MTCompleteEstablishContext,
- value = #'CSI_CompleteEstablishContext'{client_context_id = ?ULONGLONGMAX,
- context_stateful = false,
- final_context_token = [1, 255]}},
- MTContextError = #'CSI_SASContextBody'
- {label = ?CSI_MsgType_MTContextError,
- value = #'CSI_ContextError'{client_context_id = ?ULONGLONGMAX,
- major_status = 1,
- minor_status = 2,
- error_token = [2,255]}},
- MTMessageInContext = #'CSI_SASContextBody'
- {label = ?CSI_MsgType_MTMessageInContext,
- value = #'CSI_MessageInContext'{client_context_id = ?ULONGLONGMAX,
- discard_context = true}},
- Ctx = [#'IOP_ServiceContext'{context_id=?IOP_SecurityAttributeService,
- context_data = MTEstablishContext1},
- #'IOP_ServiceContext'{context_id=?IOP_SecurityAttributeService,
- context_data = MTEstablishContext2},
- #'IOP_ServiceContext'{context_id=?IOP_SecurityAttributeService,
- context_data = MTEstablishContext3},
- #'IOP_ServiceContext'{context_id=?IOP_SecurityAttributeService,
- context_data = MTEstablishContext4},
- #'IOP_ServiceContext'{context_id=?IOP_SecurityAttributeService,
- context_data = MTEstablishContext5},
- #'IOP_ServiceContext'{context_id=?IOP_SecurityAttributeService,
- context_data = MTEstablishContext6},
- #'IOP_ServiceContext'{context_id=?IOP_SecurityAttributeService,
- context_data = MTCompleteEstablishContext},
- #'IOP_ServiceContext'{context_id=?IOP_SecurityAttributeService,
- context_data = MTContextError},
- #'IOP_ServiceContext'{context_id=?IOP_SecurityAttributeService,
- context_data = MTMessageInContext}],
- ?match(ok, orber_test_server:testing_iiop_context(Obj, [{context, Ctx}])).
-
-
-fake_server_ORB(Type, Port, Options) ->
- start_ssl(Type),
- {ok, ListenSocket, NewPort} =
- orber_socket:listen(Type, Port,
- [{active, false}|Options]),
- Socket = orber_socket:accept(Type, ListenSocket),
- orber_socket:post_accept(Type, Socket),
- {ok, Socket, NewPort}.
-
--endif.
-
-fake_server_ORB(Type, Port, Options, Action, Data) ->
- start_ssl(Type),
- {ok, ListenSocket, _NewPort} =
- orber_socket:listen(Type, Port, [{active, false}|Options]),
- Socket = orber_socket:accept(Type, ListenSocket),
- orber_socket:post_accept(Type, Socket),
- do_server_action(Type, Socket, Action, Data),
- orber_socket:close(Type, Socket),
- ok.
-
-start_ssl(ssl) ->
- crypto:start(),
- ssl:start();
-start_ssl(_) ->
- ok.
-
-
-destroy_fake_ORB(ssl, Socket) ->
- orber_socket:close(ssl, Socket),
- ssl:stop();
-destroy_fake_ORB(Type, Socket) ->
- orber_socket:close(Type, Socket).
-
-fake_client_ORB(Type, Host, Port, Options) ->
- start_ssl(Type),
- Socket = orber_socket:connect(Type, Host, Port, [{active, false}|Options]),
- {ok, Socket}.
-
--ifdef(false).
-%% Not used yet.
-
-fake_client_ORB(Type, Host, Port, Options, Action, Data) ->
- start_ssl(Type),
- Socket = orber_socket:connect(Type, Host, Port, [{active, false}|Options]),
- Result = do_client_action(Type, Socket, Action, Data),
- orber_socket:close(Type, Socket),
- Result.
-
-do_client_action(Type, Socket, fragments, FragList) ->
- ok = send_data(Type, Socket, FragList),
- {ok, Bytes} = gen_tcp:recv(Socket, 0),
- {#reply_header{request_id = ?REQUEST_ID, reply_status = no_exception}, ok, [Par]} =
- cdr_decode:dec_message({tk_void,[tk_any],[tk_any]}, Bytes),
- Par;
-do_client_action(Type, Socket, fragments_max, FragList) ->
- ok = send_data(Type, Socket, FragList),
- {ok, Bytes} = gen_tcp:recv(Socket, 0),
- {#reply_header{request_id = ?REQUEST_ID, reply_status = system_exception}, Exc, []} =
- cdr_decode:dec_message({tk_void,[tk_any],[tk_any]}, Bytes),
- Exc;
-do_client_action(Type, Socket, message_error, Data) ->
- ok = send_data(Type, Socket, Data),
- {ok,Bytes} = gen_tcp:recv(Socket, 0),
- 'message_error' = cdr_decode:dec_message({tk_void,[tk_any],[tk_any]}, Bytes),
- ok;
-do_client_action(_Type, _Socket, _Action, _Data) ->
- ok.
-
--endif.
-
-do_server_action(Type, Socket, fragments, FragList) ->
- {ok, _B} = gen_tcp:recv(Socket, 0),
- ok = send_data(Type, Socket, FragList);
-do_server_action(_Type, _Socket, _Action, _Data) ->
- ok.
-
-
-send_data(_Type, _Socket, []) ->
- ok;
-send_data(Type, Socket, [H|T]) ->
- orber_socket:write(Type, Socket, H),
- send_data(Type, Socket, T).
-
diff --git a/lib/orber/test/data_types_SUITE.erl b/lib/orber/test/data_types_SUITE.erl
deleted file mode 100644
index 3873bfbaf6..0000000000
--- a/lib/orber/test/data_types_SUITE.erl
+++ /dev/null
@@ -1,187 +0,0 @@
-%%-----------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File : data_types_SUITE.erl
-%% Purpose :
-%%-----------------------------------------------------------------
-
--module(data_types_SUITE).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/include/corba.hrl").
-
--define(default_timeout, test_server:minutes(3)).
-
--define(match(ExpectedRes, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- io:format("------ CORRECT RESULT ------~n~p~n",
- [AcTuAlReS]),
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--compile(export_all).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [fixed_type, any_type].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-init_per_testcase(_Case, Config) ->
- Path = code:which(?MODULE),
- code:add_pathz(filename:join(filename:dirname(Path), "idl_output")),
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- Path = code:which(?MODULE),
- code:del_path(filename:join(filename:dirname(Path), "idl_output")),
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: Fixed Point Datatype
-%% Description:
-%%-----------------------------------------------------------------
-fixed_type(_) ->
- Val1 = ?match({fixed,3,2,314}, orber_test_server:val1()),
- _Val2 = ?match({fixed,3,2,314}, orber_test_server:val2()),
- _Val3 = ?match({fixed,3,2,314}, orber_test_server:val3()),
- Val4 = ?match({fixed,3,2,314}, orber_test_server:val4()),
- Val5 = ?match({fixed,2,2,14}, orber_test_server:val5()),
- _Val6 = ?match({fixed,1,0,3}, orber_test_server:val6()),
- Val7 = ?match({fixed,2,2,-14}, orber_test_server:val7()),
- _Val8 = ?match({fixed,1,0,-3}, orber_test_server:val8()),
- Val9 = ?match({fixed,3,2,328}, orber_test_server:val9()),
- Val10 = ?match({fixed,4,4,4396}, orber_test_server:val10()),
- Val11 = ?match({fixed,31,29,2242857142857142857142857142857}, orber_test_server:val11()),
- Val12 = ?match({fixed,9,6,123140001}, orber_test_server:val12()),
- Val13 = ?match({fixed,9,1,123140001}, orber_test_server:val13()),
- Val14 = ?match({fixed,14,6,-12313876959999}, orber_test_server:val14()),
- Val15 = ?match({fixed,14,6,12314123240001}, orber_test_server:val15()),
- Val16 = ?match({fixed,17,7,15163459846280001}, orber_test_server:val16()),
- _Val17 = ?match({fixed,3,2,402}, orber_test_server:val17()),
- _Val18 = ?match({fixed,5,4,40401}, orber_test_server:val18()),
- _Val19 = ?match({fixed,3,0,200}, orber_test_server:val19()),
- Val20 = ?match({fixed,31,0,1999999999999999999999999999999}, orber_test_server:val20()),
- Val21 = ?match({fixed,1,0,0}, orber_test_server:val21()),
- Val22 = ?match({fixed,31,0,9999999999999999999999999999998}, orber_test_server:val22()),
- Val23 = ?match({fixed,1,0,1}, orber_test_server:val23()),
- _Val24 = ?match({fixed,5,0,19998}, orber_test_server:val24()),
- _Val25 = ?match({fixed,2,0,40}, orber_test_server:val25()),
- Val26 = ?match({fixed,31,0,9999999999999999999999999999999}, orber_test_server:val26()),
-
- ?match(Val1, fixed:create(3,2,314)),
- Val27 = ?match({fixed,6,2,314}, fixed:create(6,2,314)),
-
- ?match({tk_fixed,3,2}, fixed:get_typecode(Val1)),
- ?match({tk_fixed,6,2}, fixed:get_typecode(Val27)),
- ?match({'EXCEPTION',{'BAD_PARAM',_,_,_}}, fixed:create(3,2,3140)),
- ?match({'EXCEPTION',{'BAD_PARAM',_,_,_}}, fixed:create(5,6,314)),
- ?match({'EXCEPTION',{'BAD_PARAM',_,_,_}}, fixed:create(32,2,314)),
- ?match(Val10, fixed:multiply(Val4, Val5)),
- ?match(Val16, fixed:multiply(Val12, Val13)),
- ?match(Val22, fixed:multiply(Val26, Val26)),
-
- ?match(Val9, fixed:add(Val4, Val5)),
- ?match(Val15, fixed:add(Val12, Val13)),
- ?match(Val20, fixed:add(Val26, Val26)),
-
- ?match(Val11, fixed:divide(Val4, Val5)),
- ?match(Val23, fixed:divide(Val26, Val26)),
-
- ?match(Val14, fixed:subtract(Val12, Val13)),
- ?match(Val21, fixed:subtract(Val26, Val26)),
-
- ?match(Val7, fixed:unary_minus(Val5)),
- ?match(Val5, fixed:unary_minus(Val7)),
-
-
-
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: Any type
-%% Description:
-%%-----------------------------------------------------------------
-any_type(_) ->
- ?match(#any{typecode=undefined, value=undefined},
- any:create()),
- ?match(#any{typecode=tk_short, value=undefined},
- any:set_typecode(any:create(), tk_short)),
- ?match({'EXCEPTION', #'BAD_TYPECODE'{}},
- any:set_typecode(any:create(), "wrong")),
- ?match({'EXCEPTION', #'BAD_TYPECODE'{}},
- any:create("wrong", 1)),
- ?match(#any{typecode=tk_short, value = 1},
- any:create(tk_short, 1)),
- ?match(tk_short,
- any:get_typecode(any:create(tk_short, 1))),
- ?match(1,
- any:get_value(any:create(tk_short, 1))),
- ?match(#any{typecode=tk_short, value=2},
- any:set_value(any:create(tk_short, 1), 2)),
-
- ok.
diff --git a/lib/orber/test/generated_SUITE.erl b/lib/orber/test/generated_SUITE.erl
deleted file mode 100644
index 3550941dfd..0000000000
--- a/lib/orber/test/generated_SUITE.erl
+++ /dev/null
@@ -1,372 +0,0 @@
-%%-----------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File : generated_SUITE.erl
-%% Purpose :
-%%-----------------------------------------------------------------
-
--module(generated_SUITE).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/include/corba.hrl").
-
--define(default_timeout, test_server:minutes(3)).
-
--define(match(ExpectedRes, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
--define(nomatch(Not, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- Not ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS);
- _ ->
- AcTuAlReS
- end
- end()).
-
-
--define(checktc(_Op),
- fun(TC) ->
- case orber_tc:check_tc(TC) of
- false ->
- io:format("###### ERROR ERROR ######~n~p - ~p~n", [Op, TC]),
- exit(TC);
- true ->
- true
- end
- end).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
--compile(export_all).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- ['OrberApp_IFR', erlang_binary, erlang_pid, erlang_port,
- erlang_ref, 'CosNaming_Binding',
- 'CosNaming_BindingList', 'CosNaming_Name',
- 'CosNaming_NameComponent',
- 'CosNaming_NamingContextExt_InvalidAddress',
- 'CosNaming_NamingContext_AlreadyBound',
- 'CosNaming_NamingContext_CannotProceed',
- 'CosNaming_NamingContext_InvalidName',
- 'CosNaming_NamingContext_NotEmpty',
- 'CosNaming_NamingContext_NotFound',
- 'CosNaming_BindingIterator', 'CosNaming_NamingContext',
- 'CosNaming_NamingContextExt'].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-init_per_testcase(_Case, Config) ->
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case:'OrberApp_IFR'
-%% Description:
-%%-----------------------------------------------------------------
-'OrberApp_IFR'(_) ->
- ?nomatch(undefined, 'OrberApp_IFR':oe_tc(get_absolute_name)),
- ?nomatch(undefined, 'OrberApp_IFR':oe_tc(get_user_exception_type)),
- ?match(undefined, 'OrberApp_IFR':oe_tc(undefined)),
- ?match([_|_], 'OrberApp_IFR':oe_get_interface()),
- ?match("IDL:OrberApp/IFR:1.0", 'OrberApp_IFR':typeID()),
- check_tc('OrberApp_IFR':oe_get_interface()),
- ?match(true, 'OrberApp_IFR':oe_is_a('OrberApp_IFR':typeID())),
- ?match(false, 'OrberApp_IFR':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: erlang_binary
-%% Description:
-%%-----------------------------------------------------------------
-erlang_binary(_) ->
- ?match(true, orber_tc:check_tc(erlang_binary:tc())),
- ?match("IDL:erlang/binary:1.0", erlang_binary:id()),
- ?match("erlang_binary", erlang_binary:name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: erlang_pid
-%% Description:
-%%-----------------------------------------------------------------
-erlang_pid(_) ->
- ?match(true, orber_tc:check_tc(erlang_pid:tc())),
- ?match("IDL:erlang/pid:1.0", erlang_pid:id()),
- ?match("erlang_pid", erlang_pid:name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: erlang_port
-%% Description:
-%%-----------------------------------------------------------------
-erlang_port(_) ->
- ?match(true, orber_tc:check_tc(erlang_port:tc())),
- ?match("IDL:erlang/port:1.0", erlang_port:id()),
- ?match("erlang_port", erlang_port:name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: erlang_ref
-%% Description:
-%%-----------------------------------------------------------------
-erlang_ref(_) ->
- ?match(true, orber_tc:check_tc(erlang_ref:tc())),
- ?match("IDL:erlang/ref:1.0", erlang_ref:id()),
- ?match("erlang_ref", erlang_ref:name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNaming_Binding'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNaming_Binding'(_) ->
- ?match(true, orber_tc:check_tc('CosNaming_Binding':tc())),
- ?match("IDL:omg.org/CosNaming/Binding:1.0", 'CosNaming_Binding':id()),
- ?match("CosNaming_Binding", 'CosNaming_Binding':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNaming_BindingList'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNaming_BindingList'(_) ->
- ?match(true, orber_tc:check_tc('CosNaming_BindingList':tc())),
- ?match("IDL:omg.org/CosNaming/BindingList:1.0", 'CosNaming_BindingList':id()),
- ?match("CosNaming_BindingList", 'CosNaming_BindingList':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNaming_Name'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNaming_Name'(_) ->
- ?match(true, orber_tc:check_tc('CosNaming_Name':tc())),
- ?match("IDL:omg.org/CosNaming/Name:1.0", 'CosNaming_Name':id()),
- ?match("CosNaming_Name", 'CosNaming_Name':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNaming_NameComponent'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNaming_NameComponent'(_) ->
- ?match(true, orber_tc:check_tc('CosNaming_NameComponent':tc())),
- ?match("IDL:omg.org/CosNaming/NameComponent:1.0", 'CosNaming_NameComponent':id()),
- ?match("CosNaming_NameComponent", 'CosNaming_NameComponent':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNaming_NamingContextExt_InvalidAddress'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNaming_NamingContextExt_InvalidAddress'(_) ->
- ?match(true, orber_tc:check_tc('CosNaming_NamingContextExt_InvalidAddress':tc())),
- ?match("IDL:omg.org/CosNaming/NamingContextExt/InvalidAddress:1.0", 'CosNaming_NamingContextExt_InvalidAddress':id()),
- ?match("CosNaming_NamingContextExt_InvalidAddress", 'CosNaming_NamingContextExt_InvalidAddress':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNaming_NamingContext_AlreadyBound'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNaming_NamingContext_AlreadyBound'(_) ->
- ?match(true, orber_tc:check_tc('CosNaming_NamingContext_AlreadyBound':tc())),
- ?match("IDL:omg.org/CosNaming/NamingContext/AlreadyBound:1.0", 'CosNaming_NamingContext_AlreadyBound':id()),
- ?match("CosNaming_NamingContext_AlreadyBound", 'CosNaming_NamingContext_AlreadyBound':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNaming_NamingContext_CannotProceed'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNaming_NamingContext_CannotProceed'(_) ->
- ?match(true, orber_tc:check_tc('CosNaming_NamingContext_CannotProceed':tc())),
- ?match("IDL:omg.org/CosNaming/NamingContext/CannotProceed:1.0", 'CosNaming_NamingContext_CannotProceed':id()),
- ?match("CosNaming_NamingContext_CannotProceed", 'CosNaming_NamingContext_CannotProceed':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNaming_NamingContext_InvalidName'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNaming_NamingContext_InvalidName'(_) ->
- ?match(true, orber_tc:check_tc('CosNaming_NamingContext_InvalidName':tc())),
- ?match("IDL:omg.org/CosNaming/NamingContext/InvalidName:1.0", 'CosNaming_NamingContext_InvalidName':id()),
- ?match("CosNaming_NamingContext_InvalidName", 'CosNaming_NamingContext_InvalidName':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNaming_NamingContext_NotEmpty'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNaming_NamingContext_NotEmpty'(_) ->
- ?match(true, orber_tc:check_tc('CosNaming_NamingContext_NotEmpty':tc())),
- ?match("IDL:omg.org/CosNaming/NamingContext/NotEmpty:1.0", 'CosNaming_NamingContext_NotEmpty':id()),
- ?match("CosNaming_NamingContext_NotEmpty", 'CosNaming_NamingContext_NotEmpty':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNaming_NamingContext_NotFound'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNaming_NamingContext_NotFound'(_) ->
- ?match(true, orber_tc:check_tc('CosNaming_NamingContext_NotFound':tc())),
- ?match("IDL:omg.org/CosNaming/NamingContext/NotFound:1.0", 'CosNaming_NamingContext_NotFound':id()),
- ?match("CosNaming_NamingContext_NotFound", 'CosNaming_NamingContext_NotFound':name()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNaming_BindingIterator'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNaming_BindingIterator'(_) ->
- ?nomatch(undefined, 'CosNaming_BindingIterator':oe_tc(next_one)),
- ?nomatch(undefined, 'CosNaming_BindingIterator':oe_tc(next_n)),
- ?nomatch(undefined, 'CosNaming_BindingIterator':oe_tc(destroy)),
- ?match(undefined, 'CosNaming_BindingIterator':oe_tc(undefined)),
- ?match([_|_], 'CosNaming_BindingIterator':oe_get_interface()),
- ?match("IDL:omg.org/CosNaming/BindingIterator:1.0",
- 'CosNaming_BindingIterator':typeID()),
- check_tc('CosNaming_BindingIterator':oe_get_interface()),
- ?match(true, 'CosNaming_BindingIterator':oe_is_a('CosNaming_BindingIterator':typeID())),
- ?match(false, 'CosNaming_BindingIterator':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNaming_NamingContext'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNaming_NamingContext'(_) ->
- ?nomatch(undefined, 'CosNaming_NamingContext':oe_tc(bind)),
- ?nomatch(undefined, 'CosNaming_NamingContext':oe_tc(rebind)),
- ?nomatch(undefined, 'CosNaming_NamingContext':oe_tc(bind_context)),
- ?nomatch(undefined, 'CosNaming_NamingContext':oe_tc(rebind_context)),
- ?nomatch(undefined, 'CosNaming_NamingContext':oe_tc(resolve)),
- ?nomatch(undefined, 'CosNaming_NamingContext':oe_tc(unbind)),
- ?nomatch(undefined, 'CosNaming_NamingContext':oe_tc(new_context)),
- ?nomatch(undefined, 'CosNaming_NamingContext':oe_tc(bind_new_context)),
- ?nomatch(undefined, 'CosNaming_NamingContext':oe_tc(destroy)),
- ?nomatch(undefined, 'CosNaming_NamingContext':oe_tc(list)),
- ?match(undefined, 'CosNaming_NamingContext':oe_tc(undefined)),
- ?match([_|_], 'CosNaming_NamingContext':oe_get_interface()),
- ?match("IDL:omg.org/CosNaming/NamingContext:1.0",
- 'CosNaming_NamingContext':typeID()),
- check_tc('CosNaming_NamingContext':oe_get_interface()),
- ?match(true, 'CosNaming_NamingContext':oe_is_a('CosNaming_NamingContext':typeID())),
- ?match(false, 'CosNaming_NamingContext':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: 'CosNaming_NamingContexExt'
-%% Description:
-%%-----------------------------------------------------------------
-'CosNaming_NamingContextExt'(_) ->
- ?nomatch(undefined, 'CosNaming_NamingContextExt':oe_tc(to_string)),
- ?nomatch(undefined, 'CosNaming_NamingContextExt':oe_tc(to_name)),
- ?nomatch(undefined, 'CosNaming_NamingContextExt':oe_tc(to_url)),
- ?nomatch(undefined, 'CosNaming_NamingContextExt':oe_tc(resolve_str)),
- ?nomatch(undefined, 'CosNaming_NamingContextExt':oe_tc(bind)),
- ?nomatch(undefined, 'CosNaming_NamingContextExt':oe_tc(rebind)),
- ?nomatch(undefined, 'CosNaming_NamingContextExt':oe_tc(bind_context)),
- ?nomatch(undefined, 'CosNaming_NamingContextExt':oe_tc(rebind_context)),
- ?nomatch(undefined, 'CosNaming_NamingContextExt':oe_tc(new_context)),
- ?nomatch(undefined, 'CosNaming_NamingContextExt':oe_tc(bind_new_context)),
- ?nomatch(undefined, 'CosNaming_NamingContextExt':oe_tc(destroy)),
- ?nomatch(undefined, 'CosNaming_NamingContextExt':oe_tc(list)),
- ?match(undefined, 'CosNaming_NamingContextExt':oe_tc(undefined)),
- ?match([_|_], 'CosNaming_NamingContextExt':oe_get_interface()),
- ?match("IDL:omg.org/CosNaming/NamingContextExt:1.0",
- 'CosNaming_NamingContextExt':typeID()),
- check_tc('CosNaming_NamingContextExt':oe_get_interface()),
- ?match(true, 'CosNaming_NamingContextExt':oe_is_a('CosNaming_NamingContextExt':typeID())),
- ?match(true, 'CosNaming_NamingContextExt':oe_is_a('CosNaming_NamingContext':typeID())),
- ?match(false, 'CosNaming_NamingContextExt':oe_is_a("wrong")),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% MISC functions
-%%-----------------------------------------------------------------
-check_tc([]) ->
- ok;
-check_tc([{Op, {RetType, InParameters, OutParameters}}|T]) ->
- io:format("checked - ~s~n", [Op]),
- lists:all(?checktc(Op), [RetType|InParameters]),
- lists:all(?checktc(Op), OutParameters),
- check_tc(T).
-
-
diff --git a/lib/orber/test/idl_output/.gitignore b/lib/orber/test/idl_output/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/orber/test/idl_output/.gitignore
+++ /dev/null
diff --git a/lib/orber/test/iiop_module_do_test_impl.erl b/lib/orber/test/iiop_module_do_test_impl.erl
deleted file mode 100644
index 3e433ace72..0000000000
--- a/lib/orber/test/iiop_module_do_test_impl.erl
+++ /dev/null
@@ -1,113 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(iiop_module_do_test_impl).
-
-
--export([run_all/3, run_userexception/2, run_systemexception/2]).
--export([createTestContext/0]).
-
--export([start/0, stop/0]).
--export([init/1, terminate/2]).
-
-
-init(_) ->
- {ok, []}.
-
-terminate(Reason, _State) ->
- io:format("~p terminating with reason ~p~n", [?MODULE, Reason]),
- ok.
-
-createTestContext() ->
- NS = corba:resolve_initial_references("NameService"),
- NC = lname_component:set_id(lname_component:create(), "iiop_test"),
- N = lname:insert_component(lname:create(), 1, NC),
- 'CosNaming_NamingContext':bind_new_context(NS, N).
-
-start() ->
- SFok = corba:create('iiop_module_do_test', "IDL:iiop_module/do_test:1.0"),
- NS = corba:resolve_initial_references("NameService"),
- NC1 = lname_component:set_id(lname_component:create(), "iiop_test"),
- NC2 = lname_component:set_id(lname_component:create(), "erl_dotest"),
- N = lname:insert_component(lname:create(), 1, NC1),
- N1 = lname:insert_component(N, 2, NC2),
- 'CosNaming_NamingContext':bind(NS, N1, SFok),
- SFok.
-
-stop() ->
- NS = corba:resolve_initial_references("NameService"),
- NC1 = lname_component:set_id(lname_component:create(), "iiop_test"),
- NC2 = lname_component:set_id(lname_component:create(), "erl_dotest"),
- N = lname:insert_component(lname:create(), 1, NC1),
- N1 = lname:insert_component(N, 2, NC2),
- 'CosNaming_NamingContext':unbind(NS, N1).
-
-run_all(S, X, TL) ->
- ok = iiop_module_test:send_void(X),
- {tk_short, P1} = lists:nth(1, TL),
- {R1, IO1, O1} = iiop_module_test:send_short(X, P1, P1),
- RL1= [{tk_short, R1}],
- IOL1= [{tk_short, IO1}],
- OL1= [{tk_short, O1}],
- {tk_ushort, P2} = lists:nth(2, TL),
- {R2, IO2, O2} = iiop_module_test:send_ushort(X, P2, P2),
- RL2= [{tk_ushort, R2}|RL1],
- IOL2= [{tk_ushort, IO2}|IOL1],
- OL2= [{tk_ushort, O2}|OL1],
- {tk_long, P3} = lists:nth(3, TL),
- {R3, IO3, O3} = iiop_module_test:send_long(X, P3, P3),
- RL3= [{tk_long, R3}|RL2],
- IOL3= [{tk_long, IO3}|IOL2],
- OL3= [{tk_long, O3}|OL2],
- {tk_ulong, P4} = lists:nth(4, TL),
- {R4, IO4, O4} = iiop_module_test:send_ulong(X, P4, P4),
- RL4= [{tk_ulong, R4}|RL3],
- IOL4= [{tk_ulong, IO4}|IOL3],
- OL4= [{tk_ulong, O4}|OL3],
- {tk_float, P5} = lists:nth(5, TL),
- {R5, IO5, O5} = iiop_module_test:send_float(X, P5, P5),
- RL5= [{tk_float, R5}|RL4],
- IOL5= [{tk_float, IO5}|IOL4],
- OL5= [{tk_float, O5}|OL4],
- {tk_double, P6} = lists:nth(6, TL),
- {R6, IO6, O6} = iiop_module_test:send_double(X, P6, P6),
- RL6= [{tk_double, R6}|RL5],
- IOL6= [{tk_double, IO6}|IOL5],
- OL6= [{tk_double, O6}|OL5],
- {tk_boolean, P7} = lists:nth(7, TL),
- {R7, IO7, O7} = iiop_module_test:send_boolean(X, P7, P7),
- RL7= [{tk_boolean, R7}|RL6],
- IOL7= [{tk_boolean, IO7}|IOL6],
- OL7= [{tk_boolean, O7}|OL6],
- {tk_char, P8} = lists:nth(8, TL),
- {R8, IO8, O8} = iiop_module_test:send_char(X, P8, P8),
- RL= [{tk_char, R8} |RL7],
- IOL= [{tk_char, IO8} |IOL7],
- OL= [{tk_char, O8} |OL7],
- {{lists:reverse(RL),lists:reverse(IOL),lists:reverse(OL)}, S}.
-
-run_systemexception(S, X) ->
- iiop_module_test:ret_systemexception(X),
- {ok, S}.
-
-run_userexception(S, X) ->
- iiop_module_test:ret_userexception(X),
- {ok, S}.
diff --git a/lib/orber/test/iiop_module_test_impl.erl b/lib/orber/test/iiop_module_test_impl.erl
deleted file mode 100644
index c2ec427d5d..0000000000
--- a/lib/orber/test/iiop_module_test_impl.erl
+++ /dev/null
@@ -1,129 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(iiop_module_test_impl).
--include_lib("orber/include/corba.hrl").
--include("idl_output/iiop_module.hrl").
-
-
--export([send_void/1, send_short/3, send_ushort/3]).
--export([send_long/3, send_ulong/3, send_float/3]).
--export([send_double/3, send_boolean/3, send_char/3]).
--export([send_octet/3, send_any/3, send_object/3]).
--export([send_struct1/3, send_union1/3, send_enum1/3]).
--export([send_string/3, send_sequence1/3, send_array1/3]).
--export([ret_systemexception/1, ret_userexception/1]).
-
-
-
--export([start/0, stop/0]).
--export([init/1, terminate/2]).
-
-
-init(_) ->
- {ok, []}.
-
-terminate(Reason, _State) ->
- io:format("~p terminating with reason ~p~n", [?MODULE, Reason]),
- ok.
-
-
-start() ->
- SFok = corba:create('iiop_module_test', "IDL:iiop_module/test:1.0"),
- NS = corba:resolve_initial_references("NameService"),
- NC1 = lname_component:set_id(lname_component:create(), "iiop_test"),
- NC2 = lname_component:set_id(lname_component:create(), "erl_test"),
- N = lname:insert_component(lname:create(), 1, NC1),
- N1 = lname:insert_component(N, 2, NC2),
- 'CosNaming_NamingContext':bind(NS, N1, SFok),
- SFok.
-
-stop() ->
- NS = corba:resolve_initial_references("NameService"),
- NC1 = lname_component:set_id(lname_component:create(), "iiop_test"),
- NC2 = lname_component:set_id(lname_component:create(), "erl_test"),
- N = lname:insert_component(lname:create(), 1, NC1),
- N1 = lname:insert_component(N, 2, NC2),
- 'CosNaming_NamingContext':unbind(NS, N1).
-
-
-
-send_void(S) ->
- {ok, S}.
-
-send_short(S, P1, P2) ->
- {{P1, P1, P2}, S}.
-
-send_ushort(S, P1, P2) ->
- {{P1, P1, P2}, S}.
-
-send_long(S, P1, P2) ->
- {{P1, P1, P2}, S}.
-
-send_ulong(S, P1, P2) ->
- {{P1, P1, P2}, S}.
-
-send_float(S, P1, P2) ->
- {{P1, P1, P2}, S}.
-
-send_double(S, P1, P2) ->
- {{P1, P1, P2}, S}.
-
-send_boolean(S, P1, P2) ->
- {{P1, P1, P2}, S}.
-
-send_char(S, P1, P2) ->
- {{P1, P1, P2}, S}.
-
-send_octet(S, P1, P2) ->
- {{P1, P1, P2}, S}.
-
-send_any(S, P1, P2) ->
- {{P1, P1, P2}, S}.
-
-send_object(S, P1, P2) ->
- {{P1, P1, P2}, S}.
-
-send_struct1(S, P1, P2) ->
- {{P1, P1, P2}, S}.
-
-send_union1(S, P1, P2) ->
- {{P1, P1, P2}, S}.
-
-send_enum1(S, P1, P2) ->
- {{P1, P1, P2}, S}.
-
-send_string(S, P1, P2) ->
- {{P1, P1, P2}, S}.
-
-send_sequence1(S, P1, P2) ->
- {{P1, P1, P2}, S}.
-
-send_array1(S, P1, P2) ->
- {{P1, P1, P2}, S}.
-
-ret_systemexception(S) ->
- throw(#'BAD_PARAM'{}),
- {ok, S}.
-
-ret_userexception(S) ->
- throw(#iiop_module_Except1{why="not readable",rest_of_name=["foo", "bar"]}),
- {ok, S}.
diff --git a/lib/orber/test/iiop_test.idl b/lib/orber/test/iiop_test.idl
deleted file mode 100644
index 0b20a66edd..0000000000
--- a/lib/orber/test/iiop_test.idl
+++ /dev/null
@@ -1,112 +0,0 @@
-//
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-//
-#include "cos_naming.idl"
-
-module iiop_module
-{
-
- typedef long Array1[10];
-
- enum Enum1 {horse, pig, cow};
-
- typedef sequence<long> Sequence1;
-
- typedef Sequence1 Sequence2;
-
- struct Struct1 {
- string s;
- unsigned short us;
- unsigned long ul;
- };
-
- union Union1 switch (short) {
- case 0: short First;
- case 1: string Second;
- case 2: char Third;
- };
-
- exception Except1 {
- string why;
- sequence <string> rest_of_name;
- };
-
- typedef sequence<any> test_values;
- struct test_retval {
- test_values R;
- test_values InOut;
- test_values Out;
- };
-
- interface test;
-
- interface do_test {
- void run_systemexception(in test x)
- raises(CosNaming::NamingContext::NotFound,
- CosNaming::NamingContext::CannotProceed,
- CosNaming::NamingContext::InvalidName);
- void run_userexception(in test x)
- raises(iiop_module::Except1,
- CosNaming::NamingContext::NotFound,
- CosNaming::NamingContext::CannotProceed,
- CosNaming::NamingContext::InvalidName);
- test_retval run_all(in test x, in test_values tlist)
- raises(iiop_module::Except1,
- CosNaming::NamingContext::NotFound,
- CosNaming::NamingContext::CannotProceed,
- CosNaming::NamingContext::InvalidName);
- };
-
- interface test {
- // Function to run all tests from java to erlang
- // and return the answers
- // Primitive types
- void send_void();
- short send_short(in short p1, inout short p2, out short p3);
- unsigned short send_ushort(in unsigned short p1, inout unsigned short p2,
- out unsigned short p3);
- long send_long(in long p1, inout long p2, out long p3);
- unsigned long send_ulong(in unsigned long p1, inout unsigned long p2,
- out unsigned long p3);
- float send_float(in float p1, inout float p2, out float p3);
- double send_double(in double p1, inout double p2, out double p3);
- boolean send_boolean(in boolean p1, inout boolean p2, out boolean p3);
- char send_char(in char p1, inout char p2, out char p3);
- octet send_octet(in octet p1, inout octet p2, out octet p3);
- any send_any(in any p1, inout any p2, out any p3);
- Object send_object(in Object p1, inout Object p2, out Object p3);
- // TypeCode send_typecode(in TypeCode p1, inout TypeCode p2, out TypeCode p3);
- // Principal send_principal(in Principal p); //tested in every request
-
- // Complex types
- Struct1 send_struct1(in Struct1 p1, inout Struct1 p2, out Struct1 p3);
- Union1 send_union1(in Union1 p1, inout Union1 p2, out Union1 p3);
- Enum1 send_enum1(in Enum1 p1, inout Enum1 p2, out Enum1 p3);
- string send_string(in string p1, inout string p2, out string p3);
- Sequence1 send_sequence1(in Sequence1 p1, inout Sequence1 p2,
- out Sequence1 p3);
- Array1 send_array1(in Array1 p1, inout Array1 p2, out Array1 p3);
-
- void ret_systemexception();
- void ret_userexception() raises(iiop_module::Except1);
-
-
- };
-
-};
diff --git a/lib/orber/test/iiop_test_impl.erl b/lib/orber/test/iiop_test_impl.erl
deleted file mode 100644
index 26694f8e08..0000000000
--- a/lib/orber/test/iiop_test_impl.erl
+++ /dev/null
@@ -1,35 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(iiop_test_impl).
--include_lib("orber/include/corba.hrl").
--include_lib("orber/test/iiop_test.hrl").
--export([]).
-
-
-init(Env) ->
- {ok, []}.
-
-terminate(From, Reason) ->
- ok.
-
-send_void(State) ->
- {ok, State}.
-
diff --git a/lib/orber/test/interceptors_SUITE.erl b/lib/orber/test/interceptors_SUITE.erl
deleted file mode 100644
index cec4cd1fab..0000000000
--- a/lib/orber/test/interceptors_SUITE.erl
+++ /dev/null
@@ -1,349 +0,0 @@
-%%-----------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File : interceptors_SUITE.erl
-%% Purpose :
-%%-----------------------------------------------------------------
-
--module(interceptors_SUITE).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
-
--define(default_timeout, test_server:minutes(3)).
-
--define(match(ExpectedRes, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- io:format("------ CORRECT RESULT ------~n~p~n",
- [AcTuAlReS]),
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
--define(nomatch(Not, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- Not ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS);
- _ ->
- io:format("------ CORRECT RESULT ------~n~p~n",
- [AcTuAlReS]),
- AcTuAlReS
- end
- end()).
-
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([in_reply/6, out_request/6]).
--compile(export_all).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [local_pseudo, local_default, local_local, local_global].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-init_per_testcase(_Case, Config) ->
- Dog=test_server:timetrap(?default_timeout),
- Path = code:which(?MODULE),
- code:add_pathz(filename:join(filename:dirname(Path), "idl_output")),
- corba:orb_init([{flags, (?ORB_ENV_USE_PI bor ?ORB_ENV_LOCAL_TYPECHECKING)},
- {local_interceptors, {native, [?MODULE]}}]),
- orber:jump_start(2945),
- oe_orber_test_server:oe_register(),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- oe_orber_test_server:oe_unregister(),
- orber:jump_stop(),
- Path = code:which(?MODULE),
- code:del_path(filename:join(filename:dirname(Path), "idl_output")),
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: local_pseudo
-%% Description:
-%%-----------------------------------------------------------------
-local_pseudo(_) ->
- ?match({native, [?MODULE]}, orber:get_local_interceptors()),
- %% Global settings
- Obj1 = orber_test_server:oe_create(state,[{pseudo,true}]),
- Result11 = orber_test_server:testing_iiop_ushort(Obj1, ?USHORTMAX),
- ?match([?USHORTMAX], put(out_request, undefined)),
- ?match(Result11, put(in_reply, undefined)),
-
- Result12 = ?match({'EXCEPTION',_},
- orber_test_server:testing_iiop_ushort(Obj1, ?USHORTMAX+1)),
- ?match([(?USHORTMAX+1)], put(out_request, undefined)),
- ?nomatch(Result12, put(in_reply, undefined)),
-
- Result13 = orber_test_server:testing_iiop_oneway_delay(Obj1, 0),
- ?match([0], put(out_request, undefined)),
- ?nomatch(Result13, put(in_reply, undefined)),
-
- Result14 = ?match({'EXCEPTION', _},
- orber_test_server:raise_local_exception(Obj1)),
- ?match([], put(out_request, undefined)),
- ?match(Result14, put(in_reply, undefined)),
-
- Result15 = ?match({'EXCEPTION',_}, orber_test_server:stop_brutal(Obj1)),
- ?match([], put(out_request, undefined)),
- ?match(Result15, put(in_reply, undefined)),
-
- %% Per-object
- Obj2 = orber_test_server:oe_create(state,[{pseudo,true},
- {local_interceptors, false}]),
-
- Result21 = orber_test_server:testing_iiop_ushort(Obj2, ?USHORTMAX),
- ?nomatch([?USHORTMAX], put(out_request, undefined)),
- ?nomatch(Result21, put(in_reply, undefined)),
-
- Obj3 = orber_test_server:oe_create(state,[{pseudo,true},
- {local_interceptors, true}]),
-
- Result31 = orber_test_server:testing_iiop_ushort(Obj3, ?USHORTMAX),
- ?match([?USHORTMAX], put(out_request, undefined)),
- ?match(Result31, put(in_reply, undefined)),
-
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: local_default
-%% Description:
-%%-----------------------------------------------------------------
-local_default(_) ->
- ?match({native, [?MODULE]}, orber:get_local_interceptors()),
- %% Global settings
- Obj1 = orber_test_server:oe_create(state, []),
- Result11 = orber_test_server:testing_iiop_ushort(Obj1, ?USHORTMAX),
- ?match([?USHORTMAX], put(out_request, undefined)),
- ?match(Result11, put(in_reply, undefined)),
-
- Result12 = ?match({'EXCEPTION',_},
- orber_test_server:testing_iiop_ushort(Obj1, ?USHORTMAX+1)),
- ?match([(?USHORTMAX+1)], put(out_request, undefined)),
- ?nomatch(Result12, put(in_reply, undefined)),
-
- Result13 = orber_test_server:testing_iiop_oneway_delay(Obj1, 0),
- ?match([0], put(out_request, undefined)),
- ?nomatch(Result13, put(in_reply, undefined)),
-
- Result14 = ?match({'EXCEPTION', _},
- orber_test_server:raise_local_exception(Obj1)),
- ?match([], put(out_request, undefined)),
- ?match(Result14, put(in_reply, undefined)),
-
- Result15 = ?match({'EXCEPTION',_}, orber_test_server:stop_brutal(Obj1)),
- ?match([], put(out_request, undefined)),
- ?match(Result15, put(in_reply, undefined)),
-
-
- %% Per-object
- Obj2 = orber_test_server:oe_create(state,[{local_interceptors, false}]),
-
- Result21 = orber_test_server:testing_iiop_ushort(Obj2, ?USHORTMAX),
- ?nomatch([?USHORTMAX], put(out_request, undefined)),
- ?nomatch(Result21, put(in_reply, undefined)),
- corba:dispose(Obj2),
-
- Obj3 = orber_test_server:oe_create(state,[{local_interceptors, true}]),
-
- Result31 = orber_test_server:testing_iiop_ushort(Obj3, ?USHORTMAX),
- ?match([?USHORTMAX], put(out_request, undefined)),
- ?match(Result31, put(in_reply, undefined)),
- corba:dispose(Obj3),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: local_local
-%% Description:
-%%-----------------------------------------------------------------
-local_local(_) ->
- ?match({native, [?MODULE]}, orber:get_local_interceptors()),
- %% Global settings
- Obj1 = orber_test_server:oe_create(state, [{regname, {local, regname}}]),
- Result11 = orber_test_server:testing_iiop_ushort(Obj1, ?USHORTMAX),
- ?match([?USHORTMAX], put(out_request, undefined)),
- ?match(Result11, put(in_reply, undefined)),
-
- Result12 = ?match({'EXCEPTION',_},
- orber_test_server:testing_iiop_ushort(Obj1, ?USHORTMAX+1)),
- ?match([(?USHORTMAX+1)], put(out_request, undefined)),
- ?nomatch(Result12, put(in_reply, undefined)),
-
- Result13 = orber_test_server:testing_iiop_oneway_delay(Obj1, 0),
- ?match([0], put(out_request, undefined)),
- ?nomatch(Result13, put(in_reply, undefined)),
-
- Result14 = ?match({'EXCEPTION', _},
- orber_test_server:raise_local_exception(Obj1)),
- ?match([], put(out_request, undefined)),
- ?match(Result14, put(in_reply, undefined)),
-
- Result15 = ?match({'EXCEPTION',_}, orber_test_server:stop_brutal(Obj1)),
- ?match([], put(out_request, undefined)),
- ?match(Result15, put(in_reply, undefined)),
-
- %% Per-object
- Obj2 = orber_test_server:oe_create(state,[{regname, {local, regname}},
- {local_interceptors, false}]),
-
- Result21 = orber_test_server:testing_iiop_ushort(Obj2, ?USHORTMAX),
- ?nomatch([?USHORTMAX], put(out_request, undefined)),
- ?nomatch(Result21, put(in_reply, undefined)),
- corba:dispose(Obj2),
-
- Obj3 = orber_test_server:oe_create(state,[{regname, {local, regname}},
- {local_interceptors, true}]),
-
- Result31 = orber_test_server:testing_iiop_ushort(Obj3, ?USHORTMAX),
- ?match([?USHORTMAX], put(out_request, undefined)),
- ?match(Result31, put(in_reply, undefined)),
- corba:dispose(Obj3),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: local_global
-%% Description:
-%%-----------------------------------------------------------------
-local_global(_) ->
- ?match({native, [?MODULE]}, orber:get_local_interceptors()),
- %% Global settings
- Obj1 = orber_test_server:oe_create(state, [{regname, {global, regname}}]),
- Result11 = orber_test_server:testing_iiop_ushort(Obj1, ?USHORTMAX),
- ?match([?USHORTMAX], put(out_request, undefined)),
- ?match(Result11, put(in_reply, undefined)),
-
- Result12 = ?match({'EXCEPTION',_},
- orber_test_server:testing_iiop_ushort(Obj1, ?USHORTMAX+1)),
- ?match([(?USHORTMAX+1)], put(out_request, undefined)),
- ?nomatch(Result12, put(in_reply, undefined)),
-
- Result13 = orber_test_server:testing_iiop_oneway_delay(Obj1, 0),
- ?match([0], put(out_request, undefined)),
- ?nomatch(Result13, put(in_reply, undefined)),
-
- Result14 = ?match({'EXCEPTION', _},
- orber_test_server:raise_local_exception(Obj1)),
- ?match([], put(out_request, undefined)),
- ?match(Result14, put(in_reply, undefined)),
-
- Result15 = ?match({'EXCEPTION',_}, orber_test_server:stop_brutal(Obj1)),
- ?match([], put(out_request, undefined)),
- ?match(Result15, put(in_reply, undefined)),
-
- %% Per-object
- Obj2 = orber_test_server:oe_create(state,[{regname, {global, regname}},
- {local_interceptors, false}]),
-
- Result21 = orber_test_server:testing_iiop_ushort(Obj2, ?USHORTMAX),
- ?nomatch([?USHORTMAX], put(out_request, undefined)),
- ?nomatch(Result21, put(in_reply, undefined)),
- corba:dispose(Obj2),
-
- Obj3 = orber_test_server:oe_create(state,[{regname, {global, regname}},
- {local_interceptors, true}]),
-
- Result31 = orber_test_server:testing_iiop_ushort(Obj3, ?USHORTMAX),
- ?match([?USHORTMAX], put(out_request, undefined)),
- ?match(Result31, put(in_reply, undefined)),
- corba:dispose(Obj3),
- ok.
-
-
-
-
-%%-----------------------------------------------------------------
-%% Local functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% function : in_reply
-%%-----------------------------------------------------------------
-in_reply(Ref, _ObjKey, Ctx, Op, Reply, _Args) ->
- error_logger:info_msg("=============== in_reply =================
-Connection: ~p
-Operation : ~p
-Reply : ~p
-Context : ~p
-==========================================~n",
- [Ref, Op, Reply, Ctx]),
- put(in_reply, Reply),
- {Reply, "NewArgs"}.
-
-%%-----------------------------------------------------------------
-%% function : out_request
-%%-----------------------------------------------------------------
-out_request(Ref, _ObjKey, Ctx, Op, Params, _Args) ->
- error_logger:info_msg("=============== out_request ==============
-Connection: ~p
-Operation : ~p
-Parameters: ~p
-Context : ~p
-==========================================~n",
- [Ref, Op, Params, Ctx]),
- put(out_request, Params),
- {Params, "NewArgs"}.
diff --git a/lib/orber/test/iop_ior_10_SUITE.erl b/lib/orber/test/iop_ior_10_SUITE.erl
deleted file mode 100644
index 68a6793f62..0000000000
--- a/lib/orber/test/iop_ior_10_SUITE.erl
+++ /dev/null
@@ -1,184 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%%
-%% Description:
-%% Test suite for the IOR functions
-%%
-%%-----------------------------------------------------------------
--module(iop_ior_10_SUITE).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/src/orber_iiop.hrl").
-
--define(default_timeout, test_server:minutes(3)).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
--compile(export_all).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [encoding, create_and_get_ops].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-
-init_per_testcase(_Case, Config) ->
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: IOR encoding test
-%% Description: Just testing the string_encoding function because the
-%% other encodings is called from them.
-%%-----------------------------------------------------------------
-encoding(_) ->
- V = #'IIOP_Version'{major=1,minor=0},
- M0 = 'Module_Interface',
- T0 = "IDL:Module/Interface:1.0",
- H0 = "my.hostname.org",
- P0 = 4040,
- N0 = 'name',
- O0 = corba_fake_mk_objkey(M0, registered, N0),
- PB0 = #'IIOP_ProfileBody_1_0'{iiop_version=V, host=H0, port=P0, object_key=O0},
- TP0 = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB0},
- S0 = #'IOP_IOR'{type_id=T0, profiles=[TP0]},
- N1 = list_to_pid("<0.100.0>"),
- O1 = corba_fake_mk_objkey(M0, key, N1),
- PB1 = #'IIOP_ProfileBody_1_0'{iiop_version=V, host=H0, port=P0, object_key=O1},
- TP1 = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB1},
- S1 = #'IOP_IOR'{type_id=T0, profiles=[TP1]},
- O2 = "This is an external objectkey",
- PB2 = #'IIOP_ProfileBody_1_0'{iiop_version=V, host=H0, port=P0, object_key=O2},
- TP2 = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB2},
- S2 = #'IOP_IOR'{type_id=T0, profiles=[TP2]},
- C0 = iop_ior:string_code(S0),
- {S0, <<>>, _} = iop_ior:string_decode(C0),
- C1 = iop_ior:string_code(S1),
- {S1, <<>>, _} = iop_ior:string_decode(C1),
- C2 = iop_ior:string_code(S2),
- {S2, <<>>, _} = iop_ior:string_decode(C2),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: IOR creation test
-%% Description:
-%%-----------------------------------------------------------------
-create_and_get_ops(_) ->
- V = #'IIOP_Version'{major=1,minor=0},
- M0 = 'Module_Interface',
- T0 = "IDL:Module/Interface:1.0",
- H0 = "my.hostname.org",
- P0 = 4040,
- N0 = 'name',
- O0 = corba_fake_mk_objkey(M0, registered, N0),
- PB0 = #'IIOP_ProfileBody_1_0'{iiop_version=V, host=H0, port=P0, object_key=O0},
- TP0 = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB0},
- S0 = #'IOP_IOR'{type_id=T0, profiles=[TP0]},
- S0 = iop_ior:create({1, 0}, T0, [H0], P0, -1, O0, [], 0, 0),
- N1 = list_to_pid("<0.100.0>"),
- O1 = corba_fake_mk_objkey(M0, key, N1),
- {_,_,K1,_,_,_} = O1,
- PB1 = #'IIOP_ProfileBody_1_0'{iiop_version=V, host=H0, port=P0, object_key=O1},
- TP1 = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB1},
- S1 = #'IOP_IOR'{type_id=T0, profiles=[TP1]},
- S1 = iop_ior:create({1, 0}, T0, [H0], P0, -1, O1, [], 0, 0),
- O2 = "This is an external objectkey",
- PB2 = #'IIOP_ProfileBody_1_0'{iiop_version=V, host=H0, port=P0, object_key=O2},
- TP2 = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB2},
- S2 = #'IOP_IOR'{type_id=T0, profiles=[TP2]},
- {'internal_registered', N0, _, _, M0} = iop_ior:get_key(S0),
- {'internal', K1, _, _, M0} = iop_ior:get_key(S1),
- {'external', {H0, P0, O2, _,_,
- #host_data{protocol = normal,
- ssl_data = undefined,
- version = {1,0},
- csiv2_mech = undefined,
- csiv2_statefull = false,
- charset = 65537,
- wcharset = 65801,
- ft_heartbeat = false,
- ft_primary = false,
- ft_group = undefined,
- csiv2_addresses = []}}}
- = iop_ior:get_key(S2),
- T0 = iop_ior:get_typeID(S0),
- O0 = iop_ior:get_objkey(S0),
- O1 = iop_ior:get_objkey(S1),
- O2 = iop_ior:get_objkey(S2),
- ok.
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-corba_fake_mk_objkey(Id, 'key', Pid) when is_pid(Pid) ->
- Key = make_objkey(),
- {Id, 'key', Key, term_to_binary(undefined), 0, 0};
-corba_fake_mk_objkey(Id, 'key', RegName) when is_atom(RegName) ->
- Key = term_to_binary(RegName),
- {Id, 'key', Key, term_to_binary(undefined), 0, 0};
-corba_fake_mk_objkey(Id, 'registered', RegName) when is_atom(RegName) ->
- {Id, 'registered', RegName, term_to_binary(undefined), 0, 0}.
-
-
-make_objkey() ->
- term_to_binary({{erlang:system_time(),
- erlang:unique_integer()},
- node()}).
diff --git a/lib/orber/test/iop_ior_11_SUITE.erl b/lib/orber/test/iop_ior_11_SUITE.erl
deleted file mode 100644
index 8276feeb93..0000000000
--- a/lib/orber/test/iop_ior_11_SUITE.erl
+++ /dev/null
@@ -1,203 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%%
-%% Description:
-%% Test suite for the IOR functions
-%%
-%%-----------------------------------------------------------------
--module(iop_ior_11_SUITE).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/src/orber_iiop.hrl").
-
--define(default_timeout, test_server:minutes(3)).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
--compile(export_all).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [encoding, create_and_get_ops].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-
-init_per_testcase(_Case, Config) ->
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: IOR encoding test
-%% Description: Just testing the string_encoding function because the
-%% other encodings is called from them.
-%%-----------------------------------------------------------------
-encoding(_) ->
- V = #'IIOP_Version'{major=1,minor=1},
- M0 = 'Module_Interface',
- T0 = "IDL:Module/Interface:1.0",
- H0 = "my.hostname.org",
- P0 = 4040,
- N0 = 'name',
- Components = case orber:iiop_ssl_port() of
- -1 ->
- [];
- SSLPort ->
- [#'IOP_TaggedComponent'{tag=?TAG_SSL_SEC_TRANS,
- component_data=[0 |
- cdrlib:enc_unsigned_short(2,
- cdrlib:enc_unsigned_short(2,
- cdrlib:enc_unsigned_short(SSLPort, [])))]}]
- end,
- O0 = corba_fake_mk_objkey(M0, registered, N0),
- PB0 = #'IIOP_ProfileBody_1_1'{iiop_version=V, host=H0, port=P0, object_key=O0,
- components=Components},
- TP0 = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB0},
- S0 = #'IOP_IOR'{type_id=T0, profiles=[TP0]},
- N1 = list_to_pid("<0.100.0>"),
- O1 = corba_fake_mk_objkey(M0, key, N1),
- PB1 = #'IIOP_ProfileBody_1_1'{iiop_version=V, host=H0, port=P0, object_key=O1,
- components=[]},
- TP1 = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB1},
- S1 = #'IOP_IOR'{type_id=T0, profiles=[TP1]},
- O2 = "This is an external objectkey",
- PB2 = #'IIOP_ProfileBody_1_1'{iiop_version=V, host=H0, port=P0, object_key=O2,
- components=[]},
- TP2 = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB2},
- S2 = #'IOP_IOR'{type_id=T0, profiles=[TP2]},
- C0 = iop_ior:string_code(S0),
- {S0, <<>>, _} = iop_ior:string_decode(C0),
- C1 = iop_ior:string_code(S1),
- {S1, <<>>, _} = iop_ior:string_decode(C1),
- C2 = iop_ior:string_code(S2),
- {S2, <<>>, _} = iop_ior:string_decode(C2),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: IOR creation test
-%% Description:
-%%-----------------------------------------------------------------
-create_and_get_ops(_) ->
- V = #'IIOP_Version'{major=1,minor=1},
- CSC = #'IOP_TaggedComponent'{tag=?TAG_CODE_SETS,
- component_data=?DEFAULT_CODESETS},
- M0 = 'Module_Interface',
- T0 = "IDL:Module/Interface:1.0",
- H0 = "my.hostname.org",
- P0 = 4040,
- N0 = 'name',
- O0 = corba_fake_mk_objkey(M0, registered, N0),
- PB0 = #'IIOP_ProfileBody_1_1'
- {iiop_version=V, host=H0, port=P0, object_key=O0,
- components=[CSC]},
- TP0 = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB0},
- S0 = #'IOP_IOR'{type_id=T0, profiles=[TP0]},
- S0 = iop_ior:create({1, 1}, T0, [H0], P0, -1, O0, [CSC], 0, 0),
- N1 = list_to_pid("<0.100.0>"),
- O1 = corba_fake_mk_objkey(M0, key, N1),
- {_,_,K1,_,_,_} = O1,
- PB1 = #'IIOP_ProfileBody_1_1'
- {iiop_version=V, host=H0, port=P0, object_key=O1,
- components=[CSC]},
- TP1 = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB1},
- S1 = #'IOP_IOR'{type_id=T0, profiles=[TP1]},
- S1 = iop_ior:create({1, 1}, T0, [H0], P0, -1, O1, [CSC], 0, 0),
- O2 = "This is an external objectkey",
- PB2 = #'IIOP_ProfileBody_1_1'{iiop_version=V, host=H0, port=P0, object_key=O2,
- components=[]},
- TP2 = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB2},
- S2 = #'IOP_IOR'{type_id=T0, profiles=[TP2]},
- {'internal_registered', N0, _, _, M0} = iop_ior:get_key(S0),
- {'internal', K1, _, _, M0} = iop_ior:get_key(S1),
- {'external', {H0, P0, O2, _,_,
- #host_data{protocol = normal,
- ssl_data = undefined,
- version = {1,1},
- csiv2_mech = undefined,
- csiv2_statefull = false,
- charset = 65537,
- wcharset = 65801,
- ft_heartbeat = false,
- ft_primary = false,
- ft_group = undefined,
- csiv2_addresses = []}}} =
- iop_ior:get_key(S2),
- T0 = iop_ior:get_typeID(S0),
- O0 = iop_ior:get_objkey(S0),
- O1 = iop_ior:get_objkey(S1),
- O2 = iop_ior:get_objkey(S2),
- ok.
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-corba_fake_mk_objkey(Id, 'key', Pid) when is_pid(Pid) ->
- Key = make_objkey(),
- {Id, 'key', Key, term_to_binary(undefined), 0, 0};
-corba_fake_mk_objkey(Id, 'key', RegName) when is_atom(RegName) ->
- Key = term_to_binary(RegName),
- {Id, 'key', Key, term_to_binary(undefined), 0, 0};
-corba_fake_mk_objkey(Id, 'registered', RegName) when is_atom(RegName) ->
- {Id, 'registered', RegName, term_to_binary(undefined), 0, 0}.
-
-make_objkey() ->
- term_to_binary({{erlang:system_time(),
- erlang:unique_integer()},
- node()}).
diff --git a/lib/orber/test/iop_ior_12_SUITE.erl b/lib/orber/test/iop_ior_12_SUITE.erl
deleted file mode 100644
index 802b0b11a2..0000000000
--- a/lib/orber/test/iop_ior_12_SUITE.erl
+++ /dev/null
@@ -1,204 +0,0 @@
-%%----------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File : iop_ior_12_SUITE.erl
-%% Description : Test suite for the IOR functions
-%%
-%%----------------------------------------------------------------------
--module(iop_ior_12_SUITE).
-
-
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/src/orber_iiop.hrl").
-
--define(default_timeout, test_server:minutes(3)).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
--compile(export_all).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [encoding, create_and_get_ops].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-
-init_per_testcase(_Case, Config) ->
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: IOR encoding test
-%% Description: Just testing the string_encoding function because the
-%% other encodings is called from them.
-%%-----------------------------------------------------------------
-encoding(_) ->
- V = #'IIOP_Version'{major=1,minor=2},
- M0 = 'Module_Interface',
- T0 = "IDL:Module/Interface:1.0",
- H0 = "my.hostname.org",
- P0 = 4040,
- N0 = 'name',
- Components = case orber:iiop_ssl_port() of
- -1 ->
- [];
- SSLPort ->
- [#'IOP_TaggedComponent'{tag=?TAG_SSL_SEC_TRANS,
- component_data=[0 |
- cdrlib:enc_unsigned_short(2,
- cdrlib:enc_unsigned_short(2,
- cdrlib:enc_unsigned_short(SSLPort, [])))]}]
- end,
- O0 = corba_fake_mk_objkey(M0, registered, N0),
- PB0 = #'IIOP_ProfileBody_1_1'{iiop_version=V, host=H0, port=P0, object_key=O0,
- components=Components},
- TP0 = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB0},
- S0 = #'IOP_IOR'{type_id=T0, profiles=[TP0]},
- N1 = list_to_pid("<0.100.0>"),
- O1 = corba_fake_mk_objkey(M0, key, N1),
- PB1 = #'IIOP_ProfileBody_1_1'{iiop_version=V, host=H0, port=P0, object_key=O1,
- components=[]},
- TP1 = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB1},
- S1 = #'IOP_IOR'{type_id=T0, profiles=[TP1]},
- O2 = "This is an external objectkey",
- PB2 = #'IIOP_ProfileBody_1_1'{iiop_version=V, host=H0, port=P0, object_key=O2,
- components=[]},
- TP2 = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB2},
- S2 = #'IOP_IOR'{type_id=T0, profiles=[TP2]},
- C0 = iop_ior:string_code(S0),
- {S0, <<>>, _} = iop_ior:string_decode(C0),
- C1 = iop_ior:string_code(S1),
- {S1, <<>>, _} = iop_ior:string_decode(C1),
- C2 = iop_ior:string_code(S2),
- {S2, <<>>, _} = iop_ior:string_decode(C2),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: IOR creation test
-%% Description:
-%%-----------------------------------------------------------------
-create_and_get_ops(_) ->
- V = #'IIOP_Version'{major=1,minor=2},
- CSC = #'IOP_TaggedComponent'{tag=?TAG_CODE_SETS,
- component_data=?DEFAULT_CODESETS},
- M0 = 'Module_Interface',
- T0 = "IDL:Module/Interface:1.0",
- H0 = "my.hostname.org",
- P0 = 4040,
- N0 = 'name',
- O0 = corba_fake_mk_objkey(M0, registered, N0),
- PB0 = #'IIOP_ProfileBody_1_1'
- {iiop_version=V, host=H0, port=P0, object_key=O0,
- components=[CSC]},
- TP0 = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB0},
- S0 = #'IOP_IOR'{type_id=T0, profiles=[TP0]},
- S0 = iop_ior:create({1, 2}, T0, [H0], P0, -1, O0, [CSC], 0, 0),
- N1 = list_to_pid("<0.100.0>"),
- O1 = corba_fake_mk_objkey(M0, key, N1),
- {_,_,K1,_,_,_} = O1,
- PB1 = #'IIOP_ProfileBody_1_1'
- {iiop_version=V, host=H0, port=P0, object_key=O1,
- components=[CSC]},
- TP1 = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB1},
- S1 = #'IOP_IOR'{type_id=T0, profiles=[TP1]},
- S1 = iop_ior:create({1, 2}, T0, [H0], P0, -1, O1, [CSC], 0, 0),
- O2 = "This is an external objectkey",
- PB2 = #'IIOP_ProfileBody_1_1'{iiop_version=V, host=H0, port=P0, object_key=O2,
- components=[]},
- TP2 = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, profile_data=PB2},
- S2 = #'IOP_IOR'{type_id=T0, profiles=[TP2]},
- {'internal_registered', N0, _, _, M0} = iop_ior:get_key(S0),
- {'internal', K1, _, _, M0} = iop_ior:get_key(S1),
- {'external', {H0, P0, O2,_,_,
- #host_data{protocol = normal,
- ssl_data = undefined,
- version = {1,2},
- csiv2_mech = undefined,
- csiv2_statefull = false,
- charset = 65537,
- wcharset = 65801,
- ft_heartbeat = false,
- ft_primary = false,
- ft_group = undefined,
- csiv2_addresses = []}}}
- = iop_ior:get_key(S2),
- T0 = iop_ior:get_typeID(S0),
- O0 = iop_ior:get_objkey(S0),
- O1 = iop_ior:get_objkey(S1),
- O2 = iop_ior:get_objkey(S2),
- ok.
-
-%%-----------------------------------------------------------------
-%% Internal functions
-%%-----------------------------------------------------------------
-corba_fake_mk_objkey(Id, 'key', Pid) when is_pid(Pid) ->
- Key = make_objkey(),
- {Id, 'key', Key, term_to_binary(undefined), 0, 0};
-corba_fake_mk_objkey(Id, 'key', RegName) when is_atom(RegName) ->
- Key = term_to_binary(RegName),
- {Id, 'key', Key, term_to_binary(undefined), 0, 0};
-corba_fake_mk_objkey(Id, 'registered', RegName) when is_atom(RegName) ->
- {Id, 'registered', RegName, term_to_binary(undefined), 0, 0}.
-
-make_objkey() ->
- term_to_binary({{erlang:system_time(),
- erlang:unique_integer()},
- node()}).
diff --git a/lib/orber/test/ip_v4v6_interop_SUITE.erl b/lib/orber/test/ip_v4v6_interop_SUITE.erl
deleted file mode 100644
index 48cc77eca7..0000000000
--- a/lib/orber/test/ip_v4v6_interop_SUITE.erl
+++ /dev/null
@@ -1,199 +0,0 @@
-%%----------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%----------------------------------------------------------------------
-%% File : ip_v4v6_interop_SUITE.erl
-%% Description :
-%%
-%%----------------------------------------------------------------------
--module(ip_v4v6_interop_SUITE).
-
--compile(export_all).
-%%----------------------------------------------------------------------
-%% External exports
-%%----------------------------------------------------------------------
--export([
- all/0,
- init_per_suite/1,
- end_per_suite/1,
- init_per_testcase/2,
- end_per_testcase/2,
- groups/0,
- init_per_group/2,
- end_per_group/2
- ]).
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
-
-%%----------------------------------------------------------------------
-%% Include files
-%%----------------------------------------------------------------------
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/include/corba.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming.hrl").
--include_lib("orber/src/orber_iiop.hrl").
--include_lib("orber/src/ifr_objects.hrl").
--include("idl_output/orber_test_server.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming_NamingContextExt.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming_NamingContext.hrl").
-
-%%----------------------------------------------------------------------
-%% Macros
-%%----------------------------------------------------------------------
--define(default_timeout, test_server:minutes(15)).
-
--define(match(ExpectedRes,Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- io:format("------ CORRECT RESULT ------~n~p~n",
- [AcTuAlReS]),
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~nRESULT: ~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-%%----------------------------------------------------------------------
-%% Records
-%%----------------------------------------------------------------------
-
-%%======================================================================
-%% Initialization functions.
-%%======================================================================
-
-init_per_testcase(_Case, Config) ->
- %% Starting dual configured ORB
- orber:jump_start([{iiop_port, 10001}, {flags, 16#1000}]),
- orber:info(),
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- orber:jump_stop(),
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(Config) ->
- Config.
-
-%%====================================================================
-%% SUITE specification
-%%====================================================================
-all() ->
- [
- dual_ipv4v6
- ].
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-%%====================================================================
-%% Test Cases
-%%====================================================================
-%% ORB configured for supporting both IPv4 and IPv6
-dual_ipv4v6(_Config) ->
-
- %% Starting slave node with ipv4 configured ORB
- {ok, Ipv4Node, _Ipv4Host} =
- ?match({ok,_,_}, orber_test_lib:js_node([{iiop_port, 4001}])),
- Ipv4NS = orber_test_lib:remote_apply(Ipv4Node, corba, resolve_initial_references, ["NameService"]),
-
- %% Starting slave node with ipv6 configured ORB
- {ok, Ipv6Node, _Ipv6Host} =
- ?match({ok,_,_}, orber_test_lib:js_node([{iiop_port, 6001}, {flags, 16#0100}])),
- Ipv6NS = orber_test_lib:remote_apply(Ipv6Node, corba, resolve_initial_references, ["NameService"]),
-
- %% Add the ipv6 interface in the dual configured ORB
- ?match({ok, _}, orber:add_listen_interface("::1", normal,
- [{ip_family, inet6}, {iiop_port, 10002}])),
- DualNS = corba:resolve_initial_references("NameService"),
-
- %% Bind IPv4 NameServer to a name in the dual stack orbs NameServer
- NSDual4 = orber_test_lib:remote_apply(Ipv4Node, corba, resolve_initial_references_remote,
- ["NameService", ["iiop://127.0.0.1:10001"]]),
- ?match(ok, orber_test_lib:remote_apply(Ipv4Node, 'CosNaming_NamingContext', bind,
- [NSDual4, lname:new(["ns4"]), Ipv4NS])),
- 'CosNaming_NamingContext':resolve(DualNS, lname:new(["ns4"])),
-
- %% Bind IPv6 NameServer to a name in the dual stack orbs NameServer
- NSDual6 = orber_test_lib:remote_apply(Ipv6Node, corba, resolve_initial_references_remote,
- ["NameService", ["iiop://[::1]:10002"]]),
- ?match(ok, orber_test_lib:remote_apply(Ipv6Node, 'CosNaming_NamingContext', bind,
- [NSDual6, lname:new(["ns6"]), Ipv6NS])),
- 'CosNaming_NamingContext':resolve(DualNS, lname:new(["ns6"])),
-
- %% IPv4: Fetch IPv6 NS reference from dual stack orber and register own NameServer in that
- Ipv4NSO = orber_test_lib:remote_apply(Ipv4Node, 'CosNaming_NamingContext', resolve,
- [NSDual4, lname:new(["ns6"])]),
- ?match(ok, orber_test_lib:remote_apply(Ipv4Node, 'CosNaming_NamingContext', bind,
- [Ipv4NSO, lname:new(["nso"]), Ipv4NS])),
-
- %% IPv6: Fetch IPv4 NS reference from dual stack orber and register own NameServer in that
- Ipv6NSO = orber_test_lib:remote_apply(Ipv6Node, 'CosNaming_NamingContext', resolve,
- [NSDual6, lname:new(["ns4"])]),
- ?match(ok, orber_test_lib:remote_apply(Ipv6Node, 'CosNaming_NamingContext', bind,
- [Ipv6NSO, lname:new(["nso"]), Ipv6NS])),
-
-
- %% IPv4: Fetch own NS reference from IPv6 NameServer and add a context then check that everything went well
- Ipv4NSFromIpv6 = orber_test_lib:remote_apply(Ipv6Node, 'CosNaming_NamingContext', resolve,
- [Ipv6NS, lname:new(["nso"])]),
- _Ipv4NC = orber_test_lib:remote_apply(Ipv4Node, 'CosNaming_NamingContext', bind_new_context,
- [Ipv4NSFromIpv6, lname:new(["test_context4"])]),
-
- %% IPv6: Fetch own NS reference from IPv4 NameServer and add a context then check that everything went well
- Ipv6NSFromIpv4 = orber_test_lib:remote_apply(Ipv4Node, 'CosNaming_NamingContext', resolve,
- [Ipv4NS, lname:new(["nso"])]),
- _Ipv6NC = orber_test_lib:remote_apply(Ipv6Node, 'CosNaming_NamingContext', bind_new_context,
- [Ipv6NSFromIpv4, lname:new(["test_context6"])]),
-
- %% Check that all the names are register correctly
- {ok,DualNames,_} = 'CosNaming_NamingContext':list(DualNS, 100),
- {ok,Ipv4Names,_} = orber_test_lib:remote_apply(Ipv4Node, 'CosNaming_NamingContext', list, [Ipv4NS, 100]),
- {ok,Ipv6Names,_} = orber_test_lib:remote_apply(Ipv6Node, 'CosNaming_NamingContext', list, [Ipv6NS, 100]),
-
- io:format("\nNames in Dual NS: ~p\n", [DualNames]),
- ?match(2, length(DualNames)),
- io:format("\nNames in IPv4 NS: ~p\n", [Ipv4Names]),
- ?match(2, length(Ipv4Names)),
- io:format("\nNames in IPv6 NS: ~p\n", [Ipv6Names]),
- ?match(2, length(Ipv6Names)),
-
- ok.
-
diff --git a/lib/orber/test/lname_SUITE.erl b/lib/orber/test/lname_SUITE.erl
deleted file mode 100644
index cb67cd6136..0000000000
--- a/lib/orber/test/lname_SUITE.erl
+++ /dev/null
@@ -1,213 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%%
-%% Description:
-%% Test suite for the Names Library module
-%%
-%%-----------------------------------------------------------------
--module(lname_SUITE).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming.hrl").
--include_lib("orber/COSS/CosNaming/lname.hrl").
-
--define(default_timeout, test_server:minutes(3)).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([]).
--compile(export_all).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [lname_component, lname].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-
-init_per_testcase(_Case, Config) ->
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: name component handling tests
-%% Description:
-%%-----------------------------------------------------------------
-lname_component(_) ->
- create_test(),
- get_tests(),
- set_tests().
-
-create_test() ->
- #'CosNaming_NameComponent'{} = lname_component:create(),
- ok.
-
-get_tests() ->
- NC = #'CosNaming_NameComponent'{id="first", kind="apple"},
- NC1 = #'CosNaming_NameComponent'{id="", kind="apple"},
- NC2 = #'CosNaming_NameComponent'{id="first", kind=""},
- "first" = lname_component:get_id(NC),
- "apple" = lname_component:get_kind(NC),
- {'EXCEPTION', #'LNameComponent_NotSet'{}} =
- (catch lname_component:get_id(NC1)),
- {'EXCEPTION', #'LNameComponent_NotSet'{}} =
- (catch lname_component:get_kind(NC2)),
- ok.
-
-set_tests() ->
- NC = #'CosNaming_NameComponent'{id="first", kind="apple"},
- #'CosNaming_NameComponent'{id="second", kind="apple"} =
- lname_component:set_id(NC, "second"),
- #'CosNaming_NameComponent'{id="first", kind="pear"} =
- lname_component:set_kind(NC, "pear"),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: name handling tests
-%% Description:
-%%-----------------------------------------------------------------
-lname(_) ->
- Name = [#'CosNaming_NameComponent'{id="first", kind="apple"},
- #'CosNaming_NameComponent'{id="last", kind="peach"},
- #'CosNaming_NameComponent'{id="and", kind="plum"},
- #'CosNaming_NameComponent'{id="always", kind="orange"}],
- insert_tests(Name),
- get_tests(Name),
- delete_tests(Name),
- comparision_tests(Name),
- convertion_tests(Name).
-
-insert_tests(Name) ->
- NC = #'CosNaming_NameComponent'{id="new", kind="pear"},
- [NC, #'CosNaming_NameComponent'{id="first", kind="apple"},
- #'CosNaming_NameComponent'{id="last", kind="peach"},
- #'CosNaming_NameComponent'{id="and", kind="plum"},
- #'CosNaming_NameComponent'{id="always", kind="orange"}] =
- lname:insert_component(Name, 1, NC),
- [#'CosNaming_NameComponent'{id="first", kind="apple"},
- #'CosNaming_NameComponent'{id="last", kind="peach"},
- #'CosNaming_NameComponent'{id="and", kind="plum"},
- #'CosNaming_NameComponent'{id="always", kind="orange"}, NC] =
- lname:insert_component(Name, 5, NC),
- [#'CosNaming_NameComponent'{id="first", kind="apple"},
- #'CosNaming_NameComponent'{id="last", kind="peach"},
- #'CosNaming_NameComponent'{id="and", kind="plum"}, NC,
- #'CosNaming_NameComponent'{id="always", kind="orange"}] =
- lname:insert_component(Name, 4, NC),
- [#'CosNaming_NameComponent'{id="first", kind="apple"},
- #'CosNaming_NameComponent'{id="last", kind="peach"}, NC,
- #'CosNaming_NameComponent'{id="and", kind="plum"},
- #'CosNaming_NameComponent'{id="always", kind="orange"}] =
- lname:insert_component(Name, 3, NC),
- {'EXCEPTION', #'LName_NoComponent'{}} =
- (catch lname:insert_component(Name, 6, NC)),
- {'EXCEPTION', #'LName_NoComponent'{}} =
- (catch lname:insert_component(Name, 0, NC)),
- {'EXCEPTION', #'LName_NoComponent'{}} =
- (catch lname:insert_component(Name, -2, NC)),
- ok.
-
-get_tests(Name) ->
- #'CosNaming_NameComponent'{id="first", kind="apple"} =
- lname:get_component(Name, 1),
- #'CosNaming_NameComponent'{id="always", kind="orange"} =
- lname:get_component(Name, 4),
- #'CosNaming_NameComponent'{id="and", kind="plum"} =
- lname:get_component(Name, 3),
- {'EXCEPTION', #'LName_NoComponent'{}} =
- (catch lname:get_component(Name, 5)),
- {'EXCEPTION', #'LName_NoComponent'{}} =
- (catch lname:get_component(Name, 0)),
- {'EXCEPTION', #'LName_NoComponent'{}} =
- (catch lname:get_component(Name, -2)),
- ok.
-
-delete_tests(Name) ->
- [#'CosNaming_NameComponent'{id="last", kind="peach"},
- #'CosNaming_NameComponent'{id="and", kind="plum"},
- #'CosNaming_NameComponent'{id="always", kind="orange"}] =
- lname:delete_component(Name, 1),
- [#'CosNaming_NameComponent'{id="first", kind="apple"},
- #'CosNaming_NameComponent'{id="last", kind="peach"},
- #'CosNaming_NameComponent'{id="and", kind="plum"}] =
- lname:delete_component(Name, 4),
- [#'CosNaming_NameComponent'{id="first", kind="apple"},
- #'CosNaming_NameComponent'{id="last", kind="peach"},
- #'CosNaming_NameComponent'{id="always", kind="orange"}] =
- lname:delete_component(Name, 3),
- {'EXCEPTION', #'LName_NoComponent'{}} =
- (catch lname:delete_component(Name, 6)),
- {'EXCEPTION', #'LName_NoComponent'{}} =
- (catch lname:delete_component(Name, 0)),
- {'EXCEPTION', #'LName_NoComponent'{}} =
- (catch lname:delete_component(Name, -2)),
- ok.
-
-comparision_tests(Name) ->
- true = lname:equal(Name, Name),
- false = lname:equal(Name, lname:delete_component(Name, 2)),
- true = lname:less_than(lname:delete_component(Name, 2), Name),
- false = lname:less_than(Name, Name),
- false = lname:less_than(Name, lname:delete_component(Name, 2)),
- ok.
-
-convertion_tests(Name) ->
- Name = lname:from_idl_form(Name),
- Name = lname:to_idl_form(Name),
- ok.
diff --git a/lib/orber/test/multi_ORB_SUITE.erl b/lib/orber/test/multi_ORB_SUITE.erl
deleted file mode 100644
index 3c5bb0b5e5..0000000000
--- a/lib/orber/test/multi_ORB_SUITE.erl
+++ /dev/null
@@ -1,2286 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(multi_ORB_SUITE).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/include/corba.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming.hrl").
--include_lib("orber/src/orber_iiop.hrl").
--include_lib("orber/src/ifr_objects.hrl").
--include("idl_output/orber_test_server.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming_NamingContextExt.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming_NamingContext.hrl").
-
-
--define(default_timeout, test_server:minutes(15)).
-
--define(match(ExpectedRes,Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- io:format("------ CORRECT RESULT ------~n~p~n",
- [AcTuAlReS]),
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~nRESULT: ~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2, cases/0,
- init_per_suite/1, end_per_suite/1, basic_PI_api/1, multi_orber_api/1,
- init_per_testcase/2, end_per_testcase/2, multi_pseudo_orber_api/1,
- light_orber_api/1, light_orber2_api/1,
- ssl_1_multi_orber_api/1, ssl_2_multi_orber_api/1, ssl_reconfigure_api/1,
- iiop_timeout_api/1, iiop_timeout_added_api/1, setup_connection_timeout_api/1,
- setup_multi_connection_timeout_api/1, setup_multi_connection_timeout_random_api/1,
- setup_multi_connection_timeout_attempts_api/1,
- fragments_server_api/1, fragments_max_server_api/1,
- fragments_max_server_added_api/1, fragments_client_api/1,
- light_ifr_api/1, max_requests_api/1, max_requests_added_api/1,
- max_connections_api/1, max_packet_size_exceeded_api/1,
- max_packet_size_ok_api/1, proxy_interface_api/1, proxy_interface_ipv6_api/1,
- multiple_accept_api/1, implicit_context_api/1,
- pseudo_implicit_context_api/1, pseudo_two_implicit_context_api/1,
- oneway_implicit_context_api/1, implicit_context_roundtrip_api/1,
- oneway_pseudo_implicit_context_api/1, flags_added_api/1,
- oneway_pseudo_two_implicit_context_api/1,
- local_interface_api/1, local_interface_ctx_override_api/1,
- local_interface_acl_override_api/1, bad_giop_header_api/1,
- bad_fragment_id_client_api/1, bad_id_cancel_request_api/1,
- close_connections_api/1, close_connections_local_interface_api/1,
- 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,
- close_connections_alt_iiop_addr_api/1, close_connections_multiple_profiles_api/1]).
-
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([pseudo_calls/2, pseudo_casts/2, create_fake_server_ORB/5, do_connect/3]).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- cases().
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%% NOTE - the fragment test cases must be first since we explicitly set a request
-%% id. Otherwise, the request-id counter would be increased and we cannot know
-%% what it is.
-cases() ->
- [fragments_server_api, fragments_max_server_api,
- fragments_max_server_added_api, fragments_client_api,
- flags_added_api, bad_fragment_id_client_api,
- bad_giop_header_api, bad_id_cancel_request_api,
- implicit_context_api, pseudo_implicit_context_api,
- pseudo_two_implicit_context_api,
- implicit_context_roundtrip_api,
- oneway_implicit_context_api,
- oneway_pseudo_implicit_context_api,
- oneway_pseudo_two_implicit_context_api,
- proxy_interface_api, proxy_interface_ipv6_api,
- local_interface_api, local_interface_ctx_override_api,
- local_interface_acl_override_api, close_connections_api,
- close_connections_local_interface_api,
- close_connections_local_interface_ctx_override_api,
- close_connections_alt_iiop_addr_api,
- close_connections_multiple_profiles_api,
- multiple_accept_api, max_requests_api,
- max_requests_added_api, max_connections_api,
- max_packet_size_exceeded_api, max_packet_size_ok_api,
- light_ifr_api, multi_pseudo_orber_api, multi_orber_api,
- light_orber_api, light_orber2_api, basic_PI_api,
- iiop_timeout_api, iiop_timeout_added_api,
- setup_connection_timeout_api,
- setup_multi_connection_timeout_api,
- setup_multi_connection_timeout_attempts_api,
- setup_multi_connection_timeout_random_api,
- ssl_1_multi_orber_generation_3_api,
- ssl_2_multi_orber_generation_3_api,
- ssl_reconfigure_generation_3_api].
-
-% ssl_1_multi_orber_api,ssl_2_multi_orber_api,ssl_reconfigure_api,
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-init_per_testcase(TC,Config)
- when TC =:= ssl_1_multi_orber_api;
- TC =:= ssl_2_multi_orber_api;
- TC =:= ssl_reconfigure_api ->
- init_ssl(Config);
-init_per_testcase(TC,Config)
- 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);
-init_per_testcase(_Case, Config) ->
- init_all(Config).
-
-init_ssl(Config) ->
- case proplists:get_value(crypto_started, Config) of
- true ->
- case orber_test_lib:ssl_version() of
- no_ssl ->
- {skip, "SSL is not installed!"};
- _ ->
- init_all(Config)
- end;
- false ->
- {skip, "Crypto did not start"}
- end.
-
-init_ssl_3(Config) ->
- case proplists:get_value(crypto_started, Config) of
- true ->
- case orber_test_lib:ssl_version() of
- 3 ->
- init_all(Config);
- 2 ->
- {skip, "Could not find the correct SSL version!"};
- no_ssl ->
- {skip, "SSL is not installed!"}
- end;
- false ->
- {skip, "Crypto did not start"}
- end.
-
-init_all(Config) ->
- Path = code:which(?MODULE),
- code:add_pathz(filename:join(filename:dirname(Path), "idl_output")),
- Dog=test_server:timetrap(?default_timeout),
- orber:jump_start(0),
- oe_orber_test_server:oe_register(),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- oe_orber_test_server:oe_unregister(),
- orber:jump_stop(),
- Path = code:which(?MODULE),
- code:del_path(filename:join(filename:dirname(Path), "idl_output")),
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-init_per_suite(Config) ->
- if
- is_list(Config) ->
- try crypto:start() of
- ok ->
- [{crypto_started, true} | Config]
- catch _:_ ->
- [{crypto_started, false} | Config]
- end;
- true ->
- exit("Config not a list")
- end.
-
-end_per_suite(Config) ->
- application:stop(crypto),
- Config.
-
-%%-----------------------------------------------------------------
-%% API tests for ORB to ORB, no security
-%%-----------------------------------------------------------------
-
-%% IIOP Implicit Contex tests
-implicit_context_api(_Config) ->
- IP = orber_test_lib:get_host(),
- Loopback = orber_test_lib:get_loopback_interface(),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_LOCAL_INTERFACE},
- {ip_address, IP}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- %% Create a remote server
- ?match(ok, orber_test_lib:remote_apply(ServerNode, orber_test_lib,
- install_test_data,
- [nameservice])),
- IOR = ?match(#'IOP_IOR'{},
- corba:string_to_object("corbaname::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService#mamba")),
-
- Relay = ?match({_,_,_,_,_,_}, orber_test_server:oe_create([])),
- ?match(ok,
- orber_test_server:
- relay_call(Relay,
- [{context,
- [#'IOP_ServiceContext'{context_id=?ORBER_GENERIC_CTX_ID,
- context_data = {interface,
- Loopback}}]}],
- IOR)),
-
- ?match([_,_], orber:iiop_connections(out)),
- Conns = ?match([_,_],
- orber_test_lib:remote_apply(ServerNode, orber, iiop_connections, [in])),
- ?match(true, lists:keymember(Loopback, 1, Conns)),
- ok.
-
-%% IIOP Implicit Contex roundtrip tests
-implicit_context_roundtrip_api(_Config) ->
- IP = orber_test_lib:get_host(),
- Loopback = orber_test_lib:get_loopback_interface(),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_LOCAL_INTERFACE},
- {ip_address, IP}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- %% Create a remote server
- ?match(ok, orber_test_lib:remote_apply(ServerNode, orber_test_lib,
- install_test_data,
- [nameservice])),
- Relay = ?match(#'IOP_IOR'{},
- corba:string_to_object("corbaname::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService#mamba")),
-
- IOR = ?match({_,_,_,_,_,_}, orber_test_server:oe_create([], [])),
- ?match(ok,
- orber_test_server:
- relay_call(Relay,
- [{context,
- [#'IOP_ServiceContext'{context_id=?ORBER_GENERIC_CTX_ID,
- context_data = {interface,
- Loopback}}]}],
- IOR)),
- ?match([_,_], orber:iiop_connections(out)),
- Conns = ?match([_,_],
- orber_test_lib:remote_apply(ServerNode, orber, iiop_connections, [in])),
- ?match(true, lists:keymember(Loopback, 1, Conns)),
- ok.
-
-%% IIOP Implicit Contex oneway tests
-oneway_implicit_context_api(_Config) ->
- IP = orber_test_lib:get_host(),
- Loopback = orber_test_lib:get_loopback_interface(),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_LOCAL_INTERFACE},
- {ip_address, IP}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- %% Create a remote server
- ?match(ok, orber_test_lib:remote_apply(ServerNode, orber_test_lib,
- install_test_data,
- [nameservice])),
- IOR = ?match(#'IOP_IOR'{},
- corba:string_to_object("corbaname::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService#mamba")),
-
- Relay = ?match({_,_,_,_,_,_}, orber_test_server:oe_create([])),
- ?match(ok,
- orber_test_server:
- relay_cast(Relay,
- [{context,
- [#'IOP_ServiceContext'{context_id=?ORBER_GENERIC_CTX_ID,
- context_data = {interface,
- Loopback}}]}],
- IOR)),
-
- %% We must wait for a few seconds for the client to be able to set up the
- %% connection (since it's a oneway operation).
- timer:sleep(5000),
- ?match([_,_], orber:iiop_connections(out)),
- Conns = ?match([_,_],
- orber_test_lib:remote_apply(ServerNode, orber, iiop_connections, [in])),
- ?match(true, lists:keymember(Loopback, 1, Conns)),
- ok.
-
-%% IIOP Implicit Contex tests (via pseudo object)
-pseudo_implicit_context_api(_Config) ->
- IP = orber_test_lib:get_host(),
- Loopback = orber_test_lib:get_loopback_interface(),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_LOCAL_INTERFACE},
- {ip_address, IP}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- %% Create a remote server
- ?match(ok, orber_test_lib:remote_apply(ServerNode, orber_test_lib,
- install_test_data,
- [nameservice])),
- IOR = ?match(#'IOP_IOR'{},
- corba:string_to_object("corbaname::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService#mamba")),
-
- Relay = ?match({_,_,_,_,_,_}, orber_test_server:oe_create([], [{pseudo,true}])),
- ?match(ok,
- orber_test_server:
- relay_call(Relay,
- [{context,
- [#'IOP_ServiceContext'{context_id=?ORBER_GENERIC_CTX_ID,
- context_data = {interface,
- Loopback}}]}],
- IOR)),
- ?match([_,_], orber:iiop_connections(out)),
- Conns = ?match([_,_],
- orber_test_lib:remote_apply(ServerNode, orber, iiop_connections, [in])),
- ?match(true, lists:keymember(Loopback, 1, Conns)),
- ok.
-
-%% IIOP two Implicit Contex tests (via pseudo object)
-pseudo_two_implicit_context_api(_Config) ->
- IP = orber_test_lib:get_host(),
- Loopback = orber_test_lib:get_loopback_interface(),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_LOCAL_INTERFACE},
- {ip_address, IP}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- %% Create a remote server
- ?match(ok, orber_test_lib:remote_apply(ServerNode, orber_test_lib,
- install_test_data,
- [nameservice])),
- IOR = ?match(#'IOP_IOR'{},
- corba:string_to_object("corbaname::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService#mamba")),
-
- Relay = ?match({_,_,_,_,_,_}, orber_test_server:oe_create([], [{pseudo,true}])),
- put(oe_server_in_context,
- [#'IOP_ServiceContext'{context_id=?ORBER_GENERIC_CTX_ID,
- context_data = {interface,
- IP}}]),
- ?match(ok,
- orber_test_server:
- relay_call(Relay,
- [{context,
- [#'IOP_ServiceContext'{context_id=?ORBER_GENERIC_CTX_ID,
- context_data = {interface,
- Loopback}}]}],
- IOR)),
- ?match([_,_], orber:iiop_connections(out)),
- Conns = ?match([_,_],
- orber_test_lib:remote_apply(ServerNode, orber, iiop_connections, [in])),
- ?match(true, lists:keymember(Loopback, 1, Conns)),
- ok.
-
-%% IIOP Implicit Contex tests (via pseudo object oneway)
-oneway_pseudo_implicit_context_api(_Config) ->
- IP = orber_test_lib:get_host(),
- Loopback = orber_test_lib:get_loopback_interface(),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_LOCAL_INTERFACE},
- {ip_address, IP}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- %% Create a remote server
- ?match(ok, orber_test_lib:remote_apply(ServerNode, orber_test_lib,
- install_test_data,
- [nameservice])),
- IOR = ?match(#'IOP_IOR'{},
- corba:string_to_object("corbaname::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService#mamba")),
-
- Relay = ?match({_,_,_,_,_,_}, orber_test_server:oe_create([], [{pseudo,true}])),
- ?match(ok,
- orber_test_server:
- relay_cast(Relay,
- [{context,
- [#'IOP_ServiceContext'{context_id=?ORBER_GENERIC_CTX_ID,
- context_data = {interface,
- Loopback}}]}],
- IOR)),
- ?match([_,_], orber:iiop_connections(out)),
- Conns = ?match([_,_],
- orber_test_lib:remote_apply(ServerNode, orber, iiop_connections, [in])),
- ?match(true, lists:keymember(Loopback, 1, Conns)),
- ok.
-
-%% IIOP two Implicit Contex tests (via pseudo object oneway)
-oneway_pseudo_two_implicit_context_api(_Config) ->
- IP = orber_test_lib:get_host(),
- Loopback = orber_test_lib:get_loopback_interface(),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_LOCAL_INTERFACE},
- {ip_address, IP}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- %% Create a remote server
- ?match(ok, orber_test_lib:remote_apply(ServerNode, orber_test_lib,
- install_test_data,
- [nameservice])),
- IOR = ?match(#'IOP_IOR'{},
- corba:string_to_object("corbaname::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService#mamba")),
-
- Relay = ?match({_,_,_,_,_,_}, orber_test_server:oe_create([], [{pseudo,true}])),
- %% Add incoming implicit context which must be removed.
- put(oe_server_in_context,
- [#'IOP_ServiceContext'{context_id=?ORBER_GENERIC_CTX_ID,
- context_data = {interface,
- IP}}]),
- ?match(ok,
- orber_test_server:
- relay_cast(Relay,
- [{context,
- [#'IOP_ServiceContext'{context_id=?ORBER_GENERIC_CTX_ID,
- context_data = {interface,
- Loopback}}]}],
- IOR)),
- ?match([_,_], orber:iiop_connections(out)),
- Conns = ?match([_,_],
- orber_test_lib:remote_apply(ServerNode, orber, iiop_connections, [in])),
- ?match(true, lists:keymember(Loopback, 1, Conns)),
- ok.
-
-
-
-%% IIOP Multiple Accept tests
-multiple_accept_api(_Config) ->
- IP = orber_test_lib:get_host(),
- Loopback = orber_test_lib:get_loopback_interface(),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_LOCAL_INTERFACE},
- {ip_address, IP}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- %% The server ORB doesn't listen to 127.0.0.1
- ?match({'EXCEPTION',_},
- corba:string_to_object("corbaloc::1.2@" ++Loopback++":"++integer_to_list(ServerPort)++"/NameService")),
- ?match([], orber:iiop_connections(out)),
-
- IOR1 = ?match(#'IOP_IOR'{},
- corba:string_to_object("corbaloc::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService")),
- ?match({'external', {IP, ServerPort, _ObjectKey, _Counter, _TP, _NewHD}},
- iop_ior:get_key(IOR1)),
- ?match([_], orber:iiop_connections(out)),
-
- {ok, Ref1} = ?match({ok, _},
- orber_test_lib:remote_apply(ServerNode, orber,
- add_listen_interface,
- [Loopback, normal])),
-
- IOR2 = ?match(#'IOP_IOR'{},
- corba:string_to_object("corbaloc::1.2@"++Loopback++":"++integer_to_list(ServerPort)++"/NameService")),
- ?match({'external', {Loopback, ServerPort, _ObjectKey, _Counter, _TP, _NewHD}},
- iop_ior:get_key(IOR2)),
- ?match([_,_], orber:iiop_connections(out)),
-
- {ok, Ref2} = ?match({ok, _},
- orber_test_lib:remote_apply(ServerNode, orber,
- add_listen_interface,
- [Loopback, normal, 9543])),
- ?match({error, eaddrinuse},
- orber_test_lib:remote_apply(ServerNode, orber,
- add_listen_interface,
- [Loopback, normal, 9543])),
-
- IOR3 = ?match(#'IOP_IOR'{},
- corba:string_to_object("corbaloc::1.2@"++Loopback++":9543/NameService")),
- ?match({'external', {Loopback, 9543, _ObjectKey, _Counter, _TP, _NewHD}},
- iop_ior:get_key(IOR3)),
- ?match([_,_,_], orber:iiop_connections(out)),
-
- ?match(ok,
- orber_test_lib:remote_apply(ServerNode, orber,
- remove_listen_interface, [Ref1])),
- %% Wait a few seconds to be sure that the connections really has been removed.
- timer:sleep(4000),
- ?match([_,_], orber:iiop_connections(out)),
-
- ?match(ok,
- orber_test_lib:remote_apply(ServerNode, orber,
- remove_listen_interface, [Ref2])),
- %% Wait a few seconds to be sure that the connections really has been removed.
- timer:sleep(4000),
- ?match([_], orber:iiop_connections(out)),
-
- ?match({'EXCEPTION',_},
- corba:string_to_object("corbaloc::1.2@"++Loopback++":9543/NameService")),
- ?match({'EXCEPTION',_},
- corba:string_to_object("corbaloc::1.2@"++Loopback++":"++integer_to_list(ServerPort)++"/NameService")),
-
- IOR4 = ?match(#'IOP_IOR'{},
- corba:string_to_object("corbaloc::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService")),
- ?match({'external', {IP, ServerPort, _ObjectKey, _Counter, _TP, _NewHD}},
- iop_ior:get_key(IOR4)),
-
- ok.
-
-
-%% IIOP Proxy Interface tests
-%% This case test if the server ORB use the correct
-%% interface when exporting IOR:s
-proxy_interface_api(_Config) ->
- IP = orber_test_lib:get_host(),
- Loopback = orber_test_lib:get_loopback_interface(),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_LOCAL_INTERFACE}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- IOR1 = ?match(#'IOP_IOR'{},
- corba:string_to_object("corbaloc::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService")),
- ?match({'external', {IP, ServerPort, _ObjectKey, _Counter, _TP, _NewHD}},
- iop_ior:get_key(IOR1)),
- IOR2 = ?match(#'IOP_IOR'{},
- corba:string_to_object("corbaloc::1.2@"++Loopback++":"++integer_to_list(ServerPort)++"/NameService")),
- ?match({'external', {Loopback, ServerPort, _ObjectKey, _Counter, _TP, _NewHD}},
- iop_ior:get_key(IOR2)),
- ok.
-
-%% IIOP Proxy Interface tests
-%% This case test if the server ORB use the correct
-%% IPv6 interface when exporting IOR:s
-proxy_interface_ipv6_api(_Config) ->
- case orber_test_lib:version_ok() of
- true ->
- proxy_interface_ipv6_api2();
- Reason ->
- Reason
- end.
-
-proxy_interface_ipv6_api2() ->
- Loopback = orber_test_lib:get_loopback_interface(inet6),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, (?ORB_ENV_USE_IPV6 bor
- ?ORB_ENV_LOCAL_INTERFACE)}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
-
- {ok, ClientNode, _ClientHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_USE_IPV6}])),
-
- IP = orber_test_lib:remote_apply(ClientNode, orber_test_lib, get_host, []),
-
- IOR1 = ?match(#'IOP_IOR'{},
- orber_test_lib:remote_apply(ClientNode, corba, string_to_object,
- ["corbaloc::1.2@["++IP++"]:"++integer_to_list(ServerPort)++"/NameService"])),
- ?match({'external', {IP, ServerPort, _ObjectKey, _Counter, _TP, _NewHD}},
- orber_test_lib:remote_apply(ClientNode, iop_ior, get_key, [IOR1])),
- IOR2 = ?match(#'IOP_IOR'{},
- orber_test_lib:remote_apply(ClientNode, corba, string_to_object,
- ["corbaloc::1.2@["++Loopback++"]:"++integer_to_list(ServerPort)++"/NameService"])),
- ?match({'external', {Loopback, ServerPort, _ObjectKey, _Counter, _TP, _NewHD}},
- orber_test_lib:remote_apply(ClientNode, iop_ior, get_key, [IOR2])),
- ok.
-
-%% IIOP Local Interface tests
-%% This case test if the server ORB use the correct
-%% local interface when connecting to another ORB
-local_interface_api(_Config) ->
- IP = orber_test_lib:get_host(),
- Loopback = orber_test_lib:get_loopback_interface(),
- {ok, ClientNode, _ClientHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{ip_address_local, Loopback}])),
- Port = orber:iiop_port(),
- ?match(#'IOP_IOR'{},
- orber_test_lib:remote_apply(ClientNode, corba, string_to_object,
- ["corbaloc::1.2@"++IP++":"++integer_to_list(Port)++"/NameService"])),
- [{Loopback, RemotePort}] =
- ?match([{Loopback,_RemotePort}], orber:iiop_connections(in)),
-
- ?match([{IP, Port}],
- orber_test_lib:remote_apply(ClientNode, orber,
- iiop_connections, [out])),
- ?match([{IP, Port}], orber:find_sockname_by_peername(Loopback,RemotePort)),
- ?match([{Loopback, RemotePort}], orber:find_peername_by_sockname(IP, Port)),
-
- ?match([{Loopback, RemotePort}],
- orber_test_lib:remote_apply(ClientNode, orber,
- find_sockname_by_peername,
- [IP, Port])),
- ?match([{IP, Port}],
- orber_test_lib:remote_apply(ClientNode, orber,
- find_peername_by_sockname,
- [Loopback,RemotePort])),
-
-
- ok.
-
-%% IIOP Local Interface tests
-%% This case test if the server ORB use the correct
-%% local interface when connecting to another ORB
-local_interface_ctx_override_api(_Config) ->
- IP = orber_test_lib:get_host(),
- Loopback = orber_test_lib:get_loopback_interface(),
- {ok, ClientNode, _ClientHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{ip_address_local, IP}])),
- Port = orber:iiop_port(),
- ?match(#'IOP_IOR'{},
- orber_test_lib:remote_apply(ClientNode, corba, string_to_object,
- ["corbaloc::1.2@"++IP++":"++integer_to_list(Port)++"/NameService",
- [#'IOP_ServiceContext'
- {context_id=?ORBER_GENERIC_CTX_ID,
- context_data = {interface, Loopback}}]])),
- [{Loopback, RemotePort}] =
- ?match([{Loopback,_RemotePort}], orber:iiop_connections(in)),
-
- ?match([{IP, Port, Loopback}],
- orber_test_lib:remote_apply(ClientNode, orber,
- iiop_connections, [out])),
- ?match([{IP, Port}], orber:find_sockname_by_peername(Loopback,RemotePort)),
- ?match([{Loopback, RemotePort}], orber:find_peername_by_sockname(IP, Port)),
-
- ?match([{Loopback, RemotePort}],
- orber_test_lib:remote_apply(ClientNode, orber,
- find_sockname_by_peername,
- [IP, Port])),
- ?match([{IP, Port}],
- orber_test_lib:remote_apply(ClientNode, orber,
- find_peername_by_sockname,
- [Loopback,RemotePort])),
-
- ok.
-
-%% IIOP Local Interface tests
-%% This case test if the server ORB use the correct
-%% local interface when connecting to another ORB
-local_interface_acl_override_api(_Config) ->
- IP = orber_test_lib:get_host(),
- Loopback = orber_test_lib:get_loopback_interface(),
- ACL = [{tcp_out, IP ++ "/18", [Loopback]}],
- {ok, ClientNode, _ClientHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{ip_address_local, IP},
- {iiop_acl, ACL},
- {flags, ?ORB_ENV_USE_ACL_OUTGOING}])),
- Port = orber:iiop_port(),
- ?match(#'IOP_IOR'{},
- orber_test_lib:remote_apply(ClientNode, corba, string_to_object,
- ["corbaloc::1.2@"++IP++":"++integer_to_list(Port)++"/NameService",
- [#'IOP_ServiceContext'
- {context_id=?ORBER_GENERIC_CTX_ID,
- context_data = {interface, IP}}]])),
- ?match([{Loopback,_RemotePort}], orber:iiop_connections(in)),
- ?match(#'IOP_IOR'{},
- orber_test_lib:remote_apply(ClientNode, corba, string_to_object,
- ["corbaloc::1.2@"++IP++":"++integer_to_list(Port)++"/NameService"])),
-
- [{Loopback, RemotePort}] =
- ?match([{Loopback,_RemotePort}], orber:iiop_connections(in)),
- ?match([{IP, Port, IP}], orber_test_lib:remote_apply(ClientNode, orber,
- iiop_connections, [out])),
- ?match([{IP, Port}], orber:find_sockname_by_peername(Loopback,RemotePort)),
- ?match([{Loopback, RemotePort}], orber:find_peername_by_sockname(IP, Port)),
-
- ?match([{Loopback, RemotePort}],
- orber_test_lib:remote_apply(ClientNode, orber,
- find_sockname_by_peername,
- [IP, Port])),
- ?match([{IP, Port}],
- orber_test_lib:remote_apply(ClientNode, orber,
- find_peername_by_sockname,
- [Loopback,RemotePort])),
-
- ok.
-
-
-%% IIOP TIMEOUT API tests
-%% This case test if timeout configuration behaves correctly
-iiop_timeout_api(_Config) ->
-
- %% Install two secure orber.
- {ok, ClientNode, ClientHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{iiop_timeout, 6},
- {iiop_connection_timeout, 3},
- {iiop_in_connection_timeout, 3}])),
- ClientPort = orber_test_lib:remote_apply(ClientNode, orber, iiop_port, []),
-
- {ok, ServerNode, ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{iiop_timeout, 6},
- {iiop_connection_timeout, 3},
- {iiop_in_connection_timeout, 12}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
-
- ?match(ok, orber_test_lib:remote_apply(ServerNode, orber_test_lib,
- install_test_data,
- [timeout])),
-
- %% Tell client_orb to interoperate with server_orb.
- ?match(ok, orber_test_lib:remote_apply(ClientNode, orber_test_lib,
- lookup,
- [ServerHost, ServerPort])),
- %% Interop worked fine, perform delay tests.
- ?match(ok, orber_test_lib:remote_apply(ClientNode, orber_test_lib,
- timeouts,
- [ServerHost, ServerPort, 6000])),
-
- %% Create a connection to the "client_orb", which will now act as server.
- ?match({'IOP_IOR',_,_},
- corba:string_to_object("corbaloc::1.2@"++ClientHost++":"++integer_to_list(ClientPort)++"/NameService")),
- %% Check that the connection is established.
- ?match([{_, ClientPort}], orber:iiop_connections(out)),
- %% Wait >3 seconds (i.e. iiop_in_connection_timeout) and check if the connection
- %% have been closed.
- timer:sleep(8000),
- ?match([], orber:iiop_connections(out)),
-
- ?match(ok, orber_test_lib:remote_apply(ServerNode, orber_test_lib,
- uninstall_test_data,
- [timeout])),
- ok.
-
-%% IIOP TIMEOUT API tests
-%% This case test if timeout configuration behaves correctly
-iiop_timeout_added_api(_Config) ->
- IP = orber_test_lib:get_host(),
- {ok, Node, _Host} = ?match({ok,_,_}, orber_test_lib:js_node([])),
- Port = 1 + orber_test_lib:remote_apply(Node, orber, iiop_port, []),
- ?match({ok, _},
- orber_test_lib:remote_apply(Node, orber,
- add_listen_interface,
- [IP, normal,
- [{iiop_in_connection_timeout, 3},
- {flags, ?ORB_ENV_LOCAL_INTERFACE},
- {iiop_port, Port}]])),
-
- ?match(ok, orber_test_lib:remote_apply(Node, orber_test_lib,
- install_test_data,
- [timeout])),
-
- ?match({'IOP_IOR',_,_},
- corba:string_to_object("corbaloc::1.2@"++IP++":"++integer_to_list(Port)++"/NameService")),
- %% Check that the connection is established.
- ?match([{_, Port}], orber:iiop_connections(out)),
- %% Wait >3 seconds (i.e. iiop_in_connection_timeout) and check if the connection
- %% have been closed.
- timer:sleep(8000),
- ?match([], orber:iiop_connections(out)),
-
- ?match(ok, orber_test_lib:remote_apply(Node, orber_test_lib,
- uninstall_test_data,
- [timeout])),
- ok.
-
-%%-----------------------------------------------------------------
-%% API tests for ORB to ORB using pseudo call/cast, no security
-%%-----------------------------------------------------------------
-
-%% MULTI ORB PSEUDO API tests
-%% This case test if data encode/decode (IIOP) for pseudo objects
-%% produce the correct result, i.e., the test_server echos
-%% the input parameter or an exception is raised (MARSHAL)
-multi_pseudo_orber_api(_Config) ->
- %% --- Create a slave-node ---
- {ok, Node, Host} =
- ?match({ok,_,_}, orber_test_lib:js_node()),
- Port = orber_test_lib:remote_apply(Node, orber, iiop_port, []),
-
- ?match(ok, orber_test_lib:remote_apply(Node, orber_test_lib,
- install_test_data,
- [pseudo])),
-
- NSR = ?match({'IOP_IOR',"IDL:omg.org/CosNaming/NamingContextExt:1.0",_},
- corba:string_to_object("corbaloc::1.1@"++Host++":"++
- integer_to_list(Port)++"/NameService")),
- Obj =
- ?match({'IOP_IOR',"IDL:omg.org/orber_test/server:1.0",_},
- 'CosNaming_NamingContext':resolve(NSR, lname:new(["mamba"]))),
- orber_test_lib:corba_object_tests(Obj, NSR),
-
- %% Can we even contact the object?
- ?match(ok, orber_test_server:print(Obj)),
-
- %% Invoke one blocking call followed by several invokations.
- spawn(?MODULE, pseudo_calls, [5, Obj]),
- ?match({ok, 10000}, orber_test_server:pseudo_call_delay(Obj, 10000)),
- spawn(?MODULE, pseudo_casts, [5, Obj]),
- ?match(ok, orber_test_server:pseudo_cast_delay(Obj, 10000)),
-
- %%--- Testing code and decode arguments ---
- orber_test_lib:test_coding(Obj),
-
- %% Test if exit is handled properly.
- ?match({'EXCEPTION',{'TRANSIENT',_,_,_}},
- orber_test_server:stop_brutal(Obj)),
-
- ?match(ok, orber_test_lib:remote_apply(Node, orber_test_lib,
- uninstall_test_data,
- [pseudo])),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% API tests for ORB to ORB with local flags definition set.
-%%-----------------------------------------------------------------
-%% MULTI ORB PSEUDO with local flags definition set
-flags_added_api(_Config) ->
- %% --- Create a slave-node ---
- IP = orber_test_lib:get_host(),
- {ok, Node, _Host} =
- ?match({ok,_,_}, orber_test_lib:js_node([])),
- Port = 1 + orber_test_lib:remote_apply(Node, orber, iiop_port, []),
- ?match({ok, _},
- orber_test_lib:remote_apply(Node, orber,
- add_listen_interface,
- [IP, normal,
- [{flags, (?ORB_ENV_LOCAL_INTERFACE bor
- ?ORB_ENV_EXCLUDE_CODESET_COMPONENT)},
- {iiop_port, Port}]])),
-
- ?match(ok, orber_test_lib:remote_apply(Node, orber_test_lib,
- install_test_data,
- [pseudo])),
- Obj = ?match({'IOP_IOR',"IDL:omg.org/orber_test/server:1.0",_},
- corba:string_to_object("corbaname::1.1@"++IP++":"++
- integer_to_list(Port)++"/NameService#mamba")),
- ?match({'external', {IP, Port, _ObjectKey, _Counter,
- #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP,
- profile_data=
- #'IIOP_ProfileBody_1_1'{components=[]}},
- _NewHD}},
- iop_ior:get_key(Obj)),
- ?match(ok, orber_test_lib:remote_apply(Node, orber_test_lib,
- uninstall_test_data,
- [pseudo])),
-
- ok.
-
-
-
-%%-----------------------------------------------------------------
-%% API tests for ORB to ORB with limited concurrent requests
-%%-----------------------------------------------------------------
-%% MULTI ORB PSEUDO with limited concurrent requests tests
-max_requests_api(_Config) ->
- %% --- Create a slave-node ---
- {ok, Node, Host} =
- ?match({ok,_,_}, orber_test_lib:js_node([{iiop_max_in_requests, 1}])),
- Port = orber_test_lib:remote_apply(Node, orber, iiop_port, []),
- max_requests(Node, Host, Port).
-
-%% MULTI ORB PSEUDO with limited concurrent requests tests
-max_requests_added_api(_Config) ->
- %% --- Create a slave-node ---
- [IP] = ?match([_], orber:host()),
- {ok, Node, _Host} =
- ?match({ok,_,_}, orber_test_lib:js_node([])),
- Port = 1 + orber_test_lib:remote_apply(Node, orber, iiop_port, []),
- ?match({ok, _},
- orber_test_lib:remote_apply(Node, orber,
- add_listen_interface,
- [IP, normal,
- [{iiop_max_in_requests, 1},
- {flags, ?ORB_ENV_LOCAL_INTERFACE},
- {iiop_port, Port}]])),
- max_requests(Node, IP, Port).
-
-max_requests(Node, Host, Port) ->
- ?match(ok, orber_test_lib:remote_apply(Node, orber_test_lib,
- install_test_data,
- [pseudo])),
- Obj = ?match({'IOP_IOR',"IDL:omg.org/orber_test/server:1.0",_},
- corba:string_to_object("corbaname::1.1@"++Host++":"++
- integer_to_list(Port)++"/NameService#mamba")),
-
- %% Can we even contact the object?
- ?match(ok, orber_test_server:print(Obj)),
-
- %% Invoke one blocking call followed by several invokations.
- spawn(orber_test_server, pseudo_call_delay, [Obj, 15000]),
- %% Wait for a second to be sure that the previous request has been sent
- timer:sleep(1000),
- {MegaSecsB, Before, _} = erlang:timestamp(),
- pseudo_calls(5, Obj),
- {MegaSecsA, After, _} = erlang:timestamp(),
- %% Normally we we can perform hundreds of pseudo-calls per second. Hence,
- %% if we add 8 seconds to 'Before' it should still be less since we only
- %% allow one request at a time to the target ORB.
- ?match(true, (MegaSecsB + (Before+8)*1000000) < (MegaSecsA + After*1000000)),
-
- ?match(ok, orber_test_lib:remote_apply(Node, orber_test_lib,
- uninstall_test_data,
- [pseudo])),
-
- ok.
-
-%%-----------------------------------------------------------------
-%% API tests for ORB to ORB with limited concurrent connections
-%%-----------------------------------------------------------------
-%% MULTI ORB PSEUDO with limited concurrent connections tests
-max_connections_api(_Config) ->
- %% --- Create a slave-node ---
- {ok, ServerNode, ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{iiop_backlog, 0},
- {iiop_max_in_connections, 2}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- ?match(ok, orber_test_lib:remote_apply(ServerNode, orber_test_lib,
- install_test_data,
- [nameservice])),
-
- %% Claim connection 1 & 2
- Obj = ?match({'IOP_IOR',"IDL:omg.org/orber_test/server:1.0",_},
- corba:string_to_object("corbaname::1.2@"++ServerHost++":"++
- integer_to_list(ServerPort)++"/NameService#mamba")),
- %% Claim backlog
- {ok, ClientNode, _ClientHost} =
- ?match({ok,_,_}, orber_test_lib:js_node()),
-
- spawn(ClientNode, orber_test_server, print, [Obj]),
- timer:sleep(5000),
- ?match([_], orber_test_lib:remote_apply(ClientNode, orber,
- iiop_connections, [])),
-
- %% Try to connect. Should fail. Due to the behavior of different TCP stacks, backlog 1
- %% might not be the precise value. Hence, we also need to define the iiop_timeout. Otherwise
- %% this test case will fail. For the same reason we must GC this connection.
- {ok, ClientNodeII, _ClientHostII} =
- ?match({ok,_,_}, orber_test_lib:js_node([{iiop_setup_connection_timeout, 5},
- {iiop_timeout, 5},
- {iiop_connection_timeout, 8}])),
-
- ?match({'EXCEPTION', _},
- orber_test_lib:remote_apply(ClientNodeII, orber_test_server,
- testing_iiop_string, [Obj, "Fail"])),
-
- %% Remove 2 connections. We need to wait a moment so that both sides has detected it.
- timer:sleep(5000),
- ?match([_,_], orber:iiop_connections()),
- ?match(ok, orber_iiop_pm:close_connection([{ServerHost, ServerPort}])),
- timer:sleep(5000),
- [{Host, Port}] = ?match([_], orber:iiop_connections()),
- ?match(ok, orber_iiop_pm:close_connection([{Host, Port}])),
- timer:sleep(5000),
- ?match([], orber:iiop_connections()),
-
- ?match([_], orber_test_lib:remote_apply(ClientNode, orber,
- iiop_connections, [])),
-
- ?match([], orber_test_lib:remote_apply(ClientNodeII, orber,
- iiop_connections, [])),
-
- ?match({ok, "OK"},
- orber_test_lib:remote_apply(ClientNodeII, orber_test_server,
- testing_iiop_string, [Obj, "OK"])),
-
- timer:sleep(4000),
- ?match([_], orber_test_lib:remote_apply(ClientNodeII, orber,
- iiop_connections, [])),
-
- ?match(ok, orber_test_lib:remote_apply(ServerNode, orber_test_lib,
- uninstall_test_data,
- [pseudo])),
-
- ok.
-
-
-%%-----------------------------------------------------------------
-%% API tests for terminating connection by using an IOR.
-%%-----------------------------------------------------------------
-%% Close outgoing connection
-close_connections_api(_Config) ->
- %% --- Create a slave-node ---
- IP = orber_test_lib:get_host(),
- Loopback = orber_test_lib:get_loopback_interface(),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{ip_address, IP}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- ?match(ok, orber_test_lib:remote_apply(ServerNode, orber_test_lib,
- install_test_data,
- [nameservice])),
- orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- IP = orber_test_lib:get_host(),
-
- %% Create a connection
- Obj = ?match({'IOP_IOR',"IDL:omg.org/orber_test/server:1.0",_},
- corba:string_to_object("corbaname::1.2@"++IP++":"++
- integer_to_list(ServerPort)++"/NameService#mamba")),
- %% Check that it's up.
- ?match([{IP, ServerPort}], orber:iiop_connections(out)),
- %% Try to close using the wronge interface.
- ?match(ok, orber:close_connection(Obj, Loopback)),
- %% Should still be up.
- ?match([{IP, ServerPort}], orber:iiop_connections(out)),
- %% Try to close it properly
- ?match(ok, orber:close_connection(Obj)),
- %% Wait a moment so that both sides has detected it.
- timer:sleep(5000),
- %% Worked?
- ?match([], orber:iiop_connections(out)),
- ok.
-
-
-%% IIOP Local Interface disconnect tests
-%% This case test if the server ORB use the correct
-%% local interface when connecting to another ORB
-close_connections_local_interface_api(_Config) ->
- IP = orber_test_lib:get_host(),
- Loopback = orber_test_lib:get_loopback_interface(),
- {ok, ClientNode, _ClientHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{ip_address_local, Loopback}])),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{ip_address, IP}])),
- Port = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- IOR = ?match(#'IOP_IOR'{},
- orber_test_lib:remote_apply(ClientNode, corba, string_to_object,
- ["corbaloc::1.2@"++IP++":"++integer_to_list(Port)++"/NameService"])),
-
- %% Check that the connnection is up and running using the default interface
- ?match([{Loopback,_RemotePort}], orber_test_lib:remote_apply(ServerNode, orber,
- iiop_connections, [in])),
- ?match([{IP, Port}],
- orber_test_lib:remote_apply(ClientNode, orber,
- iiop_connections, [out])),
- %% Try to close the connection
- ?match(ok, orber_test_lib:remote_apply(ClientNode, orber,
- close_connection, [IOR])),
- %% Wait a moment so that both sides has detected it.
- timer:sleep(5000),
- %% Now the connection shall be gone.
- ?match([], orber_test_lib:remote_apply(ClientNode, orber,
- iiop_connections, [out])),
- ?match([], orber_test_lib:remote_apply(ServerNode, orber,
- iiop_connections, [in])),
-
- ok.
-
-%% IIOP Local Interface disconnect tests
-%% This case test if the server ORB use the correct
-%% local interface when connecting to another ORB
-close_connections_local_interface_ctx_override_api(_Config) ->
- IP = orber_test_lib:get_host(),
- Loopback = orber_test_lib:get_loopback_interface(),
- {ok, ClientNode, _ClientHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{ip_address_local, IP},
- {ip_address, IP}])),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{ip_address, IP}])),
- Port = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- IOR = ?match(#'IOP_IOR'{},
- orber_test_lib:remote_apply(ClientNode, corba, string_to_object,
- ["corbaloc::1.2@"++IP++":"++integer_to_list(Port)++"/NameService",
- [#'IOP_ServiceContext'
- {context_id=?ORBER_GENERIC_CTX_ID,
- context_data = {interface, Loopback}}]])),
-
- timer:sleep(2000),
- %% Check that the connnection is up and running using the default interface
- ?match([{Loopback,_RemotePort}], orber_test_lib:remote_apply(ServerNode, orber,
- iiop_connections, [in])),
-
- ?match([{IP, Port, Loopback}],
- orber_test_lib:remote_apply(ClientNode, orber,
- iiop_connections, [out])),
- %% Try to close not supplying the interface.
- ?match(ok, orber_test_lib:remote_apply(ClientNode, orber,
- close_connection, [IOR])),
-
- timer:sleep(2000),
- %% The connection shall still be up and running
- ?match([{Loopback,_RemotePort}], orber_test_lib:remote_apply(ServerNode, orber,
- iiop_connections, [in])),
- ?match([{IP, Port, Loopback}],
- orber_test_lib:remote_apply(ClientNode, orber,
- iiop_connections, [out])),
- %% Try to close not supplying the interface.
- ?match(ok, orber_test_lib:remote_apply(ClientNode, orber,
- close_connection, [IOR, IP])),
-
- timer:sleep(2000),
- %% The connection shall still be up and running
- ?match([{Loopback,_RemotePort}], orber_test_lib:remote_apply(ServerNode, orber,
- iiop_connections, [in])),
- ?match([{IP, Port, Loopback}],
- orber_test_lib:remote_apply(ClientNode, orber,
- iiop_connections, [out])),
-
- %% Try to close supplying the correct interface.
- ?match(ok, orber_test_lib:remote_apply(ClientNode, orber,
- close_connection, [IOR, Loopback])),
- %% Wait a moment so that both sides has detected it.
- timer:sleep(5000),
- %% Now the connection shall be gone.
- ?match([], orber_test_lib:remote_apply(ServerNode, orber,
- iiop_connections, [in])),
- ?match([], orber_test_lib:remote_apply(ClientNode, orber,
- iiop_connections, [out])),
- ok.
-
-%% IIOP alternate address disconnect tests
-%% This case test if the server ORB use the correct
-%% local interface when connecting to another ORB
-close_connections_alt_iiop_addr_api(_Config) ->
- %% --- Create a slave-node ---
- Loopback = orber_test_lib:get_loopback_interface(),
- IP = orber_test_lib:get_host(),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{giop_version, {1, 2}},
- {ip_address, {multiple, [IP, Loopback]}}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- ?match(ok, orber_test_lib:remote_apply(ServerNode, orber_test_lib,
- install_test_data,
- [{nameservice, Loopback, ServerPort}])),
- %% Create two connections
- Obj = ?match({'IOP_IOR',"IDL:omg.org/orber_test/server:1.0",_},
- corba:string_to_object("corbaname::1.2@"++IP++":"++
- integer_to_list(ServerPort)++"/NameService#mamba")),
- ?match({'IOP_IOR',"IDL:omg.org/orber_test/server:1.0",_},
- corba:string_to_object("corbaname::1.2@"++Loopback++":"++
- integer_to_list(ServerPort)++"/NameService#mamba")),
- timer:sleep(2000),
- %% The connection shall still be up and running
- ?match([{_,_}, {_,_}], orber:iiop_connections(out)),
- ?match([{_,_}, {_,_}],
- orber_test_lib:remote_apply(ServerNode, orber,
- iiop_connections, [in])),
-
- %% Try to close the connection
- ?match(ok, orber:close_connection(Obj)),
- %% Wait a moment so that both sides has detected it.
- timer:sleep(5000),
- %% Now the connections shall be gone.
- ?match([], orber:iiop_connections(out)),
- ?match([], orber_test_lib:remote_apply(ServerNode, orber,
- iiop_connections, [in])),
- ok.
-
-%% IIOP alternate address disconnect tests
-%% This case test if the server ORB use the correct
-%% local interface when connecting to another ORB
-close_connections_multiple_profiles_api(_Config) ->
- IP = orber_test_lib:get_host(),
- Loopback = orber_test_lib:get_loopback_interface(),
- %% --- Create a slave-node ---
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{ip_address,
- {multiple, [Loopback, IP]}}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- ?match(ok, orber_test_lib:remote_apply(ServerNode, orber_test_lib,
- install_test_data, [nameservice])),
- %% Create two connections
- Obj = ?match({'IOP_IOR',"IDL:omg.org/orber_test/server:1.0",_},
- corba:string_to_object("corbaname::1.2@"++IP++":"++
- integer_to_list(ServerPort)++"/NameService#mamba")),
- ?match({'IOP_IOR',"IDL:omg.org/orber_test/server:1.0",_},
- corba:string_to_object("corbaname::1.2@"++Loopback++":"++
- integer_to_list(ServerPort)++"/NameService#mamba")),
- %% The connection shall still be up and running
- ?match([{_,_}, {_,_}], orber:iiop_connections(out)),
- ?match([{_,_}, {_,_}],
- orber_test_lib:remote_apply(ServerNode, orber,
- iiop_connections, [in])),
-
- %% Try to close the connection
- ?match(ok, orber:close_connection(Obj)),
- %% Wait a moment so that both sides has detected it.
- timer:sleep(5000),
- %% Now the connections shall be gone.
- ?match([], orber:iiop_connections(out)),
- ?match([], orber_test_lib:remote_apply(ServerNode, orber,
- iiop_connections, [in])),
- ok.
-
-%%-----------------------------------------------------------------
-%% API tests for ORB to ORB with iiop_packet_size set
-%%-----------------------------------------------------------------
-%% Exceed the maximum request size
-max_packet_size_exceeded_api(_Config) ->
- case catch gen_tcp:listen(0, [{packet,cdr}, {packet_size, 14}]) of
- {'EXIT',badarg} ->
- {skipped, "The inet option {packet_size, Max} not supported"};
- {ok, LS} ->
- (catch gen_tcp:close(LS)),
- %% --- Create a slave-node ---
- {ok, ServerNode, ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{iiop_packet_size, 1}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber,
- iiop_port, []),
- ?match({'EXCEPTION', #'CosNaming_NamingContextExt_InvalidAddress'{}},
- corba:string_to_object("corbaloc::1.2@"++ServerHost++":"++integer_to_list(ServerPort)++"/NameService")),
- ok
- end.
-
-%%-----------------------------------------------------------------
-%% API tests for ORB to ORB with iiop_packet_size set
-%%-----------------------------------------------------------------
-%% Not exceed the maximum request size
-max_packet_size_ok_api(_Config) ->
- case catch gen_tcp:listen(0, [{packet,cdr}, {packet_size, 14}]) of
- {'EXIT',badarg} ->
- {skipped, "The inet option {packet_size, Max} not supported"};
- {ok, LS} ->
- (catch gen_tcp:close(LS)),
- %% --- Create a slave-node ---
- {ok, ServerNode, ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{iiop_packet_size, 5000}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber,
- iiop_port, []),
- ?match({'IOP_IOR',_,_},
- corba:string_to_object("corbaloc::1.2@"++ServerHost++":"++integer_to_list(ServerPort)++"/NameService")),
- ok
- end.
-
-
-
-%%-----------------------------------------------------------------
-%% API tests for ORB to ORB, no security
-%%-----------------------------------------------------------------
-%% LIGHT IFR ORB API tests
-light_ifr_api(_Config) ->
-
- {ok, ClientNode, _ClientHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, 128}])),
-
- ?match([_,_,_,_], orber_test_lib:remote_apply(ClientNode, orber, get_tables, [])),
- ?match(ok, orber_test_lib:remote_apply(ClientNode, orber_test_lib,
- install_test_data,
- [nameservice])),
-
-
- {ok, ServerNode, ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, 128}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- ?match(ok, orber_test_lib:remote_apply(ServerNode, orber_test_lib,
- install_test_data,
- [nameservice])),
- ?match([_,_,_,_], orber_test_lib:remote_apply(ServerNode, orber, get_tables, [])),
-
- Obj = ?match({'IOP_IOR',_,_},
- corba:string_to_object("corbaname::1.2@"++ServerHost++":"++integer_to_list(ServerPort)++"/NameService#mamba")),
- ?match(ok, orber_test_lib:remote_apply(ClientNode, orber_test_lib, test_coding, [Obj])),
-
- ?match(0, orber_test_lib:remote_apply(ClientNode, orber_diagnostics, missing_modules, [])),
-
- ?match(ok, orber_test_lib:remote_apply(ClientNode, mnesia, dirty_write,
- [#orber_light_ifr{id = "FakeId1",
- module=non_existing,
- type=?IFR_StructDef}])),
- ?match(ok, orber_test_lib:remote_apply(ClientNode, mnesia, dirty_write,
- [#orber_light_ifr{id = "FakeId2",
- module=non_existing,
- type=?IFR_UnionDef}])),
- ?match(ok, orber_test_lib:remote_apply(ClientNode, mnesia, dirty_write,
- [#orber_light_ifr{id = "FakeId3",
- module=non_existing,
- type=?IFR_ExceptionDef}])),
- ?match(ok, orber_test_lib:remote_apply(ClientNode, mnesia, dirty_write,
- [#orber_light_ifr{id = "FakeId4",
- module=non_existing,
- type=?IFR_InterfaceDef}])),
- ?match(ok, orber_test_lib:remote_apply(ClientNode, mnesia, dirty_write,
- [#orber_light_ifr{id = "FakeId5",
- module=orber_test_lib,
- type=?IFR_InterfaceDef}])),
- ?match(5, orber_test_lib:remote_apply(ClientNode, orber_diagnostics, missing_modules, [])),
-
-
- ?match(ok, mnesia:dirty_write(#ir_UnionDef{ir_Internal_ID = "FakedIId1",
- absolute_name="::Module::NonExisting"})),
- ?match(ok, mnesia:dirty_write(#ir_StructDef{ir_Internal_ID = "FakedIId2",
- absolute_name="::Module::NonExisting"})),
- ?match(ok, mnesia:dirty_write(#ir_ExceptionDef{ir_Internal_ID = "FakedIId3",
- absolute_name="::Module::NonExisting"})),
- ?match(ok, mnesia:dirty_write(#ir_InterfaceDef{ir_Internal_ID = "FakedIId4",
- absolute_name="::Module::NonExisting"})),
- ?match(ok, mnesia:dirty_write(#ir_InterfaceDef{ir_Internal_ID = "FakedIId5",
- absolute_name="::orber::test::lib"})),
-
- ?match(5, orber_diagnostics:missing_modules()),
-
- ?match(ok, orber_test_lib:remote_apply(ServerNode, orber_test_lib,
- uninstall_test_data,
- [nameservice])),
- ?match(ok, orber_test_lib:remote_apply(ClientNode, orber_test_lib,
- uninstall_test_data,
- [nameservice])),
- ok.
-
-%%-----------------------------------------------------------------
-%% API tests for ORB to ORB, no security
-%%-----------------------------------------------------------------
-%% LIGHT ORB API tests
-%% This case test if a light Orber can communicate correctly
-%% with an fully installed Orber.
-light_orber_api(_Config) ->
- %% --- Create a slave-node ---
- LocalHost = net_adm:localhost(),
- {ok, Node, _Host} =
- ?match({ok,_,_}, orber_test_lib:js_node([{lightweight, ["iiop://"++LocalHost++":"++integer_to_list(orber:iiop_port())]}],
- lightweight)),
- ?match(ok, orber:info(io)),
- ?match([_], orber_test_lib:remote_apply(Node, orber_env, get_lightweight_nodes,[])),
-
- ?match(ok, orber_test_lib:remote_apply(Node, orber_test_lib,
- install_test_data,
- [light])),
-
- Obj1=(catch orber_test_server:oe_create(state,[{pseudo,true}])),
- ?match({_,pseudo,orber_test_server_impl, _,_, _}, Obj1),
- Obj2=(catch orber_test_server:oe_create(state,[])),
- ?match({_,key,_, _,_, _}, Obj2),
-
- NS = corba:resolve_initial_references("NameService"),
- 'CosNaming_NamingContext':bind(NS, lname:new(["mamba"]), Obj1),
- 'CosNaming_NamingContext':bind(NS, lname:new(["viper"]), Obj2),
-
- ?match(ok, orber_test_lib:remote_apply(Node, orber_test_lib,
- light_tests,
- [LocalHost,
- orber:iiop_port(), "viper"])),
- ?match(ok, orber_test_lib:remote_apply(Node, orber_test_lib,
- light_tests,
- [LocalHost,
- orber:iiop_port(), "mamba"])),
-
- %% Clean up.
-
- catch corba:dispose(Obj1),
- catch corba:dispose(Obj2),
- catch 'CosNaming_NamingContext':destroy(NS),
-
- ?match(ok, orber_test_lib:remote_apply(Node, orber_test_lib,
- uninstall_test_data,
- [light])),
- ok.
-%%-----------------------------------------------------------------
-%% API tests for ORB to ORB, no security
-%%-----------------------------------------------------------------
-%% LIGHT ORB API tests
-%% This case test if a light Orber can communicate correctly
-%% with an fully installed Orber. This case test if we can
-%% start as lightweight without first setting the environment
-%% variable
-light_orber2_api(_Config) ->
- %% --- Create a slave-node ---
- LocalHost = net_adm:localhost(),
- {ok, Node, _Host} =
- ?match({ok,_,_}, orber_test_lib:js_node([],
- {lightweight, ["iiop://"++LocalHost++":"++integer_to_list(orber:iiop_port())]})),
- ?match(ok, orber:info(io)),
- ?match([_], orber_test_lib:remote_apply(Node, orber_env, get_lightweight_nodes,[])),
-
- ?match(ok, orber_test_lib:remote_apply(Node, orber_test_lib,
- install_test_data,
- [light])),
-
- Obj1=(catch orber_test_server:oe_create(state,[{pseudo,true}])),
- ?match({_,pseudo,orber_test_server_impl, _,_, _}, Obj1),
- Obj2=(catch orber_test_server:oe_create(state,[])),
- ?match({_,key,_, _,_, _}, Obj2),
-
- NS = corba:resolve_initial_references("NameService"),
- 'CosNaming_NamingContext':bind(NS, lname:new(["mamba"]), Obj1),
- 'CosNaming_NamingContext':bind(NS, lname:new(["viper"]), Obj2),
-
- ?match(ok, orber_test_lib:remote_apply(Node, orber_test_lib,
- light_tests,
- [LocalHost,
- orber:iiop_port(), "viper"])),
- ?match(ok, orber_test_lib:remote_apply(Node, orber_test_lib,
- light_tests,
- [LocalHost,
- orber:iiop_port(), "mamba"])),
-
- %% Clean up.
-
- catch corba:dispose(Obj1),
- catch corba:dispose(Obj2),
- catch 'CosNaming_NamingContext':destroy(NS),
-
- ?match(ok, orber_test_lib:remote_apply(Node, orber_test_lib,
- uninstall_test_data,
- [light])),
- ok.
-
-%%-----------------------------------------------------------------
-%% API tests for ORB to ORB, no security
-%%-----------------------------------------------------------------
-%% MULTI ORB API tests
-%% This case test if data encode/decode (IIOP)
-%% produce the correct result, i.e., the test_server echos
-%% the input parameter or an exception is raised (MARSHAL).
-multi_orber_api(_Config) ->
-
- NewICObj1 = ?match({_,_,_,_,_,_}, orber_test_server:oe_create([])),
- NewICObj2 = ?match({_,_,_,_,_,_}, orber_test_server:oe_create([], [{regname, {local, newic2}}])),
- NewICObj3 = ?match({_,_,_,_,_,_}, orber_test_server:oe_create([], [{regname, {global, newic3}}])),
- ?match(ok, orber_test_server:print(NewICObj1)),
- ?match(ok, orber_test_server:print(NewICObj2)),
- ?match(ok, orber_test_server:print(NewICObj3)),
- catch corba:dispose(NewICObj1),
- catch corba:dispose(NewICObj2),
- catch corba:dispose(NewICObj3),
-
- %% --- Create a slave-node ---
- {ok, Node, Host} =
- ?match({ok,_,_}, orber_test_lib:js_node()),
- Port = orber_test_lib:remote_apply(Node, orber, iiop_port, []),
-
- ?match(ok, orber_test_lib:remote_apply(Node, orber_test_lib,
- install_test_data,
- [nameservice])),
-
- NSR = ?match({'IOP_IOR',"IDL:omg.org/CosNaming/NamingContextExt:1.0",_},
- corba:string_to_object("corbaloc::1.2@"++Host++":"++
- integer_to_list(Port)++"/NameService")),
-
- ?match({'EXCEPTION',{'CosNaming_NamingContext_NotFound',_,_,_}},
- 'CosNaming_NamingContext':resolve(NSR, lname:new(["not_exist"]))),
-
- Obj = ?match({'IOP_IOR',"IDL:omg.org/orber_test/server:1.0",_},
- 'CosNaming_NamingContext':resolve(NSR, lname:new(["mamba"]))),
- ?match(ok, orber_test_server:print(Obj)),
-
- Obj12B = ?match({'IOP_IOR',_,_},
- corba:string_to_object("corbaloc::1.2@"++Host++":"++integer_to_list(Port)++"/Mamba")),
-
- Obj11B = ?match({'IOP_IOR',_,_},
- corba:string_to_object("corbaloc::1.1@"++Host++":"++integer_to_list(Port)++"/Mamba")),
-
- Obj10B = ?match({'IOP_IOR',_,_},
- corba:string_to_object("corbaloc::1.0@"++Host++":"++integer_to_list(Port)++"/Mamba")),
-
- context_test(Obj12B),
- context_test(Obj11B),
-
- ?match(ok, orber_test_server:print(Obj12B)),
- ?match(ok, orber_test_server:print(Obj11B)),
- ?match(ok, orber_test_server:print(Obj10B)),
- ?match({'EXCEPTION',{'CosNaming_NamingContextExt_InvalidAddress',_}},
- corba:string_to_object("corbaloc::1.0@"++Host++":"++integer_to_list(Port)++"/Wrong")),
-
- ?match(ok, orber_test_lib:corba_object_tests(Obj12B, NSR)),
- ?match(ok, orber_test_lib:corba_object_tests(Obj11B, NSR)),
- ?match(ok, orber_test_lib:corba_object_tests(Obj10B, NSR)),
-
- %%--- Testing code and decode arguments ---
- orber_test_lib:test_coding(Obj),
-
- ?match({'EXCEPTION',#'BAD_CONTEXT'{}},
- orber_test_server:
- print(Obj12B,
- [{context,
- [#'IOP_ServiceContext'{context_id=?ORBER_GENERIC_CTX_ID,
- context_data = {interface,
- {127,0,0,1}}}]}])),
-
- ?match({'EXCEPTION',{'TRANSIENT',_,_,_}},
- orber_test_server:stop_brutal(Obj12B)),
- ?match({'EXCEPTION',{'TRANSIENT',_,_,_}},
- orber_test_server:print(Obj12B)),
-
- ?match(ok, orber_test_lib:remote_apply(Node, orber_test_lib,
- uninstall_test_data,
- [nameservice])),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% API tests for ORB to ORB, no security, using basic interceptors
-%%-----------------------------------------------------------------
-%% MULTI ORB API tests
-%% This case test if data encode/decode (IIOP)
-%% produce the correct result when using basic interceptors
-%% i.e., the test_server echos the input parameter or
-%% an exception is raised (MARSHAL).
-basic_PI_api(_Config) ->
- %% Change configuration to use Basic Interceptors.
- orber:configure_override(interceptors, {native, [orber_test_lib]}),
- %% --- Create a slave-node ---
- {ok, Node, Host} =
- ?match({ok,_,_}, orber_test_lib:js_node([{interceptors, {native, [orber_test_lib]}}])),
- Port = orber_test_lib:remote_apply(Node, orber, iiop_port, []),
-
- ?match(ok, orber_test_lib:remote_apply(Node, orber_test_lib,
- install_test_data,
- [nameservice])),
-
- Obj12 = ?match({'IOP_IOR',"IDL:omg.org/orber_test/server:1.0",_},
- corba:string_to_object("corbaname::1.2@"++Host++":"++integer_to_list(Port)++"/NameService#mamba")),
-
- Obj11 = ?match({'IOP_IOR',"IDL:omg.org/orber_test/server:1.0",_},
- corba:string_to_object("corbaname::1.1@"++Host++":"++integer_to_list(Port)++"/NameService#mamba")),
-
- Obj10 = ?match({'IOP_IOR',"IDL:omg.org/orber_test/server:1.0",_},
- corba:string_to_object("corbaname::1.0@"++Host++":"++integer_to_list(Port)++"/NameService#mamba")),
-
- ?match(ok, corba:print_object(Obj12)),
- ?match(ok, corba:print_object(Obj11, error_report)),
- ?match(ok, corba:print_object(Obj10, {error_report, "Reason"})),
-
- ?match(ok, orber_test_server:print(Obj12)),
- ?match(ok, orber_test_server:print(Obj11)),
- ?match(ok, orber_test_server:print(Obj10)),
-
-
- Obj12B = ?match({'IOP_IOR',_,_},
- corba:string_to_object("corbaloc::1.2@"++Host++":"++integer_to_list(Port)++"/Mamba")),
-
- Obj11B = ?match({'IOP_IOR',_,_},
- corba:string_to_object("corbaloc::1.1@"++Host++":"++integer_to_list(Port)++"/Mamba")),
-
- Obj10B = ?match({'IOP_IOR',_,_},
- corba:string_to_object("corbaloc::1.0@"++Host++":"++integer_to_list(Port)++"/Mamba")),
-
- ?match(ok, corba:print_object(Obj12B, info_msg)),
- ?match(ok, corba:print_object(Obj11B, {info_msg, "Comment"})),
- ?match([_|_], corba:print_object(Obj10B, string)),
-
- ?match(ok, orber_test_server:print(Obj12B)),
- ?match(ok, orber_test_server:print(Obj11B)),
- ?match(ok, orber_test_server:print(Obj10B)),
- ?match({'EXCEPTION',{'CosNaming_NamingContextExt_InvalidAddress',_}},
- corba:string_to_object("corbaloc::1.0@"++Host++":"++integer_to_list(Port)++"/Wrong")),
-
- ?match(ok, orber_test_lib:alternate_iiop_address(Host, Port)),
-
- context_test(Obj12B),
- context_test(Obj11B),
-
- %%--- Testing code and decode arguments ---
- orber_test_lib:test_coding(Obj12),
- orber_test_lib:test_coding(Obj11),
- orber_test_lib:test_coding(Obj10),
-
- application:set_env(orber, interceptors, false),
-
- ?match(ok, orber_test_lib:remote_apply(Node, orber_test_lib,
- uninstall_test_data,
- [nameservice])),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% API tests for ORB to ORB, ssl security depth 1
-%%-----------------------------------------------------------------
-
-%% 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_api(_Config) ->
- ServerOptions = orber_test_lib:get_options_old(iiop_ssl, server,
- 1, [{iiop_ssl_port, 0}]),
- ClientOptions = orber_test_lib:get_options_old(iiop_ssl, client,
- 1, [{iiop_ssl_port, 0}]),
- ssl_suite(ServerOptions, ClientOptions).
-
-
-%% 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(_Config) ->
-
- ServerOptions = orber_test_lib:get_options(iiop_ssl, server,
- 1, [{ssl_generation, 3},
- {iiop_ssl_port, 0}]),
- ClientOptions = orber_test_lib:get_options(iiop_ssl, client,
- 1, [{ssl_generation, 3},
- {iiop_ssl_port, 0}]),
- ssl_suite(ServerOptions, ClientOptions).
-
-%%-----------------------------------------------------------------
-%% API tests for ORB to ORB, ssl security depth 2
-%%-----------------------------------------------------------------
-
-%% SECURE MULTI ORB API tests (SSL depth 2)
-%% These case set up two secure orbs and test if they can
-%% communicate. They also test to access one of the
-%% secure orbs which must raise a NO_PERMISSION exception.
-ssl_2_multi_orber_api(_Config) ->
-
- ServerOptions = orber_test_lib:get_options_old(iiop_ssl, server,
- 2, [{iiop_ssl_port, 0}]),
- ClientOptions = orber_test_lib:get_options_old(iiop_ssl, client,
- 2, [{iiop_ssl_port, 0}]),
- ssl_suite(ServerOptions, ClientOptions).
-
-ssl_2_multi_orber_generation_3_api(_Config) ->
-
- ServerOptions = orber_test_lib:get_options(iiop_ssl, server,
- 2, [{ssl_generation, 3},
- {iiop_ssl_port, 0}]),
- ClientOptions = orber_test_lib:get_options(iiop_ssl, client,
- 2, [{ssl_generation, 3},
- {iiop_ssl_port, 0}]),
- ssl_suite(ServerOptions, ClientOptions).
-%%-----------------------------------------------------------------
-%% API tests for ORB to ORB, ssl security depth 2
-%%-----------------------------------------------------------------
-
-%% SECURE MULTI ORB API tests (SSL depth 2)
-%% These case set up two secure orbs and test if they can
-%% communicate. They also test to access one of the
-%% secure orbs which must raise a NO_PERMISSION exception.
-ssl_reconfigure_api(_Config) ->
- ssl_reconfigure_old([]).
-
-
-% ssl_reconfigure_generation_3_api_old(_Config) ->
-% ssl_reconfigure_old([{ssl_generation, 3}]).
-
-ssl_reconfigure_old(ExtraSSLOptions) ->
-
- IP = orber_test_lib:get_host(),
- Loopback = orber_test_lib:get_loopback_interface(),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_},
- orber_test_lib:js_node([{iiop_port, 0},
- {flags, ?ORB_ENV_LOCAL_INTERFACE},
- {ip_address, IP}|ExtraSSLOptions])),
- orber_test_lib:remote_apply(ServerNode, ssl, start, []),
- orber_test_lib:remote_apply(ServerNode, crypto, start, []),
- ?match(ok, orber_test_lib:remote_apply(ServerNode, orber_test_lib,
- install_test_data,
- [ssl])),
- ?match({ok, _},
- orber_test_lib:remote_apply(ServerNode, orber,
- add_listen_interface,
- [Loopback, normal, [{iiop_port, 5648},
- {iiop_ssl_port, 5649},
- {interceptors, {native, [orber_iiop_tracer_silent]}}|ExtraSSLOptions]])),
- ServerOptions = orber_test_lib:get_options_old(iiop_ssl, server,
- 2, [{flags, ?ORB_ENV_LOCAL_INTERFACE},
- {iiop_port, 5648},
- {iiop_ssl_port, 5649},
- {interceptors, {native, [orber_iiop_tracer_silent]}}|ExtraSSLOptions]),
- ?match({ok, _},
- orber_test_lib:remote_apply(ServerNode, orber,
- add_listen_interface,
- [Loopback, ssl, ServerOptions])),
-
- ClientOptions = orber_test_lib:get_options_old(iiop_ssl, client,
- 2, [{iiop_ssl_port, 0}|ExtraSSLOptions]),
- {ok, ClientNode, _ClientHost} =
- ?match({ok,_,_}, orber_test_lib:js_node(ClientOptions)),
-
- ?match(ok, orber_test_lib:remote_apply(ClientNode, orber_test_lib,
- install_test_data,
- [ssl])),
- orber_test_lib:remote_apply(ClientNode, ssl, start, []),
- orber_test_lib:remote_apply(ServerNode, crypto, start, []),
- Obj = ?match(#'IOP_IOR'{},
- orber_test_lib:remote_apply(ClientNode, corba,
- string_to_object, ["corbaname:iiop:1.1@"++Loopback++":5648/NameService#mamba",
- [{context, [#'IOP_ServiceContext'{context_id=?ORBER_GENERIC_CTX_ID,
- context_data = {configuration, ClientOptions}}]}]])),
- ?match(ok, orber_test_lib:remote_apply(ClientNode, orber_test_server,
- print, [Obj])).
-
-
-ssl_reconfigure_generation_3_api(_Config) ->
- ssl_reconfigure([{ssl_generation, 3}]).
-
-
-ssl_reconfigure(ExtraSSLOptions) ->
-
- IP = orber_test_lib:get_host(),
- Loopback = orber_test_lib:get_loopback_interface(),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_},
- orber_test_lib:js_node([{iiop_port, 0},
- {flags, ?ORB_ENV_LOCAL_INTERFACE},
- {ip_address, IP}|ExtraSSLOptions])),
- orber_test_lib:remote_apply(ServerNode, ssl, start, []),
- orber_test_lib:remote_apply(ServerNode, crypto, start, []),
- ?match(ok, orber_test_lib:remote_apply(ServerNode, orber_test_lib,
- install_test_data,
- [ssl])),
- ?match({ok, _},
- orber_test_lib:remote_apply(ServerNode, orber,
- add_listen_interface,
- [Loopback, normal, [{iiop_port, 5648},
- {iiop_ssl_port, 5649},
- {interceptors, {native, [orber_iiop_tracer_silent]}}|ExtraSSLOptions]])),
- ServerOptions = orber_test_lib:get_options(iiop_ssl, server,
- 2, [{flags, ?ORB_ENV_LOCAL_INTERFACE},
- {iiop_port, 5648},
- {iiop_ssl_port, 5649},
- {interceptors, {native, [orber_iiop_tracer_silent]}}|ExtraSSLOptions]),
- ?match({ok, _},
- orber_test_lib:remote_apply(ServerNode, orber,
- add_listen_interface,
- [Loopback, ssl, ServerOptions])),
-
- ClientOptions = orber_test_lib:get_options(iiop_ssl, client,
- 2, [{iiop_ssl_port, 0}|ExtraSSLOptions]),
- {ok, ClientNode, _ClientHost} =
- ?match({ok,_,_}, orber_test_lib:js_node(ClientOptions)),
-
- ?match(ok, orber_test_lib:remote_apply(ClientNode, orber_test_lib,
- install_test_data,
- [ssl])),
- orber_test_lib:remote_apply(ClientNode, ssl, start, []),
- orber_test_lib:remote_apply(ServerNode, crypto, start, []),
- Obj = ?match(#'IOP_IOR'{},
- orber_test_lib:remote_apply(ClientNode, corba,
- string_to_object, ["corbaname:iiop:1.1@"++Loopback++":5648/NameService#mamba",
- [{context, [#'IOP_ServiceContext'{context_id=?ORBER_GENERIC_CTX_ID,
- context_data = {configuration, ClientOptions}}]}]])),
- ?match(ok, orber_test_lib:remote_apply(ClientNode, orber_test_server,
- print, [Obj])).
-
-
-%%------------------------------------------------------------
-%% function : ssl_suite
-%% Arguments: Config
-%% Depth
-%% Returns : ok
-%% Effect :
-%%------------------------------------------------------------
-ssl_suite(ServerOptions, ClientOptions) ->
-
- {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, []),
-
- {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])),
- %% Tell the client to interoperate with the server. The purpose of this
- %% operation is to look up, using NameService, an object reference and
- %% use it to contact the object.
- ?match(ok, orber_test_lib:remote_apply(ClientNode, orber_test_lib,
- lookup,
- [ServerHost, ServerPort])),
-
- ?match(ok, orber_test_lib:remote_apply(ClientNode, orber_test_lib,
- alternate_ssl_iiop_address,
- [ServerHost, ServerPort, SSLServerPort])),
-
- %% 'This' node is not secure. Contact the server. Must refuse connection.
- NSR = ?match({'IOP_IOR',"IDL:omg.org/CosNaming/NamingContextExt:1.0",_},
- corba:string_to_object("corbaloc::1.2@"++ServerHost++":"++
- integer_to_list(ServerPort)++"/NameService")),
-
- %% Should be 'NO_PERMISSION'??
- ?match({'EXCEPTION',{'COMM_FAILURE',_,_,_}},
- 'CosNaming_NamingContext':resolve(NSR, lname:new(["not_exist"]))),
-
- %% Should be 'NO_PERMISSION'??
- ?match({'EXCEPTION',{'COMM_FAILURE',_,_,_}},
- 'CosNaming_NamingContext':resolve(NSR, lname:new(["mamba"]))),
-
- %% Uninstall.
- ?match(ok, orber_test_lib:remote_apply(ServerNode, orber_test_lib,
- uninstall_test_data,
- [ssl])),
- ok.
-
-%%-----------------------------------------------------------------
-%% iiop_setup_connection_timeout API tests for ORB to ORB.
-%%-----------------------------------------------------------------
-setup_connection_timeout_api(_Config) ->
- ?match(ok, application:set_env(orber, iiop_backlog, 0)),
- %% Wait to be sure that the configuration has kicked in.
- timer:sleep(2000),
- {ok, Ref, Port} = create_fake_server_ORB(normal, 0, [], listen, []),
- ?match(ok, orber:configure(iiop_setup_connection_timeout, 5)),
- ?match(ok, orber:info(io)),
- IP = orber_test_lib:get_host(),
- spawn(?MODULE, do_connect, [IP, Port, [{active, false}]]),
- spawn(?MODULE, do_connect, [IP, Port, [{active, false}]]),
- spawn(?MODULE, do_connect, [IP, Port, [{active, false}]]),
- spawn(?MODULE, do_connect, [IP, Port, [{active, false}]]),
- spawn(?MODULE, do_connect, [IP, Port, [{active, false}]]),
- timer:sleep(2000),
- Corbaloc = "corbaloc::1.2@"++IP++":"++integer_to_list(Port)++"/NameService",
- ?match({'EXCEPTION', _E}, corba:string_to_object(Corbaloc)),
- destroy_fake_ORB(Ref),
- ?match(ok, application:set_env(orber, iiop_backlog, 5)),
- ok.
-
-%%-----------------------------------------------------------------
-%% iiop_setup_connection_timeout API tests for ORB to ORB.
-%%-----------------------------------------------------------------
-setup_multi_connection_timeout_api(_Config) ->
- ?match(ok, application:set_env(orber, iiop_backlog, 0)),
- %% Wait to be sure that the configuration has kicked in.
- timer:sleep(2000),
- {ok, Ref, Port} = create_fake_server_ORB(normal, 0, [], listen, []),
- ?match(ok, application:set_env(orber, iiop_out_ports, {6042, 6234})),
- ?match(ok, orber:configure(iiop_setup_connection_timeout, 5)),
- ?match(ok, orber:info(io)),
- IP = orber_test_lib:get_host(),
- spawn(?MODULE, do_connect, [IP, Port, [{active, false}]]),
- spawn(?MODULE, do_connect, [IP, Port, [{active, false}]]),
- spawn(?MODULE, do_connect, [IP, Port, [{active, false}]]),
- spawn(?MODULE, do_connect, [IP, Port, [{active, false}]]),
- spawn(?MODULE, do_connect, [IP, Port, [{active, false}]]),
- Corbaloc = "corbaloc::1.2@"++IP++":"++integer_to_list(Port)++"/NameService",
- timer:sleep(2000),
- ?match({'EXCEPTION', _E}, corba:string_to_object(Corbaloc)),
- destroy_fake_ORB(Ref),
- ?match(ok, application:set_env(orber, iiop_backlog, 5)),
- ?match(ok, application:set_env(orber, iiop_out_ports, undefined)),
- ok.
-
-setup_multi_connection_timeout_attempts_api(_Config) ->
- ?match(ok, application:set_env(orber, iiop_backlog, 0)),
- %% Wait to be sure that the configuration has kicked in.
- timer:sleep(2000),
- {ok, Ref, Port} = create_fake_server_ORB(normal, 0, [], listen, []),
- ?match(ok, application:set_env(orber, iiop_out_ports, {6042, 6234})),
- ?match(ok, application:set_env(orber, iiop_out_ports_attempts, 1)),
- ?match(ok, orber:configure(iiop_setup_connection_timeout, 5)),
- ?match(ok, orber:info(io)),
- IP = orber_test_lib:get_host(),
- spawn(?MODULE, do_connect, [IP, Port, [{active, false}]]),
- spawn(?MODULE, do_connect, [IP, Port, [{active, false}]]),
- spawn(?MODULE, do_connect, [IP, Port, [{active, false}]]),
- spawn(?MODULE, do_connect, [IP, Port, [{active, false}]]),
- spawn(?MODULE, do_connect, [IP, Port, [{active, false}]]),
- Corbaloc = "corbaloc::1.2@"++IP++":"++integer_to_list(Port)++"/NameService",
- timer:sleep(2000),
- ?match({'EXCEPTION', _E}, corba:string_to_object(Corbaloc)),
- destroy_fake_ORB(Ref),
- ?match(ok, application:set_env(orber, iiop_backlog, 5)),
- ?match(ok, application:set_env(orber, iiop_out_ports, undefined)),
- ok.
-
-setup_multi_connection_timeout_random_api(_Config) ->
- ?match(ok, application:set_env(orber, iiop_backlog, 0)),
- %% Wait to be sure that the configuration has kicked in.
- timer:sleep(2000),
- {ok, Ref, Port} = create_fake_server_ORB(normal, 0, [], listen, []),
- ?match(ok, application:set_env(orber, iiop_out_ports, {6042, 6234})),
- ?match(ok, application:set_env(orber, iiop_out_ports_random, true)),
- ?match(ok, orber:configure(iiop_setup_connection_timeout, 5)),
- ?match(ok, orber:info(io)),
- IP = orber_test_lib:get_host(),
- spawn(?MODULE, do_connect, [IP, Port, [{active, false}]]),
- spawn(?MODULE, do_connect, [IP, Port, [{active, false}]]),
- spawn(?MODULE, do_connect, [IP, Port, [{active, false}]]),
- spawn(?MODULE, do_connect, [IP, Port, [{active, false}]]),
- spawn(?MODULE, do_connect, [IP, Port, [{active, false}]]),
- Corbaloc = "corbaloc::1.2@"++IP++":"++integer_to_list(Port)++"/NameService",
- timer:sleep(2000),
- ?match({'EXCEPTION', _E}, corba:string_to_object(Corbaloc)),
- destroy_fake_ORB(Ref),
- ?match(ok, application:set_env(orber, iiop_backlog, 5)),
- ?match(ok, application:set_env(orber, iiop_out_ports, undefined)),
- ok.
-
-%%-----------------------------------------------------------------
-%% Sending an incorrect header to the server-side ORB.
-%%-----------------------------------------------------------------
-bad_giop_header_api(_Config) ->
- orber:configure_override(interceptors, {native,[orber_iiop_tracer]}),
- orber:configure(orber_debug_level, 10),
- ?match(ok, orber:info(io)),
- {ok, ServerNode, ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node()),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- Req = <<"GIOP",1,2,0,100,0,0,0,5,0,0,0,10,50>> ,
- ?match(ok, fake_client_ORB(normal, ServerHost, ServerPort, [],
- message_error, [Req])),
-
- application:set_env(orber, interceptors, false),
- orber:configure(orber_debug_level, 0),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Fragmented IIOP tests (Server-side).
-%%-----------------------------------------------------------------
--define(REQUEST_ID, 0).
-
--define(REPLY_FRAG_1, <<71,73,79,80,1,2,2,1,0,0,0,41,0,0,0,?REQUEST_ID,0,0,0,0,0,0,0,1,78,69,79,0,0,0,0,2,0,10,0,0,0,0,0,0,0,0,0,18,0,0,0,0,0,0,0,4,49>>).
-%% The fragments are identical for requests and replies.
--define(FRAG_2, <<71,73,79,80,1,2,2,7,0,0,0,5,0,0,0,?REQUEST_ID,50>>).
--define(FRAG_3, <<71,73,79,80,1,2,2,7,0,0,0,5,0,0,0,?REQUEST_ID,51>>).
--define(FRAG_4, <<71,73,79,80,1,2,0,7,0,0,0,5,0,0,0,?REQUEST_ID,0>>).
-
-
-fragments_server_api(_Config) ->
- %% --- Create a slave-node ---
- {ok, Node, Host} =
- ?match({ok,_,_}, orber_test_lib:js_node()),
- Port = orber_test_lib:remote_apply(Node, orber, iiop_port, []),
-
- ?match(ok, orber_test_lib:remote_apply(Node, orber_test_lib,
- install_test_data,
- [nameservice])),
-
- NSR = ?match({'IOP_IOR',"IDL:omg.org/CosNaming/NamingContextExt:1.0",_},
- corba:string_to_object("corbaloc::1.2@"++Host++":"++
- integer_to_list(Port)++"/NameService")),
-
- Obj = ?match({'IOP_IOR',"IDL:omg.org/orber_test/server:1.0",_},
- 'CosNaming_NamingContext':resolve(NSR, lname:new(["mamba"]))),
-
- Any = #any{typecode = {tk_string,0},
- value = "123"},
- Target = #'GIOP_TargetAddress'{label = ?GIOP_KeyAddr,
- value = iop_ior:get_objkey(Obj)},
- %% Fix a request header.
- {Hdr, Body, HdrLen, _What, _Flags} =
- cdr_encode:enc_request_split(
- #giop_env{version = {1,2}, objkey = Target,
- request_id = ?REQUEST_ID,
- response_expected = true,
- op = testing_iiop_any,
- parameters = [49], ctx = [],
- tc = {tk_void,[tk_char],[]},
- host = [orber_test_lib:get_host()],
- iiop_port = orber:iiop_port(),
- iiop_ssl_port = orber:iiop_ssl_port(),
- domain = orber:domain(),
- partial_security = orber:partial_security()}),
- NewBody =
- case size(Body) of
- 1 ->
- <<0,0,0,18,0,0,0,0,0,0,0,4,49>> ;
- Size ->
- Aligned = Size -1,
- <<AligmnetData:Aligned/binary,49>> = Body,
- list_to_binary([AligmnetData, <<0,0,0,18,0,0,0,0,0,0,0,4,49>> ])
- end,
-
- MessSize = HdrLen+size(NewBody),
- ReqFrag = list_to_binary([ <<"GIOP",1:8,2:8,2:8,0:8,
- MessSize:32/big-unsigned-integer>> , Hdr |NewBody]),
- ?match(Any, fake_client_ORB(normal, Host, Port, [], fragments,
- [ReqFrag, ?FRAG_2, ?FRAG_3, ?FRAG_4])),
-
- ok.
-
-%%-----------------------------------------------------------------
-%% Fragmented IIOP tests (Server-side). Exceeding Maximum.
-%%-----------------------------------------------------------------
-fragments_max_server_api(_Config) ->
- %% --- Create a slave-node ---
- IP = orber_test_lib:get_host(),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{iiop_max_fragments, 2},
- {ip_address, IP}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- fragments_max_server(ServerNode, IP, ServerPort).
-
-fragments_max_server_added_api(_Config) ->
- %% --- Create a slave-node ---
- IP = orber_test_lib:get_host(),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([])),
- ServerPort = 1 + orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- ?match({ok, _},
- orber_test_lib:remote_apply(ServerNode, orber,
- add_listen_interface,
- [IP, normal,
- [{iiop_max_fragments, 2},
- {flags, ?ORB_ENV_LOCAL_INTERFACE},
- {iiop_port, ServerPort}]])),
- fragments_max_server(ServerNode, IP, ServerPort).
-
-fragments_max_server(ServerNode, ServerHost, ServerPort) ->
- ?match(ok, orber_test_lib:remote_apply(ServerNode, orber_test_lib,
- install_test_data,
- [nameservice])),
- Obj = ?match({'IOP_IOR',"IDL:omg.org/orber_test/server:1.0",_},
- corba:string_to_object("corbaname::1.2@"++ServerHost++":"++
- integer_to_list(ServerPort)++"/NameService#mamba")),
- Target = #'GIOP_TargetAddress'{label = ?GIOP_KeyAddr,
- value = iop_ior:get_objkey(Obj)},
- %% Fix a request header.
- {Hdr, Body, HdrLen, _What, _Flags} =
- cdr_encode:enc_request_split(
- #giop_env{version = {1,2},
- objkey = Target,
- request_id = ?REQUEST_ID,
- response_expected = true,
- op = testing_iiop_any,
- parameters = [49], ctx = [],
- tc = {tk_void,[tk_char],[]},
- host = [orber_test_lib:get_host()],
- iiop_port = orber:iiop_port(),
- iiop_ssl_port = orber:iiop_ssl_port(),
- domain = orber:domain(),
- partial_security = orber:partial_security()}),
- NewBody =
- case size(Body) of
- 1 ->
- <<0,0,0,18,0,0,0,0,0,0,0,4,49>> ;
- Size ->
- Aligned = Size -1,
- <<AligmnetData:Aligned/binary,49>> = Body,
- list_to_binary([AligmnetData, <<0,0,0,18,0,0,0,0,0,0,0,4,49>> ])
- end,
-
- MessSize = HdrLen+size(NewBody),
- ReqFrag = list_to_binary([ <<"GIOP",1:8,2:8,2:8,0:8,
- MessSize:32/big-unsigned-integer>> , Hdr |NewBody]),
- ?match(#'IMP_LIMIT'{},
- fake_client_ORB(normal, ServerHost, ServerPort, [], fragments_max,
- [ReqFrag, ?FRAG_2, ?FRAG_3, ?FRAG_4])),
-
- ok.
-
-%%-----------------------------------------------------------------
-%% Fragmented IIOP tests (Client-side).
-%%-----------------------------------------------------------------
-fragments_client_api(_Config) ->
- Any = #any{typecode = {tk_string,0},
- value = "123"},
- application:set_env(orber, interceptors, {native,[orber_iiop_tracer]}),
- orber:configure(orber_debug_level, 10),
- orber:info(),
- IOR = ?match({'IOP_IOR',_,_},
- iop_ior:create_external({1, 2}, "IDL:FAKE:1.0",
- "localhost", 6004, "FAKE", [])),
- spawn(?MODULE, create_fake_server_ORB, [normal, 6004, [], fragments,
- [?REPLY_FRAG_1, ?FRAG_2,
- ?FRAG_3, ?FRAG_4]]),
- ?match({ok, Any}, orber_test_server:testing_iiop_any(IOR, Any)),
- application:set_env(orber, interceptors, false),
- orber:configure(orber_debug_level, 0),
- ok.
-
-bad_fragment_id_client_api(_Config) ->
- application:set_env(orber, interceptors, {native,[orber_iiop_tracer]}),
- orber:configure(orber_debug_level, 10),
- orber:info(),
- {ok, ServerNode, ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node()),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- Req = <<71,73,79,80,1,2,2,7,0,0,0,5,0,0,0,100,50>> ,
- ?match(ok, fake_client_ORB(normal, ServerHost, ServerPort, [],
- message_error, [Req])),
-
- application:set_env(orber, interceptors, false),
- orber:configure(orber_debug_level, 0),
-
- ok.
-
-%%-----------------------------------------------------------------
-%% Non-existing request id
-%%-----------------------------------------------------------------
-bad_id_cancel_request_api(Config) when is_list(Config) ->
- Req10 = cdr_encode:enc_cancel_request(#giop_env{version = {1, 0},
- request_id = 556}),
- Req11 = cdr_encode:enc_cancel_request(#giop_env{version = {1, 1},
- request_id = 556}),
- Req12 = cdr_encode:enc_cancel_request(#giop_env{version = {1, 2},
- request_id = 556}),
- {ok, ServerNode, ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node()),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- ?match(ok, fake_client_ORB(normal, ServerHost, ServerPort, [],
- message_error, [Req10])),
- ?match(ok, fake_client_ORB(normal, ServerHost, ServerPort, [],
- message_error, [Req11])),
- ?match(ok, fake_client_ORB(normal, ServerHost, ServerPort, [],
- message_error, [Req12])),
- ok.
-
-%%-----------------------------------------------------------------
-%% Local functions.
-%%-----------------------------------------------------------------
-
-do_connect(Host, Port, Options) ->
- gen_tcp:connect(Host, Port, Options),
- timer:sleep(20000).
-
-pseudo_calls(0, _) ->
- ok;
-pseudo_calls(Times, Obj) ->
- orber_test_server:pseudo_call(Obj),
- New = Times - 1,
- pseudo_calls(New, Obj).
-pseudo_casts(0, _) ->
- ok;
-pseudo_casts(Times, Obj) ->
- orber_test_server:pseudo_cast(Obj),
- New = Times - 1,
- pseudo_casts(New, Obj).
-
-context_test(Obj) ->
- CodeSetCtx = #'CONV_FRAME_CodeSetContext'{char_data = 65537,
- wchar_data = 65801},
- FTGrp = #'FT_FTGroupVersionServiceContext'{object_group_ref_version = ?ULONGMAX},
- FTReq = #'FT_FTRequestServiceContext'{client_id = "ClientId",
- retention_id = ?LONGMAX,
- expiration_time = ?ULONGLONGMAX},
-
- IDToken1 = #'CSI_IdentityToken'{label = ?CSI_IdentityTokenType_ITTAbsent,
- value = true},
- IDToken2 = #'CSI_IdentityToken'{label = ?CSI_IdentityTokenType_ITTAnonymous,
- value = false},
- IDToken3 = #'CSI_IdentityToken'{label = ?CSI_IdentityTokenType_ITTPrincipalName,
- value = [0,255]},
- IDToken4 = #'CSI_IdentityToken'{label = ?CSI_IdentityTokenType_ITTX509CertChain,
- value = [1,255]},
- IDToken5 = #'CSI_IdentityToken'{label = ?CSI_IdentityTokenType_ITTDistinguishedName,
- value = [2,255]},
- IDToken6 = #'CSI_IdentityToken'{label = ?ULONGMAX,
- value = [3,255]},
-
- MTEstablishContext1 = #'CSI_SASContextBody'
- {label = ?CSI_MsgType_MTEstablishContext,
- value = #'CSI_EstablishContext'{client_context_id = ?ULONGLONGMAX,
- authorization_token =
- [#'CSI_AuthorizationElement'
- {the_type = ?ULONGMAX,
- the_element = [0,255]}],
- identity_token = IDToken1,
- client_authentication_token = [1, 255]}},
- MTEstablishContext2 = #'CSI_SASContextBody'
- {label = ?CSI_MsgType_MTEstablishContext,
- value = #'CSI_EstablishContext'{client_context_id = ?ULONGLONGMAX,
- authorization_token =
- [#'CSI_AuthorizationElement'
- {the_type = ?ULONGMAX,
- the_element = [0,255]}],
- identity_token = IDToken2,
- client_authentication_token = [1, 255]}},
- MTEstablishContext3 = #'CSI_SASContextBody'
- {label = ?CSI_MsgType_MTEstablishContext,
- value = #'CSI_EstablishContext'{client_context_id = ?ULONGLONGMAX,
- authorization_token =
- [#'CSI_AuthorizationElement'
- {the_type = ?ULONGMAX,
- the_element = [0,255]}],
- identity_token = IDToken3,
- client_authentication_token = [1, 255]}},
- MTEstablishContext4 = #'CSI_SASContextBody'
- {label = ?CSI_MsgType_MTEstablishContext,
- value = #'CSI_EstablishContext'{client_context_id = ?ULONGLONGMAX,
- authorization_token =
- [#'CSI_AuthorizationElement'
- {the_type = ?ULONGMAX,
- the_element = [0,255]}],
- identity_token = IDToken4,
- client_authentication_token = [1, 255]}},
- MTEstablishContext5 = #'CSI_SASContextBody'
- {label = ?CSI_MsgType_MTEstablishContext,
- value = #'CSI_EstablishContext'{client_context_id = ?ULONGLONGMAX,
- authorization_token =
- [#'CSI_AuthorizationElement'
- {the_type = ?ULONGMAX,
- the_element = [0,255]}],
- identity_token = IDToken5,
- client_authentication_token = [1, 255]}},
- MTEstablishContext6 = #'CSI_SASContextBody'
- {label = ?CSI_MsgType_MTEstablishContext,
- value = #'CSI_EstablishContext'{client_context_id = ?ULONGLONGMAX,
- authorization_token =
- [#'CSI_AuthorizationElement'
- {the_type = ?ULONGMAX,
- the_element = [0,255]}],
- identity_token = IDToken6,
- client_authentication_token = [1, 255]}},
- MTCompleteEstablishContext = #'CSI_SASContextBody'
- {label = ?CSI_MsgType_MTCompleteEstablishContext,
- value = #'CSI_CompleteEstablishContext'{client_context_id = ?ULONGLONGMAX,
- context_stateful = false,
- final_context_token = [1, 255]}},
- MTContextError = #'CSI_SASContextBody'
- {label = ?CSI_MsgType_MTContextError,
- value = #'CSI_ContextError'{client_context_id = ?ULONGLONGMAX,
- major_status = 1,
- minor_status = 2,
- error_token = [2,255]}},
- MTMessageInContext = #'CSI_SASContextBody'
- {label = ?CSI_MsgType_MTMessageInContext,
- value = #'CSI_MessageInContext'{client_context_id = ?ULONGLONGMAX,
- discard_context = true}},
- Ctx = [#'IOP_ServiceContext'{context_id=?IOP_CodeSets,
- context_data = CodeSetCtx},
- #'IOP_ServiceContext'{context_id=?IOP_FT_GROUP_VERSION,
- context_data = FTGrp},
- #'IOP_ServiceContext'{context_id=?IOP_FT_REQUEST,
- context_data = FTReq},
- #'IOP_ServiceContext'{context_id=?IOP_SecurityAttributeService,
- context_data = MTEstablishContext1},
- #'IOP_ServiceContext'{context_id=?IOP_SecurityAttributeService,
- context_data = MTEstablishContext2},
- #'IOP_ServiceContext'{context_id=?IOP_SecurityAttributeService,
- context_data = MTEstablishContext3},
- #'IOP_ServiceContext'{context_id=?IOP_SecurityAttributeService,
- context_data = MTEstablishContext4},
- #'IOP_ServiceContext'{context_id=?IOP_SecurityAttributeService,
- context_data = MTEstablishContext5},
- #'IOP_ServiceContext'{context_id=?IOP_SecurityAttributeService,
- context_data = MTEstablishContext6},
- #'IOP_ServiceContext'{context_id=?IOP_SecurityAttributeService,
- context_data = MTCompleteEstablishContext},
- #'IOP_ServiceContext'{context_id=?IOP_SecurityAttributeService,
- context_data = MTContextError},
- #'IOP_ServiceContext'{context_id=?IOP_SecurityAttributeService,
- context_data = MTMessageInContext},
- #'IOP_ServiceContext'{context_id=?ORBER_GENERIC_CTX_ID,
- context_data = {any_kind_of_data, {127,0,0,1}, 4001}}],
- ?match(ok, orber_test_server:testing_iiop_context(Obj, [{context, Ctx}])).
-
-
-create_fake_server_ORB(Type, Port, Options, listen, _Data) ->
- {ok, _ListenSocket, NewPort} =
- orber_socket:listen(Type, Port,
- [{backlog, 0}, {active, false}|Options]),
- Socket = orber_socket:connect(Type, 'localhost', NewPort, [{active, false}|Options]),
- {ok, {Type, Socket}, NewPort};
-create_fake_server_ORB(Type, Port, Options, Action, Data) ->
- {ok, ListenSocket, _NewPort} =
- orber_socket:listen(Type, Port, [{active, false}|Options]),
- Socket = orber_socket:accept(Type, ListenSocket),
- do_server_action(Type, Socket, Action, Data),
- orber_socket:close(Type, Socket),
- ok.
-
-destroy_fake_ORB({Type, Socket}) ->
- orber_socket:close(Type, Socket);
-destroy_fake_ORB(_) ->
- ok.
-
-fake_client_ORB(Type, Host, Port, Options, connect, _Data) ->
- Socket = orber_socket:connect(Type, Host, Port, [{active, false}|Options]),
- {Type, Socket};
-fake_client_ORB(Type, Host, Port, Options, Action, Data) ->
- Socket = orber_socket:connect(Type, Host, Port, [{active, false}|Options]),
- Result = do_client_action(Type, Socket, Action, Data),
- orber_socket:close(Type, Socket),
- Result.
-
-
-
-do_server_action(Type, Socket, fragments, FragList) ->
- timer:sleep(3000),
- {ok, _B} = gen_tcp:recv(Socket, 0),
- ok = send_data(Type, Socket, FragList);
-do_server_action(_Type, _Socket, _Action, _Data) ->
- ok.
-
-do_client_action(Type, Socket, fragments, FragList) ->
- ok = send_data(Type, Socket, FragList),
- timer:sleep(3000),
- {ok, Bytes} = gen_tcp:recv(Socket, 0),
- {#reply_header{request_id = ?REQUEST_ID, reply_status = no_exception}, ok, [Par]} =
- cdr_decode:dec_message({tk_void,[tk_any],[tk_any]}, Bytes),
- Par;
-do_client_action(Type, Socket, fragments_max, FragList) ->
- ok = send_data(Type, Socket, FragList),
- timer:sleep(3000),
- {ok, Bytes} = gen_tcp:recv(Socket, 0),
- {#reply_header{request_id = ?REQUEST_ID, reply_status = system_exception}, Exc, []} =
- cdr_decode:dec_message({tk_void,[tk_any],[tk_any]}, Bytes),
- Exc;
-do_client_action(Type, Socket, message_error, Data) ->
- ok = send_data(Type, Socket, Data),
- timer:sleep(3000),
- {ok,Bytes} = gen_tcp:recv(Socket, 0),
- 'message_error' = cdr_decode:dec_message({tk_void,[tk_any],[tk_any]}, Bytes),
- ok;
-do_client_action(_Type, _Socket, _Action, _Data) ->
- ok.
-
-send_data(_Type, _Socket, []) ->
- ok;
-send_data(Type, Socket, [H|T]) ->
- orber_socket:write(Type, Socket, H),
- send_data(Type, Socket, T).
-
diff --git a/lib/orber/test/naming_context_SUITE.erl b/lib/orber/test/naming_context_SUITE.erl
deleted file mode 100644
index 2afede287a..0000000000
--- a/lib/orber/test/naming_context_SUITE.erl
+++ /dev/null
@@ -1,390 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%%
-%% Description:
-%% Test suite for Name service
-%%
-%%-----------------------------------------------------------------
--module(naming_context_SUITE).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming.hrl").
--include_lib("orber/src/orber_iiop.hrl").
--include_lib("orber/include/corba.hrl").
-
--define(default_timeout, test_server:minutes(5)).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
-
--export([name_context/1, check_list/1, name_context_ext/1]).
-
--export([init_per_suite/1, end_per_suite/1, init_per_testcase/2,
- end_per_testcase/2]).
-
-
-%%-----------------------------------------------------------------
-%% Macros
-%%-----------------------------------------------------------------
--define(REMAP_EXCEPT(F), case catch F of
- {'EXCEPTION', E} -> exit(E);
- {'EXIT', E} -> exit(E);
- R -> R
- end).
-
--define(match(ExpectedRes, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- io:format("------ CORRECT RESULT ------~n~p~n",
- [AcTuAlReS]),
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- cases().
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-cases() ->
- [name_context, check_list, name_context_ext].
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-
-init_per_testcase(_Case, Config) ->
- Path = code:which(?MODULE),
- code:add_pathz(filename:join(filename:dirname(Path), "idl_output")),
- Dog=test_server:timetrap(?default_timeout),
- orber:jump_start(0),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- Path = code:which(?MODULE),
- code:del_path(filename:join(filename:dirname(Path), "idl_output")),
- orber:jump_stop(),
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(Config) ->
- Config.
-
-%%-----------------------------------------------------------------
-%% Test Case: name handling tests
-%% Description:
-%%-----------------------------------------------------------------
-name_context(_) ->
- ?REMAP_EXCEPT(name_context_run()).
-
-name_context_run() ->
- Ns = corba:resolve_initial_references("NameService"),
-
- ?match({'EXCEPTION', #'NO_PERMISSION'{}},
- 'CosNaming_NamingContextExt':destroy(Ns)),
-
- %% Create a test context.
- Tc = 'CosNaming_NamingContext':bind_new_context(Ns,
- [#'CosNaming_NameComponent'{id="testcontext",
- kind=""}]),
- %% Start testing
- 'CosNaming_NamingContext':bind(Tc, [#'CosNaming_NameComponent'
- {id="hej",
- kind=""}], Ns),
- Ns = 'CosNaming_NamingContext':resolve(Tc,
- [#'CosNaming_NameComponent'{id="hej",
- kind=""}]),
- Nc = 'CosNaming_NamingContext':new_context(Tc),
- 'CosNaming_NamingContext':bind(Tc, [#'CosNaming_NameComponent'
- {id="stop",
- kind=""}], Nc),
- Nc = 'CosNaming_NamingContext':resolve(Tc,
- [#'CosNaming_NameComponent'{id="stop",
- kind=""}]),
- {'EXCEPTION', E0} =
- (catch 'CosNaming_NamingContext':bind(Tc,
- [#'CosNaming_NameComponent'{id="stop",
- kind=""}], Ns)),
- ok = 'CosNaming_NamingContext':rebind(Tc,
- [#'CosNaming_NameComponent'{id="stop",
- kind=""}], Ns),
- {'CosNaming_NamingContext_AlreadyBound', _} = E0,
- 'CosNaming_NamingContext':bind_context(Tc,
- [#'CosNaming_NameComponent'{id="evaluate",
- kind=""}], Nc),
- Nc =
- 'CosNaming_NamingContext':resolve(Tc,
- [#'CosNaming_NameComponent'{id="evaluate",
- kind=""}]),
- 'CosNaming_NamingContext':bind(Tc,
- [#'CosNaming_NameComponent'{id="evaluate",
- kind=""},
- #'CosNaming_NameComponent'{id="hej",
- kind=""}], Ns),
- ok = 'CosNaming_NamingContext':rebind(Tc,
- [#'CosNaming_NameComponent'{id="evaluate",
- kind=""},
- #'CosNaming_NameComponent'{id="hej",
- kind=""}], Ns),
- Ns = 'CosNaming_NamingContext':resolve(Tc,
- [#'CosNaming_NameComponent'{id="evaluate",
- kind=""},
- #'CosNaming_NameComponent'{id="hej",
- kind=""}]),
- {'EXCEPTION', E1} =
- (catch 'CosNaming_NamingContext':resolve(Tc,
- [#'CosNaming_NameComponent'{id="stop",
- kind=""},
- #'CosNaming_NameComponent'{id="hej",
- kind=""}])),
- ?match(ok, orber_diagnostics:nameservice()),
-
- {'CosNaming_NamingContext_CannotProceed', _,_,_} = E1,
- {'EXCEPTION', E2} = (catch 'CosNaming_NamingContext':destroy(Nc)),
- {'CosNaming_NamingContext_NotEmpty', _} = E2,
- ok = 'CosNaming_NamingContext':unbind(Tc,
- [#'CosNaming_NameComponent'{id="evaluate",
- kind=""},
- #'CosNaming_NameComponent'{id="hej",
- kind=""}]),
- ok = 'CosNaming_NamingContext':destroy(Nc),
- ok = 'CosNaming_NamingContext':unbind(Tc,
- [#'CosNaming_NameComponent'{id="evaluate",
- kind=""}]),
- ok = 'CosNaming_NamingContext':unbind(Tc,
- [#'CosNaming_NameComponent'{id="stop",
- kind=""}]),
- ok = 'CosNaming_NamingContext':unbind(Tc,
- [#'CosNaming_NameComponent'{id="hej",
- kind=""}]),
- case 'CosNaming_NamingContext':list(Tc, 3) of
- {ok, [], ?ORBER_NIL_OBJREF} ->
- ok;
- _ ->
- exit(not_empty)
- end,
- ok = 'CosNaming_NamingContext':unbind(Ns,
- [#'CosNaming_NameComponent'{id="testcontext",
- kind=""}]),
- ok = 'CosNaming_NamingContext':destroy(Tc),
- ok.
-
-
-
-%% Check that the CosNaming::NamingContext::list() returns ok.
-%% Own Id: OTP-2023
-check_list(Config) when is_list(Config) ->
- ?REMAP_EXCEPT(check_list_run(Config)).
-
-check_list_run(_Config) ->
- create_default_contexts(),
- Ns = corba:resolve_initial_references("NameService"),
- {_, BL, _} = ?match({ok, _, ?ORBER_NIL_OBJREF},
- 'CosNaming_NamingContext':list(Ns, 256)),
-
- FF = fun(X) -> XX = hd(X#'CosNaming_Binding'.binding_name),
- XX#'CosNaming_NameComponent'.id end,
-
- L = lists:sort(lists:map(FF, BL)),
- ["host", "workgroup"] = L,
-
- %% Test next_n/2
- {_, _, BI} = ?match({ok, [], _BI}, 'CosNaming_NamingContext':list(Ns, 0)),
- ?match({true, []}, 'CosNaming_BindingIterator':next_n(BI, 0)),
- ?match({true, [_]}, 'CosNaming_BindingIterator':next_n(BI, 1)),
- ?match({false, [_]}, 'CosNaming_BindingIterator':next_n(BI, 1)),
- ?match({false, []}, 'CosNaming_BindingIterator':next_n(BI, 1)),
- ?match(ok, 'CosNaming_BindingIterator':destroy(BI)),
-
- {_, _, BI2} = ?match({ok, [], _BI2}, 'CosNaming_NamingContext':list(Ns, 0)),
- ?match({true, _}, 'CosNaming_BindingIterator':next_one(BI2)),
- ?match({true, _}, 'CosNaming_BindingIterator':next_one(BI2)),
- ?match({false, _}, 'CosNaming_BindingIterator':next_one(BI2)),
- ?match(ok, 'CosNaming_BindingIterator':destroy(BI2)),
- ?match(ok, orber_diagnostics:nameservice()),
- ok.
-
-create_default_contexts() ->
- HostComponent = lname_component:set_id(lname_component:create(),
- "host"),
- HostsComponent = lname_component:set_id(lname_component:create(),
- "hosts"),
- ResourcesComponent = lname_component:set_id(lname_component:create(),
- "resources"),
- DevelopmentComponent = lname_component:set_id(lname_component:create(),
- "development"),
- FactoriesComponent = lname_component:set_id(lname_component:create(),
- "factories"),
- WGComponent = lname_component:set_id(lname_component:create(),
- "workgroup"),
- %% Creation of Naming Context host and it's subcontexts
- NS = corba:resolve_initial_references("NameService"),
- H = 'CosNaming_NamingContext':bind_new_context(NS,
- lname:insert_component(lname:create(), 1, HostComponent)),
- HR = 'CosNaming_NamingContext':bind_new_context(H,
- lname:insert_component(lname:create(), 1, ResourcesComponent)),
- 'CosNaming_NamingContext':bind_new_context(HR,
- lname:insert_component(lname:create(), 1, FactoriesComponent)),
- HD = 'CosNaming_NamingContext':bind_new_context(H,
- lname:insert_component(lname:create(), 1, DevelopmentComponent)),
- HDR = 'CosNaming_NamingContext':bind_new_context(HD,
- lname:insert_component(lname:create(), 1, ResourcesComponent)),
- 'CosNaming_NamingContext':bind_new_context(HDR,
- lname:insert_component(lname:create(), 1, FactoriesComponent)),
- %% Creation of Naming Context workgroup and it's subcontexts
- W = 'CosNaming_NamingContext':bind_new_context(NS,
- lname:insert_component(lname:create(), 1, WGComponent)),
- 'CosNaming_NamingContext':bind_new_context(W,
- lname:insert_component(lname:create(), 1, HostsComponent)),
- WR = 'CosNaming_NamingContext':bind_new_context(W,
- lname:insert_component(lname:create(), 1, ResourcesComponent)),
- 'CosNaming_NamingContext':bind_new_context(WR,
- lname:insert_component(lname:create(), 1, FactoriesComponent)),
- WD = 'CosNaming_NamingContext':bind_new_context(W,
- lname:insert_component(lname:create(), 1, DevelopmentComponent)),
- WDR = 'CosNaming_NamingContext':bind_new_context(WD,
- lname:insert_component(lname:create(), 1, ResourcesComponent)),
- 'CosNaming_NamingContext':bind_new_context(WDR,
- lname:insert_component(lname:create(), 1, FactoriesComponent)),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case:
-%% Description:
-%%-----------------------------------------------------------------
-name_context_ext(_Config) ->
- ?REMAP_EXCEPT(name_context_ext_run()).
-
-name_context_ext_run() ->
- NS = ?match({_,pseudo,_, _,_, _},
- corba:resolve_initial_references("NameService")),
-
- Name1 = [#'CosNaming_NameComponent'{id="\\<id1\\>", kind="kind1"},
- #'CosNaming_NameComponent'{id="id2", kind="kind2"}],
- String1 = "\\<id1\\>.kind1/id2.kind2",
- Name2 = [#'CosNaming_NameComponent'{id="id1", kind=""},
- #'CosNaming_NameComponent'{id="id2", kind=""},
- #'CosNaming_NameComponent'{id="id3", kind=""}],
- String2 = "id1/id2/id3",
- Name3 = [#'CosNaming_NameComponent'{id="id1", kind="kind1"},
- #'CosNaming_NameComponent'{id="", kind=""},
- #'CosNaming_NameComponent'{id="id3", kind="kind3"}],
- String3 = "id1.kind1/./id3.kind3",
- Name4 = [#'CosNaming_NameComponent'{id="id1", kind="kind1"},
- #'CosNaming_NameComponent'{id="i.d.2", kind="kind2"},
- #'CosNaming_NameComponent'{id="id3", kind="kind3"}],
- String4 = "id1.kind1/i\\.d\\.2.kind2/id3.kind3",
- Name5 = [#'CosNaming_NameComponent'{id="id1", kind=""},
- #'CosNaming_NameComponent'{id="i/d/2", kind="kind2"},
- #'CosNaming_NameComponent'{id="id3", kind=""}],
- String5 = "id1/i\\/d\\/2.kind2/id3",
-
- BadString1 = "id1./id2/id3",
- BadString2 = "id1//id3",
-
- ?match(String1, 'CosNaming_NamingContextExt':to_string(NS, Name1)),
- ?match(String2, 'CosNaming_NamingContextExt':to_string(NS, Name2)),
- ?match(String3, 'CosNaming_NamingContextExt':to_string(NS, Name3)),
- ?match(String4, 'CosNaming_NamingContextExt':to_string(NS, Name4)),
- ?match(String5, 'CosNaming_NamingContextExt':to_string(NS, Name5)),
- ?match(Name1, 'CosNaming_NamingContextExt':to_name(NS, String1)),
- ?match(Name2, 'CosNaming_NamingContextExt':to_name(NS, String2)),
- ?match(Name3, 'CosNaming_NamingContextExt':to_name(NS, String3)),
- ?match(Name4, 'CosNaming_NamingContextExt':to_name(NS, String4)),
- ?match(Name5, 'CosNaming_NamingContextExt':to_name(NS, String5)),
-
- ?match({'EXCEPTION', {'CosNaming_NamingContext_InvalidName',_}},
- 'CosNaming_NamingContextExt':to_name(NS, BadString1)),
- ?match({'EXCEPTION', {'CosNaming_NamingContext_InvalidName',_}},
- 'CosNaming_NamingContextExt':to_name(NS, BadString2)),
-
- %% Create a test context.
- Tc = ?match({_,pseudo,_, _,_, _},
- 'CosNaming_NamingContext':bind_new_context(NS,
- [#'CosNaming_NameComponent'{id="testcontext",
- kind=""}])),
- ?match(ok, 'CosNaming_NamingContext':bind(Tc, [#'CosNaming_NameComponent'
- {id="hej",
- kind=""}], NS)),
-
- ?match(NS, 'CosNaming_NamingContextExt':resolve_str(Tc, "hej")),
-
- ?match("corbaloc:rir:", 'CosNaming_NamingContextExt':to_url(Tc, "rir:", "")),
- ?match("corbaname:rir:/NameService#org/erlang/",
- 'CosNaming_NamingContextExt':to_url(Tc, "rir:/NameService", "org/erlang/")),
- ?match("corbaloc::1.1@555%3cxyz.com:9999/Dev/NameService",
- 'CosNaming_NamingContextExt':to_url(Tc, ":1.1@555\\<xyz.com:9999/Dev/NameService", "")),
-
- %% Bad port
- ?match({'EXCEPTION', {'CosNaming_NamingContextExt_InvalidAddress',_}},
- 'CosNaming_NamingContextExt':to_url(Tc, ":[email protected]:99a9/", "")),
- %% BAd IIOP-version
- ?match({'EXCEPTION', {'CosNaming_NamingContextExt_InvalidAddress',_}},
- 'CosNaming_NamingContextExt':to_url(Tc, ":[email protected]:99a9/", "")),
- %% Bad IIOP-version
- ?match({'EXCEPTION', {'CosNaming_NamingContextExt_InvalidAddress',_}},
- 'CosNaming_NamingContextExt':to_url(Tc, ":@555xyz.com:99a9/", "")),
- %% Bad protocol
- ?match({'EXCEPTION', {'CosNaming_NamingContextExt_InvalidAddress',_}},
- 'CosNaming_NamingContextExt':to_url(Tc, "iop:@555xyz.com:99a9/", "")),
- %% Unsupported protocol
- ?match({'EXCEPTION', {'CosNaming_NamingContextExt_InvalidAddress',_}},
- 'CosNaming_NamingContextExt':to_url(Tc, "atm:@555xyz.com:9999/", "")),
- %% Bad Name
- ?match({'EXCEPTION', {'CosNaming_NamingContext_InvalidName',_}},
- 'CosNaming_NamingContextExt':to_url(Tc, ":555xyz.com:9999/", "id1./id2.kind2")),
-
- ok.
-
-
diff --git a/lib/orber/test/orber.cover b/lib/orber/test/orber.cover
deleted file mode 100644
index 807a7c2c6e..0000000000
--- a/lib/orber/test/orber.cover
+++ /dev/null
@@ -1,2 +0,0 @@
-{incl_app,orber,details}.
-
diff --git a/lib/orber/test/orber.spec b/lib/orber/test/orber.spec
deleted file mode 100644
index 0dd30deade..0000000000
--- a/lib/orber/test/orber.spec
+++ /dev/null
@@ -1 +0,0 @@
-{suites,"../orber_test",all}.
diff --git a/lib/orber/test/orber_SUITE.erl b/lib/orber/test/orber_SUITE.erl
deleted file mode 100644
index 75da31bc5f..0000000000
--- a/lib/orber/test/orber_SUITE.erl
+++ /dev/null
@@ -1,213 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(orber_SUITE).
--include_lib("common_test/include/ct.hrl").
-
--define(default_timeout, test_server:minutes(15)).
--define(application, orber).
-
-% Test server specific exports
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2]).
--export([init_per_testcase/2, end_per_testcase/2]).
-
-% Test cases must be exported.
--export([app_test/1, undefined_functions/1, install_load_order/1,
- install_local_content/1,
- otp_9887/1]).
-
-%% Exporting error handler callbacks for use in otp_9887
--export([init/1, handle_event/2]).
-
-%%
-%% all/1
-%%
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [app_test, undefined_functions, install_load_order,
- install_local_content,
- otp_9887].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-init_per_testcase(_Case, Config) ->
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-end_per_testcase(_Case, Config) ->
- Dog=proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-%
-% Test cases starts here.
-%
-app_test(_Config) ->
- ok=test_server:app_test(orber),
- ok.
-
-otp_9887(_Config) ->
- orber:jump_stop(),
- application:set_env(orber, orber_debug_level, 10),
- orber:jump_start([]),
-
- mnesia:create_table(orber_light_ifr, []),
-
- error_logger:add_report_handler(?MODULE,[self()]),
- catch orber_ifr:get_module(foo, bar),
-
- receive
- {stolen,Reason} ->
- {error,_Pid1, {_Pid2, _ErrorString, ArgumentList}} = Reason,
- 5 = length(ArgumentList)
- after 500 ->
- test_server:fail("OTP_9887 TIMED OUT")
- end,
-
- orber:jump_stop(),
- ok.
-
-%% Install Orber using the load_order option.
-install_load_order(_Config) ->
- orber:jump_stop(),
- case catch install_load_order2() of
- ok ->
- orber:jump_stop();
- What ->
- orber:jump_stop(),
- exit(What)
- end.
-
-install_load_order2() ->
- application:load(orber),
- mnesia:start(),
- corba:orb_init([{iiop_port, 0}]),
- orber:install([node()], [{ifr_storage_type, ram_copies},
- {load_order, 10}]),
- orber:start(),
- [H|_] = orber:get_tables(),
- 10 = mnesia:table_info(H, load_order),
- ok.
-
-%% Install Orber using the local_content option.
-install_local_content(_Config) ->
- orber:jump_stop(),
- case catch install_local_content2() of
- ok ->
- orber:jump_stop();
- What ->
- orber:jump_stop(),
- exit(What)
- end.
-
-install_local_content2() ->
- application:load(orber),
- mnesia:start(),
- corba:orb_init([{iiop_port, 0}]),
- orber:install([node()], [{ifr_storage_type, ram_copies},
- {local_content, true}]),
- orber:start(),
- [H|_] = orber:get_tables(),
- true = mnesia:table_info(H, local_content),
- ok.
-
-
-
-%% Check for undefined functions
-undefined_functions(_Config) ->
- App = orber,
- Root = code:root_dir(),
- LibDir = code:lib_dir(App),
- EbinDir = filename:join([LibDir,"ebin"]),
- AppFilePath = filename:join([LibDir,"ebin", "orber.app"]),
- {ok, [{application,orber,AppFile}]} = file:consult(AppFilePath),
- io:format("Using ~p~n~p~n", [AppFilePath, AppFile]),
- Mods = key1search(modules, AppFile),
- XRefTestName = undef_funcs_make_name(App, xref_test_name),
- {ok, XRef} = xref:start(XRefTestName),
- ok = xref:set_default(XRef,
- [{verbose,false},{warnings,false}]),
- XRefName = undef_funcs_make_name(App, xref_name),
- {ok, XRefName} = xref:add_release(XRef, Root, {name,XRefName}),
- {ok, App} = xref:replace_application(XRef, App, EbinDir),
- {ok, Undefs} = xref:analyze(XRef, undefined_function_calls),
- xref:stop(XRef),
- analyze_undefined_function_calls(Undefs, Mods, []).
-
-analyze_undefined_function_calls([], _, []) ->
- ok;
-analyze_undefined_function_calls([], _, AppUndefs) ->
- exit({suite_failed, {undefined_function_calls, AppUndefs}});
-analyze_undefined_function_calls([{{Mod, _F, _A}, _C} = AppUndef|Undefs],
- AppModules, AppUndefs) ->
- %% Check that this module is our's
- case lists:member(Mod,AppModules) of
- true ->
- {Calling,Called} = AppUndef,
- {Mod1,Func1,Ar1} = Calling,
- {Mod2,Func2,Ar2} = Called,
- io:format("undefined function call: "
- "~n ~w:~w/~w calls ~w:~w/~w~n",
- [Mod1,Func1,Ar1,Mod2,Func2,Ar2]),
- analyze_undefined_function_calls(Undefs, AppModules,
- [AppUndef|AppUndefs]);
- false ->
- io:format("dropping ~p~n", [Mod]),
- analyze_undefined_function_calls(Undefs, AppModules, AppUndefs)
- end.
-
-%% This function is used simply to avoid cut-and-paste errors later...
-undef_funcs_make_name(App, PostFix) ->
- list_to_atom(atom_to_list(App) ++ "_" ++ atom_to_list(PostFix)).
-
-key1search(Key, L) ->
- case lists:keysearch(Key, 1, L) of
- false ->
- fail({not_found, Key, L});
- {value, {Key, Value}} ->
- Value
- end.
-
-fail(Reason) ->
- exit({suite_failed, Reason}).
-
-%% Error handler
-
-init([Proc]) -> {ok,Proc}.
-
-handle_event(Event, Proc) ->
- Proc ! {stolen,Event},
- {ok,Proc}.
diff --git a/lib/orber/test/orber_acl_SUITE.erl b/lib/orber/test/orber_acl_SUITE.erl
deleted file mode 100644
index 2b0a48adc9..0000000000
--- a/lib/orber/test/orber_acl_SUITE.erl
+++ /dev/null
@@ -1,299 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%%
-%% Description:
-%% Test suite for the ACL functions
-%%
-%%-----------------------------------------------------------------
--module(orber_acl_SUITE).
-
--include_lib("common_test/include/ct.hrl").
-
--define(default_timeout, test_server:minutes(5)).
-
--define(match(ExpectedRes,Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- io:format("------ CORRECT RESULT ------~n~p~n",
- [AcTuAlReS]),
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~nRESULT: ~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--compile(export_all).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [ipv4_verify, ipv4_range, ipv4_interfaces, ipv4_bm,
- ipv6_verify, ipv6_range, ipv6_interfaces, ipv6_bm].
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-init_per_suite(Config) ->
- if
- is_list(Config) ->
- Config;
- true ->
- exit("Config not a list")
- end.
-
-end_per_suite(Config) ->
- Config.
-
-
-init_per_testcase(_Case, Config) ->
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case
-%% Description: Testing IPv4 Verify Operation
-%%-----------------------------------------------------------------
-ipv4_verify(_) ->
- ?match(true, orber_acl:verify("192.168.64.148", "192.168.64.0/17", inet)),
- ?match({false,"192.168.128.0","192.168.255.255"},
- orber_acl:verify("192.168.64.148", "192.168.255.0/17", inet)),
- ?match(true, orber_acl:verify("192.168.255.148", "192.168.128.0/17", inet)),
- ?match(true, orber_acl:verify("192.168.128.148", "192.168.128.0/17", inet)),
- ?match(true, orber_acl:verify("192.168.255.255", "192.168.128.0/16", inet)),
- ?match({false,"192.168.0.0","192.168.255.255"},
- orber_acl:verify("192.169.255.255", "192.168.128.0/16", inet)),
- ?match(true, orber_acl:verify("192.168.128.255", "192.168.128.0/24", inet)),
- ?match({false,"192.168.128.0","192.168.128.255"},
- orber_acl:verify("192.168.255.255", "192.168.128.0/24", inet)),
- ?match({false,"192.168.128.0","192.168.128.127"},
- orber_acl:verify("192.168.128.255", "192.168.128.0/25", inet)),
- ?match(true, orber_acl:verify("192.168.128.255", "192.168.128.128/25", inet)),
- ?match(true, orber_acl:verify("192.168.128.128", "192.168.128.128/32", inet)),
- ?match({false,"192.168.128.128.","192.168.128.128."},
- orber_acl:verify("192.168.128.255", "192.168.128.128/32", inet)),
- ?match(true, orber_acl:verify("192.168.128.128", "192.168.128.128", inet)),
- ?match({false,"192.168.128.128.","192.168.128.128."},
- orber_acl:verify("192.168.128.255", "192.168.128.128", inet)),
- ?match(true, orber_acl:verify("192.168.128.255", "192.168.128.128/7", inet)),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case :
-%% Description: Testing IPv4 Range Operation
-%%-----------------------------------------------------------------
-ipv4_range(_) ->
- ?match({ok,"192.168.0.0", "192.168.127.255"},
- orber_acl:range("192.168.64.0/17")),
- ?match({ok, "192.168.128.0", "192.168.255.255"},
- orber_acl:range("192.168.255.0/17")),
- ?match({ok,"192.168.128.0","192.168.255.255"},
- orber_acl:range("192.168.128.0/17")),
- ?match({ok,"192.168.0.0","192.168.255.255"},
- orber_acl:range("192.168.128.0/16")),
- ?match({ok,"192.168.128.0","192.168.128.255"},
- orber_acl:range("192.168.128.0/24")),
- ?match({ok,"192.168.128.0","192.168.128.127"},
- orber_acl:range("192.168.128.0/25")),
- ?match({ok,"192.168.128.128","192.168.128.255"},
- orber_acl:range("192.168.128.128/25")),
- ?match({ok,"192.168.128.128.","192.168.128.128."},
- orber_acl:range("192.168.128.128/32")),
- ?match({ok,"192.168.128.128.","192.168.128.128."},
- orber_acl:range("192.168.128.128")),
- ?match({ok,"192.0.0.0","193.255.255.255"},
- orber_acl:range("192.168.128.128/7")),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case :
-%% Description: Testing IPv4 Interfaces Operation
-%%-----------------------------------------------------------------
-ipv4_interfaces(_) ->
- ?match({ok, _},
- orber_acl:init_acl([{tcp_in, "192.168.128.0/18", ["10.1.1.1"]},
- {tcp_in, "192.167.64.0/18#4001/5001", ["10.1.1.2"]},
- {tcp_in, "192.166.192.0/18"}], inet)),
- {ok, IPTuple1} = ?match({ok, _}, inet:getaddr("192.168.128.0", inet)),
- ?match({true, ["10.1.1.1"], 0}, orber_acl:match(IPTuple1, tcp_in, true)),
- ?match({false, [], 0}, orber_acl:match(IPTuple1, tcp_out, true)),
- {ok, IPTuple2} = ?match({ok, _}, inet:getaddr("192.167.64.0", inet)),
- ?match({true, ["10.1.1.2"], {4001,5001}}, orber_acl:match(IPTuple2, tcp_in, true)),
- ?match({false, [], 0}, orber_acl:match(IPTuple2, tcp_out, true)),
- {ok, IPTuple3} = ?match({ok, _}, inet:getaddr("192.166.192.0", inet)),
- ?match({true, [], 0}, orber_acl:match(IPTuple3, tcp_in, true)),
- ?match(false, orber_acl:match(IPTuple3, tcp_out)),
- ?match(ok, orber_acl:clear_acl()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case :
-%% Description: Benchmarking runtime critical IPv4 Operations
-%%-----------------------------------------------------------------
-ipv4_bm(_) ->
- ?match({ok, _, _, _}, bm2([{tcp_in, "192.168.64.0/17"}], inet, "192.168.64.148")),
- ok.
-%%-----------------------------------------------------------------
-%% Test Case :
-%% Description: Testing IPv6 Verify Operation
-%%-----------------------------------------------------------------
-ipv6_verify(_) ->
- case orber_test_lib:version_ok() of
- true ->
- ?match(true, orber_acl:verify("2002:C0A8:0:0:0:0:0:0", "2002:C0A8::/48", inet6)),
- ?match(true, orber_acl:verify("2002:C0A8:0:FFFF:FFFF:FFFF:FFFF:FFFF", "2002:C0A8::/48", inet6)),
- ?match({false,"2002:C0A8:0:0:0:0:0:0", "2002:C0A8:0:FFFF:FFFF:FFFF:FFFF:FFFF"},
- orber_acl:verify("2002:C0A8:1:FFFF:FFFF:FFFF:FFFF:FFFF", "2002:C0A8::/48", inet6)),
- ?match(true, orber_acl:verify("2002:C0A8:1:FFFF:FFFF:FFFF:FFFF:FFFF", "2002:C0A8::/47", inet6)),
- ?match({false,"2002:C0A8:0:0:0:0:0:0", "2002:C0A8:1:FFFF:FFFF:FFFF:FFFF:FFFF"},
- orber_acl:verify("2002:C0A8:2:FFFF:FFFF:FFFF:FFFF:FFFF", "2002:C0A8::/47", inet6)),
- ok;
- Reason ->
- Reason
- end.
-
-%%-----------------------------------------------------------------
-%% Test Case :
-%% Description: Testing IPv6 Range Operation
-%%-----------------------------------------------------------------
-ipv6_range(_) ->
- case orber_test_lib:version_ok() of
- true ->
- ?match({ok,"2002:C0A8:0:0:0:0:0:0", "2002:C0A8:0:FFFF:FFFF:FFFF:FFFF:FFFF"},
- orber_acl:range("2002:C0A8::/48", inet6)),
- ?match({ok,"2002:C0A8:0:0:0:0:0:0", "2002:C0A8:1:FFFF:FFFF:FFFF:FFFF:FFFF"},
- orber_acl:range("2002:C0A8::/47", inet6)),
- ok;
- Reason ->
- Reason
- end.
-
-%%-----------------------------------------------------------------
-%% Test Case :
-%% Description: Testing IPv6 Interfaces Operation
-%%-----------------------------------------------------------------
-ipv6_interfaces(_) ->
- case orber_test_lib:version_ok() of
- true ->
- ?match({ok, _}, orber_acl:init_acl([{tcp_in, "2002:C0A8::/49", ["0:0:0:0:0:0:10.1.1.1"]}], inet6)),
- {ok, IPTuple1} = ?match({ok, _}, inet:getaddr("2002:C0A8:0:7FFF:FFFF:FFFF:FFFF:FFFF", inet6)),
- ?match({true, ["0:0:0:0:0:0:10.1.1.1"], 0}, orber_acl:match(IPTuple1, tcp_in, true)),
- ?match(false, orber_acl:match(IPTuple1, tcp_out)),
- ?match(ok, orber_acl:clear_acl()),
- ok;
- Reason ->
- Reason
- end.
-
-%%-----------------------------------------------------------------
-%% Test Case :
-%% Description: Benchmarking runtime critical IPv6 Operations
-%%-----------------------------------------------------------------
-ipv6_bm(_) ->
- case orber_test_lib:version_ok() of
- true ->
- ?match({ok, _, _, _}, bm2([{tcp_in, "2002:C0A8::/48"}], inet6, "2002:C0A8:0:0:0:0:0:0")),
- ok;
- Reason ->
- Reason
- end.
-
-%%-----------------------------------------------------------------
-%% Local Functions
-%%-----------------------------------------------------------------
--define(NO_OF_TIMES, 1000).
-
-bm2(Filters, Family, Ip) ->
- {ok, IPTuple} = inet:getaddr(Ip, Family),
- orber_acl:init_acl(Filters, Family),
- TimeBefore1 = erlang:timestamp(),
- bm_loop(IPTuple, ?NO_OF_TIMES),
- TimeAfter1 = erlang:timestamp(),
- orber_acl:clear_acl(),
- Time1 = computeTime(TimeBefore1, TimeAfter1),
- orber_acl:init_acl(Filters, Family),
- TimeBefore2 = erlang:timestamp(),
- bm_loop2(Ip, ?NO_OF_TIMES, Family),
- TimeAfter2 = erlang:timestamp(),
- orber_acl:clear_acl(),
- Time2 = computeTime(TimeBefore2, TimeAfter2),
- orber_acl:init_acl(Filters, Family),
- TimeBefore3 = erlang:timestamp(),
- bm_loop2(IPTuple, ?NO_OF_TIMES, Family),
- TimeAfter3 = erlang:timestamp(),
- orber_acl:clear_acl(),
- Time3 = computeTime(TimeBefore3, TimeAfter3),
- {ok, round(?NO_OF_TIMES/Time1), round(?NO_OF_TIMES/Time2), round(?NO_OF_TIMES/Time3)}.
-
-
-bm_loop(_Ip, 0) ->
- ok;
-bm_loop(Ip, N) ->
- true = orber_acl:match(Ip, tcp_in),
- bm_loop(Ip, N-1).
-
-bm_loop2(_Ip, 0, _Family) ->
- ok;
-bm_loop2(Ip, N, Family) ->
- {ok, IPTuple} = inet:getaddr(Ip, Family),
- true = orber_acl:match(IPTuple, tcp_in),
- bm_loop2(Ip, N-1, Family).
-
-computeTime({_MegaSecb, Secb, MicroSecb}, {_MegaSeca, Seca, MicroSeca}) ->
- (Seca - Secb) + ((MicroSeca - MicroSecb) / 1000000).
-
-
-%%-----------------------------------------------------------------
-%% END OF MODULE
-%%-----------------------------------------------------------------
diff --git a/lib/orber/test/orber_firewall_ipv4_in_SUITE.erl b/lib/orber/test/orber_firewall_ipv4_in_SUITE.erl
deleted file mode 100644
index 6d085d3bf5..0000000000
--- a/lib/orber/test/orber_firewall_ipv4_in_SUITE.erl
+++ /dev/null
@@ -1,284 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(orber_firewall_ipv4_in_SUITE).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/include/corba.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming.hrl").
--include_lib("orber/src/orber_iiop.hrl").
--include_lib("orber/src/ifr_objects.hrl").
--include("idl_output/orber_test_server.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming_NamingContextExt.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming_NamingContext.hrl").
-
--define(default_timeout, test_server:minutes(15)).
-
--define(match(ExpectedRes,Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- io:format("------ CORRECT RESULT ------~n~p~n",
- [AcTuAlReS]),
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~nRESULT: ~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2, cases/0,
- init_per_suite/1, end_per_suite/1,
- init_per_testcase/2, end_per_testcase/2,
- deny_port_api/1, deny_port_range_api/1, deny_host_api/1,
- deny_peerhost_api/1, allow_port_range_api/1,
- allow_host_api/1, allow_peerhost_api/1, check_address_api/1]).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- cases().
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%% NOTE - the fragment test cases must bu first since we explicitly set a request
-%% id. Otherwise, the request-id counter would be increased and we cannot know
-%% what it is.
-cases() ->
- [deny_port_api, deny_port_range_api, deny_host_api,
- deny_peerhost_api, allow_port_range_api, allow_host_api,
- allow_peerhost_api, check_address_api].
-
-
-init_per_testcase(_Case, Config) ->
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-init_per_suite(Config) ->
- if
- is_list(Config) ->
- orber:jump_start([{iiop_port, 0},
- {iiop_out_ports, {5980, 6000}}]),
- Config;
- true ->
- exit("Config not a list")
- end.
-
-end_per_suite(Config) ->
- orber:jump_stop(),
- Config.
-
-%%-----------------------------------------------------------------
-%% Incomming connections - Deny
-%%-----------------------------------------------------------------
-%% Deny Access due to invalid local port
-deny_port_api(_Config) ->
- [IP] = ?match([_], orber:host()),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_USE_ACL_INCOMING},
- {iiop_acl, [{tcp_in, IP++"/32#7000"}]}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- ?match({'EXCEPTION', #'CosNaming_NamingContextExt_InvalidAddress'{}},
- corba:string_to_object("corbaloc::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService")),
-% catch orber_test_lib:destroy_node(ServerNode, timeout),
- ok.
-
-%% Deny Access due to invalid local port range
-deny_port_range_api(_Config) ->
- [IP] = ?match([_], orber:host()),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_USE_ACL_INCOMING},
- {iiop_acl, [{tcp_in, IP++"/32#7000/8000"}]}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- ?match({'EXCEPTION', #'CosNaming_NamingContextExt_InvalidAddress'{}},
- corba:string_to_object("corbaloc::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService")),
-% catch orber_test_lib:destroy_node(ServerNode, timeout),
- ok.
-
-
-%% Deny Access due to invalid host
-deny_host_api(_Config) ->
- [IP] = ?match([_], orber:host()),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_USE_ACL_INCOMING},
- {iiop_acl, [{tcp_in, "123.123.123.123/32"}]}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- ?match({'EXCEPTION', #'CosNaming_NamingContextExt_InvalidAddress'{}},
- corba:string_to_object("corbaloc::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService")),
-% catch orber_test_lib:destroy_node(ServerNode, timeout),
- ok.
-
-%% Deny Access due to invalid peerhost
-deny_peerhost_api(_Config) ->
- [IP] = ?match([_], orber:host()),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_USE_ACL_INCOMING},
- {iiop_acl, [{tcp_in, IP++"/32", ["123.123.123.123"]}]}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- ?match({'EXCEPTION', #'CosNaming_NamingContextExt_InvalidAddress'{}},
- corba:string_to_object("corbaloc::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService")),
-% catch orber_test_lib:destroy_node(ServerNode, timeout),
- ok.
-
-%%-----------------------------------------------------------------
-%% Incomming connections - Allow
-%%-----------------------------------------------------------------
-%% Allow Access due to valid local port range
-allow_port_range_api(_Config) ->
- [IP] = ?match([_], orber:host()),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_USE_ACL_INCOMING},
- {iiop_acl, [{tcp_in, IP++"/32#5980/6000"}]}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- IOR =
- ?match({'IOP_IOR',_,_},
- corba:string_to_object("corbaloc::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService")),
- ?match(false, corba_object:not_existent(IOR)),
-% catch orber_test_lib:destroy_node(ServerNode, timeout),
- ok.
-
-
-%% Allow Access due to valid host
-allow_host_api(_Config) ->
- [IP] = ?match([_], orber:host()),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_USE_ACL_INCOMING},
- {iiop_acl, [{tcp_in, IP++"/32"}]}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- IOR =
- ?match({'IOP_IOR',_,_},
- corba:string_to_object("corbaloc::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService")),
- ?match(false, corba_object:not_existent(IOR)),
-% catch orber_test_lib:destroy_node(ServerNode, timeout),
- ok.
-
-%% Allow Access due to valid peerhost
-allow_peerhost_api(_Config) ->
- [IP] = ?match([_], orber:host()),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_USE_ACL_INCOMING},
- {iiop_acl, [{tcp_in, IP++"/32", [IP]}]}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- IOR =
- ?match({'IOP_IOR',_,_},
- corba:string_to_object("corbaloc::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService",
- [#'IOP_ServiceContext'
- {context_id=?ORBER_GENERIC_CTX_ID,
- context_data = {interface, IP}}])),
- ?match(false, corba_object:not_existent(IOR,
- [#'IOP_ServiceContext'
- {context_id=?ORBER_GENERIC_CTX_ID,
- context_data = {interface, IP}}])),
-% catch orber_test_lib:destroy_node(ServerNode, timeout),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test corbaloc strings
-%%-----------------------------------------------------------------
-check_address_api(_Config) ->
- ?match({[[iiop,{1,0},"10.0.0.1",2809]],"NameService"},
- orber_cosnaming_utils:addresses(":10.0.0.1/NameService")),
- ?match({[[iiop,{1,0},"10.0.0.1",2809]],[]},
- orber_cosnaming_utils:addresses(":10.0.0.1")),
- ?match({[[iiop,{1,2},"10.0.0.1",2809]],"NameService"},
- orber_cosnaming_utils:addresses(":[email protected]/NameService")),
- ?match({[[iiop,{1,0},"10.0.0.1",4001]],"NameService"},
- orber_cosnaming_utils:addresses(":10.0.0.1:4001/NameService")),
- ?match({[[iiop,{1,1},"10.0.0.1",4001]],"NameService"},
- orber_cosnaming_utils:addresses(":[email protected]:4001/NameService")),
- ?match({[[iiop,{1,1},"10.0.0.1",4001]],[]},
- orber_cosnaming_utils:addresses(":[email protected]:4001")),
- ?match({[[iiop,{1,1},"10.0.0.1",4001]],[]},
- orber_cosnaming_utils:addresses("iiop:[email protected]:4001")),
- ?match({[[iiop,{1,1},"10.0.0.1",4001]],[]},
- orber_cosnaming_utils:addresses("iiop:[email protected]:4001/")),
-
- ?match({[[iiop,{1,1},"myhost",4001]],[]},
- orber_cosnaming_utils:addresses("iiop:1.1@myhost:4001")),
- ?match({[[iiop,{1,1},"myhost.full.name",4001]],"NameService"},
- orber_cosnaming_utils:addresses("iiop:[email protected]:4001/NameService")),
- ?match({[[iiop,{1,1},"myhost",4001],
- [iiop,{1,1},"myhost.full.name",2809]],"NameService"},
- orber_cosnaming_utils:addresses("iiop:1.1@myhost:4001,iiop:[email protected]/NameService")),
-
- ?match({[[iiop,{1,1},"123.12.23.2",4001],
- [iiop,{1,1},"10.0.0.1",4001]], "NameService"},
- orber_cosnaming_utils:addresses(":[email protected]:4001,:[email protected]:4001/NameService")),
- ?match({[[iiop,{1,1},"123.12.23.2",4001],
- [iiop,{1,1},"10.0.0.1",4001]], []},
- orber_cosnaming_utils:addresses(":[email protected]:4001,:[email protected]:4001")),
- ?match({[[iiop,{1,0},"123.12.23.2",4001],
- [iiop,{1,1},"10.0.0.1",4001]], "NameService"},
- orber_cosnaming_utils:addresses(":123.12.23.2:4001,:[email protected]:4001/NameService")),
- ?match({[[iiop,{1,1},"123.12.23.2",4001],
- [iiop,{1,0},"10.0.0.1",4001]], "NameService"},
- orber_cosnaming_utils:addresses(":[email protected]:4001,:10.0.0.1:4001/NameService")),
- ?match({[[iiop,{1,1},"123.12.23.2",2809],
- [iiop,{1,1},"10.0.0.1",4001]], "NameService"},
- orber_cosnaming_utils:addresses(":[email protected],:[email protected]:4001/NameService")),
- ?match({[[iiop,{1,1},"123.12.23.2",4001],
- [iiop,{1,1},"10.0.0.1",2809]], "NameService"},
- orber_cosnaming_utils:addresses(":[email protected]:4001,:[email protected]/NameService")),
- ?match({[[iiop,{1,0},"123.12.23.2",2809],
- [iiop,{1,0},"10.0.0.1",2809]], "NameService"},
- orber_cosnaming_utils:addresses(":123.12.23.2,:10.0.0.1/NameService")),
- ?match({[[iiop,{1,0},"123.12.23.2",2809],
- [iiop,{1,0},"10.0.0.1",2809]], []},
- orber_cosnaming_utils:addresses(":123.12.23.2,:10.0.0.1/")),
- ?match({[[iiop,{1,0},"123.12.23.2",2809],
- [iiop,{1,0},"10.0.0.1",2809]], []},
- orber_cosnaming_utils:addresses("iiop:123.12.23.2,:10.0.0.1/")),
-
- [IP] = ?match([_], orber:host()),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_USE_ACL_INCOMING},
- {iiop_acl, [{tcp_in, IP++"/32"}]}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- ?match({'IOP_IOR',_,_},
- corba:string_to_object("corbaloc::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService")),
-% catch orber_test_lib:destroy_node(ServerNode, timeout),
-
- ok.
-
diff --git a/lib/orber/test/orber_firewall_ipv4_out_SUITE.erl b/lib/orber/test/orber_firewall_ipv4_out_SUITE.erl
deleted file mode 100644
index e061d0410d..0000000000
--- a/lib/orber/test/orber_firewall_ipv4_out_SUITE.erl
+++ /dev/null
@@ -1,229 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(orber_firewall_ipv4_out_SUITE).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/include/corba.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming.hrl").
--include_lib("orber/src/orber_iiop.hrl").
--include_lib("orber/src/ifr_objects.hrl").
--include("idl_output/orber_test_server.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming_NamingContextExt.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming_NamingContext.hrl").
-
--define(default_timeout, test_server:minutes(15)).
-
--define(match(ExpectedRes,Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- io:format("------ CORRECT RESULT ------~n~p~n",
- [AcTuAlReS]),
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~nRESULT: ~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2, cases/0,
- init_per_suite/1, end_per_suite/1,
- init_per_testcase/2, end_per_testcase/2,
- deny_port_api/1, deny_port_range_api/1, deny_host_api/1,
- allow_port_api/1, allow_port_range_api/1, allow_host_api/1,
- local_interface_api/1]).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- cases().
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%% NOTE - the fragment test cases must bu first since we explicitly set a request
-%% id. Otherwise, the request-id counter would be increased and we cannot know
-%% what it is.
-cases() ->
- [deny_port_api, deny_port_range_api, deny_host_api,
- allow_port_api, allow_port_range_api, allow_host_api,
- local_interface_api].
-
-
-init_per_testcase(_Case, Config) ->
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-init_per_suite(Config) ->
- if
- is_list(Config) ->
- orber:jump_start([{iiop_port, 0},
- {iiop_out_ports, {5980, 6000}}]),
- Config;
- true ->
- exit("Config not a list")
- end.
-
-end_per_suite(Config) ->
- orber:jump_stop(),
- Config.
-
-%%-----------------------------------------------------------------
-%% Incomming connections - Deny
-%%-----------------------------------------------------------------
-%% Deny Access due to invalid local port
-deny_port_api(_Config) ->
- [IP] = ?match([_], orber:host()),
- ServerPort = orber:iiop_port(),
- {ok, ClientNode, _ClientHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_USE_ACL_OUTGOING},
- {iiop_acl, [{tcp_out, IP++"/32#" ++ integer_to_list(ServerPort+10)}]}])),
- ?match({'EXCEPTION', #'CosNaming_NamingContextExt_InvalidAddress'{}},
- orber_test_lib:remote_apply(ClientNode, corba, string_to_object,
- ["corbaloc::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService"])),
-% catch orber_test_lib:destroy_node(ClientNode, timeout),
- ok.
-
-%% Deny Access due to invalid local port range
-deny_port_range_api(_Config) ->
- [IP] = ?match([_], orber:host()),
- ServerPort = orber:iiop_port(),
- {ok, ClientNode, _ClientHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_USE_ACL_OUTGOING},
- {iiop_acl, [{tcp_out, IP++"/32#"++integer_to_list(ServerPort+100)++ "/" ++ integer_to_list(ServerPort+120)}]}])),
- ?match({'EXCEPTION', #'CosNaming_NamingContextExt_InvalidAddress'{}},
- orber_test_lib:remote_apply(ClientNode, corba, string_to_object,
- ["corbaloc::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService"])),
-% catch orber_test_lib:destroy_node(ClientNode, timeout),
- ok.
-
-
-%% Deny Access due to invalid host
-deny_host_api(_Config) ->
- [IP] = ?match([_], orber:host()),
- {ok, ClientNode, _ClientHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_USE_ACL_OUTGOING},
- {iiop_acl, [{tcp_out, "123.123.123.123/32"}]}])),
- ServerPort = orber:iiop_port(),
- ?match({'EXCEPTION', #'CosNaming_NamingContextExt_InvalidAddress'{}},
- orber_test_lib:remote_apply(ClientNode, corba, string_to_object,
- ["corbaloc::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService"])),
-% catch orber_test_lib:destroy_node(ClientNode, timeout),
- ok.
-
-%%-----------------------------------------------------------------
-%% Incomming connections - Allow
-%%-----------------------------------------------------------------
-%% Allow Access due to valid local port range
-allow_port_api(_Config) ->
- [IP] = ?match([_], orber:host()),
- ServerPort = orber:iiop_port(),
- {ok, ClientNode, _ClientHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_USE_ACL_OUTGOING},
- {iiop_acl, [{tcp_out, IP++"/32#"++integer_to_list(ServerPort)}]}])),
- IOR =
- ?match({'IOP_IOR',_,_},
- orber_test_lib:remote_apply(ClientNode, corba, string_to_object,
- ["corbaloc::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService"])),
- ?match(false,
- orber_test_lib:remote_apply(ClientNode, corba_object, not_existent, [IOR])),
-% catch orber_test_lib:destroy_node(ClientNode, timeout),
- ok.
-
-%% Allow Access due to valid local port range
-allow_port_range_api(_Config) ->
- [IP] = ?match([_], orber:host()),
- ServerPort = orber:iiop_port(),
- {ok, ClientNode, _ClientHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_USE_ACL_OUTGOING},
- {iiop_acl, [{tcp_out, IP++"/32#" ++ integer_to_list(ServerPort-10) ++ "/" ++ integer_to_list(ServerPort+10)}]}])),
- IOR =
- ?match({'IOP_IOR',_,_},
- orber_test_lib:remote_apply(ClientNode, corba, string_to_object,
- ["corbaloc::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService"])),
- ?match(false,
- orber_test_lib:remote_apply(ClientNode, corba_object, not_existent, [IOR])),
-% catch orber_test_lib:destroy_node(ClientNode, timeout),
- ok.
-
-
-%% Allow Access due to valid host
-allow_host_api(_Config) ->
- [IP] = ?match([_], orber:host()),
- {ok, ClientNode, _ClientHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_USE_ACL_OUTGOING},
- {iiop_acl, [{tcp_out, IP++"/32"}]}])),
- ServerPort = orber:iiop_port(),
- IOR =
- ?match({'IOP_IOR',_,_},
- orber_test_lib:remote_apply(ClientNode, corba, string_to_object,
- ["corbaloc::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService"])),
- ?match(false,
- orber_test_lib:remote_apply(ClientNode, corba_object, not_existent, [IOR])),
-% catch orber_test_lib:destroy_node(ClientNode, timeout),
- ok.
-
-%% Allow Access due to valid host via a spcific interface
-local_interface_api(_Config) ->
- IP = orber_test_lib:get_host(),
- Loopback = orber_test_lib:get_loopback_interface(),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{iiop_port, 0},
- {iiop_out_ports, {5980, 6000}},
- {ip_address, IP}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
-
- {ok, ClientNode, _ClientHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_USE_ACL_OUTGOING},
- {iiop_acl, [{tcp_out, IP, [Loopback]}]}])),
- IOR =
- ?match({'IOP_IOR',_,_},
- orber_test_lib:remote_apply(ClientNode, corba, string_to_object,
- ["corbaloc::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService"])),
- ?match(false,
- orber_test_lib:remote_apply(ClientNode, corba_object, not_existent, [IOR])),
-% catch orber_test_lib:destroy_node(ClientNode, timeout),
- ok.
-
diff --git a/lib/orber/test/orber_firewall_ipv6_in_SUITE.erl b/lib/orber/test/orber_firewall_ipv6_in_SUITE.erl
deleted file mode 100644
index ee879f5ea8..0000000000
--- a/lib/orber/test/orber_firewall_ipv6_in_SUITE.erl
+++ /dev/null
@@ -1,315 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(orber_firewall_ipv6_in_SUITE).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/include/corba.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming.hrl").
--include_lib("orber/src/orber_iiop.hrl").
--include_lib("orber/src/ifr_objects.hrl").
--include("idl_output/orber_test_server.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming_NamingContextExt.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming_NamingContext.hrl").
-
--define(default_timeout, test_server:minutes(15)).
-
--define(match(ExpectedRes,Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- io:format("------ CORRECT RESULT ------~n~p~n",
- [AcTuAlReS]),
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~nRESULT: ~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2, cases/0,
- init_per_suite/1, end_per_suite/1,
- init_per_testcase/2, end_per_testcase/2,
- deny_port_api/1, deny_port_range_api/1, deny_host_api/1,
- deny_peerhost_api/1, allow_port_range_api/1,
- allow_host_api/1, allow_peerhost_api/1, check_address_api/1]).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- cases().
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%% NOTE - the fragment test cases must bu first since we explicitly set a request
-%% id. Otherwise, the request-id counter would be increased and we cannot know
-%% what it is.
-cases() ->
- [deny_port_api, deny_port_range_api, deny_host_api,
- deny_peerhost_api, allow_port_range_api, allow_host_api,
- allow_peerhost_api, check_address_api].
-
-
-init_per_testcase(_Case, Config) ->
- Dog=test_server:timetrap(?default_timeout),
- orber:jump_start([{iiop_port, 0},
- {iiop_out_ports, {5980, 6000}},
- {flags, ?ORB_ENV_USE_IPV6}]),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- orber:jump_stop(),
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-init_per_suite(Config) ->
- case orber_test_lib:version_ok() of
- true ->
- if
- is_list(Config) ->
- Config;
- true ->
- exit("Config not a list")
- end;
- Reason ->
- Reason
- end.
-
-end_per_suite(Config) ->
- Config.
-
-
-%%-----------------------------------------------------------------
-%% Incomming connections - Deny
-%%-----------------------------------------------------------------
-%% Deny Access due to invalid local port
-deny_port_api(_Config) ->
- [IP] = ?match([_], orber:host()),
- {ok, ServerNode, ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, (?ORB_ENV_USE_IPV6 bor
- ?ORB_ENV_USE_ACL_INCOMING)},
- {iiop_acl, [{tcp_in, IP++"/128#7000"}]}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- ?match({'EXCEPTION', #'CosNaming_NamingContextExt_InvalidAddress'{}},
- corba:string_to_object("corbaloc::1.2@"++ServerHost++":"++integer_to_list(ServerPort)++"/NameService")),
- % catch orber_test_lib:destroy_node(ServerNode, timeout),
- ok.
-
-%% Deny Access due to invalid local port range
-deny_port_range_api(_Config) ->
- [IP] = ?match([_], orber:host()),
- {ok, ServerNode, ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, (?ORB_ENV_USE_IPV6 bor
- ?ORB_ENV_USE_ACL_INCOMING)},
- {iiop_acl, [{tcp_in, IP++"/128#7000/8000"}]}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- ?match({'EXCEPTION', #'CosNaming_NamingContextExt_InvalidAddress'{}},
- corba:string_to_object("corbaloc::1.2@"++ServerHost++":"++integer_to_list(ServerPort)++"/NameService")),
-% catch orber_test_lib:destroy_node(ServerNode, timeout),
- ok.
-
-
-%% Deny Access due to invalid host
-deny_host_api(_Config) ->
- {ok, ServerNode, ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, (?ORB_ENV_USE_IPV6 bor
- ?ORB_ENV_USE_ACL_INCOMING)},
- {iiop_acl, [{tcp_in, "0:0:0:0:0:0:10.1.1.1/128"}]}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- ?match({'EXCEPTION', #'CosNaming_NamingContextExt_InvalidAddress'{}},
- corba:string_to_object("corbaloc::1.2@"++ServerHost++":"++integer_to_list(ServerPort)++"/NameService")),
-% catch orber_test_lib:destroy_node(ServerNode, timeout),
- ok.
-
-%% Deny Access due to invalid peer host
-deny_peerhost_api(_Config) ->
- [IP] = ?match([_], orber:host()),
- {ok, ServerNode, ServerHost} =
- ?match({ok,_,_},
- orber_test_lib:js_node([{flags, (?ORB_ENV_USE_IPV6 bor
- ?ORB_ENV_USE_ACL_INCOMING)},
- {iiop_acl, [{tcp_in, IP++"/128", ["0:0:0:0:0:0:10.1.1.1"]}]}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- ?match({'EXCEPTION', #'CosNaming_NamingContextExt_InvalidAddress'{}},
- corba:string_to_object("corbaloc::1.2@"++ServerHost++":"++integer_to_list(ServerPort)++"/NameService")),
-% catch orber_test_lib:destroy_node(ServerNode, timeout),
- ok.
-
-%%-----------------------------------------------------------------
-%% Incomming connections - Allow
-%%-----------------------------------------------------------------
-%% Allow Access due to valid local port range
-allow_port_range_api(_Config) ->
- [IP] = ?match([_], orber:host()),
- {ok, ServerNode, ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, (?ORB_ENV_USE_IPV6 bor
- ?ORB_ENV_USE_ACL_INCOMING)},
- {iiop_acl, [{tcp_in, IP++"/128#5980/6000"}]}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- io:format("ServerNode: ~p\nServerHost: ~p\n", [ServerNode, ServerHost]),
- IOR =
- ?match({'IOP_IOR',_,_},
- corba:string_to_object("corbaloc::1.2@"++ServerHost++":"++integer_to_list(ServerPort)++"/NameService")),
- ?match(false, corba_object:not_existent(IOR)),
-% catch orber_test_lib:destroy_node(ServerNode, timeout),
- ok.
-
-
-%% Allow Access due to valid host
-allow_host_api(_Config) ->
- [IP] = ?match([_], orber:host()),
- {ok, ServerNode, ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, (?ORB_ENV_USE_IPV6 bor
- ?ORB_ENV_USE_ACL_INCOMING)},
- {iiop_acl, [{tcp_in, IP++"/128"}]}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- IOR =
- ?match({'IOP_IOR',_,_},
- corba:string_to_object("corbaloc::1.2@"++ServerHost++":"++integer_to_list(ServerPort)++"/NameService")),
- ?match(false, corba_object:not_existent(IOR)),
-
-% catch orber_test_lib:destroy_node(ServerNode, timeout),
- ok.
-
-%% Allow Access due to valid host
-allow_peerhost_api(_Config) ->
- [IP] = ?match([_], orber:host()),
- {ok, ServerNode, ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, (?ORB_ENV_USE_IPV6 bor
- ?ORB_ENV_USE_ACL_INCOMING)},
- {iiop_acl, [{tcp_in, IP++"/128", [IP]}]}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- IOR =
- ?match({'IOP_IOR',_,_},
- corba:string_to_object("corbaloc::1.2@"++ServerHost++":"++integer_to_list(ServerPort)++"/NameService",
- [#'IOP_ServiceContext'
- {context_id=?ORBER_GENERIC_CTX_ID,
- context_data = {interface, IP}}])),
- ?match(false, corba_object:not_existent(IOR,
- [#'IOP_ServiceContext'
- {context_id=?ORBER_GENERIC_CTX_ID,
- context_data = {interface, IP}}])),
-
-% catch orber_test_lib:destroy_node(ServerNode, timeout),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test corbaloc strings
-%%-----------------------------------------------------------------
-check_address_api(_Config) ->
- ?match({[[iiop,{1,0},"0:0:0:0:0:FFFF:C02A:2A2A",2809]],"NameService"},
- orber_cosnaming_utils:addresses(":[0:0:0:0:0:FFFF:C02A:2A2A]/NameService")),
- ?match({[[iiop,{1,0},"0:0:0:0:0:FFFF:C02A:2A2A",2809]],[]},
- orber_cosnaming_utils:addresses(":[0:0:0:0:0:FFFF:C02A:2A2A]")),
- ?match({[[iiop,{1,2},"0:0:0:0:0:FFFF:C02A:2A2A",2809]],"NameService"},
- orber_cosnaming_utils:addresses(":1.2@[0:0:0:0:0:FFFF:C02A:2A2A]/NameService")),
- ?match({[[iiop,{1,0},"0:0:0:0:0:FFFF:C02A:2A2A",4001]],"NameService"},
- orber_cosnaming_utils:addresses(":[0:0:0:0:0:FFFF:C02A:2A2A]:4001/NameService")),
- ?match({[[iiop,{1,1},"0:0:0:0:0:FFFF:C02A:2A2A",4001]],"NameService"},
- orber_cosnaming_utils:addresses(":1.1@[0:0:0:0:0:FFFF:C02A:2A2A]:4001/NameService")),
- ?match({[[iiop,{1,1},"0:0:0:0:0:FFFF:C02A:2A2A",4001]],[]},
- orber_cosnaming_utils:addresses(":1.1@[0:0:0:0:0:FFFF:C02A:2A2A]:4001")),
- ?match({[[iiop,{1,1},"0:0:0:0:0:FFFF:C02A:2A2A",4001]],[]},
- orber_cosnaming_utils:addresses("iiop:1.1@[0:0:0:0:0:FFFF:C02A:2A2A]:4001")),
-
- ?match({[[iiop,{1,0},"0:0:0:0:0:FFFF:10.11.11.11",2809]],"NameService"},
- orber_cosnaming_utils:addresses(":[0:0:0:0:0:FFFF:10.11.11.11]/NameService")),
- ?match({[[iiop,{1,0},"0:0:0:0:0:FFFF:10.11.11.11",2809]],[]},
- orber_cosnaming_utils:addresses(":[0:0:0:0:0:FFFF:10.11.11.11]")),
- ?match({[[iiop,{1,2},"0:0:0:0:0:FFFF:10.11.11.11",2809]],"NameService"},
- orber_cosnaming_utils:addresses(":1.2@[0:0:0:0:0:FFFF:10.11.11.11]/NameService")),
- ?match({[[iiop,{1,0},"0:0:0:0:0:FFFF:10.11.11.11",4001]],"NameService"},
- orber_cosnaming_utils:addresses(":[0:0:0:0:0:FFFF:10.11.11.11]:4001/NameService")),
- ?match({[[iiop,{1,1},"0:0:0:0:0:FFFF:10.11.11.11",4001]],"NameService"},
- orber_cosnaming_utils:addresses(":1.1@[0:0:0:0:0:FFFF:10.11.11.11]:4001/NameService")),
- ?match({[[iiop,{1,1},"0:0:0:0:0:FFFF:10.11.11.11",4001]],[]},
- orber_cosnaming_utils:addresses(":1.1@[0:0:0:0:0:FFFF:10.11.11.11]:4001/")),
- ?match({[[iiop,{1,1},"0:0:0:0:0:FFFF:10.11.11.11",4001]],[]},
- orber_cosnaming_utils:addresses("iiop:1.1@[0:0:0:0:0:FFFF:10.11.11.11]:4001/")),
-
- ?match({[[iiop,{1,1},"myhost",4001]],[]},
- orber_cosnaming_utils:addresses("iiop:1.1@myhost:4001")),
- ?match({[[iiop,{1,1},"myhost.full.name",4001]],"NameService"},
- orber_cosnaming_utils:addresses("iiop:[email protected]:4001/NameService")),
- ?match({[[iiop,{1,1},"myhost",4001],
- [iiop,{1,1},"myhost.full.name",2809]],"NameService"},
- orber_cosnaming_utils:addresses("iiop:1.1@myhost:4001,iiop:[email protected]/NameService")),
-
- ?match({[[iiop,{1,1},"0:0:0:0:0:FFFF:10.11.11.11",4001],
- [iiop,{1,1},"0:0:0:0:0:FFFF:C02A:2A2A",4001]], "NameService"},
- orber_cosnaming_utils:addresses(":1.1@[0:0:0:0:0:FFFF:10.11.11.11]:4001,:1.1@[0:0:0:0:0:FFFF:C02A:2A2A]:4001/NameService")),
- ?match({[[iiop,{1,1},"0:0:0:0:0:FFFF:10.11.11.11",4001],
- [iiop,{1,1},"0:0:0:0:0:FFFF:C02A:2A2A",4001]], []},
- orber_cosnaming_utils:addresses(":1.1@[0:0:0:0:0:FFFF:10.11.11.11]:4001,:1.1@[0:0:0:0:0:FFFF:C02A:2A2A]:4001")),
- ?match({[[iiop,{1,0},"0:0:0:0:0:FFFF:10.11.11.11",4001],
- [iiop,{1,1},"0:0:0:0:0:FFFF:C02A:2A2A",4001]], "NameService"},
- orber_cosnaming_utils:addresses(":[0:0:0:0:0:FFFF:10.11.11.11]:4001,:1.1@[0:0:0:0:0:FFFF:C02A:2A2A]:4001/NameService")),
- ?match({[[iiop,{1,1},"0:0:0:0:0:FFFF:10.11.11.11",4001],
- [iiop,{1,0},"0:0:0:0:0:FFFF:C02A:2A2A",4001]], "NameService"},
- orber_cosnaming_utils:addresses(":1.1@[0:0:0:0:0:FFFF:10.11.11.11]:4001,:[0:0:0:0:0:FFFF:C02A:2A2A]:4001/NameService")),
- ?match({[[iiop,{1,1},"0:0:0:0:0:FFFF:10.11.11.11",2809],
- [iiop,{1,1},"0:0:0:0:0:FFFF:C02A:2A2A",4001]], "NameService"},
- orber_cosnaming_utils:addresses(":1.1@[0:0:0:0:0:FFFF:10.11.11.11],:1.1@[0:0:0:0:0:FFFF:C02A:2A2A]:4001/NameService")),
- ?match({[[iiop,{1,1},"0:0:0:0:0:FFFF:10.11.11.11",4001],
- [iiop,{1,1},"0:0:0:0:0:FFFF:C02A:2A2A",2809]], "NameService"},
- orber_cosnaming_utils:addresses(":1.1@[0:0:0:0:0:FFFF:10.11.11.11]:4001,:1.1@[0:0:0:0:0:FFFF:C02A:2A2A]/NameService")),
- ?match({[[iiop,{1,0},"0:0:0:0:0:FFFF:10.11.11.11",2809],
- [iiop,{1,0},"0:0:0:0:0:FFFF:C02A:2A2A",2809]], "NameService"},
- orber_cosnaming_utils:addresses(":[0:0:0:0:0:FFFF:10.11.11.11],:[0:0:0:0:0:FFFF:C02A:2A2A]/NameService")),
- ?match({[[iiop,{1,0},"0:0:0:0:0:FFFF:10.11.11.11",2809],
- [iiop,{1,0},"0:0:0:0:0:FFFF:C02A:2A2A",2809]], []},
- orber_cosnaming_utils:addresses(":[0:0:0:0:0:FFFF:10.11.11.11],:[0:0:0:0:0:FFFF:C02A:2A2A]/")),
- ?match({[[iiop,{1,0},"0:0:0:0:0:FFFF:10.11.11.11",2809],
- [iiop,{1,0},"0:0:0:0:0:FFFF:C02A:2A2A",2809]], []},
- orber_cosnaming_utils:addresses("iiop:[0:0:0:0:0:FFFF:10.11.11.11],:[0:0:0:0:0:FFFF:C02A:2A2A]/")),
-
- [IP] = ?match([_], orber:host()),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, (?ORB_ENV_USE_IPV6 bor
- ?ORB_ENV_USE_ACL_INCOMING)},
- {iiop_acl, [{tcp_in, IP++"/128"}]}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- ?match({'IOP_IOR',_,_},
- corba:string_to_object("corbaloc::1.2@["++IP++"]:"++integer_to_list(ServerPort)++"/NameService")),
-% catch orber_test_lib:destroy_node(ServerNode, timeout),
- ok.
-
-
diff --git a/lib/orber/test/orber_firewall_ipv6_out_SUITE.erl b/lib/orber/test/orber_firewall_ipv6_out_SUITE.erl
deleted file mode 100644
index 0fe305aeb5..0000000000
--- a/lib/orber/test/orber_firewall_ipv6_out_SUITE.erl
+++ /dev/null
@@ -1,236 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(orber_firewall_ipv6_out_SUITE).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/include/corba.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming.hrl").
--include_lib("orber/src/orber_iiop.hrl").
--include_lib("orber/src/ifr_objects.hrl").
--include("idl_output/orber_test_server.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming_NamingContextExt.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming_NamingContext.hrl").
-
--define(default_timeout, test_server:minutes(15)).
-
--define(match(ExpectedRes,Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- io:format("------ CORRECT RESULT ------~n~p~n",
- [AcTuAlReS]),
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~nRESULT: ~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2, cases/0,
- init_per_suite/1, end_per_suite/1,
- init_per_testcase/2, end_per_testcase/2,
- deny_port_api/1, deny_port_range_api/1, deny_host_api/1,
- allow_port_api/1, allow_port_range_api/1, allow_host_api/1,
- local_interface_api/1]).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- cases().
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%% NOTE - the fragment test cases must bu first since we explicitly set a request
-%% id. Otherwise, the request-id counter would be increased and we cannot know
-%% what it is.
-cases() ->
- [deny_port_api, deny_port_range_api, deny_host_api,
- allow_port_api, allow_port_range_api, allow_host_api,
- local_interface_api].
-
-
-init_per_testcase(_Case, Config) ->
- Dog=test_server:timetrap(?default_timeout),
- orber:jump_start([{iiop_port, 0},
- {iiop_out_ports, {5980, 6000}},
- {flags, ?ORB_ENV_USE_IPV6}]),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- orber:jump_stop(),
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-init_per_suite(Config) ->
- case orber_test_lib:version_ok() of
- true ->
- if
- is_list(Config) ->
- Config;
- true ->
- exit("Config not a list")
- end;
- Reason ->
- Reason
- end.
-
-end_per_suite(Config) ->
- Config.
-
-
-%%-----------------------------------------------------------------
-%% Incomming connections - Deny
-%%-----------------------------------------------------------------
-%% Deny Access due to invalid local port
-deny_port_api(_Config) ->
- [IP] = ?match([_], orber:host()),
- ServerPort = orber:iiop_port(),
- {ok, ServerNode, ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, (?ORB_ENV_USE_IPV6 bor
- ?ORB_ENV_USE_ACL_OUTGOING)},
- {iiop_acl, [{tcp_out, IP++"/128#" ++ integer_to_list(ServerPort+10)}]}])),
- ?match({'EXCEPTION', #'CosNaming_NamingContextExt_InvalidAddress'{}},
- orber_test_lib:remote_apply(ServerNode, corba, string_to_object,
- ["corbaloc::1.2@"++ServerHost++":"++integer_to_list(ServerPort)++"/NameService"])),
-% catch orber_test_lib:destroy_node(ServerNode, timeout),
- ok.
-
-%% Deny Access due to invalid local port range
-deny_port_range_api(_Config) ->
- [IP] = ?match([_], orber:host()),
- ServerPort = orber:iiop_port(),
- {ok, ServerNode, ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, (?ORB_ENV_USE_IPV6 bor
- ?ORB_ENV_USE_ACL_OUTGOING)},
- {iiop_acl, [{tcp_out, IP++"/128#"++integer_to_list(ServerPort+100)++ "/" ++ integer_to_list(ServerPort+120)}]}])),
- ?match({'EXCEPTION', #'CosNaming_NamingContextExt_InvalidAddress'{}},
- orber_test_lib:remote_apply(ServerNode, corba, string_to_object,
- ["corbaloc::1.2@"++ServerHost++":"++integer_to_list(ServerPort)++"/NameService"])),
-% catch orber_test_lib:destroy_node(ServerNode, timeout),
- ok.
-
-
-%% Deny Access due to invalid host
-deny_host_api(_Config) ->
- {ok, ServerNode, ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, (?ORB_ENV_USE_IPV6 bor
- ?ORB_ENV_USE_ACL_OUTGOING)},
- {iiop_acl, [{tcp_out, "0:0:0:0:0:0:10.1.1.1/128"}]}])),
- ServerPort = orber:iiop_port(),
- ?match({'EXCEPTION', #'CosNaming_NamingContextExt_InvalidAddress'{}},
- orber_test_lib:remote_apply(ServerNode, corba, string_to_object,
- ["corbaloc::1.2@"++ServerHost++":"++integer_to_list(ServerPort)++"/NameService"])),
-% catch orber_test_lib:destroy_node(ServerNode, timeout),
- ok.
-
-%%-----------------------------------------------------------------
-%% Incomming connections - Allow
-%%-----------------------------------------------------------------
-%% Allow Access due to valid local port
-allow_port_api(_Config) ->
- [IP] = ?match([_], orber:host()),
- ServerPort = orber:iiop_port(),
- {ok, ServerNode, ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, (?ORB_ENV_USE_IPV6 bor
- ?ORB_ENV_USE_ACL_OUTGOING)},
- {iiop_acl, [{tcp_out, IP++"/128#" ++ integer_to_list(ServerPort)}]}])),
- IOR =
- ?match({'IOP_IOR',_,_},
- orber_test_lib:remote_apply(ServerNode, corba, string_to_object,
- ["corbaloc::1.2@"++ServerHost++":"++integer_to_list(ServerPort)++"/NameService"])),
- ?match(false,
- orber_test_lib:remote_apply(ServerNode, corba_object, not_existent, [IOR])),
-% catch orber_test_lib:destroy_node(ServerNode, timeout),
- ok.
-
-%% Allow Access due to valid local port range
-allow_port_range_api(_Config) ->
- [IP] = ?match([_], orber:host()),
- ServerPort = orber:iiop_port(),
- {ok, ServerNode, ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, (?ORB_ENV_USE_IPV6 bor
- ?ORB_ENV_USE_ACL_OUTGOING)},
- {iiop_acl, [{tcp_out, IP++"/128#" ++ integer_to_list(ServerPort-10) ++ "/" ++ integer_to_list(ServerPort+10)}]}])),
- IOR =
- ?match({'IOP_IOR',_,_},
- orber_test_lib:remote_apply(ServerNode, corba, string_to_object,
- ["corbaloc::1.2@"++ServerHost++":"++integer_to_list(ServerPort)++"/NameService"])),
- ?match(false,
- orber_test_lib:remote_apply(ServerNode, corba_object, not_existent, [IOR])),
-% catch orber_test_lib:destroy_node(ServerNode, timeout),
- ok.
-
-
-%% Allow Access due to valid host
-allow_host_api(_Config) ->
- [IP] = ?match([_], orber:host()),
- {ok, ServerNode, ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, (?ORB_ENV_USE_IPV6 bor
- ?ORB_ENV_USE_ACL_OUTGOING)},
- {iiop_acl, [{tcp_out, IP}]}])),
- ServerPort = orber:iiop_port(),
- IOR =
- ?match({'IOP_IOR',_,_},
- orber_test_lib:remote_apply(ServerNode, corba, string_to_object,
- ["corbaloc::1.2@"++ServerHost++":"++integer_to_list(ServerPort)++"/NameService"])),
- ?match(false,
- orber_test_lib:remote_apply(ServerNode, corba_object, not_existent, [IOR])),
-% catch orber_test_lib:destroy_node(ServerNode, timeout),
- ok.
-
-%% Allow Access due to valid host via a spcific interface
-local_interface_api(_Config) ->
- [IP] = ?match([_], orber:host()),
- {ok, ServerNode, ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, (?ORB_ENV_USE_IPV6 bor
- ?ORB_ENV_USE_ACL_OUTGOING)},
- {iiop_acl, [{tcp_out, IP, [IP]}]}])),
- ServerPort = orber:iiop_port(),
- IOR =
- ?match({'IOP_IOR',_,_},
- orber_test_lib:remote_apply(ServerNode, corba, string_to_object,
- ["corbaloc::1.2@"++ServerHost++":"++integer_to_list(ServerPort)++"/NameService"])),
- ?match(false,
- orber_test_lib:remote_apply(ServerNode, corba_object, not_existent, [IOR])),
-% catch orber_test_lib:destroy_node(ServerNode, timeout),
- ok.
-
diff --git a/lib/orber/test/orber_nat_SUITE.erl b/lib/orber/test/orber_nat_SUITE.erl
deleted file mode 100644
index 029a5e529b..0000000000
--- a/lib/orber/test/orber_nat_SUITE.erl
+++ /dev/null
@@ -1,364 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(orber_nat_SUITE).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/include/corba.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming.hrl").
--include_lib("orber/src/orber_iiop.hrl").
--include_lib("orber/src/ifr_objects.hrl").
--include("idl_output/orber_test_server.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming_NamingContextExt.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming_NamingContext.hrl").
-
-
--define(default_timeout, test_server:minutes(15)).
-
--define(match(ExpectedRes,Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- io:format("------ CORRECT RESULT ------~n~p~n",
- [AcTuAlReS]),
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~nRESULT: ~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2, cases/0,
- init_per_suite/1, end_per_suite/1,
- init_per_testcase/2, end_per_testcase/2,
- nat_ip_address/1, nat_ip_address_multiple/1,
- 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/1, nat_iiop_ssl_port_local/1]).
-
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- cases().
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-cases() ->
- [nat_ip_address,
- nat_ip_address_multiple,
- nat_ip_address_local,
- nat_iiop_port,
- nat_iiop_port_local,
- nat_ip_address_local_local,
- nat_iiop_port_local_local,
- nat_iiop_ssl_port,
- nat_iiop_ssl_port_local].
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-init_per_testcase(TC, Config)
- when TC =:= nat_iiop_ssl_port;
- TC =:= nat_iiop_ssl_port_local ->
- case proplists:get_value(crypto_started, Config) of
- true ->
- case orber_test_lib:ssl_version() of
- no_ssl ->
- {skip,"SSL not installed!"};
- _ ->
- init_per_testcase(dummy_tc, Config)
- end;
- false ->
- {skip, "Crypto did not start"}
- end;
-init_per_testcase(_Case, Config) ->
- Path = code:which(?MODULE),
- code:add_pathz(filename:join(filename:dirname(Path), "idl_output")),
- Dog=test_server:timetrap(?default_timeout),
- orber:jump_start([{iiop_port, 0},
- {flags, 0}]),
- oe_orber_test_server:oe_register(),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- oe_orber_test_server:oe_unregister(),
- orber:jump_stop(),
- Path = code:which(?MODULE),
- code:del_path(filename:join(filename:dirname(Path), "idl_output")),
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-init_per_suite(Config) ->
- if
- is_list(Config) ->
- try crypto:start() of
- ok ->
- [{crypto_started, true} | Config]
- catch _:_ ->
- [{crypto_started, false} | Config]
- end;
- true ->
- exit("Config not a list")
- end.
-
-end_per_suite(Config) ->
- application:stop(crypto),
- Config.
-
-%%-----------------------------------------------------------------
-%% API tests for NAT
-%%-----------------------------------------------------------------
-%% These case test if the server ORB use the correct
-%% interface when exporting IOR:s
-nat_ip_address(_Config) ->
- IP = orber_test_lib:get_host(),
- Loopback = orber_test_lib:get_loopback_interface(),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_ENABLE_NAT},
- {nat_ip_address, Loopback}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- IOR = ?match(#'IOP_IOR'{},
- corba:string_to_object("corbaloc::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService")),
- ?match({'external', {Loopback, ServerPort, _ObjectKey, _Counter, _TP, _NewHD}},
- iop_ior:get_key(IOR)),
- ok.
-
-nat_ip_address_multiple(_Config) ->
- IP = orber_test_lib:get_host(),
-
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_ENABLE_NAT},
- {nat_ip_address, {multiple, ["10.0.0.1"]}}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- IOR = ?match(#'IOP_IOR'{},
- corba:string_to_object("corbaloc::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService")),
- ?match({'external', {"10.0.0.1", ServerPort, _ObjectKey, _Counter, _TP, _NewHD}},
- iop_ior:get_key(IOR)),
- ok.
-
-nat_ip_address_local(_Config) ->
- IP = orber_test_lib:get_host(),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_ENABLE_NAT},
- {nat_ip_address, {local, "10.0.0.1", [{IP, "127.0.0.1"}]}}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- IOR = ?match(#'IOP_IOR'{},
- corba:string_to_object("corbaloc::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService")),
- ?match({'external', {"10.0.0.1", ServerPort, _ObjectKey, _Counter, _TP, _NewHD}},
- iop_ior:get_key(IOR)),
- ok.
-
-nat_ip_address_local_local(_Config) ->
- IP = orber_test_lib:get_host(),
- Loopback = orber_test_lib:get_loopback_interface(),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags,
- (?ORB_ENV_LOCAL_INTERFACE bor
- ?ORB_ENV_ENABLE_NAT)},
- {nat_ip_address, {local, "10.0.0.1", [{IP, "10.0.0.2"}]}}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- IOR1 = ?match(#'IOP_IOR'{},
- corba:string_to_object("corbaloc::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService")),
- ?match({'external', {"10.0.0.2", ServerPort, _ObjectKey, _Counter, _TP, _NewHD}},
- iop_ior:get_key(IOR1)),
- IOR2 = ?match(#'IOP_IOR'{},
- corba:string_to_object("corbaloc::1.2@"++Loopback++":"++integer_to_list(ServerPort)++"/NameService")),
- ?match({'external', {"10.0.0.1", ServerPort, _ObjectKey, _Counter, _TP, _NewHD}},
- iop_ior:get_key(IOR2)),
- ok.
-
-nat_iiop_port(_Config) ->
- IP = orber_test_lib:get_host(),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_ENABLE_NAT},
- {nat_iiop_port, 42}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- IOR = ?match(#'IOP_IOR'{},
- corba:string_to_object("corbaloc::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService")),
- ?match({'external', {_IP, 42, _ObjectKey, _Counter, _TP, _NewHD}},
- iop_ior:get_key(IOR)),
- ok.
-
-nat_iiop_port_local(_Config) ->
- IP = orber_test_lib:get_host(),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags, ?ORB_ENV_ENABLE_NAT},
- {nat_iiop_port, {local, 42, [{4001, 43}]}}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- IOR = ?match(#'IOP_IOR'{},
- corba:string_to_object("corbaloc::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService")),
- ?match({'external', {_IP, 42, _ObjectKey, _Counter, _TP, _NewHD}},
- iop_ior:get_key(IOR)),
- ok.
-
-nat_iiop_port_local_local(_Config) ->
- IP = orber_test_lib:get_host(),
- Loopback = orber_test_lib:get_loopback_interface(),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node([{flags,
- (?ORB_ENV_LOCAL_INTERFACE bor
- ?ORB_ENV_ENABLE_NAT)},
- {ip_address, IP}])),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- orber_test_lib:remote_apply(ServerNode, orber_env, configure_override, [nat_iiop_port, {local, 42, [{ServerPort, 43}]}]),
- IOR1 = ?match(#'IOP_IOR'{},
- corba:string_to_object("corbaloc::1.2@"++IP++":"++integer_to_list(ServerPort)++"/NameService")),
- ?match({'external', {IP, 43, _ObjectKey, _Counter, _TP, _NewHD}},
- iop_ior:get_key(IOR1)),
- {ok, Ref} = ?match({ok, _},
- orber_test_lib:remote_apply(ServerNode, orber,
- add_listen_interface,
- [Loopback, normal, 10088])),
- IOR2 = ?match(#'IOP_IOR'{},
- corba:string_to_object("corbaloc::1.2@"++Loopback++":10088/NameService")),
- ?match({'external', {IP, 42, _ObjectKey, _Counter, _TP, _NewHD}},
- iop_ior:get_key(IOR2)),
- ?match(ok,
- orber_test_lib:remote_apply(ServerNode, orber,
- remove_listen_interface, [Ref])),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% API tests for ORB to ORB, ssl security depth 1
-%%-----------------------------------------------------------------
-%% SECURE MULTI ORB API tests (SSL depth 1)
-%% Make sure NAT works for SSL
-nat_iiop_ssl_port(_Config) ->
-
- IP = orber_test_lib:get_host(),
- ServerOptions = orber_test_lib:get_options(iiop_ssl, server,
- 1, [{iiop_ssl_port, 0},
- {flags, ?ORB_ENV_ENABLE_NAT},
- {ip_address, IP}]),
- ClientOptions = orber_test_lib:get_options(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(_Config) ->
-
- IP = orber_test_lib:get_host(),
- ServerOptions = orber_test_lib:get_options(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(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.
-
diff --git a/lib/orber/test/orber_test.idl b/lib/orber/test/orber_test.idl
deleted file mode 100644
index 852daabedf..0000000000
--- a/lib/orber/test/orber_test.idl
+++ /dev/null
@@ -1,96 +0,0 @@
-//
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1997-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-//
-module Module
-{
-
- enum Enum {horse, pig, cow};
-
- struct Struct0 {
- long l;
- short s;
- char c;
- };
-
- struct Struct1 {
- string s;
- unsigned short us;
- unsigned long ul;
- };
-
- struct Struct2 {
- sequence <long> long_sequence;
- Enum e;
- octet o;
- };
-
- struct HEADER {
- short EID;
- short NDW;
- short SSID;
- };
-
- enum Enum1 {orange,banana, apple};
-
- union Union switch (short) {
- case 0: short First;
- case 1: string Second;
- case 2: char Third;
- };
-
- union Union1 switch (Enum){
- case horse: short horse;
- case pig: sequence <string> Second;
- case cow: Enum1 Third;
- };
-
- union Union2 switch (Enum){
- case horse: long a[10];
- case pig: Union u;
- case cow: Union1 u1;
- };
-
- exception Except1 {
- string why;
- sequence <string> rest_of_name;
- };
-
- exception Except2 {
- Enum1 e;
- Struct2 s;
- };
-
- exception Except3 {
- Union1 u;
- unsigned short s;
- Object o ;
- };
-
- exception Except4 {};
-
- interface I1 {
- void a();
- };
-
- interface I2 {
- void a();
- };
-
-};
-
diff --git a/lib/orber/test/orber_test_lib.erl b/lib/orber/test/orber_test_lib.erl
deleted file mode 100644
index 9b19c4bc4e..0000000000
--- a/lib/orber/test/orber_test_lib.erl
+++ /dev/null
@@ -1,1564 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(orber_test_lib).
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/include/corba.hrl").
--include_lib("orber/include/ifr_types.hrl").
--include_lib("orber/src/orber_iiop.hrl").
--include("idl_output/orber_test_server.hrl").
--include_lib("orber/COSS/CosNaming/CosNaming.hrl").
-
--define(match(ExpectedRes,Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- io:format("------ CORRECT RESULT ------~n~p~n",
- [AcTuAlReS]),
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~nRESULT: ~p~n",
- [AcTuAlReS]),
- ?line exit(AcTuAlReS)
- end
- end()).
-
--export([js_node/2,
- js_node/1,
- js_node/0,
- slave_sup/0,
- remote_apply/4,
- install_test_data/1,
- light_tests/3,
- uninstall_test_data/1,
- destroy_node/2,
- lookup/2,
- alternate_iiop_address/2,
- create_alternate_iiop_address/2,
- alternate_ssl_iiop_address/3,
- create_alternate_ssl_iiop_address/3,
- test_coding/1,
- test_coding/2,
- corba_object_tests/2,
- timeouts/3,
- precond/3,
- postcond/4,
- oe_get_interface/0,
- create_components_IOR/1,
- get_options_old/2,
- get_options_old/3,
- get_options_old/4,
- get_options/2,
- get_options/3,
- get_options/4,
- version_ok/0,
- ssl_version/0,
- get_loopback_interface/0,
- get_loopback_interface/1,
- get_host/0,
- get_host/1]).
-
-%% Interceptor functions.
--export([new_out_connection/3,
- new_in_connection/3,
- closed_in_connection/1,
- closed_out_connection/1,
- in_request_encoded/6,
- in_reply_encoded/6,
- out_reply_encoded/6,
- out_request_encoded/6,
- in_request/6,
- in_reply/6,
- out_reply/6,
- out_request/6]).
-
-%%------------------------------------------------------------
-%% function : ssl_version
-%% Arguments:
-%% Returns : integer()
-%% Effect :
-%%
-%%------------------------------------------------------------
-ssl_version() ->
- try
- ssl:module_info(),
- case catch erlang:system_info(otp_release) of
- Version when is_list(Version) ->
- if
- "R12B" < Version ->
- 3;
- true ->
- 2
- end;
- _ ->
- 2
- end
- catch error:undef ->
- no_ssl
- end.
-
-%%------------------------------------------------------------
-%% function : version_ok
-%% Arguments:
-%% Returns : true | {skipped, Reason}
-%% Effect :
-%%
-%%------------------------------------------------------------
-version_ok() ->
- {ok, Hostname} = inet:gethostname(),
- case inet:getaddr(Hostname, inet6) of
- {error,nxdomain} ->
- {skipped, "Inet cannot handle IPv6"};
- _ ->
- case inet:getaddr("0:0:0:0:0:FFFF:127.0.0.1", inet6) of
- {error,nxdomain} ->
- {skipped, "Inet cannot handle IPv6"};
- _ ->
- case gen_tcp:listen(0, [{reuseaddr, true}, inet6]) of
- {ok, LSock} ->
- {ok, Port} = inet:port(LSock),
- case gen_tcp:connect(Hostname, Port, [inet6]) of
- {error, _} ->
- gen_tcp:close(LSock),
- {skipped, "Inet cannot handle IPv6"};
- {ok, Socket} ->
- gen_tcp:close(Socket),
- gen_tcp:close(LSock),
- true
- end;
- {error, _} ->
- {skipped, "Inet cannot handle IPv6"}
- end
- end
- end.
-
-%%------------------------------------------------------------
-%% function : get_host
-%% Arguments: Family - inet | inet6
-%% Returns : string()
-%% Effect :
-%%
-%%------------------------------------------------------------
-get_host() ->
- get_host(inet).
-get_host(Family) ->
- case os:type() of
- {win32, _} ->
- case os:version() of
- {6, _, _} when Family == inet ->
- "127.0.0.1";
- {6, _, _} ->
- "0:0:0:0:0:0:0:0001";
- _ ->
- [IP] = ?match([_], orber:host()),
- IP
- end;
- _ ->
- [IP] = ?match([_], orber:host()),
- IP
- end.
-
-%%------------------------------------------------------------
-%% function : get_loopback_interface
-%% Arguments: Family - inet | inet6
-%% Returns : string()
-%% Effect :
-%%
-%%------------------------------------------------------------
-get_loopback_interface() ->
- get_loopback_interface(inet).
-get_loopback_interface(Family) ->
- case os:type() of
- {win32, _} ->
- case os:version() of
- {6, _, _} when Family == inet ->
- "127.0.0.2";
- {6, _, _} ->
- "0:0:0:0:0:0:0:0002";
- _ when Family == inet ->
- "127.0.0.1";
- _ ->
- "0:0:0:0:0:0:0:0001"
- end;
- _ when Family == inet ->
- "127.0.0.1";
- _ ->
- "0:0:0:0:0:0:0:0001"
- end.
-
-%%------------------------------------------------------------
-%% function : js_node/4
-%% Arguments: Port - which iiop_port (integer())
-%% InitOptions - [{Key, Value}]
-%% {Type, StartOptions} - {lightweight, [{Key, Value}]}
-%% Returns : {ok, Node} | {error, _}
-%% Effect : Starts a new slave-node with given (optinally)
-%% extra arguments. If fails it retries 'Retries' times.
-%%------------------------------------------------------------
-js_node() ->
- js_node([], []).
-
-js_node(InitOptions) when is_list(InitOptions) ->
- js_node(InitOptions, []).
-
-js_node(InitOptions, StartOptions) when is_list(InitOptions) ->
- {A,B,C} = erlang:timestamp(),
- [_, Host] = string:tokens(atom_to_list(node()), [$@]),
- _NewInitOptions = check_options(InitOptions),
- js_node_helper(Host, 0, lists:concat([A,'_',B,'_',C]),
- InitOptions, 10, StartOptions).
-
-js_node_helper(Host, Port, Name, Options, Retries, StartOptions) ->
- case starter(Host, Name, create_paths()) of
- {ok, NewNode} ->
- case net_adm:ping(NewNode) of
- pong ->
- start_ssl(lists:member({secure, ssl}, Options), NewNode),
- {ok, Cwd} = file:get_cwd(),
- Path = code:get_path(),
- ok = rpc:call(NewNode, file, set_cwd, [Cwd]),
- true = rpc:call(NewNode, code, set_path, [Path]),
- rpc:call(NewNode, application, load, [orber]),
- ok = rpc:call(NewNode, corba, orb_init,
- [[{iiop_port, Port},
- {orber_debug_level, 10}|Options]]),
- start_orber(StartOptions, NewNode),
- spawn_link(NewNode, ?MODULE, slave_sup, []),
- rpc:multicall([node() | nodes()], global, sync, []),
- ok = rpc:call(NewNode, orber, info, [io]),
- {ok, NewNode, Host};
- _ ->
- {error, "net_adm:ping(Node) failed"}
- end;
- {error, Reason} when Retries == 0 ->
- {error, Reason};
- {error, Reason} ->
- io:format("Could not start slavenode ~p:~p due to: ~p~n",
- [Host, Port, Reason]),
- timer:sleep(500),
- js_node_helper(Host, Port, Name, Options, Retries-1, StartOptions)
- end.
-
-check_options(Options) ->
- case {os:type(), os:version()} of
- {{win32, _}, {6, _, _}} ->
- %% Vista, need to run additional checks.
- case {orber_tb:keysearch(ip_address, Options),
- orber_tb:keysearch(flags, Options, 0)} of
- {undefined, Flags} ->
- case ?ORB_FLAG_TEST(Flags, ?ORB_ENV_USE_IPV6) of
- true ->
- [{ip_address, get_host(inet6)}|Options];
- false ->
- [{ip_address, get_host(inet)}|Options]
- end;
- _ ->
- Options
- end;
- _ ->
- Options
- end.
-
-starter(Host, Name, Args) ->
- io:format("slave:start_link(~p,~p,~p).~n",[Host,Name,Args]),
- slave:start_link(Host, Name, Args).
-
-slave_sup() ->
- process_flag(trap_exit, true),
- receive
- {'EXIT', _, _} -> ignore
- end.
-
-start_ssl(true, Node) ->
- rpc:call(Node, ssl, start, []),
- rpc:call(Node, crypto, start, []);
-start_ssl(_, _) ->
- ok.
-
-start_orber({lightweight, Options}, Node) ->
- ok = rpc:call(Node, mnesia, start, []),
- ok = rpc:call(Node, orber, start_lightweight, [Options]);
-start_orber(lightweight, Node) ->
- ok = rpc:call(Node, mnesia, start, []),
- ok = rpc:call(Node, orber, start_lightweight, []);
-start_orber(_, Node) ->
- ok = rpc:call(Node, orber, jump_start, []).
-
-%%-----------------------------------------------------------------
-%% Type - ssl | iiop_ssl
-%% Role - 'server' | 'client'
-%% Options - [{Key, Value}]
-%%-----------------------------------------------------------------
-get_options_old(Type, Role) ->
- get_options_old(Type, Role, 2, []).
-
-get_options_old(ssl, Role, Level) ->
- get_options_old(ssl, Role, Level, []).
-
-get_options_old(ssl, Role, 2, Options) ->
- Dir = filename:join([code:lib_dir(ssl), "examples", "certs", "etc"]),
- [{depth, 2},
- {verify, 2},
- {keyfile, filename:join([Dir, Role, "key.pem"])},
- {cacertfile, filename:join([Dir, Role, "cacerts.pem"])},
- {certfile, filename:join([Dir, Role, "cert.pem"])} |Options];
-get_options_old(iiop_ssl, _Role, 2, Options) ->
- Dir = filename:join([code:lib_dir(ssl), "examples", "certs", "etc"]),
- [{ssl_server_depth, 2},
- {ssl_server_verify, 2},
- {ssl_server_certfile, filename:join([Dir, "server", "cert.pem"])},
- {ssl_server_cacertfile, filename:join([Dir, "server", "cacerts.pem"])},
- {ssl_server_keyfile, filename:join([Dir, "server", "key.pem"])},
- {ssl_client_depth, 2},
- {ssl_client_verify, 2},
- {ssl_client_certfile, filename:join([Dir, "client", "cert.pem"])},
- {ssl_client_cacertfile, filename:join([Dir, "client", "cacerts.pem"])},
- {ssl_client_keyfile, filename:join([Dir, "client", "key.pem"])},
- {secure, ssl} |Options];
-get_options_old(iiop_ssl, _Role, 1, Options) ->
- Dir = filename:join([code:lib_dir(ssl), "examples", "certs", "etc"]),
- [{ssl_server_depth, 1},
- {ssl_server_verify, 0},
- {ssl_server_certfile, filename:join([Dir, "server", "cert.pem"])},
- {ssl_server_cacertfile, filename:join([Dir, "server", "cacerts.pem"])},
- {ssl_server_keyfile, filename:join([Dir, "server", "key.pem"])},
- {ssl_client_depth, 1},
- {ssl_client_verify, 0},
- {ssl_client_certfile, filename:join([Dir, "client", "cert.pem"])},
- {ssl_client_cacertfile, filename:join([Dir, "client", "cacerts.pem"])},
- {ssl_client_keyfile, filename:join([Dir, "client", "key.pem"])},
- {secure, ssl} |Options].
-
-get_options(Type, Role) ->
- get_options(Type, Role, 2, []).
-
-get_options(ssl, Role, Level) ->
- get_options(ssl, Role, Level, []).
-
-get_options(ssl, Role, 2, Options) ->
- Dir = filename:join([code:lib_dir(ssl), "examples", "certs", "etc"]),
- Options1 = [{depth, 2},
- {verify, 2},
- {keyfile, filename:join([Dir, Role, "key.pem"])},
- {cacertfile, filename:join([Dir, Role, "cacerts.pem"])},
- {certfile, filename:join([Dir, Role, "cert.pem"])} |Options],
- case Role of
- client ->
- [{server_name_indication, disable} |Options1];
- server ->
- Options1
- end;
-get_options(iiop_ssl, _Role, 2, Options) ->
- Dir = filename:join([code:lib_dir(ssl), "examples", "certs", "etc"]),
- [{ssl_server_options, [{depth, 2},
- {verify, 2},
- {certfile, filename:join([Dir, "server", "cert.pem"])},
- {cacertfile, filename:join([Dir, "server", "cacerts.pem"])},
- {keyfile, filename:join([Dir, "server", "key.pem"])}]},
- {ssl_client_options, [{depth, 2},
- {verify, 2},
- {server_name_indication, disable},
- {certfile, filename:join([Dir, "client", "cert.pem"])},
- {cacertfile, filename:join([Dir, "client", "cacerts.pem"])},
- {keyfile, filename:join([Dir, "client", "key.pem"])}]},
- {secure, ssl} |Options];
-get_options(iiop_ssl, _Role, 1, Options) ->
- Dir = filename:join([code:lib_dir(ssl), "examples", "certs", "etc"]),
- [{ssl_server_options, [{depth, 1},
- {verify, 0},
- {certfile, filename:join([Dir, "server", "cert.pem"])},
- {cacertfile, filename:join([Dir, "server", "cacerts.pem"])},
- {keyfile, filename:join([Dir, "server", "key.pem"])}]},
- {ssl_client_options, [{depth, 1},
- {verify, 0},
- {server_name_indication, disable},
- {certfile, filename:join([Dir, "client", "cert.pem"])},
- {cacertfile, filename:join([Dir, "client", "cacerts.pem"])},
- {keyfile, filename:join([Dir, "client", "key.pem"])}]},
- {secure, ssl} |Options].
-
-create_paths() ->
- Path = filename:dirname(code:which(?MODULE)),
- " -pa " ++ Path ++ " -pa " ++
- filename:join(Path, "idl_output") ++
- " -pa " ++
- filename:join(Path, "all_SUITE_data") ++
- " -pa \"" ++
- filename:dirname(code:which(orber))++"\"".
-
-%%------------------------------------------------------------
-%% function : destroy_node
-%% Arguments: Node - which node to destroy.
-%% Type - normal | ssl
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-
-destroy_node(Node, Type) ->
- stopper(Node, Type).
-
-stopper(Node, _Type) ->
- slave:stop(Node).
-
-
-%%------------------------------------------------------------
-%% function : remote_apply
-%% Arguments: N - Node, M - Module,
-%% F - Function, A - Arguments (list)
-%% Returns :
-%% Effect :
-%%------------------------------------------------------------
-remote_apply(N, M,F,A) ->
- case rpc:call(N, M, F, A) of
- {badrpc, Reason} ->
- exit(Reason);
- Other ->
- Other
- end.
-
-
-
-%%------------------------------------------------------------
-%% function : install_test_data
-%% Arguments: WhichSuite
-%% Returns : ok
-%% Effect : Installs test data associated with 'WhichSuite'
-%%------------------------------------------------------------
-
-install_test_data(nameservice) ->
- oe_orber_test_server:oe_register(),
- Mamba = orber_test_server:oe_create([], [{regname, {local, mamba}}]),
- true = corba:add_initial_service("Mamba", Mamba),
- NS = corba:resolve_initial_references("NameService"),
- NC1 = lname_component:set_id(lname_component:create(), "mamba"),
- N = lname:insert_component(lname:create(), 1, NC1),
- 'CosNaming_NamingContext':bind(NS, N,Mamba);
-
-install_test_data({nameservice, AltAddr, AltPort}) ->
- oe_orber_test_server:oe_register(),
- Obj = orber_test_server:oe_create([], [{regname, {local, mamba}}]),
- Mamba = corba:add_alternate_iiop_address(Obj, AltAddr, AltPort),
- true = corba:add_initial_service("Mamba", Mamba),
- NS = corba:resolve_initial_references("NameService"),
- NC1 = lname_component:set_id(lname_component:create(), "mamba"),
- N = lname:insert_component(lname:create(), 1, NC1),
- 'CosNaming_NamingContext':bind(NS, N,Mamba);
-
-install_test_data(timeout) ->
- oe_orber_test_server:oe_register(),
- Mamba = orber_test_server:oe_create([], {local, mamba}),
- Viper = orber_test_timeout_server:oe_create([], {local, viper}),
- NS = corba:resolve_initial_references("NameService"),
- NC1 = lname_component:set_id(lname_component:create(), "mamba"),
- N1 = lname:insert_component(lname:create(), 1, NC1),
- NC2 = lname_component:set_id(lname_component:create(), "viper"),
- N2 = lname:insert_component(lname:create(), 1, NC2),
- 'CosNaming_NamingContext':bind(NS, N1, Mamba),
- 'CosNaming_NamingContext':bind(NS, N2, Viper);
-
-install_test_data(pseudo) ->
- oe_orber_test_server:oe_register(),
- Mamba = orber_test_server:oe_create([], [{pseudo,true}]),
- NS = corba:resolve_initial_references("NameService"),
- NC1 = lname_component:set_id(lname_component:create(), "mamba"),
- N = lname:insert_component(lname:create(), 1, NC1),
- 'CosNaming_NamingContext':bind(NS, N,Mamba);
-
-install_test_data(ssl) ->
- oe_orber_test_server:oe_register(),
- Mamba = orber_test_server:oe_create([], [{regname, {local, mamba}}]),
- NS = corba:resolve_initial_references("NameService"),
- NC1 = lname_component:set_id(lname_component:create(), "mamba"),
- N = lname:insert_component(lname:create(), 1, NC1),
- 'CosNaming_NamingContext':bind(NS, N,Mamba);
-
-install_test_data(ssl_simple) ->
- oe_orber_test_server:oe_register();
-
-install_test_data(light) ->
- %% Nothing to do at the moment but we might in the future
- ok;
-
-install_test_data(_) ->
- {error, "no_implement"}.
-
-
-%%------------------------------------------------------------
-%% function : uninstall_test_data
-%% Arguments: WhichSuite
-%% Returns : ok
-%% Effect : Uninstalls test data associated with 'WhichSuite'
-%%------------------------------------------------------------
-
-uninstall_test_data(pseudo) ->
- NS = corba:resolve_initial_references("NameService"),
- NC1 = lname_component:set_id(lname_component:create(), "mamba"),
- N = lname:insert_component(lname:create(), 1, NC1),
- _Obj = (catch 'CosNaming_NamingContext':resolve(NS, N)),
- catch 'CosNaming_NamingContext':destroy(NS),
- oe_orber_test_server:oe_unregister();
-
-uninstall_test_data(timeout) ->
- NS = corba:resolve_initial_references("NameService"),
- NC1 = lname_component:set_id(lname_component:create(), "mamba"),
- N1 = lname:insert_component(lname:create(), 1, NC1),
-
- NC2 = lname_component:set_id(lname_component:create(), "viper"),
- N2 = lname:insert_component(lname:create(), 1, NC2),
- Mamba = (catch 'CosNaming_NamingContext':resolve(NS, N1)),
- Viper = (catch 'CosNaming_NamingContext':resolve(NS, N2)),
- catch corba:dispose(Mamba),
- catch corba:dispose(Viper),
- catch 'CosNaming_NamingContext':destroy(NS),
- oe_orber_test_server:oe_unregister();
-
-uninstall_test_data(nameservice) ->
- true = corba:remove_initial_service("Mamba"),
- NS = corba:resolve_initial_references("NameService"),
- NC1 = lname_component:set_id(lname_component:create(), "mamba"),
- N = lname:insert_component(lname:create(), 1, NC1),
- Obj = (catch 'CosNaming_NamingContext':resolve(NS, N)),
- catch corba:dispose(Obj),
- catch 'CosNaming_NamingContext':destroy(NS),
- oe_orber_test_server:oe_unregister();
-
-uninstall_test_data(ssl) ->
- NS = corba:resolve_initial_references("NameService"),
- NC1 = lname_component:set_id(lname_component:create(), "mamba"),
- N = lname:insert_component(lname:create(), 1, NC1),
- Obj = (catch 'CosNaming_NamingContext':resolve(NS, N)),
- catch corba:dispose(Obj),
- catch 'CosNaming_NamingContext':destroy(NS),
- oe_orber_test_server:oe_unregister();
-
-uninstall_test_data(ssl_simple) ->
- oe_orber_test_server:oe_unregister();
-
-uninstall_test_data(light) ->
- %% Nothing to do at the moment but we might in the future
- ok;
-
-uninstall_test_data(_) ->
- {error, "no_implement"}.
-
-%%------------------------------------------------------------
-%% function : corba_object_tests
-%% Arguments: TestServerObj a orber_test_server ref
-%% OtherObj - any other Orber object.
-%% Returns : term()
-%% Effect :
-%%------------------------------------------------------------
-
-corba_object_tests(TestServerObj, OtherObj) ->
- ?match(false,
- corba_object:is_a(TestServerObj, "IDL:orber_parent/inherrit:1.0")),
- ?match(true,
- corba_object:is_a(TestServerObj, "IDL:omg.org/orber_parent/inherrit:1.0")),
- ?match(true,
- corba_object:is_a(TestServerObj, "IDL:omg.org/orber_test/server:1.0")),
- ?match(false,
- corba_object:is_a(TestServerObj, "IDL:orber_test/server:1.0")),
- ?match(false,
- corba_object:is_a(TestServerObj, "IDL:omg.org/orber_parent/inherrit:1.1")),
- ?match(false,
- corba_object:is_a(TestServerObj, "NotValidIFRID")),
- ?match(false,
- corba_object:is_nil(TestServerObj)),
- ?match(false,
- corba_object:is_equivalent(OtherObj,TestServerObj)),
- ?match(true,
- corba_object:is_equivalent(TestServerObj,TestServerObj)),
- ?match(false, corba_object:non_existent(TestServerObj)),
- ?match(false, corba_object:not_existent(TestServerObj)),
- ?match(#fullinterfacedescription{}, corba_object:get_interface(TestServerObj)),
-
- ok.
-
-%%------------------------------------------------------------
-%% function : lookup
-%% Arguments: Port - which port the other orb uses.
-%% Returns : term()
-%% Effect :
-%%------------------------------------------------------------
-
-lookup(Host, Port) ->
- Key = Host++":"++integer_to_list(Port),
- NSR = corba:resolve_initial_references_remote("NameService",
- ["iiop://"++Key]),
-
- NC1 = lname_component:set_id(lname_component:create(), "not_exist"),
- N1 = lname:insert_component(lname:create(), 1, NC1),
- ?match({'EXCEPTION',{'CosNaming_NamingContext_NotFound',_,_,_}},
- 'CosNaming_NamingContext':resolve(NSR, N1)),
-
- NC2 = lname_component:set_id(lname_component:create(), "mamba"),
- N2 = lname:insert_component(lname:create(), 1, NC2),
- Obj = ?match({'IOP_IOR',"IDL:omg.org/orber_test/server:1.0",_},
- 'CosNaming_NamingContext':resolve(NSR, N2)),
- orber_test_server:print(Obj),
- Obj2 = ?match({'IOP_IOR',"IDL:omg.org/orber_test/server:1.0",_},
- corba:string_to_object("corbaname:iiop:1.1@"++Key++"/NameService#mamba")),
-
- orber_test_server:print(Obj2),
-
- NSR2 = ?match({'IOP_IOR',"IDL:omg.org/CosNaming/NamingContextExt:1.0",_},
- corba:string_to_object("corbaloc:iiop:1.1@"++Key++"/NameService")),
- Obj3 = ?match({'IOP_IOR',"IDL:omg.org/orber_test/server:1.0",_},
- 'CosNaming_NamingContext':resolve(NSR2, N2)),
- orber_test_server:print(Obj3).
-
-%%------------------------------------------------------------
-%% function : alternate_iiop_address
-%% Arguments: Port - which port the other orb uses.
-%% Returns : term()
-%% Effect :
-%%------------------------------------------------------------
-alternate_iiop_address(Host, Port) ->
- IOR = create_alternate_iiop_address(Host, Port),
-
- ?match(false, corba_object:non_existent(IOR)),
- ?match({'object_forward',_}, corba:locate(IOR)),
- ?match({'object_forward',_}, corba:locate(IOR, 10000)),
- ok.
-
-%%------------------------------------------------------------
-%% function : create_alternate_iiop_address
-%% Arguments: Port - which port the other orb uses.
-%% Returns : term()
-%% Effect :
-%%------------------------------------------------------------
-create_alternate_iiop_address(Host, Port) ->
- MC = [#'IOP_TaggedComponent'{tag = ?TAG_ORB_TYPE,
- component_data = ?ORBER_ORB_TYPE_1},
- #'IOP_TaggedComponent'{tag = ?TAG_CODE_SETS,
- component_data = ?DEFAULT_CODESETS},
- #'IOP_TaggedComponent'{tag = ?TAG_ALTERNATE_IIOP_ADDRESS,
- component_data = #'ALTERNATE_IIOP_ADDRESS'{
- 'HostID' = Host,
- 'Port' = Port}},
- #'IOP_TaggedComponent'{tag = ?TAG_ALTERNATE_IIOP_ADDRESS,
- component_data = #'ALTERNATE_IIOP_ADDRESS'{
- 'HostID' = Host,
- 'Port' = 8000}},
- #'IOP_TaggedComponent'{tag = ?TAG_ALTERNATE_IIOP_ADDRESS,
- component_data = #'ALTERNATE_IIOP_ADDRESS'{
- 'HostID' = Host,
- 'Port' = 8000}}],
- #'IOP_IOR'{type_id=TypeID,
- profiles=P1} = _IORA = iop_ior:create({1,2},
- "IDL:omg.org/CosNaming/NamingContextExt:1.0",
- [Host], 8000, -1,
- "NameService", MC, 0, 0),
- #'IOP_IOR'{profiles=P2} = _IORB = iop_ior:create({1,1},
- "IDL:omg.org/CosNaming/NamingContextExt:1.0",
- [Host], 8000, -1,
- "NameService", [], 0, 0),
- #'IOP_IOR'{type_id=TypeID, profiles=P2++P1}.
-
-
-%%------------------------------------------------------------
-%% function : create_components_IOR
-%% Arguments:
-%% Returns : term()
-%% Effect :
-%%------------------------------------------------------------
-create_components_IOR(Version) ->
- MC = [#'IOP_TaggedComponent'{tag = ?TAG_ORB_TYPE,
- component_data = ?ORBER_ORB_TYPE_1},
- #'IOP_TaggedComponent'{tag = ?TAG_CODE_SETS,
- component_data = ?DEFAULT_CODESETS},
- #'IOP_TaggedComponent'{tag = ?TAG_ALTERNATE_IIOP_ADDRESS,
- component_data = #'ALTERNATE_IIOP_ADDRESS'{
- 'HostID' = "127.0.0.1",
- 'Port' = 4001}},
- #'IOP_TaggedComponent'{tag = ?TAG_SSL_SEC_TRANS,
- component_data = #'SSLIOP_SSL'{target_supports = 0,
- target_requires = 1,
- port = 2}},
- #'IOP_TaggedComponent'{tag = ?TAG_FT_GROUP,
- component_data =
- #'FT_TagFTGroupTaggedComponent'
- {version = #'GIOP_Version'{major = 1,
- minor = 2},
- ft_domain_id = "FT_FTDomainId",
- object_group_id = ?ULONGLONGMAX,
- object_group_ref_version = ?LONGMAX}},
- #'IOP_TaggedComponent'{tag = ?TAG_FT_PRIMARY,
- component_data =
- #'FT_TagFTPrimaryTaggedComponent'{primary = true}},
- #'IOP_TaggedComponent'{tag = ?TAG_FT_HEARTBEAT_ENABLED,
- component_data =
- #'FT_TagFTHeartbeatEnabledTaggedComponent'{heartbeat_enabled = true}},
- #'IOP_TaggedComponent'{tag = ?TAG_CSI_SEC_MECH_LIST,
- component_data =
- #'CSIIOP_CompoundSecMechList'
- {stateful = false,
- mechanism_list =
- [#'CSIIOP_CompoundSecMech'
- {target_requires = 6,
- transport_mech =
- #'IOP_TaggedComponent'
- {tag=?TAG_TLS_SEC_TRANS,
- component_data=#'CSIIOP_TLS_SEC_TRANS'
- {target_supports = 7,
- target_requires = 8,
- addresses =
- [#'CSIIOP_TransportAddress'{host_name = "127.0.0.1",
- port = 6001}]}},
- as_context_mech =
- #'CSIIOP_AS_ContextSec'
- {target_supports = 9, target_requires = 10,
- client_authentication_mech = [1, 255],
- target_name = [2,255]},
- sas_context_mech =
- #'CSIIOP_SAS_ContextSec'
- {target_supports = 11, target_requires = 12,
- privilege_authorities =
- [#'CSIIOP_ServiceConfiguration'
- {syntax = ?ULONGMAX,
- name = [3,255]}],
- supported_naming_mechanisms = [[4,255],[5,255]],
- supported_identity_types = ?ULONGMAX}},
- #'CSIIOP_CompoundSecMech'
- {target_requires = 6,
- transport_mech =
- #'IOP_TaggedComponent'
- {tag=?TAG_NULL_TAG,
- component_data=[]},
- as_context_mech =
- #'CSIIOP_AS_ContextSec'
- {target_supports = 9, target_requires = 10,
- client_authentication_mech = [1, 255],
- target_name = [2,255]},
- sas_context_mech =
- #'CSIIOP_SAS_ContextSec'
- {target_supports = 11, target_requires = 12,
- privilege_authorities =
- [#'CSIIOP_ServiceConfiguration'
- {syntax = ?ULONGMAX,
- name = [3,255]}],
- supported_naming_mechanisms = [[4,255],[5,255]],
- supported_identity_types = ?ULONGMAX}},
- #'CSIIOP_CompoundSecMech'
- {target_requires = 6,
- transport_mech =
- #'IOP_TaggedComponent'
- {tag=?TAG_SECIOP_SEC_TRANS,
- component_data=#'CSIIOP_SECIOP_SEC_TRANS'
- {target_supports = 7,
- target_requires = 8,
- mech_oid = [0,255],
- target_name = [0,255],
- addresses =
- [#'CSIIOP_TransportAddress'{host_name = "127.0.0.1",
- port = 6001}]}},
- as_context_mech =
- #'CSIIOP_AS_ContextSec'
- {target_supports = 9, target_requires = 10,
- client_authentication_mech = [1, 255],
- target_name = [2,255]},
- sas_context_mech =
- #'CSIIOP_SAS_ContextSec'
- {target_supports = 11, target_requires = 12,
- privilege_authorities =
- [#'CSIIOP_ServiceConfiguration'
- {syntax = ?ULONGMAX,
- name = [3,255]}],
- supported_naming_mechanisms = [[4,255],[5,255]],
- supported_identity_types = ?ULONGMAX}}]}}],
- iop_ior:create(Version, "IDL:omg.org/CosNaming/NamingContextExt:1.0",
- ["127.0.0.1"], 5001, -1,
- "NameService", MC, 0, 0).
-
-
-%%------------------------------------------------------------
-%% function : alternate_ssl_iiop_address
-%% Arguments: Port - which port the other orb uses.
-%% Returns : term()
-%% Effect :
-%%------------------------------------------------------------
-alternate_ssl_iiop_address(Host, Port, SSLPort) ->
- IOR = create_alternate_ssl_iiop_address(Host, Port, SSLPort),
-
- ?match(false, corba_object:non_existent(IOR)),
- ?match({'object_forward',_}, corba:locate(IOR)),
- ?match({'object_forward',_}, corba:locate(IOR, 10000)),
- ok.
-
-
-%%------------------------------------------------------------
-%% function : create_alternate_ssl_iiop_address
-%% Arguments: Port - which port the other orb uses.
-%% Returns : term()
-%% Effect :
-%%------------------------------------------------------------
-create_alternate_ssl_iiop_address(Host, Port, SSLPort) ->
- MC = [#'IOP_TaggedComponent'{tag = ?TAG_ORB_TYPE,
- component_data = ?ORBER_ORB_TYPE_1},
- #'IOP_TaggedComponent'{tag = ?TAG_CODE_SETS,
- component_data = ?DEFAULT_CODESETS},
- #'IOP_TaggedComponent'{tag = ?TAG_ALTERNATE_IIOP_ADDRESS,
- component_data = #'ALTERNATE_IIOP_ADDRESS'{
- 'HostID' = Host,
- 'Port' = Port}},
- #'IOP_TaggedComponent'{tag = ?TAG_ALTERNATE_IIOP_ADDRESS,
- component_data = #'ALTERNATE_IIOP_ADDRESS'{
- 'HostID' = Host,
- 'Port' = 8000}},
- #'IOP_TaggedComponent'{tag = ?TAG_ALTERNATE_IIOP_ADDRESS,
- component_data = #'ALTERNATE_IIOP_ADDRESS'{
- 'HostID' = Host,
- 'Port' = 8000}},
- #'IOP_TaggedComponent'{tag=?TAG_SSL_SEC_TRANS,
- component_data=#'SSLIOP_SSL'{target_supports = 2,
- target_requires = 2,
- port = SSLPort}}],
- #'IOP_IOR'{type_id=TypeID,
- profiles=P1} = _IORA = iop_ior:create_external({1,2},
- "IDL:omg.org/CosNaming/NamingContextExt:1.0",
- Host, 8000,
- "NameService", MC),
- #'IOP_IOR'{profiles=P2} = _IORB = iop_ior:create_external({1,1},
- "IDL:omg.org/CosNaming/NamingContextExt:1.0",
- Host, 8000,
- "NameService", []),
- #'IOP_IOR'{type_id=TypeID, profiles=P2++P1}.
-
-
-%%------------------------------------------------------------
-%% function : timeouts
-%% Arguments: Port - which port the other orb uses.
-%% Returns : term()
-%% Effect :
-%%------------------------------------------------------------
-
-timeouts(Host, Port, ReqT) ->
- NSR = corba:resolve_initial_references_remote("NameService",
- ["iiop://"++Host++":"++integer_to_list(Port)]),
- NC1 = lname_component:set_id(lname_component:create(), "mamba"),
- N1 = lname:insert_component(lname:create(), 1, NC1),
- NC2 = lname_component:set_id(lname_component:create(), "viper"),
- N2 = lname:insert_component(lname:create(), 1, NC2),
- Mamba = 'CosNaming_NamingContext':resolve(NSR, N1),
- Viper = 'CosNaming_NamingContext':resolve(NSR, N2),
-
- ?match({'EXCEPTION',{'TIMEOUT',_,_,_}},
- orber_test_timeout_server:twoway_function(Viper, ReqT, ReqT*2)),
- ?match(ok, orber_test_timeout_server:oneway_function(Viper, ReqT*2)),
-
- ?match({'EXCEPTION',{'TIMEOUT',_,_,_}},
- orber_test_server:testing_iiop_twoway_delay(Mamba, ReqT)),
- ?match(ok, orber_test_server:testing_iiop_oneway_delay(Mamba, ReqT)),
-
- %% Since the objects are stalled we must wait until they are available again
- %% to be able to run any more tests and get the correct results.
- timer:sleep(ReqT*4),
-
- ?match(ok, orber_test_timeout_server:twoway_function(Viper, ReqT*2, ReqT)),
- ?match(ok, orber_test_timeout_server:oneway_function(Viper, ReqT*2)),
-
- ?match(ok, orber_test_server:testing_iiop_twoway_delay(Mamba, 0)),
- ?match(ok, orber_test_server:testing_iiop_oneway_delay(Mamba, 0)),
-
- timer:sleep(ReqT*4),
- ok.
-
-%%------------------------------------------------------------
-%% function : light_tests
-%% Arguments: Host - which node to contact.
-%% Port - which port the other orb uses.
-%% Returns : term()
-%% Effect :
-%%------------------------------------------------------------
-
-light_tests(Host, Port, ObjName) ->
- NSR = corba:resolve_initial_references_remote("NameService",
- ["iiop://"++Host++":"++integer_to_list(Port)]),
- NC1 = lname_component:set_id(lname_component:create(), "not_exist"),
- N1 = lname:insert_component(lname:create(), 1, NC1),
- %% We cannot handle any unknown replies (besides those found in stub).
- ?match({'EXCEPTION',
- {'CosNaming_NamingContext_NotFound',
- "IDL:omg.org/CosNaming/NamingContext/NotFound:1.0",_,_}},
- 'CosNaming_NamingContext':resolve(NSR, N1)),
- NC2 = lname_component:set_id(lname_component:create(), ObjName),
- N2 = lname:insert_component(lname:create(), 1, NC2),
- Obj = ?match({'IOP_IOR',"IDL:omg.org/orber_test/server:1.0",_},
- 'CosNaming_NamingContext':resolve(NSR, N2)),
- Nodes = orber:get_lightweight_nodes(),
- io:format("Light Nodes: ~p~n", [Nodes]),
- orber_test_server:print(Obj),
- test_coding(Obj),
- ok.
-
-
-%%------------------------------------------------------------
-%% function : test_coding_simple
-%% Arguments: ObjReference
-%% Returns : term()
-%% Effect : test encode/decode for all simple datatypes.
-%%------------------------------------------------------------
-
-test_coding(Obj) ->
- test_coding(Obj, false).
-
-test_coding(Obj, Local) ->
- %%--- Testing code and decode arguments ---
- ?match({ok, 1.5}, orber_test_server:testing_iiop_float(Obj, 1.5)),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_float(Obj, atom)),
-
- ?match({ok,1.0}, orber_test_server:testing_iiop_double(Obj, 1.0)),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_double(Obj, "wrong")),
-
- ?match({ok,0}, orber_test_server:testing_iiop_short(Obj, 0)),
- ?match({ok,?SHORTMAX}, orber_test_server:testing_iiop_short(Obj, ?SHORTMAX)),
- ?match({ok,?SHORTMIN}, orber_test_server:testing_iiop_short(Obj, ?SHORTMIN)),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_short(Obj, atomic)),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_short(Obj, ?SHORTMAX+1)),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_short(Obj, ?SHORTMIN-1)),
-
- ?match({ok,0}, orber_test_server:testing_iiop_ushort(Obj, 0)),
- ?match({ok,?USHORTMAX}, orber_test_server:testing_iiop_ushort(Obj, ?USHORTMAX)),
- ?match({ok,?USHORTMIN}, orber_test_server:testing_iiop_ushort(Obj, ?USHORTMIN)),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_ushort(Obj, ?USHORTMAX+1)),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_ushort(Obj, ?USHORTMIN-1)),
-
- ?match({ok,0}, orber_test_server:testing_iiop_long(Obj, 0)),
- ?match({ok,?LONGMAX}, orber_test_server:testing_iiop_long(Obj, ?LONGMAX)),
- ?match({ok,?LONGMIN}, orber_test_server:testing_iiop_long(Obj, ?LONGMIN)),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_long(Obj, "wrong")),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_long(Obj, ?LONGMAX+1)),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_long(Obj, ?LONGMIN-1)),
-
- ?match({ok,0}, orber_test_server:testing_iiop_longlong(Obj, 0)),
- ?match({ok,?LONGLONGMAX}, orber_test_server:testing_iiop_longlong(Obj, ?LONGLONGMAX)),
- ?match({ok,?LONGLONGMIN}, orber_test_server:testing_iiop_longlong(Obj, ?LONGLONGMIN)),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_longlong(Obj, "wrong")),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_longlong(Obj, ?LONGLONGMAX+1)),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_longlong(Obj, ?LONGLONGMIN-1)),
-
- ?match({ok,0}, orber_test_server:testing_iiop_ulong(Obj, 0)),
- ?match({ok,?ULONGMAX}, orber_test_server:testing_iiop_ulong(Obj, ?ULONGMAX)),
- ?match({ok,?ULONGMIN}, orber_test_server:testing_iiop_ulong(Obj, ?ULONGMIN)),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_ulong(Obj, ?ULONGMAX+1)),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_ulong(Obj, ?ULONGMIN-1)),
-
- ?match({ok,0}, orber_test_server:testing_iiop_ulonglong(Obj, 0)),
- ?match({ok,?ULONGLONGMAX}, orber_test_server:testing_iiop_ulonglong(Obj, ?ULONGLONGMAX)),
- ?match({ok,?ULONGLONGMIN}, orber_test_server:testing_iiop_ulonglong(Obj, ?ULONGLONGMIN)),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_ulonglong(Obj, ?ULONGLONGMAX+1)),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_ulonglong(Obj, ?ULONGLONGMIN-1)),
-
- ?match({ok,98}, orber_test_server:testing_iiop_char(Obj, 98)),
- ?match({ok,$b}, orber_test_server:testing_iiop_char(Obj, $b)),
-
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_char(Obj, atomic)),
-
- ?match({ok,65535}, orber_test_server:testing_iiop_wchar(Obj, 65535)),
- ?match({ok,$b}, orber_test_server:testing_iiop_wchar(Obj, $b)),
-
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_wchar(Obj, atomic)),
-
- ?match({ok,true}, orber_test_server:testing_iiop_bool(Obj, true)),
- ?match({ok,false}, orber_test_server:testing_iiop_bool(Obj, false)),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_bool(Obj, atom)),
-
- ?match({ok,1}, orber_test_server:testing_iiop_octet(Obj, 1)),
-% No real guards for this case.
-% ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
-% orber_test_server:testing_iiop_octet(Obj, 1.5)),
- IOR12 = create_components_IOR({1,2}),
- ?match({ok,Obj}, orber_test_server:testing_iiop_obj(Obj, Obj)),
- ?match({ok,IOR12}, orber_test_server:testing_iiop_obj(Obj, IOR12)),
- PObj = orber_test_server:oe_create([], [{pseudo,true}]),
- ?match({ok, _}, orber_test_server:testing_iiop_obj(Obj, PObj)),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_obj(Obj, "no_object")),
- ?match({ok,"string"}, orber_test_server:testing_iiop_string(Obj, "string")),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_string(Obj, "ToLongString")),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_string(Obj, atomic)),
-
- ?match({ok,[65535]}, orber_test_server:testing_iiop_wstring(Obj, [65535])),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_wstring(Obj, "ToLongWstring")),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_wstring(Obj, atomic)),
-
- ?match({ok, one},
- orber_test_server:testing_iiop_enum(Obj, one)),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_enum(Obj, three)),
- ?match({ok,[1,2,3]},
- orber_test_server:testing_iiop_seq(Obj, [1,2,3])),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_seq(Obj, [1,2,3,4])),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_seq(Obj, false)),
-
-
- ?match({ok,[#orber_test_server_struc{a=1, b=2}]},
- orber_test_server:testing_iiop_struc_seq(Obj,
- [#orber_test_server_struc{a=1, b=2}])),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_struc_seq(Obj, false)),
-
- ?match({ok,[#orber_test_server_uni{label=1, value=66}]},
- orber_test_server:testing_iiop_uni_seq(Obj,
- [#orber_test_server_uni{label=1, value=66}])),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_uni_seq(Obj, false)),
-
- ?match({ok,{"one", "two"}},
- orber_test_server:testing_iiop_array(Obj, {"one", "two"})),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_array(Obj, {"one", "two", "three"})),
- ?match({ok,#orber_test_server_struc{a=1, b=2}},
- orber_test_server:testing_iiop_struct(Obj,
- #orber_test_server_struc{a=1, b=2})),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_struct(Obj,
- #orber_test_server_struc{a="WRONG", b=2})),
- ?match({ok,#orber_test_server_uni{label=1, value=66}},
- orber_test_server:testing_iiop_union(Obj,
- #orber_test_server_uni{label=1, value=66})),
-
- ?match({ok,#orber_test_server_uni_d{label=1, value=66}},
- orber_test_server:testing_iiop_union_d(Obj,
- #orber_test_server_uni_d{label=1, value=66})),
-
- ?match({ok,#orber_test_server_uni_d{label=2, value=true}},
- orber_test_server:testing_iiop_union_d(Obj,
- #orber_test_server_uni_d{label=2, value=true})),
-
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_union_d(Obj,
- #orber_test_server_uni_d{label=2, value=66})),
-
- case Local of
- true ->
- ?match({ok,#orber_test_server_uni{label=2, value=66}},
- orber_test_server:testing_iiop_union(Obj,
- #orber_test_server_uni{label=2, value=66}));
- false ->
- ?match({ok,#orber_test_server_uni{label=2, value=undefined}},
- orber_test_server:testing_iiop_union(Obj,
- #orber_test_server_uni{label=2, value=66}))
- end,
-
- C1 = orber_test_server:fixed52const1(),
- C2 = orber_test_server:fixed52const2(),
- C3 = orber_test_server:fixed52const3(),
-
- C4 = orber_test_server:fixed52negconst1(),
- C5 = orber_test_server:fixed52negconst2(),
- C6 = orber_test_server:fixed52negconst3(),
-
- ?match({ok,C1}, orber_test_server:testing_iiop_fixed(Obj, C1)),
- ?match({ok,C2}, orber_test_server:testing_iiop_fixed(Obj, C2)),
- ?match({ok,C3}, orber_test_server:testing_iiop_fixed(Obj, C3)),
- ?match({ok,C4}, orber_test_server:testing_iiop_fixed(Obj, C4)),
- ?match({ok,C5}, orber_test_server:testing_iiop_fixed(Obj, C5)),
- ?match({ok,C6}, orber_test_server:testing_iiop_fixed(Obj, C6)),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_fixed(Obj, #fixed{digits = 5,
- scale = 2,
- value = 123450})),
-
- ?match(ok, orber_test_server:testing_iiop_void(Obj)),
-
- ?match({'EXCEPTION',{'BAD_QOS',_,_,_}},
- orber_test_server:pseudo_call_raise_exc(Obj, 1)),
- ?match({'EXCEPTION',{'BAD_QOS',_,_,_}},
- orber_test_server:pseudo_call_raise_exc(Obj, 2)),
- ?match({'EXCEPTION',{'orber_test_server_UserDefinedException',_}},
- orber_test_server:raise_local_exception(Obj)),
- ?match({'EXCEPTION',{'orber_test_server_ComplexUserDefinedException',_,
- [#orber_test_server_struc{a=1, b=2}]}},
- orber_test_server:raise_complex_local_exception(Obj)),
- %% Test all TypeCodes
- ?match({ok, #any{typecode = tk_long, value = 1}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_long,
- value = 1})),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_long,
- value = "wrong"})),
- ?match({ok, #any{typecode = tk_float, value = 1.5}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_float,
- value = 1.5})),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_long,
- value = "wrong"})),
- ?match({ok, #any{typecode = tk_double}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_double,
- value = 1.0})),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_double,
- value = "wrong"})),
- ?match({ok, #any{typecode = tk_short, value = -1}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_short,
- value = -1})),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_short,
- value = atomic})),
- ?match({ok, #any{typecode = tk_ushort, value = 1}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_ushort,
- value = 1})),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_ushort,
- value = -1})),
- ?match({ok, #any{typecode = tk_long, value = 1}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_long,
- value = 1})),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_long,
- value = "wrong"})),
- ?match({ok, #any{typecode = tk_longlong, value = 1}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_longlong,
- value = 1})),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_longlong,
- value = "wrong"})),
- ?match({ok, #any{typecode = tk_ulong, value = 1}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_ulong,
- value = 1})),
- ?match({ok, #any{typecode = tk_ulong, value = 4294967295}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_ulong,
- value = 4294967295})),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_ulong,
- value = 4294967296})),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_ulong,
- value = -1})),
- ?match({ok, #any{typecode = tk_ulonglong, value = 1}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_ulonglong,
- value = 1})),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_ulonglong,
- value = -1})),
- ?match({ok, #any{typecode = tk_char, value = 98}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_char,
- value = 98})),
- ?match({ok, #any{typecode = tk_char, value = $b}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_char,
- value = $b})),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_char,
- value = atomic})),
- ?match({ok, #any{typecode = tk_wchar, value = 65535}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_wchar,
- value = 65535})),
- ?match({ok, #any{typecode = tk_wchar, value = $b}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_wchar,
- value = $b})),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_wchar,
- value = atomic})),
- ?match({ok, #any{typecode = tk_boolean, value = true}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_boolean,
- value = true})),
- ?match({ok, #any{typecode = tk_boolean, value = false}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_boolean,
- value = false})),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_boolean,
- value = 1})),
- ?match({ok, #any{typecode = tk_octet, value = 1}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_octet,
- value = 1})),
- ?match({ok, #any{typecode = {tk_objref, "IDL:omg.org/orber_test/server:1.0", "server"}, value = Obj}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = {tk_objref, "IDL:omg.org/orber_test/server:1.0", "server"},
- value = Obj})),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = {tk_objref, "IDL:omg.org/orber_test/server:1.0", "server"},
- value = "No Object"})),
- ?match({ok, #any{typecode = {tk_string, 6}, value = "string"}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = {tk_string, 6},
- value = "string"})),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = tk_string,
- value = atomic})),
- ?match({ok, #any{typecode = {tk_wstring, 1}, value = [65535]}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = {tk_wstring, 1},
- value = [65535]})),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = {tk_wstring, 1},
- value = atomic})),
- ?match({ok, #any{typecode = {tk_enum, "IDL:omg.org/orber_test/server/enumerant:1.0", "enumerant", ["one","two"]},
- value = two}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = {tk_enum, "IDL:omg.org/orber_test/server/enumerant:1.0", "enumerant", ["one","two"]},
- value = two})),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = {tk_enum, "IDL:omg.org/orber_test/server/enumerant:1.0", "enumerant", ["one","two"]},
- value = three})),
-
-
- ?match({ok, #any{typecode = {tk_sequence, tk_long, 3},
- value = [1,2,3]}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = {tk_sequence, tk_long, 3},
- value = [1,2,3]})),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = {tk_sequence, tk_long, 3},
- value = false})),
-
-
-
- ?match({ok, #any{typecode = {tk_array,{tk_string,0},2},
- value = {"one", "two"}}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = {tk_array,{tk_string,0},2},
- value = {"one", "two"}})),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = {tk_array,{tk_string,0},2},
- value = {"one", "two", "three"}})),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = {tk_array,{tk_string,0},2},
- value = {1, 2}})),
- ?match({ok, #any{typecode = {tk_struct,"IDL:omg.org/orber_test/server/struc:1.0",
- "struc",
- [{"a",tk_long},{"b",tk_short}]},
- value = #orber_test_server_struc{a=1, b=2}}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = {tk_struct,"IDL:omg.org/orber_test/server/struc:1.0",
- "struc",
- [{"a",tk_long},{"b",tk_short}]},
- value = #orber_test_server_struc{a=1, b=2}})),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = {tk_struct,"IDL:omg.org/orber_test/server/struc:1.0",
- "struc",
- [{"a",tk_long},{"b",tk_short}]},
- value = #orber_test_server_struc{a=1, b="string"}})),
- ?match({ok, #any{typecode =
- {tk_union,"IDL:omg.org/orber_test/server/uni:1.0",
- "uni", tk_long, -1, [{1,"a",tk_long}]},
- value = #orber_test_server_uni{label=1, value=66}}},
- orber_test_server:
- testing_iiop_any(Obj,
- #any{typecode =
- {tk_union,"IDL:omg.org/orber_test/server/uni:1.0",
- "uni", tk_long, -1, [{1,"a",tk_long}]},
- value = #orber_test_server_uni{label=1, value=66}})),
- case Local of
- true ->
- ?match({ok, #any{typecode =
- {tk_union,"IDL:omg.org/orber_test/server/uni:1.0",
- "uni", tk_long, -1, [{1,"a",tk_long}]},
- value = #orber_test_server_uni{label=2, value=66}}},
- orber_test_server:
- testing_iiop_any(Obj,
- #any{typecode =
- {tk_union,"IDL:omg.org/orber_test/server/uni:1.0",
- "uni", tk_long, -1, [{1,"a",tk_long}]},
- value = #orber_test_server_uni{label=2, value=66}}));
- false ->
- ?match({ok, #any{typecode =
- {tk_union,"IDL:omg.org/orber_test/server/uni:1.0",
- "uni", tk_long, -1, [{1,"a",tk_long}]},
- value = #orber_test_server_uni{label=2, value=undefined}}},
- orber_test_server:
- testing_iiop_any(Obj,
- #any{typecode =
- {tk_union,"IDL:omg.org/orber_test/server/uni:1.0",
- "uni", tk_long, -1, [{1,"a",tk_long}]},
- value = #orber_test_server_uni{label=2, value=66}}))
- end,
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:
- testing_iiop_any(Obj,
- #any{typecode =
- {tk_union,"IDL:omg.org/orber_test/server/uni:1.0",
- "uni", tk_long, -1, [{1,"a",tk_long}]},
- value = #orber_test_server_uni{label=1, value="string"}})),
-
- ?match({ok, #any{typecode = {tk_fixed,5,2},
- value = #fixed{digits = 5, scale = 2, value = 12345}}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = {tk_fixed,5,2},
- value = #fixed{digits = 5,
- scale = 2,
- value = 12345}})),
- ?match({ok, #any{typecode = {tk_fixed,10,2},
- value = #fixed{digits = 10, scale = 2, value = 1234567890}}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = {tk_fixed,10,2},
- value = #fixed{digits = 10,
- scale = 2,
- value = 1234567890}})),
- ?match({ok, #any{typecode = {tk_fixed,6,2},
- value = #fixed{digits = 6, scale = 2, value = 300000}}},
- orber_test_server:testing_iiop_any(Obj, #any{typecode = {tk_fixed,6,2},
- value = #fixed{digits = 6,
- scale = 2,
- value = 300000}})),
- ?match({'EXCEPTION',{'MARSHAL',_,_,_}},
- orber_test_server:
- testing_iiop_server_marshal(Obj, "string")),
-
- RecS = #orber_test_server_rec_struct{chain = [#orber_test_server_rec_struct{chain = []}]},
- ?match(RecS, orber_test_server:testing_iiop_rec_struct(Obj, RecS)),
-
- RecU = #orber_test_server_rec_union{label = 'RecursiveType',
- value = [#orber_test_server_rec_union{label = 'RecursiveType',
- value = []}]},
- ?match(RecU, orber_test_server:testing_iiop_rec_union(Obj, RecU)),
-
-%% RecA1 = #any{typecode = unsupported, value = RecS},
-%% RecA2 = #any{typecode = unsupported, value = RecU},
-%% ?match(RecA1,
-%% orber_test_server:testing_iiop_rec_any(Obj, RecA1)),
-%% ?match(RecA2,
-%% orber_test_server:testing_iiop_rec_any(Obj, RecA2)),
-
- ok.
-
-%%--------------- Testing Post- & Pre-cond -------------------
-precond(Module, Function, Args) ->
- error_logger:info_msg("=============== pre-condition ============
-Module : ~p
-Function : ~p
-Arguments : ~p
-==========================================~n", [Module, Function, Args]),
- ok.
-
-postcond(Module, Function, Args, Result) ->
- error_logger:info_msg("=============== post-condition ===========
-Module : ~p
-Function : ~p
-Arguments : ~p
-Result : ~p
-==========================================~n", [Module, Function, Args, Result]),
- ok.
-
-%%--------------- Testing Missing Module ---------------------
-oe_get_interface() ->
- non_existing_module:tc(foo).
-
-%%--------------- INTERCEPTOR FUNCTIONS ----------------------
-%%------------------------------------------------------------
-%% function : new_in_connection
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-new_in_connection(Arg, CHost, Port) ->
- Host = node(),
- [{SHost, SPort}] = orber:find_sockname_by_peername(CHost, Port),
- Peers = orber:find_peername_by_sockname(SHost, SPort),
- error_logger:info_msg("=============== new_in_connection ========
-Node : ~p
-From Host : ~p
-From Port : ~p
-To Host : ~p
-To Port : ~p
-Peers : ~p
-Arg : ~p
-==========================================~n",
- [Host, CHost, Port, SHost, SPort, Peers, Arg]),
- {Host}.
-
-%%------------------------------------------------------------
-%% function : new_out_connection
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-new_out_connection(Arg, SHost, Port) ->
- Host = node(),
- error_logger:info_msg("=============== new_out_connection =======
-Node : ~p
-To Host : ~p
-To Port : ~p
-Arg : ~p
-==========================================~n",
- [Host, SHost, Port, Arg]),
- {Host}.
-
-%%------------------------------------------------------------
-%% function : closed_in_connection
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-closed_in_connection(Arg) ->
- error_logger:info_msg("=============== closed_in_connection =====
-Node : ~p
-Connection: ~p
-==========================================~n",
- [node(), Arg]),
- Arg.
-
-%%------------------------------------------------------------
-%% function : closed_out_connection
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-closed_out_connection(Arg) ->
- error_logger:info_msg("=============== closed_out_connection ====
-Node : ~p
-Connection: ~p
-==========================================~n",
- [node(), Arg]),
- Arg.
-
-%%------------------------------------------------------------
-%% function : in_request_encoded
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-in_request_encoded(Ref, _ObjKey, Ctx, Op,
- <<100:8,101:8,102:8,103:8,104:8,105:8,106:8,107:8,108:8,109:8,110:8,T/binary>>, _Args) ->
- error_logger:info_msg("=============== in_request_encoded =======
-Connection: ~p
-Operation : ~p
-Body : ~p
-Context : ~p
-==========================================~n",
- [Ref, Op, T, Ctx]),
- {T, "NewArgs"}.
-
-%%------------------------------------------------------------
-%% function : in_reply_encoded
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-in_reply_encoded(Ref, _ObjKey, Ctx, Op,
- <<100:8,101:8,102:8,103:8,104:8,105:8,106:8,107:8,108:8,109:8,110:8,T/binary>>,
- _Args) ->
- error_logger:info_msg("============== in_reply_encoded ==========
-Connection: ~p
-Operation : ~p
-Body : ~p
-Context : ~p
-==========================================~n",
- [Ref, Op, T, Ctx]),
- {T, "NewArgs"}.
-
-%%------------------------------------------------------------
-%% function : out_reply_encoded
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-out_reply_encoded(Ref, _ObjKey, Ctx, Op, List, _Args) ->
- error_logger:info_msg("============== out_reply_encoded =========
-Connection: ~p
-Operation : ~p
-Body : ~p
-Context : ~p
-==========================================~n",
- [Ref, Op, List, Ctx]),
- {list_to_binary([<<100:8,101:8,102:8,103:8,104:8,105:8,106:8,107:8,108:8,109:8,110:8>>|List]), "NewArgs"}.
-
-%%------------------------------------------------------------
-%% function : out_request_encoded
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-out_request_encoded(Ref, _ObjKey, Ctx, Op, List, _Args) ->
- error_logger:info_msg("============== out_request_encoded =======
-Connection: ~p
-Operation : ~p
-Body : ~p
-Context : ~p
-==========================================~n",
- [Ref, Op, List, Ctx]),
- {list_to_binary([<<100:8,101:8,102:8,103:8,104:8,105:8,106:8,107:8,108:8,109:8,110:8>>|List]), "NewArgs"}.
-
-%%------------------------------------------------------------
-%% function : in_request
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-in_request(Ref, _ObjKey, Ctx, Op, Params, _Args) ->
- error_logger:info_msg("=============== in_request ===============
-Connection: ~p
-Operation : ~p
-Parameters: ~p
-Context : ~p
-==========================================~n",
- [Ref, Op, Params, Ctx]),
- {Params, "NewArgs"}.
-
-%%------------------------------------------------------------
-%% function : in_reply
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-in_reply(Ref, _ObjKey, Ctx, Op, Reply, _Args) ->
- error_logger:info_msg("=============== in_reply =================
-Connection: ~p
-Operation : ~p
-Reply : ~p
-Context : ~p
-==========================================~n",
- [Ref, Op, Reply, Ctx]),
- {Reply, "NewArgs"}.
-
-%%------------------------------------------------------------
-%% function : postinvoke
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-out_reply(Ref, _ObjKey, Ctx, Op, Reply, _Args) ->
- error_logger:info_msg("=============== out_reply ================
-Connection: ~p
-Operation : ~p
-Reply : ~p
-Context : ~p
-==========================================~n",
- [Ref, Op, Reply, Ctx]),
- {Reply, "NewArgs"}.
-
-%%------------------------------------------------------------
-%% function : postinvoke
-%% Arguments:
-%% Returns :
-%%------------------------------------------------------------
-out_request(Ref, _ObjKey, Ctx, Op, Params, _Args) ->
- error_logger:info_msg("=============== out_request ==============
-Connection: ~p
-Operation : ~p
-Parameters: ~p
-Context : ~p
-==========================================~n",
- [Ref, Op, Params, Ctx]),
- {Params, "NewArgs"}.
-
-
-%%--------------- END OF MODULE ------------------------------
-
-
-
diff --git a/lib/orber/test/orber_test_server.cfg b/lib/orber/test/orber_test_server.cfg
deleted file mode 100644
index c6bbd99f17..0000000000
--- a/lib/orber/test/orber_test_server.cfg
+++ /dev/null
@@ -1,28 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-{timeout, "orber_test::timeout_server"}.
-{this, "orber_test::timeout_server"}.
-{{handle_info, "orber_test::timeout_server"}, true}.
-{this, "orber_test::server"}.
-{{handle_info, "orber_test::server"}, true}.
-{{postcond, "orber_test::server::testing_iiop_union_d"}, {orber_test_lib, postcond}}.
-{{postcond, "orber_test::server::testing_iiop_array"}, {orber_test_lib, postcond}}.
-{{precond, "orber_test::server::testing_iiop_array"}, {orber_test_lib, precond}}.
-{{precond, "orber_test::server::testing_iiop_enum"}, {orber_test_lib, precond}}.
diff --git a/lib/orber/test/orber_test_server.idl b/lib/orber/test/orber_test_server.idl
deleted file mode 100644
index f274baed24..0000000000
--- a/lib/orber/test/orber_test_server.idl
+++ /dev/null
@@ -1,177 +0,0 @@
-//
-// %CopyrightBegin%
-//
-// Copyright Ericsson AB 1999-2016. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// %CopyrightEnd%
-//
-
-#ifndef _ORBER_TEST_SERVER_IDL
-#define _ORBER_TEST_SERVER_IDL
-#pragma prefix "omg.org"
-
-module orber_parent {
- interface inherrit {
- void print();
- };
-};
-
-module orber_test {
-
- // interface server
- interface server : orber_parent::inherrit {
- typedef string array[2];
- typedef sequence <long, 3> seq;
- typedef wstring<6> WstrLength6;
- typedef string<6> StrLength6;
-
- struct struc {long a; short b;};
- union uni switch(long) {
- case 1: long a;};
-
- union uni_d switch(long) {
- case 1: long a;
- default: boolean b;
- };
- enum enumerant {one, two};
-
- exception UserDefinedException {};
-
- typedef sequence<struc> StrucSeq;
- typedef sequence<uni> UniSeq;
- exception ComplexUserDefinedException { StrucSeq strseq; };
-
- // Testing fixed
- const fixed val1 = 3.14D;
- const fixed val2 = 003.14D;
- const fixed val3 = 003.1400D;
- const fixed val4 = 3.1400D;
- const fixed val5 = .1400D;
- const fixed val6 = 3.D;
- const fixed val7 = -.1400D;
- const fixed val8 = -3.D;
- const fixed val9 = val4+val5;
- const fixed val10 = val4*val5;
- const fixed val11 = val4/val5;
- const fixed val12 = 123.140001D;
- const fixed val13 = 12314000.1D;
- const fixed val14 = val12-val13;
- const fixed val15 = val12+val13;
- const fixed val16 = val12*val13;
- const fixed val17 = 2.01D+2.01D;
- const fixed val18 = 2.01D*2.01D;
- const fixed val19 = 200D;
- const fixed val20 = 9999999999999999999999999999999D+9999999999999999999999999999999D;
- const fixed val21 = 9999999999999999999999999999999D-9999999999999999999999999999999D;
- const fixed val22 = 9999999999999999999999999999999D*9999999999999999999999999999999D;
- const fixed val23 = 9999999999999999999999999999999D/9999999999999999999999999999999D;
- const fixed val24 = 9999D+9999D;
- const fixed val25 = 400D/10D;
- const fixed val26 = 9999999999999999999999999999999D;
-
-
- typedef fixed<5,2> fixed52;
- const fixed52 fixed52const1 = 123.45d;
- const fixed52 fixed52const2 = 123.00d;
- const fixed52 fixed52const3 = 023.00d;
- const fixed52 fixed52negconst1 = -123.45d;
- const fixed52 fixed52negconst2 = -123.00d;
- const fixed52 fixed52negconst3 = -023.00d;
-
- struct rec_struct; // Forward declaration
- typedef sequence<rec_struct> rec_struct_seq;
- struct rec_struct {
- rec_struct_seq chain;
- };
-
-
- union rec_union; // Forward declaration
- typedef sequence<rec_union>rec_union_seq;
-
- enum MyEnum {RecursiveType, NameType};
-
- union rec_union switch (MyEnum) {
- case RecursiveType : rec_union_seq chain;
- case NameType : string aName;
- };
-
- void stop_normal();
-
- void stop_brutal();
-
- // Testing encode and decode
- void testing_iiop_float(inout float Fl);
- void testing_iiop_double(inout double Do);
- void testing_iiop_short(inout short Sh);
- void testing_iiop_ushort(inout unsigned short Us);
- void testing_iiop_long(inout long Lo);
- void testing_iiop_longlong(inout long long LLo);
- void testing_iiop_ulong(inout unsigned long Ulo);
- void testing_iiop_ulonglong(inout unsigned long long LLo);
- void testing_iiop_char(inout char Ch);
- void testing_iiop_wchar(inout wchar WCh);
- void testing_iiop_bool(inout boolean Bool);
- void testing_iiop_octet(inout octet Oct);
- void testing_iiop_any(inout any AnyType);
- void testing_iiop_obj(inout Object Obj);
- void testing_iiop_string(inout StrLength6 Str);
- void testing_iiop_wstring(inout WstrLength6 WStr);
- void testing_iiop_struct(inout struc Stru);
- void testing_iiop_union(inout uni Uni);
- void testing_iiop_union_d(inout uni_d Uni);
- void testing_iiop_enum(inout enumerant Enumerant);
- void testing_iiop_seq(inout seq Seq);
- void testing_iiop_uni_seq(inout UniSeq USeq);
- void testing_iiop_struc_seq(inout StrucSeq SSeq);
- void testing_iiop_array(inout array Arr);
- void testing_iiop_fixed(inout fixed52 MyFixed);
- void testing_iiop_void();
- void testing_iiop_context();
- void testing_iiop_server_marshal(inout StrLength6 Str);
-
- // Recursive types
- any testing_iiop_rec_any(in any RecType);
- rec_struct testing_iiop_rec_struct(in rec_struct RecS);
- rec_union testing_iiop_rec_union(in rec_union RecU);
-
-
- oneway void testing_iiop_oneway_delay(in long Time);
- void testing_iiop_twoway_delay(in long Time);
-
- // Testing relay calls/casts to, for example, test that sending implicit
- // Contexts works.
- void relay_call(in Object Target);
- oneway void relay_cast(in Object Target);
-
- // Testing pseudo calls/casts
- void pseudo_call();
- oneway void pseudo_cast();
- void pseudo_call_delay(inout long Lo);
- oneway void pseudo_cast_delay(in long Lo);
- void pseudo_call_raise_exc(in long Lo);
- void raise_local_exception()
- raises(UserDefinedException);
- void raise_complex_local_exception()
- raises(ComplexUserDefinedException);
- };
-
- interface timeout_server {
- oneway void oneway_function(in long time);
- void twoway_function(in long time);
- };
-
-};
-
-#endif
diff --git a/lib/orber/test/orber_test_server_impl.erl b/lib/orber/test/orber_test_server_impl.erl
deleted file mode 100644
index d9cef17d26..0000000000
--- a/lib/orber/test/orber_test_server_impl.erl
+++ /dev/null
@@ -1,276 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(orber_test_server_impl).
--include_lib("orber/include/corba.hrl").
--include("idl_output/orber_test_server.hrl").
-
-%%--------------- specified functions ------------------------
--export([stop_normal/2,
- stop_brutal/2,
- print/2,
- %% Testing code and decode arguments
- testing_iiop_float/3,
- testing_iiop_double/3,
- testing_iiop_short/3,
- testing_iiop_ushort/3,
- testing_iiop_long/3,
- testing_iiop_longlong/3,
- testing_iiop_ulong/3,
- testing_iiop_ulonglong/3,
- testing_iiop_char/3,
- testing_iiop_wchar/3,
- testing_iiop_bool/3,
- testing_iiop_octet/3,
- testing_iiop_any/3,
- testing_iiop_obj/3,
- testing_iiop_string/3,
- testing_iiop_wstring/3,
- testing_iiop_struct/3,
- testing_iiop_union/3,
- testing_iiop_union_d/3,
- testing_iiop_enum/3,
- testing_iiop_seq/3,
- testing_iiop_uni_seq/3,
- testing_iiop_struc_seq/3,
- testing_iiop_array/3,
- testing_iiop_fixed/3,
- testing_iiop_void/2,
- testing_iiop_context/2,
- testing_iiop_server_marshal/3,
- testing_iiop_rec_any/3,
- testing_iiop_rec_struct/3,
- testing_iiop_rec_union/3,
- relay_call/3,
- relay_cast/3,
- %% Testing pseudo calls.
- pseudo_call/2,
- pseudo_cast/2,
- pseudo_call_delay/3,
- pseudo_cast_delay/3,
- pseudo_call_raise_exc/3,
- %% Testing raise locally defined exception.
- raise_local_exception/2,
- raise_complex_local_exception/2,
- %% Test timeout functionality
- testing_iiop_oneway_delay/3,
- testing_iiop_twoway_delay/3]).
-
-
-%%--------------- gen_server specific ------------------------
--export([init/1, terminate/2]).
--export([handle_call/3, handle_cast/2, handle_info/2, code_change/3]).
-
-%%--------------- LOCAL DATA ---------------------------------
-
-%%------------------------------------------------------------
-%% function : init, terminate
-%%------------------------------------------------------------
-init(State) ->
- process_flag(trap_exit,true),
- {ok, State}.
-
-terminate(Reason, State) ->
- io:format("orber_test_server:terminate(~p ~p)~n",[Reason, State]),
- ok.
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-handle_call(_,_, State) ->
- {noreply, State}.
-handle_cast(_, State) ->
- {noreply, State}.
-handle_info(_Info, State) ->
- {noreply, State}.
-
-%%--------------- SERVER FUNCTIONS ---------------------------
-
-print(Self, State) ->
- io:format("orber_test_server:print(~p ~p)~n",[Self, State]),
- {reply, ok, State}.
-
-stop_normal(_Self, State) ->
- {stop, normal, ok, State}.
-
-stop_brutal(_Self, _State) ->
- exit("killed_brutal").
-
-
-%% Testing code and decode arguments
-testing_iiop_float(_Self, State, Float) ->
- {reply, {ok, Float}, State}.
-
-testing_iiop_double(_Self, State, Double) ->
- {reply, {ok, Double}, State}.
-
-testing_iiop_short(_Self, State, Short) ->
- {reply, {ok, Short}, State}.
-
-testing_iiop_ushort(_Self, State, Ushort) ->
- {reply, {ok, Ushort}, State}.
-
-testing_iiop_long(_Self, State, Long) ->
- {reply, {ok, Long}, State}.
-
-testing_iiop_longlong(_Self, State, LLong) ->
- {reply, {ok, LLong}, State}.
-
-testing_iiop_ulong(_Self, State, Ulong) ->
- {reply, {ok, Ulong}, State}.
-
-testing_iiop_ulonglong(_Self, State, ULlong) ->
- {reply, {ok, ULlong}, State}.
-
-testing_iiop_char(_Self, State, Char) ->
- {reply, {ok, Char}, State}.
-
-testing_iiop_wchar(_Self, State, WChar) ->
- {reply, {ok, WChar}, State}.
-
-testing_iiop_bool(_Self, State, Boolean) ->
- {reply, {ok, Boolean}, State}.
-
-testing_iiop_octet(_Self, State, Octet) ->
- {reply, {ok, Octet}, State}.
-
-testing_iiop_any(_Self, State, Any) ->
- {reply, {ok, Any}, State}.
-
-testing_iiop_obj(_Self, State, Obj) ->
- {reply, {ok, Obj}, State}.
-
-testing_iiop_string(_Self, State, String) ->
- {reply, {ok, String}, State}.
-
-testing_iiop_wstring(_Self, State, WString) ->
- {reply, {ok, WString}, State}.
-
-testing_iiop_struct(_Self, State, Struct) ->
- {reply, {ok, Struct}, State}.
-
-testing_iiop_union(_Self, State, Union) ->
- {reply, {ok, Union}, State}.
-
-testing_iiop_union_d(_Self, State, Union) ->
- {reply, {ok, Union}, State}.
-
-testing_iiop_enum(_Self, State, Enum) ->
- {reply, {ok, Enum}, State}.
-
-testing_iiop_seq(_Self, State, Sequence) ->
- {reply, {ok, Sequence}, State}.
-
-testing_iiop_uni_seq(_Self, State, Sequence) ->
- {reply, {ok, Sequence}, State}.
-
-testing_iiop_struc_seq(_Self, State, Sequence) ->
- {reply, {ok, Sequence}, State}.
-
-testing_iiop_array(_Self, State, Array) ->
- {reply, {ok, Array}, State}.
-
-testing_iiop_fixed(_Self, State, Fixed) ->
- {reply, {ok, Fixed}, State}.
-
-testing_iiop_void(_Self, State) ->
- {reply, ok, State}.
-
-testing_iiop_context(_Self, State) ->
- Ctx = get(oe_server_in_context),
- io:format("orber_test_server:testing_iiop_context( ~p )~n", [Ctx]),
- {reply, ok, State}.
-
-testing_iiop_server_marshal(_Self, State, _String) ->
- {reply, {ok, false}, State}.
-
-testing_iiop_rec_any(_Self, State, RAny) ->
- {reply, RAny, State}.
-
-testing_iiop_rec_struct(_Self, State, RecS) ->
- {reply, RecS, State}.
-
-testing_iiop_rec_union(_Self, State, RecU) ->
- {reply, RecU, State}.
-
-
-testing_iiop_oneway_delay(_Self, State, Time) ->
- timer:sleep(Time),
- {noreply, State}.
-
-testing_iiop_twoway_delay(_Self, State, Time) ->
- timer:sleep(Time),
- {reply, ok, State}.
-
-raise_local_exception(_Self, State) ->
- corba:raise(#'orber_test_server_UserDefinedException'{}),
- {reply, ok, State}.
-
-raise_complex_local_exception(_Self, State) ->
- corba:raise(#'orber_test_server_ComplexUserDefinedException'{strseq=
- [#orber_test_server_struc{a=1, b=2}]}),
- {reply, ok, State}.
-
-%% Testing relay calls/casts to, for example, test that sending implicit
-%% Contexts works.
-relay_call(_Self, State, Target) ->
- io:format("orber_test_server:relay_call( ~p ) Pre~n", [get(oe_server_in_context)]),
- orber_test_server:testing_iiop_context(Target),
- io:format("orber_test_server:relay_call( ~p ) Post~n", [get(oe_server_in_context)]),
- {reply, ok, State}.
-
-relay_cast(_Self, State, Target) ->
- io:format("orber_test_server:relay_cast( ~p ) Pre~n", [get(oe_server_in_context)]),
- orber_test_server:testing_iiop_context(Target),
- io:format("orber_test_server:relay_cast( ~p ) Post~n", [get(oe_server_in_context)]),
- {noreply, State}.
-
-%% Testing pseudo calls.
-pseudo_call(_Self, State) ->
- io:format("orber_test_server:pseudo_call( ~p )~n", [erlang:timestamp()]),
- {reply, ok, State}.
-
-pseudo_cast(_Self, State) ->
- io:format("orber_test_server:pseudo_cast( ~p )~n", [erlang:timestamp()]),
- {noreply, State}.
-pseudo_call_delay(_Self, State, Time) ->
- io:format("orber_test_server:pseudo_call_delay( ~p )~n", [erlang:timestamp()]),
- timer:sleep(Time),
- io:format("orber_test_server:pseudo_call_delay( ~p )~n", [erlang:timestamp()]),
- {reply, {ok, Time}, State}.
-
-pseudo_cast_delay(_Self, State, Time) ->
- io:format("orber_test_server:pseudo_cast_delay( ~p )~n", [erlang:timestamp()]),
- timer:sleep(Time),
- io:format("orber_test_server:pseudo_cast_delay( ~p )~n", [erlang:timestamp()]),
- {noreply, State}.
-
-pseudo_call_raise_exc(_Self, State, 1) ->
- io:format("orber_test_server:pseudo_call_raise_exc( ~p )~n",[1]),
- {reply, {'EXCEPTION', #'BAD_QOS'{completion_status=?COMPLETED_NO}}, State};
-pseudo_call_raise_exc(_Self, State, 2) ->
- io:format("orber_test_server:pseudo_call_raise_exc( ~p )~n",[2]),
- corba:raise(#'BAD_QOS'{completion_status=?COMPLETED_NO}),
- {reply, ok, State}.
-
-%%--------------- LOCAL FUNCTIONS ----------------------------
-
-%%--------------- END OF MODULE ------------------------------
-
diff --git a/lib/orber/test/orber_test_timeout_server_impl.erl b/lib/orber/test/orber_test_timeout_server_impl.erl
deleted file mode 100644
index de16877dde..0000000000
--- a/lib/orber/test/orber_test_timeout_server_impl.erl
+++ /dev/null
@@ -1,66 +0,0 @@
-%%--------------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% File : orber_test_timeout_server_impl.erl
-%% Purpose :
-%%----------------------------------------------------------------------
-
--module(orber_test_timeout_server_impl).
-
--export([oneway_function/3, twoway_function/3]).
-
-
-%%--------------- gen_server specific ------------------------
--export([init/1, terminate/2, code_change/3, handle_info/2]).
-
-%%------------------------------------------------------------
-%% function : server specific
-%%------------------------------------------------------------
-init(State) ->
- %% 'trap_exit' optional
- process_flag(trap_exit,true),
- {ok, State}.
-
-terminate(_Reason, _State) ->
- ok.
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%% If use IC option {{handle_info, "Module::Interface"}, true}
-handle_info(_Info, State) ->
- %% Await the next invocation.
- {noreply, State}.
-
-%%--- two-way ------------------------------------------------
-twoway_function(_OE_THIS, State, Time) ->
- timer:sleep(Time),
- {reply, ok, State}.
-
-
-%%--- one-way ------------------------------------------------
-oneway_function(_OE_THIS, State, Time) ->
- timer:sleep(Time),
- {noreply, State}.
-
-%%--------------- END OF MODULE ------------------------------
-
diff --git a/lib/orber/test/orber_web_SUITE.erl b/lib/orber/test/orber_web_SUITE.erl
deleted file mode 100644
index b272eb3fcf..0000000000
--- a/lib/orber/test/orber_web_SUITE.erl
+++ /dev/null
@@ -1,440 +0,0 @@
-%%-----------------------------------------------------------------
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%% File : orber_web_SUITE.erl
-%% Purpose :
-%%-----------------------------------------------------------------
-
--module(orber_web_SUITE).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/include/corba.hrl").
--include_lib("orber/src/orber_iiop.hrl").
-
--define(default_timeout, test_server:minutes(3)).
-
--define(match(ExpectedRes, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- ExpectedRes ->
- io:format("------ CORRECT RESULT ------~n~p~n",
- [AcTuAlReS]),
- AcTuAlReS;
- _ ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS)
- end
- end()).
-
--define(nomatch(Not, Expr),
- fun() ->
- AcTuAlReS = (catch (Expr)),
- case AcTuAlReS of
- Not ->
- io:format("###### ERROR ERROR ######~n~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS);
- _ ->
- io:format("------ CORRECT RESULT ------~n~p~n",
- [AcTuAlReS]),
- AcTuAlReS
- end
- end()).
-
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--compile(export_all).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [menu, configure, info, nameservice, ifr_select,
- ifr_data, create, delete_ctx, add_ctx, delete_obj,
- server].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-init_per_testcase(_Case, Config) ->
- Dog=test_server:timetrap(?default_timeout),
- Path = code:which(?MODULE),
- code:add_pathz(filename:join(filename:dirname(Path), "idl_output")),
- orber:jump_start(2875),
- oe_orber_test_server:oe_register(),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- oe_orber_test_server:oe_unregister(),
- orber:jump_stop(),
- Path = code:which(?MODULE),
- code:del_path(filename:join(filename:dirname(Path), "idl_output")),
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: menu
-%% Description:
-%%-----------------------------------------------------------------
-menu(_) ->
- Node = atom_to_list(node()),
- OK = orber_web:menu(env, [{"node", Node}]),
- ?match(OK, orber_web:menu(env, [])),
- ?match(OK, orber_web:menu(env, [42, {"node", Node}, "wrong"])),
- ?match({'EXIT', _E}, orber_web:menu(env, [{"node", localhost}])),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: configure
-%% Description:
-%%-----------------------------------------------------------------
-configure(_) ->
- Node = atom_to_list(node()),
- ?match({'EXIT', _}, orber_web:configure(env, [])),
- ?match({'EXIT', _}, orber_web:configure(env, [{"node", localhost},
- {"data", atom}])),
- ?match([_H|_T], orber_web:configure(env, [{"node", Node}, {"data", ""}])),
- ?match([_H|_T], orber_web:configure(env, [{"node", Node},
- {"data", "[{orber_debug_level, 9}]"}])),
- ?match({ok, 9}, application:get_env(orber, orber_debug_level)),
- ?match([_H|_T], orber_web:configure(env, [{"node", "bad_node"},
- {"data", "[{orber_debug_level, 9}]"}])),
- ?match({error, _}, orber_web:configure(env, [{"node", Node},
- {"data", "{orber_debug_level 9}"}])),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: info
-%% Description:
-%%-----------------------------------------------------------------
-info(_) ->
- ?match({'EXIT', _}, orber_web:info(env, [])),
- ?match({'EXIT', _}, orber_web:info(env, [{"node", localhost}])),
- ?match([_H|_T], orber_web:info(env, [{"node", atom_to_list(node())}])),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: nameservice
-%% Description:
-%%-----------------------------------------------------------------
-nameservice(_) ->
- NodeStr = atom_to_list(node()),
- ?match({'EXIT', _}, orber_web:nameservice(env, [{"node", localhost},
- {"context", "root"}])),
- ?match({'EXIT', _}, orber_web:nameservice(env, [{"node", localhost},
- {"context", "id1"}])),
- ?match([_H|_T], orber_web:nameservice(env, [{"node", "bad_node"},
- {"context", "root"}])),
- ?match([_,_,_,NodeStr|_], orber_web:nameservice(env, [{"node", NodeStr},
- {"context", "root"}])),
- ?match({ok,_}, orber_web:nameservice(env, [{"node", NodeStr},
- {"context", "id1"}])),
- ?match([_H|_T], orber_web:add_ctx(env, [{"node", NodeStr},
- {"context", "root"},
- {"id", "id1"}])),
- ?match([_H|_T], orber_web:add_ctx(env, [{"node", NodeStr},
- {"context", "id1"},
- {"id", "id2"}])),
- [_,_,_,IOR] =
- ?match([_,_,_,_], orber_web:create(env, [{"node", NodeStr},
- {"module", "orber_test_server"},
- {"arguments", "[]"},
- {"options", "[{pseudo, true}]"},
- {"namestr", "id1/id2/id3"},
- {"bind", "rebind"}])),
- ?match(#'IOP_IOR'{}, corba:string_to_object(IOR)),
-
- ?match([_,"id1"|_], orber_web:nameservice(env, [{"node", NodeStr},
- {"context", "id1"}])),
- ?nomatch({error, _}, orber_web:nameservice(env, [{"node", NodeStr},
- {"context", "id1/id2"},
- {"object", "id3"}])),
-
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: ifr_select
-%% Description:
-%%-----------------------------------------------------------------
-ifr_select(_) ->
- ?match({'EXIT', _}, orber_web:ifr_select(env, [])),
- ?match({'EXIT', _}, orber_web:ifr_select(env, [{"node", localhost}])),
- ?match([_H|_T], orber_web:ifr_select(env, [{"node", "bad_node"}])),
- ?match([_H|_T], orber_web:ifr_select(env, [{"node", atom_to_list(node())}])),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: ifr_data
-%% Description:
-%%-----------------------------------------------------------------
-ifr_data(_) ->
- ?match({'EXIT', _}, orber_web:ifr_data(env, [])),
- ?match({'EXIT', _}, orber_web:ifr_data(env, [{"node", localhost},
- {"table", "ir_ModuleDef"}])),
- ?match({error, _}, orber_web:ifr_data(env, [{"node", "bad_host"},
- {"table", "ir_ModuleDef"}])),
- ?match({'EXIT', _}, orber_web:ifr_data(env, [{"node", atom_to_list(node())},
- {"table", "bad_table"}])),
- ?match([_H|_T], orber_web:ifr_data(env, [{"node", atom_to_list(node())},
- {"table", "ir_ModuleDef"}])),
- ?match([_H|_T], orber_web:ifr_data(env, [{"node", atom_to_list(node())},
- {"table", "ir_InterfaceDef"}])),
- ?match([_H|_T], orber_web:ifr_data(env, [{"node", atom_to_list(node())},
- {"table", "ir_StructDef"}])),
- ?match([_H|_T], orber_web:ifr_data(env, [{"node", atom_to_list(node())},
- {"table", "ir_ExceptionDef"}])),
- ?match([_H|_T], orber_web:ifr_data(env, [{"node", atom_to_list(node())},
- {"table", "ir_ConstantDef"}])),
- ?match([_H|_T], orber_web:ifr_data(env, [{"node", atom_to_list(node())},
- {"table", "ir_EnumDef"}])),
- ?match([_H|_T], orber_web:ifr_data(env, [{"node", atom_to_list(node())},
- {"table", "ir_AliasDef"}])),
- ?match([_H|_T], orber_web:ifr_data(env, [{"node", atom_to_list(node())},
- {"table", "ir_AttributeDef"}])),
- ?match([_H|_T], orber_web:ifr_data(env, [{"node", atom_to_list(node())},
- {"table", "ir_OperationDef"}])),
- ?match([_H|_T], orber_web:ifr_data(env, [{"node", atom_to_list(node())},
- {"table", "ir_Contained"}])),
- ?match([_H|_T], orber_web:ifr_data(env, [{"node", atom_to_list(node())},
- {"table", "ir_TypedefDef"}])),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: create
-%% Description:
-%%-----------------------------------------------------------------
-create(_) ->
- NodeStr = atom_to_list(node()),
- ?match({'EXIT', _}, orber_web:create(env, [])),
- ?match({'EXIT', _}, orber_web:create(env, [{"node", localhost}])),
- ?match({error, _}, orber_web:create(env, [{"node", NodeStr},
- {"module", "orber_test_server"},
- {"arguments", "[]"},
- {"options", "[bad_option 42]"},
- {"namestr", "[]"},
- {"bind", "rebind"}])),
- ?match({error, _}, orber_web:create(env, [{"node", NodeStr},
- {"module", "orber_test_server"},
- {"arguments", "[bad_argument 42]"},
- {"options", "[]"},
- {"namestr", "[]"},
- {"bind", "rebind"}])),
-
- ?match([_, NodeStr|_T], orber_web:create(env, [{"node", NodeStr}])),
-
- [_,IOR] = ?match([_,_], orber_web:create(env, [{"node", NodeStr},
- {"module", "orber_test_server"},
- {"arguments", "[]"},
- {"options", "[]"},
- {"namestr", ""},
- {"bind", "rebind"}])),
- ?match(#'IOP_IOR'{}, corba:string_to_object(IOR)),
-
- [_,_,_,_,_,IOR2] =
- ?match([_,_,_,_,_,_], orber_web:create(env, [{"node", NodeStr},
- {"module", "orber_test_server"},
- {"arguments", "[]"},
- {"options", "[]"},
- {"namestr", "id1"},
- {"bind", "rebind"}])),
- ?match(#'IOP_IOR'{}, corba:string_to_object(IOR2)),
-
- [_,_,_,IOR3] =
- ?match([_,_,_,_], orber_web:create(env, [{"node", NodeStr},
- {"module", "orber_test_server"},
- {"arguments", "[]"},
- {"options", "[{pseudo, true}]"},
- {"namestr", "id2"},
- {"bind", "rebind"}])),
- ?match(#'IOP_IOR'{}, corba:string_to_object(IOR3)),
-
- [_,IOR4] =?match([_,_], orber_web:create(env, [{"node", NodeStr},
- {"module", "orber_test_server"},
- {"arguments", "[]"},
- {"options", "[{pseudo, true}]"},
- {"namestr", ""},
- {"bind", "rebind"}])),
- ?match(#'IOP_IOR'{}, corba:string_to_object(IOR4)),
-
- ?match([_], orber_web:create(env, [{"node", NodeStr},
- {"module", "orber_test_server"},
- {"arguments", "[]"},
- {"options", "[{unknown, option}]"},
- {"namestr", "id1"},
- {"bind", "rebind"}])),
-
- ?match([_, "id1"], orber_web:create(env, [{"node", NodeStr},
- {"module", "orber_test_server"},
- {"arguments", "[]"},
- {"options", "[]"},
- {"namestr", "id1"},
- {"bind", "bind"}])),
-
- ?match([_, "id2"], orber_web:create(env, [{"node", NodeStr},
- {"module", "orber_test_server"},
- {"arguments", "[]"},
- {"options", "[{pseudo, true}]"},
- {"namestr", "id2"},
- {"bind", "bind"}])),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: delete_ctx
-%% Description:
-%%-----------------------------------------------------------------
-delete_ctx(_) ->
- ?match({ok, _}, orber_web:delete_ctx(env, [{"node", atom_to_list(node())},
- {"context", "id1"}])),
- ?match([_H|_T], orber_web:add_ctx(env, [{"node", atom_to_list(node())},
- {"context", "root"},
- {"id", "id1"}])),
- ?match([_H|_T], orber_web:delete_ctx(env, [{"node", atom_to_list(node())},
- {"context", "id1"}])),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: add_ctx
-%% Description:
-%%-----------------------------------------------------------------
-add_ctx(_) ->
- ?match({error, _}, orber_web:add_ctx(env, [{"node", "bad_node"},
- {"context", "root"},
- {"id", "id1"}])),
- ?match([_H|_T], orber_web:add_ctx(env, [{"node", atom_to_list(node())},
- {"context", "root"},
- {"id", ""}])),
- ?match([_H|_T], orber_web:add_ctx(env, [{"node", atom_to_list(node())},
- {"context", "root"},
- {"id", "id1"}])),
- ?match([_H|_T], orber_web:add_ctx(env, [{"node", atom_to_list(node())},
- {"context", "id1"},
- {"id", "id2"}])),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: delete_obj
-%% Description:
-%%-----------------------------------------------------------------
-delete_obj(_) ->
- NodeStr = atom_to_list(node()),
- ?match({error, _}, orber_web:delete_obj(env, [{"node", "bad_node"},
- {"context", "id1"},
- {"action", "unbind"}])),
- ?match({error, _}, orber_web:delete_obj(env, [{"node", "bad_node"},
- {"context", "id1"},
- {"action", "both"}])),
- ?match({'EXIT', _}, orber_web:delete_obj(env, [{"node", bad_node},
- {"context", "id1"},
- {"action", "both"}])),
- ?match({error, _}, orber_web:delete_obj(env, [{"node", NodeStr},
- {"context", "non/existing"},
- {"action", "unbind"}])),
- [_,_,_,_,_,IOR2] =
- ?match([_,_,_,_,_,_], orber_web:create(env, [{"node", NodeStr},
- {"module", "orber_test_server"},
- {"arguments", "[]"},
- {"options", "[]"},
- {"namestr", "id1"},
- {"bind", "rebind"}])),
- ?match(#'IOP_IOR'{}, corba:string_to_object(IOR2)),
-
- ?match({error, _}, orber_web:delete_obj(env, [{"node", NodeStr},
- {"context", "bad/INS./id"},
- {"action", "unbind"}])),
-
- [_,_,_,IOR3] =
- ?match([_,_,_,_], orber_web:create(env, [{"node", NodeStr},
- {"module", "orber_test_server"},
- {"arguments", "[]"},
- {"options", "[{pseudo, true}]"},
- {"namestr", "id2"},
- {"bind", "rebind"}])),
- ?match(#'IOP_IOR'{}, corba:string_to_object(IOR3)),
-
- ?match([_, "id1"|_], orber_web:delete_obj(env, [{"node", NodeStr},
- {"context", "id1"},
- {"action", "unbind"}])),
- ?match([_, "id2"|_], orber_web:delete_obj(env, [{"node", NodeStr},
- {"context", "id2"},
- {"action", "unbind"}])),
-
-
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: server
-%% Description:
-%%-----------------------------------------------------------------
-server(_) ->
- NodeStr = "node=" ++ atom_to_list(node()),
- {ok, Pid} = ?match({ok,_}, orber_web_server:start()),
- ?match({error,{already_started, Pid}}, orber_web_server:start_link()),
- ?match({error,{already_started,Pid}}, orber_web_server:start()),
- ?match({orber, _}, orber_web_server:config_data()),
- ?match([_H|_T], orber_web_server:ifr_select(env, "node=badnode")),
- ?match([_H|_T], orber_web_server:ifr_select(env, "node=" ++ NodeStr)),
- ?match([_H|_T], orber_web_server:menu(env, NodeStr)),
- ?match([_H|_T], orber_web_server:configure(env, NodeStr ++ "&data=[{orber_debug_level, 9}]")),
- ?match([_H|_T], orber_web_server:nameservice(env, NodeStr ++ "&context=root")),
- ?match([_H|_T], orber_web_server:info(env, NodeStr)),
- ?match([_H|_T], orber_web_server:ifr_data(env, NodeStr ++ "&table=ir_ModuleDef")),
- ?match([_H|_T], orber_web_server:create(env, NodeStr)),
- ?match([_H|_T], orber_web_server:add_ctx(env, NodeStr ++ "&context=root&id=id1")),
- ?match([_H|_T], orber_web_server:delete_ctx(env, NodeStr++"&context=id1")),
- ?match([_H|_T], orber_web_server:delete_obj(env, NodeStr++"&context=id1&action=unbind")),
- ?match([_H|_T], orber_web_server:default_selection(env, NodeStr)),
- ?match(ok, orber_web_server:stop()),
- ok.
-
-
diff --git a/lib/orber/test/tc_SUITE.erl b/lib/orber/test/tc_SUITE.erl
deleted file mode 100644
index 4572057403..0000000000
--- a/lib/orber/test/tc_SUITE.erl
+++ /dev/null
@@ -1,605 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache Li2cense, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%-----------------------------------------------------------------
-%%
-%% Description:
-%% Test suite for the basic typecode functions
-%%
-%%-----------------------------------------------------------------
--module(tc_SUITE).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("orber/src/orber_iiop.hrl").
-
--define(default_timeout, test_server:minutes(3)).
-
--define(match(Expr),
- fun() ->
- case (catch (Expr)) of
- AcTuAlReS when is_binary(AcTuAlReS)->
- io:format("###### ERROR ERROR ######~nRESULT: ~p~n",
- [AcTuAlReS]),
- exit(AcTuAlReS);
- _ ->
- ok
- end
- end()).
--define(SUB_ELIST, [{"null", orber_tc:null()},
- {"void", orber_tc:void()},
- {"short", orber_tc:short()},
- {"unsigned_short", orber_tc:unsigned_short()},
- {"long", orber_tc:long()},
- {"unsigned_long", orber_tc:unsigned_long()},
- {"long_long", orber_tc:long_long()},
- {"unsigned_long_long", orber_tc:unsigned_long_long()},
- {"float", orber_tc:'float'()},
- {"double", orber_tc:double()},
- {"longdouble", orber_tc:longdouble()},
- {"boolean", orber_tc:boolean()},
- {"char", orber_tc:char()},
- {"wchar", orber_tc:wchar()},
- {"octet", orber_tc:octet()},
- {"any", orber_tc:any()},
- {"typecode", orber_tc:typecode()},
- {"principal", orber_tc:principal()},
- {"object_reference", orber_tc:object_reference("Id", "Name")}]).
-
--define(ELIST, [{"null", orber_tc:null()},
- {"void", orber_tc:void()},
- {"short", orber_tc:short()},
- {"unsigned_short", orber_tc:unsigned_short()},
- {"long", orber_tc:long()},
- {"unsigned_long", orber_tc:unsigned_long()},
- {"long_long", orber_tc:long_long()},
- {"unsigned_long_long", orber_tc:unsigned_long_long()},
- {"float", orber_tc:'float'()},
- {"double", orber_tc:double()},
- {"longdouble", orber_tc:longdouble()},
- {"boolean", orber_tc:boolean()},
- {"char", orber_tc:char()},
- {"wchar", orber_tc:wchar()},
- {"octet", orber_tc:octet()},
- {"any", orber_tc:any()},
- {"typecode", orber_tc:typecode()},
- {"principal", orber_tc:principal()},
- {"object_reference", orber_tc:object_reference("Id", "Name")},
- {"struct", orber_tc:struct("Id", "Name", ?SUB_ELIST)},
- {"enum", orber_tc:enum("Id", "Name", ["E1", "E2"])},
- {"string", orber_tc:string(1)},
- {"wstring", orber_tc:wstring(0)},
- {"sequence", orber_tc:sequence(orber_tc:enum("Id", "Name",
- ["E1", "E2"]), 0)},
- {"array", orber_tc:array(orber_tc:enum("Id", "Name",
- ["E1", "E2"]), 2)},
- {"alias", orber_tc:alias("id", "name",
- orber_tc:enum("Id", "Name",
- ["E1", "E2"]))},
- {"exception", orber_tc:exception("Id", "Name", ?SUB_ELIST)}]).
-
--define(VELIST, [{"null", orber_tc:null(), 42},
- {"void", orber_tc:void(), 42},
- {"short", orber_tc:short(), 42},
- {"unsigned_short", orber_tc:unsigned_short(), 42},
- {"long", orber_tc:long(), 42},
- {"unsigned_long", orber_tc:unsigned_long(), 42},
- {"long_long", orber_tc:long_long(), 42},
- {"unsigned_long_long", orber_tc:unsigned_long_long(), 42},
- {"float", orber_tc:'float'(), 42},
- {"double", orber_tc:double(), 42},
- {"longdouble", orber_tc:longdouble(), 42},
- {"boolean", orber_tc:boolean(), 42},
- {"char", orber_tc:char(), 42},
- {"wchar", orber_tc:wchar(), 42},
- {"octet", orber_tc:octet(), 42},
- {"any", orber_tc:any(), 42},
- {"typecode", orber_tc:typecode(), 42},
- {"principal", orber_tc:principal(), 42},
- {"object_reference", orber_tc:object_reference("Id", "Name"), 42},
- {"struct", orber_tc:struct("Id", "Name", ?SUB_ELIST), 42},
- {"enum", orber_tc:enum("Id", "Name", ["E1", "E2"]), 42},
- {"string", orber_tc:string(1), 42},
- {"wstring", orber_tc:wstring(0), 42},
- {"sequence", orber_tc:sequence(orber_tc:enum("Id", "Name",
- ["E1", "E2"]), 0), 42},
- {"array", orber_tc:array(orber_tc:enum("Id", "Name",
- ["E1", "E2"]), 2), 42},
- {"alias", orber_tc:alias("id", "name",
- orber_tc:enum("Id", "Name",
- ["E1", "E2"])), 42},
- {"exception", orber_tc:exception("Id", "Name", ?SUB_ELIST), 42}]).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--compile(export_all).
-
-%%-----------------------------------------------------------------
-%% Func: all/1
-%% Args:
-%% Returns:
-%%-----------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [null, void, short, ushort, long, ulong, longlong,
- ulonglong, boolean, char, wchar, octet, float, double,
- longdouble, any, typecode, principal, object_reference,
- struct, union, enum, string, wstring, sequence, array,
- alias, exception, fixed, value, value_box, native,
- abstract_interface, indirection, get_tc].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%%-----------------------------------------------------------------
-%% Init and cleanup functions.
-%%-----------------------------------------------------------------
-
-init_per_testcase(_Case, Config) ->
- Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-
-
-end_per_testcase(_Case, Config) ->
- Dog = proplists:get_value(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: null test
-%% Description:
-%%-----------------------------------------------------------------
-null(_) ->
- true = orber_tc:check_tc(orber_tc:null()),
- code(orber_tc:null()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: void test
-%% Description:
-%%-----------------------------------------------------------------
-void(_) ->
- true = orber_tc:check_tc(orber_tc:void()),
- code(orber_tc:void()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: short integer test
-%% Description:
-%%-----------------------------------------------------------------
-short(_) ->
- true = orber_tc:check_tc(orber_tc:short()),
- code(orber_tc:short()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: unsigned short integer test
-%% Description:
-%%-----------------------------------------------------------------
-ushort(_) ->
- true = orber_tc:check_tc(orber_tc:unsigned_short()),
- code(orber_tc:unsigned_short()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: long integer test
-%% Description:
-%%-----------------------------------------------------------------
-long(_) ->
- true = orber_tc:check_tc(orber_tc:long()),
- code(orber_tc:long()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: unsigned long integer test
-%% Description:
-%%-----------------------------------------------------------------
-ulong(_) ->
- true = orber_tc:check_tc(orber_tc:unsigned_long()),
- code(orber_tc:unsigned_long()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: long integer test
-%% Description:
-%%-----------------------------------------------------------------
-longlong(_) ->
- true = orber_tc:check_tc(orber_tc:long_long()),
- code(orber_tc:long_long()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: unsigned long integer test
-%% Description:
-%%-----------------------------------------------------------------
-ulonglong(_) ->
- true = orber_tc:check_tc(orber_tc:unsigned_long_long()),
- code(orber_tc:unsigned_long_long()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: float test
-%% Description:
-%%-----------------------------------------------------------------
-float(_) ->
- true = orber_tc:check_tc(orber_tc:'float'()),
- code(orber_tc:'float'()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: double test
-%% Description:
-%%-----------------------------------------------------------------
-double(_) ->
- true = orber_tc:check_tc(orber_tc:double()),
- code(orber_tc:double()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: longdouble test
-%% Description:
-%%-----------------------------------------------------------------
-longdouble(_) ->
- true = orber_tc:check_tc(orber_tc:longdouble()),
- code(orber_tc:longdouble()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: boolean test
-%% Description:
-%%-----------------------------------------------------------------
-boolean(_) ->
- true = orber_tc:check_tc(orber_tc:boolean()),
- code(orber_tc:boolean()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: character test
-%% Description:
-%%-----------------------------------------------------------------
-char(_) ->
- true = orber_tc:check_tc(orber_tc:char()),
- code(orber_tc:char()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: character test
-%% Description:
-%%-----------------------------------------------------------------
-wchar(_) ->
- true = orber_tc:check_tc(orber_tc:wchar()),
- code(orber_tc:wchar()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: octet test
-%% Description:
-%%-----------------------------------------------------------------
-octet(_) ->
- true = orber_tc:check_tc(orber_tc:octet()),
- code(orber_tc:octet()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: any test
-%% Description:
-%%-----------------------------------------------------------------
-any(_) ->
- true = orber_tc:check_tc(orber_tc:any()),
- code(orber_tc:any()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: typecode test
-%% Description:
-%%-----------------------------------------------------------------
-typecode(_) ->
- true = orber_tc:check_tc(orber_tc:typecode()),
- code(orber_tc:typecode()),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: principal test
-%% Description:
-%%-----------------------------------------------------------------
-principal(_) ->
- true = orber_tc:check_tc(orber_tc:principal()),
- code(orber_tc:principal()),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: object_reference test
-%% Description:
-%%-----------------------------------------------------------------
-object_reference(_) ->
- true = orber_tc:check_tc(orber_tc:object_reference("Id", "Name")),
- false = orber_tc:check_tc(orber_tc:object_reference(42, "Name")),
- false = orber_tc:check_tc(orber_tc:object_reference("Id", 42)),
- code(orber_tc:object_reference("Id", "Name")),
- ?match(code(orber_tc:object_reference(42, "Name"))),
- ?match(code(orber_tc:object_reference("Id", 42))),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: struct
-%% Description:
-%%-----------------------------------------------------------------
-struct(_) ->
- true = orber_tc:check_tc(orber_tc:struct("Id", "Name", ?ELIST)),
- false = orber_tc:check_tc(orber_tc:struct(42, "Name", ?ELIST)),
- false = orber_tc:check_tc(orber_tc:struct("Id", false, ?ELIST)),
- false = orber_tc:check_tc(orber_tc:struct("Id", "Name", ?VELIST)),
- false = orber_tc:check_tc(orber_tc:struct("Id", "Name", "wrong")),
- code(orber_tc:struct("Id", "Name", ?ELIST)),
- ?match(code(orber_tc:struct(42, "Name", ?ELIST))),
- ?match(code(orber_tc:struct("Id", false, ?ELIST))),
- ?match(code(orber_tc:struct("Id", "Name", ?VELIST))),
- ?match(code(orber_tc:struct("Id", "Name", "wrong"))),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: union
-%% Description:
-%%-----------------------------------------------------------------
-union(_) ->
- true = orber_tc:check_tc(orber_tc:union("Id", "Name", orber_tc:long(),
- -1, [{1, "long", orber_tc:long()},
- {2, "longlong", orber_tc:long()}])),
- false = orber_tc:check_tc(orber_tc:union("Id", "Name", orber_tc:long(),
- -1, ?ELIST)),
- false = orber_tc:check_tc(orber_tc:union(42, "Name", orber_tc:long(),
- -1, [{1, "long", orber_tc:long()},
- {2, "longlong", orber_tc:long()}])),
- false = orber_tc:check_tc(orber_tc:union("Id", false, orber_tc:long(),
- -1, [{1, "long", orber_tc:long()},
- {2, "longlong", orber_tc:long()}])),
- false = orber_tc:check_tc(orber_tc:union("Id", "Name", bad_tc,
- -1, [{1, "long", orber_tc:long()},
- {2, "longlong", orber_tc:long()}])),
- false = orber_tc:check_tc(orber_tc:union("Id", "Name", orber_tc:long(),
- "wrong", [{1, "long", orber_tc:long()},
- {2, "longlong", orber_tc:long()}])),
-
- code(orber_tc:union("Id", "Name", orber_tc:long(),
- -1, [{1, "long", orber_tc:long()},
- {2, "longlong", orber_tc:long()}])),
- ok.
-
-
-%%-----------------------------------------------------------------
-%% Test Case: enum test
-%% Description:
-%%-----------------------------------------------------------------
-enum(_) ->
- true = orber_tc:check_tc(orber_tc:enum("Id", "Name",
- ["E1", "E2", "E3"])),
- false = orber_tc:check_tc(orber_tc:enum(42, "Name",
- ["E1", "E2", "E3"])),
- false = orber_tc:check_tc(orber_tc:enum("Id", false,
- ["E1", "E2", "E3"])),
- false = orber_tc:check_tc(orber_tc:enum("Id", "Name",
- ["E1", false, "E3"])),
- code(orber_tc:enum("Id", "Name", ["E1", "E2", "E3"])),
- ?match(code(orber_tc:enum(false, "Name", ["E1", "E2", "E3"]))),
- ?match(code(orber_tc:enum("Id", 42, ["E1", "E2", "E3"]))),
- ?match(code(orber_tc:enum("Id", "Name", ["E1", false, "E3"]))),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: string
-%% Description:
-%%-----------------------------------------------------------------
-string(_) ->
- true = orber_tc:check_tc(orber_tc:string(0)),
- true = orber_tc:check_tc(orber_tc:string(1)),
- false = orber_tc:check_tc(orber_tc:string("wrong")),
- code(orber_tc:string(0)),
- code(orber_tc:string(1)),
- ?match(code(orber_tc:string(-1))),
- ?match(code(orber_tc:string(?ULONGMAX+1))),
- ?match(code(orber_tc:string("wrong"))),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: wstring
-%% Description:
-%%-----------------------------------------------------------------
-wstring(_) ->
- true = orber_tc:check_tc(orber_tc:wstring(0)),
- true = orber_tc:check_tc(orber_tc:wstring(1)),
- false = orber_tc:check_tc(orber_tc:wstring("wrong")),
- code(orber_tc:wstring(0)),
- code(orber_tc:wstring(1)),
- ?match(code(orber_tc:wstring(-1))),
- ?match(code(orber_tc:wstring(?ULONGMAX+1))),
- ?match(code(orber_tc:wstring(false))),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: sequence
-%% Description:
-%%-----------------------------------------------------------------
-sequence(_) ->
- true = orber_tc:check_tc(orber_tc:sequence(orber_tc:struct("Id", "Name", ?ELIST), 0)),
- code(orber_tc:sequence(orber_tc:struct("Id", "Name", ?ELIST), 0)),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: array
-%% Description:
-%%-----------------------------------------------------------------
-array(_) ->
- true = orber_tc:check_tc(orber_tc:array(orber_tc:struct("Id", "Name", ?ELIST), 1)),
- code(orber_tc:array(orber_tc:struct("Id", "Name", ?ELIST), 1)),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: alias
-%% Description:
-%%-----------------------------------------------------------------
-alias(_) ->
- true = orber_tc:check_tc(orber_tc:alias("Id", "Name", orber_tc:struct("Id", "Name", ?ELIST))),
- false = orber_tc:check_tc(orber_tc:alias(false, "Name", orber_tc:struct("Id", "Name", ?ELIST))),
- false = orber_tc:check_tc(orber_tc:alias("Id", 42, orber_tc:struct("Id", "Name", ?ELIST))),
- false = orber_tc:check_tc(orber_tc:alias("Id", "Name", "wrong")),
- code(orber_tc:alias("Id", "Name", orber_tc:struct("Id", "Name", ?ELIST))),
- ?match(code(orber_tc:alias("Id", "Name", orber_tc:struct("Id", "Name", ?VELIST)))),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: exception
-%% Description:
-%%-----------------------------------------------------------------
-exception(_) ->
- true = orber_tc:check_tc(orber_tc:exception("Id", "Name", ?ELIST)),
- false = orber_tc:check_tc(orber_tc:exception(42, "Name", ?ELIST)),
- false = orber_tc:check_tc(orber_tc:exception("Id", false, ?ELIST)),
- false = orber_tc:check_tc(orber_tc:exception("Id", "Name", "wrong")),
- code(orber_tc:exception("Id", "Name", ?ELIST)),
- ?match(code(orber_tc:exception(42, "Name", ?ELIST))),
- ?match(code(orber_tc:exception("Id", false, ?ELIST))),
- ?match(code(orber_tc:exception("Id", "Name", "wrong"))),
-
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: fixed
-%% Description:
-%%-----------------------------------------------------------------
-fixed(_) ->
- true = orber_tc:check_tc(orber_tc:fixed(25, 2)),
- code(orber_tc:fixed(25, 2)),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: value
-%% Description:
-%%-----------------------------------------------------------------
-value(_) ->
- true = orber_tc:check_tc(orber_tc:value("Id", "Name", 42,
- orber_tc:fixed(25, 2), ?VELIST)),
- false = orber_tc:check_tc(orber_tc:value(42, "Name", 42,
- orber_tc:fixed(25, 2), ?VELIST)),
- false = orber_tc:check_tc(orber_tc:value("Id", 42, 42,
- orber_tc:fixed(25, 2), ?VELIST)),
- false = orber_tc:check_tc(orber_tc:value("Id", "Name", "wrong",
- orber_tc:fixed(25, 2), ?VELIST)),
- false = orber_tc:check_tc(orber_tc:value("Id", "Name", "42",
- orber_tc:fixed(25, 2), ?VELIST)),
- false = orber_tc:check_tc(orber_tc:value("Id", "Name", "42",
- ?VELIST, ?VELIST)),
- false = orber_tc:check_tc(orber_tc:value("Id", "Name", "42",
- orber_tc:fixed(25, 2), false)),
-
- code(orber_tc:value("Id", "Name", 42, orber_tc:long(), ?VELIST)),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: value_box
-%% Description:
-%%-----------------------------------------------------------------
-value_box(_) ->
- true = orber_tc:check_tc(orber_tc:value_box("Id", "Name",
- orber_tc:fixed(25, 2))),
- false = orber_tc:check_tc(orber_tc:value_box(42, "Name",
- orber_tc:fixed(25, 2))),
- false = orber_tc:check_tc(orber_tc:value_box("Id", 42,
- orber_tc:fixed(25, 2))),
- false = orber_tc:check_tc(orber_tc:value_box("Id", "Name", "wrong")),
- code(orber_tc:value_box("Id", "Name", orber_tc:long())),
- ?match(code(orber_tc:value_box(42, "Name", orber_tc:short()))),
- ?match(code(orber_tc:value_box("Id", 42, orber_tc:char()))),
- ?match(code(orber_tc:value_box("Id", "Name", false))),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: native
-%% Description:
-%%-----------------------------------------------------------------
-native(_) ->
- true = orber_tc:check_tc(orber_tc:native("Id", "Name")),
- false = orber_tc:check_tc(orber_tc:native(42, "Name")),
- false = orber_tc:check_tc(orber_tc:native("Id", 42)),
- code(orber_tc:native("Id", "Name")),
- ?match(code(orber_tc:native(42, "Name"))),
- ?match(code(orber_tc:native("Id", 42))),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: abstract_interface
-%% Description:
-%%-----------------------------------------------------------------
-abstract_interface(_) ->
- true = orber_tc:check_tc(orber_tc:abstract_interface("RepId", "Name")),
- false = orber_tc:check_tc(orber_tc:abstract_interface(false, "Name")),
- false = orber_tc:check_tc(orber_tc:abstract_interface("RepId", 42)),
- code(orber_tc:abstract_interface("RepId", "Name")),
- ?match(code(orber_tc:abstract_interface(42, "Name"))),
- ?match(code(orber_tc:abstract_interface("Id", 42))),
- ok.
-
-
-
-%%-----------------------------------------------------------------
-%% Test Case: indirection
-%% Description:
-%%-----------------------------------------------------------------
-indirection(_) ->
- true = orber_tc:check_tc({'none', 42}),
- ok.
-
-%%-----------------------------------------------------------------
-%% Test Case: get_tc
-%% Description:
-%%-----------------------------------------------------------------
-get_tc(_) ->
- TC = 'CosNaming_Binding':tc(),
- TC = orber_tc:get_tc({'CosNaming_Binding', 42}),
- ?match(orber_tc:get_tc({'none', 42})),
- ok.
-
-%%-----------------------------------------------------------------
-%% MISC Operations
-%%-----------------------------------------------------------------
-code(Value) ->
- cdr_encode:enc_type({1,2}, tk_TypeCode, Value).
diff --git a/lib/orber/vsn.mk b/lib/orber/vsn.mk
deleted file mode 100644
index bfd3f283b5..0000000000
--- a/lib/orber/vsn.mk
+++ /dev/null
@@ -1 +0,0 @@
-ORBER_VSN = 3.8.4
diff --git a/lib/os_mon/Makefile b/lib/os_mon/Makefile
index 1eff8a785a..40ce94e0c7 100644
--- a/lib/os_mon/Makefile
+++ b/lib/os_mon/Makefile
@@ -23,11 +23,7 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
#
# Macros
#
-ifeq ($(findstring win32,$(TARGET)),win32)
-SUB_DIRECTORIES = src c_src mibs doc/src
-else
-SUB_DIRECTORIES = src c_src mibs doc/src
-endif
+SUB_DIRECTORIES = src c_src doc/src
include vsn.mk
VSN = $(OS_MON_VSN)
diff --git a/lib/os_mon/c_src/cpu_sup.c b/lib/os_mon/c_src/cpu_sup.c
index 17ef48c26e..c96a5c9f7c 100644
--- a/lib/os_mon/c_src/cpu_sup.c
+++ b/lib/os_mon/c_src/cpu_sup.c
@@ -152,6 +152,8 @@ static void util_measure(unsigned int **result_vec, int *result_sz);
#if defined(__sun__)
static unsigned int misc_measure(char* name);
+#elif defined(__linux__)
+static unsigned int misc_measure(char cmd);
#endif
static void sendi(unsigned int data);
static void sendv(unsigned int data[], int ints);
@@ -231,6 +233,11 @@ int main(int argc, char** argv) {
case AVG1: sendi(misc_measure("avenrun_1min")); break;
case AVG5: sendi(misc_measure("avenrun_5min")); break;
case AVG15: sendi(misc_measure("avenrun_15min")); break;
+#elif defined(__linux__)
+ case NPROCS:
+ case AVG1:
+ case AVG5:
+ case AVG15: sendi(misc_measure(cmd)); break;
#elif defined(__OpenBSD__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD__) || defined(__DragonFly__)
case NPROCS: bsd_count_procs(); break;
case AVG1: bsd_loadavg(0); break;
@@ -238,7 +245,7 @@ int main(int argc, char** argv) {
case AVG15: bsd_loadavg(2); break;
#endif
#if defined(__sun__) || defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD__)
- case UTIL: util_measure(&rv,&sz); sendv(rv, sz); break;
+ case UTIL: util_measure(&rv,&sz); sendv(rv, sz); break;
#endif
case QUIT: free((void*)rv); return 0;
default: error("Bad command"); break;
@@ -329,6 +336,22 @@ static void bsd_count_procs(void) {
#if defined(__linux__)
+static unsigned int misc_measure(char cmd) {
+ struct sysinfo info;
+
+ if (sysinfo(&info))
+ error(strerror(errno));
+
+ switch (cmd) {
+ case AVG1: return (unsigned int)(info.loads[0] / 256);
+ case AVG5: return (unsigned int)(info.loads[1] / 256);
+ case AVG15: return (unsigned int)(info.loads[2] / 256);
+ case NPROCS: return info.procs;
+ }
+
+ return -1;
+}
+
static cpu_t *read_procstat(FILE *fp, cpu_t *cpu) {
char buffer[BUFFERSIZE];
@@ -357,8 +380,24 @@ static void util_measure(unsigned int **result_vec, int *result_sz) {
FILE *fp;
unsigned int *rv = NULL;
cpu_t cpu;
-
+
+ rv = *result_vec;
+ rv[0] = no_of_cpus;
+
if ( (fp = fopen(PROCSTAT,"r")) == NULL) {
+ if (errno == EACCES) { /* SELinux */
+ rv[1] = 1; /* just the cpu id */
+ ++rv; /* first value is number of cpus */
+ ++rv; /* second value is number of entries */
+ for (i = 0; i < no_of_cpus; ++i) {
+ rv[0] = CU_CPU_ID;
+ rv[1] = i;
+ rv += 1*2;
+ }
+ *result_sz = 2 + 2*1 * no_of_cpus;
+ return;
+ }
+
/* Check if procfs is mounted,
* otherwise:
* try and try again, bad procsfs.
@@ -367,20 +406,19 @@ static void util_measure(unsigned int **result_vec, int *result_sz) {
return;
}
- /*ignore read*/
+ /*ignore read*/
if (fgets(buffer, BUFFERSIZE, fp) == NULL) {
*result_sz = 0;
return;
}
- rv = *result_vec;
- rv[0] = no_of_cpus;
+
rv[1] = CU_VALUES;
++rv; /* first value is number of cpus */
++rv; /* second value is number of entries */
for (i = 0; i < no_of_cpus; ++i) {
read_procstat(fp, &cpu);
-
+
rv[ 0] = CU_CPU_ID; rv[ 1] = cpu.id;
rv[ 2] = CU_USER; rv[ 3] = cpu.user;
rv[ 4] = CU_NICE_USER; rv[ 5] = cpu.nice_user;
diff --git a/lib/os_mon/doc/src/Makefile b/lib/os_mon/doc/src/Makefile
index 4aa8879a91..8e9a4c333c 100644
--- a/lib/os_mon/doc/src/Makefile
+++ b/lib/os_mon/doc/src/Makefile
@@ -39,7 +39,6 @@ XML_APPLICATION_FILES = ref_man.xml
XML_REF3_FILES = cpu_sup.xml \
disksup.xml \
memsup.xml \
- os_mon_mib.xml \
os_sup.xml \
nteventlog.xml
@@ -98,6 +97,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/lib/os_mon/doc/src/cpu_sup.xml b/lib/os_mon/doc/src/cpu_sup.xml
index bada165a06..b7adb2bcd2 100644
--- a/lib/os_mon/doc/src/cpu_sup.xml
+++ b/lib/os_mon/doc/src/cpu_sup.xml
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>cpu_sup</module>
+ <module since="">cpu_sup</module>
<modulesummary>A CPU Load and CPU Utilization Supervisor Process</modulesummary>
<description>
<p><c>cpu_sup</c> is a process which supervises the CPU load
@@ -76,7 +76,7 @@
</description>
<funcs>
<func>
- <name>nprocs() -> UnixProcesses | {error, Reason}</name>
+ <name since="">nprocs() -> UnixProcesses | {error, Reason}</name>
<fsummary>Get the number of UNIX processes running on this host</fsummary>
<type>
<v>UnixProcesses = int()</v>
@@ -90,7 +90,7 @@
</desc>
</func>
<func>
- <name>avg1() -> SystemLoad | {error, Reason}</name>
+ <name since="">avg1() -> SystemLoad | {error, Reason}</name>
<fsummary>Get the system load average for the last minute</fsummary>
<type>
<v>SystemLoad = int()</v>
@@ -104,7 +104,7 @@
</desc>
</func>
<func>
- <name>avg5() -> SystemLoad | {error, Reason}</name>
+ <name since="">avg5() -> SystemLoad | {error, Reason}</name>
<fsummary>Get the system load average for the last five minutes</fsummary>
<type>
<v>SystemLoad = int()</v>
@@ -118,7 +118,7 @@
</desc>
</func>
<func>
- <name>avg15() -> SystemLoad | {error, Reason}</name>
+ <name since="">avg15() -> SystemLoad | {error, Reason}</name>
<fsummary>Get the system load average for the last fifteen minutes</fsummary>
<type>
<v>SystemLoad = int()</v>
@@ -132,7 +132,7 @@
</desc>
</func>
<func>
- <name>util() -> CpuUtil | {error, Reason}</name>
+ <name since="">util() -> CpuUtil | {error, Reason}</name>
<fsummary>Get the CPU utilization</fsummary>
<type>
<v>CpuUtil = float()</v>
@@ -156,7 +156,7 @@
</desc>
</func>
<func>
- <name>util(Opts) -> UtilSpec | {error, Reason}</name>
+ <name since="">util(Opts) -> UtilSpec | {error, Reason}</name>
<fsummary>Get the CPU utilization</fsummary>
<type>
<v>Opts = [detailed | per_cpu]</v>
diff --git a/lib/os_mon/doc/src/disksup.xml b/lib/os_mon/doc/src/disksup.xml
index 610ef2c907..116a6dfd19 100644
--- a/lib/os_mon/doc/src/disksup.xml
+++ b/lib/os_mon/doc/src/disksup.xml
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>disksup</module>
+ <module since="">disksup</module>
<modulesummary>A Disk Supervisor Process</modulesummary>
<description>
<p><c>disksup</c> is a process which supervises the available disk
@@ -92,7 +92,7 @@
</section>
<funcs>
<func>
- <name>get_disk_data() -> [DiskData]</name>
+ <name since="">get_disk_data() -> [DiskData]</name>
<fsummary>Get data for the disks in the system</fsummary>
<type>
<v>DiskData = {Id, KByte, Capacity}</v>
@@ -112,7 +112,7 @@
</desc>
</func>
<func>
- <name>get_check_interval() -> MS</name>
+ <name since="">get_check_interval() -> MS</name>
<fsummary>Get time interval, in milliseconds, for the periodic disk space check</fsummary>
<type>
<v>MS = int()</v>
@@ -123,7 +123,7 @@
</desc>
</func>
<func>
- <name>set_check_interval(Minutes) -> ok</name>
+ <name since="">set_check_interval(Minutes) -> ok</name>
<fsummary>Set time interval, in minutes, for the periodic disk space check</fsummary>
<type>
<v>Minutes = int()>=1</v>
@@ -138,7 +138,7 @@
</desc>
</func>
<func>
- <name>get_almost_full_threshold() -> Percent</name>
+ <name since="">get_almost_full_threshold() -> Percent</name>
<fsummary>Get threshold, in percent, for disk space utilization</fsummary>
<type>
<v>Percent = int()</v>
@@ -148,7 +148,7 @@
</desc>
</func>
<func>
- <name>set_almost_full_threshold(Float) -> ok</name>
+ <name since="">set_almost_full_threshold(Float) -> ok</name>
<fsummary>Set threshold, as percentage represented by a float, for disk space utilization</fsummary>
<type>
<v>Float = float(), 0=&lt;Float=&lt;1</v>
diff --git a/lib/os_mon/doc/src/memsup.xml b/lib/os_mon/doc/src/memsup.xml
index c669e4670a..51c78b07c2 100644
--- a/lib/os_mon/doc/src/memsup.xml
+++ b/lib/os_mon/doc/src/memsup.xml
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>memsup</module>
+ <module since="">memsup</module>
<modulesummary>A Memory Supervisor Process</modulesummary>
<description>
<p><c>memsup</c> is a process which supervises the memory usage for
@@ -127,7 +127,7 @@
</section>
<funcs>
<func>
- <name>get_memory_data() -> {Total,Allocated,Worst}</name>
+ <name since="">get_memory_data() -> {Total,Allocated,Worst}</name>
<fsummary>Get data for the memory in the system</fsummary>
<type>
<v>Total = Allocated = int()</v>
@@ -155,7 +155,7 @@
</desc>
</func>
<func>
- <name>get_system_memory_data() -> MemDataList</name>
+ <name since="">get_system_memory_data() -> MemDataList</name>
<fsummary>Get system dependent memory data</fsummary>
<type>
<v>MemDataList = [{Tag, Size}]</v>
@@ -216,7 +216,7 @@
</desc>
</func>
<func>
- <name>get_os_wordsize() -> Wordsize</name>
+ <name since="">get_os_wordsize() -> Wordsize</name>
<fsummary>Get the wordsize of running os.</fsummary>
<type>
<v>Wordsize = 32 | 64 | unsupported_os</v>
@@ -226,7 +226,7 @@
</desc>
</func>
<func>
- <name>get_check_interval() -> MS</name>
+ <name since="">get_check_interval() -> MS</name>
<fsummary>Get time interval, in milliseconds, for the periodic memory check</fsummary>
<type>
<v>MS = int()</v>
@@ -237,7 +237,7 @@
</desc>
</func>
<func>
- <name>set_check_interval(Minutes) -> ok</name>
+ <name since="">set_check_interval(Minutes) -> ok</name>
<fsummary>Set time interval, in minutes, for the periodic memory check</fsummary>
<type>
<v>Minutes = int()>0</v>
@@ -252,7 +252,7 @@
</desc>
</func>
<func>
- <name>get_procmem_high_watermark() -> int()</name>
+ <name since="">get_procmem_high_watermark() -> int()</name>
<fsummary>Get threshold, in percent, for process memory allocation</fsummary>
<desc>
<p>Returns the threshold, in percent, for process memory
@@ -260,7 +260,7 @@
</desc>
</func>
<func>
- <name>set_procmem_high_watermark(Float) -> ok</name>
+ <name since="">set_procmem_high_watermark(Float) -> ok</name>
<fsummary>Set threshold, as percentage represented by a float, for process memory allocation</fsummary>
<desc>
<p>Changes the threshold, given as a float, for process memory
@@ -273,7 +273,7 @@
</desc>
</func>
<func>
- <name>get_sysmem_high_watermark() -> int()</name>
+ <name since="">get_sysmem_high_watermark() -> int()</name>
<fsummary>Get threshold, in percent, for system memory allocation</fsummary>
<desc>
<p>Returns the threshold, in percent, for system memory
@@ -281,7 +281,7 @@
</desc>
</func>
<func>
- <name>set_sysmem_high_watermark(Float) -> ok</name>
+ <name since="">set_sysmem_high_watermark(Float) -> ok</name>
<fsummary>Set threshold, given as a float, for system memory allocation</fsummary>
<desc>
<p>Changes the threshold, given as a float, for system memory
@@ -294,7 +294,7 @@
</desc>
</func>
<func>
- <name>get_helper_timeout() -> Seconds</name>
+ <name since="">get_helper_timeout() -> Seconds</name>
<fsummary>Get the timeout value, in seconds, for memory checks</fsummary>
<type>
<v>Seconds = int()</v>
@@ -304,7 +304,7 @@
</desc>
</func>
<func>
- <name>set_helper_timeout(Seconds) -> ok</name>
+ <name since="">set_helper_timeout(Seconds) -> ok</name>
<fsummary>Set the timeout value, in seconds, for memory checks</fsummary>
<type>
<v>Seconds = int() (>= 1)</v>
diff --git a/lib/os_mon/doc/src/notes.xml b/lib/os_mon/doc/src/notes.xml
index cec0856a8b..1f169263e9 100644
--- a/lib/os_mon/doc/src/notes.xml
+++ b/lib/os_mon/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2016</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,6 +31,84 @@
</header>
<p>This document describes the changes made to the OS_Mon application.</p>
+<section><title>Os_Mon 2.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix typespec of <c>cpu_sup:util()</c>.</p>
+ <p>
+ Own Id: OTP-15770 Aux Id: PR-2208 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The application otp_mibs has been removed from OTP. Some
+ of its components (mibs) have been moved to other apps
+ (snmp), or removed completely (os_mon).</p>
+ <p>
+ Own Id: OTP-14984 Aux Id: OTP-15329 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Os_Mon 2.4.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Due to <c>/proc</c> restrictions in newer Android
+ releases enforced by SELinux, cpu_sup is fixed so that it
+ gets some basic CPU stats using the <c>sysinfo</c>
+ syscall rather than reading <c>/proc/loadavg</c>.</p>
+ <p>
+ Own Id: OTP-15387 Aux Id: PR-1966 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Os_Mon 2.4.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Os_Mon 2.4.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix <c>disksup</c> to handle mount paths with spaces in
+ them.</p>
+ <p>
+ Own Id: OTP-14513</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Os_Mon 2.4.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/os_mon/doc/src/nteventlog.xml b/lib/os_mon/doc/src/nteventlog.xml
index d32427227c..08cf165a24 100644
--- a/lib/os_mon/doc/src/nteventlog.xml
+++ b/lib/os_mon/doc/src/nteventlog.xml
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>nteventlog</module>
+ <module since="">nteventlog</module>
<modulesummary>Interface to Windows Event Log</modulesummary>
<description>
<p><c>nteventlog</c> provides a generic interface to the Windows
@@ -61,8 +61,8 @@
</description>
<funcs>
<func>
- <name>start(Identifier, MFA) -> Result</name>
- <name>start_link(Identifier, MFA) -> Result</name>
+ <name since="">start(Identifier, MFA) -> Result</name>
+ <name since="">start_link(Identifier, MFA) -> Result</name>
<fsummary>Start the NT eventlog server</fsummary>
<type>
<v>Identifier = string() | atom()</v>
@@ -82,7 +82,7 @@
</desc>
</func>
<func>
- <name>stop() -> stopped</name>
+ <name since="">stop() -> stopped</name>
<fsummary>Stop the NT eventlog server</fsummary>
<type>
<v>Result = stopped</v>
diff --git a/lib/os_mon/doc/src/os_mon_app.xml b/lib/os_mon/doc/src/os_mon_app.xml
index 99492a2021..c77a9d0411 100644
--- a/lib/os_mon/doc/src/os_mon_app.xml
+++ b/lib/os_mon/doc/src/os_mon_app.xml
@@ -88,33 +88,6 @@
</section>
<section>
- <title>SNMP MIBs</title>
- <p>The following MIBs are defined in OS_Mon:</p>
- <taglist>
- <tag>OTP-OS-MON-MIB</tag>
- <item>
- <p>This MIB contains objects for instrumentation of disk,
- memory and CPU usage of the nodes in the system.</p>
- </item>
- </taglist>
- <p>The MIB is stored in the <c>mibs</c> directory. It is defined
- in SNMPv2 SMI syntax. An SNMPv1 version of the MIB is delivered
- in the <c>mibs/v1</c> directory.</p>
- <p>The compiled MIB is located under <c>priv/mibs</c>, and
- the generated <c>.hrl</c> file under the <c>include</c> directory.
- To compile a MIB that IMPORTS the <c>OTP-OS-MON-MIB</c>, give
- the option <c>{il, ["os_mon/priv/mibs"]}</c> to the MIB compiler.</p>
- <p>If the MIB should be used in a system, it should be loaded into
- an agent with a call to <c>os_mon_mib:load(Agent)</c>, where
- <c>Agent</c> is the pid or registered name of an SNMP agent. Use
- <c>os_mon_mib:unload(Agent)</c> to unload the MIB.
- The implementation of this MIB uses Mnesia to store a cache with
- data needed, which implicates that Mnesia must be up and running.
- The MIB also use functions defined for the <c>OTP-MIB</c>, thus
- that MIB must be loaded as well.</p>
- </section>
-
- <section>
<title>See Also</title>
<p><seealso marker="cpu_sup">cpu_sup(3)</seealso>,
<seealso marker="disksup">disksup(3)</seealso>,
diff --git a/lib/os_mon/doc/src/os_mon_mib.xml b/lib/os_mon/doc/src/os_mon_mib.xml
deleted file mode 100644
index dcf3649876..0000000000
--- a/lib/os_mon/doc/src/os_mon_mib.xml
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2004</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>os_mon_mib</title>
- <prepared>Ingela Andin</prepared>
- <responsible></responsible>
- <docno></docno>
- <date></date>
- <rev></rev>
- </header>
- <module>os_mon_mib</module>
- <modulesummary>Loading and Unloading of OTP-OS-MON-MIB</modulesummary>
- <description>
- <p>Functions for loading and unloading the OTP-OS-MON-MIB into/from
- an SNMP agent. The instrumentation of the OTP-OS-MON-MIB uses
- Mnesia, hence Mnesia must be started prior to loading
- the OTP-OS-MON-MIB.</p>
- </description>
- <funcs>
- <func>
- <name>load(Agent) -> ok | {error, Reason}</name>
- <fsummary>Load the OTP-OS-MON-MIB</fsummary>
- <type>
- <v>Agent = pid() | atom()</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Loads the OTP-OS-MON-MIB.</p>
- </desc>
- </func>
- <func>
- <name>unload(Agent) -> ok | {error, Reason}</name>
- <fsummary>Unload the OTP-OS-MON-MIB</fsummary>
- <type>
- <v>Agent = pid() | atom() </v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Unloads the OTP-OS-MON-MIB.</p>
- </desc>
- </func>
- </funcs>
-
- <section>
- <title>See Also</title>
- <p><seealso marker="os_mon_app">os_mon(6)</seealso>,
- <seealso marker="snmp:snmp">snmp(3)</seealso></p>
- </section>
-</erlref>
-
diff --git a/lib/os_mon/doc/src/os_sup.xml b/lib/os_mon/doc/src/os_sup.xml
index d517f387b4..4a84165a6c 100644
--- a/lib/os_mon/doc/src/os_sup.xml
+++ b/lib/os_mon/doc/src/os_sup.xml
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>os_sup</module>
+ <module since="">os_sup</module>
<modulesummary>Interface to OS System Messages</modulesummary>
<description>
<p><c>os_sup</c> is a process providing a message passing service
@@ -159,8 +159,8 @@
</section>
<funcs>
<func>
- <name>enable() -> ok | {error, Res}</name>
- <name>enable(Dir, Conf) -> ok | {error, Error}</name>
+ <name since="">enable() -> ok | {error, Res}</name>
+ <name since="">enable(Dir, Conf) -> ok | {error, Error}</name>
<fsummary>Enable the service (Solaris only)</fsummary>
<type>
<v>Dir = Conf = Res = string()</v>
@@ -194,8 +194,8 @@
</desc>
</func>
<func>
- <name>disable() -> ok | {error, Res}</name>
- <name>disable(Dir, Conf) -> ok | {error, Error}</name>
+ <name since="">disable() -> ok | {error, Res}</name>
+ <name since="">disable(Dir, Conf) -> ok | {error, Error}</name>
<fsummary>Disable the service (Solaris only)</fsummary>
<type>
<v>Dir = Conf = Res = string()</v>
diff --git a/lib/os_mon/doc/src/ref_man.xml b/lib/os_mon/doc/src/ref_man.xml
index a8f847a8ba..57dd5c5f0b 100644
--- a/lib/os_mon/doc/src/ref_man.xml
+++ b/lib/os_mon/doc/src/ref_man.xml
@@ -36,7 +36,6 @@
<xi:include href="cpu_sup.xml"/>
<xi:include href="disksup.xml"/>
<xi:include href="memsup.xml"/>
- <xi:include href="os_mon_mib.xml"/>
<xi:include href="os_sup.xml"/>
<xi:include href="nteventlog.xml"/>
</application>
diff --git a/lib/os_mon/mibs/Makefile b/lib/os_mon/mibs/Makefile
deleted file mode 100644
index dbc105ee3d..0000000000
--- a/lib/os_mon/mibs/Makefile
+++ /dev/null
@@ -1,101 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(OS_MON_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/os_mon-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-
-MIB_FILES= OTP-OS-MON-MIB.mib
-FUNCS_FILES = OTP-OS-MON-MIB.funcs
-
-BIN_TARGETS= $(MIB_FILES:%.mib=$(SNMP_BIN_TARGET_DIR)/%.bin)
-HRL_TARGETS= $(MIB_FILES:%.mib=$(SNMP_HRL_TARGET_DIR)/%.hrl)
-V1_MIB_FILES= $(MIB_FILES:%.mib=v1/%.mib.v1)
-
-TARGET_FILES= $(SNMP_BIN_TARGET_DIR)/OTP-REG.bin \
- $(SNMP_BIN_TARGET_DIR)/OTP-TC.bin \
- $(SNMP_BIN_TARGET_DIR)/OTP-MIB.bin \
- $(BIN_TARGETS) $(HRL_TARGETS) $(V1_MIB_FILES)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-SNMP_FLAGS = -I $(SNMP_BIN_TARGET_DIR)
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug opt: $(TARGET_FILES)
-
-clean:
- rm -f $(TARGET_FILES)
- rm -f core
-
-docs:
-
-OTP_MIBDIR = $(shell if test -d ../../otp_mibs; then echo otp_mibs; \
- else echo sasl; fi)
-
-$(SNMP_BIN_TARGET_DIR)/OTP-REG.bin: $(ERL_TOP)/lib/$(OTP_MIBDIR)/mibs/OTP-REG.mib
- $(snmp_verbose)$(ERLC) -pa $(SNMP_TOOLKIT)/ebin -I $(SNMP_TOOLKIT)/priv/mibs $(SNMP_FLAGS) -o $(SNMP_BIN_TARGET_DIR) $<
-
-$(SNMP_BIN_TARGET_DIR)/OTP-TC.bin: $(ERL_TOP)/lib/$(OTP_MIBDIR)/mibs/OTP-TC.mib
- $(snmp_verbose)$(ERLC) -pa $(SNMP_TOOLKIT)/ebin -I $(SNMP_TOOLKIT)/priv/mibs $(SNMP_FLAGS) -o $(SNMP_BIN_TARGET_DIR) $<
-
-$(SNMP_BIN_TARGET_DIR)/OTP-MIB.bin: $(ERL_TOP)/lib/$(OTP_MIBDIR)/mibs/OTP-MIB.mib
- $(snmp_verbose)$(ERLC) -pa $(SNMP_TOOLKIT)/ebin -I $(SNMP_TOOLKIT)/priv/mibs $(SNMP_FLAGS) -o $(SNMP_BIN_TARGET_DIR) $<
-
-v1/%.mib.v1: %.mib
- $(gen_verbose)$(ERL_TOP)/lib/snmp/bin/snmp-v2tov1 -o $@ $<
-
-$(SNMP_BIN_TARGET_DIR)/OTP-OS-MON-MIB.bin: \
- $(SNMP_BIN_TARGET_DIR)/OTP-REG.bin \
- $(SNMP_BIN_TARGET_DIR)/OTP-MIB.bin \
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/mibs"
- $(INSTALL_DIR) "$(RELSYSDIR)/mibs/v1"
- $(INSTALL_DATA) $(MIB_FILES) $(FUNCS_FILES) "$(RELSYSDIR)/mibs"
- $(INSTALL_DATA) $(V1_MIB_FILES) "$(RELSYSDIR)/mibs/v1"
- $(INSTALL_DIR) "$(RELSYSDIR)/include"
- $(INSTALL_DATA) $(HRL_TARGETS) "$(RELSYSDIR)/include"
- $(INSTALL_DIR) "$(RELSYSDIR)/priv/mibs"
- $(INSTALL_DATA) $(BIN_TARGETS) "$(RELSYSDIR)/priv/mibs"
-
-release_docs_spec:
diff --git a/lib/os_mon/mibs/OTP-OS-MON-MIB.funcs b/lib/os_mon/mibs/OTP-OS-MON-MIB.funcs
deleted file mode 100644
index 7ed76517b9..0000000000
--- a/lib/os_mon/mibs/OTP-OS-MON-MIB.funcs
+++ /dev/null
@@ -1,5 +0,0 @@
-{loadMemorySystemWatermark, {os_mon_mib, mem_sys_mark, []}}.
-{loadMemoryErlProcWatermark, {os_mon_mib, mem_proc_mark, []}}.
-{loadTable, {os_mon_mib, load_table, []}}.
-{diskAlmostFullThreshold, {os_mon_mib, disk_threshold, []}}.
-{diskTable, {os_mon_mib, disk_table, []}}.
diff --git a/lib/os_mon/mibs/OTP-OS-MON-MIB.mib b/lib/os_mon/mibs/OTP-OS-MON-MIB.mib
deleted file mode 100644
index e027e96154..0000000000
--- a/lib/os_mon/mibs/OTP-OS-MON-MIB.mib
+++ /dev/null
@@ -1,423 +0,0 @@
---
--- %CopyrightBegin%
---
--- Copyright Ericsson AB 1997-2016. All Rights Reserved.
---
--- Licensed under the Apache License, Version 2.0 (the "License");
--- you may not use this file except in compliance with the License.
--- You may obtain a copy of the License at
---
--- http://www.apache.org/licenses/LICENSE-2.0
---
--- Unless required by applicable law or agreed to in writing, software
--- distributed under the License is distributed on an "AS IS" BASIS,
--- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--- See the License for the specific language governing permissions and
--- limitations under the License.
---
--- %CopyrightEnd%
---
-
-OTP-OS-MON-MIB DEFINITIONS ::= BEGIN
-
-IMPORTS
- MODULE-IDENTITY, NOTIFICATION-TYPE, OBJECT-TYPE,
- Counter32, Gauge32, Integer32, Unsigned32, Counter64
- FROM SNMPv2-SMI
- TEXTUAL-CONVENTION, DisplayString
- FROM SNMPv2-TC
- MODULE-COMPLIANCE, NOTIFICATION-GROUP, OBJECT-GROUP
- FROM SNMPv2-CONF
- otpModules, otpApplications
- FROM OTP-REG
- erlNodeId
- FROM OTP-MIB
- ;
-
-
-otpOsMonModule MODULE-IDENTITY
- LAST-UPDATED "0305090900Z"
- ORGANIZATION "Ericsson"
- CONTACT-INFO
- "Contact: Erlang Support see license agreement for Erlang/OTP."
-
- DESCRIPTION
- "This MIB is part of the OTP MIB. It defines MIB objects
- for the os_mon application in OTP."
-
- REVISION "0508260900Z"
- DESCRIPTION
- "Removed dependeny on EVA."
- REVISION "0305090900Z"
- DESCRIPTION
- "Changed CONTACT-INFO as it was outdated, made it more generic
- to avoid such changes in the future."
-
- REVISION "9807080900Z"
- DESCRIPTION
- "Changed MAX-ACCESS for diskDescr from not-accessible to
- read-only."
-
- REVISION "9801270900Z"
- DESCRIPTION
- "Changed erroneous name of this module to otpOsMonModule."
-
- REVISION "9712010900Z"
- DESCRIPTION
- "Converted to v2 SMI and placed in the OTP tree."
-
- REVISION "9608191700Z"
- DESCRIPTION
- "The initial revision of MIB module OTP-OS-MON-MIB."
- ::= { otpModules 4 }
-
-OTPCounterBasedGauge64 ::= TEXTUAL-CONVENTION
- STATUS current
- DESCRIPTION
- "The CounterBasedGauge64 type represents a non-negative
- integer, which may increase or decrease, but shall never
- exceed a maximum value, nor fall below a minimum value. The
- maximum value can not be greater than 2^64-1
- (18446744073709551615 decimal), and the minimum value can
-
- not be smaller than 0. The value of a CounterBasedGauge64
- has its maximum value whenever the information being modeled
- is greater than or equal to its maximum value, and has its
- minimum value whenever the information being modeled is
- smaller than or equal to its minimum value. If the
- information being modeled subsequently decreases below
- (increases above) the maximum (minimum) value, the
- CounterBasedGauge64 also decreases (increases).
-
- Note that this TC is not strictly supported in SMIv2,
- because the 'always increasing' and 'counter wrap' semantics
- associated with the Counter64 base type are not preserved.
- It is possible that management applications which rely
- solely upon the (Counter64) ASN.1 tag to determine object
- semantics will mistakenly operate upon objects of this type
- as they would for Counter64 objects.
-
- This textual convention represents a limited and short-term
- solution, and may be deprecated as a long term solution is
- defined and deployed to replace it."
- SYNTAX Counter64
-
-otpOsMonMIB OBJECT IDENTIFIER ::= { otpApplications 2 }
-otpOsMonMIBConformance
- OBJECT IDENTIFIER ::= { otpOsMonMIB 1 }
-otpOsMonMIBObjects
- OBJECT IDENTIFIER ::= { otpOsMonMIB 2 }
-otpOsMonMIBAlarms
- OBJECT IDENTIFIER ::= { otpOsMonMIB 4 }
-otpOsMonMIBAlarmsV2
- OBJECT IDENTIFIER ::= { otpOsMonMIBAlarms 0 }
-
-
--- Datatypes
-
--- Managed Objects
-
-load OBJECT IDENTIFIER ::= { otpOsMonMIBObjects 1 }
-disk OBJECT IDENTIFIER ::= { otpOsMonMIBObjects 2 }
-
-loadMemorySystemWatermark OBJECT-TYPE
- SYNTAX Integer32 (0..100)
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "Threshold in percent of the total available system
- memory, which specifies how much memory can be allocated
- by the system before an alarm is sent."
- ::= { load 1 }
-
-loadMemoryErlProcWatermark OBJECT-TYPE
- SYNTAX Integer32 (0..100)
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "Threshold in percent of the total available system
- memory, which specifies how much memory can be allocated
- by one Erlang process before an alarm is sent."
- ::= { load 2 }
-
-loadTable OBJECT-TYPE
- SYNTAX SEQUENCE OF LoadEntry
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "A table with load and memory information
- for each node."
- ::= { load 3 }
-
-loadEntry OBJECT-TYPE
- SYNTAX LoadEntry
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "A conceptual row in the loadTable."
- INDEX { loadErlNodeName }
- ::= { loadTable 1 }
-
-LoadEntry ::= SEQUENCE {
- loadErlNodeName DisplayString,
- loadSystemTotalMemory Gauge32,
- loadSystemUsedMemory Gauge32,
- loadLargestErlProcess DisplayString,
- loadLargestErlProcessUsedMemory Gauge32,
- loadCpuLoad Integer32,
- loadCpuLoad5 Integer32,
- loadCpuLoad15 Integer32,
- loadOsWordsize Unsigned32,
- loadSystemTotalMemory64 OTPCounterBasedGauge64,
- loadSystemUsedMemory64 OTPCounterBasedGauge64,
- loadLargestErlProcessUsedMemory64 OTPCounterBasedGauge64
- }
-
-loadErlNodeName OBJECT-TYPE
- SYNTAX DisplayString
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "The name of the erlang node, e.g. erlnode@host1."
- ::= { loadEntry 1 }
-
-loadSystemTotalMemory OBJECT-TYPE
- SYNTAX Gauge32
- UNITS "bytes"
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The amount of total memory in the system."
- ::= { loadEntry 2 }
-
-loadSystemUsedMemory OBJECT-TYPE
- SYNTAX Gauge32
- UNITS "bytes"
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The amount of used memory."
- ::= { loadEntry 3 }
-
-loadLargestErlProcess OBJECT-TYPE
- SYNTAX DisplayString
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The process identifier (Pid) of the largest Erlang
- process."
- ::= { loadEntry 4 }
-
-loadLargestErlProcessUsedMemory OBJECT-TYPE
- SYNTAX Gauge32
- UNITS "bytes"
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The amount of memory used by the largest Erlang
- process."
- ::= { loadEntry 5 }
-
-loadCpuLoad OBJECT-TYPE
- SYNTAX Integer32 (0..100)
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The average load the last minute in percent of the CPU
- where the Erlang node runs."
- ::= { loadEntry 6 }
-
-loadCpuLoad5 OBJECT-TYPE
- SYNTAX Integer32 (0..100)
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The average load the last 5 minutes in percent of the CPU
- where the Erlang node runs."
- ::= { loadEntry 7}
-
-loadCpuLoad15 OBJECT-TYPE
- SYNTAX Integer32 (0..100)
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The average load the last 15 minutes in percent of the CPU
- where the Erlang node runs."
- ::= { loadEntry 8}
-
-loadOsWordsize OBJECT-TYPE
- SYNTAX Unsigned32
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The wordsize of the operating operating system."
- ::= { loadEntry 9 }
-
-loadSystemTotalMemory64 OBJECT-TYPE
- SYNTAX OTPCounterBasedGauge64
- UNITS "bytes"
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The amount of total memory in the system for 64-bit operating system."
- ::= { loadEntry 10 }
-
-loadSystemUsedMemory64 OBJECT-TYPE
- SYNTAX OTPCounterBasedGauge64
- UNITS "bytes"
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The amount of used memory for 64-bit operating system."
- ::= { loadEntry 11 }
-
-loadLargestErlProcessUsedMemory64 OBJECT-TYPE
- SYNTAX OTPCounterBasedGauge64
- UNITS "bytes"
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The amount of memory used by the largest Erlang
- process for 64-bit operating system.."
- ::= { loadEntry 12 }
-
-diskAlmostFullThreshold OBJECT-TYPE
- SYNTAX Integer32 (0..100)
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "Threshold in percent of the available disk space,
- which specifies how much disk space can be used by
- a disk or partition before an alarm is sent."
- ::= { disk 1 }
-
-diskTable OBJECT-TYPE
- SYNTAX SEQUENCE OF DiskEntry
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "A table with all local disks or partitions on each
- node."
- ::= { disk 2 }
-
-diskEntry OBJECT-TYPE
- SYNTAX DiskEntry
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "A conceptual row in the diskTable."
- INDEX { erlNodeId, diskId }
- ::= { diskTable 1 }
-
-DiskEntry ::= SEQUENCE {
- diskId Integer32,
- diskDescr DisplayString,
- diskKBytes Gauge32,
- diskCapacity Integer32
- }
-
-diskId OBJECT-TYPE
- SYNTAX Integer32
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "An integer that uniquely identifies the disk
- or partition."
- ::= { diskEntry 1 }
-
-diskDescr OBJECT-TYPE
- SYNTAX DisplayString
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "A string that identifies the disk or partition."
- ::= { diskEntry 2 }
-
-diskKBytes OBJECT-TYPE
- SYNTAX Gauge32
- UNITS "kbytes"
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The amount of total disk/partition space. "
- ::= { diskEntry 3 }
-
-diskCapacity OBJECT-TYPE
- SYNTAX Integer32 (0..100)
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "How much of the disk's/partition's total capacity has
- been used, in percent."
- ::= { diskEntry 4 }
-
-
--- conformance information
-
-otpOsMonMIBCompliances
- OBJECT IDENTIFIER ::= { otpOsMonMIBConformance 1 }
-otpOsMonMIBGroups
- OBJECT IDENTIFIER ::= { otpOsMonMIBConformance 2 }
-
-
--- compliance statements
-
-otpOsMonBasicCompliance MODULE-COMPLIANCE
- STATUS current
- DESCRIPTION
- "The compliance statement for SNMPv2 entities which
- implement the OTP-OS-MON-MIB."
- MODULE -- this module
- GROUP loadGroup
- DESCRIPTION
- "This group is mandatory for systems implementing the
- load supervison functionality."
- GROUP loadAlarmsGroup
- DESCRIPTION
- "This group is optional for systems implementing the
- load supervison functionality."
- GROUP diskGroup
- DESCRIPTION
- "This group is mandatory for system implementing the
- disk supervison functionality."
- GROUP diskAlarmsGroup
- DESCRIPTION
- "This group is optional for systems implementing the
- disk supervison functionality."
- ::= { otpOsMonMIBCompliances 1 }
-
-
--- units of conformance
-
-loadGroup OBJECT-GROUP
- OBJECTS { loadMemorySystemWatermark,
- loadMemoryErlProcWatermark,
- loadSystemTotalMemory,
- loadSystemUsedMemory,
- loadLargestErlProcess,
- loadLargestErlProcessUsedMemory,
- loadCpuLoad,
- loadCpuLoad5,
- loadCpuLoad15,
- loadOsWordsize,
- loadSystemTotalMemory64,
- loadSystemUsedMemory64,
- loadLargestErlProcessUsedMemory64}
- STATUS current
- DESCRIPTION
- "A collection of objects providing basic instrumentation
- of the load of the OTP system."
- ::= { otpOsMonMIBGroups 1 }
-
-diskGroup OBJECT-GROUP
- OBJECTS { diskAlmostFullThreshold,
- diskDescr,
- diskKBytes,
- diskCapacity }
- STATUS current
- DESCRIPTION
- "A collection of objects providing basic instrumentation
- of the disks in the OTP system."
- ::= { otpOsMonMIBGroups 3 }
-
-END
diff --git a/lib/os_mon/mibs/v1/.gitignore b/lib/os_mon/mibs/v1/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/os_mon/mibs/v1/.gitignore
+++ /dev/null
diff --git a/lib/os_mon/src/Makefile b/lib/os_mon/src/Makefile
index fc2eb22393..923a31f290 100644
--- a/lib/os_mon/src/Makefile
+++ b/lib/os_mon/src/Makefile
@@ -34,8 +34,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/os_mon-$(VSN)
# ----------------------------------------------------
# Target Specs
# ----------------------------------------------------
-MODULES= disksup memsup cpu_sup os_mon os_mon_mib os_sup os_mon_sysinfo \
- nteventlog
+MODULES= disksup memsup cpu_sup os_mon os_sup os_mon_sysinfo nteventlog
INCLUDE=../include
CSRC=../c_src
diff --git a/lib/os_mon/src/cpu_sup.erl b/lib/os_mon/src/cpu_sup.erl
index e758b63d19..d28f229b3e 100644
--- a/lib/os_mon/src/cpu_sup.erl
+++ b/lib/os_mon/src/cpu_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -68,7 +68,7 @@
-type util_cpus() :: 'all' | integer() | [integer()].
-type util_state() :: 'user' | 'nice_user' | 'kernel' | 'wait' | 'idle'.
--type util_value() :: [{util_state(), float()}] | float().
+-type util_value() :: [{util_state(), number()}] | number().
-type util_desc() :: {util_cpus(), util_value(), util_value(), []}.
%%----------------------------------------------------------------------
@@ -122,7 +122,7 @@ util(Args) when is_list (Args) ->
util(_) ->
erlang:error(badarg).
--spec util() -> float() | {'error', any()}.
+-spec util() -> number() | {'error', any()}.
util() ->
case util([]) of
@@ -220,17 +220,21 @@ code_change(_OldVsn, State, _Extra) ->
%% internal functions
%%----------------------------------------------------------------------
-get_uint32_measurement(Request, #internal{os_type = {unix, linux}}) ->
- {ok,F} = file:open("/proc/loadavg",[read,raw]),
- {ok,D} = file:read_line(F),
- ok = file:close(F),
- {ok,[Load1,Load5,Load15,_PRun,PTotal],_} = io_lib:fread("~f ~f ~f ~d/~d", D),
- case Request of
- ?avg1 -> sunify(Load1);
- ?avg5 -> sunify(Load5);
- ?avg15 -> sunify(Load15);
- ?ping -> 4711;
- ?nprocs -> PTotal
+get_uint32_measurement(Request, #internal{port = P, os_type = {unix, linux}}) ->
+ case file:open("/proc/loadavg",[read,raw]) of
+ {ok,F} ->
+ {ok,D} = file:read_line(F),
+ ok = file:close(F),
+ {ok,[Load1,Load5,Load15,_PRun,PTotal],_} = io_lib:fread("~f ~f ~f ~d/~d", D),
+ case Request of
+ ?avg1 -> sunify(Load1);
+ ?avg5 -> sunify(Load5);
+ ?avg15 -> sunify(Load15);
+ ?ping -> 4711;
+ ?nprocs -> PTotal
+ end;
+ {error,_} ->
+ port_server_call(P, Request)
end;
get_uint32_measurement(Request, #internal{port = P, os_type = {unix, Sys}}) when
Sys == sunos;
@@ -244,7 +248,7 @@ get_uint32_measurement(Request, #internal{os_type = {unix, Sys}}) when Sys == ir
%% Get the load average using uptime.
%% "8:01pm up 2 days, 22:12, 4 users, load average: 0.70, 0.58, 0.43"
D = os:cmd("uptime") -- "\n",
- Avg = lists:reverse(hd(string:tokens(lists:reverse(D), ":"))),
+ Avg = lists:reverse(hd(string:lexemes(lists:reverse(D), ":"))),
{ok, [L1, L5, L15], _} = io_lib:fread("~f, ~f, ~f", Avg),
case Request of
?avg1 -> sunify(L1);
diff --git a/lib/os_mon/src/disksup.erl b/lib/os_mon/src/disksup.erl
index 044604b000..5118d807e1 100644
--- a/lib/os_mon/src/disksup.erl
+++ b/lib/os_mon/src/disksup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,7 +32,7 @@
terminate/2, code_change/3]).
%% Other exports
--export([format_status/2]).
+-export([format_status/2, parse_df/2]).
-record(state, {threshold, timeout, os, diskdata = [],port}).
@@ -294,8 +294,8 @@ check_disks_solaris("", _Threshold) ->
check_disks_solaris("\n", _Threshold) ->
[];
check_disks_solaris(Str, Threshold) ->
- case io_lib:fread("~s~d~d~d~d%~s", Str) of
- {ok, [_FS, KB, _Used, _Avail, Cap, MntOn], RestStr} ->
+ case parse_df(Str, posix) of
+ {ok, {KB, Cap, MntOn}, RestStr} ->
if
Cap >= Threshold ->
set_alarm({disk_almost_full, MntOn}, []);
@@ -308,14 +308,102 @@ check_disks_solaris(Str, Threshold) ->
check_disks_solaris(skip_to_eol(Str),Threshold)
end.
+%% @private
+%% @doc Predicate to take a word from the input string until a space or
+%% a percent '%' sign (the Capacity field is followed by a %)
+parse_df_is_not_space($ ) -> false;
+parse_df_is_not_space($%) -> false;
+parse_df_is_not_space(_) -> true.
+
+%% @private
+%% @doc Predicate to take spaces away from string. Stops on a non-space
+parse_df_is_space($ ) -> true;
+parse_df_is_space(_) -> false.
+
+%% @private
+%% @doc Predicate to consume remaining characters until end of line.
+parse_df_is_not_eol($\r) -> false;
+parse_df_is_not_eol($\n) -> false;
+parse_df_is_not_eol(_) -> true.
+
+%% @private
+%% @doc Trims leading non-spaces (the word) from the string then trims spaces.
+parse_df_skip_word(Input) ->
+ Remaining = lists:dropwhile(fun parse_df_is_not_space/1, Input),
+ lists:dropwhile(fun parse_df_is_space/1, Remaining).
+
+%% @private
+%% @doc Takes all non-spaces and then drops following spaces.
+parse_df_take_word(Input) ->
+ {Word, Remaining0} = lists:splitwith(fun parse_df_is_not_space/1, Input),
+ Remaining1 = lists:dropwhile(fun parse_df_is_space/1, Remaining0),
+ {Word, Remaining1}.
+
+%% @private
+%% @doc Takes all non-spaces and then drops the % after it and the spaces.
+parse_df_take_word_percent(Input) ->
+ {Word, Remaining0} = lists:splitwith(fun parse_df_is_not_space/1, Input),
+ %% Drop the leading % or do nothing
+ Remaining1 = case Remaining0 of
+ [$% | R1] -> R1;
+ _ -> Remaining0 % Might be no % or empty list even
+ end,
+ Remaining2 = lists:dropwhile(fun parse_df_is_space/1, Remaining1),
+ {Word, Remaining2}.
+
+%% @private
+%% @doc Given a line of 'df' POSIX/SUSv3 output split it into fields:
+%% a string (mounted device), 4 integers (kilobytes, used, available
+%% and capacity), skip % sign, (optionally for susv3 can also skip IUsed, IFree
+%% and ICap% fields) then take remaining characters as the mount path
+-spec parse_df(string(), posix | susv3) ->
+ {error, parse_df} | {ok, {integer(), integer(), list()}, string()}.
+parse_df(Input0, Flavor) ->
+ %% Format of Posix/Linux df output looks like Header + Lines
+ %% Filesystem 1024-blocks Used Available Capacity Mounted on
+ %% udev 2467108 0 2467108 0% /dev
+ Input1 = parse_df_skip_word(Input0), % skip device path field
+ {KbStr, Input2} = parse_df_take_word(Input1), % take Kb field
+ Input3 = parse_df_skip_word(Input2), % skip Used field
+ Input4 = parse_df_skip_word(Input3), % skip Avail field
+
+ % take Capacity% field; drop a % sign following the capacity
+ {CapacityStr, Input5} = parse_df_take_word_percent(Input4),
+
+ %% Format of OS X/SUSv3 df looks similar to POSIX but has 3 extra columns
+ %% Filesystem 1024-blocks Used Available Capacity iused ifree %iused Mounted
+ %% /dev/disk1 243949060 2380 86690680 65% 2029724 37555 0% /
+ Input6 = case Flavor of
+ posix -> Input5;
+ susv3 -> % there are 3 extra integers we want to skip
+ Input5a = parse_df_skip_word(Input5), % skip IUsed field
+ Input5b = parse_df_skip_word(Input5a), % skip IFree field
+ %% skip the value of ICap + '%' field
+ {_, Input5c} = parse_df_take_word_percent(Input5b),
+ Input5c
+ end,
+
+ % path is the remaining string till end of line
+ {MountPath, Input7} = lists:splitwith(fun parse_df_is_not_eol/1, Input6),
+ % Trim the newlines
+ Remaining = lists:dropwhile(fun(X) -> not parse_df_is_not_eol(X) end,
+ Input7),
+ try
+ Kb = erlang:list_to_integer(KbStr),
+ Capacity = erlang:list_to_integer(CapacityStr),
+ {ok, {Kb, Capacity, MountPath}, Remaining}
+ catch error:badarg ->
+ {error, parse_df}
+ end.
+
% Parse per SUSv3 specification, notably recent OS X
check_disks_susv3("", _Threshold) ->
[];
check_disks_susv3("\n", _Threshold) ->
[];
check_disks_susv3(Str, Threshold) ->
- case io_lib:fread("~s~d~d~d~d%~d~d~d%~s", Str) of
- {ok, [_FS, KB, _Used, _Avail, Cap, _IUsed, _IFree, _ICap, MntOn], RestStr} ->
+ case parse_df(Str, susv3) of
+ {ok, {KB, Cap, MntOn}, RestStr} ->
if
Cap >= Threshold ->
set_alarm({disk_almost_full, MntOn}, []);
diff --git a/lib/os_mon/src/memsup.erl b/lib/os_mon/src/memsup.erl
index 0a9a883390..b69d657aa7 100644
--- a/lib/os_mon/src/memsup.erl
+++ b/lib/os_mon/src/memsup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -701,11 +701,12 @@ get_os_wordsize_with_uname() ->
"sparc64" -> 64;
"amd64" -> 64;
"ppc64" -> 64;
+ "ppc64le" -> 64;
"s390x" -> 64;
_ -> 32
end.
-clean_string(String) -> lists:flatten(string:tokens(String,"\r\n\t ")).
+clean_string(String) -> lists:flatten(string:lexemes(String,[[$\r,$\n]|"\n\t "])).
%%--Replying to pending clients-----------------------------------------
diff --git a/lib/os_mon/src/os_mon.app.src b/lib/os_mon/src/os_mon.app.src
index 8be94f65d4..6c9b0d7576 100644
--- a/lib/os_mon/src/os_mon.app.src
+++ b/lib/os_mon/src/os_mon.app.src
@@ -21,7 +21,7 @@
{application, os_mon,
[{description, "CPO CXC 138 46"},
{vsn, "%VSN%"},
- {modules, [os_mon, os_mon_mib, os_sup,
+ {modules, [os_mon, os_sup,
disksup, memsup, cpu_sup, os_mon_sysinfo, nteventlog]},
{registered, [os_mon_sup, os_mon_sysinfo, disksup, memsup, cpu_sup,
os_sup_server]},
@@ -31,6 +31,4 @@
{start_memsup, true},
{start_os_sup, false}]},
{mod, {os_mon, []}},
- {runtime_dependencies, ["stdlib-2.0","snmp-4.25.1","sasl-2.4",
- "otp_mibs-1.0.9","mnesia-4.12","kernel-3.0",
- "erts-6.0"]}]}.
+ {runtime_dependencies, ["stdlib-2.0","sasl-2.4","kernel-3.0","erts-6.0"]}]}.
diff --git a/lib/os_mon/src/os_mon_mib.erl b/lib/os_mon/src/os_mon_mib.erl
deleted file mode 100644
index 9b5d2fbba6..0000000000
--- a/lib/os_mon/src/os_mon_mib.erl
+++ /dev/null
@@ -1,251 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
--module(os_mon_mib).
-%%%-----------------------------------------------------------------
-%%% Description: This module implements the OS-MON-MIB.
-%%% The tables are implemented as shadow tables with the module
-%%% snmp_shadow_table. Here the update functions are implemented.
-%%%-----------------------------------------------------------------
-
--include("../../otp_mibs/include/OTP-MIB.hrl").
-
-%% API
--export([load/1, unload/1]).
-
-%% Deprecated API
--export([init/1, stop/1]).
-
--deprecated([{init,1,eventually},
- {stop,1,eventually}]).
-
-%% SNMP instrumentation
--export([load_table/1, load_table/3, disk_table/1, disk_table/3,
- mem_sys_mark/1, mem_proc_mark/1, disk_threshold/1]).
-
-%% SNMP shadow functions
--export([update_load_table/0, update_disk_table/0]).
-
-%% Exported for internal use via rpc
--export([get_load/1, get_disks/1]).
-
-%% Shadow tables
--record(loadTable, {
- loadErlNodeName,
- loadSystemTotalMemory,
- loadSystemUsedMemory,
- loadLargestErlProcess,
- loadLargestErlProcessUsedMemory,
- loadCpuLoad,
- loadCpuLoad5,
- loadCpuLoad15,
- loadOsWordsize,
- loadSystemTotalMemory64,
- loadSystemUsedMemory64,
- loadLargestErlProcessUsedMemory64}).
-
--record(diskTable,
- {key, diskDescr, diskKBytes, diskCapacity}).
-
-%% Shadow argument macros
--define(loadShadowArgs,
- {loadTable, string, record_info(fields, loadTable), 5000,
- fun os_mon_mib:update_load_table/0}).
-
--define(diskShadowArgs,
- {diskTable, {integer, integer}, record_info(fields, diskTable), 5000,
- fun os_mon_mib:update_disk_table/0}).
-
-%% Misc
--record(diskAlloc, {diskDescr, diskId}).
-
-%%%=========================================================================
-%%% API
-%%%=========================================================================
-
-%%-------------------------------------------------------------------------
-%% load(Agent) -> ok | {error, Reason}
-%% Agent - pid() | atom()
-%% Reason - term()
-%% Description: Loads the OTP-OS-MON-MIB
-%%-------------------------------------------------------------------------
-load(Agent) ->
- MibDir = filename:join(code:priv_dir(os_mon), "mibs"),
- snmpa:load_mibs(Agent, [filename:join(MibDir, "OTP-OS-MON-MIB")]).
-
-%%-------------------------------------------------------------------------
-%% unload(Agent) -> ok | {error, Reason}
-%% Agent - pid() | atom()
-%% Reason - term()
-%% Description: Unloads the OTP-OS-MON-MIB
-%%-------------------------------------------------------------------------
-unload(Agent) ->
- snmpa:unload_mibs(Agent, ["OTP-OS-MON-MIB"]).
-
-%% To be backwards compatible
-init(Agent) ->
- load(Agent).
-stop(Agent) ->
- unload(Agent).
-
-%%%=========================================================================
-%%% SNMP instrumentation
-%%%=========================================================================
-load_table(Op) ->
- snmp_shadow_table:table_func(Op, ?loadShadowArgs).
-load_table(Op, RowIndex, Cols) ->
- snmp_shadow_table:table_func(Op, RowIndex, Cols, ?loadShadowArgs).
-
-disk_table(new) ->
- Tab = diskAlloc,
- Storage = ram_copies,
- case lists:member(Tab, mnesia:system_info(tables)) of
- true ->
- case mnesia:table_info(Tab, storage_type) of
- unknown ->
- {atomic, ok}=mnesia:add_table_copy(Tab, node(), Storage);
- Storage ->
- catch delete_all(Tab)
- end;
- false ->
- Nodes = [node()],
- Props = [{type, set},
- {attributes, record_info(fields, diskAlloc)},
- {local_content, true},
- {Storage, Nodes}],
- {atomic, ok} = mnesia:create_table(Tab, Props)
-
- end,
- Rec = #diskAlloc{diskDescr = next_index, diskId = 1},
- ok = mnesia:dirty_write(Rec),
- snmp_shadow_table:table_func(new, ?diskShadowArgs).
-
-disk_table(Op, RowIndex, Cols) ->
- snmp_shadow_table:table_func(Op, RowIndex, Cols, ?diskShadowArgs).
-
-mem_sys_mark(get) ->
- {value, memsup:get_sysmem_high_watermark()};
-mem_sys_mark(_) ->
- ok.
-
-mem_proc_mark(get) ->
- {value, memsup:get_procmem_high_watermark()};
-mem_proc_mark(_) ->
- ok.
-
-disk_threshold(get) ->
- {value, disksup:get_almost_full_threshold()};
-disk_threshold(_) ->
- ok.
-
-%%%=========================================================================
-%%% SNMP shadow functions
-%%%=========================================================================
-update_load_table() ->
- delete_all(loadTable),
- lists:foreach(
- fun(Node) ->
- case rpc:call(Node, os_mon_mib, get_load, [Node]) of
- Load when is_record(Load,loadTable) ->
- ok = mnesia:dirty_write(Load);
- _Else ->
- ok
- end
- end, [node() | nodes()]).
-
-
-update_disk_table() ->
- delete_all(diskTable),
- node_update_disk_table(
- otp_mib:erl_node_table(get_next, [], [?erlNodeName,?erlNodeOutBytes])).
-
-%%%========================================================================
-%%% Exported for internal use via rpc
-%%%========================================================================
-get_load(Node) ->
- {Total, Allocated, PidString, PidAllocated} = case memsup:get_memory_data() of
- {MemTot, MemAlloc, undefined} -> {MemTot, MemAlloc, "undefined", 0};
- {MemTot, MemAlloc, {Pid, PidMem}} -> {MemTot, MemAlloc, pid_to_str(Pid), PidMem}
- end,
- OsWordsize = case memsup:get_os_wordsize() of
- WS when is_integer(WS) -> WS;
- _ -> 0
- end,
- #loadTable{
- loadErlNodeName = atom_to_list(Node),
- loadSystemTotalMemory = mask_int32(Total),
- loadSystemUsedMemory = mask_int32(Allocated),
- loadLargestErlProcess = PidString,
- loadLargestErlProcessUsedMemory = mask_int32(PidAllocated),
- loadCpuLoad = get_cpu_load(avg1),
- loadCpuLoad5 = get_cpu_load(avg5),
- loadCpuLoad15 = get_cpu_load(avg15),
- loadOsWordsize = OsWordsize,
- loadSystemTotalMemory64 = Total,
- loadSystemUsedMemory64 = Allocated,
- loadLargestErlProcessUsedMemory64 = PidAllocated
- }.
-
-mask_int32(Value) -> Value band ((1 bsl 32) - 1).
-
-get_disks(NodeId) ->
- element(1,
- lists:mapfoldl(
- fun({Descr, KByte, Capacity}, DiskId) ->
- {#diskTable{key = {NodeId, DiskId},
- diskDescr = Descr,
- diskKBytes = KByte,
- diskCapacity = Capacity},
- DiskId + 1}
- end, 1, disksup:get_disk_data())).
-
-
-%%%========================================================================
-%%% Internal functions
-%%%========================================================================
-node_update_disk_table([_, endOfTable]) ->
- ok;
-
-node_update_disk_table([{[?erlNodeName | IndexList], NodeStr}, _]) ->
- Disks = rpc:call(list_to_atom(NodeStr), os_mon_mib, get_disks,
- IndexList),
- lists:foreach(fun(Disk) ->
- mnesia:dirty_write(Disk)
- end, Disks),
- node_update_disk_table(otp_mib:erl_node_table(get_next,
- IndexList,
- [?erlNodeName,
- ?erlNodeOutBytes])).
-
-get_cpu_load(X) when X == avg1; X == avg5; X == avg15 ->
- case erlang:round(apply(cpu_sup, X, [])/2.56) of
- Large when Large > 100 ->
- 100;
- Load ->
- Load
- end.
-
-delete_all(Name) -> delete_all(mnesia:dirty_first(Name), Name).
-delete_all('$end_of_table', _Name) -> done;
-delete_all(Key, Name) ->
- Next = mnesia:dirty_next(Name, Key),
- ok = mnesia:dirty_delete({Name, Key}),
- delete_all(Next, Name).
-
-pid_to_str(Pid) -> lists:flatten(io_lib:format("~w", [Pid])).
diff --git a/lib/os_mon/test/Makefile b/lib/os_mon/test/Makefile
index 6ac67e6bae..03c73b95ec 100644
--- a/lib/os_mon/test/Makefile
+++ b/lib/os_mon/test/Makefile
@@ -30,7 +30,6 @@ MODULES= \
disksup_SUITE \
memsup_SUITE \
cpu_sup_SUITE \
- os_mon_mib_SUITE \
os_sup_SUITE \
os_mon_conf
@@ -87,7 +86,6 @@ release_tests_spec: make_emakefile
$(INSTALL_DIR) "$(RELSYSDIR)"
$(INSTALL_DATA) os_mon.spec os_mon.cover os_mon_smoke.spec \
$(EMAKEFILE) $(SOURCE) "$(RELSYSDIR)"
- $(INSTALL_DATA) os_mon_mib_SUITE.cfg "$(RELSYSDIR)"
## tar chf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
diff --git a/lib/os_mon/test/cpu_sup_SUITE.erl b/lib/os_mon/test/cpu_sup_SUITE.erl
index 7122d23503..ba28f31f26 100644
--- a/lib/os_mon/test/cpu_sup_SUITE.erl
+++ b/lib/os_mon/test/cpu_sup_SUITE.erl
@@ -122,19 +122,19 @@ util_api(Config) when is_list(Config) ->
%% util([])
{all, Busy1, NonBusy1, []} = cpu_sup:util([]),
- 100.00 = Busy1 + NonBusy1,
+ true = tiny_diff(100.00, Busy1 + NonBusy1),
%% util([detailed])
{Cpus2, Busy2, NonBusy2, []} = cpu_sup:util([detailed]),
true = lists:all(fun(X) -> is_integer(X) end, Cpus2),
true = lists:all(BusyP, Busy2),
true = lists:all(NonBusyP, NonBusy2),
- 100.00 = lists:foldl(Sum,0,Busy2)+lists:foldl(Sum,0,NonBusy2),
+ true = tiny_diff(100.00, lists:foldl(Sum,0,Busy2)+lists:foldl(Sum,0,NonBusy2)),
%% util([per_cpu])
[{Cpu3, Busy3, NonBusy3, []}|_] = cpu_sup:util([per_cpu]),
true = is_integer(Cpu3),
- 100.00 = Busy3 + NonBusy3,
+ true = tiny_diff(100.00, Busy3 + NonBusy3),
%% util([detailed, per_cpu])
[{Cpu4, Busy4, NonBusy4, []}|_] =
@@ -142,7 +142,7 @@ util_api(Config) when is_list(Config) ->
true = is_integer(Cpu4),
true = lists:all(BusyP, Busy2),
true = lists:all(NonBusyP, NonBusy2),
- 100.00 = lists:foldl(Sum,0,Busy4)+lists:foldl(Sum,0,NonBusy4),
+ true = tiny_diff(100.00, lists:foldl(Sum,0,Busy4)+lists:foldl(Sum,0,NonBusy4)),
%% bad util/1 calls
{'EXIT',{badarg,_}} = (catch cpu_sup:util(detailed)),
@@ -150,6 +150,9 @@ util_api(Config) when is_list(Config) ->
ok.
+tiny_diff(A, B) ->
+ (abs(A - B) < 1.0e-11).
+
-define(SPIN_TIME, 1000).
%% Test utilization values
diff --git a/lib/os_mon/test/disksup_SUITE.erl b/lib/os_mon/test/disksup_SUITE.erl
index ad61985014..fe27ea9046 100644
--- a/lib/os_mon/test/disksup_SUITE.erl
+++ b/lib/os_mon/test/disksup_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -30,7 +30,7 @@
-export([port/1]).
-export([terminate/1, unavailable/1, restart/1]).
-export([otp_5910/1]).
--export([posix_only/1]).
+-export([posix_only/1, parse_df_output_posix/1, parse_df_output_susv3/1]).
init_per_suite(Config) when is_list(Config) ->
ok = application:start(os_mon),
@@ -59,7 +59,8 @@ suite() ->
all() ->
Bugs = [otp_5910],
- Always = [api, config, alarm, port, posix_only, unavailable] ++ Bugs,
+ Always = [api, config, alarm, port, posix_only, unavailable,
+ parse_df_output_posix, parse_df_output_susv3] ++ Bugs,
case test_server:os_type() of
{unix, _OSname} -> Always;
{win32, _OSname} -> Always;
@@ -413,3 +414,36 @@ get_disk_data([{"none",0,0}=E]) -> [E];
get_disk_data([{_,_,0}|Es]) -> get_disk_data(Es);
get_disk_data([E|Es]) -> [E|get_disk_data(Es)];
get_disk_data([]) -> [].
+
+%% @doc Test various expected inputs to 'df' command output (Linux/POSIX)
+parse_df_output_posix(Config) when is_list(Config) ->
+ PosixHdr = "Filesystem 1K-blocks Used Available Use% Mounted on\n",
+ {error, _} = disksup:parse_df(PosixHdr, posix),
+ {error, _} = disksup:parse_df("", posix),
+ {error, _} = disksup:parse_df("\n\n", posix),
+
+ %% Have a simple example with no funny spaces in mount path
+ Posix1 = "tmpfs 498048 7288 490760 2% /run\n",
+ {ok, {498048, 2, "/run"}, ""} = disksup:parse_df(Posix1, posix),
+
+ %% Have a mount path with some spaces in it
+ Posix2 = "tmpfs 498048 7288 490760 2% /spaces 1 2\n",
+ {ok, {498048, 2, "/spaces 1 2"}, ""} = disksup:parse_df(Posix2, posix).
+
+%% @doc Test various expected inputs to 'df' command output (Darwin/SUSv3)
+parse_df_output_susv3(Config) when is_list(Config) ->
+ DarwinHdr = "Filesystem 1024-blocks Used Available Capacity " ++
+ "iused ifree %iused Mounted on",
+ {error, _} = disksup:parse_df(DarwinHdr, susv3),
+ {error, _} = disksup:parse_df("", susv3),
+ {error, _} = disksup:parse_df("\n\n", susv3),
+
+ %% Have a simple example with no funny spaces in mount path
+ Darwin1 = "/dev/disk1 243949060 157002380 86690680 65% 2029724 " ++
+ "4292937555 0% /\n",
+ {ok, {243949060, 65, "/"}, ""} = disksup:parse_df(Darwin1, susv3),
+
+ %% Have a mount path with some spaces in it
+ Darwin2 = "/dev/disk1 243949060 157002380 86690680 65% 2029724 " ++
+ "4292937555 0% /spaces 1 2\n",
+ {ok, {243949060, 65, "/spaces 1 2"}, ""} = disksup:parse_df(Darwin2, susv3).
diff --git a/lib/os_mon/test/os_mon.spec b/lib/os_mon/test/os_mon.spec
index 4b4286b313..d292b258f3 100644
--- a/lib/os_mon/test/os_mon.spec
+++ b/lib/os_mon/test/os_mon.spec
@@ -1,2 +1 @@
{suites,"../os_mon_test",all}.
-{config,"os_mon_mib_SUITE.cfg"}. \ No newline at end of file
diff --git a/lib/os_mon/test/os_mon_mib_SUITE.cfg b/lib/os_mon/test/os_mon_mib_SUITE.cfg
deleted file mode 100644
index a33c23530b..0000000000
--- a/lib/os_mon/test/os_mon_mib_SUITE.cfg
+++ /dev/null
@@ -1,8 +0,0 @@
-%% -*- erlang -*-
-{snmp, [{start_agent,true},
- {users,[{os_mon_mib_test,[snmpm_user_default,[]]}]},
- {managed_agents,[{os_mon_mib_test,
- [os_mon_mib_test, {127,0,0,1}, 4000, []]}]},
- {agent_sysname,"Test os_mon_mibs"},
- {mgr_port,5001}
- ]}.
diff --git a/lib/os_mon/test/os_mon_mib_SUITE.erl b/lib/os_mon/test/os_mon_mib_SUITE.erl
deleted file mode 100644
index f40d5f442c..0000000000
--- a/lib/os_mon/test/os_mon_mib_SUITE.erl
+++ /dev/null
@@ -1,578 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
--module(os_mon_mib_SUITE).
-
-%%-----------------------------------------------------------------
-%% This suite can no longer be executed standalone, i.e. it must be
-%% executed with common test. The reason is that ct_snmp is used
-%% instead of the snmp application directly. The suite requires a
-%% config file, os_mon_mib_SUITE.cfg, found in the same directory as
-%% the suite.
-%%
-%% Execute with:
-%% > ct_run -suite os_mon_mib_SUITE -config os_mon_mib_SUITE.cfg
-%%-----------------------------------------------------------------
-
--include_lib("common_test/include/ct.hrl").
--include_lib("os_mon/include/OTP-OS-MON-MIB.hrl").
--include_lib("snmp/include/snmp_types.hrl").
-
-% Test server specific exports
--export([all/0, suite/0, groups/0,
- init_per_suite/1, end_per_suite/1]).
-
-
-% Test cases must be exported.
--export([update_load_table/1]).
-
--export([get_mem_sys_mark/1, get_mem_proc_mark/1, get_disk_threshold/1,
- get_load_table/1, get_disk_table/1,
- real_snmp_request/1, load_unload/1]).
-
--export([sys_tot_mem/1, sys_used_mem/1, large_erl_process/1,
- large_erl_process_mem/1, cpu_load/1, cpu_load5/1, cpu_load15/1,
- os_wordsize/1, sys_tot_mem64/1, sys_used_mem64/1,
- large_erl_process_mem64/1, disk_descr/1, disk_kbytes/1,
- disk_capacity/1]).
-
--export([otp_6351/1, otp_7441/1]).
-
--define(TRAP_UDP, 5000).
--define(AGENT_UDP, 4000).
--define(CONF_FILE_VER, [v2]).
--define(SYS_NAME, "Test os_mon_mibs").
--define(MAX_MSG_SIZE, 484).
--define(ENGINE_ID, "mgrEngine").
--define(MGR_PORT, 5001).
-
-%%---------------------------------------------------------------------
-
-suite() ->
- [{ct_hooks,[ts_install_cth]},
- {timetrap,{minutes,6}},
- {require, snmp_mgr_agent, snmp}].
-
-all() ->
- [load_unload, get_mem_sys_mark, get_mem_proc_mark,
- get_disk_threshold, get_load_table,
- {group, get_next_load_table}, get_disk_table,
- {group, get_next_disk_table}, real_snmp_request,
- update_load_table, {group, tickets}].
-
-groups() ->
- [{tickets, [], [otp_6351, otp_7441]},
- {get_next_load_table, [],
- [sys_tot_mem, sys_used_mem, large_erl_process,
- large_erl_process_mem, cpu_load, cpu_load5, cpu_load15,
- os_wordsize, sys_tot_mem64, sys_used_mem64,
- large_erl_process_mem64]},
- {get_next_disk_table, [],
- [disk_descr, disk_kbytes, disk_capacity]}].
-
-
-%%---------------------------------------------------------------------
-%%--------------------------------------------------------------------
-%% Function: init_per_suite(Config) -> Config
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Initiation before the whole suite
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
-%%--------------------------------------------------------------------
-init_per_suite(Config) ->
- application:start(sasl),
- application:start(mnesia),
- application:start(os_mon),
-
- ok = ct_snmp:start(Config,snmp_mgr_agent),
-
- %% Load the mibs that should be tested
- otp_mib:load(snmp_master_agent),
- os_mon_mib:load(snmp_master_agent),
-
- Config.
-%%--------------------------------------------------------------------
-%% Function: end_per_suite(Config) -> _
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after the whole suite
-%%--------------------------------------------------------------------
-end_per_suite(Config) ->
- PrivDir = proplists:get_value(priv_dir, Config),
- ConfDir = filename:join(PrivDir,"conf"),
- DbDir = filename:join(PrivDir,"db"),
- MgrDir = filename:join(PrivDir, "mgr"),
-
- %% Uload mibs
- snmpa:unload_mibs(snmp_master_agent,["OTP-OS-MON-MIB"]),
- otp_mib:unload(snmp_master_agent),
-
- %% Clean up
- application:stop(snmp),
- application:stop(mnesia),
- application:stop(os_mon),
-
- del_dir(ConfDir),
- del_dir(DbDir),
- (catch del_dir(MgrDir)),
- ok.
-
-%%---------------------------------------------------------------------
-%% Test cases
-%%---------------------------------------------------------------------
-
-%% Test to unload and the reload the OTP.mib
-load_unload(Config) when is_list(Config) ->
- os_mon_mib:unload(snmp_master_agent),
- os_mon_mib:load(snmp_master_agent),
- ok.
-%%---------------------------------------------------------------------
-
-%% check os_mon_mib:update_load_table error handling
-update_load_table(Config) when is_list(Config) ->
- Node = start_node(),
- ok = rpc:call(Node,application,start,[sasl]),
- ok = rpc:call(Node,application,start,[os_mon]),
- ok = os_mon_mib:update_load_table(),
- rpc:call(Node,application,stop,[os_mon]),
- ok = os_mon_mib:update_load_table(),
- stop_node(Node),
- ok.
-
-%% like update_load_table, when memsup_system_only==true
-otp_6351(Config) when is_list(Config) ->
- Node = start_node(),
- ok = rpc:call(Node,application,start,[sasl]),
- ok = rpc:call(Node,application,load,[os_mon]),
- ok = rpc:call(Node,application,set_env,
- [os_mon,memsup_system_only,true]),
- ok = rpc:call(Node,application,start,[os_mon]),
- Res = rpc:call(Node,os_mon_mib,get_load,[Node]),
- if
- is_tuple(Res), element(1, Res)==loadTable ->
- ok;
- true ->
- ct:fail(Res)
- end,
- rpc:call(Node,application,stop,[os_mon]),
- stop_node(Node),
- ok.
-
-
-%%---------------------------------------------------------------------
-%% Simulates a get call to test the instrumentation function
-%% for the loadMemorySystemWatermark variable.
-get_mem_sys_mark(Config) when is_list(Config) ->
- case os_mon_mib:mem_sys_mark(get) of
- {value, SysMark} when is_integer(SysMark) ->
- ok;
- _ ->
- ct:fail(sys_mark_value_not_integer)
- end.
-%%---------------------------------------------------------------------
-%% Simulates a get call to test the instrumentation function
-%% for the loadMemoryErlProcWatermark variable.
-get_mem_proc_mark(Config) when is_list(Config) ->
- case os_mon_mib:mem_proc_mark(get) of
- {value, ProcMark} when is_integer(ProcMark) ->
- ok;
- _ ->
- ct:fail(proc_mark_value_not_integer)
- end.
-%%---------------------------------------------------------------------
-%% Simulates a get call to test the instrumentation function
-%% for the diskAlmostFullThreshold variable.
-get_disk_threshold(Config) when is_list(Config) ->
- case os_mon_mib:disk_threshold(get) of
- {value, ProcMark} when is_integer(ProcMark) ->
- ok;
- _ ->
- ct:fail(disk_threshold_value_not_integer)
- end.
-%%---------------------------------------------------------------------
-
-%%% Note that when we have a string key, as in loadTable, the
-%%% instrumentation will deal with the [length(String), String]. We
-%%% have to know about this, when short cutting SNMP and calling
-%%% instrumentation functions directly as done in most test cases in
-%%% this test suite
-
-%% Simulates get calls to test the instrumentation function
-%% for the loadTable
-get_load_table(Config) when is_list(Config) ->
-
- NodeStr = atom_to_list(node()),
- NodeLen = length(NodeStr),
-
- {_, _, {Pid, _}} = memsup:get_memory_data(),
- PidStr = lists:flatten(io_lib:format("~w", [Pid])),
- [{value, NodeStr},{value, PidStr}] =
- os_mon_mib:load_table(get, [NodeLen | NodeStr],
- [?loadErlNodeName, ?loadLargestErlProcess]),
-
- Values = os_mon_mib:load_table(get, [NodeLen | NodeStr] ,
- [?loadSystemTotalMemory,
- ?loadSystemUsedMemory,
- ?loadLargestErlProcessUsedMemory,
- ?loadCpuLoad,
- ?loadCpuLoad5,
- ?loadCpuLoad15,
- ?loadOsWordsize,
- ?loadSystemTotalMemory64,
- ?loadSystemUsedMemory64,
- ?loadLargestErlProcessUsedMemory64]),
-
- IsInt = fun({value, Val}) when is_integer(Val) ->
- true;
- (_) ->
- false
- end,
-
- NewValues = lists:filter(IsInt, Values),
-
- case length(NewValues) of
- 10 ->
- ok;
- _ ->
- ct:fail(value_not_integer)
- end,
-
- [{noValue,noSuchInstance}, {noValue,noSuchInstance},
- {noValue,noSuchInstance}, {noValue,noSuchInstance},
- {noValue,noSuchInstance}, {noValue,noSuchInstance},
- {noValue,noSuchInstance}, {noValue,noSuchInstance},
- {noValue,noSuchInstance}, {noValue,noSuchInstance},
- {noValue,noSuchInstance}, {noValue,noSuchInstance}] =
- os_mon_mib:load_table(get, [3, 102, 111, 111],
- [?loadErlNodeName,
- ?loadSystemTotalMemory,
- ?loadSystemUsedMemory,
- ?loadLargestErlProcess,
- ?loadLargestErlProcessUsedMemory,
- ?loadCpuLoad,
- ?loadCpuLoad5,
- ?loadCpuLoad15,
- ?loadOsWordsize,
- ?loadSystemTotalMemory64,
- ?loadSystemUsedMemory64,
- ?loadLargestErlProcessUsedMemory64]),
-
- ok.
-%%---------------------------------------------------------------------
-
-sys_tot_mem(Config) when is_list(Config) ->
- [{[?loadSystemTotalMemory, Len | NodeStr], Mem}] =
- os_mon_mib:load_table(get_next, [], [?loadSystemTotalMemory]),
- Len = length(NodeStr),
- true = lists:member(list_to_atom(NodeStr), [node() | nodes()]),
-
- case Mem of
- Mem when is_integer(Mem) ->
- ok;
- _ ->
- ct:fail(sys_tot_mem_value_not_integer)
- end.
-
-sys_used_mem(Config) when is_list(Config) ->
- [{[?loadSystemUsedMemory, Len | NodeStr], Mem}] =
- os_mon_mib:load_table(get_next,[], [?loadSystemUsedMemory]),
- Len = length(NodeStr),
- true = lists:member(list_to_atom(NodeStr), [node() | nodes()]),
-
- case Mem of
- Mem when is_integer(Mem) ->
- ok;
- _ ->
- ct:fail(sys_used_mem_value_not_integer)
- end.
-
-large_erl_process(Config) when is_list(Config) ->
- {_, _, {Pid, _}} = memsup:get_memory_data(),
- PidStr = lists:flatten(io_lib:format("~w", [Pid])),
- [{[?loadLargestErlProcess, Len | NodeStr], PidStr}] =
- os_mon_mib:load_table(get_next,[], [?loadLargestErlProcess]),
- Len = length(NodeStr),
- true = lists:member(list_to_atom(NodeStr), [node() | nodes()]),
- ok.
-
-large_erl_process_mem(Config) when is_list(Config) ->
-
- [{[?loadLargestErlProcessUsedMemory, Len | NodeStr], Mem}] =
- os_mon_mib:load_table(get_next,[],
- [?loadLargestErlProcessUsedMemory]),
- Len = length(NodeStr),
- true = lists:member(list_to_atom(NodeStr), [node() | nodes()]),
-
- case Mem of
- Mem when is_integer(Mem) ->
- ok;
- _ ->
- ct:fail(erl_pid_mem_value_not_integer)
- end.
-
-cpu_load(Config) when is_list(Config) ->
- [{[?loadCpuLoad, Len | NodeStr], Load}] =
- os_mon_mib:load_table(get_next,[], [?loadCpuLoad]),
- Len = length(NodeStr),
- true = lists:member(list_to_atom(NodeStr), [node() | nodes()]),
-
- case Load of
- Load when is_integer(Load) ->
- ok;
- _ ->
- ct:fail(cpu_load_value_not_integer)
- end.
-
-cpu_load5(Config) when is_list(Config) ->
- [{[?loadCpuLoad5, Len | NodeStr], Load}] =
- os_mon_mib:load_table(get_next,[], [?loadCpuLoad5]),
- Len = length(NodeStr),
- true = lists:member(list_to_atom(NodeStr), [node() | nodes()]),
-
- case Load of
- Load when is_integer(Load) ->
- ok;
- _ ->
- ct:fail(cpu_load5_value_not_integer)
- end.
-
-cpu_load15(Config) when is_list(Config) ->
- [{[?loadCpuLoad15, Len | NodeStr], Load}] =
- os_mon_mib:load_table(get_next,[], [?loadCpuLoad15]),
- Len = length(NodeStr),
- true = lists:member(list_to_atom(NodeStr), [node() | nodes()]),
-
- case Load of
- Load when is_integer(Load) ->
- ok;
- _ ->
- ct:fail(cpu_load15_value_not_integer)
- end.
-
-os_wordsize(Config) when is_list(Config) ->
- [{[?loadOsWordsize, Len | NodeStr], Wordsize}] =
- os_mon_mib:load_table(get_next,[], [?loadOsWordsize]),
- Len = length(NodeStr),
- true = lists:member(list_to_atom(NodeStr), [node() | nodes()]),
-
- case Wordsize of
- Wordsize when is_integer(Wordsize) ->
- ok;
- _ ->
- ct:fail(os_wordsize_value_not_integer)
- end.
-
-sys_tot_mem64(Config) when is_list(Config) ->
- [{[?loadSystemTotalMemory64, Len | NodeStr], Mem}] =
- os_mon_mib:load_table(get_next, [], [?loadSystemTotalMemory64]),
- Len = length(NodeStr),
- true = lists:member(list_to_atom(NodeStr), [node() | nodes()]),
-
- case Mem of
- Mem when is_integer(Mem) ->
- ok;
- _ ->
- ct:fail(sys_tot_mem_value_not_integer)
- end.
-
-sys_used_mem64(Config) when is_list(Config) ->
- [{[?loadSystemUsedMemory64, Len | NodeStr], Mem}] =
- os_mon_mib:load_table(get_next,[], [?loadSystemUsedMemory64]),
- Len = length(NodeStr),
- true = lists:member(list_to_atom(NodeStr), [node() | nodes()]),
-
- case Mem of
- Mem when is_integer(Mem) ->
- ok;
- _ ->
- ct:fail(sys_used_mem_value_not_integer)
- end.
-
-large_erl_process_mem64(Config) when is_list(Config) ->
-
- [{[?loadLargestErlProcessUsedMemory64, Len | NodeStr], Mem}] =
- os_mon_mib:load_table(get_next,[],
- [?loadLargestErlProcessUsedMemory64]),
- Len = length(NodeStr),
- true = lists:member(list_to_atom(NodeStr), [node() | nodes()]),
-
- case Mem of
- Mem when is_integer(Mem) ->
- ok;
- _ ->
- ct:fail(erl_pid_mem_value_not_integer)
- end.
-%%---------------------------------------------------------------------
-%% Simulates get calls to test the instrumentation function
-%% for the diskTable.
-get_disk_table(Config) when is_list(Config) ->
-
- DiskData = disksup:get_disk_data(),
- DiskDataLen = length(DiskData),
-
- if
- DiskDataLen > 0 ->
- [{value, Value}] =
- os_mon_mib:disk_table(get, [1,1], [?diskDescr]),
-
- case is_list(Value) of
- true ->
- ok;
- false ->
- ct:fail(value_not_a_string)
- end,
-
- Values = os_mon_mib:disk_table(get, [1,1],
- [?diskId,
- ?diskKBytes,
- ?diskCapacity]),
-
- IsInt = fun({value, Val}) when is_integer(Val) ->
- true;
- (_) ->
- false
- end,
-
- NewValues = lists:filter(IsInt, Values),
-
- case length(NewValues) of
- 3 ->
- ok;
- _ ->
- ct:fail(value_not_integer)
- end
- end,
-
- [{noValue,noSuchInstance}, {noValue,noSuchInstance},
- {noValue,noSuchInstance}, {noValue,noSuchInstance}] =
- os_mon_mib:disk_table(get, [1, DiskDataLen + 1], [?diskId,
- ?diskDescr,
- ?diskKBytes,
- ?diskCapacity]),
-
- ok.
-
-%%---------------------------------------------------------------------
-
-disk_descr(Config) when is_list(Config) ->
- [{[?diskDescr, 1,1], Descr}] =
- os_mon_mib:disk_table(get_next, [], [?diskDescr]),
-
- case Descr of
- Descr when is_list(Descr) ->
- ok;
- _ ->
- ct:fail(disk_descr_value_not_a_string)
- end.
-
-disk_kbytes(Config) when is_list(Config) ->
- [{[?diskKBytes, 1,1], Kbytes}] =
- os_mon_mib:disk_table(get_next,[], [?diskKBytes]),
-
- case Kbytes of
- Kbytes when is_integer(Kbytes) ->
- ok;
- _ ->
- ct:fail(disk_kbytes_value_not_integer)
- end.
-
-
-disk_capacity(Config) when is_list(Config) ->
- [{[?diskCapacity, 1,1], Capacity}] =
- os_mon_mib:disk_table(get_next,[], [?diskCapacity]),
-
- case Capacity of
- Capacity when is_integer(Capacity) ->
- ok;
- _ ->
- ct:fail(disk_capacity_value_not_integer)
- end.
-
-%%---------------------------------------------------------------------
-%% Starts an snmp manager and sends a real snmp-request. i.e.
-%% sends a udp message on the correct format.
-real_snmp_request(Config) when is_list(Config) ->
- NodStr = atom_to_list(node()),
- Len = length(NodStr),
- {_, _, {Pid, _}} = memsup:get_memory_data(),
- PidStr = lists:flatten(io_lib:format("~w", [Pid])),
- io:format("FOO: ~p~n", [PidStr]),
- ok = snmp_get([?loadEntry ++
- [?loadLargestErlProcess, Len | NodStr]],
- PidStr),
- ok = snmp_get_next([?loadEntry ++
- [?loadSystemUsedMemory, Len | NodStr]],
- ?loadEntry ++ [?loadSystemUsedMemory + 1, Len
- | NodStr], PidStr),
- ok = snmp_set([?loadEntry ++ [?loadLargestErlProcess, Len | NodStr]],
- s, "<0.101.0>", Config),
- ok.
-
-%% Starts an snmp manager and requests total memory. Was previously
-%% integer32 which was errornous on 64 bit machines.
-otp_7441(Config) when is_list(Config) ->
- NodStr = atom_to_list(node()),
- Len = length(NodStr),
- Oids = [Oid|_] = [?loadEntry ++ [?loadSystemTotalMemory, Len | NodStr]],
- {noError,0,[#varbind{oid = Oid, variabletype = 'Unsigned32'}]} =
- ct_snmp:get_values(os_mon_mib_test, Oids, snmp_mgr_agent),
-
- ok.
-
-%%---------------------------------------------------------------------
-%% Internal functions
-%%---------------------------------------------------------------------
-start_node() ->
- Pa = filename:dirname(code:which(?MODULE)),
- {ok,Node} = test_server:start_node(testnisse, slave, [{args, " -pa " ++ Pa}]),
- Node.
-
-stop_node(Node) ->
- test_server:stop_node(Node).
-
-del_dir(Dir) ->
- io:format("Deleting: ~s~n",[Dir]),
- {ok, Files} = file:list_dir(Dir),
- FullPathFiles = lists:map(fun(File) -> filename:join(Dir, File) end,
- Files),
- lists:foreach(fun file:delete/1, FullPathFiles),
- file:del_dir(Dir).
-
-%%---------------------------------------------------------------------
-snmp_get(Oids = [Oid |_], Result) ->
- {noError,0,[#varbind{oid = Oid,
- variabletype = 'OCTET STRING',
- value = Result}]} =
- ct_snmp:get_values(os_mon_mib_test, Oids, snmp_mgr_agent),
- ok.
-
-snmp_get_next(Oids, NextOid, Result) ->
- {noError,0,[#varbind{oid = NextOid,
- variabletype = 'OCTET STRING',
- value = Result}]} =
- ct_snmp:get_next_values(os_mon_mib_test, Oids, snmp_mgr_agent),
- ok.
-
-snmp_set(Oid, ValuType, Value, Config) ->
- {notWritable, _, _} =
- ct_snmp:set_values(os_mon_mib_test, [{Oid, ValuType, Value}],
- snmp_mgr_agent, Config),
- ok.
diff --git a/lib/os_mon/vsn.mk b/lib/os_mon/vsn.mk
index eb4f13ea9e..845443d329 100644
--- a/lib/os_mon/vsn.mk
+++ b/lib/os_mon/vsn.mk
@@ -1 +1 @@
-OS_MON_VSN = 2.4.4
+OS_MON_VSN = 2.5
diff --git a/lib/otp_mibs/AUTHORS b/lib/otp_mibs/AUTHORS
deleted file mode 100644
index 3f570082f4..0000000000
--- a/lib/otp_mibs/AUTHORS
+++ /dev/null
@@ -1,8 +0,0 @@
-Original Authors and Contributors:
-
-Martin Bj�rklund
-Lars Thorsen
-Claes Wikstr�m
-Kent Boortz
-Bj�rn Gustavsson
-Ingela Anderton - Created otp_mibs app. to eliminate SASL's SNMP dependence.
diff --git a/lib/otp_mibs/Makefile b/lib/otp_mibs/Makefile
deleted file mode 100644
index 64bd683c7a..0000000000
--- a/lib/otp_mibs/Makefile
+++ /dev/null
@@ -1,37 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2003-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Macros
-# ----------------------------------------------------
-
-SUB_DIRECTORIES = src mibs doc/src
-
-include vsn.mk
-VSN = $(OTP_MIBS_VSN)
-
-SPECIAL_TARGETS =
-
-# ----------------------------------------------------
-# Default Subdir Targets
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_subdir.mk
diff --git a/lib/otp_mibs/doc/html/.gitignore b/lib/otp_mibs/doc/html/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/otp_mibs/doc/html/.gitignore
+++ /dev/null
diff --git a/lib/otp_mibs/doc/man3/.gitignore b/lib/otp_mibs/doc/man3/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/otp_mibs/doc/man3/.gitignore
+++ /dev/null
diff --git a/lib/otp_mibs/doc/pdf/.gitignore b/lib/otp_mibs/doc/pdf/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/otp_mibs/doc/pdf/.gitignore
+++ /dev/null
diff --git a/lib/otp_mibs/doc/src/Makefile b/lib/otp_mibs/doc/src/Makefile
deleted file mode 100644
index c65e2a8e3c..0000000000
--- a/lib/otp_mibs/doc/src/Makefile
+++ /dev/null
@@ -1,115 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2003-2017. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../../vsn.mk
-VSN=$(OTP_MIBS_VSN)
-APPLICATION=otp_mibs
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-XML_APPLICATION_FILES = ref_man.xml
-XML_REF3_FILES = otp_mib.xml
-
-XML_PART_FILES = part.xml
-XML_CHAPTER_FILES = \
- introduction.xml \
- mibs.xml \
- notes.xml
-
-BOOK_FILES = book.xml
-
-XML_FILES = \
- $(BOOK_FILES) $(XML_CHAPTER_FILES) \
- $(XML_PART_FILES) $(XML_REF3_FILES) $(XML_APPLICATION_FILES)
-
-GIF_FILES =
-
-# ----------------------------------------------------
-
-HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \
- $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html)
-
-INFO_FILE = ../../info
-
-MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-
-HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
-
-TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-XML_FLAGS +=
-DVIPS_FLAGS +=
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-$(HTMLDIR)/%.gif: %.gif
- $(INSTALL_DATA) $< $@
-
-docs: pdf html man
-
-$(TOP_PDF_FILE): $(XML_FILES)
-
-pdf: $(TOP_PDF_FILE)
-
-html: gifs $(HTML_REF_MAN_FILE)
-
-man: $(MAN3_FILES)
-
-gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
-
-debug opt:
-
-clean clean_docs:
- rm -rf $(HTMLDIR)/*
- rm -f $(MAN3DIR)/*
- rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
- rm -f errs core *~
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_docs_spec: docs
- $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
- $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
- $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
- $(INSTALL_DATA) $(HTMLDIR)/* \
- "$(RELSYSDIR)/doc/html"
- $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
- $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
- $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
-
-release_spec:
diff --git a/lib/otp_mibs/doc/src/book.xml b/lib/otp_mibs/doc/src/book.xml
deleted file mode 100644
index 482da46876..0000000000
--- a/lib/otp_mibs/doc/src/book.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE book SYSTEM "book.dtd">
-
-<book xmlns:xi="http://www.w3.org/2001/XInclude">
- <header titlestyle="normal">
- <copyright>
- <year>2003</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>OTP_Mibs</title>
- <prepared>Ingela Anderton</prepared>
- <docno></docno>
- <date>2003-04-15</date>
- <rev>A</rev>
- </header>
- <insidecover>
- </insidecover>
- <pagetext>OTP_Mibs application</pagetext>
- <preamble>
- <contents level="2"></contents>
- </preamble>
- <parts lift="no">
- <xi:include href="part.xml"/>
- </parts>
- <applications>
- <xi:include href="ref_man.xml"/>
- </applications>
- <releasenotes>
- <xi:include href="notes.xml"/>
- </releasenotes>
- <index></index>
-</book>
-
-
diff --git a/lib/otp_mibs/doc/src/introduction.xml b/lib/otp_mibs/doc/src/introduction.xml
deleted file mode 100644
index 7046cbb8ae..0000000000
--- a/lib/otp_mibs/doc/src/introduction.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2003</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Introduction</title>
- <prepared>Ingela Anderton</prepared>
- <docno></docno>
- <date>2003-05-19</date>
- <rev>A</rev>
- <file>introduction.xml</file>
- </header>
-
- <section>
- <title>Purpose</title>
- <p>The purpose of the OTP_Mibs application is to provide an SNMP
- management information base for Erlang nodes.</p>
- </section>
-
- <section>
- <title>Pre-requisites</title>
- <p>It is assumed that the reader is familiar with the Erlang
- programming language, concepts of OTP and has a basic knowledge
- of SNMP.</p>
- </section>
-</chapter>
-
-
diff --git a/lib/otp_mibs/doc/src/mibs.xml b/lib/otp_mibs/doc/src/mibs.xml
deleted file mode 100644
index a32d5ea5f5..0000000000
--- a/lib/otp_mibs/doc/src/mibs.xml
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2003</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Mibs</title>
- <prepared>Ingela Anderton</prepared>
- <docno></docno>
- <date>2003-05-19</date>
- <rev>A</rev>
- <file>mibs.xml</file>
- </header>
-
- <section>
- <title>Structure</title>
- <p>The OTP mibs are stored in the
- <c>$OTP_ROOT/lib/otp_mibs/mibs/</c> directory. They
- are defined in SNMPv2 SMI syntax. An SNMPv1 version of the mib is
- delivered in the <c>mibs/v1</c> directory. The compiled MIB is
- located under <c>priv/mibs</c>, and the generated <c>.hrl</c>
- file under the <c>include</c> directory. To compile a MIB that
- IMPORTS a MIB in the OTP_Mibs application, give the option
- <c>{il, ["otp_mibs/priv/mibs"]}</c> to the MIB compiler.</p>
- </section>
-
- <section>
- <title>OTP-MIB</title>
- <p>The OTP-MIB mib represents information about Erlang nodes such as
- node name, number of running processes, virtual machine version
- etc. If the MIB should be used in a system, it should be
- loaded into an SNMP agent by using the API function
- <c>otp_mib:load/1</c>.</p>
- </section>
-
- <section>
- <title>OTP-REG</title>
- <p>The OTP-REG mib defines the unique OTP subtree of object
- identifiers under the Ericsson subtree. Under the OTP subtree
- several object identifiers are defined. This module is typically
- included by OTP applications defining their own mibs, or ASN.1
- modules in general, that require unique object identifiers under
- the OTP subtree.</p>
- </section>
-
- <section>
- <title>OTP-TC</title>
- <p>The OTP-TC mib provides the textual convention datatype
- <c>OwnerString</c>.</p>
- </section>
-</chapter>
-
-
diff --git a/lib/otp_mibs/doc/src/notes.xml b/lib/otp_mibs/doc/src/notes.xml
deleted file mode 100644
index c99148a904..0000000000
--- a/lib/otp_mibs/doc/src/notes.xml
+++ /dev/null
@@ -1,296 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2004</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>OTP_Mibs Release Notes</title>
- <prepared>otp_appnotes</prepared>
- <docno>nil</docno>
- <date>nil</date>
- <rev>nil</rev>
- <file>notes.xml</file>
- </header>
- <p>This document describes the changes made to the OTP_Mibs
- application.</p>
-
-<section><title>Otp_Mibs 1.1.2</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> Removed all old unused files in the documentation.
- </p>
- <p>
- Own Id: OTP-14475 Aux Id: ERL-409, PR-1493 </p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Otp_Mibs 1.1.1</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Internal changes</p>
- <p>
- Own Id: OTP-13551</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Otp_Mibs 1.1</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Change license text from Erlang Public License to Apache
- Public License v2</p>
- <p>
- Own Id: OTP-12845</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Otp_Mibs 1.0.10</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Make sure the clean rule for ssh, ssl, eunit and otp_mibs
- actually removes generated files.</p>
- <p>
- Own Id: OTP-12200</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Otp_Mibs 1.0.9</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Add type based integer value truncation/reset.</p>
- <p>
- This fixes errors when querying e.g. the
- erlNodeReductions, erlNodeInBytes and erlNodeOutBytes
- objects in long-running Erlang/OTP systems.</p>
- <p>
- Update types of applicable MIB objects to 64bit based
- types.</p>
- <p>
- Potential incompatibility: Type change of Counter32 to
- Counter64 in OTP-MIB.mib</p>
- <p>
- (Thanks to Tobias Schlager)</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-11203</p>
- </item>
- <item>
- <p>
- Application upgrade (appup) files are corrected for the
- following applications: </p>
- <p>
- <c>asn1, common_test, compiler, crypto, debugger,
- dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
- inets, observer, odbc, os_mon, otp_mibs, parsetools,
- percept, public_key, reltool, runtime_tools, ssh,
- syntax_tools, test_server, tools, typer, webtool, wx,
- xmerl</c></p>
- <p>
- A new test utility for testing appup files is added to
- test_server. This is now used by most applications in
- OTP.</p>
- <p>
- (Thanks to Tobias Schlager)</p>
- <p>
- Own Id: OTP-11744</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Otp_Mibs 1.0.8</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Misc build updates</p>
- <p>
- Own Id: OTP-10784</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Otp_Mibs 1.0.7</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Tuple funs (a two-element tuple with a module name and a
- function) are now officially deprecated and will be
- removed in R16. Use '<c>fun M:F/A</c>' instead. To make
- you aware that your system uses tuple funs, the very
- first time a tuple fun is applied, a warning will be sent
- to the error logger.</p>
- <p>
- Own Id: OTP-9649</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Otp_Mibs 1.0.6</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- The documentation is now built with open source tools
- (xsltproc and fop) that exists on most platforms. One
- visible change is that the frames are removed.</p>
- <p>
- Own Id: OTP-8201</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Otp_Mibs 1.0.5</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>The copyright notices have been updated.</p>
- <p>
- Own Id: OTP-7851</p>
- </item>
- </list>
- </section>
-
-</section>
-
- <section>
- <title>Otp_Mibs 1.0.4.1</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Minor Makefile changes.</p>
- <p>Own Id: OTP-6689</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>OTP_Mibs 1.0.4</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Replaced calls to deprecated functions in <c>snmp</c>
- with calls to the equivalent functions in <c>snmpa</c>.</p>
- <p>Own Id: OTP-6112</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>OTP_Mibs 1.0.3</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>The <c>otp_mib</c> module has been cleaned up to improve the
- maintainability. It should have no effect on the
- functionality of the OTP_Mibs application.</p>
- <p>Own Id: OTP-4982</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>OTP_Mibs 1.0.2</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>Incorrect <c>.app</c> file (missing mandatory
- <c>registered</c>).</p>
- <p>Own Id: OTP-4823 Aux Id: Seq8145, OTP-4801 </p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>OTP_Mibs 1.0.1</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>Missing <c>.app</c> and <c>appup</c> files in <c>ebin</c>.</p>
- <p>Own Id: OTP-4801 Aux Id: Seq8145 </p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>OTP_Mibs 1.0</title>
- <p>The OTP mibs that where included in the SASL application
- have been moved to this new application OTP_Mibs. The OTP
- mibs had no real connection to SASL and it is desirable that
- the core of Erlang/OTP is not dependent on SNMP.</p>
- <p>Own Id: OTP-4686</p>
- </section>
-</chapter>
-
-
diff --git a/lib/otp_mibs/doc/src/otp_mib.xml b/lib/otp_mibs/doc/src/otp_mib.xml
deleted file mode 100644
index 681ce9fa2d..0000000000
--- a/lib/otp_mibs/doc/src/otp_mib.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2003</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>otp_mib</title>
- <prepared>Ingela Anderton</prepared>
- <docno></docno>
- <date></date>
- <rev></rev>
- </header>
- <module>otp_mib</module>
- <modulesummary>Handles the OTP-MIB</modulesummary>
- <description>
- <p>The SNMP application should be used to start an SNMP agent. Then
- the API functions below can be used to load/unload the OTP-MIB
- into/from the agent. The instrumentation of the OTP-MIB uses
- Mnesia, hence Mnesia must be started prior to loading the OTP-MIB.</p>
- </description>
- <funcs>
- <func>
- <name>load(Agent) -> ok | {error, Reason}</name>
- <fsummary>Load the OTP-MIB</fsummary>
- <type>
- <v>Agent = pid() | atom()</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Loads the OTP-MIB.</p>
- </desc>
- </func>
- <func>
- <name>unload(Agent) -> ok | {error, Reason}</name>
- <fsummary>Unload the OTP-MIB</fsummary>
- <type>
- <v>Agent = pid() | atom()</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Unloads the OTP-MIB.</p>
- </desc>
- </func>
- </funcs>
-
- <section>
- <title>See Also</title>
- <p>snmp(3)</p>
- </section>
-</erlref>
-
-
diff --git a/lib/otp_mibs/doc/src/part.xml b/lib/otp_mibs/doc/src/part.xml
deleted file mode 100644
index 0a8ddce268..0000000000
--- a/lib/otp_mibs/doc/src/part.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE part SYSTEM "part.dtd">
-
-<part xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>2003</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>OTP_Mibs User's Guide</title>
- <prepared>Ingela Anderton</prepared>
- <docno></docno>
- <date>2002-09-17</date>
- <rev>A</rev>
- </header>
- <description>
- <p>The <em>OTP_Mibs</em> application provides an SNMP management
- information base for Erlang nodes.</p>
- </description>
- <xi:include href="introduction.xml"/>
- <xi:include href="mibs.xml"/>
-</part>
-
-
diff --git a/lib/otp_mibs/doc/src/ref_man.xml b/lib/otp_mibs/doc/src/ref_man.xml
deleted file mode 100644
index 06c5aadcd9..0000000000
--- a/lib/otp_mibs/doc/src/ref_man.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE application SYSTEM "application.dtd">
-
-<application xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>2003</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>OTP_Mibs Reference Manual</title>
- <prepared>Ingela Anderton</prepared>
- <docno></docno>
- <date>2002-09-13</date>
- <rev>A</rev>
- </header>
- <description>
- <p>The <em>OTP_Mibs</em> application provides an SNMP management
- information base for Erlang nodes.</p>
- </description>
- <xi:include href="otp_mib.xml"/>
-</application>
-
-
diff --git a/lib/otp_mibs/ebin/.gitignore b/lib/otp_mibs/ebin/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/otp_mibs/ebin/.gitignore
+++ /dev/null
diff --git a/lib/otp_mibs/include/.gitignore b/lib/otp_mibs/include/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/otp_mibs/include/.gitignore
+++ /dev/null
diff --git a/lib/otp_mibs/info b/lib/otp_mibs/info
deleted file mode 100644
index aedd1c883b..0000000000
--- a/lib/otp_mibs/info
+++ /dev/null
@@ -1,2 +0,0 @@
-group: oam Operation & Maintenance Applications
-short: SNMP management information base for Erlang/OTP nodes.
diff --git a/lib/otp_mibs/mibs/Makefile b/lib/otp_mibs/mibs/Makefile
deleted file mode 100644
index 11d790d014..0000000000
--- a/lib/otp_mibs/mibs/Makefile
+++ /dev/null
@@ -1,89 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# Release directory specification
-# ----------------------------------------------------
-include ../vsn.mk
-ifdef SASL_VSN
-VSN=$(SASL_VSN)
-RELSYSDIR = $(RELEASE_PATH)/lib/sasl-$(VSN)
-else
-VSN=$(OTP_MIBS_VSN)
-RELSYSDIR = $(RELEASE_PATH)/lib/otp_mibs-$(VSN)
-endif
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-
-MIB_FILES= OTP-REG.mib OTP-TC.mib OTP-MIB.mib
-FUNCS_FILES = OTP-MIB.funcs
-
-BIN_TARGETS= $(MIB_FILES:%.mib=$(SNMP_BIN_TARGET_DIR)/%.bin)
-HRL_TARGETS= $(MIB_FILES:%.mib=$(SNMP_HRL_TARGET_DIR)/%.hrl)
-V1_MIB_FILES= $(MIB_FILES:%.mib=v1/%.mib.v1)
-
-TARGET_FILES= $(BIN_TARGETS) $(HRL_TARGETS) $(V1_MIB_FILES)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-SNMP_FLAGS = -I ../priv/mibs
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug opt: $(TARGET_FILES)
-
-clean:
- rm -f $(TARGET_FILES)
- rm -f core
-
-docs:
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-v1/%.mib.v1: %.mib
- $(gen_verbose)$(ERL_TOP)/lib/snmp/bin/snmp-v2tov1 -o $@ $<
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/mibs"
- $(INSTALL_DIR) "$(RELSYSDIR)/mibs/v1"
- $(INSTALL_DATA) $(MIB_FILES) $(FUNCS_FILES) "$(RELSYSDIR)/mibs"
- $(INSTALL_DATA) $(V1_MIB_FILES) "$(RELSYSDIR)/mibs/v1"
- $(INSTALL_DIR) "$(RELSYSDIR)/include"
- $(INSTALL_DATA) $(HRL_TARGETS) "$(RELSYSDIR)/include"
- $(INSTALL_DIR) "$(RELSYSDIR)/priv/mibs"
- $(INSTALL_DATA) $(BIN_TARGETS) "$(RELSYSDIR)/priv/mibs"
-
-release_docs_spec:
diff --git a/lib/otp_mibs/mibs/OTP-EVA-MIB.mib b/lib/otp_mibs/mibs/OTP-EVA-MIB.mib
deleted file mode 100644
index 4d0c53ed95..0000000000
--- a/lib/otp_mibs/mibs/OTP-EVA-MIB.mib
+++ /dev/null
@@ -1,569 +0,0 @@
---
--- %CopyrightBegin%
---
--- Copyright Ericsson AB 2004-2016. All Rights Reserved.
---
--- Licensed under the Apache License, Version 2.0 (the "License");
--- you may not use this file except in compliance with the License.
--- You may obtain a copy of the License at
---
--- http://www.apache.org/licenses/LICENSE-2.0
---
--- Unless required by applicable law or agreed to in writing, software
--- distributed under the License is distributed on an "AS IS" BASIS,
--- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--- See the License for the specific language governing permissions and
--- limitations under the License.
---
--- %CopyrightEnd%
---
-
-OTP-EVA-MIB DEFINITIONS ::= BEGIN
-
-IMPORTS
- MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE,
- Counter32, Gauge32, Integer32
- FROM SNMPv2-SMI
- TEXTUAL-CONVENTION, DisplayString, DateAndTime
- FROM SNMPv2-TC
- MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP
- FROM SNMPv2-CONF
- otpModules, otpApplications
- FROM OTP-REG
- OwnerString
- FROM OTP-TC
- ;
-
-otpEvaModule MODULE-IDENTITY
- LAST-UPDATED "200305090900Z"
- ORGANIZATION "Ericsson"
- CONTACT-INFO
- "Contact: Erlang Support see license agreement for Erlang/OTP."
- DESCRIPTION
- "This MIB is part of the OTP MIB. It defines MIB objects
- for the eva application in OTP."
-
- REVISION "200305090900Z"
- DESCRIPTION
- "Changed CONTACT-INFO as it was outdated, made it more generic
- to avoid such changes in the future."
-
- REVISION "199801270900Z"
- DESCRIPTION
- "Changed erroneous defintion of alarmCleared notification.
- Changed erroneous name of this module to otpEvaModule."
- REVISION "199712010900Z"
- DESCRIPTION
- "Converted to v2 SMI and placed in the OTP tree."
- REVISION "199705020900Z"
- DESCRIPTION
- "The initial version of this MIB module. It is very much
- inspired by the ANS-ALM-MIB and Axd301Eva-OMS mibs."
- ::= { otpModules 6 }
-
-otpEvaMIB OBJECT IDENTIFIER ::= { otpApplications 4 }
-otpEvaMIBConformance
- OBJECT IDENTIFIER ::= { otpEvaMIB 1 }
-otpEvaMIBObjects
- OBJECT IDENTIFIER ::= { otpEvaMIB 2 }
-otpEvaMIBEvents OBJECT IDENTIFIER ::= { otpEvaMIB 3 }
-otpEvaMIBEventsV2
- OBJECT IDENTIFIER ::= { otpEvaMIBEvents 0 }
-
-
--- Datatypes
-
-AlarmSeverity ::= TEXTUAL-CONVENTION
- STATUS current
- DESCRIPTION
- "The AlarmSeverity defines six severity levels,
- which provide an indication of how it is perceived that the
- capability of the managed object has been affected. Those
- severity levels which represent service affecting conditions
- ordered from most severe to least severe are critical,
- major, minor and warning. The levels used are as defined
- in X.733, ITU Alarm Reporting Function:
-
- o The Indeterminate severity level indicates that the
- severity level cannot be determined.
-
- o The Critical severity level indicates that a service
- affecting condition has occurred and an immediate
- corrective action is required. Such a severity can be
- reported, for example, when a managed object becomes
- totally out of service and its capability must be restored.
-
- o The Major severity level indicates that a service
- affecting condition has developed and an urgent corrective
- action is required. Such a severity can be reported, for
- example, when there is a severe degradation in the
- capability of the managed object and its full capability
- must be restored.
-
- o The Minor severity level indicates the existence of a
- non-service affecting fault condition and that corrective
- action should be taken in order to prevent a more serious
- (for example, service affecting) fault. Such a severity
- can be reported, for example, when the detected alarm
- condition is not currently degrading the capacity of the
- managed object.
-
- o The Warning severity level indicates the detection of a
- potential or impending service affecting fault, before any
- significant effects have been felt. Action should be taken
- to further diagnose (if necessary) and correct the problem
- in order to prevent it from becoming a more serious service
- affecting fault.
-
- When an alarm is cleared, an alarmCleared event is generated.
- This event clears the alarm with the currentAlarmFaultId
- contained in the event. It is not required that the clearing
- of previously reported alarms are reported. Therefore, a managing
- system cannot assume that the absence of an alarmedCleared event
- for a fault means that the condition that caused the generation
- of previous alarms is still present. Managed object definers
- shall state if, and under which conditions, the alarmedCleared
- event is used.
-
- The clear value of AlarmSeverity is an action which is used when
- a management station wants to clear an active alarm. This is not
- possible on all systems, and thus an agent does not have support
- write access for this value."
- REFERENCE
- "X.733, ITU Alarm Reporting Function"
- SYNTAX INTEGER {
- indeterminate (0),
- critical (1),
- major (2),
- minor (3),
- warning (4),
- clear (5) -- Written, not read
- }
-
-AlarmClass ::= TEXTUAL-CONVENTION
- STATUS current
- DESCRIPTION
- "The AlarmClass type categorizes the alarm, and is
- defined when the alarm is registered. It is as defined in
- X.733, ITU Alarm Reporting Function:
-
- o communications. An alarm of this class is principally
- associated with the procedures or processes required
- to convey information from one point to another.
-
- o qos. An alarm of this class is principally associated
- with a degradation in the quality of service.
-
- o processing. An alarm of this class is principally
- associated with a software or processing fault.
-
- o equipment. An alarm of this class is principally
- associated with an equipment fault.
-
- o environmental. An alarm of this class is principally
- associated with a condition relating to an enclosure in
- with equipment resides."
- REFERENCE
- "X.733, ITU Alarm Reporting Function"
- SYNTAX INTEGER {
- unknown (0),
- communications (1),
- qos (2),
- processing (3),
- equipment (4),
- environmental (5)
- }
-
-
--- Managed Objects
-
-event OBJECT IDENTIFIER ::= { otpEvaMIBObjects 1 }
-alarm OBJECT IDENTIFIER ::= { otpEvaMIBObjects 2 }
-currentAlarm OBJECT IDENTIFIER ::= { otpEvaMIBObjects 3 }
-
--- The Event group
---
--- The Event group controls the generation of notifications of
--- events from the system.
-
-eventTable OBJECT-TYPE
- SYNTAX SEQUENCE OF EventEntry
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "A list of events defined by the system. This table is used
- to control the sending of traps and to whom the traps are
- sent."
- ::= { event 1 }
-
-eventEntry OBJECT-TYPE
- SYNTAX EventEntry
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "A set of parameters that describe an event to be
- generated when certain conditions are met."
- INDEX { eventIndex }
- ::= { eventTable 1 }
-
-EventEntry ::= SEQUENCE {
- eventIndex Integer32 (1..2147483647),
- eventTrapName DisplayString,
- eventTreatment INTEGER,
- eventCommunity OCTET STRING (SIZE (0..127)),
- eventSentTraps Counter32,
- eventOwner OwnerString
- }
-
-eventIndex OBJECT-TYPE
- SYNTAX Integer32 (1..2147483647)
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "An index that uniquely identifies an entry in the
- event table. Each such entry defines one event that
- is to be generated when the appropriate conditions
- occur. The value for each eventIndex must remain
- constant, at least from one re-initialization of the
- entity's network management system to the next
- re-initialization."
- ::= { eventEntry 1 }
-
-eventTrapName OBJECT-TYPE
- SYNTAX DisplayString
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The identifier of the corresponding trap.
- NOTE: this should be an OID in SNMPv2, but must be
- a string in v1."
- ::= { eventEntry 2 }
-
-eventTreatment OBJECT-TYPE
- SYNTAX INTEGER {
- none(1),
- log(2),
- snmpTrap(3),
- logAndTrap(4)
- }
- MAX-ACCESS read-write
- STATUS current
- DESCRIPTION
- "Defines how the system shall treat this event. In the
- case of snmpTrap, an SNMP trap is sent to one or more
- management stations. In the case of log, the event is
- guaranteed to be logged in a log according to some log
- strategy. Each such log strategy may define a MIB module
- for control and examination of logs."
- ::= { eventEntry 3 }
-
-eventCommunity OBJECT-TYPE
- SYNTAX OCTET STRING (SIZE (0..127))
- MAX-ACCESS read-write
- STATUS current
- DESCRIPTION
- "If an SNMP trap is to be sent, it will be sent to
- the SNMP community specified by this octet string."
- ::= { eventEntry 4 }
-
-eventSentTraps OBJECT-TYPE
- SYNTAX Counter32
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The number of times this event has been sent as a trap."
- ::= { eventEntry 5 }
-
-eventOwner OBJECT-TYPE
- SYNTAX OwnerString
- MAX-ACCESS read-write
- STATUS current
- DESCRIPTION
- "The manager entity that 'owns' this event entry, and is
- therefore responsible for its contents."
- ::= { eventEntry 6 }
-
-eventTime OBJECT-TYPE
- SYNTAX DateAndTime
- MAX-ACCESS accessible-for-notify
- STATUS current
- DESCRIPTION
- "This object may be included in a trap definition for an event.
- It specifies the time the event was generated."
- ::= { event 2 }
-
-
--- The Alarm group
---
--- The Alarm group extends the Event group with objects for alarms.
-
-alarmTable OBJECT-TYPE
- SYNTAX SEQUENCE OF AlarmEntry
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "Contains additional information for alarm events."
- ::= { alarm 1 }
-
-alarmEntry OBJECT-TYPE
- SYNTAX AlarmEntry
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "A set of parameters for alarms."
- INDEX { eventIndex }
- ::= { alarmTable 1 }
-
-AlarmEntry ::= SEQUENCE {
- alarmClass AlarmClass,
- alarmSeverity AlarmSeverity
- }
-
-alarmClass OBJECT-TYPE
- SYNTAX AlarmClass
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The class of this alarm."
- ::= { alarmEntry 1 }
-
-alarmSeverity OBJECT-TYPE
- SYNTAX AlarmSeverity
- MAX-ACCESS read-write
- STATUS current
- DESCRIPTION
- "The perceived severity that shall apply to the
- associated alarms."
- ::= { alarmEntry 2 }
-
-
--- The CurrentAlarm group
---
--- The CurrentAlarm group is a collection of objects for monitoring of
--- active alarms in the system.
-
-numberOfCurrentAlarms OBJECT-TYPE
- SYNTAX Gauge32
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "Number of currently active alarms in the system."
- ::= { currentAlarm 1 }
-
-currentAlarmLastTimeChanged OBJECT-TYPE
- SYNTAX DateAndTime
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The time an entry in the currentAlarmTable was changed.
- It may be used by a management station as a value to
- poll. If the value is changed, the management station
- knows that the currentAlarmTable has been updated."
- ::= { currentAlarm 2 }
-
-currentAlarmTable OBJECT-TYPE
- SYNTAX SEQUENCE OF CurrentAlarmEntry
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "A list of currently active alarms in the system."
- ::= { currentAlarm 3 }
-
-currentAlarmEntry OBJECT-TYPE
- SYNTAX CurrentAlarmEntry
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "A set of parameters that describe a currently active
- alarm."
- INDEX { currentAlarmFaultId }
- ::= { currentAlarmTable 1 }
-
-CurrentAlarmEntry ::= SEQUENCE {
- currentAlarmFaultId Integer32 (1..2147483647),
- currentAlarmEventIndex Integer32 (1..2147483647),
- currentAlarmObject OBJECT IDENTIFIER,
- currentAlarmCause OBJECT IDENTIFIER,
- currentAlarmSeverity AlarmSeverity,
- currentAlarmTime DateAndTime,
- currentAlarmInformation DisplayString,
- currentAlarmExtra1 OBJECT IDENTIFIER,
- currentAlarmExtra2 OBJECT IDENTIFIER
- }
-
-currentAlarmFaultId OBJECT-TYPE
- SYNTAX Integer32 (1..2147483647)
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "An id that uniquely identifies a fault. Each fault is
- represented as one an entry in the currentAlarmTable."
- ::= { currentAlarmEntry 1 }
-
-currentAlarmEventIndex OBJECT-TYPE
- SYNTAX Integer32 (1..2147483647)
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "A pointer into the eventTable. Points to the event
- corresponding to this alarm."
- ::= { currentAlarmEntry 2 }
-
-currentAlarmObject OBJECT-TYPE
- SYNTAX OBJECT IDENTIFIER
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The alarming object."
- ::= { currentAlarmEntry 3 }
-
-currentAlarmCause OBJECT-TYPE
- SYNTAX OBJECT IDENTIFIER
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The probable cause of the alarm."
- ::= { currentAlarmEntry 4 }
-
-currentAlarmSeverity OBJECT-TYPE
- SYNTAX AlarmSeverity
- MAX-ACCESS read-write
- STATUS current
- DESCRIPTION
- "The perceived severity of the fault. A manager can set
- this value to clear only. When set to clear, the alarm
- is removed from this table, and a 'clearAlarm' event is
- generated."
- ::= { currentAlarmEntry 5 }
-
-currentAlarmTime OBJECT-TYPE
- SYNTAX DateAndTime
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The time the fault was detected."
- ::= { currentAlarmEntry 6 }
-
-currentAlarmInformation OBJECT-TYPE
- SYNTAX DisplayString
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "Additional information pin-pointing the problem."
- ::= { currentAlarmEntry 7 }
-
-currentAlarmExtra1 OBJECT-TYPE
- SYNTAX OBJECT IDENTIFIER
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "An extra parameter used for some alarms at their own
- discretion. Can be used for example to identify
- additional objects in the alarm, or instead of
- currentAlarmInformation to pin-point the problem, if the
- additional information is defined in some MIB."
- ::= { currentAlarmEntry 8 }
-
-currentAlarmExtra2 OBJECT-TYPE
- SYNTAX OBJECT IDENTIFIER
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "An extra parameter used for some alarms at their own
- discretion. Can be used for example to identify
- additional objects in the alarm, or instead of
- currentAlarmInformation to pin-point the problem, if the
- additional information is defined in some MIB."
- ::= { currentAlarmEntry 9 }
-
-
--- Events
-
-alarmCleared NOTIFICATION-TYPE
- OBJECTS {
- currentAlarmEventIndex,
- eventTime
- }
- STATUS current
- DESCRIPTION
- "This event is sent when an alarm has been cleared,
- either by the application or by an operator. Note that the
- currentAlarmFaultId is implicitly sent as the instance identifier
- for currentAlarmEventIndex."
- ::= { otpEvaMIBEventsV2 1 }
-
-
--- conformance information
-
-otpEvaMIBCompliances
- OBJECT IDENTIFIER ::= { otpEvaMIBConformance 1 }
-otpEvaMIBGroups
- OBJECT IDENTIFIER ::= { otpEvaMIBConformance 2 }
-
-
--- compliance statements
-
-otpEvaBasicCompliance MODULE-COMPLIANCE
- STATUS current
- DESCRIPTION
- "The compliance statement for SNMPv2 entities which
- implement the OTP-EVA-MIB."
- MODULE -- this module
- MANDATORY-GROUPS { eventGroup,
- alarmGroup,
- currentAlarmGroup,
- evaEventsGroup }
-
- ::= { otpEvaMIBCompliances 1 }
-
-
--- units of conformance
-
-eventGroup OBJECT-GROUP
- OBJECTS { eventTrapName,
- eventTreatment,
- eventCommunity,
- eventSentTraps,
- eventOwner,
- eventTime }
- STATUS current
- DESCRIPTION
- "A collection of objects providing basic instrumentation
- and control of the events defined in the OTP system."
- ::= { otpEvaMIBGroups 1 }
-
-alarmGroup OBJECT-GROUP
- OBJECTS { alarmClass,
- alarmSeverity }
- STATUS current
- DESCRIPTION
- "A collection of objects providing basic instrumentation
- and control of the alarms defined the OTP system."
- ::= { otpEvaMIBGroups 2 }
-
-currentAlarmGroup OBJECT-GROUP
- OBJECTS { numberOfCurrentAlarms,
- currentAlarmLastTimeChanged,
- currentAlarmEventIndex,
- currentAlarmObject,
- currentAlarmCause,
- currentAlarmSeverity,
- currentAlarmTime,
- currentAlarmInformation,
- currentAlarmExtra1,
- currentAlarmExtra2 }
- STATUS current
- DESCRIPTION
- "A collection of objects providing basic instrumentation
- of the activa alarm list in the OTP system."
- ::= { otpEvaMIBGroups 3 }
-
-evaEventsGroup NOTIFICATION-GROUP
- NOTIFICATIONS { alarmCleared }
- STATUS current
- DESCRIPTION
- "The notification which is generated from EVA."
- ::= { otpEvaMIBGroups 4 }
-
-
-END
diff --git a/lib/otp_mibs/mibs/OTP-MIB.funcs b/lib/otp_mibs/mibs/OTP-MIB.funcs
deleted file mode 100644
index 9f9d69c3d1..0000000000
--- a/lib/otp_mibs/mibs/OTP-MIB.funcs
+++ /dev/null
@@ -1,2 +0,0 @@
-{erlNodeTable, {otp_mib, erl_node_table, []}}.
-{applTable, {otp_mib, appl_table, []}}.
diff --git a/lib/otp_mibs/mibs/OTP-MIB.mib b/lib/otp_mibs/mibs/OTP-MIB.mib
deleted file mode 100644
index 693319eae4..0000000000
--- a/lib/otp_mibs/mibs/OTP-MIB.mib
+++ /dev/null
@@ -1,318 +0,0 @@
---
--- %CopyrightBegin%
---
--- Copyright Ericsson AB 1996-2016. All Rights Reserved.
---
--- Licensed under the Apache License, Version 2.0 (the "License");
--- you may not use this file except in compliance with the License.
--- You may obtain a copy of the License at
---
--- http://www.apache.org/licenses/LICENSE-2.0
---
--- Unless required by applicable law or agreed to in writing, software
--- distributed under the License is distributed on an "AS IS" BASIS,
--- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--- See the License for the specific language governing permissions and
--- limitations under the License.
---
--- %CopyrightEnd%
---
-
-OTP-MIB DEFINITIONS ::= BEGIN
-
-IMPORTS
- MODULE-IDENTITY, OBJECT-TYPE,
- Counter64, Gauge32, Integer32
- FROM SNMPv2-SMI
- TEXTUAL-CONVENTION, DisplayString
- FROM SNMPv2-TC
- MODULE-COMPLIANCE, OBJECT-GROUP
- FROM SNMPv2-CONF
- otpModules, otpApplications
- FROM OTP-REG
- ;
-
-otpModule MODULE-IDENTITY
- LAST-UPDATED "201307160700Z"
- ORGANIZATION "Ericsson"
- CONTACT-INFO
- "Contact: Erlang Support see license agreement for Erlang/OTP."
- DESCRIPTION
- "This is a MIB for a distributed OTP system, with one SNMP
- agent executing at one node only. Each Erlang node in the
- OTP system is represented by one row in the erlNodeTable."
-
- REVISION "201307160700Z"
- DESCRIPTION
- "Updated various types to be able to reflect larger values.
- The objects erlNodeReductions, erlNodeInBytes, erlNodeOutBytes as well
- as the type MilliSeconds have been updated to Counter64."
-
- REVISION "200305090900Z"
- DESCRIPTION
- "Changed CONTACT-INFO as it was outdated, made it more generic
- to avoid such changes in the future."
-
- REVISION "199712010900Z"
- DESCRIPTION
- "Converted to v2 SMI and placed in the OTP tree."
-
- REVISION "199608191700Z"
- DESCRIPTION
- "The initial revision of MIB module OTP-MIB."
-
- ::= { otpModules 3 }
-
-otpMIB OBJECT IDENTIFIER ::= { otpApplications 1 }
-otpMIBConformance
- OBJECT IDENTIFIER ::= { otpMIB 1 }
-otpMIBObjects OBJECT IDENTIFIER ::= { otpMIB 2 }
-
--- Datatypes
-
-MilliSeconds ::= TEXTUAL-CONVENTION
- STATUS current
- DESCRIPTION
- "The MilliSeconds type represents a Counter which represents
- the time, in milliseconds between two epochs. When objects
- are defined which use this type, the description of the object
- identifies both of the reference epochs."
- SYNTAX Counter64
-
-
--- Managed Objects
-
-erlang OBJECT IDENTIFIER ::= { otpMIBObjects 1 }
-appls OBJECT IDENTIFIER ::= { otpMIBObjects 2 }
-
-erlNodeTable OBJECT-TYPE
- SYNTAX SEQUENCE OF ErlNodeEntry
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "A table with info on each erlang node in the system."
- ::= { erlang 1 }
-
-erlNodeEntry OBJECT-TYPE
- SYNTAX ErlNodeEntry
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "A conceptual row in the erlNodeTable."
- INDEX { erlNodeId }
- ::= { erlNodeTable 1 }
-
-ErlNodeEntry ::= SEQUENCE {
- erlNodeId Integer32,
- erlNodeName DisplayString,
- erlNodeMachine DisplayString,
- erlNodeVersion DisplayString,
- erlNodeRunQueue Gauge32,
- erlNodeRunTime MilliSeconds,
- erlNodeWallClock MilliSeconds,
- erlNodeReductions Counter64,
- erlNodeProcesses Gauge32,
- erlNodeInBytes Counter64,
- erlNodeOutBytes Counter64
-}
-
-erlNodeId OBJECT-TYPE
- SYNTAX Integer32
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "An integer that uniquely identifies the erlang node."
- ::= { erlNodeEntry 1 }
-
-erlNodeName OBJECT-TYPE
- SYNTAX DisplayString
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The symbolic name of the erlang node."
- ::= { erlNodeEntry 2 }
-
-erlNodeMachine OBJECT-TYPE
- SYNTAX DisplayString
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The virtual machine executing the erlang node"
- ::= { erlNodeEntry 3 }
-
-erlNodeVersion OBJECT-TYPE
- SYNTAX DisplayString
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The version number of the virtual machine"
- ::= { erlNodeEntry 4 }
-
-erlNodeRunQueue OBJECT-TYPE
- SYNTAX Gauge32
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "Number of processes scheduled to run"
- ::= { erlNodeEntry 5 }
-
-erlNodeRunTime OBJECT-TYPE
- SYNTAX MilliSeconds
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "Total cpu time in milliseconds since the
- system started"
- ::= { erlNodeEntry 6 }
-
-erlNodeWallClock OBJECT-TYPE
- SYNTAX MilliSeconds
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "Total real time in milliseconds since the
- system started"
- ::= { erlNodeEntry 7 }
-
-erlNodeReductions OBJECT-TYPE
- SYNTAX Counter64
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "Number of function calls since the system started"
- ::= { erlNodeEntry 8 }
-
-erlNodeProcesses OBJECT-TYPE
- SYNTAX Gauge32
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "Number of running processes in the system."
- ::= { erlNodeEntry 9 }
-
-erlNodeInBytes OBJECT-TYPE
- SYNTAX Counter64
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The total number of bytes delivered to the system"
- ::= { erlNodeEntry 10 }
-
-erlNodeOutBytes OBJECT-TYPE
- SYNTAX Counter64
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The total number of bytes delivered from the system"
- ::= { erlNodeEntry 11 }
-
-
-applTable OBJECT-TYPE
- SYNTAX SEQUENCE OF ApplEntry
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "A table with all currently running applications
- for each node."
- ::= { appls 1 }
-
-applEntry OBJECT-TYPE
- SYNTAX ApplEntry
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "A conceptual row in the applTable."
- INDEX { erlNodeId, applId }
- ::= { applTable 1 }
-
-ApplEntry ::= SEQUENCE {
- applId Integer32,
- applName DisplayString,
- applDescr DisplayString,
- applVsn DisplayString
-}
-
-applId OBJECT-TYPE
- SYNTAX Integer32
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "An integer that uniquely identifies the application."
- ::= { applEntry 1 }
-
-applName OBJECT-TYPE
- SYNTAX DisplayString
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The name of the application."
- ::= { applEntry 2 }
-
-applDescr OBJECT-TYPE
- SYNTAX DisplayString
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "A short description of the application."
- ::= { applEntry 3 }
-
-applVsn OBJECT-TYPE
- SYNTAX DisplayString
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The version of the application."
- ::= { applEntry 4 }
-
-
--- conformance information
-
-otpMIBCompliances
- OBJECT IDENTIFIER ::= { otpMIBConformance 1 }
-otpMIBGroups OBJECT IDENTIFIER ::= { otpMIBConformance 2 }
-
-
--- compliance statements
-
-otpBasicCompliance MODULE-COMPLIANCE
- STATUS current
- DESCRIPTION
- "The compliance statement for SNMPv2 entities which
- implement the OTP-MIB."
- MODULE -- this module
- MANDATORY-GROUPS { erlGroup, applGroup }
-
- ::= { otpMIBCompliances 1 }
-
-
--- units of conformance
-
-erlGroup OBJECT-GROUP
- OBJECTS { erlNodeName,
- erlNodeMachine,
- erlNodeVersion,
- erlNodeRunQueue,
- erlNodeRunTime,
- erlNodeWallClock,
- erlNodeReductions,
- erlNodeProcesses,
- erlNodeInBytes,
- erlNodeOutBytes }
- STATUS current
- DESCRIPTION
- "A collection of objects providing basic instrumentation
- of the Erlang runtime system."
- ::= { otpMIBGroups 1 }
-
-applGroup OBJECT-GROUP
- OBJECTS { applName,
- applDescr,
- applVsn }
- STATUS current
- DESCRIPTION
- "A collection of objects providing basic instrumentation
- of the applications in the OTP system."
- ::= { otpMIBGroups 2 }
-
-
-END
diff --git a/lib/otp_mibs/mibs/v1/.gitignore b/lib/otp_mibs/mibs/v1/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/otp_mibs/mibs/v1/.gitignore
+++ /dev/null
diff --git a/lib/otp_mibs/priv/bin/.gitignore b/lib/otp_mibs/priv/bin/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/otp_mibs/priv/bin/.gitignore
+++ /dev/null
diff --git a/lib/otp_mibs/priv/mibs/.gitignore b/lib/otp_mibs/priv/mibs/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/otp_mibs/priv/mibs/.gitignore
+++ /dev/null
diff --git a/lib/otp_mibs/priv/obj/.gitignore b/lib/otp_mibs/priv/obj/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/otp_mibs/priv/obj/.gitignore
+++ /dev/null
diff --git a/lib/otp_mibs/src/Makefile b/lib/otp_mibs/src/Makefile
deleted file mode 100644
index 5c7af39c3f..0000000000
--- a/lib/otp_mibs/src/Makefile
+++ /dev/null
@@ -1,106 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2003-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-include $(ERL_TOP)/make/target.mk
-
-ifeq ($(TYPE),debug)
-ERL_COMPILE_FLAGS += -Ddebug -W
-endif
-
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(OTP_MIBS_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/otp_mibs-$(VSN)
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-MODULES = \
- otp_mib
-
-INCLUDE=../include
-
-HRL_FILES =
-
-INTERNAL_HRL_FILES =
-
-ERL_FILES = $(MODULES:%=%.erl)
-
-APP_FILE = otp_mibs.app
-APP_SRC = $(APP_FILE).src
-APP_TARGET = $(EBIN)/$(APP_FILE)
-
-APPUP_FILE = otp_mibs.appup
-APPUP_SRC = $(APPUP_FILE).src
-APPUP_TARGET = $(EBIN)/$(APPUP_FILE)
-
-TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-
-TARGETS = $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_COMPILE_FLAGS += -I$(INCLUDE)
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug opt: $(TARGETS)
-
-clean:
- rm -f $(TARGET_FILES)
- rm -f $(APP_TARGET)
- rm -f $(APPUP_TARGET)
- rm -f core
-
-docs:
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-$(APP_TARGET): $(APP_SRC) ../vsn.mk
- $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
-
-$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/src"
- $(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)/src"
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGETS) "$(RELSYSDIR)/ebin"
-
-release_docs_spec:
-
-
diff --git a/lib/otp_mibs/src/otp_mib.erl b/lib/otp_mibs/src/otp_mib.erl
deleted file mode 100644
index 1431818be4..0000000000
--- a/lib/otp_mibs/src/otp_mib.erl
+++ /dev/null
@@ -1,216 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
--module(otp_mib).
-%%%-----------------------------------------------------------------
-%%% Description: This module implements the OTP-MIB.
-%%% The tables are implemented as shadow tables with the module
-%%% snmp_shadow_table.
-%%%-----------------------------------------------------------------
-
-%% API
--export([load/1, unload/1]).
-
-%% SNMP instrumentation
--export([erl_node_table/1, erl_node_table/3, appl_table/1, appl_table/3]).
-
-%% SNMP shadow functions
--export([update_erl_node_table/0, update_appl_table/0]).
-
-%% Exported for internal use via rpc
--export([get_erl_node/1, get_appls/1]).
-
-%% Shadow tables
--record(erlNodeTable,
- {erlNodeId, erlNodeName, erlNodeMachine, erlNodeVersion,
- erlNodeRunQueue,
- erlNodeRunTime, erlNodeWallClock, erlNodeReductions,
- erlNodeProcesses, erlNodeInBytes, erlNodeOutBytes}).
-
--record(applTable, {key = '_', applName = '_', applDescr = '_',
- applVsn = '_'}).
-
-%% Shadow argument macros
--define(erlNodeShadowArgs,
- {erlNodeTable, integer, record_info(fields, erlNodeTable), 5000,
- fun otp_mib:update_erl_node_table/0}).
-
--define(applShadowArgs,
- {applTable, {integer, integer}, record_info(fields, applTable),
- 5000, fun otp_mib:update_appl_table/0}).
-
-%% Misc
--record(erlNodeAlloc, {nodeName, nodeId}).
-
-%%%=========================================================================
-%%% API
-%%%=========================================================================
-
-%%-------------------------------------------------------------------------
-%% load(Agent) -> ok | {error, Reason}
-%% Agent - pid() | atom()
-%% Reason - term()
-%% Description: Loads the OTP-MIB
-%%-------------------------------------------------------------------------
-load(Agent) ->
- MibDir = code:priv_dir(otp_mibs) ++ "/mibs",
- snmpa:load_mibs(Agent, [MibDir ++ "/OTP-MIB"]).
-
-%%-------------------------------------------------------------------------
-%% unload(Agent) -> ok | {error, Reason}
-%% Agent - pid() | atom()
-%% Reason - term()
-%% Description: Loads the OTP-MIB
-%%-------------------------------------------------------------------------
-unload(Agent) ->
- snmpa:unload_mibs(Agent, ["OTP-MIB"]).
-
-
-%%%=========================================================================
-%%% SNMP instrumentation
-%%%=========================================================================
-erl_node_table(new) ->
- Tab = erlNodeAlloc,
- Storage = ram_copies,
- case lists:member(Tab, mnesia:system_info(tables)) of
- true ->
- case mnesia:table_info(Tab, storage_type) of
- unknown ->
- {atomic, ok} = mnesia:add_table_copy(Tab, node(), Storage);
- Storage ->
- catch delete_all(Tab)
- end;
- false ->
- Nodes = [node()],
- Props = [{type, set},
- {attributes, record_info(fields, erlNodeAlloc)},
- {local_content, true},
- {Storage, Nodes}],
- {atomic, ok} = mnesia:create_table(Tab, Props)
- end,
- ok = mnesia:dirty_write({erlNodeAlloc, next_index, 1}),
- update_node_alloc([node() | nodes()]),
- snmp_shadow_table:table_func(new, ?erlNodeShadowArgs).
-
-erl_node_table(Op, RowIndex, Cols) ->
- snmp_shadow_table:table_func(Op, RowIndex, Cols, ?erlNodeShadowArgs).
-
-
-appl_table(Op) ->
- snmp_shadow_table:table_func(Op, ?applShadowArgs).
-appl_table(Op, RowIndex, Cols) ->
- snmp_shadow_table:table_func(Op, RowIndex, Cols, ?applShadowArgs).
-
-
-%%%=========================================================================
-%%% SNMP shadow functions
-%%%=========================================================================
-update_erl_node_table() ->
- delete_all(erlNodeTable),
- Nodes = [node() | nodes()],
- update_node_alloc(Nodes),
- lists:foreach(
- fun(Node) ->
- [{_,_,Idx}] = mnesia:dirty_read({erlNodeAlloc, Node}),
- ErlNode = rpc:call(Node, otp_mib, get_erl_node, [Idx]),
- ok = mnesia:dirty_write(ErlNode)
- end, Nodes).
-
-update_appl_table() ->
- delete_all(applTable),
- Nodes = [node() | nodes()],
- update_node_alloc(Nodes),
- lists:foreach(
- fun(Node) ->
- [{_,_,Idx}] = mnesia:dirty_read({erlNodeAlloc, Node}),
- Appls = rpc:call(Node, otp_mib, get_appls, [Idx]),
- lists:foreach(fun(Appl) ->
- ok = mnesia:dirty_write(Appl)
- end, Appls)
- end, Nodes).
-
-%%%========================================================================
-%%% Exported for internal use via rpc
-%%%========================================================================
-get_erl_node(Id) ->
- RunQueue = erlang:statistics(run_queue),
- RunTime = element(1, erlang:statistics(runtime)),
- WallClock = element(1, erlang:statistics(wall_clock)),
- Reductions = element(1, erlang:statistics(reductions)),
- Processes = length(processes()),
- IO = erlang:statistics(io),
- InBytes = element(2, element(1, IO)),
- OutBytes = element(2, element(2, IO)),
- #erlNodeTable{erlNodeId = truncate_int('Integer32', Id),
- erlNodeName = atom_to_list(node()),
- erlNodeVersion = erlang:system_info(version),
- erlNodeMachine = erlang:system_info(machine),
- erlNodeRunQueue = truncate_int('Unsigned32', RunQueue),
- erlNodeRunTime = truncate_int('Counter64', RunTime),
- erlNodeWallClock = truncate_int('Counter64', WallClock),
- erlNodeReductions = truncate_int('Counter64', Reductions),
- erlNodeProcesses = truncate_int('Unsigned32', Processes),
- erlNodeInBytes = truncate_int('Counter64', InBytes),
- erlNodeOutBytes = truncate_int('Counter64', OutBytes)}.
-
-get_appls(NodeId) ->
- element(1,
- lists:mapfoldl(
- fun({ApplName, ApplDescr, ApplVsn}, ApplId) ->
- {#applTable{key = {NodeId, ApplId},
- applName = atom_to_list(ApplName),
- applDescr = ApplDescr,
- applVsn = ApplVsn},
- ApplId + 1}
- end, 1, application:which_applications())).
-
-%%%========================================================================
-%%% Internal functions
-%%%========================================================================
-update_node_alloc([Node | T]) ->
- case mnesia:dirty_read({erlNodeAlloc, Node}) of
- [] ->
- [{_, _, Idx}] = mnesia:dirty_read({erlNodeAlloc, next_index}),
- ok = mnesia:dirty_write(#erlNodeAlloc{nodeName = Node,
- nodeId = Idx}),
- ok = mnesia:dirty_write({erlNodeAlloc, next_index, Idx + 1});
- _ ->
- ok
- end,
- update_node_alloc(T);
-update_node_alloc([]) -> ok.
-
-delete_all(Name) -> delete_all(mnesia:dirty_first(Name), Name).
-delete_all('$end_of_table', _Name) -> done;
-delete_all(Key, Name) ->
- Next = mnesia:dirty_next(Name, Key),
- ok = mnesia:dirty_delete({Name, Key}),
- delete_all(Next, Name).
-
-%% This will return a value limited to fit into the specified type.
-%% While counter types will be resetted, other integer types will
-%% only be restricted to the valid range.
-truncate_int('Counter64', Value) when Value < 0 -> 0;
-truncate_int('Counter64', Value) -> Value rem 18446744073709551615;
-truncate_int('Unsigned32', Value) when Value < 0 -> 0;
-truncate_int('Unsigned32', Value) when Value > 4294967295 -> 4294967295;
-truncate_int('Unsigned32', Value) -> Value;
-truncate_int('Integer32', Value) when Value < -2147483648 -> -2147483648;
-truncate_int('Integer32', Value) when Value > 2147483647 -> 2147483647;
-truncate_int('Integer32', Value) -> Value.
diff --git a/lib/otp_mibs/src/otp_mibs.app.src b/lib/otp_mibs/src/otp_mibs.app.src
deleted file mode 100644
index 75ef25c366..0000000000
--- a/lib/otp_mibs/src/otp_mibs.app.src
+++ /dev/null
@@ -1,30 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-{application, otp_mibs,
- [{description, "SNMP managment information base for Erlang/OTP nodes."},
- {vsn, "%VSN%"},
- {modules, [otp_mib]},
- {registered, []},
- {applications, [kernel, stdlib, snmp]},
- {env,[]},
- {runtime_dependencies, ["stdlib-2.0","snmp-4.25.1","mnesia-4.12",
- "kernel-3.0","erts-6.0"]}]}.
-
diff --git a/lib/otp_mibs/src/otp_mibs.appup.src b/lib/otp_mibs/src/otp_mibs.appup.src
deleted file mode 100644
index 9437ae2222..0000000000
--- a/lib/otp_mibs/src/otp_mibs.appup.src
+++ /dev/null
@@ -1,22 +0,0 @@
-%% -*- erlang -*-
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-{"%VSN%",
- [{<<".*">>,[{restart_application, otp_mibs}]}],
- [{<<".*">>,[{restart_application, otp_mibs}]}]
-}.
diff --git a/lib/otp_mibs/test/Makefile b/lib/otp_mibs/test/Makefile
deleted file mode 100644
index 9736cf8bce..0000000000
--- a/lib/otp_mibs/test/Makefile
+++ /dev/null
@@ -1,85 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-include $(ERL_TOP)/make/target.mk
-
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-
-MODULES= otp_mibs_SUITE
-
-EBIN = .
-
-HRL_FILES=
-
-ERL_FILES= $(MODULES:%=%.erl)
-
-TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-
-SOURCE = $(ERL_FILES) $(HRL_FILES)
-
-EMAKEFILE=Emakefile
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/otp_mibs_test
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_MAKE_FLAGS +=
-ERL_COMPILE_FLAGS += \
- -I$(ERL_TOP)/lib/snmp/include
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-make_emakefile:
- $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES)\
- > $(EMAKEFILE)
-
-tests debug opt: make_emakefile
- erl $(ERL_MAKE_FLAGS) -make
-
-clean:
- rm -f $(EMAKEFILE)
- rm -f $(TARGET_FILES)
- rm -f core *~
-
-docs:
-
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec:
-
-release_tests_spec: make_emakefile
- $(INSTALL_DIR) "$(RELSYSDIR)"
- $(INSTALL_DATA) $(EMAKEFILE) $(SOURCE) "$(RELSYSDIR)"
- $(INSTALL_DATA) otp_mibs_SUITE.cfg "$(RELSYSDIR)"
-
-release_docs_spec:
diff --git a/lib/otp_mibs/test/otp_mibs_SUITE.cfg b/lib/otp_mibs/test/otp_mibs_SUITE.cfg
deleted file mode 100644
index d01cf92104..0000000000
--- a/lib/otp_mibs/test/otp_mibs_SUITE.cfg
+++ /dev/null
@@ -1,15 +0,0 @@
-%% -*- erlang -*-
-{snmp,
- [
- {start_agent,true},
- {users,
- [
- {otp_mibs_test,[snmpm_user_default,[]]}
- ]},
- {managed_agents,
- [
- {otp_mibs_test, [otp_mibs_test, {127,0,0,1}, 4000, []]}
- ]},
- {agent_sysname,"Test otp_mibs"},
- {mgr_port,5001}
- ]}.
diff --git a/lib/otp_mibs/test/otp_mibs_SUITE.erl b/lib/otp_mibs/test/otp_mibs_SUITE.erl
deleted file mode 100644
index cb3cd28200..0000000000
--- a/lib/otp_mibs/test/otp_mibs_SUITE.erl
+++ /dev/null
@@ -1,255 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
--module(otp_mibs_SUITE).
-
-%%-----------------------------------------------------------------
-%% This suite can no longer be executed standalone, i.e. it must be
-%% executed with common test. The reason is that ct_snmp is used
-%% instead of the snmp application directly. The suite requires a
-%% config file, otp_mibs_SUITE.cfg, found in the same directory as
-%% the suite.
-%%
-%% Execute with:
-%% > ct_run -suite otp_mibs_SUITE -config otp_mibs_SUITE.cfg
-%%-----------------------------------------------------------------
-
--include_lib("common_test/include/ct.hrl").
--include_lib("otp_mibs/include/OTP-MIB.hrl").
--include_lib("snmp/include/snmp_types.hrl").
-
-% Test server specific exports
--export([all/0,
- suite/0,
- groups/0,
- init_per_group/2,
- end_per_group/2,
- init_per_suite/1,
- end_per_suite/1,
- init_per_testcase/2,
- end_per_testcase/2]).
-
-% Test cases must be exported.
--export([app/1, appup/1, nt_basic_types/1, nt_high_reduction_count/1]).
-
--define(TRAP_UDP, 5000).
--define(AGENT_UDP, 4000).
--define(CONF_FILE_VER, [v2]).
--define(SYS_NAME, "Test otp_mibs").
--define(MAX_MSG_SIZE, 484).
--define(ENGINE_ID, "mgrEngine").
--define(MGR_PORT, 5001).
-
-%% Since some cases are only interested in single entries of the OTP-MIB's
-%% node table, one row must be chosen. The first row should be sufficient
-%% for this.
--define(NODE_ENTRY, 1).
-
-%%---------------------------------------------------------------------
-%% CT setup
-%%---------------------------------------------------------------------
-
-init_per_testcase(_Case, Config) when is_list(Config) ->
- Dog = test_server:timetrap(test_server:minutes(6)),
- [{watchdog, Dog}|Config].
-
-end_per_testcase(_Case, Config) when is_list(Config) ->
- Dog = ?config(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- Config.
-
-suite() -> [{ct_hooks,[ts_install_cth]}, {require, snmp_mgr_agent, snmp}].
-
-all() -> [{group, app}, {group, node_table}].
-
-groups() -> [{app, [], [app, appup]},
- {node_table, [], [nt_basic_types, nt_high_reduction_count]}].
-
-init_per_group(_GroupName, Config) -> Config.
-
-end_per_group(_GroupName, Config) -> Config.
-
-init_per_suite(Config) ->
- ?line application:start(sasl),
- ?line application:start(mnesia),
- ?line application:start(otp_mibs),
-
- ok = ct_snmp:start(Config,snmp_mgr_agent),
-
- %% Load the mibs that should be tested
- otp_mib:load(snmp_master_agent),
-
- Config.
-
-end_per_suite(Config) ->
- PrivDir = ?config(priv_dir, Config),
- ConfDir = filename:join(PrivDir,"conf"),
- DbDir = filename:join(PrivDir,"db"),
- MgrDir = filename:join(PrivDir, "mgr"),
-
- %% Uload mibs
- otp_mib:unload(snmp_master_agent),
-
- %% Clean up
- application:stop(snmp),
- application:stop(mnesia),
- application:stop(otp_mibs),
-
- del_dir(ConfDir),
- del_dir(DbDir),
- (catch del_dir(MgrDir)),
- ok.
-
-%%---------------------------------------------------------------------
-%% Test cases
-%%---------------------------------------------------------------------
-
-%% Test that the otp_mibs app file is ok
-app(Config) when is_list(Config) ->
- ok = ?t:app_test(otp_mibs).
-
-%% Test that the otp_mibs appup file is ok
-appup(Config) when is_list(Config) ->
- ok = ?t:appup_test(otp_mibs).
-
-nt_basic_types(suite) ->
- [];
-nt_basic_types(doc) ->
- ["Query every item of the node table and check its variable "
- "type and content for sensible values."];
-nt_basic_types(Config) when is_list(Config) ->
- ok = otp_mib:update_erl_node_table(),
-
- NodeNameId = ?erlNodeEntry ++ [?erlNodeName, ?NODE_ENTRY],
- {noError, 0, [NodeNameVal]} = snmp_get([NodeNameId]),
- #varbind{variabletype = 'OCTET STRING'} = NodeNameVal,
- true = is_list(NodeNameVal#varbind.value),
-
- NodeMachineId = ?erlNodeEntry ++ [?erlNodeMachine, ?NODE_ENTRY],
- {noError, 0, [NodeMachineVal]} = snmp_get([NodeMachineId]),
- #varbind{variabletype = 'OCTET STRING'} = NodeMachineVal,
- true = is_list(NodeMachineVal#varbind.value),
-
- NodeVersionId = ?erlNodeEntry ++ [?erlNodeVersion, ?NODE_ENTRY],
- {noError, 0, [NodeVersionVal]} = snmp_get([NodeVersionId]),
- #varbind{variabletype = 'OCTET STRING'} = NodeVersionVal,
- true = is_list(NodeVersionVal#varbind.value),
-
- NodeRunQueueId = ?erlNodeEntry ++ [?erlNodeRunQueue, ?NODE_ENTRY],
- {noError, 0, [NodeRunQueueVal]} = snmp_get([NodeRunQueueId]),
- #varbind{variabletype = 'Unsigned32'} = NodeRunQueueVal,
- true = is_integer(NodeRunQueueVal#varbind.value),
- NodeRunQueueVal#varbind.value >= 0,
- NodeRunQueueVal#varbind.value =< 4294967295,
-
- NodeRunTimeId = ?erlNodeEntry ++ [?erlNodeRunTime, ?NODE_ENTRY],
- {noError, 0, [NodeRunTimeVal]} = snmp_get([NodeRunTimeId]),
- #varbind{variabletype = 'Counter64'} = NodeRunTimeVal,
- true = is_integer(NodeRunTimeVal#varbind.value),
- NodeRunTimeVal#varbind.value >= 0,
- NodeRunTimeVal#varbind.value =< 18446744073709551615,
-
- NodeWallClockId = ?erlNodeEntry ++ [?erlNodeWallClock, ?NODE_ENTRY],
- {noError, 0, [NodeWallClockVal]} = snmp_get([NodeWallClockId]),
- #varbind{variabletype = 'Counter64'} = NodeWallClockVal,
- true = is_integer(NodeWallClockVal#varbind.value),
- NodeWallClockVal#varbind.value >= 0,
- NodeWallClockVal#varbind.value =< 18446744073709551615,
-
- NodeReductionsId = ?erlNodeEntry ++ [?erlNodeReductions, ?NODE_ENTRY],
- {noError, 0, [NodeReductionsVal]} = snmp_get([NodeReductionsId]),
- #varbind{variabletype = 'Counter64'} = NodeReductionsVal,
- true = is_integer(NodeReductionsVal#varbind.value),
- NodeReductionsVal#varbind.value >= 0,
- NodeReductionsVal#varbind.value =< 18446744073709551615,
-
- NodeProcessesId = ?erlNodeEntry ++ [?erlNodeProcesses, ?NODE_ENTRY],
- {noError, 0, [NodeProcessesVal]} = snmp_get([NodeProcessesId]),
- #varbind{variabletype = 'Unsigned32'} = NodeProcessesVal,
- true = is_integer(NodeProcessesVal#varbind.value),
- NodeProcessesVal#varbind.value >= 0,
- NodeProcessesVal#varbind.value =< 4294967295,
-
- NodeInBytesId = ?erlNodeEntry ++ [?erlNodeInBytes, ?NODE_ENTRY],
- {noError, 0, [NodeInBytesVal]} = snmp_get([NodeInBytesId]),
- #varbind{variabletype = 'Counter64'} = NodeInBytesVal,
- true = is_integer(NodeInBytesVal#varbind.value),
- NodeInBytesVal#varbind.value >= 0,
- NodeInBytesVal#varbind.value =< 18446744073709551615,
-
- NodeOutBytesId = ?erlNodeEntry ++ [?erlNodeOutBytes, ?NODE_ENTRY],
- {noError, 0, [NodeOutBytesVal]} = snmp_get([NodeOutBytesId]),
- #varbind{variabletype = 'Counter64'} = NodeOutBytesVal,
- true = is_integer(NodeOutBytesVal#varbind.value),
- NodeOutBytesVal#varbind.value >= 0,
- NodeOutBytesVal#varbind.value =< 18446744073709551615,
-
- ok.
-
-nt_high_reduction_count(suite) ->
- [];
-nt_high_reduction_count(doc) ->
- ["Check that no error occurs when the erlNodeReductions field"
- "exceeds the 32bit boundary, this may take about 10min."];
-nt_high_reduction_count(Config) when is_list(Config) ->
- NodeReductions = ?erlNodeEntry ++ [?erlNodeReductions, ?NODE_ENTRY],
-
- BumpFun = fun(F, Limit) ->
- case erlang:statistics(reductions) of
- {Total, _} when Total < Limit ->
- F(F, Limit);
- _ ->
- ok
- end
- end,
-
- ok = otp_mib:update_erl_node_table(),
-
- {noError, 0, [StartVal]} = snmp_get([NodeReductions]),
- #varbind{variabletype = 'Counter64'} = StartVal,
- true = is_integer(StartVal#varbind.value),
- StartVal#varbind.value >= 0,
- case StartVal#varbind.value =< 4294967295 of
- true ->
- ok = otp_mib:update_erl_node_table(),
- BumpFun(BumpFun, 4294967295),
- {noError, 0, [EndVal]} = snmp_get([NodeReductions]),
- #varbind{variabletype = 'Counter64'} = EndVal,
- true = is_integer(EndVal#varbind.value),
- EndVal#varbind.value >= 4294967295,
- EndVal#varbind.value =< 18446744073709551615;
- false ->
- %% no need to bump more reductions, since the initial get
- %% command already returned successfully with a large value
- ok
- end.
-
-%%---------------------------------------------------------------------
-%% Internal functions
-%%---------------------------------------------------------------------
-
-snmp_get(OIdList) ->
- ct_snmp:get_values(otp_mibs_test, OIdList, snmp_mgr_agent).
-
-del_dir(Dir) ->
- io:format("Deleting: ~s~n",[Dir]),
- {ok, Files} = file:list_dir(Dir),
- FullPathFiles = lists:map(fun(File) -> filename:join(Dir, File) end, Files),
- lists:foreach(fun file:delete/1, FullPathFiles),
- file:del_dir(Dir).
diff --git a/lib/otp_mibs/vsn.mk b/lib/otp_mibs/vsn.mk
deleted file mode 100644
index 13406cb5b1..0000000000
--- a/lib/otp_mibs/vsn.mk
+++ /dev/null
@@ -1,5 +0,0 @@
-OTP_MIBS_VSN = 1.1.2
-
-# Note: The branch 'otp_mibs' is defunct as of otp_mibs-1.0.4 and
-# should NOT be used again.
-
diff --git a/lib/parsetools/doc/src/Makefile b/lib/parsetools/doc/src/Makefile
index e4cd2c0a76..2e8b232902 100644
--- a/lib/parsetools/doc/src/Makefile
+++ b/lib/parsetools/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2017. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -89,6 +89,7 @@ html: gifs $(HTML_REF_MAN_FILE)
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/lib/parsetools/doc/src/leex.xml b/lib/parsetools/doc/src/leex.xml
index 1227625287..3b82f60201 100644
--- a/lib/parsetools/doc/src/leex.xml
+++ b/lib/parsetools/doc/src/leex.xml
@@ -21,7 +21,7 @@
<rev>A</rev>
<file>leex.xml</file>
</header>
- <module>leex</module>
+ <module since="">leex</module>
<modulesummary>Lexical analyzer generator for Erlang</modulesummary>
<description>
<p>A regular expression based lexical analyzer generator for
@@ -38,7 +38,8 @@ Token = tuple()</code>
</section>
<funcs>
<func>
- <name>file(FileName, [, Options]) -> LeexRet</name>
+ <name since="">file(FileName) -> LeexRet</name>
+ <name since="OTP R16B02">file(FileName, Options) -> LeexRet</name>
<fsummary>Generate a lexical analyzer</fsummary>
<type>
<v>FileName = filename()</v>
@@ -124,7 +125,7 @@ Token = tuple()</code>
</desc>
</func>
<func>
- <name>format_error(ErrorInfo) -> Chars</name>
+ <name since="">format_error(ErrorInfo) -> Chars</name>
<fsummary>Return an English description of a an error tuple.</fsummary>
<type>
<v>Chars = [char() | Chars]</v>
@@ -145,8 +146,8 @@ Token = tuple()</code>
<funcs>
<func>
- <name>string(String) -> StringRet</name>
- <name>string(String, StartLine) -> StringRet</name>
+ <name since="">string(String) -> StringRet</name>
+ <name since="">string(String, StartLine) -> StringRet</name>
<fsummary>Generated by Leex</fsummary>
<type>
<v>String = string()</v>
@@ -163,9 +164,9 @@ Token = tuple()</code>
</func>
<func>
- <name>token(Cont, Chars) -> {more,Cont1} | {done,TokenRet,RestChars}
+ <name since="">token(Cont, Chars) -> {more,Cont1} | {done,TokenRet,RestChars}
</name>
- <name>token(Cont, Chars, StartLine) -> {more,Cont1}
+ <name since="">token(Cont, Chars, StartLine) -> {more,Cont1}
| {done,TokenRet,RestChars}
</name>
<fsummary>Generated by Leex</fsummary>
@@ -198,9 +199,9 @@ io:request(InFile, {get_until,Prompt,Module,token,[Line]})
</func>
<func>
- <name>tokens(Cont, Chars) -> {more,Cont1} | {done,TokensRet,RestChars}
+ <name since="">tokens(Cont, Chars) -> {more,Cont1} | {done,TokensRet,RestChars}
</name>
- <name>tokens(Cont, Chars, StartLine) ->
+ <name since="">tokens(Cont, Chars, StartLine) ->
{more,Cont1} | {done,TokensRet,RestChars}
</name>
<fsummary>Generated by Leex</fsummary>
diff --git a/lib/parsetools/doc/src/notes.xml b/lib/parsetools/doc/src/notes.xml
index b3370a06ab..f8cd9b972d 100644
--- a/lib/parsetools/doc/src/notes.xml
+++ b/lib/parsetools/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2017</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,6 +31,36 @@
</header>
<p>This document describes the changes made to the Parsetools application.</p>
+<section><title>Parsetools 2.1.8</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Parsetools 2.1.7</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> Calls to <c>erlang:get_stacktrace()</c> are removed.
+ </p>
+ <p>
+ Own Id: OTP-14861</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Parsetools 2.1.6</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/parsetools/doc/src/yecc.xml b/lib/parsetools/doc/src/yecc.xml
index 5f95b5c150..67a2c95c25 100644
--- a/lib/parsetools/doc/src/yecc.xml
+++ b/lib/parsetools/doc/src/yecc.xml
@@ -32,7 +32,7 @@
<rev>B</rev>
<file>yecc.sgml</file>
</header>
- <module>yecc</module>
+ <module since="">yecc</module>
<modulesummary>LALR-1 Parser Generator</modulesummary>
<description>
<p>An LALR-1 parser generator for Erlang, similar to <c>yacc</c>.
@@ -46,7 +46,7 @@
</description>
<funcs>
<func>
- <name>file(Grammarfile [, Options]) -> YeccRet</name>
+ <name since="">file(Grammarfile [, Options]) -> YeccRet</name>
<fsummary>Give information about resolved and unresolved parse action conflicts.</fsummary>
<type>
<v>Grammarfile = filename()</v>
@@ -137,7 +137,7 @@
</desc>
</func>
<func>
- <name>format_error(Reason) -> Chars</name>
+ <name since="">format_error(Reason) -> Chars</name>
<fsummary>Return an English description of a an error tuple.</fsummary>
<type>
<v>Reason =&nbsp;-&nbsp;as returned by yecc:file/1,2&nbsp;-</v>
diff --git a/lib/parsetools/include/yeccpre.hrl b/lib/parsetools/include/yeccpre.hrl
index 91d6cd49a6..562f17c19e 100644
--- a/lib/parsetools/include/yeccpre.hrl
+++ b/lib/parsetools/include/yeccpre.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -56,8 +56,7 @@ return_error(Line, Message) ->
yeccpars0(Tokens, Tzr, State, States, Vstack) ->
try yeccpars1(Tokens, Tzr, State, States, Vstack)
catch
- error: Error ->
- Stacktrace = erlang:get_stacktrace(),
+ error: Error: Stacktrace ->
try yecc_error_type(Error, Stacktrace) of
Desc ->
erlang:raise(error, {yecc_bug, ?CODE_VERSION, Desc},
diff --git a/lib/parsetools/src/leex.erl b/lib/parsetools/src/leex.erl
index e2e7d7359f..8a4a5e8d86 100644
--- a/lib/parsetools/src/leex.erl
+++ b/lib/parsetools/src/leex.erl
@@ -37,7 +37,6 @@
-import(lists, [member/2,reverse/1,sort/1,delete/2,
keysort/2,keydelete/3,
map/2,foldl/3,foreach/2,flatmap/2]).
--import(string, [substr/2,substr/3,span/2]).
-import(ordsets, [is_element/2,add_element/2,union/2]).
-import(orddict, [store/3]).
@@ -251,10 +250,10 @@ is_filename(T) ->
shorten_filename(Name0) ->
{ok,Cwd} = file:get_cwd(),
- case lists:prefix(Cwd, Name0) of
- false -> Name0;
- true ->
- case lists:nthtail(length(Cwd), Name0) of
+ case string:prefix(Name0, Cwd) of
+ nomatch -> Name0;
+ Rest ->
+ case unicode:characters_to_list(Rest) of
"/"++N -> N;
N -> N
end
@@ -490,12 +489,9 @@ parse_rules_end(_, NextLine, REAs, As, St) ->
%% action has been read. Keep track of line number.
collect_rule(Ifile, Chars, L0) ->
- %% Erlang strings are 1 based, but re 0 :-(
- {match,[{St0,Len}|_]} = re:run(Chars, "[^ \t\r\n]+", [unicode]),
- St = St0 + 1,
- %%io:fwrite("RE = ~p~n", [substr(Chars, St, Len)]),
- case collect_action(Ifile, substr(Chars, St+Len), L0, []) of
- {ok,[{':',_}|Toks],L1} -> {ok,substr(Chars, St, Len),Toks,L1};
+ {RegExp,Rest} = string:take(Chars, " \t\r\n", true),
+ case collect_action(Ifile, Rest, L0, []) of
+ {ok,[{':',_}|Toks],L1} -> {ok,RegExp,Toks,L1};
{ok,_,_} -> {error,{L0,leex,bad_rule}};
{eof,L1} -> {error,{L1,leex,bad_rule}};
{error,E,_} -> {error,E}
@@ -549,7 +545,7 @@ var_used(Name, Toks) ->
parse_rule_regexp(RE0, [{M,Exp}|Ms], St) ->
Split= re:split(RE0, "\\{" ++ M ++ "\\}", [{return,list},unicode]),
- RE1 = string:join(Split, Exp),
+ RE1 = lists:append(lists:join(Exp, Split)),
parse_rule_regexp(RE1, Ms, St);
parse_rule_regexp(RE, [], St) ->
%%io:fwrite("RE = ~p~n", [RE]),
@@ -589,9 +585,9 @@ nextline(Ifile, L, St) ->
eof -> {eof,L};
{error, _} -> add_error({L+1, leex, cannot_parse}, St);
Chars ->
- case substr(Chars, span(Chars, " \t\n")+1) of
- [$%|_Rest] -> nextline(Ifile, L+1, St);
- [] -> nextline(Ifile, L+1, St);
+ case string:take(Chars, " \t\n") of
+ {_, [$%|_Rest]} -> nextline(Ifile, L+1, St);
+ {_, []} -> nextline(Ifile, L+1, St);
_Other -> {ok,Chars,L+1}
end
end.
@@ -824,7 +820,7 @@ re_char_class(Cs, Cc, _) -> {reverse(Cc),Cs}. % Preserve order
%% posix_cc("space" ++ Cs) -> {space,Cs};
%% posix_cc("upper" ++ Cs) -> {upper,Cs};
%% posix_cc("xdigit" ++ Cs) -> {xdigit,Cs};
-%% posix_cc(Cs) -> parse_error({posix_cc,substr(Cs, 1, 5)}).
+%% posix_cc(Cs) -> parse_error({posix_cc,string:slice(Cs, 0, 5)}).
escape_char($n) -> $\n; % \n = LF
escape_char($r) -> $\r; % \r = CR
@@ -863,7 +859,7 @@ escape_char(C) -> C. % Pass it straight through
%% re_number(Cs, Acc) -> {Acc,Cs}.
string_between(Cs1, Cs2) ->
- substr(Cs1, 1, length(Cs1)-length(Cs2)).
+ string:slice(Cs1, 0, string:length(Cs1)-string:length(Cs2)).
%% We use standard methods, Thompson's construction and subset
%% construction, to create first an NFA and then a DFA from the
@@ -1343,7 +1339,7 @@ out_file(Ifile, Ofile, St, DFA, DF, Actions, Code, L) ->
eof -> output_file_directive(Ofile, St#leex.ifile, L);
{error, _} -> add_error(St#leex.ifile, {L, leex, cannot_parse}, St);
Line ->
- case substr(Line, 1, 5) of
+ case string:slice(Line, 0, 5) of
"##mod" -> out_module(Ofile, St);
"##cod" -> out_erlang_code(Ofile, St, Code, L);
"##dfa" -> out_dfa(Ofile, St, DFA, Code, DF, L);
@@ -1523,7 +1519,7 @@ prep_out_actions(As) ->
Name = list_to_atom(lists:concat([yyaction_,A])),
[Chars,Len,Line,_,_] = Vars,
Args = [V || V <- [Chars,Len,Line], V =/= "_"],
- ArgsChars = string:join(Args, ", "),
+ ArgsChars = lists:join(", ", Args),
{A,Code,Vars,Name,Args,ArgsChars}
end, As).
diff --git a/lib/parsetools/src/yecc.erl b/lib/parsetools/src/yecc.erl
index 36e33b52a4..3343a4282b 100644
--- a/lib/parsetools/src/yecc.erl
+++ b/lib/parsetools/src/yecc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -365,10 +365,10 @@ is_filename(T) ->
shorten_filename(Name0) ->
{ok,Cwd} = file:get_cwd(),
- case lists:prefix(Cwd, Name0) of
- false -> Name0;
- true ->
- case lists:nthtail(length(Cwd), Name0) of
+ case string:prefix(Name0, Cwd) of
+ nomatch -> Name0;
+ Rest ->
+ case unicode:characters_to_list(Rest) of
"/"++N -> N;
N -> N
end
@@ -455,10 +455,14 @@ os_process_size() ->
case os:type() of
{unix, sunos} ->
Size = os:cmd("ps -o vsz -p " ++ os:getpid() ++ " | tail -1"),
- list_to_integer(lib:nonl(Size));
+ list_to_integer(nonl(Size));
_ ->
0
- end.
+ end.
+
+nonl([$\n]) -> [];
+nonl([]) -> [];
+nonl([H|T]) -> [H|nonl(T)].
timeit(Name, Fun, St0) ->
Time = runtime,
@@ -2196,8 +2200,8 @@ output_reduce(St0, State, Terminal,
St20;
true ->
Ns = "Nss",
- Tmp = string:join(lists:duplicate(NmbrOfDaughters - 1, "_"),
- ","),
+ Tmp = lists:join(",",
+ lists:duplicate(NmbrOfDaughters - 1, "_")),
fwrite(St20, <<" [~s|Nss] = Ss,\n">>, [Tmp])
end,
St40 = case tokens(RuleNmbr, St30) of
diff --git a/lib/parsetools/src/yeccparser.erl b/lib/parsetools/src/yeccparser.erl
index 6f6f66d56c..0deecc7879 100644
--- a/lib/parsetools/src/yeccparser.erl
+++ b/lib/parsetools/src/yeccparser.erl
@@ -17,7 +17,7 @@ anno_of(Token) ->
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -72,8 +72,7 @@ return_error(Line, Message) ->
yeccpars0(Tokens, Tzr, State, States, Vstack) ->
try yeccpars1(Tokens, Tzr, State, States, Vstack)
catch
- error: Error ->
- Stacktrace = erlang:get_stacktrace(),
+ error: Error: Stacktrace ->
try yecc_error_type(Error, Stacktrace) of
Desc ->
erlang:raise(error, {yecc_bug, ?CODE_VERSION, Desc},
@@ -167,21 +166,20 @@ yecctoken_location(Token) ->
end.
-compile({nowarn_unused_function, yecctoken2string/1}).
-yecctoken2string({atom, _, A}) -> io_lib:write(A);
+yecctoken2string({atom, _, A}) -> io_lib:write_atom(A);
yecctoken2string({integer,_,N}) -> io_lib:write(N);
yecctoken2string({float,_,F}) -> io_lib:write(F);
yecctoken2string({char,_,C}) -> io_lib:write_char(C);
yecctoken2string({var,_,V}) -> io_lib:format("~s", [V]);
yecctoken2string({string,_,S}) -> io_lib:write_string(S);
yecctoken2string({reserved_symbol, _, A}) -> io_lib:write(A);
-yecctoken2string({_Cat, _, Val}) -> io_lib:format("~p",[Val]);
+yecctoken2string({_Cat, _, Val}) -> io_lib:format("~tp", [Val]);
yecctoken2string({dot, _}) -> "'.'";
-yecctoken2string({'$end', _}) ->
- [];
+yecctoken2string({'$end', _}) -> [];
yecctoken2string({Other, _}) when is_atom(Other) ->
- io_lib:write(Other);
+ io_lib:write_atom(Other);
yecctoken2string(Other) ->
- io_lib:write(Other).
+ io_lib:format("~tp", [Other]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/parsetools/test/leex_SUITE.erl b/lib/parsetools/test/leex_SUITE.erl
index 3f5d9fee3e..ad8fb11beb 100644
--- a/lib/parsetools/test/leex_SUITE.erl
+++ b/lib/parsetools/test/leex_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -124,10 +124,6 @@ file(Config) when is_list(Config) ->
"Erlang code.\n">>,
?line ok = file:write_file(Filename, Mini),
?line {error,[{_,[{none,leex,{file_error,_}}]}],[]} =
- leex:file(Filename, [{scannerfile,"//"} | Ret]),
- ?line {error,[{_,[{none,leex,{file_error,_}}]}],[]} =
- leex:file(Filename, [{includefile,"//"} | Ret]),
- ?line {error,[{_,[{none,leex,{file_error,_}}]}],[]} =
leex:file(Filename, [{includefile,"/ /"} | Ret]),
LeexPre = filename:join(Dir, "leexinc.hrl"),
@@ -191,7 +187,6 @@ compile(Config) when is_list(Config) ->
"{L}+ : {token,{word,TokenLine,TokenChars}}.\n"
"Erlang code.\n">>,
?line ok = file:write_file(Filename, Mini),
- ?line error = leex:compile(Filename, "//", #options{}),
?line ok = leex:compile(Filename, Scannerfile, #options{}),
file:delete(Scannerfile),
file:delete(Filename),
diff --git a/lib/parsetools/test/yecc_SUITE.erl b/lib/parsetools/test/yecc_SUITE.erl
index a7166b91ed..715e50c301 100644
--- a/lib/parsetools/test/yecc_SUITE.erl
+++ b/lib/parsetools/test/yecc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1674,8 +1674,7 @@ format_error(Message) ->
yeccpars0(Tokens, MFA) ->
try yeccpars1(Tokens, MFA, 0, [], [])
catch
- error: Error ->
- Stacktrace = erlang:get_stacktrace(),
+ error: Error : Stacktrace ->
try yecc_error_type(Error, Stacktrace) of
{syntax_error, Token} ->
yeccerror(Token);
diff --git a/lib/parsetools/vsn.mk b/lib/parsetools/vsn.mk
index b6d2ce0cd4..1a5201ce5d 100644
--- a/lib/parsetools/vsn.mk
+++ b/lib/parsetools/vsn.mk
@@ -1 +1 @@
-PARSETOOLS_VSN = 2.1.6
+PARSETOOLS_VSN = 2.1.8
diff --git a/lib/public_key/asn1/OTP-PKIX.asn1 b/lib/public_key/asn1/OTP-PKIX.asn1
index 37196bb9bf..ff3250b383 100644
--- a/lib/public_key/asn1/OTP-PKIX.asn1
+++ b/lib/public_key/asn1/OTP-PKIX.asn1
@@ -233,9 +233,13 @@ countryName ATTRIBUTE-TYPE-AND-VALUE-CLASS ::= {
-- regarding how to handle and sometimes accept incorrect certificates
-- we define and use the type below instead of X520countryName
+ -- We accept utf8String encoding of the US-ASCII
+ -- country name code and the mix up with other country code systems
+ -- that uses three characters instead of two.
+
OTP-X520countryname ::= CHOICE {
- printableString PrintableString (SIZE (2)),
- utf8String UTF8String (SIZE (2))
+ printableString PrintableString (SIZE (2..3)),
+ utf8String UTF8String (SIZE (2..3))
}
serialNumber ATTRIBUTE-TYPE-AND-VALUE-CLASS ::= {
@@ -326,8 +330,13 @@ PublicKeyAlgorithm ::= SEQUENCE {
OPTIONAL }
SupportedSignatureAlgorithms SIGNATURE-ALGORITHM-CLASS ::= {
- dsa-with-sha1 | dsaWithSHA1 | md2-with-rsa-encryption |
- md5-with-rsa-encryption | sha1-with-rsa-encryption | sha-1with-rsa-encryption |
+ dsa-with-sha1 | dsaWithSHA1 |
+ dsa-with-sha224 |
+ dsa-with-sha256 |
+ md2-with-rsa-encryption |
+ md5-with-rsa-encryption |
+ sha1-with-rsa-encryption |
+ sha-1with-rsa-encryption |
sha224-with-rsa-encryption |
sha256-with-rsa-encryption |
sha384-with-rsa-encryption |
@@ -368,6 +377,21 @@ SupportedPublicKeyAlgorithms PUBLIC-KEY-ALGORITHM-CLASS ::= {
ID id-dsaWithSHA1
TYPE DSAParams }
+ dsa-with-sha224 SIGNATURE-ALGORITHM-CLASS ::= {
+ ID id-dsa-with-sha224
+ TYPE DSAParams }
+
+ dsa-with-sha256 SIGNATURE-ALGORITHM-CLASS ::= {
+ ID id-dsa-with-sha256
+ TYPE DSAParams }
+
+ id-dsa-with-sha224 OBJECT IDENTIFIER ::= {
+ joint-iso-ccitt(2) country(16) us(840) organization(1) gov(101)
+ csor(3) algorithms(4) id-dsa-with-sha2(3) 1 }
+
+ id-dsa-with-sha256 OBJECT IDENTIFIER ::= {
+ joint-iso-ccitt(2) country(16) us(840) organization(1) gov(101)
+ csor(3) algorithms(4) id-dsa-with-sha2(3) 2 }
--
-- RSA Keys and Signatures
--
diff --git a/lib/public_key/asn1/PKCS-7.asn1 b/lib/public_key/asn1/PKCS-7.asn1
index e76f928acb..e9c188be39 100644
--- a/lib/public_key/asn1/PKCS-7.asn1
+++ b/lib/public_key/asn1/PKCS-7.asn1
@@ -124,7 +124,7 @@ SignerInfoAuthenticatedAttributes ::= CHOICE {
-- Also defined in X.509
-- Redeclared here as a parameterized type
-AlgorithmIdentifierPKSC-7 {ALGORITHM:IOSet} ::= SEQUENCE {
+AlgorithmIdentifierPKCS-7 {ALGORITHM:IOSet} ::= SEQUENCE {
algorithm ALGORITHM.&id({IOSet}),
parameters ALGORITHM.&Type({IOSet}{@algorithm}) OPTIONAL
}
@@ -146,21 +146,21 @@ CRLSequence ::=
SEQUENCE OF CertificateList
ContentEncryptionAlgorithmIdentifier ::=
- AlgorithmIdentifierPKSC-7 {{ContentEncryptionAlgorithms}}
+ AlgorithmIdentifierPKCS-7 {{ContentEncryptionAlgorithms}}
ContentEncryptionAlgorithms ALGORITHM ::= {
... -- add any application-specific algorithms here
}
DigestAlgorithmIdentifier ::=
- AlgorithmIdentifierPKSC-7 {{DigestAlgorithms}}
+ AlgorithmIdentifierPKCS-7 {{DigestAlgorithms}}
DigestAlgorithms ALGORITHM ::= {
... -- add any application-specific algorithms here
}
DigestEncryptionAlgorithmIdentifier ::=
- AlgorithmIdentifierPKSC-7 {{DigestEncryptionAlgorithms}}
+ AlgorithmIdentifierPKCS-7 {{DigestEncryptionAlgorithms}}
DigestEncryptionAlgorithms ALGORITHM ::= {
... -- add any application-specific algorithms here
@@ -182,7 +182,7 @@ IssuerAndSerialNumber ::= SEQUENCE {
}
KeyEncryptionAlgorithmIdentifier ::=
- AlgorithmIdentifierPKSC-7 {{KeyEncryptionAlgorithms}}
+ AlgorithmIdentifierPKCS-7 {{KeyEncryptionAlgorithms}}
KeyEncryptionAlgorithms ALGORITHM ::= {
... -- add any application-specific algorithms here
diff --git a/lib/public_key/doc/specs/.gitignore b/lib/public_key/doc/specs/.gitignore
new file mode 100644
index 0000000000..322eebcb06
--- /dev/null
+++ b/lib/public_key/doc/specs/.gitignore
@@ -0,0 +1 @@
+specs_*.xml
diff --git a/lib/public_key/doc/src/Makefile b/lib/public_key/doc/src/Makefile
index f5157fe87a..c8647750af 100644
--- a/lib/public_key/doc/src/Makefile
+++ b/lib/public_key/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2008-2017. All Rights Reserved.
+# Copyright Ericsson AB 2008-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -77,12 +77,18 @@ HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
+SPECS_FILES = $(XML_REF3_FILES:%.xml=$(SPECDIR)/specs_%.xml)
+
+TOP_SPECS_FILE = specs.xml
+
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
XML_FLAGS +=
DVIPS_FLAGS +=
+SPECS_FLAGS = -I../../include -I../../src -I../../..
+
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
@@ -99,9 +105,11 @@ html: gifs $(HTML_REF_MAN_FILE)
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(MAN6DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
+ rm -f $(SPECS_FILES)
rm -f errs core *~
man: $(MAN3_FILES) $(MAN6_FILES)
diff --git a/lib/public_key/doc/src/notes.xml b/lib/public_key/doc/src/notes.xml
index 11012ee9e5..d13c9a520a 100644
--- a/lib/public_key/doc/src/notes.xml
+++ b/lib/public_key/doc/src/notes.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2008</year>
- <year>2017</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -35,6 +35,239 @@
<file>notes.xml</file>
</header>
+<section><title>Public_Key 1.6.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ RSA options passed to crypto for encrypt and decrypt with
+ public or private key.</p>
+ <p>
+ Own Id: OTP-15754 Aux Id: ERL-878 </p>
+ </item>
+ <item>
+ <p>
+ Fix dialyzer warnings caused by a faulty type
+ specification for digest_type().</p>
+ <p>
+ This change updates digest_type() and the functions
+ operating with this argument type to accept both 'sha1'
+ and 'sha' as digest_type().</p>
+ <p>
+ Own Id: OTP-15776</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Add possibility to read PEM files encrypted with old PEM
+ encryption using AES-256</p>
+ <p>
+ Own Id: OTP-13726</p>
+ </item>
+ <item>
+ <p>
+ Relax decoding of certificates to so that "harmless"
+ third party encoding errors may be accepted but not
+ created by the public_key application. This adds
+ acceptance of using an incorrect three character country
+ code, the PKIX standard use two character country codes.
+ It is also accepted that the country code is utf8 encoded
+ but the specification says it should be ASCII.</p>
+ <p>
+ Own Id: OTP-15687 Aux Id: PR-2162 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Public_Key 1.6.6</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Back port of bug fix ERL-893 from OTP-22 and document
+ enhancements that will solve dialyzer warnings for users
+ of the ssl application.</p>
+ <p>
+ This change also affects public_key, eldap (and inet
+ doc).</p>
+ <p>
+ Own Id: OTP-15785 Aux Id: ERL-929, ERL-893, PR-2215 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Public_Key 1.6.5</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Add export of dialyzer type</p>
+ <p>
+ Own Id: OTP-15624</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Public_Key 1.6.4</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Added ed25519 and ed448 sign/verify.</p>
+ <p>
+ Requires OpenSSL 1.1.1 or higher as cryptolib under the
+ OTP application <c>crypto</c>.</p>
+ <p>
+ Own Id: OTP-15419 Aux Id: OTP-15094 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Public_Key 1.6.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Add DSA SHA2 oids in public_keys ASN1-spec and
+ public_key:pkix_sign_types/1</p>
+ <p>
+ Own Id: OTP-15367</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Public_Key 1.6.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Removed <c>#DSAPrivateKey{}</c> as acceptable input to
+ <c>public_key:verify/5</c>.</p>
+ <p>
+ Own Id: OTP-15284</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The typing in the CRYPTO and PUBLIC_KEY applications are
+ reworked and a few mistakes are corrected.</p>
+ <p>
+ The documentation is now generated from the typing and
+ some clarifications are made.</p>
+ <p>
+ A new chapter on Algorithm Details such as key sizes and
+ availability is added to the CRYPTO User's Guide.</p>
+ <p>
+ Own Id: OTP-15134</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Public_Key 1.6.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Some of the keylengths in the newly generated moduli file
+ in public_key are not universally supported. This could
+ cause the SSH key exchange
+ diffie-hellman-group-exchange-sha* to fail.</p>
+ <p>
+ Those keylengths are now removed.</p>
+ <p>
+ Own Id: OTP-15151 Aux Id: OTP-15113 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Public_Key 1.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Update calls to the base64 module to conform to that
+ module's type specifications.</p>
+ <p>
+ Own Id: OTP-14788 Aux Id: OTP-14624 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Use uri_string module instead of http_uri.</p>
+ <p>
+ Own Id: OTP-14902</p>
+ </item>
+ <item>
+ <p>
+ A new function -
+ <c>public_key:pkix_verify_hostname_match_fun/1</c> -
+ returns a fun to be given as option <c>match_fun</c> to
+ <c>public_key:pkix_verify_hostname/3</c> or via ssl.</p>
+ <p>
+ The fun makes the verify hostname matching according to
+ the specific rules for the protocol in the argument.
+ Presently only <c>https</c> is supported.</p>
+ <p>
+ Own Id: OTP-14962 Aux Id: ERL-542, OTP-15102 </p>
+ </item>
+ <item>
+ <p>
+ Compleate PKCS-8 encoding support and enhance the
+ decoding of 'PrivateKeyInfo' to conform to the rest of
+ Erlang public_key API.</p>
+ <p>
+ Own Id: OTP-15093</p>
+ </item>
+ <item>
+ <p>
+ A new moduli file is generated. This file is used for the
+ recommended <c>diffie-hellman-group-exchange-sha256</c>
+ key exchange algorithm in SSH.</p>
+ <p>
+ Own Id: OTP-15113</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Public_Key 1.5.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml
index dea35bc390..12bb0b21b0 100644
--- a/lib/public_key/doc/src/public_key.xml
+++ b/lib/public_key/doc/src/public_key.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2008</year>
- <year>2017</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -31,7 +31,7 @@
<date></date>
<rev></rev>
</header>
- <module>public_key</module>
+ <module since="">public_key</module>
<modulesummary>API module for public-key infrastructure.</modulesummary>
<description>
<p>Provides functions to handle public-key infrastructure,
@@ -41,7 +41,7 @@
</description>
<section>
- <title>DATA TYPES</title>
+ <title>Common Records and ASN.1 Types</title>
<note><p>All records used in this Reference Manual
<!-- except #policy_tree_node{} -->
@@ -54,191 +54,147 @@
records and constant macros described here and in the User's Guide:</p>
<code> -include_lib("public_key/include/public_key.hrl").</code>
+ </section>
+
+ <datatypes>
+ <datatype>
+ <name name="oid"/>
+ <desc>
+ <p>Object identifier, a tuple of integers as generated by the <c>ASN.1</c> compiler.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="der_encoded"/>
+ <desc>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="pki_asn1_type"/>
+ <desc>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="asn1_type"/>
+ <desc>
+ <p>ASN.1 type present in the Public Key applications ASN.1 specifications.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="pem_entry"/>
+ <name name="der_or_encrypted_der"/>
+ <name name="cipher_info"/>
+ <name name="cipher"/>
+ <name name="salt"/>
+ <name name="cipher_info_params"/>
+ <desc>
+ <code>Cipher = "RC2-CBC" | "DES-CBC" | "DES-EDE3-CBC"</code>
+ <p><c>Salt</c> could be generated with
+ <seealso marker="crypto:crypto#strong_rand_bytes-1"><c>crypto:strong_rand_bytes(8)</c></seealso>.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="public_key"/>
+ <name name="rsa_public_key"/>
+ <name name="dsa_public_key"/>
+ <name name="ec_public_key"/>
+ <name name="ecpk_parameters"/>
+ <name name="ecpk_parameters_api"/>
+ <desc>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="ed_public_key"/>
+ <desc>
+ <warning><p>This format of the EdDSA curves is temporary and may change without prior notice!</p></warning>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="private_key"/>
+ <name name="rsa_private_key"/>
+ <name name="dsa_private_key"/>
+ <name name="ec_private_key"/>
+ <desc>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="ed_private_key"/>
+ <desc>
+ <warning><p>This format of the EdDSA curves is temporary and may change without prior notice!</p></warning>
+ </desc>
+ </datatype>
+
+
+ <datatype>
+ <name name="key_params"/>
+ <desc>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="digest_type"/>
+ <desc>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="crl_reason"/>
+ <desc>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="issuer_id"/>
+ <desc>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="issuer_name"/>
+ <desc>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="ssh_file"/>
+ <desc>
+ </desc>
+ </datatype>
+
+
+
+ </datatypes>
- <p>The following data types are used in the functions for <c>public_key</c>:</p>
-
- <taglist>
- <tag><c>oid()</c></tag>
- <item><p>Object identifier, a tuple of integers as generated by the <c>ASN.1</c> compiler.</p></item>
-
- <tag><c>boolean() =</c></tag>
- <item><p><c>true | false</c></p></item>
-
- <tag><c>string() =</c></tag>
- <item><p><c>[bytes()]</c></p></item>
-
- <tag><c>der_encoded() =</c></tag>
- <item><p><c>binary()</c></p></item>
-
- <tag><c>pki_asn1_type() =</c></tag>
- <item>
- <p><c>'Certificate'</c></p>
- <p><c>| 'RSAPrivateKey'</c></p>
- <p><c>| 'RSAPublicKey'</c></p>
- <p><c>| 'DSAPrivateKey'</c></p>
- <p><c>| 'DSAPublicKey'</c></p>
- <p><c>| 'DHParameter'</c></p>
- <p><c>| 'SubjectPublicKeyInfo'</c></p>
- <p><c>| 'PrivateKeyInfo'</c></p>
- <p><c>| 'CertificationRequest'</c></p>
- <p><c>| 'CertificateList'</c></p>
- <p><c>| 'ECPrivateKey'</c></p>
- <p><c>| 'EcpkParameters'</c></p>
- </item>
-
- <tag><c>pem_entry () =</c></tag>
- <item><p><c>{pki_asn1_type(), binary(), %% DER or encrypted DER</c></p>
- <p><c> not_encrypted | cipher_info()}</c></p></item>
-
- <tag><c>cipher_info() = </c></tag>
- <item><p><c>{"RC2-CBC" | "DES-CBC" | "DES-EDE3-CBC", crypto:strong_rand_bytes(8)</c></p>
- <p><c>| {#'PBEParameter{}, digest_type()} | #'PBES2-params'{}}</c></p>
- </item>
-
- <tag><c>public_key() =</c></tag>
- <item><p><c>rsa_public_key() | dsa_public_key() | ec_public_key()</c></p></item>
-
- <tag><c>private_key() =</c></tag>
- <item><p><c>rsa_private_key() | dsa_private_key() | ec_private_key()</c></p></item>
-
- <tag><c>rsa_public_key() =</c></tag>
- <item><p><c>#'RSAPublicKey'{}</c></p></item>
-
- <tag><c>rsa_private_key() =</c></tag>
- <item><p><c>#'RSAPrivateKey'{}</c></p></item>
-
- <tag><c>dsa_public_key() =</c></tag>
- <item><p><c>{integer(), #'Dss-Parms'{}}</c></p></item>
-
- <tag><c>dsa_private_key() =</c></tag>
- <item><p><c>#'DSAPrivateKey'{}</c></p></item>
-
- <tag><c>ec_public_key()</c></tag>
- <item><p>= <c>{#'ECPoint'{}, #'ECParameters'{} | {namedCurve, oid()}}</c></p></item>
-
- <tag><c>ec_private_key() =</c></tag>
- <item><p><c>#'ECPrivateKey'{}</c></p></item>
-
- <tag><c>key_params() =</c></tag>
- <item><p> #'DHParameter'{} | {namedCurve, oid()} | #'ECParameters'{}
- | {rsa, Size::integer(), PubExp::integer()} </p></item>
-
- <tag><c>public_crypt_options() =</c></tag>
- <item><p><c>[{rsa_pad, rsa_padding()}]</c></p></item>
-
- <tag><c>rsa_padding() =</c></tag>
- <item>
- <p><c>'rsa_pkcs1_padding'</c></p>
- <p><c>| 'rsa_pkcs1_oaep_padding'</c></p>
- <p><c>| 'rsa_no_padding'</c></p>
- </item>
-
- <tag><c>public_sign_options() =</c></tag>
- <item><p><c>[{rsa_pad, rsa_sign_padding()} | {rsa_pss_saltlen, integer()}]</c></p></item>
-
- <tag><c>rsa_sign_padding() =</c></tag>
- <item>
- <p><c>'rsa_pkcs1_padding'</c></p>
- <p><c>| 'rsa_pkcs1_pss_padding'</c></p>
- </item>
-
- <tag><c>digest_type() = </c></tag>
- <item><p>Union of <c>rsa_digest_type()</c>, <c>dss_digest_type()</c>,
- and <c>ecdsa_digest_type()</c>.</p></item>
-
- <tag><c>rsa_digest_type() = </c></tag>
- <item><p><c>'md5' | 'ripemd160' | 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'</c></p></item>
-
- <tag><c>dss_digest_type() = </c></tag>
- <item><p><c>'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'</c></p>
- <p>Note that the actual supported dss_digest_type depends on the underlying crypto library.
- In OpenSSL version >= 1.0.1 the listed digest are supported, while in 1.0.0 only
- sha, sha224 and sha256 are supported. In version 0.9.8 only sha is supported.</p>
- </item>
-
- <tag><c>ecdsa_digest_type() = </c></tag>
- <item><p><c>'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'</c></p></item>
-
- <tag><c>crl_reason() = </c></tag>
- <item>
- <p><c>unspecified</c></p>
- <p><c>| keyCompromise</c></p>
- <p><c>| cACompromise</c></p>
- <p><c>| affiliationChanged</c></p>
- <p><c>| superseded</c></p>
- <p><c>| cessationOfOperation</c></p>
- <p><c>| certificateHold</c></p>
- <p><c>| privilegeWithdrawn</c></p>
- <p><c>| aACompromise</c></p>
- </item>
-
- <tag><c>issuer_name() =</c></tag>
- <item><p><c>{rdnSequence,[#'AttributeTypeAndValue'{}]}</c></p>
- </item>
-
- <tag><c>ssh_file() =</c></tag>
- <item>
- <p><c>openssh_public_key</c></p>
- <p><c>| rfc4716_public_key</c></p>
- <p><c>| known_hosts</c></p>
- <p><c>| auth_keys</c></p>
- </item>
- </taglist>
-
-
-<!-- <p><code>policy_tree() = [Root, Children]</code></p> -->
-
-<!-- <p><code>Root = #policy_tree_node{}</code></p> -->
-
-<!-- <p><code>Children = [] | policy_tree()</code></p> -->
-
-<!-- <p>The <c>policy_tree_node</c> record has the following fields:</p> -->
-
-<!-- <taglist> -->
-
-<!-- <tag>valid_policy</tag> -->
-<!-- <item>A single policy OID representing a -->
-<!-- valid policy for the path of length x.</item> -->
-
-<!-- <tag>qualifier_set</tag> -->
-<!-- <item>A set of policy qualifiers associated -->
-<!-- with the valid policy in certificate x.</item> -->
-
-<!-- <tag>critically_indicator</tag> -->
-<!-- <item>Indicates whether the -->
-<!-- certificate policy extension in certificate x was marked as -->
-<!-- critical.</item> -->
-
-<!-- <tag>expected_policy_set</tag> -->
-<!-- <item>Contains one or more policy OIDs -->
-<!-- that would satisfy this policy in the certificate x+1.</item> -->
-<!-- </taglist> -->
- </section>
<funcs>
<func>
- <name>compute_key(OthersKey, MyKey)-></name>
- <name>compute_key(OthersKey, MyKey, Params)-></name>
+ <name name="compute_key" arity="2" since="OTP R16B01"/>
+ <fsummary>Computes shared secret.</fsummary>
+ <desc>
+ <p>Computes shared secret.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="compute_key" arity="3" since="OTP R16B01"/>
<fsummary>Computes shared secret.</fsummary>
- <type>
- <v>OthersKey = #'ECPoint'{} | binary(), MyKey = #'ECPrivateKey'{} | binary()</v>
- <v>Params = #'DHParameter'{}</v>
- </type>
<desc>
<p>Computes shared secret.</p>
</desc>
</func>
<func>
- <name>decrypt_private(CipherText, Key) -> binary()</name>
- <name>decrypt_private(CipherText, Key, Options) -> binary()</name>
+ <name name="decrypt_private" arity="2" since="OTP R14B"/>
+ <name name="decrypt_private" arity="3" since="OTP R14B"/>
<fsummary>Public-key decryption.</fsummary>
- <type>
- <v>CipherText = binary()</v>
- <v>Key = rsa_private_key()</v>
- <v>Options = public_crypt_options()</v>
- </type>
<desc>
<p>Public-key decryption using the private key. See also <seealso
marker="crypto:crypto#private_decrypt/4">crypto:private_decrypt/4</seealso></p>
@@ -246,14 +202,9 @@
</func>
<func>
- <name>decrypt_public(CipherText, Key) - > binary()</name>
- <name>decrypt_public(CipherText, Key, Options) - > binary()</name>
+ <name name="decrypt_public" arity="2" since="OTP R14B"/>
+ <name name="decrypt_public" arity="3" since="OTP R14B"/>
<fsummary>Public-key decryption.</fsummary>
- <type>
- <v>CipherText = binary()</v>
- <v>Key = rsa_public_key()</v>
- <v>Options = public_crypt_options()</v>
- </type>
<desc>
<p>Public-key decryption using the public key. See also <seealso
marker="crypto:crypto#public_decrypt/4">crypto:public_decrypt/4</seealso></p>
@@ -261,47 +212,24 @@
</func>
<func>
- <name>der_decode(Asn1type, Der) -> term()</name>
+ <name name="der_decode" arity="2" since="OTP R14B"/>
<fsummary>Decodes a public-key ASN.1 DER encoded entity.</fsummary>
- <type>
- <v>Asn1Type = atom()</v>
- <d>ASN.1 type present in the Public Key applications
- ASN.1 specifications.</d>
- <v>Der = der_encoded()</v>
- </type>
- <desc>
+ <desc>
<p>Decodes a public-key ASN.1 DER encoded entity.</p>
</desc>
</func>
-
+
<func>
- <name>der_encode(Asn1Type, Entity) -> der_encoded()</name>
+ <name name="der_encode" arity="2" since="OTP R14B"/>
<fsummary>Encodes a public-key entity with ASN.1 DER encoding.</fsummary>
- <type>
- <v>Asn1Type = atom()</v>
- <d>ASN.1 type present in the Public Key applications
- ASN.1 specifications.</d>
- <v>Entity = term()</v>
- <d>Erlang representation of <c>Asn1Type</c></d>
- </type>
<desc>
<p>Encodes a public-key entity with ASN.1 DER encoding.</p>
</desc>
</func>
<func>
- <name>dh_gex_group(MinSize, SuggestedSize, MaxSize, Groups) -> {ok, {Size,Group}} | {error,Error}</name>
+ <name name="dh_gex_group" arity="4" since="OTP 18.2"/>
<fsummary>Selects a group for Diffie-Hellman key exchange</fsummary>
- <type>
- <v>MinSize = positive_integer()</v>
- <v>SuggestedSize = positive_integer()</v>
- <v>MaxSize = positive_integer()</v>
- <v>Groups = undefined | [{Size,[{G,P}]}]</v>
- <v>Size = positive_integer()</v>
- <v>Group = {G,P}</v>
- <v>G = positive_integer()</v>
- <v>P = positive_integer()</v>
- </type>
<desc>
<p>Selects a group for Diffie-Hellman key exchange with the key size in the range <c>MinSize...MaxSize</c>
and as close to <c>SuggestedSize</c> as possible. If <c>Groups == undefined</c> a default set will be
@@ -320,13 +248,10 @@
</desc>
</func>
- <func>
- <name>encrypt_private(PlainText, Key) -> binary()</name>
+ <func>
+ <name name="encrypt_private" arity="2" since="OTP R14B"/>
+ <name name="encrypt_private" arity="3" since="OTP 21.1"/>
<fsummary>Public-key encryption using the private key.</fsummary>
- <type>
- <v>PlainText = binary()</v>
- <v>Key = rsa_private_key()</v>
- </type>
<desc>
<p>Public-key encryption using the private key.
See also <seealso
@@ -335,12 +260,9 @@
</func>
<func>
- <name>encrypt_public(PlainText, Key) -> binary()</name>
+ <name name="encrypt_public" arity="2" since="OTP R14B"/>
+ <name name="encrypt_public" arity="3" since="OTP 21.1"/>
<fsummary>Public-key encryption using the public key.</fsummary>
- <type>
- <v>PlainText = binary()</v>
- <v>Key = rsa_public_key()</v>
- </type>
<desc>
<p>Public-key encryption using the public key. See also <seealso
marker="crypto:crypto#public_encrypt/4">crypto:public_encrypt/4</seealso>.</p>
@@ -348,11 +270,8 @@
</func>
<func>
- <name>generate_key(Params) -> {Public::binary(), Private::binary()} | #'ECPrivateKey'{} | #'RSAPrivateKey'{}</name>
+ <name name="generate_key" arity="1" since="OTP R16B01"/>
<fsummary>Generates a new keypair.</fsummary>
- <type>
- <v>Params = key_params()</v>
- </type>
<desc>
<p>Generates a new keypair. Note that except for Diffie-Hellman
the public key is included in the private key structure. See also
@@ -362,38 +281,29 @@
</func>
<func>
- <name>pem_decode(PemBin) -> [pem_entry()]</name>
+ <name name="pem_decode" arity="1" since="OTP R14B"/>
<fsummary>Decodes PEM binary data and returns
entries as ASN.1 DER encoded entities.</fsummary>
- <type>
- <v>PemBin = binary()</v>
- <d>Example {ok, PemBin} = file:read_file("cert.pem").</d>
- </type>
<desc>
- <p>Decodes PEM binary data and returns
- entries as ASN.1 DER encoded entities.</p>
+ <p>Decodes PEM binary data and returns entries as ASN.1 DER encoded entities.</p>
+ <p>Example <c>{ok, PemBin} = file:read_file("cert.pem").
+ PemEntries = public_key:pem_decode(PemBin).
+ </c></p>
</desc>
</func>
- <func>
- <name>pem_encode(PemEntries) -> binary()</name>
+ <func>
+ <name name="pem_encode" arity="1" since="OTP R14B"/>
<fsummary>Creates a PEM binary.</fsummary>
- <type>
- <v> PemEntries = [pem_entry()] </v>
- </type>
- <desc>
- <p>Creates a PEM binary.</p>
- </desc>
+ <desc>
+ <p>Creates a PEM binary.</p>
+ </desc>
</func>
- <func>
- <name>pem_entry_decode(PemEntry) -> term()</name>
- <name>pem_entry_decode(PemEntry, Password) -> term()</name>
+ <func>
+ <name name="pem_entry_decode" arity="1" since="OTP R14B"/>
+ <name name="pem_entry_decode" arity="2" since="OTP R14B"/>
<fsummary>Decodes a PEM entry.</fsummary>
- <type>
- <v>PemEntry = pem_entry()</v>
- <v>Password = string()</v>
- </type>
<desc>
<p>Decodes a PEM entry. <c>pem_decode/1</c> returns a list of PEM
entries. Notice that if the PEM entry is of type
@@ -402,51 +312,36 @@
</desc>
</func>
- <func>
- <name>pem_entry_encode(Asn1Type, Entity) -> pem_entry()</name>
- <name>pem_entry_encode(Asn1Type, Entity, {CipherInfo, Password}) -> pem_entry()</name>
+ <func>
+ <name name="pem_entry_encode" arity="2" since="OTP R14B"/>
+ <name name="pem_entry_encode" arity="3" since="OTP R14B"/>
<fsummary>Creates a PEM entry that can be fed to <c>pem_encode/1</c>.</fsummary>
- <type>
- <v>Asn1Type = pki_asn1_type()</v>
- <v>Entity = term()</v>
- <d>Erlang representation of
- <c>Asn1Type</c>. If <c>Asn1Type</c> is 'SubjectPublicKeyInfo',
+ <desc>
+ <p>Creates a PEM entry that can be feed to <c>pem_encode/1</c>.</p>
+ <p>If <c>Asn1Type</c> is <c>'SubjectPublicKeyInfo'</c>,
<c>Entity</c> must be either an <c>rsa_public_key()</c>,
<c>dsa_public_key()</c> or an <c>ec_public_key()</c>
and this function creates the appropriate
- 'SubjectPublicKeyInfo' entry.
- </d>
- <v>CipherInfo = cipher_info()</v>
- <v>Password = string()</v>
- </type>
- <desc>
- <p>Creates a PEM entry that can be feed to <c>pem_encode/1</c>.</p>
- </desc>
+ <c>'SubjectPublicKeyInfo'</c> entry.
+ </p>
+ </desc>
</func>
-
+
<func>
- <name>pkix_decode_cert(Cert, otp|plain) -> #'Certificate'{} | #'OTPCertificate'{}</name>
+ <name name="pkix_decode_cert" arity="2" since=""/>
<fsummary>Decodes an ASN.1 DER-encoded PKIX x509 certificate.</fsummary>
- <type>
- <v>Cert = der_encoded()</v>
- </type>
- <desc>
- <p>Decodes an ASN.1 DER-encoded PKIX certificate. Option <c>otp</c>
- uses the customized ASN.1 specification OTP-PKIX.asn1 for
- decoding and also recursively decode most of the standard
- parts.</p>
- </desc>
+ <desc>
+ <p>Decodes an ASN.1 DER-encoded PKIX certificate. Option <c>otp</c>
+ uses the customized ASN.1 specification OTP-PKIX.asn1 for
+ decoding and also recursively decode most of the standard
+ parts.</p>
+ </desc>
</func>
<func>
- <name>pkix_encode(Asn1Type, Entity, otp | plain) -> der_encoded()</name>
+ <name name="pkix_encode" arity="3" since="OTP R14B"/>
<fsummary>DER encodes a PKIX x509 certificate or part of such a
certificate.</fsummary>
- <type>
- <v>Asn1Type = atom()</v>
- <d>The ASN.1 type can be 'Certificate', 'OTPCertificate' or a subtype of either.</d>
- <v>Entity = #'Certificate'{} | #'OTPCertificate'{} | a valid subtype</v>
- </type>
<desc>
<p>DER encodes a PKIX x509 certificate or part of such a
certificate. This function must be used for encoding certificates or parts of certificates
@@ -456,71 +351,49 @@
</func>
<func>
- <name>pkix_is_issuer(Cert, IssuerCert) -> boolean()</name>
- <fsummary>Checks if <c>IssuerCert</c> issued <c>Cert</c>.</fsummary>
- <type>
- <v>Cert = der_encoded() | #'OTPCertificate'{} | #'CertificateList'{}</v>
- <v>IssuerCert = der_encoded() | #'OTPCertificate'{}</v>
- </type>
- <desc>
- <p>Checks if <c>IssuerCert</c> issued <c>Cert</c>.</p>
- </desc>
- </func>
+ <name name="pkix_is_issuer" arity="2" since="OTP R14B"/>
+ <fsummary>Checks if <c>IssuerCert</c> issued <c>Cert</c>.</fsummary>
+ <desc>
+ <p>Checks if <c>IssuerCert</c> issued <c>Cert</c>.</p>
+ </desc>
+ </func>
- <func>
- <name>pkix_is_fixed_dh_cert(Cert) -> boolean()</name>
- <fsummary>Checks if a certificate is a fixed Diffie-Hellman certificate.</fsummary>
- <type>
- <v>Cert = der_encoded() | #'OTPCertificate'{}</v>
- </type>
- <desc>
- <p>Checks if a certificate is a fixed Diffie-Hellman certificate.</p>
- </desc>
- </func>
+ <func>
+ <name name="pkix_is_fixed_dh_cert" arity="1" since="OTP R14B"/>
+ <fsummary>Checks if a certificate is a fixed Diffie-Hellman certificate.</fsummary>
+ <desc>
+ <p>Checks if a certificate is a fixed Diffie-Hellman certificate.</p>
+ </desc>
+ </func>
- <func>
- <name>pkix_is_self_signed(Cert) -> boolean()</name>
- <fsummary>Checks if a certificate is self-signed.</fsummary>
- <type>
- <v>Cert = der_encoded() | #'OTPCertificate'{}</v>
- </type>
- <desc>
- <p>Checks if a certificate is self-signed.</p>
- </desc>
- </func>
+ <func>
+ <name name="pkix_is_self_signed" arity="1" since="OTP R14B"/>
+ <fsummary>Checks if a certificate is self-signed.</fsummary>
+ <desc>
+ <p>Checks if a certificate is self-signed.</p>
+ </desc>
+ </func>
- <func>
- <name>pkix_issuer_id(Cert, IssuedBy) -> {ok, IssuerID} | {error, Reason}</name>
- <fsummary>Returns the issuer id.</fsummary>
- <type>
- <v>Cert = der_encoded() | #'OTPCertificate'{}</v>
- <v>IssuedBy = self | other</v>
- <v>IssuerID = {integer(), issuer_name()}</v>
- <d>The issuer id consists of the serial number and the issuers name.</d>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Returns the issuer id.</p>
- </desc>
- </func>
-
+ <func>
+ <name name="pkix_issuer_id" arity="2" since="OTP R14B"/>
+ <fsummary>Returns the issuer id.</fsummary>
+ <desc>
+ <p>Returns the issuer id.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="pkix_normalize_name" arity="1" since="OTP R14B"/>
+ <fsummary>Normalizes an issuer name so that it can be easily
+ compared to another issuer name.</fsummary>
+ <desc>
+ <p>Normalizes an issuer name so that it can be easily
+ compared to another issuer name.</p>
+ </desc>
+ </func>
+
<func>
- <name>pkix_normalize_name(Issuer) -> Normalized</name>
- <fsummary>Normalizes an issuer name so that it can be easily
- compared to another issuer name.</fsummary>
- <type>
- <v>Issuer = issuer_name()</v>
- <v>Normalized = issuer_name()</v>
- </type>
- <desc>
- <p>Normalizes an issuer name so that it can be easily
- compared to another issuer name.</p>
- </desc>
- </func>
-
- <func>
- <name>pkix_path_validation(TrustedCert, CertChain, Options) -> {ok, {PublicKeyInfo, PolicyTree}} | {error, {bad_cert, Reason}} </name>
+ <name since="OTP R16B">pkix_path_validation(TrustedCert, CertChain, Options) -> {ok, {PublicKeyInfo, PolicyTree}} | {error, {bad_cert, Reason}} </name>
<fsummary>Performs a basic path validation according to RFC 5280.</fsummary>
<type>
<v>TrustedCert = #'OTPCertificate'{} | der_encoded() | atom()</v>
@@ -552,7 +425,7 @@
<p>Available options:</p>
<taglist>
- <tag>{verify_fun, fun()}</tag>
+ <tag>{verify_fun, {fun(), InitialUserState::term()}</tag>
<item>
<p>The fun must be defined as:</p>
@@ -620,26 +493,16 @@ fun(OtpCert :: #'OTPCertificate'{},
</func>
<func>
- <name>pkix_crl_issuer(CRL) -> issuer_name()</name>
+ <name name="pkix_crl_issuer" arity="1" since="OTP 17.5"/>
<fsummary>Returns the issuer of the <c>CRL</c>.</fsummary>
- <type>
- <v>CRL = der_encoded() | #'CertificateList'{} </v>
- </type>
<desc>
<p>Returns the issuer of the <c>CRL</c>.</p>
</desc>
</func>
<func>
- <name>pkix_crls_validate(OTPCertificate, DPAndCRLs, Options) -> CRLStatus()</name>
+ <name name="pkix_crls_validate" arity="3" since="OTP R16B"/>
<fsummary>Performs CRL validation.</fsummary>
- <type>
- <v>OTPCertificate = #'OTPCertificate'{}</v>
- <v>DPAndCRLs = [{DP::#'DistributionPoint'{}, {DerCRL::der_encoded(), CRL::#'CertificateList'{}}}] </v>
- <v>Options = proplists:proplist()</v>
- <v>CRLStatus() = valid | {bad_cert, revocation_status_undetermined} | {bad_cert, {revocation_status_undetermined,
- {bad_crls, Details::term()}}} | {bad_cert, {revoked, crl_reason()}}</v>
- </type>
<desc>
<p>Performs CRL validation. It is intended to be called from
the verify fun of <seealso marker="#pkix_path_validation-3"> pkix_path_validation/3
@@ -680,7 +543,7 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
<tag>{undetermined_details, boolean()}</tag>
<item>
- <p>Defaults to false. When revocation status can not be
+ <p>Defaults to false. When revocation status cannot be
determined, and this option is set to true, details of why no
CRLs where accepted are included in the return value.</p>
</item>
@@ -690,24 +553,16 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
</func>
<func>
- <name>pkix_crl_verify(CRL, Cert) -> boolean()</name>
+ <name name="pkix_crl_verify" arity="2" since="OTP 17.5"/>
<fsummary> Verify that <c>Cert</c> is the <c> CRL</c> signer. </fsummary>
- <type>
- <v>CRL = der_encoded() | #'CertificateList'{} </v>
- <v>Cert = der_encoded() | #'OTPCertificate'{} </v>
- </type>
<desc>
<p>Verify that <c>Cert</c> is the <c>CRL</c> signer.</p>
</desc>
</func>
<func>
- <name>pkix_dist_point(Cert) -> DistPoint</name>
+ <name name="pkix_dist_point" arity="1" since="OTP 17.5"/>
<fsummary>Creates a distribution point for CRLs issued by the same issuer as <c>Cert</c>.</fsummary>
- <type>
- <v> Cert = der_encoded() | #'OTPCertificate'{} </v>
- <v> DistPoint = #'DistributionPoint'{}</v>
- </type>
<desc>
<p>Creates a distribution point for CRLs issued by the same issuer as <c>Cert</c>.
Can be used as input to <seealso
@@ -717,26 +572,17 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
</func>
<func>
- <name>pkix_dist_points(Cert) -> DistPoints</name>
+ <name name="pkix_dist_points" arity="1" since="OTP 17.5"/>
<fsummary> Extracts distribution points from the certificates extensions.</fsummary>
- <type>
- <v> Cert = der_encoded() | #'OTPCertificate'{} </v>
- <v> DistPoints = [#'DistributionPoint'{}]</v>
- </type>
<desc>
<p> Extracts distribution points from the certificates extensions.</p>
</desc>
</func>
<func>
- <name>pkix_match_dist_point(CRL, DistPoint) -> boolean()</name>
+ <name name="pkix_match_dist_point" arity="2" since="OTP 19.0"/>
<fsummary>Checks whether the given distribution point matches the
Issuing Distribution Point of the CRL.</fsummary>
-
- <type>
- <v>CRL = der_encoded() | #'CertificateList'{} </v>
- <v>DistPoint = #'DistributionPoint'{}</v>
- </type>
<desc>
<p>Checks whether the given distribution point matches the
Issuing Distribution Point of the CRL, as described in RFC 5280.
@@ -746,11 +592,8 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
</func>
<func>
- <name>pkix_sign(#'OTPTBSCertificate'{}, Key) -> der_encoded()</name>
+ <name name="pkix_sign" arity="2" since="OTP R14B"/>
<fsummary>Signs certificate.</fsummary>
- <type>
- <v>Key = rsa_private_key() | dsa_private_key()</v>
- </type>
<desc>
<p>Signs an 'OTPTBSCertificate'. Returns the corresponding
DER-encoded certificate.</p>
@@ -758,23 +601,18 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
</func>
<func>
- <name>pkix_sign_types(AlgorithmId) -> {DigestType, SignatureType}</name>
+ <name name="pkix_sign_types" arity="1" since="OTP R16B01"/>
<fsummary>Translates signature algorithm OID to Erlang digest and signature algorithm types.</fsummary>
- <type>
- <v>AlgorithmId = oid()</v>
- <d>Signature OID from a certificate or a certificate revocation list.</d>
- <v>DigestType = rsa_digest_type() | dss_digest_type()</v>
- <v>SignatureType = rsa | dsa | ecdsa</v>
- </type>
<desc>
<p>Translates signature algorithm OID to Erlang digest and signature types.
</p>
+ <p>The <c>AlgorithmId</c> is the signature OID from a certificate or a certificate revocation list.</p>
</desc>
</func>
<func>
- <name>pkix_test_data(Options) -> Config </name>
- <name>pkix_test_data([chain_opts()]) -> [conf_opt()]</name>
+ <name since="OTP 20.1">pkix_test_data(Options) -> Config </name>
+ <name since="OTP 20.1">pkix_test_data([chain_opts()]) -> [conf_opt()]</name>
<fsummary>Creates certificate test data.</fsummary>
<type>
<v>Options = #{chain_type() := chain_opts()} </v>
@@ -808,7 +646,7 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
<v>conf_opt() = {cert, der_encoded()} | {key, PrivateKey} |{cacerts, [der_encoded()]}</v>
<d>
This is a subset of the type
- <seealso marker="ssl:ssl#type-ssloption"> ssl:ssl_option()</seealso>.
+ <seealso marker="ssl:ssl#type-tls_option"> ssl:tls_option()</seealso>.
<c>PrivateKey</c> is what
<seealso marker="#generate_key-1">generate_key/1</seealso>
returns.
@@ -900,13 +738,13 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
<note><p>
Note that the generated certificates and keys does not provide a formally correct PKIX-trust-chain
- and they can not be used to achieve real security. This function is provided for testing purposes only.
+ and they cannot be used to achieve real security. This function is provided for testing purposes only.
</p></note>
</desc>
</func>
<func>
- <name>pkix_test_root_cert(Name, Options) -> RootCert</name>
+ <name since="OTP 20.2">pkix_test_root_cert(Name, Options) -> RootCert</name>
<fsummary>Generates a test data root cert.</fsummary>
<type>
<v>Name = string()</v>
@@ -936,20 +774,16 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
</func>
<func>
- <name>pkix_verify(Cert, Key) -> boolean()</name>
+ <name name="pkix_verify" arity="2" since="OTP R14B"/>
<fsummary>Verifies PKIX x.509 certificate signature.</fsummary>
- <type>
- <v>Cert = der_encoded()</v>
- <v>Key = rsa_public_key() | dsa_public_key() | ec_public_key()</v>
- </type>
<desc>
<p>Verifies PKIX x.509 certificate signature.</p>
</desc>
</func>
<func>
- <name>pkix_verify_hostname(Cert, ReferenceIDs) -> boolean()</name>
- <name>pkix_verify_hostname(Cert, ReferenceIDs, Opts) -> boolean()</name>
+ <name since="OTP 19.3">pkix_verify_hostname(Cert, ReferenceIDs) -> boolean()</name>
+ <name since="OTP 19.3">pkix_verify_hostname(Cert, ReferenceIDs, Opts) -> boolean()</name>
<fsummary>Verifies that a PKIX x.509 certificate <i>presented identifier</i> (e.g hostname) is
an expected one.</fsummary>
<type>
@@ -967,62 +801,121 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
</type>
<desc>
<p>This function checks that the <i>Presented Identifier</i> (e.g hostname) in a peer certificate
- is in agreement with the <i>Reference Identifier</i> that the client expects to be connected to.
+ is in agreement with at least one of the <i>Reference Identifier</i> that the client expects to be connected to.
The function is intended to be added as an extra client check of the peer certificate when performing
<seealso marker="public_key:public_key#pkix_path_validation-3">public_key:pkix_path_validation/3</seealso>
</p>
<p>See <url href="https://tools.ietf.org/html/rfc6125">RFC 6125</url>
for detailed information about hostname verification.
- The <seealso marker="using_public_key#verify_hostname">User's Manual</seealso>
+ The <seealso marker="using_public_key#verify_hostname">User's Guide</seealso>
and
<seealso marker="using_public_key#verify_hostname_examples">code examples</seealso>
describes this function more detailed.
</p>
<p>The <c>{OtherRefId,term()}</c> is defined by the user and is passed to the <c>match_fun</c>, if defined.
- If that term is a binary, it will be converted to a string.
+ If the term in <c>OtherRefId</c> is a binary, it will be converted to a string.
</p>
- <p>The <c>ip</c> Reference ID takes an <seealso marker="inet:inet#type-ip_address">inet:ip_address()</seealso>
+ <p>The <c>ip</c> Reference ID takes an
+ <seealso marker="kernel:inet#type-ip_address">inet:ip_address()</seealso>
or an ip address in string format (E.g "10.0.1.1" or "1234::5678:9012") as second element.
</p>
+ <p>The options are:</p>
+ <taglist>
+ <tag><c>match_fun</c></tag>
+ <item>
+ The <c>fun/2</c> in this option replaces the default host name matching rules. The fun should return a
+ boolean to tell if the Reference ID and Presented ID matches or not. The fun can also return a third
+ value, the atom <c>default</c>, if the default matching rules shall apply.
+ This makes it possible to augment the tests with a special case:
+ <code>
+fun(....) -> true; % My special case
+ (_, _) -> default % all others falls back to the inherit tests
+end
+ </code>
+ <br/>See <seealso marker="#pkix_verify_hostname_match_fun-1">pkix_verify_hostname_match_fun/1</seealso> for a
+ function that takes a protocol name as argument and returns a <c>fun/2</c> suitable for this option and
+ <seealso marker="using_public_key#redefining_match_op">Re-defining the match operation</seealso>
+ in the User's Guide for an example.
+ </item>
+
+ <tag><c>fail_callback</c></tag>
+ <item>If a matching fails, there could be circumstances when the certificate should be accepted anyway. Think for
+ example of a web browser where you choose to accept an outdated certificate. This option enables implementation
+ of such a function. This <c>fun/1</c> is called when no <c>ReferenceID</c> matches. The return value of the fun
+ (a <c>boolean()</c>) decides the outcome. If <c>true</c> the the certificate is accepted otherwise
+ it is rejected. See
+ <seealso marker="using_public_key#-pinning--a-certificate">"Pinning" a Certificate</seealso>
+ in the User's Guide.
+ </item>
+
+ <tag><c>fqdn_fun</c></tag>
+ <item>This option augments the host name extraction from URIs and other Reference IDs. It could for example be
+ a very special URI that is not standardised. The fun takes a Reference ID as argument and returns one of:
+ <list>
+ <item>the hostname</item>
+ <item>the atom <c>default</c>: the default host name extract function will be used</item>
+ <item>the atom <c>undefined</c>: a host name could not be extracted. The pkix_verify_hostname/3
+ will return <c>false</c>.</item>
+ </list>
+ <br/>For an example, see
+ <seealso marker="using_public_key#hostname_extraction">Hostname extraction</seealso>
+ in the User's Guide.
+ </item>
+ </taglist>
+
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0">pkix_verify_hostname_match_fun(Protcol) -> fun(RefId | FQDN::string(), PresentedID) -> boolean() | default</name>
+ <fsummary>Returns a fun that is intendended as argument to the match_fun option in pkix_verify_hostname/3.
+ </fsummary>
+ <type>
+ <v>Protocol = https</v>
+ <d>The algorithm for wich the fun should implement the special matching rules</d>
+ <v>RefId</v>
+ <d>See <seealso marker="#pkix_verify_hostname-3">pkix_verify_hostname/3</seealso>.</d>
+ <v>FQDN</v>
+ <d>See <seealso marker="#pkix_verify_hostname-3">pkix_verify_hostname/3</seealso>.</d>
+ <v>PresentedID</v>
+ <d>See <seealso marker="#pkix_verify_hostname-3">pkix_verify_hostname/3</seealso>.</d>
+ </type>
+ <desc>
+ <p>The return value of calling this function is intended to be used in the <c>match_fun</c> option in
+ <seealso marker="#pkix_verify_hostname-3">pkix_verify_hostname/3</seealso>.
+ </p>
+ <p>The returned fun augments the verify hostname matching according to the specific rules for
+ the protocol in the argument.
+ </p>
</desc>
</func>
+
<func>
- <name>sign(Msg, DigestType, Key) -> binary()</name>
- <name>sign(Msg, DigestType, Key, Options) -> binary()</name>
+ <name name="sign" arity="3" since=""/>
+ <name name="sign" arity="4" since="OTP 20.1"/>
<fsummary>Creates a digital signature.</fsummary>
- <type>
- <v>Msg = binary() | {digest,binary()}</v>
- <d>The <c>Msg</c> is either the binary "plain text" data to be
- signed or it is the hashed value of "plain text", that is, the
- digest.</d>
- <v>DigestType = rsa_digest_type() | dss_digest_type() | ecdsa_digest_type()</v>
- <v>Key = rsa_private_key() | dsa_private_key() | ec_private_key()</v>
- <v>Options = public_sign_options()</v>
- </type>
<desc>
<p>Creates a digital signature.</p>
+ <p>The <c>Msg</c> is either the binary "plain text" data to be
+ signed or it is the hashed value of "plain text", that is, the
+ digest.</p>
</desc>
</func>
<func>
- <name>ssh_decode(SshBin, Type) -> [{public_key(), Attributes::list()}]</name>
+ <name name="ssh_decode" arity="2" since="OTP R14B03"/>
<fsummary>Decodes an SSH file-binary.</fsummary>
- <type>
- <v>SshBin = binary()</v>
- <d>Example <c>{ok, SshBin} = file:read_file("known_hosts")</c>.</d>
- <v>Type = public_key | ssh_file()</v>
- <d>If <c>Type</c> is <c>public_key</c> the binary can be either
- an RFC4716 public key or an OpenSSH public key.</d>
- </type>
- <desc>
- <p>Decodes an SSH file-binary. In the case of <c>known_hosts</c> or
- <c>auth_keys</c>, the binary can include one or more lines of the
- file. Returns a list of public keys and their attributes, possible
- attribute values depends on the file type represented by the
- binary.
- </p>
-
+ <desc>
+ <p>Decodes an SSH file-binary. In the case of <c>known_hosts</c> or
+ <c>auth_keys</c>, the binary can include one or more lines of the
+ file. Returns a list of public keys and their attributes, possible
+ attribute values depends on the file type represented by the
+ binary.
+ </p>
+ <p>If the <c>Type</c> is <c>ssh2_pubkey</c>, the result will be
+ <c>Decoded_ssh2_pubkey</c>. Otherwise it will be <c>Decoded_OtherType</c>.
+ </p>
<taglist>
<tag>RFC4716 attributes - see RFC 4716.</tag>
<item><p>{headers, [{string(), utf8_string()}]}</p></item>
@@ -1035,33 +928,35 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
<item>{comment, string()}</item>
<item><p>{bits, integer()} - In SSH version 1 files.</p></item>
</taglist>
-
+ <p>Example: <c>{ok, SshBin} = file:read_file("known_hosts")</c>.
+ </p>
+ <p>If <c>Type</c> is <c>public_key</c> the binary can be either
+ an RFC4716 public key or an OpenSSH public key.</p>
</desc>
</func>
<func>
- <name>ssh_encode([{Key, Attributes}], Type) -> binary()</name>
+ <name name="ssh_encode" arity="2" since="OTP R14B03"/>
<fsummary>Encodes a list of SSH file entries to a binary.</fsummary>
- <type>
- <v>Key = public_key()</v>
- <v>Attributes = list()</v>
- <v>Type = ssh_file()</v>
- </type>
- <desc>
- <p>Encodes a list of SSH file entries (public keys and attributes) to a binary. Possible
- attributes depend on the file type, see <seealso
- marker="#ssh_decode-2"> ssh_decode/2 </seealso>.</p>
- </desc>
+ <desc>
+ <p>Encodes a list of SSH file entries (public keys and attributes) to a binary. Possible
+ attributes depend on the file type, see
+ <seealso marker="#ssh_decode-2"> ssh_decode/2 </seealso>.
+ </p>
+ <p>If the <c>Type</c> is <c>ssh2_pubkey</c>, the <c>InData</c> shall be
+ <c>InData_ssh2_pubkey</c>. Otherwise it shall be <c>OtherInData</c>.
+ </p>
+ </desc>
</func>
<func>
- <name>ssh_hostkey_fingerprint(HostKey) -> string()</name>
- <name>ssh_hostkey_fingerprint(DigestType, HostKey) -> string()</name>
- <name>ssh_hostkey_fingerprint([DigestType], HostKey) -> [string()]</name>
+ <name since="OTP 19.2">ssh_hostkey_fingerprint(HostKey) -> string()</name>
+ <name since="OTP 19.2">ssh_hostkey_fingerprint(DigestType, HostKey) -> string()</name>
+ <name since="OTP 19.2">ssh_hostkey_fingerprint([DigestType], HostKey) -> [string()]</name>
<fsummary>Calculates a ssh fingerprint for a hostkey.</fsummary>
<type>
- <v>Key = public_key()</v>
- <v>DigestType = digest_type()</v>
+ <v>HostKey = <seealso marker="#type-public_key">public_key()</seealso></v>
+ <v>DigestType = <seealso marker="#type-digest_type">digest_type()</seealso></v>
</type>
<desc>
<p>Calculates a ssh fingerprint from a public host key as openssh does.</p>
@@ -1090,29 +985,19 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
</func>
<func>
- <name>verify(Msg, DigestType, Signature, Key) -> boolean()</name>
- <name>verify(Msg, DigestType, Signature, Key, Options) -> boolean()</name>
+ <name name="verify" arity="4" since="OTP R14B"/>
+ <name name="verify" arity="5" since="OTP 20.1"/>
<fsummary>Verifies a digital signature.</fsummary>
- <type>
- <v>Msg = binary() | {digest,binary()}</v>
- <d>The <c>Msg</c> is either the binary "plain text" data
- or it is the hashed value of "plain text", that is, the digest.</d>
- <v>DigestType = rsa_digest_type() | dss_digest_type() | ecdsa_digest_type()</v>
- <v>Signature = binary()</v>
- <v>Key = rsa_public_key() | dsa_public_key() | ec_public_key()</v>
- <v>Options = public_sign_options()</v>
- </type>
<desc>
<p>Verifies a digital signature.</p>
+ <p>The <c>Msg</c> is either the binary "plain text" data
+ or it is the hashed value of "plain text", that is, the digest.</p>
</desc>
</func>
<func>
- <name>short_name_hash(Name) -> string()</name>
+ <name name="short_name_hash" arity="1" since="OTP 19.0"/>
<fsummary>Generates a short hash of an issuer name.</fsummary>
- <type>
- <v>Name = issuer_name()</v>
- </type>
<desc>
<p>Generates a short hash of an issuer name. The hash is
returned as a string containing eight hexadecimal digits.</p>
diff --git a/lib/public_key/doc/src/public_key_records.xml b/lib/public_key/doc/src/public_key_records.xml
index 9ebdbb244d..d26867c12f 100644
--- a/lib/public_key/doc/src/public_key_records.xml
+++ b/lib/public_key/doc/src/public_key_records.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2008</year>
- <year>2015</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
diff --git a/lib/public_key/doc/src/specs.xml b/lib/public_key/doc/src/specs.xml
new file mode 100644
index 0000000000..e358ea1154
--- /dev/null
+++ b/lib/public_key/doc/src/specs.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<specs xmlns:xi="http://www.w3.org/2001/XInclude">
+ <xi:include href="../specs/specs_public_key.xml"/>
+</specs>
diff --git a/lib/public_key/doc/src/using_public_key.xml b/lib/public_key/doc/src/using_public_key.xml
index 417d479da3..de0a6596c3 100644
--- a/lib/public_key/doc/src/using_public_key.xml
+++ b/lib/public_key/doc/src/using_public_key.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2011</year><year>2016</year>
+ <year>2011</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -570,6 +570,7 @@ true = public_key:verify(Digest, none, Signature, PublicKey),</code>
<c>fqdn_fun</c> and <c>match_fun</c>.
</p>
<section>
+ <marker id="hostname_extraction"></marker>
<title>Hostname extraction</title>
<p>The <c>fqdn_fun</c> extracts hostnames (Fully Qualified Domain Names) from uri_id
or other ReferenceIDs that are not pre-defined in the public_key function.
@@ -595,7 +596,8 @@ true = public_key:verify(Digest, none, Signature, PublicKey),</code>
</code>
</section>
<section>
- <title>Re-defining the match operations</title>
+ <marker id="redefining_match_op"></marker>
+ <title>Re-defining the match operation</title>
<p>The default matching handles dns_id and uri_id. In an uri_id the value is tested for
equality with a value from the <c>Subject Alternate Name</c>. If som other kind of matching
is needed, use the <c>match_fun</c> option.
diff --git a/lib/public_key/include/public_key.hrl b/lib/public_key/include/public_key.hrl
index 663e1856ac..98d032bfdd 100644
--- a/lib/public_key/include/public_key.hrl
+++ b/lib/public_key/include/public_key.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/public_key/priv/moduli b/lib/public_key/priv/moduli
index 446f4b8bf4..83e8767a5e 100644
--- a/lib/public_key/priv/moduli
+++ b/lib/public_key/priv/moduli
@@ -1,193 +1,240 @@
-20151021104105 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D182EB7
-20151021104106 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D27F94F
-20151021104107 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D398EB7
-20151021104108 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D4B850F
-20151021104108 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D4BF35B
-20151021104108 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D5031DF
-20151021104109 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D5A4933
-20151021104110 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D6434BF
-20151021104111 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D70676B
-20151021104111 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D7235E3
-20151021104113 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D963493
-20151021104114 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9DAABAA7
-20151021104115 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9DC2E333
-20151021104116 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9DE16A7B
-20151021104117 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9DE2C5D3
-20151021104118 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9DFF382F
-20151021104119 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9E158F13
-20151021104122 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9E4D9FEB
-20151021104123 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9E5C1FDB
-20151021104126 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9E9BB69B
-20151021104126 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9E9F62D3
-20151021104127 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9EAA1C27
-20151021104128 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9EBC3313
-20151021104129 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9EC0733B
-20151021104130 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9EDB7AD3
-20151021104132 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9EF56457
-20151021104132 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9EF5A9CF
-20151021104133 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9F13CBB3
-20151021104218 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17BAAFFDF
-20151021104222 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17BCB6D93
-20151021104225 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17BE660BB
-20151021104226 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17BE676C3
-20151021104229 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17BF3E23B
-20151021104230 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17BF95757
-20151021104241 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17C59BEA7
-20151021104242 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17C6231B3
-20151021104244 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17C6879BF
-20151021104250 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17C9B678F
-20151021104252 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17CA66A4B
-20151021104253 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17CAB5543
-20151021104256 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17CB96933
-20151021104300 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17CDA8493
-20151021104308 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17D18C0C7
-20151021104310 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17D1DA5BF
-20151021104318 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17D4AB15F
-20151021104325 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17D7DE42F
-20151021104329 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17DA03D3B
-20151021104335 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17DD88BFF
-20151021104338 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17DE82B5F
-20151021104342 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17E07AF43
-20151021104343 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17E091E6F
-20151021104346 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17E28B90F
-20151021104347 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17E2A24F3
-20151021104401 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17EB074A7
-20151021104403 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17EC01B0F
-20151021104406 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17ED2186F
-20151021104407 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17ED55AAB
-20151021104411 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17EF58773
-20151021104414 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17F0B3267
-20151021104423 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17F4DF61B
-20151021104434 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17F9BBB0B
-20151021104442 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17FDD6AFB
-20151021104350 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE5E381EF
-20151021104414 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE641C193
-20151021104422 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE659F523
-20151021104427 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE660E217
-20151021104438 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE6842F73
-20151021104441 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE689683B
-20151021104455 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE6C41E3B
-20151021104512 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE71E3BFF
-20151021104525 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE75C804F
-20151021104527 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE75DC48B
-20151021104535 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE7738983
-20151021104543 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE787027B
-20151021104610 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE8075A1B
-20151021104625 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE84F79B3
-20151021104628 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE859F617
-20151021104641 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE8948E2F
-20151021104646 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE8A571B3
-20151021104659 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE8CEA637
-20151021104705 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE8E590FF
-20151021104707 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE8E7943F
-20151021104731 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE95A975F
-20151021104741 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE985F923
-20151021104745 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE996E20B
-20151021104806 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE9FACFD7
-20151021104827 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BEA562C43
-20151021104839 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BEA8F25E3
-20151021104939 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BEBB1DA0B
-20151021104941 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BEBB86153
-20151021105002 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BEC1B8883
-20151021105019 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BEC71316F
-20151021105035 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BECB1D113
-20151021105042 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BECC3F3AB
-20151021105045 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BECCC109B
-20151021105101 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BED16353B
-20151021105106 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BED24854F
-20151021105109 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BED2AE4B3
-20151021105116 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BED472CF7
-20151021104612 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E360CD0C3
-20151021104628 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3620FBE7
-20151021104701 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E36490F57
-20151021105014 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E377ACADB
-20151021105125 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E37E6DE07
-20151021105320 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E38C2387F
-20151021105649 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3A61E46B
-20151021105815 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3B0A6A4B
-20151021105848 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3B47D2C3
-20151021105948 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3BBBB953
-20151021110011 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3BE3B83B
-20151021110036 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3C0A3F1B
-20151021110201 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3CB1970F
-20151021110208 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3CB70C2B
-20151021110235 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3CE4E4DF
-20151021110424 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3DB68CD7
-20151021110525 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3E290717
-20151021110655 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3ED6DA83
-20151021110731 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3F14C563
-20151021110831 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3F85477F
-20151021111418 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E420DE56B
-20151021111430 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E421DBA2F
-20151021111624 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E42F39A93
-20151021111916 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E44302363
-20151021112222 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E4585795F
-20151021112245 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E45A1DAFF
-20151021112339 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E4601674F
-20151021112437 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E46691977
-20151021112521 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E46AF3AD3
-20151021112532 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E46BCAE97
-20151021112708 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E476520D3
-20151021112724 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E477B3317
-20151021105143 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156BA7321EB
-20151021105537 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156BB3AF34B
-20151021105816 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156BBC51883
-20151021110444 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156BD1A86C7
-20151021111341 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156BEDB7BBB
-20151021111438 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156BF0297AB
-20151021111935 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156BFF381FF
-20151021113820 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C433A1BF
-20151021113833 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C43B426B
-20151021113900 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C45007D3
-20151021113921 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C45D8C3B
-20151021113941 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C4685D5F
-20151021114203 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C4F95D97
-20151021114417 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C57ED2FF
-20151021114645 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C612EC33
-20151021114825 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C67219F7
-20151021114922 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C6A942BB
-20151021115945 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C91E14DB
-20151021120515 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CA5F5DB3
-20151021120715 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CAD0D497
-20151021121027 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CB8F9D6F
-20151021121241 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CC0F677F
-20151021121518 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CC9CC647
-20151021121600 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CCC0ADC3
-20151021121734 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CD1BC68B
-20151021121759 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CD2A7DBF
-20151021122003 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CDA3D323
-20151021122542 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CED8D107
-20151021122856 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CF8DFEE7
-20151021123548 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156D11CAC4F
-20151021123633 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156D1426BBB
-20151021124201 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156D2A62F0B
-20151021124454 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156D353F0FB
-20151021124620 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156D3AE526F
-20151021125224 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156D535C4CB
-20151021130254 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156D7B5CA43
-20151021111833 2 6 100 6143 5 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B239959D5A7
-20151021112931 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B239A078C1B
-20151021123021 2 6 100 6143 5 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B239EC676DF
-20151021131523 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23A2B9FC6B
-20151021141029 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23A7BD762B
-20151021143421 2 6 100 6143 5 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23A9C3EFDF
-20151021144912 2 6 100 6143 5 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23AB1077AF
-20151021145200 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23AB49943B
-20151021145825 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23ABE06353
-20151021150910 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23ACDA0223
-20151021153131 2 6 100 6143 5 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23AE91738F
-20151021154038 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23AF40D013
-20151021154300 2 6 100 6143 5 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23AF75AD97
-20151021155008 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23B01C9553
-20151021162240 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23B319431B
-20151021162649 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23B35A3D2B
-20151021163640 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23B439E263
-20151021171004 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23B748B983
-20151021172144 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23B8609B5B
-20151021173002 2 6 100 6143 5 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23B9021E9F
-20151021182612 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23BE0C1EDB
-20151021190053 2 6 100 6143 5 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23C120FF97
-20151021192934 2 6 100 6143 5 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23C3BEB637
+20180605163926 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E3790983687163B
+20180605163926 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E379098369B52F3
+20180605163926 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E379098369DE513
+20180605163927 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909836B52273
+20180605163928 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909836C20313
+20180605163928 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909836C9430B
+20180605163929 2 6 100 1023 5 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909836DA8707
+20180605163929 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909836F54DB3
+20180605163930 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E3790983717A4D3
+20180605163931 2 6 100 1023 5 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E379098372B4C9F
+20180605163931 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E379098372F90F3
+20180605163932 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E3790983730E783
+20180605163932 2 6 100 1023 5 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E379098373292DF
+20180605163932 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909837356303
+20180605163933 2 6 100 1023 5 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E3790983743AE7F
+20180605163933 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E379098375E7EEB
+20180605163934 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E379098376750E3
+20180605163934 2 6 100 1023 5 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E379098376EC6E7
+20180605163936 2 6 100 1023 5 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909837A659EF
+20180605163936 2 6 100 1023 5 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909837AD4BE7
+20180605163937 2 6 100 1023 5 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909837B64E27
+20180605163937 2 6 100 1023 5 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909837CB4A7F
+20180605163938 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909837DDDCB3
+20180605163939 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909837FC35C3
+20180605163939 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909837FE3CDB
+20180605163939 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E379098380C0B83
+20180605163940 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909838128533
+20180605163941 2 6 100 1023 5 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E379098383338D7
+20180605163941 2 6 100 1023 5 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909838450DFF
+20180605163942 2 6 100 1023 5 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909838487D47
+20180605163942 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E379098384CCA3B
+20180605163943 2 6 100 1023 5 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909838664DEF
+20180605164241 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC0FCBFECB
+20180605164243 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC0FDD64C3
+20180605164247 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC100666A7
+20180605164250 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC1030926F
+20180605164251 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC1032D8C3
+20180605164256 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC1072924B
+20180605164259 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC1090839F
+20180605164301 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC10A234EB
+20180605164306 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC10DFDBF7
+20180605164309 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC10FA17CB
+20180605164310 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC10FE87E7
+20180605164315 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC11409597
+20180605164318 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC116159DF
+20180605164324 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC11AC1B33
+20180605164327 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC11CA3F3F
+20180605164329 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC11DC7E7B
+20180605164333 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC120452BB
+20180605164335 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC121AA82B
+20180605164336 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC12227373
+20180605164339 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC12408E5B
+20180605164343 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC126E985F
+20180605164343 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC1272F6F3
+20180605164345 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC1279FD67
+20180605164346 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC127EDDEB
+20180605164348 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC129DA56B
+20180605164351 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC12BB0F0B
+20180605164353 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC12CF73D7
+20180605164357 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC12FD603B
+20180605164359 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC13089AEF
+20180605164400 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC131627D3
+20180605164406 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC13547C4F
+20180605164412 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC139D9763
+20180605164412 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC13A041BF
+20180605164416 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC13CDD8EB
+20180605164419 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC13ED0BF3
+20180605164420 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC13EDD913
+20180605164421 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC13F9C1AF
+20180605164423 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC14000907
+20180605164424 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC14109807
+20180605164425 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC141232B3
+20180605164426 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC14128AC7
+20180605164426 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC1413D4C7
+20180605164429 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC1427B407
+20180605162024 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820A9B6DBF
+20180605162030 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820AB71C5B
+20180605162033 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820ABF82EF
+20180605162036 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820AC82523
+20180605162048 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820B08B40B
+20180605162113 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820B8A5FA7
+20180605162125 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820BC6A33F
+20180605162128 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820BD10B4B
+20180605162138 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820C01495B
+20180605162215 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820CD1DE2B
+20180605162227 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820D0FD0D3
+20180605162248 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820D7E119F
+20180605162307 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820DE78837
+20180605162313 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820E00124F
+20180605162328 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820E52028B
+20180605162338 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820E83722F
+20180605162405 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820F1A3AE7
+20180605162413 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820F3F4EFF
+20180605162422 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820F6C4983
+20180605162445 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820FE667F3
+20180605162448 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820FF1635F
+20180605162455 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA8210101C4B
+20180605162459 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA82102130B3
+20180605162503 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA821032FD0B
+20180605162512 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA821061CB83
+20180605162520 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA8210880823
+20180605162522 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA82108C26F7
+20180605162526 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA82109CB12F
+20180605162533 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA8210BB232F
+20180605162535 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA8210BC312F
+20180605162559 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA82114266EB
+20180605162617 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA8211A7EF93
+20180605162620 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA8211B1F463
+20180605162622 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA8211B2B8CB
+20180605165041 2 6 100 3071 5 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A5935413C2A47
+20180605165123 2 6 100 3071 5 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A5935418152F7
+20180605165153 2 6 100 3071 5 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A593541B11757
+20180605165207 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A593541C320AB
+20180605165355 2 6 100 3071 5 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A5935428684D7
+20180605165613 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A5935437F2AFB
+20180605165641 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A593543A9D4DB
+20180605165800 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A5935442F850B
+20180605165954 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A593544F97433
+20180605170035 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A5935453BD0D3
+20180605170132 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A5935459D2583
+20180605170224 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A593545EFFA8B
+20180605170257 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A59354623E5C3
+20180605170321 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A5935464932C3
+20180605171004 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A5935492771BB
+20180605171050 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A593549763053
+20180605171111 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A59354994174B
+20180605171124 2 6 100 3071 5 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A593549A3E147
+20180605171332 2 6 100 3071 5 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A59354A88895F
+20180605171340 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A59354A8E5173
+20180605171346 2 6 100 3071 5 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A59354A903D4F
+20180605171418 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A59354AC3192B
+20180605171917 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A59354CE17653
+20180605172016 2 6 100 3071 5 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A59354D459DC7
+20180605172106 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A59354D9A8CE3
+20180605172258 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A59354E6015A3
+20180605172334 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A59354E99359B
+20180605172635 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A59354FDAF763
+20180605173053 2 6 100 3071 5 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A593551AB6C67
+20180605173245 2 6 100 3071 5 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A5935527032B7
+20180605173251 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A59355272787B
+20180605173312 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A5935529301CB
+20180605173342 2 6 100 3071 5 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A593552C1A7E7
+20180605174443 2 6 100 4095 5 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F71BB9EBA7
+20180605175218 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F71D2678A3
+20180605175425 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F71D861ED3
+20180605175901 2 6 100 4095 5 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F71E5FB7CF
+20180605180343 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F71F3B10EB
+20180605180359 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F71F3EFC3B
+20180605181956 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F7224AFBAB
+20180605182309 2 6 100 4095 5 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F722DFE397
+20180605182606 2 6 100 4095 5 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F723682E0F
+20180605183001 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F7241C6B53
+20180605183144 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F72468A833
+20180605183823 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F725A5A94B
+20180605184629 2 6 100 4095 5 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F7271E9047
+20180605184939 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F727B4FF23
+20180605190534 2 6 100 4095 5 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F72AAFF2BF
+20180605190753 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F72B14D523
+20180605191340 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F72C1ED923
+20180605191639 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F72CA9B123
+20180605193155 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F72F768B5B
+20180605193341 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F72FC32ECB
+20180605194146 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F73137091B
+20180605194618 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F7320594AB
+20180605194826 2 6 100 4095 5 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F7326065DF
+20180605194913 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F7327A7273
+20180605195719 2 6 100 4095 5 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F733F6EE4F
+20180605200053 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F7349A133B
+20180605200209 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F734CDA683
+20180605200404 2 6 100 4095 5 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F73524AC77
+20180605200812 2 6 100 4095 5 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F735E21A27
+20180605201507 2 6 100 4095 5 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F737264DFF
+20180605201935 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F737F47113
+20180605202538 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F7390F0743
+20180606081635 2 6 100 6143 5 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A3819B8FC5F
+20180606083850 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A381B1D13EB
+20180606084353 2 6 100 6143 5 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A381B65B5F7
+20180606090554 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A381CB9AFDB
+20180606092723 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A381E06BDBB
+20180606093241 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A381E51ADE3
+20180606101118 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A3820AE5D83
+20180606101425 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A3820D4A8DB
+20180606103024 2 6 100 6143 5 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A3821C99D9F
+20180606115838 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A3827308863
+20180606121641 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A38284780CB
+20180606121947 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A38286F57DB
+20180606131248 2 6 100 6143 5 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A382B9CA287
+20180606135001 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A382DD37563
+20180606140647 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A382ECDF72B
+20180606143527 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A383086B0F3
+20180606152011 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A38333510EB
+20180606153449 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A3834099ED3
+20180606154730 2 6 100 6143 5 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A3834C6C2F7
+20180606155117 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A3834F7FF83
+20180606191134 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A3840D756E3
+20180606201246 2 6 100 6143 5 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A38446BC09F
+20180606211911 2 6 100 6143 5 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A384849597F
+20180606223301 2 6 100 6143 5 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A384C9296DF
+20180606230821 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A384E995923
+20180607010019 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A38550B3B83
+20180607010449 2 6 100 6143 5 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A385542D20F
+20180607022006 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A3859892A7B
+20180607022905 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A385A0321EB
+20180607113212 2 6 100 8191 5 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD9285F38A617
+20180607125146 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928617A82F3
+20180607125328 2 6 100 8191 5 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928617CB5DF
+20180607151424 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD92865898703
+20180607154110 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928664CFCC3
+20180607160549 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD92866F6C0D3
+20180607170551 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD92868ADB733
+20180607185631 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD9286BD88C63
+20180607214035 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928707BBADB
+20180607235316 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928743304D3
+20180608011956 2 6 100 8191 5 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928769DD007
+20180608062301 2 6 100 8191 5 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD9287EFA162F
+20180608062621 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD9287F06E163
+20180608091419 2 6 100 8191 5 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD92883A67EDF
+20180608093938 2 6 100 8191 5 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD92884520EDF
+20180608122935 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD92888E78073
+20180608144406 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD9288C8EB5F3
+20180608204615 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928965840CB
+20180608213353 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928979C33F3
+20180608221715 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD92898C4F47B
+20180608230356 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD92899FB78E3
+20180609004940 2 6 100 8191 5 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD9289CC3013F
+20180609041610 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928A235CA2B
+20180609054840 2 6 100 8191 5 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928A49B8067
+20180609133521 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928B0B91E4B
+20180609143811 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928B24E1BF3
+20180609222946 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928BE4C0EC3
+20180610032425 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928C5BA8AFB
+20180610042318 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928C72C452B
+20180610043314 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928C762DC4B
+20180610072715 2 6 100 8191 5 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928CBBDB7BF
+20180610083654 2 6 100 8191 5 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928CD718587
+20180610085444 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928CDD91733
+20180610125906 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928D3DBCC1B
20151021113847 2 6 100 8191 2 DC61EF13E4F3FC10CC946EEABC33F83EFCB35E0F47E4EC25C1CCBB2C7B502B2EFB0691AA231C8476DD51BA73204E6EA10B1A970FE2CF14AF01E72E1AEA87519A91D00D1499189F94A6CDA9E29C05F11F17FE74A4919A710A2787E180744465DF81C62AA65662FDA46FA6175E8A31E5B29E66DED6701C8FC4217E91D733FE94380F046680967D4CEA7BAC8F3916CDF96AA2C474FAD9650F48403FD0B5B756D34667D36A07767FA33027AE55484D0F701C3CA16632F413A14E4B8645AFAF15B78978C19A7661EDC569BEC72394B1204B166A48FCD5F56BE29840C7794CA6D3440356F15858CDCA9B429C7EA92E17242893FDC8C9C63841A382C32F20CFAB121B4BCAFD7BF9EF07FBF7CDFFECA0CEF3A49C3E2B24FA836F3318435255655E1B281071F62D5E4CD63361299B7828F72936E3FEA9E8044562A6F6ADD5321187C3101E4669C6271598FE1A866C93FE2870A4CEB9254BA32A4719E439317EA42200A335B5CFFA7946A7D0F1BD1A69AA11288B73C71C80B77FE3707CB077DDDEA5CA36A449FAB230C9625A0B12F8275D3FF82F5DA380E7A3F11B6F155FE7E91AC960BD95D9B13F7423AB9B15CC3C4DC34EF296033F009468EA16A721AD659F56C18516025050749ABF05E6D3EBD9778142A530979291F46DAA399A86B7BCDF09CC3E6EEF101419762A306DB45AEFC96C64E83F28338D55905F6A387E0F515E580C3A9B35330E21C32198CDEE3AFB355967A098F635FCA7C49CB4E1E82464B2B390EF1F259E40B9A06235C0273F76284FE6BD534EF3AF7CB01A4A5252B8B94CADC2850B2E56D53F9A31D7C029DF967D0A30C05BC64E119BED6076818FABC8CDD93F3255693E14EFC1A740A5D63A5E847FFE87BAB1DDE0506E1762EA61EFA9F9756151ECCCADD91B98A961A901A2D8B01ABDDD29EC804E8C8D28214BBA26048F924CA66316696E51A49D02FF034D20E44914B1115339CAD3819E0CB1640F0084886FEDDE5E28C29DC48ED30A8C3D789734338F5A9DF42584326E536FD1CF30BC85B8DCBD6120D127C98FE4B3614074F13C2CA4854E6D794156C185C40EB3DA7619CE96ADAF0941BD5499848B034C2B11DFECC0BDFA81C594241F759EF53FC7CDE7F2DE4F23CF81A5A0B7D62E31DABB9198D40307F7824DD130B7D1B80E9B6D322FEEDB5ACE34944F0BFB7D016762A9B2E173BFDD69303766AFBAB45FAB75D05430B4A3515858C4B7F04E23414E4AD03842CB0A20D8FF4B59B7C852BA9A5BE982A8ADA5CB70C36CE2A4D2C31A7015C9F3275E43D192C1B2924424088907A057DA7F2D32A2149922AB2E33F2147D637A3508911CB3FEA5E1AAB4525BACF27B6DD7A3E0AFA978FC3A39DE8882FB22688C3CCC92B6E69ACB0BBF575AB3368E51A2F6A20C414C6F146727CC0045F29061E695D29F7C030CE6929EB3AD11A5CBD0CDEE37347869A3
20151021133636 2 6 100 8191 2 DC61EF13E4F3FC10CC946EEABC33F83EFCB35E0F47E4EC25C1CCBB2C7B502B2EFB0691AA231C8476DD51BA73204E6EA10B1A970FE2CF14AF01E72E1AEA87519A91D00D1499189F94A6CDA9E29C05F11F17FE74A4919A710A2787E180744465DF81C62AA65662FDA46FA6175E8A31E5B29E66DED6701C8FC4217E91D733FE94380F046680967D4CEA7BAC8F3916CDF96AA2C474FAD9650F48403FD0B5B756D34667D36A07767FA33027AE55484D0F701C3CA16632F413A14E4B8645AFAF15B78978C19A7661EDC569BEC72394B1204B166A48FCD5F56BE29840C7794CA6D3440356F15858CDCA9B429C7EA92E17242893FDC8C9C63841A382C32F20CFAB121B4BCAFD7BF9EF07FBF7CDFFECA0CEF3A49C3E2B24FA836F3318435255655E1B281071F62D5E4CD63361299B7828F72936E3FEA9E8044562A6F6ADD5321187C3101E4669C6271598FE1A866C93FE2870A4CEB9254BA32A4719E439317EA42200A335B5CFFA7946A7D0F1BD1A69AA11288B73C71C80B77FE3707CB077DDDEA5CA36A449FAB230C9625A0B12F8275D3FF82F5DA380E7A3F11B6F155FE7E91AC960BD95D9B13F7423AB9B15CC3C4DC34EF296033F009468EA16A721AD659F56C18516025050749ABF05E6D3EBD9778142A530979291F46DAA399A86B7BCDF09CC3E6EEF101419762A306DB45AEFC96C64E83F28338D55905F6A387E0F515E580C3A9B35330E21C32198CDEE3AFB355967A098F635FCA7C49CB4E1E82464B2B390EF1F259E40B9A06235C0273F76284FE6BD534EF3AF7CB01A4A5252B8B94CADC2850B2E56D53F9A31D7C029DF967D0A30C05BC64E119BED6076818FABC8CDD93F3255693E14EFC1A740A5D63A5E847FFE87BAB1DDE0506E1762EA61EFA9F9756151ECCCADD91B98A961A901A2D8B01ABDDD29EC804E8C8D28214BBA26048F924CA66316696E51A49D02FF034D20E44914B1115339CAD3819E0CB1640F0084886FEDDE5E28C29DC48ED30A8C3D789734338F5A9DF42584326E536FD1CF30BC85B8DCBD6120D127C98FE4B3614074F13C2CA4854E6D794156C185C40EB3DA7619CE96ADAF0941BD5499848B034C2B11DFECC0BDFA81C594241F759EF53FC7CDE7F2DE4F23CF81A5A0B7D62E31DABB9198D40307F7824DD130B7D1B80E9B6D322FEEDB5ACE34944F0BFB7D016762A9B2E173BFDD69303766AFBAB45FAB75D05430B4A3515858C4B7F04E23414E4AD03842CB0A20D8FF4B59B7C852BA9A5BE982A8ADA5CB70C36CE2A4D2C31A7015C9F3275E43D192C1B2924424088907A057DA7F2D32A2149922AB2E33F2147D637A3508911CB3FEA5E1AAB4525BACF27B6DD7A3E0AFA978FC3A39DE8882FB22688C3CCC92B6E69ACB0BBF575AB3368E51A2F6A20C414C6F146727CC0045F29061E695D29F7C030CE6929EB3AD11A5CBD0CDEE373914ECA3
-20151021140108 2 6 100 8191 5 DC61EF13E4F3FC10CC946EEABC33F83EFCB35E0F47E4EC25C1CCBB2C7B502B2EFB0691AA231C8476DD51BA73204E6EA10B1A970FE2CF14AF01E72E1AEA87519A91D00D1499189F94A6CDA9E29C05F11F17FE74A4919A710A2787E180744465DF81C62AA65662FDA46FA6175E8A31E5B29E66DED6701C8FC4217E91D733FE94380F046680967D4CEA7BAC8F3916CDF96AA2C474FAD9650F48403FD0B5B756D34667D36A07767FA33027AE55484D0F701C3CA16632F413A14E4B8645AFAF15B78978C19A7661EDC569BEC72394B1204B166A48FCD5F56BE29840C7794CA6D3440356F15858CDCA9B429C7EA92E17242893FDC8C9C63841A382C32F20CFAB121B4BCAFD7BF9EF07FBF7CDFFECA0CEF3A49C3E2B24FA836F3318435255655E1B281071F62D5E4CD63361299B7828F72936E3FEA9E8044562A6F6ADD5321187C3101E4669C6271598FE1A866C93FE2870A4CEB9254BA32A4719E439317EA42200A335B5CFFA7946A7D0F1BD1A69AA11288B73C71C80B77FE3707CB077DDDEA5CA36A449FAB230C9625A0B12F8275D3FF82F5DA380E7A3F11B6F155FE7E91AC960BD95D9B13F7423AB9B15CC3C4DC34EF296033F009468EA16A721AD659F56C18516025050749ABF05E6D3EBD9778142A530979291F46DAA399A86B7BCDF09CC3E6EEF101419762A306DB45AEFC96C64E83F28338D55905F6A387E0F515E580C3A9B35330E21C32198CDEE3AFB355967A098F635FCA7C49CB4E1E82464B2B390EF1F259E40B9A06235C0273F76284FE6BD534EF3AF7CB01A4A5252B8B94CADC2850B2E56D53F9A31D7C029DF967D0A30C05BC64E119BED6076818FABC8CDD93F3255693E14EFC1A740A5D63A5E847FFE87BAB1DDE0506E1762EA61EFA9F9756151ECCCADD91B98A961A901A2D8B01ABDDD29EC804E8C8D28214BBA26048F924CA66316696E51A49D02FF034D20E44914B1115339CAD3819E0CB1640F0084886FEDDE5E28C29DC48ED30A8C3D789734338F5A9DF42584326E536FD1CF30BC85B8DCBD6120D127C98FE4B3614074F13C2CA4854E6D794156C185C40EB3DA7619CE96ADAF0941BD5499848B034C2B11DFECC0BDFA81C594241F759EF53FC7CDE7F2DE4F23CF81A5A0B7D62E31DABB9198D40307F7824DD130B7D1B80E9B6D322FEEDB5ACE34944F0BFB7D016762A9B2E173BFDD69303766AFBAB45FAB75D05430B4A3515858C4B7F04E23414E4AD03842CB0A20D8FF4B59B7C852BA9A5BE982A8ADA5CB70C36CE2A4D2C31A7015C9F3275E43D192C1B2924424088907A057DA7F2D32A2149922AB2E33F2147D637A3508911CB3FEA5E1AAB4525BACF27B6DD7A3E0AFA978FC3A39DE8882FB22688C3CCC92B6E69ACB0BBF575AB3368E51A2F6A20C414C6F146727CC0045F29061E695D29F7C030CE6929EB3AD11A5CBD0CDEE373A17959F
+b20151021140108 2 6 100 8191 5 DC61EF13E4F3FC10CC946EEABC33F83EFCB35E0F47E4EC25C1CCBB2C7B502B2EFB0691AA231C8476DD51BA73204E6EA10B1A970FE2CF14AF01E72E1AEA87519A91D00D1499189F94A6CDA9E29C05F11F17FE74A4919A710A2787E180744465DF81C62AA65662FDA46FA6175E8A31E5B29E66DED6701C8FC4217E91D733FE94380F046680967D4CEA7BAC8F3916CDF96AA2C474FAD9650F48403FD0B5B756D34667D36A07767FA33027AE55484D0F701C3CA16632F413A14E4B8645AFAF15B78978C19A7661EDC569BEC72394B1204B166A48FCD5F56BE29840C7794CA6D3440356F15858CDCA9B429C7EA92E17242893FDC8C9C63841A382C32F20CFAB121B4BCAFD7BF9EF07FBF7CDFFECA0CEF3A49C3E2B24FA836F3318435255655E1B281071F62D5E4CD63361299B7828F72936E3FEA9E8044562A6F6ADD5321187C3101E4669C6271598FE1A866C93FE2870A4CEB9254BA32A4719E439317EA42200A335B5CFFA7946A7D0F1BD1A69AA11288B73C71C80B77FE3707CB077DDDEA5CA36A449FAB230C9625A0B12F8275D3FF82F5DA380E7A3F11B6F155FE7E91AC960BD95D9B13F7423AB9B15CC3C4DC34EF296033F009468EA16A721AD659F56C18516025050749ABF05E6D3EBD9778142A530979291F46DAA399A86B7BCDF09CC3E6EEF101419762A306DB45AEFC96C64E83F28338D55905F6A387E0F515E580C3A9B35330E21C32198CDEE3AFB355967A098F635FCA7C49CB4E1E82464B2B390EF1F259E40B9A06235C0273F76284FE6BD534EF3AF7CB01A4A5252B8B94CADC2850B2E56D53F9A31D7C029DF967D0A30C05BC64E119BED6076818FABC8CDD93F3255693E14EFC1A740A5D63A5E847FFE87BAB1DDE0506E1762EA61EFA9F9756151ECCCADD91B98A961A901A2D8B01ABDDD29EC804E8C8D28214BBA26048F924CA66316696E51A49D02FF034D20E44914B1115339CAD3819E0CB1640F0084886FEDDE5E28C29DC48ED30A8C3D789734338F5A9DF42584326E536FD1CF30BC85B8DCBD6120D127C98FE4B3614074F13C2CA4854E6D794156C185C40EB3DA7619CE96ADAF0941BD5499848B034C2B11DFECC0BDFA81C594241F759EF53FC7CDE7F2DE4F23CF81A5A0B7D62E31DABB9198D40307F7824DD130B7D1B80E9B6D322FEEDB5ACE34944F0BFB7D016762A9B2E173BFDD69303766AFBAB45FAB75D05430B4A3515858C4B7F04E23414E4AD03842CB0A20D8FF4B59B7C852BA9A5BE982A8ADA5CB70C36CE2A4D2C31A7015C9F3275E43D192C1B2924424088907A057DA7F2D32A2149922AB2E33F2147D637A3508911CB3FEA5E1AAB4525BACF27B6DD7A3E0AFA978FC3A39DE8882FB22688C3CCC92B6E69ACB0BBF575AB3368E51A2F6A20C414C6F146727CC0045F29061E695D29F7C030CE6929EB3AD11A5CBD0CDEE373A17959F
diff --git a/lib/public_key/src/pubkey_cert.erl b/lib/public_key/src/pubkey_cert.erl
index c433a96585..12c61e158f 100644
--- a/lib/public_key/src/pubkey_cert.erl
+++ b/lib/public_key/src/pubkey_cert.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -371,23 +371,23 @@ match_name(directoryName, DirName, [PermittedName | Rest]) ->
match_name(fun is_rdnSeq/2, DirName, PermittedName, Rest);
match_name(uniformResourceIdentifier, URI, [PermittedName | Rest]) ->
- case split_uri(URI) of
- incomplete ->
- false;
- {_, _, Host, _, _} ->
- PN = case split_uri(PermittedName) of
- {_, _, PNhost, _, _} -> PNhost;
+ case uri_string:normalize(URI, [return_map]) of
+ #{host := Host} ->
+ PN = case uri_string:normalize(PermittedName, [return_map]) of
+ #{host := PNhost} -> PNhost;
_X -> PermittedName
end,
- match_name(fun is_valid_host_or_domain/2, Host, PN, Rest)
+ match_name(fun is_valid_host_or_domain/2, Host, PN, Rest);
+ _ ->
+ false
end;
match_name(emailAddress, Name, [PermittedName | Rest]) ->
Fun = fun(Email, PermittedEmail) ->
- is_valid_email_address(Email, PermittedEmail,
- string:tokens(PermittedEmail,"@"))
- end,
- match_name(Fun, Name, PermittedName, Rest);
+ is_valid_email_address(Email, PermittedEmail,
+ string:tokens(PermittedEmail,"@"))
+ end,
+ match_name(Fun, Name, PermittedName, Rest);
match_name(dNSName, Name, [PermittedName | Rest]) ->
Fun = fun(Domain, [$.|Domain]) -> true;
@@ -868,75 +868,12 @@ is_valid_subject_alt_name({otherName, #'AnotherName'{}}) ->
is_valid_subject_alt_name({_, _}) ->
false.
-is_ip_address(Address) ->
- case inet_parse:address(Address) of
- {ok, _} ->
- true;
- _ ->
- false
- end.
-
-is_fully_qualified_name(_Name) ->
- true.
-
is_valid_uri(AbsURI) ->
- case split_uri(AbsURI) of
- incomplete ->
- false;
- {StrScheme, _, Host, _, _} ->
- case string:to_lower(StrScheme) of
- Scheme when Scheme =:= "http"; Scheme =:= "ftp" ->
- is_valid_host(Host);
- _ ->
- false
- end
- end.
-
-is_valid_host(Host) ->
- case is_ip_address(Host) of
- true ->
- true;
- false ->
- is_fully_qualified_name(Host)
- end.
-
-%% Could have a more general split URI in stdlib? Maybe when
-%% regexs are improved. Needed also in inets!
-split_uri(Uri) ->
- case split_uri(Uri, ":", {error, no_scheme}, 1, 1) of
- {error, no_scheme} ->
- incomplete;
- {StrScheme, "//" ++ URIPart} ->
- {Authority, PathQuery} =
- split_auth_path(URIPart),
- {UserInfo, HostPort} =
- split_uri(Authority, "@", {"", Authority}, 1, 1),
- {Host, Port} =
- split_uri(HostPort, ":", {HostPort, dummy_port}, 1, 1),
- {StrScheme, UserInfo, Host, Port, PathQuery}
- end.
-
-split_auth_path(URIPart) ->
- case split_uri(URIPart, "/", URIPart, 1, 0) of
- Split = {_, _} ->
- Split;
- URIPart ->
- case split_uri(URIPart, "\\?", URIPart, 1, 0) of
- Split = {_, _} ->
- Split;
- URIPart ->
- {URIPart,""}
- end
- end.
-
-split_uri(UriPart, SplitChar, NoMatchResult, SkipLeft, SkipRight) ->
- case re:run(UriPart, SplitChar) of
- {match,[{Start, _}]} ->
- StrPos = Start + 1,
- {string:substr(UriPart, 1, StrPos - SkipLeft),
- string:substr(UriPart, StrPos + SkipRight, length(UriPart))};
- nomatch ->
- NoMatchResult
+ case uri_string:normalize(AbsURI, [return_map]) of
+ #{scheme := _} ->
+ true;
+ _ ->
+ false
end.
is_rdnSeq({rdnSequence,[]}, {rdnSequence,[none]}) ->
@@ -1250,6 +1187,8 @@ sign_algorithm(#'ECPrivateKey'{parameters = Parms}, Opts) ->
parameters = Parms}.
rsa_digest_oid(sha1) ->
?'sha1WithRSAEncryption';
+rsa_digest_oid(sha) ->
+ ?'sha1WithRSAEncryption';
rsa_digest_oid(sha512) ->
?'sha512WithRSAEncryption';
rsa_digest_oid(sha384) ->
@@ -1261,6 +1200,8 @@ rsa_digest_oid(md5) ->
ecdsa_digest_oid(sha1) ->
?'ecdsa-with-SHA1';
+ecdsa_digest_oid(sha) ->
+ ?'ecdsa-with-SHA1';
ecdsa_digest_oid(sha512) ->
?'ecdsa-with-SHA512';
ecdsa_digest_oid(sha384) ->
diff --git a/lib/public_key/src/pubkey_crl.erl b/lib/public_key/src/pubkey_crl.erl
index 3621e9c0da..50abd704de 100644
--- a/lib/public_key/src/pubkey_crl.erl
+++ b/lib/public_key/src/pubkey_crl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/public_key/src/pubkey_moduli.hrl b/lib/public_key/src/pubkey_moduli.hrl
index e4beecc12a..768db624c7 100644
--- a/lib/public_key/src/pubkey_moduli.hrl
+++ b/lib/public_key/src/pubkey_moduli.hrl
@@ -1,395 +1,489 @@
-define(dh_default_groups,
[{1023,
[{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840821904219},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016037066299},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840822843699},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016038392563},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840824293227},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016038561043},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840824411619},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016040084083},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840826770579},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016040928019},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840829698867},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016041403147},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840831699579},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016044289459},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840831788499},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016046539987},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840835116819},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016048107763},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840838791147},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016048195459},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840839741403},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016048489219},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840843908763},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016051183339},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840844149459},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016051761379},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840846037779},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016059530419},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840846316347},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016061519299},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840848087763},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016061652187},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840851778483},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016062557059},
+ {2,
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016062981427},
+ {2,
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016066800187},
+ {5,
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016042534663},
{5,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840818511543},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016047828127},
{5,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840819546447},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016048304863},
{5,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840820698807},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016049426047},
{5,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840821875983},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016052250343},
{5,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840822182367},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016055892463},
{5,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840823493823},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016056347623},
{5,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840828115623},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016056938023},
{5,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840833652783},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016058313343},
{5,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840844852263},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016065124567},
{5,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840849785943},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016066293247},
{5,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840849803727}]},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016066518343},
+ {5,
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016068472303}]},
{1535,
[{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891121581459},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789627621067},
+ {2,
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789628761283},
+ {2,
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789634361539},
+ {2,
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789638537803},
+ {2,
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789641659627},
+ {2,
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789647419339},
+ {2,
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789659085619},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891123347643},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789662256763},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891123353283},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789664867003},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891124232763},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789666330667},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891131462067},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789666841459},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891135933003},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789668814427},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891136255299},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789672118003},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891137177907},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789672898027},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891139347603},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789674915179},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891152305467},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789676842763},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891159084867},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789681188923},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891161343219},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789682812883},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891172563627},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789691688803},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891174672243},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789694851307},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891180467739},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789696895987},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891185564427},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789696948499},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891189869307},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789699330739},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891119456223},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789631448743},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891124590423},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789634212463},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891130908327},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789640500127},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891131873727},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789645700087},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891135211407},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789647710183},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891143426247},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789652039063},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891143747007},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789654186463},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891146699103},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789661060927},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891150054447},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789671831647},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891155995647},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789672578407},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891157019487},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789678179287},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891159178863},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789681924847},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891161250063},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789686897743},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891170145447},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789691863487},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891171171087},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789697728943},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891172350063},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789698140423},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891176092263}]},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789699225607},
+ {5,
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789699353287},
+ {5,
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789699437767},
+ {5,
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789700740103}]},
{2047,
[{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127673160083},
- {2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127674746147},
- {2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127677513587},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074755345499},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127677855803},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074756461859},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127681703483},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074760692747},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127691773067},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074773822283},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127693199747},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074776983899},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127694475899},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074790653483},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127702886939},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074794713299},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127707613619},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074815828619},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127713247667},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074834327939},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127727962403},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074842331123},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127729070603},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074845064267},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127741606979},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074846183603},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127745340899},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074847350027},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127764392459},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074850417539},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127764820307},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074852923427},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127771318403},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074865137387},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127781167379},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074871791507},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127782355883},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074872448099},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127782887579},
- {2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127787746619},
- {2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127789102259},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074872498379},
{5,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127666983407},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074753531327},
{5,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127675200023},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074755896047},
{5,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127687609343},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074769190823},
{5,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127691690063},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074773140287},
{5,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127708300823},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074801938847},
{5,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127712140847},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074808850487},
{5,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127715948087},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074810458703},
{5,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127717449983},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074819068463},
{5,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127717581887},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074828950247},
{5,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127725119327},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074831380223},
{5,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127735619543},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074843050847},
{5,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127776932207},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074853193463},
{5,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127788684623},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074854277423},
{5,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127790955767}]},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074856272687},
+ {5,
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074856341807}]},
{3071,
[{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199506260163},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289461870763},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199530244827},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289490971387},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199578944619},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289493767387},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199589988939},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289502528779},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199594013379},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289515762739},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199601609043},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289520111827},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199604230203},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289526490499},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199606755099},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289531918987},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199618079787},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289535321539},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199653718659},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289537766083},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199657776483},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289585885627},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199707657579},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289591046227},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199722711699},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289593005899},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199743456099},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289609404787},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199785339603},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289612863787},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199797260499},
- {5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199507581927},
- {5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199510208343},
- {5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199537327623},
- {5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199551703167},
- {5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199617722127},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289648408147},
+ {2,
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289660538083},
+ {2,
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289673483683},
+ {2,
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289677227419},
+ {2,
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289698314083},
+ {2,
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289741797499},
+ {2,
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289743929803},
{5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199621084383},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289453025863},
{5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199634824407},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289457558263},
{5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199642326807},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289460688727},
{5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199665149823},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289474675927},
{5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199708695087},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289594040647},
{5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199765825887},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289609025887},
{5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199767685887},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289609530703},
{5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199773947727},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289654971847},
{5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199780743543},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289728752743},
{5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199786221207},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289741648567},
{5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199798706967}]},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289746986983}]},
{4095,
[{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328641094123},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908261488803},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328654189387},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908267757267},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328663242883},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908296392939},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328715041723},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908296649787},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328717604779},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908347767723},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328805204587},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908378270547},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328806565843},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908383266867},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328807451707},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908404042059},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328836115507},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908438601507},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328845968059},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908495213859},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328887178459},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908512647459},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328908234163},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908521746723},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328948166083},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908568726363},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328954136203},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908573748939},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328963052323},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908598118683},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024329023777723},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908611654827},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024329047093003},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908619313779},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024329058480379},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908654940987},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024329090057419},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908658321027},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024329132001859},
- {5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328685618887},
- {5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328733393407},
- {5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328804704703},
- {5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328808160607},
- {5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328817663383},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908711194899},
+ {2,
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908729714499},
{5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328826409727},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908237597607},
{5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328842353143},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908282017743},
{5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328915670167},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908357526423},
{5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328928173423},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908366458383},
{5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328936548223},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908428742727},
{5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328945813063},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908488602303},
{5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328955100607},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908617606623},
{5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328983302407},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908644249167},
{5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328995176167},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908664024183},
{5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024329021303887},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908676438567},
{5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024329064403567}]},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908697685503}]},
{6143,
[{2,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255204878912539},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066212697067},
+ {2,
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066239737819},
+ {2,
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066261564859},
+ {2,
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066266476003},
{2,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205024824427},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066306104707},
{2,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205108938283},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066308614363},
{2,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205168452667},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066415298659},
{2,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205178336083},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066433581259},
{2,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205194695203},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066436192219},
{2,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205234987027},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066526639459},
{2,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205249389907},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066543056683},
{2,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205299503899},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066571940083},
{2,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205303762219},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066616922347},
{2,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205318419043},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066630852307},
{2,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205369723267},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066646474627},
{2,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205388065627},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066845660899},
{2,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205483192027},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104067076479267},
+ {2,
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104067184606083},
+ {2,
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104067259968123},
+ {2,
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104067267961323},
{5,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255204867528103},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066189360223},
{5,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255204958533343},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066217457143},
{5,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205142917087},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066324667807},
{5,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205164709807},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066489492103},
{5,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205223494543},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066643247863},
{5,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205238451607},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066905718943},
{5,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205398650527},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066970573183},
{5,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205534891927},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104067042481887},
{5,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205578782263}]},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104067188249103}]},
{8191,
[{2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408345391859},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408413484803},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408426294467},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408437420243},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408466188083},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408519326819},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408597129947},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408659473619},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408841130339},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645409006846067},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645409068135923},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645409232339147},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645409253569523},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645409273017467},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645409293367523},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645409431407147},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645409674894923},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645409701436403},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645409902628547},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645410027309819},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645410051540267},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645410055117899},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645410163529523},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645410264370203},
+ {2,
938991641448887958659860711024139841840373070892857314837350127283993531354468803860225599873491818506054401963417489724433963777795696041544477412963807403300832656512849715212168703537706302853428971073305304224008208665300028518281475780493382070018498379488833882168221853720545474425047940975435356027594634176129712250061883354535324982741923143373986406603949677080360223989497048086447454366625852264609369284140522273595340921542019308988041920995057608746115976973659704188342646944998285431473302075966106608530908140377765357842459486869512398523240695806503711124427370056638597159539032058092571318621818616699716647464298881944582194013388150591419588422793657857267906072494480713650129757905856314362270238621284311461743652666256381611674809565144562467655186251867429369336740018623120262859220669942243740953355278814789244133782043857008487446798345197999966787658254507117076710455244182794239065255535191498857182705725985655379455993825553257619502588673174759329362518373537685585117537004065137523099625519490356398330532110250061129576411957409731201790054967354938147031111368166150009421041430118523249245874882140875551501824754839814848195806919150975076831338899823813371473496616326897054534509843640848822974414341233324307292275820287661792887177523563243279340678632061899626115667671047274195425889742755327012266774742591229119994211561599405909368902449776535330722644597809098307346948888547387746758109319767106289995123864514603259977184876246412673772519845777697496361969177346826245108557971745523905955370437517039028495325595180934057507336816903052766590118820327869839202378278312909402987412274414739124292902164277499512007446916921747463997761815820546816791093343347969046462095463611789365326128045878985464594892022442144072282717352526544915821855299863549245012366815543939396712522935345161074836470227392836664033041735035699615758782980717425699108612161567924880267630103820215946940542401779795959759774248414245436455737309858403883625882609790799283421857564831362243562647683958370353023343221966296655134926556805244483888769178095889844741765908328185625663202823312608064683035802724504683124396450612201783060593269112984065572954508643688374585823409316161924407053191442613988480926581084892323451281350937867676271858142177713557970909833234285545964647506859724327822527317869059455132036566677244407755994867168874825546516623190701762311472512591018622127119388239627852234680483324150442403},
{2,
938991641448887958659860711024139841840373070892857314837350127283993531354468803860225599873491818506054401963417489724433963777795696041544477412963807403300832656512849715212168703537706302853428971073305304224008208665300028518281475780493382070018498379488833882168221853720545474425047940975435356027594634176129712250061883354535324982741923143373986406603949677080360223989497048086447454366625852264609369284140522273595340921542019308988041920995057608746115976973659704188342646944998285431473302075966106608530908140377765357842459486869512398523240695806503711124427370056638597159539032058092571318621818616699716647464298881944582194013388150591419588422793657857267906072494480713650129757905856314362270238621284311461743652666256381611674809565144562467655186251867429369336740018623120262859220669942243740953355278814789244133782043857008487446798345197999966787658254507117076710455244182794239065255535191498857182705725985655379455993825553257619502588673174759329362518373537685585117537004065137523099625519490356398330532110250061129576411957409731201790054967354938147031111368166150009421041430118523249245874882140875551501824754839814848195806919150975076831338899823813371473496616326897054534509843640848822974414341233324307292275820287661792887177523563243279340678632061899626115667671047274195425889742755327012266774742591229119994211561599405909368902449776535330722644597809098307346948888547387746758109319767106289995123864514603259977184876246412673772519845777697496361969177346826245108557971745523905955370437517039028495325595180934057507336816903052766590118820327869839202378278312909402987412274414739124292902164277499512007446916921747463997761815820546816791093343347969046462095463611789365326128045878985464594892022442144072282717352526544915821855299863549245012366815543939396712522935345161074836470227392836664033041735035699615758782980717425699108612161567924880267630103820215946940542401779795959759774248414245436455737309858403883625882609790799283421857564831362243562647683958370353023343221966296655134926556805244483888769178095889844741765908328185625663202823312608064683035802724504683124396450612201783060593269112984065572954508643688374585823409316161924407053191442613988480926581084892323451281350937867676271858142177713557970909833234285545964647506859724327822527317869059455132036566677244407755994867168874825546516623190701762311472512591018622127119388239627852234680483324227808419},
{5,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408307521047},
+ {5,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408345535967},
+ {5,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408700026887},
+ {5,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408840291887},
+ {5,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408918699743},
+ {5,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408929943263},
+ {5,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645409339998527},
+ {5,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645409471627367},
+ {5,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645410128181183},
+ {5,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645410156742023},
+ {5,
938991641448887958659860711024139841840373070892857314837350127283993531354468803860225599873491818506054401963417489724433963777795696041544477412963807403300832656512849715212168703537706302853428971073305304224008208665300028518281475780493382070018498379488833882168221853720545474425047940975435356027594634176129712250061883354535324982741923143373986406603949677080360223989497048086447454366625852264609369284140522273595340921542019308988041920995057608746115976973659704188342646944998285431473302075966106608530908140377765357842459486869512398523240695806503711124427370056638597159539032058092571318621818616699716647464298881944582194013388150591419588422793657857267906072494480713650129757905856314362270238621284311461743652666256381611674809565144562467655186251867429369336740018623120262859220669942243740953355278814789244133782043857008487446798345197999966787658254507117076710455244182794239065255535191498857182705725985655379455993825553257619502588673174759329362518373537685585117537004065137523099625519490356398330532110250061129576411957409731201790054967354938147031111368166150009421041430118523249245874882140875551501824754839814848195806919150975076831338899823813371473496616326897054534509843640848822974414341233324307292275820287661792887177523563243279340678632061899626115667671047274195425889742755327012266774742591229119994211561599405909368902449776535330722644597809098307346948888547387746758109319767106289995123864514603259977184876246412673772519845777697496361969177346826245108557971745523905955370437517039028495325595180934057507336816903052766590118820327869839202378278312909402987412274414739124292902164277499512007446916921747463997761815820546816791093343347969046462095463611789365326128045878985464594892022442144072282717352526544915821855299863549245012366815543939396712522935345161074836470227392836664033041735035699615758782980717425699108612161567924880267630103820215946940542401779795959759774248414245436455737309858403883625882609790799283421857564831362243562647683958370353023343221966296655134926556805244483888769178095889844741765908328185625663202823312608064683035802724504683124396450612201783060593269112984065572954508643688374585823409316161924407053191442613988480926581084892323451281350937867676271858142177713557970909833234285545964647506859724327822527317869059455132036566677244407755994867168874825546516623190701762311472512591018622127119388239627852234680483324244759967}]}]
).
diff --git a/lib/public_key/src/pubkey_pbe.erl b/lib/public_key/src/pubkey_pbe.erl
index e89e16f120..e6bcedd1b1 100644
--- a/lib/public_key/src/pubkey_pbe.erl
+++ b/lib/public_key/src/pubkey_pbe.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -42,15 +42,14 @@
encode(Data, Password, "DES-CBC" = Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
crypto:block_encrypt(des_cbc, Key, IV, pbe_pad(Data, KeyDevParams));
-
encode(Data, Password, "DES-EDE3-CBC" = Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
<<Key1:8/binary, Key2:8/binary, Key3:8/binary>> = Key,
crypto:block_encrypt(des3_cbc, [Key1, Key2, Key3], IV, pbe_pad(Data));
-
encode(Data, Password, "RC2-CBC" = Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
crypto:block_encrypt(rc2_cbc, Key, IV, pbe_pad(Data, KeyDevParams)).
+
%%--------------------------------------------------------------------
-spec decode(binary(), string(), string(), term()) -> binary().
%%
@@ -59,21 +58,20 @@ encode(Data, Password, "RC2-CBC" = Cipher, KeyDevParams) ->
decode(Data, Password,"DES-CBC"= Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
crypto:block_decrypt(des_cbc, Key, IV, Data);
-
decode(Data, Password,"DES-EDE3-CBC" = Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
<<Key1:8/binary, Key2:8/binary, Key3:8/binary>> = Key,
crypto:block_decrypt(des3_cbc, [Key1, Key2, Key3], IV, Data);
-
decode(Data, Password,"RC2-CBC"= Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
crypto:block_decrypt(rc2_cbc, Key, IV, Data);
+decode(Data, Password,"AES-128-CBC"= Cipher, KeyDevParams) ->
+ {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
+ crypto:block_decrypt(aes_cbc128, Key, IV, Data);
+decode(Data, Password,"AES-256-CBC"= Cipher, KeyDevParams) ->
+ {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
+ crypto:block_decrypt(aes_cbc256, Key, IV, Data).
-decode(Data, Password,"AES-128-CBC"= Cipher, IV) ->
- %% PKCS5_SALT_LEN is 8 bytes
- <<Salt:8/binary,_/binary>> = IV,
- {Key, _} = password_to_key_and_iv(Password, Cipher, Salt),
- crypto:block_decrypt(aes_cbc128, Key, IV, Data).
%%--------------------------------------------------------------------
-spec pbdkdf1(string(), iodata(), integer(), atom()) -> binary().
@@ -131,13 +129,15 @@ password_to_key_and_iv(Password, _Cipher, {#'PBEParameter'{salt = Salt,
<<Key:8/binary, IV:8/binary, _/binary>>
= pbdkdf1(Password, Salt, Count, Hash),
{Key, IV};
-password_to_key_and_iv(Password, Cipher, Salt) ->
- KeyLen = derived_key_length(Cipher, undefined),
+password_to_key_and_iv(Password, Cipher, KeyDevParams) ->
+ %% PKCS5_SALT_LEN is 8 bytes
+ <<Salt:8/binary,_/binary>> = KeyDevParams,
+ KeyLen = derived_key_length(Cipher, undefined),
<<Key:KeyLen/binary, _/binary>> =
pem_encrypt(<<>>, Password, Salt, ceiling(KeyLen div 16), <<>>, md5),
%% Old PEM encryption does not use standard encryption method
- %% pbdkdf1 and uses then salt as IV
- {Key, Salt}.
+ %% pbdkdf1
+ {Key, KeyDevParams}.
pem_encrypt(_, _, _, 0, Acc, _) ->
Acc;
pem_encrypt(Prev, Password, Salt, Count, Acc, Hash) ->
@@ -267,7 +267,9 @@ derived_key_length(Cipher,_) when (Cipher == ?'des-EDE3-CBC') or
(Cipher == "DES-EDE3-CBC") ->
24;
derived_key_length(Cipher,_) when (Cipher == "AES-128-CBC") ->
- 16.
+ 16;
+derived_key_length(Cipher,_) when (Cipher == "AES-256-CBC") ->
+ 32.
cipher(#'PBES2-params_encryptionScheme'{algorithm = ?'desCBC'}) ->
"DES-CBC";
diff --git a/lib/public_key/src/pubkey_pem.erl b/lib/public_key/src/pubkey_pem.erl
index 06a4455b3f..0fd1453f7c 100644
--- a/lib/public_key/src/pubkey_pem.erl
+++ b/lib/public_key/src/pubkey_pem.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -101,10 +101,10 @@ encode_pem_entry({'PrivateKeyInfo', Der, EncParams}) ->
EncDer = encode_encrypted_private_keyinfo(Der, EncParams),
StartStr = pem_start('EncryptedPrivateKeyInfo'),
[StartStr, "\n", b64encode_and_split(EncDer), "\n", pem_end(StartStr) ,"\n\n"];
-encode_pem_entry({Type, Der, {Cipher, Salt}}) ->
+encode_pem_entry({Type, Decrypted, {Cipher, Salt}}) ->
StartStr = pem_start(Type),
[StartStr,"\n", pem_decrypt(),"\n", pem_decrypt_info(Cipher, Salt),"\n\n",
- b64encode_and_split(Der), "\n", pem_end(StartStr) ,"\n\n"].
+ b64encode_and_split(Decrypted), "\n", pem_end(StartStr) ,"\n\n"].
decode_pem_entries([], Entries) ->
lists:reverse(Entries);
@@ -209,6 +209,8 @@ pem_start('DSAPrivateKey') ->
<<"-----BEGIN DSA PRIVATE KEY-----">>;
pem_start('DHParameter') ->
<<"-----BEGIN DH PARAMETERS-----">>;
+pem_start('PrivateKeyInfo') ->
+ <<"-----BEGIN PRIVATE KEY-----">>;
pem_start('EncryptedPrivateKeyInfo') ->
<<"-----BEGIN ENCRYPTED PRIVATE KEY-----">>;
pem_start('CertificationRequest') ->
@@ -220,7 +222,9 @@ pem_start('CertificateList') ->
pem_start('EcpkParameters') ->
<<"-----BEGIN EC PARAMETERS-----">>;
pem_start('ECPrivateKey') ->
- <<"-----BEGIN EC PRIVATE KEY-----">>.
+ <<"-----BEGIN EC PRIVATE KEY-----">>;
+pem_start({no_asn1, new_openssh}) -> %% Temporarily in the prototype of this format
+ <<"-----BEGIN OPENSSH PRIVATE KEY-----">>.
pem_end(<<"-----BEGIN CERTIFICATE-----">>) ->
<<"-----END CERTIFICATE-----">>;
@@ -248,6 +252,8 @@ pem_end(<<"-----BEGIN EC PARAMETERS-----">>) ->
<<"-----END EC PARAMETERS-----">>;
pem_end(<<"-----BEGIN EC PRIVATE KEY-----">>) ->
<<"-----END EC PRIVATE KEY-----">>;
+pem_end(<<"-----BEGIN OPENSSH PRIVATE KEY-----">>) ->
+ <<"-----END OPENSSH PRIVATE KEY-----">>;
pem_end(_) ->
undefined.
@@ -276,7 +282,10 @@ asn1_type(<<"-----BEGIN X509 CRL-----">>) ->
asn1_type(<<"-----BEGIN EC PARAMETERS-----">>) ->
'EcpkParameters';
asn1_type(<<"-----BEGIN EC PRIVATE KEY-----">>) ->
- 'ECPrivateKey'.
+ 'ECPrivateKey';
+asn1_type(<<"-----BEGIN OPENSSH PRIVATE KEY-----">>) ->
+ {no_asn1, new_openssh}. %% Temporarily in the prototype of this format
+
pem_decrypt() ->
<<"Proc-Type: 4,ENCRYPTED">>.
diff --git a/lib/public_key/src/pubkey_ssh.erl b/lib/public_key/src/pubkey_ssh.erl
index a7d018e440..d0ef4abfb1 100644
--- a/lib/public_key/src/pubkey_ssh.erl
+++ b/lib/public_key/src/pubkey_ssh.erl
@@ -25,7 +25,8 @@
-export([decode/2, encode/2,
dh_gex_group/4,
- dh_gex_group_sizes/0
+ dh_gex_group_sizes/0,
+pad/2, new_openssh_encode/1, new_openssh_decode/1 % For test and experiments
]).
-define(UINT32(X), X:32/unsigned-big-integer).
@@ -38,6 +39,8 @@
-define(Empint(X), (mpint(X))/binary ).
-define(Estring(X), (string(X))/binary ).
+-define(b64enc(X), base64:encode(iolist_to_binary(X)) ).
+-define(b64mime_dec(X), base64:mime_decode(iolist_to_binary(X)) ).
%% Max encoded line length is 72, but conformance examples use 68
%% Comment from rfc 4716: "The following are some examples of public
@@ -65,6 +68,8 @@ decode(Bin, rfc4716_public_key) ->
rfc4716_decode(Bin);
decode(Bin, ssh2_pubkey) ->
ssh2_pubkey_decode(Bin);
+decode(Bin, new_openssh) ->
+ new_openssh_decode(Bin);
decode(Bin, Type) ->
openssh_decode(Bin, Type).
@@ -163,7 +168,7 @@ rfc4716_decode_line(Line, Lines, Acc) ->
rfc4716_decode_lines(Lines, [{string_decode(Tag), unicode_decode(Value)} | Acc]);
_ ->
{Body, Rest} = join_entry([Line | Lines], []),
- {lists:reverse(Acc), rfc4716_pubkey_decode(base64:mime_decode(Body)), Rest}
+ {lists:reverse(Acc), rfc4716_pubkey_decode(?b64mime_dec(Body)), Rest}
end.
join_entry([<<"---- END SSH2 PUBLIC KEY ----", _/binary>>| Lines], Entry) ->
@@ -175,6 +180,70 @@ join_entry([Line | Lines], Entry) ->
rfc4716_pubkey_decode(BinKey) -> ssh2_pubkey_decode(BinKey).
+%% From https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key
+new_openssh_decode(<<"openssh-key-v1",0,
+ ?DEC_BIN(CipherName, _L1),
+ ?DEC_BIN(KdfName, _L2),
+ ?DEC_BIN(KdfOptions, _L3),
+ ?UINT32(N), % number of keys
+ ?DEC_BIN(PublicKey, _L4),
+ ?DEC_BIN(Encrypted, _L5),
+ _Rest/binary
+ >>) ->
+ %%io:format("CipherName = ~p~nKdfName = ~p~nKdfOptions = ~p~nPublicKey = ~p~nN = ~p~nEncrypted = ~p~nRest = ~p~n", [CipherName, KdfName, KdfOptions, PublicKey, N, Encrypted, _Rest]),
+ new_openssh_decode(CipherName, KdfName, KdfOptions, PublicKey, N, Encrypted).
+
+new_openssh_decode(<<"none">>, <<"none">>, <<"">>, _PublicKey, 1,
+ <<?UINT32(CheckInt),
+ ?UINT32(CheckInt),
+ ?DEC_BIN(Type, _Lt),
+ ?DEC_BIN(PubKey, _Lpu),
+ ?DEC_BIN(PrivPubKey, _Lpripub),
+ ?DEC_BIN(_Comment, _C1),
+ _Pad/binary>>) ->
+ case {Type,PrivPubKey} of
+ {<<"ssh-ed25519">>,
+ <<PrivKey:32/binary, PubKey:32/binary>>} ->
+ {ed_pri, ed25519, PubKey, PrivKey};
+
+ {<<"ssh-ed448">>,
+ <<PrivKey:57/binary, PubKey/binary>>} -> % "Intelligent" guess from
+ % https://tools.ietf.org/html/draft-ietf-curdle-ssh-ed25519-ed448
+ {ed_pri, ed448, PubKey, PrivKey}
+ end.
+
+
+new_openssh_encode({ed_pri,_,PubKey,PrivKey}=Key) ->
+ Type = key_type(Key),
+ CheckInt = 17*256+17, %crypto:strong_rand_bytes(4),
+ Comment = <<>>,
+ PublicKey = <<?STRING(Type),?STRING(PubKey)>>,
+ CipherName = <<"none">>,
+ KdfName = <<"none">>,
+ KdfOptions = <<>>,
+ BlockSize = 8, % Crypto dependent
+ NumKeys = 1,
+ Encrypted0 = <<?UINT32(CheckInt),
+ ?UINT32(CheckInt),
+ ?STRING(Type),
+ ?STRING(PubKey),
+ ?STRING(<<PrivKey/binary,PubKey/binary>>),
+ ?STRING(Comment)
+ >>,
+ Pad = pad(size(Encrypted0), BlockSize),
+ Encrypted = <<Encrypted0/binary, Pad/binary>>,
+ <<"openssh-key-v1",0,
+ ?STRING(CipherName),
+ ?STRING(KdfName),
+ ?STRING(KdfOptions),
+ ?UINT32(NumKeys),
+ ?STRING(PublicKey),
+ ?STRING(Encrypted)>>.
+
+pad(N, BlockSize) when N>BlockSize -> pad(N rem BlockSize, BlockSize);
+pad(N, BlockSize) -> list_to_binary(lists:seq(1,BlockSize-N)).
+
+
openssh_decode(Bin, FileType) ->
Lines = binary:split(Bin, <<"\n">>, [global]),
do_openssh_decode(FileType, Lines, []).
@@ -233,6 +302,8 @@ do_openssh_decode(openssh_public_key = FileType, [Line | Lines], Acc) ->
<<"ssh-rsa">> -> true;
<<"ssh-dss">> -> true;
<<"ecdsa-sha2-",Curve/binary>> -> is_ssh_curvename(Curve);
+ <<"ssh-ed25519">> -> true;
+ <<"ssh-ed448">> -> true;
_ -> false
end,
@@ -245,7 +316,9 @@ do_openssh_decode(openssh_public_key = FileType, [Line | Lines], Acc) ->
Comment = string:strip(string_decode(iolist_to_binary(Comment0)), right, $\n),
do_openssh_decode(FileType, Lines,
[{openssh_pubkey_decode(KeyType, Base64Enc),
- [{comment, Comment}]} | Acc])
+ [{comment, Comment}]} | Acc]);
+ _ when KnownKeyType==false ->
+ do_openssh_decode(FileType, Lines, Acc)
end.
@@ -257,11 +330,11 @@ decode_comment(Comment) ->
openssh_pubkey_decode(Type, Base64Enc) ->
try
- <<?DEC_BIN(Type,_TL), Bin/binary>> = base64:mime_decode(Base64Enc),
+ <<?DEC_BIN(Type,_TL), Bin/binary>> = ?b64mime_dec(Base64Enc),
ssh2_pubkey_decode(Type, Bin)
catch
_:_ ->
- {Type, base64:mime_decode(Base64Enc)}
+ {Type, ?b64mime_dec(Base64Enc)}
end.
@@ -292,12 +365,12 @@ do_encode(Type, Key, Attributes) ->
rfc4716_encode(Key, [],[]) ->
iolist_to_binary([begin_marker(),"\n",
- split_lines(base64:encode(ssh2_pubkey_encode(Key))),
+ split_lines(?b64enc(ssh2_pubkey_encode(Key))),
"\n", end_marker(), "\n"]);
rfc4716_encode(Key, [], [_|_] = Acc) ->
iolist_to_binary([begin_marker(), "\n",
lists:reverse(Acc),
- split_lines(base64:encode(ssh2_pubkey_encode(Key))),
+ split_lines(?b64enc(ssh2_pubkey_encode(Key))),
"\n", end_marker(), "\n"]);
rfc4716_encode(Key, [ Header | Headers], Acc) ->
LinesStr = rfc4716_encode_header(Header),
@@ -326,7 +399,7 @@ rfc4716_encode_value(Value) ->
openssh_encode(openssh_public_key, Key, Attributes) ->
Comment = proplists:get_value(comment, Attributes, ""),
- Enc = base64:encode(ssh2_pubkey_encode(Key)),
+ Enc = ?b64enc(ssh2_pubkey_encode(Key)),
iolist_to_binary([key_type(Key), " ", Enc, " ", Comment, "\n"]);
openssh_encode(auth_keys, Key, Attributes) ->
@@ -351,10 +424,10 @@ openssh_encode(known_hosts, Key, Attributes) ->
end.
openssh_ssh2_auth_keys_encode(undefined, Key, Comment) ->
- iolist_to_binary([key_type(Key)," ", base64:encode(ssh2_pubkey_encode(Key)), line_end(Comment)]);
+ iolist_to_binary([key_type(Key)," ", ?b64enc(ssh2_pubkey_encode(Key)), line_end(Comment)]);
openssh_ssh2_auth_keys_encode(Options, Key, Comment) ->
iolist_to_binary([comma_list_encode(Options, []), " ",
- key_type(Key)," ", base64:encode(ssh2_pubkey_encode(Key)), line_end(Comment)]).
+ key_type(Key)," ", ?b64enc(ssh2_pubkey_encode(Key)), line_end(Comment)]).
openssh_ssh1_auth_keys_encode(undefined, Bits,
#'RSAPublicKey'{modulus = N, publicExponent = E},
@@ -369,7 +442,7 @@ openssh_ssh1_auth_keys_encode(Options, Bits,
openssh_ssh2_know_hosts_encode(Hostnames, Key, Comment) ->
iolist_to_binary([comma_list_encode(Hostnames, []), " ",
- key_type(Key)," ", base64:encode(ssh2_pubkey_encode(Key)), line_end(Comment)]).
+ key_type(Key)," ", ?b64enc(ssh2_pubkey_encode(Key)), line_end(Comment)]).
openssh_ssh1_known_hosts_encode(Hostnames, Bits,
#'RSAPublicKey'{modulus = N, publicExponent = E},
@@ -384,6 +457,10 @@ line_end(Comment) ->
key_type(#'RSAPublicKey'{}) -> <<"ssh-rsa">>;
key_type({_, #'Dss-Parms'{}}) -> <<"ssh-dss">>;
+key_type({ed_pub,ed25519,_}) -> <<"ssh-ed25519">>;
+key_type({ed_pub,ed448,_}) -> <<"ssh-ed448">>;
+key_type({ed_pri,ed25519,_,_}) -> <<"ssh-ed25519">>;
+key_type({ed_pri,ed448,_,_}) -> <<"ssh-ed448">>;
key_type({#'ECPoint'{}, {namedCurve,Curve}}) -> <<"ecdsa-sha2-", (public_key:oid2ssh_curvename(Curve))/binary>>.
comma_list_encode([Option], []) ->
@@ -402,7 +479,12 @@ ssh2_pubkey_encode({Y, #'Dss-Parms'{p = P, q = Q, g = G}}) ->
<<?STRING(<<"ssh-dss">>), ?Empint(P), ?Empint(Q), ?Empint(G), ?Empint(Y)>>;
ssh2_pubkey_encode(Key={#'ECPoint'{point = Q}, {namedCurve,OID}}) ->
Curve = public_key:oid2ssh_curvename(OID),
- <<?STRING(key_type(Key)), ?Estring(Curve), ?Estring(Q)>>.
+ <<?STRING(key_type(Key)), ?Estring(Curve), ?Estring(Q)>>;
+ssh2_pubkey_encode({ed_pub, ed25519, Key}) ->
+ <<?STRING(<<"ssh-ed25519">>), ?Estring(Key)>>;
+ssh2_pubkey_encode({ed_pub, ed448, Key}) ->
+ <<?STRING(<<"ssh-ed448">>), ?Estring(Key)>>.
+
ssh2_pubkey_decode(<<?DEC_BIN(Type,_TL), Bin/binary>>) ->
@@ -428,12 +510,23 @@ ssh2_pubkey_decode(<<"ssh-dss">>,
ssh2_pubkey_decode(<<"ecdsa-sha2-",Id/binary>>,
<<?DEC_BIN(Id, _IL),
?DEC_BIN(Q, _QL)>>) ->
- {#'ECPoint'{point = Q}, {namedCurve,public_key:ssh_curvename2oid(Id)}}.
+ {#'ECPoint'{point = Q}, {namedCurve,public_key:ssh_curvename2oid(Id)}};
+
+ssh2_pubkey_decode(<<"ssh-ed25519">>,
+ <<?DEC_BIN(Key, _L)>>) ->
+ {ed_pub, ed25519, Key};
+
+ssh2_pubkey_decode(<<"ssh-ed448">>,
+ <<?DEC_BIN(Key, _L)>>) ->
+ {ed_pub, ed448, Key}.
+
is_key_field(<<"ssh-dss">>) -> true;
is_key_field(<<"ssh-rsa">>) -> true;
+is_key_field(<<"ssh-ed25519">>) -> true;
+is_key_field(<<"ssh-ed448">>) -> true;
is_key_field(<<"ecdsa-sha2-",Id/binary>>) -> is_ssh_curvename(Id);
is_key_field(_) -> false.
diff --git a/lib/public_key/src/public_key.app.src b/lib/public_key/src/public_key.app.src
index dbd732c384..5833141e87 100644
--- a/lib/public_key/src/public_key.app.src
+++ b/lib/public_key/src/public_key.app.src
@@ -14,7 +14,7 @@
{applications, [asn1, crypto, kernel, stdlib]},
{registered, []},
{env, []},
- {runtime_dependencies, ["stdlib-2.0","kernel-3.0","erts-6.0","crypto-3.8",
+ {runtime_dependencies, ["stdlib-3.5","kernel-3.0","erts-6.0","crypto-3.8",
"asn1-3.0"]}
]
}.
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index 034126655c..47266c514c 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -49,6 +49,7 @@
pkix_normalize_name/1,
pkix_path_validation/3,
pkix_verify_hostname/2, pkix_verify_hostname/3,
+ pkix_verify_hostname_match_fun/1,
ssh_decode/2, ssh_encode/2,
ssh_hostkey_fingerprint/1, ssh_hostkey_fingerprint/2,
ssh_curvename2oid/1, oid2ssh_curvename/1,
@@ -65,19 +66,22 @@
-export_type([public_key/0, private_key/0, pem_entry/0,
pki_asn1_type/0, asn1_type/0, ssh_file/0, der_encoded/0,
- key_params/0, digest_type/0]).
+ key_params/0, digest_type/0, issuer_name/0, oid/0]).
--type public_key() :: rsa_public_key() | dsa_public_key() | ec_public_key().
--type private_key() :: rsa_private_key() | dsa_private_key() | ec_private_key().
+-type public_key() :: rsa_public_key() | dsa_public_key() | ec_public_key() | ed_public_key() .
+-type private_key() :: rsa_private_key() | dsa_private_key() | ec_private_key() | ed_private_key() .
-type rsa_public_key() :: #'RSAPublicKey'{}.
-type rsa_private_key() :: #'RSAPrivateKey'{}.
-type dsa_private_key() :: #'DSAPrivateKey'{}.
-type dsa_public_key() :: {integer(), #'Dss-Parms'{}}.
-type ecpk_parameters() :: {ecParameters, #'ECParameters'{}} | {namedCurve, Oid::tuple()}.
--type ecpk_parameters_api() :: ecpk_parameters() | #'ECParameters'{} | {namedCurve, Name::atom()}.
+-type ecpk_parameters_api() :: ecpk_parameters() | #'ECParameters'{} | {namedCurve, Name::crypto:ec_named_curve()}.
-type ec_public_key() :: {#'ECPoint'{}, ecpk_parameters_api()}.
-type ec_private_key() :: #'ECPrivateKey'{}.
+-type ed_public_key() :: {ed_pub, ed25519|ed448, Key::binary()}.
+-type ed_private_key() :: {ed_pri, ed25519|ed448, Pub::binary(), Priv::binary()}.
+
-type key_params() :: #'DHParameter'{} | {namedCurve, oid()} | #'ECParameters'{} |
{rsa, Size::integer(), PubExp::integer()}.
-type der_encoded() :: binary().
@@ -87,28 +91,42 @@
'CertificationRequest' | 'CertificateList' |
'ECPrivateKey' | 'EcpkParameters'.
-type pem_entry() :: {pki_asn1_type(),
- binary(), %% DER or Encrypted DER
- not_encrypted | {Cipher :: string(), Salt :: binary()} |
- {Cipher :: string(), #'PBES2-params'{}} |
- {Cipher :: string(), {#'PBEParameter'{}, atom()}} %% hash type
+ der_or_encrypted_der(),
+ not_encrypted | cipher_info()
}.
+-type der_or_encrypted_der() :: binary().
+-type cipher_info() :: {cipher(),
+ cipher_info_params()} .
+-type cipher() :: string() . % "RC2-CBC" | "DES-CBC" | "DES-EDE3-CBC",
+-type cipher_info_params() :: salt()
+ | {#'PBEParameter'{}, digest_type()}
+ | #'PBES2-params'{} .
+
+-type salt() :: binary(). % crypto:strong_rand_bytes(8)
+%% -type cipher_info() :: {Cipher :: string(), Salt :: binary()} |
+%% {Cipher :: string(), #'PBES2-params'{}} |
+%% {Cipher :: string(), {#'PBEParameter'{}, atom()}} %% hash type
+%% .
+
-type asn1_type() :: atom(). %% see "OTP-PUB-KEY.hrl
-type ssh_file() :: openssh_public_key | rfc4716_public_key | known_hosts |
auth_keys.
--type rsa_padding() :: 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding'
- | 'rsa_no_padding'.
--type rsa_sign_padding() :: 'rsa_pkcs1_padding' | 'rsa_pkcs1_pss_padding'.
--type public_crypt_options() :: [{rsa_pad, rsa_padding()}].
--type rsa_digest_type() :: 'md5' | 'ripemd160' | 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'.
--type dss_digest_type() :: 'none' | 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'. %% None is for backwards compatibility
--type ecdsa_digest_type() :: 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'.
--type public_sign_options() :: [{rsa_pad, rsa_sign_padding()} | {rsa_pss_saltlen, integer()}].
--type digest_type() :: rsa_digest_type() | dss_digest_type() | ecdsa_digest_type().
+-type digest_type() :: none % None is for backwards compatibility
+ | sha1 % Backwards compatibility
+ | crypto:rsa_digest_type()
+ | crypto:dss_digest_type()
+ | crypto:ecdsa_digest_type().
-type crl_reason() :: unspecified | keyCompromise | cACompromise | affiliationChanged | superseded
| cessationOfOperation | certificateHold | privilegeWithdrawn | aACompromise.
-type oid() :: tuple().
-type chain_type() :: server_chain | client_chain.
+-type issuer_id() :: {SerialNr::integer(), issuer_name()} .
+
+-type issuer_name() :: {rdnSequence,[#'AttributeTypeAndValue'{}]} .
+
+
+
-define(UINT32(X), X:32/unsigned-big-integer).
-define(DER_NULL, <<5, 0>>).
@@ -133,11 +151,11 @@ pem_encode(PemEntries) when is_list(PemEntries) ->
iolist_to_binary(pubkey_pem:encode(PemEntries)).
%%--------------------------------------------------------------------
--spec pem_entry_decode(pem_entry(), string()) -> term().
-%
%% Description: Decodes a pem entry. pem_decode/1 returns a list of
%% pem entries.
%%--------------------------------------------------------------------
+-spec pem_entry_decode(PemEntry) -> term() when PemEntry :: pem_entry() .
+
pem_entry_decode({'SubjectPublicKeyInfo', Der, _}) ->
{_, {'AlgorithmIdentifier', AlgId, Params}, Key0}
= der_decode('SubjectPublicKeyInfo', Der),
@@ -152,9 +170,14 @@ pem_entry_decode({'SubjectPublicKeyInfo', Der, _}) ->
ECCParams = der_decode('EcpkParameters', Params),
{#'ECPoint'{point = Key0}, ECCParams}
end;
+pem_entry_decode({{no_asn1,new_openssh}, Special, not_encrypted}) ->
+ ssh_decode(Special, new_openssh);
pem_entry_decode({Asn1Type, Der, not_encrypted}) when is_atom(Asn1Type),
is_binary(Der) ->
der_decode(Asn1Type, Der).
+
+-spec pem_entry_decode(PemEntry, Password) -> term() when PemEntry :: pem_entry(),
+ Password :: string() .
pem_entry_decode({Asn1Type, Der, not_encrypted}, _) when is_atom(Asn1Type),
is_binary(Der) ->
der_decode(Asn1Type, Der);
@@ -180,11 +203,12 @@ pem_entry_decode({Asn1Type, CryptDer, {Cipher, Salt}} = PemEntry,
%%--------------------------------------------------------------------
--spec pem_entry_encode(pki_asn1_type(), term()) -> pem_entry().
--spec pem_entry_encode(pki_asn1_type(), term(), term()) -> pem_entry().
%%
%% Description: Creates a pem entry that can be feed to pem_encode/1.
%%--------------------------------------------------------------------
+-spec pem_entry_encode(Asn1Type, Entity) -> pem_entry() when Asn1Type :: pki_asn1_type(),
+ Entity :: term() .
+
pem_entry_encode('SubjectPublicKeyInfo', Entity=#'RSAPublicKey'{}) ->
Der = der_encode('RSAPublicKey', Entity),
Spki = {'SubjectPublicKeyInfo',
@@ -207,6 +231,13 @@ pem_entry_encode('SubjectPublicKeyInfo',
pem_entry_encode(Asn1Type, Entity) when is_atom(Asn1Type) ->
Der = der_encode(Asn1Type, Entity),
{Asn1Type, Der, not_encrypted}.
+
+-spec pem_entry_encode(Asn1Type, Entity, InfoPwd) ->
+ pem_entry() when Asn1Type :: pki_asn1_type(),
+ Entity :: term(),
+ InfoPwd :: {CipherInfo,Password},
+ CipherInfo :: cipher_info(),
+ Password :: string() .
pem_entry_encode(Asn1Type, Entity, {{Cipher, #'PBES2-params'{}} = CipherInfo,
Password}) when is_atom(Asn1Type) andalso
is_list(Password) andalso
@@ -228,7 +259,9 @@ pem_entry_encode(Asn1Type, Entity, {{Cipher, Salt} = CipherInfo,
do_pem_entry_encode(Asn1Type, Entity, CipherInfo, Password).
%%--------------------------------------------------------------------
--spec der_decode(asn1_type(), Der::binary()) -> term().
+-spec der_decode(Asn1Type, Der) -> Entity when Asn1Type :: asn1_type(),
+ Der :: binary(),
+ Entity :: term().
%%
%% Description: Decodes a public key asn1 der encoded entity.
%%--------------------------------------------------------------------
@@ -237,7 +270,7 @@ der_decode(Asn1Type, Der) when (Asn1Type == 'PrivateKeyInfo') or
andalso is_binary(Der) ->
try
{ok, Decoded} = 'PKCS-FRAME':decode(Asn1Type, Der),
- Decoded
+ der_priv_key_decode(Decoded)
catch
error:{badmatch, {error, _}} = Error ->
erlang:error(Error)
@@ -252,12 +285,47 @@ der_decode(Asn1Type, Der) when is_atom(Asn1Type), is_binary(Der) ->
erlang:error(Error)
end.
-%%--------------------------------------------------------------------
--spec der_encode(asn1_type(), term()) -> Der::binary().
+der_priv_key_decode({'PrivateKeyInfo', v1,
+ {'PrivateKeyInfo_privateKeyAlgorithm', ?'id-ecPublicKey', {asn1_OPENTYPE, Parameters}}, PrivKey, _}) ->
+ EcPrivKey = der_decode('ECPrivateKey', PrivKey),
+ EcPrivKey#'ECPrivateKey'{parameters = der_decode('EcpkParameters', Parameters)};
+der_priv_key_decode({'PrivateKeyInfo', v1,
+ {'PrivateKeyInfo_privateKeyAlgorithm', ?'rsaEncryption', _}, PrivKey, _}) ->
+ der_decode('RSAPrivateKey', PrivKey);
+der_priv_key_decode({'PrivateKeyInfo', v1,
+ {'PrivateKeyInfo_privateKeyAlgorithm', ?'id-dsa', {asn1_OPENTYPE, Parameters}}, PrivKey, _}) ->
+ {params, #'Dss-Parms'{p=P, q=Q, g=G}} = der_decode('DSAParams', Parameters),
+ X = der_decode('Prime-p', PrivKey),
+ #'DSAPrivateKey'{p=P, q=Q, g=G, x=X};
+der_priv_key_decode(PKCS8Key) ->
+ PKCS8Key.
+
+%%--------------------------------------------------------------------
+-spec der_encode(Asn1Type, Entity) -> Der when Asn1Type :: asn1_type(),
+ Entity :: term(),
+ Der :: binary() .
%%
%% Description: Encodes a public key entity with asn1 DER encoding.
%%--------------------------------------------------------------------
-der_encode(Asn1Type, Entity) when (Asn1Type == 'PrivateKeyInfo') or
+
+der_encode('PrivateKeyInfo', #'DSAPrivateKey'{p=P, q=Q, g=G, x=X}) ->
+ der_encode('PrivateKeyInfo',
+ {'PrivateKeyInfo', v1,
+ {'PrivateKeyInfo_privateKeyAlgorithm', ?'id-dsa',
+ {asn1_OPENTYPE, der_encode('Dss-Parms', #'Dss-Parms'{p=P, q=Q, g=G})}},
+ der_encode('Prime-p', X), asn1_NOVALUE});
+der_encode('PrivateKeyInfo', #'RSAPrivateKey'{} = PrivKey) ->
+ der_encode('PrivateKeyInfo',
+ {'PrivateKeyInfo', v1,
+ {'PrivateKeyInfo_privateKeyAlgorithm', ?'rsaEncryption', {asn1_OPENTYPE, ?DER_NULL}},
+ der_encode('RSAPrivateKey', PrivKey), asn1_NOVALUE});
+der_encode('PrivateKeyInfo', #'ECPrivateKey'{parameters = Parameters} = PrivKey) ->
+ der_encode('PrivateKeyInfo',
+ {'PrivateKeyInfo', v1,
+ {'PrivateKeyInfo_privateKeyAlgorithm', ?'id-ecPublicKey',
+ {asn1_OPENTYPE, der_encode('EcpkParameters', Parameters)}},
+ der_encode('ECPrivateKey', PrivKey#'ECPrivateKey'{parameters = asn1_NOVALUE}), asn1_NOVALUE});
+der_encode(Asn1Type, Entity) when (Asn1Type == 'PrivateKeyInfo') or
(Asn1Type == 'EncryptedPrivateKeyInfo') ->
try
{ok, Encoded} = 'PKCS-FRAME':encode(Asn1Type, Entity),
@@ -277,8 +345,10 @@ der_encode(Asn1Type, Entity) when is_atom(Asn1Type) ->
end.
%%--------------------------------------------------------------------
--spec pkix_decode_cert(Cert::binary(), plain | otp) ->
- #'Certificate'{} | #'OTPCertificate'{}.
+-spec pkix_decode_cert(Cert, Type) ->
+ #'Certificate'{} | #'OTPCertificate'{}
+ when Cert :: der_encoded(),
+ Type :: plain | otp .
%%
%% Description: Decodes an asn1 der encoded pkix certificate. The otp
%% option will use the customized asn1 specification OTP-PKIX.asn1 for
@@ -298,7 +368,11 @@ pkix_decode_cert(DerCert, otp) when is_binary(DerCert) ->
end.
%%--------------------------------------------------------------------
--spec pkix_encode(asn1_type(), term(), otp | plain) -> Der::binary().
+-spec pkix_encode(Asn1Type, Entity, Type) -> Der
+ when Asn1Type :: asn1_type(),
+ Entity :: term(),
+ Type :: otp | plain,
+ Der :: der_encoded() .
%%
%% Description: Der encodes a certificate or part of a certificate.
%% This function must be used for encoding certificates or parts of certificates
@@ -313,80 +387,90 @@ pkix_encode(Asn1Type, Term0, otp) when is_atom(Asn1Type) ->
der_encode(Asn1Type, Term).
%%--------------------------------------------------------------------
--spec decrypt_private(CipherText :: binary(), rsa_private_key()) ->
- PlainText :: binary().
--spec decrypt_private(CipherText :: binary(), rsa_private_key(),
- public_crypt_options()) -> PlainText :: binary().
%%
%% Description: Public key decryption using the private key.
%%--------------------------------------------------------------------
+-spec decrypt_private(CipherText, Key) ->
+ PlainText when CipherText :: binary(),
+ Key :: rsa_private_key(),
+ PlainText :: binary() .
decrypt_private(CipherText, Key) ->
decrypt_private(CipherText, Key, []).
+-spec decrypt_private(CipherText, Key, Options) ->
+ PlainText when CipherText :: binary(),
+ Key :: rsa_private_key(),
+ Options :: crypto:pk_encrypt_decrypt_opts(),
+ PlainText :: binary() .
decrypt_private(CipherText,
#'RSAPrivateKey'{} = Key,
Options)
when is_binary(CipherText),
is_list(Options) ->
- Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
- crypto:private_decrypt(rsa, CipherText, format_rsa_private_key(Key), Padding).
+ crypto:private_decrypt(rsa, CipherText, format_rsa_private_key(Key), default_options(Options)).
%%--------------------------------------------------------------------
--spec decrypt_public(CipherText :: binary(), rsa_public_key() | rsa_private_key()) ->
- PlainText :: binary().
--spec decrypt_public(CipherText :: binary(), rsa_public_key() | rsa_private_key(),
- public_crypt_options()) -> PlainText :: binary().
-%% NOTE: The rsa_private_key() is not part of the documented API it is
-%% here for testing purposes, in a real situation this is not a relevant
-%% thing to do.
-%%
%% Description: Public key decryption using the public key.
%%--------------------------------------------------------------------
+-spec decrypt_public(CipherText, Key) ->
+ PlainText
+ when CipherText :: binary(),
+ Key :: rsa_public_key(),
+ PlainText :: binary() .
decrypt_public(CipherText, Key) ->
decrypt_public(CipherText, Key, []).
+-spec decrypt_public(CipherText, Key, Options) ->
+ PlainText
+ when CipherText :: binary(),
+ Key :: rsa_public_key(),
+ Options :: crypto:pk_encrypt_decrypt_opts(),
+ PlainText :: binary() .
decrypt_public(CipherText, #'RSAPublicKey'{modulus = N, publicExponent = E},
Options) when is_binary(CipherText), is_list(Options) ->
- decrypt_public(CipherText, N,E, Options);
-
-decrypt_public(CipherText,#'RSAPrivateKey'{modulus = N, publicExponent = E},
- Options) when is_binary(CipherText), is_list(Options) ->
- decrypt_public(CipherText, N,E, Options).
+ crypto:public_decrypt(rsa, CipherText,[E, N], default_options(Options)).
%%--------------------------------------------------------------------
--spec encrypt_public(PlainText :: binary(), rsa_public_key() | rsa_private_key()) ->
- CipherText :: binary().
--spec encrypt_public(PlainText :: binary(), rsa_public_key() | rsa_private_key(),
- public_crypt_options()) -> CipherText :: binary().
-
-%% NOTE: The rsa_private_key() is not part of the documented API it is
-%% here for testing purposes, in a real situation this is not a relevant
-%% thing to do.
-%%
%% Description: Public key encryption using the public key.
%%--------------------------------------------------------------------
+-spec encrypt_public(PlainText, Key) ->
+ CipherText
+ when PlainText :: binary(),
+ Key :: rsa_public_key(),
+ CipherText :: binary() .
encrypt_public(PlainText, Key) ->
encrypt_public(PlainText, Key, []).
-encrypt_public(PlainText, #'RSAPublicKey'{modulus=N,publicExponent=E},
- Options) when is_binary(PlainText), is_list(Options) ->
- encrypt_public(PlainText, N,E, Options);
-encrypt_public(PlainText, #'RSAPrivateKey'{modulus=N,publicExponent=E},
+-spec encrypt_public(PlainText, Key, Options) ->
+ CipherText
+ when PlainText :: binary(),
+ Key :: rsa_public_key(),
+ Options :: crypto:pk_encrypt_decrypt_opts(),
+ CipherText :: binary() .
+encrypt_public(PlainText, #'RSAPublicKey'{modulus=N,publicExponent=E},
Options) when is_binary(PlainText), is_list(Options) ->
- encrypt_public(PlainText, N,E, Options).
+ crypto:public_encrypt(rsa, PlainText, [E,N], default_options(Options)).
%%--------------------------------------------------------------------
--spec encrypt_private(PlainText :: binary(), rsa_private_key()) ->
- CipherText :: binary().
--spec encrypt_private(PlainText :: binary(), rsa_private_key(),
- public_crypt_options()) -> CipherText :: binary().
%%
%% Description: Public key encryption using the private key.
%%--------------------------------------------------------------------
+-spec encrypt_private(PlainText, Key) ->
+ CipherText
+ when PlainText :: binary(),
+ Key :: rsa_private_key(),
+ CipherText :: binary() .
encrypt_private(PlainText, Key) ->
encrypt_private(PlainText, Key, []).
+
+-spec encrypt_private(PlainText, Key, Options) ->
+ CipherText
+ when PlainText :: binary(),
+ Key :: rsa_private_key(),
+ Options :: crypto:pk_encrypt_decrypt_opts(),
+ CipherText :: binary() .
encrypt_private(PlainText,
#'RSAPrivateKey'{modulus = N, publicExponent = E,
privateExponent = D} = Key,
@@ -394,26 +478,45 @@ encrypt_private(PlainText,
when is_binary(PlainText),
is_integer(N), is_integer(E), is_integer(D),
is_list(Options) ->
- Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
- crypto:private_encrypt(rsa, PlainText, format_rsa_private_key(Key), Padding).
+ crypto:private_encrypt(rsa, PlainText, format_rsa_private_key(Key), default_options(Options)).
%%--------------------------------------------------------------------
+%% Description: List available group sizes among the pre-computed dh groups
+%%--------------------------------------------------------------------
+-spec dh_gex_group_sizes() -> [pos_integer()].
dh_gex_group_sizes() ->
pubkey_ssh:dh_gex_group_sizes().
+%%--------------------------------------------------------------------
+%% Description: Select a precomputed group
+%%--------------------------------------------------------------------
+-spec dh_gex_group(MinSize, SuggestedSize, MaxSize, Groups) ->
+ {ok,{Size,Group}} | {error,term()}
+ when MinSize :: pos_integer(),
+ SuggestedSize :: pos_integer(),
+ MaxSize :: pos_integer(),
+ Groups :: undefined | [{Size,[Group]}],
+ Size :: pos_integer(),
+ Group :: {G,P},
+ G :: pos_integer(),
+ P :: pos_integer() .
dh_gex_group(Min, N, Max, Groups) ->
pubkey_ssh:dh_gex_group(Min, N, Max, Groups).
%%--------------------------------------------------------------------
--spec generate_key(#'DHParameter'{}) ->
- {Public::binary(), Private::binary()};
- (ecpk_parameters_api()) ->
- #'ECPrivateKey'{};
- ({rsa, Size::pos_integer(), PubExp::pos_integer()}) ->
- #'RSAPrivateKey'{}.
-
-%% Description: Generates a new keypair
+%% Description: Generate a new key pair
%%--------------------------------------------------------------------
+-spec generate_key(DHparams | ECparams | RSAparams) ->
+ DHkeys | ECkey | RSAkey
+ when DHparams :: #'DHParameter'{},
+ DHkeys :: {PublicDH::binary(), PrivateDH::binary()},
+ ECparams :: ecpk_parameters_api(),
+ ECkey :: #'ECPrivateKey'{},
+ RSAparams :: {rsa, Size, PubExp},
+ Size::pos_integer(),
+ PubExp::pos_integer(),
+ RSAkey :: #'RSAPrivateKey'{} .
+
generate_key(#'DHParameter'{prime = P, base = G}) ->
crypto:generate_key(dh, [P, G]);
generate_key({namedCurve, _} = Params) ->
@@ -460,24 +563,34 @@ generate_key({rsa, ModulusSize, PublicExponent}) ->
end.
%%--------------------------------------------------------------------
--spec compute_key(#'ECPoint'{} , #'ECPrivateKey'{}) -> binary().
--spec compute_key(OthersKey ::binary(), MyKey::binary(), #'DHParameter'{}) -> binary().
%% Description: Compute shared secret
%%--------------------------------------------------------------------
+-spec compute_key(OthersECDHkey, MyECDHkey) ->
+ SharedSecret
+ when OthersECDHkey :: #'ECPoint'{},
+ MyECDHkey :: #'ECPrivateKey'{},
+ SharedSecret :: binary().
compute_key(#'ECPoint'{point = Point}, #'ECPrivateKey'{privateKey = PrivKey,
parameters = Param}) ->
ECCurve = ec_curve_spec(Param),
crypto:compute_key(ecdh, Point, PrivKey, ECCurve).
+-spec compute_key(OthersDHkey, MyDHkey, DHparms) ->
+ SharedSecret
+ when OthersDHkey :: crypto:dh_public(), % Was: binary(),
+ MyDHkey :: crypto:dh_private(), % Was: binary(),
+ DHparms :: #'DHParameter'{},
+ SharedSecret :: binary().
compute_key(PubKey, PrivKey, #'DHParameter'{prime = P, base = G}) ->
crypto:compute_key(dh, PubKey, PrivKey, [P, G]).
%%--------------------------------------------------------------------
--spec pkix_sign_types(SignatureAlg::oid()) ->
- %% Relevant dsa digest type is subpart of rsa digest type
- { DigestType :: rsa_digest_type(),
- SignatureType :: rsa | dsa | ecdsa
- }.
+-spec pkix_sign_types(AlgorithmId) ->
+ {DigestType, SignatureType}
+ when AlgorithmId :: oid(),
+ %% Relevant dsa digest type is a subset of rsa_digest_type()
+ DigestType :: crypto:rsa_digest_type(),
+ SignatureType :: rsa | dsa | ecdsa .
%% Description:
%%--------------------------------------------------------------------
pkix_sign_types(?sha1WithRSAEncryption) ->
@@ -498,6 +611,10 @@ pkix_sign_types(?'id-dsa-with-sha1') ->
{sha, dsa};
pkix_sign_types(?'id-dsaWithSHA1') ->
{sha, dsa};
+pkix_sign_types(?'id-dsa-with-sha224') ->
+ {sha224, dsa};
+pkix_sign_types(?'id-dsa-with-sha256') ->
+ {sha256, dsa};
pkix_sign_types(?'ecdsa-with-SHA1') ->
{sha, ecdsa};
pkix_sign_types(?'ecdsa-with-SHA256') ->
@@ -508,24 +625,24 @@ pkix_sign_types(?'ecdsa-with-SHA512') ->
{sha512, ecdsa}.
%%--------------------------------------------------------------------
--spec sign(binary() | {digest, binary()},
- rsa_digest_type() | dss_digest_type() | ecdsa_digest_type(),
- rsa_private_key() | dsa_private_key() | ec_private_key()
- ) -> Signature :: binary().
-
--spec sign(binary() | {digest, binary()},
- rsa_digest_type() | dss_digest_type() | ecdsa_digest_type(),
- rsa_private_key() | dsa_private_key() | ec_private_key(),
- public_sign_options()
- ) -> Signature :: binary().
-
%% Description: Create digital signature.
%%--------------------------------------------------------------------
+-spec sign(Msg, DigestType, Key) ->
+ Signature when Msg :: binary() | {digest,binary()},
+ DigestType :: digest_type(),
+ Key :: private_key(),
+ Signature :: binary() .
sign(DigestOrPlainText, DigestType, Key) ->
sign(DigestOrPlainText, DigestType, Key, []).
-%% Backwards compatible
+-spec sign(Msg, DigestType, Key, Options) ->
+ Signature when Msg :: binary() | {digest,binary()},
+ DigestType :: digest_type(),
+ Key :: private_key(),
+ Options :: crypto:pk_sign_verify_opts(),
+ Signature :: binary() .
sign(Digest, none, Key = #'DSAPrivateKey'{}, Options) when is_binary(Digest) ->
+ %% Backwards compatible
sign({digest, Digest}, sha, Key, Options);
sign(DigestOrPlainText, DigestType, Key, Options) ->
case format_sign_key(Key) of
@@ -536,30 +653,26 @@ sign(DigestOrPlainText, DigestType, Key, Options) ->
end.
%%--------------------------------------------------------------------
--spec verify(binary() | {digest, binary()},
- rsa_digest_type() | dss_digest_type() | ecdsa_digest_type(),
- Signature :: binary(),
- rsa_public_key() | dsa_public_key() | ec_public_key()
- | rsa_private_key() | dsa_private_key() | ec_private_key()
- ) -> boolean().
-
--spec verify(binary() | {digest, binary()},
- rsa_digest_type() | dss_digest_type() | ecdsa_digest_type(),
- Signature :: binary(),
- rsa_public_key() | dsa_public_key() | ec_public_key()
- | rsa_private_key() | dsa_private_key() | ec_private_key(),
- public_sign_options()
- ) -> boolean().
-
%% Description: Verifies a digital signature.
%%--------------------------------------------------------------------
+-spec verify(Msg, DigestType, Signature, Key) ->
+ boolean() when Msg :: binary() | {digest, binary()},
+ DigestType :: digest_type(),
+ Signature :: binary(),
+ Key :: public_key() .
+
verify(DigestOrPlainText, DigestType, Signature, Key) ->
verify(DigestOrPlainText, DigestType, Signature, Key, []).
-%% Backwards compatible
+-spec verify(Msg, DigestType, Signature, Key, Options) ->
+ boolean() when Msg :: binary() | {digest, binary()},
+ DigestType :: digest_type(),
+ Signature :: binary(),
+ Key :: public_key(),
+ Options :: crypto:pk_sign_verify_opts().
+
verify(Digest, none, Signature, Key = {_, #'Dss-Parms'{}}, Options) when is_binary(Digest) ->
- verify({digest, Digest}, sha, Signature, Key, Options);
-verify(Digest, none, Signature, Key = #'DSAPrivateKey'{}, Options) when is_binary(Digest) ->
+ %% Backwards compatible
verify({digest, Digest}, sha, Signature, Key, Options);
verify(DigestOrPlainText, DigestType, Signature, Key, Options) when is_binary(Signature) ->
case format_verify_key(Key) of
@@ -574,8 +687,8 @@ verify(_,_,_,_,_) ->
false.
%%--------------------------------------------------------------------
--spec pkix_dist_point(der_encoded() | #'OTPCertificate'{}) ->
- #'DistributionPoint'{}.
+-spec pkix_dist_point(Cert) -> DistPoint when Cert :: der_encoded() | #'OTPCertificate'{},
+ DistPoint :: #'DistributionPoint'{}.
%% Description: Creates a distribution point for CRLs issued by the same issuer as <c>Cert</c>.
%%--------------------------------------------------------------------
pkix_dist_point(OtpCert) when is_binary(OtpCert) ->
@@ -598,8 +711,8 @@ pkix_dist_point(OtpCert) ->
reasons = asn1_NOVALUE,
distributionPoint = Point}.
%%--------------------------------------------------------------------
--spec pkix_dist_points(der_encoded() | #'OTPCertificate'{}) ->
- [#'DistributionPoint'{}].
+-spec pkix_dist_points(Cert) -> DistPoints when Cert :: der_encoded() | #'OTPCertificate'{},
+ DistPoints :: [ #'DistributionPoint'{} ].
%% Description: Extracts distributionpoints specified in the certificates extensions.
%%--------------------------------------------------------------------
pkix_dist_points(OtpCert) when is_binary(OtpCert) ->
@@ -613,8 +726,10 @@ pkix_dist_points(OtpCert) ->
[], Value).
%%--------------------------------------------------------------------
--spec pkix_match_dist_point(der_encoded() | #'CertificateList'{},
- #'DistributionPoint'{}) -> boolean().
+-spec pkix_match_dist_point(CRL, DistPoint) ->
+ boolean()
+ when CRL :: der_encoded() | #'CertificateList'{},
+ DistPoint :: #'DistributionPoint'{}.
%% Description: Check whether the given distribution point matches
%% the "issuing distribution point" of the CRL.
%%--------------------------------------------------------------------
@@ -645,8 +760,9 @@ pkix_match_dist_point(#'CertificateList'{
end.
%%--------------------------------------------------------------------
--spec pkix_sign(#'OTPTBSCertificate'{},
- rsa_private_key() | dsa_private_key() | ec_private_key()) -> Der::binary().
+-spec pkix_sign(Cert, Key) -> Der when Cert :: #'OTPTBSCertificate'{},
+ Key :: private_key(),
+ Der :: der_encoded() .
%%
%% Description: Sign a pkix x.509 certificate. Returns the corresponding
%% der encoded 'Certificate'{}
@@ -665,8 +781,8 @@ pkix_sign(#'OTPTBSCertificate'{signature =
pkix_encode('OTPCertificate', Cert, otp).
%%--------------------------------------------------------------------
--spec pkix_verify(Cert::binary(), rsa_public_key()|
- dsa_public_key() | ec_public_key()) -> boolean().
+-spec pkix_verify(Cert, Key) -> boolean() when Cert :: der_encoded(),
+ Key :: public_key() .
%%
%% Description: Verify pkix x.509 certificate signature.
%%--------------------------------------------------------------------
@@ -686,7 +802,9 @@ pkix_verify(DerCert, Key = {#'ECPoint'{}, _})
verify(PlainText, DigestType, Signature, Key).
%%--------------------------------------------------------------------
--spec pkix_crl_verify(CRL::binary() | #'CertificateList'{}, Cert::binary() | #'OTPCertificate'{}) -> boolean().
+-spec pkix_crl_verify(CRL, Cert) -> boolean()
+ when CRL :: der_encoded() | #'CertificateList'{},
+ Cert :: der_encoded() | #'OTPCertificate'{} .
%%
%% Description: Verify that Cert is the CRL signer.
%%--------------------------------------------------------------------
@@ -705,9 +823,12 @@ pkix_crl_verify(#'CertificateList'{} = CRL, #'OTPCertificate'{} = Cert) ->
PublicKey, PublicKeyParams).
%%--------------------------------------------------------------------
--spec pkix_is_issuer(Cert :: der_encoded()| #'OTPCertificate'{} | #'CertificateList'{},
- IssuerCert :: der_encoded()|
- #'OTPCertificate'{}) -> boolean().
+-spec pkix_is_issuer(Cert, IssuerCert) ->
+ boolean() when Cert :: der_encoded()
+ | #'OTPCertificate'{}
+ | #'CertificateList'{},
+ IssuerCert :: der_encoded()
+ | #'OTPCertificate'{} .
%%
%% Description: Checks if <IssuerCert> issued <Cert>.
%%--------------------------------------------------------------------
@@ -727,7 +848,7 @@ pkix_is_issuer(#'CertificateList'{tbsCertList = TBSCRL},
pubkey_cert_records:transform(TBSCRL#'TBSCertList'.issuer, decode)).
%%--------------------------------------------------------------------
--spec pkix_is_self_signed(Cert::binary()| #'OTPCertificate'{}) -> boolean().
+-spec pkix_is_self_signed(Cert) -> boolean() when Cert::der_encoded()| #'OTPCertificate'{}.
%%
%% Description: Checks if a Certificate is self signed.
%%--------------------------------------------------------------------
@@ -738,7 +859,7 @@ pkix_is_self_signed(Cert) when is_binary(Cert) ->
pkix_is_self_signed(OtpCert).
%%--------------------------------------------------------------------
--spec pkix_is_fixed_dh_cert(Cert::binary()| #'OTPCertificate'{}) -> boolean().
+-spec pkix_is_fixed_dh_cert(Cert) -> boolean() when Cert::der_encoded()| #'OTPCertificate'{}.
%%
%% Description: Checks if a Certificate is a fixed Diffie-Hellman Cert.
%%--------------------------------------------------------------------
@@ -749,13 +870,12 @@ pkix_is_fixed_dh_cert(Cert) when is_binary(Cert) ->
pkix_is_fixed_dh_cert(OtpCert).
%%--------------------------------------------------------------------
--spec pkix_issuer_id(Cert::binary()| #'OTPCertificate'{},
- IssuedBy :: self | other) ->
- {ok, {SerialNr :: integer(),
- Issuer :: {rdnSequence,
- [#'AttributeTypeAndValue'{}]}}}
- | {error, Reason :: term()}.
-%
+-spec pkix_issuer_id(Cert, IssuedBy) ->
+ {ok, issuer_id()} | {error, Reason}
+ when Cert::der_encoded()| #'OTPCertificate'{},
+ IssuedBy :: self | other,
+ Reason :: term() .
+
%% Description: Returns the issuer id.
%%--------------------------------------------------------------------
pkix_issuer_id(#'OTPCertificate'{} = OtpCert, Signed) when (Signed == self) or
@@ -766,9 +886,9 @@ pkix_issuer_id(Cert, Signed) when is_binary(Cert) ->
pkix_issuer_id(OtpCert, Signed).
%%--------------------------------------------------------------------
--spec pkix_crl_issuer(CRL::binary()| #'CertificateList'{}) ->
- {rdnSequence,
- [#'AttributeTypeAndValue'{}]}.
+-spec pkix_crl_issuer(CRL| #'CertificateList'{}) ->
+ Issuer when CRL :: der_encoded(),
+ Issuer :: issuer_name() .
%
%% Description: Returns the issuer.
%%--------------------------------------------------------------------
@@ -779,10 +899,9 @@ pkix_crl_issuer(#'CertificateList'{} = CRL) ->
CRL#'CertificateList'.tbsCertList#'TBSCertList'.issuer, decode).
%%--------------------------------------------------------------------
--spec pkix_normalize_name({rdnSequence,
- [#'AttributeTypeAndValue'{}]}) ->
- {rdnSequence,
- [#'AttributeTypeAndValue'{}]}.
+-spec pkix_normalize_name(Issuer) -> Normalized
+ when Issuer :: issuer_name(),
+ Normalized :: issuer_name() .
%%
%% Description: Normalizes a issuer name so that it can be easily
%% compared to another issuer name.
@@ -793,7 +912,7 @@ pkix_normalize_name(Issuer) ->
%%--------------------------------------------------------------------
-spec pkix_path_validation(Cert::binary()| #'OTPCertificate'{} | atom(),
CertChain :: [binary()] ,
- Options :: proplists:proplist()) ->
+ Options :: [{atom(),term()}]) ->
{ok, {PublicKeyInfo :: term(),
PolicyTree :: term()}} |
{error, {bad_cert, Reason :: term()}}.
@@ -829,11 +948,19 @@ pkix_path_validation(#'OTPCertificate'{} = TrustedCert, CertChain, Options)
path_validation(CertChain, ValidationState).
%--------------------------------------------------------------------
--spec pkix_crls_validate(#'OTPCertificate'{},
- [{DP::#'DistributionPoint'{}, {DerCRL::binary(), CRL::#'CertificateList'{}}}],
- Options :: proplists:proplist()) -> valid | {bad_cert, revocation_status_undetermined} |
- {bad_cert, {revocation_status_undetermined, Reason::term()}} |
- {bad_cert, {revoked, crl_reason()}}.
+-spec pkix_crls_validate(OTPcertificate, DPandCRLs, Options) ->
+ CRLstatus when OTPcertificate :: #'OTPCertificate'{},
+ DPandCRLs :: [DPandCRL],
+ DPandCRL :: {DP, {DerCRL, CRL}},
+ DP :: #'DistributionPoint'{},
+ DerCRL :: der_encoded(),
+ CRL :: #'CertificateList'{},
+ Options :: [{atom(),term()}],
+ CRLstatus :: valid
+ | {bad_cert, BadCertReason},
+ BadCertReason :: revocation_status_undetermined
+ | {revocation_status_undetermined, Reason::term()}
+ | {revoked, crl_reason()}.
%% Description: Performs a CRL validation according to RFC 5280.
%%--------------------------------------------------------------------
@@ -850,18 +977,31 @@ pkix_crls_validate(OtpCert, DPAndCRLs0, Options) ->
Options, pubkey_crl:init_revokation_state()).
%--------------------------------------------------------------------
--spec pkix_verify_hostname(Cert :: #'OTPCertificate'{} | binary(),
- ReferenceIDs :: [{uri_id | dns_id | ip | srv_id | oid(), string()}]) -> boolean().
+-type referenceIDs() :: [referenceID()] .
+-type referenceID() :: {uri_id | dns_id | ip | srv_id | oid(), string()}
+ | {ip, inet:ip_address()} .
--spec pkix_verify_hostname(Cert :: #'OTPCertificate'{} | binary(),
- ReferenceIDs :: [{uri_id | dns_id | ip | srv_id | oid(), string()}],
- Options :: proplists:proplist()) -> boolean().
+-type high_level_alg() :: https .
+-type match_fun() :: fun((ReferenceID::referenceID() | string(),
+ PresentedID::{atom()|oid(),string()}) -> match_fun_result() ) .
+-type match_fun_result() :: boolean() | default .
%% Description: Validates a hostname to RFC 6125
%%--------------------------------------------------------------------
+-spec pkix_verify_hostname(Cert, ReferenceIDs) -> boolean()
+ when Cert :: der_encoded()
+ | #'OTPCertificate'{},
+ ReferenceIDs :: referenceIDs() .
pkix_verify_hostname(Cert, ReferenceIDs) ->
pkix_verify_hostname(Cert, ReferenceIDs, []).
+-spec pkix_verify_hostname(Cert, ReferenceIDs, Options) ->
+ boolean()
+ when Cert :: der_encoded()
+ | #'OTPCertificate'{},
+ ReferenceIDs :: referenceIDs(),
+ Options :: [{atom(),term()}] .
+
pkix_verify_hostname(BinCert, ReferenceIDs, Options) when is_binary(BinCert) ->
pkix_verify_hostname(pkix_decode_cert(BinCert,otp), ReferenceIDs, Options);
@@ -920,10 +1060,26 @@ pkix_verify_hostname(Cert = #'OTPCertificate'{tbsCertificate = TbsCert}, Referen
end
end.
+
+-spec pkix_verify_hostname_match_fun(high_level_alg()) -> match_fun() .
+
+pkix_verify_hostname_match_fun(https) ->
+ fun({dns_id,FQDN=[_|_]}, {dNSName,Name=[_|_]}) -> verify_hostname_match_wildcard(FQDN, Name);
+ (_, _) -> default
+ end.
+
%%--------------------------------------------------------------------
--spec ssh_decode(binary(), public_key | ssh_file()) -> [{public_key(), Attributes::list()}]
- ; (binary(), ssh2_pubkey) -> public_key()
- .
+-spec ssh_decode(SshBin, Type) ->
+ Decoded
+ when SshBin :: binary(),
+ Type :: ssh2_pubkey | OtherType | InternalType,
+ OtherType :: public_key | ssh_file(),
+ InternalType :: new_openssh,
+ Decoded :: Decoded_ssh2_pubkey
+ | Decoded_OtherType,
+ Decoded_ssh2_pubkey :: public_key(),
+ Decoded_OtherType :: [{public_key(), Attributes}],
+ Attributes :: [{atom(),term()}] .
%%
%% Description: Decodes a ssh file-binary. In the case of know_hosts
%% or auth_keys the binary may include one or more lines of the
@@ -937,13 +1093,20 @@ ssh_decode(SshBin, Type) when is_binary(SshBin),
Type == openssh_public_key;
Type == auth_keys;
Type == known_hosts;
- Type == ssh2_pubkey ->
+ Type == ssh2_pubkey;
+ Type == new_openssh ->
pubkey_ssh:decode(SshBin, Type).
%%--------------------------------------------------------------------
--spec ssh_encode([{public_key(), Attributes::list()}], ssh_file()) -> binary()
- ; (public_key(), ssh2_pubkey) -> binary()
- .
+-spec ssh_encode(InData, Type) ->
+ binary()
+ when Type :: ssh2_pubkey | OtherType,
+ OtherType :: public_key | ssh_file(),
+ InData :: InData_ssh2_pubkey | OtherInData,
+ InData_ssh2_pubkey :: public_key(),
+ OtherInData :: [{Key,Attributes}],
+ Key :: public_key(),
+ Attributes :: [{atom(),term()}] .
%%
%% Description: Encodes a list of ssh file entries (public keys and
%% attributes) to a binary. Possible attributes depends on the file
@@ -978,13 +1141,14 @@ oid2ssh_curvename(?'secp521r1') -> <<"nistp521">>.
%%--------------------------------------------------------------------
-spec ssh_hostkey_fingerprint(public_key()) -> string().
--spec ssh_hostkey_fingerprint( digest_type(), public_key()) -> string()
- ; ([digest_type()], public_key()) -> [string()]
- .
ssh_hostkey_fingerprint(Key) ->
sshfp_string(md5, public_key:ssh_encode(Key,ssh2_pubkey) ).
+
+-spec ssh_hostkey_fingerprint( digest_type(), public_key()) -> string()
+ ; ([digest_type()], public_key()) -> [string()]
+ .
ssh_hostkey_fingerprint(HashAlgs, Key) when is_list(HashAlgs) ->
EncKey = public_key:ssh_encode(Key, ssh2_pubkey),
[sshfp_full_string(HashAlg,EncKey) || HashAlg <- HashAlgs];
@@ -1022,8 +1186,7 @@ fp_fmt(b64, Bin) ->
[lists:nth(C+1,B64Chars) || <<C:6>> <= <<Bin/binary,0:Padding>> ].
%%--------------------------------------------------------------------
--spec short_name_hash({rdnSequence, [#'AttributeTypeAndValue'{}]}) ->
- string().
+-spec short_name_hash(Name) -> string() when Name :: issuer_name() .
%% Description: Generates OpenSSL-style hash of a name.
%%--------------------------------------------------------------------
@@ -1054,10 +1217,11 @@ pkix_test_data(#{} = Chain) ->
pubkey_cert:gen_test_certs(maps:merge(Default, Chain)).
%%--------------------------------------------------------------------
--spec pkix_test_root_cert(
- Name :: string(), Opts :: [pubkey_cert:cert_opt()]) ->
- pubkey_cert:test_root_cert().
-
+-spec pkix_test_root_cert(Name, Options) ->
+ RootCert
+ when Name :: string(),
+ Options :: [{atom(),term()}], %[cert_opt()],
+ RootCert :: pubkey_cert:test_root_cert().
%% Description: Generates a root cert suitable for pkix_test_data/1
%%--------------------------------------------------------------------
@@ -1067,12 +1231,41 @@ pkix_test_root_cert(Name, Opts) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+default_options([]) ->
+ [{rsa_padding, rsa_pkcs1_padding}];
+default_options(Opts) ->
+ case proplists:get_value(rsa_pad, Opts) of
+ undefined ->
+ case proplists:get_value(rsa_padding, Opts) of
+ undefined ->
+ case lists:dropwhile(fun erlang:is_tuple/1, Opts) of
+ [Pad|_] ->
+ set_padding(Pad, Opts);
+ [] ->
+ set_padding(rsa_pkcs1_padding, Opts)
+ end;
+ Pad ->
+ set_padding(Pad, Opts)
+ end;
+ Pad ->
+ set_padding(Pad, Opts)
+ end.
+
+set_padding(Pad, Opts) ->
+ [{rsa_padding,Pad} | [{T,V} || {T,V} <- Opts,
+ T =/= rsa_padding,
+ T =/= rsa_pad]
+ ].
+
+
format_sign_key(Key = #'RSAPrivateKey'{}) ->
{rsa, format_rsa_private_key(Key)};
format_sign_key(#'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) ->
{dss, [P, Q, G, X]};
format_sign_key(#'ECPrivateKey'{privateKey = PrivKey, parameters = Param}) ->
{ecdsa, [PrivKey, ec_curve_spec(Param)]};
+format_sign_key({ed_pri, Curve, _Pub, Priv}) ->
+ {eddsa, [Priv,Curve]};
format_sign_key(_) ->
badarg.
@@ -1082,6 +1275,8 @@ format_verify_key({#'ECPoint'{point = Point}, Param}) ->
{ecdsa, [Point, ec_curve_spec(Param)]};
format_verify_key({Key, #'Dss-Parms'{p = P, q = Q, g = G}}) ->
{dss, [P, Q, G, Key]};
+format_verify_key({ed_pub, Curve, Key}) ->
+ {eddsa, [Key,Curve]};
%% Convert private keys to public keys
format_verify_key(#'RSAPrivateKey'{modulus = Mod, publicExponent = Exp}) ->
format_verify_key(#'RSAPublicKey'{modulus = Mod, publicExponent = Exp});
@@ -1103,14 +1298,6 @@ do_pem_entry_decode({Asn1Type,_, _} = PemEntry, Password) ->
Der = pubkey_pem:decipher(PemEntry, Password),
der_decode(Asn1Type, Der).
-encrypt_public(PlainText, N, E, Options)->
- Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
- crypto:public_encrypt(rsa, PlainText, [E,N], Padding).
-
-decrypt_public(CipherText, N,E, Options) ->
- Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
- crypto:public_decrypt(rsa, CipherText,[E, N], Padding).
-
path_validation([], #path_validation_state{working_public_key_algorithm
= Algorithm,
working_public_key =
@@ -1456,7 +1643,7 @@ ascii_to_lower(String) ->
verify_hostname_extract_fqdn_default({dns_id,S}) ->
S;
verify_hostname_extract_fqdn_default({uri_id,URI}) ->
- {ok,{https,_,Host,_,_,_}} = http_uri:parse(URI),
+ #{scheme := "https", host := Host} = uri_string:normalize(URI, [return_map]),
Host.
@@ -1483,9 +1670,7 @@ verify_hostname_match_default(Ref, Pres) ->
verify_hostname_match_default0(FQDN=[_|_], {cn,FQDN}) ->
not lists:member($*, FQDN);
verify_hostname_match_default0(FQDN=[_|_], {cn,Name=[_|_]}) ->
- [F1|Fs] = string:tokens(FQDN, "."),
- [N1|Ns] = string:tokens(Name, "."),
- match_wild(F1,N1) andalso Fs==Ns;
+ verify_hostname_match_wildcard(FQDN, Name);
verify_hostname_match_default0({dns_id,R}, {dNSName,P}) ->
R==P;
verify_hostname_match_default0({uri_id,R}, {uniformResourceIdentifier,P}) ->
@@ -1520,6 +1705,13 @@ verify_hostname_match_default0({srv_id,R}, {?srvName_OID,P}) ->
verify_hostname_match_default0(_, _) ->
false.
+
+verify_hostname_match_wildcard(FQDN, Name) ->
+ [F1|Fs] = string:tokens(FQDN, "."),
+ [N1|Ns] = string:tokens(Name, "."),
+ match_wild(F1,N1) andalso Fs==Ns.
+
+
ok({ok,X}) -> X.
l16_to_tup(L) -> list_to_tuple(l16_to_tup(L, [])).
diff --git a/lib/public_key/test/pbe_SUITE.erl b/lib/public_key/test/pbe_SUITE.erl
index 44caf479e5..1136267411 100644
--- a/lib/public_key/test/pbe_SUITE.erl
+++ b/lib/public_key/test/pbe_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -37,7 +37,7 @@ all() ->
[
pbdkdf1,
pbdkdf2,
- old_enc,
+ old_pbe,
pbes1,
pbes2].
@@ -197,23 +197,11 @@ pbdkdf2(Config) when is_list(Config) ->
= pubkey_pbe:pbdkdf2("pass\0word",
"sa\0lt", 4096, 16, fun crypto:hmac/4, sha, 20).
-old_enc() ->
- [{doc,"Tests encode/decode RSA key encrypted with different ciphers using old PEM encryption scheme"}].
-old_enc(Config) when is_list(Config) ->
- Datadir = proplists:get_value(data_dir, Config),
- %% key generated with ssh-keygen -N hello_aes -f old_aes_128_cbc_enc_key.pem
- {ok, PemAesCbc} = file:read_file(filename:join(Datadir, "old_aes_128_cbc_enc_key.pem")),
-
- PemAesCbcEntry = public_key:pem_decode(PemAesCbc),
- ct:print("Pem entry: ~p" , [PemAesCbcEntry]),
- [{'RSAPrivateKey', _, {"AES-128-CBC",_}} = PubAesCbcEntry] = PemAesCbcEntry,
- #'RSAPrivateKey'{} = public_key:pem_entry_decode(PubAesCbcEntry, "hello_aes").
-
pbes1() ->
[{doc,"Tests encode/decode EncryptedPrivateKeyInfo encrypted with different ciphers using PBES1"}].
pbes1(Config) when is_list(Config) ->
decode_encode_key_file("pbes1_des_cbc_md5_enc_key.pem", "password", "DES-CBC", Config).
-
+
pbes2() ->
[{doc,"Tests encode/decode EncryptedPrivateKeyInfo encrypted with different ciphers using PBES2"}].
pbes2(Config) when is_list(Config) ->
@@ -225,24 +213,38 @@ pbes2(Config) when is_list(Config) ->
false ->
ok
end.
+old_pbe() ->
+ [{doc,"Tests encode/decode with old format used before PBE"}].
+old_pbe(Config) when is_list(Config) ->
+ Datadir = proplists:get_value(data_dir, Config),
+ % key generated with ssh-keygen -N hello_aes -f old_aes_128_cbc.pem
+ {ok, PemAes128Cbc} = file:read_file(filename:join(Datadir, "old_aes_128_cbc.pem")),
+
+ PemAes128CbcEntries = public_key:pem_decode(PemAes128Cbc),
+ ct:print("Pem entry: ~p" , [PemAes128CbcEntries]),
+ [{'RSAPrivateKey', _, {"AES-128-CBC",_}} = Aes128CbcEntry] = PemAes128CbcEntries,
+ #'RSAPrivateKey'{} = Key = public_key:pem_entry_decode(Aes128CbcEntry, "hello_aes"),
+
-check_key_info(#'PrivateKeyInfo'{privateKeyAlgorithm =
- #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?rsaEncryption},
- privateKey = Key}) ->
- #'RSAPrivateKey'{} = public_key:der_decode('RSAPrivateKey', iolist_to_binary(Key)).
-
+ %% Converted with openssl rsa -in old_aes_128_cbc.pem -out old_aes_256_cbc.pem -aes256
+ {ok, PemAes256Cbc} = file:read_file(filename:join(Datadir, "old_aes_256_cbc.pem")),
+
+ PemAes256CbcEntries = public_key:pem_decode(PemAes256Cbc),
+ ct:print("Pem entry: ~p" , [PemAes256CbcEntries]),
+ [{'RSAPrivateKey', _, {"AES-256-CBC",_}} = Aes256CbcEntry] = PemAes256CbcEntries,
+ Key = public_key:pem_entry_decode(Aes256CbcEntry, "hello_aes").
+
decode_encode_key_file(File, Password, Cipher, Config) ->
Datadir = proplists:get_value(data_dir, Config),
{ok, PemKey} = file:read_file(filename:join(Datadir, File)),
PemEntry = public_key:pem_decode(PemKey),
- ct:print("Pem entry: ~p" , [PemEntry]),
+ ct:pal("Pem entry: ~p" , [PemEntry]),
[{Asn1Type, _, {Cipher,_} = CipherInfo} = PubEntry] = PemEntry,
- KeyInfo = public_key:pem_entry_decode(PubEntry, Password),
+ #'RSAPrivateKey'{} = KeyInfo = public_key:pem_entry_decode(PubEntry, Password),
PemKey1 = public_key:pem_encode([public_key:pem_entry_encode(Asn1Type, KeyInfo, {CipherInfo, Password})]),
Pem = strip_ending_newlines(PemKey),
- Pem = strip_ending_newlines(PemKey1),
- check_key_info(KeyInfo).
+ Pem = strip_ending_newlines(PemKey1).
strip_ending_newlines(Bin) ->
string:strip(binary_to_list(Bin), right, 10).
diff --git a/lib/public_key/test/pbe_SUITE_data/old_aes_128_cbc_enc_key.pem b/lib/public_key/test/pbe_SUITE_data/old_aes_128_cbc.pem
index 34c7543f30..34c7543f30 100644
--- a/lib/public_key/test/pbe_SUITE_data/old_aes_128_cbc_enc_key.pem
+++ b/lib/public_key/test/pbe_SUITE_data/old_aes_128_cbc.pem
diff --git a/lib/public_key/test/pbe_SUITE_data/old_aes_256_cbc.pem b/lib/public_key/test/pbe_SUITE_data/old_aes_256_cbc.pem
new file mode 100644
index 0000000000..e6aec2869d
--- /dev/null
+++ b/lib/public_key/test/pbe_SUITE_data/old_aes_256_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CBC,ABDA22398E511E9465983E1A50706044
+
+XhIcPOb6pTWL++pgeeTH5rsx0tackhllVqyXyOfbYMBJnVFRhQ/V/1MDg3Jt4wD1
+Nerhcv5srHeiwmf+vwXwDFOzvFzLVM1jFMUJe/2XloYFX4TBiLZAF/zekQA3uPY6
+DKJuBuO5vVSZ0VlxGpu3jphIAwxbssfZkZmryCP3b1/oX5Y3Em/wEWW3RduaeWFu
+Z2nTsPH3yNmHkuqFF3cq0aZs+VxtjcuYo0gbkN5hNVgOoOVxIBzw7DsgBAkdXvr3
+LRCMGg7Y2pVthA963s0xkN37XtZEiYbydoLnzHlW/Kx5QSvED8/Fn94Lcdy5NsQN
+7nYWWgYZRH39Wnsi0BrTZv399U5rBe7DnpStKWPn2Sa8Bdu3CX2oLajM1cZjAp1X
+y6vuasK7SoZ8rWpcsHQpV1HyNBTl/uRU5nrYc/KGD8l2x7tdNidGx2Hey/6O4H5v
+rxL1TB4PlzDYwCsReuyLbEjyuZQ10j0SK/SFzikHuvD2IEpM/oUaPdVFqcW8/sjw
+VhcsupAf4EXfsi2dJBylmDjI2W7h9XwBDLzQN+69DtkBmvimE5CguTITf8MAHQQ6
+Q1vYF2ij7W675tj9ulksRPaMxSsI03luai/Jrieh0mPqGEenGEEC5QU0XPOvsfyw
+GMYaBUbdYrMpbHM3wFPxM2wRlXf4gX5BhZKRGZX7OaEs54pfglyQtTPuZmD0VcAp
+EWHq70G9mbuBlhbMX1rKAomuDmIvgLeLRUpAFf59Qr8KoJSLD1S8TJB3uEPk6i39
+4GnylbpmqS4gv/OIc6WTeOeUZTAD3A77HBwSlELPk3/s1d/MLyfciYClOBEuZ6NB
+FXEKCGCEC786zJA678gLEaa2XPNkEM+2gjzNFqtYMIn5ehAq/HRRsFvW+wkTbee4
+z+qe5HbVKAQ3EOfbidvYrDaGd7HvHVG8zosl+O61iIFs04lLEMDFXBIdvIgEncOK
+Rq3yXdpBKMg89aoZLniaPobSvuvdjNOMzW6EKlb5FKZduCiR68MEZ+rLHYHTwE3W
+Z5+TCbrbV2F6WQpq3zqnB14wGu8igEb5Veq+N2vMkx4iTMTUyCty1SwIjj4NidM1
+dJM7Ighdal6tQ6hIwbDfpIPsY4eGH/UrdVZ0SkxuDR2s76cZ8nFX3lJ/BNwTZLKo
+IqAC4NjUOv3ID+0Q6Lz+sxLCi5pLYUf0E+s4pgi1BYAOu+BF3GwxyqnqVoq/Fs5D
+LXxuY0946YM+WcrYzke4mq3MPx6QQYj04H5KJ2mzxtnbZJrfLF23PVRVhvgKSjyV
+I3/zgJ16fV2H/fb26oCpTNbb11pQvhorkLwdvpwtM+go7dJGebAi1762Nbj/CqnW
+fbBPxPRvNPZn6pEodJ/L/APhvGv1K7eC9THj66H7Kmeoq8Lz74idhywP9I3QS0ZO
+15ORbTDjuiRYNJPxxu79A3/tWMUlprJ9ljhI/0DXRB0M3UGic52D/32Q64I7eewy
+qRNS/3C3ejDShIRBDFTdDkM3s/42LySXJjmjU9bpZY4POQ3kOaJb3EzSvbzTyXzu
+3FiHvDQY+b8XwbxtE/kTMaAPQZ7TtWOao7SRi7J94MvCQ5/tbakFP2suM8psnigC
+-----END RSA PRIVATE KEY-----
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index 449d1fc040..878489eb0f 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -44,7 +44,9 @@ all() ->
encrypt_decrypt,
{group, sign_verify},
pkix, pkix_countryname, pkix_emailaddress, pkix_path_validation,
- pkix_iso_rsa_oid, pkix_iso_dsa_oid, pkix_crl, general_name,
+ pkix_iso_rsa_oid, pkix_iso_dsa_oid,
+ pkix_dsa_sha2_oid,
+ pkix_crl, general_name,
pkix_verify_hostname_cn,
pkix_verify_hostname_subjAltName,
pkix_verify_hostname_subjAltName_IP,
@@ -64,6 +66,7 @@ all() ->
groups() ->
[{pem_decode_encode, [], [dsa_pem, rsa_pem, ec_pem, encrypted_pem,
dh_pem, cert_pem, pkcs7_pem, pkcs10_pem, ec_pem2,
+ rsa_priv_pkcs8, dsa_priv_pkcs8, ec_priv_pkcs8,
ec_pem_encode_generated,
gen_ec_param_prime_field, gen_ec_param_char_2_field
]},
@@ -181,6 +184,19 @@ dsa_pem(Config) when is_list(Config) ->
DSAPubPemNoEndNewLines = strip_superfluous_newlines(DSAPubPem),
DSAPubPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([PubEntry0])).
+dsa_priv_pkcs8() ->
+ [{doc, "DSA PKCS8 private key decode/encode"}].
+dsa_priv_pkcs8(Config) when is_list(Config) ->
+ Datadir = proplists:get_value(data_dir, Config),
+ {ok, DsaPem} = file:read_file(filename:join(Datadir, "dsa_key_pkcs8.pem")),
+ [{'PrivateKeyInfo', DerDSAKey, not_encrypted} = Entry0 ] = public_key:pem_decode(DsaPem),
+ DSAKey = public_key:der_decode('PrivateKeyInfo', DerDSAKey),
+ DSAKey = public_key:pem_entry_decode(Entry0),
+ true = check_entry_type(DSAKey, 'DSAPrivateKey'),
+ PrivEntry0 = public_key:pem_entry_encode('PrivateKeyInfo', DSAKey),
+ DSAPemNoEndNewLines = strip_superfluous_newlines(DsaPem),
+ DSAPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([PrivEntry0])).
+
%%--------------------------------------------------------------------
rsa_pem() ->
@@ -216,6 +232,19 @@ rsa_pem(Config) when is_list(Config) ->
RSARawPemNoEndNewLines = strip_superfluous_newlines(RSARawPem),
RSARawPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([PubEntry1])).
+rsa_priv_pkcs8() ->
+ [{doc, "RSA PKCS8 private key decode/encode"}].
+rsa_priv_pkcs8(Config) when is_list(Config) ->
+ Datadir = proplists:get_value(data_dir, Config),
+ {ok, RsaPem} = file:read_file(filename:join(Datadir, "rsa_key_pkcs8.pem")),
+ [{'PrivateKeyInfo', DerRSAKey, not_encrypted} = Entry0 ] = public_key:pem_decode(RsaPem),
+ RSAKey = public_key:der_decode('PrivateKeyInfo', DerRSAKey),
+ RSAKey = public_key:pem_entry_decode(Entry0),
+ true = check_entry_type(RSAKey, 'RSAPrivateKey'),
+ PrivEntry0 = public_key:pem_entry_encode('PrivateKeyInfo', RSAKey),
+ RSAPemNoEndNewLines = strip_superfluous_newlines(RsaPem),
+ RSAPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([PrivEntry0])).
+
%%--------------------------------------------------------------------
ec_pem() ->
@@ -262,6 +291,18 @@ ec_pem2(Config) when is_list(Config) ->
ECPemNoEndNewLines = strip_superfluous_newlines(ECPrivPem),
ECPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([Entry1, Entry2])).
+ec_priv_pkcs8() ->
+ [{doc, "EC PKCS8 private key decode/encode"}].
+ec_priv_pkcs8(Config) when is_list(Config) ->
+ Datadir = proplists:get_value(data_dir, Config),
+ {ok, ECPrivPem} = file:read_file(filename:join(Datadir, "ec_key_pkcs8.pem")),
+ [{'PrivateKeyInfo', _, not_encrypted} = PKCS8Key] = public_key:pem_decode(ECPrivPem),
+ ECPrivKey = public_key:pem_entry_decode(PKCS8Key),
+ true = check_entry_type(ECPrivKey, 'ECPrivateKey'),
+ true = check_entry_type(ECPrivKey#'ECPrivateKey'.parameters, 'EcpkParameters'),
+ PrivEntry0 = public_key:pem_entry_encode('PrivateKeyInfo', ECPrivKey),
+ ECPemNoEndNewLines = strip_superfluous_newlines(ECPrivPem),
+ ECPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([PrivEntry0])).
init_ec_pem_encode_generated(Config) ->
case catch true = lists:member('secp384r1', crypto:ec_curves()) of
@@ -271,7 +312,7 @@ init_ec_pem_encode_generated(Config) ->
ec_pem_encode_generated() ->
[{doc, "PEM-encode generated EC key"}].
-ec_pem_encode_generated(Config) ->
+ec_pem_encode_generated(_Config) ->
Key1 = public_key:generate_key({namedCurve, 'secp384r1'}),
public_key:pem_entry_encode('ECPrivateKey', Key1),
@@ -679,12 +720,8 @@ encrypt_decrypt(Config) when is_list(Config) ->
Msg = list_to_binary(lists:duplicate(5, "Foo bar 100")),
RsaEncrypted = public_key:encrypt_private(Msg, PrivateKey),
Msg = public_key:decrypt_public(RsaEncrypted, PublicKey),
- Msg = public_key:decrypt_public(RsaEncrypted, PrivateKey),
RsaEncrypted2 = public_key:encrypt_public(Msg, PublicKey),
- RsaEncrypted3 = public_key:encrypt_public(Msg, PrivateKey),
Msg = public_key:decrypt_private(RsaEncrypted2, PrivateKey),
- Msg = public_key:decrypt_private(RsaEncrypted3, PrivateKey),
-
ok.
%%--------------------------------------------------------------------
@@ -926,7 +963,7 @@ pkix_verify_hostname_cn(Config) ->
%% openssl req -x509 -nodes -newkey rsa:1024 -keyout /dev/null -extensions SAN -config public_key_SUITE_data/verify_hostname.conf 2>/dev/null > public_key_SUITE_data/pkix_verify_hostname_subjAltName.pem
%%
%% Subject: C=SE, CN=example.com
-%% Subject Alternative Name: DNS:kb.example.org, URI:http://www.example.org, URI:https://wws.example.org
+%% Subject Alternative Name: DNS:kb.example.org, DNS:*.example.org, URI:http://www.example.org, URI:https://wws.example.org
pkix_verify_hostname_subjAltName(Config) ->
DataDir = proplists:get_value(data_dir, Config),
@@ -945,7 +982,25 @@ pkix_verify_hostname_subjAltName(Config) ->
{dns_id,"wws.example.org"}]),
%% Check that a dns_id matches a DNS subjAltName:
- true = public_key:pkix_verify_hostname(Cert, [{dns_id,"kb.example.org"}]).
+ true = public_key:pkix_verify_hostname(Cert, [{dns_id,"kb.example.org"}]),
+
+ %% Check that a dns_id does not match a DNS subjAltName wiht wildcard
+ false = public_key:pkix_verify_hostname(Cert, [{dns_id,"other.example.org"}]),
+
+ %% Check that a dns_id does match a DNS subjAltName wiht wildcard with matchfun
+ true = public_key:pkix_verify_hostname(Cert, [{dns_id,"other.example.org"}],
+ [{match_fun, public_key:pkix_verify_hostname_match_fun(https)}
+ ]
+ ),
+
+ %% Check that a uri_id does not match a DNS subjAltName wiht wildcard
+ false = public_key:pkix_verify_hostname(Cert, [{uri_id,"https://other.example.org"}]),
+
+ %% Check that a dns_id does match a DNS subjAltName wiht wildcard with matchfun
+ true = public_key:pkix_verify_hostname(Cert, [{uri_id,"https://other.example.org"}],
+ [{match_fun, public_key:pkix_verify_hostname_match_fun(https)}
+ ]
+ ).
%%--------------------------------------------------------------------
%% Uses the pem-file for pkix_verify_hostname_cn
@@ -992,7 +1047,14 @@ pkix_verify_hostname_options(Config) ->
end}]),
true = public_key:pkix_verify_hostname(Cert, [{uri_id,"https://example.com"}],
[{fqdn_fun, fun(_) -> default end}]),
- false = public_key:pkix_verify_hostname(Cert, [{uri_id,"some://very.wrong.domain"}]).
+ false = public_key:pkix_verify_hostname(Cert, [{uri_id,"some://very.wrong.domain"}]),
+
+ true = public_key:pkix_verify_hostname(Cert, [{dns_id,"example.com"}]),
+ true = public_key:pkix_verify_hostname(Cert, [{dns_id,"abb.bar.example.com"}]),
+ false = public_key:pkix_verify_hostname(Cert, [{dns_id,"example.com"},
+ {dns_id,"abb.bar.example.com"}],
+ [{fqdn_fun,fun(_)->undefined end}]).
+
%%--------------------------------------------------------------------
%% To generate the PEM file contents:
@@ -1054,6 +1116,13 @@ pkix_iso_dsa_oid(Config) when is_list(Config) ->
{_, dsa} = public_key:pkix_sign_types(SigAlg#'SignatureAlgorithm'.algorithm).
%%--------------------------------------------------------------------
+pkix_dsa_sha2_oid() ->
+ [{doc, "Test support dsa_sha2 oid"}].
+pkix_dsa_sha2_oid(Config) when is_list(Config) ->
+ {sha224, dsa} = public_key:pkix_sign_types(?'id-dsa-with-sha224'),
+ {sha256, dsa} = public_key:pkix_sign_types(?'id-dsa-with-sha256').
+
+%%--------------------------------------------------------------------
pkix_crl() ->
[{doc, "test pkix_crl_* functions"}].
@@ -1312,7 +1381,7 @@ do_gen_ec_param(File) ->
ct:fail({key_gen_fail, File})
end.
-init_per_testcase_gen_ec_param(TC, Curve, Config) ->
+init_per_testcase_gen_ec_param(_TC, Curve, Config) ->
case crypto:ec_curves() of
[] ->
{skip, missing_ec_support};
@@ -1328,7 +1397,7 @@ init_per_testcase_gen_ec_param(TC, Curve, Config) ->
end.
-crypto_supported_curve(Curve, Curves) ->
+crypto_supported_curve(Curve, _Curves) ->
try crypto:generate_key(ecdh, Curve) of
{error,_} -> false; % Just in case crypto is changed in the future...
_-> true
diff --git a/lib/public_key/test/public_key_SUITE_data/dsa_key_pkcs8.pem b/lib/public_key/test/public_key_SUITE_data/dsa_key_pkcs8.pem
new file mode 100644
index 0000000000..86e38e2c76
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/dsa_key_pkcs8.pem
@@ -0,0 +1,9 @@
+-----BEGIN PRIVATE KEY-----
+MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBALez5tklY5CdFeTMos899pA6i4u4
+uCtszgBzrdBk6cl5FVqzdzWMGTQiynnTpGsrOESinzP06Ip+pG15We2OORwgvCxD
+/W95aCiN0/+MdiXqlsmboBARMzsa+SmBENN3gF/+tuuEAFzOXU1q2cmEywRLyfbM
+2KIBVE/TChWYw2eRAhUA1R64VvcQ90XA8SOKVDmMA0dBzukCgYEAlLMYP0pbgBlg
+HQVO3/avAHlWNrIq52Lxk7SdPJWgMvPjTK9Z6sv88kxsCcydtjvO439j1yqcwk50
+GQc+86ktBWWz93/HkIdnFyqafef4mmWvm2Uq6ClQKS+A0Asfaj8Mys+HUMiI+qsf
+djRbyIpwb7MX1nsVdsKzALnZNMW27A0EFgIUWYCfDrv5tqwPWKJu00ez0R192SY=
+-----END PRIVATE KEY-----
diff --git a/lib/public_key/test/public_key_SUITE_data/ec_key_pkcs8.pem b/lib/public_key/test/public_key_SUITE_data/ec_key_pkcs8.pem
new file mode 100644
index 0000000000..8280a3671a
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/ec_key_pkcs8.pem
@@ -0,0 +1,5 @@
+-----BEGIN PRIVATE KEY-----
+MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgB349XXSmba5BbJT5UuCK
+OoyoPHsygy6n+WzP1J+8eYShRANCAATTJdDtiqV9Hs7q+Y/yak1z3uJpukFQGYmr
+lJ2iztxfv7bz10eJ5yM/GNqG8kK0w7SIzjedsIkfjRK7bX6mP7h4
+-----END PRIVATE KEY-----
diff --git a/lib/public_key/test/public_key_SUITE_data/pkix_verify_hostname_subjAltName.pem b/lib/public_key/test/public_key_SUITE_data/pkix_verify_hostname_subjAltName.pem
index 83e1ad37b3..7ab9ed7b96 100644
--- a/lib/public_key/test/public_key_SUITE_data/pkix_verify_hostname_subjAltName.pem
+++ b/lib/public_key/test/public_key_SUITE_data/pkix_verify_hostname_subjAltName.pem
@@ -1,14 +1,14 @@
-----BEGIN CERTIFICATE-----
-MIICEjCCAXugAwIBAgIJANwliLph5EiAMA0GCSqGSIb3DQEBCwUAMCMxCzAJBgNV
-BAYTAlNFMRQwEgYDVQQDEwtleGFtcGxlLmNvbTAeFw0xNjEyMjAxNTEyMjRaFw0x
-NzAxMTkxNTEyMjRaMCMxCzAJBgNVBAYTAlNFMRQwEgYDVQQDEwtleGFtcGxlLmNv
-bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAydstIN157w8QxkVaOl3wm81j
-fgZ8gqO3BXkECPF6bw5ewLlmePL6Qs4RypsaRe7cKJ9rHFlwhpdcYkxWSWEt2N7Z
-Ry3N4SjuU04ohWbYgy3ijTt7bJg7jOV1Dh56BnI4hwhQj0oNFizNZOeRRfEzdMnS
-+uk03t/Qre2NS7KbwnUCAwEAAaNOMEwwSgYDVR0RBEMwQYIOa2IuZXhhbXBsZS5v
-cmeGFmh0dHA6Ly93d3cuZXhhbXBsZS5vcmeGF2h0dHBzOi8vd3dzLmV4YW1wbGUu
-b3JnMA0GCSqGSIb3DQEBCwUAA4GBAKqFqW5gCso422bXriCBJoygokOTTOw1Rzpq
-K8Mm0B8W9rrW9OTkoLEcjekllZcUCZFin2HovHC5HlHZz+mQvBI1M6sN2HVQbSzS
-EgL66U9gwJVnn9/U1hXhJ0LO28aGbyE29DxnewNR741dWN3oFxCdlNaO6eMWaEsO
-gduJ5sDl
+MIICITCCAYqgAwIBAgIJAP31suf/Fi4oMA0GCSqGSIb3DQEBCwUAMCMxCzAJBgNV
+BAYTAlNFMRQwEgYDVQQDEwtleGFtcGxlLmNvbTAeFw0xODA1MTcxMDIzNDBaFw0x
+ODA2MTYxMDIzNDBaMCMxCzAJBgNVBAYTAlNFMRQwEgYDVQQDEwtleGFtcGxlLmNv
+bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsUVMXSM4Q6vYp7H4Svsfv4QQ
+dmUD3IdTbtumlyAqLZuc6Z0HU9IOE0wpF97+5AE3moHluwN/MtSX/fb9oxCjh3L6
+iDla770uUoIgiWkA9lyzuYXt7zGsqc0EmGMJRAHp4jOxI26U/C8wdXoyZsGD8GPr
+hYAI2Me4CkdDqCoRuUUCAwEAAaNdMFswWQYDVR0RBFIwUIIOa2IuZXhhbXBsZS5v
+cmeCDSouZXhhbXBsZS5vcmeGFmh0dHA6Ly93d3cuZXhhbXBsZS5vcmeGF2h0dHBz
+Oi8vd3dzLmV4YW1wbGUub3JnMA0GCSqGSIb3DQEBCwUAA4GBAKs8vWMqpXiuFhcq
+6W1dMrVB4tuDjt1Ctr3g2USXBLgm8NxsZzslFyDnrvtZY0hbjcAkGKMMhy8lFD5t
++GjBbyp7MKII6vJaVvc+wbrsbNdvioB1puGwbgVhgD3Kb79do9h6JrNncjMvBN7j
+VK6BUB8TUofFmztMjoPlxFOs/7qK
-----END CERTIFICATE-----
diff --git a/lib/public_key/test/public_key_SUITE_data/rsa_key_pkcs8.pem b/lib/public_key/test/public_key_SUITE_data/rsa_key_pkcs8.pem
new file mode 100644
index 0000000000..9ef5b3353f
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/rsa_key_pkcs8.pem
@@ -0,0 +1,10 @@
+-----BEGIN PRIVATE KEY-----
+MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEA1GLJmDS5yLvg1zqa
+epnwCgOXzxpPvHokDQx+AcgfO14SPtCD6UTlDEwYBp+6tUTm+qgeQN/CTi7POwIA
+m7P3UwIDAQABAkALFiEJ1e7AwLXq5j88GR8Dls5s3CW/Y+zP1ZAaTbT7p0QUMxG+
+0ko7h8NoxcQJHZU27sZXCjog/IBqn577Xv4RAiEA8/aQ09kz0jxi4aNvlix4B+bW
+gX0sYtcCDkBzx8Y6iMkCIQDe3WCxV9PuiDjpuC8cAy3UMC5PBygZG4iK3arpgzxp
+OwIhAKxKJg+mpgVEJiTpsiVhNEeIS1bZWp5W75m3BM1B/haZAiBQOhEcxikcrR0P
+xaXvx5Uv1UhWWpUstKSqmLF17jBJEQIhAMx4HMLqwaGeYwOcxfzxz6Al8fnPmfAR
+hqFR28fVJrWX
+-----END PRIVATE KEY-----
diff --git a/lib/public_key/test/public_key_SUITE_data/verify_hostname.conf b/lib/public_key/test/public_key_SUITE_data/verify_hostname.conf
index a28864dc78..6b4e4f284e 100644
--- a/lib/public_key/test/public_key_SUITE_data/verify_hostname.conf
+++ b/lib/public_key/test/public_key_SUITE_data/verify_hostname.conf
@@ -10,7 +10,8 @@ CN=example.com
subjectAltName = @alt_names
[alt_names]
-DNS = kb.example.org
+DNS.1 = kb.example.org
+DNS.2 = *.example.org
URI.1 = http://www.example.org
URI.2 = https://wws.example.org
diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk
index 99a0cc087e..a5e4ec8d5a 100644
--- a/lib/public_key/vsn.mk
+++ b/lib/public_key/vsn.mk
@@ -1 +1 @@
-PUBLIC_KEY_VSN = 1.5.2
+PUBLIC_KEY_VSN = 1.6.7
diff --git a/lib/reltool/doc/src/Makefile b/lib/reltool/doc/src/Makefile
index e378cdf980..dce8059616 100644
--- a/lib/reltool/doc/src/Makefile
+++ b/lib/reltool/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2009-2016. All Rights Reserved.
+# Copyright Ericsson AB 2009-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -88,6 +88,7 @@ clean clean_docs:
fi \
done
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/lib/reltool/doc/src/notes.xml b/lib/reltool/doc/src/notes.xml
index d7ad7c8dcc..ee00b6086d 100644
--- a/lib/reltool/doc/src/notes.xml
+++ b/lib/reltool/doc/src/notes.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2009</year>
- <year>2017</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -38,7 +38,88 @@
thus constitutes one section in this document. The title of each
section is the version number of Reltool.</p>
- <section><title>Reltool 0.7.5</title>
+ <section><title>Reltool 0.8</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ A new element, <c>Opts</c>, can now be included in a
+ <c>rel</c> tuple in the reltool release specific
+ configuration format: {rel, Name, Vsn, RelApps, Opts}.</p>
+ <p>
+ This supports the use of <c>{rel, Name, Vsn, RelApps,
+ [{load_dot_erlang, false}]}</c> to prevent the boot
+ script from running the <c>.erlang</c> file.</p>
+ <p>
+ The incompatibilities are as follows:</p>
+ <p>
+ * The return from <c>reltool:get_config/1</c> and
+ <c>reltool:get_config/3</c> includes the new <c>rel</c>
+ tuple for all releases where the <c>load_dot_erlang</c>
+ option is set to <c>false</c>.<br/> * The return from
+ <c>reltool:get_config/3</c> includes the new <c>rel</c>
+ tuple for ALL releases if the <c>InclDefs</c> parameter
+ is set to <c>true</c>.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15571</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Reltool 0.7.8</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Reltool would earlier erroneously split paths like
+ <c>"c:\foo"</c> into <c>["c","\foo"]</c> when reading the
+ <c>$ERL_LIBS</c> variable on windows. This is now
+ corrected.</p>
+ <p>
+ Own Id: OTP-15454</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Reltool 0.7.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Reltool 0.7.6</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> Calls to <c>erlang:get_stacktrace()</c> are removed.
+ </p>
+ <p>
+ Own Id: OTP-14861</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Reltool 0.7.5</title>
<section><title>Improvements and New Features</title>
<list>
diff --git a/lib/reltool/doc/src/reltool.xml b/lib/reltool/doc/src/reltool.xml
index 5bfbee966b..136ec2ed69 100644
--- a/lib/reltool/doc/src/reltool.xml
+++ b/lib/reltool/doc/src/reltool.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2009</year>
- <year>2016</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -33,7 +33,7 @@
<date></date>
<rev>%VSN%</rev>
</header>
- <module>reltool</module>
+ <module since="">reltool</module>
<modulesummary>Main API of the Reltool application</modulesummary>
<description>
<p>This is an interface module for the Reltool application.</p>
@@ -503,6 +503,7 @@ sys() = {root_dir, root_dir()}
| {incl_cond, incl_cond()}
| {boot_rel, boot_rel()}
| {rel, rel_name(), rel_vsn(), [rel_app()]}
+ | {rel, rel_name(), rel_vsn(), [rel_app()], [rel_opt()]}
| {relocatable, relocatable()}
| {app_file, app_file()}
| {debug_info, debug_info()}
@@ -534,6 +535,7 @@ rel_app() = app_name()
| {app_name(), app_type()}
| {app_name(), [incl_app()]}
| {app_name(), app_type(), [incl_app()]}
+rel_opt() = {load_dot_erlang, boolean()}
app_name() = atom()
app_type() = permanent | transient | temporary | load | none
app_vsn() = string()
@@ -591,7 +593,7 @@ target_spec() = [target_spec()]
<funcs>
<func>
- <name>create_target(Server, TargetDir) -> ok | {error, Reason}</name>
+ <name since="">create_target(Server, TargetDir) -> ok | {error, Reason}</name>
<fsummary>Create a target system</fsummary>
<type>
<v>Server = server()</v>
@@ -604,7 +606,7 @@ target_spec() = [target_spec()]
</func>
<func>
- <name>eval_target_spec(TargetSpec, RootDir, TargetDir) -> ok | {error, Reason}</name>
+ <name since="">eval_target_spec(TargetSpec, RootDir, TargetDir) -> ok | {error, Reason}</name>
<fsummary>Create a target system</fsummary>
<type>
<v>TargetSpec = target_spec()</v>
@@ -655,7 +657,7 @@ target_spec() = [target_spec()]
</func>
<func>
- <name>get_config(Server) -> {ok, Config} | {error, Reason}</name>
+ <name since="">get_config(Server) -> {ok, Config} | {error, Reason}</name>
<fsummary>Get reltool configuration</fsummary>
<type>
<v>Server = server()</v>
@@ -667,7 +669,7 @@ target_spec() = [target_spec()]
</func>
<func>
- <name>get_config(Server, InclDefaults, InclDerived) -> {ok, Config} | {error, Reason}</name>
+ <name since="">get_config(Server, InclDefaults, InclDerived) -> {ok, Config} | {error, Reason}</name>
<fsummary>Get reltool configuration</fsummary>
<type>
<v>Server = server()</v>
@@ -685,7 +687,7 @@ target_spec() = [target_spec()]
</func>
<func>
- <name>get_rel(Server, Relname) -> {ok, RelFile} | {error, Reason}</name>
+ <name since="">get_rel(Server, Relname) -> {ok, RelFile} | {error, Reason}</name>
<fsummary>Get contents of a release file</fsummary>
<type>
<v>Server = server()</v>
@@ -698,7 +700,7 @@ target_spec() = [target_spec()]
</func>
<func>
- <name>get_script(Server, Relname) -> {ok, ScriptFile | {error, Reason}</name>
+ <name since="">get_script(Server, Relname) -> {ok, ScriptFile | {error, Reason}</name>
<fsummary>Get contents of a boot script file</fsummary>
<type>
<v>Server = server()</v>
@@ -711,7 +713,7 @@ target_spec() = [target_spec()]
</func>
<func>
- <name>get_status(Server) -> {ok, [Warning]} | {error, Reason}</name>
+ <name since="OTP R14B">get_status(Server) -> {ok, [Warning]} | {error, Reason}</name>
<fsummary>Get contents of a release file</fsummary>
<type>
<v>Server = server()</v>
@@ -722,7 +724,7 @@ target_spec() = [target_spec()]
</func>
<func>
- <name>get_server(WindowPid) -> {ok, ServerPid} | {error, Reason}</name>
+ <name since="">get_server(WindowPid) -> {ok, ServerPid} | {error, Reason}</name>
<fsummary>Start server process with options</fsummary>
<type>
<v>WindowPid = window_pid()</v>
@@ -733,7 +735,7 @@ target_spec() = [target_spec()]
</func>
<func>
- <name>get_target_spec(Server) -> {ok, TargetSpec} | {error, Reason}</name>
+ <name since="">get_target_spec(Server) -> {ok, TargetSpec} | {error, Reason}</name>
<fsummary>Return a specification of the target system</fsummary>
<type>
<v>Server = server()</v>
@@ -747,7 +749,7 @@ target_spec() = [target_spec()]
</func>
<func>
- <name>install(RelName, TargetDir) -> ok | {error, Reason}</name>
+ <name since="">install(RelName, TargetDir) -> ok | {error, Reason}</name>
<fsummary>Install a target system</fsummary>
<type>
<v>RelName = rel_name()</v>
@@ -758,7 +760,7 @@ target_spec() = [target_spec()]
</func>
<func>
- <name>start() -> {ok, WindowPid} | {error, Reason}</name>
+ <name since="">start() -> {ok, WindowPid} | {error, Reason}</name>
<fsummary>Start main window process</fsummary>
<type>
<v>WindowPid = window_pid()</v>
@@ -768,7 +770,7 @@ target_spec() = [target_spec()]
</func>
<func>
- <name>start(Options) -> {ok, WindowPid} | {error, Reason}</name>
+ <name since="">start(Options) -> {ok, WindowPid} | {error, Reason}</name>
<fsummary>Start main window process with options</fsummary>
<type>
<v>Options = options()</v>
@@ -779,7 +781,7 @@ target_spec() = [target_spec()]
</func>
<func>
- <name>start_link(Options) -> {ok, WindowPid} | {error, Reason}</name>
+ <name since="">start_link(Options) -> {ok, WindowPid} | {error, Reason}</name>
<fsummary>Start main window process with options</fsummary>
<type>
<v>Options = options()</v>
@@ -790,7 +792,7 @@ target_spec() = [target_spec()]
</func>
<func>
- <name>start_server(Options) -> {ok, ServerPid} | {error, Reason}</name>
+ <name since="">start_server(Options) -> {ok, ServerPid} | {error, Reason}</name>
<fsummary>Start server process with options</fsummary>
<type>
<v>Options = options()</v>
@@ -803,10 +805,10 @@ target_spec() = [target_spec()]
</func>
<func>
- <name>stop(Pid) -> ok | {error, Reason}</name>
+ <name since="">stop(Pid) -> ok | {error, Reason}</name>
<fsummary>Stop a server or window process</fsummary>
<type>
- <v>Pid = server_pid() | window_pid()()</v>
+ <v>Pid = server_pid() | window_pid()</v>
<v>Reason = reason()</v>
</type>
<desc><p>Stop a server or window process</p></desc>
diff --git a/lib/reltool/doc/src/reltool_examples.xml b/lib/reltool/doc/src/reltool_examples.xml
index 30cb3c13b6..3888b643a2 100644
--- a/lib/reltool/doc/src/reltool_examples.xml
+++ b/lib/reltool/doc/src/reltool_examples.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2009</year>
- <year>2017</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -150,17 +150,17 @@ Eshell V9.0 (abort with ^G)
{mod_cond,all},
{incl_cond,derived},
{erts,[{app,erts,
- [{vsn,"9.0"},
- {lib_dir,"/usr/local/lib/erlang/lib/erts-9.0"},
+ [{vsn,"10.0"},
+ {lib_dir,"/usr/local/lib/erlang/lib/erts-10.0"},
{mod,erl_prim_loader,[]},
{mod,erl_tracer,[]},
{mod,erlang,[]},
{mod,erts_code_purger,[]},
- {mod,erts_dirty_process_code_checker,[]},
+ {mod,erts_dirty_process_signal_handler,[]},
{mod,erts_internal,[]},
{mod,erts_literal_area_collector,[]},
{mod,init,[]},
- {mod,otp_ring0,...},
+ {mod,erl_init,...},
{mod,...},
{...}|...]}]},
{app,compiler,
@@ -309,13 +309,16 @@ Eshell V9.0 (abort with ^G)
<section>
<title>Generate release and script files</title>
<pre>
-Erlang/OTP 20 [erts-9.0] [source-c13b302] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10]
+Erlang/OTP 20 [erts-10.0] [source-c13b302] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10]
[hipe] [kernel-poll:false]
-Eshell V9.0 (abort with ^G)
+Eshell V10.0 (abort with ^G)
1&gt;
-1&gt; {ok, Server} = reltool:start_server([{config, {sys, [{boot_rel, "NAME"},
- {rel, "NAME", "VSN",
- [sasl]}]}}]).
+1&gt; {ok, Server} = reltool:start_server([{config,
+ {sys,
+ [{boot_rel, "NAME"},
+ {rel, "NAME", "VSN",
+ [sasl],
+ [{load_dot_erlang, false}]}]}}]).
{ok,&lt;0.1288.0&gt;}
2&gt;
2&gt; reltool:get_config(Server).
@@ -324,14 +327,14 @@ Eshell V9.0 (abort with ^G)
3&gt;
3&gt; reltool:get_rel(Server, "NAME").
{ok,{release,{"NAME","VSN"},
- {erts,"9.0"},
+ {erts,"10.0"},
[{kernel,"5.2"},{stdlib,"3.3"},{sasl,"3.0.3"}]}}
4&gt;
4&gt; reltool:get_script(Server, "NAME").
{ok,{script,{"NAME","VSN"},
[{preLoaded,[erl_prim_loader,erl_tracer,erlang,
- erts_code_purger,erts_dirty_process_code_checker,
- erts_internal,erts_literal_area_collector,init,otp_ring0,
+ erts_code_purger,erts_dirty_process_signal_handler,
+ erts_internal,erts_literal_area_collector,init,erl_init,
prim_eval,prim_file,prim_inet,prim_zip,zlib]},
{progress,preloaded},
{path,["$ROOT/lib/kernel-5.2/ebin",
@@ -374,9 +377,9 @@ ok
<section>
<title>Create a target system</title>
<pre>
-Erlang/OTP 20 [erts-9.0] [source-c13b302] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10]
+Erlang/OTP 20 [erts-10.0] [source-c13b302] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10]
[hipe] [kernel-poll:false]
-Eshell V9.0 (abort with ^G)
+Eshell V10.0 (abort with ^G)
1&gt;
1&gt; Config = {sys, [{escript, "examples/display_args", [{incl_cond, include}]},
{app, inets, [{incl_cond, include}]},
@@ -393,7 +396,7 @@ Eshell V9.0 (abort with ^G)
2&gt;
2&gt; {ok, Spec} = reltool:get_target_spec([Config]).
{ok,[{create_dir,"releases",
- [{write_file,"start_erl.data","9.0 1.0\n"},
+ [{write_file,"start_erl.data","10.0 1.0\n"},
{create_dir,"1.0",
[{write_file,"start_clean.rel",
[37,37,32,114,101,108,32,103,101,110,101,114,97,116|...]},
@@ -410,17 +413,17 @@ Eshell V9.0 (abort with ^G)
{create_dir,"bin",
[{copy_file,"display_args.escript",
"/usr/local/lib/erlang/lib/reltool-0.7.3/examples/display_args"},
- {copy_file,"display_args","erts-9.0/bin/escript"},
- {copy_file,"start","erts-9.0/bin/start"},
- {copy_file,"ct_run","erts-9.0/bin/ct_run"},
- {copy_file,"dialyzer","erts-9.0/bin/dialyzer"},
- {copy_file,"run_erl","erts-9.0/bin/run_erl"},
- {copy_file,"erl","erts-9.0/bin/dyn_erl"},
- {copy_file,"to_erl","erts-9.0/bin/to_erl"},
- {copy_file,"epmd","erts-9.0/bin/epmd"},
- {copy_file,"erlc","erts-9.0/bin/erlc"},
- {copy_file,"typer","erts-9.0/bin/typer"},
- {copy_file,"escript","erts-9.0/bin/escript"},
+ {copy_file,"display_args","erts-10.0/bin/escript"},
+ {copy_file,"start","erts-10.0/bin/start"},
+ {copy_file,"ct_run","erts-10.0/bin/ct_run"},
+ {copy_file,"dialyzer","erts-10.0/bin/dialyzer"},
+ {copy_file,"run_erl","erts-10.0/bin/run_erl"},
+ {copy_file,"erl","erts-10.0/bin/dyn_erl"},
+ {copy_file,"to_erl","erts-10.0/bin/to_erl"},
+ {copy_file,"epmd","erts-10.0/bin/epmd"},
+ {copy_file,"erlc","erts-10.0/bin/erlc"},
+ {copy_file,"typer","erts-10.0/bin/typer"},
+ {copy_file,"escript","erts-10.0/bin/escript"},
{write_file,"start_clean.boot",&lt;&lt;131,104,3,119,6,115,...&gt;&gt;},
{write_file,"start_sasl.boot",&lt;&lt;131,104,3,119,6,...&gt;&gt;},
{write_file,"start.boot",&lt;&lt;131,104,3,119,...&gt;&gt;}]},
@@ -451,7 +454,7 @@ Eshell V9.0 (abort with ^G)
{copy_file,[...]},
{copy_file,...},
{...}]}]},
- {create_dir,"erts-9.0",
+ {create_dir,"erts-10.0",
[{create_dir,"bin",
[{copy_file,"start"},
{copy_file,"ct_run"},
@@ -459,7 +462,7 @@ Eshell V9.0 (abort with ^G)
{copy_file,"dialyzer"},
{copy_file,"beam.smp"},
{copy_file,"run_erl"},
- {copy_file,"erl","erts-9.0/bin/dyn_erl"},
+ {copy_file,"erl","erts-10.0/bin/dyn_erl"},
{copy_file,"to_erl"},
{copy_file,"epmd"},
{copy_file,"erl_child_setup"},
@@ -511,8 +514,8 @@ Eshell V9.0 (abort with ^G)
[{create_dir,"priv",
[{create_dir,"lib",[{copy_file,[...]},{copy_file,...}]},
{create_dir,"obj",[{copy_file,...},{...}|...]}]}]},
- {archive,"erts-9.0.ez",[],
- [{create_dir,"erts-9.0",
+ {archive,"erts-10.0.ez",[],
+ [{create_dir,"erts-10.0",
[{create_dir,"src",[{...}|...]},
{create_dir,"ebin",[...]}]}]},
{archive,"hipe-3.15.4.ez",[],
@@ -549,14 +552,14 @@ ok
ok
7&gt;
7&gt; file:list_dir(TargetDir).
-{ok,["bin","Install","lib","misc","usr","erts-9.0",
+{ok,["bin","Install","lib","misc","usr","erts-10.0",
"releases"]}
8&gt;
8&gt; file:list_dir(filename:join([TargetDir,"lib"])).
{ok,["tools-2.9.1.ez","kernel-5.2.ez","inets-6.3.9.ez",
"kernel-5.2","sasl-3.0.3.ez","hipe-3.15.4.ez","inets-6.3.9",
"crypto-3.7.4","crypto-3.7.4.ez","stdlib-3.3.ez",
- "erts-9.0.ez","stdlib-3.3","compiler-7.0.4.ez"]}
+ "erts-10.0.ez","stdlib-3.3","compiler-7.0.4.ez"]}
9&gt;
9&gt; file:make_dir("/tmp/yet_another_target_dir").
ok
@@ -565,7 +568,7 @@ ok
ok
11&gt;
11&gt; file:list_dir("/tmp/yet_another_target_dir").
-{ok,["bin","Install","lib","misc","usr","erts-9.0",
+{ok,["bin","Install","lib","misc","usr","erts-10.0",
"releases"]}
</pre>
diff --git a/lib/reltool/src/reltool.app.src b/lib/reltool/src/reltool.app.src
index dc21c1cfce..dc85464750 100644
--- a/lib/reltool/src/reltool.app.src
+++ b/lib/reltool/src/reltool.app.src
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/reltool/src/reltool.erl b/lib/reltool/src/reltool.erl
index feb6925044..2e1dbfd713 100644
--- a/lib/reltool/src/reltool.erl
+++ b/lib/reltool/src/reltool.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/reltool/src/reltool.hrl b/lib/reltool/src/reltool.hrl
index 9c8aae6b7e..892aaf8649 100644
--- a/lib/reltool/src/reltool.hrl
+++ b/lib/reltool/src/reltool.hrl
@@ -61,6 +61,7 @@
| {app_name(), app_type()}
| {app_name(), [incl_app()]}
| {app_name(), app_type(), [incl_app()]}.
+-type rel_opt() :: {load_dot_erlang, boolean()}.
-type mod() :: {incl_cond, incl_cond()}
| {debug_info, debug_info()}.
-type app() :: {vsn, app_vsn()}
@@ -92,6 +93,8 @@
| {lib_dirs, [lib_dir()]}
| {boot_rel, boot_rel()}
| {rel, rel_name(), rel_vsn(), [rel_app()]}
+ | {rel, rel_name(), rel_vsn(),
+ [rel_app()], [rel_opt()]}
| {relocatable, relocatable()}
| {erts, app()}
| {escript, escript_file(), [escript()]}
@@ -220,7 +223,8 @@
{
name :: rel_name(),
vsn :: rel_vsn(),
- rel_apps :: [#rel_app{}]
+ rel_apps :: [#rel_app{}],
+ load_dot_erlang = true :: boolean()
}).
-record(sys,
@@ -300,6 +304,7 @@
-define(STANDALONE_INCL_SYS_FILTERS, ["^bin/(erl|epmd)(|\\.exe|\\.ini)\$",
"^bin/start(|_clean).boot\$",
+ "^bin/no_dot_erlang\\.boot\$",
"^erts.*/bin",
"^lib\$"]).
-define(STANDALONE_EXCL_SYS_FILTERS,
diff --git a/lib/reltool/src/reltool_app_win.erl b/lib/reltool/src/reltool_app_win.erl
index 663144861f..c84c1562ee 100644
--- a/lib/reltool/src/reltool_app_win.erl
+++ b/lib/reltool/src/reltool_app_win.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -102,8 +102,8 @@ init(Parent, WxEnv, Xref, C, AppName) ->
try
do_init(Parent, WxEnv, Xref, C, AppName)
catch
- error:Reason ->
- exit({Reason, erlang:get_stacktrace()})
+ error:Reason:Stacktrace ->
+ exit({Reason, Stacktrace})
end.
do_init(Parent, WxEnv, Xref, C, AppName) ->
diff --git a/lib/reltool/src/reltool_fgraph_win.erl b/lib/reltool/src/reltool_fgraph_win.erl
index a10a2281db..0875d5dd7d 100644
--- a/lib/reltool/src/reltool_fgraph_win.erl
+++ b/lib/reltool/src/reltool_fgraph_win.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/reltool/src/reltool_mod_win.erl b/lib/reltool/src/reltool_mod_win.erl
index 2d56d74563..7df62b71be 100644
--- a/lib/reltool/src/reltool_mod_win.erl
+++ b/lib/reltool/src/reltool_mod_win.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -107,8 +107,8 @@ init(Parent, WxEnv, Xref, RelPid, C, ModName) ->
try
do_init(Parent, WxEnv, Xref, RelPid, C, ModName)
catch
- error:Reason ->
- exit({Reason, erlang:get_stacktrace()})
+ error:Reason:Stacktrace ->
+ exit({Reason, Stacktrace})
end.
do_init(Parent, WxEnv, Xref, RelPid, C, ModName) ->
@@ -833,7 +833,7 @@ load_code(Ed, Code) when is_binary(Code) ->
keyWords() ->
L = ["after","begin","case","try","cond","catch","andalso","orelse",
- "end","fun","if","let","of","query","receive","when","bnot","not",
+ "end","fun","if","let","of","receive","when","bnot","not",
"div","rem","band","and","bor","bxor","bsl","bsr","or","xor"],
lists:flatten([K ++ " " || K <- L] ++ [0]).
diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl
index 853191c696..2de8000fd8 100644
--- a/lib/reltool/src/reltool_server.erl
+++ b/lib/reltool/src/reltool_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -135,8 +135,8 @@ init([{parent,Parent}|_] = Options) ->
catch
throw:{error,Reason} ->
proc_lib:init_ack(Parent,{error,Reason});
- error:Reason ->
- exit({Reason, erlang:get_stacktrace()})
+ error:Reason:Stacktrace ->
+ exit({Reason, Stacktrace})
end.
do_init(Options) ->
@@ -526,7 +526,7 @@ analyse(#state{sys=Sys} = S, Apps, Status) ->
%% is included in a release (rel spec - see apps_in_rels above).
%% Then initiate the same for each module, and check that there
%% are no duplicated module names (in different applications)
- %% where we can not decide which one to use.
+ %% where we cannot decide which one to use.
%% Write all #app to app_tab and all #mod to mod_tab.
Status2 = apps_init_is_included(S, Apps, RelApps, Status),
@@ -1483,6 +1483,18 @@ decode(#sys{rels = Rels} = Sys, [{rel, Name, Vsn, RelApps} | SysKeyVals])
Rel = #rel{name = Name, vsn = Vsn, rel_apps = []},
Rel2 = decode(Rel, RelApps),
decode(Sys#sys{rels = [Rel2 | Rels]}, SysKeyVals);
+decode(#sys{rels = Rels} = Sys, [{rel, Name, Vsn, RelApps, Opts} | SysKeyVals])
+ when is_list(Name), is_list(Vsn), is_list(RelApps), is_list(Opts) ->
+ Rel1 = lists:foldl(fun(Opt, Rel0) ->
+ case Opt of
+ {load_dot_erlang, Value} when is_boolean(Value) ->
+ Rel0#rel{load_dot_erlang = Value};
+ _ ->
+ reltool_utils:throw_error("Illegal rel option: ~tp", [Opt])
+ end
+ end, #rel{name = Name, vsn = Vsn, rel_apps = []}, Opts),
+ Rel2 = decode(Rel1, RelApps),
+ decode(Sys#sys{rels = [Rel2 | Rels]}, SysKeyVals);
decode(#sys{} = Sys, [{Key, Val} | KeyVals]) ->
Sys3 =
case Key of
diff --git a/lib/reltool/src/reltool_sys_win.erl b/lib/reltool/src/reltool_sys_win.erl
index 92df270752..e24f468f67 100644
--- a/lib/reltool/src/reltool_sys_win.erl
+++ b/lib/reltool/src/reltool_sys_win.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -135,9 +135,9 @@ init(Options) ->
try
do_init(Options)
catch
- error:Reason ->
- io:format("~tp: ~tp~n",[Reason, erlang:get_stacktrace()]),
- exit({Reason, erlang:get_stacktrace()})
+ error:Reason:Stacktrace ->
+ io:format("~tp: ~tp~n",[Reason, Stacktrace]),
+ exit({Reason, Stacktrace})
end.
do_init([{safe_config, Safe}, {parent, Parent} | Options]) ->
diff --git a/lib/reltool/src/reltool_target.erl b/lib/reltool/src/reltool_target.erl
index 1b1461178e..dfa62479a0 100644
--- a/lib/reltool/src/reltool_target.erl
+++ b/lib/reltool/src/reltool_target.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -55,7 +55,7 @@ mandatory_modules() ->
kernel_processes(KernelApp) ->
[
{kernelProcess, heart, {heart, start, []}},
- {kernelProcess, error_logger , {error_logger, start_link, []}},
+ {kernelProcess, logger , {logger_server, start_link, []}},
{kernelProcess,
application_controller,
{application_controller, start, [KernelApp]}}
@@ -108,12 +108,8 @@ do_gen_config(#sys{root_dir = RootDir,
emit(incl_cond, A#app.incl_cond, undefined, InclDefs)}
|| A <- Apps, A#app.is_escript],
DefaultRels = reltool_utils:default_rels(),
- RelsItems =
- [{rel, R#rel.name, R#rel.vsn, do_gen_config(R, InclDefs)} ||
- R <- Rels],
- DefaultRelsItems =
- [{rel, R#rel.name, R#rel.vsn, do_gen_config(R, InclDefs)} ||
- R <- DefaultRels],
+ RelsItems = [do_gen_config(R, InclDefs) || R <- Rels],
+ DefaultRelsItems = [do_gen_config(R, InclDefs) || R <- DefaultRels],
RelsItems2 =
case InclDefs of
true -> RelsItems;
@@ -201,11 +197,20 @@ do_gen_config(#mod{name = Name,
_ ->
[]
end;
-do_gen_config(#rel{name = _Name,
- vsn = _Vsn,
- rel_apps = RelApps},
- InclDefs) ->
- [do_gen_config(RA, InclDefs) || RA <- RelApps];
+do_gen_config(#rel{name = Name,
+ vsn = Vsn,
+ rel_apps = RelApps,
+ load_dot_erlang = LoadDotErlang},
+ InclDefs) ->
+ RelAppsConfig = [do_gen_config(RA, InclDefs) || RA <- RelApps],
+ if
+ LoadDotErlang =:= false ->
+ {rel, Name, Vsn, RelAppsConfig, [{load_dot_erlang, false}]};
+ InclDefs =:= true ->
+ {rel, Name, Vsn, RelAppsConfig, [{load_dot_erlang, true}]};
+ LoadDotErlang =:= true ->
+ {rel, Name, Vsn, RelAppsConfig}
+ end;
do_gen_config(#rel_app{name = Name,
app_type = Type,
incl_apps = InclApps},
@@ -424,7 +429,7 @@ gen_script(Rel, Sys, PathFlag, Variables) ->
{error, Text}
end.
-do_gen_script(#rel{name = RelName, vsn = RelVsn},
+do_gen_script(#rel{name = RelName, vsn = RelVsn, load_dot_erlang=LoadErlangRc},
#sys{apps = Apps},
MergedApps,
PathFlag,
@@ -474,9 +479,11 @@ do_gen_script(#rel{name = RelName, vsn = RelVsn},
Type =/= none,
Type =/= load,
not lists:member(Name, InclApps)],
-
%% Apply user specific customizations
- {apply, {c, erlangrc, []}},
+ case LoadErlangRc of
+ true -> {apply, {c, erlangrc, []}};
+ false -> []
+ end,
{progress, started}
],
{ok, {script, {RelName, RelVsn}, lists:flatten(DeepList)}}.
diff --git a/lib/reltool/src/reltool_utils.erl b/lib/reltool/src/reltool_utils.erl
index 3891b5ae4d..2afa386cb3 100644
--- a/lib/reltool/src/reltool_utils.erl
+++ b/lib/reltool/src/reltool_utils.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -47,6 +47,9 @@
call/2, cast/2, reply/3]).
+%% For testing
+-export([erl_libs/2]).
+
-include_lib("kernel/include/file.hrl").
-include_lib("wx/include/wx.hrl").
-include("reltool.hrl").
@@ -55,7 +58,15 @@ root_dir() ->
code:root_dir().
erl_libs() ->
- string:lexemes(os:getenv("ERL_LIBS", ""), ":;").
+ erl_libs(os:getenv("ERL_LIBS", ""), os:type()).
+
+erl_libs(ErlLibs, OsType) when is_list(ErlLibs) ->
+ Sep =
+ case OsType of
+ {win32, _} -> ";";
+ _ -> ":"
+ end,
+ string:lexemes(ErlLibs, Sep).
lib_dirs(Dir) ->
case erl_prim_loader:list_dir(Dir) of
@@ -154,7 +165,12 @@ default_rels() ->
rel_apps = []},
#rel{name = "start_sasl",
vsn = "1.0",
- rel_apps = [#rel_app{name = sasl}]}
+ rel_apps = [#rel_app{name = sasl}]},
+ #rel{name = "no_dot_erlang", %% Needed by escript and erlc
+ vsn = "1.0",
+ rel_apps = [],
+ load_dot_erlang = false
+ }
].
choose_default(Tag, Profile, InclDefs)
diff --git a/lib/reltool/test/reltool_app_SUITE.erl b/lib/reltool/test/reltool_app_SUITE.erl
index a51ee8875a..bd0ed5edca 100644
--- a/lib/reltool/test/reltool_app_SUITE.erl
+++ b/lib/reltool/test/reltool_app_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/reltool/test/reltool_manual_gui_SUITE.erl b/lib/reltool/test/reltool_manual_gui_SUITE.erl
index 44da4ffd2c..3a4b012d2e 100644
--- a/lib/reltool/test/reltool_manual_gui_SUITE.erl
+++ b/lib/reltool/test/reltool_manual_gui_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index 49efe5aeda..bb092e8bbf 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -102,6 +102,7 @@ all() ->
create_release,
create_release_sort,
create_script,
+ create_script_without_dot_erlang,
create_script_sort,
create_target,
create_target_unicode,
@@ -142,7 +143,8 @@ all() ->
use_selected_vsn,
use_selected_vsn_relative_path,
non_standard_vsn_id,
- undefined_regexp].
+ undefined_regexp,
+ windows_erl_libs].
groups() ->
[].
@@ -170,7 +172,7 @@ break(_Config) ->
start_server(_Config) ->
{ok, Pid} = ?msym({ok, _}, reltool:start_server([])),
- Libs = lists:sort(erl_libs()),
+ Libs = reltool_test_lib:erl_libs(),
StrippedDefault =
case Libs of
[] -> {sys, []};
@@ -184,7 +186,7 @@ start_server(_Config) ->
%% Start a server process and check that it does not crash
set_config(_Config) ->
- Libs = lists:sort(erl_libs()),
+ Libs = reltool_test_lib:erl_libs(),
Default =
{sys,
[
@@ -218,7 +220,15 @@ get_config(_Config) ->
StdLibDir = filename:join(LibDir,"stdlib-"++StdVsn),
SaslLibDir = filename:join(LibDir,"sasl-"++SaslVsn),
- Sys = {sys,[{incl_cond, exclude},
+ Libs = reltool_test_lib:erl_libs(),
+ LibDirs =
+ case Libs of
+ [] -> [];
+ _ -> [{lib_dirs,Libs}]
+ end,
+
+ Sys = {sys,LibDirs ++
+ [{incl_cond, exclude},
{app,kernel,[{incl_cond,include}]},
{app,sasl,[{incl_cond,include},{vsn,SaslVsn}]},
{app,stdlib,[{incl_cond,include},{lib_dir,StdLibDir}]}]},
@@ -227,13 +237,27 @@ get_config(_Config) ->
?m({ok, Sys}, reltool:get_config(Pid,false,false)),
%% Include derived info
- ?msym({ok,{sys,[{incl_cond, exclude},
- {erts,[]},
- {app,kernel,[{incl_cond,include},{mod,_,[]}|_]},
- {app,sasl,[{incl_cond,include},{vsn,SaslVsn},{mod,_,[]}|_]},
- {app,stdlib,[{incl_cond,include},{lib_dir,StdLibDir},
- {mod,_,[]}|_]}]}},
- reltool:get_config(Pid,false,true)),
+ case Libs of
+ [] ->
+ ?msym({ok,{sys,[{incl_cond, exclude},
+ {erts,[]},
+ {app,kernel,[{incl_cond,include},{mod,_,[]}|_]},
+ {app,sasl,[{incl_cond,include},{vsn,SaslVsn},
+ {mod,_,[]}|_]},
+ {app,stdlib,[{incl_cond,include},{lib_dir,StdLibDir},
+ {mod,_,[]}|_]}]}},
+ reltool:get_config(Pid,false,true));
+ _ ->
+ ?msym({ok,{sys,[{lib_dirs,Libs},
+ {incl_cond, exclude},
+ {erts,[]},
+ {app,kernel,[{incl_cond,include},{mod,_,[]}|_]},
+ {app,sasl,[{incl_cond,include},{vsn,SaslVsn},
+ {mod,_,[]}|_]},
+ {app,stdlib,[{incl_cond,include},{lib_dir,StdLibDir},
+ {mod,_,[]}|_]}]}},
+ reltool:get_config(Pid,false,true))
+ end,
%% Include defaults
?msym({ok,{sys,[{root_dir,_},
@@ -247,8 +271,9 @@ get_config(_Config) ->
{app,stdlib,[{incl_cond,include},{vsn,undefined},
{lib_dir,StdLibDir}]},
{boot_rel,"start_clean"},
- {rel,"start_clean","1.0",[]},
- {rel,"start_sasl","1.0",[sasl]},
+ {rel,"no_dot_erlang","1.0",[],[{load_dot_erlang,false}]},
+ {rel,"start_clean","1.0",[],[{load_dot_erlang,true}]},
+ {rel,"start_sasl","1.0",[sasl],[{load_dot_erlang,true}]},
{emu_name,"beam"},
{relocatable,true},
{profile,development},
@@ -277,8 +302,9 @@ get_config(_Config) ->
{app,stdlib,[{incl_cond,include},{vsn,StdVsn},
{lib_dir,StdLibDir},{mod,_,[]}|_]},
{boot_rel,"start_clean"},
- {rel,"start_clean","1.0",[]},
- {rel,"start_sasl","1.0",[sasl]},
+ {rel,"no_dot_erlang","1.0",[],[{load_dot_erlang,false}]},
+ {rel,"start_clean","1.0",[],[{load_dot_erlang,true}]},
+ {rel,"start_sasl","1.0",[sasl],[{load_dot_erlang,true}]},
{emu_name,"beam"},
{relocatable,true},
{profile,development},
@@ -302,11 +328,11 @@ get_config(_Config) ->
%% OTP-9135, test that app_file option can be set to all | keep | strip
otp_9135(_Config) ->
- Libs = lists:sort(erl_libs()),
+ Libs = reltool_test_lib:erl_libs(),
StrippedDefaultSys =
case Libs of
[] -> [];
- _ -> {lib_dirs, Libs}
+ _ -> [{lib_dirs, Libs}]
end,
Config1 = {sys,[{app_file, keep}]}, % this is the default
@@ -546,6 +572,32 @@ create_script(_Config) ->
?m(equal, diff_script(OrigScript, Script)),
+ %% A release defaults to load_dot_erlang == true
+ {script, {RelName, RelVsn}, ScriptInstructions} = Script,
+ ?m(true, lists:member({apply,{c,erlangrc,[]}}, ScriptInstructions)),
+
+ %% Stop server
+ ?m(ok, reltool:stop(Pid)),
+ ok.
+
+create_script_without_dot_erlang(_Config) ->
+ %% Configure the server
+ RelName = "Just testing",
+ RelVsn = "1.0",
+ Config =
+ {sys,
+ [
+ {lib_dirs, []},
+ {boot_rel, RelName},
+ {rel, RelName, RelVsn, [stdlib, kernel], [{load_dot_erlang, false}]}
+ ]},
+ {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Config}])),
+
+ %% Confirm that load_dot_erlang == false was used
+ {ok, Script} = ?msym({ok, _}, reltool:get_script(Pid, RelName)),
+ {script, {RelName, RelVsn}, ScriptInstructions} = Script,
+ ?m(false, lists:member({apply,{c,erlangrc,[]}}, ScriptInstructions)),
+
%% Stop server
?m(ok, reltool:stop(Pid)),
ok.
@@ -1036,7 +1088,7 @@ create_standalone_app(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Generate standalone system with inlined archived application
-%% Check that the inlined app can not be explicitly configured
+%% Check that the inlined app cannot be explicitly configured
create_standalone_app_clash(Config) ->
%% Create archive
@@ -1656,7 +1708,7 @@ set_apps_inlined(Config) ->
?m(true, Someapp1#app.is_included),
?m(true, Someapp1#app.is_pre_included),
- %% Check that inlined app can not be configured
+ %% Check that inlined app cannot be configured
Someapp2 = Someapp1#app{incl_cond=exclude},
?msym({error,
"Application someapp is inlined in '*escript* someapp'. "
@@ -1716,13 +1768,19 @@ set_sys_and_undo(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
load_config_and_undo(Config) ->
- Sys1 = {sys,[{incl_cond, exclude},
- {app,kernel,[{incl_cond,include}]},
- {app,sasl,[{incl_cond,include}]},
- {app,stdlib,[{incl_cond,include}]},
- {app,tools,[{incl_cond,include}]}]},
+ Sys1 = {sys,Cfg1=[{incl_cond, exclude},
+ {app,kernel,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,tools,[{incl_cond,include}]}]},
{ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys1}])),
- ?m({ok, Sys1}, reltool:get_config(Pid)),
+ Libs = reltool_test_lib:erl_libs(),
+ Sys11 =
+ case Libs of
+ [] -> Sys1;
+ _ -> {sys, [{lib_dirs, Libs}|Cfg1]}
+ end,
+ ?m({ok, Sys11}, reltool:get_config(Pid)),
?m({ok,[]}, reltool_server:get_status(Pid)),
%% Get app and mod
@@ -1777,13 +1835,19 @@ load_config_and_undo(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Test that load_config is properly rolled back if it fails
load_config_fail(_Config) ->
- Sys1 = {sys,[{incl_cond, exclude},
- {app,kernel,[{incl_cond,include}]},
- {app,sasl,[{incl_cond,include}]},
- {app,stdlib,[{incl_cond,include}]},
- {app,tools,[{incl_cond,include}]}]},
+ Sys1 = {sys,Cfg1=[{incl_cond, exclude},
+ {app,kernel,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,tools,[{incl_cond,include}]}]},
{ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys1}])),
- ?m({ok, Sys1}, reltool:get_config(Pid)),
+ Libs = reltool_test_lib:erl_libs(),
+ Sys11 =
+ case Libs of
+ [] -> Sys1;
+ _ -> {sys, [{lib_dirs, Libs}|Cfg1]}
+ end,
+ ?m({ok, Sys11}, reltool:get_config(Pid)),
?m({ok,[]}, reltool_server:get_status(Pid)),
%% Get app and mod
@@ -1801,7 +1865,7 @@ load_config_fail(_Config) ->
reltool_server:load_config(Pid,Sys2)),
%% Check that a rollback is done to the old configuration
- ?m({ok, Sys1}, reltool:get_config(Pid,false,false)),
+ ?m({ok, Sys11}, reltool:get_config(Pid,false,false)),
%% and that tools is not changed (i.e. that the new configuration
%% is not applied)
@@ -2071,25 +2135,42 @@ gen_rel_files(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
save_config(Config) ->
PrivDir = ?config(priv_dir,Config),
- Sys = {sys,[{incl_cond, exclude},
- {app,kernel,[{incl_cond,include}]},
- {app,sasl,[{incl_cond,include}]},
- {app,stdlib,[{incl_cond,include}]}]},
+ Sys = {sys,Cfg=[{incl_cond, exclude},
+ {app,kernel,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]}]},
{ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
- ?m({ok, Sys}, reltool:get_config(Pid)),
+ Libs = reltool_test_lib:erl_libs(),
+ Sys1 =
+ case Libs of
+ [] -> Sys;
+ _ -> {sys, [{lib_dirs, Libs}|Cfg]}
+ end,
+ ?m({ok, Sys1}, reltool:get_config(Pid)),
Simple = filename:join(PrivDir,"save_simple.reltool"),
?m(ok, reltool_server:save_config(Pid,Simple,false,false)),
- ?m({ok,[Sys]}, file:consult(Simple)),
+ ?m({ok,[Sys1]}, file:consult(Simple)),
Derivates = filename:join(PrivDir,"save_derivates.reltool"),
?m(ok, reltool_server:save_config(Pid,Derivates,false,true)),
- ?msym({ok,[{sys,[{incl_cond, exclude},
- {erts,[]},
- {app,kernel,[{incl_cond,include},{mod,_,[]}|_]},
- {app,sasl,[{incl_cond,include},{mod,_,[]}|_]},
- {app,stdlib,[{incl_cond,include},{mod,_,[]}|_]}]}]},
- file:consult(Derivates)),
+ case Libs of
+ [] ->
+ ?msym({ok,[{sys,[{incl_cond, exclude},
+ {erts,[]},
+ {app,kernel,[{incl_cond,include},{mod,_,[]}|_]},
+ {app,sasl,[{incl_cond,include},{mod,_,[]}|_]},
+ {app,stdlib,[{incl_cond,include},{mod,_,[]}|_]}]}]},
+ file:consult(Derivates));
+ _ ->
+ ?msym({ok,[{sys,[{lib_dirs,Libs},
+ {incl_cond, exclude},
+ {erts,[]},
+ {app,kernel,[{incl_cond,include},{mod,_,[]}|_]},
+ {app,sasl,[{incl_cond,include},{mod,_,[]}|_]},
+ {app,stdlib,[{incl_cond,include},{mod,_,[]}|_]}]}]},
+ file:consult(Derivates))
+ end,
Defaults = filename:join(PrivDir,"save_defaults.reltool"),
?m(ok, reltool_server:save_config(Pid,Defaults,true,false)),
@@ -2104,8 +2185,9 @@ save_config(Config) ->
{app,stdlib,[{incl_cond,include},{vsn,undefined},
{lib_dir,undefined}]},
{boot_rel,"start_clean"},
- {rel,"start_clean","1.0",[]},
- {rel,"start_sasl","1.0",[sasl]},
+ {rel,"no_dot_erlang","1.0",[],[{load_dot_erlang,false}]},
+ {rel,"start_clean","1.0",[],[{load_dot_erlang,true}]},
+ {rel,"start_sasl","1.0",[sasl],[{load_dot_erlang,true}]},
{emu_name,"beam"},
{relocatable,true},
{profile,development},
@@ -2144,8 +2226,9 @@ save_config(Config) ->
{app,stdlib,[{incl_cond,include},{vsn,StdVsn},
{lib_dir,StdLibDir},{mod,_,[]}|_]},
{boot_rel,"start_clean"},
- {rel,"start_clean","1.0",[]},
- {rel,"start_sasl","1.0",[sasl]},
+ {rel,"no_dot_erlang","1.0",[],[{load_dot_erlang,false}]},
+ {rel,"start_clean","1.0",[],[{load_dot_erlang,true}]},
+ {rel,"start_sasl","1.0",[sasl],[{load_dot_erlang,true}]},
{emu_name,"beam"},
{relocatable,true},
{profile,development},
@@ -2542,10 +2625,18 @@ undefined_regexp(_Config) ->
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Library functions
+%% Checks that reltool_utils can correctly read Windows ERL_LIBS
+
+windows_erl_libs(_Config) ->
+ WinErlLibs =
+ "C:\\Program Files\\Erlang Libs;C:\\Program Files\\More Erlang Libs",
+ Ret = reltool_utils:erl_libs(WinErlLibs, {win32, nt}),
+ ?m(["C:\\Program Files\\Erlang Libs","C:\\Program Files\\More Erlang Libs"],
+ Ret),
+ ok.
-erl_libs() ->
- string:tokens(os:getenv("ERL_LIBS", ""), ":;").
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Library functions
datadir(Config) ->
%% Removes the trailing slash...
@@ -2555,7 +2646,7 @@ latest(App) ->
AppStr = atom_to_list(App),
AppDirs = filelib:wildcard(filename:join(code:lib_dir(),AppStr++"-*")),
[LatestAppDir|_] = lists:reverse(AppDirs),
- [_,Vsn] = string:tokens(filename:basename(LatestAppDir),"-"),
+ [_,Vsn] = string:lexemes(filename:basename(LatestAppDir),"-"),
Vsn.
rm_missing_app(Apps) ->
@@ -2631,16 +2722,11 @@ os_cmd(Cmd) when is_list(Cmd) ->
Return->
%% Find the position of the status code wich is last in the string
%% prepended with #
- case string:rchr(Return, $#) of
-
- %% This happens only if the sh command pipe is somehow interrupted
- 0->
- {98, Return};
-
- Position->
- Result = string:left(Return,Position - 1),
- Status = string:substr(Return,Position + 1, length(Return) - Position - 1),
- {list_to_integer(Status), Result}
+ case string:split(Return, "$#", trailing) of
+ [_] -> %% This happens only if the sh command pipe is somehow interrupted
+ {98, Return};
+ [Result, Status0] ->
+ {list_to_integer(string:trim(Status0)), Result}
end
end.
diff --git a/lib/reltool/test/reltool_test_lib.erl b/lib/reltool/test/reltool_test_lib.erl
index 53aeb8c08c..033d952d0a 100644
--- a/lib/reltool/test/reltool_test_lib.erl
+++ b/lib/reltool/test/reltool_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -237,7 +237,8 @@ wait_for_close() ->
wait_for_close()
end.
-
+erl_libs() ->
+ lists:sort([filename:absname(P) || P<-reltool_utils:erl_libs()]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% A small test server, which can be run standalone in a shell
diff --git a/lib/reltool/test/reltool_wx_SUITE.erl b/lib/reltool/test/reltool_wx_SUITE.erl
index 19707894ae..983c8f6c52 100644
--- a/lib/reltool/test/reltool_wx_SUITE.erl
+++ b/lib/reltool/test/reltool_wx_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -74,7 +74,12 @@ start_all_windows(_Config) ->
%% Test that server pid can be fetched, and that server is alive
{ok, Server} = ?msym({ok,_}, reltool:get_server(SysPid)),
?m(true, erlang:is_process_alive(Server)),
- ?m({ok,{sys,[]}}, reltool:get_config(Server)),
+ Sys =
+ case reltool_test_lib:erl_libs() of
+ [] -> [];
+ Libs -> [{lib_dirs,Libs}]
+ end,
+ ?m({ok,{sys,Sys}}, reltool:get_config(Server)),
%% Terminate
check_no_win_crash(),
diff --git a/lib/reltool/test/rtt.erl b/lib/reltool/test/rtt.erl
index d9e8e5520d..479241d86b 100644
--- a/lib/reltool/test/rtt.erl
+++ b/lib/reltool/test/rtt.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/reltool/vsn.mk b/lib/reltool/vsn.mk
index 49997b1e52..c5aacfba38 100644
--- a/lib/reltool/vsn.mk
+++ b/lib/reltool/vsn.mk
@@ -1 +1 @@
-RELTOOL_VSN = 0.7.5
+RELTOOL_VSN = 0.8
diff --git a/lib/runtime_tools/c_src/Makefile.in b/lib/runtime_tools/c_src/Makefile.in
index 4530a83aee..75b3a98d56 100644
--- a/lib/runtime_tools/c_src/Makefile.in
+++ b/lib/runtime_tools/c_src/Makefile.in
@@ -36,7 +36,7 @@ CC = $(DED_CC)
CFLAGS = $(DED_CFLAGS) -I./
LD = $(DED_LD)
SHELL = /bin/sh
-LIBS = $(DED_LIBS)
+LIBS = $(DED_LIBS) @LIBS@
LDFLAGS += $(DED_LDFLAGS)
TRACE_LIBNAME = dyntrace trace_file_drv trace_ip_drv
@@ -58,7 +58,7 @@ TYPE_FLAGS = $(CFLAGS)
endif
endif
-ALL_CFLAGS = @DEFS@ $(TYPE_FLAGS) $(TRACE_DRV_INCLUDES) \
+ALL_CFLAGS = @DEFS@ @ERTS_CONFIG_H_IDIR@ $(TYPE_FLAGS) $(TRACE_DRV_INCLUDES) \
-I$(OBJDIR) -I$(ERL_TOP)/erts/emulator/$(TARGET)
ROOTDIR = $(ERL_TOP)/lib
@@ -75,7 +75,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/runtime_tools-$(VSN)
# Misc Macros
# ----------------------------------------------------
-TRACE_LIBS = $(foreach LIB, $(TRACE_LIBNAME), $(LIBDIR)/$(LIB)$(TYPEMARKER).@DED_EXT@)
+TRACE_LIBS = $(foreach LIB, $(TRACE_LIBNAME), $(LIBDIR)/$(LIB)$(TYPEMARKER).$(DED_EXT))
# ----------------------------------------------------
# Targets
@@ -94,7 +94,7 @@ $(LIBDIR):
$(OBJDIR)/%$(TYPEMARKER).o: %.c dyntrace_lttng.h
$(V_CC) -c -o $@ $(ALL_CFLAGS) $<
-$(LIBDIR)/%$(TYPEMARKER).@DED_EXT@: $(OBJDIR)/%$(TYPEMARKER).o
+$(LIBDIR)/%$(TYPEMARKER).$(DED_EXT): $(OBJDIR)/%$(TYPEMARKER).o
$(V_LD) $(LDFLAGS) -o $@ $^ $(LIBS)
clean:
diff --git a/lib/runtime_tools/doc/src/LTTng.xml b/lib/runtime_tools/doc/src/LTTng.xml
index 392d54857c..89cbc805d8 100644
--- a/lib/runtime_tools/doc/src/LTTng.xml
+++ b/lib/runtime_tools/doc/src/LTTng.xml
@@ -3,7 +3,7 @@
<chapter>
<header>
<copyright>
- <year>2016</year><year>2017</year>
+ <year>2016</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -111,7 +111,7 @@ $ make </code>
<p><em>process_register</em></p>
<list type="bulleted">
<item><c>pid : string</c> :: Process ID. Ex. <c>"&lt;0.131.0&gt;"</c></item>
- <item><c>name : string</c> :: Registered name. Ex. <c>"error_logger"</c></item>
+ <item><c>name : string</c> :: Registered name. Ex. <c>"logger"</c></item>
<item><c>type : string</c> :: <c>"register" | "unregister"</c></item>
</list>
<p>Example:</p>
@@ -134,7 +134,7 @@ $ make </code>
<p><em>port_open</em></p>
<list type="bulleted">
<item><c>pid : string</c> :: Process ID. Ex. <c>"&lt;0.131.0&gt;"</c></item>
- <item><c>driver : string</c> :: Driver name. Ex. <c>"efile"</c></item>
+ <item><c>driver : string</c> :: Driver name. Ex. <c>"tcp_inet"</c></item>
<item><c>port : string</c> :: Port ID. Ex. <c>"#Port&lt;0.1031&gt;"</c></item>
</list>
<p>
@@ -323,7 +323,7 @@ $ make </code>
<p><em>driver_init</em></p>
<list type="bulleted">
- <item><c>driver : string</c> :: Driver name. Ex. <c>"efile"</c></item>
+ <item><c>driver : string</c> :: Driver name. Ex. <c>"tcp_inet"</c></item>
<item><c>major : integer</c> :: Major version. Ex. <c>3</c></item>
<item><c>minor : integer</c> :: Minor version. Ex. <c>1</c></item>
<item><c>flags : integer</c> :: Flags. Ex. <c>1</c></item>
@@ -334,7 +334,7 @@ $ make </code>
<p><em>driver_start</em></p>
<list type="bulleted">
<item><c>pid : string</c> :: Process ID. Ex. <c>"&lt;0.131.0&gt;"</c></item>
- <item><c>driver : string</c> :: Driver name. Ex. <c>"efile"</c></item>
+ <item><c>driver : string</c> :: Driver name. Ex. <c>"tcp_inet"</c></item>
<item><c>port : string</c> :: Port ID. Ex. <c>"#Port&lt;0.1031&gt;"</c></item>
</list>
<p>Example:</p>
@@ -344,7 +344,7 @@ $ make </code>
<list type="bulleted">
<item><c>pid : string</c> :: Process ID. Ex. <c>"&lt;0.131.0&gt;"</c></item>
<item><c>port : string</c> :: Port ID. Ex. <c>"#Port&lt;0.1031&gt;"</c></item>
- <item><c>driver : string</c> :: Driver name. Ex. <c>"efile"</c></item>
+ <item><c>driver : string</c> :: Driver name. Ex. <c>"tcp_inet"</c></item>
<item><c>bytes : integer</c> :: Size of data returned. Ex. <c>82</c></item>
</list>
<p>Example:</p>
@@ -354,7 +354,7 @@ $ make </code>
<list type="bulleted">
<item><c>pid : string</c> :: Process ID. Ex. <c>"&lt;0.131.0&gt;"</c></item>
<item><c>port : string</c> :: Port ID. Ex. <c>"#Port&lt;0.1031&gt;"</c></item>
- <item><c>driver : string</c> :: Driver name. Ex. <c>"efile"</c></item>
+ <item><c>driver : string</c> :: Driver name. Ex. <c>"tcp_inet"</c></item>
<item><c>bytes : integer</c> :: Size of data returned. Ex. <c>82</c></item>
</list>
<p>Example:</p>
@@ -364,7 +364,7 @@ $ make </code>
<list type="bulleted">
<item><c>pid : string</c> :: Process ID. Ex. <c>"&lt;0.131.0&gt;"</c></item>
<item><c>port : string</c> :: Port ID. Ex. <c>"#Port&lt;0.1031&gt;"</c></item>
- <item><c>driver : string</c> :: Driver name. Ex. <c>"efile"</c></item>
+ <item><c>driver : string</c> :: Driver name. Ex. <c>"tcp_inet"</c></item>
</list>
<p>Example:</p>
<code type="none">driver_ready_input: { cpu_id = 5 }, { pid = "&lt;0.189.0&gt;", port = "#Port&lt;0.3637&gt;", driver = "inet_gethost 4 " }</code>
@@ -373,7 +373,7 @@ $ make </code>
<list type="bulleted">
<item><c>pid : string</c> :: Process ID. Ex. <c>"&lt;0.131.0&gt;"</c></item>
<item><c>port : string</c> :: Port ID. Ex. <c>"#Port&lt;0.1031&gt;"</c></item>
- <item><c>driver : string</c> :: Driver name. Ex. <c>"efile"</c></item>
+ <item><c>driver : string</c> :: Driver name. Ex. <c>"tcp_inet"</c></item>
</list>
<p>Example:</p>
<code type="none">driver_ready_output: { cpu_id = 5 }, { pid = "&lt;0.194.0&gt;", port = "#Port&lt;0.3663&gt;", driver = "tcp_inet" }</code>
@@ -382,14 +382,14 @@ $ make </code>
<list type="bulleted">
<item><c>pid : string</c> :: Process ID. Ex. <c>"&lt;0.131.0&gt;"</c></item>
<item><c>port : string</c> :: Port ID. Ex. <c>"#Port&lt;0.1031&gt;"</c></item>
- <item><c>driver : string</c> :: Driver name. Ex. <c>"efile"</c></item>
+ <item><c>driver : string</c> :: Driver name. Ex. <c>"tcp_inet"</c></item>
</list>
<p>Example:</p>
<code type="none">driver_timeout: { cpu_id = 5 }, { pid = "&lt;0.196.0&gt;", port = "#Port&lt;0.3664&gt;", driver = "tcp_inet" }</code>
<p><em>driver_stop_select</em></p>
<list type="bulleted">
- <item><c>driver : string</c> :: Driver name. Ex. <c>"efile"</c></item>
+ <item><c>driver : string</c> :: Driver name. Ex. <c>"tcp_inet"</c></item>
</list>
<p>Example:</p>
<code type="none">driver_stop_select: { cpu_id = 5 }, { driver = "unknown" }</code>
@@ -398,7 +398,7 @@ $ make </code>
<list type="bulleted">
<item><c>pid : string</c> :: Process ID. Ex. <c>"&lt;0.131.0&gt;"</c></item>
<item><c>port : string</c> :: Port ID. Ex. <c>"#Port&lt;0.1031&gt;"</c></item>
- <item><c>driver : string</c> :: Driver name. Ex. <c>"efile"</c></item>
+ <item><c>driver : string</c> :: Driver name. Ex. <c>"tcp_inet"</c></item>
</list>
<p>Example:</p>
<code type="none">driver_flush: { cpu_id = 7 }, { pid = "&lt;0.204.0&gt;", port = "#Port&lt;0.3686&gt;", driver = "tcp_inet" }</code>
@@ -407,32 +407,32 @@ $ make </code>
<list type="bulleted">
<item><c>pid : string</c> :: Process ID. Ex. <c>"&lt;0.131.0&gt;"</c></item>
<item><c>port : string</c> :: Port ID. Ex. <c>"#Port&lt;0.1031&gt;"</c></item>
- <item><c>driver : string</c> :: Driver name. Ex. <c>"efile"</c></item>
+ <item><c>driver : string</c> :: Driver name. Ex. <c>"tcp_inet"</c></item>
</list>
<p>Example:</p>
- <code type="none">driver_stop: { cpu_id = 5 }, { pid = "[]", port = "#Port&lt;0.3673&gt;", driver = "efile" }</code>
+ <code type="none">driver_stop: { cpu_id = 5 }, { pid = "[]", port = "#Port&lt;0.3673&gt;", driver = "tcp_inet" }</code>
<p><em>driver_process_exit</em></p>
<list type="bulleted">
<item><c>pid : string</c> :: Process ID. Ex. <c>"&lt;0.131.0&gt;"</c></item>
<item><c>port : string</c> :: Port ID. Ex. <c>"#Port&lt;0.1031&gt;"</c></item>
- <item><c>driver : string</c> :: Driver name. Ex. <c>"efile"</c></item>
+ <item><c>driver : string</c> :: Driver name. Ex. <c>"tcp_inet"</c></item>
</list>
<p><em>driver_ready_async</em></p>
<list type="bulleted">
<item><c>pid : string</c> :: Process ID. Ex. <c>"&lt;0.131.0&gt;"</c></item>
<item><c>port : string</c> :: Port ID. Ex. <c>"#Port&lt;0.1031&gt;"</c></item>
- <item><c>driver : string</c> :: Driver name. Ex. <c>"efile"</c></item>
+ <item><c>driver : string</c> :: Driver name. Ex. <c>"tcp_inet"</c></item>
</list>
<p>Example:</p>
- <code type="none">driver_ready_async: { cpu_id = 3 }, { pid = "&lt;0.181.0&gt;", port = "#Port&lt;0.3622&gt;", driver = "efile" }</code>
+ <code type="none">driver_ready_async: { cpu_id = 3 }, { pid = "&lt;0.181.0&gt;", port = "#Port&lt;0.3622&gt;", driver = "tcp_inet" }</code>
<p><em>driver_call</em></p>
<list type="bulleted">
<item><c>pid : string</c> :: Process ID. Ex. <c>"&lt;0.131.0&gt;"</c></item>
<item><c>port : string</c> :: Port ID. Ex. <c>"#Port&lt;0.1031&gt;"</c></item>
- <item><c>driver : string</c> :: Driver name. Ex. <c>"efile"</c></item>
+ <item><c>driver : string</c> :: Driver name. Ex. <c>"tcp_inet"</c></item>
<item><c>command : integer</c> :: Command integer. Ex. <c>1</c></item>
<item><c>bytes : integer</c> :: Size of data returned. Ex. <c>82</c></item>
</list>
@@ -443,7 +443,7 @@ $ make </code>
<list type="bulleted">
<item><c>pid : string</c> :: Process ID. Ex. <c>"&lt;0.131.0&gt;"</c></item>
<item><c>port : string</c> :: Port ID. Ex. <c>"#Port&lt;0.1031&gt;"</c></item>
- <item><c>driver : string</c> :: Driver name. Ex. <c>"efile"</c></item>
+ <item><c>driver : string</c> :: Driver name. Ex. <c>"tcp_inet"</c></item>
<item><c>command : integer</c> :: Command integer. Ex. <c>1</c></item>
<item><c>bytes : integer</c> :: Size of data returned. Ex. <c>82</c></item>
</list>
diff --git a/lib/runtime_tools/doc/src/Makefile b/lib/runtime_tools/doc/src/Makefile
index ec19a4ce59..2399ed51e0 100644
--- a/lib/runtime_tools/doc/src/Makefile
+++ b/lib/runtime_tools/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2016. All Rights Reserved.
+# Copyright Ericsson AB 1999-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -41,7 +41,13 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
# Target Specs
# ----------------------------------------------------
XML_APPLICATION_FILES = ref_man.xml
-XML_REF3_FILES = dbg.xml dyntrace.xml erts_alloc_config.xml system_information.xml msacc.xml
+XML_REF3_FILES = \
+ dbg.xml \
+ dyntrace.xml \
+ erts_alloc_config.xml \
+ system_information.xml \
+ msacc.xml \
+ scheduler.xml
XML_REF6_FILES = runtime_tools_app.xml
XML_PART_FILES = part.xml
@@ -54,8 +60,9 @@ BOOK_FILES = book.xml
XML_FILES = \
$(BOOK_FILES) $(XML_CHAPTER_FILES) \
$(XML_PART_FILES) $(XML_REF3_FILES) \
- $(XML_REF6_FILES) $(XML_APPLICATION_FILES) \
- $(GENERATED_XML_FILES)
+ $(XML_REF6_FILES) $(XML_APPLICATION_FILES)
+
+XML_GEN_FILES = $(GENERATED_XML_FILES:%=$(XMLDIR)/%)
GIF_FILES =
@@ -91,7 +98,7 @@ SPECS_FLAGS = -I../../include -I../../../kernel/src
# Targets
# ----------------------------------------------------
-%.xml: $(ERL_TOP)/HOWTO/%.md $(ERL_TOP)/make/emd2exml
+$(XMLDIR)/%.xml: $(ERL_TOP)/HOWTO/%.md $(ERL_TOP)/make/emd2exml
$(ERL_TOP)/make/emd2exml $< $@
$(HTMLDIR)/%.gif: %.gif
@@ -113,6 +120,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(MAN6DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
diff --git a/lib/runtime_tools/doc/src/dbg.xml b/lib/runtime_tools/doc/src/dbg.xml
index 95f74d4607..e15fc3efe6 100644
--- a/lib/runtime_tools/doc/src/dbg.xml
+++ b/lib/runtime_tools/doc/src/dbg.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>dbg.sgml</file>
</header>
- <module>dbg</module>
+ <module since="">dbg</module>
<modulesummary>The Text Based Trace Facility</modulesummary>
<description>
<p>This module implements a text based interface to the
@@ -68,7 +68,7 @@
</description>
<funcs>
<func>
- <name>fun2ms(LiteralFun) -> MatchSpec</name>
+ <name since="">fun2ms(LiteralFun) -> MatchSpec</name>
<fsummary>Pseudo function that transforms fun syntax to match_spec.</fsummary>
<type>
<v>LiteralFun = fun() literal</v>
@@ -113,7 +113,7 @@
<p>The imported variables will be replaced by match_spec
<c>const</c> expressions, which is consistent with the
static scoping for Erlang <c>fun()</c>s. Local or global
- function calls can not be in the guard or body of the fun
+ function calls cannot be in the guard or body of the fun
however. Calls to builtin match_spec functions of course is
allowed:</p>
<pre>
@@ -145,14 +145,14 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
</desc>
</func>
<func>
- <name>h() -> ok </name>
+ <name since="">h() -> ok </name>
<fsummary>Give a list of available help items on standard output.</fsummary>
<desc>
<p>Gives a list of items for brief online help.</p>
</desc>
</func>
<func>
- <name>h(Item) -> ok </name>
+ <name since="">h(Item) -> ok </name>
<fsummary>Give brief help for an item.</fsummary>
<type>
<v>Item = atom()</v>
@@ -163,14 +163,14 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
</desc>
</func>
<func>
- <name>p(Item) -> {ok, MatchDesc} | {error, term()} </name>
+ <name since="">p(Item) -> {ok, MatchDesc} | {error, term()} </name>
<fsummary>Trace messages to and from Item.</fsummary>
<desc>
<p>Equivalent to <c>p(Item, [m])</c>.</p>
</desc>
</func>
<func>
- <name>p(Item, Flags) -> {ok, MatchDesc} | {error, term()}</name>
+ <name since="">p(Item, Flags) -> {ok, MatchDesc} | {error, term()}</name>
<fsummary>Trace Item according to Flags.</fsummary>
<type>
<v>MatchDesc = [MatchNum]</v>
@@ -303,14 +303,14 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
</desc>
</func>
<func>
- <name>c(Mod, Fun, Args)</name>
+ <name since="">c(Mod, Fun, Args)</name>
<fsummary>Evaluate <c>apply(M,F,Args)</c>with <c>all</c>trace flags set.</fsummary>
<desc>
<p>Equivalent to <c>c(Mod, Fun, Args, all)</c>.</p>
</desc>
</func>
<func>
- <name>c(Mod, Fun, Args, Flags)</name>
+ <name since="">c(Mod, Fun, Args, Flags)</name>
<fsummary>Evaluate <c>apply(M,F,Args)</c>with <c>Flags</c>trace flags set.</fsummary>
<desc>
<p>Evaluates the expression <c>apply(Mod, Fun, Args)</c> with the trace
@@ -319,35 +319,35 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
</desc>
</func>
<func>
- <name>i() -> ok</name>
+ <name since="">i() -> ok</name>
<fsummary>Display information about all traced processes and ports.</fsummary>
<desc>
<p>Displays information about all traced processes and ports.</p>
</desc>
</func>
<func>
- <name>tp(Module,MatchSpec)</name>
+ <name since="">tp(Module,MatchSpec)</name>
<fsummary>Set pattern for traced global function calls</fsummary>
<desc>
<p>Same as tp({Module, '_', '_'}, MatchSpec)</p>
</desc>
</func>
<func>
- <name>tp(Module,Function,MatchSpec)</name>
+ <name since="">tp(Module,Function,MatchSpec)</name>
<fsummary>Set pattern for traced global function calls</fsummary>
<desc>
<p>Same as tp({Module, Function, '_'}, MatchSpec)</p>
</desc>
</func>
<func>
- <name>tp(Module, Function, Arity, MatchSpec)</name>
+ <name since="">tp(Module, Function, Arity, MatchSpec)</name>
<fsummary>Set pattern for traced global function calls</fsummary>
<desc>
<p>Same as tp({Module, Function, Arity}, MatchSpec)</p>
</desc>
</func>
<func>
- <name>tp({Module, Function, Arity}, MatchSpec) -> {ok, MatchDesc} | {error, term()}</name>
+ <name since="">tp({Module, Function, Arity}, MatchSpec) -> {ok, MatchDesc} | {error, term()}</name>
<fsummary>Set pattern for traced global function calls</fsummary>
<type>
<v>Module = atom() | '_'</v>
@@ -410,28 +410,28 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
</desc>
</func>
<func>
- <name>tpl(Module,MatchSpec)</name>
+ <name since="">tpl(Module,MatchSpec)</name>
<fsummary>Set pattern for traced local (as well as global) function calls</fsummary>
<desc>
<p>Same as tpl({Module, '_', '_'}, MatchSpec)</p>
</desc>
</func>
<func>
- <name>tpl(Module,Function,MatchSpec)</name>
+ <name since="">tpl(Module,Function,MatchSpec)</name>
<fsummary>Set pattern for traced local (as well as global) function calls</fsummary>
<desc>
<p>Same as tpl({Module, Function, '_'}, MatchSpec)</p>
</desc>
</func>
<func>
- <name>tpl(Module, Function, Arity, MatchSpec)</name>
+ <name since="">tpl(Module, Function, Arity, MatchSpec)</name>
<fsummary>Set pattern for traced local (as well as global) function calls</fsummary>
<desc>
<p>Same as tpl({Module, Function, Arity}, MatchSpec)</p>
</desc>
</func>
<func>
- <name>tpl({Module, Function, Arity}, MatchSpec) -> {ok, MatchDesc} | {error, term()}</name>
+ <name since="">tpl({Module, Function, Arity}, MatchSpec) -> {ok, MatchDesc} | {error, term()}</name>
<fsummary>Set pattern for traced local (as well as global) function calls</fsummary>
<desc>
<p>This function works as <seealso marker="#tp-2"><c>tp/2</c></seealso>, but enables
@@ -442,7 +442,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
<func>
- <name>tpe(Event, MatchSpec) -> {ok, MatchDesc} | {error, term()}</name>
+ <name since="OTP 19.0">tpe(Event, MatchSpec) -> {ok, MatchDesc} | {error, term()}</name>
<fsummary>Set pattern for traced event</fsummary>
<type>
<v>Event = send | 'receive'</v>
@@ -484,35 +484,35 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
</desc>
</func>
<func>
- <name>ctp()</name>
+ <name since="">ctp()</name>
<fsummary>Clear call trace pattern for the specified functions</fsummary>
<desc>
<p>Same as ctp({'_', '_', '_'})</p>
</desc>
</func>
<func>
- <name>ctp(Module)</name>
+ <name since="">ctp(Module)</name>
<fsummary>Clear call trace pattern for the specified functions</fsummary>
<desc>
<p>Same as ctp({Module, '_', '_'})</p>
</desc>
</func>
<func>
- <name>ctp(Module, Function)</name>
+ <name since="">ctp(Module, Function)</name>
<fsummary>Clear call trace pattern for the specified functions</fsummary>
<desc>
<p>Same as ctp({Module, Function, '_'})</p>
</desc>
</func>
<func>
- <name>ctp(Module, Function, Arity)</name>
+ <name since="">ctp(Module, Function, Arity)</name>
<fsummary>Clear call trace pattern for the specified functions</fsummary>
<desc>
<p>Same as ctp({Module, Function, Arity})</p>
</desc>
</func>
<func>
- <name>ctp({Module, Function, Arity}) -> {ok, MatchDesc} | {error, term()}</name>
+ <name since="">ctp({Module, Function, Arity}) -> {ok, MatchDesc} | {error, term()}</name>
<fsummary>Clear call trace pattern for the specified functions</fsummary>
<type>
<v>Module = atom() | '_'</v>
@@ -533,35 +533,35 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
</desc>
</func>
<func>
- <name>ctpl()</name>
+ <name since="">ctpl()</name>
<fsummary>Clear call trace pattern for the specified functions</fsummary>
<desc>
<p>Same as ctpl({'_', '_', '_'})</p>
</desc>
</func>
<func>
- <name>ctpl(Module)</name>
+ <name since="">ctpl(Module)</name>
<fsummary>Clear call trace pattern for the specified functions</fsummary>
<desc>
<p>Same as ctpl({Module, '_', '_'})</p>
</desc>
</func>
<func>
- <name>ctpl(Module, Function)</name>
+ <name since="">ctpl(Module, Function)</name>
<fsummary>Clear call trace pattern for the specified functions</fsummary>
<desc>
<p>Same as ctpl({Module, Function, '_'})</p>
</desc>
</func>
<func>
- <name>ctpl(Module, Function, Arity)</name>
+ <name since="">ctpl(Module, Function, Arity)</name>
<fsummary>Clear call trace pattern for the specified functions</fsummary>
<desc>
<p>Same as ctpl({Module, Function, Arity})</p>
</desc>
</func>
<func>
- <name>ctpl({Module, Function, Arity}) -> {ok, MatchDesc} | {error, term()}</name>
+ <name since="">ctpl({Module, Function, Arity}) -> {ok, MatchDesc} | {error, term()}</name>
<fsummary>Clear call trace pattern for the specified functions</fsummary>
<desc>
<p>This function works as <seealso marker="#ctp-1"><c>ctp/1</c></seealso>, but only disables
@@ -570,35 +570,35 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
</desc>
</func>
<func>
- <name>ctpg()</name>
+ <name since="">ctpg()</name>
<fsummary>Clear call trace pattern for the specified functions</fsummary>
<desc>
<p>Same as ctpg({'_', '_', '_'})</p>
</desc>
</func>
<func>
- <name>ctpg(Module)</name>
+ <name since="">ctpg(Module)</name>
<fsummary>Clear call trace pattern for the specified functions</fsummary>
<desc>
<p>Same as ctpg({Module, '_', '_'})</p>
</desc>
</func>
<func>
- <name>ctpg(Module, Function)</name>
+ <name since="">ctpg(Module, Function)</name>
<fsummary>>Clear call trace pattern for the specified functions</fsummary>
<desc>
<p>Same as ctpg({Module, Function, '_'})</p>
</desc>
</func>
<func>
- <name>ctpg(Module, Function, Arity)</name>
+ <name since="">ctpg(Module, Function, Arity)</name>
<fsummary>>Clear call trace pattern for the specified functions</fsummary>
<desc>
<p>Same as ctpg({Module, Function, Arity})</p>
</desc>
</func>
<func>
- <name>ctpg({Module, Function, Arity}) -> {ok, MatchDesc} | {error, term()}</name>
+ <name since="">ctpg({Module, Function, Arity}) -> {ok, MatchDesc} | {error, term()}</name>
<fsummary>Clear call trace pattern for the specified functions</fsummary>
<desc>
<p>This function works as <seealso marker="#ctp-1"><c>ctp/1</c></seealso>, but only disables
@@ -607,7 +607,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
</desc>
</func>
<func>
- <name>ctpe(Event) -> {ok, MatchDesc} | {error, term()}</name>
+ <name since="OTP 19.0">ctpe(Event) -> {ok, MatchDesc} | {error, term()}</name>
<fsummary>Clear trace pattern for the specified event</fsummary>
<type>
<v>Event = send | 'receive'</v>
@@ -623,7 +623,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
</desc>
</func>
<func>
- <name>ltp() -> ok</name>
+ <name since="">ltp() -> ok</name>
<fsummary>List saved and built-in match specifications on the console.</fsummary>
<desc>
<p>Use this function to recall all match specifications previously
@@ -654,7 +654,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
</desc>
</func>
<func>
- <name>dtp() -> ok</name>
+ <name since="">dtp() -> ok</name>
<fsummary>Delete all saved match specifications.</fsummary>
<desc>
<p>Use this function to "forget" all match specifications
@@ -665,7 +665,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
</desc>
</func>
<func>
- <name>dtp(N) -> ok</name>
+ <name since="">dtp(N) -> ok</name>
<fsummary>Delete a specific saved match_spec.</fsummary>
<type>
<v>N = integer()</v>
@@ -676,7 +676,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
</desc>
</func>
<func>
- <name>wtp(Name) -> ok | {error, IOError}</name>
+ <name since="">wtp(Name) -> ok | {error, IOError}</name>
<fsummary>Write all saved and built-in match specifications to a file</fsummary>
<type>
<v>Name = string()</v>
@@ -699,7 +699,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
</desc>
</func>
<func>
- <name>rtp(Name) -> ok | {error, Error}</name>
+ <name since="">rtp(Name) -> ok | {error, Error}</name>
<fsummary>Read saved match specifications from file.</fsummary>
<type>
<v>Name = string()</v>
@@ -728,7 +728,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
</desc>
</func>
<func>
- <name>n(Nodename) -> {ok, Nodename} | {error, Reason}</name>
+ <name since="">n(Nodename) -> {ok, Nodename} | {error, Reason}</name>
<fsummary>Add a remote node to the list of traced nodes</fsummary>
<type>
<v>Nodename = atom()</v>
@@ -756,7 +756,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
<c>cant_add_local_node</c> is returned.
</p>
<p>If a trace port (see <seealso marker="#trace_port-2"><c>trace_port/2</c></seealso>) is
- running on the local node, remote nodes can not be traced with
+ running on the local node, remote nodes cannot be traced with
a tracer process. The error reason
<c>cant_trace_remote_pid_to_local_port</c> is returned. A
trace port can however be started on the remote node with the
@@ -767,7 +767,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
</desc>
</func>
<func>
- <name>cn(Nodename) -> ok</name>
+ <name since="">cn(Nodename) -> ok</name>
<fsummary>Clear a node from the list of traced nodes.</fsummary>
<type>
<v>Nodename = atom()</v>
@@ -782,14 +782,14 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
</desc>
</func>
<func>
- <name>ln() -> ok</name>
+ <name since="">ln() -> ok</name>
<fsummary>Show the list of traced nodes on the console.</fsummary>
<desc>
<p>Shows the list of traced nodes on the console.</p>
</desc>
</func>
<func>
- <name>tracer() -> {ok, pid()} | {error, already_started}</name>
+ <name since="">tracer() -> {ok, pid()} | {error, already_started}</name>
<fsummary>Start a tracer server that handles trace messages.</fsummary>
<desc>
<p>This function starts a server on the local node that will
@@ -805,7 +805,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
</desc>
</func>
<func>
- <name>tracer(Type, Data) -> {ok, pid()} | {error, Error}</name>
+ <name since="">tracer(Type, Data) -> {ok, pid()} | {error, Error}</name>
<fsummary>Start a tracer server with additional parameters</fsummary>
<type>
<v>Type = port | process | module</v>
@@ -815,7 +815,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
<v>HandlerSpec = {HandlerFun, InitialData}</v>
<v>HandlerFun = fun() (two arguments)</v>
<v>ModuleSpec = fun() (no arguments) | {TracerModule, TracerState}</v>
- <v>ModuleModule = atom()</v>
+ <v>TracerModule = atom()</v>
<v>InitialData = TracerState = term()</v>
</type>
<desc>
@@ -859,7 +859,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
</desc>
</func>
<func>
- <name>tracer(Nodename, Type, Data) -> {ok, Nodename} | {error, Reason}</name>
+ <name since="">tracer(Nodename, Type, Data) -> {ok, Nodename} | {error, Reason}</name>
<fsummary>Start a tracer server on given node with additional parameters</fsummary>
<type>
<v>Nodename = atom()</v>
@@ -881,7 +881,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
</desc>
</func>
<func>
- <name>trace_port(Type, Parameters) -> fun()</name>
+ <name since="">trace_port(Type, Parameters) -> fun()</name>
<fsummary>Create and returns a trace port generating<em>fun</em></fsummary>
<type>
<v>Type = ip | file</v>
@@ -958,28 +958,28 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
</desc>
</func>
<func>
- <name>flush_trace_port()</name>
+ <name since="">flush_trace_port()</name>
<fsummary>Equivalent to flush_trace_port(node()).</fsummary>
<desc>
<p>Equivalent to <c>flush_trace_port(node())</c>.</p>
</desc>
</func>
<func>
- <name>flush_trace_port(Nodename) -> ok | {error, Reason}</name>
+ <name since="">flush_trace_port(Nodename) -> ok | {error, Reason}</name>
<fsummary>Flush internal data buffers in a trace driver on the given node.</fsummary>
<desc>
<p>Equivalent to <c>trace_port_control(Nodename,flush)</c>.</p>
</desc>
</func>
<func>
- <name>trace_port_control(Operation)</name>
+ <name since="">trace_port_control(Operation)</name>
<fsummary>Equivalent to trace_port_control(node(),Operation).</fsummary>
<desc>
<p>Equivalent to <c>trace_port_control(node(),Operation)</c>.</p>
</desc>
</func>
<func>
- <name>trace_port_control(Nodename,Operation) -> ok | {ok, Result} | {error, Reason}</name>
+ <name since="">trace_port_control(Nodename,Operation) -> ok | {ok, Result} | {error, Reason}</name>
<fsummary>Perform a control operation on the active trace port driver on the given node.</fsummary>
<type>
<v>Nodename = atom()</v>
@@ -1013,7 +1013,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
</desc>
</func>
<func>
- <name>trace_client(Type, Parameters) -> pid()</name>
+ <name since="">trace_client(Type, Parameters) -> pid()</name>
<fsummary>Start a trace client that reads messages created by a trace port driver</fsummary>
<type>
<v>Type = ip | file | follow_file</v>
@@ -1080,7 +1080,7 @@ hello</pre>
</desc>
</func>
<func>
- <name>trace_client(Type, Parameters, HandlerSpec) -> pid()</name>
+ <name since="">trace_client(Type, Parameters, HandlerSpec) -> pid()</name>
<fsummary>Start a trace client that reads messages created by a trace port driver, with a user defined handler</fsummary>
<type>
<v>Type = ip | file | follow_file</v>
@@ -1110,7 +1110,7 @@ hello</pre>
</desc>
</func>
<func>
- <name>stop_trace_client(Pid) -> ok</name>
+ <name since="">stop_trace_client(Pid) -> ok</name>
<fsummary>Stop a trace client gracefully.</fsummary>
<type>
<v>Pid = pid()</v>
@@ -1123,14 +1123,14 @@ hello</pre>
</desc>
</func>
<func>
- <name>get_tracer()</name>
+ <name since="">get_tracer()</name>
<fsummary>Equivalent to get_tracer(node()).</fsummary>
<desc>
<p>Equivalent to <c>get_tracer(node())</c>.</p>
</desc>
</func>
<func>
- <name>get_tracer(Nodename) -> {ok, Tracer}</name>
+ <name since="">get_tracer(Nodename) -> {ok, Tracer}</name>
<fsummary>Return the process or port to which all trace messages are sent.</fsummary>
<type>
<v>Nodename = atom()</v>
@@ -1142,7 +1142,7 @@ hello</pre>
</desc>
</func>
<func>
- <name>stop() -> ok</name>
+ <name since="">stop() -> ok</name>
<fsummary>Stop the <c>dbg</c>server and the tracing of all processes.</fsummary>
<desc>
<p>Stops the <c>dbg</c> server and clears all trace flags for
@@ -1153,7 +1153,7 @@ hello</pre>
</desc>
</func>
<func>
- <name>stop_clear() -> ok</name>
+ <name since="">stop_clear() -> ok</name>
<fsummary>Stop the <c>dbg</c>server and the tracing of all processes, and clears trace patterns.</fsummary>
<desc>
<p>Same as stop/0, but also clears all trace patterns on global functions calls.</p>
diff --git a/lib/runtime_tools/doc/src/dyntrace.xml b/lib/runtime_tools/doc/src/dyntrace.xml
index 0cdcecab68..4935dfcd71 100644
--- a/lib/runtime_tools/doc/src/dyntrace.xml
+++ b/lib/runtime_tools/doc/src/dyntrace.xml
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>dyntrace.xml</file>
</header>
- <module>dyntrace</module>
+ <module since="OTP R15B01">dyntrace</module>
<modulesummary>Interface to dynamic tracing</modulesummary>
<description>
<p>This module implements interfaces to dynamic tracing, should such be compiled into the virtual machine. For a standard and/or commercial build, no dynamic tracing is available, in which case none of the functions in this module is usable or give any effect.</p>
@@ -47,7 +47,7 @@
</description>
<funcs>
<func>
- <name>available() -> boolean()</name>
+ <name since="OTP R15B01">available() -> boolean()</name>
<fsummary>Check if dynamic tracing is available</fsummary>
<desc>
<p>This function uses the NIF library to determine if dynamic
@@ -59,42 +59,42 @@
</desc>
</func>
<func>
- <name>p() -> true | false | error | badarg</name>
+ <name since="OTP R15B01">p() -> true | false | error | badarg</name>
<fsummary>Trigger the user trace probe.</fsummary>
<desc>
<p>Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message only containing the user tag and zeroes/empty strings in all other fields.</p>
</desc>
</func>
<func>
- <name>p(integer() | string()) -> true | false | error | badarg</name>
+ <name since="OTP R15B01">p(integer() | string()) -> true | false | error | badarg</name>
<fsummary>Trigger the user trace probe.</fsummary>
<desc>
<p>Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing the user tag and the integer or string parameter in the first integer/string field.</p>
</desc>
</func>
<func>
- <name>p(integer() | string(), integer() | string()) -> true | false | error | badarg</name>
+ <name since="OTP R15B01">p(integer() | string(), integer() | string()) -> true | false | error | badarg</name>
<fsummary>Trigger the user trace probe.</fsummary>
<desc>
<p>Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing the user tag and the integer() or string() parameters as the first fields of respective type. integer() parameters should be put before any string() parameters. I.e. <c>p(1,"Hello")</c> is ok, as is <c>p(1,1)</c> and <c>p("Hello","Again")</c>, but not <c>p("Hello",1)</c>.</p>
</desc>
</func>
<func>
- <name>p(integer() | string(), integer() | string(), integer() | string()) -> true | false | error | badarg</name>
+ <name since="OTP R15B01">p(integer() | string(), integer() | string(), integer() | string()) -> true | false | error | badarg</name>
<fsummary>Trigger the user trace probe.</fsummary>
<desc>
<p>Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing the user tag and the integer() or string() parameters as the first fields of respective type. integer() parameters should be put before any string() parameters, as in <seealso marker="#p/2">p/2</seealso>.</p>
</desc>
</func>
<func>
- <name>p(integer() | string(), integer() | string(), integer() | string(), integer() | string()) -> true | false | error | badarg</name>
+ <name since="OTP R15B01">p(integer() | string(), integer() | string(), integer() | string(), integer() | string()) -> true | false | error | badarg</name>
<fsummary>Trigger the user trace probe.</fsummary>
<desc>
<p>Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing the user tag and the integer() or string() parameters as the first fields of respective type. integer() parameters should be put before any string() parameters, as in <seealso marker="#p/2">p/2</seealso>.</p>
</desc>
</func>
<func>
- <name>p(integer(), integer() | string(), integer() | string(), integer() | string(), string()) -> true | false | error | badarg</name>
+ <name since="OTP R15B01">p(integer(), integer() | string(), integer() | string(), integer() | string(), string()) -> true | false | error | badarg</name>
<fsummary>Trigger the user trace probe.</fsummary>
<desc>
<p>Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing the user tag and the integer() or string() parameters as the first fields of respective type. integer() parameters should be put before any string() parameters, as in <seealso marker="#p/2">p/2</seealso>.</p>
@@ -102,7 +102,7 @@
</desc>
</func>
<func>
- <name>p(integer(), integer(), integer() | string(), integer() | string(), string(), string()) -> true | false | error | badarg</name>
+ <name since="OTP R15B01">p(integer(), integer(), integer() | string(), integer() | string(), string(), string()) -> true | false | error | badarg</name>
<fsummary>Trigger the user trace probe.</fsummary>
<desc>
<p>Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing the user tag and the integer() or string() parameters as the first fields of respective type. integer() parameters should be put before any string() parameters, as in <seealso marker="#p/2">p/2</seealso>.</p>
@@ -110,7 +110,7 @@
</desc>
</func>
<func>
- <name>p(integer(), integer(), integer(), integer() | string(), string(), string(), string()) -> true | false | error | badarg</name>
+ <name since="OTP R15B01">p(integer(), integer(), integer(), integer() | string(), string(), string(), string()) -> true | false | error | badarg</name>
<fsummary>Trigger the user trace probe.</fsummary>
<desc>
<p>Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing the user tag and the integer() or string() parameters as the first fields of respective type. integer() parameters should be put before any string() parameters, as in <seealso marker="#p/2">p/2</seealso>.</p>
@@ -118,14 +118,14 @@
</desc>
</func>
<func>
- <name>p(integer(), integer(), integer(), integer(), string(), string(), string(), string()) -> true | false | error | badarg</name>
+ <name since="OTP R15B01">p(integer(), integer(), integer(), integer(), string(), string(), string(), string()) -> true | false | error | badarg</name>
<fsummary>Trigger the user trace probe.</fsummary>
<desc>
<p>Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing all the integer()'s and string()'s provided, as well as any user tag set in the current process.</p>
</desc>
</func>
<func>
- <name>get_tag() -> binary() | undefined</name>
+ <name since="OTP R15B01">get_tag() -> binary() | undefined</name>
<fsummary>Get the user tag set in the process.</fsummary>
<desc>
<p>This function returns the user tag set in the current
@@ -134,7 +134,7 @@
</desc>
</func>
<func>
- <name>get_tag() -> binary() | undefined</name>
+ <name since="OTP R15B01">get_tag() -> binary() | undefined</name>
<fsummary>Get the user tag set in the process or sent to the process.</fsummary>
<desc>
<p>This function returns the user tag set in the current
@@ -151,7 +151,7 @@
</func>
<func>
- <name>put_tag(Item) -> binary() | undefined </name>
+ <name since="OTP R15B01">put_tag(Item) -> binary() | undefined </name>
<fsummary>Set the user tag of the current process.</fsummary>
<type>
<v>Item = iodata()</v>
@@ -163,7 +163,7 @@
</desc>
</func>
<func>
- <name>spread_tag(boolean()) -> TagData</name>
+ <name since="OTP R15B01">spread_tag(boolean()) -> TagData</name>
<fsummary>Start or stop spreading dynamic trace user tags with the next message.</fsummary>
<type>
<v>TagData = opaque data that can be used as parameter to <seealso marker="#restore_tag/1">restore_tag/1</seealso></v>
@@ -185,7 +185,7 @@ f() ->
</desc>
</func>
<func>
- <name>restore_tag(TagData) -> true</name>
+ <name since="OTP R15B01">restore_tag(TagData) -> true</name>
<fsummary>Restore to a previous state of user tag spreading.</fsummary>
<type>
<v>TagData = opaque data returned by <seealso marker="#spread_tag/1">spread_tag/1</seealso></v>
diff --git a/lib/runtime_tools/doc/src/erts_alloc_config.xml b/lib/runtime_tools/doc/src/erts_alloc_config.xml
index ffc4ec5285..5bcce1b5e3 100644
--- a/lib/runtime_tools/doc/src/erts_alloc_config.xml
+++ b/lib/runtime_tools/doc/src/erts_alloc_config.xml
@@ -29,7 +29,7 @@
<rev>1</rev>
<file>erts_alloc_config.sgml</file>
</header>
- <module>erts_alloc_config</module>
+ <module since="">erts_alloc_config</module>
<modulesummary>Configuration tool for erts_alloc</modulesummary>
<description>
<note>
@@ -136,7 +136,7 @@
</description>
<funcs>
<func>
- <name>save_scenario() -> ok | {error, Error}</name>
+ <name since="">save_scenario() -> ok | {error, Error}</name>
<fsummary>Saves information about current runtime scenario</fsummary>
<type>
<v>Error = term()</v>
@@ -154,7 +154,7 @@
</desc>
</func>
<func>
- <name>make_config() -> ok | {error, Error}</name>
+ <name since="">make_config() -> ok | {error, Error}</name>
<fsummary>Creates an erts_alloc configuration</fsummary>
<type>
<v>Error = term()</v>
@@ -165,7 +165,7 @@
</desc>
</func>
<func>
- <name>make_config(FileNameOrIODev) -> ok | {error, Error}</name>
+ <name since="">make_config(FileNameOrIODev) -> ok | {error, Error}</name>
<fsummary>Creates an erts_alloc configuration</fsummary>
<type>
<v>FileNameOrIODev = string() | io_device()</v>
@@ -190,7 +190,7 @@
</desc>
</func>
<func>
- <name>stop() -> ok | {error, Error}</name>
+ <name since="">stop() -> ok | {error, Error}</name>
<fsummary></fsummary>
<type>
<v>Error = term()</v>
diff --git a/lib/runtime_tools/doc/src/msacc.xml b/lib/runtime_tools/doc/src/msacc.xml
index 129da3d230..ae089de8d0 100644
--- a/lib/runtime_tools/doc/src/msacc.xml
+++ b/lib/runtime_tools/doc/src/msacc.xml
@@ -31,7 +31,7 @@
<rev>A</rev>
<file>msacc.xml</file>
</header>
- <module>msacc</module>
+ <module since="OTP 19.0">msacc</module>
<modulesummary>Convenience functions for microstate accounting</modulesummary>
<description>
<p>This module implements some convenience functions for analyzing
@@ -146,7 +146,7 @@ ok
</datatypes>
<funcs>
<func>
- <name name="available" arity="0"/>
+ <name name="available" arity="0" since="OTP 19.0"/>
<fsummary>Check if microstate accounting is available</fsummary>
<desc>
<p>This function checks whether microstate accounting
@@ -154,7 +154,7 @@ ok
</desc>
</func>
<func>
- <name name="start" arity="0"/>
+ <name name="start" arity="0" since="OTP 19.0"/>
<fsummary>Start microstate accounting.</fsummary>
<desc>
<p>Start microstate accounting. Returns whether it was
@@ -162,7 +162,7 @@ ok
</desc>
</func>
<func>
- <name name="start" arity="1"/>
+ <name name="start" arity="1" since="OTP 19.0"/>
<fsummary>Start microstate accounting for a time.</fsummary>
<desc>
<p>Resets all counters and then starts microstate accounting
@@ -170,7 +170,7 @@ ok
</desc>
</func>
<func>
- <name name="stop" arity="0"/>
+ <name name="stop" arity="0" since="OTP 19.0"/>
<fsummary>Stop microstate accounting.</fsummary>
<desc>
<p>Stop microstate accounting.
@@ -178,7 +178,7 @@ ok
</desc>
</func>
<func>
- <name name="reset" arity="0"/>
+ <name name="reset" arity="0" since="OTP 19.0"/>
<fsummary>Reset microstate accounting counters</fsummary>
<desc>
<p>Reset microstate accounting counters.
@@ -186,7 +186,7 @@ ok
</desc>
</func>
<func>
- <name name="print" arity="0"/>
+ <name name="print" arity="0" since="OTP 19.0"/>
<fsummary>Print microstate statistics</fsummary>
<desc>
<p>
@@ -199,7 +199,7 @@ ok
</desc>
</func>
<func>
- <name name="print" arity="1"/>
+ <name name="print" arity="1" since="OTP 19.0"/>
<fsummary>Print microstate statistics</fsummary>
<desc>
<p>Print the given microstate statistics values to stdout.
@@ -211,7 +211,7 @@ ok
</desc>
</func>
<func>
- <name name="print" arity="2"/>
+ <name name="print" arity="2" since="OTP 19.0"/>
<fsummary>Print microstate statistics</fsummary>
<desc>
<p>Print the given microstate statistics values to standard out.
@@ -234,7 +234,7 @@ ok
</desc>
</func>
<func>
- <name name="print" arity="3"/>
+ <name name="print" arity="3" since="OTP 19.0"/>
<fsummary>Print microstate statistics</fsummary>
<desc>
<p>Print the given microstate statistics values to the given file
@@ -243,7 +243,7 @@ ok
</desc>
</func>
<func>
- <name name="stats" arity="0"/>
+ <name name="stats" arity="0" since="OTP 19.0"/>
<fsummary></fsummary>
<desc>
<p>Returns a runtime system independent version of the microstate
@@ -254,7 +254,7 @@ ok
</desc>
</func>
<func>
- <name name="stats" arity="2" clause_i="1"/>
+ <name name="stats" arity="2" clause_i="1" since="OTP 19.0"/>
<fsummary></fsummary>
<desc>
<p>Returns the system time for the given microstate statistics values.
@@ -269,7 +269,7 @@ ok
</desc>
</func>
<func>
- <name name="stats" arity="2" clause_i="2"/>
+ <name name="stats" arity="2" clause_i="2" since="OTP 19.0"/>
<fsummary></fsummary>
<desc>
<p>Returns fractions of real-time or run-time spent in the various
@@ -277,7 +277,7 @@ ok
</desc>
</func>
<func>
- <name name="stats" arity="2" clause_i="3"/>
+ <name name="stats" arity="2" clause_i="3" since="OTP 19.0"/>
<fsummary></fsummary>
<desc>
<p>Returns a list of microstate statistics values where the values
@@ -285,7 +285,7 @@ ok
</desc>
</func>
<func>
- <name name="to_file" arity="1"/>
+ <name name="to_file" arity="1" since="OTP 19.0"/>
<fsummary></fsummary>
<desc>
<p>Dumps the current microstate statistics counters to a file that can
@@ -294,7 +294,7 @@ ok
</desc>
</func>
<func>
- <name name="from_file" arity="1"/>
+ <name name="from_file" arity="1" since="OTP 19.0"/>
<fsummary></fsummary>
<desc>
<p>Read a file dump produced by <seealso marker="#to_file/1">
diff --git a/lib/runtime_tools/doc/src/notes.xml b/lib/runtime_tools/doc/src/notes.xml
index 355e3dd40d..1b94c3e6d9 100644
--- a/lib/runtime_tools/doc/src/notes.xml
+++ b/lib/runtime_tools/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,6 +32,70 @@
<p>This document describes the changes made to the Runtime_Tools
application.</p>
+<section><title>Runtime_Tools 1.13.3</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Minor updates to build system necessary due to move of
+ configuration of <c>crypto</c> application.</p>
+ <p>
+ Own Id: OTP-15262 Aux Id: OTP-15129 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Runtime_Tools 1.13.2</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Update of systemtap trace example scripts.</p>
+ <p>
+ Own Id: OTP-15670</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Runtime_Tools 1.13.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Optimize <c>observer</c> by using new
+ <c>system_info(ets_count)</c> instead of more expensive
+ <c>length(ets:all())</c>.</p>
+ <p>
+ Own Id: OTP-15163 Aux Id: PR-1844 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Runtime_Tools 1.13</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ New utility module <c>scheduler</c> which makes it easier
+ to measure scheduler utilization.</p>
+ <p>
+ Own Id: OTP-14904</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Runtime_Tools 1.12.5</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/runtime_tools/doc/src/ref_man.xml b/lib/runtime_tools/doc/src/ref_man.xml
index d2fb7a29af..fdca65422d 100644
--- a/lib/runtime_tools/doc/src/ref_man.xml
+++ b/lib/runtime_tools/doc/src/ref_man.xml
@@ -4,7 +4,7 @@
<application xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>1999</year><year>2016</year>
+ <year>1999</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -37,6 +37,7 @@
<xi:include href="dyntrace.xml"/>
<xi:include href="erts_alloc_config.xml"/>
<xi:include href="msacc.xml"/>
+ <xi:include href="scheduler.xml"/>
<xi:include href="system_information.xml"/>
</application>
diff --git a/lib/runtime_tools/doc/src/scheduler.xml b/lib/runtime_tools/doc/src/scheduler.xml
new file mode 100644
index 0000000000..b033430183
--- /dev/null
+++ b/lib/runtime_tools/doc/src/scheduler.xml
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title></title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno>1</docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>scheduler.xml</file>
+ </header>
+ <module since="OTP 21.0">scheduler</module>
+ <modulesummary>Measure scheduler utilization</modulesummary>
+ <description>
+ <p>This module contains utility functions for easier measurement and
+ calculation of scheduler utilization, otherwise obtained from calling the
+ more primitive <seealso marker="erts:erlang#statistics_scheduler_wall_time">
+ <c>statistics(scheduler_wall_time)</c></seealso>.</p>
+ <p>The simplest usage is to call <seealso marker="#utilization-1">
+ <c>scheduler:utilization(Seconds)</c></seealso>.</p>
+ </description>
+
+ <datatypes>
+ <datatype>
+ <name name="sched_sample"/>
+ </datatype>
+ <datatype>
+ <name name="sched_type"/>
+ </datatype>
+ <datatype>
+ <name name="sched_id"/>
+ </datatype>
+ <datatype>
+ <name name="sched_util_result"/>
+ <desc>
+ <p>A list of tuples containing results for individual schedulers
+ as well as aggregated averages. <c>Util</c> is the scheduler utilization
+ as a floating point value between 0.0 and 1.0. <c>Percent</c> is the
+ same utilization as a more human readable string expressed in percent.</p>
+ <taglist>
+ <tag><c>{normal, SchedulerId, Util, Percent}</c></tag>
+ <item>Scheduler utilization of a normal scheduler with number
+ <c>SchedulerId</c>.</item>
+ <tag><c>{cpu, SchedulerId, Util, Percent}</c></tag>
+ <item>Scheduler utilization of a dirty-cpu scheduler with number
+ <c>SchedulerId</c>.</item>
+ <tag><c>{io, SchedulerId, Util, Percent}</c></tag>
+ <item>Scheduler utilization of a dirty-io scheduler with number
+ <c>SchedulerId</c>. This tuple will only exist if both samples were
+ taken with <seealso marker="#sample_all-0"><c>sample_all/0</c></seealso>.</item>
+ <tag><c>{total, Util, Percent}</c></tag>
+ <item>Total utilization of all normal and dirty-cpu schedulers.</item>
+ <tag><c>{weighted, Util, Percent}</c></tag>
+ <item>Total utilization of all normal and dirty-cpu schedulers,
+ weighted against maximum amount of available CPU time.</item>
+ </taglist>
+ </desc>
+ </datatype>
+ </datatypes>
+
+ <funcs>
+
+ <func>
+ <name name="sample" arity="0" since="OTP 21.0"/>
+ <fsummary>Get scheduler utilization sample.</fsummary>
+ <desc>
+ <p>Return a scheduler utilization sample for normal and dirty-cpu
+ schedulers.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="sample_all" arity="0" since="OTP 21.0"/>
+ <fsummary>Get scheduler utilization sample.</fsummary>
+ <desc>
+ <p>Return a scheduler utilization sample for all schedulers,
+ including dirty-io schedulers.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="utilization" arity="1" clause_i="1" since="OTP 21.0"/>
+ <fsummary>Measure scheduler utilizations during a period of time.</fsummary>
+ <desc>
+ <p>Measure utilization for normal and dirty-cpu schedulers during
+ <c><anno>Seconds</anno></c> seconds, and then return the result.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="utilization" arity="1" clause_i="2" since="OTP 21.0"/>
+ <fsummary>Measure scheduler utilizations since sample.</fsummary>
+ <desc>
+ <p>Calculate scheduler utilizations for the time interval from when
+ <c><anno>Sample</anno></c> was taken and "now". The same as calling
+ <c>scheduler:utilization(Sample, scheduler:sample_all())</c>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="utilization" arity="2" since="OTP 21.0"/>
+ <fsummary>Measure scheduler utilizations between two samples.</fsummary>
+ <desc>
+ <p>Calculates scheduler utilizations for the time interval between
+ the two samples obtained from calling
+ <seealso marker="#sample-0"><c>sample/0</c></seealso> or
+ <seealso marker="#sample_all-0"><c>sample_all/0</c></seealso>.</p>
+ </desc>
+ </func>
+
+ </funcs>
+ </erlref>
diff --git a/lib/runtime_tools/doc/src/specs.xml b/lib/runtime_tools/doc/src/specs.xml
index 978bd39e55..33fe7fa370 100644
--- a/lib/runtime_tools/doc/src/specs.xml
+++ b/lib/runtime_tools/doc/src/specs.xml
@@ -2,4 +2,5 @@
<specs xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="../specs/specs_system_information.xml"/>
<xi:include href="../specs/specs_msacc.xml"/>
+ <xi:include href="../specs/specs_scheduler.xml"/>
</specs>
diff --git a/lib/runtime_tools/doc/src/system_information.xml b/lib/runtime_tools/doc/src/system_information.xml
index 53dc595e64..a356b5c6f8 100644
--- a/lib/runtime_tools/doc/src/system_information.xml
+++ b/lib/runtime_tools/doc/src/system_information.xml
@@ -32,14 +32,14 @@
<rev></rev>
<file>system_information.xml</file>
</header>
- <module>system_information</module>
+ <module since="OTP 17.0">system_information</module>
<modulesummary>System Information</modulesummary>
<description>
<p></p>
</description>
<funcs>
<func>
- <name name="sanity_check" arity="0"/>
+ <name name="sanity_check" arity="0" since="OTP 17.0"/>
<fsummary>Perform a sanity check</fsummary>
<desc>
<p>Performs a sanity check on the system. If no issues
@@ -88,7 +88,7 @@
</desc>
</func>
<func>
- <name name="to_file" arity="1"/>
+ <name name="to_file" arity="1" since="OTP 17.0"/>
<fsummary>Write miscellaneous system information to file</fsummary>
<desc><p>Writes miscellaneous system information to file. This
information will typically be requested by the Erlang/OTP team
diff --git a/lib/runtime_tools/examples/dist.systemtap b/lib/runtime_tools/examples/dist.systemtap
index bb20d617e1..4102a5243c 100644
--- a/lib/runtime_tools/examples/dist.systemtap
+++ b/lib/runtime_tools/examples/dist.systemtap
@@ -19,18 +19,18 @@
* %CopyrightEnd%
*/
/*
- * Note: This file assumes that you're using the non-SMP-enabled Erlang
- * virtual machine, "beam". The SMP-enabled VM is called "beam.smp".
+ * Note: This file assumes that you're using the SMP-enabled Erlang
+ * virtual machine, "beam.smp".
* Note that other variations of the virtual machine also have
* different names, e.g. the debug build of the SMP-enabled VM
* is "beam.debug.smp".
*
* To use a different virtual machine, replace each instance of
- * "beam" with "beam.smp" or the VM name appropriate to your
- * environment.
+ * "beam.smp" with "beam.debug.smp" or the VM name appropriate
+ * to your environment.
*/
-probe process("beam").mark("dist-monitor")
+probe process("beam.smp").mark("dist-monitor")
{
printf("monitor: pid %d, who %s, what %s, node %s, type %s, reason %s\n",
pid(),
@@ -38,38 +38,38 @@ probe process("beam").mark("dist-monitor")
user_string($arg5));
}
-probe process("beam").mark("dist-port_busy")
+probe process("beam.smp").mark("dist-port_busy")
{
printf("dist port_busy: node %s, port %s, remote_node %s, blocked pid %s\n",
user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4));
- blocked_procs[user_string($arg4)] = timestamp;
+ blocked_procs[user_string($arg4)] = local_clock_ns();
}
-probe process("beam").mark("dist-port_busy")
+probe process("beam.smp").mark("dist-port_busy")
{
printf("dist port_busy: node %s, port %s, remote_node %s, blocked pid %s\n",
user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4));
- blocked_procs[user_string($arg4)] = timestamp;
+ blocked_procs[user_string($arg4)] = local_clock_ns();
}
-probe process("beam").mark("dist-output")
+probe process("beam.smp").mark("dist-output")
{
printf("dist output: node %s, port %s, remote_node %s bytes %d\n",
user_string($arg1), user_string($arg2), user_string($arg3), $arg4);
}
-probe process("beam").mark("dist-outputv")
+probe process("beam.smp").mark("dist-outputv")
{
printf("port outputv: node %s, port %s, remote_node %s bytes %d\n",
user_string($arg1), user_string($arg2), user_string($arg3), $arg4);
}
-probe process("beam").mark("process-scheduled")
+probe process("beam.smp").mark("process-scheduled")
{
pidstr = user_string($arg1);
if (pidstr in blocked_procs) {
printf("blocked pid %s scheduled now, waited %d microseconds\n",
- pidstr, (timestamp - blocked_procs[pidstr]) / 1000);
+ pidstr, (local_clock_ns() - blocked_procs[pidstr]) / 1000);
delete blocked_procs[pidstr];
}
}
diff --git a/lib/runtime_tools/examples/driver1.systemtap b/lib/runtime_tools/examples/driver1.systemtap
index e1ee8ecffc..f5bc28b42d 100644
--- a/lib/runtime_tools/examples/driver1.systemtap
+++ b/lib/runtime_tools/examples/driver1.systemtap
@@ -19,108 +19,102 @@
* %CopyrightEnd%
*/
/*
- * Note: This file assumes that you're using the non-SMP-enabled Erlang
- * virtual machine, "beam". The SMP-enabled VM is called "beam.smp".
+ * Note: This file assumes that you're using the SMP-enabled Erlang
+ * virtual machine, "beam.smp".
* Note that other variations of the virtual machine also have
* different names, e.g. the debug build of the SMP-enabled VM
* is "beam.debug.smp".
*
* To use a different virtual machine, replace each instance of
- * "beam" with "beam.smp" or the VM name appropriate to your
- * environment.
+ * "beam.smp" with "beam.debug.smp" or the VM name appropriate
+ * to your environment.
*/
-probe process("beam").mark("driver-init")
+probe process("beam.smp").mark("driver__init")
{
printf("driver init name %s major %d minor %d flags %d\n",
user_string($arg1), $arg2, $arg3, $arg4);
}
-probe process("beam").mark("driver-start")
+probe process("beam.smp").mark("driver__start")
{
printf("driver start pid %s driver name %s port %s\n",
user_string($arg1), user_string($arg2), user_string($arg3));
}
-probe process("beam").mark("driver-stop")
+probe process("beam.smp").mark("driver__stop")
{
printf("driver stop pid %s driver name %s port %s\n",
user_string($arg1), user_string($arg2), user_string($arg3));
}
-probe process("beam").mark("driver-finish")
+probe process("beam.smp").mark("driver__finish")
{
printf("driver finish driver name %s\n",
user_string($arg1));
}
-probe process("beam").mark("driver-flush")
+probe process("beam.smp").mark("driver__flush")
{
printf("driver flush pid %s port %s port name %s\n",
user_string($arg1), user_string($arg2), user_string($arg3));
}
-probe process("beam").mark("driver-output")
+probe process("beam.smp").mark("driver__output")
{
printf("driver output pid %s port %s port name %s bytes %d\n",
user_string($arg1), user_string($arg2), user_string($arg3), $arg4);
}
-probe process("beam").mark("driver-outputv")
+probe process("beam.smp").mark("driver__outputv")
{
printf("driver outputv pid %s port %s port name %s bytes %d\n",
user_string($arg1), user_string($arg2), user_string($arg3), $arg4);
}
-probe process("beam").mark("driver-control")
+probe process("beam.smp").mark("driver__control")
{
printf("driver control pid %s port %s port name %s command %d bytes %d\n",
user_string($arg1), user_string($arg2), user_string($arg3), $arg4, $arg5);
}
-probe process("beam").mark("driver-call")
+probe process("beam.smp").mark("driver__call")
{
printf("driver call pid %s port %s port name %s command %d bytes %d\n",
user_string($arg1), user_string($arg2), user_string($arg3), $arg4, $arg5);
}
-probe process("beam").mark("driver-event")
-{
- printf("driver event pid %s port %s port name %s\n",
- user_string($arg1), user_string($arg2), user_string($arg3));
-}
-
-probe process("beam").mark("driver-ready_input")
+probe process("beam.smp").mark("driver__ready_input")
{
printf("driver ready_input pid %s port %s port name %s\n",
user_string($arg1), user_string($arg2), user_string($arg3));
}
-probe process("beam").mark("driver-ready_output")
+probe process("beam.smp").mark("driver__ready_output")
{
printf("driver ready_output pid %s port %s port name %s\n",
user_string($arg1), user_string($arg2), user_string($arg3));
}
-probe process("beam").mark("driver-timeout")
+probe process("beam.smp").mark("driver__timeout")
{
printf("driver timeout pid %s port %s port name %s\n",
user_string($arg1), user_string($arg2), user_string($arg3));
}
-probe process("beam").mark("driver-ready_async")
+probe process("beam.smp").mark("driver__ready_async")
{
printf("driver ready_async pid %s port %s port name %s\n",
user_string($arg1), user_string($arg2), user_string($arg3));
}
-probe process("beam").mark("driver-process_exit")
+probe process("beam.smp").mark("driver__process_exit")
{
printf("driver process_exit pid %s port %s port name %s\n",
user_string($arg1), user_string($arg2), user_string($arg3));
}
-probe process("beam").mark("driver-stop_select")
+probe process("beam.smp").mark("driver__stop_select")
{
printf("driver stop_select driver name %s\n", user_string($arg1));
}
diff --git a/lib/runtime_tools/examples/efile_drv.d b/lib/runtime_tools/examples/efile_drv.d
deleted file mode 100644
index a470518dd9..0000000000
--- a/lib/runtime_tools/examples/efile_drv.d
+++ /dev/null
@@ -1,105 +0,0 @@
-/* example usage: dtrace -q -s /path/to/efile_drv.d */
-/*
- * %CopyrightBegin%
- *
- * Copyright Scott Lystig Fritchie 2011-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- */
-
-BEGIN
-{
- op_map[1] = "OPEN";
- op_map[2] = "READ";
- op_map[3] = "LSEEK";
- op_map[4] = "WRITE";
- op_map[5] = "FSTAT";
- op_map[6] = "PWD";
- op_map[7] = "READDIR";
- op_map[8] = "CHDIR";
- op_map[9] = "FSYNC";
- op_map[10] = "MKDIR";
- op_map[11] = "DELETE";
- op_map[12] = "RENAME";
- op_map[13] = "RMDIR";
- op_map[14] = "TRUNCATE";
- op_map[15] = "READ_FILE";
- op_map[16] = "WRITE_INFO";
- op_map[19] = "LSTAT";
- op_map[20] = "READLINK";
- op_map[21] = "LINK";
- op_map[22] = "SYMLINK";
- op_map[23] = "CLOSE";
- op_map[24] = "PWRITEV";
- op_map[25] = "PREADV";
- op_map[26] = "SETOPT";
- op_map[27] = "IPREAD";
- op_map[28] = "ALTNAME";
- op_map[29] = "READ_LINE";
- op_map[30] = "FDATASYNC";
- op_map[31] = "FADVISE";
-}
-
-erlang*:::aio_pool-add
-{
- printf("async I/O pool port %s queue len %d\n", copyinstr(arg0), arg1);
-}
-
-erlang*:::aio_pool-get
-{
- printf("async I/O pool port %s queue len %d\n", copyinstr(arg0), arg1);
-}
-
-erlang*:::efile_drv-entry
-{
- printf("efile_drv enter tag={%d,%d} %s%s | %s (%d) | args: %s %s , %d %d (port %s)\n",
- arg0, arg1,
- arg2 == NULL ? "" : "user tag ",
- arg2 == NULL ? "" : copyinstr(arg2),
- op_map[arg3], arg3,
- arg4 == NULL ? "" : copyinstr(arg4),
- arg5 == NULL ? "" : copyinstr(arg5), arg6, arg7,
- /* NOTE: port name in args[10] is experimental */
- (args[10] == NULL) ?
- "?" : copyinstr((user_addr_t) args[10]));
-}
-
-erlang*:::efile_drv-int*
-{
- printf("async I/O worker tag={%d,%d} | %s (%d) | %s\n",
- arg0, arg1, op_map[arg2], arg2, probename);
-}
-
-/* efile_drv-return error case */
-erlang*:::efile_drv-return
-/arg4 == 0/
-{
- printf("efile_drv return tag={%d,%d} %s%s | %s (%d) | errno %d\n",
- arg0, arg1,
- arg2 == NULL ? "" : "user tag ",
- arg2 == NULL ? "" : copyinstr(arg2),
- op_map[arg3], arg3,
- arg5);
-}
-
-/* efile_drv-return success case */
-erlang*:::efile_drv-return
-/arg4 != 0/
-{
- printf("efile_drv return tag={%d,%d} %s | %s (%d) ok\n",
- arg0, arg1,
- arg2 == NULL ? "" : copyinstr(arg2),
- op_map[arg3], arg3);
-}
diff --git a/lib/runtime_tools/examples/efile_drv.systemtap b/lib/runtime_tools/examples/efile_drv.systemtap
deleted file mode 100644
index 29c3637e10..0000000000
--- a/lib/runtime_tools/examples/efile_drv.systemtap
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- */
-/*
- * Note: This file assumes that you're using the non-SMP-enabled Erlang
- * virtual machine, "beam". The SMP-enabled VM is called "beam.smp".
- * Note that other variations of the virtual machine also have
- * different names, e.g. the debug build of the SMP-enabled VM
- * is "beam.debug.smp".
- *
- * To use a different virtual machine, replace each instance of
- * "beam" with "beam.smp" or the VM name appropriate to your
- * environment.
- */
-
-probe begin
-{
- op_map[1] = "OPEN";
- op_map[2] = "READ";
- op_map[3] = "LSEEK";
- op_map[4] = "WRITE";
- op_map[5] = "FSTAT";
- op_map[6] = "PWD";
- op_map[7] = "READDIR";
- op_map[8] = "CHDIR";
- op_map[9] = "FSYNC";
- op_map[10] = "MKDIR";
- op_map[11] = "DELETE";
- op_map[12] = "RENAME";
- op_map[13] = "RMDIR";
- op_map[14] = "TRUNCATE";
- op_map[15] = "READ_FILE";
- op_map[16] = "WRITE_INFO";
- op_map[19] = "LSTAT";
- op_map[20] = "READLINK";
- op_map[21] = "LINK";
- op_map[22] = "SYMLINK";
- op_map[23] = "CLOSE";
- op_map[24] = "PWRITEV";
- op_map[25] = "PREADV";
- op_map[26] = "SETOPT";
- op_map[27] = "IPREAD";
- op_map[28] = "ALTNAME";
- op_map[29] = "READ_LINE";
- op_map[30] = "FDATASYNC";
- op_map[31] = "FADVISE";
-}
-
-probe process("beam").mark("aio_pool-add")
-{
- printf("async I/O pool port %s queue len %d\n", user_string($arg1), $arg2);
-}
-
-probe process("beam").mark("aio_pool-get")
-{
- printf("async I/O pool port %s queue len %d\n", user_string($arg1), $arg2);
-}
-
-probe process("beam").mark("efile_drv-entry")
-{
- printf("efile_drv enter tag={%d,%d} %s%s | %s (%d) | args: %s %s , %d %d (port %s)\n",
- $arg1, $arg2,
- $arg3 == NULL ? "" : "user tag ",
- $arg3 == NULL ? "" : user_string($arg3),
- op_map[$arg4], $arg4,
- $arg5 == NULL ? "" : user_string($arg5),
- $arg6 == NULL ? "" : user_string($arg6), $arg7, $arg8,
- /* NOTE: port name in $arg[11] is experimental */
- user_string($arg11))
-}
-
-probe process("beam").mark("efile_drv-int*")
-{
- printf("async I/O worker tag={%d,%d} | %s (%d) | %s\n",
- $arg1, $arg2, op_map[$arg3], $arg3, probefunc());
-}
-
-probe process("beam").mark("efile_drv-return")
-{
- if ($arg5 == 0) {
- /* efile_drv-return error case */
- printf("efile_drv return tag={%d,%d} %s%s | %s (%d) | errno %d\n",
- $arg1, $arg2,
- $arg3 == NULL ? "" : "user tag ",
- $arg3 == NULL ? "" : user_string($arg3),
- op_map[$arg4], $arg4,
- $arg6);
- } else {
- /* efile_drv-return success case */
- printf("efile_drv return tag={%d,%d} %s | %s (%d) ok\n",
- $arg1, $arg2,
- $arg3 == NULL ? "" : user_string($arg3),
- op_map[$arg4], $arg4);
- }
-}
-
-global op_map;
diff --git a/lib/runtime_tools/examples/function-calls.systemtap b/lib/runtime_tools/examples/function-calls.systemtap
index 9c44b2d014..6bb173b3ec 100644
--- a/lib/runtime_tools/examples/function-calls.systemtap
+++ b/lib/runtime_tools/examples/function-calls.systemtap
@@ -18,51 +18,51 @@
* %CopyrightEnd%
*/
/*
- * Note: This file assumes that you're using the non-SMP-enabled Erlang
- * virtual machine, "beam". The SMP-enabled VM is called "beam.smp".
+ * Note: This file assumes that you're using the SMP-enabled Erlang
+ * virtual machine, "beam.smp".
* Note that other variations of the virtual machine also have
* different names, e.g. the debug build of the SMP-enabled VM
* is "beam.debug.smp".
*
* To use a different virtual machine, replace each instance of
- * "beam" with "beam.smp" or the VM name appropriate to your
- * environment.
+ * "beam.smp" with "beam.debug.smp" or the VM name appropriate
+ * to your environment.
*/
-probe process("beam").mark("local-function-entry")
+probe process("beam.smp").mark("local-function-entry")
{
printf("pid %s enter (local) %s depth %d\n",
user_string($arg1), user_string($arg2), $arg3);
}
-probe process("beam").mark("global-function-entry")
+probe process("beam.smp").mark("global-function-entry")
{
printf("pid %s enter (global) %s depth %d\n",
user_string($arg1), user_string($arg2), $arg3);
}
-probe process("beam").mark("function-return")
+probe process("beam.smp").mark("function-return")
{
printf("pid %s return %s depth %d\n",
user_string($arg1), user_string($arg2), $arg3);
}
-probe process("beam").mark("bif-entry")
+probe process("beam.smp").mark("bif-entry")
{
printf("pid %s BIF entry mfa %s\n", user_string($arg1), user_string($arg2));
}
-probe process("beam").mark("bif-return")
+probe process("beam.smp").mark("bif-return")
{
printf("pid %s BIF return mfa %s\n", user_string($arg1), user_string($arg2));
}
-probe process("beam").mark("nif-entry")
+probe process("beam.smp").mark("nif-entry")
{
printf("pid %s NIF entry mfa %s\n", user_string($arg1), user_string($arg2));
}
-probe process("beam").mark("nif-return")
+probe process("beam.smp").mark("nif-return")
{
printf("pid %s NIF return mfa %s\n", user_string($arg1), user_string($arg2));
}
diff --git a/lib/runtime_tools/examples/garbage-collection.systemtap b/lib/runtime_tools/examples/garbage-collection.systemtap
index e414eea821..14f0d6851c 100644
--- a/lib/runtime_tools/examples/garbage-collection.systemtap
+++ b/lib/runtime_tools/examples/garbage-collection.systemtap
@@ -18,33 +18,33 @@
* %CopyrightEnd%
*/
/*
- * Note: This file assumes that you're using the non-SMP-enabled Erlang
- * virtual machine, "beam". The SMP-enabled VM is called "beam.smp".
+ * Note: This file assumes that you're using the SMP-enabled Erlang
+ * virtual machine, "beam.smp".
* Note that other variations of the virtual machine also have
* different names, e.g. the debug build of the SMP-enabled VM
* is "beam.debug.smp".
*
* To use a different virtual machine, replace each instance of
- * "beam" with "beam.smp" or the VM name appropriate to your
- * environment.
+ * "beam.smp" with "beam.debug.smp" or the VM name appropriate
+ * to your environment.
*/
-probe process("beam").mark("gc_major-start")
+probe process("beam.smp").mark("gc_major-start")
{
printf("GC major start pid %s need %d words\n", user_string($arg1), $arg2);
}
-probe process("beam").mark("gc_minor-start")
+probe process("beam.smp").mark("gc_minor-start")
{
printf("GC minor start pid %s need %d words\n", user_string($arg1), $arg2);
}
-probe process("beam").mark("gc_major-end")
+probe process("beam.smp").mark("gc_major-end")
{
printf("GC major end pid %s reclaimed %d words\n", user_string($arg1), $arg2);
}
-probe process("beam").mark("gc_minor-start")
+probe process("beam.smp").mark("gc_minor-start")
{
printf("GC minor end pid %s reclaimed %d words\n", user_string($arg1), $arg2);
}
diff --git a/lib/runtime_tools/examples/memory1.systemtap b/lib/runtime_tools/examples/memory1.systemtap
index 04df4d64c4..2fdc5a796c 100644
--- a/lib/runtime_tools/examples/memory1.systemtap
+++ b/lib/runtime_tools/examples/memory1.systemtap
@@ -18,34 +18,34 @@
* %CopyrightEnd%
*/
/*
- * Note: This file assumes that you're using the non-SMP-enabled Erlang
- * virtual machine, "beam". The SMP-enabled VM is called "beam.smp".
+ * Note: This file assumes that you're using the SMP-enabled Erlang
+ * virtual machine, "beam.smp".
* Note that other variations of the virtual machine also have
* different names, e.g. the debug build of the SMP-enabled VM
* is "beam.debug.smp".
*
* To use a different virtual machine, replace each instance of
- * "beam" with "beam.smp" or the VM name appropriate to your
- * environment.
+ * "beam.smp" with "beam.debug.smp" or the VM name appropriate
+ * to your environment.
*/
-probe process("beam").mark("copy-struct")
+probe process("beam.smp").mark("copy-struct")
{
printf("copy_struct %d bytes\n", $arg1);
}
-probe process("beam").mark("copy-object")
+probe process("beam.smp").mark("copy-object")
{
printf("copy_object pid %s %d bytes\n", user_string($arg1), $arg2);
}
-probe process("beam").mark("process-heap_grow")
+probe process("beam.smp").mark("process-heap_grow")
{
printf("proc heap grow pid %s %d -> %d bytes\n", user_string($arg1),
$arg2, $arg3);
}
-probe process("beam").mark("process-heap_shrink")
+probe process("beam.smp").mark("process-heap_shrink")
{
printf("proc heap shrink pid %s %d -> %d bytes\n", user_string($arg1),
$arg2, $arg3);
diff --git a/lib/runtime_tools/examples/messages.systemtap b/lib/runtime_tools/examples/messages.systemtap
index f2ef56a22b..49b7f46d69 100644
--- a/lib/runtime_tools/examples/messages.systemtap
+++ b/lib/runtime_tools/examples/messages.systemtap
@@ -18,15 +18,15 @@
* %CopyrightEnd%
*/
/*
- * Note: This file assumes that you're using the non-SMP-enabled Erlang
- * virtual machine, "beam". The SMP-enabled VM is called "beam.smp".
+ * Note: This file assumes that you're using the SMP-enabled Erlang
+ * virtual machine, "beam.smp".
* Note that other variations of the virtual machine also have
* different names, e.g. the debug build of the SMP-enabled VM
* is "beam.debug.smp".
*
* To use a different virtual machine, replace each instance of
- * "beam" with "beam.smp" or the VM name appropriate to your
- * environment.
+ * "beam.smp" with "beam.debug.smp" or the VM name appropriate
+ * to your environment.
*/
probe begin
@@ -38,7 +38,7 @@ probe begin
printf("\n");
}
-probe process("beam").mark("message-send")
+probe process("beam.smp").mark("message-send")
{
if ($arg4 == 0 && $arg5 == 0 && $arg6 == 0) {
printf("send: %s -> %s: %d words\n",
@@ -51,7 +51,7 @@ probe process("beam").mark("message-send")
}
}
-probe process("beam").mark("message-send-remote")
+probe process("beam.smp").mark("message-send-remote")
{
if ($arg5 == 0 && $arg6 == 0 && $arg7 == 0) {
printf("send : %s -> %s %s: %d words\n",
@@ -64,7 +64,7 @@ probe process("beam").mark("message-send-remote")
}
}
-probe process("beam").mark("message-queued")
+probe process("beam.smp").mark("message-queued")
{
if ($arg4 == 0 && $arg5 == 0 && $arg6 == 0) {
printf("queued: %s: %d words, queue len %d\n", user_string($arg1), $arg2, $arg3);
@@ -75,7 +75,7 @@ probe process("beam").mark("message-queued")
}
}
-probe process("beam").mark("message-receive")
+probe process("beam.smp").mark("message-receive")
{
if ($arg4 == 0 && $arg5 == 0 && $arg6 == 0) {
printf("receive: %s: %d words, queue len %d\n",
diff --git a/lib/runtime_tools/examples/port1.systemtap b/lib/runtime_tools/examples/port1.systemtap
index f7ce03a65e..235581b0b1 100644
--- a/lib/runtime_tools/examples/port1.systemtap
+++ b/lib/runtime_tools/examples/port1.systemtap
@@ -18,15 +18,15 @@
* %CopyrightEnd%
*/
/*
- * Note: This file assumes that you're using the non-SMP-enabled Erlang
- * virtual machine, "beam". The SMP-enabled VM is called "beam.smp".
+ * Note: This file assumes that you're using the SMP-enabled Erlang
+ * virtual machine, "beam.smp".
* Note that other variations of the virtual machine also have
* different names, e.g. the debug build of the SMP-enabled VM
* is "beam.debug.smp".
*
* To use a different virtual machine, replace each instance of
- * "beam" with "beam.smp" or the VM name appropriate to your
- * environment.
+ * "beam.smp" with "beam.debug.smp" or the VM name appropriate
+ * to your environment.
*/
probe begin
@@ -96,19 +96,19 @@ probe begin
driver_map["udp_inet", 62] = "BINDX";
}
-probe process("beam").mark("port-open")
+probe process("beam.smp").mark("port-open")
{
printf("port open pid %s port name %s port %s\n",
user_string($arg1), user_string($arg2), user_string($arg3));
}
-probe process("beam").mark("port-command")
+probe process("beam.smp").mark("port-command")
{
printf("port command pid %s port %s port name %s command type %s\n",
user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4));
}
-probe process("beam").mark("port-control")
+probe process("beam.smp").mark("port-control")
{
cmd = driver_map[user_string($arg3), $arg4];
cmd_str = (cmd == "") ? "unknown" : cmd;
@@ -118,36 +118,36 @@ probe process("beam").mark("port-control")
/* port-exit is fired as a result of port_close() or exit signal */
-probe process("beam").mark("port-exit")
+probe process("beam.smp").mark("port-exit")
{
printf("port exit pid %s port %s port name %s reason %s\n",
user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4));
}
-probe process("beam").mark("port-connect")
+probe process("beam.smp").mark("port-connect")
{
printf("port connect pid %s port %s port name %s new pid %s\n",
user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4));
}
-probe process("beam").mark("port-busy")
+probe process("beam.smp").mark("port-busy")
{
printf("port busy %s\n", user_string($arg1));
}
-probe process("beam").mark("port-not_busy")
+probe process("beam.smp").mark("port-not_busy")
{
printf("port not busy %s\n", user_string($arg1));
}
-probe process("beam").mark("aio_pool-add")
+probe process("beam.smp").mark("aio_pool-add")
{
printf("async I/O pool add thread %d queue len %d\n", $arg1, $arg2);
}
-probe process("beam").mark("aio_pool-get")
+probe process("beam.smp").mark("aio_pool-get")
{
printf("async I/O pool get thread %d queue len %d\n", $arg1, $arg2);
}
-global driver_map; \ No newline at end of file
+global driver_map;
diff --git a/lib/runtime_tools/examples/process-scheduling.systemtap b/lib/runtime_tools/examples/process-scheduling.systemtap
index b0b74257b3..231c589f64 100644
--- a/lib/runtime_tools/examples/process-scheduling.systemtap
+++ b/lib/runtime_tools/examples/process-scheduling.systemtap
@@ -18,28 +18,28 @@
* %CopyrightEnd%
*/
/*
- * Note: This file assumes that you're using the non-SMP-enabled Erlang
- * virtual machine, "beam". The SMP-enabled VM is called "beam.smp".
+ * Note: This file assumes that you're using the SMP-enabled Erlang
+ * virtual machine, "beam.smp".
* Note that other variations of the virtual machine also have
* different names, e.g. the debug build of the SMP-enabled VM
* is "beam.debug.smp".
*
* To use a different virtual machine, replace each instance of
- * "beam" with "beam.smp" or the VM name appropriate to your
- * environment.
+ * "beam.smp" with "beam.debug.smp" or the VM name appropriate
+ * to your environment.
*/
-probe process("beam").mark("process-scheduled")
+probe process("beam.smp").mark("process-scheduled")
{
printf(" Schedule pid %s mfa %s\n", user_string($arg1), user_string($arg2));
}
-probe process("beam").mark("process-unscheduled")
+probe process("beam.smp").mark("process-unscheduled")
{
printf("Unschedule pid %s\n", user_string($arg1));
}
-probe process("beam").mark("process-hibernate")
+probe process("beam.smp").mark("process-hibernate")
{
printf(" Hibernate pid %s resume mfa %s\n",
user_string($arg1), user_string($arg2));
diff --git a/lib/runtime_tools/examples/spawn-exit.systemtap b/lib/runtime_tools/examples/spawn-exit.systemtap
index 89bca14496..a7b4a0a3ea 100644
--- a/lib/runtime_tools/examples/spawn-exit.systemtap
+++ b/lib/runtime_tools/examples/spawn-exit.systemtap
@@ -18,34 +18,34 @@
* %CopyrightEnd%
*/
/*
- * Note: This file assumes that you're using the non-SMP-enabled Erlang
- * virtual machine, "beam". The SMP-enabled VM is called "beam.smp".
+ * Note: This file assumes that you're using the SMP-enabled Erlang
+ * virtual machine, "beam.smp".
* Note that other variations of the virtual machine also have
* different names, e.g. the debug build of the SMP-enabled VM
* is "beam.debug.smp".
*
* To use a different virtual machine, replace each instance of
- * "beam" with "beam.smp" or the VM name appropriate to your
- * environment.
+ * "beam.smp" with "beam.debug.smp" or the VM name appropriate
+ * to your environment.
*/
-probe process("beam").mark("process-spawn")
+probe process("beam.smp").mark("process-spawn")
{
printf("pid %s mfa %s\n", user_string($arg1), user_string($arg2));
}
-probe process("beam").mark("process-exit")
+probe process("beam.smp").mark("process-exit")
{
printf("pid %s reason %s\n", user_string($arg1), user_string($arg2));
}
-probe process("beam").mark("process-exit_signal")
+probe process("beam.smp").mark("process-exit_signal")
{
printf("sender %s -> pid %s reason %s\n",
user_string($arg1), user_string($arg2), user_string($arg3));
}
-probe process("beam").mark("process-exit_signal-remote")
+probe process("beam.smp").mark("process-exit_signal-remote")
{
printf("sender %s -> node %s pid %s reason %s\n",
user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4));
diff --git a/lib/runtime_tools/examples/user-probe-n.systemtap b/lib/runtime_tools/examples/user-probe-n.systemtap
index 25f7503283..8a0a89c931 100644
--- a/lib/runtime_tools/examples/user-probe-n.systemtap
+++ b/lib/runtime_tools/examples/user-probe-n.systemtap
@@ -18,18 +18,19 @@
* %CopyrightEnd%
*/
/*
- * Note: This file assumes that you're using the non-SMP-enabled Erlang
- * virtual machine, "beam". The SMP-enabled VM is called "beam.smp".
+ * Note: This file assumes that you're using the SMP-enabled Erlang
+ * virtual machine, "beam.smp".
* Note that other variations of the virtual machine also have
* different names, e.g. the debug build of the SMP-enabled VM
* is "beam.debug.smp".
*
* To use a different virtual machine, replace each instance of
- * "beam" with "beam.smp" or the VM name appropriate to your
- * environment.
+ * "beam.smp" with "beam.debug.smp" or the VM name appropriate
+ * to your environment.
*/
-probe process("beam").mark("user_trace-n0")
+
+probe process("beam.smp").mark("user_trace-n0")
{
printf("probe n0: %s %s %d %d %d %d '%s' '%s' '%s' '%s'\n",
user_string($arg1),
@@ -41,7 +42,7 @@ probe process("beam").mark("user_trace-n0")
$arg9 == NULL ? "" : user_string($arg9));
}
-probe process("beam").mark("user_trace-n1")
+probe process("beam.smp").mark("user_trace-n1")
{
printf("probe n1: %s %s %d %d %d %d '%s' '%s' '%s' '%s'\n",
user_string($arg1),
diff --git a/lib/runtime_tools/examples/user-probe.systemtap b/lib/runtime_tools/examples/user-probe.systemtap
index 1777476e54..ce9dde30f8 100644
--- a/lib/runtime_tools/examples/user-probe.systemtap
+++ b/lib/runtime_tools/examples/user-probe.systemtap
@@ -18,23 +18,23 @@
* %CopyrightEnd%
*/
/*
- * Note: This file assumes that you're using the non-SMP-enabled Erlang
- * virtual machine, "beam". The SMP-enabled VM is called "beam.smp".
+ * Note: This file assumes that you're using the SMP-enabled Erlang
+ * virtual machine, "beam.smp".
* Note that other variations of the virtual machine also have
* different names, e.g. the debug build of the SMP-enabled VM
* is "beam.debug.smp".
*
* To use a different virtual machine, replace each instance of
- * "beam" with "beam.smp" or the VM name appropriate to your
- * environment.
+ * "beam.smp" with "beam.debug.smp" or the VM name appropriate
+ * to your environment.
*/
-probe process("beam").mark("user_trace-s1")
+probe process("beam.smp").mark("user_trace-s1")
{
printf("%s\n", user_string($arg1));
}
-probe process("beam").mark("user_trace-i4s4")
+probe process("beam.smp").mark("user_trace-i4s4")
{
printf("%s %s %d %d %d %d '%s' '%s' '%s' '%s'\n",
user_string($arg1),
diff --git a/lib/runtime_tools/src/Makefile b/lib/runtime_tools/src/Makefile
index 5a99c6e240..76286c5499 100644
--- a/lib/runtime_tools/src/Makefile
+++ b/lib/runtime_tools/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2017. All Rights Reserved.
+# Copyright Ericsson AB 1999-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -45,6 +45,7 @@ MODULES= \
system_information \
observer_backend \
ttb_autostart\
+ scheduler\
msacc
HRL_FILES= ../include/observer_backend.hrl
diff --git a/lib/runtime_tools/src/appmon_info.erl b/lib/runtime_tools/src/appmon_info.erl
index b5500085a3..d64206decf 100644
--- a/lib/runtime_tools/src/appmon_info.erl
+++ b/lib/runtime_tools/src/appmon_info.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -690,7 +690,7 @@ find_avoid() ->
[P|Accu];
_ -> Accu end end,
[undefined],
- [application_controller, init, error_logger, gs,
+ [application_controller, init, gs,
node_serv, appmon, appmon_a, appmon_info]).
diff --git a/lib/runtime_tools/src/erts_alloc_config.erl b/lib/runtime_tools/src/erts_alloc_config.erl
index 4b028681a0..845efaf9ef 100644
--- a/lib/runtime_tools/src/erts_alloc_config.erl
+++ b/lib/runtime_tools/src/erts_alloc_config.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -627,7 +627,7 @@ format_header(FTO) ->
[Y, Mo, D, H, Mi, S]),
fcp(FTO,
"~s was used when generating the configuration.",
- [string:strip(erlang:system_info(system_version), both, $\n)]),
+ [string:trim(erlang:system_info(system_version), both, "$\n")]),
case erlang:system_info(schedulers) of
1 -> ok;
Schdlrs ->
@@ -704,28 +704,32 @@ fc(IODev, Frmt, Args) ->
fc(IODev, lists:flatten(io_lib:format(Frmt, Args))).
fc(IODev, String) ->
- fc_aux(IODev, string:tokens(String, " "), 0).
+ fc_aux(IODev, string:lexemes(String, " "), 0).
fc_aux(_IODev, [], 0) ->
ok;
fc_aux(IODev, [], _Len) ->
format(IODev, "~n");
fc_aux(IODev, [T|Ts], 0) ->
- Len = 2 + length(T),
+ Len = 2 + string:length(T),
format(IODev, "# ~s", [T]),
fc_aux(IODev, Ts, Len);
-fc_aux(IODev, [T|_Ts] = ATs, Len) when (length(T) + Len) >= ?PRINT_WITDH ->
- format(IODev, "~n"),
- fc_aux(IODev, ATs, 0);
-fc_aux(IODev, [T|Ts], Len) ->
- NewLen = Len + 1 + length(T),
- format(IODev, " ~s", [T]),
- fc_aux(IODev, Ts, NewLen).
+fc_aux(IODev, [T|Ts] = ATs, Len) ->
+ TLength = string:length(T),
+ case (TLength + Len) >= ?PRINT_WITDH of
+ true ->
+ format(IODev, "~n"),
+ fc_aux(IODev, ATs, 0);
+ false ->
+ NewLen = Len + 1 + TLength,
+ format(IODev, " ~s", [T]),
+ fc_aux(IODev, Ts, NewLen)
+ end.
%% fcl: format comment line
fcl(FTO) ->
EndStr = "# ",
- Precision = length(EndStr),
+ Precision = string:length(EndStr),
FieldWidth = -1*(?PRINT_WITDH),
format(FTO, "~*.*.*s~n", [FieldWidth, Precision, $-, EndStr]).
@@ -733,6 +737,6 @@ fcl(FTO, A) when is_atom(A) ->
fcl(FTO, atom_to_list(A));
fcl(FTO, Str) when is_list(Str) ->
Str2 = "# --- " ++ Str ++ " ",
- Precision = length(Str2),
+ Precision = string:length(Str2),
FieldWidth = -1*(?PRINT_WITDH),
format(FTO, "~*.*.*s~n", [FieldWidth, Precision, $-, Str2]).
diff --git a/lib/runtime_tools/src/msacc.erl b/lib/runtime_tools/src/msacc.erl
index 0d9b2690e5..7a3633be8e 100644
--- a/lib/runtime_tools/src/msacc.erl
+++ b/lib/runtime_tools/src/msacc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2014-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2014-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -46,7 +46,8 @@
system := float()}}.
--type msacc_type() :: scheduler | aux | async.
+-type msacc_type() :: aux | async | dirty_cpu_scheduler
+ | dirty_io_scheduler | poll | scheduler.
-type msacc_id() :: non_neg_integer().
-type msacc_state() :: alloc | aux | bif | busy_wait | check_io |
emulator | ets | gc | gc_fullsweep | nif |
diff --git a/lib/runtime_tools/src/observer_backend.erl b/lib/runtime_tools/src/observer_backend.erl
index 1b075a507d..3a24986381 100644
--- a/lib/runtime_tools/src/observer_backend.erl
+++ b/lib/runtime_tools/src/observer_backend.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -94,7 +94,7 @@ sys_info() ->
{port_limit, erlang:system_info(port_limit)},
{port_count, erlang:system_info(port_count)},
{ets_limit, erlang:system_info(ets_limit)},
- {ets_count, length(ets:all())},
+ {ets_count, erlang:system_info(ets_count)},
{dist_buf_busy_limit, erlang:system_info(dist_buf_busy_limit)}
| MemInfo].
@@ -279,7 +279,7 @@ get_table_list(mnesia, Opts) ->
end,
[Tab|Acc]
catch _:_What ->
- %% io:format("Skipped ~p: ~p ~p ~n",[Id, _What, erlang:get_stacktrace()]),
+ %% io:format("Skipped ~p: ~p ~p ~n",[Id, _What, Stacktrace]),
Acc
end
end,
@@ -293,7 +293,7 @@ fetch_stats_loop(Parent, Time) ->
erlang:system_flag(scheduler_wall_time, true),
receive
_Msg ->
- %% erlang:system_flag(scheduler_wall_time, false)
+ erlang:system_flag(scheduler_wall_time, false),
ok
after Time ->
_M = Parent ! {stats, 1,
@@ -340,7 +340,6 @@ etop_collect(Collector) ->
case SchedulerWallTime of
undefined ->
- erlang:system_flag(scheduler_wall_time,true),
spawn(fun() -> flag_holder_proc(Collector) end),
ok;
_ ->
@@ -348,10 +347,11 @@ etop_collect(Collector) ->
end.
flag_holder_proc(Collector) ->
+ erlang:system_flag(scheduler_wall_time,true),
Ref = erlang:monitor(process,Collector),
receive
{'DOWN',Ref,_,_,_} ->
- %% erlang:system_flag(scheduler_wall_time,false)
+ erlang:system_flag(scheduler_wall_time,false),
ok
end.
diff --git a/lib/runtime_tools/src/runtime_tools.app.src b/lib/runtime_tools/src/runtime_tools.app.src
index 449532e5c4..b026048b94 100644
--- a/lib/runtime_tools/src/runtime_tools.app.src
+++ b/lib/runtime_tools/src/runtime_tools.app.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@
{modules, [appmon_info, dbg,observer_backend,runtime_tools,
runtime_tools_sup,erts_alloc_config,
ttb_autostart,dyntrace,system_information,
+ scheduler,
msacc]},
{registered, [runtime_tools_sup]},
{applications, [kernel, stdlib]},
diff --git a/lib/runtime_tools/src/scheduler.erl b/lib/runtime_tools/src/scheduler.erl
new file mode 100644
index 0000000000..c896b671ac
--- /dev/null
+++ b/lib/runtime_tools/src/scheduler.erl
@@ -0,0 +1,152 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%% @doc Utility functions for easier measurement of scheduler utilization
+%% using erlang:statistics(scheduler_wall_time).
+
+-module(scheduler).
+
+-export([sample/0,
+ sample_all/0,
+ utilization/1,
+ utilization/2]).
+
+-export_type([sched_sample/0]).
+
+
+-opaque sched_sample() ::
+ {scheduler_wall_time | scheduler_wall_time_all,
+ [{sched_type(), sched_id(), ActiveTime::integer(), TotalTime::integer()}]}.
+
+-type sched_type() :: normal | cpu | io.
+
+-type sched_id() :: integer().
+
+-spec sample() -> sched_sample().
+sample() ->
+ sample(scheduler_wall_time).
+
+-spec sample_all() -> sched_sample().
+sample_all() ->
+ sample(scheduler_wall_time_all).
+
+sample(Stats) ->
+ case erlang:statistics(Stats) of
+ undefined ->
+ erlang:system_flag(scheduler_wall_time, true),
+ sample(Stats);
+
+ List ->
+ Sorted = lists:sort(List),
+ Tagged = lists:map(fun({I, A, T}) -> {sched_tag(I), I, A, T} end,
+ Sorted),
+ {Stats, Tagged}
+ end.
+
+-type sched_util_result() ::
+ [{sched_type(), sched_id(), float(), string()} |
+ {total, float(), string()} |
+ {weighted, float(), string()}].
+
+-spec utilization(Seconds) -> sched_util_result() when
+ Seconds :: pos_integer();
+ (Sample) -> sched_util_result() when
+ Sample :: sched_sample().
+utilization(Seconds) when is_integer(Seconds), Seconds > 0 ->
+ OldFlag = erlang:system_flag(scheduler_wall_time, true),
+ T0 = sample(),
+ receive after Seconds*1000 -> ok end,
+ T1 = sample(),
+ case OldFlag of
+ false ->
+ erlang:system_flag(scheduler_wall_time, OldFlag);
+ true ->
+ ok
+ end,
+ utilization(T0,T1);
+
+utilization({Stats, _}=T0) when Stats =:= scheduler_wall_time;
+ Stats =:= scheduler_wall_time_all ->
+ utilization(T0, sample(Stats)).
+
+-spec utilization(Sample1, Sample2) -> sched_util_result() when
+ Sample1 :: sched_sample(),
+ Sample2 :: sched_sample().
+utilization({Stats, Ts0}, {Stats, Ts1}) ->
+ Diffs = lists:map(fun({{Tag, I, A0, T0}, {Tag, I, A1, T1}}) ->
+ {Tag, I, (A1 - A0), (T1 - T0)}
+ end,
+ lists:zip(Ts0,Ts1)),
+
+ {Lst0, {A, T, N}} = lists:foldl(fun({Tag, I, Adiff, Tdiff}, {Lst, Acc}) ->
+ R = safe_div(Adiff, Tdiff),
+ {[{Tag, I, R, percent(R)} | Lst],
+ acc(Tag, Adiff, Tdiff, Acc)}
+ end,
+ {[], {0, 0, 0}},
+ Diffs),
+
+ Total = safe_div(A, T),
+ Lst1 = lists:reverse(Lst0),
+ Lst2 = case erlang:system_info(logical_processors_available) of
+ unknown -> Lst1;
+ LPA ->
+ Weighted = Total * (N / LPA),
+ [{weighted, Weighted, percent(Weighted)} | Lst1]
+ end,
+ [{total, Total, percent(Total)} | Lst2];
+
+utilization({scheduler_wall_time, _}=T0,
+ {scheduler_wall_time_all, Ts1}) ->
+ utilization(T0, {scheduler_wall_time, remove_io(Ts1)});
+
+utilization({scheduler_wall_time_all, Ts0},
+ {scheduler_wall_time, _}=T1) ->
+ utilization({scheduler_wall_time, remove_io(Ts0)}, T1).
+
+%% Do not include dirty-io in totals
+acc(io, _, _, Acc) ->
+ Acc;
+acc(Tag, Adiff, Tdiff, {Asum, Tsum, N}) when Tag =:= normal; Tag =:= cpu ->
+ {Adiff+Asum, Tdiff+Tsum, N+1}.
+
+
+remove_io(Ts) ->
+ lists:filter(fun({io,_,_,_}) -> false;
+ (_) -> true end,
+ Ts).
+
+safe_div(A, B) ->
+ if B == 0.0 -> 0.0;
+ true -> A / B
+ end.
+
+sched_tag(Nr) ->
+ Normal = erlang:system_info(schedulers),
+ Cpu = Normal + erlang:system_info(dirty_cpu_schedulers),
+ case Nr of
+ _ when Nr =< Normal -> normal;
+ _ when Nr =< Cpu -> cpu;
+ _ -> io
+ end.
+
+
+percent(F) ->
+ float_to_list(F*100, [{decimals,1}]) ++ [$%].
diff --git a/lib/runtime_tools/src/system_information.erl b/lib/runtime_tools/src/system_information.erl
index 3772fcd2f9..8f7bfa195b 100644
--- a/lib/runtime_tools/src/system_information.erl
+++ b/lib/runtime_tools/src/system_information.erl
@@ -400,7 +400,6 @@ os_getenv_erts_specific() ->
"ERL_MALLOC_LIB",
"ERL_MAX_PORTS",
"ERL_MAX_ETS_TABLES",
- "ERL_NO_VFORK",
"ERL_NO_KERNEL_POLL",
"ERL_THREAD_POOL_SIZE",
"ERLC_EMULATOR",
@@ -674,12 +673,12 @@ vsnstr2vsn(VsnStr) ->
list_to_tuple(lists:map(fun (Part) ->
list_to_integer(Part)
end,
- string:tokens(VsnStr, "."))).
+ string:lexemes(VsnStr, "."))).
rtdepstrs2rtdeps([]) ->
[];
rtdepstrs2rtdeps([RTDep | RTDeps]) ->
- [AppStr, VsnStr] = string:tokens(RTDep, "-"),
+ [AppStr, VsnStr] = string:lexemes(RTDep, "-"),
[{list_to_atom(AppStr), vsnstr2vsn(VsnStr)} | rtdepstrs2rtdeps(RTDeps)].
build_app_table([], AppTab) ->
diff --git a/lib/runtime_tools/test/Makefile b/lib/runtime_tools/test/Makefile
index 61377ea09e..29cf7545c9 100644
--- a/lib/runtime_tools/test/Makefile
+++ b/lib/runtime_tools/test/Makefile
@@ -9,7 +9,9 @@ MODULES = \
system_information_SUITE \
dbg_SUITE \
erts_alloc_config_SUITE \
- msacc_SUITE
+ scheduler_SUITE \
+ msacc_SUITE \
+ zzz_SUITE
ERL_FILES= $(MODULES:%=%.erl)
diff --git a/lib/runtime_tools/test/dbg_SUITE.erl b/lib/runtime_tools/test/dbg_SUITE.erl
index 4b0864858c..98cbc0360f 100644
--- a/lib/runtime_tools/test/dbg_SUITE.erl
+++ b/lib/runtime_tools/test/dbg_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@
-export([all/0, suite/0,
big/1, tiny/1, simple/1, message/1, distributed/1, port/1,
send/1, recv/1,
- ip_port/1, file_port/1, file_port2/1, file_port_schedfix/1,
+ ip_port/1, file_port/1, file_port2/1,
ip_port_busy/1, wrap_port/1, wrap_port_time/1,
with_seq_trace/1, dead_suspend/1, local_trace/1,
saved_patterns/1, tracer_exit_on_stop/1,
@@ -41,7 +41,7 @@ suite() ->
all() ->
[big, tiny, simple, message, distributed, port, ip_port,
send, recv,
- file_port, file_port2, file_port_schedfix, ip_port_busy,
+ file_port, file_port2, ip_port_busy,
wrap_port, wrap_port_time, with_seq_trace, dead_suspend,
local_trace, saved_patterns, tracer_exit_on_stop,
erl_tracer, distributed_erl_tracer].
@@ -478,8 +478,7 @@ port(Config) when is_list(Config) ->
TraceFileDrv = list_to_atom(lists:flatten(["trace_file_drv n ",TestFile])),
[{trace,Port,open,S,TraceFileDrv},
{trace,Port,getting_linked,S},
- {trace,Port,closed,normal},
- {trace,Port,unlink,S}] = flush()
+ {trace,Port,closed,normal}] = flush()
after
dbg:stop()
end,
@@ -623,99 +622,6 @@ file_port2(Config) when is_list(Config) ->
end,
ok.
-%% Test that the scheduling timestamp fix for trace flag 'running' works.
-file_port_schedfix(Config) when is_list(Config) ->
- case (catch erlang:system_info(smp_support)) of
- true ->
- {skip, "No schedule fix on SMP"};
- _ ->
- try
- file_port_schedfix1(Config)
- after
- dbg:stop()
- end
- end.
-file_port_schedfix1(Config) when is_list(Config) ->
- stop(),
- {A,B,C} = erlang:now(),
- FTMP = atom_to_list(?MODULE) ++ integer_to_list(A) ++
- "-" ++ integer_to_list(B) ++ "-" ++ integer_to_list(C),
- FName = filename:join([proplists:get_value(data_dir, Config), FTMP]),
- %%
- Port = dbg:trace_port(file, {FName, wrap, ".wraplog", 8*1024, 4}),
- {ok, _} = dbg:tracer(port, Port),
- {ok,[{matched,_node,0}]} = dbg:p(new,[running,procs,send,timestamp]),
- %%
- %% Generate the trace data
- %%
- %% This starts 3 processes that sends a message to each other in a ring,
- %% 4 laps. Prior to sending the message to the next in the ring, each
- %% process send 8 messages to itself, just to generate some trace data,
- %% and to lower the possibility that the trace log wraps just after
- %% a schedule out message (which would not burden any process and hence
- %% not show up in the result)
- %%
- %% The wrap file trace is used because it burns a lot of time when the
- %% driver swaps files, a lot more than the regular file trace. The test
- %% case is dimensioned so that the log fills two files and just starts
- %% on the third (out of four wrap files). This gives two file swaps,
- %% and there are three processes, so one process will NOT be burdened.
- %% The criterion for trace success is then that the max process
- %% execution time must not be more than twice the min process
- %% execution time. Wallclock. A normal result is about 10 times more
- %% without schedule in - schedule out compensation (OTP-3938).
- %%
- ok = token_volleyball(3, 4, 8),
- %%
- {ok,[{matched,_,_}]} = dbg:p(all, [clear]),
- stop(),
- %%
- %% Get the trace result
- %%
- Tag = make_ref(),
- dbg:trace_client(file, {FName, wrap, ".wraplog"},
- {fun schedstat_handler/2, {self(), Tag, []}}),
- Result =
- receive
- {Tag, D} ->
- lists:map(
- fun({Pid, {A1, B1, C1}}) ->
- {Pid, C1/1000000 + B1 + A1*1000000}
- end,
- D)
- end,
- ok = io:format("Result=~p", [Result]),
- % erlang:display({?MODULE, ?LINE, Result}),
- %%
- %% Analyze the result
- %%
- {Min, Max} = lists:foldl(fun({_Pid, M}, {Mi, Ma}) ->
- {if M < Mi -> M; true -> Mi end,
- if M > Ma -> M; true -> Ma end}
- end,
- {void, 0},
- Result),
- % More PaN debug
- io:format("Min = ~f, Max = ~f~n",[Min,Max]),
- %%
- %% Cleanup
- %%
- ToBeDeleted = filelib:wildcard(FName++"*"++".wraplog"),
- lists:map(fun file:delete/1, ToBeDeleted),
- % io:format("ToBeDeleted=~p", [ToBeDeleted]),
- %%
- %% Present the result
- %%
- P = (Max / Min - 1) * 100,
- BottomLine = lists:flatten(io_lib:format("~.2f %", [P])),
- if P > 100 ->
- Reason = {BottomLine, '>', "100%"},
- erlang:display({file_port_schedfix, fail, Reason}),
- ct:fail(Reason);
- true ->
- {comment, BottomLine}
- end.
-
%% Test tracing to wrapping file port
wrap_port(Config) when is_list(Config) ->
Self = self(),
diff --git a/lib/runtime_tools/test/dyntrace_SUITE.erl b/lib/runtime_tools/test/dyntrace_SUITE.erl
index 7be2f49a8b..17bc104e9a 100644
--- a/lib/runtime_tools/test/dyntrace_SUITE.erl
+++ b/lib/runtime_tools/test/dyntrace_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -51,11 +51,7 @@ init_per_suite(Config) ->
case erlang:system_info(debug_compiled) of
false -> "";
true -> ".debug"
- end ++
- case erlang:system_info(smp_support) of
- false -> "";
- true -> ".smp"
- end,
+ end ++ ".smp",
[{emu_name,N}|Config].
end_per_suite(_Config) ->
diff --git a/lib/runtime_tools/test/scheduler_SUITE.erl b/lib/runtime_tools/test/scheduler_SUITE.erl
new file mode 100644
index 0000000000..1c80253371
--- /dev/null
+++ b/lib/runtime_tools/test/scheduler_SUITE.erl
@@ -0,0 +1,104 @@
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+-module(scheduler_SUITE).
+
+-export([suite/0, all/0]).
+
+%% Test cases
+-export([basic/1]).
+
+all() -> [basic].
+
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+
+basic(_Config) ->
+ S1 = scheduler:sample(),
+ S2 = scheduler:sample_all(),
+
+ check(scheduler:utilization(1)),
+
+ check(scheduler:utilization(S1)),
+ check(scheduler:utilization(S2)),
+ check(scheduler:utilization(S1, scheduler:sample())),
+ check(scheduler:utilization(S2, scheduler:sample())),
+
+ S3 = scheduler:sample_all(),
+ U13 = scheduler:utilization(S1, S3),
+ U13 = scheduler:utilization(S1, remove_io(S3)),
+ check(U13),
+
+ U23all = scheduler:utilization(S2, S3),
+ check(U23all),
+ U23 = scheduler:utilization(S2, remove_io(S3)),
+ U23 = scheduler:utilization(remove_io(S2), S3),
+ U23 = remove_io(U23all),
+ check(U23),
+
+ ok.
+
+
+check([{total, Tf, Ts} | List]=U) ->
+ io:format("\nU = ~p\n", [U]),
+ check_values(Tf, Ts, true),
+
+ SchdList = case hd(List) of
+ {weighted, Wf, Ws} ->
+ check_values(Wf, Ws, false),
+ tl(List);
+ _ ->
+ unknown = erlang:system_info(logical_processors_available),
+ List
+ end,
+
+ lists:foreach(fun({Type, Id, F, S}) when ((Type =:= normal) or (Type =:= cpu) or (Type =:= io)),
+ is_integer(Id) ->
+ check_values(F, S, true)
+ end,
+ SchdList),
+ ok.
+
+check_values(F, S, Max100) ->
+ true = is_float(F),
+ true = F >= 0.0,
+
+ $% = lists:last(S),
+ Sf = list_to_float(lists:droplast(S)),
+ true = Sf >= 0.0,
+ true = case Max100 of
+ true ->
+ true = F =< 1.0,
+ true = Sf =< 100.0;
+ false ->
+ true
+ end,
+ MaxDiff = 0.055555555555555555, %% change to 0.05 when float_to_list/2 is fixed
+ true = abs(F*100 - Sf) =< MaxDiff,
+ ok.
+
+
+remove_io({scheduler_wall_time_all,Lst}) ->
+ {scheduler_wall_time, remove_io(Lst)};
+remove_io(Lst) ->
+ lists:filter(fun({io,_,_,_}) -> false;
+ (_) -> true end,
+ Lst).
diff --git a/lib/runtime_tools/test/system_information_SUITE_data/information_test_report.dat b/lib/runtime_tools/test/system_information_SUITE_data/information_test_report.dat
index a0e3806981..a9399a5d53 100644
--- a/lib/runtime_tools/test/system_information_SUITE_data/information_test_report.dat
+++ b/lib/runtime_tools/test/system_information_SUITE_data/information_test_report.dat
@@ -6829,7 +6829,7 @@
{native,false},
{compiler,"4.9.1"},
{md5,"55bb9fddcdf820938be2efee15eccd82"}]},
- {otp_ring0,
+ {erl_init,
[{loaded,true},
{native,false},
{compiler,"4.9.1"},
diff --git a/lib/runtime_tools/test/zzz_SUITE.erl b/lib/runtime_tools/test/zzz_SUITE.erl
new file mode 100644
index 0000000000..59c7fd7404
--- /dev/null
+++ b/lib/runtime_tools/test/zzz_SUITE.erl
@@ -0,0 +1,37 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(zzz_SUITE).
+
+%% The sole purpose of this test suite is for things we want to run last
+%% before the VM terminates.
+
+-export([all/0]).
+
+-export([lc_graph/1]).
+
+
+all() ->
+ [lc_graph].
+
+lc_graph(_Config) ->
+ %% Create "lc_graph" file in current working dir
+ %% if lock checker is enabled.
+ erts_debug:lc_graph(),
+ ok.
diff --git a/lib/runtime_tools/vsn.mk b/lib/runtime_tools/vsn.mk
index 26869b9412..3f38574be4 100644
--- a/lib/runtime_tools/vsn.mk
+++ b/lib/runtime_tools/vsn.mk
@@ -1 +1 @@
-RUNTIME_TOOLS_VSN = 1.12.5
+RUNTIME_TOOLS_VSN = 1.13.3
diff --git a/lib/sasl/doc/src/Makefile b/lib/sasl/doc/src/Makefile
index baf563ca62..8e1e8b502c 100644
--- a/lib/sasl/doc/src/Makefile
+++ b/lib/sasl/doc/src/Makefile
@@ -101,6 +101,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(MAN4DIR)/*
rm -f $(MAN6DIR)/*
diff --git a/lib/sasl/doc/src/alarm_handler.xml b/lib/sasl/doc/src/alarm_handler.xml
index 4160757164..6e74f833cd 100644
--- a/lib/sasl/doc/src/alarm_handler.xml
+++ b/lib/sasl/doc/src/alarm_handler.xml
@@ -34,7 +34,7 @@
<rev>A</rev>
<file>alarm_handler.sgml.t1</file>
</header>
- <module>alarm_handler</module>
+ <module since="">alarm_handler</module>
<modulesummary>An Alarm Handling Process</modulesummary>
<description>
<p>The alarm handler process is a
@@ -81,7 +81,7 @@
<funcs>
<func>
- <name>clear_alarm(AlarmId) -> void()</name>
+ <name since="">clear_alarm(AlarmId) -> void()</name>
<fsummary>Clears the specified alarms.</fsummary>
<type>
<v>AlarmId = term()</v>
@@ -94,7 +94,7 @@
</func>
<func>
- <name>get_alarms() -> [alarm()]</name>
+ <name since="">get_alarms() -> [alarm()]</name>
<fsummary>Gets all active alarms.</fsummary>
<desc>
<p>Returns a list of all active alarms. This function can only
@@ -103,7 +103,7 @@
</func>
<func>
- <name>set_alarm(alarm())</name>
+ <name since="">set_alarm(alarm())</name>
<fsummary>Sets an alarm with an id.</fsummary>
<type>
<v>alarm() = {AlarmId, AlarmDescription}</v>
diff --git a/lib/sasl/doc/src/appup.xml b/lib/sasl/doc/src/appup.xml
index a43a966dcb..102ea9e5d7 100644
--- a/lib/sasl/doc/src/appup.xml
+++ b/lib/sasl/doc/src/appup.xml
@@ -4,7 +4,7 @@
<fileref>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -249,9 +249,17 @@
<pre>
{restart_application, Application}
Application = atom()</pre>
- <p>Restarting an application means that the application is
- stopped and then started again, similar to using the instructions
- <c>remove_application</c> and <c>add_application</c> in sequence.</p>
+ <p>Restarting an application means that the application is stopped
+ and then started again, similar to using the instructions
+ <c>remove_application</c> and <c>add_application</c> in sequence.
+ Note that, even if the application has been started before the
+ release upgrade is performed, <c>restart_application</c> may only
+ <c>load</c> it rather than <c>start</c> it, depending on the
+ application's <c>start type</c>:
+ If <c>Type = load</c>, the application is only loaded.
+ If <c>Type = none</c>, the application is not loaded and not
+ started, although the code for its modules is loaded.
+ </p>
</section>
<section>
diff --git a/lib/sasl/doc/src/error_logging.xml b/lib/sasl/doc/src/error_logging.xml
index 4b2c960bbb..e6c244c1b9 100644
--- a/lib/sasl/doc/src/error_logging.xml
+++ b/lib/sasl/doc/src/error_logging.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,22 +32,52 @@
<rev>B</rev>
<file>error_logging.xml</file>
</header>
+ <note>
+ <p>The SASL error logging concept described in this section is
+ deprecated since Erlang/OTP 21.0, when the
+ new <seealso marker="kernel:logger_chapter">logging
+ API</seealso> was introduced.</p>
+ <p>The new default behaviour is that the SASL application no
+ longer affects which log events that are logged.
+ <seealso marker="#supervisor_report">Supervisor
+ reports</seealso> and <seealso marker="#crash_report">crash
+ reports</seealso> are logged via the default logger handler
+ which is setup by
+ Kernel. <seealso marker="#progress_report">Progress
+ reports</seealso> are by default not logged, but can be enabled
+ by setting the primary log level to <c>info</c>, for example by
+ using the Kernel configuration
+ parameter <seealso marker="kernel:kernel_app#logger_level">
+ <c>logger_level</c></seealso>.</p>
+ <p>The old SASL error logging behaviour can be re-enabled by setting the
+ Kernel configuration
+ parameter <seealso marker="kernel:kernel_app#logger_sasl_compatible">
+ <c>logger_sasl_compatible</c></seealso> to <c>true</c>.</p>
+ <p>The mechanism
+ for <seealso marker="#multi_file_logging">multi-file error report
+ logging</seealso> as described in this section is also kept for
+ backwards compatibility. However, the new logging API also
+ introduces <seealso marker="kernel:logger_disk_log_h">
+ <c>logger_disk_log_h(3)</c></seealso>, which is a logger
+ handler that can print to multiple files
+ using <seealso marker="kernel:disk_log"><c>disk_log(3)</c></seealso>.</p>
+ </note>
+
+ <section>
+ <title>SASL reports</title>
<p>The SASL application introduces three types of reports:</p>
<list type="bulleted">
<item>Supervisor report</item>
<item>Progress report</item>
<item>Crash report</item>
</list>
- <p>When the SASL application is started, it adds a handler that
- formats and writes these reports, as specified in the configuration
- parameters for SASL, that is, the environment variables
- in the SASL application specification, which is found in the
- <c>.app</c> file of SASL. For details, see the
- <seealso marker="sasl_app"><c>sasl(6)</c></seealso> application in the
- Reference Manual and the <seealso marker="kernel:app"><c>app(4)</c></seealso>
- file in the Kernel Reference Manual.</p>
+ <p>When the SASL application is started, it adds a Logger handler
+ that formats and writes these reports, as specified in
+ the <seealso marker="sasl_app#deprecated_error_logger_config">configuration
+ parameters for SASL</seealso>.</p>
<section>
+ <marker id="supervisor_report"/>
<title>Supervisor Report</title>
<p>A supervisor report is issued when a supervised child terminates
unexpectedly. A supervisor report contains the following
@@ -68,6 +98,7 @@
</section>
<section>
+ <marker id="progress_report"/>
<title>Progress Report</title>
<p>A progress report is issued when a supervisor starts or
restarts a child. A progress report contains the following items:</p>
@@ -82,6 +113,7 @@
</section>
<section>
+ <marker id="crash_report"/>
<title>Crash Report</title>
<p>Processes started with functions
<seealso marker="stdlib:proc_lib#spawn/1"><c>proc_lib:spawn</c></seealso> or
@@ -105,6 +137,7 @@
crash. The information gathered is the same as the information
for Crasher, described in the previous item.</p></item>
</taglist>
+ </section>
<section>
<title>Example</title>
@@ -163,6 +196,7 @@
</section>
<section>
+ <marker id="multi_file_logging"/>
<title>Multi-File Error Report Logging</title>
<p>Multi-file error report logging is used to store error messages
received by <c>error_logger</c>. The error messages
@@ -171,7 +205,8 @@
of files exist at the same time. The logging is very fast, as
each error message is written as a binary term.</p>
<p>For more details, see the
- <seealso marker="sasl_app"><c>sasl(6)</c></seealso>
+ <seealso marker="sasl_app#deprecated_error_logger_config">
+ <c>sasl(6)</c></seealso>
application in the Reference Manual.</p>
</section>
diff --git a/lib/sasl/doc/src/notes.xml b/lib/sasl/doc/src/notes.xml
index e532c3cd6f..a1ae404776 100644
--- a/lib/sasl/doc/src/notes.xml
+++ b/lib/sasl/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,6 +31,157 @@
</header>
<p>This document describes the changes made to the SASL application.</p>
+<section><title>SASL 3.4</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Change the first module called by erts to be named
+ erl_init instead of otp_ring0. systools in sasl have been
+ updated to reflect this change.</p>
+ <p>
+ Own Id: OTP-15336 Aux Id: PR-1825 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SASL 3.3</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ New <c>counters</c> and <c>atomics</c> modules supplies
+ access to highly efficient operations on mutable fixed
+ word sized variables.</p>
+ <p>
+ Own Id: OTP-13468</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SASL 3.2.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SASL 3.2</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>A new logging API is added to Erlang/OTP, see the
+ <seealso
+ marker="kernel:logger"><c>logger(3)</c></seealso> manual
+ page, and section <seealso
+ marker="kernel:logger_chapter">Logging</seealso> in the
+ Kernel User's Guide.</p>
+ <p>Calls to <c>error_logger</c> are automatically
+ redirected to the new API, and legacy error logger event
+ handlers can still be used. It is, however, recommended
+ to use the Logger API directly when writing new code.</p>
+ <p>Notice the following potential incompatibilities:</p>
+ <list> <item><p>Kernel configuration parameters
+ <c>error_logger</c> still works, but is overruled if the
+ default handler's output destination is configured with
+ Kernel configuration parameter <c>logger</c>.</p> <p>In
+ general, parameters for configuring error logger are
+ overwritten by new parameters for configuring
+ Logger.</p></item> <item><p>The concept of SASL error
+ logging is deprecated, meaning that by default the SASL
+ application does not affect which log events are
+ logged.</p> <p>By default, supervisor reports and crash
+ reports are logged by the default Logger handler started
+ by Kernel, and end up at the same destination (terminal
+ or file) as other standard log event from Erlang/OTP.</p>
+ <p>Progress reports are not logged by default, but can be
+ enabled by setting the primary log level to info, for
+ example with the Kernel configuration parameter
+ <c>logger_level</c>.</p> <p>To obtain backwards
+ compatibility with the SASL error logging functionality
+ from earlier releases, set Kernel configuration parameter
+ <c>logger_sasl_compatible</c> to <c>true</c>. This
+ prevents the default Logger handler from logging any
+ supervisor-, crash-, or progress reports. Instead, SASL
+ adds a separate Logger handler during application start,
+ which takes care of these log events. The SASL
+ configuration parameters <c>sasl_error_logger</c> and
+ <c>sasl_errlog_type</c> specify the destination (terminal
+ or file) and severity level to log for these
+ events.</p></item></list>
+ <p>
+ Since Logger is new in Erlang/OTP 21.0, we do reserve the
+ right to introduce changes to the Logger API and
+ functionality in patches following this release. These
+ changes might or might not be backwards compatible with
+ the initial version.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-13295</p>
+ </item>
+ <item>
+ <p>
+ The old and outdated "Status Inspection" tool (modules
+ <c>si</c> and <c>si_sasl_sup</c>) is removed.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14469</p>
+ </item>
+ <item>
+ <p>
+ When creating the release tar file, systools now includes
+ sys.config.src if it exists in the
+ $ROOT/releases/&lt;vsn&gt;/ directory. This is to allow
+ adjustments, e.g. resolving environment variables, after
+ unpacking the release, but before installing it. This
+ functionality requires a custom tool which uses
+ sys.config.src as input and creates a correct sys.config
+ file.</p>
+ <p>
+ Own Id: OTP-14950 Aux Id: PR-1560 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SASL 3.1.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ When upgrading with instruction 'restart_new_emulator',
+ the generated temporary boot file used 'kernelProcess'
+ statements from the old release instead of the new
+ release. This is now corrected.</p>
+ <p>
+ This correction is needed for upgrade to OTP-21.</p>
+ <p>
+ Own Id: OTP-15017</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>SASL 3.1.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/sasl/doc/src/rb.xml b/lib/sasl/doc/src/rb.xml
index d5df4fd345..0ed7e91c11 100644
--- a/lib/sasl/doc/src/rb.xml
+++ b/lib/sasl/doc/src/rb.xml
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>rb.sgml</file>
</header>
- <module>rb</module>
+ <module since="">rb</module>
<modulesummary>The Report Browser Tool</modulesummary>
<description>
<p>The Report Browser (RB) tool is used to browse and
@@ -43,8 +43,8 @@
<funcs>
<func>
- <name>filter(Filters)</name>
- <name>filter(Filters, Dates)</name>
+ <name since="OTP R13B04">filter(Filters)</name>
+ <name since="OTP R13B04">filter(Filters, Dates)</name>
<fsummary>Filters reports and displays them on the screen.</fsummary>
<type>
<v>Filters = [filter()]</v>
@@ -86,7 +86,7 @@
</func>
<func>
- <name>grep(RegExp)</name>
+ <name since="">grep(RegExp)</name>
<fsummary>Searches the reports for a regular expression.</fsummary>
<type>
<v>RegExp = string() | {string(), Options} | re:mp() | {re:mp(), Options}</v>
@@ -109,8 +109,8 @@
</func>
<func>
- <name>h()</name>
- <name>help()</name>
+ <name since="">h()</name>
+ <name since="">help()</name>
<fsummary>Displays help information.</fsummary>
<desc>
<p>Displays online help information.</p>
@@ -118,8 +118,8 @@
</func>
<func>
- <name>list()</name>
- <name>list(Type)</name>
+ <name since="">list()</name>
+ <name since="">list(Type)</name>
<fsummary>Lists all reports.</fsummary>
<type>
<v>Type = type()</v>
@@ -137,8 +137,8 @@
</func>
<func>
- <name>log_list()</name>
- <name>log_list(Type)</name>
+ <name since="OTP R16B02">log_list()</name>
+ <name since="OTP R16B02">log_list(Type)</name>
<fsummary>Logs report lists.</fsummary>
<type>
<v>Type = type()</v>
@@ -157,8 +157,8 @@
</func>
<func>
- <name>rescan()</name>
- <name>rescan(Options)</name>
+ <name since="">rescan()</name>
+ <name since="">rescan(Options)</name>
<fsummary>Rescans the report directory.</fsummary>
<type>
<v>Options = [opt()]</v>
@@ -171,8 +171,8 @@
</func>
<func>
- <name>show()</name>
- <name>show(Report)</name>
+ <name since="">show()</name>
+ <name since="">show(Report)</name>
<fsummary>Displays reports.</fsummary>
<type>
<v>Report = integer() | type()</v>
@@ -186,8 +186,8 @@
</func>
<func>
- <name>start()</name>
- <name>start(Options)</name>
+ <name since="">start()</name>
+ <name since="">start(Options)</name>
<fsummary>Starts the <c>rb_server</c>.</fsummary>
<type>
<v>Options = [opt()]</v>
@@ -256,7 +256,7 @@
</func>
<func>
- <name>start_log(FileName)</name>
+ <name since="">start_log(FileName)</name>
<fsummary>Redirects all output to <c>FileName</c>.</fsummary>
<type>
<v>FileName = string() | atom() | pid()</v>
@@ -268,7 +268,7 @@
</func>
<func>
- <name>stop()</name>
+ <name since="">stop()</name>
<fsummary>Stops the <c>rb_server</c>.</fsummary>
<desc>
<p>Stops <c>rb_server</c>.</p>
@@ -276,7 +276,7 @@
</func>
<func>
- <name>stop_log()</name>
+ <name since="">stop_log()</name>
<fsummary>Stops logging to file.</fsummary>
<desc>
<p>Closes the log file. The output from the RB tool is
diff --git a/lib/sasl/doc/src/release_handler.xml b/lib/sasl/doc/src/release_handler.xml
index 8f073807fb..f8ee0306d8 100644
--- a/lib/sasl/doc/src/release_handler.xml
+++ b/lib/sasl/doc/src/release_handler.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>release_handler</module>
+ <module since="">release_handler</module>
<modulesummary>Unpacking and Installation of Release Packages</modulesummary>
<description>
<p>The <em>release handler</em> process belongs to the SASL
@@ -61,6 +61,7 @@
<list type="bulleted">
<item>A release upgrade file, <c>relup</c></item>
<item>A system configuration file, <c>sys.config</c></item>
+ <item>A system configuration source file, <c>sys.config.src</c></item>
</list>
<p>The <c>relup</c> file contains instructions for how to upgrade
to, or downgrade from, this version of the release.</p>
@@ -167,8 +168,8 @@
<funcs>
<func>
- <name>check_install_release(Vsn) -> {ok, OtherVsn, Descr} | {error, Reason}</name>
- <name>check_install_release(Vsn,Opts) -> {ok, OtherVsn, Descr} | {error, Reason}</name>
+ <name since="">check_install_release(Vsn) -> {ok, OtherVsn, Descr} | {error, Reason}</name>
+ <name since="OTP R14B04">check_install_release(Vsn,Opts) -> {ok, OtherVsn, Descr} | {error, Reason}</name>
<fsummary>Checks installation of a release in the system.</fsummary>
<type>
<v>Vsn = OtherVsn = string()</v>
@@ -201,7 +202,7 @@
</func>
<func>
- <name>create_RELEASES(Root, RelDir, RelFile, AppDirs) -> ok | {error, Reason}</name>
+ <name since="">create_RELEASES(Root, RelDir, RelFile, AppDirs) -> ok | {error, Reason}</name>
<fsummary>Creates an initial <c>RELEASES</c> file.</fsummary>
<type>
<v>Root = RelDir = RelFile = string()</v>
@@ -232,7 +233,7 @@
</func>
<func>
- <name>install_file(Vsn, File) -> ok | {error, Reason}</name>
+ <name since="">install_file(Vsn, File) -> ok | {error, Reason}</name>
<fsummary>Installs a release file in the release structure.</fsummary>
<type>
<v>Vsn = File = string()</v>
@@ -251,8 +252,8 @@
</func>
<func>
- <name>install_release(Vsn) -> {ok, OtherVsn, Descr} | {error, Reason}</name>
- <name>install_release(Vsn, [Opt]) -> {ok, OtherVsn, Descr} | {continue_after_restart, OtherVsn, Descr} | {error, Reason}</name>
+ <name since="">install_release(Vsn) -> {ok, OtherVsn, Descr} | {error, Reason}</name>
+ <name since="">install_release(Vsn, [Opt]) -> {ok, OtherVsn, Descr} | {continue_after_restart, OtherVsn, Descr} | {error, Reason}</name>
<fsummary>Installs a release in the system.</fsummary>
<type>
<v>Vsn = OtherVsn = string()</v>
@@ -382,7 +383,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]).
</func>
<func>
- <name>make_permanent(Vsn) -> ok | {error, Reason}</name>
+ <name since="">make_permanent(Vsn) -> ok | {error, Reason}</name>
<fsummary>Makes the specified release version permanent.</fsummary>
<type>
<v>Vsn = string()</v>
@@ -395,7 +396,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]).
</func>
<func>
- <name>remove_release(Vsn) -> ok | {error, Reason}</name>
+ <name since="">remove_release(Vsn) -> ok | {error, Reason}</name>
<fsummary>Removes a release from the system.</fsummary>
<type>
<v>Vsn = string()</v>
@@ -409,7 +410,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]).
</func>
<func>
- <name>reboot_old_release(Vsn) -> ok | {error, Reason}</name>
+ <name since="">reboot_old_release(Vsn) -> ok | {error, Reason}</name>
<fsummary>Reboots the system from an old release.</fsummary>
<type>
<v>Vsn = string()</v>
@@ -424,7 +425,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]).
</func>
<func>
- <name>set_removed(Vsn) -> ok | {error, Reason}</name>
+ <name since="">set_removed(Vsn) -> ok | {error, Reason}</name>
<fsummary>Marks a release as removed.</fsummary>
<type>
<v>Vsn = string()</v>
@@ -439,7 +440,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]).
</func>
<func>
- <name>set_unpacked(RelFile, AppDirs) -> {ok, Vsn} | {error, Reason}</name>
+ <name since="">set_unpacked(RelFile, AppDirs) -> {ok, Vsn} | {error, Reason}</name>
<fsummary>Marks a release as unpacked.</fsummary>
<type>
<v>RelFile = string()</v>
@@ -465,7 +466,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]).
</func>
<func>
- <name>unpack_release(Name) -> {ok, Vsn} | {error, Reason}</name>
+ <name since="">unpack_release(Name) -> {ok, Vsn} | {error, Reason}</name>
<fsummary>Unpacks a release package.</fsummary>
<type>
<v>Name = Vsn = string()</v>
@@ -481,7 +482,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]).
</func>
<func>
- <name>which_releases() -> [{Name, Vsn, Apps, Status}]</name>
+ <name since="">which_releases() -> [{Name, Vsn, Apps, Status}]</name>
<fsummary>Returns all known releases.</fsummary>
<type>
<v>Name = Vsn = string()</v>
@@ -494,7 +495,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]).
</func>
<func>
- <name>which_releases(Status) -> [{Name, Vsn, Apps, Status}]</name>
+ <name since="OTP R15B">which_releases(Status) -> [{Name, Vsn, Apps, Status}]</name>
<fsummary>Returns all known releases of a specific status.</fsummary>
<type>
<v>Name = Vsn = string()</v>
@@ -536,7 +537,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]).
<funcs>
<func>
- <name>upgrade_app(App, Dir) -> {ok, Unpurged} | restart_emulator | {error, Reason}</name>
+ <name since="">upgrade_app(App, Dir) -> {ok, Unpurged} | restart_emulator | {error, Reason}</name>
<fsummary>Upgrades to a new application version.</fsummary>
<type>
<v>App = atom()</v>
@@ -585,8 +586,8 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]).
</func>
<func>
- <name>downgrade_app(App, Dir) -></name>
- <name>downgrade_app(App, OldVsn, Dir) -> {ok, Unpurged} | restart_emulator | {error, Reason}</name>
+ <name since="">downgrade_app(App, Dir) -></name>
+ <name since="">downgrade_app(App, OldVsn, Dir) -> {ok, Unpurged} | restart_emulator | {error, Reason}</name>
<fsummary>Downgrades to a previous application version.</fsummary>
<type>
<v>App = atom()</v>
@@ -632,7 +633,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]).
</func>
<func>
- <name>upgrade_script(App, Dir) -> {ok, NewVsn, Script}</name>
+ <name since="">upgrade_script(App, Dir) -> {ok, NewVsn, Script}</name>
<fsummary>Finds an application upgrade script.</fsummary>
<type>
<v>App = atom()</v>
@@ -670,7 +671,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]).
</func>
<func>
- <name>downgrade_script(App, OldVsn, Dir) -> {ok, Script}</name>
+ <name since="">downgrade_script(App, OldVsn, Dir) -> {ok, Script}</name>
<fsummary>Finds an application downgrade script.</fsummary>
<type>
<v>App = atom()</v>
@@ -709,7 +710,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]).
</func>
<func>
- <name>eval_appup_script(App, ToVsn, ToDir, Script) -> {ok, Unpurged} | restart_emulator | {error, Reason}</name>
+ <name since="">eval_appup_script(App, ToVsn, ToDir, Script) -> {ok, Unpurged} | restart_emulator | {error, Reason}</name>
<fsummary>Evaluates an application upgrade or downgrade script.</fsummary>
<type>
<v>App = atom()</v>
@@ -819,4 +820,3 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]).
<seealso marker="systools"><c>systools(3)</c></seealso></p>
</section>
</erlref>
-
diff --git a/lib/sasl/doc/src/sasl_app.xml b/lib/sasl/doc/src/sasl_app.xml
index e0693fcb60..fc83f63fe6 100644
--- a/lib/sasl/doc/src/sasl_app.xml
+++ b/lib/sasl/doc/src/sasl_app.xml
@@ -4,7 +4,7 @@
<appref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -34,12 +34,9 @@
<p>The SASL application provides the following services:</p>
<list type="bulleted">
<item><c>alarm_handler</c></item>
- <item><c>rb</c></item>
<item><c>release_handler</c></item>
<item><c>systools</c></item>
</list>
- <p>The SASL application also includes <c>error_logger</c> event
- handlers for formatting SASL error and crash reports.</p>
<note>
<p>The SASL application in OTP has nothing to do with
"Simple Authentication and Security Layer" (RFC 4422).</p>
@@ -47,51 +44,101 @@
</description>
<section>
- <title>Error Logger Event Handlers</title>
- <p>The following error logger event handlers are used by
- the SASL application.</p>
+ <title>Configuration</title>
+ <p>The following configuration parameters are defined for the SASL
+ application. For more information about configuration parameters, see
+ <seealso marker="kernel:app"><c>app(4)</c></seealso> in Kernel.</p>
+ <p>All configuration parameters are optional.</p>
+ <taglist>
+ <tag><c><![CDATA[start_prg = string() ]]></c></tag>
+ <item>
+ <p>Specifies the program to be used when restarting the system
+ during release installation. Default is
+ <c>$OTP_ROOT/bin/start</c>.</p>
+ </item>
+ <tag><c><![CDATA[masters = [atom()] ]]></c></tag>
+ <item>
+ <p>Specifies the nodes used by this node to read/write release
+ information. This parameter is ignored if parameter
+ <c>client_directory</c> is not set.</p>
+ </item>
+ <tag><c><![CDATA[client_directory = string() ]]></c></tag>
+ <item>
+ <p>This parameter specifies the client directory at the master
+ nodes. For details, see
+ <seealso marker="doc/design_principles:release_handling">Release Handling</seealso>
+ in <em>OTP Design Principles</em>. This parameter is
+ ignored if parameter <c>masters</c> is not set.</p>
+ </item>
+ <tag><c><![CDATA[static_emulator = true | false ]]></c></tag>
+ <item>
+ <p>Indicates if the Erlang emulator is statically installed. A
+ node with a static emulator cannot switch dynamically to a
+ new emulator, as the executable files are written into memory
+ statically. This parameter is ignored if parameters <c>masters</c>
+ and <c>client_directory</c> are not set.</p>
+ </item>
+ <tag><c><![CDATA[releases_dir = string() ]]></c></tag>
+ <item>
+ <p>Indicates where the <c>releases</c> directory is located.
+ The release handler writes all its files to this directory.
+ If this parameter is not set, the OS environment parameter
+ <c>RELDIR</c> is used. By default, this is
+ <c>$OTP_ROOT/releases</c>.</p>
+ </item>
+ </taglist>
+ </section>
+
+ <section>
+ <marker id="deprecated_error_logger_config"/>
+ <title>Deprecated Error Logger Event Handlers and Configuration</title>
+ <p>In Erlang/OTP 21.0, a new API for logging was added. The
+ old <c>error_logger</c> event manager, and event handlers
+ running on this manager, still work, but they are not used
+ by default.</p>
+ <p>The error logger event handlers <c>sasl_report_tty_h</c>
+ and <c>sasl_report_file_h</c>, were earlier used for printing
+ the so called SASL reports, i.e. <em>supervisor
+ reports</em>, <em>crash reports</em>, and <em>progress
+ reports</em>. These reports are now also printed by the default
+ logger handler started by the Kernel application. Progress
+ reports are by default stopped by the primary log level, but can
+ be enabled by setting this level to <c>info</c>, for example by
+ using the Kernel configuration
+ parameter <seealso marker="kernel:kernel_app#logger_level">
+ <c>logger_level</c></seealso>.</p>
+ <p>If the old error logger event handlers are still desired, they
+ must be added by
+ calling <c>error_logger:add_report_handler/1,2</c>.</p>
<taglist>
<tag><c>sasl_report_tty_h</c></tag>
<item>
<p>Formats and writes <em>supervisor reports</em>, <em>crash
reports</em>, and <em>progress reports</em> to <c>stdio</c>.
This error logger event handler uses
- <seealso marker="kernel:kernel_app#error_logger_format_depth">error_logger_format_depth</seealso>
- in the Kernel application to limit how much detail is
- printed in crash and supervisor reports.</p>
+ <seealso marker="kernel:kernel_app#deprecated-configuration-parameters"><c>error_logger_format_depth</c></seealso>
+ in the Kernel application to limit how much detail is printed
+ in crash and supervisor reports.</p>
</item>
<tag><c>sasl_report_file_h</c></tag>
<item>
<p>Formats and writes <em>supervisor reports</em>, <em>crash
report</em>, and <em>progress report</em> to a single file.
This error logger event handler uses
- <seealso marker="kernel:kernel_app#error_logger_format_depth">error_logger_format_depth</seealso>
- in the Kernel application to limit the details
- printed in crash and supervisor reports.</p>
- </item>
- <tag><c>log_mf_h</c></tag>
- <item>
- <p>This error logger writes <em>all</em> events sent to the
- error logger to disk. Multiple files and log rotation are
- used. For efficiency reasons, each event is written as a
- binary. For more information about this handler,
- see <seealso marker="stdlib:log_mf_h">the STDLIB Reference
- Manual</seealso>.</p>
- <p>To activate this event handler, three SASL
- configuration parameters must be set,
- <c>error_logger_mf_dir</c>, <c>error_logger_mf_maxbytes</c>,
- and <c>error_logger_mf_maxfiles</c>. The next section provides
- more information about the configuration parameters.</p>
+ <seealso marker="kernel:kernel_app#deprecated-configuration-parameters"><c>error_logger_format_depth</c></seealso>
+ in the Kernel application to limit the details printed in
+ crash and supervisor reports.</p>
</item>
</taglist>
- </section>
-
- <section>
- <title>Configuration</title>
- <p>The following configuration parameters are defined for the SASL
- application. For more information about configuration parameters, see
- <seealso marker="kernel:app"><c>app(4)</c></seealso> in Kernel.</p>
- <p>All configuration parameters are optional.</p>
+ <p>A similar behaviour, but still using the new logger API, can be
+ obtained by setting the Kernel application environment
+ variable <seealso marker="kernel:kernel_app#logger_sasl_compatible">
+ <c>logger_sasl_compatible</c></seealso> to <c>true</c>. This
+ adds a second instance of the standard Logger handler,
+ named <c>sasl</c>, which only prints the SASL reports. No SASL
+ reports are then printed by the Kernel logger handler.</p>
+ <p>The <c>sasl</c> handler is configured according to the values
+ of the following SASL application environment variables.</p>
<taglist>
<tag><c><![CDATA[sasl_error_logger = Value ]]></c></tag>
<item>
@@ -124,6 +171,25 @@
<c>sasl_error_logger</c> to error reports or progress reports,
or both. Default is <c>all</c>.</p>
</item>
+ <tag><marker id="utc_log"/><c><![CDATA[utc_log = true | false ]]></c></tag>
+ <item>
+ <p>If set to <c>true</c>, all dates in textual log outputs are
+ displayed in Universal Coordinated Time with the string
+ <c>UTC</c> appended.</p>
+ </item>
+ </taglist>
+
+ <p>The error logger event handler <c>log_mf_h</c> can also still
+ be used. This event handler writes <em>all</em> events sent to
+ the error logger to disk. Multiple files and log rotation are
+ used. For efficiency reasons, each event is written as a
+ binary. For more information about this handler,
+ see <seealso marker="stdlib:log_mf_h">the STDLIB Reference
+ Manual</seealso>.</p>
+ <p>To activate this event handler, three SASL configuration
+ parameters must be
+ set:</p>
+ <taglist>
<tag><c><![CDATA[error_logger_mf_dir = string() | false ]]></c></tag>
<item>
<p>Specifies in which directory <c>log_mf_h</c> is to store
@@ -142,55 +208,19 @@
this parameter is undefined, the <c>log_mf_h</c> handler is
not installed.</p>
</item>
- <tag><c><![CDATA[start_prg = string() ]]></c></tag>
- <item>
- <p>Specifies the program to be used when restarting the system
- during release installation. Default is
- <c>$OTP_ROOT/bin/start</c>.</p>
- </item>
- <tag><c><![CDATA[masters = [atom()] ]]></c></tag>
- <item>
- <p>Specifies the nodes used by this node to read/write release
- information. This parameter is ignored if parameter
- <c>client_directory</c> is not set.</p>
- </item>
- <tag><c><![CDATA[client_directory = string() ]]></c></tag>
- <item>
- <p>This parameter specifies the client directory at the master
- nodes. For details, see
- <seealso marker="doc/design_principles:release_handling">Release Handling</seealso>
- in <em>OTP Design Principles</em>. This parameter is
- ignored if parameter <c>masters</c> is not set.</p>
- </item>
- <tag><c><![CDATA[static_emulator = true | false ]]></c></tag>
- <item>
- <p>Indicates if the Erlang emulator is statically installed. A
- node with a static emulator cannot switch dynamically to a
- new emulator, as the executable files are written into memory
- statically. This parameter is ignored if parameters <c>masters</c>
- and <c>client_directory</c> are not set.</p>
- </item>
- <tag><c><![CDATA[releases_dir = string() ]]></c></tag>
- <item>
- <p>Indicates where the <c>releases</c> directory is located.
- The release handler writes all its files to this directory.
- If this parameter is not set, the OS environment parameter
- <c>RELDIR</c> is used. By default, this is
- <c>$OTP_ROOT/releases</c>.</p>
- </item>
- <tag><c><![CDATA[utc_log = true | false ]]></c></tag>
- <item>
- <p>If set to <c>true</c>, all dates in textual log outputs are
- displayed in Universal Coordinated Time with the string
- <c>UTC</c> appended.</p>
- </item>
</taglist>
+ <p>The new <seealso marker="kernel:logger_disk_log_h">
+ <c>logger_disk_log_h</c></seealso> might be an alternative
+ to <c>log_mf_h</c> if log rotation is desired. This does,
+ however, write the log events in clear text and not as binaries.</p>
+
</section>
<section>
<title>See Also</title>
<p><seealso marker="alarm_handler"><c>alarm_handler(3)</c></seealso>,
<seealso marker="kernel:error_logger"><c>error_logger(3)</c></seealso>,
+ <seealso marker="kernel:logger"><c>logger(3)</c></seealso>,
<seealso marker="stdlib:log_mf_h"><c>log_mf_h(3)</c></seealso>,
<seealso marker="rb"><c>rb(3)</c></seealso>,
<seealso marker="release_handler"><c>release_handler(3)</c></seealso>,
diff --git a/lib/sasl/doc/src/systools.xml b/lib/sasl/doc/src/systools.xml
index e7c3c499da..6facb8ddae 100644
--- a/lib/sasl/doc/src/systools.xml
+++ b/lib/sasl/doc/src/systools.xml
@@ -30,7 +30,7 @@
<date></date>
<rev></rev>
</header>
- <module>systools</module>
+ <module since="">systools</module>
<modulesummary>A Set of Release Handling Tools</modulesummary>
<description>
<p>This module contains functions to generate boot scripts
@@ -40,8 +40,8 @@
<funcs>
<func>
- <name>make_relup(Name, UpFrom, DownTo) -> Result</name>
- <name>make_relup(Name, UpFrom, DownTo, [Opt]) -> Result</name>
+ <name since="">make_relup(Name, UpFrom, DownTo) -> Result</name>
+ <name since="">make_relup(Name, UpFrom, DownTo, [Opt]) -> Result</name>
<fsummary>Generates a release upgrade file <c>relup</c>.</fsummary>
<type>
<v>Name = string()</v>
@@ -136,8 +136,8 @@
</func>
<func>
- <name>make_script(Name) -> Result</name>
- <name>make_script(Name, [Opt]) -> Result</name>
+ <name since="">make_script(Name) -> Result</name>
+ <name since="">make_script(Name, [Opt]) -> Result</name>
<fsummary>Generates a boot script <c>.script/.boot</c>.</fsummary>
<type>
<v>Name = string()</v>
@@ -263,8 +263,8 @@
</func>
<func>
- <name>make_tar(Name) -> Result</name>
- <name>make_tar(Name, [Opt]) -> Result</name>
+ <name since="">make_tar(Name) -> Result</name>
+ <name since="">make_tar(Name, [Opt]) -> Result</name>
<fsummary>Creates a release package.</fsummary>
<type>
<v>Name = string()</v>
@@ -349,10 +349,11 @@ myapp-1/ebin/myapp.app
the release version as specified in <c>Name.rel</c>.</p>
<p><c>releases/RelVsn</c> contains the boot script
<c>Name.boot</c> renamed to <c>start.boot</c> and, if found,
- the files <c>relup</c> and <c>sys.config</c>. These files
+ the files <c>relup</c> and <c>sys.config</c> or <c>sys.config.src</c>. These files
are searched for in the same directory as <c>Name.rel</c>,
in the current working directory, and in any directories
- specified using option <c>path</c>.</p>
+ specified using option <c>path</c>. In the case of <c>sys.config</c>
+ it is not included if <c>sys.config.src</c> is found.</p>
<p>If the release package is to contain a new Erlang runtime
system, the <c>bin</c> directory of the specified runtime
system <c>{erts,Dir}</c> is copied to <c>erts-ErtsVsn/bin</c>.</p>
@@ -368,7 +369,7 @@ myapp-1/ebin/myapp.app
</func>
<func>
- <name>script2boot(File) -> ok | error</name>
+ <name since="">script2boot(File) -> ok | error</name>
<fsummary>Generates a binary version of a boot script.</fsummary>
<type>
<v>File = string()</v>
@@ -397,4 +398,3 @@ myapp-1/ebin/myapp.app
<seealso marker="script"><c>script(4)</c></seealso></p>
</section>
</erlref>
-
diff --git a/lib/sasl/src/Makefile b/lib/sasl/src/Makefile
index ac7ee51100..fd62588f5c 100644
--- a/lib/sasl/src/Makefile
+++ b/lib/sasl/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2016. All Rights Reserved.
+# Copyright Ericsson AB 1996-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -37,7 +37,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/sasl-$(VSN)
MODULES= alarm_handler sasl sasl_report \
sasl_report_file_h sasl_report_tty_h format_lib_supp \
misc_supp rb rb_format_supp release_handler \
- release_handler_1 si si_sasl_supp systools \
+ release_handler_1 systools \
systools_make systools_rc systools_relup systools_lib \
erlsrv
@@ -61,7 +61,11 @@ TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) $(APP_TARGET) $(APPUP_TARGET)
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
+
ERL_COMPILE_FLAGS += -I../../stdlib/include -Werror
+ifeq ($(USE_ESOCK), yes)
+ERL_COMPILE_FLAGS += -DUSE_ESOCK=true
+endif
# ----------------------------------------------------
diff --git a/lib/sasl/src/erlsrv.erl b/lib/sasl/src/erlsrv.erl
index 29d40d362f..e0bbd37ee3 100644
--- a/lib/sasl/src/erlsrv.erl
+++ b/lib/sasl/src/erlsrv.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -34,7 +34,7 @@ erlsrv(EVer) ->
filename:join([Root, "erts-" ++ EVer, "bin", "erlsrv.exe"]).
current_version() ->
- hd(string:tokens(erlang:system_info(version),"_ ")).
+ hd(string:lexemes(erlang:system_info(version),"_ ")).
%%% Returns {ok, Output} | failed | {error, Reason}
run_erlsrv(Command) ->
@@ -107,7 +107,7 @@ get_all_services() ->
[];
{ok, [_H|T]} ->
F = fun(X) ->
- hd(string:tokens(X,"\t "))
+ hd(string:lexemes(X,"\t "))
end,
lists:map(F,T);
_ ->
@@ -191,8 +191,8 @@ get_service(EVer, ServiceName) ->
%%% have in the environment list...
EnvParts = lists:map(
fun(S) ->
- X = string:strip(S,left,$\t),
- case hd(string:tokens(X,"=")) of
+ X = string:trim(S, leading, "$\t"),
+ case hd(string:lexemes(X,"=")) of
X ->
%% Can this happen?
{X,""};
@@ -371,7 +371,7 @@ split_arglist([H|T]) ->
parse_arglist(Str) ->
lists:reverse(parse_arglist(Str,[])).
parse_arglist(Str,Accum) ->
- Stripped = string:strip(Str,left),
+ Stripped = string:trim(Str, leading),
case length(Stripped) of
0 ->
Accum;
@@ -432,14 +432,9 @@ split_by_env(Data) ->
splitline(Line) ->
- case string:chr(Line,$:) of
- 0 ->
+ case string:split(Line, ":") of
+ [_] ->
{Line, ""};
- N ->
- case length(string:substr(Line,N)) of
- 1 ->
- {string:substr(Line,1,N-1),""};
- _ ->
- {string:substr(Line,1,N-1),string:substr(Line,N+2)}
- end
+ [N, V] ->
+ {N, string:slice(V, 1)}
end.
diff --git a/lib/sasl/src/format_lib_supp.erl b/lib/sasl/src/format_lib_supp.erl
index 00ce1b4e33..2d37dfe117 100644
--- a/lib/sasl/src/format_lib_supp.erl
+++ b/lib/sasl/src/format_lib_supp.erl
@@ -102,13 +102,13 @@ print_newlines(Device, N) when N > 0 ->
print_one_line(Device, Line, Key, Value) ->
Modifier = misc_supp:modifier(Device),
StrKey = term_to_string(Key,Modifier),
- KeyLen = lists:min([length(StrKey), Line]),
+ KeyLen = lists:min([string:length(StrKey), Line]),
ValueLen = Line - KeyLen,
Format1 = lists:concat(["~-", KeyLen, Modifier, "s"]),
Format2 = lists:concat(["~", ValueLen, Modifier, "s~n"]),
io:format(Device, Format1, [StrKey]),
Try = term_to_string(Value,Modifier),
- Length = length(Try),
+ Length = string:length(Try),
if
Length < ValueLen ->
io:format(Device, Format2, [Try]);
@@ -119,7 +119,7 @@ print_one_line(Device, Line, Key, Value) ->
end.
term_to_string(Value,Modifier) ->
- lists:flatten(io_lib:format(get_format(Value,Modifier), [Value])).
+ io_lib:format(get_format(Value,Modifier), [Value]).
get_format([],_) ->
"~p";
diff --git a/lib/sasl/src/rb.erl b/lib/sasl/src/rb.erl
index 6595d29a9c..bef4268d3a 100644
--- a/lib/sasl/src/rb.erl
+++ b/lib/sasl/src/rb.erl
@@ -586,14 +586,14 @@ find_widths([], _Modifier, DescrWidth, DateWidth, Data) ->
{DescrWidth+1, DateWidth+1, lists:reverse(Data)};
find_widths([H|T], Modifier, DescrWidth, DateWidth, Data) ->
DescrTerm = element(3,H),
- Descr = lists:flatten(io_lib:format("~"++Modifier++"w", [DescrTerm])),
- DescrTry = length(Descr),
+ Descr = io_lib:format("~"++Modifier++"w", [DescrTerm]),
+ DescrTry = string:length(Descr),
NewDescrWidth =
if
DescrTry > DescrWidth -> DescrTry;
true -> DescrWidth
end,
- DateTry = length(element(4, H)),
+ DateTry = string:length(element(4, H)),
NewDateWitdh =
if
DateTry > DateWidth -> DateTry;
@@ -890,7 +890,7 @@ read_rep(Fd, FilePosition, Device, Abort, Log) ->
handle_bad_form(Date, Msg, Device, Abort, Log) ->
io:format("rb: ERROR! A report on bad form was encountered. " ++
- "It can not be printed to the log.~n~n"),
+ "It cannot be printed to the log.~n~n"),
io:format("Details:~n~p ~tp~n~n", [Date,Msg]),
case {Abort,Device,open_log_file(Log)} of
{true,standard_io,standard_io} ->
diff --git a/lib/sasl/src/rb_format_supp.erl b/lib/sasl/src/rb_format_supp.erl
index 1eda43dae4..b5b7aba151 100644
--- a/lib/sasl/src/rb_format_supp.erl
+++ b/lib/sasl/src/rb_format_supp.erl
@@ -108,7 +108,7 @@ print(Date, Report, Device) ->
format_h(Line, Header, Pid, Date) ->
NHeader = lists:flatten(io_lib:format("~s ~w", [Header, Pid])),
- DateLen = length(Date),
+ DateLen = string:length(Date),
HeaderLen = Line - DateLen,
Format = lists:concat(["~-", HeaderLen, "s~", DateLen, "s"]),
io_lib:format(Format, [NHeader, Date]).
diff --git a/lib/sasl/src/release_handler.erl b/lib/sasl/src/release_handler.erl
index d0a7c7332d..48feac1a21 100644
--- a/lib/sasl/src/release_handler.erl
+++ b/lib/sasl/src/release_handler.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -420,7 +420,7 @@ upgrade_app(App, NewDir) ->
%% located in the ebin dir of the _current_ version
%%-----------------------------------------------------------------
downgrade_app(App, OldDir) ->
- case string:tokens(filename:basename(OldDir), "-") of
+ case string:lexemes(filename:basename(OldDir), "-") of
[_AppS, OldVsn] ->
downgrade_app(App, OldVsn, OldDir);
_ ->
@@ -1052,8 +1052,8 @@ new_emulator_make_tmp_release(CurrentRelease,ToRelease,RelDir,Opts,Masters) ->
ToVsn = ToRelease#release.vsn,
TmpVsn = ?tmp_vsn(CurrentVsn),
case get_base_libs(ToRelease#release.libs) of
- {ok,{Kernel,Stdlib,Sasl}=BaseLibs,_} ->
- case get_base_libs(ToRelease#release.libs) of
+ {ok,{Kernel,Stdlib,Sasl},_} ->
+ case get_base_libs(CurrentRelease#release.libs) of
{ok,_,RestLibs} ->
TmpErtsVsn = ToRelease#release.erts_vsn,
TmpLibs = [Kernel,Stdlib,Sasl|RestLibs],
@@ -1062,7 +1062,7 @@ new_emulator_make_tmp_release(CurrentRelease,ToRelease,RelDir,Opts,Masters) ->
libs = TmpLibs,
status = unpacked},
new_emulator_make_hybrid_boot(CurrentVsn,ToVsn,TmpVsn,
- BaseLibs,RelDir,Opts,Masters),
+ RelDir,Opts,Masters),
new_emulator_make_hybrid_config(CurrentVsn,ToVsn,TmpVsn,
RelDir,Masters),
{TmpVsn,TmpRelease};
@@ -1095,7 +1095,7 @@ get_base_libs([],_Kernel,_Stdlib,undefined,_Rest) ->
get_base_libs([],Kernel,Stdlib,Sasl,Rest) ->
{ok,{Kernel,Stdlib,Sasl},lists:reverse(Rest)}.
-new_emulator_make_hybrid_boot(CurrentVsn,ToVsn,TmpVsn,BaseLibs,RelDir,Opts,Masters) ->
+new_emulator_make_hybrid_boot(CurrentVsn,ToVsn,TmpVsn,RelDir,Opts,Masters) ->
FromBootFile = filename:join([RelDir,CurrentVsn,"start.boot"]),
ToBootFile = filename:join([RelDir,ToVsn,"start.boot"]),
TmpBootFile = filename:join([RelDir,TmpVsn,"start.boot"]),
@@ -1103,11 +1103,7 @@ new_emulator_make_hybrid_boot(CurrentVsn,ToVsn,TmpVsn,BaseLibs,RelDir,Opts,Maste
Args = [ToVsn,Opts],
{ok,FromBoot} = read_file(FromBootFile,Masters),
{ok,ToBoot} = read_file(ToBootFile,Masters),
- {{_,_,KernelPath},{_,_,StdlibPath},{_,_,SaslPath}} = BaseLibs,
- Paths = {filename:join(KernelPath,"ebin"),
- filename:join(StdlibPath,"ebin"),
- filename:join(SaslPath,"ebin")},
- case systools_make:make_hybrid_boot(TmpVsn,FromBoot,ToBoot,Paths,Args) of
+ case systools_make:make_hybrid_boot(TmpVsn,FromBoot,ToBoot,Args) of
{ok,TmpBoot} ->
write_file(TmpBootFile,TmpBoot,Masters);
{error,Reason} ->
@@ -1124,7 +1120,7 @@ new_emulator_make_hybrid_config(CurrentVsn,ToVsn,TmpVsn,RelDir,Masters) ->
{ok,[FC]} ->
FC;
{error,Error1} ->
- io:format("Warning: ~w can not read ~tp: ~tp~n",
+ io:format("Warning: ~w cannot read ~tp: ~tp~n",
[?MODULE,FromFile,Error1]),
[]
end,
@@ -1134,7 +1130,7 @@ new_emulator_make_hybrid_config(CurrentVsn,ToVsn,TmpVsn,RelDir,Masters) ->
{ok,[ToConfig]} ->
[lists:keyfind(App,1,ToConfig) || App <- [kernel,stdlib,sasl]];
{error,Error2} ->
- io:format("Warning: ~w can not read ~tp: ~tp~n",
+ io:format("Warning: ~w cannot read ~tp: ~tp~n",
[?MODULE,ToFile,Error2]),
[false,false,false]
end,
@@ -1174,8 +1170,8 @@ new_emulator_rm_tmp_release(_,_,_,_,Releases,_) ->
%% Rename the tempoarary service (for erts ugprade) to the real ToVsn
rename_tmp_service(EVsn,TmpVsn,NewVsn) ->
- FromName = hd(string:tokens(atom_to_list(node()),"@")) ++ "_" ++ TmpVsn,
- ToName = hd(string:tokens(atom_to_list(node()),"@")) ++ "_" ++ NewVsn,
+ FromName = hd(string:lexemes(atom_to_list(node()),"@")) ++ "_" ++ TmpVsn,
+ ToName = hd(string:lexemes(atom_to_list(node()),"@")) ++ "_" ++ NewVsn,
case erlsrv:get_service(EVsn,ToName) of
{error, _Error} ->
ok;
@@ -1207,9 +1203,9 @@ rename_service(EVsn,FromName,ToName) ->
%%% in which case we try to rename the old service to the new name and try
%%% to update heart's view of what service we are really running.
do_make_services_permanent(PermanentVsn,Vsn, PermanentEVsn, EVsn) ->
- PermName = hd(string:tokens(atom_to_list(node()),"@"))
+ PermName = hd(string:lexemes(atom_to_list(node()),"@"))
++ "_" ++ PermanentVsn,
- Name = hd(string:tokens(atom_to_list(node()),"@"))
+ Name = hd(string:lexemes(atom_to_list(node()),"@"))
++ "_" ++ Vsn,
case erlsrv:get_service(EVsn,Name) of
{error, _Error} ->
@@ -1296,7 +1292,7 @@ do_make_permanent(#state{releases = Releases,
do_back_service(OldVersion, CurrentVersion,OldEVsn,CurrentEVsn) ->
- NN = hd(string:tokens(atom_to_list(node()),"@")),
+ NN = hd(string:lexemes(atom_to_list(node()),"@")),
OldName = NN ++ "_" ++ OldVersion,
CurrentName = NN ++ "_" ++ CurrentVersion,
UpdData = case erlsrv:get_service(CurrentEVsn,CurrentName) of
@@ -1385,7 +1381,7 @@ do_remove_service(Vsn) ->
%% Very unconditionally remove the service.
%% Note that the service could already have been removed when
%% making another release permanent.
- ServiceName = hd(string:tokens(atom_to_list(node()),"@"))
+ ServiceName = hd(string:lexemes(atom_to_list(node()),"@"))
++ "_" ++ Vsn,
case erlsrv:get_service(ServiceName) of
{error, _Error} ->
@@ -1670,9 +1666,9 @@ flush() ->
prepare_restart_nt(#release{erts_vsn = EVsn, vsn = Vsn},
#release{erts_vsn = PermEVsn, vsn = PermVsn},
DataFileName) ->
- CurrentServiceName = hd(string:tokens(atom_to_list(node()),"@"))
+ CurrentServiceName = hd(string:lexemes(atom_to_list(node()),"@"))
++ "_" ++ PermVsn,
- FutureServiceName = hd(string:tokens(atom_to_list(node()),"@"))
+ FutureServiceName = hd(string:lexemes(atom_to_list(node()),"@"))
++ "_" ++ Vsn,
CurrentService = case erlsrv:get_service(PermEVsn,CurrentServiceName) of
{error, _} = Error1 ->
diff --git a/lib/sasl/src/release_handler_1.erl b/lib/sasl/src/release_handler_1.erl
index ca97515299..bf18691687 100644
--- a/lib/sasl/src/release_handler_1.erl
+++ b/lib/sasl/src/release_handler_1.erl
@@ -147,7 +147,7 @@ split_instructions([], Before) ->
%% If PrePurgeMethod == soft_purge, the function will succeed
%% only if there is no process running old code of any of the
%% modules. Else it will throw {error,Mod}, where Mod is the
-%% first module found that can not be soft_purged.
+%% first module found that cannot be soft_purged.
%%
%% If PrePurgeMethod == brutal_purge, the function will
%% always succeed and return a list of all modules that are
diff --git a/lib/sasl/src/sasl.app.src b/lib/sasl/src/sasl.app.src
index b7bb9133ff..293af504df 100644
--- a/lib/sasl/src/sasl.app.src
+++ b/lib/sasl/src/sasl.app.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,8 +32,6 @@
sasl_report,
sasl_report_tty_h,
sasl_report_file_h,
- si,
- si_sasl_supp,
systools,
systools_make,
systools_rc,
@@ -42,9 +40,8 @@
]},
{registered, [sasl_sup, alarm_handler, release_handler]},
{applications, [kernel, stdlib]},
- {env, [{sasl_error_logger, tty},
- {errlog_type, all}]},
+ {env, []},
{mod, {sasl, []}},
{runtime_dependencies, ["tools-2.6.14","stdlib-3.4","kernel-5.3",
- "erts-9.0"]}]}.
+ "erts-10.2"]}]}.
diff --git a/lib/sasl/src/sasl.appup.src b/lib/sasl/src/sasl.appup.src
index dcb568c413..22a9027b7c 100644
--- a/lib/sasl/src/sasl.appup.src
+++ b/lib/sasl/src/sasl.appup.src
@@ -1,7 +1,7 @@
%% -*- erlang -*-
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -16,13 +16,24 @@
%% limitations under the License.
%%
%% %CopyrightEnd%
+%%
+%% We allow upgrade from, and downgrade to all previous
+%% versions from the following OTP releases:
+%% - OTP 21
+%% - OTP 22
+%%
+%% We also allow upgrade from, and downgrade to all
+%% versions that have branched off from the above
+%% stated previous versions.
+%%
{"%VSN%",
- %% Up from - max one major revision back
- [{<<"3\\.0((\\.[0-3])(\\.[0-9]+)*)?">>,[restart_new_emulator]}, % OTP-19.*
- {<<"3\\.0\\.[4-9](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-20.0*
- {<<"3\\.1(\\.[0-9]+)*">>,[restart_new_emulator]}], % OTP-20.1*
- %% Down to - max one major revision back
- [{<<"3\\.0((\\.[0-3])(\\.[0-9]+)*)?">>,[restart_new_emulator]}, % OTP-19.*
- {<<"3\\.0\\.[4-9](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-20.0*
- {<<"3\\.1(\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-20.1*
-}.
+ [{<<"^3\\.2$">>,[restart_new_emulator]},
+ {<<"^3\\.2\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^3\\.2\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^3\\.3$">>,[restart_new_emulator]},
+ {<<"^3\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}],
+ [{<<"^3\\.2$">>,[restart_new_emulator]},
+ {<<"^3\\.2\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^3\\.2\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^3\\.3$">>,[restart_new_emulator]},
+ {<<"^3\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}]}.
diff --git a/lib/sasl/src/sasl.erl b/lib/sasl/src/sasl.erl
index 24afaee183..0c68c93dc6 100644
--- a/lib/sasl/src/sasl.erl
+++ b/lib/sasl/src/sasl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -31,45 +31,52 @@
%%%-----------------------------------------------------------------
-behaviour(application).
--record(state, {sasl_error_logger, error_logger_mf}).
+-record(state, {sasl_logger, error_logger_mf}).
start(_, []) ->
- Handler = get_sasl_error_logger(),
- Type = get_sasl_error_logger_type(),
+ {Dest,Level} = get_logger_info(),
Mf = get_error_logger_mf(),
- add_sasl_error_logger(Handler, Type),
+ add_sasl_logger(Dest, Level),
add_error_logger_mf(Mf),
- State = #state{sasl_error_logger = Handler, error_logger_mf = Mf},
+ State = #state{sasl_logger = Dest, error_logger_mf = Mf},
case supervisor:start_link({local, sasl_sup}, sasl, []) of
{ok, Pid} -> {ok, Pid, State};
Error -> Error
end.
stop(State) ->
- delete_sasl_error_logger(State#state.sasl_error_logger),
+ delete_sasl_logger(State#state.sasl_logger),
delete_error_logger_mf(State#state.error_logger_mf).
%%-----------------------------------------------------------------
%% Internal functions
%%-----------------------------------------------------------------
-get_sasl_error_logger() ->
+get_logger_info() ->
+ case application:get_env(kernel, logger_sasl_compatible) of
+ {ok,true} ->
+ {get_logger_dest(),get_logger_level()};
+ _ ->
+ {std,undefined}
+ end.
+
+get_logger_dest() ->
case application:get_env(sasl, sasl_error_logger) of
- {ok, false} -> undefined;
- {ok, tty} -> tty;
- {ok, {file, File}} when is_list(File) -> {file, File, [write]};
- {ok, {file, File, Modes}} when is_list(File), is_list(Modes) ->
- {file, File, Modes};
- {ok, Bad} -> exit({bad_config, {sasl, {sasl_error_logger, Bad}}});
- _ -> undefined
+ {ok, false} -> undefined;
+ {ok, tty} -> standard_io;
+ {ok, {file, File}} when is_list(File) -> {file, File};
+ {ok, {file, File, Modes}} when is_list(File), is_list(Modes) ->
+ {file, File, Modes};
+ {ok, Bad} -> exit({bad_config, {sasl, {sasl_logger_dest, Bad}}});
+ undefined -> standard_io
end.
-get_sasl_error_logger_type() ->
+get_logger_level() ->
case application:get_env(sasl, errlog_type) of
- {ok, error} -> error;
- {ok, progress} -> progress;
- {ok, all} -> all;
- {ok, Bad} -> exit({bad_config, {sasl, {errlog_type, Bad}}});
- _ -> all
+ {ok, error} -> error;
+ {ok, progress} -> info;
+ {ok, all} -> info;
+ {ok, Bad} -> exit({bad_config, {sasl, {errlog_type, Bad}}});
+ _ -> info
end.
get_error_logger_mf() ->
@@ -119,26 +126,36 @@ get_mf_maxf() ->
{ok, Bad} -> exit({bad_config, {sasl, {error_logger_mf_maxfiles, Bad}}})
end.
-add_sasl_error_logger(undefined, _Type) -> ok;
-add_sasl_error_logger(Handler, Type) ->
- error_logger:add_report_handler(mod(Handler), args(Handler, Type)).
-
-delete_sasl_error_logger(undefined) -> ok;
-delete_sasl_error_logger(Type) ->
- error_logger:delete_report_handler(mod(Type)).
-
-mod(tty) -> sasl_report_tty_h;
-mod({file, _File, _Modes}) -> sasl_report_file_h.
-
-args({file, File, Modes}, Type) -> {File, Modes, type(Type)};
-args(_, Type) -> type(Type).
-
-type(error) -> error;
-type(progress) -> progress;
-type(_) -> all.
+add_sasl_logger(undefined, _Level) -> ok;
+add_sasl_logger(std, undefined) -> ok;
+add_sasl_logger(Dest, Level) ->
+ FC = #{legacy_header=>true,
+ single_line=>false},
+ case Level of
+ info -> allow_progress();
+ _ -> ok
+ end,
+ ok = logger:add_handler(sasl,logger_std_h,
+ #{level=>Level,
+ filter_default=>stop,
+ filters=>
+ [{remote_gl,
+ {fun logger_filters:remote_gl/2,stop}},
+ {sasl_domain,
+ {fun logger_filters:domain/2,
+ {log,equal,[otp,sasl]}}}],
+ config=>#{type=>Dest},
+ formatter=>{logger_formatter,FC}}).
+
+delete_sasl_logger(undefined) -> ok;
+delete_sasl_logger(std) -> ok;
+delete_sasl_logger(_Type) ->
+ _ = logger:remove_handler(sasl),
+ ok.
add_error_logger_mf(undefined) -> ok;
add_error_logger_mf({Dir, MaxB, MaxF}) ->
+ allow_progress(),
error_logger:add_report_handler(
log_mf_h, log_mf_h:init(Dir, MaxB, MaxF, fun pred/1)).
@@ -149,6 +166,13 @@ delete_error_logger_mf(_) ->
pred({_Type, GL, _Msg}) when node(GL) =/= node() -> false;
pred(_) -> true.
+allow_progress() ->
+ #{level:=PL} = logger:get_primary_config(),
+ case logger:compare_levels(info,PL) of
+ lt -> ok = logger:set_primary_config(level,info);
+ _ -> ok
+ end.
+
%%%-----------------------------------------------------------------
%%% supervisor functionality
%%%-----------------------------------------------------------------
diff --git a/lib/sasl/src/sasl_report_file_h.erl b/lib/sasl/src/sasl_report_file_h.erl
index d3b5c7dc0d..05d6acd076 100644
--- a/lib/sasl/src/sasl_report_file_h.erl
+++ b/lib/sasl/src/sasl_report_file_h.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/sasl/src/si.erl b/lib/sasl/src/si.erl
deleted file mode 100644
index 275c6d508b..0000000000
--- a/lib/sasl/src/si.erl
+++ /dev/null
@@ -1,169 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%-----------------------------------------------------------------
-%% l(format_lib_supp), l(si_sasl_supp), l(si), l(si_ms_aos_supp), l(misc_supp).
-%% c(format_lib_supp), c(si_sasl_supp), c(si), c(si_ms_aos_supp), c(misc_supp).
-%%-----------------------------------------------------------------
-
-
-%%--------------------------------------------------
-%% Description:
-%% Status Inspection, main module.
-%%--------------------------------------------------
-
--module(si).
-
-
-%% External exports
--export([h/0, help/0, start/0, start/1, start_log/1, stop_log/0,
- abbrevs/0, pi/1, pi/2, pi/3, pi/4, ppi/1, ppi/3, stop/0]).
-
-%% Internal exports
--export([pi_impl/2, test/0]).
-
-
-%%--------------------------------------------------
-%% Table of contents
-%% 1. Interface
-%% 2. Implementation
-
-
--import(si_sasl_supp, [status_info/1, make_pid/1, p/1]).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% 1. Interface
-%%--------------------------------------------------
-
-h() -> print_help().
-help() -> print_help().
-
-start() -> si_sasl_supp:start().
-start(Options) -> si_sasl_supp:start(Options).
-
-stop() -> si_sasl_supp:stop().
-
-start_log(FileName) ->
- si_sasl_supp:start_log(FileName).
-
-stop_log() ->
- si_sasl_supp:stop_log().
-
-%%%-----------------------------------------------------------------
-%%% All functions can be called with an option 'normal' or 'all';
-%%% default is 'normal'.
-%%%-----------------------------------------------------------------
-
-abbrevs() ->
- io:format("~p", [lists:append(si_sasl_supp:process_abbrevs(),
- process_abbrevs())]).
-
-%%-----------------------------------------------------------------
-%% Process Info that tries to determine processtype (=Module), then
-%% it uses this Module:format_info to format data from status_info/1.
-%%-----------------------------------------------------------------
-pi(XPid) ->
- si_sasl_supp:si_exec({si, pi_impl}, [normal, XPid]).
-
-pi(Opt, XPid) ->
- si_sasl_supp:si_exec({si, pi_impl}, [si_sasl_supp:valid_opt(Opt), XPid]).
-
-pi(A, B, C) when is_integer(A), is_integer(B), is_integer(C) ->
- si_sasl_supp:si_exec({si, pi_impl}, [normal, {A, B, C}]).
-
-pi(Opt, A, B, C) when is_integer(A), is_integer(B), is_integer(C) ->
- si_sasl_supp:si_exec({si, pi_impl}, [si_sasl_supp:valid_opt(Opt), {A, B, C}]).
-
-%%-----------------------------------------------------------------
-%% Pretty print Process_Info.
-%%-----------------------------------------------------------------
-ppi(XPid) ->
- si_sasl_supp:ppi(XPid).
-ppi(A, B, C) ->
- si_sasl_supp:ppi(A, B, C).
-
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% 2. Implementation
-%%--------------------------------------------------
-
-print_help() ->
- p("~nStatus Inspection tool - usage"),
- p("=============================="),
- p(" For all these functions, Opt is an optional argument"),
- p(" which can be 'normal' or 'all'; default is 'normal'."),
- p(" If 'all', all information will be printed."),
- p(" A Pid can be: \"<A.B.C>\", {A, B, C}, B, a registered_name or an abbrev."),
- p("ANY PROCESS"),
- p("si:pi([Opt,] Pid) - Formatted information about any process that"),
- p(" SI recognises."),
- p("si:pi([Opt,] A,B,C) - Same as si:pi({A, B, C})."),
- p("si:ppi(Pid) - Pretty formating of process_info."),
- p(" Works for any process."),
- p("MISC"),
- p("si:abbrevs() - Lists valid abbreviations."),
- p("si:start_log(Filename) - Logging to file."),
- p("si:stop_log()"),
- p("si:start() - Starts Status Inspection (the si_server)."),
- p("si:start([{start_log, FileName}])"),
- p("si:stop() - Shut down SI.").
-
-
-%%--------------------------------------------------
-%% Copied (and modified) code from si_sasl_supp.
-%%--------------------------------------------------
-pi_impl(Opt, XPid) ->
- case make_pid(try_local_expand_abbrev(XPid)) of
- Pid when is_pid(Pid) ->
- case status_info(Pid) of
- {status_info, Pid, {module, Module}, Data} ->
- si_sasl_supp:do_best_printout(Opt, Pid, Module, Data);
- {error, Reason} ->
- _ = si_sasl_supp:ppi_impl(Pid),
- {error, {"can not get status info from process:",
- XPid,
- Reason}};
- Else ->
- {error, {"unknown status info", Else}}
- end;
- {error, Reason} ->
- {error, Reason}
- end.
-
-%%--------------------------------------------------
-%% Functions for handling of abbreviations
-%%--------------------------------------------------
-try_local_expand_abbrev(Abbrev) ->
- case si_sasl_supp:expand_abbrev(Abbrev, process_abbrevs()) of
- {value, {_, RealName}} -> RealName;
- _ -> Abbrev
- end.
-
-process_abbrevs() ->
- [].
-
-%% Test get_status_info/format_status_info for all implemented servers.
-test() ->
- lists:foreach(fun test_all_registered/1,
- lists:append(si_sasl_supp:process_abbrevs(),
- process_abbrevs())).
-
-test_all_registered({Al, _Ful}) ->
- si:pi(all, Al).
diff --git a/lib/sasl/src/si_sasl_supp.erl b/lib/sasl/src/si_sasl_supp.erl
deleted file mode 100644
index cce628f8c4..0000000000
--- a/lib/sasl/src/si_sasl_supp.erl
+++ /dev/null
@@ -1,380 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
--module(si_sasl_supp).
-
--behaviour(gen_server).
-
-%%%---------------------------------------------------------------------------
-%%% Description:
-%%% This module contains the BOS specific parts of the Status Inspection Tool.
-%%%---------------------------------------------------------------------------
-
-
-%% user interface
--export([h/0, help/0, start_log/1, stop_log/0, abbrevs/0, pi/1, pi/2, pi/3,
- pi/4, ppi/1, ppi/3, start/0, start/1, stop/0, start_link/1]).
-
-%% intermodule exports
--export([make_pid/1, make_pid/3, process_abbrevs/0, expand_abbrev/2,
- status_info/1, valid_opt/1, p/1, do_best_printout/4,
- si_exec/2, handle_call/3, terminate/2]).
-
-%% exports for use within module
--export([init/1, start_log_impl/1, pi_impl/2, ppi_impl/1]).
-
-%% other gen_server callbacks (not used)
--export([handle_cast/2, handle_info/2, code_change/3]).
-
-%%--------------------------------------------------
-%% Table of contents
-%% 1. Interface
-%% 2. SI - Server
-%% 3. Code
-%% 4. Selectors
-%%--------------------------------------------------
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% 1. Interface
-%% -----------------------------------------------------
-
-h() -> print_help().
-help() -> print_help().
-
-si_exec(Fun, Args) -> call({si_exec, Fun, Args}).
-
-start_log(FileName) ->
- call({start_log, FileName}).
-
-stop_log() ->
- call(stop_log).
-
-abbrevs() ->
- io:format("~p", [process_abbrevs()]).
-
-%%-----------------------------------------------------------------
-%% All functions can be called with an option 'normal' or 'all';
-%% default is 'normal'.
-%%-----------------------------------------------------------------
-%% Process Info that tries to determine processtype (=Module), then
-%% it uses this Module:format_info to format data from status_info/1.
-%%-----------------------------------------------------------------
-pi(XPid) ->
- si_exec({si_sasl_supp, pi_impl}, [normal, XPid]).
-
-pi(Opt, XPid) ->
- si_exec({si_sasl_supp, pi_impl}, [valid_opt(Opt), XPid]).
-
-pi(A, B, C) when is_integer(A), is_integer(B), is_integer(C) ->
- si_exec({si_sasl_supp, pi_impl}, [normal, {A, B, C}]).
-
-pi(Opt, A, B, C) when is_integer(A), is_integer(B), is_integer(C) ->
- si_exec({si_sasl_supp, pi_impl}, [valid_opt(Opt), {A, B, C}]).
-
-%%-----------------------------------------------------------------
-%% Pretty print Process_Info.
-%%-----------------------------------------------------------------
-ppi(XPid) ->
- case whereis(si_server) of
- undefined -> % You can always run ppi.
- ppi_impl(XPid); % if si_server is down, use standard_io
- _ ->
- si_exec({si_sasl_supp, ppi_impl}, [XPid])
- end.
-ppi(A, B, C) ->
- case whereis(si_server) of
- undefined -> % You can always run ppi.
- ppi_impl({A, B, C}); % if si_server is down, use standard_io
- _ ->
- si_exec({si_sasl_supp, ppi_impl}, [{A, B, C}])
- end.
-
-
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% 2. SI - Server
-%%--------------------------------------------------
--record(state, {}).
-
-start() -> start([]).
-start(Options) ->
- supervisor:start_child(sasl_sup,
- {si_server, {si_sasl_supp, start_link, [Options]},
- temporary, brutal_kill, worker, [si_sasl_supp]}).
-
-start_link(_Options) ->
- gen_server:start_link({local, si_server}, si_sasl_supp, [], []).
-
-stop() ->
- call(stop),
- supervisor:delete_child(sasl_sup, si_server).
-
-
-init(Options) ->
- process_flag(trap_exit, true),
- start_log_impl(get_option(Options, start_log, standard_io)),
- {ok, #state{}}.
-
-%%-----------------------------------------------------------------
-%% If an error occurs and we're logging to file: write the error
-%% to the file.
-%% Always return the error.
-%% The only data held by the si_server is the device in its process dictionary.
-%%-----------------------------------------------------------------
-handle_call({si_exec, Fun, Args}, _From, State) ->
- case catch apply(Fun, Args) of
- {'EXIT', Reason} ->
- print_error(get(device),
- "SI internal error. Reason: ~w~n",
- [Reason]),
- {stop, shutdown, {internal_error, Reason}, State};
- {error, Reason} ->
- print_error(get(device), "~nSI error: ~w~n", [Reason]),
- {reply, {error, Reason}, State};
- X ->
- {reply, X, State}
- end;
-handle_call({start_log, FileName}, _From, State) ->
- start_log_impl(FileName),
- {reply, ok, State};
-handle_call(stop_log, _From, State) ->
- start_log_impl(standard_io),
- {reply, ok, State};
-handle_call(stop, _From, State) ->
- start_log_impl(standard_io),
- {stop, normal, stopped, State}.
-
-terminate(_Reason, _State) ->
- _ = close_device(get(device)),
- ok.
-
-handle_cast(_Msg, State) ->
- {noreply, State}.
-handle_info(_Info, State) ->
- {noreply, State}.
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-close_device(standard_io) -> ok;
-close_device(Fd) -> file:close(Fd).
-
-print_error(standard_io, _, _) -> ok;
-print_error(Device, Format, Args) ->
- io:format(Device, Format, Args).
-
-get_option(Options, Key, Default) ->
- case lists:keysearch(Key, 1, Options) of
- {value, {_Key, Value}} -> Value;
- _ -> Default
- end.
-
-open_log_file(undefined, NewFile) ->
- open_log_file(NewFile);
-open_log_file(standard_io, NewFile) ->
- open_log_file(NewFile);
-open_log_file(OldFile, NewFile) ->
- _ = file:close(OldFile),
- open_log_file(NewFile).
-
-open_log_file(standard_io) -> standard_io;
-open_log_file(FileName) ->
- case file:open(FileName, [write]) of
- {ok, Fd} -> Fd;
- Error ->
- io:format("si_sasl_supp: Cannot open file '~s' (~w).~n",
- [FileName, Error]),
- io:format("si_sasl_supp: Using standard_io~n"),
- standard_io
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% 3. Code
-%%--------------------------------------------------
-
-%%-----------------------------------------------------------------
-%% call(Request) -> Term
-%%-----------------------------------------------------------------
-call(Req) ->
- gen_server:call(si_server, Req, infinity).
-
-%%--------------------------------------------------
-%% Makes a Pid of almost anything.
-%% Returns: Pid|{error, Reason}
-%% Fails: Never.
-%%--------------------------------------------------
-make_pid(A,B,C) when is_integer(A), is_integer(B), is_integer(C) ->
- list_to_pid(lists:concat(["<",A,".",B,".",C,">"])).
-make_pid(P) when is_pid(P) -> P;
-make_pid(undefined) -> undefined;
-make_pid(P) when is_atom(P) ->
- case whereis(P) of
- undefined ->
- case expand_abbrev(P, process_abbrevs()) of
- {error, Reason} -> {error, Reason};
- {value, {_Abbrev, FullName}} ->
- case whereis(FullName) of
- undefined ->
- {error, {'process not registered', P}};
- Pid -> Pid
- end
- end;
- Pid -> Pid
- end;
-make_pid(P) when is_list(P) -> list_to_pid(P);
-make_pid({A, B, C}) -> make_pid(A, B, C);
-make_pid(X) -> {error, {'can not make a pid of', X}}.
-
-process_abbrevs() ->
- [{init, init},
- {fs, file_server}].
-
-%%--------------------------------------------------
-%% Args: Abbrevs is an assoc-list of {Abbrev, RealName}
-%% Returns: {value, {Abbrev, FullName}}|{error, Reason}
-%%--------------------------------------------------
-expand_abbrev(ProcessName, Abbrevs) ->
- case lists:keysearch(ProcessName, 1, Abbrevs) of
- {value, {Abbrev, FullName}} ->
- {value, {Abbrev, FullName}};
- _ ->
- case lists:keysearch(ProcessName, 2, Abbrevs) of
- {value, {Abbrev, FullName}} ->
- {value, {Abbrev, FullName}};
- _ ->
- {error, {'invalid process name', ProcessName}}
- end
- end.
-
-%%-----------------------------------------------------------------
-%% This is the function that actually gets the information out
-%% of the agent/server/...
-%% Returns: {status_info, Pid, Type, Data}
-%% | {error, Reason}
-%%-----------------------------------------------------------------
-status_info(Pid) when is_pid(Pid) ->
- case catch sys:get_status(Pid, 5000) of
- {status, Pid, Type, Info} ->
- {status_info, Pid, Type, Info};
- _ ->
- {error, {'process does not respond', Pid}}
- end;
-
-status_info(X) ->
- {error, {'not a pid', X}}.
-
-%%--------------------------------------------------
-%% Implementation starts here.
-%%--------------------------------------------------
-start_log_impl(FileName) ->
- put(device, open_log_file(get(device), FileName)).
-
-valid_opt(all) -> all;
-valid_opt(_Opt) -> normal.
-
-
-print_help() ->
- p("- - - - - - - - PROCESSES - - - - - - - - - "),
- p("si_sasl_supp:pi([Opt,] Pid) - Formatted information about any process that"),
- p(" SI recognises."),
- p("si_sasl_supp:pi([Opt,] A,B,C) - Same as si_sasl_supp:pi({A, B, C})."),
- p("si_sasl_supp:ppi(Pid) - Pretty formating of process_info."),
- p(" Works for any process."),
- p("- - - - - - - - MISC - - - - - - - - - - - "),
- p("si_sasl_supp:abbrevs() - Lists valid abbreviations."),
- p("si_sasl_supp:start_log(FileNname)"),
- p("si_sasl_supp:stop_log()"),
- p("si_sasl_supp:start() - Starts Status Inspection (the si_server)."),
- p("si_sasl_supp:start([{start_log, FileName}])"),
- p("si_sasl_supp:stop() - Shut down SI.").
-
-
-
-%% Convenient shorthand
-p(X) ->
- io:format(lists:append(X, "~n")).
-
-pi_impl(Opt, XPid) ->
- case make_pid(XPid) of
- Pid when is_pid(Pid) ->
- case status_info(Pid) of
- {status_info, Pid, {module, Module}, Data} ->
- do_best_printout(Opt, Pid, Module, Data);
- {error, Reason} ->
- _ = ppi_impl(Pid),
- {error, {"can not get status info from process:",
- XPid,
- Reason}}
- end;
- {error, Reason} ->
- {error, Reason}
- end.
-
-%%--------------------------------------------------
-%% Is there a format_info for this process? In that case, run it!
-%% Return ok|{error, Reason}
-%% Fails: Never.
-%%--------------------------------------------------
-do_best_printout(Opt, Pid, Mod, Data) when is_pid(Pid) ->
- case print_info(get(device), Pid, {Mod, format_status}, Opt, Data) of
- ok -> ok;
- {error, Reason} ->
- _ = ppi_impl(Pid),
- {error, Reason}
- end.
-
-ppi_impl(XPid) ->
- case make_pid(XPid) of
- P when is_pid(P) ->
- case process_info(P) of
- undefined ->
- {error, {'dead process', P}};
- PI ->
- Device = case get(device) of
- undefined -> standard_io;
- X -> X
- end,
- io:format(Device, "~nPretty Process Info~n", []),
- io:format(Device, "-------------------~n", []),
- io:format(Device, "~p~n", [PI])
- end;
- _ -> {error, {no_pid, XPid}}
- end.
-
-print_info(Device, Pid, {Module, Func}, Opt, Data) ->
- case erlang:function_exported(Module, Func, 2) of
- true ->
- case catch apply(Module, Func, [Opt, Data]) of
- Format when is_list(Format) ->
- format_lib_supp:print_info(Device, 79,
- add_pid_to_format(Pid, Format)),
- ok;
- Other -> {error, {'invalid format', Other}}
- end;
- _ ->
- {error, {no_such_function, Module, Func}}
- end.
-
-add_pid_to_format(Pid, [{header, H} | T]) ->
- [{header, H}, {data, [{"Pid", Pid}]} | T];
-add_pid_to_format(Pid, List) ->
- [{data, [{"Pid", Pid}]} | List].
-
-
diff --git a/lib/sasl/src/systools.erl b/lib/sasl/src/systools.erl
index dd1a58c3c1..34eca6679f 100644
--- a/lib/sasl/src/systools.erl
+++ b/lib/sasl/src/systools.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -73,7 +73,7 @@ make_tar(RelName, Opt) ->
script2boot(File) ->
case systools_lib:file_term2binary(File ++ ".script", File ++ ".boot") of
{error,Error} ->
- io:format(systools_make:format_error(Error)),
+ io:format("~ts", [systools_make:format_error(Error)]),
error;
_ ->
ok
@@ -84,7 +84,7 @@ script2boot(File, Output0, _Opt) ->
Output = Output0++".boot",
case systools_lib:file_term2binary(Input, Output) of
{error,Error} ->
- io:format(systools_make:format_error(Error)),
+ io:format("~ts", [systools_make:format_error(Error)]),
error;
_ ->
ok
diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl
index 391b1fb5cc..b5a6b44f93 100644
--- a/lib/sasl/src/systools_make.erl
+++ b/lib/sasl/src/systools_make.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,7 +32,8 @@
-export([read_application/4]).
--export([make_hybrid_boot/5]).
+-export([make_hybrid_boot/4]).
+-export([preloaded/0]). % Exported just for testing
-import(lists, [filter/2, keysort/2, keysearch/3, map/2, reverse/1,
append/1, foldl/3, member/2, foreach/2]).
@@ -45,6 +46,13 @@
-compile({inline,[{badarg,2}]}).
+-ifdef(USE_ESOCK).
+-define(ESOCK_MODS, [socket]).
+-else.
+-define(ESOCK_MODS, []).
+-endif.
+
+
%%-----------------------------------------------------------------
%% Create a boot script from a release file.
%% Options is a list of {path, Path} | silent | local
@@ -178,94 +186,153 @@ return({error,Mod,Error},_,Flags) ->
%% and sasl.
%%
%% TmpVsn = string(),
-%% Paths = {KernelPath,StdlibPath,SaslPath}
%% Returns {ok,Boot} | {error,Reason}
%% Boot1 = Boot2 = Boot = binary()
%% Reason = {app_not_found,App} | {app_not_replaced,App}
-%% App = kernel | stdlib | sasl
-make_hybrid_boot(TmpVsn, Boot1, Boot2, Paths, Args) ->
- catch do_make_hybrid_boot(TmpVsn, Boot1, Boot2, Paths, Args).
-do_make_hybrid_boot(TmpVsn, Boot1, Boot2, Paths, Args) ->
- {script,{_RelName1,_RelVsn1},Script1} = binary_to_term(Boot1),
- {script,{RelName2,_RelVsn2},Script2} = binary_to_term(Boot2),
- MatchPaths = get_regexp_path(Paths),
- NewScript1 = replace_paths(Script1,MatchPaths),
- {Kernel,Stdlib,Sasl} = get_apps(Script2,undefined,undefined,undefined),
- NewScript2 = replace_apps(NewScript1,Kernel,Stdlib,Sasl),
- NewScript3 = add_apply_upgrade(NewScript2,Args),
- Boot = term_to_binary({script,{RelName2,TmpVsn},NewScript3}),
+%% App = stdlib | sasl
+make_hybrid_boot(TmpVsn, Boot1, Boot2, Args) ->
+ catch do_make_hybrid_boot(TmpVsn, Boot1, Boot2, Args).
+do_make_hybrid_boot(TmpVsn, OldBoot, NewBoot, Args) ->
+ {script,{_RelName1,_RelVsn1},OldScript} = binary_to_term(OldBoot),
+ {script,{NewRelName,_RelVsn2},NewScript} = binary_to_term(NewBoot),
+
+ %% Everyting upto kernel_load_completed must come from the new script
+ Fun1 = fun({progress,kernel_load_completed}) -> false;
+ (_) -> true
+ end,
+ {_OldKernelLoad,OldRest1} = lists:splitwith(Fun1,OldScript),
+ {NewKernelLoad,NewRest1} = lists:splitwith(Fun1,NewScript),
+
+ Fun2 = fun({progress,modules_loaded}) -> false;
+ (_) -> true
+ end,
+ {OldModLoad,OldRest2} = lists:splitwith(Fun2,OldRest1),
+ {NewModLoad,NewRest2} = lists:splitwith(Fun2,NewRest1),
+
+ Fun3 = fun({kernelProcess,_,_}) -> false;
+ (_) -> true
+ end,
+ {OldPaths,OldRest3} = lists:splitwith(Fun3,OldRest2),
+ {NewPaths,NewRest3} = lists:splitwith(Fun3,NewRest2),
+
+ Fun4 = fun({progress,init_kernel_started}) -> false;
+ (_) -> true
+ end,
+ {_OldKernelProcs,OldApps} = lists:splitwith(Fun4,OldRest3),
+ {NewKernelProcs,NewApps} = lists:splitwith(Fun4,NewRest3),
+
+ %% Then comes all module load, which for each app consist of:
+ %% {path,[AppPath]},
+ %% {primLoad,ModuleList}
+ %% Replace kernel, stdlib and sasl here
+ MatchPaths = get_regexp_path(),
+ ModLoad = replace_module_load(OldModLoad,NewModLoad,MatchPaths),
+ Paths = replace_paths(OldPaths,NewPaths,MatchPaths),
+
+ {Stdlib,Sasl} = get_apps(NewApps,undefined,undefined),
+ Apps0 = replace_apps(OldApps,Stdlib,Sasl),
+ Apps = add_apply_upgrade(Apps0,Args),
+
+ Script = NewKernelLoad++ModLoad++Paths++NewKernelProcs++Apps,
+ Boot = term_to_binary({script,{NewRelName,TmpVsn},Script}),
{ok,Boot}.
%% For each app, compile a regexp that can be used for finding its path
-get_regexp_path({KernelPath,StdlibPath,SaslPath}) ->
+get_regexp_path() ->
{ok,KernelMP} = re:compile("kernel-[0-9\.]+",[unicode]),
{ok,StdlibMP} = re:compile("stdlib-[0-9\.]+",[unicode]),
{ok,SaslMP} = re:compile("sasl-[0-9\.]+",[unicode]),
- [{KernelMP,KernelPath},{StdlibMP,StdlibPath},{SaslMP,SaslPath}].
-
-%% For each path in the script, check if it matches any of the MPs
-%% found above, and if so replace it with the correct new path.
-replace_paths([{path,Path}|Script],MatchPaths) ->
- [{path,replace_path(Path,MatchPaths)}|replace_paths(Script,MatchPaths)];
-replace_paths([Stuff|Script],MatchPaths) ->
- [Stuff|replace_paths(Script,MatchPaths)];
-replace_paths([],_) ->
+ [KernelMP,StdlibMP,SaslMP].
+
+replace_module_load(Old,New,[MP|MatchPaths]) ->
+ replace_module_load(do_replace_module_load(Old,New,MP),New,MatchPaths);
+replace_module_load(Script,_,[]) ->
+ Script.
+
+do_replace_module_load([{path,[OldAppPath]},{primLoad,OldMods}|OldRest],New,MP) ->
+ case re:run(OldAppPath,MP,[{capture,none}]) of
+ nomatch ->
+ [{path,[OldAppPath]},{primLoad,OldMods}|
+ do_replace_module_load(OldRest,New,MP)];
+ match ->
+ get_module_load(New,MP) ++ OldRest
+ end;
+do_replace_module_load([Other|Rest],New,MP) ->
+ [Other|do_replace_module_load(Rest,New,MP)];
+do_replace_module_load([],_,_) ->
[].
-replace_path([Path|Paths],MatchPaths) ->
- [do_replace_path(Path,MatchPaths)|replace_path(Paths,MatchPaths)];
-replace_path([],_) ->
+get_module_load([{path,[AppPath]},{primLoad,Mods}|Rest],MP) ->
+ case re:run(AppPath,MP,[{capture,none}]) of
+ nomatch ->
+ get_module_load(Rest,MP);
+ match ->
+ [{path,[AppPath]},{primLoad,Mods}]
+ end;
+get_module_load([_|Rest],MP) ->
+ get_module_load(Rest,MP);
+get_module_load([],_) ->
[].
-do_replace_path(Path,[{MP,ReplacePath}|MatchPaths]) ->
- case re:run(Path,MP,[{capture,none}]) of
- nomatch -> do_replace_path(Path,MatchPaths);
- match -> ReplacePath
+replace_paths([{path,OldPaths}|Old],New,MatchPaths) ->
+ {path,NewPath} = lists:keyfind(path,1,New),
+ [{path,do_replace_paths(OldPaths,NewPath,MatchPaths)}|Old];
+replace_paths([Other|Old],New,MatchPaths) ->
+ [Other|replace_paths(Old,New,MatchPaths)].
+
+do_replace_paths(Old,New,[MP|MatchPaths]) ->
+ do_replace_paths(do_replace_paths1(Old,New,MP),New,MatchPaths);
+do_replace_paths(Paths,_,[]) ->
+ Paths.
+
+do_replace_paths1([P|Ps],New,MP) ->
+ case re:run(P,MP,[{capture,none}]) of
+ nomatch ->
+ [P|do_replace_paths1(Ps,New,MP)];
+ match ->
+ get_path(New,MP) ++ Ps
end;
-do_replace_path(Path,[]) ->
- Path.
-
-%% Return the entries for loading the three base applications
-get_apps([{kernelProcess,application_controller,
- {application_controller,start,[{application,kernel,_}]}}=Kernel|
- Script],_,Stdlib,Sasl) ->
- get_apps(Script,Kernel,Stdlib,Sasl);
+do_replace_paths1([],_,_) ->
+ [].
+
+get_path([P|Ps],MP) ->
+ case re:run(P,MP,[{capture,none}]) of
+ nomatch ->
+ get_path(Ps,MP);
+ match ->
+ [P]
+ end;
+get_path([],_) ->
+ [].
+
+
+%% Return the entries for loading stdlib and sasl
get_apps([{apply,{application,load,[{application,stdlib,_}]}}=Stdlib|Script],
- Kernel,_,Sasl) ->
- get_apps(Script,Kernel,Stdlib,Sasl);
+ _,Sasl) ->
+ get_apps(Script,Stdlib,Sasl);
get_apps([{apply,{application,load,[{application,sasl,_}]}}=Sasl|_Script],
- Kernel,Stdlib,_) ->
- {Kernel,Stdlib,Sasl};
-get_apps([_|Script],Kernel,Stdlib,Sasl) ->
- get_apps(Script,Kernel,Stdlib,Sasl);
-get_apps([],undefined,_,_) ->
- throw({error,{app_not_found,kernel}});
-get_apps([],_,undefined,_) ->
+ Stdlib,_) ->
+ {Stdlib,Sasl};
+get_apps([_|Script],Stdlib,Sasl) ->
+ get_apps(Script,Stdlib,Sasl);
+get_apps([],undefined,_) ->
throw({error,{app_not_found,stdlib}});
-get_apps([],_,_,undefined) ->
+get_apps([],_,undefined) ->
throw({error,{app_not_found,sasl}}).
-
-%% Replace the entries for loading the base applications
-replace_apps([{kernelProcess,application_controller,
- {application_controller,start,[{application,kernel,_}]}}|
- Script],Kernel,Stdlib,Sasl) ->
- [Kernel|replace_apps(Script,undefined,Stdlib,Sasl)];
+%% Replace the entries for loading the stdlib and sasl
replace_apps([{apply,{application,load,[{application,stdlib,_}]}}|Script],
- Kernel,Stdlib,Sasl) ->
- [Stdlib|replace_apps(Script,Kernel,undefined,Sasl)];
+ Stdlib,Sasl) ->
+ [Stdlib|replace_apps(Script,undefined,Sasl)];
replace_apps([{apply,{application,load,[{application,sasl,_}]}}|Script],
- _Kernel,_Stdlib,Sasl) ->
+ _Stdlib,Sasl) ->
[Sasl|Script];
-replace_apps([Stuff|Script],Kernel,Stdlib,Sasl) ->
- [Stuff|replace_apps(Script,Kernel,Stdlib,Sasl)];
-replace_apps([],undefined,undefined,_) ->
+replace_apps([Stuff|Script],Stdlib,Sasl) ->
+ [Stuff|replace_apps(Script,Stdlib,Sasl)];
+replace_apps([],undefined,_) ->
throw({error,{app_not_replaced,sasl}});
-replace_apps([],undefined,_,_) ->
- throw({error,{app_not_replaced,stdlib}});
-replace_apps([],_,_,_) ->
- throw({error,{app_not_replaced,kernel}}).
-
+replace_apps([],_,_) ->
+ throw({error,{app_not_replaced,stdlib}}).
%% Finally add an apply of release_handler:new_emulator_upgrade - which will
%% complete the execution of the upgrade script (relup).
@@ -275,8 +342,6 @@ add_apply_upgrade(Script,Args) ->
{apply,{release_handler,new_emulator_upgrade,Args}} |
RevScript]).
-
-
%%-----------------------------------------------------------------
%% Create a release package from a release file.
%% Options is a list of {path, Path} | silent |
@@ -310,6 +375,7 @@ add_apply_upgrade(Script,Args) ->
%% RelVsn/start.boot
%% relup
%% sys.config
+%% sys.config.src
%% erts-EVsn[/bin]
%%-----------------------------------------------------------------
@@ -1488,6 +1554,12 @@ mandatory_modules() ->
gen_server,
heart,
kernel,
+ logger,
+ logger_filters,
+ logger_server,
+ logger_backend,
+ logger_config,
+ logger_simple_h,
lists,
proc_lib,
supervisor
@@ -1498,11 +1570,11 @@ mandatory_modules() ->
preloaded() ->
%% Sorted
- [erl_prim_loader,erl_tracer,erlang,
- erts_code_purger,erts_dirty_process_code_checker,
+ [atomics,counters,erl_init,erl_prim_loader,erl_tracer,erlang,
+ erts_code_purger,erts_dirty_process_signal_handler,
erts_internal,erts_literal_area_collector,
- init,otp_ring0,prim_eval,prim_file,
- prim_inet,prim_zip,zlib].
+ init,net,persistent_term,prim_buffer,prim_eval,prim_file,
+ prim_inet,prim_zip] ++ ?ESOCK_MODS ++ [zlib].
%%______________________________________________________________________
%% Kernel processes; processes that are specially treated by the init
@@ -1512,7 +1584,7 @@ preloaded() ->
kernel_processes() ->
[{heart, heart, start, []},
- {error_logger, error_logger, start_link, []},
+ {logger, logger_server, start_link, []},
{application_controller, application_controller, start,
fun(Appls) ->
[{_,App}] = filter(fun({{kernel,_},_App}) -> true;
@@ -1552,6 +1624,7 @@ create_kernel_procs(Appls) ->
%% RelVsn/start.boot
%% relup
%% sys.config
+%% sys.config.src
%% erts-EVsn[/bin]
%%
%% The VariableN.tar.gz files can also be stored as own files not
@@ -1707,14 +1780,18 @@ add_system_files(Tar, RelName, Release, Path1) ->
add_to_tar(Tar, Relup, filename:join(RelVsnDir, "relup"))
end,
- case lookup_file("sys.config", Path) of
- false ->
- ignore;
- Sys ->
- check_sys_config(Sys),
- add_to_tar(Tar, Sys, filename:join(RelVsnDir, "sys.config"))
+ case lookup_file("sys.config.src", Path) of
+ false ->
+ case lookup_file("sys.config", Path) of
+ false ->
+ ignore;
+ Sys ->
+ check_sys_config(Sys),
+ add_to_tar(Tar, Sys, filename:join(RelVsnDir, "sys.config"))
+ end;
+ SysSrc ->
+ add_to_tar(Tar, SysSrc, filename:join(RelVsnDir, "sys.config.src"))
end,
-
ok.
lookup_file(Name, [Dir|Path]) ->
diff --git a/lib/sasl/src/systools_relup.erl b/lib/sasl/src/systools_relup.erl
index e836d57670..5f1176ec69 100644
--- a/lib/sasl/src/systools_relup.erl
+++ b/lib/sasl/src/systools_relup.erl
@@ -587,7 +587,7 @@ default(warnings_as_errors) -> false.
print_error({error, Mod, Error}) ->
S = apply(Mod, format_error, [Error]),
- io:format(S, []);
+ io:format("~ts", [S]);
print_error(Other) ->
io:format("Error: ~tp~n", [Other]).
diff --git a/lib/sasl/test/installer.erl b/lib/sasl/test/installer.erl
index e38d0cfa7b..5429008a5f 100644
--- a/lib/sasl/test/installer.erl
+++ b/lib/sasl/test/installer.erl
@@ -905,7 +905,7 @@ start_client(TestNode,Client,Sname) ->
wait_started(TestNode,Node)
after 30000 ->
?print([{start_client,failed,Node},net_adm:ping(Node)]),
- ?fail({"can not start", Node})
+ ?fail({"cannot start", Node})
end.
start_client_unix(TestNode,Sname,Node) ->
diff --git a/lib/sasl/test/rb_SUITE.erl b/lib/sasl/test/rb_SUITE.erl
index 4ba2540545..e5ca1775d5 100644
--- a/lib/sasl/test/rb_SUITE.erl
+++ b/lib/sasl/test/rb_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -423,7 +423,7 @@ start_stop_log(Config) ->
StdioResult2 = capture(fun() -> rb:log_list() end),
{ok,<<>>} = file:read_file(OutFile),
- %% Test that standard_io is used if log file can not be opened
+ %% Test that standard_io is used if log file cannot be opened
ok = rb:start_log(filename:join(nonexistingdir,"newfile.txt")),
StdioResult = capture(fun() -> rb:show(1) end),
{ok,<<>>} = file:read_file(OutFile),
diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl
index 50932e89e4..2ff2f29591 100644
--- a/lib/sasl/test/release_handler_SUITE.erl
+++ b/lib/sasl/test/release_handler_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -22,7 +22,8 @@
-include_lib("common_test/include/ct.hrl").
-include("test_lib.hrl").
--compile(export_all).
+-compile([export_all, nowarn_export_all]).
+-export([scheduler_wall_time/0, garbage_collect/0]). %% rpc'ed
% Default timetrap timeout (set in init_per_testcase).
%-define(default_timeout, ?t:minutes(40)).
@@ -1085,8 +1086,9 @@ otp_9395_update_many_mods(Conf) when is_list(Conf) ->
Rel2Dir = filename:dirname(Rel2),
%% Start a slave node
+ PA = filename:dirname(code:which(?MODULE)),
{ok, Node} = t_start_node(otp_9395_update_many_mods, Rel1,
- filename:join(Rel1Dir,"sys.config")),
+ filename:join(Rel1Dir,"sys.config"), "-pa " ++ PA),
%% Start a lot of processes on the new node, all with refs to each
%% module that will be updated
@@ -1109,8 +1111,8 @@ otp_9395_update_many_mods(Conf) when is_list(Conf) ->
[RelVsn2, filename:join(Rel2Dir, "sys.config")]),
%% First, install release directly and check how much time it takes
- rpc:call(Node,erlang,garbage_collect,[]),
- rpc:call(Node,erlang,system_flag,[scheduler_wall_time,true]),
+ rpc:call(Node,?MODULE,garbage_collect,[]),
+ SWTFlag0 = spawn_link(Node, ?MODULE, scheduler_wall_time, []),
{TInst0,{ok, _, []}} =
timer:tc(rpc,call,[Node, release_handler, install_release, [RelVsn2]]),
SWT0 = rpc:call(Node,erlang,statistics,[scheduler_wall_time]),
@@ -1135,9 +1137,9 @@ otp_9395_update_many_mods(Conf) when is_list(Conf) ->
%% Finally install release after check and purge, and check that
%% this install was faster than the first.
- rpc:call(Node,erlang,system_flag,[scheduler_wall_time,false]),
- rpc:call(Node,erlang,garbage_collect,[]),
- rpc:call(Node,erlang,system_flag,[scheduler_wall_time,true]),
+ SWTFlag0 ! die,
+ rpc:call(Node,?MODULE,garbage_collect,[]),
+ _SWTFlag1 = spawn_link(Node, ?MODULE, scheduler_wall_time, []),
{TInst2,{ok, _RelVsn1, []}} =
timer:tc(rpc,call,[Node, release_handler, install_release, [RelVsn2]]),
SWT2 = rpc:call(Node,erlang,statistics,[scheduler_wall_time]),
@@ -1161,6 +1163,15 @@ otp_9395_update_many_mods(Conf) when is_list(Conf) ->
ok.
+scheduler_wall_time() ->
+ erlang:system_flag(scheduler_wall_time,true),
+ receive _Msg -> normal end.
+
+garbage_collect() ->
+ Pids = processes(),
+ [erlang:garbage_collect(Pid) || Pid <- Pids].
+
+
otp_9395_update_many_mods(cleanup,_Conf) ->
stop_node(node_name(otp_9395_update_many_mods)).
@@ -1190,8 +1201,9 @@ otp_9395_rm_many_mods(Conf) when is_list(Conf) ->
Rel2Dir = filename:dirname(Rel2),
%% Start a slave node
+ PA = filename:dirname(code:which(?MODULE)),
{ok, Node} = t_start_node(otp_9395_rm_many_mods, Rel1,
- filename:join(Rel1Dir,"sys.config")),
+ filename:join(Rel1Dir,"sys.config"), "-pa " ++ PA),
%% Start a lot of processes on the new node, all with refs to each
%% module that will be updated
@@ -1214,8 +1226,8 @@ otp_9395_rm_many_mods(Conf) when is_list(Conf) ->
[RelVsn2, filename:join(Rel2Dir, "sys.config")]),
%% First, install release directly and check how much time it takes
- rpc:call(Node,erlang,garbage_collect,[]),
- rpc:call(Node,erlang,system_flag,[scheduler_wall_time,true]),
+ rpc:call(Node,?MODULE,garbage_collect,[]),
+ SWTFlag0 = spawn_link(Node, ?MODULE, scheduler_wall_time, []),
{TInst0,{ok, _, []}} =
timer:tc(rpc,call,[Node, release_handler, install_release, [RelVsn2]]),
SWT0 = rpc:call(Node,erlang,statistics,[scheduler_wall_time]),
@@ -1240,9 +1252,9 @@ otp_9395_rm_many_mods(Conf) when is_list(Conf) ->
%% Finally install release after check and purge, and check that
%% this install was faster than the first.
- rpc:call(Node,erlang,system_flag,[scheduler_wall_time,false]),
- rpc:call(Node,erlang,garbage_collect,[]),
- rpc:call(Node,erlang,system_flag,[scheduler_wall_time,true]),
+ SWTFlag0 ! die,
+ rpc:call(Node,?MODULE,garbage_collect,[]),
+ _SWTFlag1 = spawn_link(Node, ?MODULE, scheduler_wall_time, []),
{TInst2,{ok, _RelVsn1, []}} =
timer:tc(rpc,call,[Node, release_handler, install_release, [RelVsn2]]),
SWT2 = rpc:call(Node,erlang,statistics,[scheduler_wall_time]),
@@ -1384,9 +1396,9 @@ upgrade_supervisor(Conf) when is_list(Conf) ->
%% Check that the restart strategy and child spec is updated
{status, _, {module, _}, [_, _, _, _, [_,_,{data,[{"State",State}]}|_]]} =
rpc:call(Node,sys,get_status,[a_sup]),
- {state,_,RestartStrategy,[Child],_,_,_,_,_,_,_} = State,
+ {state,_,RestartStrategy,{[a],Db},_,_,_,_,_,_,_} = State,
one_for_all = RestartStrategy, % changed from one_for_one
- {child,_,_,_,_,brutal_kill,_,_} = Child, % changed from timeout 2000
+ {child,_,_,_,_,brutal_kill,_,_} = maps:get(a,Db), % changed from timeout 2000
ok.
@@ -1835,24 +1847,32 @@ otp_10463_upgrade_script_regexp(cleanup,Config) ->
code:del_path(filename:join([DataDir,regexp_appup,app1,ebin])),
ok.
-no_dot_erlang(Conf) ->
- PrivDir = ?config(data_dir,Conf),
- {ok, OrigWd} = file:get_cwd(),
- try
- ok = file:set_cwd(PrivDir),
-
- {ok, Wd} = file:get_cwd(),
- io:format("Dir ~ts~n", [Wd]),
+no_dot_erlang(_Conf) ->
+ case init:get_argument(home) of
+ {ok,[[Home]]} when is_list(Home) ->
+ no_dot_erlang_1(Home);
+ _ -> ok
+ end.
+no_dot_erlang_1(Home) ->
+ DotErlang = filename:join(Home, ".erlang"),
+ BupErlang = filename:join(Home, ".erlang_testbup"),
+ try
+ {ok, Wd} = file:get_cwd(),
+ case filelib:is_file(DotErlang) of
+ true -> {ok, _} = file:copy(DotErlang, BupErlang);
+ false -> ok
+ end,
Erl0 = filename:join([code:root_dir(),"bin","erl"]),
Erl = filename:nativename(Erl0),
Quote = "\"",
Args = " -noinput -run c pwd -run erlang halt",
- ok = file:write_file(".erlang", <<"io:put_chars(\"DOT_ERLANG_READ\\n\").\n">>),
+ ok = file:write_file(DotErlang, <<"io:put_chars(\"DOT_ERLANG_READ\\n\").\n">>),
CMD1 = Quote ++ Erl ++ Quote ++ Args ,
case os:cmd(CMD1) of
- "DOT_ERLANG_READ" ++ _ -> ok;
+ "DOT_ERLANG_READ" ++ _ ->
+ io:format("~p: Success~n", [?LINE]);
Other1 ->
io:format("Failed: ~ts~n",[CMD1]),
io:format("Expected: ~s ++ _~n",["DOT_ERLANG_READ "]),
@@ -1862,7 +1882,7 @@ no_dot_erlang(Conf) ->
NO_DOT_ERL = " -boot no_dot_erlang",
CMD2 = Quote ++ Erl ++ Quote ++ NO_DOT_ERL ++ Args,
case lists:prefix(Wd, Other2 = os:cmd(CMD2)) of
- true -> ok;
+ true -> io:format("~p: Success~n", [?LINE]);
false ->
io:format("Failed: ~ts~n",[CMD2]),
io:format("Expected: ~s~n",["TESTOK"]),
@@ -1870,9 +1890,13 @@ no_dot_erlang(Conf) ->
exit({failed_to_start, no_dot_erlang})
end
after
- _ = file:delete(".erlang"),
- ok = file:set_cwd(OrigWd),
- ok
+ case filelib:is_file(BupErlang) of
+ true ->
+ {ok, _} = file:copy(BupErlang, DotErlang),
+ _ = file:delete(BupErlang);
+ false ->
+ _ = file:delete(DotErlang)
+ end
end.
%%%-----------------------------------------------------------------
@@ -2556,15 +2580,15 @@ check_gg_info(Node,OtherAlive,OtherDead,Synced,N) ->
GGI = rpc:call(Node, global_group, info, []),
GI = rpc:call(Node, global, info,[]),
try do_check_gg_info(OtherAlive,OtherDead,Synced,GGI,GI)
- catch _:E when N==0 ->
+ catch _:E:Stacktrace when N==0 ->
?t:format("~nERROR: check_gg_info failed for ~p:~n~p~n"
"when GGI was: ~p~nand GI was: ~p~n",
- [Node,{E,erlang:get_stacktrace()},GGI,GI]),
+ [Node,{E,Stacktrace},GGI,GI]),
?t:fail("check_gg_info failed");
- _:E ->
+ _:E:Stacktrace ->
?t:format("~nWARNING: check_gg_info failed for ~p:~n~p~n"
"when GGI was: ~p~nand GI was: ~p~n",
- [Node,{E,erlang:get_stacktrace()},GGI,GI]),
+ [Node,{E,Stacktrace},GGI,GI]),
timer:sleep(1000),
check_gg_info(Node,OtherAlive,OtherDead,Synced,N-1)
end.
diff --git a/lib/sasl/test/sasl_SUITE.erl b/lib/sasl/test/sasl_SUITE.erl
index f12bde9b3d..fc80e37210 100644
--- a/lib/sasl/test/sasl_SUITE.erl
+++ b/lib/sasl/test/sasl_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
-include_lib("common_test/include/ct.hrl").
%% Test server specific exports
+-export([init_per_suite/1,end_per_suite/1]).
-export([all/0,groups/0,init_per_group/2,end_per_group/2]).
-export([init_per_testcase/2, end_per_testcase/2]).
@@ -37,6 +38,19 @@ all() ->
groups() ->
[].
+init_per_suite(Config) ->
+ S = application:get_env(kernel,logger_sasl_compatible),
+ application:set_env(kernel,logger_sasl_compatible,true),
+ [{sasl_compatible,S}|Config].
+
+end_per_suite(Config) ->
+ case ?config(sasl_compatible,Config) of
+ {ok,X} ->
+ application:set_env(kernel,logger_sasl_compatible,X);
+ undefined ->
+ application:unset_env(kernel,logger_sasl_compatible)
+ end.
+
init_per_group(_GroupName, Config) ->
Config.
diff --git a/lib/sasl/test/sasl_report_SUITE.erl b/lib/sasl/test/sasl_report_SUITE.erl
index 92df5e6e40..e639b55cee 100644
--- a/lib/sasl/test/sasl_report_SUITE.erl
+++ b/lib/sasl/test/sasl_report_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2]).
-export([gen_server_crash/1, gen_server_crash_unicode/1]).
+-export([legacy_gen_server_crash/1, legacy_gen_server_crash_unicode/1]).
-export([crash_me/0,start_link/0,init/1,handle_cast/2,terminate/2]).
@@ -29,7 +30,10 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [gen_server_crash, gen_server_crash_unicode].
+ [gen_server_crash,
+ gen_server_crash_unicode,
+ legacy_gen_server_crash,
+ legacy_gen_server_crash_unicode].
groups() ->
[].
@@ -52,14 +56,81 @@ gen_server_crash(Config) ->
gen_server_crash_unicode(Config) ->
gen_server_crash(Config, unicode).
+legacy_gen_server_crash(Config) ->
+ legacy_gen_server_crash(Config,latin1).
+
+legacy_gen_server_crash_unicode(Config) ->
+ legacy_gen_server_crash(Config,unicode).
+
gen_server_crash(Config, Encoding) ->
+ TC = list_to_atom(lists:concat([?FUNCTION_NAME,"_",Encoding])),
+ PrivDir = filename:join(?config(priv_dir,Config),?MODULE),
+ ConfigFileName = filename:join(PrivDir,TC),
+ KernelLog = filename:join(PrivDir,lists:concat([TC,"_kernel.log"])),
+ SaslLog = filename:join(PrivDir,lists:concat([TC,"_sasl.log"])),
+ KernelConfig = [{logger,[{handler,default,logger_std_h,
+ #{config=>#{type=>{file,KernelLog}}}}]},
+ {logger_sasl_compatible,true}],
+ Modes = [write, {encoding, Encoding}],
+ SaslConfig = [{sasl_error_logger,{file,SaslLog,Modes}}],
+ ok = filelib:ensure_dir(SaslLog),
+
+ ok = file:write_file(ConfigFileName ++ ".config",
+ io_lib:format("[{kernel, ~p},~n{sasl, ~p}].",
+ [KernelConfig,SaslConfig])),
+ {ok,Node} =
+ test_server:start_node(
+ TC, peer,
+ [{args, ["-pa ",filename:dirname(code:which(?MODULE)),
+ " -boot start_sasl -kernel start_timer true "
+ "-config ",ConfigFileName]}]),
+
+ %% Set depth
+ ok = rpc:call(Node,logger,update_formatter_config,[default,depth,30]),
+ ok = rpc:call(Node,logger,update_formatter_config,[sasl,depth,30]),
+
+ %% Make sure remote node logs it's own logs, and current node does
+ %% not log them.
+ ok = rpc:call(Node,logger,remove_handler_filter,[default,remote_gl]),
+ ok = rpc:call(Node,logger,remove_handler_filter,[sasl,remote_gl]),
+ ok = logger:add_primary_filter(no_remote,{fun(#{meta:=#{pid:=Pid}},_)
+ when node(Pid)=/=node() -> stop;
+ (_,_) -> ignore
+ end,[]}),
+ ct:log("Local node Logger config:~n~p",
+ [rpc:call(Node,logger,get_config,[])]),
+ ct:log("Remote node Logger config:~n~p",
+ [rpc:call(Node,logger,get_config,[])]),
+ ct:log("Remote node error_logger handlers: ~p",
+ [rpc:call(Node,error_logger,which_report_handlers,[])]),
+
+ ok = rpc:call(Node,?MODULE,crash_me,[]),
+
+ ok = rpc:call(Node,logger_std_h,filesync,[default]),
+ ok = rpc:call(Node,logger_std_h,filesync,[sasl]),
+
+ test_server:stop_node(Node),
+ ok = logger:remove_primary_filter(no_remote),
+
+ check_file(KernelLog, utf8, 70000, 150000),
+ check_file(SaslLog, Encoding, 70000, 150000),
+
+ ok = file:delete(KernelLog),
+ ok = file:delete(SaslLog),
+
+ ok.
+
+legacy_gen_server_crash(Config, Encoding) ->
+ StopFilter = {fun(_,_) -> stop end, ok},
+ logger:add_handler_filter(default,stop_all,StopFilter),
+ logger:add_handler_filter(sasl,stop_all,StopFilter),
+ logger:add_handler_filter(cth_log_redirect,stop_all,StopFilter),
try
do_gen_server_crash(Config, Encoding)
after
- error_logger:tty(true),
- ok = application:unset_env(sasl, sasl_error_logger),
- ok = application:unset_env(kernel, error_logger_format_depth),
- error_logger:add_report_handler(cth_log_redirect)
+ logger:remove_handler_filter(default,stop_all),
+ logger:remove_handler_filter(sasl,stop_all),
+ logger:remove_handler_filter(cth_log_redirect,stop_all)
end,
ok.
@@ -70,26 +141,23 @@ do_gen_server_crash(Config, Encoding) ->
SaslLog = filename:join(LogDir, "sasl.log"),
ok = filelib:ensure_dir(SaslLog),
- error_logger:delete_report_handler(cth_log_redirect),
- error_logger:tty(false),
- application:stop(sasl),
Modes = [write, {encoding, Encoding}],
- ok = application:set_env(sasl, sasl_error_logger, {file,SaslLog,Modes},
- [{persistent,true}]),
application:set_env(kernel, error_logger_format_depth, 30),
error_logger:logfile({open,KernelLog}),
- application:start(sasl),
- io:format("~p\n", [gen_event:which_handlers(error_logger)]),
+ error_logger:add_report_handler(sasl_report_file_h,{SaslLog,Modes,all}),
+ ct:log("Logger config:~n~p",[logger:get_config()]),
+ ct:log("error_logger handlers: ~p",[error_logger:which_report_handlers()]),
crash_me(),
error_logger:logfile(close),
+ error_logger:delete_report_handler(sasl_report_file_h),
check_file(KernelLog, utf8, 70000, 150000),
check_file(SaslLog, Encoding, 70000, 150000),
- %% ok = file:delete(KernelLog),
- %% ok = file:delete(SaslLog),
+ ok = file:delete(KernelLog),
+ ok = file:delete(SaslLog),
ok.
check_file(File, Encoding, Min, Max) ->
diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl
index 07748d975f..6c913850b9 100644
--- a/lib/sasl/test/systools_SUITE.erl
+++ b/lib/sasl/test/systools_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -67,7 +67,7 @@ groups() ->
otp_3065_circular_dependenies, included_and_used_sort_script]},
{tar, [],
[tar_options, normal_tar, no_mod_vsn_tar, system_files_tar,
- invalid_system_files_tar, variable_tar,
+ system_src_file_tar, invalid_system_files_tar, variable_tar,
src_tests_tar, var_tar, exref_tar, link_tar, no_sasl_tar,
otp_9507_path_ebin]},
{relup, [],
@@ -945,12 +945,47 @@ system_files_tar(Config) ->
ok.
+
system_files_tar(cleanup,Config) ->
Dir = ?privdir,
file:delete(filename:join(Dir,"sys.config")),
file:delete(filename:join(Dir,"relup")),
ok.
+%% make_tar: Check that sys.config.src and not sys.config is included
+system_src_file_tar(Config) ->
+ {ok, OldDir} = file:get_cwd(),
+
+ {LatestDir, LatestName} = create_script(latest,Config),
+
+ DataDir = filename:absname(?copydir),
+ LibDir = fname([DataDir, d_normal, lib]),
+ P = [fname([LibDir, 'db-2.1', ebin]),
+ fname([LibDir, 'fe-3.1', ebin])],
+
+ ok = file:set_cwd(LatestDir),
+
+ %% Add dummy sys.config and sys.config.src
+ ok = file:write_file("sys.config.src","[${SOMETHING}].\n"),
+ ok = file:write_file("sys.config","[].\n"),
+
+ {ok, _, _} = systools:make_script(LatestName, [silent, {path, P}]),
+ ok = systools:make_tar(LatestName, [{path, P}]),
+ ok = check_tar(fname(["releases","LATEST","sys.config.src"]), LatestName),
+ {error, _} = check_tar(fname(["releases","LATEST","sys.config"]), LatestName),
+ {ok, _, _} = systools:make_tar(LatestName, [{path, P}, silent]),
+ ok = check_tar(fname(["releases","LATEST","sys.config.src"]), LatestName),
+ {error, _} = check_tar(fname(["releases","LATEST","sys.config"]), LatestName),
+
+ ok = file:set_cwd(OldDir),
+
+ ok.
+
+system_src_file_tar(cleanup,Config) ->
+ Dir = ?privdir,
+ file:delete(filename:join(Dir,"sys.config")),
+ file:delete(filename:join(Dir,"sys.config.src")),
+ ok.
%% make_tar: Check that make_tar fails if relup or sys.config exist
%% but do not have valid content
@@ -1619,7 +1654,7 @@ abnormal_relup(Config) when is_list(Config) ->
ok.
-%% make_relup: Check relup can not be created is sasl is not in rel file.
+%% make_relup: Check relup cannot be created is sasl is not in rel file.
no_sasl_relup(Config) when is_list(Config) ->
{ok, OldDir} = file:get_cwd(),
{Dir1,Name1} = create_script(latest1_no_sasl,Config),
@@ -1760,27 +1795,28 @@ normal_hybrid(Config) ->
ok = file:set_cwd(OldDir),
- BasePaths = {"testkernelpath","teststdlibpath","testsaslpath"},
{ok,Hybrid} = systools_make:make_hybrid_boot("tmp_vsn",Boot1,Boot2,
- BasePaths, [dummy,args]),
+ [dummy,args]),
{script,{"Test release","tmp_vsn"},Script} = binary_to_term(Hybrid),
ct:log("~p.~n",[Script]),
%% Check that all paths to base apps are replaced by paths from BaseLib
Boot1Str = io_lib:format("~p~n",[binary_to_term(Boot1)]),
+ Boot2Str = io_lib:format("~p~n",[binary_to_term(Boot2)]),
HybridStr = io_lib:format("~p~n",[binary_to_term(Hybrid)]),
ReOpts = [global,{capture,first,list},unicode],
{match,OldKernelMatch} = re:run(Boot1Str,"kernel-[0-9\.]+",ReOpts),
{match,OldStdlibMatch} = re:run(Boot1Str,"stdlib-[0-9\.]+",ReOpts),
{match,OldSaslMatch} = re:run(Boot1Str,"sasl-[0-9\.]+",ReOpts),
- nomatch = re:run(HybridStr,"kernel-[0-9\.]+",ReOpts),
- nomatch = re:run(HybridStr,"stdlib-[0-9\.]+",ReOpts),
- nomatch = re:run(HybridStr,"sasl-[0-9\.]+",ReOpts),
- {match,NewKernelMatch} = re:run(HybridStr,"testkernelpath",ReOpts),
- {match,NewStdlibMatch} = re:run(HybridStr,"teststdlibpath",ReOpts),
- {match,NewSaslMatch} = re:run(HybridStr,"testsaslpath",ReOpts),
+ {match,NewKernelMatch} = re:run(Boot2Str,"kernel-[0-9\.]+",ReOpts),
+ {match,NewStdlibMatch} = re:run(Boot2Str,"stdlib-[0-9\.]+",ReOpts),
+ {match,NewSaslMatch} = re:run(Boot2Str,"sasl-[0-9\.]+",ReOpts),
+
+ {match,NewKernelMatch} = re:run(HybridStr,"kernel-[0-9\.]+",ReOpts),
+ {match,NewStdlibMatch} = re:run(HybridStr,"stdlib-[0-9\.]+",ReOpts),
+ {match,NewSaslMatch} = re:run(HybridStr,"sasl-[0-9\.]+",ReOpts),
NewKernelN = length(NewKernelMatch),
NewKernelN = length(OldKernelMatch),
@@ -1789,6 +1825,11 @@ normal_hybrid(Config) ->
NewSaslN = length(NewSaslMatch),
NewSaslN = length(OldSaslMatch),
+ %% Check that kernelProcesses are taken from new boot script
+ {script,_,Script2} = binary_to_term(Boot2),
+ NewKernelProcs = [KP || KP={kernelProcess,_,_} <- Script2],
+ NewKernelProcs = [KP || KP={kernelProcess,_,_} <- Script],
+
%% Check that application load instruction has correct versions
Apps = application:loaded_applications(),
{_,_,KernelVsn} = lists:keyfind(kernel,1,Apps),
@@ -1859,10 +1900,8 @@ hybrid_no_old_sasl(Config) ->
{ok,Boot1} = file:read_file(Name1 ++ ".boot"),
{ok,Boot2} = file:read_file(Name2 ++ ".boot"),
- BasePaths = {"testkernelpath","teststdlibpath","testsaslpath"},
{error,{app_not_replaced,sasl}} =
- systools_make:make_hybrid_boot("tmp_vsn",Boot1,Boot2,
- BasePaths,[dummy,args]),
+ systools_make:make_hybrid_boot("tmp_vsn",Boot1,Boot2,[dummy,args]),
ok = file:set_cwd(OldDir),
ok.
@@ -1892,10 +1931,8 @@ hybrid_no_new_sasl(Config) ->
{ok,Boot1} = file:read_file(Name1 ++ ".boot"),
{ok,Boot2} = file:read_file(Name2 ++ ".boot"),
- BasePaths = {"testkernelpath","teststdlibpath","testsaslpath"},
{error,{app_not_found,sasl}} =
- systools_make:make_hybrid_boot("tmp_vsn",Boot1,Boot2,
- BasePaths,[dummy,args]),
+ systools_make:make_hybrid_boot("tmp_vsn",Boot1,Boot2,[dummy,args]),
ok = file:set_cwd(OldDir),
ok.
diff --git a/lib/sasl/test/test_lib.hrl b/lib/sasl/test/test_lib.hrl
index 9a54937f96..7867d3da39 100644
--- a/lib/sasl/test/test_lib.hrl
+++ b/lib/sasl/test/test_lib.hrl
@@ -1,3 +1,3 @@
-define(ertsvsn,"4.4").
--define(kernelvsn,"5.0").
--define(stdlibvsn,"3.0").
+-define(kernelvsn,"6.0").
+-define(stdlibvsn,"3.5").
diff --git a/lib/sasl/vsn.mk b/lib/sasl/vsn.mk
index 2488197ec5..8838b514da 100644
--- a/lib/sasl/vsn.mk
+++ b/lib/sasl/vsn.mk
@@ -1 +1 @@
-SASL_VSN = 3.1.1
+SASL_VSN = 3.4
diff --git a/lib/snmp/doc/src/Makefile b/lib/snmp/doc/src/Makefile
index 3ebee792f9..e7ab491eef 100644
--- a/lib/snmp/doc/src/Makefile
+++ b/lib/snmp/doc/src/Makefile
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2017. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -140,6 +140,7 @@ clean_man:
clean_html:
@echo "cleaning html:"
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
$(MAN7DIR)/%.7: $(MIBSDIR)/%.mib
@echo "processing $*"
diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml
index 8d48cb911d..780e0cae76 100644
--- a/lib/snmp/doc/src/notes.xml
+++ b/lib/snmp/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -34,7 +34,104 @@
</header>
- <section><title>SNMP 5.2.10</title>
+ <section><title>SNMP 5.3</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The application otp_mibs has been removed from OTP. Some
+ of its components (mibs) have been moved to other apps
+ (snmp), or removed completely (os_mon).</p>
+ <p>
+ Own Id: OTP-14984 Aux Id: OTP-15329 </p>
+ </item>
+ <item>
+ <p>
+ [snmp|agent] Add a get-mechanism callback module (and a
+ corresponding behaviour). The agent calls this module to
+ handle each get (get, get-next and get-bulk) request.</p>
+ <p>
+ Own Id: OTP-15691 Aux Id: ERIERL-324 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SNMP 5.2.12</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Conversion of (agent) Audit Trail Log (ATL) failed due
+ to invalid log entries.</p> <p>The conversion aborted
+ completely midway because the ATL contained invalid
+ entries. The conversion has been improved so that it now
+ firstly handles encountered errors and write an
+ informative message (into the converted stream) and
+ secondly keeps count of the number of successful or
+ failed entry conversions. See <seealso
+ marker="snmpa#log_to_txt">log_to_txt</seealso> for more
+ info. </p> <p>The reason the ATL contained invalid
+ entries have also been fixed. The reason was that for
+ some outgoing messages (not response):</p> <list
+ type="bulleted"> <item> <p>encrypted (v3 messages)</p>
+ <p>Was logged "as is" (encrypted) without the info to
+ decrypt, making conversion impossible (which was the
+ reason the log contained bad entries).</p> </item> <item>
+ <p>un-encrypted</p> <p>Was not logged at all. </p>
+ </item> </list>
+ <p>
+ Own Id: OTP-15287 Aux Id: ERIERL-206 </p>
+ </item>
+ <item>
+ <p>
+ [compiler] Spurious version message removed. The snmp mib
+ compiler printed an spurious version message if the
+ 'version' option was provided.</p>
+ <p>
+ Own Id: OTP-15290</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+ <section><title>SNMP 5.2.11.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ [snmp|agent] Add a get-mechanism callback module (and a
+ corresponding behaviour). The agent calls this module to
+ handle each get (get, get-next and get-bulk) request.</p>
+ <p>
+ Own Id: OTP-15691 Aux Id: ERIERL-324 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SNMP 5.2.11</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The Snmp MIB compiler now allows using a
+ TEXTUAL-CONVENTION type before defining it.</p>
+ <p>
+ Own Id: OTP-14196 Aux Id: ERIERL-161 </p>
+ </item>
+ </list>
+ </section>
+
+ </section>
+
+<section><title>SNMP 5.2.10</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/snmp/doc/src/snmp.xml b/lib/snmp/doc/src/snmp.xml
index 801193675c..d20f1a8d06 100644
--- a/lib/snmp/doc/src/snmp.xml
+++ b/lib/snmp/doc/src/snmp.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmp.xml</file>
</header>
- <module>snmp</module>
+ <module since="">snmp</module>
<modulesummary>Interface functions to the SNMP toolkit</modulesummary>
<description>
<p>The module <c>snmp</c> contains interface functions to the
@@ -56,7 +56,7 @@
<funcs>
<func>
- <name>config() -> ok | {error, Reason}</name>
+ <name since="">config() -> ok | {error, Reason}</name>
<fsummary>Configure with a simple interactive tool</fsummary>
<desc>
<p>A simple interactive configuration tool. Simple
@@ -78,8 +78,8 @@
</func>
<func>
- <name>start() -> ok | {error, Reason}</name>
- <name>start(Type) -> ok | {error, Reason}</name>
+ <name since="">start() -> ok | {error, Reason}</name>
+ <name since="">start(Type) -> ok | {error, Reason}</name>
<fsummary>Start the SNMP application</fsummary>
<type>
<v>Type = start_type()</v>
@@ -93,8 +93,8 @@
</func>
<func>
- <name>start_agent() -> ok | {error, Reason}</name>
- <name>start_agent(Type) -> ok | {error, Reason}</name>
+ <name since="">start_agent() -> ok | {error, Reason}</name>
+ <name since="">start_agent(Type) -> ok | {error, Reason}</name>
<fsummary>Start the agent part of the SNMP application</fsummary>
<type>
<v>Type = start_type()</v>
@@ -117,8 +117,8 @@
</func>
<func>
- <name>start_manager() -> ok | {error, Reason}</name>
- <name>start_manager(Type) -> ok | {error, Reason}</name>
+ <name since="">start_manager() -> ok | {error, Reason}</name>
+ <name since="">start_manager(Type) -> ok | {error, Reason}</name>
<fsummary>Start the manager part of the SNMP application</fsummary>
<type>
<v>Type = start_type()</v>
@@ -141,7 +141,7 @@
</func>
<func>
- <name>date_and_time() -> DateAndTime</name>
+ <name since="">date_and_time() -> DateAndTime</name>
<fsummary>Return the current date and time as an OCTET STRING</fsummary>
<type>
<v>DateAndTime = [int()]</v>
@@ -155,7 +155,7 @@
</func>
<func>
- <name>date_and_time_to_universal_time_dst(DateAndTime) -> [utc()]</name>
+ <name since="">date_and_time_to_universal_time_dst(DateAndTime) -> [utc()]</name>
<fsummary>Convert a DateAndTime value to a list of possible utc()</fsummary>
<type>
<v>DateAndTime = [int()]</v>
@@ -171,8 +171,8 @@
</func>
<func>
- <name>date_and_time_to_string(DateAndTime) -> string()</name>
- <name>date_and_time_to_string(DateAndTime, Validate) -> string()</name>
+ <name since="">date_and_time_to_string(DateAndTime) -> string()</name>
+ <name since="">date_and_time_to_string(DateAndTime, Validate) -> string()</name>
<fsummary>Convert a DateAndTime value to a string</fsummary>
<type>
<v>DateAndTime = [int()]</v>
@@ -194,7 +194,7 @@
</func>
<func>
- <name>date_and_time_to_string2(DateAndTime) -> string()</name>
+ <name since="">date_and_time_to_string2(DateAndTime) -> string()</name>
<fsummary>Convert a DateAndTime value to a string</fsummary>
<type>
<v>DateAndTime = [int()]</v>
@@ -210,7 +210,7 @@
</func>
<func>
- <name>local_time_to_date_and_time_dst(Local) -> [DateAndTime]</name>
+ <name since="">local_time_to_date_and_time_dst(Local) -> [DateAndTime]</name>
<fsummary>Convert a Local time value to a list of possible DateAndTime(s)</fsummary>
<type>
<v>Local = {{Y,Mo,D},{H,M,S}}</v>
@@ -226,7 +226,7 @@
</func>
<func>
- <name>universal_time_to_date_and_time(UTC) -> DateAndTime</name>
+ <name since="">universal_time_to_date_and_time(UTC) -> DateAndTime</name>
<fsummary>Convert a UTC value to DateAndTime</fsummary>
<type>
<v>UTC = {{Y,Mo,D},{H,M,S}}</v>
@@ -241,8 +241,8 @@
</func>
<func>
- <name>validate_date_and_time(DateAndTime) -> bool()</name>
- <name>validate_date_and_time(DateAndTime, Validate) -> bool()</name>
+ <name since="">validate_date_and_time(DateAndTime) -> bool()</name>
+ <name since="">validate_date_and_time(DateAndTime, Validate) -> bool()</name>
<fsummary>Check if a DateAndTime value is correct</fsummary>
<type>
<v>DateAndTime = term()</v>
@@ -279,7 +279,7 @@
</func>
<func>
- <name>passwd2localized_key(Alg, Passwd, EngineID) -> Key</name>
+ <name since="">passwd2localized_key(Alg, Passwd, EngineID) -> Key</name>
<fsummary>Generates an localized key</fsummary>
<type>
<v>Alg = algorithm()</v>
@@ -298,7 +298,7 @@
</func>
<func>
- <name>octet_string_to_bits(S) -> Val</name>
+ <name since="">octet_string_to_bits(S) -> Val</name>
<fsummary>Convert an OCTET-STRING to BITS</fsummary>
<type>
<v>Val = bits()</v>
@@ -312,7 +312,7 @@
</func>
<func>
- <name>bits_to_octet_string(B) -> Val</name>
+ <name since="">bits_to_octet_string(B) -> Val</name>
<fsummary>Convert an OCTET-STRING to BITS</fsummary>
<type>
<v>Val = octet_string()</v>
@@ -326,7 +326,7 @@
</func>
<func>
- <name>read_mib(FileName) -> {ok, mib()} | {error, Reason}</name>
+ <name since="">read_mib(FileName) -> {ok, mib()} | {error, Reason}</name>
<fsummary></fsummary>
<type>
<v>FileName = string()</v>
@@ -341,10 +341,10 @@
</func>
<func>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Block | Stop) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop, Block) -> ok | {error, Reason}</name>
+ <name since="">log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="">log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="">log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Block | Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="OTP R16B03">log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop, Block) -> ok | {ok, Cnt} | {error, Reason}</name>
<fsummary>Convert an Audit Trail Log to text format</fsummary>
<type>
<v>LogDir = string()</v>
@@ -355,6 +355,9 @@
<v>LogFile = string()</v>
<v>Start = Stop = null | datetime() | {local_time,datetime()} | {universal_time,datetime()} </v>
<v>Block = boolean()</v>
+ <v>Cnt = {NumOK, NumERR}</v>
+ <v>NumOK = non_neg_integer()</v>
+ <v>NumERR = pos_integer()</v>
<v>Reason = term()</v>
</type>
<desc>
@@ -394,16 +397,25 @@
and <c>Vsn</c> is the SNMP version. <c>PDU</c> is a textual
version of the protocol data unit. There is a new line
between <c>Vsn</c> and <c>PDU</c>.</p>
+
+ <p>If the entire log is successfully converted, the function
+ will return <c>ok</c>.
+ If one of more entries fail to convert, the function will instead
+ return <c>{ok, {NumOK, NumERR}}</c>, where the counters indicate
+ how many valid and erroneous entries where found.
+ If instead <c>{error, Reason}</c> is returned, the conversion
+ encountered a fatal error and where either never done of aborted
+ midway. </p>
<marker id="log_to_io"></marker>
</desc>
</func>
<func>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Block | Stop) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop, Block) -> ok | {error, Reason}</name>
+ <name since="OTP R15B01">log_to_io(LogDir, Mibs, LogName, LogFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="OTP R15B01">log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="OTP R15B01">log_to_io(LogDir, Mibs, LogName, LogFile, Start, Block | Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="OTP R16B03">log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop, Block) -> ok | {ok, Cnt} | {error, Reason}</name>
<fsummary>Convert an Audit Trail Log to text format</fsummary>
<type>
<v>LogDir = string()</v>
@@ -412,6 +424,9 @@
<v>LogName = string()</v>
<v>LogFile = string()</v>
<v>Start = Stop = null | datetime() | {local_time,datetime()} | {universal_time,datetime()} </v>
+ <v>Cnt = {NumOK, NumERR}</v>
+ <v>NumOK = non_neg_integer()</v>
+ <v>NumERR = pos_integer()</v>
<v>Reason = term()</v>
</type>
<desc>
@@ -425,7 +440,7 @@
</func>
<func>
- <name>change_log_size(LogName, NewSize) -> ok | {error, Reason}</name>
+ <name since="">change_log_size(LogName, NewSize) -> ok | {error, Reason}</name>
<fsummary>Change the size of the Audit Trail Log</fsummary>
<type>
<v>LogName = string()</v>
@@ -448,8 +463,8 @@
</func>
<func>
- <name>print_version_info() -> void()</name>
- <name>print_version_info(Prefix) -> void()</name>
+ <name since="">print_version_info() -> void()</name>
+ <name since="">print_version_info(Prefix) -> void()</name>
<fsummary>Formatted print of result of the versions functions</fsummary>
<type>
<v>Prefix = string() | integer()</v>
@@ -469,8 +484,8 @@
</func>
<func>
- <name>versions1() -> {ok, Info} | {error, Reason}</name>
- <name>versions2() -> {ok, Info} | {error, Reason}</name>
+ <name since="">versions1() -> {ok, Info} | {error, Reason}</name>
+ <name since="">versions2() -> {ok, Info} | {error, Reason}</name>
<fsummary>Retrieve various system and application info</fsummary>
<type>
<v>Info = [info()]</v>
@@ -489,8 +504,8 @@
</func>
<func>
- <name>print_versions(VersionInfo) -> void()</name>
- <name>print_versions(Prefix, VersionInfo) -> void()</name>
+ <name since="">print_versions(VersionInfo) -> void()</name>
+ <name since="">print_versions(Prefix, VersionInfo) -> void()</name>
<fsummary>Formatted print of result of the versions functions</fsummary>
<type>
<v>VersionInfo = [version_info()]</v>
@@ -512,7 +527,7 @@
</func>
<func>
- <name>enable_trace() -> void()</name>
+ <name since="">enable_trace() -> void()</name>
<fsummary>Starts a tracer</fsummary>
<!--
<type>
@@ -528,7 +543,7 @@
</func>
<func>
- <name>disable_trace() -> void()</name>
+ <name since="">disable_trace() -> void()</name>
<fsummary>Stop the tracer</fsummary>
<!--
<type>
@@ -543,7 +558,7 @@
</func>
<func>
- <name>set_trace(Targets) -> void()</name>
+ <name since="">set_trace(Targets) -> void()</name>
<fsummary>Set trace target</fsummary>
<type>
<v>Targets = target() | targets()</v>
@@ -567,7 +582,7 @@
</func>
<func>
- <name>reset_trace(Targets) -> void()</name>
+ <name since="">reset_trace(Targets) -> void()</name>
<fsummary>Reset trace target</fsummary>
<type>
<v>Targets = module() | modules()</v>
@@ -583,7 +598,7 @@
</func>
<func>
- <name>set_trace(Targets, Opts) -> void()</name>
+ <name since="">set_trace(Targets, Opts) -> void()</name>
<fsummary>Set trace target</fsummary>
<type>
<v>Targets = target() | targets()</v>
diff --git a/lib/snmp/doc/src/snmp_community_mib.xml b/lib/snmp/doc/src/snmp_community_mib.xml
index 61dea05950..9800fb6c00 100644
--- a/lib/snmp/doc/src/snmp_community_mib.xml
+++ b/lib/snmp/doc/src/snmp_community_mib.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmp_community_mib.xml</file>
</header>
- <module>snmp_community_mib</module>
+ <module since="">snmp_community_mib</module>
<modulesummary>Instrumentation Functions for SNMP-COMMUNITY-MIB</modulesummary>
<description>
<p>The module <c>snmp_community_mib</c> implements the instrumentation
@@ -45,7 +45,7 @@
<funcs>
<func>
- <name>configure(ConfDir) -> void()</name>
+ <name since="">configure(ConfDir) -> void()</name>
<fsummary>Configure the SNMP-COMMUNITY-MIB</fsummary>
<type>
<v>ConfDir = string()</v>
@@ -77,7 +77,7 @@
</func>
<func>
- <name>reconfigure(ConfDir) -> void()</name>
+ <name since="">reconfigure(ConfDir) -> void()</name>
<fsummary>Configure the SNMP-COMMUNITY-MIB</fsummary>
<type>
<v>ConfDir = string()</v>
@@ -108,8 +108,8 @@
</func>
<func>
- <name>add_community(Idx, CommName, SecName, CtxName, TransportTag) -> Ret</name>
- <name>add_community(Idx, CommName, SecName, EngineId, CtxName, TransportTag) -> Ret</name>
+ <name since="">add_community(Idx, CommName, SecName, CtxName, TransportTag) -> Ret</name>
+ <name since="OTP R14B03">add_community(Idx, CommName, SecName, EngineId, CtxName, TransportTag) -> Ret</name>
<fsummary>Added one community</fsummary>
<type>
<v>Idx = string()</v>
@@ -132,7 +132,7 @@
</func>
<func>
- <name>delete_community(Key) -> Ret</name>
+ <name since="">delete_community(Key) -> Ret</name>
<fsummary>Delete one community</fsummary>
<type>
<v>Key = term()</v>
diff --git a/lib/snmp/doc/src/snmp_framework_mib.xml b/lib/snmp/doc/src/snmp_framework_mib.xml
index 64e5df6ff5..d84327d4d5 100644
--- a/lib/snmp/doc/src/snmp_framework_mib.xml
+++ b/lib/snmp/doc/src/snmp_framework_mib.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmp_framework_mib.xml</file>
</header>
- <module>snmp_framework_mib</module>
+ <module since="">snmp_framework_mib</module>
<modulesummary>Instrumentation Functions for SNMP-FRAMEWORK-MIB</modulesummary>
<description>
<p>The module <c>snmp_framework_mib</c> implements instrumentation
@@ -44,7 +44,7 @@
</description>
<funcs>
<func>
- <name>configure(ConfDir) -> void()</name>
+ <name since="">configure(ConfDir) -> void()</name>
<fsummary>Configure the SNMP-FRAMEWORK-MIB</fsummary>
<type>
<v>ConfDir = string()</v>
@@ -75,7 +75,7 @@
</desc>
</func>
<func>
- <name>init() -> void()</name>
+ <name since="">init() -> void()</name>
<fsummary>Initialize the SNMP-FRAMEWORK-MIB</fsummary>
<desc>
<p>This function is called from the supervisor at system
@@ -88,7 +88,7 @@
</desc>
</func>
<func>
- <name>add_context(Ctx) -> Ret</name>
+ <name since="">add_context(Ctx) -> Ret</name>
<fsummary>Added one context</fsummary>
<type>
<v>Ctx = string()</v>
@@ -103,7 +103,7 @@
</desc>
</func>
<func>
- <name>delete_context(Key) -> Ret</name>
+ <name since="">delete_context(Key) -> Ret</name>
<fsummary>Delete one context</fsummary>
<type>
<v>Key = term()</v>
diff --git a/lib/snmp/doc/src/snmp_generic.xml b/lib/snmp/doc/src/snmp_generic.xml
index 44762dec59..6fb714907c 100644
--- a/lib/snmp/doc/src/snmp_generic.xml
+++ b/lib/snmp/doc/src/snmp_generic.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmp_generic.xml</file>
</header>
- <module>snmp_generic</module>
+ <module since="">snmp_generic</module>
<modulesummary>Generic Functions for Implementing SNMP Objects in a Database</modulesummary>
<description>
<marker id="description"></marker>
@@ -127,8 +127,8 @@ value() = term()
<funcs>
<func>
- <name>get_status_col(Name, Cols)</name>
- <name>get_status_col(NameDb, Cols) -> {ok, StatusVal} | false</name>
+ <name since="">get_status_col(Name, Cols)</name>
+ <name since="">get_status_col(NameDb, Cols) -> {ok, StatusVal} | false</name>
<fsummary>Get the value of the status column from <c>Cols</c></fsummary>
<type>
<v>Name = name()</v>
@@ -148,7 +148,7 @@ value() = term()
</func>
<func>
- <name>get_index_types(Name)</name>
+ <name since="">get_index_types(Name)</name>
<fsummary>Get the index types of <c>Name</c></fsummary>
<type>
<v>Name = name()</v>
@@ -163,7 +163,7 @@ value() = term()
</func>
<func>
- <name>get_table_info(Name, Item) -> table_info_result()</name>
+ <name since="OTP R15B01">get_table_info(Name, Item) -> table_info_result()</name>
<fsummary>Get table info item of MIB table <c>Name</c></fsummary>
<type>
<v>Name = name()</v>
@@ -187,8 +187,8 @@ value() = term()
</func>
<func>
- <name>table_func(Op1, NameDb)</name>
- <name>table_func(Op2, RowIndex, Cols, NameDb) -> Ret</name>
+ <name since="">table_func(Op1, NameDb)</name>
+ <name since="">table_func(Op2, RowIndex, Cols, NameDb) -> Ret</name>
<fsummary>Default instrumentation function for tables</fsummary>
<type>
<v>Op1 = new | delete </v>
@@ -232,7 +232,7 @@ value() = term()
</func>
<func>
- <name>table_get_elements(NameDb, RowIndex, Cols) -> Values</name>
+ <name since="">table_get_elements(NameDb, RowIndex, Cols) -> Values</name>
<fsummary>Get elements in a table row</fsummary>
<type>
<v>NameDb = name_db()</v>
@@ -249,7 +249,7 @@ value() = term()
</func>
<func>
- <name>table_next(NameDb, RestOid) -> RowIndex | endOfTable</name>
+ <name since="">table_next(NameDb, RestOid) -> RowIndex | endOfTable</name>
<fsummary>Find the next row in the table</fsummary>
<type>
<v>NameDb = name_db()</v>
@@ -265,7 +265,7 @@ value() = term()
</func>
<func>
- <name>table_row_exists(NameDb, RowIndex) -> bool()</name>
+ <name since="">table_row_exists(NameDb, RowIndex) -> bool()</name>
<fsummary>Check if a row in a table exists</fsummary>
<type>
<v>NameDb = name_db()</v>
@@ -279,7 +279,7 @@ value() = term()
</func>
<func>
- <name>table_set_elements(NameDb, RowIndex, Cols) -> bool()</name>
+ <name since="">table_set_elements(NameDb, RowIndex, Cols) -> bool()</name>
<fsummary>Set elements in a table row</fsummary>
<type>
<v>NameDb = name_db()</v>
@@ -300,8 +300,8 @@ value() = term()
</func>
<func>
- <name>variable_func(Op1, NameDb)</name>
- <name>variable_func(Op2, Val, NameDb) -> Ret</name>
+ <name since="">variable_func(Op1, NameDb)</name>
+ <name since="">variable_func(Op2, Val, NameDb) -> Ret</name>
<fsummary>Default instrumentation function for tables</fsummary>
<type>
<v>Op1 = new | delete | get</v>
@@ -325,7 +325,7 @@ value() = term()
</func>
<func>
- <name>variable_get(NameDb) -> {value, Value} | undefined</name>
+ <name since="">variable_get(NameDb) -> {value, Value} | undefined</name>
<fsummary>Get the value of a variable</fsummary>
<type>
<v>NameDb = name_db()</v>
@@ -339,7 +339,7 @@ value() = term()
</func>
<func>
- <name>variable_set(NameDb, NewVal) -> true | false</name>
+ <name since="">variable_set(NameDb, NewVal) -> true | false</name>
<fsummary>Set a value for a variable</fsummary>
<type>
<v>NameDb = name_db()</v>
diff --git a/lib/snmp/doc/src/snmp_impl_example_agent.xml b/lib/snmp/doc/src/snmp_impl_example_agent.xml
index e576fa51f3..7dda3dd5cd 100644
--- a/lib/snmp/doc/src/snmp_impl_example_agent.xml
+++ b/lib/snmp/doc/src/snmp_impl_example_agent.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/snmp/doc/src/snmp_index.xml b/lib/snmp/doc/src/snmp_index.xml
index 646e9661a3..1497f4cf67 100644
--- a/lib/snmp/doc/src/snmp_index.xml
+++ b/lib/snmp/doc/src/snmp_index.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmp_index.xml</file>
</header>
- <module>snmp_index</module>
+ <module since="">snmp_index</module>
<modulesummary>Abstract Data Type for SNMP Indexing</modulesummary>
<description>
<p>The module <c>snmp_index</c> implements an Abstract
@@ -159,7 +159,7 @@ get_next_pid(Oid, SnmpIndex) ->
</section>
<funcs>
<func>
- <name>delete(Index) -> true</name>
+ <name since="">delete(Index) -> true</name>
<fsummary>Delete an index table</fsummary>
<type>
<v>Index = NewIndex = index()</v>
@@ -173,7 +173,7 @@ get_next_pid(Oid, SnmpIndex) ->
</desc>
</func>
<func>
- <name>delete(Index, Key) -> NewIndex</name>
+ <name since="">delete(Index, Key) -> NewIndex</name>
<fsummary>Delete an item from the index</fsummary>
<type>
<v>Index = NewIndex = index()</v>
@@ -185,7 +185,7 @@ get_next_pid(Oid, SnmpIndex) ->
</desc>
</func>
<func>
- <name>get(Index, KeyOid) -> {ok, {KeyOid, Value}} | undefined</name>
+ <name since="">get(Index, KeyOid) -> {ok, {KeyOid, Value}} | undefined</name>
<fsummary>Get the item with <c>KeyOid</c></fsummary>
<type>
<v>Index = index()</v>
@@ -198,7 +198,7 @@ get_next_pid(Oid, SnmpIndex) ->
</desc>
</func>
<func>
- <name>get_last(Index) -> {ok, {KeyOid, Value}} | undefined</name>
+ <name since="">get_last(Index) -> {ok, {KeyOid, Value}} | undefined</name>
<fsummary>Get the last item in the index structure</fsummary>
<type>
<v>Index = index()</v>
@@ -210,7 +210,7 @@ get_next_pid(Oid, SnmpIndex) ->
</desc>
</func>
<func>
- <name>get_next(Index, KeyOid) -> {ok, {NextKeyOid, Value}} | undefined</name>
+ <name since="">get_next(Index, KeyOid) -> {ok, {NextKeyOid, Value}} | undefined</name>
<fsummary>Get the next item</fsummary>
<type>
<v>Index = index()</v>
@@ -224,7 +224,7 @@ get_next_pid(Oid, SnmpIndex) ->
</desc>
</func>
<func>
- <name>insert(Index, Key, Value) -> NewIndex</name>
+ <name since="">insert(Index, Key, Value) -> NewIndex</name>
<fsummary>Insert an item into the index</fsummary>
<type>
<v>Index = NewIndex = index()</v>
@@ -238,7 +238,7 @@ get_next_pid(Oid, SnmpIndex) ->
</desc>
</func>
<func>
- <name>key_to_oid(Index, Key) -> KeyOid</name>
+ <name since="">key_to_oid(Index, Key) -> KeyOid</name>
<fsummary>Convert a key to an OBJECT IDENTIFIER</fsummary>
<type>
<v>Index = index()</v>
@@ -250,7 +250,7 @@ get_next_pid(Oid, SnmpIndex) ->
</desc>
</func>
<func>
- <name>new(KeyTypes) -> Index</name>
+ <name since="">new(KeyTypes) -> Index</name>
<fsummary>Create a new snmp index structure</fsummary>
<type>
<v>KeyTypes = key_types()</v>
diff --git a/lib/snmp/doc/src/snmp_notification_mib.xml b/lib/snmp/doc/src/snmp_notification_mib.xml
index d2e288ec15..9395edf155 100644
--- a/lib/snmp/doc/src/snmp_notification_mib.xml
+++ b/lib/snmp/doc/src/snmp_notification_mib.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmp_notification_mib.xml</file>
</header>
- <module>snmp_notification_mib</module>
+ <module since="">snmp_notification_mib</module>
<modulesummary>Instrumentation Functions for SNMP-NOTIFICATION-MIB</modulesummary>
<description>
<p>The module <c>snmp_notification_mib</c> implements the
@@ -43,7 +43,7 @@
</description>
<funcs>
<func>
- <name>configure(ConfDir) -> void()</name>
+ <name since="">configure(ConfDir) -> void()</name>
<fsummary>Configure the SNMP-NOTIFICATION-MIB</fsummary>
<type>
<v>ConfDir = string()</v>
@@ -70,7 +70,7 @@
</desc>
</func>
<func>
- <name>reconfigure(ConfDir) -> void()</name>
+ <name since="">reconfigure(ConfDir) -> void()</name>
<fsummary>Configure the SNMP-NOTIFICATION-MIB</fsummary>
<type>
<v>ConfDir = string()</v>
@@ -98,7 +98,7 @@
</desc>
</func>
<func>
- <name>add_notify(Name, Tag, Type) -> Ret</name>
+ <name since="">add_notify(Name, Tag, Type) -> Ret</name>
<fsummary>Added one notify definition</fsummary>
<type>
<v>Name = string()</v>
@@ -115,7 +115,7 @@
</desc>
</func>
<func>
- <name>delete_notify(Key) -> Ret</name>
+ <name since="">delete_notify(Key) -> Ret</name>
<fsummary>Delete one notify definition</fsummary>
<type>
<v>Key = term()</v>
diff --git a/lib/snmp/doc/src/snmp_pdus.xml b/lib/snmp/doc/src/snmp_pdus.xml
index 1d086e6f48..f403b6edf4 100644
--- a/lib/snmp/doc/src/snmp_pdus.xml
+++ b/lib/snmp/doc/src/snmp_pdus.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmp_pdus.xml</file>
</header>
- <module>snmp_pdus</module>
+ <module since="">snmp_pdus</module>
<modulesummary>Encode and Decode Functions for SNMP PDUs</modulesummary>
<description>
<p>RFC1157, RFC1905 and/or RFC2272 should be studied carefully
@@ -55,7 +55,7 @@
</description>
<funcs>
<func>
- <name>dec_message([byte()]) -> Message</name>
+ <name since="">dec_message([byte()]) -> Message</name>
<fsummary>Decode an SNMP Message</fsummary>
<type>
<v>Message = #message</v>
@@ -71,7 +71,7 @@
</desc>
</func>
<func>
- <name>dec_message_only([byte()]) -> Message</name>
+ <name since="">dec_message_only([byte()]) -> Message</name>
<fsummary>Decode an SNMP Message, but not the data part</fsummary>
<type>
<v>Message = #message</v>
@@ -84,7 +84,7 @@
</desc>
</func>
<func>
- <name>dec_pdu([byte()]) -> Pdu</name>
+ <name since="">dec_pdu([byte()]) -> Pdu</name>
<fsummary>Decode an SNMP Pdu</fsummary>
<type>
<v>Pdu = #pdu</v>
@@ -94,7 +94,7 @@
</desc>
</func>
<func>
- <name>dec_scoped_pdu([byte()]) -> ScopedPdu</name>
+ <name since="">dec_scoped_pdu([byte()]) -> ScopedPdu</name>
<fsummary>Decode an SNMP ScopedPdu</fsummary>
<type>
<v>ScopedPdu = #scoped_pdu</v>
@@ -104,7 +104,7 @@
</desc>
</func>
<func>
- <name>dec_scoped_pdu_data([byte()]) -> ScopedPduData</name>
+ <name since="">dec_scoped_pdu_data([byte()]) -> ScopedPduData</name>
<fsummary>Decode an SNMP ScopedPduData</fsummary>
<type>
<v>ScopedPduData = #scoped_pdu | EncryptedPDU</v>
@@ -116,7 +116,7 @@
</desc>
</func>
<func>
- <name>dec_usm_security_parameters([byte()]) -> UsmSecParams</name>
+ <name since="">dec_usm_security_parameters([byte()]) -> UsmSecParams</name>
<fsummary>Decode SNMP UsmSecurityParameters</fsummary>
<type>
<v>UsmSecParams = #usmSecurityParameters</v>
@@ -126,7 +126,7 @@
</desc>
</func>
<func>
- <name>enc_encrypted_scoped_pdu(EncryptedScopedPdu) -> [byte()]</name>
+ <name since="">enc_encrypted_scoped_pdu(EncryptedScopedPdu) -> [byte()]</name>
<fsummary>Encode an encrypted SNMP scopedPDU</fsummary>
<type>
<v>EncryptedScopedPdu = [byte()]</v>
@@ -142,7 +142,7 @@
</desc>
</func>
<func>
- <name>enc_message(Message) -> [byte()]</name>
+ <name since="">enc_message(Message) -> [byte()]</name>
<fsummary>Encode an SNMP Message</fsummary>
<type>
<v>Message = #message</v>
@@ -152,7 +152,7 @@
</desc>
</func>
<func>
- <name>enc_message_only(Message) -> [byte()]</name>
+ <name since="">enc_message_only(Message) -> [byte()]</name>
<fsummary>Encode an SNMP Message, but not the data part</fsummary>
<type>
<v>Message = #message</v>
@@ -166,7 +166,7 @@
</desc>
</func>
<func>
- <name>enc_pdu(Pd) -> [byte()]</name>
+ <name since="">enc_pdu(Pd) -> [byte()]</name>
<fsummary>Encode an SNMP Pdu</fsummary>
<type>
<v>Pdu = #pdu</v>
@@ -176,7 +176,7 @@
</desc>
</func>
<func>
- <name>enc_scoped_pdu(ScopedPdu) -> [byte()]</name>
+ <name since="">enc_scoped_pdu(ScopedPdu) -> [byte()]</name>
<fsummary>Encode an SNMP scopedPDU</fsummary>
<type>
<v>ScopedPdu = #scoped_pdu</v>
@@ -190,7 +190,7 @@
</desc>
</func>
<func>
- <name>enc_usm_security_parameters(UsmSecParams) -> [byte()]</name>
+ <name since="">enc_usm_security_parameters(UsmSecParams) -> [byte()]</name>
<fsummary>Encode SNMP UsmSecurityParameters</fsummary>
<type>
<v>UsmSecParams = #usmSecurityParameters</v>
diff --git a/lib/snmp/doc/src/snmp_standard_mib.xml b/lib/snmp/doc/src/snmp_standard_mib.xml
index 35efbba483..eb4e2fd097 100644
--- a/lib/snmp/doc/src/snmp_standard_mib.xml
+++ b/lib/snmp/doc/src/snmp_standard_mib.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmp_standard_mib.xml</file>
</header>
- <module>snmp_standard_mib</module>
+ <module since="">snmp_standard_mib</module>
<modulesummary>Instrumentation Functions for STANDARD-MIB and SNMPv2-MIB</modulesummary>
<description>
<p>The module <c>snmp_standard_mib</c> implements the instrumentation functions for the
@@ -42,7 +42,7 @@
</description>
<funcs>
<func>
- <name>configure(ConfDir) -> void()</name>
+ <name since="">configure(ConfDir) -> void()</name>
<fsummary>Configure the STANDARD-MIB and SNMPv2-MIB</fsummary>
<type>
<v>ConfDir = string()</v>
@@ -71,8 +71,8 @@
</desc>
</func>
<func>
- <name>inc(Name) -> void()</name>
- <name>inc(Name, N) -> void()</name>
+ <name since="">inc(Name) -> void()</name>
+ <name since="">inc(Name, N) -> void()</name>
<fsummary>Increment a variable in the MIB</fsummary>
<type>
<v>Name = atom()</v>
@@ -84,7 +84,7 @@
</desc>
</func>
<func>
- <name>reconfigure(ConfDir) -> void()</name>
+ <name since="">reconfigure(ConfDir) -> void()</name>
<fsummary>Configure the STANDARD-MIB and SNMPv2-MIB</fsummary>
<type>
<v>ConfDir = string()</v>
@@ -114,14 +114,14 @@
</desc>
</func>
<func>
- <name>reset() -> void()</name>
+ <name since="">reset() -> void()</name>
<fsummary>Reset all <c>snmp</c>counters to 0</fsummary>
<desc>
<p>Resets all <c>snmp</c> counters to 0.</p>
</desc>
</func>
<func>
- <name>sys_up_time() -> Time</name>
+ <name since="">sys_up_time() -> Time</name>
<fsummary>Get the system up time</fsummary>
<type>
<v>Time = int()</v>
diff --git a/lib/snmp/doc/src/snmp_target_mib.xml b/lib/snmp/doc/src/snmp_target_mib.xml
index c3bcd3b4e3..c46edb810d 100644
--- a/lib/snmp/doc/src/snmp_target_mib.xml
+++ b/lib/snmp/doc/src/snmp_target_mib.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmp_target_mib.xml</file>
</header>
- <module>snmp_target_mib</module>
+ <module since="">snmp_target_mib</module>
<modulesummary>Instrumentation Functions for SNMP-TARGET-MIB</modulesummary>
<description>
<p>The module <c>snmp_target_mib</c> implements the instrumentation
@@ -57,7 +57,7 @@
<funcs>
<func>
- <name>configure(ConfDir) -> void()</name>
+ <name since="">configure(ConfDir) -> void()</name>
<fsummary>Configure the SNMP-TARGET-MIB</fsummary>
<type>
<v>ConfDir = string()</v>
@@ -85,7 +85,7 @@
</func>
<func>
- <name>reconfigure(ConfDir) -> void()</name>
+ <name since="">reconfigure(ConfDir) -> void()</name>
<fsummary>Configure the SNMP-TARGET-MIB</fsummary>
<type>
<v>ConfDir = string()</v>
@@ -113,7 +113,7 @@
</func>
<func>
- <name>set_target_engine_id(TargetAddrName, EngineId) -> boolean()</name>
+ <name since="">set_target_engine_id(TargetAddrName, EngineId) -> boolean()</name>
<fsummary>Set the engine id for a targetAddr row.</fsummary>
<type>
<v>TargetAddrName = string()</v>
@@ -130,7 +130,7 @@
</func>
<func>
- <name>add_addr(Name, Domain, Addr, Timeout, Retry, TagList, Params, EngineId, TMask, MMS) -> Ret</name>
+ <name since="">add_addr(Name, Domain, Addr, Timeout, Retry, TagList, Params, EngineId, TMask, MMS) -> Ret</name>
<fsummary>Add one target address definition</fsummary>
<type>
<v>Name = string()</v>
@@ -156,7 +156,7 @@
</func>
<func>
- <name>delete_addr(Key) -> Ret</name>
+ <name since="">delete_addr(Key) -> Ret</name>
<fsummary>Delete one target address definition</fsummary>
<type>
<v>Key = term()</v>
@@ -171,7 +171,7 @@
</func>
<func>
- <name>add_params(Name, MPModel, SecModel, SecName, SecLevel) -> Ret</name>
+ <name since="">add_params(Name, MPModel, SecModel, SecName, SecLevel) -> Ret</name>
<fsummary>Add one target parameter definition</fsummary>
<type>
<v>Name = string()</v>
@@ -191,7 +191,7 @@
</desc>
</func>
<func>
- <name>delete_params(Key) -> Ret</name>
+ <name since="">delete_params(Key) -> Ret</name>
<fsummary>Delete one target parameter definition</fsummary>
<type>
<v>Key = term()</v>
diff --git a/lib/snmp/doc/src/snmp_user_based_sm_mib.xml b/lib/snmp/doc/src/snmp_user_based_sm_mib.xml
index cc376ac118..6c2203ed22 100644
--- a/lib/snmp/doc/src/snmp_user_based_sm_mib.xml
+++ b/lib/snmp/doc/src/snmp_user_based_sm_mib.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmp_user_based_sm_mib.xml</file>
</header>
- <module>snmp_user_based_sm_mib</module>
+ <module since="">snmp_user_based_sm_mib</module>
<modulesummary>Instrumentation Functions for SNMP-USER-BASED-SM-MIB</modulesummary>
<description>
<p>The module <c>snmp_user_based_sm_mib</c> implements the instrumentation
@@ -43,7 +43,7 @@
</description>
<funcs>
<func>
- <name>configure(ConfDir) -> void()</name>
+ <name since="">configure(ConfDir) -> void()</name>
<fsummary>Configure the SNMP-USER-BASED-SM-MIB</fsummary>
<type>
<v>ConfDir = string()</v>
@@ -72,7 +72,7 @@
</desc>
</func>
<func>
- <name>reconfigure(ConfDir) -> void()</name>
+ <name since="">reconfigure(ConfDir) -> void()</name>
<fsummary>Configure the SNMP-USER-BASED-SM-MIB</fsummary>
<type>
<v>ConfDir = string()</v>
@@ -103,7 +103,7 @@
</desc>
</func>
<func>
- <name>add_user(EngineID, Name, SecName, Clone, AuthP, AuthKeyC, OwnAuthKeyC, PrivP, PrivKeyC, OwnPrivKeyC, Public, AuthKey, PrivKey) -> Ret</name>
+ <name since="">add_user(EngineID, Name, SecName, Clone, AuthP, AuthKeyC, OwnAuthKeyC, PrivP, PrivKeyC, OwnPrivKeyC, Public, AuthKey, PrivKey) -> Ret</name>
<fsummary>Add one user</fsummary>
<type>
<v>EngineID = string()</v>
@@ -130,7 +130,7 @@
</desc>
</func>
<func>
- <name>delete_user(Key) -> Ret</name>
+ <name since="">delete_user(Key) -> Ret</name>
<fsummary>Delete one user</fsummary>
<type>
<v>Key = term()</v>
diff --git a/lib/snmp/doc/src/snmp_view_based_acm_mib.xml b/lib/snmp/doc/src/snmp_view_based_acm_mib.xml
index fdad735e71..c5e98a3eb5 100644
--- a/lib/snmp/doc/src/snmp_view_based_acm_mib.xml
+++ b/lib/snmp/doc/src/snmp_view_based_acm_mib.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmp_view_based_acm_mib.xml</file>
</header>
- <module>snmp_view_based_acm_mib</module>
+ <module since="">snmp_view_based_acm_mib</module>
<modulesummary>Instrumentation Functions for SNMP-VIEW-BASED-ACM-MIB</modulesummary>
<description>
<p>The module <c>snmp_view_based_acm_mib</c> implements the instrumentation functions for the
@@ -45,7 +45,7 @@
<funcs>
<func>
- <name>configure(ConfDir) -> void()</name>
+ <name since="">configure(ConfDir) -> void()</name>
<fsummary>Configure the SNMP-VIEW-BASED-ACM-MIB</fsummary>
<type>
<v>ConfDir = string()</v>
@@ -71,7 +71,7 @@
</func>
<func>
- <name>reconfigure(ConfDir) -> void()</name>
+ <name since="">reconfigure(ConfDir) -> void()</name>
<fsummary>Configure the SNMP-VIEW-BASED-ACM-MIB</fsummary>
<type>
<v>ConfDir = string()</v>
@@ -104,7 +104,7 @@
</func>
<func>
- <name>add_sec2group(SecModel, SecName, GroupName) -> Ret</name>
+ <name since="">add_sec2group(SecModel, SecName, GroupName) -> Ret</name>
<fsummary>Add one security to group definition</fsummary>
<type>
<v>SecModel = v1 | v2c | usm</v>
@@ -124,7 +124,7 @@
</func>
<func>
- <name>delete_sec2group(Key) -> Ret</name>
+ <name since="">delete_sec2group(Key) -> Ret</name>
<fsummary>Delete one security to group definition</fsummary>
<type>
<v>Key = term()</v>
@@ -139,7 +139,7 @@
</func>
<func>
- <name>add_access(GroupName, Prefix, SecModel, SecLevel, Match, RV, WV, NV) -> Ret</name>
+ <name since="">add_access(GroupName, Prefix, SecModel, SecLevel, Match, RV, WV, NV) -> Ret</name>
<fsummary>Add one access definition</fsummary>
<type>
<v>GroupName = string()</v>
@@ -163,7 +163,7 @@
</func>
<func>
- <name>delete_access(Key) -> Ret</name>
+ <name since="">delete_access(Key) -> Ret</name>
<fsummary>Delete one access definition</fsummary>
<type>
<v>Key = term()</v>
@@ -178,7 +178,7 @@
</func>
<func>
- <name>add_view_tree_fam(ViewIndex, SubTree, Status, Mask) -> Ret</name>
+ <name since="">add_view_tree_fam(ViewIndex, SubTree, Status, Mask) -> Ret</name>
<fsummary>Add one view tree family definition</fsummary>
<type>
<v>ViewIndex = integer()</v>
@@ -199,7 +199,7 @@
</func>
<func>
- <name>delete_view_tree_fam(Key) -> Ret</name>
+ <name since="">delete_view_tree_fam(Key) -> Ret</name>
<fsummary>Delete one view tree family definition</fsummary>
<type>
<v>Key = term()</v>
diff --git a/lib/snmp/doc/src/snmpa.xml b/lib/snmp/doc/src/snmpa.xml
index d756ff7a65..dc2f4e6d66 100644
--- a/lib/snmp/doc/src/snmpa.xml
+++ b/lib/snmp/doc/src/snmpa.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2004</year><year>2016</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmpa.xml</file>
</header>
- <module>snmpa</module>
+ <module since="">snmpa</module>
<modulesummary>Interface Functions to the SNMP toolkit agent</modulesummary>
<description>
<p>The module <c>snmpa</c> contains interface functions to the
@@ -77,7 +77,7 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
<funcs>
<func>
- <name>add_agent_caps(SysORID, SysORDescr) -> SysORIndex</name>
+ <name since="">add_agent_caps(SysORID, SysORDescr) -> SysORIndex</name>
<fsummary>Add an AGENT-CAPABILITY definition to the agent</fsummary>
<type>
<v>SysORID = oid()</v>
@@ -93,7 +93,7 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>del_agent_caps(SysORIndex) -> void()</name>
+ <name since="">del_agent_caps(SysORIndex) -> void()</name>
<fsummary>Delete an AGENT-CAPABILITY definition from the agent</fsummary>
<type>
<v>SysORIndex = integer()</v>
@@ -108,7 +108,7 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>get_agent_caps() -> [[SysORIndex, SysORID, SysORDescr, SysORUpTime]]</name>
+ <name since="">get_agent_caps() -> [[SysORIndex, SysORID, SysORDescr, SysORUpTime]]</name>
<fsummary>Return all AGENT-CAPABILITY definitions in the agent</fsummary>
<type>
<v>SysORIndex = integer()</v>
@@ -125,8 +125,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>get(Agent, Vars) -> Values | {error, Reason}</name>
- <name>get(Agent, Vars, Context) -> Values | {error, Reason}</name>
+ <name since="">get(Agent, Vars) -> Values | {error, Reason}</name>
+ <name since="">get(Agent, Vars, Context) -> Values | {error, Reason}</name>
<fsummary>Perform a get operation on the agent</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -150,8 +150,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>get_next(Agent, Vars) -> Values | {error, Reason}</name>
- <name>get_next(Agent, Vars, Context) -> Values | {error, Reason}</name>
+ <name since="">get_next(Agent, Vars) -> Values | {error, Reason}</name>
+ <name since="">get_next(Agent, Vars, Context) -> Values | {error, Reason}</name>
<fsummary>Perform a get-next operation on the agent</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -176,7 +176,7 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
<!--
<func>
- <name>get_symbolic_store_db() -> Db</name>
+ <name since="">get_symbolic_store_db() -> Db</name>
<fsummary>Retrieve the symbolic store database reference</fsummary>
<type>
<v>Db = term()</v>
@@ -193,8 +193,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
-->
<func>
- <name>backup(BackupDir) -> ok | {error, Reason}</name>
- <name>backup(Agent, BackupDir) -> ok | {error, Reason}</name>
+ <name since="">backup(BackupDir) -> ok | {error, Reason}</name>
+ <name since="">backup(Agent, BackupDir) -> ok | {error, Reason}</name>
<fsummary>Backup agent data</fsummary>
<type>
<v>BackupDir = string()</v>
@@ -216,8 +216,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</desc>
</func>
<func>
- <name>info() -> [{Key, Value}]</name>
- <name>info(Agent) -> [{Key, Value}]</name>
+ <name since="">info() -> [{Key, Value}]</name>
+ <name since="">info(Agent) -> [{Key, Value}]</name>
<fsummary>Return information about the agent</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -236,7 +236,7 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>old_info_format(NewInfo) -> OldInfo</name>
+ <name since="">old_info_format(NewInfo) -> OldInfo</name>
<fsummary>Return information about the agent</fsummary>
<type>
<v>OldInfo = NewInfo = [{Key, Value}]</v>
@@ -251,8 +251,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>load_mib(Mib) -> ok | {error, Reason}</name>
- <name>load_mib(Agent, Mib) -> ok | {error, Reason}</name>
+ <name since="OTP R16B02">load_mib(Mib) -> ok | {error, Reason}</name>
+ <name since="OTP R16B02">load_mib(Agent, Mib) -> ok | {error, Reason}</name>
<fsummary>Load single MIB into the agent</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -273,10 +273,10 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>load_mibs(Mibs) -> ok | {error, Reason}</name>
- <name>load_mibs(Mibs, Force) -> ok | {error, Reason}</name>
- <name>load_mibs(Agent, Mibs) -> ok | {error, Reason}</name>
- <name>load_mibs(Agent, Mibs, Force) -> ok | {error, Reason}</name>
+ <name since="">load_mibs(Mibs) -> ok | {error, Reason}</name>
+ <name since="">load_mibs(Mibs, Force) -> ok | {error, Reason}</name>
+ <name since="">load_mibs(Agent, Mibs) -> ok | {error, Reason}</name>
+ <name since="OTP R16B02">load_mibs(Agent, Mibs, Force) -> ok | {error, Reason}</name>
<fsummary>Load MIBs into the agent</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -305,8 +305,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>unload_mib(Mib) -> ok | {error, Reason}</name>
- <name>unload_mib(Agent, Mib) -> ok | {error, Reason}</name>
+ <name since="OTP R16B02">unload_mib(Mib) -> ok | {error, Reason}</name>
+ <name since="OTP R16B02">unload_mib(Agent, Mib) -> ok | {error, Reason}</name>
<fsummary>Unload single MIB from the agent</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -321,10 +321,10 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>unload_mibs(Mibs) -> ok | {error, Reason}</name>
- <name>unload_mibs(Mibs, Force) -> ok | {error, Reason}</name>
- <name>unload_mibs(Agent, Mibs) -> ok | {error, Reason}</name>
- <name>unload_mibs(Agent, Mibs, Force) -> ok | {error, Reason}</name>
+ <name since="">unload_mibs(Mibs) -> ok | {error, Reason}</name>
+ <name since="">unload_mibs(Mibs, Force) -> ok | {error, Reason}</name>
+ <name since="">unload_mibs(Agent, Mibs) -> ok | {error, Reason}</name>
+ <name since="OTP R16B02">unload_mibs(Agent, Mibs, Force) -> ok | {error, Reason}</name>
<fsummary>Unload MIBs from the agent</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -347,8 +347,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>which_mibs() -> Mibs</name>
- <name>which_mibs(Agent) -> Mibs</name>
+ <name since="">which_mibs() -> Mibs</name>
+ <name since="">which_mibs(Agent) -> Mibs</name>
<fsummary>Get a list of all the loaded mibs</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -365,8 +365,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>whereis_mib(MibName) -> {ok, MibFile} | {error, Reason}</name>
- <name>whereis_mib(Agent, MibName) -> {ok, MibFile} | {error, Reason}</name>
+ <name since="">whereis_mib(MibName) -> {ok, MibFile} | {error, Reason}</name>
+ <name since="">whereis_mib(Agent, MibName) -> {ok, MibFile} | {error, Reason}</name>
<fsummary>Get the path to the mib file</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -385,10 +385,10 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>current_request_id() -> {value, RequestId} | false</name>
- <name>current_context() -> {value, Context} | false</name>
- <name>current_community() -> {value, Community} | false</name>
- <name>current_address() -> {value, Address} | false</name>
+ <name since="">current_request_id() -> {value, RequestId} | false</name>
+ <name since="">current_context() -> {value, Context} | false</name>
+ <name since="">current_community() -> {value, Community} | false</name>
+ <name since="">current_address() -> {value, Address} | false</name>
<fsummary>Get the request-id, context, community and address of the current request</fsummary>
<type>
<v>RequestId = integer()</v>
@@ -409,8 +409,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>enum_to_int(Name, Enum) -> {value, Int} | false</name>
- <name>enum_to_int(Db, Name, Enum) -> {value, Int} | false</name>
+ <name since="">enum_to_int(Name, Enum) -> {value, Int} | false</name>
+ <name since="">enum_to_int(Db, Name, Enum) -> {value, Int} | false</name>
<fsummary>Convert an enum value to an integer</fsummary>
<type>
<v>Db = term()</v>
@@ -435,8 +435,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>int_to_enum(Name, Int) -> {value, Enum} | false</name>
- <name>int_to_enum(Db, Name, Int) -> {value, Enum} | false</name>
+ <name since="">int_to_enum(Name, Int) -> {value, Enum} | false</name>
+ <name since="">int_to_enum(Db, Name, Int) -> {value, Enum} | false</name>
<fsummary>Convert an integer to an enum value</fsummary>
<type>
<v>Db = term()</v>
@@ -461,8 +461,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>name_to_oid(Name) -> {value, oid()} | false</name>
- <name>name_to_oid(Db, Name) -> {value, oid()} | false</name>
+ <name since="">name_to_oid(Name) -> {value, oid()} | false</name>
+ <name since="">name_to_oid(Db, Name) -> {value, oid()} | false</name>
<fsummary>Convert a symbolic name to an OID</fsummary>
<type>
<v>Db = term()</v>
@@ -482,8 +482,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>oid_to_name(OID) -> {value, Name} | false</name>
- <name>oid_to_name(Db, OID) -> {value, Name} | false</name>
+ <name since="">oid_to_name(OID) -> {value, Name} | false</name>
+ <name since="">oid_to_name(Db, OID) -> {value, Name} | false</name>
<fsummary>Convert an OID to a symbolic name</fsummary>
<type>
<v>Db = term()</v>
@@ -503,7 +503,7 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>which_aliasnames() -> Result</name>
+ <name since="">which_aliasnames() -> Result</name>
<fsummary>Get all alias-names known to the agent</fsummary>
<type>
<v>Result = [atom()]</v>
@@ -515,7 +515,7 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>which_tables() -> Result</name>
+ <name since="">which_tables() -> Result</name>
<fsummary>Get all tables known to the agent</fsummary>
<type>
<v>Result = [atom()]</v>
@@ -528,7 +528,7 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>which_variables() -> Result</name>
+ <name since="">which_variables() -> Result</name>
<fsummary>Get all variables known to the agent</fsummary>
<type>
<v>Result = [atom()]</v>
@@ -541,7 +541,7 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>which_notifications() -> Result</name>
+ <name since="">which_notifications() -> Result</name>
<fsummary>Get all notifications known to the agent</fsummary>
<type>
<v>Result = [{Name, MibName, Info}]</v>
@@ -557,15 +557,15 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>log_to_txt(LogDir)</name>
- <name>log_to_txt(LogDir, Block | Mibs)</name>
- <name>log_to_txt(LogDir, Mibs, Block | OutFile) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, Block | LogName) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, Block | LogFile) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> ok | {error, Reason}</name>
+ <name since="OTP R15B01">log_to_txt(LogDir)</name>
+ <name since="">log_to_txt(LogDir, Block | Mibs)</name>
+ <name since="">log_to_txt(LogDir, Mibs, Block | OutFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="">log_to_txt(LogDir, Mibs, OutFile, Block | LogName) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="">log_to_txt(LogDir, Mibs, OutFile, LogName, Block | LogFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="">log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="">log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="">log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="OTP R16B03">log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
<fsummary>Convert an Audit Trail Log to text format</fsummary>
<type>
<v>LogDir = string()</v>
@@ -576,6 +576,9 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
<v>LogName = string()</v>
<v>LogFile = string()</v>
<v>Start = Stop = null | calendar:datetime() | {local_time, calendar:datetime()} | {universal_time, calendar:datetime()} </v>
+ <v>Cnt = {NumOK, NumERR}</v>
+ <v>NumOK = non_neg_integer()</v>
+ <v>NumERR = pos_integer()</v>
<v>Reason = disk_log_open_error() | file_open_error() | term()</v>
<v>disk_log_open_error() = {LogName, term()}</v>
<v>file_open_error() = {OutFile, term()}</v>
@@ -597,14 +600,14 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>log_to_io(LogDir) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Block | Mibs) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, Block | LogName) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, Block | LogFile) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> ok | {error, Reason}</name>
+ <name since="OTP R15B01">log_to_io(LogDir) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="OTP R15B01">log_to_io(LogDir, Block | Mibs) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="OTP R15B01">log_to_io(LogDir, Mibs, Block | LogName) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="OTP R15B01">log_to_io(LogDir, Mibs, LogName, Block | LogFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="OTP R15B01">log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="OTP R15B01">log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="OTP R15B01">log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="OTP R16B03">log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
<fsummary>Convert an Audit Trail Log to text format</fsummary>
<type>
<v>LogDir = string()</v>
@@ -614,6 +617,9 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
<v>LogName = string()</v>
<v>LogFile = string()</v>
<v>Start = Stop = null | calendar:datetime() | {local_time, calendar:datetime()} | {universal_time, calendar:datetime()} </v>
+ <v>Cnt = {NumOK, NumERR}</v>
+ <v>NumOK = non_neg_integer()</v>
+ <v>NumERR = pos_integer()</v>
<v>Reason = disk_log_open_error() | file_open_error() | term()</v>
<v>disk_log_open_error() = {LogName, term()}</v>
<v>file_open_error() = {OutFile, term()}</v>
@@ -635,7 +641,7 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>change_log_size(NewSize) -> ok | {error, Reason}</name>
+ <name since="">change_log_size(NewSize) -> ok | {error, Reason}</name>
<fsummary>Change the size of the Audit Trail Log</fsummary>
<type>
<v>NewSize = {MaxBytes, MaxFiles}</v>
@@ -656,8 +662,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>set_log_type(NewType) -> {ok, OldType} | {error, Reason}</name>
- <name>set_log_type(Agent, NewType) -> {ok, OldType} | {error, Reason}</name>
+ <name since="">set_log_type(NewType) -> {ok, OldType} | {error, Reason}</name>
+ <name since="">set_log_type(Agent, NewType) -> {ok, OldType} | {error, Reason}</name>
<fsummary>Change the type of the Audit Trail Log</fsummary>
<type>
<v>NewType = OldType = atl_type()</v>
@@ -678,8 +684,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>mib_of(Oid) -> {ok, MibName} | {error, Reason}</name>
- <name>mib_of(Agent, Oid) -> {ok, MibName} | {error, Reason}</name>
+ <name since="">mib_of(Oid) -> {ok, MibName} | {error, Reason}</name>
+ <name since="">mib_of(Agent, Oid) -> {ok, MibName} | {error, Reason}</name>
<fsummary>Which mib an Oid belongs to</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -698,8 +704,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>me_of(Oid) -> {ok, Me} | {error, Reason}</name>
- <name>me_of(Agent, Oid) -> {ok, Me} | {error, Reason}</name>
+ <name since="">me_of(Oid) -> {ok, Me} | {error, Reason}</name>
+ <name since="">me_of(Agent, Oid) -> {ok, Me} | {error, Reason}</name>
<fsummary>Retrieve the mib-entry of an Oid</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -718,8 +724,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>invalidate_mibs_cache() -> void()</name>
- <name>invalidate_mibs_cache(Agent) -> void()</name>
+ <name since="">invalidate_mibs_cache() -> void()</name>
+ <name since="">invalidate_mibs_cache(Agent) -> void()</name>
<fsummary>Invalidate the mib server cache</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -733,8 +739,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>enable_mibs_cache() -> void()</name>
- <name>enable_mibs_cache(Agent) -> void()</name>
+ <name since="">enable_mibs_cache() -> void()</name>
+ <name since="">enable_mibs_cache(Agent) -> void()</name>
<fsummary>Enable the mib server cache</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -747,8 +753,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>disable_mibs_cache() -> void()</name>
- <name>disable_mibs_cache(Agent) -> void()</name>
+ <name since="">disable_mibs_cache() -> void()</name>
+ <name since="">disable_mibs_cache(Agent) -> void()</name>
<fsummary>Disable the mib server cache</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -761,8 +767,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>which_mibs_cache_size() -> void()</name>
- <name>which_mibs_cache_size(Agent) -> void()</name>
+ <name since="OTP R14B">which_mibs_cache_size() -> void()</name>
+ <name since="OTP R14B">which_mibs_cache_size(Agent) -> void()</name>
<fsummary>The size of the mib server cache</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -775,12 +781,12 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>gc_mibs_cache() -> {ok, NumElementsGCed} | {error, Reason}</name>
- <name>gc_mibs_cache(Agent) -> {ok, NumElementsGCed} | {error, Reason}</name>
- <name>gc_mibs_cache(Age) -> {ok, NumElementsGCed} | {error, Reason}</name>
- <name>gc_mibs_cache(Agent, Age) -> {ok, NumElementsGCed} | {error, Reason}</name>
- <name>gc_mibs_cache(Age, GcLimit) -> {ok, NumElementsGCed} | {error, Reason}</name>
- <name>gc_mibs_cache(Agent, Age, GcLimit) -> {ok, NumElementsGCed} | {error, Reason}</name>
+ <name since="">gc_mibs_cache() -> {ok, NumElementsGCed} | {error, Reason}</name>
+ <name since="">gc_mibs_cache(Agent) -> {ok, NumElementsGCed} | {error, Reason}</name>
+ <name since="">gc_mibs_cache(Age) -> {ok, NumElementsGCed} | {error, Reason}</name>
+ <name since="">gc_mibs_cache(Agent, Age) -> {ok, NumElementsGCed} | {error, Reason}</name>
+ <name since="">gc_mibs_cache(Age, GcLimit) -> {ok, NumElementsGCed} | {error, Reason}</name>
+ <name since="">gc_mibs_cache(Agent, Age, GcLimit) -> {ok, NumElementsGCed} | {error, Reason}</name>
<fsummary>Perform mib server cache gc</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -802,8 +808,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>enable_mibs_cache_autogc() -> void()</name>
- <name>enable_mibs_cache_autogc(Agent) -> void()</name>
+ <name since="">enable_mibs_cache_autogc() -> void()</name>
+ <name since="">enable_mibs_cache_autogc(Agent) -> void()</name>
<fsummary>Enable automatic gc of the mib server cache</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -816,8 +822,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>disable_mibs_cache_autogc() -> void()</name>
- <name>disable_mibs_cache_autogc(Agent) -> void()</name>
+ <name since="">disable_mibs_cache_autogc() -> void()</name>
+ <name since="">disable_mibs_cache_autogc(Agent) -> void()</name>
<fsummary>Disable automatic gc of the mib server cache</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -830,8 +836,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>update_mibs_cache_age(NewAge) -> ok | {error, Reason}</name>
- <name>update_mibs_cache_age(Agent, NewAge) -> ok | {error, Reason}</name>
+ <name since="">update_mibs_cache_age(NewAge) -> ok | {error, Reason}</name>
+ <name since="">update_mibs_cache_age(Agent, NewAge) -> ok | {error, Reason}</name>
<fsummary>Change the mib server cache age property</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -846,8 +852,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>update_mibs_cache_gclimit(NewGcLimit) -> ok | {error, Reason}</name>
- <name>update_mibs_cache_gclimit(Agent, NewGCLimit) -> ok | {error, Reason}</name>
+ <name since="">update_mibs_cache_gclimit(NewGcLimit) -> ok | {error, Reason}</name>
+ <name since="">update_mibs_cache_gclimit(Agent, NewGCLimit) -> ok | {error, Reason}</name>
<fsummary>Change the mib server cache gclimit property</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -863,10 +869,10 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
<func>
- <name>register_notification_filter(Id, Mod, Data) -> ok | {error, Reason}</name>
- <name>register_notification_filter(Agent, Id, Mod, Data) -> ok | {error, Reason}</name>
- <name>register_notification_filter(Id, Mod, Data, Where) -> ok | {error, Reason}</name>
- <name>register_notification_filter(Agent, Id, Mod, Data, Where) -> ok | {error, Reason}</name>
+ <name since="">register_notification_filter(Id, Mod, Data) -> ok | {error, Reason}</name>
+ <name since="">register_notification_filter(Agent, Id, Mod, Data) -> ok | {error, Reason}</name>
+ <name since="">register_notification_filter(Id, Mod, Data, Where) -> ok | {error, Reason}</name>
+ <name since="">register_notification_filter(Agent, Id, Mod, Data, Where) -> ok | {error, Reason}</name>
<fsummary>Register a notification filter</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -891,8 +897,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>unregister_notification_filter(Id) -> ok | {error, Reason}</name>
- <name>unregister_notification_filter(Agent, Id) -> ok | {error, Reason}</name>
+ <name since="">unregister_notification_filter(Id) -> ok | {error, Reason}</name>
+ <name since="">unregister_notification_filter(Agent, Id) -> ok | {error, Reason}</name>
<fsummary>Unregister a notification filter</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -907,8 +913,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>which_notification_filter() -> Filters</name>
- <name>which_notification_filter(Agent) -> Filters</name>
+ <name since="">which_notification_filter() -> Filters</name>
+ <name since="">which_notification_filter(Agent) -> Filters</name>
<fsummary>Which notification filter</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -923,8 +929,8 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>set_request_limit(NewLimit) -> {ok, OldLimit} | {error, Reason}</name>
- <name>set_request_limit(Agent, NewLimit) -> {ok, OldLimit} | {error, Reason}</name>
+ <name since="">set_request_limit(NewLimit) -> {ok, OldLimit} | {error, Reason}</name>
+ <name since="">set_request_limit(Agent, NewLimit) -> {ok, OldLimit} | {error, Reason}</name>
<fsummary>Change the request limit</fsummary>
<type>
<v>NewLimit = OldLimit = infinity | integer() >= 0</v>
@@ -944,7 +950,7 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>register_subagent(Agent, SubTreeOid, Subagent) -> ok | {error, Reason}</name>
+ <name since="">register_subagent(Agent, SubTreeOid, Subagent) -> ok | {error, Reason}</name>
<fsummary>Register a sub-agent under a sub-tree</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -969,7 +975,7 @@ snmp_agent:register_subagent(SA1,[1,2,3], SA2).
</func>
<func>
- <name>unregister_subagent(Agent, SubagentOidOrPid) -> ok | {ok, SubAgentPid} | {error, Reason}</name>
+ <name since="">unregister_subagent(Agent, SubagentOidOrPid) -> ok | {ok, SubAgentPid} | {error, Reason}</name>
<fsummary>Unregister a sub-agent</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -986,7 +992,7 @@ snmp_agent:register_subagent(SA1,[1,2,3], SA2).
<func>
- <name>send_notification2(Agent, Notification, SendOpts) -> void()</name>
+ <name since="OTP R14B03">send_notification2(Agent, Notification, SendOpts) -> void()</name>
<fsummary>Send notification</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -1113,11 +1119,11 @@ snmp_agent:register_subagent(SA1,[1,2,3], SA2).
<func>
- <name>send_notification(Agent, Notification, Receiver)</name>
- <name>send_notification(Agent, Notification, Receiver, Varbinds)</name>
- <name>send_notification(Agent, Notification, Receiver, NotifyName, Varbinds)</name>
- <name>send_notification(Agent, Notification, Receiver, NotifyName, ContextName, Varbinds) -> void() </name>
- <name>send_notification(Agent, Notification, Receiver, NotifyName, ContextName, Varbinds, LocalEngineID) -> void() </name>
+ <name since="">send_notification(Agent, Notification, Receiver)</name>
+ <name since="">send_notification(Agent, Notification, Receiver, Varbinds)</name>
+ <name since="">send_notification(Agent, Notification, Receiver, NotifyName, Varbinds)</name>
+ <name since="">send_notification(Agent, Notification, Receiver, NotifyName, ContextName, Varbinds) -> void() </name>
+ <name since="OTP R14B">send_notification(Agent, Notification, Receiver, NotifyName, ContextName, Varbinds, LocalEngineID) -> void() </name>
<fsummary>Send a notification</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -1318,13 +1324,13 @@ snmp_agent:register_subagent(SA1,[1,2,3], SA2).
<func>
- <name>discovery(TargetName, Notification) -> {ok, ManagerEngineID} | {error, Reason}</name>
- <name>discovery(TargetName, Notification, Varbinds) -> {ok, ManagerEngineID} | {error, Reason}</name>
- <name>discovery(TargetName, Notification, DiscoHandler) -> {ok, ManagerEngineID} | {error, Reason}</name>
- <name>discovery(TargetName, Notification, ContextName, Varbinds) -> {ok, ManagerEngineID} | {error, Reason}</name>
- <name>discovery(TargetName, Notification, Varbinds, DiscoHandler) -> {ok, ManagerEngineID} | {error, Reason}</name>
- <name>discovery(TargetName, Notification, ContextName, Varbinds, DiscoHandler) -> {ok, ManagerEngineID} | {error, Reason}</name>
- <name>discovery(TargetName, Notification, ContextName, Varbinds, DiscoHandler, ExtraInfo) -> {ok, ManagerEngineID} | {error, Reason}</name>
+ <name since="">discovery(TargetName, Notification) -> {ok, ManagerEngineID} | {error, Reason}</name>
+ <name since="">discovery(TargetName, Notification, Varbinds) -> {ok, ManagerEngineID} | {error, Reason}</name>
+ <name since="">discovery(TargetName, Notification, DiscoHandler) -> {ok, ManagerEngineID} | {error, Reason}</name>
+ <name since="">discovery(TargetName, Notification, ContextName, Varbinds) -> {ok, ManagerEngineID} | {error, Reason}</name>
+ <name since="">discovery(TargetName, Notification, Varbinds, DiscoHandler) -> {ok, ManagerEngineID} | {error, Reason}</name>
+ <name since="">discovery(TargetName, Notification, ContextName, Varbinds, DiscoHandler) -> {ok, ManagerEngineID} | {error, Reason}</name>
+ <name since="">discovery(TargetName, Notification, ContextName, Varbinds, DiscoHandler, ExtraInfo) -> {ok, ManagerEngineID} | {error, Reason}</name>
<fsummary>Initiate the discovery process with a manager</fsummary>
<type>
<v>TargetName = string()</v>
@@ -1373,7 +1379,7 @@ snmp_agent:register_subagent(SA1,[1,2,3], SA2).
</func>
<func>
- <name>convert_config(OldConfig) -> AgentConfig</name>
+ <name since="">convert_config(OldConfig) -> AgentConfig</name>
<fsummary>Convert old snmp config to new agent config</fsummary>
<type>
<v>OldConfig = list()</v>
@@ -1397,8 +1403,8 @@ snmp_agent:register_subagent(SA1,[1,2,3], SA2).
</func>
<func>
- <name>restart_worker() -> void()</name>
- <name>restart_worker(Agent) -> void()</name>
+ <name since="">restart_worker() -> void()</name>
+ <name since="">restart_worker(Agent) -> void()</name>
<fsummary>Restart the worker process of a multi-threaded agent</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -1413,8 +1419,8 @@ snmp_agent:register_subagent(SA1,[1,2,3], SA2).
</func>
<func>
- <name>restart_set_worker() -> void()</name>
- <name>restart_set_worker(Agent) -> void()</name>
+ <name since="">restart_set_worker() -> void()</name>
+ <name since="">restart_set_worker(Agent) -> void()</name>
<fsummary>Restart the set worker process of a multi-threaded agent</fsummary>
<type>
<v>Agent = pid() | atom()</v>
@@ -1429,7 +1435,7 @@ snmp_agent:register_subagent(SA1,[1,2,3], SA2).
</func>
<func>
- <name>print_mib_info() -> void()</name>
+ <name since="OTP R14B02">print_mib_info() -> void()</name>
<fsummary>Print mib info</fsummary>
<desc>
<p>Prints the content of all the (snmp) tables and variables
@@ -1440,7 +1446,7 @@ snmp_agent:register_subagent(SA1,[1,2,3], SA2).
</func>
<func>
- <name>print_mib_tables() -> void()</name>
+ <name since="OTP R14B02">print_mib_tables() -> void()</name>
<fsummary>Print mib tables</fsummary>
<desc>
<p>Prints the content of all the (snmp) tables
@@ -1451,7 +1457,7 @@ snmp_agent:register_subagent(SA1,[1,2,3], SA2).
</func>
<func>
- <name>print_mib_variables() -> void()</name>
+ <name since="OTP R14B02">print_mib_variables() -> void()</name>
<fsummary>Print mib variables</fsummary>
<desc>
<p>Prints the content of all the (snmp) variables
@@ -1462,7 +1468,7 @@ snmp_agent:register_subagent(SA1,[1,2,3], SA2).
</func>
<func>
- <name>verbosity(Ref,Verbosity) -> void()</name>
+ <name since="">verbosity(Ref,Verbosity) -> void()</name>
<fsummary>Assign a new verbosity for the process</fsummary>
<type>
<v>Ref = pid() | sub_agents | master_agent | net_if | mib_server | symbolic_store | note_store | local_db</v>
diff --git a/lib/snmp/doc/src/snmpa_conf.xml b/lib/snmp/doc/src/snmpa_conf.xml
index 503e44a6a2..4134a81c0c 100644
--- a/lib/snmp/doc/src/snmpa_conf.xml
+++ b/lib/snmp/doc/src/snmpa_conf.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmpa_conf.xml</file>
</header>
- <module>snmpa_conf</module>
+ <module since="">snmpa_conf</module>
<modulesummary>Utility functions for handling the agent config files.</modulesummary>
<description>
<p>The module <c>snmpa_conf</c> contains various utility functions to
@@ -92,7 +92,7 @@ word() = 0..65535
<funcs>
<func>
- <name>agent_entry(Tag, Val) -> agent_entry()</name>
+ <name since="">agent_entry(Tag, Val) -> agent_entry()</name>
<fsummary>Create an agent entry</fsummary>
<type>
<v>Tag = intAgentTransports | intAgentUDPPort | intAgentMaxPacketSize | snmpEngineMaxMessageSize | snmpEngineID</v>
@@ -111,8 +111,8 @@ word() = 0..65535
</func>
<func>
- <name>write_agent_config(Dir, Conf) -> ok</name>
- <name>write_agent_config(Dir, Hdr, Conf) -> ok</name>
+ <name since="">write_agent_config(Dir, Conf) -> ok</name>
+ <name since="">write_agent_config(Dir, Hdr, Conf) -> ok</name>
<fsummary>Write the agent config to the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -134,7 +134,7 @@ word() = 0..65535
</func>
<func>
- <name>append_agent_config(Dir, Conf) -> ok</name>
+ <name since="">append_agent_config(Dir, Conf) -> ok</name>
<fsummary>Append the agent config to the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -153,7 +153,7 @@ word() = 0..65535
</func>
<func>
- <name>read_agent_config(Dir) -> Conf</name>
+ <name since="">read_agent_config(Dir) -> Conf</name>
<fsummary>Read the agent config from the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -172,7 +172,7 @@ word() = 0..65535
</func>
<func>
- <name>standard_entry(Tag, Val) -> standard_entry()</name>
+ <name since="">standard_entry(Tag, Val) -> standard_entry()</name>
<fsummary>Create an standard entry</fsummary>
<type>
<v>Tag = sysDescr | sysObjectID | sysContact | sysName | sysLocation | sysServices | snmpEnableAuthenTraps</v>
@@ -192,8 +192,8 @@ word() = 0..65535
</func>
<func>
- <name>write_standard_config(Dir, Conf) -> ok</name>
- <name>write_standard_config(Dir, Hdr, Conf) -> ok</name>
+ <name since="">write_standard_config(Dir, Conf) -> ok</name>
+ <name since="">write_standard_config(Dir, Hdr, Conf) -> ok</name>
<fsummary>Write the agent standard config to the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -216,7 +216,7 @@ word() = 0..65535
</func>
<func>
- <name>append_standard_config(Dir, Conf) -> ok</name>
+ <name since="">append_standard_config(Dir, Conf) -> ok</name>
<fsummary>Append the agent standard config to the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -236,7 +236,7 @@ word() = 0..65535
</func>
<func>
- <name>read_standard_config(Dir) -> Conf</name>
+ <name since="">read_standard_config(Dir) -> Conf</name>
<fsummary>Read the agent standard config from the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -255,7 +255,7 @@ word() = 0..65535
</func>
<func>
- <name>context_entry(Context) -> context_entry()</name>
+ <name since="">context_entry(Context) -> context_entry()</name>
<fsummary>Create an context entry</fsummary>
<type>
<v>Context = string()</v>
@@ -273,8 +273,8 @@ word() = 0..65535
</func>
<func>
- <name>write_context_config(Dir, Conf) -> ok</name>
- <name>write_context_config(Dir, Hdr, Conf) -> ok</name>
+ <name since="">write_context_config(Dir, Conf) -> ok</name>
+ <name since="">write_context_config(Dir, Hdr, Conf) -> ok</name>
<fsummary>Write the agent context(s) to the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -297,7 +297,7 @@ word() = 0..65535
</func>
<func>
- <name>append_context_config(Dir, Conf) -> ok</name>
+ <name since="">append_context_config(Dir, Conf) -> ok</name>
<fsummary>Append the agent context(s) to the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -317,7 +317,7 @@ word() = 0..65535
</func>
<func>
- <name>read_context_config(Dir) -> Conf</name>
+ <name since="">read_context_config(Dir) -> Conf</name>
<fsummary>Read the agent context config from the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -336,8 +336,8 @@ word() = 0..65535
</func>
<func>
- <name>community_entry(CommunityIndex) -> community_entry()</name>
- <name>community_entry(CommunityIndex, CommunityName, SecName, ContextName, TransportTag) -> community_entry()</name>
+ <name since="">community_entry(CommunityIndex) -> community_entry()</name>
+ <name since="">community_entry(CommunityIndex, CommunityName, SecName, ContextName, TransportTag) -> community_entry()</name>
<fsummary>Create an community entry</fsummary>
<type>
<v>CommunityIndex = string()</v>
@@ -364,8 +364,8 @@ word() = 0..65535
</func>
<func>
- <name>write_community_config(Dir, Conf) -> ok</name>
- <name>write_community_config(Dir, Hdr, Conf) -> ok</name>
+ <name since="">write_community_config(Dir, Conf) -> ok</name>
+ <name since="">write_community_config(Dir, Hdr, Conf) -> ok</name>
<fsummary>Write the agent community config to the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -388,7 +388,7 @@ word() = 0..65535
</func>
<func>
- <name>append_community_config(Dir, Conf) -> ok</name>
+ <name since="">append_community_config(Dir, Conf) -> ok</name>
<fsummary>Append the agent community config to the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -408,7 +408,7 @@ word() = 0..65535
</func>
<func>
- <name>read_community_config(Dir) -> Conf</name>
+ <name since="">read_community_config(Dir) -> Conf</name>
<fsummary>Read the agent community config from the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -427,10 +427,10 @@ word() = 0..65535
</func>
<func>
- <name>target_addr_entry(Name, Domain, Addr, TagList, ParamsName, EngineId) -> target_addr_entry()</name>
- <name>target_addr_entry(Name, Domain, Addr, TagList, ParamsName, EngineId, TMask) -> target_addr_entry()</name>
- <name>target_addr_entry(Name, Domain, Addr, TagList, ParamsName, EngineId, TMask, MaxMessageSize) -> target_addr_entry()</name>
- <name>target_addr_entry(Name, Domain, Addr, Timeout, RetryCount, TagList, ParamsName, EngineId, TMask, MaxMessageSize) -> target_addr_entry()</name>
+ <name since="">target_addr_entry(Name, Domain, Addr, TagList, ParamsName, EngineId) -> target_addr_entry()</name>
+ <name since="OTP 17.3">target_addr_entry(Name, Domain, Addr, TagList, ParamsName, EngineId, TMask) -> target_addr_entry()</name>
+ <name since="">target_addr_entry(Name, Domain, Addr, TagList, ParamsName, EngineId, TMask, MaxMessageSize) -> target_addr_entry()</name>
+ <name since="">target_addr_entry(Name, Domain, Addr, Timeout, RetryCount, TagList, ParamsName, EngineId, TMask, MaxMessageSize) -> target_addr_entry()</name>
<fsummary>Create an target_addr entry</fsummary>
<type>
<v>Name = string()</v>
@@ -464,8 +464,8 @@ word() = 0..65535
</func>
<func>
- <name>write_target_addr_config(Dir, Conf) -> ok</name>
- <name>write_target_addr_config(Dir, Hdr, Conf) -> ok</name>
+ <name since="">write_target_addr_config(Dir, Conf) -> ok</name>
+ <name since="">write_target_addr_config(Dir, Hdr, Conf) -> ok</name>
<fsummary>Write the agent target_addr config to the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -488,7 +488,7 @@ word() = 0..65535
</func>
<func>
- <name>append_target_addr_config(Dir, Conf) -> ok</name>
+ <name since="">append_target_addr_config(Dir, Conf) -> ok</name>
<fsummary>Append the agent target_addr config to the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -508,7 +508,7 @@ word() = 0..65535
</func>
<func>
- <name>read_target_addr_config(Dir) -> Conf</name>
+ <name since="">read_target_addr_config(Dir) -> Conf</name>
<fsummary>Read the agent target_addr config from the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -527,9 +527,9 @@ word() = 0..65535
</func>
<func>
- <name>target_params_entry(Name, Vsn) -> target_params_entry()</name>
- <name>target_params_entry(Name, Vsn, SecName, SecLevel) -> target_params_entry()</name>
- <name>target_params_entry(Name, MPModel, SecModel, SecName, SecLevel) -> target_params_entry()</name>
+ <name since="">target_params_entry(Name, Vsn) -> target_params_entry()</name>
+ <name since="">target_params_entry(Name, Vsn, SecName, SecLevel) -> target_params_entry()</name>
+ <name since="">target_params_entry(Name, MPModel, SecModel, SecName, SecLevel) -> target_params_entry()</name>
<fsummary>Create an target_params entry</fsummary>
<type>
<v>Name = string()</v>
@@ -564,8 +564,8 @@ word() = 0..65535
</func>
<func>
- <name>write_target_params_config(Dir, Conf) -> ok</name>
- <name>write_target_params_config(Dir, Hdr, Conf) -> ok</name>
+ <name since="">write_target_params_config(Dir, Conf) -> ok</name>
+ <name since="">write_target_params_config(Dir, Hdr, Conf) -> ok</name>
<fsummary>Write the agent target_params config to the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -588,7 +588,7 @@ word() = 0..65535
</func>
<func>
- <name>append_target_params_config(Dir, Conf) -> ok</name>
+ <name since="">append_target_params_config(Dir, Conf) -> ok</name>
<fsummary>Append the agent target_params config to the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -608,7 +608,7 @@ word() = 0..65535
</func>
<func>
- <name>read_target_params_config(Dir) -> Conf</name>
+ <name since="">read_target_params_config(Dir) -> Conf</name>
<fsummary>Read the agent target_params config from the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -627,10 +627,10 @@ word() = 0..65535
</func>
<func>
- <name>vacm_s2g_entry(SecModel, SecName, GroupName) -> vacm_s2g_entry()</name>
- <name>vacm_acc_entry(GroupName, Prefix, SecModel, SecLevel, Match, ReadView, WriteView, NotifyView) -> vacm_acc_entry()</name>
- <name>vacm_vtf_entry(ViewIndex, ViewSubtree) -> vacm_vtf_entry()</name>
- <name>vacm_vtf_entry(ViewIndex, ViewSubtree, ViewStatus, ViewMask) -> vacm_vtf_entry()</name>
+ <name since="">vacm_s2g_entry(SecModel, SecName, GroupName) -> vacm_s2g_entry()</name>
+ <name since="">vacm_acc_entry(GroupName, Prefix, SecModel, SecLevel, Match, ReadView, WriteView, NotifyView) -> vacm_acc_entry()</name>
+ <name since="">vacm_vtf_entry(ViewIndex, ViewSubtree) -> vacm_vtf_entry()</name>
+ <name since="">vacm_vtf_entry(ViewIndex, ViewSubtree, ViewStatus, ViewMask) -> vacm_vtf_entry()</name>
<fsummary>Create an vacm entry</fsummary>
<type>
<v>SecModel = v1 | v2c | usm</v>
@@ -665,8 +665,8 @@ word() = 0..65535
</func>
<func>
- <name>write_vacm_config(Dir, Conf) -> ok</name>
- <name>write_vacm_config(Dir, Hdr, Conf) -> ok</name>
+ <name since="">write_vacm_config(Dir, Conf) -> ok</name>
+ <name since="">write_vacm_config(Dir, Hdr, Conf) -> ok</name>
<fsummary>Write the agent vacm config to the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -690,7 +690,7 @@ word() = 0..65535
</func>
<func>
- <name>append_vacm_config(Dir, Conf) -> ok</name>
+ <name since="">append_vacm_config(Dir, Conf) -> ok</name>
<fsummary>Append the agent vacm config to the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -710,7 +710,7 @@ word() = 0..65535
</func>
<func>
- <name>read_vacm_config(Dir) -> Conf</name>
+ <name since="">read_vacm_config(Dir) -> Conf</name>
<fsummary>Read the agent vacm config from the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -729,8 +729,8 @@ word() = 0..65535
</func>
<func>
- <name>usm_entry(EngineId) -> usm_entry()</name>
- <name>usm_entry(EngineID, UserName, SecName, Clone, AuthP, AuthKeyC, OwnAuthKeyC, PrivP, PrivKeyC, OwnPrivKeyC, Public, AuthKey, PrivKey) -> usm_entry()</name>
+ <name since="">usm_entry(EngineId) -> usm_entry()</name>
+ <name since="">usm_entry(EngineID, UserName, SecName, Clone, AuthP, AuthKeyC, OwnAuthKeyC, PrivP, PrivKeyC, OwnPrivKeyC, Public, AuthKey, PrivKey) -> usm_entry()</name>
<fsummary>Create an usm entry</fsummary>
<type>
<v>EngineId = string()</v>
@@ -762,8 +762,8 @@ word() = 0..65535
</func>
<func>
- <name>write_usm_config(Dir, Conf) -> ok</name>
- <name>write_usm_config(Dir, Hdr, Conf) -> ok</name>
+ <name since="">write_usm_config(Dir, Conf) -> ok</name>
+ <name since="">write_usm_config(Dir, Hdr, Conf) -> ok</name>
<fsummary>Write the agent usm config to the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -786,7 +786,7 @@ word() = 0..65535
</func>
<func>
- <name>append_usm_config(Dir, Conf) -> ok</name>
+ <name since="">append_usm_config(Dir, Conf) -> ok</name>
<fsummary>Append the agent usm config to the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -805,7 +805,7 @@ word() = 0..65535
</func>
<func>
- <name>read_usm_config(Dir) -> Conf</name>
+ <name since="">read_usm_config(Dir) -> Conf</name>
<fsummary>Read the agent usm config from the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -824,7 +824,7 @@ word() = 0..65535
</func>
<func>
- <name>notify_entry(Name, Tag, Type) -> notify_entry()</name>
+ <name since="">notify_entry(Name, Tag, Type) -> notify_entry()</name>
<fsummary>Create an notify entry</fsummary>
<type>
<v>Name = string()</v>
@@ -845,8 +845,8 @@ word() = 0..65535
</func>
<func>
- <name>write_notify_config(Dir, Conf) -> ok</name>
- <name>write_notify_config(Dir, Hdr, Conf) -> ok</name>
+ <name since="">write_notify_config(Dir, Conf) -> ok</name>
+ <name since="">write_notify_config(Dir, Hdr, Conf) -> ok</name>
<fsummary>Write the agent notify config to the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -869,7 +869,7 @@ word() = 0..65535
</func>
<func>
- <name>append_notify_config(Dir, Conf) -> ok</name>
+ <name since="">append_notify_config(Dir, Conf) -> ok</name>
<fsummary>Append the agent notify config to the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -889,7 +889,7 @@ word() = 0..65535
</func>
<func>
- <name>read_notify_config(Dir) -> Conf</name>
+ <name since="">read_notify_config(Dir) -> Conf</name>
<fsummary>Read the agent notify config from the config file</fsummary>
<type>
<v>Dir = string()</v>
diff --git a/lib/snmp/doc/src/snmpa_discovery_handler.xml b/lib/snmp/doc/src/snmpa_discovery_handler.xml
index 0ea72a880c..21b8746c11 100644
--- a/lib/snmp/doc/src/snmpa_discovery_handler.xml
+++ b/lib/snmp/doc/src/snmpa_discovery_handler.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmpa_discovery_handler.xml</file>
</header>
- <module>snmpa_discovery_handler</module>
+ <module since="">snmpa_discovery_handler</module>
<modulesummary>Behaviour module for the SNMP agent discovery handler.</modulesummary>
<description>
<p>This module defines the behaviour of the agent discovery
@@ -51,7 +51,7 @@
<funcs>
<func>
- <name>stage1_finish(TargetName, ManagerEngineID, ExtraInfo) -> ignore | {ok, usm_entry() | [usm_entry()]} | {ok, usm_entry() | [usm_entry()], NewExtraInfo}</name>
+ <name since="">stage1_finish(TargetName, ManagerEngineID, ExtraInfo) -> ignore | {ok, usm_entry() | [usm_entry()]} | {ok, usm_entry() | [usm_entry()], NewExtraInfo}</name>
<fsummary>Discovery stage 1 finish</fsummary>
<type>
<v>TargetName = string()</v>
diff --git a/lib/snmp/doc/src/snmpa_error.xml b/lib/snmp/doc/src/snmpa_error.xml
index 7cc4a3513d..6e6761b7a5 100644
--- a/lib/snmp/doc/src/snmpa_error.xml
+++ b/lib/snmp/doc/src/snmpa_error.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmpa_error.xml</file>
</header>
- <module>snmpa_error</module>
+ <module since="">snmpa_error</module>
<modulesummary>Functions for Reporting SNMP Errors</modulesummary>
<description>
<marker id="desc"></marker>
@@ -57,7 +57,7 @@
</description>
<funcs>
<func>
- <name>config_err(Format, Args) -> void()</name>
+ <name since="">config_err(Format, Args) -> void()</name>
<fsummary>Called if a configuration error occurs</fsummary>
<type>
<v>Format = string()</v>
@@ -76,7 +76,7 @@
</func>
<func>
- <name>user_err(Format, Args) -> void()</name>
+ <name since="">user_err(Format, Args) -> void()</name>
<fsummary>Called if a user related error occurs</fsummary>
<type>
<v>Format = string()</v>
diff --git a/lib/snmp/doc/src/snmpa_error_io.xml b/lib/snmp/doc/src/snmpa_error_io.xml
index bcb2688646..d78e09ff13 100644
--- a/lib/snmp/doc/src/snmpa_error_io.xml
+++ b/lib/snmp/doc/src/snmpa_error_io.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmpa_error_io.xml</file>
</header>
- <module>snmpa_error_io</module>
+ <module since="">snmpa_error_io</module>
<modulesummary>Functions for Reporting SNMP Errors on stdio</modulesummary>
<description>
<p>The module <c>snmpa_error_io</c> implements the
@@ -52,7 +52,7 @@
</description>
<funcs>
<func>
- <name>config_err(Format, Args) -> void()</name>
+ <name since="">config_err(Format, Args) -> void()</name>
<fsummary>Called if a configuration error occurs</fsummary>
<type>
<v>Format = string()</v>
@@ -68,7 +68,7 @@
</desc>
</func>
<func>
- <name>user_err(Format, Args) -> void()</name>
+ <name since="">user_err(Format, Args) -> void()</name>
<fsummary>Called if a user related error occurs</fsummary>
<type>
<v>Format = string()</v>
diff --git a/lib/snmp/doc/src/snmpa_error_logger.xml b/lib/snmp/doc/src/snmpa_error_logger.xml
index 4feb2e7f32..b0565a6839 100644
--- a/lib/snmp/doc/src/snmpa_error_logger.xml
+++ b/lib/snmp/doc/src/snmpa_error_logger.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmpa_error_logger.xml</file>
</header>
- <module>snmpa_error_logger</module>
+ <module since="">snmpa_error_logger</module>
<modulesummary>Functions for Reporting SNMP Errors through the error_logger</modulesummary>
<description>
<p>The module <c>snmpa_error_logger</c> implements the
@@ -54,7 +54,7 @@
</description>
<funcs>
<func>
- <name>config_err(Format, Args) -> void()</name>
+ <name since="">config_err(Format, Args) -> void()</name>
<fsummary>Called if a configuration error occurs</fsummary>
<type>
<v>Format = string()</v>
@@ -70,7 +70,7 @@
</desc>
</func>
<func>
- <name>user_err(Format, Args) -> void()</name>
+ <name since="">user_err(Format, Args) -> void()</name>
<fsummary>Called if a user related error occurs</fsummary>
<type>
<v>Format = string()</v>
diff --git a/lib/snmp/doc/src/snmpa_error_report.xml b/lib/snmp/doc/src/snmpa_error_report.xml
index 282d9b4e59..f08dc1df23 100644
--- a/lib/snmp/doc/src/snmpa_error_report.xml
+++ b/lib/snmp/doc/src/snmpa_error_report.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmpa_error_report.xml</file>
</header>
- <module>snmpa_error_report</module>
+ <module since="">snmpa_error_report</module>
<modulesummary>Behaviour module for reporting SNMP agent errors</modulesummary>
<description>
<marker id="desc"></marker>
@@ -52,7 +52,7 @@
</description>
<funcs>
<func>
- <name>config_err(Format, Args) -> void()</name>
+ <name since="">config_err(Format, Args) -> void()</name>
<fsummary>Called if a configuration error occurs</fsummary>
<type>
<v>Format = string()</v>
@@ -68,7 +68,7 @@
</desc>
</func>
<func>
- <name>user_err(Format, Args) -> void()</name>
+ <name since="">user_err(Format, Args) -> void()</name>
<fsummary>Called if a user related error occurs</fsummary>
<type>
<v>Format = string()</v>
diff --git a/lib/snmp/doc/src/snmpa_local_db.xml b/lib/snmp/doc/src/snmpa_local_db.xml
index ac8d466ab3..229f22ab70 100644
--- a/lib/snmp/doc/src/snmpa_local_db.xml
+++ b/lib/snmp/doc/src/snmpa_local_db.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmpa_local_db.xml</file>
</header>
- <module>snmpa_local_db</module>
+ <module since="">snmpa_local_db</module>
<modulesummary>The SNMP built-in database</modulesummary>
<description>
<p>The module <c>snmpa_local_db</c> contains functions for
@@ -86,7 +86,7 @@
</section>
<funcs>
<func>
- <name>dump() -> ok | {error, Reason}</name>
+ <name since="">dump() -> ok | {error, Reason}</name>
<fsummary>Dump the database to disk</fsummary>
<type>
<v>Reason = term()</v>
@@ -97,7 +97,7 @@
</desc>
</func>
<func>
- <name>match(NameDb, Pattern)</name>
+ <name since="">match(NameDb, Pattern)</name>
<fsummary>Perform a match on the table</fsummary>
<desc>
<p>Performs an ets/dets matching on the table.
@@ -106,9 +106,9 @@
</desc>
</func>
<func>
- <name>print()</name>
- <name>print(TableName)</name>
- <name>print(TableName, Db)</name>
+ <name since="">print()</name>
+ <name since="">print(TableName)</name>
+ <name since="">print(TableName, Db)</name>
<fsummary>Print the database to screen</fsummary>
<type>
<v>TableName = atom()</v>
@@ -124,7 +124,7 @@
</desc>
</func>
<func>
- <name>table_create(NameDb) -> bool()</name>
+ <name since="">table_create(NameDb) -> bool()</name>
<fsummary>Create a table</fsummary>
<desc>
<p>Creates a table. If the table already exist, the old copy
@@ -135,7 +135,7 @@
</desc>
</func>
<func>
- <name>table_create_row(NameDb, RowIndex, Row) -> bool()</name>
+ <name since="">table_create_row(NameDb, RowIndex, Row) -> bool()</name>
<fsummary>Create a row in a table</fsummary>
<type>
<v>Row = {Val1, Val2, ..., ValN}</v>
@@ -147,28 +147,28 @@
</desc>
</func>
<func>
- <name>table_delete(NameDb) -> void()</name>
+ <name since="">table_delete(NameDb) -> void()</name>
<fsummary>Delete a table</fsummary>
<desc>
<p>Deletes a table.</p>
</desc>
</func>
<func>
- <name>table_delete_row(NameDb, RowIndex) -> bool()</name>
+ <name since="">table_delete_row(NameDb, RowIndex) -> bool()</name>
<fsummary>Delete the row in the table</fsummary>
<desc>
<p>Deletes the row in the table.</p>
</desc>
</func>
<func>
- <name>table_exists(NameDb) -> bool()</name>
+ <name since="">table_exists(NameDb) -> bool()</name>
<fsummary>Check if a table exists</fsummary>
<desc>
<p>Checks if a table exists.</p>
</desc>
</func>
<func>
- <name>table_get_row(NameDb, RowIndex) -> Row | undefined</name>
+ <name since="">table_get_row(NameDb, RowIndex) -> Row | undefined</name>
<fsummary>Get a row from the table</fsummary>
<type>
<v>Row = {Val1, Val2, ..., ValN}</v>
diff --git a/lib/snmp/doc/src/snmpa_mib_data.xml b/lib/snmp/doc/src/snmpa_mib_data.xml
index 1a73c9b634..b849a2826a 100644
--- a/lib/snmp/doc/src/snmpa_mib_data.xml
+++ b/lib/snmp/doc/src/snmpa_mib_data.xml
@@ -30,7 +30,7 @@
<file>snmpa_mib_data.xml</file>
</header>
- <module>snmpa_mib_data</module>
+ <module since="OTP R16B01">snmpa_mib_data</module>
<modulesummary>Behaviour module for the SNMP agent mib-server
data module.</modulesummary>
<description>
@@ -108,7 +108,7 @@
<funcs>
<func>
- <name>Module:new(Storage) -> State</name>
+ <name since="OTP R16B01">Module:new(Storage) -> State</name>
<fsummary>Create new (mib-server) data instance</fsummary>
<type>
<v>Storage = mib_storage()</v>
@@ -122,7 +122,7 @@
</func>
<func>
- <name>Module:close(State) -> void()</name>
+ <name since="OTP R16B01">Module:close(State) -> void()</name>
<fsummary>Close the mib-server data instance</fsummary>
<type>
<v>State = term()</v>
@@ -135,7 +135,7 @@
</func>
<func>
- <name>Module:sync(State) -> void()</name>
+ <name since="OTP R16B01">Module:sync(State) -> void()</name>
<fsummary>Synchronize to disc</fsummary>
<type>
<v>State = term()</v>
@@ -151,7 +151,7 @@
</func>
<func>
- <name>Module:load_mib(State, Filename, MeOverride, TeOverride) -> {ok, NewState} | {error, Reason}</name>
+ <name since="OTP R16B01">Module:load_mib(State, Filename, MeOverride, TeOverride) -> {ok, NewState} | {error, Reason}</name>
<fsummary>Load a mib into the mib-server</fsummary>
<type>
<v>State = NewState = term()</v>
@@ -172,7 +172,7 @@
</func>
<func>
- <name>Module:unload_mib(State, Filename) -> {ok, NewState} | {error, Reason}</name>
+ <name since="OTP R16B01">Module:unload_mib(State, Filename) -> {ok, NewState} | {error, Reason}</name>
<fsummary>Unload mib from the mib-server</fsummary>
<type>
<v>State = NewState = term()</v>
@@ -188,7 +188,7 @@
</func>
<func>
- <name>Module:lookup(State, Oid) -> Reply</name>
+ <name since="OTP R16B01">Module:lookup(State, Oid) -> Reply</name>
<fsummary>Find the mib-entry corresponding to the Oid</fsummary>
<type>
<v>State = term()</v>
@@ -210,7 +210,7 @@
</func>
<func>
- <name>Module:next(State, Oid, MibView) -> Reply</name>
+ <name since="OTP R16B01">Module:next(State, Oid, MibView) -> Reply</name>
<fsummary>Finds the lexicographically next oid</fsummary>
<type>
<v>State = term()</v>
@@ -227,7 +227,7 @@
</func>
<func>
- <name>Module:register_subagent(State, Oid, Pid) -> Reply</name>
+ <name since="OTP R16B01">Module:register_subagent(State, Oid, Pid) -> Reply</name>
<fsummary>Register the subagent</fsummary>
<type>
<v>State = NewState = term()</v>
@@ -245,7 +245,7 @@
</func>
<func>
- <name>Module:unregister_subagent(State, PidOrOid) -> Reply</name>
+ <name since="OTP R16B01">Module:unregister_subagent(State, PidOrOid) -> Reply</name>
<fsummary>Unregister the subagent</fsummary>
<type>
<v>State = NewState = term()</v>
@@ -266,7 +266,7 @@
</func>
<func>
- <name>Module:dump(State, Destination) -> Reply</name>
+ <name since="OTP R16B01">Module:dump(State, Destination) -> Reply</name>
<fsummary>Unregister the subagent</fsummary>
<type>
<v>State = term()</v>
@@ -284,7 +284,7 @@
</func>
<func>
- <name>Module:which_mib(State, Oid) -> Reply</name>
+ <name since="OTP R16B01">Module:which_mib(State, Oid) -> Reply</name>
<fsummary>Retrieve the mib file for an oid()</fsummary>
<type>
<v>State = term()</v>
@@ -301,7 +301,7 @@
</func>
<func>
- <name>Module:which_mibs(State) -> Reply</name>
+ <name since="OTP R16B01">Module:which_mibs(State) -> Reply</name>
<fsummary>Retrieve all loaded mib files</fsummary>
<type>
<v>State = term()</v>
@@ -317,7 +317,7 @@
</func>
<func>
- <name>Module:whereis_mib(State, MibName) -> Reply</name>
+ <name since="OTP R16B01">Module:whereis_mib(State, MibName) -> Reply</name>
<fsummary>Retrieve the mib file for the mib</fsummary>
<type>
<v>State = term()</v>
@@ -334,7 +334,7 @@
</func>
<func>
- <name>Module:info(State) -> Reply</name>
+ <name since="OTP R16B01">Module:info(State) -> Reply</name>
<fsummary>Retrieve misc info for the mib data</fsummary>
<type>
<v>State = term()</v>
@@ -352,7 +352,7 @@
</func>
<func>
- <name>Module:backup(State, BackupDir) -> Reply</name>
+ <name since="OTP R16B01">Module:backup(State, BackupDir) -> Reply</name>
<fsummary>Perform a backup of the mib-server data</fsummary>
<type>
<v>State = term()</v>
@@ -370,7 +370,7 @@
</func>
<func>
- <name>Module:code_change(Destination, Vsn, Extra, State) -> NewState</name>
+ <name since="OTP R16B01">Module:code_change(Destination, Vsn, Extra, State) -> NewState</name>
<fsummary>Perform a code-change</fsummary>
<type>
<v>Destination = up | down</v>
diff --git a/lib/snmp/doc/src/snmpa_mib_storage.xml b/lib/snmp/doc/src/snmpa_mib_storage.xml
index 58ce2167ec..ee2b009e77 100644
--- a/lib/snmp/doc/src/snmpa_mib_storage.xml
+++ b/lib/snmp/doc/src/snmpa_mib_storage.xml
@@ -30,7 +30,7 @@
<file>snmpa_mib_storage.xml</file>
</header>
- <module>snmpa_mib_storage</module>
+ <module since="OTP R16B01">snmpa_mib_storage</module>
<modulesummary>
Behaviour module for the SNMP agent mib storage.
</modulesummary>
@@ -96,7 +96,7 @@
<funcs>
<func>
- <name>Module:open(Name, RecordName, Fields, Type, Options) -> {ok, TabId} | {error, Reason}</name>
+ <name since="OTP R16B01">Module:open(Name, RecordName, Fields, Type, Options) -> {ok, TabId} | {error, Reason}</name>
<fsummary>Create new (mib-server) data instance</fsummary>
<type>
<v>Name = atom()</v>
@@ -122,7 +122,7 @@
</func>
<func>
- <name>Module:close(TabId) -> void()</name>
+ <name since="OTP R16B01">Module:close(TabId) -> void()</name>
<fsummary>Close the mib-storage table</fsummary>
<type>
<v>State = term()</v>
@@ -135,7 +135,7 @@
</func>
<func>
- <name>Module:read(TabId, Key) -> false | {value, Record}</name>
+ <name since="OTP R16B01">Module:read(TabId, Key) -> false | {value, Record}</name>
<fsummary>Read a record from the mib-storage table</fsummary>
<type>
<v>TabId = term()</v>
@@ -150,7 +150,7 @@
</func>
<func>
- <name>Module:write(TabId, Record) -> ok | {error, Reason}</name>
+ <name since="OTP R16B01">Module:write(TabId, Record) -> ok | {error, Reason}</name>
<fsummary>Write a record to the mib-storage table</fsummary>
<type>
<v>TabId = term()</v>
@@ -165,7 +165,7 @@
</func>
<func>
- <name>Module:delete(TabId) -> void()</name>
+ <name since="OTP R16B01">Module:delete(TabId) -> void()</name>
<fsummary>Delete an entire mib-storage table</fsummary>
<type>
<v>TabId = term()</v>
@@ -178,7 +178,7 @@
</func>
<func>
- <name>Module:delete(TabId, Key) -> ok | {error, Reason}</name>
+ <name since="OTP R16B01">Module:delete(TabId, Key) -> ok | {error, Reason}</name>
<fsummary>Delete a record from the mib-storage table</fsummary>
<type>
<v>TabId = term()</v>
@@ -193,7 +193,7 @@
</func>
<func>
- <name>Module:match_object(TabId, Pattern) -> {ok, Recs} | {error, Reason}</name>
+ <name since="OTP R16B01">Module:match_object(TabId, Pattern) -> {ok, Recs} | {error, Reason}</name>
<fsummary>Search the mib-storage table for record matching pattern</fsummary>
<type>
<v>TabId = term()</v>
@@ -210,7 +210,7 @@
</func>
<func>
- <name>Module:match_delete(TabId, Pattern) -> {ok, Recs} | {error, Reason}</name>
+ <name since="OTP R16B01">Module:match_delete(TabId, Pattern) -> {ok, Recs} | {error, Reason}</name>
<fsummary>Delete records in the mib-storage table matching pattern</fsummary>
<type>
<v>TabId = term()</v>
@@ -228,7 +228,7 @@
</func>
<func>
- <name>Module:tab2list(TabId) -> Recs</name>
+ <name since="OTP R16B01">Module:tab2list(TabId) -> Recs</name>
<fsummary>Return all records of the mib-storage table</fsummary>
<type>
<v>TabId = term()</v>
@@ -243,7 +243,7 @@
</func>
<func>
- <name>Module:info(TabId) -> {ok, Info} | {error, Reason}</name>
+ <name since="OTP R16B01">Module:info(TabId) -> {ok, Info} | {error, Reason}</name>
<fsummary>Returns information about the mib-storage table. </fsummary>
<type>
<v>TabId = term()</v>
@@ -259,7 +259,7 @@
</func>
<func>
- <name>Module:sync(TabId) -> void()</name>
+ <name since="OTP R16B01">Module:sync(TabId) -> void()</name>
<fsummary>Synchronize mib-storage table</fsummary>
<type>
<v>TabId = term()</v>
@@ -273,7 +273,7 @@
</func>
<func>
- <name>Module:backup(TabId, BackupDir) -> ok | {error, Reason}</name>
+ <name since="OTP R16B01">Module:backup(TabId, BackupDir) -> ok | {error, Reason}</name>
<fsummary>Perform a backup of the mib-storage table</fsummary>
<type>
<v>TabId = term()</v>
diff --git a/lib/snmp/doc/src/snmpa_mpd.xml b/lib/snmp/doc/src/snmpa_mpd.xml
index a39c087c20..d76a9c4a94 100644
--- a/lib/snmp/doc/src/snmpa_mpd.xml
+++ b/lib/snmp/doc/src/snmpa_mpd.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmpa_mpd.xml</file>
</header>
- <module>snmpa_mpd</module>
+ <module since="">snmpa_mpd</module>
<modulesummary>Message Processing and Dispatch module for the SNMP agent</modulesummary>
<description>
<p>The module <c>snmpa_mpd</c> implements the version independent
@@ -52,7 +52,7 @@
<funcs>
<func>
- <name>init(Vsns) -> mpd_state()</name>
+ <name since="">init(Vsns) -> mpd_state()</name>
<fsummary>Initialize the MPD module</fsummary>
<type>
<v>Vsns = [Vsn]</v>
@@ -70,8 +70,8 @@
</func>
<func>
- <name>process_packet(Packet, From, State, NoteStore, Log) -> {ok, Vsn, Pdu, PduMS, ACMData} | {discarded, Reason} | {discovery, DiscoPacket}</name>
- <name>process_packet(Packet, From, LocalEngineID, State, NoteStore, Log) -> {ok, Vsn, Pdu, PduMS, ACMData} | {discarded, Reason} | {discovery, DiscoPacket}</name>
+ <name since="OTP 17.3">process_packet(Packet, From, State, NoteStore, Log) -> {ok, Vsn, Pdu, PduMS, ACMData} | {discarded, Reason} | {discovery, DiscoPacket}</name>
+ <name since="OTP R14B">process_packet(Packet, From, LocalEngineID, State, NoteStore, Log) -> {ok, Vsn, Pdu, PduMS, ACMData} | {discarded, Reason} | {discovery, DiscoPacket}</name>
<fsummary>Process a packet received from the network</fsummary>
<type>
<v>Packet = binary()</v>
@@ -108,8 +108,8 @@
</func>
<func>
- <name>generate_response_msg(Vsn, RePdu, Type, ACMData, Log) -> {ok, Packet} | {discarded, Reason}</name>
- <name>generate_response_msg(Vsn, RePdu, Type, ACMData, LocalEngineID, Log) -> {ok, Packet} | {discarded, Reason}</name>
+ <name since="OTP R14B">generate_response_msg(Vsn, RePdu, Type, ACMData, Log) -> {ok, Packet} | {discarded, Reason}</name>
+ <name since="OTP R14B">generate_response_msg(Vsn, RePdu, Type, ACMData, LocalEngineID, Log) -> {ok, Packet} | {discarded, Reason}</name>
<fsummary>Generate a response packet to be sent to the network</fsummary>
<type>
<v>Vsn = 'version-1' | 'version-2' | 'version-3'</v>
@@ -136,8 +136,8 @@
</func>
<func>
- <name>generate_msg(Vsn, NoteStore, Pdu, MsgData, To) -> {ok, PacketsAndAddresses} | {discarded, Reason}</name>
- <name>generate_msg(Vsn, NoteStore, Pdu, MsgData, LocalEngineID, To) -> {ok, PacketsAndAddresses} | {discarded, Reason}</name>
+ <name since="OTP R14B">generate_msg(Vsn, NoteStore, Pdu, MsgData, To) -> {ok, PacketsAndAddresses} | {discarded, Reason}</name>
+ <name since="OTP R14B">generate_msg(Vsn, NoteStore, Pdu, MsgData, LocalEngineID, To) -> {ok, PacketsAndAddresses} | {discarded, Reason}</name>
<fsummary>Generate a request message to be sent to the network</fsummary>
<type>
<v>Vsn = 'version-1' | 'version-2' | 'version-3'</v>
@@ -185,7 +185,7 @@
</func>
<func>
- <name>process_taddrs(TDests) -> Dests</name>
+ <name since="OTP 17.3">process_taddrs(TDests) -> Dests</name>
<fsummary>Transform addresses from internal MIB format to a less internal
</fsummary>
<type>
@@ -211,7 +211,7 @@
</func>
<func>
- <name>discarded_pdu(Variable) -> void()</name>
+ <name since="">discarded_pdu(Variable) -> void()</name>
<fsummary>Increment the variable associated with a discarded pdu</fsummary>
<type>
<v>Variable = atom()</v>
diff --git a/lib/snmp/doc/src/snmpa_network_interface.xml b/lib/snmp/doc/src/snmpa_network_interface.xml
index d4d4989e90..3e79df11b1 100644
--- a/lib/snmp/doc/src/snmpa_network_interface.xml
+++ b/lib/snmp/doc/src/snmpa_network_interface.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmpa_network_interface.xml</file>
</header>
- <module>snmpa_network_interface</module>
+ <module since="">snmpa_network_interface</module>
<modulesummary>Behaviour module for the SNMP agent network interface.</modulesummary>
<description>
<p>This module defines the behaviour of the agent network
@@ -68,7 +68,7 @@
<funcs>
<func>
- <name>start_link(Prio, NoteStore, MasterAgent, Opts) -> {ok, Pid} | {error, Reason}</name>
+ <name since="">start_link(Prio, NoteStore, MasterAgent, Opts) -> {ok, Pid} | {error, Reason}</name>
<fsummary>Start-link the network interface process</fsummary>
<type>
<v>Prio = priority()</v>
@@ -93,7 +93,7 @@
</func>
<func>
- <name>info(Pid) -> [{Key, Value}]</name>
+ <name since="">info(Pid) -> [{Key, Value}]</name>
<fsummary>Return information about the running network interface process</fsummary>
<type>
<v>Pid = pid()</v>
@@ -112,7 +112,7 @@
</func>
<func>
- <name>verbosity(Pid, Verbosity) -> void()</name>
+ <name since="">verbosity(Pid, Verbosity) -> void()</name>
<fsummary>Change the verbosity of a running network interface process</fsummary>
<type>
<v>Pid = pid()</v>
@@ -126,7 +126,7 @@
</func>
<func>
- <name>get_log_type(Pid) -> {ok, LogType} | {error, Reason}</name>
+ <name since="">get_log_type(Pid) -> {ok, LogType} | {error, Reason}</name>
<fsummary>Get the Audit Trail Log type</fsummary>
<type>
<v>Pid = pid()</v>
@@ -147,7 +147,7 @@
</func>
<func>
- <name>set_log_type(Pid, NewType) -> {ok, OldType} | {error, Reason}</name>
+ <name since="">set_log_type(Pid, NewType) -> {ok, OldType} | {error, Reason}</name>
<fsummary>Change the Audit Trail Log type</fsummary>
<type>
<v>Pid = pid()</v>
diff --git a/lib/snmp/doc/src/snmpa_network_interface_filter.xml b/lib/snmp/doc/src/snmpa_network_interface_filter.xml
index 7cd08f8935..02c7d291dd 100644
--- a/lib/snmp/doc/src/snmpa_network_interface_filter.xml
+++ b/lib/snmp/doc/src/snmpa_network_interface_filter.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmpa_network_interface_filter.xml</file>
</header>
- <module>snmpa_network_interface_filter</module>
+ <module since="">snmpa_network_interface_filter</module>
<modulesummary>Behaviour module for the SNMP agent network-interface filter.</modulesummary>
<description>
<p>This module defines the behaviour of the agent network interface
@@ -101,7 +101,7 @@ pdu_type() = 'get-request' | 'get-next-request' | 'get-response' |
</section>
<funcs>
<func>
- <name>accept_recv(Domain, Addr) -> boolean()</name>
+ <name since="">accept_recv(Domain, Addr) -> boolean()</name>
<fsummary>Shall the received message be accepted</fsummary>
<type>
<v>Domain = transportDomain()</v>
@@ -116,7 +116,7 @@ pdu_type() = 'get-request' | 'get-next-request' | 'get-response' |
</desc>
</func>
<func>
- <name>accept_send(Domain, Addr) -> boolean()</name>
+ <name since="">accept_send(Domain, Addr) -> boolean()</name>
<fsummary>Shall the message be sent</fsummary>
<type>
<v>Domain = transportDomain()</v>
@@ -131,7 +131,7 @@ pdu_type() = 'get-request' | 'get-next-request' | 'get-response' |
</desc>
</func>
<func>
- <name>accept_recv_pdu(Domain, Addr, PduType) -> boolean()</name>
+ <name since="">accept_recv_pdu(Domain, Addr, PduType) -> boolean()</name>
<fsummary>Shall the received pdu be accepted</fsummary>
<type>
<v>Domain = transportDomain()</v>
@@ -148,7 +148,7 @@ pdu_type() = 'get-request' | 'get-next-request' | 'get-response' |
</desc>
</func>
<func>
- <name>accept_send_pdu(Targets, PduType) -> Reply</name>
+ <name since="">accept_send_pdu(Targets, PduType) -> Reply</name>
<fsummary>Shall the pdu be sent</fsummary>
<type>
<v>Targets = targets()</v>
diff --git a/lib/snmp/doc/src/snmpa_notification_delivery_info_receiver.xml b/lib/snmp/doc/src/snmpa_notification_delivery_info_receiver.xml
index cbae158544..5dad372710 100644
--- a/lib/snmp/doc/src/snmpa_notification_delivery_info_receiver.xml
+++ b/lib/snmp/doc/src/snmpa_notification_delivery_info_receiver.xml
@@ -34,7 +34,7 @@
<rev></rev>
<file>snmpa_notification_delivery_info_receiver.xml</file>
</header>
- <module>snmpa_notification_delivery_info_receiver</module>
+ <module since="">snmpa_notification_delivery_info_receiver</module>
<modulesummary>
Behaviour module for the SNMP agent notification delivery
information receiver.
@@ -76,7 +76,7 @@
<funcs>
<func>
- <name>delivery_targets(Tag, Targets, Extra) -> void()</name>
+ <name since="">delivery_targets(Tag, Targets, Extra) -> void()</name>
<fsummary>Inform about target addresses</fsummary>
<type>
<v>Tag = term()</v>
@@ -97,7 +97,7 @@
</func>
<func>
- <name>delivery_info(Tag, Target, DeliveryResult, Extra) -> void()</name>
+ <name since="">delivery_info(Tag, Target, DeliveryResult, Extra) -> void()</name>
<fsummary>Inform about delivery result</fsummary>
<type>
<v>Tag = term()</v>
diff --git a/lib/snmp/doc/src/snmpa_notification_filter.xml b/lib/snmp/doc/src/snmpa_notification_filter.xml
index 0f16ba4440..902412ccc5 100644
--- a/lib/snmp/doc/src/snmpa_notification_filter.xml
+++ b/lib/snmp/doc/src/snmpa_notification_filter.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmpa_notification_filter.xml</file>
</header>
- <module>snmpa_notification_filter</module>
+ <module since="">snmpa_notification_filter</module>
<modulesummary>Behaviour module for the SNMP agent notification filters.</modulesummary>
<description>
<p>This module defines the behaviour of the agent notification
@@ -51,7 +51,7 @@
</description>
<funcs>
<func>
- <name>handle_notification(Notif, Data) -> Reply</name>
+ <name since="">handle_notification(Notif, Data) -> Reply</name>
<fsummary>Handle a notification</fsummary>
<type>
<v>Reply = send | {send, NewNotif} | dont_send</v>
diff --git a/lib/snmp/doc/src/snmpa_supervisor.xml b/lib/snmp/doc/src/snmpa_supervisor.xml
index 86c6fbc350..e11cde390f 100644
--- a/lib/snmp/doc/src/snmpa_supervisor.xml
+++ b/lib/snmp/doc/src/snmpa_supervisor.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmpa_supervisor.xml</file>
</header>
- <module>snmpa_supervisor</module>
+ <module since="">snmpa_supervisor</module>
<modulesummary>A supervisor for the SNMP agent Processes</modulesummary>
<description>
<p>This is the top supervisor for the agent part of the SNMP
@@ -42,7 +42,7 @@
</description>
<funcs>
<func>
- <name>start_sub_sup(Opts) -> {ok, pid()} | {error, {already_started, pid()}} | {error, Reason}</name>
+ <name since="">start_sub_sup(Opts) -> {ok, pid()} | {error, {already_started, pid()}} | {error, Reason}</name>
<fsummary>Start the SNMP supervisor for sub-agents only</fsummary>
<type>
<v>Opts = [opt()]</v>
@@ -60,7 +60,7 @@
</desc>
</func>
<func>
- <name>start_master_sup(Opts) -> {ok, pid()} | {error, {already_started, pid()}} | {error, Reason}</name>
+ <name since="">start_master_sup(Opts) -> {ok, pid()} | {error, {already_started, pid()}} | {error, Reason}</name>
<fsummary>Start the SNMP supervisor for all agents</fsummary>
<type>
<v>Opts = [opt()]</v>
@@ -82,7 +82,7 @@
</desc>
</func>
<func>
- <name>start_sub_agent(ParentAgent,Subtree,Mibs) -> {ok, pid()} | {error, Reason}</name>
+ <name since="">start_sub_agent(ParentAgent,Subtree,Mibs) -> {ok, pid()} | {error, Reason}</name>
<fsummary>Start a sub-agent</fsummary>
<type>
<v>ParentAgent = pid()</v>
@@ -99,7 +99,7 @@
</desc>
</func>
<func>
- <name>stop_sub_agent(SubAgent) -> ok | no_such_child</name>
+ <name since="">stop_sub_agent(SubAgent) -> ok | no_such_child</name>
<fsummary>Stop a sub-agent</fsummary>
<type>
<v>SubAgent = pid()</v>
diff --git a/lib/snmp/doc/src/snmpc.xml b/lib/snmp/doc/src/snmpc.xml
index aba51bb500..b22b32a133 100644
--- a/lib/snmp/doc/src/snmpc.xml
+++ b/lib/snmp/doc/src/snmpc.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmpc.xml</file>
</header>
- <module>snmpc</module>
+ <module since="">snmpc</module>
<modulesummary>Interface Functions to the SNMP toolkit MIB compiler</modulesummary>
<description>
<p>The module <c>snmpc</c> contains interface functions to the
@@ -43,8 +43,8 @@
<funcs>
<func>
- <name>compile(File)</name>
- <name>compile(File, Options) -> {ok, BinFileName} | {error, Reason}</name>
+ <name since="">compile(File)</name>
+ <name since="">compile(File, Options) -> {ok, BinFileName} | {error, Reason}</name>
<fsummary>Compile the specified MIB</fsummary>
<type>
<v>File = string()</v>
@@ -236,7 +236,7 @@
</func>
<func>
- <name>is_consistent(Mibs) -> ok | {error, Reason}</name>
+ <name since="">is_consistent(Mibs) -> ok | {error, Reason}</name>
<fsummary>Check for OID conflicts between MIBs</fsummary>
<type>
<v>Mibs = [MibName]</v>
@@ -252,7 +252,7 @@
</func>
<func>
- <name>mib_to_hrl(MibName) -> ok | {error, Reason}</name>
+ <name since="">mib_to_hrl(MibName) -> ok | {error, Reason}</name>
<fsummary>Generate constants for the objects in the MIB</fsummary>
<type>
<v>MibName = string()</v>
diff --git a/lib/snmp/doc/src/snmpm.xml b/lib/snmp/doc/src/snmpm.xml
index 4818aeb697..c45df98ee0 100644
--- a/lib/snmp/doc/src/snmpm.xml
+++ b/lib/snmp/doc/src/snmpm.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2004</year><year>2016</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmpm.xml</file>
</header>
- <module>snmpm</module>
+ <module since="">snmpm</module>
<modulesummary>Interface functions to the SNMP toolkit manager</modulesummary>
<description>
<p>The module <c>snmpm</c> contains interface functions to the
@@ -77,7 +77,7 @@ sec_level() = noAuthNoPriv | authNoPriv | authPriv
</section>
<funcs>
<func>
- <name>monitor() -> Ref</name>
+ <name since="">monitor() -> Ref</name>
<fsummary>Monitor the snmp manager</fsummary>
<type>
<v>Ref = reference()</v>
@@ -92,7 +92,7 @@ sec_level() = noAuthNoPriv | authNoPriv | authPriv
</func>
<func>
- <name>demonitor(Ref) -> void()</name>
+ <name since="">demonitor(Ref) -> void()</name>
<fsummary>Turn off monitoring of the snmp manager</fsummary>
<type>
<v>Ref = reference()</v>
@@ -105,7 +105,7 @@ sec_level() = noAuthNoPriv | authNoPriv | authPriv
</func>
<func>
- <name>notify_started(Timeout) -> Pid</name>
+ <name since="">notify_started(Timeout) -> Pid</name>
<fsummary>Request to be notified when manager started</fsummary>
<type>
<v>Timeout = integer()</v>
@@ -148,7 +148,7 @@ sec_level() = noAuthNoPriv | authNoPriv | authPriv
</func>
<func>
- <name>cancel_notify_started(Pid) -> void()</name>
+ <name since="">cancel_notify_started(Pid) -> void()</name>
<fsummary>Cancel request to be notified when manager started</fsummary>
<type>
<v>Pid = pid()</v>
@@ -161,8 +161,8 @@ sec_level() = noAuthNoPriv | authNoPriv | authPriv
</func>
<func>
- <name>register_user(Id, Module, Data) -> ok | {error, Reason}</name>
- <name>register_user(Id, Module, Data, DefaultAgentConfig) -> ok | {error, Reason}</name>
+ <name since="">register_user(Id, Module, Data) -> ok | {error, Reason}</name>
+ <name since="">register_user(Id, Module, Data, DefaultAgentConfig) -> ok | {error, Reason}</name>
<fsummary>Register a user of the manager</fsummary>
<type>
<v>Id = term()</v>
@@ -204,8 +204,8 @@ sec_level = noAuthNoPriv | authNoPriv | authPriv
</func>
<func>
- <name>register_user_monitor(Id, Module, Data) -> ok | {error, Reason}</name>
- <name>register_user_monitor(Id, Module, Data, DefaultAgentConfig) -> ok | {error, Reason}</name>
+ <name since="">register_user_monitor(Id, Module, Data) -> ok | {error, Reason}</name>
+ <name since="">register_user_monitor(Id, Module, Data, DefaultAgentConfig) -> ok | {error, Reason}</name>
<fsummary>Register a monitored user of the manager</fsummary>
<type>
<v>Id = term()</v>
@@ -252,7 +252,7 @@ sec_level = noAuthNoPriv | authNoPriv | authPriv
</func>
<func>
- <name>unregister_user(Id) -> ok | {error, Reason}</name>
+ <name since="">unregister_user(Id) -> ok | {error, Reason}</name>
<fsummary>Unregister the user</fsummary>
<type>
<v>Id = term()</v>
@@ -265,7 +265,7 @@ sec_level = noAuthNoPriv | authNoPriv | authPriv
</func>
<func>
- <name>which_users() -> Users</name>
+ <name since="">which_users() -> Users</name>
<fsummary>Get a list of all users</fsummary>
<type>
<v>Users = [UserId]</v>
@@ -279,7 +279,7 @@ sec_level = noAuthNoPriv | authNoPriv | authPriv
</func>
<func>
- <name>register_agent(UserId, TargetName, Config) -> ok | {error, Reason}</name>
+ <name since="">register_agent(UserId, TargetName, Config) -> ok | {error, Reason}</name>
<fsummary>Register this agent</fsummary>
<type>
<v>UserId = term()</v>
@@ -325,7 +325,7 @@ sec_level = noAuthNoPriv | authNoPriv | authPriv
</func>
<func>
- <name>unregister_agent(UserId, TargetName) -> ok | {error, Reason}</name>
+ <name since="">unregister_agent(UserId, TargetName) -> ok | {error, Reason}</name>
<fsummary>Unregister the user</fsummary>
<type>
<v>UserId = term()</v>
@@ -339,7 +339,7 @@ sec_level = noAuthNoPriv | authNoPriv | authPriv
</func>
<func>
- <name>agent_info(TargetName, Item) -> {ok, Val} | {error, Reason}</name>
+ <name since="">agent_info(TargetName, Item) -> {ok, Val} | {error, Reason}</name>
<fsummary>Retrieve agent config</fsummary>
<type>
<v>TargetName = target_name()</v>
@@ -354,8 +354,8 @@ sec_level = noAuthNoPriv | authNoPriv | authPriv
</func>
<func>
- <name>update_agent_info(UserId, TargetName, Info) -> ok | {error, Reason}</name>
- <name>update_agent_info(UserId, TargetName, Item, Val) -> ok | {error, Reason}</name>
+ <name since="OTP R14B04">update_agent_info(UserId, TargetName, Info) -> ok | {error, Reason}</name>
+ <name since="">update_agent_info(UserId, TargetName, Item, Val) -> ok | {error, Reason}</name>
<fsummary>Update agent config</fsummary>
<type>
<v>UserId = term()</v>
@@ -379,8 +379,8 @@ sec_level = noAuthNoPriv | authNoPriv | authPriv
</func>
<func>
- <name>which_agents() -> Agents</name>
- <name>which_agents(UserId) -> Agents</name>
+ <name since="">which_agents() -> Agents</name>
+ <name since="">which_agents(UserId) -> Agents</name>
<fsummary>List the registered agents</fsummary>
<type>
<v>UserId = term()</v>
@@ -396,7 +396,7 @@ sec_level = noAuthNoPriv | authNoPriv | authPriv
</func>
<func>
- <name>register_usm_user(EngineID, UserName, Conf) -> ok | {error, Reason}</name>
+ <name since="">register_usm_user(EngineID, UserName, Conf) -> ok | {error, Reason}</name>
<fsummary>Register this USM user</fsummary>
<type>
<v>EngineID = string()</v>
@@ -427,7 +427,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>unregister_usm_user(EngineID, UserName) -> ok | {error, Reason}</name>
+ <name since="">unregister_usm_user(EngineID, UserName) -> ok | {error, Reason}</name>
<fsummary>Unregister this USM user</fsummary>
<type>
<v>EngineID = string()</v>
@@ -442,7 +442,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>usm_user_info(EngineID, UserName, Item) -> {ok, Val} | {error, Reason}</name>
+ <name since="">usm_user_info(EngineID, UserName, Item) -> {ok, Val} | {error, Reason}</name>
<fsummary>Retrieve usm user config</fsummary>
<type>
<v>EngineID = string()</v>
@@ -458,7 +458,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>update_usm_user_info(EngineID, UserName, Item, Val) -> ok | {error, Reason}</name>
+ <name since="">update_usm_user_info(EngineID, UserName, Item, Val) -> ok | {error, Reason}</name>
<fsummary>Update agent config</fsummary>
<type>
<v>EngineID = string()</v>
@@ -475,7 +475,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>which_usm_users() -> UsmUsers</name>
+ <name since="">which_usm_users() -> UsmUsers</name>
<fsummary>List all the registered usm users</fsummary>
<type>
<v>UsmUsers = [{EngineID,UserName}]</v>
@@ -490,7 +490,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>which_usm_users(EngineID) -> UsmUsers</name>
+ <name since="">which_usm_users(EngineID) -> UsmUsers</name>
<fsummary>List the registered usm users</fsummary>
<type>
<v>UsmUsers = [UserName]</v>
@@ -505,8 +505,8 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>sync_get2(UserId, TargetName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
- <name>sync_get2(UserId, TargetName, Oids, SendOpts) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name since="OTP R14B03">sync_get2(UserId, TargetName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name since="OTP R14B03">sync_get2(UserId, TargetName, Oids, SendOpts) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
<fsummary>Synchronous <c>get-request</c></fsummary>
<type>
<v>UserId = term()</v>
@@ -559,11 +559,11 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>sync_get(UserId, TargetName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
- <name>sync_get(UserId, TargetName, ContextName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
- <name>sync_get(UserId, TargetName, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
- <name>sync_get(UserId, TargetName, ContextName, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
- <name>sync_get(UserId, TargetName, ContextName, Oids, Timeout, ExtraInfo) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name since="">sync_get(UserId, TargetName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name since="">sync_get(UserId, TargetName, ContextName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name since="">sync_get(UserId, TargetName, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name since="">sync_get(UserId, TargetName, ContextName, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name since="">sync_get(UserId, TargetName, ContextName, Oids, Timeout, ExtraInfo) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
<fsummary>Synchronous <c>get-request</c></fsummary>
<type>
<v>UserId = term()</v>
@@ -605,8 +605,8 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>async_get2(UserId, TargetName, Oids) -> {ok, ReqId} | {error, Reason}</name>
- <name>async_get2(UserId, TargetName, Oids, SendOpts) -> {ok, ReqId} | {error, Reason}</name>
+ <name since="OTP R14B03">async_get2(UserId, TargetName, Oids) -> {ok, ReqId} | {error, Reason}</name>
+ <name since="OTP R14B03">async_get2(UserId, TargetName, Oids, SendOpts) -> {ok, ReqId} | {error, Reason}</name>
<fsummary>Asynchronous <c>get-request</c></fsummary>
<type>
<v>UserId = term()</v>
@@ -647,11 +647,11 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>async_get(UserId, TargetName, Oids) -> {ok, ReqId} | {error, Reason}</name>
- <name>async_get(UserId, TargetName, ContextName, Oids) -> {ok, ReqId} | {error, Reason}</name>
- <name>async_get(UserId, TargetName, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name>
- <name>async_get(UserId, TargetName, ContextName, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name>
- <name>async_get(UserId, TargetName, ContextName, Oids, Expire, ExtraInfo) -> {ok, ReqId} | {error, Reason}</name>
+ <name since="">async_get(UserId, TargetName, Oids) -> {ok, ReqId} | {error, Reason}</name>
+ <name since="">async_get(UserId, TargetName, ContextName, Oids) -> {ok, ReqId} | {error, Reason}</name>
+ <name since="">async_get(UserId, TargetName, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name>
+ <name since="">async_get(UserId, TargetName, ContextName, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name>
+ <name since="">async_get(UserId, TargetName, ContextName, Oids, Expire, ExtraInfo) -> {ok, ReqId} | {error, Reason}</name>
<fsummary>Asynchronous <c>get-request</c></fsummary>
<type>
<v>UserId = term()</v>
@@ -683,8 +683,8 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>sync_get_next2(UserId, TargetName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
- <name>sync_get_next2(UserId, TargetName, Oids, SendOpts) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name since="OTP R14B03">sync_get_next2(UserId, TargetName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name since="OTP R14B03">sync_get_next2(UserId, TargetName, Oids, SendOpts) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
<fsummary>Synchronous <c>get-next-request</c></fsummary>
<type>
<v>UserId = term()</v>
@@ -737,11 +737,11 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>sync_get_next(UserId, TargetName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
- <name>sync_get_next(UserId, TargetName, ContextName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
- <name>sync_get_next(UserId, TargetName, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
- <name>sync_get_next(UserId, TargetName, ContextName, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
- <name>sync_get_next(UserId, TargetName, ContextName, Oids, Timeout, ExtraInfo) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name since="">sync_get_next(UserId, TargetName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name since="">sync_get_next(UserId, TargetName, ContextName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name since="">sync_get_next(UserId, TargetName, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name since="">sync_get_next(UserId, TargetName, ContextName, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name since="">sync_get_next(UserId, TargetName, ContextName, Oids, Timeout, ExtraInfo) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
<fsummary>Synchronous <c>get-next-request</c></fsummary>
<type>
<v>UserId = term()</v>
@@ -775,8 +775,8 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>async_get_next2(UserId, TargetName, Oids) -> {ok, ReqId} | {error, Reason}</name>
- <name>async_get_next2(UserId, TargetName, Oids, SendOpts) -> {ok, ReqId} | {error, Reason}</name>
+ <name since="OTP R14B03">async_get_next2(UserId, TargetName, Oids) -> {ok, ReqId} | {error, Reason}</name>
+ <name since="OTP R14B03">async_get_next2(UserId, TargetName, Oids, SendOpts) -> {ok, ReqId} | {error, Reason}</name>
<fsummary>Asynchronous <c>get-next-request</c></fsummary>
<type>
<v>UserId = term()</v>
@@ -814,11 +814,11 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>async_get_next(UserId, TargetName, Oids) -> {ok, ReqId} | {error, Reason}</name>
- <name>async_get_next(UserId, TargetName, ContextName, Oids) -> {ok, ReqId} | {error, Reason}</name>
- <name>async_get_next(UserId, TargetName, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name>
- <name>async_get_next(UserId, TargetName, ContextName, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name>
- <name>async_get_next(UserId, TargetName, ContextName, Oids, Expire, ExtraInfo) -> {ok, ReqId} | {error, Reason}</name>
+ <name since="">async_get_next(UserId, TargetName, Oids) -> {ok, ReqId} | {error, Reason}</name>
+ <name since="">async_get_next(UserId, TargetName, ContextName, Oids) -> {ok, ReqId} | {error, Reason}</name>
+ <name since="">async_get_next(UserId, TargetName, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name>
+ <name since="">async_get_next(UserId, TargetName, ContextName, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name>
+ <name since="">async_get_next(UserId, TargetName, ContextName, Oids, Expire, ExtraInfo) -> {ok, ReqId} | {error, Reason}</name>
<fsummary>Asynchronous <c>get-next-request</c></fsummary>
<type>
<v>UserId = term()</v>
@@ -849,8 +849,8 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>sync_set2(UserId, TargetName, VarsAndVals) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
- <name>sync_set2(UserId, TargetName, VarsAndVals, SendOpts) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name since="OTP R14B03">sync_set2(UserId, TargetName, VarsAndVals) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name since="OTP R14B03">sync_set2(UserId, TargetName, VarsAndVals, SendOpts) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
<fsummary>Synchronous <c>set-request</c></fsummary>
<type>
<v>UserId = term()</v>
@@ -906,11 +906,11 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>sync_set(UserId, TargetName, VarsAndVals) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
- <name>sync_set(UserId, TargetName, ContextName, VarsAndVals) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
- <name>sync_set(UserId, TargetName, VarsAndVals, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
- <name>sync_set(UserId, TargetName, ContextName, VarsAndVals, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
- <name>sync_set(UserId, TargetName, ContextName, VarsAndVals, Timeout, ExtraInfo) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name since="">sync_set(UserId, TargetName, VarsAndVals) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name since="">sync_set(UserId, TargetName, ContextName, VarsAndVals) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name since="">sync_set(UserId, TargetName, VarsAndVals, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name since="">sync_set(UserId, TargetName, ContextName, VarsAndVals, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name since="">sync_set(UserId, TargetName, ContextName, VarsAndVals, Timeout, ExtraInfo) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
<fsummary>Synchronous <c>set-request</c></fsummary>
<type>
<v>UserId = term()</v>
@@ -946,8 +946,8 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>async_set2(UserId, TargetName, VarsAndVals) -> {ok, ReqId} | {error, Reason}</name>
- <name>async_set2(UserId, TargetName, VarsAndVals, SendOpts) -> {ok, ReqId} | {error, Reason}</name>
+ <name since="OTP R14B03">async_set2(UserId, TargetName, VarsAndVals) -> {ok, ReqId} | {error, Reason}</name>
+ <name since="OTP R14B03">async_set2(UserId, TargetName, VarsAndVals, SendOpts) -> {ok, ReqId} | {error, Reason}</name>
<fsummary>Asynchronous <c>set-request</c></fsummary>
<type>
<v>UserId = term()</v>
@@ -990,11 +990,11 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>async_set(UserId, TargetName, VarsAndVals) -> {ok, ReqId} | {error, Reason}</name>
- <name>async_set(UserId, TargetName, ContextName, VarsAndVals) -> {ok, ReqId} | {error, Reason}</name>
- <name>async_set(UserId, TargetName, VarsAndVals, Expire) -> {ok, ReqId} | {error, Reason}</name>
- <name>async_set(UserId, TargetName, ContextName, VarsAndVals, Expire) -> {ok, ReqId} | {error, Reason}</name>
- <name>async_set(UserId, TargetName, ContextName, VarsAndVals, Expire, ExtraInfo) -> {ok, ReqId} | {error, Reason}</name>
+ <name since="">async_set(UserId, TargetName, VarsAndVals) -> {ok, ReqId} | {error, Reason}</name>
+ <name since="">async_set(UserId, TargetName, ContextName, VarsAndVals) -> {ok, ReqId} | {error, Reason}</name>
+ <name since="">async_set(UserId, TargetName, VarsAndVals, Expire) -> {ok, ReqId} | {error, Reason}</name>
+ <name since="">async_set(UserId, TargetName, ContextName, VarsAndVals, Expire) -> {ok, ReqId} | {error, Reason}</name>
+ <name since="">async_set(UserId, TargetName, ContextName, VarsAndVals, Expire, ExtraInfo) -> {ok, ReqId} | {error, Reason}</name>
<fsummary>Asynchronous <c>set-request</c></fsummary>
<type>
<v>UserId = term()</v>
@@ -1026,8 +1026,8 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>sync_get_bulk2(UserId, TragetName, NonRep, MaxRep, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
- <name>sync_get_bulk2(UserId, TragetName, NonRep, MaxRep, Oids, SendOpts) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name since="OTP R14B03">sync_get_bulk2(UserId, TragetName, NonRep, MaxRep, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name since="OTP R14B03">sync_get_bulk2(UserId, TragetName, NonRep, MaxRep, Oids, SendOpts) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
<fsummary>Synchronous <c>get-bulk-request</c></fsummary>
<type>
<v>UserId = term()</v>
@@ -1082,11 +1082,11 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>sync_get_bulk(UserId, TragetName, NonRep, MaxRep, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
- <name>sync_get_bulk(UserId, TragetName, NonRep, MaxRep, ContextName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
- <name>sync_get_bulk(UserId, TragetName, NonRep, MaxRep, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
- <name>sync_get_bulk(UserId, TragetName, NonRep, MaxRep, ContextName, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
- <name>sync_get_bulk(UserId, TragetName, NonRep, MaxRep, ContextName, Oids, Timeout, ExtraInfo) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name since="">sync_get_bulk(UserId, TragetName, NonRep, MaxRep, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name since="">sync_get_bulk(UserId, TragetName, NonRep, MaxRep, ContextName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name since="">sync_get_bulk(UserId, TragetName, NonRep, MaxRep, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name since="">sync_get_bulk(UserId, TragetName, NonRep, MaxRep, ContextName, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name since="">sync_get_bulk(UserId, TragetName, NonRep, MaxRep, ContextName, Oids, Timeout, ExtraInfo) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
<fsummary>Synchronous <c>get-bulk-request</c></fsummary>
<type>
<v>UserId = term()</v>
@@ -1121,8 +1121,8 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>async_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids) -> {ok, ReqId} | {error, Reason}</name>
- <name>async_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids, SendOpts) -> {ok, ReqId} | {error, Reason}</name>
+ <name since="OTP R14B03">async_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids) -> {ok, ReqId} | {error, Reason}</name>
+ <name since="OTP R14B03">async_get_bulk2(UserId, TargetName, NonRep, MaxRep, Oids, SendOpts) -> {ok, ReqId} | {error, Reason}</name>
<fsummary>Asynchronous <c>get-bulk-request</c></fsummary>
<type>
<v>UserId = term()</v>
@@ -1162,11 +1162,11 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>async_get_bulk(UserId, TargetName, NonRep, MaxRep, Oids) -> {ok, ReqId} | {error, Reason}</name>
- <name>async_get_bulk(UserId, TargetName, NonRep, MaxRep, ContextName, Oids) -> {ok, ReqId} | {error, Reason}</name>
- <name>async_get_bulk(UserId, TargetName, NonRep, MaxRep, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name>
- <name>async_get_bulk(UserId, TargetName, NonRep, MaxRep, ContextName, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name>
- <name>async_get_bulk(UserId, TargetName, NonRep, MaxRep, ContextName, Oids, Expire, ExtraInfo) -> {ok, ReqId} | {error, Reason}</name>
+ <name since="">async_get_bulk(UserId, TargetName, NonRep, MaxRep, Oids) -> {ok, ReqId} | {error, Reason}</name>
+ <name since="">async_get_bulk(UserId, TargetName, NonRep, MaxRep, ContextName, Oids) -> {ok, ReqId} | {error, Reason}</name>
+ <name since="">async_get_bulk(UserId, TargetName, NonRep, MaxRep, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name>
+ <name since="">async_get_bulk(UserId, TargetName, NonRep, MaxRep, ContextName, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name>
+ <name since="">async_get_bulk(UserId, TargetName, NonRep, MaxRep, ContextName, Oids, Expire, ExtraInfo) -> {ok, ReqId} | {error, Reason}</name>
<fsummary>Asynchronous <c>get-bulk-request</c></fsummary>
<type>
<v>UserId = term()</v>
@@ -1199,7 +1199,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>cancel_async_request(UserId, ReqId) -> ok | {error, Reason}</name>
+ <name since="">cancel_async_request(UserId, ReqId) -> ok | {error, Reason}</name>
<fsummary>Cancel a asynchronous request</fsummary>
<type>
<v>UserId = term()</v>
@@ -1214,15 +1214,15 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>log_to_txt(LogDir)</name>
- <name>log_to_txt(LogDir, Block | Mibs)</name>
- <name>log_to_txt(LogDir, Mibs, Block | OutFile) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, Block | LogName) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, Block | LogFile) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> ok | {error, Reason}</name>
+ <name since="OTP R16B03">log_to_txt(LogDir)</name>
+ <name since="">log_to_txt(LogDir, Block | Mibs)</name>
+ <name since="">log_to_txt(LogDir, Mibs, Block | OutFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="">log_to_txt(LogDir, Mibs, OutFile, Block | LogName) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="">log_to_txt(LogDir, Mibs, OutFile, LogName, Block | LogFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="">log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="">log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="">log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="OTP R16B03">log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
<fsummary>Convert an Audit Trail Log to text format</fsummary>
<type>
<v>LogDir = string()</v>
@@ -1233,6 +1233,9 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
<v>LogName = string()</v>
<v>LogFile = string()</v>
<v>Start = Stop = null | calendar:datetime() | {local_time, calendar:datetime()} | {universal_time, calendar:datetime()} </v>
+ <v>Cnt = {NumOK, NumERR}</v>
+ <v>NumOK = non_neg_integer()</v>
+ <v>NumERR = pos_integer()</v>
<v>Reason = disk_log_open_error() | file_open_error() | term()</v>
<v>disk_log_open_error() = {LogName, term()}</v>
<v>file_open_error() = {OutFile, term()}</v>
@@ -1254,15 +1257,15 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>log_to_io(LogDir) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Block | Mibs) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, Block | LogName) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, Block | LogFile) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> ok | {error, Reason}</name>
+ <name since="OTP R15B01">log_to_io(LogDir) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="OTP R15B01">log_to_io(LogDir, Block | Mibs) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="OTP R15B01">log_to_io(LogDir, Mibs) -> ok | {error, Reason}</name>
+ <name since="OTP R15B01">log_to_io(LogDir, Mibs, Block | LogName) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="OTP R15B01">log_to_io(LogDir, Mibs, LogName, Block | LogFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="OTP R15B01">log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="OTP R15B01">log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="OTP R15B01">log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name since="OTP R16B03">log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
<fsummary>Convert an Audit Trail Log to text format</fsummary>
<type>
<v>LogDir = string()</v>
@@ -1272,6 +1275,9 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
<v>LogName = string()</v>
<v>LogFile = string()</v>
<v>Start = Stop = null | calendar:datetime() | {local_time, calendar:datetime()} | {universal_time, calendar:datetime()} </v>
+ <v>Cnt = {NumOK, NumERR}</v>
+ <v>NumOK = non_neg_integer()</v>
+ <v>NumERR = pos_integer()</v>
<v>Reason = disk_log_open_error() | file_open_error() | term()</v>
<v>disk_log_open_error() = {LogName, term()}</v>
<v>file_open_error() = {OutFile, term()}</v>
@@ -1293,7 +1299,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>change_log_size(NewSize) -> ok | {error, Reason}</name>
+ <name since="">change_log_size(NewSize) -> ok | {error, Reason}</name>
<fsummary>Change the size of the Audit Trail Log</fsummary>
<type>
<v>NewSize = {MaxBytes, MaxFiles}</v>
@@ -1315,7 +1321,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>set_log_type(NewType) -> {ok, OldType} | {error, Reason}</name>
+ <name since="">set_log_type(NewType) -> {ok, OldType} | {error, Reason}</name>
<fsummary>Change the Audit Trail Log type</fsummary>
<type>
<v>NewType = OldType = atl_type()</v>
@@ -1334,7 +1340,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>load_mib(Mib) -> ok | {error, Reason}</name>
+ <name since="">load_mib(Mib) -> ok | {error, Reason}</name>
<fsummary>Load a MIB into the manager</fsummary>
<type>
<v>Mib = MibName</v>
@@ -1355,7 +1361,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>unload_mib(Mib) -> ok | {error, Reason}</name>
+ <name since="">unload_mib(Mib) -> ok | {error, Reason}</name>
<fsummary>Unload a MIB from the manager</fsummary>
<type>
<v>Mib = MibName</v>
@@ -1376,7 +1382,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>which_mibs() -> Mibs</name>
+ <name since="">which_mibs() -> Mibs</name>
<fsummary>Which mibs are loaded into the manager</fsummary>
<type>
<v>Mibs = [{MibName, MibFile}]</v>
@@ -1391,7 +1397,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>name_to_oid(Name) -> {ok, Oids} | {error, Reason}</name>
+ <name since="">name_to_oid(Name) -> {ok, Oids} | {error, Reason}</name>
<fsummary>Get all the possible oid's for an alias-name</fsummary>
<type>
<v>Name = atom()</v>
@@ -1408,7 +1414,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>oid_to_name(Oid) -> {ok, Name} | {error, Reason}</name>
+ <name since="">oid_to_name(Oid) -> {ok, Name} | {error, Reason}</name>
<fsummary>Get the alias-name of the oid </fsummary>
<type>
<v>Oid = oid()</v>
@@ -1423,7 +1429,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>oid_to_type(Oid) -> {ok, Type} | {error, Reason}</name>
+ <name since="">oid_to_type(Oid) -> {ok, Type} | {error, Reason}</name>
<fsummary>Get the type of the the oid</fsummary>
<type>
<v>Oid = oid()</v>
@@ -1438,7 +1444,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>backup(BackupDir) -> ok | {error, Reason}</name>
+ <name since="">backup(BackupDir) -> ok | {error, Reason}</name>
<fsummary>Backup manager data</fsummary>
<type>
<v>BackupDir = string()</v>
@@ -1452,7 +1458,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>info() -> [{Key, Value}]</name>
+ <name since="">info() -> [{Key, Value}]</name>
<fsummary>Return information about the manager</fsummary>
<type>
<v>Key = atom()</v>
@@ -1469,7 +1475,7 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>verbosity(Ref, Verbosity) -> void()</name>
+ <name since="">verbosity(Ref, Verbosity) -> void()</name>
<fsummary>Assign a new verbosity for the process</fsummary>
<type>
<v>Ref = server | config | net_if | note_store | all</v>
@@ -1486,8 +1492,8 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>format_reason(Reason) -> string()</name>
- <name>format_reason(Prefix, Reason) -> string()</name>
+ <name since="">format_reason(Reason) -> string()</name>
+ <name since="">format_reason(Prefix, Reason) -> string()</name>
<fsummary>Assign a new verbosity for the process</fsummary>
<type>
<v>Reason = term()</v>
diff --git a/lib/snmp/doc/src/snmpm_conf.xml b/lib/snmp/doc/src/snmpm_conf.xml
index a3097e5f7e..17ecf2df7c 100644
--- a/lib/snmp/doc/src/snmpm_conf.xml
+++ b/lib/snmp/doc/src/snmpm_conf.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmpm_conf.xml</file>
</header>
- <module>snmpm_conf</module>
+ <module since="">snmpm_conf</module>
<modulesummary>Utility functions for handling the manager config files.</modulesummary>
<description>
<p>The module <c>snmpm_conf</c> contains various utility functions to
@@ -42,7 +42,7 @@
</description>
<funcs>
<func>
- <name>manager_entry(Tag, Val) -> manager_entry()</name>
+ <name since="">manager_entry(Tag, Val) -> manager_entry()</name>
<fsummary>Create an manager entry</fsummary>
<type>
<v>Tag = address | port | engine_id | max_message_size</v>
@@ -60,8 +60,8 @@
</desc>
</func>
<func>
- <name>write_manager_config(Dir, Conf) -> ok</name>
- <name>write_manager_config(Dir, Hdr, Conf) -> ok</name>
+ <name since="">write_manager_config(Dir, Conf) -> ok</name>
+ <name since="">write_manager_config(Dir, Hdr, Conf) -> ok</name>
<fsummary>Write the manager config to the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -81,7 +81,7 @@
</desc>
</func>
<func>
- <name>append_manager_config(Dir, Conf) -> ok</name>
+ <name since="">append_manager_config(Dir, Conf) -> ok</name>
<fsummary>Append the manager config to the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -98,7 +98,7 @@
</desc>
</func>
<func>
- <name>read_manager_config(Dir) -> Conf</name>
+ <name since="">read_manager_config(Dir) -> Conf</name>
<fsummary>Read the manager config from the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -115,9 +115,9 @@
</desc>
</func>
<func>
- <name>users_entry(UserId) -> users_entry()</name>
- <name>users_entry(UserId, UserMod) -> users_entry()</name>
- <name>users_entry(UserId, UserMod, UserData) -> users_entry()</name>
+ <name since="">users_entry(UserId) -> users_entry()</name>
+ <name since="">users_entry(UserId, UserMod) -> users_entry()</name>
+ <name since="">users_entry(UserId, UserMod, UserData) -> users_entry()</name>
<fsummary>Create an users entry</fsummary>
<type>
<v>UserId = term()</v>
@@ -139,8 +139,8 @@
</desc>
</func>
<func>
- <name>write_users_config(Dir, Conf) -> ok</name>
- <name>write_users_config(Dir, Hdr, Conf) -> ok</name>
+ <name since="">write_users_config(Dir, Conf) -> ok</name>
+ <name since="">write_users_config(Dir, Hdr, Conf) -> ok</name>
<fsummary>Write the manager users config to the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -161,7 +161,7 @@
</desc>
</func>
<func>
- <name>append_users_config(Dir, Conf) -> ok</name>
+ <name since="">append_users_config(Dir, Conf) -> ok</name>
<fsummary>Append the manager users config to the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -179,7 +179,7 @@
</desc>
</func>
<func>
- <name>read_users_config(Dir) -> Conf</name>
+ <name since="">read_users_config(Dir) -> Conf</name>
<fsummary>Read the manager users config from the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -196,7 +196,7 @@
</desc>
</func>
<func>
- <name>agents_entry(UserId, TargetName, Comm, Domain, Addr, EngineID, Timeout, MaxMessageSize, Version, SecModel, SecName, SecLevel) -> agents_entry()</name>
+ <name since="">agents_entry(UserId, TargetName, Comm, Domain, Addr, EngineID, Timeout, MaxMessageSize, Version, SecModel, SecName, SecLevel) -> agents_entry()</name>
<fsummary>Create an agents entry</fsummary>
<type>
<v>UserId = term()</v>
@@ -223,8 +223,8 @@
</desc>
</func>
<func>
- <name>write_agents_config(Dir, Conf) -> ok</name>
- <name>write_agents_config(Dir, Hdr, Conf) -> ok</name>
+ <name since="">write_agents_config(Dir, Conf) -> ok</name>
+ <name since="">write_agents_config(Dir, Hdr, Conf) -> ok</name>
<fsummary>Write the manager agents to the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -245,7 +245,7 @@
</desc>
</func>
<func>
- <name>append_agents_config(Dir, Conf) -> ok</name>
+ <name since="">append_agents_config(Dir, Conf) -> ok</name>
<fsummary>Append the manager agents to the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -263,7 +263,7 @@
</desc>
</func>
<func>
- <name>read_agents_config(Dir) -> Conf</name>
+ <name since="">read_agents_config(Dir) -> Conf</name>
<fsummary>Read the manager agents config from the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -280,8 +280,8 @@
</desc>
</func>
<func>
- <name>usm_entry(EngineID, UserName, AuthP, AuthKey, PrivP, PrivKey) -> usm_entry()</name>
- <name>usm_entry(EngineID, UserName, SecName, AuthP, AuthKey, PrivP, PrivKey) -> usm_entry()</name>
+ <name since="">usm_entry(EngineID, UserName, AuthP, AuthKey, PrivP, PrivKey) -> usm_entry()</name>
+ <name since="">usm_entry(EngineID, UserName, SecName, AuthP, AuthKey, PrivP, PrivKey) -> usm_entry()</name>
<fsummary>Create an usm entry</fsummary>
<type>
<v>EngineID = string()</v>
@@ -303,8 +303,8 @@
</desc>
</func>
<func>
- <name>write_usm_config(Dir, Conf) -> ok</name>
- <name>write_usm_config(Dir, Hdr, Conf) -> ok</name>
+ <name since="">write_usm_config(Dir, Conf) -> ok</name>
+ <name since="">write_usm_config(Dir, Hdr, Conf) -> ok</name>
<fsummary>Write the manager usm config to the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -325,7 +325,7 @@
</desc>
</func>
<func>
- <name>append_usm_config(Dir, Conf) -> ok</name>
+ <name since="">append_usm_config(Dir, Conf) -> ok</name>
<fsummary>Append the manager usm config to the config file</fsummary>
<type>
<v>Dir = string()</v>
@@ -343,7 +343,7 @@
</desc>
</func>
<func>
- <name>read_usm_config(Dir) -> Conf</name>
+ <name since="">read_usm_config(Dir) -> Conf</name>
<fsummary>Read the manager usm config from the config file</fsummary>
<type>
<v>Dir = string()</v>
diff --git a/lib/snmp/doc/src/snmpm_mpd.xml b/lib/snmp/doc/src/snmpm_mpd.xml
index 08276e4b30..b024f8d294 100644
--- a/lib/snmp/doc/src/snmpm_mpd.xml
+++ b/lib/snmp/doc/src/snmpm_mpd.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmpm_mpd.xml</file>
</header>
- <module>snmpm_mpd</module>
+ <module since="">snmpm_mpd</module>
<modulesummary>Message Processing and Dispatch module for the SNMP manager</modulesummary>
<description>
<p>The module <c>snmpm_mpd</c> implements the version independent
@@ -48,7 +48,7 @@
<funcs>
<func>
- <name>init_mpd(Vsns) -> mpd_state()</name>
+ <name since="">init_mpd(Vsns) -> mpd_state()</name>
<fsummary>Initialize the MPD module</fsummary>
<type>
<v>Vsns = [Vsn]</v>
@@ -64,7 +64,7 @@
</desc>
</func>
<func>
- <name>process_msg(Msg, Domain, Addr, State, NoteStore, Logger) -> {ok, Vsn, Pdu, PduMS, MsgData} | {discarded, Reason}</name>
+ <name since="OTP 17.3">process_msg(Msg, Domain, Addr, State, NoteStore, Logger) -> {ok, Vsn, Pdu, PduMS, MsgData} | {discarded, Reason}</name>
<fsummary>Process a message received from the network</fsummary>
<type>
<v>Msg = binary()</v>
@@ -92,7 +92,7 @@
</desc>
</func>
<func>
- <name>generate_msg(Vsn, NoteStore, Pdu, MsgData, Logger) -> {ok, Packet} | {discarded, Reason}</name>
+ <name since="">generate_msg(Vsn, NoteStore, Pdu, MsgData, Logger) -> {ok, Packet} | {discarded, Reason}</name>
<fsummary>Generate a request message to be sent to the network</fsummary>
<type>
<v>Vsn = 'version-1' | 'version-2' | 'version-3'</v>
@@ -117,7 +117,7 @@
</desc>
</func>
<func>
- <name>generate_response_msg(Vsn, Pdu, MsgData, Logger) -> {ok, Packet} | {discarded, Reason}</name>
+ <name since="">generate_response_msg(Vsn, Pdu, MsgData, Logger) -> {ok, Packet} | {discarded, Reason}</name>
<fsummary>Generate a response packet to be sent to the network</fsummary>
<type>
<v>Vsn = 'version-1' | 'version-2' | 'version-3'</v>
diff --git a/lib/snmp/doc/src/snmpm_network_interface.xml b/lib/snmp/doc/src/snmpm_network_interface.xml
index 73892aa2e8..e4a66ceef2 100644
--- a/lib/snmp/doc/src/snmpm_network_interface.xml
+++ b/lib/snmp/doc/src/snmpm_network_interface.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmpm_network_interface.xml</file>
</header>
- <module>snmpm_network_interface</module>
+ <module since="">snmpm_network_interface</module>
<modulesummary>Behaviour module for the SNMP manager network interface.</modulesummary>
<description>
<p>This module defines the behaviour of the manager network
@@ -79,7 +79,7 @@
<funcs>
<func>
- <name>start_link(Server, NoteStore) -> {ok, Pid} | {error, Reason}</name>
+ <name since="">start_link(Server, NoteStore) -> {ok, Pid} | {error, Reason}</name>
<fsummary>Start-link the network interface process</fsummary>
<type>
<v>Server = pid()</v>
@@ -95,7 +95,7 @@
</func>
<func>
- <name>stop(Pid) -> void()</name>
+ <name since="">stop(Pid) -> void()</name>
<fsummary>Stop the network interface process</fsummary>
<type>
<v>Pid = pid()</v>
@@ -108,7 +108,7 @@
</func>
<func>
- <name>send_pdu(Pid, Pdu, Vsn, MsgData, Domain, Addr, ExtraInfo) -> void()</name>
+ <name since="">send_pdu(Pid, Pdu, Vsn, MsgData, Domain, Addr, ExtraInfo) -> void()</name>
<fsummary>Request the network interface process to send this pdu</fsummary>
<type>
<v>Pid = pid()</v>
@@ -142,7 +142,7 @@
</func>
<func>
- <name>inform_response(Pid, Ref, Addr, Port) -> void()</name>
+ <name since="">inform_response(Pid, Ref, Addr, Port) -> void()</name>
<fsummary>Send the inform-request ack</fsummary>
<type>
<v>Pid = pid()</v>
@@ -163,7 +163,7 @@
</func>
<func>
- <name>note_store(Pid, NoteStore) -> void()</name>
+ <name since="">note_store(Pid, NoteStore) -> void()</name>
<fsummary>Change the verbosity of the network interface process</fsummary>
<type>
<v>Pid = pid()</v>
@@ -179,7 +179,7 @@
</func>
<func>
- <name>info(Pid) -> [{Key, Value}]</name>
+ <name since="">info(Pid) -> [{Key, Value}]</name>
<fsummary>Return information about the running network interface process</fsummary>
<type>
<v>Pid = pid()</v>
@@ -198,7 +198,7 @@
</func>
<func>
- <name>verbosity(Pid, Verbosity) -> void()</name>
+ <name since="">verbosity(Pid, Verbosity) -> void()</name>
<fsummary>Change the verbosity of the network interface process</fsummary>
<type>
<v>Pid = pid()</v>
@@ -212,7 +212,7 @@
</func>
<func>
- <name>get_log_type(Pid) -> {ok, LogType} | {error, Reason}</name>
+ <name since="">get_log_type(Pid) -> {ok, LogType} | {error, Reason}</name>
<fsummary>Get the Audit Trail Log type</fsummary>
<type>
<v>Pid = pid()</v>
@@ -233,7 +233,7 @@
</func>
<func>
- <name>set_log_type(Pid, NewType) -> {ok, OldType} | {error, Reason}</name>
+ <name since="">set_log_type(Pid, NewType) -> {ok, OldType} | {error, Reason}</name>
<fsummary>Change the Audit Trail Log type</fsummary>
<type>
<v>Pid = pid()</v>
diff --git a/lib/snmp/doc/src/snmpm_network_interface_filter.xml b/lib/snmp/doc/src/snmpm_network_interface_filter.xml
index 742cd53fc6..a50572da51 100644
--- a/lib/snmp/doc/src/snmpm_network_interface_filter.xml
+++ b/lib/snmp/doc/src/snmpm_network_interface_filter.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmpm_network_interface_filter.xml</file>
</header>
- <module>snmpm_network_interface_filter</module>
+ <module since="">snmpm_network_interface_filter</module>
<modulesummary>Behaviour module for the SNMP manager network-interface filter.</modulesummary>
<description>
<p>This module defines the behaviour of the manager network interface
@@ -100,7 +100,7 @@ pdu_type() = 'get-request' | 'get-next-request' | 'get-response' |
<funcs>
<func>
- <name>accept_recv(Domain, Addr) -> boolean()</name>
+ <name since="">accept_recv(Domain, Addr) -> boolean()</name>
<fsummary>Shall the received message be accepted</fsummary>
<type>
<v>Domain = transportDomain()</v>
@@ -116,7 +116,7 @@ pdu_type() = 'get-request' | 'get-next-request' | 'get-response' |
</func>
<func>
- <name>accept_send(Domain, Addr) -> boolean()</name>
+ <name since="">accept_send(Domain, Addr) -> boolean()</name>
<fsummary>Shall the message be sent</fsummary>
<type>
<v>Domain = transportDomain()</v>
@@ -132,7 +132,7 @@ pdu_type() = 'get-request' | 'get-next-request' | 'get-response' |
</func>
<func>
- <name>accept_recv_pdu(Domain, Addr, PduType) -> boolean()</name>
+ <name since="">accept_recv_pdu(Domain, Addr, PduType) -> boolean()</name>
<fsummary>Shall the received pdu be accepted</fsummary>
<type>
<v>Domain = transportDomain()</v>
@@ -150,7 +150,7 @@ pdu_type() = 'get-request' | 'get-next-request' | 'get-response' |
</func>
<func>
- <name>accept_send_pdu(Domain, Addr, PduType) -> boolean()</name>
+ <name since="">accept_send_pdu(Domain, Addr, PduType) -> boolean()</name>
<fsummary>Shall the pdu be sent</fsummary>
<type>
<v>Domain = transportDomain()</v>
diff --git a/lib/snmp/doc/src/snmpm_user.xml b/lib/snmp/doc/src/snmpm_user.xml
index 87ae1d224a..9abf596c83 100644
--- a/lib/snmp/doc/src/snmpm_user.xml
+++ b/lib/snmp/doc/src/snmpm_user.xml
@@ -32,7 +32,7 @@
<rev></rev>
<file>snmpm_user.xml</file>
</header>
- <module>snmpm_user</module>
+ <module since="">snmpm_user</module>
<modulesummary>Behaviour module for the SNMP manager user.</modulesummary>
<description>
<p>This module defines the behaviour of the manager user.
@@ -93,7 +93,7 @@ snmp_v1_trap_info() :: {Enteprise :: snmp:oid(),
<funcs>
<func>
- <name>handle_error(ReqId, Reason, UserData) -> void()</name>
+ <name since="">handle_error(ReqId, Reason, UserData) -> void()</name>
<fsummary>Handle error</fsummary>
<type>
<v>ReqId = integer()</v>
@@ -122,7 +122,7 @@ snmp_v1_trap_info() :: {Enteprise :: snmp:oid(),
</func>
<func>
- <name>handle_agent(Domain, Addr, Type, SnmpInfo, UserData) -> Reply</name>
+ <name since="">handle_agent(Domain, Addr, Type, SnmpInfo, UserData) -> Reply</name>
<fsummary>Handle agent</fsummary>
<type>
<v>Domain = transportDomainUdpIpv4 | transportDomainUdpIpv6</v>
@@ -181,7 +181,7 @@ snmp_v1_trap_info() :: {Enteprise :: snmp:oid(),
</func>
<func>
- <name>handle_pdu(TargetName, ReqId, SnmpPduInfo, UserData) -> void()</name>
+ <name since="">handle_pdu(TargetName, ReqId, SnmpPduInfo, UserData) -> void()</name>
<fsummary>Handle the reply to an asynchronous request</fsummary>
<type>
<v>TargetName = target_name()</v>
@@ -202,7 +202,7 @@ snmp_v1_trap_info() :: {Enteprise :: snmp:oid(),
</func>
<func>
- <name>handle_trap(TargetName, SnmpTrapInfo, UserData) -> Reply</name>
+ <name since="">handle_trap(TargetName, SnmpTrapInfo, UserData) -> Reply</name>
<fsummary>Handle a trap/notification message</fsummary>
<type>
<v>TargetName = TargetName2 = target_name()</v>
@@ -225,7 +225,7 @@ snmp_v1_trap_info() :: {Enteprise :: snmp:oid(),
</func>
<func>
- <name>handle_inform(TargetName, SnmpInformInfo, UserData) -> Reply</name>
+ <name since="">handle_inform(TargetName, SnmpInformInfo, UserData) -> Reply</name>
<fsummary>Handle a inform message</fsummary>
<type>
<v>TargetName = TargetName2 = target_name()</v>
@@ -253,7 +253,7 @@ snmp_v1_trap_info() :: {Enteprise :: snmp:oid(),
</func>
<func>
- <name>handle_report(TargetName, SnmpReportInfo, UserData) -> Reply</name>
+ <name since="">handle_report(TargetName, SnmpReportInfo, UserData) -> Reply</name>
<fsummary>Handle a report message</fsummary>
<type>
<v>TargetName = TargetName2 = target_name()</v>
@@ -278,7 +278,7 @@ snmp_v1_trap_info() :: {Enteprise :: snmp:oid(),
</func>
<func>
- <name>handle_invalid_result(IN, OUT) -> void()</name>
+ <name since="OTP R16B03">handle_invalid_result(IN, OUT) -> void()</name>
<fsummary>Handle a report message</fsummary>
<type>
<v>IN = {Func, Args}</v>
diff --git a/lib/snmp/include/snmp_types.hrl b/lib/snmp/include/snmp_types.hrl
index ffe30996dc..eff17a13a3 100644
--- a/lib/snmp/include/snmp_types.hrl
+++ b/lib/snmp/include/snmp_types.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -349,6 +349,9 @@
-define(view_included, 1).
-define(view_excluded, 2).
+-define(view_wildcard, 0).
+-define(view_exact, 1).
+
%%-----------------------------------------------------------------
%% From SNMPv2-SMI
diff --git a/lib/snmp/mibs/Makefile.in b/lib/snmp/mibs/Makefile.in
index 2350194077..77893cbdc8 100644
--- a/lib/snmp/mibs/Makefile.in
+++ b/lib/snmp/mibs/Makefile.in
@@ -41,14 +41,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/snmp-$(VSN)
# Common macros
# ----------------------------------------------------
-# NOTE:
-# The OTP-REG mib actually belongs to another
-# application (otp_mibs), and is exported by this
-# app. But since that app is built later, we have
-# to built it here in order to be able to build
-# OTP-SNMPEA-MIB (that needs otpModules and
-# otpApplications).
-MIBS_A = \
+MIBS = \
RFC1213-MIB \
STANDARD-MIB \
SNMPv2-TM \
@@ -62,16 +55,10 @@ MIBS_A = \
SNMP-VIEW-BASED-ACM-MIB \
SNMP-USM-AES-MIB \
INET-ADDRESS-MIB \
- TRANSPORT-ADDRESS-MIB
-
-MIBS_B = OTP-SNMPEA-MIB
-
-BUILD_MIBS = \
- $(MIBS_A) \
+ TRANSPORT-ADDRESS-MIB \
OTP-REG \
- $(MIBS_B)
-
-MIBS = $(MIBS_A) $(MIBS_B)
+ OTP-TC \
+ OTP-SNMPEA-MIB
STD_v1_MIB_FILES = \
RFC1155-SMI.mib \
@@ -100,8 +87,8 @@ HRL_FILES = $(SNMP_HRL_TARGET_DIR)/SNMPv2-TC.hrl \
TARGET_FILES = \
$(ERL_TOP)/lib/snmp/bin/snmp-v2tov1 \
- $(BUILD_MIBS:%=$(SNMP_BIN_TARGET_DIR)/%.bin) \
- $(HRL_TARGETS) \
+ $(MIBS:%=$(SNMP_BIN_TARGET_DIR)/%.bin) \
+ $(HRL_TARGETS) \
$(V1_MIB_FILES)
@@ -136,21 +123,18 @@ endif
# Targets
# ----------------------------------------------------
-OTP_MIBDIR = $(shell if test -d ../../otp_mibs; then echo otp_mibs; \
- else echo sasl; fi)
-
debug opt: $(TARGET_FILES)
$(ERL_TOP)/lib/snmp/bin/snmp-v2tov1: $(ERL_TOP)/lib/snmp/bin/snmp-v2tov1.src
$(gen_verbose)$(PERL) -p -e 's?%PERL%?$(PERL)? ' < $< > $@
$(V_at)chmod 755 $@
-$(SNMP_BIN_TARGET_DIR)/OTP-REG.bin: $(ERL_TOP)/lib/$(OTP_MIBDIR)/mibs/OTP-REG.mib
- $(snmp_verbose)$(ERLC) -pa $(SNMP_TOOLKIT)/ebin -I $(SNMP_TOOLKIT)/priv/mibs $(SNMP_FLAGS) -o $(SNMP_BIN_TARGET_DIR) $<
-
# To support parallel make, we'll need explicit dependencies
# to ensure that an imported MIB has been compiled when it's needed.
+$(SNMP_BIN_TARGET_DIR)/OTP-TC.bin: \
+ $(SNMP_BIN_TARGET_DIR)/OTP-REG.bin
+
$(SNMP_BIN_TARGET_DIR)/STANDARD-MIB.bin: \
$(SNMP_BIN_TARGET_DIR)/RFC1213-MIB.bin
@@ -208,8 +192,6 @@ info:
@echo ""
@echo "TARGET_FILES = $(TARGET_FILES)"
@echo ""
- @echo "OTP_MIBDIR = $(OTP_MIBDIR)"
- @echo ""
@echo "SNMP_VSN = $(SNMP_VSN)"
@echo "VSN = $(VSN)"
@echo "RELSYSDIR = "$(RELSYSDIR)""
diff --git a/lib/otp_mibs/mibs/OTP-REG.mib b/lib/snmp/mibs/OTP-REG.mib
index bf1585061c..bf1585061c 100644
--- a/lib/otp_mibs/mibs/OTP-REG.mib
+++ b/lib/snmp/mibs/OTP-REG.mib
diff --git a/lib/otp_mibs/mibs/OTP-TC.mib b/lib/snmp/mibs/OTP-TC.mib
index efe5451f0c..efe5451f0c 100644
--- a/lib/otp_mibs/mibs/OTP-TC.mib
+++ b/lib/snmp/mibs/OTP-TC.mib
diff --git a/lib/snmp/src/agent/depend.mk b/lib/snmp/src/agent/depend.mk
index 8eba50fa3b..49c7669e41 100644
--- a/lib/snmp/src/agent/depend.mk
+++ b/lib/snmp/src/agent/depend.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2016. All Rights Reserved.
+# Copyright Ericsson AB 2004-2019. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -24,6 +24,9 @@ $(EBIN)/snmpa_authentication_service.$(EMULATOR): \
$(EBIN)/snmpa_error_report.$(EMULATOR): \
snmpa_error_report.erl
+$(EBIN)/snmpa_get_mechanism.$(EMULATOR): \
+ snmpa_get_mechanism.erl
+
$(EBIN)/snmpa_network_interface.$(EMULATOR): \
snmpa_network_interface.erl
@@ -78,6 +81,20 @@ $(EBIN)/snmpa_error_logger.$(EMULATOR): \
snmpa_error_report.erl \
snmpa_error_logger.erl
+$(EBIN)/snmpa_set.$(EMULATOR): \
+ snmpa_set_mechanism.erl \
+ snmpa_set.erl \
+ ../misc/snmp_verbosity.hrl
+
+$(EBIN)/snmpa_get.$(EMULATOR): \
+ snmpa_get_mechanism.erl \
+ snmpa_get.erl \
+ ../misc/snmp_verbosity.hrl
+
+$(EBIN)/snmpa_get_lib.$(EMULATOR): \
+ snmpa_get_lib.erl \
+ ../misc/snmp_verbosity.hrl
+
$(EBIN)/snmpa_local_db.$(EMULATOR): \
snmpa_local_db.erl \
../misc/snmp_debug.hrl \
diff --git a/lib/snmp/src/agent/modules.mk b/lib/snmp/src/agent/modules.mk
index 0f8615588a..49cc158c2e 100644
--- a/lib/snmp/src/agent/modules.mk
+++ b/lib/snmp/src/agent/modules.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2016. All Rights Reserved.
+# Copyright Ericsson AB 2004-2019. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@ BEHAVIOUR_MODULES = \
snmpa_authentication_service \
snmpa_discovery_handler \
snmpa_error_report \
+ snmpa_get_mechanism \
snmpa_mib_storage \
snmpa_mib_data \
snmpa_network_interface \
@@ -30,12 +31,24 @@ BEHAVIOUR_MODULES = \
snmpa_notification_filter \
snmpa_set_mechanism
+MIB_MODULES = \
+ snmp_community_mib \
+ snmp_framework_mib \
+ snmp_notification_mib \
+ snmp_standard_mib \
+ snmp_target_mib \
+ snmp_user_based_sm_mib \
+ snmp_view_based_acm_mib
+
# snmpa is "plain" interface module but also defines some agent specific types
# and therefor must be compiled before the modules that use them, including
# the behaviour modules...
+# Some of the MIB modules also define types used elsewhere and therefor
+# has to be built before the other mods.
# snmpa_mib_data_ttln
MODULES = \
snmpa \
+ $(MIB_MODULES) \
$(BEHAVIOUR_MODULES) \
snmpa_acm \
snmpa_agent \
@@ -46,6 +59,8 @@ MODULES = \
snmpa_error \
snmpa_error_io \
snmpa_error_logger \
+ snmpa_get \
+ snmpa_get_lib \
snmpa_local_db \
snmpa_mib_storage_ets \
snmpa_mib_storage_dets \
@@ -66,17 +81,10 @@ MODULES = \
snmpa_trap \
snmpa_usm \
snmpa_vacm \
- snmp_community_mib \
- snmp_framework_mib \
snmp_generic \
snmp_generic_mnesia \
snmp_index \
- snmp_notification_mib \
- snmp_shadow_table \
- snmp_standard_mib \
- snmp_target_mib \
- snmp_user_based_sm_mib \
- snmp_view_based_acm_mib
+ snmp_shadow_table
INTERNAL_HRL_FILES = \
diff --git a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
index 02415e8036..c6eeb7cea2 100644
--- a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
+++ b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -37,6 +37,12 @@
%%
-export([emask2imask/1]).
+-export_type([
+ mibview/0,
+ internal_view_mask/0,
+ internal_view_mask_element/0,
+ internal_view_type/0
+ ]).
-include("snmp_types.hrl").
-include("SNMPv2-TC.hrl").
@@ -53,7 +59,13 @@
-type internal_view_mask() :: null | [internal_view_mask_element()].
--type internal_view_mask_element() :: 0 | 1.
+-type internal_view_mask_element() :: ?view_wildcard |
+ ?view_exact.
+-type internal_view_type() :: ?view_included | ?view_excluded.
+
+-type mibview() :: [{SubTree :: snmp:oid(),
+ Mask :: internal_view_mask(),
+ Type :: internal_view_type()}].
-type external_view_mask() :: octet_string(). % At most length of 16 octet
-type octet_string() :: [octet()].
diff --git a/lib/snmp/src/agent/snmpa_agent.erl b/lib/snmp/src/agent/snmpa_agent.erl
index 458b88359b..f280260f47 100644
--- a/lib/snmp/src/agent/snmpa_agent.erl
+++ b/lib/snmp/src/agent/snmpa_agent.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -28,7 +28,8 @@
%% External exports
-export([start_link/4, start_link/5, stop/1]).
--export([subagent_set/2,
+-export([subagent_get/3, subagent_get_next/3,
+ subagent_set/2,
load_mibs/3, unload_mibs/3,
which_mibs/1, whereis_mib/2, info/1,
register_subagent/3, unregister_subagent/2,
@@ -362,12 +363,19 @@ do_init(Prio, Parent, Ref, Options) ->
"~n Options: ~p",[Prio, Parent, Ref, Options]),
Mibs = get_mibs(Options),
+
SetModule = get_set_mechanism(Options),
put(set_module, SetModule),
+ ?vtrace("set-module: ~w", [SetModule]),
+
+ GetModule = get_get_mechanism(Options),
+ put(get_module, GetModule),
+ ?vtrace("get-module: ~w", [GetModule]),
%% OTP-3324. For AXD301.
AuthModule = get_authentication_service(Options),
put(auth_module, AuthModule),
+ ?vtrace("auth-module: ~w", [AuthModule]),
MultiT = get_multi_threaded(Options),
Vsns = get_versions(Options),
@@ -1133,7 +1141,7 @@ handle_call({subagent_get_next, MibView, Varbinds, PduData}, _From, S) ->
"~n PduData: ~p",
[MibView,Varbinds,PduData]),
put_pdu_data(PduData),
- {reply, do_get_next(MibView, Varbinds, infinity), S};
+ {reply, do_get_next(MibView, Varbinds), S};
handle_call({subagent_set, Arguments, PduData}, _From, S) ->
?vlog("[handle_call] subagent set:"
"~n Arguments: ~p"
@@ -1174,7 +1182,7 @@ handle_call({get_next, Vars, Context}, _From, S) ->
?vdebug("Varbinds: ~p",[Varbinds]),
MibView = snmpa_acm:get_root_mib_view(),
Reply =
- case do_get_next(MibView, Varbinds, infinity) of
+ case do_get_next(MibView, Varbinds) of
{noError, 0, NewVarbinds} ->
Vbs = lists:keysort(#varbind.org_index, NewVarbinds),
[{Oid,Val} || #varbind{oid = Oid, value = Val} <- Vbs];
@@ -1786,9 +1794,8 @@ worker_loop(Master) ->
GbMaxVBs, Extra)
end
catch
- T:E ->
- exit({worker_crash, Req, T, E,
- erlang:get_stacktrace()})
+ C:E:S ->
+ exit({worker_crash, Req, C, E, S})
end,
Master ! worker_available,
HandlePduRes; % For debugging...
@@ -1814,9 +1821,8 @@ worker_loop(Master) ->
get(net_if))
end
catch
- T:E ->
- exit({worker_crash, Req, T, E,
- erlang:get_stacktrace()})
+ C:E:S ->
+ exit({worker_crash, Req, C, E, S})
end,
Master ! worker_available,
SendTrapRes; % For debugging...
@@ -2535,22 +2541,31 @@ process_msg(
process_pdu(#pdu{type='get-request', request_id = ReqId, varbinds=Vbs},
_PduMS, Vsn, MibView, _GbMaxVBs) ->
?vtrace("get ~p",[ReqId]),
- Res = get_err(do_get(MibView, Vbs, false)),
- ?vtrace("get result: "
- "~n ~p",[Res]),
+ OrigRes = do_get(MibView, Vbs, false),
+ Res = get_err(OrigRes),
{ErrStatus, ErrIndex, ResVarbinds} =
if
Vsn =:= 'version-1' -> validate_get_v1(Res);
true -> Res
end,
- ?vtrace("get final result: "
- "~n Error status: ~p"
- "~n Error index: ~p"
- "~n Varbinds: ~p",
- [ErrStatus,ErrIndex,ResVarbinds]),
+ if
+ (ErrStatus =/= noError) ->
+ ?vlog("get final result: "
+ "~n Error status: ~p"
+ "~n Error index: ~p"
+ "~n when"
+ "~n Original Result: "
+ "~n ~p", [ErrStatus, ErrIndex, OrigRes]);
+ true ->
+ ?vtrace("get final result: "
+ "~n Error status: ~p"
+ "~n Error index: ~p"
+ "~n Varbinds: ~p",
+ [ErrStatus, ErrIndex, ResVarbinds])
+ end,
ResponseVarbinds = lists:keysort(#varbind.org_index, ResVarbinds),
?vtrace("response varbinds: "
- "~n ~p",[ResponseVarbinds]),
+ "~n ~p", [ResponseVarbinds]),
make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, ResponseVarbinds);
process_pdu(#pdu{type = 'get-next-request', request_id = ReqId, varbinds = Vbs},
@@ -2558,22 +2573,31 @@ process_pdu(#pdu{type = 'get-next-request', request_id = ReqId, varbinds = Vbs},
?vtrace("process get-next-request -> entry with"
"~n ReqId: ~p"
"~n Vbs: ~p"
- "~n MibView: ~p",[ReqId, Vbs, MibView]),
- Res = get_err(do_get_next(MibView, Vbs, infinity)),
- ?vtrace("get-next result: "
- "~n ~p",[Res]),
+ "~n MibView: ~p", [ReqId, Vbs, MibView]),
+ OrigRes = do_get_next(MibView, Vbs),
+ Res = get_err(OrigRes),
{ErrStatus, ErrIndex, ResVarbinds} =
if
Vsn =:= 'version-1' -> validate_next_v1(Res, MibView);
true -> Res
end,
- ?vtrace("get-next final result -> validation result:"
- "~n Error status: ~p"
- "~n Error index: ~p"
- "~n Varbinds: ~p",[ErrStatus,ErrIndex,ResVarbinds]),
+ if
+ (ErrStatus =/= noError) ->
+ ?vlog("get-next final result: "
+ "~n Error status: ~p"
+ "~n Error index: ~p"
+ "~n when"
+ "~n Original Result: "
+ "~n ~p", [ErrStatus, ErrIndex, OrigRes]);
+ true ->
+ ?vtrace("get-next final result:"
+ "~n Error status: ~p"
+ "~n Error index: ~p"
+ "~n Varbinds: ~p", [ErrStatus, ErrIndex, ResVarbinds])
+ end,
ResponseVarbinds = lists:keysort(#varbind.org_index, ResVarbinds),
?vtrace("get-next final result -> response varbinds: "
- "~n ~p",[ResponseVarbinds]),
+ "~n ~p", [ResponseVarbinds]),
make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, ResponseVarbinds);
process_pdu(#pdu{type = 'get-bulk-request',
@@ -2582,31 +2606,50 @@ process_pdu(#pdu{type = 'get-bulk-request',
error_status = NonRepeaters,
error_index = MaxRepetitions},
PduMS, _Vsn, MibView, GbMaxVBs) ->
- {ErrStatus, ErrIndex, ResponseVarbinds} =
- get_err(do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Vbs,
- GbMaxVBs)),
- ?vtrace("get-bulk final result: "
- "~n Error status: ~p"
- "~n Error index: ~p"
- "~n Respons varbinds: ~p",
- [ErrStatus,ErrIndex,ResponseVarbinds]),
+ OrigRes = do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Vbs,
+ GbMaxVBs),
+ {ErrStatus, ErrIndex, ResponseVarbinds} = get_err(OrigRes),
+ if
+ (ErrStatus =/= noError) ->
+ ?vlog("get-bulk final result: "
+ "~n Error Status: ~p"
+ "~n Error Index: ~p"
+ "~n when"
+ "~n Original Result: "
+ "~n ~p", [ErrStatus, ErrIndex, OrigRes]);
+ true ->
+ ?vtrace("get-bulk final result: "
+ "~n Error status: ~p"
+ "~n Error index: ~p"
+ "~n Response Varbinds: ~p",
+ [ErrStatus, ErrIndex, ResponseVarbinds])
+ end,
make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, ResponseVarbinds);
process_pdu(#pdu{type = 'set-request', request_id = ReqId, varbinds = Vbs},
- _PduMS, Vsn, MibView, _GbMaxVbs)->
- Res = do_set(MibView, Vbs),
- ?vtrace("set result: "
- "~n ~p",[Res]),
+ _PduMS, Vsn, MibView, _GbMaxVbs) ->
+ OrigRes = do_set(MibView, Vbs),
{ErrStatus, ErrIndex} =
if
- Vsn =:= 'version-1' -> validate_err(v2_to_v1, Res);
- true -> Res
+ Vsn =:= 'version-1' -> validate_err(v2_to_v1, OrigRes);
+ true -> OrigRes
end,
- ?vtrace("set final result: "
- "~n Error status: ~p"
- "~n Error index: ~p",[ErrStatus,ErrIndex]),
+ if
+ (ErrStatus =/= noError) ->
+ ?vlog("set final result: "
+ "~n Error Status: ~p"
+ "~n Error Index: ~p"
+ "~n when"
+ "~n Original Result: "
+ "~n ~p", [ErrStatus, ErrIndex, OrigRes]);
+ true ->
+ ?vtrace("set final result: "
+ "~n Error Status: ~p"
+ "~n Error Index: ~p", [ErrStatus, ErrIndex])
+ end,
make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, Vbs).
+
%%-----------------------------------------------------------------
%% Transform a value == noSuchInstance | noSuchObject or a
%% Counter64 type to a noSuchName error for the whole pdu.
@@ -2650,8 +2693,7 @@ validate_next_v1_2([Vb | _Vbs], _MibView, _Res)
{noSuchName, Vb#varbind.org_index};
validate_next_v1_2([Vb | Vbs], MibView, Res)
when Vb#varbind.variabletype =:= 'Counter64' ->
- case validate_next_v1(
- do_get_next(MibView, [mk_next_oid(Vb)], infinity), MibView) of
+ case validate_next_v1( do_get_next(MibView, [mk_next_oid(Vb)]), MibView) of
{noError, 0, [NVb]} ->
validate_next_v1_2(Vbs, MibView, [NVb | Res]);
{Error, Index, _OrgVb} ->
@@ -2693,6 +2735,20 @@ mk_next_oid(Vb) ->
%%%-----------------------------------------------------------------
%%-----------------------------------------------------------------
+%% Func: do_get/2
+%% Purpose: Handles all VBs in a request that is inside the
+%% mibview (local).
+%% Returns: {noError, 0, ListOfNewVarbinds} |
+%% {ErrorStatus, ErrorIndex, []}
+%%-----------------------------------------------------------------
+
+do_get(UnsortedVarbinds, IsNotification) ->
+ Extra = get(net_if_data),
+ GetModule = get(get_module),
+ GetModule:do_get(UnsortedVarbinds, IsNotification, Extra).
+
+
+%%-----------------------------------------------------------------
%% Func: do_get/3
%% Purpose: do_get handles "getRequests".
%% Pre: incoming varbinds have type == 'NULL', value == unSpecified
@@ -2700,390 +2756,24 @@ mk_next_oid(Vb) ->
%% {ErrorStatus, ErrorIndex, []}
%%-----------------------------------------------------------------
-%% If this function is called from a worker-process, we *may*
-%% need to tunnel into the master-agent and let it do the
-%% work
+%% If this function is called from a worker-process (or other process),
+%% we *may* need to tunnel into the master-agent and let it do the work.
do_get(MibView, UnsortedVarbinds, IsNotification) ->
- do_get(MibView, UnsortedVarbinds, IsNotification, false).
+ Extra = get(net_if_data),
+ GetModule = get(get_module),
+ GetModule:do_get(MibView, UnsortedVarbinds, IsNotification, Extra).
do_get(MibView, UnsortedVarbinds, IsNotification, ForceMaster) ->
- ?vtrace("do_get -> entry with"
- "~n MibView: ~p"
- "~n UnsortedVarbinds: ~p"
- "~n IsNotification: ~p",
- [MibView, UnsortedVarbinds, IsNotification]),
case (whereis(snmp_master_agent) =:= self()) of
false when (ForceMaster =:= true) ->
- %% I am a lowly worker process, handoff to the master agent
PduData = get_pdu_data(),
call(snmp_master_agent,
{do_get, MibView, UnsortedVarbinds, IsNotification, PduData});
-
- _ ->
- %% This is me, the master, so go ahead
- {OutSideView, InSideView} =
- split_vbs_view(UnsortedVarbinds, MibView),
- {Error, Index, NewVbs} =
- do_get(InSideView, IsNotification),
- {Error, Index, NewVbs ++ OutSideView}
-
- end.
-
-
-split_vbs_view(Vbs, MibView) ->
- ?vtrace("split the varbinds view", []),
- split_vbs_view(Vbs, MibView, [], []).
-
-split_vbs_view([Vb | Vbs], MibView, Out, In) ->
- case snmpa_acm:validate_mib_view(Vb#varbind.oid, MibView) of
- true -> split_vbs_view(Vbs, MibView, Out, [Vb | In]);
- false -> split_vbs_view(Vbs, MibView,
- [Vb#varbind{value = noSuchObject} | Out], In)
- end;
-split_vbs_view([], _MibView, Out, In) ->
- {Out, In}.
-
-do_get(UnsortedVarbinds, IsNotification) ->
- {MyVarbinds, SubagentVarbinds} = sort_varbindlist(UnsortedVarbinds),
- case do_get_local(MyVarbinds, [], IsNotification) of
- {noError, 0, NewMyVarbinds} ->
- case do_get_subagents(SubagentVarbinds, IsNotification) of
- {noError, 0, NewSubagentVarbinds} ->
- {noError, 0, NewMyVarbinds ++ NewSubagentVarbinds};
- {ErrorStatus, ErrorIndex, _} ->
- {ErrorStatus, ErrorIndex, []}
- end;
- {ErrorStatus, ErrorIndex, _} ->
- {ErrorStatus, ErrorIndex, []}
- end.
-
-%%-----------------------------------------------------------------
-%% Func: do_get_local/3
-%% Purpose: Loop the variablebindings list. We know that each varbind
-%% in that list belongs to us.
-%% Returns: {noError, 0, ListOfNewVarbinds} |
-%% {ErrorStatus, ErrorIndex, []}
-%%-----------------------------------------------------------------
-do_get_local([Vb | Vbs], Res, IsNotification) ->
- case try_get(Vb, IsNotification) of
- NewVb when is_record(NewVb, varbind) ->
- do_get_local(Vbs, [NewVb | Res], IsNotification);
- ListOfNewVb when is_list(ListOfNewVb) ->
- do_get_local(Vbs, lists:append(ListOfNewVb, Res), IsNotification);
- {error, Error, OrgIndex} ->
- {Error, OrgIndex, []}
- end;
-do_get_local([], Res, _IsNotification) ->
- {noError, 0, Res}.
-
-%%-----------------------------------------------------------------
-%% Func: do_get_subagents/2
-%% Purpose: Loop the list of varbinds for different subagents.
-%% For each of them, call sub_agent_get to retreive
-%% the values for them.
-%% Returns: {noError, 0, ListOfNewVarbinds} |
-%% {ErrorStatus, ErrorIndex, []}
-%%-----------------------------------------------------------------
-do_get_subagents(SubagentVarbinds, IsNotification) ->
- do_get_subagents(SubagentVarbinds, [], IsNotification).
-do_get_subagents([{SubAgentPid, SAVbs} | Tail], Res, IsNotification) ->
- {_SAOids, Vbs} = sa_split(SAVbs),
- case catch subagent_get(SubAgentPid, Vbs, IsNotification) of
- {noError, 0, NewVbs} ->
- do_get_subagents(Tail, lists:append(NewVbs, Res), IsNotification);
- {ErrorStatus, ErrorIndex, _} ->
- {ErrorStatus, ErrorIndex, []};
- {'EXIT', Reason} ->
- user_err("Lost contact with subagent (get) ~w. Using genErr",
- [Reason]),
- {genErr, 0, []}
- end;
-do_get_subagents([], Res, _IsNotification) ->
- {noError, 0, Res}.
-
-
-%%-----------------------------------------------------------------
-%% Func: try_get/2
-%% Returns: {error, ErrorStatus, OrgIndex} |
-%% #varbind |
-%% List of #varbind
-%%-----------------------------------------------------------------
-try_get(IVb, IsNotification) when is_record(IVb, ivarbind) ->
- ?vtrace("try_get(ivarbind) -> entry with"
- "~n IVb: ~p", [IVb]),
- get_var_value_from_ivb(IVb, IsNotification);
-try_get({TableOid, TableVbs}, IsNotification) ->
- ?vtrace("try_get(table) -> entry with"
- "~n TableOid: ~p"
- "~n TableVbs: ~p", [TableOid, TableVbs]),
- [#ivarbind{mibentry = MibEntry}|_] = TableVbs,
- {NoAccessVbs, AccessVbs} =
- check_all_table_vbs(TableVbs, IsNotification, [], []),
- case get_tab_value_from_mib(MibEntry, TableOid, AccessVbs) of
- {error, ErrorStatus, OrgIndex} ->
- {error, ErrorStatus, OrgIndex};
- NVbs ->
- NVbs ++ NoAccessVbs
- end.
-
-%%-----------------------------------------------------------------
-%% Make sure all requested columns are accessible.
-%%-----------------------------------------------------------------
-check_all_table_vbs([IVb| IVbs], IsNotification, NoA, A) ->
- #ivarbind{mibentry = Me, varbind = Vb} = IVb,
- case Me#me.access of
- 'not-accessible' ->
- NNoA = [Vb#varbind{value = noSuchInstance} | NoA],
- check_all_table_vbs(IVbs, IsNotification, NNoA, A);
- 'accessible-for-notify' when IsNotification =:= false ->
- NNoA = [Vb#varbind{value = noSuchInstance} | NoA],
- check_all_table_vbs(IVbs, IsNotification, NNoA, A);
- 'write-only' ->
- NNoA = [Vb#varbind{value = noSuchInstance} | NoA],
- check_all_table_vbs(IVbs, IsNotification, NNoA, A);
- _ ->
- check_all_table_vbs(IVbs, IsNotification, NoA, [IVb | A])
- end;
-check_all_table_vbs([], _IsNotification, NoA, A) -> {NoA, A}.
-
-%%-----------------------------------------------------------------
-%% Returns: {error, ErrorStatus, OrgIndex} |
-%% #varbind
-%%-----------------------------------------------------------------
-get_var_value_from_ivb(IVb, IsNotification)
- when IVb#ivarbind.status =:= noError ->
- ?vtrace("get_var_value_from_ivb(noError) -> entry", []),
- #ivarbind{mibentry = Me, varbind = Vb} = IVb,
- #varbind{org_index = OrgIndex, oid = Oid} = Vb,
- case Me#me.access of
- 'not-accessible' ->
- Vb#varbind{value = noSuchInstance};
- 'accessible-for-notify' when IsNotification =:= false ->
- Vb#varbind{value = noSuchInstance};
- 'write-only' ->
- Vb#varbind{value = noSuchInstance};
- _ ->
- case get_var_value_from_mib(Me, Oid) of
- {value, Type, Value} ->
- Vb#varbind{variabletype = Type, value = Value};
- {error, ErrorStatus} ->
- {error, ErrorStatus, OrgIndex}
- end
- end;
-get_var_value_from_ivb(#ivarbind{status = Status, varbind = Vb}, _) ->
- ?vtrace("get_var_value_from_ivb(~p) -> entry", [Status]),
- Vb#varbind{value = Status}.
-
-%%-----------------------------------------------------------------
-%% Func: get_var_value_from_mib/1
-%% Purpose:
-%% Returns: {error, ErrorStatus} |
-%% {value, Type, Value}
-%%-----------------------------------------------------------------
-%% Pre: Oid is a correct instance Oid (lookup checked that).
-%% Returns: A correct return value (see make_value_a_correct_value)
-get_var_value_from_mib(#me{entrytype = variable,
- asn1_type = ASN1Type,
- mfa = {Mod, Func, Args}},
- _Oid) ->
- ?vtrace("get_var_value_from_mib(variable) -> entry when"
- "~n Mod: ~p"
- "~n Func: ~p"
- "~n Args: ~p", [Mod, Func, Args]),
- Result = (catch dbg_apply(Mod, Func, [get | Args])),
- % mib shall return {value, <a-nice-value-within-range>} |
- % {noValue, noSuchName} (v1) |
- % {noValue, noSuchObject | noSuchInstance} (v2, v1)
- % everything else (including 'genErr') will generate 'genErr'.
- make_value_a_correct_value(Result, ASN1Type, {Mod, Func, Args});
-
-get_var_value_from_mib(#me{entrytype = table_column,
- oid = MeOid,
- asn1_type = ASN1Type,
- mfa = {Mod, Func, Args}},
- Oid) ->
- ?vtrace("get_var_value_from_mib(table_column) -> entry when"
- "~n MeOid: ~p"
- "~n Mod: ~p"
- "~n Func: ~p"
- "~n Args: ~p"
- "~n Oid: ~p", [MeOid, Mod, Func, Args, Oid]),
- Col = lists:last(MeOid),
- Indexes = snmp_misc:diff(Oid, MeOid),
- [Result] = (catch dbg_apply(Mod, Func, [get, Indexes, [Col] | Args])),
- make_value_a_correct_value(Result, ASN1Type,
- {Mod, Func, Args, Indexes, Col}).
-
-
-%% For table operations we need to pass RestOid down to the table-function.
-%% Its up to the table-function to check for noSuchInstance (ex: a
-%% non-existing row).
-%% Returns: {error, ErrorStatus, OrgIndex} |
-%% {value, Type, Value}
-get_tab_value_from_mib(#me{mfa = {Mod, Func, Args}}, TableOid, TableVbs) ->
- ?vtrace("get_tab_value_from_mib -> entry when"
- "~n Mod: ~p"
- "~n Func: ~p"
- "~n Args: ~p", [Mod, Func, Args]),
- TableOpsWithShortOids = deletePrefixes(TableOid, TableVbs),
- SortedVBsRows = snmpa_svbl:sort_varbinds_rows(TableOpsWithShortOids),
- case get_value_all_rows(SortedVBsRows, Mod, Func, Args, []) of
- {Error, Index} ->
- #ivarbind{varbind = Vb} = lists:nth(Index, TableVbs),
- {error, Error, Vb#varbind.org_index};
- ListOfValues ->
- merge_varbinds_and_value(TableVbs, ListOfValues)
+ _ ->
+ do_get(MibView, UnsortedVarbinds, IsNotification)
end.
-%%-----------------------------------------------------------------
-%% Values is a scrambled list of {CorrectValue, Index}, where Index
-%% is index into the #ivarbind list. So for each Value, we must
-%% find the corresponding #ivarbind, and merge them into a new
-%% #varbind.
-%% The Values list comes from validate_tab_res.
-%%-----------------------------------------------------------------
-merge_varbinds_and_value(IVbs, [{{value, Type, Value}, Index} | Values]) ->
- #ivarbind{varbind = Vb} = lists:nth(Index, IVbs),
- [Vb#varbind{variabletype = Type, value = Value} |
- merge_varbinds_and_value(IVbs, Values)];
-merge_varbinds_and_value(_, []) -> [].
-
-get_value_all_rows([{[], OrgCols} | Rows], Mod, Func, Args, Res) ->
- ?vtrace("get_value_all_rows -> entry when"
- "~n OrgCols: ~p", [OrgCols]),
- Cols = [{{value, noValue, noSuchInstance}, Index} ||
- {_Col, _ASN1Type, Index} <- OrgCols],
- NewRes = lists:append(Cols, Res),
- get_value_all_rows(Rows, Mod, Func, Args, NewRes);
-get_value_all_rows([{RowIndex, OrgCols} | Rows], Mod, Func, Args, Res) ->
- ?vtrace("get_value_all_rows -> entry when"
- "~n RowIndex: ~p"
- "~n OrgCols: ~p", [RowIndex, OrgCols]),
- {DOrgCols, Dup} = remove_duplicates(OrgCols),
- Cols = delete_index(DOrgCols),
- Result = (catch dbg_apply(Mod, Func, [get, RowIndex, Cols | Args])),
- case validate_tab_res(Result, DOrgCols, {Mod, Func, Args}) of
- Values when is_list(Values) ->
- NVals = restore_duplicates(Dup, Values),
- NewRes = lists:append(NVals, Res),
- get_value_all_rows(Rows, Mod, Func, Args, NewRes);
- {error, ErrorStatus, Index} ->
- validate_err(row_set, {ErrorStatus, Index}, {Mod, Func, Args})
- end;
-get_value_all_rows([], _Mod, _Func, _Args, Res) ->
- ?vtrace("get_value_all_rows -> entry when done"
- "~n Res: ~p", [Res]),
- Res.
-
-%%-----------------------------------------------------------------
-%% Returns: list of {ShortOid, ASN1TYpe}
-%%-----------------------------------------------------------------
-deletePrefixes(Prefix, [#ivarbind{varbind = Varbind, mibentry = ME} | Vbs]) ->
- #varbind{oid = Oid} = Varbind,
- [{snmp_misc:diff(Oid, Prefix), ME#me.asn1_type} |
- deletePrefixes(Prefix, Vbs)];
-deletePrefixes(_Prefix, []) -> [].
-
-%%-----------------------------------------------------------------
-%% Args: {RowIndex, list of {ShortOid, ASN1Type}}
-%% Returns: list of Col
-%%-----------------------------------------------------------------
-delete_index([{Col, _Val, _OrgIndex} | T]) ->
- [Col | delete_index(T)];
-delete_index([]) -> [].
-
-%%-----------------------------------------------------------------
-%% This function is called before 'get' on a table, and removes
-%% any duplicate columns. It returns {Cols, DupInfo}. The Cols
-%% are the unique columns. The instrumentation function is
-%% called to get the values. These values, together with the
-%% DupInfo, is later passed to restore_duplicates, which uses
-%% the retrieved values to reconstruct the original column list,
-%% but with the retrieved value for each column.
-%%-----------------------------------------------------------------
-remove_duplicates(Cols) ->
- remove_duplicates(Cols, [], []).
-
-
-remove_duplicates([{Col, V1, OrgIdx1}, {Col, V2, OrgIdx2} | T], NCols, Dup) ->
- remove_duplicates([{Col, V1, OrgIdx1} | T], NCols,
- [{Col, V2, OrgIdx2} | Dup]);
-remove_duplicates([Col | T], NCols, Dup) ->
- remove_duplicates(T, [Col | NCols], Dup);
-remove_duplicates([], NCols, Dup) ->
- {lists:reverse(NCols), lists:reverse(Dup)}.
-
-restore_duplicates([], Cols) ->
- [{Val, OrgIndex} || {_Col, Val, OrgIndex} <- Cols];
-restore_duplicates([{Col, _Val2, OrgIndex2} | Dup],
- [{Col, NVal, OrgIndex1} | Cols]) ->
- [{NVal, OrgIndex2} |
- restore_duplicates(Dup, [{Col, NVal, OrgIndex1} | Cols])];
-restore_duplicates(Dup, [{_Col, Val, OrgIndex} | T]) ->
- [{Val, OrgIndex} | restore_duplicates(Dup, T)].
-
-%% Maps the column number to Index.
-% col_to_index(0, _) -> 0;
-% col_to_index(Col, [{Col, _, Index}|_]) ->
-% Index;
-% col_to_index(Col, [_|Cols]) ->
-% col_to_index(Col, Cols).
-
-%%-----------------------------------------------------------------
-%% Three cases:
-%% 1) All values ok
-%% 2) table_func returned {Error, ...}
-%% 3) Some value in Values list is erroneous.
-%% Args: Value is a list of values from table_func(get..)
-%% OrgCols is a list with {Col, ASN1Type, OrgIndex}
-%% each element in Values and OrgCols correspond to each
-%% other.
-%%-----------------------------------------------------------------
-validate_tab_res(Values, OrgCols, Mfa) when is_list(Values) ->
- {_Col, _ASN1Type, OneIdx} = hd(OrgCols),
- validate_tab_res(Values, OrgCols, Mfa, [], OneIdx);
-validate_tab_res({noValue, Error}, OrgCols, Mfa) ->
- Values = lists:duplicate(length(OrgCols), {noValue, Error}),
- validate_tab_res(Values, OrgCols, Mfa);
-validate_tab_res({genErr, Col}, OrgCols, Mfa) ->
- case lists:keysearch(Col, 1, OrgCols) of
- {value, {_Col, _ASN1Type, Index}} ->
- {error, genErr, Index};
- _ ->
- user_err("Invalid column in {genErr, ~w} from ~w (get)",
- [Col, Mfa]),
- [{_Col, _ASN1Type, Index} | _] = OrgCols,
- {error, genErr, Index}
- end;
-validate_tab_res(genErr, [{_Col, __ASN1Type, Index} | _OrgCols], _Mfa) ->
- {error, genErr, Index};
-validate_tab_res(Error, [{_Col, _ASN1Type, Index} | _OrgCols], Mfa) ->
- user_err("Invalid return value ~w from ~w (get)",[Error, Mfa]),
- {error, genErr, Index}.
-
-validate_tab_res([Value | Values],
- [{Col, ASN1Type, Index} | OrgCols],
- Mfa, Res, I) ->
- %% This one makes it possible to return a list of genErr, which
- %% is not allowed according to the manual. But that's ok, as
- %% everything else will generate a genErr! (the only problem is
- %% that it won't generate a user_error).
- case make_value_a_correct_value(Value, ASN1Type, Mfa) of
- {error, ErrorStatus} ->
- {error, ErrorStatus, Index};
- CorrectValue ->
- NewRes = [{Col, CorrectValue, Index} | Res],
- validate_tab_res(Values, OrgCols, Mfa, NewRes, I)
- end;
-validate_tab_res([], [], _Mfa, Res, _I) ->
- lists:reverse(Res);
-validate_tab_res([], [{_Col, _ASN1Type, Index}|_], Mfa, _Res, _I) ->
- user_err("Too few values returned from ~w (get)", [Mfa]),
- {error, genErr, Index};
-validate_tab_res(_TooMany, [], Mfa, _Res, I) ->
- user_err("Too many values returned from ~w (get)", [Mfa]),
- {error, genErr, I}.
%%%-----------------------------------------------------------------
@@ -3125,491 +2815,12 @@ validate_tab_res(_TooMany, [], Mfa, _Res, I) ->
%% subagent must be considered to be very rare.
%%-----------------------------------------------------------------
-%% It may be a bit agressive to check this already,
-%% but since it is a security measure, it makes sense.
-do_get_next(_MibView, UnsortedVarbinds, GbMaxVBs)
- when (is_integer(GbMaxVBs) andalso (length(UnsortedVarbinds) > GbMaxVBs)) ->
- {tooBig, 0, []}; % What is the correct index in this case?
-do_get_next(MibView, UnsortedVBs, GbMaxVBs) ->
- ?vt("do_get_next -> entry when"
- "~n MibView: ~p"
- "~n UnsortedVBs: ~p", [MibView, UnsortedVBs]),
- SortedVBs = oid_sort_vbs(UnsortedVBs),
- ?vt("do_get_next -> "
- "~n SortedVBs: ~p", [SortedVBs]),
- next_loop_varbinds([], SortedVBs, MibView, [], [], GbMaxVBs).
-
-oid_sort_vbs(Vbs) ->
- lists:keysort(#varbind.oid, Vbs).
-
-next_loop_varbinds(_, Vbs, _MibView, Res, _LAVb, GbMaxVBs)
- when (is_integer(GbMaxVBs) andalso
- ((length(Vbs) + length(Res)) > GbMaxVBs)) ->
- {tooBig, 0, []}; % What is the correct index in this case?
-
-%% LAVb is Last Accessible Vb
-next_loop_varbinds([], [Vb | Vbs], MibView, Res, LAVb, GbMaxVBs) ->
- ?vt("next_loop_varbinds -> entry when"
- "~n Vb: ~p"
- "~n MibView: ~p", [Vb, MibView]),
- case varbind_next(Vb, MibView) of
- endOfMibView ->
- ?vt("next_loop_varbind -> endOfMibView", []),
- RVb = if LAVb =:= [] -> Vb;
- true -> LAVb
- end,
- NewVb = RVb#varbind{variabletype = 'NULL', value = endOfMibView},
- next_loop_varbinds([], Vbs, MibView, [NewVb | Res], [], GbMaxVBs);
-
- {variable, ME, VarOid} when ((ME#me.access =/= 'not-accessible') andalso
- (ME#me.access =/= 'write-only') andalso
- (ME#me.access =/= 'accessible-for-notify')) ->
- ?vt("next_loop_varbind -> variable: "
- "~n ME: ~p"
- "~n VarOid: ~p", [ME, VarOid]),
- case try_get_instance(Vb, ME) of
- {value, noValue, _NoSuchSomething} ->
- ?vt("next_loop_varbind -> noValue", []),
- %% Try next one
- NewVb = Vb#varbind{oid = VarOid,
- value = 'NULL'},
- next_loop_varbinds([], [NewVb | Vbs], MibView, Res, [],
- GbMaxVBs);
- {value, Type, Value} ->
- ?vt("next_loop_varbind -> value"
- "~n Type: ~p"
- "~n Value: ~p", [Type, Value]),
- NewVb = Vb#varbind{oid = VarOid,
- variabletype = Type,
- value = Value},
- next_loop_varbinds([], Vbs, MibView, [NewVb | Res], [],
- GbMaxVBs);
- {error, ErrorStatus} ->
- ?vdebug("next loop varbinds:"
- "~n ErrorStatus: ~p",[ErrorStatus]),
- {ErrorStatus, Vb#varbind.org_index, []}
- end;
- {variable, _ME, VarOid} ->
- ?vt("next_loop_varbind -> variable: "
- "~n VarOid: ~p", [VarOid]),
- RVb = if LAVb =:= [] -> Vb;
- true -> LAVb
- end,
- NewVb = Vb#varbind{oid = VarOid, value = 'NULL'},
- next_loop_varbinds([], [NewVb | Vbs], MibView, Res, RVb, GbMaxVBs);
- {table, TableOid, TableRestOid, ME} ->
- ?vt("next_loop_varbind -> table: "
- "~n TableOid: ~p"
- "~n TableRestOid: ~p"
- "~n ME: ~p", [TableOid, TableRestOid, ME]),
- next_loop_varbinds({table, TableOid, ME,
- [{tab_oid(TableRestOid), Vb}]},
- Vbs, MibView, Res, [], GbMaxVBs);
- {subagent, SubAgentPid, SAOid} ->
- ?vt("next_loop_varbind -> subagent: "
- "~n SubAgentPid: ~p"
- "~n SAOid: ~p", [SubAgentPid, SAOid]),
- NewVb = Vb#varbind{variabletype = 'NULL', value = 'NULL'},
- next_loop_varbinds({subagent, SubAgentPid, SAOid, [NewVb]},
- Vbs, MibView, Res, [], GbMaxVBs)
- end;
-next_loop_varbinds({table, TableOid, ME, TabOids},
- [Vb | Vbs], MibView, Res, _LAVb, GbMaxVBs) ->
- ?vt("next_loop_varbinds(table) -> entry with"
- "~n TableOid: ~p"
- "~n Vb: ~p", [TableOid, Vb]),
- case varbind_next(Vb, MibView) of
- {table, TableOid, TableRestOid, _ME} ->
- next_loop_varbinds({table, TableOid, ME,
- [{tab_oid(TableRestOid), Vb} | TabOids]},
- Vbs, MibView, Res, [], GbMaxVBs);
- _ ->
- case get_next_table(ME, TableOid, TabOids, MibView) of
- {ok, TabRes, TabEndOfTabVbs} ->
- NewVbs = lists:append(TabEndOfTabVbs, [Vb | Vbs]),
- NewRes = lists:append(TabRes, Res),
- next_loop_varbinds([], NewVbs, MibView, NewRes, [],
- GbMaxVBs);
- {ErrorStatus, OrgIndex} ->
- ?vdebug("next loop varbinds: next varbind"
- "~n ErrorStatus: ~p"
- "~n OrgIndex: ~p",
- [ErrorStatus,OrgIndex]),
- {ErrorStatus, OrgIndex, []}
- end
- end;
-next_loop_varbinds({table, TableOid, ME, TabOids},
- [], MibView, Res, _LAVb, GbMaxVBs) ->
- ?vt("next_loop_varbinds(table) -> entry with"
- "~n TableOid: ~p", [TableOid]),
- case get_next_table(ME, TableOid, TabOids, MibView) of
- {ok, TabRes, TabEndOfTabVbs} ->
- ?vt("next_loop_varbinds(table) -> get_next_table result:"
- "~n TabRes: ~p"
- "~n TabEndOfTabVbs: ~p", [TabRes, TabEndOfTabVbs]),
- NewRes = lists:append(TabRes, Res),
- next_loop_varbinds([], TabEndOfTabVbs, MibView, NewRes, [],
- GbMaxVBs);
- {ErrorStatus, OrgIndex} ->
- ?vdebug("next loop varbinds: next table"
- "~n ErrorStatus: ~p"
- "~n OrgIndex: ~p",
- [ErrorStatus,OrgIndex]),
- {ErrorStatus, OrgIndex, []}
- end;
-next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
- [Vb | Vbs], MibView, Res, _LAVb, GbMaxVBs) ->
- ?vt("next_loop_varbinds(subagent) -> entry with"
- "~n SAPid: ~p"
- "~n SAOid: ~p"
- "~n Vb: ~p", [SAPid, SAOid, Vb]),
- case varbind_next(Vb, MibView) of
- {subagent, _SubAgentPid, SAOid} ->
- next_loop_varbinds({subagent, SAPid, SAOid,
- [Vb | SAVbs]},
- Vbs, MibView, Res, [], GbMaxVBs);
- _ ->
- case get_next_sa(SAPid, SAOid, SAVbs, MibView) of
- {ok, SARes, SAEndOfMibViewVbs} ->
- NewVbs = lists:append(SAEndOfMibViewVbs, [Vb | Vbs]),
- NewRes = lists:append(SARes, Res),
- next_loop_varbinds([], NewVbs, MibView, NewRes, [],
- GbMaxVBs);
- {noSuchName, OrgIndex} ->
- %% v1 reply, treat this Vb as endOfMibView, and try again
- %% for the others.
- case lists:keysearch(OrgIndex, #varbind.org_index, SAVbs) of
- {value, EVb} ->
- NextOid = next_oid(SAOid),
- EndOfVb =
- EVb#varbind{oid = NextOid,
- value = {endOfMibView, NextOid}},
- case lists:delete(EVb, SAVbs) of
- [] ->
- next_loop_varbinds([], [EndOfVb, Vb | Vbs],
- MibView, Res, [],
- GbMaxVBs);
- TryAgainVbs ->
- next_loop_varbinds({subagent, SAPid, SAOid,
- TryAgainVbs},
- [EndOfVb, Vb | Vbs],
- MibView, Res, [],
- GbMaxVBs)
- end;
- false ->
- %% bad index from subagent
- {genErr, (hd(SAVbs))#varbind.org_index, []}
- end;
- {ErrorStatus, OrgIndex} ->
- ?vdebug("next loop varbinds: next subagent"
- "~n Vb: ~p"
- "~n ErrorStatus: ~p"
- "~n OrgIndex: ~p",
- [Vb,ErrorStatus,OrgIndex]),
- {ErrorStatus, OrgIndex, []}
- end
- end;
-next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
- [], MibView, Res, _LAVb, GbMaxVBs) ->
- ?vt("next_loop_varbinds(subagent) -> entry with"
- "~n SAPid: ~p"
- "~n SAOid: ~p", [SAPid, SAOid]),
- case get_next_sa(SAPid, SAOid, SAVbs, MibView) of
- {ok, SARes, SAEndOfMibViewVbs} ->
- NewRes = lists:append(SARes, Res),
- next_loop_varbinds([], SAEndOfMibViewVbs, MibView, NewRes, [],
- GbMaxVBs);
- {noSuchName, OrgIndex} ->
- %% v1 reply, treat this Vb as endOfMibView, and try again for
- %% the others.
- case lists:keysearch(OrgIndex, #varbind.org_index, SAVbs) of
- {value, EVb} ->
- NextOid = next_oid(SAOid),
- EndOfVb = EVb#varbind{oid = NextOid,
- value = {endOfMibView, NextOid}},
- case lists:delete(EVb, SAVbs) of
- [] ->
- next_loop_varbinds([], [EndOfVb], MibView, Res, [],
- GbMaxVBs);
- TryAgainVbs ->
- next_loop_varbinds({subagent, SAPid, SAOid,
- TryAgainVbs},
- [EndOfVb], MibView, Res, [],
- GbMaxVBs)
- end;
- false ->
- %% bad index from subagent
- {genErr, (hd(SAVbs))#varbind.org_index, []}
- end;
- {ErrorStatus, OrgIndex} ->
- ?vdebug("next loop varbinds: next subagent"
- "~n ErrorStatus: ~p"
- "~n OrgIndex: ~p",
- [ErrorStatus,OrgIndex]),
- {ErrorStatus, OrgIndex, []}
- end;
-next_loop_varbinds([], [], _MibView, Res, _LAVb, _GbMaxVBs) ->
- ?vt("next_loop_varbinds -> entry when done", []),
- {noError, 0, Res}.
-
-try_get_instance(_Vb, #me{mfa = {M, F, A}, asn1_type = ASN1Type}) ->
- ?vtrace("try_get_instance -> entry with"
- "~n M: ~p"
- "~n F: ~p"
- "~n A: ~p", [M,F,A]),
- Result = (catch dbg_apply(M, F, [get | A])),
- % mib shall return {value, <a-nice-value-within-range>} |
- % {noValue, noSuchName} (v1) |
- % {noValue, noSuchObject | noSuchInstance} (v2, v1)
- % everything else (including 'genErr') will generate 'genErr'.
- make_value_a_correct_value(Result, ASN1Type, {M, F, A}).
-
-tab_oid([]) -> [0];
-tab_oid(X) -> X.
-
-%%-----------------------------------------------------------------
-%% Perform a next, using the varbinds Oid if value is simple
-%% value. If value is {endOf<something>, NextOid}, use NextOid.
-%% This case happens when a table has returned endOfTable, or
-%% a subagent has returned endOfMibView.
-%%-----------------------------------------------------------------
-varbind_next(#varbind{value = Value, oid = Oid}, MibView) ->
- ?vt("varbind_next -> entry with"
- "~n Value: ~p"
- "~n Oid: ~p"
- "~n MibView: ~p", [Value, Oid, MibView]),
- case Value of
- {endOfTable, NextOid} ->
- snmpa_mib:next(get(mibserver), NextOid, MibView);
- {endOfMibView, NextOid} ->
- snmpa_mib:next(get(mibserver), NextOid, MibView);
- _ ->
- snmpa_mib:next(get(mibserver), Oid, MibView)
- end.
+do_get_next(MibView, UnsortedVarbinds) ->
+ Extra = get(net_if_data),
+ GetModule = get(get_module),
+ GetModule:do_get_next(MibView, UnsortedVarbinds, Extra).
-get_next_table(#me{mfa = {M, F, A}}, TableOid, TableOids, MibView) ->
- % We know that all TableOids have at least a column number as oid
- ?vt("get_next_table -> entry with"
- "~n M: ~p"
- "~n F: ~p"
- "~n A: ~p"
- "~n TableOid: ~p"
- "~n TableOids: ~p"
- "~n MibView: ~p", [M, F, A, TableOid, TableOids, MibView]),
- Sorted = snmpa_svbl:sort_varbinds_rows(TableOids),
- case get_next_values_all_rows(Sorted, M,F,A, [], TableOid) of
- NewVbs when is_list(NewVbs) ->
- ?vt("get_next_table -> "
- "~n NewVbs: ~p", [NewVbs]),
- % We must now check each Vb for endOfTable and that it is
- % in the MibView. If not, it becomes a endOfTable. We
- % collect all of these together.
- transform_tab_next_result(NewVbs, {[], []}, MibView);
- {ErrorStatus, OrgIndex} ->
- {ErrorStatus, OrgIndex}
- end.
-
-get_next_values_all_rows([Row | Rows], M, F, A, Res, TabOid) ->
- {RowIndex, TableOids} = Row,
- Cols = delete_index(TableOids),
- ?vt("get_next_values_all_rows -> "
- "~n Cols: ~p", [Cols]),
- Result = (catch dbg_apply(M, F, [get_next, RowIndex, Cols | A])),
- ?vt("get_next_values_all_rows -> "
- "~n Result: ~p", [Result]),
- case validate_tab_next_res(Result, TableOids, {M, F, A}, TabOid) of
- Values when is_list(Values) ->
- ?vt("get_next_values_all_rows -> "
- "~n Values: ~p", [Values]),
- NewRes = lists:append(Values, Res),
- get_next_values_all_rows(Rows, M, F, A, NewRes, TabOid);
- {ErrorStatus, OrgIndex} ->
- {ErrorStatus, OrgIndex}
- end;
-get_next_values_all_rows([], _M, _F, _A, Res, _TabOid) ->
- Res.
-
-transform_tab_next_result([Vb | Vbs], {Res, EndOfs}, MibView) ->
- case Vb#varbind.value of
- {endOfTable, _} ->
-%% ?vtrace("transform_tab_next_result -> endOfTable: "
-%% "split varbinds",[]),
-%% R = split_varbinds(Vbs, Res, [Vb | EndOfs]),
-%% ?vtrace("transform_tab_next_result -> "
-%% "~n R: ~p", [R]),
-%% R;
- split_varbinds(Vbs, Res, [Vb | EndOfs]);
- _ ->
- case snmpa_acm:validate_mib_view(Vb#varbind.oid, MibView) of
- true ->
- transform_tab_next_result(Vbs, {[Vb|Res], EndOfs},MibView);
- _ ->
- Oid = Vb#varbind.oid,
- NewEndOf = Vb#varbind{value = {endOfTable, Oid}},
- transform_tab_next_result(Vbs, {Res, [NewEndOf | EndOfs]},
- MibView)
- end
- end;
-transform_tab_next_result([], {Res, EndOfs}, _MibView) ->
- ?vt("transform_tab_next_result -> entry with: "
- "~n Res: ~p"
- "~n EndIfs: ~p",[Res, EndOfs]),
- {ok, Res, EndOfs}.
-
-%%-----------------------------------------------------------------
-%% Three cases:
-%% 1) All values ok
-%% 2) table_func returned {Error, ...}
-%% 3) Some value in Values list is erroneous.
-%% Args: Value is a list of values from table_func(get_next, ...)
-%% TableOids is a list of {TabRestOid, OrgVb}
-%% each element in Values and TableOids correspond to each
-%% other.
-%% Returns: List of NewVarbinds |
-%% {ErrorStatus, OrgIndex}
-%% (In the NewVarbinds list, the value may be endOfTable)
-%%-----------------------------------------------------------------
-validate_tab_next_res(Values, TableOids, Mfa, TabOid) ->
- ?vt("validate_tab_next_res -> entry with: "
- "~n Values: ~p"
- "~n TableOids: ~p"
- "~n Mfa: ~p"
- "~n TabOid: ~p", [Values, TableOids, Mfa, TabOid]),
- {_Col, _ASN1Type, OneIdx} = hd(TableOids),
- validate_tab_next_res(Values, TableOids, Mfa, [], TabOid,
- next_oid(TabOid), OneIdx).
-validate_tab_next_res([{NextOid, Value} | Values],
- [{_ColNo, OrgVb, _Index} | TableOids],
- Mfa, Res, TabOid, TabNextOid, I) ->
- ?vt("validate_tab_next_res -> entry with: "
- "~n NextOid: ~p"
- "~n Value: ~p"
- "~n Values: ~p"
- "~n TableOids: ~p"
- "~n Mfa: ~p"
- "~n TabOid: ~p",
- [NextOid, Value, Values, TableOids, Mfa, TabOid]),
- #varbind{org_index = OrgIndex} = OrgVb,
- ?vt("validate_tab_next_res -> OrgIndex: ~p", [OrgIndex]),
- NextCompleteOid = lists:append(TabOid, NextOid),
- case snmpa_mib:lookup(get(mibserver), NextCompleteOid) of
- {table_column, #me{asn1_type = ASN1Type}, _TableEntryOid} ->
- ?vt("validate_tab_next_res -> ASN1Type: ~p", [ASN1Type]),
- case make_value_a_correct_value({value, Value}, ASN1Type, Mfa) of
- {error, ErrorStatus} ->
- ?vt("validate_tab_next_res -> "
- "~n ErrorStatus: ~p", [ErrorStatus]),
- {ErrorStatus, OrgIndex};
- {value, Type, NValue} ->
- ?vt("validate_tab_next_res -> "
- "~n Type: ~p"
- "~n NValue: ~p", [Type, NValue]),
- NewVb = OrgVb#varbind{oid = NextCompleteOid,
- variabletype = Type, value = NValue},
- validate_tab_next_res(Values, TableOids, Mfa,
- [NewVb | Res], TabOid, TabNextOid, I)
- end;
- Error ->
- user_err("Invalid oid ~w from ~w (get_next). Using genErr => ~p",
- [NextOid, Mfa, Error]),
- {genErr, OrgIndex}
- end;
-validate_tab_next_res([endOfTable | Values],
- [{_ColNo, OrgVb, _Index} | TableOids],
- Mfa, Res, TabOid, TabNextOid, I) ->
- ?vt("validate_tab_next_res(endOfTable) -> entry with: "
- "~n Values: ~p"
- "~n OrgVb: ~p"
- "~n TableOids: ~p"
- "~n Mfa: ~p"
- "~n Res: ~p"
- "~n TabOid: ~p"
- "~n TabNextOid: ~p"
- "~n I: ~p",
- [Values, OrgVb, TableOids, Mfa, Res, TabOid, TabNextOid, I]),
- NewVb = OrgVb#varbind{value = {endOfTable, TabNextOid}},
- validate_tab_next_res(Values, TableOids, Mfa, [NewVb | Res],
- TabOid, TabNextOid, I);
-validate_tab_next_res([], [], _Mfa, Res, _TabOid, _TabNextOid, _I) ->
- Res;
-validate_tab_next_res([], [{_Col, _OrgVb, Index}|_], Mfa, _Res, _, _, _I) ->
- user_err("Too few values returned from ~w (get_next)", [Mfa]),
- {genErr, Index};
-validate_tab_next_res({genErr, ColNumber}, OrgCols,
- Mfa, _Res, _TabOid, _TabNextOid, _I) ->
- OrgIndex = snmpa_svbl:col_to_orgindex(ColNumber, OrgCols),
- validate_err(table_next, {genErr, OrgIndex}, Mfa);
-validate_tab_next_res({error, Reason}, [{_ColNo, OrgVb, _Index} | _TableOids],
- Mfa, _Res, _TabOid, _TabNextOid, _I) ->
- #varbind{org_index = OrgIndex} = OrgVb,
- user_err("Erroneous return value ~w from ~w (get_next)",
- [Reason, Mfa]),
- {genErr, OrgIndex};
-validate_tab_next_res(Error, [{_ColNo, OrgVb, _Index} | _TableOids],
- Mfa, _Res, _TabOid, _TabNextOid, _I) ->
- #varbind{org_index = OrgIndex} = OrgVb,
- user_err("Invalid return value ~w from ~w (get_next)",
- [Error, Mfa]),
- {genErr, OrgIndex};
-validate_tab_next_res(TooMany, [], Mfa, _Res, _, _, I) ->
- user_err("Too many values ~w returned from ~w (get_next)",
- [TooMany, Mfa]),
- {genErr, I}.
-
-%%-----------------------------------------------------------------
-%% Func: get_next_sa/4
-%% Purpose: Loop the list of varbinds for the subagent.
-%% Call subagent_get_next to retreive
-%% the next varbinds.
-%% Returns: {ok, ListOfNewVbs, ListOfEndOfMibViewsVbs} |
-%% {ErrorStatus, ErrorIndex}
-%%-----------------------------------------------------------------
-get_next_sa(SAPid, SAOid, SAVbs, MibView) ->
- case catch subagent_get_next(SAPid, MibView, SAVbs) of
- {noError, 0, NewVbs} ->
- NewerVbs = transform_sa_next_result(NewVbs,SAOid,next_oid(SAOid)),
- split_varbinds(NewerVbs, [], []);
- {ErrorStatus, ErrorIndex, _} ->
- {ErrorStatus, ErrorIndex};
- {'EXIT', Reason} ->
- user_err("Lost contact with subagent (next) ~w. Using genErr",
- [Reason]),
- {genErr, 0}
- end.
-
-%%-----------------------------------------------------------------
-%% Check for wrong prefix returned or endOfMibView, and convert
-%% into {endOfMibView, SANextOid}.
-%%-----------------------------------------------------------------
-transform_sa_next_result([Vb | Vbs], SAOid, SANextOid)
- when Vb#varbind.value =:= endOfMibView ->
- [Vb#varbind{value = {endOfMibView, SANextOid}} |
- transform_sa_next_result(Vbs, SAOid, SANextOid)];
-transform_sa_next_result([Vb | Vbs], SAOid, SANextOid) ->
- case lists:prefix(SAOid, Vb#varbind.oid) of
- true ->
- [Vb | transform_sa_next_result(Vbs, SAOid, SANextOid)];
- _ ->
- [Vb#varbind{oid = SANextOid, value = {endOfMibView, SANextOid}} |
- transform_sa_next_result(Vbs, SAOid, SANextOid)]
- end;
-transform_sa_next_result([], _SAOid, _SANextOid) ->
- [].
-
-split_varbinds([Vb | Vbs], Res, EndOfs) ->
- case Vb#varbind.value of
- {endOfMibView, _} -> split_varbinds(Vbs, Res, [Vb | EndOfs]);
- {endOfTable, _} -> split_varbinds(Vbs, Res, [Vb | EndOfs]);
- _ -> split_varbinds(Vbs, [Vb | Res], EndOfs)
- end;
-split_varbinds([], Res, EndOfs) -> {ok, Res, EndOfs}.
-
-next_oid(Oid) ->
- case lists:reverse(Oid) of
- [H | T] -> lists:reverse([H+1 | T]);
- [] -> []
- end.
%%%-----------------------------------------------------------------
@@ -3623,200 +2834,12 @@ next_oid(Oid) ->
%%%-----------------------------------------------------------------
do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds, GbMaxVBs) ->
- ?vtrace("do_get_bulk -> entry with"
- "~n MibView: ~p"
- "~n NonRepeaters: ~p"
- "~n MaxRepetitions: ~p"
- "~n PduMS: ~p"
- "~n Varbinds: ~p"
- "~n GbMaxVBs: ~p",
- [MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds, GbMaxVBs]),
- {NonRepVbs, RestVbs} = split_vbs(NonRepeaters, Varbinds, []),
- ?vt("do_get_bulk -> split: "
- "~n NonRepVbs: ~p"
- "~n RestVbs: ~p", [NonRepVbs, RestVbs]),
- case do_get_next(MibView, NonRepVbs, GbMaxVBs) of
- {noError, 0, UResNonRepVbs} ->
- ?vt("do_get_bulk -> next noError: "
- "~n UResNonRepVbs: ~p", [UResNonRepVbs]),
- ResNonRepVbs = lists:keysort(#varbind.org_index, UResNonRepVbs),
- %% Decode the first varbinds, produce a reversed list of
- %% listOfBytes.
- case (catch enc_vbs(PduMS - ?empty_pdu_size, ResNonRepVbs)) of
- {error, Idx, Reason} ->
- user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]),
- {genErr, Idx, []};
- {SizeLeft, Res} when is_integer(SizeLeft) and is_list(Res) ->
- ?vtrace("do_get_bulk -> encoded: "
- "~n SizeLeft: ~p"
- "~n Res: ~w", [SizeLeft, Res]),
- case (catch do_get_rep(SizeLeft, MibView, MaxRepetitions,
- RestVbs, Res,
- length(UResNonRepVbs), GbMaxVBs)) of
- {error, Idx, Reason} ->
- user_err("failed encoding varbind ~w:~n~p",
- [Idx, Reason]),
- {genErr, Idx, []};
- Res when is_list(Res) ->
- ?vtrace("do get bulk -> Res: "
- "~n ~w", [Res]),
- {noError, 0, conv_res(Res)};
- {noError, 0, Data} = OK ->
- ?vtrace("do get bulk -> OK: "
- "~n length(Data): ~w", [length(Data)]),
- OK;
- Else ->
- ?vtrace("do get bulk -> Else: "
- "~n ~w", [Else]),
- Else
- end;
- Res when is_list(Res) ->
- {noError, 0, conv_res(Res)}
- end;
+ Extra = get(net_if_data),
+ GetModule = get(get_module),
+ GetModule:do_get_bulk(MibView, NonRepeaters, MaxRepetitions,
+ PduMS, Varbinds, GbMaxVBs,
+ Extra).
- {ErrorStatus, Index, _} ->
- ?vdebug("do get bulk: "
- "~n ErrorStatus: ~p"
- "~n Index: ~p",[ErrorStatus, Index]),
- {ErrorStatus, Index, []}
- end.
-
-% sz(L) when list(L) -> length(L);
-% sz(B) when binary(B) -> size(B);
-% sz(_) -> unknown.
-
-split_vbs(N, Varbinds, Res) when N =< 0 -> {Res, Varbinds};
-split_vbs(N, [H | T], Res) -> split_vbs(N-1, T, [H | Res]);
-split_vbs(_N, [], Res) -> {Res, []}.
-
-enc_vbs(SizeLeft, Vbs) ->
- ?vt("enc_vbs -> entry with"
- "~n SizeLeft: ~w", [SizeLeft]),
- Fun = fun(Vb, {Sz, Res}) when Sz > 0 ->
- ?vt("enc_vbs -> (fun) entry with"
- "~n Vb: ~p"
- "~n Sz: ~p"
- "~n Res: ~w", [Vb, Sz, Res]),
- case (catch snmp_pdus:enc_varbind(Vb)) of
- {'EXIT', Reason} ->
- ?vtrace("enc_vbs -> encode failed: "
- "~n Reason: ~p", [Reason]),
- throw({error, Vb#varbind.org_index, Reason});
- X ->
- ?vt("enc_vbs -> X: ~w", [X]),
- Lx = length(X),
- ?vt("enc_vbs -> Lx: ~w", [Lx]),
- if
- Lx < Sz ->
- {Sz - length(X), [X | Res]};
- true ->
- throw(Res)
- end
- end;
- (_Vb, {_Sz, [_H | T]}) ->
- ?vt("enc_vbs -> (fun) entry with"
- "~n T: ~p", [T]),
- throw(T);
- (_Vb, {_Sz, []}) ->
- ?vt("enc_vbs -> (fun) entry", []),
- throw([])
- end,
- lists:foldl(Fun, {SizeLeft, []}, Vbs).
-
-do_get_rep(Sz, MibView, MaxRepetitions, Varbinds, Res, GbNumVBs, GbMaxVBs)
- when MaxRepetitions >= 0 ->
- do_get_rep(Sz, MibView, 0, MaxRepetitions, Varbinds, Res,
- GbNumVBs, GbMaxVBs);
-do_get_rep(Sz, MibView, _MaxRepetitions, Varbinds, Res, GbNumVBs, GbMaxVBs) ->
- do_get_rep(Sz, MibView, 0, 0, Varbinds, Res, GbNumVBs, GbMaxVBs).
-
-conv_res(ResVarbinds) ->
- conv_res(ResVarbinds, []).
-conv_res([VbListOfBytes | T], Bytes) ->
- conv_res(T, VbListOfBytes ++ Bytes);
-conv_res([], Bytes) ->
- Bytes.
-
-%% The only other value, then a positive integer, is infinity.
-do_get_rep(_Sz, _MibView, Count, Max, _, _Res, GbNumVBs, GbMaxVBs)
- when (is_integer(GbMaxVBs) andalso (GbNumVBs > GbMaxVBs)) ->
- ?vinfo("Max Get-BULK VBs limit (~w) exceeded (~w) when:"
- "~n Count: ~p"
- "~n Max: ~p", [GbMaxVBs, GbNumVBs, Count, Max]),
- {tooBig, 0, []};
-do_get_rep(_Sz, _MibView, Max, Max, _, Res, _GbNumVBs, _GbMaxVBs) ->
- ?vt("do_get_rep -> done when: "
- "~n Res: ~p", [Res]),
- {noError, 0, conv_res(Res)};
-do_get_rep(Sz, MibView, Count, Max, Varbinds, Res, GbNumVBs, GbMaxVBs) ->
- ?vt("do_get_rep -> entry when: "
- "~n Sz: ~p"
- "~n Count: ~p"
- "~n Res: ~w", [Sz, Count, Res]),
- case try_get_bulk(Sz, MibView, Varbinds, GbMaxVBs) of
- {noError, NextVarbinds, SizeLeft, Res2} ->
- ?vt("do_get_rep -> noError: "
- "~n SizeLeft: ~p"
- "~n Res2: ~p", [SizeLeft, Res2]),
- do_get_rep(SizeLeft, MibView, Count+1, Max, NextVarbinds,
- Res2 ++ Res,
- GbNumVBs + length(Varbinds), GbMaxVBs);
- {endOfMibView, _NextVarbinds, _SizeLeft, Res2} ->
- ?vt("do_get_rep -> endOfMibView: "
- "~n Res2: ~p", [Res2]),
- {noError, 0, conv_res(Res2 ++ Res)};
- {ErrorStatus, Index} ->
- ?vtrace("do_get_rep -> done when error: "
- "~n ErrorStatus: ~p"
- "~n Index: ~p", [ErrorStatus, Index]),
- {ErrorStatus, Index, []}
- end.
-
-org_index_sort_vbs(Vbs) ->
- lists:keysort(#varbind.org_index, Vbs).
-
-try_get_bulk(Sz, MibView, Varbinds, GbMaxVBs) ->
- ?vt("try_get_bulk -> entry with"
- "~n Sz: ~w"
- "~n MibView: ~w"
- "~n Varbinds: ~w", [Sz, MibView, Varbinds]),
- case do_get_next(MibView, Varbinds, GbMaxVBs) of
- {noError, 0, UNextVarbinds} ->
- ?vt("try_get_bulk -> noError: "
- "~n UNextVarbinds: ~p", [UNextVarbinds]),
- NextVarbinds = org_index_sort_vbs(UNextVarbinds),
- case (catch enc_vbs(Sz, NextVarbinds)) of
- {error, Idx, Reason} ->
- user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]),
- ?vtrace("try_get_bulk -> encode error: "
- "~n Idx: ~p"
- "~n Reason: ~p", [Idx, Reason]),
- {genErr, Idx};
- {SizeLeft, Res} when is_integer(SizeLeft) andalso
- is_list(Res) ->
- ?vt("try get bulk -> encode ok: "
- "~n SizeLeft: ~w"
- "~n Res: ~w", [SizeLeft, Res]),
- {check_end_of_mibview(NextVarbinds),
- NextVarbinds, SizeLeft, Res};
- Res when is_list(Res) ->
- ?vt("try get bulk -> Res: "
- "~n ~w", [Res]),
- {endOfMibView, [], 0, Res}
- end;
- {ErrorStatus, Index, _} ->
- ?vt("try_get_bulk -> error: "
- "~n ErrorStatus: ~p"
- "~n Index: ~p", [ErrorStatus, Index]),
- {ErrorStatus, Index}
- end.
-
-%% If all variables in this pass are endOfMibView,
-%% there is no reason to continue.
-check_end_of_mibview([#varbind{value = endOfMibView} | T]) ->
- check_end_of_mibview(T);
-check_end_of_mibview([]) -> endOfMibView;
-check_end_of_mibview(_) -> noError.
%%%--------------------------------------------------
@@ -3834,14 +2857,11 @@ do_subagent_set(Arguments) ->
SetModule = get(set_module),
apply(SetModule, do_subagent_set, [Arguments]).
+
+
%%%-----------------------------------------------------------------
%%% 7. Misc functions
%%%-----------------------------------------------------------------
-sort_varbindlist(Varbinds) ->
- snmpa_svbl:sort_varbindlist(get(mibserver), Varbinds).
-
-sa_split(SubagentVarbinds) ->
- snmpa_svbl:sa_split(SubagentVarbinds).
make_response_pdu(ReqId, ErrStatus, ErrIndex, OrgVarbinds, _ResponseVarbinds)
when ErrIndex =/= 0 ->
@@ -4139,6 +3159,7 @@ report_err(Val, Mfa, Err) ->
user_err("Got ~p from ~w. Using ~w", [Val, Mfa, Err]),
{error, Err}.
+
is_valid_pdu_type('get-request') -> true;
is_valid_pdu_type('get-next-request') -> true;
is_valid_pdu_type('get-bulk-request') -> true;
@@ -4176,33 +3197,8 @@ mapfoldl(F, Eas, Accu0, [Hd|Tail]) ->
mapfoldl(_F, _Eas, Accu, []) -> {Accu,[]}.
-%%-----------------------------------------------------------------
-%% Runtime debugging of the agent.
-%%-----------------------------------------------------------------
-
-dbg_apply(M,F,A) ->
- case get(verbosity) of
- silence ->
- apply(M,F,A);
- _ ->
- ?vlog("~n apply: ~w,~w,~p~n", [M,F,A]),
- Res = (catch apply(M,F,A)),
- case Res of
- {'EXIT', Reason} ->
- ?vinfo("Call to: "
- "~n Module: ~p"
- "~n Function: ~p"
- "~n Args: ~p"
- "~n"
- "~nresulted in an exit"
- "~n"
- "~n ~p", [M, F, A, Reason]);
- _ ->
- ?vlog("~n returned: ~p", [Res])
- end,
- Res
- end.
+%% ---------------------------------------------------------------------
short_name(none) -> ma;
short_name(_Pid) -> sa.
@@ -4450,6 +3446,9 @@ get_mib_storage(Opts) ->
get_set_mechanism(Opts) ->
get_option(set_mechanism, Opts, snmpa_set).
+get_get_mechanism(Opts) ->
+ get_option(get_mechanism, Opts, snmpa_get).
+
get_authentication_service(Opts) ->
get_option(authentication_service, Opts, snmpa_acm).
diff --git a/lib/snmp/src/agent/snmpa_app.erl b/lib/snmp/src/agent/snmpa_app.erl
index 86ff145e93..c00929c334 100644
--- a/lib/snmp/src/agent/snmpa_app.erl
+++ b/lib/snmp/src/agent/snmpa_app.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -67,6 +67,7 @@ convert_config(Opts) ->
SaVerb = get_sub_agent_verbosity(Opts),
[{agent_type, AgentType},
{agent_verbosity, SaVerb},
+ {get_mechanism, snmpa_get},
{set_mechanism, SetModule},
{authentication_service, AuthModule},
{priority, Prio},
@@ -97,6 +98,7 @@ convert_config(Opts) ->
{verbosity, ConfVerb}],
[{agent_type, AgentType},
{agent_verbosity, MaVerb},
+ {get_mechanism, snmpa_get},
{set_mechanism, SetModule},
{authentication_service, AuthModule},
{db_dir, DbDir},
diff --git a/lib/snmp/src/agent/snmpa_get.erl b/lib/snmp/src/agent/snmpa_get.erl
new file mode 100644
index 0000000000..e67975a67d
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_get.erl
@@ -0,0 +1,1150 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(snmpa_get).
+
+-behaviour(snmpa_get_mechanism).
+
+
+%%%-----------------------------------------------------------------
+%%% snmpa_get_mechanism exports
+%%%-----------------------------------------------------------------
+
+-export([
+ do_get/3, do_get/4,
+ do_get_next/3,
+ do_get_bulk/7
+ ]).
+
+-define(VMODULE,"GET").
+-include("snmpa_internal.hrl").
+-include("snmp_types.hrl").
+-include("snmp_debug.hrl").
+-include("snmp_verbosity.hrl").
+
+-ifndef(default_verbosity).
+-define(default_verbosity,silence).
+-endif.
+
+-define(empty_pdu_size, 21).
+
+-ifdef(snmp_extended_verbosity).
+-define(vt(F,A), ?vtrace(F, A)).
+-else.
+-define(vt(_F, _A), ok).
+-endif.
+
+
+-define(AGENT, snmpa_agent).
+-define(LIB, snmpa_get_lib).
+
+
+
+%%%-----------------------------------------------------------------
+%%% 3. GET REQUEST
+%%% --------------
+%%% According to RFC1157, section 4.1.2 and RFC1905, section 4.2.1.
+%%% In rfc1157:4.1.2 it isn't specified if noSuchName should be
+%%% returned even if some other varbind generates a genErr.
+%%% In rfc1905:4.2.1 this is not a problem since exceptions are
+%%% used, and thus a genErr will be returned anyway.
+%%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Func: do_get/2
+%% Purpose: Handles all VBs in a request that is inside the
+%% mibview (local).
+%% Returns: {noError, 0, ListOfNewVarbinds} |
+%% {ErrorStatus, ErrorIndex, []}
+%%-----------------------------------------------------------------
+
+do_get(UnsortedVarbinds, IsNotification, _Extra) ->
+ {MyVarbinds, SubagentVarbinds} = ?LIB:agent_sort_vbs(UnsortedVarbinds),
+ case do_get_local(MyVarbinds, IsNotification) of
+ {noError, 0, NewMyVarbinds} ->
+ case do_get_subagents(SubagentVarbinds, IsNotification) of
+ {noError, 0, NewSubagentVarbinds} ->
+ {noError, 0, NewMyVarbinds ++ NewSubagentVarbinds};
+ {ErrorStatus, ErrorIndex, _} ->
+ {ErrorStatus, ErrorIndex, []}
+ end;
+ {ErrorStatus, ErrorIndex, _} ->
+ {ErrorStatus, ErrorIndex, []}
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Func: do_get/3
+%% Purpose: do_get handles "getRequests".
+%% Pre: incoming varbinds have type == 'NULL', value == unSpecified
+%% Returns: {noError, 0, ListOfNewVarbinds} |
+%% {ErrorStatus, ErrorIndex, []}
+%%-----------------------------------------------------------------
+
+do_get(MibView, UnsortedVarbinds, IsNotification, Extra) ->
+ ?vtrace("do_get -> entry with"
+ "~n MibView: ~p"
+ "~n UnsortedVarbinds: ~p"
+ "~n IsNotification: ~p",
+ [MibView, UnsortedVarbinds, IsNotification]),
+ %% This is me, the master, so go ahead
+ {OutSideView, InSideView} = ?LIB:split_vbs_view(UnsortedVarbinds, MibView),
+ {Error, Index, NewVbs} = do_get(InSideView, IsNotification, Extra),
+ {Error, Index, NewVbs ++ OutSideView}.
+
+
+
+%%-----------------------------------------------------------------
+%% Func: do_get_local/2,3
+%% Purpose: Loop the variablebindings list. We know that each varbind
+%% in that list belongs to us.
+%% Returns: {noError, 0, ListOfNewVarbinds} |
+%% {ErrorStatus, ErrorIndex, []}
+%%-----------------------------------------------------------------
+
+do_get_local(VBs, IsNotification) ->
+ do_get_local(VBs, [], IsNotification).
+
+do_get_local([Vb | Vbs], Res, IsNotification) ->
+ case try_get(Vb, IsNotification) of
+ NewVb when is_record(NewVb, varbind) ->
+ do_get_local(Vbs, [NewVb | Res], IsNotification);
+ ListOfNewVb when is_list(ListOfNewVb) ->
+ do_get_local(Vbs, lists:append(ListOfNewVb, Res), IsNotification);
+ {error, Error, OrgIndex} ->
+ {Error, OrgIndex, []}
+ end;
+do_get_local([], Res, _IsNotification) ->
+ {noError, 0, Res}.
+
+
+
+%%-----------------------------------------------------------------
+%% Func: do_get_subagents/2
+%% Purpose: Loop the list of varbinds for different subagents.
+%% For each of them, call sub_agent_get to retreive
+%% the values for them.
+%% Returns: {noError, 0, ListOfNewVarbinds} |
+%% {ErrorStatus, ErrorIndex, []}
+%%-----------------------------------------------------------------
+do_get_subagents(SubagentVarbinds, IsNotification) ->
+ do_get_subagents(SubagentVarbinds, [], IsNotification).
+do_get_subagents([{SubAgentPid, SAVbs} | Tail], Res, IsNotification) ->
+ {_SAOids, Vbs} = ?LIB:sa_split(SAVbs),
+ case catch ?AGENT:subagent_get(SubAgentPid, Vbs, IsNotification) of
+ {noError, 0, NewVbs} ->
+ do_get_subagents(Tail, lists:append(NewVbs, Res), IsNotification);
+ {ErrorStatus, ErrorIndex, _} ->
+ {ErrorStatus, ErrorIndex, []};
+ {'EXIT', Reason} ->
+ ?LIB:user_err("Lost contact with subagent (get) ~w. Using genErr",
+ [Reason]),
+ {genErr, 0, []}
+ end;
+do_get_subagents([], Res, _IsNotification) ->
+ {noError, 0, Res}.
+
+
+%%-----------------------------------------------------------------
+%% Func: try_get/2
+%% Returns: {error, ErrorStatus, OrgIndex} |
+%% #varbind |
+%% List of #varbind
+%%-----------------------------------------------------------------
+try_get(IVb, IsNotification) when is_record(IVb, ivarbind) ->
+ ?vtrace("try_get(ivarbind) -> entry with"
+ "~n IVb: ~p", [IVb]),
+ get_var_value_from_ivb(IVb, IsNotification);
+try_get({TableOid, TableVbs}, IsNotification) ->
+ ?vtrace("try_get(table) -> entry with"
+ "~n TableOid: ~p"
+ "~n TableVbs: ~p", [TableOid, TableVbs]),
+ [#ivarbind{mibentry = MibEntry}|_] = TableVbs,
+ {NoAccessVbs, AccessVbs} =
+ check_all_table_vbs(TableVbs, IsNotification, [], []),
+ case get_tab_value_from_mib(MibEntry, TableOid, AccessVbs) of
+ {error, ErrorStatus, OrgIndex} ->
+ {error, ErrorStatus, OrgIndex};
+ NVbs ->
+ NVbs ++ NoAccessVbs
+ end.
+
+%%-----------------------------------------------------------------
+%% Make sure all requested columns are accessible.
+%%-----------------------------------------------------------------
+check_all_table_vbs([IVb| IVbs], IsNotification, NoA, A) ->
+ #ivarbind{mibentry = Me, varbind = Vb} = IVb,
+ case Me#me.access of
+ 'not-accessible' ->
+ NNoA = [Vb#varbind{value = noSuchInstance} | NoA],
+ check_all_table_vbs(IVbs, IsNotification, NNoA, A);
+ 'accessible-for-notify' when IsNotification =:= false ->
+ NNoA = [Vb#varbind{value = noSuchInstance} | NoA],
+ check_all_table_vbs(IVbs, IsNotification, NNoA, A);
+ 'write-only' ->
+ NNoA = [Vb#varbind{value = noSuchInstance} | NoA],
+ check_all_table_vbs(IVbs, IsNotification, NNoA, A);
+ _ ->
+ check_all_table_vbs(IVbs, IsNotification, NoA, [IVb | A])
+ end;
+check_all_table_vbs([], _IsNotification, NoA, A) -> {NoA, A}.
+
+%%-----------------------------------------------------------------
+%% Returns: {error, ErrorStatus, OrgIndex} |
+%% #varbind
+%%-----------------------------------------------------------------
+get_var_value_from_ivb(IVb, IsNotification)
+ when IVb#ivarbind.status =:= noError ->
+ ?vtrace("get_var_value_from_ivb(noError) -> entry", []),
+ #ivarbind{mibentry = Me, varbind = Vb} = IVb,
+ #varbind{org_index = OrgIndex, oid = Oid} = Vb,
+ case Me#me.access of
+ 'not-accessible' ->
+ Vb#varbind{value = noSuchInstance};
+ 'accessible-for-notify' when IsNotification =:= false ->
+ Vb#varbind{value = noSuchInstance};
+ 'write-only' ->
+ Vb#varbind{value = noSuchInstance};
+ _ ->
+ case get_var_value_from_mib(Me, Oid) of
+ {value, Type, Value} ->
+ Vb#varbind{variabletype = Type, value = Value};
+ {error, ErrorStatus} ->
+ {error, ErrorStatus, OrgIndex}
+ end
+ end;
+get_var_value_from_ivb(#ivarbind{status = Status, varbind = Vb}, _) ->
+ ?vtrace("get_var_value_from_ivb(~p) -> entry", [Status]),
+ Vb#varbind{value = Status}.
+
+%%-----------------------------------------------------------------
+%% Func: get_var_value_from_mib/1
+%% Purpose:
+%% Returns: {error, ErrorStatus} |
+%% {value, Type, Value}
+%%-----------------------------------------------------------------
+%% Pre: Oid is a correct instance Oid (lookup checked that).
+%% Returns: A correct return value (see ?AGENT:make_value_a_correct_value)
+get_var_value_from_mib(#me{entrytype = variable,
+ asn1_type = ASN1Type,
+ mfa = {Mod, Func, Args}},
+ _Oid) ->
+ ?vtrace("get_var_value_from_mib(variable) -> entry when"
+ "~n Mod: ~p"
+ "~n Func: ~p"
+ "~n Args: ~p", [Mod, Func, Args]),
+ Result = (catch ?LIB:dbg_apply(Mod, Func, [get | Args])),
+ %% mib shall return {value, <a-nice-value-within-range>} |
+ %% {noValue, noSuchName} (v1) |
+ %% {noValue, noSuchObject | noSuchInstance} (v2, v1)
+ %% everything else (including 'genErr') will generate 'genErr'.
+ ?AGENT:make_value_a_correct_value(Result, ASN1Type, {Mod, Func, Args});
+
+get_var_value_from_mib(#me{entrytype = table_column,
+ oid = MeOid,
+ asn1_type = ASN1Type,
+ mfa = {Mod, Func, Args}},
+ Oid) ->
+ ?vtrace("get_var_value_from_mib(table_column) -> entry when"
+ "~n MeOid: ~p"
+ "~n Mod: ~p"
+ "~n Func: ~p"
+ "~n Args: ~p"
+ "~n Oid: ~p", [MeOid, Mod, Func, Args, Oid]),
+ Col = lists:last(MeOid),
+ Indexes = snmp_misc:diff(Oid, MeOid),
+ [Result] = (catch ?LIB:dbg_apply(Mod, Func, [get, Indexes, [Col] | Args])),
+ ?AGENT:make_value_a_correct_value(Result, ASN1Type,
+ {Mod, Func, Args, Indexes, Col}).
+
+
+%% For table operations we need to pass RestOid down to the table-function.
+%% Its up to the table-function to check for noSuchInstance (ex: a
+%% non-existing row).
+%% Returns: {error, ErrorStatus, OrgIndex} |
+%% {value, Type, Value}
+get_tab_value_from_mib(#me{mfa = {Mod, Func, Args}}, TableOid, TableVbs) ->
+ ?vtrace("get_tab_value_from_mib -> entry when"
+ "~n Mod: ~p"
+ "~n Func: ~p"
+ "~n Args: ~p", [Mod, Func, Args]),
+ TableOpsWithShortOids = ?LIB:delete_prefixes(TableOid, TableVbs),
+ SortedVBsRows = snmpa_svbl:sort_varbinds_rows(TableOpsWithShortOids),
+ case get_value_all_rows(SortedVBsRows, Mod, Func, Args, []) of
+ {Error, Index} ->
+ #ivarbind{varbind = Vb} = lists:nth(Index, TableVbs),
+ {error, Error, Vb#varbind.org_index};
+ ListOfValues ->
+ merge_varbinds_and_value(TableVbs, ListOfValues)
+ end.
+
+%%-----------------------------------------------------------------
+%% Values is a scrambled list of {CorrectValue, Index}, where Index
+%% is index into the #ivarbind list. So for each Value, we must
+%% find the corresponding #ivarbind, and merge them into a new
+%% #varbind.
+%% The Values list comes from validate_tab_res.
+%%-----------------------------------------------------------------
+merge_varbinds_and_value(IVbs, [{{value, Type, Value}, Index} | Values]) ->
+ #ivarbind{varbind = Vb} = lists:nth(Index, IVbs),
+ [Vb#varbind{variabletype = Type, value = Value} |
+ merge_varbinds_and_value(IVbs, Values)];
+merge_varbinds_and_value(_, []) -> [].
+
+get_value_all_rows([{[], OrgCols} | Rows], Mod, Func, Args, Res) ->
+ ?vtrace("get_value_all_rows -> entry when"
+ "~n OrgCols: ~p", [OrgCols]),
+ Cols = [{{value, noValue, noSuchInstance}, Index} ||
+ {_Col, _ASN1Type, Index} <- OrgCols],
+ NewRes = lists:append(Cols, Res),
+ get_value_all_rows(Rows, Mod, Func, Args, NewRes);
+get_value_all_rows([{RowIndex, OrgCols} | Rows], Mod, Func, Args, Res) ->
+ ?vtrace("get_value_all_rows -> entry when"
+ "~n RowIndex: ~p"
+ "~n OrgCols: ~p", [RowIndex, OrgCols]),
+ {DOrgCols, Dup} = remove_duplicates(OrgCols),
+ Cols = delete_index(DOrgCols),
+ Result = (catch ?LIB:dbg_apply(Mod, Func, [get, RowIndex, Cols | Args])),
+ case validate_tab_res(Result, DOrgCols, {Mod, Func, Args}) of
+ Values when is_list(Values) ->
+ NVals = restore_duplicates(Dup, Values),
+ NewRes = lists:append(NVals, Res),
+ get_value_all_rows(Rows, Mod, Func, Args, NewRes);
+ {error, ErrorStatus, Index} ->
+ ?AGENT:validate_err(row_set, {ErrorStatus, Index}, {Mod, Func, Args})
+ end;
+get_value_all_rows([], _Mod, _Func, _Args, Res) ->
+ ?vtrace("get_value_all_rows -> entry when done"
+ "~n Res: ~p", [Res]),
+ Res.
+
+%%-----------------------------------------------------------------
+%% Args: {RowIndex, list of {ShortOid, ASN1Type}}
+%% Returns: list of Col
+%%-----------------------------------------------------------------
+delete_index([{Col, _Val, _OrgIndex} | T]) ->
+ [Col | delete_index(T)];
+delete_index([]) -> [].
+
+%%-----------------------------------------------------------------
+%% This function is called before 'get' on a table, and removes
+%% any duplicate columns. It returns {Cols, DupInfo}. The Cols
+%% are the unique columns. The instrumentation function is
+%% called to get the values. These values, together with the
+%% DupInfo, is later passed to restore_duplicates, which uses
+%% the retrieved values to reconstruct the original column list,
+%% but with the retrieved value for each column.
+%%-----------------------------------------------------------------
+remove_duplicates(Cols) ->
+ remove_duplicates(Cols, [], []).
+
+
+remove_duplicates([{Col, V1, OrgIdx1}, {Col, V2, OrgIdx2} | T], NCols, Dup) ->
+ remove_duplicates([{Col, V1, OrgIdx1} | T], NCols,
+ [{Col, V2, OrgIdx2} | Dup]);
+remove_duplicates([Col | T], NCols, Dup) ->
+ remove_duplicates(T, [Col | NCols], Dup);
+remove_duplicates([], NCols, Dup) ->
+ {lists:reverse(NCols), lists:reverse(Dup)}.
+
+restore_duplicates([], Cols) ->
+ [{Val, OrgIndex} || {_Col, Val, OrgIndex} <- Cols];
+restore_duplicates([{Col, _Val2, OrgIndex2} | Dup],
+ [{Col, NVal, OrgIndex1} | Cols]) ->
+ [{NVal, OrgIndex2} |
+ restore_duplicates(Dup, [{Col, NVal, OrgIndex1} | Cols])];
+restore_duplicates(Dup, [{_Col, Val, OrgIndex} | T]) ->
+ [{Val, OrgIndex} | restore_duplicates(Dup, T)].
+
+
+
+%%-----------------------------------------------------------------
+%% Three cases:
+%% 1) All values ok
+%% 2) table_func returned {Error, ...}
+%% 3) Some value in Values list is erroneous.
+%% Args: Value is a list of values from table_func(get..)
+%% OrgCols is a list with {Col, ASN1Type, OrgIndex}
+%% each element in Values and OrgCols correspond to each
+%% other.
+%%-----------------------------------------------------------------
+validate_tab_res(Values, OrgCols, Mfa) when is_list(Values) ->
+ {_Col, _ASN1Type, OneIdx} = hd(OrgCols),
+ validate_tab_res(Values, OrgCols, Mfa, [], OneIdx);
+validate_tab_res({noValue, Error}, OrgCols, Mfa) ->
+ Values = lists:duplicate(length(OrgCols), {noValue, Error}),
+ validate_tab_res(Values, OrgCols, Mfa);
+validate_tab_res({genErr, Col}, OrgCols, Mfa) ->
+ case lists:keysearch(Col, 1, OrgCols) of
+ {value, {_Col, _ASN1Type, Index}} ->
+ {error, genErr, Index};
+ _ ->
+ ?LIB:user_err("Invalid column in {genErr, ~w} from ~w (get)",
+ [Col, Mfa]),
+ [{_Col, _ASN1Type, Index} | _] = OrgCols,
+ {error, genErr, Index}
+ end;
+validate_tab_res(genErr, [{_Col, __ASN1Type, Index} | _OrgCols], _Mfa) ->
+ {error, genErr, Index};
+validate_tab_res(Error, [{_Col, _ASN1Type, Index} | _OrgCols], Mfa) ->
+ ?LIB:user_err("Invalid return value ~w from ~w (get)",[Error, Mfa]),
+ {error, genErr, Index}.
+
+validate_tab_res([Value | Values],
+ [{Col, ASN1Type, Index} | OrgCols],
+ Mfa, Res, I) ->
+ %% This one makes it possible to return a list of genErr, which
+ %% is not allowed according to the manual. But that's ok, as
+ %% everything else will generate a genErr! (the only problem is
+ %% that it won't generate a user_error).
+ case ?AGENT:make_value_a_correct_value(Value, ASN1Type, Mfa) of
+ {error, ErrorStatus} ->
+ {error, ErrorStatus, Index};
+ CorrectValue ->
+ NewRes = [{Col, CorrectValue, Index} | Res],
+ validate_tab_res(Values, OrgCols, Mfa, NewRes, I)
+ end;
+validate_tab_res([], [], _Mfa, Res, _I) ->
+ lists:reverse(Res);
+validate_tab_res([], [{_Col, _ASN1Type, Index}|_], Mfa, _Res, _I) ->
+ ?LIB:user_err("Too few values returned from ~w (get)", [Mfa]),
+ {error, genErr, Index};
+validate_tab_res(_TooMany, [], Mfa, _Res, I) ->
+ ?LIB:user_err("Too many values returned from ~w (get)", [Mfa]),
+ {error, genErr, I}.
+
+
+
+%%%-----------------------------------------------------------------
+%%% 4. GET-NEXT REQUEST
+%%% --------------
+%%% According to RFC1157, section 4.1.3 and RFC1905, section 4.2.2.
+%%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: do_get_next/3
+%% Purpose: do_get_next handles "getNextRequests".
+%% Note: Even if it is SNMPv1, a varbind's value can be
+%% endOfMibView. This is converted to noSuchName in process_pdu.
+%% Returns: {noError, 0, ListOfNewVarbinds} |
+%% {ErrorStatus, ErrorIndex, []}
+%% Note2: ListOfNewVarbinds is not sorted in any order!!!
+%% Alg: First, the variables are sorted in OID order.
+%%
+%% Second, next in the MIB is performed for each OID, and
+%% the result is collected as: if next oid is a variable,
+%% perform a get to retrieve its value; if next oid is in a
+%% table, save this value and continue until we get an oid
+%% outside this table. Then perform get_next on the table,
+%% and continue with all endOfTables and the oid outside the
+%% table; if next oid is an subagent, save this value and
+%% continue as in the table case.
+%%
+%% Third, each response is checked for endOfMibView, or (for
+%% subagents) that the Oid returned has the correct prefix.
+%% (This is necessary since an SA can be registered under many
+%% separated subtrees, and if the last variable in the first
+%% subtree is requested in a next, the SA will return the first
+%% variable in the second subtree. This might be working, since
+%% there may be a variable in between these subtrees.) For each
+%% of these, a new get-next is performed, one at a time.
+%% This alg. might be optimised in several ways. The most
+%% striking one is that the same SA might be called several
+%% times, when one time should be enough. But it isn't clear
+%% that this really matters, since many nexts across the same
+%% subagent must be considered to be very rare.
+%%-----------------------------------------------------------------
+
+do_get_next(MibView, UnsortedVBs, _Extra) ->
+ do_get_next2(MibView, UnsortedVBs, infinity).
+
+%% The third argument is only used if we are called as result
+%% of a get-bulk request.
+do_get_next2(_MibView, UnsortedVarbinds, GbMaxVBs)
+ when (is_integer(GbMaxVBs) andalso (length(UnsortedVarbinds) > GbMaxVBs)) ->
+ {tooBig, 0, []}; % What is the correct index in this case?
+do_get_next2(MibView, UnsortedVBs, GbMaxVBs) ->
+ ?vt("do_get_next2 -> entry when"
+ "~n MibView: ~p"
+ "~n UnsortedVBs: ~p", [MibView, UnsortedVBs]),
+ SortedVBs = ?LIB:oid_sort_vbs(UnsortedVBs),
+ ?vt("do_get_next -> "
+ "~n SortedVBs: ~p", [SortedVBs]),
+ next_loop_varbinds([], SortedVBs, MibView, [], [], GbMaxVBs).
+
+next_loop_varbinds(_, Vbs, _MibView, Res, _LAVb, GbMaxVBs)
+ when (is_integer(GbMaxVBs) andalso
+ ((length(Vbs) + length(Res)) > GbMaxVBs)) ->
+ {tooBig, 0, []}; % What is the correct index in this case?
+
+%% LAVb is Last Accessible Vb
+next_loop_varbinds([], [Vb | Vbs], MibView, Res, LAVb, GbMaxVBs) ->
+ ?vt("next_loop_varbinds -> entry when"
+ "~n Vb: ~p"
+ "~n MibView: ~p", [Vb, MibView]),
+ case varbind_next(Vb, MibView) of
+ endOfMibView ->
+ ?vt("next_loop_varbind -> endOfMibView", []),
+ RVb = if LAVb =:= [] -> Vb;
+ true -> LAVb
+ end,
+ NewVb = RVb#varbind{variabletype = 'NULL', value = endOfMibView},
+ next_loop_varbinds([], Vbs, MibView, [NewVb | Res], [], GbMaxVBs);
+
+ {variable, ME, VarOid} when ((ME#me.access =/= 'not-accessible') andalso
+ (ME#me.access =/= 'write-only') andalso
+ (ME#me.access =/= 'accessible-for-notify')) ->
+ ?vt("next_loop_varbind -> variable: "
+ "~n ME: ~p"
+ "~n VarOid: ~p", [ME, VarOid]),
+ case try_get_instance(Vb, ME) of
+ {value, noValue, _NoSuchSomething} ->
+ ?vt("next_loop_varbind -> noValue", []),
+ %% Try next one
+ NewVb = Vb#varbind{oid = VarOid,
+ value = 'NULL'},
+ next_loop_varbinds([], [NewVb | Vbs], MibView, Res, [],
+ GbMaxVBs);
+ {value, Type, Value} ->
+ ?vt("next_loop_varbind -> value"
+ "~n Type: ~p"
+ "~n Value: ~p", [Type, Value]),
+ NewVb = Vb#varbind{oid = VarOid,
+ variabletype = Type,
+ value = Value},
+ next_loop_varbinds([], Vbs, MibView, [NewVb | Res], [],
+ GbMaxVBs);
+ {error, ErrorStatus} ->
+ ?vdebug("next loop varbinds:"
+ "~n ErrorStatus: ~p",[ErrorStatus]),
+ {ErrorStatus, Vb#varbind.org_index, []}
+ end;
+ {variable, _ME, VarOid} ->
+ ?vt("next_loop_varbind -> variable: "
+ "~n VarOid: ~p", [VarOid]),
+ RVb = if LAVb =:= [] -> Vb;
+ true -> LAVb
+ end,
+ NewVb = Vb#varbind{oid = VarOid, value = 'NULL'},
+ next_loop_varbinds([], [NewVb | Vbs], MibView, Res, RVb, GbMaxVBs);
+ {table, TableOid, TableRestOid, ME} ->
+ ?vt("next_loop_varbind -> table: "
+ "~n TableOid: ~p"
+ "~n TableRestOid: ~p"
+ "~n ME: ~p", [TableOid, TableRestOid, ME]),
+ next_loop_varbinds({table, TableOid, ME,
+ [{tab_oid(TableRestOid), Vb}]},
+ Vbs, MibView, Res, [], GbMaxVBs);
+ {subagent, SubAgentPid, SAOid} ->
+ ?vt("next_loop_varbind -> subagent: "
+ "~n SubAgentPid: ~p"
+ "~n SAOid: ~p", [SubAgentPid, SAOid]),
+ NewVb = Vb#varbind{variabletype = 'NULL', value = 'NULL'},
+ next_loop_varbinds({subagent, SubAgentPid, SAOid, [NewVb]},
+ Vbs, MibView, Res, [], GbMaxVBs)
+ end;
+next_loop_varbinds({table, TableOid, ME, TabOids},
+ [Vb | Vbs], MibView, Res, _LAVb, GbMaxVBs) ->
+ ?vt("next_loop_varbinds(table) -> entry with"
+ "~n TableOid: ~p"
+ "~n Vb: ~p", [TableOid, Vb]),
+ case varbind_next(Vb, MibView) of
+ {table, TableOid, TableRestOid, _ME} ->
+ next_loop_varbinds({table, TableOid, ME,
+ [{tab_oid(TableRestOid), Vb} | TabOids]},
+ Vbs, MibView, Res, [], GbMaxVBs);
+ _ ->
+ case get_next_table(ME, TableOid, TabOids, MibView) of
+ {ok, TabRes, TabEndOfTabVbs} ->
+ NewVbs = lists:append(TabEndOfTabVbs, [Vb | Vbs]),
+ NewRes = lists:append(TabRes, Res),
+ next_loop_varbinds([], NewVbs, MibView, NewRes, [],
+ GbMaxVBs);
+ {ErrorStatus, OrgIndex} ->
+ ?vdebug("next loop varbinds: next varbind"
+ "~n ErrorStatus: ~p"
+ "~n OrgIndex: ~p",
+ [ErrorStatus,OrgIndex]),
+ {ErrorStatus, OrgIndex, []}
+ end
+ end;
+next_loop_varbinds({table, TableOid, ME, TabOids},
+ [], MibView, Res, _LAVb, GbMaxVBs) ->
+ ?vt("next_loop_varbinds(table) -> entry with"
+ "~n TableOid: ~p", [TableOid]),
+ case get_next_table(ME, TableOid, TabOids, MibView) of
+ {ok, TabRes, TabEndOfTabVbs} ->
+ ?vt("next_loop_varbinds(table) -> get_next_table result:"
+ "~n TabRes: ~p"
+ "~n TabEndOfTabVbs: ~p", [TabRes, TabEndOfTabVbs]),
+ NewRes = lists:append(TabRes, Res),
+ next_loop_varbinds([], TabEndOfTabVbs, MibView, NewRes, [],
+ GbMaxVBs);
+ {ErrorStatus, OrgIndex} ->
+ ?vdebug("next loop varbinds: next table"
+ "~n ErrorStatus: ~p"
+ "~n OrgIndex: ~p",
+ [ErrorStatus,OrgIndex]),
+ {ErrorStatus, OrgIndex, []}
+ end;
+next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
+ [Vb | Vbs], MibView, Res, _LAVb, GbMaxVBs) ->
+ ?vt("next_loop_varbinds(subagent) -> entry with"
+ "~n SAPid: ~p"
+ "~n SAOid: ~p"
+ "~n Vb: ~p", [SAPid, SAOid, Vb]),
+ case varbind_next(Vb, MibView) of
+ {subagent, _SubAgentPid, SAOid} ->
+ next_loop_varbinds({subagent, SAPid, SAOid,
+ [Vb | SAVbs]},
+ Vbs, MibView, Res, [], GbMaxVBs);
+ _ ->
+ case get_next_sa(SAPid, SAOid, SAVbs, MibView) of
+ {ok, SARes, SAEndOfMibViewVbs} ->
+ NewVbs = lists:append(SAEndOfMibViewVbs, [Vb | Vbs]),
+ NewRes = lists:append(SARes, Res),
+ next_loop_varbinds([], NewVbs, MibView, NewRes, [],
+ GbMaxVBs);
+ {noSuchName, OrgIndex} ->
+ %% v1 reply, treat this Vb as endOfMibView, and try again
+ %% for the others.
+ case lists:keysearch(OrgIndex, #varbind.org_index, SAVbs) of
+ {value, EVb} ->
+ NextOid = next_oid(SAOid),
+ EndOfVb =
+ EVb#varbind{oid = NextOid,
+ value = {endOfMibView, NextOid}},
+ case lists:delete(EVb, SAVbs) of
+ [] ->
+ next_loop_varbinds([], [EndOfVb, Vb | Vbs],
+ MibView, Res, [],
+ GbMaxVBs);
+ TryAgainVbs ->
+ next_loop_varbinds({subagent, SAPid, SAOid,
+ TryAgainVbs},
+ [EndOfVb, Vb | Vbs],
+ MibView, Res, [],
+ GbMaxVBs)
+ end;
+ false ->
+ %% bad index from subagent
+ {genErr, (hd(SAVbs))#varbind.org_index, []}
+ end;
+ {ErrorStatus, OrgIndex} ->
+ ?vdebug("next loop varbinds: next subagent"
+ "~n Vb: ~p"
+ "~n ErrorStatus: ~p"
+ "~n OrgIndex: ~p",
+ [Vb,ErrorStatus,OrgIndex]),
+ {ErrorStatus, OrgIndex, []}
+ end
+ end;
+next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
+ [], MibView, Res, _LAVb, GbMaxVBs) ->
+ ?vt("next_loop_varbinds(subagent) -> entry with"
+ "~n SAPid: ~p"
+ "~n SAOid: ~p", [SAPid, SAOid]),
+ case get_next_sa(SAPid, SAOid, SAVbs, MibView) of
+ {ok, SARes, SAEndOfMibViewVbs} ->
+ NewRes = lists:append(SARes, Res),
+ next_loop_varbinds([], SAEndOfMibViewVbs, MibView, NewRes, [],
+ GbMaxVBs);
+ {noSuchName, OrgIndex} ->
+ %% v1 reply, treat this Vb as endOfMibView, and try again for
+ %% the others.
+ case lists:keysearch(OrgIndex, #varbind.org_index, SAVbs) of
+ {value, EVb} ->
+ NextOid = next_oid(SAOid),
+ EndOfVb = EVb#varbind{oid = NextOid,
+ value = {endOfMibView, NextOid}},
+ case lists:delete(EVb, SAVbs) of
+ [] ->
+ next_loop_varbinds([], [EndOfVb], MibView, Res, [],
+ GbMaxVBs);
+ TryAgainVbs ->
+ next_loop_varbinds({subagent, SAPid, SAOid,
+ TryAgainVbs},
+ [EndOfVb], MibView, Res, [],
+ GbMaxVBs)
+ end;
+ false ->
+ %% bad index from subagent
+ {genErr, (hd(SAVbs))#varbind.org_index, []}
+ end;
+ {ErrorStatus, OrgIndex} ->
+ ?vdebug("next loop varbinds: next subagent"
+ "~n ErrorStatus: ~p"
+ "~n OrgIndex: ~p",
+ [ErrorStatus,OrgIndex]),
+ {ErrorStatus, OrgIndex, []}
+ end;
+next_loop_varbinds([], [], _MibView, Res, _LAVb, _GbMaxVBs) ->
+ ?vt("next_loop_varbinds -> entry when done", []),
+ {noError, 0, Res}.
+
+try_get_instance(_Vb, #me{mfa = {M, F, A}, asn1_type = ASN1Type}) ->
+ ?vtrace("try_get_instance -> entry with"
+ "~n M: ~p"
+ "~n F: ~p"
+ "~n A: ~p", [M,F,A]),
+ Result = (catch ?LIB:dbg_apply(M, F, [get | A])),
+ % mib shall return {value, <a-nice-value-within-range>} |
+ % {noValue, noSuchName} (v1) |
+ % {noValue, noSuchObject | noSuchInstance} (v2, v1)
+ % everything else (including 'genErr') will generate 'genErr'.
+ ?AGENT:make_value_a_correct_value(Result, ASN1Type, {M, F, A}).
+
+tab_oid([]) -> [0];
+tab_oid(X) -> X.
+
+
+%%-----------------------------------------------------------------
+%% Perform a next, using the varbinds Oid if value is simple
+%% value. If value is {endOf<something>, NextOid}, use NextOid.
+%% This case happens when a table has returned endOfTable, or
+%% a subagent has returned endOfMibView.
+%%-----------------------------------------------------------------
+varbind_next(#varbind{value = Value, oid = Oid}, MibView) ->
+ ?vt("varbind_next -> entry with"
+ "~n Value: ~p"
+ "~n Oid: ~p"
+ "~n MibView: ~p", [Value, Oid, MibView]),
+ case Value of
+ {endOfTable, NextOid} ->
+ snmpa_mib:next(get(mibserver), NextOid, MibView);
+ {endOfMibView, NextOid} ->
+ snmpa_mib:next(get(mibserver), NextOid, MibView);
+ _ ->
+ snmpa_mib:next(get(mibserver), Oid, MibView)
+ end.
+
+get_next_table(#me{mfa = {M, F, A}}, TableOid, TableOids, MibView) ->
+ % We know that all TableOids have at least a column number as oid
+ ?vt("get_next_table -> entry with"
+ "~n M: ~p"
+ "~n F: ~p"
+ "~n A: ~p"
+ "~n TableOid: ~p"
+ "~n TableOids: ~p"
+ "~n MibView: ~p", [M, F, A, TableOid, TableOids, MibView]),
+ Sorted = snmpa_svbl:sort_varbinds_rows(TableOids),
+ case get_next_values_all_rows(Sorted, M,F,A, [], TableOid) of
+ NewVbs when is_list(NewVbs) ->
+ ?vt("get_next_table -> "
+ "~n NewVbs: ~p", [NewVbs]),
+ % We must now check each Vb for endOfTable and that it is
+ % in the MibView. If not, it becomes a endOfTable. We
+ % collect all of these together.
+ transform_tab_next_result(NewVbs, {[], []}, MibView);
+ {ErrorStatus, OrgIndex} ->
+ {ErrorStatus, OrgIndex}
+ end.
+
+get_next_values_all_rows([Row | Rows], M, F, A, Res, TabOid) ->
+ {RowIndex, TableOids} = Row,
+ Cols = delete_index(TableOids),
+ ?vt("get_next_values_all_rows -> "
+ "~n Cols: ~p", [Cols]),
+ Result = (catch ?LIB:dbg_apply(M, F, [get_next, RowIndex, Cols | A])),
+ ?vt("get_next_values_all_rows -> "
+ "~n Result: ~p", [Result]),
+ case validate_tab_next_res(Result, TableOids, {M, F, A}, TabOid) of
+ Values when is_list(Values) ->
+ ?vt("get_next_values_all_rows -> "
+ "~n Values: ~p", [Values]),
+ NewRes = lists:append(Values, Res),
+ get_next_values_all_rows(Rows, M, F, A, NewRes, TabOid);
+ {ErrorStatus, OrgIndex} ->
+ {ErrorStatus, OrgIndex}
+ end;
+get_next_values_all_rows([], _M, _F, _A, Res, _TabOid) ->
+ Res.
+
+transform_tab_next_result([Vb | Vbs], {Res, EndOfs}, MibView) ->
+ case Vb#varbind.value of
+ {endOfTable, _} ->
+ {ResVBs, EndOfVBs} = ?LIB:split_vbs(Vbs, Res, [Vb | EndOfs]),
+ {ok, ResVBs, EndOfVBs};
+ _ ->
+ case snmpa_acm:validate_mib_view(Vb#varbind.oid, MibView) of
+ true ->
+ transform_tab_next_result(Vbs, {[Vb|Res], EndOfs},MibView);
+ _ ->
+ Oid = Vb#varbind.oid,
+ NewEndOf = Vb#varbind{value = {endOfTable, Oid}},
+ transform_tab_next_result(Vbs, {Res, [NewEndOf | EndOfs]},
+ MibView)
+ end
+ end;
+transform_tab_next_result([], {Res, EndOfs}, _MibView) ->
+ ?vt("transform_tab_next_result -> entry with: "
+ "~n Res: ~p"
+ "~n EndIfs: ~p",[Res, EndOfs]),
+ {ok, Res, EndOfs}.
+
+
+
+%%-----------------------------------------------------------------
+%% Three cases:
+%% 1) All values ok
+%% 2) table_func returned {Error, ...}
+%% 3) Some value in Values list is erroneous.
+%% Args: Value is a list of values from table_func(get_next, ...)
+%% TableOids is a list of {TabRestOid, OrgVb}
+%% each element in Values and TableOids correspond to each
+%% other.
+%% Returns: List of NewVarbinds |
+%% {ErrorStatus, OrgIndex}
+%% (In the NewVarbinds list, the value may be endOfTable)
+%%-----------------------------------------------------------------
+validate_tab_next_res(Values, TableOids, Mfa, TabOid) ->
+ ?vt("validate_tab_next_res -> entry with: "
+ "~n Values: ~p"
+ "~n TableOids: ~p"
+ "~n Mfa: ~p"
+ "~n TabOid: ~p", [Values, TableOids, Mfa, TabOid]),
+ {_Col, _ASN1Type, OneIdx} = hd(TableOids),
+ validate_tab_next_res(Values, TableOids, Mfa, [], TabOid,
+ next_oid(TabOid), OneIdx).
+validate_tab_next_res([{NextOid, Value} | Values],
+ [{_ColNo, OrgVb, _Index} | TableOids],
+ Mfa, Res, TabOid, TabNextOid, I) ->
+ ?vt("validate_tab_next_res -> entry with: "
+ "~n NextOid: ~p"
+ "~n Value: ~p"
+ "~n Values: ~p"
+ "~n TableOids: ~p"
+ "~n Mfa: ~p"
+ "~n TabOid: ~p",
+ [NextOid, Value, Values, TableOids, Mfa, TabOid]),
+ #varbind{org_index = OrgIndex} = OrgVb,
+ ?vt("validate_tab_next_res -> OrgIndex: ~p", [OrgIndex]),
+ NextCompleteOid = lists:append(TabOid, NextOid),
+ case snmpa_mib:lookup(get(mibserver), NextCompleteOid) of
+ {table_column, #me{asn1_type = ASN1Type}, _TableEntryOid} ->
+ ?vt("validate_tab_next_res -> ASN1Type: ~p", [ASN1Type]),
+ case ?AGENT:make_value_a_correct_value({value, Value}, ASN1Type, Mfa) of
+ {error, ErrorStatus} ->
+ ?vt("validate_tab_next_res -> "
+ "~n ErrorStatus: ~p", [ErrorStatus]),
+ {ErrorStatus, OrgIndex};
+ {value, Type, NValue} ->
+ ?vt("validate_tab_next_res -> "
+ "~n Type: ~p"
+ "~n NValue: ~p", [Type, NValue]),
+ NewVb = OrgVb#varbind{oid = NextCompleteOid,
+ variabletype = Type, value = NValue},
+ validate_tab_next_res(Values, TableOids, Mfa,
+ [NewVb | Res], TabOid, TabNextOid, I)
+ end;
+ Error ->
+ ?LIB:user_err("Invalid oid ~w from ~w (get_next). Using genErr => ~p",
+ [NextOid, Mfa, Error]),
+ {genErr, OrgIndex}
+ end;
+validate_tab_next_res([endOfTable | Values],
+ [{_ColNo, OrgVb, _Index} | TableOids],
+ Mfa, Res, TabOid, TabNextOid, I) ->
+ ?vt("validate_tab_next_res(endOfTable) -> entry with: "
+ "~n Values: ~p"
+ "~n OrgVb: ~p"
+ "~n TableOids: ~p"
+ "~n Mfa: ~p"
+ "~n Res: ~p"
+ "~n TabOid: ~p"
+ "~n TabNextOid: ~p"
+ "~n I: ~p",
+ [Values, OrgVb, TableOids, Mfa, Res, TabOid, TabNextOid, I]),
+ NewVb = OrgVb#varbind{value = {endOfTable, TabNextOid}},
+ validate_tab_next_res(Values, TableOids, Mfa, [NewVb | Res],
+ TabOid, TabNextOid, I);
+validate_tab_next_res([], [], _Mfa, Res, _TabOid, _TabNextOid, _I) ->
+ Res;
+validate_tab_next_res([], [{_Col, _OrgVb, Index}|_], Mfa, _Res, _, _, _I) ->
+ ?LIB:user_err("Too few values returned from ~w (get_next)", [Mfa]),
+ {genErr, Index};
+validate_tab_next_res({genErr, ColNumber}, OrgCols,
+ Mfa, _Res, _TabOid, _TabNextOid, _I) ->
+ OrgIndex = snmpa_svbl:col_to_orgindex(ColNumber, OrgCols),
+ ?AGENT:validate_err(table_next, {genErr, OrgIndex}, Mfa);
+validate_tab_next_res({error, Reason}, [{_ColNo, OrgVb, _Index} | _TableOids],
+ Mfa, _Res, _TabOid, _TabNextOid, _I) ->
+ #varbind{org_index = OrgIndex} = OrgVb,
+ ?LIB:user_err("Erroneous return value ~w from ~w (get_next)",
+ [Reason, Mfa]),
+ {genErr, OrgIndex};
+validate_tab_next_res(Error, [{_ColNo, OrgVb, _Index} | _TableOids],
+ Mfa, _Res, _TabOid, _TabNextOid, _I) ->
+ #varbind{org_index = OrgIndex} = OrgVb,
+ ?LIB:user_err("Invalid return value ~w from ~w (get_next)",
+ [Error, Mfa]),
+ {genErr, OrgIndex};
+validate_tab_next_res(TooMany, [], Mfa, _Res, _, _, I) ->
+ ?LIB:user_err("Too many values ~w returned from ~w (get_next)",
+ [TooMany, Mfa]),
+ {genErr, I}.
+
+%%-----------------------------------------------------------------
+%% Func: get_next_sa/4
+%% Purpose: Loop the list of varbinds for the subagent.
+%% Call subagent_get_next to retreive
+%% the next varbinds.
+%% Returns: {ok, ListOfNewVbs, ListOfEndOfMibViewsVbs} |
+%% {ErrorStatus, ErrorIndex}
+%%-----------------------------------------------------------------
+get_next_sa(SAPid, SAOid, SAVbs, MibView) ->
+ case catch ?AGENT:subagent_get_next(SAPid, MibView, SAVbs) of
+ {noError, 0, NewVbs} ->
+ NewerVbs = transform_sa_next_result(NewVbs,SAOid,next_oid(SAOid)),
+ {ResVBs, EndOfVBs} = ?LIB:split_vbs(NewerVbs),
+ {ok, ResVBs, EndOfVBs};
+ {ErrorStatus, ErrorIndex, _} ->
+ {ErrorStatus, ErrorIndex};
+ {'EXIT', Reason} ->
+ ?LIB:user_err("Lost contact with subagent (next) ~w. Using genErr",
+ [Reason]),
+ {genErr, 0}
+ end.
+
+%%-----------------------------------------------------------------
+%% Check for wrong prefix returned or endOfMibView, and convert
+%% into {endOfMibView, SANextOid}.
+%%-----------------------------------------------------------------
+transform_sa_next_result([Vb | Vbs], SAOid, SANextOid)
+ when Vb#varbind.value =:= endOfMibView ->
+ [Vb#varbind{value = {endOfMibView, SANextOid}} |
+ transform_sa_next_result(Vbs, SAOid, SANextOid)];
+transform_sa_next_result([Vb | Vbs], SAOid, SANextOid) ->
+ case lists:prefix(SAOid, Vb#varbind.oid) of
+ true ->
+ [Vb | transform_sa_next_result(Vbs, SAOid, SANextOid)];
+ _ ->
+ [Vb#varbind{oid = SANextOid, value = {endOfMibView, SANextOid}} |
+ transform_sa_next_result(Vbs, SAOid, SANextOid)]
+ end;
+transform_sa_next_result([], _SAOid, _SANextOid) ->
+ [].
+
+
+next_oid(Oid) ->
+ case lists:reverse(Oid) of
+ [H | T] -> lists:reverse([H+1 | T]);
+ [] -> []
+ end.
+
+
+
+%%%-----------------------------------------------------------------
+%%% 5. GET-BULK REQUEST
+%%%
+%%% In order to prevent excesses in reply sizes there are two
+%%% preventive methods in place. One is to check that the encode
+%%% size does not exceed Max PDU size (this is mentioned in the
+%%% standard). The other is a simple VBs limit. That is, the
+%%% resulting response cannot contain more then this number of VBs.
+%%%-----------------------------------------------------------------
+
+do_get_bulk(MibView, NonRepeaters, MaxRepetitions,
+ PduMS, Varbinds, GbMaxVBs, _Extra) ->
+ ?vtrace("do_get_bulk -> entry with"
+ "~n MibView: ~p"
+ "~n NonRepeaters: ~p"
+ "~n MaxRepetitions: ~p"
+ "~n PduMS: ~p"
+ "~n Varbinds: ~p"
+ "~n GbMaxVBs: ~p",
+ [MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds, GbMaxVBs]),
+ {NonRepVbs, RestVbs} = ?LIB:split_vbs_gb(NonRepeaters, Varbinds),
+ ?vt("do_get_bulk -> split: "
+ "~n NonRepVbs: ~p"
+ "~n RestVbs: ~p", [NonRepVbs, RestVbs]),
+ case do_get_next2(MibView, NonRepVbs, GbMaxVBs) of
+ {noError, 0, UResNonRepVbs} ->
+ ?vt("do_get_bulk -> next noError: "
+ "~n UResNonRepVbs: ~p", [UResNonRepVbs]),
+ ResNonRepVbs = lists:keysort(#varbind.org_index, UResNonRepVbs),
+ %% Decode the first varbinds, produce a reversed list of
+ %% listOfBytes.
+ case (catch enc_vbs(PduMS - ?empty_pdu_size, ResNonRepVbs)) of
+ {error, Idx, Reason} ->
+ ?LIB:user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]),
+ {genErr, Idx, []};
+ {SizeLeft, Res} when is_integer(SizeLeft) and is_list(Res) ->
+ ?vtrace("do_get_bulk -> encoded: "
+ "~n SizeLeft: ~p"
+ "~n Res: ~w", [SizeLeft, Res]),
+ case (catch do_get_rep(SizeLeft, MibView, MaxRepetitions,
+ RestVbs, Res,
+ length(UResNonRepVbs), GbMaxVBs)) of
+ {error, Idx, Reason} ->
+ ?LIB:user_err("failed encoding varbind ~w:~n~p",
+ [Idx, Reason]),
+ {genErr, Idx, []};
+ Res when is_list(Res) ->
+ ?vtrace("do get bulk -> Res: "
+ "~n ~w", [Res]),
+ {noError, 0, conv_res(Res)};
+ {noError, 0, Data} = OK ->
+ ?vtrace("do get bulk -> OK: "
+ "~n length(Data): ~w", [length(Data)]),
+ OK;
+ Else ->
+ ?vtrace("do get bulk -> Else: "
+ "~n ~w", [Else]),
+ Else
+ end;
+ Res when is_list(Res) ->
+ {noError, 0, conv_res(Res)}
+ end;
+
+ {ErrorStatus, Index, _} ->
+ ?vdebug("do get bulk: "
+ "~n ErrorStatus: ~p"
+ "~n Index: ~p",[ErrorStatus, Index]),
+ {ErrorStatus, Index, []}
+ end.
+
+enc_vbs(SizeLeft, Vbs) ->
+ ?vt("enc_vbs -> entry with"
+ "~n SizeLeft: ~w", [SizeLeft]),
+ Fun = fun(Vb, {Sz, Res}) when Sz > 0 ->
+ ?vt("enc_vbs -> (fun) entry with"
+ "~n Vb: ~p"
+ "~n Sz: ~p"
+ "~n Res: ~w", [Vb, Sz, Res]),
+ case (catch snmp_pdus:enc_varbind(Vb)) of
+ {'EXIT', Reason} ->
+ ?vtrace("enc_vbs -> encode failed: "
+ "~n Reason: ~p", [Reason]),
+ throw({error, Vb#varbind.org_index, Reason});
+ X ->
+ ?vt("enc_vbs -> X: ~w", [X]),
+ Lx = length(X),
+ ?vt("enc_vbs -> Lx: ~w", [Lx]),
+ if
+ Lx < Sz ->
+ {Sz - length(X), [X | Res]};
+ true ->
+ throw(Res)
+ end
+ end;
+ (_Vb, {_Sz, [_H | T]}) ->
+ ?vt("enc_vbs -> (fun) entry with"
+ "~n T: ~p", [T]),
+ throw(T);
+ (_Vb, {_Sz, []}) ->
+ ?vt("enc_vbs -> (fun) entry", []),
+ throw([])
+ end,
+ lists:foldl(Fun, {SizeLeft, []}, Vbs).
+
+do_get_rep(Sz, MibView, MaxRepetitions, Varbinds, Res, GbNumVBs, GbMaxVBs)
+ when MaxRepetitions >= 0 ->
+ do_get_rep(Sz, MibView, 0, MaxRepetitions, Varbinds, Res,
+ GbNumVBs, GbMaxVBs);
+do_get_rep(Sz, MibView, _MaxRepetitions, Varbinds, Res, GbNumVBs, GbMaxVBs) ->
+ do_get_rep(Sz, MibView, 0, 0, Varbinds, Res, GbNumVBs, GbMaxVBs).
+
+conv_res(ResVarbinds) ->
+ conv_res(ResVarbinds, []).
+conv_res([VbListOfBytes | T], Bytes) ->
+ conv_res(T, VbListOfBytes ++ Bytes);
+conv_res([], Bytes) ->
+ Bytes.
+
+%% The only other value, then a positive integer, is infinity.
+do_get_rep(_Sz, _MibView, Count, Max, _, _Res, GbNumVBs, GbMaxVBs)
+ when (is_integer(GbMaxVBs) andalso (GbNumVBs > GbMaxVBs)) ->
+ ?vinfo("Max Get-BULK VBs limit (~w) exceeded (~w) when:"
+ "~n Count: ~p"
+ "~n Max: ~p", [GbMaxVBs, GbNumVBs, Count, Max]),
+ {tooBig, 0, []};
+do_get_rep(_Sz, _MibView, Max, Max, _, Res, _GbNumVBs, _GbMaxVBs) ->
+ ?vt("do_get_rep -> done when: "
+ "~n Res: ~p", [Res]),
+ {noError, 0, conv_res(Res)};
+do_get_rep(Sz, MibView, Count, Max, Varbinds, Res, GbNumVBs, GbMaxVBs) ->
+ ?vt("do_get_rep -> entry when: "
+ "~n Sz: ~p"
+ "~n Count: ~p"
+ "~n Res: ~w", [Sz, Count, Res]),
+ case try_get_bulk(Sz, MibView, Varbinds, GbMaxVBs) of
+ {noError, NextVarbinds, SizeLeft, Res2} ->
+ ?vt("do_get_rep -> noError: "
+ "~n SizeLeft: ~p"
+ "~n Res2: ~p", [SizeLeft, Res2]),
+ do_get_rep(SizeLeft, MibView, Count+1, Max, NextVarbinds,
+ Res2 ++ Res,
+ GbNumVBs + length(Varbinds), GbMaxVBs);
+ {endOfMibView, _NextVarbinds, _SizeLeft, Res2} ->
+ ?vt("do_get_rep -> endOfMibView: "
+ "~n Res2: ~p", [Res2]),
+ {noError, 0, conv_res(Res2 ++ Res)};
+ {ErrorStatus, Index} ->
+ ?vtrace("do_get_rep -> done when error: "
+ "~n ErrorStatus: ~p"
+ "~n Index: ~p", [ErrorStatus, Index]),
+ {ErrorStatus, Index, []}
+ end.
+
+try_get_bulk(Sz, MibView, Varbinds, GbMaxVBs) ->
+ ?vt("try_get_bulk -> entry with"
+ "~n Sz: ~w"
+ "~n MibView: ~w"
+ "~n Varbinds: ~w", [Sz, MibView, Varbinds]),
+ case do_get_next2(MibView, Varbinds, GbMaxVBs) of
+ {noError, 0, UNextVarbinds} ->
+ ?vt("try_get_bulk -> noError: "
+ "~n UNextVarbinds: ~p", [UNextVarbinds]),
+ NextVarbinds = ?LIB:org_index_sort_vbs(UNextVarbinds),
+ case (catch enc_vbs(Sz, NextVarbinds)) of
+ {error, Idx, Reason} ->
+ ?LIB:user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]),
+ ?vtrace("try_get_bulk -> encode error: "
+ "~n Idx: ~p"
+ "~n Reason: ~p", [Idx, Reason]),
+ {genErr, Idx};
+ {SizeLeft, Res} when is_integer(SizeLeft) andalso
+ is_list(Res) ->
+ ?vt("try get bulk -> encode ok: "
+ "~n SizeLeft: ~w"
+ "~n Res: ~w", [SizeLeft, Res]),
+ {check_end_of_mibview(NextVarbinds),
+ NextVarbinds, SizeLeft, Res};
+ Res when is_list(Res) ->
+ ?vt("try get bulk -> Res: "
+ "~n ~w", [Res]),
+ {endOfMibView, [], 0, Res}
+ end;
+ {ErrorStatus, Index, _} ->
+ ?vt("try_get_bulk -> error: "
+ "~n ErrorStatus: ~p"
+ "~n Index: ~p", [ErrorStatus, Index]),
+ {ErrorStatus, Index}
+ end.
+
+%% If all variables in this pass are endOfMibView,
+%% there is no reason to continue.
+check_end_of_mibview([#varbind{value = endOfMibView} | T]) ->
+ check_end_of_mibview(T);
+check_end_of_mibview([]) -> endOfMibView;
+check_end_of_mibview(_) -> noError.
+
+
+
diff --git a/lib/snmp/src/agent/snmpa_get_lib.erl b/lib/snmp/src/agent/snmpa_get_lib.erl
new file mode 100644
index 0000000000..eaf7fe2641
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_get_lib.erl
@@ -0,0 +1,254 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%% Note that most of these functions *assume* that they are executed
+%% by the agent. If they are not they may note work as they require
+%% some properties to be set in the process dictionary!
+%%
+
+-module(snmpa_get_lib).
+
+-export([
+ split_vbs/1, split_vbs/3,
+ split_vbs_view/2,
+ split_vbs_gb/2,
+
+ agent_sort_vbs/1,
+ oid_sort_vbs/1, org_index_sort_vbs/1,
+
+ sa_split/1,
+
+ delete_prefixes/2,
+
+ dbg_apply/3,
+
+ user_err/2
+ ]).
+
+-define(VMODULE,"GET-LIB").
+-include("snmpa_internal.hrl").
+-include("snmp_types.hrl").
+-include("snmp_debug.hrl").
+-include("snmp_verbosity.hrl").
+
+
+
+
+%%-----------------------------------------------------------------
+%% split_vbs/1,3
+%%
+%% Splits the list of varbinds (basically) into two lists. One
+%% of 'end of'-varbinds (mib view and tables) and then the rest
+%% of the varbinds.
+%%-----------------------------------------------------------------
+
+-spec split_vbs(VBs :: [snmp:varbind()]) ->
+ {ResVBs :: [snmp:varbind()],
+ EndOfVBs :: [snmp:varbind()]}.
+
+split_vbs(VBs) ->
+ split_vbs(VBs, [], []).
+
+-spec split_vbs(VBs :: [snmp:varbind()],
+ Res :: [snmp:varbind()],
+ EndOfs :: [snmp:varbind()]) ->
+ {ResVBs :: [snmp:varbind()],
+ EndOfVBs :: [snmp:varbind()]}.
+
+split_vbs([], ResVBs, EndOfVBs) ->
+ {ResVBs, EndOfVBs};
+split_vbs([VB | VBs], Res, EndOfs) ->
+ case VB#varbind.value of
+ {endOfMibView, _} -> split_vbs(VBs, Res, [VB | EndOfs]);
+ {endOfTable, _} -> split_vbs(VBs, Res, [VB | EndOfs]);
+ _ -> split_vbs(VBs, [VB | Res], EndOfs)
+ end.
+
+
+
+%%-----------------------------------------------------------------
+%% split_vbs_view/2
+%%
+%% Splits a list of varbinds into two lists based on the provided
+%% MibView. One list of varbinds inside the MibView and one of
+%% varbinds outside the MibView.
+%%-----------------------------------------------------------------
+
+-spec split_vbs_view(VBs :: [snmp:varbind()],
+ MibView :: snmp_view_based_acm_mib:mibview()) ->
+ {OutSideView :: [snmp:varbind()],
+ InSideView :: [snmp:varbind()]}.
+
+split_vbs_view(VBs, MibView) ->
+ ?vtrace("split the varbinds view", []),
+ split_vbs_view(VBs, MibView, [], []).
+
+split_vbs_view([], _MibView, Out, In) ->
+ {Out, In};
+split_vbs_view([VB | VBs], MibView, Out, In) ->
+ case snmpa_acm:validate_mib_view(VB#varbind.oid, MibView) of
+ true ->
+ split_vbs_view(VBs, MibView, Out, [VB | In]);
+ false ->
+ VB2 = VB#varbind{value = noSuchObject},
+ split_vbs_view(VBs, MibView, [VB2 | Out], In)
+ end.
+
+
+
+%%-----------------------------------------------------------------
+%% split_vbs_gb/2
+%%
+%% Performs a get-bulk split of the varbinds
+%%-----------------------------------------------------------------
+
+-spec split_vbs_gb(NonRepeaters :: integer(),
+ VBs :: [snmp:varbind()]) ->
+ {NonRepVBs :: [snmp:varbind()],
+ RestVBs :: [snmp:varbind()]}.
+
+split_vbs_gb(N, VBs) ->
+ split_vbs_gb(N, VBs, []).
+
+split_vbs_gb(N, Varbinds, Res) when N =< 0 ->
+ {Res, Varbinds};
+split_vbs_gb(N, [H | T], Res) ->
+ split_vbs_gb(N-1, T, [H | Res]);
+split_vbs_gb(_N, [], Res) ->
+ {Res, []}.
+
+
+
+%%-----------------------------------------------------------------
+%% agent_sort_vbs/1
+%%
+%% Sorts the varbinds into two categories. The first is varbinds
+%% belonging to "our" agent and the other is varbinds for
+%% subagents.
+%%-----------------------------------------------------------------
+
+-spec agent_sort_vbs(VBs :: [snmp:varbind()]) ->
+ {AgentVBs :: [snmp:varbind()],
+ SubAgentVBs :: [snmp:varbind()]}.
+
+agent_sort_vbs(VBs) ->
+ snmpa_svbl:sort_varbindlist(get(mibserver), VBs).
+
+
+%%-----------------------------------------------------------------
+%% oid_sort_vbs/1
+%%
+%% Sorts the varbinds based on their oid.
+%%-----------------------------------------------------------------
+
+-spec oid_sort_vbs(VBs :: [snmp:varbind()]) -> SortedVBs :: [snmp:varbind()].
+
+oid_sort_vbs(VBs) ->
+ lists:keysort(#varbind.oid, VBs).
+
+
+%%-----------------------------------------------------------------
+%% org_index_sort_vbs/1
+%%
+%% Sorts the varbinds based on their org_index.
+%%-----------------------------------------------------------------
+
+-spec org_index_sort_vbs(VBs :: [snmp:varbind()]) -> SortedVBs :: [snmp:varbind()].
+
+org_index_sort_vbs(Vbs) ->
+ lists:keysort(#varbind.org_index, Vbs).
+
+
+
+%%-----------------------------------------------------------------
+%% sa_split/1
+%%
+%% Splits a list of {oid(), varbind()} into two lists of oid()
+%% and varbind. The resulting lists are reversed!
+%%-----------------------------------------------------------------
+
+-spec sa_split(SAVBs :: [{SAOid :: snmp:oid(), snmp:varbind()}]) ->
+ {Oids :: [snmp:oid()], VBs :: [snmp:varbind()]}.
+
+sa_split(SAVBs) ->
+ snmpa_svbl:sa_split(SAVBs).
+
+
+
+%%-----------------------------------------------------------------
+%% delete_prefixes/2
+%%
+%% Takes an Oid prefix and a list of ivarbinds and produces a list
+%% of {ShortOid, ASN1Type}. The ShortOid is basically the oid with
+%% the OidPrefix removed.
+%%-----------------------------------------------------------------
+
+-spec delete_prefixes(OidPrefix :: snmp:oid(),
+ VBs :: [snmp:ivarbind()]) ->
+ [{ShortOid :: snmp:oid(),
+ ASN1Type :: snmp:asn1_type()}].
+
+delete_prefixes(OidPrefix, IVBs) ->
+ [{snmp_misc:diff(Oid, OidPrefix), ME#me.asn1_type} ||
+ #ivarbind{varbind = #varbind{oid = Oid}, mibentry = ME} <- IVBs].
+
+
+
+%%-----------------------------------------------------------------
+%% dbg_apply/3
+%%
+%% Call instrumentation functions, but allow for debug printing
+%% of useful debug info.
+%%-----------------------------------------------------------------
+
+-spec dbg_apply(M :: atom(), F :: atom(), A :: list()) ->
+ any().
+
+dbg_apply(M, F, A) ->
+ case get(verbosity) of
+ silence ->
+ apply(M,F,A);
+ _ ->
+ ?vlog("~n apply: ~w, ~w, ~p~n", [M,F,A]),
+ Res = (catch apply(M,F,A)),
+ case Res of
+ {'EXIT', Reason} ->
+ ?vinfo("Call to: "
+ "~n Module: ~p"
+ "~n Function: ~p"
+ "~n Args: ~p"
+ "~n"
+ "~nresulted in an exit"
+ "~n"
+ "~n ~p~n", [M, F, A, Reason]);
+ _ ->
+ ?vlog("~n returned: ~p~n", [Res])
+ end,
+ Res
+ end.
+
+
+%% ---------------------------------------------------------------------
+
+user_err(F, A) ->
+ snmpa_error:user_err(F, A).
+
+
diff --git a/lib/snmp/src/agent/snmpa_get_mechanism.erl b/lib/snmp/src/agent/snmpa_get_mechanism.erl
new file mode 100644
index 0000000000..744a6529e1
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_get_mechanism.erl
@@ -0,0 +1,79 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(snmpa_get_mechanism).
+
+%%
+%% This module defines the behaviour for the undocumented (hidden)
+%% get-mechanism feature. This allows for implementing your own
+%% handling of get, get-next and get-bulk requests.
+%% Probably only useful for special cases (e.g. optimization).
+%%
+
+
+
+%% ----------- do_get/2,3 -----------------------------------------------------
+
+%% Purpose: Handles all VBs in a request that is inside the
+%% mibview (local).
+
+-callback do_get(UnsortedVBs :: [snmp:varbind()],
+ IsNotification :: boolean(),
+ Extra :: term()) ->
+ {noError, 0, ResVBs :: [snmp:varbind()]} |
+ {ErrStatus :: snmp:error_status(), ErrIndex :: snmp:error_index(), []}.
+
+
+%% Purpose: Handles "get-requests".
+
+-callback do_get(MibView :: snmp_view_based_acm_mib:mibview(),
+ UnsortedVBs :: [snmp:varbind()],
+ IsNotification :: boolean(),
+ Extra :: term()) ->
+ {noError, 0, ResVBs :: [snmp:varbind()]} |
+ {ErrStatus :: snmp:error_status(), ErrIndex :: snmp:error_index(), []}.
+
+
+
+
+%% ----------- do_get_next/2 ------------------------------------------------
+
+%% Purpose: Handles "get-next-requests".
+
+-callback do_get_next(MibView :: snmp_view_based_acm_mib:mibview(),
+ UnsortedVBs :: [snmp:varbind()],
+ Extra :: term()) ->
+ {noError, 0, ResVBs :: [snmp:varbind()]} |
+ {ErrStatus :: snmp:error_status(), ErrIndex :: snmp:error_index(), []}.
+
+
+
+
+%% ----------- do_get_bulk/6 ------------------------------------------------
+
+-callback do_get_bulk(MibView :: snmp_view_based_acm_mib:mibview(),
+ NonRepeaters :: non_neg_integer(),
+ MaxRepetitions :: non_neg_integer(),
+ PduMS :: pos_integer(),
+ VBs :: [snmp:varbind()],
+ MaxVBs :: pos_integer(),
+ Extra :: term()) ->
+ {noError, 0, ResVBs :: [snmp:varbind()]} |
+ {ErrStatus :: snmp:error_status(), ErrIndex :: snmp:error_index(), []}.
diff --git a/lib/snmp/src/agent/snmpa_local_db.erl b/lib/snmp/src/agent/snmpa_local_db.erl
index eb67b9cd6f..f481641242 100644
--- a/lib/snmp/src/agent/snmpa_local_db.erl
+++ b/lib/snmp/src/agent/snmpa_local_db.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -147,12 +147,13 @@ init([Prio, DbDir, DbInitError, Opts]) ->
do_init(Prio, DbDir, DbInitError, Opts) ->
process_flag(priority, Prio),
process_flag(trap_exit, true),
- put(sname,ldb),
- put(verbosity,get_opt(verbosity, Opts, ?default_verbosity)),
+ put(sname, get_opt(sname, Opts, ldb)),
+ put(verbosity, get_opt(verbosity, Opts, ?default_verbosity)),
?vlog("starting",[]),
Dets = dets_open(DbDir, DbInitError, Opts),
Ets = ets:new(?ETS_TAB, [set, protected]),
?vdebug("started",[]),
+ put(started, snmp_misc:formated_timestamp()),
{ok, #state{dets = Dets, ets = Ets}}.
dets_open(DbDir, DbInitError, Opts) ->
@@ -625,7 +626,7 @@ handle_info(Info, State) ->
terminate(Reason, State) ->
- ?vlog("terminate: ~p",[Reason]),
+ ?vlog("terminate: ~p", [Reason]),
close(State).
diff --git a/lib/snmp/src/agent/snmpa_net_if.erl b/lib/snmp/src/agent/snmpa_net_if.erl
index ecf9498ca9..afed4482d2 100644
--- a/lib/snmp/src/agent/snmpa_net_if.erl
+++ b/lib/snmp/src/agent/snmpa_net_if.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -137,11 +137,10 @@ init(Prio, NoteStore, MasterAgent, Parent, Opts) ->
proc_lib:init_ack({ok, self()}),
try loop(State)
catch
- C:E when C =/= exit, E =/= shutdown ->
+ C:E:S when C =/= exit, E =/= shutdown ->
Fmt =
"loop/1 EXCEPTION ~w:~w~n"
" ~p",
- S = erlang:get_stacktrace(),
case C of
exit ->
%% Externally killed, root cause is elsewhere
@@ -647,10 +646,10 @@ maybe_handle_recv(
case
try FilterMod:accept_recv(From_1, From_2)
catch
- Class:Exception ->
+ Class:Exception:StackTrace ->
error_msg(
"FilterMod:accept_recv(~p, ~p) crashed: ~w:~w~n ~p",
- [From_1,From_2,Class,Exception,erlang:get_stacktrace()]),
+ [From_1, From_2, Class, Exception, StackTrace]),
true
end
of
@@ -753,12 +752,11 @@ maybe_handle_recv_pdu(
case
try FilterMod:accept_recv_pdu(From_1, From_2, Type)
catch
- Class:Exception ->
+ Class:Exception:StackTrace ->
error_msg(
"FilterMod:accept_recv_pdu(~p, ~p, ~p) crashed: ~w:~w~n"
" ~p",
- [From_1,From_2,Type,Class,Exception,
- erlang:get_stacktrace()]),
+ [From_1, From_2, Type, Class, Exception, StackTrace]),
true
end
of
@@ -834,11 +832,10 @@ maybe_handle_reply_pdu(
try
FilterMod:accept_send_pdu(Addresses, Type)
catch
- Class:Exception ->
+ Class:Exception:StackTrace ->
error_msg(
"FilterMod:accept_send_pdu(~p, ~p) crashed: ~w:~w~n ~p",
- [Addresses, Type, Class, Exception,
- erlang:get_stacktrace()]),
+ [Addresses, Type, Class, Exception, StackTrace]),
true
end
of
@@ -872,7 +869,7 @@ handle_reply_pdu(
ACMData, LogF)) of
{ok, Packet} ->
?vinfo("time in agent: ~w mysec", [time_in_agent()]),
- try maybe_udp_send(S, Transport, To, Packet)
+ try maybe_udp_send_wo_log(S, Transport, To, Packet)
catch
{Reason, Sz} ->
error_msg("Cannot send message "
@@ -917,11 +914,10 @@ maybe_handle_send_pdu(
case
try FilterMod:accept_send_pdu(AddressesToFilter, Type)
catch
- Class:Exception ->
+ Class:Exception:StackTrace ->
error_msg(
"FilterMod:accept_send_pdu(~p, ~p) crashed: ~w:~w~n ~p",
- [AddressesToFilter,Type,
- Class,Exception,erlang:get_stacktrace()]),
+ [AddressesToFilter, Type, Class, Exception, StackTrace]),
true
end
of
@@ -1049,46 +1045,36 @@ do_handle_send_pdu(S, Type, Pdu, Addresses) ->
[Sz, Reason, Pdu])
end.
-do_handle_send_pdu1(
- #state{transports = Transports} = S,
- Type, Addresses) ->
+do_handle_send_pdu1(S, Type, Addresses) ->
lists:foreach(
- fun ({Domain, Address, Packet}) when is_binary(Packet) ->
- ?vdebug(
- "[~w] sending packet:~n"
- " size: ~p~n"
- " to: ~p", [Domain, sz(Packet), Address]),
- To = {Domain, Address},
- case select_transport_from_domain(Domain, Transports) of
- false ->
- error_msg(
- "Can not find transport~n"
- " size: ~p~n"
- " to: ~s",
- [sz(Packet), format_address(To)]);
- Transport ->
- maybe_udp_send(S, Transport, To, Packet)
- end;
- ({Domain, Address, {Packet, LogData}}) when is_binary(Packet) ->
- ?vdebug(
- "[~w] sending encrypted packet:~n"
- " size: ~p~n"
- " to: ~p", [Domain, sz(Packet), Address]),
- To = {Domain, Address},
- case select_transport_from_domain(Domain, Transports) of
- false ->
- error_msg(
- "Can not find transport~n"
- " size: ~p~n"
- " to: ~s",
- [sz(Packet), format_address(To)]);
- Transport ->
- maybe_udp_send(S, Transport, To, Packet, Type, LogData)
- end
+ fun ({Domain, Address, Pkg}) when is_binary(Pkg) ->
+ do_handle_send_pdu2(S, Type, Domain, Address,
+ Pkg, Pkg, "");
+ ({Domain, Address, {Pkg, LogPkg}}) when is_binary(Pkg) ->
+ do_handle_send_pdu2(S, Type, Domain, Address,
+ Pkg, LogPkg, " encrypted")
end,
Addresses).
-maybe_udp_send(
+do_handle_send_pdu2(#state{transports = Transports} = S,
+ Type, Domain, Address, Pkg, LogPkg, EncrStr) ->
+ ?vdebug("[~w] sending~s packet:"
+ "~n size: ~p"
+ "~n to: ~p", [Domain, EncrStr, sz(Pkg), Address]),
+ To = {Domain, Address},
+ case select_transport_from_domain(Domain, Transports) of
+ false ->
+ error_msg("Can not find transport: "
+ "~n size: ~p"
+ "~n to: ~s",
+ [sz(Pkg), format_address(To)]);
+ Transport ->
+ maybe_udp_send_w_log(S, Transport, To, Pkg, LogPkg, Type)
+ end.
+
+
+%% This function is used when logging has already been done!
+maybe_udp_send_wo_log(
#state{filter = FilterMod, transports = Transports},
#transport{socket = Socket},
To, Packet) ->
@@ -1096,10 +1082,10 @@ maybe_udp_send(
case
try FilterMod:accept_send(To_1, To_2)
catch
- Class:Exception ->
+ Class:Exception:StackTrace ->
error_msg(
"FilterMod:accept_send(~p, ~p) crashed: ~w:~w~n ~p",
- [To_1,To_2,Class,Exception,erlang:get_stacktrace()]),
+ [To_1, To_2, Class, Exception, StackTrace]),
true
end
of
@@ -1118,18 +1104,18 @@ maybe_udp_send(
udp_send(Socket, To, Packet)
end.
-maybe_udp_send(
+maybe_udp_send_w_log(
#state{log = Log, filter = FilterMod, transports = Transports},
#transport{socket = Socket},
- To, Packet, Type, _LogData) ->
+ To, Pkg, LogPkg, Type) ->
{To_1, To_2} = fix_filter_address(Transports, To),
case
try FilterMod:accept_send(To_1, To_2)
catch
- Class:Exception ->
+ Class:Exception:StackTrace ->
error_msg(
"FilterMod:accept_send(~p, ~p) crashed for: ~w:~w~n ~p",
- [To_1, To_2, Class, Exception, erlang:get_stacktrace()]),
+ [To_1, To_2, Class, Exception, StackTrace]),
true
end
of
@@ -1143,10 +1129,10 @@ maybe_udp_send(
_ ->
error_msg(
"FilterMod:accept_send(~p, ~p) returned: ~p",
- [To_1,To_2,Other])
+ [To_1, To_2, Other])
end,
- log(Log, Type, Packet, To),
- udp_send(Socket, To, Packet)
+ log(Log, Type, LogPkg, To),
+ udp_send(Socket, To, Pkg)
end.
udp_send(Socket, To, B) ->
@@ -1168,11 +1154,10 @@ udp_send(Socket, To, B) ->
ok ->
ok
catch
- error:ExitReason ->
+ error:ExitReason:StackTrace ->
error_msg("[exit] cannot send message "
"(destination: ~p:~p, size: ~p, reason: ~p, at: ~p)",
- [IpAddr, IpPort, sz(B), ExitReason,
- erlang:get_stacktrace()])
+ [IpAddr, IpPort, sz(B), ExitReason, StackTrace])
end.
sz(L) when is_list(L) -> length(L);
diff --git a/lib/snmp/src/agent/snmpa_set_lib.erl b/lib/snmp/src/agent/snmpa_set_lib.erl
index 57507a36e8..94120f4c7d 100644
--- a/lib/snmp/src/agent/snmpa_set_lib.erl
+++ b/lib/snmp/src/agent/snmpa_set_lib.erl
@@ -46,9 +46,9 @@
%%* 6) IF value is outside the acceptable range THEN wrongValue.
%% 7) IF variable does not exist and could not ever be created
%% THEN noCreation.
-%% 8) IF variable can not be created now THEN inconsistentName.
-%% 9) IF value can not be set now THEN inconsistentValue.
-%%* 9) IF instances of the variable can not be modified THEN notWritable.
+%% 8) IF variable cannot be created now THEN inconsistentName.
+%% 9) IF value cannot be set now THEN inconsistentValue.
+%%* 9) IF instances of the variable cannot be modified THEN notWritable.
%% 10) IF an unavailable resource is needed THEN resourceUnavailable.
%% 11) IF any other error THEN genErr.
%% 12) Otherwise ok!
@@ -390,7 +390,7 @@ dbg_apply(M,F,A) ->
{'EXIT', {function_clause, [{M, F, A} | _]}} ->
{'EXIT', {hook_function_clause, {M, F, A}}};
- % XYZ: Older format for compatibility
+ %% XYZ: Older format for compatibility
{'EXIT', {undef, {M, F, A}}} ->
{'EXIT', {hook_undef, {M, F, A}}};
{'EXIT', {function_clause, {M, F, A}}} ->
diff --git a/lib/snmp/src/agent/snmpa_supervisor.erl b/lib/snmp/src/agent/snmpa_supervisor.erl
index cdb5ca840d..2cb0556001 100644
--- a/lib/snmp/src/agent/snmpa_supervisor.erl
+++ b/lib/snmp/src/agent/snmpa_supervisor.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -193,36 +193,36 @@ init([AgentType, Opts]) ->
?vdebug("agent restart type: ~w", [Restart]),
%% -- Agent type --
- ets:insert(snmp_agent_table, {agent_type, AgentType}),
+ store(agent_type, AgentType),
%% -- Prio --
Prio = get_opt(priority, Opts, normal),
?vdebug("[agent table] store priority: ~p",[Prio]),
- ets:insert(snmp_agent_table, {priority, Prio}),
+ store(priority, Prio),
%% -- Versions --
Vsns = get_opt(versions, Opts, [v1,v2,v3]),
?vdebug("[agent table] store versions: ~p",[Vsns]),
- ets:insert(snmp_agent_table, {versions, Vsns}),
+ store(versions, Vsns),
%% -- Max number of VBs in a Get-BULK response --
GbMaxVBs = get_gb_max_vbs(Opts),
?vdebug("[agent table] Get-BULK max VBs: ~p", [GbMaxVBs]),
- ets:insert(snmp_agent_table, {gb_max_vbs, GbMaxVBs}),
+ store(gb_max_vbs, GbMaxVBs),
%% -- DB-directory --
DbDir = get_opt(db_dir, Opts),
?vdebug("[agent table] store db_dir: ~n ~p",[DbDir]),
- ets:insert(snmp_agent_table, {db_dir, filename:join([DbDir])}),
+ store(db_dir, filename:join([DbDir])),
DbInitError = get_opt(db_init_error, Opts, terminate),
?vdebug("[agent table] store db_init_error: ~n ~p",[DbInitError]),
- ets:insert(snmp_agent_table, {db_init_error, DbInitError}),
+ store(db_init_error, DbInitError),
%% -- Error report module --
ErrorReportMod = get_opt(error_report_mod, Opts, snmpa_error_logger),
?vdebug("[agent table] store error report module: ~w",[ErrorReportMod]),
- ets:insert(snmp_agent_table, {error_report_mod, ErrorReportMod}),
+ store(error_report_mod, ErrorReportMod),
%% -- mib storage --
%% MibStorage has only one mandatory part: module
@@ -320,31 +320,31 @@ init([AgentType, Opts]) ->
end,
?vdebug("[agent table] store mib storage: ~w", [MibStorage]),
- ets:insert(snmp_agent_table, {mib_storage, MibStorage}),
+ store(mib_storage, MibStorage),
%% -- Agent mib storage --
AgentMibStorage = get_opt(agent_mib_storage, Opts, persistent),
%% ?vdebug("[agent table] store agent mib storage: ~w",[AgentMibStorage]),
- ets:insert(snmp_agent_table, {agent_mib_storage, AgentMibStorage}),
+ store(agent_mib_storage, AgentMibStorage),
%% -- System start time --
?vdebug("[agent table] store system start time",[]),
- ets:insert(snmp_agent_table, {system_start_time, snmp_misc:now(cs)}),
+ store(system_start_time, snmp_misc:now(cs)),
%% -- Symbolic store options --
SsOpts = get_opt(symbolic_store, Opts, []),
?vdebug("[agent table] store symbolic store options: ~w",[SsOpts]),
- ets:insert(snmp_agent_table, {symbolic_store, SsOpts}),
+ store(symbolic_store, SsOpts),
%% -- Local DB options --
LdbOpts = get_opt(local_db, Opts, []),
?vdebug("[agent table] store local db options: ~w",[LdbOpts]),
- ets:insert(snmp_agent_table, {local_db, LdbOpts}),
+ store(local_db, LdbOpts),
%% -- Target cache options --
TargetCacheOpts = get_opt(target_cache, Opts, []),
?vdebug("[agent table] store target cache options: ~w",[TargetCacheOpts]),
- ets:insert(snmp_agent_table, {target_cache, TargetCacheOpts}),
+ store(target_cache, TargetCacheOpts),
%% -- Specs --
SupFlags = {one_for_all, 0, 3600},
@@ -377,7 +377,7 @@ init([AgentType, Opts]) ->
%% -- Config --
ConfOpts = get_opt(config, Opts, []),
?vdebug("[agent table] store config options: ~p", [ConfOpts]),
- ets:insert(snmp_agent_table, {config, ConfOpts}),
+ store(config, ConfOpts),
ConfigArgs = [Vsns, ConfOpts],
ConfigSpec =
@@ -390,43 +390,46 @@ init([AgentType, Opts]) ->
%% -- Discovery processing --
DiscoOpts = get_opt(discovery, Opts, []),
?vdebug("[agent table] store discovery options: ~p", [DiscoOpts]),
- ets:insert(snmp_agent_table, {discovery, DiscoOpts}),
+ store(discovery, DiscoOpts),
%% -- Mibs --
Mibs = get_mibs(get_opt(mibs, Opts, []), Vsns),
?vdebug("[agent table] store mibs: ~n ~p",[Mibs]),
- ets:insert(snmp_agent_table, {mibs, Mibs}),
+ store(mibs, Mibs),
Ref = make_ref(),
+ %% -- Get module --
+ GetModule = get_opt(get_mechanism, Opts, snmpa_get),
+ ?vdebug("[agent table] store get-module: ~p", [GetModule]),
+ store(get_mechanism, GetModule),
+
%% -- Set module --
SetModule = get_opt(set_mechanism, Opts, snmpa_set),
?vdebug("[agent table] store set-module: ~p",[SetModule]),
- ets:insert(snmp_agent_table, {set_mechanism, ConfOpts}),
+ store(set_mechanism, SetModule),
%% -- Authentication service --
AuthModule = get_opt(authentication_service, Opts, snmpa_acm),
?vdebug("[agent table] store authentication service: ~w",
[AuthModule]),
- ets:insert(snmp_agent_table,
- {authentication_service, AuthModule}),
+ store(authentication_service, AuthModule),
%% -- Multi-threaded --
MultiT = get_opt(multi_threaded, Opts, false),
- ?vdebug("[agent table] store multi-threaded: ~p",[MultiT]),
- ets:insert(snmp_agent_table, {multi_threaded, MultiT}),
+ ?vdebug("[agent table] store multi-threaded: ~p", [MultiT]),
+ store(multi_threaded, MultiT),
%% -- Audit trail log --
case get_opt(audit_trail_log, Opts, not_found) of
not_found ->
- ?vdebug("[agent table] no audit trail log",[]),
+ ?vdebug("[agent table] no audit trail log", []),
ok;
AtlOpts ->
?vdebug("[agent table] "
"store audit trail log options: ~p",
[AtlOpts]),
- ets:insert(snmp_agent_table,
- {audit_trail_log, AtlOpts}),
+ store(audit_trail_log, AtlOpts),
ok
end,
@@ -434,24 +437,25 @@ init([AgentType, Opts]) ->
MibsOpts = get_opt(mib_server, Opts, []),
?vdebug("[agent table] store mib-server options: "
"~n ~p", [MibsOpts]),
- ets:insert(snmp_agent_table, {mib_server, MibsOpts}),
+ store(mib_server, MibsOpts),
%% -- Network interface --
NiOpts = get_opt(net_if, Opts, []),
?vdebug("[agent table] store net-if options: "
"~n ~p", [NiOpts]),
- ets:insert(snmp_agent_table, {net_if, NiOpts}),
+ store(net_if, NiOpts),
%% -- Note store --
NsOpts = get_opt(note_store, Opts, []),
?vdebug("[agent table] store note-store options: "
"~n ~p",[NsOpts]),
- ets:insert(snmp_agent_table, {note_store, NsOpts}),
+ store(note_store, NsOpts),
AgentOpts =
[{verbosity, AgentVerb},
{mibs, Mibs},
{mib_storage, MibStorage},
+ {get_mechanism, GetModule},
{set_mechanism, SetModule},
{authentication_service, AuthModule},
{multi_threaded, MultiT},
@@ -480,6 +484,10 @@ init([AgentType, Opts]) ->
{ok, {SupFlags, [MiscSupSpec, SymStoreSpec, LocalDbSpec, TargetCacheSpec |
Rest]}}.
+
+store(Key, Value) ->
+ ets:insert(snmp_agent_table, {Key, Value}).
+
get_mibs(Mibs, Vsns) ->
MibDir = filename:join(code:priv_dir(snmp), "mibs"),
StdMib =
diff --git a/lib/snmp/src/agent/snmpa_trap.erl b/lib/snmp/src/agent/snmpa_trap.erl
index e75016f7ec..d04b6a206e 100644
--- a/lib/snmp/src/agent/snmpa_trap.erl
+++ b/lib/snmp/src/agent/snmpa_trap.erl
@@ -830,11 +830,11 @@ do_send_v1_trap(Enter, Spec, V1Res, NVbs, ExtraInfo, NetIf, SysUpTime) ->
case lists:keyfind(transportDomainUdpIpv4, 1, Transports) of
false ->
?vtrace(
- "snmpa_trap: can not send v1 trap "
+ "snmpa_trap: cannot send v1 trap "
"without IPv4 domain: ~p",
[Transports]),
user_err(
- "snmpa_trap: can not send v1 trap "
+ "snmpa_trap: cannot send v1 trap "
"without IPv4 domain: ~p",
[Transports]);
DomainAddr ->
@@ -917,7 +917,7 @@ do_send_v2_trap(Recvs, Vbs, ExtraInfo, NetIf) ->
TrapPdu = make_v2_notif_pdu(Vbs, 'snmpv2-trap'),
AddrCommunities = mk_addr_communities(Recvs),
lists:foreach(fun({Community, Addrs}) ->
- ?vtrace("~n send v2 trap to ~p",[Addrs]),
+ ?vtrace("send v2 trap to ~p",[Addrs]),
NetIf ! {send_pdu, 'version-2', TrapPdu,
{community, Community}, Addrs, ExtraInfo}
end, AddrCommunities),
diff --git a/lib/snmp/src/app/snmp.app.src b/lib/snmp/src/app/snmp.app.src
index d4bf0de61a..178309b488 100644
--- a/lib/snmp/src/app/snmp.app.src
+++ b/lib/snmp/src/app/snmp.app.src
@@ -49,6 +49,9 @@
snmpa_error_io,
snmpa_error_logger,
snmpa_error_report,
+ snmpa_get,
+ snmpa_get_lib,
+ snmpa_get_mechanism,
snmpa_local_db,
snmpa_mib,
snmpa_mib_data,
diff --git a/lib/snmp/src/app/snmp.config b/lib/snmp/src/app/snmp.config
index b66ef5d7df..f35a636157 100644
--- a/lib/snmp/src/app/snmp.config
+++ b/lib/snmp/src/app/snmp.config
@@ -8,6 +8,7 @@
%% {agent_verbosity, verbosity()} |
%% {versions, versions()} |
%% {priority, atom()} |
+%% {get_mechanism, module()} |
%% {set_mechanism, module()} |
%% {authentication_service, module()} |
%% {multi_threaded, bool()} |
diff --git a/lib/snmp/src/app/snmp.erl b/lib/snmp/src/app/snmp.erl
index 8a736f688b..216452afdd 100644
--- a/lib/snmp/src/app/snmp.erl
+++ b/lib/snmp/src/app/snmp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -116,7 +116,10 @@
pdu/0,
trappdu/0,
mib/0,
- mib_name/0,
+ mib_name/0,
+
+ error_status/0,
+ error_index/0,
void/0
]).
@@ -208,6 +211,23 @@
-type pdu() :: #pdu{}.
-type trappdu() :: #trappdu{}.
+%% We should really specify all of these, but they are so numerous...
+%% See the validate_err/1 function in the snmpa_agent.
+%% Here are a number of them:
+%% badValue |
+%% commitFailed |
+%% genErr |
+%% inconsistentName | inconsistentValue |
+%% noAccess | noCreation |
+%% noSuchInstance | noSuchName | noSuchObject |
+%% notWritable |
+%% resourceUnavailable |
+%% undoFailed |
+%% wrongValue
+
+-type error_status() :: atom().
+-type error_index() :: pos_integer().
+
-type void() :: term().
diff --git a/lib/snmp/src/compile/snmpc.erl b/lib/snmp/src/compile/snmpc.erl
index 4416626a4c..c810bfcd41 100644
--- a/lib/snmp/src/compile/snmpc.erl
+++ b/lib/snmp/src/compile/snmpc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -169,11 +169,7 @@ get_version() ->
MI = ?MODULE:module_info(),
Attr = get_info(attributes, MI),
Vsn = get_info(app_vsn, Attr),
- Comp = get_info(compile, MI),
- Time = get_info(time, Comp),
- {Year, Month, Day, Hour, Min, Sec} = Time,
- io_lib:format("~s [~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w]",
- [Vsn, Year, Month, Day, Hour, Min, Sec]).
+ Vsn.
maybe_display_options(Opts) ->
case lists:member(options, Opts) of
@@ -456,6 +452,7 @@ compile_parsed_data(#pdata{mib_name = MibName,
RelChk = get_relaxed_row_name_assign_check(Opts),
Data = #dldata{deprecated = Deprecated,
relaxed_row_name_assign_check = RelChk},
+ mc_new_type_loop(Definitions),
put(augmentations, false),
definitions_loop(Definitions, Data),
MibName.
@@ -481,7 +478,40 @@ do_update_imports([{{Mib, ImportsFromMib0},_Line}|Imports], Acc) ->
update_status(Name, Status) ->
#cdata{status_ets = Ets} = get(cdata),
ets:insert(Ets, {Name, Status}).
-
+
+
+mc_new_type_loop(
+ [{#mc_new_type{
+ name = NewTypeName,
+ macro = Macro,
+ syntax = OldType,
+ display_hint = DisplayHint},Line}|T]) ->
+ ?vlog2("typeloop -> new_type:"
+ "~n Macro: ~p"
+ "~n NewTypeName: ~p"
+ "~n OldType: ~p"
+ "~n DisplayHint: ~p",
+ [Macro, NewTypeName, OldType, DisplayHint], Line),
+ ensure_macro_imported(Macro,Line),
+ Types = (get(cdata))#cdata.asn1_types,
+ case lists:keysearch(NewTypeName, #asn1_type.aliasname, Types) of
+ {value,_} ->
+ snmpc_lib:print_error("Type ~w already defined.",
+ [NewTypeName],Line);
+ false ->
+ %% NameOfOldType = element(2,OldType),
+ ASN1 = snmpc_lib:make_ASN1type(OldType),
+ snmpc_lib:add_cdata(#cdata.asn1_types,
+ [ASN1#asn1_type{aliasname = NewTypeName,
+ imported = false,
+ display_hint = DisplayHint}])
+ end,
+ mc_new_type_loop(T);
+mc_new_type_loop([_|T]) ->
+ mc_new_type_loop(T);
+mc_new_type_loop([]) ->
+ ok.
+
%% A deprecated object
definitions_loop([{#mc_object_type{name = ObjName, status = deprecated},
@@ -745,32 +775,8 @@ definitions_loop([{#mc_object_type{name = NameOfTable,
ColMEs]),
definitions_loop(RestObjs, Data);
-definitions_loop([{#mc_new_type{name = NewTypeName,
- macro = Macro,
- syntax = OldType,
- display_hint = DisplayHint},Line}|T],
- Data) ->
- ?vlog2("defloop -> new_type:"
- "~n Macro: ~p"
- "~n NewTypeName: ~p"
- "~n OldType: ~p"
- "~n DisplayHint: ~p",
- [Macro, NewTypeName, OldType, DisplayHint], Line),
- ensure_macro_imported(Macro,Line),
- Types = (get(cdata))#cdata.asn1_types,
- case lists:keysearch(NewTypeName, #asn1_type.aliasname, Types) of
- {value,_} ->
- snmpc_lib:print_error("Type ~w already defined.",
- [NewTypeName],Line);
- false ->
- %% NameOfOldType = element(2,OldType),
- ASN1 = snmpc_lib:make_ASN1type(OldType),
- snmpc_lib:add_cdata(#cdata.asn1_types,
- [ASN1#asn1_type{aliasname = NewTypeName,
- imported = false,
- display_hint = DisplayHint}])
- end,
- definitions_loop(T, Data);
+definitions_loop([{#mc_new_type{},_}|T], Data) ->
+ definitions_loop(T, Data);
%% Plain variable
definitions_loop([{#mc_object_type{name = NewVarName,
diff --git a/lib/snmp/src/misc/snmp_log.erl b/lib/snmp/src/misc/snmp_log.erl
index 767d801eee..5713c14912 100644
--- a/lib/snmp/src/misc/snmp_log.erl
+++ b/lib/snmp/src/misc/snmp_log.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -649,13 +649,14 @@ do_log_to_file(Log, TextFile, Mibs, Start, Stop) ->
MiniMib = snmp_mini_mib:create(Mibs),
Write = fun(X) ->
case format_msg(X, MiniMib, Start, Stop) of
- {ok, S} ->
- io:format(Fd, "~s", [S]);
- _ ->
- ok
+ {Tag, S} when (Tag =:= ok) orelse (Tag =:= error) ->
+ io:format(Fd, "~s", [S]),
+ Tag;
+ Ignore ->
+ Ignore
end
end,
- Res = (catch loop(disk_log:chunk(Log, start), Log, Write)),
+ Res = (catch loop(Log, Write)),
snmp_mini_mib:delete(MiniMib),
file:close(Fd),
Res;
@@ -668,39 +669,63 @@ do_log_to_io(Log, Mibs, Start, Stop) ->
MiniMib = snmp_mini_mib:create(Mibs),
Write = fun(X) ->
case format_msg(X, MiniMib, Start, Stop) of
- {ok, S} ->
- io:format("~s", [S]);
- _ ->
- ok
+ {Tag, S} when (Tag =:= ok) orelse (Tag =:= error) ->
+ io:format("~s", [S]),
+ Tag;
+ X ->
+ X
end
end,
- (catch loop(disk_log:chunk(Log, start), Log, Write)),
+ Res = (catch loop(Log, Write)),
snmp_mini_mib:delete(MiniMib),
- ok.
+ Res.
+
+loop(Log, Write) ->
+ loop(disk_log:chunk(Log, start), Log, Write, 0, 0).
-loop(eof, _Log, _Write) ->
+loop(eof, _Log, _Write, _NumOK, 0 = _NumERR) ->
ok;
-loop({error, _} = Error, _Log, _Write) ->
+loop(eof, _Log, _Write, NumOK, NumERR) ->
+ {ok, {NumOK, NumERR}};
+loop({error, _} = Error, _Log, _Write, _NumOK, _NumERR) ->
Error;
-loop({Cont, Terms}, Log, Write) ->
- case (catch lists:foreach(Write, Terms)) of
- {'EXIT', Reason} ->
- {error, Reason};
- _ ->
- loop(disk_log:chunk(Log, Cont), Log, Write)
+loop({Cont, Terms}, Log, Write, NumOK, NumERR) ->
+ try loop_terms(Terms, Write) of
+ {ok, {AddedOK, AddedERR}} ->
+ loop(disk_log:chunk(Log, Cont), Log, Write,
+ NumOK+AddedOK, NumERR+AddedERR)
+ catch
+ C:E:S ->
+ {error, {C, E, S}}
end;
-loop({Cont, Terms, BadBytes}, Log, Write) ->
+loop({Cont, Terms, BadBytes}, Log, Write, NumOK, NumERR) ->
error_logger:error_msg("Skipping ~w bytes while converting ~p~n~n",
[BadBytes, Log]),
- case (catch lists:foreach(Write, Terms)) of
- {'EXIT', Reason} ->
- {error, Reason};
- _ ->
- loop(disk_log:chunk(Log, Cont), Log, Write)
- end;
-loop(Error, _Log, _Write) ->
- Error.
+ try loop_terms(Terms, Write) of
+ {ok, {AddedOK, AddedERR}} ->
+ loop(disk_log:chunk(Log, Cont), Log, Write,
+ NumOK+AddedOK, NumERR+AddedERR)
+ catch
+ C:E:S ->
+ {error, {C, E, S}}
+ end.
+
+
+loop_terms(Terms, Write) ->
+ loop_terms(Terms, Write, 0, 0).
+
+loop_terms([], _Write, NumOK, NumERR) ->
+ {ok, {NumOK, NumERR}};
+loop_terms([Term|Terms], Write, NumOK, NumERR) ->
+ case Write(Term) of
+ ok ->
+ loop_terms(Terms, Write, NumOK+1, NumERR);
+ error ->
+ loop_terms(Terms, Write, NumOK, NumERR+1);
+ _ ->
+ loop_terms(Terms, Write, NumOK, NumERR)
+ end.
format_msg(Entry, Mib, Start, Stop) ->
@@ -733,88 +758,149 @@ do_format_msg({Timestamp, SeqNo, Packet, Ip, Port}, Mib) ->
%% This is crap...
do_format_msg(_, _) ->
- format_tab("** unknown entry in log file\n\n", []).
+ {error, format_tab("** unknown entry in log file\n\n", [])}.
do_format_msg(TimeStamp, {V3Hdr, ScopedPdu}, AddrStr, Mib) ->
- case (catch snmp_pdus:dec_scoped_pdu(ScopedPdu)) of
+ try snmp_pdus:dec_scoped_pdu(ScopedPdu) of
ScopedPDU when is_record(ScopedPDU, scopedPdu) ->
Msg = #message{version = 'version-3',
vsn_hdr = V3Hdr,
data = ScopedPDU},
- f(ts2str(TimeStamp), "", Msg, AddrStr, Mib);
- {'EXIT', Reason} ->
- format_tab(
- "** error in log file at ~s from ~s ~p\n\n",
- [ts2str(TimeStamp), AddrStr, Reason])
+ try f(ts2str(TimeStamp), "", Msg, AddrStr, Mib) of
+ {ok, _} = OK ->
+ OK
+ catch
+ FormatT:FormatE ->
+ format_error("format scoped pdu",
+ TimeStamp, AddrStr, FormatT, FormatE)
+ end
+ catch
+ DecT:DecE ->
+ format_error("decode scoped pdu",
+ TimeStamp, AddrStr, DecT, DecE)
end;
do_format_msg(TimeStamp, Packet, AddrStr, Mib) ->
- case (catch snmp_pdus:dec_message(binary_to_list(Packet))) of
+ try snmp_pdus:dec_message(binary_to_list(Packet)) of
Msg when is_record(Msg, message) ->
- f(ts2str(TimeStamp), "", Msg, AddrStr, Mib);
- {'EXIT', Reason} ->
- format_tab("** error in log file ~p\n\n", [Reason])
+ try f(ts2str(TimeStamp), "", Msg, AddrStr, Mib) of
+ {ok, _} = OK ->
+ OK
+ catch
+ FormatT:FormatE ->
+ %% Provide info about the message
+ Extra =
+ case Msg#message.version of
+ 'version-3' ->
+ #v3_hdr{msgID = ID,
+ msgFlags = Flags,
+ msgSecurityModel = SecModel} =
+ Msg#message.vsn_hdr,
+ SecLevel = snmp_misc:get_sec_level(Flags),
+ f("msg-id: ~w, sec-level: ~w, sec-model: ~w",
+ [ID, SecLevel, sm2atom(SecModel)]);
+ _ -> %% Community
+ f("community: ~s", [Msg#message.vsn_hdr])
+ end,
+ format_error(f("format ~p message; ~s",
+ [Msg#message.version, Extra]),
+ TimeStamp, AddrStr, FormatT, FormatE)
+ end
+ catch
+ DecT:DecE ->
+ format_error("decode message",
+ TimeStamp, AddrStr, DecT, DecE)
+
end.
-
+
+sm2atom(?SEC_ANY) -> any;
+sm2atom(?SEC_V1) -> v1;
+sm2atom(?SEC_V2C) -> v2c;
+sm2atom(?SEC_USM) -> usm;
+sm2atom(_) -> unknown.
+
do_format_msg(TimeStamp, SeqNo, {V3Hdr, ScopedPdu}, AddrStr, Mib) ->
- case (catch snmp_pdus:dec_scoped_pdu(ScopedPdu)) of
+ try snmp_pdus:dec_scoped_pdu(ScopedPdu) of
ScopedPDU when is_record(ScopedPDU, scopedPdu) ->
Msg = #message{version = 'version-3',
vsn_hdr = V3Hdr,
data = ScopedPDU},
- f(ts2str(TimeStamp), sn2str(SeqNo), Msg, AddrStr, Mib);
- {'EXIT', Reason} ->
- format_tab(
- "** error in log file at ~s from ~s ~p\n\n",
- [ts2str(TimeStamp), sn2str(SeqNo), AddrStr, Reason])
+ try f(ts2str(TimeStamp), sn2str(SeqNo), Msg, AddrStr, Mib) of
+ {ok, _} = OK ->
+ OK
+ catch
+ FormatT:FormatE ->
+ format_error("format scoped pdu",
+ TimeStamp, SeqNo, AddrStr, FormatT, FormatE)
+ end
+ catch
+ DecT:DecE ->
+ format_error("decode scoped pdu",
+ TimeStamp, SeqNo, AddrStr, DecT, DecE)
end;
do_format_msg(TimeStamp, SeqNo, Packet, AddrStr, Mib) ->
- case (catch snmp_pdus:dec_message(binary_to_list(Packet))) of
+ try snmp_pdus:dec_message(binary_to_list(Packet)) of
Msg when is_record(Msg, message) ->
- f(ts2str(TimeStamp), sn2str(SeqNo), Msg, AddrStr, Mib);
- {'EXIT', Reason} ->
- format_tab(
- "** error in log file ~s from ~s ~p\n\n",
- [ts2str(TimeStamp), sn2str(SeqNo), AddrStr, Reason])
+ try f(ts2str(TimeStamp), sn2str(SeqNo), Msg, AddrStr, Mib) of
+ {ok, _} = OK ->
+ OK
+
+ catch
+ FormatT:FormatE ->
+ %% Provide info about the message
+ Extra =
+ case Msg#message.version of
+ 'version-3' ->
+ #v3_hdr{msgID = ID,
+ msgFlags = Flags,
+ msgSecurityModel = SecModel} =
+ Msg#message.vsn_hdr,
+ SecLevel = snmp_misc:get_sec_level(Flags),
+ f("msg-id: ~w, sec-level: ~w, sec-model: ~w",
+ [ID, SecLevel, sm2atom(SecModel)]);
+ _ -> %% Community
+ f("community: ~s", [Msg#message.vsn_hdr])
+ end,
+ format_error(f("format ~p message; ~s",
+ [Msg#message.version, Extra]),
+ TimeStamp, SeqNo, AddrStr, FormatT, FormatE)
+ end
+ catch
+ DecT:DecE ->
+ format_error("decode message",
+ TimeStamp, SeqNo, AddrStr, DecT, DecE)
end.
-
-
-%% format_msg({TimeStamp, {V3Hdr, ScopedPdu}, {Addr, Port}},
-%% Mib, Start, Stop) ->
-%% format_msg({TimeStamp, {V3Hdr, ScopedPdu}, Addr, Port},
-%% Mib, Start, Stop);
-%% format_msg({TimeStamp, {V3Hdr, ScopedPdu}, Addr, Port},
-%% Mib, Start, Stop) ->
-%% case timestamp_filter(TimeStamp, Start, Stop) of
-%% true ->
-%% case (catch snmp_pdus:dec_scoped_pdu(ScopedPdu)) of
-%% ScopedPDU when record(ScopedPDU, scopedPdu) ->
-%% Msg = #message{version = 'version-3',
-%% vsn_hdr = V3Hdr,
-%% data = ScopedPDU},
-%% f(ts2str(TimeStamp), Msg, Addr, Port, Mib);
-%% {'EXIT', Reason} ->
-%% format_tab("** error in log file at ~s from ~p:~w ~p\n\n",
-%% [ts2str(TimeStamp), ip(Addr), Port, Reason])
-%% end;
-%% false ->
-%% ignore
-%% end;
-%% format_msg({TimeStamp, Packet, {Addr, Port}}, Mib, Start, Stop) ->
-%% format_msg({TimeStamp, Packet, Addr, Port}, Mib, Start, Stop);
-%% format_msg({TimeStamp, Packet, Addr, Port}, Mib, Start, Stop) ->
-%% case timestamp_filter(TimeStamp, Start, Stop) of
-%% true ->
-%% case (catch snmp_pdus:dec_message(binary_to_list(Packet))) of
-%% Msg when record(Msg, message) ->
-%% f(ts2str(TimeStamp), Msg, Addr, Port, Mib);
-%% {'EXIT', Reason} ->
-%% format_tab("** error in log file ~p\n\n", [Reason])
-%% end;
-%% false ->
-%% ignore
-%% end;
-%% format_msg(_, _Mib, _Start, _Stop) ->
-%% format_tab("** unknown entry in log file\n\n", []).
+
+
+format_error(WhatStr, TimeStamp, AddrStr, throw, {error, Reason}) ->
+ {ok, Str} =
+ format_tab(
+ "** error (~s) in log file at ~s from ~s: "
+ "~n ~p\n\n",
+ [WhatStr, ts2str(TimeStamp), AddrStr, Reason]),
+ {error, Str};
+format_error(WhatStr, TimeStamp, AddrStr, T, E) ->
+ {ok, Str} =
+ format_tab(
+ "** error (~s) in log file at ~s from ~s: "
+ "~n ~w: ~p\n\n",
+ [WhatStr, ts2str(TimeStamp), AddrStr, T, E]),
+ {error, Str}.
+
+format_error(WhatStr, TimeStamp, SeqNo, AddrStr, throw, {error, Reason}) ->
+ {ok, Str} =
+ format_tab(
+ "** error (~s) in log file at ~s~s from ~s: "
+ "~n ~p\n\n",
+ [WhatStr, ts2str(TimeStamp), sn2str(SeqNo), AddrStr, Reason]),
+ {error, Str};
+format_error(WhatStr, TimeStamp, SeqNo, AddrStr, T, E) ->
+ {ok, Str} =
+ format_tab(
+ "** error (~s) in log file at ~s~s from ~s: "
+ "~n ~w, ~p\n\n",
+ [WhatStr, ts2str(TimeStamp), sn2str(SeqNo), AddrStr, T, E]),
+ {error, Str}.
+
f(TimeStamp, SeqNo,
#message{version = Vsn, vsn_hdr = VsnHdr, data = Data},
@@ -838,51 +924,21 @@ f(TimeStamp, SeqNo,
end,
format_tab(
"~w ~s - ~s [~s]~s ~w\n~s",
- [Class, AddrStr, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
-
-%% f(TimeStamp, SeqNo,
-%% #message{version = Vsn, vsn_hdr = VsnHdr, data = Data},
-%% Addr, Port, Mib) ->
-%% Str = format_pdu(Data, Mib),
-%% HdrStr = format_header(Vsn, VsnHdr),
-%% case get_type(Data) of
-%% trappdu ->
-%% f_trap(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
-%% 'snmpv2-trap' ->
-%% f_trap(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
-%% 'inform-request' ->
-%% f_inform(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
-%% 'get-response' ->
-%% f_response(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
-%% report ->
-%% f_report(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
-%% _ ->
-%% f_request(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port)
-%% end.
-
-%% f_request(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
-%% format_tab("request ~s:~w - ~s [~s]~s ~w\n~s",
-%% [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
-
-%% f_response(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
-%% format_tab("response ~s:~w - ~s [~s]~s ~w\n~s",
-%% [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
-
-%% f_report(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
-%% format_tab("report ~s:~w - ~s [~s]~s ~w\n~s",
-%% [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
+ [Class, AddrStr, HdrStr, TimeStamp, SeqNo, Vsn, Str]);
+f(TimeStamp, SeqNo, Msg, AddrStr, _Mib) ->
+ io:format("<ERROR> Unexpected data: "
+ "~n TimeStamp: ~s~s"
+ "~n Msg: ~p"
+ "~n AddrStr: ~p"
+ "~n", [TimeStamp, SeqNo, Msg, AddrStr]),
+ throw({error, 'invalid-message'}).
-%% f_trap(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
-%% format_tab("trap ~s:~w - ~s [~s]~s ~w\n~s",
-%% [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
+f(F, A) ->
+ lists:flatten(io_lib:format(F, A)).
-%% f_inform(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
-%% format_tab("inform ~s:~w - ~s [~s]~s ~w\n~s",
-%% [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
ipPort2Str(Ip, Port) ->
snmp_conf:mk_addr_string({Ip, Port}).
- %% io_lib:format("~s:~w", [ip(Ip), Port]).
%% Convert a timestamp 2-tupple to a printable string
%%
@@ -973,7 +1029,13 @@ format_pdu(#scopedPdu{contextName = Context, data = Pdu}, Mib) ->
io_lib:format("Context: \"~s\"\n~s",
[Context, snmp_misc:format_pdu(Pdu, Mib)]);
format_pdu(Pdu, Mib) ->
- snmp_misc:format_pdu(Pdu, Mib).
+ try snmp_misc:format_pdu(Pdu, Mib) of
+ Str ->
+ Str
+ catch
+ _:_ ->
+ throw({error, 'invalid-pdu'})
+ end.
get_type(#scopedPdu{data = Pdu}) ->
get_type(Pdu);
@@ -983,12 +1045,6 @@ get_type(#pdu{type = Type}) ->
Type.
-%% ip(Domain, Addr) ->
-%% snmp_conf:mk_addr_string(Domain, Addr).
-%% ip({A,B,C,D}) ->
-%% io_lib:format("~w.~w.~w.~w", [A,B,C,D]).
-
-
%% -------------------------------------------------------------------
%% Various utility functions
diff --git a/lib/snmp/src/misc/snmp_misc.erl b/lib/snmp/src/misc/snmp_misc.erl
index 1f847b7a29..39254503ac 100644
--- a/lib/snmp/src/misc/snmp_misc.erl
+++ b/lib/snmp/src/misc/snmp_misc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -64,8 +64,18 @@
strip_extension_from_filename/2,
str_xor/2,
time/3,
-
- verify_behaviour/2
+
+ verify_behaviour/2,
+
+ %% These are used both for debugging (verbosity printouts)
+ %% and other such "utility" operations.
+ format_timestamp/1, format_timestamp/2,
+ format_short_timestamp/1, format_short_timestamp/2,
+ format_long_timestamp/1, format_long_timestamp/2,
+ formated_timestamp/0,
+ formated_short_timestamp/0,
+ formated_long_timestamp/0
+
]).
@@ -112,6 +122,102 @@ now(sec) ->
erlang:monotonic_time(seconds).
+
+%% ---------------------------------------------------------------------------
+%% # formated_timstamp/0, formated_timstamp/1
+%% # format_short_timstamp/0, format_short_timstamp/1
+%% # format_long_timstamp/0, format_long_timstamp/1
+%%
+%% Create a formatted timestamp. Short means that it will not include
+%% the date in the formatted timestamp. Also it will only include millis.
+%% ---------------------------------------------------------------------------
+
+formated_timestamp() ->
+ formated_long_timestamp().
+
+formated_short_timestamp() ->
+ format_short_timestamp(os:timestamp()).
+
+formated_long_timestamp() ->
+ format_long_timestamp(os:timestamp()).
+
+
+%% ---------------------------------------------------------------------------
+%% # format_timstamp/1, format_timstamp/2
+%% # format_short_timstamp/1, format_short_timstamp/2
+%% # format_long_timstamp/1, format_long_timstamp/2
+%%
+%% Formats the provided timestamp. Short means that it will not include
+%% the date in the formatted timestamp.
+%% ---------------------------------------------------------------------------
+
+-spec format_timestamp(Now :: erlang:timestamp()) ->
+ string().
+
+format_timestamp(Now) ->
+ format_long_timestamp(Now).
+
+-spec format_short_timestamp(Now :: erlang:timestamp()) ->
+ string().
+
+format_short_timestamp(Now) ->
+ N2T = fun(N) -> calendar:now_to_local_time(N) end,
+ format_timestamp(short, Now, N2T).
+
+-spec format_long_timestamp(Now :: erlang:timestamp()) ->
+ string().
+
+format_long_timestamp(Now) ->
+ N2T = fun(N) -> calendar:now_to_local_time(N) end,
+ format_timestamp(long, Now, N2T).
+
+-spec format_timestamp(Now :: erlang:timestamp(),
+ N2T :: function()) ->
+ string().
+
+format_timestamp(Now, N2T) when is_tuple(Now) andalso is_function(N2T) ->
+ format_long_timestamp(Now, N2T).
+
+-spec format_short_timestamp(Now :: erlang:timestamp(),
+ N2T :: function()) ->
+ string().
+
+format_short_timestamp(Now, N2T) when is_tuple(Now) andalso is_function(N2T) ->
+ format_timestamp(short, Now, N2T).
+
+-spec format_long_timestamp(Now :: erlang:timestamp(),
+ N2T :: function()) ->
+ string().
+
+format_long_timestamp(Now, N2T) when is_tuple(Now) andalso is_function(N2T) ->
+ format_timestamp(long, Now, N2T).
+
+format_timestamp(Format, {_N1, _N2, N3} = Now, N2T) ->
+ {Date, Time} = N2T(Now),
+ do_format_timestamp(Format, Date, Time, N3).
+
+do_format_timestamp(short, _Date, Time, N3) ->
+ do_format_short_timestamp(Time, N3);
+do_format_timestamp(long, Date, Time, N3) ->
+ do_format_long_timestamp(Date, Time, N3).
+
+do_format_long_timestamp(Date, Time, N3) ->
+ {YYYY,MM,DD} = Date,
+ {Hour,Min,Sec} = Time,
+ FormatDate =
+ io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w.~.3.0w",
+ [YYYY, MM, DD, Hour, Min, Sec, N3 div 1000]),
+ lists:flatten(FormatDate).
+
+do_format_short_timestamp(Time, N3) ->
+ {Hour,Min,Sec} = Time,
+ FormatDate =
+ io_lib:format("~.2.0w:~.2.0w:~.2.0w.~.3.0w",
+ [Hour, Min, Sec, N3 div 1000]),
+ lists:flatten(FormatDate).
+
+
+
is_crypto_supported(Alg) ->
%% The 'try catch' handles the case when 'crypto' is
%% not present in the system (or not started).
diff --git a/lib/snmp/src/misc/snmp_verbosity.erl b/lib/snmp/src/misc/snmp_verbosity.erl
index edfb52a474..9b2676d048 100644
--- a/lib/snmp/src/misc/snmp_verbosity.erl
+++ b/lib/snmp/src/misc/snmp_verbosity.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -70,16 +70,7 @@ print2(_Verbosity,Format,Arguments) ->
timestamp() ->
- format_timestamp(os:timestamp()).
-
-format_timestamp({_N1, _N2, N3} = Now) ->
- {Date, Time} = calendar:now_to_datetime(Now),
- {YYYY,MM,DD} = Date,
- {Hour,Min,Sec} = Time,
- FormatDate =
- io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w ~w",
- [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
- lists:flatten(FormatDate).
+ snmp_misc:formated_timestamp().
process_args([], Acc) ->
lists:reverse(Acc);
@@ -155,7 +146,8 @@ image_of_sname(mgr) -> "MGR";
image_of_sname(mgr_misc) -> "MGR_MISC";
image_of_sname(undefined) -> "";
-image_of_sname(V) -> lists:flatten(io_lib:format("~p",[V])).
+image_of_sname(N) when is_list(N) -> N; % Used in testing
+image_of_sname(N) -> lists:flatten(io_lib:format("~p", [N])).
validate(info) -> info;
diff --git a/lib/snmp/test/modules.mk b/lib/snmp/test/modules.mk
index 0f54e67c65..8b6547f9a9 100644
--- a/lib/snmp/test/modules.mk
+++ b/lib/snmp/test/modules.mk
@@ -31,6 +31,7 @@ SUITE_MODULES = \
snmp_agent_mibs_test \
snmp_agent_nfilter_test \
snmp_agent_test \
+ snmp_agent_test_get \
snmp_agent_conf_test \
snmp_agent_test_lib \
snmp_manager_config_test \
diff --git a/lib/snmp/test/snmp_agent_test.erl b/lib/snmp/test/snmp_agent_test.erl
index 2ed2c4580c..71e3fa3b9a 100644
--- a/lib/snmp/test/snmp_agent_test.erl
+++ b/lib/snmp/test/snmp_agent_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1116,15 +1116,15 @@ init_ms(Config, Opts) when is_list(Config) ->
Opts1 = [MasterAgentVerbosity, MibsVerbosity, SymStoreVerbosity | Opts],
[{vsn, v1} | start_v1_agent(Config, Opts1)].
-init_size_check_mse(Config) when is_list(Config) ->
- MibStorage = {mib_storage, [{module, snmpa_mib_storage_ets}]},
- init_size_check_ms(Config, [MibStorage]).
+%% init_size_check_mse(Config) when is_list(Config) ->
+%% MibStorage = {mib_storage, [{module, snmpa_mib_storage_ets}]},
+%% init_size_check_ms(Config, [MibStorage]).
-init_size_check_msd(Config) when is_list(Config) ->
- AgentDbDir = ?GCONF(agent_db_dir, Config),
- MibStorage = {mib_storage, [{module, snmpa_mib_storage_dets},
- {options, [{dir, AgentDbDir}]}]},
- init_size_check_ms(Config, [MibStorage]).
+%% init_size_check_msd(Config) when is_list(Config) ->
+%% AgentDbDir = ?GCONF(agent_db_dir, Config),
+%% MibStorage = {mib_storage, [{module, snmpa_mib_storage_dets},
+%% {options, [{dir, AgentDbDir}]}]},
+%% init_size_check_ms(Config, [MibStorage]).
init_size_check_msm(Config) when is_list(Config) ->
?line AgentNode = ?GCONF(snmp_master, Config),
@@ -5146,12 +5146,21 @@ snmp_framework_mib_3(Config) when is_list(Config) ->
%% Req. SNMP-FRAMEWORK-MIB
snmp_framework_mib_test() ->
?line ["agentEngine"] = get_req(1, [[snmpEngineID,0]]),
+ T1 = snmp_misc:now(ms),
?line [EngineTime] = get_req(2, [[snmpEngineTime,0]]),
+ T2 = snmp_misc:now(ms),
?SLEEP(5000),
+ T3 = snmp_misc:now(ms),
?line [EngineTime2] = get_req(3, [[snmpEngineTime,0]]),
- ?DBG("snmp_framework_mib -> time(s): "
- "~n EngineTime 1 = ~p"
- "~n EngineTime 2 = ~p", [EngineTime, EngineTime2]),
+ T4 = snmp_misc:now(ms),
+ ?PRINT2("snmp_framework_mib -> time(s): "
+ "~n EngineTime 1: ~p"
+ "~n Time to acquire: ~w ms"
+ "~n EngineTime 2: ~p"
+ "~n Time to acquire: ~w ms"
+ "~n => (5 sec sleep between get(snmpEngineTime))"
+ "~n Total time to acquire: ~w ms",
+ [EngineTime, T2-T1, EngineTime2, T4-T3, T4-T1]),
if
(EngineTime+7) < EngineTime2 ->
?line ?FAIL({too_large_diff, EngineTime, EngineTime2});
@@ -5160,11 +5169,18 @@ snmp_framework_mib_test() ->
true ->
ok
end,
+ T5 = snmp_misc:now(ms),
?line case get_req(4, [[snmpEngineBoots,0]]) of
[Boots] when is_integer(Boots) ->
+ T6 = snmp_misc:now(ms),
+ ?PRINT2("snmp_framework_mib -> "
+ "~n boots: ~p"
+ "~n Time to acquire: ~w ms", [Boots, T6-T5]),
ok;
Else ->
- ?FAIL(Else)
+ ?PRINT2("snmp_framework_mib -> failed get proper boots:"
+ "~n ~p", [Else]),
+ ?FAIL({invalid_boots, Else})
end,
ok.
diff --git a/lib/snmp/test/snmp_agent_test_get.erl b/lib/snmp/test/snmp_agent_test_get.erl
new file mode 100644
index 0000000000..517c71507a
--- /dev/null
+++ b/lib/snmp/test/snmp_agent_test_get.erl
@@ -0,0 +1,58 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(snmp_agent_test_get).
+
+-behaviour(snmpa_get_mechanism).
+
+
+%%%-----------------------------------------------------------------
+%%% snmpa_get_mechanism exports
+%%%-----------------------------------------------------------------
+
+-export([
+ do_get/3, do_get/4,
+ do_get_next/3,
+ do_get_bulk/7
+ ]).
+
+
+
+do_get(UnsortedVarbinds, IsNotification, Extra) ->
+ snmpa_get:do_get(UnsortedVarbinds, IsNotification, Extra).
+
+
+
+do_get(MibView, UnsortedVarbinds, IsNotification, Extra) ->
+ snmpa_get:do_get(MibView, UnsortedVarbinds, IsNotification, Extra).
+
+
+
+do_get_next(MibView, UnsortedVBs, Extra) ->
+ snmpa_get:do_get_next(MibView, UnsortedVBs, Extra).
+
+
+
+
+do_get_bulk(MibView, NonRepeaters, MaxRepetitions,
+ PduMS, Varbinds, GbMaxVBs, Extra) ->
+ snmpa_get:do_get_bulk(MibView, NonRepeaters, MaxRepetitions,
+ PduMS, Varbinds, GbMaxVBs,
+ Extra).
diff --git a/lib/snmp/test/snmp_agent_test_lib.erl b/lib/snmp/test/snmp_agent_test_lib.erl
index 66211d7105..6defdadb5a 100644
--- a/lib/snmp/test/snmp_agent_test_lib.erl
+++ b/lib/snmp/test/snmp_agent_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -358,22 +358,22 @@ run(Mod, Func, Args, Opts) ->
"~n StdM: ~p",
[M,Vsn,Dir,User,SecLevel,EngineID,CtxEngineID,Community,StdM]),
case snmp_test_mgr:start([%% {agent, snmp_test_lib:hostname()},
- {packet_server_debug,true},
- {debug,true},
- {agent, get(master_host)},
- {ipfamily, get(ipfamily)},
- {agent_udp, 4000},
- {trap_udp, 5000},
- {recbuf,65535},
+ {packet_server_debug, true},
+ {debug, true},
+ {agent, get(master_host)},
+ {ipfamily, get(ipfamily)},
+ {agent_udp, 4000},
+ {trap_udp, 5000},
+ {recbuf, 65535},
quiet,
Vsn,
- {community, Community},
- {user, User},
- {sec_level, SecLevel},
- {engine_id, EngineID},
- {context_engine_id, CtxEngineID},
- {dir, Dir},
- {mibs, mibs(StdM, M)}]) of
+ {community, Community},
+ {user, User},
+ {sec_level, SecLevel},
+ {engine_id, EngineID},
+ {context_engine_id, CtxEngineID},
+ {dir, Dir},
+ {mibs, mibs(StdM, M)}]) of
{ok, _Pid} ->
case (catch apply(Mod, Func, Args)) of
{'EXIT', Reason} ->
@@ -383,10 +383,18 @@ run(Mod, Func, Args, Opts) ->
catch snmp_test_mgr:stop(),
Res
end;
+
+ {error, Reason} ->
+ ?EPRINT2("Failed starting (test) manager: "
+ "~n ~p", [Reason]),
+ catch snmp_test_mgr:stop(),
+ ?line ?FAIL({mgr_start_error, Reason});
+
Err ->
- io:format("Error starting manager: ~p\n", [Err]),
+ ?EPRINT2("Failed starting (test) manager: "
+ "~n ~p", [Err]),
catch snmp_test_mgr:stop(),
- ?line ?FAIL({mgr_start, Err})
+ ?line ?FAIL({mgr_start_failure, Err})
end.
@@ -445,6 +453,7 @@ start_agent(Config, Vsns, Opts) ->
[{versions, Vsns},
{agent_type, master},
{agent_verbosity, trace},
+ {get_mechanism, snmp_agent_test_get},
{db_dir, AgentDbDir},
{audit_trail_log, [{type, read_write},
{dir, AgentLogDir},
@@ -463,20 +472,24 @@ start_agent(Config, Vsns, Opts) ->
process_flag(trap_exit,true),
+ ?PRINT2("start_agent -> try start snmp app supervisor", []),
{ok, AppSup} = snmp_app_sup:start_link(),
unlink(AppSup),
?DBG("start_agent -> snmp app supervisor: ~p", [AppSup]),
- ?DBG("start_agent -> start master agent",[]),
+ ?PRINT2("start_agent -> try start master agent",[]),
?line Sup = start_sup(Env),
-
- ?DBG("start_agent -> unlink from supervisor", []),
?line unlink(Sup),
+ ?DBG("start_agent -> snmp supervisor: ~p", [Sup]),
+
+ ?PRINT2("start_agent -> try (rpc) start sub agent on ~p", [SaNode]),
?line SaDir = ?config(sa_dir, Config),
- ?DBG("start_agent -> (rpc) start sub on ~p", [SaNode]),
?line {ok, Sub} = start_sub_sup(SaNode, SaDir),
- ?DBG("start_agent -> done",[]),
- ?line [{snmp_sup, {Sup, self()}}, {snmp_sub, Sub} | Config].
+ ?DBG("start_agent -> done", []),
+
+ ?line [{snmp_app_sup, AppSup},
+ {snmp_sup, {Sup, self()}},
+ {snmp_sub, Sub} | Config].
app_agent_env_init(Env0, Opts) ->
@@ -669,35 +682,52 @@ merge_agent_options([{Key, _Value} = Opt|Opts], Options) ->
stop_agent(Config) when is_list(Config) ->
- ?LOG("stop_agent -> entry with"
- "~n Config: ~p",[Config]),
-
- {Sup, Par} = ?config(snmp_sup, Config),
- ?DBG("stop_agent -> attempt to stop (sup) ~p"
- "~n Sup: ~p"
- "~n Par: ~p",
- [Sup,
- (catch process_info(Sup)),
- (catch process_info(Par))]),
-
- _Info = agent_info(Sup),
- ?DBG("stop_agent -> Agent info: "
- "~n ~p", [_Info]),
-
- stop_sup(Sup, Par),
-
- {Sup2, Par2} = ?config(snmp_sub, Config),
- ?DBG("stop_agent -> attempt to stop (sub) ~p"
- "~n Sup2: ~p"
- "~n Par2: ~p",
- [Sup2,
- (catch process_info(Sup2)),
- (catch process_info(Par2))]),
- stop_sup(Sup2, Par2),
-
- ?DBG("stop_agent -> done - now cleanup config", []),
- C1 = lists:keydelete(snmp_sup, 1, Config),
- lists:keydelete(snmp_sub, 1, C1).
+ ?PRINT2("stop_agent -> entry with"
+ "~n Config: ~p",[Config]),
+
+
+ %% Stop the sub-agent (the agent supervisor)
+ {SubSup, SubPar} = ?config(snmp_sub, Config),
+ ?PRINT2("stop_agent -> attempt to stop sub agent (~p)"
+ "~n Sub Sup info: "
+ "~n ~p"
+ "~n Sub Par info: "
+ "~n ~p",
+ [SubSup,
+ (catch process_info(SubSup)),
+ (catch process_info(SubPar))]),
+ stop_sup(SubSup, SubPar),
+ Config2 = lists:keydelete(snmp_sub, 1, Config),
+
+
+ %% Stop the master-agent (the top agent supervisor)
+ {MasterSup, MasterPar} = ?config(snmp_sup, Config),
+ ?PRINT2("stop_agent -> attempt to stop master agent (~p)"
+ "~n Master Sup: "
+ "~n ~p"
+ "~n Master Par: "
+ "~n ~p"
+ "~n Agent Info: "
+ "~n ~p",
+ [MasterSup,
+ (catch process_info(MasterSup)),
+ (catch process_info(MasterPar)),
+ agent_info(MasterSup)]),
+ stop_sup(MasterSup, MasterPar),
+ Config3 = lists:keydelete(snmp_sup, 1, Config2),
+
+
+ %% Stop the top supervisor (of the snmp app)
+ AppSup = ?config(snmp_app_sup, Config),
+ ?PRINT2("stop_agent -> attempt to app sup ~p"
+ "~n App Sup: ~p",
+ [AppSup,
+ (catch process_info(AppSup))]),
+ Config4 = lists:keydelete(snmp_app_sup, 1, Config3),
+
+
+ ?PRINT2("stop_agent -> done", []),
+ Config4.
start_sup(Env) ->
@@ -727,7 +757,6 @@ stop_sup(Pid, _) ->
?LOG("stop_sup -> attempt to stop ~p", [Pid]),
Ref = erlang:monitor(process, Pid),
?LOG("stop_sup -> Ref: ~p", [Ref]),
- %% Pid ! {'EXIT', Parent, shutdown}, % usch
exit(Pid, kill),
await_stopped(Pid, Ref).
@@ -863,13 +892,15 @@ expect(Mod, Line, Type, Enterp, Generic, Specific, ExpVBs) ->
expect2(Mod, Line, Fun).
expect2(Mod, Line, F) ->
- io:format("EXPECT for ~w:~w~n", [Mod, Line]),
+ io_format_expect("for ~w:~w", [Mod, Line]),
case F() of
{error, Reason} ->
- io:format("EXPECT failed at ~w:~w => ~n~p~n", [Mod, Line, Reason]),
+ io_format_expect("failed at ~w:~w => "
+ "~n ~p", [Mod, Line, Reason]),
throw({error, {expect, Mod, Line, Reason}});
Else ->
- io:format("EXPECT result for ~w:~w => ~n~p~n", [Mod, Line, Else]),
+ io_format_expect("result for ~w:~w => "
+ "~n ~p", [Mod, Line, Else]),
Else
end.
@@ -898,20 +929,27 @@ receive_trap(To) ->
end.
+io_format_expect(F) ->
+ io_format_expect(F, []).
+
+io_format_expect(F, A) ->
+ ?PRINT2("EXPECT " ++ F, A).
+
+
do_expect(Expect) when is_atom(Expect) ->
do_expect({Expect, get_timeout()});
do_expect({any_pdu, To})
when is_integer(To) orelse (To =:= infinity) ->
- io:format("EXPECT any PDU~n", []),
+ io_format_expect("any PDU"),
receive_pdu(To);
do_expect({any_trap, To}) ->
- io:format("EXPECT any TRAP within ~w~n", [To]),
+ io_format_expect("any TRAP within ~w", [To]),
receive_trap(To);
do_expect({timeout, To}) ->
- io:format("EXPECT nothing within ~w~n", [To]),
+ io_format_expect("nothing within ~w", [To]),
receive
X ->
{error, {unexpected, X}}
@@ -923,16 +961,16 @@ do_expect({timeout, To}) ->
do_expect({Err, To})
when (is_atom(Err) andalso
((is_integer(To) andalso To > 0) orelse (To =:= infinity))) ->
- io:format("EXPECT error ~w within ~w~n", [Err, To]),
+ io_format_expect("error ~w within ~w", [Err, To]),
do_expect({{error, Err}, To});
do_expect({error, Err}) when is_atom(Err) ->
Check = fun(_, R) -> R end,
- io:format("EXPECT error ~w~n", [Err]),
+ io_format_expect("error ~w", [Err]),
do_expect2(Check, any, Err, any, any, get_timeout());
do_expect({{error, Err}, To}) ->
Check = fun(_, R) -> R end,
- io:format("EXPECT error ~w within ~w~n", [Err, To]),
+ io_format_expect("error ~w within ~w", [Err, To]),
do_expect2(Check, any, Err, any, any, To);
%% exp_varbinds() -> [exp_varbind()]
@@ -942,25 +980,23 @@ do_expect({{error, Err}, To}) ->
%% ExpVBs -> exp_varbinds() | {VbsCondition, exp_varbinds()}
do_expect(ExpVBs) ->
Check = fun(_, R) -> R end,
- io:format("EXPECT 'get-response'"
- "~n with"
- "~n Varbinds: ~p~n", [ExpVBs]),
+ io_format_expect("'get-response'"
+ "~n with"
+ "~n Varbinds: ~p", [ExpVBs]),
do_expect2(Check, 'get-response', noError, 0, ExpVBs, get_timeout()).
do_expect(v2trap, ExpVBs) ->
Check = fun(_, R) -> R end,
- io:format("EXPECT 'snmpv2-trap'"
- "~n with"
- "~n Varbinds: ~p~n", [ExpVBs]),
+ io_format_expect("'snmpv2-trap' with"
+ "~n Varbinds: ~p", [ExpVBs]),
do_expect2(Check, 'snmpv2-trap', noError, 0, ExpVBs, get_timeout());
do_expect(report, ExpVBs) ->
Check = fun(_, R) -> R end,
- io:format("EXPECT 'report'"
- "~n with"
- "~n Varbinds: ~p~n", [ExpVBs]),
+ io_format_expect("'report' with"
+ "~n Varbinds: ~p", [ExpVBs]),
do_expect2(Check, 'report', noError, 0, ExpVBs, get_timeout());
@@ -969,9 +1005,8 @@ do_expect(inform, ExpVBs) ->
do_expect({inform, false}, ExpVBs) ->
Check = fun(_, R) -> R end,
- io:format("EXPECT 'inform-request' (false)"
- "~n with"
- "~n Varbinds: ~p~n", [ExpVBs]),
+ io_format_expect("'inform-request' (false) with"
+ "~n Varbinds: ~p", [ExpVBs]),
do_expect2(Check, 'inform-request', noError, 0, ExpVBs, get_timeout());
do_expect({inform, true}, ExpVBs) ->
@@ -985,9 +1020,8 @@ do_expect({inform, true}, ExpVBs) ->
(_, Err) ->
Err
end,
- io:format("EXPECT 'inform-request' (true)"
- "~n with"
- "~n Varbinds: ~p~n", [ExpVBs]),
+ io_format_expect("'inform-request' (true) with"
+ "~n Varbinds: ~p", [ExpVBs]),
do_expect2(Check, 'inform-request', noError, 0, ExpVBs, get_timeout());
do_expect({inform, {error, EStat, EIdx}}, ExpVBs)
@@ -1002,11 +1036,10 @@ do_expect({inform, {error, EStat, EIdx}}, ExpVBs)
(_, Err) ->
Err
end,
- io:format("EXPECT 'inform-request' (error)"
- "~n with"
- "~n Error Status: ~p"
- "~n Error Index: ~p"
- "~n Varbinds: ~p~n", [EStat, EIdx, ExpVBs]),
+ io_format_expect("'inform-request' (error) with"
+ "~n Error Status: ~p"
+ "~n Error Index: ~p"
+ "~n Varbinds: ~p", [EStat, EIdx, ExpVBs]),
do_expect2(Check, 'inform-request', noError, 0, ExpVBs, get_timeout()).
@@ -1017,26 +1050,23 @@ do_expect(Err, Idx, ExpVBs, To)
when is_atom(Err) andalso
(is_integer(Idx) orelse is_list(Idx) orelse (Idx == any)) ->
Check = fun(_, R) -> R end,
- io:format("EXPECT 'get-response'"
- "~n with"
- "~n Error: ~p"
- "~n Index: ~p"
- "~n Varbinds: ~p"
- "~n within ~w~n", [Err, Idx, ExpVBs, To]),
+ io_format_expect("'get-response' withing ~w ms with"
+ "~n Error: ~p"
+ "~n Index: ~p"
+ "~n Varbinds: ~p", [To, Err, Idx, ExpVBs]),
do_expect2(Check, 'get-response', Err, Idx, ExpVBs, To).
do_expect(Type, Enterp, Generic, Specific, ExpVBs) ->
- do_expect(Type, Enterp, Generic, Specific, ExpVBs, 3500).
+ do_expect(Type, Enterp, Generic, Specific, ExpVBs, get_timeout()).
do_expect(trap, Enterp, Generic, Specific, ExpVBs, To) ->
- io:format("EXPECT trap"
- "~n with"
- "~n Enterp: ~w"
- "~n Generic: ~w"
- "~n Specific: ~w"
- "~n Varbinds: ~w"
- "~n within ~w~n", [Enterp, Generic, Specific, ExpVBs, To]),
+ io_format_expect("trap within ~w ms with"
+ "~n Enterp: ~w"
+ "~n Generic: ~w"
+ "~n Specific: ~w"
+ "~n Varbinds: ~w",
+ [To, Enterp, Generic, Specific, ExpVBs]),
PureE = purify_oid(Enterp),
case receive_trap(To) of
#trappdu{enterprise = PureE,
@@ -1071,46 +1101,46 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To)
#pdu{type = Type,
error_status = Err,
error_index = Idx} when ExpVBs =:= any ->
- io:format("EXPECT received expected pdu (1)~n", []),
+ io_format_expect("received expected pdu (1)"),
ok;
#pdu{type = Type,
request_id = ReqId,
error_status = Err2,
error_index = Idx} when ExpVBs =:= any ->
- io:format("EXPECT received expected pdu with "
- "unexpected error status (2): "
- "~n Error Status: ~p~n", [Err2]),
+ io_format_expect("received expected pdu with "
+ "unexpected error status (2): "
+ "~n Error Status: ~p", [Err2]),
{error, {unexpected_error_status, Err, Err2, ReqId}};
#pdu{error_status = Err} when (Type =:= any) andalso
(Idx =:= any) andalso
(ExpVBs =:= any) ->
- io:format("EXPECT received expected pdu (3)~n", []),
+ io_format_expect("received expected pdu (3)"),
ok;
#pdu{request_id = ReqId,
error_status = Err2} when (Type =:= any) andalso
(Idx =:= any) andalso
(ExpVBs =:= any) ->
- io:format("EXPECT received expected pdu with "
- "unexpected error status (4): "
- "~n Error Status: ~p~n", [Err2]),
+ io_format_expect("received expected pdu with "
+ "unexpected error status (4): "
+ "~n Error Status: ~p", [Err2]),
{error, {unexpected_error_status, Err, Err2, ReqId}};
#pdu{type = Type,
error_status = Err} when (Idx =:= any) andalso
(ExpVBs =:= any) ->
- io:format("EXPECT received expected pdu (5)~n", []),
+ io_format_expect("received expected pdu (5)", []),
ok;
#pdu{type = Type,
request_id = ReqId,
error_status = Err2} when (Idx =:= any) andalso
(ExpVBs =:= any) ->
- io:format("EXPECT received expected pdu with "
- "unexpected error status (6): "
- "~n Error Status: ~p~n", [Err2]),
+ io_format_expect("received expected pdu with "
+ "unexpected error status (6): "
+ "~n Error Status: ~p", [Err2]),
{error, {unexpected_error_status, Err, Err2, ReqId}};
#pdu{type = Type,
@@ -1119,13 +1149,13 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To)
error_index = EI} when is_list(Idx) andalso (ExpVBs =:= any) ->
case lists:member(EI, Idx) of
true ->
- io:format("EXPECT received expected pdu with "
- "expected error index (7)~n", []),
+ io_format_expect("received expected pdu with "
+ "expected error index (7)"),
ok;
false ->
- io:format("EXPECT received expected pdu with "
- "unexpected error index (8): "
- "~n Error Index: ~p~n", [EI]),
+ io_format_expect("received expected pdu with "
+ "unexpected error index (8): "
+ "~n Error Index: ~p", [EI]),
{error, {unexpected_error_index, EI, Idx, ReqId}}
end;
@@ -1135,15 +1165,15 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To)
error_index = EI} when is_list(Idx) andalso (ExpVBs =:= any) ->
case lists:member(EI, Idx) of
true ->
- io:format("EXPECT received expected pdu with "
- "unexpected error status (9): "
- "~n Error Status: ~p~n", [Err2]),
+ io_format_expect("received expected pdu with "
+ "unexpected error status (9): "
+ "~n Error Status: ~p", [Err2]),
{error, {unexpected_error_status, Err, Err2, ReqId}};
false ->
- io:format("EXPECT received expected pdu with "
- "unexpected error (10): "
- "~n Error Status: ~p"
- "~n Error index: ~p~n", [Err2, EI]),
+ io_format_expect("received expected pdu with "
+ "unexpected error (10): "
+ "~n Error Status: ~p"
+ "~n Error index: ~p", [Err2, EI]),
{error, {unexpected_error, {Err, Idx}, {Err2, EI}, ReqId}}
end;
@@ -1151,12 +1181,12 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To)
request_id = ReqId,
error_status = Err2,
error_index = Idx2} when ExpVBs =:= any ->
- io:format("EXPECT received unexpected pdu with (11) "
- "~n Type: ~p"
- "~n ReqId: ~p"
- "~n Errot status: ~p"
- "~n Error index: ~p"
- "~n", [Type2, ReqId, Err2, Idx2]),
+ io_format_expect("received unexpected pdu with (11) "
+ "~n Type: ~p"
+ "~n ReqId: ~p"
+ "~n Errot status: ~p"
+ "~n Error index: ~p",
+ [Type2, ReqId, Err2, Idx2]),
{error,
{unexpected_pdu,
{Type, Err, Idx}, {Type2, Err2, Idx2}, ReqId}};
@@ -1165,26 +1195,26 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To)
error_status = Err,
error_index = Idx,
varbinds = VBs} = PDU ->
- io:format("EXPECT received pdu (12): "
- "~n [exp] Type: ~p"
- "~n [exp] Error Status: ~p"
- "~n [exp] Error Index: ~p"
- "~n VBs: ~p"
- "~nwhen"
- "~n ExpVBs: ~p"
- "~n", [Type, Err, Idx, VBs, ExpVBs]),
+ io_format_expect("received pdu (12): "
+ "~n [exp] Type: ~p"
+ "~n [exp] Error Status: ~p"
+ "~n [exp] Error Index: ~p"
+ "~n VBs: ~p"
+ "~nwhen"
+ "~n ExpVBs: ~p",
+ [Type, Err, Idx, VBs, ExpVBs]),
Check(PDU, check_vbs(purify_oids(ExpVBs), VBs));
#pdu{type = Type,
error_status = Err,
varbinds = VBs} = PDU when Idx =:= any ->
- io:format("EXPECT received pdu (13): "
- "~n [exp] Type: ~p"
- "~n [exp] Error Status: ~p"
- "~n VBs: ~p"
- "~nwhen"
- "~n ExpVBs: ~p"
- "~n", [Type, Err, VBs, ExpVBs]),
+ io_format_expect("received pdu (13): "
+ "~n [exp] Type: ~p"
+ "~n [exp] Error Status: ~p"
+ "~n VBs: ~p"
+ "~nwhen"
+ "~n ExpVBs: ~p",
+ [Type, Err, VBs, ExpVBs]),
Check(PDU, check_vbs(purify_oids(ExpVBs), VBs));
#pdu{type = Type,
@@ -1192,15 +1222,15 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To)
error_status = Err,
error_index = EI,
varbinds = VBs} = PDU when is_list(Idx) ->
- io:format("EXPECT received pdu (14): "
- "~n [exp] Type: ~p"
- "~n ReqId: ~p"
- "~n [exp] Error Status: ~p"
- "~n [exp] Error Index: ~p"
- "~n VBs: ~p"
- "~nwhen"
- "~n ExpVBs: ~p"
- "~n", [Type, ReqId, Err, EI, VBs, ExpVBs]),
+ io_format_expect("received pdu (14): "
+ "~n [exp] Type: ~p"
+ "~n ReqId: ~p"
+ "~n [exp] Error Status: ~p"
+ "~n [exp] Error Index: ~p"
+ "~n VBs: ~p"
+ "~nwhen"
+ "~n ExpVBs: ~p",
+ [Type, ReqId, Err, EI, VBs, ExpVBs]),
PureVBs = purify_oids(ExpVBs),
case lists:member(EI, Idx) of
true ->
@@ -1214,13 +1244,13 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To)
error_status = Err2,
error_index = Idx2,
varbinds = VBs2} ->
- io:format("EXPECT received unexpected pdu with (15) "
- "~n Type: ~p"
- "~n ReqId: ~p"
- "~n Errot status: ~p"
- "~n Error index: ~p"
- "~n Varbinds: ~p"
- "~n", [Type2, ReqId, Err2, Idx2, VBs2]),
+ io_format_expect("received unexpected pdu with (15) "
+ "~n Type: ~p"
+ "~n ReqId: ~p"
+ "~n Errot status: ~p"
+ "~n Error index: ~p"
+ "~n Varbinds: ~p",
+ [Type2, ReqId, Err2, Idx2, VBs2]),
{error,
{unexpected_pdu,
{Type, Err, Idx, purify_oids(ExpVBs)},
@@ -1228,9 +1258,8 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To)
ReqId}};
Error ->
- io:format("EXPECT received error (16): "
- "~n Error: ~p"
- "~n", [Error]),
+ io_format_expect("received error (16): "
+ "~n Error: ~p", [Error]),
Error
end.
diff --git a/lib/snmp/test/snmp_compiler_test.erl b/lib/snmp/test/snmp_compiler_test.erl
index 2b6bba4ee6..a28f925a22 100644
--- a/lib/snmp/test/snmp_compiler_test.erl
+++ b/lib/snmp/test/snmp_compiler_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -58,7 +58,8 @@
otp_10799/1,
otp_10808/1,
otp_14145/1,
- otp_13014/1
+ otp_13014/1,
+ otp_14196/1
]).
%%----------------------------------------------------------------------
@@ -138,7 +139,7 @@ all() ->
groups() ->
[{tickets, [],
[otp_6150, otp_8574, otp_8595, otp_10799, otp_10808, otp_14145,
- otp_13014]}].
+ otp_13014, otp_14196]}].
init_per_group(_GroupName, Config) ->
Config.
@@ -225,22 +226,20 @@ agent_capabilities(Config) when is_list(Config) ->
put(tname,agent_capabilities),
p("starting with Config: ~p~n", [Config]),
- SnmpPrivDir = code:priv_dir(snmp),
+ SnmpPrivDir = which_priv_dir(snmp),
SnmpMibsDir = join(SnmpPrivDir, "mibs"),
- OtpMibsPrivDir = code:priv_dir(otp_mibs),
- OtpMibsMibsDir = join(OtpMibsPrivDir, "mibs"),
Dir = ?config(mib_dir, Config),
AcMib = join(Dir,"AC-TEST-MIB.mib"),
?line {ok, MibFile1} = snmpc:compile(AcMib, [options,
version,
- {i, [SnmpMibsDir, OtpMibsMibsDir]},
+ {i, [SnmpMibsDir]},
{outdir, Dir},
{verbosity, trace}]),
?line {ok, Mib1} = snmp_misc:read_mib(MibFile1),
?line {ok, MibFile2} = snmpc:compile(AcMib, [options,
version,
agent_capabilities,
- {i, [SnmpMibsDir, OtpMibsMibsDir]},
+ {i, [SnmpMibsDir]},
{outdir, Dir},
{verbosity, trace}]),
?line {ok, Mib2} = snmp_misc:read_mib(MibFile2),
@@ -268,28 +267,26 @@ module_compliance(Config) when is_list(Config) ->
put(tname,module_compliance),
p("starting with Config: ~p~n", [Config]),
- SnmpPrivDir = code:priv_dir(snmp),
- SnmpMibsDir = join(SnmpPrivDir, "mibs"),
- OtpMibsPrivDir = code:priv_dir(otp_mibs),
- OtpMibsMibsDir = join(OtpMibsPrivDir, "mibs"),
- Dir = ?config(mib_dir, Config),
- AcMib = join(Dir,"MC-TEST-MIB.mib"),
+ SnmpPrivDir = which_priv_dir(snmp),
+ SnmpMibsDir = join(SnmpPrivDir, "mibs"),
+ Dir = ?config(mib_dir, Config),
+ AcMib = join(Dir,"MC-TEST-MIB.mib"),
?line {ok, MibFile1} = snmpc:compile(AcMib, [options,
version,
- {i, [SnmpMibsDir, OtpMibsMibsDir]},
+ {i, [SnmpMibsDir]},
{outdir, Dir},
{verbosity, trace}]),
?line {ok, Mib1} = snmp_misc:read_mib(MibFile1),
?line {ok, MibFile2} = snmpc:compile(AcMib, [options,
version,
module_compliance,
- {i, [SnmpMibsDir, OtpMibsMibsDir]},
+ {i, [SnmpMibsDir]},
{outdir, Dir},
{verbosity, trace}]),
?line {ok, Mib2} = snmp_misc:read_mib(MibFile2),
MEDiff = Mib2#mib.mes -- Mib1#mib.mes,
%% This is a rather pathetic test, but it is somthing...
- io:format("agent_capabilities -> "
+ io:format("module_compliance -> "
"~n MEDiff: ~p"
"~n Mib1: ~p"
"~n Mib2: ~p"
@@ -489,6 +486,22 @@ otp_13014(Config) when is_list(Config) ->
TableInfo,
ok.
+%%======================================================================
+
+otp_14196(suite) ->
+ [];
+otp_14196(Config) when is_list(Config) ->
+ put(tname, otp14196),
+ p("starting with Config: ~p~n", [Config]),
+
+ Dir = ?config(case_top_dir, Config),
+ MibDir = ?config(mib_dir, Config),
+ MibFile = join(MibDir, "OTP14196-MIB.mib"),
+ ?line {ok, Mib} =
+ snmpc:compile(MibFile, [{outdir, Dir}, {verbosity, trace}]),
+ p("Mib: ~n~p~n", [Mib]),
+ ok.
+
%%======================================================================
@@ -714,6 +727,15 @@ check_desc(Desc1, Desc2) ->
exit({'description not equal', Desc1, Desc2}).
+which_priv_dir(App) ->
+ case code:priv_dir(App) of
+ Dir when is_list(Dir) ->
+ Dir;
+ {error, Reason} ->
+ exit({App, priv_dir_not_found, Reason})
+ end.
+
+
%% join(Comp) ->
%% filename:join(Comp).
diff --git a/lib/snmp/test/snmp_manager_test.erl b/lib/snmp/test/snmp_manager_test.erl
index 6ced55f0cc..5b0ebf8647 100644
--- a/lib/snmp/test/snmp_manager_test.erl
+++ b/lib/snmp/test/snmp_manager_test.erl
@@ -204,10 +204,15 @@ init_per_testcase(Case, Config) when is_list(Config) ->
Result =
case lists:member(Case, DeprecatedApiCases) of
true ->
- %% ?SKIP(api_no_longer_supported);
{skip, api_no_longer_supported};
false ->
- init_per_testcase2(Case, Config)
+ try init_per_testcase2(Case, Config)
+ catch
+ C:{skip, _} = E:_ when ((C =:= throw) orelse (C =:= exit)) ->
+ E;
+ C:E:_ when ((C =:= throw) orelse (C =:= exit)) ->
+ {skip, {catched, C, E}}
+ end
end,
p(Case, "init_per_testcase end when"
"~n Nodes: ~p"
@@ -326,9 +331,25 @@ init_per_testcase3(Case, Config) ->
true ->
Config
end,
+ %% We don't need to try catch this (init_agent)
+ %% since we have a try catch "higher up"...
Conf2 = init_agent(Conf1),
- Conf3 = init_manager(AutoInform, Conf2),
- Conf4 = init_mgr_user(Conf3),
+ Conf3 = try init_manager(AutoInform, Conf2)
+ catch AC:AE:_ ->
+ %% Ouch we need to clean up:
+ %% The init_agent starts an agent node!
+ init_per_testcase_fail_agent_cleanup(Conf2),
+ throw({skip, {manager_init_failed, AC, AE}})
+ end,
+ Conf4 = try init_mgr_user(Conf3)
+ catch MC:ME:_ ->
+ %% Ouch we need to clean up:
+ %% The init_agent starts an agent node!
+ %% The init_magager starts an manager node!
+ init_per_testcase_fail_manager_cleanup(Conf3),
+ init_per_testcase_fail_agent_cleanup(Conf3),
+ throw({skip, {manager_user_init_failed, MC, ME}})
+ end,
case lists:member(Case, ApiCases02 ++ ApiCases03) of
true ->
init_mgr_user_data2(Conf4);
@@ -339,6 +360,12 @@ init_per_testcase3(Case, Config) ->
Config
end.
+init_per_testcase_fail_manager_cleanup(Conf) ->
+ (catch fin_manager(Conf)).
+
+init_per_testcase_fail_agent_cleanup(Conf) ->
+ (catch fin_agent(Conf)).
+
end_per_testcase(Case, Config) when is_list(Config) ->
p(Case, "end_per_testcase begin when"
"~n Nodes: ~p~n~n", [erlang:nodes()]),
@@ -993,18 +1020,40 @@ notify_started02(Config) when is_list(Config) ->
{config, [{verbosity, log}, {dir, ConfDir}, {db_dir, DbDir}]}],
p("start snmpm client process"),
- Pid1 = ns02_loop1_start(),
+ NumIterations = 5,
+ Pid1 = ns02_client_start(NumIterations),
+
+ p("start snmpm ctrl (starter) process"),
+ Pid2 = ns02_ctrl_start(Opts, NumIterations),
+
+ %% On a reasonably fast machine, one iteration takes approx 4 seconds.
+ %% We measure the first iteration, and then we wait for the remaining
+ %% ones (4 in this case).
+ ApproxStartTime =
+ case ns02_client_await_approx_runtime(Pid1) of
+ {ok, T} ->
+ T;
+ {error, Reason} ->
+ %% Attempt cleanup just in case
+ exit(Pid1, kill),
+ exit(Pid2, kill),
+ ?FAIL(Reason);
+ {skip, Reason} ->
+ %% Attempt cleanup just in case
+ exit(Pid1, kill),
+ exit(Pid2, kill),
+ ?SKIP(Reason)
+ end,
- p("start snmpm starter process"),
- Pid2 = ns02_loop2_start(Opts),
-
- p("await snmpm client process exit"),
+ p("await snmpm client process exit (max ~p+10000 msec)", [ApproxStartTime]),
receive
{'EXIT', Pid1, normal} ->
ok;
{'EXIT', Pid1, Reason1} ->
- ?FAIL(Reason1)
- after 25000 ->
+ ?FAIL({client, Reason1})
+ after ApproxStartTime + 10000 ->
+ exit(Pid1, kill),
+ exit(Pid2, kill),
?FAIL(timeout)
end,
@@ -1013,8 +1062,9 @@ notify_started02(Config) when is_list(Config) ->
{'EXIT', Pid2, normal} ->
ok;
{'EXIT', Pid2, Reason2} ->
- ?FAIL(Reason2)
+ ?FAIL({ctrl, Reason2})
after 5000 ->
+ exit(Pid2, kill),
?FAIL(timeout)
end,
@@ -1022,26 +1072,63 @@ notify_started02(Config) when is_list(Config) ->
ok.
-ns02_loop1_start() ->
- spawn_link(fun() -> ns02_loop1() end).
+ns02_client_start(N) ->
+ Self = self(),
+ spawn_link(fun() -> ns02_client(Self, N) end).
+
+ns02_client_await_approx_runtime(Pid) ->
+ receive
+ {?MODULE, client_time, Time} ->
+ {ok, Time};
+ {'EXIT', Pid, Reason} ->
+ p("client (~p) failed: "
+ "~n ~p", [Pid, Reason]),
+ {error, Reason}
+
+ after 15000 ->
+ %% Either something is *really* wrong or this machine
+ %% is dog slow. Either way, this is a skip-reason...
+ {skip, approx_runtime_timeout}
+ end.
+
-ns02_loop1() ->
- put(tname,ns02_loop1),
+ns02_client(Parent, N) when is_pid(Parent) ->
+ put(tname, ns02_client),
p("starting"),
- ns02_loop1(dummy, snmpm:notify_started(?NS_TIMEOUT), 5).
+ ns02_client_loop(Parent,
+ dummy, snmpm:notify_started(?NS_TIMEOUT),
+ snmp_misc:now(ms), undefined,
+ N).
-ns02_loop1(_Ref, _Pid, 0) ->
- p("done"),
+ns02_client_loop(_Parent, _Ref, _Pid, _Begin, _End, 0) ->
+ %% p("loop -> done"),
exit(normal);
-ns02_loop1(Ref, Pid, N) ->
- p("entry when"
- "~n Ref: ~p"
- "~n Pid: ~p"
- "~n N: ~p", [Ref, Pid, N]),
+ns02_client_loop(Parent, Ref, Pid, Begin, End, N)
+ when is_pid(Parent) andalso is_integer(Begin) andalso is_integer(End) ->
+ %% p("loop -> [~w] inform parent: ~w, ~w => ~w", [N, Begin, End, End-Begin]),
+ Parent ! {?MODULE, client_time, N*(End-Begin)},
+ ns02_client_loop(undefined, Ref, Pid, snmp_misc:now(ms), undefined, N);
+ns02_client_loop(Parent, Ref, Pid, Begin, End, N)
+ when is_integer(Begin) andalso is_integer(End) ->
+ %% p("loop -> [~w] entry when"
+ %% "~n Ref: ~p"
+ %% "~n Pid: ~p"
+ %% "~n Begin: ~p"
+ %% "~n End: ~p", [N, Ref, Pid, Begin, End]),
+ ns02_client_loop(Parent, Ref, Pid, snmp_misc:now(ms), undefined, N);
+ns02_client_loop(Parent, Ref, Pid, Begin, End, N) ->
+ %% p("loop(await message) -> [~w] entry when"
+ %% "~n Ref: ~p"
+ %% "~n Pid: ~p"
+ %% "~n Begin: ~p"
+ %% "~n End: ~p", [N, Ref, Pid, Begin, End]),
receive
{snmpm_started, Pid} ->
p("received expected started message (~w)", [N]),
- ns02_loop1(snmpm:monitor(), dummy, N);
+ ns02_client_loop(Parent,
+ snmpm:monitor(), dummy,
+ Begin, End,
+ N);
{snmpm_start_timeout, Pid} ->
p("unexpected timout"),
?FAIL({unexpected_start_timeout, Pid});
@@ -1049,24 +1136,24 @@ ns02_loop1(Ref, Pid, N) ->
p("received expected DOWN message (~w) with"
"~n Obj: ~p"
"~n Reason: ~p", [N, Obj, Reason]),
- ns02_loop1(dummy, snmpm:notify_started(?NS_TIMEOUT), N-1)
- after 10000 ->
- ?FAIL(timeout)
+ ns02_client_loop(Parent,
+ dummy, snmpm:notify_started(?NS_TIMEOUT),
+ Begin, snmp_misc:now(ms),
+ N-1)
end.
-
-ns02_loop2_start(Opts) ->
- spawn_link(fun() -> ns02_loop2(Opts) end).
+ns02_ctrl_start(Opts, N) ->
+ spawn_link(fun() -> ns02_ctrl(Opts, N) end).
-ns02_loop2(Opts) ->
- put(tname,ns02_loop2),
+ns02_ctrl(Opts, N) ->
+ put(tname, ns02_ctrl),
p("starting"),
- ns02_loop2(Opts, 5).
+ ns02_ctrl_loop(Opts, N).
-ns02_loop2(_Opts, 0) ->
+ns02_ctrl_loop(_Opts, 0) ->
p("done"),
exit(normal);
-ns02_loop2(Opts, N) ->
+ns02_ctrl_loop(Opts, N) ->
p("entry when N: ~p", [N]),
?SLEEP(2000),
p("start manager"),
@@ -1074,7 +1161,7 @@ ns02_loop2(Opts, N) ->
?SLEEP(2000),
p("stop manager"),
snmpm:stop(),
- ns02_loop2(Opts, N-1).
+ ns02_ctrl_loop(Opts, N-1).
%%======================================================================
@@ -5416,15 +5503,14 @@ init_manager(AutoInform, Config) ->
start_manager(Node, Vsns, Conf)
end
catch
- T:E ->
- StackTrace = ?STACK(),
+ C:E:S ->
p("Failure during manager start: "
- "~n Error Type: ~p"
- "~n Error: ~p"
- "~n StackTrace: ~p", [T, E, StackTrace]),
+ "~n Error Class: ~p"
+ "~n Error: ~p"
+ "~n StackTrace: ~p", [C, E, S]),
%% And now, *try* to cleanup
(catch stop_node(Node)),
- ?FAIL({failed_starting_manager, T, E, StackTrace})
+ ?FAIL({failed_starting_manager, C, E, S})
end.
fin_manager(Config) ->
@@ -5432,7 +5518,7 @@ fin_manager(Config) ->
StopMgrRes = stop_manager(Node),
StopCryptoRes = fin_crypto(Node),
StopNode = stop_node(Node),
- p("fin_agent -> stop apps and (mgr node ~p) node results: "
+ p("fin_manager -> stop apps and (mgr node ~p) node results: "
"~n SNMP Mgr: ~p"
"~n Crypto: ~p"
"~n Node: ~p",
@@ -5498,15 +5584,14 @@ init_agent(Config) ->
start_agent(Node, Vsns, Conf)
end
catch
- T:E ->
- StackTrace = ?STACK(),
+ C:E:S ->
p("Failure during agent start: "
- "~n Error Type: ~p"
- "~n Error: ~p"
- "~n StackTrace: ~p", [T, E, StackTrace]),
+ "~n Error Class: ~p"
+ "~n Error: ~p"
+ "~n StackTrace: ~p", [C, E, S]),
%% And now, *try* to cleanup
(catch stop_node(Node)),
- ?FAIL({failed_starting_agent, T, E, StackTrace})
+ ?FAIL({failed_starting_agent, C, E, S})
end.
@@ -6179,7 +6264,12 @@ start_agent(Node, Vsns, Conf0, _Opts) ->
{mib_server, [{verbosity, MSV}]},
{note_store, [{verbosity, NSV}]},
{stymbolic_store, [{verbosity, SSV}]},
- {net_if, [{verbosity, NIV}]},
+ {net_if, [{verbosity, NIV},
+ %% On some linux "they" add a 127.0.1.1 or somthing
+ %% similar, so if we don't specify bind_to
+ %% we don't know which address will be selected
+ %% (which will cause problems for some test cases).
+ {options, [{bind_to, true}]}]},
{multi_threaded, true}],
?line ok = set_agent_env(Node, Env),
diff --git a/lib/snmp/test/snmp_test_data/OTP14196-MIB.mib b/lib/snmp/test/snmp_test_data/OTP14196-MIB.mib
new file mode 100644
index 0000000000..0b3c718a02
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/OTP14196-MIB.mib
@@ -0,0 +1,47 @@
+OTP14196-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, snmpModules, mib-2
+ FROM SNMPv2-SMI
+ TEXTUAL-CONVENTION
+ FROM SNMPv2-TC
+ OBJECT-GROUP
+ FROM SNMPv2-CONF
+ ;
+
+otp14196MIB MODULE-IDENTITY
+ LAST-UPDATED "1004210000Z"
+ ORGANIZATION ""
+ CONTACT-INFO
+ ""
+ DESCRIPTION
+ "Test mib for OTP-14196"
+ ::= { snmpModules 1 }
+
+testCompliances OBJECT IDENTIFIER ::= { otp14196MIB 1 }
+test OBJECT IDENTIFIER ::= { mib-2 15 }
+
+typeA OBJECT-TYPE
+ SYNTAX TypeAType
+ MAX-ACCESS accessible-for-notify
+ STATUS current
+ DESCRIPTION
+ "Test type for OTP-14196"
+ ::= { test 4711 }
+
+TypeAType ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ ""
+ SYNTAX INTEGER
+
+testGroups OBJECT IDENTIFIER ::= { testCompliances 1 }
+
+testGroupA OBJECT-GROUP
+ OBJECTS { typeA }
+ STATUS current
+ DESCRIPTION
+ ""
+ ::= { testGroups 17 }
+
+END
diff --git a/lib/snmp/test/snmp_test_lib.erl b/lib/snmp/test/snmp_test_lib.erl
index 290f1bc31a..a483690653 100644
--- a/lib/snmp/test/snmp_test_lib.erl
+++ b/lib/snmp/test/snmp_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -41,7 +41,7 @@
-export([watchdog/3, watchdog_start/1, watchdog_start/2, watchdog_stop/1]).
-export([del_dir/1]).
-export([cover/1]).
--export([p/2, print/5, formated_timestamp/0]).
+-export([p/2, print1/2, print2/2, print/5, formated_timestamp/0]).
%% ----------------------------------------------------------------------
@@ -58,12 +58,67 @@ from(H, [H | T]) -> T;
from(H, [_ | T]) -> from(H, T);
from(_H, []) -> [].
+%% localhost() ->
+%% {ok, Ip} = snmp_misc:ip(net_adm:localhost()),
+%% Ip.
+%% localhost(Family) ->
+%% {ok, Ip} = snmp_misc:ip(net_adm:localhost(), Family),
+%% Ip.
+
localhost() ->
- {ok, Ip} = snmp_misc:ip(net_adm:localhost()),
- Ip.
+ localhost(inet).
+
localhost(Family) ->
- {ok, Ip} = snmp_misc:ip(net_adm:localhost(), Family),
- Ip.
+ case inet:getaddr(net_adm:localhost(), Family) of
+ {ok, {127, _, _, _}} when (Family =:= inet) ->
+ %% Ouch, we need to use something else
+ case inet:getifaddrs() of
+ {ok, IfList} ->
+ which_addr(Family, IfList);
+ {error, Reason1} ->
+ fail({getifaddrs, Reason1}, ?MODULE, ?LINE)
+ end;
+ {ok, {0, _, _, _, _, _, _, _}} when (Family =:= inet6) ->
+ %% Ouch, we need to use something else
+ case inet:getifaddrs() of
+ {ok, IfList} ->
+ which_addr(Family, IfList);
+ {error, Reason1} ->
+ fail({getifaddrs, Reason1}, ?MODULE, ?LINE)
+ end;
+ {ok, Addr} ->
+ Addr;
+ {error, Reason2} ->
+ fail({getaddr, Reason2}, ?MODULE, ?LINE)
+ end.
+
+which_addr(_Family, []) ->
+ fail(no_valid_addr, ?MODULE, ?LINE);
+which_addr(Family, [{"lo", _} | IfList]) ->
+ which_addr(Family, IfList);
+which_addr(Family, [{"docker" ++ _, _} | IfList]) ->
+ which_addr(Family, IfList);
+which_addr(Family, [{"br-" ++ _, _} | IfList]) ->
+ which_addr(Family, IfList);
+which_addr(Family, [{_Name, IfOpts} | IfList]) ->
+ case which_addr2(Family, IfOpts) of
+ {ok, Addr} ->
+ Addr;
+ {error, _} ->
+ which_addr(Family, IfList)
+ end.
+
+which_addr2(_Family, []) ->
+ {error, not_found};
+which_addr2(Family, [{addr, Addr}|_])
+ when (Family =:= inet) andalso (size(Addr) =:= 4) ->
+ {ok, Addr};
+which_addr2(Family, [{addr, Addr}|_])
+ when (Family =:= inet6) andalso (size(Addr) =:= 8) ->
+ {ok, Addr};
+which_addr2(Family, [_|IfOpts]) ->
+ which_addr2(Family, IfOpts).
+
sz(L) when is_list(L) ->
length(L);
@@ -605,19 +660,30 @@ p(Mod, Case) when is_atom(Mod) andalso is_atom(Case) ->
p(F, A) when is_list(F) andalso is_list(A) ->
io:format(user, F ++ "~n", A).
+%% This is just a bog standard printout, with a (formatted) timestamp
+%% prefix and a newline after.
+%% print1 - prints to both standard_io and user.
+%% print2 - prints to just standard_io.
+
+print_format(F, A) ->
+ FTS = snmp_test_lib:formated_timestamp(),
+ io_lib:format("[~s] " ++ F ++ "~n", [FTS | A]).
+
+print1(F, A) ->
+ S = print_format(F, A),
+ io:format("~s", [S]),
+ io:format(user, "~s", [S]).
+
+print2(F, A) ->
+ S = print_format(F, A),
+ io:format("~s", [S]).
+
+
print(Prefix, Module, Line, Format, Args) ->
io:format("*** [~s] ~s ~p ~p ~p:~p *** " ++ Format ++ "~n",
[formated_timestamp(),
Prefix, node(), self(), Module, Line|Args]).
formated_timestamp() ->
- format_timestamp(os:timestamp()).
-
-format_timestamp({_N1, _N2, N3} = Now) ->
- {Date, Time} = calendar:now_to_datetime(Now),
- {YYYY,MM,DD} = Date,
- {Hour,Min,Sec} = Time,
- FormatDate =
- io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w ~w",
- [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
- lists:flatten(FormatDate).
+ snmp_misc:formated_timestamp().
+
diff --git a/lib/snmp/test/snmp_test_lib.hrl b/lib/snmp/test/snmp_test_lib.hrl
index 7acebee1f1..335f3fff3c 100644
--- a/lib/snmp/test/snmp_test_lib.hrl
+++ b/lib/snmp/test/snmp_test_lib.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -127,24 +127,31 @@
-endif.
-ifdef(snmp_debug).
--define(DBG(F,A),?PRINT("DBG",F,A)).
+-define(DBG(F,A), ?PRINT("DBG", F, A)).
-else.
--define(DBG(F,A),ok).
+-define(DBG(F,A), ok).
-endif.
-ifdef(snmp_log).
--define(LOG(F,A),?PRINT("LOG",F,A)).
+-define(LOG(F,A), ?PRINT("LOG", F, A)).
-else.
--define(LOG(F,A),ok).
+-define(LOG(F,A), ok).
-endif.
-ifdef(snmp_error).
--define(ERR(F,A),?PRINT("ERR",F,A)).
+-define(ERR(F,A), ?PRINT("ERR", F, A)).
-else.
--define(ERR(F,A),ok).
+-define(ERR(F,A), ok).
-endif.
--define(INF(F,A),?PRINT("INF",F,A)).
+-define(INF(F,A), ?PRINT("INF", F, A)).
-define(PRINT(P,F,A),
- snmp_test_lib:print(P,?MODULE,?LINE,F,A)).
+ snmp_test_lib:print(P, ?MODULE, ?LINE, F, A)).
+
+-define(PRINT1(F, A), snmp_test_lib:print1(F, A)).
+-define(EPRINT1(F, A), ?PRINT1("<ERROR> " ++ F, A)).
+
+-define(PRINT2(F, A), snmp_test_lib:print2(F, A)).
+-define(EPRINT2(F, A), ?PRINT2("<ERROR> " ++ F, A)).
+
diff --git a/lib/snmp/test/snmp_test_mgr.erl b/lib/snmp/test/snmp_test_mgr.erl
index 36637d5cf4..73a4d56084 100644
--- a/lib/snmp/test/snmp_test_mgr.erl
+++ b/lib/snmp/test/snmp_test_mgr.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -20,8 +20,10 @@
-module(snmp_test_mgr).
+
%%----------------------------------------------------------------------
-%% This module implements a simple SNMP manager for Erlang.
+%% This module implements a simple SNMP manager for Erlang. Its used
+%% during by the agent test suite.
%%----------------------------------------------------------------------
%% c(snmp_test_mgr).
@@ -49,16 +51,17 @@
-include_lib("snmp/include/snmp_types.hrl").
-include_lib("snmp/include/STANDARD-MIB.hrl").
-
--record(state,{dbg = true,
- quiet,
- parent,
- timeout = 3500,
- print_traps = true,
- mini_mib,
- packet_server,
- last_sent_pdu,
- last_received_pdu}).
+-include("snmp_test_lib.hrl").
+
+-record(state, {dbg = true,
+ quiet,
+ parent,
+ timeout = 3500,
+ print_traps = true,
+ mini_mib,
+ packet_server,
+ last_sent_pdu,
+ last_received_pdu}).
-define(SERVER, ?MODULE).
-define(PACK_SERV, snmp_test_mgr_misc).
@@ -197,27 +200,28 @@ init({Options, CallerPid}) ->
put(debug, get_value(debug, Options, false)),
d("init -> (~p) extract options",[self()]),
PacksDbg = get_value(packet_server_debug, Options, false),
- io:format("[~w] ~p -> PacksDbg: ~p~n", [?MODULE, self(), PacksDbg]),
+ print("[~w] ~p -> PacksDbg: ~p~n", [?MODULE, self(), PacksDbg]),
RecBufSz = get_value(recbuf, Options, 1024),
- io:format("[~w] ~p -> RecBufSz: ~p~n", [?MODULE, self(), RecBufSz]),
+ print("[~w] ~p -> RecBufSz: ~p~n", [?MODULE, self(), RecBufSz]),
Mibs = get_value(mibs, Options, []),
- io:format("[~w] ~p -> Mibs: ~p~n", [?MODULE, self(), Mibs]),
+ print("[~w] ~p -> Mibs: ~p~n", [?MODULE, self(), Mibs]),
Udp = get_value(agent_udp, Options, 4000),
- io:format("[~w] ~p -> Udp: ~p~n", [?MODULE, self(), Udp]),
+ print("[~w] ~p -> Udp: ~p~n", [?MODULE, self(), Udp]),
User = get_value(user, Options, "initial"),
- io:format("[~w] ~p -> User: ~p~n", [?MODULE, self(), User]),
+ print("[~w] ~p -> User: ~p~n", [?MODULE, self(), User]),
EngineId = get_value(engine_id, Options, "agentEngine"),
- io:format("[~w] ~p -> EngineId: ~p~n", [?MODULE, self(), EngineId]),
+ print("[~w] ~p -> EngineId: ~p~n", [?MODULE, self(), EngineId]),
CtxEngineId = get_value(context_engine_id, Options, EngineId),
- io:format("[~w] ~p -> CtxEngineId: ~p~n", [?MODULE, self(), CtxEngineId]),
+ print("[~w] ~p -> CtxEngineId: ~p~n", [?MODULE, self(), CtxEngineId]),
TrapUdp = get_value(trap_udp, Options, 5000),
- io:format("[~w] ~p -> TrapUdp: ~p~n", [?MODULE, self(), TrapUdp]),
+ print("[~w] ~p -> TrapUdp: ~p~n", [?MODULE, self(), TrapUdp]),
Dir = get_value(dir, Options, "."),
- io:format("[~w] ~p -> Dir: ~p~n", [?MODULE, self(), Dir]),
+ print("[~w] ~p -> Dir: ~p~n", [?MODULE, self(), Dir]),
SecLevel = get_value(sec_level, Options, noAuthNoPriv),
- io:format("[~w] ~p -> SecLevel: ~p~n", [?MODULE, self(), SecLevel]),
+ print("[~w] ~p -> SecLevel: ~p~n", [?MODULE, self(), SecLevel]),
MiniMIB = snmp_mini_mib:create(Mibs),
- io:format("[~w] ~p -> MiniMIB: ~p~n", [?MODULE, self(), MiniMIB]),
+ d("[~w] ~p -> MiniMIB: "
+ "~n ~p", [?MODULE, self(), MiniMIB]),
Version = case lists:member(v2, Options) of
true -> 'version-2';
false ->
@@ -226,19 +230,19 @@ init({Options, CallerPid}) ->
false -> 'version-1'
end
end,
- io:format("[~w] ~p -> Version: ~p~n", [?MODULE, self(), Version]),
+ print("[~w] ~p -> Version: ~p~n", [?MODULE, self(), Version]),
Com = case Version of
'version-3' ->
get_value(context, Options, "");
_ ->
get_value(community, Options, "public")
end,
- io:format("[~w] ~p -> Com: ~p~n", [?MODULE, self(), Com]),
+ print("[~w] ~p -> Com: ~p~n", [?MODULE, self(), Com]),
VsnHdrD =
{Com, User, EngineId, CtxEngineId, mk_seclevel(SecLevel)},
- io:format("[~w] ~p -> VsnHdrD: ~p~n", [?MODULE, self(), VsnHdrD]),
+ print("[~w] ~p -> VsnHdrD: ~p~n", [?MODULE, self(), VsnHdrD]),
IpFamily = get_value(ipfamily, Options, inet),
- io:format("[~w] ~p -> IpFamily: ~p~n", [?MODULE, self(), IpFamily]),
+ print("[~w] ~p -> IpFamily: ~p~n", [?MODULE, self(), IpFamily]),
AgIp = case snmp_misc:assq(agent, Options) of
{value, Tuple4} when is_tuple(Tuple4) andalso
(size(Tuple4) =:= 4) ->
@@ -247,9 +251,9 @@ init({Options, CallerPid}) ->
{ok, Ip} = snmp_misc:ip(Host, IpFamily),
Ip
end,
- io:format("[~w] ~p -> AgIp: ~p~n", [?MODULE, self(), AgIp]),
+ print("[~w] ~p -> AgIp: ~p~n", [?MODULE, self(), AgIp]),
Quiet = lists:member(quiet, Options),
- io:format("[~w] ~p -> Quiet: ~p~n", [?MODULE, self(), Quiet]),
+ print("[~w] ~p -> Quiet: ~p~n", [?MODULE, self(), Quiet]),
PackServ =
start_packet_server(
Quiet, Options, CallerPid, AgIp, Udp, TrapUdp,
@@ -443,7 +447,8 @@ handle_cast({bulk, Args}, State) ->
{noreply, execute_request(bulk, Args, State)};
handle_cast({response, RespPdu}, State) ->
- d("handle_cast -> response request with ~p", [RespPdu]),
+ d("handle_cast -> response request with "
+ "~n ~p", [RespPdu]),
?PACK_SERV:send_pdu(RespPdu, State#state.packet_server),
{noreply, State};
@@ -1126,14 +1131,15 @@ sizeOf(L) when is_list(L) ->
sizeOf(B) when is_binary(B) ->
size(B).
-d(F,A) -> d(get(debug),F,A).
+d(F, A) -> d(get(debug), F, A).
-d(true,F,A) ->
- io:format("*** [~s] MGR_DBG *** " ++ F ++ "~n",
- [formated_timestamp()|A]);
+d(true, F, A) ->
+ print(F, A);
d(_,_F,_A) ->
ok.
+print(F, A) ->
+ ?PRINT2("MGR " ++ F, A).
formated_timestamp() ->
snmp_test_lib:formated_timestamp().
diff --git a/lib/snmp/test/snmp_test_mgr_misc.erl b/lib/snmp/test/snmp_test_mgr_misc.erl
index 274fb5be26..315e3ebd9e 100644
--- a/lib/snmp/test/snmp_test_mgr_misc.erl
+++ b/lib/snmp/test/snmp_test_mgr_misc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -38,11 +38,14 @@
-define(SNMP_USE_V3, true).
-include_lib("snmp/include/snmp_types.hrl").
+-include_lib("snmp/src/misc/snmp_verbosity.hrl").
+-include("snmp_test_lib.hrl").
%%----------------------------------------------------------------------
%% The InHandler process will receive messages on the form {snmp_pdu, Pdu}.
%%----------------------------------------------------------------------
+
start_link_packet(
InHandler, AgentIp, UdpPort, TrapUdp, VsnHdr, Version, Dir, BufSz) ->
start_link_packet(
@@ -101,11 +104,11 @@ init_packet(
DbgOptions, IpFamily) ->
put(sname, mgr_misc),
init_debug(DbgOptions),
- {ok, UdpId} =
- gen_udp:open(TrapUdp, [{recbuf,BufSz}, {reuseaddr, true}, IpFamily]),
+ UdpOpts = [{recbuf,BufSz}, {reuseaddr, true}, IpFamily],
+ {ok, UdpId} = gen_udp:open(TrapUdp, UdpOpts),
put(msg_id, 1),
- proc_lib:init_ack(Parent, self()),
init_usm(Version, Dir),
+ proc_lib:init_ack(Parent, self()),
packet_loop(SnmpMgr, UdpId, AgentIp, UdpPort, VsnHdr, Version, []).
init_debug(Dbg) when is_atom(Dbg) ->
@@ -200,86 +203,24 @@ packet_loop(SnmpMgr, UdpId, AgentIp, UdpPort, VsnHdr, Version, MsgData) ->
handle_udp_packet(_V, undefined,
UdpId, Ip, UdpPort,
Bytes, SnmpMgr, AgentIp) ->
- M = (catch snmp_pdus:dec_message_only(Bytes)),
- MsgData3 =
- case M of
- Message when Message#message.version =:= 'version-3' ->
- d("handle_udp_packet -> version 3"),
- case catch handle_v3_msg(Bytes, Message) of
- {ok, NewData, MsgData2} ->
- Msg = Message#message{data = NewData},
- case SnmpMgr of
- {pdu, Pid} ->
- Pdu = get_pdu(Msg),
- d("packet_loop -> "
- "send pdu to manager (~w): ~p", [Pid, Pdu]),
- Pid ! {snmp_pdu, Pdu};
- {msg, Pid} ->
- d("packet_loop -> "
- "send msg to manager (~w): ~p", [Pid, Msg]),
- Pid ! {snmp_msg, Msg, Ip, UdpPort}
- end,
- MsgData2;
- {error, Reason, B} ->
- udp_send(UdpId, AgentIp, UdpPort, B),
- error("Decoding error. Auto-sending Report.\n"
- "Reason: ~w "
- "(UDPport: ~w, Ip: ~w)",
- [Reason, UdpPort, Ip]),
- [];
- {error, Reason} ->
- error("Decoding error. "
- "Bytes: ~w ~n Reason: ~w "
- "(UDPport: ~w, Ip: ~w)",
- [Bytes, Reason, UdpPort, Ip]),
- []
- end;
- Message when is_record(Message, message) ->
- %% v1 or v2c
- d("handle_udp_packet -> version v1 or v2c"),
- case catch snmp_pdus:dec_pdu(Message#message.data) of
- Pdu when is_record(Pdu, pdu) ->
- case SnmpMgr of
- {pdu, Pid} ->
- d("handle_udp_packet -> "
- "send pdu to manager (~w): ~p",
- [Pid, Pdu]),
- Pid ! {snmp_pdu, Pdu};
- {msg, Pid} ->
- d("handle_udp_packet -> "
- "send pdu-msg to manager (~w): ~p",
- [Pid, Pdu]),
- Msg = Message#message{data = Pdu},
- Pid ! {snmp_msg, Msg, Ip, UdpPort}
- end;
- Pdu when is_record(Pdu, trappdu) ->
- case SnmpMgr of
- {pdu, Pid} ->
- d("handle_udp_packet -> "
- "send trap to manager (~w): ~p",
- [Pid, Pdu]),
- Pid ! {snmp_pdu, Pdu};
- {msg, Pid} ->
- d("handle_udp_packet -> "
- "send trap-msg to manager (~w): ~p",
- [Pid, Pdu]),
- Msg = Message#message{data = Pdu},
- Pid ! {snmp_msg, Msg, Ip, UdpPort}
- end;
- Reason ->
- error("Decoding error. "
- "Bytes: ~w ~n Reason: ~w "
- "(UDPport: ~w, Ip: ~w)",
- [Bytes, Reason, UdpPort, Ip])
- end,
- [];
- Reason ->
- error("Decoding error. Bytes: ~w ~n Reason: ~w "
- "(UDPport: ~w, Ip: ~w)",
- [Bytes, Reason, UdpPort, Ip]),
- []
- end,
- MsgData3;
+ try snmp_pdus:dec_message_only(Bytes) of
+ Message when Message#message.version =:= 'version-3' ->
+ d("handle_udp_packet -> version 3"),
+ handle_v3_message(SnmpMgr, UdpId, Ip, UdpPort, AgentIp,
+ Bytes, Message);
+
+ Message when is_record(Message, message) ->
+ d("handle_udp_packet -> version 1 or 2"),
+ handle_v1_or_v2_message(SnmpMgr, UdpId, Ip, UdpPort, AgentIp,
+ Bytes, Message)
+
+ catch
+ Class:Error:_ ->
+ error("Decoding error (~w). Bytes: ~w ~n Error: ~w "
+ "(UDPport: ~w, Ip: ~w)",
+ [Class, Bytes, Error, UdpPort, Ip]),
+ []
+ end;
handle_udp_packet(V, {DiscoReqMsg, From}, _UdpId, _Ip, _UdpPort,
Bytes, _, _AgentIp) ->
DiscoRspMsg = (catch snmp_pdus:dec_message(Bytes)),
@@ -297,6 +238,88 @@ handle_udp_packet(V, {DiscoReqMsg, From}, _UdpId, _Ip, _UdpPort,
[]
end.
+handle_v3_message(Mgr, UdpId, Ip, UdpPort, AgentIp,
+ Bytes, Message) ->
+ try handle_v3_msg(Bytes, Message) of
+ {ok, NewData, MsgData} ->
+ Msg = Message#message{data = NewData},
+ case Mgr of
+ {pdu, Pid} ->
+ Pdu = get_pdu(Msg),
+ d("handle_v3_message -> send pdu to manager (~p): "
+ "~n ~p", [Pid, Pdu]),
+ Pid ! {snmp_pdu, Pdu};
+ {msg, Pid} ->
+ d("handle_v3_message -> send msg to manager (~p): "
+ "~n ~p", [Pid, Msg]),
+ Pid ! {snmp_msg, Msg, Ip, UdpPort}
+ end,
+ MsgData
+
+ catch
+ throw:{error, Reason, B}:_ ->
+ udp_send(UdpId, AgentIp, UdpPort, B),
+ error("Decoding (v3) error. Auto-sending Report.\n"
+ "~n Reason: ~w "
+ "(UDPport: ~w, Ip: ~w)",
+ [Reason, UdpPort, Ip]),
+ [];
+
+ throw:{error, Reason}:_ ->
+ error("Decoding (v3) error. "
+ "~n Bytes: ~w"
+ "~n Reason: ~w "
+ "(UDPport: ~w, Ip: ~w)",
+ [Bytes, Reason, UdpPort, Ip]),
+ [];
+
+ Class:Error:_ ->
+ error("Decoding (v3) error (~w). "
+ "~n Bytes: ~w"
+ "~n Error: ~w "
+ "(UDPport: ~w, Ip: ~w)",
+ [Class, Bytes, Error, UdpPort, Ip]),
+ []
+
+ end.
+
+handle_v1_or_v2_message(Mgr, _UdpId, Ip, UdpPort, _AgentIp,
+ Bytes, Message) ->
+ try snmp_pdus:dec_pdu(Message#message.data) of
+ Pdu when is_record(Pdu, pdu) ->
+ case Mgr of
+ {pdu, Pid} ->
+ d("handle_v1_or_v2_message -> send pdu to manager (~p): "
+ "~n ~p", [Pid, Pdu]),
+ Pid ! {snmp_pdu, Pdu};
+ {msg, Pid} ->
+ d("handle_v1_or_v2_message -> send msg to manager (~p): "
+ "~n ~p", [Pid, Pdu]),
+ Msg = Message#message{data = Pdu},
+ Pid ! {snmp_msg, Msg, Ip, UdpPort}
+ end;
+ Pdu when is_record(Pdu, trappdu) ->
+ case Mgr of
+ {pdu, Pid} ->
+ d("handle_v1_or_v2_message -> send trap-pdu to manager (~p): "
+ "~n ~p", [Pid, Pdu]),
+ Pid ! {snmp_pdu, Pdu};
+ {msg, Pid} ->
+ d("handle_v1_or_v2_message -> send trap-msg to manager (~p): "
+ "~n ~p", [Pid, Pdu]),
+ Msg = Message#message{data = Pdu},
+ Pid ! {snmp_msg, Msg, Ip, UdpPort}
+ end
+
+ catch
+ Class:Error:_ ->
+ error("Decoding (v1 or v2) error (~w): "
+ "~n Bytes: ~w"
+ "~n Error: ~w "
+ "(UDPport: ~w, Ip: ~w)",
+ [Class, Bytes, Error, UdpPort, Ip])
+ end.
+
%% This function assumes that the agent and the manager (thats us)
%% has the same version.
@@ -578,18 +601,100 @@ set_pdu(Msg, RePdu) ->
init_usm('version-3', Dir) ->
+ ?vlog("init_usm -> create (and init) fake \"agent\" table", []),
ets:new(snmp_agent_table, [set, public, named_table]),
ets:insert(snmp_agent_table, {agent_mib_storage, persistent}),
- snmpa_local_db:start_link(normal, Dir, [{verbosity,trace}]),
+ %% The local-db process may *still* be running (from a previous
+ %% test case), on the way down, but not yet dead.
+ %% Either way, before we start it, make sure its dead and *gone*!
+ %% How do we do that without getting hung up? Calling the stop
+ %% function, will not do since it uses Timeout=infinity.
+ ?vlog("init_usm -> ensure (old) fake local-db is dead", []),
+ ensure_local_db_dead(),
+ ?vlog("init_usm -> try start fake local-db", []),
+ case snmpa_local_db:start_link(normal, Dir,
+ [{sname, "MGR-LOCAL-DB"},
+ {verbosity, trace}]) of
+ {ok, Pid} ->
+ ?vlog("started: ~p"
+ "~n ~p", [Pid, process_info(Pid)]);
+ {error, {already_started, Pid}} ->
+ LDBInfo = process_info(Pid),
+ ?vlog("already started: ~p"
+ "~n ~p", [Pid, LDBInfo]),
+ ?FAIL({still_running, snmpa_local_db, LDBInfo});
+ {error, Reason} ->
+ ?FAIL({failed_starting, snmpa_local_db, Reason})
+ end,
NameDb = snmpa_agent:db(snmpEngineID),
+ ?vlog("init_usm -> try set manager engine-id", []),
R = snmp_generic:variable_set(NameDb, "mgrEngine"),
- io:format("~w:init_usm -> engine-id set result: ~p~n", [?MODULE,R]),
+ snmp_verbosity:print(info, info, "init_usm -> engine-id set result: ~p", [R]),
+ ?vlog("init_usm -> try set engine boots (framework-mib)", []),
snmp_framework_mib:set_engine_boots(1),
+ ?vlog("init_usm -> try set engine time (framework-mib)", []),
snmp_framework_mib:set_engine_time(1),
- snmp_user_based_sm_mib:reconfigure(Dir);
+ ?vlog("init_usm -> try usm (mib) reconfigure", []),
+ snmp_user_based_sm_mib:reconfigure(Dir),
+ ?vlog("init_usm -> done", []),
+ ok;
init_usm(_Vsn, _Dir) ->
ok.
+ensure_local_db_dead() ->
+ ensure_dead(whereis(snmpa_local_db), 2000).
+
+ensure_dead(Pid, Timeout) when is_pid(Pid) ->
+ MRef = erlang:monitor(process, Pid),
+ try
+ begin
+ ensure_dead_wait(Pid, MRef, Timeout),
+ ensure_dead_stop(Pid, MRef, Timeout),
+ ensure_dead_kill(Pid, MRef, Timeout),
+ exit(failed_stop_local_db)
+ end
+ catch
+ throw:ok ->
+ ok
+ end;
+ensure_dead(_, _) ->
+ ?vlog("ensure_dead -> already dead", []),
+ ok.
+
+ensure_dead_wait(Pid, MRef, Timeout) ->
+ receive
+ {'DOWN', MRef, process, Pid, _Info} ->
+ ?vlog("ensure_dead_wait -> died peacefully", []),
+ throw(ok)
+ after Timeout ->
+ ?vlog("ensure_dead_wait -> giving up", []),
+ ok
+ end.
+
+ensure_dead_stop(Pid, MRef, Timeout) ->
+ StopPid = spawn(fun() -> snmpa_local_db:stop() end),
+ receive
+ {'DOWN', MRef, process, Pid, _Info} ->
+ ?vlog("ensure_dead -> dead (stopped)", []),
+ throw(ok)
+ after Timeout ->
+ ?vlog("ensure_dead_stop -> giving up", []),
+ exit(StopPid, kill),
+ ok
+ end.
+
+ensure_dead_kill(Pid, MRef, Timeout) ->
+ exit(Pid, kill),
+ receive
+ {'DOWN', MRef, process, Pid, _Info} ->
+ ?vlog("ensure_dead -> dead (killed)", []),
+ throw(ok)
+ after Timeout ->
+ ?vlog("ensure_dead_kill -> giving up", []),
+ ok
+ end.
+
+
display_incomming_message(M) ->
display_message("Incomming",M).
@@ -782,13 +887,13 @@ sz(O) ->
{unknown_size, O}.
d(F) -> d(F, []).
-d(F,A) -> d(get(debug),F,A).
+d(F,A) -> d(get(debug), F, A).
-d(true,F,A) ->
- io:format("*** [~s] MGR_PS_DBG *** " ++ F ++ "~n",
- [formated_timestamp()|A]);
+d(true, F, A) ->
+ print(F, A);
d(_,_F,_A) ->
ok.
-formated_timestamp() ->
- snmp_test_lib:formated_timestamp().
+print(F, A) ->
+ ?PRINT2("MGR_PS " ++ F, A).
+
diff --git a/lib/snmp/test/snmp_to_snmpnet_SUITE.erl b/lib/snmp/test/snmp_to_snmpnet_SUITE.erl
index 6a3466b6e4..b83c7461d1 100644
--- a/lib/snmp/test/snmp_to_snmpnet_SUITE.erl
+++ b/lib/snmp/test/snmp_to_snmpnet_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2014-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2014-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/snmp/test/test-mibs/ALARM-MIB.mib b/lib/snmp/test/test-mibs/ALARM-MIB.mib
index 18e43d4b4b..10d2adbff9 100644
--- a/lib/snmp/test/test-mibs/ALARM-MIB.mib
+++ b/lib/snmp/test/test-mibs/ALARM-MIB.mib
@@ -330,7 +330,7 @@ alarmModelRowStatus OBJECT-TYPE
cannot be used as an alarm suppression mechanism. Entries
that are notInService will disappear as described in RFC2579.
- This row can not be modified while it is being
+ This row cannot be modified while it is being
referenced by a value of alarmActiveModelPointer. In these
cases, an error of `inconsistentValue' will be returned to
the manager.
diff --git a/lib/snmp/test/test-mibs/SNMPv2-TC.mib b/lib/snmp/test/test-mibs/SNMPv2-TC.mib
index fd6a728ab5..1d75c4bbd8 100644
--- a/lib/snmp/test/test-mibs/SNMPv2-TC.mib
+++ b/lib/snmp/test/test-mibs/SNMPv2-TC.mib
@@ -454,7 +454,7 @@ value | | see 1| ->C| ->D
associated with this column or that there is no
conceptual row for which this column would be
accessible in the MIB view used by the retrieval. As
- such, the management station can not issue any
+ such, the management station cannot issue any
management protocol set operations to create an
instance of this column.
@@ -576,7 +576,7 @@ value | | see 1| ->C| ->D
associated with this column or that there is no
conceptual row for which this column would be
accessible in the MIB view used by the retrieval. As
- such, the management station can not issue any
+ such, the management station cannot issue any
management protocol set operations to create an
instance of this column.
diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk
index 2c97683625..f305497cd3 100644
--- a/lib/snmp/vsn.mk
+++ b/lib/snmp/vsn.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2017. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -19,6 +19,6 @@
# %CopyrightEnd%
APPLICATION = snmp
-SNMP_VSN = 5.2.10
+SNMP_VSN = 5.3
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(SNMP_VSN)$(PRE_VSN)"
diff --git a/lib/ssh/doc/specs/.gitignore b/lib/ssh/doc/specs/.gitignore
new file mode 100644
index 0000000000..322eebcb06
--- /dev/null
+++ b/lib/ssh/doc/specs/.gitignore
@@ -0,0 +1 @@
+specs_*.xml
diff --git a/lib/ssh/doc/src/Makefile b/lib/ssh/doc/src/Makefile
index f54f5e0708..4e32dd9976 100644
--- a/lib/ssh/doc/src/Makefile
+++ b/lib/ssh/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2017. All Rights Reserved.
+# Copyright Ericsson AB 2004-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -38,23 +38,27 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
# Target Specs
# ----------------------------------------------------
XML_APPLICATION_FILES = ref_man.xml
-XML_REF3_FILES = ssh.xml \
- ssh_channel.xml \
- ssh_connection.xml \
+XML_REF3_FILES = \
+ ssh.xml \
+ ssh_client_channel.xml \
ssh_client_key_api.xml \
+ ssh_connection.xml \
+ ssh_server_channel.xml \
ssh_server_key_api.xml \
+ ssh_file.xml \
ssh_sftp.xml \
ssh_sftpd.xml \
XML_REF6_FILES = ssh_app.xml
-XML_PART_FILES = \
- usersguide.xml
-XML_CHAPTER_FILES = notes.xml \
+XML_PART_FILES = usersguide.xml
+
+XML_CHAPTER_FILES = \
+ notes.xml \
introduction.xml \
using_ssh.xml \
+ terminology.xml \
configure_algos.xml
-# ssh_protocol.xml \
BOOK_FILES = book.xml
@@ -84,12 +88,19 @@ HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
+SPECS_FILES = $(XML_REF3_FILES:%.xml=$(SPECDIR)/specs_%.xml)
+
+TOP_SPECS_FILE = specs.xml
+
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
XML_FLAGS +=
DVIPS_FLAGS +=
+#SPECS_FLAGS = -I../../include -I../../../kernel/include
+SPECS_FLAGS = -I../../../public_key/include -I../../../public_key/src -I../../..
+
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
@@ -109,8 +120,10 @@ html: images $(HTML_REF_MAN_FILE)
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
+ rm -f $(SPECS_FILES)
rm -f errs core *~
man: $(MAN3_FILES) $(MAN6_FILES)
diff --git a/lib/ssh/doc/src/configure_algos.xml b/lib/ssh/doc/src/configure_algos.xml
index dd60324851..fa45b1cb4c 100644
--- a/lib/ssh/doc/src/configure_algos.xml
+++ b/lib/ssh/doc/src/configure_algos.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2017</year>
- <year>2017</year>
+ <year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -117,6 +117,7 @@
<p>Due to this, it impossible to list in documentation what algorithms that are available in a certain installation.</p>
<p>There is an important command to list the actual algorithms and their ordering:
<seealso marker="ssh#default_algorithms-0">ssh:default_algorithms/0</seealso>.</p>
+ <marker id="example_default_algorithms"/>
<code type="erl">
0> ssh:default_algorithms().
[{kex,['ecdh-sha2-nistp384','ecdh-sha2-nistp521',
@@ -156,7 +157,7 @@
<section>
<title>Replacing the default set: preferred_algorithms</title>
- <p>See the <seealso marker="ssh#option_preferred_algorithms">Reference Manual</seealso> for details</p>
+ <p>See the <seealso marker="ssh#type-preferred_algorithms_common_option">Reference Manual</seealso> for details</p>
<p>Here follows a series of examples ranging from simple to more complex.</p>
@@ -301,7 +302,7 @@
First one has to list them with <c>ssh:default_algorithms()</c> and then do changes in the lists.</p>
<p>To facilitate addition or removal of algorithms the option <c>modify_algorithms</c> is available.
- See the <seealso marker="ssh#option_modify_algorithms">Reference Manual</seealso> for details.</p>
+ See the <seealso marker="ssh#type-modify_algorithms_common_option">Reference Manual</seealso> for details.</p>
<p>The option takes a list with instructions to append, prepend or remove algorithms:</p>
<code type="erl">
diff --git a/lib/ssh/doc/src/introduction.xml b/lib/ssh/doc/src/introduction.xml
index b7a73e2597..8444daf0cc 100644
--- a/lib/ssh/doc/src/introduction.xml
+++ b/lib/ssh/doc/src/introduction.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2012</year>
- <year>2016</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -145,7 +145,7 @@
data that can be sent to the channel peer without adjusting the
window. Typically, an SSH client opens a channel, sends data (commands),
receives data (control information), and then closes the channel.
- The <seealso marker="ssh_channel">ssh_channel</seealso> behaviour
+ The <seealso marker="ssh_client_channel">ssh_client_channel</seealso> behaviour
handles generic parts of SSH channel management. This makes it easy
to write your own SSH client/server processes that use flow-control
and thus opens for more focus on the application logic.
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index ba563335a2..60f20c7c3f 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -30,6 +30,499 @@
<file>notes.xml</file>
</header>
+<section><title>Ssh 4.7.7</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ SSH uses the new crypto API.</p>
+ <p>
+ Own Id: OTP-15673</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.7.6</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ When an SSH server receives the very first message on a
+ new TCP connection, and that message is not the expected
+ one, the 64 first bytes of the received message are now
+ dumped in the INFO REPORT that reports the Protocol
+ Error.</p>
+ <p>
+ This facilitates the debugging of who sends the bad
+ message or of detecting a possible port scanning.</p>
+ <p>
+ Own Id: OTP-15772</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.7.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The callback <c>ssh_channel:init/1</c> was missing in
+ OTP-21</p>
+ <p>
+ Own Id: OTP-15762</p>
+ </item>
+ <item>
+ <p>
+ If a client was connected to an server on an already open
+ socket, the callback <c>fun(PeerName,FingerPrint)</c> in
+ the <c>accept_callback</c> option passed the local name
+ in the argument PeerName instead of the remote name.</p>
+ <p>
+ Own Id: OTP-15763</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.7.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ SSH sftp daemon now accepts an SSH_FXP_STAT message
+ encoded according to the wrong sftp version. Some clients
+ sends such messages.</p>
+ <p>
+ Own Id: OTP-15498 Aux Id: ERL-822, PR-2077 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.7.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed port leakage if a ssh:daemon call failed.</p>
+ <p>
+ Own Id: OTP-15397 Aux Id: ERL-801 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.7.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Incompatibility with newer OpenSSH fixed. Previously
+ versions 7.8 and later could cause Erlang SSH to exit.</p>
+ <p>
+ Own Id: OTP-15413</p>
+ </item>
+ <item>
+ <p>
+ The '<c>exec</c>' option for ssh daemons had wrong format
+ in the documentation.</p>
+ <p>
+ Own Id: OTP-15416</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Added public key methods ssh-ed25519 and ssh-ed448.</p>
+ <p>
+ Requires OpenSSL 1.1.1 or higher as cryptolib under the
+ OTP application <c>crypto</c>.</p>
+ <p>
+ Own Id: OTP-15094 Aux Id: OTP-15419 </p>
+ </item>
+ <item>
+ <p>
+ The SSH property tests are now adapted to the PropEr
+ testing tool.</p>
+ <p>
+ Own Id: OTP-15312</p>
+ </item>
+ <item>
+ <p>
+ The term "user" was not documented in the SSH app. A new
+ chapter with terminology is added to the User's Manual
+ where the term "user" is defined.</p>
+ <p>
+ A reference manual page about the module <c>ssh_file</c>
+ is also added. This is the default callback module for
+ user's keys, host keys etc.</p>
+ <p>
+ Own Id: OTP-15314</p>
+ </item>
+ <item>
+ <p>
+ Host and user key checking is made more robust.</p>
+ <p>
+ Own Id: OTP-15424</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.7.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Extended the undocumented <c>ssh_dbg</c> debug module
+ with an api for a circular trace buffer. This makes it
+ easy to record the last low-level events before an error
+ is detected. It is intended for solving difficult errors.</p>
+ <p>
+ Own Id: OTP-15020</p>
+ </item>
+ <item>
+ <p>
+ The key exchange methods
+ <c>'[email protected]'</c>,
+ <c>'curve25519-sha256'</c> and <c>'curve448-sha512'</c>
+ are implemented. The last two are defined in
+ https://tools.ietf.org/html/draft-ietf-curdle-ssh-curves</p>
+ <p>
+ They all depends on that OpenSSL 1.1.1 or higher is used
+ as cryptolib.</p>
+ <p>
+ Own Id: OTP-15133 Aux Id: OTP-15240 </p>
+ </item>
+ <item>
+ <p>
+ The cipher '<c>[email protected]</c>' is now
+ supported if OpenSSL 1.1.1 or higher is used as
+ cryptolib.</p>
+ <p>
+ Own Id: OTP-15209 Aux Id: OTP-15164 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.7</title>
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ If the daemon port listener is restarted, it could
+ potentially fail with <c>eaddrinuse</c> if the timing is
+ unlucky. It will now retry and exponentially back off the
+ listener restart a few times before failing.</p>
+ <p>
+ Own Id: OTP-14955</p>
+ </item>
+ <item>
+ <p>
+ A channel callback module always got the module name as
+ reason in a call to terminate. Now it will get the proper
+ Reason, usually 'normal'.</p>
+ <p>
+ Own Id: OTP-15084</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The option <c>exec</c> has new option values defined to
+ make it much more easy to implement an own <c>exec</c>
+ server.</p>
+ <p>
+ An option called <c>exec</c> for daemons implementing the
+ handling of 'exec' requests has existed a long time but
+ has been undocumented. The old undocumented value - as
+ well as its behavior - is kept for compatibility EXCEPT
+ that error messages are changed and are sent as
+ "stderror" text.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14851</p>
+ </item>
+ <item>
+ <p>
+ Updated ssh_connection:shell/2 documentation.</p>
+ <p>
+ Own Id: OTP-14880</p>
+ </item>
+ <item>
+ <p>
+ The experimental <c>ssh_dbg</c> module is completely
+ re-written. Its purpose is to make tracing and debugging
+ easier on deployed systems.</p>
+ <p>
+ Own Id: OTP-14896</p>
+ </item>
+ <item>
+ <p>
+ The SSH supervisor structure has been slightly changed.
+ This makes stopping the ssh application considerably
+ faster if there are open connections. This is important
+ in for example restarts.</p>
+ <p>
+ Own Id: OTP-14988</p>
+ </item>
+ <item>
+ <p>
+ The type specifications in SSH are completly reworked and
+ the following types are renamed:</p>
+ <p>
+ <c>ssh:ssh_connection_ref()</c> is changed to
+ <c>ssh:connection_ref()</c>, </p>
+ <p>
+ <c>ssh:ssh_daemon_ref()</c> is changed to
+ <c>ssh:daemon_ref()</c>,</p>
+ <p>
+ <c>ssh:ssh_channel_id()</c> is changed to
+ <c>ssh:channel_id()</c>.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15002 Aux Id: OTP-15030 </p>
+ </item>
+ <item>
+ <p>
+ The internal timer handling in SSH is now based on the
+ gen_statem timers.</p>
+ <p>
+ Own Id: OTP-15019</p>
+ </item>
+ <item>
+ <p>
+ Removed the undocumented and unused modules
+ <c>ssh_client_key.erl</c> and <c>ssh_server_key.erl</c>.</p>
+ <p>
+ Own Id: OTP-15028</p>
+ </item>
+ <item>
+ <p>
+ The Reference Manual pages are partly updated.</p>
+ <p>
+ The ssh page is now generated from specs and types, is
+ restructured and is partly rephrased.</p>
+ <p>
+ The ssh_channel, ssh_connection, ssh_client_key_api,
+ ssh_server_key_api and ssh_sftp pages are updated with
+ links, correct type names and some minor changes.</p>
+ <p>
+ Own Id: OTP-15030 Aux Id: OTP-15002 </p>
+ </item>
+ <item>
+ <p>
+ The behaviors <c>ssh_channel</c> and
+ <c>ssh_daemon_channel</c> are renamed to
+ <c>ssh_client_channel</c> and <c>ssh_server_channel</c>
+ respectively.</p>
+ <p>
+ The old modules are kept for compatibility but should
+ preferably be replaced when updating callback modules
+ referring them.</p>
+ <p>
+ Own Id: OTP-15041</p>
+ </item>
+ <item>
+ <p>
+ New test suite for channels.</p>
+ <p>
+ Own Id: OTP-15051</p>
+ </item>
+ <item>
+ <p>
+ The <c>rekey_limit</c> option could now set the max time
+ as well as the previously max data amount.</p>
+ <p>
+ Own Id: OTP-15069 Aux Id: ERL-617 </p>
+ </item>
+ <item>
+ <p>
+ Changed process exit supervision from links to monitors.</p>
+ <p>
+ Own Id: OTP-15082</p>
+ </item>
+ <item>
+ <p>
+ Better handling of misbehaving channel callback modules.</p>
+ <p>
+ Own Id: OTP-15083</p>
+ </item>
+ <item>
+ <p>
+ A new moduli file is generated. This file is used for the
+ recommended <c>diffie-hellman-group-exchange-sha256</c>
+ key exchange algorithm in SSH.</p>
+ <p>
+ Own Id: OTP-15113</p>
+ </item>
+ </list>
+ </section>
+</section>
+
+<section><title>Ssh 4.6.9.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ If a client was connected to an server on an already open
+ socket, the callback <c>fun(PeerName,FingerPrint)</c> in
+ the <c>accept_callback</c> option passed the local name
+ in the argument PeerName instead of the remote name.</p>
+ <p>
+ Own Id: OTP-15763</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.6.9.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed port leakage if a ssh:daemon call failed.</p>
+ <p>
+ Own Id: OTP-15397 Aux Id: ERL-801 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.6.9.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Incompatibility with newer OpenSSH fixed. Previously
+ versions 7.8 and later could cause Erlang SSH to exit.</p>
+ <p>
+ Own Id: OTP-15413</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.6.9.1</title>
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ SFTP clients reported the error reason <c>""</c> if a
+ non-OTP sftp server was killed during a long file
+ transmission.</p>
+ <p>
+ Now the signal name (for example <c>"KILL"</c>) will be
+ the error reason if the server's reason is empty.</p>
+ <p>
+ The documentation also lacked type information about this
+ class of errors.</p>
+ <p>
+ Own Id: OTP-15148 Aux Id: ERIERL-194 </p>
+ </item>
+ <item>
+ <p>
+ Fix ssh_sftp decode error for sftp protocol version 4</p>
+ <p>
+ Own Id: OTP-15149 Aux Id: ERIERL-199 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.6.9</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Host key hash erroneously calculated for clients
+ following draft-00 of RFC 4419, for example PuTTY</p>
+ <p>
+ Own Id: OTP-15064</p>
+ </item>
+ <item>
+ <p>
+ Renegotiation could fail in some states</p>
+ <p>
+ Own Id: OTP-15066</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.6.8</title>
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ An ssh_sftp server (running version 6) could fail if it
+ is told to remove a file which in fact is a directory.</p>
+ <p>
+ Own Id: OTP-15004</p>
+ </item>
+ <item>
+ <p>
+ Fix rare spurios shutdowns of ssh servers when receiveing
+ <c>{'EXIT',_,normal}</c> messages.</p>
+ <p>
+ Own Id: OTP-15018</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.6.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix bad spec in ssh.hrl: <c>double_algs()</c>.</p>
+ <p>
+ Own Id: OTP-14990</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Ssh 4.6.6</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -44,8 +537,6 @@
</item>
</list>
</section>
-
-
<section><title>Improvements and New Features</title>
<list>
<item>
@@ -452,6 +943,48 @@
</section>
+<section><title>Ssh 4.4.2.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix rare spurios shutdowns of ssh servers when receiveing
+ <c>{'EXIT',_,normal}</c> messages.</p>
+ <p>
+ Own Id: OTP-15018</p>
+ </item>
+ <item>
+ <p>
+ Host key hash erroneously calculated for clients
+ following draft-00 of RFC 4419, for example PuTTY</p>
+ <p>
+ Own Id: OTP-15064</p>
+ </item>
+ <item>
+ <p>
+ Renegotiation could fail in some states</p>
+ <p>
+ Own Id: OTP-15066</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.4.2.3</title>
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ An ssh_sftp server (running version 6) could fail if it
+ is told to remove a file which in fact is a directory.</p>
+ <p>
+ Own Id: OTP-15004</p>
+ </item>
+ </list>
+ </section>
+</section>
<section><title>Ssh 4.4.2.2</title>
<section><title>Improvements and New Features</title>
@@ -856,6 +1389,21 @@
</section>
+<section><title>Ssh 4.2.2.6</title>
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix rare spurios shutdowns of ssh servers when receiveing
+ <c>{'EXIT',_,normal}</c> messages.</p>
+ <p>
+ Own Id: OTP-15018</p>
+ </item>
+ </list>
+ </section>
+</section>
+
+
<section><title>Ssh 4.2.2.5</title>
<section><title>Improvements and New Features</title>
<list>
@@ -2462,7 +3010,7 @@
</item>
<item>
<p>
- Fixed internal error on when client and server can not
+ Fixed internal error on when client and server cannot
agree o which authmethod to use.</p>
<p>
Own Id: OTP-10731 Aux Id: seq12237 </p>
@@ -3527,4 +4075,3 @@
</section>
</chapter>
-
diff --git a/lib/ssh/doc/src/ref_man.xml b/lib/ssh/doc/src/ref_man.xml
index 140ebd8c76..60572b985b 100644
--- a/lib/ssh/doc/src/ref_man.xml
+++ b/lib/ssh/doc/src/ref_man.xml
@@ -4,7 +4,7 @@
<application xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>2004</year><year>2016</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -35,10 +35,12 @@
</description>
<xi:include href="ssh_app.xml"/>
<xi:include href="ssh.xml"/>
- <xi:include href="ssh_channel.xml"/>
+ <xi:include href="ssh_client_channel.xml"/>
+ <xi:include href="ssh_server_channel.xml"/>
<xi:include href="ssh_connection.xml"/>
<xi:include href="ssh_client_key_api.xml"/>
<xi:include href="ssh_server_key_api.xml"/>
+ <xi:include href="ssh_file.xml"/>
<xi:include href="ssh_sftp.xml"/>
<xi:include href="ssh_sftpd.xml"/>
</application>
diff --git a/lib/ssh/doc/src/specs.xml b/lib/ssh/doc/src/specs.xml
new file mode 100644
index 0000000000..a6517f3660
--- /dev/null
+++ b/lib/ssh/doc/src/specs.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<specs xmlns:xi="http://www.w3.org/2001/XInclude">
+ <xi:include href="../specs/specs_ssh.xml"/>
+ <xi:include href="../specs/specs_ssh_client_channel.xml"/>
+ <xi:include href="../specs/specs_ssh_client_key_api.xml"/>
+ <xi:include href="../specs/specs_ssh_connection.xml"/>
+ <xi:include href="../specs/specs_ssh_server_channel.xml"/>
+ <xi:include href="../specs/specs_ssh_server_key_api.xml"/>
+ <xi:include href="../specs/specs_ssh_file.xml"/>
+ <xi:include href="../specs/specs_ssh_sftp.xml"/>
+ <xi:include href="../specs/specs_ssh_sftpd.xml"/>
+</specs>
+
+
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index acf94ff6af..3fd6eae423 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -4,15 +4,15 @@
<erlref>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
+
+ http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
@@ -28,188 +28,189 @@
<date>2007-10-06</date>
<rev></rev>
</header>
- <module>ssh</module>
+ <module since="">ssh</module>
<modulesummary>Main API of the ssh application</modulesummary>
<description>
- <p>Interface module for the <c>ssh</c> application.</p>
- <p>See <seealso marker="ssh:SSH_app#supported">ssh(6)</seealso> for details of supported version,
- algorithms and unicode support.</p>
+ <p>This is the interface module for the <c>SSH</c> application.
+ The Secure Shell (SSH) Protocol is a protocol for secure remote login
+ and other secure network services over an insecure network.
+ See <seealso marker="ssh:SSH_app#supported">ssh(6)</seealso> for details of supported RFCs, versions,
+ algorithms and unicode handling.
+ </p>
+ <p>With the SSH application it is possible to start <i>clients</i> and to start <i>daemons</i> (servers).
+ </p>
+ <p>Clients are started with
+ <seealso marker="#connect/2">connect/2</seealso>,
+ <seealso marker="#connect/3">connect/3</seealso> or
+ <seealso marker="#connect/4">connect/4</seealso>. They open an encrypted connection on top of TCP/IP.
+ In that encrypted connection one or more channels could be opened with
+ <seealso marker="ssh_connection#session_channel/2">ssh_connection:session_channel/2,4</seealso>.
+ </p>
+ <p>Each channel is an isolated "pipe" between a client-side process and a server-side process. Those process
+ pairs could handle for example file transfers (sftp) or remote command execution (shell, exec and/or cli).
+ If a custom shell is implemented, the user of the client could execute the special commands remotely. Note that
+ the user is not necessarily a human but probably a system interfacing the SSH app.
+ </p>
+ <p>A server-side subssystem (channel) server is requested by the client with
+ <seealso marker="ssh_connection#subsystem/4">ssh_connection:subsystem/4</seealso>.
+ </p>
+ <p>A server (daemon) is started with
+ <seealso marker="#daemon/2">daemon/1</seealso>,
+ <seealso marker="#daemon/2">daemon/2</seealso> or
+ <seealso marker="#daemon/2">daemon/3</seealso>.
+ Possible channel handlers (subsystems) are declared with the
+ <seealso marker="#type-subsystem_daemon_option">subsystem</seealso> option when the daemon is started.
+ </p>
+ <p>To just run a shell on a remote machine, there are functions that bundles the needed
+ three steps needed into one:
+ <seealso marker="#shell/1">shell/1,2,3</seealso>.
+ Similarily, to just open an sftp (file transfer) connection to a remote machine, the simplest way is to use
+ <seealso marker="ssh_sftp#start_channel/1">ssh_sftp:start_channel/1,2,3</seealso>.
+ </p>
+ <p>To write your own client channel handler, use the behaviour
+ <seealso marker="ssh_client_channel">ssh_client_channel</seealso>. For server channel handlers use
+ <seealso marker="ssh_server_channel">ssh_server_channel</seealso> behaviour (replaces ssh_daemon_channel).
+ </p>
+ <p>Both clients and daemons accepts options that controls the exact behaviour. Some options are common to both.
+ The three sets are called
+ <seealso marker="#type-client_options">Client Options</seealso>,
+ <seealso marker="#type-daemon_options">Daemon Options</seealso> and
+ <seealso marker="#type-common_options">Common Options</seealso>.
+ </p>
+ <p>The descriptions of the options uses the
+ <seealso marker="doc/reference_manual:typespec">Erlang Type Language</seealso> with explaining text.
+ </p>
+ <note>
+ <p>The <seealso marker="users_guide">User's Guide</seealso> has examples and a
+ <seealso marker="using_ssh">Getting Started</seealso>
+ section.
+ </p>
+ </note>
</description>
<section>
- <title>OPTIONS</title>
- <p>The exact behaviour of some functions can be adjusted with the use of options which are documented together
- with the functions. Generally could each option be used at most one time in each function call. If given two or more
- times, the effect is not predictable unless explicitly documented.</p>
- <p>The options are of different kinds:</p>
- <taglist>
- <tag>Limits</tag>
- <item><p>which alters limits in the system, for example number of simultaneous login attempts.</p></item>
-
- <tag>Timeouts</tag>
- <item><p>which give some defined behaviour if too long time elapses before a given event or action,
- for example time to wait for an answer.</p></item>
-
- <tag>Callbacks</tag>
- <item><p>which gives the caller of the function the possibility to execute own code on some events,
- for example calling an own logging function or to perform an own login function</p></item>
-
- <tag>Behaviour</tag>
- <item><p>which changes the systems behaviour.</p></item>
- </taglist>
+ <title>Keys and files</title>
+ <p>A number of objects must be present for the SSH application to work.
+ Thoose objects are per default stored in files.
+ The default names, paths and file formats are the same as for
+ <url href="http://www.openssh.com">OpenSSH</url>. Keys could be generated with the <c>ssh-keygen</c>
+ program from OpenSSH. See the
+ <seealso marker="using_ssh#running-an-erlang-ssh-daemon">User's Guide</seealso>.
+ </p>
+
+ <p>The paths could easily be changed by options:
+ <seealso marker="ssh_file#type-user_dir_common_option"><c>user_dir</c></seealso> and
+ <seealso marker="ssh_file#type-system_dir_daemon_option"><c>system_dir</c></seealso>.
+ </p>
+ <p>A completly different storage could be interfaced by writing call-back modules
+ using the behaviours
+ <seealso marker="ssh_client_key_api">ssh_client_key_api</seealso> and/or
+ <seealso marker="ssh_server_key_api">ssh_server_key_api</seealso>.
+ A callback module is installed with the option
+ <seealso marker="#type-key_cb_common_option"><c>key_cb</c></seealso>
+ to the client and/or the daemon.
+ </p>
+
+ <section>
+ <title>Daemons</title>
+ <p>The keys are by default stored in files:</p>
+ <list>
+ <item>Mandatory: one or more <i>Host key(s)</i>, both private and public. Default is to
+ store them in the directory <c>/etc/ssh</c> in the files
+ <list>
+ <item><c>ssh_host_dsa_key</c> and <c>ssh_host_dsa_key.pub</c></item>
+ <item><c>ssh_host_rsa_key</c> and <c>ssh_host_rsa_key.pub</c></item>
+ <item><c>ssh_host_ecdsa_key</c> and <c>ssh_host_ecdsa_key.pub</c></item>
+ </list>
+ <p>The host keys directory could be changed with the option
+ <seealso marker="ssh_file#type-system_dir_daemon_option"><c>system_dir</c></seealso>.</p>
+ </item>
+ <item>Optional: one or more <i>User's public key</i> in case of <c>publickey</c> authorization.
+ Default is to store them concatenated in the file <c>.ssh/authorized_keys</c> in the user's home directory.
+ <p>The user keys directory could be changed with the option
+ <seealso marker="ssh_file#type-user_dir_common_option"><c>user_dir</c></seealso>.</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Clients</title>
+ <p>The keys and some other data are by default stored in files in the directory <c>.ssh</c>
+ in the user's home directory.</p>
+ <p>The directory could be changed with the option
+ <seealso marker="ssh_file#type-user_dir_common_option"><c>user_dir</c></seealso>.
+ </p>
+ <list>
+ <item>Optional: a list of <i>Host public key(s)</i> for previously connected hosts. This list
+ is handled by the SSH application without any need of user assistance. The default
+ is to store them in the file <c>known_hosts</c>.
+ <p>The
+ <seealso marker="#type-host_accepting_client_options">host_accepting_client_options()</seealso>
+ are associated with this list of keys.
+ </p>
+ </item>
+ <item>Optional: one or more <i>User's private key(s)</i> in case of <c>publickey</c> authorization.
+ The default files are
+ <list>
+ <item><c>id_dsa</c> and <c>id_dsa.pub</c></item>
+ <item><c>id_rsa</c> and <c>id_rsa.pub</c></item>
+ <item><c>id_ecdsa</c> and <c>id_ecdsa.pub</c></item>
+ </list>
+ </item>
+ </list>
+ </section>
+
</section>
- <section>
- <title>DATA TYPES</title>
- <p>Type definitions that are used more than once in
- this module, or abstractions to indicate the intended use of the data
- type, or both:</p>
- <taglist>
- <tag><c>boolean() =</c></tag>
- <item><p><c>true | false</c></p></item>
- <tag><c>string() =</c></tag>
- <item><p><c>[byte()]</c></p></item>
- <tag><c>ssh_daemon_ref() =</c></tag>
- <item><p>opaque() -
- as returned by <c>ssh:daemon/[1,2,3]</c></p></item>
- <tag><c>ssh_connection_ref() =</c></tag>
- <item><p>opaque() - as returned by <c>ssh:connect/3</c></p></item>
- <tag><c>ip_address() =</c></tag>
- <item><p><c>inet::ip_address</c></p></item>
- <tag><c>subsystem_spec() =</c></tag>
- <item><p><c>{subsystem_name(),
- {channel_callback(), channel_init_args()}}</c></p></item>
- <tag><c>subsystem_name() =</c></tag>
- <item><p><c>string()</c></p></item>
- <tag><c>channel_callback() =</c></tag>
- <item><p><c>atom()</c> - Name of the Erlang module
- implementing the subsystem using the <c>ssh_channel</c> behavior, see
- <seealso marker="ssh_channel">ssh_channel(3)</seealso></p></item>
- <tag><c>key_cb() =</c></tag>
- <item>
- <p><c>atom() | {atom(), list()}</c></p>
- <p><c>atom()</c> - Name of the erlang module implementing the behaviours
- <seealso marker="ssh_client_key_api">ssh_client_key_api</seealso> or
- <seealso marker="ssh_client_key_api">ssh_client_key_api</seealso> as the
- case maybe.</p>
- <p><c>list()</c> - List of options that can be passed to the callback module.</p>
- </item>
- <tag><c>channel_init_args() =</c></tag>
- <item><p><c>list()</c></p></item>
-
- <tag><c>algs_list() =</c></tag>
- <item><p><c>list( alg_entry() )</c></p></item>
-
- <tag><c>alg_entry() =</c></tag>
- <item><p><c>{kex, simple_algs()} | {public_key, simple_algs()} | {cipher, double_algs()} | {mac, double_algs()} | {compression, double_algs()}</c></p></item>
-
- <tag><c>simple_algs() =</c></tag>
- <item><p><c>list( atom() )</c></p></item>
-
- <tag><c>double_algs() =</c></tag>
- <item><p><c>[{client2serverlist,simple_algs()},{server2client,simple_algs()}] | simple_algs()</c></p></item>
+ <!--
+ ================================================================
+ = Data types =
+ ================================================================
+ -->
- <tag><c>modify_algs_list() =</c></tag>
- <item><p><c>list( {append,algs_list()} | {prepend,algs_list()} | {rm,algs_list()} )</c></p></item>
- </taglist>
-</section>
+ <datatypes>
- <funcs>
-
- <func>
- <name>close(ConnectionRef) -> ok </name>
- <fsummary>Closes an SSH connection.</fsummary>
- <type>
- <v>ConnectionRef = ssh_connection_ref()</v>
- </type>
- <desc><p>Closes an SSH connection.</p>
+ <datatype_title>Client Options</datatype_title>
+
+ <datatype>
+ <name name="client_options"/>
+ <name name="client_option"/>
+ <desc>
+ <p>Options for <seealso marker="#connect/3">clients</seealso>.
+ The individual options are further explained below or by following the hyperlinks.
+ </p>
</desc>
- </func>
-
- <func>
- <name>connect(Host, Port, Options) -> </name>
- <name>connect(Host, Port, Options, Timeout) -> </name>
- <name>connect(TcpSocket, Options) -> </name>
- <name>connect(TcpSocket, Options, Timeout) ->
- {ok, ssh_connection_ref()} | {error, Reason}</name>
- <fsummary>Connects to an SSH server.</fsummary>
- <type>
- <v>Host = string()</v>
- <v>Port = integer()</v>
- <d><c><![CDATA[22]]></c> is default, the assigned well-known port
- number for SSH.</d>
- <v>Options = [{Option, Value}]</v>
- <v>Timeout = infinity | integer()</v>
- <d>Negotiation time-out in milli-seconds. The default value is <c>infinity</c>.
- For connection time-out, use option <c>{connect_timeout, timeout()}</c>.</d>
- <v>TcpSocket = port()</v>
- <d>The socket is supposed to be from <seealso marker="kernel:gen_tcp#connect-3">gen_tcp:connect</seealso> or <seealso marker="kernel:gen_tcp#accept-1">gen_tcp:accept</seealso> with option <c>{active,false}</c></d>
- </type>
+ </datatype>
+
+ <datatype>
+ <name name="host_accepting_client_options"/>
+ <name name="accept_hosts"/>
+ <name name="fp_digest_alg"/>
+ <name name="accept_callback"/>
+ <name name="fingerprint"/>
<desc>
- <p>Connects to an SSH server. No channel is started. This is done
- by calling
- <seealso marker="ssh_connection#session_channel/2">
- ssh_connection:session_channel/[2, 4]</seealso>.</p>
- <p>Options:</p>
<taglist>
- <tag><c><![CDATA[{inet, inet | inet6}]]></c></tag>
- <item>
- <p>IP version to use.</p>
- </item>
- <tag><marker id="opt_user_dir"></marker><c><![CDATA[{user_dir, string()}]]></c></tag>
- <item>
- <p>Sets the user directory, that is, the directory containing
- <c>ssh</c> configuration files for the user, such as
- <c><![CDATA[known_hosts]]></c>, <c><![CDATA[id_rsa,
- id_dsa]]></c>, and
- <c><![CDATA[authorized_key]]></c>. Defaults to the
- directory normally referred to as
- <c><![CDATA[~/.ssh]]></c>.</p>
- </item>
- <tag><c><![CDATA[{dsa_pass_phrase, string()}]]></c></tag>
- <item>
- <p>If the user DSA key is protected by a passphrase, it can be
- supplied with this option.
- </p>
- </item>
- <tag><c><![CDATA[{rsa_pass_phrase, string()}]]></c></tag>
+ <tag><c>silently_accept_hosts</c></tag>
<item>
- <p>If the user RSA key is protected by a passphrase, it can be
- supplied with this option.
- </p>
- </item>
- <tag><c><![CDATA[{ecdsa_pass_phrase, string()}]]></c></tag>
- <item>
- <p>If the user ECDSA key is protected by a passphrase, it can be
- supplied with this option.
- </p>
- </item>
- <tag>
- <c><![CDATA[{silently_accept_hosts, boolean()}]]></c> <br/>
- <c><![CDATA[{silently_accept_hosts, CallbackFun}]]></c> <br/>
- <c><![CDATA[{silently_accept_hosts, {HashAlgoSpec, CallbackFun} }]]></c> <br/>
- <br/>
- <c><![CDATA[HashAlgoSpec = crypto:digest_type() | [ crypto:digest_type() ] ]]></c><br/>
- <c><![CDATA[CallbackFun = fun(PeerName, FingerPrint) -> boolean()]]></c><br/>
- <c><![CDATA[PeerName = string()]]></c><br/>
- <c><![CDATA[FingerPrint = string() | [ string() ] ]]></c>
- </tag>
- <item>
- <p>This option guides the <c>connect</c> function how to act when the connected server presents a Host
+ <p>This option guides the <c>connect</c> function on how to act when the connected server presents a Host
Key that the client has not seen before. The default is to ask the user with a question on stdio of whether to
accept or reject the new Host Key.
- See also the option <seealso marker="#opt_user_dir"><c>user_dir</c></seealso>
- for the path to the file <c>known_hosts</c> where previously accepted Host Keys are recorded.
- </p>
+ See the option <seealso marker="ssh_file#type-user_dir_common_option"><c>user_dir</c></seealso>
+ for specifying the path to the file <c>known_hosts</c> where previously accepted Host Keys are recorded.
+ See also the option
+ <seealso marker="#type-key_cb_common_option">key_cb</seealso>
+ for the general way to handle keys.
+ </p>
<p>The option can be given in three different forms as seen above:</p>
<list>
- <item>The value is a <c>boolean()</c>. The value <c>true</c> will make the client accept any unknown
- Host Key without any user interaction. The value <c>false</c> keeps the default behaviour of asking the
- the user on stdio.
+ <item>The value is a <c>boolean()</c>.
+ The value <c>true</c> will make the client accept any unknown Host Key without any user interaction.
+ The value <c>false</c> preserves the default behaviour of asking the user on stdio.
</item>
- <item>A <c>CallbackFun</c> will be called and the boolean return value <c>true</c> will make the client
- accept the Host Key. A return value of <c>false</c> will make the client to reject the Host Key and therefore
- also the connection will be closed. The arguments to the fun are:
+ <item>An <c>accept_callback()</c> will be called and the boolean return value <c>true</c>
+ will make the client
+ accept the Host Key. A return value of <c>false</c> will make the client to reject the Host Key and as a
+ result the connection will be closed. The arguments to the fun are:
<list type="bulleted">
<item><c>PeerName</c> - a string with the name or address of the remote host.</item>
<item><c>FingerPrint</c> - the fingerprint of the Host Key as
@@ -218,471 +219,338 @@
</item>
</list>
</item>
- <item>A tuple <c>{HashAlgoSpec, CallbackFun}</c>. The <c>HashAlgoSpec</c> specifies which hash algorithm
- shall be used to calculate the fingerprint used in the call of the <c>CallbackFun</c>. The <c>HashALgoSpec</c>
- is either an atom or a list of atoms as the first argument in
- <seealso marker="public_key:public_key#ssh_hostkey_fingerprint-2">public_key:ssh_hostkey_fingerprint/2</seealso>.
- If it is a list of hash algorithm names, the <c>FingerPrint</c> argument in the <c>CallbackFun</c> will be
- a list of fingerprints in the same order as the corresponding name in the <c>HashAlgoSpec</c> list.
+ <item>A tuple <c>{HashAlgoSpec, accept_callback}</c>. The <c>HashAlgoSpec</c>
+ specifies which hash algorithm
+ shall be used to calculate the fingerprint used in the call of the <c>accept_callback()</c>.
+ The <c>HashALgoSpec</c>
+ is either an atom or a list of atoms as the first argument in
+ <seealso marker="public_key:public_key#ssh_hostkey_fingerprint-2">public_key:ssh_hostkey_fingerprint/2</seealso>.
+ If it is a list of hash algorithm names, the <c>FingerPrint</c> argument in the
+ <c>accept_callback()</c> will be
+ a list of fingerprints in the same order as the corresponding name in the <c>HashAlgoSpec</c> list.
</item>
</list>
</item>
-
- <tag><c><![CDATA[{save_accepted_host, boolean()}]]></c></tag>
- <item>
- <p>If <c>true</c>, the client saves an accepted host key to avoid the
- accept question the next time the same host is connected. If the option
- <c>key_cb</c> is not present, the key is saved in the file "known_hosts".
- </p>
- <p>If <c>false</c>, the key is not saved and the key will still be unknown
- at the next access of the same host.
- </p>
- </item>
-
- <tag><c><![CDATA[{user_interaction, boolean()}]]></c></tag>
+
+ <tag><c>user_interaction</c></tag>
<item>
<p>If <c>false</c>, disables the client to connect to the server
if any user interaction is needed, such as accepting
the server to be added to the <c>known_hosts</c> file, or
- supplying a password. Defaults to <c>true</c>.
- Even if user interaction is allowed it can be
+ supplying a password.</p>
+ <p>Even if user interaction is allowed it can be
suppressed by other options, such as <c>silently_accept_hosts</c>
and <c>password</c>. However, those options are not always desirable
to use from a security point of view.</p>
+ <p>Defaults to <c>true</c>.</p>
</item>
- <tag><c><![CDATA[{disconnectfun, fun(Reason:term()) -> _}]]></c></tag>
- <item>
- <p>Provides a fun to implement your own logging when a server disconnects the client.</p>
- </item>
-
- <tag><c><![CDATA[{unexpectedfun, fun(Message:term(), Peer) -> report | skip }]]></c></tag>
- <item>
- <p>Provides a fun to implement your own logging or other action when an unexpected message arrives.
- If the fun returns <c>report</c> the usual info report is issued but if <c>skip</c> is returned no
- report is generated.</p>
- <p><c>Peer</c> is in the format of <c>{Host,Port}</c>.</p>
- </item>
-
- <tag><c><![CDATA[{pref_public_key_algs, list()}]]></c></tag>
- <item>
- <p>List of user (client) public key algorithms to try to use.</p>
- <p>The default value is the <c>public_key</c> entry in
- <seealso marker="#default_algorithms/0">ssh:default_algorithms/0</seealso>.
- </p>
- <p>If there is no public key of a specified type available, the corresponding entry is ignored.
- Note that the available set is dependent on the underlying cryptolib and current user's public keys.
- </p>
- </item>
-
- <tag><marker id="option_preferred_algorithms"></marker>
- <c><![CDATA[{preferred_algorithms, algs_list()}]]></c></tag>
+ <tag><c>save_accepted_host</c></tag>
<item>
- <p>List of algorithms to use in the algorithm negotiation. The default <c>algs_list()</c> can
- be obtained from <seealso marker="#default_algorithms/0">default_algorithms/0</seealso>.
+ <p>If <c>true</c>, the client saves an accepted host key to avoid the
+ accept question the next time the same host is connected. If the option
+ <seealso marker="#type-key_cb_common_option"><c>key_cb</c></seealso>
+ is not present, the key is saved in the file "known_hosts". See option
+ <seealso marker="ssh_file#type-user_dir_common_option"><c>user_dir</c></seealso> for
+ the location of that file.
</p>
- <p>If an alg_entry() is missing in the algs_list(), the default value is used for that entry.</p>
- <p>Here is an example of this option:</p>
- <code>
-{preferred_algorithms,
- [{public_key,['ssh-rsa','ssh-dss']},
- {cipher,[{client2server,['aes128-ctr']},
- {server2client,['aes128-cbc','3des-cbc']}]},
- {mac,['hmac-sha2-256','hmac-sha1']},
- {compression,[none,zlib]}
- ]
-}
-</code>
- <p>The example specifies different algorithms in the two directions (client2server and server2client),
- for cipher but specifies the same algorithms for mac and compression in both directions.
- The kex (key exchange) is implicit but public_key is set explicitly.</p>
-
- <p>For background and more examples see the <seealso marker="configure_algos#introduction">User's Guide</seealso>.</p>
-
- <warning>
- <p>Changing the values can make a connection less secure. Do not change unless you
- know exactly what you are doing. If you do not understand the values then you
- are not supposed to change them.</p>
- </warning>
- </item>
-
- <tag><marker id="option_modify_algorithms"></marker>
- <c><![CDATA[{modify_algorithms, modify_algs_list()}]]></c></tag>
- <item>
- <p>Modifies the list of algorithms to use in the algorithm negotiation. The modifications are
- applied after the option <c>preferred_algorithms</c> (if existing) is applied.</p>
- <p>The algoritm for modifications works like this:</p>
- <list>
- <item>
- <p>Input is the <c>modify_algs_list()</c> and a set of algorithms <c>A</c>
- obtained from the <c>preferred_algorithms</c> option if existing, or else from the
- <seealso marker="ssh#default_algorithms-0">ssh:default_algorithms/0</seealso>.
- </p>
- </item>
- <item>
- <p>The head of the <c>modify_algs_list()</c> modifies <c>A</c> giving the result <c>A'</c>.</p>
- <p>The possible modifications are:</p>
- <list>
- <item>
- <p>Append or prepend supported but not enabled algorithm(s) to the list of
- algorithms. If the wanted algorithms already are in <c>A</c> they will first
- be removed and then appended or prepended,
- </p>
- </item>
- <item>
- <p>Remove (rm) one or more algorithms from <c>A</c>.
- </p>
- </item>
- </list>
- </item>
- <item>
- <p>Repeat the modification step with the tail of <c>modify_algs_list()</c> and the resulting
- <c>A'</c>.
- </p>
- </item>
- </list>
- <p>If an unsupported algorithm is in the <c>modify_algs_list()</c>, it will be silently ignored</p>
- <p>If there are more than one modify_algorithms options, the result is undefined.</p>
- <p>Here is an example of this option:</p>
- <code>
-{modify_algorithms,
- [{prepend, [{kex, ['diffie-hellman-group1-sha1']}],
- {rm, [{compression, [none]}]}
- ]
-}
-</code>
- <p>The example specifies that:</p>
- <list>
- <item><p>the old key exchange algorithm 'diffie-hellman-group1-sha1' should be
- the main alternative. It will be the main alternative since it is prepened to the list</p>
- </item>
- <item><p>The compression algorithm none (= no compression) is removed so compression is enforced</p>
- </item>
- </list>
- <p>For background and more examples see the <seealso marker="configure_algos#introduction">User's Guide</seealso>.</p>
- </item>
-
- <tag><c><![CDATA[{dh_gex_limits,{Min=integer(),I=integer(),Max=integer()}}]]></c></tag>
- <item>
- <p>Sets the three diffie-hellman-group-exchange parameters that guides the connected server in choosing a group.
- See RFC 4419 for the function of thoose. The default value is <c>{1024, 6144, 8192}</c>.
+ <p>If <c>false</c>, the key is not saved and the key will still be unknown
+ at the next access of the same host.
</p>
+ <p>Defaults to <c>true</c></p>
</item>
- <tag><c><![CDATA[{connect_timeout, timeout()}]]></c></tag>
+ <tag><c>quiet_mode</c></tag>
<item>
- <p>Sets a time-out on the transport layer
- connection. For <c>gen_tcp</c> the time is in milli-seconds and the default value is
- <c>infinity</c>.</p>
+ <p>If <c>true</c>, the client does not print anything on authorization.</p>
+ <p>Defaults to <c>false</c></p>
</item>
+ </taglist>
+ </desc>
+ </datatype>
- <tag><c><![CDATA[{auth_methods, string()}]]></c></tag>
- <item>
- <p>Comma-separated string that determines which
- authentication methods that the client shall support and
- in which order they are tried. Defaults to
- <c><![CDATA["publickey,keyboard-interactive,password"]]></c></p>
- </item>
-
- <tag><c><![CDATA[{user, string()}]]></c></tag>
+ <datatype>
+ <name name="authentication_client_options"/>
+ <desc>
+ <taglist>
+ <tag><c>user</c></tag>
<item>
- <p>Provides a username. If this option is not given, <c>ssh</c>
+ <p>Provides the username. If this option is not given, <c>ssh</c>
reads from the environment (<c><![CDATA[LOGNAME]]></c> or
<c><![CDATA[USER]]></c> on UNIX,
<c><![CDATA[USERNAME]]></c> on Windows).</p>
</item>
- <tag><c><![CDATA[{password, string()}]]></c></tag>
+ <tag><c>password</c></tag>
<item>
<p>Provides a password for password authentication.
If this option is not given, the user is asked for a
password, if the password authentication method is
attempted.</p>
</item>
-
- <!--tag><c><![CDATA[{send_ext_info, boolean()}]]></c></tag>
- <item>
- <p>Send a list of extensions to the server if the server has asked for it. See
- <url href="https://tools.ietf.org/html/draft-ietf-curdle-ssh-ext-info">Draft-ietf-curdle-ssh-ext-info (work in progress)</url> for details.
- </p>
- <p>Currently the client do not react on any extensions.
- </p>
- <p>Default value is <c>true</c>.
- </p>
- </item-->
-
- <tag><c><![CDATA[{recv_ext_info, boolean()}]]></c></tag>
- <item>
- <p>Tell the server that the client accepts extension negotiation. See
- <url href="https://tools.ietf.org/html/draft-ietf-curdle-ssh-ext-info">Draft-ietf-curdle-ssh-ext-info (work in progress)</url> for details.
- </p>
- <p>Currently implemented extension is <c>server-sig-algs</c> which is the list of the server's preferred
- user's public key algorithms.
- </p>
- <p>Default value is <c>true</c>.
- </p>
- </item>
-
- <tag><c><![CDATA[{key_cb, key_cb()}]]></c></tag>
- <item>
- <p>Module implementing the behaviour <seealso
- marker="ssh_client_key_api">ssh_client_key_api</seealso>. Can be used to
- customize the handling of public keys. If callback options are provided
- along with the module name, they are made available to the callback
- module via the options passed to it under the key 'key_cb_private'.
- </p>
- </item>
-
- <tag><c><![CDATA[{quiet_mode, atom() = boolean()}]]></c></tag>
- <item>
- <p>If <c>true</c>, the client does not print anything on authorization.</p>
- </item>
-
- <tag><c><![CDATA[{id_string, random | string()}]]></c></tag>
- <item>
- <p>The string that the client presents to a connected server initially. The default value is "Erlang/VSN" where VSN is the ssh application version number.
- </p>
- <p>The value <c>random</c> will cause a random string to be created at each connection attempt. This is to make it a bit more difficult for a malicious peer to find the ssh software brand and version.
- </p>
- </item>
-
- <tag><c><![CDATA[{fd, file_descriptor()}]]></c></tag>
- <item>
- <p>Allows an existing file descriptor to be used
- (by passing it on to the transport protocol).</p></item>
- <tag><c><![CDATA[{rekey_limit, integer()}]]></c></tag>
- <item>
- <p>Provides, in bytes, when rekeying is to be initiated.
- Defaults to once per each GB and once per hour.</p>
- </item>
- <tag><c><![CDATA[{idle_time, integer()}]]></c></tag>
- <item>
- <p>Sets a time-out on a connection when no channels are active.
- Defaults to <c>infinity</c>.</p></item>
- <tag><c><![CDATA[{ssh_msg_debug_fun, fun(ConnectionRef::ssh_connection_ref(), AlwaysDisplay::boolean(), Msg::binary(), LanguageTag::binary()) -> _}]]></c></tag>
- <item>
- <p>Provide a fun to implement your own logging of the SSH message SSH_MSG_DEBUG. The last three parameters are from the message, see RFC4253, section 11.3. The <c>ConnectionRef</c> is the reference to the connection on which the message arrived. The return value from the fun is not checked.</p>
- <p>The default behaviour is ignore the message.
- To get a printout for each message with <c>AlwaysDisplay = true</c>, use for example <c>{ssh_msg_debug_fun, fun(_,true,M,_)-> io:format("DEBUG: ~p~n", [M]) end}</c></p>
- </item>
-
</taglist>
- </desc>
- </func>
+ </desc>
+ </datatype>
- <func>
- <name>connection_info(ConnectionRef, [Option]) ->[{Option,
- Value}]</name>
- <fsummary>Retrieves information about a connection.</fsummary>
- <type>
- <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>
+ <datatype>
+ <name name="diffie_hellman_group_exchange_client_option"/>
<desc>
- <p>Retrieves information about a connection.</p>
+ <p>Sets the three diffie-hellman-group-exchange parameters that guides the connected server in choosing a group.
+ See
+ <url href="https://tools.ietf.org/html/rfc4419">RFC 4419</url>
+ for the details. The default value is <c>{1024, 6144, 8192}</c>.
+ </p>
</desc>
- </func>
-
- <func>
- <name>daemon(Port) -> </name>
- <name>daemon(Port, Options) -> </name>
- <name>daemon(HostAddress, Port, Options) -> </name>
- <name>daemon(TcpSocket) -> </name>
- <name>daemon(TcpSocket, Options) -> {ok, ssh_daemon_ref()} | {error, atom()}</name>
- <fsummary>Starts a server listening for SSH connections
- on the given port.</fsummary>
- <type>
- <v>Port = integer()</v>
- <v>HostAddress = ip_address() | any | loopback</v>
- <v>Options = [{Option, Value}]</v>
- <v>Option = atom()</v>
- <v>Value = term()</v>
- <v>TcpSocket = port()</v>
- <d>The socket is supposed to be from <seealso marker="kernel:gen_tcp#connect-3">gen_tcp:connect</seealso> or <seealso marker="kernel:gen_tcp#accept-1">gen_tcp:accept</seealso> with option <c>{active,false}</c></d>
- </type>
- <desc>
- <p>Starts a server listening for SSH connections on the given
- port. If the <c>Port</c> is 0, a random free port is selected. See
- <seealso marker="#daemon_info/1">daemon_info/1</seealso> about how to find the selected port number.</p>
+ </datatype>
- <p>Please note that by historical reasons both the <c>HostAddress</c> argument and the inet socket option
- <c>ip</c> set the listening address. This is a source of possible inconsistent settings.</p>
+ <datatype>
+ <name name="connect_timeout_client_option"/>
+ <desc>
+ <p>Sets a timeout on the transport layer connect time.
+ For <seealso marker="kernel:gen_tcp"><c>gen_tcp</c></seealso> the time is in milli-seconds and the default
+ value is <c>infinity</c>.
+ </p>
+ <p>See the parameter <c>Timeout</c> in <seealso marker="#connect/4">connect/4</seealso> for
+ a timeout of the negotiation phase.
+ </p>
+ </desc>
+ </datatype>
- <p>The rules for handling the two address passing options are:</p>
- <list>
- <item>if <c>HostAddress</c> is an IP-address, that IP-address is the listening address.
- An 'ip'-option will be discarded if present.</item>
+ <datatype>
+ <name name="recv_ext_info_client_option"/>
+ <desc>
+ <p>Make the client tell the server that the client accepts extension negotiation, that is,
+ include <c>ext-info-c</c> in the kexinit message sent. See
+ <url href="https://tools.ietf.org/html/rfc8308">RFC 8308</url>
+ for details and <seealso marker="SSH_app#supported-ext-info">ssh(6)</seealso>
+ for a list of currently implemented extensions.
+ </p>
+ <p>
+ Default value is <c>true</c> which is compatible with other implementations not supporting ext-info.
+ </p>
+ </desc>
+ </datatype>
- <item>if <c>HostAddress</c> is <c>loopback</c>, the listening address
- is <c>loopback</c> and an loopback address will be choosen by the underlying layers.
- An 'ip'-option will be discarded if present.</item>
+ <!--................................................................-->
+ <datatype_title>Daemon Options (Server Options)</datatype_title>
- <item>if <c>HostAddress</c> is <c>any</c> and no 'ip'-option is present, the listening address is
- <c>any</c> and the socket will listen to all addresses</item>
+ <datatype>
+ <name name="daemon_options"/>
+ <name name="daemon_option"/>
+ <desc>
+ <p>Options for <seealso marker="#daemon/1">daemons</seealso>.
+ The individual options are further explained below or by following the hyperlinks.
+ </p>
+ </desc>
+ </datatype>
- <item>if <c>HostAddress</c> is <c>any</c> and an 'ip'-option is present, the listening address is
- set to the value of the 'ip'-option</item>
- </list>
+
+ <datatype>
+ <name name="subsystem_daemon_option"/>
+ <name name="subsystem_spec"/>
+ <desc>
+ <p>Defines a subsystem in the daemon.</p>
+ <p>The <c>subsystem_name</c> is the name that a client requests to start with for example
+ <seealso marker="ssh_connection#subsystem/4">ssh_connection:subsystem/4</seealso>.
+ </p>
+ <p>The <c>channel_callback</c> is the module that implements the
+ <seealso marker="ssh_server_channel">ssh_server_channel</seealso> (replaces ssh_daemon_channel)
+ behaviour in the daemon. See the section
+ <seealso marker="using_ssh#usersguide_creating_a_subsystem">Creating a Subsystem</seealso>
+ in the User's Guide for more information and an example.
+ </p>
+ <p>If the subsystems option is not present, the value of <c>ssh_sftpd:subsystem_spec([])</c> is used.
+ This enables the sftp subsystem by default.
+ The option can be set to the empty list if you do not want the daemon to run any subsystems.</p>
+ </desc>
+ </datatype>
- <p>Options:</p>
- <taglist>
- <tag><c><![CDATA[{inet, inet | inet6}]]></c></tag>
- <item><p>IP version to use when the host address is specified as <c>any</c>.</p></item>
- <tag><c><![CDATA[{subsystems, [subsystem_spec()]}]]></c></tag>
+ <datatype>
+ <name name="shell_daemon_option"/>
+ <name name="'shell_fun/1'"/>
+ <name name="'shell_fun/2'"/>
+ <desc>
+ <p>Defines the read-eval-print loop used in a daemon when a shell is requested by the client.
+ The default is to use the Erlang shell: <c><![CDATA[{shell, start, []}]]></c>
+ </p>
+ <p>See the option <seealso marker="#type-exec_daemon_option"><c>exec</c></seealso>
+ for a description of how the daemon execute exec-requests depending on
+ the shell- and exec-options.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="exec_daemon_option"/>
+ <name name="exec_spec"/>
+ <desc/>
+ </datatype>
+ <datatype>
+ <name name="exec_fun"/>
+ <desc/>
+ </datatype>
+ <datatype>
+ <name name="'exec_fun/1'"/>
+ <name name="'exec_fun/2'"/>
+ <name name="'exec_fun/3'"/>
+ <desc/>
+ </datatype>
+ <datatype>
+ <name name="exec_result"/>
+ <desc>
+ <p>This option changes how the daemon execute exec-requests from clients. The term in the return value
+ is formatted to a string if it is a non-string type. No trailing newline is added in the ok-case but in the
+ error case.</p>
+ <p>Error texts are returned on channel-type 1 which usually is piped to <c>stderr</c> on e.g Linux systems.
+ Texts from a successful execution will in similar manner be piped to <c>stdout</c>. The exit-status code
+ is set to 0 for success and -1 for errors. The exact results presented on the client side depends on the
+ client and the client's operating system.
+ </p>
+ <p>The option cooperates with the daemon-option <seealso marker="#type-shell_daemon_option"><c>shell</c></seealso>
+ in the following way:</p>
+ <taglist>
+ <tag>1. If the exec-option is present (the shell-option may or may not be present):</tag>
<item>
- <p>Provides specifications for handling of subsystems. The
- "sftp" subsystem specification is retrieved by calling
- <c>ssh_sftpd:subsystem_spec/1</c>. If the subsystems option is
- not present, the value of
- <c>[ssh_sftpd:subsystem_spec([])]</c> is used.
- The option can be set to the empty list if
- you do not want the daemon to run any subsystems.</p>
+ <p>The exec-option fun is called with the same number of parameters as the arity of the fun,
+ and the result is returned to the client.
+ </p>
</item>
- <tag><c><![CDATA[{shell, {Module, Function, Args} |
- fun(string() = User) - > pid() | fun(string() = User,
- ip_address() = PeerAddr) -> pid()}]]></c></tag>
+
+ <tag>2. If the exec-option is absent, but a shell-option is present with the default Erlang shell:</tag>
<item>
- <p>Defines the read-eval-print loop used when a shell is
- requested by the client. The default is to use the Erlang shell:
- <c><![CDATA[{shell, start, []}]]></c></p>
+ <p>The default Erlang evaluator is used and the result is returned to the client.</p>
</item>
- <tag><c><![CDATA[{ssh_cli, {channel_callback(),
- channel_init_args()} | no_cli}]]></c></tag>
+
+ <tag>3. If the exec-option is absent, but a shell-option is present that is not the default Erlang shell:</tag>
<item>
- <p>Provides your own CLI implementation, that is, a channel callback
- module that implements a shell and command execution. The shell
- read-eval-print loop can be customized, using the
- option <c>shell</c>. This means less work than implementing
- an own CLI channel. If set to <c>no_cli</c>, the CLI channels
- are disabled and only subsystem channels are allowed.</p>
+ <p>The exec-request is not evaluated and an error message is returned to the client.</p>
</item>
- <tag><c><![CDATA[{user_dir, string()}]]></c></tag>
+
+ <tag>4. If neither the exec-option nor the shell-option is present:</tag>
<item>
- <p>Sets the user directory. That is, the directory containing
- <c>ssh</c> configuration files for the user, such as
- <c><![CDATA[known_hosts]]></c>, <c><![CDATA[id_rsa,
- id_dsa]]></c>, and
- <c><![CDATA[authorized_key]]></c>. Defaults to the
- directory normally referred to as
- <c><![CDATA[~/.ssh]]></c>.</p>
- </item>
- <tag><c><![CDATA[{system_dir, string()}]]></c></tag>
- <item>
- <p>Sets the system directory, containing the host key files
- that identify the host keys for <c>ssh</c>. Defaults to
- <c><![CDATA[/etc/ssh]]></c>. For security reasons,
- this directory is normally accessible only to the root user.</p>
+ <p>The default Erlang evaluator is used and the result is returned to the client.</p>
</item>
+ </taglist>
+ <p>If a custom CLI is installed (see the option <seealso marker="#type-ssh_cli_daemon_option"><c>ssh_cli</c></seealso>)
+ the rules above are replaced by thoose implied by the custom CLI.
+ </p>
+ <note>
+ <p>The exec-option has existed for a long time but has not previously been documented. The old
+ definition and behaviour are retained but obey the rules 1-4 above if conflicting.
+ The old and undocumented style should not be used in new programs.</p>
+ </note>
+ </desc>
+ </datatype>
- <tag><c><![CDATA[{auth_methods, string()}]]></c></tag>
- <item>
- <p>Comma-separated string that determines which
- authentication methods that the server is to support and
- in what order they are tried. Defaults to
- <c><![CDATA["publickey,keyboard-interactive,password"]]></c></p>
- <p>Note that the client is free to use any order and to exclude methods.</p>
- </item>
-
- <tag><c><![CDATA[{auth_method_kb_interactive_data, PromptTexts}]]></c>
- <br/><c>where:</c>
- <br/><c>PromptTexts = kb_int_tuple() | fun(Peer::{IP::tuple(),Port::integer()}, User::string(), Service::string()) -> kb_int_tuple()</c>
- <br/><c>kb_int_tuple() = {Name::string(), Instruction::string(), Prompt::string(), Echo::boolean()}</c>
- </tag>
+ <datatype>
+ <name name="ssh_cli_daemon_option"/>
+ <desc>
+ <p>Provides your own CLI implementation in a daemon.</p>
+ <p>It is a channel callback module that implements a shell
+ and command execution. The shell's read-eval-print loop can be customized, using the
+ option <seealso marker="#type-shell_daemon_option"><c>shell</c></seealso>. This means less work than implementing
+ an own CLI channel. If <c>ssh_cli</c> is set to <c>no_cli</c>, the CLI channels
+ like <seealso marker="#type-shell_daemon_option"><c>shell</c></seealso>
+ and <seealso marker="#type-exec_daemon_option"><c>exec</c></seealso>
+ are disabled and only subsystem channels are allowed.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="authentication_daemon_options"/>
+ <name name="prompt_texts"/>
+ <name name="kb_int_tuple"/>
+ <name name="kb_int_fun_3"/>
+ <name name="pwdfun_2"/>
+ <name name="pwdfun_4"/>
+ <desc>
+ <taglist>
+ <tag><c>auth_method_kb_interactive_data</c></tag>
<item>
- <p>Sets the text strings that the daemon sends to the client for presentation to the user when using <c>keyboar-interactive</c> authentication. If the fun/3 is used, it is called when the actual authentication occurs and may therefore return dynamic data like time, remote ip etc.</p>
+ <p>Sets the text strings that the daemon sends to the client for presentation to the user when
+ using <c>keyboard-interactive</c> authentication.</p>
+ <p>If the fun/3 is used, it is called when the actual authentication occurs and may therefore
+ return dynamic data like time, remote ip etc.</p>
<p>The parameter <c>Echo</c> guides the client about need to hide the password.</p>
<p>The default value is:
- <c>{auth_method_kb_interactive_data, {"SSH server", "Enter password for \""++User++"\"", "password: ", false}></c></p>
+ <c>{auth_method_kb_interactive_data, {"SSH server", "Enter password for \""++User++"\"", "password: ", false}></c>
+ </p>
</item>
- <tag><c><![CDATA[{user_passwords, [{string() = User,
- string() = Password}]}]]></c></tag>
+ <tag><marker id="option-user_passwords"/><c>user_passwords</c></tag>
<item>
- <p>Provides passwords for password authentication. The passwords
- are used when someone tries to connect to the server and
- public key user-authentication fails. The option provides
+ <p>Provides passwords for password authentication. The passwords are used when someone tries
+ to connect to the server and public key user-authentication fails. The option provides
a list of valid usernames and the corresponding passwords.
</p>
</item>
- <tag><c><![CDATA[{password, string()}]]></c></tag>
+
+ <tag><marker id="option-password"/><c>password</c></tag>
<item>
- <p>Provides a global password that authenticates any
- user. From a security perspective this option makes
- the server very vulnerable.</p>
+ <p>Provides a global password that authenticates any user.</p>
+ <warning>
+ <p>Intended to facilitate testing.</p>
+ <p>From a security perspective this option makes the server very vulnerable.</p>
+ </warning>
</item>
- <tag><c><![CDATA[{preferred_algorithms, algs_list()}]]></c></tag>
+ <tag><marker id="option-pwdfun"/><c>pwdfun</c> with
+ <seealso marker="#type-pwdfun_4"><c>pwdfun_4()</c></seealso>
+ </tag>
<item>
- <p>List of algorithms to use in the algorithm negotiation. The default <c>algs_list()</c> can
- be obtained from <seealso marker="#default_algorithms/0">default_algorithms/0</seealso>.
+ <p>Provides a function for password validation. This could used for calling an external system or handeling
+ passwords stored as hash values.
</p>
- <p>If an alg_entry() is missing in the algs_list(), the default value is used for that entry.</p>
- <p>Here is an example of this option:</p>
- <code>
-{preferred_algorithms,
- [{public_key,['ssh-rsa','ssh-dss']},
- {cipher,[{client2server,['aes128-ctr']},
- {server2client,['aes128-cbc','3des-cbc']}]},
- {mac,['hmac-sha2-256','hmac-sha1']},
- {compression,[none,zlib]}
- ]
-}
-</code>
- <p>The example specifies different algorithms in the two directions (client2server and server2client),
- for cipher but specifies the same algorithms for mac and compression in both directions.
- The kex (key exchange) is implicit but public_key is set explicitly.</p>
-
- <p>For background and more examples see the <seealso marker="configure_algos#introduction">User's Guide</seealso>.</p>
+ <p>This fun can also be used to make delays in authentication tries for example by calling
+ <seealso marker="stdlib:timer#sleep/1">timer:sleep/1</seealso>.</p>
+ <p>To facilitate for instance counting of failed tries,
+ the <c>State</c> variable could be used. This state is per connection only. The first time the pwdfun
+ is called for a connection, the <c>State</c> variable has the value <c>undefined</c>.
+ </p>
+
+ <p>The fun should return:
+ </p>
+ <list type="bulleted">
+ <item><c>true</c> if the user and password is valid</item>
+ <item><c>false</c> if the user or password is invalid</item>
+ <item><c>disconnect</c> if a SSH_MSG_DISCONNECT message should be sent immediately. It will
+ be followed by a close of the underlying tcp connection.</item>
+ <item><c>{true, NewState:any()}</c> if the user and password is valid</item>
+ <item><c>{false, NewState:any()}</c> if the user or password is invalid</item>
+ </list>
- <warning>
- <p>Changing the values can make a connection less secure. Do not change unless you
- know exactly what you are doing. If you do not understand the values then you
- are not supposed to change them.</p>
- </warning>
+ <p>A third usage is to block login attempts from a missbehaving peer. The <c>State</c> described above
+ can be used for this. The return value <c>disconnect</c> is useful for this.</p>
</item>
- <tag><marker id="option_modify_algorithms"></marker>
- <c><![CDATA[{modify_algorithms, modify_algs_list()}]]></c></tag>
+ <tag><c>pwdfun</c> with
+ <seealso marker="#type-pwdfun_2"><c>pwdfun_2()</c></seealso>
+ </tag>
<item>
- <p>Modifies the list of algorithms to use in the algorithm negotiation. The modifications are
- applied after the option <c>preferred_algorithms</c> is applied (if existing)</p>
- <p>The possible modifications are to:</p>
- <list>
- <item><p>Append or prepend supported but not enabled algorithm(s) to the list of
- algorithms.</p><p>If the wanted algorithms already are in the list of algorithms, they will first
- be removed and then appended or prepended.
- </p>
- </item>
- <item><p>Remove (rm) one or more algorithms from the list of algorithms.</p></item>
+ <p>Provides a function for password validation. This function is called with user and password
+ as strings, and returns:</p>
+ <list type="bulleted">
+ <item><c>true</c> if the user and password is valid</item>
+ <item><c>false</c> if the user or password is invalid</item>
</list>
- <p>If an unsupported algorithm is in the list, it will be silently ignored</p>
-
- <p>Here is an example of this option:</p>
- <code>
-{modify_algorithms,
- [{prepend, [{kex, ['diffie-hellman-group1-sha1']}],
- {rm, [{compression, [none]}]}
- ]
-}
-</code>
- <p>The example specifies that:</p>
- <list>
- <item><p>the old key exchange algorithm 'diffie-hellman-group1-sha1' should be
- the main alternative. It will be the main alternative since it is prepened to the list</p>
- </item>
- <item><p>The compression algorithm none (= no compression) is removed so compression is enforced</p>
- </item>
- </list>
- <p>For background and more examples see the <seealso marker="configure_algos#introduction">User's Guide</seealso>.</p>
+ <p>This variant is kept for compatibility.</p>
</item>
+ </taglist>
+ </desc>
+ </datatype>
- <tag><c><![CDATA[{dh_gex_groups, [{Size=integer(),G=integer(),P=integer()}] | {file,filename()} {ssh_moduli_file,filename()} }]]></c></tag>
+ <datatype>
+ <name name="diffie_hellman_group_exchange_daemon_option"/>
+ <name name="explicit_group"/>
+ <name name="explicit_group_file"/>
+ <name name="ssh_moduli_file"/>
+ <desc>
+ <taglist>
+ <tag><c>dh_gex_groups</c></tag>
<item>
<p>Defines the groups the server may choose among when diffie-hellman-group-exchange is negotiated.
- See RFC 4419 for details. The three variants of this option are:
+ See
+ <url href="https://tools.ietf.org/html/rfc4419">RFC 4419</url>
+ for details. The three variants of this option are:
</p>
<taglist>
<tag><c>{Size=integer(),G=integer(),P=integer()}</c></tag>
@@ -704,7 +572,7 @@
</p>
</item>
- <tag><c><![CDATA[{dh_gex_limits,{Min=integer(),Max=integer()}}]]></c></tag>
+ <tag><c>dh_gex_limits</c></tag>
<item>
<p>Limits what a client can ask for in diffie-hellman-group-exchange.
The limits will be
@@ -715,57 +583,29 @@
</p>
<p>If <c>MaxUsed &lt; MinUsed</c> in a key exchange, it will fail with a disconnect.
</p>
- <p>See RFC 4419 for the function of the Max and Min values.</p>
- </item>
-
- <tag><c><![CDATA[{pwdfun, fun(User::string(), Password::string(), PeerAddress::{ip_adress(),port_number()}, State::any()) -> boolean() | disconnect | {boolean(),any()} }]]></c></tag>
- <item>
- <p>Provides a function for password validation. This could used for calling an external system or if
- passwords should be stored as a hash. The fun returns:
- </p>
- <list type="bulleted">
- <item><c>true</c> if the user and password is valid and</item>
- <item><c>false</c> otherwise.</item>
- </list>
- <p>This fun can also be used to make delays in authentication tries for example by calling
- <seealso marker="stdlib:timer#sleep/1">timer:sleep/1</seealso>. To facilitate counting of failed tries
- the <c>State</c> variable could be used. This state is per connection only. The first time the pwdfun
- is called for a connection, the <c>State</c> variable has the value <c>undefined</c>.
- The pwdfun can return - in addition to the values above - a new state
- as:
- </p>
- <list type="bulleted">
- <item><c>{true, NewState:any()}</c> if the user and password is valid or</item>
- <item><c>{false, NewState:any()}</c> if the user or password is invalid</item>
- </list>
- <p>A third usage is to block login attempts from a missbehaving peer. The <c>State</c> described above
- can be used for this. In addition to the responses above, the following return value is introduced:
- </p>
- <list type="bulleted">
- <item><c>disconnect</c> if the connection should be closed immediately after sending a SSH_MSG_DISCONNECT
- message.</item>
- </list>
- </item>
-
- <tag><c><![CDATA[{pwdfun, fun(User::string(), Password::string()) -> boolean()}]]></c></tag>
- <item>
- <p>Provides a function for password validation. This function is called
- with user and password as strings, and returns
- <c><![CDATA[true]]></c> if the password is valid and
- <c><![CDATA[false]]></c> otherwise.</p>
- <p>This option (<c>{pwdfun,fun/2}</c>) is the same as a subset of the previous
- (<c>{pwdfun,fun/4}</c>). It is kept for compatibility.</p>
+ <p>See
+ <url href="https://tools.ietf.org/html/rfc4419">RFC 4419</url>
+ for the function of the Max and Min values.</p>
</item>
+ </taglist>
+ </desc>
+ </datatype>
- <tag><c><![CDATA[{negotiation_timeout, integer()}]]></c></tag>
- <item>
- <p>Maximum time in milliseconds for the authentication negotiation.
- Defaults to 120000 (2 minutes). If the client fails to log in within this time,
- the connection is closed.
- </p>
- </item>
+ <datatype>
+ <name name="negotiation_timeout_daemon_option"/>
+ <desc>
+ <p>Maximum time in milliseconds for the authentication negotiation.
+ Defaults to 120000 ms (2 minutes). If the client fails to log in within this time,
+ the connection is closed.
+ </p>
+ </desc>
+ </datatype>
- <tag><c><![CDATA[{max_sessions, pos_integer()}]]></c></tag>
+ <datatype>
+ <name name="hardening_daemon_options"/>
+ <desc>
+ <taglist>
+ <tag><c>max_sessions</c></tag>
<item>
<p>The maximum number of simultaneous sessions that are accepted at any time
for this daemon. This includes sessions that are being authorized.
@@ -785,7 +625,7 @@
</p>
</item>
- <tag><c><![CDATA[{max_channels, pos_integer()}]]></c></tag>
+ <tag><c>max_channels</c></tag>
<item>
<p>The maximum number of channels with active remote subsystem that are accepted for
each connection to this daemon</p>
@@ -793,8 +633,7 @@
</p>
</item>
-
- <tag><c><![CDATA[{parallel_login, boolean()}]]></c></tag>
+ <tag><c>parallel_login</c></tag>
<item>
<p>If set to false (the default value), only one login is handled at a time.
If set to true, an unlimited number of login attempts are allowed simultaneously.
@@ -811,171 +650,562 @@
</warning>
</item>
- <tag><c><![CDATA[{minimal_remote_max_packet_size, non_negative_integer()}]]></c></tag>
+ <tag><c>minimal_remote_max_packet_size</c></tag>
<item>
- <p>The least maximum packet size that the daemon will accept in channel open requests from the client. The default value is 0.
+ <p>The least maximum packet size that the daemon will accept in channel open requests from the client.
+ The default value is 0.
</p>
</item>
+
+ </taglist>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="callbacks_daemon_options"/>
+ <desc>
+ <taglist>
+ <tag><c>connectfun</c></tag>
+ <item>
+ <p>Provides a fun to implement your own logging when a user authenticates to the server.</p>
+ </item>
- <tag><c><![CDATA[{id_string, random | string()}]]></c></tag>
+ <tag><c>failfun</c></tag>
<item>
- <p>The string the daemon will present to a connecting peer initially. The default value is "Erlang/VSN" where VSN is the ssh application version number.
- </p>
- <p>The value <c>random</c> will cause a random string to be created at each connection attempt. This is to make it a bit more difficult for a malicious peer to find the ssh software brand and version.
- </p>
+ <p>Provides a fun to implement your own logging when a user fails to authenticate.</p>
</item>
+ </taglist>
+ </desc>
+ </datatype>
- <tag><c><![CDATA[{send_ext_info, boolean()}]]></c></tag>
- <item>
- <p>Send a list of extensions to the client if the client has asked for it. See
- <url href="https://tools.ietf.org/html/draft-ietf-curdle-ssh-ext-info">Draft-ietf-curdle-ssh-ext-info (work in progress)</url> for details.
- </p>
- <p>Currently implemented extension is sending <c>server-sig-algs</c> which is the list of the server's preferred
- user's public key algorithms.
- </p>
- <p>Default value is <c>true</c>.
- </p>
- </item>
+ <datatype>
+ <name name="send_ext_info_daemon_option"/>
+ <desc>
+ <p>Make the server (daemon) tell the client that the server accepts extension negotiation, that is,
+ include <c>ext-info-s</c> in the kexinit message sent. See
+ <url href="https://tools.ietf.org/html/rfc8308">RFC 8308</url>
+ for details and <seealso marker="SSH_app#supported-ext-info">ssh(6)</seealso>
+ for a list of currently implemented extensions.
+ </p>
+ <p>Default value is <c>true</c> which is compatible with other implementations not supporting ext-info.
+ </p>
+ </desc>
+ </datatype>
- <!--tag><c><![CDATA[{recv_ext_info, boolean()}]]></c></tag>
- <item>
- <p>Tell the client that the server accepts extension negotiation. See
- <url href="https://tools.ietf.org/html/draft-ietf-curdle-ssh-ext-info">Draft-ietf-curdle-ssh-ext-info (work in progress)</url> for details.
- </p>
- <p>Default value is <c>true</c>.
- </p>
- </item-->
- <tag><c><![CDATA[{key_cb, key_cb()}]]></c></tag>
+ <!--................................................................-->
+ <datatype_title>Options common to clients and daemons</datatype_title>
+ <datatype>
+ <name name="common_options"/>
+ <name name="common_option"/>
+ <desc><p>The options above can be used both in clients and in daemons (servers). They are further explained below.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="profile_common_option"/>
+ <desc>
+ <p>Used together with <c>ip-address</c> and <c>port</c> to
+ uniquely identify a ssh daemon. This can be useful in a
+ virtualized environment, where there can be more that one
+ server that has the same <c>ip-address</c> and
+ <c>port</c>. If this property is not explicitly set, it is
+ assumed that the the <c>ip-address</c> and <c>port</c>
+ uniquely identifies the SSH daemon.
+ </p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="max_idle_time_common_option"/>
+ <desc>
+ <p>Sets a time-out on a connection when no channels are active. Defaults to <c>infinity</c>.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="rekey_limit_common_option"/>
+ <name name="limit_bytes"/>
+ <name name="limit_time"/>
+ <desc>
+ <p>Sets the limit when rekeying is to be initiated. Both the max time and max amount of data
+ could be configured:
+ </p>
+ <list>
+ <item><c>{Minutes, Bytes}</c> initiate rekeying when any of the limits are reached.</item>
+ <item><c>Bytes</c> initiate rekeying when <c>Bytes</c> number of bytes are transferred,
+ or at latest after one hour.</item>
+ </list>
+ <p>When a rekeying is done, both the timer and the byte counter are restarted.
+ Defaults to one hour and one GByte.</p>
+ <p>If <c>Minutes</c> is set to <c>infinity</c>, no rekeying will ever occur due to that max time has passed.
+ Setting <c>Bytes</c> to <c>infinity</c> will inhibit rekeying after a certain amount of data has been transferred.
+ If the option value is set to <c>{infinity, infinity}</c>, no rekeying will be initiated. Note that rekeying initiated
+ by the peer will still be performed.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="key_cb_common_option"/>
+ <desc>
+ <p>Module implementing the behaviour
+ <seealso marker="ssh_client_key_api">ssh_client_key_api</seealso> and/or
+ <seealso marker="ssh_server_key_api">ssh_server_key_api</seealso>.
+ Can be used to
+ customize the handling of public keys. If callback options are provided
+ along with the module name, they are made available to the callback
+ module via the options passed to it under the key 'key_cb_private'.
+ </p>
+ <p>The <c>Opts</c> defaults to <c>[]</c> when only the <c>Module</c> is specified.
+ </p>
+ <p>The default value of this option is <c>{ssh_file, []}</c>. See also the manpage of
+ <seealso marker="ssh:ssh_file">ssh_file</seealso>.
+ </p>
+ <p>A call to the call-back function <c>F</c> will be</p>
+ <code>
+ Module:F(..., [{key_cb_private,Opts}|UserOptions])
+ </code>
+ <p>where <c>...</c> are arguments to <c>F</c> as in
+ <seealso marker="ssh_client_key_api">ssh_client_key_api</seealso> and/or
+ <seealso marker="ssh_server_key_api">ssh_server_key_api</seealso>.
+ The <c>UserOptions</c> are the options given to
+ <seealso marker="ssh:ssh#connect-3">ssh:connect</seealso>,
+ <seealso marker="ssh:ssh#shell-1">ssh:shell</seealso> or
+ <seealso marker="ssh:ssh#daemon-2">ssh:daemon</seealso>.
+ </p>
+
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="pref_public_key_algs_common_option"/>
+ <desc>
+ <p>List of user (client) public key algorithms to try to use.</p>
+ <p>The default value is the <c>public_key</c> entry in the list returned by
+ <seealso marker="#default_algorithms/0">ssh:default_algorithms/0</seealso>.
+ </p>
+ <p>If there is no public key of a specified type available, the corresponding entry is ignored.
+ Note that the available set is dependent on the underlying cryptolib and current user's public keys.
+ </p>
+ <p>See also the option <seealso marker="ssh_file#type-user_dir_common_option"><c>user_dir</c></seealso>
+ for specifying the path to the user's keys.
+ </p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="disconnectfun_common_option"/>
+ <desc>
+ <p>Provides a fun to implement your own logging when the peer disconnects.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="unexpectedfun_common_option"/>
+ <desc>
+ <p>Provides a fun to implement your own logging or other action when an unexpected message arrives.
+ If the fun returns <c>report</c> the usual info report is issued but if <c>skip</c> is returned no
+ report is generated.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="ssh_msg_debug_fun_common_option"/>
+ <desc>
+ <p>Provide a fun to implement your own logging of the SSH message SSH_MSG_DEBUG.
+ The last three parameters are from the message, see
+ <url href="https://tools.ietf.org/html/rfc4253#section-11.3">RFC 4253, section 11.3</url>.
+ The <seealso marker="#type-connection_ref"><c>connection_ref()</c></seealso> is the reference
+ to the connection on which the message arrived.
+ The return value from the fun is not checked.
+ </p>
+ <p>The default behaviour is ignore the message.
+ To get a printout for each message with <c>AlwaysDisplay = true</c>,
+ use for example <c>{ssh_msg_debug_fun, fun(_,true,M,_)-> io:format("DEBUG: ~p~n", [M]) end}</c></p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="id_string_common_option"/>
+ <desc>
+ <p>The string the daemon will present to a connecting peer initially.
+ The default value is "Erlang/VSN" where VSN is the ssh application version number.
+ </p>
+ <p>The value <c>random</c> will cause a random string to be created at each connection attempt.
+ This is to make it a bit more difficult for a malicious peer to find the ssh software brand and version.
+ </p>
+ <p>The value <c>{random, Nmin, Nmax}</c> will make a random string with at least <c>Nmin</c> characters and
+ at most <c>Nmax</c> characters.
+ </p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="preferred_algorithms_common_option"/>
+ <name name="algs_list"/>
+ <name name="alg_entry"/>
+ <name name="kex_alg"/>
+ <name name="pubkey_alg"/>
+ <name name="cipher_alg"/>
+ <name name="mac_alg"/>
+ <name name="compression_alg"/>
+ <name name="double_algs"/>
+
+ <desc>
+ <p>List of algorithms to use in the algorithm negotiation. The default <c>algs_list()</c> can
+ be obtained from <seealso marker="#default_algorithms/0">default_algorithms/0</seealso>.
+ </p>
+ <p>If an alg_entry() is missing in the algs_list(), the default value is used for that entry.</p>
+ <p>Here is an example of this option:</p>
+ <code>
+ {preferred_algorithms,
+ [{public_key,['ssh-rsa','ssh-dss']},
+ {cipher,[{client2server,['aes128-ctr']},
+ {server2client,['aes128-cbc','3des-cbc']}]},
+ {mac,['hmac-sha2-256','hmac-sha1']},
+ {compression,[none,zlib]}
+ ]
+ }
+ </code>
+ <p>The example specifies different algorithms in the two directions (client2server and server2client),
+ for cipher but specifies the same algorithms for mac and compression in both directions.
+ The kex (key exchange) is implicit but public_key is set explicitly.</p>
+
+ <p>For background and more examples see the <seealso marker="configure_algos#introduction">User's Guide</seealso>.</p>
+
+ <p>If an algorithm name occurs more than once in a list, the behaviour is undefined. The tags in the property lists
+ are also assumed to occur at most one time.
+ </p>
+
+ <warning>
+ <p>Changing the values can make a connection less secure. Do not change unless you
+ know exactly what you are doing. If you do not understand the values then you
+ are not supposed to change them.</p>
+ </warning>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="modify_algorithms_common_option"/>
+ <name name="modify_algs_list"/>
+ <desc>
+ <p>Modifies the list of algorithms to use in the algorithm negotiation. The modifications are
+ applied after the option <c>preferred_algorithms</c> (if existing) is applied.</p>
+ <p>The algoritm for modifications works like this:</p>
+ <list>
<item>
- <p>Module implementing the behaviour <seealso
- marker="ssh_server_key_api">ssh_server_key_api</seealso>. Can be used to
- customize the handling of public keys. If callback options are provided
- along with the module name, they are made available to the callback
- module via the options passed to it under the key 'key_cb_private'.
+ <p>Input is the <c>modify_algs_list()</c> and a set of algorithms <c>A</c>
+ obtained from the <c>preferred_algorithms</c> option if existing, or else from the
+ <seealso marker="ssh#default_algorithms-0">ssh:default_algorithms/0</seealso>.
</p>
</item>
-
- <tag><c>{profile, atom()}</c></tag>
<item>
- <p>Used together with <c>ip-address</c> and <c>port</c> to
- uniquely identify a ssh daemon. This can be useful in a
- virtualized environment, where there can be more that one
- server that has the same <c>ip-address</c> and
- <c>port</c>. If this property is not explicitly set, it is
- assumed that the the <c>ip-address</c> and <c>port</c>
- uniquely identifies the SSH daemon.
- </p>
+ <p>The head of the <c>modify_algs_list()</c> modifies <c>A</c> giving the result <c>A'</c>.</p>
+ <p>The possible modifications are:</p>
+ <list>
+ <item>
+ <p>Append or prepend supported but not enabled algorithm(s) to the list of
+ algorithms. If the wanted algorithms already are in <c>A</c> they will first
+ be removed and then appended or prepended,
+ </p>
+ </item>
+ <item>
+ <p>Remove (rm) one or more algorithms from <c>A</c>.
+ </p>
+ </item>
+ </list>
</item>
-
- <tag><c><![CDATA[{fd, file_descriptor()}]]></c></tag>
- <item>
- <p>Allows an existing file-descriptor to be used
- (passed on to the transport protocol).</p></item>
- <tag><c><![CDATA[{failfun, fun(User::string(),
- PeerAddress::ip_address(), Reason::term()) -> _}]]></c></tag>
<item>
- <p>Provides a fun to implement your own logging when a user fails to authenticate.</p>
+ <p>Repeat the modification step with the tail of <c>modify_algs_list()</c> and the resulting
+ <c>A'</c>.
+ </p>
</item>
- <tag><c><![CDATA[{connectfun, fun(User::string(), PeerAddress::ip_address(),
- Method::string()) ->_}]]></c></tag>
- <item>
- <p>Provides a fun to implement your own logging when a user authenticates to the server.</p>
+ </list>
+ <p>If an unsupported algorithm is in the <c>modify_algs_list()</c>, it will be silently ignored</p>
+ <p>If there are more than one modify_algorithms options, the result is undefined.</p>
+ <p>Here is an example of this option:</p>
+ <code>
+ {modify_algorithms,
+ [{prepend, [{kex, ['diffie-hellman-group1-sha1']}],
+ {rm, [{compression, [none]}]}
+ ]
+ }
+ </code>
+ <p>The example specifies that:</p>
+ <list>
+ <item><p>the old key exchange algorithm 'diffie-hellman-group1-sha1' should be
+ the main alternative. It will be the main alternative since it is prepened to the list</p>
</item>
- <tag><c><![CDATA[{disconnectfun, fun(Reason:term()) -> _}]]></c></tag>
- <item>
- <p>Provides a fun to implement your own logging when a user disconnects from the server.</p>
+ <item><p>The compression algorithm none (= no compression) is removed so compression is enforced</p>
</item>
+ </list>
+ <p>For background and more examples see the <seealso marker="configure_algos#introduction">User's Guide</seealso>.</p>
+ </desc>
+ </datatype>
- <tag><c><![CDATA[{unexpectedfun, fun(Message:term(), Peer) -> report | skip }]]></c></tag>
- <item>
- <p>Provides a fun to implement your own logging or other action when an unexpected message arrives.
- If the fun returns <c>report</c> the usual info report is issued but if <c>skip</c> is returned no
- report is generated.</p>
- <p><c>Peer</c> is in the format of <c>{Host,Port}</c>.</p>
- </item>
- <tag><c><![CDATA[{idle_time, integer()}]]></c></tag>
- <item>
- <p>Sets a time-out on a connection when no channels are active.
- Defaults to <c>infinity</c>.</p>
- </item>
+ <datatype>
+ <name name="inet_common_option"/>
+ <desc>
+ <p>IP version to use when the host address is specified as <c>any</c>.</p>
+ </desc>
+ </datatype>
- <tag><c><![CDATA[{ssh_msg_debug_fun, fun(ConnectionRef::ssh_connection_ref(), AlwaysDisplay::boolean(), Msg::binary(), LanguageTag::binary()) -> _}]]></c></tag>
- <item>
- <p>Provide a fun to implement your own logging of the SSH message SSH_MSG_DEBUG. The last three parameters are from the message, see RFC4253, section 11.3. The <c>ConnectionRef</c> is the reference to the connection on which the message arrived. The return value from the fun is not checked.</p>
- <p>The default behaviour is ignore the message.
- To get a printout for each message with <c>AlwaysDisplay = true</c>, use for example <c>{ssh_msg_debug_fun, fun(_,true,M,_)-> io:format("DEBUG: ~p~n", [M]) end}</c></p>
- </item>
+ <datatype>
+ <name name="auth_methods_common_option"/>
+ <desc>
+ <p>Comma-separated string that determines which authentication methods that the client shall
+ support and in which order they are tried. Defaults to <c>"publickey,keyboard-interactive,password"</c>
+ </p>
+ <p>Note that the client is free to use any order and to exclude methods.
+ </p>
+ </desc>
+ </datatype>
- </taglist>
- </desc>
- </func>
+ <datatype>
+ <name name="fd_common_option"/>
+ <desc>
+ <p>Allows an existing file-descriptor to be used (passed on to the transport protocol).</p>
+ </desc>
+ </datatype>
- <func>
- <name>daemon_info(Daemon) -> {ok, [DaemonInfo]} | {error,Error}</name>
- <fsummary>Get info about a daemon</fsummary>
- <type>
- <v>DaemonInfo = {port,Port::pos_integer()} | {listen_address, any|ip_address()} | {profile,atom()}</v>
- <v>Port = integer()</v>
- <v>Error = bad_daemon_ref</v>
- </type>
+ <!--................................................................-->
+ <datatype_title>Other data types</datatype_title>
+
+ <datatype>
+ <name name="host"/>
<desc>
- <p>Returns a key-value list with information about the daemon. For now, only the listening port is returned. This is intended for the case the daemon is started with the port set to 0.</p>
</desc>
+ </datatype>
+
+ <datatype>
+ <name name="ip_port"/>
+ <desc>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="mod_args"/>
+ <desc>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="mod_fun_args"/>
+ <desc>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="open_socket"/>
+ <desc>
+ <p>The socket is supposed to be result of a <seealso marker="kernel:gen_tcp#connect-3">gen_tcp:connect</seealso>
+ or a <seealso marker="kernel:gen_tcp#accept-1">gen_tcp:accept</seealso>. The socket must be in passive
+ mode (that is, opened with the option <c>{active,false})</c>.
+ </p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="daemon_ref"/>
+ <desc>
+ <p>Opaque data type representing a daemon.</p>
+ <p>Returned by the functions <seealso marker="ssh#daemon-1"><c>daemon/1,2,3</c></seealso>.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name>connection_ref()</name>
+ <desc>
+ <p>Opaque data type representing a connection between a client and a server (daemon).</p>
+ <p>Returned by the functions
+ <seealso marker="ssh#connect-3"><c>connect/2,3,4</c></seealso> and
+ <seealso marker="ssh_sftp#start_channel-2"><c>ssh_sftp:start_channel/2,3</c></seealso>.
+ </p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="channel_id"/>
+ <desc>
+ <p>Opaque data type representing a channel inside a connection.</p>
+ <p>Returned by the functions
+ <seealso marker="ssh_connection#session_channel/2">ssh_connection:session_channel/2,4</seealso>.
+ </p>
+ </desc>
+ </datatype>
+
+
+ <datatype>
+ <name>opaque_client_options</name>
+ <name>opaque_daemon_options</name>
+ <name>opaque_common_options</name>
+ <desc>
+ <marker id="type-opaque_client_options"/>
+ <marker id="type-opaque_daemon_options"/>
+ <marker id="type-opaque_common_options"/>
+ <p>Opaque types that define experimental options that are not to be used in products.</p>
+ </desc>
+ </datatype>
+ </datatypes>
+
+<!--
+ ================================================================
+ = Function definitions =
+ ================================================================
+-->
+
+ <funcs>
+
+<!-- CLOSE/1 -->
+ <func>
+ <name name="close" arity="1" since=""/>
+ <fsummary>Closes an SSH connection.</fsummary>
+ <desc><p>Closes an SSH connection.</p></desc>
</func>
+
+<!-- CONNECT/2 etc -->
+ <func>
+ <name since="">connect(Host, Port, Options) -> Result </name>
+ <name since="">connect(Host, Port, Options, NegotiationTimeout) -> Result </name>
+ <name since="OTP 19.0">connect(TcpSocket, Options) -> Result</name>
+ <name since="">connect(TcpSocket, Options, NegotiationTimeout) -> Result</name>
+ <fsummary>Connects to an SSH server.</fsummary>
+ <type>
+ <v>Host = <seealso marker="#type-host">host()</seealso></v>
+ <v>Port = <seealso marker="kernel:inet#type-port_number">inet:port_number()</seealso></v>
+ <v>Options = <seealso marker="#type-client_options">client_options()</seealso></v>
+ <v>TcpSocket = <seealso marker="#type-open_socket">open_socket()</seealso></v>
+ <v>NegotiationTimeout = timeout()</v>
+ <v>Result = {ok, <seealso marker="#type-connection_ref">connection_ref()</seealso>} | {error, term()}</v>
+ </type>
+ <desc>
+ <p>Connects to an SSH server at the <c>Host</c> on <c>Port</c>.
+ </p>
+ <p>As an alternative, an already open TCP socket could be passed to the function in <c>TcpSocket</c>.
+ The SSH initiation and negotiation will be initiated on that one with the SSH that should be at the
+ other end.
+ </p>
+ <p>No channel is started. This is done by calling <seealso marker="ssh_connection#session_channel/2">
+ ssh_connection:session_channel/[2, 4]</seealso>.
+ </p>
+ <p>The <c>NegotiationTimeout</c> is in milli-seconds. The default value is <c>infinity</c>.
+ For connection timeout, use the option
+ <seealso marker="#type-connect_timeout_client_option"><c>connect_timeout</c></seealso>.
+ </p>
+ </desc>
+ </func>
+
+<!-- CONNECTION_INFO/1, CONNECTION_INFO/2 -->
+ <func>
+ <name name="connection_info" arity="2" since=""/>
+ <fsummary>Retrieves information about a connection.</fsummary>
+ <desc>
+ <p>Retrieves information about a connection. The list <c>Keys</c> defines which information that
+ is returned.</p>
+ </desc>
+ </func>
+
+<!-- DEAMON/1,2,3 -->
+ <func>
+ <name since="">daemon(Port | TcpSocket) -> Result</name>
+ <name since="">daemon(Port | TcpSocket, Options) -> Result</name>
+ <name since="">daemon(HostAddress, Port, Options) -> Result</name>
+ <fsummary>Starts a server listening for SSH connections.</fsummary>
+ <type>
+ <v>Port = integer()</v>
+ <v>TcpSocket = <seealso marker="#type-open_socket">open_socket()</seealso></v>
+ <v>Options = <seealso marker="#type-daemon_options">daemon_options()</seealso></v>
+ <v>HostAddress = <seealso marker="#type-host">host()</seealso> | any</v>
+ <v>Result = {ok, <seealso marker="#type-daemon_ref">daemon_ref()</seealso>} | {error, atom()}</v>
+ </type>
+ <desc>
+ <p>Starts a server listening for SSH connections on the given port. If the <c>Port</c> is 0,
+ a random free port is selected. See <seealso marker="#daemon_info/1">daemon_info/1</seealso>
+ about how to find the selected port number.
+ </p>
+ <p>As an alternative, an already open TCP socket could be passed to the function in <c>TcpSocket</c>.
+ The SSH initiation and negotiation will be initiated on that one when an SSH starts at the other end
+ of the TCP socket.
+ </p>
+ <p>For a description of the options, see <seealso marker="#type-daemon_options">Daemon Options</seealso>.
+ </p>
+ <p>Please note that by historical reasons both the <c>HostAddress</c> argument and the
+ <seealso marker="kernel:gen_tcp#type-connect_option">gen_tcp connect_option() <c>{ip,Address}</c></seealso>
+ set the listening address. This is a source of possible inconsistent settings.
+ </p>
+ <p>The rules for handling the two address passing options are:</p>
+ <list>
+ <item>if <c>HostAddress</c> is an IP-address, that IP-address is the listening address.
+ An 'ip'-option will be discarded if present.</item>
+
+ <item>if <c>HostAddress</c> is the atom <c>loopback</c>, the listening address
+ is <c>loopback</c> and an loopback address will be choosen by the underlying layers.
+ An 'ip'-option will be discarded if present.</item>
+
+ <item>if <c>HostAddress</c> is the atom <c>any</c> and no 'ip'-option is present, the listening address is
+ <c>any</c> and the socket will listen to all addresses</item>
+
+ <item>if <c>HostAddress</c> is <c>any</c> and an 'ip'-option is present, the listening address is
+ set to the value of the 'ip'-option</item>
+ </list>
+ </desc>
+ </func>
+<!-- DAEMON_INFO/1 -->
+ <func>
+ <name name="daemon_info" arity="1" since="OTP 19.0"/>
+ <fsummary>Get info about a daemon</fsummary>
+ <desc>
+ <p>Returns a key-value list with information about the daemon.</p>
+ </desc>
+ </func>
+
+
+<!-- DEFAULT_ALGORITHMS/0 -->
<func>
- <name>default_algorithms() -> algs_list()</name>
+ <name name="default_algorithms" arity="0" since="OTP 18.0"/>
<fsummary>Get a list declaring the supported algorithms</fsummary>
<desc>
<p>Returns a key-value list, where the keys are the different types of algorithms and the values are the
- algorithms themselves. An example:</p>
- <code>
-20> ssh:default_algorithms().
-[{kex,['diffie-hellman-group1-sha1']},
- {public_key,['ssh-rsa','ssh-dss']},
- {cipher,[{client2server,['aes128-ctr','aes128-cbc','3des-cbc']},
- {server2client,['aes128-ctr','aes128-cbc','3des-cbc']}]},
- {mac,[{client2server,['hmac-sha2-256','hmac-sha1']},
- {server2client,['hmac-sha2-256','hmac-sha1']}]},
- {compression,[{client2server,[none,zlib]},
- {server2client,[none,zlib]}]}]
-21>
-</code>
+ algorithms themselves.</p>
+ <p>See the <seealso marker="configure_algos#example_default_algorithms">User's Guide</seealso> for
+ an example.</p>
</desc>
</func>
+<!-- SHELL/1,2,3 -->
<func>
- <name>shell(Host) -> </name>
- <name>shell(Host, Option) -> </name>
- <name>shell(Host, Port, Option) -> </name>
- <name>shell(TcpSocket) -> _</name>
- <fsummary>Starts an interactive shell over an SSH server.</fsummary>
+ <name since="">shell(Host | TcpSocket) -> Result </name>
+ <name since="">shell(Host | TcpSocket, Options) -> Result </name>
+ <name since="">shell(Host, Port, Options) -> Result </name>
+ <fsummary>Starts an interactive shell on a remote SSH server.</fsummary>
<type>
- <v>Host = string()</v>
- <v>Port = integer()</v>
- <v>Options - see ssh:connect/3</v>
- <v>TcpSocket = port()</v>
- <d>The socket is supposed to be from <seealso marker="kernel:gen_tcp#connect-3">gen_tcp:connect</seealso> or <seealso marker="kernel:gen_tcp#accept-1">gen_tcp:accept</seealso> with option <c>{active,false}</c></d>
+ <v>Host = <seealso marker="#type-host">host()</seealso></v>
+ <v>TcpSocket = <seealso marker="#type-open_socket">open_socket()</seealso></v>
+ <v>Port = <seealso marker="kernel:inet#type-port_number">inet:port_number()</seealso></v>
+ <v>Options = <seealso marker="#type-client_options">client_options()</seealso></v>
+ <v>Result = ok | {error, Reason::term()}</v>
</type>
<desc>
- <p>Starts an interactive shell over an SSH server on the
- given <c>Host</c>. The function waits for user input,
- and does not return until the remote shell is ended (that is,
+ <p>Connects to an SSH server at <c>Host</c> and <c>Port</c> (defaults to 22) and starts an
+ interactive shell on that remote host.
+ </p>
+ <p>As an alternative, an already open TCP socket could be passed to the function in <c>TcpSocket</c>.
+ The SSH initiation and negotiation will be initiated on that one and finaly a shell will be started
+ on the host at the other end of the TCP socket.
+ </p>
+ <p>For a description of the options, see <seealso marker="#type-client_options">Client Options</seealso>.</p>
+ <p>The function waits for user input, and does not return until the remote shell is ended (that is,
exit from the shell).
</p>
</desc>
</func>
<func>
- <name>start() -> </name>
- <name>start(Type) -> ok | {error, Reason}</name>
+ <name name="start" arity="0" since=""/>
+ <name name="start" arity="1" since=""/>
<fsummary>Starts the SSH application.</fsummary>
- <type>
- <v>Type = permanent | transient | temporary</v>
- <v>Reason = term() </v>
- </type>
<desc>
<p>Utility function that starts the applications <c>crypto</c>, <c>public_key</c>,
and <c>ssh</c>. Default type is <c>temporary</c>.
@@ -985,11 +1215,8 @@
</func>
<func>
- <name>stop() -> ok | {error, Reason}</name>
+ <name name="stop" arity="0" since=""/>
<fsummary>Stops the <c>ssh</c> application.</fsummary>
- <type>
- <v>Reason = term()</v>
- </type>
<desc>
<p>Stops the <c>ssh</c> application.
For more information, see the <seealso marker="kernel:application">application(3)</seealso>
@@ -998,34 +1225,22 @@
</func>
<func>
- <name>stop_daemon(DaemonRef) -> </name>
- <name>stop_daemon(Address, Port) -> ok </name>
- <fsummary>Stops the listener and all connections started by
- the listener.</fsummary>
- <type>
- <v>DaemonRef = ssh_daemon_ref()</v>
- <v>Address = ip_address()</v>
- <v>Port = integer()</v>
- </type>
+ <name name="stop_daemon" arity="1" since=""/>
+ <name name="stop_daemon" arity="2" since=""/>
+ <name name="stop_daemon" arity="3" since="OTP 21.0"/>
+ <fsummary>Stops the listener and all connections started by the listener.</fsummary>
<desc>
- <p>Stops the listener and all connections started by
- the listener.</p>
+ <p>Stops the listener and all connections started by the listener.</p>
</desc>
</func>
<func>
- <name>stop_listener(DaemonRef) -> </name>
- <name>stop_listener(Address, Port) -> ok </name>
- <fsummary>Stops the listener, but leaves existing connections started
- by the listener operational.</fsummary>
- <type>
- <v>DaemonRef = ssh_daemon_ref()</v>
- <v>Address = ip_address()</v>
- <v>Port = integer()</v>
- </type>
+ <name name="stop_listener" arity="1" since=""/>
+ <name name="stop_listener" arity="2" since=""/>
+ <name name="stop_listener" arity="3" since="OTP 21.0"/>
+ <fsummary>Stops the listener, but leaves existing connections started by the listener operational.</fsummary>
<desc>
- <p>Stops the listener, but leaves existing connections started
- by the listener operational.</p>
+ <p>Stops the listener, but leaves existing connections started by the listener operational.</p>
</desc>
</func>
diff --git a/lib/ssh/doc/src/ssh_app.xml b/lib/ssh/doc/src/ssh_app.xml
index 1cbbdfcf38..0c22a50c3f 100644
--- a/lib/ssh/doc/src/ssh_app.xml
+++ b/lib/ssh/doc/src/ssh_app.xml
@@ -4,7 +4,7 @@
<appref>
<header>
<copyright>
- <year>2012</year><year>2017</year>
+ <year>2012</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -74,13 +74,18 @@
<c>id_ecdsa_key</c>,
<c>known_hosts</c>, and <c>authorized_keys</c> in ~/.ssh,
and for the host key files in <c>/etc/ssh</c>. These locations can be changed
- by the options <c>user_dir</c> and <c>system_dir</c>.
+ by the options
+ <seealso marker="ssh_file#type-user_dir_common_option"><c>user_dir</c></seealso> and
+ <seealso marker="ssh_file#type-system_dir_daemon_option"><c>system_dir</c></seealso>.
</p>
<p>Public key handling can also be customized through a callback module that
implements the behaviors
<seealso marker="ssh_client_key_api">ssh_client_key_api</seealso> and
<seealso marker="ssh_server_key_api">ssh_server_key_api</seealso>.
</p>
+ <p>See also the default callback module documentation in
+ <seealso marker="ssh_file">ssh_file</seealso>.
+ </p>
</section>
<section>
@@ -130,39 +135,52 @@
For the list on a particular installation, use the command
<seealso marker="ssh:ssh#default_algorithms/0">ssh:default_algorithms/0</seealso>.
The user may override the default algorithm configuration both on the server side and the client side.
- See the option <c>preferred_algorithms</c> in the <seealso marker="ssh:ssh#daemon/1">ssh:daemon/1,2,3</seealso> and
+ See the options
+ <seealso marker="ssh:ssh#type-preferred_algorithms_common_option">preferred_algorithms</seealso>
+ and
+ <seealso marker="ssh:ssh#type-modify_algorithms_common_option">modify_algorithms</seealso>
+ in the <seealso marker="ssh:ssh#daemon/1">ssh:daemon/1,2,3</seealso> and
<seealso marker="ssh:ssh#connect/3">ssh:connect/3,4</seealso> functions.
</p>
- <p>Supported algorithms are:</p>
+ <p>Supported algorithms are (in the default order):</p>
<marker id="supported_algos"></marker>
<taglist>
<tag>Key exchange algorithms</tag>
<item>
<list type="bulleted">
- <item>ecdh-sha2-nistp256</item>
<item>ecdh-sha2-nistp384</item>
<item>ecdh-sha2-nistp521</item>
- <item>diffie-hellman-group-exchange-sha1</item>
+ <item>ecdh-sha2-nistp256</item>
<item>diffie-hellman-group-exchange-sha256</item>
- <item>diffie-hellman-group14-sha1</item>
- <item>diffie-hellman-group14-sha256</item>
<item>diffie-hellman-group16-sha512</item>
<item>diffie-hellman-group18-sha512</item>
- <item>(diffie-hellman-group1-sha1, retired: can be enabled with the <c>preferred_algorithms</c> option)</item>
+ <item>diffie-hellman-group14-sha256</item>
+ <item>curve25519-sha256</item>
+ <item>[email protected]</item>
+ <item>curve448-sha512</item>
+ <item>diffie-hellman-group14-sha1</item>
+ <item>diffie-hellman-group-exchange-sha1</item>
+ <item>(diffie-hellman-group1-sha1, retired: It can be enabled with the
+ <seealso marker="ssh:ssh#type-preferred_algorithms_common_option">preferred_algorithms</seealso>
+ or
+ <seealso marker="ssh:ssh#type-modify_algorithms_common_option">modify_algorithms</seealso>
+ options)</item>
</list>
</item>
<tag>Public key algorithms</tag>
<item>
<list type="bulleted">
- <item>ecdsa-sha2-nistp256</item>
<item>ecdsa-sha2-nistp384</item>
<item>ecdsa-sha2-nistp521</item>
+ <item>ecdsa-sha2-nistp256</item>
+ <item>ssh-ed25519</item>
+ <item>ssh-ed448</item>
<item>ssh-rsa</item>
- <item>ssh-dss</item>
<item>rsa-sha2-256</item>
<item>rsa-sha2-512</item>
+ <item>ssh-dss</item>
</list>
</item>
@@ -178,11 +196,12 @@
<tag>Encryption algorithms (ciphers)</tag>
<item>
<list type="bulleted">
- <item>[email protected]</item>
+ <item>[email protected]</item>
<item>[email protected]</item>
- <item>aes128-ctr</item>
- <item>aes192-ctr</item>
<item>aes256-ctr</item>
+ <item>aes192-ctr</item>
+ <item>[email protected]</item>
+ <item>aes128-ctr</item>
<item>aes128-cbc</item>
<item>3des-cbc</item>
<item>(AEAD_AES_128_GCM, not enabled per default)</item>
@@ -241,7 +260,11 @@
<item><url href="https://tools.ietf.org/html/rfc4253">RFC 4253</url>, The Secure Shell (SSH) Transport Layer Protocol.
<p>Except</p>
<list type="bulleted">
- <item>8.1. diffie-hellman-group1-sha1. Disabled by default, can be enabled with the <c>preferred_algorithms</c> option.</item>
+ <item>8.1. diffie-hellman-group1-sha1. Disabled by default, can be enabled with the
+ <seealso marker="ssh:ssh#type-preferred_algorithms_common_option">preferred_algorithms</seealso>
+ or
+ <seealso marker="ssh:ssh#type-modify_algorithms_common_option">modify_algorithms</seealso>
+ options.</item>
</list>
<p/>
</item>
@@ -280,7 +303,10 @@
<p><marker id="rfc5647_note"/>There is an ambiguity in the synchronized selection of cipher and mac algorithm.
This is resolved by OpenSSH in the ciphers [email protected] and [email protected] which are implemented.
If the explicit ciphers and macs AEAD_AES_128_GCM or AEAD_AES_256_GCM are needed,
- they could be enabled with the option preferred_algorithms.
+ they could be enabled with the options
+ <seealso marker="ssh:ssh#type-preferred_algorithms_common_option">preferred_algorithms</seealso>
+ or
+ <seealso marker="ssh:ssh#type-modify_algorithms_common_option">modify_algorithms</seealso>.
</p>
<warning>
<p>
@@ -322,18 +348,27 @@
<p>Deviations:</p>
<list type="bulleted">
<item>The <c>diffie-hellman-group1-sha1</c> is not enabled by default, but is still supported and can be enabled
- with the option <c>preferred-algorithms</c></item>
+ with the options
+ <seealso marker="ssh:ssh#type-preferred_algorithms_common_option">preferred_algorithms</seealso>
+ or
+ <seealso marker="ssh:ssh#type-modify_algorithms_common_option">modify_algorithms</seealso>.
+ </item>
<item>The questionable sha1-based algorithms <c>diffie-hellman-group-exchange-sha1</c> and
<c>diffie-hellman-group14-sha1</c> are still enabled by default for compatibility with ancient clients and servers.
- They can be disabled with the option <c>preferred-algorithms</c></item>
+ They can be disabled with the options
+ <seealso marker="ssh:ssh#type-preferred_algorithms_common_option">preferred_algorithms</seealso>
+ or
+ <seealso marker="ssh:ssh#type-modify_algorithms_common_option">modify_algorithms</seealso>.
+ They will be disabled by default when the draft is turned into an RFC.</item>
</list>
<p/>
</item>
- <item><url href="https://tools.ietf.org/html/draft-ietf-curdle-rsa-sha2">Draft-ietf-curdle-rsa-sha2 (work in progress)</url>, Use of RSA Keys with SHA-2 256 and 512 in Secure Shell (SSH).
+ <item><url href="https://tools.ietf.org/html/rfc8332">RFC 8332</url>, Use of RSA Keys with SHA-256 and SHA-512 in the Secure Shell (SSH) Protocol.
</item>
- <item><url href="https://tools.ietf.org/html/draft-ietf-curdle-ssh-ext-info">Draft-ietf-curdle-ssh-ext-info (work in progress)</url>, Extension Negotiation in Secure Shell (SSH).
+ <item><marker id="supported-ext-info"/>
+ <url href="https://tools.ietf.org/html/rfc8308">RFC 8308</url>, Extension Negotiation in the Secure Shell (SSH) Protocol.
<p>Implemented are:</p>
<list type="bulleted">
<item>The Extension Negotiation Mechanism</item>
@@ -341,7 +376,15 @@
</list>
<p/>
</item>
-
+
+ <item>
+ <url href="https://tools.ietf.org/html/draft-ietf-curdle-ssh-curves">Secure Shell (SSH) Key Exchange Method using Curve25519 and Curve448 (work in progress)</url>
+ </item>
+
+ <item>
+ <url href="https://tools.ietf.org/html/draft-ietf-curdle-ssh-ed25519-ed448">Ed25519 and Ed448 public key algorithms for the Secure Shell (SSH) protocol (work in progress)</url>
+ </item>
+
</list>
</section>
diff --git a/lib/ssh/doc/src/ssh_channel.xml b/lib/ssh/doc/src/ssh_channel.xml
deleted file mode 100644
index 7b598494f7..0000000000
--- a/lib/ssh/doc/src/ssh_channel.xml
+++ /dev/null
@@ -1,443 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2009</year>
- <year>2016</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
- <title>ssh_channel</title>
- <prepared></prepared>
- <docno></docno>
- <date></date>
- <rev></rev>
- </header>
- <module>ssh_channel</module>
- <modulesummary>-behaviour(ssh_channel).
- </modulesummary>
- <description>
- <p>SSH services (clients and servers) are implemented as channels
- that are multiplexed over an SSH connection and communicates over
- the <url href="http://www.ietf.org/rfc/rfc4254.txt"> SSH
- Connection Protocol</url>. This module provides a callback API
- that takes care of generic channel aspects, such as flow control
- and close messages. It lets the callback functions take care of
- the service (application) specific parts. This behavior also ensures
- that the channel process honors the principal of an OTP-process so
- that it can be part of a supervisor tree. This is a requirement of
- channel processes implementing a subsystem that will be added to
- the <c>ssh</c> applications supervisor tree.
- </p>
-
- <note><p>When implementing an <c>ssh</c> subsystem, use
- <c>-behaviour(ssh_daemon_channel)</c> instead of <c>-behaviour(ssh_channel)</c>.
- The reason is that the only relevant callback functions for subsystems are
- <c>init/1</c>, <c>handle_ssh_msg/2</c>, <c>handle_msg/2</c>, and <c>terminate/2</c>.
- So, the <c>ssh_daemon_channel</c> behaviour is a limited version of the
- <c>ssh_channel</c> behaviour.
- </p></note>
- </description>
-
- <section>
- <title>DATA TYPES</title>
-
- <p>Type definitions that are used more than once in this module,
- or abstractions to indicate the intended use of the data
- type, or both:</p>
-
- <taglist>
- <tag><c>boolean() =</c></tag>
- <item><p><c>true | false</c></p></item>
- <tag><c>string() =</c></tag>
- <item><p>list of ASCII characters</p></item>
- <tag><c>timeout() =</c></tag>
- <item><p><c>infinity | integer()</c> in milliseconds</p></item>
- <tag><c>ssh_connection_ref() =</c></tag>
- <item><p>opaque() -as returned by
- <c>ssh:connect/3</c> or sent to an SSH channel process</p></item>
- <tag><c>ssh_channel_id() =</c></tag>
- <item><p><c>integer()</c></p></item>
- <tag><c>ssh_data_type_code() =</c></tag>
- <item><p><c>1</c> ("stderr") | <c>0</c> ("normal") are
- the valid values,
- see <url href="http://www.ietf.org/rfc/rfc4254.txt">RFC 4254</url>
- Section 5.2</p></item>
- </taglist>
- </section>
-
- <funcs>
- <func>
- <name>call(ChannelRef, Msg) -></name>
- <name>call(ChannelRef, Msg, Timeout) -> Reply | {error, Reason}</name>
- <fsummary>Makes a synchronous call to a channel.</fsummary>
- <type>
- <v>ChannelRef = pid() </v>
- <d>As returned by <seealso marker = "#start_link-4">ssh_channel:start_link/4</seealso></d>
- <v>Msg = term()</v>
- <v>Timeout = timeout()</v>
- <v>Reply = term()</v>
- <v>Reason = closed | timeout</v>
-
- </type>
- <desc>
- <p>Makes a synchronous call to the channel process by sending
- a message and waiting until a reply arrives, or a time-out
- occurs. The channel calls <seealso marker =
- "#Module:handle_call-3">Module:handle_call/3</seealso>
- to handle the message. If the channel process does not exist,
- <c>{error, closed}</c> is returned.
- </p>
- </desc>
- </func>
-
- <func>
- <name>cast(ChannelRef, Msg) -> ok </name>
- <fsummary>Sends an asynchronous message to the channel
- ChannelRef and returns ok.</fsummary>
- <type>
- <v>ChannelRef = pid()</v>
- <d>As returned by <seealso marker = "#start_link-4">ssh_channel:start_link/4</seealso></d>
- <v>Msg = term()</v>
- </type>
- <desc>
- <p>Sends an asynchronous message to the channel process and
- returns ok immediately, ignoring if the destination node or
- channel process does not exist. The channel calls
- <seealso marker = "#Module:handle_cast-2">Module:handle_cast/2</seealso>
- to handle the message.
- </p>
- </desc>
- </func>
-
- <func>
- <name>enter_loop(State) -> _ </name>
- <fsummary>Makes an existing process an ssh_channel process.</fsummary>
- <type>
- <v>State = term()</v>
- <d>as returned by <seealso marker = "#init-1">ssh_channel:init/1</seealso></d>
- </type>
- <desc>
- <p>Makes an existing process an <c>ssh_channel</c>
- process. Does not return, instead the calling process
- enters the <c>ssh_channel</c> process receive loop and become an
- <c>ssh_channel process</c>. The process must have been started using
- one of the start functions in <c>proc_lib</c>, see the <seealso
- marker="stdlib:proc_lib">proc_lib(3)</seealso> manual page in STDLIB.
- The user is responsible for any initialization of the process
- and must call <seealso marker = "#init-1">ssh_channel:init/1</seealso>.
- </p>
- </desc>
- </func>
-
- <func>
- <name>init(Options) -> {ok, State} | {ok, State, Timeout} | {stop, Reason} </name>
- <fsummary>Initiates an <c>ssh_channel</c> process.</fsummary>
- <type>
- <v>Options = [{Option, Value}]</v>
- <v>State = term()</v>
- <v>Timeout = timeout()</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>
- The following options must be present:
- </p>
- <taglist>
- <tag><c><![CDATA[{channel_cb, atom()}]]></c></tag>
- <item><p>The module that implements the channel behaviour.</p></item>
-
- <tag><c><![CDATA[{init_args(), list()}]]></c></tag>
- <item><p>The list of arguments to the <c>init</c> function of the callback module.</p></item>
-
- <tag><c><![CDATA[{cm, connection_ref()}]]></c></tag>
- <item><p>Reference to the <c>ssh</c> connection as returned by <seealso
- marker="ssh#connect-3">ssh:connect/3</seealso></p></item>
-
- <tag><c><![CDATA[{channel_id, channel_id()}]]></c></tag>
- <item><p>Id of the <c>ssh</c> channel.</p></item>
-
- </taglist>
-
- <note><p>This function is normally not called by the
- user. The user only needs to call if the
- channel process needs to be started with help of
- <c>proc_lib</c> instead of calling
- <c>ssh_channel:start/4</c> or
- <c>ssh_channel:start_link/4</c>.</p>
- </note>
- </desc>
- </func>
-
- <func>
- <name>reply(Client, Reply) -> _</name>
- <fsummary>Sends a reply to a client.</fsummary>
- <type>
- <v>Client = opaque()</v>
- <v>Reply = term()</v>
- </type>
- <desc>
- <p>This function can be used by a channel to send a
- reply to a client that called <c>call/[2,3]</c> when the reply
- cannot be defined in the return value of
- <seealso marker ="#Module:handle_call-3">Module:handle_call/3</seealso>.</p>
- <p><c>Client</c> must be the <c>From</c> argument provided to
- the callback function <c>handle_call/3</c>.
- <c>Reply</c> is an arbitrary term,
- which is given back to the client as the return value of
- <seealso marker="#call-2">ssh_channel:call/[2,3].</seealso></p>
- </desc>
- </func>
-
- <func>
- <name>start(SshConnection, ChannelId, ChannelCb, CbInitArgs) -> </name>
- <name>start_link(SshConnection, ChannelId, ChannelCb, CbInitArgs) ->
- {ok, ChannelRef} | {error, Reason}</name>
- <fsummary>Starts a process that handles an SSH channel.</fsummary>
- <type>
- <v>SshConnection = ssh_connection_ref()</v>
- <v>ChannelId = ssh_channel_id()</v>
- <d>As returned by
- <seealso marker ="ssh_connection#session_channel/2">
- ssh_connection:session_channel/[2,4]</seealso>.</d>
- <v>ChannelCb = atom()</v>
- <d>Name of the module implementing the service-specific parts
- of the channel.</d>
- <v>CbInitArgs = [term()]</v>
- <d>Argument list for the <c>init</c> function in the callback module.</d>
- <v>ChannelRef = pid()</v>
- </type>
- <desc>
- <p>Starts a process that handles an SSH channel. It is
- called internally, by the <c>ssh</c> daemon, or explicitly by the <c>ssh</c>
- client implementations. The behavior sets the
- <c>trap_exit</c> flag to <c>true</c>.
- </p>
- </desc>
- </func>
-
- </funcs>
-
- <section>
- <marker id="cb_timeouts"></marker>
- <title>CALLBACK TIME-OUTS</title>
-
- <p>The time-out values that can be returned by the callback functions
- have the same semantics as in a <seealso marker="stdlib:gen_server">gen_server</seealso>.
- If the time-out occurs, <seealso marker="#Module:handle_msg-2">handle_msg/2</seealso>
- is called as <c>handle_msg(timeout, State)</c>.</p>
- </section>
-
- <funcs>
- <func>
- <name>Module:code_change(OldVsn, State, Extra) -> {ok,
- NewState}</name>
- <fsummary>Converts process state when code is changed.</fsummary>
- <type>
- <v>OldVsn = term()</v>
- <d>In the case of an upgrade, <c>OldVsn</c> is <c>Vsn</c>, and
- in the case of a downgrade, <c>OldVsn</c> is
- <c>{down,Vsn}</c>. <c>Vsn</c> is defined by the <c>vsn</c>
- attribute(s) of the old version of the callback module
- <c>Module</c>. If no such attribute is defined, the version is
- the checksum of the BEAM file.</d>
- <v>State = term()</v>
- <d>Internal state of the channel.</d>
- <v>Extra = term()</v>
- <d>Passed "as-is" from the <c>{advanced,Extra}</c>
- part of the update instruction.</d>
- </type>
- <desc>
- <p>Converts process state when code is changed.</p>
-
- <p>This function is called by a client-side channel when it
- is to update its internal state during a release
- upgrade or downgrade, that is, when the instruction
- <c>{update,Module,Change,...}</c>, where
- <c>Change={advanced,Extra}</c>, is given in the <c>appup</c>
- file. For more information, refer to Section 9.11.6
- Release Handling Instructions in the
- <seealso marker="doc/design_principles:release_handling#instr">System Documentation</seealso>.
- </p>
-
- <note><p>Soft upgrade according to the OTP release concept
- is not straight forward for the server side, as subsystem
- channel processes are spawned by the <c>ssh</c> application and
- hence added to its supervisor tree. The subsystem channels can
- be upgraded when upgrading the user application, if the callback
- functions can handle two versions of the state, but this function
- cannot be used in the normal way.</p>
- </note>
-
- </desc>
- </func>
-
- <func>
- <name>Module:init(Args) -> {ok, State} | {ok, State, timeout()} |
- {stop, Reason}</name>
- <fsummary>Makes necessary initializations and returns the
- initial channel state if the initializations succeed.</fsummary>
- <type>
- <v>Args = term()</v>
- <d>Last argument to <c>ssh_channel:start_link/4</c>.</d>
- <v>State = term()</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Makes necessary initializations and returns the initial channel
- state if the initializations succeed.
- </p>
- <p>For more detailed information on time-outs, see Section
- <seealso marker="#cb_timeouts">CALLBACK TIME-OUTS</seealso>. </p>
- </desc>
- </func>
-
- <func>
- <name>Module:handle_call(Msg, From, State) -> Result</name>
- <fsummary>Handles messages sent by calling
- <c>ssh_channel:call/[2,3]</c>.</fsummary>
- <type>
- <v>Msg = term()</v>
- <v>From = opaque()</v>
- <d>Is to be used as argument to
- <seealso marker="#reply-2">ssh_channel:reply/2</seealso></d>
- <v>State = term()</v>
- <v>Result = {reply, Reply, NewState} | {reply, Reply, NewState, timeout()}
- | {noreply, NewState} | {noreply , NewState, timeout()}
- | {stop, Reason, Reply, NewState} | {stop, Reason, NewState} </v>
- <v>Reply = term()</v>
- <d>Will be the return value of <seealso marker="#call-2">ssh_channel:call/[2,3]</seealso></d>
- <v>NewState = term()</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Handles messages sent by calling
- <seealso marker="#call-2">ssh_channel:call/[2,3]</seealso>
- </p>
- <p>For more detailed information on time-outs,, see Section
- <seealso marker="#cb_timeouts">CALLBACK TIME-OUTS</seealso>.</p>
- </desc>
- </func>
-
- <func>
- <name>Module:handle_cast(Msg, State) -> Result</name>
- <fsummary>Handles messages sent by calling
- <c>ssh_channel:cact/2</c>.</fsummary>
- <type>
- <v>Msg = term()</v>
- <v>State = term()</v>
- <v>Result = {noreply, NewState} | {noreply, NewState, timeout()}
- | {stop, Reason, NewState}</v>
- <v>NewState = term() </v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Handles messages sent by calling
- <c>ssh_channel:cast/2</c>.
- </p>
- <p>For more detailed information on time-outs, see Section
- <seealso marker="#cb_timeouts">CALLBACK TIME-OUTS</seealso>.</p>
- </desc>
- </func>
-
- <func>
- <name>Module:handle_msg(Msg, State) -> {ok, State} |
- {stop, ChannelId, State}</name>
-
- <fsummary>Handles other messages than SSH connection protocol,
- call, or cast messages sent to the channel.</fsummary>
- <type>
- <v>Msg = timeout | term()</v>
- <v>ChannelId = ssh_channel_id()</v>
- <v>State = term() </v>
- </type>
- <desc>
- <p>Handles other messages than SSH Connection Protocol, call, or
- cast messages sent to the channel.
- </p>
-
- <p>Possible Erlang 'EXIT' messages is to be handled by this
- function and all channels are to handle the following message.</p>
-
- <taglist>
- <tag><c><![CDATA[{ssh_channel_up, ssh_channel_id(),
- ssh_connection_ref()}]]></c></tag>
- <item><p>This is the first message that the channel receives.
- It is sent just before the <seealso
- marker="#init-1">ssh_channel:init/1</seealso> function
- returns successfully. This is especially useful if the
- server wants to send a message to the client without first
- receiving a message from it. If the message is not
- useful for your particular scenario, ignore it by
- immediately returning <c>{ok, State}</c>.
- </p></item>
- </taglist>
- </desc>
- </func>
-
- <func>
- <name>Module:handle_ssh_msg(Msg, State) -> {ok, State} | {stop,
- ChannelId, State}</name>
- <fsummary>Handles <c>ssh</c> connection protocol messages.</fsummary>
- <type>
- <v>Msg = ssh_connection:event()</v>
- <v>ChannelId = ssh_channel_id()</v>
- <v>State = term()</v>
- </type>
- <desc>
- <p>Handles SSH Connection Protocol messages that may need
- service-specific attention. For details,
- see <seealso marker="ssh_connection"> ssh_connection:event()</seealso>.
- </p>
-
- <p>The following message is taken care of by the
- <c>ssh_channel</c> behavior.</p>
-
- <taglist>
- <tag><c><![CDATA[{closed, ssh_channel_id()}]]></c></tag>
- <item><p>The channel behavior sends a close message to the
- other side, if such a message has not already been sent.
- Then it terminates the channel with reason <c>normal</c>.</p></item>
- </taglist>
- </desc>
- </func>
-
- <func>
- <name>Module:terminate(Reason, State) -> _</name>
- <fsummary>Does cleaning up before channel process termination.
- </fsummary>
- <type>
- <v>Reason = term()</v>
- <v>State = term()</v>
- </type>
- <desc>
- <p>This function is called by a channel process when it is
- about to terminate. Before this function is called, <seealso
- marker="ssh_connection#close-2"> ssh_connection:close/2
- </seealso> is called, if it has not been called earlier.
- This function does any necessary cleaning
- up. When it returns, the channel process terminates with
- reason <c>Reason</c>. The return value is ignored.
- </p>
- </desc>
- </func>
-
- </funcs>
-
-</erlref>
diff --git a/lib/ssh/doc/src/ssh_client_channel.xml b/lib/ssh/doc/src/ssh_client_channel.xml
new file mode 100644
index 0000000000..cd28b95fd3
--- /dev/null
+++ b/lib/ssh/doc/src/ssh_client_channel.xml
@@ -0,0 +1,440 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2009</year>
+ <year>2018</year>
+ <holder>Ericsson AB, All Rights Reserved</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ The Initial Developer of the Original Code is Ericsson AB.
+ </legalnotice>
+ <title>ssh_client_channel</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ </header>
+ <module since="OTP 21.0">ssh_client_channel</module>
+ <modulesummary>-behaviour(ssh_client_channel). (Replaces ssh_channel)
+ </modulesummary>
+ <description>
+ <note>
+ <p>This module replaces ssh_channel.</p>
+ <p>The old module is still available for compatibility, but should not be used for new programs.
+ The old module will not be maintained except for some error corrections
+ </p>
+ </note>
+ <p>SSH services (clients and servers) are implemented as channels
+ that are multiplexed over an SSH connection and communicates over
+ the <url href="http://www.ietf.org/rfc/rfc4254.txt"> SSH
+ Connection Protocol</url>. This module provides a callback API
+ that takes care of generic channel aspects for clients, such as flow control
+ and close messages. It lets the callback functions take care of
+ the service (application) specific parts. This behavior also ensures
+ that the channel process honors the principal of an OTP-process so
+ that it can be part of a supervisor tree. This is a requirement of
+ channel processes implementing a subsystem that will be added to
+ the <c>ssh</c> applications supervisor tree.
+ </p>
+
+ <note><p>When implementing a <c>ssh</c> subsystem for daemons, use
+ <seealso marker="ssh_server_channel">-behaviour(ssh_server_channel)</seealso> (Replaces ssh_daemon_channel)
+ instead.
+ </p>
+ </note>
+
+ <dont>
+ <p>Functions in this module are not supposed to be called outside a module implementing this
+ behaviour!
+ </p>
+ </dont>
+
+ </description>
+
+ <funcs>
+ <func>
+ <name since="OTP 21.0">call(ChannelRef, Msg) -></name>
+ <name since="OTP 21.0">call(ChannelRef, Msg, Timeout) -> Reply | {error, Reason}</name>
+ <fsummary>Makes a synchronous call to a channel.</fsummary>
+ <type>
+ <v>ChannelRef = pid() </v>
+ <d>As returned by <seealso marker = "#start_link-4">start_link/4</seealso></d>
+ <v>Msg = term()</v>
+ <v>Timeout = timeout()</v>
+ <v>Reply = term()</v>
+ <v>Reason = closed | timeout</v>
+
+ </type>
+ <desc>
+ <p>Makes a synchronous call to the channel process by sending
+ a message and waiting until a reply arrives, or a time-out
+ occurs. The channel calls <seealso marker =
+ "#Module:handle_call-3">Module:handle_call/3</seealso>
+ to handle the message. If the channel process does not exist,
+ <c>{error, closed}</c> is returned.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0">cast(ChannelRef, Msg) -> ok </name>
+ <fsummary>Sends an asynchronous message to the channel
+ ChannelRef and returns ok.</fsummary>
+ <type>
+ <v>ChannelRef = pid()</v>
+ <d>As returned by <seealso marker = "#start_link-4">start_link/4</seealso></d>
+ <v>Msg = term()</v>
+ </type>
+ <desc>
+ <p>Sends an asynchronous message to the channel process and
+ returns ok immediately, ignoring if the destination node or
+ channel process does not exist. The channel calls
+ <seealso marker = "#Module:handle_cast-2">Module:handle_cast/2</seealso>
+ to handle the message.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0">enter_loop(State) -> _ </name>
+ <fsummary>Makes an existing process an ssh_client_channel (replaces ssh_channel) process.</fsummary>
+ <type>
+ <v>State = term()</v>
+ <d>as returned by <seealso marker = "#init-1">init/1</seealso></d>
+ </type>
+ <desc>
+ <p>Makes an existing process an <c>ssh_client_channel</c> (replaces ssh_channel)
+ process. Does not return, instead the calling process
+ enters the <c>ssh_client_channel</c> (replaces ssh_channel) process receive loop and become an
+ <c>ssh_client_channel</c> process. The process must have been started using
+ one of the start functions in <c>proc_lib</c>, see the <seealso
+ marker="stdlib:proc_lib">proc_lib(3)</seealso> manual page in STDLIB.
+ The user is responsible for any initialization of the process
+ and must call <seealso marker = "#init-1">init/1</seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0">init(Options) -> {ok, State} | {ok, State, Timeout} | {stop, Reason} </name>
+ <fsummary>Initiates an <c>ssh_client_channel</c> process.</fsummary>
+ <type>
+ <v>Options = [{Option, Value}]</v>
+ <v>State = term()</v>
+ <v>Timeout = timeout()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>
+ The following options must be present:
+ </p>
+ <taglist>
+ <tag><c>{channel_cb, atom()}</c></tag>
+ <item><p>The module that implements the channel behaviour.</p></item>
+
+ <tag><c>{init_args(), list()}</c></tag>
+ <item><p>The list of arguments to the <c>init</c> function of the callback module.</p></item>
+
+ <tag><c>{cm, ssh:connection_ref()}</c></tag>
+ <item><p>Reference to the <c>ssh</c> connection as returned by
+ <seealso marker="ssh#connect-3">ssh:connect/3</seealso>.
+ </p></item>
+
+ <tag><c>{channel_id, ssh:channel_id()}</c></tag>
+ <item><p>Id of the <c>ssh</c> channel as returned by
+ <seealso marker="ssh_connection#session_channel/2">ssh_connection:session_channel/2,4</seealso>.
+ </p></item>
+
+ </taglist>
+
+ <note><p>This function is normally not called by the
+ user. The user only needs to call if the
+ channel process needs to be started with help of
+ <c>proc_lib</c> instead of calling
+ <c>start/4</c> or
+ <c>start_link/4</c>.</p>
+ </note>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0">reply(Client, Reply) -> _</name>
+ <fsummary>Sends a reply to a client.</fsummary>
+ <type>
+ <v>Client = opaque()</v>
+ <v>Reply = term()</v>
+ </type>
+ <desc>
+ <p>This function can be used by a channel to send a
+ reply to a client that called <c>call/[2,3]</c> when the reply
+ cannot be defined in the return value of
+ <seealso marker ="#Module:handle_call-3">Module:handle_call/3</seealso>.</p>
+ <p><c>Client</c> must be the <c>From</c> argument provided to
+ the callback function <c>handle_call/3</c>.
+ <c>Reply</c> is an arbitrary term,
+ which is given back to the client as the return value of
+ <seealso marker="#call-2">call/[2,3].</seealso></p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0">start(SshConnection, ChannelId, ChannelCb, CbInitArgs) -> </name>
+ <name since="OTP 21.0">start_link(SshConnection, ChannelId, ChannelCb, CbInitArgs) ->
+ {ok, ChannelRef} | {error, Reason}</name>
+ <fsummary>Starts a process that handles an SSH channel.</fsummary>
+ <type>
+ <v>SshConnection = ssh:connection_ref()</v>
+ <d>As returned by <seealso marker="ssh#connect-3">ssh:connect/3</seealso></d>
+
+ <v>ChannelId = <seealso marker="ssh#type-channel_id">ssh:channel_id()</seealso></v>
+ <d>As returned by
+ <seealso marker ="ssh_connection#session_channel/2">
+ ssh_connection:session_channel/[2,4]</seealso>.</d>
+
+ <v>ChannelCb = atom()</v>
+ <d>Name of the module implementing the service-specific parts
+ of the channel.</d>
+
+ <v>CbInitArgs = [term()]</v>
+ <d>Argument list for the <c>init</c> function in the callback module.</d>
+
+ <v>ChannelRef = pid()</v>
+ </type>
+ <desc>
+ <p>Starts a process that handles an SSH channel. It is
+ called internally, by the <c>ssh</c> daemon, or explicitly by the <c>ssh</c>
+ client implementations. The behavior sets the
+ <c>trap_exit</c> flag to <c>true</c>.
+ </p>
+ </desc>
+ </func>
+
+ </funcs>
+
+ <section>
+ <title>Callback Functions</title>
+ <p>
+ The following functions are to be exported from a
+ <c>ssh_client_channel</c> callback module.
+ </p>
+ <marker id="cb_timeouts"></marker>
+ <section>
+ <title>Callback timeouts</title>
+ <p>The timeout values that can be returned by the callback functions
+ have the same semantics as in a <seealso marker="stdlib:gen_server">gen_server</seealso>.
+ If the time-out occurs, <seealso marker="#Module:handle_msg-2">handle_msg/2</seealso>
+ is called as <c>handle_msg(timeout, State)</c>.</p>
+ </section>
+ </section>
+
+ <funcs>
+ <func>
+ <name since="OTP 21.0">Module:code_change(OldVsn, State, Extra) -> {ok,
+ NewState}</name>
+ <fsummary>Converts process state when code is changed.</fsummary>
+ <type>
+ <v>OldVsn = term()</v>
+ <d>In the case of an upgrade, <c>OldVsn</c> is <c>Vsn</c>, and
+ in the case of a downgrade, <c>OldVsn</c> is
+ <c>{down,Vsn}</c>. <c>Vsn</c> is defined by the <c>vsn</c>
+ attribute(s) of the old version of the callback module
+ <c>Module</c>. If no such attribute is defined, the version is
+ the checksum of the BEAM file.</d>
+ <v>State = term()</v>
+ <d>Internal state of the channel.</d>
+ <v>Extra = term()</v>
+ <d>Passed "as-is" from the <c>{advanced,Extra}</c>
+ part of the update instruction.</d>
+ </type>
+ <desc>
+ <p>Converts process state when code is changed.</p>
+
+ <p>This function is called by a client-side channel when it
+ is to update its internal state during a release
+ upgrade or downgrade, that is, when the instruction
+ <c>{update,Module,Change,...}</c>, where
+ <c>Change={advanced,Extra}</c>, is given in the <c>appup</c>
+ file. For more information, refer to Section 9.11.6
+ Release Handling Instructions in the
+ <seealso marker="doc/design_principles:release_handling#instr">System Documentation</seealso>.
+ </p>
+
+ <note><p>Soft upgrade according to the OTP release concept
+ is not straight forward for the server side, as subsystem
+ channel processes are spawned by the <c>ssh</c> application and
+ hence added to its supervisor tree. The subsystem channels can
+ be upgraded when upgrading the user application, if the callback
+ functions can handle two versions of the state, but this function
+ cannot be used in the normal way.</p>
+ </note>
+
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0">Module:init(Args) -> {ok, State} | {ok, State, timeout()} |
+ {stop, Reason}</name>
+ <fsummary>Makes necessary initializations and returns the
+ initial channel state if the initializations succeed.</fsummary>
+ <type>
+ <v>Args = term()</v>
+ <d>Last argument to <c>start_link/4</c>.</d>
+ <v>State = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Makes necessary initializations and returns the initial channel
+ state if the initializations succeed.
+ </p>
+ <p>For more detailed information on time-outs, see Section
+ <seealso marker="#cb_timeouts">Callback timeouts</seealso>. </p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0">Module:handle_call(Msg, From, State) -> Result</name>
+ <fsummary>Handles messages sent by calling
+ <c>call/[2,3]</c>.</fsummary>
+ <type>
+ <v>Msg = term()</v>
+ <v>From = opaque()</v>
+ <d>Is to be used as argument to
+ <seealso marker="#reply-2">reply/2</seealso></d>
+ <v>State = term()</v>
+ <v>Result = {reply, Reply, NewState} | {reply, Reply, NewState, timeout()}
+ | {noreply, NewState} | {noreply , NewState, timeout()}
+ | {stop, Reason, Reply, NewState} | {stop, Reason, NewState} </v>
+ <v>Reply = term()</v>
+ <d>Will be the return value of <seealso marker="#call-2">call/[2,3]</seealso></d>
+ <v>NewState = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Handles messages sent by calling
+ <seealso marker="#call-2">call/[2,3]</seealso>
+ </p>
+ <p>For more detailed information on time-outs,, see Section
+ <seealso marker="#cb_timeouts">Callback timeouts</seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0">Module:handle_cast(Msg, State) -> Result</name>
+ <fsummary>Handles messages sent by calling
+ <c>cast/2</c>.</fsummary>
+ <type>
+ <v>Msg = term()</v>
+ <v>State = term()</v>
+ <v>Result = {noreply, NewState} | {noreply, NewState, timeout()}
+ | {stop, Reason, NewState}</v>
+ <v>NewState = term() </v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Handles messages sent by calling
+ <c>cast/2</c>.
+ </p>
+ <p>For more detailed information on time-outs, see Section
+ <seealso marker="#cb_timeouts">Callback timeouts</seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0">Module:handle_msg(Msg, State) -> {ok, State} |
+ {stop, ChannelId, State}</name>
+
+ <fsummary>Handles other messages than SSH connection protocol,
+ call, or cast messages sent to the channel.</fsummary>
+ <type>
+ <v>Msg = timeout | term()</v>
+ <v>ChannelId = <seealso marker="ssh#type-channel_id">ssh:channel_id()</seealso></v>
+ <v>State = term() </v>
+ </type>
+ <desc>
+ <p>Handles other messages than SSH Connection Protocol, call, or
+ cast messages sent to the channel.
+ </p>
+
+ <p>Possible Erlang 'EXIT' messages is to be handled by this
+ function and all channels are to handle the following message.</p>
+
+ <taglist>
+ <tag><c>{ssh_channel_up, ssh:channel_id(), ssh:connection_ref()}</c></tag>
+ <item><p>This is the first message that the channel receives.
+ It is sent just before the <seealso
+ marker="#init-1">init/1</seealso> function
+ returns successfully. This is especially useful if the
+ server wants to send a message to the client without first
+ receiving a message from it. If the message is not
+ useful for your particular scenario, ignore it by
+ immediately returning <c>{ok, State}</c>.
+ </p></item>
+ </taglist>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0">Module:handle_ssh_msg(Msg, State) -> {ok, State} | {stop,
+ ChannelId, State}</name>
+ <fsummary>Handles <c>ssh</c> connection protocol messages.</fsummary>
+ <type>
+ <v>Msg = ssh_connection:event()</v>
+ <v>ChannelId = <seealso marker="ssh#type-channel_id">ssh:channel_id()</seealso></v>
+ <v>State = term()</v>
+ </type>
+ <desc>
+ <p>Handles SSH Connection Protocol messages that may need
+ service-specific attention. For details,
+ see <seealso marker="ssh_connection"> ssh_connection:event()</seealso>.
+ </p>
+
+ <p>The following message is taken care of by the
+ <c>ssh_client_channel</c> behavior.</p>
+
+ <taglist>
+ <tag><c>{closed, ssh:channel_id()}</c></tag>
+ <item><p>The channel behavior sends a close message to the
+ other side, if such a message has not already been sent.
+ Then it terminates the channel with reason <c>normal</c>.</p></item>
+ </taglist>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0">Module:terminate(Reason, State) -> _</name>
+ <fsummary>Does cleaning up before channel process termination.
+ </fsummary>
+ <type>
+ <v>Reason = term()</v>
+ <v>State = term()</v>
+ </type>
+ <desc>
+ <p>This function is called by a channel process when it is
+ about to terminate. Before this function is called, <seealso
+ marker="ssh_connection#close-2"> ssh_connection:close/2
+ </seealso> is called, if it has not been called earlier.
+ This function does any necessary cleaning
+ up. When it returns, the channel process terminates with
+ reason <c>Reason</c>. The return value is ignored.
+ </p>
+ </desc>
+ </func>
+
+ </funcs>
+
+</erlref>
diff --git a/lib/ssh/doc/src/ssh_client_key_api.xml b/lib/ssh/doc/src/ssh_client_key_api.xml
index 98a1676ca4..9f2f3013e5 100644
--- a/lib/ssh/doc/src/ssh_client_key_api.xml
+++ b/lib/ssh/doc/src/ssh_client_key_api.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2012</year>
- <year>2016</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -29,7 +29,7 @@
<date></date>
<rev></rev>
</header>
- <module>ssh_client_key_api</module>
+ <module since="OTP R16B">ssh_client_key_api</module>
<modulesummary>
-behaviour(ssh_client_key_api).
</modulesummary>
@@ -41,7 +41,7 @@
see the <seealso marker="SSH_app"> ssh(6)</seealso> application manual.</p>
</description>
- <section>
+ <!-- section>
<title>DATA TYPES</title>
<p>Type definitions that are used more than once in this module,
@@ -68,23 +68,34 @@
| 'rsa-sha2-256' | 'rsa-sha2-384' | 'rsa-sha2-512'
| 'ecdsa-sha2-nistp256' | 'ecdsa-sha2-nistp384' | 'ecdsa-sha2-nistp521' </c></p></item>
</taglist>
- </section>
+ </section -->
+
+ <datatypes>
+ <datatype>
+ <name name="client_key_cb_options"/>
+ <desc>
+ <p>Options provided to <seealso marker="ssh#connect-3">ssh:connect/[3,4]</seealso>.
+ </p>
+ <p>The option list given in the
+ <seealso marker="ssh#type-key_cb_common_option"><c>key_cb</c></seealso>
+ option is available with the key <c>key_cb_private</c>.
+ </p>
+ </desc>
+ </datatype>
+ </datatypes>
<funcs>
<func>
- <name>Module:add_host_key(HostNames, Key, ConnectOptions) -> ok | {error, Reason}</name>
+ <name since="OTP R16B">Module:add_host_key(HostNames, PublicHostKey, ConnectOptions) -> ok | {error, Reason}</name>
<fsummary>Adds a host key to the set of trusted host keys.</fsummary>
<type>
- <v>HostNames = string()</v>
- <d>Description of the host that owns the <c>PublicKey</c>.</d>
+ <v>HostNames = string()</v>
+ <d>Description of the host that owns the <c>PublicHostKey</c>.</d>
- <v>Key = public_key()</v>
- <d>Normally an RSA, DSA or ECDSA public key, but handling of other public keys can be added.</d>
+ <v>PublicHostKey = <seealso marker="public_key:public_key#type-public_key">public_key:public_key()</seealso></v>
+ <d>Of ECDSA keys, only the Normally an RSA, DSA or ECDSA public key, but handling of other public keys can be added.</d>
- <v>ConnectOptions = proplists:proplist()</v>
- <d>Options provided to <seealso marker="ssh#connect-3">ssh:connect/[3,4]</seealso>. The option list given in
- the <c>key_cb</c> option is available with the key <c>key_cb_private</c>.</d>
- <v>Reason = term().</v>
+ <v>ConnectOptions = <seealso marker="#type-client_key_cb_options">client_key_cb_options()</seealso></v>
</type>
<desc>
<p>Adds a host key to the set of trusted host keys.</p>
@@ -92,21 +103,19 @@
</func>
<func>
- <name>Module:is_host_key(Key, Host, Algorithm, ConnectOptions) -> Result</name>
+ <name since="OTP R16B">Module:is_host_key(Key, Host, Algorithm, ConnectOptions) -> Result</name>
<fsummary>Checks if a host key is trusted.</fsummary>
<type>
- <v>Key = public_key() </v>
+ <v>Key = <seealso marker="public_key:public_key#type-public_key">public_key:public_key()</seealso></v>
<d>Normally an RSA, DSA or ECDSA public key, but handling of other public keys can be added.</d>
<v>Host = string()</v>
<d>Description of the host.</d>
- <v>Algorithm = public_key_algorithm()</v>
+ <v>Algorithm = <seealso marker="ssh#type-pubkey_alg">ssh:pubkey_alg()</seealso></v>
<d>Host key algorithm.</d>
- <v>ConnectOptions = proplists:proplist() </v>
- <d>Options provided to <seealso marker="ssh#connect-3">ssh:connect/[3,4]</seealso>. The option list given in
- the <c>key_cb</c> option is available with the key <c>key_cb_private</c>.</d>
+ <v>ConnectOptions = <seealso marker="#type-client_key_cb_options">client_key_cb_options()</seealso></v>
<v>Result = boolean()</v>
</type>
@@ -116,18 +125,16 @@
</func>
<func>
- <name>Module:user_key(Algorithm, ConnectOptions) ->
+ <name since="OTP R16B">Module:user_key(Algorithm, ConnectOptions) ->
{ok, PrivateKey} | {error, Reason}</name>
<fsummary>Fetches the users <em>public key</em> matching the <c>Algorithm</c>.</fsummary>
<type>
- <v>Algorithm = public_key_algorithm()</v>
+ <v>Algorithm = <seealso marker="ssh#type-pubkey_alg">ssh:pubkey_alg()</seealso></v>
<d>Host key algorithm.</d>
- <v>ConnectOptions = proplists:proplist()</v>
- <d>Options provided to <seealso marker="ssh#connect-3">ssh:connect/[3,4]</seealso>. The option list given in
- the <c>key_cb</c> option is available with the key <c>key_cb_private</c>.</d>
+ <v>ConnectOptions = <seealso marker="#type-client_key_cb_options">client_key_cb_options()</seealso></v>
- <v>PrivateKey = private_key()</v>
+ <v>PrivateKey = <seealso marker="public_key:public_key#type-private_key">public_key:private_key()</seealso></v>
<d>Private key of the user matching the <c>Algorithm</c>.</d>
<v>Reason = term()</v>
diff --git a/lib/ssh/doc/src/ssh_connection.xml b/lib/ssh/doc/src/ssh_connection.xml
index 150d46a9a2..2a701929f6 100644
--- a/lib/ssh/doc/src/ssh_connection.xml
+++ b/lib/ssh/doc/src/ssh_connection.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2008</year>
- <year>2015</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -30,7 +30,7 @@
<date></date>
<rev></rev>
</header>
- <module>ssh_connection</module>
+ <module since="">ssh_connection</module>
<modulesummary>
This module provides API functions to send SSH Connection Protocol
events to the other side of an SSH channel.
@@ -43,10 +43,10 @@
which are received as messages by the remote channel.
If the receiving channel is an Erlang process, the
messages have the format
- <c><![CDATA[{ssh_cm, ssh_connection_ref(), ssh_event_msg()}]]></c>.
- If the <seealso marker="ssh_channel">ssh_channel</seealso> behavior is used to
+ <c><![CDATA[{ssh_cm, connection_ref(), ssh_event_msg()}]]></c>.
+ If the <seealso marker="ssh_client_channel">ssh_client_channel</seealso> behavior is used to
implement the channel process, these messages are handled by
- <seealso marker="ssh_channel#Module:handle_ssh_msg-2">handle_ssh_msg/2</seealso>.</p>
+ <seealso marker="ssh_client_channel#Module:handle_ssh_msg-2">handle_ssh_msg/2</seealso>.</p>
</description>
<section>
@@ -63,10 +63,10 @@
<item><p>list of ASCII characters</p></item>
<tag><c>timeout() =</c></tag>
<item><p><c>infinity | integer()</c> in milliseconds</p></item>
- <tag><c>ssh_connection_ref() =</c></tag>
+ <tag><c>connection_ref() =</c></tag>
<item><p>opaque() -as returned by
<c>ssh:connect/3</c> or sent to an SSH channel processes</p></item>
- <tag><c>ssh_channel_id() =</c></tag>
+ <tag><c>channel_id() =</c></tag>
<item><p><c>integer()</c></p></item>
<tag><c>ssh_data_type_code() =</c></tag>
<item><p><c>1</c> ("stderr") | <c>0</c> ("normal") are
@@ -75,7 +75,7 @@
<tag><c>ssh_request_status() =</c></tag>
<item><p> <c>success | failure</c></p></item>
<tag><c>event() =</c></tag>
- <item><p><c>{ssh_cm, ssh_connection_ref(), ssh_event_msg()}</c></p></item>
+ <item><p><c>{ssh_cm, connection_ref(), ssh_event_msg()}</c></p></item>
<tag><c>ssh_event_msg() =</c></tag>
<item><p><c>data_events() | status_events() | terminal_events()</c></p></item>
<tag><c>reason() =</c></tag>
@@ -86,12 +86,12 @@
<tag><em>data_events()</em></tag>
<item>
<taglist>
- <tag><c><![CDATA[{data, ssh_channel_id(), ssh_data_type_code(), Data :: binary()}]]></c></tag>
+ <tag><c><![CDATA[{data, channel_id(), ssh_data_type_code(), Data :: binary()}]]></c></tag>
<item><p>Data has arrived on the channel. This event is sent as a
result of calling <seealso marker="ssh_connection#send-3">
ssh_connection:send/[3,4,5]</seealso>.</p></item>
- <tag><c><![CDATA[{eof, ssh_channel_id()}]]></c></tag>
+ <tag><c><![CDATA[{eof, channel_id()}]]></c></tag>
<item><p>Indicates that the other side sends no more data.
This event is sent as a result of calling <seealso
marker="ssh_connection#send_eof-2"> ssh_connection:send_eof/2</seealso>.
@@ -103,7 +103,7 @@
<item>
<taglist>
- <tag><c><![CDATA[{signal, ssh_channel_id(), ssh_signal()}]]></c></tag>
+ <tag><c><![CDATA[{signal, channel_id(), ssh_signal()}]]></c></tag>
<item><p>A signal can be delivered to the remote process/service
using the following message. Some systems do not support
signals, in which case they are to ignore this message. There is
@@ -111,7 +111,7 @@
referred to are on OS-level and not something generated by an
Erlang program.</p></item>
- <tag><c><![CDATA[{exit_signal, ssh_channel_id(), ExitSignal :: string(), ErrorMsg ::string(),
+ <tag><c><![CDATA[{exit_signal, channel_id(), ExitSignal :: string(), ErrorMsg ::string(),
LanguageString :: string()}]]></c></tag>
<item><p>A remote execution can terminate violently because of a signal.
@@ -119,7 +119,7 @@
values, see <url href="http://www.ietf.org/rfc/rfc4254.txt">RFC 4254</url>
Section 6.10, which shows a special case of these signals.</p></item>
- <tag><c><![CDATA[{exit_status, ssh_channel_id(), ExitStatus :: integer()}]]></c></tag>
+ <tag><c><![CDATA[{exit_status, channel_id(), ExitStatus :: integer()}]]></c></tag>
<item><p>When the command running at the other end terminates, the
following message can be sent to return the exit status of the
command. A zero <c>exit_status</c> usually means that the command
@@ -127,11 +127,11 @@
<seealso marker="ssh_connection#exit_status-3">
ssh_connection:exit_status/3</seealso>.</p></item>
- <tag><c><![CDATA[{closed, ssh_channel_id()}]]></c></tag>
+ <tag><c><![CDATA[{closed, channel_id()}]]></c></tag>
<item><p>This event is sent as a result of calling
<seealso marker="ssh_connection#close-2">ssh_connection:close/2</seealso>.
Both the handling of this event and sending it are taken care of by the
- <seealso marker="ssh_channel">ssh_channel</seealso> behavior.</p></item>
+ <seealso marker="ssh_client_channel">ssh_client_channel</seealso> behavior.</p></item>
</taglist>
</item>
@@ -149,14 +149,14 @@
with the boolean value of <c>WantReply</c> as the second argument.</p>
<taglist>
- <tag><c><![CDATA[{env, ssh_channel_id(), WantReply :: boolean(),
+ <tag><c><![CDATA[{env, channel_id(), WantReply :: boolean(),
Var ::string(), Value :: string()}]]></c></tag>
<item><p>Environment variables can be passed to the shell/command
to be started later. This event is sent as a result of calling <seealso
marker="ssh_connection#setenv-5"> ssh_connection:setenv/5</seealso>.
</p></item>
- <tag><c><![CDATA[{pty, ssh_channel_id(),
+ <tag><c><![CDATA[{pty, channel_id(),
WantReply :: boolean(), {Terminal :: string(), CharWidth :: integer(),
RowHeight :: integer(), PixelWidth :: integer(), PixelHeight :: integer(),
TerminalModes :: [{Opcode :: atom() | integer(),
@@ -181,13 +181,13 @@
<seealso marker="ssh_connection#shell-2"> ssh_connection:shell/2</seealso>.
</p></item>
- <tag><c><![CDATA[{window_change, ssh_channel_id(), CharWidth() :: integer(),
+ <tag><c><![CDATA[{window_change, channel_id(), CharWidth() :: integer(),
RowHeight :: integer(), PixWidth :: integer(), PixHeight :: integer()}]]></c></tag>
<item><p>When the window (terminal) size changes on the client
side, it <em>can</em> send a message to the server side to inform it of
the new dimensions. No API function generates this event.</p></item>
- <tag><c><![CDATA[{exec, ssh_channel_id(),
+ <tag><c><![CDATA[{exec, channel_id(),
WantReply :: boolean(), Cmd :: string()}]]></c></tag>
<item><p>This message requests that the server starts
execution of the given command. This event is sent as a result of calling <seealso
@@ -201,51 +201,51 @@
<funcs>
<func>
- <name>adjust_window(ConnectionRef, ChannelId, NumOfBytes) -> ok</name>
+ <name since="">adjust_window(ConnectionRef, ChannelId, NumOfBytes) -> ok</name>
<fsummary>Adjusts the SSH flow control window.</fsummary>
<type>
- <v>ConnectionRef = ssh_connection_ref()</v>
- <v>ChannelId = ssh_channel_id()</v>
+ <v>ConnectionRef = connection_ref()</v>
+ <v>ChannelId = channel_id()</v>
<v>NumOfBytes = integer()</v>
</type>
<desc>
<p>Adjusts the SSH flow control window. This is to be done by both the
client- and server-side channel processes.</p>
- <note><p>Channels implemented with the <seealso marker="ssh_channel"> ssh_channel</seealso>
+ <note><p>Channels implemented with the <seealso marker="ssh_client_channel"> ssh_client_channel</seealso>
behavior do not normally need to call this function as flow control
is handled by the behavior. The behavior adjusts the window every time
- the callback <seealso marker="ssh_channel#Module:handle_ssh_msg-2">
+ the callback <seealso marker="ssh_client_channel#Module:handle_ssh_msg-2">
handle_ssh_msg/2</seealso> returns after processing channel data.</p></note>
</desc>
</func>
<func>
- <name>close(ConnectionRef, ChannelId) -> ok</name>
+ <name since="">close(ConnectionRef, ChannelId) -> ok</name>
<fsummary>Sends a close message on the channel <c>ChannelId</c>.</fsummary>
<type>
- <v>ConnectionRef = ssh_connection_ref()</v>
- <v>ChannelId = ssh_channel_id()</v>
+ <v>ConnectionRef = connection_ref()</v>
+ <v>ChannelId = channel_id()</v>
</type>
<desc>
<p>A server- or client-channel process can choose to close their session by
sending a close event.
</p>
- <note><p>This function is called by the <c>ssh_channel</c>
+ <note><p>This function is called by the <c>ssh_client_channel</c>
behavior when the channel is terminated, see <seealso
- marker="ssh_channel"> ssh_channel(3)</seealso>. Thus, channels implemented
+ marker="ssh_client_channel"> ssh_client_channel(3)</seealso>. Thus, channels implemented
with the behavior are not to call this function explicitly.</p></note>
</desc>
</func>
<func>
- <name>exec(ConnectionRef, ChannelId, Command, TimeOut) -> ssh_request_status() |
+ <name since="">exec(ConnectionRef, ChannelId, Command, TimeOut) -> ssh_request_status() |
{error, reason()}</name>
<fsummary>Requests that the server starts the execution of the given command.</fsummary>
<type>
- <v>ConnectionRef = ssh_connection_ref()</v>
- <v>ChannelId = ssh_channel_id()</v>
+ <v>ConnectionRef = connection_ref()</v>
+ <v>ChannelId = channel_id()</v>
<v>Command = string()</v>
<v>Timeout = timeout()</v>
</type>
@@ -256,39 +256,39 @@
request is a one-time execution that closes the channel when it is done.</p>
<taglist>
- <tag><c>N x {ssh_cm, ssh_connection_ref(),
- {data, ssh_channel_id(), ssh_data_type_code(), Data :: binary()}}</c></tag>
+ <tag><c>N x {ssh_cm, connection_ref(),
+ {data, channel_id(), ssh_data_type_code(), Data :: binary()}}</c></tag>
<item><p>The result of executing the command can be only one line
or thousands of lines depending on the command.</p></item>
- <tag><c>0 or 1 x {ssh_cm, ssh_connection_ref(), {eof, ssh_channel_id()}}</c></tag>
+ <tag><c>0 or 1 x {ssh_cm, connection_ref(), {eof, channel_id()}}</c></tag>
<item><p>Indicates that no more data is to be sent.</p></item>
<tag><c>0 or 1 x {ssh_cm,
- ssh_connection_ref(), {exit_signal,
- ssh_channel_id(), ExitSignal :: string(), ErrorMsg :: string(), LanguageString :: string()}}</c></tag>
+ connection_ref(), {exit_signal,
+ channel_id(), ExitSignal :: string(), ErrorMsg :: string(), LanguageString :: string()}}</c></tag>
<item><p>Not all systems send signals. For details on valid string
values, see RFC 4254, Section 6.10</p></item>
- <tag><c>0 or 1 x {ssh_cm, ssh_connection_ref(), {exit_status,
- ssh_channel_id(), ExitStatus :: integer()}}</c></tag>
+ <tag><c>0 or 1 x {ssh_cm, connection_ref(), {exit_status,
+ channel_id(), ExitStatus :: integer()}}</c></tag>
<item><p>It is recommended by the SSH Connection Protocol to send this
message, but that is not always the case.</p></item>
- <tag><c>1 x {ssh_cm, ssh_connection_ref(),
- {closed, ssh_channel_id()}}</c></tag>
- <item><p>Indicates that the <c>ssh_channel</c> started for the
+ <tag><c>1 x {ssh_cm, connection_ref(),
+ {closed, channel_id()}}</c></tag>
+ <item><p>Indicates that the <c>ssh_client_channel</c> started for the
execution of the command has now been shut down.</p></item>
</taglist>
</desc>
</func>
<func>
- <name>exit_status(ConnectionRef, ChannelId, Status) -> ok</name>
+ <name since="">exit_status(ConnectionRef, ChannelId, Status) -> ok</name>
<fsummary>Sends the exit status of a command to the client.</fsummary>
<type>
- <v>ConnectionRef = ssh_connection_ref() </v>
- <v>ChannelId = ssh_channel_id()</v>
+ <v>ConnectionRef = connection_ref() </v>
+ <v>ChannelId = channel_id()</v>
<v>Status = integer()</v>
</type>
<desc>
@@ -298,14 +298,14 @@
</func>
<func>
- <name>ptty_alloc(ConnectionRef, ChannelId, Options) -></name>
- <name>ptty_alloc(ConnectionRef, ChannelId, Options, Timeout) -> > ssh_request_status() |
+ <name since="OTP 17.5">ptty_alloc(ConnectionRef, ChannelId, Options) -></name>
+ <name since="OTP 17.4">ptty_alloc(ConnectionRef, ChannelId, Options, Timeout) -> > ssh_request_status() |
{error, reason()}</name>
<fsummary>Sends an SSH Connection Protocol <c>pty_req</c>,
to allocate a pseudo-terminal.</fsummary>
<type>
- <v>ConnectionRef = ssh_connection_ref()</v>
- <v>ChannelId = ssh_channel_id()</v>
+ <v>ConnectionRef = connection_ref()</v>
+ <v>ChannelId = channel_id()</v>
<v>Options = proplists:proplist()</v>
</type>
<desc>
@@ -339,13 +339,13 @@
</func>
<func>
- <name>reply_request(ConnectionRef, WantReply, Status, ChannelId) -> ok</name>
+ <name since="">reply_request(ConnectionRef, WantReply, Status, ChannelId) -> ok</name>
<fsummary>Sends status replies to requests that want such replies.</fsummary>
<type>
- <v>ConnectionRef = ssh_connection_ref()</v>
+ <v>ConnectionRef = connection_ref()</v>
<v>WantReply = boolean()</v>
<v>Status = ssh_request_status()</v>
- <v>ChannelId = ssh_channel_id()</v>
+ <v>ChannelId = channel_id()</v>
</type>
<desc>
<p>Sends status replies to requests where the requester has
@@ -357,15 +357,15 @@
</func>
<func>
- <name>send(ConnectionRef, ChannelId, Data) -></name>
- <name>send(ConnectionRef, ChannelId, Data, Timeout) -></name>
- <name>send(ConnectionRef, ChannelId, Type, Data) -></name>
- <name>send(ConnectionRef, ChannelId, Type, Data, TimeOut) ->
+ <name since="">send(ConnectionRef, ChannelId, Data) -></name>
+ <name since="">send(ConnectionRef, ChannelId, Data, Timeout) -></name>
+ <name since="">send(ConnectionRef, ChannelId, Type, Data) -></name>
+ <name since="">send(ConnectionRef, ChannelId, Type, Data, TimeOut) ->
ok | {error, timeout} | {error, closed}</name>
<fsummary>Sends channel data.</fsummary>
<type>
- <v>ConnectionRef = ssh_connection_ref()</v>
- <v>ChannelId = ssh_channel_id()</v>
+ <v>ConnectionRef = connection_ref()</v>
+ <v>ChannelId = channel_id()</v>
<v>Data = binary()</v>
<v>Type = ssh_data_type_code()</v>
<v>Timeout = timeout()</v>
@@ -380,11 +380,11 @@
</func>
<func>
- <name>send_eof(ConnectionRef, ChannelId) -> ok | {error, closed}</name>
+ <name since="">send_eof(ConnectionRef, ChannelId) -> ok | {error, closed}</name>
<fsummary>Sends EOF on channel <c>ChannelId</c>.</fsummary>
<type>
- <v>ConnectionRef = ssh_connection_ref()</v>
- <v>ChannelId = ssh_channel_id()</v>
+ <v>ConnectionRef = connection_ref()</v>
+ <v>ChannelId = channel_id()</v>
</type>
<desc>
<p>Sends EOF on channel <c>ChannelId</c>.</p>
@@ -392,12 +392,12 @@
</func>
<func>
- <name>session_channel(ConnectionRef, Timeout) -></name>
- <name>session_channel(ConnectionRef, InitialWindowSize,
- MaxPacketSize, Timeout) -> {ok, ssh_channel_id()} | {error, reason()}</name>
+ <name since="">session_channel(ConnectionRef, Timeout) -></name>
+ <name since="">session_channel(ConnectionRef, InitialWindowSize,
+ MaxPacketSize, Timeout) -> {ok, channel_id()} | {error, reason()}</name>
<fsummary>Opens a channel for an SSH session.</fsummary>
<type>
- <v>ConnectionRef = ssh_connection_ref()</v>
+ <v>ConnectionRef = connection_ref()</v>
<v>InitialWindowSize = integer()</v>
<v>MaxPacketSize = integer()</v>
<v>Timeout = timeout()</v>
@@ -410,13 +410,13 @@
</func>
<func>
- <name>setenv(ConnectionRef, ChannelId, Var, Value, TimeOut) -> ssh_request_status() |
+ <name since="">setenv(ConnectionRef, ChannelId, Var, Value, TimeOut) -> ssh_request_status() |
{error, reason()}</name>
<fsummary>Environment variables can be passed to the
shell/command to be started later.</fsummary>
<type>
- <v>ConnectionRef = ssh_connection_ref()</v>
- <v>ChannelId = ssh_channel_id()</v>
+ <v>ConnectionRef = connection_ref()</v>
+ <v>ChannelId = channel_id()</v>
<v>Var = string()</v>
<v>Value = string()</v>
<v>Timeout = timeout()</v>
@@ -428,28 +428,32 @@
</func>
<func>
- <name>shell(ConnectionRef, ChannelId) -> ssh_request_status() | {error, closed}
+ <name since="">shell(ConnectionRef, ChannelId) -> ok | failure | {error, closed}
</name>
<fsummary>Requests that the user default shell (typically defined in
/etc/passwd in Unix systems) is to be executed at the server end.</fsummary>
<type>
- <v>ConnectionRef = ssh_connection_ref()</v>
- <v>ChannelId = ssh_channel_id()</v>
+ <v>ConnectionRef = connection_ref()</v>
+ <v>ChannelId = channel_id()</v>
</type>
<desc>
<p>Is to be called by a client channel process to request that the user default
shell (typically defined in /etc/passwd in Unix systems) is executed
at the server end.</p>
+ <p>Note: the return value is <c>ok</c> instead of <c>success</c> unlike in other
+ functions in this module. This is a fault that was introduced so long ago that
+ any change would break a large number of existing software.
+ </p>
</desc>
</func>
<func>
- <name>subsystem(ConnectionRef, ChannelId, Subsystem, Timeout) -> ssh_request_status() |
+ <name since="">subsystem(ConnectionRef, ChannelId, Subsystem, Timeout) -> ssh_request_status() |
{error, reason()}</name>
<fsummary>Requests to execute a predefined subsystem on the server.</fsummary>
<type>
- <v>ConnectionRef = ssh_connection_ref()</v>
- <v>ChannelId = ssh_channel_id()</v>
+ <v>ConnectionRef = connection_ref()</v>
+ <v>ChannelId = channel_id()</v>
<v>Subsystem = string()</v>
<v>Timeout = timeout()</v>
</type>
diff --git a/lib/ssh/doc/src/ssh_file.xml b/lib/ssh/doc/src/ssh_file.xml
new file mode 100644
index 0000000000..f1fef09083
--- /dev/null
+++ b/lib/ssh/doc/src/ssh_file.xml
@@ -0,0 +1,285 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2018</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>ssh_file</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ </header>
+ <module since="OTP 21.2">ssh_file</module>
+ <modulesummary>Default callback module for the client's and server's database operations in the ssh application</modulesummary>
+ <description>
+ <p>This module is the default callback handler for the client's and the server's user and host "database" operations.
+ All data, for instance key pairs, are stored in files in the normal file system. This page documents the files, where they
+ are stored and configuration options for this callback module.
+ </p>
+ <p>The intention is to be compatible with the
+ <url href="http://www.openssh.com">OpenSSH</url>
+ storage in files. Therefore it mimics directories and filenames of
+ <url href="http://www.openssh.com">OpenSSH</url>.
+ </p>
+
+ <p>Ssh_file implements the <seealso marker="ssh:ssh_server_key_api">ssh_server_key_api</seealso> and
+ the <seealso marker="ssh:ssh_client_key_api">ssh_client_key_api</seealso>.
+ This enables the user to make an own interface using for example a database handler.
+ </p>
+ <p>Such another callback module could be used by setting the option
+ <seealso marker="ssh:ssh#type-key_cb_common_option"><c>key_cb</c></seealso>
+ when starting a client or a server (with for example
+ <seealso marker="ssh:ssh#connect-3">ssh:connect</seealso>,
+ <seealso marker="ssh:ssh#daemon-2">ssh:daemon</seealso> of
+ <seealso marker="ssh:ssh#shell-1">ssh:shell</seealso>
+ ).
+ </p>
+
+ <note>
+ <p>The functions are <i>Callbacks</i> for the SSH app. They are not intended to be called from the user's code!
+ </p>
+ </note>
+ </description>
+
+ <section>
+ <title>Files, directories and who uses them</title>
+ <section>
+ <title>Daemons</title>
+ <p>Daemons uses all files stored in the <seealso marker="#SYSDIR">SYSDIR</seealso> directory.
+ </p>
+ <p>Optionaly, in case of <c>publickey</c> authorization, one or more of the remote user's public keys
+ in the <seealso marker="#USERDIR">USERDIR</seealso> directory are used.
+ See the files
+ <seealso marker="#USERDIR-authorized_keys"><c>USERDIR/authorized_keys</c></seealso> and
+ <seealso marker="#USERDIR-authorized_keys2"><c>USERDIR/authorized_keys2</c></seealso>.
+ </p>
+ </section>
+
+ <section>
+ <title>Clients</title>
+ <p>Clients uses all files stored in the <seealso marker="#USERDIR">USERDIR</seealso> directory.
+ </p>
+ </section>
+
+ <section>
+ <title>Directory contents</title>
+ <taglist>
+ <tag><marker id="LOCALUSER"/>LOCALUSER</tag>
+ <item><p>The user name of the OS process running the Erlang virtual machine (emulator).</p>
+ </item>
+
+ <tag><marker id="SYSDIR"/>SYSDIR</tag>
+ <item><p>This is the directory holding the server's files:</p>
+ <list>
+ <item><marker id="SYSDIR-ssh_host_dsa_key"/><c>ssh_host_dsa_key</c> - private dss host key (optional)</item>
+ <item><marker id="SYSDIR-ssh_host_rsa_key"/><c>ssh_host_rsa_key</c> - private rsa host key (optional)</item>
+ <item><marker id="SYSDIR-ssh_host_ecdsa_key"/><c>ssh_host_ecdsa_key</c> - private ecdsa host key (optional)</item>
+ <item><marker id="SYSDIR-ssh_host_ed25519_key"/><c>ssh_host_ed25519_key</c> - private eddsa host key for curve 25519 (optional)</item>
+ <item><marker id="SYSDIR-ssh_host_ed448_key"/><c>ssh_host_ed448_key</c> - private eddsa host key for curve 448 (optional)</item>
+ </list>
+ <p>At least one host key must be defined. The default value of SYSDIR is <marker id="#/etc/ssh"/><c>/etc/ssh</c>.
+ </p>
+ <p>For security reasons, this directory is normally accessible only to the root user.
+ </p>
+ <p>To change the SYSDIR, see the <seealso marker="#type-system_dir_daemon_option">system_dir</seealso> option.
+ </p>
+ </item>
+
+ <tag><marker id="USERDIR"/>USERDIR</tag>
+ <item><p>This is the directory holding the files:</p>
+ <list>
+ <item><marker id="USERDIR-authorized_keys"/><c>authorized_keys</c>
+ and, as second alternative
+ <marker id="USERDIR-authorized_keys2"/><c>authorized_keys2</c> -
+ the user's public keys are stored concatenated in one of those files.
+ </item>
+ <item><marker id="USERDIR-known_hosts"/><c>known_hosts</c> - host keys from hosts visited
+ concatenated. The file is created and used by the client.</item>
+ <item><marker id="USERDIR-id_dsa"/><c>id_dsa</c> - private dss user key (optional)</item>
+ <item><marker id="USERDIR-id_rsa"/><c>id_rsa</c> - private rsa user key (optional)</item>
+ <item><marker id="USERDIR-id_ecdsa"/><c>id_ecdsa</c> - private ecdsa user key (optional)</item>
+ <item><marker id="USERDIR-id_ed25519"/><c>id_ed25519</c> - private eddsa user key for curve 25519 (optional)</item>
+ <item><marker id="USERDIR-id_ed448"/><c>id_ed448</c> - private eddsa user key for curve 448 (optional)</item>
+ </list>
+ <p>The default value of USERDIR is <c>/home/</c><seealso marker="#LOCALUSER"><c>LOCALUSER</c></seealso><c>/.ssh</c>.
+ </p>
+ <p>To change the USERDIR, see the <seealso marker="#type-user_dir_common_option">user_dir</seealso> option
+ </p>
+ </item>
+ </taglist>
+ </section>
+ </section>
+
+ <datatypes>
+ <datatype_title>Options for the default ssh_file callback module</datatype_title>
+ <datatype>
+ <name name="user_dir_common_option"/>
+ <desc>
+ <p>Sets the <seealso marker="#USERDIR">user directory</seealso>.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="user_dir_fun_common_option"/>
+ <name name="user2dir"/>
+ <desc>
+ <p>Sets the <seealso marker="#USERDIR">user directory</seealso> dynamically
+ by evaluating the <c>user2dir</c> function.
+ </p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="system_dir_daemon_option"/>
+ <desc>
+ <p>Sets the <seealso marker="#SYSDIR">system directory</seealso>.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="pubkey_passphrase_client_options"/>
+ <desc>
+ <p>If the user's DSA, RSA or ECDSA key is protected by a passphrase, it can be
+ supplied with thoose options.
+ </p>
+ <p>Note that EdDSA passhrases (Curves 25519 and 448) are not implemented.</p>
+ </desc>
+ </datatype>
+
+ </datatypes>
+
+ <funcs>
+ <func>
+ <name since="OTP 21.2">host_key(Algorithm, DaemonOptions) -> {ok, Key} | {error, Reason}</name>
+ <fsummary></fsummary>
+ <desc>
+ <p><strong>Types and description</strong></p>
+ <p>See the api description in
+ <seealso marker="ssh:ssh_server_key_api#Module:host_key-2">ssh_server_key_api, Module:host_key/2</seealso>.
+ </p>
+ <p><strong>Options</strong></p>
+ <list>
+ <item><seealso marker="#type-system_dir_daemon_option">system_dir</seealso></item>
+ <!-- item>dsa_pass_phrase</item -->
+ <!-- item>rsa_pass_phrase</item -->
+ <!-- item>ecdsa_pass_phrase</item -->
+ </list>
+ <p><strong>Files</strong></p>
+ <list>
+ <item><seealso marker="#SYSDIR-ssh_host_rsa_key"><c>SYSDIR/ssh_host_rsa_key</c></seealso></item>
+ <item><seealso marker="#SYSDIR-ssh_host_dsa_key"><c>SYSDIR/ssh_host_dsa_key</c></seealso></item>
+ <item><seealso marker="#SYSDIR-ssh_host_ecdsa_key"><c>SYSDIR/ssh_host_ecdsa_key</c></seealso></item>
+ <item><seealso marker="#SYSDIR-ssh_host_ed25519_key"><c>SYSDIR/ssh_host_ed25519_key</c></seealso></item>
+ <item><seealso marker="#SYSDIR-ssh_host_ed448_key"><c>SYSDIR/ssh_host_ed448_key</c>c></seealso></item>
+ </list>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.2">is_auth_key(PublicUserKey, User, DaemonOptions) -> Result</name>
+ <fsummary></fsummary>
+ <desc>
+ <p><strong>Types and description</strong></p>
+ <p>See the api description in
+ <seealso marker="ssh:ssh_server_key_api#Module:is_auth_key-3">ssh_server_key_api: Module:is_auth_key/3</seealso>.
+ </p>
+ <p><strong>Options</strong></p>
+ <list>
+ <item><seealso marker="#type-user_dir_fun_common_option">user_dir_fun</seealso></item>
+ <item><seealso marker="#type-user_dir_common_option">user_dir</seealso></item>
+ </list>
+ <p><strong>Files</strong></p>
+ <list>
+ <item><seealso marker="#USERDIR-authorized_keys"><c>USERDIR/authorized_keys</c></seealso></item>
+ <item><seealso marker="#USERDIR-authorized_keys2"><c>USERDIR/authorized_keys2</c></seealso></item>
+ </list>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.2">add_host_key(HostNames, PublicHostKey, ConnectOptions) -> ok | {error, Reason}</name>
+ <fsummary></fsummary>
+ <desc>
+ <p><strong>Types and description</strong></p>
+ <p>See the api description in
+ <seealso marker="ssh:ssh_client_key_api#Module:add_host_key-3">ssh_client_key_api, Module:add_host_key/3</seealso>.
+ </p>
+ <p><strong>Option</strong></p>
+ <list>
+ <item><seealso marker="#type-user_dir_common_option">user_dir</seealso></item>
+ </list>
+ <p><strong>File</strong></p>
+ <list>
+ <item><seealso marker="#USERDIR-known_hosts"><c>USERDIR/known_hosts</c></seealso></item>
+ </list>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.2">is_host_key(Key, Host, Algorithm, ConnectOptions) -> Result</name>
+ <fsummary></fsummary>
+ <desc>
+ <p><strong>Types and description</strong></p>
+ <p>See the api description in
+ <seealso marker="ssh:ssh_client_key_api#Module:is_host_key-4">ssh_client_key_api, Module:is_host_key/4</seealso>.
+ </p>
+ <p><strong>Option</strong></p>
+ <list>
+ <item><seealso marker="#type-user_dir_common_option">user_dir</seealso></item>
+ </list>
+ <p><strong>File</strong></p>
+ <list>
+ <item><seealso marker="#USERDIR-known_hosts"><c>USERDIR/known_hosts</c></seealso></item>
+ </list>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.2">user_key(Algorithm, ConnectOptions) -> {ok, PrivateKey} | {error, Reason}</name>
+ <fsummary></fsummary>
+ <desc>
+ <p><strong>Types and description</strong></p>
+ <p>See the api description in
+ <seealso marker="ssh:ssh_client_key_api#Module:user_key-2">ssh_client_key_api, Module:user_key/2</seealso>.
+ </p>
+ <p><strong>Options</strong></p>
+ <list>
+ <item><seealso marker="#type-user_dir_common_option">user_dir</seealso></item>
+ <item><seealso marker="#type-pubkey_passphrase_client_options">dsa_pass_phrase</seealso></item>
+ <item><seealso marker="#type-pubkey_passphrase_client_options">rsa_pass_phrase</seealso></item>
+ <item><seealso marker="#type-pubkey_passphrase_client_options">ecdsa_pass_phrase</seealso></item>
+ </list>
+ <p>Note that EdDSA passhrases (Curves 25519 and 448) are not implemented.</p>
+ <p><strong>Files</strong></p>
+ <list>
+ <item><seealso marker="#USERDIR-id_dsa"><c>USERDIR/id_dsa</c></seealso></item>
+ <item><seealso marker="#USERDIR-id_rsa"><c>USERDIR/id_rsa</c></seealso></item>
+ <item><seealso marker="#USERDIR-id_ecdsa"><c>USERDIR/id_ecdsa</c></seealso></item>
+ <item><seealso marker="#USERDIR-id_ed25519"><c>USERDIR/id_ed25519</c></seealso></item>
+ <item><seealso marker="#USERDIR-id_ed448"><c>USERDIR/id_ed448</c></seealso></item>
+ </list>
+ </desc>
+ </func>
+
+ </funcs>
+
+</erlref>
diff --git a/lib/ssh/doc/src/ssh_protocol.xml b/lib/ssh/doc/src/ssh_protocol.xml
index a0032ab449..0d99a96997 100644
--- a/lib/ssh/doc/src/ssh_protocol.xml
+++ b/lib/ssh/doc/src/ssh_protocol.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2013</year><year>2016</year>
+ <year>2013</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -87,8 +87,10 @@
connection, and all channels are flow-controlled. Typically an
SSH client will open a channel, send data/commands, receive
data/"control information" and when it is done close the
- channel. The <seealso
- marker="ssh_channel">ssh_channel</seealso> behaviour makes it easy to
+ channel. The
+ <seealso marker="ssh_client_channel">ssh_client_channel</seealso> /
+ <seealso marker="ssh_server_channel">ssh_server_channel</seealso> (Replaces ssh_daemon_channel)
+ behaviours makes it easy to
write your own SSH client/server processes that use flow
control. It handles generic parts of SSH channel management and
lets you focus on the application logic.
diff --git a/lib/ssh/doc/src/ssh_server_channel.xml b/lib/ssh/doc/src/ssh_server_channel.xml
new file mode 100644
index 0000000000..a4e18bbfbf
--- /dev/null
+++ b/lib/ssh/doc/src/ssh_server_channel.xml
@@ -0,0 +1,176 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2009</year>
+ <year>2018</year>
+ <holder>Ericsson AB, All Rights Reserved</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ The Initial Developer of the Original Code is Ericsson AB.
+ </legalnotice>
+ <title>ssh_server_channel</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ </header>
+ <module since="OTP 21.0">ssh_server_channel</module>
+ <modulesummary>-behaviour(ssh_server_channel). (Replaces ssh_daemon_channel)
+ </modulesummary>
+ <description>
+ <note>
+ <p>This module replaces ssh_daemon_channel.</p>
+ <p>The old module is still available for compatibility, but should not be used for new programs.
+ The old module will not be maintained except for some error corrections
+ </p>
+ </note>
+
+ <p>SSH services (clients and servers) are implemented as channels
+ that are multiplexed over an SSH connection and communicates over
+ the <url href="http://www.ietf.org/rfc/rfc4254.txt"> SSH
+ Connection Protocol</url>. This module provides a callback API
+ that takes care of generic channel aspects for daemons, such as flow control
+ and close messages. It lets the callback functions take care of
+ the service (application) specific parts. This behavior also ensures
+ that the channel process honors the principal of an OTP-process so
+ that it can be part of a supervisor tree. This is a requirement of
+ channel processes implementing a subsystem that will be added to
+ the <c>ssh</c> applications supervisor tree.
+ </p>
+
+ <note><p>When implementing a client subsystem handler, use
+ <seealso marker="ssh_client_channel">-behaviour(ssh_client_channel)</seealso> instead.
+ </p>
+ </note>
+
+ </description>
+
+ <section>
+ <title>Callback Functions</title>
+ <p>
+ The following functions are to be exported from a
+ <c>ssh_server_channel</c> callback module.
+ </p>
+ </section>
+
+ <funcs>
+ <func>
+ <name since="OTP 21.0">Module:init(Args) -> {ok, State} | {ok, State, timeout()} |
+ {stop, Reason}</name>
+ <fsummary>Makes necessary initializations and returns the
+ initial channel state if the initializations succeed.</fsummary>
+ <type>
+ <v>Args = term()</v>
+ <d>Last argument to <c>start_link/4</c>.</d>
+ <v>State = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Makes necessary initializations and returns the initial channel
+ state if the initializations succeed.
+ </p>
+ <p>The time-out values that can be returned
+ have the same semantics as in a <seealso marker="stdlib:gen_server">gen_server</seealso>.
+ If the time-out occurs, <seealso marker="#Module:handle_msg-2">handle_msg/2</seealso>
+ is called as <c>handle_msg(timeout, State)</c>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0">Module:handle_msg(Msg, State) -> {ok, State} |
+ {stop, ChannelId, State}</name>
+
+ <fsummary>Handles other messages than SSH connection protocol,
+ call, or cast messages sent to the channel.</fsummary>
+ <type>
+ <v>Msg = timeout | term()</v>
+ <v>ChannelId = <seealso marker="ssh#type-channel_id">ssh:channel_id()</seealso></v>
+ <v>State = term() </v>
+ </type>
+ <desc>
+ <p>Handles other messages than SSH Connection Protocol, call, or
+ cast messages sent to the channel.
+ </p>
+
+ <p>Possible Erlang 'EXIT' messages is to be handled by this
+ function and all channels are to handle the following message.</p>
+
+ <taglist>
+ <tag><c>{ssh_channel_up, ssh:channel_id(), ssh:connection_ref()}</c></tag>
+ <item><p>This is the first message that the channel receives.
+ This is especially useful if the
+ server wants to send a message to the client without first
+ receiving a message from it. If the message is not
+ useful for your particular scenario, ignore it by
+ immediately returning <c>{ok, State}</c>.
+ </p></item>
+ </taglist>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0">Module:handle_ssh_msg(Msg, State) -> {ok, State} | {stop,
+ ChannelId, State}</name>
+ <fsummary>Handles <c>ssh</c> connection protocol messages.</fsummary>
+ <type>
+ <v>Msg = ssh_connection:event()</v>
+ <v>ChannelId = <seealso marker="ssh#type-channel_id">ssh:channel_id()</seealso></v>
+ <v>State = term()</v>
+ </type>
+ <desc>
+ <p>Handles SSH Connection Protocol messages that may need
+ service-specific attention. For details,
+ see <seealso marker="ssh_connection"> ssh_connection:event()</seealso>.
+ </p>
+
+ <p>The following message is taken care of by the
+ <c>ssh_server_channel</c> behavior.</p>
+
+ <taglist>
+ <tag><c>{closed, ssh:channel_id()}</c></tag>
+ <item><p>The channel behavior sends a close message to the
+ other side, if such a message has not already been sent.
+ Then it terminates the channel with reason <c>normal</c>.</p></item>
+ </taglist>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0">Module:terminate(Reason, State) -> _</name>
+ <fsummary>Does cleaning up before channel process termination.
+ </fsummary>
+ <type>
+ <v>Reason = term()</v>
+ <v>State = term()</v>
+ </type>
+ <desc>
+ <p>This function is called by a channel process when it is
+ about to terminate. Before this function is called, <seealso
+ marker="ssh_connection#close-2"> ssh_connection:close/2
+ </seealso> is called, if it has not been called earlier.
+ This function does any necessary cleaning
+ up. When it returns, the channel process terminates with
+ reason <c>Reason</c>. The return value is ignored.
+ </p>
+ </desc>
+ </func>
+
+ </funcs>
+
+</erlref>
diff --git a/lib/ssh/doc/src/ssh_server_key_api.xml b/lib/ssh/doc/src/ssh_server_key_api.xml
index c6808b95d1..013a788a4a 100644
--- a/lib/ssh/doc/src/ssh_server_key_api.xml
+++ b/lib/ssh/doc/src/ssh_server_key_api.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2012</year>
- <year>2015</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -29,7 +29,7 @@
<date></date>
<rev></rev>
</header>
- <module>ssh_server_key_api</module>
+ <module since="OTP R16B">ssh_server_key_api</module>
<modulesummary>
-behaviour(ssh_server_key_api).
</modulesummary>
@@ -41,7 +41,7 @@
see the <seealso marker="SSH_app"> ssh(6)</seealso> application manual.</p>
</description>
- <section>
+ <!-- section>
<title>DATA TYPES</title>
<p>Type definitions that are used more than once in this module,
@@ -69,22 +69,40 @@
| 'rsa-sha2-256' | 'rsa-sha2-384' | 'rsa-sha2-512'
| 'ecdsa-sha2-nistp256' | 'ecdsa-sha2-nistp384' | 'ecdsa-sha2-nistp521' </c></p></item>
</taglist>
- </section>
+ </section -->
+ <datatypes>
+ <datatype>
+ <name name="daemon_key_cb_options"/>
+ <desc>
+ <p>Options provided to <seealso marker="ssh#daemon-2">ssh:daemon/2,3</seealso>.
+ </p>
+ <p>The option list given in the
+ <seealso marker="ssh#type-key_cb_common_option"><c>key_cb</c></seealso>
+ option is available with the key <c>key_cb_private</c>.
+ </p>
+ </desc>
+ </datatype>
+ </datatypes>
+
<funcs>
<func>
- <name>Module:host_key(Algorithm, DaemonOptions) ->
+ <name since="OTP R16B">Module:host_key(Algorithm, DaemonOptions) ->
{ok, Key} | {error, Reason}</name>
<fsummary>Fetches the host’s private key.</fsummary>
<type>
- <v>Algorithm = public_key_algorithm()</v>
+ <v>Algorithm = <seealso marker="ssh#type-pubkey_alg">ssh:pubkey_alg()</seealso></v>
<d>Host key algorithm.</d>
- <v>DaemonOptions = proplists:proplist()</v>
- <d>Options provided to <seealso marker="ssh#daemon-2">ssh:daemon/[2,3]</seealso>. The option list given in
- the <c>key_cb</c> option is available with the key <c>key_cb_private</c>.</d>
- <v>Key = private_key() | crypto:engine_key_ref()</v>
+
+ <v>DaemonOptions = <seealso marker="#type-daemon_key_cb_options">daemon_key_cb_options()</seealso></v>
+
+ <v>PrivateKey = <seealso marker="public_key:public_key#type-private_key">public_key:private_key()</seealso>
+ | <seealso marker="crypto:crypto#type-engine_key_ref">crypto:engine_key_ref()</seealso>
+ </v>
+
<d>Private key of the host matching the <c>Algorithm</c>.
It may be a reference to a 'ssh-rsa', rsa-sha2-* or 'ssh-dss' (NOT ecdsa) key stored in a loaded Engine.</d>
+
<v>Reason = term()</v>
</type>
<desc>
@@ -93,16 +111,17 @@
</func>
<func>
- <name>Module:is_auth_key(Key, User, DaemonOptions) -> Result</name>
+ <name since="OTP R16B">Module:is_auth_key(PublicUserKey, User, DaemonOptions) -> Result</name>
<fsummary>Checks if the user key is authorized.</fsummary>
<type>
- <v>Key = public_key()</v>
+ <v>PublicUserKey = <seealso marker="public_key:public_key#type-public_key">public_key:public_key()</seealso></v>
<d>Normally an RSA, DSA or ECDSA public key, but handling of other public keys can be added</d>
+
<v>User = string()</v>
<d>User owning the public key.</d>
- <v>DaemonOptions = proplists:proplist()</v>
- <d>Options provided to <seealso marker="ssh#daemon-2">ssh:daemon/[2,3]</seealso>. The option list given in
- the <c>key_cb</c> option is available with the key <c>key_cb_private</c>.</d>
+
+ <v>DaemonOptions = <seealso marker="#type-daemon_key_cb_options">daemon_key_cb_options()</seealso></v>
+
<v>Result = boolean()</v>
</type>
<desc>
diff --git a/lib/ssh/doc/src/ssh_sftp.xml b/lib/ssh/doc/src/ssh_sftp.xml
index 129426a6d5..c89092798d 100644
--- a/lib/ssh/doc/src/ssh_sftp.xml
+++ b/lib/ssh/doc/src/ssh_sftp.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2005</year><year>2017</year>
+ <year>2005</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -29,7 +29,7 @@
<rev></rev>
<file>ssh_sftp.sgml</file>
</header>
- <module>ssh_sftp</module>
+ <module since="">ssh_sftp</module>
<modulesummary>SFTP client.</modulesummary>
<description>
<p>This module implements an SSH FTP (SFTP) client. SFTP is a
@@ -46,9 +46,9 @@
<taglist>
<tag><c>reason()</c></tag>
<item>
- <p>= <c>atom()</c> A description of the reason why an operation failed.</p>
+ <p>= <c>atom() | string() | tuple() </c>A description of the reason why an operation failed.</p>
<p>
- The value is formed from the sftp error codes in the protocol-level responses as defined in
+ The <c>atom()</c> value is formed from the sftp error codes in the protocol-level responses as defined in
<url href="https://tools.ietf.org/id/draft-ietf-secsh-filexfer-13.txt">draft-ietf-secsh-filexfer-13.txt</url>
section 9.1.
</p>
@@ -57,9 +57,13 @@
E.g. the error code <c>SSH_FX_NO_SUCH_FILE</c>
will cause the <c>reason()</c> to be <c>no_such_file</c>.
</p>
+ <p>The <c>string()</c> reason is the error information from the server in case of an exit-signal. If that information is empty, the reason is the exit signal name.
+ </p>
+ <p>The <c>tuple()</c> reason are other errors like the <c>{exit_status,integer()}</c> if the exit status is not 0.
+ </p>
</item>
- <tag><c>ssh_connection_ref() =</c></tag>
+ <tag><c>connection_ref() =</c></tag>
<item><p><c>opaque()</c> - as returned by
<seealso marker="ssh#connect-3"><c>ssh:connect/3</c></seealso></p></item>
@@ -78,7 +82,7 @@
<funcs>
<func>
- <name>apread(ChannelPid, Handle, Position, Len) -> {async, N} | {error, reason()}</name>
+ <name since="">apread(ChannelPid, Handle, Position, Len) -> {async, N} | {error, reason()}</name>
<fsummary>Reads asynchronously from an open file.</fsummary>
<type>
<v>ChannelPid = pid()</v>
@@ -94,7 +98,7 @@
</func>
<func>
- <name>apwrite(ChannelPid, Handle, Position, Data) -> {async, N} | {error, reason()}</name>
+ <name since="">apwrite(ChannelPid, Handle, Position, Data) -> {async, N} | {error, reason()}</name>
<fsummary>Writes asynchronously to an open file.</fsummary>
<type>
<v>ChannelPid = pid()</v>
@@ -112,7 +116,7 @@
</func>
<func>
- <name>aread(ChannelPid, Handle, Len) -> {async, N} | {error, reason()}</name>
+ <name since="">aread(ChannelPid, Handle, Len) -> {async, N} | {error, reason()}</name>
<fsummary>Reads asynchronously from an open file.</fsummary>
<type>
<v>ChannelPid = pid()</v>
@@ -133,7 +137,7 @@
</func>
<func>
- <name>awrite(ChannelPid, Handle, Data) -> {async, N} | {error, reason()}</name>
+ <name since="">awrite(ChannelPid, Handle, Data) -> {async, N} | {error, reason()}</name>
<fsummary>Writes asynchronously to an open file.</fsummary>
<type>
<v>ChannelPid = pid()</v>
@@ -155,8 +159,8 @@
</func>
<func>
- <name>close(ChannelPid, Handle) -></name>
- <name>close(ChannelPid, Handle, Timeout) -> ok | {error, reason()}</name>
+ <name since="">close(ChannelPid, Handle) -></name>
+ <name since="">close(ChannelPid, Handle, Timeout) -> ok | {error, reason()}</name>
<fsummary>Closes an open handle.</fsummary>
<type>
<v>ChannelPid = pid()</v>
@@ -169,8 +173,8 @@
</func>
<func>
- <name>delete(ChannelPid, Name) -></name>
- <name>delete(ChannelPid, Name, Timeout) -> ok | {error, reason()}</name>
+ <name since="">delete(ChannelPid, Name) -></name>
+ <name since="">delete(ChannelPid, Name, Timeout) -> ok | {error, reason()}</name>
<fsummary>Deletes a file.</fsummary>
<type>
<v>ChannelPid = pid()</v>
@@ -184,8 +188,8 @@
</func>
<func>
- <name>del_dir(ChannelPid, Name) -></name>
- <name>del_dir(ChannelPid, Name, Timeout) -> ok | {error, reason()}</name>
+ <name since="">del_dir(ChannelPid, Name) -></name>
+ <name since="">del_dir(ChannelPid, Name, Timeout) -> ok | {error, reason()}</name>
<fsummary>Deletes an empty directory.</fsummary>
<type>
<v>ChannelPid = pid()</v>
@@ -200,8 +204,8 @@
</func>
<func>
- <name>list_dir(ChannelPid, Path) -></name>
- <name>list_dir(ChannelPid, Path, Timeout) -> {ok, Filenames} | {error, reason()}</name>
+ <name since="">list_dir(ChannelPid, Path) -></name>
+ <name since="">list_dir(ChannelPid, Path, Timeout) -> {ok, Filenames} | {error, reason()}</name>
<fsummary>Lists the directory.</fsummary>
<type>
<v>ChannelPid = pid()</v>
@@ -217,8 +221,8 @@
</func>
<func>
- <name>make_dir(ChannelPid, Name) -></name>
- <name>make_dir(ChannelPid, Name, Timeout) -> ok | {error, reason()}</name>
+ <name since="">make_dir(ChannelPid, Name) -></name>
+ <name since="">make_dir(ChannelPid, Name, Timeout) -> ok | {error, reason()}</name>
<fsummary>Creates a directory.</fsummary>
<type>
<v>ChannelPid = pid()</v>
@@ -233,8 +237,8 @@
</func>
<func>
- <name>make_symlink(ChannelPid, Name, Target) -></name>
- <name>make_symlink(ChannelPid, Name, Target, Timeout) -> ok | {error, reason()}</name>
+ <name since="">make_symlink(ChannelPid, Name, Target) -></name>
+ <name since="">make_symlink(ChannelPid, Name, Target, Timeout) -> ok | {error, reason()}</name>
<fsummary>Creates a symbolic link.</fsummary>
<type>
<v>ChannelPid = pid()</v>
@@ -249,8 +253,8 @@
</func>
<func>
- <name>open(ChannelPid, File, Mode) -></name>
- <name>open(ChannelPid, File, Mode, Timeout) -> {ok, Handle} | {error, reason()}</name>
+ <name since="">open(ChannelPid, File, Mode) -></name>
+ <name since="">open(ChannelPid, File, Mode, Timeout) -> {ok, Handle} | {error, reason()}</name>
<fsummary>Opens a file and returns a handle.</fsummary>
<type>
<v>ChannelPid = pid()</v>
@@ -266,8 +270,8 @@
</desc>
</func>
<func>
- <name>opendir(ChannelPid, Path) -></name>
- <name>opendir(ChannelPid, Path, Timeout) -> {ok, Handle} | {error, reason()}</name>
+ <name since="">opendir(ChannelPid, Path) -></name>
+ <name since="">opendir(ChannelPid, Path, Timeout) -> {ok, Handle} | {error, reason()}</name>
<fsummary>Opens a directory and returns a handle.</fsummary>
<type>
<v>ChannelPid = pid()</v>
@@ -281,8 +285,8 @@
</func>
<func>
- <name>open_tar(ChannelPid, Path, Mode) -></name>
- <name>open_tar(ChannelPid, Path, Mode, Timeout) -> {ok, Handle} | {error, reason()}</name>
+ <name since="OTP 17.4">open_tar(ChannelPid, Path, Mode) -></name>
+ <name since="OTP 17.4">open_tar(ChannelPid, Path, Mode, Timeout) -> {ok, Handle} | {error, reason()}</name>
<fsummary>Opens a tar file on the server to which <c>ChannelPid</c>
is connected and returns a handle.</fsummary>
<type>
@@ -335,8 +339,8 @@
</func>
<func>
- <name>position(ChannelPid, Handle, Location) -></name>
- <name>position(ChannelPid, Handle, Location, Timeout) -> {ok, NewPosition | {error, reason()}</name>
+ <name since="">position(ChannelPid, Handle, Location) -></name>
+ <name since="">position(ChannelPid, Handle, Location, Timeout) -> {ok, NewPosition | {error, reason()}</name>
<fsummary>Sets the file position of a file.</fsummary>
<type>
<v>ChannelPid = pid()</v>
@@ -380,8 +384,8 @@
</func>
<func>
- <name>pread(ChannelPid, Handle, Position, Len) -></name>
- <name>pread(ChannelPid, Handle, Position, Len, Timeout) -> {ok, Data} | eof | {error, reason()}</name>
+ <name since="">pread(ChannelPid, Handle, Position, Len) -></name>
+ <name since="">pread(ChannelPid, Handle, Position, Len, Timeout) -> {ok, Data} | eof | {error, reason()}</name>
<fsummary>Reads from an open file.</fsummary>
<type>
<v>ChannelPid = pid()</v>
@@ -398,8 +402,8 @@
</func>
<func>
- <name>pwrite(ChannelPid, Handle, Position, Data) -> ok</name>
- <name>pwrite(ChannelPid, Handle, Position, Data, Timeout) -> ok | {error, reason()}</name>
+ <name since="">pwrite(ChannelPid, Handle, Position, Data) -> ok</name>
+ <name since="">pwrite(ChannelPid, Handle, Position, Data, Timeout) -> ok | {error, reason()}</name>
<fsummary>Writes to an open file.</fsummary>
<type>
<v>ChannelPid = pid()</v>
@@ -415,13 +419,12 @@
</func>
<func>
- <name>read(ChannelPid, Handle, Len) -></name>
- <name>read(ChannelPid, Handle, Len, Timeout) -> {ok, Data} | eof | {error, reason()}</name>
+ <name since="">read(ChannelPid, Handle, Len) -></name>
+ <name since="">read(ChannelPid, Handle, Len, Timeout) -> {ok, Data} | eof | {error, reason()}</name>
<fsummary>Reads from an open file.</fsummary>
<type>
<v>ChannelPid = pid()</v>
<v>Handle = term()</v>
- <v>Position = integer()</v>
<v>Len = integer()</v>
<v>Timeout = timeout()</v>
<v>Data = string() | binary()</v>
@@ -438,8 +441,8 @@
</func>
<func>
- <name>read_file(ChannelPid, File) -></name>
- <name>read_file(ChannelPid, File, Timeout) -> {ok, Data} | {error, reason()}</name>
+ <name since="">read_file(ChannelPid, File) -></name>
+ <name since="">read_file(ChannelPid, File, Timeout) -> {ok, Data} | {error, reason()}</name>
<fsummary>Reads a file.</fsummary>
<type>
<v>ChannelPid = pid()</v>
@@ -453,8 +456,8 @@
</func>
<func>
- <name>read_file_info(ChannelPid, Name) -></name>
- <name>read_file_info(ChannelPid, Name, Timeout) -> {ok, FileInfo} | {error, reason()}</name>
+ <name since="">read_file_info(ChannelPid, Name) -></name>
+ <name since="">read_file_info(ChannelPid, Name, Timeout) -> {ok, FileInfo} | {error, reason()}</name>
<fsummary>Gets information about a file.</fsummary>
<type>
<v>ChannelPid = pid()</v>
@@ -478,8 +481,8 @@
</func>
<func>
- <name>read_link(ChannelPid, Name) -></name>
- <name>read_link(ChannelPid, Name, Timeout) -> {ok, Target} | {error, reason()}</name>
+ <name since="">read_link(ChannelPid, Name) -></name>
+ <name since="">read_link(ChannelPid, Name, Timeout) -> {ok, Target} | {error, reason()}</name>
<fsummary>Reads symbolic link.</fsummary>
<type>
<v>ChannelPid = pid()</v>
@@ -493,8 +496,8 @@
</func>
<func>
- <name>read_link_info(ChannelPid, Name) -> {ok, FileInfo} | {error, reason()}</name>
- <name>read_link_info(ChannelPid, Name, Timeout) -> {ok, FileInfo} | {error, reason()}</name>
+ <name since="">read_link_info(ChannelPid, Name) -> {ok, FileInfo} | {error, reason()}</name>
+ <name since="">read_link_info(ChannelPid, Name, Timeout) -> {ok, FileInfo} | {error, reason()}</name>
<fsummary>Gets information about a symbolic link.</fsummary>
<type>
<v>ChannelPid = pid()</v>
@@ -514,8 +517,8 @@
</func>
<func>
- <name>rename(ChannelPid, OldName, NewName) -> </name>
- <name>rename(ChannelPid, OldName, NewName, Timeout) -> ok | {error, reason()}</name>
+ <name since="">rename(ChannelPid, OldName, NewName) -> </name>
+ <name since="">rename(ChannelPid, OldName, NewName, Timeout) -> ok | {error, reason()}</name>
<fsummary>Renames a file.</fsummary>
<type>
<v>ChannelPid = pid()</v>
@@ -531,22 +534,22 @@
</func>
<func>
- <name>start_channel(ConnectionRef) -></name>
- <name>start_channel(ConnectionRef, Options) ->
+ <name since="">start_channel(ConnectionRef) -></name>
+ <name since="">start_channel(ConnectionRef, Options) ->
{ok, Pid} | {error, reason()|term()}</name>
- <name>start_channel(Host, Options) -></name>
- <name>start_channel(Host, Port, Options) ->
+ <name since="">start_channel(Host, Options) -></name>
+ <name since="">start_channel(Host, Port, Options) ->
{ok, Pid, ConnectionRef} | {error, reason()|term()}</name>
- <name>start_channel(TcpSocket) -></name>
- <name>start_channel(TcpSocket, Options) ->
+ <name since="">start_channel(TcpSocket) -></name>
+ <name since="">start_channel(TcpSocket, Options) ->
{ok, Pid, ConnectionRef} | {error, reason()|term()}</name>
<fsummary>Starts an SFTP client.</fsummary>
<type>
<v>Host = string()</v>
- <v>ConnectionRef = ssh_connection_ref()</v>
+ <v>ConnectionRef = connection_ref()</v>
<v>Port = integer()</v>
<v>TcpSocket = port()</v>
<d>The socket is supposed to be from <seealso marker="kernel:gen_tcp#connect-3">gen_tcp:connect</seealso> or <seealso marker="kernel:gen_tcp#accept-1">gen_tcp:accept</seealso> with option <c>{active,false}</c></d>
@@ -591,7 +594,7 @@
</func>
<func>
- <name>stop_channel(ChannelPid) -> ok</name>
+ <name since="">stop_channel(ChannelPid) -> ok</name>
<fsummary>Stops the SFTP client channel.</fsummary>
<type>
<v>ChannelPid = pid()</v>
@@ -603,8 +606,8 @@
</func>
<func>
- <name>write(ChannelPid, Handle, Data) -></name>
- <name>write(ChannelPid, Handle, Data, Timeout) -> ok | {error, reason()}</name>
+ <name since="">write(ChannelPid, Handle, Data) -></name>
+ <name since="">write(ChannelPid, Handle, Data, Timeout) -> ok | {error, reason()}</name>
<fsummary>Writes to an open file.</fsummary>
<type>
<v>ChannelPid = pid()</v>
@@ -622,8 +625,8 @@
</func>
<func>
- <name>write_file(ChannelPid, File, Iolist) -></name>
- <name>write_file(ChannelPid, File, Iolist, Timeout) -> ok | {error, reason()}</name>
+ <name since="">write_file(ChannelPid, File, Iolist) -></name>
+ <name since="">write_file(ChannelPid, File, Iolist, Timeout) -> ok | {error, reason()}</name>
<fsummary>Writes a file.</fsummary>
<type>
<v>ChannelPid = pid()</v>
@@ -638,8 +641,8 @@
</func>
<func>
- <name>write_file_info(ChannelPid, Name, Info) -></name>
- <name>write_file_info(ChannelPid, Name, Info, Timeout) -> ok | {error, reason()}</name>
+ <name since="">write_file_info(ChannelPid, Name, Info) -></name>
+ <name since="">write_file_info(ChannelPid, Name, Info, Timeout) -> ok | {error, reason()}</name>
<fsummary>Writes information for a file.</fsummary>
<type>
<v>ChannelPid = pid()</v>
diff --git a/lib/ssh/doc/src/ssh_sftpd.xml b/lib/ssh/doc/src/ssh_sftpd.xml
index 1be29b3b29..ee72784add 100644
--- a/lib/ssh/doc/src/ssh_sftpd.xml
+++ b/lib/ssh/doc/src/ssh_sftpd.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2005</year><year>2016</year>
+ <year>2005</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -29,7 +29,7 @@
<rev></rev>
<file>ssh_sftpd.sgml</file>
</header>
- <module>ssh_sftpd</module>
+ <module since="">ssh_sftpd</module>
<modulesummary>Specifies the channel process to handle an SFTP subsystem.</modulesummary>
<description>
<p>Specifies a channel process to handle an SFTP subsystem.</p>
@@ -44,15 +44,14 @@
<item><p><c>"sftp"</c></p></item>
<tag><c>channel_callback() =</c></tag>
<item><p><c>atom()</c> - Name of the Erlang module implementing the subsystem using the
- <c>ssh_channel</c> behavior, see the
- <seealso marker="ssh_channel">ssh_channel(3)</seealso> manual page.</p></item>
+ <seealso marker="ssh_server_channel">ssh_server_channel</seealso> (replaces ssh_daemon_channel) behaviour.</p></item>
<tag><c>channel_init_args() =</c></tag>
<item><p><c>list()</c> - The one given as argument to function <c>subsystem_spec/1</c>.</p></item>
</taglist>
</section>
<funcs>
<func>
- <name>subsystem_spec(Options) -> subsystem_spec()</name>
+ <name since="">subsystem_spec(Options) -> subsystem_spec()</name>
<fsummary>Returns the subsystem specification that allows an SSH daemon to handle the subsystem "sftp".</fsummary>
<type>
<v>Options = [{Option, Value}]</v>
diff --git a/lib/ssh/doc/src/terminology.xml b/lib/ssh/doc/src/terminology.xml
new file mode 100644
index 0000000000..db1e08970d
--- /dev/null
+++ b/lib/ssh/doc/src/terminology.xml
@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2018</year>
+ <year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>Terminology</title>
+ <prepared></prepared>
+ <docno></docno>
+ <approved></approved>
+ <date></date>
+ <rev></rev>
+ <file>terminology.xml</file>
+ </header>
+
+ <section>
+ <title>General Information</title>
+ <p>In the following terms that may cause confusion are explained.
+ </p>
+ </section>
+
+ <section>
+ <title>The term "user"</title>
+ <p>A "user" is a term that everyone understands intuitively. However, the understandings may differ which can
+ cause confusion.
+ </p>
+ <p>The term is used differently in <url href="http://www.openssh.com">OpenSSH</url> and SSH in Erlang/OTP.
+ The reason is the different environments and use cases that are not immediatly obvious.
+ </p>
+ <p>This chapter aims at explaining the differences and giving a rationale for why Erlang/OTP handles "user" as
+ it does.
+ </p>
+
+ <section>
+ <title>In OpenSSH</title>
+ <p>Many have been in contact with the command 'ssh' on a Linux machine (or similar) to remotly log in on
+ another machine. One types
+ </p>
+ <code>ssh host</code>
+ <p>to log in on the machine named <c>host</c>. The command prompts for your password on the remote <c>host</c> and
+ then you can read, write and execute as your <i>user name</i> has rights on the remote <c>host</c>. There are
+ stronger variants with pre-distributed keys or certificates, but that are for now just details in the
+ authentication process.
+ </p>
+ <p>You could log in as the user <c>anotheruser</c> with
+ </p>
+ <code>ssh anotheruser@host</code>
+ <p>and you will then be enabled to act as <c>anotheruser</c> on the <c>host</c> if authorized correctly.
+ </p>
+ <p>So what does <i>"your user name has rights"</i> mean? In a UNIX/Linux/etc context it is exactly as that context:
+ The <i>user</i> could read, write and execute programs according to the OS rules.
+ In addition, the user has a home directory (<c>$HOME</c>) and there is a <c>$HOME/.ssh/</c> directory
+ with ssh-specific files.
+ </p>
+ <section>
+ <title>SSH password authentication</title>
+ <p>When SSH tries to log in to a host, the ssh protocol communicates the user name (as a string) and a password.
+ The remote ssh server checks that there is such a user defined and that the provided password is acceptable.
+ </p>
+ <p>If so, the user is authorized.
+ </p>
+ </section>
+ <section>
+ <title>SSH public key authentication</title>
+ <p>This is a stronger method where the ssh protocol brings the user name, the user's public key and some
+ cryptographic information which we could ignore here.
+ </p>
+ <p>The ssh server on the remote host checks:
+ </p>
+ <list>
+ <item>That the <i>user</i> has a home directory,</item>
+ <item>that home directory contains a .ssh/ directory and</item>
+ <item>the .ssh/ directory contains the public key just received in the <c>authorized_keys</c> file</item>
+ </list>
+ <p>if so, the user is authorized.
+ </p>
+ </section>
+ <section>
+ <title>The SSH server on UNIX/Linux/etc after a succesful authentication</title>
+ <p>After a succesful incoming authentication, a new process runs as the just authenticated user.</p>
+ <p>Next step is to start a service according to the ssh request. In case of a request of a shell,
+ a new one is started which handles the OS-commands that arrives from the client (that's "you").
+ </p>
+ <p>In case of a sftp request, an sftp server is started in with the user's rights. So it could read, write or delete
+ files if allowed for that user.
+ </p>
+ </section>
+ </section>
+
+ <section>
+ <title>In Erlang/OTP SSH</title>
+ <p>For the Erlang/OTP SSH server the situation is different. The server executes in an Erlang process
+ in the Erlang emulator which in turn executes in an OS process. The emulator does not try to change its
+ user when authenticated over the SSH protocol.
+ So the remote user name is only for authentication purposes in the Erlang/OTP SSH application.
+ </p>
+ <section>
+ <title>Password authentication in Erlang SSH</title>
+ <p>The Erlang/OTP SSH server checks the user name and password in the following order:
+ </p>
+ <list type="ordered">
+ <item>If a
+ <seealso marker="ssh:ssh#option-pwdfun"><c>pwdfun</c></seealso>
+ is defined, that one is called and the returned boolean is the authentication result.
+ </item>
+ <item>Else, if the
+ <seealso marker="ssh:ssh#option-user_passwords"><c>user_passwords</c></seealso>
+ option is defined and the username and the password matches, the authentication is a success.
+ </item>
+ <item>Else, if the option
+ <seealso marker="ssh:ssh#option-password"><c>password</c></seealso>
+ is defined and matches the password the authentication is a success.
+ Note that the use of this option is not recommended in non-test code.
+ </item>
+ </list>
+ </section>
+ <section>
+ <title>Public key authentication in Erlang SSH</title>
+ <p>The user name, public key and cryptographic data (a signature) that is sent by the client, are used as follows
+ (some steps left out for clearity):
+ </p>
+ <list type="ordered">
+ <item>A callback module is selected using the options
+ <seealso marker="ssh:ssh#type-key_cb_common_option"><c>key_cb</c></seealso>.
+ </item>
+ <item>The callback module is used to check that the provided public key is one of the user's pre-stored.
+ In case of the default callback module, the files <c>authorized_keys</c> and <c>authorized_keys2</c>
+ are searched in a directory found in the following order:
+ <list>
+ <item>If the option
+ <seealso marker="ssh:ssh_file#type-user_dir_fun_common_option"><c>user_dir_fun</c></seealso>
+ is defined, that fun is called and the returned directory is used,
+ </item>
+ <item>Else, If the option
+ <seealso marker="ssh:ssh_file#type-user_dir_common_option"><c>user_dir</c></seealso>
+ is defined, that directory is used,
+ </item>
+ <item>Else the subdirectory <c>.ssh</c> in the home directory of the user executing
+ the OS process of the Erlang emulator is used.
+ </item>
+ </list>
+ If the provided public key is not found, the authentication fails.
+ </item>
+ <item>Finally, if the provided public key is found, the signature provided by the client is checked with
+ the public key.
+ </item>
+ </list>
+ </section>
+ <section>
+ <title>The Erlang/OTP SSH server after a succesful authentication</title>
+ <p>After a successful authentication an <i>Erlang process</i> is handling the service request from the remote
+ ssh client. The rights of that process are those of the user of the OS process running the Erlang emulator.
+ </p>
+ <p>If a shell service request arrives to the server, an <i>Erlang shell</i> is opened in the server's emulator.
+ The rights in that shell is independent of the just authenticated user.
+ </p>
+ <p>In case of an sftp request, an sftp server is started with the rights of the user of the Erlang emulator's OS
+ process. So with sftp the authenticated user does not influence the rights.
+ </p>
+ <p>So after an authentication, the user name is not used anymore and has no influence.
+ </p>
+ </section>
+ </section>
+ </section>
+</chapter>
+
diff --git a/lib/ssh/doc/src/usersguide.xml b/lib/ssh/doc/src/usersguide.xml
index d902df6848..8a4df208d8 100644
--- a/lib/ssh/doc/src/usersguide.xml
+++ b/lib/ssh/doc/src/usersguide.xml
@@ -4,7 +4,7 @@
<part xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>2012</year><year>2016</year>
+ <year>2012</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -36,5 +36,6 @@
</description>
<xi:include href="introduction.xml"/>
<xi:include href="using_ssh.xml"/>
+ <xi:include href="terminology.xml"/>
<xi:include href="configure_algos.xml"/>
</part>
diff --git a/lib/ssh/doc/src/using_ssh.xml b/lib/ssh/doc/src/using_ssh.xml
index ab307624e6..4455d5ecc5 100644
--- a/lib/ssh/doc/src/using_ssh.xml
+++ b/lib/ssh/doc/src/using_ssh.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2012</year>
- <year>2017</year>
+ <year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -74,16 +74,17 @@
<marker id="Running an Erlang ssh Daemon"></marker>
<title>Running an Erlang ssh Daemon</title>
- <p>The <c>system_dir</c> option must be a directory containing a host
- key file and it defaults to <c>/etc/ssh</c>. For details, see Section
- Configuration Files in <seealso
- marker="SSH_app">ssh(6)</seealso>.
+ <p>The
+ <seealso marker="ssh_file#type-system_dir_daemon_option"><c>system_dir</c></seealso>
+ option must be a directory containing a host key file and it defaults to <c>/etc/ssh</c>.
+ For details, see Section Configuration Files in <seealso marker="SSH_app">ssh(6)</seealso>.
</p>
<note><p>Normally, the <c>/etc/ssh</c> directory is only readable by root.</p>
</note>
- <p>The option <c>user_dir</c> defaults to directory <c>users ~/.ssh</c>.</p>
+ <p>The option <seealso marker="ssh_file#type-user_dir_common_option"><c>user_dir</c></seealso>
+ defaults to directory <c>users ~/.ssh</c>.</p>
<p><em>Step 1.</em> To run the example without root privileges,
generate new keys and host keys:</p>
@@ -298,6 +299,7 @@ ok = erl_tar:close(HandleRead),
</section>
<section>
+ <marker id="usersguide_creating_a_subsystem"/>
<title>Creating a Subsystem</title>
<p>A small <c>ssh</c> subsystem that echoes N bytes can be implemented as shown
@@ -305,7 +307,7 @@ ok = erl_tar:close(HandleRead),
<code type="erl" >
-module(ssh_echo_server).
--behaviour(ssh_daemon_channel).
+-behaviour(ssh_server_channel). % replaces ssh_daemon_channel
-record(state, {
n,
id,
@@ -383,7 +385,7 @@ terminate(_Reason, _State) ->
{ssh_msg, &lt;0.57.0>, {closed, 0}}
7> {error, closed} = ssh_connection:send(ConnectionRef, ChannelId, "10", infinity).
</code>
-<p>See also <seealso marker="ssh_channel"> ssh_channel(3)</seealso>.</p>
+<p>See also <seealso marker="ssh_client_channel">ssh_client_channel(3)</seealso> (replaces ssh_channel(3)).</p>
</section>
diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile
index 9e8d80c71f..6d64a45112 100644
--- a/lib/ssh/src/Makefile
+++ b/lib/ssh/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2017. All Rights Reserved.
+# Copyright Ericsson AB 2004-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -40,42 +40,44 @@ RELSYSDIR = $(RELEASE_PATH)/lib/ssh-$(VSN)
# Behaviour (api) modules are first so they are compiled when
# the compiler reaches a callback module using them.
BEHAVIOUR_MODULES= \
- ssh_sftpd_file_api \
- ssh_channel \
- ssh_daemon_channel \
ssh_client_key_api \
- ssh_server_key_api
+ ssh_daemon_channel \
+ ssh_server_channel \
+ ssh_server_key_api \
+ ssh_sftpd_file_api \
+ ssh_channel \
+ ssh_client_channel
MODULES= \
ssh \
- ssh_sup \
- sshc_sup \
- sshd_sup \
- ssh_options \
- ssh_connection_sup \
- ssh_connection \
- ssh_connection_handler \
- ssh_dbg \
- ssh_shell \
- ssh_system_sup \
- ssh_subsystem_sup \
- ssh_channel_sup \
- ssh_acceptor_sup \
ssh_acceptor \
+ ssh_acceptor_sup \
ssh_app \
ssh_auth\
ssh_bits \
ssh_cli \
+ ssh_connection \
+ ssh_connection_handler \
+ ssh_connection_sup \
+ ssh_dbg \
ssh_file \
- ssh_io \
ssh_info \
+ ssh_io \
ssh_message \
ssh_no_io \
+ ssh_options \
+ ssh_server_channel_sup \
ssh_sftp \
ssh_sftpd \
ssh_sftpd_file\
+ ssh_shell \
+ ssh_subsystem_sup \
+ ssh_sup \
+ ssh_system_sup \
ssh_transport \
- ssh_xfer
+ ssh_xfer \
+ sshc_sup \
+ sshd_sup
HRL_FILES =
@@ -97,7 +99,7 @@ APP_TARGET= $(EBIN)/$(APP_FILE)
APPUP_SRC= $(APPUP_FILE).src
APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
-INTERNAL_HRL_FILES = ssh_auth.hrl ssh_connect.hrl ssh_transport.hrl ssh.hrl ssh_userauth.hrl ssh_xfer.hrl ssh_dbg.hrl
+INTERNAL_HRL_FILES = ssh_auth.hrl ssh_connect.hrl ssh_transport.hrl ssh.hrl ssh_userauth.hrl ssh_xfer.hrl
# ----------------------------------------------------
# FLAGS
@@ -169,7 +171,7 @@ $(EBIN)/ssh_connection_handler.$(EMULATOR): ssh_connection_handler.erl ssh.hrl \
$(EBIN)/ssh_shell.$(EMULATOR): ssh_shell.erl ssh_connect.hrl
$(EBIN)/ssh_system_sup.$(EMULATOR): ssh_system_sup.erl ssh.hrl
$(EBIN)/ssh_subsystem_sup.$(EMULATOR): ssh_subsystem_sup.erl
-$(EBIN)/ssh_channel_sup.$(EMULATOR): ssh_channel_sup.erl
+$(EBIN)/ssh_server_channel_sup.$(EMULATOR): ssh_server_channel_sup.erl
$(EBIN)/ssh_acceptor_sup.$(EMULATOR): ssh_acceptor_sup.erl ssh.hrl
$(EBIN)/ssh_acceptor.$(EMULATOR): ssh_acceptor.erl ssh.hrl
$(EBIN)/ssh_app.$(EMULATOR): ssh_app.erl
@@ -208,8 +210,10 @@ $(EBIN)/ssh_transport.$(EMULATOR): ssh_transport.erl \
ssh_transport.hrl ssh.hrl
$(EBIN)/ssh_xfer.$(EMULATOR): ssh_xfer.erl ssh.hrl ssh_xfer.hrl
$(EBIN)/ssh_sftpd_file_api.$(EMULATOR): ssh_sftpd_file_api.erl
+$(EBIN)/ssh_client_channel.$(EMULATOR): ssh_client_channel.erl ssh_connect.hrl
$(EBIN)/ssh_channel.$(EMULATOR): ssh_channel.erl ssh_connect.hrl
$(EBIN)/ssh_daemon_channel.$(EMULATOR): ssh_daemon_channel.erl
+$(EBIN)/ssh_server_channel.$(EMULATOR): ssh_server_channel.erl
$(EBIN)/ssh_client_key_api.$(EMULATOR): ssh_client_key_api.erl \
../../public_key/include/public_key.hrl \
../../public_key/include/OTP-PUB-KEY.hrl \
diff --git a/lib/ssh/src/ssh.app.src b/lib/ssh/src/ssh.app.src
index 4a22322333..2193c14611 100644
--- a/lib/ssh/src/ssh.app.src
+++ b/lib/ssh/src/ssh.app.src
@@ -12,9 +12,9 @@
ssh_message,
ssh_bits,
ssh_cli,
+ ssh_client_channel,
ssh_client_key_api,
ssh_channel,
- ssh_channel_sup,
ssh_connection,
ssh_connection_handler,
ssh_connection_sup,
@@ -27,6 +27,8 @@
ssh_io,
ssh_info,
ssh_no_io,
+ ssh_server_channel,
+ ssh_server_channel_sup,
ssh_server_key_api,
ssh_sftp,
ssh_sftpd,
@@ -42,10 +44,10 @@
{env, []},
{mod, {ssh_app, []}},
{runtime_dependencies, [
- "crypto-4.2",
- "erts-6.0",
- "kernel-3.0",
- "public_key-1.5.2",
- "stdlib-3.3"
+ "crypto-4.5",
+ "erts-9.0",
+ "kernel-5.3",
+ "public_key-1.6.1",
+ "stdlib-3.4.1"
]}]}.
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 25d537c624..ff5aee14d7 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -1,7 +1,7 @@
%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -41,35 +41,51 @@
shell/1, shell/2, shell/3
]).
+%%% "Deprecated" types export:
+-export_type([ssh_daemon_ref/0, ssh_connection_ref/0, ssh_channel_id/0]).
+-opaque ssh_daemon_ref() :: daemon_ref().
+-opaque ssh_connection_ref() :: connection_ref().
+-opaque ssh_channel_id() :: channel_id().
+
+
%%% Type exports
--export_type([ssh_daemon_ref/0,
- ssh_connection_ref/0,
- ssh_channel_id/0,
+-export_type([daemon_ref/0,
+ connection_ref/0,
+ channel_id/0,
+ client_options/0, client_option/0,
+ daemon_options/0, daemon_option/0,
+ common_options/0,
role/0,
subsystem_spec/0,
- subsystem_name/0,
- channel_callback/0,
- channel_init_args/0,
algs_list/0,
+ double_algs/1,
+ modify_algs_list/0,
alg_entry/0,
- simple_algs/0,
- double_algs/0
+ kex_alg/0,
+ pubkey_alg/0,
+ cipher_alg/0,
+ mac_alg/0,
+ compression_alg/0,
+ ip_port/0
]).
--opaque ssh_daemon_ref() :: daemon_ref() .
--opaque ssh_connection_ref() :: connection_ref() .
--opaque ssh_channel_id() :: channel_id().
+
+-opaque daemon_ref() :: pid() .
+-opaque channel_id() :: non_neg_integer().
+-type connection_ref() :: pid(). % should be -opaque, but that gives problems
%%--------------------------------------------------------------------
--spec start() -> ok | {error, term()}.
--spec start(permanent | transient | temporary) -> ok | {error, term()}.
-%%
%% Description: Starts the ssh application. Default type
%% is temporary. see application(3)
%%--------------------------------------------------------------------
+-spec start() -> ok | {error, term()}.
+
start() ->
start(temporary).
+-spec start(Type) -> ok | {error, term()} when
+ Type :: permanent | transient | temporary .
+
start(Type) ->
case application:ensure_all_started(ssh, Type) of
{ok, _} ->
@@ -79,48 +95,57 @@ start(Type) ->
end.
%%--------------------------------------------------------------------
--spec stop() -> ok | {error, term()}.
-%%
%% Description: Stops the ssh application.
%%--------------------------------------------------------------------
+-spec stop() -> ok | {error, term()}.
+
stop() ->
application:stop(ssh).
%%--------------------------------------------------------------------
--spec connect(inet:socket(), proplists:proplist()) -> ok_error(connection_ref()).
+%% Description: Starts an ssh connection.
+%%--------------------------------------------------------------------
+-spec connect(OpenTcpSocket, Options) -> {ok,connection_ref()} | {error,term()} when
+ OpenTcpSocket :: open_socket(),
+ Options :: client_options().
--spec connect(inet:socket(), proplists:proplist(), timeout()) -> ok_error(connection_ref())
- ; (string(), inet:port_number(), proplists:proplist()) -> ok_error(connection_ref()).
+connect(OpenTcpSocket, Options) when is_port(OpenTcpSocket),
+ is_list(Options) ->
+ connect(OpenTcpSocket, Options, infinity).
--spec connect(string(), inet:port_number(), proplists:proplist(), timeout()) -> ok_error(connection_ref()).
-%%
-%% Description: Starts an ssh connection.
-%%--------------------------------------------------------------------
-connect(Socket, UserOptions) when is_port(Socket),
- is_list(UserOptions) ->
- connect(Socket, UserOptions, infinity).
+-spec connect(open_socket(), client_options(), timeout()) ->
+ {ok,connection_ref()} | {error,term()}
+ ; (host(), inet:port_number(), client_options()) ->
+ {ok,connection_ref()} | {error,term()}.
-connect(Socket, UserOptions, Timeout) when is_port(Socket),
- is_list(UserOptions) ->
+connect(Socket, UserOptions, NegotiationTimeout) when is_port(Socket),
+ is_list(UserOptions) ->
case ssh_options:handle_options(client, UserOptions) of
{error, Error} ->
{error, Error};
Options ->
case valid_socket_to_use(Socket, ?GET_OPT(transport,Options)) of
ok ->
- {ok, {Host,_Port}} = inet:sockname(Socket),
+ {ok, {Host,_Port}} = inet:peername(Socket),
Opts = ?PUT_INTERNAL_OPT([{user_pid,self()}, {host,Host}], Options),
- ssh_connection_handler:start_connection(client, Socket, Opts, Timeout);
+ ssh_connection_handler:start_connection(client, Socket, Opts, NegotiationTimeout);
{error,SockError} ->
{error,SockError}
end
end;
-connect(Host, Port, UserOptions) when is_integer(Port),
- Port>0,
- is_list(UserOptions) ->
- connect(Host, Port, UserOptions, infinity).
+connect(Host, Port, Options) when is_integer(Port),
+ Port>0,
+ is_list(Options) ->
+ connect(Host, Port, Options, infinity).
+
+
+-spec connect(Host, Port, Options, NegotiationTimeout) -> {ok,connection_ref()} | {error,term()} when
+ Host :: host(),
+ Port :: inet:port_number(),
+ Options :: client_options(),
+ NegotiationTimeout :: timeout().
connect(Host0, Port, UserOptions, Timeout) when is_integer(Port),
Port>0,
@@ -148,7 +173,8 @@ connect(Host0, Port, UserOptions, Timeout) when is_integer(Port),
end.
%%--------------------------------------------------------------------
--spec close(pid()) -> ok.
+-spec close(ConnectionRef) -> ok | {error,term()} when
+ ConnectionRef :: connection_ref() .
%%
%% Description: Closes an ssh connection.
%%--------------------------------------------------------------------
@@ -156,15 +182,25 @@ close(ConnectionRef) ->
ssh_connection_handler:stop(ConnectionRef).
%%--------------------------------------------------------------------
--spec connection_info(pid(), [atom()]) -> [{atom(), term()}].
-%%
%% Description: Retrieves information about a connection.
%%--------------------------------------------------------------------
-connection_info(ConnectionRef, Options) ->
- ssh_connection_handler:connection_info(ConnectionRef, Options).
+-spec connection_info(ConnectionRef, Keys) -> ConnectionInfo when
+ ConnectionRef :: connection_ref(),
+ Keys :: [client_version | server_version | user | peer | sockname],
+ ConnectionInfo :: [{client_version, Version}
+ | {server_version, Version}
+ | {user,string()}
+ | {peer, {inet:hostname(), ip_port()}}
+ | {sockname, ip_port()}
+ ],
+ Version :: {ProtocolVersion, VersionString::string()},
+ ProtocolVersion :: {Major::pos_integer(), Minor::non_neg_integer()} .
+
+connection_info(Connection, Options) ->
+ ssh_connection_handler:connection_info(Connection, Options).
%%--------------------------------------------------------------------
--spec channel_info(pid(), channel_id(), [atom()]) -> [{atom(), term()}].
+-spec channel_info(connection_ref(), channel_id(), [atom()]) -> proplists:proplist().
%%
%% Description: Retrieves information about a connection.
%%--------------------------------------------------------------------
@@ -172,18 +208,17 @@ channel_info(ConnectionRef, ChannelId, Options) ->
ssh_connection_handler:channel_info(ConnectionRef, ChannelId, Options).
%%--------------------------------------------------------------------
--spec daemon(inet:port_number()) -> ok_error(daemon_ref()).
--spec daemon(inet:port_number()|inet:socket(), proplists:proplist()) -> ok_error(daemon_ref()).
--spec daemon(any | inet:ip_address(), inet:port_number(), proplists:proplist()) -> ok_error(daemon_ref())
- ;(socket, inet:socket(), proplists:proplist()) -> ok_error(daemon_ref())
- .
-
%% Description: Starts a server listening for SSH connections
%% on the given port.
%%--------------------------------------------------------------------
+-spec daemon(inet:port_number()) -> {ok,daemon_ref()} | {error,term()}.
+
daemon(Port) ->
daemon(Port, []).
+
+-spec daemon(inet:port_number()|open_socket(), daemon_options()) -> {ok,daemon_ref()} | {error,term()}.
+
daemon(Socket, UserOptions) when is_port(Socket) ->
try
#{} = Options = ssh_options:handle_options(server, UserOptions),
@@ -226,30 +261,47 @@ daemon(Port, UserOptions) when 0 =< Port, Port =< 65535 ->
daemon(any, Port, UserOptions).
+-spec daemon(any | inet:ip_address(), inet:port_number(), daemon_options()) -> {ok,daemon_ref()} | {error,term()}
+ ;(socket, open_socket(), daemon_options()) -> {ok,daemon_ref()} | {error,term()}
+ .
+
daemon(Host0, Port0, UserOptions0) when 0 =< Port0, Port0 =< 65535,
Host0 == any ; Host0 == loopback ; is_tuple(Host0) ->
try
{Host1, UserOptions} = handle_daemon_args(Host0, UserOptions0),
#{} = Options0 = ssh_options:handle_options(server, UserOptions),
-
- {{Host,Port}, ListenSocket} =
- open_listen_socket(Host1, Port0, Options0),
-
- %% Now Host,Port is what to use for the supervisor to register its name,
- %% and ListenSocket is for listening on connections. But it is still owned
- %% by self()...
-
- finalize_start(Host, Port, ?GET_OPT(profile, Options0),
- ?PUT_INTERNAL_OPT({lsocket,{ListenSocket,self()}}, Options0),
- fun(Opts, Result) ->
- {_, Callback, _} = ?GET_OPT(transport, Opts),
- receive
- {request_control, ListenSocket, ReqPid} ->
- ok = Callback:controlling_process(ListenSocket, ReqPid),
- ReqPid ! {its_yours,ListenSocket},
- Result
- end
- end)
+ {open_listen_socket(Host1, Port0, Options0), Options0}
+ of
+ {{{Host,Port}, ListenSocket}, Options1} ->
+ try
+ %% Now Host,Port is what to use for the supervisor to register its name,
+ %% and ListenSocket is for listening on connections. But it is still owned
+ %% by self()...
+ finalize_start(Host, Port, ?GET_OPT(profile, Options1),
+ ?PUT_INTERNAL_OPT({lsocket,{ListenSocket,self()}}, Options1),
+ fun(Opts, Result) ->
+ {_, Callback, _} = ?GET_OPT(transport, Opts),
+ receive
+ {request_control, ListenSocket, ReqPid} ->
+ ok = Callback:controlling_process(ListenSocket, ReqPid),
+ ReqPid ! {its_yours,ListenSocket},
+ Result
+ end
+ end)
+ of
+ {error,Err} ->
+ close_listen_socket(ListenSocket, Options1),
+ {error,Err};
+ OK ->
+ OK
+ catch
+ error:Error ->
+ close_listen_socket(ListenSocket, Options1),
+ error(Error);
+ exit:Exit ->
+ close_listen_socket(ListenSocket, Options1),
+ exit(Exit)
+ end
catch
throw:bad_fd ->
{error,bad_fd};
@@ -267,7 +319,12 @@ daemon(_, _, _) ->
{error, badarg}.
%%--------------------------------------------------------------------
--spec daemon_info(daemon_ref()) -> ok_error( [{atom(), term()}] ).
+-spec daemon_info(Daemon) -> {ok, DaemonInfo} | {error,term()} when
+ Daemon :: daemon_ref(),
+ DaemonInfo :: [ {ip, inet:ip_address()}
+ | {port, inet:port_number()}
+ | {profile, term()}
+ ].
daemon_info(Pid) ->
case catch ssh_system_sup:acceptor_supervisor(Pid) of
@@ -290,16 +347,23 @@ daemon_info(Pid) ->
end.
%%--------------------------------------------------------------------
--spec stop_listener(daemon_ref()) -> ok.
--spec stop_listener(inet:ip_address(), inet:port_number()) -> ok.
-%%
%% Description: Stops the listener, but leaves
%% existing connections started by the listener up and running.
%%--------------------------------------------------------------------
+-spec stop_listener(daemon_ref()) -> ok.
+
stop_listener(SysSup) ->
ssh_system_sup:stop_listener(SysSup).
+
+
+-spec stop_listener(inet:ip_address(), inet:port_number()) -> ok.
+
stop_listener(Address, Port) ->
stop_listener(Address, Port, ?DEFAULT_PROFILE).
+
+
+-spec stop_listener(any|inet:ip_address(), inet:port_number(), term()) -> ok.
+
stop_listener(any, Port, Profile) ->
map_ip(fun(IP) ->
ssh_system_sup:stop_listener(IP, Port, Profile)
@@ -310,17 +374,23 @@ stop_listener(Address, Port, Profile) ->
end, {address,Address}).
%%--------------------------------------------------------------------
--spec stop_daemon(daemon_ref()) -> ok.
--spec stop_daemon(inet:ip_address(), inet:port_number()) -> ok.
--spec stop_daemon(inet:ip_address(), inet:port_number(), atom()) -> ok.
-%%
%% Description: Stops the listener and all connections started by
%% the listener.
%%--------------------------------------------------------------------
+-spec stop_daemon(DaemonRef::daemon_ref()) -> ok.
+
stop_daemon(SysSup) ->
ssh_system_sup:stop_system(SysSup).
+
+
+-spec stop_daemon(inet:ip_address(), inet:port_number()) -> ok.
+
stop_daemon(Address, Port) ->
stop_daemon(Address, Port, ?DEFAULT_PROFILE).
+
+
+-spec stop_daemon(any|inet:ip_address(), inet:port_number(), atom()) -> ok.
+
stop_daemon(any, Port, Profile) ->
map_ip(fun(IP) ->
ssh_system_sup:stop_system(IP, Port, Profile)
@@ -331,33 +401,37 @@ stop_daemon(Address, Port, Profile) ->
end, {address,Address}).
%%--------------------------------------------------------------------
--spec shell(inet:socket() | string()) -> _.
--spec shell(inet:socket() | string(), proplists:proplist()) -> _.
--spec shell(string(), inet:port_number(), proplists:proplist()) -> _.
-
-%% Host = string()
-%% Port = integer()
-%% Options = [{Option, Value}]
-%%
%% Description: Starts an interactive shell to an SSH server on the
%% given <Host>. The function waits for user input,
%% and will not return until the remote shell is ended.(e.g. on
%% exit from the shell)
%%--------------------------------------------------------------------
+-spec shell(open_socket() | host()) -> _.
+
shell(Socket) when is_port(Socket) ->
shell(Socket, []);
shell(Host) ->
shell(Host, ?SSH_DEFAULT_PORT, []).
+
+-spec shell(open_socket() | host(), client_options()) -> _.
+
shell(Socket, Options) when is_port(Socket) ->
start_shell( connect(Socket, Options) );
shell(Host, Options) ->
shell(Host, ?SSH_DEFAULT_PORT, Options).
+
+-spec shell(Host, Port, Options) -> _ when
+ Host :: host(),
+ Port :: inet:port_number(),
+ Options :: client_options() .
+
shell(Host, Port, Options) ->
start_shell( connect(Host, Port, Options) ).
+
start_shell({ok, ConnectionRef}) ->
case ssh_connection:session_channel(ConnectionRef, infinity) of
{ok,ChannelId} ->
@@ -365,11 +439,17 @@ start_shell({ok, ConnectionRef}) ->
Args = [{channel_cb, ssh_shell},
{init_args,[ConnectionRef, ChannelId]},
{cm, ConnectionRef}, {channel_id, ChannelId}],
- {ok, State} = ssh_channel:init([Args]),
- ssh_channel:enter_loop(State);
+ {ok, State} = ssh_client_channel:init([Args]),
+ try
+ ssh_client_channel:enter_loop(State)
+ catch
+ exit:normal ->
+ ok
+ end;
Error ->
Error
end;
+
start_shell(Error) ->
Error.
@@ -380,7 +460,7 @@ default_algorithms() ->
ssh_transport:default_algorithms().
%%--------------------------------------------------------------------
--spec chk_algos_opts(list(any())) -> algs_list() .
+-spec chk_algos_opts(client_options()|daemon_options()) -> internal_options() | {error,term()}.
%%--------------------------------------------------------------------
chk_algos_opts(Opts) ->
case lists:foldl(
@@ -457,6 +537,15 @@ open_listen_socket(_Host0, Port0, Options0) ->
{{LHost,LPort}, LSock}.
%%%----------------------------------------------------------------
+close_listen_socket(ListenSocket, Options) ->
+ try
+ {_, Callback, _} = ?GET_OPT(transport, Options),
+ Callback:close(ListenSocket)
+ catch
+ _C:_E -> ok
+ end.
+
+%%%----------------------------------------------------------------
finalize_start(Host, Port, Profile, Options0, F) ->
try
%% throws error:Error if no usable hostkey is found
diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl
index 4711f54fb5..04453e6ef0 100644
--- a/lib/ssh/src/ssh.hrl
+++ b/lib/ssh/src/ssh.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,7 +29,6 @@
-define(SSH_DEFAULT_PORT, 22).
-define(SSH_MAX_PACKET_SIZE, (256*1024)).
--define(REKEY_TIMOUT, 3600000).
-define(REKEY_DATA_TIMOUT, 60000).
-define(DEFAULT_PROFILE, default).
@@ -98,35 +97,271 @@
%% Types
--type role() :: client | server .
--type ok_error(SuccessType) :: {ok, SuccessType} | {error, any()} .
--type daemon_ref() :: pid() .
+-type role() :: client | server .
+
+-type host() :: string() | inet:ip_address() | loopback .
+-type open_socket() :: gen_tcp:socket().
+
+-type subsystem_spec() :: {Name::string(), mod_args()} .
+
+-type algs_list() :: list( alg_entry() ).
+-type alg_entry() :: {kex, [kex_alg()]}
+ | {public_key, [pubkey_alg()]}
+ | {cipher, double_algs(cipher_alg())}
+ | {mac, double_algs(mac_alg())}
+ | {compression, double_algs(compression_alg())} .
+
+-type kex_alg() :: 'diffie-hellman-group-exchange-sha1' |
+ 'diffie-hellman-group-exchange-sha256' |
+ 'diffie-hellman-group1-sha1' |
+ 'diffie-hellman-group14-sha1' |
+ 'diffie-hellman-group14-sha256' |
+ 'diffie-hellman-group16-sha512' |
+ 'diffie-hellman-group18-sha512' |
+ 'curve25519-sha256' |
+ 'curve448-sha512' |
+ 'ecdh-sha2-nistp256' |
+ 'ecdh-sha2-nistp384' |
+ 'ecdh-sha2-nistp521'
+ .
+
+-type pubkey_alg() :: 'ecdsa-sha2-nistp256' |
+ 'ecdsa-sha2-nistp384' |
+ 'ecdsa-sha2-nistp521' |
+ 'ssh-ed25519' |
+ 'ssh-ed448' |
+ 'rsa-sha2-256' |
+ 'rsa-sha2-512' |
+ 'ssh-dss' |
+ 'ssh-rsa'
+ .
+
+-type cipher_alg() :: '3des-cbc' |
+ 'AEAD_AES_128_GCM' |
+ 'AEAD_AES_256_GCM' |
+ 'aes128-cbc' |
+ 'aes128-ctr' |
+ 'aes192-ctr' |
+ 'aes256-ctr' |
+ .
+
+-type mac_alg() :: 'AEAD_AES_128_GCM' |
+ 'AEAD_AES_256_GCM' |
+ 'hmac-sha1' |
+ 'hmac-sha2-256' |
+ 'hmac-sha2-512'
+ .
+
+-type compression_alg() :: 'none' |
+ 'zlib' |
+ .
+
+-type double_algs(AlgType) :: list( {client2server,[AlgType]} | {server2client,[AlgType]} )
+ | [AlgType].
+
+-type modify_algs_list() :: list( {append,algs_list()} | {prepend,algs_list()} | {rm,algs_list()} ) .
+
+-type internal_options() :: ssh_options:private_options().
+-type socket_options() :: [gen_tcp:connect_option() | gen_tcp:listen_option()].
+
+-type client_options() :: [ client_option() ] .
+-type daemon_options() :: [ daemon_option() ].
+
+
+-type common_options() :: [ common_option() ].
+-type common_option() ::
+ ssh_file:user_dir_common_option()
+ | profile_common_option()
+ | max_idle_time_common_option()
+ | key_cb_common_option()
+ | disconnectfun_common_option()
+ | unexpectedfun_common_option()
+ | ssh_msg_debug_fun_common_option()
+ | rekey_limit_common_option()
+ | id_string_common_option()
+ | pref_public_key_algs_common_option()
+ | preferred_algorithms_common_option()
+ | modify_algorithms_common_option()
+ | auth_methods_common_option()
+ | inet_common_option()
+ | fd_common_option()
+ .
+
+-define(COMMON_OPTION, common_option()).
+
+-type profile_common_option() :: {profile, atom() }.
+-type max_idle_time_common_option() :: {idle_time, timeout()}.
+-type rekey_limit_common_option() :: {rekey_limit, Bytes::limit_bytes() |
+ {Minutes::limit_time(), Bytes::limit_bytes()}
+ }.
+
+-type limit_bytes() :: non_neg_integer() | infinity . % non_neg_integer due to compatibility
+-type limit_time() :: pos_integer() | infinity .
+
+-type key_cb_common_option() :: {key_cb, Module::atom() | {Module::atom(),Opts::[term()]} } .
+-type disconnectfun_common_option() ::
+ {disconnectfun, fun((Reason::term()) -> void | any()) }.
+-type unexpectedfun_common_option() ::
+ {unexpectedfun, fun((Message::term(),{Host::term(),Port::term()}) -> report | skip ) }.
+-type ssh_msg_debug_fun_common_option() ::
+ {ssh_msg_debug_fun, fun((ssh:connection_ref(),AlwaysDisplay::boolean(),Msg::binary(),LanguageTag::binary()) -> any()) } .
+
+-type id_string_common_option() :: {id_string, string() | random | {random,Nmin::pos_integer(),Nmax::pos_integer()} }.
+-type pref_public_key_algs_common_option() :: {pref_public_key_algs, [pubkey_alg()] } .
+-type preferred_algorithms_common_option():: {preferred_algorithms, algs_list()}.
+-type modify_algorithms_common_option() :: {modify_algorithms, modify_algs_list()}.
+-type auth_methods_common_option() :: {auth_methods, string() }.
+
+-type inet_common_option() :: {inet, inet | inet6} .
+-type fd_common_option() :: {fd, gen_tcp:socket()} .
+
+
+-type opaque_common_options() ::
+ {transport, {atom(),atom(),atom()} }
+ | {vsn, {non_neg_integer(),non_neg_integer()} }
+ | {tstflg, list(term())}
+ | ssh_file:user_dir_fun_common_option()
+ | {max_random_length_padding, non_neg_integer()} .
+
+
+
+-type client_option() ::
+ ssh_file:pubkey_passphrase_client_options()
+ | host_accepting_client_options()
+ | authentication_client_options()
+ | diffie_hellman_group_exchange_client_option()
+ | connect_timeout_client_option()
+ | recv_ext_info_client_option()
+ | opaque_client_options()
+ | gen_tcp:connect_option()
+ | ?COMMON_OPTION .
+
+-type opaque_client_options() ::
+ {keyboard_interact_fun, fun((Name::iodata(),
+ Instruction::iodata(),
+ Prompts::[{Prompt::iodata(),Echo::boolean()}]
+ ) ->
+ [Response::iodata()]
+ )}
+ | opaque_common_options().
+
+-type host_accepting_client_options() ::
+ {silently_accept_hosts, accept_hosts()}
+ | {user_interaction, boolean()}
+ | {save_accepted_host, boolean()}
+ | {quiet_mode, boolean()} .
+
+-type accept_hosts() :: boolean()
+ | accept_callback()
+ | {HashAlgoSpec::fp_digest_alg(), accept_callback()}.
+
+-type fp_digest_alg() :: 'md5' | crypto:sha1() | crypto:sha2() .
+
+-type accept_callback() :: fun((PeerName::string(), fingerprint() ) -> boolean()) .
+-type fingerprint() :: string() | [string()].
+
+-type authentication_client_options() ::
+ {user, string()}
+ | {password, string()} .
+
+-type diffie_hellman_group_exchange_client_option() ::
+ {dh_gex_limits, {Min::pos_integer(), I::pos_integer(), Max::pos_integer()} } .
+
+-type connect_timeout_client_option() :: {connect_timeout, timeout()} .
+
+-type recv_ext_info_client_option() :: {recv_ext_info, boolean()} .
+
+
+
+-type daemon_option() ::
+ subsystem_daemon_option()
+ | shell_daemon_option()
+ | exec_daemon_option()
+ | ssh_cli_daemon_option()
+ | authentication_daemon_options()
+ | diffie_hellman_group_exchange_daemon_option()
+ | negotiation_timeout_daemon_option()
+ | hardening_daemon_options()
+ | callbacks_daemon_options()
+ | send_ext_info_daemon_option()
+ | opaque_daemon_options()
+ | gen_tcp:listen_option()
+ | ?COMMON_OPTION .
+
+-type subsystem_daemon_option() :: {subsystems, subsystem_spec()}.
+
+-type shell_daemon_option() :: {shell, mod_fun_args() | 'shell_fun/1'() | 'shell_fun/2'() }.
+-type 'shell_fun/1'() :: fun((User::string()) -> pid()) .
+-type 'shell_fun/2'() :: fun((User::string(), PeerAddr::inet:ip_address()) -> pid()).
+
+-type exec_daemon_option() :: {exec, exec_spec()} .
+-type exec_spec() :: {direct, exec_fun()} .
+-type exec_fun() :: 'exec_fun/1'() | 'exec_fun/2'() | 'exec_fun/3'().
+-type 'exec_fun/1'() :: fun((Cmd::string()) -> exec_result()) .
+-type 'exec_fun/2'() :: fun((Cmd::string(), User::string()) -> exec_result()) .
+-type 'exec_fun/3'() :: fun((Cmd::string(), User::string(), ClientAddr::ip_port()) -> exec_result()) .
+-type exec_result() :: {ok,Result::term()} | {error,Reason::term()} .
+
+-type ssh_cli_daemon_option() :: {ssh_cli, mod_args() | no_cli }.
+
+-type send_ext_info_daemon_option() :: {send_ext_info, boolean()} .
--type subsystem_spec() :: {subsystem_name(), {channel_callback(), channel_init_args()}} .
--type subsystem_name() :: string() .
--type channel_callback() :: atom() .
--type channel_init_args() :: list() .
+-type authentication_daemon_options() ::
+ ssh_file:system_dir_daemon_option()
+ | {auth_method_kb_interactive_data, prompt_texts() }
+ | {user_passwords, [{UserName::string(),Pwd::string()}]}
+ | {password, string()}
+ | {pwdfun, pwdfun_2() | pwdfun_4()} .
--type algs_list() :: list( alg_entry() ).
--type alg_entry() :: {kex, simple_algs()}
- | {public_key, simple_algs()}
- | {cipher, double_algs()}
- | {mac, double_algs()}
- | {compression, double_algs()} .
--type simple_algs() :: list( atom() ) .
--type double_algs() :: list( {client2serverlist,simple_algs()} | {server2client,simple_algs()} )
- | simple_algs() .
+-type prompt_texts() ::
+ kb_int_tuple()
+ | kb_int_fun_3()
+ .
+
+-type kb_int_fun_3() :: fun((Peer::ip_port(), User::string(), Service::string()) -> kb_int_tuple()).
+-type kb_int_tuple() :: {Name::string(), Instruction::string(), Prompt::string(), Echo::boolean()}.
--type options() :: #{socket_options := socket_options(),
- internal_options := internal_options(),
- option_key() => any()
- }.
+-type pwdfun_2() :: fun((User::string(), Password::string()) -> boolean()) .
+-type pwdfun_4() :: fun((User::string(),
+ Password::string(),
+ PeerAddress::ip_port(),
+ State::any()) ->
+ boolean() | disconnect | {boolean(),NewState::any()}
+ ) .
+
+-type diffie_hellman_group_exchange_daemon_option() ::
+ {dh_gex_groups, [explicit_group()] | explicit_group_file() | ssh_moduli_file()}
+ | {dh_gex_limits, {Min::pos_integer(), Max::pos_integer()} } .
--type socket_options() :: proplists:proplist().
--type internal_options() :: #{option_key() => any()}.
+-type explicit_group() :: {Size::pos_integer(),G::pos_integer(),P::pos_integer()} .
+-type explicit_group_file() :: {file,string()} .
+-type ssh_moduli_file() :: {ssh_moduli_file,string()}.
--type option_key() :: atom().
+-type negotiation_timeout_daemon_option() :: {negotiation_timeout, timeout()} .
+-type hardening_daemon_options() ::
+ {max_sessions, pos_integer()}
+ | {max_channels, pos_integer()}
+ | {parallel_login, boolean()}
+ | {minimal_remote_max_packet_size, pos_integer()}.
+
+-type callbacks_daemon_options() ::
+ {failfun, fun((User::string(), PeerAddress::inet:ip_address(), Reason::term()) -> _)}
+ | {connectfun, fun((User::string(), PeerAddress::inet:ip_address(), Method::string()) ->_)} .
+
+-type opaque_daemon_options() ::
+ {infofun, fun()}
+ | opaque_common_options().
+
+-type ip_port() :: {inet:ip_address(), inet:port_number()} .
+
+-type mod_args() :: {Module::atom(), Args::list()} .
+-type mod_fun_args() :: {Module::atom(), Function::atom(), Args::list()} .
%% Records
@@ -134,8 +369,9 @@
{
role :: client | role(),
peer :: undefined |
- {inet:hostname(),
- {inet:ip_address(),inet:port_number()}}, %% string version of peer address
+ {inet:hostname(),ip_port()}, %% string version of peer address
+
+ local, %% Local sockname. Need this AFTER a socket is closed by i.e. a crash
c_vsn, %% client version {Major,Minor}
s_vsn, %% server version {Major,Minor}
@@ -151,11 +387,6 @@
algorithms, %% #alg{}
- kex, %% key exchange algorithm
- hkey, %% host key algorithm
- key_cb, %% Private/Public key callback module
- io_cb, %% Interaction callback module
-
send_mac = none, %% send MAC algorithm
send_mac_key, %% key used in send MAC algorithm
send_mac_size = 0,
@@ -165,11 +396,13 @@
recv_mac_size = 0,
encrypt = none, %% encrypt algorithm
+ encrypt_cipher, %% cipher. could be different from the algorithm
encrypt_keys, %% encrypt keys
encrypt_block_size = 8,
encrypt_ctx,
decrypt = none, %% decrypt algorithm
+ decrypt_cipher, %% cipher. could be different from the algorithm
decrypt_keys, %% decrypt keys
decrypt_block_size = 8,
decrypt_ctx, %% Decryption context
@@ -248,4 +481,38 @@
_ -> exit(Reason)
end).
+
+%% dbg help macros
+-define(wr_record(N,BlackList),
+ wr_record(R=#N{}) -> ssh_dbg:wr_record(R, record_info(fields,N), BlackList)
+ ).
+
+-define(wr_record(N), ?wr_record(N, [])).
+
+
+%% Circular trace buffer macros
+
+-record(circ_buf_entry,
+ {
+ module,
+ line,
+ function,
+ pid = self(),
+ value
+ }).
+
+-define(CIRC_BUF_IN(VALUE),
+ ssh_dbg:cbuf_in(
+ #circ_buf_entry{module = ?MODULE,
+ line = ?LINE,
+ function = {?FUNCTION_NAME,?FUNCTION_ARITY},
+ pid = self(),
+ value = (VALUE)
+ })
+ ).
+
+-define(CIRC_BUF_IN_ONCE(VALUE),
+ ((fun(V) -> ?CIRC_BUF_IN(V), V end)(VALUE))
+ ).
+
-endif. % SSH_HRL defined
diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl
index d66a34c58a..11ce80354e 100644
--- a/lib/ssh/src/ssh_acceptor.erl
+++ b/lib/ssh/src/ssh_acceptor.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -33,6 +33,8 @@
%% spawn export
-export([acceptor_init/5, acceptor_loop/6]).
+-export([dbg_trace/3]).
+
-define(SLEEP_TIME, 200).
%%====================================================================
@@ -86,7 +88,8 @@ acceptor_init(Parent, Port, Address, Opts, AcceptTimeout) ->
acceptor_loop(Callback, Port, Address, Opts, LSock, AcceptTimeout);
{error,_} -> % Not open, a restart
- {ok,NewLSock} = listen(Port, Opts),
+ %% Allow gen_tcp:listen to fail 4 times if eaddrinuse:
+ {ok,NewLSock} = try_listen(Port, Opts, 4),
proc_lib:init_ack(Parent, {ok, self()}),
Opts1 = ?DELETE_INTERNAL_OPT(lsocket, Opts),
{_, Callback, _} = ?GET_OPT(transport, Opts1),
@@ -98,6 +101,19 @@ acceptor_init(Parent, Port, Address, Opts, AcceptTimeout) ->
end.
+try_listen(Port, Opts, NtriesLeft) ->
+ try_listen(Port, Opts, 1, NtriesLeft).
+
+try_listen(Port, Opts, N, Nmax) ->
+ case listen(Port, Opts) of
+ {error,eaddrinuse} when N<Nmax ->
+ timer:sleep(10*N), % Sleep 10, 20, 30,... ms
+ try_listen(Port, Opts, N+1, Nmax);
+ Other ->
+ Other
+ end.
+
+
request_ownership(LSock, SockOwner) ->
SockOwner ! {request_control,LSock,self()},
receive
@@ -181,3 +197,33 @@ handle_error(Reason) ->
error_logger:error_report(String),
exit({accept_failed, String}).
+%%%################################################################
+%%%#
+%%%# Tracing
+%%%#
+
+dbg_trace(points, _, _) -> [connections];
+
+dbg_trace(flags, connections, _) -> [c];
+dbg_trace(on, connections, _) -> dbg:tp(?MODULE, acceptor_init, 5, x),
+ dbg:tpl(?MODULE, handle_connection, 5, x);
+dbg_trace(off, connections, _) -> dbg:ctp(?MODULE, acceptor_init, 5),
+ dbg:ctp(?MODULE, handle_connection, 5);
+dbg_trace(format, connections, {call, {?MODULE,acceptor_init,
+ [_Parent, Port, Address, _Opts, _AcceptTimeout]}}) ->
+ [io_lib:format("Starting LISTENER on ~s:~p\n", [ntoa(Address),Port])
+ ];
+dbg_trace(format, connections, {return_from, {?MODULE,handle_connection,5}, {error,Error}}) ->
+ ["Starting connection to server failed:\n",
+ io_lib:format("Error = ~p", [Error])
+ ].
+
+
+
+ntoa(A) ->
+ try inet:ntoa(A)
+ catch
+ _:_ when is_list(A) -> A;
+ _:_ -> io_lib:format('~p',[A])
+ end.
+
diff --git a/lib/ssh/src/ssh_acceptor_sup.erl b/lib/ssh/src/ssh_acceptor_sup.erl
index fc564a359b..15a2238dd3 100644
--- a/lib/ssh/src/ssh_acceptor_sup.erl
+++ b/lib/ssh/src/ssh_acceptor_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -36,8 +36,6 @@
-define(DEFAULT_TIMEOUT, 50000).
--spec init( [term()] ) -> {ok,{supervisor:sup_flags(),[supervisor:child_spec()]}} | ignore .
-
%%%=========================================================================
%%% API
%%%=========================================================================
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index 03d264745b..9632168e65 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -40,15 +40,12 @@
%%--------------------------------------------------------------------
%%%----------------------------------------------------------------
userauth_request_msg(#ssh{userauth_methods = ServerMethods,
- userauth_supported_methods = UserPrefMethods, % Note: this is not documented as supported for clients
+ userauth_supported_methods = UserPrefMethods,
userauth_preference = ClientMethods0
} = Ssh0) ->
case sort_select_mthds(ClientMethods0, UserPrefMethods, ServerMethods) of
[] ->
- Msg = #ssh_msg_disconnect{code = ?SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE,
- description = "Unable to connect using the available authentication methods",
- language = "en"},
- {disconnect, Msg, ssh_transport:ssh_packet(Msg, Ssh0)};
+ {send_disconnect, ?SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE, Ssh0};
[{Pref,Module,Function,Args} | Prefs] ->
Ssh = case Pref of
@@ -94,8 +91,10 @@ unique(L) ->
%%%---- userauth_request_msg "callbacks"
-password_msg([#ssh{opts = Opts, io_cb = IoCb,
- user = User, service = Service} = Ssh0]) ->
+password_msg([#ssh{opts = Opts,
+ user = User,
+ service = Service} = Ssh0]) ->
+ IoCb = ?GET_INTERNAL_OPT(io_cb, Opts),
{Password,Ssh} =
case ?GET_OPT(password, Opts) of
undefined when IoCb == ssh_no_io ->
@@ -140,9 +139,7 @@ keyboard_interactive_msg([#ssh{user = User,
get_public_key(SigAlg, #ssh{opts = Opts}) ->
KeyAlg = key_alg(SigAlg),
- {KeyCb,KeyCbOpts} = ?GET_OPT(key_cb, Opts),
- UserOpts = ?GET_OPT(user_options, Opts),
- case KeyCb:user_key(KeyAlg, [{key_cb_private,KeyCbOpts}|UserOpts]) of
+ case ssh_transport:call_KeyCb(user_key, [KeyAlg], Opts) of
{ok, PrivKey} ->
try
%% Check the key - the KeyCb may be a buggy plugin
@@ -196,11 +193,8 @@ init_userauth_request_msg(#ssh{opts = Opts} = Ssh) ->
%% Client side
case ?GET_OPT(user, Opts) of
undefined ->
- ErrStr = "Could not determine the users name",
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{code = ?SSH_DISCONNECT_ILLEGAL_USER_NAME,
- description = ErrStr});
-
+ ?DISCONNECT(?SSH_DISCONNECT_ILLEGAL_USER_NAME,
+ "Could not determine the users name");
User ->
ssh_transport:ssh_packet(
#ssh_msg_userauth_request{user = User,
@@ -393,11 +387,9 @@ handle_userauth_info_request(#ssh_msg_userauth_info_request{name = Name,
instruction = Instr,
num_prompts = NumPrompts,
data = Data},
- #ssh{opts = Opts,
- io_cb = IoCb
- } = Ssh) ->
+ #ssh{opts=Opts} = Ssh) ->
PromptInfos = decode_keyboard_interactive_prompts(NumPrompts,Data),
- case keyboard_interact_get_responses(IoCb, Opts, Name, Instr, PromptInfos) of
+ case keyboard_interact_get_responses(Opts, Name, Instr, PromptInfos) of
not_ok ->
not_ok;
Responses ->
@@ -451,11 +443,8 @@ handle_userauth_info_response({extra,#ssh_msg_userauth_info_response{}},
handle_userauth_info_response(#ssh_msg_userauth_info_response{},
_Auth) ->
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{code = ?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
- description = "Server does not support keyboard-interactive"
- }).
-
+ ?DISCONNECT(?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
+ "Server does not support keyboard-interactive").
%%--------------------------------------------------------------------
%%% Internal functions
@@ -492,10 +481,8 @@ check_password(User, Password, Opts, Ssh) ->
{false,NewState} ->
{false, Ssh#ssh{pwdfun_user_state=NewState}};
disconnect ->
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{code = ?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
- description = "Unable to connect using the available authentication methods"
- })
+ ?DISCONNECT(?SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE,
+ "")
end
end.
@@ -509,9 +496,7 @@ get_password_option(Opts, User) ->
pre_verify_sig(User, KeyBlob, Opts) ->
try
Key = public_key:ssh_decode(KeyBlob, ssh2_pubkey), % or exception
- {KeyCb,KeyCbOpts} = ?GET_OPT(key_cb, Opts),
- UserOpts = ?GET_OPT(user_options, Opts),
- KeyCb:is_auth_key(Key, User, [{key_cb_private,KeyCbOpts}|UserOpts])
+ ssh_transport:call_KeyCb(is_auth_key, [Key, User], Opts)
catch
_:_ ->
false
@@ -520,10 +505,8 @@ pre_verify_sig(User, KeyBlob, Opts) ->
verify_sig(SessionId, User, Service, AlgBin, KeyBlob, SigWLen, #ssh{opts = Opts} = Ssh) ->
try
Alg = binary_to_list(AlgBin),
- {KeyCb,KeyCbOpts} = ?GET_OPT(key_cb, Opts),
- UserOpts = ?GET_OPT(user_options, Opts),
Key = public_key:ssh_decode(KeyBlob, ssh2_pubkey), % or exception
- true = KeyCb:is_auth_key(Key, User, [{key_cb_private,KeyCbOpts}|UserOpts]),
+ true = ssh_transport:call_KeyCb(is_auth_key, [Key, User], Opts),
PlainText = build_sig_data(SessionId, User, Service, KeyBlob, Alg),
<<?UINT32(AlgSigLen), AlgSig:AlgSigLen/binary>> = SigWLen,
<<?UINT32(AlgLen), _Alg:AlgLen/binary,
@@ -547,60 +530,78 @@ build_sig_data(SessionId, User, Service, KeyBlob, Alg) ->
+key_alg('rsa-sha2-256') -> 'ssh-rsa';
+key_alg('rsa-sha2-512') -> 'ssh-rsa';
+key_alg(Alg) -> Alg.
+
+%%%================================================================
+%%%
+%%% Keyboard-interactive
+%%%
+
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),
+keyboard_interact_get_responses(Opts, Name, Instr, PromptInfos) ->
keyboard_interact_get_responses(?GET_OPT(user_interaction, Opts),
?GET_OPT(keyboard_interact_fun, Opts),
- ?GET_OPT(password, Opts), IoCb, Name,
- Instr, PromptInfos, Opts, NumPrompts).
+ ?GET_OPT(password, Opts),
+ Name,
+ Instr,
+ PromptInfos,
+ Opts).
-keyboard_interact_get_responses(_, _, not_ok, _, _, _, _, _, _) ->
+%% Don't re-try an already rejected password. This could happen if both keyboard-interactive
+%% and password methods are tried:
+keyboard_interact_get_responses(_, _, not_ok, _, _, _, _) ->
not_ok;
-keyboard_interact_get_responses(_, undefined, Password, _, _, _, _, _,
- 1) when Password =/= undefined ->
- [Password]; %% Password auth implemented with keyboard-interaction and passwd is known
-keyboard_interact_get_responses(_, _, _, _, _, _, _, _, 0) ->
+
+%% Only one password requestedm and we have got one via the 'password' option for the daemon:
+keyboard_interact_get_responses(_, undefined, Pwd, _, _, [_], _) when Pwd =/= undefined ->
+ [Pwd]; %% Password auth implemented with keyboard-interaction and passwd is known
+
+%% No password requested (keyboard-interactive):
+keyboard_interact_get_responses(_, _, _, _, _, [], _) ->
[];
-keyboard_interact_get_responses(false, undefined, undefined, _, _, _, [Prompt|_], Opts, _) ->
- ssh_no_io:read_line(Prompt, Opts); %% Throws error as keyboard interaction is not allowed
-keyboard_interact_get_responses(true, undefined, _,IoCb, Name, Instr, PromptInfos, Opts, _) ->
- keyboard_interact(IoCb, Name, Instr, PromptInfos, Opts);
-keyboard_interact_get_responses(true, Fun, _Pwd, _IoCb, Name, Instr, PromptInfos, _Opts, NumPrompts) ->
- keyboard_interact_fun(Fun, Name, Instr, PromptInfos, NumPrompts).
-
-keyboard_interact(IoCb, Name, Instr, Prompts, Opts) ->
+
+%% user_interaction is forbidden (by option user_interaction) and we have to ask
+%% the user for one or more.
+%% Throw an error:
+keyboard_interact_get_responses(false, undefined, undefined, _, _, [Prompt|_], Opts) ->
+ ssh_no_io:read_line(Prompt, Opts);
+
+%% One or more passwords are requested, we may prompt the user and no fun is used
+%% to get the responses:
+keyboard_interact_get_responses(true, undefined, _, Name, Instr, PromptInfos, Opts) ->
+ prompt_user_for_passwords(Name, Instr, PromptInfos, Opts);
+
+%% The passwords are provided with a fun. Use that one!
+keyboard_interact_get_responses(true, Fun, _Pwd, Name, Instr, PromptInfos, _Opts) ->
+ keyboard_interact_fun(Fun, Name, Instr, PromptInfos).
+
+
+
+prompt_user_for_passwords(Name, Instr, PromptInfos, Opts) ->
+ IoCb = ?GET_INTERNAL_OPT(io_cb, Opts),
write_if_nonempty(IoCb, Name),
write_if_nonempty(IoCb, Instr),
lists:map(fun({Prompt, true}) -> IoCb:read_line(Prompt, Opts);
({Prompt, false}) -> IoCb:read_password(Prompt, Opts)
end,
- Prompts).
+ PromptInfos).
+
+keyboard_interact_fun(KbdInteractFun, Name, Instr, PromptInfos) ->
+ case KbdInteractFun(Name, Instr, PromptInfos) of
+ Responses when is_list(Responses),
+ length(Responses) == length(PromptInfos) ->
+ Responses;
+ _ ->
+ nok
+ end.
+
write_if_nonempty(_, "") -> ok;
write_if_nonempty(_, <<>>) -> ok;
write_if_nonempty(IoCb, Text) -> IoCb:format("~s~n",[Text]).
-
-keyboard_interact_fun(KbdInteractFun, Name, Instr, PromptInfos, NumPrompts) ->
- Prompts = lists:map(fun({Prompt, _Echo}) -> Prompt end,
- PromptInfos),
- case KbdInteractFun(Name, Instr, Prompts) of
- Rs when length(Rs) == NumPrompts ->
- Rs;
- Rs ->
- throw({mismatching_number_of_responses,
- {got,Rs},
- {expected, NumPrompts},
- #ssh_msg_disconnect{code = ?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
- description = "User interaction failed",
- language = "en"}})
- end.
-
-
-key_alg('rsa-sha2-256') -> 'ssh-rsa';
-key_alg('rsa-sha2-512') -> 'ssh-rsa';
-key_alg(Alg) -> Alg.
diff --git a/lib/ssh/src/ssh_channel.erl b/lib/ssh/src/ssh_channel.erl
index 85b31f3669..1d977e3bc9 100644
--- a/lib/ssh/src/ssh_channel.erl
+++ b/lib/ssh/src/ssh_channel.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@
-module(ssh_channel).
+-include("ssh.hrl").
-include("ssh_connect.hrl").
-callback init(Args :: term()) ->
@@ -49,331 +50,47 @@
{ok, NewState :: term()} | {error, Reason :: term()}.
-callback handle_msg(Msg ::term(), State :: term()) ->
- {ok, State::term()} | {stop, ChannelId::integer(), State::term()}.
+ {ok, State::term()} | {stop, ChannelId::ssh:channel_id(), State::term()}.
--callback handle_ssh_msg({ssh_cm, ConnectionRef::term(), SshMsg::term()},
+-callback handle_ssh_msg({ssh_cm, ConnectionRef::ssh:connection_ref(), SshMsg::term()},
State::term()) -> {ok, State::term()} |
- {stop, ChannelId::integer(),
+ {stop, ChannelId::ssh:channel_id(),
State::term()}.
--behaviour(gen_server).
-
%%% API
-export([start/4, start/5, start_link/4, start_link/5, call/2, call/3,
+ init/1,
cast/2, reply/2, enter_loop/1]).
-%% gen_server callbacks
--export([init/1, handle_call/3, handle_cast/2, handle_info/2,
- terminate/2, code_change/3]).
-
-%% Internal application API
--export([cache_create/0, cache_lookup/2, cache_update/2,
- cache_delete/1, cache_delete/2, cache_foldl/3,
- cache_info/2, cache_find/2,
- get_print_info/1]).
-
--record(state, {
- cm,
- channel_cb,
- channel_state,
- channel_id,
- close_sent = false
- }).
-
%%====================================================================
%% API
%%====================================================================
call(ChannelPid, Msg) ->
- call(ChannelPid, Msg, infinity).
+ ssh_client_channel:call(ChannelPid, Msg).
call(ChannelPid, Msg, TimeOute) ->
- try gen_server:call(ChannelPid, Msg, TimeOute) of
- Result ->
- Result
- catch
- exit:{noproc, _} ->
- {error, closed};
- exit:{normal, _} ->
- {error, closed};
- exit:{shutdown, _} ->
- {error, closed};
- exit:{{shutdown, _}, _} ->
- {error, closed};
- exit:{timeout, _} ->
- {error, timeout}
- end.
+ ssh_client_channel:call(ChannelPid, Msg, TimeOute).
cast(ChannelPid, Msg) ->
- gen_server:cast(ChannelPid, Msg).
-
+ ssh_client_channel:cast(ChannelPid, Msg).
reply(From, Msg) ->
- gen_server:reply(From, Msg).
+ ssh_client_channel:reply(From, Msg).
-%%====================================================================
-%% Internal application API
-%%====================================================================
+init(Args) ->
+ ssh_client_channel:init(Args).
-%%--------------------------------------------------------------------
-%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
-%% Description: Starts the server
-%%--------------------------------------------------------------------
start(ConnectionManager, ChannelId, CallBack, CbInitArgs) ->
- start(ConnectionManager, ChannelId, CallBack, CbInitArgs, undefined).
+ ssh_client_channel:start(ConnectionManager, ChannelId, CallBack, CbInitArgs).
start(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec) ->
- Options = [{channel_cb, CallBack},
- {channel_id, ChannelId},
- {init_args, CbInitArgs},
- {cm, ConnectionManager},
- {exec, Exec}],
- gen_server:start(?MODULE, [Options], []).
+ ssh_client_channel:start(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec).
start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs) ->
- start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, undefined).
+ ssh_client_channel:start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs).
start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec) ->
- Options = [{channel_cb, CallBack},
- {channel_id, ChannelId},
- {init_args, CbInitArgs},
- {cm, ConnectionManager},
- {exec, Exec}],
- gen_server:start_link(?MODULE, [Options], []).
+ ssh_client_channel:start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec).
enter_loop(State) ->
- gen_server:enter_loop(?MODULE, [], State).
-
-%%====================================================================
-%% gen_server callbacks
-%%====================================================================
-
-%%--------------------------------------------------------------------
-%% Function: init(Args) -> {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
-%% Description: Initiates the server
-%%--------------------------------------------------------------------
-init([Options]) ->
- Cb = proplists:get_value(channel_cb, Options),
- ConnectionManager = proplists:get_value(cm, Options),
- ChannelId = proplists:get_value(channel_id, Options),
- process_flag(trap_exit, true),
- InitArgs =
- case proplists:get_value(exec, Options) of
- undefined ->
- proplists:get_value(init_args, Options);
- Exec ->
- proplists:get_value(init_args, Options) ++ [Exec]
- end,
- try Cb:init(InitArgs) of
- {ok, ChannelState} ->
- State = #state{cm = ConnectionManager,
- channel_cb = Cb,
- channel_id = ChannelId,
- channel_state = ChannelState},
- self() ! {ssh_channel_up, ChannelId, ConnectionManager},
- {ok, State};
- {ok, ChannelState, Timeout} ->
- State = #state{cm = ConnectionManager,
- channel_cb = Cb,
- channel_id = ChannelId,
- channel_state = ChannelState},
- self() ! {ssh_channel_up, ChannelId, ConnectionManager},
- {ok, State, Timeout};
- {stop, Why} ->
- {stop, Why}
- catch
- _:Reason ->
- {stop, Reason}
- end.
-
-%%--------------------------------------------------------------------
-%% 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_print_info, _From, State) ->
- Reply =
- {{State#state.cm,
- State#state.channel_id},
- io_lib:format('CB=~p',[State#state.channel_cb])
- },
- {reply, Reply, State};
-
-handle_call(Request, From, #state{channel_cb = Module,
- channel_state = ChannelState} = State) ->
- try Module:handle_call(Request, From, ChannelState) of
- Result ->
- handle_cb_result(Result, State)
- catch
- error:{undef, _} ->
- {noreply, State}
- end.
-
-
-%%--------------------------------------------------------------------
-%% Function: handle_cast(Msg, State) -> {noreply, State} |
-%% {noreply, State, Timeout} |
-%% {stop, Reason, State}
-%% Description: Handling cast messages
-%%--------------------------------------------------------------------
-handle_cast(Msg, #state{channel_cb = Module,
- channel_state = ChannelState} = State) ->
-
- try Module:handle_cast(Msg, ChannelState) of
- Result ->
- handle_cb_result(Result, State)
- catch
- error:{undef, _} ->
- {noreply, State}
- end.
-
-%%--------------------------------------------------------------------
-%% Function: handle_info(Info, State) -> {noreply, State} |
-%% {noreply, State, Timeout} |
-%% {stop, Reason, State}
-%% Description: Handling all non call/cast messages
-%%--------------------------------------------------------------------
-handle_info({ssh_cm, ConnectionManager, {closed, _ChannelId}},
- #state{cm = ConnectionManager,
- close_sent = true} = State) ->
- {stop, normal, State};
-handle_info({ssh_cm, ConnectionManager, {closed, ChannelId}},
- #state{cm = ConnectionManager,
- close_sent = false} = State) ->
- %% To be on the safe side, i.e. the manager has already been terminated.
- (catch ssh_connection:close(ConnectionManager, ChannelId)),
- {stop, normal, State#state{close_sent = true}};
-
-handle_info({ssh_cm, _, _} = Msg, #state{cm = ConnectionManager,
- channel_cb = Module,
- channel_state = ChannelState0} = State) ->
- case Module:handle_ssh_msg(Msg, ChannelState0) of
- {ok, ChannelState} ->
- adjust_window(Msg),
- {noreply, State#state{channel_state = ChannelState}};
- {ok, ChannelState, Timeout} ->
- adjust_window(Msg),
- {noreply, State#state{channel_state = ChannelState}, Timeout};
- {stop, ChannelId, ChannelState} ->
- catch ssh_connection:close(ConnectionManager, ChannelId),
- {stop, normal, State#state{close_sent = true,
- channel_state = ChannelState}}
- end;
-
-handle_info(Msg, #state{cm = ConnectionManager, channel_cb = Module,
- channel_state = ChannelState0} = State) ->
- case Module:handle_msg(Msg, ChannelState0) of
- {ok, ChannelState} ->
- {noreply, State#state{channel_state = ChannelState}};
- {ok, ChannelState, Timeout} ->
- {noreply, State#state{channel_state = ChannelState}, Timeout};
- {stop, Reason, ChannelState} when is_atom(Reason)->
- {stop, Reason, State#state{close_sent = true,
- channel_state = ChannelState}};
- {stop, ChannelId, ChannelState} ->
- Reason =
- case Msg of
- {'EXIT', _Pid, shutdown} ->
- shutdown;
- _ ->
- normal
- end,
- (catch ssh_connection:close(ConnectionManager, ChannelId)),
- {stop, Reason, State#state{close_sent = true,
- channel_state = ChannelState}}
- 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{cm = ConnectionManager,
- channel_id = ChannelId,
- close_sent = false} = State) ->
- 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),
- ok.
-
-%%--------------------------------------------------------------------
-%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
-%% Description: Convert process state when code is changed
-%%--------------------------------------------------------------------
-code_change(OldVsn, #state{channel_cb = Module,
- channel_state = ChannelState0} = State, Extra) ->
- {ok, ChannelState} = Module:code_change(OldVsn, ChannelState0, Extra),
- {ok, State#state{channel_state = ChannelState}}.
-
-%%====================================================================
-%% Internal application API
-%%====================================================================
-cache_create() ->
- ets:new(cm_tab, [set,{keypos, #channel.local_id}]).
-
-cache_lookup(Cache, Key) ->
- case ets:lookup(Cache, Key) of
- [Channel] ->
- Channel;
- [] ->
- undefined
- end.
-
-cache_update(Cache, #channel{local_id = Id} = Entry) when Id =/= undefined ->
- ets:insert(Cache, Entry).
-
-cache_delete(Cache, Key) ->
- ets:delete(Cache, Key).
-
-cache_delete(Cache) ->
- ets:delete(Cache).
-
-cache_foldl(Fun, Acc, Cache) ->
- ets:foldl(Fun, Acc, Cache).
-
-cache_info(num_entries, Cache) ->
- proplists:get_value(size, ets:info(Cache)).
-
-cache_find(ChannelPid, Cache) ->
- case ets:match_object(Cache, #channel{user = ChannelPid}) of
- [] ->
- undefined;
- [Channel] ->
- Channel
- end.
-
-get_print_info(Pid) ->
- call(Pid, get_print_info, 1000).
-
-%%--------------------------------------------------------------------
-%%% Internal functions
-%%--------------------------------------------------------------------
-handle_cb_result({reply, Reply, ChannelState}, State) ->
- {reply, Reply, State#state{channel_state = ChannelState}};
-handle_cb_result({reply, Reply, ChannelState, Timeout}, State) ->
- {reply, Reply,State#state{channel_state = ChannelState}, Timeout};
-handle_cb_result({noreply, ChannelState}, State) ->
- {noreply, State#state{channel_state = ChannelState}};
-handle_cb_result({noreply, ChannelState, Timeout}, State) ->
- {noreply, State#state{channel_state = ChannelState}, Timeout};
-handle_cb_result({stop, Reason, Reply, ChannelState}, State) ->
- {stop, Reason, Reply, State#state{channel_state = ChannelState}};
-handle_cb_result({stop, Reason, ChannelState}, State) ->
- {stop, Reason, State#state{channel_state = ChannelState}}.
-
-adjust_window({ssh_cm, ConnectionManager,
- {data, ChannelId, _, Data}}) ->
- ssh_connection:adjust_window(ConnectionManager, ChannelId, size(Data));
-adjust_window(_) ->
- ok.
-
-
+ ssh_client_channel:enter_loop(State).
diff --git a/lib/ssh/src/ssh_channel_sup.erl b/lib/ssh/src/ssh_channel_sup.erl
deleted file mode 100644
index 8444533fd1..0000000000
--- a/lib/ssh/src/ssh_channel_sup.erl
+++ /dev/null
@@ -1,64 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
-%%----------------------------------------------------------------------
-%% Purpose: Ssh channel supervisor.
-%%----------------------------------------------------------------------
--module(ssh_channel_sup).
-
--behaviour(supervisor).
-
--export([start_link/1, start_child/5]).
-
-%% Supervisor callback
--export([init/1]).
-
-%%%=========================================================================
-%%% Internal API
-%%%=========================================================================
-start_link(Args) ->
- supervisor:start_link(?MODULE, [Args]).
-
-start_child(Sup, Callback, Id, Args, Exec) ->
- ChildSpec =
- #{id => make_ref(),
- start => {ssh_channel, start_link, [self(), Id, Callback, Args, Exec]},
- restart => temporary,
- type => worker,
- modules => [ssh_channel]
- },
- supervisor:start_child(Sup, ChildSpec).
-
-%%%=========================================================================
-%%% Supervisor callback
-%%%=========================================================================
--spec init( [term()] ) -> {ok,{supervisor:sup_flags(),[supervisor:child_spec()]}} | ignore .
-
-init(_Args) ->
- RestartStrategy = one_for_one,
- MaxR = 10,
- MaxT = 3600,
- Children = [],
- {ok, {{RestartStrategy, MaxR, MaxT}, Children}}.
-
-%%%=========================================================================
-%%% Internal functions
-%%%=========================================================================
diff --git a/lib/ssh/src/ssh_cli.erl b/lib/ssh/src/ssh_cli.erl
index 958c342f5f..af51356355 100644
--- a/lib/ssh/src/ssh_cli.erl
+++ b/lib/ssh/src/ssh_cli.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,14 +25,16 @@
-module(ssh_cli).
--behaviour(ssh_daemon_channel).
+-behaviour(ssh_server_channel).
-include("ssh.hrl").
-include("ssh_connect.hrl").
-%% ssh_channel callbacks
+%% ssh_server_channel callbacks
-export([init/1, handle_ssh_msg/2, handle_msg/2, terminate/2]).
+-export([dbg_trace/3]).
+
%% state
-record(state, {
cm,
@@ -45,23 +47,8 @@
}).
%%====================================================================
-%% ssh_channel callbacks
+%% ssh_server_channel callbacks
%%====================================================================
--spec init(Args :: term()) ->
- {ok, State :: term()} | {ok, State :: term(), timeout() | hibernate} |
- {stop, Reason :: term()} | ignore.
-
--spec terminate(Reason :: (normal | shutdown | {shutdown, term()} |
- term()),
- State :: term()) ->
- term().
-
--spec handle_msg(Msg ::term(), State :: term()) ->
- {ok, State::term()} | {stop, ChannelId::integer(), State::term()}.
--spec handle_ssh_msg({ssh_cm, ConnectionRef::term(), SshMsg::term()},
- State::term()) -> {ok, State::term()} |
- {stop, ChannelId::integer(),
- State::term()}.
%%--------------------------------------------------------------------
%% Function: init(Args) -> {ok, State}
@@ -118,42 +105,53 @@ handle_ssh_msg({ssh_cm, ConnectionHandler,
write_chars(ConnectionHandler, ChannelId, Chars),
{ok, State#state{pty = Pty, buf = NewBuf}};
-handle_ssh_msg({ssh_cm, ConnectionHandler,
- {shell, ChannelId, WantReply}}, State) ->
+handle_ssh_msg({ssh_cm, ConnectionHandler, {shell, ChannelId, WantReply}}, State) ->
NewState = start_shell(ConnectionHandler, State),
- ssh_connection:reply_request(ConnectionHandler, WantReply,
- success, ChannelId),
- {ok, NewState#state{channel = ChannelId,
- cm = ConnectionHandler}};
-
-handle_ssh_msg({ssh_cm, ConnectionHandler,
- {exec, ChannelId, WantReply, Cmd}}, #state{exec=undefined,
- shell=?DEFAULT_SHELL} = State) ->
- {Reply, Status} = exec(Cmd),
- write_chars(ConnectionHandler,
- ChannelId, io_lib:format("~p\n", [Reply])),
- ssh_connection:reply_request(ConnectionHandler, WantReply,
- success, ChannelId),
- 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{exec = undefined} = State) ->
- write_chars(ConnectionHandler, ChannelId, 1, "Prohibited.\n"),
ssh_connection:reply_request(ConnectionHandler, WantReply, success, ChannelId),
- ssh_connection:exit_status(ConnectionHandler, ChannelId, 255),
- 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(ConnectionHandler, Cmd, State),
- ssh_connection:reply_request(ConnectionHandler, WantReply,
- success, ChannelId),
{ok, NewState#state{channel = ChannelId,
cm = ConnectionHandler}};
+handle_ssh_msg({ssh_cm, ConnectionHandler, {exec, ChannelId, WantReply, Cmd}}, S0) ->
+ case
+ case S0#state.exec of
+ {direct,F} ->
+ %% Exec called and a Fun or MFA is defined to use. The F returns the
+ %% value to return.
+ exec_direct(ConnectionHandler, F, Cmd);
+
+ undefined when S0#state.shell == ?DEFAULT_SHELL ->
+ %% Exec called and the shell is the default shell (= Erlang shell).
+ %% To be exact, eval the term as an Erlang term (but not using the
+ %% ?DEFAULT_SHELL directly). This disables banner, prompts and such.
+ exec_in_erlang_default_shell(Cmd);
+
+ undefined ->
+ %% Exec called, but the a shell other than the default shell is defined.
+ %% No new exec shell is defined, so don't execute!
+ %% We don't know if it is intended to use the new shell or not.
+ {"Prohibited.", 255, 1};
+
+ _ ->
+ %% Exec called and a Fun or MFA is defined to use. The F communicates via
+ %% standard io:write/read.
+ %% Kept for compatibility.
+ S1 = start_exec_shell(ConnectionHandler, Cmd, S0),
+ ssh_connection:reply_request(ConnectionHandler, WantReply, success, ChannelId),
+ {ok, S1}
+ end
+ of
+ {Reply, Status, Type} ->
+ write_chars(ConnectionHandler, ChannelId, Type, Reply),
+ ssh_connection:reply_request(ConnectionHandler, WantReply, success, ChannelId),
+ ssh_connection:exit_status(ConnectionHandler, ChannelId, Status),
+ ssh_connection:send_eof(ConnectionHandler, ChannelId),
+ {stop, ChannelId, S0#state{channel = ChannelId, cm = ConnectionHandler}};
+
+ {ok, S} ->
+ {ok, S#state{channel = ChannelId,
+ cm = ConnectionHandler}}
+ end;
+
handle_ssh_msg({ssh_cm, _ConnectionHandler, {eof, _ChannelId}}, State) ->
{ok, State};
@@ -259,35 +257,7 @@ to_group(Data, Group) ->
end,
to_group(Tail, Group).
-exec(Cmd) ->
- case eval(parse(scan(Cmd))) of
- {error, _} ->
- {Cmd, 0}; %% This should be an external call
- Term ->
- Term
- end.
-
-scan(Cmd) ->
- erl_scan:string(Cmd).
-
-parse({ok, Tokens, _}) ->
- erl_parse:parse_exprs(Tokens);
-parse(Error) ->
- Error.
-
-eval({ok, Expr_list}) ->
- case (catch erl_eval:exprs(Expr_list,
- erl_eval:new_bindings())) of
- {value, Value, _NewBindings} ->
- {Value, 0};
- {'EXIT', {Error, _}} ->
- {Error, -1};
- Error ->
- {Error, -1}
- end;
-eval(Error) ->
- {Error, -1}.
-
+%%--------------------------------------------------------------------
%%% io_request, handle io requests from the user process,
%%% Note, this is not the real I/O-protocol, but the mockup version
%%% used between edlin and a user_driver. The protocol tags are
@@ -506,53 +476,130 @@ bin_to_list(L) when is_list(L) ->
bin_to_list(I) when is_integer(I) ->
I.
+
+%%--------------------------------------------------------------------
start_shell(ConnectionHandler, State) ->
- Shell = State#state.shell,
- ConnectionInfo = ssh_connection_handler:connection_info(ConnectionHandler,
- [peer, user]),
- ShellFun = case is_function(Shell) of
- true ->
- User = proplists:get_value(user, ConnectionInfo),
- case erlang:fun_info(Shell, arity) of
- {arity, 1} ->
- fun() -> Shell(User) end;
- {arity, 2} ->
- {_, PeerAddr} = proplists:get_value(peer, ConnectionInfo),
- fun() -> Shell(User, PeerAddr) end;
- _ ->
- Shell
- end;
- _ ->
- Shell
- end,
- Echo = get_echo(State#state.pty),
- Group = group:start(self(), ShellFun, [{echo, Echo}]),
- State#state{group = Group, buf = empty_buf()}.
-
-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(ConnectionHandler, Cmd, #state{exec=Shell} = State) when is_function(Shell) ->
-
- ConnectionInfo = ssh_connection_handler:connection_info(ConnectionHandler,
- [peer, user]),
- User = proplists:get_value(user, ConnectionInfo),
- ShellFun =
- case erlang:fun_info(Shell, arity) of
- {arity, 1} ->
- fun() -> Shell(Cmd) end;
- {arity, 2} ->
- fun() -> Shell(Cmd, User) end;
- {arity, 3} ->
- {_, PeerAddr} = proplists:get_value(peer, ConnectionInfo),
- fun() -> Shell(Cmd, User, PeerAddr) end;
- _ ->
- Shell
- end,
- Echo = get_echo(State#state.pty),
- Group = group:start(self(), ShellFun, [{echo,Echo}]),
- State#state{group = Group, buf = empty_buf()}.
+ ShellSpawner =
+ case State#state.shell of
+ Shell when is_function(Shell, 1) ->
+ [{user,User}] = ssh_connection_handler:connection_info(ConnectionHandler, [user]),
+ fun() -> Shell(User) end;
+ Shell when is_function(Shell, 2) ->
+ ConnectionInfo =
+ ssh_connection_handler:connection_info(ConnectionHandler, [peer, user]),
+ User = proplists:get_value(user, ConnectionInfo),
+ {_, PeerAddr} = proplists:get_value(peer, ConnectionInfo),
+ fun() -> Shell(User, PeerAddr) end;
+ {_,_,_} = Shell ->
+ Shell
+ end,
+ State#state{group = group:start(self(), ShellSpawner, [{echo, get_echo(State#state.pty)}]),
+ buf = empty_buf()}.
+
+%%--------------------------------------------------------------------
+start_exec_shell(ConnectionHandler, Cmd, State) ->
+ ExecShellSpawner =
+ case State#state.exec of
+ ExecShell when is_function(ExecShell, 1) ->
+ fun() -> ExecShell(Cmd) end;
+ ExecShell when is_function(ExecShell, 2) ->
+ [{user,User}] = ssh_connection_handler:connection_info(ConnectionHandler, [user]),
+ fun() -> ExecShell(Cmd, User) end;
+ ExecShell when is_function(ExecShell, 3) ->
+ ConnectionInfo =
+ ssh_connection_handler:connection_info(ConnectionHandler, [peer, user]),
+ User = proplists:get_value(user, ConnectionInfo),
+ {_, PeerAddr} = proplists:get_value(peer, ConnectionInfo),
+ fun() -> ExecShell(Cmd, User, PeerAddr) end;
+ {M,F,A} ->
+ {M, F, A++[Cmd]}
+ end,
+ State#state{group = group:start(self(), ExecShellSpawner, [{echo,false}]),
+ buf = empty_buf()}.
+
+%%--------------------------------------------------------------------
+exec_in_erlang_default_shell(Cmd) ->
+ case eval(parse(scan(Cmd))) of
+ {ok, Term} ->
+ {io_lib:format("~p\n", [Term]), 0, 0};
+ {error, Error} when is_atom(Error) ->
+ {io_lib:format("Error in ~p: ~p\n", [Cmd,Error]), -1, 1};
+ _ ->
+ {io_lib:format("Error: ~p\n", [Cmd]), -1, 1}
+ end.
+
+scan(Cmd) ->
+ erl_scan:string(Cmd).
+
+parse({ok, Tokens, _}) ->
+ erl_parse:parse_exprs(Tokens);
+parse(Error) ->
+ Error.
+eval({ok, Expr_list}) ->
+ case (catch erl_eval:exprs(Expr_list,
+ erl_eval:new_bindings())) of
+ {value, Value, _NewBindings} ->
+ {ok, Value};
+ {'EXIT', {Error, _}} ->
+ {error, Error};
+ {error, Error} ->
+ {error, Error};
+ Error ->
+ {error, Error}
+ end;
+eval({error,Error}) ->
+ {error, Error};
+eval(Error) ->
+ {error, Error}.
+
+%%--------------------------------------------------------------------
+exec_direct(ConnectionHandler, ExecSpec, Cmd) ->
+ try
+ case ExecSpec of
+ _ when is_function(ExecSpec, 1) ->
+ ExecSpec(Cmd);
+ _ when is_function(ExecSpec, 2) ->
+ [{user,User}] = ssh_connection_handler:connection_info(ConnectionHandler, [user]),
+ ExecSpec(Cmd, User);
+ _ when is_function(ExecSpec, 3) ->
+ ConnectionInfo =
+ ssh_connection_handler:connection_info(ConnectionHandler, [peer, user]),
+ User = proplists:get_value(user, ConnectionInfo),
+ {_, PeerAddr} = proplists:get_value(peer, ConnectionInfo),
+ ExecSpec(Cmd, User, PeerAddr)
+ end
+ of
+ Reply ->
+ return_direct_exec_reply(Reply, Cmd)
+ catch
+ C:Error ->
+ {io_lib:format("Error in \"~s\": ~p ~p~n", [Cmd,C,Error]), -1, 1}
+ end.
+
+
+
+return_direct_exec_reply(Reply, Cmd) ->
+ case fmt_exec_repl(Reply) of
+ {ok,S} ->
+ {S, 0, 0};
+ {error,S} ->
+ {io_lib:format("Error in \"~s\": ~s~n", [Cmd,S]), -1, 1}
+ end.
+
+fmt_exec_repl({T,A}) when T==ok ; T==error ->
+ try
+ {T, io_lib:format("~s",[A])}
+ catch
+ error:badarg ->
+ {T, io_lib:format("~p", [A])};
+ C:Err ->
+ {error, io_lib:format("~p:~p~n",[C,Err])}
+ end;
+fmt_exec_repl(Other) ->
+ {error, io_lib:format("Bad exec-plugin return: ~p",[Other])}.
+
+%%--------------------------------------------------------------------
% Pty can be undefined if the client never sets any pty options before
% starting the shell.
get_echo(undefined) ->
@@ -578,3 +625,19 @@ not_zero(0, B) ->
not_zero(A, _) ->
A.
+%%%################################################################
+%%%#
+%%%# Tracing
+%%%#
+
+dbg_trace(points, _, _) -> [terminate];
+
+dbg_trace(flags, terminate, _) -> [c];
+dbg_trace(on, terminate, _) -> dbg:tp(?MODULE, terminate, 2, x);
+dbg_trace(off, terminate, _) -> dbg:ctpg(?MODULE, terminate, 2);
+dbg_trace(format, terminate, {call, {?MODULE,terminate, [Reason, State]}}) ->
+ ["Cli Terminating:\n",
+ io_lib:format("Reason: ~p,~nState:~n~s", [Reason, wr_record(State)])
+ ].
+
+?wr_record(state).
diff --git a/lib/ssh/src/ssh_client_channel.erl b/lib/ssh/src/ssh_client_channel.erl
new file mode 100644
index 0000000000..f985d8e273
--- /dev/null
+++ b/lib/ssh/src/ssh_client_channel.erl
@@ -0,0 +1,458 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+-module(ssh_client_channel).
+
+-include("ssh.hrl").
+-include("ssh_connect.hrl").
+
+-callback init(Args :: term()) ->
+ {ok, State :: term()} | {ok, State :: term(), timeout() | hibernate} |
+ {stop, Reason :: term()} | ignore.
+-callback handle_call(Request :: term(), From :: {pid(), Tag :: term()},
+ State :: term()) ->
+ {reply, Reply :: term(), NewState :: term()} |
+ {reply, Reply :: term(), NewState :: term(), timeout() | hibernate} |
+ {noreply, NewState :: term()} |
+ {noreply, NewState :: term(), timeout() | hibernate} |
+ {stop, Reason :: term(), Reply :: term(), NewState :: term()} |
+ {stop, Reason :: term(), NewState :: term()}.
+-callback handle_cast(Request :: term(), State :: term()) ->
+ {noreply, NewState :: term()} |
+ {noreply, NewState :: term(), timeout() | hibernate} |
+ {stop, Reason :: term(), NewState :: term()}.
+
+-callback terminate(Reason :: (normal | shutdown | {shutdown, term()} |
+ term()),
+ State :: term()) ->
+ term().
+-callback code_change(OldVsn :: (term() | {down, term()}), State :: term(),
+ Extra :: term()) ->
+ {ok, NewState :: term()} | {error, Reason :: term()}.
+
+-callback handle_msg(Msg ::term(), State :: term()) ->
+ {ok, State::term()} | {stop, ChannelId::ssh:channel_id(), State::term()}.
+
+-callback handle_ssh_msg({ssh_cm, ConnectionRef::ssh:connection_ref(), SshMsg::term()},
+ State::term()) -> {ok, State::term()} |
+ {stop, ChannelId::ssh:channel_id(),
+ State::term()}.
+-behaviour(gen_server).
+
+%%% API
+-export([start/4, start/5, start_link/4, start_link/5, call/2, call/3,
+ cast/2, reply/2, enter_loop/1]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+%% Internal application API
+-export([cache_create/0, cache_lookup/2, cache_update/2,
+ cache_delete/1, cache_delete/2, cache_foldl/3,
+ cache_info/2, cache_find/2,
+ get_print_info/1]).
+
+-export([dbg_trace/3]).
+
+-record(state, {
+ cm,
+ channel_cb,
+ channel_state,
+ channel_id,
+ close_sent = false
+ }).
+
+%%====================================================================
+%% API
+%%====================================================================
+
+call(ChannelPid, Msg) ->
+ call(ChannelPid, Msg, infinity).
+
+call(ChannelPid, Msg, TimeOute) ->
+ try gen_server:call(ChannelPid, Msg, TimeOute) of
+ Result ->
+ Result
+ catch
+ exit:{noproc, _} ->
+ {error, closed};
+ exit:{normal, _} ->
+ {error, closed};
+ exit:{shutdown, _} ->
+ {error, closed};
+ exit:{{shutdown, _}, _} ->
+ {error, closed};
+ exit:{timeout, _} ->
+ {error, timeout}
+ end.
+
+cast(ChannelPid, Msg) ->
+ gen_server:cast(ChannelPid, Msg).
+
+
+reply(From, Msg) ->
+ gen_server:reply(From, Msg).
+
+%%====================================================================
+%% Internal application API
+%%====================================================================
+
+%%--------------------------------------------------------------------
+%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
+%% Description: Starts the server
+%%--------------------------------------------------------------------
+start(ConnectionManager, ChannelId, CallBack, CbInitArgs) ->
+ start(ConnectionManager, ChannelId, CallBack, CbInitArgs, undefined).
+
+start(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec) ->
+ Options = [{channel_cb, CallBack},
+ {channel_id, ChannelId},
+ {init_args, CbInitArgs},
+ {cm, ConnectionManager},
+ {exec, Exec}],
+ gen_server:start(?MODULE, [Options], []).
+
+start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs) ->
+ start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, undefined).
+
+start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec) ->
+ Options = [{channel_cb, CallBack},
+ {channel_id, ChannelId},
+ {init_args, CbInitArgs},
+ {cm, ConnectionManager},
+ {exec, Exec}],
+ gen_server:start_link(?MODULE, [Options], []).
+
+enter_loop(State) ->
+ gen_server:enter_loop(?MODULE, [], State).
+
+%%====================================================================
+%% gen_server callbacks
+%%====================================================================
+
+%%--------------------------------------------------------------------
+%% Function: init(Args) -> {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%% Description: Initiates the server
+%%--------------------------------------------------------------------
+init([Options]) ->
+ Cb = proplists:get_value(channel_cb, Options),
+ ConnectionManager = proplists:get_value(cm, Options),
+ ChannelId = proplists:get_value(channel_id, Options),
+ process_flag(trap_exit, true),
+ try Cb:init(channel_cb_init_args(Options)) of
+ {ok, ChannelState} ->
+ State = #state{cm = ConnectionManager,
+ channel_cb = Cb,
+ channel_id = ChannelId,
+ channel_state = ChannelState},
+ self() ! {ssh_channel_up, ChannelId, ConnectionManager},
+ {ok, State};
+ {ok, ChannelState, Timeout} ->
+ State = #state{cm = ConnectionManager,
+ channel_cb = Cb,
+ channel_id = ChannelId,
+ channel_state = ChannelState},
+ self() ! {ssh_channel_up, ChannelId, ConnectionManager},
+ {ok, State, Timeout};
+ {stop, Why} ->
+ {stop, Why}
+ catch
+ _:undef ->
+ {stop, {bad_channel_callback_module,Cb}};
+ _:Reason ->
+ {stop, Reason}
+ end.
+
+channel_cb_init_args(Options) ->
+ case proplists:get_value(exec, Options) of
+ undefined ->
+ proplists:get_value(init_args, Options);
+ Exec ->
+ proplists:get_value(init_args, Options) ++ [Exec]
+ end.
+
+%%--------------------------------------------------------------------
+%% 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_print_info, _From, State) ->
+ Reply =
+ {{State#state.cm,
+ State#state.channel_id},
+ io_lib:format('CB=~p',[State#state.channel_cb])
+ },
+ {reply, Reply, State};
+
+handle_call(Request, From, #state{channel_cb = Module,
+ channel_state = ChannelState} = State) ->
+ try Module:handle_call(Request, From, ChannelState) of
+ Result ->
+ handle_cb_result(Result, State)
+ catch
+ error:{undef, _} ->
+ {noreply, State}
+ end.
+
+
+%%--------------------------------------------------------------------
+%% Function: handle_cast(Msg, State) -> {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State}
+%% Description: Handling cast messages
+%%--------------------------------------------------------------------
+handle_cast(Msg, #state{channel_cb = Module,
+ channel_state = ChannelState} = State) ->
+
+ try Module:handle_cast(Msg, ChannelState) of
+ Result ->
+ handle_cb_result(Result, State)
+ catch
+ error:{undef, _} ->
+ {noreply, State}
+ end.
+
+%%--------------------------------------------------------------------
+%% Function: handle_info(Info, State) -> {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State}
+%% Description: Handling all non call/cast messages
+%%--------------------------------------------------------------------
+handle_info({ssh_cm, ConnectionManager, {closed, _ChannelId}},
+ #state{cm = ConnectionManager,
+ close_sent = true} = State) ->
+ {stop, normal, State};
+handle_info({ssh_cm, ConnectionManager, {closed, ChannelId}},
+ #state{cm = ConnectionManager,
+ close_sent = false} = State) ->
+ %% To be on the safe side, i.e. the manager has already been terminated.
+ (catch ssh_connection:close(ConnectionManager, ChannelId)),
+ {stop, normal, State#state{close_sent = true}};
+
+handle_info({ssh_cm, _, _} = Msg, #state{cm = ConnectionManager,
+ channel_cb = Module,
+ channel_state = ChannelState0} = State) ->
+ case Module:handle_ssh_msg(Msg, ChannelState0) of
+ {ok, ChannelState} ->
+ adjust_window(Msg),
+ {noreply, State#state{channel_state = ChannelState}};
+ {ok, ChannelState, Timeout} ->
+ adjust_window(Msg),
+ {noreply, State#state{channel_state = ChannelState}, Timeout};
+ {stop, ChannelId, ChannelState} ->
+ catch ssh_connection:close(ConnectionManager, ChannelId),
+ {stop, normal, State#state{close_sent = true,
+ channel_state = ChannelState}}
+ end;
+
+handle_info(Msg, #state{cm = ConnectionManager, channel_cb = Module,
+ channel_state = ChannelState0} = State) ->
+ case Module:handle_msg(Msg, ChannelState0) of
+ {ok, ChannelState} ->
+ {noreply, State#state{channel_state = ChannelState}};
+ {ok, ChannelState, Timeout} ->
+ {noreply, State#state{channel_state = ChannelState}, Timeout};
+ {stop, Reason, ChannelState} when is_atom(Reason)->
+ {stop, Reason, State#state{close_sent = true,
+ channel_state = ChannelState}};
+ {stop, ChannelId, ChannelState} ->
+ Reason =
+ case Msg of
+ {'EXIT', _Pid, shutdown} ->
+ shutdown;
+ _ ->
+ normal
+ end,
+ (catch ssh_connection:close(ConnectionManager, ChannelId)),
+ {stop, Reason, State#state{close_sent = true,
+ channel_state = ChannelState}}
+ 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{cm = ConnectionManager,
+ channel_id = ChannelId,
+ close_sent = false} = State) ->
+ catch ssh_connection:close(ConnectionManager, ChannelId),
+ terminate(Reason, State#state{close_sent = true});
+terminate(Reason, #state{channel_cb = Cb, channel_state = ChannelState}) ->
+ catch Cb:terminate(Reason, ChannelState),
+ ok.
+
+%%--------------------------------------------------------------------
+%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
+%% Description: Convert process state when code is changed
+%%--------------------------------------------------------------------
+code_change(OldVsn, #state{channel_cb = Module,
+ channel_state = ChannelState0} = State, Extra) ->
+ {ok, ChannelState} = Module:code_change(OldVsn, ChannelState0, Extra),
+ {ok, State#state{channel_state = ChannelState}}.
+
+%%====================================================================
+%% Internal application API
+%%====================================================================
+cache_create() ->
+ ets:new(cm_tab, [set,{keypos, #channel.local_id}]).
+
+cache_lookup(Cache, Key) ->
+ case ets:lookup(Cache, Key) of
+ [Channel] ->
+ Channel;
+ [] ->
+ undefined
+ end.
+
+cache_update(Cache, #channel{local_id = Id} = Entry) when Id =/= undefined ->
+ ets:insert(Cache, Entry).
+
+cache_delete(Cache, Key) ->
+ ets:delete(Cache, Key).
+
+cache_delete(Cache) ->
+ ets:delete(Cache).
+
+cache_foldl(Fun, Acc, Cache) ->
+ ets:foldl(Fun, Acc, Cache).
+
+cache_info(num_entries, Cache) ->
+ proplists:get_value(size, ets:info(Cache)).
+
+cache_find(ChannelPid, Cache) ->
+ case ets:match_object(Cache, #channel{user = ChannelPid}) of
+ [] ->
+ undefined;
+ [Channel] ->
+ Channel
+ end.
+
+get_print_info(Pid) ->
+ call(Pid, get_print_info, 1000).
+
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
+handle_cb_result({reply, Reply, ChannelState}, State) ->
+ {reply, Reply, State#state{channel_state = ChannelState}};
+handle_cb_result({reply, Reply, ChannelState, Timeout}, State) ->
+ {reply, Reply,State#state{channel_state = ChannelState}, Timeout};
+handle_cb_result({noreply, ChannelState}, State) ->
+ {noreply, State#state{channel_state = ChannelState}};
+handle_cb_result({noreply, ChannelState, Timeout}, State) ->
+ {noreply, State#state{channel_state = ChannelState}, Timeout};
+handle_cb_result({stop, Reason, Reply, ChannelState}, State) ->
+ {stop, Reason, Reply, State#state{channel_state = ChannelState}};
+handle_cb_result({stop, Reason, ChannelState}, State) ->
+ {stop, Reason, State#state{channel_state = ChannelState}}.
+
+adjust_window({ssh_cm, ConnectionManager,
+ {data, ChannelId, _, Data}}) ->
+ ssh_connection:adjust_window(ConnectionManager, ChannelId, size(Data));
+adjust_window(_) ->
+ ok.
+
+
+%%%################################################################
+%%%#
+%%%# Tracing
+%%%#
+
+dbg_trace(points, _, _) -> [terminate, channels, channel_events];
+
+
+dbg_trace(flags, channels, A) -> [c] ++ dbg_trace(flags, terminate, A);
+dbg_trace(on, channels, A) -> dbg:tp(?MODULE, init, 1, x),
+ dbg_trace(on, terminate, A);
+dbg_trace(off, channels, A) -> dbg:ctpg(?MODULE, init, 1),
+ dbg_trace(off, terminate, A);
+dbg_trace(format, channels, {call, {?MODULE,init, [[KVs]]}}) ->
+ ["Server Channel Starting:\n",
+ io_lib:format("Connection: ~p, ChannelId: ~p, CallBack: ~p\nCallBack init args = ~p",
+ [proplists:get_value(K,KVs) || K <- [cm, channel_id, channel_cb]]
+ ++ [channel_cb_init_args(KVs)])
+ ];
+dbg_trace(format, channels, {return_from, {?MODULE,init,1}, {stop,Reason}}) ->
+ ["Server Channel Start FAILED!\n",
+ io_lib:format("Reason = ~p", [Reason])
+ ];
+dbg_trace(format, channels, F) ->
+ dbg_trace(format, terminate, F);
+
+
+dbg_trace(flags, terminate, _) -> [c];
+dbg_trace(on, terminate, _) -> dbg:tp(?MODULE, terminate, 2, x);
+dbg_trace(off, terminate, _) -> dbg:ctpg(?MODULE, terminate, 2);
+dbg_trace(format, terminate, {call, {?MODULE,terminate, [Reason, State]}}) ->
+ ["Server Channel Terminating:\n",
+ io_lib:format("Reason: ~p,~nState:~n~s", [Reason, wr_record(State)])
+ ];
+
+dbg_trace(flags, channel_events, _) -> [c];
+dbg_trace(on, channel_events, _) -> dbg:tp(?MODULE, handle_call, 3, x),
+ dbg:tp(?MODULE, handle_cast, 2, x),
+ dbg:tp(?MODULE, handle_info, 2, x);
+dbg_trace(off, channel_events, _) -> dbg:ctpg(?MODULE, handle_call, 3),
+ dbg:ctpg(?MODULE, handle_cast, 2),
+ dbg:ctpg(?MODULE, handle_info, 2);
+dbg_trace(format, channel_events, {call, {?MODULE,handle_call, [Call,From,State]}}) ->
+ [hdr("is called", State),
+ io_lib:format("From: ~p~nCall: ~p~n", [From, Call])
+ ];
+dbg_trace(format, channel_events, {return_from, {?MODULE,handle_call,3}, Ret}) ->
+ ["Server Channel call returned:\n",
+ io_lib:format("~p~n", [ssh_dbg:reduce_state(Ret)])
+ ];
+dbg_trace(format, channel_events, {call, {?MODULE,handle_cast, [Cast,State]}}) ->
+ [hdr("got cast", State),
+ io_lib:format("Cast: ~p~n", [Cast])
+ ];
+dbg_trace(format, channel_events, {return_from, {?MODULE,handle_cast,2}, Ret}) ->
+ ["Server Channel cast returned:\n",
+ io_lib:format("~p~n", [ssh_dbg:reduce_state(Ret)])
+ ];
+dbg_trace(format, channel_events, {call, {?MODULE,handle_info, [Info,State]}}) ->
+ [hdr("got info", State),
+ io_lib:format("Info: ~p~n", [Info])
+ ];
+dbg_trace(format, channel_events, {return_from, {?MODULE,handle_info,2}, Ret}) ->
+ ["Server Channel info returned:\n",
+ io_lib:format("~p~n", [ssh_dbg:reduce_state(Ret)])
+ ].
+
+hdr(Title, S) ->
+ io_lib:format("Server Channel (Id=~p, CB=~p) ~s:\n", [S#state.channel_id, S#state.channel_cb, Title]).
+
+?wr_record(state).
+
+
diff --git a/lib/ssh/src/ssh_client_key.erl b/lib/ssh/src/ssh_client_key.erl
deleted file mode 100644
index 5296ac2a02..0000000000
--- a/lib/ssh/src/ssh_client_key.erl
+++ /dev/null
@@ -1,35 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
--module(ssh_client_key).
-
--include_lib("public_key/include/public_key.hrl").
--include("ssh.hrl").
-
--callback is_host_key(Key :: public_key(), Host :: string(),
- Algorithm :: 'ssh-rsa'| 'ssh-dsa'| atom(), Options :: proplists:proplist()) ->
- boolean().
-
--callback user_key(Algorithm :: 'ssh-rsa'| 'ssh-dsa'| atom(), Options :: list()) ->
- {ok, PrivateKey :: term()} | {error, string()}.
-
-
--callback add_host_key(Host :: string(), PublicKey :: term(), Options :: list()) ->
- ok | {error, Error::term()}.
diff --git a/lib/ssh/src/ssh_client_key_api.erl b/lib/ssh/src/ssh_client_key_api.erl
index 6e994ff292..384740b786 100644
--- a/lib/ssh/src/ssh_client_key_api.erl
+++ b/lib/ssh/src/ssh_client_key_api.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,26 +23,25 @@
-include_lib("public_key/include/public_key.hrl").
-include("ssh.hrl").
--export_type([algorithm/0]).
+-export_type([client_key_cb_options/0]).
--type algorithm() :: 'ssh-rsa'
- | 'ssh-dss'
- | 'ecdsa-sha2-nistp256'
- | 'ecdsa-sha2-nistp384'
- | 'ecdsa-sha2-nistp521'
- .
+-type client_key_cb_options() :: [{key_cb_private,term()} | ssh:client_option()].
--callback is_host_key(PublicKey :: public_key:public_key(),
- Host :: string(),
- Algorithm :: algorithm(),
- ConnectOptions :: proplists:proplist()) ->
+-callback is_host_key(Key :: public_key:public_key(),
+ Host :: string(),
+ Algorithm :: ssh:pubkey_alg(),
+ Options :: client_key_cb_options()
+ ) ->
boolean().
--callback user_key(Algorithm :: algorithm(),
- ConnectOptions :: proplists:proplist()) ->
- {ok, PrivateKey::public_key:private_key()} | {error, term()}.
+-callback user_key(Algorithm :: ssh:pubkey_alg(),
+ Options :: client_key_cb_options()
+ ) ->
+ {ok, PrivateKey :: public_key:private_key()} | {error, string()}.
--callback add_host_key(Host :: string(), PublicKey :: public_key:public_key(),
- Options :: proplists:proplist()) ->
+-callback add_host_key(Host :: string(),
+ PublicKey :: public_key:public_key(),
+ Options :: client_key_cb_options()
+ ) ->
ok | {error, Error::term()}.
diff --git a/lib/ssh/src/ssh_connect.hrl b/lib/ssh/src/ssh_connect.hrl
index a8de5f9a2f..9a060b8304 100644
--- a/lib/ssh/src/ssh_connect.hrl
+++ b/lib/ssh/src/ssh_connect.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -22,10 +22,6 @@
%%% Description : SSH connection protocol
--type channel_id() :: pos_integer().
--type connection_ref() :: pid().
-
-
-define(DEFAULT_PACKET_SIZE, 65536).
-define(DEFAULT_WINDOW_SIZE, 10*?DEFAULT_PACKET_SIZE).
diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl
index 946ae2967b..83f85b1d8e 100644
--- a/lib/ssh/src/ssh_connection.erl
+++ b/lib/ssh/src/ssh_connection.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -40,40 +40,56 @@
-export([window_change/4, window_change/6,
signal/3, exit_status/3]).
-%% 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,
+%% Internal SSH application API
+-export([channel_data/5,
+ handle_msg/3,
+ handle_stop/1,
+
+ channel_adjust_window_msg/2,
+ channel_close_msg/1,
+ channel_open_failure_msg/4,
+ channel_open_msg/5,
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,
+ channel_data_msg/3,
+ channel_eof_msg/1,
+ channel_failure_msg/1,
+ channel_open_confirmation_msg/4,
+ channel_request_msg/4,
+ channel_success_msg/1,
+
request_failure_msg/0,
- request_success_msg/1, bind/4, unbind/3, unbind_channel/2,
- bound_channel/3, encode_ip/1]).
+ request_success_msg/1,
+
+ bind/4, unbind/3, unbind_channel/2,
+ bound_channel/3, encode_ip/1
+ ]).
+
+-type connection_ref() :: ssh:connection_ref().
+-type channel_id() :: ssh:channel_id().
%%--------------------------------------------------------------------
%%% API
%%--------------------------------------------------------------------
%%--------------------------------------------------------------------
--spec session_channel(connection_ref(), timeout()) -> {ok, channel_id()} | {error, timeout | closed}.
--spec session_channel(connection_ref(), integer(), integer(), timeout()) -> {ok, channel_id()} | {error, timeout | closed}.
-
%% 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.
%% --------------------------------------------------------------------
+-spec session_channel(connection_ref(), timeout()) ->
+ {ok, channel_id()} | {error, timeout | closed}.
+
session_channel(ConnectionHandler, Timeout) ->
- session_channel(ConnectionHandler,
- ?DEFAULT_WINDOW_SIZE, ?DEFAULT_PACKET_SIZE,
- Timeout).
+ session_channel(ConnectionHandler, ?DEFAULT_WINDOW_SIZE, ?DEFAULT_PACKET_SIZE, Timeout).
+
+-spec session_channel(connection_ref(), integer(), integer(), timeout()) ->
+ {ok, channel_id()} | {error, timeout | closed}.
-session_channel(ConnectionHandler, InitialWindowSize,
- MaxPacketSize, Timeout) ->
+session_channel(ConnectionHandler, InitialWindowSize, MaxPacketSize, Timeout) ->
case ssh_connection_handler:open_channel(ConnectionHandler, "session", <<>>,
- InitialWindowSize,
- MaxPacketSize, Timeout) of
+ InitialWindowSize,
+ MaxPacketSize, Timeout) of
{open, Channel} ->
{ok, Channel};
Error ->
@@ -81,55 +97,63 @@ session_channel(ConnectionHandler, InitialWindowSize,
end.
%%--------------------------------------------------------------------
--spec exec(connection_ref(), channel_id(), string(), timeout()) ->
- success | failure | {error, timeout | closed}.
-
%% Description: Will request that the server start the
%% execution of the given command.
%%--------------------------------------------------------------------
+-spec exec(connection_ref(), channel_id(), string(), timeout()) ->
+ success | failure | {error, timeout | closed}.
+
exec(ConnectionHandler, ChannelId, Command, TimeOut) ->
ssh_connection_handler:request(ConnectionHandler, self(), ChannelId, "exec",
true, [?string(Command)], TimeOut).
%%--------------------------------------------------------------------
--spec shell(connection_ref(), 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.
%%--------------------------------------------------------------------
+-spec shell(connection_ref(), channel_id()) ->
+ ok | success | failure | {error, timeout}.
+
shell(ConnectionHandler, ChannelId) ->
ssh_connection_handler:request(ConnectionHandler, self(), ChannelId,
"shell", false, <<>>, 0).
%%--------------------------------------------------------------------
--spec subsystem(connection_ref(), channel_id(), string(), timeout()) ->
- success | failure | {error, timeout | closed}.
%%
%% Description: Executes a predefined subsystem.
%%--------------------------------------------------------------------
+-spec subsystem(connection_ref(), channel_id(), string(), timeout()) ->
+ success | failure | {error, timeout | closed}.
+
subsystem(ConnectionHandler, ChannelId, SubSystem, TimeOut) ->
ssh_connection_handler:request(ConnectionHandler, self(),
ChannelId, "subsystem",
true, [?string(SubSystem)], TimeOut).
%%--------------------------------------------------------------------
--spec send(connection_ref(), channel_id(), iodata()) ->
- ok | {error, closed}.
--spec send(connection_ref(), channel_id(), integer()| iodata(), timeout() | iodata()) ->
- ok | {error, timeout} | {error, closed}.
--spec send(connection_ref(), channel_id(), integer(), iodata(), timeout()) ->
- ok | {error, timeout} | {error, closed}.
-%%
-%%
%% Description: Sends channel data.
%%--------------------------------------------------------------------
+-spec send(connection_ref(), channel_id(), iodata()) ->
+ ok | {error, timeout | closed}.
send(ConnectionHandler, ChannelId, Data) ->
send(ConnectionHandler, ChannelId, 0, Data, infinity).
+
+
+-spec send(connection_ref(), channel_id(), integer()| iodata(), timeout() | iodata()) ->
+ ok | {error, timeout | closed}.
+
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).
+
+
+-spec send(connection_ref(), channel_id(), integer(), iodata(), timeout()) ->
+ ok | {error, timeout | closed}.
+
send(ConnectionHandler, ChannelId, Type, Data, TimeOut) ->
ssh_connection_handler:send(ConnectionHandler, ChannelId,
Type, Data, TimeOut).
@@ -143,7 +167,7 @@ send_eof(ConnectionHandler, Channel) ->
ssh_connection_handler:send_eof(ConnectionHandler, Channel).
%%--------------------------------------------------------------------
--spec adjust_window(connection_ref(), channel_id(), integer()) -> ok | {error, closed}.
+-spec adjust_window(connection_ref(), channel_id(), integer()) -> ok.
%%
%%
%% Description: Adjusts the ssh flowcontrol window.
@@ -185,17 +209,18 @@ reply_request(_,false, _, _) ->
ok.
%%--------------------------------------------------------------------
--spec ptty_alloc(connection_ref(), channel_id(), proplists:proplist()) ->
- success | failiure | {error, closed}.
--spec ptty_alloc(connection_ref(), channel_id(), proplists:proplist(), timeout()) ->
- success | failiure | {error, timeout} | {error, closed}.
-
-%%
-%%
%% Description: Sends a ssh connection protocol pty_req.
%%--------------------------------------------------------------------
+-spec ptty_alloc(connection_ref(), channel_id(), proplists:proplist()) ->
+ success | failure | {error, timeout}.
+
ptty_alloc(ConnectionHandler, Channel, Options) ->
ptty_alloc(ConnectionHandler, Channel, Options, infinity).
+
+
+-spec ptty_alloc(connection_ref(), channel_id(), proplists:proplist(), timeout()) ->
+ success | failure | {error, timeout | closed}.
+
ptty_alloc(ConnectionHandler, Channel, Options0, TimeOut) ->
TermData = backwards_compatible(Options0, []), % FIXME
{Width, PixWidth} = pty_default_dimensions(width, TermData),
@@ -232,33 +257,21 @@ exit_status(ConnectionHandler, Channel, Status) ->
"exit-status", false, [?uint32(Status)], 0).
%%--------------------------------------------------------------------
-%%% Internal API
+%%% Internal, that is, ssh application internal API
%%--------------------------------------------------------------------
-l2b(L) when is_integer(hd(L)) ->
- try list_to_binary(L)
- of
- B -> B
- catch
- _:_ ->
- unicode:characters_to_binary(L)
- end;
-l2b([H|T]) ->
- << (l2b(H))/binary, (l2b(T))/binary >>;
-l2b(B) when is_binary(B) ->
- B;
-l2b([]) ->
- <<>>.
-
+%%%----------------------------------------------------------------
+%%% Send data on a channel/connection as result of for example
+%%% ssh_connection:send (executed in the ssh_connection_state machine)
+%%%
-channel_data(ChannelId, DataType, Data, Connection, From)
- when is_list(Data)->
+channel_data(ChannelId, DataType, Data, Connection, From) when is_list(Data)->
channel_data(ChannelId, DataType, l2b(Data), Connection, From);
channel_data(ChannelId, DataType, Data,
#connection{channel_cache = Cache} = Connection,
From) ->
- case ssh_channel:cache_lookup(Cache, ChannelId) of
+ case ssh_client_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,
@@ -271,11 +284,18 @@ channel_data(ChannelId, DataType, Data,
SendData)}
end, SendList),
FlowCtrlMsgs = flow_control(Replies, Channel, Cache),
- {{replies, Replies ++ FlowCtrlMsgs}, Connection};
+ {Replies ++ FlowCtrlMsgs, Connection};
_ ->
- {{replies,[{channel_request_reply,From,{error,closed}}]}, Connection}
+ {[{channel_request_reply,From,{error,closed}}], Connection}
end.
+%%%----------------------------------------------------------------
+%%% Handle the channel messages on behalf of the ssh_connection_handler
+%%% state machine.
+%%%
+%%% Replies {Reply, UpdatedConnection}
+%%%
+
handle_msg(#ssh_msg_channel_open_confirmation{recipient_channel = ChannelId,
sender_channel = RemoteId,
initial_window_size = WindowSz,
@@ -283,63 +303,42 @@ handle_msg(#ssh_msg_channel_open_confirmation{recipient_channel = ChannelId,
#connection{channel_cache = Cache} = Connection0, _) ->
#channel{remote_id = undefined} = Channel =
- ssh_channel:cache_lookup(Cache, ChannelId),
+ ssh_client_channel:cache_lookup(Cache, ChannelId),
- ssh_channel:cache_update(Cache, Channel#channel{
+ ssh_client_channel:cache_update(Cache, Channel#channel{
remote_id = RemoteId,
recv_packet_size = max(32768, % rfc4254/5.2
min(PacketSz, Channel#channel.recv_packet_size)
),
send_window_size = WindowSz,
send_packet_size = PacketSz}),
- {Reply, Connection} = reply_msg(Channel, Connection0, {open, ChannelId}),
- {{replies, [Reply]}, Connection};
+ reply_msg(Channel, Connection0, {open, ChannelId});
handle_msg(#ssh_msg_channel_open_failure{recipient_channel = ChannelId,
reason = Reason,
description = Descr,
lang = Lang},
#connection{channel_cache = Cache} = Connection0, _) ->
- Channel = ssh_channel:cache_lookup(Cache, ChannelId),
- ssh_channel:cache_delete(Cache, ChannelId),
- {Reply, Connection} =
- reply_msg(Channel, Connection0, {open_error, Reason, Descr, Lang}),
- {{replies, [Reply]}, Connection};
+ Channel = ssh_client_channel:cache_lookup(Cache, ChannelId),
+ ssh_client_channel:cache_delete(Cache, ChannelId),
+ reply_msg(Channel, Connection0, {open_error, Reason, Descr, Lang});
-handle_msg(#ssh_msg_channel_success{recipient_channel = ChannelId},
- #connection{channel_cache = Cache} = Connection0, _) ->
- Channel = ssh_channel:cache_lookup(Cache, ChannelId),
- case reply_msg(Channel, Connection0, success) of
- {[], Connection} ->
- {noreply, Connection};
- {Reply, Connection} ->
- {{replies, [Reply]}, Connection}
- end;
+handle_msg(#ssh_msg_channel_success{recipient_channel = ChannelId}, Connection, _) ->
+ reply_msg(ChannelId, Connection, success);
-handle_msg(#ssh_msg_channel_failure{recipient_channel = ChannelId},
- #connection{channel_cache = Cache} = Connection0, _) ->
- Channel = ssh_channel:cache_lookup(Cache, ChannelId),
- case reply_msg(Channel, Connection0, failure) of
- {[], Connection} ->
- {noreply, Connection};
- {Reply, Connection} ->
- {{replies, [Reply]}, Connection}
- end;
+handle_msg(#ssh_msg_channel_failure{recipient_channel = ChannelId}, Connection, _) ->
+ reply_msg(ChannelId, Connection, failure);
-
-handle_msg(#ssh_msg_channel_eof{recipient_channel = ChannelId},
- #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_eof{recipient_channel = ChannelId}, Connection, _) ->
+ reply_msg(ChannelId, Connection, {eof, ChannelId});
handle_msg(#ssh_msg_channel_close{recipient_channel = ChannelId},
#connection{channel_cache = Cache} = Connection0, _) ->
- case ssh_channel:cache_lookup(Cache, ChannelId) of
+ case ssh_client_channel:cache_lookup(Cache, ChannelId) of
#channel{sent_close = Closed, remote_id = RemoteId,
flow_control = FlowControl} = Channel ->
- ssh_channel:cache_delete(Cache, ChannelId),
+ ssh_client_channel:cache_delete(Cache, ChannelId),
{CloseMsg, Connection} =
reply_msg(Channel, Connection0, {closed, ChannelId}),
ConnReplyMsgs =
@@ -358,48 +357,29 @@ handle_msg(#ssh_msg_channel_close{recipient_channel = ChannelId},
[{flow_control, From, {error, closed}}]
end,
- Replies = ConnReplyMsgs ++ [CloseMsg] ++ SendReplyMsgs,
- {{replies, Replies}, Connection};
+ Replies = ConnReplyMsgs ++ CloseMsg ++ SendReplyMsgs,
+ {Replies, Connection};
undefined ->
- {{replies, []}, Connection0}
+ {[], Connection0}
end;
handle_msg(#ssh_msg_channel_data{recipient_channel = ChannelId,
data = Data},
- #connection{channel_cache = Cache} = Connection0, _) ->
-
- 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;
+ Connection, _) ->
+ channel_data_reply_msg(ChannelId, Connection, 0, Data);
handle_msg(#ssh_msg_channel_extended_data{recipient_channel = ChannelId,
data_type_code = DataType,
data = Data},
- #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, DataType, Data),
- {{replies, Replies}, Connection};
+ Connection, _) ->
+ channel_data_reply_msg(ChannelId, Connection, DataType, Data);
handle_msg(#ssh_msg_channel_window_adjust{recipient_channel = ChannelId,
bytes_to_add = Add},
#connection{channel_cache = Cache} = Connection, _) ->
#channel{send_window_size = Size, remote_id = RemoteId} =
- Channel0 = ssh_channel:cache_lookup(Cache, ChannelId),
+ Channel0 = ssh_client_channel:cache_lookup(Cache, ChannelId),
{SendList, Channel} = %% TODO: Datatype 0 ?
update_send_window(Channel0#channel{send_window_size = Size + Add},
@@ -409,7 +389,7 @@ handle_msg(#ssh_msg_channel_window_adjust{recipient_channel = ChannelId,
{connection_reply, channel_data_msg(RemoteId, Type, Data)}
end, SendList),
FlowCtrlMsgs = flow_control(Channel, Cache),
- {{replies, Replies ++ FlowCtrlMsgs}, Connection};
+ {Replies ++ FlowCtrlMsgs, Connection};
handle_msg(#ssh_msg_channel_open{channel_type = "session" = Type,
sender_channel = RemoteId,
@@ -430,8 +410,7 @@ 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, FailMsg}]},
- Connection0}
+ {[{connection_reply, FailMsg}], Connection0}
end;
MinAcceptedPackSz > PacketSz ->
@@ -439,7 +418,7 @@ handle_msg(#ssh_msg_channel_open{channel_type = "session" = Type,
?SSH_OPEN_ADMINISTRATIVELY_PROHIBITED,
lists:concat(["Maximum packet size below ",MinAcceptedPackSz,
" not supported"]), "en"),
- {{replies, [{connection_reply, FailMsg}]}, Connection0}
+ {[{connection_reply, FailMsg}], Connection0}
end;
handle_msg(#ssh_msg_channel_open{channel_type = "session",
@@ -452,35 +431,31 @@ handle_msg(#ssh_msg_channel_open{channel_type = "session",
FailMsg = channel_open_failure_msg(RemoteId,
?SSH_OPEN_CONNECT_FAILED,
"Connection refused", "en"),
- {{replies, [{connection_reply, FailMsg}]},
- Connection};
+ {[{connection_reply, FailMsg}], Connection};
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, FailMsg}]}, Connection};
+ {[{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, _) ->
<<?UINT32(Status)>> = Data,
- Channel = ssh_channel:cache_lookup(Cache, ChannelId),
- {Reply, Connection} =
- reply_msg(Channel, Connection, {exit_status, ChannelId, Status}),
- {{replies, [Reply]}, Connection};
+ reply_msg(ChannelId, Connection, {exit_status, ChannelId, Status});
handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
request_type = "exit-signal",
want_reply = false,
data = Data},
- #connection{channel_cache = Cache} = Connection0, _) ->
- <<?UINT32(SigLen), SigName:SigLen/binary,
- ?BOOLEAN(_Core),
- ?UINT32(ErrLen), Err:ErrLen/binary,
- ?UINT32(LangLen), Lang:LangLen/binary>> = Data,
- Channel = ssh_channel:cache_lookup(Cache, ChannelId),
+ #connection{channel_cache = Cache} = Connection0, _) ->
+ <<?DEC_BIN(SigName, _SigLen),
+ ?BOOLEAN(_Core),
+ ?DEC_BIN(Err, _ErrLen),
+ ?DEC_BIN(Lang, _LangLen)>> = Data,
+ Channel = ssh_client_channel:cache_lookup(Cache, ChannelId),
RemoteId = Channel#channel.remote_id,
{Reply, Connection} = reply_msg(Channel, Connection0,
{exit_signal, ChannelId,
@@ -488,167 +463,139 @@ 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, CloseMsg}, Reply]},
- Connection};
+ {[{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, _) ->
<<?BOOLEAN(CDo)>> = Data,
- Channel = ssh_channel:cache_lookup(Cache, ChannelId),
- {Reply, Connection} =
- reply_msg(Channel, Connection, {xon_xoff, ChannelId, CDo=/= 0}),
- {{replies, [Reply]}, Connection};
+ reply_msg(ChannelId, Connection, {xon_xoff, ChannelId, CDo=/= 0});
handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
request_type = "window-change",
want_reply = false,
data = Data},
- #connection{channel_cache = Cache} = Connection0, _) ->
+ Connection0, _) ->
<<?UINT32(Width),?UINT32(Height),
- ?UINT32(PixWidth), ?UINT32(PixHeight)>> = Data,
- Channel = ssh_channel:cache_lookup(Cache, ChannelId),
- {Reply, Connection} =
- reply_msg(Channel, Connection0, {window_change, ChannelId,
- Width, Height,
- PixWidth, PixHeight}),
- {{replies, [Reply]}, Connection};
+ ?UINT32(PixWidth), ?UINT32(PixHeight)>> = Data,
+ reply_msg(ChannelId, Connection0, {window_change, ChannelId,
+ Width, Height,
+ PixWidth, PixHeight});
handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
request_type = "signal",
data = Data},
- #connection{channel_cache = Cache} = Connection0, _) ->
- <<?UINT32(SigLen), SigName:SigLen/binary>> = Data,
-
- Channel = ssh_channel:cache_lookup(Cache, ChannelId),
- {Reply, Connection} =
- reply_msg(Channel, Connection0, {signal, ChannelId,
- binary_to_list(SigName)}),
- {{replies, [Reply]}, Connection};
+ Connection0, _) ->
+ <<?DEC_BIN(SigName, _SigLen)>> = Data,
+ reply_msg(ChannelId, Connection0, {signal, ChannelId,
+ binary_to_list(SigName)});
handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
request_type = "subsystem",
want_reply = WantReply,
data = Data},
#connection{channel_cache = Cache} = Connection, server) ->
- <<?UINT32(SsLen), SsName:SsLen/binary>> = Data,
-
- #channel{remote_id = RemoteId} = Channel0 =
- ssh_channel:cache_lookup(Cache, ChannelId),
-
- ReplyMsg = {subsystem, ChannelId, WantReply, binary_to_list(SsName)},
-
- try
- {ok, Pid} = start_subsystem(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;
+ <<?DEC_BIN(SsName,_SsLen)>> = Data,
+ #channel{remote_id=RemoteId} = Channel =
+ ssh_client_channel:cache_lookup(Cache, ChannelId),
+ Reply =
+ try
+ start_subsystem(SsName, Connection, Channel,
+ {subsystem, ChannelId, WantReply, binary_to_list(SsName)})
+ of
+ {ok, Pid} ->
+ erlang:monitor(process, Pid),
+ ssh_client_channel:cache_update(Cache, Channel#channel{user=Pid}),
+ channel_success_msg(RemoteId);
+ {error,_Error} ->
+ channel_failure_msg(RemoteId)
+ catch
+ _:_ ->
+ channel_failure_msg(RemoteId)
+ end,
+ {[{connection_reply,Reply}], Connection};
handle_msg(#ssh_msg_channel_request{request_type = "subsystem"},
Connection, client) ->
%% The client SHOULD ignore subsystem requests. See RFC 4254 6.5.
- {{replies, []}, Connection};
+ {[], Connection};
handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
request_type = "pty-req",
want_reply = WantReply,
data = Data},
- #connection{channel_cache = Cache} = Connection, server) ->
- <<?UINT32(TermLen), BTermName:TermLen/binary,
- ?UINT32(Width),?UINT32(Height),
- ?UINT32(PixWidth), ?UINT32(PixHeight),
- Modes/binary>> = Data,
+ Connection, server) ->
+ <<?DEC_BIN(BTermName,_TermLen),
+ ?UINT32(Width),?UINT32(Height),
+ ?UINT32(PixWidth), ?UINT32(PixHeight),
+ Modes/binary>> = Data,
TermName = binary_to_list(BTermName),
-
PtyRequest = {TermName, Width, Height,
PixWidth, PixHeight, decode_pty_opts(Modes)},
-
- Channel = ssh_channel:cache_lookup(Cache, ChannelId),
- handle_cli_msg(Connection, Channel,
+ handle_cli_msg(Connection, ChannelId,
{pty, ChannelId, WantReply, PtyRequest});
handle_msg(#ssh_msg_channel_request{request_type = "pty-req"},
Connection, client) ->
%% The client SHOULD ignore pty requests. See RFC 4254 6.2.
- {{replies, []}, Connection};
+ {[], Connection};
handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
request_type = "shell",
want_reply = WantReply},
- #connection{channel_cache = Cache} = Connection, server) ->
-
- Channel = ssh_channel:cache_lookup(Cache, ChannelId),
-
- handle_cli_msg(Connection, Channel,
+ Connection, server) ->
+ handle_cli_msg(Connection, ChannelId,
{shell, ChannelId, WantReply});
handle_msg(#ssh_msg_channel_request{request_type = "shell"},
Connection, client) ->
%% The client SHOULD ignore shell requests. See RFC 4254 6.5.
- {{replies, []}, Connection};
+ {[], Connection};
handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
request_type = "exec",
want_reply = WantReply,
data = Data},
- #connection{channel_cache = Cache} = Connection, server) ->
- <<?UINT32(Len), Command:Len/binary>> = Data,
-
- Channel = ssh_channel:cache_lookup(Cache, ChannelId),
-
- handle_cli_msg(Connection, Channel,
+ Connection, server) ->
+ <<?DEC_BIN(Command, _Len)>> = Data,
+ handle_cli_msg(Connection, ChannelId,
{exec, ChannelId, WantReply, binary_to_list(Command)});
handle_msg(#ssh_msg_channel_request{request_type = "exec"},
Connection, client) ->
%% The client SHOULD ignore exec requests. See RFC 4254 6.5.
- {{replies, []}, Connection};
+ {[], Connection};
handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
request_type = "env",
want_reply = WantReply,
data = Data},
- #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, Channel,
+ Connection, server) ->
+ <<?DEC_BIN(Var,_VarLen), ?DEC_BIN(Value,_ValLen)>> = Data,
+ handle_cli_msg(Connection, ChannelId,
{env, ChannelId, WantReply, Var, Value});
handle_msg(#ssh_msg_channel_request{request_type = "env"},
Connection, client) ->
%% The client SHOULD ignore env requests.
- {{replies, []}, Connection};
+ {[], Connection};
handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
request_type = _Other,
want_reply = WantReply},
#connection{channel_cache = Cache} = Connection, _) ->
if WantReply == true ->
- case ssh_channel:cache_lookup(Cache, ChannelId) of
+ case ssh_client_channel:cache_lookup(Cache, ChannelId) of
#channel{remote_id = RemoteId} ->
FailMsg = channel_failure_msg(RemoteId),
- {{replies, [{connection_reply, FailMsg}]},
- Connection};
+ {[{connection_reply, FailMsg}], Connection};
undefined -> %% Chanel has been closed
- {noreply, Connection}
+ {[], Connection}
end;
true ->
- {noreply, Connection}
+ {[], Connection}
end;
handle_msg(#ssh_msg_global_request{name = _Type,
@@ -656,79 +603,54 @@ handle_msg(#ssh_msg_global_request{name = _Type,
data = _Data}, Connection, _) ->
if WantReply == true ->
FailMsg = request_failure_msg(),
- {{replies, [{connection_reply, FailMsg}]},
- Connection};
+ {[{connection_reply, FailMsg}], Connection};
true ->
- {noreply, Connection}
+ {[], Connection}
end;
handle_msg(#ssh_msg_request_failure{},
#connection{requests = [{_, From} | Rest]} = Connection, _) ->
- {{replies, [{channel_request_reply, From, {failure, <<>>}}]},
+ {[{channel_request_reply, From, {failure, <<>>}}],
Connection#connection{requests = Rest}};
+
handle_msg(#ssh_msg_request_success{data = Data},
#connection{requests = [{_, From} | Rest]} = Connection, _) ->
- {{replies, [{channel_request_reply, From, {success, Data}}]},
+ {[{channel_request_reply, From, {success, Data}}],
Connection#connection{requests = Rest}};
handle_msg(#ssh_msg_disconnect{code = Code,
- description = Description,
- language = _Lang },
- #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}),
- {Connection2, [Reply | Acc]}
- end, {Connection0, []}, Cache),
-
- ssh_channel:cache_delete(Cache),
- {disconnect, {Code, Description}, {{replies, Replies}, Connection}}.
-
-handle_cli_msg(#connection{channel_cache = Cache} = Connection,
- #channel{user = undefined,
- remote_id = RemoteId,
- local_id = ChannelId} = Channel0, Reply0) ->
- 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, Connection1} = reply_msg(Channel, Connection, Reply0),
- {{replies, [Reply]}, Connection1};
- _Other ->
- Reply = {connection_reply,
- channel_failure_msg(RemoteId)},
- {{replies, [Reply]}, Connection}
- end;
-
-handle_cli_msg(Connection0, Channel, Reply0) ->
- {Reply, Connection} = reply_msg(Channel, Connection0, Reply0),
- {{replies, [Reply]}, Connection}.
+ description = Description},
+ Connection, _) ->
+ {disconnect, {Code, Description}, handle_stop(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}.
-
-channel_failure_msg(ChannelId) ->
- #ssh_msg_channel_failure{recipient_channel = ChannelId}.
+%%%----------------------------------------------------------------
+%%% Returns pending responses to be delivered to the peer when a
+%%% Channel/Connection closes
+%%%
+handle_stop(#connection{channel_cache = Cache} = Connection0) ->
+ {Connection, Replies} =
+ ssh_client_channel:cache_foldl(
+ fun(Channel, {Connection1, Acc}) ->
+ {Reply, Connection2} =
+ reply_msg(Channel, Connection1,
+ {closed, Channel#channel.local_id}),
+ {Connection2, Reply ++ Acc}
+ end, {Connection0, []}, Cache),
+ ssh_client_channel:cache_delete(Cache),
+ {Replies, Connection}.
+
+%%%----------------------------------------------------------------
+%%% channel_*_msg(...)
+%%% Returns a #ssh_msg_....{} for channel operations.
+%%%
channel_adjust_window_msg(ChannelId, Bytes) ->
#ssh_msg_channel_window_adjust{recipient_channel = ChannelId,
bytes_to_add = Bytes}.
+channel_close_msg(ChannelId) ->
+ #ssh_msg_channel_close {recipient_channel = ChannelId}.
+
channel_data_msg(ChannelId, 0, Data) ->
#ssh_msg_channel_data{recipient_channel = ChannelId,
data = Data};
@@ -737,6 +659,12 @@ channel_data_msg(ChannelId, Type, Data) ->
data_type_code = Type,
data = Data}.
+channel_eof_msg(ChannelId) ->
+ #ssh_msg_channel_eof{recipient_channel = ChannelId}.
+
+channel_failure_msg(ChannelId) ->
+ #ssh_msg_channel_failure{recipient_channel = ChannelId}.
+
channel_open_msg(Type, ChannelId, WindowSize, MaxPacketSize, Data) ->
#ssh_msg_channel_open{channel_type = Type,
sender_channel = ChannelId,
@@ -757,18 +685,34 @@ channel_open_failure_msg(RemoteId, Reason, Description, Lang) ->
description = Description,
lang = Lang}.
+channel_status_msg({success, ChannelId}) ->
+ channel_success_msg(ChannelId);
+
+channel_status_msg({failure, ChannelId}) ->
+ channel_failure_msg(ChannelId).
+
channel_request_msg(ChannelId, Type, WantReply, Data) ->
#ssh_msg_channel_request{recipient_channel = ChannelId,
request_type = Type,
want_reply = WantReply,
data = Data}.
+channel_success_msg(ChannelId) ->
+ #ssh_msg_channel_success{recipient_channel = ChannelId}.
+
+%%%----------------------------------------------------------------
+%%% request_*_msg(...)
+%%% Returns a #ssh_msg_....{} for request responses.
+%%%
request_failure_msg() ->
#ssh_msg_request_failure{}.
request_success_msg(Data) ->
#ssh_msg_request_success{data = Data}.
+%%%----------------------------------------------------------------
+%%%
+%%%
bind(IP, Port, ChannelPid, Connection) ->
Binds = [{{IP, Port}, ChannelPid}
| lists:keydelete({IP, Port}, 1,
@@ -808,6 +752,68 @@ encode_ip(Addr) when is_list(Addr) ->
end
end.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%
+%%% Internal functions
+%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%----------------------------------------------------------------
+%%% Create the channel data when an ssh_msg_open_channel message
+%%% of "session" typ is handled
+%%%
+setup_session(#connection{channel_cache = Cache,
+ channel_id_seed = NewChannelID
+ } = C,
+ RemoteId, Type, WindowSize, PacketSize) ->
+ NextChannelID = NewChannelID + 1,
+ Channel =
+ #channel{type = Type,
+ sys = "ssh",
+ local_id = NewChannelID,
+ recv_window_size = ?DEFAULT_WINDOW_SIZE,
+ recv_packet_size = ?DEFAULT_PACKET_SIZE,
+ send_window_size = WindowSize,
+ send_packet_size = PacketSize,
+ send_buf = queue:new(),
+ remote_id = RemoteId
+ },
+ ssh_client_channel:cache_update(Cache, Channel),
+ OpenConfMsg = channel_open_confirmation_msg(RemoteId, NewChannelID,
+ ?DEFAULT_WINDOW_SIZE,
+ ?DEFAULT_PACKET_SIZE),
+ Reply = {connection_reply, OpenConfMsg},
+ {[Reply], C#connection{channel_id_seed = NextChannelID}}.
+
+
+%%%----------------------------------------------------------------
+%%% Start a cli or subsystem
+%%%
+start_cli(#connection{options = Options,
+ cli_spec = CliSpec,
+ exec = Exec,
+ sub_system_supervisor = SubSysSup}, ChannelId) ->
+ case CliSpec of
+ no_cli ->
+ {error, cli_disabled};
+ {CbModule, Args} ->
+ start_channel(CbModule, ChannelId, Args, SubSysSup, Exec, Options)
+ end.
+
+
+start_subsystem(BinName, #connection{options = Options,
+ sub_system_supervisor = SubSysSup},
+ #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, Options);
+ {Other, _} when Other =/= none ->
+ {error, legacy_option_not_supported}
+ end.
+
+
+%%% Helpers for starting cli/subsystems
start_channel(Cb, Id, Args, SubSysSup, Opts) ->
start_channel(Cb, Id, Args, SubSysSup, undefined, Opts).
@@ -815,45 +821,23 @@ start_channel(Cb, Id, Args, SubSysSup, Exec, Opts) ->
ChannelSup = ssh_subsystem_sup:channel_supervisor(SubSysSup),
case max_num_channels_not_exceeded(ChannelSup, Opts) of
true ->
- ssh_channel_sup:start_child(ChannelSup, Cb, Id, Args, Exec);
+ case ssh_server_channel_sup:start_child(ChannelSup, Cb, Id, Args, Exec) of
+ {error,{Error,_Info}} ->
+ throw(Error);
+ Others ->
+ Others
+ end;
false ->
throw(max_num_channels_exceeded)
end.
max_num_channels_not_exceeded(ChannelSup, Opts) ->
MaxNumChannels = ?GET_OPT(max_channels, Opts),
- NumChannels = length([x || {_,_,worker,[ssh_channel]} <-
+ NumChannels = length([x || {_,_,worker,[ssh_server_channel]} <-
supervisor:which_children(ChannelSup)]),
%% Note that NumChannels is BEFORE starting a new one
NumChannels < MaxNumChannels.
-%%--------------------------------------------------------------------
-%%% Internal functions
-%%--------------------------------------------------------------------
-setup_session(#connection{channel_cache = Cache
- } = Connection0,
- RemoteId,
- Type, WindowSize, PacketSize) ->
- {ChannelId, Connection} = new_channel_id(Connection0),
-
- Channel = #channel{type = Type,
- sys = "ssh",
- local_id = ChannelId,
- recv_window_size = ?DEFAULT_WINDOW_SIZE,
- recv_packet_size = ?DEFAULT_PACKET_SIZE,
- send_window_size = WindowSize,
- send_packet_size = PacketSize,
- send_buf = queue:new(),
- remote_id = RemoteId
- },
- ssh_channel:cache_update(Cache, Channel),
- OpenConfMsg = channel_open_confirmation_msg(RemoteId, ChannelId,
- ?DEFAULT_WINDOW_SIZE,
- ?DEFAULT_PACKET_SIZE),
-
- {{replies, [{connection_reply, OpenConfMsg}]}, Connection}.
-
-
check_subsystem("sftp"= SsName, Options) ->
case ?GET_OPT(subsystems, Options) of
no_subsys -> % FIXME: Can 'no_subsys' ever be matched?
@@ -872,64 +856,10 @@ check_subsystem(SsName, Options) ->
Value
end.
-start_cli(#connection{cli_spec = no_cli}, _) ->
- {error, cli_disabled};
-start_cli(#connection{options = Options,
- cli_spec = {CbModule, Args},
- exec = Exec,
- sub_system_supervisor = SubSysSup}, ChannelId) ->
- start_channel(CbModule, ChannelId, Args, SubSysSup, Exec, Options).
-
-start_subsystem(BinName, #connection{options = Options,
- sub_system_supervisor = SubSysSup},
- #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, Options);
- {Other, _} when Other =/= none ->
- {error, legacy_option_not_supported}
- end.
-
-channel_data_reply(_, #channel{local_id = ChannelId} = Channel,
- Connection0, DataType, Data) ->
- {Reply, Connection} =
- reply_msg(Channel, Connection0, {data, ChannelId, DataType, Data}),
- {[Reply], Connection}.
-
-new_channel_id(Connection) ->
- ID = Connection#connection.channel_id_seed,
- {ID, Connection#connection{channel_id_seed = ID + 1}}.
-
-reply_msg(Channel, Connection, {open, _} = Reply) ->
- request_reply_or_data(Channel, Connection, Reply);
-reply_msg(Channel, Connection, {open_error, _, _, _} = Reply) ->
- request_reply_or_data(Channel, Connection, Reply);
-reply_msg(Channel, Connection, success = Reply) ->
- request_reply_or_data(Channel, Connection, Reply);
-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) ->
- case lists:keysearch(ChannelId, 1, Requests) of
- {value, {ChannelId, From}} ->
- {{channel_request_reply, From, Reply},
- Connection#connection{requests =
- lists:keydelete(ChannelId, 1, Requests)}};
- false when (Reply == success) or (Reply == failure) ->
- {[], Connection};
- false ->
- {{channel_data, ChannelPid, Reply}, Connection}
- end.
+%%%----------------------------------------------------------------
+%%%
+%%% Send-window handling
+%%%
update_send_window(Channel, _, undefined,
#connection{channel_cache = Cache}) ->
@@ -942,7 +872,7 @@ update_send_window(#channel{send_buf = SendBuffer} = Channel, DataType, Data,
do_update_send_window(Channel0, Cache) ->
{SendMsgs, Channel} = get_window(Channel0, []),
- ssh_channel:cache_update(Cache, Channel),
+ ssh_client_channel:cache_update(Cache, Channel),
{SendMsgs, Channel}.
get_window(#channel{send_window_size = 0
@@ -984,17 +914,22 @@ handle_send_window({Type, Data}, _, PacketSize, WindowSize, Acc) ->
<<Msg1:PacketSize/binary, Msg2/binary>> = Data,
{WindowSize - PacketSize, [{Type, Msg1} | Acc], {Type, Msg2}}.
+%%%----------------------------------------------------------------
+%%%
+%%% Flow control
+%%%
+
flow_control(Channel, Cache) ->
flow_control([window_adjusted], Channel, Cache).
flow_control([], Channel, Cache) ->
- ssh_channel:cache_update(Cache, Channel),
+ ssh_client_channel:cache_update(Cache, Channel),
[];
flow_control([_|_], #channel{flow_control = From,
send_buf = Buffer} = Channel, Cache) when From =/= undefined ->
case queue:is_empty(Buffer) of
true ->
- ssh_channel:cache_update(Cache, Channel#channel{flow_control = undefined}),
+ ssh_client_channel:cache_update(Cache, Channel#channel{flow_control = undefined}),
[{flow_control, Cache, Channel, From, ok}];
false ->
[]
@@ -1002,6 +937,11 @@ flow_control([_|_], #channel{flow_control = From,
flow_control(_,_,_) ->
[].
+%%%----------------------------------------------------------------
+%%%
+%%% Pseudo terminal stuff
+%%%
+
pty_req(ConnectionHandler, Channel, Term, Width, Height,
PixWidth, PixHeight, PtyOpts, TimeOut) ->
ssh_connection_handler:request(ConnectionHandler,
@@ -1027,8 +967,7 @@ pty_default_dimensions(Dimension, TermData) ->
encode_pty_opts(Opts) ->
Bin = list_to_binary(encode_pty_opts2(Opts)),
- Len = size(Bin),
- <<?UINT32(Len), Bin/binary>>.
+ <<?STRING(Bin)>>.
encode_pty_opts2([]) ->
[?TTY_OP_END];
@@ -1147,7 +1086,7 @@ decode_pty_opts(<<>>) ->
[];
decode_pty_opts(<<0, 0, 0, 0>>) ->
[];
-decode_pty_opts(<<?UINT32(Len), Modes:Len/binary>>) ->
+decode_pty_opts(<<?DEC_BIN(Modes,_Len)>>) ->
decode_pty_opts2(Modes);
decode_pty_opts(Binary) ->
decode_pty_opts2(Binary).
@@ -1224,3 +1163,104 @@ backwards_compatible([{pixel_hight, Value} | Rest], Acc) ->
backwards_compatible(Rest, [{height, Value} | Acc]);
backwards_compatible([Value| Rest], Acc) ->
backwards_compatible(Rest, [ Value | Acc]).
+
+
+%%%----------------------------------------------------------------
+%%%
+%%% Common part of handling channel messages meant for a cli (like "env", "exec" etc)
+%%% Called at the finnish of handle_msg(#ssh_msg_channel_request,...)
+%%%
+
+handle_cli_msg(C0, ChId, Reply0) ->
+ Cache = C0#connection.channel_cache,
+ Ch0 = ssh_client_channel:cache_lookup(Cache, ChId),
+ case Ch0#channel.user of
+ undefined ->
+ case (catch start_cli(C0, ChId)) of
+ {ok, Pid} ->
+ erlang:monitor(process, Pid),
+ Ch = Ch0#channel{user = Pid},
+ ssh_client_channel:cache_update(Cache, Ch),
+ reply_msg(Ch, C0, Reply0);
+ _Other ->
+ Reply = {connection_reply, channel_failure_msg(Ch0#channel.remote_id)},
+ {[Reply], C0}
+ end;
+
+ _ ->
+ reply_msg(Ch0, C0, Reply0)
+ end.
+
+%%%----------------------------------------------------------------
+%%%
+%%% Request response handling on return to the calling ssh_connection_handler
+%%% state machine.
+%%%
+
+channel_data_reply_msg(ChannelId, Connection, DataType, Data) ->
+ case ssh_client_channel:cache_lookup(Connection#connection.channel_cache, ChannelId) of
+ #channel{recv_window_size = Size} = Channel ->
+ WantedSize = Size - size(Data),
+ ssh_client_channel:cache_update(Connection#connection.channel_cache,
+ Channel#channel{recv_window_size = WantedSize}),
+ reply_msg(Channel, Connection, {data, ChannelId, DataType, Data});
+ undefined ->
+ {[], Connection}
+ end.
+
+
+reply_msg(ChId, C, Reply) when is_integer(ChId) ->
+ reply_msg(ssh_client_channel:cache_lookup(C#connection.channel_cache, ChId), C, Reply);
+
+reply_msg(Channel, Connection, {open, _} = Reply) ->
+ request_reply_or_data(Channel, Connection, Reply);
+reply_msg(Channel, Connection, {open_error, _, _, _} = Reply) ->
+ request_reply_or_data(Channel, Connection, Reply);
+reply_msg(Channel, Connection, success = Reply) ->
+ request_reply_or_data(Channel, Connection, Reply);
+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) ->
+ {[], 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) ->
+ case lists:keysearch(ChannelId, 1, Requests) of
+ {value, {ChannelId, From}} ->
+ {[{channel_request_reply, From, Reply}],
+ Connection#connection{requests =
+ lists:keydelete(ChannelId, 1, Requests)}};
+ false when (Reply == success) or (Reply == failure) ->
+ {[], Connection};
+ false ->
+ {[{channel_data, ChannelPid, Reply}], Connection}
+ end.
+
+
+
+%%%----------------------------------------------------------------
+%%% l(ist)2b(inary)
+%%%
+l2b(L) when is_integer(hd(L)) ->
+ try list_to_binary(L)
+ of
+ B -> B
+ catch
+ _:_ ->
+ unicode:characters_to_binary(L)
+ end;
+l2b([H|T]) ->
+ << (l2b(H))/binary, (l2b(T))/binary >>;
+l2b(B) when is_binary(B) ->
+ B;
+l2b([]) ->
+ <<>>.
+
+
+
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index e11d3adee4..8f32966a12 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -56,10 +56,13 @@
connection_info/2,
channel_info/3,
adjust_window/3, close/2,
- disconnect/1, disconnect/2,
+ disconnect/4,
get_print_info/1
]).
+-type connection_ref() :: ssh:connection_ref().
+-type channel_id() :: ssh:channel_id().
+
%%% Behaviour callbacks
-export([init/1, callback_mode/0, handle_event/4, terminate/3,
format_status/2, code_change/4]).
@@ -68,16 +71,28 @@
-export([init_connection_handler/3, % proc_lib:spawn needs this
init_ssh_record/3, % Export of this internal function
% intended for low-level protocol test suites
- renegotiate/1, renegotiate_data/1 % Export intended for test cases
+ renegotiate/1, alg/1 % Export intended for test cases
]).
+-export([dbg_trace/3]).
+
+
+-define(send_disconnect(Code, DetailedText, StateName, State),
+ send_disconnect(Code, DetailedText, ?MODULE, ?LINE, StateName, State)).
+
+-define(send_disconnect(Code, Reason, DetailedText, StateName, State),
+ send_disconnect(Code, Reason, DetailedText, ?MODULE, ?LINE, StateName, State)).
+
+-define(call_disconnectfun_and_log_cond(LogMsg, DetailedText, StateName, D),
+ call_disconnectfun_and_log_cond(LogMsg, DetailedText, ?MODULE, ?LINE, StateName, D)).
+
%%====================================================================
%% Start / stop
%%====================================================================
%%--------------------------------------------------------------------
-spec start_link(role(),
- inet:socket(),
- ssh_options:options()
+ gen_tcp:socket(),
+ internal_options()
) -> {ok, pid()}.
%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
start_link(Role, Socket, Options) ->
@@ -106,8 +121,8 @@ stop(ConnectionHandler)->
%%--------------------------------------------------------------------
-spec start_connection(role(),
- inet:socket(),
- ssh_options:options(),
+ gen_tcp:socket(),
+ internal_options(),
timeout()
) -> {ok, connection_ref()} | {error, term()}.
%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
@@ -149,17 +164,16 @@ start_connection(server = Role, Socket, Options, Timeout) ->
%%--------------------------------------------------------------------
%%% Some other module has decided to disconnect.
--spec disconnect(#ssh_msg_disconnect{}) -> no_return().
--spec disconnect(#ssh_msg_disconnect{}, iodata()) -> no_return().
+
+-spec disconnect(Code::integer(), Details::iodata(),
+ Module::atom(), Line::integer()) -> no_return().
%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-disconnect(Msg = #ssh_msg_disconnect{}) ->
- throw({keep_state_and_data,
- [{next_event, internal, {disconnect, Msg, Msg#ssh_msg_disconnect.description}}]}).
-disconnect(Msg = #ssh_msg_disconnect{}, ExtraInfo) ->
- throw({keep_state_and_data,
- [{next_event, internal, {disconnect, Msg, {Msg#ssh_msg_disconnect.description,ExtraInfo}}}]}).
+% Preferable called with the macro ?DISCONNECT
+disconnect(Code, DetailedText, Module, Line) ->
+ throw({keep_state_and_data,
+ [{next_event, internal, {send_disconnect, Code, DetailedText, Module, Line}}]}).
%%--------------------------------------------------------------------
-spec open_channel(connection_ref(),
@@ -311,15 +325,11 @@ close(ConnectionHandler, ChannelId) ->
) -> ok.
%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
renegotiate(ConnectionHandler) ->
- cast(ConnectionHandler, renegotiate).
+ cast(ConnectionHandler, force_renegotiate).
%%--------------------------------------------------------------------
--spec renegotiate_data(connection_ref()
- ) -> ok.
-%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-renegotiate_data(ConnectionHandler) ->
- cast(ConnectionHandler, data_size).
-
+alg(ConnectionHandler) ->
+ call(ConnectionHandler, get_alg).
%%====================================================================
%% Internal process state
@@ -332,11 +342,6 @@ renegotiate_data(ConnectionHandler) ->
connection_state :: #connection{},
latest_channel_id = 0 :: non_neg_integer()
| undefined,
- idle_timer_ref :: undefined
- | infinity
- | reference(),
- idle_timer_value = infinity :: infinity
- | pos_integer(),
transport_protocol :: atom()
| undefined, % ex: tcp
transport_cb :: atom()
@@ -345,18 +350,19 @@ renegotiate_data(ConnectionHandler) ->
| undefined, % ex: tcp_closed
ssh_params :: #ssh{}
| undefined,
- socket :: inet:socket()
+ socket :: gen_tcp:socket()
| undefined,
decrypted_data_buffer = <<>> :: binary()
| undefined,
encrypted_data_buffer = <<>> :: binary()
| undefined,
+ aead_data = <<>> :: binary()
+ | undefined,
undecrypted_packet_length :: undefined | non_neg_integer(),
key_exchange_init_msg :: #ssh_msg_kexinit{}
| undefined,
last_size_rekey = 0 :: non_neg_integer(),
event_queue = [] :: list(),
-% opts :: ssh_options:options(),
inet_initial_recbuf_size :: pos_integer()
| undefined
}).
@@ -366,8 +372,8 @@ renegotiate_data(ConnectionHandler) ->
%%====================================================================
%%--------------------------------------------------------------------
-spec init_connection_handler(role(),
- inet:socket(),
- ssh_options:options()
+ gen_tcp:socket(),
+ internal_options()
) -> no_return().
%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
init_connection_handler(Role, Socket, Opts) ->
@@ -398,7 +404,7 @@ init([Role,Socket,Opts]) ->
case inet:peername(Socket) of
{ok, PeerAddr} ->
{Protocol, Callback, CloseTag} = ?GET_OPT(transport, Opts),
- C = #connection{channel_cache = ssh_channel:cache_create(),
+ C = #connection{channel_cache = ssh_client_channel:cache_create(),
channel_id_seed = 0,
port_bindings = [],
requests = [],
@@ -413,20 +419,16 @@ init([Role,Socket,Opts]) ->
},
D = case Role of
client ->
- %% Start the renegotiation timers
- timer:apply_after(?REKEY_TIMOUT, gen_statem, cast, [self(), renegotiate]),
- timer:apply_after(?REKEY_DATA_TIMOUT, gen_statem, cast, [self(), data_size]),
- cache_init_idle_timer(D0);
+ D0;
server ->
Sups = ?GET_INTERNAL_OPT(supervisors, Opts),
- cache_init_idle_timer(
- D0#data{connection_state =
- C#connection{cli_spec = ?GET_OPT(ssh_cli, Opts, {ssh_cli,[?GET_OPT(shell, Opts)]}),
- exec = ?GET_OPT(exec, Opts),
- system_supervisor = proplists:get_value(system_sup, Sups),
- sub_system_supervisor = proplists:get_value(subsystem_sup, Sups),
- connection_supervisor = proplists:get_value(connection_sup, Sups)
- }})
+ D0#data{connection_state =
+ C#connection{cli_spec = ?GET_OPT(ssh_cli, Opts, {ssh_cli,[?GET_OPT(shell, Opts)]}),
+ exec = ?GET_OPT(exec, Opts),
+ system_supervisor = proplists:get_value(system_sup, Sups),
+ sub_system_supervisor = proplists:get_value(subsystem_sup, Sups),
+ connection_supervisor = proplists:get_value(connection_sup, Sups)
+ }}
end,
{ok, {hello,Role}, D};
@@ -442,10 +444,9 @@ init_ssh_record(Role, Socket, Opts) ->
{ok,PeerAddr} = inet:peername(Socket),
init_ssh_record(Role, Socket, PeerAddr, Opts).
-init_ssh_record(Role, _Socket, PeerAddr, Opts) ->
+init_ssh_record(Role, Socket, PeerAddr, Opts) ->
AuthMethods = ?GET_OPT(auth_methods, Opts),
S0 = #ssh{role = Role,
- key_cb = ?GET_OPT(key_cb, Opts),
opts = Opts,
userauth_supported_methods = AuthMethods,
available_host_keys = available_hkey_algorithms(Role, Opts),
@@ -453,6 +454,10 @@ init_ssh_record(Role, _Socket, PeerAddr, Opts) ->
},
{Vsn, Version} = ssh_transport:versions(Role, Opts),
+ LocalName = case inet:sockname(Socket) of
+ {ok,Local} -> Local;
+ _ -> undefined
+ end,
case Role of
client ->
PeerName = case ?GET_INTERNAL_OPT(host, Opts) of
@@ -466,12 +471,14 @@ init_ssh_record(Role, _Socket, PeerAddr, Opts) ->
S1 =
S0#ssh{c_vsn = Vsn,
c_version = Version,
- io_cb = case ?GET_OPT(user_interaction, Opts) of
- true -> ssh_io;
- false -> ssh_no_io
- end,
+ opts = ?PUT_INTERNAL_OPT({io_cb, case ?GET_OPT(user_interaction, Opts) of
+ true -> ssh_io;
+ false -> ssh_no_io
+ end},
+ Opts),
userauth_quiet_mode = ?GET_OPT(quiet_mode, Opts),
- peer = {PeerName, PeerAddr}
+ peer = {PeerName, PeerAddr},
+ local = LocalName
},
S1#ssh{userauth_pubkeys = [K || K <- ?GET_OPT(pref_public_key_algs, Opts),
is_usable_user_pubkey(K, S1)
@@ -481,10 +488,10 @@ init_ssh_record(Role, _Socket, PeerAddr, Opts) ->
server ->
S0#ssh{s_vsn = Vsn,
s_version = Version,
- io_cb = ?GET_INTERNAL_OPT(io_cb, Opts, ssh_io),
userauth_methods = string:tokens(AuthMethods, ","),
kb_tries_left = 3,
- peer = {undefined, PeerAddr}
+ peer = {undefined, PeerAddr},
+ local = LocalName
}
end.
@@ -522,7 +529,7 @@ role({_,Role}) -> Role;
role({_,Role,_}) -> Role.
-spec renegotiation(state_name()) -> boolean().
-renegotiation({_,_,ReNeg}) -> ReNeg == renegotiation;
+renegotiation({_,_,ReNeg}) -> ReNeg == renegotiate;
renegotiation(_) -> false.
@@ -536,13 +543,18 @@ renegotiation(_) -> false.
#data{}
) -> gen_statem:event_handler_result(state_name()) .
+-define(CONNECTION_MSG(Msg),
+ [{next_event, internal, prepare_next_packet},
+ {next_event,internal,{conn_msg,Msg}}]).
+
%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
callback_mode() ->
- handle_event_function.
+ [handle_event_function,
+ state_enter].
-handle_event(_, _Event, {init_error,Error}, _) ->
+handle_event(_, _Event, {init_error,Error}=StateName, D) ->
case Error of
enotconn ->
%% Handles the abnormal sequence:
@@ -550,6 +562,9 @@ handle_event(_, _Event, {init_error,Error}, _) ->
%% <-SYNACK
%% ACK->
%% RST->
+ ?call_disconnectfun_and_log_cond("Protocol Error",
+ "TCP connenction to server was prematurely closed by the client",
+ StateName, D),
{stop, {shutdown,"TCP connenction to server was prematurely closed by the client"}};
OtherError ->
@@ -558,7 +573,7 @@ handle_event(_, _Event, {init_error,Error}, _) ->
%%% ######## {hello, client|server} ####
%% The very first event that is sent when the we are set as controlling process of Socket
-handle_event(_, socket_control, {hello,_}, D) ->
+handle_event(_, socket_control, {hello,_}=StateName, D) ->
VsnMsg = ssh_transport:hello_version_msg(string_version(D#data.ssh_params)),
send_bytes(VsnMsg, D),
case inet:getopts(Socket=D#data.socket, [recbuf]) of
@@ -573,10 +588,13 @@ handle_event(_, socket_control, {hello,_}, D) ->
{keep_state, D#data{inet_initial_recbuf_size=Size}};
Other ->
+ ?call_disconnectfun_and_log_cond("Option return",
+ io_lib:format("Unexpected getopts return:~n ~p",[Other]),
+ StateName, D),
{stop, {shutdown,{unexpected_getopts_return, Other}}}
end;
-handle_event(_, {info_line,_Line}, {hello,Role}, D) ->
+handle_event(_, {info_line,Line}, {hello,Role}=StateName, D) ->
case Role of
client ->
%% The server may send info lines to the client before the version_exchange
@@ -587,28 +605,33 @@ handle_event(_, {info_line,_Line}, {hello,Role}, D) ->
%% But the client may NOT send them to the server. Openssh answers with cleartext,
%% and so do we
send_bytes("Protocol mismatch.", D),
+ Msg = io_lib:format("Protocol mismatch in version exchange. Client sent info lines.~n~s",
+ [ssh_dbg:hex_dump(Line, 64)]),
+ ?call_disconnectfun_and_log_cond("Protocol mismatch.", Msg, StateName, D),
{stop, {shutdown,"Protocol mismatch in version exchange. Client sent info lines."}}
end;
-handle_event(_, {version_exchange,Version}, {hello,Role}, D) ->
+handle_event(_, {version_exchange,Version}, {hello,Role}, D0) ->
{NumVsn, StrVsn} = ssh_transport:handle_hello_version(Version),
- case handle_version(NumVsn, StrVsn, D#data.ssh_params) of
+ case handle_version(NumVsn, StrVsn, D0#data.ssh_params) of
{ok, Ssh1} ->
%% Since the hello part is finnished correctly, we set the
%% socket to the packet handling mode (including recbuf size):
- inet:setopts(D#data.socket, [{packet,0},
+ inet:setopts(D0#data.socket, [{packet,0},
{mode,binary},
{active, once},
- {recbuf, D#data.inet_initial_recbuf_size}]),
+ {recbuf, D0#data.inet_initial_recbuf_size}]),
{KeyInitMsg, SshPacket, Ssh} = ssh_transport:key_exchange_init_msg(Ssh1),
- send_bytes(SshPacket, D),
- {next_state, {kexinit,Role,init}, D#data{ssh_params = Ssh,
+ send_bytes(SshPacket, D0),
+ {next_state, {kexinit,Role,init}, D0#data{ssh_params = Ssh,
key_exchange_init_msg = KeyInitMsg}};
not_supported ->
- disconnect(
- #ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED,
- description = ["Protocol version ",StrVsn," not supported"]},
- {next_state, {hello,Role}, D})
+ {Shutdown, D} =
+ ?send_disconnect(?SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED,
+ io_lib:format("Offending version is ~p",[string:chomp(Version)]),
+ {hello,Role},
+ D0),
+ {stop, Shutdown, D}
end;
@@ -754,18 +777,20 @@ handle_event(internal, Msg, {ext_info,Role,_ReNegFlag}, D) when is_tuple(Msg) ->
%%% ######## {service_request, client|server} ####
-handle_event(_, Msg = #ssh_msg_service_request{name=ServiceName}, StateName = {service_request,server}, D) ->
+handle_event(_, Msg = #ssh_msg_service_request{name=ServiceName}, StateName = {service_request,server}, D0) ->
case ServiceName of
"ssh-userauth" ->
- Ssh0 = #ssh{session_id=SessionId} = D#data.ssh_params,
+ Ssh0 = #ssh{session_id=SessionId} = D0#data.ssh_params,
{ok, {Reply, Ssh}} = ssh_auth:handle_userauth_request(Msg, SessionId, Ssh0),
- send_bytes(Reply, D),
- {next_state, {userauth,server}, D#data{ssh_params = Ssh}};
+ send_bytes(Reply, D0),
+ {next_state, {userauth,server}, D0#data{ssh_params = Ssh}};
_ ->
- disconnect(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
- description = "Unknown service"},
- StateName, D)
+ {Shutdown, D} =
+ ?send_disconnect(?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
+ io_lib:format("Unknown service: ~p",[ServiceName]),
+ StateName, D0),
+ {stop, Shutdown, D}
end;
handle_event(_, #ssh_msg_service_accept{name = "ssh-userauth"}, {service_request,client},
@@ -781,15 +806,15 @@ handle_event(_, #ssh_msg_service_accept{name = "ssh-userauth"}, {service_request
handle_event(_,
Msg = #ssh_msg_userauth_request{service = ServiceName, method = Method},
StateName = {userauth,server},
- D = #data{ssh_params=Ssh0}) ->
+ D0 = #data{ssh_params=Ssh0}) ->
case {ServiceName, Ssh0#ssh.service, Method} of
{"ssh-connection", "ssh-connection", "none"} ->
%% Probably the very first userauth_request but we deny unauthorized login
{not_authorized, _, {Reply,Ssh}} =
ssh_auth:handle_userauth_request(Msg, Ssh0#ssh.session_id, Ssh0),
- send_bytes(Reply, D),
- {keep_state, D#data{ssh_params = Ssh}};
+ send_bytes(Reply, D0),
+ {keep_state, D0#data{ssh_params = Ssh}};
{"ssh-connection", "ssh-connection", Method} ->
%% Userauth request with a method like "password" or so
@@ -798,20 +823,20 @@ handle_event(_,
%% Yepp! we support this method
case ssh_auth:handle_userauth_request(Msg, Ssh0#ssh.session_id, Ssh0) of
{authorized, User, {Reply, Ssh}} ->
- send_bytes(Reply, D),
- D#data.starter ! ssh_connected,
- connected_fun(User, Method, D),
+ send_bytes(Reply, D0),
+ D0#data.starter ! ssh_connected,
+ connected_fun(User, Method, D0),
{next_state, {connected,server},
- D#data{auth_user = User,
+ D0#data{auth_user = User,
ssh_params = Ssh#ssh{authenticated = true}}};
{not_authorized, {User, Reason}, {Reply, Ssh}} when Method == "keyboard-interactive" ->
- retry_fun(User, Reason, D),
- send_bytes(Reply, D),
- {next_state, {userauth_keyboard_interactive,server}, D#data{ssh_params = Ssh}};
+ retry_fun(User, Reason, D0),
+ send_bytes(Reply, D0),
+ {next_state, {userauth_keyboard_interactive,server}, D0#data{ssh_params = Ssh}};
{not_authorized, {User, Reason}, {Reply, Ssh}} ->
- retry_fun(User, Reason, D),
- send_bytes(Reply, D),
- {keep_state, D#data{ssh_params = Ssh}}
+ retry_fun(User, Reason, D0),
+ send_bytes(Reply, D0),
+ {keep_state, D0#data{ssh_params = Ssh}}
end;
false ->
%% No we do not support this method (=/= none)
@@ -825,9 +850,11 @@ handle_event(_,
%% {ServiceName, Expected, Method} when Expected =/= ServiceName -> Do what?
{ServiceName, _, _} when ServiceName =/= "ssh-connection" ->
- disconnect(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
- description = "Unknown service"},
- StateName, D)
+ {Shutdown, D} =
+ ?send_disconnect(?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
+ io_lib:format("Unknown service: ~p",[ServiceName]),
+ StateName, D0),
+ {stop, Shutdown, D}
end;
%%---- userauth success to client
@@ -843,14 +870,14 @@ handle_event(_, #ssh_msg_userauth_success{}, {userauth,client}, D=#data{ssh_para
%%---- userauth failure response to client
handle_event(_, #ssh_msg_userauth_failure{}, {userauth,client}=StateName,
- D = #data{ssh_params = #ssh{userauth_methods = []}}) ->
- Msg = #ssh_msg_disconnect{code = ?SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE,
- description = "Unable to connect using the available"
- " authentication methods"},
- disconnect(Msg, StateName, D);
-
+ #data{ssh_params = #ssh{userauth_methods = []}} = D0) ->
+ {Shutdown, D} =
+ ?send_disconnect(?SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE,
+ io_lib:format("User auth failed for: ~p",[D0#data.auth_user]),
+ StateName, D0),
+ {stop, Shutdown, D};
handle_event(_, #ssh_msg_userauth_failure{authentications = Methods}, StateName={userauth,client},
- D = #data{ssh_params = Ssh0}) ->
+ D0 = #data{ssh_params = Ssh0}) ->
%% The prefered authentication method failed try next method
Ssh1 = case Ssh0#ssh.userauth_methods of
none ->
@@ -861,15 +888,18 @@ handle_event(_, #ssh_msg_userauth_failure{authentications = Methods}, StateName=
Ssh0
end,
case ssh_auth:userauth_request_msg(Ssh1) of
- {disconnect, DisconnectMsg, {Msg, Ssh}} ->
- send_bytes(Msg, D),
- disconnect(DisconnectMsg, StateName, D#data{ssh_params = Ssh});
+ {send_disconnect, Code, Ssh} ->
+ {Shutdown, D} =
+ ?send_disconnect(Code,
+ io_lib:format("User auth failed for: ~p",[D0#data.auth_user]),
+ StateName, D0#data{ssh_params = Ssh}),
+ {stop, Shutdown, D};
{"keyboard-interactive", {Msg, Ssh}} ->
- send_bytes(Msg, D),
- {next_state, {userauth_keyboard_interactive,client}, D#data{ssh_params = Ssh}};
+ send_bytes(Msg, D0),
+ {next_state, {userauth_keyboard_interactive,client}, D0#data{ssh_params = Ssh}};
{_Method, {Msg, Ssh}} ->
- send_bytes(Msg, D),
- {keep_state, D#data{ssh_params = Ssh}}
+ send_bytes(Msg, D0),
+ {keep_state, D0#data{ssh_params = Ssh}}
end;
%%---- banner to client
@@ -952,6 +982,10 @@ handle_event(_, #ssh_msg_userauth_info_request{}, {userauth_keyboard_interactive
%%% ######## {connected, client|server} ####
+%% Skip ext_info messages in connected state (for example from OpenSSH >= 7.7)
+handle_event(_, #ssh_msg_ext_info{}, {connected,_Role}, D) ->
+ {keep_state, D};
+
handle_event(_, {#ssh_msg_kexinit{},_}, {connected,Role}, D0) ->
{KeyInitMsg, SshPacket, Ssh} = ssh_transport:key_exchange_init_msg(D0#data.ssh_params),
D = D0#data{ssh_params = Ssh,
@@ -960,10 +994,10 @@ handle_event(_, {#ssh_msg_kexinit{},_}, {connected,Role}, D0) ->
{next_state, {kexinit,Role,renegotiate}, D, [postpone]};
handle_event(_, #ssh_msg_disconnect{description=Desc} = Msg, StateName, D0) ->
- {disconnect, _, {{replies,Replies}, _}} =
+ {disconnect, _, RepliesCon} =
ssh_connection:handle_msg(Msg, D0#data.connection_state, role(StateName)),
- {Actions,D} = send_replies(Replies, D0),
- disconnect_fun(Desc, D),
+ {Actions,D} = send_replies(RepliesCon, D0),
+ disconnect_fun("Received disconnect: "++Desc, D),
{stop_and_reply, {shutdown,Desc}, Actions, D};
handle_event(_, #ssh_msg_ignore{}, _, _) ->
@@ -976,102 +1010,103 @@ handle_event(_, #ssh_msg_debug{} = Msg, _, D) ->
debug_fun(Msg, D),
keep_state_and_data;
-handle_event(internal, Msg=#ssh_msg_global_request{}, StateName, D) ->
- handle_connection_msg(Msg, StateName, D);
-
-handle_event(internal, Msg=#ssh_msg_request_success{}, StateName, D) ->
- handle_connection_msg(Msg, StateName, D);
-
-handle_event(internal, Msg=#ssh_msg_request_failure{}, StateName, D) ->
- handle_connection_msg(Msg, StateName, D);
-
-handle_event(internal, Msg=#ssh_msg_channel_open{}, StateName, D) ->
- handle_connection_msg(Msg, StateName, D);
-
-handle_event(internal, Msg=#ssh_msg_channel_open_confirmation{}, StateName, D) ->
- handle_connection_msg(Msg, StateName, D);
-
-handle_event(internal, Msg=#ssh_msg_channel_open_failure{}, StateName, D) ->
- handle_connection_msg(Msg, StateName, D);
-
-handle_event(internal, Msg=#ssh_msg_channel_window_adjust{}, StateName, D) ->
- handle_connection_msg(Msg, StateName, D);
-
-handle_event(internal, Msg=#ssh_msg_channel_data{}, StateName, D) ->
- handle_connection_msg(Msg, StateName, D);
-
-handle_event(internal, Msg=#ssh_msg_channel_extended_data{}, StateName, D) ->
- handle_connection_msg(Msg, StateName, D);
-
-handle_event(internal, Msg=#ssh_msg_channel_eof{}, StateName, D) ->
- handle_connection_msg(Msg, StateName, D);
-
-handle_event(internal, Msg=#ssh_msg_channel_close{}, {connected,server} = StateName, D) ->
- handle_connection_msg(Msg, StateName, cache_request_idle_timer_check(D));
-
-handle_event(internal, Msg=#ssh_msg_channel_close{}, StateName, D) ->
- handle_connection_msg(Msg, StateName, D);
-
-handle_event(internal, Msg=#ssh_msg_channel_request{}, StateName, D) ->
- handle_connection_msg(Msg, StateName, D);
-
-handle_event(internal, Msg=#ssh_msg_channel_success{}, StateName, D) ->
- update_inet_buffers(D#data.socket),
- handle_connection_msg(Msg, StateName, D);
-
-handle_event(internal, Msg=#ssh_msg_channel_failure{}, StateName, D) ->
- handle_connection_msg(Msg, StateName, D);
-
+handle_event(internal, {conn_msg,Msg}, StateName, #data{starter = User,
+ connection_state = Connection0,
+ event_queue = Qev0} = D0) ->
+ Role = role(StateName),
+ Rengotation = renegotiation(StateName),
+ try ssh_connection:handle_msg(Msg, Connection0, Role) of
+ {disconnect, Reason0, RepliesConn} ->
+ {Repls, D} = send_replies(RepliesConn, D0),
+ case {Reason0,Role} of
+ {{_, Reason}, client} when ((StateName =/= {connected,client})
+ and (not Rengotation)) ->
+ User ! {self(), not_connected, Reason};
+ _ ->
+ ok
+ end,
+ {stop_and_reply, {shutdown,normal}, Repls, D};
-handle_event(cast, renegotiate, {connected,Role}, D) ->
- {KeyInitMsg, SshPacket, Ssh} = ssh_transport:key_exchange_init_msg(D#data.ssh_params),
- send_bytes(SshPacket, D),
- timer:apply_after(?REKEY_TIMOUT, gen_statem, cast, [self(), renegotiate]),
- {next_state, {kexinit,Role,renegotiate}, D#data{ssh_params = Ssh,
- key_exchange_init_msg = KeyInitMsg}};
+ {Replies, Connection} when is_list(Replies) ->
+ {Repls, D} =
+ case StateName of
+ {connected,_} ->
+ send_replies(Replies, D0#data{connection_state=Connection});
+ _ ->
+ {ConnReplies, NonConnReplies} = lists:splitwith(fun not_connected_filter/1, Replies),
+ send_replies(NonConnReplies, D0#data{event_queue = Qev0 ++ ConnReplies})
+ end,
+ case {Msg, StateName} of
+ {#ssh_msg_channel_close{}, {connected,_}} ->
+ {keep_state, D, [cond_set_idle_timer(D)|Repls]};
+ {#ssh_msg_channel_success{}, _} ->
+ update_inet_buffers(D#data.socket),
+ {keep_state, D, Repls};
+ _ ->
+ {keep_state, D, Repls}
+ end
-handle_event(cast, renegotiate, _, _) ->
- %% Already in key-exchange so safe to ignore
- timer:apply_after(?REKEY_TIMOUT, gen_statem, cast, [self(), renegotiate]), % FIXME: not here in original
- keep_state_and_data;
+ catch
+ Class:Error ->
+ {Repls, D1} = send_replies(ssh_connection:handle_stop(Connection0), D0),
+ {Shutdown, D} = ?send_disconnect(?SSH_DISCONNECT_BY_APPLICATION,
+ io_lib:format("Internal error: ~p:~p",[Class,Error]),
+ StateName, D1),
+ {stop_and_reply, Shutdown, Repls, D}
+ end;
-%% Rekey due to sent data limit reached?
-handle_event(cast, data_size, {connected,Role}, D) ->
- {ok, [{send_oct,Sent0}]} = inet:getstat(D#data.socket, [send_oct]),
- Sent = Sent0 - D#data.last_size_rekey,
- MaxSent = ?GET_OPT(rekey_limit, (D#data.ssh_params)#ssh.opts),
- timer:apply_after(?REKEY_DATA_TIMOUT, gen_statem, cast, [self(), data_size]),
- case Sent >= MaxSent of
- true ->
- {KeyInitMsg, SshPacket, Ssh} =
- ssh_transport:key_exchange_init_msg(D#data.ssh_params),
- send_bytes(SshPacket, D),
- {next_state, {kexinit,Role,renegotiate}, D#data{ssh_params = Ssh,
- key_exchange_init_msg = KeyInitMsg,
- last_size_rekey = Sent0}};
- _ ->
- keep_state_and_data
+handle_event(enter, _OldState, {connected,_}=State, D) ->
+ %% Entering the state where re-negotiation is possible
+ init_renegotiate_timers(State, D);
+
+handle_event(enter, _OldState, {ext_info,_,renegotiate}=State, D) ->
+ %% Could be hanging in exit_info state if nothing else arrives
+ init_renegotiate_timers(State, D);
+
+handle_event(enter, {connected,_}, State, D) ->
+ %% Exiting the state where re-negotiation is possible
+ pause_renegotiate_timers(State, D);
+
+handle_event(cast, force_renegotiate, StateName, D) ->
+ handle_event({timeout,renegotiate}, undefined, StateName, D);
+
+handle_event({timeout,renegotiate}, _, StateName, D0) ->
+ case StateName of
+ {connected,Role} ->
+ start_rekeying(Role, D0);
+ {ext_info,Role,renegotiate} ->
+ start_rekeying(Role, D0);
+ _ ->
+ %% Wrong state for starting a renegotiation, must be in re-negotiation
+ keep_state_and_data
end;
-handle_event(cast, data_size, _, _) ->
- %% Already in key-exchange so safe to ignore
- timer:apply_after(?REKEY_DATA_TIMOUT, gen_statem, cast, [self(), data_size]), % FIXME: not here in original
- keep_state_and_data;
-
+handle_event({timeout,check_data_size}, _, StateName, D0) ->
+ %% Rekey due to sent data limit reached? (Can't be in {ext_info,...} if data is sent)
+ case StateName of
+ {connected,Role} ->
+ check_data_rekeying(Role, D0);
+ _ ->
+ %% Wrong state for starting a renegotiation, must be in re-negotiation
+ keep_state_and_data
+ end;
+handle_event({call,From}, get_alg, _, D) ->
+ #ssh{algorithms=Algs} = D#data.ssh_params,
+ {keep_state_and_data, [{reply,From,Algs}]};
handle_event(cast, _, StateName, _) when not ?CONNECTED(StateName) ->
{keep_state_and_data, [postpone]};
handle_event(cast, {adjust_window,ChannelId,Bytes}, StateName, D) when ?CONNECTED(StateName) ->
- case ssh_channel:cache_lookup(cache(D), ChannelId) of
+ case ssh_client_channel:cache_lookup(cache(D), ChannelId) of
#channel{recv_window_size = WinSize,
recv_window_pending = Pending,
recv_packet_size = PktSize} = Channel
when (WinSize-Bytes) >= 2*PktSize ->
%% The peer can send at least two more *full* packet, no hurry.
- ssh_channel:cache_update(cache(D),
+ ssh_client_channel:cache_update(cache(D),
Channel#channel{recv_window_pending = Pending + Bytes}),
keep_state_and_data;
@@ -1079,7 +1114,7 @@ handle_event(cast, {adjust_window,ChannelId,Bytes}, StateName, D) when ?CONNECTE
recv_window_pending = Pending,
remote_id = Id} = Channel ->
%% Now we have to update the window - we can't receive so many more pkts
- ssh_channel:cache_update(cache(D),
+ ssh_client_channel:cache_update(cache(D),
Channel#channel{recv_window_size =
WinSize + Bytes + Pending,
recv_window_pending = 0}),
@@ -1091,7 +1126,7 @@ handle_event(cast, {adjust_window,ChannelId,Bytes}, StateName, D) when ?CONNECTE
end;
handle_event(cast, {reply_request,success,ChannelId}, StateName, D) when ?CONNECTED(StateName) ->
- case ssh_channel:cache_lookup(cache(D), ChannelId) of
+ case ssh_client_channel:cache_lookup(cache(D), ChannelId) of
#channel{remote_id = RemoteId} ->
Msg = ssh_connection:channel_success_msg(RemoteId),
update_inet_buffers(D#data.socket),
@@ -1134,7 +1169,7 @@ handle_event({call,From}, {connection_info, Options}, _, D) ->
{keep_state_and_data, [{reply,From,Info}]};
handle_event({call,From}, {channel_info,ChannelId,Options}, _, D) ->
- case ssh_channel:cache_lookup(cache(D), ChannelId) of
+ case ssh_client_channel:cache_lookup(cache(D), ChannelId) of
#channel{} = Channel ->
Info = fold_keys(Options, fun chann_info/2, Channel),
{keep_state_and_data, [{reply,From,Info}]};
@@ -1144,14 +1179,14 @@ handle_event({call,From}, {channel_info,ChannelId,Options}, _, D) ->
handle_event({call,From}, {info, all}, _, D) ->
- Result = ssh_channel:cache_foldl(fun(Channel, Acc) ->
+ Result = ssh_client_channel:cache_foldl(fun(Channel, Acc) ->
[Channel | Acc]
end,
[], cache(D)),
{keep_state_and_data, [{reply, From, {ok,Result}}]};
handle_event({call,From}, {info, ChannelPid}, _, D) ->
- Result = ssh_channel:cache_foldl(
+ Result = ssh_client_channel:cache_foldl(
fun(Channel, Acc) when Channel#channel.user == ChannelPid ->
[Channel | Acc];
(_, Acc) ->
@@ -1159,15 +1194,9 @@ handle_event({call,From}, {info, ChannelPid}, _, D) ->
end, [], cache(D)),
{keep_state_and_data, [{reply, From, {ok,Result}}]};
-handle_event({call,From}, stop, StateName, D0) ->
- {disconnect, _Reason, {{replies, Replies}, Connection}} =
- ssh_connection:handle_msg(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION,
- description = "User closed down connection"},
- D0#data.connection_state,
- role(StateName)),
- {Repls,D} = send_replies(Replies, D0),
- {stop_and_reply, normal, [{reply,From,ok}|Repls], D#data{connection_state=Connection}};
-
+handle_event({call,From}, stop, _StateName, D0) ->
+ {Repls,D} = send_replies(ssh_connection:handle_stop(D0#data.connection_state), D0),
+ {stop_and_reply, normal, [{reply,From,ok}|Repls], D};
handle_event({call,_}, _, StateName, _) when not ?CONNECTED(StateName) ->
{keep_state_and_data, [postpone]};
@@ -1180,7 +1209,7 @@ handle_event({call,From}, {request, ChannelPid, ChannelId, Type, Data, Timeout},
D ->
%% Note reply to channel will happen later when reply is recived from peer on the socket
start_channel_request_timer(ChannelId, From, Timeout),
- {keep_state, cache_request_idle_timer_check(D)}
+ {keep_state, D, cond_set_idle_timer(D)}
end;
handle_event({call,From}, {request, ChannelId, Type, Data, Timeout}, StateName, D0)
@@ -1191,20 +1220,19 @@ handle_event({call,From}, {request, ChannelId, Type, Data, Timeout}, StateName,
D ->
%% Note reply to channel will happen later when reply is recived from peer on the socket
start_channel_request_timer(ChannelId, From, Timeout),
- {keep_state, cache_request_idle_timer_check(D)}
+ {keep_state, D, cond_set_idle_timer(D)}
end;
handle_event({call,From}, {data, ChannelId, Type, Data, Timeout}, StateName, D0)
when ?CONNECTED(StateName) ->
- {{replies, Replies}, Connection} =
- ssh_connection:channel_data(ChannelId, Type, Data, D0#data.connection_state, From),
- {Repls,D} = send_replies(Replies, D0#data{connection_state = Connection}),
+ {Repls,D} = send_replies(ssh_connection:channel_data(ChannelId, Type, Data, D0#data.connection_state, From),
+ D0),
start_channel_request_timer(ChannelId, From, Timeout), % FIXME: No message exchange so why?
{keep_state, D, Repls};
handle_event({call,From}, {eof, ChannelId}, StateName, D0)
when ?CONNECTED(StateName) ->
- case ssh_channel:cache_lookup(cache(D0), ChannelId) of
+ case ssh_client_channel:cache_lookup(cache(D0), ChannelId) of
#channel{remote_id = Id, sent_close = false} ->
D = send_msg(ssh_connection:channel_eof_msg(Id), D0),
{keep_state, D, [{reply,From,ok}]};
@@ -1222,7 +1250,7 @@ handle_event({call,From},
InitialWindowSize,
MaxPacketSize, Data),
D1),
- ssh_channel:cache_update(cache(D2),
+ ssh_client_channel:cache_update(cache(D2),
#channel{type = Type,
sys = "none",
user = ChannelPid,
@@ -1233,11 +1261,11 @@ handle_event({call,From},
}),
D = add_request(true, ChannelId, From, D2),
start_channel_request_timer(ChannelId, From, Timeout),
- {keep_state, cache_cancel_idle_timer(D)};
+ {keep_state, D, cond_set_idle_timer(D)};
handle_event({call,From}, {send_window, ChannelId}, StateName, D)
when ?CONNECTED(StateName) ->
- Reply = case ssh_channel:cache_lookup(cache(D), ChannelId) of
+ Reply = case ssh_client_channel:cache_lookup(cache(D), ChannelId) of
#channel{send_window_size = WinSize,
send_packet_size = Packsize} ->
{ok, {WinSize, Packsize}};
@@ -1248,7 +1276,7 @@ handle_event({call,From}, {send_window, ChannelId}, StateName, D)
handle_event({call,From}, {recv_window, ChannelId}, StateName, D)
when ?CONNECTED(StateName) ->
- Reply = case ssh_channel:cache_lookup(cache(D), ChannelId) of
+ Reply = case ssh_client_channel:cache_lookup(cache(D), ChannelId) of
#channel{recv_window_size = WinSize,
recv_packet_size = Packsize} ->
{ok, {WinSize, Packsize}};
@@ -1259,11 +1287,11 @@ handle_event({call,From}, {recv_window, ChannelId}, StateName, D)
handle_event({call,From}, {close, ChannelId}, StateName, D0)
when ?CONNECTED(StateName) ->
- case ssh_channel:cache_lookup(cache(D0), ChannelId) of
+ case ssh_client_channel:cache_lookup(cache(D0), ChannelId) of
#channel{remote_id = Id} = Channel ->
D1 = send_msg(ssh_connection:channel_close_msg(Id), D0),
- ssh_channel:cache_update(cache(D1), Channel#channel{sent_close = true}),
- {keep_state, cache_request_idle_timer_check(D1), [{reply,From,ok}]};
+ ssh_client_channel:cache_update(cache(D1), Channel#channel{sent_close = true}),
+ {keep_state, D1, [cond_set_idle_timer(D1), {reply,From,ok}]};
undefined ->
{keep_state_and_data, [{reply,From,ok}]}
end;
@@ -1279,61 +1307,91 @@ handle_event(info, {Proto, Sock, Info}, {hello,_}, #data{socket = Sock,
{keep_state_and_data, [{next_event, internal, {info_line,Info}}]}
end;
+
handle_event(info, {Proto, Sock, NewData}, StateName, D0 = #data{socket = Sock,
transport_protocol = Proto}) ->
try ssh_transport:handle_packet_part(
D0#data.decrypted_data_buffer,
<<(D0#data.encrypted_data_buffer)/binary, NewData/binary>>,
- D0#data.undecrypted_packet_length,
+ D0#data.aead_data,
+ D0#data.undecrypted_packet_length,
D0#data.ssh_params)
of
{packet_decrypted, DecryptedBytes, EncryptedDataRest, Ssh1} ->
- D = D0#data{ssh_params =
+ D1 = D0#data{ssh_params =
Ssh1#ssh{recv_sequence = ssh_transport:next_seqnum(Ssh1#ssh.recv_sequence)},
decrypted_data_buffer = <<>>,
- undecrypted_packet_length = undefined,
+ undecrypted_packet_length = undefined,
+ aead_data = <<>>,
encrypted_data_buffer = EncryptedDataRest},
try
- ssh_message:decode(set_kex_overload_prefix(DecryptedBytes,D))
+ ssh_message:decode(set_kex_overload_prefix(DecryptedBytes,D1))
of
- Msg = #ssh_msg_kexinit{} ->
- {keep_state, D, [{next_event, internal, prepare_next_packet},
+ #ssh_msg_kexinit{} = Msg ->
+ {keep_state, D1, [{next_event, internal, prepare_next_packet},
{next_event, internal, {Msg,DecryptedBytes}}
]};
+
+ #ssh_msg_global_request{} = Msg -> {keep_state, D1, ?CONNECTION_MSG(Msg)};
+ #ssh_msg_request_success{} = Msg -> {keep_state, D1, ?CONNECTION_MSG(Msg)};
+ #ssh_msg_request_failure{} = Msg -> {keep_state, D1, ?CONNECTION_MSG(Msg)};
+ #ssh_msg_channel_open{} = Msg -> {keep_state, D1, ?CONNECTION_MSG(Msg)};
+ #ssh_msg_channel_open_confirmation{} = Msg -> {keep_state, D1, ?CONNECTION_MSG(Msg)};
+ #ssh_msg_channel_open_failure{} = Msg -> {keep_state, D1, ?CONNECTION_MSG(Msg)};
+ #ssh_msg_channel_window_adjust{} = Msg -> {keep_state, D1, ?CONNECTION_MSG(Msg)};
+ #ssh_msg_channel_data{} = Msg -> {keep_state, D1, ?CONNECTION_MSG(Msg)};
+ #ssh_msg_channel_extended_data{} = Msg -> {keep_state, D1, ?CONNECTION_MSG(Msg)};
+ #ssh_msg_channel_eof{} = Msg -> {keep_state, D1, ?CONNECTION_MSG(Msg)};
+ #ssh_msg_channel_close{} = Msg -> {keep_state, D1, ?CONNECTION_MSG(Msg)};
+ #ssh_msg_channel_request{} = Msg -> {keep_state, D1, ?CONNECTION_MSG(Msg)};
+ #ssh_msg_channel_failure{} = Msg -> {keep_state, D1, ?CONNECTION_MSG(Msg)};
+ #ssh_msg_channel_success{} = Msg -> {keep_state, D1, ?CONNECTION_MSG(Msg)};
+
Msg ->
- {keep_state, D, [{next_event, internal, prepare_next_packet},
- {next_event, internal, Msg}
+ {keep_state, D1, [{next_event, internal, prepare_next_packet},
+ {next_event, internal, Msg}
]}
catch
- _C:_E ->
- disconnect(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR,
- description = "Bad packet"},
- StateName, D)
+ C:E:ST ->
+ {Shutdown, D} =
+ ?send_disconnect(?SSH_DISCONNECT_PROTOCOL_ERROR,
+ io_lib:format("Bad packet: Decrypted, but can't decode~n~p:~p~n~p",
+ [C,E,ST]),
+ StateName, D1),
+ {stop, Shutdown, D}
end;
- {get_more, DecryptedBytes, EncryptedDataRest, RemainingSshPacketLen, Ssh1} ->
+ {get_more, DecryptedBytes, EncryptedDataRest, AeadData, RemainingSshPacketLen, Ssh1} ->
%% Here we know that there are not enough bytes in
%% EncryptedDataRest to use. We must wait for more.
inet:setopts(Sock, [{active, once}]),
{keep_state, D0#data{encrypted_data_buffer = EncryptedDataRest,
decrypted_data_buffer = DecryptedBytes,
- undecrypted_packet_length = RemainingSshPacketLen,
+ undecrypted_packet_length = RemainingSshPacketLen,
+ aead_data = AeadData,
ssh_params = Ssh1}};
{bad_mac, Ssh1} ->
- disconnect(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR,
- description = "Bad packet"},
- StateName, D0#data{ssh_params=Ssh1});
-
- {error, {exceeds_max_size,_PacketLen}} ->
- disconnect(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR,
- description = "Bad packet"},
- StateName, D0)
+ {Shutdown, D} =
+ ?send_disconnect(?SSH_DISCONNECT_PROTOCOL_ERROR,
+ "Bad packet: bad mac",
+ StateName, D0#data{ssh_params=Ssh1}),
+ {stop, Shutdown, D};
+
+ {error, {exceeds_max_size,PacketLen}} ->
+ {Shutdown, D} =
+ ?send_disconnect(?SSH_DISCONNECT_PROTOCOL_ERROR,
+ io_lib:format("Bad packet: Size (~p bytes) exceeds max size",
+ [PacketLen]),
+ StateName, D0),
+ {stop, Shutdown, D}
catch
- _C:_E ->
- disconnect(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR,
- description = "Bad packet"},
- StateName, D0)
+ C:E:ST ->
+ {Shutdown, D} =
+ ?send_disconnect(?SSH_DISCONNECT_PROTOCOL_ERROR,
+ io_lib:format("Bad packet: Couldn't decrypt~n~p:~p~n~p",[C,E,ST]),
+ StateName, D0),
+ {stop, Shutdown, D}
end;
@@ -1349,15 +1407,13 @@ handle_event(internal, prepare_next_packet, _, D) ->
inet:setopts(D#data.socket, [{active, once}]),
keep_state_and_data;
-handle_event(info, {CloseTag,Socket}, StateName,
- D = #data{socket = Socket,
- transport_close_tag = CloseTag}) ->
- %% Simulate a disconnect from the peer
- handle_event(info,
- #ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION,
- description = "Connection closed"},
- StateName,
- D);
+handle_event(info, {CloseTag,Socket}, _StateName,
+ D0 = #data{socket = Socket,
+ transport_close_tag = CloseTag,
+ connection_state = C0}) ->
+ {Repls, D} = send_replies(ssh_connection:handle_stop(C0), D0),
+ disconnect_fun("Received a transport close", D),
+ {stop_and_reply, {shutdown,"Connection closed"}, Repls, D};
handle_event(info, {timeout, {_, From} = Request}, _,
#data{connection_state = #connection{requests = Requests} = C0} = D) ->
@@ -1373,17 +1429,40 @@ handle_event(info, {timeout, {_, From} = Request}, _,
end;
%%% Handle that ssh channels user process goes down
-handle_event(info, {'DOWN', _Ref, process, ChannelPid, _Reason}, _, D0) ->
- {{replies, Replies}, D1} = handle_channel_down(ChannelPid, D0),
- {Repls, D} = send_replies(Replies, D1),
- {keep_state, D, Repls};
+handle_event(info, {'DOWN', _Ref, process, ChannelPid, _Reason}, _, D) ->
+ Cache = cache(D),
+ ssh_client_channel:cache_foldl(
+ fun(#channel{user=U,
+ local_id=Id}, Acc) when U == ChannelPid ->
+ ssh_client_channel:cache_delete(Cache, Id),
+ Acc;
+ (_,Acc) ->
+ Acc
+ end, [], Cache),
+ {keep_state, D, cond_set_idle_timer(D)};
+
+handle_event({timeout,idle_time}, _Data, _StateName, _D) ->
+ {stop, {shutdown, "Timeout"}};
%%% So that terminate will be run when supervisor is shutdown
-handle_event(info, {'EXIT', _Sup, Reason}, _, _) ->
- {stop, {shutdown, Reason}};
+handle_event(info, {'EXIT', _Sup, Reason}, StateName, _) ->
+ Role = role(StateName),
+ if
+ Role == client ->
+ %% OTP-8111 tells this function clause fixes a problem in
+ %% clients, but there were no check for that role.
+ {stop, {shutdown, Reason}};
+
+ Reason == normal ->
+ %% An exit normal should not cause a server to crash. This has happend...
+ keep_state_and_data;
+
+ true ->
+ {stop, {shutdown, Reason}}
+ end;
handle_event(info, check_cache, _, D) ->
- {keep_state, cache_check_set_idle_timer(D)};
+ {keep_state, D, cond_set_idle_timer(D)};
handle_event(info, UnexpectedMessage, StateName, D = #data{ssh_params = Ssh}) ->
case unexpected_fun(UnexpectedMessage, D) of
@@ -1425,62 +1504,83 @@ handle_event(info, UnexpectedMessage, StateName, D = #data{ssh_params = Ssh}) ->
keep_state_and_data
end;
-handle_event(internal, {disconnect,Msg,_Reason}, StateName, D) ->
- disconnect(Msg, StateName, D);
+handle_event(internal, {send_disconnect,Code,DetailedText,Module,Line}, StateName, D0) ->
+ {Shutdown, D} =
+ send_disconnect(Code, DetailedText, Module, Line, StateName, D0),
+ {stop, Shutdown, D};
+
+
+handle_event(enter, _OldState, State, D) ->
+ %% Just skip
+ {next_state, State, D};
handle_event(_Type, _Msg, {ext_info,Role,_ReNegFlag}, D) ->
%% If something else arrives, goto next state and handle the event in that one
{next_state, {connected,Role}, D, [postpone]};
-handle_event(Type, Ev, StateName, D) ->
- Descr =
+handle_event(Type, Ev, StateName, D0) ->
+ Details =
case catch atom_to_list(element(1,Ev)) of
"ssh_msg_" ++_ when Type==internal ->
-%% "Message in wrong state";
lists:flatten(io_lib:format("Message ~p in wrong state (~p)", [element(1,Ev), StateName]));
_ ->
- "Internal error"
+ io_lib:format("Unhandled event in state ~p:~n~p", [StateName,Ev])
end,
- disconnect(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR,
- description = Descr},
- StateName, D).
+ {Shutdown, D} =
+ ?send_disconnect(?SSH_DISCONNECT_PROTOCOL_ERROR, Details, StateName, D0),
+ {stop, Shutdown, D}.
%%--------------------------------------------------------------------
-spec terminate(any(),
state_name(),
#data{}
- ) -> finalize_termination_result() .
+ ) -> term().
%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-terminate(normal, StateName, State) ->
- finalize_termination(StateName, State);
+terminate(normal, _StateName, D) ->
+ stop_subsystem(D),
+ close_transport(D);
-terminate({shutdown,{init,Reason}}, StateName, State) ->
- error_logger:info_report(io_lib:format("Erlang ssh in connection handler init: ~p~n",[Reason])),
- finalize_termination(StateName, State);
-
-terminate(shutdown, StateName, State0) ->
- %% Terminated by supervisor
- State = send_msg(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION,
- description = "Application shutdown"},
- State0),
- finalize_termination(StateName, State);
+terminate({shutdown,"Connection closed"}, _StateName, D) ->
+ %% Normal: terminated by a sent by peer
+ stop_subsystem(D),
+ close_transport(D);
-terminate({shutdown,_R}, StateName, State) ->
- finalize_termination(StateName, State);
+terminate({shutdown,{init,Reason}}, StateName, D) ->
+ %% Error in initiation. "This error should not occur".
+ log(error, D, io_lib:format("Shutdown in init (StateName=~p): ~p~n",[StateName,Reason])),
+ stop_subsystem(D),
+ close_transport(D);
-terminate(kill, StateName, State) ->
- finalize_termination(StateName, State);
+terminate({shutdown,_R}, _StateName, D) ->
+ %% Internal termination, usually already reported via ?send_disconnect resulting in a log entry
+ stop_subsystem(D),
+ close_transport(D);
-terminate(Reason, StateName, State0) ->
- %% Others, e.g undef, {badmatch,_}
- log_error(Reason),
- State = send_msg(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION,
- description = "Internal error"},
- State0),
- finalize_termination(StateName, State).
+terminate(shutdown, _StateName, D0) ->
+ %% Terminated by supervisor
+ %% Use send_msg directly instead of ?send_disconnect to avoid filling the log
+ D = send_msg(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION,
+ description = "Terminated (shutdown) by supervisor"},
+ D0),
+ close_transport(D);
+
+terminate(kill, _StateName, D) ->
+ %% Got a kill signal
+ stop_subsystem(D),
+ close_transport(D);
+
+terminate(Reason, StateName, D0) ->
+ %% Others, e.g undef, {badmatch,_}, ...
+ log(error, D0, Reason),
+ {_ShutdownReason, D} = ?send_disconnect(?SSH_DISCONNECT_BY_APPLICATION,
+ "Internal error",
+ io_lib:format("Reason: ~p",[Reason]),
+ StateName, D0),
+ stop_subsystem(D),
+ close_transport(D).
%%--------------------------------------------------------------------
@@ -1489,36 +1589,41 @@ terminate(Reason, StateName, State0) ->
format_status(normal, [_, _StateName, D]) ->
[{data, [{"State", D}]}];
format_status(terminate, [_, _StateName, D]) ->
- DataPropList0 = fmt_stat_rec(record_info(fields, data), D,
- [decrypted_data_buffer,
- encrypted_data_buffer,
- key_exchange_init_msg,
- user_passwords,
- opts,
- inet_initial_recbuf_size]),
- SshPropList = fmt_stat_rec(record_info(fields, ssh), D#data.ssh_params,
- [c_keyinit,
- s_keyinit,
- send_mac_key,
- send_mac_size,
- recv_mac_key,
- recv_mac_size,
- encrypt_keys,
- encrypt_ctx,
- decrypt_keys,
- decrypt_ctx,
- compress_ctx,
- decompress_ctx,
- shared_secret,
- exchanged_hash,
- session_id,
- keyex_key,
- keyex_info,
- available_host_keys]),
- DataPropList = lists:keyreplace(ssh_params, 1, DataPropList0,
- {ssh_params,SshPropList}),
- [{data, [{"State", DataPropList}]}].
-
+ [{data, [{"State", state_data2proplist(D)}]}].
+
+
+state_data2proplist(D) ->
+ DataPropList0 =
+ fmt_stat_rec(record_info(fields, data), D,
+ [decrypted_data_buffer,
+ encrypted_data_buffer,
+ key_exchange_init_msg,
+ user_passwords,
+ opts,
+ inet_initial_recbuf_size]),
+ SshPropList =
+ fmt_stat_rec(record_info(fields, ssh), D#data.ssh_params,
+ [c_keyinit,
+ s_keyinit,
+ send_mac_key,
+ send_mac_size,
+ recv_mac_key,
+ recv_mac_size,
+ encrypt_keys,
+ encrypt_ctx,
+ decrypt_keys,
+ decrypt_ctx,
+ compress_ctx,
+ decompress_ctx,
+ shared_secret,
+ exchanged_hash,
+ session_id,
+ keyex_key,
+ keyex_info,
+ available_host_keys]),
+ lists:keyreplace(ssh_params, 1, DataPropList0,
+ {ssh_params,SshPropList}).
+
fmt_stat_rec(FieldNames, Rec, Exclude) ->
Values = tl(tuple_to_list(Rec)),
@@ -1555,39 +1660,44 @@ start_the_connection_child(UserPid, Role, Socket, Options0) ->
%%--------------------------------------------------------------------
%% Stopping
--type finalize_termination_result() :: ok .
-
-finalize_termination(_StateName, #data{transport_cb = Transport,
- connection_state = Connection,
- socket = Socket}) ->
- case Connection of
- #connection{system_supervisor = SysSup,
- sub_system_supervisor = SubSysSup} when is_pid(SubSysSup) ->
- ssh_system_sup:stop_subsystem(SysSup, SubSysSup);
- _ ->
- do_nothing
- end,
- (catch Transport:close(Socket)),
+
+stop_subsystem(#data{connection_state =
+ #connection{system_supervisor = SysSup,
+ sub_system_supervisor = SubSysSup}}) when is_pid(SubSysSup) ->
+ ssh_system_sup:stop_subsystem(SysSup, SubSysSup);
+stop_subsystem(_) ->
ok.
+
+close_transport(#data{transport_cb = Transport,
+ socket = Socket}) ->
+ try
+ Transport:close(Socket)
+ of
+ _ -> ok
+ catch
+ _:_ -> ok
+ end.
+
%%--------------------------------------------------------------------
%% "Invert" the Role
peer_role(client) -> server;
peer_role(server) -> client.
%%--------------------------------------------------------------------
-available_hkey_algorithms(Role, Options) ->
- KeyCb = ?GET_OPT(key_cb, Options),
- case [A || A <- available_hkey_algos(Options),
- (Role==client) orelse available_host_key(KeyCb, A, Options)
- ] of
-
- [] when Role==client ->
- error({shutdown, "No public key algs"});
-
- [] when Role==server ->
- error({shutdown, "No host key available"});
+available_hkey_algorithms(client, Options) ->
+ case available_hkey_algos(Options) of
+ [] ->
+ error({shutdown, "No public key algs"});
+ Algs ->
+ [atom_to_list(A) || A<-Algs]
+ end;
+available_hkey_algorithms(server, Options) ->
+ case [A || A <- available_hkey_algos(Options),
+ is_usable_host_key(A, Options)] of
+ [] ->
+ error({shutdown, "No host key available"});
Algs ->
[atom_to_list(A) || A<-Algs]
end.
@@ -1603,18 +1713,6 @@ available_hkey_algos(Options) ->
AvailableAndSupported.
-%% Alg :: atom()
-available_host_key({KeyCb,KeyCbOpts}, Alg, Opts) ->
- UserOpts = ?GET_OPT(user_options, Opts),
- case KeyCb:host_key(Alg, [{key_cb_private,KeyCbOpts}|UserOpts]) of
- {ok,Key} ->
- %% Check the key - the KeyCb may be a buggy plugin
- ssh_transport:valid_key_sha_alg(Key, Alg);
- _ ->
- false
- end.
-
-
send_msg(Msg, State=#data{ssh_params=Ssh0}) when is_tuple(Msg) ->
{Bytes, Ssh} = ssh_transport:ssh_packet(Msg, Ssh0),
send_bytes(Bytes, State),
@@ -1662,48 +1760,6 @@ call(FsmPid, Event, Timeout) ->
end.
-handle_connection_msg(Msg, StateName, D0 = #data{starter = User,
- connection_state = Connection0,
- event_queue = Qev0}) ->
- Renegotiation = renegotiation(StateName),
- Role = role(StateName),
- try ssh_connection:handle_msg(Msg, Connection0, Role) of
- {{replies, Replies}, Connection} ->
- {Repls, D} =
- case StateName of
- {connected,_} ->
- send_replies(Replies, D0#data{connection_state=Connection});
- _ ->
- {ConnReplies, NonConnReplies} = lists:splitwith(fun not_connected_filter/1, Replies),
- send_replies(NonConnReplies, D0#data{event_queue = Qev0 ++ ConnReplies})
- end,
- {keep_state, D, Repls};
-
- {noreply, Connection} ->
- {keep_state, D0#data{connection_state = Connection}};
-
- {disconnect, Reason0, {{replies, Replies}, Connection}} ->
- {Repls, D} = send_replies(Replies, D0#data{connection_state = Connection}),
- case {Reason0,Role} of
- {{_, Reason}, client} when ((StateName =/= {connected,client}) and (not Renegotiation)) ->
- User ! {self(), not_connected, Reason};
- _ ->
- ok
- end,
- {stop_and_reply, {shutdown,normal}, Repls, D#data{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"},
- Connection0, Role),
- {Repls, D} = send_replies(Replies, D0#data{connection_state = Connection}),
- {stop_and_reply, {shutdown,Error}, Repls, D#data{connection_state = Connection}}
- end.
-
-
set_kex_overload_prefix(Msg = <<?BYTE(Op),_/binary>>, #data{ssh_params=SshParams})
when Op == 30;
Op == 31
@@ -1711,6 +1767,10 @@ set_kex_overload_prefix(Msg = <<?BYTE(Op),_/binary>>, #data{ssh_params=SshParams
case catch atom_to_list(kex(SshParams)) of
"ecdh-sha2-" ++ _ ->
<<"ecdh",Msg/binary>>;
+ "curve25519-" ++ _ ->
+ <<"ecdh",Msg/binary>>;
+ "curve448-" ++ _ ->
+ <<"ecdh",Msg/binary>>;
"diffie-hellman-group-exchange-" ++ _ ->
<<"dh_gex",Msg/binary>>;
"diffie-hellman-group" ++ _ ->
@@ -1772,15 +1832,26 @@ ext_info(_, D0) ->
D0.
%%%----------------------------------------------------------------
-is_usable_user_pubkey(A, Ssh) ->
- case ssh_auth:get_public_key(A, Ssh) of
+is_usable_user_pubkey(Alg, Ssh) ->
+ try ssh_auth:get_public_key(Alg, Ssh) of
{ok,_} -> true;
_ -> false
+ catch
+ _:_ -> false
+ end.
+
+%%%----------------------------------------------------------------
+is_usable_host_key(Alg, Opts) ->
+ try ssh_transport:get_host_key(Alg, Opts)
+ of
+ _PrivHostKey -> true
+ catch
+ _:_ -> false
end.
%%%----------------------------------------------------------------
handle_request(ChannelPid, ChannelId, Type, Data, WantReply, From, D) ->
- case ssh_channel:cache_lookup(cache(D), ChannelId) of
+ case ssh_client_channel:cache_lookup(cache(D), ChannelId) of
#channel{remote_id = Id,
sent_close = false} = Channel ->
update_sys(cache(D), Channel, Type, ChannelPid),
@@ -1795,7 +1866,7 @@ handle_request(ChannelPid, ChannelId, Type, Data, WantReply, From, D) ->
end.
handle_request(ChannelId, Type, Data, WantReply, From, D) ->
- case ssh_channel:cache_lookup(cache(D), ChannelId) of
+ case ssh_client_channel:cache_lookup(cache(D), ChannelId) of
#channel{remote_id = Id,
sent_close = false} ->
send_msg(ssh_connection:channel_request_msg(Id, Type, WantReply, Data),
@@ -1809,20 +1880,8 @@ handle_request(ChannelId, Type, Data, WantReply, From, D) ->
end.
%%%----------------------------------------------------------------
-handle_channel_down(ChannelPid, D) ->
- ssh_channel:cache_foldl(
- fun(Channel, Acc) when Channel#channel.user == ChannelPid ->
- ssh_channel:cache_delete(cache(D),
- Channel#channel.local_id),
- Acc;
- (_,Acc) ->
- Acc
- end, [], cache(D)),
- {{replies, []}, cache_check_set_idle_timer(D)}.
-
-
update_sys(Cache, Channel, Type, ChannelPid) ->
- ssh_channel:cache_update(Cache,
+ ssh_client_channel:cache_update(Cache,
Channel#channel{sys = Type, user = ChannelPid}).
add_request(false, _ChannelId, _From, State) ->
@@ -1839,12 +1898,86 @@ new_channel_id(#data{connection_state = #connection{channel_id_seed = Id} =
{Id, State#data{connection_state =
Connection#connection{channel_id_seed = Id + 1}}}.
+
%%%----------------------------------------------------------------
-%% %%% This server/client has decided to disconnect via the state machine:
-disconnect(Msg=#ssh_msg_disconnect{description=Description}, _StateName, State0) ->
- State = send_msg(Msg, State0),
- disconnect_fun(Description, State),
- {stop, {shutdown,Description}, State}.
+start_rekeying(Role, D0) ->
+ {KeyInitMsg, SshPacket, Ssh} = ssh_transport:key_exchange_init_msg(D0#data.ssh_params),
+ send_bytes(SshPacket, D0),
+ D = D0#data{ssh_params = Ssh,
+ key_exchange_init_msg = KeyInitMsg},
+ {next_state, {kexinit,Role,renegotiate}, D}.
+
+
+init_renegotiate_timers(State, D) ->
+ {RekeyTimeout,_MaxSent} = ?GET_OPT(rekey_limit, (D#data.ssh_params)#ssh.opts),
+ {next_state, State, D, [{{timeout,renegotiate}, RekeyTimeout, none},
+ {{timeout,check_data_size}, ?REKEY_DATA_TIMOUT, none} ]}.
+
+
+pause_renegotiate_timers(State, D) ->
+ {next_state, State, D, [{{timeout,renegotiate}, infinity, none},
+ {{timeout,check_data_size}, infinity, none} ]}.
+
+check_data_rekeying(Role, D) ->
+ {ok, [{send_oct,SocketSentTotal}]} = inet:getstat(D#data.socket, [send_oct]),
+ SentSinceRekey = SocketSentTotal - D#data.last_size_rekey,
+ {_RekeyTimeout,MaxSent} = ?GET_OPT(rekey_limit, (D#data.ssh_params)#ssh.opts),
+ case check_data_rekeying_dbg(SentSinceRekey, MaxSent) of
+ true ->
+ start_rekeying(Role, D#data{last_size_rekey = SocketSentTotal});
+ _ ->
+ %% Not enough data sent for a re-negotiation. Restart timer.
+ {keep_state, D, {{timeout,check_data_size}, ?REKEY_DATA_TIMOUT, none}}
+ end.
+
+check_data_rekeying_dbg(SentSinceRekey, MaxSent) ->
+ %% This function is for the ssh_dbg to trace on. See dbg_trace/3 at the end.
+ SentSinceRekey >= MaxSent.
+
+%%%----------------------------------------------------------------
+%%% This server/client has decided to disconnect via the state machine:
+%%% The unused arguments are for debugging.
+
+send_disconnect(Code, DetailedText, Module, Line, StateName, D) ->
+ send_disconnect(Code, default_text(Code), DetailedText, Module, Line, StateName, D).
+
+send_disconnect(Code, Reason, DetailedText, Module, Line, StateName, D0) ->
+ Msg = #ssh_msg_disconnect{code = Code,
+ description = Reason},
+ D = send_msg(Msg, D0),
+ LogMsg = io_lib:format("Disconnects with code = ~p [RFC4253 11.1]: ~s",[Code,Reason]),
+ call_disconnectfun_and_log_cond(LogMsg, DetailedText, Module, Line, StateName, D),
+ {{shutdown,Reason}, D}.
+
+call_disconnectfun_and_log_cond(LogMsg, DetailedText, Module, Line, StateName, D) ->
+ case disconnect_fun(LogMsg, D) of
+ void ->
+ log(info, D,
+ io_lib:format("~s~n"
+ "State = ~p~n"
+ "Module = ~p, Line = ~p.~n"
+ "Details:~n ~s~n",
+ [LogMsg, StateName, Module, Line, DetailedText]));
+ _ ->
+ ok
+ end.
+
+
+default_text(?SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT) -> "Host not allowed to connect";
+default_text(?SSH_DISCONNECT_PROTOCOL_ERROR) -> "Protocol error";
+default_text(?SSH_DISCONNECT_KEY_EXCHANGE_FAILED) -> "Key exchange failed";
+default_text(?SSH_DISCONNECT_RESERVED) -> "Reserved";
+default_text(?SSH_DISCONNECT_MAC_ERROR) -> "Mac error";
+default_text(?SSH_DISCONNECT_COMPRESSION_ERROR) -> "Compression error";
+default_text(?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE) -> "Service not available";
+default_text(?SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED) -> "Protocol version not supported";
+default_text(?SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE) -> "Host key not verifiable";
+default_text(?SSH_DISCONNECT_CONNECTION_LOST) -> "Connection lost";
+default_text(?SSH_DISCONNECT_BY_APPLICATION) -> "By application";
+default_text(?SSH_DISCONNECT_TOO_MANY_CONNECTIONS) -> "Too many connections";
+default_text(?SSH_DISCONNECT_AUTH_CANCELLED_BY_USER) -> "Auth cancelled by user";
+default_text(?SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE) -> "Unable to connect using the available authentication methods";
+default_text(?SSH_DISCONNECT_ILLEGAL_USER_NAME) -> "Illegal user name".
%%%----------------------------------------------------------------
counterpart_versions(NumVsn, StrVsn, #ssh{role = server} = Ssh) ->
@@ -1857,12 +1990,11 @@ conn_info(client_version, #data{ssh_params=S}) -> {S#ssh.c_vsn, S#ssh.c_version}
conn_info(server_version, #data{ssh_params=S}) -> {S#ssh.s_vsn, S#ssh.s_version};
conn_info(peer, #data{ssh_params=S}) -> S#ssh.peer;
conn_info(user, D) -> D#data.auth_user;
-conn_info(sockname, D) -> {ok, SockName} = inet:sockname(D#data.socket),
- SockName;
+conn_info(sockname, #data{ssh_params=S}) -> S#ssh.local;
%% dbg options ( = not documented):
conn_info(socket, D) -> D#data.socket;
conn_info(chan_ids, D) ->
- ssh_channel:cache_foldl(fun(#channel{local_id=Id}, Acc) ->
+ ssh_client_channel:cache_foldl(fun(#channel{local_id=Id}, Acc) ->
[Id | Acc]
end, [], cache(D)).
@@ -1889,23 +2021,54 @@ fold_keys(Keys, Fun, Extra) ->
end, [], Keys).
%%%----------------------------------------------------------------
-log_error(Reason) ->
- Report = io_lib:format("Erlang ssh connection handler failed with reason:~n"
- " ~p~n"
- "Stacktrace:~n"
- " ~p~n",
- [Reason, erlang:get_stacktrace()]),
- error_logger:error_report(Report).
+log(Tag, D, Reason) ->
+ case atom_to_list(Tag) of % Dialyzer-technical reasons...
+ "error" -> do_log(error_msg, Reason, D);
+ "warning" -> do_log(warning_msg, Reason, D);
+ "info" -> do_log(info_msg, Reason, D)
+ end.
+
+do_log(F, Reason, #data{ssh_params = #ssh{role = Role} = S
+ }) ->
+ VSN =
+ case application:get_key(ssh,vsn) of
+ {ok,Vsn} -> Vsn;
+ undefined -> ""
+ end,
+ PeerVersion =
+ case Role of
+ server -> S#ssh.c_version;
+ client -> S#ssh.s_version
+ end,
+ CryptoInfo =
+ try
+ [{_,_,CI}] = crypto:info_lib(),
+ <<"(",CI/binary,")">>
+ catch
+ _:_ -> ""
+ end,
+ Other =
+ case Role of
+ server -> "Client";
+ client -> "Server"
+ end,
+ error_logger:F("Erlang SSH ~p ~s ~s.~n"
+ "~s: ~p~n"
+ "~s~n",
+ [Role, VSN, CryptoInfo,
+ Other, PeerVersion,
+ Reason]).
%%%----------------------------------------------------------------
not_connected_filter({connection_reply, _Data}) -> true;
not_connected_filter(_) -> false.
%%%----------------------------------------------------------------
+
+send_replies({Repls,C = #connection{}}, D) when is_list(Repls) ->
+ send_replies(Repls, D#data{connection_state=C});
send_replies(Repls, State) ->
- lists:foldl(fun get_repl/2,
- {[],State},
- Repls).
+ lists:foldl(fun get_repl/2, {[],State}, Repls).
get_repl({connection_reply,Msg}, {CallRepls,S}) ->
if is_record(Msg, ssh_msg_channel_success) ->
@@ -1922,19 +2085,21 @@ get_repl({channel_data,Pid,Data}, Acc) ->
get_repl({channel_request_reply,From,Data}, {CallRepls,S}) ->
{[{reply,From,Data}|CallRepls], S};
get_repl({flow_control,Cache,Channel,From,Msg}, {CallRepls,S}) ->
- ssh_channel:cache_update(Cache, Channel#channel{flow_control = undefined}),
+ ssh_client_channel:cache_update(Cache, Channel#channel{flow_control = undefined}),
{[{reply,From,Msg}|CallRepls], S};
get_repl({flow_control,From,Msg}, {CallRepls,S}) ->
{[{reply,From,Msg}|CallRepls], S};
-get_repl(noreply, Acc) ->
- Acc;
+%% get_repl(noreply, Acc) ->
+%% Acc;
+%% get_repl([], Acc) ->
+%% Acc;
get_repl(X, Acc) ->
exit({get_repl,X,Acc}).
%%%----------------------------------------------------------------
-define(CALL_FUN(Key,D), catch (?GET_OPT(Key, (D#data.ssh_params)#ssh.opts)) ).
-disconnect_fun({disconnect,Msg}, D) -> ?CALL_FUN(disconnectfun,D)(Msg);
+%%disconnect_fun({disconnect,Msg}, D) -> ?CALL_FUN(disconnectfun,D)(Msg);
disconnect_fun(Reason, D) -> ?CALL_FUN(disconnectfun,D)(Reason).
unexpected_fun(UnexpectedMessage, #data{ssh_params = #ssh{peer = {_,Peer} }} = D) ->
@@ -1981,60 +2146,12 @@ retry_fun(User, Reason, #data{ssh_params = #ssh{opts = Opts,
%%% Cache idle timer that closes the connection if there are no
%%% channels open for a while.
-cache_init_idle_timer(D) ->
- case ?GET_OPT(idle_time, (D#data.ssh_params)#ssh.opts) of
- infinity ->
- D#data{idle_timer_value = infinity,
- idle_timer_ref = infinity % A flag used later...
- };
- IdleTime ->
- %% We dont want to set the timeout on first connect
- D#data{idle_timer_value = IdleTime}
- end.
-
-
-cache_check_set_idle_timer(D = #data{idle_timer_ref = undefined,
- idle_timer_value = IdleTime}) ->
- %% No timer set - shall we set one?
- case ssh_channel:cache_info(num_entries, cache(D)) of
- 0 when IdleTime == infinity ->
- %% No. Meaningless to set a timer that fires in an infinite time...
- D;
- 0 ->
- %% Yes, we'll set one since the cache is empty and it should not
- %% be that for a specified time
- D#data{idle_timer_ref =
- erlang:send_after(IdleTime, self(), {'EXIT',[],"Timeout"})};
- _ ->
- %% No - there are entries in the cache
- D
- end;
-cache_check_set_idle_timer(D) ->
- %% There is already a timer set or the timeout time is infinite
- D.
-
-
-cache_cancel_idle_timer(D) ->
- case D#data.idle_timer_ref of
- infinity ->
- %% The timer is not activated
- D;
- undefined ->
- %% The timer is already cancelled
- D;
- TimerRef ->
- %% The timer is active
- erlang:cancel_timer(TimerRef),
- D#data{idle_timer_ref = undefined}
+cond_set_idle_timer(D) ->
+ case ssh_client_channel:cache_info(num_entries, cache(D)) of
+ 0 -> {{timeout,idle_time}, ?GET_OPT(idle_time, (D#data.ssh_params)#ssh.opts), none};
+ _ -> {{timeout,idle_time}, infinity, none}
end.
-
-cache_request_idle_timer_check(D = #data{idle_timer_value = infinity}) ->
- D;
-cache_request_idle_timer_check(D = #data{idle_timer_value = IdleTime}) ->
- erlang:send_after(IdleTime, self(), check_cache),
- D.
-
%%%----------------------------------------------------------------
start_channel_request_timer(_,_, infinity) ->
ok;
@@ -2089,3 +2206,164 @@ update_inet_buffers(Socket) ->
catch
_:_ -> ok
end.
+
+%%%################################################################
+%%%#
+%%%# Tracing
+%%%#
+
+dbg_trace(points, _, _) -> [terminate, disconnect, connections, connection_events, renegotiation];
+
+dbg_trace(flags, connections, A) -> [c] ++ dbg_trace(flags, terminate, A);
+dbg_trace(on, connections, A) -> dbg:tp(?MODULE, init_connection_handler, 3, x),
+ dbg_trace(on, terminate, A);
+dbg_trace(off, connections, A) -> dbg:ctpg(?MODULE, init_connection_handler, 3),
+ dbg_trace(off, terminate, A);
+dbg_trace(format, connections, {call, {?MODULE,init_connection_handler, [Role, Sock, Opts]}}) ->
+ DefaultOpts = ssh_options:handle_options(Role,[]),
+ ExcludedKeys = [internal_options, user_options],
+ NonDefaultOpts =
+ maps:filter(fun(K,V) ->
+ case lists:member(K,ExcludedKeys) of
+ true ->
+ false;
+ false ->
+ V =/= (catch maps:get(K,DefaultOpts))
+ end
+ end,
+ Opts),
+ {ok, {IPp,Portp}} = inet:peername(Sock),
+ {ok, {IPs,Ports}} = inet:sockname(Sock),
+ [io_lib:format("Starting ~p connection:\n",[Role]),
+ io_lib:format("Socket = ~p, Peer = ~s:~p, Local = ~s:~p,~n"
+ "Non-default options:~n~p",
+ [Sock,inet:ntoa(IPp),Portp,inet:ntoa(IPs),Ports,
+ NonDefaultOpts])
+ ];
+dbg_trace(format, connections, F) ->
+ dbg_trace(format, terminate, F);
+
+dbg_trace(flags, connection_events, _) -> [c];
+dbg_trace(on, connection_events, _) -> dbg:tp(?MODULE, handle_event, 4, x);
+dbg_trace(off, connection_events, _) -> dbg:ctpg(?MODULE, handle_event, 4);
+dbg_trace(format, connection_events, {call, {?MODULE,handle_event, [EventType, EventContent, State, _Data]}}) ->
+ ["Connection event\n",
+ io_lib:format("EventType: ~p~nEventContent: ~p~nState: ~p~n", [EventType, EventContent, State])
+ ];
+dbg_trace(format, connection_events, {return_from, {?MODULE,handle_event,4}, Ret}) ->
+ ["Connection event result\n",
+ io_lib:format("~p~n", [event_handler_result(Ret)])
+ ];
+
+dbg_trace(flags, renegotiation, _) -> [c];
+dbg_trace(on, renegotiation, _) -> dbg:tpl(?MODULE, init_renegotiate_timers, 2, x),
+ dbg:tpl(?MODULE, pause_renegotiate_timers, 2, x),
+ dbg:tpl(?MODULE, check_data_rekeying_dbg, 2, x),
+ dbg:tpl(?MODULE, start_rekeying, 2, x);
+dbg_trace(off, renegotiation, _) -> dbg:ctpl(?MODULE, init_renegotiate_timers, 2),
+ dbg:ctpl(?MODULE, pause_renegotiate_timers, 2),
+ dbg:ctpl(?MODULE, check_data_rekeying_dbg, 2),
+ dbg:ctpl(?MODULE, start_rekeying, 2);
+dbg_trace(format, renegotiation, {call, {?MODULE,init_renegotiate_timers,[_State,D]}}) ->
+ ["Renegotiation init\n",
+ io_lib:format("rekey_limit: ~p ({ms,bytes})~ncheck_data_size: ~p (ms)~n",
+ [?GET_OPT(rekey_limit, (D#data.ssh_params)#ssh.opts),
+ ?REKEY_DATA_TIMOUT])
+ ];
+dbg_trace(format, renegotiation, {call, {?MODULE,pause_renegotiate_timers,[_State,_D]}}) ->
+ ["Renegotiation pause\n"];
+dbg_trace(format, renegotiation, {call, {?MODULE,start_rekeying,[_Role,_D]}}) ->
+ ["Renegotiation start rekeying\n"];
+dbg_trace(format, renegotiation, {call, {?MODULE,check_data_rekeying_dbg,[SentSinceRekey, MaxSent]}}) ->
+ ["Renegotiation check data sent\n",
+ io_lib:format("TotalSentSinceRekey: ~p~nMaxBeforeRekey: ~p~nStartRekey: ~p~n",
+ [SentSinceRekey, MaxSent, SentSinceRekey >= MaxSent])
+ ];
+
+
+
+dbg_trace(flags, terminate, _) -> [c];
+dbg_trace(on, terminate, _) -> dbg:tp(?MODULE, terminate, 3, x);
+dbg_trace(off, terminate, _) -> dbg:ctpg(?MODULE, terminate, 3);
+dbg_trace(format, terminate, {call, {?MODULE,terminate, [Reason, StateName, D]}}) ->
+ ExtraInfo =
+ try
+ {conn_info(peer,D),
+ conn_info(user,D),
+ conn_info(sockname,D)}
+ of
+ {{_,{IPp,Portp}}, Usr, {IPs,Ports}} when is_tuple(IPp), is_tuple(IPs),
+ is_integer(Portp), is_integer(Ports) ->
+ io_lib:format("Peer=~s:~p, Local=~s:~p, User=~p",
+ [inet:ntoa(IPp),Portp,inet:ntoa(IPs),Ports,Usr]);
+ {Peer,Usr,Sockname} ->
+ io_lib:format("Peer=~p, Local=~p, User=~p",[Peer,Sockname,Usr])
+ catch
+ _:_ ->
+ ""
+ end,
+ if
+ Reason == normal ;
+ Reason == shutdown ;
+ element(1,Reason) == shutdown
+ ->
+ ["Connection Terminating:\n",
+ io_lib:format("Reason: ~p, StateName: ~p~n~s", [Reason, StateName, ExtraInfo])
+ ];
+
+ true ->
+ ["Connection Terminating:\n",
+ io_lib:format("Reason: ~p, StateName: ~p~n~s~nStateData = ~p",
+ [Reason, StateName, ExtraInfo, state_data2proplist(D)])
+ ]
+ end;
+
+dbg_trace(flags, disconnect, _) -> [c];
+dbg_trace(on, disconnect, _) -> dbg:tpl(?MODULE, send_disconnect, 7, x);
+dbg_trace(off, disconnect, _) -> dbg:ctpl(?MODULE, send_disconnect, 7);
+dbg_trace(format, disconnect, {call,{?MODULE,send_disconnect,
+ [Code, Reason, DetailedText, Module, Line, StateName, _D]}}) ->
+ ["Disconnecting:\n",
+ io_lib:format(" Module = ~p, Line = ~p, StateName = ~p,~n"
+ " Code = ~p, Reason = ~p,~n"
+ " DetailedText =~n"
+ " ~p",
+ [Module, Line, StateName, Code, Reason, lists:flatten(DetailedText)])
+ ].
+
+
+event_handler_result({next_state, NextState, _NewData}) ->
+ {next_state, NextState, "#data{}"};
+event_handler_result({next_state, NextState, _NewData, Actions}) ->
+ {next_state, NextState, "#data{}", Actions};
+event_handler_result(R) ->
+ state_callback_result(R).
+
+state_callback_result({keep_state, _NewData}) ->
+ {keep_state, "#data{}"};
+state_callback_result({keep_state, _NewData, Actions}) ->
+ {keep_state, "#data{}", Actions};
+state_callback_result(keep_state_and_data) ->
+ keep_state_and_data;
+state_callback_result({keep_state_and_data, Actions}) ->
+ {keep_state_and_data, Actions};
+state_callback_result({repeat_state, _NewData}) ->
+ {repeat_state, "#data{}"};
+state_callback_result({repeat_state, _NewData, Actions}) ->
+ {repeat_state, "#data{}", Actions};
+state_callback_result(repeat_state_and_data) ->
+ repeat_state_and_data;
+state_callback_result({repeat_state_and_data, Actions}) ->
+ {repeat_state_and_data, Actions};
+state_callback_result(stop) ->
+ stop;
+state_callback_result({stop, Reason}) ->
+ {stop, Reason};
+state_callback_result({stop, Reason, _NewData}) ->
+ {stop, Reason, "#data{}"};
+state_callback_result({stop_and_reply, Reason, Replies}) ->
+ {stop_and_reply, Reason, Replies};
+state_callback_result({stop_and_reply, Reason, Replies, _NewData}) ->
+ {stop_and_reply, Reason, Replies, "#data{}"};
+state_callback_result(R) ->
+ R.
diff --git a/lib/ssh/src/ssh_connection_sup.erl b/lib/ssh/src/ssh_connection_sup.erl
index 2e8450090a..79804b8630 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-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_daemon_channel.erl b/lib/ssh/src/ssh_daemon_channel.erl
index 6ca93eff44..30c4773a7a 100644
--- a/lib/ssh/src/ssh_daemon_channel.erl
+++ b/lib/ssh/src/ssh_daemon_channel.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,7 +25,7 @@
-module(ssh_daemon_channel).
-%% API to special server side channel that can be pluged into the erlang ssh daemeon
+%% API to server side channel that can be pluged into the erlang ssh daemeon
-callback init(Args :: term()) ->
{ok, State :: term()} | {ok, State :: term(), timeout() | hibernate} |
{stop, Reason :: term()} | ignore.
@@ -36,34 +36,20 @@
term().
-callback handle_msg(Msg ::term(), State :: term()) ->
- {ok, State::term()} | {stop, ChannelId::integer(), State::term()}.
--callback handle_ssh_msg({ssh_cm, ConnectionRef::term(), SshMsg::term()},
+ {ok, State::term()} | {stop, ChannelId::ssh:channel_id(), State::term()}.
+-callback handle_ssh_msg({ssh_cm, ConnectionRef::ssh:connection_ref(), SshMsg::term()},
State::term()) -> {ok, State::term()} |
- {stop, ChannelId::integer(),
+ {stop, ChannelId::ssh:channel_id(),
State::term()}.
-%%% API
--export([start/4, start/5, start_link/4, start_link/5, enter_loop/1]).
-
-%% gen_server callbacks
--export([init/1, terminate/2]).
-
-start(ConnectionManager, ChannelId, CallBack, CbInitArgs) ->
- ssh_channel:start(ConnectionManager, ChannelId, CallBack, CbInitArgs, undefined).
-
-start(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec) ->
- ssh_channel:start(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec).
-
-start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs) ->
- ssh_channel:start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, undefined).
+%%% Internal API
+-export([start_link/5,
+ get_print_info/1
+ ]).
start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec) ->
- ssh_channel:start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec).
+ ssh_server_channel:start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec).
-enter_loop(State) ->
- ssh_channel:enter_loop(State).
-init(Args) ->
- ssh_channel:init(Args).
-terminate(Reason, State) ->
- ssh_channel:terminate(Reason, State).
+get_print_info(Pid) ->
+ ssh_server_channel:get_print_info(Pid).
diff --git a/lib/ssh/src/ssh_dbg.erl b/lib/ssh/src/ssh_dbg.erl
index eb2c2848f3..43ac4c0ccf 100644
--- a/lib/ssh/src/ssh_dbg.erl
+++ b/lib/ssh/src/ssh_dbg.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -20,339 +20,119 @@
%%
+%%% Purpose:
+%%% This module implements support for using the Erlang trace in a simple way for ssh
+%%% debugging.
+%%%
+%%% Begin the session with ssh_dbg:start(). This will do a dbg:start() if needed and
+%%% then dbg:p/2 to set some flags.
+%%%
+%%% Next select trace points to activate: for example plain text printouts of messages
+%%% sent or received. This is switched on and off with ssh_dbg:on(TracePoint(s)) and
+%%% ssh_dbg:off(TracePoint(s)). For example:
+%%%
+%%% ssh_dbg:on(messages) -- switch on printing plain text messages
+%%% ssh_dbg:on([alg,terminate]) -- switch on printing info about algorithm negotiation
+%%% ssh_dbg:on() -- switch on all ssh debugging
+%%%
+%%% To switch, use the off/0 or off/1 function in the same way, for example:
+%%%
+%%% ssh_dbg:off(alg) -- switch off algorithm negotiation tracing, but keep all other
+%%% ssh_dbg:off() -- switch off all ssh debugging
+%%%
+%%% Present the trace result with some other method than the default io:format/2:
+%%% ssh_dbg:start(fun(Format,Args) ->
+%%% my_special( io_lib:format(Format,Args) )
+%%% end)
+%%%
+
-module(ssh_dbg).
--export([messages/0, messages/1, messages/2, messages/3,
- auth/0, auth/1, auth/2, auth/3,
- algs/0, algs/1, algs/2, algs/3,
- hostkey/0, hostkey/1, hostkey/2, hostkey/3,
- stop/0
+-export([start/0, start/1,
+ stop/0,
+ start_server/0,
+ start_tracer/0, start_tracer/1,
+ on/1, on/0,
+ off/1, off/0,
+ go_on/0,
+ %% Circular buffer
+ cbuf_start/0, cbuf_start/1,
+ cbuf_stop_clear/0,
+ cbuf_in/1,
+ cbuf_list/0,
+ hex_dump/1, hex_dump/2,
+ fmt_cbuf_items/0, fmt_cbuf_item/1
]).
-export([shrink_bin/1,
- wr_record/3]).
+ reduce_state/1,
+ wr_record/3]).
+
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2]).
-include("ssh.hrl").
-include("ssh_transport.hrl").
-include("ssh_connect.hrl").
-include("ssh_auth.hrl").
-%%%================================================================
-messages() -> start(msg).
-messages(F) -> start(msg,F).
-messages(F,X) -> start(msg,F,X).
-messages(F,M,I) -> start(msg,F,M,I).
-
-auth() -> start(auth).
-auth(F) -> start(auth,F).
-auth(F,X) -> start(auth,F,X).
-auth(F,M,I) -> start(auth,F,M,I).
-
-algs() -> start(algs).
-algs(F) -> start(algs,F).
-algs(F,X) -> start(algs,F,X).
-algs(F,M,I) -> start(algs,F,M,I).
-
-hostkey() -> start(hostkey).
-hostkey(F) -> start(hostkey,F).
-hostkey(F,X) -> start(hostkey,F,X).
-hostkey(F,M,I) -> start(hostkey,F,M,I).
-
-stop() -> dbg:stop().
+-behaviour(gen_server).
+-define(SERVER, ?MODULE).
-%%%----------------------------------------------------------------
-start(Type) -> start(Type, fun io:format/2).
-
-start(Type, F) when is_function(F,2) -> start(Type, fmt_fun(F));
-start(Type, F) when is_function(F,3) -> start(Type, F, id_fun()).
+-define(CALL_TIMEOUT, 15000). % 3x the default
-start(Type, WriteFun, MangleArgFun) when is_function(WriteFun, 3),
- is_function(MangleArgFun, 1) ->
- start(Type, WriteFun, MangleArgFun, []);
-start(Type, WriteFun, InitValue) ->
- start(Type, WriteFun, id_fun(), InitValue).
+%%%================================================================
-start(Type, WriteFun, MangleArgFun, InitValue) when is_function(WriteFun, 3),
- is_function(MangleArgFun, 1) ->
- cond_start(Type, WriteFun, MangleArgFun, InitValue),
- dbg_ssh(Type).
+-define(ALL_DBG_TYPES, get_all_dbg_types()).
-%%%----------------------------------------------------------------
-fmt_fun(F) -> fun(Fmt,Args,Data) -> F(Fmt,Args), Data end.
+start() -> start(fun io:format/2).
-id_fun() -> fun(X) -> X end.
+start(IoFmtFun) when is_function(IoFmtFun,2) ; is_function(IoFmtFun,3) ->
+ start_server(),
+ catch dbg:start(),
+ start_tracer(IoFmtFun),
+ dbg:p(all, get_all_trace_flags()),
+ ?ALL_DBG_TYPES.
-%%%----------------------------------------------------------------
-dbg_ssh(What) ->
- case [E || E <- lists:flatten(dbg_ssh0(What)),
- element(1,E) =/= ok] of
- [] -> ok;
- Other -> Other
- end.
-
-
-dbg_ssh0(auth) ->
- [dbg:tp(ssh_transport,hello_version_msg,1, x),
- dbg:tp(ssh_transport,handle_hello_version,1, x),
- dbg:tp(ssh_message,encode,1, x),
- dbg:tpl(ssh_transport,select_algorithm,4, x),
- dbg:tpl(ssh_connection_handler,ext_info,2, x),
- lists:map(fun(F) -> dbg:tp(ssh_auth, F, x) end,
- [publickey_msg, password_msg, keyboard_interactive_msg])
- ];
-
-dbg_ssh0(algs) ->
- [dbg:tpl(ssh_transport,select_algorithm,4, x),
- dbg:tpl(ssh_connection_handler,ext_info,2, x)
- ];
-
-dbg_ssh0(hostkey) ->
- [dbg:tpl(ssh_transport, verify_host_key, 4, x),
- dbg:tp(ssh_transport, verify, 4, x),
- dbg:tpl(ssh_transport, known_host_key, 3, x),
-%% dbg:tpl(ssh_transport, accepted_host, 4, x),
- dbg:tpl(ssh_transport, add_host_key, 4, x),
- dbg:tpl(ssh_transport, is_host_key, 5, x)
- ];
-
-dbg_ssh0(msg) ->
- [dbg_ssh0(hostkey),
- dbg_ssh0(auth),
- dbg:tp(ssh_message,encode,1, x),
- dbg:tp(ssh_message,decode,1, x),
- dbg:tpl(ssh_transport,select_algorithm,4, x),
- dbg:tp(ssh_transport,hello_version_msg,1, x),
- dbg:tp(ssh_transport,handle_hello_version,1, x),
- dbg:tpl(ssh_connection_handler,ext_info,2, x)
- ].
-
-
-%%%================================================================
-cond_start(Type, WriteFun, MangleArgFun, Init) ->
+stop() ->
try
- dbg:start(),
- setup_tracer(Type, WriteFun, MangleArgFun, Init),
- dbg:p(new,[c,timestamp])
+ dbg:stop_clear(),
+ gen_server:stop(?SERVER)
catch
_:_ -> ok
end.
+start_server() ->
+ gen_server:start({local,?SERVER}, ?MODULE, [], []).
-msg_formater(msg, {trace_ts,Pid,call,{ssh_message,encode,[Msg]},TS}, D) ->
- fmt("~n~s SEND ~p ~s~n", [ts(TS),Pid,wr_record(shrink_bin(Msg))], D);
-msg_formater(msg, {trace_ts,_Pid,return_from,{ssh_message,encode,1},_Res,_TS}, D) ->
- D;
-
-msg_formater(msg, {trace_ts,_Pid,call,{ssh_message,decode,_},_TS}, D) ->
- D;
-msg_formater(msg, {trace_ts,Pid,return_from,{ssh_message,decode,1},Msg,TS}, D) ->
- Extra =
- case Msg of
- #ssh_msg_userauth_info_request{data = D0} ->
- try ssh_message:decode_keyboard_interactive_prompts(D0, [])
- of
- Acc ->
- io_lib:format(" -- decoded data:~n", []) ++
- element(1,
- lists:mapfoldl(
- fun({Prompt,Echo}, N) ->
- {io_lib:format(" prompt[~p]: \"~s\" (echo=~p)~n",[N,Prompt,Echo]), N+1}
- end, 1, Acc))
- catch
- _:_ ->
- ""
- end;
- _ ->
- ""
+
+start_tracer() -> start_tracer(fun io:format/2).
+
+start_tracer(WriteFun) when is_function(WriteFun,2) ->
+ start_tracer(fun(F,A,S) -> WriteFun(F,A), S end);
+start_tracer(WriteFun) when is_function(WriteFun,3) ->
+ start_tracer(WriteFun, undefined).
+
+
+start_tracer(WriteFun, InitAcc) when is_function(WriteFun, 3) ->
+ Handler =
+ fun(Arg, Acc0) ->
+ try_all_types_in_all_modules(gen_server:call(?SERVER, get_on, ?CALL_TIMEOUT),
+ Arg, WriteFun,
+ Acc0)
end,
- fmt("~n~s ~p RECV ~s~s~n", [ts(TS),Pid,wr_record(shrink_bin(Msg)),Extra], D);
-
-msg_formater(_auth, {trace_ts,Pid,return_from,{ssh_message,decode,1},#ssh_msg_userauth_failure{authentications=As},TS}, D) ->
- fmt("~n~s ~p Client login FAILURE. Try ~s~n", [ts(TS),Pid,As], D);
-
-msg_formater(_auth, {trace_ts,Pid,return_from,{ssh_message,decode,1},#ssh_msg_userauth_success{},TS}, D) ->
- fmt("~n~s ~p Client login SUCCESS~n", [ts(TS),Pid], D);
-
-
-msg_formater(_, {trace_ts,_Pid,call,{ssh_transport,select_algorithm,_},_TS}, D) ->
- D;
-msg_formater(_, {trace_ts,Pid,return_from,{ssh_transport,select_algorithm,_},{ok,Alg},TS}, D) ->
- fmt("~n~s ~p ALGORITHMS~n~s~n", [ts(TS),Pid, wr_record(Alg)], D);
-
-msg_formater(_, {trace_ts,_Pid,call,{ssh_transport,hello_version_msg,_},_TS}, D) ->
- D;
-msg_formater(_, {trace_ts,Pid,return_from,{ssh_transport,hello_version_msg,1},Hello,TS}, D) ->
- fmt("~n~s ~p TCP SEND HELLO~n ~p~n", [ts(TS),Pid,lists:flatten(Hello)], D);
-
-msg_formater(_, {trace_ts,Pid,call,{ssh_transport,handle_hello_version,[Hello]},TS}, D) ->
- fmt("~n~s ~p RECV HELLO~n ~p~n", [ts(TS),Pid,lists:flatten(Hello)], D);
-msg_formater(_, {trace_ts,_Pid,return_from,{ssh_transport,handle_hello_version,1},_,_TS}, D) ->
- D;
-
-msg_formater(_, {trace_ts,Pid,call,{ssh_connection_handler,ext_info,[{"server-sig-algs",SigAlgs},State]},TS}, D) ->
- try lists:keyfind(ssh, 1, tuple_to_list(State)) of
- false ->
- D;
- #ssh{userauth_pubkeys = PKs} ->
- fmt("~n~s ~p Client got suggestion to use user public key sig-algs~n ~p~n and can use~n ~p~n",
- [ts(TS),Pid,string:tokens(SigAlgs,","),PKs], D)
- catch
- _:_ ->
- D
- end;
-
-msg_formater(_, {trace_ts,Pid,return_from,{ssh_connection_handler,ext_info,2},State,TS}, D) ->
- try lists:keyfind(ssh, 1, tuple_to_list(State)) of
- false ->
- D;
- #ssh{userauth_pubkeys = PKs} ->
- fmt("~n~s ~p Client will try user public key sig-algs~n ~p~n", [ts(TS),Pid,PKs], D)
- catch
- _:_ ->
- D
- end;
-
-msg_formater(_, {trace_ts,Pid,call, {ssh_transport,verify_host_key,[_Ssh,_PK,_Dgst,{AlgStr,_Sign}]},TS}, D) ->
- fmt("~n~s ~p Client got a ~s hostkey. Will try to verify it~n", [ts(TS),Pid,AlgStr], D);
-msg_formater(_, {trace_ts,Pid,return_from, {ssh_transport,verify_host_key,4}, Result, TS}, D) ->
- case Result of
- ok -> fmt("~n~s ~p Hostkey verified.~n", [ts(TS),Pid], D);
- {error,E} ->
- fmt("~n~s ~p ***** Hostkey NOT verified: ~p ******!~n", [ts(TS),Pid,E], D);
- _ -> fmt("~n~s ~p ***** Hostkey is NOT verified: ~p ******!~n", [ts(TS),Pid,Result], D)
- end;
-
-msg_formater(_, {trace_ts,Pid,return_from, {ssh_transport,verify,4}, Result, TS}, D) ->
- case Result of
- true -> D;
- _ -> fmt("~n~s ~p Couldn't verify the signature!~n", [ts(TS),Pid], D)
- end;
-
-msg_formater(_, {trace_ts,_Pid,call, {ssh_transport,is_host_key,_}, _TS}, D) -> D;
-msg_formater(_, {trace_ts,Pid,return_from, {ssh_transport,is_host_key,5}, {CbMod,Result}, TS}, D) ->
- case Result of
- true -> fmt("~n~s ~p Hostkey found by ~p.~n", [ts(TS),Pid,CbMod], D);
- _ -> fmt("~n~s ~p Hostkey NOT found by ~p.~n", [ts(TS),Pid,CbMod], D)
- end;
-
-msg_formater(_, {trace_ts,_Pid,call, {ssh_transport,add_host_key,_}, _TS}, D) -> D;
-msg_formater(_, {trace_ts,Pid,return_from, {ssh_transport,add_host_key,4}, {CbMod,Result}, TS}, D) ->
- case Result of
- ok -> fmt("~n~s ~p New hostkey added by ~p.~n", [ts(TS),Pid,CbMod], D);
- _ -> D
- end;
-
-msg_formater(_, {trace_ts,_Pid,call,{ssh_transport,known_host_key,_},_TS}, D) -> D;
-msg_formater(_, {trace_ts,Pid,return_from, {ssh_transport,known_host_key,3}, Result, TS}, D) ->
- case Result of
- ok -> D;
- {error,E} -> fmt("~n~s ~p Hostkey addition failed: ~p~n", [ts(TS),Pid,E], D);
- _ -> fmt("~n~s ~p Hostkey addition: ~p~n", [ts(TS),Pid,Result], D)
- end;
-
-msg_formater(_, {trace_ts,Pid,call,{ssh_auth,publickey_msg,[[SigAlg,#ssh{user=User}]]},TS}, D) ->
- fmt("~n~s ~p Client will try to login user ~p with method: public key algorithm ~p~n", [ts(TS),Pid,User,SigAlg], D);
-msg_formater(_, {trace_ts,Pid,return_from,{ssh_auth,publickey_msg,1},{not_ok,#ssh{user=User}},TS}, D) ->
- fmt("~s ~p User ~p can't use that kind of public key~n", [ts(TS),Pid,User], D);
-msg_formater(_, {trace_ts,_Pid,return_from,{ssh_auth,publickey_msg,1},_,_TS}, D) -> D;
-
-msg_formater(_, {trace_ts,Pid,call,{ssh_auth,password_msg,[[#ssh{user=User}]]},TS}, D) ->
- fmt("~n~s ~p Client will try to login user ~p with method: password~n", [ts(TS),Pid,User], D);
-msg_formater(_, {trace_ts,Pid,return_from,{ssh_auth,password_msg,1},{not_ok,#ssh{user=User}},TS}, D) ->
- fmt("~s ~p User ~p can't use method password as login method~n", [ts(TS),Pid,User], D);
-msg_formater(_, {trace_ts,_Pid,return_from,{ssh_auth,password_msg,1},_Result,_TS}, D) -> D;
-
-msg_formater(_, {trace_ts,Pid,call,{ssh_auth,keyboard_interactive_msg,[[#ssh{user=User}]]},TS}, D) ->
- fmt("~n~s ~p Client will try to login user ~p with method: keyboard-interactive~n", [ts(TS),Pid,User], D);
-msg_formater(_, {trace_ts,Pid,return_from,{ssh_auth,keyboard_interactive_msg,1},{not_ok,#ssh{user=User}},TS}, D) ->
- fmt("~s ~p User ~p can't use method keyboard-interactive as login method~n", [ts(TS),Pid,User], D);
-msg_formater(_, {trace_ts,_Pid,return_from,{ssh_auth,keyboard_interactive_msg,1},_Result,_TS}, D) -> D;
-
-msg_formater(msg, {trace_ts,Pid,send,{tcp,Sock,Bytes},Pid,TS}, D) ->
- fmt("~n~s ~p TCP SEND on ~p~n ~p~n", [ts(TS),Pid,Sock, shrink_bin(Bytes)], D);
-
-msg_formater(msg, {trace_ts,Pid,send,{tcp,Sock,Bytes},Dest,TS}, D) ->
- fmt("~n~s ~p TCP SEND from ~p TO ~p~n ~p~n", [ts(TS),Pid,Sock,Dest, shrink_bin(Bytes)], D);
-
-msg_formater(msg, {trace_ts,Pid,send,ErlangMsg,Dest,TS}, D) ->
- fmt("~n~s ~p ERL MSG SEND TO ~p~n ~p~n", [ts(TS),Pid,Dest, shrink_bin(ErlangMsg)], D);
-
-
-msg_formater(msg, {trace_ts,Pid,'receive',{tcp,Sock,Bytes},TS}, D) ->
- fmt("~n~s ~p TCP RECEIVE on ~p~n ~p~n", [ts(TS),Pid,Sock,shrink_bin(Bytes)], D);
-
-msg_formater(msg, {trace_ts,Pid,'receive',ErlangMsg,TS}, D) ->
- fmt("~n~s ~p ERL MSG RECEIVE~n ~p~n", [ts(TS),Pid,shrink_bin(ErlangMsg)], D);
-
-
-msg_formater(_, _M, D) ->
- fmt("~nDBG other ~n~p~n", [shrink_bin(_M)], D),
- D.
+ dbg:tracer(process, {Handler,InitAcc}).
%%%----------------------------------------------------------------
--record(data, {writer,
- initialized,
- acc}).
-
-fmt(Fmt, Args, D=#data{initialized=false}) ->
- fmt(Fmt, Args,
- D#data{acc = (D#data.writer)("~s~n", [initial_info()], D#data.acc),
- initialized = true}
- );
-fmt(Fmt, Args, D=#data{writer=Write, acc=Acc}) ->
- D#data{acc = Write(Fmt,Args,Acc)}.
-
-ts({_,_,Usec}=Now) ->
- {_Date,{HH,MM,SS}} = calendar:now_to_local_time(Now),
- io_lib:format("~.2.0w:~.2.0w:~.2.0w.~.6.0w",[HH,MM,SS,Usec]);
-ts(_) ->
- "-".
-
-setup_tracer(Type, WriteFun, MangleArgFun, Init) ->
- Handler = fun(Arg, D) ->
- msg_formater(Type, MangleArgFun(Arg), D)
- end,
- InitialData = #data{writer = WriteFun,
- initialized = false,
- acc = Init},
- {ok,_} = dbg:tracer(process, {Handler, InitialData}),
- ok.
+on() -> on(?ALL_DBG_TYPES).
+on(Type) -> switch(on, Type).
-initial_info() ->
- Lines =
- [ts(erlang:timestamp()),
- "",
- "SSH:"]
- ++ as_list_of_lines(case application:get_key(ssh,vsn) of
- {ok,Vsn} -> Vsn;
- _ -> "(ssh not started)"
- end)
- ++ ["",
- "Cryptolib:"]
- ++ as_list_of_lines(crypto:info_lib())
- ++ ["",
- "Crypto app:"]
- ++ as_list_of_lines(crypto:supports()),
- W = max_len(Lines),
- append_lines([line_of($*, W+4)]
- ++ prepend_lines("* ", Lines)
- ++ [line_of($-, W+4)],
- io_lib:nl()
- ).
-
+off() -> off(?ALL_DBG_TYPES). % A bit overkill...
+off(Type) -> switch(off, Type).
-as_list_of_lines(Term) ->
- prepend_lines(" ",
- string:tokens(lists:flatten(io_lib:format("~p",[Term])),
- io_lib:nl() % Get line endings in current OS
- )
- ).
-
-line_of(Char,W) -> lists:duplicate(W,Char).
-max_len(L) -> lists:max([length(S) || S<-L]).
-append_lines(L, X) -> [S++X || S<-L].
-prepend_lines(X, L) -> [X++S || S<-L].
+go_on() ->
+ IsOn = gen_server:call(?SERVER, get_on, ?CALL_TIMEOUT),
+ on(IsOn).
%%%----------------------------------------------------------------
shrink_bin(B) when is_binary(B), size(B)>256 -> {'*** SHRINKED BIN',
@@ -365,69 +145,370 @@ shrink_bin(L) when is_list(L) -> lists:map(fun shrink_bin/1, L);
shrink_bin(T) when is_tuple(T) -> list_to_tuple(shrink_bin(tuple_to_list(T)));
shrink_bin(X) -> X.
+%%%----------------------------------------------------------------
+%% Replace last element (the state) with "#<state-name>{}"
+reduce_state(T) ->
+ try
+ erlang:setelement(size(T),
+ T,
+ lists:concat(['#',element(1,element(size(T),T)),'{}'])
+ )
+ catch
+ _:_ ->
+ T
+ end.
+
+%%%================================================================
+-record(data, {
+ types_on = []
+ }).
+
%%%----------------------------------------------------------------
--define(wr_record(N,BlackList), wr_record(R=#N{}) -> wr_record(R, record_info(fields,N), BlackList)).
-
--define(wr_record(N), ?wr_record(N, [])).
-
-
-?wr_record(alg);
-
-?wr_record(ssh_msg_disconnect);
-?wr_record(ssh_msg_ignore);
-?wr_record(ssh_msg_unimplemented);
-?wr_record(ssh_msg_debug);
-?wr_record(ssh_msg_service_request);
-?wr_record(ssh_msg_service_accept);
-?wr_record(ssh_msg_kexinit);
-?wr_record(ssh_msg_kexdh_init);
-?wr_record(ssh_msg_kexdh_reply);
-?wr_record(ssh_msg_newkeys);
-?wr_record(ssh_msg_ext_info);
-?wr_record(ssh_msg_kex_dh_gex_request);
-?wr_record(ssh_msg_kex_dh_gex_request_old);
-?wr_record(ssh_msg_kex_dh_gex_group);
-?wr_record(ssh_msg_kex_dh_gex_init);
-?wr_record(ssh_msg_kex_dh_gex_reply);
-?wr_record(ssh_msg_kex_ecdh_init);
-?wr_record(ssh_msg_kex_ecdh_reply);
-
-?wr_record(ssh_msg_userauth_request);
-?wr_record(ssh_msg_userauth_failure);
-?wr_record(ssh_msg_userauth_success);
-?wr_record(ssh_msg_userauth_banner);
-?wr_record(ssh_msg_userauth_passwd_changereq);
-?wr_record(ssh_msg_userauth_pk_ok);
-?wr_record(ssh_msg_userauth_info_request);
-?wr_record(ssh_msg_userauth_info_response);
-
-?wr_record(ssh_msg_global_request);
-?wr_record(ssh_msg_request_success);
-?wr_record(ssh_msg_request_failure);
-?wr_record(ssh_msg_channel_open);
-?wr_record(ssh_msg_channel_open_confirmation);
-?wr_record(ssh_msg_channel_open_failure);
-?wr_record(ssh_msg_channel_window_adjust);
-?wr_record(ssh_msg_channel_data);
-?wr_record(ssh_msg_channel_extended_data);
-?wr_record(ssh_msg_channel_eof);
-?wr_record(ssh_msg_channel_close);
-?wr_record(ssh_msg_channel_request);
-?wr_record(ssh_msg_channel_success);
-?wr_record(ssh_msg_channel_failure);
-
-wr_record(R) -> io_lib:format('~p~n',[R]).
+init(_) ->
+ {ok, #data{}}.
+
+%%%----------------------------------------------------------------
+handle_call({switch,on,Types}, _From, D) ->
+ NowOn = lists:usort(Types ++ D#data.types_on),
+ call_modules(on, Types, NowOn),
+ {reply, {ok,NowOn}, D#data{types_on = NowOn}};
+
+handle_call({switch,off,Types}, _From, D) ->
+ StillOn = D#data.types_on -- Types,
+ call_modules(off, Types, StillOn),
+ call_modules(on, StillOn, StillOn),
+ {reply, {ok,StillOn}, D#data{types_on = StillOn}};
+
+handle_call(get_on, _From, D) ->
+ {reply, D#data.types_on, D};
+
+handle_call(C, _From, D) ->
+ io:format('*** Unknown call: ~p~n',[C]),
+ {reply, {error,{unknown_call,C}}, D}.
+
+handle_cast(C, D) ->
+ io:format('*** Unknown cast: ~p~n',[C]),
+ {noreply, D}.
+
+handle_info(C, D) ->
+ io:format('*** Unknown info: ~p~n',[C]),
+ {noreply, D}.
+
+
+%%%================================================================
+
+%%%----------------------------------------------------------------
+ssh_modules_with_trace() ->
+ {ok,AllSshModules} = application:get_key(ssh, modules),
+ [M || M <- AllSshModules,
+ lists:member({dbg_trace,3}, M:module_info(exports))].
+
+%%%----------------------------------------------------------------
+get_all_trace_flags() ->
+ get_all_trace_flags(ssh_modules_with_trace()).
+
+get_all_trace_flags(Modules) ->
+ lists:usort(
+ lists:flatten(
+ lists:foldl(
+ fun(Type, Acc) ->
+ call_modules(flags, Type, undefined, Acc, Modules)
+ end, [timestamp], ?ALL_DBG_TYPES))).
+
+%%%----------------------------------------------------------------
+get_all_dbg_types() ->
+ lists:usort(
+ lists:flatten(
+ call_modules(points, undefined) )).
+
+%%%----------------------------------------------------------------
+call_modules(Cmnd, Type) ->
+ call_modules(Cmnd, Type, undefined).
+
+call_modules(Cmnd, Type, Arg) ->
+ call_modules(Cmnd, Type, Arg, []).
+
+call_modules(Cmnd, Type, Arg, Acc0) ->
+ call_modules(Cmnd, Type, Arg, Acc0, ssh_modules_with_trace()).
+
+call_modules(Cmnd, Types, Arg, Acc0, Modules) when is_list(Types) ->
+ lists:foldl(
+ fun(Type, Acc) ->
+ call_modules(Cmnd, Type, Arg, Acc, Modules)
+ end, Acc0, Types);
+
+call_modules(Cmnd, Type, Arg, Acc0, Modules) ->
+ lists:foldl(
+ fun(Mod, Acc) ->
+ try Mod:dbg_trace(Cmnd, Type, Arg)
+ of
+ Result -> [Result|Acc]
+ catch
+ _:_ -> Acc
+ end
+ end, Acc0, Modules).
+%%%----------------------------------------------------------------
+switch(X, Type) when is_atom(Type) ->
+ switch(X, [Type]);
+
+switch(X, Types) when is_list(Types) ->
+ case whereis(?SERVER) of
+ undefined ->
+ start();
+ _ ->
+ ok
+ end,
+ case lists:usort(Types) -- ?ALL_DBG_TYPES of
+ [] ->
+ gen_server:call(?SERVER, {switch,X,Types}, ?CALL_TIMEOUT);
+ L ->
+ {error, {unknown, L}}
+ end.
+
+%%%----------------------------------------------------------------
+%%% Format of trace messages are described in reference manual for erlang:trace/4
+%%% {call,MFA}
+%%% {return_from,{M,F,N},Result}
+%%% {send,Msg,To}
+%%% {'receive',Msg}
+
+trace_pid({trace,Pid,_}) -> Pid;
+trace_pid({trace,Pid,_,_}) -> Pid;
+trace_pid({trace,Pid,_,_,_}) -> Pid;
+trace_pid({trace,Pid,_,_,_,_}) -> Pid;
+trace_pid({trace,Pid,_,_,_,_,_}) -> Pid;
+trace_pid({trace_ts,Pid,_,_TS}) -> Pid;
+trace_pid({trace_ts,Pid,_,_,_TS}) -> Pid;
+trace_pid({trace_ts,Pid,_,_,_,_TS}) -> Pid;
+trace_pid({trace_ts,Pid,_,_,_,_,_TS}) -> Pid;
+trace_pid({trace_ts,Pid,_,_,_,_,_,_TS}) -> Pid.
+
+trace_ts({trace_ts,_Pid,_,TS}) -> ts(TS);
+trace_ts({trace_ts,_Pid,_,_,TS}) -> ts(TS);
+trace_ts({trace_ts,_Pid,_,_,_,TS}) -> ts(TS);
+trace_ts({trace_ts,_Pid,_,_,_,_,TS}) -> ts(TS);
+trace_ts({trace_ts,_Pid,_,_,_,_,_,TS}) -> ts(TS);
+trace_ts(_) -> "-".
+
+trace_info({trace,_Pid,A}) -> A;
+trace_info({trace,_Pid,A,B}) -> {A,B};
+trace_info({trace,_Pid,A,B,C}) -> {A,B,C};
+trace_info({trace,_Pid,A,B,C,D}) -> {A,B,C,D};
+trace_info({trace,_Pid,A,B,C,D,E}) -> {A,B,C,D,E};
+trace_info({trace_ts,_Pid,A,_TS}) -> A;
+trace_info({trace_ts,_Pid,A,B,_TS}) -> {A,B};
+trace_info({trace_ts,_Pid,A,B,C,_TS}) -> {A,B,C};
+trace_info({trace_ts,_Pid,A,B,C,D,_TS}) -> {A,B,C,D};
+trace_info({trace_ts,_Pid,A,B,C,D,E,_TS}) -> {A,B,C,D,E}.
+
+
+try_all_types_in_all_modules(TypesOn, Arg, WriteFun, Acc0) ->
+ SshModules = ssh_modules_with_trace(),
+ TS = trace_ts(Arg),
+ PID = trace_pid(Arg),
+ INFO = trace_info(Arg),
+ lists:foldl(
+ fun(Type, Acc1) ->
+ lists:foldl(
+ fun(SshMod,Acc) ->
+ try WriteFun("~n~s ~p ~s~n",
+ [lists:flatten(TS), PID, lists:flatten(SshMod:dbg_trace(format,Type,INFO))],
+ Acc)
+ catch
+ _:_ -> Acc
+ end
+ end, Acc1, SshModules)
+ end, Acc0, TypesOn).
+
+%%%----------------------------------------------------------------
wr_record(T, Fs, BL) when is_tuple(T) ->
wr_record(tuple_to_list(T), Fs, BL);
-wr_record([Name|Values], Fields, BlackL) ->
+wr_record([_Name|Values], Fields, BlackL) ->
W = case Fields of
[] -> 0;
_ -> lists:max([length(atom_to_list(F)) || F<-Fields])
end,
- [io_lib:format("~p:~n",[string:to_upper(atom_to_list(Name))])
- | [io_lib:format(" ~*p: ~p~n",[W,Tag,Value]) || {Tag,Value} <- lists:zip(Fields,Values),
- not lists:member(Tag,BlackL)
- ]
+ [io_lib:format(" ~*p: ~p~n",[W,Tag,Value]) || {Tag,Value} <- lists:zip(Fields,Values),
+ not lists:member(Tag,BlackL)
].
+
+%%%----------------------------------------------------------------
+ts({_,_,Usec}=Now) when is_integer(Usec) ->
+ {_Date,{HH,MM,SS}} = calendar:now_to_local_time(Now),
+ io_lib:format("~.2.0w:~.2.0w:~.2.0w.~.6.0w",[HH,MM,SS,Usec]);
+ts(_) ->
+ "-".
+
+%%%================================================================
+-define(CIRC_BUF, circ_buf).
+
+cbuf_start() ->
+ cbuf_start(20).
+
+cbuf_start(CbufMaxLen) ->
+ put(?CIRC_BUF, {CbufMaxLen,queue:new()}),
+ ok.
+
+
+cbuf_stop_clear() ->
+ case erase(?CIRC_BUF) of
+ undefined ->
+ [];
+ {_CbufMaxLen,Queue} ->
+ queue:to_list(Queue)
+ end.
+
+
+cbuf_in(Value) ->
+ case get(?CIRC_BUF) of
+ undefined ->
+ disabled;
+ {CbufMaxLen,Queue} ->
+ UpdatedQueue =
+ try queue:head(Queue) of
+ {Value, TS0, Cnt0} ->
+ %% Same Value as last saved in the queue
+ queue:in_r({Value, TS0, Cnt0+1},
+ queue:drop(Queue)
+ );
+ _ ->
+ queue:in_r({Value, erlang:timestamp(), 1},
+ truncate_cbuf(Queue, CbufMaxLen)
+ )
+ catch
+ error:empty ->
+ queue:in_r({Value, erlang:timestamp(), 1}, Queue)
+ end,
+ put(?CIRC_BUF, {CbufMaxLen,UpdatedQueue}),
+ ok
+ end.
+
+
+cbuf_list() ->
+ case get(?CIRC_BUF) of
+ undefined ->
+ [];
+ {_CbufMaxLen,Queue} ->
+ queue:to_list(Queue)
+ end.
+
+
+truncate_cbuf(Q, CbufMaxLen) ->
+ case queue:len(Q) of
+ N when N>=CbufMaxLen ->
+ truncate_cbuf(element(2,queue:out_r(Q)), CbufMaxLen);
+ _ ->
+ Q
+ end.
+
+fmt_cbuf_items() ->
+ lists:flatten(
+ io_lib:format("Circular trace buffer. Latest item first.~n~s~n",
+ [case get(?CIRC_BUF) of
+ {Max,_} ->
+ L = cbuf_list(),
+ [io_lib:format("==== ~.*w: ~s~n",[num_digits(Max),N,fmt_cbuf_item(X)]) ||
+ {N,X} <- lists:zip(lists:seq(1,length(L)), L)
+ ];
+ _ ->
+ io_lib:format("Not started.~n",[])
+ end])).
+
+
+num_digits(0) -> 1;
+num_digits(N) when N>0 -> 1+trunc(math:log10(N)).
+
+
+fmt_cbuf_item({Value, TimeStamp, N}) ->
+ io_lib:format("~s~s~n~s~n",
+ [fmt_ts(TimeStamp),
+ [io_lib:format(" (Repeated ~p times)",[N]) || N>1],
+ fmt_value(Value)]).
+
+
+fmt_ts(TS = {_,_,Us}) ->
+ {{YY,MM,DD},{H,M,S}} = calendar:now_to_universal_time(TS),
+ io_lib:format("~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w.~.6.0w UTC",[YY,MM,DD,H,M,S,Us]).
+
+fmt_value(#circ_buf_entry{module = M,
+ line = L,
+ function = {F,A},
+ pid = Pid,
+ value = V}) ->
+ io_lib:format("~p:~p ~p/~p ~p~n~s",[M,L,F,A,Pid,fmt_value(V)]);
+fmt_value(Value) ->
+ io_lib:format("~p",[Value]).
+
+%%%================================================================
+
+-record(h, {max_bytes = 65536,
+ bytes_per_line = 16,
+ address_len = 4
+ }).
+
+
+hex_dump(Data) -> hex_dump1(Data, hd_opts([])).
+
+hex_dump(X, Max) when is_integer(Max) ->
+ hex_dump(X, [{max_bytes,Max}]);
+hex_dump(X, OptList) when is_list(OptList) ->
+ hex_dump1(X, hd_opts(OptList)).
+
+hex_dump1(B, Opts) when is_binary(B) -> hex_dump1(binary_to_list(B), Opts);
+hex_dump1(L, Opts) when is_list(L), length(L) > Opts#h.max_bytes ->
+ io_lib:format("~s---- skip ~w bytes----~n", [hex_dump1(lists:sublist(L,Opts#h.max_bytes), Opts),
+ length(L) - Opts#h.max_bytes
+ ]);
+hex_dump1(L, Opts0) when is_list(L) ->
+ Opts = Opts0#h{address_len = num_hex_digits(Opts0#h.max_bytes)},
+ Result = hex_dump(L, [{0,[],[]}], Opts),
+ [io_lib:format("~*.s | ~*s | ~s~n"
+ "~*.c-+-~*c-+-~*c~n",
+ [Opts#h.address_len, lists:sublist("Address",Opts#h.address_len),
+ -3*Opts#h.bytes_per_line, lists:sublist("Hexdump",3*Opts#h.bytes_per_line),
+ "ASCII",
+ Opts#h.address_len, $-,
+ 3*Opts#h.bytes_per_line, $-,
+ Opts#h.bytes_per_line, $-
+ ]) |
+ [io_lib:format("~*.16.0b | ~s~*c | ~s~n",[Opts#h.address_len, N*Opts#h.bytes_per_line,
+ lists:reverse(Hexs),
+ 3*(Opts#h.bytes_per_line-length(Hexs)), $ ,
+ lists:reverse(Chars)])
+ || {N,Hexs,Chars} <- lists:reverse(Result)
+ ]
+ ].
+
+
+hd_opts(L) -> lists:foldl(fun hd_opt/2, #h{}, L).
+
+hd_opt({max_bytes,M}, O) -> O#h{max_bytes=M};
+hd_opt({bytes_per_line,M}, O) -> O#h{bytes_per_line=M}.
+
+
+num_hex_digits(N) when N<16 -> 1;
+num_hex_digits(N) -> trunc(math:ceil(math:log2(N)/4)).
+
+
+hex_dump([L|Cs], Result0, Opts) when is_list(L) ->
+ Result = hex_dump(L,Result0, Opts),
+ hex_dump(Cs, Result, Opts);
+
+hex_dump(Cs, [{N0,_,Chars}|_]=Lines, Opts) when length(Chars) == Opts#h.bytes_per_line ->
+ hex_dump(Cs, [{N0+1,[],[]}|Lines], Opts);
+
+hex_dump([C|Cs], [{N,Hexs,Chars}|Lines], Opts) ->
+ Asc = if
+ 16#20 =< C,C =< 16#7E -> C;
+ true -> $.
+ end,
+ Hex = io_lib:format("~2.16.0b ", [C]),
+ hex_dump(Cs, [{N, [Hex|Hexs], [Asc|Chars]} | Lines], Opts);
+
+hex_dump([], Result, _) ->
+ Result.
+
+
+
diff --git a/lib/ssh/src/ssh_dbg.hrl b/lib/ssh/src/ssh_dbg.hrl
deleted file mode 100644
index e94664737b..0000000000
--- a/lib/ssh/src/ssh_dbg.hrl
+++ /dev/null
@@ -1,27 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
--ifndef(SSH_DBG_HRL).
--define(SSH_DBG_HRL, 1).
-
--define(formatrec(RecName,R),
- ssh_dbg:wr_record(R, record_info(fields,RecName), [])).
-
--endif. % SSH_DBG_HRL defined
diff --git a/lib/ssh/src/ssh_file.erl b/lib/ssh/src/ssh_file.erl
index 33792da38f..510269bbb1 100644
--- a/lib/ssh/src/ssh_file.erl
+++ b/lib/ssh/src/ssh_file.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -39,32 +39,29 @@
is_auth_key/3]).
--define(PERM_700, 8#700).
--define(PERM_644, 8#644).
-
-
-%%% API
+-export_type([system_dir_daemon_option/0,
+ user_dir_common_option/0,
+ user_dir_fun_common_option/0,
+ pubkey_passphrase_client_options/0
+ ]).
-%%% client
--spec add_host_key(string(),
- public_key:public_key(),
- proplists:proplist()) -> ok | {error,term()}.
+-type system_dir_daemon_option() :: {system_dir, string()}.
+-type user_dir_common_option() :: {user_dir, string()}.
+-type user_dir_fun_common_option() :: {user_dir_fun, user2dir()}.
+-type user2dir() :: fun((RemoteUserName::string()) -> UserDir :: string()) .
--spec is_host_key(public_key:public_key(),
- string(),
- ssh_client_key_api:algorithm(),
- proplists:proplist()) -> boolean().
+-type pubkey_passphrase_client_options() :: {dsa_pass_phrase, string()}
+ | {rsa_pass_phrase, string()}
+%% Not yet implemented: | {ed25519_pass_phrase, string()}
+%% Not yet implemented: | {ed448_pass_phrase, string()}
+ | {ecdsa_pass_phrase, string()} .
--spec user_key(ssh_client_key_api:algorithm(),
- proplists:proplist()) -> {ok, public_key:private_key()} | {error,term()}.
-%%% server
--spec host_key(ssh_server_key_api:algorithm(),
- proplists:proplist()) -> {ok, public_key:private_key()} | {error,term()}.
+-define(PERM_700, 8#700).
+-define(PERM_644, 8#644).
--spec is_auth_key(public_key:public_key(),
- string(), proplists:proplist()) -> boolean().
+%%% API
%% Used by server
host_key(Algorithm, Opts) ->
@@ -124,6 +121,8 @@ file_base_name('ssh-dss' ) -> "ssh_host_dsa_key";
file_base_name('ecdsa-sha2-nistp256') -> "ssh_host_ecdsa_key";
file_base_name('ecdsa-sha2-nistp384') -> "ssh_host_ecdsa_key";
file_base_name('ecdsa-sha2-nistp521') -> "ssh_host_ecdsa_key";
+file_base_name('ssh-ed25519' ) -> "ssh_host_ed25519_key";
+file_base_name('ssh-ed448' ) -> "ssh_host_ed448_key";
file_base_name(_ ) -> "ssh_host_key".
decode(File, Password) ->
@@ -261,6 +260,8 @@ identity_key_filename('ssh-rsa' ) -> "id_rsa";
identity_key_filename('rsa-sha2-256' ) -> "id_rsa";
identity_key_filename('rsa-sha2-384' ) -> "id_rsa";
identity_key_filename('rsa-sha2-512' ) -> "id_rsa";
+identity_key_filename('ssh-ed25519' ) -> "id_ed25519";
+identity_key_filename('ssh-ed448' ) -> "id_ed448";
identity_key_filename('ecdsa-sha2-nistp256') -> "id_ecdsa";
identity_key_filename('ecdsa-sha2-nistp384') -> "id_ecdsa";
identity_key_filename('ecdsa-sha2-nistp521') -> "id_ecdsa".
@@ -270,9 +271,12 @@ identity_pass_phrase("ssh-rsa" ) -> rsa_pass_phrase;
identity_pass_phrase("rsa-sha2-256" ) -> rsa_pass_phrase;
identity_pass_phrase("rsa-sha2-384" ) -> rsa_pass_phrase;
identity_pass_phrase("rsa-sha2-512" ) -> rsa_pass_phrase;
+%% Not yet implemented: identity_pass_phrase("ssh-ed25519" ) -> ed25519_pass_phrase;
+%% Not yet implemented: identity_pass_phrase("ssh-ed448" ) -> ed448_pass_phrase;
identity_pass_phrase("ecdsa-sha2-"++_) -> ecdsa_pass_phrase;
identity_pass_phrase(P) when is_atom(P) ->
- identity_pass_phrase(atom_to_list(P)).
+ identity_pass_phrase(atom_to_list(P));
+identity_pass_phrase(_) -> undefined.
lookup_host_key_fd(Fd, KeyToMatch, Host, KeyType) ->
case io:get_line(Fd, '') of
@@ -322,6 +326,10 @@ key_match({#'ECPoint'{},{namedCurve,Curve}}, Alg) ->
_ ->
false
end;
+key_match({ed_pub,ed25519,_}, 'ssh-ed25519') ->
+ true;
+key_match({ed_pub,ed448,_}, 'ssh-ed448') ->
+ true;
key_match(_, _) ->
false.
diff --git a/lib/ssh/src/ssh_info.erl b/lib/ssh/src/ssh_info.erl
index d464def6fa..79cd95e422 100644
--- a/lib/ssh/src/ssh_info.erl
+++ b/lib/ssh/src/ssh_info.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -140,15 +140,15 @@ print_system_sup({{ssh_acceptor_sup,_LocalHost,_LocalPort,_Profile}, Pid, superv
-print_channels({{server,ssh_channel_sup,_,_},Pid,supervisor,[ssh_channel_sup]}) when is_pid(Pid) ->
+print_channels({{server,ssh_server_channel_sup,_,_},Pid,supervisor,[ssh_server_channel_sup]}) when is_pid(Pid) ->
Children = supervisor:which_children(Pid),
- ChannelPids = [P || {R,P,worker,[ssh_channel]} <- Children,
+ ChannelPids = [P || {R,P,worker,[ssh_server_channel]} <- Children,
is_pid(P),
is_reference(R)],
case ChannelPids of
[] -> io_lib:format(?INDENT?INDENT"No channels~n",[]);
[Ch1Pid|_] ->
- {{ConnManager,_}, _Str} = ssh_channel:get_print_info(Ch1Pid),
+ {{ConnManager,_}, _Str} = ssh_server_channel:get_print_info(Ch1Pid),
{{_,Remote},_} = ssh_connection_handler:get_print_info(ConnManager),
[io_lib:format(?INDENT?INDENT"Remote: ~s ConnectionRef = ~p~n",[fmt_host_port(Remote),ConnManager]),
lists:map(fun print_ch/1, ChannelPids)
@@ -159,7 +159,7 @@ print_channels({{server,ssh_connection_sup,_,_},Pid,supervisor,[ssh_connection_s
print_ch(Pid) ->
try
- {{ConnManager,ChannelID}, Str} = ssh_channel:get_print_info(Pid),
+ {{ConnManager,ChannelID}, Str} = ssh_server_channel:get_print_info(Pid),
{_LocalRemote,StrM} = ssh_connection_handler:get_print_info(ConnManager),
io_lib:format(?INDENT?INDENT?INDENT"ch ~p ~p: ~s ~s~n",[ChannelID, Pid, StrM, Str])
catch
diff --git a/lib/ssh/src/ssh_message.erl b/lib/ssh/src/ssh_message.erl
index eb06f05a4a..d95e58c1bb 100644
--- a/lib/ssh/src/ssh_message.erl
+++ b/lib/ssh/src/ssh_message.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,6 +32,8 @@
-export([encode/1, decode/1, decode_keyboard_interactive_prompts/2]).
+-export([dbg_trace/3]).
+
-define('2bin'(X), (if is_binary(X) -> X;
is_list(X) -> list_to_binary(X);
X==undefined -> <<>>
@@ -287,12 +289,12 @@ encode(#ssh_msg_kex_dh_gex_reply{
<<?Ebyte(?SSH_MSG_KEX_DH_GEX_REPLY), ?Ebinary(EncKey), ?Empint(F), ?Ebinary(EncSign)>>;
encode(#ssh_msg_kex_ecdh_init{q_c = Q_c}) ->
- <<?Ebyte(?SSH_MSG_KEX_ECDH_INIT), ?Empint(Q_c)>>;
+ <<?Ebyte(?SSH_MSG_KEX_ECDH_INIT), ?Ebinary(Q_c)>>;
encode(#ssh_msg_kex_ecdh_reply{public_host_key = {Key,SigAlg}, q_s = Q_s, h_sig = Sign}) ->
EncKey = public_key:ssh_encode(Key, ssh2_pubkey),
EncSign = encode_signature(Key, SigAlg, Sign),
- <<?Ebyte(?SSH_MSG_KEX_ECDH_REPLY), ?Ebinary(EncKey), ?Empint(Q_s), ?Ebinary(EncSign)>>;
+ <<?Ebyte(?SSH_MSG_KEX_ECDH_REPLY), ?Ebinary(EncKey), ?Ebinary(Q_s), ?Ebinary(EncSign)>>;
encode(#ssh_msg_ignore{data = Data}) ->
<<?Ebyte(?SSH_MSG_IGNORE), ?Estring_utf8(Data)>>;
@@ -502,13 +504,13 @@ decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_REPLY), ?DEC_BIN(Key,__0), ?DEC_MPINT(F,__1),
h_sig = decode_signature(Hashsign)
};
-decode(<<"ecdh",?BYTE(?SSH_MSG_KEX_ECDH_INIT), ?DEC_MPINT(Q_c,__0)>>) ->
+decode(<<"ecdh",?BYTE(?SSH_MSG_KEX_ECDH_INIT), ?DEC_BIN(Q_c,__0)>>) ->
#ssh_msg_kex_ecdh_init{
q_c = Q_c
};
decode(<<"ecdh",?BYTE(?SSH_MSG_KEX_ECDH_REPLY),
- ?DEC_BIN(Key,__1), ?DEC_MPINT(Q_s,__2), ?DEC_BIN(Sig,__3)>>) ->
+ ?DEC_BIN(Key,__1), ?DEC_BIN(Q_s,__2), ?DEC_BIN(Sig,__3)>>) ->
#ssh_msg_kex_ecdh_reply{
public_host_key = public_key:ssh_decode(Key, ssh2_pubkey),
q_s = Q_s,
@@ -609,5 +611,94 @@ encode_signature({_, #'Dss-Parms'{}}, _SigAlg, Signature) ->
<<?Ebinary(<<"ssh-dss">>), ?Ebinary(Signature)>>;
encode_signature({#'ECPoint'{}, {namedCurve,OID}}, _SigAlg, Signature) ->
CurveName = public_key:oid2ssh_curvename(OID),
- <<?Ebinary(<<"ecdsa-sha2-",CurveName/binary>>), ?Ebinary(Signature)>>.
+ <<?Ebinary(<<"ecdsa-sha2-",CurveName/binary>>), ?Ebinary(Signature)>>;
+encode_signature({ed_pub, ed25519,_}, _SigAlg, Signature) ->
+ <<?Ebinary(<<"ssh-ed25519">>), ?Ebinary(Signature)>>;
+encode_signature({ed_pub, ed448,_}, _SigAlg, Signature) ->
+ <<?Ebinary(<<"ssh-ed448">>), ?Ebinary(Signature)>>.
+
+
+
+%%%################################################################
+%%%#
+%%%# Tracing
+%%%#
+
+dbg_trace(points, _, _) -> [ssh_messages, raw_messages];
+
+dbg_trace(flags, ssh_messages, _) -> [c];
+dbg_trace(on, ssh_messages, _) -> dbg:tp(?MODULE,encode,1,x),
+ dbg:tp(?MODULE,decode,1,x);
+dbg_trace(off, ssh_messages, _) -> dbg:ctpg(?MODULE,encode,1),
+ dbg:ctpg(?MODULE,decode,1);
+
+dbg_trace(flags, raw_messages, A) -> dbg_trace(flags, ssh_messages, A);
+dbg_trace(on, raw_messages, A) -> dbg_trace(on, ssh_messages, A);
+dbg_trace(off, raw_messages, A) -> dbg_trace(off, ssh_messages, A);
+
+dbg_trace(format, ssh_messages, {call,{?MODULE,encode,[Msg]}}) ->
+ Name = string:to_upper(atom_to_list(element(1,Msg))),
+ ["Going to send ",Name,":\n",
+ wr_record(ssh_dbg:shrink_bin(Msg))
+ ];
+dbg_trace(format, ssh_messages, {return_from,{?MODULE,decode,1},Msg}) ->
+ Name = string:to_upper(atom_to_list(element(1,Msg))),
+ ["Received ",Name,":\n",
+ wr_record(ssh_dbg:shrink_bin(Msg))
+ ];
+
+dbg_trace(format, raw_messages, {call,{?MODULE,decode,[BytesPT]}}) ->
+ ["Received plain text bytes (shown after decryption):\n",
+ io_lib:format("~p",[BytesPT])
+ ];
+dbg_trace(format, raw_messages, {return_from,{?MODULE,encode,1},BytesPT}) ->
+ ["Going to send plain text bytes (shown before encryption):\n",
+ io_lib:format("~p",[BytesPT])
+ ].
+
+
+?wr_record(ssh_msg_disconnect);
+?wr_record(ssh_msg_ignore);
+?wr_record(ssh_msg_unimplemented);
+?wr_record(ssh_msg_debug);
+?wr_record(ssh_msg_service_request);
+?wr_record(ssh_msg_service_accept);
+?wr_record(ssh_msg_kexinit);
+?wr_record(ssh_msg_kexdh_init);
+?wr_record(ssh_msg_kexdh_reply);
+?wr_record(ssh_msg_newkeys);
+?wr_record(ssh_msg_ext_info);
+?wr_record(ssh_msg_kex_dh_gex_request);
+?wr_record(ssh_msg_kex_dh_gex_request_old);
+?wr_record(ssh_msg_kex_dh_gex_group);
+?wr_record(ssh_msg_kex_dh_gex_init);
+?wr_record(ssh_msg_kex_dh_gex_reply);
+?wr_record(ssh_msg_kex_ecdh_init);
+?wr_record(ssh_msg_kex_ecdh_reply);
+
+?wr_record(ssh_msg_userauth_request);
+?wr_record(ssh_msg_userauth_failure);
+?wr_record(ssh_msg_userauth_success);
+?wr_record(ssh_msg_userauth_banner);
+?wr_record(ssh_msg_userauth_passwd_changereq);
+?wr_record(ssh_msg_userauth_pk_ok);
+?wr_record(ssh_msg_userauth_info_request);
+?wr_record(ssh_msg_userauth_info_response);
+
+?wr_record(ssh_msg_global_request);
+?wr_record(ssh_msg_request_success);
+?wr_record(ssh_msg_request_failure);
+?wr_record(ssh_msg_channel_open);
+?wr_record(ssh_msg_channel_open_confirmation);
+?wr_record(ssh_msg_channel_open_failure);
+?wr_record(ssh_msg_channel_window_adjust);
+?wr_record(ssh_msg_channel_data);
+?wr_record(ssh_msg_channel_extended_data);
+?wr_record(ssh_msg_channel_eof);
+?wr_record(ssh_msg_channel_close);
+?wr_record(ssh_msg_channel_request);
+?wr_record(ssh_msg_channel_success);
+?wr_record(ssh_msg_channel_failure);
+
+wr_record(R) -> io_lib:format('~p~n',[R]).
diff --git a/lib/ssh/src/ssh_no_io.erl b/lib/ssh/src/ssh_no_io.erl
index 1da257ed99..31963118cb 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-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -31,35 +31,24 @@
-spec yes_no(any(), any()) -> no_return().
yes_no(_, _) ->
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{code = ?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
- description = "User interaction is not allowed"},
- {no_io_allowed, yes_no}).
+ ?DISCONNECT(?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
+ "User interaction is not allowed").
-spec read_password(any(), any()) -> no_return().
read_password(_, _) ->
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{code = ?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
- description = "User interaction is not allowed"},
- {no_io_allowed, read_password}).
-
+ ?DISCONNECT(?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
+ "User interaction is not allowed").
-spec read_line(any(), any()) -> no_return().
read_line(_, _) ->
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{code = ?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
- description = "User interaction is not allowed"},
- {no_io_allowed, read_line}).
-
+ ?DISCONNECT(?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
+ "User interaction is not allowed").
-spec format(any(), any()) -> no_return().
format(_, _) ->
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{code = ?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
- description = "User interaction is not allowed"},
- {no_io_allowed, format}).
-
+ ?DISCONNECT(?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
+ "User interaction is not allowed").
diff --git a/lib/ssh/src/ssh_options.erl b/lib/ssh/src/ssh_options.erl
index 1e10f72956..1010c9be55 100644
--- a/lib/ssh/src/ssh_options.erl
+++ b/lib/ssh/src/ssh_options.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,7 +32,7 @@
handle_options/2
]).
--export_type([options/0
+-export_type([private_options/0
]).
%%%================================================================
@@ -47,16 +47,23 @@
default => any()
}.
+-type option_key() :: atom().
+
-type option_declarations() :: #{ {option_key(),def} := option_declaration() }.
-type error() :: {error,{eoptions,any()}} .
+-type private_options() :: #{socket_options := socket_options(),
+ internal_options := internal_options(),
+ option_key() => any()
+ }.
+
%%%================================================================
%%%
%%% Get an option
%%%
--spec get_value(option_class(), option_key(), options(),
+-spec get_value(option_class(), option_key(), private_options(),
atom(), non_neg_integer()) -> any() | no_return().
get_value(Class, Key, Opts, _CallerMod, _CallerLine) when is_map(Opts) ->
@@ -69,7 +76,7 @@ get_value(Class, Key, Opts, _CallerMod, _CallerLine) ->
error({bad_options,Class, Key, Opts, _CallerMod, _CallerLine}).
--spec get_value(option_class(), option_key(), options(), fun(() -> any()),
+-spec get_value(option_class(), option_key(), private_options(), fun(() -> any()),
atom(), non_neg_integer()) -> any() | no_return().
get_value(socket_options, Key, Opts, DefFun, _CallerMod, _CallerLine) when is_map(Opts) ->
@@ -91,8 +98,8 @@ get_value(Class, Key, Opts, _DefFun, _CallerMod, _CallerLine) ->
%%% Put an option
%%%
--spec put_value(option_class(), option_in(), options(),
- atom(), non_neg_integer()) -> options().
+-spec put_value(option_class(), option_in(), private_options(),
+ atom(), non_neg_integer()) -> private_options().
put_value(user_options, KeyVal, Opts, _CallerMod, _CallerLine) when is_map(Opts) ->
put_user_value(KeyVal, Opts);
@@ -131,8 +138,8 @@ put_socket_value(A, SockOpts) when is_atom(A) ->
%%% Delete an option
%%%
--spec delete_key(option_class(), option_key(), options(),
- atom(), non_neg_integer()) -> options().
+-spec delete_key(option_class(), option_key(), private_options(),
+ atom(), non_neg_integer()) -> private_options().
delete_key(internal_options, Key, Opts, _CallerMod, _CallerLine) when is_map(Opts) ->
InternalOpts = maps:get(internal_options,Opts),
@@ -144,9 +151,7 @@ delete_key(internal_options, Key, Opts, _CallerMod, _CallerLine) when is_map(Opt
%%% Initialize the options
%%%
--spec handle_options(role(), proplists:proplist()) -> options() | error() .
-
--spec handle_options(role(), proplists:proplist(), options()) -> options() | error() .
+-spec handle_options(role(), client_options()|daemon_options()) -> private_options() | error() .
handle_options(Role, PropList0) ->
handle_options(Role, PropList0, #{socket_options => [],
@@ -155,7 +160,7 @@ handle_options(Role, PropList0) ->
}).
handle_options(Role, PropList0, Opts0) when is_map(Opts0),
- is_list(PropList0) ->
+ is_list(PropList0) ->
PropList1 = proplists:unfold(PropList0),
try
OptionDefinitions = default(Role),
@@ -275,10 +280,12 @@ default(server) ->
class => user_options
},
- {exec, def} => % FIXME: need some archeology....
+ {exec, def} =>
#{default => undefined,
- chk => fun({M,F,_}) -> is_atom(M) andalso is_atom(F);
- (V) -> is_function(V)
+ chk => fun({direct, V}) -> check_function1(V) orelse check_function2(V) orelse check_function3(V);
+ %% Compatibility (undocumented):
+ ({M,F,A}) -> is_atom(M) andalso is_atom(F) andalso is_list(A);
+ (V) -> check_function1(V) orelse check_function2(V) orelse check_function3(V)
end,
class => user_options
},
@@ -427,6 +434,18 @@ default(client) ->
class => user_options
},
+%%% Not yet implemented {ed25519_pass_phrase, def} =>
+%%% Not yet implemented #{default => undefined,
+%%% Not yet implemented chk => fun check_string/1,
+%%% Not yet implemented class => user_options
+%%% Not yet implemented },
+%%% Not yet implemented
+%%% Not yet implemented {ed448_pass_phrase, def} =>
+%%% Not yet implemented #{default => undefined,
+%%% Not yet implemented chk => fun check_string/1,
+%%% Not yet implemented class => user_options
+%%% Not yet implemented },
+%%% Not yet implemented
{silently_accept_hosts, def} =>
#{default => false,
chk => fun check_silently_accept_hosts/1,
@@ -445,12 +464,6 @@ default(client) ->
class => user_options
},
- {pref_public_key_algs, def} =>
- #{default => ssh_transport:default_algorithms(public_key),
- chk => fun check_pref_public_key_algs/1,
- class => user_options
- },
-
{dh_gex_limits, def} =>
#{default => {1024, 6144, 8192}, % FIXME: Is this true nowadays?
chk => fun({Min,I,Max}) ->
@@ -516,6 +529,12 @@ default(common) ->
class => user_options
},
+ {pref_public_key_algs, def} =>
+ #{default => ssh_transport:default_algorithms(public_key),
+ chk => fun check_pref_public_key_algs/1,
+ class => user_options
+ },
+
{preferred_algorithms, def} =>
#{default => ssh:default_algorithms(),
chk => fun check_preferred_algorithms/1,
@@ -592,9 +611,24 @@ default(common) ->
class => user_options
},
- {rekey_limit, def} => % FIXME: Why not common?
- #{default => 1024000000,
- chk => fun check_non_neg_integer/1,
+ {rekey_limit, def} =>
+ #{default => {3600000, 1024000000}, % {1 hour, 1 GB}
+ chk => fun({infinity, infinity}) ->
+ true;
+ ({Mins, infinity}) when is_integer(Mins), Mins>0 ->
+ {true, {Mins*60*1000, infinity}};
+ ({infinity, Bytes}) when is_integer(Bytes), Bytes>=0 ->
+ true;
+ ({Mins, Bytes}) when is_integer(Mins), Mins>0,
+ is_integer(Bytes), Bytes>=0 ->
+ {true, {Mins*60*1000, Bytes}};
+ (infinity) ->
+ {true, {3600000, infinity}};
+ (Bytes) when is_integer(Bytes), Bytes>=0 ->
+ {true, {3600000, Bytes}};
+ (_) ->
+ false
+ end,
class => user_options
},
diff --git a/lib/ssh/src/ssh_server_channel.erl b/lib/ssh/src/ssh_server_channel.erl
new file mode 100644
index 0000000000..555080e9ee
--- /dev/null
+++ b/lib/ssh/src/ssh_server_channel.erl
@@ -0,0 +1,55 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%% Description: a gen_server implementing a simple
+%% terminal (using the group module) for a CLI
+%% over SSH
+
+-module(ssh_server_channel).
+
+%% API to server side channel that can be pluged into the erlang ssh daemeon
+-callback init(Args :: term()) ->
+ {ok, State :: term()} | {ok, State :: term(), timeout() | hibernate} |
+ {stop, Reason :: term()} | ignore.
+
+-callback terminate(Reason :: (normal | shutdown | {shutdown, term()} |
+ term()),
+ State :: term()) ->
+ term().
+
+-callback handle_msg(Msg ::term(), State :: term()) ->
+ {ok, State::term()} | {stop, ChannelId::ssh:channel_id(), State::term()}.
+-callback handle_ssh_msg({ssh_cm, ConnectionRef::ssh:connection_ref(), SshMsg::term()},
+ State::term()) -> {ok, State::term()} |
+ {stop, ChannelId::ssh:channel_id(),
+ State::term()}.
+
+%%% Internal API
+-export([start_link/5,
+ get_print_info/1
+ ]).
+
+start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec) ->
+ ssh_client_channel:start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec).
+
+
+get_print_info(Pid) ->
+ ssh_client_channel:get_print_info(Pid).
diff --git a/lib/ssh/src/ssh_server_channel_sup.erl b/lib/ssh/src/ssh_server_channel_sup.erl
new file mode 100644
index 0000000000..ff74061bb3
--- /dev/null
+++ b/lib/ssh/src/ssh_server_channel_sup.erl
@@ -0,0 +1,62 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Ssh channel supervisor.
+%%----------------------------------------------------------------------
+-module(ssh_server_channel_sup).
+
+-behaviour(supervisor).
+
+-export([start_link/1, start_child/5]).
+
+%% Supervisor callback
+-export([init/1]).
+
+%%%=========================================================================
+%%% Internal API
+%%%=========================================================================
+start_link(Args) ->
+ supervisor:start_link(?MODULE, [Args]).
+
+start_child(Sup, Callback, Id, Args, Exec) ->
+ ChildSpec =
+ #{id => make_ref(),
+ start => {ssh_server_channel, start_link, [self(), Id, Callback, Args, Exec]},
+ restart => temporary,
+ type => worker,
+ modules => [ssh_server_channel]
+ },
+ supervisor:start_child(Sup, ChildSpec).
+
+%%%=========================================================================
+%%% Supervisor callback
+%%%=========================================================================
+init(_Args) ->
+ RestartStrategy = one_for_one,
+ MaxR = 10,
+ MaxT = 3600,
+ Children = [],
+ {ok, {{RestartStrategy, MaxR, MaxT}, Children}}.
+
+%%%=========================================================================
+%%% Internal functions
+%%%=========================================================================
diff --git a/lib/ssh/src/ssh_server_key.erl b/lib/ssh/src/ssh_server_key.erl
deleted file mode 100644
index 2ce0c7e3fe..0000000000
--- a/lib/ssh/src/ssh_server_key.erl
+++ /dev/null
@@ -1,34 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
--module(ssh_server_key).
-
--include_lib("public_key/include/public_key.hrl").
--include("ssh.hrl").
-
--type ssh_algorithm() :: string().
-
--callback host_key(Algorithm :: ssh_algorithm(), Options :: list()) ->
- {ok, [{public_key(), Attributes::list()}]} | public_key()
- | {error, string()}.
-
--callback is_auth_key(Key :: public_key(), User :: string(),
- Algorithm :: ssh_algorithm(), Options :: list()) ->
- boolean().
diff --git a/lib/ssh/src/ssh_server_key_api.erl b/lib/ssh/src/ssh_server_key_api.erl
index 3f1b886fa7..ef1fe7d69c 100644
--- a/lib/ssh/src/ssh_server_key_api.erl
+++ b/lib/ssh/src/ssh_server_key_api.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,16 +23,18 @@
-include_lib("public_key/include/public_key.hrl").
-include("ssh.hrl").
--export_type([algorithm/0]).
+-export_type([daemon_key_cb_options/0]).
--type algorithm() :: ssh_client_key_api:algorithm().
+-type daemon_key_cb_options() :: [{key_cb_private,term()} | ssh:daemon_option()].
--callback host_key(Algorithm :: algorithm(),
- DaemonOptions :: proplists:proplist()) ->
+-callback host_key(Algorithm :: ssh:pubkey_alg(),
+ DaemonOptions :: daemon_key_cb_options()
+ ) ->
{ok, PrivateKey :: public_key:private_key()} | {error, term()}.
-callback is_auth_key(PublicKey :: public_key:public_key(),
User :: string(),
- DaemonOptions :: proplists:proplist()) ->
+ DaemonOptions :: daemon_key_cb_options()
+ ) ->
boolean().
diff --git a/lib/ssh/src/ssh_sftp.erl b/lib/ssh/src/ssh_sftp.erl
index 9e1229dc85..1b2ba5a50b 100644
--- a/lib/ssh/src/ssh_sftp.erl
+++ b/lib/ssh/src/ssh_sftp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@
-module(ssh_sftp).
--behaviour(ssh_channel).
+-behaviour(ssh_client_channel).
-include_lib("kernel/include/file.hrl").
-include("ssh.hrl").
@@ -47,11 +47,13 @@
recv_window/1, list_dir/2, read_file/2, write_file/3,
recv_window/2, list_dir/3, read_file/3, write_file/4]).
-%% ssh_channel callbacks
+%% ssh_client_channel callbacks
-export([init/1, handle_call/3, handle_cast/2, code_change/3, handle_msg/2, handle_ssh_msg/2, terminate/2]).
%% TODO: Should be placed elsewhere ssh_sftpd should not call functions in ssh_sftp!
-export([info_to_attr/1, attr_to_info/1]).
+-export([dbg_trace/3]).
+
-record(state,
{
xf,
@@ -121,7 +123,7 @@ start_channel(Cm, UserOptions) when is_pid(Cm) ->
{_SshOpts, ChanOpts, SftpOpts} = handle_options(UserOptions),
case ssh_xfer:attach(Cm, [], ChanOpts) of
{ok, ChannelId, Cm} ->
- case ssh_channel:start(Cm, ChannelId,
+ case ssh_client_channel:start(Cm, ChannelId,
?MODULE, [Cm, ChannelId, SftpOpts]) of
{ok, Pid} ->
case wait_for_version_negotiation(Pid, Timeout) of
@@ -149,7 +151,7 @@ start_channel(Host, Port, UserOptions) ->
proplists:get_value(timeout, SftpOpts, infinity)),
case ssh_xfer:connect(Host, Port, SshOpts, ChanOpts, Timeout) of
{ok, ChannelId, Cm} ->
- case ssh_channel:start(Cm, ChannelId, ?MODULE, [Cm,ChannelId,SftpOpts]) of
+ case ssh_client_channel:start(Cm, ChannelId, ?MODULE, [Cm,ChannelId,SftpOpts]) of
{ok, Pid} ->
case wait_for_version_negotiation(Pid, Timeout) of
ok ->
@@ -169,21 +171,16 @@ start_channel(Host, Port, UserOptions) ->
stop_channel(Pid) ->
case is_process_alive(Pid) of
true ->
- OldValue = process_flag(trap_exit, true),
- link(Pid),
- exit(Pid, ssh_sftp_stop_channel),
- receive
- {'EXIT', Pid, normal} ->
- ok
- after 5000 ->
- exit(Pid, kill),
- receive
- {'EXIT', Pid, killed} ->
- ok
- end
- end,
- process_flag(trap_exit, OldValue),
- ok;
+ MonRef = erlang:monitor(process, Pid),
+ unlink(Pid),
+ exit(Pid, ssh_sftp_stop_channel),
+ receive {'DOWN',MonRef,_,_,_} -> ok
+ after
+ 1000 ->
+ exit(Pid, kill),
+ erlang:demonitor(MonRef, [flush]),
+ ok
+ end;
false ->
ok
end.
@@ -801,13 +798,22 @@ handle_ssh_msg({ssh_cm, _, {signal, _, _}}, State) ->
%% Ignore signals according to RFC 4254 section 6.9.
{ok, State};
-handle_ssh_msg({ssh_cm, _, {exit_signal, ChannelId, _, Error, _}},
+handle_ssh_msg({ssh_cm, _, {exit_signal, ChannelId, Signal, Error0, _}},
State0) ->
+ Error =
+ case Error0 of
+ "" -> Signal;
+ _ -> Error0
+ end,
State = reply_all(State0, {error, Error}),
{stop, ChannelId, State};
handle_ssh_msg({ssh_cm, _, {exit_status, ChannelId, Status}}, State0) ->
- State = reply_all(State0, {error, {exit_status, Status}}),
+ State =
+ case State0 of
+ 0 -> State0;
+ _ -> reply_all(State0, {error, {exit_status, Status}})
+ end,
{stop, ChannelId, State}.
%%--------------------------------------------------------------------
@@ -823,7 +829,7 @@ handle_msg({ssh_channel_up, _, _}, #state{opts = Options, xf = Xf} = State) ->
%% Version negotiation timed out
handle_msg({timeout, undefined, From},
#state{xf = #ssh_xfer{channel = ChannelId}} = State) ->
- ssh_channel:reply(From, {error, timeout}),
+ ssh_client_channel:reply(From, {error, timeout}),
{stop, ChannelId, State};
handle_msg({timeout, Id, From}, #state{req_list = ReqList0} = State) ->
@@ -832,7 +838,7 @@ handle_msg({timeout, Id, From}, #state{req_list = ReqList0} = State) ->
{ok, State};
_ ->
ReqList = lists:keydelete(Id, 1, ReqList0),
- ssh_channel:reply(From, {error, timeout}),
+ ssh_client_channel:reply(From, {error, timeout}),
{ok, State#state{req_list = ReqList}}
end;
@@ -880,7 +886,7 @@ handle_options([Opt|Rest], Sftp, Chan, Ssh) ->
handle_options(Rest, Sftp, Chan, [Opt|Ssh]).
call(Pid, Msg, TimeOut) ->
- ssh_channel:call(Pid, {{timeout, TimeOut}, Msg}, infinity).
+ ssh_client_channel:call(Pid, {{timeout, TimeOut}, Msg}, infinity).
handle_reply(State, <<?UINT32(Len),Reply:Len/binary,Rest/binary>>) ->
do_handle_reply(State, Reply, Rest);
@@ -899,7 +905,7 @@ do_handle_reply(#state{xf = Xf} = State,
true ->
ok
end,
- ssh_channel:reply(From, ok)
+ ssh_client_channel:reply(From, ok)
end,
State#state{xf = Xf#ssh_xfer{vsn = Version, ext = Ext}, rep_buf = Rest};
@@ -947,7 +953,7 @@ async_reply(ReqID, Reply, _From={To,_}, State) ->
State.
sync_reply(Reply, From, State) ->
- catch (ssh_channel:reply(From, Reply)),
+ catch (ssh_client_channel:reply(From, Reply)),
State.
open2(OrigReqID,FileName,Handle,Mode,Async,From,State) ->
@@ -1460,3 +1466,21 @@ format_channel_start_error({shutdown, Reason}) ->
Reason;
format_channel_start_error(Reason) ->
Reason.
+
+%%%################################################################
+%%%#
+%%%# Tracing
+%%%#
+
+dbg_trace(points, _, _) -> [terminate];
+
+dbg_trace(flags, terminate, _) -> [c];
+dbg_trace(on, terminate, _) -> dbg:tp(?MODULE, terminate, 2, x);
+dbg_trace(off, terminate, _) -> dbg:ctpg(?MODULE, terminate, 2);
+dbg_trace(format, terminate, {call, {?MODULE,terminate, [Reason, State]}}) ->
+ ["Sftp Terminating:\n",
+ io_lib:format("Reason: ~p,~nState:~n~s", [Reason, wr_record(State)])
+ ].
+
+?wr_record(state).
+
diff --git a/lib/ssh/src/ssh_sftpd.erl b/lib/ssh/src/ssh_sftpd.erl
index 427edf01ab..5ec12e2d04 100644
--- a/lib/ssh/src/ssh_sftpd.erl
+++ b/lib/ssh/src/ssh_sftpd.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@
-module(ssh_sftpd).
--behaviour(ssh_daemon_channel).
+-behaviour(ssh_server_channel).
-include_lib("kernel/include/file.hrl").
@@ -38,6 +38,8 @@
-export([init/1, handle_ssh_msg/2, handle_msg/2, terminate/2]).
+-export([dbg_trace/3]).
+
-record(state, {
xf, % [{channel,ssh_xfer states}...]
cwd, % current dir (on first connect)
@@ -56,21 +58,7 @@
%%====================================================================
%% API
%%====================================================================
--spec init(Args :: term()) ->
- {ok, State :: term()} | {ok, State :: term(), timeout() | hibernate} |
- {stop, Reason :: term()} | ignore.
-
--spec terminate(Reason :: (normal | shutdown | {shutdown, term()} |
- term()),
- State :: term()) ->
- term().
-
--spec handle_msg(Msg ::term(), State :: term()) ->
- {ok, State::term()} | {stop, ChannelId::integer(), State::term()}.
--spec handle_ssh_msg({ssh_cm, ConnectionRef::term(), SshMsg::term()},
- State::term()) -> {ok, State::term()} |
- {stop, ChannelId::integer(),
- State::term()}.
+-spec subsystem_spec(list()) -> subsystem_spec().
subsystem_spec(Options) ->
{"sftp", {?MODULE, Options}}.
@@ -137,9 +125,9 @@ handle_ssh_msg({ssh_cm, _, {signal, _, _}}, State) ->
%% Ignore signals according to RFC 4254 section 6.9.
{ok, State};
-handle_ssh_msg({ssh_cm, _, {exit_signal, ChannelId, _, Error, _}}, State) ->
- Report = io_lib:format("Connection closed by peer ~n Error ~p~n",
- [Error]),
+handle_ssh_msg({ssh_cm, _, {exit_signal, ChannelId, Signal, Error, _}}, State) ->
+ Report = io_lib:format("Connection closed by peer signal ~p~n Error ~p~n",
+ [Signal,Error]),
error_logger:error_report(Report),
{stop, ChannelId, State};
@@ -360,10 +348,12 @@ handle_op(?SSH_FXP_REMOVE, ReqId, <<?UINT32(PLen), BPath:PLen/binary>>,
case IsDir of %% This version 6 we still have ver 5
true when Vsn > 5 ->
ssh_xfer:xf_send_status(State0#state.xf, ReqId,
- ?SSH_FX_FILE_IS_A_DIRECTORY, "File is a directory");
+ ?SSH_FX_FILE_IS_A_DIRECTORY, "File is a directory"),
+ State0;
true ->
ssh_xfer:xf_send_status(State0#state.xf, ReqId,
- ?SSH_FX_FAILURE, "File is a directory");
+ ?SSH_FX_FAILURE, "File is a directory"),
+ State0;
false ->
{Status, FS1} = FileMod:delete(Path, FS0),
State1 = State0#state{file_state = FS1},
@@ -518,11 +508,8 @@ close_our_file({_,Fd}, FileMod, FS0) ->
FS1.
%%% stat: do the stat
-stat(Vsn, ReqId, Data, State, F) when Vsn =< 3->
- <<?UINT32(BLen), BPath:BLen/binary>> = Data,
- stat(ReqId, unicode:characters_to_list(BPath), State, F);
-stat(Vsn, ReqId, Data, State, F) when Vsn >= 4->
- <<?UINT32(BLen), BPath:BLen/binary, ?UINT32(_Flags)>> = Data,
+stat(_Vsn, ReqId, Data, State, F) ->
+ <<?UINT32(BLen), BPath:BLen/binary, _/binary>> = Data,
stat(ReqId, unicode:characters_to_list(BPath), State, F).
fstat(Vsn, ReqId, Data, State) when Vsn =< 3->
@@ -947,3 +934,20 @@ maybe_increase_recv_window(ConnectionManager, ChannelId, Options) ->
Increment =< 0 ->
do_nothing
end.
+
+%%%################################################################
+%%%#
+%%%# Tracing
+%%%#
+
+dbg_trace(points, _, _) -> [terminate];
+
+dbg_trace(flags, terminate, _) -> [c];
+dbg_trace(on, terminate, _) -> dbg:tp(?MODULE, terminate, 2, x);
+dbg_trace(off, terminate, _) -> dbg:ctpg(?MODULE, terminate, 2);
+dbg_trace(format, terminate, {call, {?MODULE,terminate, [Reason, State]}}) ->
+ ["SftpD Terminating:\n",
+ io_lib:format("Reason: ~p,~nState:~n~s", [Reason, wr_record(State)])
+ ].
+
+?wr_record(state).
diff --git a/lib/ssh/src/ssh_shell.erl b/lib/ssh/src/ssh_shell.erl
index 17224b6ef4..cdc9a6df5b 100644
--- a/lib/ssh/src/ssh_shell.erl
+++ b/lib/ssh/src/ssh_shell.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -22,18 +22,21 @@
-module(ssh_shell).
+-include("ssh.hrl").
-include("ssh_connect.hrl").
%%% As this is an user interactive client it behaves like a daemon
%%% channel inspite of it being a client.
--behaviour(ssh_daemon_channel).
+-behaviour(ssh_server_channel).
-%% ssh_channel callbacks
+%% ssh_server_channel callbacks
-export([init/1, handle_msg/2, handle_ssh_msg/2, terminate/2]).
%% Spawn export
-export([input_loop/2]).
+-export([dbg_trace/3]).
+
-record(state,
{
io, %% Io process
@@ -43,23 +46,8 @@
).
%%====================================================================
-%% ssh_channel callbacks
+%% ssh_server_channel callbacks
%%====================================================================
--spec init(Args :: term()) ->
- {ok, State :: term()} | {ok, State :: term(), timeout() | hibernate} |
- {stop, Reason :: term()} | ignore.
-
--spec terminate(Reason :: (normal | shutdown | {shutdown, term()} |
- term()),
- State :: term()) ->
- term().
-
--spec handle_msg(Msg ::term(), State :: term()) ->
- {ok, State::term()} | {stop, ChannelId::integer(), State::term()}.
--spec handle_ssh_msg({ssh_cm, ConnectionRef::term(), SshMsg::term()},
- State::term()) -> {ok, State::term()} |
- {stop, ChannelId::integer(),
- State::term()}.
%%--------------------------------------------------------------------
%% Function: init(Args) -> {ok, State}
@@ -194,3 +182,20 @@ get_ancestors() ->
A when is_list(A) -> A;
_ -> []
end.
+
+%%%################################################################
+%%%#
+%%%# Tracing
+%%%#
+
+dbg_trace(points, _, _) -> [terminate];
+
+dbg_trace(flags, terminate, _) -> [c];
+dbg_trace(on, terminate, _) -> dbg:tp(?MODULE, terminate, 2, x);
+dbg_trace(off, terminate, _) -> dbg:ctpg(?MODULE, terminate, 2);
+dbg_trace(format, terminate, {call, {?MODULE,terminate, [Reason, State]}}) ->
+ ["Shell Terminating:\n",
+ io_lib:format("Reason: ~p,~nState:~n~s", [Reason, wr_record(State)])
+ ].
+
+?wr_record(state).
diff --git a/lib/ssh/src/ssh_subsystem_sup.erl b/lib/ssh/src/ssh_subsystem_sup.erl
index 77da240a66..5fc8f7e764 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-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -48,7 +48,7 @@ connection_supervisor(SupPid) ->
channel_supervisor(SupPid) ->
Children = supervisor:which_children(SupPid),
- ssh_channel_sup(Children).
+ ssh_server_channel_sup(Children).
%%%=========================================================================
%%% Supervisor callback
@@ -78,8 +78,8 @@ ssh_connection_child_spec(Role, Address, Port, _Profile, Options) ->
}.
ssh_channel_child_spec(Role, Address, Port, _Profile, Options) ->
- #{id => id(Role, ssh_channel_sup, Address, Port),
- start => {ssh_channel_sup, start_link, [Options]},
+ #{id => id(Role, ssh_server_channel_sup, Address, Port),
+ start => {ssh_server_channel_sup, start_link, [Options]},
restart => temporary,
type => supervisor
}.
@@ -92,10 +92,10 @@ ssh_connection_sup([{_, Child, _, [ssh_connection_sup]} | _]) ->
ssh_connection_sup([_ | Rest]) ->
ssh_connection_sup(Rest).
-ssh_channel_sup([{_, Child, _, [ssh_channel_sup]} | _]) ->
+ssh_server_channel_sup([{_, Child, _, [ssh_server_channel_sup]} | _]) ->
Child;
-ssh_channel_sup([_ | Rest]) ->
- ssh_channel_sup(Rest).
+ssh_server_channel_sup([_ | Rest]) ->
+ ssh_server_channel_sup(Rest).
diff --git a/lib/ssh/src/ssh_sup.erl b/lib/ssh/src/ssh_sup.erl
index 8183016ba5..61afbcd2ed 100644
--- a/lib/ssh/src/ssh_sup.erl
+++ b/lib/ssh/src/ssh_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_system_sup.erl b/lib/ssh/src/ssh_system_sup.erl
index 17f990c5d8..ed7c0c2bd5 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-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -88,11 +88,11 @@ stop_listener(Address, Port, Profile) ->
stop_system(SysSup) ->
- spawn(fun() -> sshd_sup:stop_child(SysSup) end),
+ catch sshd_sup:stop_child(SysSup),
ok.
stop_system(Address, Port, Profile) ->
- spawn(fun() -> sshd_sup:stop_child(Address, Port, Profile) end),
+ catch sshd_sup:stop_child(Address, Port, Profile),
ok.
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 975053d301..eaab13433a 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -36,7 +36,7 @@
default_algorithms/0, default_algorithms/1,
algo_classes/0, algo_class/1,
algo_two_spec_classes/0, algo_two_spec_class/1,
- handle_packet_part/4,
+ handle_packet_part/5,
handle_hello_version/1,
key_exchange_init_msg/1,
key_init/3, new_keys_message/1,
@@ -51,7 +51,11 @@
extract_public_key/1,
ssh_packet/2, pack/2,
valid_key_sha_alg/2,
- sha/1, sign/3, verify/5]).
+ sha/1, sign/3, verify/5,
+ get_host_key/2,
+ call_KeyCb/3]).
+
+-export([dbg_trace/3]).
%%% For test suites
-export([pack/3, adjust_algs_for_peer_version/2]).
@@ -102,12 +106,14 @@ algo_two_spec_class(_) -> false.
default_algorithms(kex) ->
supported_algorithms(kex, [
- 'diffie-hellman-group1-sha1' % Gone in OpenSSH 7.3.p1
+ %% Gone in OpenSSH 7.3.p1:
+ 'diffie-hellman-group1-sha1'
]);
default_algorithms(cipher) ->
supported_algorithms(cipher, same(['AEAD_AES_128_GCM',
- 'AEAD_AES_256_GCM']));
+ 'AEAD_AES_256_GCM'
+ ]));
default_algorithms(mac) ->
supported_algorithms(mac, same(['AEAD_AES_128_GCM',
'AEAD_AES_256_GCM']));
@@ -121,13 +127,18 @@ supported_algorithms() -> [{K,supported_algorithms(K)} || K <- algo_classes()].
supported_algorithms(kex) ->
select_crypto_supported(
[
- {'ecdh-sha2-nistp384', [{public_keys,ecdh}, {ec_curve,secp384r1}, {hashs,sha384}]},
- {'ecdh-sha2-nistp521', [{public_keys,ecdh}, {ec_curve,secp521r1}, {hashs,sha512}]},
- {'ecdh-sha2-nistp256', [{public_keys,ecdh}, {ec_curve,secp256r1}, {hashs,sha256}]},
+ {'ecdh-sha2-nistp384', [{public_keys,ecdh}, {curves,secp384r1}, {hashs,sha384}]},
+ {'ecdh-sha2-nistp521', [{public_keys,ecdh}, {curves,secp521r1}, {hashs,sha512}]},
+ {'ecdh-sha2-nistp256', [{public_keys,ecdh}, {curves,secp256r1}, {hashs,sha256}]},
{'diffie-hellman-group-exchange-sha256', [{public_keys,dh}, {hashs,sha256}]},
{'diffie-hellman-group16-sha512', [{public_keys,dh}, {hashs,sha512}]}, % In OpenSSH 7.3.p1
{'diffie-hellman-group18-sha512', [{public_keys,dh}, {hashs,sha512}]}, % In OpenSSH 7.3.p1
{'diffie-hellman-group14-sha256', [{public_keys,dh}, {hashs,sha256}]}, % In OpenSSH 7.3.p1
+ %% https://tools.ietf.org/html/draft-ietf-curdle-ssh-curves
+ %% Secure Shell (SSH) Key Exchange Method using Curve25519 and Curve448
+ {'curve25519-sha256', [{public_keys,ecdh}, {curves,x25519}, {hashs,sha256}]},
+ {'[email protected]', [{public_keys,ecdh}, {curves,x25519}, {hashs,sha256}]},
+ {'curve448-sha512', [{public_keys,ecdh}, {curves,x448}, {hashs,sha512}]},
{'diffie-hellman-group14-sha1', [{public_keys,dh}, {hashs,sha}]},
{'diffie-hellman-group-exchange-sha1', [{public_keys,dh}, {hashs,sha}]},
{'diffie-hellman-group1-sha1', [{public_keys,dh}, {hashs,sha}]}
@@ -135,9 +146,11 @@ supported_algorithms(kex) ->
supported_algorithms(public_key) ->
select_crypto_supported(
[
- {'ecdsa-sha2-nistp384', [{public_keys,ecdsa}, {hashs,sha384}, {ec_curve,secp384r1}]},
- {'ecdsa-sha2-nistp521', [{public_keys,ecdsa}, {hashs,sha512}, {ec_curve,secp521r1}]},
- {'ecdsa-sha2-nistp256', [{public_keys,ecdsa}, {hashs,sha256}, {ec_curve,secp256r1}]},
+ {'ecdsa-sha2-nistp384', [{public_keys,ecdsa}, {hashs,sha384}, {curves,secp384r1}]},
+ {'ecdsa-sha2-nistp521', [{public_keys,ecdsa}, {hashs,sha512}, {curves,secp521r1}]},
+ {'ecdsa-sha2-nistp256', [{public_keys,ecdsa}, {hashs,sha256}, {curves,secp256r1}]},
+ {'ssh-ed25519', [{public_keys,eddsa}, {curves,ed25519} ]},
+ {'ssh-ed448', [{public_keys,eddsa}, {curves,ed448} ]},
{'ssh-rsa', [{public_keys,rsa}, {hashs,sha} ]},
{'rsa-sha2-256', [{public_keys,rsa}, {hashs,sha256} ]},
{'rsa-sha2-512', [{public_keys,rsa}, {hashs,sha512} ]},
@@ -148,25 +161,26 @@ supported_algorithms(cipher) ->
same(
select_crypto_supported(
[
- {'[email protected]', [{ciphers,{aes_gcm,256}}]},
- {'aes256-ctr', [{ciphers,{aes_ctr,256}}]},
- {'aes192-ctr', [{ciphers,{aes_ctr,192}}]},
- {'[email protected]', [{ciphers,{aes_gcm,128}}]},
- {'aes128-ctr', [{ciphers,{aes_ctr,128}}]},
- {'AEAD_AES_256_GCM', [{ciphers,{aes_gcm,256}}]},
- {'AEAD_AES_128_GCM', [{ciphers,{aes_gcm,128}}]},
- {'aes128-cbc', [{ciphers,aes_cbc128}]},
- {'3des-cbc', [{ciphers,des3_cbc}]}
+ {'[email protected]', [{ciphers,chacha20}, {macs,poly1305}]},
+ {'[email protected]', [{ciphers,aes_256_gcm}]},
+ {'aes256-ctr', [{ciphers,aes_256_ctr}]},
+ {'aes192-ctr', [{ciphers,aes_192_ctr}]},
+ {'[email protected]', [{ciphers,aes_128_gcm}]},
+ {'aes128-ctr', [{ciphers,aes_128_ctr}]},
+ {'AEAD_AES_256_GCM', [{ciphers,aes_256_gcm}]},
+ {'AEAD_AES_128_GCM', [{ciphers,aes_128_gcm}]},
+ {'aes128-cbc', [{ciphers,aes_128_cbc}]},
+ {'3des-cbc', [{ciphers,des_ede3_cbc}]}
]
));
supported_algorithms(mac) ->
same(
select_crypto_supported(
- [{'hmac-sha2-256', [{hashs,sha256}]},
- {'hmac-sha2-512', [{hashs,sha512}]},
- {'hmac-sha1', [{hashs,sha}]},
- {'AEAD_AES_128_GCM', [{ciphers,{aes_gcm,128}}]},
- {'AEAD_AES_256_GCM', [{ciphers,{aes_gcm,256}}]}
+ [{'hmac-sha2-256', [{macs,hmac}, {hashs,sha256}]},
+ {'hmac-sha2-512', [{macs,hmac}, {hashs,sha512}]},
+ {'hmac-sha1', [{macs,hmac}, {hashs,sha}]},
+ {'AEAD_AES_128_GCM', [{ciphers,aes_128_gcm}]},
+ {'AEAD_AES_256_GCM', [{ciphers,aes_256_gcm}]}
]
));
supported_algorithms(compression) ->
@@ -319,10 +333,11 @@ handle_kexinit_msg(#ssh_msg_kexinit{} = CounterPart, #ssh_msg_kexinit{} = Own,
key_exchange_first_msg(Algos#alg.kex,
Ssh#ssh{algorithms = Algos})
catch
- _:_ ->
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- description = "Selection of key exchange algorithm failed"})
+ Class:Error ->
+ ?DISCONNECT(?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
+ io_lib:format("Kexinit failed in client: ~p:~p",
+ [Class,Error])
+ )
end;
handle_kexinit_msg(#ssh_msg_kexinit{} = CounterPart, #ssh_msg_kexinit{} = Own,
@@ -335,10 +350,11 @@ handle_kexinit_msg(#ssh_msg_kexinit{} = CounterPart, #ssh_msg_kexinit{} = Own,
Algos ->
{ok, Ssh#ssh{algorithms = Algos}}
catch
- _:_ ->
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- description = "Selection of key exchange algorithm failed"})
+ Class:Error ->
+ ?DISCONNECT(?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
+ io_lib:format("Kexinit failed in server: ~p:~p",
+ [Class,Error])
+ )
end.
@@ -399,7 +415,10 @@ key_exchange_first_msg(Kex, Ssh0=#ssh{opts=Opts}) when Kex == 'diffie-hellman-gr
key_exchange_first_msg(Kex, Ssh0) when Kex == 'ecdh-sha2-nistp256' ;
Kex == 'ecdh-sha2-nistp384' ;
- Kex == 'ecdh-sha2-nistp521' ->
+ Kex == 'ecdh-sha2-nistp521' ;
+ Kex == 'curve25519-sha256' ;
+ Kex == '[email protected]';
+ Kex == 'curve448-sha512' ->
Curve = ecdh_curve(Kex),
{Public, Private} = generate_key(ecdh, Curve),
{SshPacket, Ssh1} = ssh_packet(#ssh_msg_kex_ecdh_init{q_c=Public}, Ssh0),
@@ -416,7 +435,8 @@ key_exchange_first_msg(Kex, Ssh0) when Kex == 'ecdh-sha2-nistp256' ;
%%%
handle_kexdh_init(#ssh_msg_kexdh_init{e = E},
Ssh0 = #ssh{algorithms = #alg{kex=Kex,
- hkey=SignAlg} = Algs}) ->
+ hkey=SignAlg} = Algs,
+ opts = Opts}) ->
%% server
{G, P} = dh_group(Kex),
if
@@ -424,7 +444,7 @@ handle_kexdh_init(#ssh_msg_kexdh_init{e = E},
Sz = dh_bits(Algs),
{Public, Private} = generate_key(dh, [P,G,2*Sz]),
K = compute_key(dh, E, Private, [P,G]),
- MyPrivHostKey = get_host_key(Ssh0, SignAlg),
+ MyPrivHostKey = get_host_key(SignAlg, Opts),
MyPubHostKey = extract_public_key(MyPrivHostKey),
H = kex_hash(Ssh0, MyPubHostKey, sha(Kex), {E,Public,K}),
H_SIG = sign(H, sha(SignAlg), MyPrivHostKey),
@@ -439,12 +459,10 @@ handle_kexdh_init(#ssh_msg_kexdh_init{e = E},
session_id = sid(Ssh1, H)}};
true ->
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{
- code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- description = "Key exchange failed, 'e' out of bounds"},
- {error,bad_e_from_peer}
- )
+ ?DISCONNECT(?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
+ io_lib:format("Kexdh init failed, received 'e' out of bounds~n E=~p~n P=~p",
+ [E,P])
+ )
end.
handle_kexdh_reply(#ssh_msg_kexdh_reply{public_host_key = PeerPubHostKey,
@@ -464,20 +482,16 @@ handle_kexdh_reply(#ssh_msg_kexdh_reply{public_host_key = PeerPubHostKey,
exchanged_hash = H,
session_id = sid(Ssh, H)})};
Error ->
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{
- code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- description = "Key exchange failed"},
- Error)
+ ?DISCONNECT(?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
+ io_lib:format("Kexdh init failed. Verify host key: ~p",[Error])
+ )
end;
true ->
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{
- code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- description = "Key exchange failed, 'f' out of bounds"},
- bad_f_from_peer
- )
+ ?DISCONNECT(?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
+ io_lib:format("Kexdh init failed, received 'f' out of bounds~n F=~p~n P=~p",
+ [F,P])
+ )
end.
@@ -501,11 +515,9 @@ handle_kex_dh_gex_request(#ssh_msg_kex_dh_gex_request{min = Min0,
keyex_info = {Min0, Max0, NBits}
}};
{error,_} ->
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{
- code = ?SSH_DISCONNECT_PROTOCOL_ERROR,
- description = "No possible diffie-hellman-group-exchange group found"
- })
+ ?DISCONNECT(?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
+ io_lib:format("No possible diffie-hellman-group-exchange group found",[])
+ )
end;
handle_kex_dh_gex_request(#ssh_msg_kex_dh_gex_request_old{n = NBits},
@@ -535,20 +547,14 @@ handle_kex_dh_gex_request(#ssh_msg_kex_dh_gex_request_old{n = NBits},
keyex_info = {-1, -1, NBits} % flag for kex_hash calc
}};
{error,_} ->
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{
- code = ?SSH_DISCONNECT_PROTOCOL_ERROR,
- description = "No possible diffie-hellman-group-exchange group found"
- })
+ ?DISCONNECT(?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
+ io_lib:format("No possible diffie-hellman-group-exchange group found",[])
+ )
end;
handle_kex_dh_gex_request(_, _) ->
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{
- code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- description = "Key exchange failed, bad values in ssh_msg_kex_dh_gex_request"},
- bad_ssh_msg_kex_dh_gex_request).
-
+ ?DISCONNECT(?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
+ "Key exchange failed, bad values in ssh_msg_kex_dh_gex_request").
adjust_gex_min_max(Min0, Max0, Opts) ->
{Min1, Max1} = ?GET_OPT(dh_gex_limits, Opts),
@@ -558,11 +564,8 @@ adjust_gex_min_max(Min0, Max0, Opts) ->
Min2 =< Max2 ->
{Min2, Max2};
Max2 < Min2 ->
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{
- code = ?SSH_DISCONNECT_PROTOCOL_ERROR,
- description = "No possible diffie-hellman-group-exchange group possible"
- })
+ ?DISCONNECT(?SSH_DISCONNECT_PROTOCOL_ERROR,
+ "No possible diffie-hellman-group-exchange group possible")
end.
@@ -580,14 +583,15 @@ handle_kex_dh_gex_init(#ssh_msg_kex_dh_gex_init{e = E},
#ssh{keyex_key = {{Private, Public}, {G, P}},
keyex_info = {Min, Max, NBits},
algorithms = #alg{kex=Kex,
- hkey=SignAlg}} = Ssh0) ->
+ hkey=SignAlg},
+ opts = Opts} = Ssh0) ->
%% server
if
1=<E, E=<(P-1) ->
K = compute_key(dh, E, Private, [P,G]),
if
1<K, K<(P-1) ->
- MyPrivHostKey = get_host_key(Ssh0, SignAlg),
+ MyPrivHostKey = get_host_key(SignAlg, Opts),
MyPubHostKey = extract_public_key(MyPrivHostKey),
H = kex_hash(Ssh0, MyPubHostKey, sha(Kex), {Min,NBits,Max,P,G,E,Public,K}),
H_SIG = sign(H, sha(SignAlg), MyPrivHostKey),
@@ -600,18 +604,15 @@ handle_kex_dh_gex_init(#ssh_msg_kex_dh_gex_init{e = E},
session_id = sid(Ssh, H)
}};
true ->
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{
- code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- description = "Key exchange failed, 'K' out of bounds"},
- bad_K)
+ ?DISCONNECT(?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
+ "Kexdh init failed, received 'k' out of bounds"
+ )
end;
true ->
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{
- code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- description = "Key exchange failed, 'e' out of bounds"},
- bad_e_from_peer)
+ ?DISCONNECT(?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
+ io_lib:format("Kexdh gex init failed, received 'e' out of bounds~n E=~p~n P=~p",
+ [E,P])
+ )
end.
handle_kex_dh_gex_reply(#ssh_msg_kex_dh_gex_reply{public_host_key = PeerPubHostKey,
@@ -634,28 +635,22 @@ handle_kex_dh_gex_reply(#ssh_msg_kex_dh_gex_reply{public_host_key = PeerPubHostK
{ok, SshPacket, install_alg(snd, Ssh#ssh{shared_secret = ssh_bits:mpint(K),
exchanged_hash = H,
session_id = sid(Ssh, H)})};
- _Error ->
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{
- code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- description = "Key exchange failed"
- })
+ Error ->
+ ?DISCONNECT(?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
+ io_lib:format("Kexdh gex reply failed. Verify host key: ~p",[Error])
+ )
end;
true ->
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{
- code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- description = "Key exchange failed, 'K' out of bounds"},
- bad_K)
+ ?DISCONNECT(?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
+ "Kexdh gex init failed, 'K' out of bounds"
+ )
end;
true ->
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{
- code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- description = "Key exchange failed, 'f' out of bounds"},
- bad_f_from_peer
- )
+ ?DISCONNECT(?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
+ io_lib:format("Kexdh gex init failed, received 'f' out of bounds~n F=~p~n P=~p",
+ [F,P])
+ )
end.
%%%----------------------------------------------------------------
@@ -664,7 +659,8 @@ handle_kex_dh_gex_reply(#ssh_msg_kex_dh_gex_reply{public_host_key = PeerPubHostK
%%%
handle_kex_ecdh_init(#ssh_msg_kex_ecdh_init{q_c = PeerPublic},
Ssh0 = #ssh{algorithms = #alg{kex=Kex,
- hkey=SignAlg}}) ->
+ hkey=SignAlg},
+ opts = Opts}) ->
%% at server
Curve = ecdh_curve(Kex),
{MyPublic, MyPrivate} = generate_key(ecdh, Curve),
@@ -672,7 +668,7 @@ handle_kex_ecdh_init(#ssh_msg_kex_ecdh_init{q_c = PeerPublic},
compute_key(ecdh, PeerPublic, MyPrivate, Curve)
of
K ->
- MyPrivHostKey = get_host_key(Ssh0, SignAlg),
+ MyPrivHostKey = get_host_key(SignAlg, Opts),
MyPubHostKey = extract_public_key(MyPrivHostKey),
H = kex_hash(Ssh0, MyPubHostKey, sha(Curve), {PeerPublic, MyPublic, K}),
H_SIG = sign(H, sha(SignAlg), MyPrivHostKey),
@@ -686,12 +682,13 @@ handle_kex_ecdh_init(#ssh_msg_kex_ecdh_init{q_c = PeerPublic},
exchanged_hash = H,
session_id = sid(Ssh1, H)}}
catch
- _:_ ->
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{
- code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- description = "Peer ECDH public key is invalid"},
- invalid_peer_public_key)
+ Class:Error ->
+ ?DISCONNECT(?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
+ io_lib:format("ECDH compute key failed in server: ~p:~p~n"
+ "Kex: ~p, Curve: ~p~n"
+ "PeerPublic: ~p",
+ [Class,Error,Kex,Curve,PeerPublic])
+ )
end.
handle_kex_ecdh_reply(#ssh_msg_kex_ecdh_reply{public_host_key = PeerPubHostKey,
@@ -713,19 +710,16 @@ handle_kex_ecdh_reply(#ssh_msg_kex_ecdh_reply{public_host_key = PeerPubHostKey,
exchanged_hash = H,
session_id = sid(Ssh, H)})};
Error ->
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{
- code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- description = "Key exchange failed"},
- Error)
+ ?DISCONNECT(?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
+ io_lib:format("ECDH reply failed. Verify host key: ~p",[Error])
+ )
end
catch
- _:_ ->
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{
- code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- description = "Peer ECDH public key is invalid"},
- invalid_peer_public_key)
+ Class:Error ->
+ ?DISCONNECT(?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
+ io_lib:format("Peer ECDH public key seem invalid: ~p:~p",
+ [Class,Error])
+ )
end.
@@ -735,11 +729,11 @@ handle_new_keys(#ssh_msg_newkeys{}, Ssh0) ->
#ssh{} = Ssh ->
{ok, Ssh}
catch
- _C:_Error -> %% TODO: Throw earlier ....
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR,
- description = "Install alg failed"
- })
+ Class:Error -> %% TODO: Throw earlier ...
+ ?DISCONNECT(?SSH_DISCONNECT_PROTOCOL_ERROR,
+ io_lib:format("Install alg failed: ~p:~p",
+ [Class,Error])
+ )
end.
@@ -772,8 +766,7 @@ ext_info_message(#ssh{role=server,
send_ext_info=true,
opts = Opts} = Ssh0) ->
AlgsList = lists:map(fun erlang:atom_to_list/1,
- proplists:get_value(public_key,
- ?GET_OPT(preferred_algorithms, Opts))),
+ ?GET_OPT(pref_public_key_algs, Opts)),
Msg = #ssh_msg_ext_info{nr_extensions = 1,
data = [{"server-sig-algs", string:join(AlgsList,",")}]
},
@@ -791,10 +784,8 @@ sid(#ssh{session_id = Id}, _) -> Id.
%%
%% The host key should be read from storage
%%
-get_host_key(SSH, SignAlg) ->
- #ssh{key_cb = {KeyCb,KeyCbOpts}, opts = Opts} = SSH,
- UserOpts = ?GET_OPT(user_options, Opts),
- case KeyCb:host_key(SignAlg, [{key_cb_private,KeyCbOpts}|UserOpts]) of
+get_host_key(SignAlg, Opts) ->
+ case call_KeyCb(host_key, [SignAlg], Opts) of
{ok, PrivHostKey} ->
%% Check the key - the KeyCb may be a buggy plugin
case valid_key_sha_alg(PrivHostKey, SignAlg) of
@@ -805,6 +796,11 @@ get_host_key(SSH, SignAlg) ->
exit({error, {Result, unsupported_key_type}})
end.
+call_KeyCb(F, Args, Opts) ->
+ {KeyCb,KeyCbOpts} = ?GET_OPT(key_cb, Opts),
+ UserOpts = ?GET_OPT(user_options, Opts),
+ apply(KeyCb, F, Args ++ [[{key_cb_private,KeyCbOpts}|UserOpts]]).
+
extract_public_key(#'RSAPrivateKey'{modulus = N, publicExponent = E}) ->
#'RSAPublicKey'{modulus = N, publicExponent = E};
extract_public_key(#'DSAPrivateKey'{y = Y, p = P, q = Q, g = G}) ->
@@ -812,6 +808,8 @@ extract_public_key(#'DSAPrivateKey'{y = Y, p = P, q = Q, g = G}) ->
extract_public_key(#'ECPrivateKey'{parameters = {namedCurve,OID},
publicKey = Q}) ->
{#'ECPoint'{point=Q}, {namedCurve,OID}};
+extract_public_key({ed_pri, Alg, Pub, _Priv}) ->
+ {ed_pub, Alg, Pub};
extract_public_key(#{engine:=_, key_id:=_, algorithm:=Alg} = M) ->
case {Alg, crypto:privkey_to_pubkey(Alg, M)} of
{rsa, [E,N]} ->
@@ -871,29 +869,30 @@ accepted_host(Ssh, PeerName, Public, Opts) ->
end.
-yes_no(Ssh, Prompt) ->
- (Ssh#ssh.io_cb):yes_no(Prompt, Ssh#ssh.opts).
+yes_no(#ssh{opts=Opts}, Prompt) ->
+ IoCb = ?GET_INTERNAL_OPT(io_cb, Opts, ssh_io),
+ IoCb:yes_no(Prompt, Opts).
fmt_hostkey('ssh-rsa') -> "RSA";
fmt_hostkey('ssh-dss') -> "DSA";
+fmt_hostkey('ssh-ed25519') -> "ED25519";
+fmt_hostkey('ssh-ed448') -> "ED448";
fmt_hostkey(A) when is_atom(A) -> fmt_hostkey(atom_to_list(A));
fmt_hostkey("ecdsa"++_) -> "ECDSA";
fmt_hostkey(X) -> X.
-known_host_key(#ssh{opts = Opts, key_cb = {KeyCb,KeyCbOpts}, peer = {PeerName,_}} = Ssh,
+known_host_key(#ssh{opts = Opts, peer = {PeerName,_}} = Ssh,
Public, Alg) ->
- UserOpts = ?GET_OPT(user_options, Opts),
- case is_host_key(KeyCb, Public, PeerName, Alg, [{key_cb_private,KeyCbOpts}|UserOpts]) of
- {_,true} ->
+ case call_KeyCb(is_host_key, [Public, PeerName, Alg], Opts) of
+ true ->
ok;
- {_,false} ->
+ false ->
DoAdd = ?GET_OPT(save_accepted_host, Opts),
case accepted_host(Ssh, PeerName, Public, Opts) of
true when DoAdd == true ->
- {_,R} = add_host_key(KeyCb, PeerName, Public, [{key_cb_private,KeyCbOpts}|UserOpts]),
- R;
+ call_KeyCb(add_host_key, [PeerName, Public], Opts);
true when DoAdd == false ->
ok;
false ->
@@ -903,13 +902,6 @@ known_host_key(#ssh{opts = Opts, key_cb = {KeyCb,KeyCbOpts}, peer = {PeerName,_}
end
end.
-is_host_key(KeyCb, Public, PeerName, Alg, Data) ->
- {KeyCb, KeyCb:is_host_key(Public, PeerName, Alg, Data)}.
-
-add_host_key(KeyCb, PeerName, Public, Data) ->
- {KeyCb, KeyCb:add_host_key(PeerName, Public, Data)}.
-
-
%% Each of the algorithm strings MUST be a comma-separated list of
%% algorithm names (see ''Algorithm Naming'' in [SSH-ARCH]). Each
%% supported (allowed) algorithm MUST be listed in order of preference.
@@ -993,13 +985,14 @@ select_algorithm(Role, Client, Server, Opts) ->
%%% the exchanged MAC algorithms are ignored and there doesn't have to be
%%% a matching MAC.
-aead_gcm_simultan('[email protected]', _) -> {'AEAD_AES_128_GCM', 'AEAD_AES_128_GCM'};
-aead_gcm_simultan('[email protected]', _) -> {'AEAD_AES_256_GCM', 'AEAD_AES_256_GCM'};
-aead_gcm_simultan('AEAD_AES_128_GCM', _) -> {'AEAD_AES_128_GCM', 'AEAD_AES_128_GCM'};
-aead_gcm_simultan('AEAD_AES_256_GCM', _) -> {'AEAD_AES_256_GCM', 'AEAD_AES_256_GCM'};
-aead_gcm_simultan(_, 'AEAD_AES_128_GCM') -> {'AEAD_AES_128_GCM', 'AEAD_AES_128_GCM'};
-aead_gcm_simultan(_, 'AEAD_AES_256_GCM') -> {'AEAD_AES_256_GCM', 'AEAD_AES_256_GCM'};
-aead_gcm_simultan(Cipher, Mac) -> {Cipher,Mac}.
+aead_gcm_simultan('[email protected]', _) -> {'AEAD_AES_128_GCM', 'AEAD_AES_128_GCM'};
+aead_gcm_simultan('[email protected]', _) -> {'AEAD_AES_256_GCM', 'AEAD_AES_256_GCM'};
+aead_gcm_simultan('AEAD_AES_128_GCM'=C, _) -> {C, C};
+aead_gcm_simultan('AEAD_AES_256_GCM'=C, _) -> {C, C};
+aead_gcm_simultan(_, 'AEAD_AES_128_GCM'=C) -> {C, C};
+aead_gcm_simultan(_, 'AEAD_AES_256_GCM'=C) -> {C, C};
+aead_gcm_simultan('[email protected]'=C, _)-> {C, C};
+aead_gcm_simultan(Cipher, Mac) -> {Cipher,Mac}.
select_encrypt_decrypt(client, Client, Server) ->
@@ -1057,9 +1050,7 @@ install_alg(Dir, SSH) ->
alg_setup(snd, SSH) ->
ALG = SSH#ssh.algorithms,
- SSH#ssh{kex = ALG#alg.kex,
- hkey = ALG#alg.hkey,
- encrypt = ALG#alg.encrypt,
+ SSH#ssh{encrypt = ALG#alg.encrypt,
send_mac = ALG#alg.send_mac,
send_mac_size = mac_digest_size(ALG#alg.send_mac),
compress = ALG#alg.compress,
@@ -1071,9 +1062,7 @@ alg_setup(snd, SSH) ->
alg_setup(rcv, SSH) ->
ALG = SSH#ssh.algorithms,
- SSH#ssh{kex = ALG#alg.kex,
- hkey = ALG#alg.hkey,
- decrypt = ALG#alg.decrypt,
+ SSH#ssh{decrypt = ALG#alg.decrypt,
recv_mac = ALG#alg.recv_mac,
recv_mac_size = mac_digest_size(ALG#alg.recv_mac),
decompress = ALG#alg.decompress,
@@ -1115,10 +1104,9 @@ select_all(CL, SL) when length(CL) + length(SL) < ?MAX_NUM_ALGORITHMS ->
%% algorithms used by client and server (client pref)
lists:map(fun(ALG) -> list_to_atom(ALG) end, (CL -- A));
select_all(CL, SL) ->
- Err = lists:concat(["Received too many algorithms (",length(CL),"+",length(SL)," >= ",?MAX_NUM_ALGORITHMS,")."]),
- ssh_connection_handler:disconnect(
- #ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR,
- description = Err}).
+ Error = lists:concat(["Received too many algorithms (",length(CL),"+",length(SL)," >= ",?MAX_NUM_ALGORITHMS,")."]),
+ ?DISCONNECT(?SSH_DISCONNECT_PROTOCOL_ERROR,
+ Error).
select([], []) ->
@@ -1152,7 +1140,7 @@ pack(PlainText,
encrypt = CryptoAlg} = Ssh0, PacketLenDeviationForTests) when is_binary(PlainText) ->
{Ssh1, CompressedPlainText} = compress(Ssh0, PlainText),
- {EcryptedPacket, MAC, Ssh3} =
+ {FinalPacket, Ssh3} =
case pkt_type(CryptoAlg) of
common ->
PaddingLen = padding_length(4+1+size(CompressedPlainText), Ssh0),
@@ -1161,16 +1149,15 @@ pack(PlainText,
PlainPacketData = <<?UINT32(PlainPacketLen),?BYTE(PaddingLen), CompressedPlainText/binary, Padding/binary>>,
{Ssh2, EcryptedPacket0} = encrypt(Ssh1, PlainPacketData),
MAC0 = mac(MacAlg, MacKey, SeqNum, PlainPacketData),
- {EcryptedPacket0, MAC0, Ssh2};
+ {<<EcryptedPacket0/binary,MAC0/binary>>, Ssh2};
aead ->
PaddingLen = padding_length(1+size(CompressedPlainText), Ssh0),
Padding = ssh_bits:random(PaddingLen),
PlainPacketLen = 1 + PaddingLen + size(CompressedPlainText) + PacketLenDeviationForTests,
PlainPacketData = <<?BYTE(PaddingLen), CompressedPlainText/binary, Padding/binary>>,
- {Ssh2, {EcryptedPacket0,MAC0}} = encrypt(Ssh1, {<<?UINT32(PlainPacketLen)>>,PlainPacketData}),
- {<<?UINT32(PlainPacketLen),EcryptedPacket0/binary>>, MAC0, Ssh2}
+ {Ssh2, {EcryptedPacket0,MAC0}} = encrypt(Ssh1, <<?UINT32(PlainPacketLen),PlainPacketData/binary>>),
+ {<<EcryptedPacket0/binary,MAC0/binary>>, Ssh2}
end,
- FinalPacket = [EcryptedPacket, MAC],
Ssh = Ssh3#ssh{send_sequence = (SeqNum+1) band 16#ffffffff},
{FinalPacket, Ssh}.
@@ -1190,31 +1177,31 @@ padding_length(Size, #ssh{encrypt_block_size = BlockSize,
-handle_packet_part(<<>>, Encrypted0, undefined, #ssh{decrypt = CryptoAlg} = Ssh0) ->
+handle_packet_part(<<>>, Encrypted0, AEAD0, undefined, #ssh{decrypt = CryptoAlg} = Ssh0) ->
%% New ssh packet
case get_length(pkt_type(CryptoAlg), Encrypted0, Ssh0) of
get_more ->
%% too short to get the length
- {get_more, <<>>, Encrypted0, undefined, Ssh0};
+ {get_more, <<>>, Encrypted0, AEAD0, undefined, Ssh0};
- {ok, PacketLen, _, _, _} when PacketLen > ?SSH_MAX_PACKET_SIZE ->
+ {ok, PacketLen, _, _, _, _} when PacketLen > ?SSH_MAX_PACKET_SIZE ->
%% far too long message than expected
{error, {exceeds_max_size,PacketLen}};
- {ok, PacketLen, Decrypted, Encrypted1,
+ {ok, PacketLen, Decrypted, Encrypted1, AEAD,
#ssh{recv_mac_size = MacSize} = Ssh1} ->
%% enough bytes so we got the length and can calculate how many
%% more bytes to expect for a full packet
TotalNeeded = (4 + PacketLen + MacSize),
- handle_packet_part(Decrypted, Encrypted1, TotalNeeded, Ssh1)
+ handle_packet_part(Decrypted, Encrypted1, AEAD, TotalNeeded, Ssh1)
end;
-handle_packet_part(DecryptedPfx, EncryptedBuffer, TotalNeeded, Ssh0)
+handle_packet_part(DecryptedPfx, EncryptedBuffer, AEAD, TotalNeeded, Ssh0)
when (size(DecryptedPfx)+size(EncryptedBuffer)) < TotalNeeded ->
%% need more bytes to finalize the packet
- {get_more, DecryptedPfx, EncryptedBuffer, TotalNeeded, Ssh0};
+ {get_more, DecryptedPfx, EncryptedBuffer, AEAD, TotalNeeded, Ssh0};
-handle_packet_part(DecryptedPfx, EncryptedBuffer, TotalNeeded,
+handle_packet_part(DecryptedPfx, EncryptedBuffer, AEAD, TotalNeeded,
#ssh{recv_mac_size = MacSize,
decrypt = CryptoAlg} = Ssh0) ->
%% enough bytes to decode the packet.
@@ -1232,8 +1219,7 @@ handle_packet_part(DecryptedPfx, EncryptedBuffer, TotalNeeded,
{packet_decrypted, DecompressedPayload, NextPacketBytes, Ssh}
end;
aead ->
- PacketLenBin = DecryptedPfx,
- case decrypt(Ssh0, {PacketLenBin,EncryptedSfx,Mac}) of
+ case decrypt(Ssh0, {AEAD,EncryptedSfx,Mac}) of
{Ssh1, error} ->
{bad_mac, Ssh1};
{Ssh1, DecryptedSfx} ->
@@ -1250,22 +1236,25 @@ get_length(common, EncryptedBuffer, #ssh{decrypt_block_size = BlockSize} = Ssh0)
<<EncBlock:BlockSize/binary, EncryptedRest/binary>> = EncryptedBuffer,
{Ssh,
<<?UINT32(PacketLen),_/binary>> = Decrypted} = decrypt(Ssh0, EncBlock),
- {ok, PacketLen, Decrypted, EncryptedRest, Ssh};
+ {ok, PacketLen, Decrypted, EncryptedRest, <<>>, Ssh};
false ->
get_more
end;
+
get_length(aead, EncryptedBuffer, Ssh) ->
- case size(EncryptedBuffer) >= 4 of
- true ->
+ case {size(EncryptedBuffer) >= 4, Ssh#ssh.decrypt} of
+ {true, '[email protected]'} ->
+ <<EncryptedLen:4/binary, EncryptedRest/binary>> = EncryptedBuffer,
+ {Ssh1, PacketLenBin} = decrypt(Ssh, {length,EncryptedLen}),
+ <<?UINT32(PacketLen)>> = PacketLenBin,
+ {ok, PacketLen, PacketLenBin, EncryptedRest, EncryptedLen, Ssh1};
+ {true, _} ->
<<?UINT32(PacketLen), EncryptedRest/binary>> = EncryptedBuffer,
- {ok, PacketLen, <<?UINT32(PacketLen)>>, EncryptedRest, Ssh};
- false ->
+ {ok, PacketLen, <<?UINT32(PacketLen)>>, EncryptedRest, <<?UINT32(PacketLen)>>, Ssh};
+ {false, _} ->
get_more
end.
-pkt_type('AEAD_AES_128_GCM') -> aead;
-pkt_type('AEAD_AES_256_GCM') -> aead;
-pkt_type(_) -> common.
payload(<<PacketLen:32, PaddingLen:8, PayloadAndPadding/binary>>) ->
PayloadLen = PacketLen - PaddingLen - 1,
@@ -1329,188 +1318,163 @@ verify(PlainText, HashAlg, Sig, Key, _) ->
%%% Unit: bytes
--record(cipher_data, {
- key_bytes,
- iv_bytes,
- block_bytes
- }).
+-record(cipher, {
+ impl,
+ key_bytes,
+ iv_bytes,
+ block_bytes,
+ pkt_type = common
+ }).
%%% Start of a more parameterized crypto handling.
cipher('AEAD_AES_128_GCM') ->
- #cipher_data{key_bytes = 16,
- iv_bytes = 12,
- block_bytes = 16};
+ #cipher{impl = aes_128_gcm,
+ key_bytes = 16,
+ iv_bytes = 12,
+ block_bytes = 16,
+ pkt_type = aead};
cipher('AEAD_AES_256_GCM') ->
- #cipher_data{key_bytes = 32,
- iv_bytes = 12,
- block_bytes = 16};
+ #cipher{impl = aes_256_gcm,
+ key_bytes = 32,
+ iv_bytes = 12,
+ block_bytes = 16,
+ pkt_type = aead};
cipher('3des-cbc') ->
- #cipher_data{key_bytes = 24,
- iv_bytes = 8,
- block_bytes = 8};
+ #cipher{impl = des_ede3_cbc,
+ key_bytes = 24,
+ iv_bytes = 8,
+ block_bytes = 8};
cipher('aes128-cbc') ->
- #cipher_data{key_bytes = 16,
- iv_bytes = 16,
- block_bytes = 16};
+ #cipher{impl = aes_128_cbc,
+ key_bytes = 16,
+ iv_bytes = 16,
+ block_bytes = 16};
cipher('aes128-ctr') ->
- #cipher_data{key_bytes = 16,
- iv_bytes = 16,
- block_bytes = 16};
+ #cipher{impl = aes_128_ctr,
+ key_bytes = 16,
+ iv_bytes = 16,
+ block_bytes = 16};
cipher('aes192-ctr') ->
- #cipher_data{key_bytes = 24,
- iv_bytes = 16,
- block_bytes = 16};
+ #cipher{impl = aes_192_ctr,
+ key_bytes = 24,
+ iv_bytes = 16,
+ block_bytes = 16};
cipher('aes256-ctr') ->
- #cipher_data{key_bytes = 32,
- iv_bytes = 16,
- block_bytes = 16}.
+ #cipher{impl = aes_256_ctr,
+ key_bytes = 32,
+ iv_bytes = 16,
+ block_bytes = 16};
+
+cipher('[email protected]') -> % FIXME: Verify!!
+ #cipher{impl = chacha20_poly1305,
+ key_bytes = 32,
+ iv_bytes = 12,
+ block_bytes = 8,
+ pkt_type = aead};
+
+cipher(_) ->
+ #cipher{}.
+
+
+pkt_type(SshCipher) -> (cipher(SshCipher))#cipher.pkt_type.
+
+decrypt_magic(server) -> {"A", "C"};
+decrypt_magic(client) -> {"B", "D"}.
+
+encrypt_magic(client) -> decrypt_magic(server);
+encrypt_magic(server) -> decrypt_magic(client).
+
encrypt_init(#ssh{encrypt = none} = Ssh) ->
{ok, Ssh};
-encrypt_init(#ssh{encrypt = 'AEAD_AES_128_GCM', role = client} = Ssh) ->
- IV = hash(Ssh, "A", 12*8),
- <<K:16/binary>> = hash(Ssh, "C", 128),
- {ok, Ssh#ssh{encrypt_keys = K,
- encrypt_block_size = 16,
- encrypt_ctx = IV}};
-encrypt_init(#ssh{encrypt = 'AEAD_AES_128_GCM', role = server} = Ssh) ->
- IV = hash(Ssh, "B", 12*8),
- <<K:16/binary>> = hash(Ssh, "D", 128),
- {ok, Ssh#ssh{encrypt_keys = K,
- encrypt_block_size = 16,
- encrypt_ctx = IV}};
-encrypt_init(#ssh{encrypt = 'AEAD_AES_256_GCM', role = client} = Ssh) ->
- IV = hash(Ssh, "A", 12*8),
- <<K:32/binary>> = hash(Ssh, "C", 256),
- {ok, Ssh#ssh{encrypt_keys = K,
- encrypt_block_size = 16,
- encrypt_ctx = IV}};
-encrypt_init(#ssh{encrypt = 'AEAD_AES_256_GCM', role = server} = Ssh) ->
- IV = hash(Ssh, "B", 12*8),
- <<K:32/binary>> = hash(Ssh, "D", 256),
- {ok, Ssh#ssh{encrypt_keys = K,
- encrypt_block_size = 16,
- encrypt_ctx = IV}};
-encrypt_init(#ssh{encrypt = '3des-cbc', role = client} = Ssh) ->
- IV = hash(Ssh, "A", 64),
- <<K1:8/binary, K2:8/binary, K3:8/binary>> = hash(Ssh, "C", 192),
- {ok, Ssh#ssh{encrypt_keys = {K1,K2,K3},
- encrypt_block_size = 8,
- encrypt_ctx = IV}};
-encrypt_init(#ssh{encrypt = '3des-cbc', role = server} = Ssh) ->
- IV = hash(Ssh, "B", 64),
- <<K1:8/binary, K2:8/binary, K3:8/binary>> = hash(Ssh, "D", 192),
- {ok, Ssh#ssh{encrypt_keys = {K1,K2,K3},
- encrypt_block_size = 8,
- encrypt_ctx = IV}};
-encrypt_init(#ssh{encrypt = 'aes128-cbc', role = client} = Ssh) ->
- IV = hash(Ssh, "A", 128),
- <<K:16/binary>> = hash(Ssh, "C", 128),
- {ok, Ssh#ssh{encrypt_keys = K,
- encrypt_block_size = 16,
+
+encrypt_init(#ssh{encrypt = '[email protected]', role = Role} = Ssh) ->
+ %% [email protected] uses two independent crypto streams, one (chacha20)
+ %% for the length used in stream mode, and the other (chacha20-poly1305) as AEAD for
+ %% the payload and to MAC the length||payload.
+ %% See draft-josefsson-ssh-chacha20-poly1305-openssh-00
+ {_, KeyMagic} = encrypt_magic(Role),
+ <<K2:32/binary,K1:32/binary>> = hash(Ssh, KeyMagic, 8*64),
+ {ok, Ssh#ssh{encrypt_keys = {K1,K2}
+ % encrypt_block_size = 16, %default = 8. What to set it to? 64 (openssl chacha.h)
+ % ctx and iv is setup for each packet
+ }};
+
+encrypt_init(#ssh{encrypt = SshCipher, role = Role} = Ssh) when SshCipher == 'AEAD_AES_128_GCM';
+ SshCipher == 'AEAD_AES_256_GCM' ->
+ {IvMagic, KeyMagic} = encrypt_magic(Role),
+ #cipher{impl = CryptoCipher,
+ key_bytes = KeyBytes,
+ iv_bytes = IvBytes,
+ block_bytes = BlockBytes} = cipher(SshCipher),
+ IV = hash(Ssh, IvMagic, 8*IvBytes),
+ K = hash(Ssh, KeyMagic, 8*KeyBytes),
+ {ok, Ssh#ssh{encrypt_cipher = CryptoCipher,
+ encrypt_keys = K,
+ encrypt_block_size = BlockBytes,
encrypt_ctx = IV}};
-encrypt_init(#ssh{encrypt = 'aes128-cbc', role = server} = Ssh) ->
- IV = hash(Ssh, "B", 128),
- <<K:16/binary>> = hash(Ssh, "D", 128),
- {ok, Ssh#ssh{encrypt_keys = K,
- encrypt_block_size = 16,
- encrypt_ctx = IV}};
-encrypt_init(#ssh{encrypt = 'aes128-ctr', role = client} = Ssh) ->
- IV = hash(Ssh, "A", 128),
- <<K:16/binary>> = hash(Ssh, "C", 128),
- State = crypto:stream_init(aes_ctr, K, IV),
- {ok, Ssh#ssh{encrypt_keys = K,
- encrypt_block_size = 16,
- encrypt_ctx = State}};
-encrypt_init(#ssh{encrypt = 'aes192-ctr', role = client} = Ssh) ->
- IV = hash(Ssh, "A", 128),
- <<K:24/binary>> = hash(Ssh, "C", 192),
- State = crypto:stream_init(aes_ctr, K, IV),
- {ok, Ssh#ssh{encrypt_keys = K,
- encrypt_block_size = 16,
- encrypt_ctx = State}};
-encrypt_init(#ssh{encrypt = 'aes256-ctr', role = client} = Ssh) ->
- IV = hash(Ssh, "A", 128),
- <<K:32/binary>> = hash(Ssh, "C", 256),
- State = crypto:stream_init(aes_ctr, K, IV),
- {ok, Ssh#ssh{encrypt_keys = K,
- encrypt_block_size = 16,
- encrypt_ctx = State}};
-encrypt_init(#ssh{encrypt = 'aes128-ctr', role = server} = Ssh) ->
- IV = hash(Ssh, "B", 128),
- <<K:16/binary>> = hash(Ssh, "D", 128),
- State = crypto:stream_init(aes_ctr, K, IV),
- {ok, Ssh#ssh{encrypt_keys = K,
- encrypt_block_size = 16,
- encrypt_ctx = State}};
-encrypt_init(#ssh{encrypt = 'aes192-ctr', role = server} = Ssh) ->
- IV = hash(Ssh, "B", 128),
- <<K:24/binary>> = hash(Ssh, "D", 192),
- State = crypto:stream_init(aes_ctr, K, IV),
- {ok, Ssh#ssh{encrypt_keys = K,
- encrypt_block_size = 16,
- encrypt_ctx = State}};
-encrypt_init(#ssh{encrypt = 'aes256-ctr', role = server} = Ssh) ->
- IV = hash(Ssh, "B", 128),
- <<K:32/binary>> = hash(Ssh, "D", 256),
- State = crypto:stream_init(aes_ctr, K, IV),
- {ok, Ssh#ssh{encrypt_keys = K,
- encrypt_block_size = 16,
- encrypt_ctx = State}}.
+
+encrypt_init(#ssh{encrypt = SshCipher, role = Role} = Ssh) ->
+ {IvMagic, KeyMagic} = encrypt_magic(Role),
+ #cipher{impl = CryptoCipher,
+ key_bytes = KeyBytes,
+ iv_bytes = IvBytes,
+ block_bytes = BlockBytes} = cipher(SshCipher),
+ IV = hash(Ssh, IvMagic, 8*IvBytes),
+ K = hash(Ssh, KeyMagic, 8*KeyBytes),
+ Ctx0 = crypto:crypto_init(CryptoCipher, K, IV, true),
+ {ok, Ssh#ssh{encrypt_cipher = CryptoCipher,
+ encrypt_block_size = BlockBytes,
+ encrypt_ctx = Ctx0}}.
encrypt_final(Ssh) ->
- {ok, Ssh#ssh{encrypt = none,
+ {ok, Ssh#ssh{encrypt = none,
encrypt_keys = undefined,
encrypt_block_size = 8,
encrypt_ctx = undefined
}}.
+
encrypt(#ssh{encrypt = none} = Ssh, Data) ->
{Ssh, Data};
-encrypt(#ssh{encrypt = 'AEAD_AES_128_GCM',
- encrypt_keys = K,
- encrypt_ctx = IV0} = Ssh, Data={_AAD,_Ptext}) ->
- Enc = {_Ctext,_Ctag} = crypto:block_encrypt(aes_gcm, K, IV0, Data),
- IV = next_gcm_iv(IV0),
- {Ssh#ssh{encrypt_ctx = IV}, Enc};
-encrypt(#ssh{encrypt = 'AEAD_AES_256_GCM',
- encrypt_keys = K,
- encrypt_ctx = IV0} = Ssh, Data={_AAD,_Ptext}) ->
- Enc = {_Ctext,_Ctag} = crypto:block_encrypt(aes_gcm, K, IV0, Data),
+
+encrypt(#ssh{encrypt = '[email protected]',
+ encrypt_keys = {K1,K2},
+ send_sequence = Seq} = Ssh,
+ <<LenData:4/binary, PayloadData/binary>>) ->
+ %% Encrypt length
+ IV1 = <<0:8/unit:8, Seq:8/unit:8>>,
+ EncLen = crypto:crypto_one_time(chacha20, K1, IV1, LenData, true),
+ %% Encrypt payload
+ IV2 = <<1:8/little-unit:8, Seq:8/unit:8>>,
+ EncPayloadData = crypto:crypto_one_time(chacha20, K2, IV2, PayloadData, true),
+ %% MAC tag
+ PolyKey = crypto:crypto_one_time(chacha20, K2, <<0:8/unit:8,Seq:8/unit:8>>, <<0:32/unit:8>>, true),
+ EncBytes = <<EncLen/binary,EncPayloadData/binary>>,
+ Ctag = crypto:poly1305(PolyKey, EncBytes),
+ %% Result
+ {Ssh, {EncBytes,Ctag}};
+
+encrypt(#ssh{encrypt = SshCipher,
+ encrypt_cipher = CryptoCipher,
+ encrypt_keys = K,
+ encrypt_ctx = IV0} = Ssh,
+ <<LenData:4/binary, PayloadData/binary>>) when SshCipher == 'AEAD_AES_128_GCM' ;
+ SshCipher == 'AEAD_AES_256_GCM' ->
+ {Ctext,Ctag} = crypto:crypto_one_time_aead(CryptoCipher, K, IV0, PayloadData, LenData, true),
IV = next_gcm_iv(IV0),
- {Ssh#ssh{encrypt_ctx = IV}, Enc};
-encrypt(#ssh{encrypt = '3des-cbc',
- encrypt_keys = {K1,K2,K3},
- encrypt_ctx = IV0} = Ssh, Data) ->
- Enc = crypto:block_encrypt(des3_cbc, [K1,K2,K3], IV0, Data),
- IV = crypto:next_iv(des3_cbc, Enc),
- {Ssh#ssh{encrypt_ctx = IV}, Enc};
-encrypt(#ssh{encrypt = 'aes128-cbc',
- encrypt_keys = K,
- encrypt_ctx = IV0} = Ssh, Data) ->
- Enc = crypto:block_encrypt(aes_cbc128, K,IV0,Data),
- IV = crypto:next_iv(aes_cbc, Enc),
- {Ssh#ssh{encrypt_ctx = IV}, Enc};
-encrypt(#ssh{encrypt = 'aes128-ctr',
- encrypt_ctx = State0} = Ssh, Data) ->
- {State, Enc} = crypto:stream_encrypt(State0,Data),
- {Ssh#ssh{encrypt_ctx = State}, Enc};
-encrypt(#ssh{encrypt = 'aes192-ctr',
- encrypt_ctx = State0} = Ssh, Data) ->
- {State, Enc} = crypto:stream_encrypt(State0,Data),
- {Ssh#ssh{encrypt_ctx = State}, Enc};
-encrypt(#ssh{encrypt = 'aes256-ctr',
- encrypt_ctx = State0} = Ssh, Data) ->
- {State, Enc} = crypto:stream_encrypt(State0,Data),
- {Ssh#ssh{encrypt_ctx = State}, Enc}.
-
+ {Ssh#ssh{encrypt_ctx = IV}, {<<LenData/binary,Ctext/binary>>,Ctag}};
+
+encrypt(#ssh{encrypt_ctx = Ctx0} = Ssh, Data) ->
+ Enc = crypto:crypto_update(Ctx0, Data),
+ {Ssh, Enc}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Decryption
@@ -1518,148 +1482,92 @@ encrypt(#ssh{encrypt = 'aes256-ctr',
decrypt_init(#ssh{decrypt = none} = Ssh) ->
{ok, Ssh};
-decrypt_init(#ssh{decrypt = 'AEAD_AES_128_GCM', role = client} = Ssh) ->
- IV = hash(Ssh, "B", 12*8),
- <<K:16/binary>> = hash(Ssh, "D", 128),
- {ok, Ssh#ssh{decrypt_keys = K,
- decrypt_block_size = 16,
- decrypt_ctx = IV}};
-decrypt_init(#ssh{decrypt = 'AEAD_AES_128_GCM', role = server} = Ssh) ->
- IV = hash(Ssh, "A", 12*8),
- <<K:16/binary>> = hash(Ssh, "C", 128),
- {ok, Ssh#ssh{decrypt_keys = K,
- decrypt_block_size = 16,
- decrypt_ctx = IV}};
-decrypt_init(#ssh{decrypt = 'AEAD_AES_256_GCM', role = client} = Ssh) ->
- IV = hash(Ssh, "B", 12*8),
- <<K:32/binary>> = hash(Ssh, "D", 256),
- {ok, Ssh#ssh{decrypt_keys = K,
- decrypt_block_size = 16,
- decrypt_ctx = IV}};
-decrypt_init(#ssh{decrypt = 'AEAD_AES_256_GCM', role = server} = Ssh) ->
- IV = hash(Ssh, "A", 12*8),
- <<K:32/binary>> = hash(Ssh, "C", 256),
- {ok, Ssh#ssh{decrypt_keys = K,
- decrypt_block_size = 16,
+
+decrypt_init(#ssh{decrypt = '[email protected]', role = Role} = Ssh) ->
+ {_, KeyMagic} = decrypt_magic(Role),
+ <<K2:32/binary,K1:32/binary>> = hash(Ssh, KeyMagic, 8*64),
+ {ok, Ssh#ssh{decrypt_keys = {K1,K2}
+ }};
+
+decrypt_init(#ssh{decrypt = SshCipher, role = Role} = Ssh) when SshCipher == 'AEAD_AES_128_GCM';
+ SshCipher == 'AEAD_AES_256_GCM' ->
+ {IvMagic, KeyMagic} = decrypt_magic(Role),
+ #cipher{impl = CryptoCipher,
+ key_bytes = KeyBytes,
+ iv_bytes = IvBytes,
+ block_bytes = BlockBytes} = cipher(SshCipher),
+ IV = hash(Ssh, IvMagic, 8*IvBytes),
+ K = hash(Ssh, KeyMagic, 8*KeyBytes),
+ {ok, Ssh#ssh{decrypt_cipher = CryptoCipher,
+ decrypt_keys = K,
+ decrypt_block_size = BlockBytes,
decrypt_ctx = IV}};
-decrypt_init(#ssh{decrypt = '3des-cbc', role = client} = Ssh) ->
- {IV, KD} = {hash(Ssh, "B", 64),
- hash(Ssh, "D", 192)},
- <<K1:8/binary, K2:8/binary, K3:8/binary>> = KD,
- {ok, Ssh#ssh{decrypt_keys = {K1,K2,K3}, decrypt_ctx = IV,
- decrypt_block_size = 8}};
-decrypt_init(#ssh{decrypt = '3des-cbc', role = server} = Ssh) ->
- {IV, KD} = {hash(Ssh, "A", 64),
- hash(Ssh, "C", 192)},
- <<K1:8/binary, K2:8/binary, K3:8/binary>> = KD,
- {ok, Ssh#ssh{decrypt_keys = {K1, K2, K3}, decrypt_ctx = IV,
- decrypt_block_size = 8}};
-decrypt_init(#ssh{decrypt = 'aes128-cbc', role = client} = Ssh) ->
- {IV, KD} = {hash(Ssh, "B", 128),
- hash(Ssh, "D", 128)},
- <<K:16/binary>> = KD,
- {ok, Ssh#ssh{decrypt_keys = K, decrypt_ctx = IV,
- decrypt_block_size = 16}};
-decrypt_init(#ssh{decrypt = 'aes128-cbc', role = server} = Ssh) ->
- {IV, KD} = {hash(Ssh, "A", 128),
- hash(Ssh, "C", 128)},
- <<K:16/binary>> = KD,
- {ok, Ssh#ssh{decrypt_keys = K, decrypt_ctx = IV,
- decrypt_block_size = 16}};
-decrypt_init(#ssh{decrypt = 'aes128-ctr', role = client} = Ssh) ->
- IV = hash(Ssh, "B", 128),
- <<K:16/binary>> = hash(Ssh, "D", 128),
- State = crypto:stream_init(aes_ctr, K, IV),
- {ok, Ssh#ssh{decrypt_keys = K,
- decrypt_block_size = 16,
- decrypt_ctx = State}};
-decrypt_init(#ssh{decrypt = 'aes192-ctr', role = client} = Ssh) ->
- IV = hash(Ssh, "B", 128),
- <<K:24/binary>> = hash(Ssh, "D", 192),
- State = crypto:stream_init(aes_ctr, K, IV),
- {ok, Ssh#ssh{decrypt_keys = K,
- decrypt_block_size = 16,
- decrypt_ctx = State}};
-decrypt_init(#ssh{decrypt = 'aes256-ctr', role = client} = Ssh) ->
- IV = hash(Ssh, "B", 128),
- <<K:32/binary>> = hash(Ssh, "D", 256),
- State = crypto:stream_init(aes_ctr, K, IV),
- {ok, Ssh#ssh{decrypt_keys = K,
- decrypt_block_size = 16,
- decrypt_ctx = State}};
-decrypt_init(#ssh{decrypt = 'aes128-ctr', role = server} = Ssh) ->
- IV = hash(Ssh, "A", 128),
- <<K:16/binary>> = hash(Ssh, "C", 128),
- State = crypto:stream_init(aes_ctr, K, IV),
- {ok, Ssh#ssh{decrypt_keys = K,
- decrypt_block_size = 16,
- decrypt_ctx = State}};
-decrypt_init(#ssh{decrypt = 'aes192-ctr', role = server} = Ssh) ->
- IV = hash(Ssh, "A", 128),
- <<K:24/binary>> = hash(Ssh, "C", 192),
- State = crypto:stream_init(aes_ctr, K, IV),
- {ok, Ssh#ssh{decrypt_keys = K,
- decrypt_block_size = 16,
- decrypt_ctx = State}};
-decrypt_init(#ssh{decrypt = 'aes256-ctr', role = server} = Ssh) ->
- IV = hash(Ssh, "A", 128),
- <<K:32/binary>> = hash(Ssh, "C", 256),
- State = crypto:stream_init(aes_ctr, K, IV),
- {ok, Ssh#ssh{decrypt_keys = K,
- decrypt_block_size = 16,
- decrypt_ctx = State}}.
-
-
+
+decrypt_init(#ssh{decrypt = SshCipher, role = Role} = Ssh) ->
+ {IvMagic, KeyMagic} = decrypt_magic(Role),
+ #cipher{impl = CryptoCipher,
+ key_bytes = KeyBytes,
+ iv_bytes = IvBytes,
+ block_bytes = BlockBytes} = cipher(SshCipher),
+ IV = hash(Ssh, IvMagic, 8*IvBytes),
+ K = hash(Ssh, KeyMagic, 8*KeyBytes),
+ Ctx0 = crypto:crypto_init(CryptoCipher, K, IV, false),
+ {ok, Ssh#ssh{decrypt_cipher = CryptoCipher,
+ decrypt_block_size = BlockBytes,
+ decrypt_ctx = Ctx0}}.
+
+
decrypt_final(Ssh) ->
{ok, Ssh#ssh {decrypt = none,
decrypt_keys = undefined,
decrypt_ctx = undefined,
decrypt_block_size = 8}}.
+
decrypt(Ssh, <<>>) ->
{Ssh, <<>>};
+
+decrypt(#ssh{decrypt = '[email protected]',
+ decrypt_keys = {K1,K2},
+ recv_sequence = Seq} = Ssh, Data) ->
+ case Data of
+ {length,EncryptedLen} ->
+ %% The length is decrypted separately in a first step
+ PacketLenBin = crypto:crypto_one_time(chacha20, K1, <<0:8/unit:8, Seq:8/unit:8>>, EncryptedLen, false),
+ {Ssh, PacketLenBin};
+ {AAD,Ctext,Ctag} ->
+ %% The length is already decrypted and used to divide the input
+ %% Check the mac (important that it is timing-safe):
+ PolyKey = crypto:crypto_one_time(chacha20, K2, <<0:8/unit:8,Seq:8/unit:8>>, <<0:32/unit:8>>, false),
+ case equal_const_time(Ctag, crypto:poly1305(PolyKey, <<AAD/binary,Ctext/binary>>)) of
+ true ->
+ %% MAC is ok, decode
+ IV2 = <<1:8/little-unit:8, Seq:8/unit:8>>,
+ PlainText = crypto:crypto_one_time(chacha20, K2, IV2, Ctext, false),
+ {Ssh, PlainText};
+ false ->
+ {Ssh,error}
+ end
+ end;
+
decrypt(#ssh{decrypt = none} = Ssh, Data) ->
{Ssh, Data};
-decrypt(#ssh{decrypt = 'AEAD_AES_128_GCM',
- decrypt_keys = K,
- decrypt_ctx = IV0} = Ssh, Data = {_AAD,_Ctext,_Ctag}) ->
- Dec = crypto:block_decrypt(aes_gcm, K, IV0, Data), % Dec = PlainText | error
- IV = next_gcm_iv(IV0),
- {Ssh#ssh{decrypt_ctx = IV}, Dec};
-decrypt(#ssh{decrypt = 'AEAD_AES_256_GCM',
+
+decrypt(#ssh{decrypt = SshCipher,
+ decrypt_cipher = CryptoCipher,
decrypt_keys = K,
- decrypt_ctx = IV0} = Ssh, Data = {_AAD,_Ctext,_Ctag}) ->
- Dec = crypto:block_decrypt(aes_gcm, K, IV0, Data), % Dec = PlainText | error
+ decrypt_ctx = IV0} = Ssh, {AAD,Ctext,Ctag}) when SshCipher == 'AEAD_AES_128_GCM' ;
+ SshCipher == 'AEAD_AES_256_GCM' ->
+ Dec = crypto:crypto_one_time_aead(CryptoCipher, K, IV0, Ctext, AAD, Ctag, false),
IV = next_gcm_iv(IV0),
{Ssh#ssh{decrypt_ctx = IV}, Dec};
-decrypt(#ssh{decrypt = '3des-cbc', decrypt_keys = Keys,
- decrypt_ctx = IV0} = Ssh, Data) ->
- {K1, K2, K3} = Keys,
- Dec = crypto:block_decrypt(des3_cbc, [K1,K2,K3], IV0, Data),
- IV = crypto:next_iv(des3_cbc, Data),
- {Ssh#ssh{decrypt_ctx = IV}, Dec};
-decrypt(#ssh{decrypt = 'aes128-cbc', decrypt_keys = Key,
- decrypt_ctx = IV0} = Ssh, Data) ->
- Dec = crypto:block_decrypt(aes_cbc128, Key,IV0,Data),
- IV = crypto:next_iv(aes_cbc, Data),
- {Ssh#ssh{decrypt_ctx = IV}, Dec};
-decrypt(#ssh{decrypt = 'aes128-ctr',
- decrypt_ctx = State0} = Ssh, Data) ->
- {State, Enc} = crypto:stream_decrypt(State0,Data),
- {Ssh#ssh{decrypt_ctx = State}, Enc};
-decrypt(#ssh{decrypt = 'aes192-ctr',
- decrypt_ctx = State0} = Ssh, Data) ->
- {State, Enc} = crypto:stream_decrypt(State0,Data),
- {Ssh#ssh{decrypt_ctx = State}, Enc};
-decrypt(#ssh{decrypt = 'aes256-ctr',
- decrypt_ctx = State0} = Ssh, Data) ->
- {State, Enc} = crypto:stream_decrypt(State0,Data),
- {Ssh#ssh{decrypt_ctx = State}, Enc}.
+decrypt(#ssh{decrypt_ctx = Ctx0} = Ssh, Data) ->
+ Dec = crypto:crypto_update(Ctx0, Data),
+ {Ssh, Dec}.
next_gcm_iv(<<Fixed:32, InvCtr:64>>) -> <<Fixed:32, (InvCtr+1):64>>.
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Compression
%%
@@ -1760,7 +1668,7 @@ send_mac_init(SSH) ->
Key = hash(SSH, "F", KeySize),
{ok, SSH#ssh { send_mac_key = Key }}
end;
- aead ->
+ _ ->
%% Not applicable
{ok, SSH}
end.
@@ -1781,7 +1689,7 @@ recv_mac_init(SSH) ->
Key = hash(SSH, "E", 8*mac_key_bytes(SSH#ssh.recv_mac)),
{ok, SSH#ssh { recv_mac_key = Key }}
end;
- aead ->
+ _ ->
%% Not applicable
{ok, SSH}
end.
@@ -1810,7 +1718,7 @@ mac('hmac-sha2-512', Key, SeqNum, Data) ->
hash(_SSH, _Char, 0) ->
<<>>;
hash(SSH, Char, N) ->
- HashAlg = sha(SSH#ssh.kex),
+ HashAlg = sha(SSH#ssh.algorithms#alg.kex),
K = SSH#ssh.shared_secret,
H = SSH#ssh.exchanged_hash,
K1 = crypto:hash(HashAlg, [K, H, Char, SSH#ssh.session_id]),
@@ -1828,6 +1736,7 @@ hash(K, H, Ki, N, HashAlg) ->
kex_hash(SSH, Key, HashAlg, Args) ->
crypto:hash(HashAlg, kex_plaintext(SSH,Key,Args)).
+
kex_plaintext(SSH, Key, Args) ->
EncodedKey = public_key:ssh_encode(Key, ssh2_pubkey),
<<?Estring(SSH#ssh.c_version), ?Estring(SSH#ssh.s_version),
@@ -1835,13 +1744,19 @@ kex_plaintext(SSH, Key, Args) ->
?Ebinary(EncodedKey),
(kex_alg_dependent(Args))/binary>>.
+
+kex_alg_dependent({Q_c, Q_s, K}) when is_binary(Q_c), is_binary(Q_s) ->
+ %% ecdh
+ <<?Ebinary(Q_c), ?Ebinary(Q_s), ?Empint(K)>>;
+
kex_alg_dependent({E, F, K}) ->
- %% diffie-hellman and ec diffie-hellman (with E = Q_c, F = Q_s)
+ %% diffie-hellman
<<?Empint(E), ?Empint(F), ?Empint(K)>>;
-kex_alg_dependent({-1, _, -1, _, _, E, F, K}) ->
+kex_alg_dependent({-1, NBits, -1, Prime, Gen, E, F, K}) ->
%% ssh_msg_kex_dh_gex_request_old
- <<?Empint(E), ?Empint(F), ?Empint(K)>>;
+ <<?Euint32(NBits),
+ ?Empint(Prime), ?Empint(Gen), ?Empint(E), ?Empint(F), ?Empint(K)>>;
kex_alg_dependent({Min, NBits, Max, Prime, Gen, E, F, K}) ->
%% diffie-hellman group exchange
@@ -1865,6 +1780,11 @@ valid_key_sha_alg(#'RSAPrivateKey'{}, 'ssh-rsa' ) -> true;
valid_key_sha_alg({_, #'Dss-Parms'{}}, 'ssh-dss') -> true;
valid_key_sha_alg(#'DSAPrivateKey'{}, 'ssh-dss') -> true;
+valid_key_sha_alg({ed_pub, ed25519,_}, 'ssh-ed25519') -> true;
+valid_key_sha_alg({ed_pri, ed25519,_,_},'ssh-ed25519') -> true;
+valid_key_sha_alg({ed_pub, ed448,_}, 'ssh-ed448') -> true;
+valid_key_sha_alg({ed_pri, ed448,_,_}, 'ssh-ed448') -> true;
+
valid_key_sha_alg({#'ECPoint'{},{namedCurve,OID}}, Alg) -> valid_key_sha_alg_ec(OID, Alg);
valid_key_sha_alg(#'ECPrivateKey'{parameters = {namedCurve,OID}}, Alg) -> valid_key_sha_alg_ec(OID, Alg);
valid_key_sha_alg(_, _) -> false.
@@ -1874,15 +1794,17 @@ valid_key_sha_alg_ec(OID, Alg) ->
Alg == list_to_atom("ecdsa-sha2-" ++ binary_to_list(Curve)).
+-dialyzer({no_match, public_algo/1}).
+
public_algo(#'RSAPublicKey'{}) -> 'ssh-rsa'; % FIXME: Not right with draft-curdle-rsa-sha2
public_algo({_, #'Dss-Parms'{}}) -> 'ssh-dss';
+public_algo({ed_pub, ed25519,_}) -> 'ssh-ed25519';
+public_algo({ed_pub, ed448,_}) -> 'ssh-ed448';
public_algo({#'ECPoint'{},{namedCurve,OID}}) ->
Curve = public_key:oid2ssh_curvename(OID),
list_to_atom("ecdsa-sha2-" ++ binary_to_list(Curve)).
-
-
sha('ssh-rsa') -> sha;
sha('rsa-sha2-256') -> sha256;
sha('rsa-sha2-384') -> sha384;
@@ -1891,6 +1813,8 @@ sha('ssh-dss') -> sha;
sha('ecdsa-sha2-nistp256') -> sha(secp256r1);
sha('ecdsa-sha2-nistp384') -> sha(secp384r1);
sha('ecdsa-sha2-nistp521') -> sha(secp521r1);
+sha('ssh-ed25519') -> undefined; % Included in the spec of ed25519
+sha('ssh-ed448') -> undefined; % Included in the spec of ed448
sha(secp256r1) -> sha256;
sha(secp384r1) -> sha384;
sha(secp521r1) -> sha512;
@@ -1907,6 +1831,11 @@ sha(?'secp521r1') -> sha(secp521r1);
sha('ecdh-sha2-nistp256') -> sha(secp256r1);
sha('ecdh-sha2-nistp384') -> sha(secp384r1);
sha('ecdh-sha2-nistp521') -> sha(secp521r1);
+sha('curve25519-sha256' ) -> sha256;
+sha('[email protected]' ) -> sha256;
+sha('curve448-sha512') -> sha512;
+sha(x25519) -> sha256;
+sha(x448) -> sha512;
sha(Str) when is_list(Str), length(Str)<50 -> sha(list_to_atom(Str)).
@@ -1918,6 +1847,7 @@ mac_key_bytes('hmac-sha2-256')-> 32;
mac_key_bytes('hmac-sha2-512')-> 64;
mac_key_bytes('AEAD_AES_128_GCM') -> 0;
mac_key_bytes('AEAD_AES_256_GCM') -> 0;
+mac_key_bytes('[email protected]') -> 0;
mac_key_bytes(none) -> 0.
mac_digest_size('hmac-sha1') -> 20;
@@ -1928,6 +1858,7 @@ mac_digest_size('hmac-sha2-256') -> 32;
mac_digest_size('hmac-sha2-512') -> 64;
mac_digest_size('AEAD_AES_128_GCM') -> 16;
mac_digest_size('AEAD_AES_256_GCM') -> 16;
+mac_digest_size('[email protected]') -> 16;
mac_digest_size(none) -> 0.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1950,11 +1881,13 @@ parallell_gen_key(Ssh = #ssh{keyex_key = {x, {G, P}},
Ssh#ssh{keyex_key = {{Private, Public}, {G, P}}}.
+generate_key(ecdh = Algorithm, Args) ->
+ crypto:generate_key(Algorithm, Args);
generate_key(Algorithm, Args) ->
{Public,Private} = crypto:generate_key(Algorithm, Args),
{crypto:bytes_to_integer(Public), crypto:bytes_to_integer(Private)}.
-
+
compute_key(Algorithm, OthersPublic, MyPrivate, Args) ->
Shared = crypto:compute_key(Algorithm, OthersPublic, MyPrivate, Args),
crypto:bytes_to_integer(Shared).
@@ -1963,16 +1896,18 @@ compute_key(Algorithm, OthersPublic, MyPrivate, Args) ->
dh_bits(#alg{encrypt = Encrypt,
send_mac = SendMac}) ->
C = cipher(Encrypt),
- 8 * lists:max([C#cipher_data.key_bytes,
- C#cipher_data.block_bytes,
- C#cipher_data.iv_bytes,
+ 8 * lists:max([C#cipher.key_bytes,
+ C#cipher.block_bytes,
+ C#cipher.iv_bytes,
mac_key_bytes(SendMac)
]).
ecdh_curve('ecdh-sha2-nistp256') -> secp256r1;
ecdh_curve('ecdh-sha2-nistp384') -> secp384r1;
-ecdh_curve('ecdh-sha2-nistp521') -> secp521r1.
-
+ecdh_curve('ecdh-sha2-nistp521') -> secp521r1;
+ecdh_curve('curve448-sha512' ) -> x448;
+ecdh_curve('curve25519-sha256' ) -> x25519;
+ecdh_curve('[email protected]' ) -> x25519.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
@@ -1988,46 +1923,18 @@ supported_algorithms(Key, BlackList) ->
select_crypto_supported(L) ->
- Sup = [{ec_curve,crypto_supported_curves()} | crypto:supports()],
+ Sup = crypto:supports(),
[Name || {Name,CryptoRequires} <- L,
crypto_supported(CryptoRequires, Sup)].
-crypto_supported_curves() ->
- try crypto:ec_curves()
- catch _:_ -> []
- end.
-
crypto_supported(Conditions, Supported) ->
lists:all( fun({Tag,CryptoName}) when is_atom(CryptoName) ->
- crypto_name_supported(Tag,CryptoName,Supported);
- ({Tag,{Name,Len}}) when is_integer(Len) ->
- crypto_name_supported(Tag,Name,Supported) andalso
- len_supported(Name,Len)
+ crypto_name_supported(Tag,CryptoName,Supported)
end, Conditions).
crypto_name_supported(Tag, CryptoName, Supported) ->
- lists:member(CryptoName, proplists:get_value(Tag,Supported,[])).
-
-len_supported(Name, Len) ->
- try
- case Name of
- aes_ctr ->
- {_, <<_/binary>>} =
- %% Test encryption
- crypto:stream_encrypt(crypto:stream_init(Name, <<0:Len>>, <<0:128>>), <<"">>);
- aes_gcm ->
- {<<_/binary>>, <<_/binary>>} =
- crypto:block_encrypt(Name,
- _Key = <<0:Len>>,
- _IV = <<0:12/unsigned-unit:8>>,
- {<<"AAD">>,"PT"})
- end
- of
- _ -> true
- catch
- _:_ -> false
- end.
-
+ Vs = proplists:get_value(Tag,Supported,[]),
+ lists:member(CryptoName, Vs).
same(Algs) -> [{client2server,Algs}, {server2client,Algs}].
@@ -2037,7 +1944,58 @@ same(Algs) -> [{client2server,Algs}, {server2client,Algs}].
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%% Compare two binaries in a timing safe maner.
+%%% The time spent in comparing should not be different depending on where in the binaries they differ.
+%%% This is to avoid a certain side-channel attac.
+equal_const_time(X1, X2) -> equal_const_time(X1, X2, true).
+
+equal_const_time(<<B1,R1/binary>>, <<B2,R2/binary>>, Truth) ->
+ equal_const_time(R1, R2, Truth and (B1 == B2));
+equal_const_time(<<>>, <<>>, Truth) ->
+ Truth;
+equal_const_time(_, _, _) ->
+ false.
+
+%%%-------- Remove CR, LF and following characters from a line
+
trim_tail(Str) ->
lists:takewhile(fun(C) ->
C=/=$\r andalso C=/=$\n
end, Str).
+
+%%%################################################################
+%%%#
+%%%# Tracing
+%%%#
+
+dbg_trace(points, _, _) -> [alg, ssh_messages, raw_messages, hello];
+
+dbg_trace(flags, hello, _) -> [c];
+dbg_trace(on, hello, _) -> dbg:tp(?MODULE,hello_version_msg,1,x),
+ dbg:tp(?MODULE,handle_hello_version,1,x);
+dbg_trace(off, hello, _) -> dbg:ctpg(?MODULE,hello_version_msg,1),
+ dbg:ctpg(?MODULE,handle_hello_version,1);
+
+dbg_trace(C, raw_messages, A) -> dbg_trace(C, hello, A);
+dbg_trace(C, ssh_messages, A) -> dbg_trace(C, hello, A);
+
+dbg_trace(flags, alg, _) -> [c];
+dbg_trace(on, alg, _) -> dbg:tpl(?MODULE,select_algorithm,4,x);
+dbg_trace(off, alg, _) -> dbg:ctpl(?MODULE,select_algorithm,4);
+
+
+dbg_trace(format, hello, {return_from,{?MODULE,hello_version_msg,1},Hello}) ->
+ ["Going to send hello message:\n",
+ Hello
+ ];
+dbg_trace(format, hello, {call,{?MODULE,handle_hello_version,[Hello]}}) ->
+ ["Received hello message:\n",
+ Hello
+ ];
+
+dbg_trace(format, alg, {return_from,{?MODULE,select_algorithm,4},{ok,Alg}}) ->
+ ["Negotiated algorithms:\n",
+ wr_record(Alg)
+ ].
+
+?wr_record(alg).
diff --git a/lib/ssh/src/ssh_transport.hrl b/lib/ssh/src/ssh_transport.hrl
index 87c3719514..f424a4ff63 100644
--- a/lib/ssh/src/ssh_transport.hrl
+++ b/lib/ssh/src/ssh_transport.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -220,6 +220,9 @@
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-define(DISCONNECT(Code, DetailedText),
+ ssh_connection_handler:disconnect(Code, DetailedText, ?MODULE, ?LINE)).
+
-define(SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT, 1).
-define(SSH_DISCONNECT_PROTOCOL_ERROR, 2).
-define(SSH_DISCONNECT_KEY_EXCHANGE_FAILED, 3).
diff --git a/lib/ssh/src/ssh_xfer.erl b/lib/ssh/src/ssh_xfer.erl
index e1680c120e..1d77ccb311 100644
--- a/lib/ssh/src/ssh_xfer.erl
+++ b/lib/ssh/src/ssh_xfer.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -734,7 +734,7 @@ decode_ATTR(Vsn, <<?UINT32(Flags), Tail/binary>>) ->
{Type,Tail2} =
if Vsn =< 3 ->
{?SSH_FILEXFER_TYPE_UNKNOWN, Tail};
- Vsn >= 5 ->
+ true ->
<<?BYTE(T), TL/binary>> = Tail,
{T, TL}
end,
diff --git a/lib/ssh/src/sshc_sup.erl b/lib/ssh/src/sshc_sup.erl
index fd4d8a3c07..869de244ac 100644
--- a/lib/ssh/src/sshc_sup.erl
+++ b/lib/ssh/src/sshc_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -27,7 +27,7 @@
-behaviour(supervisor).
--export([start_link/0, start_child/1, stop_child/1]).
+-export([start_link/0, start_child/1]).
%% Supervisor callback
-export([init/1]).
@@ -43,13 +43,6 @@ start_link() ->
start_child(Args) ->
supervisor:start_child(?MODULE, Args).
-stop_child(Client) ->
- spawn(fun() ->
- ClientSup = whereis(?SSHC_SUP),
- supervisor:terminate_child(ClientSup, Client)
- end),
- ok.
-
%%%=========================================================================
%%% Supervisor callback
%%%=========================================================================
diff --git a/lib/ssh/src/sshd_sup.erl b/lib/ssh/src/sshd_sup.erl
index 779a861a54..b5361abba5 100644
--- a/lib/ssh/src/sshd_sup.erl
+++ b/lib/ssh/src/sshd_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/.gitignore b/lib/ssh/test/.gitignore
new file mode 100644
index 0000000000..c9d5f086b3
--- /dev/null
+++ b/lib/ssh/test/.gitignore
@@ -0,0 +1,5 @@
+
+
+property_test/ssh_eqc_client_server_dirs/system
+property_test/ssh_eqc_client_server_dirs/user
+
diff --git a/lib/ssh/test/Makefile b/lib/ssh/test/Makefile
index 21359a0386..e221e94075 100644
--- a/lib/ssh/test/Makefile
+++ b/lib/ssh/test/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2017. All Rights Reserved.
+# Copyright Ericsson AB 2004-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -34,11 +34,12 @@ VSN=$(GS_VSN)
MODULES= \
ssh_algorithms_SUITE \
ssh_options_SUITE \
- ssh_renegotiate_SUITE \
ssh_basic_SUITE \
ssh_bench_SUITE \
+ ssh_chan_behaviours_SUITE \
ssh_compat_SUITE \
ssh_connection_SUITE \
+ ssh_dbg_SUITE \
ssh_engine_SUITE \
ssh_protocol_SUITE \
ssh_property_test_SUITE \
@@ -53,6 +54,8 @@ MODULES= \
ssh_key_cb_options \
ssh_key_cb_engine_keys \
ssh_trpt_test_lib \
+ ssh_chan_behaviours_client \
+ ssh_chan_behaviours_server \
ssh_echo_server \
ssh_bench_dev_null \
ssh_peername_sockname_server \
@@ -136,6 +139,6 @@ release_tests_spec: opt
$(INSTALL_DATA) ssh.spec ssh_bench.spec ssh.cover "$(RELSYSDIR)"
$(INSTALL_DATA) $(HRL_FILES_NEEDED_IN_TEST) "$(RELSYSDIR)"
chmod -R u+w "$(RELSYSDIR)"
- @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
+ @tar cf - *_SUITE_data property_test | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/ssh/test/property_test/ssh_eqc_client_info_timing.erl b/lib/ssh/test/property_test/ssh_eqc_client_info_timing.erl
index 19e2754eba..f4b521356f 100644
--- a/lib/ssh/test/property_test/ssh_eqc_client_info_timing.erl
+++ b/lib/ssh/test/property_test/ssh_eqc_client_info_timing.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -58,6 +58,7 @@
%%% Properties:
prop_seq(Config) ->
+ error_logger:tty(false),
{ok,Pid} = ssh_eqc_event_handler:add_report_handler(),
{_, _, Port} = init_daemon(Config),
numtests(1000,
@@ -66,16 +67,25 @@ prop_seq(Config) ->
send_bad_sequence(Port, Delay, Pid),
not any_relevant_error_report(Pid)
catch
- C:E -> io:format('~p:~p~n',[C,E]),
+ C:E:S -> ct:log("~p:~p~n~p",[C,E,S]),
false
end
)).
send_bad_sequence(Port, Delay, Pid) ->
- {ok,S} = gen_tcp:connect("localhost",Port,[]),
- gen_tcp:send(S,"Illegal info-string\r\n"),
- ssh_test_lib:sleep_microsec(Delay),
- gen_tcp:close(S).
+ send_bad_sequence(Port, Delay, Pid, 10).
+
+send_bad_sequence(Port, Delay, Pid, N) ->
+ case gen_tcp:connect("localhost",Port,[]) of
+ {ok,S} ->
+ gen_tcp:send(S,"Illegal info-string\r\n"),
+ ssh_test_lib:sleep_microsec(Delay),
+ gen_tcp:close(S);
+
+ {error,econnreset} when N>0 ->
+ timer:sleep(1),
+ send_bad_sequence(Port, Delay, Pid, N-1)
+ end.
any_relevant_error_report(Pid) ->
{ok, Reports} = ssh_eqc_event_handler:get_reports(Pid),
diff --git a/lib/ssh/test/property_test/ssh_eqc_client_server.erl b/lib/ssh/test/property_test/ssh_eqc_client_server.erl
index 39d0b4e410..acb0faa0c7 100644
--- a/lib/ssh/test/property_test/ssh_eqc_client_server.erl
+++ b/lib/ssh/test/property_test/ssh_eqc_client_server.erl
@@ -22,25 +22,27 @@
-module(ssh_eqc_client_server).
-compile(export_all).
+
+-proptest([proper]).
--include_lib("common_test/include/ct.hrl").
-
--ifdef(PROPER).
-%% Proper is not supported.
--else.
--ifdef(TRIQ).
-%% Proper is not supported.
+-ifndef(PROPER).
-else.
+%% Only use proper
+%%
+%% Previously only EQC was supported, but the changes to support PROPER is not
+%% just a wrapper. Since we do not have access to eqc we can't test the changes
+%% so therefore eqc is disabeled.
+%% However, with access to eqc it ought to be quite easy to re-enable eqc by
+%% studying the diff.
+-include_lib("proper/include/proper.hrl").
+-define(MOD_eqc,proper).
+
+-include_lib("common_test/include/ct.hrl").
%% Limit the testing time on CI server... this needs to be improved in % from total budget.
-define(TESTINGTIME(Prop), eqc:testing_time(30,Prop)).
-
--include_lib("eqc/include/eqc.hrl").
--include_lib("eqc/include/eqc_statem.hrl").
--eqc_group_commands(true).
-
-define(SSH_DIR,"ssh_eqc_client_server_dirs").
-define(sec, *1000).
@@ -51,10 +53,6 @@
port
}).
--record(conn,{ref,
- srvr_ref
- }).
-
-record(chan, {ref,
conn_ref,
subsystem,
@@ -65,7 +63,7 @@
initialized = false,
servers = [], % [#srvr{}]
clients = [],
- connections = [], % [#conn{}]
+ connections = [],
channels = [], % [#chan{}]
data_dir
}).
@@ -80,9 +78,8 @@
-define(SUBSYSTEMS, ["echo1", "echo2", "echo3", "echo4"]).
--define(SERVER_ADDRESS, { {127,1,0,choose(1,254)}, % IP
- choose(1024,65535) % Port
- }).
+-define(SERVER_ADDRESS, {127,0,0,1}). % Server listening IP. Darwin, Solaris & FreeBSD
+ % dislikes all other in 127.0.0.0/24
-define(SERVER_EXTRA_OPTIONS, [{parallel_login,bool()}] ).
@@ -104,10 +101,12 @@
%% To be called as eqc:quickcheck( ssh_eqc_client_server:prop_seq() ).
prop_seq() ->
- ?TESTINGTIME(do_prop_seq(?SSH_DIR)).
+ error_logger:tty(false),
+ ?TESTINGTIME(do_prop_seq(?SSH_DIR)).
%% To be called from a common_test test suite
prop_seq(CT_Config) ->
+ error_logger:tty(false),
do_prop_seq(full_path(?SSH_DIR, CT_Config)).
@@ -124,10 +123,12 @@ full_path(SSHdir, CT_Config) ->
SSHdir).
%%%----
prop_parallel() ->
+ error_logger:tty(false),
?TESTINGTIME(do_prop_parallel(?SSH_DIR)).
%% To be called from a common_test test suite
prop_parallel(CT_Config) ->
+ error_logger:tty(false),
do_prop_parallel(full_path(?SSH_DIR, CT_Config)).
do_prop_parallel(DataDir) ->
@@ -139,22 +140,22 @@ do_prop_parallel(DataDir) ->
end).
%%%----
-prop_parallel_multi() ->
- ?TESTINGTIME(do_prop_parallel_multi(?SSH_DIR)).
-
-%% To be called from a common_test test suite
-prop_parallel_multi(CT_Config) ->
- do_prop_parallel_multi(full_path(?SSH_DIR, CT_Config)).
-
-do_prop_parallel_multi(DataDir) ->
- setup_rsa(DataDir),
- ?FORALL(Repetitions,?SHRINK(1,[10]),
- ?FORALL(Cmds,parallel_commands(?MODULE),
- ?ALWAYS(Repetitions,
- begin
- {H,Sf,Result} = run_parallel_commands(?MODULE,Cmds,[{data_dir,DataDir}]),
- present_result(?MODULE, Cmds, {H,Sf,Result}, Result==ok)
- end))).
+%% prop_parallel_multi() ->
+%% ?TESTINGTIME(do_prop_parallel_multi(?SSH_DIR)).
+
+%% %% To be called from a common_test test suite
+%% prop_parallel_multi(CT_Config) ->
+%% do_prop_parallel_multi(full_path(?SSH_DIR, CT_Config)).
+
+%% do_prop_parallel_multi(DataDir) ->
+%% setup_rsa(DataDir),
+%% ?FORALL(Repetitions,?SHRINK(1,[10]),
+%% ?FORALL(Cmds,parallel_commands(?MODULE),
+%% ?ALWAYS(Repetitions,
+%% begin
+%% {H,Sf,Result} = run_parallel_commands(?MODULE,Cmds,[{data_dir,DataDir}]),
+%% present_result(?MODULE, Cmds, {H,Sf,Result}, Result==ok)
+%% end))).
%%%================================================================
%%% State machine spec
@@ -169,13 +170,50 @@ initial_state(DataDir) ->
ssh:start().
%%%----------------
-weight(S, ssh_send) -> 5*length([C || C<-S#state.channels, has_subsyst(C)]);
-weight(S, ssh_start_subsyst) -> 3*length([C || C<-S#state.channels, no_subsyst(C)]);
+weight(S, ssh_send) -> 20*length([C || C<-S#state.channels, has_subsyst(C)]);
+weight(S, ssh_start_subsyst) -> 10*length([C || C<-S#state.channels, no_subsyst(C)]);
weight(S, ssh_close_channel) -> 2*length([C || C<-S#state.channels, has_subsyst(C)]);
-weight(S, ssh_open_channel) -> length(S#state.connections);
+weight(S, ssh_open_channel) -> 2*length(S#state.connections);
weight(_S, _) -> 1.
%%%----------------
+fns() -> [initial_state,
+ ssh_server,
+ ssh_client,
+ ssh_open_connection,
+ ssh_close_connection,
+ ssh_open_channel,
+ ssh_close_channel,
+ ssh_start_subsyst,
+ ssh_send
+ ].
+
+call_f(Name, Sfx) ->
+ case get({Name,Sfx}) of
+ undefined -> F = list_to_atom(lists:concat([Name,"_",Sfx])),
+ put({Name,Sfx}, F),
+ F;
+ F when is_atom(F) -> F
+ end.
+
+-define(call(Name, What, Args), apply(?MODULE, call_f(Name,What), Args)).
+
+symbolic_call(S,Name) -> {call, ?MODULE, Name, ?call(Name,args,[S])}.
+
+may_generate(S, F) -> ?call(F,pre,[S]).
+
+command(S) ->
+ frequency([{weight(S,F), symbolic_call(S,F)} || F <- fns(),
+ may_generate(S, F)]
+ ).
+
+precondition(S, {call,_M,F,As}) -> try ?call(F, pre, [S,As])
+ catch _:undef -> try ?call(F,pre,[S]) catch _:undef -> true end
+ end.
+next_state(S, Res, {call,_M,F,As}) -> try ?call(F, next, [S,Res,As]) catch _:undef -> S end.
+postcondition(S, {call,_M,F,As}, Res) -> try ?call(F, post, [S,As,Res]) catch _:undef -> true end.
+
+%%%----------------
%%% Initialize
initial_state_pre(S) -> not S#state.initialized.
@@ -200,24 +238,34 @@ ssh_server_pre(S) -> S#state.initialized andalso
ssh_server_args(_) -> [?SERVER_ADDRESS, {var,data_dir}, ?SERVER_EXTRA_OPTIONS].
-ssh_server({IP,Port}, DataDir, ExtraOptions) ->
- ok(ssh:daemon(IP, Port,
- [
- {system_dir, system_dir(DataDir)},
- {user_dir, user_dir(DataDir)},
- {subsystems, [{SS, {ssh_eqc_subsys, [SS]}} || SS <- ?SUBSYSTEMS]}
- | ExtraOptions
- ])).
-
-ssh_server_post(_S, _Args, {error,eaddrinuse}) -> true;
-ssh_server_post(_S, _Args, Result) -> is_ok(Result).
-
-ssh_server_next(S, {error,eaddrinuse}, _) -> S;
-ssh_server_next(S, Result, [{IP,Port},_,_]) ->
- S#state{servers=[#srvr{ref = Result,
- address = IP,
- port = Port}
- | S#state.servers]}.
+ssh_server(IP0, DataDir, ExtraOptions) ->
+ case ssh:daemon(IP0, 0,
+ [
+ {system_dir, system_dir(DataDir)},
+ {user_dir, user_dir(DataDir)},
+ {subsystems, [{SS, {ssh_eqc_subsys, [SS]}} || SS <- ?SUBSYSTEMS]}
+ | ExtraOptions
+ ]) of
+ {ok,DaemonRef} ->
+ case ssh:daemon_info(DaemonRef) of
+ {ok, Props} ->
+ Port = proplists:get_value(port,Props),
+ IP = proplists:get_value(ip,Props),
+ #srvr{ref = DaemonRef,
+ address = IP,
+ port = Port};
+ Other ->
+ Other
+ end;
+ Other ->
+ Other
+ end.
+
+ssh_server_post(_S, _Args, #srvr{port=Port}) -> (0 < Port) andalso (Port < 65536);
+ssh_server_post(_S, _Args, _) -> false.
+
+ssh_server_next(S, Srvr, _) ->
+ S#state{servers=[Srvr | S#state.servers]}.
%%%----------------
%%% Start a new client
@@ -271,8 +319,7 @@ ssh_open_connection(#srvr{address=Ip, port=Port}, DataDir) ->
ssh_open_connection_post(_S, _Args, Result) -> is_ok(Result).
-ssh_open_connection_next(S, ConnRef, [#srvr{ref=SrvrRef},_]) ->
- S#state{connections=[#conn{ref=ConnRef, srvr_ref=SrvrRef}|S#state.connections]}.
+ssh_open_connection_next(S, ConnRef, [_,_]) -> S#state{connections=[ConnRef|S#state.connections]}.
%%%----------------
%%% Stop a new connection
@@ -282,12 +329,12 @@ ssh_close_connection_pre(S) -> S#state.connections /= [].
ssh_close_connection_args(S) -> [oneof(S#state.connections)].
-ssh_close_connection(#conn{ref=ConnectionRef}) -> ssh:close(ConnectionRef).
+ssh_close_connection(ConnectionRef) -> ssh:close(ConnectionRef).
-ssh_close_connection_next(S, _, [Conn=#conn{ref=ConnRef}]) ->
- S#state{connections = S#state.connections--[Conn],
- channels = [C || C <- S#state.channels,
- C#chan.conn_ref /= ConnRef]
+ssh_close_connection_next(S, _, [ConnRef]) ->
+ S#state{connections = S#state.connections--[ConnRef],
+ channels = [C || C <- S#state.channels,
+ C#chan.conn_ref /= ConnRef]
}.
%%%----------------
@@ -299,14 +346,14 @@ ssh_open_channel_pre(S) -> S#state.connections /= [].
ssh_open_channel_args(S) -> [oneof(S#state.connections)].
%%% For re-arrangement in parallel tests.
-ssh_open_channel_pre(S,[C]) -> lists:member(C,S#state.connections).
+ssh_open_channel_pre(S,[C]) when is_record(S,state) -> lists:member(C,S#state.connections).
-ssh_open_channel(#conn{ref=ConnectionRef}) ->
+ssh_open_channel(ConnectionRef) ->
ok(ssh_connection:session_channel(ConnectionRef, 20?sec)).
ssh_open_channel_post(_S, _Args, Result) -> is_ok(Result).
-ssh_open_channel_next(S, ChannelRef, [#conn{ref=ConnRef}]) ->
+ssh_open_channel_next(S, ChannelRef, [ConnRef]) ->
S#state{channels=[#chan{ref=ChannelRef,
conn_ref=ConnRef}
| S#state.channels]}.
@@ -326,9 +373,7 @@ ssh_close_channel_next(S, _, [C]) ->
S#state{channels = [Ci || Ci <- S#state.channels,
sig(C) /= sig(Ci)]}.
-
sig(C) -> {C#chan.ref, C#chan.conn_ref}.
-
%%%----------------
%%% Start a sub system on a channel
@@ -361,9 +406,10 @@ ssh_start_subsyst_next(S, _Result, [C,SS,Pid|_]) ->
ssh_send_pre(S) -> lists:any(fun has_subsyst/1, S#state.channels).
-ssh_send_args(S) -> [oneof(lists:filter(fun has_subsyst/1, S#state.channels)),
- choose(0,1),
- message()].
+ssh_send_args(S) ->
+ [oneof(lists:filter(fun has_subsyst/1, S#state.channels)),
+ choose(0,1),
+ message()].
%% For re-arrangement in parallel tests.
ssh_send_pre(S, [C|_]) -> lists:member(C, S#state.channels).
@@ -388,17 +434,17 @@ ssh_send(C=#chan{conn_ref=ConnectionRef, ref=ChannelRef, client_pid=Pid}, Type,
end).
ssh_send_blocking(_S, _Args) ->
- true.
+ true.
ssh_send_post(_S, [C,_,Msg], Response) when is_binary(Response) ->
- Expected = ssh_eqc_subsys:response(modify_msg(C,Msg), C#chan.subsystem),
+ Expected = ssh_eqc_subsys:response(modify_msg(C,Msg), C#chan.subsystem),
case Response of
Expected -> true;
_ -> {send_failed, size(Response), size(Expected)}
end;
ssh_send_post(_S, _Args, Response) ->
- {error,Response}.
+ {error,Response}.
modify_msg(_, <<>>) -> <<>>;
@@ -440,7 +486,11 @@ present_result(_Module, Cmds, _Triple, true) ->
true)))));
present_result(Module, Cmds, Triple, false) ->
- pretty_commands(Module, Cmds, Triple, [{show_states,true}], false).
+ pretty_comands(Module, Cmds, Triple, [{show_states,true}], false),
+ false. % Proper dislikes non-boolean results while eqc treats non-true as false.
+
+pretty_comands(Module, Cmds, Triple, Opts, Bool) ->
+ ct:log("Module = ~p,~n Cmds = ~p,~n Triple = ~p,~n Opts = ~p,~n Bool = ~p",[Module, Cmds, Triple, Opts, Bool]).
@@ -476,23 +526,35 @@ traverse_commands(Fseq, Fpar, {Seq, ParLs}) -> lists:append([Fseq(Seq)|Fpar(ParL
print_frequencies() -> print_frequencies(10).
print_frequencies(Ngroups) -> fun([]) -> io:format('Empty list!~n',[]);
- (L ) -> print_frequencies(L,Ngroups,0,element(1,lists:last(L)))
+ (L ) ->
+ try
+ M = lists:last(L),
+ Max = if is_integer(M) -> M;
+ is_tuple(M) -> element(1,L)
+ end,
+ print_frequencies(L,Ngroups,0,Max)
+ catch
+ C:E:S ->
+ ct:pal("~p:~p ~p:~p~n~p~n~p",[?MODULE,?LINE,C,E,S,L])
+ end
end.
+
print_frequencies(Ngroups, MaxValue) -> fun(L) -> print_frequencies(L,Ngroups,0,MaxValue) end.
print_frequencies(L, N, Min, Max) when N>Max -> print_frequencies(L++[{N,0}], N, Min, N);
-print_frequencies(L, N, Min, Max) ->
-%%io:format('L=~p~n',[L]),
+print_frequencies(L, N, Min, Max0) ->
try
+ Interval = round((Max0-Min)/N),
+ Max = Max0 + (Max0 rem Interval),
IntervalUpperLimits =
lists:reverse(
- [Max | tl(lists:reverse(lists:seq(Min,Max,round((Max-Min)/N))))]
+ [Max | tl(lists:reverse(lists:seq(Min,Max,Interval)))]
),
{Acc0,_} = lists:mapfoldl(fun(Upper,Lower) ->
{{{Lower,Upper},0}, Upper+1}
end, hd(IntervalUpperLimits), tl(IntervalUpperLimits)),
- Fs0 = get_frequencies(L, Acc0),
+ Fs0 = get_frequencies(L, Acc0),
SumVal = lists:sum([V||{_,V}<-Fs0]),
Fs = with_percentage(Fs0, SumVal),
Mean = mean(L),
@@ -517,7 +579,6 @@ print_frequencies(L, N, Min, Max) ->
|| {Interval={Rlow,Rhigh},Val,Percent} <- Fs],
io:format('~*c ~*c~n',[2*Npos_range,32,Npos_value+2,$-]),
io:format('~*c ~*w~n',[2*Npos_range,32,Npos_value,SumVal])
- %%,io:format('L=~p~n',[L])
catch
C:E ->
io:format('*** Faild printing (~p:~p) for~n~p~n',[C,E,L])
@@ -527,6 +588,8 @@ get_frequencies([{I,Num}|T], [{{Lower,Upper},Cnt}|Acc]) when Lower=<I,I=<Upper -
get_frequencies(T, [{{Lower,Upper},Cnt+Num}|Acc]);
get_frequencies(L=[{I,_Num}|_], [Ah={{_Lower,Upper},_Cnt}|Acc]) when I>Upper ->
[Ah | get_frequencies(L,Acc)];
+get_frequencies([I|T], Acc) when is_integer(I) ->
+ get_frequencies([{I,1}|T], Acc);
get_frequencies([], Acc) ->
Acc.
@@ -616,4 +679,3 @@ erase_dir(Dir) ->
file:del_dir(Dir).
-endif.
--endif.
diff --git a/lib/ssh/test/property_test/ssh_eqc_subsys.erl b/lib/ssh/test/property_test/ssh_eqc_subsys.erl
index 30b254b9c0..087b3ebfa7 100644
--- a/lib/ssh/test/property_test/ssh_eqc_subsys.erl
+++ b/lib/ssh/test/property_test/ssh_eqc_subsys.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,7 +21,7 @@
-module(ssh_eqc_subsys).
--behaviour(ssh_daemon_channel).
+-behaviour(ssh_server_channel).
-export([init/1, handle_msg/2, handle_ssh_msg/2, terminate/2]).
diff --git a/lib/ssh/test/ssh_algorithms_SUITE.erl b/lib/ssh/test/ssh_algorithms_SUITE.erl
index de6e448ebd..02e5f40c38 100644
--- a/lib/ssh/test/ssh_algorithms_SUITE.erl
+++ b/lib/ssh/test/ssh_algorithms_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -35,7 +35,7 @@
suite() ->
[{ct_hooks,[ts_install_cth]},
- {timetrap,{seconds,round(1.5*?TIMEOUT/1000)}}].
+ {timetrap,{seconds,60}}].
all() ->
%% [{group,kex},{group,cipher}... etc
@@ -100,7 +100,7 @@ init_per_suite(Config) ->
ct:log("all() ->~n ~p.~n~ngroups()->~n ~p.~n",[all(),groups()]),
ssh:start(),
[{std_simple_sftp_size,25000} % Sftp transferred data size
- | setup_pubkey(Config)]
+ | Config]
end
).
@@ -184,12 +184,15 @@ init_per_testcase(TC, {public_key,Alg}, Config) ->
| ExtraOpts],
[{extra_daemon,true}|Config]);
{{ok,_}, {error,Err}} ->
+ ct:log("Alg = ~p~nOpts = ~p",[Alg,Opts]),
{skip, io_lib:format("No host key: ~p",[Err])};
{{error,Err}, {ok,_}} ->
+ ct:log("Alg = ~p~nOpts = ~p",[Alg,Opts]),
{skip, io_lib:format("No user key: ~p",[Err])};
_ ->
+ ct:log("Alg = ~p~nOpts = ~p",[Alg,Opts]),
{skip, "Neither host nor user key"}
end;
@@ -257,15 +260,14 @@ try_exec_simple_group(Group, Config) ->
of
_ -> ct:fail("Exec though no group available")
catch
- error:{badmatch,{error,"No possible diffie-hellman-group-exchange group found"}} -> ok;
- error:{badmatch,{error,"Connection closed"}} -> ok
+ error:{badmatch,{error,"Key exchange failed"}} -> ok
end.
%%--------------------------------------------------------------------
%% Testing all default groups
simple_exec_groups() ->
- [{timetrap,{seconds,120}}].
+ [{timetrap,{seconds,180}}].
simple_exec_groups(Config) ->
Sizes = interpolate( public_key:dh_gex_group_sizes() ),
@@ -460,17 +462,6 @@ pubkey_opts(Config) ->
{system_dir, SystemDir}].
-setup_pubkey(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- UserDir = proplists:get_value(priv_dir, Config),
- Keys =
- [ssh_test_lib:setup_dsa(DataDir, UserDir),
- ssh_test_lib:setup_rsa(DataDir, UserDir),
- ssh_test_lib:setup_ecdsa("256", DataDir, UserDir)
- ],
- ssh_test_lib:write_auth_keys(Keys, UserDir), % 'authorized_keys' shall contain ALL pub keys
- Config.
-
setup_pubkey(Alg, Config) ->
DataDir = proplists:get_value(data_dir, Config),
UserDir = proplists:get_value(priv_dir, Config),
@@ -482,7 +473,9 @@ setup_pubkey(Alg, Config) ->
'rsa-sha2-512' -> ssh_test_lib:setup_rsa(DataDir, UserDir);
'ecdsa-sha2-nistp256' -> ssh_test_lib:setup_ecdsa("256", DataDir, UserDir);
'ecdsa-sha2-nistp384' -> ssh_test_lib:setup_ecdsa("384", DataDir, UserDir);
- 'ecdsa-sha2-nistp521' -> ssh_test_lib:setup_ecdsa("521", DataDir, UserDir)
+ 'ecdsa-sha2-nistp521' -> ssh_test_lib:setup_ecdsa("521", DataDir, UserDir);
+ 'ssh-ed25519' -> ssh_test_lib:setup_eddsa(ed25519, DataDir, UserDir);
+ 'ssh-ed448' -> ssh_test_lib:setup_eddsa(ed448, DataDir, UserDir)
end,
Config.
diff --git a/lib/ssh/test/ssh_algorithms_SUITE_data/id_ed25519 b/lib/ssh/test/ssh_algorithms_SUITE_data/id_ed25519
new file mode 100644
index 0000000000..401a3e4a9a
--- /dev/null
+++ b/lib/ssh/test/ssh_algorithms_SUITE_data/id_ed25519
@@ -0,0 +1,7 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
+QyNTUxOQAAACDm9P8/gC0IOKmwHLSvkmEtS2Xx0RRqUDqC6wY6UgDVnwAAAJg3+6xpN/us
+aQAAAAtzc2gtZWQyNTUxOQAAACDm9P8/gC0IOKmwHLSvkmEtS2Xx0RRqUDqC6wY6UgDVnw
+AAAEBzC/Z2WGJhZ3l3tIBnUc6DCbp+lXY2yc2RRpWQTdf8sub0/z+ALQg4qbActK+SYS1L
+ZfHRFGpQOoLrBjpSANWfAAAAE3VhYmhuaWxAZWx4YWRsajNxMzIBAg==
+-----END OPENSSH PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_algorithms_SUITE_data/id_ed25519.pub b/lib/ssh/test/ssh_algorithms_SUITE_data/id_ed25519.pub
new file mode 100644
index 0000000000..a5c03b19c1
--- /dev/null
+++ b/lib/ssh/test/ssh_algorithms_SUITE_data/id_ed25519.pub
@@ -0,0 +1 @@
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOb0/z+ALQg4qbActK+SYS1LZfHRFGpQOoLrBjpSANWf uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_algorithms_SUITE_data/id_ed448 b/lib/ssh/test/ssh_algorithms_SUITE_data/id_ed448
new file mode 100644
index 0000000000..8ecfd710dc
--- /dev/null
+++ b/lib/ssh/test/ssh_algorithms_SUITE_data/id_ed448
@@ -0,0 +1,10 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAASgAAAAlz
+c2gtZWQ0NDgAAAA53OqeePNaG/NJmoMbELhskKrAHNhLZ6AQm1WjbpMoseNl/OFh
+1xznExpUPqTLX36fHYsAaWRHABQAAAAA0AAAEREAABERAAAACXNzaC1lZDQ0OAAA
+ADnc6p5481ob80magxsQuGyQqsAc2EtnoBCbVaNukyix42X84WHXHOcTGlQ+pMtf
+fp8diwBpZEcAFAAAAAByzSPST3FCdOdENDI3uTKQ9RH2Ql+Y5kRZ/yA+iYUIP/32
+BQBVOrwOBc0CGEvbicTM1n4YeVEmfrMo3OqeePNaG/NJmoMbELhskKrAHNhLZ6AQ
+m1WjbpMoseNl/OFh1xznExpUPqTLX36fHYsAaWRHABQAAAAAAAECAwQ=
+-----END OPENSSH PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_algorithms_SUITE_data/id_ed448.pub b/lib/ssh/test/ssh_algorithms_SUITE_data/id_ed448.pub
new file mode 100644
index 0000000000..cec0765a5d
--- /dev/null
+++ b/lib/ssh/test/ssh_algorithms_SUITE_data/id_ed448.pub
@@ -0,0 +1 @@
+ssh-ed448 AAAACXNzaC1lZDQ0OAAAADnc6p5481ob80magxsQuGyQqsAc2EtnoBCbVaNukyix42X84WHXHOcTGlQ+pMtffp8diwBpZEcAFAA= uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ed25519_key b/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ed25519_key
new file mode 100644
index 0000000000..13a8fcf491
--- /dev/null
+++ b/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ed25519_key
@@ -0,0 +1,7 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
+QyNTUxOQAAACBJSOuiYGWaO9lye8Bgafod1kw8P6cV3Xb2qJgCB6yJfQAAAJi+h4O7voeD
+uwAAAAtzc2gtZWQyNTUxOQAAACBJSOuiYGWaO9lye8Bgafod1kw8P6cV3Xb2qJgCB6yJfQ
+AAAEBaOcJfGPNemKc1wPHTCmM4Kwvh6dZ0CqY14UT361UnN0lI66JgZZo72XJ7wGBp+h3W
+TDw/pxXddvaomAIHrIl9AAAAE3VhYmhuaWxAZWx4YWRsajNxMzIBAg==
+-----END OPENSSH PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ed25519_key.pub b/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ed25519_key.pub
new file mode 100644
index 0000000000..156ef4045c
--- /dev/null
+++ b/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ed25519_key.pub
@@ -0,0 +1 @@
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIElI66JgZZo72XJ7wGBp+h3WTDw/pxXddvaomAIHrIl9 uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ed448_key b/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ed448_key
new file mode 100644
index 0000000000..31a7e4e8c3
--- /dev/null
+++ b/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ed448_key
@@ -0,0 +1,10 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAASgAAAAlz
+c2gtZWQ0NDgAAAA5X9dEm1m0Yf0s54fsYWrUah2hNCSFpw4fig6nXYDpZ3jt8SR2
+m0bHBhvWeD3x5Q9s0foavq/oJWGAAAAA0AAAEREAABERAAAACXNzaC1lZDQ0OAAA
+ADlf10SbWbRh/Sznh+xhatRqHaE0JIWnDh+KDqddgOlneO3xJHabRscGG9Z4PfHl
+D2zR+hq+r+glYYAAAABybIKlYsuAjRDWMr6JyFE+v2ySnzTd+oyfY8mWDvbjSKNS
+jIo/zC8ETjmj/FuUSS+PAy51SaIAmPlbX9dEm1m0Yf0s54fsYWrUah2hNCSFpw4f
+ig6nXYDpZ3jt8SR2m0bHBhvWeD3x5Q9s0foavq/oJWGAAAAAAAECAwQ=
+-----END OPENSSH PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ed448_key.pub b/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ed448_key.pub
new file mode 100644
index 0000000000..8c390dcb58
--- /dev/null
+++ b/lib/ssh/test/ssh_algorithms_SUITE_data/ssh_host_ed448_key.pub
@@ -0,0 +1 @@
+ssh-ed448 AAAACXNzaC1lZDQ0OAAAADlf10SbWbRh/Sznh+xhatRqHaE0JIWnDh+KDqddgOlneO3xJHabRscGG9Z4PfHlD2zR+hq+r+glYYA=
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index 365f25fabb..9b987dea5a 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -28,60 +28,12 @@
-include("ssh_test_lib.hrl").
%% Note: This directive should only be used in test suites.
-%%-compile(export_all).
-
-%%% Test cases
--export([
- app_test/1,
- appup_test/1,
- cli/1,
- close/1,
- daemon_already_started/1,
- daemon_opt_fd/1,
- multi_daemon_opt_fd/1,
- double_close/1,
- exec/1,
- exec_compressed/1,
- exec_key_differs1/1,
- exec_key_differs2/1,
- exec_key_differs3/1,
- exec_key_differs_fail/1,
- fail_daemon_start/1,
- idle_time_client/1,
- idle_time_server/1,
- inet6_option/1,
- inet_option/1,
- internal_error/1,
- known_hosts/1,
- login_bad_pwd_no_retry1/1,
- login_bad_pwd_no_retry2/1,
- login_bad_pwd_no_retry3/1,
- login_bad_pwd_no_retry4/1,
- login_bad_pwd_no_retry5/1,
- misc_ssh_options/1,
- openssh_zlib_basic_test/1,
- packet_size/1,
- pass_phrase/1,
- peername_sockname/1,
- send/1,
- shell/1,
- shell_no_unicode/1,
- shell_unicode_string/1,
- ssh_info_print/1,
- key_callback/1,
- key_callback_options/1,
- shell_exit_status/1
- ]).
-
-%%% Common test callbacks
--export([suite/0, all/0, groups/0,
- init_per_suite/1, end_per_suite/1,
- init_per_group/2, end_per_group/2,
- init_per_testcase/2, end_per_testcase/2
- ]).
+-compile(export_all).
-define(NEWLINE, <<"\r\n">>).
+-define(REKEY_DATA_TMO, 1 * 60000). % Should be multiples of 60000
+
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
@@ -91,76 +43,111 @@ suite() ->
{timetrap,{seconds,40}}].
all() ->
- [app_test,
- appup_test,
- {group, dsa_key},
- {group, rsa_key},
- {group, ecdsa_sha2_nistp256_key},
- {group, ecdsa_sha2_nistp384_key},
- {group, ecdsa_sha2_nistp521_key},
- {group, dsa_pass_key},
- {group, rsa_pass_key},
- {group, ecdsa_sha2_nistp256_pass_key},
- {group, ecdsa_sha2_nistp384_pass_key},
- {group, ecdsa_sha2_nistp521_pass_key},
- {group, host_user_key_differs},
- {group, key_cb},
- {group, internal_error},
- {group, rsa_host_key_is_actualy_ecdsa},
- daemon_already_started,
- double_close,
- daemon_opt_fd,
- multi_daemon_opt_fd,
- packet_size,
- ssh_info_print,
- {group, login_bad_pwd_no_retry},
- shell_exit_status
+ [{group, all_tests},
+ daemon_already_started
].
groups() ->
- [{dsa_key, [], basic_tests()},
- {rsa_key, [], basic_tests()},
- {ecdsa_sha2_nistp256_key, [], basic_tests()},
- {ecdsa_sha2_nistp384_key, [], basic_tests()},
- {ecdsa_sha2_nistp521_key, [], basic_tests()},
+ [{all_tests, [parallel], [{group, ssh_renegotiate_SUITE},
+ {group, ssh_basic_SUITE}
+ ]},
+ {ssh_basic_SUITE, [], [app_test,
+ appup_test,
+ {group, dsa_key},
+ {group, rsa_key},
+ {group, ecdsa_sha2_nistp256_key},
+ {group, ecdsa_sha2_nistp384_key},
+ {group, ecdsa_sha2_nistp521_key},
+ {group, ed25519_key},
+ {group, ed448_key},
+ {group, dsa_pass_key},
+ {group, rsa_pass_key},
+ {group, ecdsa_sha2_nistp256_pass_key},
+ {group, ecdsa_sha2_nistp384_pass_key},
+ {group, ecdsa_sha2_nistp521_pass_key},
+ {group, host_user_key_differs},
+ {group, key_cb},
+ {group, internal_error},
+ {group, rsa_host_key_is_actualy_ecdsa},
+ daemon_already_started,
+ double_close,
+ daemon_opt_fd,
+ multi_daemon_opt_fd,
+ packet_size,
+ ssh_info_print,
+ {group, login_bad_pwd_no_retry},
+ shell_exit_status
+ ]},
+
+ {ssh_renegotiate_SUITE, [parallel], [rekey0,
+ rekey1,
+ rekey2,
+ rekey3,
+ rekey4,
+ rekey_limit_client,
+ rekey_limit_daemon,
+ rekey_time_limit_client,
+ rekey_time_limit_daemon,
+ norekey_limit_client,
+ norekey_limit_daemon,
+ renegotiate1,
+ renegotiate2]},
+
+ {dsa_key, [], [{group, basic}]},
+ {rsa_key, [], [{group, basic}]},
+ {ecdsa_sha2_nistp256_key, [], [{group, basic}]},
+ {ecdsa_sha2_nistp384_key, [], [{group, basic}]},
+ {ecdsa_sha2_nistp521_key, [], [{group, basic}]},
+ {ed25519_key, [], [{group, basic}]},
+ {ed448_key, [], [{group, basic}]},
{rsa_host_key_is_actualy_ecdsa, [], [fail_daemon_start]},
- {host_user_key_differs, [], [exec_key_differs1,
- exec_key_differs2,
- exec_key_differs3,
- exec_key_differs_fail]},
+ {host_user_key_differs, [parallel], [exec_key_differs1,
+ exec_key_differs2,
+ exec_key_differs3,
+ exec_key_differs_fail]},
{dsa_pass_key, [], [pass_phrase]},
{rsa_pass_key, [], [pass_phrase]},
{ecdsa_sha2_nistp256_pass_key, [], [pass_phrase]},
{ecdsa_sha2_nistp384_pass_key, [], [pass_phrase]},
{ecdsa_sha2_nistp521_pass_key, [], [pass_phrase]},
- {key_cb, [], [key_callback, key_callback_options]},
+ {key_cb, [parallel], [key_callback, key_callback_options]},
{internal_error, [], [internal_error]},
- {login_bad_pwd_no_retry, [], [login_bad_pwd_no_retry1,
- login_bad_pwd_no_retry2,
- login_bad_pwd_no_retry3,
- login_bad_pwd_no_retry4,
- login_bad_pwd_no_retry5
- ]}
+ {login_bad_pwd_no_retry, [parallel], [login_bad_pwd_no_retry1,
+ login_bad_pwd_no_retry2,
+ login_bad_pwd_no_retry3,
+ login_bad_pwd_no_retry4,
+ login_bad_pwd_no_retry5
+ ]},
+
+ {basic, [], [{group,p_basic},
+ shell, shell_no_unicode, shell_unicode_string,
+ close,
+ known_hosts
+ ]},
+ {p_basic, [parallel], [send, peername_sockname,
+ exec, exec_compressed,
+ cli,
+ idle_time_client, idle_time_server, openssh_zlib_basic_test,
+ misc_ssh_options, inet_option, inet6_option]}
].
-basic_tests() ->
- [send, close, peername_sockname,
- exec, exec_compressed,
- shell, shell_no_unicode, shell_unicode_string,
- cli, known_hosts,
- idle_time_client, idle_time_server, openssh_zlib_basic_test,
- misc_ssh_options, inet_option, inet6_option].
+
%%--------------------------------------------------------------------
init_per_suite(Config) ->
- ?CHECK_CRYPTO(Config).
+ ?CHECK_CRYPTO(begin
+ ssh:start(),
+ Config
+ end).
end_per_suite(_Config) ->
ssh:stop().
%%--------------------------------------------------------------------
+init_per_group(ssh_renegotiate_SUITE, Config) ->
+ [{preferred_algorithms, ssh:default_algorithms()} | Config];
init_per_group(dsa_key, Config) ->
case lists:member('ssh-dss',
ssh_transport:default_algorithms(public_key)) of
@@ -241,6 +228,28 @@ init_per_group(ecdsa_sha2_nistp521_key, Config) ->
false ->
{skip, unsupported_pub_key}
end;
+init_per_group(ed25519_key, Config) ->
+ case lists:member('ssh-ed25519',
+ ssh_transport:default_algorithms(public_key)) of
+ true ->
+ DataDir = proplists:get_value(data_dir, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
+ ssh_test_lib:setup_eddsa(ed25519, DataDir, PrivDir),
+ Config;
+ false ->
+ {skip, unsupported_pub_key}
+ end;
+init_per_group(ed448_key, Config) ->
+ case lists:member('ssh-ed448',
+ ssh_transport:default_algorithms(public_key)) of
+ true ->
+ DataDir = proplists:get_value(data_dir, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
+ ssh_test_lib:setup_eddsa(ed448, DataDir, PrivDir),
+ Config;
+ false ->
+ {skip, unsupported_pub_key}
+ end;
init_per_group(rsa_pass_key, Config) ->
case lists:member('ssh-rsa',
ssh_transport:default_algorithms(public_key)) of
@@ -414,7 +423,6 @@ init_per_testcase(TC, Config) when TC==shell_no_unicode ;
PrivDir = proplists:get_value(priv_dir, Config),
UserDir = proplists:get_value(priv_dir, Config),
SysDir = proplists:get_value(data_dir, Config),
- ssh:start(),
Sftpd = {_Pid, _Host, Port} =
ssh_test_lib:daemon([{system_dir, SysDir},
{user_dir, PrivDir},
@@ -437,7 +445,6 @@ init_per_testcase(inet6_option, Config) ->
{skip,"No ipv6 interface address"}
end;
init_per_testcase(_TestCase, Config) ->
- ssh:start(),
Config.
end_per_testcase(TestCase, Config) when TestCase == server_password_option;
@@ -458,7 +465,6 @@ end_per_testcase(_TestCase, Config) ->
end_per_testcase(Config).
end_per_testcase(_Config) ->
- ssh:stop(),
ok.
%%--------------------------------------------------------------------
@@ -480,8 +486,8 @@ misc_ssh_options(Config) when is_list(Config) ->
SystemDir = filename:join(proplists:get_value(priv_dir, Config), system),
UserDir = proplists:get_value(priv_dir, Config),
- CMiscOpt0 = [{connect_timeout, 1000}, {user_dir, UserDir}],
- CMiscOpt1 = [{connect_timeout, infinity}, {user_dir, UserDir}],
+ CMiscOpt0 = [{connect_timeout, 1000}, {user_dir, UserDir}, {silently_accept_hosts, true}],
+ CMiscOpt1 = [{connect_timeout, infinity}, {user_dir, UserDir}, {silently_accept_hosts, true}],
SMiscOpt0 = [{user_dir, UserDir}, {system_dir, SystemDir}],
SMiscOpt1 = [{user_dir, UserDir}, {system_dir, SystemDir}],
@@ -797,6 +803,24 @@ daemon_already_started(Config) when is_list(Config) ->
ssh:stop_daemon(Pid).
%%--------------------------------------------------------------------
+%%% Test that a failed daemon start does not leave the port open
+daemon_error_closes_port(Config) ->
+ GoodSystemDir = proplists:get_value(data_dir, Config),
+ Port = ssh_test_lib:inet_port(),
+ {error,_} = ssh_test_lib:daemon(Port, []), % No system dir
+ case ssh_test_lib:daemon(Port, [{system_dir, GoodSystemDir}]) of
+ {error,eaddrinuse} ->
+ {fail, "Port leakage"};
+ {error,Error} ->
+ ct:log("Strange error: ~p",[Error]),
+ {fail, "Strange error"};
+ {Pid, _Host, Port} ->
+ %% Ok
+ ssh:stop_daemon(Pid)
+ end.
+
+
+%%--------------------------------------------------------------------
%%% check that known_hosts is updated correctly
known_hosts(Config) when is_list(Config) ->
SystemDir = proplists:get_value(data_dir, Config),
@@ -1124,11 +1148,14 @@ packet_size(Config) ->
ct:log("Try max_packet_size=~p",[MaxPacketSize]),
{ok,Ch} = ssh_connection:session_channel(Conn, 1000, MaxPacketSize, 60000),
ok = ssh_connection:shell(Conn, Ch),
- rec(Server, Conn, Ch, MaxPacketSize)
+ rec(Server, Conn, Ch, MaxPacketSize),
+ ssh_connection:close(Conn, Ch)
end, [0, 1, 10, 25]),
ssh:close(Conn),
- ssh:stop_daemon(Server).
+ ssh:stop_daemon(Server),
+ ok.
+
rec(Server, Conn, Ch, MaxSz) ->
receive
@@ -1141,7 +1168,9 @@ rec(Server, Conn, Ch, MaxSz) ->
ssh:stop_daemon(Server),
ct:fail("Does not obey max_packet_size=~p",[MaxSz])
after
- 2000 -> ok
+ 2000 ->
+ ct:log("~p: ok!",[MaxSz]),
+ ok
end.
%%--------------------------------------------------------------------
@@ -1350,6 +1379,318 @@ shell_exit_status(Config) when is_list(Config) ->
ssh:stop_daemon(Pid).
+%%----------------------------------------------------------------------------
+%%% Idle timeout test
+rekey0() -> [{timetrap,{seconds,90}}].
+rekey1() -> [{timetrap,{seconds,90}}].
+rekey2() -> [{timetrap,{seconds,90}}].
+rekey3() -> [{timetrap,{seconds,90}}].
+rekey4() -> [{timetrap,{seconds,90}}].
+
+rekey0(Config) -> rekey_chk(Config, 0, 0).
+rekey1(Config) -> rekey_chk(Config, infinity, 0).
+rekey2(Config) -> rekey_chk(Config, {infinity,infinity}, 0).
+rekey3(Config) -> rekey_chk(Config, 0, infinity).
+rekey4(Config) -> rekey_chk(Config, 0, {infinity,infinity}).
+
+rekey_chk(Config, RLdaemon, RLclient) ->
+ {Pid, Host, Port} = ssh_test_lib:std_daemon(Config, [{rekey_limit, RLdaemon}]),
+ ConnectionRef = ssh_test_lib:std_connect(Config, Host, Port, [{rekey_limit, RLclient}]),
+ Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
+
+ %% Make both sides send something:
+ {ok, _SftpPid} = ssh_sftp:start_channel(ConnectionRef),
+
+ %% Check rekeying
+ timer:sleep(?REKEY_DATA_TMO),
+ ?wait_match(false, Kex1==ssh_test_lib:get_kex_init(ConnectionRef), [], 2000, 10),
+
+ ssh:close(ConnectionRef),
+ ssh:stop_daemon(Pid).
+
+%%--------------------------------------------------------------------
+%%% Test rekeying by data volume
+
+rekey_limit_client() -> [{timetrap,{seconds,400}}].
+rekey_limit_client(Config) ->
+ Limit = 6000,
+ UserDir = proplists:get_value(priv_dir, Config),
+ DataFile = filename:join(UserDir, "rekey.data"),
+ Data = lists:duplicate(Limit+10,1),
+ Algs = proplists:get_value(preferred_algorithms, Config),
+ {Pid, Host, Port} = ssh_test_lib:std_daemon(Config,[{max_random_length_padding,0},
+ {preferred_algorithms,Algs}]),
+
+ ConnectionRef = ssh_test_lib:std_connect(Config, Host, Port, [{rekey_limit, Limit},
+ {max_random_length_padding,0}]),
+ {ok, SftpPid} = ssh_sftp:start_channel(ConnectionRef),
+
+ %% Check that it doesn't rekey without data transfer
+ Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
+ timer:sleep(?REKEY_DATA_TMO),
+ true = (Kex1 == ssh_test_lib:get_kex_init(ConnectionRef)),
+
+ %% Check that datatransfer triggers rekeying
+ ok = ssh_sftp:write_file(SftpPid, DataFile, Data),
+ timer:sleep(?REKEY_DATA_TMO),
+ ?wait_match(false, Kex1==(Kex2=ssh_test_lib:get_kex_init(ConnectionRef)), Kex2, 2000, 10),
+
+ %% Check that datatransfer continues to trigger rekeying
+ ok = ssh_sftp:write_file(SftpPid, DataFile, Data),
+ timer:sleep(?REKEY_DATA_TMO),
+ ?wait_match(false, Kex2==(Kex3=ssh_test_lib:get_kex_init(ConnectionRef)), Kex3, 2000, 10),
+
+ %% Check that it doesn't rekey without data transfer
+ timer:sleep(?REKEY_DATA_TMO),
+ true = (Kex3 == ssh_test_lib:get_kex_init(ConnectionRef)),
+
+ %% Check that it doesn't rekey on a small datatransfer
+ ok = ssh_sftp:write_file(SftpPid, DataFile, "hi\n"),
+ timer:sleep(?REKEY_DATA_TMO),
+ true = (Kex3 == ssh_test_lib:get_kex_init(ConnectionRef)),
+
+ %% Check that it doesn't rekey without data transfer
+ timer:sleep(?REKEY_DATA_TMO),
+ true = (Kex3 == ssh_test_lib:get_kex_init(ConnectionRef)),
+
+ ssh_sftp:stop_channel(SftpPid),
+ ssh:close(ConnectionRef),
+ ssh:stop_daemon(Pid).
+
+
+
+rekey_limit_daemon() -> [{timetrap,{seconds,400}}].
+rekey_limit_daemon(Config) ->
+ Limit = 6000,
+ UserDir = proplists:get_value(priv_dir, Config),
+ DataFile1 = filename:join(UserDir, "rekey1.data"),
+ DataFile2 = filename:join(UserDir, "rekey2.data"),
+ file:write_file(DataFile1, lists:duplicate(Limit+10,1)),
+ file:write_file(DataFile2, "hi\n"),
+
+ Algs = proplists:get_value(preferred_algorithms, Config),
+ {Pid, Host, Port} = ssh_test_lib:std_daemon(Config,[{rekey_limit, Limit},
+ {max_random_length_padding,0},
+ {preferred_algorithms,Algs}]),
+ ConnectionRef = ssh_test_lib:std_connect(Config, Host, Port, [{max_random_length_padding,0}]),
+ {ok, SftpPid} = ssh_sftp:start_channel(ConnectionRef),
+
+ %% Check that it doesn't rekey without data transfer
+ Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
+ timer:sleep(?REKEY_DATA_TMO),
+ Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
+
+ %% Check that datatransfer triggers rekeying
+ {ok,_} = ssh_sftp:read_file(SftpPid, DataFile1),
+ timer:sleep(?REKEY_DATA_TMO),
+ ?wait_match(false, Kex1==(Kex2=ssh_test_lib:get_kex_init(ConnectionRef)), Kex2, 2000, 10),
+
+ %% Check that datatransfer continues to trigger rekeying
+ {ok,_} = ssh_sftp:read_file(SftpPid, DataFile1),
+ timer:sleep(?REKEY_DATA_TMO),
+ ?wait_match(false, Kex2==(Kex3=ssh_test_lib:get_kex_init(ConnectionRef)), Kex3, 2000, 10),
+
+ %% Check that it doesn't rekey without data transfer
+ timer:sleep(?REKEY_DATA_TMO),
+ true = (Kex3 == ssh_test_lib:get_kex_init(ConnectionRef)),
+
+ %% Check that it doesn't rekey on a small datatransfer
+ {ok,_} = ssh_sftp:read_file(SftpPid, DataFile2),
+ timer:sleep(?REKEY_DATA_TMO),
+ true = (Kex3 == ssh_test_lib:get_kex_init(ConnectionRef)),
+
+ %% Check that it doesn't rekey without data transfer
+ timer:sleep(?REKEY_DATA_TMO),
+ true = (Kex3 == ssh_test_lib:get_kex_init(ConnectionRef)),
+
+ ssh_sftp:stop_channel(SftpPid),
+ ssh:close(ConnectionRef),
+ ssh:stop_daemon(Pid).
+
+
+%%--------------------------------------------------------------------
+%% Check that datatransfer in the other direction does not trigger re-keying
+norekey_limit_client() -> [{timetrap,{seconds,400}}].
+norekey_limit_client(Config) ->
+ Limit = 6000,
+ UserDir = proplists:get_value(priv_dir, Config),
+ DataFile = filename:join(UserDir, "rekey3.data"),
+ file:write_file(DataFile, lists:duplicate(Limit+10,1)),
+
+ Algs = proplists:get_value(preferred_algorithms, Config),
+ {Pid, Host, Port} = ssh_test_lib:std_daemon(Config,[{max_random_length_padding,0},
+ {preferred_algorithms,Algs}]),
+
+ ConnectionRef = ssh_test_lib:std_connect(Config, Host, Port, [{rekey_limit, Limit},
+ {max_random_length_padding,0}]),
+ {ok, SftpPid} = ssh_sftp:start_channel(ConnectionRef),
+
+ Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
+ timer:sleep(?REKEY_DATA_TMO),
+ true = (Kex1 == ssh_test_lib:get_kex_init(ConnectionRef)),
+
+ {ok,_} = ssh_sftp:read_file(SftpPid, DataFile),
+ timer:sleep(?REKEY_DATA_TMO),
+ true = (Kex1 == ssh_test_lib:get_kex_init(ConnectionRef)),
+
+ ssh_sftp:stop_channel(SftpPid),
+ ssh:close(ConnectionRef),
+ ssh:stop_daemon(Pid).
+
+%% Check that datatransfer in the other direction does not trigger re-keying
+norekey_limit_daemon() -> [{timetrap,{seconds,400}}].
+norekey_limit_daemon(Config) ->
+ Limit = 6000,
+ UserDir = proplists:get_value(priv_dir, Config),
+ DataFile = filename:join(UserDir, "rekey4.data"),
+
+ Algs = proplists:get_value(preferred_algorithms, Config),
+ {Pid, Host, Port} = ssh_test_lib:std_daemon(Config,[{rekey_limit, Limit},
+ {max_random_length_padding,0},
+ {preferred_algorithms,Algs}]),
+
+ ConnectionRef = ssh_test_lib:std_connect(Config, Host, Port, [{max_random_length_padding,0}]),
+ {ok, SftpPid} = ssh_sftp:start_channel(ConnectionRef),
+
+ Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
+ timer:sleep(?REKEY_DATA_TMO),
+ true = (Kex1 == ssh_test_lib:get_kex_init(ConnectionRef)),
+
+ ok = ssh_sftp:write_file(SftpPid, DataFile, lists:duplicate(Limit+10,1)),
+ timer:sleep(?REKEY_DATA_TMO),
+ true = (Kex1 == ssh_test_lib:get_kex_init(ConnectionRef)),
+
+ ssh_sftp:stop_channel(SftpPid),
+ ssh:close(ConnectionRef),
+ ssh:stop_daemon(Pid).
+
+%%--------------------------------------------------------------------
+%%% Test rekeying by time
+
+rekey_time_limit_client() -> [{timetrap,{seconds,400}}].
+rekey_time_limit_client(Config) ->
+ Minutes = ?REKEY_DATA_TMO div 60000,
+ GB = 1024*1000*1000,
+ Algs = proplists:get_value(preferred_algorithms, Config),
+ {Pid, Host, Port} = ssh_test_lib:std_daemon(Config,[{max_random_length_padding,0},
+ {preferred_algorithms,Algs}]),
+ ConnectionRef = ssh_test_lib:std_connect(Config, Host, Port, [{rekey_limit, {Minutes, GB}},
+ {max_random_length_padding,0}]),
+ rekey_time_limit(Pid, ConnectionRef).
+
+rekey_time_limit_daemon() -> [{timetrap,{seconds,400}}].
+rekey_time_limit_daemon(Config) ->
+ Minutes = ?REKEY_DATA_TMO div 60000,
+ GB = 1024*1000*1000,
+ Algs = proplists:get_value(preferred_algorithms, Config),
+ {Pid, Host, Port} = ssh_test_lib:std_daemon(Config,[{rekey_limit, {Minutes, GB}},
+ {max_random_length_padding,0},
+ {preferred_algorithms,Algs}]),
+ ConnectionRef = ssh_test_lib:std_connect(Config, Host, Port, [{max_random_length_padding,0}]),
+ rekey_time_limit(Pid, ConnectionRef).
+
+
+rekey_time_limit(Pid, ConnectionRef) ->
+ {ok, SftpPid} = ssh_sftp:start_channel(ConnectionRef),
+ Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
+
+ timer:sleep(5000),
+ true = (Kex1 == ssh_test_lib:get_kex_init(ConnectionRef)),
+
+ %% Check that it rekeys when the max time + 30s has passed
+ timer:sleep(?REKEY_DATA_TMO + 30*1000),
+ ?wait_match(false, Kex1==(Kex2=ssh_test_lib:get_kex_init(ConnectionRef)), Kex2, 2000, 10),
+
+ %% Check that it does not rekey when nothing is transferred
+ timer:sleep(?REKEY_DATA_TMO + 30*1000),
+ ?wait_match(false, Kex2==ssh_test_lib:get_kex_init(ConnectionRef), [], 2000, 10),
+
+ ssh_sftp:stop_channel(SftpPid),
+ ssh:close(ConnectionRef),
+ ssh:stop_daemon(Pid).
+
+%%--------------------------------------------------------------------
+
+%%% Test rekeying with simultaneous send request
+
+renegotiate1(Config) ->
+ UserDir = proplists:get_value(priv_dir, Config),
+ DataFile = filename:join(UserDir, "renegotiate1.data"),
+
+ Algs = proplists:get_value(preferred_algorithms, Config),
+ {Pid, Host, DPort} = ssh_test_lib:std_daemon(Config,[{max_random_length_padding,0},
+ {preferred_algorithms,Algs}]),
+
+ RPort = ssh_test_lib:inet_port(),
+ {ok,RelayPid} = ssh_relay:start_link({0,0,0,0}, RPort, Host, DPort),
+
+
+ ConnectionRef = ssh_test_lib:std_connect(Config, Host, RPort, [{max_random_length_padding,0}]),
+ {ok, SftpPid} = ssh_sftp:start_channel(ConnectionRef),
+
+ Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
+
+ {ok, Handle} = ssh_sftp:open(SftpPid, DataFile, [write]),
+
+ ok = ssh_sftp:write(SftpPid, Handle, "hi\n"),
+
+ ssh_relay:hold(RelayPid, rx, 20, 1000),
+ ssh_connection_handler:renegotiate(ConnectionRef),
+ spawn(fun() -> ok=ssh_sftp:write(SftpPid, Handle, "another hi\n") end),
+
+ timer:sleep(2000),
+
+ Kex2 = ssh_test_lib:get_kex_init(ConnectionRef),
+
+ false = (Kex2 == Kex1),
+
+ ssh_relay:stop(RelayPid),
+ ssh_sftp:stop_channel(SftpPid),
+ ssh:close(ConnectionRef),
+ ssh:stop_daemon(Pid).
+
+%%--------------------------------------------------------------------
+
+%%% Test rekeying with inflight messages from peer
+
+renegotiate2(Config) ->
+ UserDir = proplists:get_value(priv_dir, Config),
+ DataFile = filename:join(UserDir, "renegotiate2.data"),
+
+ Algs = proplists:get_value(preferred_algorithms, Config),
+ {Pid, Host, DPort} = ssh_test_lib:std_daemon(Config,[{max_random_length_padding,0},
+ {preferred_algorithms,Algs}]),
+
+ RPort = ssh_test_lib:inet_port(),
+ {ok,RelayPid} = ssh_relay:start_link({0,0,0,0}, RPort, Host, DPort),
+
+ ConnectionRef = ssh_test_lib:std_connect(Config, Host, RPort, [{max_random_length_padding,0}]),
+ {ok, SftpPid} = ssh_sftp:start_channel(ConnectionRef),
+
+ Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
+
+ {ok, Handle} = ssh_sftp:open(SftpPid, DataFile, [write]),
+
+ ok = ssh_sftp:write(SftpPid, Handle, "hi\n"),
+
+ ssh_relay:hold(RelayPid, rx, 20, infinity),
+ spawn(fun() -> ok=ssh_sftp:write(SftpPid, Handle, "another hi\n") end),
+ %% need a small pause here to ensure ssh_sftp:write is executed
+ ct:sleep(10),
+ ssh_connection_handler:renegotiate(ConnectionRef),
+ ssh_relay:release(RelayPid, rx),
+
+ timer:sleep(2000),
+
+ Kex2 = ssh_test_lib:get_kex_init(ConnectionRef),
+
+ false = (Kex2 == Kex1),
+
+ ssh_relay:stop(RelayPid),
+ ssh_sftp:stop_channel(SftpPid),
+ ssh:close(ConnectionRef),
+ ssh:stop_daemon(Pid).
+
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
diff --git a/lib/ssh/test/ssh_basic_SUITE_data/id_ed25519 b/lib/ssh/test/ssh_basic_SUITE_data/id_ed25519
new file mode 100644
index 0000000000..401a3e4a9a
--- /dev/null
+++ b/lib/ssh/test/ssh_basic_SUITE_data/id_ed25519
@@ -0,0 +1,7 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
+QyNTUxOQAAACDm9P8/gC0IOKmwHLSvkmEtS2Xx0RRqUDqC6wY6UgDVnwAAAJg3+6xpN/us
+aQAAAAtzc2gtZWQyNTUxOQAAACDm9P8/gC0IOKmwHLSvkmEtS2Xx0RRqUDqC6wY6UgDVnw
+AAAEBzC/Z2WGJhZ3l3tIBnUc6DCbp+lXY2yc2RRpWQTdf8sub0/z+ALQg4qbActK+SYS1L
+ZfHRFGpQOoLrBjpSANWfAAAAE3VhYmhuaWxAZWx4YWRsajNxMzIBAg==
+-----END OPENSSH PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_basic_SUITE_data/id_ed25519.pub b/lib/ssh/test/ssh_basic_SUITE_data/id_ed25519.pub
new file mode 100644
index 0000000000..a5c03b19c1
--- /dev/null
+++ b/lib/ssh/test/ssh_basic_SUITE_data/id_ed25519.pub
@@ -0,0 +1 @@
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOb0/z+ALQg4qbActK+SYS1LZfHRFGpQOoLrBjpSANWf uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_basic_SUITE_data/id_ed448 b/lib/ssh/test/ssh_basic_SUITE_data/id_ed448
new file mode 100644
index 0000000000..8ecfd710dc
--- /dev/null
+++ b/lib/ssh/test/ssh_basic_SUITE_data/id_ed448
@@ -0,0 +1,10 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAASgAAAAlz
+c2gtZWQ0NDgAAAA53OqeePNaG/NJmoMbELhskKrAHNhLZ6AQm1WjbpMoseNl/OFh
+1xznExpUPqTLX36fHYsAaWRHABQAAAAA0AAAEREAABERAAAACXNzaC1lZDQ0OAAA
+ADnc6p5481ob80magxsQuGyQqsAc2EtnoBCbVaNukyix42X84WHXHOcTGlQ+pMtf
+fp8diwBpZEcAFAAAAAByzSPST3FCdOdENDI3uTKQ9RH2Ql+Y5kRZ/yA+iYUIP/32
+BQBVOrwOBc0CGEvbicTM1n4YeVEmfrMo3OqeePNaG/NJmoMbELhskKrAHNhLZ6AQ
+m1WjbpMoseNl/OFh1xznExpUPqTLX36fHYsAaWRHABQAAAAAAAECAwQ=
+-----END OPENSSH PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_basic_SUITE_data/id_ed448.pub b/lib/ssh/test/ssh_basic_SUITE_data/id_ed448.pub
new file mode 100644
index 0000000000..cec0765a5d
--- /dev/null
+++ b/lib/ssh/test/ssh_basic_SUITE_data/id_ed448.pub
@@ -0,0 +1 @@
+ssh-ed448 AAAACXNzaC1lZDQ0OAAAADnc6p5481ob80magxsQuGyQqsAc2EtnoBCbVaNukyix42X84WHXHOcTGlQ+pMtffp8diwBpZEcAFAA= uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ed25519_key b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ed25519_key
new file mode 100644
index 0000000000..13a8fcf491
--- /dev/null
+++ b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ed25519_key
@@ -0,0 +1,7 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
+QyNTUxOQAAACBJSOuiYGWaO9lye8Bgafod1kw8P6cV3Xb2qJgCB6yJfQAAAJi+h4O7voeD
+uwAAAAtzc2gtZWQyNTUxOQAAACBJSOuiYGWaO9lye8Bgafod1kw8P6cV3Xb2qJgCB6yJfQ
+AAAEBaOcJfGPNemKc1wPHTCmM4Kwvh6dZ0CqY14UT361UnN0lI66JgZZo72XJ7wGBp+h3W
+TDw/pxXddvaomAIHrIl9AAAAE3VhYmhuaWxAZWx4YWRsajNxMzIBAg==
+-----END OPENSSH PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ed25519_key.pub b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ed25519_key.pub
new file mode 100644
index 0000000000..156ef4045c
--- /dev/null
+++ b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ed25519_key.pub
@@ -0,0 +1 @@
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIElI66JgZZo72XJ7wGBp+h3WTDw/pxXddvaomAIHrIl9 uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ed448_key b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ed448_key
new file mode 100644
index 0000000000..31a7e4e8c3
--- /dev/null
+++ b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ed448_key
@@ -0,0 +1,10 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAASgAAAAlz
+c2gtZWQ0NDgAAAA5X9dEm1m0Yf0s54fsYWrUah2hNCSFpw4fig6nXYDpZ3jt8SR2
+m0bHBhvWeD3x5Q9s0foavq/oJWGAAAAA0AAAEREAABERAAAACXNzaC1lZDQ0OAAA
+ADlf10SbWbRh/Sznh+xhatRqHaE0JIWnDh+KDqddgOlneO3xJHabRscGG9Z4PfHl
+D2zR+hq+r+glYYAAAABybIKlYsuAjRDWMr6JyFE+v2ySnzTd+oyfY8mWDvbjSKNS
+jIo/zC8ETjmj/FuUSS+PAy51SaIAmPlbX9dEm1m0Yf0s54fsYWrUah2hNCSFpw4f
+ig6nXYDpZ3jt8SR2m0bHBhvWeD3x5Q9s0foavq/oJWGAAAAAAAECAwQ=
+-----END OPENSSH PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ed448_key.pub b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ed448_key.pub
new file mode 100644
index 0000000000..8c390dcb58
--- /dev/null
+++ b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_ed448_key.pub
@@ -0,0 +1 @@
+ssh-ed448 AAAACXNzaC1lZDQ0OAAAADlf10SbWbRh/Sznh+xhatRqHaE0JIWnDh+KDqddgOlneO3xJHabRscGG9Z4PfHlD2zR+hq+r+glYYA=
diff --git a/lib/ssh/test/ssh_bench_SUITE.erl b/lib/ssh/test/ssh_bench_SUITE.erl
index b6c6147646..880c519a5e 100644
--- a/lib/ssh/test/ssh_bench_SUITE.erl
+++ b/lib/ssh/test/ssh_bench_SUITE.erl
@@ -1,7 +1,7 @@
%%%-------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -65,10 +65,10 @@ init_per_suite(Config) ->
{preferred_algorithms, Algs},
{modify_algorithms,[{prepend,[{cipher,[none]},
{mac,[none]}
- ]},
- {rm, [{cipher,['[email protected]',
- ]}
+ ]}
+ %% ,{rm, [{cipher,['[email protected]',
+ %% ]}
]},
{max_random_length_padding, 0},
{subsystems, [{"/dev/null", {ssh_bench_dev_null,[DataSize]}}]}
@@ -109,11 +109,10 @@ connect(Config) ->
lists:foreach(
fun(KexAlg) ->
PrefAlgs = preferred_algorithms(KexAlg),
- report([{value, measure_connect(Config,
- [{preferred_algorithms,PrefAlgs}])},
- {suite, ?MODULE},
- {name, mk_name(["Connect erlc erld ",KexAlg," [µs]"])}
- ])
+ TimeMicroSec = measure_connect(Config,
+ [{preferred_algorithms,PrefAlgs}]),
+ report(["Connect erlc erld ",KexAlg," [connects per sec]"],
+ 1000000 / TimeMicroSec)
end, KexAlgs).
@@ -130,7 +129,7 @@ measure_connect(Config, Opts) ->
[begin
{Time, {ok,Pid}} = timer:tc(ssh,connect,["localhost", Port, ConnectOptions]),
ssh:close(Pid),
- Time
+ Time % in µs
end || _ <- lists:seq(1,?Nruns)]).
%%%----------------------------------------------------------------
@@ -152,7 +151,8 @@ transfer_text(Config) ->
|| {Crypto,Mac} <- [{ none, none},
{'aes128-ctr', 'hmac-sha1'},
{'aes256-ctr', 'hmac-sha1'},
-%% {'[email protected]', 'hmac-sha1'},
+{'[email protected]', 'hmac-sha1'},
+{'[email protected]', 'hmac-sha1'},
{'aes128-cbc', 'hmac-sha1'},
{'3des-cbc', 'hmac-sha1'},
{'aes128-ctr', 'hmac-sha2-256'},
@@ -177,34 +177,32 @@ gen_data(DataSz) ->
<<Data0/binary, Data1/binary>>.
-%% connect_measure(Port, Cipher, Mac, Data, Options) ->
-%% report([{value, 1},
-%% {suite, ?MODULE},
-%% {name, mk_name(["Transfer 1M bytes ",Cipher,"/",Mac," [µs]"])}]);
connect_measure(Port, Cipher, Mac, Data, Options) ->
- AES_GCM = {cipher,['[email protected]',
+ _AES_GCM = {cipher,
+ []},
AlgOpt = case {Cipher,Mac} of
{none,none} ->
[{modify_algorithms,[{prepend, [{cipher,[Cipher]},
- {mac,[Mac]}]},
- {rm,[AES_GCM]}
+ {mac,[Mac]}]}
+%%% ,{rm,[_AES_GCM]}
]}];
{none,_} ->
- [{modify_algorithms,[{prepend, [{cipher,[Cipher]}]},
- {rm,[AES_GCM]}
+ [{modify_algorithms,[{prepend, [{cipher,[Cipher]}]}
+%%% ,{rm,[_AES_GCM]}
]},
{preferred_algorithms, [{mac,[Mac]}]}];
{_,none} ->
- [{modify_algorithms,[{prepend, [{mac,[Mac]}]},
- {rm,[AES_GCM]}
+ [{modify_algorithms,[{prepend, [{mac,[Mac]}]}
+%%% ,{rm,[_AES_GCM]}
]},
{preferred_algorithms, [{cipher,[Cipher]}]}];
_ ->
[{preferred_algorithms, [{cipher,[Cipher]},
- {mac,[Mac]}]},
- {modify_algorithms, [{rm,[AES_GCM]}]}
+ {mac,[Mac]}]}
+%%% ,{modify_algorithms, [{rm,[_AES_GCM]}]}
]
end,
Times =
@@ -217,10 +215,8 @@ connect_measure(Port, Cipher, Mac, Data, Options) ->
ssh:close(C),
Time
end || _ <- lists:seq(1,?Nruns)],
-
- report([{value, median(Times)},
- {suite, ?MODULE},
- {name, mk_name(["Transfer 1M bytes ",Cipher,"/",Mac," [µs]"])}]).
+ report(["Transfer ",Cipher,"/",Mac," [Mbyte per sec]"],
+ 1000000 / median(Times)).
send_wait_acc(C, Ch, Data) ->
ssh_connection:send(C, Ch, Data),
@@ -235,12 +231,6 @@ send_wait_acc(C, Ch, Data) ->
%%%
%%%----------------------------------------------------------------
-mk_name(Name) -> [char(C) || C <- lists:concat(Name)].
-
-char($-) -> $_;
-char(C) -> C.
-
-%%%----------------------------------------------------------------
preferred_algorithms(KexAlg) ->
[{kex, [KexAlg]},
{public_key, ['ssh-rsa']},
@@ -262,11 +252,22 @@ median(Data) when is_list(Data) ->
1 ->
lists:nth(N div 2 + 1, SortedData)
end,
- ct:log("median(~p) = ~p",[SortedData,Median]),
+ ct:pal("median(~p) = ~p",[SortedData,Median]),
Median.
+%%%----------------------------------------------------------------
+report(LabelList, Value) ->
+ Label = report_chars(lists:concat(LabelList)),
+ ct:pal("ct_event:notify ~p: ~p", [Label, Value]),
+ ct_event:notify(
+ #event{name = benchmark_data,
+ data = [{suite, ?MODULE},
+ {name, Label},
+ {value, Value}]}).
+
+report_chars(Cs) ->
+ [case C of
+ $- -> $_;
+ _ -> C
+ end || C <- Cs].
-report(Data) ->
- ct:log("EventData = ~p",[Data]),
- ct_event:notify(#event{name = benchmark_data,
- data = Data}).
diff --git a/lib/ssh/test/ssh_bench_dev_null.erl b/lib/ssh/test/ssh_bench_dev_null.erl
index 5166247714..868eea5643 100644
--- a/lib/ssh/test/ssh_bench_dev_null.erl
+++ b/lib/ssh/test/ssh_bench_dev_null.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@
%%% Description: Example ssh server
-module(ssh_bench_dev_null).
--behaviour(ssh_daemon_channel).
+-behaviour(ssh_server_channel).
-record(state, {
cm,
diff --git a/lib/ssh/test/ssh_chan_behaviours_SUITE.erl b/lib/ssh/test/ssh_chan_behaviours_SUITE.erl
new file mode 100644
index 0000000000..103d7253fd
--- /dev/null
+++ b/lib/ssh/test/ssh_chan_behaviours_SUITE.erl
@@ -0,0 +1,152 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+-module(ssh_chan_behaviours_SUITE).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("ssh/src/ssh.hrl").
+-include("ssh_test_lib.hrl").
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap,{seconds,60}}].
+
+all() ->
+ [
+ noexist_subsystem,
+ undefined_subsystem,
+ defined_subsystem,
+ subsystem_client
+ ].
+
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ ?CHECK_CRYPTO(
+ begin
+ ssh:start(),
+ Config
+ end).
+
+end_per_suite(_Config) ->
+ {Time,R} = timer:tc(ssh, stop, []),
+ ct:log("Stop ssh: ~p ms",[(100*(Time div 1000)) / 100]),
+ R.
+
+init_per_testcase(_TC, Config) ->
+ SubSystems = [
+ {"bad_cb", {ssh_chan_behaviours_undefined, []}}, % A non-existing file
+ {"ch1", {ssh_chan_behaviours_server, [self(),true]}}
+ ],
+ {Pid, Host, Port} = ssh_test_lib:std_daemon(Config, [{subsystems,SubSystems}]),
+ C = ssh_test_lib:std_connect(Config, Host, Port, []),
+ [{connref,C}, {daemon_pid,Pid}| Config].
+
+end_per_testcase(_TC, Config) ->
+ {Time,_} = timer:tc(ssh, stop_daemon, [proplists:get_value(daemon_pid,Config)]),
+ ct:log("Stop daemon: ~p ms",[(100*(Time div 1000)) / 100]),
+ case flush() of
+ [] -> ok;
+ Msgs -> ct:pal("Unhandled messages:~n~p", [Msgs])
+ end.
+
+
+-define(EXPECT(What, Bind),
+ Bind =
+ (fun() ->
+ receive What ->
+ ct:log("~p:~p ~p got ~p",[?MODULE,?LINE,self(),What]),
+ Bind
+ after 5000 ->
+ ct:log("~p:~p ~p Flushed:~n~p",[?MODULE,?LINE,self(),flush()]),
+ ct:fail("Timeout!",[])
+ end
+ end)()
+ ).
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+%% Try start a subsystem whos name is not known by the server
+noexist_subsystem(Config) ->
+ C = proplists:get_value(connref, Config),
+ {ok, Ch} = ssh_connection:session_channel(C, infinity),
+ failure = ssh_connection:subsystem(C, Ch, "noexist", infinity),
+ ok = ssh_connection:close(C, Ch),
+ ?EXPECT({ssh_cm,C,{closed,Ch}},[]),
+ ok.
+
+%% Try to start a subsystem with a known name, but without any callback file
+undefined_subsystem(Config) ->
+ C = proplists:get_value(connref, Config),
+ {ok, Ch} = ssh_connection:session_channel(C, infinity),
+ failure = ssh_connection:subsystem(C, Ch, "bad_cb", infinity),
+ ok = ssh_connection:close(C, Ch),
+ ?EXPECT({ssh_cm,C,{closed,Ch}},[]), % self() is instead of a proper channel handler
+ ok.
+
+%% Try to start and stop a subsystem with known name and defined callback file
+defined_subsystem(Config) ->
+ C = proplists:get_value(connref, Config),
+ {ok, Ch1} = ssh_connection:session_channel(C, infinity),
+
+ success = ssh_connection:subsystem(C, Ch1, "ch1", infinity),
+ IDsrv = ?EXPECT({{_Csrv,_Ch1srv}, {ssh_channel_up,_Ch1srv,_Csrv}}, {_Csrv,_Ch1srv}),
+
+ ok = ssh_connection:close(C, Ch1),
+ ?EXPECT({IDsrv, {terminate,normal}}, []),
+ ?EXPECT({ssh_cm, C, {closed,Ch1}}, []), % self() is instead of a proper channel handler
+ ok.
+
+%% Try to start and stop a subsystem from a ssh_client_channel behviour
+subsystem_client(Config) ->
+ C = proplists:get_value(connref, Config),
+
+ {ok,ChRef} = ssh_chan_behaviours_client:start_link(C),
+ IDclt = ?EXPECT({{C,_Ch1clt}, {ssh_channel_up,_Ch1clt,C}}, {C,_Ch1clt}),
+ IDsrv = ?EXPECT({{_Csrv,_Ch1srv}, {ssh_channel_up,_Ch1srv,_Csrv}}, {_Csrv,_Ch1srv}),
+
+ ok = ssh_chan_behaviours_client:stop(ChRef),
+ ?EXPECT({IDclt, {terminate,normal}}, []), % From the proper channel handler
+ ?EXPECT({IDsrv, {terminate,normal}}, []),
+ ok.
+
+%%%================================================================
+%%%
+%%%
+
+flush() -> lists:reverse(flush([])).
+
+flush(Acc) ->
+ receive
+ M ->
+ flush([M|Acc])
+ after 0 ->
+ Acc
+ end.
+
diff --git a/lib/ssh/test/ssh_renegotiate_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_dsa_key
index 51ab6fbd88..51ab6fbd88 100644
--- a/lib/ssh/test/ssh_renegotiate_SUITE_data/ssh_host_dsa_key
+++ b/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_dsa_key
diff --git a/lib/ssh/test/ssh_renegotiate_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_dsa_key.pub
index 4dbb1305b0..4dbb1305b0 100644
--- a/lib/ssh/test/ssh_renegotiate_SUITE_data/ssh_host_dsa_key.pub
+++ b/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_dsa_key.pub
diff --git a/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_ecdsa_key b/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_ecdsa_key
new file mode 100644
index 0000000000..fb1a862ded
--- /dev/null
+++ b/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_ecdsa_key
@@ -0,0 +1,6 @@
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDArxbDfh3p1okrD9wQw6jJ4d4DdlBPD5GqXE8bIeRJiK41Sh40LgvPw
+mkqEDSXK++CgBwYFK4EEACKhZANiAAScl43Ih2lWTDKrSox5ve5uiTXil4smsup3
+CfS1XPjKxgBAmlfBim8izbdrT0BFdQzz2joduNMtpt61wO4rGs6jm0UP7Kim9PC7
+Hneb/99fIYopdMH5NMnk60zGO1uZ2vc=
+-----END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_ecdsa_key.pub b/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_ecdsa_key.pub
new file mode 100644
index 0000000000..428d5fb7d7
--- /dev/null
+++ b/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_ecdsa_key.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBJyXjciHaVZMMqtKjHm97m6JNeKXiyay6ncJ9LVc+MrGAECaV8GKbyLNt2tPQEV1DPPaOh240y2m3rXA7isazqObRQ/sqKb08Lsed5v/318hiil0wfk0yeTrTMY7W5na9w== uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_renegotiate_SUITE_data/ssh_host_rsa_key b/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_rsa_key
index 79968bdd7d..79968bdd7d 100644
--- a/lib/ssh/test/ssh_renegotiate_SUITE_data/ssh_host_rsa_key
+++ b/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_rsa_key
diff --git a/lib/ssh/test/ssh_renegotiate_SUITE_data/ssh_host_rsa_key.pub b/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_rsa_key.pub
index 75d2025c71..75d2025c71 100644
--- a/lib/ssh/test/ssh_renegotiate_SUITE_data/ssh_host_rsa_key.pub
+++ b/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_rsa_key.pub
diff --git a/lib/ssh/test/ssh_chan_behaviours_client.erl b/lib/ssh/test/ssh_chan_behaviours_client.erl
new file mode 100644
index 0000000000..8dd18973ad
--- /dev/null
+++ b/lib/ssh/test/ssh_chan_behaviours_client.erl
@@ -0,0 +1,143 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+%%% Description: Example ssh client
+-module(ssh_chan_behaviours_client).
+-behaviour(ssh_client_channel).
+-record(state, {
+ parent,
+ cm,
+ ch,
+ dbg
+ }).
+-export([start_link/1, start/1,
+ stop/1, send_eof/1,
+ init/1, handle_msg/2, handle_ssh_msg/2, terminate/2,
+ code_change/3, handle_call/3, handle_cast/2
+ ]).
+
+-define(DBG(State,Fmt,Args),
+ case State#state.dbg of
+ true -> ct:log("~p:~p ~p C=~p Ch=~p "++Fmt,
+ [?MODULE,?LINE,self(),State#state.cm,State#state.ch|Args]);
+ false -> ok
+ end).
+
+
+start_link(C) ->
+ {ok, Ch} = ssh_connection:session_channel(C, infinity),
+ ssh_client_channel:start_link(C, Ch, ssh_chan_behaviours_client, [C, Ch, self(), true]).
+
+start(C) ->
+ {ok, Ch} = ssh_connection:session_channel(C, infinity),
+ ssh_client_channel:start(C, Ch, ssh_chan_behaviours_client, [C, Ch, self(), true]).
+
+send_eof(ChRef) ->
+ ssh_client_channel:call(ChRef, send_eof).
+
+stop(ChRef) ->
+ ssh_client_channel:call(ChRef, stop).
+
+
+init([C, Ch, Parent, Dbg|_Exec]) ->
+ case ssh_connection:subsystem(C, Ch, "ch1", infinity) of
+ success ->
+ State = #state{cm = C,
+ ch = Ch,
+ parent=Parent,
+ dbg=Dbg},
+ ?DBG(State, "callback spawned, parent = ~p", [Parent]),
+ {ok, State};
+
+ Other ->
+ {stop, Other}
+ end.
+
+handle_msg({ssh_channel_up, ChannelId, ConnectionManager}=M, State0) ->
+ State = State0#state{cm = ConnectionManager,
+ ch = ChannelId},
+ tell_parent(M, State),
+ ?DBG(State, "ssh_channel_up",[]),
+ {ok, State}.
+
+handle_ssh_msg({ssh_cm, C, {data, Ch, 0, Data}}=M, #state{ch=Ch,cm=C} = State) ->
+ tell_parent(M, State),
+ ?DBG(State, "ssh_cm data size(Data)=~p",[size(Data)]),
+ {ok, State};
+
+handle_ssh_msg({ssh_cm, C, {data, Ch, Type, Data}}=M, #state{ch=Ch,cm=C} = State) ->
+ tell_parent(M, State),
+ ?DBG(State, "ssh_cm data Type=~p : ~p",[Type,Data]),
+ {ok, State};
+
+handle_ssh_msg({ssh_cm, C, {eof, Ch}}=M, #state{ch=Ch,cm=C} = State) ->
+ tell_parent(M, State),
+ ?DBG(State, "eof",[]),
+ {ok, State};
+
+handle_ssh_msg({ssh_cm, C, {signal, Ch, _SigNameStr}=Sig} = M, #state{ch=Ch,cm=C} = State) ->
+ %% Ignore signals according to RFC 4254 section 6.9.
+ tell_parent(M, State),
+ ?DBG(State, "~p",[Sig]),
+ {ok, State};
+
+handle_ssh_msg({ssh_cm, C, {exit_signal, Ch, _, _Error, _}=Sig}=M, #state{ch=Ch,cm=C} = State) ->
+ tell_parent(M, State),
+ ?DBG(State, "~p",[Sig]),
+ {stop, Ch, State};
+
+handle_ssh_msg({ssh_cm, C, {exit_status, Ch, _Status}=Sig}=M, #state{ch=Ch,cm=C} = State) ->
+ tell_parent(M, State),
+ ?DBG(State, "~p",[Sig]),
+ {stop, Ch, State}.
+
+
+handle_call(send_eof, _From,#state{ch=Ch,cm=C} = State) ->
+ {reply, ssh_connection:send_eof(C,Ch), State};
+
+handle_call(stop, _From, State) ->
+ {stop, normal, ok, State};
+
+handle_call(Msg, _From, State) ->
+ ?DBG(State, "Unknown call ~p", [Msg]),
+ {reply, {unknown_call,Msg}, State}.
+
+
+terminate(Reason, State) ->
+ tell_parent({terminate,Reason}, State),
+ ?DBG(State, "terminate Reason = ~p",[Reason]).
+
+
+handle_cast(Msg, State) ->
+ ?DBG(State, "Unknown cast ~p", [Msg]),
+ {noreply, State}.
+
+code_change(_OldVsn, State, _Extra) -> {ok, State}.
+
+%%%================================================================
+%%%
+%%%
+
+tell_parent(Msg, #state{parent = Parent,
+ cm = C,
+ ch = Ch}) -> Parent ! {{C,Ch}, Msg}.
+
diff --git a/lib/ssh/test/ssh_chan_behaviours_server.erl b/lib/ssh/test/ssh_chan_behaviours_server.erl
new file mode 100644
index 0000000000..1d504b1bc6
--- /dev/null
+++ b/lib/ssh/test/ssh_chan_behaviours_server.erl
@@ -0,0 +1,96 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+%%% Description: Example ssh server
+-module(ssh_chan_behaviours_server).
+-behaviour(ssh_server_channel).
+-record(state, {
+ parent,
+ cm,
+ ch,
+ dbg
+ }).
+-export([init/1, handle_msg/2, handle_ssh_msg/2, terminate/2]).
+
+-define(DBG(State,Fmt,Args),
+ case State#state.dbg of
+ true -> ct:log("~p:~p ~p C=~p Ch=~p "++Fmt,
+ [?MODULE,?LINE,self(),State#state.cm,State#state.ch|Args]);
+ false -> ok
+ end).
+
+
+init([Pid,Dbg|_Exec]) ->
+ {ok, #state{parent=Pid,
+ dbg=Dbg}}.
+
+handle_msg({ssh_channel_up, ChannelId, ConnectionManager}=M, State0) ->
+ State = State0#state{cm = ConnectionManager,
+ ch = ChannelId},
+ tell_parent(M, State),
+ ?DBG(State, "ssh_channel_up",[]),
+ {ok, State}.
+
+handle_ssh_msg({ssh_cm, C, {data, Ch, 0, Data}}=M, #state{ch=Ch,cm=C} = State) ->
+ tell_parent(M, State),
+ ?DBG(State, "ssh_cm data size(Data)=~p",[size(Data)]),
+ {ok, State};
+
+handle_ssh_msg({ssh_cm, C, {data, Ch, Type, Data}}=M, #state{ch=Ch,cm=C} = State) ->
+ tell_parent(M, State),
+ ?DBG(State, "ssh_cm data Type=~p : ~p",[Type,Data]),
+ {ok, State};
+
+handle_ssh_msg({ssh_cm, C, {eof, Ch}}=M, #state{ch=Ch,cm=C} = State) ->
+ tell_parent(M, State),
+ ?DBG(State, "eof",[]),
+ {ok, State};
+
+handle_ssh_msg({ssh_cm, C, {signal, Ch, _SigNameStr}=Sig} = M, #state{ch=Ch,cm=C} = State) ->
+ %% Ignore signals according to RFC 4254 section 6.9.
+ tell_parent(M, State),
+ ?DBG(State, "~p",[Sig]),
+ {ok, State};
+
+handle_ssh_msg({ssh_cm, C, {exit_signal, Ch, _, _Error, _}=Sig}=M, #state{ch=Ch,cm=C} = State) ->
+ tell_parent(M, State),
+ ?DBG(State, "~p",[Sig]),
+ {stop, Ch, State};
+
+handle_ssh_msg({ssh_cm, C, {exit_status, Ch, _Status}=Sig}=M, #state{ch=Ch,cm=C} = State) ->
+ tell_parent(M, State),
+ ?DBG(State, "~p",[Sig]),
+ {stop, Ch, State}.
+
+terminate(Reason, State) ->
+ tell_parent({terminate,Reason}, State),
+ ?DBG(State, "terminate Reason = ~p",[Reason]),
+ ok.
+
+%%%================================================================
+%%%
+%%%
+
+tell_parent(Msg, #state{parent = Parent,
+ cm = C,
+ ch = Ch}) -> Parent ! {{C,Ch}, Msg}.
+
diff --git a/lib/ssh/test/ssh_compat_SUITE.erl b/lib/ssh/test/ssh_compat_SUITE.erl
index f7eda1dc08..06ed9082cf 100644
--- a/lib/ssh/test/ssh_compat_SUITE.erl
+++ b/lib/ssh/test/ssh_compat_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -41,8 +41,7 @@
%%--------------------------------------------------------------------
suite() ->
- [%%{ct_hooks,[ts_install_cth]},
- {timetrap,{seconds,40}}].
+ [{timetrap,{seconds,60}}].
all() ->
%% [check_docker_present] ++
@@ -151,8 +150,7 @@ init_per_group(G, Config0) ->
stop_docker(ID),
{fail, "Can't contact docker sshd"}
catch
- Class:Exc ->
- ST = erlang:get_stacktrace(),
+ Class:Exc:ST ->
ct:log("common_algs: ~p:~p~n~p",[Class,Exc,ST]),
stop_docker(ID),
{fail, "Failed during setup"}
@@ -161,8 +159,7 @@ init_per_group(G, Config0) ->
cant_start_docker ->
{skip, "Can't start docker"};
- C:E ->
- ST = erlang:get_stacktrace(),
+ C:E:ST ->
ct:log("No ~p~n~p:~p~n~p",[G,C,E,ST]),
{skip, "Can't start docker"}
end;
@@ -649,6 +646,7 @@ setup_remote_priv_and_local_auth_keys(KeyAlg, IP, Port, UserDir, Config) ->
{silently_accept_hosts,true},
{user_interaction,false}
]),
+ rm_id_in_remote_dir(Ch, ".ssh"),
_ = ssh_sftp:make_dir(Ch, ".ssh"),
DstFile = filename:join(".ssh", dst_filename(user,KeyAlg)),
ok = ssh_sftp:write_file(Ch, DstFile, Priv),
@@ -659,6 +657,18 @@ setup_remote_priv_and_local_auth_keys(KeyAlg, IP, Port, UserDir, Config) ->
ok = ssh:close(Cc),
UserDir.
+rm_id_in_remote_dir(Ch, Dir) ->
+ case ssh_sftp:list_dir(Ch, Dir) of
+ {error,_Error} ->
+ ok;
+ {ok,FileNames} ->
+ lists:foreach(fun("id_"++_ = F) ->
+ ok = ssh_sftp:delete(Ch, filename:join(Dir,F));
+ (_) ->
+ leave
+ end, FileNames)
+ end.
+
user_priv_pub_keys(Config, KeyAlg) -> priv_pub_keys("users_keys", user, Config, KeyAlg).
host_priv_pub_keys(Config, KeyAlg) -> priv_pub_keys("host_keys", host, Config, KeyAlg).
@@ -674,6 +684,8 @@ src_filename(user, 'ssh-rsa' ) -> "id_rsa";
src_filename(user, 'rsa-sha2-256' ) -> "id_rsa";
src_filename(user, 'rsa-sha2-512' ) -> "id_rsa";
src_filename(user, 'ssh-dss' ) -> "id_dsa";
+src_filename(user, 'ssh-ed25519' ) -> "id_ed25519";
+src_filename(user, 'ssh-ed448' ) -> "id_ed448";
src_filename(user, 'ecdsa-sha2-nistp256') -> "id_ecdsa256";
src_filename(user, 'ecdsa-sha2-nistp384') -> "id_ecdsa384";
src_filename(user, 'ecdsa-sha2-nistp521') -> "id_ecdsa521";
@@ -681,6 +693,8 @@ src_filename(host, 'ssh-rsa' ) -> "ssh_host_rsa_key";
src_filename(host, 'rsa-sha2-256' ) -> "ssh_host_rsa_key";
src_filename(host, 'rsa-sha2-512' ) -> "ssh_host_rsa_key";
src_filename(host, 'ssh-dss' ) -> "ssh_host_dsa_key";
+src_filename(host, 'ssh-ed25519' ) -> "ssh_host_ed25519_key";
+src_filename(host, 'ssh-ed448' ) -> "ssh_host_ed448_key";
src_filename(host, 'ecdsa-sha2-nistp256') -> "ssh_host_ecdsa_key256";
src_filename(host, 'ecdsa-sha2-nistp384') -> "ssh_host_ecdsa_key384";
src_filename(host, 'ecdsa-sha2-nistp521') -> "ssh_host_ecdsa_key521".
@@ -689,6 +703,8 @@ dst_filename(user, 'ssh-rsa' ) -> "id_rsa";
dst_filename(user, 'rsa-sha2-256' ) -> "id_rsa";
dst_filename(user, 'rsa-sha2-512' ) -> "id_rsa";
dst_filename(user, 'ssh-dss' ) -> "id_dsa";
+dst_filename(user, 'ssh-ed25519' ) -> "id_ed25519";
+dst_filename(user, 'ssh-ed448' ) -> "id_ed448";
dst_filename(user, 'ecdsa-sha2-nistp256') -> "id_ecdsa";
dst_filename(user, 'ecdsa-sha2-nistp384') -> "id_ecdsa";
dst_filename(user, 'ecdsa-sha2-nistp521') -> "id_ecdsa";
@@ -696,6 +712,8 @@ dst_filename(host, 'ssh-rsa' ) -> "ssh_host_rsa_key";
dst_filename(host, 'rsa-sha2-256' ) -> "ssh_host_rsa_key";
dst_filename(host, 'rsa-sha2-512' ) -> "ssh_host_rsa_key";
dst_filename(host, 'ssh-dss' ) -> "ssh_host_dsa_key";
+dst_filename(host, 'ssh-ed25519' ) -> "ssh_host_ed25519_key";
+dst_filename(host, 'ssh-ed448' ) -> "ssh_host_ed448_key";
dst_filename(host, 'ecdsa-sha2-nistp256') -> "ssh_host_ecdsa_key";
dst_filename(host, 'ecdsa-sha2-nistp384') -> "ssh_host_ecdsa_key";
dst_filename(host, 'ecdsa-sha2-nistp521') -> "ssh_host_ecdsa_key".
@@ -1006,8 +1024,7 @@ receive_hello(S) ->
Result ->
Result
catch
- Class:Error ->
- ST = erlang:get_stacktrace(),
+ Class:Error:ST ->
{error, {Class,Error,ST}}
end.
@@ -1084,8 +1101,7 @@ sftp_tests_erl_server(Config, ServerIP, ServerPort, ServerRootDir, UserDir) ->
call_sftp_in_docker(Config, ServerIP, ServerPort, Cmnds, UserDir),
check_local_directory(ServerRootDir)
catch
- Class:Error ->
- ST = erlang:get_stacktrace(),
+ Class:Error:ST ->
{error, {Class,Error,ST}}
end.
@@ -1106,7 +1122,24 @@ prepare_local_directory(ServerRootDir) ->
"chmod 222 unreadable_file",
"exit"].
+
check_local_directory(ServerRootDir) ->
+ TimesToTry = 3, % sleep 0.5, 1, 2 and then 4 secs (7.5s in total)
+ check_local_directory(ServerRootDir, 500, TimesToTry-1).
+
+check_local_directory(ServerRootDir, SleepTime, N) ->
+ case do_check_local_directory(ServerRootDir) of
+ {error,_Error} when N>0 ->
+ %% Could be that the erlang side is faster and the docker's operations
+ %% are not yet finalized.
+ %% Sleep for a while and retry a few times:
+ timer:sleep(SleepTime),
+ check_local_directory(ServerRootDir, 2*SleepTime, N-1);
+ Other ->
+ Other
+ end.
+
+do_check_local_directory(ServerRootDir) ->
case lists:sort(ok(file:list_dir(ServerRootDir)) -- [".",".."]) of
["ex_tst1","mydir","tst2"] ->
{ok,Expect} = file:read_file(filename:join(ServerRootDir,"ex_tst1")),
@@ -1141,6 +1174,7 @@ check_local_directory(ServerRootDir) ->
{error,{bad_dir_contents,"/"}}
end.
+
call_sftp_in_docker(Config, ServerIP, ServerPort, Cmnds, UserDir) ->
{DockerIP,DockerPort} = ip_port(Config),
{ok,C} = ssh:connect(DockerIP, DockerPort,
@@ -1309,8 +1343,7 @@ one_test_erl_client(SFTP, Id, C) when SFTP==sftp ; SFTP==sftp_async ->
catch ssh_sftp:stop_channel(Ch),
R
catch
- Class:Error ->
- ST = erlang:get_stacktrace(),
+ Class:Error:ST ->
{error, {SFTP,Id,Class,Error,ST}}
end.
diff --git a/lib/ssh/test/ssh_compat_SUITE_data/build_scripts/create_all b/lib/ssh/test/ssh_compat_SUITE_data/build_scripts/create_all
index 0dcf8cb570..c2e77fcc79 100755
--- a/lib/ssh/test/ssh_compat_SUITE_data/build_scripts/create_all
+++ b/lib/ssh/test/ssh_compat_SUITE_data/build_scripts/create_all
@@ -18,6 +18,12 @@ SSH_SSL_VERSIONS=(\
openssh 7.6p1 openssl 1.0.2n \
\
openssh 7.6p1 libressl 2.6.4 \
+ \
+ openssh 7.7p1 openssl 1.0.2p \
+ openssh 7.8p1 openssl 1.0.2p \
+ openssh 7.9p1 openssl 1.0.2p \
+ \
+ openssh 7.9p1 libressl 2.6.4 \
)
if [ "x$1" == "x-b" ]
diff --git a/lib/ssh/test/ssh_compat_SUITE_data/host_keys/ssh_host_ed25519_key b/lib/ssh/test/ssh_compat_SUITE_data/host_keys/ssh_host_ed25519_key
new file mode 100644
index 0000000000..13a8fcf491
--- /dev/null
+++ b/lib/ssh/test/ssh_compat_SUITE_data/host_keys/ssh_host_ed25519_key
@@ -0,0 +1,7 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
+QyNTUxOQAAACBJSOuiYGWaO9lye8Bgafod1kw8P6cV3Xb2qJgCB6yJfQAAAJi+h4O7voeD
+uwAAAAtzc2gtZWQyNTUxOQAAACBJSOuiYGWaO9lye8Bgafod1kw8P6cV3Xb2qJgCB6yJfQ
+AAAEBaOcJfGPNemKc1wPHTCmM4Kwvh6dZ0CqY14UT361UnN0lI66JgZZo72XJ7wGBp+h3W
+TDw/pxXddvaomAIHrIl9AAAAE3VhYmhuaWxAZWx4YWRsajNxMzIBAg==
+-----END OPENSSH PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_compat_SUITE_data/host_keys/ssh_host_ed25519_key.pub b/lib/ssh/test/ssh_compat_SUITE_data/host_keys/ssh_host_ed25519_key.pub
new file mode 100644
index 0000000000..156ef4045c
--- /dev/null
+++ b/lib/ssh/test/ssh_compat_SUITE_data/host_keys/ssh_host_ed25519_key.pub
@@ -0,0 +1 @@
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIElI66JgZZo72XJ7wGBp+h3WTDw/pxXddvaomAIHrIl9 uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_compat_SUITE_data/host_keys/ssh_host_ed448_key b/lib/ssh/test/ssh_compat_SUITE_data/host_keys/ssh_host_ed448_key
new file mode 100644
index 0000000000..31a7e4e8c3
--- /dev/null
+++ b/lib/ssh/test/ssh_compat_SUITE_data/host_keys/ssh_host_ed448_key
@@ -0,0 +1,10 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAASgAAAAlz
+c2gtZWQ0NDgAAAA5X9dEm1m0Yf0s54fsYWrUah2hNCSFpw4fig6nXYDpZ3jt8SR2
+m0bHBhvWeD3x5Q9s0foavq/oJWGAAAAA0AAAEREAABERAAAACXNzaC1lZDQ0OAAA
+ADlf10SbWbRh/Sznh+xhatRqHaE0JIWnDh+KDqddgOlneO3xJHabRscGG9Z4PfHl
+D2zR+hq+r+glYYAAAABybIKlYsuAjRDWMr6JyFE+v2ySnzTd+oyfY8mWDvbjSKNS
+jIo/zC8ETjmj/FuUSS+PAy51SaIAmPlbX9dEm1m0Yf0s54fsYWrUah2hNCSFpw4f
+ig6nXYDpZ3jt8SR2m0bHBhvWeD3x5Q9s0foavq/oJWGAAAAAAAECAwQ=
+-----END OPENSSH PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_compat_SUITE_data/host_keys/ssh_host_ed448_key.pub b/lib/ssh/test/ssh_compat_SUITE_data/host_keys/ssh_host_ed448_key.pub
new file mode 100644
index 0000000000..8c390dcb58
--- /dev/null
+++ b/lib/ssh/test/ssh_compat_SUITE_data/host_keys/ssh_host_ed448_key.pub
@@ -0,0 +1 @@
+ssh-ed448 AAAACXNzaC1lZDQ0OAAAADlf10SbWbRh/Sznh+xhatRqHaE0JIWnDh+KDqddgOlneO3xJHabRscGG9Z4PfHlD2zR+hq+r+glYYA=
diff --git a/lib/ssh/test/ssh_compat_SUITE_data/users_keys/id_ed25519 b/lib/ssh/test/ssh_compat_SUITE_data/users_keys/id_ed25519
new file mode 100644
index 0000000000..401a3e4a9a
--- /dev/null
+++ b/lib/ssh/test/ssh_compat_SUITE_data/users_keys/id_ed25519
@@ -0,0 +1,7 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
+QyNTUxOQAAACDm9P8/gC0IOKmwHLSvkmEtS2Xx0RRqUDqC6wY6UgDVnwAAAJg3+6xpN/us
+aQAAAAtzc2gtZWQyNTUxOQAAACDm9P8/gC0IOKmwHLSvkmEtS2Xx0RRqUDqC6wY6UgDVnw
+AAAEBzC/Z2WGJhZ3l3tIBnUc6DCbp+lXY2yc2RRpWQTdf8sub0/z+ALQg4qbActK+SYS1L
+ZfHRFGpQOoLrBjpSANWfAAAAE3VhYmhuaWxAZWx4YWRsajNxMzIBAg==
+-----END OPENSSH PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_compat_SUITE_data/users_keys/id_ed25519.pub b/lib/ssh/test/ssh_compat_SUITE_data/users_keys/id_ed25519.pub
new file mode 100644
index 0000000000..a5c03b19c1
--- /dev/null
+++ b/lib/ssh/test/ssh_compat_SUITE_data/users_keys/id_ed25519.pub
@@ -0,0 +1 @@
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOb0/z+ALQg4qbActK+SYS1LZfHRFGpQOoLrBjpSANWf uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_compat_SUITE_data/users_keys/id_ed448 b/lib/ssh/test/ssh_compat_SUITE_data/users_keys/id_ed448
new file mode 100644
index 0000000000..8ecfd710dc
--- /dev/null
+++ b/lib/ssh/test/ssh_compat_SUITE_data/users_keys/id_ed448
@@ -0,0 +1,10 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAASgAAAAlz
+c2gtZWQ0NDgAAAA53OqeePNaG/NJmoMbELhskKrAHNhLZ6AQm1WjbpMoseNl/OFh
+1xznExpUPqTLX36fHYsAaWRHABQAAAAA0AAAEREAABERAAAACXNzaC1lZDQ0OAAA
+ADnc6p5481ob80magxsQuGyQqsAc2EtnoBCbVaNukyix42X84WHXHOcTGlQ+pMtf
+fp8diwBpZEcAFAAAAAByzSPST3FCdOdENDI3uTKQ9RH2Ql+Y5kRZ/yA+iYUIP/32
+BQBVOrwOBc0CGEvbicTM1n4YeVEmfrMo3OqeePNaG/NJmoMbELhskKrAHNhLZ6AQ
+m1WjbpMoseNl/OFh1xznExpUPqTLX36fHYsAaWRHABQAAAAAAAECAwQ=
+-----END OPENSSH PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_compat_SUITE_data/users_keys/id_ed448.pub b/lib/ssh/test/ssh_compat_SUITE_data/users_keys/id_ed448.pub
new file mode 100644
index 0000000000..cec0765a5d
--- /dev/null
+++ b/lib/ssh/test/ssh_compat_SUITE_data/users_keys/id_ed448.pub
@@ -0,0 +1 @@
+ssh-ed448 AAAACXNzaC1lZDQ0OAAAADnc6p5481ob80magxsQuGyQqsAc2EtnoBCbVaNukyix42X84WHXHOcTGlQ+pMtffp8diwBpZEcAFAA= uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_connection_SUITE.erl b/lib/ssh/test/ssh_connection_SUITE.erl
index 9587c0c251..6aa587dc7f 100644
--- a/lib/ssh/test/ssh_connection_SUITE.erl
+++ b/lib/ssh/test/ssh_connection_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -50,6 +50,13 @@ all() ->
start_shell,
start_shell_exec,
start_shell_exec_fun,
+ start_shell_exec_fun2,
+ start_shell_exec_fun3,
+ start_shell_exec_direct_fun,
+ start_shell_exec_direct_fun2,
+ start_shell_exec_direct_fun3,
+ start_shell_exec_direct_fun1_error,
+ start_shell_exec_direct_fun1_error_type,
start_shell_sock_exec_fun,
start_shell_sock_daemon_exec,
connect_sock_not_tcp,
@@ -522,7 +529,7 @@ start_shell_exec(Config) when is_list(Config) ->
{Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
{user_dir, UserDir},
{password, "morot"},
- {exec, {?MODULE,ssh_exec,[]}} ]),
+ {exec, {?MODULE,ssh_exec_echo,[]}} ]),
ConnectionRef = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
{user, "foo"},
@@ -535,7 +542,7 @@ start_shell_exec(Config) when is_list(Config) ->
success = ssh_connection:exec(ConnectionRef, ChannelId0,
"testing", infinity),
receive
- {ssh_cm, ConnectionRef, {data, _ChannelId, 0, <<"testing\r\n">>}} ->
+ {ssh_cm, ConnectionRef, {data, _ChannelId, 0, <<"echo testing\r\n">>}} ->
ok
after 5000 ->
ct:fail("Exec Timeout")
@@ -618,10 +625,49 @@ exec_erlang_term_non_default_shell(Config) when is_list(Config) ->
TestResult.
%%--------------------------------------------------------------------
-start_shell_exec_fun() ->
- [{doc, "start shell to exec command"}].
+start_shell_exec_fun(Config) ->
+ do_start_shell_exec_fun(fun ssh_exec_echo/1,
+ "testing", <<"echo testing\r\n">>, 0,
+ Config).
+
+start_shell_exec_fun2(Config) ->
+ do_start_shell_exec_fun(fun ssh_exec_echo/2,
+ "testing", <<"echo foo testing\r\n">>, 0,
+ Config).
+
+start_shell_exec_fun3(Config) ->
+ do_start_shell_exec_fun(fun ssh_exec_echo/3,
+ "testing", <<"echo foo testing\r\n">>, 0,
+ Config).
+
+start_shell_exec_direct_fun(Config) ->
+ do_start_shell_exec_fun({direct, fun ssh_exec_direct_echo/1},
+ "testing", <<"echo testing\n">>, 0,
+ Config).
+
+start_shell_exec_direct_fun2(Config) ->
+ do_start_shell_exec_fun({direct, fun ssh_exec_direct_echo/2},
+ "testing", <<"echo foo testing">>, 0,
+ Config).
+
+start_shell_exec_direct_fun3(Config) ->
+ do_start_shell_exec_fun({direct, fun ssh_exec_direct_echo/3},
+ "testing", <<"echo foo testing">>, 0,
+ Config).
+
+start_shell_exec_direct_fun1_error(Config) ->
+ do_start_shell_exec_fun({direct, fun ssh_exec_direct_echo_error_return/1},
+ "testing", <<"Error in \"testing\": {bad}\n">>, 1,
+ Config).
+
+start_shell_exec_direct_fun1_error_type(Config) ->
+ do_start_shell_exec_fun({direct, fun ssh_exec_direct_echo_error_return_type/1},
+ "testing", <<"Error in \"testing\": Bad exec-plugin return: very_bad\n">>, 1,
+ Config).
+
+
-start_shell_exec_fun(Config) when is_list(Config) ->
+do_start_shell_exec_fun(Fun, Command, Expect, ExpectType, Config) ->
PrivDir = proplists:get_value(priv_dir, Config),
UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
file:make_dir(UserDir),
@@ -629,7 +675,7 @@ start_shell_exec_fun(Config) when is_list(Config) ->
{Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
{user_dir, UserDir},
{password, "morot"},
- {exec, fun ssh_exec/1}]),
+ {exec, Fun}]),
ConnectionRef = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
{user, "foo"},
@@ -639,14 +685,19 @@ start_shell_exec_fun(Config) when is_list(Config) ->
{ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity),
- success = ssh_connection:exec(ConnectionRef, ChannelId0,
- "testing", infinity),
+ success = ssh_connection:exec(ConnectionRef, ChannelId0, Command, infinity),
receive
- {ssh_cm, ConnectionRef, {data, _ChannelId, 0, <<"testing\r\n">>}} ->
+ {ssh_cm, ConnectionRef, {data, _ChannelId, ExpectType, Expect}} ->
ok
after 5000 ->
- ct:fail("Exec Timeout")
+ receive
+ Other ->
+ ct:pal("Received other:~n~p",[Other]),
+ ct:fail("Unexpected response")
+ after 0 ->
+ ct:fail("Exec Timeout")
+ end
end,
ssh:close(ConnectionRef),
@@ -664,7 +715,7 @@ start_shell_sock_exec_fun(Config) when is_list(Config) ->
{Pid, HostD, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
{user_dir, UserDir},
{password, "morot"},
- {exec, fun ssh_exec/1}]),
+ {exec, fun ssh_exec_echo/1}]),
Host = ssh_test_lib:ntoa(ssh_test_lib:mangle_connect_address(HostD)),
{ok, Sock} = ssh_test_lib:gen_tcp_connect(Host, Port, [{active,false}]),
@@ -680,7 +731,7 @@ start_shell_sock_exec_fun(Config) when is_list(Config) ->
"testing", infinity),
receive
- {ssh_cm, ConnectionRef, {data, _ChannelId, 0, <<"testing\r\n">>}} ->
+ {ssh_cm, ConnectionRef, {data, _ChannelId, 0, <<"echo testing\r\n">>}} ->
ok
after 5000 ->
ct:fail("Exec Timeout")
@@ -704,7 +755,7 @@ start_shell_sock_daemon_exec(Config) ->
{ok, _Pid} = ssh:daemon(Ss, [{system_dir, SysDir},
{user_dir, UserDir},
{password, "morot"},
- {exec, fun ssh_exec/1}])
+ {exec, fun ssh_exec_echo/1}])
end),
{ok,Sc} = gen_tcp:accept(Sl),
{ok,ConnectionRef} = ssh:connect(Sc, [{silently_accept_hosts, true},
@@ -719,7 +770,7 @@ start_shell_sock_daemon_exec(Config) ->
"testing", infinity),
receive
- {ssh_cm, ConnectionRef, {data, _ChannelId, 0, <<"testing\r\n">>}} ->
+ {ssh_cm, ConnectionRef, {data, _ChannelId, 0, <<"echo testing\r\n">>}} ->
ok
after 5000 ->
ct:fail("Exec Timeout")
@@ -830,7 +881,7 @@ stop_listener(Config) when is_list(Config) ->
{Pid0, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
{user_dir, UserDir},
{password, "morot"},
- {exec, fun ssh_exec/1}]),
+ {exec, fun ssh_exec_echo/1}]),
ConnectionRef0 = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
{user, "foo"},
@@ -850,7 +901,7 @@ stop_listener(Config) when is_list(Config) ->
success = ssh_connection:exec(ConnectionRef0, ChannelId0,
"testing", infinity),
receive
- {ssh_cm, ConnectionRef0, {data, ChannelId0, 0, <<"testing\r\n">>}} ->
+ {ssh_cm, ConnectionRef0, {data, ChannelId0, 0, <<"echo testing\r\n">>}} ->
ok
after 5000 ->
ct:fail("Exec Timeout")
@@ -859,7 +910,7 @@ stop_listener(Config) when is_list(Config) ->
case ssh_test_lib:daemon(Port, [{system_dir, SysDir},
{user_dir, UserDir},
{password, "potatis"},
- {exec, fun ssh_exec/1}]) of
+ {exec, fun ssh_exec_echo/1}]) of
{Pid1, Host, Port} ->
ConnectionRef1 = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
{user, "foo"},
@@ -1070,7 +1121,22 @@ start_our_shell(_User, _Peer) ->
%% Don't actually loop, just exit
end).
-ssh_exec(Cmd) ->
+
+ssh_exec_echo(Cmd) ->
spawn(fun() ->
- io:format(Cmd ++ "\n")
+ io:format("echo ~s\n", [Cmd])
end).
+
+ssh_exec_echo(Cmd, User) ->
+ spawn(fun() ->
+ io:format("echo ~s ~s\n",[User,Cmd])
+ end).
+ssh_exec_echo(Cmd, User, _PeerAddr) ->
+ ssh_exec_echo(Cmd,User).
+
+ssh_exec_direct_echo(Cmd) -> {ok, io_lib:format("echo ~s~n",[Cmd])}.
+ssh_exec_direct_echo(Cmd, User) -> {ok, io_lib:format("echo ~s ~s",[User,Cmd])}.
+ssh_exec_direct_echo(Cmd, User, _PeerAddr) -> ssh_exec_direct_echo(Cmd,User).
+
+ssh_exec_direct_echo_error_return(_Cmd) -> {error, {bad}}.
+ssh_exec_direct_echo_error_return_type(_Cmd) -> very_bad.
diff --git a/lib/ssh/test/ssh_dbg_SUITE.erl b/lib/ssh/test/ssh_dbg_SUITE.erl
new file mode 100644
index 0000000000..ab7918fa90
--- /dev/null
+++ b/lib/ssh/test/ssh_dbg_SUITE.erl
@@ -0,0 +1,465 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+-module(ssh_dbg_SUITE).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("ssh/src/ssh.hrl").
+-include("ssh_test_lib.hrl").
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap,{seconds,60}}].
+
+all() ->
+ [{group, dbg},
+ {group, circ_buf}
+ ].
+
+groups() ->
+ [{dbg, [], [dbg_basic,
+ dbg_alg_terminate,
+ dbg_ssh_messages,
+ dbg_connections,
+ dbg_channels]},
+ {circ_buf, [], [cb_basic,
+ cb_print,
+ cb_macros_print
+ ]}
+ ].
+
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ ?CHECK_CRYPTO(begin
+ ssh:start(),
+ Config
+ end).
+
+end_per_suite(_Config) ->
+ ssh:stop().
+
+%%--------------------------------------------------------------------
+init_per_testcase(_TC, Config) ->
+ Config.
+
+end_per_testcase(_TC, Config) ->
+ ssh_dbg:stop(),
+ Config.
+
+%%--------------------------------------------------------------------
+-define(USR, "foo").
+-define(PWD, "bar").
+
+-define(DBG_RECEIVE(ExpectPfx, Ref, C, Pid),
+ receive
+ {Ref, [_, C, ExpectPfx++_]} ->
+ ok
+
+ after 5000 ->
+ ssh_dbg:stop(),
+ ssh:stop_daemon(Pid),
+ ct:fail("No '~s' debug message",[ExpectPfx])
+ end
+ ).
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+dbg_basic(_Config) ->
+ L0 = ssh_dbg:start(),
+ true = is_pid(whereis(ssh_dbg)),
+ true = is_list(L0),
+
+ {ok,L0} = ssh_dbg:on(),
+ {ok,L0} = ssh_dbg:on(),
+
+ L1 = [hd(L0)],
+ {ok,L1} = ssh_dbg:off(tl(L0)),
+
+ {ok,L1} = ssh_dbg:go_on(),
+
+ {ok,[]} = ssh_dbg:off(),
+ {ok,[]} = ssh_dbg:off(),
+
+ ok = ssh_dbg:stop(),
+ undefined = whereis(ssh_dbg).
+
+
+%%--------------------------------------------------------------------
+dbg_alg_terminate(Config) ->
+ SystemDir = proplists:get_value(data_dir, Config),
+ UserDir = proplists:get_value(priv_dir, Config),
+
+ Ref = ssh_dbg_start(),
+ {ok,[alg,connections,terminate]} = ssh_dbg:on([alg,terminate,connections]),
+ {ok,[alg,terminate]} = ssh_dbg:off(connections), % just testing that terminate is not canceled
+
+ Parent = self(),
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {user_dir, UserDir},
+ {user_passwords, [{?USR,?PWD}]},
+ {connectfun, fun(_,_,_) ->
+ Parent ! {daemon_c,Ref,self()}
+ end},
+ {failfun, fun ssh_test_lib:failfun/2}]),
+ C = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user_dir, UserDir},
+ {user,?USR},
+ {password,?PWD},
+ {user_interaction, false}]),
+
+ %% Daemon connection ref (D):
+ D = receive
+ {daemon_c,Ref,D0} -> D0
+ end,
+ ct:log("~p:~p~nC = ~p, D=~p",[?MODULE,?LINE, C, D]),
+
+ ?DBG_RECEIVE("Negotiated algorithms:", Ref, C, Pid),
+ ?DBG_RECEIVE("Negotiated algorithms:", Ref, D, Pid),
+
+ ssh:close(C),
+ ?DBG_RECEIVE("Connection Terminating:", Ref, C, Pid),
+ ?DBG_RECEIVE("Connection Terminating:", Ref, D, Pid),
+
+ stop_and_fail_if_unhandled_dbg_msgs(Ref, [C,D], Pid).
+
+%%--------------------------------------------------------------------
+dbg_connections(Config) ->
+ SystemDir = proplists:get_value(data_dir, Config),
+ UserDir = proplists:get_value(priv_dir, Config),
+
+ Ref = ssh_dbg_start(),
+ {ok,[connections,terminate]} = ssh_dbg:on([connections, terminate]),
+ {ok,[connections]} = ssh_dbg:off(terminate), % Just testing that terminate doesn't cancel connections
+
+ Parent = self(),
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {user_dir, UserDir},
+ {user_passwords, [{?USR,?PWD}]},
+ {connectfun, fun(_,_,_) ->
+ Parent ! {daemon_c,Ref,self()}
+ end},
+ {failfun, fun ssh_test_lib:failfun/2}]),
+
+ ?DBG_RECEIVE("Starting LISTENER on ", Ref, _, Pid),
+
+ C = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user_dir, UserDir},
+ {user,?USR},
+ {password,?PWD},
+ {user_interaction, false}]),
+
+ %% Daemon connection ref (D):
+ D = receive
+ {daemon_c,Ref,D0} -> D0
+ end,
+ ct:log("~p:~p~nC = ~p, D=~p",[?MODULE,?LINE, C, D]),
+
+ ?DBG_RECEIVE("Starting server connection:", Ref, D, Pid),
+ ?DBG_RECEIVE("Starting client connection:", Ref, C, Pid),
+
+ ssh:close(C),
+ ?DBG_RECEIVE("Connection Terminating:", Ref, C, Pid),
+ ?DBG_RECEIVE("Connection Terminating:", Ref, D, Pid),
+
+ stop_and_fail_if_unhandled_dbg_msgs(Ref, [C,D], Pid).
+
+%%--------------------------------------------------------------------
+dbg_ssh_messages(Config) ->
+ SystemDir = proplists:get_value(data_dir, Config),
+ UserDir = proplists:get_value(priv_dir, Config),
+
+ Parent = self(),
+ Ref = make_ref(),
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {user_dir, UserDir},
+ {user_passwords, [{?USR,?PWD}]},
+ {connectfun, fun(_,_,_) ->
+ Parent ! {daemon_c,Ref,self()}
+ end},
+ {failfun, fun ssh_test_lib:failfun/2}]),
+
+ ssh_dbg_start(Ref),
+ {ok,[ssh_messages]} = ssh_dbg:on([ssh_messages]),
+
+ C = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user_dir, UserDir},
+ {user,?USR},
+ {password,?PWD},
+ {user_interaction, false}]),
+
+ %% Daemon connection ref (D):
+ D = receive
+ {daemon_c,Ref,D0} -> D0
+ end,
+ ct:log("~p:~p~nC = ~p, D=~p",[?MODULE,?LINE, C, D]),
+
+ ?DBG_RECEIVE("Going to send hello message:", Ref, C, Pid),
+ ?DBG_RECEIVE("Received hello message:", Ref, D, Pid),
+
+ ?DBG_RECEIVE("Going to send hello message:", Ref, D, Pid),
+ ?DBG_RECEIVE("Received hello message:", Ref, C, Pid),
+
+ ?DBG_RECEIVE("Going to send SSH_MSG_KEXINIT:", Ref, C, Pid),
+ ?DBG_RECEIVE("Received SSH_MSG_KEXINIT:", Ref, D, Pid),
+
+ ?DBG_RECEIVE("Going to send SSH_MSG_KEXINIT:", Ref, D, Pid),
+ ?DBG_RECEIVE("Received SSH_MSG_KEXINIT:", Ref, C, Pid),
+
+ case atom_to_list( (ssh_connection_handler:alg(C))#alg.kex ) of
+ "ecdh-"++_ ->
+ ?DBG_RECEIVE("Going to send SSH_MSG_KEX_ECDH_INIT:", Ref, C, Pid),
+ ?DBG_RECEIVE("Received SSH_MSG_KEX_ECDH_INIT:", Ref, D, Pid),
+ ?DBG_RECEIVE("Going to send SSH_MSG_KEX_ECDH_REPLY:", Ref, D, Pid),
+ ?DBG_RECEIVE("Received SSH_MSG_KEX_ECDH_REPLY:", Ref, C, Pid);
+
+ "diffie-hellman-group-exchange-"++_ ->
+ ?DBG_RECEIVE("Going to send SSH_MSG_KEX_DH_GEX_REQUEST:", Ref, C, Pid),
+ ?DBG_RECEIVE("Received SSH_MSG_KEX_DH_GEX_REQUEST:", Ref, D, Pid),
+ ?DBG_RECEIVE("Going to send SSH_MSG_KEX_DH_GEX_GROUP:", Ref, D, Pid),
+ ?DBG_RECEIVE("Received SSH_MSG_KEX_DH_GEX_GROUP:", Ref, C, Pid),
+ ?DBG_RECEIVE("Going to send SSH_MSG_KEX_DH_GEX_INIT:", Ref, C, Pid),
+ ?DBG_RECEIVE("Received SSH_MSG_KEX_DH_GEX_INIT:", Ref, D, Pid),
+ ?DBG_RECEIVE("Going to send SSH_MSG_KEX_DH_GEX_REPLY:", Ref, D, Pid),
+ ?DBG_RECEIVE("Received SSH_MSG_KEX_DH_GEX_REPLY:", Ref, C, Pid);
+
+ "diffie-hellman-group"++_ ->
+ ?DBG_RECEIVE("Going to send SSH_MSG_KEXDH_INIT:", Ref, C, Pid),
+ ?DBG_RECEIVE("Received SSH_MSG_KEXDH_INIT:", Ref, D, Pid),
+ ?DBG_RECEIVE("Going to send SSH_MSG_KEXDH_REPLY:", Ref, D, Pid),
+ ?DBG_RECEIVE("Received SSH_MSG_KEXDH_REPLY:", Ref, C, Pid)
+ end,
+
+
+ ?DBG_RECEIVE("Going to send SSH_MSG_NEWKEYS:", Ref, C, Pid),
+ ?DBG_RECEIVE("Received SSH_MSG_NEWKEYS:", Ref, D, Pid),
+
+ ?DBG_RECEIVE("Going to send SSH_MSG_NEWKEYS:", Ref, D, Pid),
+ ?DBG_RECEIVE("Received SSH_MSG_NEWKEYS:", Ref, C, Pid),
+
+ ?DBG_RECEIVE("Going to send SSH_MSG_SERVICE_REQUEST:", Ref, C, Pid),
+ ?DBG_RECEIVE("Received SSH_MSG_SERVICE_REQUEST:", Ref, D, Pid),
+
+ ?DBG_RECEIVE("Going to send SSH_MSG_SERVICE_ACCEPT:", Ref, D, Pid),
+ ?DBG_RECEIVE("Received SSH_MSG_SERVICE_ACCEPT:", Ref, C, Pid),
+
+ ?DBG_RECEIVE("Going to send SSH_MSG_USERAUTH_REQUEST:", Ref, C, Pid),
+ ?DBG_RECEIVE("Received SSH_MSG_USERAUTH_REQUEST:", Ref, D, Pid),
+
+ ?DBG_RECEIVE("Going to send SSH_MSG_USERAUTH_FAILURE:", Ref, D, Pid),
+ ?DBG_RECEIVE("Received SSH_MSG_USERAUTH_FAILURE:", Ref, C, Pid),
+
+ ?DBG_RECEIVE("Going to send SSH_MSG_USERAUTH_REQUEST:", Ref, C, Pid),
+ ?DBG_RECEIVE("Received SSH_MSG_USERAUTH_REQUEST:", Ref, D, Pid),
+
+ ?DBG_RECEIVE("Going to send SSH_MSG_USERAUTH_SUCCESS:", Ref, D, Pid),
+ ?DBG_RECEIVE("Received SSH_MSG_USERAUTH_SUCCESS:", Ref, C, Pid),
+
+
+ UnexpectedMsgs =
+ dbg_SKIP(Ref,
+ [S_R ++ P ++ ":" || P <- ["SSH_MSG_USERAUTH_REQUEST",
+ "SSH_MSG_USERAUTH_INFO_REQUEST",
+ "SSH_MSG_USERAUTH_INFO_RESPONSE",
+ "SSH_MSG_USERAUTH_FAILURE",
+ "SSH_MSG_EXT_INFO"
+ ],
+ S_R <- ["Going to send ",
+ "Received "
+ ]
+ ]),
+
+ ssh:close(C),
+ stop_and_fail_if_unhandled_dbg_msgs(UnexpectedMsgs, Ref, [C,D], Pid).
+
+%%--------------------------------------------------------------------
+dbg_channels(Config) ->
+ SystemDir = proplists:get_value(data_dir, Config),
+ UserDir = proplists:get_value(priv_dir, Config),
+
+ Ref = ssh_dbg_start(),
+ {ok,[channels,connections]} = ssh_dbg:on([connections, channels]),
+
+ Parent = self(),
+ TimeoutShell =
+ fun() ->
+ io:format("TimeoutShell started!~n",[]),
+ timer:sleep(1000),
+ Parent ! {daemon_channel,Ref,self()},
+ ct:log("~p TIMEOUT!",[self()])
+ end,
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {user_dir, UserDir},
+ {user_passwords, [{?USR,?PWD}]},
+ {connectfun, fun(_,_,_) ->
+ Parent ! {daemon_c,Ref,self()}
+ end},
+ {shell, fun(_User) ->
+ spawn(TimeoutShell)
+ end
+ },
+ {failfun, fun ssh_test_lib:failfun/2}]),
+
+ ?DBG_RECEIVE("Starting LISTENER on ", Ref, _, Pid),
+
+ C = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user_dir, UserDir},
+ {user,?USR},
+ {password,?PWD},
+ {user_interaction, false}]),
+ {ok, Ch0} = ssh_connection:session_channel(C, infinity),
+ ok = ssh_connection:shell(C, Ch0),
+
+ %% Daemon connection ref (D):
+ D = receive {daemon_c,Ref,D0} -> D0 end,
+
+ %% Daemon channel (Dch):
+ Dch = receive {daemon_channel,Ref,Dch0} -> Dch0 end,
+ ct:log("~p:~p~nC = ~p, D=~p, Dch=~p~n~s",[?MODULE,?LINE, C, D, Dch, ssh_info:string()]),
+
+ ?DBG_RECEIVE("Starting server connection:", Ref, D, Pid),
+ ?DBG_RECEIVE("Starting client connection:", Ref, C, Pid),
+ ?DBG_RECEIVE("Server Channel Starting:", Ref, _, Pid),
+ ?DBG_RECEIVE("Server Channel Terminating:", Ref, _, Pid),
+
+ stop_and_fail_if_unhandled_dbg_msgs(Ref, [C,D], Pid).
+
+%%--------------------------------------------------------------------
+cb_basic(_Config) ->
+ %% Check that the circular buffer is disabled at start:
+ [] = ssh_dbg:cbuf_list(),
+ disabled = ssh_dbg:cbuf_in(anything),
+ [] = ssh_dbg:cbuf_list(),
+ %% Start it and enter three values, first is duplicated;
+ ok = ssh_dbg:cbuf_start(3),
+ ok = ssh_dbg:cbuf_in(v1),
+ ok = ssh_dbg:cbuf_in(v1),
+ ok = ssh_dbg:cbuf_in(v2),
+ ok = ssh_dbg:cbuf_in(v3),
+ [{v3,_,1}, {v2,_,1}, {v1,_,2}] = ssh_dbg:cbuf_list(),
+ %% Check that a fourth value erase the first entered:
+ ok = ssh_dbg:cbuf_in(v4),
+ [{v4,_,1}, {v3,_,1}, {v2,_,1}] = ssh_dbg:cbuf_list(),
+ %% Check that entering a value that is in the tail but not in the head is treated as a new value:
+ ok = ssh_dbg:cbuf_in(v2),
+ [{v2,_,1}, {v4,_,1}, {v3,_,1}] = ssh_dbg:cbuf_list(),
+ %% Stop and check that the buffer is returned:
+ [{v2,_,1}, {v4,_,1}, {v3,_,1}] = ssh_dbg:cbuf_stop_clear(),
+ %% Stopping a stopped buffer returns empty:
+ [] = ssh_dbg:cbuf_stop_clear(),
+ %% Check that a value can't be entered in a stopped buffer:
+ disabled = ssh_dbg:cbuf_in(v2).
+
+%%--------------------------------------------------------------------
+cb_print(_Config) ->
+ ssh_dbg:cbuf_start(),
+ [begin
+ ssh_dbg:cbuf_in(V),
+ ct:log("Enter ~p",[V])
+ end || V <- lists:seq(1,10)],
+ ct:log("~s",[ssh_dbg:fmt_cbuf_items()]),
+ ssh_dbg:cbuf_stop_clear().
+
+%%--------------------------------------------------------------------
+cb_macros_print(_Config) ->
+ ssh_dbg:cbuf_start(),
+ [begin
+ V = {test,V0},
+ ?CIRC_BUF_IN(V),
+ ct:log("Enter ~p",[V])
+ end || V0 <- lists:seq(1,5)],
+ ct:log("~s",[ssh_dbg:fmt_cbuf_items()]),
+ ssh_dbg:cbuf_stop_clear().
+
+%%--------------------------------------------------------------------
+%%--------------------------------------------------------------------
+%%--------------------------------------------------------------------
+
+ssh_dbg_start() ->
+ ssh_dbg_start(make_ref()).
+
+ssh_dbg_start(Ref) ->
+ Parent = self(),
+ [_|_] = ssh_dbg:start(fun(_F,A) ->
+ Parent ! {Ref,A}
+ end),
+ Ref.
+
+%%--------------------------------------------------------------------
+queued_msgs(Ref, Conns) ->
+ queued_msgs(Ref, Conns, []).
+
+queued_msgs(Ref, Conns, Acc) ->
+ receive
+ {Ref, [_, C, _]=Msg} ->
+ case is_list(Conns) andalso lists:member(C, Conns) of
+ true ->
+ queued_msgs(Ref, [Msg|Acc]);
+ false ->
+ queued_msgs(Ref, Conns, Acc)
+ end
+ after 0 ->
+ lists:reverse(Acc)
+ end.
+
+%%--------------------------------------------------------------------
+stop_and_fail_if_unhandled_dbg_msgs(Ref, Conns, DaemonPid) ->
+ stop_and_fail_if_unhandled_dbg_msgs(queued_msgs(Ref,Conns), Ref, Conns, DaemonPid).
+
+stop_and_fail_if_unhandled_dbg_msgs(Msgs, _Ref, _Conns, DaemonPid) ->
+ ssh:stop_daemon(DaemonPid),
+ case Msgs of
+ [] ->
+ ok;
+ _ ->
+ ct:log("Unexpected messages:~n~p",[Msgs]),
+ ct:fail("Unexpected messages")
+ end.
+
+%%--------------------------------------------------------------------
+dbg_SKIP(Ref, Prefixes) ->
+ dbg_SKIP(Ref, Prefixes, []).
+
+dbg_SKIP(Ref, Prefixes, UnexpectedAcc) ->
+ receive
+ {Ref, [_, _C, Msg]=M} ->
+ case lists:any(
+ fun(Pfx) ->
+ lists:prefix(Pfx, Msg)
+ end, Prefixes) of
+ true ->
+ ct:log("Skip:~n~p", [M]),
+ dbg_SKIP(Ref, Prefixes, UnexpectedAcc);
+ false ->
+ dbg_SKIP(Ref, Prefixes, [Msg|UnexpectedAcc])
+ end
+ after 0 ->
+ lists:reverse(UnexpectedAcc)
+ end.
+
diff --git a/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_dsa_key
new file mode 100644
index 0000000000..51ab6fbd88
--- /dev/null
+++ b/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_dsa_key
@@ -0,0 +1,13 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBuwIBAAKBgQCClaHzE2ul0gKSUxah5W0W8UiJLy4hXngKEqpaUq9SSdVdY2LK
+wVfKH1gt5iuaf1FfzOhsIC9G/GLnjYttXZc92cv/Gfe3gR+s0ni2++MX+T++mE/Q
+diltXv/Hp27PybS67SmiFW7I+RWnT2OKlMPtw2oUuKeztCe5UWjaj/y5FQIVAPLA
+l9RpiU30Z87NRAHY3NTRaqtrAoGANMRxw8UfdtNVR0CrQj3AgPaXOGE4d+G4Gp4X
+skvnCHycSVAjtYxebUkzUzt5Q6f/IabuLUdge3gXrc8BetvrcKbp+XZgM0/Vj2CF
+Ymmy3in6kzGZq7Fw1sZaku6AOU8vLa5woBT2vAcHLLT1bLAzj7viL048T6MfjrOP
+ef8nHvACgYBhDWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah
+/XcF3DeRF+eEoz48wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+U
+ykSTXYUbtsfTNRFQGBW2/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0CgIVAN4wtL5W
+Lv62jKcdskxNyz2NQoBx
+-----END DSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_dsa_key.pub
new file mode 100644
index 0000000000..4dbb1305b0
--- /dev/null
+++ b/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_dsa_key.pub
@@ -0,0 +1,11 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+AAAAB3NzaC1kc3MAAACBAIKVofMTa6XSApJTFqHlbRbxSIkvLiFeeAoSqlpSr1JJ1V1j
+YsrBV8ofWC3mK5p/UV/M6GwgL0b8YueNi21dlz3Zy/8Z97eBH6zSeLb74xf5P76YT9B2
+KW1e/8enbs/JtLrtKaIVbsj5FadPY4qUw+3DahS4p7O0J7lRaNqP/LkVAAAAFQDywJfU
+aYlN9GfOzUQB2NzU0WqrawAAAIA0xHHDxR9201VHQKtCPcCA9pc4YTh34bganheyS+cI
+fJxJUCO1jF5tSTNTO3lDp/8hpu4tR2B7eBetzwF62+twpun5dmAzT9WPYIViabLeKfqT
+MZmrsXDWxlqS7oA5Ty8trnCgFPa8BwcstPVssDOPu+IvTjxPox+Os495/yce8AAAAIBh
+DWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah/XcF3DeRF+eEoz48
+wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+UykSTXYUbtsfTNRFQGBW2
+/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0Cg==
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_ecdsa_key256 b/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_ecdsa_key256
new file mode 100644
index 0000000000..2979ea88ed
--- /dev/null
+++ b/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_ecdsa_key256
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIMe4MDoit0t8RzSVPwkCBemQ9fhXL+xnTSAWISw8HNCioAoGCCqGSM49
+AwEHoUQDQgAEo2q7U3P6r0W5WGOLtM78UQtofM9UalEhiZeDdiyylsR/RR17Op0s
+VPGSADLmzzgcucLEKy17j2S+oz42VUJy5A==
+-----END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_ecdsa_key256.pub b/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_ecdsa_key256.pub
new file mode 100644
index 0000000000..85dc419345
--- /dev/null
+++ b/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_ecdsa_key256.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKNqu1Nz+q9FuVhji7TO/FELaHzPVGpRIYmXg3YsspbEf0UdezqdLFTxkgAy5s84HLnCxCste49kvqM+NlVCcuQ= uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_ecdsa_key384 b/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_ecdsa_key384
new file mode 100644
index 0000000000..fb1a862ded
--- /dev/null
+++ b/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_ecdsa_key384
@@ -0,0 +1,6 @@
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDArxbDfh3p1okrD9wQw6jJ4d4DdlBPD5GqXE8bIeRJiK41Sh40LgvPw
+mkqEDSXK++CgBwYFK4EEACKhZANiAAScl43Ih2lWTDKrSox5ve5uiTXil4smsup3
+CfS1XPjKxgBAmlfBim8izbdrT0BFdQzz2joduNMtpt61wO4rGs6jm0UP7Kim9PC7
+Hneb/99fIYopdMH5NMnk60zGO1uZ2vc=
+-----END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_ecdsa_key384.pub b/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_ecdsa_key384.pub
new file mode 100644
index 0000000000..428d5fb7d7
--- /dev/null
+++ b/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_ecdsa_key384.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBJyXjciHaVZMMqtKjHm97m6JNeKXiyay6ncJ9LVc+MrGAECaV8GKbyLNt2tPQEV1DPPaOh240y2m3rXA7isazqObRQ/sqKb08Lsed5v/318hiil0wfk0yeTrTMY7W5na9w== uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_ecdsa_key521 b/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_ecdsa_key521
new file mode 100644
index 0000000000..3e51ec2ecd
--- /dev/null
+++ b/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_ecdsa_key521
@@ -0,0 +1,7 @@
+-----BEGIN EC PRIVATE KEY-----
+MIHcAgEBBEIB8O1BFkl2HQjQLRLonEZ97da/h39DMa9/0/hvPZWAI8gUPEQcHxRx
+U7b09p3Zh+EBbMFq8+1ae9ds+ZTxE4WFSvKgBwYFK4EEACOhgYkDgYYABAAlWVjq
+Bzg7Wt4gE6UNb1lRE2cnlmH2L/A5uo6qZRx5lPnSKOxEhxSb/Oay1+9d6KRdrh6/
+vlhd9SHDBhLcAPDvWgBnJIEj92Q3pXX4JtoitL0yl+SvvU+vUh966mzHShHzj8p5
+ccOgPkPNoA70yrpGzkIhPezpZOQdCaOXj/jFqNCTDg==
+-----END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_ecdsa_key521.pub b/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_ecdsa_key521.pub
new file mode 100644
index 0000000000..017a29f4da
--- /dev/null
+++ b/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_ecdsa_key521.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAAlWVjqBzg7Wt4gE6UNb1lRE2cnlmH2L/A5uo6qZRx5lPnSKOxEhxSb/Oay1+9d6KRdrh6/vlhd9SHDBhLcAPDvWgBnJIEj92Q3pXX4JtoitL0yl+SvvU+vUh966mzHShHzj8p5ccOgPkPNoA70yrpGzkIhPezpZOQdCaOXj/jFqNCTDg== uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_rsa_key b/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_rsa_key
new file mode 100644
index 0000000000..79968bdd7d
--- /dev/null
+++ b/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_rsa_key
@@ -0,0 +1,16 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8semM4q843337
+zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RWRWzjaxSB
+6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4QIDAQAB
+AoGANmvJzJO5hkLuvyDZHKfAnGTtpifcR1wtSa9DjdKUyn8vhKF0mIimnbnYQEmW
+NUUb3gXCZLi9PvkpRSVRrASDOZwcjoU/Kvww163vBUVb2cOZfFhyn6o2Sk88Tt++
+udH3hdjpf9i7jTtUkUe+QYPsia+wgvvrmn4QrahLAH86+kECQQDx5gFeXTME3cnW
+WMpFz3PPumduzjqgqMMWEccX4FtQkMX/gyGa5UC7OHFyh0N/gSWvPbRHa8A6YgIt
+n8DO+fh5AkEAzbqX4DOn8NY6xJIi42q7l/2jIA0RkB6P7YugW5NblhqBZ0XDnpA5
+sMt+rz+K07u9XZtxgh1xi7mNfwY6lEAMqQJBAJBEauCKmRj35Z6OyeQku59SPsnY
++SJEREVvSNw2lH9SOKQQ4wPsYlTGbvKtNVZgAcen91L5MmYfeckYE/fdIZECQQCt
+64zxsTnM1I8iFxj/gP/OYlJBikrKt8udWmjaghzvLMEw+T2DExJyb9ZNeT53+UMB
+m6O+B/4xzU/djvp+0hbhAkAemIt+rA5kTmYlFndhpvzkSSM8a2EXsO4XIPgGWCTT
+tQKS/tTly0ADMjN/TVy11+9d6zcqadNVuHXHGtR4W0GR
+-----END RSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_rsa_key.pub b/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_rsa_key.pub
new file mode 100644
index 0000000000..75d2025c71
--- /dev/null
+++ b/lib/ssh/test/ssh_dbg_SUITE_data/ssh_host_rsa_key.pub
@@ -0,0 +1,5 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+AAAAB3NzaC1yc2EAAAADAQABAAAAgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8
+semM4q843337zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RW
+RWzjaxSB6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4Q==
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/ssh/test/ssh_echo_server.erl b/lib/ssh/test/ssh_echo_server.erl
index 5387d21efd..e039439f87 100644
--- a/lib/ssh/test/ssh_echo_server.erl
+++ b/lib/ssh/test/ssh_echo_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@
%%% Description: Example ssh server
-module(ssh_echo_server).
--behaviour(ssh_daemon_channel).
+-behaviour(ssh_server_channel).
-record(state, {
n,
id,
diff --git a/lib/ssh/test/ssh_engine_SUITE.erl b/lib/ssh/test/ssh_engine_SUITE.erl
index c131a70973..3adb23acdb 100644
--- a/lib/ssh/test/ssh_engine_SUITE.erl
+++ b/lib/ssh/test/ssh_engine_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -126,10 +126,17 @@ simple_connect(Config) ->
load_engine() ->
case crypto:get_test_engine() of
{ok, Engine} ->
- try crypto:engine_load(<<"dynamic">>,
+ try
+ %% The test engine has it's own fake rsa sign/verify that
+ %% you don't want to use, so exclude it from methods to load:
+ Methods =
+ crypto:engine_get_all_methods() -- [engine_method_rsa],
+ crypto:engine_load(<<"dynamic">>,
[{<<"SO_PATH">>, Engine},
<<"LOAD">>],
- [])
+ [],
+ Methods
+ )
catch
error:notsup ->
{error, notsup}
diff --git a/lib/ssh/test/ssh_options_SUITE.erl b/lib/ssh/test/ssh_options_SUITE.erl
index 12a85c40aa..bf90f74324 100644
--- a/lib/ssh/test/ssh_options_SUITE.erl
+++ b/lib/ssh/test/ssh_options_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -49,7 +49,7 @@
server_userpassword_option/1,
server_pwdfun_option/1,
server_pwdfun_4_option/1,
- server_pwdfun_4_option_repeat/1,
+ server_keyboard_interactive/1,
ssh_connect_arg4_timeout/1,
ssh_connect_negtimeout_parallel/1,
ssh_connect_negtimeout_sequential/1,
@@ -99,7 +99,7 @@ all() ->
server_userpassword_option,
server_pwdfun_option,
server_pwdfun_4_option,
- server_pwdfun_4_option_repeat,
+ server_keyboard_interactive,
{group, dir_options},
ssh_connect_timeout,
ssh_connect_arg4_timeout,
@@ -214,7 +214,7 @@ init_per_testcase(_TestCase, Config) ->
file:make_dir(UserDir),
[{user_dir,UserDir}|Config].
-end_per_testcase(_TestCase, Config) ->
+end_per_testcase(_TestCase, _Config) ->
ssh:stop(),
ok.
@@ -381,7 +381,7 @@ server_pwdfun_4_option(Config) ->
%%--------------------------------------------------------------------
-server_pwdfun_4_option_repeat(Config) ->
+server_keyboard_interactive(Config) ->
UserDir = proplists:get_value(user_dir, Config),
SysDir = proplists:get_value(data_dir, Config),
%% Test that the state works
@@ -396,19 +396,28 @@ server_pwdfun_4_option_repeat(Config) ->
{pwdfun,PWDFUN}]),
%% Try with passwords "incorrect", "Bad again" and finally "bar"
- KIFFUN = fun(_,_,_) ->
+ KIFFUN = fun(_Name, _Instr, _PromptInfos) ->
K={k,self()},
- case get(K) of
- undefined ->
- put(K,1),
- ["incorrect"];
- 2 ->
- put(K,3),
- ["bar"];
- S->
- put(K,S+1),
- ["Bad again"]
- end
+ Answer =
+ case get(K) of
+ undefined ->
+ put(K,1),
+ ["incorrect"];
+ 2 ->
+ put(K,3),
+ ["bar"];
+ S->
+ put(K,S+1),
+ ["Bad again"]
+ end,
+ ct:log("keyboard_interact_fun:~n"
+ " Name = ~p~n"
+ " Instruction = ~p~n"
+ " Prompts = ~p~n"
+ "~nAnswer:~n ~p~n",
+ [_Name, _Instr, _PromptInfos, Answer]),
+
+ Answer
end,
ConnectionRef2 =
@@ -1227,7 +1236,7 @@ max_sessions(Config, ParallelLogin, Connect0) when is_function(Connect0,2) ->
[_|_] = Connections,
%% Now try one more than alowed:
- ct:log("Info Report might come here...",[]),
+ ct:pal("Info Report expected here (if not disabled) ...",[]),
try Connect(Host,Port)
of
_ConnectionRef1 ->
@@ -1235,8 +1244,7 @@ max_sessions(Config, ParallelLogin, Connect0) when is_function(Connect0,2) ->
{fail,"Too many connections accepted"}
catch
error:{badmatch,{error,"Connection closed"}} ->
- %% Step 2 ok: could not set up max_sessions+1 connections
- %% This is expected
+ ct:log("Step 2 ok: could not set up too many connections. Good.",[]),
%% Now stop one connection and try to open one more
ok = ssh:close(hd(Connections)),
try_to_connect(Connect, Host, Port, Pid)
@@ -1249,16 +1257,15 @@ max_sessions(Config, ParallelLogin, Connect0) when is_function(Connect0,2) ->
try_to_connect(Connect, Host, Port, Pid) ->
- {ok,Tref} = timer:send_after(3000, timeout_no_connection), % give the supervisors some time...
+ {ok,Tref} = timer:send_after(30000, timeout_no_connection), % give the supervisors some time...
try_to_connect(Connect, Host, Port, Pid, Tref, 1). % will take max 3300 ms after 11 tries
try_to_connect(Connect, Host, Port, Pid, Tref, N) ->
try Connect(Host,Port)
of
_ConnectionRef1 ->
- %% Step 3 ok: could set up one more connection after killing one
- %% Thats good.
timer:cancel(Tref),
+ ct:log("Step 3 ok: could set up one more connection after killing one. Thats good.",[]),
ssh:stop_daemon(Pid),
receive % flush.
timeout_no_connection -> ok
diff --git a/lib/ssh/test/ssh_peername_sockname_server.erl b/lib/ssh/test/ssh_peername_sockname_server.erl
index 8731d80f62..1cc53edf6d 100644
--- a/lib/ssh/test/ssh_peername_sockname_server.erl
+++ b/lib/ssh/test/ssh_peername_sockname_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,7 +26,7 @@
%% ssh connection.
--behaviour(ssh_daemon_channel).
+-behaviour(ssh_server_channel).
-record(state, {}).
-export([init/1, handle_msg/2, handle_ssh_msg/2, terminate/2]).
diff --git a/lib/ssh/test/ssh_property_test_SUITE.erl b/lib/ssh/test/ssh_property_test_SUITE.erl
index 3318b86d39..9aaac898a0 100644
--- a/lib/ssh/test/ssh_property_test_SUITE.erl
+++ b/lib/ssh/test/ssh_property_test_SUITE.erl
@@ -46,8 +46,9 @@ groups() ->
[{messages, [], [decode,
decode_encode]},
{client_server, [], [client_server_sequential,
- client_server_parallel,
- client_server_parallel_multi]}
+ client_server_parallel
+ %% client_server_parallel_multi
+ ]}
].
@@ -62,7 +63,7 @@ end_per_suite(Config) ->
%%% if we run proper.
init_per_group(client_server, Config) ->
case proplists:get_value(property_test_tool,Config) of
- eqc -> Config;
+ proper -> Config;
X -> {skip, lists:concat([X," is not supported"])}
end;
init_per_group(_, Config) ->
diff --git a/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_dsa_key
new file mode 100644
index 0000000000..51ab6fbd88
--- /dev/null
+++ b/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_dsa_key
@@ -0,0 +1,13 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBuwIBAAKBgQCClaHzE2ul0gKSUxah5W0W8UiJLy4hXngKEqpaUq9SSdVdY2LK
+wVfKH1gt5iuaf1FfzOhsIC9G/GLnjYttXZc92cv/Gfe3gR+s0ni2++MX+T++mE/Q
+diltXv/Hp27PybS67SmiFW7I+RWnT2OKlMPtw2oUuKeztCe5UWjaj/y5FQIVAPLA
+l9RpiU30Z87NRAHY3NTRaqtrAoGANMRxw8UfdtNVR0CrQj3AgPaXOGE4d+G4Gp4X
+skvnCHycSVAjtYxebUkzUzt5Q6f/IabuLUdge3gXrc8BetvrcKbp+XZgM0/Vj2CF
+Ymmy3in6kzGZq7Fw1sZaku6AOU8vLa5woBT2vAcHLLT1bLAzj7viL048T6MfjrOP
+ef8nHvACgYBhDWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah
+/XcF3DeRF+eEoz48wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+U
+ykSTXYUbtsfTNRFQGBW2/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0CgIVAN4wtL5W
+Lv62jKcdskxNyz2NQoBx
+-----END DSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_dsa_key.pub
new file mode 100644
index 0000000000..4dbb1305b0
--- /dev/null
+++ b/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_dsa_key.pub
@@ -0,0 +1,11 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+AAAAB3NzaC1kc3MAAACBAIKVofMTa6XSApJTFqHlbRbxSIkvLiFeeAoSqlpSr1JJ1V1j
+YsrBV8ofWC3mK5p/UV/M6GwgL0b8YueNi21dlz3Zy/8Z97eBH6zSeLb74xf5P76YT9B2
+KW1e/8enbs/JtLrtKaIVbsj5FadPY4qUw+3DahS4p7O0J7lRaNqP/LkVAAAAFQDywJfU
+aYlN9GfOzUQB2NzU0WqrawAAAIA0xHHDxR9201VHQKtCPcCA9pc4YTh34bganheyS+cI
+fJxJUCO1jF5tSTNTO3lDp/8hpu4tR2B7eBetzwF62+twpun5dmAzT9WPYIViabLeKfqT
+MZmrsXDWxlqS7oA5Ty8trnCgFPa8BwcstPVssDOPu+IvTjxPox+Os495/yce8AAAAIBh
+DWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah/XcF3DeRF+eEoz48
+wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+UykSTXYUbtsfTNRFQGBW2
+/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0Cg==
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_ecdsa_key b/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_ecdsa_key
new file mode 100644
index 0000000000..2979ea88ed
--- /dev/null
+++ b/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_ecdsa_key
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIMe4MDoit0t8RzSVPwkCBemQ9fhXL+xnTSAWISw8HNCioAoGCCqGSM49
+AwEHoUQDQgAEo2q7U3P6r0W5WGOLtM78UQtofM9UalEhiZeDdiyylsR/RR17Op0s
+VPGSADLmzzgcucLEKy17j2S+oz42VUJy5A==
+-----END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_ecdsa_key.pub b/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_ecdsa_key.pub
new file mode 100644
index 0000000000..85dc419345
--- /dev/null
+++ b/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_ecdsa_key.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKNqu1Nz+q9FuVhji7TO/FELaHzPVGpRIYmXg3YsspbEf0UdezqdLFTxkgAy5s84HLnCxCste49kvqM+NlVCcuQ= uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_rsa_key b/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_rsa_key
new file mode 100644
index 0000000000..79968bdd7d
--- /dev/null
+++ b/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_rsa_key
@@ -0,0 +1,16 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8semM4q843337
+zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RWRWzjaxSB
+6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4QIDAQAB
+AoGANmvJzJO5hkLuvyDZHKfAnGTtpifcR1wtSa9DjdKUyn8vhKF0mIimnbnYQEmW
+NUUb3gXCZLi9PvkpRSVRrASDOZwcjoU/Kvww163vBUVb2cOZfFhyn6o2Sk88Tt++
+udH3hdjpf9i7jTtUkUe+QYPsia+wgvvrmn4QrahLAH86+kECQQDx5gFeXTME3cnW
+WMpFz3PPumduzjqgqMMWEccX4FtQkMX/gyGa5UC7OHFyh0N/gSWvPbRHa8A6YgIt
+n8DO+fh5AkEAzbqX4DOn8NY6xJIi42q7l/2jIA0RkB6P7YugW5NblhqBZ0XDnpA5
+sMt+rz+K07u9XZtxgh1xi7mNfwY6lEAMqQJBAJBEauCKmRj35Z6OyeQku59SPsnY
++SJEREVvSNw2lH9SOKQQ4wPsYlTGbvKtNVZgAcen91L5MmYfeckYE/fdIZECQQCt
+64zxsTnM1I8iFxj/gP/OYlJBikrKt8udWmjaghzvLMEw+T2DExJyb9ZNeT53+UMB
+m6O+B/4xzU/djvp+0hbhAkAemIt+rA5kTmYlFndhpvzkSSM8a2EXsO4XIPgGWCTT
+tQKS/tTly0ADMjN/TVy11+9d6zcqadNVuHXHGtR4W0GR
+-----END RSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_rsa_key.pub b/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_rsa_key.pub
new file mode 100644
index 0000000000..75d2025c71
--- /dev/null
+++ b/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_rsa_key.pub
@@ -0,0 +1,5 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+AAAAB3NzaC1yc2EAAAADAQABAAAAgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8
+semM4q843337zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RW
+RWzjaxSB6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4Q==
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl
index 3e3e151781..b12ddfeef6 100644
--- a/lib/ssh/test/ssh_protocol_SUITE.erl
+++ b/lib/ssh/test/ssh_protocol_SUITE.erl
@@ -38,7 +38,11 @@
-define(EXTRA_KEX, 'diffie-hellman-group1-sha1').
-define(CIPHERS, ['aes256-ctr','aes192-ctr','aes128-ctr','aes128-cbc','3des-cbc']).
--define(DEFAULT_CIPHERS, [{client2server,?CIPHERS}, {server2client,?CIPHERS}]).
+-define(DEFAULT_CIPHERS, (fun() -> Ciphs = filter_supported(cipher, ?CIPHERS),
+ [{client2server,Ciphs}, {server2client,Ciphs}]
+ end)()
+ ).
+
-define(v(Key, Config), proplists:get_value(Key, Config)).
-define(v(Key, Config, Default), proplists:get_value(Key, Config, Default)).
diff --git a/lib/ssh/test/ssh_renegotiate_SUITE.erl b/lib/ssh/test/ssh_renegotiate_SUITE.erl
deleted file mode 100644
index 74bbc291b2..0000000000
--- a/lib/ssh/test/ssh_renegotiate_SUITE.erl
+++ /dev/null
@@ -1,237 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
--module(ssh_renegotiate_SUITE).
-
--include_lib("common_test/include/ct.hrl").
--include("ssh_test_lib.hrl").
-
-%% Note: This directive should only be used in test suites.
--compile(export_all).
-
--define(REKEY_DATA_TMO, 65000).
-%%--------------------------------------------------------------------
-%% Common Test interface functions -----------------------------------
-%%--------------------------------------------------------------------
-
-suite() -> [{ct_hooks,[ts_install_cth]},
- {timetrap,{seconds,40}}].
-
-all() -> [{group,default_algs},
- {group,aes_gcm}
- ].
-
-groups() -> [{default_algs, [], tests()},
- {aes_gcm, [], tests()}
- ].
-
-tests() -> [rekey, rekey_limit, renegotiate1, renegotiate2].
-
-%%--------------------------------------------------------------------
-init_per_suite(Config) ->
- ?CHECK_CRYPTO(Config).
-
-end_per_suite(_Config) ->
- ssh:stop().
-
-%%--------------------------------------------------------------------
-init_per_group(aes_gcm, Config) ->
- case lists:member({client2server,['[email protected]']},
- ssh_transport:supported_algorithms(cipher)) of
- true ->
- [{preferred_algorithms, [{cipher,[{client2server,['[email protected]']},
- {server2client,['[email protected]']}]}]}
- | Config];
- false ->
- {skip, "aes_gcm not supported"}
- end;
-init_per_group(_, Config) ->
- [{preferred_algorithms, ssh:default_algorithms()} | Config].
-
-
-end_per_group(_, Config) ->
- Config.
-
-%%--------------------------------------------------------------------
-init_per_testcase(_TestCase, Config) ->
- ssh:start(),
- Config.
-
-end_per_testcase(_TestCase, _Config) ->
- ssh:stop(),
- ok.
-
-%%--------------------------------------------------------------------
-%% Test Cases --------------------------------------------------------
-%%--------------------------------------------------------------------
-
-%%% Idle timeout test
-rekey() -> [{timetrap,{seconds,90}}].
-
-rekey(Config) ->
- {Pid, Host, Port} =
- ssh_test_lib:std_daemon(Config,
- [{rekey_limit, 0}]),
- ConnectionRef =
- ssh_test_lib:std_connect(Config, Host, Port,
- [{rekey_limit, 0}]),
- Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
- receive
- after ?REKEY_DATA_TMO ->
- %%By this time rekeying would have been done
- Kex2 = ssh_test_lib:get_kex_init(ConnectionRef),
- false = (Kex2 == Kex1),
- ssh:close(ConnectionRef),
- ssh:stop_daemon(Pid)
- end.
-
-%%--------------------------------------------------------------------
-
-%%% Test rekeying by data volume
-
-rekey_limit() -> [{timetrap,{seconds,400}}].
-
-rekey_limit(Config) ->
- UserDir = proplists:get_value(priv_dir, Config),
- DataFile = filename:join(UserDir, "rekey.data"),
-
- Algs = proplists:get_value(preferred_algorithms, Config),
- {Pid, Host, Port} = ssh_test_lib:std_daemon(Config,[{max_random_length_padding,0},
- {preferred_algorithms,Algs}]),
-
- ConnectionRef = ssh_test_lib:std_connect(Config, Host, Port, [{rekey_limit, 6000},
- {max_random_length_padding,0}]),
- {ok, SftpPid} = ssh_sftp:start_channel(ConnectionRef),
-
- Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
-
- timer:sleep(?REKEY_DATA_TMO),
- Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
-
- Data = lists:duplicate(159000,1),
- ok = ssh_sftp:write_file(SftpPid, DataFile, Data),
-
- timer:sleep(?REKEY_DATA_TMO),
- Kex2 = ssh_test_lib:get_kex_init(ConnectionRef),
-
- false = (Kex2 == Kex1),
-
- timer:sleep(?REKEY_DATA_TMO),
- Kex2 = ssh_test_lib:get_kex_init(ConnectionRef),
-
- ok = ssh_sftp:write_file(SftpPid, DataFile, "hi\n"),
-
- timer:sleep(?REKEY_DATA_TMO),
- Kex2 = ssh_test_lib:get_kex_init(ConnectionRef),
-
- false = (Kex2 == Kex1),
-
- timer:sleep(?REKEY_DATA_TMO),
- Kex2 = ssh_test_lib:get_kex_init(ConnectionRef),
-
- ssh_sftp:stop_channel(SftpPid),
- ssh:close(ConnectionRef),
- ssh:stop_daemon(Pid).
-
-%%--------------------------------------------------------------------
-
-%%% Test rekeying with simulataneous send request
-
-renegotiate1(Config) ->
- UserDir = proplists:get_value(priv_dir, Config),
- DataFile = filename:join(UserDir, "renegotiate1.data"),
-
- Algs = proplists:get_value(preferred_algorithms, Config),
- {Pid, Host, DPort} = ssh_test_lib:std_daemon(Config,[{max_random_length_padding,0},
- {preferred_algorithms,Algs}]),
-
- RPort = ssh_test_lib:inet_port(),
- {ok,RelayPid} = ssh_relay:start_link({0,0,0,0}, RPort, Host, DPort),
-
-
- ConnectionRef = ssh_test_lib:std_connect(Config, Host, RPort, [{max_random_length_padding,0}]),
- {ok, SftpPid} = ssh_sftp:start_channel(ConnectionRef),
-
- Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
-
- {ok, Handle} = ssh_sftp:open(SftpPid, DataFile, [write]),
-
- ok = ssh_sftp:write(SftpPid, Handle, "hi\n"),
-
- ssh_relay:hold(RelayPid, rx, 20, 1000),
- ssh_connection_handler:renegotiate(ConnectionRef),
- spawn(fun() -> ok=ssh_sftp:write(SftpPid, Handle, "another hi\n") end),
-
- timer:sleep(2000),
-
- Kex2 = ssh_test_lib:get_kex_init(ConnectionRef),
-
- false = (Kex2 == Kex1),
-
- ssh_relay:stop(RelayPid),
- ssh_sftp:stop_channel(SftpPid),
- ssh:close(ConnectionRef),
- ssh:stop_daemon(Pid).
-
-%%--------------------------------------------------------------------
-
-%%% Test rekeying with inflight messages from peer
-
-renegotiate2(Config) ->
- UserDir = proplists:get_value(priv_dir, Config),
- DataFile = filename:join(UserDir, "renegotiate2.data"),
-
- Algs = proplists:get_value(preferred_algorithms, Config),
- {Pid, Host, DPort} = ssh_test_lib:std_daemon(Config,[{max_random_length_padding,0},
- {preferred_algorithms,Algs}]),
-
- RPort = ssh_test_lib:inet_port(),
- {ok,RelayPid} = ssh_relay:start_link({0,0,0,0}, RPort, Host, DPort),
-
- ConnectionRef = ssh_test_lib:std_connect(Config, Host, RPort, [{max_random_length_padding,0}]),
- {ok, SftpPid} = ssh_sftp:start_channel(ConnectionRef),
-
- Kex1 = ssh_test_lib:get_kex_init(ConnectionRef),
-
- {ok, Handle} = ssh_sftp:open(SftpPid, DataFile, [write]),
-
- ok = ssh_sftp:write(SftpPid, Handle, "hi\n"),
-
- ssh_relay:hold(RelayPid, rx, 20, infinity),
- spawn(fun() -> ok=ssh_sftp:write(SftpPid, Handle, "another hi\n") end),
- %% need a small pause here to ensure ssh_sftp:write is executed
- ct:sleep(10),
- ssh_connection_handler:renegotiate(ConnectionRef),
- ssh_relay:release(RelayPid, rx),
-
- timer:sleep(2000),
-
- Kex2 = ssh_test_lib:get_kex_init(ConnectionRef),
-
- false = (Kex2 == Kex1),
-
- ssh_relay:stop(RelayPid),
- ssh_sftp:stop_channel(SftpPid),
- ssh:close(ConnectionRef),
- ssh:stop_daemon(Pid).
-
-%%--------------------------------------------------------------------
-%% Internal functions ------------------------------------------------
-%%--------------------------------------------------------------------
diff --git a/lib/ssh/test/ssh_renegotiate_SUITE_data/id_dsa b/lib/ssh/test/ssh_renegotiate_SUITE_data/id_dsa
deleted file mode 100644
index d306f8b26e..0000000000
--- a/lib/ssh/test/ssh_renegotiate_SUITE_data/id_dsa
+++ /dev/null
@@ -1,13 +0,0 @@
------BEGIN DSA PRIVATE KEY-----
-MIIBvAIBAAKBgQDfi2flSTZZofwT4yQT0NikX/LGNT7UPeB/XEWe/xovEYCElfaQ
-APFixXvEgXwoojmZ5kiQRKzLM39wBP0jPERLbnZXfOOD0PDnw0haMh7dD7XKVMod
-/EigVgHf/qBdM2M8yz1s/rRF7n1UpLSypziKjkzCm7JoSQ2zbWIPdmBIXwIVAMgP
-kpr7Sq3O7sHdb8D601DRjoExAoGAMOQxDfB2Fd8ouz6G96f/UOzRMI/Kdv8kYYKW
-JIGY+pRYrLPyYzUeJznwZreOJgrczAX+luHnKFWJ2Dnk5CyeXk67Wsr7pJ/4MBMD
-OKeIS0S8qoSBN8+Krp79fgA+yS3IfqbkJLtLu4EBaCX4mKQIX4++k44d4U5lc8pt
-+9hlEI8CgYEAznKxx9kyC6bVo7LUYKaGhofRFt0SYFc5PVmT2VUGRs1R6+6DPD+e
-uEO6IhFct7JFSRbP9p0JD4Uk+3zlZF+XX6b2PsZkeV8f/02xlNGUSmEzCSiNg1AX
-Cy/WusYhul0MncWCHMcOZB5rIvU/aP5EJJtn3xrRaz6u0SThF6AnT34CFQC63czE
-ZU8w8Q+H7z0j+a+70x2iAw==
------END DSA PRIVATE KEY-----
-
diff --git a/lib/ssh/test/ssh_renegotiate_SUITE_data/id_rsa b/lib/ssh/test/ssh_renegotiate_SUITE_data/id_rsa
deleted file mode 100644
index 9d7e0dd5fb..0000000000
--- a/lib/ssh/test/ssh_renegotiate_SUITE_data/id_rsa
+++ /dev/null
@@ -1,15 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIICXAIBAAKBgQD1OET+3O/Bvj/dtjxDTXmj1oiJt4sIph5kGy0RfjoPrZfaS+CU
-DhakCmS6t2ivxWFgtpKWaoGMZMJqWj6F6ZsumyFl3FPBtujwY/35cgifrI9Ns4Tl
-zR1uuengNBmV+WRQ5cd9F2qS6Z8aDQihzt0r8JUqLcK+VQbrmNzboCCQQwIDAQAB
-AoGAPQEyqPTt8JUT7mRXuaacjFXiweAXhp9NEDpyi9eLOjtFe9lElZCrsUOkq47V
-TGUeRKEm9qSodfTbKPoqc8YaBJGJPhUaTAcha+7QcDdfHBvIsgxvU7ePVnlpXRp3
-CCUEMPhlnx6xBoTYP+fRU0e3+xJIPVyVCqX1jAdUMkzfRoECQQD6ux7B1QJAIWyK
-SGkbDUbBilNmzCFNgIpOP6PA+bwfi5d16diTpra5AX09keQABAo/KaP1PdV8Vg0p
-z4P3A7G3AkEA+l+AKG6m0kQTTBMJDqOdVPYwe+5GxunMaqmhokpEbuGsrZBl5Dvd
-WpcBjR7jmenrhKZRIuA+Fz5HPo/UQJPl1QJBAKxstDkeED8j/S2XoFhPKAJ+6t39
-sUVICVTIZQeXdmzHJXCcUSkw8+WEhakqw/3SyW0oaK2FSWQJFWJUZ+8eJj8CQEh3
-xeduB5kKnS9CvzdeghZqX6QvVosSdtlUmfUYW/BgH5PpHKTP8wTaeld3XldZTpMJ
-dKiMkUw2+XYROVUrubUCQD+Na1LhULlpn4ISEtIEfqpdlUhxDgO15Wg8USmsng+x
-ICliVOSQtwaZjm8kwaFt0W7XnpnDxbRs37vIEbIMWak=
------END RSA PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_sup_SUITE.erl b/lib/ssh/test/ssh_sup_SUITE.erl
index 1df55834b1..a0e3d809be 100644
--- a/lib/ssh/test/ssh_sup_SUITE.erl
+++ b/lib/ssh/test/ssh_sup_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -201,8 +201,6 @@ killed_acceptor_restarts(Config) ->
Port2 = ssh_test_lib:daemon_port(DaemonPid2),
true = (Port /= Port2),
- ct:log("~s",[lists:flatten(ssh_info:string())]),
-
{ok,[{AccPid,ListenAddr,Port}]} = acceptor_pid(DaemonPid),
{ok,[{AccPid2,ListenAddr,Port2}]} = acceptor_pid(DaemonPid2),
@@ -216,23 +214,34 @@ killed_acceptor_restarts(Config) ->
{user_dir, UserDir}]),
[{client_version,_}] = ssh:connection_info(C1,[client_version]),
+ ct:log("~s",[lists:flatten(ssh_info:string())]),
+
%% Make acceptor restart:
exit(AccPid, kill),
?wait_match(undefined, process_info(AccPid)),
- %% Check it is a new acceptor:
+ %% Check it is a new acceptor and wait if it is not:
?wait_match({ok,[{AccPid1,ListenAddr,Port}]}, AccPid1=/=AccPid,
acceptor_pid(DaemonPid),
AccPid1,
500, 30),
- AccPid1 =/= AccPid2,
+
+ true = (AccPid1 =/= AccPid2),
%% Connect second client and check it is alive:
- {ok,C2} = ssh:connect("localhost", Port, [{silently_accept_hosts, true},
- {user_interaction, false},
- {user, ?USER},
- {password, ?PASSWD},
- {user_dir, UserDir}]),
+ C2 =
+ case ssh:connect("localhost", Port, [{silently_accept_hosts, true},
+ {user_interaction, false},
+ {user, ?USER},
+ {password, ?PASSWD},
+ {user_dir, UserDir}]) of
+ {ok,_C2} ->
+ _C2;
+ _Other ->
+ ct:log("new connect failed: ~p~n~n~s",[_Other,lists:flatten(ssh_info:string())]),
+ ct:fail("Re-connect failed!", [])
+ end,
+
[{client_version,_}] = ssh:connection_info(C2,[client_version]),
ct:log("~s",[lists:flatten(ssh_info:string())]),
@@ -247,8 +256,8 @@ killed_acceptor_restarts(Config) ->
ok = ssh:stop_daemon(DaemonPid),
?wait_match(undefined, process_info(DaemonPid), 1000, 30),
- {error,closed} = ssh:connection_info(C1,[client_version]),
- {error,closed} = ssh:connection_info(C2,[client_version]).
+ ?wait_match({error,closed}, ssh:connection_info(C1,[client_version]), 1000, 5),
+ ?wait_match({error,closed}, ssh:connection_info(C2,[client_version]), 1000, 5).
%%-------------------------------------------------------------------------
shell_channel_tree(Config) ->
@@ -281,7 +290,7 @@ shell_channel_tree(Config) ->
{ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity),
ok = ssh_connection:shell(ConnectionRef,ChannelId0),
- ?wait_match([{_, GroupPid,worker,[ssh_channel]}],
+ ?wait_match([{_, GroupPid,worker,[ssh_server_channel]}],
supervisor:which_children(ChannelSup),
[GroupPid]),
{links,GroupLinks} = erlang:process_info(GroupPid, links),
@@ -330,9 +339,9 @@ chk_empty_con_daemon(Daemon) ->
?wait_match([{{server,ssh_connection_sup, _,_},
ConnectionSup, supervisor,
[ssh_connection_sup]},
- {{server,ssh_channel_sup,_ ,_},
+ {{server,ssh_server_channel_sup,_ ,_},
ChannelSup,supervisor,
- [ssh_channel_sup]}],
+ [ssh_server_channel_sup]}],
supervisor:which_children(SubSysSup),
[ConnectionSup,ChannelSup]),
?wait_match([{{ssh_acceptor_sup,_,_,_},_,worker,[ssh_acceptor]}],
@@ -363,9 +372,9 @@ check_sshd_system_tree(Daemon, Config) ->
?wait_match([{{server,ssh_connection_sup, _,_},
ConnectionSup, supervisor,
[ssh_connection_sup]},
- {{server,ssh_channel_sup,_ ,_},
+ {{server,ssh_server_channel_sup,_ ,_},
ChannelSup,supervisor,
- [ssh_channel_sup]}],
+ [ssh_server_channel_sup]}],
supervisor:which_children(SubSysSup),
[ConnectionSup,ChannelSup]),
@@ -379,7 +388,7 @@ check_sshd_system_tree(Daemon, Config) ->
ssh_sftp:start_channel(Client),
- ?wait_match([{_, _,worker,[ssh_channel]}],
+ ?wait_match([{_, _,worker,[ssh_server_channel]}],
supervisor:which_children(ChannelSup)),
ssh:close(Client).
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl
index 57ae2dbac2..1129303414 100644
--- a/lib/ssh/test/ssh_test_lib.erl
+++ b/lib/ssh/test/ssh_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -408,6 +408,21 @@ ct:log("DataDir ~p:~n ~p~n~nSystDir ~p:~n ~p~n~nUserDir ~p:~n ~p",[DataDir, file
setup_ecdsa_known_host(Size, System, UserDir),
setup_ecdsa_auth_keys(Size, DataDir, UserDir).
+setup_eddsa(Alg, DataDir, UserDir) ->
+ {IdPriv, _IdPub, HostPriv, HostPub} =
+ case Alg of
+ ed25519 -> {"id_ed25519", "id_ed25519.pub", "ssh_host_ed25519_key", "ssh_host_ed25519_key.pub"};
+ ed448 -> {"id_ed448", "id_ed448.pub", "ssh_host_ed448_key", "ssh_host_ed448_key.pub"}
+ end,
+ file:copy(filename:join(DataDir, IdPriv), filename:join(UserDir, IdPriv)),
+ System = filename:join(UserDir, "system"),
+ file:make_dir(System),
+ file:copy(filename:join(DataDir, HostPriv), filename:join(System, HostPriv)),
+ file:copy(filename:join(DataDir, HostPub), filename:join(System, HostPub)),
+ct:log("DataDir ~p:~n ~p~n~nSystDir ~p:~n ~p~n~nUserDir ~p:~n ~p",[DataDir, file:list_dir(DataDir), System, file:list_dir(System), UserDir, file:list_dir(UserDir)]),
+ setup_eddsa_known_host(HostPub, DataDir, UserDir),
+ setup_eddsa_auth_keys(IdPriv, DataDir, UserDir).
+
clean_dsa(UserDir) ->
del_dirs(filename:join(UserDir, "system")),
file:delete(filename:join(UserDir,"id_dsa")),
@@ -487,6 +502,11 @@ setup_ecdsa_known_host(_Size, SystemDir, UserDir) ->
[{Key, _}] = public_key:ssh_decode(SshBin, public_key),
setup_known_hosts(Key, UserDir).
+setup_eddsa_known_host(HostPub, SystemDir, UserDir) ->
+ {ok, SshBin} = file:read_file(filename:join(SystemDir, HostPub)),
+ [{Key, _}] = public_key:ssh_decode(SshBin, public_key),
+ setup_known_hosts(Key, UserDir).
+
setup_known_hosts(Key, UserDir) ->
{ok, Hostname} = inet:gethostname(),
{ok, {A, B, C, D}} = inet:getaddr(Hostname, inet),
@@ -529,6 +549,11 @@ setup_ecdsa_auth_keys(Size, Dir, UserDir) ->
PKey = #'ECPoint'{point = Q},
setup_auth_keys([{ {PKey,Param}, [{comment, "Test"}]}], UserDir).
+setup_eddsa_auth_keys(IdPriv, Dir, UserDir) ->
+ {ok, Pem} = file:read_file(filename:join(Dir, IdPriv)),
+ {ed_pri, Alg, Pub, _} = public_key:pem_entry_decode(hd(public_key:pem_decode(Pem))),
+ setup_auth_keys([{{ed_pub,Alg,Pub}, [{comment, "Test"}]}], UserDir).
+
setup_auth_keys(Keys, Dir) ->
AuthKeys = public_key:ssh_encode(Keys, auth_keys),
AuthKeysFile = filename:join(Dir, "authorized_keys"),
@@ -926,7 +951,7 @@ get_kex_init(Conn, Ref, TRef) ->
end;
false ->
- ct:log("Not in 'connected' state: ~p",[State]),
+ ct:log("~p:~p Not in 'connected' state: ~p",[?MODULE,?LINE,State]),
receive
{reneg_timeout,Ref} ->
ct:log("S = ~p", [S]),
@@ -945,7 +970,7 @@ expected_state(_) -> false.
%%%----------------------------------------------------------------
%%% Return a string with N random characters
%%%
-random_chars(N) -> [crypto:rand_uniform($a,$z) || _<-lists:duplicate(N,x)].
+random_chars(N) -> [($a-1)+rand:uniform($z-$a) || _<-lists:duplicate(N,x)].
create_random_dir(Config) ->
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index 9df404d7ed..334281f53b 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_trpt_test_lib.erl b/lib/ssh/test/ssh_trpt_test_lib.erl
index 8de550af15..3f4df2c986 100644
--- a/lib/ssh/test/ssh_trpt_test_lib.erl
+++ b/lib/ssh/test/ssh_trpt_test_lib.erl
@@ -41,15 +41,20 @@
opts = [],
timeout = 5000, % ms
seen_hello = false,
- enc = <<>>,
ssh = #ssh{}, % #ssh{}
alg_neg = {undefined,undefined}, % {own_kexinit, peer_kexinit}
alg, % #alg{}
vars = dict:new(),
reply = [], % Some repy msgs are generated hidden in ssh_transport :[
prints = [],
- return_value
- }).
+ return_value,
+
+ %% Packet retrival and decryption
+ decrypted_data_buffer = <<>>,
+ encrypted_data_buffer = <<>>,
+ aead_data = <<>>,
+ undecrypted_packet_length
+ }).
-define(role(S), ((S#s.ssh)#ssh.role) ).
@@ -475,11 +480,11 @@ recv(S0 = #s{}) ->
%%%================================================================
try_find_crlf(Seen, S0) ->
- case erlang:decode_packet(line,S0#s.enc,[]) of
+ case erlang:decode_packet(line,S0#s.encrypted_data_buffer,[]) of
{more,_} ->
- Line = <<Seen/binary,(S0#s.enc)/binary>>,
+ Line = <<Seen/binary,(S0#s.encrypted_data_buffer)/binary>>,
S0#s{seen_hello = {more,Line},
- enc = <<>>, % didn't find a complete line
+ encrypted_data_buffer = <<>>, % didn't find a complete line
% -> no more characters to test
return_value = {more,Line}
};
@@ -490,13 +495,13 @@ try_find_crlf(Seen, S0) ->
S = opt(print_messages, S0,
fun(X) when X==true;X==detail -> {"Recv info~n~p~n",[Line]} end),
S#s{seen_hello = false,
- enc = Rest,
+ encrypted_data_buffer = Rest,
return_value = {info,Line}};
S1=#s{} ->
S = opt(print_messages, S1,
fun(X) when X==true;X==detail -> {"Recv hello~n~p~n",[Line]} end),
S#s{seen_hello = true,
- enc = Rest,
+ encrypted_data_buffer = Rest,
return_value = {hello,Line}}
end
end.
@@ -511,73 +516,58 @@ handle_hello(Bin, S=#s{ssh=C}) ->
{{Vp,Vs}, server} -> S#s{ssh = C#ssh{c_vsn=Vp, c_version=Vs}}
end.
-receive_binary_msg(S0=#s{ssh=C0=#ssh{decrypt_block_size = BlockSize,
- recv_mac_size = MacSize
- }
- }) ->
- case size(S0#s.enc) >= max(8,BlockSize) of
- false ->
- %% Need more bytes to decode the packet_length field
- Remaining = max(8,BlockSize) - size(S0#s.enc),
- receive_binary_msg( receive_wait(Remaining, S0) );
- true ->
- %% Has enough bytes to decode the packet_length field
- {_, <<?UINT32(PacketLen), _/binary>>, _} =
- ssh_transport:decrypt_blocks(S0#s.enc, BlockSize, C0), % FIXME: BlockSize should be at least 4
-
- %% FIXME: Check that ((4+PacketLen) rem BlockSize) == 0 ?
-
- S1 = if
- PacketLen > ?SSH_MAX_PACKET_SIZE ->
- fail({too_large_message,PacketLen},S0); % FIXME: disconnect
-
- ((4+PacketLen) rem BlockSize) =/= 0 ->
- fail(bad_packet_length_modulo, S0); % FIXME: disconnect
-
- size(S0#s.enc) >= (4 + PacketLen + MacSize) ->
- %% has the whole packet
- S0;
-
- true ->
- %% need more bytes to get have the whole packet
- Remaining = (4 + PacketLen + MacSize) - size(S0#s.enc),
- receive_wait(Remaining, S0)
- end,
-
- %% Decrypt all, including the packet_length part (re-use the initial #ssh{})
- {C1, SshPacket = <<?UINT32(_),?BYTE(PadLen),Tail/binary>>, EncRest} =
- ssh_transport:decrypt_blocks(S1#s.enc, PacketLen+4, C0),
-
- PayloadLen = PacketLen - 1 - PadLen,
- <<CompressedPayload:PayloadLen/binary, _Padding:PadLen/binary>> = Tail,
-
- {C2, Payload} = ssh_transport:decompress(C1, CompressedPayload),
-
- <<Mac:MacSize/binary, Rest/binary>> = EncRest,
-
- case {ssh_transport:is_valid_mac(Mac, SshPacket, C2),
- catch ssh_message:decode(set_prefix_if_trouble(Payload,S1))}
- of
- {false, _} -> fail(bad_mac,S1);
- {_, {'EXIT',_}} -> fail(decode_failed,S1);
-
- {true, Msg} ->
- C3 = case Msg of
- #ssh_msg_kexinit{} ->
- ssh_transport:key_init(opposite_role(C2), C2, Payload);
- _ ->
- C2
+receive_binary_msg(S0=#s{}) ->
+ case ssh_transport:handle_packet_part(
+ S0#s.decrypted_data_buffer,
+ S0#s.encrypted_data_buffer,
+ S0#s.aead_data,
+ S0#s.undecrypted_packet_length,
+ S0#s.ssh)
+ of
+ {packet_decrypted, DecryptedBytes, EncryptedDataRest, Ssh1} ->
+ S1 = S0#s{ssh = Ssh1#ssh{recv_sequence = ssh_transport:next_seqnum(Ssh1#ssh.recv_sequence)},
+ decrypted_data_buffer = <<>>,
+ undecrypted_packet_length = undefined,
+ aead_data = <<>>,
+ encrypted_data_buffer = EncryptedDataRest},
+ case
+ catch ssh_message:decode(set_prefix_if_trouble(DecryptedBytes,S1))
+ of
+ {'EXIT',_} -> fail(decode_failed,S1);
+
+ Msg ->
+ Ssh2 = case Msg of
+ #ssh_msg_kexinit{} ->
+ ssh_transport:key_init(opposite_role(Ssh1), Ssh1, DecryptedBytes);
+ _ ->
+ Ssh1
end,
- S2 = opt(print_messages, S1,
- fun(X) when X==true;X==detail -> {"Recv~n~s~n",[format_msg(Msg)]} end),
- S3 = opt(print_messages, S2,
- fun(detail) -> {"decrypted bytes ~p~n",[SshPacket]} end),
- S3#s{ssh = inc_recv_seq_num(C3),
- enc = Rest,
- return_value = Msg
- }
- end
- end.
+ S2 = opt(print_messages, S1,
+ fun(X) when X==true;X==detail -> {"Recv~n~s~n",[format_msg(Msg)]} end),
+ S3 = opt(print_messages, S2,
+ fun(detail) -> {"decrypted bytes ~p~n",[DecryptedBytes]} end),
+ S3#s{ssh = inc_recv_seq_num(Ssh2),
+ return_value = Msg
+ }
+ end;
+
+ {get_more, DecryptedBytes, EncryptedDataRest, AeadData, TotalNeeded, Ssh1} ->
+ %% Here we know that there are not enough bytes in
+ %% EncryptedDataRest to use. We must wait for more.
+ Remaining = case TotalNeeded of
+ undefined -> 8;
+ _ -> TotalNeeded - size(DecryptedBytes) - size(EncryptedDataRest)
+ end,
+ receive_binary_msg(
+ receive_wait(Remaining,
+ S0#s{encrypted_data_buffer = EncryptedDataRest,
+ decrypted_data_buffer = DecryptedBytes,
+ undecrypted_packet_length = TotalNeeded,
+ aead_data = AeadData,
+ ssh = Ssh1}
+ ))
+ end.
+
set_prefix_if_trouble(Msg = <<?BYTE(Op),_/binary>>, #s{alg=#alg{kex=Kex}})
@@ -602,7 +592,7 @@ receive_poll(S=#s{socket=Sock}) ->
inet:setopts(Sock, [{active,once}]),
receive
{tcp,Sock,Data} ->
- receive_poll( S#s{enc = <<(S#s.enc)/binary,Data/binary>>} );
+ receive_poll( S#s{encrypted_data_buffer = <<(S#s.encrypted_data_buffer)/binary,Data/binary>>} );
{tcp_closed,Sock} ->
throw({tcp,tcp_closed});
{tcp_error, Sock, Reason} ->
@@ -616,7 +606,7 @@ receive_wait(S=#s{socket=Sock,
inet:setopts(Sock, [{active,once}]),
receive
{tcp,Sock,Data} ->
- S#s{enc = <<(S#s.enc)/binary,Data/binary>>};
+ S#s{encrypted_data_buffer = <<(S#s.encrypted_data_buffer)/binary,Data/binary>>};
{tcp_closed,Sock} ->
throw({tcp,tcp_closed});
{tcp_error, Sock, Reason} ->
@@ -627,11 +617,11 @@ receive_wait(S=#s{socket=Sock,
receive_wait(N, S=#s{socket=Sock,
timeout=Timeout,
- enc=Enc0}) when N>0 ->
+ encrypted_data_buffer=Enc0}) when N>0 ->
inet:setopts(Sock, [{active,once}]),
receive
{tcp,Sock,Data} ->
- receive_wait(N-size(Data), S#s{enc = <<Enc0/binary,Data/binary>>});
+ receive_wait(N-size(Data), S#s{encrypted_data_buffer = <<Enc0/binary,Data/binary>>});
{tcp_closed,Sock} ->
throw({tcp,tcp_closed});
{tcp_error, Sock, Reason} ->
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index 99c5cbd346..bb87dd388c 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,4 +1,4 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.6.6
+SSH_VSN = 4.7.7
APP_VSN = "ssh-$(SSH_VSN)"
diff --git a/lib/ssl/doc/specs/.gitignore b/lib/ssl/doc/specs/.gitignore
new file mode 100644
index 0000000000..322eebcb06
--- /dev/null
+++ b/lib/ssl/doc/specs/.gitignore
@@ -0,0 +1 @@
+specs_*.xml
diff --git a/lib/ssl/doc/src/Makefile b/lib/ssl/doc/src/Makefile
index f9128e8e45..064131944c 100644
--- a/lib/ssl/doc/src/Makefile
+++ b/lib/ssl/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2017. All Rights Reserved.
+# Copyright Ericsson AB 1999-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -47,6 +47,7 @@ XML_CHAPTER_FILES = \
ssl_protocol.xml \
using_ssl.xml \
ssl_distribution.xml \
+ standards_compliance.xml \
notes.xml
BOOK_FILES = book.xml
@@ -80,11 +81,16 @@ HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
+SPECS_FILES = $(XML_REF3_FILES:%.xml=$(SPECDIR)/specs_%.xml)
+
+TOP_SPECS_FILE = specs.xml
+
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
XML_FLAGS +=
DVIPS_FLAGS +=
+SPECS_FLAGS = -I../../../public_key/include -I../../../public_key/src -I../../..
# ----------------------------------------------------
# Targets
@@ -92,7 +98,7 @@ DVIPS_FLAGS +=
$(HTMLDIR)/%.gif: %.gif
$(INSTALL_DATA) $< $@
-docs: pdf html man
+docs: html pdf man
$(TOP_PDF_FILE): $(XML_FILES)
@@ -102,8 +108,10 @@ html: gifs $(HTML_REF_MAN_FILE)
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
+ rm -f $(SPECS_FILES)
rm -f errs core *~
man: $(MAN3_FILES) $(MAN6_FILES)
diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml
index 14ba12167a..5fdcf15b5f 100644
--- a/lib/ssl/doc/src/notes.xml
+++ b/lib/ssl/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1999</year><year>2017</year>
+ <year>1999</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -27,6 +27,794 @@
</header>
<p>This document describes the changes made to the SSL application.</p>
+<section><title>SSL 9.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The distribution handshake with TLS distribution
+ (<c>inet_tls_dist</c>) does now utilize the socket option
+ <c>{nodelay, true}</c>, which decreases the distribution
+ setup time significantly.</p>
+ <p>
+ Own Id: OTP-14792</p>
+ </item>
+ <item>
+ <p>
+ Correct shutdown reason to avoid an incorrect crash
+ report</p>
+ <p>
+ Own Id: OTP-15710 Aux Id: ERL-893 </p>
+ </item>
+ <item>
+ <p>
+ Enhance documentation and type specifications.</p>
+ <p>
+ Own Id: OTP-15746 Aux Id: ERIERL-333 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ TLS-1.0, TLS-1.1 and DTLS-1.0 are now considered legacy
+ and not supported by default</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14865</p>
+ </item>
+ <item>
+ <p>
+ Use new logger API in ssl. Introduce log levels and
+ verbose debug logging for SSL.</p>
+ <p>
+ Own Id: OTP-15055</p>
+ </item>
+ <item>
+ <p>
+ Add new API function str_to_suite/1, cipher_suites/3
+ (list cipher suites as rfc or OpenSSL name strings) and
+ suite_to_openssl_str/1</p>
+ <p>
+ Own Id: OTP-15483 Aux Id: ERL-924 </p>
+ </item>
+ <item>
+ <p>
+ Basic support for TLS 1.3 Server for experimental use.
+ The client is not yet functional, for more information
+ see the Standards Compliance chapter of the User's Guide.</p>
+ <p>
+ Own Id: OTP-15591</p>
+ </item>
+ <item>
+ <p>
+ Add support for PSK CCM ciphers from RFC 6655</p>
+ <p>
+ Own Id: OTP-15626</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 9.2.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Missing check of size of user_data_buffer made internal
+ socket behave as an active socket instead of active N.
+ This could cause memory problems.</p>
+ <p>
+ Own Id: OTP-15802 Aux Id: ERL-934 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Back port of bug fix ERL-893 from OTP-22 and document
+ enhancements that will solve dialyzer warnings for users
+ of the ssl application.</p>
+ <p>
+ This change also affects public_key, eldap (and inet
+ doc).</p>
+ <p>
+ Own Id: OTP-15785 Aux Id: ERL-929, ERL-893, PR-2215 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 9.2.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ With the default BEAST Mitigation strategy for TLS 1.0 an
+ empty TLS fragment could be sent after a one-byte
+ fragment. This glitch has been fixed.</p>
+ <p>
+ Own Id: OTP-15054 Aux Id: ERIERL-346 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 9.2.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The timeout for a passive receive was sometimes not
+ cancelled and later caused a server crash. This bug has
+ now been corrected.</p>
+ <p>
+ Own Id: OTP-14701 Aux Id: ERL-883, ERL-884 </p>
+ </item>
+ <item>
+ <p>
+ Add tag for passive message (active N) in cb_info to
+ retain transport transparency.</p>
+ <p>
+ Own Id: OTP-15679 Aux Id: ERL-861 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 9.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix bug that an incorrect return value for gen_statem
+ could be created when alert was a result of handling
+ renegotiation info extension</p>
+ <p>
+ Own Id: OTP-15502</p>
+ </item>
+ <item>
+ <p>
+ Correct check for 3des_ede_cbc, could cause ssl to claim
+ to support 3des_ede_cbc when cryptolib does not.</p>
+ <p>
+ Own Id: OTP-15539</p>
+ </item>
+ <item>
+ <p>
+ Improved DTLS error handling, avoids unexpected
+ connection failure in rare cases.</p>
+ <p>
+ Own Id: OTP-15561</p>
+ </item>
+ <item>
+ <p>
+ Corrected active once emulation bug that could cause the
+ ssl_closed meassage to not be sent. Bug introduced by
+ OTP-15449</p>
+ <p>
+ Own Id: OTP-15666 Aux Id: ERIERL-316, </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Add client option {reuse_session, SessionID::binary()}
+ that can be used together with new option value
+ {reuse_sessions, save}. This makes it possible to reuse a
+ session from a specific connection establishment.</p>
+ <p>
+ Own Id: OTP-15369</p>
+ </item>
+ <item>
+ <p>
+ The Reason part of of the error return from the functions
+ connect and handshake has a better and documented format.
+ This will sometimes differ from previous returned
+ reasons, however those where only documented as term()
+ and should for that reason not be relied on.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15423</p>
+ </item>
+ <item>
+ <p>
+ Refactor of state handling to improve TLS application
+ data throughput and reduce CPU overhead</p>
+ <p>
+ Own Id: OTP-15445</p>
+ </item>
+ <item>
+ <p>
+ The SSL code has been optimized in many small ways to
+ reduce CPU load for encryption/decryption, especially for
+ Erlang's distribution protocol over TLS.</p>
+ <p>
+ Own Id: OTP-15529</p>
+ </item>
+ <item>
+ <p>
+ Add support for active N</p>
+ <p>
+ Own Id: OTP-15665 Aux Id: ERL-811, PR-2072 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 9.1.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix encoding of the SRP extension length field in ssl.
+ The old encoding of the SRP extension length could cause
+ interoperability problems with third party SSL
+ implementations when SRP was used.</p>
+ <p>
+ Own Id: OTP-15477 Aux Id: ERL-790 </p>
+ </item>
+ <item>
+ <p>
+ Guarantee active once data delivery, handling TCP stream
+ properly.</p>
+ <p>
+ Own Id: OTP-15504 Aux Id: ERL-371 </p>
+ </item>
+ <item>
+ <p>
+ Correct gen_statem returns for some error cases</p>
+ <p>
+ Own Id: OTP-15505</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 9.1.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed renegotiation bug. Client did not handle server
+ initiated renegotiation correctly after rewrite to two
+ connection processes, due to ERL-622 commit
+ d87ac1c55188f5ba5cdf72384125d94d42118c18. This could
+ manifest it self as a " bad_record_mac" alert.</p>
+ <p>
+ Also included are some optimizations</p>
+ <p>
+ Own Id: OTP-15489 Aux Id: ERL-308 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 9.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ PEM cache was not evicting expired entries due to due to
+ timezone confusion.</p>
+ <p>
+ Own Id: OTP-15368</p>
+ </item>
+ <item>
+ <p>
+ Make sure an error is returned if a "transport_accept
+ socket" is used in some other call than ssl:handshake* or
+ ssl:controlling_process</p>
+ <p>
+ Own Id: OTP-15384 Aux Id: ERL-756 </p>
+ </item>
+ <item>
+ <p>
+ Fix timestamp handling in the PEM-cache could cause
+ entries to not be invalidated at the correct time.</p>
+ <p>
+ Own Id: OTP-15402</p>
+ </item>
+ <item>
+ <p>
+ Extend check for undelivered data at closing, could under
+ some circumstances fail to deliver all data that was
+ actually received.</p>
+ <p>
+ Own Id: OTP-15412 Aux Id: ERL-731 </p>
+ </item>
+ <item>
+ <p>
+ Correct signature check for TLS-1.2 that allows different
+ algorithms for signature of peer cert and peer cert key.
+ Not all allowed combinations where accepted.</p>
+ <p>
+ Own Id: OTP-15415 Aux Id: ERL-763 </p>
+ </item>
+ <item>
+ <p>
+ Correct gen_statem return value, could cause
+ renegotiation to fail.</p>
+ <p>
+ Own Id: OTP-15418 Aux Id: ERL-770 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Add engine support for RSA key exchange</p>
+ <p>
+ Own Id: OTP-15420 Aux Id: ERIERL-268 </p>
+ </item>
+ <item>
+ <p>
+ ssl now uses active n internally to boost performance.
+ Old active once behavior can be restored by setting
+ application variable see manual page for ssl application
+ (man 6).</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15449</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 9.0.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Correct alert handling with new TLS sender process, from
+ ssl-9.0.2. CLOSE ALERTS could under some circumstances be
+ encoded using an incorrect cipher state. This would cause
+ the peer to regard them as unknown messages.</p>
+ <p>
+ Own Id: OTP-15337 Aux Id: ERL-738 </p>
+ </item>
+ <item>
+ <p>
+ Correct handling of socket packet option with new TLS
+ sender process, from ssl-9.0.2. When changing the socket
+ option {packet, 1|2|3|4} with ssl:setopts/2 the option
+ must internally be propagated to the sender process as
+ well as the reader process as this particular option also
+ affects the data to be sent.</p>
+ <p>
+ Own Id: OTP-15348 Aux Id: ERL-747 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 9.0.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Use separate processes for sending and receiving
+ application data for TLS connections to avoid potential
+ deadlock that was most likely to occur when using TLS for
+ Erlang distribution. Note does not change the API.</p>
+ <p>
+ Own Id: OTP-15122</p>
+ </item>
+ <item>
+ <p>
+ Correct handling of empty server SNI extension</p>
+ <p>
+ Own Id: OTP-15168</p>
+ </item>
+ <item>
+ <p>
+ Correct PSK cipher suite handling and add
+ selected_cipher_suite to connection information</p>
+ <p>
+ Own Id: OTP-15172</p>
+ </item>
+ <item>
+ <p>
+ Adopt to the fact that cipher suite sign restriction are
+ relaxed in TLS-1.2</p>
+ <p>
+ Own Id: OTP-15173</p>
+ </item>
+ <item>
+ <p>
+ Enhance error handling of non existing PEM files</p>
+ <p>
+ Own Id: OTP-15174</p>
+ </item>
+ <item>
+ <p>
+ Correct close handling of transport accepted sockets in
+ the error state</p>
+ <p>
+ Own Id: OTP-15216</p>
+ </item>
+ <item>
+ <p>
+ Correct PEM cache to not add references to empty entries
+ when PEM file does not exist.</p>
+ <p>
+ Own Id: OTP-15224</p>
+ </item>
+ <item>
+ <p>
+ Correct handling of all PSK cipher suites</p>
+ <p>
+ Before only some PSK suites would be correctly negotiated
+ and most PSK ciphers suites would fail the connection.</p>
+ <p>
+ Own Id: OTP-15285</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ TLS will now try to order certificate chains if they
+ appear to be unordered. That is prior to TLS 1.3,
+ “certificate_list” ordering was required to be
+ strict, however some implementations already allowed for
+ some flexibility. For maximum compatibility, all
+ implementations SHOULD be prepared to handle potentially
+ extraneous certificates and arbitrary orderings from any
+ TLS version.</p>
+ <p>
+ Own Id: OTP-12983</p>
+ </item>
+ <item>
+ <p>
+ TLS will now try to reconstructed an incomplete
+ certificate chains from its local CA-database and use
+ that data for the certificate path validation. This
+ especially makes sense for partial chains as then the
+ peer might not send an intermediate CA as it is
+ considered the trusted root in that case.</p>
+ <p>
+ Own Id: OTP-15060</p>
+ </item>
+ <item>
+ <p>
+ Option keyfile defaults to certfile and should be trumped
+ with key. This failed for engine keys.</p>
+ <p>
+ Own Id: OTP-15193</p>
+ </item>
+ <item>
+ <p>
+ Error message improvement when own certificate has
+ decoding issues, see also issue ERL-668.</p>
+ <p>
+ Own Id: OTP-15234</p>
+ </item>
+ <item>
+ <p>
+ Correct dialyzer spec for key option</p>
+ <p>
+ Own Id: OTP-15281</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 9.0.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Correct cipher suite handling for ECDHE_*, the incorrect
+ handling could cause an incorrrect suite to be selected
+ and most likly fail the handshake.</p>
+ <p>
+ Own Id: OTP-15203</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 9.0</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Correct handling of ECDH suites.</p>
+ <p>
+ Own Id: OTP-14974</p>
+ </item>
+ <item>
+ <p>
+ Proper handling of clients that choose to send an empty
+ answer to a certificate request</p>
+ <p>
+ Own Id: OTP-15050</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Distribution over SSL (inet_tls) has, to improve
+ performance, been rewritten to not use intermediate
+ processes and ports.</p>
+ <p>
+ Own Id: OTP-14465</p>
+ </item>
+ <item>
+ <p>
+ Add suport for ECDHE_PSK cipher suites</p>
+ <p>
+ Own Id: OTP-14547</p>
+ </item>
+ <item>
+ <p>
+ For security reasons no longer support 3-DES cipher
+ suites by default</p>
+ <p>
+ *** INCOMPATIBILITY with possibly ***</p>
+ <p>
+ Own Id: OTP-14768</p>
+ </item>
+ <item>
+ <p>
+ For security reasons RSA-key exchange cipher suites are
+ no longer supported by default</p>
+ <p>
+ *** INCOMPATIBILITY with possible ***</p>
+ <p>
+ Own Id: OTP-14769</p>
+ </item>
+ <item>
+ <p>
+ The interoperability option to fallback to insecure
+ renegotiation now has to be explicitly turned on.</p>
+ <p>
+ *** INCOMPATIBILITY with possibly ***</p>
+ <p>
+ Own Id: OTP-14789</p>
+ </item>
+ <item>
+ <p>
+ Drop support for SSLv2 enabled clients. SSLv2 has been
+ broken for decades and never supported by the Erlang
+ SSL/TLS implementation. This option was by default
+ disabled and enabling it has proved to sometimes break
+ connections not using SSLv2 enabled clients.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14824</p>
+ </item>
+ <item>
+ <p>
+ Remove CHACHA20_POLY1305 ciphers form default for now. We
+ have discovered interoperability problems, ERL-538, that
+ we believe needs to be solved in crypto.</p>
+ <p>
+ *** INCOMPATIBILITY with possibly ***</p>
+ <p>
+ Own Id: OTP-14882</p>
+ </item>
+ <item>
+ <p>
+ Generalize DTLS packet multiplexing to make it easier to
+ add future DTLS features and uses.</p>
+ <p>
+ Own Id: OTP-14888</p>
+ </item>
+ <item>
+ <p>
+ Use uri_string module instead of http_uri.</p>
+ <p>
+ Own Id: OTP-14902</p>
+ </item>
+ <item>
+ <p>
+ The SSL distribution protocol <c>-proto inet_tls</c> has
+ stopped setting the SSL option
+ <c>server_name_indication</c>. New verify funs for client
+ and server in <c>inet_tls_dist</c> has been added, not
+ documented yet, that checks node name if present in peer
+ certificate. Usage is still also yet to be documented.</p>
+ <p>
+ Own Id: OTP-14969 Aux Id: OTP-14465, ERL-598 </p>
+ </item>
+ <item>
+ <p>
+ Deprecate ssl:ssl_accept/[1,2,3] in favour of
+ ssl:handshake/[1,2,3]</p>
+ <p>
+ Own Id: OTP-15056</p>
+ </item>
+ <item>
+ <p>
+ Customizes the hostname verification of the peer
+ certificate, as different protocols that use TLS such as
+ HTTP or LDAP may want to do it differently</p>
+ <p>
+ Own Id: OTP-15102 Aux Id: ERL-542, OTP-14962 </p>
+ </item>
+ <item>
+ <p>
+ Add utility function for converting erlang cipher suites
+ to a string represenation (ERL-600).</p>
+ <p>
+ Own Id: OTP-15106</p>
+ </item>
+ <item>
+ <p>
+ First version with support for DTLS</p>
+ <p>
+ Own Id: OTP-15142</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 8.2.6.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Add engine support for RSA key exchange</p>
+ <p>
+ Own Id: OTP-15420</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 8.2.6.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Extend check for undelivered data at closing, could under
+ some circumstances fail to deliverd all data that was
+ acctualy recivied.</p>
+ <p>
+ Own Id: OTP-15412</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 8.2.6.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Correct handling of empty server SNI extension</p>
+ <p>
+ Own Id: OTP-15168</p>
+ </item>
+ <item>
+ <p>
+ Correct cipher suite handling for ECDHE_*, the incorrect
+ handling could cause an incorrrect suite to be selected
+ and most likly fail the handshake.</p>
+ <p>
+ Own Id: OTP-15203</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 8.2.6.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improve cipher suite handling correcting ECC and TLS-1.2
+ requierments. Backport of solution for ERL-641</p>
+ <p>
+ Own Id: OTP-15178</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Option keyfile defaults to certfile and should be trumped
+ with key. This failed for engine keys.</p>
+ <p>
+ Own Id: OTP-15193</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 8.2.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Proper handling of clients that choose to send an empty
+ answer to a certificate request</p>
+ <p>
+ Own Id: OTP-15050</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 8.2.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix filter function to not incorrectly exclude AEAD
+ cipher suites</p>
+ <p>
+ Own Id: OTP-14981</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>SSL 8.2.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -64,13 +852,6 @@
</item>
<item>
<p>
- Fix alert handling so that unexpected messages are logged
- and alerted correctly</p>
- <p>
- Own Id: OTP-14929</p>
- </item>
- <item>
- <p>
Correct handling of anonymous cipher suites</p>
<p>
Own Id: OTP-14952</p>
@@ -171,7 +952,7 @@
<p>
TLS sessions must be registered with SNI if provided, so
that sessions where client hostname verification would
- fail can not connect reusing a session created when the
+ fail cannot connect reusing a session created when the
server name verification succeeded.</p>
<p>
Own Id: OTP-14632</p>
@@ -349,7 +1130,7 @@
public_key:pkix_verify_hostname/2 to verify the hostname
of the connection with the server certificates specified
hostname during certificate path validation. The user may
- explicitly disables it. Also if the hostname can not be
+ explicitly disables it. Also if the hostname cannot be
derived from the first argument to connect or is not
supplied by the server name indication option, the check
will not be performed.</p>
@@ -2780,5 +3561,3 @@
</section>
</section>
</chapter>
-
-
diff --git a/lib/ssl/doc/src/specs.xml b/lib/ssl/doc/src/specs.xml
new file mode 100644
index 0000000000..50e9428fec
--- /dev/null
+++ b/lib/ssl/doc/src/specs.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<specs xmlns:xi="http://www.w3.org/2001/XInclude">
+ <xi:include href="../specs/specs_ssl_crl_cache_api.xml"/>
+ <xi:include href="../specs/specs_ssl_crl_cache.xml"/>
+ <xi:include href="../specs/specs_ssl_session_cache_api.xml"/>
+ <xi:include href="../specs/specs_ssl.xml"/>
+</specs>
+
+
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index 3db5aa19ac..3aa6e09c2c 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1999</year><year>2017</year>
+ <year>1999</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -28,256 +28,375 @@
<rev></rev>
<file>ssl.xml</file>
</header>
- <module>ssl</module>
+ <module since="">ssl</module>
<modulesummary>Interface Functions for Secure Socket Layer</modulesummary>
<description>
<p>
- This module contains interface functions for the SSL/TLS protocol.
+ This module contains interface functions for the SSL/TLS/DTLS protocol.
For detailed information about the supported standards see
<seealso marker="ssl_app">ssl(6)</seealso>.
</p>
</description>
+
+ <!--
+ ================================================================
+ = Data types =
+ ================================================================
+ -->
+
+ <datatypes>
+ <datatype_title>Types used in SSL/TLS/DTLS</datatype_title>
+
- <section>
- <title>DATA TYPES</title>
- <p>The following data types are used in the functions for SSL:</p>
-
- <taglist>
-
- <tag><c>boolean() =</c></tag>
- <item><p><c>true | false</c></p></item>
-
- <tag><c>option() =</c></tag>
- <item><p><c>socketoption() | ssl_option() | transport_option()</c></p>
- </item>
-
- <tag><c>socketoption() =</c></tag>
- <item><p><c>proplists:property()</c></p>
- <p>The default socket options are
- <c>[{mode,list},{packet, 0},{header, 0},{active, true}]</c>.</p>
- <p>For valid options, see the
- <seealso marker="kernel:inet">inet(3)</seealso> and
- <seealso marker="kernel:gen_tcp">gen_tcp(3)</seealso> manual pages
- in Kernel.</p></item>
-
- <tag><marker id="type-ssloption"/><c>ssl_option() =</c></tag>
- <item>
- <p><c>{verify, verify_type()}</c></p>
- <p><c>| {verify_fun, {fun(), term()}}</c></p>
- <p><c>| {fail_if_no_peer_cert, boolean()}</c></p>
- <p><c>| {depth, integer()}</c></p>
- <p><c>| {cert, public_key:der_encoded()}</c></p>
- <p><c>| {certfile, path()}</c></p>
- <p><c>| {key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'ECPrivateKey'
- | 'PrivateKeyInfo', public_key:der_encoded()} |
- #{algorithm := rsa | dss | ecdsa,
- engine := crypto:engine_ref(), key_id := crypto:key_id(), password => crypto:password()}</c></p>
- <p><c>| {keyfile, path()}</c></p>
- <p><c>| {password, string()}</c></p>
- <p><c>| {cacerts, [public_key:der_encoded()]}</c></p>
- <p><c>| {cacertfile, path()}</c></p>
- <p><c>| {dh, public_key:der_encoded()}</c></p>
- <p><c>| {dhfile, path()}</c></p>
- <p><c>| {ciphers, ciphers()}</c></p>
- <p><c>| {user_lookup_fun, {fun(), term()}}, {psk_identity, string()},
- {srp_identity, {string(), string()}}</c></p>
- <p><c>| {reuse_sessions, boolean()}</c></p>
- <p><c>| {reuse_session, fun()} {next_protocols_advertised, [binary()]}</c></p>
- <p><c>| {client_preferred_next_protocols, {client | server,
- [binary()]} | {client | server, [binary()], binary()}}</c></p>
- <p><c>| {log_alert, boolean()}</c></p>
- <p><c>| {server_name_indication, hostname() | disable}</c></p>
- <p><c>| {sni_hosts, [{hostname(), [ssl_option()]}]}</c></p>
- <p><c>| {sni_fun, SNIfun::fun()}</c></p>
- </item>
+ <datatype>
+ <name name="socket"/>
+ </datatype>
+
+ <datatype>
+ <name name="sslsocket"/>
+ <desc>
+ <p>An opaque reference to the TLS/DTLS connection, may be used for equality matching.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="tls_option"/>
+ </datatype>
+
+ <datatype>
+ <name name="tls_client_option"/>
+ </datatype>
+
+ <datatype>
+ <name name="tls_server_option"/>
+ </datatype>
+
+
+ <datatype>
+ <name name="socket_option"/>
+ <desc>
+ <p>The default socket options are
+ <c>[{mode,list},{packet, 0},{header, 0},{active, true}]</c>.</p>
+ <p>For valid options, see the
+ <seealso marker="kernel:inet">inet(3)</seealso>,
+ <seealso marker="kernel:gen_tcp">gen_tcp(3)</seealso> and
+ <seealso marker="kernel:gen_tcp">gen_udp(3)</seealso>
+ manual pages in Kernel. Note that stream oriented options such as packet
+ are only relevant for SSL/TLS and not DTLS</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="active_msgs"/>
+ <desc>
+ <p>When a TLS/DTLS socket is in active mode (the default), data from the
+ socket is delivered to the owner of the socket in the form of
+ messages as described above.</p>
+ <p>The <c>ssl_passive</c> message is sent only when the socket is in
+ <c>{active, N}</c> mode and the counter dropped to 0. It indicates
+ that the socket has transitioned to passive (<c>{active, false}</c>) mode.</p>
+ </desc>
+ </datatype>
- <tag><c>transport_option() =</c></tag>
- <item><p><c>{cb_info, {CallbackModule::atom(), DataTag::atom(),
-
- ClosedTag::atom(), ErrTag:atom()}}</c></p>
- <p>Defaults to <c>{gen_tcp, tcp, tcp_closed, tcp_error}</c>. Can be used
- to customize the transport layer. The callback module must implement a
- reliable transport protocol, behave as <c>gen_tcp</c>, and have functions
- corresponding to <c>inet:setopts/2</c>, <c>inet:getopts/2</c>,
- <c>inet:peername/1</c>, <c>inet:sockname/1</c>, and <c>inet:port/1</c>.
- The callback <c>gen_tcp</c> is treated specially and calls <c>inet</c>
- directly.</p>
- <taglist>
- <tag><c>CallbackModule =</c></tag>
- <item><p><c>atom()</c></p></item>
- <tag><c>DataTag =</c></tag>
- <item><p><c>atom()</c></p>
- <p>Used in socket data message.</p></item>
- <tag><c>ClosedTag =</c></tag>
- <item><p><c>atom()</c></p>
- <p>Used in socket close message.</p></item>
- </taglist>
- </item>
+ <datatype>
+ <name name="transport_option"/>
+ <desc>
+ <p>Defaults to <c>{gen_tcp, tcp, tcp_closed, tcp_error,
+ tcp_passive}</c> for TLS (for backward compatibility a four
+ tuple will be converted to a five tuple with the last element
+ "second_element"_passive) and <c>{gen_udp, udp, udp_closed,
+ udp_error}</c> for DTLS (might also be changed to five tuple in
+ the future). Can be used to customize the transport layer. The
+ tag values should be the values used by the underlying
+ transport in its active mode messages. For TLS the callback
+ module must implement a reliable transport protocol, behave as
+ <c>gen_tcp</c>, and have functions corresponding to
+ <c>inet:setopts/2</c>, <c>inet:getopts/2</c>,
+ <c>inet:peername/1</c>, <c>inet:sockname/1</c>, and
+ <c>inet:port/1</c>. The callback <c>gen_tcp</c> is treated
+ specially and calls <c>inet</c> directly. For DTLS this
+ feature must be considered exprimental.
+ </p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="host"/>
+ </datatype>
- <tag><c>verify_type() =</c></tag>
- <item><p><c>verify_none | verify_peer</c></p></item>
+ <datatype>
+ <name name="hostname"/>
+ </datatype>
- <tag><c>path() =</c></tag>
- <item><p><c>string()</c></p>
- <p>Represents a file path.</p></item>
+ <datatype>
+ <name name="ip_address"/>
+ </datatype>
- <tag><c>public_key:der_encoded() =</c></tag>
- <item><p><c>binary()</c></p>
- <p>ASN.1 DER-encoded entity as an Erlang binary.</p></item>
+ <datatype>
+ <name name="protocol_version"/>
+ </datatype>
- <tag><c>host() =</c></tag>
- <item><p><c>hostname() | ipaddress()</c></p></item>
+ <datatype>
+ <name name="tls_version"/>
+ </datatype>
- <tag><c>hostname() =</c></tag>
- <item><p><c>string() - DNS hostname</c></p></item>
+ <datatype>
+ <name name="dtls_version"/>
+ </datatype>
- <tag><c>ip_address() =</c></tag>
- <item><p><c>{N1,N2,N3,N4} % IPv4 | {K1,K2,K3,K4,K5,K6,K7,K8} % IPv6
- </c></p></item>
+ <datatype>
+ <name name="tls_legacy_version"/>
+ </datatype>
- <tag><c>sslsocket() =</c></tag>
- <item><p>opaque()</p></item>
+ <datatype>
+ <name name="dtls_legacy_version"/>
+ </datatype>
- <tag><marker id="type-protocol"/><c>protocol_version() =</c></tag>
- <item><p><c>sslv3 | tlsv1 | 'tlsv1.1' | 'tlsv1.2'</c></p></item>
+ <datatype>
+ <name name="prf_random"/>
+ </datatype>
+
+ <datatype>
+ <name name="verify_type"/>
+ </datatype>
+
+ <datatype>
+ <name name="ciphers"/>
+ </datatype>
+
+ <datatype>
+ <name name="erl_cipher_suite"/>
+ </datatype>
+
+ <datatype>
+ <name name="cipher"/>
+ </datatype>
+
+ <datatype>
+ <name name="legacy_cipher"/>
+ </datatype>
+
+ <datatype>
+ <name name="cipher_filters"/>
+ </datatype>
+
+ <datatype>
+ <name name="hash"/>
+ </datatype>
- <tag><c>ciphers() =</c></tag>
- <item><p><c>= [ciphersuite()]</c></p>
- <p>Tuples and string formats accepted by versions
- before ssl-8.2.4 will be converted for backwards compatibility</p></item>
+ <datatype>
+ <name name="sha2"/>
+ </datatype>
- <tag><c>ciphersuite() =</c></tag>
- <item><p><c>
- #{key_exchange := key_exchange(),
- cipher := cipher(),
- mac := MAC::hash() | aead,
- prf := PRF::hash() | default_prf} </c></p></item>
+ <datatype>
+ <name name="legacy_hash"/>
+ </datatype>
- <tag><c>key_exchange()=</c></tag>
- <item><p><c>rsa | dhe_dss | dhe_rsa | dh_anon | psk | dhe_psk
- | rsa_psk | srp_anon | srp_dss | srp_rsa | ecdh_anon | ecdh_ecdsa
- | ecdhe_ecdsa | ecdh_rsa | ecdhe_rsa</c></p></item>
+ <datatype>
+ <name name="old_cipher_suite"/>
+ </datatype>
+
+ <datatype>
+ <name name="signature_algs"/>
+ </datatype>
- <tag><c>cipher() =</c></tag>
- <item><p><c>rc4_128 | des_cbc | '3des_ede_cbc'
- | aes_128_cbc | aes_256_cbc | aes_128_gcm | aes_256_gcm | chacha20_poly1305</c></p></item>
+ <datatype>
+ <name name="sign_algo"/>
+ </datatype>
+
+ <datatype>
+ <name name="sign_scheme"/>
+ </datatype>
+
+ <datatype>
+ <name name="kex_algo"/>
+ </datatype>
- <tag><c>hash() =</c></tag>
- <item><p><c>md5 | sha | sha224 | sha256 | sha348 | sha512</c></p></item>
+ <datatype>
+ <name name="algo_filter"/>
+ </datatype>
- <tag><c>prf_random() =</c></tag>
- <item><p><c>client_random | server_random</c></p></item>
+ <datatype>
+ <name name="named_curve"/>
+ </datatype>
- <tag><c>cipher_filters() =</c></tag>
- <item><p><c> [{key_exchange | cipher | mac | prf, algo_filter()}])</c></p></item>
+ <datatype>
+ <name name="psk_identity"/>
+ </datatype>
- <tag><c>algo_filter() =</c></tag>
- <item><p>fun(key_exchange() | cipher() | hash() | aead | default_prf) -> true | false </p></item>
+ <datatype>
+ <name name="srp_identity"/>
+ </datatype>
- <tag><c>srp_param_type() =</c></tag>
- <item><p><c>srp_1024 | srp_1536 | srp_2048 | srp_3072
- | srp_4096 | srp_6144 | srp_8192</c></p></item>
+ <datatype>
+ <name name="srp_param_type"/>
+ </datatype>
+
+ <datatype>
+ <name name="app_level_protocol"/>
+ </datatype>
- <tag><c>SNIfun::fun()</c></tag>
- <item><p><c>= fun(ServerName :: string()) -> [ssl_option()]</c></p></item>
+ <datatype>
+ <name name="protocol_extensions"/>
+ </datatype>
- <tag><c>named_curve() =</c></tag>
- <item><p><c>sect571r1 | sect571k1 | secp521r1 | brainpoolP512r1
- | sect409k1 | sect409r1 | brainpoolP384r1 | secp384r1
- | sect283k1 | sect283r1 | brainpoolP256r1 | secp256k1 | secp256r1
- | sect239k1 | sect233k1 | sect233r1 | secp224k1 | secp224r1
- | sect193r1 | sect193r2 | secp192k1 | secp192r1 | sect163k1
- | sect163r1 | sect163r2 | secp160k1 | secp160r1 | secp160r2</c></p></item>
+ <datatype>
+ <name name="error_alert"/>
+ </datatype>
- </taglist>
- </section>
+ <datatype>
+ <name name="tls_alert"/>
+ </datatype>
- <section>
- <title>SSL OPTION DESCRIPTIONS - COMMON for SERVER and CLIENT</title>
+ <datatype>
+ <name name="reason"/>
+ </datatype>
- <p>The following options have the same meaning in the client and
- the server:</p>
+ <datatype_title>TLS/DTLS OPTION DESCRIPTIONS - COMMON for SERVER and CLIENT</datatype_title>
- <taglist>
-
- <tag><c>{protocol, tls | dtls}</c></tag>
- <item><p>Choose TLS or DTLS protocol for the transport layer security.
- Defaults to <c>tls</c> Introduced in OTP 20, DTLS support is considered
- experimental in this release. DTLS over other transports than UDP are not yet supported.</p></item>
-
- <tag><c>{cert, public_key:der_encoded()}</c></tag>
- <item><p>The DER-encoded users certificate. If this option
- is supplied, it overrides option <c>certfile</c>.</p></item>
-
- <tag><c>{certfile, path()}</c></tag>
- <item><p>Path to a file containing the user certificate.</p></item>
-
- <tag>
- <marker id="key_option_def"/>
- <c>{key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'ECPrivateKey'
- |'PrivateKeyInfo', public_key:der_encoded()} | #{algorithm := rsa | dss | ecdsa,
- engine := crypto:engine_ref(), key_id := crypto:key_id(), password => crypto:password()}</c></tag>
- <item><p>The DER-encoded user's private key or a map refering to a crypto
- engine and its key reference that optionally can be password protected,
- seealso <seealso marker="crypto:crypto#engine_load-4"> crypto:engine_load/4
- </seealso> and <seealso marker="crypto:engine_load"> Crypto's Users Guide</seealso>. If this option
- is supplied, it overrides option <c>keyfile</c>.</p></item>
-
- <tag><c>{keyfile, path()}</c></tag>
- <item><p>Path to the file containing the user's
- private PEM-encoded key. As PEM-files can contain several
- entries, this option defaults to the same file as given by
- option <c>certfile</c>.</p></item>
-
- <tag><c>{password, string()}</c></tag>
- <item><p>String containing the user's password. Only used if the
- private keyfile is password-protected.</p></item>
-
- <tag><c>{ciphers, ciphers()}</c></tag>
- <item><p>Supported cipher suites. The function
- <c>cipher_suites/0</c> can be used to find all ciphers that are
- supported by default. <c>cipher_suites(all)</c> can be called
- to find all available cipher suites. Pre-Shared Key
- (<url href="http://www.ietf.org/rfc/rfc4279.txt">RFC 4279</url> and
- <url href="http://www.ietf.org/rfc/rfc5487.txt">RFC 5487</url>),
- Secure Remote Password
- (<url href="http://www.ietf.org/rfc/rfc5054.txt">RFC 5054</url>), RC4 cipher suites,
- and anonymous cipher suites only work if explicitly enabled by
- this option; they are supported/enabled by the peer also.
- Anonymous cipher suites are supported for testing purposes
- only and are not be used when security matters.</p></item>
-
- <tag><c>{eccs, [named_curve()]}</c></tag>
- <item><p> Allows to specify the order of preference for named curves
- and to restrict their usage when using a cipher suite supporting them.
- </p></item>
-
- <tag><c>{secure_renegotiate, boolean()}</c></tag>
- <item><p>Specifies if to reject renegotiation attempt that does
- not live up to
- <url href="http://www.ietf.org/rfc/rfc5746.txt">RFC 5746</url>.
- By default <c>secure_renegotiate</c> is set to <c>false</c>,
- that is, secure renegotiation is used if possible,
- but it falls back to insecure renegotiation if the peer
- does not support
- <url href="http://www.ietf.org/rfc/rfc5746.txt">RFC 5746</url>.</p>
- </item>
-
- <tag><c>{depth, integer()}</c></tag>
- <item><p>Maximum number of non-self-issued
+ <datatype>
+ <name name="common_option"/>
+ </datatype>
+
+ <datatype>
+ <name since="OTP 20" name="protocol"/>
+ <desc>
+ <p>Choose TLS or DTLS protocol for the transport layer security.
+ Defaults to <c>tls</c>. For DTLS other transports than UDP are not yet supported.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="handshake_completion"/>
+ <desc>
+ <p>Defaults to <c>full</c>. If hello is specified the handshake will
+ pause after the hello message and give the user a possibility make decisions
+ based on hello extensions before continuing or aborting the handshake by calling
+ <seealso marker="#handshake_continue-3"> handshake_continue/3</seealso> or
+ <seealso marker="#handshake_cancel-1"> handshake_cancel/1</seealso></p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="cert"/>
+ <desc>
+ <p>The DER-encoded users certificate. If this option
+ is supplied, it overrides option <c>certfile</c>.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="cert_pem"/>
+ <desc>
+ <p>Path to a file containing the user certificate on PEM format.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="key"/>
+ <desc>
+ <p>The DER-encoded user's private key or a map refering to a crypto
+ engine and its key reference that optionally can be password protected,
+ seealso <seealso marker="crypto:crypto#engine_load-4"> crypto:engine_load/4
+ </seealso> and <seealso marker="crypto:engine_load"> Crypto's Users Guide</seealso>. If this option
+ is supplied, it overrides option <c>keyfile</c>.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="key_pem"/>
+ <desc>
+ <p>Path to the file containing the user's
+ private PEM-encoded key. As PEM-files can contain several
+ entries, this option defaults to the same file as given by
+ option <c>certfile</c>.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="key_password"/>
+ <desc>
+ <p>String containing the user's password. Only used if the
+ private keyfile is password-protected.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="cipher_suites"/>
+ <desc>
+ <p>Supported cipher suites. The function
+ <c>cipher_suites/2</c> can be used to find all ciphers that
+ are supported by default. <c>cipher_suites(all, 'tlsv1.2')</c> can be
+ called to find all available cipher suites. Pre-Shared Key
+ (<url href="http://www.ietf.org/rfc/rfc4279.txt">RFC
+ 4279</url> and <url
+ href="http://www.ietf.org/rfc/rfc5487.txt">RFC 5487</url>),
+ Secure Remote Password (<url
+ href="http://www.ietf.org/rfc/rfc5054.txt">RFC 5054</url>),
+ RC4, 3DES, DES cipher suites, and anonymous cipher suites only work if
+ explicitly enabled by this option; they are supported/enabled
+ by the peer also. Anonymous cipher suites are supported for
+ testing purposes only and are not be used when security
+ matters.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="signature_schemes"/>
+ <desc>
+ <p>
+ In addition to the signature_algorithms extension from TLS 1.2,
+ <url href="http://www.ietf.org/rfc/rfc8446.txt#section-4.2.3">TLS 1.3
+ (RFC 5246 Section 4.2.3)</url>adds the signature_algorithms_cert extension
+ which enables having special requirements on the signatures used in the
+ certificates that differs from the requirements on digital signatures as a whole.
+ If this is not required this extension is not needed.
+ </p>
+ <p>
+ The client will send a signature_algorithms_cert extension (ClientHello),
+ if TLS version 1.3 or later is used, and the signature_algs_cert option is
+ explicitly specified. By default, only the signature_algs extension is sent.
+ </p>
+ <p>
+ The signature schemes shall be ordered according to the client's preference
+ (favorite choice first).
+ </p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="secure_renegotiation"/>
+ <desc><p>Specifies if to reject renegotiation attempt that does
+ not live up to <url
+ href="http://www.ietf.org/rfc/rfc5746.txt">RFC 5746</url>. By
+ default <c>secure_renegotiate</c> is set to <c>true</c>, that
+ is, secure renegotiation is enforced. If set to <c>false</c>
+ secure renegotiation will still be used if possible, but it
+ falls back to insecure renegotiation if the peer does not
+ support <url href="http://www.ietf.org/rfc/rfc5746.txt">RFC
+ 5746</url>.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="allowed_cert_chain_length"/>
+ <desc><p>Maximum number of non-self-issued
intermediate certificates that can follow the peer certificate
in a valid certification path. So, if depth is 0 the PEER must
be signed by the trusted ROOT-CA directly; if 1 the path can
be PEER, CA, ROOT-CA; if 2 the path can be PEER, CA, CA,
- ROOT-CA, and so on. The default value is 1.</p></item>
-
- <tag><marker id="verify_fun"/><c>{verify_fun, {Verifyfun :: fun(), InitialUserState ::
- term()}}</c></tag>
- <item><p>The verification fun is to be defined as follows:</p>
+ ROOT-CA, and so on. The default value is 1.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="custom_verify"/>
+ <desc>
+ <p>The verification fun is to be defined as follows:</p>
<code>
-fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom() | {revoked,
-atom()}} |
+fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom() |
+ {revoked, atom()}} |
{extension, #'Extension'{}}, InitialUserState :: term()) ->
{valid, UserState :: term()} | {valid_peer, UserState :: term()} |
{fail, Reason :: term()} | {unknown, UserState :: term()}.
@@ -285,24 +404,25 @@ atom()}} |
<p>The verification fun is called during the X509-path
validation when an error or an extension unknown to the SSL
- application is encountered. It is also called
- when a certificate is considered valid by the path validation
- to allow access to each certificate in the path to the user
- application. It differentiates between the peer
- certificate and the CA certificates by using <c>valid_peer</c> or
- <c>valid</c> as second argument to the verification fun. See the
- <seealso marker="public_key:public_key_records">public_key User's
- Guide</seealso> for definition of <c>#'OTPCertificate'{}</c> and
- <c>#'Extension'{}</c>.</p>
+ application is encountered. It is also called when a
+ certificate is considered valid by the path validation to
+ allow access to each certificate in the path to the user
+ application. It differentiates between the peer certificate
+ and the CA certificates by using <c>valid_peer</c> or
+ <c>valid</c> as second argument to the verification fun. See
+ the <seealso marker="public_key:public_key_records">public_key
+ User's Guide</seealso> for definition of
+ <c>#'OTPCertificate'{}</c> and <c>#'Extension'{}</c>.</p>
<list type="bulleted">
- <item><p>If the verify callback fun returns <c>{fail, Reason}</c>,
- the verification process is immediately stopped, an alert is
- sent to the peer, and the TLS/SSL handshake terminates.</p></item>
+ <item><p>If the verify callback fun returns <c>{fail,
+ Reason}</c>, the verification process is immediately
+ stopped, an alert is sent to the peer, and the TLS/DTLS
+ handshake terminates.</p></item>
<item><p>If the verify callback fun returns <c>{valid, UserState}</c>,
the verification process continues.</p></item>
<item><p>If the verify callback fun always returns
- <c>{valid, UserState}</c>, the TLS/SSL handshake does not
+ <c>{valid, UserState}</c>, the TLS/DTLS handshake does not
terminate regarding verification failures and the connection is
established.</p></item>
<item><p>If called with an extension unknown to the user application,
@@ -348,10 +468,12 @@ atom()}} |
<taglist>
<tag><c>unknown_ca</c></tag>
- <item><p>No trusted CA was found in the trusted store. The trusted CA is
- normally a so called ROOT CA, which is a self-signed certificate. Trust can
- be claimed for an intermediate CA (trusted anchor does not have to be
- self-signed according to X-509) by using option <c>partial_chain</c>.</p>
+ <item><p>No trusted CA was found in the trusted store. The
+ trusted CA is normally a so called ROOT CA, which is a
+ self-signed certificate. Trust can be claimed for an
+ intermediate CA (trusted anchor does not have to be
+ self-signed according to X-509) by using option
+ <c>partial_chain</c>.</p>
</item>
<tag><c>selfsigned_peer</c></tag>
@@ -362,15 +484,17 @@ atom()}} |
marker="public_key:public_key#pkix_path_validation-3">public_key:pkix_path_validation/3</seealso>
</p></item>
</taglist>
- </item>
-
- <tag><c>{crl_check, boolean() | peer | best_effort }</c></tag>
- <item>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="crl_check"/>
+ <desc>
<p>Perform CRL (Certificate Revocation List) verification
<seealso marker="public_key:public_key#pkix_crls_validate-3">
- (public_key:pkix_crls_validate/3)</seealso> on all the certificates during the path validation
- <seealso
- marker="public_key:public_key#pkix_path_validation-3">(public_key:pkix_path_validation/3)
+ (public_key:pkix_crls_validate/3)</seealso> on all the
+ certificates during the path validation <seealso
+ marker="public_key:public_key#pkix_path_validation-3">(public_key:pkix_path_validation/3)
</seealso>
of the certificate chain. Defaults to <c>false</c>.</p>
@@ -379,114 +503,114 @@ marker="public_key:public_key#pkix_path_validation-3">public_key:pkix_path_valid
<item>check is only performed on the peer certificate.</item>
<tag><c>best_effort</c></tag>
- <item>if certificate revocation status can not be determined
+ <item>if certificate revocation status cannot be determined
it will be accepted as valid.</item>
</taglist>
-
+
<p>The CA certificates specified for the connection will be used to
construct the certificate chain validating the CRLs.</p>
<p>The CRLs will be fetched from a local or external cache. See
<seealso marker="ssl:ssl_crl_cache_api">ssl_crl_cache_api(3)</seealso>.</p>
- </item>
-
- <tag><c>{crl_cache, {Module :: atom(), {DbHandle :: internal | term(), Args :: list()}}}</c></tag>
- <item>
- <p>Specify how to perform lookup and caching of certificate revocation lists.
- <c>Module</c> defaults to <seealso marker="ssl:ssl_crl_cache">ssl_crl_cache</seealso>
- with <c> DbHandle </c> being <c>internal</c> and an
- empty argument list.</p>
-
- <p>There are two implementations available:</p>
-
- <taglist>
- <tag><c>ssl_crl_cache</c></tag>
- <item>
- <p>This module maintains a cache of CRLs. CRLs can be
- added to the cache using the function <seealso
- marker="ssl:ssl_crl_cache#insert-1">ssl_crl_cache:insert/1</seealso>,
- and optionally automatically fetched through HTTP if the
- following argument is specified:</p>
-
- <taglist>
- <tag><c>{http, timeout()}</c></tag>
- <item><p>
- Enables fetching of CRLs specified as http URIs in<seealso
- marker="public_key:public_key_records">X509 certificate extensions</seealso>.
- Requires the OTP inets application.</p>
- </item>
- </taglist>
- </item>
-
- <tag><c>ssl_crl_hash_dir</c></tag>
- <item>
- <p>This module makes use of a directory where CRLs are
- stored in files named by the hash of the issuer name.</p>
-
- <p>The file names consist of eight hexadecimal digits
- followed by <c>.rN</c>, where <c>N</c> is an integer,
- e.g. <c>1a2b3c4d.r0</c>. For the first version of the
- CRL, <c>N</c> starts at zero, and for each new version,
- <c>N</c> is incremented by one. The OpenSSL utility
- <c>c_rehash</c> creates symlinks according to this
- pattern.</p>
-
- <p>For a given hash value, this module finds all
- consecutive <c>.r*</c> files starting from zero, and those
- files taken together make up the revocation list. CRL
- files whose <c>nextUpdate</c> fields are in the past, or
- that are issued by a different CA that happens to have the
- same name hash, are excluded.</p>
-
- <p>The following argument is required:</p>
-
- <taglist>
- <tag><c>{dir, string()}</c></tag>
- <item><p>Specifies the directory in which the CRLs can be found.</p></item>
- </taglist>
-
- </item>
-
- <tag><c>max_handshake_size</c></tag>
- <item>
- <p>Integer (24 bits unsigned). Used to limit the size of
- valid TLS handshake packets to avoid DoS attacks.
- Defaults to 256*1024.</p>
- </item>
-
- </taglist>
+ </desc>
+ </datatype>
- </item>
+ <datatype>
+ <name name="crl_cache_opts"/>
+ <desc>
+ <p>Specify how to perform lookup and caching of certificate revocation lists.
+ <c>Module</c> defaults to <seealso marker="ssl:ssl_crl_cache">ssl_crl_cache</seealso>
+ with <c> DbHandle </c> being <c>internal</c> and an
+ empty argument list.</p>
+
+ <p>There are two implementations available:</p>
+
+ <taglist>
+ <tag><c>ssl_crl_cache</c></tag>
+ <item>
+ <p>This module maintains a cache of CRLs. CRLs can be
+ added to the cache using the function <seealso
+ marker="ssl:ssl_crl_cache#insert-1">ssl_crl_cache:insert/1</seealso>,
+ and optionally automatically fetched through HTTP if the
+ following argument is specified:</p>
+
+ <taglist>
+ <tag><c>{http, timeout()}</c></tag>
+ <item><p>
+ Enables fetching of CRLs specified as http URIs in<seealso
+ marker="public_key:public_key_records">X509 certificate extensions</seealso>.
+ Requires the OTP inets application.</p>
+ </item>
+ </taglist>
+ </item>
+
+ <tag><c>ssl_crl_hash_dir</c></tag>
+ <item>
+ <p>This module makes use of a directory where CRLs are
+ stored in files named by the hash of the issuer name.</p>
+
+ <p>The file names consist of eight hexadecimal digits
+ followed by <c>.rN</c>, where <c>N</c> is an integer,
+ e.g. <c>1a2b3c4d.r0</c>. For the first version of the
+ CRL, <c>N</c> starts at zero, and for each new version,
+ <c>N</c> is incremented by one. The OpenSSL utility
+ <c>c_rehash</c> creates symlinks according to this
+ pattern.</p>
+
+ <p>For a given hash value, this module finds all
+ consecutive <c>.r*</c> files starting from zero, and those
+ files taken together make up the revocation list. CRL
+ files whose <c>nextUpdate</c> fields are in the past, or
+ that are issued by a different CA that happens to have the
+ same name hash, are excluded.</p>
+
+ <p>The following argument is required:</p>
+
+ <taglist>
+ <tag><c>{dir, string()}</c></tag>
+ <item><p>Specifies the directory in which the CRLs can be found.</p></item>
+ </taglist>
+ </item>
+ </taglist>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="root_fun"/>
+ <desc>
+ <code>
+fun(Chain::[public_key:der_encoded()]) ->
+ {trusted_ca, DerCert::public_key:der_encoded()} | unknown_ca}
+ </code>
+ <p>Claim an intermediate CA in the chain as trusted. TLS then
+ performs <seealso
+ marker="public_key:public_key#pkix_path_validation-3">public_key:pkix_path_validation/3</seealso>
+ with the selected CA as trusted anchor and the rest of the chain.</p>
+ </desc>
+ </datatype>
- <tag><c>{partial_chain, fun(Chain::[DerCert]) -> {trusted_ca, DerCert} |
- unknown_ca }</c></tag>
- <item><p>Claim an intermediate CA in the chain as trusted. TLS then
- performs <seealso
- marker="public_key:public_key#pkix_path_validation-3">public_key:pkix_path_validation/3</seealso>
- with the selected CA as trusted anchor and the rest of the chain.</p></item>
- <tag><c>{versions, [protocol_version()]}</c></tag>
- <item><p>TLS protocol versions supported by started clients and servers.
+ <datatype>
+ <name name="protocol_versions"/>
+ <desc><p>TLS protocol versions supported by started clients and servers.
This option overrides the application environment option
- <c>protocol_version</c>. If the environment option is not set, it defaults
+ <c>protocol_version</c> and <c>dtls_protocol_version</c>. If the environment option is not set, it defaults
to all versions, except SSL-3.0, supported by the SSL application.
- See also <seealso marker="ssl:ssl_app">ssl(6).</seealso></p></item>
+ See also <seealso marker="ssl:ssl_app">ssl(6).</seealso></p>
+ </desc>
+ </datatype>
- <tag><c>{hibernate_after, integer()|undefined}</c></tag>
- <item><p>When an integer-value is specified, <c>ssl_connection</c>
- goes into hibernation after the specified number of milliseconds
- of inactivity, thus reducing its memory footprint. When
- <c>undefined</c> is specified (this is the default), the process
- never goes into hibernation.</p></item>
- <tag><c>{user_lookup_fun, {Lookupfun :: fun(), UserState :: term()}}</c></tag>
- <item><p>The lookup fun is to defined as follows:</p>
+ <datatype>
+ <name name="custom_user_lookup"/>
+ <desc><p>The lookup fun is to defined as follows:</p>
<code>
fun(psk, PSKIdentity ::string(), UserState :: term()) ->
{ok, SharedSecret :: binary()} | error;
fun(srp, Username :: string(), UserState :: term()) ->
- {ok, {SRPParams :: srp_param_type(), Salt :: binary(), DerivedKey :: binary()}} | error.
+ {ok, {SRPParams :: srp_param_type(), Salt :: binary(),
+ DerivedKey :: binary()}} | error.
</code>
<p>For Pre-Shared Key (PSK) cipher suites, the lookup fun is
@@ -502,20 +626,63 @@ fun(srp, Username :: string(), UserState :: term()) ->
<url href="http://tools.ietf.org/html/rfc5054#section-2.4"> RFC 5054</url>:
<c>crypto:sha([Salt, crypto:sha([Username, &lt;&lt;$:&gt;&gt;, Password])])</c>
</p>
- </item>
+ </desc>
+ </datatype>
- <tag><c>{padding_check, boolean()}</c></tag>
- <item><p>Affects TLS-1.0 connections only.
+ <datatype>
+ <name name="session_id"/>
+ <desc>
+ <p>Identifies a TLS session.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="log_alert"/>
+ <desc><p>If set to <c>false</c>, error reports are not displayed.
+ Deprecated in OTP 22, use {log_level, <seealso marker="#type-logging_level">logging_level()</seealso>} instead.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="logging_level"/>
+ <desc><p>Specifies the log level for TLS/DTLS. At verbosity level <c>notice</c> and above error reports are
+ displayed in TLS/DTLS. The level <c>debug</c> triggers verbose logging of TLS/DTLS protocol
+ messages.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="hibernate_after"/>
+ <desc><p>When an integer-value is specified, <c>TLS/DTLS-connection</c>
+ goes into hibernation after the specified number of milliseconds
+ of inactivity, thus reducing its memory footprint. When
+ <c>undefined</c> is specified (this is the default), the process
+ never goes into hibernation.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="handshake_size"/>
+ <desc>
+ <p>Integer (24 bits unsigned). Used to limit the size of
+ valid TLS handshake packets to avoid DoS attacks.
+ Defaults to 256*1024.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="padding_check"/>
+ <desc><p>Affects TLS-1.0 connections only.
If set to <c>false</c>, it disables the block cipher padding check
to be able to interoperate with legacy software.</p>
<warning><p>Using <c>{padding_check, boolean()}</c> makes TLS
vulnerable to the Poodle attack.</p></warning>
- </item>
-
-
+ </desc>
+ </datatype>
- <tag><c>{beast_mitigation, one_n_minus_one | zero_n | disabled}</c></tag>
- <item><p>Affects SSL-3.0 and TLS-1.0 connections only. Used to change the BEAST
+ <datatype>
+ <name name="beast_mitigation"/>
+ <desc><p>Affects SSL-3.0 and TLS-1.0 connections only. Used to change the BEAST
mitigation strategy to interoperate with legacy software.
Defaults to <c>one_n_minus_one</c>.</p>
@@ -525,119 +692,170 @@ fun(srp, Username :: string(), UserState :: term()) ->
<p><c>disabled</c> - Disable BEAST mitigation.</p>
- <warning><p>Using <c>{beast_mitigation, disabled}</c> makes SSL or TLS
+ <warning><p>Using <c>{beast_mitigation, disabled}</c> makes SSL-3.0 or TLS-1.0
vulnerable to the BEAST attack.</p></warning>
- </item>
- </taglist>
-
- </section>
-
- <section>
- <title>SSL OPTION DESCRIPTIONS - CLIENT SIDE</title>
-
- <p>The following options are client-specific or have a slightly different
- meaning in the client than in the server:</p>
-
- <taglist>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="ssl_imp"/>
+ <desc><p>Deprecated since OTP-17, has no affect.</p></desc>
+ </datatype>
+
+ <datatype_title>TLS/DTLS OPTION DESCRIPTIONS - CLIENT</datatype_title>
+
+ <datatype>
+ <name name="client_option"/>
+ </datatype>
+
+ <datatype>
+ <name name="client_verify_type"/>
+ <desc><p>In mode <c>verify_none</c> the default behavior is to allow
+ all x509-path validation errors. See also option <seealso marker="#type-custom_verify">verify_fun</seealso>.</p>
+ </desc>
+ </datatype>
- <tag><c>{verify, verify_type()}</c></tag>
- <item><p>In mode <c>verify_none</c> the default behavior is to allow
- all x509-path validation errors. See also option <c>verify_fun</c>.</p>
- </item>
+ <datatype>
+ <name name="client_reuse_session"/>
+ <desc>
+ <p>Reuses a specific session earlier saved with the option
+ <c>{reuse_sessions, save} since OTP-21.3 </c>
+ </p>
+ </desc>
+ </datatype>
- <tag><c>{reuse_sessions, boolean()}</c></tag>
- <item><p>Specifies if the client is to try to reuse sessions
- when possible.</p></item>
+ <datatype>
+ <name name="client_reuse_sessions"/>
+ <desc>
+ <p>When <c>save</c> is specified a new connection will be negotiated
+ and saved for later reuse. The session ID can be fetched with
+ <seealso marker="#connection_information-2">connection_information/2</seealso>
+ and used with the client option <seealso marker="#type-client_reuse_session">reuse_session</seealso>
+ The boolean value true specifies that if possible, automatized session reuse will
+ be performed. If a new session is created, and is unique in regard
+ to previous stored sessions, it will be saved for possible later reuse. Since OTP-21.3</p>
+ </desc>
+ </datatype>
- <tag><c>{cacerts, [public_key:der_encoded()]}</c></tag>
- <item><p>The DER-encoded trusted certificates. If this option
- is supplied it overrides option <c>cacertfile</c>.</p></item>
-
- <tag><c>{cacertfile, path()}</c></tag>
- <item><p>Path to a file containing PEM-encoded CA certificates. The CA
+ <datatype>
+ <name name="client_cacerts"/>
+ <desc>
+ <p>The DER-encoded trusted certificates. If this option
+ is supplied it overrides option <c>cacertfile</c>.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="client_cafile"/>
+ <desc>
+ <p>Path to a file containing PEM-encoded CA certificates. The CA
certificates are used during server authentication and when building the
client certificate chain.</p>
- </item>
-
- <tag><c>{alpn_advertised_protocols, [binary()]}</c></tag>
- <item>
- <p>The list of protocols supported by the client to be sent to the
- server to be used for an Application-Layer Protocol Negotiation (ALPN).
- If the server supports ALPN then it will choose a protocol from this
- list; otherwise it will fail the connection with a "no_application_protocol"
- alert. A server that does not support ALPN will ignore this value.</p>
-
- <p>The list of protocols must not contain an empty binary.</p>
-
- <p>The negotiated protocol can be retrieved using the <c>negotiated_protocol/1</c> function.</p>
- </item>
-
- <tag><c>{client_preferred_next_protocols, {Precedence :: server | client, ClientPrefs :: [binary()]}}</c><br/>
- <c>{client_preferred_next_protocols, {Precedence :: server | client, ClientPrefs :: [binary()], Default :: binary()}}</c></tag>
- <item>
- <p>Indicates that the client is to try to perform Next Protocol
- Negotiation.</p>
-
- <p>If precedence is server, the negotiated protocol is the
- first protocol to be shown on the server advertised list, which is
- also on the client preference list.</p>
-
- <p>If precedence is client, the negotiated protocol is the
- first protocol to be shown on the client preference list, which is
- also on the server advertised list.</p>
-
- <p>If the client does not support any of the server advertised
- protocols or the server does not advertise any protocols, the
- client falls back to the first protocol in its list or to the
- default protocol (if a default is supplied). If the
- server does not support Next Protocol Negotiation, the
- connection terminates if no default protocol is supplied.</p>
- </item>
-
- <tag><c>{psk_identity, string()}</c></tag>
- <item><p>Specifies the identity the client presents to the server.
- The matching secret is found by calling <c>user_lookup_fun</c>.</p>
- </item>
-
- <tag><c>{srp_identity, {Username :: string(), Password :: string()}
- </c></tag>
- <item><p>Specifies the username and password to use to authenticate
- to the server.</p></item>
-
- <tag><c>{server_name_indication, HostName :: hostname()}</c></tag>
- <item><p>Specify the hostname to be used in TLS Server Name Indication extension.
- If not specified it will default to the <c>Host</c> argument of <seealso marker="#connect-3">connect/[3,4]</seealso>
- unless it is of type inet:ipaddress().</p>
- <p>
- The <c>HostName</c> will also be used in the hostname verification of the peer certificate using
- <seealso marker="public_key:public_key#pkix_verify_hostname-2">public_key:pkix_verify_hostname/2</seealso>.
- </p>
- </item>
- <tag><c>{server_name_indication, disable}</c></tag>
- <item>
- <p> Prevents the Server Name Indication extension from being sent and
- disables the hostname verification check
- <seealso marker="public_key:public_key#pkix_verify_hostname-2">public_key:pkix_verify_hostname/2</seealso> </p>
- </item>
- <tag><c>{fallback, boolean()}</c></tag>
- <item>
- <p> Send special cipher suite TLS_FALLBACK_SCSV to avoid undesired TLS version downgrade.
- Defaults to false</p>
- <warning><p>Note this option is not needed in normal TLS usage and should not be used
- to implement new clients. But legacy clients that retries connections in the following manner</p>
-
- <p><c> ssl:connect(Host, Port, [...{versions, ['tlsv2', 'tlsv1.1', 'tlsv1', 'sslv3']}])</c></p>
- <p><c> ssl:connect(Host, Port, [...{versions, [tlsv1.1', 'tlsv1', 'sslv3']}, {fallback, true}])</c></p>
- <p><c> ssl:connect(Host, Port, [...{versions, ['tlsv1', 'sslv3']}, {fallback, true}]) </c></p>
- <p><c> ssl:connect(Host, Port, [...{versions, ['sslv3']}, {fallback, true}]) </c></p>
-
- <p>may use it to avoid undesired TLS version downgrade. Note that TLS_FALLBACK_SCSV must also
- be supported by the server for the prevention to work.
- </p></warning>
- </item>
- <tag><marker id="client_signature_algs"/><c>{signature_algs, [{hash(), ecdsa | rsa | dsa}]}</c></tag>
- <item>
- <p>In addition to the algorithms negotiated by the cipher
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="client_alpn"/>
+ <desc>
+ <p>The list of protocols supported by the client to be sent to the
+ server to be used for an Application-Layer Protocol Negotiation (ALPN).
+ If the server supports ALPN then it will choose a protocol from this
+ list; otherwise it will fail the connection with a "no_application_protocol"
+ alert. A server that does not support ALPN will ignore this value.</p>
+
+ <p>The list of protocols must not contain an empty binary.</p>
+
+ <p>The negotiated protocol can be retrieved using the <c>negotiated_protocol/1</c> function.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="client_preferred_next_protocols"/>
+ <desc>
+ <p>Indicates that the client is to try to perform Next Protocol
+ Negotiation.</p>
+
+ <p>If precedence is server, the negotiated protocol is the
+ first protocol to be shown on the server advertised list, which is
+ also on the client preference list.</p>
+
+ <p>If precedence is client, the negotiated protocol is the
+ first protocol to be shown on the client preference list, which is
+ also on the server advertised list.</p>
+
+ <p>If the client does not support any of the server advertised
+ protocols or the server does not advertise any protocols, the
+ client falls back to the first protocol in its list or to the
+ default protocol (if a default is supplied). If the
+ server does not support Next Protocol Negotiation, the
+ connection terminates if no default protocol is supplied.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="client_psk_identity"/>
+ <desc>
+ <p>Specifies the identity the client presents to the server.
+ The matching secret is found by calling <c>user_lookup_fun</c></p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="client_srp_identity"/>
+ <desc>
+ <p>Specifies the username and password to use to authenticate
+ to the server.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="sni"/>
+ <desc>
+ <p>Specify the hostname to be used in TLS Server Name Indication extension.
+ If not specified it will default to the <c>Host</c> argument of <seealso marker="#connect-3">connect/[3,4]</seealso>
+ unless it is of type inet:ipaddress().</p>
+ <p>
+ The <c>HostName</c> will also be used in the hostname verification of the peer certificate using
+ <seealso marker="public_key:public_key#pkix_verify_hostname-2">public_key:pkix_verify_hostname/2</seealso>.
+ </p>
+ <p> The special value <c>disable</c> prevents the Server Name Indication extension from being sent and
+ disables the hostname verification check
+ <seealso marker="public_key:public_key#pkix_verify_hostname-2">public_key:pkix_verify_hostname/2</seealso> </p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="customize_hostname_check"/>
+ <desc>
+ <p> Customizes the hostname verification of the peer certificate, as different protocols that use
+ TLS such as HTTP or LDAP may want to do it differently, for possible options see
+ <seealso marker="public_key:public_key#pkix_verify_hostname-3">public_key:pkix_verify_hostname/3</seealso> </p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="fallback"/>
+ <desc>
+ <p> Send special cipher suite TLS_FALLBACK_SCSV to avoid undesired TLS version downgrade.
+ Defaults to false</p>
+ <warning><p>Note this option is not needed in normal TLS usage and should not be used
+ to implement new clients. But legacy clients that retries connections in the following manner</p>
+
+ <p><c> ssl:connect(Host, Port, [...{versions, ['tlsv2', 'tlsv1.1', 'tlsv1', 'sslv3']}])</c></p>
+ <p><c> ssl:connect(Host, Port, [...{versions, [tlsv1.1', 'tlsv1', 'sslv3']}, {fallback, true}])</c></p>
+ <p><c> ssl:connect(Host, Port, [...{versions, ['tlsv1', 'sslv3']}, {fallback, true}]) </c></p>
+ <p><c> ssl:connect(Host, Port, [...{versions, ['sslv3']}, {fallback, true}]) </c></p>
+
+ <p>may use it to avoid undesired TLS version downgrade. Note that TLS_FALLBACK_SCSV must also
+ be supported by the server for the prevention to work.
+ </p></warning>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="client_signature_algs"/>
+ <desc>
+ <p>In addition to the algorithms negotiated by the cipher
suite used for key exchange, payload encryption, message
authentication and pseudo random calculation, the TLS signature
algorithm extension <url
@@ -668,184 +886,223 @@ fun(srp, Username :: string(), UserState :: term()) ->
Selected signature algorithm can restrict which hash functions
that may be selected. Default support for {md5, rsa} removed in ssl-8.0
</p>
- </item>
- </taglist>
- </section>
-
- <section>
- <title>SSL OPTION DESCRIPTIONS - SERVER SIDE</title>
-
- <p>The following options are server-specific or have a slightly different
- meaning in the server than in the client:</p>
+ </desc>
+ </datatype>
+
+ <datatype_title>TLS/DTLS OPTION DESCRIPTIONS - SERVER </datatype_title>
- <taglist>
- <tag><c>{cacerts, [public_key:der_encoded()]}</c></tag>
- <item><p>The DER-encoded trusted certificates. If this option
- is supplied it overrides option <c>cacertfile</c>.</p></item>
+ <datatype>
+ <name name="server_option"/>
+ </datatype>
+
+ <datatype>
+ <name name="server_cacerts"/>
+ <desc><p>The DER-encoded trusted certificates. If this option
+ is supplied it overrides option <c>cacertfile</c>.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="server_cafile"/>
+ <desc><p>Path to a file containing PEM-encoded CA
+ certificates. The CA certificates are used to build the server
+ certificate chain and for client authentication. The CAs are
+ also used in the list of acceptable client CAs passed to the
+ client when a certificate is requested. Can be omitted if
+ there is no need to verify the client and if there are no
+ intermediate CAs for the server certificate.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="dh_der"/>
+ <desc><p>The DER-encoded Diffie-Hellman parameters. If
+ specified, it overrides option <c>dhfile</c>.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="dh_file"/>
+ <desc><p>Path to a file containing PEM-encoded Diffie Hellman
+ parameters to be used by the server if a cipher suite using
+ Diffie Hellman key exchange is negotiated. If not specified,
+ default parameters are used.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="server_verify_type"/>
+ <desc><p>A server only does x509-path validation in mode
+ <c>verify_peer</c>, as it then sends a certificate request to
+ the client (this message is not sent if the verify option is
+ <c>verify_none</c>). You can then also want to specify option
+ <c>fail_if_no_peer_cert</c>. </p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="fail_if_no_peer_cert"/>
+ <desc><p>Used together with <c>{verify, verify_peer}</c> by an
+ TLS/DTLS server. If set to <c>true</c>, the server fails if
+ the client does not have a certificate to send, that is, sends
+ an empty certificate. If set to <c>false</c>, it fails only if
+ the client sends an invalid certificate (an empty certificate
+ is considered valid). Defaults to false.</p>
+ </desc>
+ </datatype>
- <tag><c>{cacertfile, path()}</c></tag>
- <item><p>Path to a file containing PEM-encoded CA
- certificates. The CA certificates are used to build the server
- certificate chain and for client authentication. The CAs are
- also used in the list of acceptable client CAs passed to the
- client when a certificate is requested. Can be omitted if there
- is no need to verify the client and if there are no
- intermediate CAs for the server certificate.</p></item>
-
- <tag><c>{dh, public_key:der_encoded()}</c></tag>
- <item><p>The DER-encoded Diffie-Hellman parameters. If specified,
- it overrides option <c>dhfile</c>.</p></item>
-
- <tag><c>{dhfile, path()}</c></tag>
- <item><p>Path to a file containing PEM-encoded Diffie Hellman parameters
- to be used by the server if a cipher suite using Diffie Hellman key
- exchange is negotiated. If not specified, default parameters are used.
- </p></item>
-
- <tag><c>{verify, verify_type()}</c></tag>
- <item><p>A server only does x509-path validation in mode <c>verify_peer</c>,
- as it then sends a certificate request to the client
- (this message is not sent if the verify option is <c>verify_none</c>).
- You can then also want to specify option <c>fail_if_no_peer_cert</c>.
- </p></item>
-
- <tag><c>{fail_if_no_peer_cert, boolean()}</c></tag>
- <item><p>Used together with <c>{verify, verify_peer}</c> by an SSL server.
- If set to <c>true</c>, the server fails if the client does not have
- a certificate to send, that is, sends an empty certificate. If set to
- <c>false</c>, it fails only if the client sends an invalid
- certificate (an empty certificate is considered valid). Defaults to false.</p>
- </item>
-
- <tag><c>{reuse_sessions, boolean()}</c></tag>
- <item><p>Specifies if the server is to agree to reuse sessions
- when requested by the clients. See also option <c>reuse_session</c>.
- </p></item>
-
- <tag><c>{reuse_session, fun(SuggestedSessionId,
- PeerCert, Compression, CipherSuite) -> boolean()}</c></tag>
- <item><p>Enables the SSL server to have a local policy
- for deciding if a session is to be reused or not.
- Meaningful only if <c>reuse_sessions</c> is set to <c>true</c>.
- <c>SuggestedSessionId</c> is a <c>binary()</c>, <c>PeerCert</c> is
- a DER-encoded certificate, <c>Compression</c> is an enumeration integer,
- and <c>CipherSuite</c> is of type <c>ciphersuite()</c>.</p></item>
-
- <tag><c>{alpn_preferred_protocols, [binary()]}</c></tag>
- <item>
- <p>Indicates the server will try to perform Application-Layer
- Protocol Negotiation (ALPN).</p>
-
- <p>The list of protocols is in order of preference. The protocol
- negotiated will be the first in the list that matches one of the
- protocols advertised by the client. If no protocol matches, the
- server will fail the connection with a "no_application_protocol" alert.</p>
-
- <p>The negotiated protocol can be retrieved using the <c>negotiated_protocol/1</c> function.</p>
- </item>
-
- <tag><c>{next_protocols_advertised, Protocols :: [binary()]}</c></tag>
- <item><p>List of protocols to send to the client if the client indicates that
- it supports the Next Protocol extension. The client can select a protocol
- that is not on this list. The list of protocols must not contain an empty
- binary. If the server negotiates a Next Protocol, it can be accessed
- using the <c>negotiated_next_protocol/1</c> method.</p></item>
-
- <tag><c>{psk_identity, string()}</c></tag>
- <item><p>Specifies the server identity hint, which the server presents to
- the client.</p></item>
-
- <tag><c>{log_alert, boolean()}</c></tag>
- <item><p>If set to <c>false</c>, error reports are not displayed.</p></item>
-
- <tag><c>{honor_cipher_order, boolean()}</c></tag>
- <item><p>If set to <c>true</c>, use the server preference for cipher
- selection. If set to <c>false</c> (the default), use the client
- preference.</p></item>
-
- <tag><c>{sni_hosts, [{hostname(), [ssl_option()]}]}</c></tag>
- <item><p>If the server receives a SNI (Server Name Indication) from the client
- matching a host listed in the <c>sni_hosts</c> option, the specific options for
- that host will override previously specified options.
-
- The option <c>sni_fun</c>, and <c>sni_hosts</c> are mutually exclusive.</p></item>
-
- <tag><c>{sni_fun, SNIfun::fun()}</c></tag>
- <item><p>If the server receives a SNI (Server Name Indication) from the client,
- the given function will be called to retrieve <c>[ssl_option()]</c> for the indicated server.
- These options will be merged into predefined <c>[ssl_option()]</c>.
-
- The function should be defined as:
- <c>fun(ServerName :: string()) -> [ssl_option()]</c>
- and can be specified as a fun or as named <c>fun module:function/1</c>
-
- The option <c>sni_fun</c>, and <c>sni_hosts</c> are mutually exclusive.</p></item>
-
- <tag><c>{client_renegotiation, boolean()}</c></tag>
- <item>In protocols that support client-initiated renegotiation, the cost
- of resources of such an operation is higher for the server than the
- client. This can act as a vector for denial of service attacks. The SSL
- application already takes measures to counter-act such attempts,
- but client-initiated renegotiation can be strictly disabled by setting
- this option to <c>false</c>. The default value is <c>true</c>.
- Note that disabling renegotiation can result in long-lived connections
- becoming unusable due to limits on the number of messages the underlying
- cipher suite can encipher.
- </item>
-
- <tag><c>{honor_cipher_order, boolean()}</c></tag>
- <item>If true, use the server's preference for cipher selection. If false
- (the default), use the client's preference.
- </item>
+ <datatype>
+ <name name="server_reuse_sessions"/>
+ <desc><p>The boolean value true specifies that the server will
+ agree to reuse sessions. Setting it to false will result in an empty
+ session table, that is no sessions will be reused.
+ See also option <seealso marker="#type-server_reuse_session">reuse_session</seealso>
+ </p>
+ </desc>
+ </datatype>
- <tag><c>{honor_ecc_order, boolean()}</c></tag>
- <item>If true, use the server's preference for ECC curve selection. If false
- (the default), use the client's preference.
- </item>
-
- <tag><c>{signature_algs, [{hash(), ecdsa | rsa | dsa}]}</c></tag>
- <item><p> The algorithms specified by
- this option will be the ones accepted by the server in a signature algorithm
- negotiation, introduced in TLS-1.2. The algorithms will also be offered to the client if a
- client certificate is requested. For more details see the <seealso marker="#client_signature_algs">corresponding client option</seealso>.
- </p> </item>
-
- <tag><c>{v2_hello_compatible, boolean()}</c></tag>
- <item>If true, the server accepts clients that send hello messages on SSL-2.0 format but offers
- supported SSL/TLS versions. Defaults to false, that is the server will not interoperate with clients that
- offers SSL-2.0.
- </item>
-
- </taglist>
- </section>
-
- <section>
- <title>General</title>
+ <datatype>
+ <name name="server_reuse_session"/>
+ <desc><p>Enables the TLS/DTLS server to have a local policy
+ for deciding if a session is to be reused or not. Meaningful
+ only if <c>reuse_sessions</c> is set to <c>true</c>.
+ <c>SuggestedSessionId</c> is a <c>binary()</c>,
+ <c>PeerCert</c> is a DER-encoded certificate,
+ <c>Compression</c> is an enumeration integer, and
+ <c>CipherSuite</c> is of type <c>ciphersuite()</c>.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="server_alpn"/>
+ <desc>
+ <p>Indicates the server will try to perform
+ Application-Layer Protocol Negotiation (ALPN).</p>
+
+ <p>The list of protocols is in order of preference. The
+ protocol negotiated will be the first in the list that
+ matches one of the protocols advertised by the client. If no
+ protocol matches, the server will fail the connection with a
+ "no_application_protocol" alert.</p>
+
+ <p>The negotiated protocol can be retrieved using the
+ <c>negotiated_protocol/1</c> function.</p>
+ </desc>
+ </datatype>
- <p>When an SSL socket is in active mode (the default), data from the
- socket is delivered to the owner of the socket in the form of
- messages:</p>
+ <datatype>
+ <name name="server_next_protocol"/>
+ <desc><p>List of protocols to send to the client if the client
+ indicates that it supports the Next Protocol extension. The
+ client can select a protocol that is not on this list. The
+ list of protocols must not contain an empty binary. If the
+ server negotiates a Next Protocol, it can be accessed using
+ the <c>negotiated_next_protocol/1</c> method.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="server_psk_identity"/>
+ <desc>
+ <p>Specifies the server identity hint, which the server presents to
+ the client.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="honor_cipher_order"/>
+ <desc>
+ <p>If set to <c>true</c>, use the server preference for cipher
+ selection. If set to <c>false</c> (the default), use the client
+ preference.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="sni_hosts"/>
+ <desc><p>If the server receives a SNI (Server Name Indication) from the client
+ matching a host listed in the <c>sni_hosts</c> option, the specific options for
+ that host will override previously specified options.
+
+ The option <c>sni_fun</c>, and <c>sni_hosts</c> are mutually exclusive.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="sni_fun"/>
+ <desc>
+ <p>If the server receives a SNI (Server Name Indication)
+ from the client, the given function will be called to
+ retrieve <seealso marker="#type-server_option">[server_option()] </seealso> for the indicated server.
+ These options will be merged into predefined
+ <seealso marker="#type-server_option">[server_option()] </seealso> list.
+
+ The function should be defined as:
+ fun(ServerName :: string()) -> <seealso marker="#type-server_option">[server_option()] </seealso>
+ and can be specified as a fun or as named <c>fun module:function/1</c>
+
+ The option <c>sni_fun</c>, and <c>sni_hosts</c> are mutually exclusive.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="client_renegotiation"/>
+ <desc><p>In protocols that support client-initiated
+ renegotiation, the cost of resources of such an operation is
+ higher for the server than the client. This can act as a
+ vector for denial of service attacks. The SSL application
+ already takes measures to counter-act such attempts, but
+ client-initiated renegotiation can be strictly disabled by
+ setting this option to <c>false</c>. The default value is
+ <c>true</c>. Note that disabling renegotiation can result in
+ long-lived connections becoming unusable due to limits on the
+ number of messages the underlying cipher suite can
+ encipher.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="honor_cipher_order"/>
+ <desc><p>If true, use the server's preference for cipher
+ selection. If false (the default), use the client's
+ preference.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="honor_ecc_order"/>
+ <desc><p>If true, use the server's preference for ECC curve
+ selection. If false (the default), use the client's
+ preference.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="server_signature_algs"/>
+ <desc><p> The algorithms specified by this option will be the
+ ones accepted by the server in a signature algorithm
+ negotiation, introduced in TLS-1.2. The algorithms will also
+ be offered to the client if a client certificate is
+ requested. For more details see the <seealso
+ marker="#type-client_signature_algs">corresponding client
+ option</seealso>.
+ </p>
+ </desc>
+ </datatype>
+ </datatypes>
- <list type="bulleted">
- <item><p><c>{ssl, Socket, Data}</c></p></item>
- <item><p><c>{ssl_closed, Socket}</c></p></item>
- <item><p><c>{ssl_error, Socket, Reason}</c></p></item>
- </list>
+<!--
+ ================================================================
+ = Function definitions =
+ ================================================================
+-->
- <p>A <c>Timeout</c> argument specifies a time-out in milliseconds. The
- default value for argument <c>Timeout</c> is <c>infinity</c>.</p>
- </section>
-
<funcs>
<func>
- <name>append_cipher_suites(Deferred, Suites) -> ciphers() </name>
+ <name name="append_cipher_suites" arity="2" since="OTP 20.3"/>
<fsummary></fsummary>
- <type>
- <v>Deferred = ciphers() | cipher_filters() </v>
- <v>Suites = ciphers() </v>
- </type>
<desc><p>Make <c>Deferred</c> suites become the least preferred
suites, that is put them at the end of the cipher suite list
<c>Suites</c> after removing them from <c>Suites</c> if
@@ -856,54 +1113,46 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>cipher_suites() -></name>
- <name>cipher_suites(Type) -> old_ciphers()</name>
+ <name name="cipher_suites" arity="0" since="OTP R14B"/>
+ <name name="cipher_suites" arity="1" since="OTP R14B"/>
<fsummary>Returns a list of supported cipher suites.</fsummary>
- <type>
- <v>Type = erlang | openssl | all</v>
- </type>
<desc>
- <p>Returns a list of supported cipher suites.
- This function will become deprecated in OTP 21, and replaced
- by <seealso marker="#cipher_suites-2">ssl:cipher-suites/2</seealso>
- <c>cipher_suites()</c> is equivalent to <c>cipher_suites(erlang).</c>
- Type <c>openssl</c> is provided for backwards compatibility with the
- old SSL, which used OpenSSL. <c>cipher_suites(all)</c> returns
- all available cipher suites. The cipher suites not present
- in <c>cipher_suites(erlang)</c> but included in
- <c>cipher_suites(all)</c> are not used unless explicitly configured
- by the user.</p>
+ <p>Deprecated in OTP 21, use <seealso marker="#cipher_suites-2">cipher_suites/2</seealso> instead.</p>
</desc>
</func>
<func>
- <name>cipher_suites(Supported, Version) -> ciphers()</name>
+ <name name="cipher_suites" arity="2" since="OTP 20.3"/>
<fsummary>Returns a list of all default or
all supported cipher suites.</fsummary>
- <type>
- <v> Supported = default | all | anonymous </v>
- <v> Version = protocol_version() </v>
- </type>
- <desc><p>Returns all default or all supported (except anonymous), or all anonymous cipher suites for a
+ <desc><p>Returns all default or all supported (except anonymous),
+ or all anonymous cipher suites for a
TLS version</p>
</desc>
</func>
<func>
- <name>eccs() -></name>
- <name>eccs(protocol_version()) -> [named_curve()]</name>
+ <name name="cipher_suites" arity="3" since="OTP 22.0"/>
+ <fsummary>Returns a list of RFC or OpenSSL names</fsummary>
+ <desc><p>Same as <seealso marker="#cipher_suites-2">cipher_suites/2</seealso>
+ but lists RFC or OpenSSL string names instead of <seealso marker="#type-erl_cipher_suite">erl_cipher_suite()</seealso>
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="eccs" arity="0" since="OTP 19.2"/>
+ <name name="eccs" arity="1" since="OTP 19.2"/>
<fsummary>Returns a list of supported ECCs.</fsummary>
-
<desc><p>Returns a list of supported ECCs. <c>eccs()</c>
is equivalent to calling <c>eccs(Protocol)</c> with all
supported protocols and then deduplicating the output.</p>
</desc>
</func>
-
+
<func>
- <name>clear_pem_cache() -> ok </name>
+ <name name="clear_pem_cache" arity="0" since="OTP 17.5"/>
<fsummary> Clears the pem cache</fsummary>
-
<desc><p>PEM files, used by ssl API-functions, are cached. The
cache is regularly checked to see if any cache entries should be
invalidated, however this function provides a way to
@@ -913,50 +1162,51 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>connect(Socket, SslOptions) -> </name>
- <name>connect(Socket, SslOptions, Timeout) -> {ok, SslSocket}
- | {error, Reason}</name>
+ <name name="connect" arity="2" since="OTP R14B"/>
+ <name name="connect" arity="3" clause_i="1" since=""/>
<fsummary>Upgrades a <c>gen_tcp</c>, or
- equivalent, connected socket to an SSL socket.</fsummary>
- <type>
- <v>Socket = socket()</v>
- <v>SslOptions = [ssl_option()]</v>
- <v>Timeout = integer() | infinity</v>
- <v>SslSocket = sslsocket()</v>
- <v>Reason = term()</v>
- </type>
+ equivalent, connected socket to an TLS socket.</fsummary>
<desc><p>Upgrades a <c>gen_tcp</c>, or equivalent,
- connected socket to an SSL socket, that is, performs the
- client-side ssl handshake.</p>
+ connected socket to an TLS socket, that is, performs the
+ client-side TLS handshake.</p>
- <note><p>If the option <c>verify</c> is set to <c>verify_peer</c>
- the option <c>server_name_indication</c> shall also be specified,
- if it is not no Server Name Indication extension will be sent,
- and <seealso marker="public_key:public_key#pkix_verify_hostname-2">public_key:pkix_verify_hostname/2</seealso>
- will be called with the IP-address of the connection as <c>ReferenceID</c>, which is proably not what you want.</p></note>
+ <note><p>If the option <c>verify</c> is set to
+ <c>verify_peer</c> the option <c>server_name_indication</c>
+ shall also be specified, if it is not no Server Name
+ Indication extension will be sent, and <seealso
+ marker="public_key:public_key#pkix_verify_hostname-2">public_key:pkix_verify_hostname/2</seealso>
+ will be called with the IP-address of the connection as
+ <c>ReferenceID</c>, which is proably not what you want.</p>
+ </note>
+
+ <p> If the option <c>{handshake, hello}</c> is used the
+ handshake is paused after receiving the server hello message
+ and the success response is <c>{ok, SslSocket, Ext}</c>
+ instead of <c>{ok, SslSocket}</c>. Thereafter the handshake
+ is continued or canceled by calling <seealso
+ marker="#handshake_continue-3">
+ <c>handshake_continue/3</c></seealso> or <seealso
+ marker="#handshake_cancel-1"><c>handshake_cancel/1</c></seealso>.
+ </p>
+
+ <p> If the option <c>active</c> is set to <c>once</c>, <c>true</c> or an integer value,
+ the process owning the sslsocket will receive messages of type
+ <seealso marker="#type-active_msgs"> active_msgs() </seealso>
+ </p>
</desc>
</func>
<func>
- <name>connect(Host, Port, Options) -></name>
- <name>connect(Host, Port, Options, Timeout) ->
- {ok, SslSocket} | {error, Reason}</name>
- <fsummary>Opens an SSL connection to <c>Host</c>, <c>Port</c>.</fsummary>
- <type>
- <v>Host = host()</v>
- <v>Port = integer()</v>
- <v>Options = [option()]</v>
- <v>Timeout = integer() | infinity</v>
- <v>SslSocket = sslsocket()</v>
- <v>Reason = term()</v>
- </type>
- <desc><p>Opens an SSL connection to <c>Host</c>, <c>Port</c>.</p>
+ <name since="" name="connect" arity="3" clause_i="2"/>
+ <name since="" name="connect" arity="4"/>
+ <fsummary>Opens an TLS/DTLS connection to <c>Host</c>, <c>Port</c>.</fsummary>
+ <desc><p>Opens an TLS/DTLS connection to <c>Host</c>, <c>Port</c>.</p>
<p> When the option <c>verify</c> is set to <c>verify_peer</c> the check
<seealso marker="public_key:public_key#pkix_verify_hostname-2">public_key:pkix_verify_hostname/2</seealso>
will be performed in addition to the usual x509-path validation checks. If the check fails the error {bad_cert, hostname_check_failed} will
- be propagated to the path validation fun <seealso marker="#verify_fun">verify_fun</seealso>, where it is possible to do customized
- checks by using the full possibilitis of the <seealso marker="public_key:public_key#pkix_verify_hostname-2">public_key:pkix_verify_hostname/2</seealso> API.
+ be propagated to the path validation fun <seealso marker="#type-custom_verify">verify_fun</seealso>, where it is possible to do customized
+ checks by using the full possibilities of the <seealso marker="public_key:public_key#pkix_verify_hostname-3">public_key:pkix_verify_hostname/3</seealso> API.
When the option <c>server_name_indication</c> is provided, its value (the DNS name) will be used as <c>ReferenceID</c>
to <seealso marker="public_key:public_key#pkix_verify_hostname-2">public_key:pkix_verify_hostname/2</seealso>.
@@ -967,29 +1217,35 @@ fun(srp, Username :: string(), UserState :: term()) ->
<c>dns_id</c> will be assumed with a fallback to <c>ip</c> if that fails. </p>
<note><p>According to good practices certificates should not use IP-addresses as "server names". It would
be very surprising if this happen outside a closed network. </p></note>
+
+
+ <p> If the option <c>{handshake, hello}</c> is used the
+ handshake is paused after receiving the server hello message
+ and the success response is <c>{ok, SslSocket, Ext}</c>
+ instead of <c>{ok, SslSocket}</c>. Thereafter the handshake is continued or
+ canceled by calling <seealso marker="#handshake_continue-3">
+ <c>handshake_continue/3</c></seealso> or <seealso
+ marker="#handshake_cancel-1"><c>handshake_cancel/1</c></seealso>.
+ </p>
+
+ <p> If the option <c>active</c> is set to <c>once</c>, <c>true</c> or an integer value,
+ the process owning the sslsocket will receive messages of type
+ <seealso marker="#type-active_msgs"> active_msgs() </seealso>
+ </p>
</desc>
</func>
<func>
- <name>close(SslSocket) -> ok | {error, Reason}</name>
- <fsummary>Closes an SSL connection.</fsummary>
- <type>
- <v>SslSocket = sslsocket()</v>
- <v>Reason = term()</v>
- </type>
- <desc><p>Closes an SSL connection.</p>
+ <name since="" name="close" arity="1" />
+ <fsummary>Closes an TLS/DTLS connection.</fsummary>
+ <desc><p>Closes an TLS/DTLS connection.</p>
</desc>
</func>
<func>
- <name>close(SslSocket, How) -> ok | {ok, port()} | {error, Reason}</name>
- <fsummary>Closes an SSL connection.</fsummary>
- <type>
- <v>SslSocket = sslsocket()</v>
- <v>How = timeout() | {NewController::pid(), timeout()} </v>
- <v>Reason = term()</v>
- </type>
- <desc><p>Closes or downgrades an SSL connection. In the latter case the transport
+ <name since="OTP 18.1" name="close" arity="2"/>
+ <fsummary>Closes an TLS connection.</fsummary>
+ <desc><p>Closes or downgrades an TLS connection. In the latter case the transport
connection will be handed over to the <c>NewController</c> process after receiving
the TLS close alert from the peer. The returned transport socket will have
the following options set: <c>[{active, false}, {packet, 0}, {mode, binary}]</c></p>
@@ -997,15 +1253,9 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>controlling_process(SslSocket, NewOwner) ->
- ok | {error, Reason}</name>
+ <name since="" name="controlling_process" arity="2" />
<fsummary>Assigns a new controlling process to the
- SSL socket.</fsummary>
- <type>
- <v>SslSocket = sslsocket()</v>
- <v>NewOwner = pid()</v>
- <v>Reason = term()</v>
- </type>
+ TLS/DTLS socket.</fsummary>
<desc><p>Assigns a new controlling process to the SSL socket. A
controlling process is the owner of an SSL socket, and receives
all messages from the socket.</p>
@@ -1013,50 +1263,36 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>connection_information(SslSocket) ->
- {ok, Result} | {error, Reason} </name>
+ <name since="OTP 18.0" name="connection_information" arity="1"/>
<fsummary>Returns all the connection information.
</fsummary>
- <type>
- <v>Item = protocol | cipher_suite | sni_hostname | ecc | session_id | atom()</v>
- <d>Meaningful atoms, not specified above, are the ssl option names.</d>
- <v>Result = [{Item::atom(), Value::term()}]</v>
- <v>Reason = term()</v>
- </type>
<desc><p>Returns the most relevant information about the connection, ssl options that
are undefined will be filtered out. Note that values that affect the security of the
connection will only be returned if explicitly requested by connection_information/2.</p>
+ <note><p>The legacy <c>Item = cipher_suite</c> is still supported
+ and returns the cipher suite on its (undocumented) legacy format.
+ It should be replaced by <c>selected_cipher_suite</c>.</p></note>
</desc>
</func>
<func>
- <name>connection_information(SslSocket, Items) ->
- {ok, Result} | {error, Reason} </name>
+ <name since="OTP 18.0" name="connection_information" arity="2"/>
<fsummary>Returns the requested connection information.
</fsummary>
- <type>
- <v>Items = [Item]</v>
- <v>Item = protocol | cipher_suite | sni_hostname | ecc | session_id | client_random
- | server_random | master_secret | atom()</v>
- <d>Note that client_random, server_random and master_secret are values
- that affect the security of connection. Meaningful atoms, not specified above, are the ssl option names.</d>
- <v>Result = [{Item::atom(), Value::term()}]</v>
- <v>Reason = term()</v>
- </type>
<desc><p>Returns the requested information items about the connection,
if they are defined.</p>
+ <p>Note that client_random, server_random and master_secret are values
+ that affect the security of connection. Meaningful atoms, not specified
+ above, are the ssl option names.</p>
+
<note><p>If only undefined options are requested the
resulting list can be empty.</p></note>
</desc>
</func>
<func>
- <name>filter_cipher_suites(Suites, Filters) -> ciphers()</name>
+ <name since="OTP 20.3" name="filter_cipher_suites" arity="2" />
<fsummary></fsummary>
- <type>
- <v> Suites = ciphers()</v>
- <v> Filters = cipher_filters()</v>
- </type>
<desc><p>Removes cipher suites if any of the filter functions
returns false for any part of the cipher suite. This function
also calls default filter functions to make sure the cipher
@@ -1066,24 +1302,16 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>format_error(Reason) -> string()</name>
+ <name since="" name="format_error" arity="1" />
<fsummary>Returns an error string.</fsummary>
- <type>
- <v>Reason = term()</v>
- </type>
<desc>
<p>Presents the error returned by an SSL function as a printable string.</p>
</desc>
</func>
<func>
- <name>getopts(Socket, OptionNames) ->
- {ok, [socketoption()]} | {error, Reason}</name>
+ <name since="" name="getopts" arity="2" />
<fsummary>Gets the values of the specified options.</fsummary>
- <type>
- <v>Socket = sslsocket()</v>
- <v>OptionNames = [atom()]</v>
- </type>
<desc>
<p>Gets the values of the specified socket options.
</p>
@@ -1091,16 +1319,9 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>getstat(Socket) ->
- {ok, OptionValues} | {error, inet:posix()}</name>
- <name>getstat(Socket, OptionNames) ->
- {ok, OptionValues} | {error, inet:posix()}</name>
+ <name since="OTP 19.0" name="getstat" arity="1" />
+ <name since="OTP 19.0" name="getstat" arity="2" />
<fsummary>Get one or more statistic options for a socket</fsummary>
- <type>
- <v>Socket = sslsocket()</v>
- <v>OptionNames = [atom()]</v>
- <v>OptionValues = [{inet:stat_option(), integer()}]</v>
- </type>
<desc>
<p>Gets one or more statistic options for the underlying TCP socket.</p>
<p>See inet:getstat/2 for statistic options description.</p>
@@ -1108,26 +1329,86 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>listen(Port, Options) ->
- {ok, ListenSocket} | {error, Reason}</name>
+ <name since="OTP 21.0" name="handshake" arity="1" />
+ <name since="OTP 21.0" name="handshake" arity="2" clause_i="1" />
+ <fsummary>Performs server-side SSL/TLS handshake.</fsummary>
+ <desc>
+ <p>Performs the SSL/TLS/DTLS server-side handshake.</p>
+ <p>Returns a new TLS/DTLS socket if the handshake is successful.</p>
+
+ <p> If the option <c>active</c> is set to <c>once</c>, <c>true</c> or an integer value,
+ the process owning the sslsocket will receive messages of type
+ <seealso marker="#type-active_msgs"> active_msgs() </seealso>
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0" name="handshake" arity="2" clause_i="2" />
+ <name since="OTP 21.0" name="handshake" arity="3" />
+ <fsummary>Performs server-side SSL/TLS/DTLS handshake.</fsummary>
+ <desc>
+ <p>If <c>Socket</c> is a ordinary <c>socket()</c>: upgrades a <c>gen_tcp</c>,
+ or equivalent, socket to an SSL socket, that is, performs
+ the SSL/TLS server-side handshake and returns a TLS socket.</p>
+
+ <warning><p>The <c>Socket</c> shall be in passive mode ({active,
+ false}) before calling this function or else the behavior of this function
+ is undefined.
+ </p></warning>
+
+ <p>If <c>Socket</c> is an
+ <seealso marker="#type-sslsocket"> sslsocket() </seealso>: provides extra SSL/TLS/DTLS
+ options to those specified in
+ <seealso marker="#listen-2">listen/2 </seealso> and then performs
+ the SSL/TLS/DTLS handshake. Returns a new TLS/DTLS socket if the handshake is successful.</p>
+
+ <p>
+ If option <c>{handshake, hello}</c> is specified the handshake is
+ paused after receiving the client hello message and the
+ success response is <c>{ok, SslSocket, Ext}</c> instead of <c>{ok,
+ SslSocket}</c>. Thereafter the handshake is continued or
+ canceled by calling <seealso marker="#handshake_continue-3">
+ <c>handshake_continue/3</c></seealso> or <seealso
+ marker="#handshake_cancel-1"><c>handshake_cancel/1</c></seealso>.
+ </p>
+
+ <p> If the option <c>active</c> is set to <c>once</c>, <c>true</c> or an integer value,
+ the process owning the sslsocket will receive messages of type
+ <seealso marker="#type-active_msgs"> active_msgs() </seealso>
+ </p>
+
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0" name="handshake_cancel" arity="1" />
+ <fsummary>Cancel handshake with a fatal alert</fsummary>
+ <desc>
+ <p>Cancel the handshake with a fatal <c>USER_CANCELED</c> alert.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0" name="handshake_continue" arity="2" />
+ <name since="OTP 21.0" name="handshake_continue" arity="3" />
+ <fsummary>Continue the SSL/TLS handshake.</fsummary>
+ <desc>
+ <p>Continue the SSL/TLS handshake possiby with new, additional or changed options.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="" name="listen" arity="2" />
<fsummary>Creates an SSL listen socket.</fsummary>
- <type>
- <v>Port = integer()</v>
- <v>Options = options()</v>
- <v>ListenSocket = sslsocket()</v>
- </type>
<desc>
<p>Creates an SSL listen socket.</p>
</desc>
</func>
<func>
- <name>negotiated_protocol(Socket) -> {ok, Protocol} | {error, protocol_not_negotiated}</name>
+ <name since="OTP 18.0" name="negotiated_protocol" arity="1" />
<fsummary>Returns the protocol negotiated through ALPN or NPN extensions.</fsummary>
- <type>
- <v>Socket = sslsocket()</v>
- <v>Protocol = binary()</v>
- </type>
<desc>
<p>
Returns the protocol negotiated through ALPN or NPN extensions.
@@ -1136,40 +1417,27 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>peercert(Socket) -> {ok, Cert} | {error, Reason}</name>
+ <name since="" name="peercert" arity="1" />
<fsummary>Returns the peer certificate.</fsummary>
- <type>
- <v>Socket = sslsocket()</v>
- <v>Cert = binary()</v>
- </type>
<desc>
<p>The peer certificate is returned as a DER-encoded binary.
The certificate can be decoded with
- <c>public_key:pkix_decode_cert/2</c>.</p>
+ <seealso marker="public_key:public_key#pkix_decode_cert-2">public_key:pkix_decode_cert/2</seealso>
+ </p>
</desc>
</func>
<func>
- <name>peername(Socket) -> {ok, {Address, Port}} |
- {error, Reason}</name>
+ <name since="" name="peername" arity="1" />
<fsummary>Returns the peer address and port.</fsummary>
- <type>
- <v>Socket = sslsocket()</v>
- <v>Address = ipaddress()</v>
- <v>Port = integer()</v>
- </type>
<desc>
<p>Returns the address and port number of the peer.</p>
</desc>
</func>
<func>
- <name>prepend_cipher_suites(Preferred, Suites) -> ciphers()</name>
+ <name since="OTP 20.3" name="prepend_cipher_suites" arity="2" />
<fsummary></fsummary>
- <type>
- <v>Preferred = ciphers() | cipher_filters() </v>
- <v>Suites = ciphers() </v>
- </type>
<desc><p>Make <c>Preferred</c> suites become the most preferred
suites that is put them at the head of the cipher suite list
<c>Suites</c> after removing them from <c>Suites</c> if
@@ -1180,36 +1448,27 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>prf(Socket, Secret, Label, Seed, WantedLength) -> {ok, binary()} | {error, reason()}</name>
+ <name since="OTP R15B01" name="prf" arity="5" />
<fsummary>Uses a session Pseudo-Random Function to generate key material.</fsummary>
- <type>
- <v>Socket = sslsocket()</v>
- <v>Secret = binary() | master_secret</v>
- <v>Label = binary()</v>
- <v>Seed = [binary() | prf_random()]</v>
- <v>WantedLength = non_neg_integer()</v>
- </type>
<desc>
<p>Uses the Pseudo-Random Function (PRF) of a TLS session to generate
extra key material. It either takes user-generated values for
<c>Secret</c> and <c>Seed</c> or atoms directing it to use a specific
value from the session security parameters.</p>
- <p>Can only be used with TLS connections; <c>{error, undefined}</c>
+ <p>Can only be used with TLS/DTLS connections; <c>{error, undefined}</c>
is returned for SSLv3 connections.</p>
</desc>
</func>
<func>
- <name>recv(Socket, Length) -> </name>
- <name>recv(Socket, Length, Timeout) -> {ok, Data} | {error,
- Reason}</name>
+ <name since="" name="recv" arity="2" />
+ <name since="" name="recv" arity="3" />
<fsummary>Receives data on a socket.</fsummary>
- <type>
- <v>Socket = sslsocket()</v>
- <v>Length = integer()</v>
- <v>Timeout = integer()</v>
- <v>Data = [char()] | binary()</v>
- </type>
+ <type_desc variable="HttpPacket">See the description of
+ <c>HttpPacket</c> in
+ <seealso marker="erts:erlang#decode_packet/3"><c>erlang:decode_packet/3</c></seealso>
+ in ERTS.
+ </type_desc>
<desc>
<p>Receives a packet from a socket in passive
mode. A closed socket is indicated by return value
@@ -1227,11 +1486,8 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>renegotiate(Socket) -> ok | {error, Reason}</name>
+ <name since="OTP R14B" name="renegotiate" arity="1" />
<fsummary>Initiates a new handshake.</fsummary>
- <type>
- <v>Socket = sslsocket()</v>
- </type>
<desc><p>Initiates a new handshake. A notable return value is
<c>{error, renegotiation_rejected}</c> indicating that the peer
refused to go through with the renegotiation, but the connection
@@ -1240,40 +1496,27 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>send(Socket, Data) -> ok | {error, Reason}</name>
+ <name since="" name="send" arity="2" />
<fsummary>Writes data to a socket.</fsummary>
- <type>
- <v>Socket = sslsocket()</v>
- <v>Data = iodata()</v>
- </type>
<desc>
- <p>Writes <c>Data</c> to <c>Socket</c>.</p>
+ <p>Writes <c>Data</c> to <c>SslSocket</c>.</p>
<p>A notable return value is <c>{error, closed}</c> indicating that
the socket is closed.</p>
</desc>
</func>
<func>
- <name>setopts(Socket, Options) -> ok | {error, Reason}</name>
+ <name since="" name="setopts" arity="2" />
<fsummary>Sets socket options.</fsummary>
- <type>
- <v>Socket = sslsocket()</v>
- <v>Options = [socketoption]()</v>
- </type>
<desc>
<p>Sets options according to <c>Options</c> for socket
- <c>Socket</c>.</p>
+ <c>SslSocket</c>.</p>
</desc>
</func>
<func>
- <name>shutdown(Socket, How) -> ok | {error, Reason}</name>
+ <name since="OTP R14B" name="shutdown" arity="2" />
<fsummary>Immediately closes a socket.</fsummary>
- <type>
- <v>Socket = sslsocket()</v>
- <v>How = read | write | read_write</v>
- <v>Reason = reason()</v>
- </type>
<desc>
<p>Immediately closes a socket in one or two directions.</p>
<p><c>How == write</c> means closing the socket for writing,
@@ -1285,72 +1528,37 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>ssl_accept(Socket) -> </name>
- <name>ssl_accept(Socket, Timeout) -> ok | {error, Reason}</name>
+ <name since="" name="ssl_accept" arity="1" />
+ <name since="" name="ssl_accept" arity="2" />
<fsummary>Performs server-side SSL/TLS handshake.</fsummary>
- <type>
- <v>Socket = sslsocket()</v>
- <v>Timeout = integer()</v>
- <v>Reason = term()</v>
- </type>
<desc>
- <p>Performs the SSL/TLS server-side handshake.</p>
- <p><c>Socket</c> is a socket as returned by
- <seealso marker="#transport_accept-2">ssl:transport_accept/[1,2]</seealso>
- </p>
+ <p>Deprecated in OTP 21, use <seealso marker="#handshake-1">handshake/[1,2]</seealso> instead.</p>
+ <note><p>handshake/[1,2] always returns a new socket.</p></note>
</desc>
</func>
<func>
- <name>ssl_accept(Socket, SslOptions) -> </name>
- <name>ssl_accept(Socket, SslOptions, Timeout) -> {ok, Socket} | ok | {error, Reason}</name>
- <fsummary>Performs server-side SSL/TLS handshake.</fsummary>
- <type>
- <v>Socket = socket() | sslsocket() </v>
- <v>SslOptions = [ssl_option()]</v>
- <v>Timeout = integer()</v>
- <v>Reason = term()</v>
- </type>
+ <name since="OTP R14B" name="ssl_accept" arity="3" />
+ <fsummary>Performs server-side SSL/TLS/DTLS handshake.</fsummary>
<desc>
- <p>If <c>Socket</c> is a <c>socket()</c>: upgrades a <c>gen_tcp</c>,
- or equivalent, socket to an SSL socket, that is, performs
- the SSL/TLS server-side handshake and returns the SSL socket.</p>
-
- <warning><p>The listen socket is to be in mode <c>{active, false}</c>
- before telling the client that the server is ready to upgrade
- by calling this function, else the upgrade succeeds or does not
- succeed depending on timing.</p></warning>
-
- <p>If <c>Socket</c> is an <c>sslsocket()</c>: provides extra SSL/TLS
- options to those specified in
- <seealso marker="#listen-2">ssl:listen/2 </seealso> and then performs
- the SSL/TLS handshake.
- </p>
+ <p>Deprecated in OTP 21, use <seealso marker="#handshake-3">handshake/[2,3]</seealso> instead.</p>
+ <note><p>handshake/[2,3] always returns a new socket.</p></note>
</desc>
</func>
<func>
- <name>sockname(Socket) -> {ok, {Address, Port}} |
- {error, Reason}</name>
+ <name since="" name="sockname" arity="1" />
<fsummary>Returns the local address and port.</fsummary>
- <type>
- <v>Socket = sslsocket()</v>
- <v>Address = ipaddress()</v>
- <v>Port = integer()</v>
- </type>
<desc>
<p>Returns the local address and port number of socket
- <c>Socket</c>.</p>
+ <c>SslSocket</c>.</p>
</desc>
</func>
<func>
- <name>start() -> </name>
- <name>start(Type) -> ok | {error, Reason}</name>
+ <name since="OTP R14B" name="start" arity="0" />
+ <name since="OTP R14B">start(Type) -> ok | {error, Reason}</name>
<fsummary>Starts the SSL application.</fsummary>
- <type>
- <v>Type = permanent | transient | temporary</v>
- </type>
<desc>
<p>Starts the SSL application. Default type
is <c>temporary</c>.</p>
@@ -1358,40 +1566,66 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>stop() -> ok </name>
+ <name since="OTP R14B" name="stop" arity="0" />
<fsummary>Stops the SSL application.</fsummary>
<desc>
<p>Stops the SSL application.</p>
</desc>
</func>
+
+ <func>
+ <name since="OTP 22.0" name="str_to_suite" arity="1" />
+ <fsummary>Converts an RFC or OpenSSL name string to an erlang cipher suite format</fsummary>
+ <desc>
+ <p>Converts an RFC or OpenSSL name string to an
+ <seealso marker="#type-erl_cipher_suite">erl_cipher_suite()</seealso>
+ Returns an error if the cipher suite is not supported or the name is not a valid cipher suite name.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 22.0" name="suite_to_openssl_str" arity="1" />
+ <fsummary>Converts erlang cipher suite format to an OpenSSL name string.
+ </fsummary>
+ <desc>
+ <p>Converts <seealso marker="#type-erl_cipher_suite">erl_cipher_suite()</seealso>
+ to OpenSSL name string. </p>
+
+ <p>PRE TLS-1.3 these names differ for RFC names</p>
+
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 21.0" name="suite_to_str" arity="1" clause_i="1" />
+ <fsummary>Converts an erlang cipher suite to an RFC name string.</fsummary>
+ <desc>
+ <p>Converts <seealso marker="#type-erl_cipher_suite">erl_cipher_suite()</seealso>
+ to RFC name string.</p>
+ </desc>
+ </func>
<func>
- <name>transport_accept(ListenSocket) -></name>
- <name>transport_accept(ListenSocket, Timeout) ->
- {ok, NewSocket} | {error, Reason}</name>
+ <name since="" name="transport_accept" arity="1" />
+ <name since="" name="transport_accept" arity="2" />
<fsummary>Accepts an incoming connection and
prepares for <c>ssl_accept</c>.</fsummary>
- <type>
- <v>ListenSocket = NewSocket = sslsocket()</v>
- <v>Timeout = integer()</v>
- <v>Reason = reason()</v>
- </type>
<desc>
<p>Accepts an incoming connection request on a listen socket.
<c>ListenSocket</c> must be a socket returned from
- <seealso marker="#listen-2"> ssl:listen/2</seealso>.
+ <seealso marker="#listen-2"> listen/2</seealso>.
The socket returned is to be passed to
- <seealso marker="#ssl_accept-2"> ssl:ssl_accept[2,3]</seealso>
+ <seealso marker="#handshake-2"> handshake/[2,3]</seealso>
to complete handshaking, that is,
- establishing the SSL/TLS connection.</p>
+ establishing the SSL/TLS/DTLS connection.</p>
<warning>
- <p>The socket returned can only be used with
- <seealso marker="#ssl_accept-2"> ssl:ssl_accept[2,3]</seealso>.
- No traffic can be sent or received before that call.</p>
+ <p>Most API functions require that the TLS/DTLS
+ connection is established to work as expected.
+ </p>
</warning>
<p>The accepted socket inherits the options set for
<c>ListenSocket</c> in
- <seealso marker="#listen-2"> ssl:listen/2</seealso>.</p>
+ <seealso marker="#listen-2"> listen/2</seealso>.</p>
<p>The default
value for <c>Timeout</c> is <c>infinity</c>. If
<c>Timeout</c> is specified and no connection is accepted
@@ -1401,12 +1635,9 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>versions() -> [versions_info()]</name>
+ <name since="OTP R14B" name="versions" arity="0" />
<fsummary>Returns version information relevant for the
SSL application.</fsummary>
- <type>
- <v>versions_info() = {app_vsn, string()} | {supported | available, [protocol_version()] </v>
- </type>
<desc>
<p>Returns version information relevant for the SSL
application.</p>
@@ -1415,19 +1646,35 @@ fun(srp, Username :: string(), UserState :: term()) ->
<item>The application version of the SSL application.</item>
<tag><c>supported</c></tag>
- <item>TLS/SSL versions supported by default.
+ <item>SSL/TLS versions supported by default.
Overridden by a version option on
<seealso marker="#connect-2"> connect/[2,3,4]</seealso>,
<seealso marker="#listen-2"> listen/2</seealso>, and <seealso
marker="#ssl_accept-2">ssl_accept/[1,2,3]</seealso>.
- For the negotiated TLS/SSL version, see <seealso
- marker="#connection_information-1">ssl:connection_information/1
+ For the negotiated SSL/TLS version, see <seealso
+ marker="#connection_information-1">connection_information/1
</seealso>.</item>
-
+
+ <tag><c>supported_dtls</c></tag>
+ <item>DTLS versions supported by default.
+ Overridden by a version option on
+ <seealso marker="#connect-2"> connect/[2,3,4]</seealso>,
+ <seealso marker="#listen-2"> listen/2</seealso>, and <seealso
+ marker="#ssl_accept-2">ssl_accept/[1,2,3]</seealso>.
+ For the negotiated DTLS version, see <seealso
+ marker="#connection_information-1">connection_information/1
+ </seealso>.</item>
+
<tag><c>available</c></tag>
- <item>All TLS/SSL versions supported by the SSL application.
+ <item>All SSL/TLS versions supported by the SSL application.
TLS 1.2 requires sufficient support from the Crypto
application.</item>
+
+ <tag><c>available_dtls</c></tag>
+ <item>All DTLS versions supported by the SSL application.
+ DTLS 1.2 requires sufficient support from the Crypto
+ application.</item>
+
</taglist>
</desc>
</func>
@@ -1438,6 +1685,7 @@ fun(srp, Username :: string(), UserState :: term()) ->
<title>SEE ALSO</title>
<p><seealso marker="kernel:inet">inet(3)</seealso> and
<seealso marker="kernel:gen_tcp">gen_tcp(3)</seealso>
+ <seealso marker="kernel:gen_udp">gen_udp(3)</seealso>
</p>
</section>
diff --git a/lib/ssl/doc/src/ssl_app.xml b/lib/ssl/doc/src/ssl_app.xml
index f317dfded4..b05caf44ea 100644
--- a/lib/ssl/doc/src/ssl_app.xml
+++ b/lib/ssl/doc/src/ssl_app.xml
@@ -4,7 +4,7 @@
<appref>
<header>
<copyright>
- <year>1999</year><year>2016</year>
+ <year>1999</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -35,44 +35,14 @@
<description>
<p>
- The ssl application is an implementation of the SSL/TLS protocol in Erlang.
+ The ssl application is an implementation of the SSL, TLS and DTLS protocols in Erlang.
</p>
- <list type="bulleted">
- <item>Supported SSL/TLS-versions are SSL-3.0, TLS-1.0,
- TLS-1.1, and TLS-1.2.</item>
- <item>For security reasons SSL-2.0 is not supported.</item>
- <item>For security reasons SSL-3.0 is no longer supported by default,
- but can be configured.</item>
- <item>For security reasons DES cipher suites are no longer supported by default,
- but can be configured.</item>
- <item> Renegotiation Indication Extension <url href="http://www.ietf.org/rfc/rfc5746.txt">RFC 5746</url> is supported
- </item>
- <item>Ephemeral Diffie-Hellman cipher suites are supported,
- but not Diffie Hellman Certificates cipher suites.</item>
- <item>Elliptic Curve cipher suites are supported if the Crypto
- application supports it and named curves are used.
- </item>
- <item>Export cipher suites are not supported as the
- U.S. lifted its export restrictions in early 2000.</item>
- <item>IDEA cipher suites are not supported as they have
- become deprecated by the latest TLS specification so it is not
- motivated to implement them.</item>
- <item>Compression is not supported.</item>
- <item>CRL validation is supported.</item>
- <item>Policy certificate extensions are not supported.</item>
- <item>'Server Name Indication' extension
- (<url href="http://www.ietf.org/rfc/rfc6066.txt">RFC 6066</url>) is supported.</item>
- <item>Application Layer Protocol Negotiation (ALPN) and its successor Next Protocol Negotiation (NPN)
- are supported. </item>
- <item>It is possible to use Pre-Shared Key (PSK) and Secure Remote Password (SRP)
- cipher suites, but they are not enabled by default.
- </item>
- </list>
- </description>
+ <p>For current statement of standards compliance see the <seealso marker="standards_compliance">User's Guide</seealso>.</p>
+ </description>
<section>
<title>DEPENDENCIES</title>
- <p>The SSL application uses the <c>public_key</c> and
+ <p>The SSL application uses the <c>public_key</c>, <c>asn1</c> and
Crypto application to handle public keys and encryption, hence
these applications must be loaded for the SSL application to work.
In an embedded environment this means they must be started with
@@ -94,13 +64,20 @@
<p><c>erl -ssl protocol_version "['tlsv1.2', 'tlsv1.1']"</c></p>
<taglist>
- <tag><c>protocol_version = </c><seealso marker="ssl#type-protocol">ssl:protocol()</seealso><c><![CDATA[<optional>]]></c></tag>
+ <tag><c>protocol_version = </c><seealso marker="ssl#type-protocol">ssl:ssl_tls_protocol()</seealso><c><![CDATA[<optional>]]></c></tag>
<item><p>Protocol supported by started clients and
servers. If this option is not set, it defaults to all
- protocols currently supported by the SSL application.
+ TLS protocols currently supported by the SSL application.
This option can be overridden by the version option
to <c>ssl:connect/[2,3]</c> and <c>ssl:listen/2</c>.</p></item>
+ <tag><c>dtls_protocol_version = </c><seealso marker="ssl#type-protocol">ssl:dtls_protocol()</seealso><c><![CDATA[<optional>]]></c></tag>
+ <item><p>Protocol supported by started clients and
+ servers. If this option is not set, it defaults to all
+ DTLS protocols currently supported by the SSL application.
+ This option can be overridden by the version option
+ to <c>ssl:connect/[2,3]</c> and <c>ssl:listen/2</c>.</p></item>
+
<tag><c><![CDATA[session_lifetime = integer() <optional>]]></c></tag>
<item><p>Maximum lifetime of the session data in seconds. Defaults to 24 hours which is the maximum
recommended lifetime by <url href="http://www.ietf.org/rfc/5246rfc.txt">RFC 5246</url>. However
@@ -123,14 +100,14 @@
new client connections. If the maximum number of sessions is
reached, the current cache entries will be invalidated
regardless of their remaining lifetime. Defaults to
- 1000.</p></item>
+ 1000. Recommended ssl-8.2.1 or later for this option to work as intended.</p></item>
<tag> <c><![CDATA[session_cache_server_max = integer() <optional>]]></c></tag>
<item><p>Limits the growth of the servers session cache, that is
how many client sessions are cached by the server. If the
maximum number of sessions is reached, the current cache entries
will be invalidated regardless of their remaining
- lifetime. Defaults to 1000.</p></item>
+ lifetime. Defaults to 1000. Recommended ssl-8.2.1 or later for this option to work as intended.</p></item>
<tag><c><![CDATA[ssl_pem_cache_clean = integer() <optional>]]></c></tag>
<item>
@@ -145,9 +122,8 @@
<tag><c><![CDATA[bypass_pem_cache = boolean() <optional>]]></c></tag>
<item>
<p>Introduced in ssl-8.0.2. Disables the PEM-cache.
- The PEM cache has proven to be a bottleneck, until the
- implementation has been improved this can be used as
- a workaround. Defaults to false.
+ Can be used as a workaround for the PEM-cache bottleneck
+ before ssl-8.1.1. Defaults to false.
</p>
</item>
@@ -160,6 +136,20 @@
shutdown gracefully. Defaults to 5000 milliseconds.
</p>
</item>
+
+ <tag><c><![CDATA[internal_active_n = integer() <optional>]]></c></tag>
+ <item>
+ <p>
+ For TLS connections this value is used to handle the
+ internal socket. As the implementation was changed from an
+ active once to an active N behavior (N = 100), for
+ performance reasons, this option exist for possible tweaking
+ or restoring of the old behavior (internal_active_n = 1) in
+ unforeseen scenarios. The option will not affect erlang
+ distribution over TLS that will always run in active N mode.
+ Added in ssl-9.1 (OTP-21.2).
+ </p>
+ </item>
</taglist>
</section>
@@ -167,7 +157,7 @@
<title>ERROR LOGGER AND EVENT HANDLERS</title>
<p>The SSL application uses the default <seealso
marker="kernel:error_logger">OTP error logger</seealso> to log
- unexpected errors and TLS alerts. The logging of TLS alerts may be
+ unexpected errors and TLS/DTLS alerts. The logging of TLS/DTLS alerts may be
turned off with the <c>log_alert</c> option. </p>
</section>
diff --git a/lib/ssl/doc/src/ssl_crl_cache.xml b/lib/ssl/doc/src/ssl_crl_cache.xml
index 7a67de3971..a33aec62a7 100644
--- a/lib/ssl/doc/src/ssl_crl_cache.xml
+++ b/lib/ssl/doc/src/ssl_crl_cache.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2015</year><year>2015</year>
+ <year>2015</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -24,7 +24,7 @@
<file>ssl_crl_cache.xml</file>
</header>
- <module>ssl_crl_cache</module>
+ <module since="OTP 18.0">ssl_crl_cache</module>
<modulesummary>CRL cache </modulesummary>
<description>
<p>
@@ -34,33 +34,44 @@
the following functions are available.
</p>
</description>
+
+ <datatypes>
+ <datatype_title>DATA TYPES</datatype_title>
+
+ <datatype>
+ <name name="crl_src"/>
+ </datatype>
+
+ <datatype>
+ <name name="uri"/>
+ </datatype>
+
+ </datatypes>
<funcs>
<func>
- <name>delete(Entries) -> ok | {error, Reason} </name>
+ <name since="OTP 18.0">delete(Entries) -> ok | {error, Reason} </name>
<fsummary> </fsummary>
<type>
- <v> Entries = <seealso marker="inets:http_uri">http_uri:uri() </seealso> | {file, string()} | {der, [<seealso
- marker="public_key:public_key"> public_key:der_encoded() </seealso>]}</v>
- <v> Reason = term()</v>
+ <v> Entries = <seealso marker="#type-crl_src">crl_src()</seealso>]}</v>
+ <v> Reason = crl_reason()</v>
</type>
<desc>
<p>Delete CRLs from the ssl applications local cache. </p>
</desc>
</func>
<func>
- <name>insert(CRLSrc) -> ok | {error, Reason}</name>
- <name>insert(URI, CRLSrc) -> ok | {error, Reason}</name>
+ <name since="OTP 18.0">insert(CRLSrc) -> ok | {error, Reason}</name>
+ <name since="OTP 18.0">insert(URI, CRLSrc) -> ok | {error, Reason}</name>
<fsummary> </fsummary>
<type>
- <v> CRLSrc = {file, string()} | {der, [ <seealso
- marker="public_key:public_key"> public_key:der_encoded() </seealso> ]}</v>
- <v> URI = <seealso marker="inets:http_uri">http_uri:uri() </seealso> </v>
+ <v> CRLSrc = <seealso marker="#type-crl_src">crl_src()</seealso>]}</v>
+ <v> URI = <seealso marker="#type-uri">uri()</seealso> </v>
<v> Reason = term()</v>
</type>
<desc>
- <p>Insert CRLs into the ssl applications local cache. </p>
+ <p>Insert CRLs, available to fetch on DER format from <c>URI</c>, into the ssl applications local cache. </p>
</desc>
</func>
</funcs>
-</erlref> \ No newline at end of file
+</erlref>
diff --git a/lib/ssl/doc/src/ssl_crl_cache_api.xml b/lib/ssl/doc/src/ssl_crl_cache_api.xml
index c6774b4df6..4cba4e1de1 100644
--- a/lib/ssl/doc/src/ssl_crl_cache_api.xml
+++ b/lib/ssl/doc/src/ssl_crl_cache_api.xml
@@ -24,7 +24,7 @@
<file>ssl_crl_cache_api.xml</file>
</header>
- <module>ssl_crl_cache_api</module>
+ <module since="OTP 18.0">ssl_crl_cache_api</module>
<modulesummary>API for a SSL/TLS CRL (Certificate Revocation List) cache.</modulesummary>
<description>
<p>
@@ -39,35 +39,44 @@
a CRL cache.
</p>
</description>
-
- <section>
- <title>DATA TYPES</title>
-
- <p>The following data types are used in the functions below:
- </p>
-
- <taglist>
-
- <tag><c>cache_ref() =</c></tag>
- <item>opaque()</item>
- <tag><c>dist_point() =</c></tag>
- <item><p>#'DistributionPoint'{} see <seealso
- marker="public_key:public_key_records"> X509 certificates records</seealso></p></item>
-
- </taglist>
+
+
+ <!--
+ ================================================================
+ = Data types =
+ ================================================================
+ -->
+
+ <datatypes>
- </section>
+ <datatype>
+ <name name="crl_cache_ref"/>
+ <desc>
+ <p>Reference to the CRL cache.</p>
+ </desc>
+ </datatype>
+
+
+ <datatype>
+ <name name="dist_point"/>
+ <desc>
+ <p>For description see <seealso
+ marker="public_key:public_key_records"> X509 certificates records</seealso></p>
+ </desc>
+ </datatype>
+ </datatypes>
+
<funcs>
<func>
- <name>fresh_crl(DistributionPoint, CRL) -> FreshCRL</name>
+ <name since="OTP 18.0">fresh_crl(DistributionPoint, CRL) -> FreshCRL</name>
<fsummary> <c>fun fresh_crl/2 </c> will be used as input option <c>update_crl</c> to
public_key:pkix_crls_validate/3 </fsummary>
<type>
- <v> DistributionPoint = dist_point() </v>
+ <v> DistributionPoint = <seealso marker="#type-dist_point"> dist_point() </seealso> </v>
<v> CRL = [<seealso
- marker="public_key:public_key">public_key:der_encoded()</seealso>] </v>
+ marker="public_key:public_key#type-der_encoded">public_key:der_encoded()</seealso>] </v>
<v> FreshCRL = [<seealso
- marker="public_key:public_key">public_key:der_encoded()</seealso>] </v>
+ marker="public_key:public_key#type-der_encoded">public_key:der_encoded()</seealso>] </v>
</type>
<desc>
<p> <c>fun fresh_crl/2 </c> will be used as input option <c>update_crl</c> to
@@ -76,16 +85,16 @@
</func>
<func>
- <name>lookup(DistributionPoint, Issuer, DbHandle) -> not_available | CRLs </name>
- <name>lookup(DistributionPoint, DbHandle) -> not_available | CRLs </name>
+ <name since="OTP 19.0">lookup(DistributionPoint, Issuer, DbHandle) -> not_available | CRLs </name>
+ <name since="OTP 18.0">lookup(DistributionPoint, DbHandle) -> not_available | CRLs </name>
<fsummary> </fsummary>
<type>
- <v> DistributionPoint = dist_point() </v>
+ <v> DistributionPoint = <seealso marker="#type-dist_point"> dist_point() </seealso> </v>
<v> Issuer = <seealso
- marker="public_key:public_key">public_key:issuer_name()</seealso> </v>
- <v> DbHandle = cache_ref() </v>
+ marker="public_key:public_key#type-issuer_name">public_key:issuer_name()</seealso> </v>
+ <v> DbHandle = <seealso marker="#type-crl_cache_ref"> crl_cache_ref() </seealso></v>
<v> CRLs = [<seealso
- marker="public_key:public_key">public_key:der_encoded()</seealso>] </v>
+ marker="public_key:public_key#type-der_encoded">public_key:der_encoded()</seealso>] </v>
</type>
<desc> <p>Lookup the CRLs belonging to the distribution point <c> Distributionpoint</c>.
This function may choose to only look in the cache or to follow distribution point
@@ -106,12 +115,12 @@
</func>
<func>
- <name>select(Issuer, DbHandle) -> CRLs </name>
+ <name since="OTP 18.0">select(Issuer, DbHandle) -> CRLs </name>
<fsummary>Select the CRLs in the cache that are issued by <c>Issuer</c></fsummary>
<type>
<v> Issuer = <seealso
- marker="public_key:public_key">public_key:issuer_name()</seealso></v>
- <v> DbHandle = cache_ref() </v>
+ marker="public_key:public_key#type-issuer_name">public_key:issuer_name()</seealso></v>
+ <v> DbHandle = <seealso marker="#type-crl_cache_ref"> cache_ref() </seealso></v>
</type>
<desc>
<p>Select the CRLs in the cache that are issued by <c>Issuer</c> </p>
diff --git a/lib/ssl/doc/src/ssl_distribution.xml b/lib/ssl/doc/src/ssl_distribution.xml
index 7f8a08f704..1774bd8f77 100644
--- a/lib/ssl/doc/src/ssl_distribution.xml
+++ b/lib/ssl/doc/src/ssl_distribution.xml
@@ -22,7 +22,7 @@
</legalnotice>
- <title>Using SSL for Erlang Distribution</title>
+ <title>Using TLS for Erlang Distribution</title>
<prepared>P Nyblom</prepared>
<responsible></responsible>
<docno></docno>
@@ -33,7 +33,7 @@
<file>ssl_distribution.xml</file>
</header>
<p>This section describes how the Erlang distribution can use
- SSL to get extra verification and security.</p>
+ TLS to get extra verification and security.</p>
<p>The Erlang distribution can in theory use almost any
connection-based protocol as bearer. However, a module that
@@ -45,16 +45,16 @@
<p>In the SSL application, an extra distribution
module, <c>inet_tls_dist</c>, can be used as an
- alternative. All distribution connections will use SSL and
+ alternative. All distribution connections will use TLS and
all participating Erlang nodes in a distributed system must use
this distribution module.</p>
<p>The security level depends on the parameters provided to the
- SSL connection setup. Erlang node cookies are however always
+ TLS connection setup. Erlang node cookies are however always
used, as they can be used to differentiate between two different
Erlang networks.</p>
- <p>To set up Erlang distribution over SSL:</p>
+ <p>To set up Erlang distribution over TLS:</p>
<list type="bulleted">
<item><em>Step 1:</em> Build boot scripts including the
@@ -63,13 +63,13 @@
<c>net_kernel</c>.</item>
<item><em>Step 3:</em> Specify the security options and other
SSL options.</item>
- <item><em>Step 4:</em> Set up the environment to always use SSL.</item>
+ <item><em>Step 4:</em> Set up the environment to always use TLS.</item>
</list>
<p>The following sections describe these steps.</p>
<section>
- <title>Building Boot Scripts Including the ssl Application</title>
+ <title>Building Boot Scripts Including the SSL Application</title>
<p>Boot scripts are built using the <c>systools</c> utility in the
SASL application. For more information on <c>systools</c>,
see the SASL documentation. This is only an example of
@@ -90,7 +90,7 @@
STDLIB application.</p></item>
</list>
- <p>The following shows an example <c>.rel</c> file with SSL
+ <p>The following shows an example <c>.rel</c> file with TLS
added:</p>
<code type="none">
{release, {"OTP APN 181 01","R15A"}, {erts, "5.9"},
@@ -154,7 +154,7 @@ Eshell V5.0 (abort with ^G)
<section>
<title>Specifying Distribution Module for net_kernel</title>
- <p>The distribution module for SSL is named <c>inet_tls_dist</c>
+ <p>The distribution module for SSL/TLS is named <c>inet_tls_dist</c>
and is specified on the command line with option <c>-proto_dist</c>.
The argument to <c>-proto_dist</c> is to be the module
name without suffix <c>_dist</c>. So, this distribution
@@ -174,24 +174,24 @@ Eshell V5.0 (abort with ^G)
(ssl_test@myhost)1> </code>
<p>However, a node started in this way refuses to talk
- to other nodes, as no SSL parameters are supplied
+ to other nodes, as no TLS parameters are supplied
(see the next section).</p>
</section>
<section>
- <title>Specifying SSL Options</title>
+ <title>Specifying SSL/TLS Options</title>
<p>
- The SSL distribution options can be written into a file
+ The SSL/TLS distribution options can be written into a file
that is consulted when the node is started. This file name
is then specified with the command line argument
<c>-ssl_dist_optfile</c>.
</p>
<p>
- Any available SSL option can be specified in an options file,
+ Any available SSL/TLS option can be specified in an options file,
but note that options that take a <c>fun()</c> has to use
the syntax <c>fun Mod:Func/Arity</c> since a function
- body can not be compiled when consulting a file.
+ body cannot be compiled when consulting a file.
</p>
<p>
Do not tamper with the socket options
@@ -202,7 +202,7 @@ Eshell V5.0 (abort with ^G)
interfere severely, so beware!
</p>
<p>
- For SSL to work, at least a public key and a certificate
+ For SSL/TLS to work, at least a public key and a certificate
must be specified for the server side.
In the following example, the PEM file
<c>"/home/me/ssl/erlserver.pem"</c> contains both
@@ -257,13 +257,13 @@ $ erl -boot /home/me/ssl/start_ssl -proto_dist inet_tls
still be accepted if it does not present any certificate.
</p>
<p>
- A node started in this way is fully functional, using SSL
+ A node started in this way is fully functional, using TLS
as the distribution protocol.
</p>
</section>
<section>
- <title>Specifying SSL Options (Legacy)</title>
+ <title>Specifying SSL/TLS Options (Legacy)</title>
<p>
As in the previous section the PEM file
@@ -272,9 +272,9 @@ $ erl -boot /home/me/ssl/start_ssl -proto_dist inet_tls
</p>
<p>On the <c>erl</c> command line you can specify options that the
- SSL distribution adds when creating a socket.</p>
+ SSL/TLS distribution adds when creating a socket.</p>
- <p>The simplest SSL options in the following list can be specified
+ <p>The simplest SSL/TLS options in the following list can be specified
by adding the
prefix <c>server_</c> or <c>client_</c> to the option name:</p>
<list type="bulleted">
@@ -294,7 +294,7 @@ $ erl -boot /home/me/ssl/start_ssl -proto_dist inet_tls
</list>
<p>Note that <c>verify_fun</c> needs to be written in a different
- form than the corresponding SSL option, since funs are not
+ form than the corresponding SSL/TLS option, since funs are not
accepted on the command line.</p>
<p>The server can also take the options <c>dhfile</c> and
@@ -307,7 +307,7 @@ $ erl -boot /home/me/ssl/start_ssl -proto_dist inet_tls
<p>Raw socket options, such as <c>packet</c> and <c>size</c> must not
be specified on the command line.</p>
- <p>The command-line argument for specifying the SSL options is named
+ <p>The command-line argument for specifying the SSL/TLS options is named
<c>-ssl_dist_opt</c> and is to be followed by pairs of
SSL options and their values. Argument <c>-ssl_dist_opt</c> can
be repeated any number of times.</p>
@@ -331,10 +331,10 @@ Eshell V5.0 (abort with ^G)
</section>
<section>
- <title>Setting up Environment to Always Use SSL (Legacy)</title>
+ <title>Setting up Environment to Always Use SSL/TLS (Legacy)</title>
<p>A convenient way to specify arguments to Erlang is to use environment
variable <c>ERL_FLAGS</c>. All the flags needed to
- use the SSL distribution can be specified in that variable and are
+ use the SSL/TLS distribution can be specified in that variable and are
then interpreted as command-line arguments for all
subsequent invocations of Erlang.</p>
@@ -365,8 +365,8 @@ Eshell V5.0 (abort with ^G)
</section>
<section>
- <title>Using SSL distribution over IPv6</title>
- <p>It is possible to use SSL distribution over IPv6 instead of
+ <title>Using SSL/TLS distribution over IPv6</title>
+ <p>It is possible to use SSL/TLS distribution over IPv6 instead of
IPv4. To do this, pass the option <c>-proto_dist inet6_tls</c>
instead of <c>-proto_dist inet_tls</c> when starting Erlang,
either on the command line or in the <c>ERL_FLAGS</c> environment
@@ -380,6 +380,6 @@ $ erl -boot /home/me/ssl/start_ssl -proto_dist inet6_tls
</code>
<p>A node started in this way will only be able to communicate with
- other nodes using SSL distribution over IPv6.</p>
+ other nodes using SSL/TLS distribution over IPv6.</p>
</section>
</chapter>
diff --git a/lib/ssl/doc/src/ssl_introduction.xml b/lib/ssl/doc/src/ssl_introduction.xml
index 25b05a769d..adcfb091b7 100644
--- a/lib/ssl/doc/src/ssl_introduction.xml
+++ b/lib/ssl/doc/src/ssl_introduction.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2015</year>
- <year>2015</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -41,14 +41,15 @@
authenticate the counterpart with whom they communicate,
and to exchange a symmetric key for payload encryption. The protocol provides
data/message confidentiality (encryption), integrity (through message authentication code checks)
- and host verification (through certificate path validation).</p>
+ and host verification (through certificate path validation). DTLS (Datagram Transport Layer Security) that
+ is based on TLS but datagram oriented instead of stream oriented.</p>
</section>
<section>
<title>Prerequisites</title>
<p>It is assumed that the reader is familiar with the Erlang
programming language, the concepts of OTP, and has a basic
- understanding of SSL/TLS.</p>
+ understanding of SSL/TLS/DTLS.</p>
</section>
</chapter>
diff --git a/lib/ssl/doc/src/ssl_protocol.xml b/lib/ssl/doc/src/ssl_protocol.xml
index 31a22db58b..3ab836443f 100644
--- a/lib/ssl/doc/src/ssl_protocol.xml
+++ b/lib/ssl/doc/src/ssl_protocol.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2003</year><year>2015</year>
+ <year>2003</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -22,7 +22,7 @@
</legalnotice>
- <title>TLS and its Predecessor, SSL</title>
+ <title>TLS/DTLS and TLS Predecessor, SSL</title>
<prepared></prepared>
<responsible></responsible>
<docno></docno>
@@ -33,7 +33,7 @@
<file>ssl_protocol.xml</file>
</header>
- <p>The Erlang SSL application implements the SSL/TLS protocol
+ <p>The Erlang SSL application implements the SSL/TLS/DTLS protocol
for the currently supported versions, see the
<seealso marker="ssl">ssl(3)</seealso> manual page.
</p>
@@ -41,20 +41,22 @@
<p>By default SSL/TLS is run over the TCP/IP protocol even
though you can plug in any other reliable transport protocol
with the same Application Programming Interface (API) as the
- <c>gen_tcp</c> module in Kernel.</p>
+ <c>gen_tcp</c> module in Kernel. DTLS is by default run over UDP/IP,
+ which means that application data has no delivery guarentees. Other
+ transports, such as SCTP, may be supported in future releases.</p>
<p>If a client and a server wants to use an upgrade mechanism, such as
- defined by RFC 2817, to upgrade a regular TCP/IP connection to an SSL
+ defined by RFC 2817, to upgrade a regular TCP/IP connection to an TLS
connection, this is supported by the Erlang SSL application API. This can be
useful for, for example, supporting HTTP and HTTPS on the same port and
- implementing virtual hosting.
+ implementing virtual hosting. Note this is a TLS feature only.
</p>
<section>
<title>Security Overview</title>
<p>To achieve authentication and privacy, the client and server
- perform a TLS handshake procedure before transmitting or receiving
+ perform a TLS/DTLS handshake procedure before transmitting or receiving
any data. During the handshake, they agree on a protocol version and
cryptographic algorithms, generate shared secrets using public
key cryptographies, and optionally authenticate each other with
@@ -73,10 +75,10 @@
<p>The keys for the symmetric encryption are generated uniquely
for each connection and are based on a secret negotiated
- in the TLS handshake.</p>
+ in the TLS/DTLS handshake.</p>
- <p>The TLS handshake protocol and data transfer is run on top of
- the TLS Record Protocol, which uses a keyed-hash Message
+ <p>The TLS/DTLS handshake protocol and data transfer is run on top of
+ the TLS/DTLS Record Protocol, which uses a keyed-hash Message
Authenticity Code (MAC), or a Hash-based MAC (HMAC),
to protect the message data
integrity. From the TLS RFC: "A Message Authentication Code is a
@@ -152,8 +154,8 @@
from it was saved, for security reasons. The amount of time the
session data is to be saved can be configured.</p>
- <p>By default the SSL clients try to reuse an available session and
- by default the SSL servers agree to reuse sessions when clients
+ <p>By default the TLS/DTLS clients try to reuse an available session and
+ by default the TLS/DTLS servers agree to reuse sessions when clients
ask for it.</p>
</section>
diff --git a/lib/ssl/doc/src/ssl_session_cache_api.xml b/lib/ssl/doc/src/ssl_session_cache_api.xml
index a84a3dfce9..e841729e57 100644
--- a/lib/ssl/doc/src/ssl_session_cache_api.xml
+++ b/lib/ssl/doc/src/ssl_session_cache_api.xml
@@ -28,7 +28,7 @@
<rev></rev>
<file>ssl_session_cache_api.xml</file>
</header>
- <module>ssl_session_cache_api</module>
+ <module since="OTP R14B">ssl_session_cache_api</module>
<modulesummary>TLS session cache API</modulesummary>
<description>
@@ -38,39 +38,50 @@
defining a new callback module implementing this API.
</p>
</description>
- <section>
- <title>DATA TYPES</title>
- <p>The following data types are used in the functions for
- <c>ssl_session_cache_api</c>:</p>
-
- <taglist>
- <tag><c>cache_ref() =</c></tag>
- <item><p><c>opaque()</c></p></item>
-
- <tag><c>key() =</c></tag>
- <item><p><c>{partialkey(), session_id()}</c></p></item>
-
- <tag><c>partialkey() =</c></tag>
- <item><p><c>opaque()</c></p></item>
-
- <tag><c>session_id() =</c></tag>
- <item><p><c>binary()</c></p></item>
-
- <tag><c>session()</c> =</tag>
- <item><p><c>opaque()</c></p></item>
- </taglist>
-
- </section>
+ <!--
+ ================================================================
+ = Data types =
+ ================================================================
+ -->
+
+ <datatypes>
+
+ <datatype>
+ <name name="session_cache_ref"/>
+ </datatype>
+
+ <datatype>
+ <name name="session_cache_key"/>
+ <desc>
+ <p>A key to an entry in the session cache.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="partial_key"/>
+ <desc>
+ <p>The opaque part of the key. Does not need to be handled
+ by the callback.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="session"/>
+ <desc>
+ <p>The session data that is stored for each session.</p>
+ </desc>
+ </datatype>
+ </datatypes>
<funcs>
<func>
- <name>delete(Cache, Key) -> _</name>
+ <name since="OTP R14B">delete(Cache, Key) -> _</name>
<fsummary>Deletes a cache entry.</fsummary>
<type>
- <v>Cache = cache_ref()</v>
- <v>Key = key()</v>
+ <v>Cache = <seealso marker="#type-session_cache_ref"> session_cache_ref() </seealso></v>
+ <v>Key = <seealso marker="#type-session_cache_key">session_cache_key() </seealso> </v>
</type>
<desc>
<p>Deletes a cache entry. Is only called from the cache
@@ -80,10 +91,12 @@
</func>
<func>
- <name>foldl(Fun, Acc0, Cache) -> Acc</name>
+ <name since="OTP R14B">foldl(Fun, Acc0, Cache) -> Acc</name>
<fsummary></fsummary>
<type>
- <v></v>
+ <v>Fun = fun()</v>
+ <v>Acc0 = Acc = term()</v>
+ <v>Cache = <seealso marker="#type-session_cache_ref"> session_cache_ref() </seealso></v>
</type>
<desc>
<p>Calls <c>Fun(Elem, AccIn)</c> on successive elements of the
@@ -96,10 +109,11 @@
</func>
<func>
- <name>init(Args) -> opaque() </name>
+ <name since="OTP 18.0">init(Args) -> Cache </name>
<fsummary>Returns cache reference.</fsummary>
<type>
- <v>Args = proplists:proplist()</v>
+ <v>Cache = <seealso marker="#type-session_cache_ref"> session_cache_ref() </seealso></v>
+ <v>Args = <seealso marker="stdlib:proplists#type-proplist">proplists:proplist()</seealso></v>
</type>
<desc>
<p>Includes property <c>{role, client | server}</c>.
@@ -121,12 +135,12 @@
</func>
<func>
- <name>lookup(Cache, Key) -> Entry</name>
+ <name since="OTP R14B">lookup(Cache, Key) -> Entry</name>
<fsummary>Looks up a cache entry.</fsummary>
<type>
- <v>Cache = cache_ref()</v>
- <v>Key = key()</v>
- <v>Entry = session() | undefined</v>
+ <v>Cache = <seealso marker="#type-session_cache_ref"> session_cache_ref() </seealso></v>
+ <v>Key = <seealso marker="#type-session_cache_key">session_cache_key()</seealso> </v>
+ <v>Session = <seealso marker="#type-session">session()</seealso> | undefined</v>
</type>
<desc>
<p>Looks up a cache entry. Is to be callable from any
@@ -136,12 +150,12 @@
</func>
<func>
- <name>select_session(Cache, PartialKey) -> [session()]</name>
+ <name since="OTP R14B">select_session(Cache, PartialKey) -> [Session]</name>
<fsummary>Selects sessions that can be reused.</fsummary>
<type>
- <v>Cache = cache_ref()</v>
- <v>PartialKey = partialkey()</v>
- <v>Session = session()</v>
+ <v>Cache = <seealso marker="#type-session_cache_ref"> session_cache_ref() </seealso></v>
+ <v>PartialKey = <seealso marker="#type-partial_key"> partial_key() </seealso></v>
+ <v>Session = <seealso marker="#type-session">session()</seealso></v>
</type>
<desc>
<p>Selects sessions that can be reused. Is to be callable
@@ -151,10 +165,10 @@
</func>
<func>
- <name>size(Cache) -> integer()</name>
+ <name since="OTP 19.3">size(Cache) -> integer()</name>
<fsummary>Returns the number of sessions in the cache.</fsummary>
<type>
- <v>Cache = cache_ref()</v>
+ <v>Cache = <seealso marker="#type-session_cache_ref"> session_cache_ref() </seealso></v>
</type>
<desc>
<p>Returns the number of sessions in the cache. If size
@@ -166,11 +180,12 @@
</func>
<func>
- <name>terminate(Cache) -> _</name>
+ <name since="OTP R14B">terminate(Cache) -> _</name>
<fsummary>Called by the process that handles the cache when it
is about to terminate.</fsummary>
<type>
- <v>Cache = term() - as returned by init/0</v>
+ <v>Cache = <seealso marker="#type-session_cache_ref"> session_cache_ref() </seealso></v>
+ <d>As returned by init/0</d>
</type>
<desc>
<p>Takes care of possible cleanup that is needed when the
@@ -180,12 +195,12 @@
</func>
<func>
- <name>update(Cache, Key, Session) -> _</name>
+ <name since="OTP R14B">update(Cache, Key, Session) -> _</name>
<fsummary>Caches a new session or updates an already cached one.</fsummary>
<type>
- <v>Cache = cache_ref()</v>
- <v>Key = key()</v>
- <v>Session = session()</v>
+ <v>Cache = <seealso marker="#type-session_cache_ref"> session_cache_ref() </seealso></v>
+ <v>Key = <seealso marker="#type-session_cache_key">session_cache_key()</seealso> </v>
+ <v>Session = <seealso marker="#type-session">session()</seealso></v>
</type>
<desc>
<p>Caches a new session or updates an already cached one. Is
diff --git a/lib/ssl/doc/src/standards_compliance.xml b/lib/ssl/doc/src/standards_compliance.xml
new file mode 100644
index 0000000000..ca98385f85
--- /dev/null
+++ b/lib/ssl/doc/src/standards_compliance.xml
@@ -0,0 +1,2338 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2015</year>
+ <year>2019</year>
+ <holder>Ericsson AB, All Rights Reserved</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ The Initial Developer of the Original Code is Ericsson AB.
+ </legalnotice>
+
+ <title>Standards Compliance</title>
+ <prepared>OTP team</prepared>
+ <docno></docno>
+ <date>2019-03-20</date>
+ <rev>A</rev>
+ <file>standards_compliance.xml</file>
+ </header>
+
+ <section>
+ <title>Purpose</title>
+ <p>This section describes the current state of standards compliance of the ssl application.</p>
+ </section>
+
+ <section>
+ <title>Common (pre TLS 1.3)</title>
+ <list type="bulleted">
+ <item>For security reasons RSA key exchange cipher suites are no longer supported by default,
+ but can be configured. (OTP 21)
+ </item>
+ <item>For security reasons DES cipher suites are no longer supported by default,
+ but can be configured. (OTP 20)
+ </item>
+ <item>For security reasons 3DES cipher suites are no longer supported by default,
+ but can be configured. (OTP 21)
+ </item>
+ <item>Renegotiation Indication Extension <url href="http://www.ietf.org/rfc/rfc5746.txt">RFC 5746</url> is supported
+ </item>
+ <item>Ephemeral Diffie-Hellman cipher suites are supported,
+ but not Diffie Hellman Certificates cipher suites.
+ </item>
+ <item>Elliptic Curve cipher suites are supported if the Crypto
+ application supports it and named curves are used.
+ </item>
+ <item>Export cipher suites are not supported as the
+ U.S. lifted its export restrictions in early 2000.
+ </item>
+ <item>IDEA cipher suites are not supported as they have
+ become deprecated by the TLS 1.2 specification so it is not
+ motivated to implement them.
+ </item>
+ <item>Compression is not supported.
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Common</title>
+ <list type="bulleted">
+ <item>CRL validation is supported.</item>
+ <item>Policy certificate extensions are not supported.</item>
+ <item>'Server Name Indication' extension
+ (<url href="http://www.ietf.org/rfc/rfc6066.txt">RFC 6066</url>) is supported.</item>
+ <item>Application Layer Protocol Negotiation (ALPN) and its successor Next Protocol Negotiation (NPN) are supported. </item>
+ <item>It is possible to use Pre-Shared Key (PSK) and Secure Remote Password (SRP)
+ cipher suites, but they are not enabled by default.
+ </item>
+ </list>
+ </section>
+
+
+ <section>
+ <title>SSL 2.0</title>
+ <p>For security reasons SSL-2.0 is not supported. Interoperability with SSL-2.0 enabled clients dropped. (OTP 21)</p>
+ </section>
+
+ <section>
+ <title>SSL 3.0</title>
+ <p>For security reasons SSL-3.0 is no longer supported by default, but can be configured. (OTP 19)</p>
+ </section>
+
+ <section>
+ <title>TLS 1.0</title>
+ <p>For security reasons TLS-1.0 is no longer supported by default, but can be configured. (OTP 22)</p>
+ </section>
+
+ <section>
+ <title>TLS 1.1</title>
+ <p>For security reasons TLS-1.1 is no longer supported by default, but can be configured. (OTP 22)</p>
+ </section>
+
+ <section>
+ <title>TLS 1.2</title>
+ <p>Supported</p>
+ </section>
+
+ <section>
+ <title>DTLS 1.0</title>
+ <p>For security reasons DTLS-1.0 (based on TLS 1.1) is no longer supported by default, but can be configured. (OTP 22)</p>
+ </section>
+
+ <section>
+ <title>DTLS 1.2</title>
+ <p>Supported (based on TLS 1.2)</p>
+ </section>
+
+ <section>
+ <title>DTLS 1.3</title>
+ <p>Not yet supported</p>
+ </section>
+
+ <section>
+ <title>TLS 1.3</title>
+ <p>OTP-22 introduces basic support for TLS 1.3 on the server side. Basic functionality
+ covers a simple TLS 1.3 handshake with support of the mandatory extensions
+ (supported_groups, signature_algorithms, key_share, supported_versions and
+ signature_algorithms_cert). The server supports a selective set of cryptographic algorithms:</p>
+ <list type="bulleted">
+ <item>Key Exchange: ECDHE</item>
+ <item>Groups: all standard groups supported for the Diffie-Hellman key exchange</item>
+ <item>Ciphers: TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384,
+ TLS_CHACHA20_POLY1305_SHA256 and TLS_AES_128_CCM_SHA256</item>
+ <item>Signature Algorithms: RSA and RSA PSS</item>
+ <item>Certificates: currently only certificates with RSA keys are supported</item>
+ </list>
+ <p>Other notable features:</p>
+ <list type="bulleted">
+ <item>The server supports the HelloRetryRequest mechanism</item>
+ <item>PSK and session resumption not supported</item>
+ <item>Early data and 0-RTT not supported</item>
+ <item>Key and Initialization Vector Update not supported</item>
+ </list>
+ <p>For more detailed information see the
+ <seealso marker="#soc_table">Standards Compliance</seealso> below.</p>
+ <warning><p>Note that the client side is not yet functional. It is planned to be released
+ later in OTP-22.</p></warning>
+
+ <p> The following table describes the current state of standards compliance for TLS 1.3.</p>
+ <p>(<em>C</em> = Compliant, <em>NC</em> = Non-Compliant, <em>PC</em> = Partially-Compliant,
+ <em>NA</em> = Not Applicable)</p>
+ <marker id="soc_table"/>
+ <table>
+ <row>
+ <cell align="left" valign="middle"><em>Section</em></cell>
+ <cell align="left" valign="middle"><em>Feature</em></cell>
+ <cell align="left" valign="middle"><em>State</em></cell>
+ <cell align="left" valign="middle"><em>Since</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-1.2">
+ 1.3. Updates Affecting TLS 1.2
+ </url>
+ </cell>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">Version downgrade protection mechanism</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">RSASSA-PSS signature schemes</cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">supported_versions (ClientHello) extension</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">signature_algorithms_cert extension</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-2">
+ 2. Protocol Overview
+ </url>
+ </cell>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">(EC)DHE</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">PSK-only</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">PSK with (EC)DHE</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-2.1">
+ 2.1. Incorrect DHE share
+ </url>
+ </cell>
+ <cell align="left" valign="middle">HelloRetryRequest</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-2.2">
+ 2.2. Resumption and Pre-Shared Key (PSK)
+ </url>
+ </cell>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-2.3">
+ 2.3. 0-RTT Data
+ </url>
+ </cell>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.1.1">
+ 4.1.1. Cryptographic Negotiation
+ </url>
+ </cell>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">supported_groups extension</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">signature_algorithms extension</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">pre_shared_key extension</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.1.2">
+ 4.1.2. Client Hello
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Client</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">server_name (RFC6066)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">max_fragment_length (RFC6066)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">status_request (RFC6066)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">supported_groups (RFC7919)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">signature_algorithms (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">use_srtp (RFC5764)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">heartbeat (RFC6520)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">application_layer_protocol_negotiation (RFC7301)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">signed_certificate_timestamp (RFC6962)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">client_certificate_type (RFC7250)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">server_certificate_type (RFC7250)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">padding (RFC7685)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">key_share (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">pre_shared_key (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">psk_key_exchange_modes (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">early_data (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">cookie (RFC8446) </cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">supported_versions (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">certificate_authorities (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">oid_filters (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">post_handshake_auth (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">signature_algorithms_cert (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">server_name (RFC6066)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">max_fragment_length (RFC6066)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">status_request (RFC6066)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">supported_groups (RFC7919)</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">signature_algorithms (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">use_srtp (RFC5764)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">heartbeat (RFC6520)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">application_layer_protocol_negotiation (RFC7301)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">signed_certificate_timestamp (RFC6962)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">client_certificate_type (RFC7250)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">server_certificate_type (RFC7250)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">padding (RFC7685)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">key_share (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">pre_shared_key (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">psk_key_exchange_modes (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">early_data (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">cookie (RFC8446) </cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">supported_versions (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">certificate_authorities (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">oid_filters (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">post_handshake_auth (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">signature_algorithms_cert (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.1.3">
+ 4.1.3. Server Hello
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Client</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">Version downgrade protection</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">key_share (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">pre_shared_key (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">supported_versions (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">Version downgrade protection</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">key_share (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">pre_shared_key (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">supported_versions (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.1.4">
+ 4.1.4. Hello Retry Request
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">key_share (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">cookie (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">supported_versions (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.2.1">
+ 4.2.1. Supported Versions
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Client</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.2.2">
+ 4.2.2. Cookie
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Client</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.2.3">
+ 4.2.3. Signature Algorithms
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Client</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">rsa_pkcs1_sha256</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">rsa_pkcs1_sha384</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">rsa_pkcs1_sha512</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ecdsa_secp256r1_sha256</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ecdsa_secp384r1_sha384</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ecdsa_secp521r1_sha512</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">rsa_pss_rsae_sha256</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">rsa_pss_rsae_sha384</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">rsa_pss_rsae_sha512</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ed25519</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ed448</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">rsa_pss_pss_sha256</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">rsa_pss_pss_sha384</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">rsa_pss_pss_sha512</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">rsa_pkcs1_sha1</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ecdsa_sha1</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">rsa_pkcs1_sha256</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">rsa_pkcs1_sha384</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">rsa_pkcs1_sha512</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ecdsa_secp256r1_sha256</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ecdsa_secp384r1_sha384</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ecdsa_secp521r1_sha512</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">rsa_pss_rsae_sha256</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">rsa_pss_rsae_sha384</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">rsa_pss_rsae_sha512</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ed25519</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ed448</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">rsa_pss_pss_sha256</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">rsa_pss_pss_sha384</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">rsa_pss_pss_sha512</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">rsa_pkcs1_sha1</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ecdsa_sha1</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.2.4">
+ 4.2.4. Certificate Authorities
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Client</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.2.5">
+ 4.2.5. OID Filters
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Client</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.2.6">
+ 4.2.6. Post-Handshake Client Authentication
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Client</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.2.7">
+ 4.2.7. Supported Groups
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Client</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">secp256r1</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">secp384r1</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">secp521r1</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">x25519</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">x448</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ffdhe2048</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ffdhe3072</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ffdhe4096</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ffdhe6144</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ffdhe8192</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">secp256r1</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">secp384r1</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">secp521r1</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">x25519</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">x448</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ffdhe2048</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ffdhe3072</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ffdhe4096</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ffdhe6144</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ffdhe8192</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.2.8">
+ 4.2.8. Key Share
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Client</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.2.9">
+ 4.2.9. Pre-Shared Key Exchange Modes
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Client</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.2.10">
+ 4.2.10. Early Data Indication
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Client</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.2.11">
+ 4.2.11. Pre-Shared Key Extension
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Client</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.2.11.1">
+ 4.2.11.1. Ticket Age
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Client</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.2.11.2">
+ 4.2.11.2. PSK Binder
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Client</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.2.11.3">
+ 4.2.11.3. Processing Order
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Client</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.3.1">
+ 4.3.1. Encrypted Extensions
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Client</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">server_name (RFC6066)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">max_fragment_length (RFC6066)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">supported_groups (RFC7919)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">use_srtp (RFC5764)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">heartbeat (RFC6520)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">application_layer_protocol_negotiation (RFC7301)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">client_certificate_type (RFC7250)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">server_certificate_type (RFC7250)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">early_data (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">supported_versions (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">server_name (RFC6066)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">max_fragment_length (RFC6066)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">supported_groups (RFC7919)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">use_srtp (RFC5764)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">heartbeat (RFC6520)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">application_layer_protocol_negotiation (RFC7301)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">client_certificate_type (RFC7250)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">server_certificate_type (RFC7250)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">early_data (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">supported_versions (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.3.2">
+ 4.3.2. Certificate Request
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Client</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">status_request (RFC6066)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">signature_algorithms (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">signed_certificate_timestamp (RFC6962)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">certificate_authorities (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">oid_filters (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">signature_algorithms_cert (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">status_request (RFC6066)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">signature_algorithms (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">signed_certificate_timestamp (RFC6962)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">certificate_authorities (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">oid_filters (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">signature_algorithms_cert (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.4.1">
+ 4.4.1. The Transcript Hash
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.4.2">
+ 4.4.2. Certificate
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Client</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">status_request (RFC6066)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">signed_certificate_timestamp (RFC6962)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">status_request (RFC6066)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">signed_certificate_timestamp (RFC6962)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.4.2.1">
+ 4.4.2.1. OCSP Status and SCT Extensions
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Client</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.4.2.2">
+ 4.4.2.2. Server Certificate Selection
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Client</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">certificate type MUST be X.509v3</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">certificate's public key is compatible</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">The certificate MUST allow the key to be used for signing</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">server_name and certificate_authorities are used</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">certificate type MUST be X.509v3</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">certificate's public key is compatible</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">The certificate MUST allow the key to be used for signing</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">server_name and certificate_authorities are used</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.4.2.3">
+ 4.4.2.3. Client Certificate Selection
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.4.2.4">
+ 4.4.2.4. Receiving a Certificate Message
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Client</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.4.3">
+ 4.4.3. Certificate Verify
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Client</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.4.4">
+ 4.4.4. Finished
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Client</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.5">
+ 4.5. End of Early Data
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Client</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.6.1">
+ 4.6.1. New Session Ticket Message
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Client</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">early_data (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">early_data (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.6.2">
+ 4.6.2. Post-Handshake Authentication
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Client</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.6.3">
+ 4.6.3. Key and Initialization Vector Update
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Client</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-5.1">
+ 5.1. Record Layer
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">MUST NOT be interleaved with other record types</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">MUST NOT span key changes</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">MUST NOT send zero-length fragments</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">Alert messages MUST NOT be fragmented</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-5.2">
+ 5.2. Record Payload Protection
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-5.3">
+ 5.3. Per-Record Nonce
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-5.4">
+ 5.4. Record Padding
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">MAY choose to pad</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">MUST NOT send Handshake and Alert records that have a zero-length TLSInnerPlaintext.content</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">The padding sent is automatically verified</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-5.5">
+ 5.5. Limits on Key Usage
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-6.1">
+ 6.1. Closure Alerts
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">close_notify</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">user_cancelled</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-6.2">
+ 6.2. Error Alerts
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-7.1">
+ 7.1. Key Schedule
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-7.2">
+ 7.2. Updating Traffic Secrets
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-7.3">
+ 7.3. Traffic Key Calculation
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-7.5">
+ 7.5. Exporters
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-8">
+ 8. 0-RTT and Anti-Replay
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-8.1">
+ 8.1. Single-Use Tickets
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-8.2">
+ 8.2. Client Hello Recording
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-8.3">
+ 8.3. Freshness Checks
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-9.1">
+ 9.1. Mandatory-to-Implement Cipher Suites
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">MUST implement the TLS_AES_128_GCM_SHA256</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">SHOULD implement the TLS_AES_256_GCM_SHA384</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">SHOULD implement the TLS_CHACHA20_POLY1305_SHA256</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Digital signatures</em></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">MUST support rsa_pkcs1_sha256 (for certificates)</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">MUST support rsa_pss_rsae_sha256 (for CertificateVerify and certificates)</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">MUST support ecdsa_secp256r1_sha256</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Key Exchange</em></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">MUST support key exchange with secp256r1</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">SHOULD support key exchange with X25519</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-9.2">
+ 9.2. Mandatory-to-Implement Extensions
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">Supported Versions</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">Cookie</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">Signature Algorithms</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">Signature Algorithms Certificate</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">Negotiated Groups</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">Key Share</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">Server Name Indication</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>MUST send and use these extensions</em></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">"supported_versions" is REQUIRED for ClientHello, ServerHello and HelloRetryRequest</cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">"signature_algorithms" is REQUIRED for certificate authentication</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">"supported_groups" is REQUIRED for ClientHello messages using (EC)DHE key exchange</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">"key_share" is REQUIRED for (EC)DHE key exchange</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">"pre_shared_key" is REQUIRED for PSK key agreement</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">"psk_key_exchange_modes" is REQUIRED for PSK key agreement</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>TLS 1.3 ClientHello</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">If not containing a "pre_shared_key" extension, it MUST contain both a "signature_algorithms" extension and a "supported_groups" extension.</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">If containing a "supported_groups" extension, it MUST also contain a "key_share" extension, and vice versa. An empty KeyShare.client_shares vector is permitted.</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>TLS 1.3 ServerHello</em></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">MUST support the use of the "server_name" extension</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-9.3">
+ 9.3. Protocol Invariants
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>MUST correctly handle extensible fields</em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">A client sending a ClientHello MUST support all parameters advertised in it.</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">A middlebox which terminates a TLS connection MUST behave as a compliant TLS server</cell>
+ <cell align="left" valign="middle"><em>NA</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">A middlebox which forwards ClientHello parameters it does not understand MUST NOT process any messages beyond that ClientHello.</cell>
+ <cell align="left" valign="middle"><em>NA</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-B.4">
+ B.4. Cipher Suites
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">TLS_AES_128_GCM_SHA256</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">TLS_AES_256_GCM_SHA384</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">TLS_CHACHA20_POLY1305_SHA256</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">TLS_AES_128_CCM_SHA256</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">TLS_AES_128_CCM_8_SHA256</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-C.1">
+ C.1. Random Number Generation and Seeding
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-C.2">
+ C.2. Certificates and Authentication
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-C.3">
+ C.3. Implementation Pitfalls
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-C.4">
+ C.4. Client Tracking Prevention
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-C.5">
+ C.5. Unauthenticated Operation
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-D.1">
+ D.1. Negotiating with an Older Server
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-D.2">
+ D.2. Negotiating with an Older Client
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-D.3">
+ D.3. 0-RTT Backward Compatibility
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-D.4">
+ D.4. Middlebox Compatibility Mode
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-D.5">
+ D.5. Security Restrictions Related to Backward Compatibility
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+
+ <tcaption>Standards Compliance</tcaption>
+ </table>
+
+ </section>
+
+</chapter>
diff --git a/lib/ssl/doc/src/usersguide.xml b/lib/ssl/doc/src/usersguide.xml
index 23ccf668c3..b22b2456e4 100644
--- a/lib/ssl/doc/src/usersguide.xml
+++ b/lib/ssl/doc/src/usersguide.xml
@@ -38,6 +38,7 @@
<xi:include href="ssl_protocol.xml"/>
<xi:include href="using_ssl.xml"/>
<xi:include href="ssl_distribution.xml"/>
+ <xi:include href="standards_compliance.xml"/>
</part>
diff --git a/lib/ssl/doc/src/using_ssl.xml b/lib/ssl/doc/src/using_ssl.xml
index 775066ef7d..f2f9b66a31 100644
--- a/lib/ssl/doc/src/using_ssl.xml
+++ b/lib/ssl/doc/src/using_ssl.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2003</year><year>2016</year>
+ <year>2003</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -22,7 +22,7 @@
</legalnotice>
- <title>Using SSL API</title>
+ <title>Using SSL application API</title>
<prepared></prepared>
<responsible></responsible>
<docno></docno>
@@ -51,7 +51,7 @@
<section>
<title>Minimal Example</title>
- <note><p> The minimal setup is not the most secure setup of SSL.</p>
+ <note><p> The minimal setup is not the most secure setup of SSL/TLS/DTLS.</p>
</note>
<p>To set up client/server connections:</p>
@@ -60,27 +60,27 @@
<code type="erl">1 server> ssl:start().
ok</code>
- <p><em>Step 2:</em> Create an SSL listen socket:</p>
+ <p><em>Step 2:</em> Create an TLS listen socket: (To run DTLS add the option {protocol, dtls})</p>
<code type="erl">2 server> {ok, ListenSocket} =
ssl:listen(9999, [{certfile, "cert.pem"}, {keyfile, "key.pem"},{reuseaddr, true}]).
{ok,{sslsocket, [...]}}</code>
- <p><em>Step 3:</em> Do a transport accept on the SSL listen socket:</p>
- <code type="erl">3 server> {ok, Socket} = ssl:transport_accept(ListenSocket).
+ <p><em>Step 3:</em> Do a transport accept on the TLS listen socket:</p>
+ <code type="erl">3 server> {ok, TLSTransportSocket} = ssl:transport_accept(ListenSocket).
{ok,{sslsocket, [...]}}</code>
- <p><em>Step 4:</em> Start the client side:</p>
+ <p><em>Step 4:</em> Start the client side: </p>
<code type="erl">1 client> ssl:start().
ok</code>
-
+ <p> To run DTLS add the option {protocol, dtls} to third argument.</p>
<code type="erl">2 client> {ok, Socket} = ssl:connect("localhost", 9999, [], infinity).
{ok,{sslsocket, [...]}}</code>
- <p><em>Step 5:</em> Do the SSL handshake:</p>
- <code type="erl">4 server> ok = ssl:ssl_accept(Socket).
+ <p><em>Step 5:</em> Do the TLS handshake:</p>
+ <code type="erl">4 server> {ok, Socket} = ssl:handshake(TLSTransportSocket).
ok</code>
- <p><em>Step 6:</em> Send a message over SSL:</p>
+ <p><em>Step 6:</em> Send a message over TLS:</p>
<code type="erl">5 server> ssl:send(Socket, "foo").
ok</code>
@@ -92,7 +92,7 @@ ok</code>
</section>
<section>
- <title>Upgrade Example</title>
+ <title>Upgrade Example - TLS only </title>
<note><p>To upgrade a TCP/IP connection to an SSL connection, the
client and server must agree to do so. The agreement
@@ -125,24 +125,24 @@ ok</code>
<code type="erl">4 server> inet:setopts(Socket, [{active, false}]).
ok</code>
- <p><em>Step 6:</em> Do the SSL handshake:</p>
- <code type="erl">5 server> {ok, SSLSocket} = ssl:ssl_accept(Socket, [{cacertfile, "cacerts.pem"},
+ <p><em>Step 6:</em> Do the TLS handshake:</p>
+ <code type="erl">5 server> {ok, TLSSocket} = ssl:handshake(Socket, [{cacertfile, "cacerts.pem"},
{certfile, "cert.pem"}, {keyfile, "key.pem"}]).
{ok,{sslsocket,[...]}}</code>
- <p><em>Step 7:</em> Upgrade to an SSL connection. The client and server
+ <p><em>Step 7:</em> Upgrade to an TLS connection. The client and server
must agree upon the upgrade. The server must call
- <c>ssl:accept/2</c> before the client calls <c>ssl:connect/3.</c></p>
- <code type="erl">3 client>{ok, SSLSocket} = ssl:connect(Socket, [{cacertfile, "cacerts.pem"},
+ <c>ssl:handshake/2</c> before the client calls <c>ssl:connect/3.</c></p>
+ <code type="erl">3 client>{ok, TLSSocket} = ssl:connect(Socket, [{cacertfile, "cacerts.pem"},
{certfile, "cert.pem"}, {keyfile, "key.pem"}], infinity).
{ok,{sslsocket,[...]}}</code>
- <p><em>Step 8:</em> Send a message over SSL:</p>
- <code type="erl">4 client> ssl:send(SSLSocket, "foo").
+ <p><em>Step 8:</em> Send a message over TLS:</p>
+ <code type="erl">4 client> ssl:send(TLSSocket, "foo").
ok</code>
- <p><em>Step 9:</em> Set <c>active true</c> on the SSL socket:</p>
- <code type="erl">4 server> ssl:setopts(SSLSocket, [{active, true}]).
+ <p><em>Step 9:</em> Set <c>active true</c> on the TLS socket:</p>
+ <code type="erl">4 server> ssl:setopts(TLSSocket, [{active, true}]).
ok</code>
<p><em>Step 10:</em> Flush the shell message queue to see that the message
diff --git a/lib/ssl/examples/src/client_server.erl b/lib/ssl/examples/src/client_server.erl
index c150f43bff..8d68da12d5 100644
--- a/lib/ssl/examples/src/client_server.erl
+++ b/lib/ssl/examples/src/client_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -39,15 +39,15 @@ start() ->
%% Accept
{ok, ASock} = ssl:transport_accept(LSock),
- ok = ssl:ssl_accept(ASock),
+ {ok, SslSocket} = ssl:handshake(ASock),
io:fwrite("Accept: accepted.~n"),
- {ok, Cert} = ssl:peercert(ASock),
+ {ok, Cert} = ssl:peercert(SslSocket),
io:fwrite("Accept: peer cert:~n~p~n", [public_key:pkix_decode_cert(Cert, otp)]),
io:fwrite("Accept: sending \"hello\".~n"),
- ssl:send(ASock, "hello"),
- {error, closed} = ssl:recv(ASock, 0),
+ ssl:send(SslSocket, "hello"),
+ {error, closed} = ssl:recv(SslSocket, 0),
io:fwrite("Accept: detected closed.~n"),
- ssl:close(ASock),
+ ssl:close(SslSocket),
io:fwrite("Listen: closing and terminating.~n"),
ssl:close(LSock),
@@ -75,7 +75,7 @@ mk_opts(Role) ->
[{active, false},
{verify, 2},
{depth, 2},
+ {server_name_indication, disable},
{cacertfile, filename:join([Dir, Role, "cacerts.pem"])},
{certfile, filename:join([Dir, Role, "cert.pem"])},
{keyfile, filename:join([Dir, Role, "key.pem"])}].
-
diff --git a/lib/ssl/src/Makefile b/lib/ssl/src/Makefile
index 2e7df9792e..8dc76f2638 100644
--- a/lib/ssl/src/Makefile
+++ b/lib/ssl/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2016. All Rights Reserved.
+# Copyright Ericsson AB 1999-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -39,62 +39,80 @@ RELSYSDIR = $(RELEASE_PATH)/lib/ssl-$(VSN)
# ----------------------------------------------------
BEHAVIOUR_MODULES= \
- ssl_session_cache_api \
- ssl_crl_cache_api
+ ssl_crl_cache_api \
+ ssl_session_cache_api
+
MODULES= \
- ssl \
- tls \
- dtls \
- ssl_alert \
- ssl_app \
- ssl_sup \
- ssl_admin_sup\
- tls_connection_sup \
- ssl_connection_sup \
- ssl_listen_tracker_sup\
+ dtls_connection \
dtls_connection_sup \
- dtls_udp_listener\
- dtls_udp_sup \
- ssl_dist_sup\
- ssl_dist_admin_sup\
- ssl_dist_connection_sup\
+ dtls_handshake \
+ dtls_listener_sup \
+ dtls_packet_demux \
+ dtls_record \
+ dtls_socket \
+ dtls_v1 \
inet_tls_dist \
inet6_tls_dist \
- ssl_certificate\
- ssl_pkix_db\
+ ssl \
+ ssl_admin_sup \
+ ssl_alert \
+ ssl_app \
+ ssl_certificate \
ssl_cipher \
- ssl_srp_primes \
- tls_connection \
- dtls_connection \
+ ssl_cipher_format \
ssl_config \
ssl_connection \
- tls_handshake \
- dtls_handshake\
- ssl_handshake\
- ssl_manager \
- ssl_session \
- ssl_session_cache \
- ssl_pem_cache \
- ssl_crl\
+ ssl_connection_sup \
+ ssl_crl \
ssl_crl_cache \
ssl_crl_hash_dir \
- tls_socket \
- dtls_socket \
- tls_record \
- dtls_record \
+ ssl_dh_groups \
+ ssl_dist_admin_sup \
+ ssl_dist_connection_sup \
+ ssl_dist_sup \
+ ssl_handshake \
+ ssl_listen_tracker_sup \
+ ssl_logger \
+ ssl_manager \
+ ssl_pem_cache \
+ ssl_pkix_db \
ssl_record \
- ssl_v2 \
+ ssl_session \
+ ssl_session_cache \
+ ssl_srp_primes \
+ ssl_sup \
ssl_v3 \
- tls_v1 \
- dtls_v1 \
- ssl_tls_dist_proxy
+ tls_connection \
+ tls_connection_sup \
+ tls_connection_1_3 \
+ tls_handshake \
+ tls_handshake_1_3 \
+ tls_record \
+ tls_record_1_3 \
+ tls_sender \
+ tls_socket \
+ tls_v1
+
INTERNAL_HRL_FILES = \
- ssl_alert.hrl ssl_cipher.hrl \
- tls_connection.hrl dtls_connection.hrl ssl_connection.hrl \
- ssl_handshake.hrl tls_handshake.hrl dtls_handshake.hrl ssl_api.hrl ssl_internal.hrl \
- ssl_record.hrl tls_record.hrl dtls_record.hrl ssl_srp.hrl
+ dtls_connection.hrl \
+ dtls_handshake.hrl \
+ dtls_record.hrl \
+ ssl_alert.hrl \
+ ssl_api.hrl \
+ ssl_cipher.hrl \
+ ssl_connection.hrl \
+ ssl_handshake.hrl \
+ ssl_internal.hrl \
+ ssl_record.hrl \
+ ssl_srp.hrl \
+ tls_connection.hrl \
+ tls_handshake.hrl \
+ tls_handshake_1_3.hrl \
+ tls_record.hrl \
+ tls_record_1_3.hrl
+
ERL_FILES= \
$(MODULES:%=%.erl) \
@@ -113,6 +131,10 @@ APP_TARGET= $(EBIN)/$(APP_FILE)
APPUP_SRC= $(APPUP_FILE).src
APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
+DEPDIR=$(ERL_TOP)/lib/ssl/src/deps
+DEP_FILE=$(DEPDIR)/ssl.d
+$(shell mkdir -p $(dir $(DEP_FILE)) >/dev/null)
+
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
@@ -120,7 +142,7 @@ EXTRA_ERLC_FLAGS = +warn_unused_vars
ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/kernel/src \
-pz $(EBIN) \
-pz $(ERL_TOP)/lib/public_key/ebin \
- $(EXTRA_ERLC_FLAGS) -DVSN=\"$(VSN)\"
+ $(EXTRA_ERLC_FLAGS)
# ----------------------------------------------------
@@ -129,11 +151,22 @@ ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/kernel/src \
$(TARGET_FILES): $(BEHAVIOUR_TARGET_FILES)
-debug opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
+$(DEP_FILE): $(ERL_FILES)
+ $(gen_verbose)erlc -M $(ERL_FILES) \
+ | sed "s@$(ERL_TOP)@../../..@g" \
+ | sed "s/\.$(EMULATOR)/\.$$\(EMULATOR\)/" \
+ | sed 's@^dtls_@$$(EBIN)/dtls_@' \
+ | sed 's@^inet_@$$(EBIN)/inet_@' \
+ | sed 's@^ssl_@$$(EBIN)/ssl_@' \
+ | sed 's@^tls_@$$(EBIN)/tls_@' \
+ > $(DEP_FILE)
+
+debug opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(DEP_FILE)
clean:
rm -f $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(BEHAVIOUR_TARGET_FILES)
rm -f errs core *~
+ rm -rf $(DEPDIR)
$(APP_TARGET): $(APP_SRC) ../vsn.mk
$(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
@@ -143,7 +176,6 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
docs:
-
# ----------------------------------------------------
# Release Target
# ----------------------------------------------------
@@ -161,22 +193,4 @@ release_docs_spec:
# ----------------------------------------------------
# Dependencies
# ----------------------------------------------------
-$(EBIN)/inet_tls_dist.$(EMULATOR): ../../kernel/include/net_address.hrl ../../kernel/include/dist.hrl ../../kernel/include/dist_util.hrl
-$(EBIN)/tls.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl ssl_handshake.hrl ../../public_key/include/public_key.hrl
-$(EBIN)/ssl_alert.$(EMULATOR): ssl_alert.hrl ssl_record.hrl
-$(EBIN)/ssl_certificate.$(EMULATOR): ssl_internal.hrl ssl_alert.hrl ssl_handshake.hrl ../../public_key/include/public_key.hrl
-$(EBIN)/ssl_certificate_db.$(EMULATOR): ssl_internal.hrl ../../public_key/include/public_key.hrl ../../kernel/include/file.hrl
-$(EBIN)/ssl_cipher.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_alert.hrl ../../public_key/include/public_key.hrl
-$(EBIN)/tls_connection.$(EMULATOR): ssl_internal.hrl tls_connection.hrl tls_record.hrl ssl_cipher.hrl tls_handshake.hrl ssl_alert.hrl ../../public_key/include/public_key.hrl
-$(EBIN)/dtls_connection.$(EMULATOR): ssl_internal.hrl dtls_connection.hrl dtls_record.hrl ssl_cipher.hrl dtls_handshake.hrl ssl_alert.hrl ../../public_key/include/public_key.hrl
-$(EBIN)/tls_handshake.$(EMULATOR): ssl_internal.hrl tls_record.hrl ssl_cipher.hrl tls_handshake.hrl ssl_alert.hrl ../../public_key/include/public_key.hrl
-$(EBIN)/tls_handshake.$(EMULATOR): ssl_internal.hrl ssl_connection.hrl ssl_record.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_alert.hrl ../../public_key/include/public_key.hrl
-$(EBIN)/ssl_manager.$(EMULATOR): ssl_internal.hrl ssl_handshake.hrl ../../kernel/include/file.hrl
-$(EBIN)/ssl_record.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_alert.hrl
-$(EBIN)/ssl_session.$(EMULATOR): ssl_internal.hrl ssl_handshake.hrl
-$(EBIN)/ssl_session_cache.$(EMULATOR): ssl_internal.hrl ssl_handshake.hrl
-$(EBIN)/ssl_session_cache_api.$(EMULATOR): ssl_internal.hrl ssl_handshake.hrl
-$(EBIN)/ssl_ssl3.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl
-$(EBIN)/ssl_tls1.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl
-$(EBIN)/ssl_cache.$(EMULATOR): ssl_cache.erl ssl_internal.hrl ../../public_key/include/public_key.hrl
-
+-include $(DEP_FILE)
diff --git a/lib/ssl/src/dtls.erl b/lib/ssl/src/dtls.erl
deleted file mode 100644
index cd705152a8..0000000000
--- a/lib/ssl/src/dtls.erl
+++ /dev/null
@@ -1,113 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
-
-%%% Purpose : Reflect DTLS specific API options (fairly simple wrapper at the moment)
-%% First implementation will support DTLS connections only in a "TLS/TCP like way"
-
--module(dtls).
-
--include("ssl_api.hrl").
--include("ssl_internal.hrl").
-
--export([connect/2, connect/3, listen/2, accept/1, accept/2,
- handshake/1, handshake/2, handshake/3]).
-
-%%--------------------------------------------------------------------
-%%
-%% Description: Connect to a DTLS server.
-%%--------------------------------------------------------------------
-
--spec connect(host() | port(), [connect_option()]) -> {ok, #sslsocket{}} |
- {error, reason()}.
-
-connect(Socket, Options) when is_port(Socket) ->
- connect(Socket, Options, infinity).
-
--spec connect(host() | port(), [connect_option()] | inet:port_number(),
- timeout() | list()) ->
- {ok, #sslsocket{}} | {error, reason()}.
-
-connect(Socket, SslOptions, Timeout) when is_port(Socket) ->
- DTLSOpts = [{protocol, dtls} | SslOptions],
- ssl:connect(Socket, DTLSOpts, Timeout);
-connect(Host, Port, Options) ->
- connect(Host, Port, Options, infinity).
-
--spec connect(host() | port(), inet:port_number(), list(), timeout()) ->
- {ok, #sslsocket{}} | {error, reason()}.
-
-connect(Host, Port, Options, Timeout) ->
- DTLSOpts = [{protocol, dtls} | Options],
- ssl:connect(Host, Port, DTLSOpts, Timeout).
-
-%%--------------------------------------------------------------------
--spec listen(inet:port_number(), [listen_option()]) ->{ok, #sslsocket{}} | {error, reason()}.
-
-%%
-%% Description: Creates an ssl listen socket.
-%%--------------------------------------------------------------------
-listen(Port, Options) ->
- DTLSOpts = [{protocol, dtls} | Options],
- ssl:listen(Port, DTLSOpts).
-
-%%--------------------------------------------------------------------
-%%
-%% Description: Performs transport accept on an ssl listen socket
-%%--------------------------------------------------------------------
--spec accept(#sslsocket{}) -> {ok, #sslsocket{}} |
- {error, reason()}.
-accept(ListenSocket) ->
- accept(ListenSocket, infinity).
-
--spec accept(#sslsocket{}, timeout()) -> {ok, #sslsocket{}} |
- {error, reason()}.
-accept(Socket, Timeout) ->
- ssl:transport_accept(Socket, Timeout).
-
-%%--------------------------------------------------------------------
-%%
-%% Description: Performs accept on an ssl listen socket. e.i. performs
-%% ssl handshake.
-%%--------------------------------------------------------------------
-
--spec handshake(#sslsocket{}) -> ok | {error, reason()}.
-
-handshake(ListenSocket) ->
- handshake(ListenSocket, infinity).
-
-
--spec handshake(#sslsocket{} | port(), timeout()| [ssl_option()
- | transport_option()]) ->
- ok | {ok, #sslsocket{}} | {error, reason()}.
-
-handshake(#sslsocket{} = Socket, Timeout) ->
- ssl:ssl_accept(Socket, Timeout);
-
-handshake(ListenSocket, SslOptions) when is_port(ListenSocket) ->
- handshake(ListenSocket, SslOptions, infinity).
-
-
--spec handshake(port(), [ssl_option()| transport_option()], timeout()) ->
- {ok, #sslsocket{}} | {error, reason()}.
-
-handshake(Socket, SslOptions, Timeout) when is_port(Socket) ->
- ssl:ssl_accept(Socket, SslOptions, Timeout).
diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl
index 03725089dd..e070006900 100644
--- a/lib/ssl/src/dtls_connection.erl
+++ b/lib/ssl/src/dtls_connection.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,30 +32,30 @@
-include("ssl_internal.hrl").
-include("ssl_srp.hrl").
-include_lib("public_key/include/public_key.hrl").
+-include_lib("kernel/include/logger.hrl").
%% Internal application API
%% Setup
--export([start_fsm/8, start_link/7, init/1]).
+-export([start_fsm/8, start_link/7, init/1, pids/1]).
%% State transition handling
--export([next_record/1, next_event/3, next_event/4, handle_common_event/4]).
+-export([next_event/3, next_event/4, handle_protocol_record/3]).
%% Handshake handling
-export([renegotiate/2, send_handshake/2,
queue_handshake/2, queue_change_cipher/2,
- reinit_handshake_data/1, select_sni_extension/1, empty_connection_state/2]).
+ reinit/1, reinit_handshake_data/1, select_sni_extension/1, empty_connection_state/2]).
%% Alert and close handling
--export([encode_alert/3,send_alert/2, close/5, protocol_name/0]).
+-export([encode_alert/3, send_alert/2, send_alert_in_connection/2, close/5, protocol_name/0]).
%% Data handling
--export([encode_data/3, passive_receive/2, next_record_if_active/1,
- send/3, socket/5, setopts/3, getopts/3]).
+-export([next_record/1, socket/4, setopts/3, getopts/3]).
%% gen_statem state functions
-export([init/3, error/3, downgrade/3, %% Initiation and take down states
- hello/3, certify/3, cipher/3, abbreviated/3, %% Handshake states
+ hello/3, user_hello/3, certify/3, cipher/3, abbreviated/3, %% Handshake states
connection/3]).
%% gen_statem callbacks
-export([callback_mode/0, terminate/3, code_change/4, format_status/2]).
@@ -67,21 +67,20 @@
%% Setup
%%====================================================================
start_fsm(Role, Host, Port, Socket, {#ssl_options{erl_dist = false},_, Tracker} = Opts,
- User, {CbModule, _,_, _} = CbInfo,
+ User, {CbModule, _, _, _, _} = CbInfo,
Timeout) ->
try
{ok, Pid} = dtls_connection_sup:start_child([Role, Host, Port, Socket,
Opts, User, CbInfo]),
- {ok, SslSocket} = ssl_connection:socket_control(?MODULE, Socket, Pid, CbModule, Tracker),
- ok = ssl_connection:handshake(SslSocket, Timeout),
- {ok, SslSocket}
+ {ok, SslSocket} = ssl_connection:socket_control(?MODULE, Socket, [Pid], CbModule, Tracker),
+ ssl_connection:handshake(SslSocket, Timeout)
catch
error:{badmatch, {error, _} = Error} ->
Error
end.
%%--------------------------------------------------------------------
--spec start_link(atom(), host(), inet:port_number(), port(), list(), pid(), tuple()) ->
+-spec start_link(atom(), ssl:host(), inet:port_number(), port(), list(), pid(), tuple()) ->
{ok, pid()} | ignore | {error, reason()}.
%%
%% Description: Creates a gen_statem process which calls Module:init/1 to
@@ -92,20 +91,27 @@ start_link(Role, Host, Port, Socket, Options, User, CbInfo) ->
init([Role, Host, Port, Socket, Options, User, CbInfo]) ->
process_flag(trap_exit, true),
- State0 = initial_state(Role, Host, Port, Socket, Options, User, CbInfo),
+ State0 = #state{protocol_specific = Map} = initial_state(Role, Host, Port, Socket, Options, User, CbInfo),
try
State = ssl_connection:ssl_config(State0#state.ssl_options, Role, State0),
gen_statem:enter_loop(?MODULE, [], init, State)
catch
throw:Error ->
- gen_statem:enter_loop(?MODULE, [], error, {Error,State0})
+ EState = State0#state{protocol_specific = Map#{error => Error}},
+ gen_statem:enter_loop(?MODULE, [], error, EState)
end.
+
+pids(_) ->
+ [self()].
+
%%====================================================================
%% State transition handling
%%====================================================================
-next_record(#state{unprocessed_handshake_events = N} = State) when N > 0 ->
- {no_record, State#state{unprocessed_handshake_events = N-1}};
-
+next_record(#state{handshake_env =
+ #handshake_env{unprocessed_handshake_events = N} = HsEnv}
+ = State) when N > 0 ->
+ {no_record, State#state{handshake_env =
+ HsEnv#handshake_env{unprocessed_handshake_events = N-1}}};
next_record(#state{protocol_buffers =
#protocol_buffers{dtls_cipher_texts = [#ssl_tls{epoch = Epoch} = CT | Rest]}
= Buffers,
@@ -137,18 +143,20 @@ next_record(#state{protocol_buffers =
next_record(State#state{protocol_buffers =
Buffers#protocol_buffers{dtls_cipher_texts = Rest},
connection_states = ConnectionStates});
-next_record(#state{role = server,
- socket = {Listener, {Client, _}},
- transport_cb = gen_udp} = State) ->
- dtls_udp_listener:active_once(Listener, Client, self()),
+next_record(#state{static_env = #static_env{role = server,
+ socket = {Listener, {Client, _}}}} = State) ->
+ dtls_packet_demux:active_once(Listener, Client, self()),
{no_record, State};
-next_record(#state{role = client,
- socket = {_Server, Socket} = DTLSSocket,
- close_tag = CloseTag,
- transport_cb = Transport} = State) ->
- case dtls_socket:setopts(Transport, Socket, [{active,once}]) of
+next_record(#state{protocol_specific = #{active_n_toggle := true,
+ active_n := N} = ProtocolSpec,
+ static_env = #static_env{role = client,
+ socket = {_Server, Socket} = DTLSSocket,
+ close_tag = CloseTag,
+ transport_cb = Transport}} = State) ->
+ case dtls_socket:setopts(Transport, Socket, [{active,N}]) of
ok ->
- {no_record, State};
+ {no_record, State#state{protocol_specific =
+ ProtocolSpec#{active_n_toggle => false}}};
_ ->
self() ! {CloseTag, DTLSSocket},
{no_record, State}
@@ -159,9 +167,9 @@ next_record(State) ->
next_event(StateName, Record, State) ->
next_event(StateName, Record, State, []).
-next_event(connection = StateName, no_record,
+next_event(StateName, no_record,
#state{connection_states = #{current_read := #{epoch := CurrentEpoch}}} = State0, Actions) ->
- case next_record_if_active(State0) of
+ case next_record(State0) of
{no_record, State} ->
ssl_connection:hibernate_after(StateName, State, Actions);
{#ssl_tls{epoch = CurrentEpoch,
@@ -175,23 +183,21 @@ next_event(connection = StateName, no_record,
{#ssl_tls{epoch = Epoch,
type = ?HANDSHAKE,
version = _Version}, State1} = _Record when Epoch == CurrentEpoch-1 ->
- {State2, MoreActions} = send_handshake_flight(State1, CurrentEpoch),
- {NextRecord, State} = next_record(State2),
- next_event(StateName, NextRecord, State, Actions ++ MoreActions);
+ {State, MoreActions} = send_handshake_flight(State1, CurrentEpoch),
+ next_event(StateName, no_record, State, Actions ++ MoreActions);
%% From FLIGHT perspective CHANGE_CIPHER_SPEC is treated as a handshake
{#ssl_tls{epoch = Epoch,
type = ?CHANGE_CIPHER_SPEC,
version = _Version}, State1} = _Record when Epoch == CurrentEpoch-1 ->
- {State2, MoreActions} = send_handshake_flight(State1, CurrentEpoch),
- {NextRecord, State} = next_record(State2),
- next_event(StateName, NextRecord, State, Actions ++ MoreActions);
+ {State, MoreActions} = send_handshake_flight(State1, CurrentEpoch),
+ next_event(StateName, no_record, State, Actions ++ MoreActions);
{#ssl_tls{epoch = _Epoch,
- version = _Version}, State1} ->
+ version = _Version}, State} ->
%% TODO maybe buffer later epoch
- {Record, State} = next_record(State1),
- next_event(StateName, Record, State, Actions);
+ next_event(StateName, no_record, State, Actions);
{#alert{} = Alert, State} ->
- {next_state, StateName, State, [{next_event, internal, Alert} | Actions]}
+ Version = State#state.connection_env#connection_env.negotiated_version,
+ handle_own_alert(Alert, Version, StateName, State)
end;
next_event(connection = StateName, Record,
#state{connection_states = #{current_read := #{epoch := CurrentEpoch}}} = State0, Actions) ->
@@ -207,24 +213,20 @@ next_event(connection = StateName, Record,
#ssl_tls{epoch = Epoch,
type = ?HANDSHAKE,
version = _Version} when Epoch == CurrentEpoch-1 ->
- {State1, MoreActions} = send_handshake_flight(State0, CurrentEpoch),
- {NextRecord, State} = next_record(State1),
- next_event(StateName, NextRecord, State, Actions ++ MoreActions);
+ {State, MoreActions} = send_handshake_flight(State0, CurrentEpoch),
+ next_event(StateName, no_record, State, Actions ++ MoreActions);
%% From FLIGHT perspective CHANGE_CIPHER_SPEC is treated as a handshake
#ssl_tls{epoch = Epoch,
type = ?CHANGE_CIPHER_SPEC,
version = _Version} when Epoch == CurrentEpoch-1 ->
- {State1, MoreActions} = send_handshake_flight(State0, CurrentEpoch),
- {NextRecord, State} = next_record(State1),
- next_event(StateName, NextRecord, State, Actions ++ MoreActions);
+ {State, MoreActions} = send_handshake_flight(State0, CurrentEpoch),
+ next_event(StateName, no_record, State, Actions ++ MoreActions);
_ ->
next_event(StateName, no_record, State0, Actions)
end;
next_event(StateName, Record,
#state{connection_states = #{current_read := #{epoch := CurrentEpoch}}} = State0, Actions) ->
case Record of
- no_record ->
- {next_state, StateName, State0, Actions};
#ssl_tls{epoch = CurrentEpoch,
version = Version} = Record ->
State = dtls_version(StateName, Version, State0),
@@ -233,44 +235,51 @@ next_event(StateName, Record,
#ssl_tls{epoch = _Epoch,
version = _Version} = _Record ->
%% TODO maybe buffer later epoch
- {Record, State} = next_record(State0),
- next_event(StateName, Record, State, Actions);
+ next_event(StateName, no_record, State0, Actions);
#alert{} = Alert ->
- {next_state, StateName, State0, [{next_event, internal, Alert} | Actions]}
+ Version = State0#state.connection_env#connection_env.negotiated_version,
+ handle_own_alert(Alert, Version, StateName, State0)
end.
-handle_common_event(internal, #alert{} = Alert, StateName,
- #state{negotiated_version = Version} = State) ->
- handle_own_alert(Alert, Version, StateName, State);
+%%% DTLS record protocol level application data messages
+
+handle_protocol_record(#ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, StateName0, State0) ->
+ case ssl_connection:read_application_data(Data, State0) of
+ {stop, _, _} = Stop->
+ Stop;
+ {Record, State1} ->
+ {next_state, StateName, State, Actions} = next_event(StateName0, Record, State1),
+ ssl_connection:hibernate_after(StateName, State, Actions)
+ end;
%%% DTLS record protocol level handshake messages
-handle_common_event(internal, #ssl_tls{type = ?HANDSHAKE,
+handle_protocol_record(#ssl_tls{type = ?HANDSHAKE,
fragment = Data},
StateName,
- #state{protocol_buffers = Buffers0,
- negotiated_version = Version} = State0) ->
+ #state{protocol_buffers = Buffers0,
+ connection_env = #connection_env{negotiated_version = Version},
+ ssl_options = Options} = State) ->
try
- case dtls_handshake:get_dtls_handshake(Version, Data, Buffers0) of
+ case dtls_handshake:get_dtls_handshake(Version, Data, Buffers0, Options) of
{[], Buffers} ->
- {Record, State} = next_record(State0#state{protocol_buffers = Buffers}),
- next_event(StateName, Record, State);
+ next_event(StateName, no_record, State#state{protocol_buffers = Buffers});
{Packets, Buffers} ->
- State = State0#state{protocol_buffers = Buffers},
+ HsEnv = State#state.handshake_env,
Events = dtls_handshake_events(Packets),
{next_state, StateName,
- State#state{unprocessed_handshake_events = unprocessed_events(Events)}, Events}
+ State#state{protocol_buffers = Buffers,
+ handshake_env =
+ HsEnv#handshake_env{unprocessed_handshake_events
+ = unprocessed_events(Events)}}, Events}
end
catch throw:#alert{} = Alert ->
- handle_own_alert(Alert, Version, StateName, State0)
+ handle_own_alert(Alert, Version, StateName, State)
end;
-%%% DTLS record protocol level application data messages
-handle_common_event(internal, #ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, StateName, State) ->
- {next_state, StateName, State, [{next_event, internal, {application_data, Data}}]};
%%% DTLS record protocol level change cipher messages
-handle_common_event(internal, #ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = Data}, StateName, State) ->
+handle_protocol_record(#ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = Data}, StateName, State) ->
{next_state, StateName, State, [{next_event, internal, #change_cipher_spec{type = Data}}]};
%%% DTLS record protocol level Alert messages
-handle_common_event(internal, #ssl_tls{type = ?ALERT, fragment = EncAlerts}, StateName,
- #state{negotiated_version = Version} = State) ->
+handle_protocol_record(#ssl_tls{type = ?ALERT, fragment = EncAlerts}, StateName,
+ #state{connection_env = #connection_env{negotiated_version = Version}} = State) ->
case decode_alerts(EncAlerts) of
Alerts = [_|_] ->
handle_alerts(Alerts, {next_state, StateName, State});
@@ -278,62 +287,75 @@ handle_common_event(internal, #ssl_tls{type = ?ALERT, fragment = EncAlerts}, Sta
handle_own_alert(Alert, Version, StateName, State)
end;
%% Ignore unknown TLS record level protocol messages
-handle_common_event(internal, #ssl_tls{type = _Unknown}, StateName, State) ->
- {next_state, StateName, State}.
+handle_protocol_record(#ssl_tls{type = _Unknown}, StateName, State) ->
+ {next_state, StateName, State, []}.
%%====================================================================
%% Handshake handling
%%====================================================================
-renegotiate(#state{role = client} = State, Actions) ->
+renegotiate(#state{static_env = #static_env{role = client}} = State0, Actions) ->
%% Handle same way as if server requested
%% the renegotiation
+ State = reinit_handshake_data(State0),
{next_state, connection, State,
[{next_event, internal, #hello_request{}} | Actions]};
-renegotiate(#state{role = server} = State0, Actions) ->
+renegotiate(#state{static_env = #static_env{role = server}} = State0, Actions) ->
HelloRequest = ssl_handshake:hello_request(),
State1 = prepare_flight(State0),
- {State2, MoreActions} = send_handshake(HelloRequest, State1),
- {Record, State} = next_record(State2),
- next_event(hello, Record, State, Actions ++ MoreActions).
+ {State, MoreActions} = send_handshake(HelloRequest, State1),
+ next_event(hello, no_record, State, Actions ++ MoreActions).
send_handshake(Handshake, #state{connection_states = ConnectionStates} = State) ->
#{epoch := Epoch} = ssl_record:current_connection_state(ConnectionStates, write),
send_handshake_flight(queue_handshake(Handshake, State), Epoch).
-queue_handshake(Handshake0, #state{tls_handshake_history = Hist0,
- negotiated_version = Version,
+queue_handshake(Handshake0, #state{handshake_env = #handshake_env{tls_handshake_history = Hist0} = HsEnv,
+ connection_env = #connection_env{negotiated_version = Version},
flight_buffer = #{handshakes := HsBuffer0,
change_cipher_spec := undefined,
- next_sequence := Seq} = Flight0} = State) ->
+ next_sequence := Seq} = Flight0,
+ ssl_options = SslOpts} = State) ->
Handshake = dtls_handshake:encode_handshake(Handshake0, Version, Seq),
Hist = update_handshake_history(Handshake0, Handshake, Hist0),
+ ssl_logger:debug(SslOpts#ssl_options.log_level, outbound, 'handshake', Handshake0),
+
State#state{flight_buffer = Flight0#{handshakes => [Handshake | HsBuffer0],
next_sequence => Seq +1},
- tls_handshake_history = Hist};
+ handshake_env = HsEnv#handshake_env{tls_handshake_history = Hist}};
-queue_handshake(Handshake0, #state{tls_handshake_history = Hist0,
- negotiated_version = Version,
+queue_handshake(Handshake0, #state{handshake_env = #handshake_env{tls_handshake_history = Hist0} = HsEnv,
+ connection_env = #connection_env{negotiated_version = Version},
flight_buffer = #{handshakes_after_change_cipher_spec := Buffer0,
- next_sequence := Seq} = Flight0} = State) ->
+ next_sequence := Seq} = Flight0,
+ ssl_options = SslOpts} = State) ->
Handshake = dtls_handshake:encode_handshake(Handshake0, Version, Seq),
Hist = update_handshake_history(Handshake0, Handshake, Hist0),
+ ssl_logger:debug(SslOpts#ssl_options.log_level, outbound, 'handshake', Handshake0),
+
State#state{flight_buffer = Flight0#{handshakes_after_change_cipher_spec => [Handshake | Buffer0],
next_sequence => Seq +1},
- tls_handshake_history = Hist}.
+ handshake_env = HsEnv#handshake_env{tls_handshake_history = Hist}}.
queue_change_cipher(ChangeCipher, #state{flight_buffer = Flight,
connection_states = ConnectionStates0} = State) ->
ConnectionStates =
- dtls_record:next_epoch(ConnectionStates0, write),
+ dtls_record:next_epoch(ConnectionStates0, write),
State#state{flight_buffer = Flight#{change_cipher_spec => ChangeCipher},
connection_states = ConnectionStates}.
-reinit_handshake_data(#state{protocol_buffers = Buffers} = State) ->
- State#state{premaster_secret = undefined,
- public_key_info = undefined,
- tls_handshake_history = ssl_handshake:init_handshake_history(),
- flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT},
+
+reinit(State) ->
+ %% To be API compatible with TLS NOOP here
+ reinit_handshake_data(State).
+reinit_handshake_data(#state{static_env = #static_env{data_tag = DataTag},
+ protocol_buffers = Buffers,
+ protocol_specific = PS,
+ handshake_env = HsEnv} = State) ->
+ State#state{handshake_env = HsEnv#handshake_env{tls_handshake_history = ssl_handshake:init_handshake_history(),
+ public_key_info = undefined,
+ premaster_secret = undefined},
+ protocol_specific = PS#{flight_state => initial_flight_state(DataTag)},
flight_buffer = new_flight(),
protocol_buffers =
Buffers#protocol_buffers{
@@ -342,8 +364,8 @@ reinit_handshake_data(#state{protocol_buffers = Buffers} = State) ->
dtls_handshake_later_fragments = []
}}.
-select_sni_extension(#client_hello{extensions = HelloExtensions}) ->
- HelloExtensions#hello_extensions.sni;
+select_sni_extension(#client_hello{extensions = #{sni := SNI}}) ->
+ SNI;
select_sni_extension(_) ->
undefined.
@@ -357,15 +379,22 @@ empty_connection_state(ConnectionEnd, BeastMitigation) ->
encode_alert(#alert{} = Alert, Version, ConnectionStates) ->
dtls_record:encode_alert_record(Alert, Version, ConnectionStates).
-send_alert(Alert, #state{negotiated_version = Version,
- socket = Socket,
- transport_cb = Transport,
- connection_states = ConnectionStates0} = State0) ->
+send_alert(Alert, #state{static_env = #static_env{socket = Socket,
+ transport_cb = Transport},
+
+ connection_env = #connection_env{negotiated_version = Version},
+ connection_states = ConnectionStates0,
+ ssl_options = SslOpts} = State0) ->
{BinMsg, ConnectionStates} =
encode_alert(Alert, Version, ConnectionStates0),
send(Transport, Socket, BinMsg),
+ ssl_logger:debug(SslOpts#ssl_options.log_level, outbound, 'record', BinMsg),
State0#state{connection_states = ConnectionStates}.
+send_alert_in_connection(Alert, State) ->
+ _ = send_alert(Alert, State),
+ ok.
+
close(downgrade, _,_,_,_) ->
ok;
%% Other
@@ -379,33 +408,13 @@ protocol_name() ->
%% Data handling
%%====================================================================
-encode_data(Data, Version, ConnectionStates0)->
- dtls_record:encode_data(Data, Version, ConnectionStates0).
-
-passive_receive(State0 = #state{user_data_buffer = Buffer}, StateName) ->
- case Buffer of
- <<>> ->
- {Record, State} = next_record(State0),
- next_event(StateName, Record, State);
- _ ->
- {Record, State} = ssl_connection:read_application_data(<<>>, State0),
- next_event(StateName, Record, State)
- end.
-next_record_if_active(State =
- #state{socket_options =
- #socket_options{active = false}}) ->
- {no_record ,State};
-
-next_record_if_active(State) ->
- next_record(State).
+send(Transport, {Listener, Socket}, Data) when is_pid(Listener) -> % Server socket
+ dtls_socket:send(Transport, Socket, Data);
+send(Transport, Socket, Data) -> % Client socket
+ dtls_socket:send(Transport, Socket, Data).
-send(Transport, {_, {{_,_}, _} = Socket}, Data) ->
- send(Transport, Socket, Data);
-send(Transport, Socket, Data) ->
- dtls_socket:send(Transport, Socket, Data).
-
-socket(Pid, Transport, Socket, Connection, _) ->
- dtls_socket:socket(Pid, Transport, Socket, Connection).
+socket(Pid, Transport, Socket, _Tracker) ->
+ dtls_socket:socket(Pid, Transport, Socket, ?MODULE).
setopts(Transport, Socket, Other) ->
dtls_socket:setopts(Transport, Socket, Other).
@@ -424,44 +433,38 @@ getopts(Transport, Socket, Tag) ->
init(enter, _, State) ->
{keep_state, State};
init({call, From}, {start, Timeout},
- #state{host = Host, port = Port, role = client,
+ #state{static_env = #static_env{host = Host,
+ port = Port,
+ role = client,
+ session_cache = Cache,
+ session_cache_cb = CacheCb},
+ handshake_env = #handshake_env{renegotiation = {Renegotiation, _}},
+ connection_env = CEnv,
ssl_options = SslOpts,
session = #session{own_certificate = Cert} = Session0,
- connection_states = ConnectionStates0,
- renegotiation = {Renegotiation, _},
- session_cache = Cache,
- session_cache_cb = CacheCb
+ connection_states = ConnectionStates0
} = State0) ->
- Timer = ssl_connection:start_or_recv_cancel_timer(Timeout, From),
Hello = dtls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
Cache, CacheCb, Renegotiation, Cert),
Version = Hello#client_hello.client_version,
HelloVersion = dtls_record:hello_version(Version, SslOpts#ssl_options.versions),
- State1 = prepare_flight(State0#state{negotiated_version = Version}),
- {State2, Actions} = send_handshake(Hello, State1#state{negotiated_version = HelloVersion}),
- State3 = State2#state{negotiated_version = Version, %% Requested version
+ State1 = prepare_flight(State0#state{connection_env = CEnv#connection_env{negotiated_version = Version}}),
+ {State2, Actions} = send_handshake(Hello, State1#state{connection_env = CEnv#connection_env{negotiated_version = HelloVersion}}),
+ State3 = State2#state{connection_env = CEnv#connection_env{negotiated_version = Version}, %% RequestedVersion
session =
Session0#session{session_id = Hello#client_hello.session_id},
- start_or_recv_from = From,
- timer = Timer,
- flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT}
- },
- {Record, State} = next_record(State3),
- next_event(hello, Record, State, Actions);
-init({call, _} = Type, Event, #state{role = server, transport_cb = gen_udp} = State) ->
+ start_or_recv_from = From},
+ next_event(hello, no_record, State3, [{{timeout, handshake}, Timeout, close} | Actions]);
+init({call, _} = Type, Event, #state{static_env = #static_env{role = server},
+ protocol_specific = PS} = State) ->
Result = gen_handshake(?FUNCTION_NAME, Type, Event,
- State#state{flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT},
- protocol_specific = #{current_cookie_secret => dtls_v1:cookie_secret(),
- previous_cookie_secret => <<>>,
- ignored_alerts => 0,
- max_ignored_alerts => 10}}),
+ State#state{protocol_specific = PS#{current_cookie_secret => dtls_v1:cookie_secret(),
+ previous_cookie_secret => <<>>,
+ ignored_alerts => 0,
+ max_ignored_alerts => 10}}),
erlang:send_after(dtls_v1:cookie_timeout(), self(), new_cookie_secret),
Result;
-
-init({call, _} = Type, Event, #state{role = server} = State) ->
- %% I.E. DTLS over sctp
- gen_handshake(?FUNCTION_NAME, Type, Event, State#state{flight_state = reliable});
init(Type, Event, State) ->
gen_handshake(?FUNCTION_NAME, Type, Event, State).
@@ -472,8 +475,10 @@ init(Type, Event, State) ->
%%--------------------------------------------------------------------
error(enter, _, State) ->
{keep_state, State};
-error({call, From}, {start, _Timeout}, {Error, State}) ->
- {stop_and_reply, normal, {reply, From, {error, Error}}, State};
+error({call, From}, {start, _Timeout},
+ #state{protocol_specific = #{error := Error}} = State) ->
+ {stop_and_reply, {shutdown, normal},
+ [{reply, From, {error, Error}}], State};
error({call, _} = Call, Msg, State) ->
gen_handshake(?FUNCTION_NAME, Call, Msg, State);
error(_, _, _) ->
@@ -485,16 +490,19 @@ error(_, _, _) ->
#state{}) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
-hello(enter, _, #state{role = server} = State) ->
+hello(enter, _, #state{static_env = #static_env{role = server}} = State) ->
{keep_state, State};
-hello(enter, _, #state{role = client} = State0) ->
+hello(enter, _, #state{static_env = #static_env{role = client}} = State0) ->
{State, Actions} = handle_flight_timer(State0),
{keep_state, State, Actions};
hello(internal, #client_hello{cookie = <<>>,
- client_version = Version} = Hello, #state{role = server,
- transport_cb = Transport,
- socket = Socket,
- protocol_specific = #{current_cookie_secret := Secret}} = State0) ->
+ client_version = Version} = Hello,
+ #state{static_env = #static_env{role = server,
+ transport_cb = Transport,
+ socket = Socket},
+ handshake_env = HsEnv,
+ connection_env = CEnv,
+ protocol_specific = #{current_cookie_secret := Secret}} = State0) ->
{ok, {IP, Port}} = dtls_socket:peername(Transport, Socket),
Cookie = dtls_handshake:cookie(Secret, IP, Port, Hello),
%% FROM RFC 6347 regarding HelloVerifyRequest message:
@@ -504,15 +512,61 @@ hello(internal, #client_hello{cookie = <<>>,
%% version 1.0 regardless of the version of TLS that is expected to be
%% negotiated.
VerifyRequest = dtls_handshake:hello_verify_request(Cookie, ?HELLO_VERIFY_REQUEST_VERSION),
- State1 = prepare_flight(State0#state{negotiated_version = Version}),
- {State2, Actions} = send_handshake(VerifyRequest, State1),
- {Record, State} = next_record(State2),
- next_event(?FUNCTION_NAME, Record, State#state{tls_handshake_history = ssl_handshake:init_handshake_history()}, Actions);
-hello(internal, #client_hello{cookie = Cookie} = Hello, #state{role = server,
- transport_cb = Transport,
- socket = Socket,
+ State1 = prepare_flight(State0#state{connection_env = CEnv#connection_env{negotiated_version = Version}}),
+ {State, Actions} = send_handshake(VerifyRequest, State1),
+ next_event(?FUNCTION_NAME, no_record,
+ State#state{handshake_env = HsEnv#handshake_env{
+ tls_handshake_history =
+ ssl_handshake:init_handshake_history()}},
+ Actions);
+hello(internal, #hello_verify_request{cookie = Cookie}, #state{static_env = #static_env{role = client,
+ host = Host,
+ port = Port,
+ session_cache = Cache,
+ session_cache_cb = CacheCb},
+ handshake_env = #handshake_env{renegotiation = {Renegotiation, _}} = HsEnv,
+ connection_env = CEnv,
+ ssl_options = SslOpts,
+ session = #session{own_certificate = OwnCert}
+ = Session0,
+ connection_states = ConnectionStates0
+ } = State0) ->
+
+ Hello = dtls_handshake:client_hello(Host, Port, Cookie, ConnectionStates0,
+ SslOpts,
+ Cache, CacheCb, Renegotiation, OwnCert),
+ Version = Hello#client_hello.client_version,
+ State1 = prepare_flight(State0#state{handshake_env =
+ HsEnv#handshake_env{tls_handshake_history
+ = ssl_handshake:init_handshake_history()}}),
+
+ {State2, Actions} = send_handshake(Hello, State1),
+ State = State2#state{connection_env = CEnv#connection_env{negotiated_version = Version}, %% Requested version
+ session =
+ Session0#session{session_id =
+ Hello#client_hello.session_id}},
+ next_event(?FUNCTION_NAME, no_record, State, Actions);
+hello(internal, #client_hello{extensions = Extensions} = Hello,
+ #state{ssl_options = #ssl_options{handshake = hello},
+ handshake_env = HsEnv,
+ start_or_recv_from = From} = State) ->
+ {next_state, user_hello, State#state{start_or_recv_from = undefined,
+ handshake_env = HsEnv#handshake_env{hello = Hello}},
+ [{reply, From, {ok, Extensions}}]};
+hello(internal, #server_hello{extensions = Extensions} = Hello,
+ #state{ssl_options = #ssl_options{handshake = hello},
+ handshake_env = HsEnv,
+ start_or_recv_from = From} = State) ->
+ {next_state, user_hello, State#state{start_or_recv_from = undefined,
+ handshake_env = HsEnv#handshake_env{hello = Hello}},
+ [{reply, From, {ok, Extensions}}]};
+
+hello(internal, #client_hello{cookie = Cookie} = Hello, #state{static_env = #static_env{role = server,
+ transport_cb = Transport,
+ socket = Socket},
protocol_specific = #{current_cookie_secret := Secret,
- previous_cookie_secret := PSecret}} = State0) ->
+ previous_cookie_secret := PSecret}
+ } = State0) ->
{ok, {IP, Port}} = dtls_socket:peername(Transport, Socket),
case dtls_handshake:cookie(Secret, IP, Port, Hello) of
Cookie ->
@@ -526,36 +580,13 @@ hello(internal, #client_hello{cookie = Cookie} = Hello, #state{role = server,
hello(internal, Hello#client_hello{cookie = <<>>}, State0)
end
end;
-hello(internal, #hello_verify_request{cookie = Cookie}, #state{role = client,
- host = Host, port = Port,
- ssl_options = SslOpts,
- session = #session{own_certificate = OwnCert}
- = Session0,
- connection_states = ConnectionStates0,
- renegotiation = {Renegotiation, _},
- session_cache = Cache,
- session_cache_cb = CacheCb
- } = State0) ->
-
- Hello = dtls_handshake:client_hello(Host, Port, Cookie, ConnectionStates0,
- SslOpts,
- Cache, CacheCb, Renegotiation, OwnCert),
- Version = Hello#client_hello.client_version,
- State1 = prepare_flight(State0#state{tls_handshake_history = ssl_handshake:init_handshake_history()}),
-
- {State2, Actions} = send_handshake(Hello, State1),
- State3 = State2#state{negotiated_version = Version, %% Requested version
- session =
- Session0#session{session_id =
- Hello#client_hello.session_id}},
- {Record, State} = next_record(State3),
- next_event(?FUNCTION_NAME, Record, State, Actions);
hello(internal, #server_hello{} = Hello,
- #state{connection_states = ConnectionStates0,
- negotiated_version = ReqVersion,
- role = client,
- renegotiation = {Renegotiation, _},
- ssl_options = SslOptions} = State) ->
+ #state{
+ static_env = #static_env{role = client},
+ handshake_env = #handshake_env{renegotiation = {Renegotiation, _}},
+ connection_env = #connection_env{negotiated_version = ReqVersion},
+ connection_states = ConnectionStates0,
+ ssl_options = SslOptions} = State) ->
case dtls_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of
#alert{} = Alert ->
handle_own_alert(Alert, ReqVersion, ?FUNCTION_NAME, State);
@@ -569,6 +600,11 @@ hello(internal, {handshake, {#client_hello{cookie = <<>>} = Handshake, _}}, Stat
hello(internal, {handshake, {#hello_verify_request{} = Handshake, _}}, State) ->
%% hello_verify should not be in handshake history
{next_state, ?FUNCTION_NAME, State, [{next_event, internal, Handshake}]};
+hello(internal, #change_cipher_spec{type = <<1>>}, State0) ->
+ {State1, Actions0} = send_handshake_flight(State0, retransmit_epoch(?FUNCTION_NAME, State0)),
+ {next_state, ?FUNCTION_NAME, State, Actions} = next_event(?FUNCTION_NAME, no_record, State1, Actions0),
+ %% This will reset the retransmission timer by repeating the enter state event
+ {repeat_state, State, Actions};
hello(info, Event, State) ->
gen_info(Event, ?FUNCTION_NAME, State);
hello(state_timeout, Event, State) ->
@@ -576,6 +612,11 @@ hello(state_timeout, Event, State) ->
hello(Type, Event, State) ->
gen_handshake(?FUNCTION_NAME, Type, Event, State).
+user_hello(enter, _, State) ->
+ {keep_state, State};
+user_hello(Type, Event, State) ->
+ gen_handshake(?FUNCTION_NAME, Type, Event, State).
+
%%--------------------------------------------------------------------
-spec abbreviated(gen_statem:event_type(), term(), #state{}) ->
gen_statem:state_function_result().
@@ -591,10 +632,11 @@ abbreviated(internal = Type,
ConnectionStates1 = dtls_record:save_current_connection_state(ConnectionStates0, read),
ConnectionStates = dtls_record:next_epoch(ConnectionStates1, read),
gen_handshake(?FUNCTION_NAME, Type, Event, State#state{connection_states = ConnectionStates});
-abbreviated(internal = Type, #finished{} = Event, #state{connection_states = ConnectionStates} = State) ->
+abbreviated(internal = Type, #finished{} = Event, #state{connection_states = ConnectionStates,
+ protocol_specific = PS} = State) ->
gen_handshake(?FUNCTION_NAME, Type, Event,
prepare_flight(State#state{connection_states = ConnectionStates,
- flight_state = connection}));
+ protocol_specific = PS#{flight_state => connection}}));
abbreviated(state_timeout, Event, State) ->
handle_state_timeout(Event, ?FUNCTION_NAME, State);
abbreviated(Type, Event, State) ->
@@ -612,8 +654,7 @@ certify(internal = Type, #server_hello_done{} = Event, State) ->
ssl_connection:certify(Type, Event, prepare_flight(State), ?MODULE);
certify(internal, #change_cipher_spec{type = <<1>>}, State0) ->
{State1, Actions0} = send_handshake_flight(State0, retransmit_epoch(?FUNCTION_NAME, State0)),
- {Record, State2} = next_record(State1),
- {next_state, ?FUNCTION_NAME, State, Actions} = next_event(?FUNCTION_NAME, Record, State2, Actions0),
+ {next_state, ?FUNCTION_NAME, State, Actions} = next_event(?FUNCTION_NAME, no_record, State1, Actions0),
%% This will reset the retransmission timer by repeating the enter state event
{repeat_state, State, Actions};
certify(state_timeout, Event, State) ->
@@ -635,10 +676,11 @@ cipher(internal = Type, #change_cipher_spec{type = <<1>>} = Event,
ConnectionStates1 = dtls_record:save_current_connection_state(ConnectionStates0, read),
ConnectionStates = dtls_record:next_epoch(ConnectionStates1, read),
ssl_connection:?FUNCTION_NAME(Type, Event, State#state{connection_states = ConnectionStates}, ?MODULE);
-cipher(internal = Type, #finished{} = Event, #state{connection_states = ConnectionStates} = State) ->
+cipher(internal = Type, #finished{} = Event, #state{connection_states = ConnectionStates,
+ protocol_specific = PS} = State) ->
ssl_connection:?FUNCTION_NAME(Type, Event,
prepare_flight(State#state{connection_states = ConnectionStates,
- flight_state = connection}),
+ protocol_specific = PS#{flight_state => connection}}),
?MODULE);
cipher(state_timeout, Event, State) ->
handle_state_timeout(Event, ?FUNCTION_NAME, State);
@@ -654,39 +696,53 @@ connection(enter, _, State) ->
{keep_state, State};
connection(info, Event, State) ->
gen_info(Event, ?FUNCTION_NAME, State);
-connection(internal, #hello_request{}, #state{host = Host, port = Port,
+connection(internal, #hello_request{}, #state{static_env = #static_env{host = Host,
+ port = Port,
+ data_tag = DataTag,
+ session_cache = Cache,
+ session_cache_cb = CacheCb
+ },
+ handshake_env = #handshake_env{ renegotiation = {Renegotiation, _}},
+ connection_env = CEnv,
session = #session{own_certificate = Cert} = Session0,
- session_cache = Cache, session_cache_cb = CacheCb,
ssl_options = SslOpts,
connection_states = ConnectionStates0,
- renegotiation = {Renegotiation, _}} = State0) ->
+ protocol_specific = PS
+ } = State0) ->
Hello = dtls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
Cache, CacheCb, Renegotiation, Cert),
Version = Hello#client_hello.client_version,
HelloVersion = dtls_record:hello_version(Version, SslOpts#ssl_options.versions),
State1 = prepare_flight(State0),
- {State2, Actions} = send_handshake(Hello, State1#state{negotiated_version = HelloVersion}),
- {Record, State} =
- next_record(
- State2#state{flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT},
- session = Session0#session{session_id
- = Hello#client_hello.session_id}}),
- next_event(hello, Record, State, Actions);
-connection(internal, #client_hello{} = Hello, #state{role = server, allow_renegotiate = true} = State) ->
+ {State2, Actions} = send_handshake(Hello, State1#state{connection_env = CEnv#connection_env{negotiated_version = HelloVersion}}),
+ State = State2#state{protocol_specific = PS#{flight_state => initial_flight_state(DataTag)},
+ session = Session0#session{session_id
+ = Hello#client_hello.session_id}},
+ next_event(hello, no_record, State, Actions);
+connection(internal, #client_hello{} = Hello, #state{static_env = #static_env{role = server},
+ handshake_env = #handshake_env{allow_renegotiate = true} = HsEnv} = State) ->
%% Mitigate Computational DoS attack
%% http://www.educatedguesswork.org/2011/10/ssltls_and_computational_dos.html
%% http://www.thc.org/thc-ssl-dos/ Rather than disabling client
%% initiated renegotiation we will disallow many client initiated
%% renegotiations immediately after each other.
erlang:send_after(?WAIT_TO_ALLOW_RENEGOTIATION, self(), allow_renegotiate),
- {next_state, hello, State#state{allow_renegotiate = false, renegotiation = {true, peer}},
+ {next_state, hello, State#state{handshake_env = HsEnv#handshake_env{renegotiation = {true, peer},
+ allow_renegotiate = false}},
[{next_event, internal, Hello}]};
-connection(internal, #client_hello{}, #state{role = server, allow_renegotiate = false} = State0) ->
+connection(internal, #client_hello{}, #state{static_env = #static_env{role = server},
+ handshake_env = #handshake_env{allow_renegotiate = false}} = State0) ->
Alert = ?ALERT_REC(?WARNING, ?NO_RENEGOTIATION),
State1 = send_alert(Alert, State0),
{Record, State} = ssl_connection:prepare_connection(State1, ?MODULE),
next_event(?FUNCTION_NAME, Record, State);
+connection({call, From}, {application_data, Data}, State) ->
+ try
+ send_application_data(Data, From, ?FUNCTION_NAME, State)
+ catch throw:Error ->
+ ssl_connection:hibernate_after(?FUNCTION_NAME, State, [{reply, From, Error}])
+ end;
connection(Type, Event, State) ->
ssl_connection:?FUNCTION_NAME(Type, Event, State, ?MODULE).
@@ -719,7 +775,7 @@ format_status(Type, Data) ->
%%% Internal functions
%%--------------------------------------------------------------------
initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions, _}, User,
- {CbModule, DataTag, CloseTag, ErrorTag}) ->
+ {CbModule, DataTag, CloseTag, ErrorTag, PassiveTag}) ->
#ssl_options{beast_mitigation = BeastMitigation} = SSLOptions,
ConnectionStates = dtls_record:init_connection_states(Role, BeastMitigation),
@@ -729,41 +785,61 @@ initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions, _}, User,
_ ->
ssl_session_cache
end,
-
+ InternalActiveN = case application:get_env(ssl, internal_active_n) of
+ {ok, N} when is_integer(N) ->
+ N;
+ _ ->
+ ?INTERNAL_ACTIVE_N
+ end,
Monitor = erlang:monitor(process, User),
-
- #state{socket_options = SocketOptions,
+ InitStatEnv = #static_env{
+ role = Role,
+ transport_cb = CbModule,
+ protocol_cb = ?MODULE,
+ data_tag = DataTag,
+ close_tag = CloseTag,
+ error_tag = ErrorTag,
+ passive_tag = PassiveTag,
+ host = Host,
+ port = Port,
+ socket = Socket,
+ session_cache_cb = SessionCacheCb
+ },
+
+ #state{static_env = InitStatEnv,
+ handshake_env = #handshake_env{
+ tls_handshake_history = ssl_handshake:init_handshake_history(),
+ renegotiation = {false, first},
+ allow_renegotiate = SSLOptions#ssl_options.client_renegotiation
+ },
+ connection_env = #connection_env{user_application = {Monitor, User}},
+ socket_options = SocketOptions,
%% We do not want to save the password in the state so that
%% could be written in the clear into error logs.
ssl_options = SSLOptions#ssl_options{password = undefined},
session = #session{is_resumable = new},
- transport_cb = CbModule,
- data_tag = DataTag,
- close_tag = CloseTag,
- error_tag = ErrorTag,
- role = Role,
- host = Host,
- port = Port,
- socket = Socket,
connection_states = ConnectionStates,
protocol_buffers = #protocol_buffers{},
- user_application = {Monitor, User},
- user_data_buffer = <<>>,
- session_cache_cb = SessionCacheCb,
- renegotiation = {false, first},
- allow_renegotiate = SSLOptions#ssl_options.client_renegotiation,
+ user_data_buffer = {[],0,[]},
start_or_recv_from = undefined,
- protocol_cb = ?MODULE,
flight_buffer = new_flight(),
- flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT}
+ protocol_specific = #{active_n => InternalActiveN,
+ active_n_toggle => true,
+ flight_state => initial_flight_state(DataTag)}
}.
+initial_flight_state(udp)->
+ {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT};
+initial_flight_state(_) ->
+ reliable.
+
next_dtls_record(Data, StateName, #state{protocol_buffers = #protocol_buffers{
dtls_record_buffer = Buf0,
- dtls_cipher_texts = CT0} = Buffers} = State0) ->
+ dtls_cipher_texts = CT0} = Buffers,
+ ssl_options = SslOpts} = State0) ->
case dtls_record:get_dtls_records(Data,
acceptable_record_versions(StateName, State0),
- Buf0) of
+ Buf0, SslOpts) of
{Records, Buf1} ->
CT1 = CT0 ++ Records,
next_record(State0#state{protocol_buffers =
@@ -774,8 +850,8 @@ next_dtls_record(Data, StateName, #state{protocol_buffers = #protocol_buffers{
end.
acceptable_record_versions(hello, _) ->
- [dtls_record:protocol_version(Vsn) || Vsn <- ?ALL_DATAGRAM_SUPPORTED_VERSIONS];
-acceptable_record_versions(_, #state{negotiated_version = Version}) ->
+ [dtls_record:protocol_version(Vsn) || Vsn <- ?ALL_AVAILABLE_DATAGRAM_VERSIONS];
+acceptable_record_versions(_, #state{connection_env = #connection_env{negotiated_version = Version}}) ->
[Version].
dtls_handshake_events(Packets) ->
@@ -794,19 +870,22 @@ decode_cipher_text(#state{protocol_buffers = #protocol_buffers{dtls_cipher_texts
{Alert, State}
end.
-dtls_version(hello, Version, #state{role = server} = State) ->
- State#state{negotiated_version = Version}; %%Inital version
+dtls_version(hello, Version, #state{static_env = #static_env{role = server},
+ connection_env = CEnv} = State) ->
+ State#state{connection_env = CEnv#connection_env{negotiated_version = Version}}; %%Inital version
dtls_version(_,_, State) ->
State.
handle_client_hello(#client_hello{client_version = ClientVersion} = Hello,
#state{connection_states = ConnectionStates0,
- port = Port, session = #session{own_certificate = Cert} = Session0,
- renegotiation = {Renegotiation, _},
- session_cache = Cache,
- session_cache_cb = CacheCb,
- negotiated_protocol = CurrentProtocol,
- key_algorithm = KeyExAlg,
+ static_env = #static_env{port = Port,
+ session_cache = Cache,
+ session_cache_cb = CacheCb},
+ handshake_env = #handshake_env{kex_algorithm = KeyExAlg,
+ renegotiation = {Renegotiation, _},
+ negotiated_protocol = CurrentProtocol} = HsEnv,
+ connection_env = CEnv,
+ session = #session{own_certificate = Cert} = Session0,
ssl_options = SslOpts} = State0) ->
case dtls_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb,
@@ -821,11 +900,12 @@ handle_client_hello(#client_hello{client_version = ClientVersion} = Hello,
end,
State = prepare_flight(State0#state{connection_states = ConnectionStates,
- negotiated_version = Version,
- hashsign_algorithm = HashSign,
- client_hello_version = ClientVersion,
- session = Session,
- negotiated_protocol = Protocol}),
+ connection_env = CEnv#connection_env{negotiated_version = Version},
+ handshake_env = HsEnv#handshake_env{
+ hashsign_algorithm = HashSign,
+ client_hello_version = ClientVersion,
+ negotiated_protocol = Protocol},
+ session = Session}),
ssl_connection:hello(internal, {common_client_hello, Type, ServerHelloExt},
State, ?MODULE)
@@ -834,20 +914,29 @@ handle_client_hello(#client_hello{client_version = ClientVersion} = Hello,
%% raw data from socket, unpack records
handle_info({Protocol, _, _, _, Data}, StateName,
- #state{data_tag = Protocol} = State0) ->
+ #state{static_env = #static_env{data_tag = Protocol}} = State0) ->
case next_dtls_record(Data, StateName, State0) of
{Record, State} ->
next_event(StateName, Record, State);
#alert{} = Alert ->
ssl_connection:handle_normal_shutdown(Alert, StateName, State0),
- {stop, {shutdown, own_alert}}
+ {stop, {shutdown, own_alert}, State0}
end;
+
+handle_info({PassiveTag, Socket}, StateName,
+ #state{static_env = #static_env{socket = {_, Socket},
+ passive_tag = PassiveTag},
+ protocol_specific = PS} = State) ->
+ next_event(StateName, no_record,
+ State#state{protocol_specific = PS#{active_n_toggle => true}});
+
handle_info({CloseTag, Socket}, StateName,
- #state{socket = Socket,
+ #state{static_env = #static_env{socket = Socket,
+ close_tag = CloseTag},
+ connection_env = #connection_env{negotiated_version = Version},
socket_options = #socket_options{active = Active},
protocol_buffers = #protocol_buffers{dtls_cipher_texts = CTs},
- close_tag = CloseTag,
- negotiated_version = Version} = State) ->
+ protocol_specific = PS} = State) ->
%% Note that as of DTLS 1.2 (TLS 1.1),
%% failure to properly close a connection no longer requires that a
%% session not be resumed. This is a change from DTLS 1.0 to conform
@@ -865,12 +954,13 @@ handle_info({CloseTag, Socket}, StateName,
ok
end,
ssl_connection:handle_normal_shutdown(?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), StateName, State),
- {stop, {shutdown, transport_closed}};
+ {stop, {shutdown, transport_closed}, State};
true ->
%% Fixes non-delivery of final DTLS record in {active, once}.
%% Basically allows the application the opportunity to set {active, once} again
%% and then receive the final message.
- next_event(StateName, no_record, State)
+ next_event(StateName, no_record, State#state{
+ protocol_specific = PS#{active_n_toggle => true}})
end;
handle_info(new_cookie_secret, StateName,
@@ -883,29 +973,29 @@ handle_info(Msg, StateName, State) ->
ssl_connection:StateName(info, Msg, State, ?MODULE).
handle_state_timeout(flight_retransmission_timeout, StateName,
- #state{flight_state = {retransmit, NextTimeout}} = State0) ->
- {State1, Actions0} = send_handshake_flight(State0#state{flight_state = {retransmit, NextTimeout}},
- retransmit_epoch(StateName, State0)),
- {Record, State2} = next_record(State1),
- {next_state, StateName, State, Actions} = next_event(StateName, Record, State2, Actions0),
+ #state{protocol_specific =
+ #{flight_state := {retransmit, _NextTimeout}}} = State0) ->
+ {State1, Actions0} = send_handshake_flight(State0,
+ retransmit_epoch(StateName, State0)),
+ {next_state, StateName, State, Actions} = next_event(StateName, no_record, State1, Actions0),
%% This will reset the retransmission timer by repeating the enter state event
{repeat_state, State, Actions}.
handle_alerts([], Result) ->
Result;
-handle_alerts(_, {stop,_} = Stop) ->
+handle_alerts(_, {stop, _, _} = Stop) ->
Stop;
handle_alerts([Alert | Alerts], {next_state, StateName, State}) ->
handle_alerts(Alerts, ssl_connection:handle_alert(Alert, StateName, State));
handle_alerts([Alert | Alerts], {next_state, StateName, State, _Actions}) ->
handle_alerts(Alerts, ssl_connection:handle_alert(Alert, StateName, State)).
-handle_own_alert(Alert, Version, StateName, #state{transport_cb = gen_udp,
- role = Role,
+handle_own_alert(Alert, Version, StateName, #state{static_env = #static_env{data_tag = udp,
+ role = Role},
ssl_options = Options} = State0) ->
case ignore_alert(Alert, State0) of
{true, State} ->
- log_ignore_alert(Options#ssl_options.log_alert, StateName, Alert, Role),
+ log_ignore_alert(Options#ssl_options.log_level, StateName, Alert, Role),
{next_state, StateName, State};
{false, State} ->
ssl_connection:handle_own_alert(Alert, Version, StateName, State)
@@ -926,7 +1016,7 @@ decode_alerts(Bin) ->
ssl_alert:decode(Bin).
gen_handshake(StateName, Type, Event,
- #state{negotiated_version = Version} = State) ->
+ #state{connection_env = #connection_env{negotiated_version = Version}} = State) ->
try ssl_connection:StateName(Type, Event, State, ?MODULE) of
Result ->
Result
@@ -937,7 +1027,7 @@ gen_handshake(StateName, Type, Event,
Version, StateName, State)
end.
-gen_info(Event, connection = StateName, #state{negotiated_version = Version} = State) ->
+gen_info(Event, connection = StateName, #state{connection_env = #connection_env{negotiated_version = Version}} = State) ->
try handle_info(Event, StateName, State) of
Result ->
Result
@@ -948,7 +1038,7 @@ gen_info(Event, connection = StateName, #state{negotiated_version = Version} =
Version, StateName, State)
end;
-gen_info(Event, StateName, #state{negotiated_version = Version} = State) ->
+gen_info(Event, StateName, #state{connection_env = #connection_env{negotiated_version = Version}} = State) ->
try handle_info(Event, StateName, State) of
Result ->
Result
@@ -969,8 +1059,7 @@ unprocessed_events(Events) ->
update_handshake_history(#hello_verify_request{}, _, Hist) ->
Hist;
update_handshake_history(_, Handshake, Hist) ->
- %% DTLS never needs option "v2_hello_compatible" to be true
- ssl_handshake:update_handshake_history(Hist, iolist_to_binary(Handshake), false).
+ ssl_handshake:update_handshake_history(Hist, iolist_to_binary(Handshake)).
prepare_flight(#state{flight_buffer = Flight,
connection_states = ConnectionStates0,
protocol_buffers =
@@ -992,58 +1081,67 @@ next_flight(Flight) ->
change_cipher_spec => undefined,
handshakes_after_change_cipher_spec => []}.
-handle_flight_timer(#state{transport_cb = gen_udp,
- flight_state = {retransmit, Timeout}} = State) ->
+handle_flight_timer(#state{static_env = #static_env{data_tag = udp},
+ protocol_specific = #{flight_state := {retransmit, Timeout}}} = State) ->
start_retransmision_timer(Timeout, State);
-handle_flight_timer(#state{transport_cb = gen_udp,
- flight_state = connection} = State) ->
+handle_flight_timer(#state{static_env = #static_env{data_tag = udp},
+ protocol_specific = #{flight_state := connection}} = State) ->
{State, []};
-handle_flight_timer(State) ->
+handle_flight_timer(#state{protocol_specific = #{flight_state := reliable}} = State) ->
%% No retransmision needed i.e DTLS over SCTP
- {State#state{flight_state = reliable}, []}.
+ {State, []}.
-start_retransmision_timer(Timeout, State) ->
- {State#state{flight_state = {retransmit, new_timeout(Timeout)}},
+start_retransmision_timer(Timeout, #state{protocol_specific = PS} = State) ->
+ {State#state{protocol_specific = PS#{flight_state => {retransmit, new_timeout(Timeout)}}},
[{state_timeout, Timeout, flight_retransmission_timeout}]}.
-new_timeout(N) when N =< 30 ->
+new_timeout(N) when N =< 30000 ->
N * 2;
new_timeout(_) ->
- 60.
+ 60000.
-send_handshake_flight(#state{socket = Socket,
- transport_cb = Transport,
- flight_buffer = #{handshakes := Flight,
+send_handshake_flight(#state{static_env = #static_env{socket = Socket,
+ transport_cb = Transport},
+ connection_env = #connection_env{negotiated_version = Version},
+ flight_buffer = #{handshakes := Flight,
change_cipher_spec := undefined},
- negotiated_version = Version,
- connection_states = ConnectionStates0} = State0, Epoch) ->
+ connection_states = ConnectionStates0,
+ ssl_options = #ssl_options{log_level = LogLevel}} = State0,
+ Epoch) ->
%% TODO remove hardcoded Max size
{Encoded, ConnectionStates} =
encode_handshake_flight(lists:reverse(Flight), Version, 1400, Epoch, ConnectionStates0),
- send(Transport, Socket, Encoded),
+ send(Transport, Socket, Encoded),
+ ssl_logger:debug(LogLevel, outbound, 'record', Encoded),
{State0#state{connection_states = ConnectionStates}, []};
-send_handshake_flight(#state{socket = Socket,
- transport_cb = Transport,
+send_handshake_flight(#state{static_env = #static_env{socket = Socket,
+ transport_cb = Transport},
+ connection_env = #connection_env{negotiated_version = Version},
flight_buffer = #{handshakes := [_|_] = Flight0,
change_cipher_spec := ChangeCipher,
handshakes_after_change_cipher_spec := []},
- negotiated_version = Version,
- connection_states = ConnectionStates0} = State0, Epoch) ->
+ connection_states = ConnectionStates0,
+ ssl_options = #ssl_options{log_level = LogLevel}} = State0,
+ Epoch) ->
{HsBefore, ConnectionStates1} =
encode_handshake_flight(lists:reverse(Flight0), Version, 1400, Epoch, ConnectionStates0),
{EncChangeCipher, ConnectionStates} = encode_change_cipher(ChangeCipher, Version, Epoch, ConnectionStates1),
send(Transport, Socket, [HsBefore, EncChangeCipher]),
+ ssl_logger:debug(LogLevel, outbound, 'record', [HsBefore]),
+ ssl_logger:debug(LogLevel, outbound, 'record', [EncChangeCipher]),
{State0#state{connection_states = ConnectionStates}, []};
-send_handshake_flight(#state{socket = Socket,
- transport_cb = Transport,
+send_handshake_flight(#state{static_env = #static_env{socket = Socket,
+ transport_cb = Transport},
+ connection_env = #connection_env{negotiated_version = Version},
flight_buffer = #{handshakes := [_|_] = Flight0,
change_cipher_spec := ChangeCipher,
handshakes_after_change_cipher_spec := Flight1},
- negotiated_version = Version,
- connection_states = ConnectionStates0} = State0, Epoch) ->
+ connection_states = ConnectionStates0,
+ ssl_options = #ssl_options{log_level = LogLevel}} = State0,
+ Epoch) ->
{HsBefore, ConnectionStates1} =
encode_handshake_flight(lists:reverse(Flight0), Version, 1400, Epoch-1, ConnectionStates0),
{EncChangeCipher, ConnectionStates2} =
@@ -1051,20 +1149,27 @@ send_handshake_flight(#state{socket = Socket,
{HsAfter, ConnectionStates} =
encode_handshake_flight(lists:reverse(Flight1), Version, 1400, Epoch, ConnectionStates2),
send(Transport, Socket, [HsBefore, EncChangeCipher, HsAfter]),
+ ssl_logger:debug(LogLevel, outbound, 'record', [HsBefore]),
+ ssl_logger:debug(LogLevel, outbound, 'record', [EncChangeCipher]),
+ ssl_logger:debug(LogLevel, outbound, 'record', [HsAfter]),
{State0#state{connection_states = ConnectionStates}, []};
-send_handshake_flight(#state{socket = Socket,
- transport_cb = Transport,
+send_handshake_flight(#state{static_env = #static_env{socket = Socket,
+ transport_cb = Transport},
+ connection_env = #connection_env{negotiated_version = Version},
flight_buffer = #{handshakes := [],
change_cipher_spec := ChangeCipher,
handshakes_after_change_cipher_spec := Flight1},
- negotiated_version = Version,
- connection_states = ConnectionStates0} = State0, Epoch) ->
+ connection_states = ConnectionStates0,
+ ssl_options = #ssl_options{log_level = LogLevel}} = State0,
+ Epoch) ->
{EncChangeCipher, ConnectionStates1} =
encode_change_cipher(ChangeCipher, Version, Epoch-1, ConnectionStates0),
{HsAfter, ConnectionStates} =
encode_handshake_flight(lists:reverse(Flight1), Version, 1400, Epoch, ConnectionStates1),
send(Transport, Socket, [EncChangeCipher, HsAfter]),
+ ssl_logger:debug(LogLevel, outbound, 'record', [EncChangeCipher]),
+ ssl_logger:debug(LogLevel, outbound, 'record', [HsAfter]),
{State0#state{connection_states = ConnectionStates}, []}.
retransmit_epoch(_StateName, #state{connection_states = ConnectionStates}) ->
@@ -1103,9 +1208,51 @@ is_ignore_alert(#alert{description = ?ILLEGAL_PARAMETER}) ->
is_ignore_alert(_) ->
false.
-log_ignore_alert(true, StateName, Alert, Role) ->
+log_ignore_alert(debug, StateName, Alert, Role) ->
Txt = ssl_alert:alert_txt(Alert),
- error_logger:format("DTLS over UDP ~p: In state ~p ignored to send ALERT ~s as DoS-attack mitigation \n",
- [Role, StateName, Txt]);
-log_ignore_alert(false, _, _,_) ->
+ ?LOG_ERROR("DTLS over UDP ~p: In state ~p ignored to send ALERT ~s as DoS-attack mitigation \n",
+ [Role, StateName, Txt]);
+log_ignore_alert(_, _, _, _) ->
ok.
+
+send_application_data(Data, From, _StateName,
+ #state{static_env = #static_env{socket = Socket,
+ transport_cb = Transport},
+ connection_env = #connection_env{negotiated_version = Version},
+ handshake_env = HsEnv,
+ connection_states = ConnectionStates0,
+ ssl_options = #ssl_options{renegotiate_at = RenegotiateAt,
+ log_level = LogLevel}} = State0) ->
+
+ case time_to_renegotiate(Data, ConnectionStates0, RenegotiateAt) of
+ true ->
+ renegotiate(State0#state{handshake_env = HsEnv#handshake_env{renegotiation = {true, internal}}},
+ [{next_event, {call, From}, {application_data, Data}}]);
+ false ->
+ {Msgs, ConnectionStates} =
+ dtls_record:encode_data(Data, Version, ConnectionStates0),
+ State = State0#state{connection_states = ConnectionStates},
+ case send(Transport, Socket, Msgs) of
+ ok ->
+ ssl_logger:debug(LogLevel, outbound, 'record', Msgs),
+ ssl_connection:hibernate_after(connection, State, [{reply, From, ok}]);
+ Result ->
+ ssl_connection:hibernate_after(connection, State, [{reply, From, Result}])
+ end
+ end.
+
+time_to_renegotiate(_Data,
+ #{current_write := #{sequence_number := Num}},
+ RenegotiateAt) ->
+
+ %% We could do test:
+ %% is_time_to_renegotiate((erlang:byte_size(_Data) div
+ %% ?MAX_PLAIN_TEXT_LENGTH) + 1, RenegotiateAt), but we chose to
+ %% have a some what lower renegotiateAt and a much cheaper test
+ is_time_to_renegotiate(Num, RenegotiateAt).
+
+is_time_to_renegotiate(N, M) when N < M->
+ false;
+is_time_to_renegotiate(_,_) ->
+ true.
+
diff --git a/lib/ssl/src/dtls_handshake.erl b/lib/ssl/src/dtls_handshake.erl
index 6071eece13..d8c0e30973 100644
--- a/lib/ssl/src/dtls_handshake.erl
+++ b/lib/ssl/src/dtls_handshake.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -37,7 +37,7 @@
-export([fragment_handshake/2, encode_handshake/3]).
%% Handshake decodeing
--export([get_dtls_handshake/3]).
+-export([get_dtls_handshake/4]).
-type dtls_handshake() :: #client_hello{} | #hello_verify_request{} |
ssl_handshake:ssl_handshake().
@@ -46,7 +46,7 @@
%% Handshake handling
%%====================================================================
%%--------------------------------------------------------------------
--spec client_hello(host(), inet:port_number(), ssl_record:connection_states(),
+-spec client_hello(ssl:host(), inet:port_number(), ssl_record:connection_states(),
#ssl_options{}, integer(), atom(), boolean(), der_cert()) ->
#client_hello{}.
%%
@@ -59,7 +59,7 @@ client_hello(Host, Port, ConnectionStates, SslOpts,
Cache, CacheCb, Renegotiation, OwnCert).
%%--------------------------------------------------------------------
--spec client_hello(host(), inet:port_number(), term(), ssl_record:connection_states(),
+-spec client_hello(ssl:host(), inet:port_number(), term(), ssl_record:connection_states(),
#ssl_options{}, integer(), atom(), boolean(), der_cert()) ->
#client_hello{}.
%%
@@ -79,7 +79,7 @@ client_hello(Host, Port, Cookie, ConnectionStates,
Extensions = ssl_handshake:client_hello_extensions(TLSVersion, CipherSuites,
SslOpts, ConnectionStates,
- Renegotiation),
+ Renegotiation, undefined),
Id = ssl_session:client_id({Host, Port, SslOpts}, Cache, CacheCb, OwnCert),
#client_hello{session_id = Id,
@@ -123,7 +123,7 @@ cookie(Key, Address, Port, #client_hello{client_version = {Major, Minor},
Random, SessionId, CipherSuites, CompressionMethods],
crypto:hmac(sha, Key, CookieData).
%%--------------------------------------------------------------------
--spec hello_verify_request(binary(), dtls_record:dtls_version()) -> #hello_verify_request{}.
+-spec hello_verify_request(binary(), ssl_record:ssl_version()) -> #hello_verify_request{}.
%%
%% Description: Creates a hello verify request message sent by server to
%% verify client
@@ -151,15 +151,15 @@ encode_handshake(Handshake, Version, Seq) ->
%%--------------------------------------------------------------------
%%--------------------------------------------------------------------
--spec get_dtls_handshake(dtls_record:dtls_version(), binary(), #protocol_buffers{}) ->
+-spec get_dtls_handshake(ssl_record:ssl_version(), binary(), #protocol_buffers{}, #ssl_options{}) ->
{[dtls_handshake()], #protocol_buffers{}}.
%%
%% Description: Given buffered and new data from dtls_record, collects
%% and returns it as a list of handshake messages, also returns
%% possible leftover data in the new "protocol_buffers".
%%--------------------------------------------------------------------
-get_dtls_handshake(Version, Fragment, ProtocolBuffers) ->
- handle_fragments(Version, Fragment, ProtocolBuffers, []).
+get_dtls_handshake(Version, Fragment, ProtocolBuffers, Options) ->
+ handle_fragments(Version, Fragment, ProtocolBuffers, Options, []).
%%--------------------------------------------------------------------
%%% Internal functions
@@ -169,20 +169,21 @@ handle_client_hello(Version,
cipher_suites = CipherSuites,
compression_methods = Compressions,
random = Random,
- extensions =
- #hello_extensions{elliptic_curves = Curves,
- signature_algs = ClientHashSigns}
- = HelloExt},
+ extensions = HelloExt},
#ssl_options{versions = Versions,
- signature_algs = SupportedHashSigns} = SslOpts,
+ signature_algs = SupportedHashSigns,
+ eccs = SupportedECCs,
+ honor_ecc_order = ECCOrder} = SslOpts,
{Port, Session0, Cache, CacheCb, ConnectionStates0, Cert, _},
Renegotiation) ->
case dtls_record:is_acceptable_version(Version, Versions) of
true ->
+ Curves = maps:get(elliptic_curves, HelloExt, undefined),
+ ClientHashSigns = maps:get(signature_algs, HelloExt, undefined),
TLSVersion = dtls_v1:corresponding_tls_version(Version),
AvailableHashSigns = ssl_handshake:available_signature_algs(
ClientHashSigns, SupportedHashSigns, Cert,TLSVersion),
- ECCCurve = ssl_handshake:select_curve(Curves, ssl_handshake:supported_ecc(TLSVersion)),
+ ECCCurve = ssl_handshake:select_curve(Curves, SupportedECCs, ECCOrder),
{Type, #session{cipher_suite = CipherSuite} = Session1}
= ssl_handshake:select_session(SugesstedId, CipherSuites,
AvailableHashSigns, Compressions,
@@ -192,8 +193,8 @@ handle_client_hello(Version,
no_suite ->
?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY);
_ ->
- #{key_exchange := KeyExAlg} = ssl_cipher:suite_definition(CipherSuite),
- case ssl_handshake:select_hashsign(ClientHashSigns, Cert, KeyExAlg,
+ #{key_exchange := KeyExAlg} = ssl_cipher_format:suite_bin_to_map(CipherSuite),
+ case ssl_handshake:select_hashsign({ClientHashSigns, undefined}, Cert, KeyExAlg,
SupportedHashSigns, TLSVersion) of
#alert{} = Alert ->
Alert;
@@ -213,8 +214,6 @@ handle_client_hello_extensions(Version, Type, Random, CipherSuites,
HelloExt, dtls_v1:corresponding_tls_version(Version),
SslOpts, Session0,
ConnectionStates0, Renegotiation) of
- #alert{} = Alert ->
- Alert;
{Session, ConnectionStates, Protocol, ServerHelloExt} ->
{Version, {Type, Session}, ConnectionStates, Protocol, ServerHelloExt, HashSign}
catch throw:Alert ->
@@ -223,17 +222,16 @@ handle_client_hello_extensions(Version, Type, Random, CipherSuites,
handle_server_hello_extensions(Version, SessionId, Random, CipherSuite,
Compression, HelloExt, SslOpt, ConnectionStates0, Renegotiation) ->
- case ssl_handshake:handle_server_hello_extensions(dtls_record, Random, CipherSuite,
- Compression, HelloExt,
- dtls_v1:corresponding_tls_version(Version),
- SslOpt, ConnectionStates0, Renegotiation) of
- #alert{} = Alert ->
- Alert;
+ try ssl_handshake:handle_server_hello_extensions(dtls_record, Random, CipherSuite,
+ Compression, HelloExt,
+ dtls_v1:corresponding_tls_version(Version),
+ SslOpt, ConnectionStates0, Renegotiation) of
{ConnectionStates, ProtoExt, Protocol} ->
{Version, SessionId, ConnectionStates, ProtoExt, Protocol}
+ catch throw:Alert ->
+ Alert
end.
-
%%--------------------------------------------------------------------
enc_handshake(#hello_verify_request{protocol_version = {Major, Minor},
@@ -312,20 +310,21 @@ address_to_bin({A,B,C,D,E,F,G,H}, Port) ->
%%--------------------------------------------------------------------
-handle_fragments(Version, FragmentData, Buffers0, Acc) ->
+handle_fragments(Version, FragmentData, Buffers0, Options, Acc) ->
Fragments = decode_handshake_fragments(FragmentData),
- do_handle_fragments(Version, Fragments, Buffers0, Acc).
+ do_handle_fragments(Version, Fragments, Buffers0, Options, Acc).
-do_handle_fragments(_, [], Buffers, Acc) ->
+do_handle_fragments(_, [], Buffers, _Options, Acc) ->
{lists:reverse(Acc), Buffers};
-do_handle_fragments(Version, [Fragment | Fragments], Buffers0, Acc) ->
+do_handle_fragments(Version, [Fragment | Fragments], Buffers0, Options, Acc) ->
case reassemble(Version, Fragment, Buffers0) of
{more_data, Buffers} when Fragments == [] ->
{lists:reverse(Acc), Buffers};
{more_data, Buffers} ->
- do_handle_fragments(Version, Fragments, Buffers, Acc);
- {HsPacket, Buffers} ->
- do_handle_fragments(Version, Fragments, Buffers, [HsPacket | Acc])
+ do_handle_fragments(Version, Fragments, Buffers, Options, Acc);
+ {{Handshake, _} = HsPacket, Buffers} ->
+ ssl_logger:debug(Options#ssl_options.log_level, inbound, 'handshake', Handshake),
+ do_handle_fragments(Version, Fragments, Buffers, Options, [HsPacket | Acc])
end.
decode_handshake(Version, <<?BYTE(Type), Bin/binary>>) ->
@@ -333,7 +332,7 @@ decode_handshake(Version, <<?BYTE(Type), Bin/binary>>) ->
decode_handshake(_, ?HELLO_REQUEST, <<>>) ->
#hello_request{};
-decode_handshake(_Version, ?CLIENT_HELLO, <<?UINT24(_), ?UINT16(_),
+decode_handshake(Version, ?CLIENT_HELLO, <<?UINT24(_), ?UINT16(_),
?UINT24(_), ?UINT24(_),
?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SID_length), Session_ID:SID_length/binary,
@@ -341,8 +340,10 @@ decode_handshake(_Version, ?CLIENT_HELLO, <<?UINT24(_), ?UINT16(_),
?UINT16(Cs_length), CipherSuites:Cs_length/binary,
?BYTE(Cm_length), Comp_methods:Cm_length/binary,
Extensions/binary>>) ->
-
- DecodedExtensions = ssl_handshake:decode_hello_extensions({client, Extensions}),
+ TLSVersion = dtls_v1:corresponding_tls_version(Version),
+ LegacyVersion = dtls_v1:corresponding_tls_version({Major, Minor}),
+ Exts = ssl_handshake:decode_vector(Extensions),
+ DecodedExtensions = ssl_handshake:decode_hello_extensions(Exts, TLSVersion, LegacyVersion, client),
#client_hello{
client_version = {Major,Minor},
@@ -363,9 +364,9 @@ decode_handshake(_Version, ?HELLO_VERIFY_REQUEST, <<?UINT24(_), ?UINT16(_),
decode_handshake(Version, Tag, <<?UINT24(_), ?UINT16(_),
?UINT24(_), ?UINT24(_), Msg/binary>>) ->
%% DTLS specifics stripped
- decode_tls_thandshake(Version, Tag, Msg).
+ decode_tls_handshake(Version, Tag, Msg).
-decode_tls_thandshake(Version, Tag, Msg) ->
+decode_tls_handshake(Version, Tag, Msg) ->
TLSVersion = dtls_v1:corresponding_tls_version(Version),
ssl_handshake:decode_handshake(TLSVersion, Tag, Msg).
@@ -426,74 +427,135 @@ merge_fragment(Frag0, [Frag1 | Rest]) ->
Frag ->
merge_fragment(Frag, Rest)
end.
-%% Duplicate
+
+
+%% Duplicate (fully contained fragment)
+%% 2,5 _ _ P P P P P
+%% 2,5 _ _ C C C C C
merge_fragments(#handshake_fragment{
- fragment_offset = PreviousOffSet,
+ fragment_offset = PreviousOffSet,
fragment_length = PreviousLen,
fragment = PreviousData
- } = Previous,
+ } = Previous,
#handshake_fragment{
fragment_offset = PreviousOffSet,
fragment_length = PreviousLen,
fragment = PreviousData}) ->
Previous;
-%% Lager fragment save new data
+%% Duplicate (fully contained fragment)
+%% 2,5 _ _ P P P P P
+%% 2,2 _ _ C C
+%% 0,3 X X X
+%% 5,3 _ _ _ _ _ X X X
merge_fragments(#handshake_fragment{
- fragment_offset = PreviousOffSet,
- fragment_length = PreviousLen,
+ fragment_offset = PreviousOffset,
+ fragment_length = PreviousLen
+ } = Previous,
+ #handshake_fragment{
+ fragment_offset = CurrentOffset,
+ fragment_length = CurrentLen})
+ when PreviousOffset =< CurrentOffset andalso
+ CurrentOffset =< PreviousOffset + PreviousLen andalso
+ CurrentOffset + CurrentLen =< PreviousOffset + PreviousLen ->
+ Previous;
+
+%% Fully overlapping fragments
+%% 2,5 _ _ P P P P P
+%% 0,8 C C C C C C C C
+merge_fragments(#handshake_fragment{
+ fragment_offset = PreviousOffset,
+ fragment_length = PreviousLen
+ },
+ #handshake_fragment{
+ fragment_offset = CurrentOffset,
+ fragment_length = CurrentLen} = Current)
+ when CurrentOffset =< PreviousOffset andalso
+ CurrentOffset + CurrentLen >= PreviousOffset + PreviousLen ->
+ Current;
+
+%% Overlapping fragments
+%% 2,5 _ _ P P P P P
+%% 0,3 C C C
+merge_fragments(#handshake_fragment{
+ fragment_offset = PreviousOffset,
+ fragment_length = PreviousLen,
fragment = PreviousData
- } = Previous,
- #handshake_fragment{
- fragment_offset = PreviousOffSet,
- fragment_length = CurrentLen,
- fragment = CurrentData}) when CurrentLen > PreviousLen ->
- NewLength = CurrentLen - PreviousLen,
- <<_:PreviousLen/binary, NewData/binary>> = CurrentData,
+ } = Previous,
+ #handshake_fragment{
+ fragment_offset = CurrentOffset,
+ fragment_length = CurrentLen,
+ fragment = CurrentData})
+ when CurrentOffset < PreviousOffset andalso
+ CurrentOffset + CurrentLen < PreviousOffset + PreviousLen ->
+ NewDataLen = PreviousOffset - CurrentOffset,
+ <<NewData:NewDataLen/binary, _/binary>> = CurrentData,
Previous#handshake_fragment{
- fragment_length = PreviousLen + NewLength,
- fragment = <<PreviousData/binary, NewData/binary>>
+ fragment_length = PreviousLen + NewDataLen,
+ fragment = <<NewData/binary, PreviousData/binary>>
};
-%% Smaller fragment
+%% Overlapping fragments
+%% 2,5 _ _ P P P P P
+%% 5,3 _ _ _ _ _ C C C
merge_fragments(#handshake_fragment{
- fragment_offset = PreviousOffSet,
- fragment_length = PreviousLen
- } = Previous,
- #handshake_fragment{
- fragment_offset = PreviousOffSet,
- fragment_length = CurrentLen}) when CurrentLen < PreviousLen ->
- Previous;
-%% Next fragment, might be overlapping
+ fragment_offset = PreviousOffset,
+ fragment_length = PreviousLen,
+ fragment = PreviousData
+ } = Previous,
+ #handshake_fragment{
+ fragment_offset = CurrentOffset,
+ fragment_length = CurrentLen,
+ fragment = CurrentData})
+ when CurrentOffset > PreviousOffset andalso
+ CurrentOffset < PreviousOffset + PreviousLen ->
+ NewDataLen = CurrentOffset + CurrentLen - (PreviousOffset + PreviousLen),
+ DropLen = CurrentLen - NewDataLen,
+ <<_:DropLen/binary, NewData/binary>> = CurrentData,
+ Previous#handshake_fragment{
+ fragment_length = PreviousLen + NewDataLen,
+ fragment = <<PreviousData/binary, NewData/binary>>
+ };
+
+%% Adjacent fragments
+%% 2,5 _ _ P P P P P
+%% 7,3 _ _ _ _ _ _ _ C C C
merge_fragments(#handshake_fragment{
- fragment_offset = PreviousOffSet,
- fragment_length = PreviousLen,
+ fragment_offset = PreviousOffset,
+ fragment_length = PreviousLen,
fragment = PreviousData
- } = Previous,
- #handshake_fragment{
- fragment_offset = CurrentOffSet,
- fragment_length = CurrentLen,
- fragment = CurrentData})
- when PreviousOffSet + PreviousLen >= CurrentOffSet andalso
- PreviousOffSet + PreviousLen < CurrentOffSet + CurrentLen ->
- CurrentStart = PreviousOffSet + PreviousLen - CurrentOffSet,
- <<_:CurrentStart/bytes, Data/binary>> = CurrentData,
+ } = Previous,
+ #handshake_fragment{
+ fragment_offset = CurrentOffset,
+ fragment_length = CurrentLen,
+ fragment = CurrentData})
+ when CurrentOffset =:= PreviousOffset + PreviousLen ->
Previous#handshake_fragment{
- fragment_length = PreviousLen + CurrentLen - CurrentStart,
- fragment = <<PreviousData/binary, Data/binary>>};
-%% already fully contained fragment
+ fragment_length = PreviousLen + CurrentLen,
+ fragment = <<PreviousData/binary, CurrentData/binary>>
+ };
+
+%% Adjacent fragments
+%% 2,5 _ _ P P P P P
+%% 0,2 C C
merge_fragments(#handshake_fragment{
- fragment_offset = PreviousOffSet,
- fragment_length = PreviousLen
- } = Previous,
+ fragment_offset = PreviousOffset,
+ fragment_length = PreviousLen,
+ fragment = PreviousData
+ } = Previous,
#handshake_fragment{
- fragment_offset = CurrentOffSet,
- fragment_length = CurrentLen})
- when PreviousOffSet + PreviousLen >= CurrentOffSet andalso
- PreviousOffSet + PreviousLen >= CurrentOffSet + CurrentLen ->
- Previous;
+ fragment_offset = CurrentOffset,
+ fragment_length = CurrentLen,
+ fragment = CurrentData})
+ when PreviousOffset =:= CurrentOffset + CurrentLen ->
+ Previous#handshake_fragment{
+ fragment_length = PreviousLen + CurrentLen,
+ fragment = <<CurrentData/binary, PreviousData/binary>>
+ };
%% No merge there is a gap
+%% 3,5 _ _ _ P P P P
+%% 0,2 C C
merge_fragments(Previous, Current) ->
[Previous, Current].
diff --git a/lib/ssl/src/dtls_handshake.hrl b/lib/ssl/src/dtls_handshake.hrl
index 50e92027d2..de2be1daeb 100644
--- a/lib/ssl/src/dtls_handshake.hrl
+++ b/lib/ssl/src/dtls_handshake.hrl
@@ -26,22 +26,13 @@
-ifndef(dtls_handshake).
-define(dtls_handshake, true).
+-include("tls_handshake.hrl"). %% Common TLS and DTLS records and Constantes
-include("ssl_handshake.hrl"). %% Common TLS and DTLS records and Constantes
+-include("ssl_api.hrl").
-define(HELLO_VERIFY_REQUEST, 3).
-define(HELLO_VERIFY_REQUEST_VERSION, {254, 255}).
--record(client_hello, {
- client_version,
- random,
- session_id, % opaque SessionID<0..32>
- cookie, % opaque<2..2^16-1>
- cipher_suites, % cipher_suites<2..2^16-1>
- compression_methods, % compression_methods<1..2^8-1>,
- %% Extensions
- extensions
- }).
-
-record(hello_verify_request, {
protocol_version,
cookie
@@ -56,4 +47,11 @@
fragment
}).
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% RFC 7764 Datagram Transport Layer Security (DTLS) Extension to Establish Keys
+%% for the Secure Real-time Transport Protocol (SRTP)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Not supported
+-define(USE_SRTP, 14).
+
-endif. % -ifdef(dtls_handshake).
diff --git a/lib/ssl/src/dtls_listener_sup.erl b/lib/ssl/src/dtls_listener_sup.erl
new file mode 100644
index 0000000000..dc30696a2c
--- /dev/null
+++ b/lib/ssl/src/dtls_listener_sup.erl
@@ -0,0 +1,62 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2016-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Supervisor for a procsses dispatching upd datagrams to
+%% correct DTLS handler
+%%----------------------------------------------------------------------
+-module(dtls_listener_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/0]).
+-export([start_child/1]).
+
+%% Supervisor callback
+-export([init/1]).
+
+%%%=========================================================================
+%%% API
+%%%=========================================================================
+start_link() ->
+ supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+start_child(Args) ->
+ supervisor:start_child(?MODULE, Args).
+
+%%%=========================================================================
+%%% Supervisor callback
+%%%=========================================================================
+init(_O) ->
+ RestartStrategy = simple_one_for_one,
+ MaxR = 0,
+ MaxT = 3600,
+
+ Name = undefined, % As simple_one_for_one is used.
+ StartFunc = {dtls_packet_demux, start_link, []},
+ Restart = temporary, % E.g. should not be restarted
+ Shutdown = 4000,
+ Modules = [dtls_packet_demux],
+ Type = worker,
+
+ ChildSpec = {Name, StartFunc, Restart, Shutdown, Type, Modules},
+ {ok, {{RestartStrategy, MaxR, MaxT}, [ChildSpec]}}.
diff --git a/lib/ssl/src/dtls_packet_demux.erl b/lib/ssl/src/dtls_packet_demux.erl
new file mode 100644
index 0000000000..c6431b55a9
--- /dev/null
+++ b/lib/ssl/src/dtls_packet_demux.erl
@@ -0,0 +1,328 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2016-2018. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+-module(dtls_packet_demux).
+
+-behaviour(gen_server).
+
+-include("ssl_internal.hrl").
+-include_lib("kernel/include/logger.hrl").
+
+%% API
+-export([start_link/5, active_once/3, accept/2, sockname/1, close/1,
+ get_all_opts/1, get_sock_opts/2, set_sock_opts/2]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+-record(state,
+ {active_n,
+ port,
+ listener,
+ transport,
+ dtls_options,
+ emulated_options,
+ dtls_msq_queues = kv_new(),
+ clients = set_new(),
+ dtls_processes = kv_new(),
+ accepters = queue:new(),
+ first,
+ close
+ }).
+
+%%%===================================================================
+%%% API
+%%%===================================================================
+
+start_link(Port, TransportInfo, EmOpts, InetOptions, DTLSOptions) ->
+ gen_server:start_link(?MODULE, [Port, TransportInfo, EmOpts, InetOptions, DTLSOptions], []).
+
+active_once(PacketSocket, Client, Pid) ->
+ gen_server:cast(PacketSocket, {active_once, Client, Pid}).
+
+accept(PacketSocket, Accepter) ->
+ call(PacketSocket, {accept, Accepter}).
+
+sockname(PacketSocket) ->
+ call(PacketSocket, sockname).
+close(PacketSocket) ->
+ call(PacketSocket, close).
+get_sock_opts(PacketSocket, SplitSockOpts) ->
+ call(PacketSocket, {get_sock_opts, SplitSockOpts}).
+get_all_opts(PacketSocket) ->
+ call(PacketSocket, get_all_opts).
+set_sock_opts(PacketSocket, Opts) ->
+ call(PacketSocket, {set_sock_opts, Opts}).
+
+%%%===================================================================
+%%% gen_server callbacks
+%%%===================================================================
+
+init([Port, {TransportModule, _,_,_,_} = TransportInfo, EmOpts, InetOptions, DTLSOptions]) ->
+ try
+ {ok, Socket} = TransportModule:open(Port, InetOptions),
+ InternalActiveN = case application:get_env(ssl, internal_active_n) of
+ {ok, N} when is_integer(N) ->
+ N;
+ _ ->
+ ?INTERNAL_ACTIVE_N
+ end,
+
+ {ok, #state{active_n = InternalActiveN,
+ port = Port,
+ first = true,
+ transport = TransportInfo,
+ dtls_options = DTLSOptions,
+ emulated_options = EmOpts,
+ listener = Socket,
+ close = false}}
+ catch _:_ ->
+ {stop, {shutdown, {error, closed}}}
+ end.
+handle_call({accept, _}, _, #state{close = true} = State) ->
+ {reply, {error, closed}, State};
+
+handle_call({accept, Accepter}, From, #state{active_n = N,
+ first = true,
+ accepters = Accepters,
+ listener = Socket} = State0) ->
+ next_datagram(Socket, N),
+ State = State0#state{first = false,
+ accepters = queue:in({Accepter, From}, Accepters)},
+ {noreply, State};
+
+handle_call({accept, Accepter}, From, #state{accepters = Accepters} = State0) ->
+ State = State0#state{accepters = queue:in({Accepter, From}, Accepters)},
+ {noreply, State};
+handle_call(sockname, _, #state{listener = Socket} = State) ->
+ Reply = inet:sockname(Socket),
+ {reply, Reply, State};
+handle_call(close, _, #state{dtls_processes = Processes,
+ accepters = Accepters} = State) ->
+ case kv_empty(Processes) of
+ true ->
+ {stop, normal, ok, State#state{close=true}};
+ false ->
+ lists:foreach(fun({_, From}) ->
+ gen_server:reply(From, {error, closed})
+ end, queue:to_list(Accepters)),
+ {reply, ok, State#state{close = true, accepters = queue:new()}}
+ end;
+handle_call({get_sock_opts, {SocketOptNames, EmOptNames}}, _, #state{listener = Socket,
+ emulated_options = EmOpts} = State) ->
+ case get_socket_opts(Socket, SocketOptNames) of
+ {ok, Opts} ->
+ {reply, {ok, emulated_opts_list(EmOpts, EmOptNames, []) ++ Opts}, State};
+ {error, Reason} ->
+ {reply, {error, Reason}, State}
+ end;
+handle_call(get_all_opts, _, #state{dtls_options = DTLSOptions,
+ emulated_options = EmOpts} = State) ->
+ {reply, {ok, EmOpts, DTLSOptions}, State};
+handle_call({set_sock_opts, {SocketOpts, NewEmOpts}}, _, #state{listener = Socket, emulated_options = EmOpts0} = State) ->
+ set_socket_opts(Socket, SocketOpts),
+ EmOpts = do_set_emulated_opts(NewEmOpts, EmOpts0),
+ {reply, ok, State#state{emulated_options = EmOpts}}.
+
+handle_cast({active_once, Client, Pid}, State0) ->
+ State = handle_active_once(Client, Pid, State0),
+ {noreply, State}.
+
+handle_info({Transport, Socket, IP, InPortNo, _} = Msg, #state{listener = Socket, transport = {_,Transport,_,_,_}} = State0) ->
+ State = handle_datagram({IP, InPortNo}, Msg, State0),
+ {noreply, State};
+
+handle_info({PassiveTag, Socket},
+ #state{active_n = N,
+ listener = Socket,
+ transport = {_,_,_, udp_error, PassiveTag}}) ->
+ next_datagram(Socket, N);
+
+%% UDP socket does not have a connection and should not receive an econnreset
+%% This does however happens on some windows versions. Just ignoring it
+%% appears to make things work as expected!
+handle_info({udp_error, Socket, econnreset = Error}, #state{listener = Socket, transport = {_,_,_, udp_error,_}} = State) ->
+ Report = io_lib:format("Ignore SSL UDP Listener: Socket error: ~p ~n", [Error]),
+ ?LOG_NOTICE(Report),
+ {noreply, State};
+handle_info({ErrorTag, Socket, Error}, #state{listener = Socket, transport = {_,_,_, ErrorTag,_}} = State) ->
+ Report = io_lib:format("SSL Packet muliplxer shutdown: Socket error: ~p ~n", [Error]),
+ ?LOG_NOTICE(Report),
+ {noreply, State#state{close=true}};
+
+handle_info({'DOWN', _, process, Pid, _}, #state{clients = Clients,
+ dtls_processes = Processes0,
+ dtls_msq_queues = MsgQueues0,
+ close = ListenClosed} = State) ->
+ Client = kv_get(Pid, Processes0),
+ Processes = kv_delete(Pid, Processes0),
+ MsgQueues = kv_delete(Client, MsgQueues0),
+ case ListenClosed andalso kv_empty(Processes) of
+ true ->
+ {stop, normal, State};
+ false ->
+ {noreply, State#state{clients = set_delete(Client, Clients),
+ dtls_processes = Processes,
+ dtls_msq_queues = MsgQueues}}
+ end.
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%%%===================================================================
+%%% Internal functions
+%%%===================================================================
+handle_datagram(Client, Msg, #state{clients = Clients,
+ accepters = AcceptorsQueue0} = State) ->
+ case set_is_member(Client, Clients) of
+ false ->
+ case queue:out(AcceptorsQueue0) of
+ {{value, {UserPid, From}}, AcceptorsQueue} ->
+ setup_new_connection(UserPid, From, Client, Msg,
+ State#state{accepters = AcceptorsQueue});
+ {empty, _} ->
+ %% Drop packet client will resend
+ State
+ end;
+ true ->
+ dispatch(Client, Msg, State)
+ end.
+
+dispatch(Client, Msg, #state{dtls_msq_queues = MsgQueues} = State) ->
+ case kv_lookup(Client, MsgQueues) of
+ {value, Queue0} ->
+ case queue:out(Queue0) of
+ {{value, Pid}, Queue} when is_pid(Pid) ->
+ Pid ! Msg,
+ State#state{dtls_msq_queues =
+ kv_update(Client, Queue, MsgQueues)};
+ {{value, _UDP}, _Queue} ->
+ State#state{dtls_msq_queues =
+ kv_update(Client, queue:in(Msg, Queue0), MsgQueues)};
+ {empty, Queue} ->
+ State#state{dtls_msq_queues =
+ kv_update(Client, queue:in(Msg, Queue), MsgQueues)}
+ end
+ end.
+next_datagram(Socket, N) ->
+ inet:setopts(Socket, [{active, N}]).
+
+handle_active_once(Client, Pid, #state{dtls_msq_queues = MsgQueues} = State0) ->
+ Queue0 = kv_get(Client, MsgQueues),
+ case queue:out(Queue0) of
+ {{value, Pid}, _} when is_pid(Pid) ->
+ State0;
+ {{value, Msg}, Queue} ->
+ Pid ! Msg,
+ State0#state{dtls_msq_queues = kv_update(Client, Queue, MsgQueues)};
+ {empty, Queue0} ->
+ State0#state{dtls_msq_queues = kv_update(Client, queue:in(Pid, Queue0), MsgQueues)}
+ end.
+
+setup_new_connection(User, From, Client, Msg, #state{dtls_processes = Processes,
+ clients = Clients,
+ dtls_msq_queues = MsgQueues,
+ dtls_options = DTLSOpts,
+ port = Port,
+ listener = Socket,
+ emulated_options = EmOpts} = State) ->
+ ConnArgs = [server, "localhost", Port, {self(), {Client, Socket}},
+ {DTLSOpts, EmOpts, dtls_listener}, User, dtls_socket:default_cb_info()],
+ case dtls_connection_sup:start_child(ConnArgs) of
+ {ok, Pid} ->
+ erlang:monitor(process, Pid),
+ gen_server:reply(From, {ok, Pid, {Client, Socket}}),
+ Pid ! Msg,
+ State#state{clients = set_insert(Client, Clients),
+ dtls_msq_queues = kv_insert(Client, queue:new(), MsgQueues),
+ dtls_processes = kv_insert(Pid, Client, Processes)};
+ {error, Reason} ->
+ gen_server:reply(From, {error, Reason}),
+ State
+ end.
+
+kv_update(Key, Value, Store) ->
+ gb_trees:update(Key, Value, Store).
+kv_lookup(Key, Store) ->
+ gb_trees:lookup(Key, Store).
+kv_insert(Key, Value, Store) ->
+ gb_trees:insert(Key, Value, Store).
+kv_get(Key, Store) ->
+ gb_trees:get(Key, Store).
+kv_delete(Key, Store) ->
+ gb_trees:delete(Key, Store).
+kv_new() ->
+ gb_trees:empty().
+kv_empty(Store) ->
+ gb_trees:is_empty(Store).
+
+set_new() ->
+ gb_sets:empty().
+set_insert(Item, Set) ->
+ gb_sets:insert(Item, Set).
+set_delete(Item, Set) ->
+ gb_sets:delete(Item, Set).
+set_is_member(Item, Set) ->
+ gb_sets:is_member(Item, Set).
+
+call(Server, Msg) ->
+ try
+ gen_server:call(Server, Msg, infinity)
+ catch
+ exit:{noproc, _} ->
+ {error, closed};
+ exit:{normal, _} ->
+ {error, closed};
+ exit:{{shutdown, _},_} ->
+ {error, closed}
+ end.
+
+set_socket_opts(_, []) ->
+ ok;
+set_socket_opts(Socket, SocketOpts) ->
+ inet:setopts(Socket, SocketOpts).
+
+get_socket_opts(_, []) ->
+ {ok, []};
+get_socket_opts(Socket, SocketOpts) ->
+ inet:getopts(Socket, SocketOpts).
+
+do_set_emulated_opts([], Opts) ->
+ Opts;
+do_set_emulated_opts([{mode, Value} | Rest], Opts) ->
+ do_set_emulated_opts(Rest, Opts#socket_options{mode = Value});
+do_set_emulated_opts([{active, N0} | Rest], Opts=#socket_options{active = Active}) when is_integer(N0) ->
+ N = tls_socket:update_active_n(N0, Active),
+ do_set_emulated_opts(Rest, Opts#socket_options{active = N});
+do_set_emulated_opts([{active, Value} | Rest], Opts) ->
+ do_set_emulated_opts(Rest, Opts#socket_options{active = Value}).
+
+emulated_opts_list(_,[], Acc) ->
+ Acc;
+emulated_opts_list( Opts, [mode | Rest], Acc) ->
+ emulated_opts_list(Opts, Rest, [{mode, Opts#socket_options.mode} | Acc]);
+emulated_opts_list(Opts, [active | Rest], Acc) ->
+ emulated_opts_list(Opts, Rest, [{active, Opts#socket_options.active} | Acc]).
+
diff --git a/lib/ssl/src/dtls_record.erl b/lib/ssl/src/dtls_record.erl
index 316de05532..a4846f42c5 100644
--- a/lib/ssl/src/dtls_record.erl
+++ b/lib/ssl/src/dtls_record.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -30,7 +30,7 @@
-include("ssl_cipher.hrl").
%% Handling of incoming data
--export([get_dtls_records/3, init_connection_states/2, empty_connection_state/1]).
+-export([get_dtls_records/4, init_connection_states/2, empty_connection_state/1]).
-export([save_current_connection_state/2, next_epoch/2, get_connection_state_by_epoch/3, replay_detect/2,
init_connection_state_seq/2, current_connection_state_epoch/2]).
@@ -49,9 +49,8 @@
is_acceptable_version/2, hello_version/2]).
--export_type([dtls_version/0, dtls_atom_version/0]).
+-export_type([dtls_atom_version/0]).
--type dtls_version() :: ssl_record:ssl_version().
-type dtls_atom_version() :: dtlsv1 | 'dtlsv1.2'.
-define(REPLAY_WINDOW_SIZE, 64).
@@ -135,7 +134,7 @@ set_connection_state_by_epoch(ReadState, Epoch, #{saved_read := #{epoch := Epoch
States#{saved_read := ReadState}.
%%--------------------------------------------------------------------
--spec init_connection_state_seq(dtls_version(), ssl_record:connection_states()) ->
+-spec init_connection_state_seq(ssl_record:ssl_version(), ssl_record:connection_states()) ->
ssl_record:connection_state().
%%
%% Description: Copy the read sequence number to the write sequence number
@@ -163,24 +162,25 @@ current_connection_state_epoch(#{current_write := #{epoch := Epoch}},
Epoch.
%%--------------------------------------------------------------------
--spec get_dtls_records(binary(), [dtls_version()], binary()) -> {[binary()], binary()} | #alert{}.
+-spec get_dtls_records(binary(), [ssl_record:ssl_version()], binary(),
+ #ssl_options{}) -> {[binary()], binary()} | #alert{}.
%%
%% Description: Given old buffer and new data from UDP/SCTP, packs up a records
%% and returns it as a list of tls_compressed binaries also returns leftover
%% data
%%--------------------------------------------------------------------
-get_dtls_records(Data, Versions, Buffer) ->
+get_dtls_records(Data, Versions, Buffer, SslOpts) ->
BinData = list_to_binary([Buffer, Data]),
case erlang:byte_size(BinData) of
N when N >= 3 ->
case assert_version(BinData, Versions) of
true ->
- get_dtls_records_aux(BinData, []);
+ get_dtls_records_aux(BinData, [], SslOpts);
false ->
?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
end;
_ ->
- get_dtls_records_aux(BinData, [])
+ get_dtls_records_aux(BinData, [], SslOpts)
end.
%%====================================================================
@@ -188,7 +188,7 @@ get_dtls_records(Data, Versions, Buffer) ->
%%====================================================================
%%--------------------------------------------------------------------
--spec encode_handshake(iolist(), dtls_version(), integer(), ssl_record:connection_states()) ->
+-spec encode_handshake(iolist(), ssl_record:ssl_version(), integer(), ssl_record:connection_states()) ->
{iolist(), ssl_record:connection_states()}.
%
%% Description: Encodes a handshake message to send on the ssl-socket.
@@ -198,7 +198,7 @@ encode_handshake(Frag, Version, Epoch, ConnectionStates) ->
%%--------------------------------------------------------------------
--spec encode_alert_record(#alert{}, dtls_version(), ssl_record:connection_states()) ->
+-spec encode_alert_record(#alert{}, ssl_record:ssl_version(), ssl_record:connection_states()) ->
{iolist(), ssl_record:connection_states()}.
%%
%% Description: Encodes an alert message to send on the ssl-socket.
@@ -210,7 +210,7 @@ encode_alert_record(#alert{level = Level, description = Description},
ConnectionStates).
%%--------------------------------------------------------------------
--spec encode_change_cipher_spec(dtls_version(), integer(), ssl_record:connection_states()) ->
+-spec encode_change_cipher_spec(ssl_record:ssl_version(), integer(), ssl_record:connection_states()) ->
{iolist(), ssl_record:connection_states()}.
%%
%% Description: Encodes a change_cipher_spec-message to send on the ssl socket.
@@ -219,7 +219,7 @@ encode_change_cipher_spec(Version, Epoch, ConnectionStates) ->
encode_plain_text(?CHANGE_CIPHER_SPEC, Version, Epoch, ?byte(?CHANGE_CIPHER_SPEC_PROTO), ConnectionStates).
%%--------------------------------------------------------------------
--spec encode_data(binary(), dtls_version(), ssl_record:connection_states()) ->
+-spec encode_data(binary(), ssl_record:ssl_version(), ssl_record:connection_states()) ->
{iolist(),ssl_record:connection_states()}.
%%
%% Description: Encodes data to send on the ssl-socket.
@@ -248,8 +248,8 @@ decode_cipher_text(#ssl_tls{epoch = Epoch} = CipherText, ConnnectionStates0) ->
%%====================================================================
%%--------------------------------------------------------------------
--spec protocol_version(dtls_atom_version() | dtls_version()) ->
- dtls_version() | dtls_atom_version().
+-spec protocol_version(dtls_atom_version() | ssl_record:ssl_version()) ->
+ ssl_record:ssl_version() | dtls_atom_version().
%%
%% Description: Creates a protocol version record from a version atom
%% or vice versa.
@@ -263,7 +263,7 @@ protocol_version({254, 253}) ->
protocol_version({254, 255}) ->
dtlsv1.
%%--------------------------------------------------------------------
--spec lowest_protocol_version(dtls_version(), dtls_version()) -> dtls_version().
+-spec lowest_protocol_version(ssl_record:ssl_version(), ssl_record:ssl_version()) -> ssl_record:ssl_version().
%%
%% Description: Lowes protocol version of two given versions
%%--------------------------------------------------------------------
@@ -277,7 +277,7 @@ lowest_protocol_version(_,Version) ->
Version.
%%--------------------------------------------------------------------
--spec lowest_protocol_version([dtls_version()]) -> dtls_version().
+-spec lowest_protocol_version([ssl_record:ssl_version()]) -> ssl_record:ssl_version().
%%
%% Description: Lowest protocol version present in a list
%%--------------------------------------------------------------------
@@ -288,7 +288,7 @@ lowest_protocol_version(Versions) ->
lowest_list_protocol_version(Ver, Vers).
%%--------------------------------------------------------------------
--spec highest_protocol_version([dtls_version()]) -> dtls_version().
+-spec highest_protocol_version([ssl_record:ssl_version()]) -> ssl_record:ssl_version().
%%
%% Description: Highest protocol version present in a list
%%--------------------------------------------------------------------
@@ -299,7 +299,7 @@ highest_protocol_version(Versions) ->
highest_list_protocol_version(Ver, Vers).
%%--------------------------------------------------------------------
--spec highest_protocol_version(dtls_version(), dtls_version()) -> dtls_version().
+-spec highest_protocol_version(ssl_record:ssl_version(), ssl_record:ssl_version()) -> ssl_record:ssl_version().
%%
%% Description: Highest protocol version of two given versions
%%--------------------------------------------------------------------
@@ -315,7 +315,7 @@ highest_protocol_version(_,Version) ->
Version.
%%--------------------------------------------------------------------
--spec is_higher(V1 :: dtls_version(), V2::dtls_version()) -> boolean().
+-spec is_higher(V1 :: ssl_record:ssl_version(), V2::ssl_record:ssl_version()) -> boolean().
%%
%% Description: Is V1 > V2
%%--------------------------------------------------------------------
@@ -327,7 +327,7 @@ is_higher(_, _) ->
false.
%%--------------------------------------------------------------------
--spec supported_protocol_versions() -> [dtls_version()].
+-spec supported_protocol_versions() -> [ssl_record:ssl_version()].
%%
%% Description: Protocol versions supported
%%--------------------------------------------------------------------
@@ -370,7 +370,7 @@ supported_protocol_versions([_|_] = Vsns) ->
end.
%%--------------------------------------------------------------------
--spec is_acceptable_version(dtls_version(), Supported :: [dtls_version()]) -> boolean().
+-spec is_acceptable_version(ssl_record:ssl_version(), Supported :: [ssl_record:ssl_version()]) -> boolean().
%%
%% Description: ssl version 2 is not acceptable security risks are too big.
%%
@@ -378,7 +378,7 @@ supported_protocol_versions([_|_] = Vsns) ->
is_acceptable_version(Version, Versions) ->
lists:member(Version, Versions).
--spec hello_version(dtls_version(), [dtls_version()]) -> dtls_version().
+-spec hello_version(ssl_record:ssl_version(), [ssl_record:ssl_version()]) -> ssl_record:ssl_version().
hello_version(Version, Versions) ->
case dtls_v1:corresponding_tls_version(Version) of
TLSVersion when TLSVersion >= {3, 3} ->
@@ -410,43 +410,47 @@ assert_version(<<?BYTE(_), ?BYTE(MajVer), ?BYTE(MinVer), _/binary>>, Versions) -
get_dtls_records_aux(<<?BYTE(?APPLICATION_DATA),?BYTE(MajVer),?BYTE(MinVer),
?UINT16(Epoch), ?UINT48(SequenceNumber),
- ?UINT16(Length), Data:Length/binary, Rest/binary>>,
- Acc) ->
+ ?UINT16(Length), Data:Length/binary, Rest/binary>> = RawDTLSRecord,
+ Acc, SslOpts) ->
+ ssl_logger:debug(SslOpts#ssl_options.log_level, inbound, 'record', [RawDTLSRecord]),
get_dtls_records_aux(Rest, [#ssl_tls{type = ?APPLICATION_DATA,
version = {MajVer, MinVer},
epoch = Epoch, sequence_number = SequenceNumber,
- fragment = Data} | Acc]);
+ fragment = Data} | Acc], SslOpts);
get_dtls_records_aux(<<?BYTE(?HANDSHAKE),?BYTE(MajVer),?BYTE(MinVer),
?UINT16(Epoch), ?UINT48(SequenceNumber),
?UINT16(Length),
- Data:Length/binary, Rest/binary>>, Acc) when MajVer >= 128 ->
+ Data:Length/binary, Rest/binary>> = RawDTLSRecord,
+ Acc, SslOpts) when MajVer >= 128 ->
+ ssl_logger:debug(SslOpts#ssl_options.log_level, inbound, 'record', [RawDTLSRecord]),
get_dtls_records_aux(Rest, [#ssl_tls{type = ?HANDSHAKE,
version = {MajVer, MinVer},
epoch = Epoch, sequence_number = SequenceNumber,
- fragment = Data} | Acc]);
+ fragment = Data} | Acc], SslOpts);
get_dtls_records_aux(<<?BYTE(?ALERT),?BYTE(MajVer),?BYTE(MinVer),
?UINT16(Epoch), ?UINT48(SequenceNumber),
?UINT16(Length), Data:Length/binary,
- Rest/binary>>, Acc) ->
+ Rest/binary>> = RawDTLSRecord, Acc, SslOpts) ->
+ ssl_logger:debug(SslOpts#ssl_options.log_level, inbound, 'record', [RawDTLSRecord]),
get_dtls_records_aux(Rest, [#ssl_tls{type = ?ALERT,
version = {MajVer, MinVer},
epoch = Epoch, sequence_number = SequenceNumber,
- fragment = Data} | Acc]);
+ fragment = Data} | Acc], SslOpts);
get_dtls_records_aux(<<?BYTE(?CHANGE_CIPHER_SPEC),?BYTE(MajVer),?BYTE(MinVer),
?UINT16(Epoch), ?UINT48(SequenceNumber),
- ?UINT16(Length), Data:Length/binary, Rest/binary>>,
- Acc) ->
+ ?UINT16(Length), Data:Length/binary, Rest/binary>> = RawDTLSRecord,
+ Acc, SslOpts) ->
+ ssl_logger:debug(SslOpts#ssl_options.log_level, inbound, 'record', [RawDTLSRecord]),
get_dtls_records_aux(Rest, [#ssl_tls{type = ?CHANGE_CIPHER_SPEC,
version = {MajVer, MinVer},
epoch = Epoch, sequence_number = SequenceNumber,
- fragment = Data} | Acc]);
-
+ fragment = Data} | Acc], SslOpts);
get_dtls_records_aux(<<?BYTE(_), ?BYTE(_MajVer), ?BYTE(_MinVer),
?UINT16(Length), _/binary>>,
- _Acc) when Length > ?MAX_CIPHER_TEXT_LENGTH ->
+ _Acc, _) when Length > ?MAX_CIPHER_TEXT_LENGTH ->
?ALERT_REC(?FATAL, ?RECORD_OVERFLOW);
-get_dtls_records_aux(Data, Acc) ->
+get_dtls_records_aux(Data, Acc, _) ->
case size(Data) =< ?MAX_CIPHER_TEXT_LENGTH + ?INITIAL_BYTES of
true ->
{lists:reverse(Acc), Data};
@@ -500,23 +504,22 @@ encode_dtls_cipher_text(Type, {MajVer, MinVer}, Fragment,
WriteState#{sequence_number => Seq + 1}}.
encode_plain_text(Type, Version, Data, #{compression_state := CompS0,
+ cipher_state := CipherS0,
epoch := Epoch,
sequence_number := Seq,
- cipher_state := CipherS0,
security_parameters :=
#security_parameters{
cipher_type = ?AEAD,
- bulk_cipher_algorithm =
- BulkCipherAlgo,
+ bulk_cipher_algorithm = BCAlg,
compression_algorithm = CompAlg}
} = WriteState0) ->
{Comp, CompS1} = ssl_record:compress(CompAlg, Data, CompS0),
- AAD = calc_aad(Type, Version, Epoch, Seq),
+ AAD = start_additional_data(Type, Version, Epoch, Seq),
+ CipherS = ssl_record:nonce_seed(BCAlg, <<?UINT16(Epoch), ?UINT48(Seq)>>, CipherS0),
+ WriteState = WriteState0#{compression_state => CompS1,
+ cipher_state => CipherS},
TLSVersion = dtls_v1:corresponding_tls_version(Version),
- {CipherFragment, CipherS1} =
- ssl_cipher:cipher_aead(BulkCipherAlgo, CipherS0, Seq, AAD, Comp, TLSVersion),
- {CipherFragment, WriteState0#{compression_state => CompS1,
- cipher_state => CipherS1}};
+ ssl_record:cipher_aead(TLSVersion, Comp, WriteState, AAD);
encode_plain_text(Type, Version, Fragment, #{compression_state := CompS0,
epoch := Epoch,
sequence_number := Seq,
@@ -548,15 +551,16 @@ decode_cipher_text(#ssl_tls{type = Type, version = Version,
BulkCipherAlgo,
compression_algorithm = CompAlg}} = ReadState0,
ConnnectionStates0) ->
- AAD = calc_aad(Type, Version, Epoch, Seq),
+ AAD = start_additional_data(Type, Version, Epoch, Seq),
+ CipherS = ssl_record:nonce_seed(BulkCipherAlgo, <<?UINT16(Epoch), ?UINT48(Seq)>>, CipherS0),
TLSVersion = dtls_v1:corresponding_tls_version(Version),
- case ssl_cipher:decipher_aead(BulkCipherAlgo, CipherS0, Seq, AAD, CipherFragment, TLSVersion) of
- {PlainFragment, CipherState} ->
- {Plain, CompressionS1} = ssl_record:uncompress(CompAlg,
+ case ssl_record:decipher_aead(BulkCipherAlgo, CipherS, AAD, CipherFragment, TLSVersion) of
+ PlainFragment when is_binary(PlainFragment) ->
+ {Plain, CompressionS} = ssl_record:uncompress(CompAlg,
PlainFragment, CompressionS0),
- ReadState0 = ReadState0#{compression_state => CompressionS1,
- cipher_state => CipherState},
- ReadState = update_replay_window(Seq, ReadState0),
+ ReadState1 = ReadState0#{compression_state := CompressionS,
+ cipher_state := CipherS},
+ ReadState = update_replay_window(Seq, ReadState1),
ConnnectionStates = set_connection_state_by_epoch(ReadState, Epoch, ConnnectionStates0, read),
{CipherText#ssl_tls{fragment = Plain}, ConnnectionStates};
#alert{} = Alert ->
@@ -601,7 +605,7 @@ mac_hash({Major, Minor}, MacAlg, MacSecret, Epoch, SeqNo, Type, Length, Fragment
Fragment],
dtls_v1:hmac_hash(MacAlg, MacSecret, Value).
-calc_aad(Type, {MajVer, MinVer}, Epoch, SeqNo) ->
+start_additional_data(Type, {MajVer, MinVer}, Epoch, SeqNo) ->
<<?UINT16(Epoch), ?UINT48(SeqNo), ?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer)>>.
%%--------------------------------------------------------------------
diff --git a/lib/ssl/src/dtls_socket.erl b/lib/ssl/src/dtls_socket.erl
index 0e4ab089dc..b305d08f70 100644
--- a/lib/ssl/src/dtls_socket.erl
+++ b/lib/ssl/src/dtls_socket.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2016-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2016-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -22,38 +22,40 @@
-include("ssl_internal.hrl").
-include("ssl_api.hrl").
--export([send/3, listen/3, accept/3, connect/4, socket/4, setopts/3, getopts/3, getstat/3,
+-export([send/3, listen/2, accept/3, connect/4, socket/4, setopts/3, getopts/3, getstat/3,
peername/2, sockname/2, port/2, close/2]).
-export([emulated_options/0, emulated_options/1, internal_inet_values/0, default_inet_values/0, default_cb_info/0]).
send(Transport, {{IP,Port},Socket}, Data) ->
Transport:send(Socket, IP, Port, Data).
-listen(gen_udp = Transport, Port, #config{transport_info = {Transport, _, _, _},
- ssl = SslOpts,
- emulated = EmOpts,
- inet_user = Options} = Config) ->
+listen(Port, #config{transport_info = TransportInfo,
+ ssl = SslOpts,
+ emulated = EmOpts,
+ inet_user = Options} = Config) ->
- case dtls_udp_sup:start_child([Port, emulated_socket_options(EmOpts, #socket_options{}),
+ case dtls_listener_sup:start_child([Port, TransportInfo, emulated_socket_options(EmOpts, #socket_options{}),
Options ++ internal_inet_values(), SslOpts]) of
{ok, Pid} ->
- {ok, #sslsocket{pid = {udp, Config#config{udp_handler = {Pid, Port}}}}};
+ Socket = #sslsocket{pid = {dtls, Config#config{dtls_handler = {Pid, Port}}}},
+ check_active_n(EmOpts, Socket),
+ {ok, Socket};
Err = {error, _} ->
Err
end.
-accept(udp, #config{transport_info = {Transport = gen_udp,_,_,_},
+accept(dtls, #config{transport_info = {Transport,_,_,_,_},
connection_cb = ConnectionCb,
- udp_handler = {Listner, _}}, _Timeout) ->
- case dtls_udp_listener:accept(Listner, self()) of
+ dtls_handler = {Listner, _}}, _Timeout) ->
+ case dtls_packet_demux:accept(Listner, self()) of
{ok, Pid, Socket} ->
- {ok, socket(Pid, Transport, {Listner, Socket}, ConnectionCb)};
+ {ok, socket([Pid], Transport, {Listner, Socket}, ConnectionCb)};
{error, Reason} ->
{error, Reason}
end.
-connect(Address, Port, #config{transport_info = {Transport, _, _, _} = CbInfo,
+connect(Address, Port, #config{transport_info = {Transport, _, _, _, _} = CbInfo,
connection_cb = ConnectionCb,
ssl = SslOpts,
emulated = EmOpts,
@@ -69,28 +71,57 @@ connect(Address, Port, #config{transport_info = {Transport, _, _, _} = CbInfo,
end.
close(gen_udp, {_Client, _Socket}) ->
- ok.
+ ok;
+close(Transport, {_Client, Socket}) ->
+ Transport:close(Socket).
-socket(Pid, gen_udp = Transport, {{_, _}, Socket}, ConnectionCb) ->
- #sslsocket{pid = Pid,
+socket(Pids, gen_udp = Transport, {{_, _}, Socket}, ConnectionCb) ->
+ #sslsocket{pid = Pids,
%% "The name "fd" is keept for backwards compatibility
fd = {Transport, Socket, ConnectionCb}};
-socket(Pid, Transport, Socket, ConnectionCb) ->
- #sslsocket{pid = Pid,
+socket(Pids, Transport, Socket, ConnectionCb) ->
+ #sslsocket{pid = Pids,
%% "The name "fd" is keept for backwards compatibility
fd = {Transport, Socket, ConnectionCb}}.
-setopts(_, #sslsocket{pid = {udp, #config{udp_handler = {ListenPid, _}}}}, Options) ->
- SplitOpts = tls_socket:split_options(Options),
- dtls_udp_listener:set_sock_opts(ListenPid, SplitOpts);
+setopts(_, Socket = #sslsocket{pid = {dtls, #config{dtls_handler = {ListenPid, _}}}}, Options) ->
+ SplitOpts = {_, EmOpts} = tls_socket:split_options(Options),
+ check_active_n(EmOpts, Socket),
+ dtls_packet_demux:set_sock_opts(ListenPid, SplitOpts);
%%% Following clauses will not be called for emulated options, they are handled in the connection process
setopts(gen_udp, Socket, Options) ->
inet:setopts(Socket, Options);
setopts(Transport, Socket, Options) ->
Transport:setopts(Socket, Options).
-getopts(_, #sslsocket{pid = {udp, #config{udp_handler = {ListenPid, _}}}}, Options) ->
+check_active_n(EmulatedOpts, Socket = #sslsocket{pid = {dtls, #config{dtls_handler = {ListenPid, _}}}}) ->
+ %% We check the resulting options to send an ssl_passive message if necessary.
+ case proplists:lookup(active, EmulatedOpts) of
+ %% The provided value is out of bound.
+ {_, N} when is_integer(N), N < -32768 ->
+ throw(einval);
+ {_, N} when is_integer(N), N > 32767 ->
+ throw(einval);
+ {_, N} when is_integer(N) ->
+ {ok, #socket_options{active = Active}, _} = dtls_packet_demux:get_all_opts(ListenPid),
+ case Active of
+ Atom when is_atom(Atom), N =< 0 ->
+ self() ! {ssl_passive, Socket};
+ %% The result of the addition is out of bound.
+ %% We do not need to check < -32768 because Active can't be below 1.
+ A when is_integer(A), A + N > 32767 ->
+ throw(einval);
+ A when is_integer(A), A + N =< 0 ->
+ self() ! {ssl_passive, Socket};
+ _ ->
+ ok
+ end;
+ _ ->
+ ok
+ end.
+
+getopts(_, #sslsocket{pid = {dtls, #config{dtls_handler = {ListenPid, _}}}}, Options) ->
SplitOpts = tls_socket:split_options(Options),
- dtls_udp_listener:get_sock_opts(ListenPid, SplitOpts);
+ dtls_packet_demux:get_sock_opts(ListenPid, SplitOpts);
getopts(gen_udp, #sslsocket{pid = {Socket, #config{emulated = EmOpts}}}, Options) ->
{SockOptNames, EmulatedOptNames} = tls_socket:split_options(Options),
EmulatedOpts = get_emulated_opts(EmOpts, EmulatedOptNames),
@@ -112,7 +143,7 @@ getstat(gen_udp, {_,Socket}, Options) ->
inet:getstat(Socket, Options);
getstat(Transport, Socket, Options) ->
Transport:getstat(Socket, Options).
-peername(udp, _) ->
+peername(_, undefined) ->
{error, enotconn};
peername(gen_udp, {_, {Client, _Socket}}) ->
{ok, Client};
@@ -143,7 +174,7 @@ default_inet_values() ->
[{active, true}, {mode, list}, {packet, 0}, {packet_size, 0}].
default_cb_info() ->
- {gen_udp, udp, udp_closed, udp_error}.
+ {gen_udp, udp, udp_closed, udp_error, udp_passive}.
get_emulated_opts(EmOpts, EmOptNames) ->
lists:map(fun(Name) -> {value, Value} = lists:keysearch(Name, 1, EmOpts),
@@ -159,9 +190,18 @@ emulated_socket_options(InetValues, #socket_options{
mode = proplists:get_value(mode, InetValues, Mode),
packet = proplists:get_value(packet, InetValues, Packet),
packet_size = proplists:get_value(packet_size, InetValues, PacketSize),
- active = proplists:get_value(active, InetValues, Active)
+ active = emulated_active_option(InetValues, Active)
}.
+emulated_active_option([], Active) ->
+ Active;
+emulated_active_option([{active, Active} | _], _) when Active =< 0 ->
+ false;
+emulated_active_option([{active, Active} | _], _) ->
+ Active;
+emulated_active_option([_|Tail], Active) ->
+ emulated_active_option(Tail, Active).
+
emulated_options([{mode, Value} = Opt |Opts], Inet, Emulated) ->
validate_inet_option(mode, Value),
emulated_options(Opts, Inet, [Opt | proplists:delete(mode, Emulated)]);
@@ -183,6 +223,9 @@ validate_inet_option(mode, Value)
when Value =/= list, Value =/= binary ->
throw({error, {options, {mode,Value}}});
validate_inet_option(active, Value)
+ when Value >= -32768, Value =< 32767 ->
+ ok;
+validate_inet_option(active, Value)
when Value =/= true, Value =/= false, Value =/= once ->
throw({error, {options, {active,Value}}});
validate_inet_option(_, _) ->
diff --git a/lib/ssl/src/dtls_udp_listener.erl b/lib/ssl/src/dtls_udp_listener.erl
deleted file mode 100644
index 12e54a0e51..0000000000
--- a/lib/ssl/src/dtls_udp_listener.erl
+++ /dev/null
@@ -1,307 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2016-2017. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
-
--module(dtls_udp_listener).
-
--behaviour(gen_server).
-
--include("ssl_internal.hrl").
-
-%% API
--export([start_link/4, active_once/3, accept/2, sockname/1, close/1,
- get_all_opts/1, get_sock_opts/2, set_sock_opts/2]).
-
-%% gen_server callbacks
--export([init/1, handle_call/3, handle_cast/2, handle_info/2,
- terminate/2, code_change/3]).
-
--record(state,
- {port,
- listner,
- dtls_options,
- emulated_options,
- dtls_msq_queues = kv_new(),
- clients = set_new(),
- dtls_processes = kv_new(),
- accepters = queue:new(),
- first,
- close
- }).
-
-%%%===================================================================
-%%% API
-%%%===================================================================
-
-start_link(Port, EmOpts, InetOptions, DTLSOptions) ->
- gen_server:start_link(?MODULE, [Port, EmOpts, InetOptions, DTLSOptions], []).
-
-active_once(UDPConnection, Client, Pid) ->
- gen_server:cast(UDPConnection, {active_once, Client, Pid}).
-
-accept(UDPConnection, Accepter) ->
- call(UDPConnection, {accept, Accepter}).
-
-sockname(UDPConnection) ->
- call(UDPConnection, sockname).
-close(UDPConnection) ->
- call(UDPConnection, close).
-get_sock_opts(UDPConnection, SplitSockOpts) ->
- call(UDPConnection, {get_sock_opts, SplitSockOpts}).
-get_all_opts(UDPConnection) ->
- call(UDPConnection, get_all_opts).
-set_sock_opts(UDPConnection, Opts) ->
- call(UDPConnection, {set_sock_opts, Opts}).
-
-%%%===================================================================
-%%% gen_server callbacks
-%%%===================================================================
-
-init([Port, EmOpts, InetOptions, DTLSOptions]) ->
- try
- {ok, Socket} = gen_udp:open(Port, InetOptions),
- {ok, #state{port = Port,
- first = true,
- dtls_options = DTLSOptions,
- emulated_options = EmOpts,
- listner = Socket,
- close = false}}
- catch _:_ ->
- {stop, {shutdown, {error, closed}}}
- end.
-handle_call({accept, _}, _, #state{close = true} = State) ->
- {reply, {error, closed}, State};
-
-handle_call({accept, Accepter}, From, #state{first = true,
- accepters = Accepters,
- listner = Socket} = State0) ->
- next_datagram(Socket),
- State = State0#state{first = false,
- accepters = queue:in({Accepter, From}, Accepters)},
- {noreply, State};
-
-handle_call({accept, Accepter}, From, #state{accepters = Accepters} = State0) ->
- State = State0#state{accepters = queue:in({Accepter, From}, Accepters)},
- {noreply, State};
-handle_call(sockname, _, #state{listner = Socket} = State) ->
- Reply = inet:sockname(Socket),
- {reply, Reply, State};
-handle_call(close, _, #state{dtls_processes = Processes,
- accepters = Accepters} = State) ->
- case kv_empty(Processes) of
- true ->
- {stop, normal, ok, State#state{close=true}};
- false ->
- lists:foreach(fun({_, From}) ->
- gen_server:reply(From, {error, closed})
- end, queue:to_list(Accepters)),
- {reply, ok, State#state{close = true, accepters = queue:new()}}
- end;
-handle_call({get_sock_opts, {SocketOptNames, EmOptNames}}, _, #state{listner = Socket,
- emulated_options = EmOpts} = State) ->
- case get_socket_opts(Socket, SocketOptNames) of
- {ok, Opts} ->
- {reply, {ok, emulated_opts_list(EmOpts, EmOptNames, []) ++ Opts}, State};
- {error, Reason} ->
- {reply, {error, Reason}, State}
- end;
-handle_call(get_all_opts, _, #state{dtls_options = DTLSOptions,
- emulated_options = EmOpts} = State) ->
- {reply, {ok, EmOpts, DTLSOptions}, State};
-handle_call({set_sock_opts, {SocketOpts, NewEmOpts}}, _, #state{listner = Socket, emulated_options = EmOpts0} = State) ->
- set_socket_opts(Socket, SocketOpts),
- EmOpts = do_set_emulated_opts(NewEmOpts, EmOpts0),
- {reply, ok, State#state{emulated_options = EmOpts}}.
-
-handle_cast({active_once, Client, Pid}, State0) ->
- State = handle_active_once(Client, Pid, State0),
- {noreply, State}.
-
-handle_info({udp, Socket, IP, InPortNo, _} = Msg, #state{listner = Socket} = State0) ->
- State = handle_datagram({IP, InPortNo}, Msg, State0),
- next_datagram(Socket),
- {noreply, State};
-
-%% UDP socket does not have a connection and should not receive an econnreset
-%% This does however happens on on some windows versions. Just ignoring it
-%% appears to make things work as expected!
-handle_info({udp_error, Socket, econnreset = Error}, #state{listner = Socket} = State) ->
- Report = io_lib:format("Ignore SSL UDP Listener: Socket error: ~p ~n", [Error]),
- error_logger:info_report(Report),
- {noreply, State};
-handle_info({udp_error, Socket, Error}, #state{listner = Socket} = State) ->
- Report = io_lib:format("SSL UDP Listener shutdown: Socket error: ~p ~n", [Error]),
- error_logger:info_report(Report),
- {noreply, State#state{close=true}};
-
-handle_info({'DOWN', _, process, Pid, _}, #state{clients = Clients,
- dtls_processes = Processes0,
- dtls_msq_queues = MsgQueues0,
- close = ListenClosed} = State) ->
- Client = kv_get(Pid, Processes0),
- Processes = kv_delete(Pid, Processes0),
- MsgQueues = kv_delete(Client, MsgQueues0),
- case ListenClosed andalso kv_empty(Processes) of
- true ->
- {stop, normal, State};
- false ->
- {noreply, State#state{clients = set_delete(Client, Clients),
- dtls_processes = Processes,
- dtls_msq_queues = MsgQueues}}
- end.
-
-terminate(_Reason, _State) ->
- ok.
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%%===================================================================
-%%% Internal functions
-%%%===================================================================
-handle_datagram(Client, Msg, #state{clients = Clients,
- accepters = AcceptorsQueue0} = State) ->
- case set_is_member(Client, Clients) of
- false ->
- case queue:out(AcceptorsQueue0) of
- {{value, {UserPid, From}}, AcceptorsQueue} ->
- setup_new_connection(UserPid, From, Client, Msg,
- State#state{accepters = AcceptorsQueue});
- {empty, _} ->
- %% Drop packet client will resend
- State
- end;
- true ->
- dispatch(Client, Msg, State)
- end.
-
-dispatch(Client, Msg, #state{dtls_msq_queues = MsgQueues} = State) ->
- case kv_lookup(Client, MsgQueues) of
- {value, Queue0} ->
- case queue:out(Queue0) of
- {{value, Pid}, Queue} when is_pid(Pid) ->
- Pid ! Msg,
- State#state{dtls_msq_queues =
- kv_update(Client, Queue, MsgQueues)};
- {{value, _}, Queue} ->
- State#state{dtls_msq_queues =
- kv_update(Client, queue:in(Msg, Queue), MsgQueues)};
- {empty, Queue} ->
- State#state{dtls_msq_queues =
- kv_update(Client, queue:in(Msg, Queue), MsgQueues)}
- end
- end.
-next_datagram(Socket) ->
- inet:setopts(Socket, [{active, once}]).
-
-handle_active_once(Client, Pid, #state{dtls_msq_queues = MsgQueues} = State0) ->
- Queue0 = kv_get(Client, MsgQueues),
- case queue:out(Queue0) of
- {{value, Pid}, _} when is_pid(Pid) ->
- State0;
- {{value, Msg}, Queue} ->
- Pid ! Msg,
- State0#state{dtls_msq_queues = kv_update(Client, Queue, MsgQueues)};
- {empty, Queue0} ->
- State0#state{dtls_msq_queues = kv_update(Client, queue:in(Pid, Queue0), MsgQueues)}
- end.
-
-setup_new_connection(User, From, Client, Msg, #state{dtls_processes = Processes,
- clients = Clients,
- dtls_msq_queues = MsgQueues,
- dtls_options = DTLSOpts,
- port = Port,
- listner = Socket,
- emulated_options = EmOpts} = State) ->
- ConnArgs = [server, "localhost", Port, {self(), {Client, Socket}},
- {DTLSOpts, EmOpts, udp_listner}, User, dtls_socket:default_cb_info()],
- case dtls_connection_sup:start_child(ConnArgs) of
- {ok, Pid} ->
- erlang:monitor(process, Pid),
- gen_server:reply(From, {ok, Pid, {Client, Socket}}),
- Pid ! Msg,
- State#state{clients = set_insert(Client, Clients),
- dtls_msq_queues = kv_insert(Client, queue:new(), MsgQueues),
- dtls_processes = kv_insert(Pid, Client, Processes)};
- {error, Reason} ->
- gen_server:reply(From, {error, Reason}),
- State
- end.
-
-kv_update(Key, Value, Store) ->
- gb_trees:update(Key, Value, Store).
-kv_lookup(Key, Store) ->
- gb_trees:lookup(Key, Store).
-kv_insert(Key, Value, Store) ->
- gb_trees:insert(Key, Value, Store).
-kv_get(Key, Store) ->
- gb_trees:get(Key, Store).
-kv_delete(Key, Store) ->
- gb_trees:delete(Key, Store).
-kv_new() ->
- gb_trees:empty().
-kv_empty(Store) ->
- gb_trees:is_empty(Store).
-
-set_new() ->
- gb_sets:empty().
-set_insert(Item, Set) ->
- gb_sets:insert(Item, Set).
-set_delete(Item, Set) ->
- gb_sets:delete(Item, Set).
-set_is_member(Item, Set) ->
- gb_sets:is_member(Item, Set).
-
-call(Server, Msg) ->
- try
- gen_server:call(Server, Msg, infinity)
- catch
- exit:{noproc, _} ->
- {error, closed};
- exit:{normal, _} ->
- {error, closed};
- exit:{{shutdown, _},_} ->
- {error, closed}
- end.
-
-set_socket_opts(_, []) ->
- ok;
-set_socket_opts(Socket, SocketOpts) ->
- inet:setopts(Socket, SocketOpts).
-
-get_socket_opts(_, []) ->
- {ok, []};
-get_socket_opts(Socket, SocketOpts) ->
- inet:getopts(Socket, SocketOpts).
-
-do_set_emulated_opts([], Opts) ->
- Opts;
-do_set_emulated_opts([{mode, Value} | Rest], Opts) ->
- do_set_emulated_opts(Rest, Opts#socket_options{mode = Value});
-do_set_emulated_opts([{active, Value} | Rest], Opts) ->
- do_set_emulated_opts(Rest, Opts#socket_options{active = Value}).
-
-emulated_opts_list(_,[], Acc) ->
- Acc;
-emulated_opts_list( Opts, [mode | Rest], Acc) ->
- emulated_opts_list(Opts, Rest, [{mode, Opts#socket_options.mode} | Acc]);
-emulated_opts_list(Opts, [active | Rest], Acc) ->
- emulated_opts_list(Opts, Rest, [{active, Opts#socket_options.active} | Acc]).
-
diff --git a/lib/ssl/src/dtls_udp_sup.erl b/lib/ssl/src/dtls_udp_sup.erl
deleted file mode 100644
index 197882e92f..0000000000
--- a/lib/ssl/src/dtls_udp_sup.erl
+++ /dev/null
@@ -1,62 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2016-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
-%%----------------------------------------------------------------------
-%% Purpose: Supervisor for a procsses dispatching upd datagrams to
-%% correct DTLS handler
-%%----------------------------------------------------------------------
--module(dtls_udp_sup).
-
--behaviour(supervisor).
-
-%% API
--export([start_link/0]).
--export([start_child/1]).
-
-%% Supervisor callback
--export([init/1]).
-
-%%%=========================================================================
-%%% API
-%%%=========================================================================
-start_link() ->
- supervisor:start_link({local, ?MODULE}, ?MODULE, []).
-
-start_child(Args) ->
- supervisor:start_child(?MODULE, Args).
-
-%%%=========================================================================
-%%% Supervisor callback
-%%%=========================================================================
-init(_O) ->
- RestartStrategy = simple_one_for_one,
- MaxR = 0,
- MaxT = 3600,
-
- Name = undefined, % As simple_one_for_one is used.
- StartFunc = {dtls_udp_listener, start_link, []},
- Restart = temporary, % E.g. should not be restarted
- Shutdown = 4000,
- Modules = [dtls_udp_listener],
- Type = worker,
-
- ChildSpec = {Name, StartFunc, Restart, Shutdown, Type, Modules},
- {ok, {{RestartStrategy, MaxR, MaxT}, [ChildSpec]}}.
diff --git a/lib/ssl/src/dtls_v1.erl b/lib/ssl/src/dtls_v1.erl
index 0f6344b6f7..fc9dce02ce 100644
--- a/lib/ssl/src/dtls_v1.erl
+++ b/lib/ssl/src/dtls_v1.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -27,22 +27,22 @@
-define(COOKIE_BASE_TIMEOUT, 30000).
--spec suites(Minor:: 253|255) -> [ssl_cipher:cipher_suite()].
+-spec suites(Minor:: 253|255) -> [ssl_cipher_format:cipher_suite()].
suites(Minor) ->
lists:filter(fun(Cipher) ->
- is_acceptable_cipher(ssl_cipher:suite_definition(Cipher))
+ is_acceptable_cipher(ssl_cipher_format:suite_bin_to_map(Cipher))
end,
tls_v1:suites(corresponding_minor_tls_version(Minor))).
all_suites(Version) ->
lists:filter(fun(Cipher) ->
- is_acceptable_cipher(ssl_cipher:suite_definition(Cipher))
+ is_acceptable_cipher(ssl_cipher_format:suite_bin_to_map(Cipher))
end,
ssl_cipher:all_suites(corresponding_tls_version(Version))).
anonymous_suites(Version) ->
lists:filter(fun(Cipher) ->
- is_acceptable_cipher(ssl_cipher:suite_definition(Cipher))
+ is_acceptable_cipher(ssl_cipher_format:suite_bin_to_map(Cipher))
end,
ssl_cipher:anonymous_suites(corresponding_tls_version(Version))).
diff --git a/lib/ssl/src/inet6_tls_dist.erl b/lib/ssl/src/inet6_tls_dist.erl
index ffd7296f93..96ce4d493a 100644
--- a/lib/ssl/src/inet6_tls_dist.erl
+++ b/lib/ssl/src/inet6_tls_dist.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,7 +21,8 @@
%%
-module(inet6_tls_dist).
--export([childspecs/0, listen/1, accept/1, accept_connection/5,
+-export([childspecs/0]).
+-export([listen/1, accept/1, accept_connection/5,
setup/5, close/1, select/1]).
childspecs() ->
@@ -43,4 +44,4 @@ setup(Node, Type, MyNode, LongOrShortNames,SetupTime) ->
inet_tls_dist:gen_setup(inet6_tcp, Node, Type, MyNode, LongOrShortNames,SetupTime).
close(Socket) ->
- inet_tls_dist:close(Socket).
+ inet_tls_dist:gen_close(inet6_tcp, Socket).
diff --git a/lib/ssl/src/inet_tls_dist.erl b/lib/ssl/src/inet_tls_dist.erl
index 4c677b9c33..8d9b92361b 100644
--- a/lib/ssl/src/inet_tls_dist.erl
+++ b/lib/ssl/src/inet_tls_dist.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,16 +21,29 @@
%%
-module(inet_tls_dist).
--export([childspecs/0, listen/1, accept/1, accept_connection/5,
+-export([childspecs/0]).
+-export([listen/1, accept/1, accept_connection/5,
setup/5, close/1, select/1, is_node_name/1]).
%% Generalized dist API
-export([gen_listen/2, gen_accept/2, gen_accept_connection/6,
- gen_setup/6, gen_select/2]).
+ gen_setup/6, gen_close/2, gen_select/2]).
+
+-export([nodelay/0]).
+
+-export([verify_client/3, cert_nodes/1]).
+
+-export([dbg/0]). % Debug
-include_lib("kernel/include/net_address.hrl").
-include_lib("kernel/include/dist.hrl").
-include_lib("kernel/include/dist_util.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+-include("ssl_api.hrl").
+-include_lib("kernel/include/logger.hrl").
+
+%% -------------------------------------------------------------------------
childspecs() ->
{ok, [{ssl_dist_sup,{ssl_dist_sup, start_link, []},
@@ -40,107 +53,529 @@ select(Node) ->
gen_select(inet_tcp, Node).
gen_select(Driver, Node) ->
- case split_node(atom_to_list(Node), $@, []) of
- [_, Host] ->
- case inet:getaddr(Host, Driver:family()) of
+ case dist_util:split_node(Node) of
+ {node,_,Host} ->
+ case Driver:getaddr(Host) of
{ok, _} -> true;
_ -> false
end;
- _ ->
- false
+ _ ->
+ false
+ end.
+
+%% -------------------------------------------------------------------------
+
+is_node_name(Node) ->
+ dist_util:is_node_name(Node).
+
+%% -------------------------------------------------------------------------
+
+hs_data_common(#sslsocket{pid = [_, DistCtrl|_]} = SslSocket) ->
+ #hs_data{
+ f_send =
+ fun (_Ctrl, Packet) ->
+ f_send(SslSocket, Packet)
+ end,
+ f_recv =
+ fun (_, Length, Timeout) ->
+ f_recv(SslSocket, Length, Timeout)
+ end,
+ f_setopts_pre_nodeup =
+ fun (Ctrl) when Ctrl == DistCtrl ->
+ f_setopts_pre_nodeup(SslSocket)
+ end,
+ f_setopts_post_nodeup =
+ fun (Ctrl) when Ctrl == DistCtrl ->
+%%% sys:trace(Ctrl, true),
+ f_setopts_post_nodeup(SslSocket)
+ end,
+ f_getll =
+ fun (Ctrl) when Ctrl == DistCtrl ->
+ f_getll(DistCtrl)
+ end,
+ f_address =
+ fun (Ctrl, Node) when Ctrl == DistCtrl ->
+ f_address(SslSocket, Node)
+ end,
+ mf_tick =
+ fun (Ctrl) when Ctrl == DistCtrl ->
+ mf_tick(DistCtrl)
+ end,
+ mf_getstat =
+ fun (Ctrl) when Ctrl == DistCtrl ->
+ mf_getstat(SslSocket)
+ end,
+ mf_setopts =
+ fun (Ctrl, Opts) when Ctrl == DistCtrl ->
+ mf_setopts(SslSocket, Opts)
+ end,
+ mf_getopts =
+ fun (Ctrl, Opts) when Ctrl == DistCtrl ->
+ mf_getopts(SslSocket, Opts)
+ end,
+ f_handshake_complete =
+ fun (Ctrl, Node, DHandle) when Ctrl == DistCtrl ->
+ f_handshake_complete(DistCtrl, Node, DHandle)
+ end}.
+
+f_send(SslSocket, Packet) ->
+ ssl:send(SslSocket, Packet).
+
+f_recv(SslSocket, Length, Timeout) ->
+ case ssl:recv(SslSocket, Length, Timeout) of
+ {ok, Bin} when is_binary(Bin) ->
+ {ok, binary_to_list(Bin)};
+ Other ->
+ Other
+ end.
+
+f_setopts_pre_nodeup(_SslSocket) ->
+ ok.
+
+f_setopts_post_nodeup(SslSocket) ->
+ ssl:setopts(SslSocket, [nodelay()]).
+
+f_getll(DistCtrl) ->
+ {ok, DistCtrl}.
+
+f_address(SslSocket, Node) ->
+ case ssl:peername(SslSocket) of
+ {ok, Address} ->
+ case dist_util:split_node(Node) of
+ {node,_,Host} ->
+ #net_address{
+ address=Address, host=Host,
+ protocol=tls, family=inet};
+ _ ->
+ {error, no_node}
+ end
+ end.
+
+mf_tick(DistCtrl) ->
+ DistCtrl ! tick,
+ ok.
+
+mf_getstat(SslSocket) ->
+ case ssl:getstat(
+ SslSocket, [recv_cnt, send_cnt, send_pend]) of
+ {ok, Stat} ->
+ split_stat(Stat,0,0,0);
+ Error ->
+ Error
end.
-is_node_name(Node) when is_atom(Node) ->
- select(Node);
-is_node_name(_) ->
- false.
+mf_setopts(SslSocket, Opts) ->
+ case setopts_filter(Opts) of
+ [] ->
+ ssl:setopts(SslSocket, Opts);
+ Opts1 ->
+ {error, {badopts,Opts1}}
+ end.
+
+mf_getopts(SslSocket, Opts) ->
+ ssl:getopts(SslSocket, Opts).
+
+f_handshake_complete(DistCtrl, Node, DHandle) ->
+ tls_sender:dist_handshake_complete(DistCtrl, Node, DHandle).
+
+setopts_filter(Opts) ->
+ [Opt || {K,_} = Opt <- Opts,
+ K =:= active orelse K =:= deliver orelse K =:= packet].
+
+split_stat([{recv_cnt, R}|Stat], _, W, P) ->
+ split_stat(Stat, R, W, P);
+split_stat([{send_cnt, W}|Stat], R, _, P) ->
+ split_stat(Stat, R, W, P);
+split_stat([{send_pend, P}|Stat], R, W, _) ->
+ split_stat(Stat, R, W, P);
+split_stat([], R, W, P) ->
+ {ok, R, W, P}.
+
+%% -------------------------------------------------------------------------
listen(Name) ->
gen_listen(inet_tcp, Name).
gen_listen(Driver, Name) ->
- ssl_tls_dist_proxy:listen(Driver, Name).
+ case inet_tcp_dist:gen_listen(Driver, Name) of
+ {ok, {Socket, Address, Creation}} ->
+ inet:setopts(Socket, [{packet, 4}, {nodelay, true}]),
+ {ok, {Socket, Address#net_address{protocol=tls}, Creation}};
+ Other ->
+ Other
+ end.
+
+%% -------------------------------------------------------------------------
accept(Listen) ->
gen_accept(inet_tcp, Listen).
gen_accept(Driver, Listen) ->
- ssl_tls_dist_proxy:accept(Driver, Listen).
+ Kernel = self(),
+ monitor_pid(
+ spawn_opt(
+ fun () ->
+ accept_loop(Driver, Listen, Kernel)
+ end,
+ [link, {priority, max}])).
-accept_connection(AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
- gen_accept_connection(inet_tcp, AcceptPid, Socket, MyNode, Allowed, SetupTime).
+accept_loop(Driver, Listen, Kernel) ->
+ case Driver:accept(Listen) of
+ {ok, Socket} ->
+ case check_ip(Driver, Socket) of
+ true ->
+ accept_loop(Driver, Listen, Kernel, Socket);
+ {false,IP} ->
+ ?LOG_ERROR(
+ "** Connection attempt from "
+ "disallowed IP ~w ** ~n", [IP]),
+ ?shutdown2(no_node, trace({disallowed, IP}))
+ end;
+ Error ->
+ exit(trace(Error))
+ end.
-gen_accept_connection(Driver, AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
+accept_loop(Driver, Listen, Kernel, Socket) ->
+ Opts = setup_verify_client(Socket, get_ssl_options(server)),
+ wait_for_code_server(),
+ case
+ ssl:handshake(
+ Socket,
+ trace([{active, false},{packet, 4}|Opts]),
+ net_kernel:connecttime())
+ of
+ {ok, #sslsocket{pid = [_, DistCtrl| _]} = SslSocket} ->
+ trace(
+ Kernel !
+ {accept, self(), DistCtrl,
+ Driver:family(), tls}),
+ receive
+ {Kernel, controller, Pid} ->
+ ok = ssl:controlling_process(SslSocket, Pid),
+ trace(
+ Pid ! {self(), controller});
+ {Kernel, unsupported_protocol} ->
+ exit(trace(unsupported_protocol))
+ end,
+ accept_loop(Driver, Listen, Kernel);
+ {error, {options, _}} = Error ->
+ %% Bad options: that's probably our fault.
+ %% Let's log that.
+ ?LOG_ERROR(
+ "Cannot accept TLS distribution connection: ~s~n",
+ [ssl:format_error(Error)]),
+ gen_tcp:close(Socket),
+ exit(trace(Error));
+ Other ->
+ gen_tcp:close(Socket),
+ exit(trace(Other))
+ end.
+
+
+%% {verify_fun,{fun ?MODULE:verify_client/3,_}} is used
+%% as a configuration marker that verify_client/3 shall be used.
+%%
+%% Replace the State in the first occurence of
+%% {verify_fun,{fun ?MODULE:verify_client/3,State}}
+%% and remove the rest.
+%% The inserted state is not accesible from a configuration file
+%% since it is dynamic and connection dependent.
+%%
+setup_verify_client(Socket, Opts) ->
+ setup_verify_client(Socket, Opts, true, []).
+%%
+setup_verify_client(_Socket, [], _, OptsR) ->
+ lists:reverse(OptsR);
+setup_verify_client(Socket, [Opt|Opts], First, OptsR) ->
+ case Opt of
+ {verify_fun,{Fun,_}} ->
+ case Fun =:= fun ?MODULE:verify_client/3 of
+ true ->
+ if
+ First ->
+ case inet:peername(Socket) of
+ {ok,{PeerIP,_Port}} ->
+ {ok,Allowed} = net_kernel:allowed(),
+ AllowedHosts = allowed_hosts(Allowed),
+ setup_verify_client(
+ Socket, Opts, false,
+ [{verify_fun,
+ {Fun, {AllowedHosts,PeerIP}}}
+ |OptsR]);
+ {error,Reason} ->
+ exit(trace({no_peername,Reason}))
+ end;
+ true ->
+ setup_verify_client(
+ Socket, Opts, First, OptsR)
+ end;
+ false ->
+ setup_verify_client(
+ Socket, Opts, First, [Opt|OptsR])
+ end;
+ _ ->
+ setup_verify_client(Socket, Opts, First, [Opt|OptsR])
+ end.
+
+allowed_hosts(Allowed) ->
+ lists:usort(allowed_node_hosts(Allowed)).
+%%
+allowed_node_hosts([]) -> [];
+allowed_node_hosts([Node|Allowed]) ->
+ case dist_util:split_node(Node) of
+ {node,_,Host} ->
+ [Host|allowed_node_hosts(Allowed)];
+ {host,Host} ->
+ [Host|allowed_node_hosts(Allowed)];
+ _ ->
+ allowed_node_hosts(Allowed)
+ end.
+
+%% Same as verify_peer but check cert host names for
+%% peer IP address
+verify_client(_, {bad_cert,_} = Reason, _) ->
+ {fail,Reason};
+verify_client(_, {extension,_}, S) ->
+ {unknown,S};
+verify_client(_, valid, S) ->
+ {valid,S};
+verify_client(_, valid_peer, {[],_} = S) ->
+ %% Allow all hosts
+ {valid,S};
+verify_client(PeerCert, valid_peer, {AllowedHosts,PeerIP} = S) ->
+ case
+ public_key:pkix_verify_hostname(
+ PeerCert,
+ [{ip,PeerIP}|[{dns_id,Host} || Host <- AllowedHosts]])
+ of
+ true ->
+ {valid,S};
+ false ->
+ {fail,cert_no_hostname_nor_ip_match}
+ end.
+
+
+wait_for_code_server() ->
+ %% This is an ugly hack. Upgrading a socket to TLS requires the
+ %% crypto module to be loaded. Loading the crypto module triggers
+ %% its on_load function, which calls code:priv_dir/1 to find the
+ %% directory where its NIF library is. However, distribution is
+ %% started earlier than the code server, so the code server is not
+ %% necessarily started yet, and code:priv_dir/1 might fail because
+ %% of that, if we receive an incoming connection on the
+ %% distribution port early enough.
+ %%
+ %% If the on_load function of a module fails, the module is
+ %% unloaded, and the function call that triggered loading it fails
+ %% with 'undef', which is rather confusing.
+ %%
+ %% Thus, the accept process will terminate, and be
+ %% restarted by ssl_dist_sup. However, it won't have any memory
+ %% of being asked by net_kernel to listen for incoming
+ %% connections. Hence, the node will believe that it's open for
+ %% distribution, but it actually isn't.
+ %%
+ %% So let's avoid that by waiting for the code server to start.
+ case whereis(code_server) of
+ undefined ->
+ timer:sleep(10),
+ wait_for_code_server();
+ Pid when is_pid(Pid) ->
+ ok
+ end.
+
+%% -------------------------------------------------------------------------
+
+accept_connection(AcceptPid, DistCtrl, MyNode, Allowed, SetupTime) ->
+ gen_accept_connection(
+ inet_tcp, AcceptPid, DistCtrl, MyNode, Allowed, SetupTime).
+
+gen_accept_connection(
+ Driver, AcceptPid, DistCtrl, MyNode, Allowed, SetupTime) ->
Kernel = self(),
- spawn_link(fun() -> do_accept(Driver, Kernel, AcceptPid, Socket,
- MyNode, Allowed, SetupTime) end).
+ monitor_pid(
+ spawn_opt(
+ fun() ->
+ do_accept(
+ Driver, AcceptPid, DistCtrl,
+ MyNode, Allowed, SetupTime, Kernel)
+ end,
+ [link, {priority, max}])).
-setup(Node, Type, MyNode, LongOrShortNames,SetupTime) ->
- gen_setup(inet_tcp, Node, Type, MyNode, LongOrShortNames,SetupTime).
+do_accept(
+ _Driver, AcceptPid, DistCtrl, MyNode, Allowed, SetupTime, Kernel) ->
+ {ok, SslSocket} = tls_sender:dist_tls_socket(DistCtrl),
+ receive
+ {AcceptPid, controller} ->
+ Timer = dist_util:start_timer(SetupTime),
+ NewAllowed = allowed_nodes(SslSocket, Allowed),
+ HSData0 = hs_data_common(SslSocket),
+ HSData =
+ HSData0#hs_data{
+ kernel_pid = Kernel,
+ this_node = MyNode,
+ socket = DistCtrl,
+ timer = Timer,
+ this_flags = 0,
+ allowed = NewAllowed},
+ link(DistCtrl),
+ dist_util:handshake_other_started(trace(HSData))
+ end.
-gen_setup(Driver, Node, Type, MyNode, LongOrShortNames,SetupTime) ->
+allowed_nodes(_SslSocket, []) ->
+ %% Allow all
+ [];
+allowed_nodes(SslSocket, Allowed) ->
+ case ssl:peercert(SslSocket) of
+ {ok,PeerCertDER} ->
+ case ssl:peername(SslSocket) of
+ {ok,{PeerIP,_Port}} ->
+ PeerCert =
+ public_key:pkix_decode_cert(PeerCertDER, otp),
+ case
+ allowed_nodes(
+ PeerCert, allowed_hosts(Allowed), PeerIP)
+ of
+ [] ->
+ ?LOG_ERROR(
+ "** Connection attempt from "
+ "disallowed node(s) ~p ** ~n", [PeerIP]),
+ ?shutdown2(
+ PeerIP, trace({is_allowed, not_allowed}));
+ AllowedNodes ->
+ AllowedNodes
+ end;
+ Error1 ->
+ ?shutdown2(no_peer_ip, trace(Error1))
+ end;
+ {error,no_peercert} ->
+ Allowed;
+ Error2 ->
+ ?shutdown2(no_peer_cert, trace(Error2))
+ end.
+
+allowed_nodes(PeerCert, [], PeerIP) ->
+ case public_key:pkix_verify_hostname(PeerCert, [{ip,PeerIP}]) of
+ true ->
+ Host = inet:ntoa(PeerIP),
+ true = is_list(Host),
+ [Host];
+ false ->
+ []
+ end;
+allowed_nodes(PeerCert, [Node|Allowed], PeerIP) ->
+ case dist_util:split_node(Node) of
+ {node,_,Host} ->
+ allowed_nodes(PeerCert, Allowed, PeerIP, Node, Host);
+ {host,Host} ->
+ allowed_nodes(PeerCert, Allowed, PeerIP, Node, Host);
+ _ ->
+ allowed_nodes(PeerCert, Allowed, PeerIP)
+ end.
+
+allowed_nodes(PeerCert, Allowed, PeerIP, Node, Host) ->
+ case public_key:pkix_verify_hostname(PeerCert, [{dns_id,Host}]) of
+ true ->
+ [Node|allowed_nodes(PeerCert, Allowed, PeerIP)];
+ false ->
+ allowed_nodes(PeerCert, Allowed, PeerIP)
+ end.
+
+setup(Node, Type, MyNode, LongOrShortNames, SetupTime) ->
+ gen_setup(inet_tcp, Node, Type, MyNode, LongOrShortNames, SetupTime).
+
+gen_setup(Driver, Node, Type, MyNode, LongOrShortNames, SetupTime) ->
Kernel = self(),
- spawn_opt(fun() -> do_setup(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) end, [link, {priority, max}]).
-
+ monitor_pid(
+ spawn_opt(setup_fun(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime),
+ [link, {priority, max}])).
+
+-spec setup_fun(_,_,_,_,_,_,_) -> fun(() -> no_return()).
+setup_fun(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) ->
+ fun() ->
+ do_setup(
+ Driver, Kernel, Node, Type,
+ MyNode, LongOrShortNames, SetupTime)
+ end.
+
+
+-spec do_setup(_,_,_,_,_,_,_) -> no_return().
do_setup(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) ->
- [Name, Address] = splitnode(Driver, Node, LongOrShortNames),
- case inet:getaddr(Address, Driver:family()) of
+ {Name, Address} = split_node(Driver, Node, LongOrShortNames),
+ ErlEpmd = net_kernel:epmd_module(),
+ {ARMod, ARFun} = get_address_resolver(ErlEpmd, Driver),
+ Timer = trace(dist_util:start_timer(SetupTime)),
+ case ARMod:ARFun(Name,Address,Driver:family()) of
+ {ok, Ip, TcpPort, Version} ->
+ do_setup_connect(Driver, Kernel, Node, Address, Ip, TcpPort, Version, Type, MyNode, Timer);
{ok, Ip} ->
- Timer = dist_util:start_timer(SetupTime),
- ErlEpmd = net_kernel:epmd_module(),
case ErlEpmd:port_please(Name, Ip) of
{port, TcpPort, Version} ->
- ?trace("port_please(~p) -> version ~p~n",
- [Node,Version]),
- dist_util:reset_timer(Timer),
- case
- ssl_tls_dist_proxy:connect(
- Driver, Address, TcpPort,
- [{server_name_indication, atom_to_list(Node)}])
- of
- {ok, Socket} ->
- HSData = connect_hs_data(Kernel, Node, MyNode, Socket,
- Timer, Version, Ip, TcpPort, Address,
- Type),
- dist_util:handshake_we_started(HSData);
- Other ->
- %% Other Node may have closed since
- %% port_please !
- ?trace("other node (~p) "
- "closed since port_please.~n",
- [Node]),
- ?shutdown2(Node, {shutdown, {connect_failed, Other}})
- end;
+ do_setup_connect(Driver, Kernel, Node, Address, Ip, TcpPort, Version, Type, MyNode, Timer);
Other ->
- ?trace("port_please (~p) "
- "failed.~n", [Node]),
- ?shutdown2(Node, {shutdown, {port_please_failed, Other}})
+ ?shutdown2(
+ Node,
+ trace(
+ {port_please_failed, ErlEpmd, Name, Ip, Other}))
end;
Other ->
- ?trace("inet_getaddr(~p) "
- "failed (~p).~n", [Node,Other]),
- ?shutdown2(Node, {shutdown, {inet_getaddr_failed, Other}})
+ ?shutdown2(
+ Node,
+ trace({getaddr_failed, Driver, Address, Other}))
+ end.
+
+-spec do_setup_connect(_,_,_,_,_,_,_,_,_,_) -> no_return().
+
+do_setup_connect(Driver, Kernel, Node, Address, Ip, TcpPort, Version, Type, MyNode, Timer) ->
+ Opts = trace(connect_options(get_ssl_options(client))),
+ dist_util:reset_timer(Timer),
+ case ssl:connect(
+ Address, TcpPort,
+ [binary, {active, false}, {packet, 4},
+ Driver:family(), {nodelay, true}] ++ Opts,
+ net_kernel:connecttime()) of
+ {ok, #sslsocket{pid = [_, DistCtrl| _]} = SslSocket} ->
+ _ = monitor_pid(DistCtrl),
+ ok = ssl:controlling_process(SslSocket, self()),
+ HSData0 = hs_data_common(SslSocket),
+ HSData =
+ HSData0#hs_data{
+ kernel_pid = Kernel,
+ other_node = Node,
+ this_node = MyNode,
+ socket = DistCtrl,
+ timer = Timer,
+ this_flags = 0,
+ other_version = Version,
+ request_type = Type},
+ link(DistCtrl),
+ dist_util:handshake_we_started(trace(HSData));
+ Other ->
+ %% Other Node may have closed since
+ %% port_please !
+ ?shutdown2(
+ Node,
+ trace(
+ {ssl_connect_failed, Ip, TcpPort, Other}))
end.
close(Socket) ->
- gen_tcp:close(Socket),
- ok.
+ gen_close(inet, Socket).
-do_accept(Driver, Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
- process_flag(priority, max),
- receive
- {AcceptPid, controller} ->
- Timer = dist_util:start_timer(SetupTime),
- case check_ip(Driver, Socket) of
- true ->
- HSData = accept_hs_data(Kernel, MyNode, Socket, Timer, Allowed),
- dist_util:handshake_other_started(HSData);
- {false,IP} ->
- error_logger:error_msg("** Connection attempt from "
- "disallowed IP ~w ** ~n", [IP]),
- ?shutdown(no_node)
- end
+gen_close(Driver, Socket) ->
+ trace(Driver:close(Socket)).
+
+
+%% ------------------------------------------------------------
+%% Determine if EPMD module supports address resolving. Default
+%% is to use inet_tcp:getaddr/2.
+%% ------------------------------------------------------------
+get_address_resolver(EpmdModule, _Driver) ->
+ case erlang:function_exported(EpmdModule, address_please, 3) of
+ true -> {EpmdModule, address_please};
+ _ -> {erl_epmd, address_please}
end.
+
%% ------------------------------------------------------------
%% Do only accept new connection attempts from nodes at our
%% own LAN, if the check_ip environment parameter is true.
@@ -151,16 +586,26 @@ check_ip(Driver, Socket) ->
case get_ifs(Socket) of
{ok, IFs, IP} ->
check_ip(Driver, IFs, IP);
- _ ->
- ?shutdown(no_node)
+ Other ->
+ ?shutdown2(
+ no_node, trace({check_ip_failed, Socket, Other}))
end;
_ ->
true
end.
+check_ip(Driver, [{OwnIP, _, Netmask}|IFs], PeerIP) ->
+ case {Driver:mask(Netmask, PeerIP), Driver:mask(Netmask, OwnIP)} of
+ {M, M} -> true;
+ _ -> check_ip(IFs, PeerIP)
+ end;
+check_ip(_Driver, [], PeerIP) ->
+ {false, PeerIP}.
+
get_ifs(Socket) ->
case inet:peername(Socket) of
{ok, {IP, _}} ->
+ %% XXX this is seriously broken for IPv6
case inet:getif(Socket) of
{ok, IFs} -> {ok, IFs, IP};
Error -> Error
@@ -169,125 +614,262 @@ get_ifs(Socket) ->
Error
end.
-check_ip(Driver, [{OwnIP, _, Netmask}|IFs], PeerIP) ->
- case {Driver:mask(Netmask, PeerIP), Driver:mask(Netmask, OwnIP)} of
- {M, M} -> true;
- _ -> check_ip(IFs, PeerIP)
+
+%% Look in Extensions, in all subjectAltName:s
+%% to find node names in this certificate.
+%% Host names are picked up as a subjectAltName containing
+%% a dNSName, and the first subjectAltName containing
+%% a commonName is the node name.
+%%
+cert_nodes(
+ #'OTPCertificate'{
+ tbsCertificate = #'OTPTBSCertificate'{extensions = Extensions}}) ->
+ parse_extensions(Extensions).
+
+
+parse_extensions(Extensions) when is_list(Extensions) ->
+ parse_extensions(Extensions, [], []);
+parse_extensions(asn1_NOVALUE) ->
+ undefined. % Allow all nodes
+%%
+parse_extensions([], [], []) ->
+ undefined; % Allow all nodes
+parse_extensions([], Hosts, []) ->
+ lists:reverse(Hosts);
+parse_extensions([], [], Names) ->
+ [Name ++ "@" || Name <- lists:reverse(Names)];
+parse_extensions([], Hosts, Names) ->
+ [Name ++ "@" ++ Host ||
+ Host <- lists:reverse(Hosts),
+ Name <- lists:reverse(Names)];
+parse_extensions(
+ [#'Extension'{
+ extnID = ?'id-ce-subjectAltName',
+ extnValue = AltNames}
+ |Extensions],
+ Hosts, Names) ->
+ case parse_subject_altname(AltNames) of
+ none ->
+ parse_extensions(Extensions, Hosts, Names);
+ {host,Host} ->
+ parse_extensions(Extensions, [Host|Hosts], Names);
+ {name,Name} ->
+ parse_extensions(Extensions, Hosts, [Name|Names])
end;
-check_ip(_Driver, [], PeerIP) ->
- {false, PeerIP}.
+parse_extensions([_|Extensions], Hosts, Names) ->
+ parse_extensions(Extensions, Hosts, Names).
+
+parse_subject_altname([]) ->
+ none;
+parse_subject_altname([{dNSName,Host}|_AltNames]) ->
+ {host,Host};
+parse_subject_altname(
+ [{directoryName,{rdnSequence,[Rdn|_]}}|AltNames]) ->
+ %%
+ %% XXX Why is rdnSequence a sequence?
+ %% Should we parse all members?
+ %%
+ case parse_rdn(Rdn) of
+ none ->
+ parse_subject_altname(AltNames);
+ Name ->
+ {name,Name}
+ end;
+parse_subject_altname([_|AltNames]) ->
+ parse_subject_altname(AltNames).
+
+
+parse_rdn([]) ->
+ none;
+parse_rdn(
+ [#'AttributeTypeAndValue'{
+ type = ?'id-at-commonName',
+ value = {utf8String,CommonName}}|_]) ->
+ unicode:characters_to_list(CommonName);
+parse_rdn([_|Rdn]) ->
+ parse_rdn(Rdn).
%% If Node is illegal terminate the connection setup!!
-splitnode(Driver, Node, LongOrShortNames) ->
- case split_node(atom_to_list(Node), $@, []) of
- [Name|Tail] when Tail =/= [] ->
- Host = lists:append(Tail),
- check_node(Driver, Name, Node, Host, LongOrShortNames);
- [_] ->
- error_logger:error_msg("** Nodename ~p illegal, no '@' character **~n",
- [Node]),
- ?shutdown(Node);
+split_node(Driver, Node, LongOrShortNames) ->
+ case dist_util:split_node(Node) of
+ {node, Name, Host} ->
+ check_node(Driver, Node, Name, Host, LongOrShortNames);
+ {host, _} ->
+ ?LOG_ERROR(
+ "** Nodename ~p illegal, no '@' character **~n",
+ [Node]),
+ ?shutdown2(Node, trace({illegal_node_n@me, Node}));
_ ->
- error_logger:error_msg("** Nodename ~p illegal **~n", [Node]),
- ?shutdown(Node)
+ ?LOG_ERROR(
+ "** Nodename ~p illegal **~n", [Node]),
+ ?shutdown2(Node, trace({illegal_node_name, Node}))
end.
-check_node(Driver, Name, Node, Host, LongOrShortNames) ->
- case split_node(Host, $., []) of
- [_] when LongOrShortNames == longnames ->
+check_node(Driver, Node, Name, Host, LongOrShortNames) ->
+ case string:split(Host, ".", all) of
+ [_] when LongOrShortNames =:= longnames ->
case Driver:parse_address(Host) of
{ok, _} ->
- [Name, Host];
+ {Name, Host};
_ ->
- error_logger:error_msg("** System running to use "
- "fully qualified "
- "hostnames **~n"
- "** Hostname ~s is illegal **~n",
- [Host]),
- ?shutdown(Node)
+ ?LOG_ERROR(
+ "** System running to use "
+ "fully qualified hostnames **~n"
+ "** Hostname ~s is illegal **~n",
+ [Host]),
+ ?shutdown2(Node, trace({not_longnames, Host}))
end;
- [_, _ | _] when LongOrShortNames == shortnames ->
- error_logger:error_msg("** System NOT running to use fully qualified "
- "hostnames **~n"
- "** Hostname ~s is illegal **~n",
- [Host]),
- ?shutdown(Node);
+ [_,_|_] when LongOrShortNames =:= shortnames ->
+ ?LOG_ERROR(
+ "** System NOT running to use "
+ "fully qualified hostnames **~n"
+ "** Hostname ~s is illegal **~n",
+ [Host]),
+ ?shutdown2(Node, trace({not_shortnames, Host}));
_ ->
- [Name, Host]
+ {Name, Host}
end.
-split_node([Chr|T], Chr, Ack) ->
- [lists:reverse(Ack)|split_node(T, Chr, [])];
-split_node([H|T], Chr, Ack) ->
- split_node(T, Chr, [H|Ack]);
-split_node([], _, Ack) ->
- [lists:reverse(Ack)].
-
-connect_hs_data(Kernel, Node, MyNode, Socket, Timer, Version, Ip, TcpPort, Address, Type) ->
- common_hs_data(Kernel, MyNode, Socket, Timer,
- #hs_data{other_node = Node,
- other_version = Version,
- f_address =
- fun(_,_) ->
- #net_address{address = {Ip,TcpPort},
- host = Address,
- protocol = proxy,
- family = inet}
- end,
- request_type = Type
- }).
-
-accept_hs_data(Kernel, MyNode, Socket, Timer, Allowed) ->
- common_hs_data(Kernel, MyNode, Socket, Timer, #hs_data{
- allowed = Allowed,
- f_address = fun get_remote_id/2
- }).
-
-common_hs_data(Kernel, MyNode, Socket, Timer, HsData) ->
- HsData#hs_data{
- kernel_pid = Kernel,
- this_node = MyNode,
- socket = Socket,
- timer = Timer,
- this_flags = 0,
- f_send =
- fun(S,D) ->
- gen_tcp:send(S,D)
- end,
- f_recv =
- fun(S,N,T) ->
- gen_tcp:recv(S,N,T)
- end,
- f_setopts_pre_nodeup =
- fun(S) ->
- inet:setopts(S, [{active, false}, {packet, 4}])
- end,
- f_setopts_post_nodeup =
- fun(S) ->
- inet:setopts(S, [{deliver, port},{active, true}])
- end,
- f_getll =
- fun(S) ->
- inet:getll(S)
- end,
- mf_tick =
- fun(S) ->
- gen_tcp:send(S, <<>>)
- end,
- mf_getstat =
- fun(S) ->
- {ok, Stats} = inet:getstat(S, [recv_cnt, send_cnt, send_pend]),
- R = proplists:get_value(recv_cnt, Stats, 0),
- W = proplists:get_value(send_cnt, Stats, 0),
- P = proplists:get_value(send_pend, Stats, 0),
- {ok, R,W,P}
- end}.
-
-get_remote_id(Socket, _Node) ->
- case ssl_tls_dist_proxy:get_tcp_address(Socket) of
- {ok, Address} ->
- Address;
- {error, _Reason} ->
- ?shutdown(no_node)
+%% -------------------------------------------------------------------------
+
+connect_options(Opts) ->
+ case application:get_env(kernel, inet_dist_connect_options) of
+ {ok,ConnectOpts} ->
+ lists:ukeysort(1, ConnectOpts ++ Opts);
+ _ ->
+ Opts
+ end.
+
+%% we may not always want the nodelay behaviour
+%% for performance reasons
+nodelay() ->
+ case application:get_env(kernel, dist_nodelay) of
+ undefined ->
+ {nodelay, true};
+ {ok, true} ->
+ {nodelay, true};
+ {ok, false} ->
+ {nodelay, false};
+ _ ->
+ {nodelay, true}
+ end.
+
+
+get_ssl_options(Type) ->
+ try ets:lookup(ssl_dist_opts, Type) of
+ [{Type, Opts}] ->
+ [{erl_dist, true} | Opts];
+ _ ->
+ get_ssl_dist_arguments(Type)
+ catch
+ error:badarg ->
+ get_ssl_dist_arguments(Type)
end.
+
+get_ssl_dist_arguments(Type) ->
+ case init:get_argument(ssl_dist_opt) of
+ {ok, Args} ->
+ [{erl_dist, true} | ssl_options(Type, lists:append(Args))];
+ _ ->
+ [{erl_dist, true}]
+ end.
+
+
+ssl_options(_Type, []) ->
+ [];
+ssl_options(client, ["client_" ++ Opt, Value | T] = Opts) ->
+ ssl_options(client, T, Opts, Opt, Value);
+ssl_options(server, ["server_" ++ Opt, Value | T] = Opts) ->
+ ssl_options(server, T, Opts, Opt, Value);
+ssl_options(Type, [_Opt, _Value | T]) ->
+ ssl_options(Type, T).
+%%
+ssl_options(Type, T, Opts, Opt, Value) ->
+ case ssl_option(Type, Opt) of
+ error ->
+ error(malformed_ssl_dist_opt, [Type, Opts]);
+ Fun ->
+ [{list_to_atom(Opt), Fun(Value)}|ssl_options(Type, T)]
+ end.
+
+ssl_option(server, Opt) ->
+ case Opt of
+ "dhfile" -> fun listify/1;
+ "fail_if_no_peer_cert" -> fun atomize/1;
+ _ -> ssl_option(client, Opt)
+ end;
+ssl_option(client, Opt) ->
+ case Opt of
+ "certfile" -> fun listify/1;
+ "cacertfile" -> fun listify/1;
+ "keyfile" -> fun listify/1;
+ "password" -> fun listify/1;
+ "verify" -> fun atomize/1;
+ "verify_fun" -> fun verify_fun/1;
+ "crl_check" -> fun atomize/1;
+ "crl_cache" -> fun termify/1;
+ "reuse_sessions" -> fun atomize/1;
+ "secure_renegotiate" -> fun atomize/1;
+ "depth" -> fun erlang:list_to_integer/1;
+ "hibernate_after" -> fun erlang:list_to_integer/1;
+ "ciphers" -> fun listify/1;
+ _ -> error
+ end.
+
+listify(List) when is_list(List) ->
+ List.
+
+atomize(List) when is_list(List) ->
+ list_to_atom(List);
+atomize(Atom) when is_atom(Atom) ->
+ Atom.
+
+termify(String) when is_list(String) ->
+ {ok, Tokens, _} = erl_scan:string(String ++ "."),
+ {ok, Term} = erl_parse:parse_term(Tokens),
+ Term.
+
+verify_fun(Value) ->
+ case termify(Value) of
+ {Mod, Func, State} when is_atom(Mod), is_atom(Func) ->
+ Fun = fun Mod:Func/3,
+ {Fun, State};
+ _ ->
+ error(malformed_ssl_dist_opt, [Value])
+ end.
+
+%% -------------------------------------------------------------------------
+
+%% Trace point
+trace(Term) -> Term.
+
+%% Keep an eye on distribution Pid:s we know of
+monitor_pid(Pid) ->
+ %%spawn(
+ %% fun () ->
+ %% MRef = erlang:monitor(process, Pid),
+ %% receive
+ %% {'DOWN', MRef, _, _, normal} ->
+ %% ?LOG_ERROR(
+ %% [{slogan, dist_proc_died},
+ %% {reason, normal},
+ %% {pid, Pid}]);
+ %% {'DOWN', MRef, _, _, Reason} ->
+ %% ?LOG_NOTICE(
+ %% [{slogan, dist_proc_died},
+ %% {reason, Reason},
+ %% {pid, Pid}])
+ %% end
+ %% end),
+ Pid.
+
+dbg() ->
+ dbg:stop(),
+ dbg:tracer(),
+ dbg:p(all, c),
+ dbg:tpl(?MODULE, cx),
+ dbg:tpl(erlang, dist_ctrl_get_data_notification, cx),
+ dbg:tpl(erlang, dist_ctrl_get_data, cx),
+ dbg:tpl(erlang, dist_ctrl_put_data, cx),
+ ok.
diff --git a/lib/ssl/src/ssl.app.src b/lib/ssl/src/ssl.app.src
index 762aa2f8d8..e7a4d73ec4 100644
--- a/lib/ssl/src/ssl.app.src
+++ b/lib/ssl/src/ssl.app.src
@@ -4,13 +4,17 @@
{modules, [
%% TLS/SSL
tls_connection,
+ tls_connection_1_3,
tls_handshake,
+ tls_handshake_1_3,
tls_record,
+ tls_record_1_3,
tls_socket,
tls_v1,
ssl_v3,
- ssl_v2,
tls_connection_sup,
+ tls_sender,
+ ssl_dh_groups,
%% DTLS
dtls_connection,
dtls_handshake,
@@ -18,12 +22,10 @@
dtls_socket,
dtls_v1,
dtls_connection_sup,
- dtls_udp_listener,
- dtls_udp_sup,
+ dtls_packet_demux,
+ dtls_listener_sup,
%% API
ssl, %% Main API
- tls, %% TLS specific
- dtls, %% DTLS specific
ssl_session_cache_api,
%% Both TLS/SSL and DTLS
ssl_config,
@@ -31,13 +33,13 @@
ssl_handshake,
ssl_record,
ssl_cipher,
+ ssl_cipher_format,
ssl_srp_primes,
ssl_alert,
ssl_listen_tracker_sup, %% may be used by DTLS over SCTP
%% Erlang Distribution over SSL/TLS
inet_tls_dist,
inet6_tls_dist,
- ssl_tls_dist_proxy,
ssl_dist_sup,
ssl_dist_connection_sup,
ssl_dist_admin_sup,
@@ -53,6 +55,8 @@
ssl_crl_cache,
ssl_crl_cache_api,
ssl_crl_hash_dir,
+ %% Logging
+ ssl_logger,
%% App structure
ssl_app,
ssl_sup,
@@ -63,7 +67,5 @@
{applications, [crypto, public_key, kernel, stdlib]},
{env, []},
{mod, {ssl_app, []}},
- {runtime_dependencies, ["stdlib-3.2","public_key-1.5","kernel-3.0",
- "erts-7.0","crypto-4.2", "inets-5.10.7"]}]}.
-
-
+ {runtime_dependencies, ["stdlib-3.5","public_key-1.5","kernel-6.0",
+ "erts-10.0","crypto-4.2", "inets-5.10.7"]}]}.
diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src
index bfdd0c205b..ae4d60b6ed 100644
--- a/lib/ssl/src/ssl.appup.src
+++ b/lib/ssl/src/ssl.appup.src
@@ -1,6 +1,7 @@
%% -*- erlang -*-
{"%VSN%",
- [
+[
+ {<<"9\\..*">>, [{restart_application, ssl}]},
{<<"8\\..*">>, [{restart_application, ssl}]},
{<<"7\\..*">>, [{restart_application, ssl}]},
{<<"6\\..*">>, [{restart_application, ssl}]},
@@ -9,6 +10,7 @@
{<<"3\\..*">>, [{restart_application, ssl}]}
],
[
+ {<<"9\\..*">>, [{restart_application, ssl}]},
{<<"8\\..*">>, [{restart_application, ssl}]},
{<<"7\\..*">>, [{restart_application, ssl}]},
{<<"6\\..*">>, [{restart_application, ssl}]},
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index fb4448e180..6af65e09f2 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,30 +23,10 @@
%%% Purpose : Main API module for SSL see also tls.erl and dtls.erl
-module(ssl).
--include("ssl_internal.hrl").
--include_lib("public_key/include/public_key.hrl").
-
-%% Application handling
--export([start/0, start/1, stop/0, clear_pem_cache/0]).
-
-%% Socket handling
--export([connect/3, connect/2, connect/4,
- listen/2, transport_accept/1, transport_accept/2,
- ssl_accept/1, ssl_accept/2, ssl_accept/3,
- controlling_process/2, peername/1, peercert/1, sockname/1,
- close/1, close/2, shutdown/2, recv/2, recv/3, send/2,
- getopts/2, setopts/2, getstat/1, getstat/2
- ]).
-%% SSL/TLS protocol handling
--export([cipher_suites/0, cipher_suites/1, cipher_suites/2, filter_cipher_suites/2,
- prepend_cipher_suites/2, append_cipher_suites/2,
- eccs/0, eccs/1, versions/0,
- format_error/1, renegotiate/1, prf/5, negotiated_protocol/1,
- connection_information/1, connection_information/2]).
-%% Misc
--export([handle_options/2, tls_version/1]).
+-include_lib("public_key/include/public_key.hrl").
+-include("ssl_internal.hrl").
-include("ssl_api.hrl").
-include("ssl_internal.hrl").
-include("ssl_record.hrl").
@@ -54,18 +34,418 @@
-include("ssl_handshake.hrl").
-include("ssl_srp.hrl").
--include_lib("public_key/include/public_key.hrl").
+%% Application handling
+-export([start/0,
+ start/1,
+ stop/0,
+ clear_pem_cache/0]).
+
+%% Socket handling
+-export([connect/3,
+ connect/2,
+ connect/4,
+ listen/2,
+ transport_accept/1,
+ transport_accept/2,
+ handshake/1,
+ handshake/2,
+ handshake/3,
+ handshake_continue/2,
+ handshake_continue/3,
+ handshake_cancel/1,
+ ssl_accept/1,
+ ssl_accept/2,
+ ssl_accept/3,
+ controlling_process/2,
+ peername/1,
+ peercert/1,
+ sockname/1,
+ close/1,
+ close/2,
+ shutdown/2,
+ recv/2,
+ recv/3,
+ send/2,
+ getopts/2,
+ setopts/2,
+ getstat/1,
+ getstat/2
+ ]).
+
+%% SSL/TLS protocol handling
+-export([cipher_suites/0,
+ cipher_suites/1,
+ cipher_suites/2,
+ cipher_suites/3,
+ filter_cipher_suites/2,
+ prepend_cipher_suites/2,
+ append_cipher_suites/2,
+ eccs/0,
+ eccs/1,
+ versions/0,
+ groups/0,
+ groups/1,
+ format_error/1,
+ renegotiate/1,
+ prf/5,
+ negotiated_protocol/1,
+ connection_information/1,
+ connection_information/2]).
+%% Misc
+-export([handle_options/2,
+ tls_version/1,
+ new_ssl_options/3,
+ suite_to_str/1,
+ suite_to_openssl_str/1,
+ str_to_suite/1]).
+
+-deprecated({ssl_accept, 1, eventually}).
+-deprecated({ssl_accept, 2, eventually}).
+-deprecated({ssl_accept, 3, eventually}).
+
+-export_type([socket/0,
+ sslsocket/0,
+ socket_option/0,
+ active_msgs/0,
+ host/0,
+ tls_option/0,
+ tls_client_option/0,
+ tls_server_option/0,
+ erl_cipher_suite/0,
+ old_cipher_suite/0,
+ ciphers/0,
+ cipher/0,
+ hash/0,
+ key/0,
+ kex_algo/0,
+ prf_random/0,
+ cipher_filters/0,
+ sign_algo/0,
+ protocol_version/0,
+ protocol_extensions/0,
+ session_id/0,
+ error_alert/0,
+ srp_param_type/0]).
+
+%% -------------------------------------------------------------------------------------------------------
+
+-type socket() :: gen_tcp:socket(). % exported
+-type socket_option() :: gen_tcp:connect_option() | gen_tcp:listen_option() | gen_udp:option(). % exported
+-type sslsocket() :: any(). % exported
+-type tls_option() :: tls_client_option() | tls_server_option(). % exported
+-type tls_client_option() :: client_option() | common_option() | socket_option() | transport_option(). % exported
+-type tls_server_option() :: server_option() | common_option() | socket_option() | transport_option(). % exported
+-type active_msgs() :: {ssl, sslsocket(), Data::binary() | list()} | {ssl_closed, sslsocket()} |
+ {ssl_error, sslsocket(), Reason::any()} | {ssl_passive, sslsocket()}. % exported
+-type transport_option() :: {cb_info, {CallbackModule::atom(), DataTag::atom(),
+ ClosedTag::atom(), ErrTag::atom()}} |
+ {cb_info, {CallbackModule::atom(), DataTag::atom(),
+ ClosedTag::atom(), ErrTag::atom(), PassiveTag::atom()}}.
+-type host() :: hostname() | ip_address(). % exported
+-type hostname() :: string().
+-type ip_address() :: inet:ip_address().
+-type session_id() :: binary(). % exported
+-type protocol_version() :: tls_version() | dtls_version(). % exported
+-type tls_version() :: 'tlsv1.2' | 'tlsv1.3' | tls_legacy_version().
+-type dtls_version() :: 'dtlsv1.2' | dtls_legacy_version().
+-type tls_legacy_version() :: tlsv1 | 'tlsv1.1' | sslv3.
+-type dtls_legacy_version() :: 'dtlsv1'.
+-type verify_type() :: verify_none | verify_peer.
+-type cipher() :: aes_128_cbc |
+ aes_256_cbc |
+ aes_128_gcm |
+ aes_256_gcm |
+ aes_128_ccm |
+ aes_256_ccm |
+ aes_128_ccm_8 |
+ aes_256_ccm_8 |
+ chacha20_poly1305 |
+ legacy_cipher(). % exported
+-type legacy_cipher() :: rc4_128 |
+ des_cbc |
+ '3des_ede_cbc'.
+
+-type hash() :: sha |
+ sha2() |
+ legacy_hash(). % exported
+
+-type sha2() :: sha224 |
+ sha256 |
+ sha384 |
+ sha512.
+
+-type legacy_hash() :: md5.
+
+-type sign_algo() :: rsa | dsa | ecdsa. % exported
+
+-type sign_scheme() :: rsa_pkcs1_sha256
+ | rsa_pkcs1_sha384
+ | rsa_pkcs1_sha512
+ | ecdsa_secp256r1_sha256
+ | ecdsa_secp384r1_sha384
+ | ecdsa_secp521r1_sha512
+ | rsa_pss_rsae_sha256
+ | rsa_pss_rsae_sha384
+ | rsa_pss_rsae_sha512
+ | rsa_pss_pss_sha256
+ | rsa_pss_pss_sha384
+ | rsa_pss_pss_sha512
+ | rsa_pkcs1_sha1
+ | ecdsa_sha1.
+-type kex_algo() :: rsa |
+ dhe_rsa | dhe_dss |
+ ecdhe_ecdsa | ecdh_ecdsa | ecdh_rsa |
+ srp_rsa| srp_dss |
+ psk | dhe_psk | rsa_psk |
+ dh_anon | ecdh_anon | srp_anon |
+ any. %% TLS 1.3 , exported
+-type erl_cipher_suite() :: #{key_exchange := kex_algo(),
+ cipher := cipher(),
+ mac := hash() | aead,
+ prf := hash() | default_prf %% Old cipher suites, version dependent
+ }.
+
+-type old_cipher_suite() :: {kex_algo(), cipher(), hash()} % Pre TLS 1.2
+ %% TLS 1.2, internally PRE TLS 1.2 will use default_prf
+ | {kex_algo(), cipher(), hash() | aead, hash()}.
+
+-type named_curve() :: sect571r1 |
+ sect571k1 |
+ secp521r1 |
+ brainpoolP512r1 |
+ sect409k1 |
+ sect409r1 |
+ brainpoolP384r1 |
+ secp384r1 |
+ sect283k1 |
+ sect283r1 |
+ brainpoolP256r1 |
+ secp256k1 |
+ secp256r1 |
+ sect239k1 |
+ sect233k1 |
+ sect233r1 |
+ secp224k1 |
+ secp224r1 |
+ sect193r1 |
+ sect193r2 |
+ secp192k1 |
+ secp192r1 |
+ sect163k1 |
+ sect163r1 |
+ sect163r2 |
+ secp160k1 |
+ secp160r1 |
+ secp160r2.
+
+-type group() :: secp256r1 | secp384r1 | secp521r1 | ffdhe2048 |
+ ffdhe3072 | ffdhe4096 | ffdhe6144 | ffdhe8192.
+
+-type srp_param_type() :: srp_1024 |
+ srp_1536 |
+ srp_2048 |
+ srp_3072 |
+ srp_4096 |
+ srp_6144 |
+ srp_8192. % exported
+
+-type error_alert() :: {tls_alert, {tls_alert(), Description::string()}}. % exported
+
+-type tls_alert() :: close_notify |
+ unexpected_message |
+ bad_record_mac |
+ record_overflow |
+ handshake_failure |
+ bad_certificate |
+ unsupported_certificate |
+ certificate_revoked |
+ certificate_expired |
+ certificate_unknown |
+ illegal_parameter |
+ unknown_ca |
+ access_denied |
+ decode_error |
+ decrypt_error |
+ export_restriction|
+ protocol_version |
+ insufficient_security |
+ internal_error |
+ inappropriate_fallback |
+ user_canceled |
+ no_renegotiation |
+ unsupported_extension |
+ certificate_unobtainable |
+ unrecognized_name |
+ bad_certificate_status_response |
+ bad_certificate_hash_value |
+ unknown_psk_identity |
+ no_application_protocol.
+
+%% -------------------------------------------------------------------------------------------------------
+-type common_option() :: {protocol, protocol()} |
+ {handshake, handshake_completion()} |
+ {cert, cert()} |
+ {certfile, cert_pem()} |
+ {key, key()} |
+ {keyfile, key_pem()} |
+ {password, key_password()} |
+ {ciphers, cipher_suites()} |
+ {eccs, [named_curve()]} |
+ {signature_algs_cert, signature_schemes()} |
+ {secure_renegotiate, secure_renegotiation()} |
+ {depth, allowed_cert_chain_length()} |
+ {verify_fun, custom_verify()} |
+ {crl_check, crl_check()} |
+ {crl_cache, crl_cache_opts()} |
+ {max_handshake_size, handshake_size()} |
+ {partial_chain, root_fun()} |
+ {versions, protocol_versions()} |
+ {user_lookup_fun, custom_user_lookup()} |
+ {log_level, logging_level()} |
+ {log_alert, log_alert()} |
+ {hibernate_after, hibernate_after()} |
+ {padding_check, padding_check()} |
+ {beast_mitigation, beast_mitigation()} |
+ {ssl_imp, ssl_imp()}.
+
+-type protocol() :: tls | dtls.
+-type handshake_completion() :: hello | full.
+-type cert() :: public_key:der_encoded().
+-type cert_pem() :: file:filename().
+-type key() :: {'RSAPrivateKey'| 'DSAPrivateKey' | 'ECPrivateKey' |'PrivateKeyInfo',
+ public_key:der_encoded()} |
+ #{algorithm := rsa | dss | ecdsa,
+ engine := crypto:engine_ref(),
+ key_id := crypto:key_id(),
+ password => crypto:password()}. % exported
+-type key_pem() :: file:filename().
+-type key_password() :: string().
+-type cipher_suites() :: ciphers().
+-type ciphers() :: [erl_cipher_suite()] |
+ string(). % (according to old API) exported
+-type cipher_filters() :: list({key_exchange | cipher | mac | prf,
+ algo_filter()}). % exported
+-type algo_filter() :: fun((kex_algo()|cipher()|hash()|aead|default_prf) -> true | false).
+-type secure_renegotiation() :: boolean().
+-type allowed_cert_chain_length() :: integer().
+
+-type custom_verify() :: {Verifyfun :: fun(), InitialUserState :: any()}.
+-type crl_check() :: boolean() | peer | best_effort.
+-type crl_cache_opts() :: [any()].
+-type handshake_size() :: integer().
+-type hibernate_after() :: timeout().
+-type root_fun() :: fun().
+-type protocol_versions() :: [protocol_version()].
+-type signature_algs() :: [{hash(), sign_algo()}].
+-type signature_schemes() :: [sign_scheme()].
+-type custom_user_lookup() :: {Lookupfun :: fun(), UserState :: any()}.
+-type padding_check() :: boolean().
+-type beast_mitigation() :: one_n_minus_one | zero_n | disabled.
+-type srp_identity() :: {Username :: string(), Password :: string()}.
+-type psk_identity() :: string().
+-type log_alert() :: boolean().
+-type logging_level() :: logger:level().
+
+%% -------------------------------------------------------------------------------------------------------
+
+-type client_option() :: {verify, client_verify_type()} |
+ {reuse_session, client_reuse_session()} |
+ {reuse_sessions, client_reuse_sessions()} |
+ {cacerts, client_cacerts()} |
+ {cacertfile, client_cafile()} |
+ {alpn_advertised_protocols, client_alpn()} |
+ {client_preferred_next_protocols, client_preferred_next_protocols()} |
+ {psk_identity, client_psk_identity()} |
+ {srp_identity, client_srp_identity()} |
+ {server_name_indication, sni()} |
+ {customize_hostname_check, customize_hostname_check()} |
+ {signature_algs, client_signature_algs()} |
+ {fallback, fallback()}.
+
+-type client_verify_type() :: verify_type().
+-type client_reuse_session() :: session_id().
+-type client_reuse_sessions() :: boolean() | save.
+-type client_cacerts() :: [public_key:der_encoded()].
+-type client_cafile() :: file:filename().
+-type app_level_protocol() :: binary().
+-type client_alpn() :: [app_level_protocol()].
+-type client_preferred_next_protocols() :: {Precedence :: server | client,
+ ClientPrefs :: [app_level_protocol()]} |
+ {Precedence :: server | client,
+ ClientPrefs :: [app_level_protocol()],
+ Default::app_level_protocol()}.
+-type client_psk_identity() :: psk_identity().
+-type client_srp_identity() :: srp_identity().
+-type customize_hostname_check() :: list().
+-type sni() :: HostName :: hostname() | disable.
+-type client_signature_algs() :: signature_algs().
+-type fallback() :: boolean().
+-type ssl_imp() :: new | old.
+
+%% -------------------------------------------------------------------------------------------------------
+
+-type server_option() :: {cacerts, server_cacerts()} |
+ {cacertfile, server_cafile()} |
+ {dh, dh_der()} |
+ {dhfile, dh_file()} |
+ {verify, server_verify_type()} |
+ {fail_if_no_peer_cert, fail_if_no_peer_cert()} |
+ {reuse_sessions, server_reuse_sessions()} |
+ {reuse_session, server_reuse_session()} |
+ {alpn_preferred_protocols, server_alpn()} |
+ {next_protocols_advertised, server_next_protocol()} |
+ {psk_identity, server_psk_identity()} |
+ {honor_cipher_order, boolean()} |
+ {sni_hosts, sni_hosts()} |
+ {sni_fun, sni_fun()} |
+ {honor_cipher_order, honor_cipher_order()} |
+ {honor_ecc_order, honor_ecc_order()} |
+ {client_renegotiation, client_renegotiation()}|
+ {signature_algs, server_signature_algs()}.
+
+-type server_cacerts() :: [public_key:der_encoded()].
+-type server_cafile() :: file:filename().
+-type server_alpn() :: [app_level_protocol()].
+-type server_next_protocol() :: [app_level_protocol()].
+-type server_psk_identity() :: psk_identity().
+-type dh_der() :: binary().
+-type dh_file() :: file:filename().
+-type server_verify_type() :: verify_type().
+-type fail_if_no_peer_cert() :: boolean().
+-type server_signature_algs() :: signature_algs().
+-type server_reuse_session() :: fun().
+-type server_reuse_sessions() :: boolean().
+-type sni_hosts() :: [{hostname(), [server_option() | common_option()]}].
+-type sni_fun() :: fun().
+-type honor_cipher_order() :: boolean().
+-type honor_ecc_order() :: boolean().
+-type client_renegotiation() :: boolean().
+%% -------------------------------------------------------------------------------------------------------
+-type prf_random() :: client_random | server_random. % exported
+-type protocol_extensions() :: #{renegotiation_info => binary(),
+ signature_algs => signature_algs(),
+ alpn => app_level_protocol(),
+ srp => binary(),
+ next_protocol => app_level_protocol(),
+ ec_point_formats => [0..2],
+ elliptic_curves => [public_key:oid()],
+ sni => hostname()}. % exported
+%% -------------------------------------------------------------------------------------------------------
+
+%%%--------------------------------------------------------------------
+%%% API
+%%%--------------------------------------------------------------------
%%--------------------------------------------------------------------
--spec start() -> ok | {error, reason()}.
--spec start(permanent | transient | temporary) -> ok | {error, reason()}.
%%
%% Description: Utility function that starts the ssl and applications
%% that it depends on.
%% see application(3)
%%--------------------------------------------------------------------
+-spec start() -> ok | {error, reason()}.
start() ->
start(temporary).
+-spec start(permanent | transient | temporary) -> ok | {error, reason()}.
start(Type) ->
case application:ensure_all_started(ssl, Type) of
{ok, _} ->
@@ -82,24 +462,38 @@ stop() ->
application:stop(ssl).
%%--------------------------------------------------------------------
--spec connect(host() | port(), [connect_option()]) -> {ok, #sslsocket{}} |
- {error, reason()}.
--spec connect(host() | port(), [connect_option()] | inet:port_number(),
- timeout() | list()) ->
- {ok, #sslsocket{}} | {error, reason()}.
--spec connect(host() | port(), inet:port_number(), list(), timeout()) ->
- {ok, #sslsocket{}} | {error, reason()}.
-
%%
%% Description: Connect to an ssl server.
%%--------------------------------------------------------------------
+
+-spec connect(TCPSocket, TLSOptions) ->
+ {ok, sslsocket()} |
+ {error, reason()} |
+ {option_not_a_key_value_tuple, any()} when
+ TCPSocket :: socket(),
+ TLSOptions :: [tls_client_option()].
+
connect(Socket, SslOptions) when is_port(Socket) ->
connect(Socket, SslOptions, infinity).
+-spec connect(TCPSocket, TLSOptions, Timeout) ->
+ {ok, sslsocket()} | {error, reason()} when
+ TCPSocket :: socket(),
+ TLSOptions :: [tls_client_option()],
+ Timeout :: timeout();
+ (Host, Port, TLSOptions) ->
+ {ok, sslsocket()} |
+ {ok, sslsocket(),Ext :: protocol_extensions()} |
+ {error, reason()} |
+ {option_not_a_key_value_tuple, any()} when
+ Host :: host(),
+ Port :: inet:port_number(),
+ TLSOptions :: [tls_client_option()].
+
connect(Socket, SslOptions0, Timeout) when is_port(Socket),
- (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
- {Transport,_,_,_} = proplists:get_value(cb_info, SslOptions0,
- {gen_tcp, tcp, tcp_closed, tcp_error}),
+ (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
+ CbInfo = handle_option(cb_info, SslOptions0, default_cb_info(tls)),
+ Transport = element(1, CbInfo),
EmulatedOptions = tls_socket:emulated_options(),
{ok, SocketValues} = tls_socket:getopts(Transport, Socket, EmulatedOptions),
try handle_options(SslOptions0 ++ SocketValues, client) of
@@ -112,6 +506,17 @@ connect(Socket, SslOptions0, Timeout) when is_port(Socket),
connect(Host, Port, Options) ->
connect(Host, Port, Options, infinity).
+
+-spec connect(Host, Port, TLSOptions, Timeout) ->
+ {ok, sslsocket()} |
+ {ok, sslsocket(),Ext :: protocol_extensions()} |
+ {error, reason()} |
+ {option_not_a_key_value_tuple, any()} when
+ Host :: host(),
+ Port :: inet:port_number(),
+ TLSOptions :: [tls_client_option()],
+ Timeout :: timeout().
+
connect(Host, Port, Options, Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
try
{ok, Config} = handle_options(Options, client, Host),
@@ -127,7 +532,10 @@ connect(Host, Port, Options, Timeout) when (is_integer(Timeout) andalso Timeout
end.
%%--------------------------------------------------------------------
--spec listen(inet:port_number(), [listen_option()]) ->{ok, #sslsocket{}} | {error, reason()}.
+-spec listen(Port, Options) -> {ok, ListenSocket} | {error, reason()} when
+ Port::inet:port_number(),
+ Options::[tls_server_option()],
+ ListenSocket :: sslsocket().
%%
%% Description: Creates an ssl listen socket.
@@ -143,16 +551,23 @@ listen(Port, Options0) ->
Error
end.
%%--------------------------------------------------------------------
--spec transport_accept(#sslsocket{}) -> {ok, #sslsocket{}} |
- {error, reason()}.
--spec transport_accept(#sslsocket{}, timeout()) -> {ok, #sslsocket{}} |
- {error, reason()}.
%%
%% Description: Performs transport accept on an ssl listen socket
%%--------------------------------------------------------------------
+-spec transport_accept(ListenSocket) -> {ok, SslSocket} |
+ {error, reason()} when
+ ListenSocket :: sslsocket(),
+ SslSocket :: sslsocket().
+
transport_accept(ListenSocket) ->
transport_accept(ListenSocket, infinity).
+-spec transport_accept(ListenSocket, Timeout) -> {ok, SslSocket} |
+ {error, reason()} when
+ ListenSocket :: sslsocket(),
+ Timeout :: timeout(),
+ SslSocket :: sslsocket().
+
transport_accept(#sslsocket{pid = {ListenSocket,
#config{connection_cb = ConnectionCb} = Config}}, Timeout)
when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
@@ -164,29 +579,106 @@ transport_accept(#sslsocket{pid = {ListenSocket,
end.
%%--------------------------------------------------------------------
--spec ssl_accept(#sslsocket{}) -> ok | {error, reason()}.
--spec ssl_accept(#sslsocket{} | port(), timeout()| [ssl_option()
- | transport_option()]) ->
- ok | {ok, #sslsocket{}} | {error, reason()}.
-
--spec ssl_accept(#sslsocket{} | port(), [ssl_option()] | [ssl_option()| transport_option()], timeout()) ->
- {ok, #sslsocket{}} | {error, reason()}.
%%
%% Description: Performs accept on an ssl listen socket. e.i. performs
%% ssl handshake.
%%--------------------------------------------------------------------
+-spec ssl_accept(SslSocket) ->
+ ok |
+ {error, Reason} when
+ SslSocket :: sslsocket(),
+ Reason :: closed | timeout | error_alert().
+
ssl_accept(ListenSocket) ->
- ssl_accept(ListenSocket, infinity).
+ ssl_accept(ListenSocket, [], infinity).
+
+-spec ssl_accept(Socket, TimeoutOrOptions) ->
+ ok |
+ {ok, sslsocket()} | {error, Reason} when
+ Socket :: sslsocket() | socket(),
+ TimeoutOrOptions :: timeout() | [tls_server_option()],
+ Reason :: timeout | closed | {options, any()} | error_alert().
+
+ssl_accept(Socket, Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
+ ssl_accept(Socket, [], Timeout);
+ssl_accept(ListenSocket, SslOptions) when is_port(ListenSocket) ->
+ ssl_accept(ListenSocket, SslOptions, infinity);
+ssl_accept(Socket, Timeout) ->
+ ssl_accept(Socket, [], Timeout).
+
+-spec ssl_accept(Socket, Options, Timeout) ->
+ ok | {ok, sslsocket()} | {error, Reason} when
+ Socket :: sslsocket() | socket(),
+ Options :: [tls_server_option()],
+ Timeout :: timeout(),
+ Reason :: timeout | closed | {options, any()} | error_alert().
+
+ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket) ->
+ handshake(Socket, SslOptions, Timeout);
+ssl_accept(Socket, SslOptions, Timeout) ->
+ case handshake(Socket, SslOptions, Timeout) of
+ {ok, _} ->
+ ok;
+ Error ->
+ Error
+ end.
+%%--------------------------------------------------------------------
+%%
+%% Description: Performs accept on an ssl listen socket. e.i. performs
+%% ssl handshake.
+%%--------------------------------------------------------------------
-ssl_accept(#sslsocket{} = Socket, Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
+%% Performs the SSL/TLS/DTLS server-side handshake.
+-spec handshake(HsSocket) -> {ok, SslSocket} | {ok, SslSocket, Ext} | {error, Reason} when
+ HsSocket :: sslsocket(),
+ SslSocket :: sslsocket(),
+ Ext :: protocol_extensions(),
+ Reason :: closed | timeout | error_alert().
+
+handshake(ListenSocket) ->
+ handshake(ListenSocket, infinity).
+
+-spec handshake(HsSocket, Timeout) -> {ok, SslSocket} | {ok, SslSocket, Ext} | {error, Reason} when
+ HsSocket :: sslsocket(),
+ Timeout :: timeout(),
+ SslSocket :: sslsocket(),
+ Ext :: protocol_extensions(),
+ Reason :: closed | timeout | error_alert();
+ (Socket, Options) -> {ok, SslSocket} | {ok, SslSocket, Ext} | {error, Reason} when
+ Socket :: socket() | sslsocket(),
+ SslSocket :: sslsocket(),
+ Options :: [server_option()],
+ Ext :: protocol_extensions(),
+ Reason :: closed | timeout | error_alert().
+
+handshake(#sslsocket{} = Socket, Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or
+ (Timeout == infinity) ->
ssl_connection:handshake(Socket, Timeout);
-ssl_accept(ListenSocket, SslOptions) when is_port(ListenSocket) ->
- ssl_accept(ListenSocket, SslOptions, infinity).
-
-ssl_accept(#sslsocket{} = Socket, [], Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)->
- ssl_accept(Socket, Timeout);
-ssl_accept(#sslsocket{fd = {_, _, _, Tracker}} = Socket, SslOpts, Timeout) when
+%% If Socket is a ordinary socket(): upgrades a gen_tcp, or equivalent, socket to
+%% an SSL socket, that is, performs the SSL/TLS server-side handshake and returns
+%% the SSL socket.
+%%
+%% If Socket is an sslsocket(): provides extra SSL/TLS/DTLS options to those
+%% specified in ssl:listen/2 and then performs the SSL/TLS/DTLS handshake.
+handshake(ListenSocket, SslOptions) when is_port(ListenSocket) ->
+ handshake(ListenSocket, SslOptions, infinity).
+
+-spec handshake(Socket, Options, Timeout) ->
+ {ok, SslSocket} |
+ {ok, SslSocket, Ext} |
+ {error, Reason} when
+ Socket :: socket() | sslsocket(),
+ SslSocket :: sslsocket(),
+ Options :: [server_option()],
+ Timeout :: timeout(),
+ Ext :: protocol_extensions(),
+ Reason :: closed | timeout | {options, any()} | error_alert().
+
+handshake(#sslsocket{} = Socket, [], Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or
+ (Timeout == infinity)->
+ handshake(Socket, Timeout);
+handshake(#sslsocket{fd = {_, _, _, Tracker}} = Socket, SslOpts, Timeout) when
(is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)->
try
{ok, EmOpts, _} = tls_socket:get_all_opts(Tracker),
@@ -195,19 +687,19 @@ ssl_accept(#sslsocket{fd = {_, _, _, Tracker}} = Socket, SslOpts, Timeout) when
catch
Error = {error, _Reason} -> Error
end;
-ssl_accept(#sslsocket{pid = Pid, fd = {_, _, _}} = Socket, SslOpts, Timeout) when
+handshake(#sslsocket{pid = [Pid|_], fd = {_, _, _}} = Socket, SslOpts, Timeout) when
(is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)->
try
- {ok, EmOpts, _} = dtls_udp_listener:get_all_opts(Pid),
+ {ok, EmOpts, _} = dtls_packet_demux:get_all_opts(Pid),
ssl_connection:handshake(Socket, {SslOpts,
tls_socket:emulated_socket_options(EmOpts, #socket_options{})}, Timeout)
catch
Error = {error, _Reason} -> Error
end;
-ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket),
- (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
- {Transport,_,_,_} =
- proplists:get_value(cb_info, SslOptions, {gen_tcp, tcp, tcp_closed, tcp_error}),
+handshake(Socket, SslOptions, Timeout) when is_port(Socket),
+ (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
+ CbInfo = handle_option(cb_info, SslOptions, default_cb_info(tls)),
+ Transport = element(1, CbInfo),
EmulatedOptions = tls_socket:emulated_options(),
{ok, SocketValues} = tls_socket:getopts(Transport, Socket, EmulatedOptions),
ConnetionCb = connection_cb(SslOptions),
@@ -215,85 +707,148 @@ ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket),
{ok, #config{transport_info = CbInfo, ssl = SslOpts, emulated = EmOpts}} ->
ok = tls_socket:setopts(Transport, Socket, tls_socket:internal_inet_values()),
{ok, Port} = tls_socket:port(Transport, Socket),
- ssl_connection:ssl_accept(ConnetionCb, Port, Socket,
- {SslOpts,
- tls_socket:emulated_socket_options(EmOpts, #socket_options{}), undefined},
- self(), CbInfo, Timeout)
+ ssl_connection:handshake(ConnetionCb, Port, Socket,
+ {SslOpts,
+ tls_socket:emulated_socket_options(EmOpts, #socket_options{}), undefined},
+ self(), CbInfo, Timeout)
catch
Error = {error, _Reason} -> Error
end.
+
+
+%%--------------------------------------------------------------------
+-spec handshake_continue(HsSocket, Options) ->
+ {ok, SslSocket} | {error, Reason} when
+ HsSocket :: sslsocket(),
+ Options :: [tls_client_option() | tls_server_option()],
+ SslSocket :: sslsocket(),
+ Reason :: closed | timeout | error_alert().
+%%
+%%
+%% Description: Continues the handshke possible with newly supplied options.
+%%--------------------------------------------------------------------
+handshake_continue(Socket, SSLOptions) ->
+ handshake_continue(Socket, SSLOptions, infinity).
+%%--------------------------------------------------------------------
+-spec handshake_continue(HsSocket, Options, Timeout) ->
+ {ok, SslSocket} | {error, Reason} when
+ HsSocket :: sslsocket(),
+ Options :: [tls_client_option() | tls_server_option()],
+ Timeout :: timeout(),
+ SslSocket :: sslsocket(),
+ Reason :: closed | timeout | error_alert().
+%%
+%%
+%% Description: Continues the handshke possible with newly supplied options.
+%%--------------------------------------------------------------------
+handshake_continue(Socket, SSLOptions, Timeout) ->
+ ssl_connection:handshake_continue(Socket, SSLOptions, Timeout).
+%%--------------------------------------------------------------------
+-spec handshake_cancel(#sslsocket{}) -> any().
+%%
+%% Description: Cancels the handshakes sending a close alert.
+%%--------------------------------------------------------------------
+handshake_cancel(Socket) ->
+ ssl_connection:handshake_cancel(Socket).
+
%%--------------------------------------------------------------------
--spec close(#sslsocket{}) -> term().
+-spec close(SslSocket) -> ok | {error, Reason} when
+ SslSocket :: sslsocket(),
+ Reason :: any().
%%
%% Description: Close an ssl connection
%%--------------------------------------------------------------------
-close(#sslsocket{pid = Pid}) when is_pid(Pid) ->
+close(#sslsocket{pid = [Pid|_]}) when is_pid(Pid) ->
ssl_connection:close(Pid, {close, ?DEFAULT_TIMEOUT});
-close(#sslsocket{pid = {udp, #config{udp_handler = {Pid, _}}}}) ->
- dtls_udp_listener:close(Pid);
-close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_, _, _}}}}) ->
+close(#sslsocket{pid = {dtls, #config{dtls_handler = {Pid, _}}}}) ->
+ dtls_packet_demux:close(Pid);
+close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_,_,_,_}}}}) ->
Transport:close(ListenSocket).
%%--------------------------------------------------------------------
--spec close(#sslsocket{}, timeout() | {pid(), integer()}) -> term().
+-spec close(SslSocket, How) -> ok | {ok, port()} | {error,Reason} when
+ SslSocket :: sslsocket(),
+ How :: timeout() | {NewController::pid(), timeout()},
+ Reason :: any().
%%
%% Description: Close an ssl connection
%%--------------------------------------------------------------------
-close(#sslsocket{pid = TLSPid},
+close(#sslsocket{pid = [TLSPid|_]},
{Pid, Timeout} = DownGrade) when is_pid(TLSPid),
is_pid(Pid),
(is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
ssl_connection:close(TLSPid, {close, DownGrade});
-close(#sslsocket{pid = TLSPid}, Timeout) when is_pid(TLSPid),
+close(#sslsocket{pid = [TLSPid|_]}, Timeout) when is_pid(TLSPid),
(is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
ssl_connection:close(TLSPid, {close, Timeout});
-close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_, _, _}}}}, _) ->
+close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_,_,_,_}}}}, _) ->
Transport:close(ListenSocket).
%%--------------------------------------------------------------------
--spec send(#sslsocket{}, iodata()) -> ok | {error, reason()}.
+-spec send(SslSocket, Data) -> ok | {error, reason()} when
+ SslSocket :: sslsocket(),
+ Data :: iodata().
%%
%% Description: Sends data over the ssl connection
%%--------------------------------------------------------------------
-send(#sslsocket{pid = Pid}, Data) when is_pid(Pid) ->
+send(#sslsocket{pid = [Pid]}, Data) when is_pid(Pid) ->
ssl_connection:send(Pid, Data);
-send(#sslsocket{pid = {_, #config{transport_info={gen_udp, _, _, _}}}}, _) ->
+send(#sslsocket{pid = [_, Pid]}, Data) when is_pid(Pid) ->
+ tls_sender:send_data(Pid, erlang:iolist_to_iovec(Data));
+send(#sslsocket{pid = {_, #config{transport_info={_, udp, _, _}}}}, _) ->
{error,enotconn}; %% Emulate connection behaviour
-send(#sslsocket{pid = {udp,_}}, _) ->
- {error,enotconn};
-send(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport, _, _, _}}}}, Data) ->
+send(#sslsocket{pid = {dtls,_}}, _) ->
+ {error,enotconn}; %% Emulate connection behaviour
+send(#sslsocket{pid = {ListenSocket, #config{transport_info = Info}}}, Data) ->
+ Transport = element(1, Info),
Transport:send(ListenSocket, Data). %% {error,enotconn}
%%--------------------------------------------------------------------
--spec recv(#sslsocket{}, integer()) -> {ok, binary()| list()} | {error, reason()}.
--spec recv(#sslsocket{}, integer(), timeout()) -> {ok, binary()| list()} | {error, reason()}.
%%
%% Description: Receives data when active = false
%%--------------------------------------------------------------------
+-spec recv(SslSocket, Length) -> {ok, Data} | {error, reason()} when
+ SslSocket :: sslsocket(),
+ Length :: integer(),
+ Data :: binary() | list() | HttpPacket,
+ HttpPacket :: any().
+
recv(Socket, Length) ->
recv(Socket, Length, infinity).
-recv(#sslsocket{pid = Pid}, Length, Timeout) when is_pid(Pid),
+
+-spec recv(SslSocket, Length, Timeout) -> {ok, Data} | {error, reason()} when
+ SslSocket :: sslsocket(),
+ Length :: integer(),
+ Data :: binary() | list() | HttpPacket,
+ Timeout :: timeout(),
+ HttpPacket :: any().
+
+recv(#sslsocket{pid = [Pid|_]}, Length, Timeout) when is_pid(Pid),
(is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)->
ssl_connection:recv(Pid, Length, Timeout);
-recv(#sslsocket{pid = {udp,_}}, _, _) ->
+recv(#sslsocket{pid = {dtls,_}}, _, _) ->
{error,enotconn};
recv(#sslsocket{pid = {Listen,
- #config{transport_info = {Transport, _, _, _}}}}, _,_) when is_port(Listen)->
+ #config{transport_info = Info}}},_,_) when is_port(Listen)->
+ Transport = element(1, Info),
Transport:recv(Listen, 0). %% {error,enotconn}
%%--------------------------------------------------------------------
--spec controlling_process(#sslsocket{}, pid()) -> ok | {error, reason()}.
+-spec controlling_process(SslSocket, NewOwner) -> ok | {error, Reason} when
+ SslSocket :: sslsocket(),
+ NewOwner :: pid(),
+ Reason :: any().
%%
%% Description: Changes process that receives the messages when active = true
%% or once.
%%--------------------------------------------------------------------
-controlling_process(#sslsocket{pid = Pid}, NewOwner) when is_pid(Pid), is_pid(NewOwner) ->
+controlling_process(#sslsocket{pid = [Pid|_]}, NewOwner) when is_pid(Pid), is_pid(NewOwner) ->
ssl_connection:new_user(Pid, NewOwner);
-controlling_process(#sslsocket{pid = {udp, _}},
+controlling_process(#sslsocket{pid = {dtls, _}},
NewOwner) when is_pid(NewOwner) ->
ok; %% Meaningless but let it be allowed to conform with TLS
controlling_process(#sslsocket{pid = {Listen,
- #config{transport_info = {Transport, _, _, _}}}},
+ #config{transport_info = {Transport,_,_,_,_}}}},
NewOwner) when is_port(Listen),
is_pid(NewOwner) ->
%% Meaningless but let it be allowed to conform with normal sockets
@@ -301,11 +856,15 @@ controlling_process(#sslsocket{pid = {Listen,
%%--------------------------------------------------------------------
--spec connection_information(#sslsocket{}) -> {ok, list()} | {error, reason()}.
+-spec connection_information(SslSocket) -> {ok, Result} | {error, reason()} when
+ SslSocket :: sslsocket(),
+ Result :: [{OptionName, OptionValue}],
+ OptionName :: atom(),
+ OptionValue :: any().
%%
%% Description: Return SSL information for the connection
%%--------------------------------------------------------------------
-connection_information(#sslsocket{pid = Pid}) when is_pid(Pid) ->
+connection_information(#sslsocket{pid = [Pid|_]}) when is_pid(Pid) ->
case ssl_connection:connection_information(Pid, false) of
{ok, Info} ->
{ok, [Item || Item = {_Key, Value} <- Info, Value =/= undefined]};
@@ -314,15 +873,20 @@ connection_information(#sslsocket{pid = Pid}) when is_pid(Pid) ->
end;
connection_information(#sslsocket{pid = {Listen, _}}) when is_port(Listen) ->
{error, enotconn};
-connection_information(#sslsocket{pid = {udp,_}}) ->
+connection_information(#sslsocket{pid = {dtls,_}}) ->
{error,enotconn}.
%%--------------------------------------------------------------------
--spec connection_information(#sslsocket{}, [atom()]) -> {ok, list()} | {error, reason()}.
+-spec connection_information(SslSocket, Items) -> {ok, Result} | {error, reason()} when
+ SslSocket :: sslsocket(),
+ Items :: [OptionName],
+ Result :: [{OptionName, OptionValue}],
+ OptionName :: atom(),
+ OptionValue :: any().
%%
%% Description: Return SSL information for the connection
%%--------------------------------------------------------------------
-connection_information(#sslsocket{pid = Pid}, Items) when is_pid(Pid) ->
+connection_information(#sslsocket{pid = [Pid|_]}, Items) when is_pid(Pid) ->
case ssl_connection:connection_information(Pid, include_security_info(Items)) of
{ok, Info} ->
{ok, [Item || Item = {Key, Value} <- Info, lists:member(Key, Items),
@@ -332,73 +896,82 @@ connection_information(#sslsocket{pid = Pid}, Items) when is_pid(Pid) ->
end.
%%--------------------------------------------------------------------
--spec peername(#sslsocket{}) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}.
+-spec peername(SslSocket) -> {ok, {Address, Port}} |
+ {error, reason()} when
+ SslSocket :: sslsocket(),
+ Address :: inet:ip_address(),
+ Port :: inet:port_number().
%%
%% Description: same as inet:peername/1.
%%--------------------------------------------------------------------
-peername(#sslsocket{pid = Pid, fd = {Transport, Socket, _}}) when is_pid(Pid)->
+peername(#sslsocket{pid = [Pid|_], fd = {Transport, Socket,_}}) when is_pid(Pid)->
dtls_socket:peername(Transport, Socket);
-peername(#sslsocket{pid = Pid, fd = {Transport, Socket, _, _}}) when is_pid(Pid)->
+peername(#sslsocket{pid = [Pid|_], fd = {Transport, Socket,_,_}}) when is_pid(Pid)->
tls_socket:peername(Transport, Socket);
-peername(#sslsocket{pid = {udp = Transport, #config{udp_handler = {_Pid, _}}}}) ->
- dtls_socket:peername(Transport, undefined);
-peername(#sslsocket{pid = Pid, fd = {gen_udp= Transport, Socket, _, _}}) when is_pid(Pid) ->
- dtls_socket:peername(Transport, Socket);
-peername(#sslsocket{pid = {ListenSocket, #config{transport_info = {Transport,_,_,_}}}}) ->
+peername(#sslsocket{pid = {dtls, #config{dtls_handler = {_Pid,_}}}}) ->
+ dtls_socket:peername(dtls, undefined);
+peername(#sslsocket{pid = {ListenSocket, #config{transport_info = {Transport,_,_,_,_}}}}) ->
tls_socket:peername(Transport, ListenSocket); %% Will return {error, enotconn}
-peername(#sslsocket{pid = {udp,_}}) ->
+peername(#sslsocket{pid = {dtls,_}}) ->
{error,enotconn}.
%%--------------------------------------------------------------------
--spec peercert(#sslsocket{}) ->{ok, DerCert::binary()} | {error, reason()}.
+-spec peercert(SslSocket) -> {ok, Cert} | {error, reason()} when
+ SslSocket :: sslsocket(),
+ Cert :: binary().
%%
%% Description: Returns the peercert.
%%--------------------------------------------------------------------
-peercert(#sslsocket{pid = Pid}) when is_pid(Pid) ->
+peercert(#sslsocket{pid = [Pid|_]}) when is_pid(Pid) ->
case ssl_connection:peer_certificate(Pid) of
{ok, undefined} ->
{error, no_peercert};
Result ->
Result
end;
-peercert(#sslsocket{pid = {udp, _}}) ->
+peercert(#sslsocket{pid = {dtls, _}}) ->
{error, enotconn};
peercert(#sslsocket{pid = {Listen, _}}) when is_port(Listen) ->
{error, enotconn}.
%%--------------------------------------------------------------------
--spec negotiated_protocol(#sslsocket{}) -> {ok, binary()} | {error, reason()}.
+-spec negotiated_protocol(SslSocket) -> {ok, Protocol} | {error, Reason} when
+ SslSocket :: sslsocket(),
+ Protocol :: binary(),
+ Reason :: protocol_not_negotiated.
%%
%% Description: Returns the protocol that has been negotiated. If no
%% protocol has been negotiated will return {error, protocol_not_negotiated}
%%--------------------------------------------------------------------
-negotiated_protocol(#sslsocket{pid = Pid}) ->
+negotiated_protocol(#sslsocket{pid = [Pid|_]}) when is_pid(Pid) ->
ssl_connection:negotiated_protocol(Pid).
%%--------------------------------------------------------------------
--spec cipher_suites() -> [ssl_cipher:old_erl_cipher_suite()] | [string()].
+-spec cipher_suites() -> [old_cipher_suite()] | [string()].
%%--------------------------------------------------------------------
cipher_suites() ->
cipher_suites(erlang).
%%--------------------------------------------------------------------
--spec cipher_suites(erlang | openssl | all) ->
- [ssl_cipher:old_erl_cipher_suite() | string()].
+-spec cipher_suites(Type) -> [old_cipher_suite() | string()] when
+ Type :: erlang | openssl | all.
+
%% Description: Returns all supported cipher suites.
%%--------------------------------------------------------------------
cipher_suites(erlang) ->
- [ssl_cipher:erl_suite_definition(Suite) || Suite <- available_suites(default)];
+ [ssl_cipher_format:suite_legacy(Suite) || Suite <- available_suites(default)];
cipher_suites(openssl) ->
- [ssl_cipher:openssl_suite_name(Suite) ||
+ [ssl_cipher_format:suite_map_to_openssl_str(ssl_cipher_format:suite_bin_to_map(Suite)) ||
Suite <- available_suites(default)];
cipher_suites(all) ->
- [ssl_cipher:erl_suite_definition(Suite) || Suite <- available_suites(all)].
+ [ssl_cipher_format:suite_legacy(Suite) || Suite <- available_suites(all)].
%%--------------------------------------------------------------------
--spec cipher_suites(default | all | anonymous, tls_record:tls_version() | dtls_record:dtls_version() |
- tls_record:tls_atom_version() | dtls_record:dtls_atom_version()) ->
- [ssl_cipher:erl_cipher_suite()].
+-spec cipher_suites(Supported, Version) -> ciphers() when
+ Supported :: default | all | anonymous,
+ Version :: protocol_version().
+
%% Description: Returns all default and all supported cipher suites for a
%% TLS/DTLS version
%%--------------------------------------------------------------------
@@ -411,12 +984,37 @@ cipher_suites(Base, Version) when Version == 'dtlsv1.2';
Version == 'dtlsv1'->
cipher_suites(Base, dtls_record:protocol_version(Version));
cipher_suites(Base, Version) ->
- [ssl_cipher:suite_definition(Suite) || Suite <- supported_suites(Base, Version)].
+ [ssl_cipher_format:suite_bin_to_map(Suite) || Suite <- supported_suites(Base, Version)].
%%--------------------------------------------------------------------
--spec filter_cipher_suites([ssl_cipher:erl_cipher_suite()],
- [{key_exchange | cipher | mac | prf, fun()}] | []) ->
- [ssl_cipher:erl_cipher_suite()].
+-spec cipher_suites(Supported, Version, rfc | openssl) -> [string()] when
+ Supported :: default | all | anonymous,
+ Version :: protocol_version().
+
+%% Description: Returns all default and all supported cipher suites for a
+%% TLS/DTLS version
+%%--------------------------------------------------------------------
+cipher_suites(Base, Version, StringType) when Version == 'tlsv1.2';
+ Version == 'tlsv1.1';
+ Version == tlsv1;
+ Version == sslv3 ->
+ cipher_suites(Base, tls_record:protocol_version(Version), StringType);
+cipher_suites(Base, Version, StringType) when Version == 'dtlsv1.2';
+ Version == 'dtlsv1'->
+ cipher_suites(Base, dtls_record:protocol_version(Version), StringType);
+cipher_suites(Base, Version, rfc) ->
+ [ssl_cipher_format:suite_map_to_str(ssl_cipher_format:suite_bin_to_map(Suite))
+ || Suite <- supported_suites(Base, Version)];
+cipher_suites(Base, Version, openssl) ->
+ [ssl_cipher_format:suite_map_to_openssl_str(ssl_cipher_format:suite_bin_to_map(Suite))
+ || Suite <- supported_suites(Base, Version)].
+
+%%--------------------------------------------------------------------
+-spec filter_cipher_suites(Suites, Filters) -> Ciphers when
+ Suites :: ciphers(),
+ Filters :: cipher_filters(),
+ Ciphers :: ciphers().
+
%% Description: Removes cipher suites if any of the filter functions returns false
%% for any part of the cipher suite. This function also calls default filter functions
%% to make sure the cipher suite are supported by crypto.
@@ -433,10 +1031,10 @@ filter_cipher_suites(Suites, Filters0) ->
prf_filters => add_filter(proplists:get_value(prf, Filters0), PrfF)},
ssl_cipher:filter_suites(Suites, Filters).
%%--------------------------------------------------------------------
--spec prepend_cipher_suites([ssl_cipher:erl_cipher_suite()] |
- [{key_exchange | cipher | mac | prf, fun()}],
- [ssl_cipher:erl_cipher_suite()]) ->
- [ssl_cipher:erl_cipher_suite()].
+-spec prepend_cipher_suites(Preferred, Suites) -> ciphers() when
+ Preferred :: ciphers() | cipher_filters(),
+ Suites :: ciphers().
+
%% Description: Make <Preferred> suites become the most prefered
%% suites that is put them at the head of the cipher suite list
%% and remove them from <Suites> if present. <Preferred> may be a
@@ -451,10 +1049,10 @@ prepend_cipher_suites(Filters, Suites) ->
Preferred = filter_cipher_suites(Suites, Filters),
Preferred ++ (Suites -- Preferred).
%%--------------------------------------------------------------------
--spec append_cipher_suites(Deferred :: [ssl_cipher:erl_cipher_suite()] |
- [{key_exchange | cipher | mac | prf, fun()}],
- [ssl_cipher:erl_cipher_suite()]) ->
- [ssl_cipher:erl_cipher_suite()].
+-spec append_cipher_suites(Deferred, Suites) -> ciphers() when
+ Deferred :: ciphers() | cipher_filters(),
+ Suites :: ciphers().
+
%% Description: Make <Deferred> suites suites become the
%% least prefered suites that is put them at the end of the cipher suite list
%% and removed them from <Suites> if present.
@@ -468,7 +1066,9 @@ append_cipher_suites(Filters, Suites) ->
(Suites -- Deferred) ++ Deferred.
%%--------------------------------------------------------------------
--spec eccs() -> tls_v1:curves().
+-spec eccs() -> NamedCurves when
+ NamedCurves :: [named_curve()].
+
%% Description: returns all supported curves across all versions
%%--------------------------------------------------------------------
eccs() ->
@@ -476,18 +1076,24 @@ eccs() ->
eccs_filter_supported(Curves).
%%--------------------------------------------------------------------
--spec eccs(tls_record:tls_version() | tls_record:tls_atom_version()) ->
- tls_v1:curves().
+-spec eccs(Version) -> NamedCurves when
+ Version :: protocol_version(),
+ NamedCurves :: [named_curve()].
+
%% Description: returns the curves supported for a given version of
%% ssl/tls.
%%--------------------------------------------------------------------
-eccs({3,0}) ->
+eccs(sslv3) ->
[];
-eccs({3,_}) ->
+eccs('dtlsv1') ->
+ eccs('tlsv1.1');
+eccs('dtlsv1.2') ->
+ eccs('tlsv1.2');
+eccs(Version) when Version == 'tlsv1.2';
+ Version == 'tlsv1.1';
+ Version == tlsv1 ->
Curves = tls_v1:ecc_curves(all),
- eccs_filter_supported(Curves);
-eccs(AtomVersion) when is_atom(AtomVersion) ->
- eccs(tls_record:protocol_version(AtomVersion)).
+ eccs_filter_supported(Curves).
eccs_filter_supported(Curves) ->
CryptoCurves = crypto:ec_curves(),
@@ -495,14 +1101,30 @@ eccs_filter_supported(Curves) ->
Curves).
%%--------------------------------------------------------------------
--spec getopts(#sslsocket{}, [gen_tcp:option_name()]) ->
- {ok, [gen_tcp:option()]} | {error, reason()}.
+-spec groups() -> [group()].
+%% Description: returns all supported groups (TLS 1.3 and later)
+%%--------------------------------------------------------------------
+groups() ->
+ tls_v1:groups(4).
+
+%%--------------------------------------------------------------------
+-spec groups(default) -> [group()].
+%% Description: returns the default groups (TLS 1.3 and later)
+%%--------------------------------------------------------------------
+groups(default) ->
+ tls_v1:default_groups(4).
+
+%%--------------------------------------------------------------------
+-spec getopts(SslSocket, OptionNames) ->
+ {ok, [gen_tcp:option()]} | {error, reason()} when
+ SslSocket :: sslsocket(),
+ OptionNames :: [gen_tcp:option_name()].
%%
%% Description: Gets options
%%--------------------------------------------------------------------
-getopts(#sslsocket{pid = Pid}, OptionTags) when is_pid(Pid), is_list(OptionTags) ->
+getopts(#sslsocket{pid = [Pid|_]}, OptionTags) when is_pid(Pid), is_list(OptionTags) ->
ssl_connection:get_opts(Pid, OptionTags);
-getopts(#sslsocket{pid = {udp, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket, OptionTags) when is_list(OptionTags) ->
+getopts(#sslsocket{pid = {dtls, #config{transport_info = {Transport,_,_,_,_}}}} = ListenSocket, OptionTags) when is_list(OptionTags) ->
try dtls_socket:getopts(Transport, ListenSocket, OptionTags) of
{ok, _} = Result ->
Result;
@@ -512,7 +1134,7 @@ getopts(#sslsocket{pid = {udp, #config{transport_info = {Transport,_,_,_}}}} = L
_:Error ->
{error, {options, {socket_options, OptionTags, Error}}}
end;
-getopts(#sslsocket{pid = {_, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket,
+getopts(#sslsocket{pid = {_, #config{transport_info = {Transport,_,_,_,_}}}} = ListenSocket,
OptionTags) when is_list(OptionTags) ->
try tls_socket:getopts(Transport, ListenSocket, OptionTags) of
{ok, _} = Result ->
@@ -527,11 +1149,32 @@ getopts(#sslsocket{}, OptionTags) ->
{error, {options, {socket_options, OptionTags}}}.
%%--------------------------------------------------------------------
--spec setopts(#sslsocket{}, [gen_tcp:option()]) -> ok | {error, reason()}.
+-spec setopts(SslSocket, Options) -> ok | {error, reason()} when
+ SslSocket :: sslsocket(),
+ Options :: [gen_tcp:option()].
%%
%% Description: Sets options
%%--------------------------------------------------------------------
-setopts(#sslsocket{pid = Pid}, Options0) when is_pid(Pid), is_list(Options0) ->
+setopts(#sslsocket{pid = [Pid, Sender]}, Options0) when is_pid(Pid), is_list(Options0) ->
+ try proplists:expand([{binary, [{mode, binary}]},
+ {list, [{mode, list}]}], Options0) of
+ Options ->
+ case proplists:get_value(packet, Options, undefined) of
+ undefined ->
+ ssl_connection:set_opts(Pid, Options);
+ PacketOpt ->
+ case tls_sender:setopts(Sender, [{packet, PacketOpt}]) of
+ ok ->
+ ssl_connection:set_opts(Pid, Options);
+ Error ->
+ Error
+ end
+ end
+ catch
+ _:_ ->
+ {error, {options, {not_a_proplist, Options0}}}
+ end;
+setopts(#sslsocket{pid = [Pid|_]}, Options0) when is_pid(Pid), is_list(Options0) ->
try proplists:expand([{binary, [{mode, binary}]},
{list, [{mode, list}]}], Options0) of
Options ->
@@ -540,7 +1183,7 @@ setopts(#sslsocket{pid = Pid}, Options0) when is_pid(Pid), is_list(Options0) ->
_:_ ->
{error, {options, {not_a_proplist, Options0}}}
end;
-setopts(#sslsocket{pid = {udp, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket, Options) when is_list(Options) ->
+setopts(#sslsocket{pid = {dtls, #config{transport_info = {Transport,_,_,_,_}}}} = ListenSocket, Options) when is_list(Options) ->
try dtls_socket:setopts(Transport, ListenSocket, Options) of
ok ->
ok;
@@ -550,7 +1193,7 @@ setopts(#sslsocket{pid = {udp, #config{transport_info = {Transport,_,_,_}}}} = L
_:Error ->
{error, {options, {socket_options, Options, Error}}}
end;
-setopts(#sslsocket{pid = {_, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket, Options) when is_list(Options) ->
+setopts(#sslsocket{pid = {_, #config{transport_info = {Transport,_,_,_,_}}}} = ListenSocket, Options) when is_list(Options) ->
try tls_socket:setopts(Transport, ListenSocket, Options) of
ok ->
ok;
@@ -564,9 +1207,9 @@ setopts(#sslsocket{}, Options) ->
{error, {options,{not_a_proplist, Options}}}.
%%---------------------------------------------------------------
--spec getstat(Socket) ->
- {ok, OptionValues} | {error, inet:posix()} when
- Socket :: #sslsocket{},
+-spec getstat(SslSocket) ->
+ {ok, OptionValues} | {error, inet:posix()} when
+ SslSocket :: sslsocket(),
OptionValues :: [{inet:stat_option(), integer()}].
%%
%% Description: Get all statistic options for a socket.
@@ -575,84 +1218,111 @@ getstat(Socket) ->
getstat(Socket, inet:stats()).
%%---------------------------------------------------------------
--spec getstat(Socket, Options) ->
- {ok, OptionValues} | {error, inet:posix()} when
- Socket :: #sslsocket{},
+-spec getstat(SslSocket, Options) ->
+ {ok, OptionValues} | {error, inet:posix()} when
+ SslSocket :: sslsocket(),
Options :: [inet:stat_option()],
OptionValues :: [{inet:stat_option(), integer()}].
%%
%% Description: Get one or more statistic options for a socket.
%%--------------------------------------------------------------------
-getstat(#sslsocket{pid = {Listen, #config{transport_info = {Transport, _, _, _}}}}, Options) when is_port(Listen), is_list(Options) ->
+getstat(#sslsocket{pid = {Listen, #config{transport_info = {Transport, _, _, _, _}}}}, Options) when is_port(Listen), is_list(Options) ->
tls_socket:getstat(Transport, Listen, Options);
-getstat(#sslsocket{pid = Pid, fd = {Transport, Socket, _, _}}, Options) when is_pid(Pid), is_list(Options) ->
+getstat(#sslsocket{pid = [Pid|_], fd = {Transport, Socket, _, _}}, Options) when is_pid(Pid), is_list(Options) ->
tls_socket:getstat(Transport, Socket, Options).
%%---------------------------------------------------------------
--spec shutdown(#sslsocket{}, read | write | read_write) -> ok | {error, reason()}.
+-spec shutdown(SslSocket, How) -> ok | {error, reason()} when
+ SslSocket :: sslsocket(),
+ How :: read | write | read_write.
%%
%% Description: Same as gen_tcp:shutdown/2
%%--------------------------------------------------------------------
-shutdown(#sslsocket{pid = {Listen, #config{transport_info = {Transport,_, _, _}}}},
+shutdown(#sslsocket{pid = {Listen, #config{transport_info = Info}}},
How) when is_port(Listen) ->
+ Transport = element(1, Info),
Transport:shutdown(Listen, How);
-shutdown(#sslsocket{pid = {udp,_}},_) ->
+shutdown(#sslsocket{pid = {dtls,_}},_) ->
{error, enotconn};
-shutdown(#sslsocket{pid = Pid}, How) ->
+shutdown(#sslsocket{pid = [Pid|_]}, How) when is_pid(Pid) ->
ssl_connection:shutdown(Pid, How).
%%--------------------------------------------------------------------
--spec sockname(#sslsocket{}) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}.
+-spec sockname(SslSocket) ->
+ {ok, {Address, Port}} | {error, reason()} when
+ SslSocket :: sslsocket(),
+ Address :: inet:ip_address(),
+ Port :: inet:port_number().
%%
%% Description: Same as inet:sockname/1
%%--------------------------------------------------------------------
-sockname(#sslsocket{pid = {Listen, #config{transport_info = {Transport, _, _, _}}}}) when is_port(Listen) ->
+sockname(#sslsocket{pid = {Listen, #config{transport_info = {Transport,_,_,_,_}}}}) when is_port(Listen) ->
tls_socket:sockname(Transport, Listen);
-sockname(#sslsocket{pid = {udp, #config{udp_handler = {Pid, _}}}}) ->
- dtls_udp_listener:sockname(Pid);
-sockname(#sslsocket{pid = Pid, fd = {Transport, Socket, _}}) when is_pid(Pid) ->
+sockname(#sslsocket{pid = {dtls, #config{dtls_handler = {Pid, _}}}}) ->
+ dtls_packet_demux:sockname(Pid);
+sockname(#sslsocket{pid = [Pid|_], fd = {Transport, Socket,_}}) when is_pid(Pid) ->
dtls_socket:sockname(Transport, Socket);
-sockname(#sslsocket{pid = Pid, fd = {Transport, Socket, _, _}}) when is_pid(Pid) ->
+sockname(#sslsocket{pid = [Pid| _], fd = {Transport, Socket,_,_}}) when is_pid(Pid) ->
tls_socket:sockname(Transport, Socket).
%%---------------------------------------------------------------
--spec versions() -> [{ssl_app, string()} | {supported, [tls_record:tls_atom_version()]} |
- {available, [tls_record:tls_atom_version()]}].
+-spec versions() -> [VersionInfo] when
+ VersionInfo :: {ssl_app, string()} |
+ {supported | available, [tls_version()]} |
+ {supported_dtls | available_dtls, [dtls_version()]}.
%%
%% Description: Returns a list of relevant versions.
%%--------------------------------------------------------------------
versions() ->
- Vsns = tls_record:supported_protocol_versions(),
- SupportedVsns = [tls_record:protocol_version(Vsn) || Vsn <- Vsns],
- AvailableVsns = ?ALL_AVAILABLE_VERSIONS,
- %% TODO Add DTLS versions when supported
- [{ssl_app, ?VSN}, {supported, SupportedVsns}, {available, AvailableVsns}].
+ TLSVsns = tls_record:supported_protocol_versions(),
+ DTLSVsns = dtls_record:supported_protocol_versions(),
+ SupportedTLSVsns = [tls_record:protocol_version(Vsn) || Vsn <- TLSVsns],
+ SupportedDTLSVsns = [dtls_record:protocol_version(Vsn) || Vsn <- DTLSVsns],
+ AvailableTLSVsns = ?ALL_AVAILABLE_VERSIONS,
+ AvailableDTLSVsns = ?ALL_AVAILABLE_DATAGRAM_VERSIONS,
+ [{ssl_app, "9.2"}, {supported, SupportedTLSVsns},
+ {supported_dtls, SupportedDTLSVsns},
+ {available, AvailableTLSVsns},
+ {available_dtls, AvailableDTLSVsns}].
%%---------------------------------------------------------------
--spec renegotiate(#sslsocket{}) -> ok | {error, reason()}.
+-spec renegotiate(SslSocket) -> ok | {error, reason()} when
+ SslSocket :: sslsocket().
%%
%% Description: Initiates a renegotiation.
%%--------------------------------------------------------------------
-renegotiate(#sslsocket{pid = Pid}) when is_pid(Pid) ->
+renegotiate(#sslsocket{pid = [Pid, Sender |_]}) when is_pid(Pid),
+ is_pid(Sender) ->
+ case tls_sender:renegotiate(Sender) of
+ {ok, Write} ->
+ tls_connection:renegotiation(Pid, Write);
+ Error ->
+ Error
+ end;
+renegotiate(#sslsocket{pid = [Pid |_]}) when is_pid(Pid) ->
ssl_connection:renegotiation(Pid);
-renegotiate(#sslsocket{pid = {udp,_}}) ->
+renegotiate(#sslsocket{pid = {dtls,_}}) ->
{error, enotconn};
renegotiate(#sslsocket{pid = {Listen,_}}) when is_port(Listen) ->
{error, enotconn}.
%%--------------------------------------------------------------------
--spec prf(#sslsocket{}, binary() | 'master_secret', binary(),
- [binary() | prf_random()], non_neg_integer()) ->
- {ok, binary()} | {error, reason()}.
+-spec prf(SslSocket, Secret, Label, Seed, WantedLength) ->
+ {ok, binary()} | {error, reason()} when
+ SslSocket :: sslsocket(),
+ Secret :: binary() | 'master_secret',
+ Label::binary(),
+ Seed :: [binary() | prf_random()],
+ WantedLength :: non_neg_integer().
%%
%% Description: use a ssl sessions TLS PRF to generate key material
%%--------------------------------------------------------------------
-prf(#sslsocket{pid = Pid},
+prf(#sslsocket{pid = [Pid|_]},
Secret, Label, Seed, WantedLength) when is_pid(Pid) ->
ssl_connection:prf(Pid, Secret, Label, Seed, WantedLength);
-prf(#sslsocket{pid = {udp,_}}, _,_,_,_) ->
+prf(#sslsocket{pid = {dtls,_}}, _,_,_,_) ->
{error, enotconn};
prf(#sslsocket{pid = {Listen,_}}, _,_,_,_) when is_port(Listen) ->
{error, enotconn}.
@@ -666,7 +1336,8 @@ clear_pem_cache() ->
ssl_pem_cache:clear().
%%---------------------------------------------------------------
--spec format_error({error, term()}) -> list().
+-spec format_error({error, Reason}) -> string() when
+ Reason :: any().
%%
%% Description: Creates error string.
%%--------------------------------------------------------------------
@@ -676,8 +1347,8 @@ format_error(Reason) when is_list(Reason) ->
Reason;
format_error(closed) ->
"TLS connection is closed";
-format_error({tls_alert, Description}) ->
- "TLS Alert: " ++ Description;
+format_error({tls_alert, {_, Description}}) ->
+ Description;
format_error({options,{FileType, File, Reason}}) when FileType == cacertfile;
FileType == certfile;
FileType == keyfile;
@@ -704,10 +1375,54 @@ tls_version({3, _} = Version) ->
tls_version({254, _} = Version) ->
dtls_v1:corresponding_tls_version(Version).
+%%--------------------------------------------------------------------
+-spec suite_to_str(CipherSuite) -> string() when
+ CipherSuite :: erl_cipher_suite();
+ (CipherSuite) -> string() when
+ %% For internal use!
+ CipherSuite :: #{key_exchange := null,
+ cipher := null,
+ mac := null,
+ prf := null}.
+%%
+%% Description: Return the string representation of a cipher suite.
+%%--------------------------------------------------------------------
+suite_to_str(Cipher) ->
+ ssl_cipher_format:suite_map_to_str(Cipher).
+
+%%--------------------------------------------------------------------
+-spec suite_to_openssl_str(CipherSuite) -> string() when
+ CipherSuite :: erl_cipher_suite().
+%%
+%% Description: Return the string representation of a cipher suite.
+%%--------------------------------------------------------------------
+suite_to_openssl_str(Cipher) ->
+ ssl_cipher_format:suite_map_to_openssl_str(Cipher).
+
+%%
+%%--------------------------------------------------------------------
+-spec str_to_suite(CipherSuiteName) -> erl_cipher_suite() when
+ CipherSuiteName :: string() | {error, {not_recognized, CipherSuiteName :: string()}}.
+%%
+%% Description: Return the map representation of a cipher suite.
+%%--------------------------------------------------------------------
+str_to_suite(CipherSuiteName) ->
+ try
+ %% Note in TLS-1.3 OpenSSL conforms to RFC names
+ %% so if CipherSuiteName starts with TLS this
+ %% function will call ssl_cipher_format:suite_str_to_map
+ %% so both RFC names and legacy OpenSSL names of supported
+ %% cipher suites will be handled
+ ssl_cipher_format:suite_openssl_str_to_map(CipherSuiteName)
+ catch
+ _:_ ->
+ {error, {not_recognized, CipherSuiteName}}
+ end.
+
%%%--------------------------------------------------------------
%%% Internal functions
%%%--------------------------------------------------------------------
-
+
%% Possible filters out suites not supported by crypto
available_suites(default) ->
Version = tls_record:highest_protocol_version([]),
@@ -723,11 +1438,11 @@ supported_suites(all, Version) ->
supported_suites(anonymous, Version) ->
ssl_cipher:anonymous_suites(Version).
-do_listen(Port, #config{transport_info = {Transport, _, _, _}} = Config, tls_connection) ->
+do_listen(Port, #config{transport_info = {Transport, _, _, _,_}} = Config, tls_connection) ->
tls_socket:listen(Transport, Port, Config);
-do_listen(Port, #config{transport_info = {Transport, _, _, _}} = Config, dtls_connection) ->
- dtls_socket:listen(Transport, Port, Config).
+do_listen(Port, Config, dtls_connection) ->
+ dtls_socket:listen(Port, Config).
%% Handle extra ssl options given to ssl_accept
-spec handle_options([any()], #ssl_options{}) -> #ssl_options{}
@@ -764,9 +1479,10 @@ handle_options(Opts0, #ssl_options{protocol = Protocol, cacerts = CaCerts0,
[] ->
new_ssl_options(SslOpts1, NewVerifyOpts, RecordCB);
Value ->
- Versions = [RecordCB:protocol_version(Vsn) || Vsn <- Value],
+ Versions0 = [RecordCB:protocol_version(Vsn) || Vsn <- Value],
+ Versions1 = lists:sort(fun RecordCB:is_higher/2, Versions0),
new_ssl_options(proplists:delete(versions, SslOpts1),
- NewVerifyOpts#ssl_options{versions = Versions}, record_cb(Protocol))
+ NewVerifyOpts#ssl_options{versions = Versions1}, record_cb(Protocol))
end;
%% Handle all options in listen and connect
@@ -775,22 +1491,21 @@ handle_options(Opts0, Role, Host) ->
{list, [{mode, list}]}], Opts0),
assert_proplist(Opts),
RecordCb = record_cb(Opts),
-
- ReuseSessionFun = fun(_, _, _, _) -> true end,
CaCerts = handle_option(cacerts, Opts, undefined),
{Verify, FailIfNoPeerCert, CaCertDefault, VerifyFun, PartialChainHanlder, VerifyClientOnce} =
handle_verify_options(Opts, CaCerts),
CertFile = handle_option(certfile, Opts, <<>>),
- RecordCb = record_cb(Opts),
- Versions = case handle_option(versions, Opts, []) of
- [] ->
- RecordCb:supported_protocol_versions();
- Vsns ->
- [RecordCb:protocol_version(Vsn) || Vsn <- Vsns]
- end,
+ [HighestVersion|_] = Versions =
+ case handle_option(versions, Opts, []) of
+ [] ->
+ RecordCb:supported_protocol_versions();
+ Vsns ->
+ Versions0 = [RecordCb:protocol_version(Vsn) || Vsn <- Vsns],
+ lists:sort(fun RecordCb:is_higher/2, Versions0)
+ end,
Protocol = handle_option(protocol, Opts, tls),
@@ -801,7 +1516,7 @@ handle_options(Opts0, Role, Host) ->
ok
end,
- SSLOptions = #ssl_options{
+ SSLOptions0 = #ssl_options{
versions = Versions,
verify = validate_option(verify, Verify),
verify_fun = VerifyFun,
@@ -822,17 +1537,32 @@ handle_options(Opts0, Role, Host) ->
psk_identity = handle_option(psk_identity, Opts, undefined),
srp_identity = handle_option(srp_identity, Opts, undefined),
ciphers = handle_cipher_option(proplists:get_value(ciphers, Opts, []),
- RecordCb:highest_protocol_version(Versions)),
+ HighestVersion),
eccs = handle_eccs_option(proplists:get_value(eccs, Opts, eccs()),
- RecordCb:highest_protocol_version(Versions)),
- signature_algs = handle_hashsigns_option(proplists:get_value(signature_algs, Opts,
- default_option_role(server,
- tls_v1:default_signature_algs(Versions), Role)),
- tls_version(RecordCb:highest_protocol_version(Versions))),
- %% Server side option
- reuse_session = handle_option(reuse_session, Opts, ReuseSessionFun),
- reuse_sessions = handle_option(reuse_sessions, Opts, true),
- secure_renegotiate = handle_option(secure_renegotiate, Opts, false),
+ HighestVersion),
+ supported_groups = handle_supported_groups_option(
+ proplists:get_value(supported_groups, Opts, groups(default)),
+ HighestVersion),
+ signature_algs =
+ handle_hashsigns_option(
+ proplists:get_value(
+ signature_algs,
+ Opts,
+ default_option_role_sign_algs(server,
+ tls_v1:default_signature_algs(HighestVersion),
+ Role,
+ HighestVersion)),
+ tls_version(HighestVersion)),
+ signature_algs_cert =
+ handle_signature_algorithms_option(
+ proplists:get_value(
+ signature_algs_cert,
+ Opts,
+ undefined), %% Do not send by default
+ tls_version(HighestVersion)),
+ reuse_sessions = handle_reuse_sessions_option(reuse_sessions, Opts, Role),
+ reuse_session = handle_reuse_session_option(reuse_session, Opts, Role),
+ secure_renegotiate = handle_option(secure_renegotiate, Opts, true),
client_renegotiation = handle_option(client_renegotiation, Opts,
default_option_role(server, true, Role),
server, Role),
@@ -848,7 +1578,6 @@ handle_options(Opts0, Role, Host) ->
next_protocol_selector =
make_next_protocol_selector(
handle_option(client_preferred_next_protocols, Opts, undefined)),
- log_alert = handle_option(log_alert, Opts, true),
server_name_indication = handle_option(server_name_indication, Opts,
default_option_role(client,
server_name_indication_default(Host), Role)),
@@ -870,11 +1599,16 @@ handle_options(Opts0, Role, Host) ->
client, Role),
crl_check = handle_option(crl_check, Opts, false),
crl_cache = handle_option(crl_cache, Opts, {ssl_crl_cache, {internal, []}}),
- v2_hello_compatible = handle_option(v2_hello_compatible, Opts, false),
- max_handshake_size = handle_option(max_handshake_size, Opts, ?DEFAULT_MAX_HANDSHAKE_SIZE)
+ max_handshake_size = handle_option(max_handshake_size, Opts, ?DEFAULT_MAX_HANDSHAKE_SIZE),
+ handshake = handle_option(handshake, Opts, full),
+ customize_hostname_check = handle_option(customize_hostname_check, Opts, [])
},
+ LogLevel = handle_option(log_alert, Opts, true),
+ SSLOptions = SSLOptions0#ssl_options{
+ log_level = handle_option(log_level, Opts, LogLevel)
+ },
- CbInfo = proplists:get_value(cb_info, Opts, default_cb_info(Protocol)),
+ CbInfo = handle_option(cb_info, Opts, default_cb_info(Protocol)),
SslOptions = [protocol, versions, verify, verify_fun, partial_chain,
fail_if_no_peer_cert, verify_client_once,
depth, cert, certfile, key, keyfile,
@@ -884,10 +1618,11 @@ handle_options(Opts0, Role, Host) ->
cb_info, renegotiate_at, secure_renegotiate, hibernate_after,
erl_dist, alpn_advertised_protocols, sni_hosts, sni_fun,
alpn_preferred_protocols, next_protocols_advertised,
- client_preferred_next_protocols, log_alert,
+ client_preferred_next_protocols, log_alert, log_level,
server_name_indication, honor_cipher_order, padding_check, crl_check, crl_cache,
- fallback, signature_algs, eccs, honor_ecc_order, beast_mitigation, v2_hello_compatible,
- max_handshake_size],
+ fallback, signature_algs, signature_algs_cert, eccs, honor_ecc_order,
+ beast_mitigation, max_handshake_size, handshake, customize_hostname_check,
+ supported_groups],
SockOpts = lists:foldl(fun(Key, PropList) ->
proplists:delete(Key, PropList)
@@ -900,8 +1635,6 @@ handle_options(Opts0, Role, Host) ->
inet_user = Sock, transport_info = CbInfo, connection_cb = ConnetionCb
}}.
-
-
handle_option(OptionName, Opts, Default, Role, Role) ->
handle_option(OptionName, Opts, Default);
handle_option(_, _, undefined = Value, _, _) ->
@@ -919,6 +1652,10 @@ handle_option(sni_fun, Opts, Default) ->
_ ->
throw({error, {conflict_options, [sni_fun, sni_hosts]}})
end;
+handle_option(cb_info, Opts, Default) ->
+ CbInfo = proplists:get_value(cb_info, Opts, Default),
+ true = validate_option(cb_info, CbInfo),
+ handle_cb_info(CbInfo, Default);
handle_option(OptionName, Opts, Default) ->
validate_option(OptionName,
proplists:get_value(OptionName, Opts, Default)).
@@ -1024,11 +1761,16 @@ validate_option(srp_identity, {Username, Password})
{unicode:characters_to_binary(Username),
unicode:characters_to_binary(Password)};
+validate_option(reuse_session, undefined) ->
+ undefined;
validate_option(reuse_session, Value) when is_function(Value) ->
Value;
+validate_option(reuse_session, Value) when is_binary(Value) ->
+ Value;
validate_option(reuse_sessions, Value) when is_boolean(Value) ->
Value;
-
+validate_option(reuse_sessions, save = Value) ->
+ Value;
validate_option(secure_renegotiate, Value) when is_boolean(Value) ->
Value;
validate_option(client_renegotiation, Value) when is_boolean(Value) ->
@@ -1066,7 +1808,20 @@ validate_option(client_preferred_next_protocols, {Precedence, PreferredProtocols
Value;
validate_option(client_preferred_next_protocols, undefined) ->
undefined;
-validate_option(log_alert, Value) when is_boolean(Value) ->
+validate_option(log_alert, true) ->
+ notice;
+validate_option(log_alert, false) ->
+ warning;
+validate_option(log_level, Value) when
+ is_atom(Value) andalso
+ (Value =:= emergency orelse
+ Value =:= alert orelse
+ Value =:= critical orelse
+ Value =:= error orelse
+ Value =:= warning orelse
+ Value =:= notice orelse
+ Value =:= info orelse
+ Value =:= debug) ->
Value;
validate_option(next_protocols_advertised, Value) when is_list(Value) ->
validate_binary_list(next_protocols_advertised, Value),
@@ -1123,30 +1878,97 @@ validate_option(beast_mitigation, Value) when Value == one_n_minus_one orelse
Value == zero_n orelse
Value == disabled ->
Value;
-validate_option(v2_hello_compatible, Value) when is_boolean(Value) ->
- Value;
validate_option(max_handshake_size, Value) when is_integer(Value) andalso Value =< ?MAX_UNIT24 ->
Value;
validate_option(protocol, Value = tls) ->
Value;
validate_option(protocol, Value = dtls) ->
Value;
+validate_option(handshake, hello = Value) ->
+ Value;
+validate_option(handshake, full = Value) ->
+ Value;
+validate_option(customize_hostname_check, Value) when is_list(Value) ->
+ Value;
+validate_option(cb_info, {V1, V2, V3, V4}) when is_atom(V1),
+ is_atom(V2),
+ is_atom(V3),
+ is_atom(V4)
+ ->
+ true;
+validate_option(cb_info, {V1, V2, V3, V4, V5}) when is_atom(V1),
+ is_atom(V2),
+ is_atom(V3),
+ is_atom(V4),
+ is_atom(V5)
+ ->
+ true;
+validate_option(cb_info, _) ->
+ false;
validate_option(Opt, Value) ->
throw({error, {options, {Opt, Value}}}).
+handle_cb_info({V1, V2, V3, V4}, {_,_,_,_,_}) ->
+ {V1,V2,V3,V4, list_to_atom(atom_to_list(V2) ++ "passive")};
+handle_cb_info(CbInfo, _) ->
+ CbInfo.
+
+handle_hashsigns_option(Value, Version) when is_list(Value)
+ andalso Version >= {3, 4} ->
+ case tls_v1:signature_schemes(Version, Value) of
+ [] ->
+ throw({error, {options,
+ no_supported_signature_schemes,
+ {signature_algs, Value}}});
+ _ ->
+ Value
+ end;
handle_hashsigns_option(Value, Version) when is_list(Value)
- andalso Version >= {3, 3} ->
+ andalso Version =:= {3, 3} ->
case tls_v1:signature_algs(Version, Value) of
[] ->
throw({error, {options, no_supported_algorithms, {signature_algs, Value}}});
_ ->
Value
end;
-handle_hashsigns_option(_, Version) when Version >= {3, 3} ->
+handle_hashsigns_option(_, Version) when Version =:= {3, 3} ->
handle_hashsigns_option(tls_v1:default_signature_algs(Version), Version);
handle_hashsigns_option(_, _Version) ->
undefined.
+handle_signature_algorithms_option(Value, Version) when is_list(Value)
+ andalso Version >= {3, 4} ->
+ case tls_v1:signature_schemes(Version, Value) of
+ [] ->
+ throw({error, {options,
+ no_supported_signature_schemes,
+ {signature_algs_cert, Value}}});
+ _ ->
+ Value
+ end;
+handle_signature_algorithms_option(_, _Version) ->
+ undefined.
+
+handle_reuse_sessions_option(Key, Opts, client) ->
+ Value = proplists:get_value(Key, Opts, true),
+ validate_option(Key, Value),
+ Value;
+handle_reuse_sessions_option(Key, Opts0, server) ->
+ Opts = proplists:delete({Key, save}, Opts0),
+ Value = proplists:get_value(Key, Opts, true),
+ validate_option(Key, Value),
+ Value.
+
+handle_reuse_session_option(Key, Opts, client) ->
+ Value = proplists:get_value(Key, Opts, undefined),
+ validate_option(Key, Value),
+ Value;
+handle_reuse_session_option(Key, Opts, server) ->
+ ReuseSessionFun = fun(_, _, _, _) -> true end,
+ Value = proplists:get_value(Key, Opts, ReuseSessionFun),
+ validate_option(Key, Value),
+ Value.
+
validate_options([]) ->
[];
validate_options([{Opt, Value} | Tail]) ->
@@ -1170,7 +1992,8 @@ validate_binary_list(Opt, List) ->
end, List).
validate_versions([], Versions) ->
Versions;
-validate_versions([Version | Rest], Versions) when Version == 'tlsv1.2';
+validate_versions([Version | Rest], Versions) when Version == 'tlsv1.3';
+ Version == 'tlsv1.2';
Version == 'tlsv1.1';
Version == tlsv1;
Version == sslv3 ->
@@ -1183,10 +2006,11 @@ validate_versions([Ver| _], Versions) ->
tls_validate_versions([], Versions) ->
Versions;
-tls_validate_versions([Version | Rest], Versions) when Version == 'tlsv1.2';
- Version == 'tlsv1.1';
- Version == tlsv1;
- Version == sslv3 ->
+tls_validate_versions([Version | Rest], Versions) when Version == 'tlsv1.3';
+ Version == 'tlsv1.2';
+ Version == 'tlsv1.1';
+ Version == tlsv1;
+ Version == sslv3 ->
tls_validate_versions(Rest, Versions);
tls_validate_versions([Ver| _], Versions) ->
throw({error, {options, {Ver, {versions, Versions}}}}).
@@ -1234,10 +2058,10 @@ binary_cipher_suites(Version, []) ->
%% not require explicit configuration
default_binary_suites(Version);
binary_cipher_suites(Version, [Map|_] = Ciphers0) when is_map(Map) ->
- Ciphers = [ssl_cipher:suite(C) || C <- Ciphers0],
+ Ciphers = [ssl_cipher_format:suite_map_to_bin(C) || C <- Ciphers0],
binary_cipher_suites(Version, Ciphers);
binary_cipher_suites(Version, [Tuple|_] = Ciphers0) when is_tuple(Tuple) ->
- Ciphers = [ssl_cipher:suite(tuple_to_map(C)) || C <- Ciphers0],
+ Ciphers = [ssl_cipher_format:suite_map_to_bin(tuple_to_map(C)) || C <- Ciphers0],
binary_cipher_suites(Version, Ciphers);
binary_cipher_suites(Version, [Cipher0 | _] = Ciphers0) when is_binary(Cipher0) ->
All = ssl_cipher:all_suites(Version) ++
@@ -1252,11 +2076,11 @@ binary_cipher_suites(Version, [Cipher0 | _] = Ciphers0) when is_binary(Cipher0)
end;
binary_cipher_suites(Version, [Head | _] = Ciphers0) when is_list(Head) ->
%% Format: ["RC4-SHA","RC4-MD5"]
- Ciphers = [ssl_cipher:openssl_suite(C) || C <- Ciphers0],
+ Ciphers = [ssl_cipher_format:suite_openssl_str_to_map(C) || C <- Ciphers0],
binary_cipher_suites(Version, Ciphers);
binary_cipher_suites(Version, Ciphers0) ->
%% Format: "RC4-SHA:RC4-MD5"
- Ciphers = [ssl_cipher:openssl_suite(C) || C <- string:lexemes(Ciphers0, ":")],
+ Ciphers = [ssl_cipher_format:suite_openssl_str_to_map(C) || C <- string:lexemes(Ciphers0, ":")],
binary_cipher_suites(Version, Ciphers).
default_binary_suites(Version) ->
@@ -1292,6 +2116,16 @@ handle_eccs_option(Value, Version) when is_list(Value) ->
error:_ -> throw({error, {options, {eccs, Value}}})
end.
+handle_supported_groups_option(Value, Version) when is_list(Value) ->
+ {_Major, Minor} = tls_version(Version),
+ try tls_v1:groups(Minor, Value) of
+ Groups -> #supported_groups{supported_groups = Groups}
+ catch
+ exit:_ -> throw({error, {options, {supported_groups, Value}}});
+ error:_ -> throw({error, {options, {supported_groups, Value}}})
+ end.
+
+
unexpected_format(Error) ->
lists:flatten(io_lib:format("Unexpected error: ~p", [Error])).
@@ -1437,8 +2271,10 @@ new_ssl_options([{next_protocols_advertised, Value} | Rest], #ssl_options{} = Op
new_ssl_options([{client_preferred_next_protocols, Value} | Rest], #ssl_options{} = Opts, RecordCB) ->
new_ssl_options(Rest, Opts#ssl_options{next_protocol_selector =
make_next_protocol_selector(validate_option(client_preferred_next_protocols, Value))}, RecordCB);
-new_ssl_options([{log_alert, Value} | Rest], #ssl_options{} = Opts, RecordCB) ->
- new_ssl_options(Rest, Opts#ssl_options{log_alert = validate_option(log_alert, Value)}, RecordCB);
+new_ssl_options([{log_alert, Value} | Rest], #ssl_options{} = Opts, RecordCB) ->
+ new_ssl_options(Rest, Opts#ssl_options{log_level = validate_option(log_alert, Value)}, RecordCB);
+new_ssl_options([{log_level, Value} | Rest], #ssl_options{} = Opts, RecordCB) ->
+ new_ssl_options(Rest, Opts#ssl_options{log_level = validate_option(log_level, Value)}, RecordCB);
new_ssl_options([{server_name_indication, Value} | Rest], #ssl_options{} = Opts, RecordCB) ->
new_ssl_options(Rest, Opts#ssl_options{server_name_indication = validate_option(server_name_indication, Value)}, RecordCB);
new_ssl_options([{honor_cipher_order, Value} | Rest], #ssl_options{} = Opts, RecordCB) ->
@@ -1451,12 +2287,26 @@ new_ssl_options([{eccs, Value} | Rest], #ssl_options{} = Opts, RecordCB) ->
handle_eccs_option(Value, RecordCB:highest_protocol_version())
},
RecordCB);
+new_ssl_options([{supported_groups, Value} | Rest], #ssl_options{} = Opts, RecordCB) ->
+ new_ssl_options(Rest,
+ Opts#ssl_options{supported_groups =
+ handle_supported_groups_option(Value, RecordCB:highest_protocol_version())
+ },
+ RecordCB);
new_ssl_options([{signature_algs, Value} | Rest], #ssl_options{} = Opts, RecordCB) ->
new_ssl_options(Rest,
Opts#ssl_options{signature_algs =
handle_hashsigns_option(Value,
tls_version(RecordCB:highest_protocol_version()))},
RecordCB);
+new_ssl_options([{signature_algs_cert, Value} | Rest], #ssl_options{} = Opts, RecordCB) ->
+ new_ssl_options(
+ Rest,
+ Opts#ssl_options{signature_algs_cert =
+ handle_signature_algorithms_option(
+ Value,
+ tls_version(RecordCB:highest_protocol_version()))},
+ RecordCB);
new_ssl_options([{protocol, dtls = Value} | Rest], #ssl_options{} = Opts, dtls_record = RecordCB) ->
new_ssl_options(Rest, Opts#ssl_options{protocol = Value}, RecordCB);
new_ssl_options([{protocol, tls = Value} | Rest], #ssl_options{} = Opts, tls_record = RecordCB) ->
@@ -1518,15 +2368,24 @@ handle_verify_options(Opts, CaCerts) ->
throw({error, {options, {verify, Value}}})
end.
+%% Added to handle default values for signature_algs in TLS 1.3
+default_option_role_sign_algs(_, Value, _, Version) when Version >= {3,4} ->
+ Value;
+default_option_role_sign_algs(Role, Value, Role, _) ->
+ Value;
+default_option_role_sign_algs(_, _, _, _) ->
+ undefined.
+
default_option_role(Role, Value, Role) ->
Value;
default_option_role(_,_,_) ->
undefined.
+
default_cb_info(tls) ->
- {gen_tcp, tcp, tcp_closed, tcp_error};
+ {gen_tcp, tcp, tcp_closed, tcp_error, tcp_passive};
default_cb_info(dtls) ->
- {gen_udp, udp, udp_closed, udp_error}.
+ {gen_udp, udp, udp_closed, udp_error, udp_passive}.
include_security_info([]) ->
false;
diff --git a/lib/ssl/src/ssl_alert.erl b/lib/ssl/src/ssl_alert.erl
index 95ab955ad0..06b1b005a5 100644
--- a/lib/ssl/src/ssl_alert.erl
+++ b/lib/ssl/src/ssl_alert.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -48,7 +48,9 @@ decode(Bin) ->
decode(Bin, [], 0).
%%--------------------------------------------------------------------
--spec reason_code(#alert{}, client | server) -> closed | {essl, string()}.
+%% -spec reason_code(#alert{}, client | server) ->
+%% {tls_alert, unicode:chardata()} | closed.
+%-spec reason_code(#alert{}, client | server) -> closed | {essl, string()}.
%%
%% Description: Returns the error reason that will be returned to the
%% user.
@@ -56,8 +58,10 @@ decode(Bin) ->
reason_code(#alert{description = ?CLOSE_NOTIFY}, _) ->
closed;
-reason_code(#alert{description = Description}, _) ->
- {tls_alert, string:casefold(description_txt(Description))}.
+reason_code(#alert{description = Description, role = Role} = Alert, Role) ->
+ {tls_alert, {description_atom(Description), own_alert_txt(Alert)}};
+reason_code(#alert{description = Description} = Alert, Role) ->
+ {tls_alert, {description_atom(Description), alert_txt(Alert#alert{role = Role})}}.
%%--------------------------------------------------------------------
-spec own_alert_txt(#alert{}) -> string().
@@ -157,10 +161,14 @@ description_txt(?INSUFFICIENT_SECURITY) ->
"Insufficient Security";
description_txt(?INTERNAL_ERROR) ->
"Internal Error";
+description_txt(?INAPPROPRIATE_FALLBACK) ->
+ "Inappropriate Fallback";
description_txt(?USER_CANCELED) ->
"User Canceled";
description_txt(?NO_RENEGOTIATION) ->
"No Renegotiation";
+description_txt(?MISSING_EXTENSION) ->
+ "Missing extension";
description_txt(?UNSUPPORTED_EXTENSION) ->
"Unsupported Extension";
description_txt(?CERTIFICATE_UNOBTAINABLE) ->
@@ -173,9 +181,80 @@ description_txt(?BAD_CERTIFICATE_HASH_VALUE) ->
"Bad Certificate Hash Value";
description_txt(?UNKNOWN_PSK_IDENTITY) ->
"Unknown Psk Identity";
-description_txt(?INAPPROPRIATE_FALLBACK) ->
- "Inappropriate Fallback";
+description_txt(?CERTIFICATE_REQUIRED) ->
+ "Certificate required";
description_txt(?NO_APPLICATION_PROTOCOL) ->
"No application protocol";
description_txt(Enum) ->
lists:flatten(io_lib:format("unsupported/unknown alert: ~p", [Enum])).
+
+description_atom(?CLOSE_NOTIFY) ->
+ close_notify;
+description_atom(?UNEXPECTED_MESSAGE) ->
+ unexpected_message;
+description_atom(?BAD_RECORD_MAC) ->
+ bad_record_mac;
+description_atom(?DECRYPTION_FAILED_RESERVED) ->
+ decryption_failed_reserved;
+description_atom(?RECORD_OVERFLOW) ->
+ record_overflow;
+description_atom(?DECOMPRESSION_FAILURE) ->
+ decompression_failure;
+description_atom(?HANDSHAKE_FAILURE) ->
+ handshake_failure;
+description_atom(?NO_CERTIFICATE_RESERVED) ->
+ no_certificate_reserved;
+description_atom(?BAD_CERTIFICATE) ->
+ bad_certificate;
+description_atom(?UNSUPPORTED_CERTIFICATE) ->
+ unsupported_certificate;
+description_atom(?CERTIFICATE_REVOKED) ->
+ certificate_revoked;
+description_atom(?CERTIFICATE_EXPIRED) ->
+ certificate_expired;
+description_atom(?CERTIFICATE_UNKNOWN) ->
+ certificate_unknown;
+description_atom(?ILLEGAL_PARAMETER) ->
+ illegal_parameter;
+description_atom(?UNKNOWN_CA) ->
+ unknown_ca;
+description_atom(?ACCESS_DENIED) ->
+ access_denied;
+description_atom(?DECODE_ERROR) ->
+ decode_error;
+description_atom(?DECRYPT_ERROR) ->
+ decrypt_error;
+description_atom(?EXPORT_RESTRICTION) ->
+ export_restriction;
+description_atom(?PROTOCOL_VERSION) ->
+ protocol_version;
+description_atom(?INSUFFICIENT_SECURITY) ->
+ insufficient_security;
+description_atom(?INTERNAL_ERROR) ->
+ internal_error;
+description_atom(?INAPPROPRIATE_FALLBACK) ->
+ inappropriate_fallback;
+description_atom(?USER_CANCELED) ->
+ user_canceled;
+description_atom(?NO_RENEGOTIATION) ->
+ no_renegotiation;
+description_atom(?MISSING_EXTENSION) ->
+ missing_extension;
+description_atom(?UNSUPPORTED_EXTENSION) ->
+ unsupported_extension;
+description_atom(?CERTIFICATE_UNOBTAINABLE) ->
+ certificate_unobtainable;
+description_atom(?UNRECOGNISED_NAME) ->
+ unrecognised_name;
+description_atom(?BAD_CERTIFICATE_STATUS_RESPONSE) ->
+ bad_certificate_status_response;
+description_atom(?BAD_CERTIFICATE_HASH_VALUE) ->
+ bad_certificate_hash_value;
+description_atom(?UNKNOWN_PSK_IDENTITY) ->
+ unknown_psk_identity;
+description_atom(?CERTIFICATE_REQUIRED) ->
+ certificate_required;
+description_atom(?NO_APPLICATION_PROTOCOL) ->
+ no_application_protocol;
+description_atom(_) ->
+ 'unsupported/unknown_alert'.
diff --git a/lib/ssl/src/ssl_alert.hrl b/lib/ssl/src/ssl_alert.hrl
index 35670edea5..9b2322da17 100644
--- a/lib/ssl/src/ssl_alert.hrl
+++ b/lib/ssl/src/ssl_alert.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,6 +29,9 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Alert protocol - RFC 2246 section 7.2
+%%% updated by RFC 8486 with
+%%% missing_extension(109),
+%%% certificate_required(116),
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% AlertLevel
@@ -100,12 +103,14 @@
-define(INAPPROPRIATE_FALLBACK, 86).
-define(USER_CANCELED, 90).
-define(NO_RENEGOTIATION, 100).
+-define(MISSING_EXTENSION, 109).
-define(UNSUPPORTED_EXTENSION, 110).
-define(CERTIFICATE_UNOBTAINABLE, 111).
-define(UNRECOGNISED_NAME, 112).
-define(BAD_CERTIFICATE_STATUS_RESPONSE, 113).
-define(BAD_CERTIFICATE_HASH_VALUE, 114).
-define(UNKNOWN_PSK_IDENTITY, 115).
+-define(CERTIFICATE_REQUIRED, 116).
-define(NO_APPLICATION_PROTOCOL, 120).
-define(ALERT_REC(Level,Desc), #alert{level=Level,description=Desc,where={?FILE, ?LINE}}).
diff --git a/lib/ssl/src/ssl_api.hrl b/lib/ssl/src/ssl_api.hrl
index 2bd51cf91e..f4594912bd 100644
--- a/lib/ssl/src/ssl_api.hrl
+++ b/lib/ssl/src/ssl_api.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,48 +21,7 @@
-ifndef(ssl_api).
-define(ssl_api, true).
--include("ssl_cipher.hrl").
-
-%% Visible in API
--export_type([connect_option/0, listen_option/0, ssl_option/0, transport_option/0,
- prf_random/0, sslsocket/0]).
-
-
%% Looks like it does for backwards compatibility reasons
-record(sslsocket, {fd = nil, pid = nil}).
-
--type sslsocket() :: #sslsocket{}.
--type connect_option() :: socket_connect_option() | ssl_option() | transport_option().
--type socket_connect_option() :: gen_tcp:connect_option().
--type listen_option() :: socket_listen_option() | ssl_option() | transport_option().
--type socket_listen_option() :: gen_tcp:listen_option().
-
--type ssl_option() :: {versions, ssl_record:ssl_atom_version()} |
- {verify, verify_type()} |
- {verify_fun, {fun(), InitialUserState::term()}} |
- {fail_if_no_peer_cert, boolean()} | {depth, integer()} |
- {cert, Der::binary()} | {certfile, path()} | {key, Der::binary()} |
- {keyfile, path()} | {password, string()} | {cacerts, [Der::binary()]} |
- {cacertfile, path()} | {dh, Der::binary()} | {dhfile, path()} |
- {user_lookup_fun, {fun(), InitialUserState::term()}} |
- {psk_identity, string()} |
- {srp_identity, {string(), string()}} |
- {ciphers, ciphers()} | {ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} |
- {reuse_session, fun()} | {hibernate_after, integer()|undefined} |
- {alpn_advertised_protocols, [binary()]} |
- {alpn_preferred_protocols, [binary()]} |
- {next_protocols_advertised, list(binary())} |
- {client_preferred_next_protocols, binary(), client | server, list(binary())}.
-
--type verify_type() :: verify_none | verify_peer.
--type path() :: string().
--type ciphers() :: [ssl_cipher:erl_cipher_suite()] |
- string(). % (according to old API)
--type ssl_imp() :: new | old.
-
--type transport_option() :: {cb_info, {CallbackModule::atom(), DataTag::atom(),
- ClosedTag::atom(), ErrTag::atom()}}.
--type prf_random() :: client_random | server_random.
-
-endif. % -ifdef(ssl_api).
diff --git a/lib/ssl/src/ssl_app.erl b/lib/ssl/src/ssl_app.erl
index 62e8765d4a..9e6d676bef 100644
--- a/lib/ssl/src/ssl_app.erl
+++ b/lib/ssl/src/ssl_app.erl
@@ -29,9 +29,26 @@
-export([start/2, stop/1]).
start(_Type, _StartArgs) ->
+ start_logger(),
ssl_sup:start_link().
stop(_State) ->
+ stop_logger(),
ok.
+%%
+%% Description: Start SSL logger
+start_logger() ->
+ Config = #{level => debug,
+ filter_default => stop,
+ formatter => {ssl_logger, #{}}},
+ Filter = {fun logger_filters:domain/2,{log,sub,[otp,ssl]}},
+ logger:add_handler(ssl_handler, logger_std_h, Config),
+ logger:add_handler_filter(ssl_handler, filter_non_ssl, Filter),
+ logger:set_application_level(ssl, debug).
+%%
+%% Description: Stop SSL logger
+stop_logger() ->
+ logger:unset_application_level(ssl),
+ logger:remove_handler(ssl_handler).
diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl
index a3333d35e9..9997f5e0c8 100644
--- a/lib/ssl/src/ssl_certificate.erl
+++ b/lib/ssl/src/ssl_certificate.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017 All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018 All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -33,6 +33,7 @@
-export([trusted_cert_and_path/4,
certificate_chain/3,
+ certificate_chain/4,
file_to_certificats/2,
file_to_crls/2,
validate/3,
@@ -40,7 +41,8 @@
is_valid_key_usage/2,
select_extension/2,
extensions_list/1,
- public_key_type/1
+ public_key_type/1,
+ foldl_db/3
]).
%%====================================================================
@@ -69,7 +71,7 @@ trusted_cert_and_path(CertChain, CertDbHandle, CertDbRef, PartialChainHandler) -
case SignedAndIssuerID of
{error, issuer_not_found} ->
- %% The root CA was not sent and can not be found.
+ %% The root CA was not sent and cannot be found.
handle_incomplete_chain(Path, PartialChainHandler);
{self, _} when length(Path) == 1 ->
{selfsigned_peer, Path};
@@ -79,7 +81,8 @@ trusted_cert_and_path(CertChain, CertDbHandle, CertDbRef, PartialChainHandler) -
%% Trusted must be selfsigned or it is an incomplete chain
handle_path(Trusted, Path, PartialChainHandler);
_ ->
- %% Root CA could not be verified
+ %% Root CA could not be verified, but partial
+ %% chain handler may trusted a cert that we got
handle_incomplete_chain(Path, PartialChainHandler)
end
end.
@@ -94,10 +97,23 @@ certificate_chain(undefined, _, _) ->
{error, no_cert};
certificate_chain(OwnCert, CertDbHandle, CertsDbRef) when is_binary(OwnCert) ->
ErlCert = public_key:pkix_decode_cert(OwnCert, otp),
- certificate_chain(ErlCert, OwnCert, CertDbHandle, CertsDbRef, [OwnCert]);
+ certificate_chain(ErlCert, OwnCert, CertDbHandle, CertsDbRef, [OwnCert], []);
certificate_chain(OwnCert, CertDbHandle, CertsDbRef) ->
DerCert = public_key:pkix_encode('OTPCertificate', OwnCert, otp),
- certificate_chain(OwnCert, DerCert, CertDbHandle, CertsDbRef, [DerCert]).
+ certificate_chain(OwnCert, DerCert, CertDbHandle, CertsDbRef, [DerCert], []).
+
+%%--------------------------------------------------------------------
+-spec certificate_chain(undefined | binary() | #'OTPCertificate'{} , db_handle(), certdb_ref(), [der_cert()]) ->
+ {error, no_cert} | {ok, #'OTPCertificate'{} | undefined, [der_cert()]}.
+%%
+%% Description: Create certificate chain with certs from
+%%--------------------------------------------------------------------
+certificate_chain(Cert, CertDbHandle, CertsDbRef, Candidates) when is_binary(Cert) ->
+ ErlCert = public_key:pkix_decode_cert(Cert, otp),
+ certificate_chain(ErlCert, Cert, CertDbHandle, CertsDbRef, [Cert], Candidates);
+certificate_chain(Cert, CertDbHandle, CertsDbRef, Candidates) ->
+ DerCert = public_key:pkix_encode('OTPCertificate', Cert, otp),
+ certificate_chain(Cert, DerCert, CertDbHandle, CertsDbRef, [DerCert], Candidates).
%%--------------------------------------------------------------------
-spec file_to_certificats(binary(), term()) -> [der_cert()].
%%
@@ -138,8 +154,8 @@ validate(_, {bad_cert, _} = Reason, _) ->
{fail, Reason};
validate(_, valid, UserState) ->
{valid, UserState};
-validate(Cert, valid_peer, UserState = {client, _,_, Hostname, _, _}) when Hostname =/= disable ->
- verify_hostname(Hostname, Cert, UserState);
+validate(Cert, valid_peer, UserState = {client, _,_, {Hostname, Customize}, _, _}) when Hostname =/= disable ->
+ verify_hostname(Hostname, Customize, Cert, UserState);
validate(_, valid_peer, UserState) ->
{valid, UserState}.
@@ -187,9 +203,20 @@ public_key_type(?'id-ecPublicKey') ->
ec.
%%--------------------------------------------------------------------
+-spec foldl_db(fun(), db_handle() | {extracted, list()}, list()) ->
+ {ok, term()} | issuer_not_found.
+%%
+%% Description:
+%%--------------------------------------------------------------------
+foldl_db(IsIssuerFun, CertDbHandle, []) ->
+ ssl_pkix_db:foldl(IsIssuerFun, issuer_not_found, CertDbHandle);
+foldl_db(IsIssuerFun, _, [_|_] = ListDb) ->
+ lists:foldl(IsIssuerFun, issuer_not_found, ListDb).
+
+%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-certificate_chain(OtpCert, BinCert, CertDbHandle, CertsDbRef, Chain) ->
+certificate_chain(OtpCert, BinCert, CertDbHandle, CertsDbRef, Chain, ListDb) ->
IssuerAndSelfSigned =
case public_key:pkix_is_self_signed(OtpCert) of
true ->
@@ -200,12 +227,12 @@ certificate_chain(OtpCert, BinCert, CertDbHandle, CertsDbRef, Chain) ->
case IssuerAndSelfSigned of
{_, true = SelfSigned} ->
- certificate_chain(CertDbHandle, CertsDbRef, Chain, ignore, ignore, SelfSigned);
+ do_certificate_chain(CertDbHandle, CertsDbRef, Chain, ignore, ignore, SelfSigned, ListDb);
{{error, issuer_not_found}, SelfSigned} ->
- case find_issuer(OtpCert, BinCert, CertDbHandle, CertsDbRef) of
+ case find_issuer(OtpCert, BinCert, CertDbHandle, CertsDbRef, ListDb) of
{ok, {SerialNr, Issuer}} ->
- certificate_chain(CertDbHandle, CertsDbRef, Chain,
- SerialNr, Issuer, SelfSigned);
+ do_certificate_chain(CertDbHandle, CertsDbRef, Chain,
+ SerialNr, Issuer, SelfSigned, ListDb);
_ ->
%% Guess the the issuer must be the root
%% certificate. The verification of the
@@ -214,19 +241,19 @@ certificate_chain(OtpCert, BinCert, CertDbHandle, CertsDbRef, Chain) ->
{ok, undefined, lists:reverse(Chain)}
end;
{{ok, {SerialNr, Issuer}}, SelfSigned} ->
- certificate_chain(CertDbHandle, CertsDbRef, Chain, SerialNr, Issuer, SelfSigned)
+ do_certificate_chain(CertDbHandle, CertsDbRef, Chain, SerialNr, Issuer, SelfSigned, ListDb)
end.
-certificate_chain(_, _, [RootCert | _] = Chain, _, _, true) ->
+do_certificate_chain(_, _, [RootCert | _] = Chain, _, _, true, _) ->
{ok, RootCert, lists:reverse(Chain)};
-certificate_chain(CertDbHandle, CertsDbRef, Chain, SerialNr, Issuer, _SelfSigned) ->
+do_certificate_chain(CertDbHandle, CertsDbRef, Chain, SerialNr, Issuer, _, ListDb) ->
case ssl_manager:lookup_trusted_cert(CertDbHandle, CertsDbRef,
SerialNr, Issuer) of
{ok, {IssuerCert, ErlCert}} ->
ErlCert = public_key:pkix_decode_cert(IssuerCert, otp),
certificate_chain(ErlCert, IssuerCert,
- CertDbHandle, CertsDbRef, [IssuerCert | Chain]);
+ CertDbHandle, CertsDbRef, [IssuerCert | Chain], ListDb);
_ ->
%% The trusted cert may be obmitted from the chain as the
%% counter part needs to have it anyway to be able to
@@ -234,7 +261,8 @@ certificate_chain(CertDbHandle, CertsDbRef, Chain, SerialNr, Issuer, _SelfSigned
{ok, undefined, lists:reverse(Chain)}
end.
-find_issuer(OtpCert, BinCert, CertDbHandle, CertsDbRef) ->
+
+find_issuer(OtpCert, BinCert, CertDbHandle, CertsDbRef, ListDb) ->
IsIssuerFun =
fun({_Key, {_Der, #'OTPCertificate'{} = ErlCertCandidate}}, Acc) ->
case public_key:pkix_is_issuer(OtpCert, ErlCertCandidate) of
@@ -252,26 +280,29 @@ find_issuer(OtpCert, BinCert, CertDbHandle, CertsDbRef) ->
Acc
end,
- if is_reference(CertsDbRef) -> % actual DB exists
- try ssl_pkix_db:foldl(IsIssuerFun, issuer_not_found, CertDbHandle) of
- issuer_not_found ->
- {error, issuer_not_found}
- catch
- {ok, _IssuerId} = Return ->
- Return
- end;
- is_tuple(CertsDbRef), element(1,CertsDbRef) =:= extracted -> % cache bypass byproduct
- {extracted, CertsData} = CertsDbRef,
- DB = [Entry || {decoded, Entry} <- CertsData],
- try lists:foldl(IsIssuerFun, issuer_not_found, DB) of
- issuer_not_found ->
- {error, issuer_not_found}
- catch
- {ok, _IssuerId} = Return ->
- Return
- end
+ Result = case is_reference(CertsDbRef) of
+ true ->
+ do_find_issuer(IsIssuerFun, CertDbHandle, ListDb);
+ false ->
+ {extracted, CertsData} = CertsDbRef,
+ DB = [Entry || {decoded, Entry} <- CertsData],
+ do_find_issuer(IsIssuerFun, CertDbHandle, DB)
+ end,
+ case Result of
+ issuer_not_found ->
+ {error, issuer_not_found};
+ Result ->
+ Result
end.
+do_find_issuer(IssuerFun, CertDbHandle, CertDb) ->
+ try
+ foldl_db(IssuerFun, CertDbHandle, CertDb)
+ catch
+ throw:{ok, _} = Return ->
+ Return
+ end.
+
is_valid_extkey_usage(KeyUse, client) ->
%% Client wants to verify server
is_valid_key_usage(KeyUse,?'id-kp-serverAuth');
@@ -300,7 +331,7 @@ other_issuer(OtpCert, BinCert, CertDbHandle, CertDbRef) ->
{ok, IssuerId} ->
{other, IssuerId};
{error, issuer_not_found} ->
- case find_issuer(OtpCert, BinCert, CertDbHandle, CertDbRef) of
+ case find_issuer(OtpCert, BinCert, CertDbHandle, CertDbRef, []) of
{ok, IssuerId} ->
{other, IssuerId};
Other ->
@@ -333,12 +364,12 @@ new_trusteded_chain(DerCert, [_ | Rest]) ->
new_trusteded_chain(_, []) ->
unknown_ca.
-verify_hostname({fallback, Hostname}, Cert, UserState) when is_list(Hostname) ->
- case public_key:pkix_verify_hostname(Cert, [{dns_id, Hostname}]) of
+verify_hostname({fallback, Hostname}, Customize, Cert, UserState) when is_list(Hostname) ->
+ case public_key:pkix_verify_hostname(Cert, [{dns_id, Hostname}], Customize) of
true ->
{valid, UserState};
false ->
- case public_key:pkix_verify_hostname(Cert, [{ip, Hostname}]) of
+ case public_key:pkix_verify_hostname(Cert, [{ip, Hostname}], Customize) of
true ->
{valid, UserState};
false ->
@@ -346,16 +377,16 @@ verify_hostname({fallback, Hostname}, Cert, UserState) when is_list(Hostname) ->
end
end;
-verify_hostname({fallback, Hostname}, Cert, UserState) ->
- case public_key:pkix_verify_hostname(Cert, [{ip, Hostname}]) of
+verify_hostname({fallback, Hostname}, Customize, Cert, UserState) ->
+ case public_key:pkix_verify_hostname(Cert, [{ip, Hostname}], Customize) of
true ->
{valid, UserState};
false ->
{fail, {bad_cert, hostname_check_failed}}
end;
-verify_hostname(Hostname, Cert, UserState) ->
- case public_key:pkix_verify_hostname(Cert, [{dns_id, Hostname}]) of
+verify_hostname(Hostname, Customize, Cert, UserState) ->
+ case public_key:pkix_verify_hostname(Cert, [{dns_id, Hostname}], Customize) of
true ->
{valid, UserState};
false ->
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index 62a172ca7c..21db887bb5 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -1,7 +1,7 @@
%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -31,44 +31,33 @@
-include("ssl_cipher.hrl").
-include("ssl_handshake.hrl").
-include("ssl_alert.hrl").
+-include("tls_handshake_1_3.hrl").
-include_lib("public_key/include/public_key.hrl").
--export([security_parameters/2, security_parameters/3, suite_definition/1,
- erl_suite_definition/1,
- cipher_init/3, decipher/6, cipher/5, decipher_aead/6, cipher_aead/6,
- suite/1, suites/1, all_suites/1, crypto_support_filters/0,
- ec_keyed_suites/0, anonymous_suites/1, psk_suites/1, psk_suites_anon/1, srp_suites/0,
- srp_suites_anon/0, rc4_suites/1, des_suites/1, openssl_suite/1, openssl_suite_name/1,
- filter/2, filter_suites/1, filter_suites/2,
+-export([security_parameters/2, security_parameters/3, security_parameters_1_3/2,
+ cipher_init/3, nonce_seed/2, decipher/6, cipher/5, aead_encrypt/6, aead_decrypt/6,
+ suites/1, all_suites/1, crypto_support_filters/0,
+ chacha_suites/1, anonymous_suites/1, psk_suites/1, psk_suites_anon/1,
+ srp_suites/0, srp_suites_anon/0,
+ rc4_suites/1, des_suites/1, rsa_suites/1,
+ filter/3, filter_suites/1, filter_suites/2,
hash_algorithm/1, sign_algorithm/1, is_acceptable_hash/2, is_fallback/1,
- random_bytes/1, calc_mac_hash/4,
- is_stream_ciphersuite/1]).
-
--export_type([cipher_suite/0,
- erl_cipher_suite/0, old_erl_cipher_suite/0, openssl_cipher_suite/0,
- hash/0, key_algo/0, sign_algo/0]).
-
--type cipher() :: null |rc4_128 | des_cbc | '3des_ede_cbc' | aes_128_cbc | aes_256_cbc | aes_128_gcm | aes_256_gcm | chacha20_poly1305.
--type hash() :: null | md5 | sha | sha224 | sha256 | sha384 | sha512.
--type sign_algo() :: rsa | dsa | ecdsa.
--type key_algo() :: null | rsa | dhe_rsa | dhe_dss | ecdhe_ecdsa| ecdh_ecdsa | ecdh_rsa| srp_rsa| srp_dss | psk | dhe_psk | rsa_psk | dh_anon | ecdh_anon | srp_anon.
--type erl_cipher_suite() :: #{key_exchange := key_algo(),
- cipher := cipher(),
- mac := hash() | aead,
- prf := hash() | default_prf %% Old cipher suites, version dependent
- }.
--type old_erl_cipher_suite() :: {key_algo(), cipher(), hash()} % Pre TLS 1.2
- %% TLS 1.2, internally PRE TLS 1.2 will use default_prf
- | {key_algo(), cipher(), hash(), hash() | default_prf}.
--type cipher_suite() :: binary().
--type cipher_enum() :: integer().
--type openssl_cipher_suite() :: string().
+ random_bytes/1, calc_mac_hash/4, calc_mac_hash/6,
+ is_stream_ciphersuite/1, signature_scheme/1,
+ scheme_to_components/1, hash_size/1, effective_key_bits/1,
+ key_material/1, signature_algorithm_to_scheme/1]).
+%% RFC 8446 TLS 1.3
+-export([generate_client_shares/1, generate_server_share/1, add_zero_padding/2]).
-compile(inline).
+-type cipher_enum() :: integer().
+
+-export_type([cipher_enum/0]).
+
%%--------------------------------------------------------------------
--spec security_parameters(cipher_suite(), #security_parameters{}) ->
+-spec security_parameters(ssl_cipher_format:cipher_suite(), #security_parameters{}) ->
#security_parameters{}.
%% Only security_parameters/2 should call security_parameters/3 with undefined as
%% first argument.
@@ -78,7 +67,8 @@ security_parameters(?TLS_NULL_WITH_NULL_NULL = CipherSuite, SecParams) ->
security_parameters(undefined, CipherSuite, SecParams).
%%--------------------------------------------------------------------
--spec security_parameters(ssl_record:ssl_version() | undefined, cipher_suite(), #security_parameters{}) ->
+-spec security_parameters(ssl_record:ssl_version() | undefined,
+ ssl_cipher_format:cipher_suite(), #security_parameters{}) ->
#security_parameters{}.
%%
%% Description: Returns a security parameters record where the
@@ -86,7 +76,7 @@ security_parameters(?TLS_NULL_WITH_NULL_NULL = CipherSuite, SecParams) ->
%%-------------------------------------------------------------------
security_parameters(Version, CipherSuite, SecParams) ->
#{cipher := Cipher, mac := Hash,
- prf := PrfHashAlg} = suite_definition(CipherSuite),
+ prf := PrfHashAlg} = ssl_cipher_format:suite_bin_to_map(CipherSuite),
SecParams#security_parameters{
cipher_suite = CipherSuite,
bulk_cipher_algorithm = bulk_cipher_algorithm(Cipher),
@@ -99,6 +89,15 @@ security_parameters(Version, CipherSuite, SecParams) ->
prf_algorithm = prf_algorithm(PrfHashAlg, Version),
hash_size = hash_size(Hash)}.
+security_parameters_1_3(SecParams, CipherSuite) ->
+ #{cipher := Cipher, prf := PrfHashAlg} =
+ ssl_cipher_format:suite_bin_to_map(CipherSuite),
+ SecParams#security_parameters{
+ cipher_suite = CipherSuite,
+ bulk_cipher_algorithm = bulk_cipher_algorithm(Cipher),
+ prf_algorithm = PrfHashAlg, %% HKDF hash algorithm
+ cipher_type = ?AEAD}.
+
%%--------------------------------------------------------------------
-spec cipher_init(cipher_enum(), binary(), binary()) -> #cipher_state{}.
%%
@@ -107,11 +106,21 @@ security_parameters(Version, CipherSuite, SecParams) ->
cipher_init(?RC4, IV, Key) ->
State = crypto:stream_init(rc4, Key),
#cipher_state{iv = IV, key = Key, state = State};
-cipher_init(?AES_GCM, IV, Key) ->
+cipher_init(Type, IV, Key) when Type == ?AES_GCM;
+ Type == ?AES_CCM ->
+ <<Nonce:64>> = random_bytes(8),
+ #cipher_state{iv = IV, key = Key, nonce = Nonce, tag_len = 16};
+cipher_init(?AES_CCM_8, IV, Key) ->
<<Nonce:64>> = random_bytes(8),
- #cipher_state{iv = IV, key = Key, nonce = Nonce};
+ #cipher_state{iv = IV, key = Key, nonce = Nonce, tag_len = 8};
+cipher_init(?CHACHA20_POLY1305, IV, Key) ->
+ #cipher_state{iv = IV, key = Key, tag_len = 16};
cipher_init(_BCA, IV, Key) ->
- #cipher_state{iv = IV, key = Key}.
+ %% Initialize random IV cache, not used for aead ciphers
+ #cipher_state{iv = IV, key = Key, state = <<>>}.
+
+nonce_seed(Seed, CipherState) ->
+ CipherState#cipher_state{nonce = Seed}.
%%--------------------------------------------------------------------
-spec cipher(cipher_enum(), #cipher_state{}, binary(), iodata(), ssl_record:ssl_version()) ->
@@ -123,12 +132,11 @@ cipher_init(_BCA, IV, Key) ->
%% data is calculated and the data plus the HMAC is ecncrypted.
%%-------------------------------------------------------------------
cipher(?NULL, CipherState, <<>>, Fragment, _Version) ->
- GenStreamCipherList = [Fragment, <<>>],
- {GenStreamCipherList, CipherState};
+ {iolist_to_binary(Fragment), CipherState};
cipher(?RC4, CipherState = #cipher_state{state = State0}, Mac, Fragment, _Version) ->
GenStreamCipherList = [Fragment, Mac],
{State1, T} = crypto:stream_encrypt(State0, GenStreamCipherList),
- {T, CipherState#cipher_state{state = State1}};
+ {iolist_to_binary(T), CipherState#cipher_state{state = State1}};
cipher(?DES, CipherState, Mac, Fragment, Version) ->
block_cipher(fun(Key, IV, T) ->
crypto:block_encrypt(des_cbc, Key, IV, T)
@@ -144,37 +152,24 @@ cipher(?AES_CBC, CipherState, Mac, Fragment, Version) ->
crypto:block_encrypt(aes_cbc256, Key, IV, T)
end, block_size(aes_128_cbc), CipherState, Mac, Fragment, Version).
-%%--------------------------------------------------------------------
--spec cipher_aead(cipher_enum(), #cipher_state{}, integer(), binary(), iodata(), ssl_record:ssl_version()) ->
- {binary(), #cipher_state{}}.
-%%
-%% Description: Encrypts the data and protects associated data (AAD) using chipher
-%% described by cipher_enum() and updating the cipher state
-%% Use for suites that use authenticated encryption with associated data (AEAD)
-%%-------------------------------------------------------------------
-cipher_aead(?AES_GCM, CipherState, SeqNo, AAD, Fragment, Version) ->
- aead_cipher(aes_gcm, CipherState, SeqNo, AAD, Fragment, Version);
-cipher_aead(?CHACHA20_POLY1305, CipherState, SeqNo, AAD, Fragment, Version) ->
- aead_cipher(chacha20_poly1305, CipherState, SeqNo, AAD, Fragment, Version).
-
-aead_cipher(chacha20_poly1305, #cipher_state{key=Key} = CipherState, SeqNo, AAD0, Fragment, _Version) ->
- CipherLen = erlang:iolist_size(Fragment),
- AAD = <<AAD0/binary, ?UINT16(CipherLen)>>,
- Nonce = ?uint64(SeqNo),
- {Content, CipherTag} = crypto:block_encrypt(chacha20_poly1305, Key, Nonce, {AAD, Fragment}),
- {<<Content/binary, CipherTag/binary>>, CipherState};
-aead_cipher(Type, #cipher_state{key=Key, iv = IV0, nonce = Nonce} = CipherState, _SeqNo, AAD0, Fragment, _Version) ->
- CipherLen = erlang:iolist_size(Fragment),
- AAD = <<AAD0/binary, ?UINT16(CipherLen)>>,
- <<Salt:4/bytes, _/binary>> = IV0,
- IV = <<Salt/binary, Nonce:64/integer>>,
- {Content, CipherTag} = crypto:block_encrypt(Type, Key, IV, {AAD, Fragment}),
- {<<Nonce:64/integer, Content/binary, CipherTag/binary>>, CipherState#cipher_state{nonce = Nonce + 1}}.
+aead_encrypt(Type, Key, Nonce, Fragment, AdditionalData, TagLen) ->
+ crypto:block_encrypt(aead_type(Type), Key, Nonce, {AdditionalData, Fragment, TagLen}).
+
+aead_decrypt(Type, Key, Nonce, CipherText, CipherTag, AdditionalData) ->
+ crypto:block_decrypt(aead_type(Type), Key, Nonce, {AdditionalData, CipherText, CipherTag}).
+
+aead_type(?AES_GCM) ->
+ aes_gcm;
+aead_type(?AES_CCM) ->
+ aes_ccm;
+aead_type(?AES_CCM_8) ->
+ aes_ccm;
+aead_type(?CHACHA20_POLY1305) ->
+ chacha20_poly1305.
build_cipher_block(BlockSz, Mac, Fragment) ->
TotSz = byte_size(Mac) + erlang:iolist_size(Fragment) + 1,
- {PaddingLength, Padding} = get_padding(TotSz, BlockSz),
- [Fragment, Mac, PaddingLength, Padding].
+ [Fragment, Mac, padding_with_len(TotSz, BlockSz)].
block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0,
Mac, Fragment, {3, N})
@@ -184,14 +179,21 @@ block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0,
NextIV = next_iv(T, IV),
{T, CS0#cipher_state{iv=NextIV}};
-block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0,
+block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV, state = IV_Cache0} = CS0,
Mac, Fragment, {3, N})
- when N == 2; N == 3 ->
- NextIV = random_iv(IV),
+ when N == 2; N == 3; N == 4 ->
+ IV_Size = byte_size(IV),
+ <<NextIV:IV_Size/binary, IV_Cache/binary>> =
+ case IV_Cache0 of
+ <<>> ->
+ random_bytes(IV_Size bsl 5); % 32 IVs
+ _ ->
+ IV_Cache0
+ end,
L0 = build_cipher_block(BlockSz, Mac, Fragment),
L = [NextIV|L0],
T = Fun(Key, IV, L),
- {T, CS0#cipher_state{iv=NextIV}}.
+ {T, CS0#cipher_state{iv=NextIV, state = IV_Cache}}.
%%--------------------------------------------------------------------
-spec decipher(cipher_enum(), integer(), #cipher_state{}, binary(),
@@ -236,19 +238,6 @@ decipher(?AES_CBC, HashSz, CipherState, Fragment, Version, PaddingCheck) ->
crypto:block_decrypt(aes_cbc256, Key, IV, T)
end, CipherState, HashSz, Fragment, Version, PaddingCheck).
-%%--------------------------------------------------------------------
--spec decipher_aead(cipher_enum(), #cipher_state{}, integer(), binary(), binary(), ssl_record:ssl_version()) ->
- {binary(), binary(), #cipher_state{}} | #alert{}.
-%%
-%% Description: Decrypts the data and checks the associated data (AAD) MAC using
-%% cipher described by cipher_enum() and updating the cipher state.
-%% Use for suites that use authenticated encryption with associated data (AEAD)
-%%-------------------------------------------------------------------
-decipher_aead(?AES_GCM, CipherState, SeqNo, AAD, Fragment, Version) ->
- aead_decipher(aes_gcm, CipherState, SeqNo, AAD, Fragment, Version);
-decipher_aead(?CHACHA20_POLY1305, CipherState, SeqNo, AAD, Fragment, Version) ->
- aead_decipher(chacha20_poly1305, CipherState, SeqNo, AAD, Fragment, Version).
-
block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0,
HashSz, Fragment, Version, PaddingCheck) ->
try
@@ -279,36 +268,8 @@ block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0,
?ALERT_REC(?FATAL, ?BAD_RECORD_MAC, decryption_failed)
end.
-aead_ciphertext_to_state(chacha20_poly1305, SeqNo, _IV, AAD0, Fragment, _Version) ->
- CipherLen = size(Fragment) - 16,
- <<CipherText:CipherLen/bytes, CipherTag:16/bytes>> = Fragment,
- AAD = <<AAD0/binary, ?UINT16(CipherLen)>>,
- Nonce = ?uint64(SeqNo),
- {Nonce, AAD, CipherText, CipherTag};
-aead_ciphertext_to_state(_, _SeqNo, <<Salt:4/bytes, _/binary>>, AAD0, Fragment, _Version) ->
- CipherLen = size(Fragment) - 24,
- <<ExplicitNonce:8/bytes, CipherText:CipherLen/bytes, CipherTag:16/bytes>> = Fragment,
- AAD = <<AAD0/binary, ?UINT16(CipherLen)>>,
- Nonce = <<Salt/binary, ExplicitNonce/binary>>,
- {Nonce, AAD, CipherText, CipherTag}.
-
-aead_decipher(Type, #cipher_state{key = Key, iv = IV} = CipherState,
- SeqNo, AAD0, Fragment, Version) ->
- try
- {Nonce, AAD, CipherText, CipherTag} = aead_ciphertext_to_state(Type, SeqNo, IV, AAD0, Fragment, Version),
- case crypto:block_decrypt(Type, Key, Nonce, {AAD, CipherText, CipherTag}) of
- Content when is_binary(Content) ->
- {Content, CipherState};
- _ ->
- ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC, decryption_failed)
- end
- catch
- _:_ ->
- ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC, decryption_failed)
- end.
-
%%--------------------------------------------------------------------
--spec suites(ssl_record:ssl_version()) -> [cipher_suite()].
+-spec suites(ssl_record:ssl_version()) -> [ssl_cipher_format:cipher_suite()].
%%
%% Description: Returns a list of supported cipher suites.
%%--------------------------------------------------------------------
@@ -321,26 +282,44 @@ suites({_, Minor}) ->
all_suites({3, _} = Version) ->
suites(Version)
+ ++ chacha_suites(Version)
++ psk_suites(Version)
++ srp_suites()
++ rc4_suites(Version)
- ++ des_suites(Version);
+ ++ des_suites(Version)
+ ++ rsa_suites(Version);
+
all_suites(Version) ->
dtls_v1:all_suites(Version).
+%%--------------------------------------------------------------------
+-spec chacha_suites(ssl_record:ssl_version() | integer()) ->
+ [ssl_cipher_format:cipher_suite()].
+%%
+%% Description: Returns list of the chacha cipher suites, only supported
+%% if explicitly set by user for now due to interop problems, proably need
+%% to be fixed in crypto.
+%%--------------------------------------------------------------------
+chacha_suites({3, _}) ->
+ [?TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
+ ?TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+ ?TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256];
+chacha_suites(_) ->
+ [].
%%--------------------------------------------------------------------
--spec anonymous_suites(ssl_record:ssl_version() | integer()) -> [cipher_suite()].
+-spec anonymous_suites(ssl_record:ssl_version() | integer()) ->
+ [ssl_cipher_format:cipher_suite()].
%%
%% Description: Returns a list of the anonymous cipher suites, only supported
%% if explicitly set by user. Intended only for testing.
%%--------------------------------------------------------------------
-
anonymous_suites({3, N}) ->
srp_suites_anon() ++ anonymous_suites(N);
anonymous_suites({254, _} = Version) ->
dtls_v1:anonymous_suites(Version);
-anonymous_suites(N)
- when N >= 3 ->
+anonymous_suites(4) ->
+ []; %% Raw public key negotiation may be used instead
+anonymous_suites( 3 = N) ->
psk_suites_anon(N) ++
[?TLS_DH_anon_WITH_AES_128_GCM_SHA256,
?TLS_DH_anon_WITH_AES_256_GCM_SHA384,
@@ -366,15 +345,16 @@ anonymous_suites(N) when N == 0;
].
%%--------------------------------------------------------------------
--spec psk_suites(ssl_record:ssl_version() | integer()) -> [cipher_suite()].
+-spec psk_suites(ssl_record:ssl_version() | integer()) -> [ssl_cipher_format:cipher_suite()].
%%
%% Description: Returns a list of the PSK cipher suites, only supported
%% if explicitly set by user.
%%--------------------------------------------------------------------
psk_suites({3, N}) ->
psk_suites(N);
-psk_suites(N)
- when N >= 3 ->
+psk_suites(4) ->
+ []; %% TODO Add new PSK, PSK_(EC)DHE suites
+psk_suites(3) ->
[
?TLS_RSA_PSK_WITH_AES_256_GCM_SHA384,
?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384,
@@ -388,36 +368,54 @@ psk_suites(_) ->
?TLS_RSA_PSK_WITH_RC4_128_SHA].
%%--------------------------------------------------------------------
--spec psk_suites_anon(ssl_record:ssl_version() | integer()) -> [cipher_suite()].
+-spec psk_suites_anon(ssl_record:ssl_version() | integer()) -> [ssl_cipher_format:cipher_suite()].
%%
%% Description: Returns a list of the anonymous PSK cipher suites, only supported
%% if explicitly set by user.
%%--------------------------------------------------------------------
psk_suites_anon({3, N}) ->
psk_suites_anon(N);
-psk_suites_anon(N)
- when N >= 3 ->
+psk_suites_anon(3) ->
[
?TLS_DHE_PSK_WITH_AES_256_GCM_SHA384,
?TLS_PSK_WITH_AES_256_GCM_SHA384,
+ ?TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384,
?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384,
?TLS_PSK_WITH_AES_256_CBC_SHA384,
+ ?TLS_DHE_PSK_WITH_AES_256_CCM,
+ ?TLS_PSK_DHE_WITH_AES_256_CCM_8,
+ ?TLS_PSK_WITH_AES_256_CCM,
+ ?TLS_PSK_WITH_AES_256_CCM_8,
+ ?TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256,
+ ?TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256,
+ ?TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256,
?TLS_DHE_PSK_WITH_AES_128_GCM_SHA256,
?TLS_PSK_WITH_AES_128_GCM_SHA256,
+ ?TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256,
+ ?TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256,
+ ?TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,
- ?TLS_PSK_WITH_AES_128_CBC_SHA256
+ ?TLS_PSK_WITH_AES_128_CBC_SHA256,
+ ?TLS_DHE_PSK_WITH_AES_128_CCM,
+ ?TLS_PSK_DHE_WITH_AES_128_CCM_8,
+ ?TLS_PSK_WITH_AES_128_CCM,
+ ?TLS_PSK_WITH_AES_128_CCM_8,
+ ?TLS_ECDHE_PSK_WITH_RC4_128_SHA
] ++ psk_suites_anon(0);
psk_suites_anon(_) ->
[?TLS_DHE_PSK_WITH_AES_256_CBC_SHA,
?TLS_PSK_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA,
?TLS_DHE_PSK_WITH_AES_128_CBC_SHA,
?TLS_PSK_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA,
?TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
?TLS_PSK_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDHE_PSK_WITH_RC4_128_SHA,
?TLS_DHE_PSK_WITH_RC4_128_SHA,
?TLS_PSK_WITH_RC4_128_SHA].
%%--------------------------------------------------------------------
--spec srp_suites() -> [cipher_suite()].
+-spec srp_suites() -> [ssl_cipher_format:cipher_suite()].
%%
%% Description: Returns a list of the SRP cipher suites, only supported
%% if explicitly set by user.
@@ -431,7 +429,7 @@ srp_suites() ->
?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA].
%%--------------------------------------------------------------------
--spec srp_suites_anon() -> [cipher_suite()].
+-spec srp_suites_anon() -> [ssl_cipher_format:cipher_suite()].
%%
%% Description: Returns a list of the SRP anonymous cipher suites, only supported
%% if explicitly set by user.
@@ -442,7 +440,8 @@ srp_suites_anon() ->
?TLS_SRP_SHA_WITH_AES_256_CBC_SHA].
%%--------------------------------------------------------------------
--spec rc4_suites(Version::ssl_record:ssl_version() | integer()) -> [cipher_suite()].
+-spec rc4_suites(Version::ssl_record:ssl_version() | integer()) ->
+ [ssl_cipher_format:cipher_suite()].
%%
%% Description: Returns a list of the RSA|(ECDH/RSA)| (ECDH/ECDSA)
%% with RC4 cipher suites, only supported if explicitly set by user.
@@ -456,13 +455,14 @@ rc4_suites({3, Minor}) ->
rc4_suites(0) ->
[?TLS_RSA_WITH_RC4_128_SHA,
?TLS_RSA_WITH_RC4_128_MD5];
-rc4_suites(N) when N =< 3 ->
+rc4_suites(N) when N =< 4 ->
[?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
?TLS_ECDHE_RSA_WITH_RC4_128_SHA,
?TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
?TLS_ECDH_RSA_WITH_RC4_128_SHA].
+
%%--------------------------------------------------------------------
--spec des_suites(Version::ssl_record:ssl_version()) -> [cipher_suite()].
+-spec des_suites(Version::ssl_record:ssl_version()) -> [ssl_cipher_format:cipher_suite()].
%%
%% Description: Returns a list of the cipher suites
%% with DES cipher, only supported if explicitly set by user.
@@ -470,1588 +470,63 @@ rc4_suites(N) when N =< 3 ->
%%--------------------------------------------------------------------
des_suites(_)->
[?TLS_DHE_RSA_WITH_DES_CBC_SHA,
- ?TLS_RSA_WITH_DES_CBC_SHA].
-
-%%--------------------------------------------------------------------
--spec suite_definition(cipher_suite()) -> erl_cipher_suite().
-%%
-%% Description: Return erlang cipher suite definition.
-%% Note: Currently not supported suites are commented away.
-%% They should be supported or removed in the future.
-%%-------------------------------------------------------------------
-%% TLS v1.1 suites
-suite_definition(?TLS_NULL_WITH_NULL_NULL) ->
- #{key_exchange => null,
- cipher => null,
- mac => null,
- prf => null};
-%% RFC 5746 - Not a real cipher suite used to signal empty "renegotiation_info" extension
-%% to avoid handshake failure from old servers that do not ignore
-%% hello extension data as they should.
-suite_definition(?TLS_EMPTY_RENEGOTIATION_INFO_SCSV) ->
- #{key_exchange => null,
- cipher => null,
- mac => null,
- prf => null};
-suite_definition(?TLS_RSA_WITH_RC4_128_MD5) ->
- #{key_exchange => rsa,
- cipher => rc4_128,
- mac => md5,
- prf => default_prf};
-suite_definition(?TLS_RSA_WITH_RC4_128_SHA) ->
- #{key_exchange => rsa,
- cipher => rc4_128,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_RSA_WITH_DES_CBC_SHA) ->
- #{key_exchange => rsa,
- cipher => des_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_RSA_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => rsa,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DHE_DSS_WITH_DES_CBC_SHA) ->
- #{key_exchange => dhe_dss,
- cipher => des_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => dhe_dss,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DHE_RSA_WITH_DES_CBC_SHA) ->
- #{key_exchange => dhe_rsa,
- cipher => des_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => dhe_rsa,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-%%% TSL V1.1 AES suites
-suite_definition(?TLS_RSA_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => rsa,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DHE_DSS_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => dhe_dss,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DHE_RSA_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => dhe_rsa,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_RSA_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => rsa,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => dhe_dss,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => dhe_rsa,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-%% TLS v1.2 suites
-%% suite_definition(?TLS_RSA_WITH_NULL_SHA) ->
-%% {rsa, null, sha, default_prf};
-suite_definition(?TLS_RSA_WITH_AES_128_CBC_SHA256) ->
- #{key_exchange => rsa,
- cipher => aes_128_cbc,
- mac => sha256,
- prf => default_prf};
-suite_definition(?TLS_RSA_WITH_AES_256_CBC_SHA256) ->
- #{key_exchange => rsa,
- cipher => aes_256_cbc,
- mac => sha256,
- prf => default_prf};
-suite_definition(?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256) ->
- #{key_exchange => dhe_dss,
- cipher => aes_128_cbc,
- mac => sha256,
- prf => default_prf};
-suite_definition(?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256) ->
- #{key_exchange => dhe_rsa,
- cipher => aes_128_cbc,
- mac => sha256,
- prf => default_prf};
-suite_definition(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256) ->
- #{key_exchange => dhe_dss,
- cipher => aes_256_cbc,
- mac => sha256,
- prf => default_prf};
-suite_definition(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256) ->
- #{key_exchange => dhe_rsa,
- cipher => aes_256_cbc,
- mac => sha256,
- prf => default_prf};
-%% not defined YET:
-%% TLS_DH_DSS_WITH_AES_128_CBC_SHA256 DH_DSS AES_128_CBC SHA256
-%% TLS_DH_RSA_WITH_AES_128_CBC_SHA256 DH_RSA AES_128_CBC SHA256
-%% TLS_DH_DSS_WITH_AES_256_CBC_SHA256 DH_DSS AES_256_CBC SHA256
-%% TLS_DH_RSA_WITH_AES_256_CBC_SHA256 DH_RSA AES_256_CBC SHA256
-%%% DH-ANON deprecated by TLS spec and not available
-%%% by default, but good for testing purposes.
-suite_definition(?TLS_DH_anon_WITH_RC4_128_MD5) ->
- #{key_exchange => dh_anon,
- cipher => rc4_128,
- mac => md5,
- prf => default_prf};
-suite_definition(?TLS_DH_anon_WITH_DES_CBC_SHA) ->
- #{key_exchange => dh_anon,
- cipher => des_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => dh_anon,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DH_anon_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => dh_anon,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DH_anon_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => dh_anon,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DH_anon_WITH_AES_128_CBC_SHA256) ->
- #{key_exchange => dh_anon,
- cipher => aes_128_cbc,
- mac => sha256,
- prf => default_prf};
-suite_definition(?TLS_DH_anon_WITH_AES_256_CBC_SHA256) ->
- #{key_exchange => dh_anon,
- cipher => aes_256_cbc,
- mac => sha256,
- prf => default_prf};
-%%% PSK Cipher Suites RFC 4279
-suite_definition(?TLS_PSK_WITH_RC4_128_SHA) ->
- #{key_exchange => psk,
- cipher => rc4_128,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_PSK_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => psk,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_PSK_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => psk,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_PSK_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => psk,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DHE_PSK_WITH_RC4_128_SHA) ->
- #{key_exchange => dhe_psk,
- cipher => rc4_128,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => dhe_psk,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DHE_PSK_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => dhe_psk,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DHE_PSK_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => dhe_psk,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_RSA_PSK_WITH_RC4_128_SHA) ->
- #{key_exchange => rsa_psk,
- cipher => rc4_128,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => rsa_psk,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_RSA_PSK_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => rsa_psk,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_RSA_PSK_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => rsa_psk,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-%%% TLS 1.2 PSK Cipher Suites RFC 5487
-suite_definition(?TLS_PSK_WITH_AES_128_GCM_SHA256) ->
- #{key_exchange => psk,
- cipher => aes_128_gcm,
- mac => aead,
- prf => sha256};
-suite_definition(?TLS_PSK_WITH_AES_256_GCM_SHA384) ->
- #{key_exchange => psk,
- cipher => aes_256_gcm,
- mac => aead,
- prf => sha384};
-suite_definition(?TLS_DHE_PSK_WITH_AES_128_GCM_SHA256) ->
- #{key_exchange => dhe_psk,
- cipher => aes_128_gcm,
- mac => aead,
- prf => sha256};
-suite_definition(?TLS_DHE_PSK_WITH_AES_256_GCM_SHA384) ->
- #{key_exchange => dhe_psk,
- cipher => aes_256_gcm,
- mac => aead,
- prf => sha384};
-suite_definition(?TLS_RSA_PSK_WITH_AES_128_GCM_SHA256) ->
- #{key_exchange => rsa_psk,
- cipher => aes_128_gcm,
- mac => aead,
- prf => sha256};
-suite_definition(?TLS_RSA_PSK_WITH_AES_256_GCM_SHA384) ->
- #{key_exchange => rsa_psk,
- cipher => aes_256_gcm,
- mac => aead,
- prf => sha384};
-suite_definition(?TLS_PSK_WITH_AES_128_CBC_SHA256) ->
- #{key_exchange => psk,
- cipher => aes_128_cbc,
- mac => sha256,
- prf => default_prf};
-suite_definition(?TLS_PSK_WITH_AES_256_CBC_SHA384) ->
- #{key_exchange => psk,
- cipher => aes_256_cbc,
- mac => sha384,
- prf => default_prf};
-suite_definition(?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256) ->
- #{key_exchange => dhe_psk,
- cipher => aes_128_cbc,
- mac => sha256,
- prf => default_prf};
-suite_definition(?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384) ->
- #{key_exchange => dhe_psk,
- cipher => aes_256_cbc,
- mac => sha384,
- prf => default_prf};
-suite_definition(?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256) ->
- #{key_exchange => rsa_psk,
- cipher => aes_128_cbc,
- mac => sha256,
- prf => default_prf};
-suite_definition(?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384) ->
- #{key_exchange => rsa_psk,
- cipher => aes_256_cbc,
- mac => sha384,
- prf => default_prf};
-suite_definition(?TLS_PSK_WITH_NULL_SHA256) ->
- #{key_exchange => psk,
- cipher => null,
- mac => sha256,
- prf => default_prf};
-suite_definition(?TLS_PSK_WITH_NULL_SHA384) ->
- #{key_exchange => psk,
- cipher => null,
- mac => sha384,
- prf => default_prf};
-suite_definition(?TLS_DHE_PSK_WITH_NULL_SHA256) ->
- #{key_exchange => dhe_psk,
- cipher => null,
- mac => sha256,
- prf => default_prf};
-suite_definition(?TLS_DHE_PSK_WITH_NULL_SHA384) ->
- #{key_exchange => dhe_psk,
- cipher => null,
- mac => sha384,
- prf => default_prf};
-suite_definition(?TLS_RSA_PSK_WITH_NULL_SHA256) ->
- #{key_exchange => rsa_psk,
- cipher => null,
- mac => sha256,
- prf => default_prf};
-suite_definition(?TLS_RSA_PSK_WITH_NULL_SHA384) ->
- #{key_exchange => rsa_psk,
- cipher => null,
- mac => sha384,
- prf => default_prf};
-%%% SRP Cipher Suites RFC 5054
-suite_definition(?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => srp_anon,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => srp_rsa,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => srp_dss,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_SRP_SHA_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => srp_anon,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => srp_rsa,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => srp_dss,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_SRP_SHA_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => srp_anon,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => srp_rsa,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => srp_dss,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-%% RFC 4492 EC TLS suites
-suite_definition(?TLS_ECDH_ECDSA_WITH_NULL_SHA) ->
- #{key_exchange => ecdh_ecdsa,
- cipher => null,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDH_ECDSA_WITH_RC4_128_SHA) ->
- #{key_exchange => ecdh_ecdsa,
- cipher => rc4_128,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => ecdh_ecdsa,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => ecdh_ecdsa,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => ecdh_ecdsa,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDHE_ECDSA_WITH_NULL_SHA) ->
- #{key_exchange => ecdhe_ecdsa,
- cipher => null,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA) ->
- #{key_exchange => ecdhe_ecdsa,
- cipher => rc4_128,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => ecdhe_ecdsa,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => ecdhe_ecdsa,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => ecdhe_ecdsa,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDH_RSA_WITH_NULL_SHA) ->
- #{key_exchange => ecdh_rsa,
- cipher => null,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDH_RSA_WITH_RC4_128_SHA) ->
- #{key_exchange => ecdh_rsa,
- cipher => rc4_128,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => ecdh_rsa,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => ecdh_rsa,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => ecdh_rsa,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDHE_RSA_WITH_NULL_SHA) ->
- #{key_exchange => ecdhe_rsa,
- cipher => null,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDHE_RSA_WITH_RC4_128_SHA) ->
- #{key_exchange => ecdhe_rsa,
- cipher => rc4_128,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => ecdhe_rsa,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => ecdhe_rsa,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => ecdhe_rsa,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDH_anon_WITH_NULL_SHA) ->
- #{key_exchange => ecdh_anon,
- cipher => null,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDH_anon_WITH_RC4_128_SHA) ->
- #{key_exchange => ecdh_anon,
- cipher => rc4_128,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => ecdh_anon,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDH_anon_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => ecdh_anon,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDH_anon_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => ecdh_anon,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-%% RFC 5289 EC TLS suites
-suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) ->
- #{key_exchange => ecdhe_ecdsa,
- cipher => aes_128_cbc,
- mac => sha256,
- prf => sha256};
-suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384) ->
- #{key_exchange => ecdhe_ecdsa,
- cipher => aes_256_cbc,
- mac => sha384,
- prf => sha384};
-suite_definition(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256) ->
- #{key_exchange => ecdh_ecdsa,
- cipher => aes_128_cbc,
- mac => sha256,
- prf => sha256};
-suite_definition(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384) ->
- #{key_exchange => ecdh_ecdsa,
- cipher => aes_256_cbc,
- mac => sha384,
- prf => sha384};
-suite_definition(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) ->
- #{key_exchange => ecdhe_rsa,
- cipher => aes_128_cbc,
- mac => sha256,
- prf => sha256};
-suite_definition(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) ->
- #{key_exchange => ecdhe_rsa,
- cipher => aes_256_cbc,
- mac => sha384,
- prf => sha384};
-suite_definition(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256) ->
- #{key_exchange => ecdh_rsa,
- cipher => aes_128_cbc,
- mac => sha256,
- prf => sha256};
-suite_definition(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384) ->
- #{key_exchange => ecdh_rsa,
- cipher => aes_256_cbc,
- mac => sha384,
- prf => sha384};
-%% RFC 5288 AES-GCM Cipher Suites
-suite_definition(?TLS_RSA_WITH_AES_128_GCM_SHA256) ->
- #{key_exchange => rsa,
- cipher => aes_128_gcm,
- mac => aead,
- prf => sha256};
-suite_definition(?TLS_RSA_WITH_AES_256_GCM_SHA384) ->
- #{key_exchange => rsa,
- cipher => aes_256_gcm,
- mac => aead,
- prf => sha384};
-suite_definition(?TLS_DHE_RSA_WITH_AES_128_GCM_SHA256) ->
- #{key_exchange => dhe_rsa,
- cipher => aes_128_gcm,
- mac => aead,
- prf => sha256};
-suite_definition(?TLS_DHE_RSA_WITH_AES_256_GCM_SHA384) ->
- #{key_exchange => dhe_rsa,
- cipher => aes_256_gcm,
- mac => aead,
- prf => sha384};
-suite_definition(?TLS_DH_RSA_WITH_AES_128_GCM_SHA256) ->
- #{key_exchange => dh_rsa,
- cipher => aes_128_gcm,
- mac => aead,
- prf => sha256};
-suite_definition(?TLS_DH_RSA_WITH_AES_256_GCM_SHA384) ->
- #{key_exchange => dh_rsa,
- cipher => aes_256_gcm,
- mac => aead,
- prf => sha384};
-suite_definition(?TLS_DHE_DSS_WITH_AES_128_GCM_SHA256) ->
- #{key_exchange => dhe_dss,
- cipher => aes_128_gcm,
- mac => aead,
- prf => sha256};
-suite_definition(?TLS_DHE_DSS_WITH_AES_256_GCM_SHA384) ->
- #{key_exchange => dhe_dss,
- cipher => aes_256_gcm,
- mac => aead,
- prf => sha384};
-suite_definition(?TLS_DH_DSS_WITH_AES_128_GCM_SHA256) ->
- #{key_exchange => dh_dss,
- cipher => aes_128_gcm,
- mac => null,
- prf => sha256};
-suite_definition(?TLS_DH_DSS_WITH_AES_256_GCM_SHA384) ->
- #{key_exchange => dh_dss,
- cipher => aes_256_gcm,
- mac => aead,
- prf => sha384};
-suite_definition(?TLS_DH_anon_WITH_AES_128_GCM_SHA256) ->
- #{key_exchange => dh_anon,
- cipher => aes_128_gcm,
- mac => aead,
- prf => sha256};
-suite_definition(?TLS_DH_anon_WITH_AES_256_GCM_SHA384) ->
- #{key_exchange => dh_anon,
- cipher => aes_256_gcm,
- mac => aead,
- prf => sha384};
-%% RFC 5289 ECC AES-GCM Cipher Suites
-suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) ->
- #{key_exchange => ecdhe_ecdsa,
- cipher => aes_128_gcm,
- mac => aead,
- prf => sha256};
-suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384) ->
- #{key_exchange => ecdhe_ecdsa,
- cipher => aes_256_gcm,
- mac => aead,
- prf => sha384};
-suite_definition(?TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256) ->
- #{key_exchange => ecdh_ecdsa,
- cipher => aes_128_gcm,
- mac => aead,
- prf => sha256};
-suite_definition(?TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384) ->
- #{key_exchange => ecdh_ecdsa,
- cipher => aes_256_gcm,
- mac => aead,
- prf => sha384};
-suite_definition(?TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) ->
- #{key_exchange => ecdhe_rsa,
- cipher => aes_128_gcm,
- mac => aead,
- prf => sha256};
-suite_definition(?TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) ->
- #{key_exchange => ecdhe_rsa,
- cipher => aes_256_gcm,
- mac => aead,
- prf => sha384};
-suite_definition(?TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256) ->
- #{key_exchange => ecdh_rsa,
- cipher => aes_128_gcm,
- mac => aead,
- prf => sha256};
-suite_definition(?TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384) ->
- #{key_exchange => ecdh_rsa,
- cipher => aes_256_gcm,
- mac => aead,
- prf => sha384};
-%% draft-agl-tls-chacha20poly1305-04 Chacha20/Poly1305 Suites
-suite_definition(?TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256) ->
- #{key_exchange => ecdhe_rsa,
- cipher => chacha20_poly1305,
- mac => aead,
- prf => sha256};
-suite_definition(?TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256) ->
- #{key_exchange => ecdhe_ecdsa,
- cipher => chacha20_poly1305,
- mac => aead,
- prf => sha256};
-suite_definition(?TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256) ->
- #{key_exchange => dhe_rsa,
- cipher => chacha20_poly1305,
- mac => aead,
- prf => sha256}.
-
-%%--------------------------------------------------------------------
--spec erl_suite_definition(cipher_suite() | erl_cipher_suite()) -> old_erl_cipher_suite().
-%%
-%% Description: Return erlang cipher suite definition. Filters last value
-%% for now (compatibility reasons).
-%%--------------------------------------------------------------------
-erl_suite_definition(Bin) when is_binary(Bin) ->
- erl_suite_definition(suite_definition(Bin));
-erl_suite_definition(#{key_exchange := KeyExchange, cipher := Cipher,
- mac := Hash, prf := Prf}) ->
- case Prf of
- default_prf ->
- {KeyExchange, Cipher, Hash};
- _ ->
- {KeyExchange, Cipher, Hash, Prf}
- end.
-
-%%--------------------------------------------------------------------
--spec suite(erl_cipher_suite()) -> cipher_suite().
-%%
-%% Description: Return TLS cipher suite definition.
-%%--------------------------------------------------------------------
-%% TLS v1.1 suites
-suite(#{key_exchange := rsa,
- cipher := rc4_128,
- mac := md5}) ->
- ?TLS_RSA_WITH_RC4_128_MD5;
-suite(#{key_exchange := rsa,
- cipher := rc4_128,
- mac := sha}) ->
- ?TLS_RSA_WITH_RC4_128_SHA;
-suite(#{key_exchange := rsa,
- cipher := des_cbc,
- mac := sha}) ->
- ?TLS_RSA_WITH_DES_CBC_SHA;
-suite(#{key_exchange := rsa,
- cipher :='3des_ede_cbc',
- mac := sha}) ->
- ?TLS_RSA_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := dhe_dss,
- cipher:= des_cbc,
- mac := sha}) ->
- ?TLS_DHE_DSS_WITH_DES_CBC_SHA;
-suite(#{key_exchange := dhe_dss,
- cipher:= '3des_ede_cbc',
- mac := sha}) ->
- ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := dhe_rsa,
- cipher:= des_cbc,
- mac := sha}) ->
- ?TLS_DHE_RSA_WITH_DES_CBC_SHA;
-suite(#{key_exchange := dhe_rsa,
- cipher:= '3des_ede_cbc',
- mac := sha}) ->
- ?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := dh_anon,
- cipher:= rc4_128,
- mac := md5}) ->
- ?TLS_DH_anon_WITH_RC4_128_MD5;
-suite(#{key_exchange := dh_anon,
- cipher:= des_cbc,
- mac := sha}) ->
- ?TLS_DH_anon_WITH_DES_CBC_SHA;
-suite(#{key_exchange := dh_anon,
- cipher:= '3des_ede_cbc',
- mac := sha}) ->
- ?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
-%%% TSL V1.1 AES suites
-suite(#{key_exchange := rsa,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_RSA_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := dhe_dss,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := dhe_rsa,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := dh_anon,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_DH_anon_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := rsa,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_RSA_WITH_AES_256_CBC_SHA;
-suite(#{key_exchange := dhe_dss,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA;
-suite(#{key_exchange := dhe_rsa,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
-suite(#{key_exchange := dh_anon,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_DH_anon_WITH_AES_256_CBC_SHA;
-%% TLS v1.2 suites
-suite(#{key_exchange := rsa,
- cipher := aes_128_cbc,
- mac := sha256}) ->
- ?TLS_RSA_WITH_AES_128_CBC_SHA256;
-suite(#{key_exchange := rsa,
- cipher := aes_256_cbc,
- mac := sha256}) ->
- ?TLS_RSA_WITH_AES_256_CBC_SHA256;
-suite(#{key_exchange := dhe_dss,
- cipher := aes_128_cbc,
- mac := sha256}) ->
- ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256;
-suite(#{key_exchange := dhe_rsa,
- cipher := aes_128_cbc,
- mac := sha256}) ->
- ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256;
-suite(#{key_exchange := dhe_dss,
- cipher := aes_256_cbc,
- mac := sha256}) ->
- ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256;
-suite(#{key_exchange := dhe_rsa,
- cipher := aes_256_cbc,
- mac := sha256}) ->
- ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
-suite(#{key_exchange := dh_anon,
- cipher := aes_128_cbc,
- mac := sha256}) ->
- ?TLS_DH_anon_WITH_AES_128_CBC_SHA256;
-suite(#{key_exchange := dh_anon,
- cipher := aes_256_cbc,
- mac := sha256}) ->
- ?TLS_DH_anon_WITH_AES_256_CBC_SHA256;
-%%% PSK Cipher Suites RFC 4279
-suite(#{key_exchange := psk,
- cipher := rc4_128,
- mac := sha}) ->
- ?TLS_PSK_WITH_RC4_128_SHA;
-suite(#{key_exchange := psk,
- cipher := '3des_ede_cbc',
- mac := sha}) ->
- ?TLS_PSK_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := psk,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_PSK_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := psk,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_PSK_WITH_AES_256_CBC_SHA;
-suite(#{key_exchange := dhe_psk,
- cipher := rc4_128,
- mac := sha}) ->
- ?TLS_DHE_PSK_WITH_RC4_128_SHA;
-suite(#{key_exchange := dhe_psk,
- cipher := '3des_ede_cbc',
- mac := sha}) ->
- ?TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := dhe_psk,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := dhe_psk,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_DHE_PSK_WITH_AES_256_CBC_SHA;
-suite(#{key_exchange := rsa_psk,
- cipher := rc4_128,
- mac := sha}) ->
- ?TLS_RSA_PSK_WITH_RC4_128_SHA;
-suite(#{key_exchange := rsa_psk,
- cipher := '3des_ede_cbc',
- mac := sha}) ->
- ?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := rsa_psk,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := rsa_psk,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA;
-%%% TLS 1.2 PSK Cipher Suites RFC 5487
-suite(#{key_exchange := psk,
- cipher := aes_128_gcm,
- mac := aead,
- prf := sha256}) ->
- ?TLS_PSK_WITH_AES_128_GCM_SHA256;
-suite(#{key_exchange := psk,
- cipher := aes_256_gcm,
- mac := aead,
- prf := sha384}) ->
- ?TLS_PSK_WITH_AES_256_GCM_SHA384;
-suite(#{key_exchange := dhe_psk,
- cipher := aes_128_gcm,
- mac := aead,
- prf := sha256}) ->
- ?TLS_DHE_PSK_WITH_AES_128_GCM_SHA256;
-suite(#{key_exchange := dhe_psk,
- cipher := aes_256_gcm,
- mac := aead,
- prf := sha384}) ->
- ?TLS_DHE_PSK_WITH_AES_256_GCM_SHA384;
-suite(#{key_exchange := rsa_psk,
- cipher := aes_128_gcm,
- mac := aead,
- prf := sha256}) ->
- ?TLS_RSA_PSK_WITH_AES_128_GCM_SHA256;
-suite(#{key_exchange := rsa_psk,
- cipher := aes_256_gcm,
- mac := aead,
- prf := sha384}) ->
- ?TLS_RSA_PSK_WITH_AES_256_GCM_SHA384;
-suite(#{key_exchange := psk,
- cipher := aes_128_cbc,
- mac := sha256}) ->
- ?TLS_PSK_WITH_AES_128_CBC_SHA256;
-suite(#{key_exchange := psk,
- cipher := aes_256_cbc,
- mac := sha384}) ->
- ?TLS_PSK_WITH_AES_256_CBC_SHA384;
-suite(#{key_exchange := dhe_psk,
- cipher := aes_128_cbc,
- mac := sha256}) ->
- ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256;
-suite(#{key_exchange := dhe_psk,
- cipher := aes_256_cbc,
- mac := sha384}) ->
- ?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384;
-suite(#{key_exchange := rsa_psk,
- cipher := aes_128_cbc,
- mac := sha256}) ->
- ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256;
-suite(#{key_exchange := rsa_psk,
- cipher := aes_256_cbc,
- mac := sha384}) ->
- ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384;
-suite(#{key_exchange := psk,
- cipher := null,
- mac := sha256}) ->
- ?TLS_PSK_WITH_NULL_SHA256;
-suite(#{key_exchange := psk,
- cipher := null,
- mac := sha384}) ->
- ?TLS_PSK_WITH_NULL_SHA384;
-suite(#{key_exchange := dhe_psk,
- cipher := null,
- mac := sha256}) ->
- ?TLS_DHE_PSK_WITH_NULL_SHA256;
-suite(#{key_exchange := dhe_psk,
- cipher := null,
- mac := sha384}) ->
- ?TLS_DHE_PSK_WITH_NULL_SHA384;
-suite(#{key_exchange := rsa_psk,
- cipher := null,
- mac := sha256}) ->
- ?TLS_RSA_PSK_WITH_NULL_SHA256;
-suite(#{key_exchange := rsa_psk,
- cipher := null,
- mac := sha384}) ->
- ?TLS_RSA_PSK_WITH_NULL_SHA384;
-%%% SRP Cipher Suites RFC 5054
-suite(#{key_exchange := srp_anon,
- cipher := '3des_ede_cbc',
- mac := sha}) ->
- ?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := srp_rsa,
- cipher := '3des_ede_cbc',
- mac := sha}) ->
- ?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := srp_dss,
- cipher := '3des_ede_cbc',
- mac := sha}) ->
- ?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := srp_anon,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_SRP_SHA_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := srp_rsa,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := srp_dss,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := srp_anon,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_SRP_SHA_WITH_AES_256_CBC_SHA;
-suite(#{key_exchange := srp_rsa,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA;
-suite(#{key_exchange := srp_dss,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA;
-%%% RFC 4492 EC TLS suites
-suite(#{key_exchange := ecdh_ecdsa,
- cipher := null,
- mac := sha}) ->
- ?TLS_ECDH_ECDSA_WITH_NULL_SHA;
-suite(#{key_exchange := ecdh_ecdsa,
- cipher := rc4_128,
- mac := sha}) ->
- ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA;
-suite(#{key_exchange := ecdh_ecdsa,
- cipher := '3des_ede_cbc',
- mac := sha}) ->
- ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := ecdh_ecdsa,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := ecdh_ecdsa,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA;
-suite(#{key_exchange := ecdhe_ecdsa,
- cipher := null,
- mac := sha}) ->
- ?TLS_ECDHE_ECDSA_WITH_NULL_SHA;
-suite(#{key_exchange := ecdhe_ecdsa,
- cipher := rc4_128,
- mac := sha}) ->
- ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA;
-suite(#{key_exchange := ecdhe_ecdsa,
- cipher := '3des_ede_cbc',
- mac := sha}) ->
- ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := ecdhe_ecdsa,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := ecdhe_ecdsa,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
-suite(#{key_exchange := ecdh_rsa,
- cipher := null,
- mac := sha}) ->
- ?TLS_ECDH_RSA_WITH_NULL_SHA;
-suite(#{key_exchange := ecdh_rsa,
- cipher := rc4_128,
- mac := sha}) ->
- ?TLS_ECDH_RSA_WITH_RC4_128_SHA;
-suite(#{key_exchange := ecdh_rsa,
- cipher := '3des_ede_cbc', mac := sha}) ->
- ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := ecdh_rsa,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := ecdh_rsa,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA;
-suite(#{key_exchange := ecdhe_rsa,
- cipher := null,
- mac := sha}) ->
- ?TLS_ECDHE_RSA_WITH_NULL_SHA;
-suite(#{key_exchange := ecdhe_rsa,
- cipher := rc4_128,
- mac := sha}) ->
- ?TLS_ECDHE_RSA_WITH_RC4_128_SHA;
-suite(#{key_exchange := ecdhe_rsa,
- cipher := '3des_ede_cbc',
- mac := sha}) ->
- ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := ecdhe_rsa,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := ecdhe_rsa,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
-suite(#{key_exchange := ecdh_anon,
- cipher := null,
- mac := sha}) ->
- ?TLS_ECDH_anon_WITH_NULL_SHA;
-suite(#{key_exchange := ecdh_anon,
- cipher := rc4_128,
- mac := sha}) ->
- ?TLS_ECDH_anon_WITH_RC4_128_SHA;
-suite(#{key_exchange := ecdh_anon,
- cipher := '3des_ede_cbc',
- mac := sha}) ->
- ?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := ecdh_anon,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_ECDH_anon_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := ecdh_anon,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_ECDH_anon_WITH_AES_256_CBC_SHA;
-%%% RFC 5289 EC TLS suites
-suite(#{key_exchange := ecdhe_ecdsa,
- cipher := aes_128_cbc,
- mac:= sha256,
- prf := sha256}) ->
- ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
-suite(#{key_exchange := ecdhe_ecdsa,
- cipher := aes_256_cbc,
- mac := sha384,
- prf := sha384}) ->
- ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384;
-suite(#{key_exchange := ecdh_ecdsa,
- cipher := aes_128_cbc,
- mac := sha256,
- prf := sha256}) ->
- ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256;
-suite(#{key_exchange := ecdh_ecdsa,
- cipher := aes_256_cbc,
- mac := sha384,
- prf := sha384}) ->
- ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384;
-suite(#{key_exchange := ecdhe_rsa,
- cipher := aes_128_cbc,
- mac := sha256,
- prf := sha256}) ->
- ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256;
-suite(#{key_exchange := ecdhe_rsa,
- cipher := aes_256_cbc,
- mac := sha384,
- prf := sha384}) ->
- ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384;
-suite(#{key_exchange := ecdh_rsa,
- cipher := aes_128_cbc,
- mac := sha256,
- prf := sha256}) ->
- ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;
-suite(#{key_exchange := ecdh_rsa,
- cipher := aes_256_cbc,
- mac := sha384,
- prf := sha384}) ->
- ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384;
-%% RFC 5288 AES-GCM Cipher Suites
-suite(#{key_exchange := rsa,
- cipher := aes_128_gcm,
- mac := aead,
- prf := sha256}) ->
- ?TLS_RSA_WITH_AES_128_GCM_SHA256;
-suite(#{key_exchange := rsa,
- cipher := aes_256_gcm,
- mac := aead,
- prf := sha384}) ->
- ?TLS_RSA_WITH_AES_256_GCM_SHA384;
-suite(#{key_exchange := dhe_rsa,
- cipher := aes_128_gcm,
- mac := aead,
- prf := sha256}) ->
- ?TLS_DHE_RSA_WITH_AES_128_GCM_SHA256;
-suite(#{key_exchange := dhe_rsa,
- cipher := aes_256_gcm,
- mac := aead,
- prf := sha384}) ->
- ?TLS_DHE_RSA_WITH_AES_256_GCM_SHA384;
-suite(#{key_exchange := dh_rsa,
- cipher := aes_128_gcm,
- mac := aead,
- prf := sha256}) ->
- ?TLS_DH_RSA_WITH_AES_128_GCM_SHA256;
-suite(#{key_exchange := dh_rsa,
- cipher := aes_256_gcm,
- mac := aead,
- prf := sha384}) ->
- ?TLS_DH_RSA_WITH_AES_256_GCM_SHA384;
-suite(#{key_exchange := dhe_dss,
- cipher := aes_128_gcm,
- mac := aead,
- prf := sha256}) ->
- ?TLS_DHE_DSS_WITH_AES_128_GCM_SHA256;
-suite(#{key_exchange := dhe_dss,
- cipher := aes_256_gcm,
- mac := aead,
- prf := sha384}) ->
- ?TLS_DHE_DSS_WITH_AES_256_GCM_SHA384;
-suite(#{key_exchange := dh_dss,
- cipher := aes_128_gcm,
- mac := aead,
- prf := sha256}) ->
- ?TLS_DH_DSS_WITH_AES_128_GCM_SHA256;
-suite(#{key_exchange := dh_dss,
- cipher := aes_256_gcm,
- mac := aead,
- prf := sha384}) ->
- ?TLS_DH_DSS_WITH_AES_256_GCM_SHA384;
-suite(#{key_exchange := dh_anon,
- cipher := aes_128_gcm,
- mac := aead,
- prf := sha256}) ->
- ?TLS_DH_anon_WITH_AES_128_GCM_SHA256;
-suite(#{key_exchange := dh_anon,
- cipher := aes_256_gcm,
- mac := aead,
- prf := sha384}) ->
- ?TLS_DH_anon_WITH_AES_256_GCM_SHA384;
-%% RFC 5289 ECC AES-GCM Cipher Suites
-suite(#{key_exchange := ecdhe_ecdsa,
- cipher := aes_128_gcm,
- mac := aead,
- prf := sha256}) ->
- ?TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256;
-suite(#{key_exchange := ecdhe_ecdsa,
- cipher := aes_256_gcm,
- mac := aead,
- prf := sha384}) ->
- ?TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384;
-suite(#{key_exchange := ecdh_ecdsa,
- cipher := aes_128_gcm,
- mac := aead,
- prf := sha256}) ->
- ?TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256;
-suite(#{key_exchange := ecdh_ecdsa,
- cipher := aes_256_gcm,
- mac := aead,
- prf := sha384}) ->
- ?TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384;
-suite(#{key_exchange := ecdhe_rsa,
- cipher := aes_128_gcm,
- mac := aead,
- prf := sha256}) ->
- ?TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256;
-suite(#{key_exchange := ecdhe_rsa,
- cipher := aes_256_gcm,
- mac := aead,
- prf := sha384}) ->
- ?TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384;
-suite(#{key_exchange := ecdh_rsa,
- cipher := aes_128_gcm,
- mac := aead,
- prf := sha256}) ->
- ?TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256;
-suite(#{key_exchange := ecdh_rsa,
- cipher := aes_256_gcm,
- mac := aead,
- prf := sha384}) ->
- ?TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384;
-%% draft-agl-tls-chacha20poly1305-04 Chacha20/Poly1305 Suites
-suite(#{key_exchange := ecdhe_rsa,
- cipher := chacha20_poly1305,
- mac := aead,
- prf := sha256}) ->
- ?TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256;
-suite(#{key_exchange := ecdhe_ecdsa,
- cipher := chacha20_poly1305,
- mac := aead,
- prf := sha256}) ->
- ?TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256;
-suite(#{key_exchange := dhe_rsa,
- cipher := chacha20_poly1305,
- mac := aead,
- prf := sha256}) ->
- ?TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256.
+ ?TLS_RSA_WITH_DES_CBC_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
+ ].
%%--------------------------------------------------------------------
--spec openssl_suite(openssl_cipher_suite()) -> cipher_suite().
+-spec rsa_suites(Version::ssl_record:ssl_version() | integer()) -> [ssl_cipher_format:cipher_suite()].
%%
-%% Description: Return TLS cipher suite definition.
-%%--------------------------------------------------------------------
-%% translate constants <-> openssl-strings
-openssl_suite("DHE-RSA-AES256-SHA256") ->
- ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
-openssl_suite("DHE-DSS-AES256-SHA256") ->
- ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256;
-openssl_suite("AES256-SHA256") ->
- ?TLS_RSA_WITH_AES_256_CBC_SHA256;
-openssl_suite("DHE-RSA-AES128-SHA256") ->
- ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256;
-openssl_suite("DHE-DSS-AES128-SHA256") ->
- ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256;
-openssl_suite("AES128-SHA256") ->
- ?TLS_RSA_WITH_AES_128_CBC_SHA256;
-openssl_suite("DHE-RSA-AES256-SHA") ->
- ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
-openssl_suite("DHE-DSS-AES256-SHA") ->
- ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA;
-openssl_suite("AES256-SHA") ->
- ?TLS_RSA_WITH_AES_256_CBC_SHA;
-openssl_suite("EDH-RSA-DES-CBC3-SHA") ->
- ?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
-openssl_suite("EDH-DSS-DES-CBC3-SHA") ->
- ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA;
-openssl_suite("DES-CBC3-SHA") ->
- ?TLS_RSA_WITH_3DES_EDE_CBC_SHA;
-openssl_suite("DHE-RSA-AES128-SHA") ->
- ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
-openssl_suite("DHE-DSS-AES128-SHA") ->
- ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA;
-openssl_suite("AES128-SHA") ->
- ?TLS_RSA_WITH_AES_128_CBC_SHA;
-openssl_suite("RC4-SHA") ->
- ?TLS_RSA_WITH_RC4_128_SHA;
-openssl_suite("RC4-MD5") ->
- ?TLS_RSA_WITH_RC4_128_MD5;
-openssl_suite("EDH-RSA-DES-CBC-SHA") ->
- ?TLS_DHE_RSA_WITH_DES_CBC_SHA;
-openssl_suite("DES-CBC-SHA") ->
- ?TLS_RSA_WITH_DES_CBC_SHA;
-
-%%% SRP Cipher Suites RFC 5054
-
-openssl_suite("SRP-DSS-AES-256-CBC-SHA") ->
- ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA;
-openssl_suite("SRP-RSA-AES-256-CBC-SHA") ->
- ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA;
-openssl_suite("SRP-DSS-3DES-EDE-CBC-SHA") ->
- ?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA;
-openssl_suite("SRP-RSA-3DES-EDE-CBC-SHA") ->
- ?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA;
-openssl_suite("SRP-DSS-AES-128-CBC-SHA") ->
- ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA;
-openssl_suite("SRP-RSA-AES-128-CBC-SHA") ->
- ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA;
-
-%% RFC 4492 EC TLS suites
-openssl_suite("ECDH-ECDSA-RC4-SHA") ->
- ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA;
-openssl_suite("ECDH-ECDSA-DES-CBC3-SHA") ->
- ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA;
-openssl_suite("ECDH-ECDSA-AES128-SHA") ->
- ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA;
-openssl_suite("ECDH-ECDSA-AES256-SHA") ->
- ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA;
-
-openssl_suite("ECDHE-ECDSA-RC4-SHA") ->
- ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA;
-openssl_suite("ECDHE-ECDSA-DES-CBC3-SHA") ->
- ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;
-openssl_suite("ECDHE-ECDSA-AES128-SHA") ->
- ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA;
-openssl_suite("ECDHE-ECDSA-AES256-SHA") ->
- ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
-
-openssl_suite("ECDHE-RSA-RC4-SHA") ->
- ?TLS_ECDHE_RSA_WITH_RC4_128_SHA;
-openssl_suite("ECDHE-RSA-DES-CBC3-SHA") ->
- ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;
-openssl_suite("ECDHE-RSA-AES128-SHA") ->
- ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
-openssl_suite("ECDHE-RSA-AES256-SHA") ->
- ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
-
-openssl_suite("ECDH-RSA-RC4-SHA") ->
- ?TLS_ECDH_RSA_WITH_RC4_128_SHA;
-openssl_suite("ECDH-RSA-DES-CBC3-SHA") ->
- ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA;
-openssl_suite("ECDH-RSA-AES128-SHA") ->
- ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;
-openssl_suite("ECDH-RSA-AES256-SHA") ->
- ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA;
-
-%% RFC 5289 EC TLS suites
-openssl_suite("ECDHE-ECDSA-AES128-SHA256") ->
- ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
-openssl_suite("ECDHE-ECDSA-AES256-SHA384") ->
- ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384;
-openssl_suite("ECDH-ECDSA-AES128-SHA256") ->
- ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256;
-openssl_suite("ECDH-ECDSA-AES256-SHA384") ->
- ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384;
-openssl_suite("ECDHE-RSA-AES128-SHA256") ->
- ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256;
-openssl_suite("ECDHE-RSA-AES256-SHA384") ->
- ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384;
-openssl_suite("ECDH-RSA-AES128-SHA256") ->
- ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;
-openssl_suite("ECDH-RSA-AES256-SHA384") ->
- ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384;
-
-%% RFC 5288 AES-GCM Cipher Suites
-openssl_suite("AES128-GCM-SHA256") ->
- ?TLS_RSA_WITH_AES_128_GCM_SHA256;
-openssl_suite("AES256-GCM-SHA384") ->
- ?TLS_RSA_WITH_AES_256_GCM_SHA384;
-openssl_suite("DHE-RSA-AES128-GCM-SHA256") ->
- ?TLS_DHE_RSA_WITH_AES_128_GCM_SHA256;
-openssl_suite("DHE-RSA-AES256-GCM-SHA384") ->
- ?TLS_DHE_RSA_WITH_AES_256_GCM_SHA384;
-openssl_suite("DH-RSA-AES128-GCM-SHA256") ->
- ?TLS_DH_RSA_WITH_AES_128_GCM_SHA256;
-openssl_suite("DH-RSA-AES256-GCM-SHA384") ->
- ?TLS_DH_RSA_WITH_AES_256_GCM_SHA384;
-openssl_suite("DHE-DSS-AES128-GCM-SHA256") ->
- ?TLS_DHE_DSS_WITH_AES_128_GCM_SHA256;
-openssl_suite("DHE-DSS-AES256-GCM-SHA384") ->
- ?TLS_DHE_DSS_WITH_AES_256_GCM_SHA384;
-openssl_suite("DH-DSS-AES128-GCM-SHA256") ->
- ?TLS_DH_DSS_WITH_AES_128_GCM_SHA256;
-openssl_suite("DH-DSS-AES256-GCM-SHA384") ->
- ?TLS_DH_DSS_WITH_AES_256_GCM_SHA384;
-
-%% RFC 5289 ECC AES-GCM Cipher Suites
-openssl_suite("ECDHE-ECDSA-AES128-GCM-SHA256") ->
- ?TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256;
-openssl_suite("ECDHE-ECDSA-AES256-GCM-SHA384") ->
- ?TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384;
-openssl_suite("ECDH-ECDSA-AES128-GCM-SHA256") ->
- ?TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256;
-openssl_suite("ECDH-ECDSA-AES256-GCM-SHA384") ->
- ?TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384;
-openssl_suite("ECDHE-RSA-AES128-GCM-SHA256") ->
- ?TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256;
-openssl_suite("ECDHE-RSA-AES256-GCM-SHA384") ->
- ?TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384;
-openssl_suite("ECDH-RSA-AES128-GCM-SHA256") ->
- ?TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256;
-openssl_suite("ECDH-RSA-AES256-GCM-SHA384") ->
- ?TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384.
-
+%% Description: Returns a list of the RSA key exchange
+%% cipher suites, only supported if explicitly set by user.
+%% Are not considered secure any more.
%%--------------------------------------------------------------------
--spec openssl_suite_name(cipher_suite()) -> openssl_cipher_suite() | erl_cipher_suite().
-%%
-%% Description: Return openssl cipher suite name if possible
-%%-------------------------------------------------------------------
-openssl_suite_name(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA) ->
- "DHE-RSA-AES256-SHA";
-openssl_suite_name(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA) ->
- "DHE-DSS-AES256-SHA";
-openssl_suite_name(?TLS_RSA_WITH_AES_256_CBC_SHA) ->
- "AES256-SHA";
-openssl_suite_name(?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA) ->
- "EDH-RSA-DES-CBC3-SHA";
-openssl_suite_name(?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA) ->
- "EDH-DSS-DES-CBC3-SHA";
-openssl_suite_name(?TLS_RSA_WITH_3DES_EDE_CBC_SHA) ->
- "DES-CBC3-SHA";
-openssl_suite_name( ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA) ->
- "DHE-RSA-AES128-SHA";
-openssl_suite_name(?TLS_DHE_DSS_WITH_AES_128_CBC_SHA) ->
- "DHE-DSS-AES128-SHA";
-openssl_suite_name(?TLS_RSA_WITH_AES_128_CBC_SHA) ->
- "AES128-SHA";
-openssl_suite_name(?TLS_RSA_WITH_RC4_128_SHA) ->
- "RC4-SHA";
-openssl_suite_name(?TLS_RSA_WITH_RC4_128_MD5) ->
- "RC4-MD5";
-openssl_suite_name(?TLS_DHE_RSA_WITH_DES_CBC_SHA) ->
- "EDH-RSA-DES-CBC-SHA";
-openssl_suite_name(?TLS_RSA_WITH_DES_CBC_SHA) ->
- "DES-CBC-SHA";
-openssl_suite_name(?TLS_RSA_WITH_NULL_SHA256) ->
- "NULL-SHA256";
-openssl_suite_name(?TLS_RSA_WITH_AES_128_CBC_SHA256) ->
- "AES128-SHA256";
-openssl_suite_name(?TLS_RSA_WITH_AES_256_CBC_SHA256) ->
- "AES256-SHA256";
-openssl_suite_name(?TLS_DH_DSS_WITH_AES_128_CBC_SHA256) ->
- "DH-DSS-AES128-SHA256";
-openssl_suite_name(?TLS_DH_RSA_WITH_AES_128_CBC_SHA256) ->
- "DH-RSA-AES128-SHA256";
-openssl_suite_name(?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256) ->
- "DHE-DSS-AES128-SHA256";
-openssl_suite_name(?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256) ->
- "DHE-RSA-AES128-SHA256";
-openssl_suite_name(?TLS_DH_DSS_WITH_AES_256_CBC_SHA256) ->
- "DH-DSS-AES256-SHA256";
-openssl_suite_name(?TLS_DH_RSA_WITH_AES_256_CBC_SHA256) ->
- "DH-RSA-AES256-SHA256";
-openssl_suite_name(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256) ->
- "DHE-DSS-AES256-SHA256";
-openssl_suite_name(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256) ->
- "DHE-RSA-AES256-SHA256";
-
-%%% PSK Cipher Suites RFC 4279
-
-openssl_suite_name(?TLS_PSK_WITH_AES_256_CBC_SHA) ->
- "PSK-AES256-CBC-SHA";
-openssl_suite_name(?TLS_PSK_WITH_3DES_EDE_CBC_SHA) ->
- "PSK-3DES-EDE-CBC-SHA";
-openssl_suite_name(?TLS_PSK_WITH_AES_128_CBC_SHA) ->
- "PSK-AES128-CBC-SHA";
-openssl_suite_name(?TLS_PSK_WITH_RC4_128_SHA) ->
- "PSK-RC4-SHA";
-
-%%% SRP Cipher Suites RFC 5054
-
-openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA) ->
- "SRP-RSA-3DES-EDE-CBC-SHA";
-openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA) ->
- "SRP-DSS-3DES-EDE-CBC-SHA";
-openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA) ->
- "SRP-RSA-AES-128-CBC-SHA";
-openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA) ->
- "SRP-DSS-AES-128-CBC-SHA";
-openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA) ->
- "SRP-RSA-AES-256-CBC-SHA";
-openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA) ->
- "SRP-DSS-AES-256-CBC-SHA";
-
-%% RFC 4492 EC TLS suites
-openssl_suite_name(?TLS_ECDH_ECDSA_WITH_RC4_128_SHA) ->
- "ECDH-ECDSA-RC4-SHA";
-openssl_suite_name(?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
- "ECDH-ECDSA-DES-CBC3-SHA";
-openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA) ->
- "ECDH-ECDSA-AES128-SHA";
-openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA) ->
- "ECDH-ECDSA-AES256-SHA";
-
-openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA) ->
- "ECDHE-ECDSA-RC4-SHA";
-openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
- "ECDHE-ECDSA-DES-CBC3-SHA";
-openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) ->
- "ECDHE-ECDSA-AES128-SHA";
-openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) ->
- "ECDHE-ECDSA-AES256-SHA";
-
-openssl_suite_name(?TLS_ECDH_RSA_WITH_RC4_128_SHA) ->
- "ECDH-RSA-RC4-SHA";
-openssl_suite_name(?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA) ->
- "ECDH-RSA-DES-CBC3-SHA";
-openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA) ->
- "ECDH-RSA-AES128-SHA";
-openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA) ->
- "ECDH-RSA-AES256-SHA";
-
-openssl_suite_name(?TLS_ECDHE_RSA_WITH_RC4_128_SHA) ->
- "ECDHE-RSA-RC4-SHA";
-openssl_suite_name(?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA) ->
- "ECDHE-RSA-DES-CBC3-SHA";
-openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) ->
- "ECDHE-RSA-AES128-SHA";
-openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) ->
- "ECDHE-RSA-AES256-SHA";
-
-%% RFC 5289 EC TLS suites
-openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) ->
- "ECDHE-ECDSA-AES128-SHA256";
-openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384) ->
- "ECDHE-ECDSA-AES256-SHA384";
-openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256) ->
- "ECDH-ECDSA-AES128-SHA256";
-openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384) ->
- "ECDH-ECDSA-AES256-SHA384";
-openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) ->
- "ECDHE-RSA-AES128-SHA256";
-openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) ->
- "ECDHE-RSA-AES256-SHA384";
-openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256) ->
- "ECDH-RSA-AES128-SHA256";
-openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384) ->
- "ECDH-RSA-AES256-SHA384";
-
-%% RFC 5288 AES-GCM Cipher Suites
-openssl_suite_name(?TLS_RSA_WITH_AES_128_GCM_SHA256) ->
- "AES128-GCM-SHA256";
-openssl_suite_name(?TLS_RSA_WITH_AES_256_GCM_SHA384) ->
- "AES256-GCM-SHA384";
-openssl_suite_name(?TLS_DHE_RSA_WITH_AES_128_GCM_SHA256) ->
- "DHE-RSA-AES128-GCM-SHA256";
-openssl_suite_name(?TLS_DHE_RSA_WITH_AES_256_GCM_SHA384) ->
- "DHE-RSA-AES256-GCM-SHA384";
-openssl_suite_name(?TLS_DH_RSA_WITH_AES_128_GCM_SHA256) ->
- "DH-RSA-AES128-GCM-SHA256";
-openssl_suite_name(?TLS_DH_RSA_WITH_AES_256_GCM_SHA384) ->
- "DH-RSA-AES256-GCM-SHA384";
-openssl_suite_name(?TLS_DHE_DSS_WITH_AES_128_GCM_SHA256) ->
- "DHE-DSS-AES128-GCM-SHA256";
-openssl_suite_name(?TLS_DHE_DSS_WITH_AES_256_GCM_SHA384) ->
- "DHE-DSS-AES256-GCM-SHA384";
-openssl_suite_name(?TLS_DH_DSS_WITH_AES_128_GCM_SHA256) ->
- "DH-DSS-AES128-GCM-SHA256";
-openssl_suite_name(?TLS_DH_DSS_WITH_AES_256_GCM_SHA384) ->
- "DH-DSS-AES256-GCM-SHA384";
-
-%% RFC 5289 ECC AES-GCM Cipher Suites
-openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) ->
- "ECDHE-ECDSA-AES128-GCM-SHA256";
-openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384) ->
- "ECDHE-ECDSA-AES256-GCM-SHA384";
-openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256) ->
- "ECDH-ECDSA-AES128-GCM-SHA256";
-openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384) ->
- "ECDH-ECDSA-AES256-GCM-SHA384";
-openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) ->
- "ECDHE-RSA-AES128-GCM-SHA256";
-openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) ->
- "ECDHE-RSA-AES256-GCM-SHA384";
-openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256) ->
- "ECDH-RSA-AES128-GCM-SHA256";
-openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384) ->
- "ECDH-RSA-AES256-GCM-SHA384";
-
-%% No oppenssl name
-openssl_suite_name(Cipher) ->
- suite_definition(Cipher).
+rsa_suites({3, 0}) ->
+ rsa_suites(0);
+rsa_suites({3, Minor}) ->
+ rsa_suites(Minor) ++ rsa_suites(0);
+rsa_suites(0) ->
+ [?TLS_RSA_WITH_AES_256_CBC_SHA,
+ ?TLS_RSA_WITH_AES_128_CBC_SHA,
+ ?TLS_RSA_WITH_3DES_EDE_CBC_SHA
+ ];
+rsa_suites(N) when N =< 4 ->
+ [
+ ?TLS_RSA_WITH_AES_256_GCM_SHA384,
+ ?TLS_RSA_WITH_AES_256_CBC_SHA256,
+ ?TLS_RSA_WITH_AES_128_GCM_SHA256,
+ ?TLS_RSA_WITH_AES_128_CBC_SHA256
+ ].
%%--------------------------------------------------------------------
--spec filter(undefined | binary(), [cipher_suite()]) -> [cipher_suite()].
+-spec filter(undefined | binary(), [ssl_cipher_format:cipher_suite()],
+ ssl_record:ssl_version()) -> [ssl_cipher_format:cipher_suite()].
%%
%% Description: Select the cipher suites that can be used together with the
%% supplied certificate. (Server side functionality)
%%-------------------------------------------------------------------
-filter(undefined, Ciphers) ->
+filter(undefined, Ciphers, _) ->
Ciphers;
-filter(DerCert, Ciphers) ->
+filter(DerCert, Ciphers0, Version) ->
OtpCert = public_key:pkix_decode_cert(DerCert, otp),
SigAlg = OtpCert#'OTPCertificate'.signatureAlgorithm,
PubKeyInfo = OtpCert#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.subjectPublicKeyInfo,
PubKeyAlg = PubKeyInfo#'OTPSubjectPublicKeyInfo'.algorithm,
- Ciphers1 =
- case ssl_certificate:public_key_type(PubKeyAlg#'PublicKeyAlgorithm'.algorithm) of
- rsa ->
- filter_keyuse(OtpCert, ((Ciphers -- dsa_signed_suites()) -- ec_keyed_suites()) -- ecdh_suites(),
- rsa_suites(), dhe_rsa_suites() ++ ecdhe_rsa_suites());
- dsa ->
- (Ciphers -- rsa_keyed_suites()) -- ec_keyed_suites();
- ec ->
- filter_keyuse(OtpCert, (Ciphers -- rsa_keyed_suites()) -- dsa_signed_suites(),
- [], ecdhe_ecdsa_suites())
- end,
-
- case public_key:pkix_sign_types(SigAlg#'SignatureAlgorithm'.algorithm) of
- {_, rsa} ->
- Ciphers1 -- ecdsa_signed_suites();
- {_, dsa} ->
- Ciphers1;
- {_, ecdsa} ->
- Ciphers1 -- rsa_signed_suites()
- end.
+ Ciphers = filter_suites_pubkey(
+ ssl_certificate:public_key_type(PubKeyAlg#'PublicKeyAlgorithm'.algorithm),
+ Ciphers0, Version, OtpCert),
+ {_, Sign} = public_key:pkix_sign_types(SigAlg#'SignatureAlgorithm'.algorithm),
+ filter_suites_signature(Sign, Ciphers, Version).
+
%%--------------------------------------------------------------------
--spec filter_suites([erl_cipher_suite()] | [cipher_suite()], map()) ->
- [erl_cipher_suite()] | [cipher_suite()].
+-spec filter_suites([ssl:erl_cipher_suite()] | [ssl_cipher_format:cipher_suite()], map()) ->
+ [ssl:erl_cipher_suite()] | [ssl_cipher_format:cipher_suite()].
%%
%% Description: Filter suites using supplied filter funs
%%-------------------------------------------------------------------
@@ -2074,11 +549,11 @@ filter_suite(#{key_exchange := KeyExchange,
all_filters(Hash, HashFilters) andalso
all_filters(Prf, PrfFilters);
filter_suite(Suite, Filters) ->
- filter_suite(suite_definition(Suite), Filters).
+ filter_suite(ssl_cipher_format:suite_bin_to_map(Suite), Filters).
%%--------------------------------------------------------------------
--spec filter_suites([erl_cipher_suite()] | [cipher_suite()]) ->
- [erl_cipher_suite()] | [cipher_suite()].
+-spec filter_suites([ssl:erl_cipher_suite()] | [ssl_cipher_format:cipher_suite()]) ->
+ [ssl:erl_cipher_suite()] | [ssl_cipher_format:cipher_suite()].
%%
%% Description: Filter suites for algorithms supported by crypto.
%%-------------------------------------------------------------------
@@ -2119,7 +594,8 @@ crypto_support_filters() ->
end]}.
is_acceptable_keyexchange(KeyExchange, _Algos) when KeyExchange == psk;
- KeyExchange == null ->
+ KeyExchange == null;
+ KeyExchange == any ->
true;
is_acceptable_keyexchange(KeyExchange, Algos) when KeyExchange == dh_anon;
KeyExchange == dhe_psk ->
@@ -2130,7 +606,8 @@ is_acceptable_keyexchange(dhe_dss, Algos) ->
is_acceptable_keyexchange(dhe_rsa, Algos) ->
proplists:get_bool(dh, Algos) andalso
proplists:get_bool(rsa, Algos);
-is_acceptable_keyexchange(ecdh_anon, Algos) ->
+is_acceptable_keyexchange(KeyExchange, Algos) when KeyExchange == ecdh_anon;
+ KeyExchange == ecdhe_psk ->
proplists:get_bool(ecdh, Algos);
is_acceptable_keyexchange(KeyExchange, Algos) when KeyExchange == ecdh_ecdsa;
KeyExchange == ecdhe_ecdsa ->
@@ -2161,7 +638,7 @@ is_acceptable_cipher(rc4_128, Algos) ->
is_acceptable_cipher(des_cbc, Algos) ->
proplists:get_bool(des_cbc, Algos);
is_acceptable_cipher('3des_ede_cbc', Algos) ->
- proplists:get_bool(des3_cbc, Algos);
+ proplists:get_bool(des_ede3, Algos);
is_acceptable_cipher(aes_128_cbc, Algos) ->
proplists:get_bool(aes_cbc128, Algos);
is_acceptable_cipher(aes_256_cbc, Algos) ->
@@ -2170,11 +647,19 @@ is_acceptable_cipher(Cipher, Algos)
when Cipher == aes_128_gcm;
Cipher == aes_256_gcm ->
proplists:get_bool(aes_gcm, Algos);
+is_acceptable_cipher(Cipher, Algos)
+ when Cipher == aes_128_ccm;
+ Cipher == aes_256_ccm;
+ Cipher == aes_128_ccm_8;
+ Cipher == aes_256_ccm_8 ->
+ proplists:get_bool(aes_ccm, Algos);
is_acceptable_cipher(Cipher, Algos) ->
proplists:get_bool(Cipher, Algos).
is_acceptable_hash(null, _Algos) ->
true;
+is_acceptable_hash(aead, _Algos) ->
+ true;
is_acceptable_hash(Hash, Algos) ->
proplists:get_bool(Hash, Algos).
@@ -2199,17 +684,40 @@ random_bytes(N) ->
calc_mac_hash(Type, Version,
PlainFragment, #{sequence_number := SeqNo,
mac_secret := MacSecret,
- security_parameters:=
- SecPars}) ->
+ security_parameters :=
+ #security_parameters{mac_algorithm = MacAlgorithm}}) ->
+ calc_mac_hash(Type, Version, PlainFragment, MacAlgorithm, MacSecret, SeqNo).
+%%
+calc_mac_hash(Type, Version, PlainFragment, MacAlgorithm, MacSecret, SeqNo) ->
Length = erlang:iolist_size(PlainFragment),
- mac_hash(Version, SecPars#security_parameters.mac_algorithm,
- MacSecret, SeqNo, Type,
- Length, PlainFragment).
+ mac_hash(Version, MacAlgorithm, MacSecret, SeqNo, Type, Length, PlainFragment).
is_stream_ciphersuite(#{cipher := rc4_128}) ->
true;
is_stream_ciphersuite(_) ->
false.
+
+-spec hash_size(atom()) -> integer().
+hash_size(null) ->
+ 0;
+%% The AEAD MAC hash size is not used in the context
+%% of calculating the master secret. See RFC 5246 Section 6.2.3.3.
+hash_size(aead) ->
+ 0;
+hash_size(md5) ->
+ 16;
+hash_size(sha) ->
+ 20;
+%% Uncomment when adding cipher suite that needs it
+%hash_size(sha224) ->
+% 28;
+hash_size(sha256) ->
+ 32;
+hash_size(sha384) ->
+ 48;
+hash_size(sha512) ->
+ 64.
+
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
@@ -2219,7 +727,7 @@ mac_hash({_,_}, ?NULL, _MacSecret, _SeqNo, _Type,
mac_hash({3, 0}, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) ->
ssl_v3:mac_hash(MacAlg, MacSecret, SeqNo, Type, Length, Fragment);
mac_hash({3, N} = Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment)
- when N =:= 1; N =:= 2; N =:= 3 ->
+ when N =:= 1; N =:= 2; N =:= 3; N =:= 4 ->
tls_v1:mac_hash(MacAlg, MacSecret, SeqNo, Type, Version,
Length, Fragment).
@@ -2237,6 +745,12 @@ bulk_cipher_algorithm(Cipher) when Cipher == aes_128_cbc;
bulk_cipher_algorithm(Cipher) when Cipher == aes_128_gcm;
Cipher == aes_256_gcm ->
?AES_GCM;
+bulk_cipher_algorithm(Cipher) when Cipher == aes_128_ccm;
+ Cipher == aes_256_ccm ->
+ ?AES_CCM;
+bulk_cipher_algorithm(Cipher) when Cipher == aes_128_ccm_8;
+ Cipher == aes_256_ccm_8 ->
+ ?AES_CCM_8;
bulk_cipher_algorithm(chacha20_poly1305) ->
?CHACHA20_POLY1305.
@@ -2251,6 +765,10 @@ type(Cipher) when Cipher == des_cbc;
?BLOCK;
type(Cipher) when Cipher == aes_128_gcm;
Cipher == aes_256_gcm;
+ Cipher == aes_128_ccm;
+ Cipher == aes_256_ccm;
+ Cipher == aes_128_ccm_8;
+ Cipher == aes_256_ccm_8;
Cipher == chacha20_poly1305 ->
?AEAD.
@@ -2268,8 +786,16 @@ key_material(aes_256_cbc) ->
32;
key_material(aes_128_gcm) ->
16;
+key_material(aes_128_ccm) ->
+ 16;
+key_material(aes_128_ccm_8) ->
+ 16;
key_material(aes_256_gcm) ->
32;
+key_material(aes_256_ccm_8) ->
+ 32;
+key_material(aes_256_ccm) ->
+ 32;
key_material(chacha20_poly1305) ->
32.
@@ -2285,45 +811,58 @@ expanded_key_material(Cipher) when Cipher == aes_128_cbc;
Cipher == aes_256_cbc;
Cipher == aes_128_gcm;
Cipher == aes_256_gcm;
+ Cipher == aes_128_ccm;
+ Cipher == aes_256_ccm;
+ Cipher == aes_128_ccm_8;
+ Cipher == aes_256_ccm_8;
Cipher == chacha20_poly1305 ->
unknown.
-
effective_key_bits(null) ->
0;
effective_key_bits(des_cbc) ->
56;
effective_key_bits(Cipher) when Cipher == rc4_128;
Cipher == aes_128_cbc;
- Cipher == aes_128_gcm ->
+ Cipher == aes_128_gcm;
+ Cipher == aes_128_ccm;
+ Cipher == aes_128_ccm_8 ->
128;
effective_key_bits('3des_ede_cbc') ->
168;
effective_key_bits(Cipher) when Cipher == aes_256_cbc;
Cipher == aes_256_gcm;
+ Cipher == aes_256_ccm;
+ Cipher == aes_256_ccm_8;
Cipher == chacha20_poly1305 ->
256.
iv_size(Cipher) when Cipher == null;
- Cipher == rc4_128;
- Cipher == chacha20_poly1305->
+ Cipher == rc4_128 ->
0;
-
iv_size(Cipher) when Cipher == aes_128_gcm;
- Cipher == aes_256_gcm ->
+ Cipher == aes_256_gcm;
+ Cipher == aes_128_ccm;
+ Cipher == aes_256_ccm;
+ Cipher == aes_128_ccm_8;
+ Cipher == aes_256_ccm_8 ->
4;
-
+iv_size(chacha20_poly1305) ->
+ 12;
iv_size(Cipher) ->
block_size(Cipher).
block_size(Cipher) when Cipher == des_cbc;
Cipher == '3des_ede_cbc' ->
8;
-
block_size(Cipher) when Cipher == aes_128_cbc;
Cipher == aes_256_cbc;
Cipher == aes_128_gcm;
Cipher == aes_256_gcm;
+ Cipher == aes_128_ccm;
+ Cipher == aes_256_ccm;
+ Cipher == aes_128_ccm_8;
+ Cipher == aes_256_ccm_8;
Cipher == chacha20_poly1305 ->
16.
@@ -2367,26 +906,75 @@ sign_algorithm(?ECDSA) -> ecdsa;
sign_algorithm(Other) when is_integer(Other) andalso ((Other >= 4) and (Other =< 223)) -> unassigned;
sign_algorithm(Other) when is_integer(Other) andalso ((Other >= 224) and (Other =< 255)) -> Other.
-hash_size(null) ->
- 0;
-%% The AEAD MAC hash size is not used in the context
-%% of calculating the master secret. See RFC 5246 Section 6.2.3.3.
-hash_size(aead) ->
- 0;
-hash_size(md5) ->
- 16;
-hash_size(sha) ->
- 20;
-%% Uncomment when adding cipher suite that needs it
-%hash_size(sha224) ->
-% 28;
-hash_size(sha256) ->
- 32;
-hash_size(sha384) ->
- 48.
-%% Uncomment when adding cipher suite that needs it
-%hash_size(sha512) ->
-% 64.
+
+signature_scheme(rsa_pkcs1_sha256) -> ?RSA_PKCS1_SHA256;
+signature_scheme(rsa_pkcs1_sha384) -> ?RSA_PKCS1_SHA384;
+signature_scheme(rsa_pkcs1_sha512) -> ?RSA_PKCS1_SHA512;
+signature_scheme(ecdsa_secp256r1_sha256) -> ?ECDSA_SECP256R1_SHA256;
+signature_scheme(ecdsa_secp384r1_sha384) -> ?ECDSA_SECP384R1_SHA384;
+signature_scheme(ecdsa_secp521r1_sha512) -> ?ECDSA_SECP521R1_SHA512;
+signature_scheme(rsa_pss_rsae_sha256) -> ?RSA_PSS_RSAE_SHA256;
+signature_scheme(rsa_pss_rsae_sha384) -> ?RSA_PSS_RSAE_SHA384;
+signature_scheme(rsa_pss_rsae_sha512) -> ?RSA_PSS_RSAE_SHA512;
+signature_scheme(ed25519) -> ?ED25519;
+signature_scheme(ed448) -> ?ED448;
+signature_scheme(rsa_pss_pss_sha256) -> ?RSA_PSS_PSS_SHA256;
+signature_scheme(rsa_pss_pss_sha384) -> ?RSA_PSS_PSS_SHA384;
+signature_scheme(rsa_pss_pss_sha512) -> ?RSA_PSS_PSS_SHA512;
+signature_scheme(rsa_pkcs1_sha1) -> ?RSA_PKCS1_SHA1;
+signature_scheme(ecdsa_sha1) -> ?ECDSA_SHA1;
+signature_scheme(?RSA_PKCS1_SHA256) -> rsa_pkcs1_sha256;
+signature_scheme(?RSA_PKCS1_SHA384) -> rsa_pkcs1_sha384;
+signature_scheme(?RSA_PKCS1_SHA512) -> rsa_pkcs1_sha512;
+signature_scheme(?ECDSA_SECP256R1_SHA256) -> ecdsa_secp256r1_sha256;
+signature_scheme(?ECDSA_SECP384R1_SHA384) -> ecdsa_secp384r1_sha384;
+signature_scheme(?ECDSA_SECP521R1_SHA512) -> ecdsa_secp521r1_sha512;
+signature_scheme(?RSA_PSS_RSAE_SHA256) -> rsa_pss_rsae_sha256;
+signature_scheme(?RSA_PSS_RSAE_SHA384) -> rsa_pss_rsae_sha384;
+signature_scheme(?RSA_PSS_RSAE_SHA512) -> rsa_pss_rsae_sha512;
+signature_scheme(?ED25519) -> ed25519;
+signature_scheme(?ED448) -> ed448;
+signature_scheme(?RSA_PSS_PSS_SHA256) -> rsa_pss_pss_sha256;
+signature_scheme(?RSA_PSS_PSS_SHA384) -> rsa_pss_pss_sha384;
+signature_scheme(?RSA_PSS_PSS_SHA512) -> rsa_pss_pss_sha512;
+signature_scheme(?RSA_PKCS1_SHA1) -> rsa_pkcs1_sha1;
+signature_scheme(?ECDSA_SHA1) -> ecdsa_sha1;
+%% Handling legacy signature algorithms for logging purposes. These algorithms
+%% cannot be used in TLS 1.3 handshakes.
+signature_scheme(SignAlgo) when is_integer(SignAlgo) ->
+ <<?BYTE(Hash),?BYTE(Sign)>> = <<?UINT16(SignAlgo)>>,
+ {ssl_cipher:hash_algorithm(Hash), ssl_cipher:sign_algorithm(Sign)};
+signature_scheme(_) -> unassigned.
+%% TODO: reserved code points?
+
+scheme_to_components(rsa_pkcs1_sha256) -> {sha256, rsa_pkcs1, undefined};
+scheme_to_components(rsa_pkcs1_sha384) -> {sha384, rsa_pkcs1, undefined};
+scheme_to_components(rsa_pkcs1_sha512) -> {sha512, rsa_pkcs1, undefined};
+scheme_to_components(ecdsa_secp256r1_sha256) -> {sha256, ecdsa, secp256r1};
+scheme_to_components(ecdsa_secp384r1_sha384) -> {sha384, ecdsa, secp384r1};
+scheme_to_components(ecdsa_secp521r1_sha512) -> {sha512, ecdsa, secp521r1};
+scheme_to_components(rsa_pss_rsae_sha256) -> {sha256, rsa_pss_rsae, undefined};
+scheme_to_components(rsa_pss_rsae_sha384) -> {sha384, rsa_pss_rsae, undefined};
+scheme_to_components(rsa_pss_rsae_sha512) -> {sha512, rsa_pss_rsae, undefined};
+scheme_to_components(ed25519) -> {undefined, undefined, undefined};
+scheme_to_components(ed448) -> {undefined, undefined, undefined};
+scheme_to_components(rsa_pss_pss_sha256) -> {sha256, rsa_pss_pss, undefined};
+scheme_to_components(rsa_pss_pss_sha384) -> {sha384, rsa_pss_pss, undefined};
+scheme_to_components(rsa_pss_pss_sha512) -> {sha512, rsa_pss_pss, undefined};
+scheme_to_components(rsa_pkcs1_sha1) -> {sha1, rsa_pkcs1, undefined};
+scheme_to_components(ecdsa_sha1) -> {sha1, ecdsa, undefined}.
+
+
+%% TODO: Add support for EC and RSA-SSA signatures
+signature_algorithm_to_scheme(#'SignatureAlgorithm'{algorithm = ?sha1WithRSAEncryption}) ->
+ rsa_pkcs1_sha1;
+signature_algorithm_to_scheme(#'SignatureAlgorithm'{algorithm = ?sha256WithRSAEncryption}) ->
+ rsa_pkcs1_sha256;
+signature_algorithm_to_scheme(#'SignatureAlgorithm'{algorithm = ?sha384WithRSAEncryption}) ->
+ rsa_pkcs1_sha384;
+signature_algorithm_to_scheme(#'SignatureAlgorithm'{algorithm = ?sha512WithRSAEncryption}) ->
+ rsa_pkcs1_sha512.
+
%% RFC 5246: 6.2.3.2. CBC Block Cipher
%%
@@ -2424,7 +1012,7 @@ generic_block_cipher_from_bin({3, N}, T, IV, HashSize)
next_iv = IV};
generic_block_cipher_from_bin({3, N}, T, IV, HashSize)
- when N == 2; N == 3 ->
+ when N == 2; N == 3; N == 4 ->
Sz1 = byte_size(T) - 1,
<<_:Sz1/binary, ?BYTE(PadLength)>> = T,
IVLength = byte_size(IV),
@@ -2454,21 +1042,51 @@ is_correct_padding(GenBlockCipher, {3, 1}, false) ->
%% Padding must be checked in TLS 1.1 and after
is_correct_padding(#generic_block_cipher{padding_length = Len,
padding = Padding}, _, _) ->
- Len == byte_size(Padding) andalso
- list_to_binary(lists:duplicate(Len, Len)) == Padding.
-
-get_padding(Length, BlockSize) ->
- get_padding_aux(BlockSize, Length rem BlockSize).
-
-get_padding_aux(_, 0) ->
- {0, <<>>};
-get_padding_aux(BlockSize, PadLength) ->
- N = BlockSize - PadLength,
- {N, list_to_binary(lists:duplicate(N, N))}.
+ (Len == byte_size(Padding)) andalso (padding(Len) == Padding).
+
+padding(PadLen) ->
+ case PadLen of
+ 0 -> <<>>;
+ 1 -> <<1>>;
+ 2 -> <<2,2>>;
+ 3 -> <<3,3,3>>;
+ 4 -> <<4,4,4,4>>;
+ 5 -> <<5,5,5,5,5>>;
+ 6 -> <<6,6,6,6,6,6>>;
+ 7 -> <<7,7,7,7,7,7,7>>;
+ 8 -> <<8,8,8,8,8,8,8,8>>;
+ 9 -> <<9,9,9,9,9,9,9,9,9>>;
+ 10 -> <<10,10,10,10,10,10,10,10,10,10>>;
+ 11 -> <<11,11,11,11,11,11,11,11,11,11,11>>;
+ 12 -> <<12,12,12,12,12,12,12,12,12,12,12,12>>;
+ 13 -> <<13,13,13,13,13,13,13,13,13,13,13,13,13>>;
+ 14 -> <<14,14,14,14,14,14,14,14,14,14,14,14,14,14>>;
+ 15 -> <<15,15,15,15,15,15,15,15,15,15,15,15,15,15,15>>;
+ _ ->
+ binary:copy(<<PadLen>>, PadLen)
+ end.
-random_iv(IV) ->
- IVSz = byte_size(IV),
- random_bytes(IVSz).
+padding_with_len(TextLen, BlockSize) ->
+ case BlockSize - (TextLen rem BlockSize) of
+ 0 -> <<0>>;
+ 1 -> <<1,1>>;
+ 2 -> <<2,2,2>>;
+ 3 -> <<3,3,3,3>>;
+ 4 -> <<4,4,4,4,4>>;
+ 5 -> <<5,5,5,5,5,5>>;
+ 6 -> <<6,6,6,6,6,6,6>>;
+ 7 -> <<7,7,7,7,7,7,7,7>>;
+ 8 -> <<8,8,8,8,8,8,8,8,8>>;
+ 9 -> <<9,9,9,9,9,9,9,9,9,9>>;
+ 10 -> <<10,10,10,10,10,10,10,10,10,10,10>>;
+ 11 -> <<11,11,11,11,11,11,11,11,11,11,11,11>>;
+ 12 -> <<12,12,12,12,12,12,12,12,12,12,12,12,12>>;
+ 13 -> <<13,13,13,13,13,13,13,13,13,13,13,13,13,13>>;
+ 14 -> <<14,14,14,14,14,14,14,14,14,14,14,14,14,14,14>>;
+ 15 -> <<15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15>>;
+ PadLen ->
+ binary:copy(<<PadLen>>, PadLen + 1)
+ end.
next_iv(Bin, IV) ->
BinSz = byte_size(Bin),
@@ -2477,143 +1095,214 @@ next_iv(Bin, IV) ->
<<_:FirstPart/binary, NextIV:IVSz/binary>> = Bin,
NextIV.
-rsa_signed_suites() ->
- dhe_rsa_suites() ++ rsa_suites() ++
- psk_rsa_suites() ++ srp_rsa_suites() ++
- ecdh_rsa_suites() ++ ecdhe_rsa_suites().
-
-rsa_keyed_suites() ->
- dhe_rsa_suites() ++ rsa_suites() ++
- psk_rsa_suites() ++ srp_rsa_suites() ++
- ecdhe_rsa_suites().
-
-dhe_rsa_suites() ->
- [?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
- ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
- ?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
- ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
- ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
- ?TLS_DHE_RSA_WITH_DES_CBC_SHA,
- ?TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
- ?TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
- ?TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
- ].
-
-psk_rsa_suites() ->
- [?TLS_RSA_PSK_WITH_AES_256_GCM_SHA384,
- ?TLS_RSA_PSK_WITH_AES_128_GCM_SHA256,
- ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384,
- ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256,
- ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA,
- ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA,
- ?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
- ?TLS_RSA_PSK_WITH_RC4_128_SHA].
-
-srp_rsa_suites() ->
- [?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA,
- ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA,
- ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA].
-
-rsa_suites() ->
- [?TLS_RSA_WITH_AES_256_CBC_SHA256,
- ?TLS_RSA_WITH_AES_256_CBC_SHA,
- ?TLS_RSA_WITH_3DES_EDE_CBC_SHA,
- ?TLS_RSA_WITH_AES_128_CBC_SHA256,
- ?TLS_RSA_WITH_AES_128_CBC_SHA,
- ?TLS_RSA_WITH_RC4_128_SHA,
- ?TLS_RSA_WITH_RC4_128_MD5,
- ?TLS_RSA_WITH_DES_CBC_SHA,
- ?TLS_RSA_WITH_AES_128_GCM_SHA256,
- ?TLS_RSA_WITH_AES_256_GCM_SHA384].
-
-ecdh_rsa_suites() ->
- [?TLS_ECDH_RSA_WITH_NULL_SHA,
- ?TLS_ECDH_RSA_WITH_RC4_128_SHA,
- ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
- ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
- ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
- ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
- ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
- ?TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
- ?TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384].
-
-ecdhe_rsa_suites() ->
- [?TLS_ECDHE_RSA_WITH_NULL_SHA,
- ?TLS_ECDHE_RSA_WITH_RC4_128_SHA,
- ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
- ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
- ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
- ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
- ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
- ?TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
- ?TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
- ?TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256].
-
-dsa_signed_suites() ->
- dhe_dss_suites() ++ srp_dss_suites().
-
-dhe_dss_suites() ->
- [?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
- ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
- ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
- ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
- ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
- ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
- ?TLS_DHE_DSS_WITH_AES_128_GCM_SHA256,
- ?TLS_DHE_DSS_WITH_AES_256_GCM_SHA384].
-
-srp_dss_suites() ->
- [?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA,
- ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
- ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA].
+filter_suites_pubkey(rsa, CiphersSuites0, _Version, OtpCert) ->
+ KeyUses = key_uses(OtpCert),
+ NotECDSAKeyed = (CiphersSuites0 -- ec_keyed_suites(CiphersSuites0))
+ -- dss_keyed_suites(CiphersSuites0),
+ CiphersSuites = filter_keyuse_suites(keyEncipherment, KeyUses,
+ NotECDSAKeyed,
+ rsa_suites_encipher(CiphersSuites0)),
+ filter_keyuse_suites(digitalSignature, KeyUses, CiphersSuites,
+ rsa_ecdhe_dhe_suites(CiphersSuites));
+filter_suites_pubkey(dsa, Ciphers, _, OtpCert) ->
+ KeyUses = key_uses(OtpCert),
+ NotECRSAKeyed = (Ciphers -- rsa_keyed_suites(Ciphers)) -- ec_keyed_suites(Ciphers),
+ filter_keyuse_suites(digitalSignature, KeyUses, NotECRSAKeyed,
+ dss_dhe_suites(Ciphers));
+filter_suites_pubkey(ec, Ciphers, _, OtpCert) ->
+ Uses = key_uses(OtpCert),
+ NotRSADSAKeyed = (Ciphers -- rsa_keyed_suites(Ciphers)) -- dss_keyed_suites(Ciphers),
+ CiphersSuites = filter_keyuse_suites(digitalSignature, Uses, NotRSADSAKeyed,
+ ec_ecdhe_suites(Ciphers)),
+ filter_keyuse_suites(keyAgreement, Uses, CiphersSuites, ec_ecdh_suites(Ciphers)).
+
+filter_suites_signature(_, Ciphers, {3, N}) when N >= 3 ->
+ Ciphers;
+filter_suites_signature(rsa, Ciphers, Version) ->
+ (Ciphers -- ecdsa_signed_suites(Ciphers, Version)) -- dsa_signed_suites(Ciphers, Version);
+filter_suites_signature(dsa, Ciphers, Version) ->
+ (Ciphers -- ecdsa_signed_suites(Ciphers, Version)) -- rsa_signed_suites(Ciphers, Version);
+filter_suites_signature(ecdsa, Ciphers, Version) ->
+ (Ciphers -- rsa_signed_suites(Ciphers, Version)) -- dsa_signed_suites(Ciphers, Version).
+
+
+%% From RFC 5246 - Section 7.4.2. Server Certificate
+%% If the client provided a "signature_algorithms" extension, then all
+%% certificates provided by the server MUST be signed by a
+%% hash/signature algorithm pair that appears in that extension. Note
+%% that this implies that a certificate containing a key for one
+%% signature algorithm MAY be signed using a different signature
+%% algorithm (for instance, an RSA key signed with a DSA key). This is
+%% a departure from TLS 1.1, which required that the algorithms be the
+%% same.
+%% Note that this also implies that the DH_DSS, DH_RSA,
+%% ECDH_ECDSA, and ECDH_RSA key exchange algorithms do not restrict the
+%% algorithm used to sign the certificate. Fixed DH certificates MAY be
+%% signed with any hash/signature algorithm pair appearing in the
+%% extension. The names DH_DSS, DH_RSA, ECDH_ECDSA, and ECDH_RSA are
+%% historical.
+%% Note: DH_DSS and DH_RSA is not supported
+rsa_signed({3,N}) when N >= 3 ->
+ fun(rsa) -> true;
+ (dhe_rsa) -> true;
+ (ecdhe_rsa) -> true;
+ (rsa_psk) -> true;
+ (srp_rsa) -> true;
+ (_) -> false
+ end;
+rsa_signed(_) ->
+ fun(rsa) -> true;
+ (dhe_rsa) -> true;
+ (ecdhe_rsa) -> true;
+ (ecdh_rsa) -> true;
+ (rsa_psk) -> true;
+ (srp_rsa) -> true;
+ (_) -> false
+ end.
+%% Cert should be signed by RSA
+rsa_signed_suites(Ciphers, Version) ->
+ filter_suites(Ciphers, #{key_exchange_filters => [rsa_signed(Version)],
+ cipher_filters => [],
+ mac_filters => [],
+ prf_filters => []}).
+ecdsa_signed({3,N}) when N >= 3 ->
+ fun(ecdhe_ecdsa) -> true;
+ (_) -> false
+ end;
+ecdsa_signed(_) ->
+ fun(ecdhe_ecdsa) -> true;
+ (ecdh_ecdsa) -> true;
+ (_) -> false
+ end.
+
+%% Cert should be signed by ECDSA
+ecdsa_signed_suites(Ciphers, Version) ->
+ filter_suites(Ciphers, #{key_exchange_filters => [ecdsa_signed(Version)],
+ cipher_filters => [],
+ mac_filters => [],
+ prf_filters => []}).
+
+rsa_keyed(dhe_rsa) ->
+ true;
+rsa_keyed(ecdhe_rsa) ->
+ true;
+rsa_keyed(rsa) ->
+ true;
+rsa_keyed(rsa_psk) ->
+ true;
+rsa_keyed(srp_rsa) ->
+ true;
+rsa_keyed(_) ->
+ false.
-ec_keyed_suites() ->
- ecdh_ecdsa_suites() ++ ecdhe_ecdsa_suites()
- ++ ecdh_rsa_suites().
+%% Certs key is an RSA key
+rsa_keyed_suites(Ciphers) ->
+ filter_suites(Ciphers, #{key_exchange_filters => [fun(Kex) -> rsa_keyed(Kex) end],
+ cipher_filters => [],
+ mac_filters => [],
+ prf_filters => []}).
+
+%% RSA Certs key can be used for encipherment
+rsa_suites_encipher(Ciphers) ->
+ filter_suites(Ciphers, #{key_exchange_filters => [fun(rsa) -> true;
+ (rsa_psk) -> true;
+ (_) -> false
+ end],
+ cipher_filters => [],
+ mac_filters => [],
+ prf_filters => []}).
+
+dss_keyed(dhe_dss) ->
+ true;
+dss_keyed(spr_dss) ->
+ true;
+dss_keyed(_) ->
+ false.
+
+%% Cert should be have DSS key (DSA)
+dss_keyed_suites(Ciphers) ->
+ filter_suites(Ciphers, #{key_exchange_filters => [fun(Kex) -> dss_keyed(Kex) end],
+ cipher_filters => [],
+ mac_filters => [],
+ prf_filters => []}).
+
+%% Cert should be signed by DSS (DSA)
+dsa_signed_suites(Ciphers, Version) ->
+ filter_suites(Ciphers, #{key_exchange_filters => [dsa_signed(Version)],
+ cipher_filters => [],
+ mac_filters => [],
+ prf_filters => []}).
+dsa_signed(_) ->
+ fun(dhe_dss) -> true;
+ (_) -> false
+ end.
-ecdsa_signed_suites() ->
- ecdh_ecdsa_suites() ++ ecdhe_ecdsa_suites().
+dss_dhe_suites(Ciphers) ->
+ filter_suites(Ciphers, #{key_exchange_filters => [fun(dhe_dss) -> true;
+ (_) -> false
+ end],
+ cipher_filters => [],
+ mac_filters => [],
+ prf_filters => []}).
-ecdh_suites() ->
- ecdh_rsa_suites() ++ ecdh_ecdsa_suites().
+ec_keyed(ecdh_ecdsa) ->
+ true;
+ec_keyed(ecdh_rsa) ->
+ true;
+ec_keyed(ecdhe_ecdsa) ->
+ true;
+ec_keyed(_) ->
+ false.
-ecdh_ecdsa_suites() ->
- [?TLS_ECDH_ECDSA_WITH_NULL_SHA,
- ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
- ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
- ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
- ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
- ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
- ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
- ?TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
- ?TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384].
-
-ecdhe_ecdsa_suites() ->
- [?TLS_ECDHE_ECDSA_WITH_NULL_SHA,
- ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
- ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
- ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
- ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
- ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
- ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
- ?TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
- ?TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
- ?TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256].
-
-filter_keyuse(OtpCert, Ciphers, Suites, SignSuites) ->
+%% Certs key is an ECC key
+ec_keyed_suites(Ciphers) ->
+ filter_suites(Ciphers, #{key_exchange_filters => [fun(Kex) -> ec_keyed(Kex) end],
+ cipher_filters => [],
+ mac_filters => [],
+ prf_filters => []}).
+
+%% EC Certs key usage keyAgreement
+ec_ecdh_suites(Ciphers)->
+ filter_suites(Ciphers, #{key_exchange_filters => [fun(ecdh_ecdsa) -> true;
+ (_) -> false
+ end],
+ cipher_filters => [],
+ mac_filters => [],
+ prf_filters => []}).
+
+%% EC Certs key usage digitalSignature
+ec_ecdhe_suites(Ciphers) ->
+ filter_suites(Ciphers, #{key_exchange_filters => [fun(ecdhe_ecdsa) -> true;
+ (ecdhe_rsa) -> true;
+ (_) -> false
+ end],
+ cipher_filters => [],
+ mac_filters => [],
+ prf_filters => []}).
+%% RSA Certs key usage digitalSignature
+rsa_ecdhe_dhe_suites(Ciphers) ->
+ filter_suites(Ciphers, #{key_exchange_filters => [fun(dhe_rsa) -> true;
+ (ecdhe_rsa) -> true;
+ (_) -> false
+ end],
+ cipher_filters => [],
+ mac_filters => [],
+ prf_filters => []}).
+
+key_uses(OtpCert) ->
TBSCert = OtpCert#'OTPCertificate'.tbsCertificate,
TBSExtensions = TBSCert#'OTPTBSCertificate'.extensions,
Extensions = ssl_certificate:extensions_list(TBSExtensions),
case ssl_certificate:select_extension(?'id-ce-keyUsage', Extensions) of
undefined ->
- Ciphers;
- #'Extension'{extnValue = KeyUse} ->
- Result = filter_keyuse_suites(keyEncipherment,
- KeyUse, Ciphers, Suites),
- filter_keyuse_suites(digitalSignature,
- KeyUse, Result, SignSuites)
+ [];
+ #'Extension'{extnValue = KeyUses} ->
+ KeyUses
end.
+%% If no key-usage extension is defined all key-usages are allowed
+filter_keyuse_suites(_, [], CiphersSuites, _) ->
+ CiphersSuites;
filter_keyuse_suites(Use, KeyUse, CipherSuits, Suites) ->
case ssl_certificate:is_valid_key_usage(KeyUse, Use) of
true ->
@@ -2621,3 +1310,55 @@ filter_keyuse_suites(Use, KeyUse, CipherSuits, Suites) ->
false ->
CipherSuits -- Suites
end.
+
+generate_server_share(Group) ->
+ Key = generate_key_exchange(Group),
+ #key_share_server_hello{
+ server_share = #key_share_entry{
+ group = Group,
+ key_exchange = Key
+ }}.
+
+generate_client_shares([]) ->
+ #key_share_client_hello{client_shares = []};
+generate_client_shares(Groups) ->
+ generate_client_shares(Groups, []).
+%%
+generate_client_shares([], Acc) ->
+ #key_share_client_hello{client_shares = lists:reverse(Acc)};
+generate_client_shares([Group|Groups], Acc) ->
+ Key = generate_key_exchange(Group),
+ KeyShareEntry = #key_share_entry{
+ group = Group,
+ key_exchange = Key
+ },
+ generate_client_shares(Groups, [KeyShareEntry|Acc]).
+
+
+generate_key_exchange(secp256r1) ->
+ public_key:generate_key({namedCurve, secp256r1});
+generate_key_exchange(secp384r1) ->
+ public_key:generate_key({namedCurve, secp384r1});
+generate_key_exchange(secp521r1) ->
+ public_key:generate_key({namedCurve, secp521r1});
+generate_key_exchange(x25519) ->
+ crypto:generate_key(ecdh, x25519);
+generate_key_exchange(x448) ->
+ crypto:generate_key(ecdh, x448);
+generate_key_exchange(FFDHE) ->
+ public_key:generate_key(ssl_dh_groups:dh_params(FFDHE)).
+
+
+%% TODO: Move this functionality to crypto!
+%% 7.4.1. Finite Field Diffie-Hellman
+%%
+%% For finite field groups, a conventional Diffie-Hellman [DH76]
+%% computation is performed. The negotiated key (Z) is converted to a
+%% byte string by encoding in big-endian form and left-padded with zeros
+%% up to the size of the prime. This byte string is used as the shared
+%% secret in the key schedule as specified above.
+add_zero_padding(Bin, PrimeSize)
+ when byte_size (Bin) =:= PrimeSize ->
+ Bin;
+add_zero_padding(Bin, PrimeSize) ->
+ add_zero_padding(<<0, Bin/binary>>, PrimeSize).
diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl
index 8e8f3d9c67..0fa5f66c49 100644
--- a/lib/ssl/src/ssl_cipher.hrl
+++ b/lib/ssl/src/ssl_cipher.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -47,8 +47,10 @@
-record(cipher_state, {
iv,
key,
+ finished_key,
state,
- nonce
+ nonce,
+ tag_len
}).
%%% TLS_NULL_WITH_NULL_NULL is specified and is the initial state of a
@@ -399,6 +401,17 @@
%% TLS_RSA_PSK_WITH_AES_256_CBC_SHA = { 0x00, 0x95 };
-define(TLS_RSA_PSK_WITH_AES_256_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#95)>>).
+%%% PSK NULL Cipher Suites RFC 4785
+
+%% TLS_PSK_WITH_NULL_SHA = { 0x00, 0x2C };
+-define(TLS_PSK_WITH_NULL_SHA, <<?BYTE(16#00), ?BYTE(16#2C)>>).
+
+%% TLS_DHE_PSK_WITH_NULL_SHA = { 0x00, 0x2D };
+-define(TLS_DHE_PSK_WITH_NULL_SHA, <<?BYTE(16#00), ?BYTE(16#2D)>>).
+
+%% TLS_RSA_PSK_WITH_NULL_SHA = { 0x00, 0x2E };
+-define(TLS_RSA_PSK_WITH_NULL_SHA, <<?BYTE(16#00), ?BYTE(16#2E)>>).
+
%%% TLS 1.2 PSK Cipher Suites RFC 5487
%% TLS_PSK_WITH_AES_128_GCM_SHA256 = {0x00,0xA8};
@@ -455,6 +468,46 @@
%% TLS_RSA_PSK_WITH_NULL_SHA384 = {0x00,0xB9};
-define(TLS_RSA_PSK_WITH_NULL_SHA384, <<?BYTE(16#00), ?BYTE(16#B9)>>).
+%%% ECDHE PSK Cipher Suites RFC 5489
+
+%% TLS_ECDHE_PSK_WITH_RC4_128_SHA = {0xC0,0x33};
+-define(TLS_ECDHE_PSK_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#33)>>).
+
+%% TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA = {0xC0,0x34};
+-define(TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#34)>>).
+
+%% TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA = {0xC0,0x35};
+-define(TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#35)>>).
+
+%% TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA = {0xC0,0x36};
+-define(TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#36)>>).
+
+%% TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 = {0xC0,0x37};
+-define(TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, <<?BYTE(16#C0), ?BYTE(16#37)>>).
+
+%% TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 = {0xC0,0x38};
+-define(TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384, <<?BYTE(16#C0), ?BYTE(16#38)>>).
+
+%% TLS_ECDHE_PSK_WITH_NULL_SHA256 = {0xC0,0x3A};
+-define(TLS_ECDHE_PSK_WITH_NULL_SHA256, <<?BYTE(16#C0), ?BYTE(16#3A)>>).
+
+%% TLS_ECDHE_PSK_WITH_NULL_SHA384 = {0xC0,0x3B};
+-define(TLS_ECDHE_PSK_WITH_NULL_SHA384, <<?BYTE(16#C0), ?BYTE(16#3B)>>).
+
+%%% ECDHE_PSK with AES-GCM and AES-CCM Cipher Suites, draft-ietf-tls-ecdhe-psk-aead-05
+
+%% TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256 = {0xTBD; 0xTBD} {0xD0,0x01};
+-define(TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256, <<?BYTE(16#D0), ?BYTE(16#01)>>).
+
+%% TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384 = {0xTBD; 0xTBD} {0xD0,0x02};
+-define(TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384, <<?BYTE(16#D0), ?BYTE(16#02)>>).
+
+%% TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256 = {0xTBD; 0xTBD} {0xD0,0x03};
+-define(TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256, <<?BYTE(16#D0), ?BYTE(16#03)>>).
+
+%% TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256 = {0xTBD; 0xTBD} {0xD0,0x05};
+-define(TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256, <<?BYTE(16#D0), ?BYTE(16#05)>>).
+
%%% SRP Cipher Suites RFC 5054
%% TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = { 0xC0,0x1A };
@@ -548,15 +601,98 @@
%% TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 = {0xC0,0x32};
-define(TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, <<?BYTE(16#C0), ?BYTE(16#32)>>).
-%%% Chacha20/Poly1305 Suites draft-agl-tls-chacha20poly1305-04
-%% TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = {0xcc, 0x13}
--define(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, <<?BYTE(16#CC), ?BYTE(16#13)>>).
+%%% ChaCha20-Poly1305 Cipher Suites for Transport Layer Security (TLS) RFC7905
+
+%% TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = {0xCC, 0xA8}
+-define(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, <<?BYTE(16#CC), ?BYTE(16#A8)>>).
+
+%% TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = {0xCC, 0xA9}
+-define(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, <<?BYTE(16#CC), ?BYTE(16#A9)>>).
+
+%% TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = {0xCC, 0xAA}
+-define(TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, <<?BYTE(16#CC), ?BYTE(16#AA)>>).
+
+%% TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 = {0xCC, 0xAB}
+-define(TLS_PSK_WITH_CHACHA20_POLY1305_SHA256, <<?BYTE(16#CC), ?BYTE(16#AB)>>).
+
+%% TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = {0xCC, 0xAC}
+-define(TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256, <<?BYTE(16#CC), ?BYTE(16#AC)>>).
+
+%% TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = {0xCC, 0xAD}
+-define(TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256, <<?BYTE(16#CC), ?BYTE(16#AD)>>).
+
+%% TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 = {0xCC, 0xAE}
+-define(TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256, <<?BYTE(16#CC), ?BYTE(16#AE)>>).
+
+
+
+%% RFC 6655 - TLS-1.2 cipher suites
+
+%% TLS_RSA_WITH_AES_128_CCM = {0xC0,0x9C}
+-define(TLS_RSA_WITH_AES_128_CCM, <<?BYTE(16#C0), ?BYTE(16#9C)>>).
+
+%% TLS_RSA_WITH_AES_256_CCM = {0xC0,0x9D}
+-define(TLS_RSA_WITH_AES_256_CCM, <<?BYTE(16#C0), ?BYTE(16#9D)>>).
+
+%% TLS_DHE_RSA_WITH_AES_256_CCM = {0xC0,0x9E}
+-define(TLS_DHE_RSA_WITH_AES_256_CCM, <<?BYTE(16#C0), ?BYTE(16#9E)>>).
+
+%% TLS_DHE_RSA_WITH_AES_128_CCM = {0xC0,0x9F}
+-define(TLS_DHE_RSA_WITH_AES_128_CCM, <<?BYTE(16#C0), ?BYTE(16#9F)>>).
+
+%% TLS_RSA_WITH_AES_256_CCM_8 = {0xC0,0x9A0}
+-define(TLS_RSA_WITH_AES_256_CCM_8, <<?BYTE(16#C0), ?BYTE(16#A0)>>).
+
+%% TLS_RSA_WITH_AES_128_CCM_8 = {0xC0,0xA1}
+-define(TLS_RSA_WITH_AES_128_CCM_8, <<?BYTE(16#C0), ?BYTE(16#A1)>>).
+
+%% TLS_DHE_RSA_WITH_AES_128_CCM_8 = {0xC0,0xA2}
+-define(TLS_DHE_RSA_WITH_AES_128_CCM_8, <<?BYTE(16#C0), ?BYTE(16#A2)>>).
+
+%% TLS_DHE_RSA_WITH_AES_256_CCM_8 = {0xC0,0xA3}
+-define(TLS_DHE_RSA_WITH_AES_256_CCM_8, <<?BYTE(16#C0), ?BYTE(16#A3)>>).
+
+%% TLS_PSK_WITH_AES_128_CCM = {0xC0,0xA4}
+-define(TLS_PSK_WITH_AES_128_CCM, <<?BYTE(16#C0), ?BYTE(16#A4)>>).
+
+%% TLS_PSK_WITH_AES_256_CCM = {0xC0,0xA5)
+-define(TLS_PSK_WITH_AES_256_CCM, <<?BYTE(16#C0), ?BYTE(16#A5)>>).
+
+%% TLS_DHE_PSK_WITH_AES_128_CCM = {0xC0,0xA6}
+-define(TLS_DHE_PSK_WITH_AES_128_CCM, <<?BYTE(16#C0), ?BYTE(16#A6)>>).
+
+%% TLS_DHE_PSK_WITH_AES_256_CCM = {0xC0,0xA7}
+-define(TLS_DHE_PSK_WITH_AES_256_CCM, <<?BYTE(16#C0), ?BYTE(16#A7)>>).
+
+%% TLS_PSK_WITH_AES_128_CCM_8 = {0xC0,0xA8}
+-define(TLS_PSK_WITH_AES_128_CCM_8, <<?BYTE(16#C0), ?BYTE(16#A8)>>).
+
+%% TLS_PSK_WITH_AES_256_CCM_8 = {0xC0,0xA9)
+-define(TLS_PSK_WITH_AES_256_CCM_8, <<?BYTE(16#C0), ?BYTE(16#A9)>>).
+
+%% TLS_PSK_DHE_WITH_AES_128_CCM_8 = {0xC0,0xAA}
+-define(TLS_PSK_DHE_WITH_AES_128_CCM_8, <<?BYTE(16#C0), ?BYTE(16#AA)>>).
+
+%% TLS_PSK_DHE_WITH_AES_256_CCM_8 = << ?BYTE(0xC0,0xAB}
+-define(TLS_PSK_DHE_WITH_AES_256_CCM_8, <<?BYTE(16#C0),?BYTE(16#AB)>>).
+
+
+%%% TLS 1.3 cipher suites RFC8446
+
+%% TLS_AES_128_GCM_SHA256 = {0x13,0x01}
+-define(TLS_AES_128_GCM_SHA256, <<?BYTE(16#13), ?BYTE(16#01)>>).
+
+%% TLS_AES_256_GCM_SHA384 = {0x13,0x02}
+-define(TLS_AES_256_GCM_SHA384, <<?BYTE(16#13),?BYTE(16#02)>>).
+
+%% TLS_CHACHA20_POLY1305_SHA256 = {0x13,0x03}
+-define(TLS_CHACHA20_POLY1305_SHA256, <<?BYTE(16#13),?BYTE(16#03)>>).
-%% TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = {0xcc, 0x14}
--define(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, <<?BYTE(16#CC), ?BYTE(16#14)>>).
+%% %% TLS_AES_128_CCM_SHA256 = {0x13,0x04}
+-define(TLS_AES_128_CCM_SHA256, <<?BYTE(16#13), ?BYTE(16#04)>>).
-%% TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = {0xcc, 0x15}
--define(TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, <<?BYTE(16#CC), ?BYTE(16#15)>>).
+%% %% TLS_AES_128_CCM_8_SHA256 = {0x13,0x05}
+-define(TLS_AES_128_CCM_8_SHA256, <<?BYTE(16#13),?BYTE(16#05)>>).
-endif. % -ifdef(ssl_cipher).
diff --git a/lib/ssl/src/ssl_cipher_format.erl b/lib/ssl/src/ssl_cipher_format.erl
new file mode 100644
index 0000000000..bca1022b5f
--- /dev/null
+++ b/lib/ssl/src/ssl_cipher_format.erl
@@ -0,0 +1,1919 @@
+%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Convert between diffrent cipher suite representations
+%%
+%%----------------------------------------------------------------------
+-module(ssl_cipher_format).
+
+-include("ssl_api.hrl").
+-include("ssl_cipher.hrl").
+-include("ssl_internal.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+-export_type([old_erl_cipher_suite/0, openssl_cipher_suite/0, cipher_suite/0]).
+
+-type internal_cipher() :: null | ssl:cipher().
+-type internal_hash() :: null | ssl:hash().
+-type internal_kex_algo() :: null | ssl:kex_algo().
+-type internal_erl_cipher_suite() :: #{key_exchange := internal_kex_algo(),
+ cipher := internal_cipher(),
+ mac := internal_hash() | aead,
+ prf := internal_hash() | default_prf %% Old cipher suites, version dependent
+ }.
+-type old_erl_cipher_suite() :: {ssl:kex_algo(), internal_cipher(), internal_hash()} % Pre TLS 1.2
+ %% TLS 1.2, internally PRE TLS 1.2 will use default_prf
+ | {ssl:kex_algo(), internal_cipher(), internal_hash(),
+ internal_hash() | default_prf}.
+-type cipher_suite() :: binary().
+-type openssl_cipher_suite() :: string().
+
+
+-export([suite_map_to_bin/1, %% Binary format
+ suite_bin_to_map/1, %% Erlang API format
+ suite_map_to_str/1, %% RFC string
+ suite_str_to_map/1,
+ suite_map_to_openssl_str/1, %% OpenSSL name
+ suite_openssl_str_to_map/1,
+ suite_legacy/1 %% Erlang legacy format
+ ]).
+
+%%--------------------------------------------------------------------
+-spec suite_map_to_str(internal_erl_cipher_suite()) -> string().
+%%
+%% Description: Return the string representation of a cipher suite.
+%%--------------------------------------------------------------------
+suite_map_to_str(#{key_exchange := null,
+ cipher := null,
+ mac := null,
+ prf := null}) ->
+ "TLS_EMPTY_RENEGOTIATION_INFO_SCSV";
+suite_map_to_str(#{key_exchange := any,
+ cipher := Cipher,
+ mac := aead,
+ prf := PRF}) ->
+ "TLS_" ++ string:to_upper(atom_to_list(Cipher)) ++
+ "_" ++ string:to_upper(atom_to_list(PRF));
+suite_map_to_str(#{key_exchange := Kex,
+ cipher := Cipher,
+ mac := aead,
+ prf := PRF}) ->
+ "TLS_" ++ string:to_upper(atom_to_list(Kex)) ++
+ "_WITH_" ++ string:to_upper(atom_to_list(Cipher)) ++
+ "_" ++ string:to_upper(atom_to_list(PRF));
+suite_map_to_str(#{key_exchange := Kex,
+ cipher := Cipher,
+ mac := Mac}) ->
+ "TLS_" ++ string:to_upper(atom_to_list(Kex)) ++
+ "_WITH_" ++ string:to_upper(atom_to_list(Cipher)) ++
+ "_" ++ string:to_upper(atom_to_list(Mac)).
+
+suite_str_to_map("TLS_EMPTY_RENEGOTIATION_INFO_SCSV") ->
+ #{key_exchange => null,
+ cipher => null,
+ mac => null,
+ prf => null};
+suite_str_to_map(SuiteStr)->
+ Str0 = string:prefix(SuiteStr, "TLS_"),
+ case string:split(Str0, "_WITH_") of
+ [Rest] ->
+ tls_1_3_suite_str_to_map(Rest);
+ [Prefix, Kex | Rest] when Prefix == "SPR";
+ Prefix == "PSK";
+ Prefix == "DHE";
+ Prefix == "ECDHE"
+ ->
+ pre_tls_1_3_suite_str_to_map(Prefix ++ "_" ++ Kex, Rest);
+ [Kex| Rest] ->
+ pre_tls_1_3_suite_str_to_map(Kex, Rest)
+ end.
+
+suite_map_to_openssl_str(#{key_exchange := any,
+ mac := aead} = Suite) ->
+ %% TLS 1.3 OpenSSL finally use RFC names
+ suite_map_to_str(Suite);
+suite_map_to_openssl_str(#{key_exchange := null} = Suite) ->
+ %% TLS_EMPTY_RENEGOTIATION_INFO_SCSV
+ suite_map_to_str(Suite);
+suite_map_to_openssl_str(#{key_exchange := rsa = Kex,
+ cipher := Cipher,
+ mac := Mac}) when Cipher == "des_cbc";
+ Cipher == "3des_ede_cbc" ->
+ openssl_cipher_name(Kex, string:to_upper(atom_to_list(Cipher))) ++
+ "-" ++ string:to_upper(atom_to_list(Mac));
+suite_map_to_openssl_str(#{key_exchange := Kex,
+ cipher := chacha20_poly1305 = Cipher,
+ mac := aead}) ->
+ openssl_suite_start(string:to_upper(atom_to_list(Kex)))
+ ++ openssl_cipher_name(Kex, string:to_upper(atom_to_list(Cipher)));
+suite_map_to_openssl_str(#{key_exchange := Kex,
+ cipher := Cipher,
+ mac := aead,
+ prf := PRF}) ->
+ openssl_suite_start(string:to_upper(atom_to_list(Kex)))
+ ++ openssl_cipher_name(Kex, string:to_upper(atom_to_list(Cipher))) ++
+ "-" ++ string:to_upper(atom_to_list(PRF));
+suite_map_to_openssl_str(#{key_exchange := Kex,
+ cipher := Cipher,
+ mac := Mac}) ->
+ openssl_suite_start(string:to_upper(atom_to_list(Kex)))
+ ++ openssl_cipher_name(Kex, string:to_upper(atom_to_list(Cipher))) ++
+ "-" ++ string:to_upper(atom_to_list(Mac)).
+
+
+suite_openssl_str_to_map("TLS_" ++ _ = SuiteStr) ->
+ suite_str_to_map(SuiteStr);
+suite_openssl_str_to_map("DES-CBC-SHA") ->
+ suite_str_to_map("TLS_RSA_WITH_DES_CBC_SHA");
+suite_openssl_str_to_map("DES-CBC3-SHA") ->
+ suite_str_to_map("TLS_RSA_WITH_3DES_EDE_CBC_SHA");
+suite_openssl_str_to_map("SRP-DSS-DES-CBC3-SHA") ->
+ suite_str_to_map("TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA");
+suite_openssl_str_to_map("DHE-RSA-" ++ Rest) ->
+ suite_openssl_str_to_map("DHE-RSA", Rest);
+suite_openssl_str_to_map("DHE-DSS-" ++ Rest) ->
+ suite_openssl_str_to_map("DHE-DSS", Rest);
+suite_openssl_str_to_map("EDH-RSA-" ++ Rest) ->
+ suite_openssl_str_to_map("DHE-RSA", Rest);
+suite_openssl_str_to_map("EDH-DSS-" ++ Rest) ->
+ suite_openssl_str_to_map("DHE-DSS", Rest);
+suite_openssl_str_to_map("DES" ++ _ = Rest) ->
+ suite_openssl_str_to_map("RSA", Rest);
+suite_openssl_str_to_map("AES" ++ _ = Rest) ->
+ suite_openssl_str_to_map("RSA", Rest);
+suite_openssl_str_to_map("RC4" ++ _ = Rest) ->
+ suite_openssl_str_to_map("RSA", Rest);
+suite_openssl_str_to_map("ECDH-RSA-" ++ Rest) ->
+ suite_openssl_str_to_map("ECDH-RSA", Rest);
+suite_openssl_str_to_map("ECDH-ECDSA-" ++ Rest) ->
+ suite_openssl_str_to_map("ECDH-ECDSA", Rest);
+suite_openssl_str_to_map("ECDHE-RSA-" ++ Rest) ->
+ suite_openssl_str_to_map("ECDHE-RSA", Rest);
+suite_openssl_str_to_map("ECDHE-ECDSA-" ++ Rest) ->
+ suite_openssl_str_to_map("ECDHE-ECDSA", Rest);
+suite_openssl_str_to_map("RSA-PSK-" ++ Rest) ->
+ suite_openssl_str_to_map("RSA-PSK", Rest);
+suite_openssl_str_to_map("RSA-" ++ Rest) ->
+ suite_openssl_str_to_map("RSA", Rest);
+suite_openssl_str_to_map("DHE-PSK-" ++ Rest) ->
+ suite_openssl_str_to_map("DHE-PSK", Rest);
+suite_openssl_str_to_map("ECDHE-PSK-" ++ Rest) ->
+ suite_openssl_str_to_map("ECDHE-PSK", Rest);
+suite_openssl_str_to_map("PSK-" ++ Rest) ->
+ suite_openssl_str_to_map("PSK", Rest);
+suite_openssl_str_to_map("SRP-RSA-" ++ Rest) ->
+ suite_openssl_str_to_map("SRP-RSA", Rest);
+suite_openssl_str_to_map("SRP-DSS-" ++ Rest) ->
+ suite_openssl_str_to_map("SRP-DSS", Rest);
+suite_openssl_str_to_map("SRP-" ++ Rest) ->
+ suite_openssl_str_to_map("SRP", Rest).
+
+%%--------------------------------------------------------------------
+-spec suite_bin_to_map(cipher_suite()) -> internal_erl_cipher_suite().
+%%
+%% Description: Return erlang cipher suite definition.
+%% Note: Currently not supported suites are commented away.
+%% They should be supported or removed in the future.
+%%-------------------------------------------------------------------
+%% TLS v1.1 suites
+suite_bin_to_map(?TLS_NULL_WITH_NULL_NULL) ->
+ #{key_exchange => null,
+ cipher => null,
+ mac => null,
+ prf => null};
+%% RFC 5746 - Not a real cipher suite used to signal empty "renegotiation_info" extension
+%% to avoid handshake failure from old servers that do not ignore
+%% hello extension data as they should.
+suite_bin_to_map(?TLS_EMPTY_RENEGOTIATION_INFO_SCSV) ->
+ #{key_exchange => null,
+ cipher => null,
+ mac => null,
+ prf => null};
+suite_bin_to_map(?TLS_RSA_WITH_RC4_128_MD5) ->
+ #{key_exchange => rsa,
+ cipher => rc4_128,
+ mac => md5,
+ prf => default_prf};
+suite_bin_to_map(?TLS_RSA_WITH_RC4_128_SHA) ->
+ #{key_exchange => rsa,
+ cipher => rc4_128,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_RSA_WITH_DES_CBC_SHA) ->
+ #{key_exchange => rsa,
+ cipher => des_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => rsa,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_DHE_DSS_WITH_DES_CBC_SHA) ->
+ #{key_exchange => dhe_dss,
+ cipher => des_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => dhe_dss,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_DHE_RSA_WITH_DES_CBC_SHA) ->
+ #{key_exchange => dhe_rsa,
+ cipher => des_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => dhe_rsa,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+%%% TSL V1.1 AES suites
+suite_bin_to_map(?TLS_RSA_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_DHE_DSS_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => dhe_dss,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_DHE_RSA_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => dhe_rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_RSA_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => rsa,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => dhe_dss,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => dhe_rsa,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+%% TLS v1.2 suites
+%% suite_bin_to_map(?TLS_RSA_WITH_NULL_SHA) ->
+%% {rsa, null, sha, default_prf};
+suite_bin_to_map(?TLS_RSA_WITH_AES_128_CBC_SHA256) ->
+ #{key_exchange => rsa,
+ cipher => aes_128_cbc,
+ mac => sha256,
+ prf => default_prf};
+suite_bin_to_map(?TLS_RSA_WITH_AES_256_CBC_SHA256) ->
+ #{key_exchange => rsa,
+ cipher => aes_256_cbc,
+ mac => sha256,
+ prf => default_prf};
+suite_bin_to_map(?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256) ->
+ #{key_exchange => dhe_dss,
+ cipher => aes_128_cbc,
+ mac => sha256,
+ prf => default_prf};
+suite_bin_to_map(?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256) ->
+ #{key_exchange => dhe_rsa,
+ cipher => aes_128_cbc,
+ mac => sha256,
+ prf => default_prf};
+suite_bin_to_map(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256) ->
+ #{key_exchange => dhe_dss,
+ cipher => aes_256_cbc,
+ mac => sha256,
+ prf => default_prf};
+suite_bin_to_map(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256) ->
+ #{key_exchange => dhe_rsa,
+ cipher => aes_256_cbc,
+ mac => sha256,
+ prf => default_prf};
+%% not defined YET:
+%% TLS_DH_DSS_WITH_AES_128_CBC_SHA256 DH_DSS AES_128_CBC SHA256
+%% TLS_DH_RSA_WITH_AES_128_CBC_SHA256 DH_RSA AES_128_CBC SHA256
+%% TLS_DH_DSS_WITH_AES_256_CBC_SHA256 DH_DSS AES_256_CBC SHA256
+%% TLS_DH_RSA_WITH_AES_256_CBC_SHA256 DH_RSA AES_256_CBC SHA256
+%%% DH-ANON deprecated by TLS spec and not available
+%%% by default, but good for testing purposes.
+suite_bin_to_map(?TLS_DH_anon_WITH_RC4_128_MD5) ->
+ #{key_exchange => dh_anon,
+ cipher => rc4_128,
+ mac => md5,
+ prf => default_prf};
+suite_bin_to_map(?TLS_DH_anon_WITH_DES_CBC_SHA) ->
+ #{key_exchange => dh_anon,
+ cipher => des_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => dh_anon,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_DH_anon_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => dh_anon,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_DH_anon_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => dh_anon,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_DH_anon_WITH_AES_128_CBC_SHA256) ->
+ #{key_exchange => dh_anon,
+ cipher => aes_128_cbc,
+ mac => sha256,
+ prf => default_prf};
+suite_bin_to_map(?TLS_DH_anon_WITH_AES_256_CBC_SHA256) ->
+ #{key_exchange => dh_anon,
+ cipher => aes_256_cbc,
+ mac => sha256,
+ prf => default_prf};
+%%% PSK Cipher Suites RFC 4279
+suite_bin_to_map(?TLS_PSK_WITH_RC4_128_SHA) ->
+ #{key_exchange => psk,
+ cipher => rc4_128,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_PSK_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => psk,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_PSK_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => psk,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_PSK_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => psk,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_DHE_PSK_WITH_RC4_128_SHA) ->
+ #{key_exchange => dhe_psk,
+ cipher => rc4_128,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => dhe_psk,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_DHE_PSK_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => dhe_psk,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_DHE_PSK_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => dhe_psk,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_RSA_PSK_WITH_RC4_128_SHA) ->
+ #{key_exchange => rsa_psk,
+ cipher => rc4_128,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => rsa_psk,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_RSA_PSK_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => rsa_psk,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_RSA_PSK_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => rsa_psk,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+%%% PSK NULL Cipher Suites RFC 4785
+suite_bin_to_map(?TLS_PSK_WITH_NULL_SHA) ->
+ #{key_exchange => psk,
+ cipher => null,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_DHE_PSK_WITH_NULL_SHA) ->
+ #{key_exchange => dhe_psk,
+ cipher => null,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_RSA_PSK_WITH_NULL_SHA) ->
+ #{key_exchange => rsa_psk,
+ cipher => null,
+ mac => sha,
+ prf => default_prf};
+%%% TLS 1.2 PSK Cipher Suites RFC 5487
+suite_bin_to_map(?TLS_PSK_WITH_AES_128_GCM_SHA256) ->
+ #{key_exchange => psk,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256};
+suite_bin_to_map(?TLS_PSK_WITH_AES_256_GCM_SHA384) ->
+ #{key_exchange => psk,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384};
+suite_bin_to_map(?TLS_DHE_PSK_WITH_AES_128_GCM_SHA256) ->
+ #{key_exchange => dhe_psk,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256};
+suite_bin_to_map(?TLS_DHE_PSK_WITH_AES_256_GCM_SHA384) ->
+ #{key_exchange => dhe_psk,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384};
+suite_bin_to_map(?TLS_RSA_PSK_WITH_AES_128_GCM_SHA256) ->
+ #{key_exchange => rsa_psk,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256};
+suite_bin_to_map(?TLS_RSA_PSK_WITH_AES_256_GCM_SHA384) ->
+ #{key_exchange => rsa_psk,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384};
+suite_bin_to_map(?TLS_PSK_WITH_AES_128_CBC_SHA256) ->
+ #{key_exchange => psk,
+ cipher => aes_128_cbc,
+ mac => sha256,
+ prf => default_prf};
+suite_bin_to_map(?TLS_PSK_WITH_AES_256_CBC_SHA384) ->
+ #{key_exchange => psk,
+ cipher => aes_256_cbc,
+ mac => sha384,
+ prf => sha384};
+suite_bin_to_map(?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256) ->
+ #{key_exchange => dhe_psk,
+ cipher => aes_128_cbc,
+ mac => sha256,
+ prf => default_prf};
+suite_bin_to_map(?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384) ->
+ #{key_exchange => dhe_psk,
+ cipher => aes_256_cbc,
+ mac => sha384,
+ prf => sha384};
+suite_bin_to_map(?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256) ->
+ #{key_exchange => rsa_psk,
+ cipher => aes_128_cbc,
+ mac => sha256,
+ prf => default_prf};
+suite_bin_to_map(?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384) ->
+ #{key_exchange => rsa_psk,
+ cipher => aes_256_cbc,
+ mac => sha384,
+ prf => sha384};
+suite_bin_to_map(?TLS_PSK_WITH_NULL_SHA256) ->
+ #{key_exchange => psk,
+ cipher => null,
+ mac => sha256,
+ prf => default_prf};
+suite_bin_to_map(?TLS_PSK_WITH_NULL_SHA384) ->
+ #{key_exchange => psk,
+ cipher => null,
+ mac => sha384,
+ prf => sha384};
+suite_bin_to_map(?TLS_DHE_PSK_WITH_NULL_SHA256) ->
+ #{key_exchange => dhe_psk,
+ cipher => null,
+ mac => sha256,
+ prf => default_prf};
+suite_bin_to_map(?TLS_DHE_PSK_WITH_NULL_SHA384) ->
+ #{key_exchange => dhe_psk,
+ cipher => null,
+ mac => sha384,
+ prf => sha384};
+suite_bin_to_map(?TLS_RSA_PSK_WITH_NULL_SHA256) ->
+ #{key_exchange => rsa_psk,
+ cipher => null,
+ mac => sha256,
+ prf => default_prf};
+suite_bin_to_map(?TLS_RSA_PSK_WITH_NULL_SHA384) ->
+ #{key_exchange => rsa_psk,
+ cipher => null,
+ mac => sha384,
+ prf => sha384};
+%%% ECDHE PSK Cipher Suites RFC 5489
+suite_bin_to_map(?TLS_ECDHE_PSK_WITH_RC4_128_SHA) ->
+ #{key_exchange => ecdhe_psk,
+ cipher => rc4_128,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => ecdhe_psk,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => ecdhe_psk,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => ecdhe_psk,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256) ->
+ #{key_exchange => ecdhe_psk,
+ cipher => aes_128_cbc,
+ mac => sha256,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384) ->
+ #{key_exchange => ecdhe_psk,
+ cipher => aes_256_cbc,
+ mac => sha384,
+ prf => sha384};
+suite_bin_to_map(?TLS_ECDHE_PSK_WITH_NULL_SHA256) ->
+ #{key_exchange => ecdhe_psk,
+ cipher => null,
+ mac => sha256,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDHE_PSK_WITH_NULL_SHA384) ->
+ #{key_exchange => ecdhe_psk,
+ cipher => null, mac => sha384,
+ prf => sha384};
+%%% ECDHE_PSK with AES-GCM and AES-CCM Cipher Suites, draft-ietf-tls-ecdhe-psk-aead-05
+suite_bin_to_map(?TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256) ->
+ #{key_exchange => ecdhe_psk,
+ cipher => aes_128_gcm,
+ mac => null,
+ prf => sha256};
+suite_bin_to_map(?TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384) ->
+ #{key_exchange => ecdhe_psk,
+ cipher => aes_256_gcm,
+ mac => null,
+ prf => sha384};
+suite_bin_to_map(?TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256) ->
+ #{key_exchange => ecdhe_psk,
+ cipher => aes_128_ccm,
+ mac => null,
+ prf => sha256};
+suite_bin_to_map(?TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256) ->
+ #{key_exchange => ecdhe_psk,
+ cipher => aes_128_ccm_8,
+ mac => null,
+ prf => sha256};
+%%% SRP Cipher Suites RFC 5054
+suite_bin_to_map(?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => srp_anon,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => srp_rsa,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => srp_dss,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_SRP_SHA_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => srp_anon,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => srp_rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => srp_dss,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_SRP_SHA_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => srp_anon,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => srp_rsa,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => srp_dss,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+%% RFC 4492 EC TLS suites
+suite_bin_to_map(?TLS_ECDH_ECDSA_WITH_NULL_SHA) ->
+ #{key_exchange => ecdh_ecdsa,
+ cipher => null,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDH_ECDSA_WITH_RC4_128_SHA) ->
+ #{key_exchange => ecdh_ecdsa,
+ cipher => rc4_128,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => ecdh_ecdsa,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => ecdh_ecdsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => ecdh_ecdsa,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDHE_ECDSA_WITH_NULL_SHA) ->
+ #{key_exchange => ecdhe_ecdsa,
+ cipher => null,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA) ->
+ #{key_exchange => ecdhe_ecdsa,
+ cipher => rc4_128,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => ecdhe_ecdsa,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => ecdhe_ecdsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => ecdhe_ecdsa,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDH_RSA_WITH_NULL_SHA) ->
+ #{key_exchange => ecdh_rsa,
+ cipher => null,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDH_RSA_WITH_RC4_128_SHA) ->
+ #{key_exchange => ecdh_rsa,
+ cipher => rc4_128,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => ecdh_rsa,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => ecdh_rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => ecdh_rsa,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDHE_RSA_WITH_NULL_SHA) ->
+ #{key_exchange => ecdhe_rsa,
+ cipher => null,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDHE_RSA_WITH_RC4_128_SHA) ->
+ #{key_exchange => ecdhe_rsa,
+ cipher => rc4_128,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => ecdhe_rsa,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => ecdhe_rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => ecdhe_rsa,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDH_anon_WITH_NULL_SHA) ->
+ #{key_exchange => ecdh_anon,
+ cipher => null,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDH_anon_WITH_RC4_128_SHA) ->
+ #{key_exchange => ecdh_anon,
+ cipher => rc4_128,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => ecdh_anon,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDH_anon_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => ecdh_anon,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_bin_to_map(?TLS_ECDH_anon_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => ecdh_anon,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+%% RFC 5289 EC TLS suites
+suite_bin_to_map(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) ->
+ #{key_exchange => ecdhe_ecdsa,
+ cipher => aes_128_cbc,
+ mac => sha256,
+ prf => sha256};
+suite_bin_to_map(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384) ->
+ #{key_exchange => ecdhe_ecdsa,
+ cipher => aes_256_cbc,
+ mac => sha384,
+ prf => sha384};
+suite_bin_to_map(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256) ->
+ #{key_exchange => ecdh_ecdsa,
+ cipher => aes_128_cbc,
+ mac => sha256,
+ prf => sha256};
+suite_bin_to_map(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384) ->
+ #{key_exchange => ecdh_ecdsa,
+ cipher => aes_256_cbc,
+ mac => sha384,
+ prf => sha384};
+suite_bin_to_map(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) ->
+ #{key_exchange => ecdhe_rsa,
+ cipher => aes_128_cbc,
+ mac => sha256,
+ prf => sha256};
+suite_bin_to_map(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) ->
+ #{key_exchange => ecdhe_rsa,
+ cipher => aes_256_cbc,
+ mac => sha384,
+ prf => sha384};
+suite_bin_to_map(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256) ->
+ #{key_exchange => ecdh_rsa,
+ cipher => aes_128_cbc,
+ mac => sha256,
+ prf => sha256};
+suite_bin_to_map(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384) ->
+ #{key_exchange => ecdh_rsa,
+ cipher => aes_256_cbc,
+ mac => sha384,
+ prf => sha384};
+%% RFC 5288 AES-GCM Cipher Suites
+suite_bin_to_map(?TLS_RSA_WITH_AES_128_GCM_SHA256) ->
+ #{key_exchange => rsa,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256};
+suite_bin_to_map(?TLS_RSA_WITH_AES_256_GCM_SHA384) ->
+ #{key_exchange => rsa,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384};
+suite_bin_to_map(?TLS_DHE_RSA_WITH_AES_128_GCM_SHA256) ->
+ #{key_exchange => dhe_rsa,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256};
+suite_bin_to_map(?TLS_DHE_RSA_WITH_AES_256_GCM_SHA384) ->
+ #{key_exchange => dhe_rsa,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384};
+suite_bin_to_map(?TLS_DH_RSA_WITH_AES_128_GCM_SHA256) ->
+ #{key_exchange => dh_rsa,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256};
+suite_bin_to_map(?TLS_DH_RSA_WITH_AES_256_GCM_SHA384) ->
+ #{key_exchange => dh_rsa,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384};
+suite_bin_to_map(?TLS_DHE_DSS_WITH_AES_128_GCM_SHA256) ->
+ #{key_exchange => dhe_dss,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256};
+suite_bin_to_map(?TLS_DHE_DSS_WITH_AES_256_GCM_SHA384) ->
+ #{key_exchange => dhe_dss,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384};
+suite_bin_to_map(?TLS_DH_DSS_WITH_AES_128_GCM_SHA256) ->
+ #{key_exchange => dh_dss,
+ cipher => aes_128_gcm,
+ mac => null,
+ prf => sha256};
+suite_bin_to_map(?TLS_DH_DSS_WITH_AES_256_GCM_SHA384) ->
+ #{key_exchange => dh_dss,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384};
+suite_bin_to_map(?TLS_DH_anon_WITH_AES_128_GCM_SHA256) ->
+ #{key_exchange => dh_anon,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256};
+suite_bin_to_map(?TLS_DH_anon_WITH_AES_256_GCM_SHA384) ->
+ #{key_exchange => dh_anon,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384};
+%% RFC 5289 ECC AES-GCM Cipher Suites
+suite_bin_to_map(?TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) ->
+ #{key_exchange => ecdhe_ecdsa,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256};
+suite_bin_to_map(?TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384) ->
+ #{key_exchange => ecdhe_ecdsa,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384};
+suite_bin_to_map(?TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256) ->
+ #{key_exchange => ecdh_ecdsa,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256};
+suite_bin_to_map(?TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384) ->
+ #{key_exchange => ecdh_ecdsa,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384};
+suite_bin_to_map(?TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) ->
+ #{key_exchange => ecdhe_rsa,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256};
+suite_bin_to_map(?TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) ->
+ #{key_exchange => ecdhe_rsa,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384};
+suite_bin_to_map(?TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256) ->
+ #{key_exchange => ecdh_rsa,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256};
+suite_bin_to_map(?TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384) ->
+ #{key_exchange => ecdh_rsa,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384};
+suite_bin_to_map(?TLS_PSK_WITH_AES_128_CCM) ->
+ #{key_exchange => psk,
+ cipher => aes_128_ccm,
+ mac => aead,
+ prf => sha256};
+suite_bin_to_map(?TLS_PSK_WITH_AES_256_CCM) ->
+ #{key_exchange => psk,
+ cipher => aes_256_ccm,
+ mac => aead,
+ prf => sha256};
+suite_bin_to_map(?TLS_DHE_PSK_WITH_AES_128_CCM) ->
+ #{key_exchange => dhe_psk,
+ cipher => aes_128_ccm,
+ mac => aead,
+ prf => sha256};
+suite_bin_to_map(?TLS_DHE_PSK_WITH_AES_256_CCM) ->
+ #{key_exchange => dhe_psk,
+ cipher => aes_256_ccm,
+ mac => aead,
+ prf => sha256};
+suite_bin_to_map(?TLS_PSK_WITH_AES_128_CCM_8) ->
+ #{key_exchange => psk,
+ cipher => aes_128_ccm_8,
+ mac => aead,
+ prf => sha256};
+suite_bin_to_map(?TLS_PSK_WITH_AES_256_CCM_8) ->
+ #{key_exchange => psk,
+ cipher => aes_256_ccm_8,
+ mac => aead,
+ prf => sha256};
+suite_bin_to_map(?TLS_PSK_DHE_WITH_AES_128_CCM_8) ->
+ #{key_exchange => dhe_psk,
+ cipher => aes_128_ccm_8,
+ mac => aead,
+ prf => sha256};
+suite_bin_to_map(?TLS_PSK_DHE_WITH_AES_256_CCM_8) ->
+ #{key_exchange => dhe_psk,
+ cipher => aes_256_ccm_8,
+ mac => aead,
+ prf => sha256};
+suite_bin_to_map(#{key_exchange := psk_dhe,
+ cipher := aes_256_ccm_8,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_PSK_DHE_WITH_AES_256_CCM_8;
+
+% draft-agl-tls-chacha20poly1305-04 Chacha20/Poly1305 Suites
+suite_bin_to_map(?TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256) ->
+ #{key_exchange => ecdhe_rsa,
+ cipher => chacha20_poly1305,
+ mac => aead,
+ prf => sha256};
+suite_bin_to_map(?TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256) ->
+ #{key_exchange => ecdhe_ecdsa,
+ cipher => chacha20_poly1305,
+ mac => aead,
+ prf => sha256};
+suite_bin_to_map(?TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256) ->
+ #{key_exchange => dhe_rsa,
+ cipher => chacha20_poly1305,
+ mac => aead,
+ prf => sha256};
+%% TLS 1.3 Cipher Suites RFC8446
+suite_bin_to_map(?TLS_AES_128_GCM_SHA256) ->
+ #{key_exchange => any,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256};
+suite_bin_to_map(?TLS_AES_256_GCM_SHA384) ->
+ #{key_exchange => any,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384};
+suite_bin_to_map(?TLS_CHACHA20_POLY1305_SHA256) ->
+ #{key_exchange => any,
+ cipher => chacha20_poly1305,
+ mac => aead,
+ prf => sha256};
+suite_bin_to_map(?TLS_AES_128_CCM_SHA256) ->
+ #{key_exchange => any,
+ cipher => aes_128_ccm,
+ mac => aead,
+ prf => sha256}.
+%% suite_bin_to_map(?TLS_AES_128_CCM_8_SHA256) ->
+%% #{key_exchange => any,
+%% cipher => aes_128_ccm_8,
+%% mac => aead,
+%% prf => sha256}.
+
+%%--------------------------------------------------------------------
+-spec suite_legacy(cipher_suite() | internal_erl_cipher_suite()) -> old_erl_cipher_suite().
+%%
+%% Description: Return erlang cipher suite definition. Filters last value
+%% for now (compatibility reasons).
+%%--------------------------------------------------------------------
+suite_legacy(Bin) when is_binary(Bin) ->
+ suite_legacy(suite_bin_to_map(Bin));
+suite_legacy(#{key_exchange := KeyExchange, cipher := Cipher,
+ mac := Hash, prf := Prf}) ->
+ case Prf of
+ default_prf ->
+ {KeyExchange, Cipher, Hash};
+ _ ->
+ {KeyExchange, Cipher, Hash, Prf}
+ end.
+
+%%--------------------------------------------------------------------
+-spec suite_map_to_bin(internal_erl_cipher_suite()) -> cipher_suite().
+%%
+%% Description: Return TLS cipher suite definition.
+%%--------------------------------------------------------------------
+%% TLS v1.1 suites
+suite_map_to_bin(#{key_exchange := rsa,
+ cipher := rc4_128,
+ mac := md5}) ->
+ ?TLS_RSA_WITH_RC4_128_MD5;
+suite_map_to_bin(#{key_exchange := rsa,
+ cipher := rc4_128,
+ mac := sha}) ->
+ ?TLS_RSA_WITH_RC4_128_SHA;
+suite_map_to_bin(#{key_exchange := rsa,
+ cipher := des_cbc,
+ mac := sha}) ->
+ ?TLS_RSA_WITH_DES_CBC_SHA;
+suite_map_to_bin(#{key_exchange := rsa,
+ cipher :='3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_RSA_WITH_3DES_EDE_CBC_SHA;
+suite_map_to_bin(#{key_exchange := dhe_dss,
+ cipher:= des_cbc,
+ mac := sha}) ->
+ ?TLS_DHE_DSS_WITH_DES_CBC_SHA;
+suite_map_to_bin(#{key_exchange := dhe_dss,
+ cipher:= '3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA;
+suite_map_to_bin(#{key_exchange := dhe_rsa,
+ cipher:= des_cbc,
+ mac := sha}) ->
+ ?TLS_DHE_RSA_WITH_DES_CBC_SHA;
+suite_map_to_bin(#{key_exchange := dhe_rsa,
+ cipher:= '3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
+suite_map_to_bin(#{key_exchange := dh_anon,
+ cipher:= rc4_128,
+ mac := md5}) ->
+ ?TLS_DH_anon_WITH_RC4_128_MD5;
+suite_map_to_bin(#{key_exchange := dh_anon,
+ cipher:= des_cbc,
+ mac := sha}) ->
+ ?TLS_DH_anon_WITH_DES_CBC_SHA;
+suite_map_to_bin(#{key_exchange := dh_anon,
+ cipher:= '3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
+%%% TSL V1.1 AES suites
+suite_map_to_bin(#{key_exchange := rsa,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_RSA_WITH_AES_128_CBC_SHA;
+suite_map_to_bin(#{key_exchange := dhe_dss,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA;
+suite_map_to_bin(#{key_exchange := dhe_rsa,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
+suite_map_to_bin(#{key_exchange := dh_anon,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_DH_anon_WITH_AES_128_CBC_SHA;
+suite_map_to_bin(#{key_exchange := rsa,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_RSA_WITH_AES_256_CBC_SHA;
+suite_map_to_bin(#{key_exchange := dhe_dss,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA;
+suite_map_to_bin(#{key_exchange := dhe_rsa,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
+suite_map_to_bin(#{key_exchange := dh_anon,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_DH_anon_WITH_AES_256_CBC_SHA;
+%% TLS v1.2 suites
+suite_map_to_bin(#{key_exchange := rsa,
+ cipher := aes_128_cbc,
+ mac := sha256}) ->
+ ?TLS_RSA_WITH_AES_128_CBC_SHA256;
+suite_map_to_bin(#{key_exchange := rsa,
+ cipher := aes_256_cbc,
+ mac := sha256}) ->
+ ?TLS_RSA_WITH_AES_256_CBC_SHA256;
+suite_map_to_bin(#{key_exchange := dhe_dss,
+ cipher := aes_128_cbc,
+ mac := sha256}) ->
+ ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256;
+suite_map_to_bin(#{key_exchange := dhe_rsa,
+ cipher := aes_128_cbc,
+ mac := sha256}) ->
+ ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256;
+suite_map_to_bin(#{key_exchange := dhe_dss,
+ cipher := aes_256_cbc,
+ mac := sha256}) ->
+ ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256;
+suite_map_to_bin(#{key_exchange := dhe_rsa,
+ cipher := aes_256_cbc,
+ mac := sha256}) ->
+ ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
+suite_map_to_bin(#{key_exchange := dh_anon,
+ cipher := aes_128_cbc,
+ mac := sha256}) ->
+ ?TLS_DH_anon_WITH_AES_128_CBC_SHA256;
+suite_map_to_bin(#{key_exchange := dh_anon,
+ cipher := aes_256_cbc,
+ mac := sha256}) ->
+ ?TLS_DH_anon_WITH_AES_256_CBC_SHA256;
+%%% PSK Cipher Suites RFC 4279
+suite_map_to_bin(#{key_exchange := psk,
+ cipher := rc4_128,
+ mac := sha}) ->
+ ?TLS_PSK_WITH_RC4_128_SHA;
+suite_map_to_bin(#{key_exchange := psk,
+ cipher := '3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_PSK_WITH_3DES_EDE_CBC_SHA;
+suite_map_to_bin(#{key_exchange := psk,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_PSK_WITH_AES_128_CBC_SHA;
+suite_map_to_bin(#{key_exchange := psk,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_PSK_WITH_AES_256_CBC_SHA;
+suite_map_to_bin(#{key_exchange := dhe_psk,
+ cipher := rc4_128,
+ mac := sha}) ->
+ ?TLS_DHE_PSK_WITH_RC4_128_SHA;
+suite_map_to_bin(#{key_exchange := dhe_psk,
+ cipher := '3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA;
+suite_map_to_bin(#{key_exchange := dhe_psk,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA;
+suite_map_to_bin(#{key_exchange := dhe_psk,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_DHE_PSK_WITH_AES_256_CBC_SHA;
+suite_map_to_bin(#{key_exchange := rsa_psk,
+ cipher := rc4_128,
+ mac := sha}) ->
+ ?TLS_RSA_PSK_WITH_RC4_128_SHA;
+suite_map_to_bin(#{key_exchange := rsa_psk,
+ cipher := '3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA;
+suite_map_to_bin(#{key_exchange := rsa_psk,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA;
+suite_map_to_bin(#{key_exchange := rsa_psk,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA;
+%%% PSK NULL Cipher Suites RFC 4785
+suite_map_to_bin(#{key_exchange := psk,
+ cipher := null,
+ mac := sha}) ->
+ ?TLS_PSK_WITH_NULL_SHA;
+suite_map_to_bin(#{key_exchange := dhe_psk,
+ cipher := null,
+ mac := sha}) ->
+ ?TLS_DHE_PSK_WITH_NULL_SHA;
+suite_map_to_bin(#{key_exchange := rsa_psk,
+ cipher := null,
+ mac := sha}) ->
+ ?TLS_RSA_PSK_WITH_NULL_SHA;
+%%% TLS 1.2 PSK Cipher Suites RFC 5487
+suite_map_to_bin(#{key_exchange := psk,
+ cipher := aes_128_gcm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_PSK_WITH_AES_128_GCM_SHA256;
+suite_map_to_bin(#{key_exchange := psk,
+ cipher := aes_256_gcm,
+ mac := aead,
+ prf := sha384}) ->
+ ?TLS_PSK_WITH_AES_256_GCM_SHA384;
+suite_map_to_bin(#{key_exchange := dhe_psk,
+ cipher := aes_128_gcm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DHE_PSK_WITH_AES_128_GCM_SHA256;
+suite_map_to_bin(#{key_exchange := dhe_psk,
+ cipher := aes_256_gcm,
+ mac := aead,
+ prf := sha384}) ->
+ ?TLS_DHE_PSK_WITH_AES_256_GCM_SHA384;
+suite_map_to_bin(#{key_exchange := rsa_psk,
+ cipher := aes_128_gcm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_RSA_PSK_WITH_AES_128_GCM_SHA256;
+suite_map_to_bin(#{key_exchange := rsa_psk,
+ cipher := aes_256_gcm,
+ mac := aead,
+ prf := sha384}) ->
+ ?TLS_RSA_PSK_WITH_AES_256_GCM_SHA384;
+suite_map_to_bin(#{key_exchange := psk,
+ cipher := aes_128_cbc,
+ mac := sha256}) ->
+ ?TLS_PSK_WITH_AES_128_CBC_SHA256;
+suite_map_to_bin(#{key_exchange := psk,
+ cipher := aes_256_cbc,
+ mac := sha384}) ->
+ ?TLS_PSK_WITH_AES_256_CBC_SHA384;
+suite_map_to_bin(#{key_exchange := dhe_psk,
+ cipher := aes_128_cbc,
+ mac := sha256}) ->
+ ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256;
+suite_map_to_bin(#{key_exchange := dhe_psk,
+ cipher := aes_256_cbc,
+ mac := sha384}) ->
+ ?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384;
+suite_map_to_bin(#{key_exchange := rsa_psk,
+ cipher := aes_128_cbc,
+ mac := sha256}) ->
+ ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256;
+suite_map_to_bin(#{key_exchange := rsa_psk,
+ cipher := aes_256_cbc,
+ mac := sha384}) ->
+ ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384;
+suite_map_to_bin(#{key_exchange := psk,
+ cipher := null,
+ mac := sha256}) ->
+ ?TLS_PSK_WITH_NULL_SHA256;
+suite_map_to_bin(#{key_exchange := psk,
+ cipher := null,
+ mac := sha384}) ->
+ ?TLS_PSK_WITH_NULL_SHA384;
+suite_map_to_bin(#{key_exchange := dhe_psk,
+ cipher := null,
+ mac := sha256}) ->
+ ?TLS_DHE_PSK_WITH_NULL_SHA256;
+suite_map_to_bin(#{key_exchange := dhe_psk,
+ cipher := null,
+ mac := sha384}) ->
+ ?TLS_DHE_PSK_WITH_NULL_SHA384;
+suite_map_to_bin(#{key_exchange := rsa_psk,
+ cipher := null,
+ mac := sha256}) ->
+ ?TLS_RSA_PSK_WITH_NULL_SHA256;
+suite_map_to_bin(#{key_exchange := rsa_psk,
+ cipher := null,
+ mac := sha384}) ->
+ ?TLS_RSA_PSK_WITH_NULL_SHA384;
+%%% ECDHE PSK Cipher Suites RFC 5489
+suite_map_to_bin(#{key_exchange := ecdhe_psk,
+ cipher := rc4_128,
+ mac := sha}) ->
+ ?TLS_ECDHE_PSK_WITH_RC4_128_SHA;
+suite_map_to_bin(#{key_exchange := ecdhe_psk,
+ cipher :='3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA;
+suite_map_to_bin(#{key_exchange := ecdhe_psk,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA;
+suite_map_to_bin(#{key_exchange := ecdhe_psk,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA;
+suite_map_to_bin(#{key_exchange := ecdhe_psk,
+ cipher := aes_128_cbc,
+ mac := sha256}) ->
+ ?TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256;
+suite_map_to_bin(#{key_exchange := ecdhe_psk,
+ cipher := aes_256_cbc,
+ mac := sha384}) ->
+ ?TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384;
+suite_map_to_bin(#{key_exchange := ecdhe_psk,
+ cipher := null,
+ mac := sha256}) ->
+ ?TLS_ECDHE_PSK_WITH_NULL_SHA256;
+suite_map_to_bin(#{key_exchange := ecdhe_psk,
+ cipher := null,
+ mac := sha384}) ->
+ ?TLS_ECDHE_PSK_WITH_NULL_SHA384;
+%%% ECDHE_PSK with AES-GCM and AES-CCM Cipher Suites, draft-ietf-tls-ecdhe-psk-aead-05
+suite_map_to_bin(#{key_exchange := ecdhe_psk,
+ cipher := aes_128_gcm,
+ mac := null,
+ prf := sha256}) ->
+ ?TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256;
+suite_map_to_bin(#{key_exchange := ecdhe_psk,
+ cipher := aes_256_gcm,
+ mac := null,
+ prf := sha384}) ->
+ ?TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384;
+suite_map_to_bin(#{key_exchange := ecdhe_psk,
+ cipher := aes_128_ccm_8,
+ mac := null,
+ prf := sha256}) ->
+ ?TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256;
+suite_map_to_bin(#{key_exchange := ecdhe_psk,
+ cipher := aes_128_ccm,
+ mac := null,
+ prf := sha256}) ->
+ ?TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256;
+%%% SRP Cipher Suites RFC 5054
+suite_map_to_bin(#{key_exchange := srp_anon,
+ cipher := '3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA;
+suite_map_to_bin(#{key_exchange := srp_rsa,
+ cipher := '3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA;
+suite_map_to_bin(#{key_exchange := srp_dss,
+ cipher := '3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA;
+suite_map_to_bin(#{key_exchange := srp_anon,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_SRP_SHA_WITH_AES_128_CBC_SHA;
+suite_map_to_bin(#{key_exchange := srp_rsa,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA;
+suite_map_to_bin(#{key_exchange := srp_dss,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA;
+suite_map_to_bin(#{key_exchange := srp_anon,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_SRP_SHA_WITH_AES_256_CBC_SHA;
+suite_map_to_bin(#{key_exchange := srp_rsa,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA;
+suite_map_to_bin(#{key_exchange := srp_dss,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA;
+%%% RFC 4492 EC TLS suites
+suite_map_to_bin(#{key_exchange := ecdh_ecdsa,
+ cipher := null,
+ mac := sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_NULL_SHA;
+suite_map_to_bin(#{key_exchange := ecdh_ecdsa,
+ cipher := rc4_128,
+ mac := sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA;
+suite_map_to_bin(#{key_exchange := ecdh_ecdsa,
+ cipher := '3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA;
+suite_map_to_bin(#{key_exchange := ecdh_ecdsa,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA;
+suite_map_to_bin(#{key_exchange := ecdh_ecdsa,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA;
+suite_map_to_bin(#{key_exchange := ecdhe_ecdsa,
+ cipher := null,
+ mac := sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_NULL_SHA;
+suite_map_to_bin(#{key_exchange := ecdhe_ecdsa,
+ cipher := rc4_128,
+ mac := sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA;
+suite_map_to_bin(#{key_exchange := ecdhe_ecdsa,
+ cipher := '3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;
+suite_map_to_bin(#{key_exchange := ecdhe_ecdsa,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA;
+suite_map_to_bin(#{key_exchange := ecdhe_ecdsa,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
+suite_map_to_bin(#{key_exchange := ecdh_rsa,
+ cipher := null,
+ mac := sha}) ->
+ ?TLS_ECDH_RSA_WITH_NULL_SHA;
+suite_map_to_bin(#{key_exchange := ecdh_rsa,
+ cipher := rc4_128,
+ mac := sha}) ->
+ ?TLS_ECDH_RSA_WITH_RC4_128_SHA;
+suite_map_to_bin(#{key_exchange := ecdh_rsa,
+ cipher := '3des_ede_cbc', mac := sha}) ->
+ ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA;
+suite_map_to_bin(#{key_exchange := ecdh_rsa,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;
+suite_map_to_bin(#{key_exchange := ecdh_rsa,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA;
+suite_map_to_bin(#{key_exchange := ecdhe_rsa,
+ cipher := null,
+ mac := sha}) ->
+ ?TLS_ECDHE_RSA_WITH_NULL_SHA;
+suite_map_to_bin(#{key_exchange := ecdhe_rsa,
+ cipher := rc4_128,
+ mac := sha}) ->
+ ?TLS_ECDHE_RSA_WITH_RC4_128_SHA;
+suite_map_to_bin(#{key_exchange := ecdhe_rsa,
+ cipher := '3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;
+suite_map_to_bin(#{key_exchange := ecdhe_rsa,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
+suite_map_to_bin(#{key_exchange := ecdhe_rsa,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
+suite_map_to_bin(#{key_exchange := ecdh_anon,
+ cipher := null,
+ mac := sha}) ->
+ ?TLS_ECDH_anon_WITH_NULL_SHA;
+suite_map_to_bin(#{key_exchange := ecdh_anon,
+ cipher := rc4_128,
+ mac := sha}) ->
+ ?TLS_ECDH_anon_WITH_RC4_128_SHA;
+suite_map_to_bin(#{key_exchange := ecdh_anon,
+ cipher := '3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA;
+suite_map_to_bin(#{key_exchange := ecdh_anon,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_ECDH_anon_WITH_AES_128_CBC_SHA;
+suite_map_to_bin(#{key_exchange := ecdh_anon,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_ECDH_anon_WITH_AES_256_CBC_SHA;
+%%% RFC 5289 EC TLS suites
+suite_map_to_bin(#{key_exchange := ecdhe_ecdsa,
+ cipher := aes_128_cbc,
+ mac:= sha256,
+ prf := sha256}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
+suite_map_to_bin(#{key_exchange := ecdhe_ecdsa,
+ cipher := aes_256_cbc,
+ mac := sha384,
+ prf := sha384}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384;
+suite_map_to_bin(#{key_exchange := ecdh_ecdsa,
+ cipher := aes_128_cbc,
+ mac := sha256,
+ prf := sha256}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256;
+suite_map_to_bin(#{key_exchange := ecdh_ecdsa,
+ cipher := aes_256_cbc,
+ mac := sha384,
+ prf := sha384}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384;
+suite_map_to_bin(#{key_exchange := ecdhe_rsa,
+ cipher := aes_128_cbc,
+ mac := sha256,
+ prf := sha256}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256;
+suite_map_to_bin(#{key_exchange := ecdhe_rsa,
+ cipher := aes_256_cbc,
+ mac := sha384,
+ prf := sha384}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384;
+suite_map_to_bin(#{key_exchange := ecdh_rsa,
+ cipher := aes_128_cbc,
+ mac := sha256,
+ prf := sha256}) ->
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;
+suite_map_to_bin(#{key_exchange := ecdh_rsa,
+ cipher := aes_256_cbc,
+ mac := sha384,
+ prf := sha384}) ->
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384;
+%% RFC 5288 AES-GCM Cipher Suites
+suite_map_to_bin(#{key_exchange := rsa,
+ cipher := aes_128_gcm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_RSA_WITH_AES_128_GCM_SHA256;
+suite_map_to_bin(#{key_exchange := rsa,
+ cipher := aes_256_gcm,
+ mac := aead,
+ prf := sha384}) ->
+ ?TLS_RSA_WITH_AES_256_GCM_SHA384;
+suite_map_to_bin(#{key_exchange := dhe_rsa,
+ cipher := aes_128_gcm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DHE_RSA_WITH_AES_128_GCM_SHA256;
+suite_map_to_bin(#{key_exchange := dhe_rsa,
+ cipher := aes_256_gcm,
+ mac := aead,
+ prf := sha384}) ->
+ ?TLS_DHE_RSA_WITH_AES_256_GCM_SHA384;
+suite_map_to_bin(#{key_exchange := dh_rsa,
+ cipher := aes_128_gcm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DH_RSA_WITH_AES_128_GCM_SHA256;
+suite_map_to_bin(#{key_exchange := dh_rsa,
+ cipher := aes_256_gcm,
+ mac := aead,
+ prf := sha384}) ->
+ ?TLS_DH_RSA_WITH_AES_256_GCM_SHA384;
+suite_map_to_bin(#{key_exchange := dhe_dss,
+ cipher := aes_128_gcm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DHE_DSS_WITH_AES_128_GCM_SHA256;
+suite_map_to_bin(#{key_exchange := dhe_dss,
+ cipher := aes_256_gcm,
+ mac := aead,
+ prf := sha384}) ->
+ ?TLS_DHE_DSS_WITH_AES_256_GCM_SHA384;
+suite_map_to_bin(#{key_exchange := dh_dss,
+ cipher := aes_128_gcm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DH_DSS_WITH_AES_128_GCM_SHA256;
+suite_map_to_bin(#{key_exchange := dh_dss,
+ cipher := aes_256_gcm,
+ mac := aead,
+ prf := sha384}) ->
+ ?TLS_DH_DSS_WITH_AES_256_GCM_SHA384;
+suite_map_to_bin(#{key_exchange := dh_anon,
+ cipher := aes_128_gcm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DH_anon_WITH_AES_128_GCM_SHA256;
+suite_map_to_bin(#{key_exchange := dh_anon,
+ cipher := aes_256_gcm,
+ mac := aead,
+ prf := sha384}) ->
+ ?TLS_DH_anon_WITH_AES_256_GCM_SHA384;
+%% RFC 5289 ECC AES-GCM Cipher Suites
+suite_map_to_bin(#{key_exchange := ecdhe_ecdsa,
+ cipher := aes_128_gcm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256;
+suite_map_to_bin(#{key_exchange := ecdhe_ecdsa,
+ cipher := aes_256_gcm,
+ mac := aead,
+ prf := sha384}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384;
+suite_map_to_bin(#{key_exchange := ecdh_ecdsa,
+ cipher := aes_128_gcm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256;
+suite_map_to_bin(#{key_exchange := ecdh_ecdsa,
+ cipher := aes_256_gcm,
+ mac := aead,
+ prf := sha384}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384;
+suite_map_to_bin(#{key_exchange := ecdhe_rsa,
+ cipher := aes_128_gcm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256;
+suite_map_to_bin(#{key_exchange := ecdhe_rsa,
+ cipher := aes_256_gcm,
+ mac := aead,
+ prf := sha384}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384;
+suite_map_to_bin(#{key_exchange := ecdh_rsa,
+ cipher := aes_128_gcm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256;
+suite_map_to_bin(#{key_exchange := ecdh_rsa,
+ cipher := aes_256_gcm,
+ mac := aead,
+ prf := sha384}) ->
+ ?TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384;
+%% draft-agl-tls-chacha20poly1305-04 Chacha20/Poly1305 Suites
+suite_map_to_bin(#{key_exchange := ecdhe_rsa,
+ cipher := chacha20_poly1305,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256;
+suite_map_to_bin(#{key_exchange := ecdhe_ecdsa,
+ cipher := chacha20_poly1305,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256;
+suite_map_to_bin(#{key_exchange := dhe_rsa,
+ cipher := chacha20_poly1305,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256;
+
+%% RFC 6655 - TLS-1.2 cipher suites
+suite_map_to_bin(#{key_exchange := psk,
+ cipher := aes_128_ccm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_PSK_WITH_AES_128_CCM;
+suite_map_to_bin(#{key_exchange := psk,
+ cipher := aes_256_ccm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_PSK_WITH_AES_256_CCM;
+suite_map_to_bin(#{key_exchange := dhe_psk,
+ cipher := aes_128_ccm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DHE_PSK_WITH_AES_128_CCM;
+suite_map_to_bin(#{key_exchange := dhe_psk,
+ cipher := aes_256_ccm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DHE_PSK_WITH_AES_256_CCM;
+suite_map_to_bin(#{key_exchange := rsa,
+ cipher := aes_128_ccm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_RSA_WITH_AES_128_CCM;
+suite_map_to_bin(#{key_exchange := rsa,
+ cipher := aes_256_ccm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_RSA_WITH_AES_256_CCM;
+suite_map_to_bin(#{key_exchange := dhe_rsa,
+ cipher := aes_128_ccm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DHE_RSA_WITH_AES_128_CCM;
+suite_map_to_bin(#{key_exchange := dhe_rsa,
+ cipher := aes_256_ccm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DHE_RSA_WITH_AES_256_CCM;
+
+suite_map_to_bin(#{key_exchange := psk,
+ cipher := aes_128_ccm_8,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_PSK_WITH_AES_128_CCM_8;
+suite_map_to_bin(#{key_exchange := psk,
+ cipher := aes_256_ccm_8,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_PSK_WITH_AES_256_CCM_8;
+suite_map_to_bin(#{key_exchange := dhe_psk,
+ cipher := aes_128_ccm_8,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_PSK_DHE_WITH_AES_128_CCM_8;
+suite_map_to_bin(#{key_exchange := dhe_psk,
+ cipher := aes_256_ccm_8,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_PSK_DHE_WITH_AES_256_CCM_8;
+suite_map_to_bin(#{key_exchange := rsa,
+ cipher := aes_128_ccm_8,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_RSA_WITH_AES_128_CCM_8;
+suite_map_to_bin(#{key_exchange := rsa,
+ cipher := aes_256_ccm_8,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_RSA_WITH_AES_256_CCM_8;
+suite_map_to_bin(#{key_exchange := dhe_rsa,
+ cipher := aes_128_ccm_8,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DHE_RSA_WITH_AES_128_CCM_8;
+suite_map_to_bin(#{key_exchange := dhe_rsa,
+ cipher := aes_256_ccm_8,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DHE_RSA_WITH_AES_256_CCM_8;
+
+%% TLS 1.3 Cipher Suites RFC8446
+suite_map_to_bin(#{key_exchange := any,
+ cipher := aes_128_gcm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_AES_128_GCM_SHA256;
+suite_map_to_bin(#{key_exchange := any,
+ cipher := aes_256_gcm,
+ mac := aead,
+ prf := sha384}) ->
+ ?TLS_AES_256_GCM_SHA384;
+suite_map_to_bin(#{key_exchange := any,
+ cipher := chacha20_poly1305,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_CHACHA20_POLY1305_SHA256;
+suite_map_to_bin(#{key_exchange := any,
+ cipher := aes_128_ccm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_AES_128_CCM_SHA256.
+%% suite_map_to_bin(#{key_exchange := any,
+%% cipher := aes_128_ccm_8,
+%% mac := aead,
+%% prf := sha256}) ->
+%% ?TLS_AES_128_CCM_8_SHA256.
+
+
+tls_1_3_suite_str_to_map(CipherStr) ->
+ {Cipher, Mac, Prf} = cipher_str_to_algs(any, CipherStr, ""),
+ #{key_exchange => any,
+ mac => Mac,
+ cipher => Cipher,
+ prf => Prf
+ }.
+
+pre_tls_1_3_suite_str_to_map(KexStr, Rest) ->
+ Kex = algo_str_to_atom(KexStr),
+ [CipherStr, AlgStr] = string:split(Rest, "_", trailing),
+ {Cipher, Mac, Prf} = cipher_str_to_algs(Kex, CipherStr, AlgStr),
+ #{key_exchange => Kex,
+ mac => Mac,
+ cipher => Cipher,
+ prf => Prf
+ }.
+
+cipher_str_to_algs(_, CipherStr, "CCM"= End) -> %% PRE TLS 1.3
+ Cipher = algo_str_to_atom(CipherStr ++ "_" ++ End),
+ {Cipher, aead, sha256};
+cipher_str_to_algs(_, CipherStr, "8" = End) -> %% PRE TLS 1.3
+ Cipher = algo_str_to_atom(CipherStr ++ "_" ++ End),
+ {Cipher, aead, sha256};
+cipher_str_to_algs(_, CipherStr, "CHACHA20_POLY1305" = End) -> %% PRE TLS 1.3
+ Cipher = algo_str_to_atom(CipherStr ++ "_" ++ End),
+ {Cipher, aead, sha256};
+cipher_str_to_algs(_, CipherStr0, "") -> %% TLS 1.3
+ [CipherStr, AlgStr] = string:split(CipherStr0, "_", trailing),
+ Hash = algo_str_to_atom(AlgStr),
+ Cipher = algo_str_to_atom(CipherStr),
+ {Cipher, aead, Hash};
+cipher_str_to_algs(Kex, CipherStr, HashStr) -> %% PRE TLS 1.3
+ Hash = algo_str_to_atom(HashStr),
+ Cipher = algo_str_to_atom(CipherStr),
+ case is_aead_cipher(CipherStr) of
+ true ->
+ {Cipher, aead, Hash};
+ false ->
+ {Cipher, Hash, default_prf(Kex, Hash)}
+ end.
+
+default_prf(_, md5) ->
+ default_prf;
+default_prf(_, sha) ->
+ default_prf;
+default_prf(ecdhe_ecdsa, sha256) ->
+ sha256;
+default_prf(ecdhe_rsa, sha256) ->
+ sha256;
+default_prf(dhe_rsa, sha256) ->
+ default_prf;
+default_prf(dhe_dss, sha256) ->
+ default_prf;
+default_prf(rsa, sha256) ->
+ default_prf;
+default_prf(rsa_psk, sha256) ->
+ default_prf;
+default_prf(_, Hash) ->
+ Hash.
+
+%% PRE TLS 1.3
+is_aead_cipher("CHACHA20_POLY1305") ->
+ true;
+is_aead_cipher(CipherStr) ->
+ [_, Rest] = string:split(CipherStr, "_", trailing),
+ (Rest == "GCM") orelse (Rest == "CCM") orelse (Rest == "8").
+
+openssl_is_aead_cipher("CHACHA20-POLY1305") ->
+ true;
+openssl_is_aead_cipher(CipherStr) ->
+ case string:split(CipherStr, "-", trailing) of
+ [_, Rest] ->
+ (Rest == "GCM") orelse (Rest == "CCM") orelse (Rest == "8");
+ [_] ->
+ false
+ end.
+
+algo_str_to_atom("SRP_SHA_DSS") ->
+ srp_dss;
+algo_str_to_atom(AlgoStr) ->
+ erlang:list_to_existing_atom(string:to_lower(AlgoStr)).
+
+openssl_cipher_name(_, "3DES_EDE_CBC" ++ _) ->
+ "DES-CBC3";
+openssl_cipher_name(Kex, "AES_128_CBC" ++ _ = CipherStr) when Kex == rsa;
+ Kex == dhe_rsa;
+ Kex == ecdhe_rsa;
+ Kex == ecdhe_ecdsa ->
+ openssl_name_concat(CipherStr);
+openssl_cipher_name(Kex, "AES_256_CBC" ++ _ = CipherStr) when Kex == rsa;
+ Kex == dhe_rsa;
+ Kex == ecdhe_rsa;
+ Kex == ecdhe_ecdsa ->
+ openssl_name_concat(CipherStr);
+openssl_cipher_name(Kex, "AES_128_CBC" ++ _ = CipherStr) when Kex == srp;
+ Kex == srp_rsa ->
+ lists:append(string:replace(CipherStr, "_", "-", all));
+openssl_cipher_name(Kex, "AES_256_CBC" ++ _ = CipherStr) when Kex == srp;
+ Kex == srp_rsa ->
+ lists:append(string:replace(CipherStr, "_", "-", all));
+openssl_cipher_name(_, "AES_128_CBC" ++ _ = CipherStr) ->
+ openssl_name_concat(CipherStr) ++ "-CBC";
+openssl_cipher_name(_, "AES_256_CBC" ++ _ = CipherStr) ->
+ openssl_name_concat(CipherStr) ++ "-CBC";
+openssl_cipher_name(_, "AES_128_GCM" ++ _ = CipherStr) ->
+ openssl_name_concat(CipherStr) ++ "-GCM";
+openssl_cipher_name(_, "AES_256_GCM" ++ _ = CipherStr) ->
+ openssl_name_concat(CipherStr) ++ "-GCM";
+openssl_cipher_name(_, "RC4" ++ _) ->
+ "RC4";
+openssl_cipher_name(_, CipherStr) ->
+ lists:append(string:replace(CipherStr, "_", "-", all)).
+
+
+openssl_suite_start(Kex) ->
+ case openssl_kex_name(Kex) of
+ "" ->
+ "";
+ Name ->
+ Name ++ "-"
+ end.
+
+openssl_kex_name("RSA") ->
+ "";
+openssl_kex_name(Kex) ->
+ lists:append(string:replace(Kex, "_", "-", all)).
+
+kex_name_from_openssl(Kex) ->
+ lists:append(string:replace(Kex, "-", "_", all)).
+
+cipher_name_from_openssl("AES128") ->
+ "AES_128_CBC";
+cipher_name_from_openssl("AES256") ->
+ "AES_256_CBC";
+cipher_name_from_openssl("AES128-CBC") ->
+ "AES_128_CBC";
+cipher_name_from_openssl("AES256-CBC") ->
+ "AES_256_CBC";
+cipher_name_from_openssl("AES-128-CBC") ->
+ "AES_128_CBC";
+cipher_name_from_openssl("AES-256-CBC") ->
+ "AES_256_CBC";
+cipher_name_from_openssl("AES128-GCM") ->
+ "AES_128_GCM";
+cipher_name_from_openssl("AES256-GCM") ->
+ "AES_256_GCM";
+cipher_name_from_openssl("DES-CBC") ->
+ "DES_CBC";
+cipher_name_from_openssl("DES-CBC3") ->
+ "3DES_EDE_CBC";
+cipher_name_from_openssl("RC4") ->
+ "RC4_128";
+cipher_name_from_openssl(Str) ->
+ Str.
+
+openssl_name_concat(Str0) ->
+ [Str, _] = string:split(Str0, "_", trailing),
+ [Part1, Part2] = string:split(Str, "_", trailing),
+ Part1 ++ Part2.
+
+
+suite_openssl_str_to_map(Kex0, Rest) ->
+ Kex = algo_str_to_atom(kex_name_from_openssl(Kex0)),
+ [CipherStr, AlgStr] = string:split(Rest, "-", trailing),
+ {Cipher, Mac, Prf} = openssl_cipher_str_to_algs(Kex, CipherStr, AlgStr),
+ #{key_exchange => Kex,
+ mac => Mac,
+ cipher => Cipher,
+ prf => Prf
+ }.
+
+%% Does only need own implementation PRE TLS 1.3
+openssl_cipher_str_to_algs(_, CipherStr, "CCM"= End) ->
+ Cipher = algo_str_to_atom(CipherStr ++ "_" ++ End),
+ {Cipher, aead, sha256};
+openssl_cipher_str_to_algs(_, CipherStr, "8" = End) ->
+ Cipher = algo_str_to_atom(CipherStr ++ "_" ++ End),
+ {Cipher, aead, sha256};
+openssl_cipher_str_to_algs(_, CipherStr, "POLY1305" = End) ->
+ Cipher = algo_str_to_atom(CipherStr ++ "_" ++ End),
+ {Cipher, aead, sha256};
+openssl_cipher_str_to_algs(Kex, CipherStr, HashStr) ->
+ Hash = algo_str_to_atom(HashStr),
+ Cipher = algo_str_to_atom(cipher_name_from_openssl(CipherStr)),
+ case openssl_is_aead_cipher(CipherStr) of
+ true ->
+ {Cipher, aead, Hash};
+ false ->
+ {Cipher, Hash, default_prf(Kex, Hash)}
+ end.
+
+
+
diff --git a/lib/ssl/src/ssl_config.erl b/lib/ssl/src/ssl_config.erl
index 022fb7eac0..1e6dab9276 100644
--- a/lib/ssl/src/ssl_config.erl
+++ b/lib/ssl/src/ssl_config.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -91,9 +91,9 @@ init_certificates(undefined, #{pem_cache := PemCache} = Config, CertFile, server
end;
init_certificates(Cert, Config, _, _) ->
{ok, Config#{own_certificate => Cert}}.
-init_private_key(_, #{algorithm := Alg} = Key, <<>>, _Password, _Client) when Alg == ecdsa;
- Alg == rsa;
- Alg == dss ->
+init_private_key(_, #{algorithm := Alg} = Key, _, _Password, _Client) when Alg == ecdsa;
+ Alg == rsa;
+ Alg == dss ->
case maps:is_key(engine, Key) andalso maps:is_key(key_id, Key) of
true ->
Key;
@@ -132,7 +132,13 @@ private_key(#'PrivateKeyInfo'{privateKeyAlgorithm =
#'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?'id-dsa'},
privateKey = Key}) ->
public_key:der_decode('DSAPrivateKey', iolist_to_binary(Key));
-
+private_key(#'PrivateKeyInfo'{privateKeyAlgorithm =
+ #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?'id-ecPublicKey',
+ parameters = {asn1_OPENTYPE, Parameters}},
+ privateKey = Key}) ->
+ ECKey = public_key:der_decode('ECPrivateKey', iolist_to_binary(Key)),
+ ECParameters = public_key:der_decode('EcpkParameters', Parameters),
+ ECKey#'ECPrivateKey'{parameters = ECParameters};
private_key(Key) ->
Key.
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index 63fae78195..a5f754d2e3 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -35,10 +35,13 @@
-include("ssl_internal.hrl").
-include("ssl_srp.hrl").
-include_lib("public_key/include/public_key.hrl").
+-include_lib("kernel/include/logger.hrl").
%% Setup
--export([connect/8, ssl_accept/7, handshake/2, handshake/3,
- socket_control/4, socket_control/5, start_or_recv_cancel_timer/2]).
+
+-export([connect/8, handshake/7, handshake/2, handshake/3, handle_common_event/5,
+ handshake_continue/3, handshake_cancel/1,
+ socket_control/4, socket_control/5]).
%% User Events
-export([send/2, recv/3, close/2, shutdown/2,
@@ -49,11 +52,11 @@
%% Alert and close handling
-export([handle_own_alert/4, handle_alert/3,
- handle_normal_shutdown/3
- ]).
+ handle_normal_shutdown/3,
+ handle_trusted_certs_db/1]).
%% Data handling
--export([write_application_data/3, read_application_data/2]).
+-export([read_application_data/2, internal_renegotiation/2]).
%% Help functions for tls|dtls_connection.erl
-export([handle_session/7, ssl_config/3,
@@ -61,17 +64,21 @@
%% General gen_statem state functions with extra callback argument
%% to determine if it is an SSL/TLS or DTLS gen_statem machine
--export([init/4, error/4, hello/4, abbreviated/4, certify/4, cipher/4, connection/4, downgrade/4]).
+-export([init/4, error/4, hello/4, user_hello/4, abbreviated/4, certify/4, cipher/4,
+ connection/4, downgrade/4]).
%% gen_statem callbacks
-export([terminate/3, format_status/2]).
+%% Erlang Distribution export
+-export([dist_handshake_complete/2]).
+
%%====================================================================
%% Setup
%%====================================================================
%%--------------------------------------------------------------------
-spec connect(tls_connection | dtls_connection,
- host(), inet:port_number(),
+ ssl:host(), inet:port_number(),
port() | {tuple(), port()}, %% TLS | DTLS
{#ssl_options{}, #socket_options{},
%% Tracker only needed on server side
@@ -89,7 +96,7 @@ connect(Connection, Host, Port, Socket, Options, User, CbInfo, Timeout) ->
{error, ssl_not_started}
end.
%%--------------------------------------------------------------------
--spec ssl_accept(tls_connection | dtls_connection,
+-spec handshake(tls_connection | dtls_connection,
inet:port_number(), port(),
{#ssl_options{}, #socket_options{}, undefined | pid()},
pid(), tuple(), timeout()) ->
@@ -98,7 +105,7 @@ connect(Connection, Host, Port, Socket, Options, User, CbInfo, Timeout) ->
%% Description: Performs accept on an ssl listen socket. e.i. performs
%% ssl handshake.
%%--------------------------------------------------------------------
-ssl_accept(Connection, Port, Socket, Opts, User, CbInfo, Timeout) ->
+handshake(Connection, Port, Socket, Opts, User, CbInfo, Timeout) ->
try Connection:start_fsm(server, "localhost", Port, Socket, Opts, User,
CbInfo, Timeout)
catch
@@ -107,34 +114,62 @@ ssl_accept(Connection, Port, Socket, Opts, User, CbInfo, Timeout) ->
end.
%%--------------------------------------------------------------------
--spec handshake(#sslsocket{}, timeout()) -> ok | {error, reason()}.
+-spec handshake(#sslsocket{}, timeout()) -> {ok, #sslsocket{}} |
+ {ok, #sslsocket{}, map()}| {error, reason()}.
%%
%% Description: Starts ssl handshake.
%%--------------------------------------------------------------------
-handshake(#sslsocket{pid = Pid}, Timeout) ->
+handshake(#sslsocket{pid = [Pid|_]} = Socket, Timeout) ->
case call(Pid, {start, Timeout}) of
connected ->
- ok;
+ {ok, Socket};
+ {ok, Ext} ->
+ {ok, Socket, Ext};
Error ->
Error
end.
%%--------------------------------------------------------------------
--spec handshake(#sslsocket{}, {#ssl_options{},#socket_options{}},
- timeout()) -> ok | {error, reason()}.
+-spec handshake(#sslsocket{}, {#ssl_options{},#socket_options{}}, timeout()) ->
+ {ok, #sslsocket{}} | {ok, #sslsocket{}, map()} | {error, reason()}.
%%
%% Description: Starts ssl handshake with some new options
%%--------------------------------------------------------------------
-handshake(#sslsocket{pid = Pid}, SslOptions, Timeout) ->
+handshake(#sslsocket{pid = [Pid|_]} = Socket, SslOptions, Timeout) ->
case call(Pid, {start, SslOptions, Timeout}) of
connected ->
- ok;
+ {ok, Socket};
Error ->
Error
end.
+%%--------------------------------------------------------------------
+-spec handshake_continue(#sslsocket{}, [ssl:tls_server_option()],
+ timeout()) -> {ok, #sslsocket{}}| {error, reason()}.
+%%
+%% Description: Continues handshake with new options
+%%--------------------------------------------------------------------
+handshake_continue(#sslsocket{pid = [Pid|_]} = Socket, SslOptions, Timeout) ->
+ case call(Pid, {handshake_continue, SslOptions, Timeout}) of
+ connected ->
+ {ok, Socket};
+ Error ->
+ Error
+ end.
+%%--------------------------------------------------------------------
+-spec handshake_cancel(#sslsocket{}) -> ok | {error, reason()}.
+%%
+%% Description: Cancels connection
+%%--------------------------------------------------------------------
+handshake_cancel(#sslsocket{pid = [Pid|_]}) ->
+ case call(Pid, cancel) of
+ closed ->
+ ok;
+ Error ->
+ Error
+ end.
%--------------------------------------------------------------------
--spec socket_control(tls_connection | dtls_connection, port(), pid(), atom()) ->
+-spec socket_control(tls_connection | dtls_connection, port(), [pid()], atom()) ->
{ok, #sslsocket{}} | {error, reason()}.
%%
%% Description: Set the ssl process to own the accept socket
@@ -143,32 +178,28 @@ socket_control(Connection, Socket, Pid, Transport) ->
socket_control(Connection, Socket, Pid, Transport, undefined).
%--------------------------------------------------------------------
--spec socket_control(tls_connection | dtls_connection, port(), pid(), atom(), pid()| undefined) ->
+-spec socket_control(tls_connection | dtls_connection, port(), [pid()], atom(), pid()| atom()) ->
{ok, #sslsocket{}} | {error, reason()}.
%%--------------------------------------------------------------------
-socket_control(Connection, Socket, Pid, Transport, udp_listner) ->
- %% dtls listner process must have the socket control
- {ok, Connection:socket(Pid, Transport, Socket, Connection, undefined)};
+socket_control(Connection, Socket, Pids, Transport, udp_listener) ->
+ %% dtls listener process must have the socket control
+ {ok, Connection:socket(Pids, Transport, Socket, undefined)};
-socket_control(tls_connection = Connection, Socket, Pid, Transport, ListenTracker) ->
+socket_control(tls_connection = Connection, Socket, [Pid|_] = Pids, Transport, ListenTracker) ->
case Transport:controlling_process(Socket, Pid) of
ok ->
- {ok, Connection:socket(Pid, Transport, Socket, Connection, ListenTracker)};
+ {ok, Connection:socket(Pids, Transport, Socket, ListenTracker)};
{error, Reason} ->
{error, Reason}
end;
-socket_control(dtls_connection = Connection, {_, Socket}, Pid, Transport, ListenTracker) ->
+socket_control(dtls_connection = Connection, {_, Socket}, [Pid|_] = Pids, Transport, ListenTracker) ->
case Transport:controlling_process(Socket, Pid) of
ok ->
- {ok, Connection:socket(Pid, Transport, Socket, Connection, ListenTracker)};
+ {ok, Connection:socket(Pids, Transport, Socket, ListenTracker)};
{error, Reason} ->
{error, Reason}
end.
-start_or_recv_cancel_timer(infinity, _RecvFrom) ->
- undefined;
-start_or_recv_cancel_timer(Timeout, RecvFrom) ->
- erlang:send_after(Timeout, self(), {cancel_start_or_recv, RecvFrom}).
%%====================================================================
%% User events
@@ -181,9 +212,9 @@ start_or_recv_cancel_timer(Timeout, RecvFrom) ->
%%--------------------------------------------------------------------
send(Pid, Data) ->
call(Pid, {application_data,
- %% iolist_to_binary should really
- %% be called iodata_to_binary()
- erlang:iolist_to_binary(Data)}).
+ %% iolist_to_iovec should really
+ %% be called iodata_to_iovec()
+ erlang:iolist_to_iovec(Data)}).
%%--------------------------------------------------------------------
-spec recv(pid(), integer(), timeout()) ->
@@ -273,6 +304,18 @@ renegotiation(ConnectionPid) ->
call(ConnectionPid, renegotiate).
%%--------------------------------------------------------------------
+-spec internal_renegotiation(pid(), ssl_record:connection_states()) ->
+ ok.
+%%
+%% Description: Starts a renegotiation of the ssl session.
+%%--------------------------------------------------------------------
+internal_renegotiation(ConnectionPid, #{current_write := WriteState}) ->
+ gen_statem:cast(ConnectionPid, {internal_renegotiate, WriteState}).
+
+dist_handshake_complete(ConnectionPid, DHandle) ->
+ gen_statem:cast(ConnectionPid, {dist_handshake_complete, DHandle}).
+
+%%--------------------------------------------------------------------
-spec prf(pid(), binary() | 'master_secret', binary(),
[binary() | ssl:prf_random()], non_neg_integer()) ->
{ok, binary()} | {error, reason()} | {'EXIT', term()}.
@@ -285,155 +328,366 @@ prf(ConnectionPid, Secret, Label, Seed, WantedLength) ->
%%====================================================================
%% Alert and close handling
%%====================================================================
-handle_own_alert(Alert, Version, StateName,
- #state{role = Role,
- transport_cb = Transport,
- socket = Socket,
- protocol_cb = Connection,
- connection_states = ConnectionStates,
+handle_own_alert(Alert, _, StateName,
+ #state{static_env = #static_env{role = Role,
+ protocol_cb = Connection},
ssl_options = SslOpts} = State) ->
try %% Try to tell the other side
- {BinMsg, _} =
- Connection:encode_alert(Alert, Version, ConnectionStates),
- Connection:send(Transport, Socket, BinMsg)
+ send_alert(Alert, StateName, State)
catch _:_ -> %% Can crash if we are in a uninitialized state
ignore
end,
try %% Try to tell the local user
- log_alert(SslOpts#ssl_options.log_alert, Role, Connection:protocol_name(), StateName, Alert#alert{role = Role}),
+ log_alert(SslOpts#ssl_options.log_level, Role,
+ Connection:protocol_name(), StateName,
+ Alert#alert{role = Role}),
handle_normal_shutdown(Alert,StateName, State)
catch _:_ ->
ok
end,
- {stop, {shutdown, own_alert}}.
-
-handle_normal_shutdown(Alert, _, #state{socket = Socket,
- transport_cb = Transport,
- protocol_cb = Connection,
- start_or_recv_from = StartFrom,
- tracker = Tracker,
- role = Role, renegotiation = {false, first}}) ->
- alert_user(Transport, Tracker,Socket, StartFrom, Alert, Role, Connection);
-
-handle_normal_shutdown(Alert, StateName, #state{socket = Socket,
- socket_options = Opts,
- transport_cb = Transport,
- protocol_cb = Connection,
- user_application = {_Mon, Pid},
- tracker = Tracker,
- start_or_recv_from = RecvFrom, role = Role}) ->
- alert_user(Transport, Tracker, Socket, StateName, Opts, Pid, RecvFrom, Alert, Role, Connection).
+ {stop, {shutdown, own_alert}, State}.
+
+handle_normal_shutdown(Alert, _, #state{static_env = #static_env{role = Role,
+ socket = Socket,
+ transport_cb = Transport,
+ protocol_cb = Connection,
+ tracker = Tracker},
+ handshake_env = #handshake_env{renegotiation = {false, first}},
+ start_or_recv_from = StartFrom} = State) ->
+ Pids = Connection:pids(State),
+ alert_user(Pids, Transport, Tracker,Socket, StartFrom, Alert, Role, Connection);
+
+handle_normal_shutdown(Alert, StateName, #state{static_env = #static_env{role = Role,
+ socket = Socket,
+ transport_cb = Transport,
+ protocol_cb = Connection,
+ tracker = Tracker},
+ connection_env = #connection_env{user_application = {_Mon, Pid}},
+ socket_options = Opts,
+ start_or_recv_from = RecvFrom} = State) ->
+ Pids = Connection:pids(State),
+ alert_user(Pids, Transport, Tracker, Socket, StateName, Opts, Pid, RecvFrom, Alert, Role, Connection).
handle_alert(#alert{level = ?FATAL} = Alert, StateName,
- #state{socket = Socket, transport_cb = Transport,
- protocol_cb = Connection,
- ssl_options = SslOpts, start_or_recv_from = From, host = Host,
- port = Port, session = Session, user_application = {_Mon, Pid},
- role = Role, socket_options = Opts, tracker = Tracker}) ->
+ #state{static_env = #static_env{role = Role,
+ socket = Socket,
+ host = Host,
+ port = Port,
+ tracker = Tracker,
+ transport_cb = Transport,
+ protocol_cb = Connection},
+ connection_env = #connection_env{user_application = {_Mon, Pid}},
+ ssl_options = SslOpts,
+ start_or_recv_from = From,
+ session = Session,
+ socket_options = Opts} = State) ->
invalidate_session(Role, Host, Port, Session),
- log_alert(SslOpts#ssl_options.log_alert, Role, Connection:protocol_name(),
+ log_alert(SslOpts#ssl_options.log_level, Role, Connection:protocol_name(),
StateName, Alert#alert{role = opposite_role(Role)}),
- alert_user(Transport, Tracker, Socket, StateName, Opts, Pid, From, Alert, Role, Connection),
- {stop, normal};
+ Pids = Connection:pids(State),
+ alert_user(Pids, Transport, Tracker, Socket, StateName, Opts, Pid, From, Alert,
+ opposite_role(Role), Connection),
+ {stop, {shutdown, normal}, State};
handle_alert(#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} = Alert,
- StateName, State) ->
+ downgrade= StateName, State) ->
+ {next_state, StateName, State, [{next_event, internal, Alert}]};
+handle_alert(#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} = Alert,
+ StateName, State) ->
handle_normal_shutdown(Alert, StateName, State),
- {stop, {shutdown, peer_close}};
-
+ {stop,{shutdown, peer_close}, State};
handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert, StateName,
- #state{role = Role, ssl_options = SslOpts, protocol_cb = Connection, renegotiation = {true, internal}} = State) ->
- log_alert(SslOpts#ssl_options.log_alert, Role,
+ #state{static_env = #static_env{role = Role,
+ protocol_cb = Connection},
+ handshake_env = #handshake_env{renegotiation = {true, internal}},
+ ssl_options = SslOpts} = State) ->
+ log_alert(SslOpts#ssl_options.log_level, Role,
Connection:protocol_name(), StateName, Alert#alert{role = opposite_role(Role)}),
handle_normal_shutdown(Alert, StateName, State),
- {stop, {shutdown, peer_close}};
+ {stop,{shutdown, peer_close}, State};
+
+handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert, connection = StateName,
+ #state{static_env = #static_env{role = Role,
+ protocol_cb = Connection},
+ handshake_env = #handshake_env{renegotiation = {true, From}} = HsEnv,
+ ssl_options = SslOpts
+ } = State0) ->
+ log_alert(SslOpts#ssl_options.log_level, Role,
+ Connection:protocol_name(), StateName, Alert#alert{role = opposite_role(Role)}),
+ gen_statem:reply(From, {error, renegotiation_rejected}),
+ State = Connection:reinit_handshake_data(State0),
+ Connection:next_event(connection, no_record, State#state{handshake_env = HsEnv#handshake_env{renegotiation = undefined}});
handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert, StateName,
- #state{role = Role,
- ssl_options = SslOpts, renegotiation = {true, From},
- protocol_cb = Connection} = State0) ->
- log_alert(SslOpts#ssl_options.log_alert, Role,
+ #state{static_env = #static_env{role = Role,
+ protocol_cb = Connection},
+ handshake_env = #handshake_env{renegotiation = {true, From}} = HsEnv,
+ ssl_options = SslOpts
+ } = State0) ->
+ log_alert(SslOpts#ssl_options.log_level, Role,
Connection:protocol_name(), StateName, Alert#alert{role = opposite_role(Role)}),
gen_statem:reply(From, {error, renegotiation_rejected}),
- {Record, State1} = Connection:next_record(State0),
%% Go back to connection!
- State = Connection:reinit_handshake_data(State1#state{renegotiation = undefined}),
- Connection:next_event(connection, Record, State);
+ State = Connection:reinit(State0#state{handshake_env = HsEnv#handshake_env{renegotiation = undefined}}),
+ Connection:next_event(connection, no_record, State);
%% Gracefully log and ignore all other warning alerts
handle_alert(#alert{level = ?WARNING} = Alert, StateName,
- #state{ssl_options = SslOpts, protocol_cb = Connection, role = Role} = State0) ->
- log_alert(SslOpts#ssl_options.log_alert, Role,
- Connection:protocol_name(), StateName, Alert#alert{role = opposite_role(Role)}),
- {Record, State} = Connection:next_record(State0),
- Connection:next_event(StateName, Record, State).
+ #state{static_env = #static_env{role = Role,
+ protocol_cb = Connection},
+ ssl_options = SslOpts} = State) ->
+ log_alert(SslOpts#ssl_options.log_level, Role,
+ Connection:protocol_name(), StateName,
+ Alert#alert{role = opposite_role(Role)}),
+ Connection:next_event(StateName, no_record, State).
%%====================================================================
%% Data handling
%%====================================================================
-write_application_data(Data0, From,
- #state{socket = Socket,
- negotiated_version = Version,
- protocol_cb = Connection,
- transport_cb = Transport,
- connection_states = ConnectionStates0,
- socket_options = SockOpts,
- ssl_options = #ssl_options{renegotiate_at = RenegotiateAt}} = State) ->
- Data = encode_packet(Data0, SockOpts),
-
- case time_to_renegotiate(Data, ConnectionStates0, RenegotiateAt) of
- true ->
- Connection:renegotiate(State#state{renegotiation = {true, internal}},
- [{next_event, {call, From}, {application_data, Data0}}]);
- false ->
- {Msgs, ConnectionStates} = Connection:encode_data(Data, Version, ConnectionStates0),
- Result = Connection:send(Transport, Socket, Msgs),
- ssl_connection:hibernate_after(connection, State#state{connection_states = ConnectionStates},
- [{reply, From, Result}])
+passive_receive(State0 = #state{user_data_buffer = {_,BufferSize,_}}, StateName, Connection, StartTimerAction) ->
+ case BufferSize of
+ 0 ->
+ Connection:next_event(StateName, no_record, State0, StartTimerAction);
+ _ ->
+ case read_application_data(<<>>, State0) of
+ {stop, _, _} = ShutdownError ->
+ ShutdownError;
+ {Record, State} ->
+ case State#state.start_or_recv_from of
+ undefined ->
+ %% Cancel recv timeout as data has been delivered
+ Connection:next_event(StateName, Record, State,
+ [{{timeout, recv}, infinity, timeout}]);
+ _ ->
+ Connection:next_event(StateName, Record, State, StartTimerAction)
+ end
+ end
end.
-read_application_data(Data, #state{user_application = {_Mon, Pid},
- socket = Socket,
- protocol_cb = Connection,
- transport_cb = Transport,
- socket_options = SOpts,
- bytes_to_read = BytesToRead,
- start_or_recv_from = RecvFrom,
- timer = Timer,
- user_data_buffer = Buffer0,
- tracker = Tracker} = State0) ->
- Buffer1 = if
- Buffer0 =:= <<>> -> Data;
- Data =:= <<>> -> Buffer0;
- true -> <<Buffer0/binary, Data/binary>>
- end,
- case get_data(SOpts, BytesToRead, Buffer1) of
- {ok, ClientData, Buffer} -> % Send data
- SocketOpt = deliver_app_data(Transport, Socket, SOpts,
- ClientData, Pid, RecvFrom, Tracker, Connection),
- cancel_timer(Timer),
- State = State0#state{user_data_buffer = Buffer,
- start_or_recv_from = undefined,
- timer = undefined,
- bytes_to_read = undefined,
- socket_options = SocketOpt
- },
- if
- SocketOpt#socket_options.active =:= false; Buffer =:= <<>> ->
- %% Passive mode, wait for active once or recv
- %% Active and empty, get more data
- Connection:next_record_if_active(State);
- true -> %% We have more data
- read_application_data(<<>>, State)
- end;
- {more, Buffer} -> % no reply, we need more data
- Connection:next_record(State0#state{user_data_buffer = Buffer});
- {passive, Buffer} ->
- Connection:next_record_if_active(State0#state{user_data_buffer = Buffer});
- {error,_Reason} -> %% Invalid packet in packet mode
- deliver_packet_error(Transport, Socket, SOpts, Buffer1, Pid, RecvFrom, Tracker, Connection),
- {stop, normal, State0}
+read_application_data(
+ Data,
+ #state{
+ user_data_buffer = {Front0,BufferSize0,Rear0},
+ connection_env = #connection_env{erl_dist_handle = DHandle}} = State) ->
+ %%
+ Front = Front0,
+ BufferSize = BufferSize0 + byte_size(Data),
+ Rear = [Data|Rear0],
+ case DHandle of
+ undefined ->
+ read_application_data(State, Front, BufferSize, Rear);
+ _ ->
+ try read_application_dist_data(DHandle, Front, BufferSize, Rear) of
+ Buffer ->
+ {no_record, State#state{user_data_buffer = Buffer}}
+ catch error:_ ->
+ {stop,disconnect,
+ State#state{user_data_buffer = {Front,BufferSize,Rear}}}
+ end
+ end.
+
+
+read_application_data(#state{
+ socket_options = SocketOpts,
+ bytes_to_read = BytesToRead,
+ start_or_recv_from = RecvFrom} = State, Front, BufferSize, Rear) ->
+ read_application_data(State, Front, BufferSize, Rear, SocketOpts, RecvFrom, BytesToRead).
+
+%% Pick binary from queue front, if empty wait for more data
+read_application_data(State, [Bin|Front], BufferSize, Rear, SocketOpts, RecvFrom, BytesToRead) ->
+ read_application_data_bin(State, Front, BufferSize, Rear, SocketOpts, RecvFrom, BytesToRead, Bin);
+read_application_data(State, [] = Front, BufferSize, [] = Rear, SocketOpts, RecvFrom, BytesToRead) ->
+ 0 = BufferSize, % Assert
+ {no_record, State#state{socket_options = SocketOpts,
+ bytes_to_read = BytesToRead,
+ start_or_recv_from = RecvFrom,
+ user_data_buffer = {Front,BufferSize,Rear}}};
+read_application_data(State, [], BufferSize, Rear, SocketOpts, RecvFrom, BytesToRead) ->
+ [Bin|Front] = lists:reverse(Rear),
+ read_application_data_bin(State, Front, BufferSize, [], SocketOpts, RecvFrom, BytesToRead, Bin).
+
+read_application_data_bin(State, Front, BufferSize, Rear, SocketOpts, RecvFrom, BytesToRead, <<>>) ->
+ %% Done with this binary - get next
+ read_application_data(State, Front, BufferSize, Rear, SocketOpts, RecvFrom, BytesToRead);
+read_application_data_bin(State, Front0, BufferSize0, Rear0, SocketOpts0, RecvFrom, BytesToRead, Bin0) ->
+ %% Decode one packet from a binary
+ case get_data(SocketOpts0, BytesToRead, Bin0) of
+ {ok, Data, Bin} -> % Send data
+ BufferSize = BufferSize0 - (byte_size(Bin0) - byte_size(Bin)),
+ read_application_data_deliver(
+ State, [Bin|Front0], BufferSize, Rear0, SocketOpts0, RecvFrom, Data);
+ {more, undefined} ->
+ %% We need more data, do not know how much
+ if
+ byte_size(Bin0) < BufferSize0 ->
+ %% We have more data in the buffer besides the first binary - concatenate all and retry
+ Bin = iolist_to_binary([Bin0,Front0|lists:reverse(Rear0)]),
+ read_application_data_bin(
+ State, [], BufferSize0, [], SocketOpts0, RecvFrom, BytesToRead, Bin);
+ true ->
+ %% All data is in the first binary, no use to retry - wait for more
+ {no_record, State#state{socket_options = SocketOpts0,
+ bytes_to_read = BytesToRead,
+ start_or_recv_from = RecvFrom,
+ user_data_buffer = {[Bin0|Front0],BufferSize0,Rear0}}}
+ end;
+ {more, Size} when Size =< BufferSize0 ->
+ %% We have a packet in the buffer - collect it in a binary and decode
+ {Data,Front,Rear} = iovec_from_front(Size - byte_size(Bin0), Front0, Rear0, [Bin0]),
+ Bin = iolist_to_binary(Data),
+ read_application_data_bin(
+ State, Front, BufferSize0, Rear, SocketOpts0, RecvFrom, BytesToRead, Bin);
+ {more, _Size} ->
+ %% We do not have a packet in the buffer - wait for more
+ {no_record, State#state{socket_options = SocketOpts0,
+ bytes_to_read = BytesToRead,
+ start_or_recv_from = RecvFrom,
+ user_data_buffer = {[Bin0|Front0],BufferSize0,Rear0}}};
+ passive ->
+ {no_record, State#state{socket_options = SocketOpts0,
+ bytes_to_read = BytesToRead,
+ start_or_recv_from = RecvFrom,
+ user_data_buffer = {[Bin0|Front0],BufferSize0,Rear0}}};
+ {error,_Reason} ->
+ %% Invalid packet in packet mode
+ #state{
+ static_env =
+ #static_env{
+ socket = Socket,
+ protocol_cb = Connection,
+ transport_cb = Transport,
+ tracker = Tracker},
+ connection_env =
+ #connection_env{user_application = {_Mon, Pid}}} = State,
+ Buffer = iolist_to_binary([Bin0,Front0|lists:reverse(Rear0)]),
+ deliver_packet_error(
+ Connection:pids(State), Transport, Socket, SocketOpts0,
+ Buffer, Pid, RecvFrom, Tracker, Connection),
+ {stop, {shutdown, normal}, State#state{socket_options = SocketOpts0,
+ bytes_to_read = BytesToRead,
+ start_or_recv_from = RecvFrom,
+ user_data_buffer = {[Buffer],BufferSize0,[]}}}
end.
+
+read_application_data_deliver(State, Front, BufferSize, Rear, SocketOpts0, RecvFrom, Data) ->
+ #state{
+ static_env =
+ #static_env{
+ socket = Socket,
+ protocol_cb = Connection,
+ transport_cb = Transport,
+ tracker = Tracker},
+ connection_env =
+ #connection_env{user_application = {_Mon, Pid}}} = State,
+ SocketOpts =
+ deliver_app_data(
+ Connection:pids(State), Transport, Socket, SocketOpts0, Data, Pid, RecvFrom, Tracker, Connection),
+ if
+ SocketOpts#socket_options.active =:= false ->
+ %% Passive mode, wait for active once or recv
+ {no_record,
+ State#state{
+ user_data_buffer = {Front,BufferSize,Rear},
+ start_or_recv_from = undefined,
+ bytes_to_read = undefined,
+ socket_options = SocketOpts
+ }};
+ true -> %% Try to deliver more data
+ read_application_data(State, Front, BufferSize, Rear, SocketOpts, undefined, undefined)
+ end.
+
+
+read_application_dist_data(DHandle, [Bin|Front], BufferSize, Rear) ->
+ read_application_dist_data(DHandle, Front, BufferSize, Rear, Bin);
+read_application_dist_data(_DHandle, [] = Front, BufferSize, [] = Rear) ->
+ BufferSize = 0,
+ {Front,BufferSize,Rear};
+read_application_dist_data(DHandle, [], BufferSize, Rear) ->
+ [Bin|Front] = lists:reverse(Rear),
+ read_application_dist_data(DHandle, Front, BufferSize, [], Bin).
+%%
+read_application_dist_data(DHandle, Front0, BufferSize, Rear0, Bin0) ->
+ case Bin0 of
+ %%
+ %% START Optimization
+ %% It is cheaper to match out several packets in one match operation than to loop for each
+ <<SizeA:32, DataA:SizeA/binary,
+ SizeB:32, DataB:SizeB/binary,
+ SizeC:32, DataC:SizeC/binary,
+ SizeD:32, DataD:SizeD/binary, Rest/binary>> ->
+ %% We have 4 complete packets in the first binary
+ erlang:dist_ctrl_put_data(DHandle, DataA),
+ erlang:dist_ctrl_put_data(DHandle, DataB),
+ erlang:dist_ctrl_put_data(DHandle, DataC),
+ erlang:dist_ctrl_put_data(DHandle, DataD),
+ read_application_dist_data(
+ DHandle, Front0, BufferSize - (4*4+SizeA+SizeB+SizeC+SizeD), Rear0, Rest);
+ <<SizeA:32, DataA:SizeA/binary,
+ SizeB:32, DataB:SizeB/binary,
+ SizeC:32, DataC:SizeC/binary, Rest/binary>> ->
+ %% We have 3 complete packets in the first binary
+ erlang:dist_ctrl_put_data(DHandle, DataA),
+ erlang:dist_ctrl_put_data(DHandle, DataB),
+ erlang:dist_ctrl_put_data(DHandle, DataC),
+ read_application_dist_data(
+ DHandle, Front0, BufferSize - (3*4+SizeA+SizeB+SizeC), Rear0, Rest);
+ <<SizeA:32, DataA:SizeA/binary,
+ SizeB:32, DataB:SizeB/binary, Rest/binary>> ->
+ %% We have 2 complete packets in the first binary
+ erlang:dist_ctrl_put_data(DHandle, DataA),
+ erlang:dist_ctrl_put_data(DHandle, DataB),
+ read_application_dist_data(
+ DHandle, Front0, BufferSize - (2*4+SizeA+SizeB), Rear0, Rest);
+ %% END Optimization
+ %%
+ %% Basic one packet code path
+ <<Size:32, Data:Size/binary, Rest/binary>> ->
+ %% We have a complete packet in the first binary
+ erlang:dist_ctrl_put_data(DHandle, Data),
+ read_application_dist_data(DHandle, Front0, BufferSize - (4+Size), Rear0, Rest);
+ <<Size:32, FirstData/binary>> when 4+Size =< BufferSize ->
+ %% We have a complete packet in the buffer
+ %% - fetch the missing content from the buffer front
+ {Data,Front,Rear} = iovec_from_front(Size - byte_size(FirstData), Front0, Rear0, [FirstData]),
+ erlang:dist_ctrl_put_data(DHandle, Data),
+ read_application_dist_data(DHandle, Front, BufferSize - (4+Size), Rear);
+ <<Bin/binary>> ->
+ %% In OTP-21 the match context reuse optimization fails if we use Bin0 in recursion, so here we
+ %% match out the whole binary which will trick the optimization into keeping the match context
+ %% for the first binary contains complete packet code above
+ case Bin of
+ <<_Size:32, _InsufficientData/binary>> ->
+ %% We have a length field in the first binary but there is not enough data
+ %% in the buffer to form a complete packet - await more data
+ {[Bin|Front0],BufferSize,Rear0};
+ <<IncompleteLengthField/binary>> when 4 < BufferSize ->
+ %% We do not have a length field in the first binary but the buffer
+ %% contains enough data to maybe form a packet
+ %% - fetch a tiny binary from the buffer front to complete the length field
+ {LengthField,Front,Rear} =
+ iovec_from_front(4 - byte_size(IncompleteLengthField), Front0, Rear0, [IncompleteLengthField]),
+ LengthBin = iolist_to_binary(LengthField),
+ read_application_dist_data(DHandle, Front, BufferSize, Rear, LengthBin);
+ <<IncompleteLengthField/binary>> ->
+ %% We do not have enough data in the buffer to even form a length field - await more data
+ {[IncompleteLengthField|Front0],BufferSize,Rear0}
+ end
+ end.
+
+iovec_from_front(Size, [], Rear, Acc) ->
+ iovec_from_front(Size, lists:reverse(Rear), [], Acc);
+iovec_from_front(Size, [Bin|Front], Rear, Acc) ->
+ case Bin of
+ <<Last:Size/binary>> -> % Just enough
+ {lists:reverse(Acc, [Last]),Front,Rear};
+ <<Last:Size/binary, Rest/binary>> -> % More than enough, split here
+ {lists:reverse(Acc, [Last]),[Rest|Front],Rear};
+ <<_/binary>> -> % Not enough
+ BinSize = byte_size(Bin),
+ iovec_from_front(Size - BinSize, Front, Rear, [Bin|Acc])
+ end.
+
+
%%====================================================================
%% Help functions for tls|dtls_connection.erl
%%====================================================================
@@ -446,10 +700,10 @@ handle_session(#server_hello{cipher_suite = CipherSuite,
compression_method = Compression},
Version, NewId, ConnectionStates, ProtoExt, Protocol0,
#state{session = #session{session_id = OldId},
- negotiated_version = ReqVersion,
- negotiated_protocol = CurrentProtocol} = State0) ->
+ handshake_env = #handshake_env{negotiated_protocol = CurrentProtocol} = HsEnv,
+ connection_env = #connection_env{negotiated_version = ReqVersion} = CEnv} = State0) ->
#{key_exchange := KeyAlgorithm} =
- ssl_cipher:suite_definition(CipherSuite),
+ ssl_cipher_format:suite_bin_to_map(CipherSuite),
PremasterSecret = make_premaster_secret(ReqVersion, KeyAlgorithm),
@@ -460,12 +714,12 @@ handle_session(#server_hello{cipher_suite = CipherSuite,
{ProtoExt =:= npn, Protocol0}
end,
- State = State0#state{key_algorithm = KeyAlgorithm,
- negotiated_version = Version,
- connection_states = ConnectionStates,
- premaster_secret = PremasterSecret,
- expecting_next_protocol_negotiation = ExpectNPN,
- negotiated_protocol = Protocol},
+ State = State0#state{connection_states = ConnectionStates,
+ handshake_env = HsEnv#handshake_env{kex_algorithm = KeyAlgorithm,
+ premaster_secret = PremasterSecret,
+ expecting_next_protocol_negotiation = ExpectNPN,
+ negotiated_protocol = Protocol},
+ connection_env = CEnv#connection_env{negotiated_version = Version}},
case ssl_session:is_new(OldId, NewId) of
true ->
@@ -479,7 +733,9 @@ handle_session(#server_hello{cipher_suite = CipherSuite,
%%--------------------------------------------------------------------
-spec ssl_config(#ssl_options{}, client | server, #state{}) -> #state{}.
%%--------------------------------------------------------------------
-ssl_config(Opts, Role, State) ->
+ssl_config(Opts, Role, #state{static_env = InitStatEnv0,
+ handshake_env = HsEnv,
+ connection_env = CEnv} = State0) ->
{ok, #{cert_db_ref := Ref,
cert_db_handle := CertDbHandle,
fileref_db_handle := FileRefHandle,
@@ -489,20 +745,21 @@ ssl_config(Opts, Role, State) ->
dh_params := DHParams,
own_certificate := OwnCert}} =
ssl_config:init(Opts, Role),
- Handshake = ssl_handshake:init_handshake_history(),
TimeStamp = erlang:monotonic_time(),
- Session = State#state.session,
- State#state{tls_handshake_history = Handshake,
- session = Session#session{own_certificate = OwnCert,
- time_stamp = TimeStamp},
- file_ref_db = FileRefHandle,
- cert_db_ref = Ref,
- cert_db = CertDbHandle,
- crl_db = CRLDbHandle,
- session_cache = CacheHandle,
- private_key = Key,
- diffie_hellman_params = DHParams,
- ssl_options = Opts}.
+ Session = State0#state.session,
+
+ State0#state{session = Session#session{own_certificate = OwnCert,
+ time_stamp = TimeStamp},
+ static_env = InitStatEnv0#static_env{
+ file_ref_db = FileRefHandle,
+ cert_db_ref = Ref,
+ cert_db = CertDbHandle,
+ crl_db = CRLDbHandle,
+ session_cache = CacheHandle
+ },
+ handshake_env = HsEnv#handshake_env{diffie_hellman_params = DHParams},
+ connection_env = CEnv#connection_env{private_key = Key},
+ ssl_options = Opts}.
%%====================================================================
%% gen_statem general state functions with connection cb argument
@@ -515,23 +772,25 @@ ssl_config(Opts, Role, State) ->
%%--------------------------------------------------------------------
init({call, From}, {start, Timeout}, State0, Connection) ->
- Timer = start_or_recv_cancel_timer(Timeout, From),
- {Record, State} = Connection:next_record(State0#state{start_or_recv_from = From,
- timer = Timer}),
- Connection:next_event(hello, Record, State);
+ Connection:next_event(hello, no_record, State0#state{start_or_recv_from = From},
+ [{{timeout, handshake}, Timeout, close}]);
init({call, From}, {start, {Opts, EmOpts}, Timeout},
- #state{role = Role, ssl_options = OrigSSLOptions,
+ #state{static_env = #static_env{role = Role},
+ ssl_options = OrigSSLOptions,
socket_options = SockOpts} = State0, Connection) ->
try
SslOpts = ssl:handle_options(Opts, OrigSSLOptions),
State = ssl_config(SslOpts, Role, State0),
init({call, From}, {start, Timeout},
- State#state{ssl_options = SslOpts, socket_options = new_emulated(EmOpts, SockOpts)}, Connection)
+ State#state{ssl_options = SslOpts,
+ socket_options = new_emulated(EmOpts, SockOpts)}, Connection)
catch throw:Error ->
- {stop_and_reply, normal, {reply, From, {error, Error}}}
+ {stop_and_reply, {shutdown, normal}, {reply, From, {error, Error}}, State0}
end;
-init({call, From}, Msg, State, Connection) ->
+init({call, From}, {new_user, _} = Msg, State, Connection) ->
handle_call(Msg, From, ?FUNCTION_NAME, State, Connection);
+init({call, From}, _Msg, _State, _Connection) ->
+ {keep_state_and_data, [{reply, From, {error, notsup_on_transport_accept_socket}}]};
init(_Type, _Event, _State, _Connection) ->
{keep_state_and_data, [postpone]}.
@@ -541,8 +800,10 @@ init(_Type, _Event, _State, _Connection) ->
tls_connection | dtls_connection) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
-error({call, From}, Msg, State, Connection) ->
- handle_call(Msg, From, ?FUNCTION_NAME, State, Connection).
+error({call, From}, {close, _}, State, _Connection) ->
+ {stop_and_reply, {shutdown, normal}, {reply, From, ok}, State};
+error({call, From}, _Msg, State, _Connection) ->
+ {next_state, ?FUNCTION_NAME, State, [{reply, From, {error, closed}}]}.
%%--------------------------------------------------------------------
-spec hello(gen_statem:event_type(),
@@ -559,6 +820,21 @@ hello(info, Msg, State, _) ->
hello(Type, Msg, State, Connection) ->
handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection).
+user_hello({call, From}, cancel, #state{connection_env = #connection_env{negotiated_version = Version}} = State, _) ->
+ gen_statem:reply(From, ok),
+ handle_own_alert(?ALERT_REC(?FATAL, ?USER_CANCELED, user_canceled),
+ Version, ?FUNCTION_NAME, State);
+user_hello({call, From}, {handshake_continue, NewOptions, Timeout},
+ #state{static_env = #static_env{role = Role},
+ handshake_env = #handshake_env{hello = Hello},
+ ssl_options = Options0} = State0, _Connection) ->
+ Options = ssl:handle_options(NewOptions, Options0#ssl_options{handshake = full}),
+ State = ssl_config(Options, Role, State0),
+ {next_state, hello, State#state{start_or_recv_from = From},
+ [{next_event, internal, Hello}, {{timeout, handshake}, Timeout, close}]};
+user_hello(_, _, _, _) ->
+ {keep_state_and_data, [postpone]}.
+
%%--------------------------------------------------------------------
-spec abbreviated(gen_statem:event_type(),
#hello_request{} | #finished{} | term(),
@@ -568,61 +844,63 @@ hello(Type, Msg, State, Connection) ->
abbreviated({call, From}, Msg, State, Connection) ->
handle_call(Msg, From, ?FUNCTION_NAME, State, Connection);
abbreviated(internal, #finished{verify_data = Data} = Finished,
- #state{role = server,
- negotiated_version = Version,
- expecting_finished = true,
- tls_handshake_history = Handshake,
+ #state{static_env = #static_env{role = server},
+ handshake_env = #handshake_env{tls_handshake_history = Hist,
+ expecting_finished = true} = HsEnv,
+ connection_env = #connection_env{negotiated_version = Version},
session = #session{master_secret = MasterSecret},
connection_states = ConnectionStates0} =
State0, Connection) ->
case ssl_handshake:verify_connection(ssl:tls_version(Version), Finished, client,
get_current_prf(ConnectionStates0, write),
- MasterSecret, Handshake) of
+ MasterSecret, Hist) of
verified ->
ConnectionStates =
ssl_record:set_client_verify_data(current_both, Data, ConnectionStates0),
{Record, State} = prepare_connection(State0#state{connection_states = ConnectionStates,
- expecting_finished = false}, Connection),
- Connection:next_event(connection, Record, State);
+ handshake_env = HsEnv#handshake_env{expecting_finished = false}}, Connection),
+ Connection:next_event(connection, Record, State, [{{timeout, handshake}, infinity, close}]);
#alert{} = Alert ->
handle_own_alert(Alert, Version, ?FUNCTION_NAME, State0)
end;
abbreviated(internal, #finished{verify_data = Data} = Finished,
- #state{role = client, tls_handshake_history = Handshake0,
+ #state{static_env = #static_env{role = client},
+ handshake_env = #handshake_env{tls_handshake_history = Hist0},
+ connection_env = #connection_env{negotiated_version = Version},
session = #session{master_secret = MasterSecret},
- negotiated_version = Version,
connection_states = ConnectionStates0} = State0, Connection) ->
case ssl_handshake:verify_connection(ssl:tls_version(Version), Finished, server,
get_pending_prf(ConnectionStates0, write),
- MasterSecret, Handshake0) of
+ MasterSecret, Hist0) of
verified ->
ConnectionStates1 =
ssl_record:set_server_verify_data(current_read, Data, ConnectionStates0),
- {State1, Actions} =
+ {#state{handshake_env = HsEnv} = State1, Actions} =
finalize_handshake(State0#state{connection_states = ConnectionStates1},
?FUNCTION_NAME, Connection),
- {Record, State} = prepare_connection(State1#state{expecting_finished = false}, Connection),
- Connection:next_event(connection, Record, State, Actions);
+ {Record, State} = prepare_connection(State1#state{handshake_env = HsEnv#handshake_env{expecting_finished = false}}, Connection),
+ Connection:next_event(connection, Record, State, [{{timeout, handshake}, infinity, close} | Actions]);
#alert{} = Alert ->
handle_own_alert(Alert, Version, ?FUNCTION_NAME, State0)
end;
%% only allowed to send next_protocol message after change cipher spec
%% & before finished message and it is not allowed during renegotiation
abbreviated(internal, #next_protocol{selected_protocol = SelectedProtocol},
- #state{role = server, expecting_next_protocol_negotiation = true} = State0,
+ #state{static_env = #static_env{role = server},
+ handshake_env = #handshake_env{expecting_next_protocol_negotiation = true} = HsEnv} = State,
Connection) ->
- {Record, State} =
- Connection:next_record(State0#state{negotiated_protocol = SelectedProtocol}),
- Connection:next_event(?FUNCTION_NAME, Record,
- State#state{expecting_next_protocol_negotiation = false});
+ Connection:next_event(?FUNCTION_NAME, no_record,
+ State#state{handshake_env = HsEnv#handshake_env{negotiated_protocol = SelectedProtocol,
+ expecting_next_protocol_negotiation = false}});
abbreviated(internal,
- #change_cipher_spec{type = <<1>>}, #state{connection_states = ConnectionStates0} =
- State0, Connection) ->
+ #change_cipher_spec{type = <<1>>},
+ #state{connection_states = ConnectionStates0,
+ handshake_env = HsEnv} = State, Connection) ->
ConnectionStates1 =
ssl_record:activate_pending_connection_state(ConnectionStates0, read, Connection),
- {Record, State} = Connection:next_record(State0#state{connection_states =
- ConnectionStates1}),
- Connection:next_event(?FUNCTION_NAME, Record, State#state{expecting_finished = true});
+ Connection:next_event(?FUNCTION_NAME, no_record, State#state{connection_states =
+ ConnectionStates1,
+ handshake_env = HsEnv#handshake_env{expecting_finished = true}});
abbreviated(info, Msg, State, _) ->
handle_info(Msg, ?FUNCTION_NAME, State);
abbreviated(Type, Msg, State, Connection) ->
@@ -640,34 +918,34 @@ certify({call, From}, Msg, State, Connection) ->
certify(info, Msg, State, _) ->
handle_info(Msg, ?FUNCTION_NAME, State);
certify(internal, #certificate{asn1_certificates = []},
- #state{role = server, negotiated_version = Version,
+ #state{static_env = #static_env{role = server},
+ connection_env = #connection_env{negotiated_version = Version},
ssl_options = #ssl_options{verify = verify_peer,
fail_if_no_peer_cert = true}} =
State, _) ->
Alert = ?ALERT_REC(?FATAL,?HANDSHAKE_FAILURE),
handle_own_alert(Alert, Version, ?FUNCTION_NAME, State);
certify(internal, #certificate{asn1_certificates = []},
- #state{role = server,
+ #state{static_env = #static_env{role = server},
ssl_options = #ssl_options{verify = verify_peer,
fail_if_no_peer_cert = false}} =
State0, Connection) ->
- {Record, State} =
- Connection:next_record(State0#state{client_certificate_requested = false}),
- Connection:next_event(?FUNCTION_NAME, Record, State);
+ Connection:next_event(?FUNCTION_NAME, no_record, State0#state{client_certificate_requested = false});
certify(internal, #certificate{},
- #state{role = server,
- negotiated_version = Version,
+ #state{static_env = #static_env{role = server},
+ connection_env = #connection_env{negotiated_version = Version},
ssl_options = #ssl_options{verify = verify_none}} =
State, _) ->
Alert = ?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE, unrequested_certificate),
handle_own_alert(Alert, Version, ?FUNCTION_NAME, State);
certify(internal, #certificate{} = Cert,
- #state{negotiated_version = Version,
- role = Role,
- host = Host,
- cert_db = CertDbHandle,
- cert_db_ref = CertDbRef,
- crl_db = CRLDbInfo,
+ #state{static_env = #static_env{
+ role = Role,
+ host = Host,
+ cert_db = CertDbHandle,
+ cert_db_ref = CertDbRef,
+ crl_db = CRLDbInfo},
+ connection_env = #connection_env{negotiated_version = Version},
ssl_options = Opts} = State, Connection) ->
case ssl_handshake:certify(Cert, CertDbHandle, CertDbRef,
Opts, CRLDbInfo, Role, Host) of
@@ -678,95 +956,132 @@ certify(internal, #certificate{} = Cert,
handle_own_alert(Alert, Version, ?FUNCTION_NAME, State)
end;
certify(internal, #server_key_exchange{exchange_keys = Keys},
- #state{role = client, negotiated_version = Version,
- key_algorithm = Alg,
- public_key_info = PubKeyInfo,
+ #state{static_env = #static_env{role = client},
+ handshake_env = #handshake_env{kex_algorithm = KexAlg,
+ public_key_info = PubKeyInfo} = HsEnv,
+ connection_env = #connection_env{negotiated_version = Version},
+ session = Session,
connection_states = ConnectionStates} = State, Connection)
- when Alg == dhe_dss; Alg == dhe_rsa;
- Alg == ecdhe_rsa; Alg == ecdhe_ecdsa;
- Alg == dh_anon; Alg == ecdh_anon;
- Alg == psk; Alg == dhe_psk; Alg == rsa_psk;
- Alg == srp_dss; Alg == srp_rsa; Alg == srp_anon ->
-
- Params = ssl_handshake:decode_server_key(Keys, Alg, ssl:tls_version(Version)),
+ when KexAlg == dhe_dss;
+ KexAlg == dhe_rsa;
+ KexAlg == ecdhe_rsa;
+ KexAlg == ecdhe_ecdsa;
+ KexAlg == dh_anon;
+ KexAlg == ecdh_anon;
+ KexAlg == psk;
+ KexAlg == dhe_psk;
+ KexAlg == ecdhe_psk;
+ KexAlg == rsa_psk;
+ KexAlg == srp_dss;
+ KexAlg == srp_rsa;
+ KexAlg == srp_anon ->
+
+ Params = ssl_handshake:decode_server_key(Keys, KexAlg, ssl:tls_version(Version)),
%% Use negotiated value if TLS-1.2 otherwhise return default
- HashSign = negotiated_hashsign(Params#server_key_params.hashsign, Alg, PubKeyInfo, ssl:tls_version(Version)),
+ HashSign = negotiated_hashsign(Params#server_key_params.hashsign, KexAlg, PubKeyInfo, ssl:tls_version(Version)),
- case is_anonymous(Alg) of
+ case is_anonymous(KexAlg) of
true ->
calculate_secret(Params#server_key_params.params,
- State#state{hashsign_algorithm = HashSign}, Connection);
+ State#state{handshake_env = HsEnv#handshake_env{hashsign_algorithm = HashSign}}, Connection);
false ->
case ssl_handshake:verify_server_key(Params, HashSign,
ConnectionStates, ssl:tls_version(Version), PubKeyInfo) of
true ->
calculate_secret(Params#server_key_params.params,
- State#state{hashsign_algorithm = HashSign},
- Connection);
+ State#state{handshake_env = HsEnv#handshake_env{hashsign_algorithm = HashSign},
+ session = session_handle_params(Params#server_key_params.params, Session)},
+ Connection);
false ->
handle_own_alert(?ALERT_REC(?FATAL, ?DECRYPT_ERROR),
Version, ?FUNCTION_NAME, State)
end
end;
+certify(internal, #certificate_request{},
+ #state{static_env = #static_env{role = client},
+ handshake_env = #handshake_env{kex_algorithm = KexAlg},
+ connection_env = #connection_env{negotiated_version = Version}} = State, _)
+ when KexAlg == dh_anon;
+ KexAlg == ecdh_anon;
+ KexAlg == psk;
+ KexAlg == dhe_psk;
+ KexAlg == ecdhe_psk;
+ KexAlg == rsa_psk;
+ KexAlg == srp_dss;
+ KexAlg == srp_rsa;
+ KexAlg == srp_anon ->
+ handle_own_alert(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE),
+ Version, ?FUNCTION_NAME, State);
+certify(internal, #certificate_request{},
+ #state{static_env = #static_env{role = client},
+ session = #session{own_certificate = undefined}} = State, Connection) ->
+ %% The client does not have a certificate and will send an empty reply, the server may fail
+ %% or accept the connection by its own preference. No signature algorihms needed as there is
+ %% no certificate to verify.
+ Connection:next_event(?FUNCTION_NAME, no_record, State#state{client_certificate_requested = true});
certify(internal, #certificate_request{} = CertRequest,
- #state{session = #session{own_certificate = Cert},
- role = client,
- ssl_options = #ssl_options{signature_algs = SupportedHashSigns},
- negotiated_version = Version} = State0, Connection) ->
- case ssl_handshake:select_hashsign(CertRequest, Cert, SupportedHashSigns, ssl:tls_version(Version)) of
+ #state{static_env = #static_env{role = client},
+ handshake_env = HsEnv,
+ connection_env = #connection_env{negotiated_version = Version},
+ session = #session{own_certificate = Cert},
+ ssl_options = #ssl_options{signature_algs = SupportedHashSigns}} = State, Connection) ->
+ case ssl_handshake:select_hashsign(CertRequest, Cert,
+ SupportedHashSigns, ssl:tls_version(Version)) of
#alert {} = Alert ->
- handle_own_alert(Alert, Version, ?FUNCTION_NAME, State0);
- NegotiatedHashSign ->
- {Record, State} = Connection:next_record(State0#state{client_certificate_requested = true}),
- Connection:next_event(?FUNCTION_NAME, Record,
- State#state{cert_hashsign_algorithm = NegotiatedHashSign})
+ handle_own_alert(Alert, Version, ?FUNCTION_NAME, State);
+ NegotiatedHashSign ->
+ Connection:next_event(?FUNCTION_NAME, no_record,
+ State#state{client_certificate_requested = true,
+ handshake_env = HsEnv#handshake_env{cert_hashsign_algorithm = NegotiatedHashSign}})
end;
%% PSK and RSA_PSK might bypass the Server-Key-Exchange
certify(internal, #server_hello_done{},
- #state{session = #session{master_secret = undefined},
- negotiated_version = Version,
- psk_identity = PSKIdentity,
- ssl_options = #ssl_options{user_lookup_fun = PSKLookup},
- premaster_secret = undefined,
- role = client,
- key_algorithm = Alg} = State0, Connection)
- when Alg == psk ->
- case ssl_handshake:premaster_secret({Alg, PSKIdentity}, PSKLookup) of
+ #state{static_env = #static_env{role = client},
+ session = #session{master_secret = undefined},
+ connection_env = #connection_env{negotiated_version = Version},
+ handshake_env = #handshake_env{kex_algorithm = KexAlg,
+ premaster_secret = undefined,
+ server_psk_identity = PSKIdentity} = HsEnv,
+ ssl_options = #ssl_options{user_lookup_fun = PSKLookup}} = State0, Connection)
+ when KexAlg == psk ->
+ case ssl_handshake:premaster_secret({KexAlg, PSKIdentity}, PSKLookup) of
#alert{} = Alert ->
handle_own_alert(Alert, Version, ?FUNCTION_NAME, State0);
PremasterSecret ->
State = master_secret(PremasterSecret,
- State0#state{premaster_secret = PremasterSecret}),
- client_certify_and_key_exchange(State, Connection)
+ State0#state{handshake_env =
+ HsEnv#handshake_env{premaster_secret = PremasterSecret}}),
+ client_certify_and_key_exchange(State, Connection)
end;
certify(internal, #server_hello_done{},
- #state{session = #session{master_secret = undefined},
- ssl_options = #ssl_options{user_lookup_fun = PSKLookup},
- negotiated_version = {Major, Minor} = Version,
- psk_identity = PSKIdentity,
- premaster_secret = undefined,
- role = client,
- key_algorithm = Alg} = State0, Connection)
- when Alg == rsa_psk ->
+ #state{static_env = #static_env{role = client},
+ connection_env = #connection_env{negotiated_version = {Major, Minor}} = Version,
+ handshake_env = #handshake_env{kex_algorithm = KexAlg,
+ premaster_secret = undefined,
+ server_psk_identity = PSKIdentity} = HsEnv,
+ session = #session{master_secret = undefined},
+ ssl_options = #ssl_options{user_lookup_fun = PSKLookup}} = State0, Connection)
+ when KexAlg == rsa_psk ->
Rand = ssl_cipher:random_bytes(?NUM_OF_PREMASTERSECRET_BYTES-2),
RSAPremasterSecret = <<?BYTE(Major), ?BYTE(Minor), Rand/binary>>,
- case ssl_handshake:premaster_secret({Alg, PSKIdentity}, PSKLookup,
+ case ssl_handshake:premaster_secret({KexAlg, PSKIdentity}, PSKLookup,
RSAPremasterSecret) of
#alert{} = Alert ->
handle_own_alert(Alert, Version, ?FUNCTION_NAME, State0);
PremasterSecret ->
State = master_secret(PremasterSecret,
- State0#state{premaster_secret = RSAPremasterSecret}),
+ State0#state{handshake_env =
+ HsEnv#handshake_env{premaster_secret = RSAPremasterSecret}}),
client_certify_and_key_exchange(State, Connection)
end;
%% Master secret was determined with help of server-key exchange msg
certify(internal, #server_hello_done{},
- #state{session = #session{master_secret = MasterSecret} = Session,
- connection_states = ConnectionStates0,
- negotiated_version = Version,
- premaster_secret = undefined,
- role = client} = State0, Connection) ->
+ #state{static_env = #static_env{role = client},
+ connection_env = #connection_env{negotiated_version = Version},
+ handshake_env = #handshake_env{premaster_secret = undefined},
+ session = #session{master_secret = MasterSecret} = Session,
+ connection_states = ConnectionStates0} = State0, Connection) ->
case ssl_handshake:master_secret(ssl:tls_version(Version), Session,
ConnectionStates0, client) of
{MasterSecret, ConnectionStates} ->
@@ -777,11 +1092,11 @@ certify(internal, #server_hello_done{},
end;
%% Master secret is calculated from premaster_secret
certify(internal, #server_hello_done{},
- #state{session = Session0,
- connection_states = ConnectionStates0,
- negotiated_version = Version,
- premaster_secret = PremasterSecret,
- role = client} = State0, Connection) ->
+ #state{static_env = #static_env{role = client},
+ connection_env = #connection_env{negotiated_version = Version},
+ handshake_env = #handshake_env{premaster_secret = PremasterSecret},
+ session = Session0,
+ connection_states = ConnectionStates0} = State0, Connection) ->
case ssl_handshake:master_secret(ssl:tls_version(Version), PremasterSecret,
ConnectionStates0, client) of
{MasterSecret, ConnectionStates} ->
@@ -793,14 +1108,15 @@ certify(internal, #server_hello_done{},
handle_own_alert(Alert, Version, ?FUNCTION_NAME, State0)
end;
certify(internal = Type, #client_key_exchange{} = Msg,
- #state{role = server,
+ #state{static_env = #static_env{role = server},
client_certificate_requested = true,
ssl_options = #ssl_options{fail_if_no_peer_cert = true}} = State,
Connection) ->
%% We expect a certificate here
handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection);
certify(internal, #client_key_exchange{exchange_keys = Keys},
- State = #state{key_algorithm = KeyAlg, negotiated_version = Version}, Connection) ->
+ State = #state{handshake_env = #handshake_env{kex_algorithm = KeyAlg},
+ connection_env = #connection_env{negotiated_version = Version}}, Connection) ->
try
certify_client_key_exchange(ssl_handshake:decode_client_key(Keys, KeyAlg, ssl:tls_version(Version)),
State, Connection)
@@ -823,70 +1139,70 @@ cipher(info, Msg, State, _) ->
handle_info(Msg, ?FUNCTION_NAME, State);
cipher(internal, #certificate_verify{signature = Signature,
hashsign_algorithm = CertHashSign},
- #state{role = server,
- key_algorithm = KexAlg,
- public_key_info = PublicKeyInfo,
- negotiated_version = Version,
- session = #session{master_secret = MasterSecret},
- tls_handshake_history = Handshake
- } = State0, Connection) ->
+ #state{static_env = #static_env{role = server},
+ handshake_env = #handshake_env{tls_handshake_history = Hist,
+ kex_algorithm = KexAlg,
+ public_key_info = PubKeyInfo} = HsEnv,
+ connection_env = #connection_env{negotiated_version = Version},
+ session = #session{master_secret = MasterSecret}
+ } = State, Connection) ->
TLSVersion = ssl:tls_version(Version),
%% Use negotiated value if TLS-1.2 otherwhise return default
- HashSign = negotiated_hashsign(CertHashSign, KexAlg, PublicKeyInfo, TLSVersion),
- case ssl_handshake:certificate_verify(Signature, PublicKeyInfo,
- TLSVersion, HashSign, MasterSecret, Handshake) of
+ HashSign = negotiated_hashsign(CertHashSign, KexAlg, PubKeyInfo, TLSVersion),
+ case ssl_handshake:certificate_verify(Signature, PubKeyInfo,
+ TLSVersion, HashSign, MasterSecret, Hist) of
valid ->
- {Record, State} = Connection:next_record(State0),
- Connection:next_event(?FUNCTION_NAME, Record,
- State#state{cert_hashsign_algorithm = HashSign});
+ Connection:next_event(?FUNCTION_NAME, no_record,
+ State#state{handshake_env = HsEnv#handshake_env{cert_hashsign_algorithm = HashSign}});
#alert{} = Alert ->
- handle_own_alert(Alert, Version, ?FUNCTION_NAME, State0)
+ handle_own_alert(Alert, Version, ?FUNCTION_NAME, State)
end;
%% client must send a next protocol message if we are expecting it
cipher(internal, #finished{},
- #state{role = server, expecting_next_protocol_negotiation = true,
- negotiated_protocol = undefined, negotiated_version = Version} = State0,
+ #state{static_env = #static_env{role = server},
+ handshake_env = #handshake_env{expecting_next_protocol_negotiation = true,
+ negotiated_protocol = undefined},
+ connection_env = #connection_env{negotiated_version = Version}} = State0,
_Connection) ->
handle_own_alert(?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE), Version, ?FUNCTION_NAME, State0);
cipher(internal, #finished{verify_data = Data} = Finished,
- #state{negotiated_version = Version,
- host = Host,
- port = Port,
- role = Role,
- expecting_finished = true,
+ #state{static_env = #static_env{role = Role,
+ host = Host,
+ port = Port},
+ handshake_env = #handshake_env{tls_handshake_history = Hist,
+ expecting_finished = true} = HsEnv,
+ connection_env = #connection_env{negotiated_version = Version},
session = #session{master_secret = MasterSecret}
= Session0,
ssl_options = SslOpts,
- connection_states = ConnectionStates0,
- tls_handshake_history = Handshake0} = State, Connection) ->
+ connection_states = ConnectionStates0} = State, Connection) ->
case ssl_handshake:verify_connection(ssl:tls_version(Version), Finished,
opposite_role(Role),
get_current_prf(ConnectionStates0, read),
- MasterSecret, Handshake0) of
+ MasterSecret, Hist) of
verified ->
- Session = register_session(Role, host_id(Role, Host, SslOpts), Port, Session0),
+ Session = handle_session(Role, SslOpts, Host, Port, Session0),
cipher_role(Role, Data, Session,
- State#state{expecting_finished = false}, Connection);
+ State#state{handshake_env = HsEnv#handshake_env{expecting_finished = false}}, Connection);
#alert{} = Alert ->
handle_own_alert(Alert, Version, ?FUNCTION_NAME, State)
end;
%% only allowed to send next_protocol message after change cipher spec
%% & before finished message and it is not allowed during renegotiation
cipher(internal, #next_protocol{selected_protocol = SelectedProtocol},
- #state{role = server, expecting_next_protocol_negotiation = true,
- expecting_finished = true} = State0, Connection) ->
- {Record, State} =
- Connection:next_record(State0#state{negotiated_protocol = SelectedProtocol}),
- Connection:next_event(?FUNCTION_NAME, Record,
- State#state{expecting_next_protocol_negotiation = false});
-cipher(internal, #change_cipher_spec{type = <<1>>}, #state{connection_states = ConnectionStates0} =
- State0, Connection) ->
- ConnectionStates1 =
+ #state{static_env = #static_env{role = server},
+ handshake_env = #handshake_env{expecting_finished = true,
+ expecting_next_protocol_negotiation = true} = HsEnv} = State, Connection) ->
+ Connection:next_event(?FUNCTION_NAME, no_record,
+ State#state{handshake_env = HsEnv#handshake_env{negotiated_protocol = SelectedProtocol,
+ expecting_next_protocol_negotiation = false}});
+cipher(internal, #change_cipher_spec{type = <<1>>}, #state{handshake_env = HsEnv, connection_states = ConnectionStates0} =
+ State, Connection) ->
+ ConnectionStates =
ssl_record:activate_pending_connection_state(ConnectionStates0, read, Connection),
- {Record, State} = Connection:next_record(State0#state{connection_states =
- ConnectionStates1}),
- Connection:next_event(?FUNCTION_NAME, Record, State#state{expecting_finished = true});
+ Connection:next_event(?FUNCTION_NAME, no_record, State#state{handshake_env = HsEnv#handshake_env{expecting_finished = true},
+ connection_states = ConnectionStates});
cipher(Type, Msg, State, Connection) ->
handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection).
@@ -895,26 +1211,18 @@ cipher(Type, Msg, State, Connection) ->
#state{}, tls_connection | dtls_connection) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
-connection({call, From}, {application_data, Data},
- #state{protocol_cb = Connection} = State, Connection) ->
- %% We should look into having a worker process to do this to
- %% parallize send and receive decoding and not block the receiver
- %% if sending is overloading the socket.
- try
- write_application_data(Data, From, State)
- catch throw:Error ->
- hibernate_after(?FUNCTION_NAME, State, [{reply, From, Error}])
- end;
connection({call, RecvFrom}, {recv, N, Timeout},
- #state{protocol_cb = Connection, socket_options =
- #socket_options{active = false}} = State0, Connection) ->
- Timer = start_or_recv_cancel_timer(Timeout, RecvFrom),
- Connection:passive_receive(State0#state{bytes_to_read = N,
- start_or_recv_from = RecvFrom,
- timer = Timer}, ?FUNCTION_NAME);
-connection({call, From}, renegotiate, #state{protocol_cb = Connection} = State,
+ #state{static_env = #static_env{protocol_cb = Connection},
+ socket_options =
+ #socket_options{active = false}} = State0, Connection) ->
+ passive_receive(State0#state{bytes_to_read = N,
+ start_or_recv_from = RecvFrom}, ?FUNCTION_NAME, Connection,
+ [{{timeout, recv}, Timeout, timeout}]);
+
+connection({call, From}, renegotiate, #state{static_env = #static_env{protocol_cb = Connection},
+ handshake_env = HsEnv} = State,
Connection) ->
- Connection:renegotiate(State#state{renegotiation = {true, From}}, []);
+ Connection:renegotiate(State#state{handshake_env = HsEnv#handshake_env{renegotiation = {true, From}}}, []);
connection({call, From}, peer_certificate,
#state{session = #session{peer_certificate = Cert}} = State, _) ->
hibernate_after(?FUNCTION_NAME, State, [{reply, From, {ok, Cert}}]);
@@ -925,18 +1233,36 @@ connection({call, From}, {connection_information, false}, State, _) ->
Info = connection_info(State),
hibernate_after(?FUNCTION_NAME, State, [{reply, From, {ok, Info}}]);
connection({call, From}, negotiated_protocol,
- #state{negotiated_protocol = undefined} = State, _) ->
+ #state{handshake_env = #handshake_env{negotiated_protocol = undefined}} = State, _) ->
hibernate_after(?FUNCTION_NAME, State, [{reply, From, {error, protocol_not_negotiated}}]);
connection({call, From}, negotiated_protocol,
- #state{negotiated_protocol = SelectedProtocol} = State, _) ->
+ #state{handshake_env = #handshake_env{negotiated_protocol = SelectedProtocol}} = State, _) ->
hibernate_after(?FUNCTION_NAME, State,
[{reply, From, {ok, SelectedProtocol}}]);
connection({call, From}, Msg, State, Connection) ->
handle_call(Msg, From, ?FUNCTION_NAME, State, Connection);
+connection(cast, {internal_renegotiate, WriteState}, #state{static_env = #static_env{protocol_cb = Connection},
+ handshake_env = HsEnv,
+ connection_states = ConnectionStates}
+ = State, Connection) ->
+ Connection:renegotiate(State#state{handshake_env = HsEnv#handshake_env{renegotiation = {true, internal}},
+ connection_states = ConnectionStates#{current_write => WriteState}}, []);
+connection(cast, {dist_handshake_complete, DHandle},
+ #state{ssl_options = #ssl_options{erl_dist = true},
+ connection_env = CEnv,
+ socket_options = SockOpts} = State0, Connection) ->
+ process_flag(priority, normal),
+ State1 =
+ State0#state{
+ socket_options = SockOpts#socket_options{active = true},
+ connection_env = CEnv#connection_env{erl_dist_handle = DHandle},
+ bytes_to_read = undefined},
+ {Record, State} = read_application_data(<<>>, State1),
+ Connection:next_event(connection, Record, State);
connection(info, Msg, State, _) ->
handle_info(Msg, ?FUNCTION_NAME, State);
-connection(internal, {recv, _}, State, Connection) ->
- Connection:passive_receive(State, ?FUNCTION_NAME);
+connection(internal, {recv, Timeout}, State, Connection) ->
+ passive_receive(State, ?FUNCTION_NAME, Connection, [{{timeout, recv}, Timeout, timeout}]);
connection(Type, Msg, State, Connection) ->
handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection).
@@ -945,16 +1271,6 @@ connection(Type, Msg, State, Connection) ->
#state{}, tls_connection | dtls_connection) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
-downgrade(internal, #alert{description = ?CLOSE_NOTIFY},
- #state{transport_cb = Transport, socket = Socket,
- downgrade = {Pid, From}} = State, _) ->
- tls_socket:setopts(Transport, Socket, [{active, false}, {packet, 0}, {mode, binary}]),
- Transport:controlling_process(Socket, Pid),
- gen_statem:reply(From, {ok, Socket}),
- {stop, normal, State};
-downgrade(timeout, downgrade, #state{downgrade = {_, From}} = State, _) ->
- gen_statem:reply(From, {error, timeout}),
- {stop, normal, State};
downgrade(Type, Event, State, Connection) ->
handle_common_event(Type, Event, ?FUNCTION_NAME, State, Connection).
@@ -963,84 +1279,87 @@ downgrade(Type, Event, State, Connection) ->
%% common or unexpected events for the state.
%%--------------------------------------------------------------------
handle_common_event(internal, {handshake, {#hello_request{} = Handshake, _}}, connection = StateName,
- #state{role = client} = State, _) ->
+ #state{static_env = #static_env{role = client},
+ handshake_env = HsEnv} = State, _) ->
%% Should not be included in handshake history
- {next_state, StateName, State#state{renegotiation = {true, peer}}, [{next_event, internal, Handshake}]};
-handle_common_event(internal, {handshake, {#hello_request{}, _}}, StateName, #state{role = client}, _)
+ {next_state, StateName, State#state{handshake_env = HsEnv#handshake_env{renegotiation = {true, peer}}},
+ [{next_event, internal, Handshake}]};
+handle_common_event(internal, {handshake, {#hello_request{}, _}}, StateName,
+ #state{static_env = #static_env{role = client}}, _)
when StateName =/= connection ->
- {keep_state_and_data};
-handle_common_event(internal, {handshake, {Handshake, Raw}}, StateName,
- #state{tls_handshake_history = Hs0,
- ssl_options = #ssl_options{v2_hello_compatible = V2HComp}} = State0,
+ keep_state_and_data;
+handle_common_event(internal, {handshake, {Handshake, Raw}}, StateName,
+ #state{handshake_env = #handshake_env{tls_handshake_history = Hist0}} = State0,
Connection) ->
PossibleSNI = Connection:select_sni_extension(Handshake),
%% This function handles client SNI hello extension when Handshake is
%% a client_hello, which needs to be determined by the connection callback.
%% In other cases this is a noop
- State = handle_sni_extension(PossibleSNI, State0),
- HsHist = ssl_handshake:update_handshake_history(Hs0, iolist_to_binary(Raw), V2HComp),
- {next_state, StateName, State#state{tls_handshake_history = HsHist},
+ State = #state{handshake_env = HsEnv} = handle_sni_extension(PossibleSNI, State0),
+
+ Hist = ssl_handshake:update_handshake_history(Hist0, Raw),
+ {next_state, StateName, State#state{handshake_env = HsEnv#handshake_env{tls_handshake_history = Hist}},
[{next_event, internal, Handshake}]};
handle_common_event(internal, {protocol_record, TLSorDTLSRecord}, StateName, State, Connection) ->
- Connection:handle_common_event(internal, TLSorDTLSRecord, StateName, State);
+ Connection:handle_protocol_record(TLSorDTLSRecord, StateName, State);
handle_common_event(timeout, hibernate, _, _, _) ->
{keep_state_and_data, [hibernate]};
-handle_common_event(internal, {application_data, Data}, StateName, State0, Connection) ->
- case read_application_data(Data, State0) of
- {stop, Reason, State} ->
- {stop, Reason, State};
- {Record, State} ->
- Connection:next_event(StateName, Record, State)
- end;
handle_common_event(internal, #change_cipher_spec{type = <<1>>}, StateName,
- #state{negotiated_version = Version} = State, _) ->
+ #state{connection_env = #connection_env{negotiated_version = Version}} = State, _) ->
handle_own_alert(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE), Version,
StateName, State);
-handle_common_event(_Type, Msg, StateName, #state{negotiated_version = Version} = State,
+handle_common_event({timeout, handshake}, close, _StateName, #state{start_or_recv_from = StartFrom} = State, _) ->
+ {stop_and_reply,
+ {shutdown, user_timeout},
+ {reply, StartFrom, {error, timeout}}, State#state{start_or_recv_from = undefined}};
+handle_common_event({timeout, recv}, timeout, StateName, #state{start_or_recv_from = RecvFrom} = State, _) ->
+ {next_state, StateName, State#state{start_or_recv_from = undefined,
+ bytes_to_read = undefined}, [{reply, RecvFrom, {error, timeout}}]};
+handle_common_event(Type, Msg, StateName, #state{connection_env =
+ #connection_env{negotiated_version = Version}} = State,
_) ->
- Alert = ?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE, {unexpected_msg, Msg}),
+ Alert = ?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE, {unexpected_msg, {Type,Msg}}),
handle_own_alert(Alert, Version, StateName, State).
handle_call({application_data, _Data}, _, _, _, _) ->
%% In renegotiation priorities handshake, send data when handshake is finished
{keep_state_and_data, [postpone]};
-handle_call({close, {Pid, Timeout}}, From, StateName, State0, Connection) when is_pid(Pid) ->
- %% terminate will send close alert to peer
- State = State0#state{downgrade = {Pid, From}},
- Connection:terminate(downgrade, StateName, State),
- %% User downgrades connection
- %% When downgrading an TLS connection to a transport connection
- %% we must recive the close alert from the peer before releasing the
- %% transport socket.
- {next_state, downgrade, State#state{terminated = true}, [{timeout, Timeout, downgrade}]};
-handle_call({close, _} = Close, From, StateName, State, Connection) ->
+handle_call({close, _} = Close, From, StateName, #state{connection_env = CEnv} = State, _Connection) ->
%% Run terminate before returning so that the reuseaddr
%% inet-option works properly
- Result = Connection:terminate(Close, StateName, State#state{terminated = true}),
- {stop_and_reply, {shutdown, normal},
- {reply, From, Result}, State};
-handle_call({shutdown, How0}, From, _,
- #state{transport_cb = Transport,
- negotiated_version = Version,
- connection_states = ConnectionStates,
- socket = Socket}, Connection) ->
- case How0 of
- How when How == write; How == both ->
- Alert = ?ALERT_REC(?WARNING, ?CLOSE_NOTIFY),
- {BinMsg, _} =
- Connection:encode_alert(Alert, Version, ConnectionStates),
- Connection:send(Transport, Socket, BinMsg);
- _ ->
- ok
- end,
-
+ Result = terminate(Close, StateName, State),
+ {stop_and_reply,
+ {shutdown, normal},
+ {reply, From, Result}, State#state{connection_env = CEnv#connection_env{terminated = true}}};
+handle_call({shutdown, read_write = How}, From, StateName,
+ #state{static_env = #static_env{transport_cb = Transport,
+ socket = Socket},
+ connection_env = CEnv} = State, _) ->
+ try send_alert(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY),
+ StateName, State) of
+ _ ->
+ case Transport:shutdown(Socket, How) of
+ ok ->
+ {next_state, StateName, State#state{connection_env =
+ CEnv#connection_env{terminated = true}},
+ [{reply, From, ok}]};
+ Error ->
+ {stop_and_reply, {shutdown, normal}, {reply, From, Error},
+ State#state{connection_env = CEnv#connection_env{terminated = true}}}
+ end
+ catch
+ throw:Return ->
+ Return
+ end;
+handle_call({shutdown, How0}, From, StateName,
+ #state{static_env = #static_env{transport_cb = Transport,
+ socket = Socket}} = State, _) ->
case Transport:shutdown(Socket, How0) of
ok ->
- {keep_state_and_data, [{reply, From, ok}]};
+ {next_state, StateName, State, [{reply, From, ok}]};
Error ->
- gen_statem:reply(From, {error, Error}),
- {stop, normal}
+ {stop_and_reply, {shutdown, normal}, {reply, From, Error}, State}
end;
handle_call({recv, _N, _Timeout}, From, _,
#state{socket_options =
@@ -1049,35 +1368,47 @@ handle_call({recv, _N, _Timeout}, From, _,
handle_call({recv, N, Timeout}, RecvFrom, StateName, State, _) ->
%% Doing renegotiate wait with handling request until renegotiate is
%% finished.
- Timer = start_or_recv_cancel_timer(Timeout, RecvFrom),
- {next_state, StateName, State#state{bytes_to_read = N, start_or_recv_from = RecvFrom,
- timer = Timer},
- [{next_event, internal, {recv, RecvFrom}}]};
+ {next_state, StateName, State#state{bytes_to_read = N, start_or_recv_from = RecvFrom},
+ [{next_event, internal, {recv, RecvFrom}} , {{timeout, recv}, Timeout, timeout}]};
handle_call({new_user, User}, From, StateName,
- State =#state{user_application = {OldMon, _}}, _) ->
+ State = #state{connection_env = #connection_env{user_application = {OldMon, _}} = CEnv}, _) ->
NewMon = erlang:monitor(process, User),
erlang:demonitor(OldMon, [flush]),
- {next_state, StateName, State#state{user_application = {NewMon,User}},
+ {next_state, StateName, State#state{connection_env = CEnv#connection_env{user_application = {NewMon, User}}},
[{reply, From, ok}]};
handle_call({get_opts, OptTags}, From, _,
- #state{socket = Socket,
- transport_cb = Transport,
+ #state{static_env = #static_env{socket = Socket,
+ transport_cb = Transport},
socket_options = SockOpts}, Connection) ->
OptsReply = get_socket_opts(Connection, Transport, Socket, OptTags, SockOpts, []),
{keep_state_and_data, [{reply, From, OptsReply}]};
handle_call({set_opts, Opts0}, From, StateName,
- #state{socket_options = Opts1,
- socket = Socket,
- transport_cb = Transport} = State0, Connection) ->
+ #state{static_env = #static_env{socket = Socket,
+ transport_cb = Transport,
+ tracker = Tracker},
+ connection_env =
+ #connection_env{user_application = {_Mon, Pid}},
+ socket_options = Opts1
+ } = State0, Connection) ->
{Reply, Opts} = set_socket_opts(Connection, Transport, Socket, Opts0, Opts1, []),
+ case {proplists:lookup(active, Opts0), Opts} of
+ {{_, N}, #socket_options{active=false}} when is_integer(N) ->
+ send_user(
+ Pid,
+ format_passive(
+ Connection:pids(State0), Transport, Socket, Tracker, Connection));
+ _ ->
+ ok
+ end,
State = State0#state{socket_options = Opts},
handle_active_option(Opts#socket_options.active, StateName, From, Reply, State);
handle_call(renegotiate, From, StateName, _, _) when StateName =/= connection ->
{keep_state_and_data, [{reply, From, {error, already_renegotiating}}]};
+
handle_call({prf, Secret, Label, Seed, WantedLength}, From, _,
#state{connection_states = ConnectionStates,
- negotiated_version = Version}, _) ->
+ connection_env = #connection_env{negotiated_version = Version}}, _) ->
#{security_parameters := SecParams} =
ssl_record:current_connection_state(ConnectionStates, read),
#security_parameters{master_secret = MasterSecret,
@@ -1104,53 +1435,59 @@ handle_call(_,_,_,_,_) ->
{keep_state_and_data, [postpone]}.
handle_info({ErrorTag, Socket, econnaborted}, StateName,
- #state{socket = Socket, transport_cb = Transport,
- protocol_cb = Connection,
- start_or_recv_from = StartFrom, role = Role,
- error_tag = ErrorTag,
- tracker = Tracker} = State) when StateName =/= connection ->
- alert_user(Transport, Tracker,Socket,
+ #state{static_env = #static_env{role = Role,
+ socket = Socket,
+ transport_cb = Transport,
+ error_tag = ErrorTag,
+ tracker = Tracker,
+ protocol_cb = Connection},
+ start_or_recv_from = StartFrom
+ } = State) when StateName =/= connection ->
+ Pids = Connection:pids(State),
+ alert_user(Pids, Transport, Tracker,Socket,
StartFrom, ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), Role, Connection),
- {stop, normal, State};
-handle_info({ErrorTag, Socket, Reason}, StateName, #state{socket = Socket,
- error_tag = ErrorTag} = State) ->
+ {stop, {shutdown, normal}, State};
+
+handle_info({ErrorTag, Socket, Reason}, StateName, #state{static_env = #static_env{socket = Socket,
+ error_tag = ErrorTag}} = State) ->
Report = io_lib:format("SSL: Socket error: ~p ~n", [Reason]),
- error_logger:info_report(Report),
+ ?LOG_ERROR(Report),
handle_normal_shutdown(?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), StateName, State),
- {stop, normal, State};
-handle_info({'DOWN', MonitorRef, _, _, _}, _,
- State = #state{user_application={MonitorRef,_Pid}}) ->
- {stop, normal, State};
+ {stop, {shutdown,normal}, State};
+
+handle_info({'DOWN', MonitorRef, _, _, Reason}, _,
+ #state{connection_env = #connection_env{user_application = {MonitorRef, _Pid}},
+ ssl_options = #ssl_options{erl_dist = true}}) ->
+ {stop, {shutdown, Reason}};
+handle_info({'DOWN', MonitorRef, _, _, _}, _,
+ #state{connection_env = #connection_env{user_application = {MonitorRef, _Pid}}}) ->
+ {stop, {shutdown, normal}};
+handle_info({'EXIT', Pid, _Reason}, StateName,
+ #state{connection_env = #connection_env{user_application = {_MonitorRef, Pid}}} = State) ->
+ %% It seems the user application has linked to us
+ %% - ignore that and let the monitor handle this
+ {next_state, StateName, State};
%%% So that terminate will be run when supervisor issues shutdown
handle_info({'EXIT', _Sup, shutdown}, _StateName, State) ->
{stop, shutdown, State};
-handle_info({'EXIT', Socket, normal}, _StateName, #state{socket = Socket} = State) ->
+handle_info({'EXIT', Socket, normal}, _StateName, #state{static_env = #static_env{socket = Socket}} = State) ->
%% Handle as transport close"
- {stop, {shutdown, transport_closed}, State};
-handle_info(allow_renegotiate, StateName, State) ->
- {next_state, StateName, State#state{allow_renegotiate = true}};
-
-handle_info({cancel_start_or_recv, StartFrom}, StateName,
- #state{renegotiation = {false, first}} = State) when StateName =/= connection ->
- {stop_and_reply, {shutdown, user_timeout},
- {reply, StartFrom, {error, timeout}}, State#state{timer = undefined}};
-handle_info({cancel_start_or_recv, RecvFrom}, StateName,
- #state{start_or_recv_from = RecvFrom} = State) when RecvFrom =/= undefined ->
- {next_state, StateName, State#state{start_or_recv_from = undefined,
- bytes_to_read = undefined,
- timer = undefined}, [{reply, RecvFrom, {error, timeout}}]};
-handle_info({cancel_start_or_recv, _RecvFrom}, StateName, State) ->
- {next_state, StateName, State#state{timer = undefined}};
+ {stop,{shutdown, transport_closed}, State};
+handle_info({'EXIT', Socket, Reason}, _StateName, #state{static_env = #static_env{socket = Socket}} = State) ->
+ {stop,{shutdown, Reason}, State};
+
+handle_info(allow_renegotiate, StateName, #state{handshake_env = HsEnv} = State) ->
+ {next_state, StateName, State#state{handshake_env = HsEnv#handshake_env{allow_renegotiate = true}}};
-handle_info(Msg, StateName, #state{socket = Socket, error_tag = Tag} = State) ->
+handle_info(Msg, StateName, #state{static_env = #static_env{socket = Socket, error_tag = Tag}} = State) ->
Report = io_lib:format("SSL: Got unexpected info: ~p ~n", [{Msg, Tag, Socket}]),
- error_logger:info_report(Report),
+ ?LOG_NOTICE(Report),
{next_state, StateName, State}.
%%====================================================================
%% general gen_statem callbacks
%%====================================================================
-terminate(_, _, #state{terminated = true}) ->
+terminate(_, _, #state{connection_env = #connection_env{terminated = true}}) ->
%% Happens when user closes the connection using ssl:close/1
%% we want to guarantee that Transport:close has been called
%% when ssl:close/1 returns unless it is a downgrade where
@@ -1159,14 +1496,15 @@ terminate(_, _, #state{terminated = true}) ->
%% before run by gen_statem which will end up here
ok;
terminate({shutdown, transport_closed} = Reason,
- _StateName, #state{protocol_cb = Connection,
- socket = Socket, transport_cb = Transport} = State) ->
+ _StateName, #state{static_env = #static_env{protocol_cb = Connection,
+ socket = Socket,
+ transport_cb = Transport}} = State) ->
handle_trusted_certs_db(State),
Connection:close(Reason, Socket, Transport, undefined, undefined);
-terminate({shutdown, own_alert}, _StateName, #state{%%send_queue = SendQueue,
- protocol_cb = Connection,
- socket = Socket,
- transport_cb = Transport} = State) ->
+terminate({shutdown, own_alert}, _StateName, #state{
+ static_env = #static_env{protocol_cb = Connection,
+ socket = Socket,
+ transport_cb = Transport}} = State) ->
handle_trusted_certs_db(State),
case application:get_env(ssl, alert_timeout) of
{ok, Timeout} when is_integer(Timeout) ->
@@ -1174,18 +1512,27 @@ terminate({shutdown, own_alert}, _StateName, #state{%%send_queue = SendQueue,
_ ->
Connection:close({timeout, ?DEFAULT_TIMEOUT}, Socket, Transport, undefined, undefined)
end;
-terminate(Reason, connection, #state{negotiated_version = Version,
- protocol_cb = Connection,
- connection_states = ConnectionStates0,
- ssl_options = #ssl_options{padding_check = Check},
- transport_cb = Transport, socket = Socket
- } = State) ->
+terminate({shutdown, downgrade = Reason}, downgrade, #state{static_env = #static_env{protocol_cb = Connection,
+ transport_cb = Transport,
+ socket = Socket}
+ } = State) ->
+ handle_trusted_certs_db(State),
+ Connection:close(Reason, Socket, Transport, undefined, undefined);
+terminate(Reason, connection, #state{static_env = #static_env{
+ protocol_cb = Connection,
+ transport_cb = Transport,
+ socket = Socket},
+ connection_states = ConnectionStates,
+ ssl_options = #ssl_options{padding_check = Check}
+ } = State) ->
handle_trusted_certs_db(State),
- {BinAlert, ConnectionStates} = terminate_alert(Reason, Version, ConnectionStates0, Connection),
- Connection:send(Transport, Socket, BinAlert),
- Connection:close(Reason, Socket, Transport, ConnectionStates, Check);
-terminate(Reason, _StateName, #state{transport_cb = Transport, protocol_cb = Connection,
- socket = Socket
+ Alert = terminate_alert(Reason),
+ %% Send the termination ALERT if possible
+ catch (ok = Connection:send_alert_in_connection(Alert, State)),
+ Connection:close({timeout, ?DEFAULT_TIMEOUT}, Socket, Transport, ConnectionStates, Check);
+terminate(Reason, _StateName, #state{static_env = #static_env{transport_cb = Transport,
+ protocol_cb = Connection,
+ socket = Socket}
} = State) ->
handle_trusted_certs_db(State),
Connection:close(Reason, Socket, Transport, undefined, undefined).
@@ -1204,14 +1551,9 @@ format_status(terminate, [_, StateName, State]) ->
[{data, [{"State", {StateName, State#state{connection_states = ?SECRET_PRINTOUT,
protocol_buffers = ?SECRET_PRINTOUT,
user_data_buffer = ?SECRET_PRINTOUT,
- tls_handshake_history = ?SECRET_PRINTOUT,
+ handshake_env = ?SECRET_PRINTOUT,
+ connection_env = ?SECRET_PRINTOUT,
session = ?SECRET_PRINTOUT,
- private_key = ?SECRET_PRINTOUT,
- diffie_hellman_params = ?SECRET_PRINTOUT,
- diffie_hellman_keys = ?SECRET_PRINTOUT,
- srp_params = ?SECRET_PRINTOUT,
- srp_keys = ?SECRET_PRINTOUT,
- premaster_secret = ?SECRET_PRINTOUT,
ssl_options = NewOptions,
flight_buffer = ?SECRET_PRINTOUT}
}}]}].
@@ -1219,16 +1561,21 @@ format_status(terminate, [_, StateName, State]) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-connection_info(#state{sni_hostname = SNIHostname,
- session = #session{session_id = SessionId,
+send_alert(Alert, connection, #state{static_env = #static_env{protocol_cb = Connection}} = State) ->
+ Connection:send_alert_in_connection(Alert, State);
+send_alert(Alert, _, #state{static_env = #static_env{protocol_cb = Connection}} = State) ->
+ Connection:send_alert(Alert, State).
+
+connection_info(#state{static_env = #static_env{protocol_cb = Connection},
+ handshake_env = #handshake_env{sni_hostname = SNIHostname},
+ session = #session{session_id = SessionId,
cipher_suite = CipherSuite, ecc = ECCCurve},
- protocol_cb = Connection,
- negotiated_version = {_,_} = Version,
+ connection_env = #connection_env{negotiated_version = {_,_} = Version},
ssl_options = Opts}) ->
RecordCB = record_cb(Connection),
- CipherSuiteDef = #{key_exchange := KexAlg} = ssl_cipher:suite_definition(CipherSuite),
+ CipherSuiteDef = #{key_exchange := KexAlg} = ssl_cipher_format:suite_bin_to_map(CipherSuite),
IsNamedCurveSuite = lists:member(KexAlg,
- [ecdh_ecdsa, ecdhe_ecdsa, ecdh_anon]),
+ [ecdh_ecdsa, ecdhe_ecdsa, ecdh_rsa, ecdhe_rsa, ecdh_anon]),
CurveInfo = case ECCCurve of
{namedCurve, Curve} when IsNamedCurveSuite ->
[{ecc, {named_curve, pubkey_cert_records:namedCurves(Curve)}}];
@@ -1237,7 +1584,8 @@ connection_info(#state{sni_hostname = SNIHostname,
end,
[{protocol, RecordCB:protocol_version(Version)},
{session_id, SessionId},
- {cipher_suite, ssl_cipher:erl_suite_definition(CipherSuiteDef)},
+ {cipher_suite, ssl_cipher_format:suite_legacy(CipherSuiteDef)},
+ {selected_cipher_suite, CipherSuiteDef},
{sni_hostname, SNIHostname} | CurveInfo] ++ ssl_options_list(Opts).
security_info(#state{connection_states = ConnectionStates}) ->
@@ -1248,18 +1596,24 @@ security_info(#state{connection_states = ConnectionStates}) ->
ssl_record:current_connection_state(ConnectionStates, read),
[{client_random, ClientRand}, {server_random, ServerRand}, {master_secret, MasterSecret}].
-do_server_hello(Type, #hello_extensions{next_protocol_negotiation = NextProtocols} =
+do_server_hello(Type, #{next_protocol_negotiation := NextProtocols} =
ServerHelloExt,
- #state{negotiated_version = Version,
+ #state{connection_env = #connection_env{negotiated_version = Version},
+ handshake_env = HsEnv,
session = #session{session_id = SessId},
- connection_states = ConnectionStates0}
+ connection_states = ConnectionStates0,
+ ssl_options = #ssl_options{versions = [HighestVersion|_]}}
= State0, Connection) when is_atom(Type) ->
-
+ %% TLS 1.3 - Section 4.1.3
+ %% Override server random values for TLS 1.3 downgrade protection mechanism.
+ ConnectionStates1 = update_server_random(ConnectionStates0, Version, HighestVersion),
+ State1 = State0#state{connection_states = ConnectionStates1},
ServerHello =
- ssl_handshake:server_hello(SessId, ssl:tls_version(Version), ConnectionStates0, ServerHelloExt),
+ ssl_handshake:server_hello(SessId, ssl:tls_version(Version),
+ ConnectionStates1, ServerHelloExt),
State = server_hello(ServerHello,
- State0#state{expecting_next_protocol_negotiation =
- NextProtocols =/= undefined}, Connection),
+ State1#state{handshake_env = HsEnv#handshake_env{expecting_next_protocol_negotiation =
+ NextProtocols =/= undefined}}, Connection),
case Type of
new ->
new_server_hello(ServerHello, State, Connection);
@@ -1267,20 +1621,73 @@ do_server_hello(Type, #hello_extensions{next_protocol_negotiation = NextProtocol
resumed_server_hello(State, Connection)
end.
+update_server_random(#{pending_read := #{security_parameters := ReadSecParams0} =
+ ReadState0,
+ pending_write := #{security_parameters := WriteSecParams0} =
+ WriteState0} = ConnectionStates,
+ Version, HighestVersion) ->
+ ReadRandom = override_server_random(
+ ReadSecParams0#security_parameters.server_random,
+ Version,
+ HighestVersion),
+ WriteRandom = override_server_random(
+ WriteSecParams0#security_parameters.server_random,
+ Version,
+ HighestVersion),
+ ReadSecParams = ReadSecParams0#security_parameters{server_random = ReadRandom},
+ WriteSecParams = WriteSecParams0#security_parameters{server_random = WriteRandom},
+ ReadState = ReadState0#{security_parameters => ReadSecParams},
+ WriteState = WriteState0#{security_parameters => WriteSecParams},
+
+ ConnectionStates#{pending_read => ReadState, pending_write => WriteState}.
+
+%% TLS 1.3 - Section 4.1.3
+%%
+%% If negotiating TLS 1.2, TLS 1.3 servers MUST set the last eight bytes
+%% of their Random value to the bytes:
+%%
+%% 44 4F 57 4E 47 52 44 01
+%%
+%% If negotiating TLS 1.1 or below, TLS 1.3 servers MUST and TLS 1.2
+%% servers SHOULD set the last eight bytes of their Random value to the
+%% bytes:
+%%
+%% 44 4F 57 4E 47 52 44 00
+override_server_random(<<Random0:24/binary,_:8/binary>> = Random, {M,N}, {Major,Minor})
+ when Major > 3 orelse Major =:= 3 andalso Minor >= 4 -> %% TLS 1.3 or above
+ if M =:= 3 andalso N =:= 3 -> %% Negotating TLS 1.2
+ Down = ?RANDOM_OVERRIDE_TLS12,
+ <<Random0/binary,Down/binary>>;
+ M =:= 3 andalso N < 3 -> %% Negotating TLS 1.1 or prior
+ Down = ?RANDOM_OVERRIDE_TLS11,
+ <<Random0/binary,Down/binary>>;
+ true ->
+ Random
+ end;
+override_server_random(<<Random0:24/binary,_:8/binary>> = Random, {M,N}, {Major,Minor})
+ when Major =:= 3 andalso Minor =:= 3 -> %% TLS 1.2
+ if M =:= 3 andalso N < 3 -> %% Negotating TLS 1.1 or prior
+ Down = ?RANDOM_OVERRIDE_TLS11,
+ <<Random0/binary,Down/binary>>;
+ true ->
+ Random
+ end;
+override_server_random(Random, _, _) ->
+ Random.
+
new_server_hello(#server_hello{cipher_suite = CipherSuite,
compression_method = Compression,
session_id = SessionId},
- #state{session = Session0,
- negotiated_version = Version} = State0, Connection) ->
+ #state{session = Session0,
+ connection_env = #connection_env{negotiated_version = Version}} = State0, Connection) ->
try server_certify_and_key_exchange(State0, Connection) of
#state{} = State1 ->
- {State2, Actions} = server_hello_done(State1, Connection),
+ {State, Actions} = server_hello_done(State1, Connection),
Session =
Session0#session{session_id = SessionId,
cipher_suite = CipherSuite,
compression_method = Compression},
- {Record, State} = Connection:next_record(State2#state{session = Session}),
- Connection:next_event(certify, Record, State, Actions)
+ Connection:next_event(certify, no_record, State#state{session = Session}, Actions)
catch
#alert{} = Alert ->
handle_own_alert(Alert, Version, hello, State0)
@@ -1288,66 +1695,58 @@ new_server_hello(#server_hello{cipher_suite = CipherSuite,
resumed_server_hello(#state{session = Session,
connection_states = ConnectionStates0,
- negotiated_version = Version} = State0, Connection) ->
+ connection_env = #connection_env{negotiated_version = Version}} = State0, Connection) ->
case ssl_handshake:master_secret(ssl:tls_version(Version), Session,
ConnectionStates0, server) of
{_, ConnectionStates1} ->
State1 = State0#state{connection_states = ConnectionStates1,
session = Session},
- {State2, Actions} =
+ {State, Actions} =
finalize_handshake(State1, abbreviated, Connection),
- {Record, State} = Connection:next_record(State2),
- Connection:next_event(abbreviated, Record, State, Actions);
+ Connection:next_event(abbreviated, no_record, State, Actions);
#alert{} = Alert ->
handle_own_alert(Alert, Version, hello, State0)
end.
server_hello(ServerHello, State0, Connection) ->
CipherSuite = ServerHello#server_hello.cipher_suite,
- #{key_exchange := KeyAlgorithm} = ssl_cipher:suite_definition(CipherSuite),
- State = Connection:queue_handshake(ServerHello, State0),
- State#state{key_algorithm = KeyAlgorithm}.
+ #{key_exchange := KeyAlgorithm} = ssl_cipher_format:suite_bin_to_map(CipherSuite),
+ #state{handshake_env = HsEnv} = State = Connection:queue_handshake(ServerHello, State0),
+ State#state{handshake_env = HsEnv#handshake_env{kex_algorithm = KeyAlgorithm}}.
server_hello_done(State, Connection) ->
HelloDone = ssl_handshake:server_hello_done(),
Connection:send_handshake(HelloDone, State).
handle_peer_cert(Role, PeerCert, PublicKeyInfo,
- #state{session = #session{cipher_suite = CipherSuite} = Session} = State0,
+ #state{handshake_env = HsEnv,
+ session = #session{cipher_suite = CipherSuite} = Session} = State0,
Connection) ->
- State1 = State0#state{session =
- Session#session{peer_certificate = PeerCert},
- public_key_info = PublicKeyInfo},
- #{key_exchange := KeyAlgorithm} = ssl_cipher:suite_definition(CipherSuite),
- State2 = handle_peer_cert_key(Role, PeerCert, PublicKeyInfo, KeyAlgorithm, State1),
-
- {Record, State} = Connection:next_record(State2),
- Connection:next_event(certify, Record, State).
+ State1 = State0#state{handshake_env = HsEnv#handshake_env{public_key_info = PublicKeyInfo},
+ session =
+ Session#session{peer_certificate = PeerCert}},
+ #{key_exchange := KeyAlgorithm} = ssl_cipher_format:suite_bin_to_map(CipherSuite),
+ State = handle_peer_cert_key(Role, PeerCert, PublicKeyInfo, KeyAlgorithm, State1),
+ Connection:next_event(certify, no_record, State).
handle_peer_cert_key(client, _,
{?'id-ecPublicKey', #'ECPoint'{point = _ECPoint} = PublicKey,
PublicKeyParams},
- KeyAlg, State) when KeyAlg == ecdh_rsa;
- KeyAlg == ecdh_ecdsa ->
+ KeyAlg, #state{handshake_env = HsEnv,
+ session = Session} = State) when KeyAlg == ecdh_rsa;
+ KeyAlg == ecdh_ecdsa ->
ECDHKey = public_key:generate_key(PublicKeyParams),
PremasterSecret = ssl_handshake:premaster_secret(PublicKey, ECDHKey),
- master_secret(PremasterSecret, State#state{diffie_hellman_keys = ECDHKey});
-%% We do currently not support cipher suites that use fixed DH.
-%% If we want to implement that the following clause can be used
-%% to extract DH parameters form cert.
-%% handle_peer_cert_key(client, _PeerCert, {?dhpublicnumber, PublicKey, PublicKeyParams},
-%% {_,SignAlg},
-%% #state{diffie_hellman_keys = {_, MyPrivatKey}} = State) when
-%% SignAlg == dh_rsa;
-%% SignAlg == dh_dss ->
-%% dh_master_secret(PublicKeyParams, PublicKey, MyPrivatKey, State);
+ master_secret(PremasterSecret, State#state{handshake_env = HsEnv#handshake_env{kex_keys = ECDHKey},
+ session = Session#session{ecc = PublicKeyParams}});
handle_peer_cert_key(_, _, _, _, State) ->
State.
-certify_client(#state{client_certificate_requested = true, role = client,
- cert_db = CertDbHandle,
- cert_db_ref = CertDbRef,
+certify_client(#state{static_env = #static_env{role = client,
+ cert_db = CertDbHandle,
+ cert_db_ref = CertDbRef},
+ client_certificate_requested = true,
session = #session{own_certificate = OwnCert}}
= State, Connection) ->
Certificate = ssl_handshake:certificate(OwnCert, CertDbHandle, CertDbRef, client),
@@ -1355,16 +1754,17 @@ certify_client(#state{client_certificate_requested = true, role = client,
certify_client(#state{client_certificate_requested = false} = State, _) ->
State.
-verify_client_cert(#state{client_certificate_requested = true, role = client,
- negotiated_version = Version,
- private_key = PrivateKey,
+verify_client_cert(#state{static_env = #static_env{role = client},
+ handshake_env = #handshake_env{tls_handshake_history = Hist,
+ cert_hashsign_algorithm = HashSign},
+ connection_env = #connection_env{negotiated_version = Version,
+ private_key = PrivateKey},
+ client_certificate_requested = true,
session = #session{master_secret = MasterSecret,
- own_certificate = OwnCert},
- cert_hashsign_algorithm = HashSign,
- tls_handshake_history = Handshake0} = State, Connection) ->
+ own_certificate = OwnCert}} = State, Connection) ->
case ssl_handshake:client_certificate_verify(OwnCert, MasterSecret,
- ssl:tls_version(Version), HashSign, PrivateKey, Handshake0) of
+ ssl:tls_version(Version), HashSign, PrivateKey, Hist) of
#certificate_verify{} = Verified ->
Connection:queue_handshake(Verified, State);
ignore ->
@@ -1375,16 +1775,15 @@ verify_client_cert(#state{client_certificate_requested = true, role = client,
verify_client_cert(#state{client_certificate_requested = false} = State, _) ->
State.
-client_certify_and_key_exchange(#state{negotiated_version = Version} =
+client_certify_and_key_exchange(#state{connection_env = #connection_env{negotiated_version = Version}} =
State0, Connection) ->
try do_client_certify_and_key_exchange(State0, Connection) of
State1 = #state{} ->
{State2, Actions} = finalize_handshake(State1, certify, Connection),
- State3 = State2#state{
- %% Reinitialize
- client_certificate_requested = false},
- {Record, State} = Connection:next_record(State3),
- Connection:next_event(cipher, Record, State, Actions)
+ State = State2#state{
+ %% Reinitialize
+ client_certificate_requested = false},
+ Connection:next_event(cipher, no_record, State, Actions)
catch
throw:#alert{} = Alert ->
handle_own_alert(Alert, Version, certify, State0)
@@ -1401,7 +1800,9 @@ server_certify_and_key_exchange(State0, Connection) ->
request_client_cert(State2, Connection).
certify_client_key_exchange(#encrypted_premaster_secret{premaster_secret= EncPMS},
- #state{private_key = Key, client_hello_version = {Major, Minor} = Version} = State, Connection) ->
+ #state{connection_env = #connection_env{private_key = Key},
+ handshake_env = #handshake_env{client_hello_version = {Major, Minor} = Version}}
+ = State, Connection) ->
FakeSecret = make_premaster_secret(Version, rsa),
%% Countermeasure for Bleichenbacher attack always provide some kind of premaster secret
%% and fail handshake later.RFC 5246 section 7.4.7.1.
@@ -1422,14 +1823,15 @@ certify_client_key_exchange(#encrypted_premaster_secret{premaster_secret= EncPMS
end,
calculate_master_secret(PremasterSecret, State, Connection, certify, cipher);
certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPublicDhKey},
- #state{diffie_hellman_params = #'DHParameter'{} = Params,
- diffie_hellman_keys = {_, ServerDhPrivateKey}} = State,
+ #state{handshake_env = #handshake_env{diffie_hellman_params = #'DHParameter'{} = Params,
+ kex_keys = {_, ServerDhPrivateKey}}
+ } = State,
Connection) ->
PremasterSecret = ssl_handshake:premaster_secret(ClientPublicDhKey, ServerDhPrivateKey, Params),
calculate_master_secret(PremasterSecret, State, Connection, certify, cipher);
certify_client_key_exchange(#client_ec_diffie_hellman_public{dh_public = ClientPublicEcDhPoint},
- #state{diffie_hellman_keys = ECDHKey} = State, Connection) ->
+ #state{handshake_env = #handshake_env{kex_keys = ECDHKey}} = State, Connection) ->
PremasterSecret = ssl_handshake:premaster_secret(#'ECPoint'{point = ClientPublicEcDhPoint}, ECDHKey),
calculate_master_secret(PremasterSecret, State, Connection, certify, cipher);
certify_client_key_exchange(#client_psk_identity{} = ClientKey,
@@ -1439,36 +1841,46 @@ certify_client_key_exchange(#client_psk_identity{} = ClientKey,
PremasterSecret = ssl_handshake:premaster_secret(ClientKey, PSKLookup),
calculate_master_secret(PremasterSecret, State0, Connection, certify, cipher);
certify_client_key_exchange(#client_dhe_psk_identity{} = ClientKey,
- #state{diffie_hellman_params = #'DHParameter'{} = Params,
- diffie_hellman_keys = {_, ServerDhPrivateKey},
+ #state{handshake_env = #handshake_env{diffie_hellman_params = #'DHParameter'{} = Params,
+ kex_keys = {_, ServerDhPrivateKey}},
ssl_options =
#ssl_options{user_lookup_fun = PSKLookup}} = State0,
Connection) ->
PremasterSecret =
ssl_handshake:premaster_secret(ClientKey, ServerDhPrivateKey, Params, PSKLookup),
calculate_master_secret(PremasterSecret, State0, Connection, certify, cipher);
+certify_client_key_exchange(#client_ecdhe_psk_identity{} = ClientKey,
+ #state{handshake_env = #handshake_env{kex_keys = ServerEcDhPrivateKey},
+ ssl_options =
+ #ssl_options{user_lookup_fun = PSKLookup}} = State,
+ Connection) ->
+ PremasterSecret =
+ ssl_handshake:premaster_secret(ClientKey, ServerEcDhPrivateKey, PSKLookup),
+ calculate_master_secret(PremasterSecret, State, Connection, certify, cipher);
certify_client_key_exchange(#client_rsa_psk_identity{} = ClientKey,
- #state{private_key = Key,
+ #state{connection_env = #connection_env{private_key = Key},
ssl_options =
#ssl_options{user_lookup_fun = PSKLookup}} = State0,
Connection) ->
PremasterSecret = ssl_handshake:premaster_secret(ClientKey, Key, PSKLookup),
calculate_master_secret(PremasterSecret, State0, Connection, certify, cipher);
certify_client_key_exchange(#client_srp_public{} = ClientKey,
- #state{srp_params = Params,
- srp_keys = Key
+ #state{handshake_env = #handshake_env{srp_params = Params,
+ kex_keys = Key}
} = State0, Connection) ->
PremasterSecret = ssl_handshake:premaster_secret(ClientKey, Key, Params),
calculate_master_secret(PremasterSecret, State0, Connection, certify, cipher).
-certify_server(#state{key_algorithm = Algo} = State, _) when Algo == dh_anon;
- Algo == ecdh_anon;
- Algo == psk;
- Algo == dhe_psk;
- Algo == srp_anon ->
+certify_server(#state{handshake_env = #handshake_env{kex_algorithm = KexAlg}} =
+ State, _) when KexAlg == dh_anon;
+ KexAlg == ecdh_anon;
+ KexAlg == psk;
+ KexAlg == dhe_psk;
+ KexAlg == ecdhe_psk;
+ KexAlg == srp_anon ->
State;
-certify_server(#state{cert_db = CertDbHandle,
- cert_db_ref = CertDbRef,
+certify_server(#state{static_env = #static_env{cert_db = CertDbHandle,
+ cert_db_ref = CertDbRef},
session = #session{own_certificate = OwnCert}} = State, Connection) ->
case ssl_handshake:certificate(OwnCert, CertDbHandle, CertDbRef, server) of
Cert = #certificate{} ->
@@ -1477,18 +1889,19 @@ certify_server(#state{cert_db = CertDbHandle,
throw(Alert)
end.
-key_exchange(#state{role = server, key_algorithm = rsa} = State,_) ->
+key_exchange(#state{static_env = #static_env{role = server},
+ handshake_env = #handshake_env{kex_algorithm = rsa}} = State,_) ->
State;
-key_exchange(#state{role = server, key_algorithm = Algo,
- hashsign_algorithm = HashSignAlgo,
- diffie_hellman_params = #'DHParameter'{} = Params,
- private_key = PrivateKey,
- connection_states = ConnectionStates0,
- negotiated_version = Version
- } = State0, Connection)
- when Algo == dhe_dss;
- Algo == dhe_rsa;
- Algo == dh_anon ->
+key_exchange(#state{static_env = #static_env{role = server},
+ handshake_env = #handshake_env{kex_algorithm = KexAlg,
+ diffie_hellman_params = #'DHParameter'{} = Params,
+ hashsign_algorithm = HashSignAlgo},
+ connection_env = #connection_env{negotiated_version = Version,
+ private_key = PrivateKey},
+ connection_states = ConnectionStates0} = State0, Connection)
+ when KexAlg == dhe_dss;
+ KexAlg == dhe_rsa;
+ KexAlg == dh_anon ->
DHKeys = public_key:generate_key(Params),
#{security_parameters := SecParams} =
ssl_record:pending_connection_state(ConnectionStates0, read),
@@ -1498,20 +1911,26 @@ key_exchange(#state{role = server, key_algorithm = Algo,
HashSignAlgo, ClientRandom,
ServerRandom,
PrivateKey}),
- State = Connection:queue_handshake(Msg, State0),
- State#state{diffie_hellman_keys = DHKeys};
-key_exchange(#state{role = server, private_key = Key, key_algorithm = Algo} = State, _)
- when Algo == ecdh_ecdsa; Algo == ecdh_rsa ->
- State#state{diffie_hellman_keys = Key};
-key_exchange(#state{role = server, key_algorithm = Algo,
- hashsign_algorithm = HashSignAlgo,
- private_key = PrivateKey,
+ #state{handshake_env = HsEnv} = State = Connection:queue_handshake(Msg, State0),
+ State#state{handshake_env = HsEnv#handshake_env{kex_keys = DHKeys}};
+key_exchange(#state{static_env = #static_env{role = server},
+ handshake_env = #handshake_env{kex_algorithm = KexAlg} = HsEnv,
+ connection_env = #connection_env{private_key = #'ECPrivateKey'{parameters = ECCurve} = Key},
+ session = Session} = State, _)
+ when KexAlg == ecdh_ecdsa;
+ KexAlg == ecdh_rsa ->
+ State#state{handshake_env = HsEnv#handshake_env{kex_keys = Key},
+ session = Session#session{ecc = ECCurve}};
+key_exchange(#state{static_env = #static_env{role = server},
+ handshake_env = #handshake_env{kex_algorithm = KexAlg,
+ hashsign_algorithm = HashSignAlgo},
+ connection_env = #connection_env{negotiated_version = Version,
+ private_key = PrivateKey},
session = #session{ecc = ECCCurve},
- connection_states = ConnectionStates0,
- negotiated_version = Version
- } = State0, Connection)
- when Algo == ecdhe_ecdsa; Algo == ecdhe_rsa;
- Algo == ecdh_anon ->
+ connection_states = ConnectionStates0} = State0, Connection)
+ when KexAlg == ecdhe_ecdsa;
+ KexAlg == ecdhe_rsa;
+ KexAlg == ecdh_anon ->
ECDHKeys = public_key:generate_key(ECCCurve),
#{security_parameters := SecParams} =
@@ -1523,18 +1942,19 @@ key_exchange(#state{role = server, key_algorithm = Algo,
HashSignAlgo, ClientRandom,
ServerRandom,
PrivateKey}),
- State = Connection:queue_handshake(Msg, State0),
- State#state{diffie_hellman_keys = ECDHKeys};
-key_exchange(#state{role = server, key_algorithm = psk,
+ #state{handshake_env = HsEnv} = State = Connection:queue_handshake(Msg, State0),
+ State#state{handshake_env = HsEnv#handshake_env{kex_keys = ECDHKeys}};
+key_exchange(#state{static_env = #static_env{role = server},
+ handshake_env = #handshake_env{kex_algorithm = psk},
ssl_options = #ssl_options{psk_identity = undefined}} = State, _) ->
State;
-key_exchange(#state{role = server, key_algorithm = psk,
+key_exchange(#state{static_env = #static_env{role = server},
ssl_options = #ssl_options{psk_identity = PskIdentityHint},
- hashsign_algorithm = HashSignAlgo,
- private_key = PrivateKey,
- connection_states = ConnectionStates0,
- negotiated_version = Version
- } = State0, Connection) ->
+ handshake_env = #handshake_env{kex_algorithm = psk,
+ hashsign_algorithm = HashSignAlgo},
+ connection_env = #connection_env{negotiated_version = Version,
+ private_key = PrivateKey},
+ connection_states = ConnectionStates0} = State0, Connection) ->
#{security_parameters := SecParams} =
ssl_record:pending_connection_state(ConnectionStates0, read),
#security_parameters{client_random = ClientRandom,
@@ -1543,15 +1963,16 @@ key_exchange(#state{role = server, key_algorithm = psk,
{psk, PskIdentityHint,
HashSignAlgo, ClientRandom,
ServerRandom,
- PrivateKey}),
+ PrivateKey}),
Connection:queue_handshake(Msg, State0);
-key_exchange(#state{role = server, key_algorithm = dhe_psk,
+key_exchange(#state{static_env = #static_env{role = server},
ssl_options = #ssl_options{psk_identity = PskIdentityHint},
- hashsign_algorithm = HashSignAlgo,
- diffie_hellman_params = #'DHParameter'{} = Params,
- private_key = PrivateKey,
- connection_states = ConnectionStates0,
- negotiated_version = Version
+ handshake_env = #handshake_env{kex_algorithm = dhe_psk,
+ diffie_hellman_params = #'DHParameter'{} = Params,
+ hashsign_algorithm = HashSignAlgo},
+ connection_env = #connection_env{negotiated_version = Version,
+ private_key = PrivateKey},
+ connection_states = ConnectionStates0
} = State0, Connection) ->
DHKeys = public_key:generate_key(Params),
#{security_parameters := SecParams} =
@@ -1564,17 +1985,41 @@ key_exchange(#state{role = server, key_algorithm = dhe_psk,
HashSignAlgo, ClientRandom,
ServerRandom,
PrivateKey}),
- State = Connection:queue_handshake(Msg, State0),
- State#state{diffie_hellman_keys = DHKeys};
-key_exchange(#state{role = server, key_algorithm = rsa_psk,
+ #state{handshake_env = HsEnv} = State = Connection:queue_handshake(Msg, State0),
+ State#state{handshake_env = HsEnv#handshake_env{kex_keys = DHKeys}};
+key_exchange(#state{static_env = #static_env{role = server},
+ ssl_options = #ssl_options{psk_identity = PskIdentityHint},
+ handshake_env = #handshake_env{kex_algorithm = ecdhe_psk,
+ hashsign_algorithm = HashSignAlgo},
+ connection_env = #connection_env{negotiated_version = Version,
+ private_key = PrivateKey},
+ session = #session{ecc = ECCCurve},
+ connection_states = ConnectionStates0
+ } = State0, Connection) ->
+ ECDHKeys = public_key:generate_key(ECCCurve),
+ #{security_parameters := SecParams} =
+ ssl_record:pending_connection_state(ConnectionStates0, read),
+ #security_parameters{client_random = ClientRandom,
+ server_random = ServerRandom} = SecParams,
+ Msg = ssl_handshake:key_exchange(server, ssl:tls_version(Version),
+ {ecdhe_psk,
+ PskIdentityHint, ECDHKeys,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
+ PrivateKey}),
+ #state{handshake_env = HsEnv} = State = Connection:queue_handshake(Msg, State0),
+ State#state{handshake_env = HsEnv#handshake_env{kex_keys = ECDHKeys}};
+key_exchange(#state{static_env = #static_env{role = server},
+ handshake_env = #handshake_env{kex_algorithm = rsa_psk},
ssl_options = #ssl_options{psk_identity = undefined}} = State, _) ->
State;
-key_exchange(#state{role = server, key_algorithm = rsa_psk,
+key_exchange(#state{static_env = #static_env{role = server},
ssl_options = #ssl_options{psk_identity = PskIdentityHint},
- hashsign_algorithm = HashSignAlgo,
- private_key = PrivateKey,
- connection_states = ConnectionStates0,
- negotiated_version = Version
+ handshake_env = #handshake_env{kex_algorithm = rsa_psk,
+ hashsign_algorithm = HashSignAlgo},
+ connection_env = #connection_env{negotiated_version = Version,
+ private_key = PrivateKey},
+ connection_states = ConnectionStates0
} = State0, Connection) ->
#{security_parameters := SecParams} =
ssl_record:pending_connection_state(ConnectionStates0, read),
@@ -1586,17 +2031,18 @@ key_exchange(#state{role = server, key_algorithm = rsa_psk,
ServerRandom,
PrivateKey}),
Connection:queue_handshake(Msg, State0);
-key_exchange(#state{role = server, key_algorithm = Algo,
+key_exchange(#state{static_env = #static_env{role = server},
ssl_options = #ssl_options{user_lookup_fun = LookupFun},
- hashsign_algorithm = HashSignAlgo,
+ handshake_env = #handshake_env{kex_algorithm = KexAlg,
+ hashsign_algorithm = HashSignAlgo},
+ connection_env = #connection_env{negotiated_version = Version,
+ private_key = PrivateKey},
session = #session{srp_username = Username},
- private_key = PrivateKey,
- connection_states = ConnectionStates0,
- negotiated_version = Version
+ connection_states = ConnectionStates0
} = State0, Connection)
- when Algo == srp_dss;
- Algo == srp_rsa;
- Algo == srp_anon ->
+ when KexAlg == srp_dss;
+ KexAlg == srp_rsa;
+ KexAlg == srp_anon ->
SrpParams = handle_srp_identity(Username, LookupFun),
Keys = case generate_srp_server_keys(SrpParams, 0) of
Alert = #alert{} ->
@@ -1613,70 +2059,86 @@ key_exchange(#state{role = server, key_algorithm = Algo,
HashSignAlgo, ClientRandom,
ServerRandom,
PrivateKey}),
- State = Connection:queue_handshake(Msg, State0),
- State#state{srp_params = SrpParams,
- srp_keys = Keys};
-key_exchange(#state{role = client,
- key_algorithm = rsa,
- public_key_info = PublicKeyInfo,
- negotiated_version = Version,
- premaster_secret = PremasterSecret} = State0, Connection) ->
+ #state{handshake_env = HsEnv} = State = Connection:queue_handshake(Msg, State0),
+ State#state{handshake_env = HsEnv#handshake_env{srp_params = SrpParams,
+ kex_keys = Keys}};
+key_exchange(#state{static_env = #static_env{role = client},
+ handshake_env = #handshake_env{kex_algorithm = rsa,
+ public_key_info = PublicKeyInfo,
+ premaster_secret = PremasterSecret},
+ connection_env = #connection_env{negotiated_version = Version}
+ } = State0, Connection) ->
Msg = rsa_key_exchange(ssl:tls_version(Version), PremasterSecret, PublicKeyInfo),
Connection:queue_handshake(Msg, State0);
-key_exchange(#state{role = client,
- key_algorithm = Algorithm,
- negotiated_version = Version,
- diffie_hellman_keys = {DhPubKey, _}
- } = State0, Connection)
- when Algorithm == dhe_dss;
- Algorithm == dhe_rsa;
- Algorithm == dh_anon ->
+key_exchange(#state{static_env = #static_env{role = client},
+ handshake_env = #handshake_env{kex_algorithm = KexAlg,
+ kex_keys = {DhPubKey, _}},
+ connection_env = #connection_env{negotiated_version = Version}
+ } = State0, Connection)
+ when KexAlg == dhe_dss;
+ KexAlg == dhe_rsa;
+ KexAlg == dh_anon ->
Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version), {dh, DhPubKey}),
Connection:queue_handshake(Msg, State0);
-key_exchange(#state{role = client,
- key_algorithm = Algorithm,
- negotiated_version = Version,
- diffie_hellman_keys = Keys} = State0, Connection)
- when Algorithm == ecdhe_ecdsa; Algorithm == ecdhe_rsa;
- Algorithm == ecdh_ecdsa; Algorithm == ecdh_rsa;
- Algorithm == ecdh_anon ->
- Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version), {ecdh, Keys}),
- Connection:queue_handshake(Msg, State0);
-key_exchange(#state{role = client,
- ssl_options = SslOpts,
- key_algorithm = psk,
- negotiated_version = Version} = State0, Connection) ->
+key_exchange(#state{static_env = #static_env{role = client},
+ handshake_env = #handshake_env{kex_algorithm = KexAlg,
+ kex_keys = #'ECPrivateKey'{parameters = ECCurve} = Key},
+ connection_env = #connection_env{negotiated_version = Version},
+ session = Session
+ } = State0, Connection)
+ when KexAlg == ecdhe_ecdsa;
+ KexAlg == ecdhe_rsa;
+ KexAlg == ecdh_ecdsa;
+ KexAlg == ecdh_rsa;
+ KexAlg == ecdh_anon ->
+ Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version), {ecdh, Key}),
+ Connection:queue_handshake(Msg, State0#state{session = Session#session{ecc = ECCurve}});
+key_exchange(#state{static_env = #static_env{role = client},
+ handshake_env = #handshake_env{kex_algorithm = psk},
+ connection_env = #connection_env{negotiated_version = Version},
+ ssl_options = SslOpts} = State0, Connection) ->
Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version),
{psk, SslOpts#ssl_options.psk_identity}),
Connection:queue_handshake(Msg, State0);
-key_exchange(#state{role = client,
- ssl_options = SslOpts,
- key_algorithm = dhe_psk,
- negotiated_version = Version,
- diffie_hellman_keys = {DhPubKey, _}} = State0, Connection) ->
+key_exchange(#state{static_env = #static_env{role = client},
+ handshake_env = #handshake_env{kex_algorithm = dhe_psk,
+ kex_keys = {DhPubKey, _}},
+ connection_env = #connection_env{negotiated_version = Version},
+ ssl_options = SslOpts} = State0, Connection) ->
Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version),
{dhe_psk,
SslOpts#ssl_options.psk_identity, DhPubKey}),
Connection:queue_handshake(Msg, State0);
-key_exchange(#state{role = client,
- ssl_options = SslOpts,
- key_algorithm = rsa_psk,
- public_key_info = PublicKeyInfo,
- negotiated_version = Version,
- premaster_secret = PremasterSecret}
+
+key_exchange(#state{static_env = #static_env{role = client},
+ handshake_env = #handshake_env{kex_algorithm = ecdhe_psk,
+ kex_keys = ECDHKeys},
+ connection_env = #connection_env{negotiated_version = Version},
+ ssl_options = SslOpts} = State0, Connection) ->
+ Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version),
+ {ecdhe_psk,
+ SslOpts#ssl_options.psk_identity, ECDHKeys}),
+ Connection:queue_handshake(Msg, State0);
+
+key_exchange(#state{static_env = #static_env{role = client},
+ handshake_env = #handshake_env{kex_algorithm = rsa_psk,
+ public_key_info = PublicKeyInfo,
+ premaster_secret = PremasterSecret},
+ connection_env = #connection_env{negotiated_version = Version},
+ ssl_options = SslOpts}
= State0, Connection) ->
Msg = rsa_psk_key_exchange(ssl:tls_version(Version), SslOpts#ssl_options.psk_identity,
PremasterSecret, PublicKeyInfo),
Connection:queue_handshake(Msg, State0);
-key_exchange(#state{role = client,
- key_algorithm = Algorithm,
- negotiated_version = Version,
- srp_keys = {ClientPubKey, _}}
+key_exchange(#state{static_env = #static_env{role = client},
+ handshake_env = #handshake_env{kex_algorithm = KexAlg,
+ kex_keys = {ClientPubKey, _}},
+ connection_env = #connection_env{negotiated_version = Version}}
= State0, Connection)
- when Algorithm == srp_dss;
- Algorithm == srp_rsa;
- Algorithm == srp_anon ->
+ when KexAlg == srp_dss;
+ KexAlg == srp_rsa;
+ KexAlg == srp_anon ->
Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version), {srp, ClientPubKey}),
Connection:queue_handshake(Msg, State0).
@@ -1713,12 +2175,24 @@ rsa_psk_key_exchange(Version, PskIdentity, PremasterSecret,
rsa_psk_key_exchange(_, _, _, _) ->
throw (?ALERT_REC(?FATAL,?HANDSHAKE_FAILURE, pub_key_is_not_rsa)).
-request_client_cert(#state{ssl_options = #ssl_options{verify = verify_peer,
- signature_algs = SupportedHashSigns},
- connection_states = ConnectionStates0,
- cert_db = CertDbHandle,
- cert_db_ref = CertDbRef,
- negotiated_version = Version} = State0, Connection) ->
+request_client_cert(#state{handshake_env = #handshake_env{kex_algorithm = Alg}} = State, _)
+ when Alg == dh_anon;
+ Alg == ecdh_anon;
+ Alg == psk;
+ Alg == dhe_psk;
+ Alg == ecdhe_psk;
+ Alg == rsa_psk;
+ Alg == srp_dss;
+ Alg == srp_rsa;
+ Alg == srp_anon ->
+ State;
+
+request_client_cert(#state{static_env = #static_env{cert_db = CertDbHandle,
+ cert_db_ref = CertDbRef},
+ connection_env = #connection_env{negotiated_version = Version},
+ ssl_options = #ssl_options{verify = verify_peer,
+ signature_algs = SupportedHashSigns},
+ connection_states = ConnectionStates0} = State0, Connection) ->
#{security_parameters :=
#security_parameters{cipher_suite = CipherSuite}} =
ssl_record:pending_connection_state(ConnectionStates0, read),
@@ -1735,7 +2209,7 @@ request_client_cert(#state{ssl_options = #ssl_options{verify = verify_none}} =
State.
calculate_master_secret(PremasterSecret,
- #state{negotiated_version = Version,
+ #state{connection_env = #connection_env{negotiated_version = Version},
connection_states = ConnectionStates0,
session = Session0} = State0, Connection,
_Current, Next) ->
@@ -1743,10 +2217,9 @@ calculate_master_secret(PremasterSecret,
ConnectionStates0, server) of
{MasterSecret, ConnectionStates} ->
Session = Session0#session{master_secret = MasterSecret},
- State1 = State0#state{connection_states = ConnectionStates,
+ State = State0#state{connection_states = ConnectionStates,
session = Session},
- {Record, State} = Connection:next_record(State1),
- Connection:next_event(Next, Record, State);
+ Connection:next_event(Next, no_record, State);
#alert{} = Alert ->
handle_own_alert(Alert, Version, certify, State0)
end.
@@ -1763,27 +2236,29 @@ finalize_handshake(State0, StateName, Connection) ->
State = next_protocol(State2, Connection),
finished(State, StateName, Connection).
-next_protocol(#state{role = server} = State, _) ->
+next_protocol(#state{static_env = #static_env{role = server}} = State, _) ->
State;
-next_protocol(#state{negotiated_protocol = undefined} = State, _) ->
+next_protocol(#state{handshake_env = #handshake_env{negotiated_protocol = undefined}} = State, _) ->
State;
-next_protocol(#state{expecting_next_protocol_negotiation = false} = State, _) ->
+next_protocol(#state{handshake_env = #handshake_env{expecting_next_protocol_negotiation = false}} = State, _) ->
State;
-next_protocol(#state{negotiated_protocol = NextProtocol} = State0, Connection) ->
+next_protocol(#state{handshake_env = #handshake_env{negotiated_protocol = NextProtocol}} = State0, Connection) ->
NextProtocolMessage = ssl_handshake:next_protocol(NextProtocol),
Connection:queue_handshake(NextProtocolMessage, State0).
cipher_protocol(State, Connection) ->
Connection:queue_change_cipher(#change_cipher_spec{}, State).
-finished(#state{role = Role, negotiated_version = Version,
+finished(#state{static_env = #static_env{role = Role},
+ handshake_env = #handshake_env{tls_handshake_history = Hist},
+ connection_env = #connection_env{negotiated_version = Version},
session = Session,
- connection_states = ConnectionStates0,
- tls_handshake_history = Handshake0} = State0, StateName, Connection) ->
+ connection_states = ConnectionStates0} = State0,
+ StateName, Connection) ->
MasterSecret = Session#session.master_secret,
Finished = ssl_handshake:finished(ssl:tls_version(Version), Role,
get_current_prf(ConnectionStates0, write),
- MasterSecret, Handshake0),
+ MasterSecret, Hist),
ConnectionStates = save_verify_data(Role, Finished, ConnectionStates0, StateName),
Connection:send_handshake(Finished, State0#state{connection_states =
ConnectionStates}).
@@ -1799,53 +2274,71 @@ save_verify_data(server, #finished{verify_data = Data}, ConnectionStates, abbrev
calculate_secret(#server_dh_params{dh_p = Prime, dh_g = Base,
dh_y = ServerPublicDhKey} = Params,
- State, Connection) ->
+ #state{handshake_env = HsEnv} = State, Connection) ->
Keys = {_, PrivateDhKey} = crypto:generate_key(dh, [Prime, Base]),
PremasterSecret =
ssl_handshake:premaster_secret(ServerPublicDhKey, PrivateDhKey, Params),
calculate_master_secret(PremasterSecret,
- State#state{diffie_hellman_keys = Keys},
+ State#state{handshake_env = HsEnv#handshake_env{kex_keys = Keys}},
Connection, certify, certify);
calculate_secret(#server_ecdh_params{curve = ECCurve, public = ECServerPubKey},
- State=#state{session=Session}, Connection) ->
+ #state{handshake_env = HsEnv,
+ session = Session} = State, Connection) ->
ECDHKeys = public_key:generate_key(ECCurve),
PremasterSecret =
ssl_handshake:premaster_secret(#'ECPoint'{point = ECServerPubKey}, ECDHKeys),
calculate_master_secret(PremasterSecret,
- State#state{diffie_hellman_keys = ECDHKeys,
+ State#state{handshake_env = HsEnv#handshake_env{kex_keys = ECDHKeys},
session = Session#session{ecc = ECCurve}},
Connection, certify, certify);
calculate_secret(#server_psk_params{
hint = IdentityHint},
- State0, Connection) ->
+ #state{handshake_env = HsEnv} = State, Connection) ->
%% store for later use
- {Record, State} = Connection:next_record(State0#state{psk_identity = IdentityHint}),
- Connection:next_event(certify, Record, State);
+ Connection:next_event(certify, no_record,
+ State#state{handshake_env =
+ HsEnv#handshake_env{server_psk_identity = IdentityHint}});
calculate_secret(#server_dhe_psk_params{
dh_params = #server_dh_params{dh_p = Prime, dh_g = Base}} = ServerKey,
- #state{ssl_options = #ssl_options{user_lookup_fun = PSKLookup}} =
+ #state{handshake_env = HsEnv,
+ ssl_options = #ssl_options{user_lookup_fun = PSKLookup}} =
State, Connection) ->
Keys = {_, PrivateDhKey} =
crypto:generate_key(dh, [Prime, Base]),
PremasterSecret = ssl_handshake:premaster_secret(ServerKey, PrivateDhKey, PSKLookup),
- calculate_master_secret(PremasterSecret, State#state{diffie_hellman_keys = Keys},
+ calculate_master_secret(PremasterSecret, State#state{handshake_env = HsEnv#handshake_env{kex_keys = Keys}},
+ Connection, certify, certify);
+
+calculate_secret(#server_ecdhe_psk_params{
+ dh_params = #server_ecdh_params{curve = ECCurve}} = ServerKey,
+ #state{ssl_options = #ssl_options{user_lookup_fun = PSKLookup}} =
+ #state{handshake_env = HsEnv,
+ session = Session} = State, Connection) ->
+ ECDHKeys = public_key:generate_key(ECCurve),
+
+ PremasterSecret = ssl_handshake:premaster_secret(ServerKey, ECDHKeys, PSKLookup),
+ calculate_master_secret(PremasterSecret,
+ State#state{handshake_env = HsEnv#handshake_env{kex_keys = ECDHKeys},
+ session = Session#session{ecc = ECCurve}},
Connection, certify, certify);
calculate_secret(#server_srp_params{srp_n = Prime, srp_g = Generator} = ServerKey,
- #state{ssl_options = #ssl_options{srp_identity = SRPId}} = State,
+ #state{handshake_env = HsEnv,
+ ssl_options = #ssl_options{srp_identity = SRPId}} = State,
Connection) ->
Keys = generate_srp_client_keys(Generator, Prime, 0),
PremasterSecret = ssl_handshake:premaster_secret(ServerKey, Keys, SRPId),
- calculate_master_secret(PremasterSecret, State#state{srp_keys = Keys}, Connection,
+ calculate_master_secret(PremasterSecret, State#state{handshake_env = HsEnv#handshake_env{kex_keys = Keys}}, Connection,
certify, certify).
master_secret(#alert{} = Alert, _) ->
Alert;
-master_secret(PremasterSecret, #state{session = Session,
- negotiated_version = Version, role = Role,
+master_secret(PremasterSecret, #state{static_env = #static_env{role = Role},
+ connection_env = #connection_env{negotiated_version = Version},
+ session = Session,
connection_states = ConnectionStates0} = State) ->
case ssl_handshake:master_secret(ssl:tls_version(Version), PremasterSecret,
ConnectionStates0, Role) of
@@ -1863,22 +2356,24 @@ generate_srp_server_keys(_SrpParams, 10) ->
generate_srp_server_keys(SrpParams =
#srp_user{generator = Generator, prime = Prime,
verifier = Verifier}, N) ->
- case crypto:generate_key(srp, {host, [Verifier, Generator, Prime, '6a']}) of
- error ->
- generate_srp_server_keys(SrpParams, N+1);
+ try crypto:generate_key(srp, {host, [Verifier, Generator, Prime, '6a']}) of
Keys ->
Keys
+ catch
+ error:_ ->
+ generate_srp_server_keys(SrpParams, N+1)
end.
generate_srp_client_keys(_Generator, _Prime, 10) ->
?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
generate_srp_client_keys(Generator, Prime, N) ->
- case crypto:generate_key(srp, {user, [Generator, Prime, '6a']}) of
- error ->
- generate_srp_client_keys(Generator, Prime, N+1);
+ try crypto:generate_key(srp, {user, [Generator, Prime, '6a']}) of
Keys ->
Keys
+ catch
+ error:_ ->
+ generate_srp_client_keys(Generator, Prime, N+1)
end.
handle_srp_identity(Username, {Fun, UserState}) ->
@@ -1903,7 +2398,7 @@ cipher_role(client, Data, Session, #state{connection_states = ConnectionStates0}
{Record, State} = prepare_connection(State0#state{session = Session,
connection_states = ConnectionStates},
Connection),
- Connection:next_event(connection, Record, State);
+ Connection:next_event(connection, Record, State, [{{timeout, handshake}, infinity, close}]);
cipher_role(server, Data, Session, #state{connection_states = ConnectionStates0} = State0,
Connection) ->
ConnectionStates1 = ssl_record:set_client_verify_data(current_read, Data,
@@ -1912,14 +2407,15 @@ cipher_role(server, Data, Session, #state{connection_states = ConnectionStates0
finalize_handshake(State0#state{connection_states = ConnectionStates1,
session = Session}, cipher, Connection),
{Record, State} = prepare_connection(State1, Connection),
- Connection:next_event(connection, Record, State, Actions).
-
-is_anonymous(Algo) when Algo == dh_anon;
- Algo == ecdh_anon;
- Algo == psk;
- Algo == dhe_psk;
- Algo == rsa_psk;
- Algo == srp_anon ->
+ Connection:next_event(connection, Record, State, [{{timeout, handshake}, infinity, close} | Actions]).
+
+is_anonymous(KexAlg) when KexAlg == dh_anon;
+ KexAlg == ecdh_anon;
+ KexAlg == psk;
+ KexAlg == dhe_psk;
+ KexAlg == ecdhe_psk;
+ KexAlg == rsa_psk;
+ KexAlg == srp_anon ->
true;
is_anonymous(_) ->
false.
@@ -2033,6 +2529,30 @@ set_socket_opts(ConnectionCb, Transport, Socket, [{active, Active}| Opts], SockO
Active == false ->
set_socket_opts(ConnectionCb, Transport, Socket, Opts,
SockOpts#socket_options{active = Active}, Other);
+set_socket_opts(ConnectionCb, Transport, Socket, [{active, Active1} = Opt| Opts],
+ SockOpts=#socket_options{active = Active0}, Other)
+ when Active1 >= -32768, Active1 =< 32767 ->
+ Active = if
+ is_integer(Active0), Active0 + Active1 < -32768 ->
+ error;
+ is_integer(Active0), Active0 + Active1 =< 0 ->
+ false;
+ is_integer(Active0), Active0 + Active1 > 32767 ->
+ error;
+ Active1 =< 0 ->
+ false;
+ is_integer(Active0) ->
+ Active0 + Active1;
+ true ->
+ Active1
+ end,
+ case Active of
+ error ->
+ {{error, {options, {socket_options, Opt}} }, SockOpts};
+ _ ->
+ set_socket_opts(ConnectionCb, Transport, Socket, Opts,
+ SockOpts#socket_options{active = Active}, Other)
+ end;
set_socket_opts(_,_, _, [{active, _} = Opt| _], SockOpts, _) ->
{{error, {options, {socket_options, Opt}} }, SockOpts};
set_socket_opts(ConnectionCb, Transport, Socket, [Opt | Opts], SockOpts, Other) ->
@@ -2046,36 +2566,32 @@ hibernate_after(connection = StateName,
{next_state, StateName, State, [{timeout, HibernateAfter, hibernate} | Actions]};
hibernate_after(StateName, State, Actions) ->
{next_state, StateName, State, Actions}.
-
-terminate_alert(normal, Version, ConnectionStates, Connection) ->
- Connection:encode_alert(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY),
- Version, ConnectionStates);
-terminate_alert({Reason, _}, Version, ConnectionStates, Connection) when Reason == close;
- Reason == shutdown ->
- Connection:encode_alert(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY),
- Version, ConnectionStates);
-
-terminate_alert(_, Version, ConnectionStates, Connection) ->
- {BinAlert, _} = Connection:encode_alert(?ALERT_REC(?FATAL, ?INTERNAL_ERROR),
- Version, ConnectionStates),
- BinAlert.
+
+
+terminate_alert(normal) ->
+ ?ALERT_REC(?WARNING, ?CLOSE_NOTIFY);
+terminate_alert({Reason, _}) when Reason == close;
+ Reason == shutdown ->
+ ?ALERT_REC(?WARNING, ?CLOSE_NOTIFY);
+terminate_alert(_) ->
+ ?ALERT_REC(?FATAL, ?INTERNAL_ERROR).
handle_trusted_certs_db(#state{ssl_options =
#ssl_options{cacertfile = <<>>, cacerts = []}}) ->
%% No trusted certs specified
ok;
-handle_trusted_certs_db(#state{cert_db_ref = Ref,
- cert_db = CertDb,
- ssl_options = #ssl_options{cacertfile = <<>>}}) when CertDb =/= undefined ->
+handle_trusted_certs_db(#state{static_env = #static_env{cert_db_ref = Ref,
+ cert_db = CertDb},
+ ssl_options = #ssl_options{cacertfile = <<>>}}) when CertDb =/= undefined ->
%% Certs provided as DER directly can not be shared
%% with other connections and it is safe to delete them when the connection ends.
ssl_pkix_db:remove_trusted_certs(Ref, CertDb);
-handle_trusted_certs_db(#state{file_ref_db = undefined}) ->
+handle_trusted_certs_db(#state{static_env = #static_env{file_ref_db = undefined}}) ->
%% Something went wrong early (typically cacertfile does not
%% exist) so there is nothing to handle
ok;
-handle_trusted_certs_db(#state{cert_db_ref = Ref,
- file_ref_db = RefDb,
+handle_trusted_certs_db(#state{static_env = #static_env{cert_db_ref = Ref,
+ file_ref_db = RefDb},
ssl_options = #ssl_options{cacertfile = File}}) ->
case ssl_pkix_db:ref_count(Ref, RefDb, -1) of
0 ->
@@ -2084,49 +2600,64 @@ handle_trusted_certs_db(#state{cert_db_ref = Ref,
ok
end.
-prepare_connection(#state{renegotiation = Renegotiate,
+prepare_connection(#state{handshake_env = #handshake_env{renegotiation = Renegotiate},
start_or_recv_from = RecvFrom} = State0, Connection)
when Renegotiate =/= {false, first},
RecvFrom =/= undefined ->
- State1 = Connection:reinit_handshake_data(State0),
- {Record, State} = Connection:next_record(State1),
- {Record, ack_connection(State)};
+ State = Connection:reinit(State0),
+ {no_record, ack_connection(State)};
prepare_connection(State0, Connection) ->
- State = Connection:reinit_handshake_data(State0),
+ State = Connection:reinit(State0),
{no_record, ack_connection(State)}.
-ack_connection(#state{renegotiation = {true, Initiater}} = State)
- when Initiater == internal;
- Initiater == peer ->
- State#state{renegotiation = undefined};
-ack_connection(#state{renegotiation = {true, From}} = State) ->
+ack_connection(#state{handshake_env = #handshake_env{renegotiation = {true, Initiater}} = HsEnv} = State) when Initiater == peer;
+ Initiater == internal ->
+ State#state{handshake_env = HsEnv#handshake_env{renegotiation = undefined}};
+ack_connection(#state{handshake_env = #handshake_env{renegotiation = {true, From}} = HsEnv} = State) ->
gen_statem:reply(From, ok),
- State#state{renegotiation = undefined};
-ack_connection(#state{renegotiation = {false, first},
- start_or_recv_from = StartFrom,
- timer = Timer} = State) when StartFrom =/= undefined ->
+ State#state{handshake_env = HsEnv#handshake_env{renegotiation = undefined}};
+ack_connection(#state{handshake_env = #handshake_env{renegotiation = {false, first}} = HsEnv,
+ start_or_recv_from = StartFrom} = State) when StartFrom =/= undefined ->
gen_statem:reply(StartFrom, connected),
- cancel_timer(Timer),
- State#state{renegotiation = undefined,
- start_or_recv_from = undefined, timer = undefined};
+ State#state{handshake_env = HsEnv#handshake_env{renegotiation = undefined},
+ start_or_recv_from = undefined};
ack_connection(State) ->
State.
-cancel_timer(undefined) ->
- ok;
-cancel_timer(Timer) ->
- erlang:cancel_timer(Timer),
- ok.
+session_handle_params(#server_ecdh_params{curve = ECCurve}, Session) ->
+ Session#session{ecc = ECCurve};
+session_handle_params(_, Session) ->
+ Session.
+
+handle_session(Role = server, #ssl_options{reuse_sessions = true} = SslOpts,
+ Host, Port, Session0) ->
+ register_session(Role, host_id(Role, Host, SslOpts), Port, Session0, true);
+handle_session(Role = client, #ssl_options{verify = verify_peer,
+ reuse_sessions = Reuse} = SslOpts,
+ Host, Port, Session0) when Reuse =/= false ->
+ register_session(Role, host_id(Role, Host, SslOpts), Port, Session0, reg_type(Reuse));
+handle_session(server, _, Host, Port, Session) ->
+ %% Remove "session of type new" entry from session DB
+ ssl_manager:invalidate_session(Host, Port, Session),
+ Session;
+handle_session(client, _,_,_, Session) ->
+ %% In client case there is no entry yet, so nothing to remove
+ Session.
+
+reg_type(save) ->
+ true;
+reg_type(true) ->
+ unique.
-register_session(client, Host, Port, #session{is_resumable = new} = Session0) ->
+register_session(client, Host, Port, #session{is_resumable = new} = Session0, Save) ->
Session = Session0#session{is_resumable = true},
- ssl_manager:register_session(Host, Port, Session),
+ ssl_manager:register_session(Host, Port, Session, Save),
Session;
-register_session(server, _, Port, #session{is_resumable = new} = Session0) ->
+register_session(server, _, Port, #session{is_resumable = new} = Session0, _) ->
Session = Session0#session{is_resumable = true},
ssl_manager:register_session(Port, Session),
Session;
-register_session(_, _, _, Session) ->
+register_session(_, _, _, Session, _) ->
Session. %% Already registered
host_id(client, _Host, #ssl_options{server_name_indication = Hostname}) when is_list(Hostname) ->
@@ -2135,31 +2666,30 @@ host_id(_, Host, _) ->
Host.
handle_new_session(NewId, CipherSuite, Compression,
- #state{session = Session0,
- protocol_cb = Connection} = State0) ->
+ #state{static_env = #static_env{protocol_cb = Connection},
+ session = Session0
+ } = State0) ->
Session = Session0#session{session_id = NewId,
cipher_suite = CipherSuite,
compression_method = Compression},
- {Record, State} = Connection:next_record(State0#state{session = Session}),
- Connection:next_event(certify, Record, State).
-
-handle_resumed_session(SessId, #state{connection_states = ConnectionStates0,
- negotiated_version = Version,
- host = Host, port = Port,
- protocol_cb = Connection,
- session_cache = Cache,
- session_cache_cb = CacheCb} = State0) ->
+ Connection:next_event(certify, no_record, State0#state{session = Session}).
+
+handle_resumed_session(SessId, #state{static_env = #static_env{host = Host,
+ port = Port,
+ protocol_cb = Connection,
+ session_cache = Cache,
+ session_cache_cb = CacheCb},
+ connection_env = #connection_env{negotiated_version = Version},
+ connection_states = ConnectionStates0} = State) ->
Session = CacheCb:lookup(Cache, {{Host, Port}, SessId}),
case ssl_handshake:master_secret(ssl:tls_version(Version), Session,
ConnectionStates0, client) of
{_, ConnectionStates} ->
- {Record, State} =
- Connection:next_record(State0#state{
- connection_states = ConnectionStates,
- session = Session}),
- Connection:next_event(abbreviated, Record, State);
+ Connection:next_event(abbreviated, no_record, State#state{
+ connection_states = ConnectionStates,
+ session = Session});
#alert{} = Alert ->
- handle_own_alert(Alert, Version, hello, State0)
+ handle_own_alert(Alert, Version, hello, State)
end.
make_premaster_secret({MajVer, MinVer}, rsa) ->
@@ -2198,7 +2728,7 @@ ssl_options_list([ciphers = Key | Keys], [Value | Values], Acc) ->
ssl_options_list(Keys, Values,
[{Key, lists:map(
fun(Suite) ->
- ssl_cipher:erl_suite_definition(Suite)
+ ssl_cipher_format:suite_bin_to_map(Suite)
end, Value)}
| Acc]);
ssl_options_list([Key | Keys], [Value | Values], Acc) ->
@@ -2207,28 +2737,31 @@ ssl_options_list([Key | Keys], [Value | Values], Acc) ->
handle_active_option(false, connection = StateName, To, Reply, State) ->
hibernate_after(StateName, State, [{reply, To, Reply}]);
-handle_active_option(_, connection = StateName0, To, Reply, #state{protocol_cb = Connection,
- user_data_buffer = <<>>} = State0) ->
- %% Need data, set active once
- {Record, State1} = Connection:next_record_if_active(State0),
- %% Note: Renogotiation may cause StateName0 =/= StateName
- case Connection:next_event(StateName0, Record, State1) of
+handle_active_option(_, connection = StateName, To, _Reply, #state{connection_env = #connection_env{terminated = true},
+ user_data_buffer = {_,0,_}} = State) ->
+ handle_normal_shutdown(?ALERT_REC(?FATAL, ?CLOSE_NOTIFY, all_data_deliverd), StateName,
+ State#state{start_or_recv_from = To}),
+ {stop,{shutdown, peer_close}, State};
+handle_active_option(_, connection = StateName0, To, Reply, #state{static_env = #static_env{protocol_cb = Connection},
+ user_data_buffer = {_,0,_}} = State0) ->
+ case Connection:next_event(StateName0, no_record, State0) of
{next_state, StateName, State} ->
hibernate_after(StateName, State, [{reply, To, Reply}]);
{next_state, StateName, State, Actions} ->
hibernate_after(StateName, State, [{reply, To, Reply} | Actions]);
- {stop, Reason, State} ->
- {stop, Reason, State}
+ {stop, _, _} = Stop ->
+ Stop
end;
-handle_active_option(_, StateName, To, Reply, #state{user_data_buffer = <<>>} = State) ->
+handle_active_option(_, StateName, To, Reply, #state{user_data_buffer = {_,0,_}} = State) ->
%% Active once already set
{next_state, StateName, State, [{reply, To, Reply}]};
-%% user_data_buffer =/= <<>>
-handle_active_option(_, StateName0, To, Reply, #state{protocol_cb = Connection} = State0) ->
+%% user_data_buffer nonempty
+handle_active_option(_, StateName0, To, Reply,
+ #state{static_env = #static_env{protocol_cb = Connection}} = State0) ->
case read_application_data(<<>>, State0) of
- {stop, Reason, State} ->
- {stop, Reason, State};
+ {stop, _, _} = Stop ->
+ Stop;
{Record, State1} ->
%% Note: Renogotiation may cause StateName0 =/= StateName
case Connection:next_event(StateName0, Record, State1) of
@@ -2241,64 +2774,27 @@ handle_active_option(_, StateName0, To, Reply, #state{protocol_cb = Connection}
end
end.
-encode_packet(Data, #socket_options{packet=Packet}) ->
- case Packet of
- 1 -> encode_size_packet(Data, 8, (1 bsl 8) - 1);
- 2 -> encode_size_packet(Data, 16, (1 bsl 16) - 1);
- 4 -> encode_size_packet(Data, 32, (1 bsl 32) - 1);
- _ -> Data
- end.
-
-encode_size_packet(Bin, Size, Max) ->
- Len = erlang:byte_size(Bin),
- case Len > Max of
- true -> throw({error, {badarg, {packet_to_large, Len, Max}}});
- false -> <<Len:Size, Bin/binary>>
- end.
-
-time_to_renegotiate(_Data,
- #{current_write := #{sequence_number := Num}},
- RenegotiateAt) ->
-
- %% We could do test:
- %% is_time_to_renegotiate((erlang:byte_size(_Data) div ?MAX_PLAIN_TEXT_LENGTH) + 1, RenegotiateAt),
- %% but we chose to have a some what lower renegotiateAt and a much cheaper test
- is_time_to_renegotiate(Num, RenegotiateAt).
-
-is_time_to_renegotiate(N, M) when N < M->
- false;
-is_time_to_renegotiate(_,_) ->
- true.
-
%% Picks ClientData
-get_data(_, _, <<>>) ->
- {more, <<>>};
-%% Recv timed out save buffer data until next recv
-get_data(#socket_options{active=false}, undefined, Buffer) ->
- {passive, Buffer};
-get_data(#socket_options{active=Active, packet=Raw}, BytesToRead, Buffer)
+get_data(#socket_options{active=false}, undefined, _Bin) ->
+ %% Recv timed out save buffer data until next recv
+ passive;
+get_data(#socket_options{active=Active, packet=Raw}, BytesToRead, Bin)
when Raw =:= raw; Raw =:= 0 -> %% Raw Mode
- if
- Active =/= false orelse BytesToRead =:= 0 ->
+ case Bin of
+ <<_/binary>> when Active =/= false orelse BytesToRead =:= 0 ->
%% Active true or once, or passive mode recv(0)
- {ok, Buffer, <<>>};
- byte_size(Buffer) >= BytesToRead ->
+ {ok, Bin, <<>>};
+ <<Data:BytesToRead/binary, Rest/binary>> ->
%% Passive Mode, recv(Bytes)
- <<Data:BytesToRead/binary, Rest/binary>> = Buffer,
- {ok, Data, Rest};
- true ->
+ {ok, Data, Rest};
+ <<_/binary>> ->
%% Passive Mode not enough data
- {more, Buffer}
+ {more, BytesToRead}
end;
-get_data(#socket_options{packet=Type, packet_size=Size}, _, Buffer) ->
+get_data(#socket_options{packet=Type, packet_size=Size}, _, Bin) ->
PacketOpts = [{packet_size, Size}],
- case decode_packet(Type, Buffer, PacketOpts) of
- {more, _} ->
- {more, Buffer};
- Decoded ->
- Decoded
- end.
+ decode_packet(Type, Bin, PacketOpts).
decode_packet({http, headers}, Buffer, PacketOpts) ->
decode_packet(httph, Buffer, PacketOpts);
@@ -2316,42 +2812,61 @@ decode_packet(Type, Buffer, PacketOpts) ->
%% Note that if the user has explicitly configured the socket to expect
%% HTTP headers using the {packet, httph} option, we don't do any automatic
%% switching of states.
-deliver_app_data(Transport, Socket, SOpts = #socket_options{active=Active, packet=Type},
- Data, Pid, From, Tracker, Connection) ->
- send_or_reply(Active, Pid, From, format_reply(Transport, Socket, SOpts, Data, Tracker, Connection)),
- SO = case Data of
- {P, _, _, _} when ((P =:= http_request) or (P =:= http_response)),
- ((Type =:= http) or (Type =:= http_bin)) ->
- SOpts#socket_options{packet={Type, headers}};
- http_eoh when tuple_size(Type) =:= 2 ->
- % End of headers - expect another Request/Response line
- {Type1, headers} = Type,
- SOpts#socket_options{packet=Type1};
- _ ->
- SOpts
- end,
+deliver_app_data(
+ CPids, Transport, Socket,
+ #socket_options{active=Active, packet=Type} = SOpts,
+ Data, Pid, From, Tracker, Connection) ->
+ %%
+ send_or_reply(
+ Active, Pid, From,
+ format_reply(
+ CPids, Transport, Socket, SOpts, Data, Tracker, Connection)),
+ SO =
+ case Data of
+ {P, _, _, _}
+ when ((P =:= http_request) or (P =:= http_response)),
+ ((Type =:= http) or (Type =:= http_bin)) ->
+ SOpts#socket_options{packet={Type, headers}};
+ http_eoh when tuple_size(Type) =:= 2 ->
+ %% End of headers - expect another Request/Response line
+ {Type1, headers} = Type,
+ SOpts#socket_options{packet=Type1};
+ _ ->
+ SOpts
+ end,
case Active of
once ->
SO#socket_options{active=false};
+ 1 ->
+ send_user(
+ Pid,
+ format_passive(
+ CPids, Transport, Socket, Tracker, Connection)),
+ SO#socket_options{active=false};
+ N when is_integer(N) ->
+ SO#socket_options{active=N - 1};
_ ->
SO
end.
-format_reply(_, _,#socket_options{active = false, mode = Mode, packet = Packet,
+format_reply(_, _, _,#socket_options{active = false, mode = Mode, packet = Packet,
header = Header}, Data, _, _) ->
{ok, do_format_reply(Mode, Packet, Header, Data)};
-format_reply(Transport, Socket, #socket_options{active = _, mode = Mode, packet = Packet,
+format_reply(CPids, Transport, Socket, #socket_options{active = _, mode = Mode, packet = Packet,
header = Header}, Data, Tracker, Connection) ->
- {ssl, Connection:socket(self(), Transport, Socket, Connection, Tracker),
+ {ssl, Connection:socket(CPids, Transport, Socket, Tracker),
do_format_reply(Mode, Packet, Header, Data)}.
-deliver_packet_error(Transport, Socket, SO= #socket_options{active = Active}, Data, Pid, From, Tracker, Connection) ->
- send_or_reply(Active, Pid, From, format_packet_error(Transport, Socket, SO, Data, Tracker, Connection)).
+deliver_packet_error(CPids, Transport, Socket,
+ SO= #socket_options{active = Active}, Data, Pid, From, Tracker, Connection) ->
+ send_or_reply(Active, Pid, From, format_packet_error(CPids,
+ Transport, Socket, SO, Data, Tracker, Connection)).
-format_packet_error(_, _,#socket_options{active = false, mode = Mode}, Data, _, _) ->
+format_packet_error(_, _, _,#socket_options{active = false, mode = Mode}, Data, _, _) ->
{error, {invalid_packet, do_format_reply(Mode, raw, 0, Data)}};
-format_packet_error(Transport, Socket, #socket_options{active = _, mode = Mode}, Data, Tracker, Connection) ->
- {ssl_error, Connection:socket(self(), Transport, Socket, Connection, Tracker),
+format_packet_error(CPids, Transport, Socket, #socket_options{active = _, mode = Mode},
+ Data, Tracker, Connection) ->
+ {ssl_error, Connection:socket(CPids, Transport, Socket, Tracker),
{invalid_packet, do_format_reply(Mode, raw, 0, Data)}}.
do_format_reply(binary, _, N, Data) when N > 0 -> % Header mode
@@ -2366,6 +2881,9 @@ do_format_reply(list, Packet, _, Data)
do_format_reply(list, _,_, Data) ->
binary_to_list(Data).
+format_passive(CPids, Transport, Socket, Tracker, Connection) ->
+ {ssl_passive, Connection:socket(CPids, Transport, Socket, Tracker)}.
+
header(0, <<>>) ->
<<>>;
header(_, <<>>) ->
@@ -2386,42 +2904,41 @@ send_or_reply(_, Pid, _From, Data) ->
send_user(Pid, Data).
send_user(Pid, Msg) ->
- Pid ! Msg.
+ Pid ! Msg,
+ ok.
-alert_user(Transport, Tracker, Socket, connection, Opts, Pid, From, Alert, Role, Connection) ->
- alert_user(Transport, Tracker, Socket, Opts#socket_options.active, Pid, From, Alert, Role, Connection);
-alert_user(Transport, Tracker, Socket,_, _, _, From, Alert, Role, Connection) ->
- alert_user(Transport, Tracker, Socket, From, Alert, Role, Connection).
+alert_user(Pids, Transport, Tracker, Socket, connection, Opts, Pid, From, Alert, Role, Connection) ->
+ alert_user(Pids, Transport, Tracker, Socket, Opts#socket_options.active, Pid, From, Alert, Role, Connection);
+alert_user(Pids, Transport, Tracker, Socket,_, _, _, From, Alert, Role, Connection) ->
+ alert_user(Pids, Transport, Tracker, Socket, From, Alert, Role, Connection).
-alert_user(Transport, Tracker, Socket, From, Alert, Role, Connection) ->
- alert_user(Transport, Tracker, Socket, false, no_pid, From, Alert, Role, Connection).
+alert_user(Pids, Transport, Tracker, Socket, From, Alert, Role, Connection) ->
+ alert_user(Pids, Transport, Tracker, Socket, false, no_pid, From, Alert, Role, Connection).
-alert_user(_, _, _, false = Active, Pid, From, Alert, Role, _) when From =/= undefined ->
+alert_user(_, _, _, _, false = Active, Pid, From, Alert, Role, _) when From =/= undefined ->
%% If there is an outstanding ssl_accept | recv
%% From will be defined and send_or_reply will
%% send the appropriate error message.
ReasonCode = ssl_alert:reason_code(Alert, Role),
send_or_reply(Active, Pid, From, {error, ReasonCode});
-alert_user(Transport, Tracker, Socket, Active, Pid, From, Alert, Role, Connection) ->
+alert_user(Pids, Transport, Tracker, Socket, Active, Pid, From, Alert, Role, Connection) ->
case ssl_alert:reason_code(Alert, Role) of
closed ->
send_or_reply(Active, Pid, From,
- {ssl_closed, Connection:socket(self(),
- Transport, Socket, Connection, Tracker)});
+ {ssl_closed, Connection:socket(Pids, Transport, Socket, Tracker)});
ReasonCode ->
send_or_reply(Active, Pid, From,
- {ssl_error, Connection:socket(self(),
- Transport, Socket, Connection, Tracker), ReasonCode})
+ {ssl_error, Connection:socket(Pids, Transport, Socket, Tracker), ReasonCode})
end.
-log_alert(true, Role, ProtocolName, StateName, #alert{role = Role} = Alert) ->
+log_alert(Level, Role, ProtocolName, StateName, #alert{role = Role} = Alert) ->
Txt = ssl_alert:own_alert_txt(Alert),
- error_logger:info_report(io_lib:format("~s ~p: In state ~p ~s\n", [ProtocolName, Role, StateName, Txt]));
-log_alert(true, Role, ProtocolName, StateName, Alert) ->
+ Report = io_lib:format("~s ~p: In state ~p ~s\n", [ProtocolName, Role, StateName, Txt]),
+ ssl_logger:notice(Level, Report);
+log_alert(Level, Role, ProtocolName, StateName, Alert) ->
Txt = ssl_alert:alert_txt(Alert),
- error_logger:info_report(io_lib:format("~s ~p: In state ~p ~s\n", [ProtocolName, Role, StateName, Txt]));
-log_alert(false, _, _, _, _) ->
- ok.
+ Report = io_lib:format("~s ~p: In state ~p ~s\n", [ProtocolName, Role, StateName, Txt]),
+ ssl_logger:notice(Level, Report).
invalidate_session(client, Host, Port, Session) ->
ssl_manager:invalidate_session(Host, Port, Session);
@@ -2430,7 +2947,9 @@ invalidate_session(server, _, Port, Session) ->
handle_sni_extension(undefined, State) ->
State;
-handle_sni_extension(#sni{hostname = Hostname}, State0) ->
+handle_sni_extension(#sni{hostname = Hostname}, #state{static_env = #static_env{role = Role} = InitStatEnv0,
+ handshake_env = HsEnv,
+ connection_env = CEnv} = State0) ->
NewOptions = update_ssl_options_from_sni(State0#state.ssl_options, Hostname),
case NewOptions of
undefined ->
@@ -2444,19 +2963,21 @@ handle_sni_extension(#sni{hostname = Hostname}, State0) ->
private_key := Key,
dh_params := DHParams,
own_certificate := OwnCert}} =
- ssl_config:init(NewOptions, State0#state.role),
+ ssl_config:init(NewOptions, Role),
State0#state{
session = State0#state.session#session{own_certificate = OwnCert},
- file_ref_db = FileRefHandle,
- cert_db_ref = Ref,
- cert_db = CertDbHandle,
- crl_db = CRLDbHandle,
- session_cache = CacheHandle,
- private_key = Key,
- diffie_hellman_params = DHParams,
- ssl_options = NewOptions,
- sni_hostname = Hostname
- }
+ static_env = InitStatEnv0#static_env{
+ file_ref_db = FileRefHandle,
+ cert_db_ref = Ref,
+ cert_db = CertDbHandle,
+ crl_db = CRLDbHandle,
+ session_cache = CacheHandle
+ },
+ connection_env = CEnv#connection_env{private_key = Key},
+ ssl_options = NewOptions,
+ handshake_env = HsEnv#handshake_env{sni_hostname = Hostname,
+ diffie_hellman_params = DHParams}
+ }
end.
update_ssl_options_from_sni(OrigSSLOptions, SNIHostname) ->
diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl
index f9d2149170..ff7207a8ce 100644
--- a/lib/ssl/src/ssl_connection.hrl
+++ b/lib/ssl/src/ssl_connection.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -33,71 +33,151 @@
-include("ssl_cipher.hrl").
-include_lib("public_key/include/public_key.hrl").
+-record(static_env, {
+ role :: client | server,
+ transport_cb :: atom(), % callback module
+ protocol_cb :: tls_connection | dtls_connection,
+ data_tag :: atom(), % ex tcp.
+ close_tag :: atom(), % ex tcp_closed
+ error_tag :: atom(), % ex tcp_error
+ passive_tag :: atom(), % ex tcp_passive
+ host :: string() | inet:ip_address(),
+ port :: integer(),
+ socket :: port() | tuple(), %% TODO: dtls socket
+ cert_db :: reference() | 'undefined',
+ session_cache :: db_handle(),
+ session_cache_cb :: atom(),
+ crl_db :: term(),
+ file_ref_db :: db_handle(),
+ cert_db_ref :: certdb_ref() | 'undefined',
+ tracker :: pid() | 'undefined' %% Tracker process for listen socket
+ }).
+
+-record(handshake_env, {
+ client_hello_version :: ssl_record:ssl_version() | 'undefined',
+ unprocessed_handshake_events = 0 :: integer(),
+ tls_handshake_history :: ssl_handshake:ssl_handshake_history() | secret_printout()
+ | 'undefined',
+ expecting_finished = false ::boolean(),
+ renegotiation :: undefined | {boolean(), From::term() | internal | peer},
+ allow_renegotiate = true ::boolean(),
+ %% Ext handling
+ hello, %%:: #client_hello{} | #server_hello{}
+ sni_hostname = undefined,
+ expecting_next_protocol_negotiation = false ::boolean(),
+ next_protocol = undefined :: undefined | binary(),
+ negotiated_protocol,
+ hashsign_algorithm = {undefined, undefined},
+ cert_hashsign_algorithm = {undefined, undefined},
+ %% key exchange
+ kex_algorithm :: ssl:kex_algo(),
+ kex_keys :: {PublicKey :: binary(), PrivateKey :: binary()} | #'ECPrivateKey'{} | undefined | secret_printout(),
+ diffie_hellman_params:: #'DHParameter'{} | undefined | secret_printout(),
+ srp_params :: #srp_user{} | secret_printout() | 'undefined',
+ public_key_info :: ssl_handshake:public_key_info() | 'undefined',
+ premaster_secret :: binary() | secret_printout() | 'undefined',
+ server_psk_identity :: binary() | 'undefined' % server psk identity hint
+ }).
+
+-record(connection_env, {
+ user_application :: {Monitor::reference(), User::pid()},
+ downgrade,
+ terminated = false ::boolean() | closed,
+ negotiated_version :: ssl_record:ssl_version() | 'undefined',
+ erl_dist_handle = undefined :: erlang:dist_handle() | 'undefined',
+ private_key :: public_key:private_key() | secret_printout() | 'undefined'
+ }).
+
-record(state, {
- role :: client | server,
- user_application :: {Monitor::reference(), User::pid()},
- transport_cb :: atom(), % callback module
- protocol_cb :: tls_connection | dtls_connection,
- data_tag :: atom(), % ex tcp.
- close_tag :: atom(), % ex tcp_closed
- error_tag :: atom(), % ex tcp_error
- host :: string() | inet:ip_address(),
- port :: integer(),
- socket :: port() | tuple(), %% TODO: dtls socket
- ssl_options :: #ssl_options{},
- socket_options :: #socket_options{},
- connection_states :: ssl_record:connection_states() | secret_printout(),
- protocol_buffers :: term() | secret_printout() , %% #protocol_buffers{} from tls_record.hrl or dtls_recor.hrl
- unprocessed_handshake_events = 0 :: integer(),
- tls_handshake_history :: ssl_handshake:ssl_handshake_history() | secret_printout()
- | 'undefined',
- cert_db :: reference() | 'undefined',
- session :: #session{} | secret_printout(),
- session_cache :: db_handle(),
- session_cache_cb :: atom(),
- crl_db :: term(),
- negotiated_version :: ssl_record:ssl_version() | 'undefined',
- client_hello_version :: ssl_record:ssl_version() | 'undefined',
- client_certificate_requested = false :: boolean(),
- key_algorithm :: ssl_cipher:key_algo(),
- hashsign_algorithm = {undefined, undefined},
- cert_hashsign_algorithm,
- public_key_info :: ssl_handshake:public_key_info() | 'undefined',
- private_key :: public_key:private_key() | secret_printout() | 'undefined',
- diffie_hellman_params:: #'DHParameter'{} | undefined | secret_printout(),
- diffie_hellman_keys :: {PublicKey :: binary(), PrivateKey :: binary()} | #'ECPrivateKey'{} | undefined | secret_printout(),
- psk_identity :: binary() | 'undefined', % server psk identity hint
- srp_params :: #srp_user{} | secret_printout() | 'undefined',
- srp_keys ::{PublicKey :: binary(), PrivateKey :: binary()} | secret_printout() | 'undefined',
- premaster_secret :: binary() | secret_printout() | 'undefined',
- file_ref_db :: db_handle(),
- cert_db_ref :: certdb_ref() | 'undefined',
- bytes_to_read :: undefined | integer(), %% bytes to read in passive mode
- user_data_buffer :: undefined | binary() | secret_printout(),
- renegotiation :: undefined | {boolean(), From::term() | internal | peer},
- start_or_recv_from :: term(),
- timer :: undefined | reference(), % start_or_recive_timer
- %%send_queue :: queue:queue(),
- terminated = false ::boolean(),
- allow_renegotiate = true ::boolean(),
- expecting_next_protocol_negotiation = false ::boolean(),
- expecting_finished = false ::boolean(),
- next_protocol = undefined :: undefined | binary(),
- negotiated_protocol,
- tracker :: pid() | 'undefined', %% Tracker process for listen socket
- sni_hostname = undefined,
- downgrade,
- flight_buffer = [] :: list() | map(), %% Buffer of TLS/DTLS records, used during the TLS handshake
- %% to when possible pack more than on TLS record into the
- %% underlaying packet format. Introduced by DTLS - RFC 4347.
- %% The mecahnism is also usefull in TLS although we do not
- %% need to worry about packet loss in TLS. In DTLS we need to track DTLS handshake seqnr
- flight_state = reliable, %% reliable | {retransmit, integer()}| {waiting, ref(), integer()} - last two is used in DTLS over udp.
- protocol_specific = #{} :: map()
- }).
+ static_env :: #static_env{},
+ connection_env :: #connection_env{} | secret_printout(),
+ ssl_options :: #ssl_options{},
+ socket_options :: #socket_options{},
+
+ %% Hanshake %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ handshake_env :: #handshake_env{} | secret_printout(),
+ %% Buffer of TLS/DTLS records, used during the TLS
+ %% handshake to when possible pack more than one TLS
+ %% record into the underlaying packet
+ %% format. Introduced by DTLS - RFC 4347. The
+ %% mecahnism is also usefull in TLS although we do not
+ %% need to worry about packet loss in TLS. In DTLS we
+ %% need to track DTLS handshake seqnr
+ flight_buffer = [] :: list() | map(),
+ client_certificate_requested = false :: boolean(),
+ protocol_specific = #{} :: map(),
+ session :: #session{} | secret_printout(),
+ key_share,
+ %% Data shuffling %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ connection_states :: ssl_record:connection_states() | secret_printout(),
+ protocol_buffers :: term() | secret_printout() , %% #protocol_buffers{} from tls_record.hrl or dtls_recor.hr
+ user_data_buffer :: undefined | {[binary()],non_neg_integer(),[binary()]} | secret_printout(),
+ bytes_to_read :: undefined | integer(), %% bytes to read in passive mode
+ %% recv and start handling
+ start_or_recv_from :: term(),
+ log_level
+ }).
+
-define(DEFAULT_DIFFIE_HELLMAN_PARAMS,
#'DHParameter'{prime = ?DEFAULT_DIFFIE_HELLMAN_PRIME,
base = ?DEFAULT_DIFFIE_HELLMAN_GENERATOR}).
-define(WAIT_TO_ALLOW_RENEGOTIATION, 12000).
+
+%%----------------------------------------------------------------------
+%% TLS 1.3
+%%----------------------------------------------------------------------
+
+%% TLS 1.3 uses the same state record with the following differences:
+%%
+%% state :: record()
+%%
+%% session_cache - not implemented
+%% session_cache_cb - not implemented
+%% crl_db - not implemented
+%% client_hello_version - Bleichenbacher mitigation in TLS 1.2
+%% client_certificate_requested - Built into TLS 1.3 state machine
+%% key_algorithm - not used
+%% diffie_hellman_params - used in TLS 1.2 ECDH key exchange
+%% diffie_hellman_keys - used in TLS 1.2 ECDH key exchange
+%% psk_identity - not used
+%% srp_params - not used, no srp extension in TLS 1.3
+%% srp_keys - not used, no srp extension in TLS 1.3
+%% premaster_secret - not used
+%% renegotiation - TLS 1.3 forbids renegotiation
+%% hello - used in user_hello, handshake continue
+%% allow_renegotiate - TLS 1.3 forbids renegotiation
+%% expecting_next_protocol_negotiation - ALPN replaced NPN, depricated in TLS 1.3
+%% expecting_finished - not implemented, used by abbreviated
+%% next_protocol - ALPN replaced NPN, depricated in TLS 1.3
+%%
+%% connection_state :: map()
+%%
+%% compression_state - not used
+%% mac_secret - not used
+%% sequence_number - not used
+%% secure_renegotiation - not used, no renegotiation_info in TLS 1.3
+%% client_verify_data - not used, no renegotiation_info in TLS 1.3
+%% server_verify_data - not used, no renegotiation_info in TLS 1.3
+%% beast_mitigation - not used
+%%
+%% security_parameters :: map()
+%%
+%% cipher_type - TLS 1.3 uses only AEAD ciphers
+%% iv_size - not used
+%% key_size - not used
+%% key_material_length - not used
+%% expanded_key_material_length - used in SSL 3.0
+%% mac_algorithm - not used
+%% prf_algorithm - not used
+%% hash_size - not used
+%% compression_algorithm - not used
+%% master_secret - used for multiple secret types in TLS 1.3
+%% client_random - not used
+%% server_random - not used
+%% exportable - not used
+%%
+%% cipher_state :: record()
+%% nonce - used for sequence_number
+
-endif. % -ifdef(ssl_connection).
diff --git a/lib/ssl/src/ssl_connection_sup.erl b/lib/ssl/src/ssl_connection_sup.erl
index 1a1f43e683..934dd39df5 100644
--- a/lib/ssl/src/ssl_connection_sup.erl
+++ b/lib/ssl/src/ssl_connection_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -51,12 +51,12 @@ init([]) ->
ListenOptionsTracker = listen_options_tracker_child_spec(),
DTLSConnetionManager = dtls_connection_manager_child_spec(),
- DTLSUdpListeners = dtls_udp_listeners_spec(),
+ DTLSListeners = dtls_listeners_spec(),
{ok, {{one_for_one, 10, 3600}, [TLSConnetionManager,
ListenOptionsTracker,
DTLSConnetionManager,
- DTLSUdpListeners
+ DTLSListeners
]}}.
@@ -91,9 +91,9 @@ listen_options_tracker_child_spec() ->
Type = supervisor,
{Name, StartFunc, Restart, Shutdown, Type, Modules}.
-dtls_udp_listeners_spec() ->
- Name = dtls_udp_listener,
- StartFunc = {dtls_udp_sup, start_link, []},
+dtls_listeners_spec() ->
+ Name = dtls_listener,
+ StartFunc = {dtls_listener_sup, start_link, []},
Restart = permanent,
Shutdown = 4000,
Modules = [],
diff --git a/lib/ssl/src/ssl_crl_cache.erl b/lib/ssl/src/ssl_crl_cache.erl
index 8817b0c884..841620ce57 100644
--- a/lib/ssl/src/ssl_crl_cache.erl
+++ b/lib/ssl/src/ssl_crl_cache.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -28,6 +28,10 @@
-behaviour(ssl_crl_cache_api).
+-export_type([crl_src/0, uri/0]).
+-type crl_src() :: {file, file:filename()} | {der, public_key:der_encoded()}.
+-type uri() :: uri_string:uri_string().
+
-export([lookup/3, select/2, fresh_crl/2]).
-export([insert/1, insert/2, delete/1]).
@@ -92,8 +96,8 @@ delete({der, CRLs}) ->
ssl_manager:delete_crls({?NO_DIST_POINT, CRLs});
delete(URI) ->
- case http_uri:parse(URI) of
- {ok, {http, _, _ , _, Path,_}} ->
+ case uri_string:normalize(URI, [return_map]) of
+ #{scheme := "http", path := Path} ->
ssl_manager:delete_crls(string:trim(Path, leading, "/"));
_ ->
{error, {only_http_distribution_points_supported, URI}}
@@ -103,8 +107,8 @@ delete(URI) ->
%%% Internal functions
%%--------------------------------------------------------------------
do_insert(URI, CRLs) ->
- case http_uri:parse(URI) of
- {ok, {http, _, _ , _, Path,_}} ->
+ case uri_string:normalize(URI, [return_map]) of
+ #{scheme := "http", path := Path} ->
ssl_manager:insert_crls(string:trim(Path, leading, "/"), CRLs);
_ ->
{error, {only_http_distribution_points_supported, URI}}
@@ -161,7 +165,7 @@ http_get(URL, Rest, CRLDbInfo, Timeout) ->
cache_lookup(_, undefined) ->
[];
cache_lookup(URL, {{Cache, _}, _}) ->
- {ok, {_, _, _ , _, Path,_}} = http_uri:parse(URL),
+ #{path := Path} = uri_string:normalize(URL, [return_map]),
case ssl_pkix_db:lookup(string:trim(Path, leading, "/"), Cache) of
undefined ->
[];
diff --git a/lib/ssl/src/ssl_crl_cache_api.erl b/lib/ssl/src/ssl_crl_cache_api.erl
index d5380583e7..8a750b3929 100644
--- a/lib/ssl/src/ssl_crl_cache_api.erl
+++ b/lib/ssl/src/ssl_crl_cache_api.erl
@@ -21,12 +21,15 @@
%%
-module(ssl_crl_cache_api).
-
-include_lib("public_key/include/public_key.hrl").
--type db_handle() :: term().
--type issuer_name() :: {rdnSequence, [#'AttributeTypeAndValue'{}]}.
+-export_type([dist_point/0, crl_cache_ref/0]).
+
+-type crl_cache_ref() :: any().
+-type issuer_name() :: {rdnSequence,[#'AttributeTypeAndValue'{}]}.
+-type dist_point() :: #'DistributionPoint'{}.
--callback lookup(#'DistributionPoint'{}, issuer_name(), db_handle()) -> not_available | [public_key:der_encoded()].
--callback select(issuer_name(), db_handle()) -> [public_key:der_encoded()].
--callback fresh_crl(#'DistributionPoint'{}, public_key:der_encoded()) -> public_key:der_encoded().
+
+-callback lookup(dist_point(), issuer_name(), crl_cache_ref()) -> not_available | [public_key:der_encoded()].
+-callback select(issuer_name(), crl_cache_ref()) -> [public_key:der_encoded()].
+-callback fresh_crl(dist_point(), public_key:der_encoded()) -> public_key:der_encoded().
diff --git a/lib/ssl/src/ssl_crl_hash_dir.erl b/lib/ssl/src/ssl_crl_hash_dir.erl
index bb62737232..9478ff9b78 100644
--- a/lib/ssl/src/ssl_crl_hash_dir.erl
+++ b/lib/ssl/src/ssl_crl_hash_dir.erl
@@ -20,6 +20,7 @@
-module(ssl_crl_hash_dir).
-include_lib("public_key/include/public_key.hrl").
+-include_lib("kernel/include/logger.hrl").
-behaviour(ssl_crl_cache_api).
@@ -55,7 +56,7 @@ select(Issuer, {_DbHandle, [{dir, Dir}]}) ->
%% is happy with that, but if it's true, this is an error.
[];
{error, Error} ->
- error_logger:error_report(
+ ?LOG_ERROR(
[{cannot_find_crl, Error},
{dir, Dir},
{module, ?MODULE},
@@ -86,7 +87,7 @@ find_crls(Issuer, Hash, Dir, N, Acc) ->
error:Error ->
%% Something is wrong with the file. Report
%% it, and try the next one.
- error_logger:error_report(
+ ?LOG_ERROR(
[{crl_parse_error, Error},
{filename, Filename},
{module, ?MODULE},
diff --git a/lib/ssl/src/ssl_dh_groups.erl b/lib/ssl/src/ssl_dh_groups.erl
new file mode 100644
index 0000000000..20d53de430
--- /dev/null
+++ b/lib/ssl/src/ssl_dh_groups.erl
@@ -0,0 +1,467 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(ssl_dh_groups).
+
+-include_lib("public_key/include/public_key.hrl").
+
+-export([modp2048_generator/0, modp2048_prime/0,
+ ffdhe2048_generator/0, ffdhe2048_prime/0,
+ ffdhe3072_generator/0, ffdhe3072_prime/0,
+ ffdhe4096_generator/0, ffdhe4096_prime/0,
+ ffdhe6144_generator/0, ffdhe6144_prime/0,
+ ffdhe8192_generator/0, ffdhe8192_prime/0,
+ dh_params/1]).
+
+%% RFC3526 - 2048-bit MODP Group
+%% This group is assigned id 14.
+%%
+%% This prime is: 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 }
+%%
+%% Its hexadecimal value is:
+%%
+%% FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
+%% 29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
+%% EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
+%% E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
+%% EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D
+%% C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F
+%% 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
+%% 670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B
+%% E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9
+%% DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510
+%% 15728E5A 8AACAA68 FFFFFFFF FFFFFFFF
+%%
+%% The generator is: 2.
+modp2048_generator() ->
+ 2.
+
+modp2048_prime() ->
+ P = "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
+ "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
+ "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
+ "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
+ "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
+ "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
+ "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
+ "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
+ "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
+ "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
+ "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF",
+ list_to_integer(P, 16).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%% RFC8446 - TLS 1.3
+%%% RFC7919 - Negotiated FFDHE for TLS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% ffdhe2048
+%% ---------
+%% The 2048-bit group has registry value 256 and is calculated from the
+%% following formula:
+%%
+%% The modulus is:
+%%
+%% p = 2^2048 - 2^1984 + {[2^1918 * e] + 560316 } * 2^64 - 1
+%%
+%% The hexadecimal representation of p is:
+%%
+%% FFFFFFFF FFFFFFFF ADF85458 A2BB4A9A AFDC5620 273D3CF1
+%% D8B9C583 CE2D3695 A9E13641 146433FB CC939DCE 249B3EF9
+%% 7D2FE363 630C75D8 F681B202 AEC4617A D3DF1ED5 D5FD6561
+%% 2433F51F 5F066ED0 85636555 3DED1AF3 B557135E 7F57C935
+%% 984F0C70 E0E68B77 E2A689DA F3EFE872 1DF158A1 36ADE735
+%% 30ACCA4F 483A797A BC0AB182 B324FB61 D108A94B B2C8E3FB
+%% B96ADAB7 60D7F468 1D4F42A3 DE394DF4 AE56EDE7 6372BB19
+%% 0B07A7C8 EE0A6D70 9E02FCE1 CDF7E2EC C03404CD 28342F61
+%% 9172FE9C E98583FF 8E4F1232 EEF28183 C3FE3B1B 4C6FAD73
+%% 3BB5FCBC 2EC22005 C58EF183 7D1683B2 C6F34A26 C1B2EFFA
+%% 886B4238 61285C97 FFFFFFFF FFFFFFFF
+%%
+%% The generator is: g = 2
+%%
+%% The group size is: q = (p-1)/2
+%%
+%% The estimated symmetric-equivalent strength of this group is 103
+%% bits.
+ffdhe2048_generator() ->
+ 2.
+
+ffdhe2048_prime() ->
+ P = "FFFFFFFF" "FFFFFFFF" "ADF85458" "A2BB4A9A" "AFDC5620" "273D3CF1"
+ "D8B9C583" "CE2D3695" "A9E13641" "146433FB" "CC939DCE" "249B3EF9"
+ "7D2FE363" "630C75D8" "F681B202" "AEC4617A" "D3DF1ED5" "D5FD6561"
+ "2433F51F" "5F066ED0" "85636555" "3DED1AF3" "B557135E" "7F57C935"
+ "984F0C70" "E0E68B77" "E2A689DA" "F3EFE872" "1DF158A1" "36ADE735"
+ "30ACCA4F" "483A797A" "BC0AB182" "B324FB61" "D108A94B" "B2C8E3FB"
+ "B96ADAB7" "60D7F468" "1D4F42A3" "DE394DF4" "AE56EDE7" "6372BB19"
+ "0B07A7C8" "EE0A6D70" "9E02FCE1" "CDF7E2EC" "C03404CD" "28342F61"
+ "9172FE9C" "E98583FF" "8E4F1232" "EEF28183" "C3FE3B1B" "4C6FAD73"
+ "3BB5FCBC" "2EC22005" "C58EF183" "7D1683B2" "C6F34A26" "C1B2EFFA"
+ "886B4238" "61285C97" "FFFFFFFF" "FFFFFFFF",
+ list_to_integer(P, 16).
+
+
+%% ffdhe3072
+%% ---------
+%% The 3072-bit prime has registry value 257 and is calculated from the
+%% following formula:
+%%
+%% The modulus is:
+%%
+%% p = 2^3072 - 2^3008 + {[2^2942 * e] + 2625351} * 2^64 - 1
+%%
+%% The hexadecimal representation of p is:
+%%
+%% FFFFFFFF FFFFFFFF ADF85458 A2BB4A9A AFDC5620 273D3CF1
+%% D8B9C583 CE2D3695 A9E13641 146433FB CC939DCE 249B3EF9
+%% 7D2FE363 630C75D8 F681B202 AEC4617A D3DF1ED5 D5FD6561
+%% 2433F51F 5F066ED0 85636555 3DED1AF3 B557135E 7F57C935
+%% 984F0C70 E0E68B77 E2A689DA F3EFE872 1DF158A1 36ADE735
+%% 30ACCA4F 483A797A BC0AB182 B324FB61 D108A94B B2C8E3FB
+%% B96ADAB7 60D7F468 1D4F42A3 DE394DF4 AE56EDE7 6372BB19
+%% 0B07A7C8 EE0A6D70 9E02FCE1 CDF7E2EC C03404CD 28342F61
+%% 9172FE9C E98583FF 8E4F1232 EEF28183 C3FE3B1B 4C6FAD73
+%% 3BB5FCBC 2EC22005 C58EF183 7D1683B2 C6F34A26 C1B2EFFA
+%% 886B4238 611FCFDC DE355B3B 6519035B BC34F4DE F99C0238
+%% 61B46FC9 D6E6C907 7AD91D26 91F7F7EE 598CB0FA C186D91C
+%% AEFE1309 85139270 B4130C93 BC437944 F4FD4452 E2D74DD3
+%% 64F2E21E 71F54BFF 5CAE82AB 9C9DF69E E86D2BC5 22363A0D
+%% ABC52197 9B0DEADA 1DBF9A42 D5C4484E 0ABCD06B FA53DDEF
+%% 3C1B20EE 3FD59D7C 25E41D2B 66C62E37 FFFFFFFF FFFFFFFF
+%%
+%% The generator is: g = 2
+%%
+%% The group size is: q = (p-1)/2
+%%
+%% The estimated symmetric-equivalent strength of this group is 125
+%% bits.
+ffdhe3072_generator() ->
+ 2.
+
+ffdhe3072_prime() ->
+ P = "FFFFFFFF" "FFFFFFFF" "ADF85458" "A2BB4A9A" "AFDC5620" "273D3CF1"
+ "D8B9C583" "CE2D3695" "A9E13641" "146433FB" "CC939DCE" "249B3EF9"
+ "7D2FE363" "630C75D8" "F681B202" "AEC4617A" "D3DF1ED5" "D5FD6561"
+ "2433F51F" "5F066ED0" "85636555" "3DED1AF3" "B557135E" "7F57C935"
+ "984F0C70" "E0E68B77" "E2A689DA" "F3EFE872" "1DF158A1" "36ADE735"
+ "30ACCA4F" "483A797A" "BC0AB182" "B324FB61" "D108A94B" "B2C8E3FB"
+ "B96ADAB7" "60D7F468" "1D4F42A3" "DE394DF4" "AE56EDE7" "6372BB19"
+ "0B07A7C8" "EE0A6D70" "9E02FCE1" "CDF7E2EC" "C03404CD" "28342F61"
+ "9172FE9C" "E98583FF" "8E4F1232" "EEF28183" "C3FE3B1B" "4C6FAD73"
+ "3BB5FCBC" "2EC22005" "C58EF183" "7D1683B2" "C6F34A26" "C1B2EFFA"
+ "886B4238" "611FCFDC" "DE355B3B" "6519035B" "BC34F4DE" "F99C0238"
+ "61B46FC9" "D6E6C907" "7AD91D26" "91F7F7EE" "598CB0FA" "C186D91C"
+ "AEFE1309" "85139270" "B4130C93" "BC437944" "F4FD4452" "E2D74DD3"
+ "64F2E21E" "71F54BFF" "5CAE82AB" "9C9DF69E" "E86D2BC5" "22363A0D"
+ "ABC52197" "9B0DEADA" "1DBF9A42" "D5C4484E" "0ABCD06B" "FA53DDEF"
+ "3C1B20EE" "3FD59D7C" "25E41D2B" "66C62E37" "FFFFFFFF" "FFFFFFFF",
+ list_to_integer(P, 16).
+
+
+%% ffdhe4096
+%% ---------
+%% The 4096-bit group has registry value 258 and is calculated from the
+%% following formula:
+%%
+%% The modulus is:
+%%
+%% p = 2^4096 - 2^4032 + {[2^3966 * e] + 5736041} * 2^64 - 1
+%%
+%% The hexadecimal representation of p is:
+%%
+%% FFFFFFFF FFFFFFFF ADF85458 A2BB4A9A AFDC5620 273D3CF1
+%% D8B9C583 CE2D3695 A9E13641 146433FB CC939DCE 249B3EF9
+%% 7D2FE363 630C75D8 F681B202 AEC4617A D3DF1ED5 D5FD6561
+%% 2433F51F 5F066ED0 85636555 3DED1AF3 B557135E 7F57C935
+%% 984F0C70 E0E68B77 E2A689DA F3EFE872 1DF158A1 36ADE735
+%% 30ACCA4F 483A797A BC0AB182 B324FB61 D108A94B B2C8E3FB
+%% B96ADAB7 60D7F468 1D4F42A3 DE394DF4 AE56EDE7 6372BB19
+%% 0B07A7C8 EE0A6D70 9E02FCE1 CDF7E2EC C03404CD 28342F61
+%% 9172FE9C E98583FF 8E4F1232 EEF28183 C3FE3B1B 4C6FAD73
+%% 3BB5FCBC 2EC22005 C58EF183 7D1683B2 C6F34A26 C1B2EFFA
+%% 886B4238 611FCFDC DE355B3B 6519035B BC34F4DE F99C0238
+%% 61B46FC9 D6E6C907 7AD91D26 91F7F7EE 598CB0FA C186D91C
+%% AEFE1309 85139270 B4130C93 BC437944 F4FD4452 E2D74DD3
+%% 64F2E21E 71F54BFF 5CAE82AB 9C9DF69E E86D2BC5 22363A0D
+%% ABC52197 9B0DEADA 1DBF9A42 D5C4484E 0ABCD06B FA53DDEF
+%% 3C1B20EE 3FD59D7C 25E41D2B 669E1EF1 6E6F52C3 164DF4FB
+%% 7930E9E4 E58857B6 AC7D5F42 D69F6D18 7763CF1D 55034004
+%% 87F55BA5 7E31CC7A 7135C886 EFB4318A ED6A1E01 2D9E6832
+%% A907600A 918130C4 6DC778F9 71AD0038 092999A3 33CB8B7A
+%% 1A1DB93D 7140003C 2A4ECEA9 F98D0ACC 0A8291CD CEC97DCF
+%% 8EC9B55A 7F88A46B 4DB5A851 F44182E1 C68A007E 5E655F6A
+%% FFFFFFFF FFFFFFFF
+%%
+%% The generator is: g = 2
+%%
+%% The group size is: q = (p-1)/2
+%%
+%% The estimated symmetric-equivalent strength of this group is 150
+%% bits.
+ffdhe4096_generator() ->
+ 2.
+
+ffdhe4096_prime() ->
+ P = "FFFFFFFF" "FFFFFFFF" "ADF85458" "A2BB4A9A" "AFDC5620" "273D3CF1"
+ "D8B9C583" "CE2D3695" "A9E13641" "146433FB" "CC939DCE" "249B3EF9"
+ "7D2FE363" "630C75D8" "F681B202" "AEC4617A" "D3DF1ED5" "D5FD6561"
+ "2433F51F" "5F066ED0" "85636555" "3DED1AF3" "B557135E" "7F57C935"
+ "984F0C70" "E0E68B77" "E2A689DA" "F3EFE872" "1DF158A1" "36ADE735"
+ "30ACCA4F" "483A797A" "BC0AB182" "B324FB61" "D108A94B" "B2C8E3FB"
+ "B96ADAB7" "60D7F468" "1D4F42A3" "DE394DF4" "AE56EDE7" "6372BB19"
+ "0B07A7C8" "EE0A6D70" "9E02FCE1" "CDF7E2EC" "C03404CD" "28342F61"
+ "9172FE9C" "E98583FF" "8E4F1232" "EEF28183" "C3FE3B1B" "4C6FAD73"
+ "3BB5FCBC" "2EC22005" "C58EF183" "7D1683B2" "C6F34A26" "C1B2EFFA"
+ "886B4238" "611FCFDC" "DE355B3B" "6519035B" "BC34F4DE" "F99C0238"
+ "61B46FC9" "D6E6C907" "7AD91D26" "91F7F7EE" "598CB0FA" "C186D91C"
+ "AEFE1309" "85139270" "B4130C93" "BC437944" "F4FD4452" "E2D74DD3"
+ "64F2E21E" "71F54BFF" "5CAE82AB" "9C9DF69E" "E86D2BC5" "22363A0D"
+ "ABC52197" "9B0DEADA" "1DBF9A42" "D5C4484E" "0ABCD06B" "FA53DDEF"
+ "3C1B20EE" "3FD59D7C" "25E41D2B" "669E1EF1" "6E6F52C3" "164DF4FB"
+ "7930E9E4" "E58857B6" "AC7D5F42" "D69F6D18" "7763CF1D" "55034004"
+ "87F55BA5" "7E31CC7A" "7135C886" "EFB4318A" "ED6A1E01" "2D9E6832"
+ "A907600A" "918130C4" "6DC778F9" "71AD0038" "092999A3" "33CB8B7A"
+ "1A1DB93D" "7140003C" "2A4ECEA9" "F98D0ACC" "0A8291CD" "CEC97DCF"
+ "8EC9B55A" "7F88A46B" "4DB5A851" "F44182E1" "C68A007E" "5E655F6A"
+ "FFFFFFFF" "FFFFFFFF",
+ list_to_integer(P, 16).
+
+
+%% ffdhe6144
+%% ---------
+%% The 6144-bit group has registry value 259 and is calculated from the
+%% following formula:
+%%
+%% The modulus is:
+%%
+%% p = 2^6144 - 2^6080 + {[2^6014 * e] + 15705020} * 2^64 - 1
+%%
+%% The hexadecimal representation of p is:
+%%
+%% FFFFFFFF FFFFFFFF ADF85458 A2BB4A9A AFDC5620 273D3CF1
+%% D8B9C583 CE2D3695 A9E13641 146433FB CC939DCE 249B3EF9
+%% 7D2FE363 630C75D8 F681B202 AEC4617A D3DF1ED5 D5FD6561
+%% 2433F51F 5F066ED0 85636555 3DED1AF3 B557135E 7F57C935
+%% 984F0C70 E0E68B77 E2A689DA F3EFE872 1DF158A1 36ADE735
+%% 30ACCA4F 483A797A BC0AB182 B324FB61 D108A94B B2C8E3FB
+%% B96ADAB7 60D7F468 1D4F42A3 DE394DF4 AE56EDE7 6372BB19
+%% 0B07A7C8 EE0A6D70 9E02FCE1 CDF7E2EC C03404CD 28342F61
+%% 9172FE9C E98583FF 8E4F1232 EEF28183 C3FE3B1B 4C6FAD73
+%% 3BB5FCBC 2EC22005 C58EF183 7D1683B2 C6F34A26 C1B2EFFA
+%% 886B4238 611FCFDC DE355B3B 6519035B BC34F4DE F99C0238
+%% 61B46FC9 D6E6C907 7AD91D26 91F7F7EE 598CB0FA C186D91C
+%% AEFE1309 85139270 B4130C93 BC437944 F4FD4452 E2D74DD3
+%% 64F2E21E 71F54BFF 5CAE82AB 9C9DF69E E86D2BC5 22363A0D
+%% ABC52197 9B0DEADA 1DBF9A42 D5C4484E 0ABCD06B FA53DDEF
+%% 3C1B20EE 3FD59D7C 25E41D2B 669E1EF1 6E6F52C3 164DF4FB
+%% 7930E9E4 E58857B6 AC7D5F42 D69F6D18 7763CF1D 55034004
+%% 87F55BA5 7E31CC7A 7135C886 EFB4318A ED6A1E01 2D9E6832
+%% A907600A 918130C4 6DC778F9 71AD0038 092999A3 33CB8B7A
+%% 1A1DB93D 7140003C 2A4ECEA9 F98D0ACC 0A8291CD CEC97DCF
+%% 8EC9B55A 7F88A46B 4DB5A851 F44182E1 C68A007E 5E0DD902
+%% 0BFD64B6 45036C7A 4E677D2C 38532A3A 23BA4442 CAF53EA6
+%% 3BB45432 9B7624C8 917BDD64 B1C0FD4C B38E8C33 4C701C3A
+%% CDAD0657 FCCFEC71 9B1F5C3E 4E46041F 388147FB 4CFDB477
+%% A52471F7 A9A96910 B855322E DB6340D8 A00EF092 350511E3
+%% 0ABEC1FF F9E3A26E 7FB29F8C 183023C3 587E38DA 0077D9B4
+%% 763E4E4B 94B2BBC1 94C6651E 77CAF992 EEAAC023 2A281BF6
+%% B3A739C1 22611682 0AE8DB58 47A67CBE F9C9091B 462D538C
+%% D72B0374 6AE77F5E 62292C31 1562A846 505DC82D B854338A
+%% E49F5235 C95B9117 8CCF2DD5 CACEF403 EC9D1810 C6272B04
+%% 5B3B71F9 DC6B80D6 3FDD4A8E 9ADB1E69 62A69526 D43161C1
+%% A41D570D 7938DAD4 A40E329C D0E40E65 FFFFFFFF FFFFFFFF
+%%
+%% The generator is: g = 2
+%%
+%% The group size is: q = (p-1)/2
+%%
+%% The estimated symmetric-equivalent strength of this group is 175
+%% bits.
+ffdhe6144_generator() ->
+ 2.
+
+ffdhe6144_prime() ->
+ P = "FFFFFFFF" "FFFFFFFF" "ADF85458" "A2BB4A9A" "AFDC5620" "273D3CF1"
+ "D8B9C583" "CE2D3695" "A9E13641" "146433FB" "CC939DCE" "249B3EF9"
+ "7D2FE363" "630C75D8" "F681B202" "AEC4617A" "D3DF1ED5" "D5FD6561"
+ "2433F51F" "5F066ED0" "85636555" "3DED1AF3" "B557135E" "7F57C935"
+ "984F0C70" "E0E68B77" "E2A689DA" "F3EFE872" "1DF158A1" "36ADE735"
+ "30ACCA4F" "483A797A" "BC0AB182" "B324FB61" "D108A94B" "B2C8E3FB"
+ "B96ADAB7" "60D7F468" "1D4F42A3" "DE394DF4" "AE56EDE7" "6372BB19"
+ "0B07A7C8" "EE0A6D70" "9E02FCE1" "CDF7E2EC" "C03404CD" "28342F61"
+ "9172FE9C" "E98583FF" "8E4F1232" "EEF28183" "C3FE3B1B" "4C6FAD73"
+ "3BB5FCBC" "2EC22005" "C58EF183" "7D1683B2" "C6F34A26" "C1B2EFFA"
+ "886B4238" "611FCFDC" "DE355B3B" "6519035B" "BC34F4DE" "F99C0238"
+ "61B46FC9" "D6E6C907" "7AD91D26" "91F7F7EE" "598CB0FA" "C186D91C"
+ "AEFE1309" "85139270" "B4130C93" "BC437944" "F4FD4452" "E2D74DD3"
+ "64F2E21E" "71F54BFF" "5CAE82AB" "9C9DF69E" "E86D2BC5" "22363A0D"
+ "ABC52197" "9B0DEADA" "1DBF9A42" "D5C4484E" "0ABCD06B" "FA53DDEF"
+ "3C1B20EE" "3FD59D7C" "25E41D2B" "669E1EF1" "6E6F52C3" "164DF4FB"
+ "7930E9E4" "E58857B6" "AC7D5F42" "D69F6D18" "7763CF1D" "55034004"
+ "87F55BA5" "7E31CC7A" "7135C886" "EFB4318A" "ED6A1E01" "2D9E6832"
+ "A907600A" "918130C4" "6DC778F9" "71AD0038" "092999A3" "33CB8B7A"
+ "1A1DB93D" "7140003C" "2A4ECEA9" "F98D0ACC" "0A8291CD" "CEC97DCF"
+ "8EC9B55A" "7F88A46B" "4DB5A851" "F44182E1" "C68A007E" "5E0DD902"
+ "0BFD64B6" "45036C7A" "4E677D2C" "38532A3A" "23BA4442" "CAF53EA6"
+ "3BB45432" "9B7624C8" "917BDD64" "B1C0FD4C" "B38E8C33" "4C701C3A"
+ "CDAD0657" "FCCFEC71" "9B1F5C3E" "4E46041F" "388147FB" "4CFDB477"
+ "A52471F7" "A9A96910" "B855322E" "DB6340D8" "A00EF092" "350511E3"
+ "0ABEC1FF" "F9E3A26E" "7FB29F8C" "183023C3" "587E38DA" "0077D9B4"
+ "763E4E4B" "94B2BBC1" "94C6651E" "77CAF992" "EEAAC023" "2A281BF6"
+ "B3A739C1" "22611682" "0AE8DB58" "47A67CBE" "F9C9091B" "462D538C"
+ "D72B0374" "6AE77F5E" "62292C31" "1562A846" "505DC82D" "B854338A"
+ "E49F5235" "C95B9117" "8CCF2DD5" "CACEF403" "EC9D1810" "C6272B04"
+ "5B3B71F9" "DC6B80D6" "3FDD4A8E" "9ADB1E69" "62A69526" "D43161C1"
+ "A41D570D" "7938DAD4" "A40E329C" "D0E40E65" "FFFFFFFF" "FFFFFFFF",
+ list_to_integer(P, 16).
+
+
+%% ffdhe8192
+%% ---------
+%% The 8192-bit group has registry value 260 and is calculated from the
+%% following formula:
+%%
+%% The modulus is:
+%%
+%% p = 2^8192 - 2^8128 + {[2^8062 * e] + 10965728} * 2^64 - 1
+%%
+%% The hexadecimal representation of p is:
+%%
+%% FFFFFFFF FFFFFFFF ADF85458 A2BB4A9A AFDC5620 273D3CF1
+%% D8B9C583 CE2D3695 A9E13641 146433FB CC939DCE 249B3EF9
+%% 7D2FE363 630C75D8 F681B202 AEC4617A D3DF1ED5 D5FD6561
+%% 2433F51F 5F066ED0 85636555 3DED1AF3 B557135E 7F57C935
+%% 984F0C70 E0E68B77 E2A689DA F3EFE872 1DF158A1 36ADE735
+%% 30ACCA4F 483A797A BC0AB182 B324FB61 D108A94B B2C8E3FB
+%% B96ADAB7 60D7F468 1D4F42A3 DE394DF4 AE56EDE7 6372BB19
+%% 0B07A7C8 EE0A6D70 9E02FCE1 CDF7E2EC C03404CD 28342F61
+%% 9172FE9C E98583FF 8E4F1232 EEF28183 C3FE3B1B 4C6FAD73
+%% 3BB5FCBC 2EC22005 C58EF183 7D1683B2 C6F34A26 C1B2EFFA
+%% 886B4238 611FCFDC DE355B3B 6519035B BC34F4DE F99C0238
+%% 61B46FC9 D6E6C907 7AD91D26 91F7F7EE 598CB0FA C186D91C
+%% AEFE1309 85139270 B4130C93 BC437944 F4FD4452 E2D74DD3
+%% 64F2E21E 71F54BFF 5CAE82AB 9C9DF69E E86D2BC5 22363A0D
+%% ABC52197 9B0DEADA 1DBF9A42 D5C4484E 0ABCD06B FA53DDEF
+%% 3C1B20EE 3FD59D7C 25E41D2B 669E1EF1 6E6F52C3 164DF4FB
+%% 7930E9E4 E58857B6 AC7D5F42 D69F6D18 7763CF1D 55034004
+%% 87F55BA5 7E31CC7A 7135C886 EFB4318A ED6A1E01 2D9E6832
+%% A907600A 918130C4 6DC778F9 71AD0038 092999A3 33CB8B7A
+%% 1A1DB93D 7140003C 2A4ECEA9 F98D0ACC 0A8291CD CEC97DCF
+%% 8EC9B55A 7F88A46B 4DB5A851 F44182E1 C68A007E 5E0DD902
+%% 0BFD64B6 45036C7A 4E677D2C 38532A3A 23BA4442 CAF53EA6
+%% 3BB45432 9B7624C8 917BDD64 B1C0FD4C B38E8C33 4C701C3A
+%% CDAD0657 FCCFEC71 9B1F5C3E 4E46041F 388147FB 4CFDB477
+%% A52471F7 A9A96910 B855322E DB6340D8 A00EF092 350511E3
+%% 0ABEC1FF F9E3A26E 7FB29F8C 183023C3 587E38DA 0077D9B4
+%% 763E4E4B 94B2BBC1 94C6651E 77CAF992 EEAAC023 2A281BF6
+%% B3A739C1 22611682 0AE8DB58 47A67CBE F9C9091B 462D538C
+%% D72B0374 6AE77F5E 62292C31 1562A846 505DC82D B854338A
+%% E49F5235 C95B9117 8CCF2DD5 CACEF403 EC9D1810 C6272B04
+%% 5B3B71F9 DC6B80D6 3FDD4A8E 9ADB1E69 62A69526 D43161C1
+%% A41D570D 7938DAD4 A40E329C CFF46AAA 36AD004C F600C838
+%% 1E425A31 D951AE64 FDB23FCE C9509D43 687FEB69 EDD1CC5E
+%% 0B8CC3BD F64B10EF 86B63142 A3AB8829 555B2F74 7C932665
+%% CB2C0F1C C01BD702 29388839 D2AF05E4 54504AC7 8B758282
+%% 2846C0BA 35C35F5C 59160CC0 46FD8251 541FC68C 9C86B022
+%% BB709987 6A460E74 51A8A931 09703FEE 1C217E6C 3826E52C
+%% 51AA691E 0E423CFC 99E9E316 50C1217B 624816CD AD9A95F9
+%% D5B80194 88D9C0A0 A1FE3075 A577E231 83F81D4A 3F2FA457
+%% 1EFC8CE0 BA8A4FE8 B6855DFE 72B0A66E DED2FBAB FBE58A30
+%% FAFABE1C 5D71A87E 2F741EF8 C1FE86FE A6BBFDE5 30677F0D
+%% 97D11D49 F7A8443D 0822E506 A9F4614E 011E2A94 838FF88C
+%% D68C8BB7 C5C6424C FFFFFFFF FFFFFFFF
+%%
+%% The generator is: g = 2
+%%
+%% The group size is: q = (p-1)/2
+%%
+%% The estimated symmetric-equivalent strength of this group is 192
+%% bits.
+ffdhe8192_generator() ->
+ 2.
+
+ffdhe8192_prime() ->
+ P = "FFFFFFFF" "FFFFFFFF" "ADF85458" "A2BB4A9A" "AFDC5620" "273D3CF1"
+ "D8B9C583" "CE2D3695" "A9E13641" "146433FB" "CC939DCE" "249B3EF9"
+ "7D2FE363" "630C75D8" "F681B202" "AEC4617A" "D3DF1ED5" "D5FD6561"
+ "2433F51F" "5F066ED0" "85636555" "3DED1AF3" "B557135E" "7F57C935"
+ "984F0C70" "E0E68B77" "E2A689DA" "F3EFE872" "1DF158A1" "36ADE735"
+ "30ACCA4F" "483A797A" "BC0AB182" "B324FB61" "D108A94B" "B2C8E3FB"
+ "B96ADAB7" "60D7F468" "1D4F42A3" "DE394DF4" "AE56EDE7" "6372BB19"
+ "0B07A7C8" "EE0A6D70" "9E02FCE1" "CDF7E2EC" "C03404CD" "28342F61"
+ "9172FE9C" "E98583FF" "8E4F1232" "EEF28183" "C3FE3B1B" "4C6FAD73"
+ "3BB5FCBC" "2EC22005" "C58EF183" "7D1683B2" "C6F34A26" "C1B2EFFA"
+ "886B4238" "611FCFDC" "DE355B3B" "6519035B" "BC34F4DE" "F99C0238"
+ "61B46FC9" "D6E6C907" "7AD91D26" "91F7F7EE" "598CB0FA" "C186D91C"
+ "AEFE1309" "85139270" "B4130C93" "BC437944" "F4FD4452" "E2D74DD3"
+ "64F2E21E" "71F54BFF" "5CAE82AB" "9C9DF69E" "E86D2BC5" "22363A0D"
+ "ABC52197" "9B0DEADA" "1DBF9A42" "D5C4484E" "0ABCD06B" "FA53DDEF"
+ "3C1B20EE" "3FD59D7C" "25E41D2B" "669E1EF1" "6E6F52C3" "164DF4FB"
+ "7930E9E4" "E58857B6" "AC7D5F42" "D69F6D18" "7763CF1D" "55034004"
+ "87F55BA5" "7E31CC7A" "7135C886" "EFB4318A" "ED6A1E01" "2D9E6832"
+ "A907600A" "918130C4" "6DC778F9" "71AD0038" "092999A3" "33CB8B7A"
+ "1A1DB93D" "7140003C" "2A4ECEA9" "F98D0ACC" "0A8291CD" "CEC97DCF"
+ "8EC9B55A" "7F88A46B" "4DB5A851" "F44182E1" "C68A007E" "5E0DD902"
+ "0BFD64B6" "45036C7A" "4E677D2C" "38532A3A" "23BA4442" "CAF53EA6"
+ "3BB45432" "9B7624C8" "917BDD64" "B1C0FD4C" "B38E8C33" "4C701C3A"
+ "CDAD0657" "FCCFEC71" "9B1F5C3E" "4E46041F" "388147FB" "4CFDB477"
+ "A52471F7" "A9A96910" "B855322E" "DB6340D8" "A00EF092" "350511E3"
+ "0ABEC1FF" "F9E3A26E" "7FB29F8C" "183023C3" "587E38DA" "0077D9B4"
+ "763E4E4B" "94B2BBC1" "94C6651E" "77CAF992" "EEAAC023" "2A281BF6"
+ "B3A739C1" "22611682" "0AE8DB58" "47A67CBE" "F9C9091B" "462D538C"
+ "D72B0374" "6AE77F5E" "62292C31" "1562A846" "505DC82D" "B854338A"
+ "E49F5235" "C95B9117" "8CCF2DD5" "CACEF403" "EC9D1810" "C6272B04"
+ "5B3B71F9" "DC6B80D6" "3FDD4A8E" "9ADB1E69" "62A69526" "D43161C1"
+ "A41D570D" "7938DAD4" "A40E329C" "CFF46AAA" "36AD004C" "F600C838"
+ "1E425A31" "D951AE64" "FDB23FCE" "C9509D43" "687FEB69" "EDD1CC5E"
+ "0B8CC3BD" "F64B10EF" "86B63142" "A3AB8829" "555B2F74" "7C932665"
+ "CB2C0F1C" "C01BD702" "29388839" "D2AF05E4" "54504AC7" "8B758282"
+ "2846C0BA" "35C35F5C" "59160CC0" "46FD8251" "541FC68C" "9C86B022"
+ "BB709987" "6A460E74" "51A8A931" "09703FEE" "1C217E6C" "3826E52C"
+ "51AA691E" "0E423CFC" "99E9E316" "50C1217B" "624816CD" "AD9A95F9"
+ "D5B80194" "88D9C0A0" "A1FE3075" "A577E231" "83F81D4A" "3F2FA457"
+ "1EFC8CE0" "BA8A4FE8" "B6855DFE" "72B0A66E" "DED2FBAB" "FBE58A30"
+ "FAFABE1C" "5D71A87E" "2F741EF8" "C1FE86FE" "A6BBFDE5" "30677F0D"
+ "97D11D49" "F7A8443D" "0822E506" "A9F4614E" "011E2A94" "838FF88C"
+ "D68C8BB7" "C5C6424C" "FFFFFFFF" "FFFFFFFF",
+ list_to_integer(P, 16).
+
+dh_params(ffdhe2048) ->
+ #'DHParameter'{
+ prime = ffdhe2048_prime(),
+ base = ffdhe2048_generator()};
+dh_params(ffdhe3072) ->
+ #'DHParameter'{
+ prime = ffdhe3072_prime(),
+ base = ffdhe3072_generator()};
+dh_params(ffdhe4096) ->
+ #'DHParameter'{
+ prime = ffdhe4096_prime(),
+ base = ffdhe4096_generator()};
+dh_params(ffdhe6144) ->
+ #'DHParameter'{
+ prime = ffdhe6144_prime(),
+ base = ffdhe6144_generator()};
+dh_params(ffdhe8192) ->
+ #'DHParameter'{
+ prime = ffdhe8192_prime(),
+ base = ffdhe8192_generator()}.
diff --git a/lib/ssl/src/ssl_dist_sup.erl b/lib/ssl/src/ssl_dist_sup.erl
index e92f3d3979..bea67935d8 100644
--- a/lib/ssl/src/ssl_dist_sup.erl
+++ b/lib/ssl/src/ssl_dist_sup.erl
@@ -60,8 +60,7 @@ start_link() ->
init([]) ->
AdminSup = ssl_admin_child_spec(),
ConnectionSup = ssl_connection_sup(),
- ProxyServer = proxy_server_child_spec(),
- {ok, {{one_for_all, 10, 3600}, [AdminSup, ProxyServer, ConnectionSup]}}.
+ {ok, {{one_for_all, 10, 3600}, [AdminSup, ConnectionSup]}}.
%%--------------------------------------------------------------------
%%% Internal functions
@@ -84,15 +83,6 @@ ssl_connection_sup() ->
Type = supervisor,
{Name, StartFunc, Restart, Shutdown, Type, Modules}.
-proxy_server_child_spec() ->
- Name = ssl_tls_dist_proxy,
- StartFunc = {ssl_tls_dist_proxy, start_link, []},
- Restart = permanent,
- Shutdown = 4000,
- Modules = [ssl_tls_dist_proxy],
- Type = worker,
- {Name, StartFunc, Restart, Shutdown, Type, Modules}.
-
consult(File) ->
case erl_prim_loader:get_file(File) of
{ok, Binary, _FullName} ->
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 7efb89bfae..7b34991f4f 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -30,6 +30,7 @@
-include("ssl_alert.hrl").
-include("ssl_internal.hrl").
-include("ssl_srp.hrl").
+-include("tls_handshake_1_3.hrl").
-include_lib("public_key/include/public_key.hrl").
-export_type([ssl_handshake/0, ssl_handshake_history/0,
@@ -38,7 +39,7 @@
-type oid() :: tuple().
-type public_key_params() :: #'Dss-Parms'{} | {namedCurve, oid()} | #'ECParameters'{} | term().
-type public_key_info() :: {oid(), #'RSAPublicKey'{} | integer() | #'ECPoint'{}, public_key_params()}.
--type ssl_handshake_history() :: {[binary()], [binary()]}.
+-type ssl_handshake_history() :: {iodata(), iodata()}.
-type ssl_handshake() :: #server_hello{} | #server_hello_done{} | #certificate{} | #certificate_request{} |
#client_key_exchange{} | #finished{} | #certificate_verify{} |
@@ -52,15 +53,15 @@
%% Handle handshake messages
-export([certify/7, certificate_verify/6, verify_signature/5,
master_secret/4, server_key_exchange_hash/2, verify_connection/6,
- init_handshake_history/0, update_handshake_history/3, verify_server_key/5,
- select_version/3
+ init_handshake_history/0, update_handshake_history/2, verify_server_key/5,
+ select_version/3, select_supported_version/2, extension_value/1
]).
%% Encode
--export([encode_handshake/2, encode_hello_extensions/1,
+-export([encode_handshake/2, encode_hello_extensions/1, encode_extensions/1, encode_extensions/2,
encode_client_protocol_negotiation/2, encode_protocols_advertised_on_server/1]).
%% Decode
--export([decode_handshake/3, decode_hello_extensions/1,
+-export([decode_handshake/3, decode_vector/1, decode_hello_extensions/4, decode_extensions/3,
decode_server_key/3, decode_client_key/3,
decode_suites/2
]).
@@ -71,13 +72,18 @@
premaster_secret/2, premaster_secret/3, premaster_secret/4]).
%% Extensions handling
--export([client_hello_extensions/5,
+-export([client_hello_extensions/6,
handle_client_hello_extensions/9, %% Returns server hello extensions
handle_server_hello_extensions/9, select_curve/2, select_curve/3,
select_hashsign/4, select_hashsign/5,
- select_hashsign_algs/3
+ select_hashsign_algs/3, empty_extensions/2, add_server_share/3
]).
+-export([get_cert_params/1,
+ server_name/3,
+ validation_fun_and_state/9,
+ handle_path_validation_error/7]).
+
%%====================================================================
%% Create handshake messages
%%====================================================================
@@ -92,8 +98,8 @@ hello_request() ->
#hello_request{}.
%%--------------------------------------------------------------------
--spec server_hello(#session{}, ssl_record:ssl_version(), ssl_record:connection_states(),
- #hello_extensions{}) -> #server_hello{}.
+-spec server_hello(binary(), ssl_record:ssl_version(), ssl_record:connection_states(),
+ Extension::map()) -> #server_hello{}.
%%
%% Description: Creates a server hello message.
%%--------------------------------------------------------------------
@@ -139,8 +145,8 @@ certificate(OwnCert, CertDbHandle, CertDbRef, server) ->
case ssl_certificate:certificate_chain(OwnCert, CertDbHandle, CertDbRef) of
{ok, _, Chain} ->
#certificate{asn1_certificates = Chain};
- {error, _} ->
- ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, server_has_no_suitable_certificates)
+ {error, Error} ->
+ ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {server_has_no_suitable_certificates, Error})
end.
%%--------------------------------------------------------------------
@@ -169,14 +175,14 @@ client_certificate_verify(OwnCert, MasterSecret, Version,
end.
%%--------------------------------------------------------------------
--spec certificate_request(ssl_cipher:cipher_suite(), db_handle(),
+-spec certificate_request(ssl_cipher_format:cipher_suite(), db_handle(),
certdb_ref(), #hash_sign_algos{}, ssl_record:ssl_version()) ->
#certificate_request{}.
%%
%% Description: Creates a certificate_request message, called by the server.
%%--------------------------------------------------------------------
certificate_request(CipherSuite, CertDbHandle, CertDbRef, HashSigns, Version) ->
- Types = certificate_types(ssl_cipher:suite_definition(CipherSuite), Version),
+ Types = certificate_types(ssl_cipher_format:suite_bin_to_map(CipherSuite), Version),
Authorities = certificate_authorities(CertDbHandle, CertDbRef),
#certificate_request{
certificate_types = Types,
@@ -189,11 +195,18 @@ certificate_request(CipherSuite, CertDbHandle, CertDbRef, HashSigns, Version) ->
{dh, binary()} |
{dh, {binary(), binary()}, #'DHParameter'{}, {HashAlgo::atom(), SignAlgo::atom()},
binary(), binary(), public_key:private_key()} |
+ {ecdh, _, _, _, _, _} |
{ecdh, #'ECPrivateKey'{}} |
+ {psk, _, _, _, _, _} |
{psk, binary()} |
+ {dhe_psk, _, _, _, _, _, _, _} |
{dhe_psk, binary(), binary()} |
+ {ecdhe_psk, _, _, _, _, _, _} |
+ {ecdhe_psk, binary(), #'ECPrivateKey'{}} |
{srp, {binary(), binary()}, #srp_user{}, {HashAlgo::atom(), SignAlgo::atom()},
- binary(), binary(), public_key:private_key()}) ->
+ binary(), binary(), public_key:private_key()} |
+ {srp, _} |
+ {psk_premaster_secret, _, _, _}) ->
#client_key_exchange{} | #server_key_exchange{}.
%%
@@ -229,6 +242,13 @@ key_exchange(client, _Version, {dhe_psk, Identity, PublicKey}) ->
dh_public = PublicKey}
};
+key_exchange(client, _Version, {ecdhe_psk, Identity, #'ECPrivateKey'{publicKey = ECPublicKey}}) ->
+ #client_key_exchange{
+ exchange_keys = #client_ecdhe_psk_identity{
+ identity = Identity,
+ dh_public = ECPublicKey}
+ };
+
key_exchange(client, _Version, {psk_premaster_secret, PskIdentity, Secret, {_, PublicKey, _}}) ->
EncPremasterSecret =
encrypted_premaster_secret(Secret, PublicKey),
@@ -275,6 +295,16 @@ key_exchange(server, Version, {dhe_psk, PskIdentityHint, {PublicKey, _},
enc_server_key_exchange(Version, ServerEDHPSKParams,
HashSign, ClientRandom, ServerRandom, PrivateKey);
+key_exchange(server, Version, {ecdhe_psk, PskIdentityHint,
+ #'ECPrivateKey'{publicKey = ECPublicKey,
+ parameters = ECCurve},
+ HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
+ ServerECDHEPSKParams = #server_ecdhe_psk_params{
+ hint = PskIdentityHint,
+ dh_params = #server_ecdh_params{curve = ECCurve, public = ECPublicKey}},
+ enc_server_key_exchange(Version, ServerECDHEPSKParams, HashSign,
+ ClientRandom, ServerRandom, PrivateKey);
+
key_exchange(server, Version, {srp, {PublicKey, _},
#srp_user{generator = Generator, prime = Prime,
salt = Salt},
@@ -314,22 +344,23 @@ certify(#certificate{asn1_certificates = ASN1Certs}, CertDbHandle, CertDbRef,
Opts, CRLDbHandle, Role, Host) ->
ServerName = server_name(Opts#ssl_options.server_name_indication, Host, Role),
- [PeerCert | _] = ASN1Certs,
+ [PeerCert | ChainCerts ] = ASN1Certs,
try
{TrustedCert, CertPath} =
ssl_certificate:trusted_cert_and_path(ASN1Certs, CertDbHandle, CertDbRef,
Opts#ssl_options.partial_chain),
ValidationFunAndState = validation_fun_and_state(Opts#ssl_options.verify_fun, Role,
CertDbHandle, CertDbRef, ServerName,
+ Opts#ssl_options.customize_hostname_check,
Opts#ssl_options.crl_check, CRLDbHandle, CertPath),
- case public_key:pkix_path_validation(TrustedCert,
- CertPath,
- [{max_path_length, Opts#ssl_options.depth},
- {verify_fun, ValidationFunAndState}]) of
+ Options = [{max_path_length, Opts#ssl_options.depth},
+ {verify_fun, ValidationFunAndState}],
+ case public_key:pkix_path_validation(TrustedCert, CertPath, Options) of
{ok, {PublicKeyInfo,_}} ->
{PeerCert, PublicKeyInfo};
{error, Reason} ->
- path_validation_alert(Reason)
+ handle_path_validation_error(Reason, PeerCert, ChainCerts, Opts, Options,
+ CertDbHandle, CertDbRef)
end
catch
error:{badmatch,{asn1, Asn1Reason}} ->
@@ -338,7 +369,6 @@ certify(#certificate{asn1_certificates = ASN1Certs}, CertDbHandle, CertDbRef,
error:OtherReason ->
?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {unexpected_error, OtherReason})
end.
-
%%--------------------------------------------------------------------
-spec certificate_verify(binary(), public_key_info(), ssl_record:ssl_version(), term(),
binary(), ssl_handshake_history()) -> valid | #alert{}.
@@ -455,24 +485,12 @@ init_handshake_history() ->
{[], []}.
%%--------------------------------------------------------------------
--spec update_handshake_history(ssl_handshake:ssl_handshake_history(), Data ::term(), boolean()) ->
+-spec update_handshake_history(ssl_handshake:ssl_handshake_history(), Data ::term()) ->
ssl_handshake:ssl_handshake_history().
%%
%% Description: Update the handshake history buffer with Data.
%%--------------------------------------------------------------------
-update_handshake_history(Handshake, % special-case SSL2 client hello
- <<?CLIENT_HELLO, ?UINT24(_), ?BYTE(Major), ?BYTE(Minor),
- ?UINT16(CSLength), ?UINT16(0),
- ?UINT16(CDLength),
- CipherSuites:CSLength/binary,
- ChallengeData:CDLength/binary>>, true) ->
- update_handshake_history(Handshake,
- <<?CLIENT_HELLO, ?BYTE(Major), ?BYTE(Minor),
- ?UINT16(CSLength), ?UINT16(0),
- ?UINT16(CDLength),
- CipherSuites:CSLength/binary,
- ChallengeData:CDLength/binary>>, true);
-update_handshake_history({Handshake0, _Prev}, Data, _) ->
+update_handshake_history({Handshake0, _Prev}, Data) ->
{[Data|Handshake0], Handshake0}.
verify_server_key(#server_key_params{params_bin = EncParams,
@@ -492,6 +510,21 @@ verify_server_key(#server_key_params{params_bin = EncParams,
select_version(RecordCB, ClientVersion, Versions) ->
do_select_version(RecordCB, ClientVersion, Versions).
+
+%% Called by TLS 1.2/1.3 Server when "supported_versions" is present
+%% in ClientHello.
+%% Input lists are ordered (highest first)
+select_supported_version([], _ServerVersions) ->
+ undefined;
+select_supported_version([ClientVersion|T], ServerVersions) ->
+ case lists:member(ClientVersion, ServerVersions) of
+ true ->
+ ClientVersion;
+ false ->
+ select_supported_version(T, ServerVersions)
+ end.
+
+
%%====================================================================
%% Encode handshake
%%====================================================================
@@ -505,7 +538,7 @@ encode_handshake(#server_hello{server_version = {Major, Minor},
session_id = Session_ID,
cipher_suite = CipherSuite,
compression_method = Comp_method,
- extensions = #hello_extensions{} = Extensions}, _Version) ->
+ extensions = Extensions}, _Version) ->
SID_length = byte_size(Session_ID),
ExtensionsBin = encode_hello_extensions(Extensions),
{?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
@@ -555,71 +588,126 @@ encode_handshake(#certificate_verify{signature = BinSig, hashsign_algorithm = Ha
encode_handshake(#finished{verify_data = VerifyData}, _Version) ->
{?FINISHED, VerifyData}.
-encode_hello_extensions(#hello_extensions{} = Extensions) ->
- encode_hello_extensions(hello_extensions_list(Extensions), <<>>).
-encode_hello_extensions([], <<>>) ->
- <<>>;
-encode_hello_extensions([], Acc) ->
+encode_hello_extensions(Extensions) ->
+ encode_extensions(hello_extensions_list(Extensions), <<>>).
+
+encode_extensions(Exts) ->
+ encode_extensions(Exts, <<>>).
+
+encode_extensions([], <<>>) ->
+ <<?UINT16(0)>>;
+encode_extensions([], Acc) ->
Size = byte_size(Acc),
<<?UINT16(Size), Acc/binary>>;
-
-encode_hello_extensions([#alpn{extension_data = ExtensionData} | Rest], Acc) ->
- Len = byte_size(ExtensionData),
+encode_extensions([#alpn{extension_data = ExtensionData} | Rest], Acc) ->
+ Len = byte_size(ExtensionData),
ExtLen = Len + 2,
- encode_hello_extensions(Rest, <<?UINT16(?ALPN_EXT), ?UINT16(ExtLen), ?UINT16(Len),
- ExtensionData/binary, Acc/binary>>);
-encode_hello_extensions([#next_protocol_negotiation{extension_data = ExtensionData} | Rest], Acc) ->
+ encode_extensions(Rest, <<?UINT16(?ALPN_EXT), ?UINT16(ExtLen), ?UINT16(Len),
+ ExtensionData/binary, Acc/binary>>);
+encode_extensions([#next_protocol_negotiation{extension_data = ExtensionData} | Rest], Acc) ->
Len = byte_size(ExtensionData),
- encode_hello_extensions(Rest, <<?UINT16(?NEXTPROTONEG_EXT), ?UINT16(Len),
+ encode_extensions(Rest, <<?UINT16(?NEXTPROTONEG_EXT), ?UINT16(Len),
ExtensionData/binary, Acc/binary>>);
-encode_hello_extensions([#renegotiation_info{renegotiated_connection = undefined} | Rest], Acc) ->
- encode_hello_extensions(Rest, Acc);
-encode_hello_extensions([#renegotiation_info{renegotiated_connection = ?byte(0) = Info} | Rest], Acc) ->
+encode_extensions([#renegotiation_info{renegotiated_connection = undefined} | Rest], Acc) ->
+ encode_extensions(Rest, Acc);
+encode_extensions([#renegotiation_info{renegotiated_connection = ?byte(0) = Info} | Rest], Acc) ->
Len = byte_size(Info),
- encode_hello_extensions(Rest, <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), Info/binary, Acc/binary>>);
+ encode_extensions(Rest, <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), Info/binary, Acc/binary>>);
-encode_hello_extensions([#renegotiation_info{renegotiated_connection = Info} | Rest], Acc) ->
+encode_extensions([#renegotiation_info{renegotiated_connection = Info} | Rest], Acc) ->
InfoLen = byte_size(Info),
Len = InfoLen +1,
- encode_hello_extensions(Rest, <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), ?BYTE(InfoLen),
+ encode_extensions(Rest, <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), ?BYTE(InfoLen),
Info/binary, Acc/binary>>);
-encode_hello_extensions([#elliptic_curves{elliptic_curve_list = EllipticCurves} | Rest], Acc) ->
+encode_extensions([#elliptic_curves{elliptic_curve_list = EllipticCurves} | Rest], Acc) ->
EllipticCurveList = << <<(tls_v1:oid_to_enum(X)):16>> || X <- EllipticCurves>>,
ListLen = byte_size(EllipticCurveList),
Len = ListLen + 2,
- encode_hello_extensions(Rest, <<?UINT16(?ELLIPTIC_CURVES_EXT),
+ encode_extensions(Rest, <<?UINT16(?ELLIPTIC_CURVES_EXT),
?UINT16(Len), ?UINT16(ListLen), EllipticCurveList/binary, Acc/binary>>);
-encode_hello_extensions([#ec_point_formats{ec_point_format_list = ECPointFormats} | Rest], Acc) ->
+encode_extensions([#supported_groups{supported_groups = SupportedGroups} | Rest], Acc) ->
+
+ SupportedGroupList = << <<(tls_v1:group_to_enum(X)):16>> || X <- SupportedGroups>>,
+ ListLen = byte_size(SupportedGroupList),
+ Len = ListLen + 2,
+ encode_extensions(Rest, <<?UINT16(?ELLIPTIC_CURVES_EXT),
+ ?UINT16(Len), ?UINT16(ListLen),
+ SupportedGroupList/binary, Acc/binary>>);
+encode_extensions([#ec_point_formats{ec_point_format_list = ECPointFormats} | Rest], Acc) ->
ECPointFormatList = list_to_binary(ECPointFormats),
ListLen = byte_size(ECPointFormatList),
Len = ListLen + 1,
- encode_hello_extensions(Rest, <<?UINT16(?EC_POINT_FORMATS_EXT),
+ encode_extensions(Rest, <<?UINT16(?EC_POINT_FORMATS_EXT),
?UINT16(Len), ?BYTE(ListLen), ECPointFormatList/binary, Acc/binary>>);
-encode_hello_extensions([#srp{username = UserName} | Rest], Acc) ->
+encode_extensions([#srp{username = UserName} | Rest], Acc) ->
SRPLen = byte_size(UserName),
- Len = SRPLen + 2,
- encode_hello_extensions(Rest, <<?UINT16(?SRP_EXT), ?UINT16(Len), ?BYTE(SRPLen),
+ Len = SRPLen + 1,
+ encode_extensions(Rest, <<?UINT16(?SRP_EXT), ?UINT16(Len), ?BYTE(SRPLen),
UserName/binary, Acc/binary>>);
-encode_hello_extensions([#hash_sign_algos{hash_sign_algos = HashSignAlgos} | Rest], Acc) ->
+encode_extensions([#hash_sign_algos{hash_sign_algos = HashSignAlgos} | Rest], Acc) ->
SignAlgoList = << <<(ssl_cipher:hash_algorithm(Hash)):8, (ssl_cipher:sign_algorithm(Sign)):8>> ||
{Hash, Sign} <- HashSignAlgos >>,
ListLen = byte_size(SignAlgoList),
Len = ListLen + 2,
- encode_hello_extensions(Rest, <<?UINT16(?SIGNATURE_ALGORITHMS_EXT),
+ encode_extensions(Rest, <<?UINT16(?SIGNATURE_ALGORITHMS_EXT),
?UINT16(Len), ?UINT16(ListLen), SignAlgoList/binary, Acc/binary>>);
-encode_hello_extensions([#sni{hostname = Hostname} | Rest], Acc) ->
+encode_extensions([#signature_algorithms{
+ signature_scheme_list = SignatureSchemes} | Rest], Acc) ->
+ SignSchemeList = << <<(ssl_cipher:signature_scheme(SignatureScheme)):16 >> ||
+ SignatureScheme <- SignatureSchemes >>,
+ ListLen = byte_size(SignSchemeList),
+ Len = ListLen + 2,
+ encode_extensions(Rest, <<?UINT16(?SIGNATURE_ALGORITHMS_EXT),
+ ?UINT16(Len), ?UINT16(ListLen), SignSchemeList/binary, Acc/binary>>);
+encode_extensions([#signature_algorithms_cert{
+ signature_scheme_list = SignatureSchemes} | Rest], Acc) ->
+ SignSchemeList = << <<(ssl_cipher:signature_scheme(SignatureScheme)):16 >> ||
+ SignatureScheme <- SignatureSchemes >>,
+ ListLen = byte_size(SignSchemeList),
+ Len = ListLen + 2,
+ encode_extensions(Rest, <<?UINT16(?SIGNATURE_ALGORITHMS_CERT_EXT),
+ ?UINT16(Len), ?UINT16(ListLen), SignSchemeList/binary, Acc/binary>>);
+encode_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>>).
+ encode_extensions(Rest, <<?UINT16(?SNI_EXT), ?UINT16(ExtLength),
+ ?UINT16(ServerNameLength),
+ ?BYTE(?SNI_NAMETYPE_HOST_NAME),
+ ?UINT16(HostLen), HostnameBin/binary,
+ Acc/binary>>);
+encode_extensions([#client_hello_versions{versions = Versions0} | Rest], Acc) ->
+ Versions = encode_versions(Versions0),
+ VerLen = byte_size(Versions),
+ Len = VerLen + 1,
+ encode_extensions(Rest, <<?UINT16(?SUPPORTED_VERSIONS_EXT),
+ ?UINT16(Len), ?BYTE(VerLen), Versions/binary, Acc/binary>>);
+encode_extensions([#server_hello_selected_version{selected_version = Version0} | Rest], Acc) ->
+ Version = encode_versions([Version0]),
+ Len = byte_size(Version), %% 2
+ encode_extensions(Rest, <<?UINT16(?SUPPORTED_VERSIONS_EXT),
+ ?UINT16(Len), Version/binary, Acc/binary>>);
+encode_extensions([#key_share_client_hello{client_shares = ClientShares0} | Rest], Acc) ->
+ ClientShares = encode_client_shares(ClientShares0),
+ ClientSharesLen = byte_size(ClientShares),
+ Len = ClientSharesLen + 2,
+ encode_extensions(Rest, <<?UINT16(?KEY_SHARE_EXT),
+ ?UINT16(Len), ?UINT16(ClientSharesLen),
+ ClientShares/binary, Acc/binary>>);
+encode_extensions([#key_share_server_hello{server_share = ServerShare0} | Rest], Acc) ->
+ ServerShare = encode_key_share_entry(ServerShare0),
+ Len = byte_size(ServerShare),
+ encode_extensions(Rest, <<?UINT16(?KEY_SHARE_EXT),
+ ?UINT16(Len), ServerShare/binary, Acc/binary>>);
+encode_extensions([#key_share_hello_retry_request{selected_group = Group0} | Rest], Acc) ->
+ Group = tls_v1:group_to_enum(Group0),
+ encode_extensions(Rest, <<?UINT16(?KEY_SHARE_EXT),
+ ?UINT16(2), ?UINT16(Group), Acc/binary>>).
+
encode_client_protocol_negotiation(undefined, _) ->
undefined;
@@ -645,7 +733,7 @@ decode_handshake(_, ?NEXT_PROTOCOL, <<?BYTE(SelectedProtocolLength),
?BYTE(PaddingLength), _Padding:PaddingLength/binary>>) ->
#next_protocol{selected_protocol = SelectedProtocol};
-decode_handshake(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
+decode_handshake(Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SID_length), Session_ID:SID_length/binary,
Cipher_suite:2/binary, ?BYTE(Comp_method)>>) ->
#server_hello{
@@ -654,14 +742,13 @@ decode_handshake(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:3
session_id = Session_ID,
cipher_suite = Cipher_suite,
compression_method = Comp_method,
- extensions = #hello_extensions{}};
+ extensions = empty_extensions(Version, server_hello)};
-decode_handshake(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
+decode_handshake(Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SID_length), Session_ID:SID_length/binary,
Cipher_suite:2/binary, ?BYTE(Comp_method),
?UINT16(ExtLen), Extensions:ExtLen/binary>>) ->
-
- HelloExtensions = decode_hello_extensions(Extensions),
+ HelloExtensions = decode_hello_extensions(Extensions, Version, {Major, Minor}, server_hello),
#server_hello{
server_version = {Major,Minor},
@@ -704,20 +791,52 @@ decode_handshake(_Version, ?FINISHED, VerifyData) ->
decode_handshake(_, Message, _) ->
throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, {unknown_or_malformed_handshake, Message})).
+
+%%--------------------------------------------------------------------
+-spec decode_vector(binary()) -> binary().
+%%
+%% Description: Remove length tag from TLS Vector type. Needed
+%% for client hello when extensions in older versions may be empty.
+%%
+%%--------------------------------------------------------------------
+decode_vector(<<>>) ->
+ <<>>;
+decode_vector(<<?UINT16(Len), Vector:Len/binary>>) ->
+ Vector.
+
%%--------------------------------------------------------------------
--spec decode_hello_extensions({client, binary()} | binary()) -> #hello_extensions{}.
+-spec decode_hello_extensions(binary(), ssl_record:ssl_version(),
+ ssl_record:ssl_version(), atom()) -> map().
%%
%% Description: Decodes TLS hello extensions
%%--------------------------------------------------------------------
-decode_hello_extensions({client, <<>>}) ->
- #hello_extensions{};
-decode_hello_extensions({client, <<?UINT16(ExtLen), Extensions:ExtLen/binary>>}) ->
- decode_hello_extensions(Extensions);
-decode_hello_extensions(Extensions) ->
- dec_hello_extensions(Extensions, #hello_extensions{}).
+decode_hello_extensions(Extensions, LocalVersion, LegacyVersion, MessageType0) ->
+ %% Convert legacy atoms
+ MessageType =
+ case MessageType0 of
+ client -> client_hello;
+ server -> server_hello;
+ T -> T
+ end,
+ %% RFC 8446 - 4.2.1
+ %% Servers MUST be prepared to receive ClientHellos that include this extension but
+ %% do not include 0x0304 in the list of versions.
+ %% Clients MUST check for this extension prior to processing the rest of the
+ %% ServerHello (although they will have to parse the ServerHello in order to read
+ %% the extension).
+ Version = process_supported_versions_extension(Extensions, LocalVersion, LegacyVersion),
+ decode_extensions(Extensions, Version, MessageType, empty_extensions(Version, MessageType)).
%%--------------------------------------------------------------------
--spec decode_server_key(binary(), ssl_cipher:key_algo(), ssl_record:ssl_version()) ->
+-spec decode_extensions(binary(),tuple(), atom()) -> map().
+%%
+%% Description: Decodes TLS hello extensions
+%%--------------------------------------------------------------------
+decode_extensions(Extensions, Version, MessageType) ->
+ decode_extensions(Extensions, Version, MessageType, empty_extensions()).
+
+%%--------------------------------------------------------------------
+-spec decode_server_key(binary(), ssl:kex_algo(), ssl_record:ssl_version()) ->
#server_key_params{}.
%%
%% Description: Decode server_key data and return appropriate type
@@ -726,12 +845,13 @@ decode_server_key(ServerKey, Type, Version) ->
dec_server_key(ServerKey, key_exchange_alg(Type), Version).
%%--------------------------------------------------------------------
--spec decode_client_key(binary(), ssl_cipher:key_algo(), ssl_record:ssl_version()) ->
+-spec decode_client_key(binary(), ssl:kex_algo(), ssl_record:ssl_version()) ->
#encrypted_premaster_secret{}
| #client_diffie_hellman_public{}
| #client_ec_diffie_hellman_public{}
| #client_psk_identity{}
| #client_dhe_psk_identity{}
+ | #client_ecdhe_psk_identity{}
| #client_rsa_psk_identity{}
| #client_srp_public{}.
%%
@@ -759,11 +879,12 @@ available_suites(UserSuites, Version) ->
lists:filtermap(fun(Suite) -> lists:member(Suite, VersionSuites) end, UserSuites).
available_suites(ServerCert, UserSuites, Version, undefined, Curve) ->
- ssl_cipher:filter(ServerCert, available_suites(UserSuites, Version))
- -- unavailable_ecc_suites(Curve);
+ Suites = ssl_cipher:filter(ServerCert, available_suites(UserSuites, Version), Version),
+ filter_unavailable_ecc_suites(Curve, Suites);
available_suites(ServerCert, UserSuites, Version, HashSigns, Curve) ->
Suites = available_suites(ServerCert, UserSuites, Version, undefined, Curve),
- filter_hashsigns(Suites, [ssl_cipher:suite_definition(Suite) || Suite <- Suites], HashSigns, []).
+ filter_hashsigns(Suites, [ssl_cipher_format:suite_bin_to_map(Suite) || Suite <- Suites], HashSigns,
+ Version, []).
available_signature_algs(undefined, _) ->
undefined;
@@ -801,7 +922,7 @@ prf({3,0}, _, _, _, _, _) ->
prf({3,_N}, PRFAlgo, Secret, Label, Seed, WantedLength) ->
{ok, tls_v1:prf(PRFAlgo, Secret, Label, Seed, WantedLength)}.
-select_session(SuggestedSessionId, CipherSuites, HashSigns, Compressions, Port, #session{ecc = ECCCurve} =
+select_session(SuggestedSessionId, CipherSuites, HashSigns, Compressions, Port, #session{ecc = ECCCurve0} =
Session, Version,
#ssl_options{ciphers = UserSuites, honor_cipher_order = HonorCipherOrder} = SslOpts,
Cache, CacheCb, Cert) ->
@@ -810,10 +931,12 @@ select_session(SuggestedSessionId, CipherSuites, HashSigns, Compressions, Port,
Cache, CacheCb),
case Resumed of
undefined ->
- Suites = available_suites(Cert, UserSuites, Version, HashSigns, ECCCurve),
- CipherSuite = select_cipher_suite(CipherSuites, Suites, HonorCipherOrder),
+ Suites = available_suites(Cert, UserSuites, Version, HashSigns, ECCCurve0),
+ CipherSuite0 = select_cipher_suite(CipherSuites, Suites, HonorCipherOrder),
+ {ECCCurve, CipherSuite} = cert_curve(Cert, ECCCurve0, CipherSuite0),
Compression = select_compression(Compressions),
{new, Session#session{session_id = SessionId,
+ ecc = ECCCurve,
cipher_suite = CipherSuite,
compression_method = Compression}};
_ ->
@@ -842,22 +965,24 @@ premaster_secret(PublicDhKey, PrivateDhKey, #server_dh_params{dh_p = Prime, dh_g
end;
premaster_secret(#client_srp_public{srp_a = ClientPublicKey}, ServerKey, #srp_user{prime = Prime,
verifier = Verifier}) ->
- case crypto:compute_key(srp, ClientPublicKey, ServerKey, {host, [Verifier, Prime, '6a']}) of
- error ->
- throw(?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER));
+ try crypto:compute_key(srp, ClientPublicKey, ServerKey, {host, [Verifier, Prime, '6a']}) of
PremasterSecret ->
PremasterSecret
+ catch
+ error:_ ->
+ throw(?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER))
end;
premaster_secret(#server_srp_params{srp_n = Prime, srp_g = Generator, srp_s = Salt, srp_b = Public},
ClientKeys, {Username, Password}) ->
case ssl_srp_primes:check_srp_params(Generator, Prime) of
ok ->
DerivedKey = crypto:hash(sha, [Salt, crypto:hash(sha, [Username, <<$:>>, Password])]),
- case crypto:compute_key(srp, Public, ClientKeys, {user, [DerivedKey, Prime, Generator, '6a']}) of
- error ->
- throw(?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER));
+ try crypto:compute_key(srp, Public, ClientKeys, {user, [DerivedKey, Prime, Generator, '6a']}) of
PremasterSecret ->
PremasterSecret
+ catch
+ error ->
+ throw(?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER))
end;
_ ->
throw(?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER))
@@ -875,9 +1000,21 @@ premaster_secret(#server_dhe_psk_params{
LookupFun) ->
PremasterSecret = premaster_secret(PublicDhKey, PrivateDhKey, Params),
psk_secret(IdentityHint, LookupFun, PremasterSecret);
+premaster_secret(#server_ecdhe_psk_params{
+ hint = IdentityHint,
+ dh_params = #server_ecdh_params{
+ public = ECServerPubKey}},
+ PrivateEcDhKey,
+ LookupFun) ->
+ PremasterSecret = premaster_secret(#'ECPoint'{point = ECServerPubKey}, PrivateEcDhKey),
+ psk_secret(IdentityHint, LookupFun, PremasterSecret);
premaster_secret({rsa_psk, PSKIdentity}, PSKLookup, RSAPremasterSecret) ->
- psk_secret(PSKIdentity, PSKLookup, RSAPremasterSecret).
-
+ psk_secret(PSKIdentity, PSKLookup, RSAPremasterSecret);
+premaster_secret(#client_ecdhe_psk_identity{
+ identity = PSKIdentity,
+ dh_public = PublicEcDhPoint}, PrivateEcDhKey, PSKLookup) ->
+ PremasterSecret = premaster_secret(#'ECPoint'{point = PublicEcDhPoint}, PrivateEcDhKey),
+ psk_secret(PSKIdentity, PSKLookup, PremasterSecret).
premaster_secret(#client_dhe_psk_identity{
identity = PSKIdentity,
dh_public = PublicDhKey}, PrivateKey, #'DHParameter'{} = Params, PSKLookup) ->
@@ -895,102 +1032,229 @@ premaster_secret(EncSecret, #'RSAPrivateKey'{} = RSAPrivateKey) ->
catch
_:_ ->
throw(?ALERT_REC(?FATAL, ?DECRYPT_ERROR))
+ end;
+premaster_secret(EncSecret, #{algorithm := rsa} = Engine) ->
+ try crypto:private_decrypt(rsa, EncSecret, maps:remove(algorithm, Engine),
+ [{rsa_pad, rsa_pkcs1_padding}])
+ catch
+ _:_ ->
+ throw(?ALERT_REC(?FATAL, ?DECRYPT_ERROR))
end.
%%====================================================================
%% Extensions handling
%%====================================================================
-client_hello_extensions(Version, CipherSuites,
- #ssl_options{signature_algs = SupportedHashSigns,
- eccs = SupportedECCs} = SslOpts, ConnectionStates, Renegotiation) ->
- {EcPointFormats, EllipticCurves} =
- case advertises_ec_ciphers(lists:map(fun ssl_cipher:suite_definition/1, CipherSuites)) of
- true ->
- client_ecc_extensions(SupportedECCs);
- false ->
- {undefined, undefined}
- end,
+client_hello_extensions(Version, CipherSuites, SslOpts, ConnectionStates, Renegotiation, KeyShare) ->
+ HelloExtensions0 = add_tls12_extensions(Version, SslOpts, ConnectionStates, Renegotiation),
+ HelloExtensions1 = add_common_extensions(Version, HelloExtensions0, CipherSuites, SslOpts),
+ maybe_add_tls13_extensions(Version, HelloExtensions1, SslOpts, KeyShare).
+
+
+add_tls12_extensions(_Version,
+ SslOpts,
+ ConnectionStates,
+ Renegotiation) ->
SRP = srp_user(SslOpts),
+ #{renegotiation_info => renegotiation_info(tls_record, client,
+ ConnectionStates, Renegotiation),
+ srp => SRP,
+ alpn => encode_alpn(SslOpts#ssl_options.alpn_advertised_protocols, Renegotiation),
+ next_protocol_negotiation =>
+ encode_client_protocol_negotiation(SslOpts#ssl_options.next_protocol_selector,
+ Renegotiation),
+ sni => sni(SslOpts#ssl_options.server_name_indication)
+ }.
+
- #hello_extensions{
- renegotiation_info = renegotiation_info(tls_record, client,
- ConnectionStates, Renegotiation),
- srp = SRP,
- signature_algs = available_signature_algs(SupportedHashSigns, Version),
- ec_point_formats = EcPointFormats,
- elliptic_curves = EllipticCurves,
- alpn = encode_alpn(SslOpts#ssl_options.alpn_advertised_protocols, Renegotiation),
- next_protocol_negotiation =
- encode_client_protocol_negotiation(SslOpts#ssl_options.next_protocol_selector,
- Renegotiation),
- sni = sni(SslOpts#ssl_options.server_name_indication)}.
+add_common_extensions({3,4},
+ HelloExtensions,
+ _CipherSuites,
+ #ssl_options{eccs = SupportedECCs,
+ supported_groups = Groups,
+ signature_algs = SignatureSchemes}) ->
+ {EcPointFormats, _} =
+ client_ecc_extensions(SupportedECCs),
+ HelloExtensions#{ec_point_formats => EcPointFormats,
+ elliptic_curves => Groups,
+ signature_algs => signature_algs_ext(SignatureSchemes)};
+
+add_common_extensions(Version,
+ HelloExtensions,
+ CipherSuites,
+ #ssl_options{eccs = SupportedECCs,
+ signature_algs = SupportedHashSigns}) ->
+
+ {EcPointFormats, EllipticCurves} =
+ case advertises_ec_ciphers(
+ lists:map(fun ssl_cipher_format:suite_bin_to_map/1,
+ CipherSuites)) of
+ true ->
+ client_ecc_extensions(SupportedECCs);
+ false ->
+ {undefined, undefined}
+ end,
+ HelloExtensions#{ec_point_formats => EcPointFormats,
+ elliptic_curves => EllipticCurves,
+ signature_algs => available_signature_algs(SupportedHashSigns, Version)}.
+
+
+maybe_add_tls13_extensions({3,4},
+ HelloExtensions0,
+ #ssl_options{signature_algs_cert = SignatureSchemes,
+ versions = SupportedVersions},
+ KeyShare) ->
+ HelloExtensions =
+ HelloExtensions0#{client_hello_versions =>
+ #client_hello_versions{versions = SupportedVersions},
+ signature_algs_cert =>
+ signature_algs_cert(SignatureSchemes)},
+ maybe_add_key_share(HelloExtensions, KeyShare);
+maybe_add_tls13_extensions(_, HelloExtensions, _, _) ->
+ HelloExtensions.
+
+
+%% TODO: Add support for PSK key establishment
+
+%% RFC 8446 (TLS 1.3) - 4.2.8. Key Share
+%%
+%% 4.2.8.1. Diffie-Hellman Parameters
+%% Diffie-Hellman [DH76] parameters for both clients and servers are
+%% encoded in the opaque key_exchange field of a KeyShareEntry in a
+%% KeyShare structure. The opaque value contains the Diffie-Hellman
+%% public value (Y = g^X mod p) for the specified group (see [RFC7919]
+%% for group definitions) encoded as a big-endian integer and padded to
+%% the left with zeros to the size of p in bytes.
+%%
+%% 4.2.8.2. ECDHE Parameters
+%%
+%% ECDHE parameters for both clients and servers are encoded in the
+%% opaque key_exchange field of a KeyShareEntry in a KeyShare structure.
+%%
+%% For secp256r1, secp384r1, and secp521r1, the contents are the
+%% serialized value of the following struct:
+%%
+%% struct {
+%% uint8 legacy_form = 4;
+%% opaque X[coordinate_length];
+%% opaque Y[coordinate_length];
+%% } UncompressedPointRepresentation;
+%%
+%% X and Y, respectively, are the binary representations of the x and y
+%% values in network byte order. There are no internal length markers,
+%% so each number representation occupies as many octets as implied by
+%% the curve parameters. For P-256, this means that each of X and Y use
+%% 32 octets, padded on the left by zeros if necessary. For P-384, they
+%% take 48 octets each. For P-521, they take 66 octets each.
+maybe_add_key_share(HelloExtensions, undefined) ->
+ HelloExtensions;
+maybe_add_key_share(HelloExtensions, KeyShare) ->
+ #key_share_client_hello{client_shares = ClientShares0} = KeyShare,
+ %% Keep only public keys
+ ClientShares = lists:map(fun kse_remove_private_key/1, ClientShares0),
+ HelloExtensions#{key_share => #key_share_client_hello{
+ client_shares = ClientShares}}.
+
+add_server_share(server_hello, Extensions, KeyShare) ->
+ #key_share_server_hello{server_share = ServerShare0} = KeyShare,
+ %% Keep only public keys
+ ServerShare = kse_remove_private_key(ServerShare0),
+ Extensions#{key_share => #key_share_server_hello{
+ server_share = ServerShare}};
+add_server_share(hello_retry_request, Extensions,
+ #key_share_server_hello{
+ server_share = #key_share_entry{group = Group}}) ->
+ Extensions#{key_share => #key_share_hello_retry_request{
+ selected_group = Group}}.
+
+
+kse_remove_private_key(#key_share_entry{
+ group = Group,
+ key_exchange =
+ #'ECPrivateKey'{publicKey = PublicKey}}) ->
+ #key_share_entry{
+ group = Group,
+ key_exchange = PublicKey};
+kse_remove_private_key(#key_share_entry{
+ group = Group,
+ key_exchange =
+ {PublicKey, _}}) ->
+ #key_share_entry{
+ group = Group,
+ key_exchange = PublicKey}.
+
+signature_algs_ext(undefined) ->
+ undefined;
+signature_algs_ext(SignatureSchemes0) ->
+ %% The SSL option signature_algs contains both hash-sign algorithms (tuples) and
+ %% signature schemes (atoms) if TLS 1.3 is configured.
+ %% Filter out all hash-sign tuples when creating the signature_algs extension.
+ %% (TLS 1.3 specific record type)
+ SignatureSchemes = lists:filter(fun is_atom/1, SignatureSchemes0),
+ #signature_algorithms{signature_scheme_list = SignatureSchemes}.
+
+signature_algs_cert(undefined) ->
+ undefined;
+signature_algs_cert(SignatureSchemes) ->
+ #signature_algorithms_cert{signature_scheme_list = SignatureSchemes}.
handle_client_hello_extensions(RecordCB, Random, ClientCipherSuites,
- #hello_extensions{renegotiation_info = Info,
- srp = SRP,
- ec_point_formats = ECCFormat,
- alpn = ALPN,
- next_protocol_negotiation = NextProtocolNegotiation}, Version,
+ Exts, Version,
#ssl_options{secure_renegotiate = SecureRenegotation,
alpn_preferred_protocols = ALPNPreferredProtocols} = Opts,
#session{cipher_suite = NegotiatedCipherSuite,
compression_method = Compression} = Session0,
ConnectionStates0, Renegotiation) ->
- Session = handle_srp_extension(SRP, Session0),
- ConnectionStates = handle_renegotiation_extension(server, RecordCB, Version, Info,
+ Session = handle_srp_extension(maps:get(srp, Exts, undefined), Session0),
+ ConnectionStates = handle_renegotiation_extension(server, RecordCB, Version, maps:get(renegotiation_info, Exts, undefined),
Random, NegotiatedCipherSuite,
ClientCipherSuites, Compression,
ConnectionStates0, Renegotiation, SecureRenegotation),
- ServerHelloExtensions = #hello_extensions{
- renegotiation_info = renegotiation_info(RecordCB, server,
- ConnectionStates, Renegotiation),
- ec_point_formats = server_ecc_extension(Version, ECCFormat)
- },
-
+ Empty = empty_extensions(Version, server_hello),
+ ServerHelloExtensions = Empty#{renegotiation_info => renegotiation_info(RecordCB, server,
+ ConnectionStates, Renegotiation),
+ ec_point_formats => server_ecc_extension(Version,
+ maps:get(ec_point_formats, Exts, undefined))
+ },
+
%% If we receive an ALPN extension and have ALPN configured for this connection,
%% we handle it. Otherwise we check for the NPN extension.
+ ALPN = maps:get(alpn, Exts, undefined),
if
ALPN =/= undefined, ALPNPreferredProtocols =/= undefined ->
- case handle_alpn_extension(ALPNPreferredProtocols, decode_alpn(ALPN)) of
- #alert{} = Alert ->
- Alert;
- Protocol ->
- {Session, ConnectionStates, Protocol,
- ServerHelloExtensions#hello_extensions{alpn=encode_alpn([Protocol], Renegotiation)}}
- end;
+ Protocol = handle_alpn_extension(ALPNPreferredProtocols, decode_alpn(ALPN)),
+ {Session, ConnectionStates, Protocol,
+ ServerHelloExtensions#{alpn => encode_alpn([Protocol], Renegotiation)}};
true ->
+ NextProtocolNegotiation = maps:get(next_protocol_negotiation, Exts, undefined),
ProtocolsToAdvertise = handle_next_protocol_extension(NextProtocolNegotiation, Renegotiation, Opts),
{Session, ConnectionStates, undefined,
- ServerHelloExtensions#hello_extensions{next_protocol_negotiation=
- encode_protocols_advertised_on_server(ProtocolsToAdvertise)}}
+ ServerHelloExtensions#{next_protocol_negotiation =>
+ encode_protocols_advertised_on_server(ProtocolsToAdvertise)}}
end.
handle_server_hello_extensions(RecordCB, Random, CipherSuite, Compression,
- #hello_extensions{renegotiation_info = Info,
- alpn = ALPN,
- next_protocol_negotiation = NextProtocolNegotiation}, Version,
+ Exts, Version,
#ssl_options{secure_renegotiate = SecureRenegotation,
next_protocol_selector = NextProtoSelector},
ConnectionStates0, Renegotiation) ->
- ConnectionStates = handle_renegotiation_extension(client, RecordCB, Version, Info, Random,
+ ConnectionStates = handle_renegotiation_extension(client, RecordCB, Version,
+ maps:get(renegotiation_info, Exts, undefined), Random,
CipherSuite, undefined,
Compression, ConnectionStates0,
Renegotiation, SecureRenegotation),
%% If we receive an ALPN extension then this is the protocol selected,
%% otherwise handle the NPN extension.
+ ALPN = maps:get(alpn, Exts, undefined),
case decode_alpn(ALPN) of
%% ServerHello contains exactly one protocol: the one selected.
%% We also ignore the ALPN extension during renegotiation (see encode_alpn/2).
[Protocol] when not Renegotiation ->
{ConnectionStates, alpn, Protocol};
undefined ->
- case handle_next_protocol(NextProtocolNegotiation, NextProtoSelector, Renegotiation) of
- #alert{} = Alert ->
- Alert;
- Protocol ->
- {ConnectionStates, npn, Protocol}
- end;
+ NextProtocolNegotiation = maps:get(next_protocol_negotiation, Exts, undefined),
+ Protocol = handle_next_protocol(NextProtocolNegotiation, NextProtoSelector, Renegotiation),
+ {ConnectionStates, npn, Protocol};
{error, Reason} ->
?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, Reason);
[] ->
@@ -1026,33 +1290,57 @@ select_curve(undefined, _, _) ->
%%--------------------------------------------------------------------
select_hashsign(_, _, KeyExAlgo, _, _Version) when KeyExAlgo == dh_anon;
KeyExAlgo == ecdh_anon;
- KeyExAlgo == srp_anon ->
+ KeyExAlgo == srp_anon;
+ KeyExAlgo == psk;
+ KeyExAlgo == dhe_psk;
+ KeyExAlgo == ecdhe_psk ->
{null, anon};
%% The signature_algorithms extension was introduced with TLS 1.2. Ignore it if we have
%% negotiated a lower version.
-select_hashsign(HashSigns, Cert, KeyExAlgo,
- undefined, {Major, Minor} = Version) when Major >= 3 andalso Minor >= 3->
- select_hashsign(HashSigns, Cert, KeyExAlgo, tls_v1:default_signature_algs(Version), Version);
-select_hashsign(#hash_sign_algos{hash_sign_algos = HashSigns}, Cert, KeyExAlgo, SupportedHashSigns,
- {Major, Minor}) when Major >= 3 andalso Minor >= 3 ->
- #'OTPCertificate'{tbsCertificate = TBSCert,
- signatureAlgorithm = {_,SignAlgo, _}} = public_key:pkix_decode_cert(Cert, otp),
- #'OTPSubjectPublicKeyInfo'{algorithm = {_, SubjAlgo, _}} =
- TBSCert#'OTPTBSCertificate'.subjectPublicKeyInfo,
-
- Sign = sign_algo(SignAlgo),
- SubSing = sign_algo(SubjAlgo),
-
- case lists:filter(fun({_, S} = Algos) when S == Sign ->
- is_acceptable_hash_sign(Algos, Sign,
- SubSing, KeyExAlgo, SupportedHashSigns);
- (_) ->
- false
- end, HashSigns) of
- [] ->
- ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_signature_algorithm);
- [HashSign | _] ->
- HashSign
+select_hashsign({ClientHashSigns, ClientSignatureSchemes},
+ Cert, KeyExAlgo, undefined, {Major, Minor} = Version)
+ when Major >= 3 andalso Minor >= 3->
+ select_hashsign({ClientHashSigns, ClientSignatureSchemes}, Cert, KeyExAlgo,
+ tls_v1:default_signature_algs(Version), Version);
+select_hashsign({#hash_sign_algos{hash_sign_algos = ClientHashSigns},
+ ClientSignatureSchemes0},
+ Cert, KeyExAlgo, SupportedHashSigns, {Major, Minor})
+ when Major >= 3 andalso Minor >= 3 ->
+ ClientSignatureSchemes = get_signature_scheme(ClientSignatureSchemes0),
+ {SignAlgo0, Param, PublicKeyAlgo0} = get_cert_params(Cert),
+ SignAlgo = sign_algo(SignAlgo0),
+ PublicKeyAlgo = public_key_algo(PublicKeyAlgo0),
+
+ %% RFC 5246 (TLS 1.2)
+ %% If the client provided a "signature_algorithms" extension, then all
+ %% certificates provided by the server MUST be signed by a
+ %% hash/signature algorithm pair that appears in that extension.
+ %%
+ %% RFC 8446 (TLS 1.3)
+ %% TLS 1.3 provides two extensions for indicating which signature
+ %% algorithms may be used in digital signatures. The
+ %% "signature_algorithms_cert" extension applies to signatures in
+ %% certificates and the "signature_algorithms" extension, which
+ %% originally appeared in TLS 1.2, applies to signatures in
+ %% CertificateVerify messages.
+ %%
+ %% If no "signature_algorithms_cert" extension is
+ %% present, then the "signature_algorithms" extension also applies to
+ %% signatures appearing in certificates.
+ case is_supported_sign(SignAlgo, Param, ClientHashSigns, ClientSignatureSchemes) of
+ true ->
+ case lists:filter(fun({_, S} = Algos) when S == PublicKeyAlgo ->
+ is_acceptable_hash_sign(Algos, KeyExAlgo, SupportedHashSigns);
+ (_) ->
+ false
+ end, ClientHashSigns) of
+ [] ->
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_signature_algorithm);
+ [HashSign | _] ->
+ HashSign
+ end;
+ false ->
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_signature_algorithm)
end;
select_hashsign(_, Cert, _, _, Version) ->
#'OTPCertificate'{tbsCertificate = TBSCert} = public_key:pkix_decode_cert(Cert, otp),
@@ -1066,27 +1354,23 @@ select_hashsign(_, Cert, _, _, Version) ->
%%
%% Description: Handles signature algorithms selection for certificate requests (client)
%%--------------------------------------------------------------------
-select_hashsign(#certificate_request{}, undefined, _, {Major, Minor}) when Major >= 3 andalso Minor >= 3->
- %% There client does not have a certificate and will send an empty reply, the server may fail
- %% or accept the connection by its own preference. No signature algorihms needed as there is
- %% no certificate to verify.
- {undefined, undefined};
-
-select_hashsign(#certificate_request{hashsign_algorithms = #hash_sign_algos{hash_sign_algos = HashSigns},
- certificate_types = Types}, Cert, SupportedHashSigns,
+select_hashsign(#certificate_request{
+ hashsign_algorithms = #hash_sign_algos{
+ hash_sign_algos = HashSigns},
+ certificate_types = Types},
+ Cert,
+ SupportedHashSigns,
{Major, Minor}) when Major >= 3 andalso Minor >= 3->
- #'OTPCertificate'{tbsCertificate = TBSCert} = public_key:pkix_decode_cert(Cert, otp),
- #'OTPCertificate'{tbsCertificate = TBSCert,
- signatureAlgorithm = {_,SignAlgo, _}} = public_key:pkix_decode_cert(Cert, otp),
- #'OTPSubjectPublicKeyInfo'{algorithm = {_, SubjAlgo, _}} =
- TBSCert#'OTPTBSCertificate'.subjectPublicKeyInfo,
-
- Sign = sign_algo(SignAlgo),
- SubSign = sign_algo(SubjAlgo),
-
- case is_acceptable_cert_type(SubSign, HashSigns, Types) andalso is_supported_sign(Sign, HashSigns) of
+ {SignAlgo0, Param, PublicKeyAlgo0} = get_cert_params(Cert),
+ SignAlgo = sign_algo(SignAlgo0),
+ PublicKeyAlgo = public_key_algo(PublicKeyAlgo0),
+
+ case is_acceptable_cert_type(PublicKeyAlgo, Types) andalso
+ %% certificate_request has no "signature_algorithms_cert"
+ %% extension in TLS 1.2.
+ is_supported_sign(SignAlgo, Param, HashSigns, undefined) of
true ->
- case lists:filter(fun({_, S} = Algos) when S == SubSign ->
+ case lists:filter(fun({_, S} = Algos) when S == PublicKeyAlgo ->
is_acceptable_hash_sign(Algos, SupportedHashSigns);
(_) ->
false
@@ -1099,8 +1383,38 @@ select_hashsign(#certificate_request{hashsign_algorithms = #hash_sign_algos{hash
false ->
?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_signature_algorithm)
end;
-select_hashsign(#certificate_request{}, Cert, _, Version) ->
- select_hashsign(undefined, Cert, undefined, [], Version).
+select_hashsign(#certificate_request{certificate_types = Types}, Cert, _, Version) ->
+ {_, _, PublicKeyAlgo0} = get_cert_params(Cert),
+ PublicKeyAlgo = public_key_algo(PublicKeyAlgo0),
+
+ %% Check cert even for TLS 1.0/1.1
+ case is_acceptable_cert_type(PublicKeyAlgo, Types) of
+ true ->
+ select_hashsign(undefined, Cert, undefined, [], Version);
+ false ->
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_signature_algorithm)
+ end.
+
+
+%% Gets the relevant parameters of a certificate:
+%% - signature algorithm
+%% - parameters of the signature algorithm
+%% - public key algorithm (key type)
+get_cert_params(Cert) ->
+ #'OTPCertificate'{tbsCertificate = TBSCert,
+ signatureAlgorithm =
+ {_,SignAlgo, Param}} = public_key:pkix_decode_cert(Cert, otp),
+ #'OTPSubjectPublicKeyInfo'{algorithm = {_, PublicKeyAlgo, _}} =
+ TBSCert#'OTPTBSCertificate'.subjectPublicKeyInfo,
+ {SignAlgo, Param, PublicKeyAlgo}.
+
+
+get_signature_scheme(undefined) ->
+ undefined;
+get_signature_scheme(#signature_algorithms_cert{
+ signature_scheme_list = ClientSignatureSchemes}) ->
+ ClientSignatureSchemes.
+
%%--------------------------------------------------------------------
-spec select_hashsign_algs({atom(), atom()}| undefined, oid(), ssl_record:ssl_version()) ->
@@ -1136,12 +1450,32 @@ select_hashsign_algs(undefined, ?rsaEncryption, _) ->
select_hashsign_algs(undefined, ?'id-dsa', _) ->
{sha, dsa}.
-
srp_user(#ssl_options{srp_identity = {UserName, _}}) ->
#srp{username = UserName};
srp_user(_) ->
undefined.
+extension_value(undefined) ->
+ undefined;
+extension_value(#sni{hostname = HostName}) ->
+ HostName;
+extension_value(#ec_point_formats{ec_point_format_list = List}) ->
+ List;
+extension_value(#elliptic_curves{elliptic_curve_list = List}) ->
+ List;
+extension_value(#supported_groups{supported_groups = SupportedGroups}) ->
+ SupportedGroups;
+extension_value(#hash_sign_algos{hash_sign_algos = Algos}) ->
+ Algos;
+extension_value(#alpn{extension_data = Data}) ->
+ Data;
+extension_value(#next_protocol_negotiation{extension_data = Data}) ->
+ Data;
+extension_value(#srp{username = Name}) ->
+ Name;
+extension_value(#renegotiation_info{renegotiated_connection = Data}) ->
+ Data.
+
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
@@ -1151,34 +1485,30 @@ int_to_bin(I) ->
L = (length(integer_to_list(I, 16)) + 1) div 2,
<<I:(L*8)>>.
-certificate_types(_, {N, M}) when N >= 3 andalso M >= 3 ->
- case proplists:get_bool(ecdsa,
- proplists:get_value(public_keys, crypto:supports())) of
- true ->
- <<?BYTE(?ECDSA_SIGN), ?BYTE(?RSA_SIGN), ?BYTE(?DSS_SIGN)>>;
- false ->
- <<?BYTE(?RSA_SIGN), ?BYTE(?DSS_SIGN)>>
- end;
-
-certificate_types(#{key_exchange := KeyExchange}, _) when KeyExchange == rsa;
- KeyExchange == dh_rsa;
- KeyExchange == dhe_rsa;
- KeyExchange == ecdhe_rsa ->
- <<?BYTE(?RSA_SIGN)>>;
-
-certificate_types(#{key_exchange := KeyExchange}, _) when KeyExchange == dh_dss;
- KeyExchange == dhe_dss;
- KeyExchange == srp_dss ->
- <<?BYTE(?DSS_SIGN)>>;
-
-certificate_types(#{key_exchange := KeyExchange}, _) when KeyExchange == dh_ecdsa;
- KeyExchange == dhe_ecdsa;
- KeyExchange == ecdh_ecdsa;
- KeyExchange == ecdhe_ecdsa ->
- <<?BYTE(?ECDSA_SIGN)>>;
-
+%% TLS 1.0+
+%% The end-entity certificate provided by the client MUST contain a
+%% key that is compatible with certificate_types.
+certificate_types(_, {N, M}) when N >= 3 andalso M >= 1 ->
+ ECDSA = supported_cert_type_or_empty(ecdsa, ?ECDSA_SIGN),
+ RSA = supported_cert_type_or_empty(rsa, ?RSA_SIGN),
+ DSS = supported_cert_type_or_empty(dss, ?DSS_SIGN),
+ <<ECDSA/binary,RSA/binary,DSS/binary>>;
+%% SSL 3.0
certificate_types(_, _) ->
- <<?BYTE(?RSA_SIGN)>>.
+ RSA = supported_cert_type_or_empty(rsa, ?RSA_SIGN),
+ DSS = supported_cert_type_or_empty(dss, ?DSS_SIGN),
+ <<RSA/binary,DSS/binary>>.
+
+%% Returns encoded certificate_type if algorithm is supported
+supported_cert_type_or_empty(Algo, Type) ->
+ case proplists:get_bool(
+ Algo,
+ proplists:get_value(public_keys, crypto:supports())) of
+ true ->
+ <<?BYTE(Type)>>;
+ false ->
+ <<>>
+ end.
certificate_authorities(CertDbHandle, CertDbRef) ->
Authorities = certificate_authorities_from_db(CertDbHandle, CertDbRef),
@@ -1204,7 +1534,7 @@ certificate_authorities_from_db(_CertDbHandle, {extracted, CertDbData}) ->
%%-------------Handle handshake messages --------------------------------
validation_fun_and_state({Fun, UserState0}, Role, CertDbHandle, CertDbRef,
- ServerNameIndication, CRLCheck, CRLDbHandle, CertPath) ->
+ ServerNameIndication, CustomizeHostCheck, CRLCheck, CRLDbHandle, CertPath) ->
{fun(OtpCert, {extension, _} = Extension, {SslState, UserState}) ->
case ssl_certificate:validate(OtpCert,
Extension,
@@ -1221,9 +1551,9 @@ validation_fun_and_state({Fun, UserState0}, Role, CertDbHandle, CertDbRef,
(OtpCert, VerifyResult, {SslState, UserState}) ->
apply_user_fun(Fun, OtpCert, VerifyResult, UserState,
SslState, CertPath)
- end, {{Role, CertDbHandle, CertDbRef, ServerNameIndication, CRLCheck, CRLDbHandle}, UserState0}};
+ end, {{Role, CertDbHandle, CertDbRef, {ServerNameIndication, CustomizeHostCheck}, CRLCheck, CRLDbHandle}, UserState0}};
validation_fun_and_state(undefined, Role, CertDbHandle, CertDbRef,
- ServerNameIndication, CRLCheck, CRLDbHandle, CertPath) ->
+ ServerNameIndication, CustomizeHostCheck, CRLCheck, CRLDbHandle, CertPath) ->
{fun(OtpCert, {extension, _} = Extension, SslState) ->
ssl_certificate:validate(OtpCert,
Extension,
@@ -1243,7 +1573,7 @@ validation_fun_and_state(undefined, Role, CertDbHandle, CertDbRef,
ssl_certificate:validate(OtpCert,
VerifyResult,
SslState)
- end, {Role, CertDbHandle, CertDbRef, ServerNameIndication, CRLCheck, CRLDbHandle}}.
+ end, {Role, CertDbHandle, CertDbRef, {ServerNameIndication, CustomizeHostCheck}, CRLCheck, CRLDbHandle}}.
apply_user_fun(Fun, OtpCert, VerifyResult, UserState0,
{_, CertDbHandle, CertDbRef, _, CRLCheck, CRLDbHandle} = SslState, CertPath) when
@@ -1270,6 +1600,45 @@ apply_user_fun(Fun, OtpCert, ExtensionOrError, UserState0, SslState, _CertPath)
{unknown, {SslState, UserState}}
end.
+handle_path_validation_error({bad_cert, unknown_ca} = Reason, PeerCert, Chain,
+ Opts, Options, CertDbHandle, CertsDbRef) ->
+ handle_incomplete_chain(PeerCert, Chain, Opts, Options, CertDbHandle, CertsDbRef, Reason);
+handle_path_validation_error({bad_cert, invalid_issuer} = Reason, PeerCert, Chain0,
+ Opts, Options, CertDbHandle, CertsDbRef) ->
+ case ssl_certificate:certificate_chain(PeerCert, CertDbHandle, CertsDbRef, Chain0) of
+ {ok, _, [PeerCert | Chain] = OrdedChain} when Chain =/= Chain0 -> %% Chain appaears to be unorded
+ {Trusted, Path} = ssl_certificate:trusted_cert_and_path(OrdedChain,
+ CertDbHandle, CertsDbRef,
+ Opts#ssl_options.partial_chain),
+ case public_key:pkix_path_validation(Trusted, Path, Options) of
+ {ok, {PublicKeyInfo,_}} ->
+ {PeerCert, PublicKeyInfo};
+ {error, PathError} ->
+ handle_path_validation_error(PathError, PeerCert, Path,
+ Opts, Options, CertDbHandle, CertsDbRef)
+ end;
+ _ ->
+ path_validation_alert(Reason)
+ end;
+handle_path_validation_error(Reason, _, _, _, _,_, _) ->
+ path_validation_alert(Reason).
+
+handle_incomplete_chain(PeerCert, Chain0, Opts, Options, CertDbHandle, CertsDbRef, PathError0) ->
+ case ssl_certificate:certificate_chain(PeerCert, CertDbHandle, CertsDbRef) of
+ {ok, _, [PeerCert | _] = Chain} when Chain =/= Chain0 -> %% Chain candidate found
+ {Trusted, Path} = ssl_certificate:trusted_cert_and_path(Chain,
+ CertDbHandle, CertsDbRef,
+ Opts#ssl_options.partial_chain),
+ case public_key:pkix_path_validation(Trusted, Path, Options) of
+ {ok, {PublicKeyInfo,_}} ->
+ {PeerCert, PublicKeyInfo};
+ {error, PathError} ->
+ path_validation_alert(PathError)
+ end;
+ _ ->
+ path_validation_alert(PathError0)
+ end.
+
path_validation_alert({bad_cert, cert_expired}) ->
?ALERT_REC(?FATAL, ?CERTIFICATE_EXPIRED);
path_validation_alert({bad_cert, invalid_issuer}) ->
@@ -1282,8 +1651,6 @@ path_validation_alert({bad_cert, unknown_critical_extension}) ->
?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE);
path_validation_alert({bad_cert, {revoked, _}}) ->
?ALERT_REC(?FATAL, ?CERTIFICATE_REVOKED);
-%%path_validation_alert({bad_cert, revocation_status_undetermined}) ->
-%% ?ALERT_REC(?FATAL, ?BAD_CERTIFICATE);
path_validation_alert({bad_cert, {revocation_status_undetermined, Details}}) ->
Alert = ?ALERT_REC(?FATAL, ?BAD_CERTIFICATE),
Alert#alert{reason = Details};
@@ -1573,6 +1940,18 @@ encode_server_key(#server_dhe_psk_params{
YLen = byte_size(Y),
<<?UINT16(Len), PskIdentityHint/binary,
?UINT16(PLen), P/binary, ?UINT16(GLen), G/binary, ?UINT16(YLen), Y/binary>>;
+encode_server_key(Params = #server_ecdhe_psk_params{hint = undefined}) ->
+ encode_server_key(Params#server_ecdhe_psk_params{hint = <<>>});
+encode_server_key(#server_ecdhe_psk_params{
+ hint = PskIdentityHint,
+ dh_params = #server_ecdh_params{
+ curve = {namedCurve, ECCurve}, public = ECPubKey}}) ->
+ %%TODO: support arbitrary keys
+ Len = byte_size(PskIdentityHint),
+ KLen = size(ECPubKey),
+ <<?UINT16(Len), PskIdentityHint/binary,
+ ?BYTE(?NAMED_CURVE), ?UINT16((tls_v1:oid_to_enum(ECCurve))),
+ ?BYTE(KLen), ECPubKey/binary>>;
encode_server_key(#server_srp_params{srp_n = N, srp_g = G, srp_s = S, srp_b = B}) ->
NLen = byte_size(N),
GLen = byte_size(G),
@@ -1605,6 +1984,12 @@ encode_client_key(#client_dhe_psk_identity{identity = Id, dh_public = DHPublic},
Len = byte_size(Id),
DHLen = byte_size(DHPublic),
<<?UINT16(Len), Id/binary, ?UINT16(DHLen), DHPublic/binary>>;
+encode_client_key(Identity = #client_ecdhe_psk_identity{identity = undefined}, Version) ->
+ encode_client_key(Identity#client_ecdhe_psk_identity{identity = <<"psk_identity">>}, Version);
+encode_client_key(#client_ecdhe_psk_identity{identity = Id, dh_public = DHPublic}, _) ->
+ Len = byte_size(Id),
+ DHLen = byte_size(DHPublic),
+ <<?UINT16(Len), Id/binary, ?BYTE(DHLen), DHPublic/binary>>;
encode_client_key(Identity = #client_rsa_psk_identity{identity = undefined}, Version) ->
encode_client_key(Identity#client_rsa_psk_identity{identity = <<"psk_identity">>}, Version);
encode_client_key(#client_rsa_psk_identity{identity = Id, exchange_keys = ExchangeKeys}, Version) ->
@@ -1666,16 +2051,32 @@ encode_alpn(undefined, _) ->
encode_alpn(Protocols, _) ->
#alpn{extension_data = lists:foldl(fun encode_protocol/2, <<>>, Protocols)}.
-hello_extensions_list(#hello_extensions{renegotiation_info = RenegotiationInfo,
- srp = SRP,
- signature_algs = HashSigns,
- ec_point_formats = EcPointFormats,
- elliptic_curves = EllipticCurves,
- alpn = ALPN,
- next_protocol_negotiation = NextProtocolNegotiation,
- sni = Sni}) ->
- [Ext || Ext <- [RenegotiationInfo, SRP, HashSigns,
- EcPointFormats, EllipticCurves, ALPN, NextProtocolNegotiation, Sni], Ext =/= undefined].
+
+encode_versions(Versions) ->
+ encode_versions(lists:reverse(Versions), <<>>).
+%%
+encode_versions([], Acc) ->
+ Acc;
+encode_versions([{M,N}|T], Acc) ->
+ encode_versions(T, <<?BYTE(M),?BYTE(N),Acc/binary>>).
+
+encode_client_shares(ClientShares) ->
+ encode_client_shares(ClientShares, <<>>).
+%%
+encode_client_shares([], Acc) ->
+ Acc;
+encode_client_shares([KeyShareEntry0|T], Acc) ->
+ KeyShareEntry = encode_key_share_entry(KeyShareEntry0),
+ encode_client_shares(T, <<Acc/binary,KeyShareEntry/binary>>).
+
+encode_key_share_entry(#key_share_entry{
+ group = Group,
+ key_exchange = KeyExchange}) ->
+ Len = byte_size(KeyExchange),
+ <<?UINT16((tls_v1:group_to_enum(Group))),?UINT16(Len),KeyExchange/binary>>.
+
+hello_extensions_list(HelloExtensions) ->
+ [Ext || {_, Ext} <- maps:to_list(HelloExtensions), Ext =/= undefined].
%%-------------Decode handshakes---------------------------------
dec_server_key(<<?UINT16(PLen), P:PLen/binary,
@@ -1725,6 +2126,22 @@ dec_server_key(<<?UINT16(Len), IdentityHint:Len/binary,
params_bin = BinMsg,
hashsign = HashSign,
signature = Signature};
+dec_server_key(<<?UINT16(Len), IdentityHint:Len/binary,
+ ?BYTE(?NAMED_CURVE), ?UINT16(CurveID),
+ ?BYTE(PointLen), ECPoint:PointLen/binary,
+ _/binary>> = KeyStruct,
+ ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN_PSK, Version) ->
+ DHParams = #server_ecdh_params{
+ curve = {namedCurve, tls_v1:enum_to_oid(CurveID)},
+ public = ECPoint},
+ Params = #server_ecdhe_psk_params{
+ hint = IdentityHint,
+ dh_params = DHParams},
+ {BinMsg, HashSign, Signature} = dec_server_key_params(Len + 2 + PointLen + 4, KeyStruct, Version),
+ #server_key_params{params = Params,
+ params_bin = BinMsg,
+ hashsign = HashSign,
+ signature = Signature};
dec_server_key(<<?UINT16(NLen), N:NLen/binary,
?UINT16(GLen), G:GLen/binary,
?BYTE(SLen), S:SLen/binary,
@@ -1760,6 +2177,10 @@ dec_client_key(<<?UINT16(Len), Id:Len/binary,
?UINT16(DH_YLen), DH_Y:DH_YLen/binary>>,
?KEY_EXCHANGE_DHE_PSK, _) ->
#client_dhe_psk_identity{identity = Id, dh_public = DH_Y};
+dec_client_key(<<?UINT16(Len), Id:Len/binary,
+ ?BYTE(DH_YLen), DH_Y:DH_YLen/binary>>,
+ ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN_PSK, _) ->
+ #client_ecdhe_psk_identity{identity = Id, dh_public = DH_Y};
dec_client_key(<<?UINT16(Len), Id:Len/binary, PKEPMS/binary>>,
?KEY_EXCHANGE_RSA_PSK, {3, 0}) ->
#client_rsa_psk_identity{identity = Id,
@@ -1795,16 +2216,60 @@ dec_server_key_signature(Params, <<?UINT16(Len), Signature:Len/binary>>, _) ->
dec_server_key_signature(_, _, _) ->
throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, failed_to_decrypt_server_key_sign)).
-dec_hello_extensions(<<>>, Acc) ->
+%% Processes a ClientHello/ServerHello message and returns the version to be used
+%% in the decoding functions. The following rules apply:
+%% - IF supported_versions extension is absent:
+%% RETURN the lowest of (LocalVersion and LegacyVersion)
+%% - IF supported_versions estension is present:
+%% RETURN the lowest of (LocalVersion and first element of supported versions)
+process_supported_versions_extension(<<>>, LocalVersion, LegacyVersion)
+ when LegacyVersion =< LocalVersion ->
+ LegacyVersion;
+process_supported_versions_extension(<<>>, LocalVersion, _LegacyVersion) ->
+ LocalVersion;
+process_supported_versions_extension(<<?UINT16(?SUPPORTED_VERSIONS_EXT), ?UINT16(Len),
+ ExtData:Len/binary, _Rest/binary>>,
+ LocalVersion, _LegacyVersion) when Len > 2 ->
+ <<?BYTE(_),Versions0/binary>> = ExtData,
+ [Highest|_] = decode_versions(Versions0),
+ if Highest =< LocalVersion ->
+ Highest;
+ true ->
+ LocalVersion
+ end;
+process_supported_versions_extension(<<?UINT16(?SUPPORTED_VERSIONS_EXT), ?UINT16(Len),
+ ?BYTE(Major),?BYTE(Minor), _Rest/binary>>,
+ LocalVersion, _LegacyVersion) when Len =:= 2 ->
+ SelectedVersion = {Major, Minor},
+ if SelectedVersion =< LocalVersion ->
+ SelectedVersion;
+ true ->
+ LocalVersion
+ end;
+process_supported_versions_extension(<<?UINT16(_), ?UINT16(Len),
+ _ExtData:Len/binary, Rest/binary>>,
+ LocalVersion, LegacyVersion) ->
+ process_supported_versions_extension(Rest, LocalVersion, LegacyVersion);
+%% Tolerate protocol encoding errors and skip parsing the rest of the extension.
+process_supported_versions_extension(_, LocalVersion, LegacyVersion)
+ when LegacyVersion =< LocalVersion ->
+ LegacyVersion;
+process_supported_versions_extension(_, LocalVersion, _) ->
+ LocalVersion.
+
+decode_extensions(<<>>, _Version, _MessageType, Acc) ->
Acc;
-dec_hello_extensions(<<?UINT16(?ALPN_EXT), ?UINT16(ExtLen), ?UINT16(Len), ExtensionData:Len/binary, Rest/binary>>, Acc)
- when Len + 2 =:= ExtLen ->
+decode_extensions(<<?UINT16(?ALPN_EXT), ?UINT16(ExtLen), ?UINT16(Len),
+ ExtensionData:Len/binary, Rest/binary>>, Version, MessageType, Acc)
+ when Len + 2 =:= ExtLen ->
ALPN = #alpn{extension_data = ExtensionData},
- dec_hello_extensions(Rest, Acc#hello_extensions{alpn = ALPN});
-dec_hello_extensions(<<?UINT16(?NEXTPROTONEG_EXT), ?UINT16(Len), ExtensionData:Len/binary, Rest/binary>>, Acc) ->
+ decode_extensions(Rest, Version, MessageType, Acc#{alpn => ALPN});
+decode_extensions(<<?UINT16(?NEXTPROTONEG_EXT), ?UINT16(Len),
+ ExtensionData:Len/binary, Rest/binary>>, Version, MessageType, Acc) ->
NextP = #next_protocol_negotiation{extension_data = ExtensionData},
- dec_hello_extensions(Rest, Acc#hello_extensions{next_protocol_negotiation = NextP});
-dec_hello_extensions(<<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), Info:Len/binary, Rest/binary>>, Acc) ->
+ decode_extensions(Rest, Version, MessageType, Acc#{next_protocol_negotiation => NextP});
+decode_extensions(<<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len),
+ Info:Len/binary, Rest/binary>>, Version, MessageType, Acc) ->
RenegotiateInfo = case Len of
1 -> % Initial handshake
Info; % should be <<0>> will be matched in handle_renegotiation_info
@@ -1813,25 +2278,54 @@ dec_hello_extensions(<<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), Info:Len/binar
<<?BYTE(VerifyLen), VerifyInfo/binary>> = Info,
VerifyInfo
end,
- dec_hello_extensions(Rest, Acc#hello_extensions{renegotiation_info =
- #renegotiation_info{renegotiated_connection =
- RenegotiateInfo}});
-
-dec_hello_extensions(<<?UINT16(?SRP_EXT), ?UINT16(Len), ?BYTE(SRPLen), SRP:SRPLen/binary, Rest/binary>>, Acc)
- when Len == SRPLen + 2 ->
- dec_hello_extensions(Rest, Acc#hello_extensions{srp = #srp{username = SRP}});
-
-dec_hello_extensions(<<?UINT16(?SIGNATURE_ALGORITHMS_EXT), ?UINT16(Len),
- ExtData:Len/binary, Rest/binary>>, Acc) ->
+ decode_extensions(Rest, Version, MessageType,
+ Acc#{renegotiation_info =>
+ #renegotiation_info{renegotiated_connection =
+ RenegotiateInfo}});
+
+decode_extensions(<<?UINT16(?SRP_EXT), ?UINT16(Len), ?BYTE(SRPLen),
+ SRP:SRPLen/binary, Rest/binary>>, Version, MessageType, Acc)
+ when Len == SRPLen + 1 ->
+ decode_extensions(Rest, Version, MessageType, Acc#{srp => #srp{username = SRP}});
+
+decode_extensions(<<?UINT16(?SIGNATURE_ALGORITHMS_EXT), ?UINT16(Len),
+ ExtData:Len/binary, Rest/binary>>, Version, MessageType, Acc)
+ when Version < {3,4} ->
SignAlgoListLen = Len - 2,
<<?UINT16(SignAlgoListLen), SignAlgoList/binary>> = ExtData,
HashSignAlgos = [{ssl_cipher:hash_algorithm(Hash), ssl_cipher:sign_algorithm(Sign)} ||
<<?BYTE(Hash), ?BYTE(Sign)>> <= SignAlgoList],
- dec_hello_extensions(Rest, Acc#hello_extensions{signature_algs =
- #hash_sign_algos{hash_sign_algos = HashSignAlgos}});
-
-dec_hello_extensions(<<?UINT16(?ELLIPTIC_CURVES_EXT), ?UINT16(Len),
- ExtData:Len/binary, Rest/binary>>, Acc) ->
+ decode_extensions(Rest, Version, MessageType,
+ Acc#{signature_algs =>
+ #hash_sign_algos{hash_sign_algos =
+ HashSignAlgos}});
+
+decode_extensions(<<?UINT16(?SIGNATURE_ALGORITHMS_EXT), ?UINT16(Len),
+ ExtData:Len/binary, Rest/binary>>, Version, MessageType, Acc)
+ when Version =:= {3,4} ->
+ SignSchemeListLen = Len - 2,
+ <<?UINT16(SignSchemeListLen), SignSchemeList/binary>> = ExtData,
+ SignSchemes = [ssl_cipher:signature_scheme(SignScheme) ||
+ <<?UINT16(SignScheme)>> <= SignSchemeList],
+ decode_extensions(Rest, Version, MessageType,
+ Acc#{signature_algs =>
+ #signature_algorithms{
+ signature_scheme_list = SignSchemes}});
+
+decode_extensions(<<?UINT16(?SIGNATURE_ALGORITHMS_CERT_EXT), ?UINT16(Len),
+ ExtData:Len/binary, Rest/binary>>, Version, MessageType, Acc) ->
+ SignSchemeListLen = Len - 2,
+ <<?UINT16(SignSchemeListLen), SignSchemeList/binary>> = ExtData,
+ SignSchemes = [ssl_cipher:signature_scheme(SignScheme) ||
+ <<?UINT16(SignScheme)>> <= SignSchemeList],
+ decode_extensions(Rest, Version, MessageType,
+ Acc#{signature_algs_cert =>
+ #signature_algorithms_cert{
+ signature_scheme_list = SignSchemes}});
+
+decode_extensions(<<?UINT16(?ELLIPTIC_CURVES_EXT), ?UINT16(Len),
+ ExtData:Len/binary, Rest/binary>>, Version, MessageType, Acc)
+ when Version < {3,4} ->
<<?UINT16(_), EllipticCurveList/binary>> = ExtData,
%% Ignore unknown curves
Pick = fun(Enum) ->
@@ -1843,31 +2337,103 @@ dec_hello_extensions(<<?UINT16(?ELLIPTIC_CURVES_EXT), ?UINT16(Len),
end
end,
EllipticCurves = lists:filtermap(Pick, [ECC || <<ECC:16>> <= EllipticCurveList]),
- dec_hello_extensions(Rest, Acc#hello_extensions{elliptic_curves =
- #elliptic_curves{elliptic_curve_list =
- EllipticCurves}});
-dec_hello_extensions(<<?UINT16(?EC_POINT_FORMATS_EXT), ?UINT16(Len),
- ExtData:Len/binary, Rest/binary>>, Acc) ->
+ decode_extensions(Rest, Version, MessageType,
+ Acc#{elliptic_curves =>
+ #elliptic_curves{elliptic_curve_list =
+ EllipticCurves}});
+
+decode_extensions(<<?UINT16(?ELLIPTIC_CURVES_EXT), ?UINT16(Len),
+ ExtData:Len/binary, Rest/binary>>, Version, MessageType, Acc)
+ when Version =:= {3,4} ->
+ <<?UINT16(_), GroupList/binary>> = ExtData,
+ %% Ignore unknown curves
+ Pick = fun(Enum) ->
+ case tls_v1:enum_to_group(Enum) of
+ undefined ->
+ false;
+ Group ->
+ {true, Group}
+ end
+ end,
+ SupportedGroups = lists:filtermap(Pick, [Group || <<Group:16>> <= GroupList]),
+ decode_extensions(Rest, Version, MessageType,
+ Acc#{elliptic_curves =>
+ #supported_groups{supported_groups =
+ SupportedGroups}});
+
+decode_extensions(<<?UINT16(?EC_POINT_FORMATS_EXT), ?UINT16(Len),
+ ExtData:Len/binary, Rest/binary>>, Version, MessageType, Acc) ->
<<?BYTE(_), ECPointFormatList/binary>> = ExtData,
ECPointFormats = binary_to_list(ECPointFormatList),
- dec_hello_extensions(Rest, Acc#hello_extensions{ec_point_formats =
- #ec_point_formats{ec_point_format_list =
- ECPointFormats}});
+ decode_extensions(Rest, Version, MessageType,
+ Acc#{ec_point_formats =>
+ #ec_point_formats{ec_point_format_list =
+ ECPointFormats}});
+
+decode_extensions(<<?UINT16(?SNI_EXT), ?UINT16(Len),
+ Rest/binary>>, Version, MessageType, Acc) when Len == 0 ->
+ decode_extensions(Rest, Version, MessageType,
+ Acc#{sni => #sni{hostname = ""}}); %% Server may send an empy SNI
+
+decode_extensions(<<?UINT16(?SNI_EXT), ?UINT16(Len),
+ ExtData:Len/binary, Rest/binary>>, Version, MessageType, Acc) ->
+ <<?UINT16(_), NameList/binary>> = ExtData,
+ decode_extensions(Rest, Version, MessageType,
+ Acc#{sni => dec_sni(NameList)});
+
+decode_extensions(<<?UINT16(?SUPPORTED_VERSIONS_EXT), ?UINT16(Len),
+ ExtData:Len/binary, Rest/binary>>, Version, MessageType, Acc) when Len > 2 ->
+ <<?BYTE(_),Versions/binary>> = ExtData,
+ decode_extensions(Rest, Version, MessageType,
+ Acc#{client_hello_versions =>
+ #client_hello_versions{
+ versions = decode_versions(Versions)}});
+
+decode_extensions(<<?UINT16(?SUPPORTED_VERSIONS_EXT), ?UINT16(Len),
+ ?UINT16(SelectedVersion), Rest/binary>>, Version, MessageType, Acc)
+ when Len =:= 2, SelectedVersion =:= 16#0304 ->
+ decode_extensions(Rest, Version, MessageType,
+ Acc#{server_hello_selected_version =>
+ #server_hello_selected_version{selected_version =
+ {3,4}}});
+
+decode_extensions(<<?UINT16(?KEY_SHARE_EXT), ?UINT16(Len),
+ ExtData:Len/binary, Rest/binary>>,
+ Version, MessageType = client_hello, Acc) ->
+ <<?UINT16(_),ClientShares/binary>> = ExtData,
+ decode_extensions(Rest, Version, MessageType,
+ Acc#{key_share =>
+ #key_share_client_hello{
+ client_shares = decode_client_shares(ClientShares)}});
+
+decode_extensions(<<?UINT16(?KEY_SHARE_EXT), ?UINT16(Len),
+ ExtData:Len/binary, Rest/binary>>,
+ Version, MessageType = server_hello, Acc) ->
+ <<?UINT16(Group),?UINT16(KeyLen),KeyExchange:KeyLen/binary>> = ExtData,
+ decode_extensions(Rest, Version, MessageType,
+ Acc#{key_share =>
+ #key_share_server_hello{
+ server_share =
+ #key_share_entry{
+ group = tls_v1:enum_to_group(Group),
+ key_exchange = KeyExchange}}});
+
+decode_extensions(<<?UINT16(?KEY_SHARE_EXT), ?UINT16(Len),
+ ExtData:Len/binary, Rest/binary>>,
+ Version, MessageType = hello_retry_request, Acc) ->
+ <<?UINT16(Group)>> = ExtData,
+ decode_extensions(Rest, Version, MessageType,
+ Acc#{key_share =>
+ #key_share_hello_retry_request{
+ selected_group = tls_v1:enum_to_group(Group)}});
-dec_hello_extensions(<<?UINT16(?SNI_EXT), ?UINT16(Len), Rest/binary>>, Acc) when Len == 0 ->
- dec_hello_extensions(Rest, Acc#hello_extensions{sni = ""}); %% Server may send an empy SNI
-dec_hello_extensions(<<?UINT16(?SNI_EXT), ?UINT16(Len),
- ExtData:Len/binary, Rest/binary>>, Acc) ->
- <<?UINT16(_), NameList/binary>> = ExtData,
- dec_hello_extensions(Rest, Acc#hello_extensions{sni = dec_sni(NameList)});
%% Ignore data following the ClientHello (i.e.,
%% extensions) if not understood.
-
-dec_hello_extensions(<<?UINT16(_), ?UINT16(Len), _Unknown:Len/binary, Rest/binary>>, Acc) ->
- dec_hello_extensions(Rest, Acc);
+decode_extensions(<<?UINT16(_), ?UINT16(Len), _Unknown:Len/binary, Rest/binary>>, Version, MessageType, Acc) ->
+ decode_extensions(Rest, Version, MessageType, Acc);
%% This theoretically should not happen if the protocol is followed, but if it does it is ignored.
-dec_hello_extensions(_, Acc) ->
+decode_extensions(_, _, _, Acc) ->
Acc.
dec_hashsign(<<?BYTE(HashAlgo), ?BYTE(SignAlgo)>>) ->
@@ -1885,6 +2451,26 @@ decode_alpn(undefined) ->
decode_alpn(#alpn{extension_data=Data}) ->
decode_protocols(Data, []).
+decode_versions(Versions) ->
+ decode_versions(Versions, []).
+%%
+decode_versions(<<>>, Acc) ->
+ lists:reverse(Acc);
+decode_versions(<<?BYTE(M),?BYTE(N),Rest/binary>>, Acc) ->
+ decode_versions(Rest, [{M,N}|Acc]).
+
+
+decode_client_shares(ClientShares) ->
+ decode_client_shares(ClientShares, []).
+%%
+decode_client_shares(<<>>, Acc) ->
+ lists:reverse(Acc);
+decode_client_shares(<<?UINT16(Group),?UINT16(Len),KeyExchange:Len/binary,Rest/binary>>, Acc) ->
+ decode_client_shares(Rest, [#key_share_entry{
+ group = tls_v1:enum_to_group(Group),
+ key_exchange= KeyExchange
+ }|Acc]).
+
decode_next_protocols({next_protocol_negotiation, Protocols}) ->
decode_protocols(Protocols, []).
@@ -1943,6 +2529,8 @@ key_exchange_alg(psk) ->
?KEY_EXCHANGE_PSK;
key_exchange_alg(dhe_psk) ->
?KEY_EXCHANGE_DHE_PSK;
+key_exchange_alg(ecdhe_psk) ->
+ ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN_PSK;
key_exchange_alg(rsa_psk) ->
?KEY_EXCHANGE_RSA_PSK;
key_exchange_alg(Alg)
@@ -1999,25 +2587,26 @@ handle_psk_identity(_PSKIdentity, LookupFun)
handle_psk_identity(PSKIdentity, {Fun, UserState}) ->
Fun(psk, PSKIdentity, UserState).
-filter_hashsigns([], [], _, Acc) ->
- lists:reverse(Acc);
-filter_hashsigns([Suite | Suites], [#{key_exchange := KeyExchange} | Algos], HashSigns,
- Acc) when KeyExchange == dhe_ecdsa;
- KeyExchange == ecdhe_ecdsa ->
- do_filter_hashsigns(ecdsa, Suite, Suites, Algos, HashSigns, Acc);
-filter_hashsigns([Suite | Suites], [#{key_exchange := KeyExchange} | Algos], HashSigns,
+filter_hashsigns([], [], _, _, Acc) ->
+ lists:reverse(Acc);
+filter_hashsigns([Suite | Suites], [#{key_exchange := KeyExchange} | Algos], HashSigns, Version,
+ Acc) when KeyExchange == dhe_ecdsa;
+ KeyExchange == ecdhe_ecdsa ->
+ do_filter_hashsigns(ecdsa, Suite, Suites, Algos, HashSigns, Version, Acc);
+filter_hashsigns([Suite | Suites], [#{key_exchange := KeyExchange} | Algos], HashSigns, Version,
Acc) when KeyExchange == rsa;
KeyExchange == dhe_rsa;
KeyExchange == ecdhe_rsa;
KeyExchange == srp_rsa;
KeyExchange == rsa_psk ->
- do_filter_hashsigns(rsa, Suite, Suites, Algos, HashSigns, Acc);
-filter_hashsigns([Suite | Suites], [#{key_exchange := KeyExchange} | Algos], HashSigns, Acc) when
+ do_filter_hashsigns(rsa, Suite, Suites, Algos, HashSigns, Version, Acc);
+filter_hashsigns([Suite | Suites], [#{key_exchange := KeyExchange} | Algos], HashSigns, Version, Acc) when
KeyExchange == dhe_dss;
KeyExchange == srp_dss ->
- do_filter_hashsigns(dsa, Suite, Suites, Algos, HashSigns, Acc);
-filter_hashsigns([Suite | Suites], [#{key_exchange := KeyExchange} | Algos], HashSigns, Acc) when
+ do_filter_hashsigns(dsa, Suite, Suites, Algos, HashSigns, Version, Acc);
+filter_hashsigns([Suite | Suites], [#{key_exchange := KeyExchange} | Algos], HashSigns, Verion,
+ Acc) when
KeyExchange == dh_dss;
KeyExchange == dh_rsa;
KeyExchange == dh_ecdsa;
@@ -2026,57 +2615,63 @@ filter_hashsigns([Suite | Suites], [#{key_exchange := KeyExchange} | Algos], Has
%% Fixed DH certificates MAY be signed with any hash/signature
%% algorithm pair appearing in the hash_sign extension. The names
%% DH_DSS, DH_RSA, ECDH_ECDSA, and ECDH_RSA are historical.
- filter_hashsigns(Suites, Algos, HashSigns, [Suite| Acc]);
-filter_hashsigns([Suite | Suites], [#{key_exchange := KeyExchange} | Algos], HashSigns, Acc) when
+ filter_hashsigns(Suites, Algos, HashSigns, Verion, [Suite| Acc]);
+filter_hashsigns([Suite | Suites], [#{key_exchange := KeyExchange} | Algos], HashSigns, Version,
+ Acc) when
KeyExchange == dh_anon;
KeyExchange == ecdh_anon;
KeyExchange == srp_anon;
KeyExchange == psk;
- KeyExchange == dhe_psk ->
+ KeyExchange == dhe_psk;
+ KeyExchange == ecdhe_psk ->
%% In this case hashsigns is not used as the kexchange is anonaymous
- filter_hashsigns(Suites, Algos, HashSigns, [Suite| Acc]).
+ filter_hashsigns(Suites, Algos, HashSigns, Version, [Suite| Acc]).
-do_filter_hashsigns(SignAlgo, Suite, Suites, Algos, HashSigns, Acc) ->
+do_filter_hashsigns(SignAlgo, Suite, Suites, Algos, HashSigns, Version, Acc) ->
case lists:keymember(SignAlgo, 2, HashSigns) of
true ->
- filter_hashsigns(Suites, Algos, HashSigns, [Suite| Acc]);
+ filter_hashsigns(Suites, Algos, HashSigns, Version, [Suite| Acc]);
false ->
- filter_hashsigns(Suites, Algos, HashSigns, Acc)
+ filter_hashsigns(Suites, Algos, HashSigns, Version, Acc)
end.
-unavailable_ecc_suites(no_curve) ->
- ssl_cipher:ec_keyed_suites();
-unavailable_ecc_suites(_) ->
- [].
+filter_unavailable_ecc_suites(no_curve, Suites) ->
+ ECCSuites = ssl_cipher:filter_suites(Suites, #{key_exchange_filters => [fun(ecdh_ecdsa) -> true;
+ (ecdhe_ecdsa) -> true;
+ (ecdh_rsa) -> true;
+ (_) -> false
+ end],
+ cipher_filters => [],
+ mac_filters => [],
+ prf_filters => []}),
+ Suites -- ECCSuites;
+filter_unavailable_ecc_suites(_, Suites) ->
+ Suites.
%%-------------Extension handling --------------------------------
handle_renegotiation_extension(Role, RecordCB, Version, Info, Random, NegotiatedCipherSuite,
ClientCipherSuites, Compression,
ConnectionStates0, Renegotiation, SecureRenegotation) ->
- case handle_renegotiation_info(RecordCB, Role, Info, ConnectionStates0,
- Renegotiation, SecureRenegotation,
- ClientCipherSuites) of
- {ok, ConnectionStates} ->
- hello_pending_connection_states(RecordCB, Role,
- Version,
- NegotiatedCipherSuite,
- Random,
- Compression,
- ConnectionStates);
- #alert{} = Alert ->
- throw(Alert)
- end.
+ {ok, ConnectionStates} = handle_renegotiation_info(RecordCB, Role, Info, ConnectionStates0,
+ Renegotiation, SecureRenegotation,
+ ClientCipherSuites),
+ hello_pending_connection_states(RecordCB, Role,
+ Version,
+ NegotiatedCipherSuite,
+ Random,
+ Compression,
+ ConnectionStates).
%% Receive protocols, choose one from the list, return it.
handle_alpn_extension(_, {error, Reason}) ->
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, Reason);
+ throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, Reason));
handle_alpn_extension([], _) ->
- ?ALERT_REC(?FATAL, ?NO_APPLICATION_PROTOCOL);
+ throw(?ALERT_REC(?FATAL, ?NO_APPLICATION_PROTOCOL));
handle_alpn_extension([ServerProtocol|Tail], ClientProtocols) ->
- case lists:member(ServerProtocol, ClientProtocols) of
- true -> ServerProtocol;
- false -> handle_alpn_extension(Tail, ClientProtocols)
- end.
+ case lists:member(ServerProtocol, ClientProtocols) of
+ true -> ServerProtocol;
+ false -> handle_alpn_extension(Tail, ClientProtocols)
+ end.
handle_next_protocol(undefined,
_NextProtocolSelector, _Renegotiating) ->
@@ -2089,14 +2684,14 @@ handle_next_protocol(#next_protocol_negotiation{} = NextProtocols,
true ->
select_next_protocol(decode_next_protocols(NextProtocols), NextProtocolSelector);
false ->
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, unexpected_next_protocol_extension)
+ throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, unexpected_next_protocol_extension))
end.
handle_next_protocol_extension(NextProtocolNegotiation, Renegotiation, SslOpts)->
case handle_next_protocol_on_server(NextProtocolNegotiation, Renegotiation, SslOpts) of
#alert{} = Alert ->
- Alert;
+ throw(Alert);
ProtocolsToAdvertise ->
ProtocolsToAdvertise
end.
@@ -2129,67 +2724,95 @@ handle_srp_extension(undefined, Session) ->
handle_srp_extension(#srp{username = Username}, Session) ->
Session#session{srp_username = Username}.
-
-sign_algo(?rsaEncryption) ->
- rsa;
-sign_algo(?'id-ecPublicKey') ->
- ecdsa;
-sign_algo(?'id-dsa') ->
- dsa;
-sign_algo(Alg) ->
- {_, Sign} =public_key:pkix_sign_types(Alg),
- Sign.
-
-is_acceptable_hash_sign(Algos, _, _, KeyExAlgo, SupportedHashSigns) when
- KeyExAlgo == dh_dss;
- KeyExAlgo == dh_rsa;
- KeyExAlgo == dh_ecdsa ->
- %% dh_* could be called only dh in TLS-1.2
- is_acceptable_hash_sign(Algos, SupportedHashSigns);
-is_acceptable_hash_sign(Algos, rsa, ecdsa, ecdh_rsa, SupportedHashSigns) ->
- is_acceptable_hash_sign(Algos, SupportedHashSigns);
-is_acceptable_hash_sign({_, rsa} = Algos, rsa, _, dhe_rsa, SupportedHashSigns) ->
- is_acceptable_hash_sign(Algos, SupportedHashSigns);
-is_acceptable_hash_sign({_, rsa} = Algos, rsa, rsa, ecdhe_rsa, SupportedHashSigns) ->
- is_acceptable_hash_sign(Algos, SupportedHashSigns);
-is_acceptable_hash_sign({_, rsa} = Algos, rsa, rsa, rsa, SupportedHashSigns) ->
- is_acceptable_hash_sign(Algos, SupportedHashSigns);
-is_acceptable_hash_sign({_, rsa} = Algos, rsa, _, srp_rsa, SupportedHashSigns) ->
- is_acceptable_hash_sign(Algos, SupportedHashSigns);
-is_acceptable_hash_sign({_, rsa} = Algos, rsa, _, rsa_psk, SupportedHashSigns) ->
- is_acceptable_hash_sign(Algos, SupportedHashSigns);
-is_acceptable_hash_sign({_, dsa} = Algos, dsa, _, dhe_dss, SupportedHashSigns) ->
- is_acceptable_hash_sign(Algos, SupportedHashSigns);
-is_acceptable_hash_sign({_, dsa} = Algos, dsa, _, srp_dss, SupportedHashSigns) ->
- is_acceptable_hash_sign(Algos, SupportedHashSigns);
-is_acceptable_hash_sign({_, ecdsa} = Algos, ecdsa, _, dhe_ecdsa, SupportedHashSigns) ->
- is_acceptable_hash_sign(Algos, SupportedHashSigns);
-is_acceptable_hash_sign({_, ecdsa} = Algos, ecdsa, ecdsa, ecdh_ecdsa, SupportedHashSigns) ->
- is_acceptable_hash_sign(Algos, SupportedHashSigns);
-is_acceptable_hash_sign({_, ecdsa} = Algos, ecdsa, ecdsa, ecdhe_ecdsa, SupportedHashSigns) ->
- is_acceptable_hash_sign(Algos, SupportedHashSigns);
-is_acceptable_hash_sign(_, _, _, KeyExAlgo, _) when
+is_acceptable_hash_sign( _, KeyExAlgo, _) when
KeyExAlgo == psk;
KeyExAlgo == dhe_psk;
+ KeyExAlgo == ecdhe_psk;
KeyExAlgo == srp_anon;
KeyExAlgo == dh_anon;
KeyExAlgo == ecdhe_anon
->
true;
-is_acceptable_hash_sign(_,_, _,_,_) ->
- false.
+is_acceptable_hash_sign(Algos,_, SupportedHashSigns) ->
+ is_acceptable_hash_sign(Algos, SupportedHashSigns).
+
is_acceptable_hash_sign(Algos, SupportedHashSigns) ->
lists:member(Algos, SupportedHashSigns).
-is_acceptable_cert_type(Sign, _HashSigns, Types) ->
+is_acceptable_cert_type(Sign, Types) ->
lists:member(sign_type(Sign), binary_to_list(Types)).
-is_supported_sign(Sign, HashSigns) ->
- [] =/= lists:dropwhile(fun({_, S}) when S =/= Sign ->
- true;
- (_)->
- false
- end, HashSigns).
+%% signature_algorithms_cert = undefined
+is_supported_sign(SignAlgo, _, HashSigns, undefined) ->
+ lists:member(SignAlgo, HashSigns);
+
+%% {'SignatureAlgorithm',{1,2,840,113549,1,1,11},'NULL'}
+is_supported_sign({Hash, Sign}, 'NULL', _, SignatureSchemes) ->
+ Fun = fun (Scheme, Acc) ->
+ {H0, S0, _} = ssl_cipher:scheme_to_components(Scheme),
+ S1 = case S0 of
+ rsa_pkcs1 -> rsa;
+ S -> S
+ end,
+ H1 = case H0 of
+ sha1 -> sha;
+ H -> H
+ end,
+ Acc orelse (Sign =:= S1 andalso
+ Hash =:= H1)
+ end,
+ lists:foldl(Fun, false, SignatureSchemes);
+
+%% TODO: Implement validation for the curve used in the signature
+%% RFC 3279 - 2.2.3 ECDSA Signature Algorithm
+%% When the ecdsa-with-SHA1 algorithm identifier appears as the
+%% algorithm field in an AlgorithmIdentifier, the encoding MUST omit the
+%% parameters field. That is, the AlgorithmIdentifier SHALL be a
+%% SEQUENCE of one component: the OBJECT IDENTIFIER ecdsa-with-SHA1.
+%%
+%% The elliptic curve parameters in the subjectPublicKeyInfo field of
+%% the certificate of the issuer SHALL apply to the verification of the
+%% signature.
+is_supported_sign({Hash, Sign}, _Param, _, SignatureSchemes) ->
+ Fun = fun (Scheme, Acc) ->
+ {H0, S0, _} = ssl_cipher:scheme_to_components(Scheme),
+ S1 = case S0 of
+ rsa_pkcs1 -> rsa;
+ S -> S
+ end,
+ H1 = case H0 of
+ sha1 -> sha;
+ H -> H
+ end,
+ Acc orelse (Sign =:= S1 andalso
+ Hash =:= H1)
+ end,
+ lists:foldl(Fun, false, SignatureSchemes).
+
+%% SupportedPublicKeyAlgorithms PUBLIC-KEY-ALGORITHM-CLASS ::= {
+%% dsa | rsa-encryption | dh | kea | ec-public-key }
+public_key_algo(?rsaEncryption) ->
+ rsa;
+public_key_algo(?'id-ecPublicKey') ->
+ ecdsa;
+public_key_algo(?'id-dsa') ->
+ dsa.
+
+%% SupportedSignatureAlgorithms SIGNATURE-ALGORITHM-CLASS ::= {
+%% dsa-with-sha1 | dsaWithSHA1 | md2-with-rsa-encryption |
+%% md5-with-rsa-encryption | sha1-with-rsa-encryption | sha-1with-rsa-encryption |
+%% sha224-with-rsa-encryption |
+%% sha256-with-rsa-encryption |
+%% sha384-with-rsa-encryption |
+%% sha512-with-rsa-encryption |
+%% ecdsa-with-sha1 |
+%% ecdsa-with-sha224 |
+%% ecdsa-with-sha256 |
+%% ecdsa-with-sha384 |
+%% ecdsa-with-sha512 }
+sign_algo(Alg) ->
+ public_key:pkix_sign_types(Alg).
+
sign_type(rsa) ->
?RSA_SIGN;
sign_type(dsa) ->
@@ -2208,6 +2831,11 @@ client_ecc_extensions(SupportedECCs) ->
CryptoSupport = proplists:get_value(public_keys, crypto:supports()),
case proplists:get_bool(ecdh, CryptoSupport) of
true ->
+ %% RFC 8422 - 5.1. Client Hello Extensions
+ %% Clients SHOULD send both the Supported Elliptic Curves Extension and the
+ %% Supported Point Formats Extension. If the Supported Point Formats
+ %% Extension is indeed sent, it MUST contain the value 0 (uncompressed)
+ %% as one of the items in the list of point formats.
EcPointFormats = #ec_point_formats{ec_point_format_list = [?ECPOINT_UNCOMPRESSED]},
EllipticCurves = SupportedECCs,
{EcPointFormats, EllipticCurves};
@@ -2241,6 +2869,8 @@ advertises_ec_ciphers([#{key_exchange := ecdhe_rsa} | _]) ->
true;
advertises_ec_ciphers([#{key_exchange := ecdh_anon} | _]) ->
true;
+advertises_ec_ciphers([{ecdhe_psk, _,_,_} | _]) ->
+ true;
advertises_ec_ciphers([_| Rest]) ->
advertises_ec_ciphers(Rest).
@@ -2316,14 +2946,14 @@ handle_renegotiation_info(_RecordCB, client, #renegotiation_info{renegotiated_co
true ->
{ok, ConnectionStates};
false ->
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, client_renegotiation)
+ throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, client_renegotiation))
end;
handle_renegotiation_info(_RecordCB, server, #renegotiation_info{renegotiated_connection = ClientVerify},
ConnectionStates, true, _, CipherSuites) ->
case is_member(?TLS_EMPTY_RENEGOTIATION_INFO_SCSV, CipherSuites) of
true ->
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, {server_renegotiation, empty_renegotiation_info_scsv});
+ throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, {server_renegotiation, empty_renegotiation_info_scsv}));
false ->
ConnectionState = ssl_record:current_connection_state(ConnectionStates, read),
Data = maps:get(client_verify_data, ConnectionState),
@@ -2331,7 +2961,7 @@ handle_renegotiation_info(_RecordCB, server, #renegotiation_info{renegotiated_co
true ->
{ok, ConnectionStates};
false ->
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, server_renegotiation)
+ throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, server_renegotiation))
end
end;
@@ -2341,7 +2971,7 @@ handle_renegotiation_info(RecordCB, client, undefined, ConnectionStates, true, S
handle_renegotiation_info(RecordCB, server, undefined, ConnectionStates, true, SecureRenegotation, CipherSuites) ->
case is_member(?TLS_EMPTY_RENEGOTIATION_INFO_SCSV, CipherSuites) of
true ->
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, {server_renegotiation, empty_renegotiation_info_scsv});
+ throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, {server_renegotiation, empty_renegotiation_info_scsv}));
false ->
handle_renegotiation_info(RecordCB, ConnectionStates, SecureRenegotation)
end.
@@ -2350,9 +2980,74 @@ handle_renegotiation_info(_RecordCB, ConnectionStates, SecureRenegotation) ->
ConnectionState = ssl_record:current_connection_state(ConnectionStates, read),
case {SecureRenegotation, maps:get(secure_renegotiation, ConnectionState)} of
{_, true} ->
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, already_secure);
+ throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, already_secure));
{true, false} ->
- ?ALERT_REC(?FATAL, ?NO_RENEGOTIATION);
+ throw(?ALERT_REC(?FATAL, ?NO_RENEGOTIATION));
{false, false} ->
{ok, ConnectionStates}
end.
+
+cert_curve(_, _, no_suite) ->
+ {no_curve, no_suite};
+cert_curve(Cert, ECCCurve0, CipherSuite) ->
+ case ssl_cipher_format:suite_bin_to_map(CipherSuite) of
+ #{key_exchange := Kex} when Kex == ecdh_ecdsa;
+ Kex == ecdh_rsa ->
+ OtpCert = public_key:pkix_decode_cert(Cert, otp),
+ TBSCert = OtpCert#'OTPCertificate'.tbsCertificate,
+ #'OTPSubjectPublicKeyInfo'{algorithm = AlgInfo}
+ = TBSCert#'OTPTBSCertificate'.subjectPublicKeyInfo,
+ {namedCurve, Oid} = AlgInfo#'PublicKeyAlgorithm'.parameters,
+ {{namedCurve, Oid}, CipherSuite};
+ _ ->
+ {ECCCurve0, CipherSuite}
+ end.
+
+empty_extensions() ->
+ #{}.
+
+empty_extensions({3,4}, client_hello) ->
+ #{
+ sni => undefined,
+ %% max_fragment_length => undefined,
+ %% status_request => undefined,
+ elliptic_curves => undefined,
+ signature_algs => undefined,
+ %% use_srtp => undefined,
+ %% heartbeat => undefined,
+ alpn => undefined,
+ %% signed_cert_timestamp => undefined,
+ %% client_cert_type => undefined,
+ %% server_cert_type => undefined,
+ %% padding => undefined,
+ key_share => undefined,
+ pre_shared_key => undefined,
+ %% psk_key_exhange_modes => undefined,
+ %% early_data => undefined,
+ %% cookie => undefined,
+ client_hello_versions => undefined,
+ %% cert_authorities => undefined,
+ %% post_handshake_auth => undefined,
+ signature_algs_cert => undefined
+ };
+empty_extensions({3, 3}, client_hello) ->
+ Ext = empty_extensions({3,2}, client_hello),
+ Ext#{signature_algs => undefined};
+empty_extensions(_, client_hello) ->
+ #{renegotiation_info => undefined,
+ alpn => undefined,
+ next_protocol_negotiation => undefined,
+ srp => undefined,
+ ec_point_formats => undefined,
+ elliptic_curves => undefined,
+ sni => undefined};
+empty_extensions({3,4}, server_hello) ->
+ #{server_hello_selected_version => undefined,
+ key_share => undefined,
+ pre_shared_key => undefined
+ };
+empty_extensions(_, server_hello) ->
+ #{renegotiation_info => undefined,
+ alpn => undefined,
+ next_protocol_negotiation => undefined,
+ ec_point_formats => undefined}.
diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl
index 324b7dbde3..b248edcaa9 100644
--- a/lib/ssl/src/ssl_handshake.hrl
+++ b/lib/ssl/src/ssl_handshake.hrl
@@ -47,14 +47,15 @@
srp_username,
is_resumable,
time_stamp,
- ecc
+ ecc, %% TLS 1.3 Group
+ sign_alg, %% TLS 1.3 Signature Algorithm
+ dh_public_value %% TLS 1.3 DH Public Value from peer
}).
-define(NUM_OF_SESSION_ID_BYTES, 32). % TSL 1.1 & SSL 3
-define(NUM_OF_PREMASTERSECRET_BYTES, 48).
--define(DEFAULT_DIFFIE_HELLMAN_GENERATOR, 2).
--define(DEFAULT_DIFFIE_HELLMAN_PRIME,
- 16#FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF).
+-define(DEFAULT_DIFFIE_HELLMAN_GENERATOR, ssl_dh_groups:modp2048_generator()).
+-define(DEFAULT_DIFFIE_HELLMAN_PRIME, ssl_dh_groups:modp2048_prime()).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Handsake protocol - RFC 4346 section 7.4
@@ -105,7 +106,11 @@
srp,
ec_point_formats,
elliptic_curves,
- sni
+ sni,
+ client_hello_versions,
+ server_hello_selected_version,
+ signature_algs_cert,
+ key_share
}).
-record(server_hello, {
@@ -133,6 +138,7 @@
-define(KEY_EXCHANGE_DIFFIE_HELLMAN, 1).
-define(KEY_EXCHANGE_EC_DIFFIE_HELLMAN, 6).
-define(KEY_EXCHANGE_PSK, 2).
+-define(KEY_EXCHANGE_EC_DIFFIE_HELLMAN_PSK, 7).
-define(KEY_EXCHANGE_DHE_PSK, 3).
-define(KEY_EXCHANGE_RSA_PSK, 4).
-define(KEY_EXCHANGE_SRP, 5).
@@ -162,6 +168,11 @@
dh_params
}).
+-record(server_ecdhe_psk_params, {
+ hint,
+ dh_params
+ }).
+
-record(server_srp_params, {
srp_n, %% opaque srp_N<1..2^16-1>
srp_g, %% opaque srp_g<1..2^16-1>
@@ -254,6 +265,11 @@
dh_public
}).
+-record(client_ecdhe_psk_identity, {
+ identity,
+ dh_public
+ }).
+
-record(client_rsa_psk_identity, {
identity,
exchange_keys
@@ -302,12 +318,12 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-define(SIGNATURE_ALGORITHMS_EXT, 13).
--record(hash_sign_algos, {
- hash_sign_algos
- }).
+-record(hash_sign_algos, {hash_sign_algos}).
+%% RFC 8446 (TLS 1.3)
+-record(signature_algorithms, {signature_scheme_list}).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Application-Layer Protocol Negotiation RFC 7301
+%% RFC 7301 Application-Layer Protocol Negotiation
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-define(ALPN_EXT, 16).
@@ -327,9 +343,8 @@
-record(next_protocol, {selected_protocol}).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% ECC Extensions RFC 4492 section 4 and 5
+%% ECC Extensions RFC 8422 section 4 and 5
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-define(ELLIPTIC_CURVES_EXT, 10).
-define(EC_POINT_FORMATS_EXT, 11).
@@ -337,11 +352,18 @@
elliptic_curve_list
}).
+%% RFC 8446 (TLS 1.3) renamed the "elliptic_curve" extension.
+-record(supported_groups, {
+ supported_groups
+ }).
+
-record(ec_point_formats, {
ec_point_format_list
}).
-define(ECPOINT_UNCOMPRESSED, 0).
+%% Defined in RFC 4492, deprecated by RFC 8422
+%% RFC 8422 compliant implementations MUST not support the two formats below
-define(ECPOINT_ANSIX962_COMPRESSED_PRIME, 1).
-define(ECPOINT_ANSIX962_COMPRESSED_CHAR2, 2).
@@ -354,10 +376,11 @@
-define(NAMED_CURVE, 3).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Server name indication RFC 6066 section 3
+%% RFC 6066 Server name indication
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--define(SNI_EXT, 16#0000).
+%% section 3
+-define(SNI_EXT, 0).
%% enum { host_name(0), (255) } NameType;
-define(SNI_NAMETYPE_HOST_NAME, 0).
@@ -366,4 +389,56 @@
hostname = undefined
}).
+%% Other possible values from RFC 6066, not supported
+-define(MAX_FRAGMENT_LENGTH, 1).
+-define(CLIENT_CERTIFICATE_URL, 2).
+-define(TRUSTED_CA_KEYS, 3).
+-define(TRUNCATED_HMAC, 4).
+-define(STATUS_REQUEST, 5).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% RFC 7250 Using Raw Public Keys in Transport Layer Security (TLS)
+%% and Datagram Transport Layer Security (DTLS)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Not supported
+-define(CLIENT_CERTIFICATE_TYPE, 19).
+-define(SERVER_CERTIFICATE_TYPE, 20).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% RFC 6520 Transport Layer Security (TLS) and
+%% Datagram Transport Layer Security (DTLS) Heartbeat Extension
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Not supported
+-define(HS_HEARTBEAT, 15).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% RFC 6962 Certificate Transparency
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Not supported
+-define(SIGNED_CERTIFICATE_TIMESTAMP, 18).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% RFC 7685 A Transport Layer Security (TLS) ClientHello Padding Extension
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Not supported
+-define(PADDING, 21).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Supported Versions RFC 8446 (TLS 1.3) section 4.2.1 also affects TLS-1.2
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-define(SUPPORTED_VERSIONS_EXT, 43).
+
+-record(client_hello_versions, {versions}).
+-record(server_hello_selected_version, {selected_version}).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Signature Algorithms RFC 8446 (TLS 1.3) section 4.2.3 also affects TLS-1.2
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-define(SIGNATURE_ALGORITHMS_CERT_EXT, 50).
+
+-record(signature_algorithms_cert, {signature_scheme_list}).
+
-endif. % -ifdef(ssl_handshake).
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index 9bb1cbaeb0..06c3ccae45 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,16 +25,15 @@
-include_lib("public_key/include/public_key.hrl").
+-define(VSN, "8.2.6").
-define(SECRET_PRINTOUT, "***").
--type reason() :: term().
--type reply() :: term().
--type msg() :: term().
--type from() :: term().
--type host() :: inet:ip_address() | inet:hostname().
--type session_id() :: 0 | binary().
+-type reason() :: any().
+-type reply() :: any().
+-type msg() :: any().
+-type from() :: any().
-type certdb_ref() :: reference().
--type db_handle() :: term().
+-type db_handle() :: any().
-type der_cert() :: binary().
-type issuer() :: tuple().
-type serialnumber() :: integer().
@@ -60,6 +59,7 @@
-define(CDR_MAGIC, "GIOP").
-define(CDR_HDR_SIZE, 12).
+-define(INTERNAL_ACTIVE_N, 100).
-define(DEFAULT_TIMEOUT, 5000).
-define(NO_DIST_POINT, "http://dummy/no_distribution_point").
@@ -71,36 +71,64 @@
-define(FALSE, 1).
%% sslv3 is considered insecure due to lack of padding check (Poodle attack)
-%% Keep as interop with legacy software but do not support as default
--define(ALL_AVAILABLE_VERSIONS, ['tlsv1.2', 'tlsv1.1', tlsv1, sslv3]).
--define(ALL_SUPPORTED_VERSIONS, ['tlsv1.2', 'tlsv1.1', tlsv1]).
--define(MIN_SUPPORTED_VERSIONS, ['tlsv1.1', tlsv1]).
--define(ALL_DATAGRAM_SUPPORTED_VERSIONS, ['dtlsv1.2', dtlsv1]).
+%% Keep as interop with legacy software but do not support as default
+%% tlsv1.0 and tlsv1.1 is now also considered legacy
+%% tlsv1.3 is under development (experimental).
+-define(ALL_AVAILABLE_VERSIONS, ['tlsv1.3', 'tlsv1.2', 'tlsv1.1', tlsv1, sslv3]).
+-define(ALL_AVAILABLE_DATAGRAM_VERSIONS, ['dtlsv1.2', dtlsv1]).
+%% Defines the default versions when not specified by an ssl option.
+-define(ALL_SUPPORTED_VERSIONS, ['tlsv1.2']).
+-define(MIN_SUPPORTED_VERSIONS, ['tlsv1.1']).
+
+%% Versions allowed in TLSCiphertext.version (TLS 1.2 and prior) and
+%% TLSCiphertext.legacy_record_version (TLS 1.3).
+%% TLS 1.3 sets TLSCiphertext.legacy_record_version to 0x0303 for all records
+%% generated other than an than an initial ClientHello, where it MAY also be 0x0301.
+%% Thus, the allowed range is limited to 0x0300 - 0x0303.
+-define(ALL_TLS_RECORD_VERSIONS, ['tlsv1.2', 'tlsv1.1', tlsv1, sslv3]).
+
+-define(ALL_DATAGRAM_SUPPORTED_VERSIONS, ['dtlsv1.2']).
-define(MIN_DATAGRAM_SUPPORTED_VERSIONS, [dtlsv1]).
+%% TLS 1.3 - Section 4.1.3
+%%
+%% If negotiating TLS 1.2, TLS 1.3 servers MUST set the last eight bytes
+%% of their Random value to the bytes:
+%%
+%% 44 4F 57 4E 47 52 44 01
+%%
+%% If negotiating TLS 1.1 or below, TLS 1.3 servers MUST and TLS 1.2
+%% servers SHOULD set the last eight bytes of their Random value to the
+%% bytes:
+%%
+%% 44 4F 57 4E 47 52 44 00
+-define(RANDOM_OVERRIDE_TLS12, <<16#44,16#4F,16#57,16#4E,16#47,16#52,16#44,16#01>>).
+-define(RANDOM_OVERRIDE_TLS11, <<16#44,16#4F,16#57,16#4E,16#47,16#52,16#44,16#00>>).
+
-define('24H_in_msec', 86400000).
-define('24H_in_sec', 86400).
-record(ssl_options, {
- protocol :: tls | dtls,
- versions :: [ssl_record:ssl_version()], %% ssl_record:atom_version() in API
- verify :: verify_none | verify_peer,
+ protocol :: tls | dtls | 'undefined',
+ versions :: [ssl_record:ssl_version()] | 'undefined', %% ssl_record:atom_version() in API
+ verify :: verify_none | verify_peer | 'undefined',
verify_fun, %%:: fun(CertVerifyErrors::term()) -> boolean(),
- partial_chain :: fun(),
- fail_if_no_peer_cert :: boolean(),
- verify_client_once :: boolean(),
+ partial_chain :: fun() | 'undefined',
+ fail_if_no_peer_cert :: boolean() | 'undefined',
+ verify_client_once :: boolean() | 'undefined',
%% fun(Extensions, State, Verify, AccError) -> {Extensions, State, AccError}
validate_extensions_fun,
- depth :: integer(),
- certfile :: binary(),
+ depth :: integer() | 'undefined',
+ certfile :: binary() | 'undefined',
cert :: public_key:der_encoded() | secret_printout() | 'undefined',
- keyfile :: binary(),
- key :: {'RSAPrivateKey' | 'DSAPrivateKey' | 'ECPrivateKey' | 'PrivateKeyInfo',
- public_key:der_encoded()} | key_map() | secret_printout() | 'undefined',
+ keyfile :: binary() | 'undefined',
+ key :: {'RSAPrivateKey' | 'DSAPrivateKey' | 'ECPrivateKey' | 'PrivateKeyInfo' | 'undefined',
+ public_key:der_encoded()} | map() %%map() -> ssl:key() how to handle dialyzer?
+ | secret_printout() | 'undefined',
password :: string() | secret_printout() | 'undefined',
cacerts :: [public_key:der_encoded()] | secret_printout() | 'undefined',
- cacertfile :: binary(),
- dh :: public_key:der_encoded() | secret_printout(),
+ cacertfile :: binary() | 'undefined',
+ dh :: public_key:der_encoded() | secret_printout() | 'undefined',
dhfile :: binary() | secret_printout() | 'undefined',
user_lookup_fun, % server option, fun to lookup the user
psk_identity :: binary() | secret_printout() | 'undefined',
@@ -109,26 +137,26 @@
%% Local policy for the server if it want's to reuse the session
%% or not. Defaluts to allways returning true.
%% fun(SessionId, PeerCert, Compression, CipherSuite) -> boolean()
- reuse_session,
+ reuse_session :: fun() | binary() | undefined, %% Server side is a fun()
%% If false sessions will never be reused, if true they
%% will be reused if possible.
- reuse_sessions :: boolean(),
+ reuse_sessions :: boolean() | save | 'undefined', %% Only client side can use value save
renegotiate_at,
secure_renegotiate,
client_renegotiation,
%% undefined if not hibernating, or number of ms of
%% inactivity after which ssl_connection will go into
%% hibernation
- hibernate_after :: timeout(),
+ hibernate_after :: timeout() | 'undefined',
%% This option should only be set to true by inet_tls_dist
erl_dist = false :: boolean(),
- alpn_advertised_protocols = undefined :: [binary()] | undefined ,
+ alpn_advertised_protocols = undefined :: [binary()] | undefined,
alpn_preferred_protocols = undefined :: [binary()] | undefined,
next_protocols_advertised = undefined :: [binary()] | undefined,
next_protocol_selector = undefined, %% fun([binary()]) -> binary())
- log_alert :: boolean(),
+ log_level = notice :: atom(),
server_name_indication = undefined,
- sni_hosts :: [{inet:hostname(), [tuple()]}],
+ sni_hosts :: [{inet:hostname(), [tuple()]}] | 'undefined',
sni_fun :: function() | undefined,
%% Should the server prefer its own cipher order over the one provided by
%% the client?
@@ -138,13 +166,18 @@
%%mitigation entirely?
beast_mitigation = one_n_minus_one :: one_n_minus_one | zero_n | disabled,
fallback = false :: boolean(),
- crl_check :: boolean() | peer | best_effort,
+ crl_check :: boolean() | peer | best_effort | 'undefined',
crl_cache,
signature_algs,
+ signature_algs_cert,
eccs,
- honor_ecc_order :: boolean(),
- v2_hello_compatible :: boolean(),
- max_handshake_size :: integer()
+ supported_groups, %% RFC 8422, RFC 8446
+ honor_ecc_order :: boolean() | 'undefined',
+ max_handshake_size :: integer() | 'undefined',
+ handshake,
+ customize_hostname_check
+ %% ,
+ %% save_session :: boolean()
}).
-record(socket_options,
@@ -159,25 +192,18 @@
-record(config, {ssl, %% SSL parameters
inet_user, %% User set inet options
emulated, %% Emulated option list or "inherit_tracker" pid
- udp_handler,
+ dtls_handler,
inet_ssl, %% inet options for internal ssl socket
transport_info, %% Callback info
connection_cb
}).
--type key_map() :: #{algorithm := rsa | dss | ecdsa,
- %% engine and key_id ought to
- %% be :=, but putting it in
- %% the spec gives dialyzer warning
- %% of correct code!
- engine => crypto:engine_ref(),
- key_id => crypto:key_id(),
- password => crypto:password()
- }.
-type state_name() :: hello | abbreviated | certify | cipher | connection.
--type gen_fsm_state_return() :: {next_state, state_name(), term()} |
- {next_state, state_name(), term(), timeout()} |
- {stop, term(), term()}.
+-type gen_fsm_state_return() :: {next_state, state_name(), any()} |
+ {next_state, state_name(), any(), timeout()} |
+ {stop, any(), any()}.
+-type ssl_options() :: #ssl_options{}.
+
-endif. % -ifdef(ssl_internal).
diff --git a/lib/ssl/src/ssl_logger.erl b/lib/ssl/src/ssl_logger.erl
new file mode 100644
index 0000000000..987693b96b
--- /dev/null
+++ b/lib/ssl/src/ssl_logger.erl
@@ -0,0 +1,446 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(ssl_logger).
+
+-export([debug/4,
+ format/2,
+ notice/2]).
+
+-define(DEC2HEX(X),
+ if ((X) >= 0) andalso ((X) =< 9) -> (X) + $0;
+ ((X) >= 10) andalso ((X) =< 15) -> (X) + $a - 10
+ end).
+
+-define(rec_info(T,R),lists:zip(record_info(fields,T),tl(tuple_to_list(R)))).
+
+-include("tls_record.hrl").
+-include("ssl_cipher.hrl").
+-include("ssl_internal.hrl").
+-include("tls_handshake.hrl").
+-include("dtls_handshake.hrl").
+-include("tls_handshake_1_3.hrl").
+-include_lib("kernel/include/logger.hrl").
+
+%%-------------------------------------------------------------------------
+%% External API
+%%-------------------------------------------------------------------------
+
+%% SSL log formatter
+format(#{level:= _Level, msg:= {report, Msg}, meta:= _Meta}, _Config0) ->
+ #{direction := Direction,
+ protocol := Protocol,
+ message := Content} = Msg,
+ case Protocol of
+ 'record' ->
+ BinMsg =
+ case Content of
+ #ssl_tls{} ->
+ [tls_record:build_tls_record(Content)];
+ _ when is_list(Content) ->
+ lists:flatten(Content)
+ end,
+ format_tls_record(Direction, BinMsg);
+ 'handshake' ->
+ format_handshake(Direction, Content);
+ _Other ->
+ []
+ end.
+
+%% Stateful logging
+debug(Level, Direction, Protocol, Message)
+ when (Direction =:= inbound orelse Direction =:= outbound) andalso
+ (Protocol =:= 'record' orelse Protocol =:= 'handshake') ->
+ case logger:compare_levels(Level, debug) of
+ lt ->
+ ?LOG_DEBUG(#{direction => Direction,
+ protocol => Protocol,
+ message => Message},
+ #{domain => [otp,ssl,Protocol]});
+ eq ->
+ ?LOG_DEBUG(#{direction => Direction,
+ protocol => Protocol,
+ message => Message},
+ #{domain => [otp,ssl,Protocol]});
+ _ ->
+ ok
+ end.
+
+%% Stateful logging
+notice(Level, Report) ->
+ case logger:compare_levels(Level, notice) of
+ lt ->
+ ?LOG_NOTICE(Report);
+ eq ->
+ ?LOG_NOTICE(Report);
+ _ ->
+ ok
+ end.
+
+
+%%-------------------------------------------------------------------------
+%% Handshake Protocol
+%%-------------------------------------------------------------------------
+format_handshake(Direction, BinMsg) ->
+ {Header, Message} = parse_handshake(Direction, BinMsg),
+ io_lib:format("~s~n~s~n", [Header, Message]).
+
+
+parse_handshake(Direction, #client_hello{
+ client_version = Version0,
+ cipher_suites = CipherSuites0,
+ extensions = Extensions
+ } = ClientHello) ->
+ Version = get_client_version(Version0, Extensions),
+ Header = io_lib:format("~s ~s Handshake, ClientHello",
+ [header_prefix(Direction),
+ version(Version)]),
+ CipherSuites = parse_cipher_suites(CipherSuites0),
+ Message = io_lib:format("~p",
+ [?rec_info(client_hello,
+ ClientHello#client_hello{cipher_suites = CipherSuites})]),
+ {Header, Message};
+parse_handshake(Direction, #server_hello{
+ server_version = Version0,
+ cipher_suite = CipherSuite0,
+ extensions = Extensions
+ } = ServerHello) ->
+ Version = get_server_version(Version0, Extensions),
+ Header = io_lib:format("~s ~s Handshake, ServerHello",
+ [header_prefix(Direction),
+ version(Version)]),
+ CipherSuite = format_cipher(CipherSuite0),
+ Message = io_lib:format("~p",
+ [?rec_info(server_hello,
+ ServerHello#server_hello{cipher_suite = CipherSuite})]),
+ {Header, Message};
+parse_handshake(Direction, #hello_verify_request{} = HelloVerifyRequest) ->
+ Header = io_lib:format("~s Handshake, HelloVerifyRequest",
+ [header_prefix(Direction)]),
+ Message = io_lib:format("~p", [?rec_info(hello_verify_request, HelloVerifyRequest)]),
+ {Header, Message};
+parse_handshake(Direction, #certificate{} = Certificate) ->
+ Header = io_lib:format("~s Handshake, Certificate",
+ [header_prefix(Direction)]),
+ Message = io_lib:format("~p", [?rec_info(certificate, Certificate)]),
+ {Header, Message};
+parse_handshake(Direction, #server_key_exchange{} = ServerKeyExchange) ->
+ Header = io_lib:format("~s Handshake, ServerKeyExchange",
+ [header_prefix(Direction)]),
+ Message = io_lib:format("~p", [?rec_info(server_key_exchange, ServerKeyExchange)]),
+ {Header, Message};
+parse_handshake(Direction, #server_key_params{} = ServerKeyExchange) ->
+ Header = io_lib:format("~s Handshake, ServerKeyExchange",
+ [header_prefix(Direction)]),
+ Message = io_lib:format("~p", [?rec_info(server_key_params, ServerKeyExchange)]),
+ {Header, Message};
+parse_handshake(Direction, #certificate_request{} = CertificateRequest) ->
+ Header = io_lib:format("~s Handshake, CertificateRequest",
+ [header_prefix(Direction)]),
+ Message = io_lib:format("~p", [?rec_info(certificate_request, CertificateRequest)]),
+ {Header, Message};
+parse_handshake(Direction, #server_hello_done{} = ServerHelloDone) ->
+ Header = io_lib:format("~s Handshake, ServerHelloDone",
+ [header_prefix(Direction)]),
+ Message = io_lib:format("~p", [?rec_info(server_hello_done, ServerHelloDone)]),
+ {Header, Message};
+parse_handshake(Direction, #client_key_exchange{} = ClientKeyExchange) ->
+ Header = io_lib:format("~s Handshake, ClientKeyExchange",
+ [header_prefix(Direction)]),
+ Message = io_lib:format("~p", [?rec_info(client_key_exchange, ClientKeyExchange)]),
+ {Header, Message};
+parse_handshake(Direction, #certificate_verify{} = CertificateVerify) ->
+ Header = io_lib:format("~s Handshake, CertificateVerify",
+ [header_prefix(Direction)]),
+ Message = io_lib:format("~p", [?rec_info(certificate_verify, CertificateVerify)]),
+ {Header, Message};
+parse_handshake(Direction, #finished{} = Finished) ->
+ Header = io_lib:format("~s Handshake, Finished",
+ [header_prefix(Direction)]),
+ Message = io_lib:format("~p", [?rec_info(finished, Finished)]),
+ {Header, Message};
+parse_handshake(Direction, #hello_request{} = HelloRequest) ->
+ Header = io_lib:format("~s Handshake, HelloRequest",
+ [header_prefix(Direction)]),
+ Message = io_lib:format("~p", [?rec_info(hello_request, HelloRequest)]),
+ {Header, Message};
+parse_handshake(Direction, #certificate_request_1_3{} = CertificateRequest) ->
+ Header = io_lib:format("~s Handshake, CertificateRequest",
+ [header_prefix(Direction)]),
+ Message = io_lib:format("~p", [?rec_info(certificate_request_1_3, CertificateRequest)]),
+ {Header, Message};
+parse_handshake(Direction, #certificate_1_3{} = Certificate) ->
+ Header = io_lib:format("~s Handshake, Certificate",
+ [header_prefix(Direction)]),
+ Message = io_lib:format("~p", [?rec_info(certificate_1_3, Certificate)]),
+ {Header, Message};
+parse_handshake(Direction, #certificate_verify_1_3{} = CertificateVerify) ->
+ Header = io_lib:format("~s Handshake, CertificateVerify",
+ [header_prefix(Direction)]),
+ Message = io_lib:format("~p", [?rec_info(certificate_verify_1_3, CertificateVerify)]),
+ {Header, Message};
+parse_handshake(Direction, #encrypted_extensions{} = EncryptedExtensions) ->
+ Header = io_lib:format("~s Handshake, EncryptedExtensions",
+ [header_prefix(Direction)]),
+ Message = io_lib:format("~p", [?rec_info(encrypted_extensions, EncryptedExtensions)]),
+ {Header, Message}.
+
+
+parse_cipher_suites([_|_] = Ciphers) ->
+ [format_cipher(C) || C <- Ciphers].
+
+format_cipher(C0) ->
+ try ssl_cipher_format:suite_bin_to_map(C0) of
+ Map ->
+ ssl_cipher_format:suite_map_to_str(Map)
+ catch
+ error:function_clause ->
+ format_uknown_cipher_suite(C0)
+ end.
+
+get_client_version(Version, Extensions) ->
+ CHVersions = maps:get(client_hello_versions, Extensions, undefined),
+ case CHVersions of
+ #client_hello_versions{versions = [Highest|_]} ->
+ Highest;
+ undefined ->
+ Version
+ end.
+
+get_server_version(Version, Extensions) ->
+ SHVersion = maps:get(server_hello_selected_version, Extensions, undefined),
+ case SHVersion of
+ #server_hello_selected_version{selected_version = SelectedVersion} ->
+ SelectedVersion;
+ undefined ->
+ Version
+ end.
+
+version({3,4}) ->
+ "TLS 1.3";
+version({3,3}) ->
+ "TLS 1.2";
+version({3,2}) ->
+ "TLS 1.1";
+version({3,1}) ->
+ "TLS 1.0";
+version({3,0}) ->
+ "SSL 3.0";
+version({254,253}) ->
+ "DTLS 1.2";
+version({254,255}) ->
+ "DTLS 1.0";
+version({M,N}) ->
+ io_lib:format("TLS/DTLS [0x0~B0~B]", [M,N]).
+
+header_prefix(inbound) ->
+ "<<<";
+header_prefix(outbound) ->
+ ">>>".
+
+
+%%-------------------------------------------------------------------------
+%% TLS Record Protocol
+%%-------------------------------------------------------------------------
+format_tls_record(Direction, BinMsg) ->
+ {Message, Size} = convert_to_hex('tls_record', BinMsg),
+ Header = io_lib:format("~s (~B bytes) ~s~n",
+ [header_prefix_tls_record(Direction),
+ Size,
+ tls_record_version(BinMsg)]),
+ Header ++ Message.
+
+
+header_prefix_tls_record(inbound) ->
+ "reading";
+header_prefix_tls_record(outbound) ->
+ "writing".
+
+
+tls_record_version([<<?BYTE(B),?BYTE(3),?BYTE(3),_/binary>>|_]) ->
+ io_lib:format("TLS 1.2 Record Protocol, ~s", [msg_type(B)]);
+tls_record_version([<<?BYTE(B),?BYTE(3),?BYTE(2),_/binary>>|_]) ->
+ io_lib:format("TLS 1.1 Record Protocol, ~s", [msg_type(B)]);
+tls_record_version([<<?BYTE(B),?BYTE(3),?BYTE(1),_/binary>>|_]) ->
+ io_lib:format("TLS 1.0 Record Protocol, ~s", [msg_type(B)]);
+tls_record_version([<<?BYTE(B),?BYTE(3),?BYTE(0),_/binary>>|_]) ->
+ io_lib:format("SSL 3.0 Record Protocol, ~s", [msg_type(B)]);
+tls_record_version([<<?BYTE(B),?BYTE(254),?BYTE(253),_/binary>>|_]) ->
+ io_lib:format("DTLS 1.2 Record Protocol, ~s", [msg_type(B)]);
+tls_record_version([<<?BYTE(B),?BYTE(254),?BYTE(255),_/binary>>|_]) ->
+ io_lib:format("DTLS 1.0 Record Protocol, ~s", [msg_type(B)]);
+tls_record_version([<<?BYTE(B),?BYTE(M),?BYTE(N),_/binary>>|_]) ->
+ io_lib:format("TLS/DTLS [0x0~B0~B] Record Protocol, ~s", [M, N, msg_type(B)]).
+
+
+msg_type(20) -> "change_cipher_spec";
+msg_type(21) -> "alert";
+msg_type(22) -> "handshake";
+msg_type(23) -> "application_data";
+msg_type(_) -> unknown.
+
+
+%%-------------------------------------------------------------------------
+%% Hex encoding functions
+%%-------------------------------------------------------------------------
+convert_to_hex(Protocol, BinMsg) ->
+ convert_to_hex(Protocol, BinMsg, [], [], 0).
+%%
+convert_to_hex(P, [], Row0, Acc, C) when C rem 16 =:= 0 ->
+ Row = lists:reverse(end_row(P, Row0)),
+ {lists:reverse(Acc) ++ Row ++ io_lib:nl(), C};
+convert_to_hex(P, [], Row0, Acc, C) ->
+ Row = lists:reverse(end_row(P, Row0)),
+ Padding = calculate_padding(Row0, Acc),
+ PaddedRow = string:pad(Row, Padding, leading, $ ),
+ {lists:reverse(Acc) ++ PaddedRow ++ io_lib:nl(), C};
+convert_to_hex(P, [H|T], Row, Acc, C) when is_list(H) ->
+ convert_to_hex(P, H ++ T, Row, Acc, C);
+convert_to_hex(P, [<<>>|T], Row, Acc, C) ->
+ convert_to_hex(P, T, Row, Acc, C);
+
+%% First line
+convert_to_hex(P, [<<A:4,B:4,R/binary>>|T], Row, Acc, C) when C =:= 0 ->
+ convert_to_hex(P, [<<R/binary>>|T],
+ update_row(<<A:4,B:4>>, Row),
+ prepend_first_row(P, A, B, Acc, C),
+ C + 1);
+%% New line
+convert_to_hex(P, [<<A:4,B:4,R/binary>>|T], Row, Acc, C) when C rem 16 =:= 0 ->
+ convert_to_hex(P, [<<R/binary>>|T],
+ update_row(<<A:4,B:4>>, []),
+ prepend_row(P, A, B, Row, Acc, C),
+ C + 1);
+%% Add 8th hex with extra whitespace
+%% 0000 - 16 03 02 00 bd 01 00 00 b9 ...
+%% ^^^^
+convert_to_hex(P, [<<A:4,B:4,R/binary>>|T], Row, Acc, C) when C rem 8 =:= 7 ->
+ convert_to_hex(P, [<<R/binary>>|T],
+ update_row(<<A:4,B:4>>, Row),
+ prepend_eighths_hex(A, B, Acc),
+ C + 1);
+convert_to_hex(P, [<<A:4,B:4,R/binary>>|T], Row, Acc, C) ->
+ convert_to_hex(P, [<<R/binary>>|T],
+ update_row(<<A:4,B:4>>, Row),
+ prepend_hex(A, B, Acc),
+ C + 1);
+%% First line
+convert_to_hex(P, [H|T], Row, Acc, C) when is_integer(H), C =:= 0 ->
+ convert_to_hex(P, T,
+ update_row(H, Row),
+ prepend_first_row(P, H, Acc, C),
+ C + 1);
+%% New line
+convert_to_hex(P, [H|T], Row, Acc, C) when is_integer(H), C rem 16 =:= 0 ->
+ convert_to_hex(P, T,
+ update_row(H, []),
+ prepend_row(P, H, Row, Acc, C),
+ C + 1);
+%% Add 8th hex with extra whitespace
+%% 0000 - 16 03 02 00 bd 01 00 00 b9 ...
+%% ^^^^
+convert_to_hex(P, [H|T], Row, Acc, C) when is_integer(H), C rem 8 =:= 7 ->
+ convert_to_hex(P, T,
+ update_row(H, Row),
+ prepend_eighths_hex(H, Acc),
+ C + 1);
+convert_to_hex(P, [H|T], Row, Acc, C) when is_integer(H) ->
+ convert_to_hex(P, T,
+ update_row(H, Row),
+ prepend_hex(H, Acc),
+ C + 1).
+
+
+row_prefix(_ , N) ->
+ S = string:pad(string:to_lower(erlang:integer_to_list(N, 16)),4,leading,$0),
+ lists:reverse(lists:flatten(S ++ " - ")).
+
+
+end_row(_, Row) ->
+ Row ++ " ".
+
+
+%% Calculate padding of the "printable character" lines in order to be
+%% visually aligned.
+calculate_padding(Row, Acc) ->
+ %% Number of new line characters
+ NNL = (length(Acc) div 75) * length(io_lib:nl()),
+ %% Length of the last printed line
+ Length = (length(Acc) - NNL) rem 75,
+ %% Adjusted length of the last printed line
+ PaddedLength = 75 - (16 - length(Row)), %% Length
+ %% Padding
+ PaddedLength - Length.
+
+
+%%-------------------------------------------------------------------------
+%% Functions operating on reversed lists
+%%-------------------------------------------------------------------------
+update_row(B, Row) when is_binary(B) ->
+ case binary_to_list(B) of
+ [C] when 32 =< C, C =< 126 ->
+ [C|Row];
+ _Else ->
+ [$.|Row]
+ end;
+update_row(C, Row) when 32 =< C, C =< 126 ->
+ [C|Row];
+update_row(_, Row) ->
+ [$.|Row].
+
+
+prepend_first_row(P, A, B, Acc, C) ->
+ prepend_hex(A, B,row_prefix(P, C) ++ Acc).
+%%
+prepend_first_row(P, N, Acc, C) ->
+ prepend_hex(N,row_prefix(P, C) ++ Acc).
+
+prepend_row(P, A, B, Row, Acc, C) ->
+ prepend_hex(A, B,row_prefix(P, C) ++ io_lib:nl() ++ end_row(P, Row) ++ Acc).
+%%
+prepend_row(P, N, Row, Acc, C) ->
+ prepend_hex(N,row_prefix(P, C) ++ io_lib:nl() ++ end_row(P, Row) ++ Acc).
+
+
+
+prepend_hex(A, B, Acc) ->
+ [$ ,?DEC2HEX(B),?DEC2HEX(A)|Acc].
+%%
+prepend_hex(N, Acc) ->
+ " " ++ number_to_hex(N) ++ Acc.
+
+
+prepend_eighths_hex(A, B, Acc) ->
+ [$ ,$ ,?DEC2HEX(B),?DEC2HEX(A)|Acc].
+%%
+prepend_eighths_hex(N, Acc) ->
+ " " ++ number_to_hex(N) ++ Acc.
+
+number_to_hex(N) ->
+ case string:to_lower(erlang:integer_to_list(N, 16)) of
+ H when length(H) < 2 ->
+ lists:append(H, "0");
+ H ->
+ lists:reverse(H)
+ end.
+
+format_uknown_cipher_suite(<<?BYTE(X), ?BYTE(Y)>>) ->
+ "0x" ++ number_to_hex(X) ++ "0x" ++ number_to_hex(Y).
+
diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl
index f44fe6a2bf..456a560bf6 100644
--- a/lib/ssl/src/ssl_manager.erl
+++ b/lib/ssl/src/ssl_manager.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -30,7 +30,7 @@
connection_init/3, cache_pem_file/2,
lookup_trusted_cert/4,
new_session_id/1, clean_cert_db/2,
- register_session/2, register_session/3, invalidate_session/2,
+ register_session/2, register_session/4, invalidate_session/2,
insert_crls/2, insert_crls/3, delete_crls/1, delete_crls/2,
invalidate_session/3, name/1]).
@@ -42,6 +42,8 @@
-include("ssl_handshake.hrl").
-include("ssl_internal.hrl").
+-include("ssl_api.hrl").
+
-include_lib("kernel/include/file.hrl").
-record(state, {
@@ -127,7 +129,13 @@ cache_pem_file(File, DbHandle) ->
[Content] ->
{ok, Content};
undefined ->
- ssl_pem_cache:insert(File)
+ case ssl_pkix_db:decode_pem_file(File) of
+ {ok, Content} ->
+ ssl_pem_cache:insert(File, Content),
+ {ok, Content};
+ Error ->
+ Error
+ end
end.
%%--------------------------------------------------------------------
@@ -142,7 +150,7 @@ lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer) ->
ssl_pkix_db:lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer).
%%--------------------------------------------------------------------
--spec new_session_id(integer()) -> session_id().
+-spec new_session_id(integer()) -> ssl:session_id().
%%
%% Description: Creates a session id for the server.
%%--------------------------------------------------------------------
@@ -164,9 +172,11 @@ clean_cert_db(Ref, File) ->
%%
%% Description: Make the session available for reuse.
%%--------------------------------------------------------------------
--spec register_session(host(), inet:port_number(), #session{}) -> ok.
-register_session(Host, Port, Session) ->
- cast({register_session, Host, Port, Session}).
+-spec register_session(ssl:host(), inet:port_number(), #session{}, unique | true) -> ok.
+register_session(Host, Port, Session, true) ->
+ call({register_session, Host, Port, Session});
+register_session(Host, Port, Session, unique = Save) ->
+ cast({register_session, Host, Port, Session, Save}).
-spec register_session(inet:port_number(), #session{}) -> ok.
register_session(Port, Session) ->
@@ -177,7 +187,7 @@ register_session(Port, Session) ->
%% a the session has been marked "is_resumable = false" for some while
%% it will be safe to remove the data from the session database.
%%--------------------------------------------------------------------
--spec invalidate_session(host(), inet:port_number(), #session{}) -> ok.
+-spec invalidate_session(ssl:host(), inet:port_number(), #session{}) -> ok.
invalidate_session(Host, Port, Session) ->
load_mitigation(),
cast({invalidate_session, Host, Port, Session}).
@@ -295,7 +305,10 @@ handle_call({{new_session_id, Port}, _},
_, #state{session_cache_cb = CacheCb,
session_cache_server = Cache} = State) ->
Id = new_id(Port, ?GEN_UNIQUE_ID_MAX_TRIES, Cache, CacheCb),
- {reply, Id, State}.
+ {reply, Id, State};
+handle_call({{register_session, Host, Port, Session},_}, _, State0) ->
+ State = client_register_session(Host, Port, Session, State0),
+ {reply, ok, State}.
%%--------------------------------------------------------------------
-spec handle_cast(msg(), #state{}) -> {noreply, #state{}}.
@@ -305,8 +318,12 @@ handle_call({{new_session_id, Port}, _},
%%
%% Description: Handling cast messages
%%--------------------------------------------------------------------
-handle_cast({register_session, Host, Port, Session}, State0) ->
- State = ssl_client_register_session(Host, Port, Session, State0),
+handle_cast({register_session, Host, Port, Session, unique}, State0) ->
+ State = client_register_unique_session(Host, Port, Session, State0),
+ {noreply, State};
+
+handle_cast({register_session, Host, Port, Session, true}, State0) ->
+ State = client_register_session(Host, Port, Session, State0),
{noreply, State};
handle_cast({register_session, Port, Session}, State0) ->
@@ -499,10 +516,10 @@ last_delay_timer({{_,_},_}, TRef, {LastServer, _}) ->
last_delay_timer({_,_}, TRef, {_, LastClient}) ->
{TRef, LastClient}.
-%% If we can not generate a not allready in use session ID in
+%% If we cannot generate a not allready in use session ID in
%% ?GEN_UNIQUE_ID_MAX_TRIES we make the new session uncacheable The
%% value of ?GEN_UNIQUE_ID_MAX_TRIES is stolen from open SSL which
-%% states : "If we can not find a session id in
+%% states : "If we cannot find a session id in
%% ?GEN_UNIQUE_ID_MAX_TRIES either the RAND code is broken or someone
%% is trying to open roughly very close to 2^128 (or 2^256) SSL
%% sessions to our server"
@@ -513,7 +530,7 @@ new_id(Port, Tries, Cache, CacheCb) ->
case CacheCb:lookup(Cache, {Port, Id}) of
undefined ->
Now = erlang:monotonic_time(),
- %% New sessions can not be set to resumable
+ %% New sessions cannot be set to resumable
%% until handshake is compleate and the
%% other session values are set.
CacheCb:update(Cache, {Port, Id}, #session{session_id = Id,
@@ -534,10 +551,10 @@ clean_cert_db(Ref, CertDb, RefDb, FileMapDb, File) ->
ok
end.
-ssl_client_register_session(Host, Port, Session, #state{session_cache_client = Cache,
- session_cache_cb = CacheCb,
- session_cache_client_max = Max,
- session_client_invalidator = Pid0} = State) ->
+client_register_unique_session(Host, Port, Session, #state{session_cache_client = Cache,
+ session_cache_cb = CacheCb,
+ session_cache_client_max = Max,
+ session_client_invalidator = Pid0} = State) ->
TimeStamp = erlang:monotonic_time(),
NewSession = Session#session{time_stamp = TimeStamp},
@@ -551,6 +568,17 @@ ssl_client_register_session(Host, Port, Session, #state{session_cache_client = C
register_unique_session(Sessions, NewSession, {Host, Port}, State)
end.
+client_register_session(Host, Port, Session, #state{session_cache_client = Cache,
+ session_cache_cb = CacheCb,
+ session_cache_client_max = Max,
+ session_client_invalidator = Pid0} = State) ->
+ TimeStamp = erlang:monotonic_time(),
+ NewSession = Session#session{time_stamp = TimeStamp},
+ Pid = do_register_session({{Host, Port},
+ NewSession#session.session_id},
+ NewSession, Max, Pid0, Cache, CacheCb),
+ State#state{session_client_invalidator = Pid}.
+
server_register_session(Port, Session, #state{session_cache_server_max = Max,
session_cache_server = Cache,
session_cache_cb = CacheCb,
diff --git a/lib/ssl/src/ssl_pem_cache.erl b/lib/ssl/src/ssl_pem_cache.erl
index 115ab4451d..41bca2f7b5 100644
--- a/lib/ssl/src/ssl_pem_cache.erl
+++ b/lib/ssl/src/ssl_pem_cache.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 20016-2017. All Rights Reserved.
+%% Copyright Ericsson AB 20016-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@
-export([start_link/1,
start_link_dist/1,
name/1,
- insert/1,
+ insert/2,
clear/0]).
% Spawn export
@@ -45,7 +45,7 @@
-record(state, {
pem_cache,
- last_pem_check :: erlang:timestamp(),
+ last_pem_check :: integer(),
clear :: integer()
}).
@@ -90,19 +90,17 @@ start_link_dist(_) ->
%%--------------------------------------------------------------------
--spec insert(binary()) -> {ok, term()} | {error, reason()}.
+-spec insert(binary(), term()) -> ok | {error, reason()}.
%%
%% Description: Cache a pem file and return its content.
%%--------------------------------------------------------------------
-insert(File) ->
- {ok, PemBin} = file:read_file(File),
- Content = public_key:pem_decode(PemBin),
+insert(File, Content) ->
case bypass_cache() of
true ->
- {ok, Content};
+ ok;
false ->
cast({cache_pem, File, Content}),
- {ok, Content}
+ ok
end.
%%--------------------------------------------------------------------
@@ -136,8 +134,9 @@ init([Name]) ->
PemCache = ssl_pkix_db:create_pem_cache(Name),
Interval = pem_check_interval(),
erlang:send_after(Interval, self(), clear_pem_cache),
+ erlang:system_time(second),
{ok, #state{pem_cache = PemCache,
- last_pem_check = os:timestamp(),
+ last_pem_check = erlang:convert_time_unit(os:system_time(), native, second),
clear = Interval
}}.
@@ -185,7 +184,7 @@ handle_cast({invalidate_pem, File}, #state{pem_cache = Db} = State) ->
handle_info(clear_pem_cache, #state{pem_cache = PemCache,
clear = Interval,
last_pem_check = CheckPoint} = State) ->
- NewCheckPoint = os:timestamp(),
+ NewCheckPoint = erlang:convert_time_unit(os:system_time(), native, second),
start_pem_cache_validator(PemCache, CheckPoint),
erlang:send_after(Interval, self(), clear_pem_cache),
{noreply, State#state{last_pem_check = NewCheckPoint}};
@@ -231,24 +230,14 @@ init_pem_cache_validator([CacheName, PemCache, CheckPoint]) ->
CheckPoint, PemCache).
pem_cache_validate({File, _}, CheckPoint) ->
- case file:read_file_info(File, []) of
- {ok, #file_info{mtime = Time}} ->
- case is_before_checkpoint(Time, CheckPoint) of
- true ->
- ok;
- false ->
- invalidate_pem(File)
- end;
+ case file:read_file_info(File, [{time, posix}]) of
+ {ok, #file_info{mtime = Time}} when Time < CheckPoint ->
+ ok;
_ ->
invalidate_pem(File)
end,
CheckPoint.
-is_before_checkpoint(Time, CheckPoint) ->
- calendar:datetime_to_gregorian_seconds(
- calendar:now_to_datetime(CheckPoint)) -
- calendar:datetime_to_gregorian_seconds(Time) > 0.
-
pem_check_interval() ->
case application:get_env(ssl, ssl_pem_cache_clean) of
{ok, Interval} when is_integer(Interval) ->
diff --git a/lib/ssl/src/ssl_pkix_db.erl b/lib/ssl/src/ssl_pkix_db.erl
index 8828c3a0d8..dec48fa914 100644
--- a/lib/ssl/src/ssl_pkix_db.erl
+++ b/lib/ssl/src/ssl_pkix_db.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@
-include("ssl_internal.hrl").
-include_lib("public_key/include/public_key.hrl").
-include_lib("kernel/include/file.hrl").
+-include_lib("kernel/include/logger.hrl").
-export([create/1, create_pem_cache/1,
add_crls/3, remove_crls/2, remove/1, add_trusted_certs/3,
@@ -157,7 +158,7 @@ extract_trusted_certs(File) ->
{error, {badmatch, Error}}
end.
--spec decode_pem_file(binary()) -> {ok, term()}.
+-spec decode_pem_file(binary()) -> {ok, term()} | {error, term()}.
decode_pem_file(File) ->
case file:read_file(File) of
{ok, PemBin} ->
@@ -311,16 +312,21 @@ decode_certs(Ref, Cert) ->
error:_ ->
Report = io_lib:format("SSL WARNING: Ignoring a CA cert as "
"it could not be correctly decoded.~n", []),
- error_logger:info_report(Report),
+ ?LOG_NOTICE(Report),
undefined
end.
new_trusted_cert_entry(File, [CertsDb, RefsDb, _ | _]) ->
- Ref = make_ref(),
- init_ref_db(Ref, File, RefsDb),
- {ok, Content} = ssl_pem_cache:insert(File),
- add_certs_from_pem(Content, Ref, CertsDb),
- {ok, Ref}.
+ case decode_pem_file(File) of
+ {ok, Content} ->
+ Ref = make_ref(),
+ init_ref_db(Ref, File, RefsDb),
+ ok = ssl_pem_cache:insert(File, Content),
+ add_certs_from_pem(Content, Ref, CertsDb),
+ {ok, Ref};
+ Error ->
+ Error
+ end.
add_crls([_,_,_, {_, Mapping} | _], ?NO_DIST_POINT, CRLs) ->
[add_crls(CRL, Mapping) || CRL <- CRLs];
diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl
index dd6a3e8521..867d2cfc5a 100644
--- a/lib/ssl/src/ssl_record.erl
+++ b/lib/ssl/src/ssl_record.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
-module(ssl_record).
-include("ssl_record.hrl").
+-include("ssl_connection.hrl").
-include("ssl_internal.hrl").
-include("ssl_cipher.hrl").
-include("ssl_alert.hrl").
@@ -39,20 +40,23 @@
set_renegotiation_flag/2,
set_client_verify_data/3,
set_server_verify_data/3,
- empty_connection_state/2, initial_connection_state/2, record_protocol_role/1]).
+ empty_connection_state/2, initial_connection_state/2, record_protocol_role/1,
+ step_encryption_state/1]).
%% Compression
-export([compress/3, uncompress/3, compressions/0]).
%% Payload encryption/decryption
--export([cipher/4, decipher/4, cipher_aead/4, is_correct_mac/2]).
+-export([cipher/4, cipher/5, decipher/4,
+ cipher_aead/4, cipher_aead/5, decipher_aead/5,
+ is_correct_mac/2, nonce_seed/3]).
-export_type([ssl_version/0, ssl_atom_version/0, connection_states/0, connection_state/0]).
-type ssl_version() :: {integer(), integer()}.
-type ssl_atom_version() :: tls_record:tls_atom_version().
--type connection_states() :: term(). %% Map
--type connection_state() :: term(). %% Map
+-type connection_states() :: map(). %% Map
+-type connection_state() :: map(). %% Map
%%====================================================================
%% Connection state handling
@@ -118,6 +122,22 @@ activate_pending_connection_state(#{current_write := Current,
}.
%%--------------------------------------------------------------------
+-spec step_encryption_state(#state{}) -> #state{}.
+%%
+%% Description: Activates the next encyrption state (e.g. handshake
+%% encryption).
+%%--------------------------------------------------------------------
+step_encryption_state(#state{connection_states =
+ #{pending_read := PendingRead,
+ pending_write := PendingWrite} = ConnStates} = State) ->
+ NewRead = PendingRead#{sequence_number => 0},
+ NewWrite = PendingWrite#{sequence_number => 0},
+ State#state{connection_states =
+ ConnStates#{current_read => NewRead,
+ current_write => NewWrite}}.
+
+
+%%--------------------------------------------------------------------
-spec set_security_params(#security_parameters{}, #security_parameters{},
connection_states()) -> connection_states().
%%
@@ -278,13 +298,12 @@ compress(?NULL, Data, CS) ->
{Data, CS}.
%%--------------------------------------------------------------------
--spec compressions() -> [binary()].
+-spec compressions() -> [integer()].
%%
%% Description: return a list of compressions supported (currently none)
%%--------------------------------------------------------------------
compressions() ->
- [?byte(?NULL)].
-
+ [?NULL].
%%====================================================================
%% Payload encryption/decryption
@@ -302,31 +321,51 @@ cipher(Version, Fragment,
#security_parameters{bulk_cipher_algorithm =
BulkCipherAlgo}
} = WriteState0, MacHash) ->
-
+ %%
{CipherFragment, CipherS1} =
ssl_cipher:cipher(BulkCipherAlgo, CipherS0, MacHash, Fragment, Version),
{CipherFragment, WriteState0#{cipher_state => CipherS1}}.
+
+%%--------------------------------------------------------------------
+-spec cipher(ssl_version(), iodata(), #cipher_state{}, MacHash::binary(), #security_parameters{}) ->
+ {CipherFragment::binary(), #cipher_state{}}.
+%%
+%% Description: Payload encryption
+%%--------------------------------------------------------------------
+cipher(Version, Fragment, CipherS0, MacHash,
+ #security_parameters{bulk_cipher_algorithm = BulkCipherAlgo}) ->
+ %%
+ ssl_cipher:cipher(BulkCipherAlgo, CipherS0, MacHash, Fragment, Version).
+
+%%--------------------------------------------------------------------
+-spec cipher_aead(ssl_version(), iodata(), connection_state(), AAD::binary()) ->
+ {CipherFragment::binary(), connection_state()}.
+
+%% Description: Payload encryption
%% %%--------------------------------------------------------------------
-%% -spec cipher_aead(ssl_version(), iodata(), connection_state(), MacHash::binary()) ->
-%% {CipherFragment::binary(), connection_state()}.
-%% %%
-%% %% Description: Payload encryption
-%% %%--------------------------------------------------------------------
-cipher_aead(Version, Fragment,
+cipher_aead(_Version, Fragment,
#{cipher_state := CipherS0,
- sequence_number := SeqNo,
security_parameters :=
#security_parameters{bulk_cipher_algorithm =
BulkCipherAlgo}
} = WriteState0, AAD) ->
-
{CipherFragment, CipherS1} =
- ssl_cipher:cipher_aead(BulkCipherAlgo, CipherS0, SeqNo, AAD, Fragment, Version),
+ do_cipher_aead(BulkCipherAlgo, Fragment, CipherS0, AAD),
{CipherFragment, WriteState0#{cipher_state => CipherS1}}.
%%--------------------------------------------------------------------
+-spec cipher_aead(ssl_version(), iodata(), #cipher_state{}, AAD::binary(), #security_parameters{}) ->
+ {CipherFragment::binary(), #cipher_state{}}.
+
+%% Description: Payload encryption
+%% %%--------------------------------------------------------------------
+cipher_aead(_Version, Fragment, CipherS, AAD,
+ #security_parameters{bulk_cipher_algorithm = BulkCipherAlgo}) ->
+ do_cipher_aead(BulkCipherAlgo, Fragment, CipherS, AAD).
+
+%%--------------------------------------------------------------------
-spec decipher(ssl_version(), binary(), connection_state(), boolean()) ->
- {binary(), binary(), connection_state} | #alert{}.
+ {binary(), binary(), connection_state()} | #alert{}.
%%
%% Description: Payload decryption
%%--------------------------------------------------------------------
@@ -344,10 +383,38 @@ decipher(Version, CipherFragment,
#alert{} = Alert ->
Alert
end.
+%%--------------------------------------------------------------------
+-spec decipher_aead(ssl_cipher:cipher_enum(), #cipher_state{}, binary(), binary(), ssl_record:ssl_version()) ->
+ binary() | #alert{}.
+%%
+%% Description: Decrypts the data and checks the associated data (AAD) MAC using
+%% cipher described by cipher_enum() and updating the cipher state.
+%% Use for suites that use authenticated encryption with associated data (AEAD)
+%%-------------------------------------------------------------------
+decipher_aead(Type, #cipher_state{key = Key} = CipherState, AAD0, CipherFragment, _) ->
+ try
+ Nonce = decrypt_nonce(Type, CipherState, CipherFragment),
+ {AAD, CipherText, CipherTag} = aead_ciphertext_split(Type, CipherState, CipherFragment, AAD0),
+ case ssl_cipher:aead_decrypt(Type, Key, Nonce, CipherText, CipherTag, AAD) of
+ Content when is_binary(Content) ->
+ Content;
+ _ ->
+ ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC, decryption_failed)
+ end
+ catch
+ _:_ ->
+ ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC, decryption_failed)
+ end.
+
+nonce_seed(?CHACHA20_POLY1305, Seed, CipherState) ->
+ ssl_cipher:nonce_seed(Seed, CipherState);
+nonce_seed(_,_, CipherState) ->
+ CipherState.
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+
empty_connection_state(ConnectionEnd, BeastMitigation) ->
SecParams = empty_security_params(ConnectionEnd),
#{security_parameters => SecParams,
@@ -372,11 +439,13 @@ random() ->
Random_28_bytes = ssl_cipher:random_bytes(28),
<<?UINT32(Secs_since_1970), Random_28_bytes/binary>>.
+-compile({inline, [is_correct_mac/2]}).
is_correct_mac(Mac, Mac) ->
true;
is_correct_mac(_M,_H) ->
false.
+-compile({inline, [record_protocol_role/1]}).
record_protocol_role(client) ->
?CLIENT;
record_protocol_role(server) ->
@@ -400,3 +469,45 @@ initial_security_params(ConnectionEnd) ->
compression_algorithm = ?NULL},
ssl_cipher:security_parameters(?TLS_NULL_WITH_NULL_NULL, SecParams).
+-define(end_additional_data(AAD, Len), << (begin(AAD)end)/binary, ?UINT16(begin(Len)end) >>).
+
+do_cipher_aead(?CHACHA20_POLY1305 = Type, Fragment, #cipher_state{key=Key, tag_len = TagLen} = CipherState, AAD0) ->
+ AAD = ?end_additional_data(AAD0, erlang:iolist_size(Fragment)),
+ Nonce = chacha_nonce(CipherState),
+ {Content, CipherTag} = ssl_cipher:aead_encrypt(Type, Key, Nonce, Fragment, AAD, TagLen),
+ {<<Content/binary, CipherTag/binary>>, CipherState};
+do_cipher_aead(Type, Fragment, #cipher_state{key=Key, tag_len = TagLen, nonce = ExplicitNonce} = CipherState, AAD0) ->
+ AAD = ?end_additional_data(AAD0, erlang:iolist_size(Fragment)),
+ Nonce = encrypt_nonce(Type, CipherState),
+ {Content, CipherTag} = ssl_cipher:aead_encrypt(Type, Key, Nonce, Fragment, AAD, TagLen),
+ {<<ExplicitNonce:64/integer, Content/binary, CipherTag/binary>>, CipherState#cipher_state{nonce = ExplicitNonce + 1}}.
+
+
+chacha_nonce(#cipher_state{nonce = Nonce, iv = IV}) ->
+ crypto:exor(<<?UINT32(0), Nonce/binary>>, IV).
+
+encrypt_nonce(Type, #cipher_state{iv = IV, nonce = ExplicitNonce}) when Type == ?AES_GCM;
+ Type == ?AES_CCM;
+ Type == ?AES_CCM_8 ->
+ <<Salt:4/bytes, _/binary>> = IV,
+ <<Salt/binary, ExplicitNonce:64/integer>>.
+
+decrypt_nonce(?CHACHA20_POLY1305, CipherState, _) ->
+ chacha_nonce(CipherState);
+decrypt_nonce(Type, #cipher_state{iv = <<Salt:4/bytes, _/binary>>}, <<ExplicitNonce:8/bytes, _/binary>>) when
+ Type == ?AES_GCM;
+ Type == ?AES_CCM;
+ Type == ?AES_CCM_8 ->
+ <<Salt/binary, ExplicitNonce/binary>>.
+
+-compile({inline, [aead_ciphertext_split/4]}).
+aead_ciphertext_split(?CHACHA20_POLY1305, #cipher_state{tag_len = Len}, CipherTextFragment, AAD) ->
+ CipherLen = byte_size(CipherTextFragment) - Len,
+ <<CipherText:CipherLen/bytes, CipherTag:Len/bytes>> = CipherTextFragment,
+ {?end_additional_data(AAD, CipherLen), CipherText, CipherTag};
+aead_ciphertext_split(Type, #cipher_state{tag_len = Len}, CipherTextFragment, AAD) when Type == ?AES_GCM;
+ Type == ?AES_CCM;
+ Type == ?AES_CCM_8 ->
+ CipherLen = byte_size(CipherTextFragment) - (Len + 8), %% 8 is length of explicit Nonce
+ << _:8/bytes, CipherText:CipherLen/bytes, CipherTag:Len/bytes>> = CipherTextFragment,
+ {?end_additional_data(AAD, CipherLen), CipherText, CipherTag}.
diff --git a/lib/ssl/src/ssl_record.hrl b/lib/ssl/src/ssl_record.hrl
index ed007f58d7..6d4d47cedb 100644
--- a/lib/ssl/src/ssl_record.hrl
+++ b/lib/ssl/src/ssl_record.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -74,7 +74,7 @@
-define(INITIAL_BYTES, 5).
-define(MAX_SEQENCE_NUMBER, 18446744073709551615). %% (1 bsl 64) - 1 = 18446744073709551615
-%% Sequence numbers can not wrap so when max is about to be reached we should renegotiate.
+%% Sequence numbers cannot wrap so when max is about to be reached we should renegotiate.
%% We will renegotiate a little before so that there will be sequence numbers left
%% for the rehandshake and a little data. Currently we decided to renegotiate a little more
%% often as we can have a cheaper test to check if it is time to renegotiate. It will still
@@ -96,6 +96,11 @@
-define(AES_CBC, 7).
-define(AES_GCM, 8).
-define(CHACHA20_POLY1305, 9).
+%% Following two are not defined in any RFC but we want to have the
+%% same type of handling internaly, all of these "bulk_cipher_algorithm"
+%% enums are only used internaly anyway.
+-define(AES_CCM, 10).
+-define(AES_CCM_8, 11).
%% CipherType
-define(STREAM, 0).
@@ -140,6 +145,9 @@
-define(ALERT, 21).
-define(HANDSHAKE, 22).
-define(APPLICATION_DATA, 23).
+-define(HEARTBEAT, 24).
+-define(KNOWN_RECORD_TYPE(Type),
+ (is_integer(Type) andalso (20 =< (Type)) andalso ((Type) =< 23))).
-define(MAX_PLAIN_TEXT_LENGTH, 16384).
-define(MAX_COMPRESSED_LENGTH, (?MAX_PLAIN_TEXT_LENGTH+1024)).
-define(MAX_CIPHER_TEXT_LENGTH, (?MAX_PLAIN_TEXT_LENGTH+2048)).
diff --git a/lib/ssl/src/ssl_session.erl b/lib/ssl/src/ssl_session.erl
index c9607489e9..44305c65fe 100644
--- a/lib/ssl/src/ssl_session.erl
+++ b/lib/ssl/src/ssl_session.erl
@@ -27,6 +27,7 @@
-include("ssl_handshake.hrl").
-include("ssl_internal.hrl").
+-include("ssl_api.hrl").
%% Internal application API
-export([is_new/2, client_id/4, server_id/6, valid_session/2]).
@@ -34,7 +35,7 @@
-type seconds() :: integer().
%%--------------------------------------------------------------------
--spec is_new(session_id(), session_id()) -> boolean().
+-spec is_new(ssl:session_id(), ssl:session_id()) -> boolean().
%%
%% Description: Checks if the session id decided by the server is a
%% new or resumed sesion id.
@@ -47,12 +48,19 @@ is_new(_ClientSuggestion, _ServerDecision) ->
true.
%%--------------------------------------------------------------------
--spec client_id({host(), inet:port_number(), #ssl_options{}}, db_handle(), atom(),
+-spec client_id({ssl:host(), inet:port_number(), #ssl_options{}}, db_handle(), atom(),
undefined | binary()) -> binary().
%%
%% Description: Should be called by the client side to get an id
%% for the client hello message.
%%--------------------------------------------------------------------
+client_id({Host, Port, #ssl_options{reuse_session = SessionId}}, Cache, CacheCb, _) when is_binary(SessionId)->
+ case CacheCb:lookup(Cache, {{Host, Port}, SessionId}) of
+ undefined ->
+ <<>>;
+ #session{} ->
+ SessionId
+ end;
client_id(ClientInfo, Cache, CacheCb, OwnCert) ->
case select_session(ClientInfo, Cache, CacheCb, OwnCert) of
no_session ->
@@ -91,7 +99,8 @@ server_id(Port, SuggestedId, Options, Cert, Cache, CacheCb) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-select_session({_, _, #ssl_options{reuse_sessions=false}}, _Cache, _CacheCb, _OwnCert) ->
+select_session({_, _, #ssl_options{reuse_sessions = Reuse}}, _Cache, _CacheCb, _OwnCert) when Reuse =/= true ->
+ %% If reuse_sessions == true | save a new session should be created
no_session;
select_session({HostIP, Port, SslOpts}, Cache, CacheCb, OwnCert) ->
Sessions = CacheCb:select_session(Cache, {HostIP, Port}),
@@ -132,7 +141,7 @@ is_resumable(SuggestedSessionId, Port, #ssl_options{reuse_session = ReuseFun} =
false -> {false, undefined}
end;
undefined ->
- {false, undefined}
+ {false, undefined}
end.
resumable(new) ->
diff --git a/lib/ssl/src/ssl_session_cache_api.erl b/lib/ssl/src/ssl_session_cache_api.erl
index b68c75a09b..5f96f905b1 100644
--- a/lib/ssl/src/ssl_session_cache_api.erl
+++ b/lib/ssl/src/ssl_session_cache_api.erl
@@ -23,14 +23,20 @@
-module(ssl_session_cache_api).
-include("ssl_handshake.hrl").
-include("ssl_internal.hrl").
+-include("ssl_api.hrl").
--type key() :: {{host(), inet:port_number()}, session_id()} | {inet:port_number(), session_id()}.
+-export_type([session_cache_key/0, session/0, partial_key/0, session_cache_ref/0]).
--callback init(list()) -> db_handle().
--callback terminate(db_handle()) -> any().
--callback lookup(db_handle(), key()) -> #session{} | undefined.
--callback update(db_handle(), key(), #session{}) -> any().
--callback delete(db_handle(), key()) -> any().
--callback foldl(fun(), term(), db_handle()) -> term().
--callback select_session(db_handle(), {host(), inet:port_number()} | inet:port_number()) -> [#session{}].
--callback size(db_handle()) -> integer().
+-type session_cache_ref() :: any().
+-type session_cache_key() :: {partial_key(), ssl:session_id()}.
+-opaque session() :: #session{}.
+-opaque partial_key() :: {ssl:host(), inet:port_number()} | inet:port_number().
+
+-callback init(list()) -> session_cache_ref().
+-callback terminate(session_cache_ref()) -> any().
+-callback lookup(session_cache_ref(), session_cache_key()) -> #session{} | undefined.
+-callback update(session_cache_ref(), session_cache_key(), #session{}) -> any().
+-callback delete(session_cache_ref(), session_cache_key()) -> any().
+-callback foldl(fun(), term(), session_cache_ref()) -> term().
+-callback select_session(session_cache_ref(), {ssl:host(), inet:port_number()} | inet:port_number()) -> [#session{}].
+-callback size(session_cache_ref()) -> integer().
diff --git a/lib/ssl/src/ssl_tls_dist_proxy.erl b/lib/ssl/src/ssl_tls_dist_proxy.erl
deleted file mode 100644
index 12a057fd22..0000000000
--- a/lib/ssl/src/ssl_tls_dist_proxy.erl
+++ /dev/null
@@ -1,493 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2011-2017. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
--module(ssl_tls_dist_proxy).
-
-
--export([listen/2, accept/2, connect/4, get_tcp_address/1]).
--export([init/1, start_link/0, handle_call/3, handle_cast/2, handle_info/2,
- terminate/2, code_change/3, ssl_options/2]).
-
--include_lib("kernel/include/net_address.hrl").
-
--record(state,
- {listen,
- accept_loop
- }).
-
--define(PPRE, 4).
--define(PPOST, 4).
-
-
-%%====================================================================
-%% Internal application API
-%%====================================================================
-
-listen(Driver, Name) ->
- gen_server:call(?MODULE, {listen, Driver, Name}, infinity).
-
-accept(Driver, Listen) ->
- gen_server:call(?MODULE, {accept, Driver, Listen}, infinity).
-
-connect(Driver, Ip, Port, ExtraOpts) ->
- gen_server:call(
- ?MODULE, {connect, Driver, Ip, Port, ExtraOpts}, infinity).
-
-
-do_listen(Options) ->
- {First,Last} = case application:get_env(kernel,inet_dist_listen_min) of
- {ok,N} when is_integer(N) ->
- case application:get_env(kernel,
- inet_dist_listen_max) of
- {ok,M} when is_integer(M) ->
- {N,M};
- _ ->
- {N,N}
- end;
- _ ->
- {0,0}
- end,
- do_listen(First, Last, listen_options([{backlog,128}|Options])).
-
-do_listen(First,Last,_) when First > Last ->
- {error,eaddrinuse};
-do_listen(First,Last,Options) ->
- case gen_tcp:listen(First, Options) of
- {error, eaddrinuse} ->
- do_listen(First+1,Last,Options);
- Other ->
- Other
- end.
-
-listen_options(Opts0) ->
- Opts1 =
- case application:get_env(kernel, inet_dist_use_interface) of
- {ok, Ip} ->
- [{ip, Ip} | Opts0];
- _ ->
- Opts0
- end,
- case application:get_env(kernel, inet_dist_listen_options) of
- {ok,ListenOpts} ->
- ListenOpts ++ Opts1;
- _ ->
- Opts1
- end.
-
-connect_options(Opts) ->
- case application:get_env(kernel, inet_dist_connect_options) of
- {ok,ConnectOpts} ->
- lists:ukeysort(1, ConnectOpts ++ Opts);
- _ ->
- Opts
- end.
-
-%%====================================================================
-%% gen_server callbacks
-%%====================================================================
-
-start_link() ->
- gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
-
-init([]) ->
- process_flag(priority, max),
- {ok, #state{}}.
-
-handle_call({listen, Driver, Name}, _From, State) ->
- case gen_tcp:listen(0, [{active, false}, {packet,?PPRE}, {ip, loopback}]) of
- {ok, Socket} ->
- {ok, World} = do_listen([{active, false}, binary, {packet,?PPRE}, {reuseaddr, true},
- Driver:family()]),
- {ok, TcpAddress} = get_tcp_address(Socket),
- {ok, WorldTcpAddress} = get_tcp_address(World),
- {_,Port} = WorldTcpAddress#net_address.address,
- ErlEpmd = net_kernel:epmd_module(),
- case ErlEpmd:register_node(Name, Port, Driver) of
- {ok, Creation} ->
- {reply, {ok, {Socket, TcpAddress, Creation}},
- State#state{listen={Socket, World}}};
- {error, _} = Error ->
- {reply, Error, State}
- end;
- Error ->
- {reply, Error, State}
- end;
-
-handle_call({accept, _Driver, Listen}, {From, _}, State = #state{listen={_, World}}) ->
- Self = self(),
- ErtsPid = spawn_link(fun() -> accept_loop(Self, erts, Listen, From) end),
- WorldPid = spawn_link(fun() -> accept_loop(Self, world, World, Listen) end),
- {reply, ErtsPid, State#state{accept_loop={ErtsPid, WorldPid}}};
-
-handle_call({connect, Driver, Ip, Port, ExtraOpts}, {From, _}, State) ->
- Me = self(),
- Pid =
- spawn_link(
- fun() -> setup_proxy(Driver, Ip, Port, ExtraOpts, Me) end),
- receive
- {Pid, go_ahead, LPort} ->
- Res = {ok, Socket} = try_connect(LPort),
- case gen_tcp:controlling_process(Socket, From) of
- {error, badarg} = Error -> {reply, Error, State}; % From is dead anyway.
- ok ->
- flush_old_controller(From, Socket),
- {reply, Res, State}
- end;
- {Pid, Error} ->
- {reply, Error, State}
- end;
-
-handle_call(_What, _From, State) ->
- {reply, ok, State}.
-
-handle_cast(_What, State) ->
- {noreply, State}.
-
-handle_info(_What, State) ->
- {noreply, State}.
-
-terminate(_Reason, _St) ->
- ok.
-
-code_change(_OldVsn, St, _Extra) ->
- {ok, St}.
-
-%%--------------------------------------------------------------------
-%%% Internal functions
-%%--------------------------------------------------------------------
-get_tcp_address(Socket) ->
- case inet:sockname(Socket) of
- {ok, Address} ->
- {ok, Host} = inet:gethostname(),
- NetAddress = #net_address{
- address = Address,
- host = Host,
- protocol = proxy,
- family = inet
- },
- {ok, NetAddress};
- {error, _} = Error -> Error
- end.
-
-accept_loop(Proxy, erts = Type, Listen, Extra) ->
- process_flag(priority, max),
- case gen_tcp:accept(Listen) of
- {ok, Socket} ->
- Extra ! {accept,self(),Socket,inet,proxy},
- receive
- {_Kernel, controller, Pid} ->
- inet:setopts(Socket, [nodelay()]),
- ok = gen_tcp:controlling_process(Socket, Pid),
- flush_old_controller(Pid, Socket),
- Pid ! {self(), controller};
- {_Kernel, unsupported_protocol} ->
- exit(unsupported_protocol)
- end;
- {error, closed} ->
- %% The listening socket is closed: the proxy process is
- %% shutting down. Exit normally, to avoid generating a
- %% spurious error report.
- exit(normal);
- Error ->
- exit(Error)
- end,
- accept_loop(Proxy, Type, Listen, Extra);
-
-accept_loop(Proxy, world = Type, Listen, Extra) ->
- process_flag(priority, max),
- case gen_tcp:accept(Listen) of
- {ok, Socket} ->
- Opts = get_ssl_options(server),
- wait_for_code_server(),
- case ssl:ssl_accept(Socket, Opts) of
- {ok, SslSocket} ->
- PairHandler =
- spawn_link(fun() ->
- setup_connection(SslSocket, Extra)
- end),
- ok = ssl:controlling_process(SslSocket, PairHandler),
- flush_old_controller(PairHandler, SslSocket);
- {error, {options, _}} = Error ->
- %% Bad options: that's probably our fault. Let's log that.
- error_logger:error_msg("Cannot accept TLS distribution connection: ~s~n",
- [ssl:format_error(Error)]),
- gen_tcp:close(Socket);
- _ ->
- gen_tcp:close(Socket)
- end;
- Error ->
- exit(Error)
- end,
- accept_loop(Proxy, Type, Listen, Extra).
-
-wait_for_code_server() ->
- %% This is an ugly hack. Upgrading a socket to TLS requires the
- %% crypto module to be loaded. Loading the crypto module triggers
- %% its on_load function, which calls code:priv_dir/1 to find the
- %% directory where its NIF library is. However, distribution is
- %% started earlier than the code server, so the code server is not
- %% necessarily started yet, and code:priv_dir/1 might fail because
- %% of that, if we receive an incoming connection on the
- %% distribution port early enough.
- %%
- %% If the on_load function of a module fails, the module is
- %% unloaded, and the function call that triggered loading it fails
- %% with 'undef', which is rather confusing.
- %%
- %% Thus, the ssl_tls_dist_proxy process will terminate, and be
- %% restarted by ssl_dist_sup. However, it won't have any memory
- %% of being asked by net_kernel to listen for incoming
- %% connections. Hence, the node will believe that it's open for
- %% distribution, but it actually isn't.
- %%
- %% So let's avoid that by waiting for the code server to start.
- case whereis(code_server) of
- undefined ->
- timer:sleep(10),
- wait_for_code_server();
- Pid when is_pid(Pid) ->
- ok
- end.
-
-try_connect(Port) ->
- case gen_tcp:connect({127,0,0,1}, Port, [{active, false}, {packet,?PPRE}, nodelay()]) of
- R = {ok, _S} ->
- R;
- {error, _R} ->
- try_connect(Port)
- end.
-
-setup_proxy(Driver, Ip, Port, ExtraOpts, Parent) ->
- process_flag(trap_exit, true),
- Opts = connect_options(ExtraOpts ++ get_ssl_options(client)),
- case ssl:connect(Ip, Port, [{active, true}, binary, {packet,?PPRE}, nodelay(),
- Driver:family()] ++ Opts) of
- {ok, World} ->
- {ok, ErtsL} = gen_tcp:listen(0, [{active, true}, {ip, loopback}, binary, {packet,?PPRE}]),
- {ok, #net_address{address={_,LPort}}} = get_tcp_address(ErtsL),
- Parent ! {self(), go_ahead, LPort},
- case gen_tcp:accept(ErtsL) of
- {ok, Erts} ->
- %% gen_tcp:close(ErtsL),
- loop_conn_setup(World, Erts);
- Err ->
- Parent ! {self(), Err}
- end;
- {error, {options, _}} = Err ->
- %% Bad options: that's probably our fault. Let's log that.
- error_logger:error_msg("Cannot open TLS distribution connection: ~s~n",
- [ssl:format_error(Err)]),
- Parent ! {self(), Err};
- Err ->
- Parent ! {self(), Err}
- end.
-
-
-%% we may not always want the nodelay behaviour
-%% %% for performance reasons
-
-nodelay() ->
- case application:get_env(kernel, dist_nodelay) of
- undefined ->
- {nodelay, true};
- {ok, true} ->
- {nodelay, true};
- {ok, false} ->
- {nodelay, false};
- _ ->
- {nodelay, true}
- end.
-
-setup_connection(World, ErtsListen) ->
- process_flag(trap_exit, true),
- {ok, TcpAddress} = get_tcp_address(ErtsListen),
- {_Addr,Port} = TcpAddress#net_address.address,
- {ok, Erts} = gen_tcp:connect({127,0,0,1}, Port, [{active, true}, binary, {packet,?PPRE}, nodelay()]),
- ssl:setopts(World, [{active,true}, {packet,?PPRE}, nodelay()]),
- loop_conn_setup(World, Erts).
-
-loop_conn_setup(World, Erts) ->
- receive
- {ssl, World, Data = <<$a, _/binary>>} ->
- gen_tcp:send(Erts, Data),
- ssl:setopts(World, [{packet,?PPOST}, nodelay()]),
- inet:setopts(Erts, [{packet,?PPOST}, nodelay()]),
- loop_conn(World, Erts);
- {tcp, Erts, Data = <<$a, _/binary>>} ->
- ssl:send(World, Data),
- ssl:setopts(World, [{packet,?PPOST}, nodelay()]),
- inet:setopts(Erts, [{packet,?PPOST}, nodelay()]),
- loop_conn(World, Erts);
- {ssl, World, Data = <<_, _/binary>>} ->
- gen_tcp:send(Erts, Data),
- loop_conn_setup(World, Erts);
- {tcp, Erts, Data = <<_, _/binary>>} ->
- ssl:send(World, Data),
- loop_conn_setup(World, Erts);
- {ssl, World, Data} ->
- gen_tcp:send(Erts, Data),
- loop_conn_setup(World, Erts);
- {tcp, Erts, Data} ->
- ssl:send(World, Data),
- loop_conn_setup(World, Erts);
- {tcp_closed, Erts} ->
- ssl:close(World);
- {ssl_closed, World} ->
- gen_tcp:close(Erts);
- {ssl_error, World, _} ->
-
- ssl:close(World)
- end.
-
-loop_conn(World, Erts) ->
- receive
- {ssl, World, Data} ->
- gen_tcp:send(Erts, Data),
- loop_conn(World, Erts);
- {tcp, Erts, Data} ->
- ssl:send(World, Data),
- loop_conn(World, Erts);
- {tcp_closed, Erts} ->
- ssl:close(World);
- {ssl_closed, World} ->
- gen_tcp:close(Erts);
- {ssl_error, World, _} ->
- ssl:close(World)
- end.
-
-get_ssl_options(Type) ->
- try ets:lookup(ssl_dist_opts, Type) of
- [{Type, Opts}] ->
- [{erl_dist, true} | Opts];
- _ ->
- get_ssl_dist_arguments(Type)
- catch
- error:badarg ->
- get_ssl_dist_arguments(Type)
- end.
-
-get_ssl_dist_arguments(Type) ->
- case init:get_argument(ssl_dist_opt) of
- {ok, Args} ->
- [{erl_dist, true} | ssl_options(Type, lists:append(Args))];
- _ ->
- [{erl_dist, true}]
- end.
-
-ssl_options(_,[]) ->
- [];
-ssl_options(server, ["client_" ++ _, _Value |T]) ->
- ssl_options(server,T);
-ssl_options(client, ["server_" ++ _, _Value|T]) ->
- ssl_options(client,T);
-ssl_options(server, ["server_certfile", Value|T]) ->
- [{certfile, Value} | ssl_options(server,T)];
-ssl_options(client, ["client_certfile", Value | T]) ->
- [{certfile, Value} | ssl_options(client,T)];
-ssl_options(server, ["server_cacertfile", Value|T]) ->
- [{cacertfile, Value} | ssl_options(server,T)];
-ssl_options(client, ["client_cacertfile", Value|T]) ->
- [{cacertfile, Value} | ssl_options(client,T)];
-ssl_options(server, ["server_keyfile", Value|T]) ->
- [{keyfile, Value} | ssl_options(server,T)];
-ssl_options(client, ["client_keyfile", Value|T]) ->
- [{keyfile, Value} | ssl_options(client,T)];
-ssl_options(server, ["server_password", Value|T]) ->
- [{password, Value} | ssl_options(server,T)];
-ssl_options(client, ["client_password", Value|T]) ->
- [{password, Value} | ssl_options(client,T)];
-ssl_options(server, ["server_verify", Value|T]) ->
- [{verify, atomize(Value)} | ssl_options(server,T)];
-ssl_options(client, ["client_verify", Value|T]) ->
- [{verify, atomize(Value)} | ssl_options(client,T)];
-ssl_options(server, ["server_verify_fun", Value|T]) ->
- [{verify_fun, verify_fun(Value)} | ssl_options(server,T)];
-ssl_options(client, ["client_verify_fun", Value|T]) ->
- [{verify_fun, verify_fun(Value)} | ssl_options(client,T)];
-ssl_options(server, ["server_crl_check", Value|T]) ->
- [{crl_check, atomize(Value)} | ssl_options(server,T)];
-ssl_options(client, ["client_crl_check", Value|T]) ->
- [{crl_check, atomize(Value)} | ssl_options(client,T)];
-ssl_options(server, ["server_crl_cache", Value|T]) ->
- [{crl_cache, termify(Value)} | ssl_options(server,T)];
-ssl_options(client, ["client_crl_cache", Value|T]) ->
- [{crl_cache, termify(Value)} | ssl_options(client,T)];
-ssl_options(server, ["server_reuse_sessions", Value|T]) ->
- [{reuse_sessions, atomize(Value)} | ssl_options(server,T)];
-ssl_options(client, ["client_reuse_sessions", Value|T]) ->
- [{reuse_sessions, atomize(Value)} | ssl_options(client,T)];
-ssl_options(server, ["server_secure_renegotiate", Value|T]) ->
- [{secure_renegotiate, atomize(Value)} | ssl_options(server,T)];
-ssl_options(client, ["client_secure_renegotiate", Value|T]) ->
- [{secure_renegotiate, atomize(Value)} | ssl_options(client,T)];
-ssl_options(server, ["server_depth", Value|T]) ->
- [{depth, list_to_integer(Value)} | ssl_options(server,T)];
-ssl_options(client, ["client_depth", Value|T]) ->
- [{depth, list_to_integer(Value)} | ssl_options(client,T)];
-ssl_options(server, ["server_hibernate_after", Value|T]) ->
- [{hibernate_after, list_to_integer(Value)} | ssl_options(server,T)];
-ssl_options(client, ["client_hibernate_after", Value|T]) ->
- [{hibernate_after, list_to_integer(Value)} | ssl_options(client,T)];
-ssl_options(server, ["server_ciphers", Value|T]) ->
- [{ciphers, Value} | ssl_options(server,T)];
-ssl_options(client, ["client_ciphers", Value|T]) ->
- [{ciphers, Value} | ssl_options(client,T)];
-ssl_options(server, ["server_dhfile", Value|T]) ->
- [{dhfile, Value} | ssl_options(server,T)];
-ssl_options(server, ["server_fail_if_no_peer_cert", Value|T]) ->
- [{fail_if_no_peer_cert, atomize(Value)} | ssl_options(server,T)];
-ssl_options(Type, Opts) ->
- error(malformed_ssl_dist_opt, [Type, Opts]).
-
-atomize(List) when is_list(List) ->
- list_to_atom(List);
-atomize(Atom) when is_atom(Atom) ->
- Atom.
-
-termify(String) when is_list(String) ->
- {ok, Tokens, _} = erl_scan:string(String ++ "."),
- {ok, Term} = erl_parse:parse_term(Tokens),
- Term.
-
-verify_fun(Value) ->
- case termify(Value) of
- {Mod, Func, State} when is_atom(Mod), is_atom(Func) ->
- Fun = fun Mod:Func/3,
- {Fun, State};
- _ ->
- error(malformed_ssl_dist_opt, [Value])
- end.
-
-flush_old_controller(Pid, Socket) ->
- receive
- {tcp, Socket, Data} ->
- Pid ! {tcp, Socket, Data},
- flush_old_controller(Pid, Socket);
- {tcp_closed, Socket} ->
- Pid ! {tcp_closed, Socket},
- flush_old_controller(Pid, Socket);
- {ssl, Socket, Data} ->
- Pid ! {ssl, Socket, Data},
- flush_old_controller(Pid, Socket);
- {ssl_closed, Socket} ->
- Pid ! {ssl_closed, Socket},
- flush_old_controller(Pid, Socket)
- after 0 ->
- ok
- end.
diff --git a/lib/ssl/src/ssl_v2.erl b/lib/ssl/src/ssl_v2.erl
deleted file mode 100644
index 37134cbe5d..0000000000
--- a/lib/ssl/src/ssl_v2.erl
+++ /dev/null
@@ -1,38 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
-%%----------------------------------------------------------------------
-%% Purpose: Handles sslv2 hello as clients supporting sslv2 and higher
-%% will send an sslv2 hello.
-%%----------------------------------------------------------------------
-
--module(ssl_v2).
-
--export([client_random/2]).
-
-client_random(ChallengeData, 32) ->
- ChallengeData;
-client_random(ChallengeData, N) when N > 32 ->
- <<NewChallengeData:32/binary, _/binary>> = ChallengeData,
- NewChallengeData;
-client_random(ChallengeData, N) ->
- Pad = list_to_binary(lists:duplicate(N, 0)),
- <<Pad/binary, ChallengeData/binary>>.
diff --git a/lib/ssl/src/ssl_v3.erl b/lib/ssl/src/ssl_v3.erl
index 82d165f995..4eab60b440 100644
--- a/lib/ssl/src/ssl_v3.erl
+++ b/lib/ssl/src/ssl_v3.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -131,7 +131,7 @@ setup_keys(MasterSecret, ServerRandom, ClientRandom, HS, KML, _EKML, IVS) ->
{ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey,
ServerWriteKey, ClientIV, ServerIV}.
--spec suites() -> [ssl_cipher:cipher_suite()].
+-spec suites() -> [ssl_cipher_format:cipher_suite()].
suites() ->
[
diff --git a/lib/ssl/src/tls.erl b/lib/ssl/src/tls.erl
deleted file mode 100644
index aa41cd1ba6..0000000000
--- a/lib/ssl/src/tls.erl
+++ /dev/null
@@ -1,112 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
-
-%%% Purpose : Reflect TLS specific API options (fairly simple wrapper at the moment)
-
--module(tls).
-
--include("ssl_api.hrl").
--include("ssl_internal.hrl").
-
--export([connect/2, connect/3, listen/2, accept/1, accept/2,
- handshake/1, handshake/2, handshake/3]).
-
-%%--------------------------------------------------------------------
-%%
-%% Description: Connect to an TLS server.
-%%--------------------------------------------------------------------
-
--spec connect(host() | port(), [connect_option()]) -> {ok, #sslsocket{}} |
- {error, reason()}.
-
-connect(Socket, Options) when is_port(Socket) ->
- connect(Socket, Options, infinity).
-
--spec connect(host() | port(), [connect_option()] | inet:port_number(),
- timeout() | list()) ->
- {ok, #sslsocket{}} | {error, reason()}.
-
-connect(Socket, SslOptions, Timeout) when is_port(Socket) ->
- TLSOpts = [{protocol, tls} | SslOptions],
- ssl:connect(Socket, TLSOpts, Timeout);
-connect(Host, Port, Options) ->
- connect(Host, Port, Options, infinity).
-
--spec connect(host() | port(), inet:port_number(), list(), timeout()) ->
- {ok, #sslsocket{}} | {error, reason()}.
-
-connect(Host, Port, Options, Timeout) ->
- TLSOpts = [{protocol, tls} | Options],
- ssl:connect(Host, Port, TLSOpts, Timeout).
-
-%%--------------------------------------------------------------------
--spec listen(inet:port_number(), [listen_option()]) ->{ok, #sslsocket{}} | {error, reason()}.
-
-%%
-%% Description: Creates an ssl listen socket.
-%%--------------------------------------------------------------------
-listen(Port, Options) ->
- TLSOpts = [{protocol, tls} | Options],
- ssl:listen(Port, TLSOpts).
-
-%%--------------------------------------------------------------------
-%%
-%% Description: Performs transport accept on an ssl listen socket
-%%--------------------------------------------------------------------
--spec accept(#sslsocket{}) -> {ok, #sslsocket{}} |
- {error, reason()}.
-accept(ListenSocket) ->
- accept(ListenSocket, infinity).
-
--spec accept(#sslsocket{}, timeout()) -> {ok, #sslsocket{}} |
- {error, reason()}.
-accept(Socket, Timeout) ->
- ssl:transport_accept(Socket, Timeout).
-
-%%--------------------------------------------------------------------
-%%
-%% Description: Performs accept on an ssl listen socket. e.i. performs
-%% ssl handshake.
-%%--------------------------------------------------------------------
-
--spec handshake(#sslsocket{}) -> ok | {error, reason()}.
-
-handshake(ListenSocket) ->
- handshake(ListenSocket, infinity).
-
-
--spec handshake(#sslsocket{} | port(), timeout()| [ssl_option()
- | transport_option()]) ->
- ok | {ok, #sslsocket{}} | {error, reason()}.
-
-handshake(#sslsocket{} = Socket, Timeout) ->
- ssl:ssl_accept(Socket, Timeout);
-
-handshake(ListenSocket, SslOptions) when is_port(ListenSocket) ->
- handshake(ListenSocket, SslOptions, infinity).
-
-
--spec handshake(port(), [ssl_option()| transport_option()], timeout()) ->
- {ok, #sslsocket{}} | {error, reason()}.
-
-handshake(Socket, SslOptions, Timeout) when is_port(Socket) ->
- ssl:ssl_accept(Socket, SslOptions, Timeout).
diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl
index 914ee9f22f..a05858221a 100644
--- a/lib/ssl/src/tls_connection.erl
+++ b/lib/ssl/src/tls_connection.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -17,7 +17,6 @@
%%
%% %CopyrightEnd%
%%
-
%%
%%----------------------------------------------------------------------
%% Purpose: Handles an ssl connection, e.i. both the setup
@@ -38,35 +37,60 @@
-include("ssl_api.hrl").
-include("ssl_internal.hrl").
-include("ssl_srp.hrl").
--include_lib("public_key/include/public_key.hrl").
+-include_lib("public_key/include/public_key.hrl").
+-include_lib("kernel/include/logger.hrl").
%% Internal application API
%% Setup
--export([start_fsm/8, start_link/7, init/1]).
+-export([start_fsm/8, start_link/8, init/1, pids/1]).
%% State transition handling
--export([next_record/1, next_event/3, next_event/4, handle_common_event/4]).
+-export([next_event/3, next_event/4,
+ handle_protocol_record/3]).
%% Handshake handling
--export([renegotiate/2, send_handshake/2,
+-export([renegotiation/2, renegotiate/2, send_handshake/2,
+ send_handshake_flight/1,
queue_handshake/2, queue_change_cipher/2,
- reinit_handshake_data/1, select_sni_extension/1, empty_connection_state/2]).
+ reinit/1, reinit_handshake_data/1, select_sni_extension/1,
+ empty_connection_state/2]).
%% Alert and close handling
--export([encode_alert/3, send_alert/2, close/5, protocol_name/0]).
+-export([send_alert/2, send_alert_in_connection/2,
+ send_sync_alert/2,
+ close/5, protocol_name/0]).
%% Data handling
--export([encode_data/3, passive_receive/2, next_record_if_active/1, send/3,
- socket/5, setopts/3, getopts/3]).
+-export([next_record/1, socket/4, setopts/3, getopts/3]).
%% gen_statem state functions
-export([init/3, error/3, downgrade/3, %% Initiation and take down states
- hello/3, certify/3, cipher/3, abbreviated/3, %% Handshake states
- connection/3]).
+ hello/3, user_hello/3, certify/3, cipher/3, abbreviated/3, %% Handshake states
+ connection/3]).
+%% TLS 1.3 state functions (server)
+-export([start/3, %% common state with client
+ negotiated/3,
+ recvd_ch/3,
+ wait_cert/3, %% common state with client
+ wait_cv/3, %% common state with client
+ wait_eoed/3,
+ wait_finished/3, %% common state with client
+ wait_flight2/3,
+ connected/3 %% common state with client
+ ]).
+%% TLS 1.3 state functions (client)
+-export([wait_cert_cr/3,
+ wait_ee/3,
+ wait_sh/3
+ ]).
%% gen_statem callbacks
-export([callback_mode/0, terminate/3, code_change/4, format_status/2]).
+-export([encode_handshake/4]).
+
+-define(DIST_CNTRL_SPAWN_OPTS, [{priority, max}]).
+
%%====================================================================
%% Internal application API
%%====================================================================
@@ -74,96 +98,145 @@
%% Setup
%%====================================================================
start_fsm(Role, Host, Port, Socket, {#ssl_options{erl_dist = false},_, Tracker} = Opts,
- User, {CbModule, _,_, _} = CbInfo,
+ User, {CbModule, _,_, _, _} = CbInfo,
Timeout) ->
try
- {ok, Pid} = tls_connection_sup:start_child([Role, Host, Port, Socket,
+ {ok, Sender} = tls_sender:start(),
+ {ok, Pid} = tls_connection_sup:start_child([Role, Sender, Host, Port, Socket,
Opts, User, CbInfo]),
- {ok, SslSocket} = ssl_connection:socket_control(?MODULE, Socket, Pid, CbModule, Tracker),
- ok = ssl_connection:handshake(SslSocket, Timeout),
- {ok, SslSocket}
+ {ok, SslSocket} = ssl_connection:socket_control(?MODULE, Socket, [Pid, Sender], CbModule, Tracker),
+ ssl_connection:handshake(SslSocket, Timeout)
catch
error:{badmatch, {error, _} = Error} ->
Error
end;
start_fsm(Role, Host, Port, Socket, {#ssl_options{erl_dist = true},_, Tracker} = Opts,
- User, {CbModule, _,_, _} = CbInfo,
+ User, {CbModule, _,_, _, _} = CbInfo,
Timeout) ->
try
- {ok, Pid} = tls_connection_sup:start_child_dist([Role, Host, Port, Socket,
+ {ok, Sender} = tls_sender:start([{spawn_opt, ?DIST_CNTRL_SPAWN_OPTS}]),
+ {ok, Pid} = tls_connection_sup:start_child_dist([Role, Sender, Host, Port, Socket,
Opts, User, CbInfo]),
- {ok, SslSocket} = ssl_connection:socket_control(?MODULE, Socket, Pid, CbModule, Tracker),
- ok = ssl_connection:handshake(SslSocket, Timeout),
- {ok, SslSocket}
+ {ok, SslSocket} = ssl_connection:socket_control(?MODULE, Socket, [Pid, Sender], CbModule, Tracker),
+ ssl_connection:handshake(SslSocket, Timeout)
catch
error:{badmatch, {error, _} = Error} ->
Error
end.
%%--------------------------------------------------------------------
--spec start_link(atom(), host(), inet:port_number(), port(), list(), pid(), tuple()) ->
+-spec start_link(atom(), pid(), ssl:host(), inet:port_number(), port(), list(), pid(), tuple()) ->
{ok, pid()} | ignore | {error, reason()}.
%%
%% Description: Creates a gen_statem process which calls Module:init/1 to
%% initialize.
%%--------------------------------------------------------------------
-start_link(Role, Host, Port, Socket, Options, User, CbInfo) ->
- {ok, proc_lib:spawn_link(?MODULE, init, [[Role, Host, Port, Socket, Options, User, CbInfo]])}.
+start_link(Role, Sender, Host, Port, Socket, Options, User, CbInfo) ->
+ {ok, proc_lib:spawn_link(?MODULE, init, [[Role, Sender, Host, Port, Socket, Options, User, CbInfo]])}.
-init([Role, Host, Port, Socket, Options, User, CbInfo]) ->
+init([Role, Sender, Host, Port, Socket, {SslOpts, _, _} = Options, User, CbInfo]) ->
process_flag(trap_exit, true),
- State0 = initial_state(Role, Host, Port, Socket, Options, User, CbInfo),
+ link(Sender),
+ case SslOpts#ssl_options.erl_dist of
+ true ->
+ process_flag(priority, max);
+ _ ->
+ ok
+ end,
+ State0 = #state{protocol_specific = Map} = initial_state(Role, Sender,
+ Host, Port, Socket, Options, User, CbInfo),
try
State = ssl_connection:ssl_config(State0#state.ssl_options, Role, State0),
- gen_statem:enter_loop(?MODULE, [], init, State)
+ initialize_tls_sender(State),
+ gen_statem:enter_loop(?MODULE, [], init, State)
catch throw:Error ->
- gen_statem:enter_loop(?MODULE, [], error, {Error, State0})
+ EState = State0#state{protocol_specific = Map#{error => Error}},
+ gen_statem:enter_loop(?MODULE, [], error, EState)
end.
+
+pids(#state{protocol_specific = #{sender := Sender}}) ->
+ [self(), Sender].
+
%%====================================================================
%% State transition handling
%%====================================================================
-next_record(#state{unprocessed_handshake_events = N} = State) when N > 0 ->
- {no_record, State#state{unprocessed_handshake_events = N-1}};
-
+next_record(#state{handshake_env =
+ #handshake_env{unprocessed_handshake_events = N} = HsEnv}
+ = State) when N > 0 ->
+ {no_record, State#state{handshake_env =
+ HsEnv#handshake_env{unprocessed_handshake_events = N-1}}};
next_record(#state{protocol_buffers =
- #protocol_buffers{tls_packets = [], tls_cipher_texts = [CT | Rest]}
- = Buffers,
- connection_states = ConnStates0,
- ssl_options = #ssl_options{padding_check = Check}} = State) ->
- case tls_record:decode_cipher_text(CT, ConnStates0, Check) of
- {Plain, ConnStates} ->
- {Plain, State#state{protocol_buffers =
- Buffers#protocol_buffers{tls_cipher_texts = Rest},
- connection_states = ConnStates}};
- #alert{} = Alert ->
- {Alert, State}
- end;
-next_record(#state{protocol_buffers = #protocol_buffers{tls_packets = [], tls_cipher_texts = []},
- socket = Socket,
- close_tag = CloseTag,
- transport_cb = Transport} = State) ->
- case tls_socket:setopts(Transport, Socket, [{active,once}]) of
- ok ->
- {no_record, State};
- _ ->
- self() ! {CloseTag, Socket},
- {no_record, State}
- end;
+ #protocol_buffers{tls_cipher_texts = [_|_] = CipherTexts},
+ connection_states = ConnectionStates,
+ ssl_options = #ssl_options{padding_check = Check}} = State) ->
+ next_record(State, CipherTexts, ConnectionStates, Check);
+next_record(#state{protocol_buffers = #protocol_buffers{tls_cipher_texts = []},
+ protocol_specific = #{active_n_toggle := true, active_n := N} = ProtocolSpec,
+ static_env = #static_env{socket = Socket,
+ close_tag = CloseTag,
+ transport_cb = Transport}
+ } = State) ->
+ case tls_socket:setopts(Transport, Socket, [{active, N}]) of
+ ok ->
+ {no_record, State#state{protocol_specific = ProtocolSpec#{active_n_toggle => false}}};
+ _ ->
+ self() ! {CloseTag, Socket},
+ {no_record, State}
+ end;
next_record(State) ->
{no_record, State}.
+%% Decipher next record and concatenate consecutive ?APPLICATION_DATA records into one
+%%
+next_record(State, CipherTexts, ConnectionStates, Check) ->
+ next_record(State, CipherTexts, ConnectionStates, Check, []).
+%%
+next_record(#state{connection_env = #connection_env{negotiated_version = Version}} = State,
+ [CT|CipherTexts], ConnectionStates0, Check, Acc) ->
+ case tls_record:decode_cipher_text(Version, CT, ConnectionStates0, Check) of
+ {#ssl_tls{type = ?APPLICATION_DATA, fragment = Fragment}, ConnectionStates} ->
+ case CipherTexts of
+ [] ->
+ %% End of cipher texts - build and deliver an ?APPLICATION_DATA record
+ %% from the accumulated fragments
+ next_record_done(State, [], ConnectionStates,
+ #ssl_tls{type = ?APPLICATION_DATA,
+ fragment = iolist_to_binary(lists:reverse(Acc, [Fragment]))});
+ [_|_] ->
+ next_record(State, CipherTexts, ConnectionStates, Check, [Fragment|Acc])
+ end;
+ {Record, ConnectionStates} when Acc =:= [] ->
+ %% Singelton non-?APPLICATION_DATA record - deliver
+ next_record_done(State, CipherTexts, ConnectionStates, Record);
+ {_Record, _ConnectionStates_to_forget} ->
+ %% Not ?APPLICATION_DATA but we have accumulated fragments
+ %% -> build an ?APPLICATION_DATA record with concatenated fragments
+ %% and forget about decrypting this record - we'll decrypt it again next time
+ next_record_done(State, [CT|CipherTexts], ConnectionStates0,
+ #ssl_tls{type = ?APPLICATION_DATA, fragment = iolist_to_binary(lists:reverse(Acc))});
+ #alert{} = Alert ->
+ Alert
+ end.
+
+next_record_done(#state{protocol_buffers = Buffers} = State, CipherTexts, ConnectionStates, Record) ->
+ {Record,
+ State#state{protocol_buffers = Buffers#protocol_buffers{tls_cipher_texts = CipherTexts},
+ connection_states = ConnectionStates}}.
+
+
next_event(StateName, Record, State) ->
next_event(StateName, Record, State, []).
-
-next_event(connection = StateName, no_record, State0, Actions) ->
- case next_record_if_active(State0) of
- {no_record, State} ->
- ssl_connection:hibernate_after(StateName, State, Actions);
- {#ssl_tls{} = Record, State} ->
- {next_state, StateName, State, [{next_event, internal, {protocol_record, Record}} | Actions]};
- {#alert{} = Alert, State} ->
- {next_state, StateName, State, [{next_event, internal, Alert} | Actions]}
+%%
+next_event(StateName, no_record, State0, Actions) ->
+ case next_record(State0) of
+ {no_record, State} ->
+ {next_state, StateName, State, Actions};
+ {#ssl_tls{} = Record, State} ->
+ {next_state, StateName, State, [{next_event, internal, {protocol_record, Record}} | Actions]};
+ #alert{} = Alert ->
+ Version = State0#state.connection_env#connection_env.negotiated_version,
+ ssl_connection:handle_own_alert(Alert, Version, StateName, State0)
end;
next_event(StateName, Record, State, Actions) ->
case Record of
@@ -172,58 +245,85 @@ next_event(StateName, Record, State, Actions) ->
#ssl_tls{} = Record ->
{next_state, StateName, State, [{next_event, internal, {protocol_record, Record}} | Actions]};
#alert{} = Alert ->
- {next_state, StateName, State, [{next_event, internal, Alert} | Actions]}
+ Version = State#state.connection_env#connection_env.negotiated_version,
+ ssl_connection:handle_own_alert(Alert, Version, StateName, State)
end.
-handle_common_event(internal, #alert{} = Alert, StateName,
- #state{negotiated_version = Version} = State) ->
- ssl_connection:handle_own_alert(Alert, Version, StateName, State);
+
+%%% TLS record protocol level application data messages
+handle_protocol_record(#ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, StateName,
+ #state{start_or_recv_from = From,
+ socket_options = #socket_options{active = false}} = State0) when From =/= undefined ->
+ case ssl_connection:read_application_data(Data, State0) of
+ {stop, _, _} = Stop->
+ Stop;
+ {Record, #state{start_or_recv_from = Caller} = State1} ->
+ TimerAction = case Caller of
+ undefined -> %% Passive recv complete cancel timer
+ [{{timeout, recv}, infinity, timeout}];
+ _ ->
+ []
+ end,
+ {next_state, StateName, State, Actions} = next_event(StateName, Record, State1, TimerAction),
+ ssl_connection:hibernate_after(StateName, State, Actions)
+ end;
+handle_protocol_record(#ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, StateName, State0) ->
+ case ssl_connection:read_application_data(Data, State0) of
+ {stop, _, _} = Stop->
+ Stop;
+ {Record, State1} ->
+ case next_event(StateName, Record, State1) of
+ {next_state, StateName, State, Actions} ->
+ ssl_connection:hibernate_after(StateName, State, Actions);
+ {stop, _, _} = Stop ->
+ Stop
+ end
+ end;
%%% TLS record protocol level handshake messages
-handle_common_event(internal, #ssl_tls{type = ?HANDSHAKE, fragment = Data},
+handle_protocol_record(#ssl_tls{type = ?HANDSHAKE, fragment = Data},
StateName, #state{protocol_buffers =
#protocol_buffers{tls_handshake_buffer = Buf0} = Buffers,
- negotiated_version = Version,
+ connection_env = #connection_env{negotiated_version = Version},
ssl_options = Options} = State0) ->
try
- {Packets, Buf} = tls_handshake:get_tls_handshake(Version,Data,Buf0, Options),
- State1 =
+ EffectiveVersion = effective_version(Version, Options),
+ {Packets, Buf} = tls_handshake:get_tls_handshake(EffectiveVersion,Data,Buf0, Options),
+ State =
State0#state{protocol_buffers =
Buffers#protocol_buffers{tls_handshake_buffer = Buf}},
case Packets of
[] ->
assert_buffer_sanity(Buf, Options),
- {Record, State} = next_record(State1),
- next_event(StateName, Record, State);
+ next_event(StateName, no_record, State);
_ ->
Events = tls_handshake_events(Packets),
case StateName of
connection ->
- ssl_connection:hibernate_after(StateName, State1, Events);
+ ssl_connection:hibernate_after(StateName, State, Events);
_ ->
+ HsEnv = State#state.handshake_env,
{next_state, StateName,
- State1#state{unprocessed_handshake_events = unprocessed_events(Events)}, Events}
+ State#state{protocol_buffers = Buffers,
+ handshake_env =
+ HsEnv#handshake_env{unprocessed_handshake_events
+ = unprocessed_events(Events)}}, Events}
end
end
catch throw:#alert{} = Alert ->
ssl_connection:handle_own_alert(Alert, Version, StateName, State0)
end;
-%%% TLS record protocol level application data messages
-handle_common_event(internal, #ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, StateName, State) ->
- {next_state, StateName, State, [{next_event, internal, {application_data, Data}}]};
%%% TLS record protocol level change cipher messages
-handle_common_event(internal, #ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = Data}, StateName, State) ->
+handle_protocol_record(#ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = Data}, StateName, State) ->
{next_state, StateName, State, [{next_event, internal, #change_cipher_spec{type = Data}}]};
%%% TLS record protocol level Alert messages
-handle_common_event(internal, #ssl_tls{type = ?ALERT, fragment = EncAlerts}, StateName,
- #state{negotiated_version = Version} = State) ->
+handle_protocol_record(#ssl_tls{type = ?ALERT, fragment = EncAlerts}, StateName,
+ #state{connection_env = #connection_env{negotiated_version = Version}} = State) ->
try decode_alerts(EncAlerts) of
Alerts = [_|_] ->
handle_alerts(Alerts, {next_state, StateName, State});
[] ->
ssl_connection:handle_own_alert(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, empty_alert),
- Version, StateName, State);
- #alert{} = Alert ->
- ssl_connection:handle_own_alert(Alert, Version, StateName, State)
+ Version, StateName, State)
catch
_:_ ->
ssl_connection:handle_own_alert(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, alert_decode_error),
@@ -231,75 +331,91 @@ handle_common_event(internal, #ssl_tls{type = ?ALERT, fragment = EncAlerts}, Sta
end;
%% Ignore unknown TLS record level protocol messages
-handle_common_event(internal, #ssl_tls{type = _Unknown}, StateName, State) ->
- {next_state, StateName, State}.
+handle_protocol_record(#ssl_tls{type = _Unknown}, StateName, State) ->
+ {next_state, StateName, State, []}.
%%====================================================================
%% Handshake handling
%%====================================================================
-renegotiate(#state{role = client} = State, Actions) ->
+renegotiation(Pid, WriteState) ->
+ gen_statem:call(Pid, {user_renegotiate, WriteState}).
+
+renegotiate(#state{static_env = #static_env{role = client},
+ handshake_env = HsEnv} = State, Actions) ->
%% Handle same way as if server requested
%% the renegotiation
Hs0 = ssl_handshake:init_handshake_history(),
- {next_state, connection, State#state{tls_handshake_history = Hs0},
+ {next_state, connection, State#state{handshake_env = HsEnv#handshake_env{tls_handshake_history = Hs0}},
[{next_event, internal, #hello_request{}} | Actions]};
-
-renegotiate(#state{role = server,
- socket = Socket,
- transport_cb = Transport,
- negotiated_version = Version,
+renegotiate(#state{static_env = #static_env{role = server,
+ socket = Socket,
+ transport_cb = Transport},
+ handshake_env = HsEnv,
+ connection_env = #connection_env{negotiated_version = Version},
connection_states = ConnectionStates0} = State0, Actions) ->
HelloRequest = ssl_handshake:hello_request(),
Frag = tls_handshake:encode_handshake(HelloRequest, Version),
Hs0 = ssl_handshake:init_handshake_history(),
{BinMsg, ConnectionStates} =
tls_record:encode_handshake(Frag, Version, ConnectionStates0),
- send(Transport, Socket, BinMsg),
- State1 = State0#state{connection_states =
+ tls_socket:send(Transport, Socket, BinMsg),
+ State = State0#state{connection_states =
ConnectionStates,
- tls_handshake_history = Hs0},
- {Record, State} = next_record(State1),
- next_event(hello, Record, State, Actions).
+ handshake_env = HsEnv#handshake_env{tls_handshake_history = Hs0}},
+ next_event(hello, no_record, State, Actions).
send_handshake(Handshake, State) ->
send_handshake_flight(queue_handshake(Handshake, State)).
-queue_handshake(Handshake, #state{negotiated_version = Version,
- tls_handshake_history = Hist0,
- flight_buffer = Flight0,
- ssl_options = #ssl_options{v2_hello_compatible = V2HComp},
+
+queue_handshake(Handshake, #state{handshake_env = #handshake_env{tls_handshake_history = Hist0} = HsEnv,
+ connection_env = #connection_env{negotiated_version = Version},
+ flight_buffer = Flight0,
+ ssl_options = SslOpts,
connection_states = ConnectionStates0} = State0) ->
{BinHandshake, ConnectionStates, Hist} =
- encode_handshake(Handshake, Version, ConnectionStates0, Hist0, V2HComp),
+ encode_handshake(Handshake, Version, ConnectionStates0, Hist0),
+ ssl_logger:debug(SslOpts#ssl_options.log_level, outbound, 'handshake', Handshake),
+ ssl_logger:debug(SslOpts#ssl_options.log_level, outbound, 'record', BinHandshake),
+
State0#state{connection_states = ConnectionStates,
- tls_handshake_history = Hist,
+ handshake_env = HsEnv#handshake_env{tls_handshake_history = Hist},
flight_buffer = Flight0 ++ [BinHandshake]}.
-send_handshake_flight(#state{socket = Socket,
- transport_cb = Transport,
+send_handshake_flight(#state{static_env = #static_env{socket = Socket,
+ transport_cb = Transport},
flight_buffer = Flight} = State0) ->
- send(Transport, Socket, Flight),
+ tls_socket:send(Transport, Socket, Flight),
{State0#state{flight_buffer = []}, []}.
-queue_change_cipher(Msg, #state{negotiated_version = Version,
- flight_buffer = Flight0,
- connection_states = ConnectionStates0} = State0) ->
+
+queue_change_cipher(Msg, #state{connection_env = #connection_env{negotiated_version = Version},
+ flight_buffer = Flight0,
+ ssl_options = SslOpts,
+ connection_states = ConnectionStates0} = State0) ->
{BinChangeCipher, ConnectionStates} =
encode_change_cipher(Msg, Version, ConnectionStates0),
+ ssl_logger:debug(SslOpts#ssl_options.log_level, outbound, 'record', BinChangeCipher),
State0#state{connection_states = ConnectionStates,
flight_buffer = Flight0 ++ [BinChangeCipher]}.
-reinit_handshake_data(State) ->
+reinit(#state{protocol_specific = #{sender := Sender},
+ connection_env = #connection_env{negotiated_version = Version},
+ connection_states = #{current_write := Write}} = State) ->
+ tls_sender:update_connection_state(Sender, Write, Version),
+ reinit_handshake_data(State).
+
+reinit_handshake_data(#state{handshake_env = HsEnv} =State) ->
%% premaster_secret, public_key_info and tls_handshake_info
%% are only needed during the handshake phase.
%% To reduce memory foot print of a connection reinitialize them.
State#state{
- premaster_secret = undefined,
- public_key_info = undefined,
- tls_handshake_history = ssl_handshake:init_handshake_history()
+ handshake_env = HsEnv#handshake_env{tls_handshake_history = ssl_handshake:init_handshake_history(),
+ public_key_info = undefined,
+ premaster_secret = undefined}
}.
-select_sni_extension(#client_hello{extensions = HelloExtensions}) ->
- HelloExtensions#hello_extensions.sni;
+select_sni_extension(#client_hello{extensions = #{sni := SNI}}) ->
+ SNI;
select_sni_extension(_) ->
undefined.
@@ -309,14 +425,6 @@ empty_connection_state(ConnectionEnd, BeastMitigation) ->
%%====================================================================
%% Alert and close handling
%%====================================================================
-send_alert(Alert, #state{negotiated_version = Version,
- socket = Socket,
- transport_cb = Transport,
- connection_states = ConnectionStates0} = State0) ->
- {BinMsg, ConnectionStates} =
- encode_alert(Alert, Version, ConnectionStates0),
- send(Transport, Socket, BinMsg),
- State0#state{connection_states = ConnectionStates}.
%%--------------------------------------------------------------------
-spec encode_alert(#alert{}, ssl_record:ssl_version(), ssl_record:connection_states()) ->
@@ -326,6 +434,38 @@ send_alert(Alert, #state{negotiated_version = Version,
%%--------------------------------------------------------------------
encode_alert(#alert{} = Alert, Version, ConnectionStates) ->
tls_record:encode_alert_record(Alert, Version, ConnectionStates).
+
+send_alert(Alert, #state{static_env = #static_env{socket = Socket,
+ transport_cb = Transport},
+ connection_env = #connection_env{negotiated_version = Version},
+ ssl_options = SslOpts,
+ connection_states = ConnectionStates0} = StateData0) ->
+ {BinMsg, ConnectionStates} =
+ encode_alert(Alert, Version, ConnectionStates0),
+ tls_socket:send(Transport, Socket, BinMsg),
+ ssl_logger:debug(SslOpts#ssl_options.log_level, outbound, 'record', BinMsg),
+ StateData0#state{connection_states = ConnectionStates}.
+
+%% If an ALERT sent in the connection state, should cause the TLS
+%% connection to end, we need to synchronize with the tls_sender
+%% process so that the ALERT if possible (that is the tls_sender process is
+%% not blocked) is sent before the connection process terminates and
+%% thereby closes the transport socket.
+send_alert_in_connection(#alert{level = ?FATAL} = Alert, State) ->
+ send_sync_alert(Alert, State);
+send_alert_in_connection(#alert{description = ?CLOSE_NOTIFY} = Alert, State) ->
+ send_sync_alert(Alert, State);
+send_alert_in_connection(Alert,
+ #state{protocol_specific = #{sender := Sender}}) ->
+ tls_sender:send_alert(Sender, Alert).
+send_sync_alert(
+ Alert, #state{protocol_specific = #{sender := Sender}} = State) ->
+ try tls_sender:send_and_ack_alert(Sender, Alert)
+ catch
+ _:_ ->
+ throw({stop, {shutdown, own_alert}, State})
+ end.
+
%% User closes or recursive call!
close({close, Timeout}, Socket, Transport = gen_tcp, _,_) ->
tls_socket:setopts(Transport, Socket, [{active, false}]),
@@ -357,31 +497,9 @@ protocol_name() ->
%%====================================================================
%% Data handling
%%====================================================================
-encode_data(Data, Version, ConnectionStates0)->
- tls_record:encode_data(Data, Version, ConnectionStates0).
-
-passive_receive(State0 = #state{user_data_buffer = Buffer}, StateName) ->
- case Buffer of
- <<>> ->
- {Record, State} = next_record(State0),
- next_event(StateName, Record, State);
- _ ->
- {Record, State} = ssl_connection:read_application_data(<<>>, State0),
- next_event(StateName, Record, State)
- end.
-
-next_record_if_active(State =
- #state{socket_options =
- #socket_options{active = false}}) ->
- {no_record ,State};
-next_record_if_active(State) ->
- next_record(State).
-send(Transport, Socket, Data) ->
- tls_socket:send(Transport, Socket, Data).
-
-socket(Pid, Transport, Socket, Connection, Tracker) ->
- tls_socket:socket(Pid, Transport, Socket, Connection, Tracker).
+socket(Pids, Transport, Socket, Tracker) ->
+ tls_socket:socket(Pids, Transport, Socket, ?MODULE, Tracker).
setopts(Transport, Socket, Other) ->
tls_socket:setopts(Transport, Socket, Other).
@@ -399,34 +517,40 @@ getopts(Transport, Socket, Tag) ->
%%--------------------------------------------------------------------
init({call, From}, {start, Timeout},
- #state{host = Host, port = Port, role = client,
- ssl_options = #ssl_options{v2_hello_compatible = V2HComp} = SslOpts,
+ #state{static_env = #static_env{role = client,
+ host = Host,
+ port = Port,
+ transport_cb = Transport,
+ socket = Socket,
+ session_cache = Cache,
+ session_cache_cb = CacheCb},
+ handshake_env = #handshake_env{renegotiation = {Renegotiation, _}} = HsEnv,
+ connection_env = CEnv,
+ ssl_options = SslOpts,
session = #session{own_certificate = Cert} = Session0,
- transport_cb = Transport, socket = Socket,
- connection_states = ConnectionStates0,
- renegotiation = {Renegotiation, _},
- session_cache = Cache,
- session_cache_cb = CacheCb
+ connection_states = ConnectionStates0
} = State0) ->
- Timer = ssl_connection:start_or_recv_cancel_timer(Timeout, From),
+ KeyShare = maybe_generate_client_shares(SslOpts),
Hello = tls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
- Cache, CacheCb, Renegotiation, Cert),
-
- Version = Hello#client_hello.client_version,
- HelloVersion = tls_record:hello_version(Version, SslOpts#ssl_options.versions),
+ Cache, CacheCb, Renegotiation, Cert, KeyShare),
+
+ HelloVersion = tls_record:hello_version(SslOpts#ssl_options.versions),
Handshake0 = ssl_handshake:init_handshake_history(),
{BinMsg, ConnectionStates, Handshake} =
- encode_handshake(Hello, HelloVersion, ConnectionStates0, Handshake0, V2HComp),
- send(Transport, Socket, BinMsg),
- State1 = State0#state{connection_states = ConnectionStates,
- negotiated_version = Version, %% Requested version
- session =
- Session0#session{session_id = Hello#client_hello.session_id},
- tls_handshake_history = Handshake,
- start_or_recv_from = From,
- timer = Timer},
- {Record, State} = next_record(State1),
- next_event(hello, Record, State);
+ encode_handshake(Hello, HelloVersion, ConnectionStates0, Handshake0),
+ tls_socket:send(Transport, Socket, BinMsg),
+ ssl_logger:debug(SslOpts#ssl_options.log_level, outbound, 'handshake', Hello),
+ ssl_logger:debug(SslOpts#ssl_options.log_level, outbound, 'record', BinMsg),
+
+ State = State0#state{connection_states = ConnectionStates,
+ connection_env = CEnv#connection_env{negotiated_version = HelloVersion}, %% Requested version
+ session =
+ Session0#session{session_id = Hello#client_hello.session_id},
+ handshake_env = HsEnv#handshake_env{tls_handshake_history = Handshake},
+ start_or_recv_from = From,
+ key_share = KeyShare},
+ next_event(hello, no_record, State, [{{timeout, handshake}, Timeout, close}]);
+
init(Type, Event, State) ->
gen_handshake(?FUNCTION_NAME, Type, Event, State).
@@ -435,13 +559,13 @@ init(Type, Event, State) ->
{start, timeout()} | term(), #state{}) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
+error({call, From}, {start, _Timeout},
+ #state{protocol_specific = #{error := Error}} = State) ->
+ {stop_and_reply, {shutdown, normal},
+ [{reply, From, {error, Error}}], State};
-error({call, From}, {start, _Timeout}, {Error, State}) ->
- {stop_and_reply, normal, {reply, From, {error, Error}}, State};
-error({call, From}, {start, _Timeout}, #state{protocol_specific = #{error := Error}} = State) ->
- {stop_and_reply, normal, {reply, From, {error, Error}}, State};
-error({call, _} = Call, Msg, {Error, #state{protocol_specific = Map} = State}) ->
- gen_handshake(?FUNCTION_NAME, Call, Msg, State#state{protocol_specific = Map#{error => Error}});
+error({call, _} = Call, Msg, State) ->
+ gen_handshake(?FUNCTION_NAME, Call, Msg, State);
error(_, _, _) ->
{keep_state_and_data, [postpone]}.
@@ -451,43 +575,78 @@ error(_, _, _) ->
#state{}) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
+hello(internal, #client_hello{extensions = Extensions} = Hello,
+ #state{ssl_options = #ssl_options{handshake = hello},
+ handshake_env = HsEnv,
+ start_or_recv_from = From} = State) ->
+ {next_state, user_hello, State#state{start_or_recv_from = undefined,
+ handshake_env = HsEnv#handshake_env{hello = Hello}},
+ [{reply, From, {ok, Extensions}}]};
+hello(internal, #server_hello{extensions = Extensions} = Hello,
+ #state{ssl_options = #ssl_options{handshake = hello},
+ handshake_env = HsEnv,
+ start_or_recv_from = From} = State) ->
+ {next_state, user_hello, State#state{start_or_recv_from = undefined,
+ handshake_env = HsEnv#handshake_env{hello = Hello}},
+ [{reply, From, {ok, Extensions}}]};
+
hello(internal, #client_hello{client_version = ClientVersion} = Hello,
#state{connection_states = ConnectionStates0,
- port = Port, session = #session{own_certificate = Cert} = Session0,
- renegotiation = {Renegotiation, _},
- session_cache = Cache,
- session_cache_cb = CacheCb,
- negotiated_protocol = CurrentProtocol,
- key_algorithm = KeyExAlg,
+ static_env = #static_env{
+ port = Port,
+ session_cache = Cache,
+ session_cache_cb = CacheCb},
+ handshake_env = #handshake_env{kex_algorithm = KeyExAlg,
+ renegotiation = {Renegotiation, _},
+ negotiated_protocol = CurrentProtocol} = HsEnv,
+ connection_env = CEnv,
+ session = #session{own_certificate = Cert} = Session0,
ssl_options = SslOpts} = State) ->
- case tls_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb,
- ConnectionStates0, Cert, KeyExAlg}, Renegotiation) of
- #alert{} = Alert ->
- ssl_connection:handle_own_alert(Alert, ClientVersion, hello, State);
- {Version, {Type, Session},
- ConnectionStates, Protocol0, ServerHelloExt, HashSign} ->
- Protocol = case Protocol0 of
- undefined -> CurrentProtocol;
- _ -> Protocol0
- end,
- gen_handshake(?FUNCTION_NAME, internal, {common_client_hello, Type, ServerHelloExt},
- State#state{connection_states = ConnectionStates,
- negotiated_version = Version,
- hashsign_algorithm = HashSign,
- client_hello_version = ClientVersion,
- session = Session,
- negotiated_protocol = Protocol})
+ case choose_tls_version(SslOpts, Hello) of
+ 'tls_v1.3' ->
+ %% Continue in TLS 1.3 'start' state
+ {next_state, start, State, [{next_event, internal, Hello}]};
+ 'tls_v1.2' ->
+ case tls_handshake:hello(Hello,
+ SslOpts,
+ {Port, Session0, Cache, CacheCb,
+ ConnectionStates0, Cert, KeyExAlg},
+ Renegotiation) of
+ #alert{} = Alert ->
+ ssl_connection:handle_own_alert(Alert, ClientVersion, hello,
+ State#state{connection_env = CEnv#connection_env{negotiated_version
+ = ClientVersion}});
+ {Version, {Type, Session},
+ ConnectionStates, Protocol0, ServerHelloExt, HashSign} ->
+ Protocol = case Protocol0 of
+ undefined -> CurrentProtocol;
+ _ -> Protocol0
+ end,
+ gen_handshake(?FUNCTION_NAME,
+ internal,
+ {common_client_hello, Type, ServerHelloExt},
+ State#state{connection_states = ConnectionStates,
+ connection_env = CEnv#connection_env{negotiated_version = Version},
+ handshake_env = HsEnv#handshake_env{
+ hashsign_algorithm = HashSign,
+ client_hello_version = ClientVersion,
+ negotiated_protocol = Protocol},
+ session = Session
+ })
+ end
+
end;
-hello(internal, #server_hello{} = Hello,
+hello(internal, #server_hello{} = Hello,
#state{connection_states = ConnectionStates0,
- negotiated_version = ReqVersion,
- role = client,
- renegotiation = {Renegotiation, _},
+ connection_env = #connection_env{negotiated_version = ReqVersion} = CEnv,
+ static_env = #static_env{role = client},
+ handshake_env = #handshake_env{renegotiation = {Renegotiation, _}},
ssl_options = SslOptions} = State) ->
case tls_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of
- #alert{} = Alert ->
- ssl_connection:handle_own_alert(Alert, ReqVersion, hello, State);
+ #alert{} = Alert -> %%TODO
+ ssl_connection:handle_own_alert(Alert, ReqVersion, hello,
+ State#state{connection_env = CEnv#connection_env{negotiated_version = ReqVersion}});
{Version, NewId, ConnectionStates, ProtoExt, Protocol} ->
ssl_connection:handle_session(Hello,
Version, NewId, ConnectionStates, ProtoExt, Protocol, State)
@@ -497,6 +656,9 @@ hello(info, Event, State) ->
hello(Type, Event, State) ->
gen_handshake(?FUNCTION_NAME, Type, Event, State).
+user_hello(Type, Event, State) ->
+ gen_handshake(?FUNCTION_NAME, Type, Event, State).
+
%%--------------------------------------------------------------------
-spec abbreviated(gen_statem:event_type(), term(), #state{}) ->
gen_statem:state_function_result().
@@ -531,38 +693,103 @@ cipher(Type, Event, State) ->
%%--------------------------------------------------------------------
connection(info, Event, State) ->
gen_info(Event, ?FUNCTION_NAME, State);
+connection({call, From}, {user_renegotiate, WriteState},
+ #state{connection_states = ConnectionStates} = State) ->
+ {next_state, ?FUNCTION_NAME, State#state{connection_states = ConnectionStates#{current_write => WriteState}},
+ [{next_event,{call, From}, renegotiate}]};
+connection({call, From},
+ {close, {Pid, _Timeout}},
+ #state{connection_env = #connection_env{terminated = closed} =CEnv} = State) ->
+ {next_state, downgrade, State#state{connection_env =
+ CEnv#connection_env{terminated = true,
+ downgrade = {Pid, From}}},
+ [{next_event, internal, ?ALERT_REC(?WARNING, ?CLOSE_NOTIFY)}]};
+connection({call, From},
+ {close,{Pid, Timeout}},
+ #state{connection_states = ConnectionStates,
+ protocol_specific = #{sender := Sender},
+ connection_env = CEnv
+ } = State0) ->
+ case tls_sender:downgrade(Sender, Timeout) of
+ {ok, Write} ->
+ %% User downgrades connection
+ %% When downgrading an TLS connection to a transport connection
+ %% we must recive the close alert from the peer before releasing the
+ %% transport socket.
+ State = send_alert(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY),
+ State0#state{connection_states =
+ ConnectionStates#{current_write => Write}}),
+ {next_state, downgrade, State#state{connection_env =
+ CEnv#connection_env{downgrade = {Pid, From},
+ terminated = true}},
+ [{timeout, Timeout, downgrade}]};
+ {error, timeout} ->
+ {stop_and_reply, {shutdown, downgrade_fail}, [{reply, From, {error, timeout}}]}
+ end;
connection(internal, #hello_request{},
- #state{role = client, host = Host, port = Port,
+ #state{static_env = #static_env{role = client,
+ host = Host,
+ port = Port,
+ session_cache = Cache,
+ session_cache_cb = CacheCb},
+ handshake_env = #handshake_env{renegotiation = {Renegotiation, peer}},
session = #session{own_certificate = Cert} = Session0,
- session_cache = Cache, session_cache_cb = CacheCb,
- ssl_options = SslOpts,
- connection_states = ConnectionStates0,
- renegotiation = {Renegotiation, _}} = State0) ->
- Hello = tls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
- Cache, CacheCb, Renegotiation, Cert),
- {State1, Actions} = send_handshake(Hello, State0),
- {Record, State} =
- next_record(
- State1#state{session = Session0#session{session_id
- = Hello#client_hello.session_id}}),
- next_event(hello, Record, State, Actions);
+ ssl_options = SslOpts,
+ protocol_specific = #{sender := Pid},
+ connection_states = ConnectionStates} = State0) ->
+ try tls_sender:peer_renegotiate(Pid) of
+ {ok, Write} ->
+ Hello = tls_handshake:client_hello(Host, Port, ConnectionStates, SslOpts,
+ Cache, CacheCb, Renegotiation, Cert, undefined),
+ {State, Actions} = send_handshake(Hello, State0#state{connection_states = ConnectionStates#{current_write => Write}}),
+ next_event(hello, no_record, State#state{session = Session0#session{session_id
+ = Hello#client_hello.session_id}}, Actions)
+ catch
+ _:_ ->
+ {stop, {shutdown, sender_blocked}, State0}
+ end;
+connection(internal, #hello_request{},
+ #state{static_env = #static_env{role = client,
+ host = Host,
+ port = Port,
+ session_cache = Cache,
+ session_cache_cb = CacheCb},
+ handshake_env = #handshake_env{renegotiation = {Renegotiation, _}},
+ session = #session{own_certificate = Cert} = Session0,
+ ssl_options = SslOpts,
+ connection_states = ConnectionStates} = State0) ->
+ Hello = tls_handshake:client_hello(Host, Port, ConnectionStates, SslOpts,
+ Cache, CacheCb, Renegotiation, Cert, undefined),
+
+ {State, Actions} = send_handshake(Hello, State0),
+ next_event(hello, no_record, State#state{session = Session0#session{session_id
+ = Hello#client_hello.session_id}}, Actions);
connection(internal, #client_hello{} = Hello,
- #state{role = server, allow_renegotiate = true} = State0) ->
+ #state{static_env = #static_env{role = server},
+ handshake_env = #handshake_env{allow_renegotiate = true}= HsEnv,
+ connection_states = CS,
+ protocol_specific = #{sender := Sender}
+ } = State) ->
%% Mitigate Computational DoS attack
%% http://www.educatedguesswork.org/2011/10/ssltls_and_computational_dos.html
%% http://www.thc.org/thc-ssl-dos/ Rather than disabling client
%% initiated renegotiation we will disallow many client initiated
%% renegotiations immediately after each other.
erlang:send_after(?WAIT_TO_ALLOW_RENEGOTIATION, self(), allow_renegotiate),
- {Record, State} = next_record(State0#state{allow_renegotiate = false,
- renegotiation = {true, peer}}),
- next_event(hello, Record, State, [{next_event, internal, Hello}]);
+ {ok, Write} = tls_sender:renegotiate(Sender),
+ next_event(hello, no_record, State#state{connection_states = CS#{current_write => Write},
+ handshake_env = HsEnv#handshake_env{renegotiation = {true, peer},
+ allow_renegotiate = false}
+ },
+ [{next_event, internal, Hello}]);
connection(internal, #client_hello{},
- #state{role = server, allow_renegotiate = false} = State0) ->
+ #state{static_env = #static_env{role = server},
+ handshake_env = #handshake_env{allow_renegotiate = false}} = State0) ->
Alert = ?ALERT_REC(?WARNING, ?NO_RENEGOTIATION),
- State1 = send_alert(Alert, State0),
- {Record, State} = ssl_connection:prepare_connection(State1, ?MODULE),
- next_event(?FUNCTION_NAME, Record, State);
+ send_alert_in_connection(Alert, State0),
+ State = reinit_handshake_data(State0),
+ next_event(?FUNCTION_NAME, no_record, State);
+
connection(Type, Event, State) ->
ssl_connection:?FUNCTION_NAME(Type, Event, State, ?MODULE).
@@ -570,17 +797,152 @@ connection(Type, Event, State) ->
-spec downgrade(gen_statem:event_type(), term(), #state{}) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
+downgrade(internal, #alert{description = ?CLOSE_NOTIFY},
+ #state{static_env = #static_env{transport_cb = Transport,
+ socket = Socket},
+ connection_env = #connection_env{downgrade = {Pid, From}}} = State) ->
+ tls_socket:setopts(Transport, Socket, [{active, false}, {packet, 0}, {mode, binary}]),
+ Transport:controlling_process(Socket, Pid),
+ {stop_and_reply, {shutdown, downgrade},[{reply, From, {ok, Socket}}], State};
+downgrade(timeout, downgrade, #state{ connection_env = #connection_env{downgrade = {_, From}}} = State) ->
+ {stop_and_reply, {shutdown, normal},[{reply, From, {error, timeout}}], State};
+downgrade(info, {CloseTag, Socket},
+ #state{static_env = #static_env{socket = Socket,
+ close_tag = CloseTag},
+ connection_env = #connection_env{downgrade = {_, From}}} =
+ State) ->
+ {stop_and_reply, {shutdown, normal},[{reply, From, {error, CloseTag}}], State};
+downgrade(info, Info, State) ->
+ handle_info(Info, ?FUNCTION_NAME, State);
downgrade(Type, Event, State) ->
ssl_connection:?FUNCTION_NAME(Type, Event, State, ?MODULE).
+%%--------------------------------------------------------------------
+%% TLS 1.3 state functions
+%%--------------------------------------------------------------------
+%%--------------------------------------------------------------------
+-spec start(gen_statem:event_type(), term(), #state{}) ->
+ gen_statem:state_function_result().
+%%--------------------------------------------------------------------
+start(info, Event, State) ->
+ gen_info_1_3(Event, ?FUNCTION_NAME, State);
+start(Type, Event, State) ->
+ gen_handshake_1_3(?FUNCTION_NAME, Type, Event, State).
+
+%%--------------------------------------------------------------------
+-spec negotiated(gen_statem:event_type(), term(), #state{}) ->
+ gen_statem:state_function_result().
+%%--------------------------------------------------------------------
+negotiated(info, Event, State) ->
+ gen_info_1_3(Event, ?FUNCTION_NAME, State);
+negotiated(Type, Event, State) ->
+ gen_handshake_1_3(?FUNCTION_NAME, Type, Event, State).
+
+%%--------------------------------------------------------------------
+-spec recvd_ch(gen_statem:event_type(), term(), #state{}) ->
+ gen_statem:state_function_result().
+%%--------------------------------------------------------------------
+recvd_ch(info, Event, State) ->
+ gen_info_1_3(Event, ?FUNCTION_NAME, State);
+recvd_ch(Type, Event, State) ->
+ gen_handshake_1_3(?FUNCTION_NAME, Type, Event, State).
+
+%%--------------------------------------------------------------------
+-spec wait_cert(gen_statem:event_type(), term(), #state{}) ->
+ gen_statem:state_function_result().
+%%--------------------------------------------------------------------
+wait_cert(info, Event, State) ->
+ gen_info_1_3(Event, ?FUNCTION_NAME, State);
+wait_cert(Type, Event, State) ->
+ gen_handshake_1_3(?FUNCTION_NAME, Type, Event, State).
+
+%%--------------------------------------------------------------------
+-spec wait_cv(gen_statem:event_type(), term(), #state{}) ->
+ gen_statem:state_function_result().
+%%--------------------------------------------------------------------
+wait_cv(info, Event, State) ->
+ gen_info_1_3(Event, ?FUNCTION_NAME, State);
+wait_cv(Type, Event, State) ->
+ gen_handshake_1_3(?FUNCTION_NAME, Type, Event, State).
+
+%%--------------------------------------------------------------------
+-spec wait_eoed(gen_statem:event_type(), term(), #state{}) ->
+ gen_statem:state_function_result().
+%%--------------------------------------------------------------------
+wait_eoed(info, Event, State) ->
+ gen_info_1_3(Event, ?FUNCTION_NAME, State);
+wait_eoed(Type, Event, State) ->
+ gen_handshake_1_3(?FUNCTION_NAME, Type, Event, State).
+
+%%--------------------------------------------------------------------
+-spec wait_finished(gen_statem:event_type(), term(), #state{}) ->
+ gen_statem:state_function_result().
+%%--------------------------------------------------------------------
+wait_finished(info, Event, State) ->
+ gen_info_1_3(Event, ?FUNCTION_NAME, State);
+wait_finished(Type, Event, State) ->
+ gen_handshake_1_3(?FUNCTION_NAME, Type, Event, State).
+
+%%--------------------------------------------------------------------
+-spec wait_flight2(gen_statem:event_type(), term(), #state{}) ->
+ gen_statem:state_function_result().
+%%--------------------------------------------------------------------
+wait_flight2(info, Event, State) ->
+ gen_info_1_3(Event, ?FUNCTION_NAME, State);
+wait_flight2(Type, Event, State) ->
+ gen_handshake_1_3(?FUNCTION_NAME, Type, Event, State).
+
+%%--------------------------------------------------------------------
+-spec connected(gen_statem:event_type(), term(), #state{}) ->
+ gen_statem:state_function_result().
+%%--------------------------------------------------------------------
+connected(info, Event, State) ->
+ gen_info_1_3(Event, ?FUNCTION_NAME, State);
+connected(Type, Event, State) ->
+ gen_handshake_1_3(?FUNCTION_NAME, Type, Event, State).
+
+%%--------------------------------------------------------------------
+-spec wait_cert_cr(gen_statem:event_type(), term(), #state{}) ->
+ gen_statem:state_function_result().
+%%--------------------------------------------------------------------
+wait_cert_cr(info, Event, State) ->
+ gen_info_1_3(Event, ?FUNCTION_NAME, State);
+wait_cert_cr(Type, Event, State) ->
+ gen_handshake_1_3(?FUNCTION_NAME, Type, Event, State).
+
+%%--------------------------------------------------------------------
+-spec wait_ee(gen_statem:event_type(), term(), #state{}) ->
+ gen_statem:state_function_result().
+%%--------------------------------------------------------------------
+wait_ee(info, Event, State) ->
+ gen_info_1_3(Event, ?FUNCTION_NAME, State);
+wait_ee(Type, Event, State) ->
+ gen_handshake_1_3(?FUNCTION_NAME, Type, Event, State).
+
+%%--------------------------------------------------------------------
+-spec wait_sh(gen_statem:event_type(), term(), #state{}) ->
+ gen_statem:state_function_result().
+%%--------------------------------------------------------------------
+wait_sh(info, Event, State) ->
+ gen_info_1_3(Event, ?FUNCTION_NAME, State);
+wait_sh(Type, Event, State) ->
+ gen_handshake_1_3(?FUNCTION_NAME, Type, Event, State).
+
%--------------------------------------------------------------------
%% gen_statem callbacks
%%--------------------------------------------------------------------
callback_mode() ->
state_functions.
+terminate({shutdown, {sender_died, Reason}}, _StateName,
+ #state{static_env = #static_env{socket = Socket,
+ transport_cb = Transport}}
+ = State) ->
+ ssl_connection:handle_trusted_certs_db(State),
+ close(Reason, Socket, Transport, undefined, undefined);
terminate(Reason, StateName, State) ->
- catch ssl_connection:terminate(Reason, StateName, State).
+ catch ssl_connection:terminate(Reason, StateName, State),
+ ensure_sender_terminate(Reason, State).
format_status(Type, Data) ->
ssl_connection:format_status(Type, Data).
@@ -591,51 +953,100 @@ code_change(_OldVsn, StateName, State, _) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions, Tracker}, User,
- {CbModule, DataTag, CloseTag, ErrorTag}) ->
- #ssl_options{beast_mitigation = BeastMitigation} = SSLOptions,
+initial_state(Role, Sender, Host, Port, Socket, {SSLOptions, SocketOptions, Tracker}, User,
+ {CbModule, DataTag, CloseTag, ErrorTag, PassiveTag}) ->
+ #ssl_options{beast_mitigation = BeastMitigation,
+ erl_dist = IsErlDist} = SSLOptions,
ConnectionStates = tls_record:init_connection_states(Role, BeastMitigation),
-
SessionCacheCb = case application:get_env(ssl, session_cb) of
{ok, Cb} when is_atom(Cb) ->
Cb;
_ ->
ssl_session_cache
end,
-
- Monitor = erlang:monitor(process, User),
-
- #state{socket_options = SocketOptions,
- ssl_options = SSLOptions,
- session = #session{is_resumable = new},
- transport_cb = CbModule,
- data_tag = DataTag,
- close_tag = CloseTag,
- error_tag = ErrorTag,
- role = Role,
- host = Host,
- port = Port,
- socket = Socket,
- connection_states = ConnectionStates,
- protocol_buffers = #protocol_buffers{},
- user_application = {Monitor, User},
- user_data_buffer = <<>>,
- session_cache_cb = SessionCacheCb,
- renegotiation = {false, first},
- allow_renegotiate = SSLOptions#ssl_options.client_renegotiation,
- start_or_recv_from = undefined,
- protocol_cb = ?MODULE,
- tracker = Tracker,
- flight_buffer = []
- }.
-
-next_tls_record(Data, StateName, #state{protocol_buffers =
- #protocol_buffers{tls_record_buffer = Buf0,
- tls_cipher_texts = CT0} = Buffers}
- = State0) ->
- case tls_record:get_tls_records(Data,
- acceptable_record_versions(StateName, State0),
- Buf0) of
+ InternalActiveN = case application:get_env(ssl, internal_active_n) of
+ {ok, N} when is_integer(N) andalso (not IsErlDist) ->
+ N;
+ _ ->
+ ?INTERNAL_ACTIVE_N
+ end,
+ UserMonitor = erlang:monitor(process, User),
+ InitStatEnv = #static_env{
+ role = Role,
+ transport_cb = CbModule,
+ protocol_cb = ?MODULE,
+ data_tag = DataTag,
+ close_tag = CloseTag,
+ error_tag = ErrorTag,
+ passive_tag = PassiveTag,
+ host = Host,
+ port = Port,
+ socket = Socket,
+ session_cache_cb = SessionCacheCb,
+ tracker = Tracker
+ },
+ #state{
+ static_env = InitStatEnv,
+ handshake_env = #handshake_env{
+ tls_handshake_history = ssl_handshake:init_handshake_history(),
+ renegotiation = {false, first},
+ allow_renegotiate = SSLOptions#ssl_options.client_renegotiation
+ },
+ connection_env = #connection_env{user_application = {UserMonitor, User}},
+ socket_options = SocketOptions,
+ ssl_options = SSLOptions,
+ session = #session{is_resumable = new},
+ connection_states = ConnectionStates,
+ protocol_buffers = #protocol_buffers{},
+ user_data_buffer = {[],0,[]},
+ start_or_recv_from = undefined,
+ flight_buffer = [],
+ protocol_specific = #{sender => Sender,
+ active_n => InternalActiveN,
+ active_n_toggle => true
+ }
+ }.
+
+initialize_tls_sender(#state{static_env = #static_env{
+ role = Role,
+ transport_cb = Transport,
+ socket = Socket,
+ tracker = Tracker
+ },
+ connection_env = #connection_env{negotiated_version = Version},
+ socket_options = SockOpts,
+ ssl_options = #ssl_options{renegotiate_at = RenegotiateAt,
+ log_level = LogLevel},
+ connection_states = #{current_write := ConnectionWriteState},
+ protocol_specific = #{sender := Sender}}) ->
+ Init = #{current_write => ConnectionWriteState,
+ role => Role,
+ socket => Socket,
+ socket_options => SockOpts,
+ tracker => Tracker,
+ transport_cb => Transport,
+ negotiated_version => Version,
+ renegotiate_at => RenegotiateAt,
+ log_level => LogLevel},
+ tls_sender:initialize(Sender, Init).
+
+next_tls_record(Data, StateName,
+ #state{protocol_buffers =
+ #protocol_buffers{tls_record_buffer = Buf0,
+ tls_cipher_texts = CT0} = Buffers,
+ ssl_options = SslOpts} = State0) ->
+ Versions =
+ %% TLS 1.3 Client/Server
+ %% - Ignore TLSPlaintext.legacy_record_version
+ %% - Verify that TLSCiphertext.legacy_record_version is set to 0x0303 for all records
+ %% other than an initial ClientHello, where it MAY also be 0x0301.
+ case StateName of
+ hello ->
+ [tls_record:protocol_version(Vsn) || Vsn <- ?ALL_AVAILABLE_VERSIONS];
+ _ ->
+ State0#state.connection_env#connection_env.negotiated_version
+ end,
+ case tls_record:get_tls_records(Data, Versions, Buf0, SslOpts) of
{Records, Buf1} ->
CT1 = CT0 ++ Records,
next_record(State0#state{protocol_buffers =
@@ -645,15 +1056,7 @@ next_tls_record(Data, StateName, #state{protocol_buffers =
handle_record_alert(Alert, State0)
end.
-acceptable_record_versions(hello, #state{ssl_options = #ssl_options{v2_hello_compatible = true}}) ->
- [tls_record:protocol_version(Vsn) || Vsn <- ?ALL_AVAILABLE_VERSIONS ++ ['sslv2']];
-acceptable_record_versions(hello, _) ->
- [tls_record:protocol_version(Vsn) || Vsn <- ?ALL_AVAILABLE_VERSIONS];
-acceptable_record_versions(_, #state{negotiated_version = Version}) ->
- [Version].
-handle_record_alert(#alert{description = ?BAD_RECORD_MAC},
- #state{ssl_options = #ssl_options{v2_hello_compatible = true}}) ->
- ?ALERT_REC(?FATAL, ?PROTOCOL_VERSION);
+
handle_record_alert(Alert, _) ->
Alert.
@@ -664,26 +1067,35 @@ tls_handshake_events(Packets) ->
%% raw data from socket, upack records
handle_info({Protocol, _, Data}, StateName,
- #state{data_tag = Protocol} = State0) ->
+ #state{static_env = #static_env{data_tag = Protocol}} = State0) ->
case next_tls_record(Data, StateName, State0) of
{Record, State} ->
next_event(StateName, Record, State);
#alert{} = Alert ->
ssl_connection:handle_normal_shutdown(Alert, StateName, State0),
- {stop, {shutdown, own_alert}}
+ {stop, {shutdown, own_alert}, State0}
end;
+handle_info({PassiveTag, Socket}, StateName,
+ #state{static_env = #static_env{socket = Socket,
+ passive_tag = PassiveTag},
+ protocol_specific = PS
+ } = State) ->
+ next_event(StateName, no_record,
+ State#state{protocol_specific = PS#{active_n_toggle => true}});
handle_info({CloseTag, Socket}, StateName,
- #state{socket = Socket, close_tag = CloseTag,
+ #state{static_env = #static_env{socket = Socket, close_tag = CloseTag},
+ connection_env = #connection_env{negotiated_version = Version},
socket_options = #socket_options{active = Active},
protocol_buffers = #protocol_buffers{tls_cipher_texts = CTs},
- negotiated_version = Version} = State) ->
+ user_data_buffer = {_,BufferSize,_},
+ protocol_specific = PS} = State) ->
%% Note that as of TLS 1.1,
%% failure to properly close a connection no longer requires that a
%% session not be resumed. This is a change from TLS 1.0 to conform
%% with widespread implementation practice.
- case (Active == false) andalso (CTs =/= []) of
+ case (Active == false) andalso ((CTs =/= []) or (BufferSize =/= 0)) of
false ->
case Version of
{1, N} when N >= 1 ->
@@ -697,28 +1109,40 @@ handle_info({CloseTag, Socket}, StateName,
end,
ssl_connection:handle_normal_shutdown(?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), StateName, State),
- {stop, {shutdown, transport_closed}};
+ {stop, {shutdown, transport_closed}, State};
true ->
%% Fixes non-delivery of final TLS record in {active, once}.
%% Basically allows the application the opportunity to set {active, once} again
- %% and then receive the final message.
- next_event(StateName, no_record, State)
+ %% and then receive the final message. Set internal active_n to zero
+ %% to ensure socket close message is sent if there is not enough data to deliver.
+ next_event(StateName, no_record, State#state{protocol_specific = PS#{active_n_toggle => true}})
end;
+handle_info({'EXIT', Sender, Reason}, _,
+ #state{protocol_specific = #{sender := Sender}} = State) ->
+ {stop, {shutdown, {sender_died, Reason}}, State};
handle_info(Msg, StateName, State) ->
ssl_connection:StateName(info, Msg, State, ?MODULE).
handle_alerts([], Result) ->
Result;
-handle_alerts(_, {stop,_} = Stop) ->
+handle_alerts(_, {stop, _, _} = Stop) ->
Stop;
+handle_alerts([#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} | _Alerts],
+ {next_state, connection = StateName, #state{connection_env = CEnv,
+ socket_options = #socket_options{active = false},
+ user_data_buffer = {_,BufferSize,_},
+ protocol_buffers = #protocol_buffers{tls_cipher_texts = CTs}} =
+ State}) when (BufferSize =/= 0) orelse
+ (CTs =/= []) ->
+ {next_state, StateName, State#state{connection_env = CEnv#connection_env{terminated = true}}};
handle_alerts([Alert | Alerts], {next_state, StateName, State}) ->
handle_alerts(Alerts, ssl_connection:handle_alert(Alert, StateName, State));
handle_alerts([Alert | Alerts], {next_state, StateName, State, _Actions}) ->
handle_alerts(Alerts, ssl_connection:handle_alert(Alert, StateName, State)).
-encode_handshake(Handshake, Version, ConnectionStates0, Hist0, V2HComp) ->
+encode_handshake(Handshake, Version, ConnectionStates0, Hist0) ->
Frag = tls_handshake:encode_handshake(Handshake, Version),
- Hist = ssl_handshake:update_handshake_history(Hist0, Frag, V2HComp),
+ Hist = ssl_handshake:update_handshake_history(Hist0, Frag),
{Encoded, ConnectionStates} =
tls_record:encode_handshake(Frag, Version, ConnectionStates0),
{Encoded, ConnectionStates, Hist}.
@@ -726,11 +1150,12 @@ encode_handshake(Handshake, Version, ConnectionStates0, Hist0, V2HComp) ->
encode_change_cipher(#change_cipher_spec{}, Version, ConnectionStates) ->
tls_record:encode_change_cipher_spec(Version, ConnectionStates).
+-spec decode_alerts(binary()) -> list().
decode_alerts(Bin) ->
ssl_alert:decode(Bin).
gen_handshake(StateName, Type, Event,
- #state{negotiated_version = Version} = State) ->
+ #state{connection_env = #connection_env{negotiated_version = Version}} = State) ->
try ssl_connection:StateName(Type, Event, State, ?MODULE) of
Result ->
Result
@@ -740,19 +1165,33 @@ gen_handshake(StateName, Type, Event,
malformed_handshake_data),
Version, StateName, State)
end.
-
-gen_info(Event, connection = StateName, #state{negotiated_version = Version} = State) ->
+
+
+gen_handshake_1_3(StateName, Type, Event,
+ #state{connection_env = #connection_env{negotiated_version = Version}} = State) ->
+ try tls_connection_1_3:StateName(Type, Event, State, ?MODULE) of
+ Result ->
+ Result
+ catch
+ _:_ ->
+ ssl_connection:handle_own_alert(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE,
+ malformed_handshake_data),
+ Version, StateName, State)
+ end.
+
+
+gen_info(Event, connection = StateName, #state{connection_env = #connection_env{negotiated_version = Version}} = State) ->
try handle_info(Event, StateName, State) of
Result ->
Result
catch
- _:_ ->
+ _:_ ->
ssl_connection:handle_own_alert(?ALERT_REC(?FATAL, ?INTERNAL_ERROR,
malformed_data),
Version, StateName, State)
end;
-gen_info(Event, StateName, #state{negotiated_version = Version} = State) ->
+gen_info(Event, StateName, #state{connection_env = #connection_env{negotiated_version = Version}} = State) ->
try handle_info(Event, StateName, State) of
Result ->
Result
@@ -762,6 +1201,29 @@ gen_info(Event, StateName, #state{negotiated_version = Version} = State) ->
malformed_handshake_data),
Version, StateName, State)
end.
+
+gen_info_1_3(Event, connected = StateName, #state{connection_env = #connection_env{negotiated_version = Version}} = State) ->
+ try handle_info(Event, StateName, State) of
+ Result ->
+ Result
+ catch
+ _:_ ->
+ ssl_connection:handle_own_alert(?ALERT_REC(?FATAL, ?INTERNAL_ERROR,
+ malformed_data),
+ Version, StateName, State)
+ end;
+
+gen_info_1_3(Event, StateName, #state{connection_env = #connection_env{negotiated_version = Version}} = State) ->
+ try handle_info(Event, StateName, State) of
+ Result ->
+ Result
+ catch
+ _:_ ->
+ ssl_connection:handle_own_alert(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE,
+ malformed_handshake_data),
+ Version, StateName, State)
+ end.
+
unprocessed_events(Events) ->
%% The first handshake event will be processed immediately
@@ -772,7 +1234,8 @@ unprocessed_events(Events) ->
erlang:length(Events)-1.
-assert_buffer_sanity(<<?BYTE(_Type), ?UINT24(Length), Rest/binary>>, #ssl_options{max_handshake_size = Max}) when
+assert_buffer_sanity(<<?BYTE(_Type), ?UINT24(Length), Rest/binary>>,
+ #ssl_options{max_handshake_size = Max}) when
Length =< Max ->
case size(Rest) of
N when N < Length ->
@@ -792,3 +1255,47 @@ assert_buffer_sanity(Bin, _) ->
throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE,
malformed_handshake_data))
end.
+
+ensure_sender_terminate(downgrade, _) ->
+ ok; %% Do not terminate sender during downgrade phase
+ensure_sender_terminate(_, #state{protocol_specific = #{sender := Sender}}) ->
+ %% Make sure TLS sender dies when connection process is terminated normally
+ %% This is needed if the tls_sender is blocked in prim_inet:send
+ Kill = fun() ->
+ receive
+ after 5000 ->
+ catch (exit(Sender, kill))
+ end
+ end,
+ spawn(Kill).
+
+maybe_generate_client_shares(#ssl_options{
+ versions = [Version|_],
+ supported_groups =
+ #supported_groups{
+ supported_groups = Groups}})
+ when Version =:= {3,4} ->
+ ssl_cipher:generate_client_shares(Groups);
+maybe_generate_client_shares(_) ->
+ undefined.
+
+choose_tls_version(#ssl_options{versions = Versions},
+ #client_hello{
+ extensions = #{client_hello_versions :=
+ #client_hello_versions{versions = ClientVersions}
+ }
+ }) ->
+ case ssl_handshake:select_supported_version(ClientVersions, Versions) of
+ {3,4} ->
+ 'tls_v1.3';
+ _Else ->
+ 'tls_v1.2'
+ end;
+choose_tls_version(_, _) ->
+ 'tls_v1.2'.
+
+
+effective_version(undefined, #ssl_options{versions = [Version|_]}) ->
+ Version;
+effective_version(Version, _) ->
+ Version.
diff --git a/lib/ssl/src/tls_connection.hrl b/lib/ssl/src/tls_connection.hrl
index 0af2258932..9063b1b736 100644
--- a/lib/ssl/src/tls_connection.hrl
+++ b/lib/ssl/src/tls_connection.hrl
@@ -30,7 +30,6 @@
-include("tls_record.hrl").
-record(protocol_buffers, {
- tls_packets = [], %% :: [#ssl_tls{}], % Not yet handled decode SSL/TLS packets.
tls_record_buffer = <<>>, %% :: binary(), % Buffer of incomplete records
tls_handshake_buffer = <<>>, %% :: binary(), % Buffer of incomplete handshakes
tls_cipher_texts = [] %%:: [binary()]
diff --git a/lib/ssl/src/tls_connection_1_3.erl b/lib/ssl/src/tls_connection_1_3.erl
new file mode 100644
index 0000000000..701a5860c2
--- /dev/null
+++ b/lib/ssl/src/tls_connection_1_3.erl
@@ -0,0 +1,192 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: TODO
+%%----------------------------------------------------------------------
+
+%% RFC 8446
+%% A.1. Client
+%%
+%% START <----+
+%% Send ClientHello | | Recv HelloRetryRequest
+%% [K_send = early data] | |
+%% v |
+%% / WAIT_SH ----+
+%% | | Recv ServerHello
+%% | | K_recv = handshake
+%% Can | V
+%% send | WAIT_EE
+%% early | | Recv EncryptedExtensions
+%% data | +--------+--------+
+%% | Using | | Using certificate
+%% | PSK | v
+%% | | WAIT_CERT_CR
+%% | | Recv | | Recv CertificateRequest
+%% | | Certificate | v
+%% | | | WAIT_CERT
+%% | | | | Recv Certificate
+%% | | v v
+%% | | WAIT_CV
+%% | | | Recv CertificateVerify
+%% | +> WAIT_FINISHED <+
+%% | | Recv Finished
+%% \ | [Send EndOfEarlyData]
+%% | K_send = handshake
+%% | [Send Certificate [+ CertificateVerify]]
+%% Can send | Send Finished
+%% app data --> | K_send = K_recv = application
+%% after here v
+%% CONNECTED
+%%
+%% A.2. Server
+%%
+%% START <-----+
+%% Recv ClientHello | | Send HelloRetryRequest
+%% v |
+%% RECVD_CH ----+
+%% | Select parameters
+%% v
+%% NEGOTIATED
+%% | Send ServerHello
+%% | K_send = handshake
+%% | Send EncryptedExtensions
+%% | [Send CertificateRequest]
+%% Can send | [Send Certificate + CertificateVerify]
+%% app data | Send Finished
+%% after --> | K_send = application
+%% here +--------+--------+
+%% No 0-RTT | | 0-RTT
+%% | |
+%% K_recv = handshake | | K_recv = early data
+%% [Skip decrypt errors] | +------> WAIT_EOED -+
+%% | | Recv | | Recv EndOfEarlyData
+%% | | early data | | K_recv = handshake
+%% | +------------+ |
+%% | |
+%% +> WAIT_FLIGHT2 <--------+
+%% |
+%% +--------+--------+
+%% No auth | | Client auth
+%% | |
+%% | v
+%% | WAIT_CERT
+%% | Recv | | Recv Certificate
+%% | empty | v
+%% | Certificate | WAIT_CV
+%% | | | Recv
+%% | v | CertificateVerify
+%% +-> WAIT_FINISHED <---+
+%% | Recv Finished
+%% | K_recv = application
+%% v
+%% CONNECTED
+
+-module(tls_connection_1_3).
+
+-include("ssl_alert.hrl").
+-include("ssl_connection.hrl").
+-include("tls_handshake.hrl").
+-include("tls_handshake_1_3.hrl").
+
+%% gen_statem helper functions
+-export([start/4,
+ negotiated/4,
+ wait_cert/4,
+ wait_cv/4,
+ wait_finished/4
+ ]).
+
+
+start(internal, #change_cipher_spec{}, State0, _Module) ->
+ {Record, State} = tls_connection:next_record(State0),
+ tls_connection:next_event(?FUNCTION_NAME, Record, State);
+start(internal, #client_hello{} = Hello, State0, _Module) ->
+ case tls_handshake_1_3:do_start(Hello, State0) of
+ #alert{} = Alert ->
+ ssl_connection:handle_own_alert(Alert, {3,4}, start, State0);
+ {State, start} ->
+ {next_state, start, State, []};
+ {State, negotiated} ->
+ {next_state, negotiated, State, [{next_event, internal, start_handshake}]}
+ end;
+start(Type, Msg, State, Connection) ->
+ ssl_connection:handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection).
+
+
+negotiated(internal, #change_cipher_spec{}, State0, _Module) ->
+ {Record, State} = tls_connection:next_record(State0),
+ tls_connection:next_event(?FUNCTION_NAME, Record, State);
+negotiated(internal, Message, State0, _Module) ->
+ case tls_handshake_1_3:do_negotiated(Message, State0) of
+ #alert{} = Alert ->
+ ssl_connection:handle_own_alert(Alert, {3,4}, negotiated, State0);
+ {State, NextState} ->
+ {next_state, NextState, State, []}
+ end.
+
+
+wait_cert(internal, #change_cipher_spec{}, State0, _Module) ->
+ {Record, State} = tls_connection:next_record(State0),
+ tls_connection:next_event(?FUNCTION_NAME, Record, State);
+wait_cert(internal,
+ #certificate_1_3{} = Certificate, State0, _Module) ->
+ case tls_handshake_1_3:do_wait_cert(Certificate, State0) of
+ {#alert{} = Alert, State} ->
+ ssl_connection:handle_own_alert(Alert, {3,4}, wait_cert, State);
+ {State1, NextState} ->
+ {Record, State} = tls_connection:next_record(State1),
+ tls_connection:next_event(NextState, Record, State)
+ end;
+wait_cert(Type, Msg, State, Connection) ->
+ ssl_connection:handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection).
+
+
+wait_cv(internal, #change_cipher_spec{}, State0, _Module) ->
+ {Record, State} = tls_connection:next_record(State0),
+ tls_connection:next_event(?FUNCTION_NAME, Record, State);
+wait_cv(internal,
+ #certificate_verify_1_3{} = CertificateVerify, State0, _Module) ->
+ case tls_handshake_1_3:do_wait_cv(CertificateVerify, State0) of
+ {#alert{} = Alert, State} ->
+ ssl_connection:handle_own_alert(Alert, {3,4}, wait_cv, State);
+ {State1, NextState} ->
+ {Record, State} = tls_connection:next_record(State1),
+ tls_connection:next_event(NextState, Record, State)
+ end;
+wait_cv(Type, Msg, State, Connection) ->
+ ssl_connection:handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection).
+
+
+wait_finished(internal, #change_cipher_spec{}, State0, _Module) ->
+ {Record, State} = tls_connection:next_record(State0),
+ tls_connection:next_event(?FUNCTION_NAME, Record, State);
+wait_finished(internal,
+ #finished{} = Finished, State0, Module) ->
+ case tls_handshake_1_3:do_wait_finished(Finished, State0) of
+ #alert{} = Alert ->
+ ssl_connection:handle_own_alert(Alert, {3,4}, finished, State0);
+ State1 ->
+ {Record, State} = ssl_connection:prepare_connection(State1, Module),
+ tls_connection:next_event(connection, Record, State)
+ end;
+wait_finished(Type, Msg, State, Connection) ->
+ ssl_connection:handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection).
diff --git a/lib/ssl/src/tls_handshake.erl b/lib/ssl/src/tls_handshake.erl
index 8817418fb0..2480e05097 100644
--- a/lib/ssl/src/tls_handshake.erl
+++ b/lib/ssl/src/tls_handshake.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,20 +26,23 @@
-module(tls_handshake).
-include("tls_handshake.hrl").
+-include("tls_handshake_1_3.hrl").
-include("tls_record.hrl").
-include("ssl_alert.hrl").
-include("ssl_internal.hrl").
-include("ssl_cipher.hrl").
+-include("ssl_api.hrl").
-include_lib("public_key/include/public_key.hrl").
+-include_lib("kernel/include/logger.hrl").
%% Handshake handling
--export([client_hello/8, hello/4]).
+-export([client_hello/9, hello/4]).
%% Handshake encoding
-export([encode_handshake/2]).
%% Handshake decodeing
--export([get_tls_handshake/4, decode_handshake/4]).
+-export([get_tls_handshake/4, decode_handshake/3]).
-type tls_handshake() :: #client_hello{} | ssl_handshake:ssl_handshake().
@@ -47,8 +50,9 @@
%% Handshake handling
%%====================================================================
%%--------------------------------------------------------------------
--spec client_hello(host(), inet:port_number(), ssl_record:connection_states(),
- #ssl_options{}, integer(), atom(), boolean(), der_cert()) ->
+-spec client_hello(ssl:host(), inet:port_number(), ssl_record:connection_states(),
+ #ssl_options{}, integer(), atom(), boolean(), der_cert(),
+ #key_share_client_hello{} | undefined) ->
#client_hello{}.
%%
%% Description: Creates a client hello message.
@@ -58,19 +62,32 @@ client_hello(Host, Port, ConnectionStates,
ciphers = UserSuites,
fallback = Fallback
} = SslOpts,
- Cache, CacheCb, Renegotiation, OwnCert) ->
+ Cache, CacheCb, Renegotiation, OwnCert, KeyShare) ->
Version = tls_record:highest_protocol_version(Versions),
+
+ %% In TLS 1.3, the client indicates its version preferences in the
+ %% "supported_versions" extension (Section 4.2.1) and the
+ %% legacy_version field MUST be set to 0x0303, which is the version
+ %% number for TLS 1.2.
+ LegacyVersion =
+ case tls_record:is_higher(Version, {3,2}) of
+ true ->
+ {3,3};
+ false ->
+ Version
+ end,
#{security_parameters := SecParams} =
ssl_record:pending_connection_state(ConnectionStates, read),
AvailableCipherSuites = ssl_handshake:available_suites(UserSuites, Version),
Extensions = ssl_handshake:client_hello_extensions(Version,
AvailableCipherSuites,
SslOpts, ConnectionStates,
- Renegotiation),
+ Renegotiation,
+ KeyShare),
CipherSuites = ssl_handshake:cipher_suites(AvailableCipherSuites, Renegotiation, Fallback),
Id = ssl_session:client_id({Host, Port, SslOpts}, Cache, CacheCb, OwnCert),
#client_hello{session_id = Id,
- client_version = Version,
+ client_version = LegacyVersion,
cipher_suites = CipherSuites,
compression_methods = ssl_record:compressions(),
random = SecParams#security_parameters.client_random,
@@ -81,17 +98,75 @@ client_hello(Host, Port, ConnectionStates,
-spec hello(#server_hello{} | #client_hello{}, #ssl_options{},
ssl_record:connection_states() | {inet:port_number(), #session{}, db_handle(),
atom(), ssl_record:connection_states(),
- binary() | undefined, ssl_cipher:key_algo()},
+ binary() | undefined, ssl:kex_algo()},
boolean()) ->
- {tls_record:tls_version(), session_id(),
+ {tls_record:tls_version(), ssl:session_id(),
ssl_record:connection_states(), alpn | npn, binary() | undefined}|
{tls_record:tls_version(), {resumed | new, #session{}},
ssl_record:connection_states(), binary() | undefined,
- #hello_extensions{}, {ssl_cipher:hash(), ssl_cipher:sign_algo()} |
+ HelloExt::map(), {ssl:hash(), ssl:sign_algo()} |
undefined} | #alert{}.
%%
%% Description: Handles a received hello message
%%--------------------------------------------------------------------
+
+
+%% TLS 1.3 - Section 4.1.3
+%% TLS 1.3 clients receiving a ServerHello indicating TLS 1.2 or below
+%% MUST check that the last eight bytes are not equal to either of these
+%% values.
+hello(#server_hello{server_version = {Major, Minor},
+ random = <<_:24/binary,Down:8/binary>>},
+ #ssl_options{versions = [{M,N}|_]}, _, _)
+ when (M > 3 orelse M =:= 3 andalso N >= 4) andalso %% TLS 1.3 client
+ (Major =:= 3 andalso Minor =:= 3 andalso %% Negotiating TLS 1.2
+ Down =:= ?RANDOM_OVERRIDE_TLS12) orelse
+
+ (M > 3 orelse M =:= 3 andalso N >= 4) andalso %% TLS 1.3 client
+ (Major =:= 3 andalso Minor < 3 andalso %% Negotiating TLS 1.1 or prior
+ Down =:= ?RANDOM_OVERRIDE_TLS11) ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
+
+%% TLS 1.2 clients SHOULD also check that the last eight bytes are not
+%% equal to the second value if the ServerHello indicates TLS 1.1 or below.
+hello(#server_hello{server_version = {Major, Minor},
+ random = <<_:24/binary,Down:8/binary>>},
+ #ssl_options{versions = [{M,N}|_]}, _, _)
+ when (M =:= 3 andalso N =:= 3) andalso %% TLS 1.2 client
+ (Major =:= 3 andalso Minor < 3 andalso %% Negotiating TLS 1.1 or prior
+ Down =:= ?RANDOM_OVERRIDE_TLS11) ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
+
+
+%% TLS 1.3 - 4.2.1. Supported Versions
+%% If the "supported_versions" extension in the ServerHello contains a
+%% version not offered by the client or contains a version prior to TLS
+%% 1.3, the client MUST abort the handshake with an "illegal_parameter"
+%% alert.
+%%--------------------------------------------------------------------
+%% TLS 1.2 Client
+%%
+%% - If "supported_version" is present (ServerHello):
+%% - Abort handshake with an "illegal_parameter" alert
+hello(#server_hello{server_version = Version,
+ extensions = #{server_hello_selected_version :=
+ #server_hello_selected_version{selected_version = Version}}
+ },
+ #ssl_options{versions = SupportedVersions},
+ _ConnectionStates0, _Renegotiation) ->
+ case tls_record:is_higher({3,4}, Version) of
+ true ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
+ false ->
+ case tls_record:is_acceptable_version(Version, SupportedVersions) of
+ true ->
+ %% Implement TLS 1.3 statem ???
+ ?ALERT_REC(?FATAL, ?PROTOCOL_VERSION);
+ false ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)
+ end
+ end;
+
hello(#server_hello{server_version = Version, random = Random,
cipher_suite = CipherSuite,
compression_method = Compression,
@@ -106,6 +181,36 @@ hello(#server_hello{server_version = Version, random = Random,
false ->
?ALERT_REC(?FATAL, ?PROTOCOL_VERSION)
end;
+
+
+%% TLS 1.2 Server
+%% - If "supported_versions" is present (ClientHello):
+%% - Select version from "supported_versions" (ignore ClientHello.legacy_version)
+%% - If server only supports versions greater than "supported_versions":
+%% - Abort handshake with a "protocol_version" alert (*)
+%% - If "supported_versions" is absent (ClientHello):
+%% - Negotiate the minimum of ClientHello.legacy_version and TLS 1.2 (**)
+%% - If server only supports versions greater than ClientHello.legacy_version:
+%% - Abort handshake with a "protocol_version" alert
+%%
+%% (*) Sends alert even if there is a gap in supported versions
+%% e.g. Server 1.0,1.2 Client 1.1,1.3
+%% (**) Current implementation can negotiate a version not supported by the client
+%% e.g. Server 1.0,1.2 Client 1.1 -> ServerHello 1.0
+hello(#client_hello{client_version = _ClientVersion,
+ cipher_suites = CipherSuites,
+ extensions = #{client_hello_versions :=
+ #client_hello_versions{versions = ClientVersions}
+ }} = Hello,
+ #ssl_options{versions = Versions} = SslOpts,
+ Info, Renegotiation) ->
+ try
+ Version = ssl_handshake:select_supported_version(ClientVersions, Versions),
+ do_hello(Version, Versions, CipherSuites, Hello, SslOpts, Info, Renegotiation)
+ catch
+ _:_ ->
+ ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, malformed_handshake_data)
+ end;
hello(#client_hello{client_version = ClientVersion,
cipher_suites = CipherSuites} = Hello,
@@ -113,19 +218,11 @@ hello(#client_hello{client_version = ClientVersion,
Info, Renegotiation) ->
try
Version = ssl_handshake:select_version(tls_record, ClientVersion, Versions),
- case ssl_cipher:is_fallback(CipherSuites) of
- true ->
- Highest = tls_record:highest_protocol_version(Versions),
- case tls_record:is_higher(Highest, Version) of
- true ->
- ?ALERT_REC(?FATAL, ?INAPPROPRIATE_FALLBACK);
- false ->
- handle_client_hello(Version, Hello, SslOpts, Info, Renegotiation)
- end;
- false ->
- handle_client_hello(Version, Hello, SslOpts, Info, Renegotiation)
- end
+ do_hello(Version, Versions, CipherSuites, Hello, SslOpts, Info, Renegotiation)
catch
+ error:{case_clause,{asn1, Asn1Reason}} ->
+ %% ASN-1 decode of certificate somehow failed
+ ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {failed_to_decode_own_certificate, Asn1Reason});
_:_ ->
?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, malformed_handshake_data)
end.
@@ -136,7 +233,8 @@ hello(#client_hello{client_version = ClientVersion,
%%--------------------------------------------------------------------
%%--------------------------------------------------------------------
--spec encode_handshake(tls_handshake(), tls_record:tls_version()) -> iolist().
+-spec encode_handshake(tls_handshake() | tls_handshake_1_3:tls_handshake_1_3(),
+ tls_record:tls_version()) -> iolist().
%%
%% Description: Encode a handshake packet
%%--------------------------------------------------------------------
@@ -153,7 +251,7 @@ encode_handshake(Package, Version) ->
%%--------------------------------------------------------------------
-spec get_tls_handshake(tls_record:tls_version(), binary(), binary() | iolist(),
#ssl_options{}) ->
- {[tls_handshake()], binary()}.
+ {[{tls_handshake(), binary()}], binary()}.
%%
%% Description: Given buffered and new data from ssl_record, collects
%% and returns it as a list of handshake messages, also returns leftover
@@ -172,10 +270,7 @@ handle_client_hello(Version,
cipher_suites = CipherSuites,
compression_methods = Compressions,
random = Random,
- extensions =
- #hello_extensions{elliptic_curves = Curves,
- signature_algs = ClientHashSigns}
- = HelloExt},
+ extensions = HelloExt},
#ssl_options{versions = Versions,
signature_algs = SupportedHashSigns,
eccs = SupportedECCs,
@@ -184,6 +279,9 @@ handle_client_hello(Version,
Renegotiation) ->
case tls_record:is_acceptable_version(Version, Versions) of
true ->
+ Curves = maps:get(elliptic_curves, HelloExt, undefined),
+ ClientHashSigns = maps:get(signature_algs, HelloExt, undefined),
+ ClientSignatureSchemes = maps:get(signature_algs_cert, HelloExt, undefined),
AvailableHashSigns = ssl_handshake:available_signature_algs(
ClientHashSigns, SupportedHashSigns, Cert, Version),
ECCCurve = ssl_handshake:select_curve(Curves, SupportedECCs, ECCOrder),
@@ -196,9 +294,11 @@ handle_client_hello(Version,
no_suite ->
?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_ciphers);
_ ->
- #{key_exchange := KeyExAlg} = ssl_cipher:suite_definition(CipherSuite),
- case ssl_handshake:select_hashsign(ClientHashSigns, Cert, KeyExAlg,
- SupportedHashSigns, Version) of
+ #{key_exchange := KeyExAlg} = ssl_cipher_format:suite_bin_to_map(CipherSuite),
+ case ssl_handshake:select_hashsign({ClientHashSigns, ClientSignatureSchemes},
+ Cert, KeyExAlg,
+ SupportedHashSigns,
+ Version) of
#alert{} = Alert ->
Alert;
HashSign ->
@@ -220,8 +320,6 @@ handle_client_hello_extensions(Version, Type, Random, CipherSuites,
HelloExt, Version, SslOpts,
Session0, ConnectionStates0,
Renegotiation) of
- #alert{} = Alert ->
- Alert;
{Session, ConnectionStates, Protocol, ServerHelloExt} ->
{Version, {Type, Session}, ConnectionStates, Protocol,
ServerHelloExt, HashSign}
@@ -232,17 +330,35 @@ handle_client_hello_extensions(Version, Type, Random, CipherSuites,
handle_server_hello_extensions(Version, SessionId, Random, CipherSuite,
Compression, HelloExt, SslOpt, ConnectionStates0, Renegotiation) ->
- case ssl_handshake:handle_server_hello_extensions(tls_record, Random, CipherSuite,
+ try ssl_handshake:handle_server_hello_extensions(tls_record, Random, CipherSuite,
Compression, HelloExt, Version,
SslOpt, ConnectionStates0,
- Renegotiation) of
- #alert{} = Alert ->
- Alert;
+ Renegotiation) of
{ConnectionStates, ProtoExt, Protocol} ->
{Version, SessionId, ConnectionStates, ProtoExt, Protocol}
+ catch throw:Alert ->
+ Alert
+ end.
+
+
+do_hello(undefined, _Versions, _CipherSuites, _Hello, _SslOpts, _Info, _Renegotiation) ->
+ ?ALERT_REC(?FATAL, ?PROTOCOL_VERSION);
+do_hello(Version, Versions, CipherSuites, Hello, SslOpts, Info, Renegotiation) ->
+ case ssl_cipher:is_fallback(CipherSuites) of
+ true ->
+ Highest = tls_record:highest_protocol_version(Versions),
+ case tls_record:is_higher(Highest, Version) of
+ true ->
+ ?ALERT_REC(?FATAL, ?INAPPROPRIATE_FALLBACK);
+ false ->
+ handle_client_hello(Version, Hello, SslOpts, Info, Renegotiation)
+ end;
+ false ->
+ handle_client_hello(Version, Hello, SslOpts, Info, Renegotiation)
end.
+
%%--------------------------------------------------------------------
-enc_handshake(#hello_request{}, _Version) ->
+enc_handshake(#hello_request{}, {3, N}) when N < 4 ->
{?HELLO_REQUEST, <<>>};
enc_handshake(#client_hello{client_version = {Major, Minor},
random = Random,
@@ -261,17 +377,19 @@ enc_handshake(#client_hello{client_version = {Major, Minor},
?BYTE(SIDLength), SessionID/binary,
?UINT16(CsLength), BinCipherSuites/binary,
?BYTE(CmLength), BinCompMethods/binary, ExtensionsBin/binary>>};
-
+enc_handshake(HandshakeMsg, {3, 4}) ->
+ tls_handshake_1_3:encode_handshake(HandshakeMsg);
enc_handshake(HandshakeMsg, Version) ->
ssl_handshake:encode_handshake(HandshakeMsg, Version).
%%--------------------------------------------------------------------
get_tls_handshake_aux(Version, <<?BYTE(Type), ?UINT24(Length),
Body:Length/binary,Rest/binary>>,
- #ssl_options{v2_hello_compatible = V2Hello} = Opts, Acc) ->
+ Opts, Acc) ->
Raw = <<?BYTE(Type), ?UINT24(Length), Body/binary>>,
- try decode_handshake(Version, Type, Body, V2Hello) of
+ try decode_handshake(Version, Type, Body) of
Handshake ->
+ ssl_logger:debug(Opts#ssl_options.log_level, inbound, 'handshake', Handshake),
get_tls_handshake_aux(Version, Rest, Opts, [{Handshake,Raw} | Acc])
catch
_:_ ->
@@ -280,67 +398,26 @@ get_tls_handshake_aux(Version, <<?BYTE(Type), ?UINT24(Length),
get_tls_handshake_aux(_Version, Data, _, Acc) ->
{lists:reverse(Acc), Data}.
-decode_handshake(_, ?HELLO_REQUEST, <<>>, _) ->
+decode_handshake({3, N}, ?HELLO_REQUEST, <<>>) when N < 4 ->
#hello_request{};
-
-decode_handshake(_Version, ?CLIENT_HELLO, Bin, true) ->
- try decode_hello(Bin) of
- Hello ->
- Hello
- catch
- _:_ ->
- decode_v2_hello(Bin)
- end;
-decode_handshake(_Version, ?CLIENT_HELLO, Bin, false) ->
- decode_hello(Bin);
-
-decode_handshake(_Version, ?CLIENT_HELLO,
+decode_handshake(Version, ?CLIENT_HELLO,
<<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SID_length), Session_ID:SID_length/binary,
?UINT16(Cs_length), CipherSuites:Cs_length/binary,
?BYTE(Cm_length), Comp_methods:Cm_length/binary,
- Extensions/binary>>, _) ->
-
- DecodedExtensions = ssl_handshake:decode_hello_extensions({client, Extensions}),
-
+ Extensions/binary>>) ->
+ Exts = ssl_handshake:decode_vector(Extensions),
+ DecodedExtensions = ssl_handshake:decode_hello_extensions(Exts, Version, {Major, Minor},
+ client_hello),
#client_hello{
client_version = {Major,Minor},
random = Random,
session_id = Session_ID,
cipher_suites = ssl_handshake:decode_suites('2_bytes', CipherSuites),
- compression_methods = Comp_methods,
+ compression_methods = erlang:binary_to_list(Comp_methods),
extensions = DecodedExtensions
};
-decode_handshake(Version, Tag, Msg, _) ->
+decode_handshake({3, 4}, Tag, Msg) ->
+ tls_handshake_1_3:decode_handshake(Tag, Msg);
+decode_handshake(Version, Tag, Msg) ->
ssl_handshake:decode_handshake(Version, Tag, Msg).
-
-
-decode_hello(<<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
- ?BYTE(SID_length), Session_ID:SID_length/binary,
- ?UINT16(Cs_length), CipherSuites:Cs_length/binary,
- ?BYTE(Cm_length), Comp_methods:Cm_length/binary,
- Extensions/binary>>) ->
- DecodedExtensions = ssl_handshake:decode_hello_extensions({client, Extensions}),
-
- #client_hello{
- client_version = {Major,Minor},
- random = Random,
- session_id = Session_ID,
- cipher_suites = ssl_handshake:decode_suites('2_bytes', CipherSuites),
- compression_methods = Comp_methods,
- extensions = DecodedExtensions
- }.
-%% The server must be able to receive such messages, from clients that
-%% are willing to use ssl v3 or higher, but have ssl v2 compatibility.
-decode_v2_hello(<<?BYTE(Major), ?BYTE(Minor),
- ?UINT16(CSLength), ?UINT16(0),
- ?UINT16(CDLength),
- CipherSuites:CSLength/binary,
- ChallengeData:CDLength/binary>>) ->
- #client_hello{client_version = {Major, Minor},
- random = ssl_v2:client_random(ChallengeData, CDLength),
- session_id = 0,
- cipher_suites = ssl_handshake:decode_suites('3_bytes', CipherSuites),
- compression_methods = [?NULL],
- extensions = #hello_extensions{}
- }.
diff --git a/lib/ssl/src/tls_handshake.hrl b/lib/ssl/src/tls_handshake.hrl
index f6644f64af..fc67bb61fd 100644
--- a/lib/ssl/src/tls_handshake.hrl
+++ b/lib/ssl/src/tls_handshake.hrl
@@ -32,6 +32,7 @@
client_version,
random,
session_id, % opaque SessionID<0..32>
+ cookie, % opaque<2..2^16-1>
cipher_suites, % cipher_suites<2..2^16-1>
compression_methods, % compression_methods<1..2^8-1>,
%% Extensions
diff --git a/lib/ssl/src/tls_handshake_1_3.erl b/lib/ssl/src/tls_handshake_1_3.erl
new file mode 100644
index 0000000000..8a4ad922e1
--- /dev/null
+++ b/lib/ssl/src/tls_handshake_1_3.erl
@@ -0,0 +1,1343 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%----------------------------------------------------------------------
+%% Purpose: Help funtions for handling the TLS 1.3 (specific parts of)
+%%% TLS handshake protocol
+%%----------------------------------------------------------------------
+
+-module(tls_handshake_1_3).
+
+-include("tls_handshake_1_3.hrl").
+-include("ssl_alert.hrl").
+-include("ssl_cipher.hrl").
+-include("ssl_connection.hrl").
+-include("ssl_internal.hrl").
+-include("ssl_record.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+%% Encode
+-export([encode_handshake/1, decode_handshake/2]).
+
+%% Create handshake messages
+-export([certificate/5,
+ certificate_verify/4,
+ encrypted_extensions/0,
+ server_hello/4]).
+
+-export([do_start/2,
+ do_negotiated/2,
+ do_wait_cert/2,
+ do_wait_cv/2,
+ do_wait_finished/2]).
+
+%%====================================================================
+%% Create handshake messages
+%%====================================================================
+
+server_hello(MsgType, SessionId, KeyShare, ConnectionStates) ->
+ #{security_parameters := SecParams} =
+ ssl_record:pending_connection_state(ConnectionStates, read),
+ Extensions = server_hello_extensions(MsgType, KeyShare),
+ #server_hello{server_version = {3,3}, %% legacy_version
+ cipher_suite = SecParams#security_parameters.cipher_suite,
+ compression_method = 0, %% legacy attribute
+ random = server_hello_random(MsgType, SecParams),
+ session_id = SessionId,
+ extensions = Extensions
+ }.
+
+server_hello_extensions(MsgType, KeyShare) ->
+ SupportedVersions = #server_hello_selected_version{selected_version = {3,4}},
+ Extensions = #{server_hello_selected_version => SupportedVersions},
+ ssl_handshake:add_server_share(MsgType, Extensions, KeyShare).
+
+server_hello_random(server_hello, #security_parameters{server_random = Random}) ->
+ Random;
+%% For reasons of backward compatibility with middleboxes (see
+%% Appendix D.4), the HelloRetryRequest message uses the same structure
+%% as the ServerHello, but with Random set to the special value of the
+%% SHA-256 of "HelloRetryRequest":
+%%
+%% CF 21 AD 74 E5 9A 61 11 BE 1D 8C 02 1E 65 B8 91
+%% C2 A2 11 16 7A BB 8C 5E 07 9E 09 E2 C8 A8 33 9C
+server_hello_random(hello_retry_request, _) ->
+ crypto:hash(sha256, "HelloRetryRequest").
+
+
+%% TODO: implement support for encrypted_extensions
+encrypted_extensions() ->
+ #encrypted_extensions{
+ extensions = #{}
+ }.
+
+
+certificate_request(SignAlgs0, SignAlgsCert0) ->
+ %% Input arguments contain TLS 1.2 algorithms due to backward compatibility
+ %% reasons. These {Hash, Algo} tuples must be filtered before creating the
+ %% the extensions.
+ SignAlgs = filter_tls13_algs(SignAlgs0),
+ SignAlgsCert = filter_tls13_algs(SignAlgsCert0),
+ Extensions0 = add_signature_algorithms(#{}, SignAlgs),
+ Extensions = add_signature_algorithms_cert(Extensions0, SignAlgsCert),
+ #certificate_request_1_3{
+ certificate_request_context = <<>>,
+ extensions = Extensions}.
+
+
+add_signature_algorithms(Extensions, SignAlgs) ->
+ Extensions#{signature_algorithms =>
+ #signature_algorithms{signature_scheme_list = SignAlgs}}.
+
+
+add_signature_algorithms_cert(Extensions, undefined) ->
+ Extensions;
+add_signature_algorithms_cert(Extensions, SignAlgsCert) ->
+ Extensions#{signature_algorithms_cert =>
+ #signature_algorithms{signature_scheme_list = SignAlgsCert}}.
+
+
+filter_tls13_algs(undefined) -> undefined;
+filter_tls13_algs(Algo) ->
+ lists:filter(fun is_atom/1, Algo).
+
+
+%% TODO: use maybe monad for error handling!
+%% enum {
+%% X509(0),
+%% RawPublicKey(2),
+%% (255)
+%% } CertificateType;
+%%
+%% struct {
+%% select (certificate_type) {
+%% case RawPublicKey:
+%% /* From RFC 7250 ASN.1_subjectPublicKeyInfo */
+%% opaque ASN1_subjectPublicKeyInfo<1..2^24-1>;
+%%
+%% case X509:
+%% opaque cert_data<1..2^24-1>;
+%% };
+%% Extension extensions<0..2^16-1>;
+%% } CertificateEntry;
+%%
+%% struct {
+%% opaque certificate_request_context<0..2^8-1>;
+%% CertificateEntry certificate_list<0..2^24-1>;
+%% } Certificate;
+certificate(OwnCert, CertDbHandle, CertDbRef, _CRContext, server) ->
+ case ssl_certificate:certificate_chain(OwnCert, CertDbHandle, CertDbRef) of
+ {ok, _, Chain} ->
+ CertList = chain_to_cert_list(Chain),
+ %% If this message is in response to a CertificateRequest, the value of
+ %% certificate_request_context in that message. Otherwise (in the case
+ %%of server authentication), this field SHALL be zero length.
+ #certificate_1_3{
+ certificate_request_context = <<>>,
+ certificate_list = CertList};
+ {error, Error} ->
+ ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {server_has_no_suitable_certificates, Error})
+ end.
+
+
+certificate_verify(PrivateKey, SignatureScheme,
+ #state{connection_states = ConnectionStates,
+ handshake_env =
+ #handshake_env{
+ tls_handshake_history = {Messages, _}}}, server) ->
+ #{security_parameters := SecParamsR} =
+ ssl_record:pending_connection_state(ConnectionStates, write),
+ #security_parameters{prf_algorithm = HKDFAlgo} = SecParamsR,
+
+ {HashAlgo, _, _} =
+ ssl_cipher:scheme_to_components(SignatureScheme),
+
+ Context = lists:reverse(Messages),
+
+ %% Transcript-Hash uses the HKDF hash function defined by the cipher suite.
+ THash = tls_v1:transcript_hash(Context, HKDFAlgo),
+
+ %% Digital signatures use the hash function defined by the selected signature
+ %% scheme.
+ case sign(THash, <<"TLS 1.3, server CertificateVerify">>,
+ HashAlgo, PrivateKey) of
+ {ok, Signature} ->
+ {ok, #certificate_verify_1_3{
+ algorithm = SignatureScheme,
+ signature = Signature
+ }};
+ {error, badarg} ->
+ {error, badarg}
+
+ end.
+
+
+finished(#state{connection_states = ConnectionStates,
+ handshake_env =
+ #handshake_env{
+ tls_handshake_history = {Messages, _}}}) ->
+ #{security_parameters := SecParamsR,
+ cipher_state := #cipher_state{finished_key = FinishedKey}} =
+ ssl_record:current_connection_state(ConnectionStates, write),
+ #security_parameters{prf_algorithm = HKDFAlgo} = SecParamsR,
+
+ VerifyData = tls_v1:finished_verify_data(FinishedKey, HKDFAlgo, Messages),
+
+ #finished{
+ verify_data = VerifyData
+ }.
+
+
+%%====================================================================
+%% Encode handshake
+%%====================================================================
+
+encode_handshake(#certificate_request_1_3{
+ certificate_request_context = Context,
+ extensions = Exts})->
+ EncContext = encode_cert_req_context(Context),
+ BinExts = encode_extensions(Exts),
+ {?CERTIFICATE_REQUEST, <<EncContext/binary, BinExts/binary>>};
+encode_handshake(#certificate_1_3{
+ certificate_request_context = Context,
+ certificate_list = Entries}) ->
+ EncContext = encode_cert_req_context(Context),
+ EncEntries = encode_cert_entries(Entries),
+ {?CERTIFICATE, <<EncContext/binary, EncEntries/binary>>};
+encode_handshake(#certificate_verify_1_3{
+ algorithm = Algorithm,
+ signature = Signature}) ->
+ EncAlgo = encode_algorithm(Algorithm),
+ EncSign = encode_signature(Signature),
+ {?CERTIFICATE_VERIFY, <<EncAlgo/binary, EncSign/binary>>};
+encode_handshake(#encrypted_extensions{extensions = Exts})->
+ {?ENCRYPTED_EXTENSIONS, encode_extensions(Exts)};
+encode_handshake(#new_session_ticket{
+ ticket_lifetime = LifeTime,
+ ticket_age_add = Age,
+ ticket_nonce = Nonce,
+ ticket = Ticket,
+ extensions = Exts}) ->
+ TicketSize = byte_size(Ticket),
+ BinExts = encode_extensions(Exts),
+ {?NEW_SESSION_TICKET, <<?UINT32(LifeTime), ?UINT32(Age),
+ ?BYTE(Nonce), ?UINT16(TicketSize), Ticket/binary,
+ BinExts/binary>>};
+encode_handshake(#end_of_early_data{}) ->
+ {?END_OF_EARLY_DATA, <<>>};
+encode_handshake(#key_update{request_update = Update}) ->
+ {?KEY_UPDATE, <<?BYTE(Update)>>};
+encode_handshake(HandshakeMsg) ->
+ ssl_handshake:encode_handshake(HandshakeMsg, {3,4}).
+
+
+%%====================================================================
+%% Decode handshake
+%%====================================================================
+
+decode_handshake(?CERTIFICATE_REQUEST, <<?BYTE(0), ?UINT16(Size), EncExts:Size/binary>>) ->
+ Exts = decode_extensions(EncExts, certificate_request),
+ #certificate_request_1_3{
+ certificate_request_context = <<>>,
+ extensions = Exts};
+decode_handshake(?CERTIFICATE_REQUEST, <<?BYTE(CSize), Context:CSize/binary,
+ ?UINT16(Size), EncExts:Size/binary>>) ->
+ Exts = decode_extensions(EncExts, certificate_request),
+ #certificate_request_1_3{
+ certificate_request_context = Context,
+ extensions = Exts};
+decode_handshake(?CERTIFICATE, <<?BYTE(0), ?UINT24(Size), Certs:Size/binary>>) ->
+ CertList = decode_cert_entries(Certs),
+ #certificate_1_3{
+ certificate_request_context = <<>>,
+ certificate_list = CertList
+ };
+decode_handshake(?CERTIFICATE, <<?BYTE(CSize), Context:CSize/binary,
+ ?UINT24(Size), Certs:Size/binary>>) ->
+ CertList = decode_cert_entries(Certs),
+ #certificate_1_3{
+ certificate_request_context = Context,
+ certificate_list = CertList
+ };
+decode_handshake(?CERTIFICATE_VERIFY, <<?UINT16(EncAlgo), ?UINT16(Size), Signature:Size/binary>>) ->
+ Algorithm = ssl_cipher:signature_scheme(EncAlgo),
+ #certificate_verify_1_3{
+ algorithm = Algorithm,
+ signature = Signature};
+decode_handshake(?ENCRYPTED_EXTENSIONS, <<?UINT16(Size), EncExts:Size/binary>>) ->
+ #encrypted_extensions{
+ extensions = decode_extensions(EncExts, encrypted_extensions)
+ };
+decode_handshake(?NEW_SESSION_TICKET, <<?UINT32(LifeTime), ?UINT32(Age),
+ ?BYTE(Nonce), ?UINT16(TicketSize), Ticket:TicketSize/binary,
+ BinExts/binary>>) ->
+ Exts = decode_extensions(BinExts, encrypted_extensions),
+ #new_session_ticket{ticket_lifetime = LifeTime,
+ ticket_age_add = Age,
+ ticket_nonce = Nonce,
+ ticket = Ticket,
+ extensions = Exts};
+decode_handshake(?END_OF_EARLY_DATA, _) ->
+ #end_of_early_data{};
+decode_handshake(?KEY_UPDATE, <<?BYTE(Update)>>) ->
+ #key_update{request_update = Update};
+decode_handshake(Tag, HandshakeMsg) ->
+ ssl_handshake:decode_handshake({3,4}, Tag, HandshakeMsg).
+
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
+encode_cert_req_context(<<>>) ->
+ <<?BYTE(0)>>;
+encode_cert_req_context(Bin) ->
+ Size = byte_size(Bin),
+ <<?BYTE(Size), Bin/binary>>.
+
+encode_cert_entries(Entries) ->
+ CertEntryList = encode_cert_entries(Entries, []),
+ Size = byte_size(CertEntryList),
+ <<?UINT24(Size), CertEntryList/binary>>.
+
+encode_cert_entries([], Acc) ->
+ iolist_to_binary(lists:reverse(Acc));
+encode_cert_entries([#certificate_entry{data = Data,
+ extensions = Exts} | Rest], Acc) ->
+ DSize = byte_size(Data),
+ BinExts = encode_extensions(Exts),
+ encode_cert_entries(Rest,
+ [<<?UINT24(DSize), Data/binary, BinExts/binary>> | Acc]).
+
+encode_algorithm(Algo) ->
+ Scheme = ssl_cipher:signature_scheme(Algo),
+ <<?UINT16(Scheme)>>.
+
+encode_signature(Signature) ->
+ Size = byte_size(Signature),
+ <<?UINT16(Size), Signature/binary>>.
+
+decode_cert_entries(Entries) ->
+ decode_cert_entries(Entries, []).
+
+decode_cert_entries(<<>>, Acc) ->
+ lists:reverse(Acc);
+decode_cert_entries(<<?UINT24(DSize), Data:DSize/binary, ?UINT16(Esize), BinExts:Esize/binary,
+ Rest/binary>>, Acc) ->
+ Exts = decode_extensions(BinExts, certificate_request),
+ decode_cert_entries(Rest, [#certificate_entry{data = Data,
+ extensions = Exts} | Acc]).
+
+encode_extensions(Exts)->
+ ssl_handshake:encode_extensions(extensions_list(Exts)).
+decode_extensions(Exts, MessageType) ->
+ ssl_handshake:decode_extensions(Exts, {3,4}, MessageType).
+
+extensions_list(HelloExtensions) ->
+ [Ext || {_, Ext} <- maps:to_list(HelloExtensions)].
+
+
+%% TODO: add extensions!
+chain_to_cert_list(L) ->
+ chain_to_cert_list(L, []).
+%%
+chain_to_cert_list([], Acc) ->
+ lists:reverse(Acc);
+chain_to_cert_list([H|T], Acc) ->
+ chain_to_cert_list(T, [certificate_entry(H)|Acc]).
+
+
+certificate_entry(DER) ->
+ #certificate_entry{
+ data = DER,
+ extensions = #{} %% Extensions not supported.
+ }.
+
+%% The digital signature is then computed over the concatenation of:
+%% - A string that consists of octet 32 (0x20) repeated 64 times
+%% - The context string
+%% - A single 0 byte which serves as the separator
+%% - The content to be signed
+%%
+%% For example, if the transcript hash was 32 bytes of 01 (this length
+%% would make sense for SHA-256), the content covered by the digital
+%% signature for a server CertificateVerify would be:
+%%
+%% 2020202020202020202020202020202020202020202020202020202020202020
+%% 2020202020202020202020202020202020202020202020202020202020202020
+%% 544c5320312e332c207365727665722043657274696669636174655665726966
+%% 79
+%% 00
+%% 0101010101010101010101010101010101010101010101010101010101010101
+sign(THash, Context, HashAlgo, PrivateKey) ->
+ Content = build_content(Context, THash),
+
+ %% The length of the Salt MUST be equal to the length of the output
+ %% of the digest algorithm: rsa_pss_saltlen = -1
+ try public_key:sign(Content, HashAlgo, PrivateKey,
+ [{rsa_padding, rsa_pkcs1_pss_padding},
+ {rsa_pss_saltlen, -1},
+ {rsa_mgf1_md, HashAlgo}]) of
+ Signature ->
+ {ok, Signature}
+ catch
+ error:badarg ->
+ {error, badarg}
+ end.
+
+
+verify(THash, Context, HashAlgo, Signature, PublicKey) ->
+ Content = build_content(Context, THash),
+
+ %% The length of the Salt MUST be equal to the length of the output
+ %% of the digest algorithm: rsa_pss_saltlen = -1
+ try public_key:verify(Content, HashAlgo, Signature, PublicKey,
+ [{rsa_padding, rsa_pkcs1_pss_padding},
+ {rsa_pss_saltlen, -1},
+ {rsa_mgf1_md, HashAlgo}]) of
+ Result ->
+ {ok, Result}
+ catch
+ error:badarg ->
+ {error, badarg}
+ end.
+
+
+build_content(Context, THash) ->
+ Prefix = binary:copy(<<32>>, 64),
+ <<Prefix/binary,Context/binary,?BYTE(0),THash/binary>>.
+
+
+%%====================================================================
+%% Handle handshake messages
+%%====================================================================
+
+
+do_start(#client_hello{cipher_suites = ClientCiphers,
+ session_id = SessionId,
+ extensions = Extensions} = _Hello,
+ #state{connection_states = _ConnectionStates0,
+ ssl_options = #ssl_options{ciphers = ServerCiphers,
+ signature_algs = ServerSignAlgs,
+ supported_groups = ServerGroups0},
+ session = #session{own_certificate = Cert}} = State0) ->
+
+ ClientGroups0 = maps:get(elliptic_curves, Extensions, undefined),
+ ClientGroups = get_supported_groups(ClientGroups0),
+ ServerGroups = get_supported_groups(ServerGroups0),
+
+ ClientShares0 = maps:get(key_share, Extensions, undefined),
+ ClientShares = get_key_shares(ClientShares0),
+
+ ClientSignAlgs = get_signature_scheme_list(
+ maps:get(signature_algs, Extensions, undefined)),
+ ClientSignAlgsCert = get_signature_scheme_list(
+ maps:get(signature_algs_cert, Extensions, undefined)),
+
+ %% TODO: use library function if it exists
+ %% Init the maybe "monad"
+ {Ref,Maybe} = maybe(),
+
+ try
+ %% If the server does not select a PSK, then the server independently selects a
+ %% cipher suite, an (EC)DHE group and key share for key establishment,
+ %% and a signature algorithm/certificate pair to authenticate itself to
+ %% the client.
+ Cipher = Maybe(select_cipher_suite(ClientCiphers, ServerCiphers)),
+ Groups = Maybe(select_common_groups(ServerGroups, ClientGroups)),
+ Maybe(validate_key_share(ClientGroups, ClientShares)),
+
+ {PublicKeyAlgo, SignAlgo, SignHash} = get_certificate_params(Cert),
+
+ %% Check if client supports signature algorithm of server certificate
+ Maybe(check_cert_sign_algo(SignAlgo, SignHash, ClientSignAlgs, ClientSignAlgsCert)),
+
+ %% Select signature algorithm (used in CertificateVerify message).
+ SelectedSignAlg = Maybe(select_sign_algo(PublicKeyAlgo, ClientSignAlgs, ServerSignAlgs)),
+
+ %% Select client public key. If no public key found in ClientShares or
+ %% ClientShares is empty, trigger HelloRetryRequest as we were able
+ %% to find an acceptable set of parameters but the ClientHello does not
+ %% contain sufficient information.
+ {Group, ClientPubKey} = get_client_public_key(Groups, ClientShares),
+
+ %% Generate server_share
+ KeyShare = ssl_cipher:generate_server_share(Group),
+
+ State1 = update_start_state(State0, Cipher, KeyShare, SessionId,
+ Group, SelectedSignAlg, ClientPubKey),
+
+ %% 4.1.4. Hello Retry Request
+ %%
+ %% The server will send this message in response to a ClientHello
+ %% message if it is able to find an acceptable set of parameters but the
+ %% ClientHello does not contain sufficient information to proceed with
+ %% the handshake.
+ Maybe(send_hello_retry_request(State1, ClientPubKey, KeyShare, SessionId))
+
+ %% TODO:
+ %% - session handling
+ %% - handle extensions: ALPN
+ %% (do not handle: NPN, srp, renegotiation_info, ec_point_formats)
+
+ catch
+ {Ref, {insufficient_security, no_suitable_groups}} ->
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_groups);
+ {Ref, illegal_parameter} ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
+ {Ref, no_suitable_cipher} ->
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_cipher);
+ {Ref, {insufficient_security, no_suitable_signature_algorithm}} ->
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, "No suitable signature algorithm");
+ {Ref, {insufficient_security, no_suitable_public_key}} ->
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_public_key)
+ end.
+
+
+do_negotiated(start_handshake,
+ #state{connection_states = ConnectionStates0,
+ session = #session{session_id = SessionId,
+ own_certificate = OwnCert,
+ ecc = SelectedGroup,
+ sign_alg = SignatureScheme,
+ dh_public_value = ClientKey},
+ ssl_options = #ssl_options{} = SslOpts,
+ key_share = KeyShare,
+ handshake_env = #handshake_env{tls_handshake_history = _HHistory0},
+ connection_env = #connection_env{private_key = CertPrivateKey},
+ static_env = #static_env{
+ cert_db = CertDbHandle,
+ cert_db_ref = CertDbRef,
+ socket = _Socket,
+ transport_cb = _Transport}
+ } = State0) ->
+ {Ref,Maybe} = maybe(),
+
+ try
+ %% Create server_hello
+ %% Extensions: supported_versions, key_share, (pre_shared_key)
+ ServerHello = server_hello(server_hello, SessionId, KeyShare, ConnectionStates0),
+
+ {State1, _} = tls_connection:send_handshake(ServerHello, State0),
+
+ State2 =
+ calculate_handshake_secrets(ClientKey, SelectedGroup, KeyShare, State1),
+
+ State3 = ssl_record:step_encryption_state(State2),
+
+ %% Create EncryptedExtensions
+ EncryptedExtensions = encrypted_extensions(),
+
+ %% Encode EncryptedExtensions
+ State4 = tls_connection:queue_handshake(EncryptedExtensions, State3),
+
+ %% Create and send CertificateRequest ({verify, verify_peer})
+ {State5, NextState} = maybe_send_certificate_request(State4, SslOpts),
+
+ %% Create Certificate
+ Certificate = certificate(OwnCert, CertDbHandle, CertDbRef, <<>>, server),
+
+ %% Encode Certificate
+ State6 = tls_connection:queue_handshake(Certificate, State5),
+
+ %% Create CertificateVerify
+ CertificateVerify = Maybe(certificate_verify(CertPrivateKey, SignatureScheme,
+ State6, server)),
+ %% Encode CertificateVerify
+ State7 = tls_connection:queue_handshake(CertificateVerify, State6),
+
+ %% Create Finished
+ Finished = finished(State7),
+
+ %% Encode Finished
+ State8 = tls_connection:queue_handshake(Finished, State7),
+
+ %% Send first flight
+ {State9, _} = tls_connection:send_handshake_flight(State8),
+
+ {State9, NextState}
+
+ catch
+ {Ref, badarg} ->
+ ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {digitally_sign, badarg})
+ end.
+
+
+do_wait_cert(#certificate_1_3{} = Certificate, State0) ->
+ {Ref,Maybe} = maybe(),
+ try
+ Maybe(process_client_certificate(Certificate, State0))
+ catch
+ {Ref, {certificate_required, State}} ->
+ {?ALERT_REC(?FATAL, ?CERTIFICATE_REQUIRED, certificate_required), State};
+ {Ref, {{certificate_unknown, Reason}, State}} ->
+ {?ALERT_REC(?FATAL, ?CERTIFICATE_UNKNOWN, Reason), State};
+ {Ref, {{internal_error, Reason}, State}} ->
+ {?ALERT_REC(?FATAL, ?INTERNAL_ERROR, Reason), State};
+ {Ref, {{handshake_failure, Reason}, State}} ->
+ {?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, Reason), State};
+ {#alert{} = Alert, State} ->
+ {Alert, State}
+ end.
+
+
+do_wait_cv(#certificate_verify_1_3{} = CertificateVerify, State0) ->
+ {Ref,Maybe} = maybe(),
+ try
+ Maybe(verify_signature_algorithm(State0, CertificateVerify)),
+ Maybe(verify_certificate_verify(State0, CertificateVerify))
+ catch
+ {Ref, {{bad_certificate, Reason}, State}} ->
+ {?ALERT_REC(?FATAL, ?BAD_CERTIFICATE, {bad_certificate, Reason}), State};
+ {Ref, {badarg, State}} ->
+ {?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {verify, badarg}), State};
+ {Ref, {{handshake_failure, Reason}, State}} ->
+ {?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, {handshake_failure, Reason}), State}
+ end.
+
+
+do_wait_finished(#finished{verify_data = VerifyData},
+ #state{connection_states = _ConnectionStates0,
+ session = #session{session_id = _SessionId,
+ own_certificate = _OwnCert},
+ ssl_options = #ssl_options{} = _SslOpts,
+ key_share = _KeyShare,
+ handshake_env = #handshake_env{tls_handshake_history = _HHistory0},
+ static_env = #static_env{
+ cert_db = _CertDbHandle,
+ cert_db_ref = _CertDbRef,
+ socket = _Socket,
+ transport_cb = _Transport}
+ } = State0) ->
+
+ {Ref,Maybe} = maybe(),
+
+ try
+ Maybe(validate_client_finished(State0, VerifyData)),
+
+ State1 = calculate_traffic_secrets(State0),
+
+ %% Configure traffic keys
+ ssl_record:step_encryption_state(State1)
+
+
+ catch
+ {Ref, decrypt_error} ->
+ ?ALERT_REC(?FATAL, ?DECRYPT_ERROR, decrypt_error)
+ end.
+
+
+%% TODO: Remove this function!
+%% not_implemented(State, Reason) ->
+%% {error, {not_implemented, State, Reason}}.
+%%
+%% not_implemented(update_secrets, State0, Reason) ->
+%% State1 = calculate_traffic_secrets(State0),
+%% State = ssl_record:step_encryption_state(State1),
+%% {error, {not_implemented, State, Reason}}.
+
+
+
+%% Recipients of Finished messages MUST verify that the contents are
+%% correct and if incorrect MUST terminate the connection with a
+%% "decrypt_error" alert.
+validate_client_finished(#state{connection_states = ConnectionStates,
+ handshake_env =
+ #handshake_env{
+ tls_handshake_history = {Messages0, _}}}, VerifyData) ->
+ #{security_parameters := SecParamsR,
+ cipher_state := #cipher_state{finished_key = FinishedKey}} =
+ ssl_record:current_connection_state(ConnectionStates, read),
+ #security_parameters{prf_algorithm = HKDFAlgo} = SecParamsR,
+
+ %% Drop the client's finished message, it is not part of the handshake context
+ %% when the client calculates its finished message.
+ [_|Messages] = Messages0,
+
+ ControlData = tls_v1:finished_verify_data(FinishedKey, HKDFAlgo, Messages),
+ compare_verify_data(ControlData, VerifyData).
+
+
+compare_verify_data(Data, Data) ->
+ ok;
+compare_verify_data(_, _) ->
+ {error, decrypt_error}.
+
+
+send_hello_retry_request(#state{connection_states = ConnectionStates0} = State0,
+ no_suitable_key, KeyShare, SessionId) ->
+ ServerHello = server_hello(hello_retry_request, SessionId, KeyShare, ConnectionStates0),
+ {State1, _} = tls_connection:send_handshake(ServerHello, State0),
+
+ %% TODO: Fix handshake history!
+ State2 = replace_ch1_with_message_hash(State1),
+
+ {ok, {State2, start}};
+send_hello_retry_request(State0, _, _, _) ->
+ %% Suitable key found.
+ {ok, {State0, negotiated}}.
+
+
+maybe_send_certificate_request(State, #ssl_options{verify = verify_none}) ->
+ {State, wait_finished};
+maybe_send_certificate_request(State, #ssl_options{
+ verify = verify_peer,
+ signature_algs = SignAlgs,
+ signature_algs_cert = SignAlgsCert}) ->
+ CertificateRequest = certificate_request(SignAlgs, SignAlgsCert),
+ {tls_connection:queue_handshake(CertificateRequest, State), wait_cert}.
+
+
+process_client_certificate(#certificate_1_3{
+ certificate_request_context = <<>>,
+ certificate_list = []},
+ #state{ssl_options =
+ #ssl_options{
+ fail_if_no_peer_cert = false}} = State) ->
+ {ok, {State, wait_finished}};
+process_client_certificate(#certificate_1_3{
+ certificate_request_context = <<>>,
+ certificate_list = []},
+ #state{ssl_options =
+ #ssl_options{
+ fail_if_no_peer_cert = true}} = State0) ->
+
+ %% At this point the client believes that the connection is up and starts using
+ %% its traffic secrets. In order to be able send an proper Alert to the client
+ %% the server should also change its connection state and use the traffic
+ %% secrets.
+ State1 = calculate_traffic_secrets(State0),
+ State = ssl_record:step_encryption_state(State1),
+ {error, {certificate_required, State}};
+process_client_certificate(#certificate_1_3{certificate_list = Certs0},
+ #state{ssl_options =
+ #ssl_options{signature_algs = SignAlgs,
+ signature_algs_cert = SignAlgsCert} = SslOptions,
+ static_env =
+ #static_env{
+ role = Role,
+ host = Host,
+ cert_db = CertDbHandle,
+ cert_db_ref = CertDbRef,
+ crl_db = CRLDbHandle}} = State0) ->
+ %% TODO: handle extensions!
+
+ %% Remove extensions from list of certificates!
+ Certs = convert_certificate_chain(Certs0),
+ case is_supported_signature_algorithm(Certs, SignAlgs, SignAlgsCert) of
+ true ->
+ case validate_certificate_chain(Certs, CertDbHandle, CertDbRef,
+ SslOptions, CRLDbHandle, Role, Host) of
+ {ok, {PeerCert, PublicKeyInfo}} ->
+ State = store_peer_cert(State0, PeerCert, PublicKeyInfo),
+ {ok, {State, wait_cv}};
+ {error, Reason} ->
+ State1 = calculate_traffic_secrets(State0),
+ State = ssl_record:step_encryption_state(State1),
+ {error, {Reason, State}};
+ #alert{} = Alert ->
+ State1 = calculate_traffic_secrets(State0),
+ State = ssl_record:step_encryption_state(State1),
+ {Alert, State}
+ end;
+ false ->
+ State1 = calculate_traffic_secrets(State0),
+ State = ssl_record:step_encryption_state(State1),
+ {error, {{handshake_failure,
+ "Client certificate uses unsupported signature algorithm"}, State}}
+ end.
+
+
+%% TODO: check whole chain!
+is_supported_signature_algorithm(Certs, SignAlgs, undefined) ->
+ is_supported_signature_algorithm(Certs, SignAlgs);
+is_supported_signature_algorithm(Certs, _, SignAlgsCert) ->
+ is_supported_signature_algorithm(Certs, SignAlgsCert).
+%%
+is_supported_signature_algorithm([BinCert|_], SignAlgs0) ->
+ #'OTPCertificate'{signatureAlgorithm = SignAlg} =
+ public_key:pkix_decode_cert(BinCert, otp),
+ SignAlgs = filter_tls13_algs(SignAlgs0),
+ Scheme = ssl_cipher:signature_algorithm_to_scheme(SignAlg),
+ lists:member(Scheme, SignAlgs).
+
+
+validate_certificate_chain(Certs, CertDbHandle, CertDbRef, SslOptions, CRLDbHandle, Role, Host) ->
+ ServerName = ssl_handshake:server_name(SslOptions#ssl_options.server_name_indication, Host, Role),
+ [PeerCert | ChainCerts ] = Certs,
+ try
+ {TrustedCert, CertPath} =
+ ssl_certificate:trusted_cert_and_path(Certs, CertDbHandle, CertDbRef,
+ SslOptions#ssl_options.partial_chain),
+ ValidationFunAndState =
+ ssl_handshake:validation_fun_and_state(SslOptions#ssl_options.verify_fun, Role,
+ CertDbHandle, CertDbRef, ServerName,
+ SslOptions#ssl_options.customize_hostname_check,
+ SslOptions#ssl_options.crl_check, CRLDbHandle, CertPath),
+ Options = [{max_path_length, SslOptions#ssl_options.depth},
+ {verify_fun, ValidationFunAndState}],
+ %% TODO: Validate if Certificate is using a supported signature algorithm
+ %% (signature_algs_cert)!
+ case public_key:pkix_path_validation(TrustedCert, CertPath, Options) of
+ {ok, {PublicKeyInfo,_}} ->
+ {ok, {PeerCert, PublicKeyInfo}};
+ {error, Reason} ->
+ ssl_handshake:handle_path_validation_error(Reason, PeerCert, ChainCerts,
+ SslOptions, Options,
+ CertDbHandle, CertDbRef)
+ end
+ catch
+ error:{badmatch,{asn1, Asn1Reason}} ->
+ %% ASN-1 decode of certificate somehow failed
+ {error, {certificate_unknown, {failed_to_decode_certificate, Asn1Reason}}};
+ error:OtherReason ->
+ {error, {internal_error, {unexpected_error, OtherReason}}}
+ end.
+
+
+store_peer_cert(#state{session = Session,
+ handshake_env = HsEnv} = State, PeerCert, PublicKeyInfo) ->
+ State#state{session = Session#session{peer_certificate = PeerCert},
+ handshake_env = HsEnv#handshake_env{public_key_info = PublicKeyInfo}}.
+
+
+convert_certificate_chain(Certs) ->
+ Fun = fun(#certificate_entry{data = Data}) ->
+ {true, Data};
+ (_) ->
+ false
+ end,
+ lists:filtermap(Fun, Certs).
+
+
+%% 4.4.1. The Transcript Hash
+%%
+%% As an exception to this general rule, when the server responds to a
+%% ClientHello with a HelloRetryRequest, the value of ClientHello1 is
+%% replaced with a special synthetic handshake message of handshake type
+%% "message_hash" containing Hash(ClientHello1). I.e.,
+%%
+%% Transcript-Hash(ClientHello1, HelloRetryRequest, ... Mn) =
+%% Hash(message_hash || /* Handshake type */
+%% 00 00 Hash.length || /* Handshake message length (bytes) */
+%% Hash(ClientHello1) || /* Hash of ClientHello1 */
+%% HelloRetryRequest || ... || Mn)
+%%
+%% NOTE: Hash.length is used in practice (openssl) and not message length!
+%% It is most probably a fault in the RFC.
+replace_ch1_with_message_hash(#state{connection_states = ConnectionStates,
+ handshake_env =
+ #handshake_env{
+ tls_handshake_history =
+ {[HRR,CH1|HHistory], LM}} = HSEnv} = State0) ->
+ #{security_parameters := SecParamsR} =
+ ssl_record:pending_connection_state(ConnectionStates, read),
+ #security_parameters{prf_algorithm = HKDFAlgo} = SecParamsR,
+ MessageHash = message_hash(CH1, HKDFAlgo),
+ State0#state{handshake_env =
+ HSEnv#handshake_env{
+ tls_handshake_history =
+ {[HRR,MessageHash|HHistory], LM}}}.
+
+
+message_hash(ClientHello1, HKDFAlgo) ->
+ [?MESSAGE_HASH,
+ 0,0,ssl_cipher:hash_size(HKDFAlgo),
+ crypto:hash(HKDFAlgo, ClientHello1)].
+
+
+calculate_handshake_secrets(ClientKey, SelectedGroup, KeyShare,
+ #state{connection_states = ConnectionStates,
+ handshake_env =
+ #handshake_env{
+ tls_handshake_history = HHistory}} = State0) ->
+ #{security_parameters := SecParamsR} =
+ ssl_record:pending_connection_state(ConnectionStates, read),
+ #security_parameters{prf_algorithm = HKDFAlgo,
+ cipher_suite = CipherSuite} = SecParamsR,
+
+ %% Calculate handshake_secret
+ PSK = binary:copy(<<0>>, ssl_cipher:hash_size(HKDFAlgo)),
+ EarlySecret = tls_v1:key_schedule(early_secret, HKDFAlgo , {psk, PSK}),
+ PrivateKey = get_server_private_key(KeyShare), %% #'ECPrivateKey'{}
+
+ IKM = calculate_shared_secret(ClientKey, PrivateKey, SelectedGroup),
+ HandshakeSecret = tls_v1:key_schedule(handshake_secret, HKDFAlgo, IKM, EarlySecret),
+
+ %% Calculate [sender]_handshake_traffic_secret
+ {Messages, _} = HHistory,
+ ClientHSTrafficSecret =
+ tls_v1:client_handshake_traffic_secret(HKDFAlgo, HandshakeSecret, lists:reverse(Messages)),
+ ServerHSTrafficSecret =
+ tls_v1:server_handshake_traffic_secret(HKDFAlgo, HandshakeSecret, lists:reverse(Messages)),
+
+ %% Calculate traffic keys
+ #{cipher := Cipher} = ssl_cipher_format:suite_bin_to_map(CipherSuite),
+ {ReadKey, ReadIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, ClientHSTrafficSecret),
+ {WriteKey, WriteIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, ServerHSTrafficSecret),
+
+ %% Calculate Finished Keys
+ ReadFinishedKey = tls_v1:finished_key(ClientHSTrafficSecret, HKDFAlgo),
+ WriteFinishedKey = tls_v1:finished_key(ServerHSTrafficSecret, HKDFAlgo),
+
+ update_pending_connection_states(State0, HandshakeSecret,
+ ReadKey, ReadIV, ReadFinishedKey,
+ WriteKey, WriteIV, WriteFinishedKey).
+
+calculate_traffic_secrets(#state{connection_states = ConnectionStates,
+ handshake_env =
+ #handshake_env{
+ tls_handshake_history = HHistory}} = State0) ->
+ #{security_parameters := SecParamsR} =
+ ssl_record:pending_connection_state(ConnectionStates, read),
+ #security_parameters{prf_algorithm = HKDFAlgo,
+ cipher_suite = CipherSuite,
+ master_secret = HandshakeSecret} = SecParamsR,
+
+ MasterSecret =
+ tls_v1:key_schedule(master_secret, HKDFAlgo, HandshakeSecret),
+
+ %% Get the correct list messages for the handshake context.
+ Messages = get_handshake_context(HHistory),
+
+ %% Calculate [sender]_application_traffic_secret_0
+ ClientAppTrafficSecret0 =
+ tls_v1:client_application_traffic_secret_0(HKDFAlgo, MasterSecret, lists:reverse(Messages)),
+ ServerAppTrafficSecret0 =
+ tls_v1:server_application_traffic_secret_0(HKDFAlgo, MasterSecret, lists:reverse(Messages)),
+
+ %% Calculate traffic keys
+ #{cipher := Cipher} = ssl_cipher_format:suite_bin_to_map(CipherSuite),
+ {ReadKey, ReadIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, ClientAppTrafficSecret0),
+ {WriteKey, WriteIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, ServerAppTrafficSecret0),
+
+ update_pending_connection_states(State0, MasterSecret,
+ ReadKey, ReadIV, undefined,
+ WriteKey, WriteIV, undefined).
+
+
+get_server_private_key(#key_share_server_hello{server_share = ServerShare}) ->
+ get_private_key(ServerShare).
+
+get_private_key(#key_share_entry{
+ key_exchange = #'ECPrivateKey'{} = PrivateKey}) ->
+ PrivateKey;
+get_private_key(#key_share_entry{
+ key_exchange =
+ {_, PrivateKey}}) ->
+ PrivateKey.
+
+%% TODO: implement EC keys
+get_public_key({?'rsaEncryption', PublicKey, _}) ->
+ PublicKey.
+
+
+%% X25519, X448
+calculate_shared_secret(OthersKey, MyKey, Group)
+ when is_binary(OthersKey) andalso is_binary(MyKey) andalso
+ (Group =:= x25519 orelse Group =:= x448)->
+ crypto:compute_key(ecdh, OthersKey, MyKey, Group);
+%% FFDHE
+calculate_shared_secret(OthersKey, MyKey, Group)
+ when is_binary(OthersKey) andalso is_binary(MyKey) ->
+ Params = #'DHParameter'{prime = P} = ssl_dh_groups:dh_params(Group),
+ S = public_key:compute_key(OthersKey, MyKey, Params),
+ Size = byte_size(binary:encode_unsigned(P)),
+ ssl_cipher:add_zero_padding(S, Size);
+%% ECDHE
+calculate_shared_secret(OthersKey, MyKey = #'ECPrivateKey'{}, _Group)
+ when is_binary(OthersKey) ->
+ Point = #'ECPoint'{point = OthersKey},
+ public_key:compute_key(Point, MyKey).
+
+
+update_pending_connection_states(#state{connection_states =
+ CS = #{pending_read := PendingRead0,
+ pending_write := PendingWrite0}} = State,
+ HandshakeSecret,
+ ReadKey, ReadIV, ReadFinishedKey,
+ WriteKey, WriteIV, WriteFinishedKey) ->
+ PendingRead = update_connection_state(PendingRead0, HandshakeSecret,
+ ReadKey, ReadIV, ReadFinishedKey),
+ PendingWrite = update_connection_state(PendingWrite0, HandshakeSecret,
+ WriteKey, WriteIV, WriteFinishedKey),
+ State#state{connection_states = CS#{pending_read => PendingRead,
+ pending_write => PendingWrite}}.
+
+update_connection_state(ConnectionState = #{security_parameters := SecurityParameters0},
+ HandshakeSecret, Key, IV, FinishedKey) ->
+ %% Store secret
+ SecurityParameters = SecurityParameters0#security_parameters{
+ master_secret = HandshakeSecret},
+ ConnectionState#{security_parameters => SecurityParameters,
+ cipher_state => cipher_init(Key, IV, FinishedKey)}.
+
+
+update_start_state(#state{connection_states = ConnectionStates0,
+ connection_env = CEnv,
+ session = Session} = State,
+ Cipher, KeyShare, SessionId,
+ Group, SelectedSignAlg, ClientPubKey) ->
+ #{security_parameters := SecParamsR0} = PendingRead =
+ maps:get(pending_read, ConnectionStates0),
+ #{security_parameters := SecParamsW0} = PendingWrite =
+ maps:get(pending_write, ConnectionStates0),
+ SecParamsR = ssl_cipher:security_parameters_1_3(SecParamsR0, Cipher),
+ SecParamsW = ssl_cipher:security_parameters_1_3(SecParamsW0, Cipher),
+ ConnectionStates =
+ ConnectionStates0#{pending_read => PendingRead#{security_parameters => SecParamsR},
+ pending_write => PendingWrite#{security_parameters => SecParamsW}},
+ State#state{connection_states = ConnectionStates,
+ key_share = KeyShare,
+ session = Session#session{session_id = SessionId,
+ ecc = Group,
+ sign_alg = SelectedSignAlg,
+ dh_public_value = ClientPubKey,
+ cipher_suite = Cipher},
+ connection_env = CEnv#connection_env{negotiated_version = {3,4}}}.
+
+
+cipher_init(Key, IV, FinishedKey) ->
+ #cipher_state{key = Key,
+ iv = IV,
+ finished_key = FinishedKey,
+ tag_len = 16}.
+
+
+%% Get handshake context for verification of CertificateVerify.
+%%
+%% Verify CertificateVerify:
+%% ClientHello (client) (1)
+%% ServerHello (server) (2)
+%% EncryptedExtensions (server) (8)
+%% CertificateRequest (server) (13)
+%% Certificate (server) (11)
+%% CertificateVerify (server) (15)
+%% Finished (server) (20)
+%% Certificate (client) (11)
+%% CertificateVerify (client) (15) - Drop! Not included in calculations!
+get_handshake_context_cv({[<<15,_/binary>>|Messages], _}) ->
+ Messages.
+
+
+%% Get handshake context for traffic key calculation.
+%%
+%% Client is authenticated with certificate:
+%% ClientHello (client) (1)
+%% ServerHello (server) (2)
+%% EncryptedExtensions (server) (8)
+%% CertificateRequest (server) (13)
+%% Certificate (server) (11)
+%% CertificateVerify (server) (15)
+%% Finished (server) (20)
+%% Certificate (client) (11) - Drop! Not included in calculations!
+%% CertificateVerify (client) (15) - Drop! Not included in calculations!
+%% Finished (client) (20) - Drop! Not included in calculations!
+%%
+%% Client is authenticated but sends empty certificate:
+%% ClientHello (client) (1)
+%% ServerHello (server) (2)
+%% EncryptedExtensions (server) (8)
+%% CertificateRequest (server) (13)
+%% Certificate (server) (11)
+%% CertificateVerify (server) (15)
+%% Finished (server) (20)
+%% Certificate (client) (11) - Drop! Not included in calculations!
+%% Finished (client) (20) - Drop! Not included in calculations!
+%%
+%% Client is not authenticated:
+%% ClientHello (client) (1)
+%% ServerHello (server) (2)
+%% EncryptedExtensions (server) (8)
+%% Certificate (server) (11)
+%% CertificateVerify (server) (15)
+%% Finished (server) (20)
+%% Finished (client) (20) - Drop! Not included in calculations!
+%%
+%% Drop all client messages from the front of the iolist using the property that
+%% incoming messages are binaries.
+get_handshake_context({Messages, _}) ->
+ get_handshake_context(Messages);
+get_handshake_context([H|T]) when is_binary(H) ->
+ get_handshake_context(T);
+get_handshake_context(L) ->
+ L.
+
+
+%% If sent by a client, the signature algorithm used in the signature
+%% MUST be one of those present in the supported_signature_algorithms
+%% field of the "signature_algorithms" extension in the
+%% CertificateRequest message.
+verify_signature_algorithm(#state{ssl_options =
+ #ssl_options{
+ signature_algs = ServerSignAlgs}} = State0,
+ #certificate_verify_1_3{algorithm = ClientSignAlg}) ->
+ case lists:member(ClientSignAlg, ServerSignAlgs) of
+ true ->
+ ok;
+ false ->
+ State1 = calculate_traffic_secrets(State0),
+ State = ssl_record:step_encryption_state(State1),
+ {error, {{handshake_failure,
+ "CertificateVerify uses unsupported signature algorithm"}, State}}
+ end.
+
+
+verify_certificate_verify(#state{connection_states = ConnectionStates,
+ handshake_env =
+ #handshake_env{
+ public_key_info = PublicKeyInfo,
+ tls_handshake_history = HHistory}} = State0,
+ #certificate_verify_1_3{
+ algorithm = SignatureScheme,
+ signature = Signature}) ->
+ #{security_parameters := SecParamsR} =
+ ssl_record:pending_connection_state(ConnectionStates, write),
+ #security_parameters{prf_algorithm = HKDFAlgo} = SecParamsR,
+
+ {HashAlgo, _, _} =
+ ssl_cipher:scheme_to_components(SignatureScheme),
+
+ Messages = get_handshake_context_cv(HHistory),
+
+ Context = lists:reverse(Messages),
+
+ %% Transcript-Hash uses the HKDF hash function defined by the cipher suite.
+ THash = tls_v1:transcript_hash(Context, HKDFAlgo),
+
+ PublicKey = get_public_key(PublicKeyInfo),
+
+ %% Digital signatures use the hash function defined by the selected signature
+ %% scheme.
+ case verify(THash, <<"TLS 1.3, client CertificateVerify">>,
+ HashAlgo, Signature, PublicKey) of
+ {ok, true} ->
+ {ok, {State0, wait_finished}};
+ {ok, false} ->
+ State1 = calculate_traffic_secrets(State0),
+ State = ssl_record:step_encryption_state(State1),
+ {error, {{handshake_failure, "Failed to verify CertificateVerify"}, State}};
+ {error, badarg} ->
+ State1 = calculate_traffic_secrets(State0),
+ State = ssl_record:step_encryption_state(State1),
+ {error, {badarg, State}}
+ end.
+
+
+%% If there is no overlap between the received
+%% "supported_groups" and the groups supported by the server, then the
+%% server MUST abort the handshake with a "handshake_failure" or an
+%% "insufficient_security" alert.
+select_common_groups(_, []) ->
+ {error, {insufficient_security, no_suitable_groups}};
+select_common_groups(ServerGroups, ClientGroups) ->
+ Fun = fun(E) -> lists:member(E, ClientGroups) end,
+ case lists:filter(Fun, ServerGroups) of
+ [] ->
+ {error, {insufficient_security, no_suitable_groups}};
+ L ->
+ {ok, L}
+ end.
+
+
+%% RFC 8446 - 4.2.8. Key Share
+%% This vector MAY be empty if the client is requesting a
+%% HelloRetryRequest. Each KeyShareEntry value MUST correspond to a
+%% group offered in the "supported_groups" extension and MUST appear in
+%% the same order. However, the values MAY be a non-contiguous subset
+%% of the "supported_groups" extension and MAY omit the most preferred
+%% groups.
+%%
+%% Clients can offer as many KeyShareEntry values as the number of
+%% supported groups it is offering, each representing a single set of
+%% key exchange parameters.
+%%
+%% Clients MUST NOT offer multiple KeyShareEntry values
+%% for the same group. Clients MUST NOT offer any KeyShareEntry values
+%% for groups not listed in the client's "supported_groups" extension.
+%% Servers MAY check for violations of these rules and abort the
+%% handshake with an "illegal_parameter" alert if one is violated.
+validate_key_share(_ ,[]) ->
+ ok;
+validate_key_share([], _) ->
+ {error, illegal_parameter};
+validate_key_share([G|ClientGroups], [{_, G, _}|ClientShares]) ->
+ validate_key_share(ClientGroups, ClientShares);
+validate_key_share([_|ClientGroups], [_|_] = ClientShares) ->
+ validate_key_share(ClientGroups, ClientShares).
+
+
+get_client_public_key([Group|_] = Groups, ClientShares) ->
+ get_client_public_key(Groups, ClientShares, Group).
+%%
+get_client_public_key(_, [], PreferredGroup) ->
+ {PreferredGroup, no_suitable_key};
+get_client_public_key([], _, PreferredGroup) ->
+ {PreferredGroup, no_suitable_key};
+get_client_public_key([Group|Groups], ClientShares, PreferredGroup) ->
+ case lists:keysearch(Group, 2, ClientShares) of
+ {value, {_, _, ClientPublicKey}} ->
+ {Group, ClientPublicKey};
+ false ->
+ get_client_public_key(Groups, ClientShares, PreferredGroup)
+ end.
+
+
+%% get_client_public_key(Group, ClientShares) ->
+%% case lists:keysearch(Group, 2, ClientShares) of
+%% {value, {_, _, ClientPublicKey}} ->
+%% ClientPublicKey;
+%% false ->
+%% %% 4.1.4. Hello Retry Request
+%% %%
+%% %% The server will send this message in response to a ClientHello
+%% %% message if it is able to find an acceptable set of parameters but the
+%% %% ClientHello does not contain sufficient information to proceed with
+%% %% the handshake.
+%% no_suitable_key
+%% end.
+
+select_cipher_suite([], _) ->
+ {error, no_suitable_cipher};
+select_cipher_suite([Cipher|ClientCiphers], ServerCiphers) ->
+ case lists:member(Cipher, tls_v1:suites('TLS_v1.3')) andalso
+ lists:member(Cipher, ServerCiphers) of
+ true ->
+ {ok, Cipher};
+ false ->
+ select_cipher_suite(ClientCiphers, ServerCiphers)
+ end.
+
+%% RFC 8446 (TLS 1.3)
+%% TLS 1.3 provides two extensions for indicating which signature
+%% algorithms may be used in digital signatures. The
+%% "signature_algorithms_cert" extension applies to signatures in
+%% certificates and the "signature_algorithms" extension, which
+%% originally appeared in TLS 1.2, applies to signatures in
+%% CertificateVerify messages.
+%%
+%% If no "signature_algorithms_cert" extension is
+%% present, then the "signature_algorithms" extension also applies to
+%% signatures appearing in certificates.
+
+%% Check if the signature algorithm of the server certificate is supported
+%% by the client.
+check_cert_sign_algo(SignAlgo, SignHash, ClientSignAlgs, undefined) ->
+ do_check_cert_sign_algo(SignAlgo, SignHash, ClientSignAlgs);
+check_cert_sign_algo(SignAlgo, SignHash, _, ClientSignAlgsCert) ->
+ do_check_cert_sign_algo(SignAlgo, SignHash, ClientSignAlgsCert).
+
+
+%% DSA keys are not supported by TLS 1.3
+select_sign_algo(dsa, _ClientSignAlgs, _ServerSignAlgs) ->
+ {error, {insufficient_security, no_suitable_public_key}};
+%% TODO: Implement support for ECDSA keys!
+select_sign_algo(_, [], _) ->
+ {error, {insufficient_security, no_suitable_signature_algorithm}};
+select_sign_algo(PublicKeyAlgo, [C|ClientSignAlgs], ServerSignAlgs) ->
+ {_, S, _} = ssl_cipher:scheme_to_components(C),
+ %% RSASSA-PKCS1-v1_5 and Legacy algorithms are not defined for use in signed
+ %% TLS handshake messages: filter sha-1 and rsa_pkcs1.
+ case ((PublicKeyAlgo =:= rsa andalso S =:= rsa_pss_rsae)
+ orelse (PublicKeyAlgo =:= rsa_pss andalso S =:= rsa_pss_rsae))
+ andalso
+ lists:member(C, ServerSignAlgs) of
+ true ->
+ {ok, C};
+ false ->
+ select_sign_algo(PublicKeyAlgo, ClientSignAlgs, ServerSignAlgs)
+ end.
+
+
+do_check_cert_sign_algo(_, _, []) ->
+ {error, {insufficient_security, no_suitable_signature_algorithm}};
+do_check_cert_sign_algo(SignAlgo, SignHash, [Scheme|T]) ->
+ {Hash, Sign, _Curve} = ssl_cipher:scheme_to_components(Scheme),
+ case compare_sign_algos(SignAlgo, SignHash, Sign, Hash) of
+ true ->
+ ok;
+ _Else ->
+ do_check_cert_sign_algo(SignAlgo, SignHash, T)
+ end.
+
+
+%% id-RSASSA-PSS (rsa_pss) indicates that the key may only be used for PSS signatures.
+%% TODO: Uncomment when rsa_pss signatures are supported in certificates
+%% compare_sign_algos(rsa_pss, Hash, Algo, Hash)
+%% when Algo =:= rsa_pss_pss ->
+%% true;
+%% rsaEncryption (rsa) allows the key to be used for any of the standard encryption or
+%% signature schemes.
+compare_sign_algos(rsa, Hash, Algo, Hash)
+ when Algo =:= rsa_pss_rsae orelse
+ Algo =:= rsa_pkcs1 ->
+ true;
+compare_sign_algos(Algo, Hash, Algo, Hash) ->
+ true;
+compare_sign_algos(_, _, _, _) ->
+ false.
+
+
+get_certificate_params(Cert) ->
+ {SignAlgo0, _Param, PublicKeyAlgo0} = ssl_handshake:get_cert_params(Cert),
+ {SignHash0, SignAlgo} = public_key:pkix_sign_types(SignAlgo0),
+ %% Convert hash to new format
+ SignHash = case SignHash0 of
+ sha ->
+ sha1;
+ H -> H
+ end,
+ PublicKeyAlgo = public_key_algo(PublicKeyAlgo0),
+ {PublicKeyAlgo, SignAlgo, SignHash}.
+
+
+%% Note: copied from ssl_handshake
+public_key_algo(?'id-RSASSA-PSS') ->
+ rsa_pss;
+public_key_algo(?rsaEncryption) ->
+ rsa;
+public_key_algo(?'id-ecPublicKey') ->
+ ecdsa;
+public_key_algo(?'id-dsa') ->
+ dsa.
+
+get_signature_scheme_list(undefined) ->
+ undefined;
+get_signature_scheme_list(#signature_algorithms_cert{
+ signature_scheme_list = ClientSignatureSchemes}) ->
+ ClientSignatureSchemes;
+get_signature_scheme_list(#signature_algorithms{
+ signature_scheme_list = ClientSignatureSchemes}) ->
+ %% Filter unassigned and legacy elements
+ lists:filter(fun (E) -> is_atom(E) andalso E =/= unassigned end,
+ ClientSignatureSchemes).
+
+get_supported_groups(#supported_groups{supported_groups = Groups}) ->
+ Groups.
+
+get_key_shares(#key_share_client_hello{client_shares = ClientShares}) ->
+ ClientShares.
+
+maybe() ->
+ Ref = erlang:make_ref(),
+ Ok = fun(ok) -> ok;
+ ({ok,R}) -> R;
+ ({error,Reason}) ->
+ throw({Ref,Reason})
+ end,
+ {Ref,Ok}.
diff --git a/lib/ssl/src/tls_handshake_1_3.hrl b/lib/ssl/src/tls_handshake_1_3.hrl
new file mode 100644
index 0000000000..7ae1b93e1c
--- /dev/null
+++ b/lib/ssl/src/tls_handshake_1_3.hrl
@@ -0,0 +1,238 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Record and constant defenitions for the TLS-handshake protocol
+%% see RFC 8446. Also includes supported hello extensions.
+%%----------------------------------------------------------------------
+
+-ifndef(tls_handshake_1_3).
+-define(tls_handshake_1_3, true).
+
+%% Common to TLS-1.3 and previous TLS versions
+%% Some defenitions may not exist in TLS-1.3 this is
+%% handled elsewhere
+-include("tls_handshake.hrl").
+
+%% New handshake types in TLS-1.3 RFC 8446 B.3
+-define(NEW_SESSION_TICKET, 4).
+-define(END_OF_EARLY_DATA, 5).
+-define(ENCRYPTED_EXTENSIONS, 8).
+-define(KEY_UPDATE, 24).
+%% %% Not really a message but special way to handle handshake hashes
+%% %% when a "hello-retry-request" (special server_hello) is sent
+-define(MESSAGE_HASH, 254).
+
+%% %% RFC 8446 B.3.1.
+%% %% New extension types in TLS-1.3
+-define(PRE_SHARED_KEY_EXT, 41).
+-define(EARLY_DATA_EXT, 42).
+%%-define(SUPPORTED_VERSIONS_EXT, 43). %% Updates TLS 1.2 so defined in ssl_handshake.hrl
+-define(COOKIE_EXT, 44).
+-define(PSK_KEY_EXCHANGE_MODES_EXT, 45).
+-define(CERTIFICATE_AUTHORITIES_EXT, 47).
+-define(OID_FILTERS_EXT, 48).
+-define(POST_HANDSHAKE_AUTH_EXT, 49).
+%% -define(SIGNATURE_ALGORITHMS_CERT_EXT, 50). %% Updates TLS 1.2 so defined in ssl_handshake.hrl
+-define(KEY_SHARE_EXT, 51).
+
+%% RFC 8446 B.3.1
+-record(key_share_entry, {
+ group, %NamedGroup
+ key_exchange %key_exchange<1..2^16-1>;
+ }).
+-record(key_share_client_hello, {
+ client_shares %% KeyShareEntry client_shares<0..2^16-1>;
+ }).
+-record(key_share_hello_retry_request, {
+ selected_group %% NamedGroup
+ }).
+-record(key_share_server_hello, {
+ server_share %% KeyShareEntry server_share;
+ }).
+
+-record(uncompressed_point_representation, {
+ legacy_form = 4, % uint8 legacy_form = 4;
+ x, % opaque X[coordinate_length];
+ y % opaque Y[coordinate_length];
+ }).
+
+-define(PSK_KE, 0).
+-define(PSK_DHE_KE, 1).
+
+-record(psk_keyexchange_modes, {
+ ke_modes % ke_modes<1..255>
+ }).
+-record(empty, {
+ }).
+-record(early_data_indication, {
+ indication % uint32 max_early_data_size (new_session_ticket) |
+ %% #empty{} (client_hello, encrypted_extensions)
+ }).
+-record(psk_identity, {
+ identity, % opaque identity<1..2^16-1>
+ obfuscated_ticket_age % uint32
+ }).
+-record(offered_psks, {
+ psk_identity, %identities<7..2^16-1>;
+ psk_binder_entry %binders<33..2^16-1>, opaque PskBinderEntry<32..255>
+ }).
+-record(pre_shared_keyextension,{
+ extension %OfferedPsks (client_hello) | uint16 selected_identity (server_hello)
+ }).
+
+%% RFC 8446 B.3.1.2.
+-record(cookie, {
+ cookie %cookie<1..2^16-1>;
+ }).
+
+%%% RFC 8446 B.3.1.3. Signature Algorithm Extension
+%% Signature Schemes
+%% RSASSA-PKCS1-v1_5 algorithms
+-define(RSA_PKCS1_SHA256, 16#0401).
+-define(RSA_PKCS1_SHA384, 16#0501).
+-define(RSA_PKCS1_SHA512, 16#0601).
+
+%% ECDSA algorithms
+-define(ECDSA_SECP256R1_SHA256, 16#0403).
+-define(ECDSA_SECP384R1_SHA384, 16#0503).
+-define(ECDSA_SECP521R1_SHA512, 16#0603).
+
+%% RSASSA-PSS algorithms with public key OID rsaEncryption
+-define(RSA_PSS_RSAE_SHA256, 16#0804).
+-define(RSA_PSS_RSAE_SHA384, 16#0805).
+-define(RSA_PSS_RSAE_SHA512, 16#0806).
+
+%% EdDSA algorithms
+-define(ED25519, 16#0807).
+-define(ED448, 16#0808).
+
+%% RSASSA-PSS algorithms with public key OID RSASSA-PSS
+-define(RSA_PSS_PSS_SHA256, 16#0809).
+-define(RSA_PSS_PSS_SHA384, 16#080a).
+-define(RSA_PSS_PSS_SHA512, 16#080b).
+
+%% Legacy algorithms
+-define(RSA_PKCS1_SHA1, 16#201).
+-define(ECDSA_SHA1, 16#0203).
+
+%% RFC 8446 B.3.1.4. Supported Groups Extension
+%% Elliptic Curve Groups (ECDHE)
+-define(SECP256R1, 16#0017).
+-define(SECP384R1, 16#0018).
+-define(SECP521R1, 16#0019).
+-define(X25519, 16#001D).
+-define(X448, 16#001E).
+
+%% RFC 8446 Finite Field Groups (DHE)
+-define(FFDHE2048, 16#0100).
+-define(FFDHE3072, 16#0101).
+-define(FFDHE4096, 16#0102).
+-define(FFDHE6144, 16#0103).
+-define(FFDHE8192 ,16#0104).
+
+-record(named_group_list, {
+ named_group_list %named_group_list<2..2^16-1>;
+ }).
+
+%% RFC 8446 B.3.2 Server Parameters Messages
+%% opaque DistinguishedName<1..2^16-1>;XS
+-record(certificate_authoritie_sextension, {
+ authorities %DistinguishedName authorities<3..2^16-1>;
+ }).
+
+-record(oid_filter, {
+ certificate_extension_oid, % opaque certificate_extension_oid<1..2^8-1>;
+ certificate_extension_values % opaque certificate_extension_values<0..2^16-1>;
+ }).
+
+-record(oid_filter_extension, {
+ filters %OIDFilter filters<0..2^16-1>;
+ }).
+-record(post_handshake_auth, {
+ }).
+
+-record(encrypted_extensions, {
+ extensions %extensions<0..2^16-1>;
+ }).
+
+-record(certificate_request_1_3, {
+ certificate_request_context, % opaque certificate_request_context<0..2^8-1>;
+ extensions %Extension extensions<2..2^16-1>;
+ }).
+
+%% RFC 8446 B.3.3 Authentication Messages
+
+%% Certificate Type
+-define(X509, 0).
+-define(OpenPGP_RESERVED, 1).
+-define(RawPublicKey, 2).
+
+-record(certificate_entry, {
+ data,
+ %% select (certificate_type) {
+ %% case RawPublicKey:
+ %% /* From RFC 7250 ASN.1_subjectPublicKeyInfo */
+ %% opaque ASN1_subjectPublicKeyInfo<1..2^24-1>;
+ %%
+ %% case X509:
+ %% opaque cert_data<1..2^24-1>;
+ %% };
+ extensions %% Extension extensions<0..2^16-1>;
+ }).
+
+-record(certificate_1_3, {
+ certificate_request_context, % opaque certificate_request_context<0..2^8-1>;
+ certificate_list % CertificateEntry certificate_list<0..2^24-1>;
+ }).
+
+-record(certificate_verify_1_3, {
+ algorithm, % SignatureScheme
+ signature % signature<0..2^16-1>
+ }).
+
+%% RFC 8446 B.3.4. Ticket Establishment
+-record(new_session_ticket, {
+ ticket_lifetime, %unit32
+ ticket_age_add, %unit32
+ ticket_nonce, %opaque ticket_nonce<0..255>;
+ ticket, %opaque ticket<1..2^16-1>
+ extensions %extensions<0..2^16-2>
+ }).
+
+%% RFC 8446 B.3.5. Updating Keys
+-record(end_of_early_data, {
+ }).
+
+-define(UPDATE_NOT_REQUESTED, 0).
+-define(UPDATE_REQUESTED, 1).
+
+-record(key_update, {
+ request_update
+ }).
+
+-type tls_handshake_1_3() :: #encrypted_extensions{} |
+ #certificate_request_1_3{} |
+ #certificate_1_3{} |
+ #certificate_verify_1_3{}.
+
+-export_type([tls_handshake_1_3/0]).
+
+-endif. % -ifdef(tls_handshake_1_3).
diff --git a/lib/ssl/src/tls_record.erl b/lib/ssl/src/tls_record.erl
index 188ec6809d..a5c550a429 100644
--- a/lib/ssl/src/tls_record.erl
+++ b/lib/ssl/src/tls_record.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -30,9 +30,10 @@
-include("ssl_alert.hrl").
-include("tls_handshake.hrl").
-include("ssl_cipher.hrl").
+-include_lib("kernel/include/logger.hrl").
%% Handling of incoming data
--export([get_tls_records/3, init_connection_states/2]).
+-export([get_tls_records/4, init_connection_states/2]).
%% Encoding TLS records
-export([encode_handshake/3, encode_alert_record/3,
@@ -40,13 +41,16 @@
-export([encode_plain_text/4]).
%% Decoding
--export([decode_cipher_text/3]).
+-export([decode_cipher_text/4]).
+
+%% Logging helper
+-export([build_tls_record/1]).
%% Protocol version handling
-export([protocol_version/1, lowest_protocol_version/1, lowest_protocol_version/2,
highest_protocol_version/1, highest_protocol_version/2,
is_higher/2, supported_protocol_versions/0,
- is_acceptable_version/1, is_acceptable_version/2, hello_version/2]).
+ is_acceptable_version/1, is_acceptable_version/2, hello_version/1]).
-export_type([tls_version/0, tls_atom_version/0]).
@@ -75,25 +79,23 @@ init_connection_states(Role, BeastMitigation) ->
pending_write => Pending}.
%%--------------------------------------------------------------------
--spec get_tls_records(binary(), [tls_version()], binary()) -> {[binary()], binary()} | #alert{}.
+-spec get_tls_records(
+ binary(),
+ [tls_version()] | tls_version(),
+ Buffer0 :: binary() | {'undefined' | #ssl_tls{}, {[binary()],non_neg_integer(),[binary()]}},
+ #ssl_options{}) ->
+ {Records :: [#ssl_tls{}],
+ Buffer :: {'undefined' | #ssl_tls{}, {[binary()],non_neg_integer(),[binary()]}}} |
+ #alert{}.
%%
%% and returns it as a list of tls_compressed binaries also returns leftover
%% Description: Given old buffer and new data from TCP, packs up a records
%% data
%%--------------------------------------------------------------------
-get_tls_records(Data, Versions, Buffer) ->
- BinData = list_to_binary([Buffer, Data]),
- case erlang:byte_size(BinData) of
- N when N >= 3 ->
- case assert_version(BinData, Versions) of
- true ->
- get_tls_records_aux(BinData, []);
- false ->
- ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
- end;
- _ ->
- get_tls_records_aux(BinData, [])
- end.
+get_tls_records(Data, Versions, Buffer, SslOpts) when is_binary(Buffer) ->
+ parse_tls_records(Versions, {[Data],byte_size(Data),[]}, SslOpts, undefined);
+get_tls_records(Data, Versions, {Hdr, {Front,Size,Rear}}, SslOpts) ->
+ parse_tls_records(Versions, {Front,Size + byte_size(Data),[Data|Rear]}, SslOpts, Hdr).
%%====================================================================
%% Encoding
@@ -105,6 +107,8 @@ get_tls_records(Data, Versions, Buffer) ->
%
%% Description: Encodes a handshake message to send on the ssl-socket.
%%--------------------------------------------------------------------
+encode_handshake(Frag, {3, 4}, ConnectionStates) ->
+ tls_record_1_3:encode_handshake(Frag, ConnectionStates);
encode_handshake(Frag, Version,
#{current_write :=
#{beast_mitigation := BeastMitigation,
@@ -113,8 +117,8 @@ encode_handshake(Frag, Version,
ConnectionStates) ->
case iolist_size(Frag) of
N when N > ?MAX_PLAIN_TEXT_LENGTH ->
- Data = split_bin(iolist_to_binary(Frag), ?MAX_PLAIN_TEXT_LENGTH, Version, BCA, BeastMitigation),
- encode_iolist(?HANDSHAKE, Data, Version, ConnectionStates);
+ Data = split_iovec(erlang:iolist_to_iovec(Frag), Version, BCA, BeastMitigation),
+ encode_fragments(?HANDSHAKE, Version, Data, ConnectionStates);
_ ->
encode_plain_text(?HANDSHAKE, Version, Frag, ConnectionStates)
end.
@@ -125,6 +129,8 @@ encode_handshake(Frag, Version,
%%
%% Description: Encodes an alert message to send on the ssl-socket.
%%--------------------------------------------------------------------
+encode_alert_record(Alert, {3, 4}, ConnectionStates) ->
+ tls_record_1_3:encode_alert_record(Alert, ConnectionStates);
encode_alert_record(#alert{level = Level, description = Description},
Version, ConnectionStates) ->
encode_plain_text(?ALERT, Version, <<?BYTE(Level), ?BYTE(Description)>>,
@@ -140,79 +146,86 @@ encode_change_cipher_spec(Version, ConnectionStates) ->
encode_plain_text(?CHANGE_CIPHER_SPEC, Version, ?byte(?CHANGE_CIPHER_SPEC_PROTO), ConnectionStates).
%%--------------------------------------------------------------------
--spec encode_data(binary(), tls_version(), ssl_record:connection_states()) ->
- {iolist(), ssl_record:connection_states()}.
+-spec encode_data([binary()], tls_version(), ssl_record:connection_states()) ->
+ {[[binary()]], ssl_record:connection_states()}.
%%
%% Description: Encodes data to send on the ssl-socket.
%%--------------------------------------------------------------------
-encode_data(Frag, Version,
+encode_data(Data, {3, 4}, ConnectionStates) ->
+ tls_record_1_3:encode_data(Data, ConnectionStates);
+encode_data(Data, Version,
#{current_write := #{beast_mitigation := BeastMitigation,
security_parameters :=
#security_parameters{bulk_cipher_algorithm = BCA}}} =
ConnectionStates) ->
- Data = split_bin(Frag, ?MAX_PLAIN_TEXT_LENGTH, Version, BCA, BeastMitigation),
- encode_iolist(?APPLICATION_DATA, Data, Version, ConnectionStates).
+ Fragments = split_iovec(Data, Version, BCA, BeastMitigation),
+ encode_fragments(?APPLICATION_DATA, Version, Fragments, ConnectionStates).
%%====================================================================
%% Decoding
%%====================================================================
%%--------------------------------------------------------------------
--spec decode_cipher_text(#ssl_tls{}, ssl_record:connection_states(), boolean()) ->
+-spec decode_cipher_text(tls_version(), #ssl_tls{}, ssl_record:connection_states(), boolean()) ->
{#ssl_tls{}, ssl_record:connection_states()}| #alert{}.
%%
%% Description: Decode cipher text
%%--------------------------------------------------------------------
-decode_cipher_text(#ssl_tls{type = Type, version = Version,
- fragment = CipherFragment} = CipherText,
+decode_cipher_text({3,4}, CipherTextRecord, ConnectionStates, _) ->
+ tls_record_1_3:decode_cipher_text(CipherTextRecord, ConnectionStates);
+decode_cipher_text(_, CipherTextRecord,
#{current_read :=
- #{compression_state := CompressionS0,
- sequence_number := Seq,
- cipher_state := CipherS0,
+ #{sequence_number := Seq,
security_parameters :=
- #security_parameters{
- cipher_type = ?AEAD,
- bulk_cipher_algorithm =
- BulkCipherAlgo,
- compression_algorithm = CompAlg}
- } = ReadState0} = ConnnectionStates0, _) ->
- AAD = calc_aad(Type, Version, ReadState0),
- case ssl_cipher:decipher_aead(BulkCipherAlgo, CipherS0, Seq, AAD, CipherFragment, Version) of
- {PlainFragment, CipherS1} ->
- {Plain, CompressionS1} = ssl_record:uncompress(CompAlg,
- PlainFragment, CompressionS0),
- ConnnectionStates = ConnnectionStates0#{
+ #security_parameters{cipher_type = ?AEAD,
+ bulk_cipher_algorithm = BulkCipherAlgo},
+ cipher_state := CipherS0
+ }
+ } = ConnectionStates0, _) ->
+ SeqBin = <<?UINT64(Seq)>>,
+ #ssl_tls{type = Type, version = {MajVer,MinVer} = Version, fragment = Fragment} = CipherTextRecord,
+ StartAdditionalData = <<SeqBin/binary, ?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer)>>,
+ CipherS = ssl_record:nonce_seed(BulkCipherAlgo, SeqBin, CipherS0),
+ case ssl_record:decipher_aead(
+ BulkCipherAlgo, CipherS, StartAdditionalData, Fragment, Version)
+ of
+ PlainFragment when is_binary(PlainFragment) ->
+ #{current_read :=
+ #{security_parameters := SecParams,
+ compression_state := CompressionS0} = ReadState0} = ConnectionStates0,
+ {Plain, CompressionS} = ssl_record:uncompress(SecParams#security_parameters.compression_algorithm,
+ PlainFragment, CompressionS0),
+ ConnectionStates = ConnectionStates0#{
current_read => ReadState0#{
- cipher_state => CipherS1,
+ cipher_state => CipherS,
sequence_number => Seq + 1,
- compression_state => CompressionS1}},
- {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates};
+ compression_state => CompressionS}},
+ {CipherTextRecord#ssl_tls{fragment = Plain}, ConnectionStates};
#alert{} = Alert ->
Alert
end;
-decode_cipher_text(#ssl_tls{type = Type, version = Version,
- fragment = CipherFragment} = CipherText,
- #{current_read :=
- #{compression_state := CompressionS0,
- sequence_number := Seq,
- security_parameters :=
- #security_parameters{compression_algorithm = CompAlg}
- } = ReadState0} = ConnnectionStates0, PaddingCheck) ->
+decode_cipher_text(_, #ssl_tls{version = Version,
+ fragment = CipherFragment} = CipherTextRecord,
+ #{current_read := ReadState0} = ConnnectionStates0, PaddingCheck) ->
case ssl_record:decipher(Version, CipherFragment, ReadState0, PaddingCheck) of
{PlainFragment, Mac, ReadState1} ->
- MacHash = ssl_cipher:calc_mac_hash(Type, Version, PlainFragment, ReadState1),
+ MacHash = ssl_cipher:calc_mac_hash(CipherTextRecord#ssl_tls.type, Version, PlainFragment, ReadState1),
case ssl_record:is_correct_mac(Mac, MacHash) of
true ->
+ #{sequence_number := Seq,
+ compression_state := CompressionS0,
+ security_parameters :=
+ #security_parameters{compression_algorithm = CompAlg}} = ReadState0,
{Plain, CompressionS1} = ssl_record:uncompress(CompAlg,
PlainFragment, CompressionS0),
- ConnnectionStates = ConnnectionStates0#{
- current_read => ReadState1#{
- sequence_number => Seq + 1,
- compression_state => CompressionS1}},
- {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates};
+ ConnnectionStates =
+ ConnnectionStates0#{current_read =>
+ ReadState1#{sequence_number => Seq + 1,
+ compression_state => CompressionS1}},
+ {CipherTextRecord#ssl_tls{fragment = Plain}, ConnnectionStates};
false ->
- ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
+ ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
end;
#alert{} = Alert ->
Alert
@@ -229,6 +242,8 @@ decode_cipher_text(#ssl_tls{type = Type, version = Version,
%% Description: Creates a protocol version record from a version atom
%% or vice versa.
%%--------------------------------------------------------------------
+protocol_version('tlsv1.3') ->
+ {3, 4};
protocol_version('tlsv1.2') ->
{3, 3};
protocol_version('tlsv1.1') ->
@@ -239,6 +254,8 @@ protocol_version(sslv3) ->
{3, 0};
protocol_version(sslv2) -> %% Backwards compatibility
{2, 0};
+protocol_version({3, 4}) ->
+ 'tlsv1.3';
protocol_version({3, 3}) ->
'tlsv1.2';
protocol_version({3, 2}) ->
@@ -372,10 +389,10 @@ is_acceptable_version({N,_} = Version, Versions)
is_acceptable_version(_,_) ->
false.
--spec hello_version(tls_version(), [tls_version()]) -> tls_version().
-hello_version(Version, _) when Version >= {3, 3} ->
- Version;
-hello_version(_, Versions) ->
+-spec hello_version([tls_version()]) -> tls_version().
+hello_version([Highest|_]) when Highest >= {3,3} ->
+ Highest;
+hello_version(Versions) ->
lowest_protocol_version(Versions).
%%--------------------------------------------------------------------
@@ -394,145 +411,232 @@ initial_connection_state(ConnectionEnd, BeastMitigation) ->
server_verify_data => undefined
}.
-assert_version(<<1:1, Length0:15, Data0:Length0/binary, _/binary>>, Versions) ->
- case Data0 of
- <<?BYTE(?CLIENT_HELLO), ?BYTE(Major), ?BYTE(Minor), _/binary>> ->
- %% First check v2_hello_compatible mode is active
- lists:member({2,0}, Versions) andalso
- %% andalso we want to negotiate higher version
- lists:member({Major, Minor}, Versions -- [{2,0}]);
- _ ->
- false
+%% Used by logging to recreate the received bytes
+build_tls_record(#ssl_tls{type = Type, version = {MajVer, MinVer}, fragment = Fragment}) ->
+ Length = byte_size(Fragment),
+ <<?BYTE(Type),?BYTE(MajVer),?BYTE(MinVer),?UINT16(Length), Fragment/binary>>.
+
+
+parse_tls_records(Versions, Q, SslOpts, undefined) ->
+ decode_tls_records(Versions, Q, SslOpts, [], undefined, undefined, undefined);
+parse_tls_records(Versions, Q, SslOpts, #ssl_tls{type = Type, version = Version, fragment = Length}) ->
+ decode_tls_records(Versions, Q, SslOpts, [], Type, Version, Length).
+
+%% Generic code path
+decode_tls_records(Versions, {_,Size,_} = Q0, SslOpts, Acc, undefined, _Version, _Length) ->
+ if
+ 5 =< Size ->
+ {<<?BYTE(Type),?BYTE(MajVer),?BYTE(MinVer), ?UINT16(Length)>>, Q} = binary_from_front(5, Q0),
+ validate_tls_records_type(Versions, Q, SslOpts, Acc, Type, {MajVer,MinVer}, Length);
+ 3 =< Size ->
+ {<<?BYTE(Type),?BYTE(MajVer),?BYTE(MinVer)>>, Q} = binary_from_front(3, Q0),
+ validate_tls_records_type(Versions, Q, SslOpts, Acc, Type, {MajVer,MinVer}, undefined);
+ 1 =< Size ->
+ {<<?BYTE(Type)>>, Q} = binary_from_front(1, Q0),
+ validate_tls_records_type(Versions, Q, SslOpts, Acc, Type, undefined, undefined);
+ true ->
+ validate_tls_records_type(Versions, Q0, SslOpts, Acc, undefined, undefined, undefined)
+ end;
+decode_tls_records(Versions, {_,Size,_} = Q0, SslOpts, Acc, Type, undefined, _Length) ->
+ if
+ 4 =< Size ->
+ {<<?BYTE(MajVer),?BYTE(MinVer), ?UINT16(Length)>>, Q} = binary_from_front(4, Q0),
+ validate_tls_record_version(Versions, Q, SslOpts, Acc, Type, {MajVer,MinVer}, Length);
+ 2 =< Size ->
+ {<<?BYTE(MajVer),?BYTE(MinVer)>>, Q} = binary_from_front(2, Q0),
+ validate_tls_record_version(Versions, Q, SslOpts, Acc, Type, {MajVer,MinVer}, undefined);
+ true ->
+ validate_tls_record_version(Versions, Q0, SslOpts, Acc, Type, undefined, undefined)
end;
-assert_version(<<?BYTE(_), ?BYTE(MajVer), ?BYTE(MinVer), _/binary>>, Versions) ->
- is_acceptable_version({MajVer, MinVer}, Versions).
-
-get_tls_records_aux(<<?BYTE(?APPLICATION_DATA),?BYTE(MajVer),?BYTE(MinVer),
- ?UINT16(Length), Data:Length/binary, Rest/binary>>,
- Acc) ->
- get_tls_records_aux(Rest, [#ssl_tls{type = ?APPLICATION_DATA,
- version = {MajVer, MinVer},
- fragment = Data} | Acc]);
-get_tls_records_aux(<<?BYTE(?HANDSHAKE),?BYTE(MajVer),?BYTE(MinVer),
- ?UINT16(Length),
- Data:Length/binary, Rest/binary>>, Acc) ->
- get_tls_records_aux(Rest, [#ssl_tls{type = ?HANDSHAKE,
- version = {MajVer, MinVer},
- fragment = Data} | Acc]);
-get_tls_records_aux(<<?BYTE(?ALERT),?BYTE(MajVer),?BYTE(MinVer),
- ?UINT16(Length), Data:Length/binary,
- Rest/binary>>, Acc) ->
- get_tls_records_aux(Rest, [#ssl_tls{type = ?ALERT,
- version = {MajVer, MinVer},
- fragment = Data} | Acc]);
-get_tls_records_aux(<<?BYTE(?CHANGE_CIPHER_SPEC),?BYTE(MajVer),?BYTE(MinVer),
- ?UINT16(Length), Data:Length/binary, Rest/binary>>,
- Acc) ->
- get_tls_records_aux(Rest, [#ssl_tls{type = ?CHANGE_CIPHER_SPEC,
- version = {MajVer, MinVer},
- fragment = Data} | Acc]);
-%% Matches an ssl v2 client hello message.
-%% The server must be able to receive such messages, from clients that
-%% are willing to use ssl v3 or higher, but have ssl v2 compatibility.
-get_tls_records_aux(<<1:1, Length0:15, Data0:Length0/binary, Rest/binary>>,
- Acc) ->
- case Data0 of
- <<?BYTE(?CLIENT_HELLO), ?BYTE(MajVer), ?BYTE(MinVer), _/binary>> ->
- Length = Length0-1,
- <<?BYTE(_), Data1:Length/binary>> = Data0,
- Data = <<?BYTE(?CLIENT_HELLO), ?UINT24(Length), Data1/binary>>,
- get_tls_records_aux(Rest, [#ssl_tls{type = ?HANDSHAKE,
- version = {MajVer, MinVer},
- fragment = Data} | Acc]);
- _ ->
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)
-
+decode_tls_records(Versions, {_,Size,_} = Q0, SslOpts, Acc, Type, Version, undefined) ->
+ if
+ 2 =< Size ->
+ {<<?UINT16(Length)>>, Q} = binary_from_front(2, Q0),
+ validate_tls_record_length(Versions, Q, SslOpts, Acc, Type, Version, Length);
+ true ->
+ validate_tls_record_length(Versions, Q0, SslOpts, Acc, Type, Version, undefined)
end;
+decode_tls_records(Versions, Q, SslOpts, Acc, Type, Version, Length) ->
+ validate_tls_record_length(Versions, Q, SslOpts, Acc, Type, Version, Length).
+
+validate_tls_records_type(_Versions, Q, _SslOpts, Acc, undefined, _Version, _Length) ->
+ {lists:reverse(Acc),
+ {undefined, Q}};
+validate_tls_records_type(Versions, Q, SslOpts, Acc, Type, Version, Length) ->
+ if
+ ?KNOWN_RECORD_TYPE(Type) ->
+ validate_tls_record_version(Versions, Q, SslOpts, Acc, Type, Version, Length);
+ true ->
+ %% Not ?KNOWN_RECORD_TYPE(Type)
+ ?ALERT_REC(?FATAL, ?UNEXPECTED_MESSAGE)
+ end.
-get_tls_records_aux(<<0:1, _CT:7, ?BYTE(_MajVer), ?BYTE(_MinVer),
- ?UINT16(Length), _/binary>>,
- _Acc) when Length > ?MAX_CIPHER_TEXT_LENGTH ->
- ?ALERT_REC(?FATAL, ?RECORD_OVERFLOW);
-get_tls_records_aux(<<1:1, Length0:15, _/binary>>,_Acc)
- when Length0 > ?MAX_CIPHER_TEXT_LENGTH ->
- ?ALERT_REC(?FATAL, ?RECORD_OVERFLOW);
-
-get_tls_records_aux(Data, Acc) ->
- case size(Data) =< ?MAX_CIPHER_TEXT_LENGTH + ?INITIAL_BYTES of
- true ->
- {lists:reverse(Acc), Data};
- false ->
- ?ALERT_REC(?FATAL, ?UNEXPECTED_MESSAGE)
- end.
-%%--------------------------------------------------------------------
-encode_plain_text(Type, Version, Data, #{current_write := Write0} = ConnectionStates) ->
- {CipherFragment, Write1} = do_encode_plain_text(Type, Version, Data, Write0),
- {CipherText, Write} = encode_tls_cipher_text(Type, Version, CipherFragment, Write1),
- {CipherText, ConnectionStates#{current_write => Write}}.
-
-encode_tls_cipher_text(Type, {MajVer, MinVer}, Fragment, #{sequence_number := Seq} = Write) ->
- Length = erlang:iolist_size(Fragment),
- {[<<?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer), ?UINT16(Length)>>, Fragment],
- Write#{sequence_number => Seq +1}}.
-
-encode_iolist(Type, Data, Version, ConnectionStates0) ->
- {ConnectionStates, EncodedMsg} =
- lists:foldl(fun(Text, {CS0, Encoded}) ->
- {Enc, CS1} =
- encode_plain_text(Type, Version, Text, CS0),
- {CS1, [Enc | Encoded]}
- end, {ConnectionStates0, []}, Data),
- {lists:reverse(EncodedMsg), ConnectionStates}.
-%%--------------------------------------------------------------------
-do_encode_plain_text(Type, Version, Data, #{compression_state := CompS0,
- security_parameters :=
- #security_parameters{
- cipher_type = ?AEAD,
- compression_algorithm = CompAlg}
- } = WriteState0) ->
- {Comp, CompS1} = ssl_record:compress(CompAlg, Data, CompS0),
- WriteState1 = WriteState0#{compression_state => CompS1},
- AAD = calc_aad(Type, Version, WriteState1),
- ssl_record:cipher_aead(Version, Comp, WriteState1, AAD);
-do_encode_plain_text(Type, Version, Data, #{compression_state := CompS0,
- security_parameters :=
- #security_parameters{compression_algorithm = CompAlg}
- }= WriteState0) ->
- {Comp, CompS1} = ssl_record:compress(CompAlg, Data, CompS0),
- WriteState1 = WriteState0#{compression_state => CompS1},
- MacHash = ssl_cipher:calc_mac_hash(Type, Version, Comp, WriteState1),
- ssl_record:cipher(Version, Comp, WriteState1, MacHash);
-do_encode_plain_text(_,_,_,CS) ->
+validate_tls_record_version(_Versions, Q, _SslOpts, Acc, Type, undefined, _Length) ->
+ {lists:reverse(Acc),
+ {#ssl_tls{type = Type, version = undefined, fragment = undefined}, Q}};
+validate_tls_record_version(Versions, Q, SslOpts, Acc, Type, Version, Length) ->
+ case Versions of
+ _ when is_list(Versions) ->
+ case is_acceptable_version(Version, Versions) of
+ true ->
+ validate_tls_record_length(Versions, Q, SslOpts, Acc, Type, Version, Length);
+ false ->
+ ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
+ end;
+ {3, 4} when Version =:= {3, 3} ->
+ validate_tls_record_length(Versions, Q, SslOpts, Acc, Type, Version, Length);
+ Version ->
+ %% Exact version match
+ validate_tls_record_length(Versions, Q, SslOpts, Acc, Type, Version, Length);
+ _ ->
+ ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
+ end.
+
+validate_tls_record_length(_Versions, Q, _SslOpts, Acc, Type, Version, undefined) ->
+ {lists:reverse(Acc),
+ {#ssl_tls{type = Type, version = Version, fragment = undefined}, Q}};
+validate_tls_record_length(Versions, {_,Size0,_} = Q0, SslOpts, Acc, Type, Version, Length) ->
+ if
+ Length =< ?MAX_CIPHER_TEXT_LENGTH ->
+ if
+ Length =< Size0 ->
+ %% Complete record
+ {Fragment, Q} = binary_from_front(Length, Q0),
+ Record = #ssl_tls{type = Type, version = Version, fragment = Fragment},
+ ssl_logger:debug(SslOpts#ssl_options.log_level, inbound, 'record', Record),
+ decode_tls_records(Versions, Q, SslOpts, [Record|Acc], undefined, undefined, undefined);
+ true ->
+ {lists:reverse(Acc),
+ {#ssl_tls{type = Type, version = Version, fragment = Length}, Q0}}
+ end;
+ true ->
+ ?ALERT_REC(?FATAL, ?RECORD_OVERFLOW)
+ end.
+
+
+binary_from_front(SplitSize, {Front,Size,Rear}) ->
+ binary_from_front(SplitSize, Front, Size, Rear, []).
+%%
+binary_from_front(SplitSize, [], Size, [_] = Rear, Acc) ->
+ %% Optimize a simple case
+ binary_from_front(SplitSize, Rear, Size, [], Acc);
+binary_from_front(SplitSize, [], Size, Rear, Acc) ->
+ binary_from_front(SplitSize, lists:reverse(Rear), Size, [], Acc);
+binary_from_front(SplitSize, [Bin|Front], Size, Rear, []) ->
+ %% Optimize a frequent case
+ BinSize = byte_size(Bin),
+ if
+ SplitSize < BinSize ->
+ {RetBin, Rest} = erlang:split_binary(Bin, SplitSize),
+ {RetBin, {[Rest|Front],Size - SplitSize,Rear}};
+ BinSize < SplitSize ->
+ binary_from_front(SplitSize - BinSize, Front, Size, Rear, [Bin]);
+ true -> % Perfect fit
+ {Bin, {Front,Size - SplitSize,Rear}}
+ end;
+binary_from_front(SplitSize, [Bin|Front], Size, Rear, Acc) ->
+ BinSize = byte_size(Bin),
+ if
+ SplitSize < BinSize ->
+ {Last, Rest} = erlang:split_binary(Bin, SplitSize),
+ RetBin = iolist_to_binary(lists:reverse(Acc, [Last])),
+ {RetBin, {[Rest|Front],Size - byte_size(RetBin),Rear}};
+ BinSize < SplitSize ->
+ binary_from_front(SplitSize - BinSize, Front, Size, Rear, [Bin|Acc]);
+ true -> % Perfect fit
+ RetBin = iolist_to_binary(lists:reverse(Acc, [Bin])),
+ {RetBin, {Front,Size - byte_size(RetBin),Rear}}
+ end.
+
+%%--------------------------------------------------------------------
+encode_plain_text(Type, Version, Data, ConnectionStates0) ->
+ {[CipherText],ConnectionStates} = encode_fragments(Type, Version, [Data], ConnectionStates0),
+ {CipherText,ConnectionStates}.
+%%--------------------------------------------------------------------
+encode_fragments(Type, Version, Data,
+ #{current_write := #{compression_state := CompS,
+ cipher_state := CipherS,
+ sequence_number := Seq}} = ConnectionStates) ->
+ encode_fragments(Type, Version, Data, ConnectionStates, CompS, CipherS, Seq, []).
+%%
+encode_fragments(_Type, _Version, [], #{current_write := WriteS} = CS,
+ CompS, CipherS, Seq, CipherFragments) ->
+ {lists:reverse(CipherFragments),
+ CS#{current_write := WriteS#{compression_state := CompS,
+ cipher_state := CipherS,
+ sequence_number := Seq}}};
+encode_fragments(Type, Version, [Text|Data],
+ #{current_write := #{security_parameters :=
+ #security_parameters{cipher_type = ?AEAD,
+ bulk_cipher_algorithm = BCAlg,
+ compression_algorithm = CompAlg} = SecPars}} = CS,
+ CompS0, CipherS0, Seq, CipherFragments) ->
+ {CompText, CompS} = ssl_record:compress(CompAlg, Text, CompS0),
+ SeqBin = <<?UINT64(Seq)>>,
+ CipherS1 = ssl_record:nonce_seed(BCAlg, SeqBin, CipherS0),
+ {MajVer, MinVer} = Version,
+ VersionBin = <<?BYTE(MajVer), ?BYTE(MinVer)>>,
+ StartAdditionalData = <<SeqBin/binary, ?BYTE(Type), VersionBin/binary>>,
+ {CipherFragment,CipherS} = ssl_record:cipher_aead(Version, CompText, CipherS1, StartAdditionalData, SecPars),
+ Length = byte_size(CipherFragment),
+ CipherHeader = <<?BYTE(Type), VersionBin/binary, ?UINT16(Length)>>,
+ encode_fragments(Type, Version, Data, CS, CompS, CipherS, Seq + 1,
+ [[CipherHeader, CipherFragment] | CipherFragments]);
+encode_fragments(Type, Version, [Text|Data],
+ #{current_write := #{security_parameters :=
+ #security_parameters{compression_algorithm = CompAlg,
+ mac_algorithm = MacAlgorithm} = SecPars,
+ mac_secret := MacSecret}} = CS,
+ CompS0, CipherS0, Seq, CipherFragments) ->
+ {CompText, CompS} = ssl_record:compress(CompAlg, Text, CompS0),
+ MacHash = ssl_cipher:calc_mac_hash(Type, Version, CompText, MacAlgorithm, MacSecret, Seq),
+ {CipherFragment,CipherS} = ssl_record:cipher(Version, CompText, CipherS0, MacHash, SecPars),
+ Length = byte_size(CipherFragment),
+ {MajVer, MinVer} = Version,
+ CipherHeader = <<?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer), ?UINT16(Length)>>,
+ encode_fragments(Type, Version, Data, CS, CompS, CipherS, Seq + 1,
+ [[CipherHeader, CipherFragment] | CipherFragments]);
+encode_fragments(_Type, _Version, _Data, CS, _CompS, _CipherS, _Seq, _CipherFragments) ->
exit({cs, CS}).
%%--------------------------------------------------------------------
-calc_aad(Type, {MajVer, MinVer},
- #{sequence_number := SeqNo}) ->
- <<?UINT64(SeqNo), ?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer)>>.
%% 1/n-1 splitting countermeasure Rizzo/Duong-Beast, RC4 chiphers are
%% not vulnerable to this attack.
-split_bin(<<FirstByte:8, Rest/binary>>, ChunkSize, Version, BCA, one_n_minus_one) when
- BCA =/= ?RC4 andalso ({3, 1} == Version orelse
- {3, 0} == Version) ->
- do_split_bin(Rest, ChunkSize, [[FirstByte]]);
+split_iovec(Data, Version, BCA, one_n_minus_one)
+ when (BCA =/= ?RC4) andalso ({3, 1} == Version orelse
+ {3, 0} == Version) ->
+ {Part, RestData} = split_iovec(Data, 1, []),
+ [Part|split_iovec(RestData)];
%% 0/n splitting countermeasure for clients that are incompatible with 1/n-1
%% splitting.
-split_bin(Bin, ChunkSize, Version, BCA, zero_n) when
- BCA =/= ?RC4 andalso ({3, 1} == Version orelse
- {3, 0} == Version) ->
- do_split_bin(Bin, ChunkSize, [[<<>>]]);
-split_bin(Bin, ChunkSize, _, _, _) ->
- do_split_bin(Bin, ChunkSize, []).
-
-do_split_bin(<<>>, _, Acc) ->
- lists:reverse(Acc);
-do_split_bin(Bin, ChunkSize, Acc) ->
- case Bin of
- <<Chunk:ChunkSize/binary, Rest/binary>> ->
- do_split_bin(Rest, ChunkSize, [Chunk | Acc]);
- _ ->
- lists:reverse(Acc, [Bin])
- end.
+split_iovec(Data, Version, BCA, zero_n)
+ when (BCA =/= ?RC4) andalso ({3, 1} == Version orelse
+ {3, 0} == Version) ->
+ {Part, RestData} = split_iovec(Data, 0, []),
+ [Part|split_iovec(RestData)];
+split_iovec(Data, _Version, _BCA, _BeatMitigation) ->
+ split_iovec(Data).
+
+split_iovec([]) ->
+ [];
+split_iovec(Data) ->
+ {Part,Rest} = split_iovec(Data, ?MAX_PLAIN_TEXT_LENGTH, []),
+ [Part|split_iovec(Rest)].
+%%
+split_iovec([Bin|Data] = Bin_Data, SplitSize, Acc) ->
+ BinSize = byte_size(Bin),
+ if
+ BinSize =< SplitSize ->
+ split_iovec(Data, SplitSize - BinSize, [Bin|Acc]);
+ SplitSize == 0 ->
+ {lists:reverse(Acc), Bin_Data};
+ SplitSize < BinSize ->
+ {Last, Rest} = erlang:split_binary(Bin, SplitSize),
+ {lists:reverse(Acc, [Last]), [Rest|Data]}
+ end;
+split_iovec([], _SplitSize, Acc) ->
+ {lists:reverse(Acc),[]}.
+
%%--------------------------------------------------------------------
lowest_list_protocol_version(Ver, []) ->
Ver;
diff --git a/lib/ssl/src/tls_record_1_3.erl b/lib/ssl/src/tls_record_1_3.erl
new file mode 100644
index 0000000000..74321a1ae2
--- /dev/null
+++ b/lib/ssl/src/tls_record_1_3.erl
@@ -0,0 +1,311 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+
+-module(tls_record_1_3).
+
+-include("tls_record.hrl").
+-include("tls_record_1_3.hrl").
+-include("ssl_internal.hrl").
+-include("ssl_alert.hrl").
+-include("ssl_cipher.hrl").
+
+%% Encoding
+-export([encode_handshake/2, encode_alert_record/2,
+ encode_data/2]).
+-export([encode_plain_text/3]).
+
+%% Decoding
+-export([decode_cipher_text/2]).
+
+%%====================================================================
+%% Encoding
+%%====================================================================
+
+%%--------------------------------------------------------------------
+-spec encode_handshake(iolist(), ssl_record:connection_states()) ->
+ {iolist(), ssl_record:connection_states()}.
+%
+%% Description: Encodes a handshake message to send on the tls-1.3-socket.
+%%--------------------------------------------------------------------
+encode_handshake(Frag, ConnectionStates) ->
+ case iolist_size(Frag) of
+ N when N > ?MAX_PLAIN_TEXT_LENGTH ->
+ %% TODO: Consider padding here
+ Data = split_bin(iolist_to_binary(Frag), ?MAX_PLAIN_TEXT_LENGTH),
+ encode_iolist(?HANDSHAKE, Data, ConnectionStates);
+ _ ->
+ encode_plain_text(?HANDSHAKE, Frag, ConnectionStates)
+ end.
+
+%%--------------------------------------------------------------------
+-spec encode_alert_record(#alert{}, ssl_record:connection_states()) ->
+ {iolist(), ssl_record:connection_states()}.
+%%
+%% Description: Encodes an alert message to send on the ssl-socket.
+%%--------------------------------------------------------------------
+encode_alert_record(#alert{level = Level, description = Description},
+ ConnectionStates) ->
+ encode_plain_text(?ALERT, <<?BYTE(Level), ?BYTE(Description)>>,
+ ConnectionStates).
+%%--------------------------------------------------------------------
+-spec encode_data(binary(), ssl_record:connection_states()) ->
+ {iolist(), ssl_record:connection_states()}.
+%%
+%% Description: Encodes data to send on the ssl-socket.
+%%--------------------------------------------------------------------
+encode_data(Frag, ConnectionStates) ->
+ Data = split_bin(Frag, ?MAX_PLAIN_TEXT_LENGTH, {3,4}),
+ encode_iolist(?APPLICATION_DATA, Data, ConnectionStates).
+
+encode_plain_text(Type, Data0, #{current_write := Write0} = ConnectionStates) ->
+ PadLen = 0, %% TODO where to specify PadLen?
+ Data = inner_plaintext(Type, Data0, PadLen),
+ CipherFragment = encode_plain_text(Data, Write0),
+ {CipherText, Write} = encode_tls_cipher_text(CipherFragment, Write0),
+ {CipherText, ConnectionStates#{current_write => Write}}.
+
+encode_iolist(Type, Data, ConnectionStates0) ->
+ {ConnectionStates, EncodedMsg} =
+ lists:foldl(fun(Text, {CS0, Encoded}) ->
+ {Enc, CS1} =
+ encode_plain_text(Type, Text, CS0),
+ {CS1, [Enc | Encoded]}
+ end, {ConnectionStates0, []}, Data),
+ {lists:reverse(EncodedMsg), ConnectionStates}.
+
+%%====================================================================
+%% Decoding
+%%====================================================================
+
+%%--------------------------------------------------------------------
+-spec decode_cipher_text(#ssl_tls{}, ssl_record:connection_states()) ->
+ {#ssl_tls{}, ssl_record:connection_states()}| #alert{}.
+%%
+%% Description: Decode cipher text, use legacy type ssl_tls instead of tls_cipher_text
+%% in decoding context so that we can reuse the code from erlier versions.
+%%--------------------------------------------------------------------
+decode_cipher_text(#ssl_tls{type = ?OPAQUE_TYPE,
+ version = ?LEGACY_VERSION,
+ fragment = CipherFragment},
+ #{current_read :=
+ #{sequence_number := Seq,
+ cipher_state := #cipher_state{key = Key,
+ iv = IV,
+ tag_len = TagLen},
+ security_parameters :=
+ #security_parameters{
+ cipher_type = ?AEAD,
+ bulk_cipher_algorithm =
+ BulkCipherAlgo}
+ } = ReadState0} = ConnectionStates0) ->
+ case decipher_aead(CipherFragment, BulkCipherAlgo, Key, Seq, IV, TagLen) of
+ #alert{} = Alert ->
+ Alert;
+ PlainFragment ->
+ ConnectionStates =
+ ConnectionStates0#{current_read =>
+ ReadState0#{sequence_number => Seq + 1}},
+ {decode_inner_plaintext(PlainFragment), ConnectionStates}
+ end;
+
+
+%% RFC8446 - TLS 1.3 (OpenSSL compatibility)
+%% Handle unencrypted Alerts from openssl s_client when server's
+%% connection states are already stepped into traffic encryption.
+%% (E.g. openssl s_client receives a CertificateRequest with
+%% a signature_algorithms_cert extension that does not contain
+%% the signature algorithm of the client's certificate.)
+decode_cipher_text(#ssl_tls{type = ?ALERT,
+ version = ?LEGACY_VERSION,
+ fragment = <<2,47>>},
+ ConnectionStates0) ->
+ {#ssl_tls{type = ?ALERT,
+ version = {3,4}, %% Internally use real version
+ fragment = <<2,47>>}, ConnectionStates0};
+%% RFC8446 - TLS 1.3
+%% D.4. Middlebox Compatibility Mode
+%% - If not offering early data, the client sends a dummy
+%% change_cipher_spec record (see the third paragraph of Section 5)
+%% immediately before its second flight. This may either be before
+%% its second ClientHello or before its encrypted handshake flight.
+%% If offering early data, the record is placed immediately after the
+%% first ClientHello.
+decode_cipher_text(#ssl_tls{type = ?CHANGE_CIPHER_SPEC,
+ version = ?LEGACY_VERSION,
+ fragment = <<1>>},
+ ConnectionStates0) ->
+ {#ssl_tls{type = ?CHANGE_CIPHER_SPEC,
+ version = {3,4}, %% Internally use real version
+ fragment = <<1>>}, ConnectionStates0};
+decode_cipher_text(#ssl_tls{type = Type,
+ version = ?LEGACY_VERSION,
+ fragment = CipherFragment},
+ #{current_read :=
+ #{security_parameters :=
+ #security_parameters{
+ cipher_suite = ?TLS_NULL_WITH_NULL_NULL}
+ }} = ConnnectionStates0) ->
+ {#ssl_tls{type = Type,
+ version = {3,4}, %% Internally use real version
+ fragment = CipherFragment}, ConnnectionStates0};
+decode_cipher_text(#ssl_tls{type = Type}, _) ->
+ %% Version mismatch is already asserted
+ ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC, {record_type_mismatch, Type}).
+
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
+split_bin(Bin, ChunkSize) ->
+ split_bin(Bin, ChunkSize, []).
+split_bin(Bin, ChunkSize, _) ->
+ do_split_bin(Bin, ChunkSize, []).
+
+do_split_bin(<<>>, _, Acc) ->
+ lists:reverse(Acc);
+do_split_bin(Bin, ChunkSize, Acc) ->
+ case Bin of
+ <<Chunk:ChunkSize/binary, Rest/binary>> ->
+ do_split_bin(Rest, ChunkSize, [Chunk | Acc]);
+ _ ->
+ lists:reverse(Acc, [Bin])
+ end.
+
+inner_plaintext(Type, Data, Length) ->
+ #inner_plaintext{
+ content = Data,
+ type = Type,
+ zeros = zero_padding(Length)
+ }.
+zero_padding(Length)->
+ binary:copy(<<?BYTE(0)>>, Length).
+
+encode_plain_text(#inner_plaintext{
+ content = Data,
+ type = Type,
+ zeros = Zeros
+ }, #{cipher_state := #cipher_state{key= Key,
+ iv = IV,
+ tag_len = TagLen},
+ sequence_number := Seq,
+ security_parameters :=
+ #security_parameters{
+ cipher_type = ?AEAD,
+ bulk_cipher_algorithm = BulkCipherAlgo}
+ }) ->
+ PlainText = [Data, Type, Zeros],
+ Encoded = cipher_aead(PlainText, BulkCipherAlgo, Key, Seq, IV, TagLen),
+ #tls_cipher_text{opaque_type = 23, %% 23 (application_data) for outward compatibility
+ legacy_version = {3,3},
+ encoded_record = Encoded};
+encode_plain_text(#inner_plaintext{
+ content = Data,
+ type = Type
+ }, #{security_parameters :=
+ #security_parameters{
+ cipher_suite = ?TLS_NULL_WITH_NULL_NULL}
+ }) ->
+ %% RFC8446 - 5.1. Record Layer
+ %% When record protection has not yet been engaged, TLSPlaintext
+ %% structures are written directly onto the wire.
+ #tls_cipher_text{opaque_type = Type,
+ legacy_version = {3,3},
+ encoded_record = Data};
+
+encode_plain_text(_, CS) ->
+ exit({cs, CS}).
+
+additional_data(Length) ->
+ <<?BYTE(?OPAQUE_TYPE), ?BYTE(3), ?BYTE(3),?UINT16(Length)>>.
+
+%% The per-record nonce for the AEAD construction is formed as
+%% follows:
+%%
+%% 1. The 64-bit record sequence number is encoded in network byte
+%% order and padded to the left with zeros to iv_length.
+%%
+%% 2. The padded sequence number is XORed with either the static
+%% client_write_iv or server_write_iv (depending on the role).
+%%
+%% The resulting quantity (of length iv_length) is used as the
+%% per-record nonce.
+nonce(Seq, IV) ->
+ Padding = binary:copy(<<0>>, byte_size(IV) - 8),
+ crypto:exor(<<Padding/binary,?UINT64(Seq)>>, IV).
+
+cipher_aead(Fragment, BulkCipherAlgo, Key, Seq, IV, TagLen) ->
+ AAD = additional_data(erlang:iolist_size(Fragment) + TagLen),
+ Nonce = nonce(Seq, IV),
+ {Content, CipherTag} =
+ ssl_cipher:aead_encrypt(BulkCipherAlgo, Key, Nonce, Fragment, AAD, TagLen),
+ <<Content/binary, CipherTag/binary>>.
+
+encode_tls_cipher_text(#tls_cipher_text{opaque_type = Type,
+ legacy_version = {MajVer, MinVer},
+ encoded_record = Encoded}, #{sequence_number := Seq} = Write) ->
+ Length = erlang:iolist_size(Encoded),
+ {[<<?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer), ?UINT16(Length)>>, Encoded],
+ Write#{sequence_number => Seq +1}}.
+
+decipher_aead(CipherFragment, BulkCipherAlgo, Key, Seq, IV, TagLen) ->
+ try
+ AAD = additional_data(erlang:iolist_size(CipherFragment)),
+ Nonce = nonce(Seq, IV),
+ {CipherText, CipherTag} = aead_ciphertext_split(CipherFragment, TagLen),
+ case ssl_cipher:aead_decrypt(BulkCipherAlgo, Key, Nonce, CipherText, CipherTag, AAD) of
+ Content when is_binary(Content) ->
+ Content;
+ _ ->
+ ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC, decryption_failed)
+ end
+ catch
+ _:_ ->
+ ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC, decryption_failed)
+ end.
+
+
+aead_ciphertext_split(CipherTextFragment, TagLen)
+ when is_binary(CipherTextFragment) ->
+ CipherLen = erlang:byte_size(CipherTextFragment) - TagLen,
+ <<CipherText:CipherLen/bytes, CipherTag:TagLen/bytes>> = CipherTextFragment,
+ {CipherText, CipherTag};
+aead_ciphertext_split(CipherTextFragment, TagLen)
+ when is_list(CipherTextFragment) ->
+ CipherLen = erlang:iolist_size(CipherTextFragment) - TagLen,
+ <<CipherText:CipherLen/bytes, CipherTag:TagLen/bytes>> =
+ erlang:iolist_to_binary(CipherTextFragment),
+ {CipherText, CipherTag}.
+
+decode_inner_plaintext(PlainText) ->
+ case binary:last(PlainText) of
+ 0 ->
+ decode_inner_plaintext(init_binary(PlainText));
+ Type when Type =:= ?APPLICATION_DATA orelse
+ Type =:= ?HANDSHAKE orelse
+ Type =:= ?ALERT ->
+ #ssl_tls{type = Type,
+ version = {3,4}, %% Internally use real version
+ fragment = init_binary(PlainText)};
+ _Else ->
+ ?ALERT_REC(?FATAL, ?UNEXPECTED_MESSAGE, empty_alert)
+ end.
+
+init_binary(B) ->
+ {Init, _} =
+ split_binary(B, byte_size(B) - 1),
+ Init.
diff --git a/lib/ssl/src/tls_record_1_3.hrl b/lib/ssl/src/tls_record_1_3.hrl
new file mode 100644
index 0000000000..273427a34e
--- /dev/null
+++ b/lib/ssl/src/tls_record_1_3.hrl
@@ -0,0 +1,58 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Record and constant defenitions for the TLS-1.3-record protocol
+%% see RFC 8446 not present in earlier versions
+%%----------------------------------------------------------------------
+
+-ifndef(tls_record_1_3).
+-define(tls_record_1_3, true).
+
+%% enum {
+%% invalid(0),
+%% %% defined in ssl_record.hrl
+%% change_cipher_spec(20),
+%% alert(21),
+%% handshake(22),
+%% application_data(23),
+%% heartbeat(24), /* RFC 6520 */
+%% (255)
+%% } ContentType;
+
+-define(INVALID, 0).
+-define(LEGACY_VERSION, {3,3}).
+-define(OPAQUE_TYPE, 23).
+
+-record(inner_plaintext, {
+ content, %% data
+ type, %% Contentype
+ zeros %% padding "uint8 zeros[length_of_padding]"
+ }).
+-record(tls_cipher_text, { %% Equivalent of encrypted version of #ssl_tls from previous versions
+ %% decrypted version will still use #ssl_tls for code reuse purposes
+ %% with real values for content type and version
+ opaque_type = ?OPAQUE_TYPE,
+ legacy_version = ?LEGACY_VERSION,
+ encoded_record
+ }).
+
+-endif. % -ifdef(tls_record_1_3).
diff --git a/lib/ssl/src/tls_sender.erl b/lib/ssl/src/tls_sender.erl
new file mode 100644
index 0000000000..d0604565e3
--- /dev/null
+++ b/lib/ssl/src/tls_sender.erl
@@ -0,0 +1,524 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(tls_sender).
+
+-behaviour(gen_statem).
+
+-include("ssl_internal.hrl").
+-include("ssl_alert.hrl").
+-include("ssl_handshake.hrl").
+-include("ssl_api.hrl").
+
+%% API
+-export([start/0, start/1, initialize/2, send_data/2, send_alert/2,
+ send_and_ack_alert/2, setopts/2, renegotiate/1, peer_renegotiate/1, downgrade/2,
+ update_connection_state/3, dist_tls_socket/1, dist_handshake_complete/3]).
+
+%% gen_statem callbacks
+-export([callback_mode/0, init/1, terminate/3, code_change/4]).
+-export([init/3, connection/3, handshake/3, death_row/3]).
+
+-define(SERVER, ?MODULE).
+
+-record(static,
+ {connection_pid,
+ role,
+ socket,
+ socket_options,
+ tracker,
+ transport_cb,
+ negotiated_version,
+ renegotiate_at,
+ connection_monitor,
+ dist_handle,
+ log_level
+ }).
+
+-record(data,
+ {static = #static{},
+ connection_states = #{}
+ }).
+
+%%%===================================================================
+%%% API
+%%%===================================================================
+%%--------------------------------------------------------------------
+-spec start() -> {ok, Pid :: pid()} |
+ ignore |
+ {error, Error :: term()}.
+-spec start(list()) -> {ok, Pid :: pid()} |
+ ignore |
+ {error, Error :: term()}.
+
+%% Description: Start sender process to avoid dead lock that
+%% may happen when a socket is busy (busy port) and the
+%% same process is sending and receiving
+%%--------------------------------------------------------------------
+start() ->
+ gen_statem:start(?MODULE, [], []).
+start(SpawnOpts) ->
+ gen_statem:start(?MODULE, [], SpawnOpts).
+
+%%--------------------------------------------------------------------
+-spec initialize(pid(), map()) -> ok.
+%% Description: So TLS connection process can initialize it sender
+%% process.
+%%--------------------------------------------------------------------
+initialize(Pid, InitMsg) ->
+ gen_statem:call(Pid, {self(), InitMsg}).
+
+%%--------------------------------------------------------------------
+-spec send_data(pid(), iodata()) -> ok | {error, term()}.
+%% Description: Send application data
+%%--------------------------------------------------------------------
+send_data(Pid, AppData) ->
+ %% Needs error handling for external API
+ call(Pid, {application_data, AppData}).
+
+%%--------------------------------------------------------------------
+-spec send_alert(pid(), #alert{}) -> _.
+%% Description: TLS connection process wants to send an Alert
+%% in the connection state.
+%%--------------------------------------------------------------------
+send_alert(Pid, Alert) ->
+ gen_statem:cast(Pid, Alert).
+
+%%--------------------------------------------------------------------
+-spec send_and_ack_alert(pid(), #alert{}) -> _.
+%% Description: TLS connection process wants to send an Alert
+%% in the connection state and recive an ack.
+%%--------------------------------------------------------------------
+send_and_ack_alert(Pid, Alert) ->
+ gen_statem:call(Pid, {ack_alert, Alert}, ?DEFAULT_TIMEOUT).
+%%--------------------------------------------------------------------
+-spec setopts(pid(), [{packet, integer() | atom()}]) -> ok | {error, term()}.
+%% Description: Send application data
+%%--------------------------------------------------------------------
+setopts(Pid, Opts) ->
+ call(Pid, {set_opts, Opts}).
+
+%%--------------------------------------------------------------------
+-spec renegotiate(pid()) -> {ok, WriteState::map()} | {error, closed}.
+%% Description: So TLS connection process can synchronize the
+%% encryption state to be used when handshaking.
+%%--------------------------------------------------------------------
+renegotiate(Pid) ->
+ %% Needs error handling for external API
+ call(Pid, renegotiate).
+
+%%--------------------------------------------------------------------
+-spec peer_renegotiate(pid()) -> {ok, WriteState::map()} | {error, term()}.
+%% Description: So TLS connection process can synchronize the
+%% encryption state to be used when handshaking.
+%%--------------------------------------------------------------------
+peer_renegotiate(Pid) ->
+ gen_statem:call(Pid, renegotiate, ?DEFAULT_TIMEOUT).
+
+%%--------------------------------------------------------------------
+-spec update_connection_state(pid(), WriteState::map(), tls_record:tls_version()) -> ok.
+%% Description: So TLS connection process can synchronize the
+%% encryption state to be used when sending application data.
+%%--------------------------------------------------------------------
+update_connection_state(Pid, NewState, Version) ->
+ gen_statem:cast(Pid, {new_write, NewState, Version}).
+
+%%--------------------------------------------------------------------
+-spec downgrade(pid(), integer()) -> {ok, ssl_record:connection_state()}
+ | {error, timeout}.
+%% Description: So TLS connection process can synchronize the
+%% encryption state to be used when sending application data.
+%%--------------------------------------------------------------------
+downgrade(Pid, Timeout) ->
+ try gen_statem:call(Pid, downgrade, Timeout) of
+ Result ->
+ Result
+ catch
+ _:_ ->
+ {error, timeout}
+ end.
+%%--------------------------------------------------------------------
+-spec dist_handshake_complete(pid(), node(), term()) -> ok.
+%% Description: Erlang distribution callback
+%%--------------------------------------------------------------------
+dist_handshake_complete(ConnectionPid, Node, DHandle) ->
+ gen_statem:call(ConnectionPid, {dist_handshake_complete, Node, DHandle}).
+%%--------------------------------------------------------------------
+-spec dist_tls_socket(pid()) -> {ok, #sslsocket{}}.
+%% Description: To enable distribution startup to get a proper "#sslsocket{}"
+%%--------------------------------------------------------------------
+dist_tls_socket(Pid) ->
+ gen_statem:call(Pid, dist_get_tls_socket).
+
+%%%===================================================================
+%%% gen_statem callbacks
+%%%===================================================================
+%%--------------------------------------------------------------------
+-spec callback_mode() -> gen_statem:callback_mode_result().
+%%--------------------------------------------------------------------
+callback_mode() ->
+ state_functions.
+
+
+-define(HANDLE_COMMON,
+ ?FUNCTION_NAME(Type, Msg, StateData) ->
+ handle_common(Type, Msg, StateData)).
+%%--------------------------------------------------------------------
+-spec init(Args :: term()) ->
+ gen_statem:init_result(atom()).
+%%--------------------------------------------------------------------
+init(_) ->
+ %% Note: Should not trap exits so that this process
+ %% will be terminated if tls_connection process is
+ %% killed brutally
+ {ok, init, #data{}}.
+
+%%--------------------------------------------------------------------
+-spec init(gen_statem:event_type(),
+ Msg :: term(),
+ StateData :: term()) ->
+ gen_statem:event_handler_result(atom()).
+%%--------------------------------------------------------------------
+init({call, From}, {Pid, #{current_write := WriteState,
+ role := Role,
+ socket := Socket,
+ socket_options := SockOpts,
+ tracker := Tracker,
+ transport_cb := Transport,
+ negotiated_version := Version,
+ renegotiate_at := RenegotiateAt,
+ log_level := LogLevel}},
+ #data{connection_states = ConnectionStates, static = Static0} = StateData0) ->
+ Monitor = erlang:monitor(process, Pid),
+ StateData =
+ StateData0#data{connection_states = ConnectionStates#{current_write => WriteState},
+ static = Static0#static{connection_pid = Pid,
+ connection_monitor = Monitor,
+ role = Role,
+ socket = Socket,
+ socket_options = SockOpts,
+ tracker = Tracker,
+ transport_cb = Transport,
+ negotiated_version = Version,
+ renegotiate_at = RenegotiateAt,
+ log_level = LogLevel}},
+ {next_state, handshake, StateData, [{reply, From, ok}]};
+init(_, _, _) ->
+ %% Just in case anything else sneeks through
+ {keep_state_and_data, [postpone]}.
+
+%%--------------------------------------------------------------------
+-spec connection(gen_statem:event_type(),
+ Msg :: term(),
+ StateData :: term()) ->
+ gen_statem:event_handler_result(atom()).
+%%--------------------------------------------------------------------
+connection({call, From}, {application_data, AppData},
+ #data{static = #static{socket_options = #socket_options{packet = Packet}}} =
+ StateData) ->
+ case encode_packet(Packet, AppData) of
+ {error, _} = Error ->
+ {next_state, ?FUNCTION_NAME, StateData, [{reply, From, Error}]};
+ Data ->
+ send_application_data(Data, From, ?FUNCTION_NAME, StateData)
+ end;
+connection({call, From}, {ack_alert, #alert{} = Alert}, StateData0) ->
+ StateData = send_tls_alert(Alert, StateData0),
+ {next_state, ?FUNCTION_NAME, StateData,
+ [{reply,From,ok}]};
+connection({call, From}, renegotiate,
+ #data{connection_states = #{current_write := Write}} = StateData) ->
+ {next_state, handshake, StateData, [{reply, From, {ok, Write}}]};
+connection({call, From}, downgrade, #data{connection_states =
+ #{current_write := Write}} = StateData) ->
+ {next_state, death_row, StateData, [{reply,From, {ok, Write}}]};
+connection({call, From}, {set_opts, Opts}, StateData) ->
+ handle_set_opts(From, Opts, StateData);
+connection({call, From}, dist_get_tls_socket,
+ #data{static = #static{transport_cb = Transport,
+ socket = Socket,
+ connection_pid = Pid,
+ tracker = Tracker}} = StateData) ->
+ TLSSocket = tls_connection:socket([Pid, self()], Transport, Socket, Tracker),
+ {next_state, ?FUNCTION_NAME, StateData, [{reply, From, {ok, TLSSocket}}]};
+connection({call, From}, {dist_handshake_complete, _Node, DHandle},
+ #data{static = #static{connection_pid = Pid} = Static} = StateData) ->
+ ok = erlang:dist_ctrl_input_handler(DHandle, Pid),
+ ok = ssl_connection:dist_handshake_complete(Pid, DHandle),
+ %% From now on we execute on normal priority
+ process_flag(priority, normal),
+ {keep_state, StateData#data{static = Static#static{dist_handle = DHandle}},
+ [{reply,From,ok}|
+ case dist_data(DHandle) of
+ [] ->
+ [];
+ Data ->
+ [{next_event, internal,
+ {application_packets,{self(),undefined},erlang:iolist_to_iovec(Data)}}]
+ end]};
+connection(internal, {application_packets, From, Data}, StateData) ->
+ send_application_data(Data, From, ?FUNCTION_NAME, StateData);
+%%
+connection(cast, #alert{} = Alert, StateData0) ->
+ StateData = send_tls_alert(Alert, StateData0),
+ {next_state, ?FUNCTION_NAME, StateData};
+connection(cast, {new_write, WritesState, Version},
+ #data{connection_states = ConnectionStates, static = Static} = StateData) ->
+ {next_state, connection,
+ StateData#data{connection_states =
+ ConnectionStates#{current_write => WritesState},
+ static = Static#static{negotiated_version = Version}}};
+%%
+connection(info, dist_data, #data{static = #static{dist_handle = DHandle}}) ->
+ {keep_state_and_data,
+ case dist_data(DHandle) of
+ [] ->
+ [];
+ Data ->
+ [{next_event, internal,
+ {application_packets,{self(),undefined},erlang:iolist_to_iovec(Data)}}]
+ end};
+connection(info, tick, StateData) ->
+ consume_ticks(),
+ Data = [<<0:32>>], % encode_packet(4, <<>>)
+ From = {self(), undefined},
+ send_application_data(Data, From, ?FUNCTION_NAME, StateData);
+connection(info, {send, From, Ref, Data}, _StateData) ->
+ %% This is for testing only!
+ %%
+ %% Needed by some OTP distribution
+ %% test suites...
+ From ! {Ref, ok},
+ {keep_state_and_data,
+ [{next_event, {call, {self(), undefined}},
+ {application_data, erlang:iolist_to_iovec(Data)}}]};
+?HANDLE_COMMON.
+
+%%--------------------------------------------------------------------
+-spec handshake(gen_statem:event_type(),
+ Msg :: term(),
+ StateData :: term()) ->
+ gen_statem:event_handler_result(atom()).
+%%--------------------------------------------------------------------
+handshake({call, From}, {set_opts, Opts}, StateData) ->
+ handle_set_opts(From, Opts, StateData);
+handshake({call, _}, _, _) ->
+ %% Postpone all calls to the connection state
+ {keep_state_and_data, [postpone]};
+handshake(internal, {application_packets,_,_}, _) ->
+ {keep_state_and_data, [postpone]};
+handshake(cast, {new_write, WritesState, Version},
+ #data{connection_states = ConnectionStates, static = Static} = StateData) ->
+ {next_state, connection,
+ StateData#data{connection_states = ConnectionStates#{current_write => WritesState},
+ static = Static#static{negotiated_version = Version}}};
+handshake(info, dist_data, _) ->
+ {keep_state_and_data, [postpone]};
+handshake(info, tick, _) ->
+ %% Ignore - data is sent anyway during handshake
+ consume_ticks(),
+ keep_state_and_data;
+handshake(info, {send, _, _, _}, _) ->
+ %% Testing only, OTP distribution test suites...
+ {keep_state_and_data, [postpone]};
+?HANDLE_COMMON.
+
+%%--------------------------------------------------------------------
+-spec death_row(gen_statem:event_type(),
+ Msg :: term(),
+ StateData :: term()) ->
+ gen_statem:event_handler_result(atom()).
+%%--------------------------------------------------------------------
+death_row(state_timeout, Reason, _State) ->
+ {stop, {shutdown, Reason}};
+death_row(_Type, _Msg, _State) ->
+ %% Waste all other events
+ keep_state_and_data.
+
+%%--------------------------------------------------------------------
+-spec terminate(Reason :: term(), State :: term(), Data :: term()) ->
+ any().
+%%--------------------------------------------------------------------
+terminate(_Reason, _State, _Data) ->
+ void.
+
+%%--------------------------------------------------------------------
+-spec code_change(
+ OldVsn :: term() | {down,term()},
+ State :: term(), Data :: term(), Extra :: term()) ->
+ {ok, NewState :: term(), NewData :: term()} |
+ (Reason :: term()).
+%% Convert process state when code is changed
+%%--------------------------------------------------------------------
+code_change(_OldVsn, State, Data, _Extra) ->
+ {ok, State, Data}.
+
+%%%===================================================================
+%%% Internal functions
+%%%===================================================================
+
+handle_set_opts(
+ From, Opts, #data{static = #static{socket_options = SockOpts} = Static} = StateData) ->
+ {keep_state, StateData#data{static = Static#static{socket_options = set_opts(SockOpts, Opts)}},
+ [{reply, From, ok}]}.
+
+handle_common(
+ {call, From}, {set_opts, Opts},
+ #data{static = #static{socket_options = SockOpts} = Static} = StateData) ->
+ {keep_state, StateData#data{static = Static#static{socket_options = set_opts(SockOpts, Opts)}},
+ [{reply, From, ok}]};
+handle_common(
+ info, {'DOWN', Monitor, _, _, Reason},
+ #data{static = #static{connection_monitor = Monitor,
+ dist_handle = Handle}} = StateData) when Handle =/= undefined ->
+ {next_state, death_row, StateData,
+ [{state_timeout, 5000, Reason}]};
+handle_common(
+ info, {'DOWN', Monitor, _, _, _},
+ #data{static = #static{connection_monitor = Monitor}} = StateData) ->
+ {stop, normal, StateData};
+handle_common(info, Msg, _) ->
+ Report =
+ io_lib:format("TLS sender: Got unexpected info: ~p ~n", [Msg]),
+ error_logger:info_report(Report),
+ keep_state_and_data;
+handle_common(Type, Msg, _) ->
+ Report =
+ io_lib:format(
+ "TLS sender: Got unexpected event: ~p ~n", [{Type,Msg}]),
+ error_logger:error_report(Report),
+ keep_state_and_data.
+
+send_tls_alert(#alert{} = Alert,
+ #data{static = #static{negotiated_version = Version,
+ socket = Socket,
+ transport_cb = Transport,
+ log_level = LogLevel},
+ connection_states = ConnectionStates0} = StateData0) ->
+ {BinMsg, ConnectionStates} =
+ tls_record:encode_alert_record(Alert, Version, ConnectionStates0),
+ tls_socket:send(Transport, Socket, BinMsg),
+ ssl_logger:debug(LogLevel, outbound, 'record', BinMsg),
+ StateData0#data{connection_states = ConnectionStates}.
+
+send_application_data(Data, From, StateName,
+ #data{static = #static{connection_pid = Pid,
+ socket = Socket,
+ dist_handle = DistHandle,
+ negotiated_version = Version,
+ transport_cb = Transport,
+ renegotiate_at = RenegotiateAt,
+ log_level = LogLevel},
+ connection_states = ConnectionStates0} = StateData0) ->
+ case time_to_renegotiate(Data, ConnectionStates0, RenegotiateAt) of
+ true ->
+ ssl_connection:internal_renegotiation(Pid, ConnectionStates0),
+ {next_state, handshake, StateData0,
+ [{next_event, internal, {application_packets, From, Data}}]};
+ false ->
+ {Msgs, ConnectionStates} = tls_record:encode_data(Data, Version, ConnectionStates0),
+ StateData = StateData0#data{connection_states = ConnectionStates},
+ case tls_socket:send(Transport, Socket, Msgs) of
+ ok when DistHandle =/= undefined ->
+ ssl_logger:debug(LogLevel, outbound, 'record', Msgs),
+ {next_state, StateName, StateData, []};
+ Reason when DistHandle =/= undefined ->
+ {next_state, death_row, StateData, [{state_timeout, 5000, Reason}]};
+ ok ->
+ ssl_logger:debug(LogLevel, outbound, 'record', Msgs),
+ {next_state, StateName, StateData, [{reply, From, ok}]};
+ Result ->
+ {next_state, StateName, StateData, [{reply, From, Result}]}
+ end
+ end.
+
+-compile({inline, encode_packet/2}).
+encode_packet(Packet, Data) ->
+ Len = iolist_size(Data),
+ case Packet of
+ 1 when Len < (1 bsl 8) -> [<<Len:8>>|Data];
+ 2 when Len < (1 bsl 16) -> [<<Len:16>>|Data];
+ 4 when Len < (1 bsl 32) -> [<<Len:32>>|Data];
+ N when N =:= 1; N =:= 2; N =:= 4 ->
+ {error,
+ {badarg, {packet_to_large, Len, (1 bsl (Packet bsl 3)) - 1}}};
+ _ ->
+ Data
+ end.
+
+set_opts(SocketOptions, [{packet, N}]) ->
+ SocketOptions#socket_options{packet = N}.
+
+time_to_renegotiate(_Data,
+ #{current_write := #{sequence_number := Num}},
+ RenegotiateAt) ->
+
+ %% We could do test:
+ %% is_time_to_renegotiate((erlang:byte_size(_Data) div
+ %% ?MAX_PLAIN_TEXT_LENGTH) + 1, RenegotiateAt), but we chose to
+ %% have a some what lower renegotiateAt and a much cheaper test
+ is_time_to_renegotiate(Num, RenegotiateAt).
+
+is_time_to_renegotiate(N, M) when N < M->
+ false;
+is_time_to_renegotiate(_,_) ->
+ true.
+
+call(FsmPid, Event) ->
+ try gen_statem:call(FsmPid, Event)
+ catch
+ exit:{noproc, _} ->
+ {error, closed};
+ exit:{normal, _} ->
+ {error, closed};
+ exit:{{shutdown, _},_} ->
+ {error, closed}
+ end.
+
+%%-------------- Erlang distribution helpers ------------------------------
+
+dist_data(DHandle) ->
+ case erlang:dist_ctrl_get_data(DHandle) of
+ none ->
+ erlang:dist_ctrl_get_data_notification(DHandle),
+ [];
+ %% This is encode_packet(4, Data) without Len check
+ %% since the emulator will always deliver a Data
+ %% smaller than 4 GB, and the distribution will
+ %% therefore always have to use {packet,4}
+ Data when is_binary(Data) ->
+ Len = byte_size(Data),
+ [[<<Len:32>>,Data]|dist_data(DHandle)];
+ [BA,BB] = Data ->
+ Len = byte_size(BA) + byte_size(BB),
+ [[<<Len:32>>|Data]|dist_data(DHandle)];
+ Data when is_list(Data) ->
+ Len = iolist_size(Data),
+ [[<<Len:32>>|Data]|dist_data(DHandle)]
+ end.
+
+
+%% Empty the inbox from distribution ticks - do not let them accumulate
+consume_ticks() ->
+ receive tick ->
+ consume_ticks()
+ after 0 ->
+ ok
+ end.
diff --git a/lib/ssl/src/tls_socket.erl b/lib/ssl/src/tls_socket.erl
index 453a908401..6c32e6fa04 100644
--- a/lib/ssl/src/tls_socket.erl
+++ b/lib/ssl/src/tls_socket.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,6 +32,7 @@
emulated_socket_options/2, get_emulated_opts/1,
set_emulated_opts/2, get_all_opts/1, handle_call/3, handle_cast/2,
handle_info/2, code_change/3]).
+-export([update_active_n/2]).
-record(state, {
emulated_opts,
@@ -45,18 +46,20 @@
send(Transport, Socket, Data) ->
Transport:send(Socket, Data).
-listen(Transport, Port, #config{transport_info = {Transport, _, _, _},
+listen(Transport, Port, #config{transport_info = {Transport, _, _, _, _},
inet_user = Options,
ssl = SslOpts, emulated = EmOpts} = Config) ->
case Transport:listen(Port, Options ++ internal_inet_values()) of
{ok, ListenSocket} ->
{ok, Tracker} = inherit_tracker(ListenSocket, EmOpts, SslOpts),
- {ok, #sslsocket{pid = {ListenSocket, Config#config{emulated = Tracker}}}};
+ Socket = #sslsocket{pid = {ListenSocket, Config#config{emulated = Tracker}}},
+ check_active_n(EmOpts, Socket),
+ {ok, Socket};
Err = {error, _} ->
Err
end.
-accept(ListenSocket, #config{transport_info = {Transport,_,_,_} = CbInfo,
+accept(ListenSocket, #config{transport_info = {Transport,_,_,_,_} = CbInfo,
connection_cb = ConnectionCb,
ssl = SslOpts,
emulated = Tracker}, Timeout) ->
@@ -64,11 +67,12 @@ accept(ListenSocket, #config{transport_info = {Transport,_,_,_} = CbInfo,
{ok, Socket} ->
{ok, EmOpts} = get_emulated_opts(Tracker),
{ok, Port} = tls_socket:port(Transport, Socket),
- ConnArgs = [server, "localhost", Port, Socket,
+ {ok, Sender} = tls_sender:start(),
+ ConnArgs = [server, Sender, "localhost", Port, Socket,
{SslOpts, emulated_socket_options(EmOpts, #socket_options{}), Tracker}, self(), CbInfo],
case tls_connection_sup:start_child(ConnArgs) of
{ok, Pid} ->
- ssl_connection:socket_control(ConnectionCb, Socket, Pid, Transport, Tracker);
+ ssl_connection:socket_control(ConnectionCb, Socket, [Pid, Sender], Transport, Tracker);
{error, Reason} ->
{error, Reason}
end;
@@ -76,7 +80,7 @@ accept(ListenSocket, #config{transport_info = {Transport,_,_,_} = CbInfo,
{error, Reason}
end.
-upgrade(Socket, #config{transport_info = {Transport,_,_,_}= CbInfo,
+upgrade(Socket, #config{transport_info = {Transport,_,_,_,_}= CbInfo,
ssl = SslOptions,
emulated = EmOpts, connection_cb = ConnectionCb}, Timeout) ->
ok = setopts(Transport, Socket, tls_socket:internal_inet_values()),
@@ -94,7 +98,7 @@ connect(Address, Port,
#config{transport_info = CbInfo, inet_user = UserOpts, ssl = SslOpts,
emulated = EmOpts, inet_ssl = SocketOpts, connection_cb = ConnetionCb},
Timeout) ->
- {Transport, _, _, _} = CbInfo,
+ {Transport, _, _, _, _} = CbInfo,
try Transport:connect(Address, Port, SocketOpts, Timeout) of
{ok, Socket} ->
ssl_connection:connect(ConnetionCb, Address, Port, Socket,
@@ -112,18 +116,20 @@ connect(Address, Port,
{error, {options, {socket_options, UserOpts}}}
end.
-socket(Pid, Transport, Socket, ConnectionCb, Tracker) ->
- #sslsocket{pid = Pid,
+socket(Pids, Transport, Socket, ConnectionCb, Tracker) ->
+ #sslsocket{pid = Pids,
%% "The name "fd" is keept for backwards compatibility
fd = {Transport, Socket, ConnectionCb, Tracker}}.
-setopts(gen_tcp, #sslsocket{pid = {ListenSocket, #config{emulated = Tracker}}}, Options) ->
+setopts(gen_tcp, Socket = #sslsocket{pid = {ListenSocket, #config{emulated = Tracker}}}, Options) ->
{SockOpts, EmulatedOpts} = split_options(Options),
ok = set_emulated_opts(Tracker, EmulatedOpts),
+ check_active_n(EmulatedOpts, Socket),
inet:setopts(ListenSocket, SockOpts);
-setopts(_, #sslsocket{pid = {ListenSocket, #config{transport_info = {Transport,_,_,_},
+setopts(_, Socket = #sslsocket{pid = {ListenSocket, #config{transport_info = {Transport,_,_,_,_},
emulated = Tracker}}}, Options) ->
{SockOpts, EmulatedOpts} = split_options(Options),
ok = set_emulated_opts(Tracker, EmulatedOpts),
+ check_active_n(EmulatedOpts, Socket),
Transport:setopts(ListenSocket, SockOpts);
%%% Following clauses will not be called for emulated options, they are handled in the connection process
setopts(gen_tcp, Socket, Options) ->
@@ -131,6 +137,31 @@ setopts(gen_tcp, Socket, Options) ->
setopts(Transport, Socket, Options) ->
Transport:setopts(Socket, Options).
+check_active_n(EmulatedOpts, Socket = #sslsocket{pid = {_, #config{emulated = Tracker}}}) ->
+ %% We check the resulting options to send an ssl_passive message if necessary.
+ case proplists:lookup(active, EmulatedOpts) of
+ %% The provided value is out of bound.
+ {_, N} when is_integer(N), N < -32768 ->
+ throw(einval);
+ {_, N} when is_integer(N), N > 32767 ->
+ throw(einval);
+ {_, N} when is_integer(N) ->
+ case get_emulated_opts(Tracker, [active]) of
+ [{_, false}] ->
+ self() ! {ssl_passive, Socket},
+ ok;
+ %% The result of the addition is out of bound.
+ [{_, A}] when is_integer(A), A < -32768 ->
+ throw(einval);
+ [{_, A}] when is_integer(A), A > 32767 ->
+ throw(einval);
+ _ ->
+ ok
+ end;
+ _ ->
+ ok
+ end.
+
getopts(gen_tcp, #sslsocket{pid = {ListenSocket, #config{emulated = Tracker}}}, Options) ->
{SockOptNames, EmulatedOptNames} = split_options(Options),
EmulatedOpts = get_emulated_opts(Tracker, EmulatedOptNames),
@@ -208,7 +239,7 @@ start_link(Port, SockOpts, SslOpts) ->
init([Port, Opts, SslOpts]) ->
process_flag(trap_exit, true),
true = link(Port),
- {ok, #state{emulated_opts = Opts, port = Port, ssl_opts = SslOpts}}.
+ {ok, #state{emulated_opts = do_set_emulated_opts(Opts, []), port = Port, ssl_opts = SslOpts}}.
%%--------------------------------------------------------------------
-spec handle_call(msg(), from(), #state{}) -> {reply, reply(), #state{}}.
@@ -303,9 +334,24 @@ split_options([Name | Opts], Emu, SocketOptNames, EmuOptNames) ->
do_set_emulated_opts([], Opts) ->
Opts;
+do_set_emulated_opts([{active, N0} | Rest], Opts) when is_integer(N0) ->
+ N = update_active_n(N0, proplists:get_value(active, Opts, false)),
+ do_set_emulated_opts(Rest, [{active, N} | proplists:delete(active, Opts)]);
do_set_emulated_opts([{Name,_} = Opt | Rest], Opts) ->
do_set_emulated_opts(Rest, [Opt | proplists:delete(Name, Opts)]).
+update_active_n(New, Current) ->
+ if
+ is_integer(Current), New + Current =< 0 ->
+ false;
+ is_integer(Current) ->
+ New + Current;
+ New =< 0 ->
+ false;
+ true ->
+ New
+ end.
+
get_socket_opts(_, [], _) ->
[];
get_socket_opts(ListenSocket, SockOptNames, Cb) ->
@@ -365,6 +411,9 @@ validate_inet_option(header, Value)
when not is_integer(Value) ->
throw({error, {options, {header,Value}}});
validate_inet_option(active, Value)
+ when Value >= -32768, Value =< 32767 ->
+ ok;
+validate_inet_option(active, Value)
when Value =/= true, Value =/= false, Value =/= once ->
throw({error, {options, {active,Value}}});
validate_inet_option(_, _) ->
diff --git a/lib/ssl/src/tls_v1.erl b/lib/ssl/src/tls_v1.erl
index a8fe119bf8..27cd5765e5 100644
--- a/lib/ssl/src/tls_v1.erl
+++ b/lib/ssl/src/tls_v1.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,7 +32,19 @@
-export([master_secret/4, finished/5, certificate_verify/3, mac_hash/7, hmac_hash/3,
setup_keys/8, suites/1, prf/5,
ecc_curves/1, ecc_curves/2, oid_to_enum/1, enum_to_oid/1,
- default_signature_algs/1, signature_algs/2]).
+ default_signature_algs/1, signature_algs/2,
+ default_signature_schemes/1, signature_schemes/2,
+ groups/1, groups/2, group_to_enum/1, enum_to_group/1, default_groups/1]).
+
+-export([derive_secret/4, hkdf_expand_label/5, hkdf_extract/3, hkdf_expand/4,
+ key_schedule/3, key_schedule/4, create_info/3,
+ external_binder_key/2, resumption_binder_key/2,
+ client_early_traffic_secret/3, early_exporter_master_secret/3,
+ client_handshake_traffic_secret/3, server_handshake_traffic_secret/3,
+ client_application_traffic_secret_0/3, server_application_traffic_secret_0/3,
+ exporter_master_secret/3, resumption_master_secret/3,
+ update_traffic_secret/2, calculate_traffic_keys/3,
+ transcript_hash/2, finished_key/2, finished_verify_data/3]).
-type named_curve() :: sect571r1 | sect571k1 | secp521r1 | brainpoolP512r1 |
sect409k1 | sect409r1 | brainpoolP384r1 | secp384r1 |
@@ -41,12 +53,68 @@
sect193r1 | sect193r2 | secp192k1 | secp192r1 | sect163k1 |
sect163r1 | sect163r2 | secp160k1 | secp160r1 | secp160r2.
-type curves() :: [named_curve()].
--export_type([curves/0, named_curve/0]).
+-type group() :: secp256r1 | secp384r1 | secp521r1 | ffdhe2048 |
+ ffdhe3072 | ffdhe4096 | ffdhe6144 | ffdhe8192.
+-type supported_groups() :: [group()].
+-export_type([curves/0, named_curve/0, group/0, supported_groups/0]).
%%====================================================================
%% Internal application API
%%====================================================================
+%% TLS 1.3 ---------------------------------------------------
+-spec derive_secret(Secret::binary(), Label::binary(),
+ Messages::iodata(), Algo::ssl:hash()) -> Key::binary().
+derive_secret(Secret, Label, Messages, Algo) ->
+ Hash = crypto:hash(mac_algo(Algo), Messages),
+ hkdf_expand_label(Secret, Label,
+ Hash, ssl_cipher:hash_size(Algo), Algo).
+
+-spec hkdf_expand_label(Secret::binary(), Label0::binary(),
+ Context::binary(), Length::integer(),
+ Algo::ssl:hash()) -> KeyingMaterial::binary().
+hkdf_expand_label(Secret, Label0, Context, Length, Algo) ->
+ HkdfLabel = create_info(Label0, Context, Length),
+ hkdf_expand(Secret, HkdfLabel, Length, Algo).
+
+%% Create info parameter for HKDF-Expand:
+%% HKDF-Expand(PRK, info, L) -> OKM
+create_info(Label0, Context0, Length) ->
+ %% struct {
+ %% uint16 length = Length;
+ %% opaque label<7..255> = "tls13 " + Label;
+ %% opaque context<0..255> = Context;
+ %% } HkdfLabel;
+ Label1 = << <<"tls13 ">>/binary, Label0/binary>>,
+ LabelLen = size(Label1),
+ Label = <<?BYTE(LabelLen), Label1/binary>>,
+ ContextLen = size(Context0),
+ Context = <<?BYTE(ContextLen),Context0/binary>>,
+ Content = <<Label/binary, Context/binary>>,
+ <<?UINT16(Length), Content/binary>>.
+
+-spec hkdf_extract(MacAlg::ssl:hash(), Salt::binary(),
+ KeyingMaterial::binary()) -> PseudoRandKey::binary().
+
+hkdf_extract(MacAlg, Salt, KeyingMaterial) ->
+ hmac_hash(MacAlg, Salt, KeyingMaterial).
+
+
+-spec hkdf_expand(PseudoRandKey::binary(), ContextInfo::binary(),
+ Length::integer(), Algo::ssl:hash()) -> KeyingMaterial::binary().
+
+hkdf_expand(PseudoRandKey, ContextInfo, Length, Algo) ->
+ Iterations = erlang:ceil(Length / ssl_cipher:hash_size(Algo)),
+ hkdf_expand(Algo, PseudoRandKey, ContextInfo, Length, 1, Iterations, <<>>, <<>>).
+
+
+-spec transcript_hash(Messages::iodata(), Algo::ssl:hash()) -> Hash::binary().
+
+transcript_hash(Messages, Algo) ->
+ crypto:hash(mac_algo(Algo), Messages).
+%% TLS 1.3 ---------------------------------------------------
+
+%% TLS 1.0 -1.2 ---------------------------------------------------
-spec master_secret(integer(), binary(), binary(), binary()) -> binary().
master_secret(PrfAlgo, PreMasterSecret, ClientRandom, ServerRandom) ->
@@ -56,9 +124,10 @@ master_secret(PrfAlgo, PreMasterSecret, ClientRandom, ServerRandom) ->
prf(PrfAlgo, PreMasterSecret, <<"master secret">>,
[ClientRandom, ServerRandom], 48).
+%% TLS 1.0 -1.2 ---------------------------------------------------
-spec finished(client | server, integer(), integer(), binary(), [binary()]) -> binary().
-
+%% TLS 1.0 -1.1 ---------------------------------------------------
finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
when Version == 1; Version == 2; PrfAlgo == ?MD5SHA ->
%% RFC 2246 & 4346 - 7.4.9. Finished
@@ -72,7 +141,9 @@ finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
MD5 = crypto:hash(md5, Handshake),
SHA = crypto:hash(sha, Handshake),
prf(?MD5SHA, MasterSecret, finished_label(Role), [MD5, SHA], 12);
+%% TLS 1.0 -1.1 ---------------------------------------------------
+%% TLS 1.2 ---------------------------------------------------
finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
when Version == 3 ->
%% RFC 5246 - 7.4.9. Finished
@@ -84,21 +155,28 @@ finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
%% PRF(master_secret, finished_label, Hash(handshake_messages)) [0..11];
Hash = crypto:hash(mac_algo(PrfAlgo), Handshake),
prf(PrfAlgo, MasterSecret, finished_label(Role), Hash, 12).
+%% TLS 1.2 ---------------------------------------------------
+
+%% TODO 1.3 finished
-spec certificate_verify(md5sha | sha, integer(), [binary()]) -> binary().
+%% TLS 1.0 -1.1 ---------------------------------------------------
certificate_verify(md5sha, _Version, Handshake) ->
MD5 = crypto:hash(md5, Handshake),
SHA = crypto:hash(sha, Handshake),
<<MD5/binary, SHA/binary>>;
+%% TLS 1.0 -1.1 ---------------------------------------------------
+%% TLS 1.2 ---------------------------------------------------
certificate_verify(HashAlgo, _Version, Handshake) ->
crypto:hash(HashAlgo, Handshake).
+%% TLS 1.2 ---------------------------------------------------
-spec setup_keys(integer(), integer(), binary(), binary(), binary(), integer(),
integer(), integer()) -> {binary(), binary(), binary(),
binary(), binary(), binary()}.
-
+%% TLS v1.0 ---------------------------------------------------
setup_keys(Version, _PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize,
KeyMatLen, IVSize)
when Version == 1 ->
@@ -123,8 +201,9 @@ setup_keys(Version, _PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize
ClientIV:IVSize/binary, ServerIV:IVSize/binary>> = KeyBlock,
{ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey,
ServerWriteKey, ClientIV, ServerIV};
+%% TLS v1.0 ---------------------------------------------------
-%% TLS v1.1
+%% TLS v1.1 ---------------------------------------------------
setup_keys(Version, _PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize,
KeyMatLen, IVSize)
when Version == 2 ->
@@ -150,11 +229,12 @@ setup_keys(Version, _PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize
ClientIV:IVSize/binary, ServerIV:IVSize/binary>> = KeyBlock,
{ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey,
ServerWriteKey, ClientIV, ServerIV};
+%% TLS v1.1 ---------------------------------------------------
-%% TLS v1.2
+%% TLS v1.2 ---------------------------------------------------
setup_keys(Version, PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize,
KeyMatLen, IVSize)
- when Version == 3 ->
+ when Version == 3; Version == 4 ->
%% RFC 5246 - 6.3. Key calculation
%% key_block = PRF(SecurityParameters.master_secret,
%% "key expansion",
@@ -176,8 +256,177 @@ setup_keys(Version, PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize,
ClientIV:IVSize/binary, ServerIV:IVSize/binary>> = KeyBlock,
{ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey,
ServerWriteKey, ClientIV, ServerIV}.
+%% TLS v1.2 ---------------------------------------------------
--spec mac_hash(integer(), binary(), integer(), integer(), tls_record:tls_version(),
+%% TLS v1.3 ---------------------------------------------------
+%% RFC 8446 - 7.1. Key Schedule
+%%
+%% 0
+%% |
+%% v
+%% PSK -> HKDF-Extract = Early Secret
+%% |
+%% +-----> Derive-Secret(., "ext binder" | "res binder", "")
+%% | = binder_key
+%% |
+%% +-----> Derive-Secret(., "c e traffic", ClientHello)
+%% | = client_early_traffic_secret
+%% |
+%% +-----> Derive-Secret(., "e exp master", ClientHello)
+%% | = early_exporter_master_secret
+%% v
+%% Derive-Secret(., "derived", "")
+%% |
+%% v
+%% (EC)DHE -> HKDF-Extract = Handshake Secret
+%% |
+%% +-----> Derive-Secret(., "c hs traffic",
+%% | ClientHello...ServerHello)
+%% | = client_handshake_traffic_secret
+%% |
+%% +-----> Derive-Secret(., "s hs traffic",
+%% | ClientHello...ServerHello)
+%% | = server_handshake_traffic_secret
+%% v
+%% Derive-Secret(., "derived", "")
+%% |
+%% v
+%% 0 -> HKDF-Extract = Master Secret
+%% |
+%% +-----> Derive-Secret(., "c ap traffic",
+%% | ClientHello...server Finished)
+%% | = client_application_traffic_secret_0
+%% |
+%% +-----> Derive-Secret(., "s ap traffic",
+%% | ClientHello...server Finished)
+%% | = server_application_traffic_secret_0
+%% |
+%% +-----> Derive-Secret(., "exp master",
+%% | ClientHello...server Finished)
+%% | = exporter_master_secret
+%% |
+%% +-----> Derive-Secret(., "res master",
+%% ClientHello...client Finished)
+%% = resumption_master_secret
+-spec key_schedule(early_secret | handshake_secret | master_secret,
+ atom(), {psk | early_secret | handshake_secret, binary()}) ->
+ {early_secret | handshake_secret | master_secret, binary()}.
+
+key_schedule(early_secret, Algo, {psk, PSK}) ->
+ Len = ssl_cipher:hash_size(Algo),
+ Salt = binary:copy(<<?BYTE(0)>>, Len),
+ {early_secret, hkdf_extract(Algo, Salt, PSK)};
+key_schedule(master_secret, Algo, {handshake_secret, Secret}) ->
+ Len = ssl_cipher:hash_size(Algo),
+ IKM = binary:copy(<<?BYTE(0)>>, Len),
+ Salt = derive_secret(Secret, <<"derived">>, <<>>, Algo),
+ {master_secret, hkdf_extract(Algo, Salt, IKM)}.
+%%
+key_schedule(handshake_secret, Algo, IKM, {early_secret, Secret}) ->
+ Salt = derive_secret(Secret, <<"derived">>, <<>>, Algo),
+ {handshake_secret, hkdf_extract(Algo, Salt, IKM)}.
+
+-spec external_binder_key(atom(), {early_secret, binary()}) -> binary().
+external_binder_key(Algo, {early_secret, Secret}) ->
+ derive_secret(Secret, <<"ext binder">>, <<>>, Algo).
+
+-spec resumption_binder_key(atom(), {early_secret, binary()}) -> binary().
+resumption_binder_key(Algo, {early_secret, Secret}) ->
+ derive_secret(Secret, <<"res binder">>, <<>>, Algo).
+
+-spec client_early_traffic_secret(atom(), {early_secret, binary()}, iodata()) -> binary().
+%% M = ClientHello
+client_early_traffic_secret(Algo, {early_secret, Secret}, M) ->
+ derive_secret(Secret, <<"c e traffic">>, M, Algo).
+
+-spec early_exporter_master_secret(atom(), {early_secret, binary()}, iodata()) -> binary().
+%% M = ClientHello
+early_exporter_master_secret(Algo, {early_secret, Secret}, M) ->
+ derive_secret(Secret, <<"e exp master">>, M, Algo).
+
+-spec client_handshake_traffic_secret(atom(), {handshake_secret, binary()}, iodata()) -> binary().
+%% M = ClientHello...ServerHello
+client_handshake_traffic_secret(Algo, {handshake_secret, Secret}, M) ->
+ derive_secret(Secret, <<"c hs traffic">>, M, Algo).
+
+-spec server_handshake_traffic_secret(atom(), {handshake_secret, binary()}, iodata()) -> binary().
+%% M = ClientHello...ServerHello
+server_handshake_traffic_secret(Algo, {handshake_secret, Secret}, M) ->
+ derive_secret(Secret, <<"s hs traffic">>, M, Algo).
+
+-spec client_application_traffic_secret_0(atom(), {master_secret, binary()}, iodata()) -> binary().
+%% M = ClientHello...server Finished
+client_application_traffic_secret_0(Algo, {master_secret, Secret}, M) ->
+ derive_secret(Secret, <<"c ap traffic">>, M, Algo).
+
+-spec server_application_traffic_secret_0(atom(), {master_secret, binary()}, iodata()) -> binary().
+%% M = ClientHello...server Finished
+server_application_traffic_secret_0(Algo, {master_secret, Secret}, M) ->
+ derive_secret(Secret, <<"s ap traffic">>, M, Algo).
+
+-spec exporter_master_secret(atom(), {master_secret, binary()}, iodata()) -> binary().
+%% M = ClientHello...server Finished
+exporter_master_secret(Algo, {master_secret, Secret}, M) ->
+ derive_secret(Secret, <<"exp master">>, M, Algo).
+
+-spec resumption_master_secret(atom(), {master_secret, binary()}, iodata()) -> binary().
+%% M = ClientHello...client Finished
+resumption_master_secret(Algo, {master_secret, Secret}, M) ->
+ derive_secret(Secret, <<"res master">>, M, Algo).
+
+-spec finished_key(binary(), atom()) -> binary().
+finished_key(BaseKey, Algo) ->
+ %% finished_key =
+ %% HKDF-Expand-Label(BaseKey, "finished", "", Hash.length)
+ ssl_cipher:hash_size(Algo),
+ hkdf_expand_label(BaseKey, <<"finished">>, <<>>, ssl_cipher:hash_size(Algo), Algo).
+
+-spec finished_verify_data(binary(), atom(), iodata()) -> binary().
+finished_verify_data(FinishedKey, HKDFAlgo, Messages) ->
+ %% The verify_data value is computed as follows:
+ %%
+ %% verify_data =
+ %% HMAC(finished_key,
+ %% Transcript-Hash(Handshake Context,
+ %% Certificate*, CertificateVerify*))
+ Context = lists:reverse(Messages),
+ THash = tls_v1:transcript_hash(Context, HKDFAlgo),
+ tls_v1:hmac_hash(HKDFAlgo, FinishedKey, THash).
+
+%% The next-generation application_traffic_secret is computed as:
+%%
+%% application_traffic_secret_N+1 =
+%% HKDF-Expand-Label(application_traffic_secret_N,
+%% "traffic upd", "", Hash.length)
+-spec update_traffic_secret(atom(), binary()) -> binary().
+update_traffic_secret(Algo, Secret) ->
+ hkdf_expand_label(Secret, <<"traffic upd">>, <<>>, ssl_cipher:hash_size(Algo), Algo).
+
+%% The traffic keying material is generated from the following input
+%% values:
+%%
+%% - A secret value
+%%
+%% - A purpose value indicating the specific value being generated
+%%
+%% - The length of the key being generated
+%%
+%% The traffic keying material is generated from an input traffic secret
+%% value using:
+%%
+%% [sender]_write_key = HKDF-Expand-Label(Secret, "key", "", key_length)
+%% [sender]_write_iv = HKDF-Expand-Label(Secret, "iv", "", iv_length)
+-spec calculate_traffic_keys(atom(), atom(), binary()) -> {binary(), binary()}.
+calculate_traffic_keys(HKDFAlgo, Cipher, Secret) ->
+ Key = hkdf_expand_label(Secret, <<"key">>, <<>>, ssl_cipher:key_material(Cipher), HKDFAlgo),
+ %% TODO: remove hard coded IV size
+ IV = hkdf_expand_label(Secret, <<"iv">>, <<>>, 12, HKDFAlgo),
+ {Key, IV}.
+
+%% TLS v1.3 ---------------------------------------------------
+
+%% TLS 1.0 -1.2 ---------------------------------------------------
+-spec mac_hash(integer() | atom(), binary(), integer(), integer(), tls_record:tls_version(),
integer(), binary()) -> binary().
mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor},
@@ -191,8 +440,11 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor},
?BYTE(Major), ?BYTE(Minor), ?UINT16(Length)>>,
Fragment]),
Mac.
+%% TLS 1.0 -1.2 ---------------------------------------------------
+
+%% TODO 1.3 same as above?
--spec suites(1|2|3) -> [ssl_cipher:cipher_suite()].
+-spec suites(1|2|3|4|'TLS_v1.3') -> [ssl_cipher_format:cipher_suite()].
suites(Minor) when Minor == 1; Minor == 2 ->
[
@@ -202,23 +454,13 @@ suites(Minor) when Minor == 1; Minor == 2 ->
?TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
- ?TLS_RSA_WITH_AES_256_CBC_SHA,
?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
?TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
?TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
- ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
- ?TLS_RSA_WITH_AES_128_CBC_SHA,
-
- ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
- ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
- ?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
- ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
- ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
- ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
- ?TLS_RSA_WITH_3DES_EDE_CBC_SHA
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
];
suites(3) ->
[?TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
@@ -230,16 +472,10 @@ suites(3) ->
?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
- ?TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
- ?TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
- ?TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
-
?TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
?TLS_DHE_DSS_WITH_AES_256_GCM_SHA384,
?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
- ?TLS_RSA_WITH_AES_256_GCM_SHA384,
- ?TLS_RSA_WITH_AES_256_CBC_SHA256,
?TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
?TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
@@ -253,19 +489,36 @@ suites(3) ->
?TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
?TLS_DHE_DSS_WITH_AES_128_GCM_SHA256,
?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
- ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
- ?TLS_RSA_WITH_AES_128_GCM_SHA256,
- ?TLS_RSA_WITH_AES_128_CBC_SHA256
+ ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
%% not supported
%% ?TLS_DH_RSA_WITH_AES_256_GCM_SHA384,
%% ?TLS_DH_DSS_WITH_AES_256_GCM_SHA384,
%% ?TLS_DH_RSA_WITH_AES_128_GCM_SHA256,
%% ?TLS_DH_DSS_WITH_AES_128_GCM_SHA256
- ] ++ suites(2).
-
-
-
+ ] ++ suites(2);
+
+suites(4) ->
+ [?TLS_AES_256_GCM_SHA384,
+ ?TLS_AES_128_GCM_SHA256,
+ ?TLS_CHACHA20_POLY1305_SHA256,
+ ?TLS_AES_128_CCM_SHA256
+ %% Not supported
+ %% ?TLS_AES_128_CCM_8_SHA256
+ ] ++ suites(3);
+
+suites('TLS_v1.3') ->
+ [?TLS_AES_256_GCM_SHA384,
+ ?TLS_AES_128_GCM_SHA256,
+ ?TLS_CHACHA20_POLY1305_SHA256,
+ ?TLS_AES_128_CCM_SHA256
+ %% Not supported
+ %% ?TLS_AES_128_CCM_8_SHA256
+ ].
+
+
+signature_algs({3, 4}, HashSigns) ->
+ signature_algs({3, 3}, HashSigns);
signature_algs({3, 3}, HashSigns) ->
CryptoSupports = crypto:supports(),
Hashes = proplists:get_value(hashs, CryptoSupports),
@@ -293,6 +546,10 @@ signature_algs({3, 3}, HashSigns) ->
end, [], HashSigns),
lists:reverse(Supported).
+default_signature_algs({3, 4} = Version) ->
+ %% TLS 1.3 servers shall be prepared to process TLS 1.2 ClientHellos
+ %% containing legacy hash-sign tuples.
+ default_signature_schemes(Version) ++ default_signature_algs({3,3});
default_signature_algs({3, 3} = Version) ->
Default = [%% SHA2
{sha512, ecdsa},
@@ -311,15 +568,99 @@ default_signature_algs({3, 3} = Version) ->
default_signature_algs(_) ->
undefined.
+
+signature_schemes(Version, SignatureSchemes) when is_tuple(Version)
+ andalso Version >= {3, 3} ->
+ CryptoSupports = crypto:supports(),
+ Hashes = proplists:get_value(hashs, CryptoSupports),
+ PubKeys = proplists:get_value(public_keys, CryptoSupports),
+ Curves = proplists:get_value(curves, CryptoSupports),
+ RSAPSSSupported = lists:member(rsa_pkcs1_pss_padding,
+ proplists:get_value(rsa_opts, CryptoSupports)),
+ Fun = fun (Scheme, Acc) when is_atom(Scheme) ->
+ {Hash0, Sign0, Curve} =
+ ssl_cipher:scheme_to_components(Scheme),
+ Sign = case Sign0 of
+ rsa_pkcs1 ->
+ rsa;
+ rsa_pss_rsae when RSAPSSSupported ->
+ rsa;
+ rsa_pss_pss when RSAPSSSupported ->
+ rsa;
+ S -> S
+ end,
+ Hash = case Hash0 of
+ sha1 ->
+ sha;
+ H -> H
+ end,
+ case proplists:get_bool(Sign, PubKeys)
+ andalso proplists:get_bool(Hash, Hashes)
+ andalso (Curve =:= undefined orelse
+ proplists:get_bool(Curve, Curves))
+ andalso is_pair(Hash, Sign, Hashes)
+ of
+ true ->
+ [Scheme | Acc];
+ false ->
+ Acc
+ end;
+ %% Special clause for filtering out the legacy hash-sign tuples.
+ (_ , Acc) ->
+ Acc
+ end,
+ Supported = lists:foldl(Fun, [], SignatureSchemes),
+ lists:reverse(Supported);
+signature_schemes(_, _) ->
+ [].
+
+default_signature_schemes(Version) ->
+ Default = [
+ ecdsa_secp521r1_sha512,
+ ecdsa_secp384r1_sha384,
+ ecdsa_secp256r1_sha256,
+ rsa_pss_pss_sha512,
+ rsa_pss_pss_sha384,
+ rsa_pss_pss_sha256,
+ rsa_pss_rsae_sha512,
+ rsa_pss_rsae_sha384,
+ rsa_pss_rsae_sha256,
+ %% ed25519,
+ %% ed448,
+
+ %% These values refer solely to signatures
+ %% which appear in certificates (see Section 4.4.2.2) and are not
+ %% defined for use in signed TLS handshake messages, although they
+ %% MAY appear in "signature_algorithms" and
+ %% "signature_algorithms_cert" for backward compatibility with
+ %% TLS 1.2.
+ rsa_pkcs1_sha512,
+ rsa_pkcs1_sha384,
+ rsa_pkcs1_sha256,
+ ecdsa_sha1,
+ rsa_pkcs1_sha1
+ ],
+ signature_schemes(Version, Default).
+
+
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+hkdf_expand(Algo, PseudoRandKey, ContextInfo, Length, N, N, Prev, Acc) ->
+ Keyingmaterial = hmac_hash(Algo, PseudoRandKey, <<Prev/binary, ContextInfo/binary, ?BYTE(N)>>),
+ binary:part(<<Acc/binary, Keyingmaterial/binary>>, {0, Length});
+hkdf_expand(Algo, PseudoRandKey, ContextInfo, Length, M, N, Prev, Acc) ->
+ Keyingmaterial = hmac_hash(Algo, PseudoRandKey, <<Prev/binary, ContextInfo/binary, ?BYTE(M)>>),
+ hkdf_expand(Algo, PseudoRandKey, ContextInfo, Length, M + 1, N, Keyingmaterial, <<Acc/binary, Keyingmaterial/binary>>).
+
%%%% HMAC and the Pseudorandom Functions RFC 2246 & 4346 - 5.%%%%
hmac_hash(?NULL, _, _) ->
<<>>;
hmac_hash(Alg, Key, Value) ->
crypto:hmac(mac_algo(Alg), Key, Value).
+mac_algo(Alg) when is_atom(Alg) ->
+ Alg;
mac_algo(?MD5) -> md5;
mac_algo(?SHA) -> sha;
mac_algo(?SHA256) -> sha256;
@@ -415,6 +756,7 @@ ecc_curves(all) ->
sect239k1,sect233k1,sect233r1,secp224k1,secp224r1,
sect193r1,sect193r2,secp192k1,secp192r1,sect163k1,
sect163r1,sect163r2,secp160k1,secp160r1,secp160r2];
+
ecc_curves(Minor) ->
TLSCurves = ecc_curves(all),
ecc_curves(Minor, TLSCurves).
@@ -429,6 +771,63 @@ ecc_curves(_Minor, TLSCurves) ->
end
end, [], TLSCurves).
+-spec groups(4 | all | default) -> [group()].
+groups(all) ->
+ [x25519,
+ x448,
+ secp256r1,
+ secp384r1,
+ secp521r1,
+ ffdhe2048,
+ ffdhe3072,
+ ffdhe4096,
+ ffdhe6144,
+ ffdhe8192];
+groups(default) ->
+ [x25519,
+ x448,
+ secp256r1,
+ secp384r1];
+groups(Minor) ->
+ TLSGroups = groups(all),
+ groups(Minor, TLSGroups).
+%%
+-spec groups(4, [group()]) -> [group()].
+groups(_Minor, TLSGroups) ->
+ CryptoGroups = supported_groups(),
+ lists:filter(fun(Group) -> proplists:get_bool(Group, CryptoGroups) end, TLSGroups).
+
+default_groups(Minor) ->
+ TLSGroups = groups(default),
+ groups(Minor, TLSGroups).
+
+supported_groups() ->
+ %% TODO: Add new function to crypto?
+ proplists:get_value(curves, crypto:supports()) ++
+ [ffdhe2048,ffdhe3072,ffdhe4096,ffdhe6144,ffdhe8192].
+
+group_to_enum(secp256r1) -> 23;
+group_to_enum(secp384r1) -> 24;
+group_to_enum(secp521r1) -> 25;
+group_to_enum(x25519) -> 29;
+group_to_enum(x448) -> 30;
+group_to_enum(ffdhe2048) -> 256;
+group_to_enum(ffdhe3072) -> 257;
+group_to_enum(ffdhe4096) -> 258;
+group_to_enum(ffdhe6144) -> 259;
+group_to_enum(ffdhe8192) -> 260.
+
+enum_to_group(23) -> secp256r1;
+enum_to_group(24) -> secp384r1;
+enum_to_group(25) -> secp521r1;
+enum_to_group(29) -> x25519;
+enum_to_group(30) -> x448;
+enum_to_group(256) -> ffdhe2048;
+enum_to_group(257) -> ffdhe3072;
+enum_to_group(258) -> ffdhe4096;
+enum_to_group(259) -> ffdhe6144;
+enum_to_group(260) -> ffdhe8192;
+enum_to_group(_) -> undefined.
%% ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005)
oid_to_enum(?sect163k1) -> 1;
diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile
index aa01552c39..dba90aaff0 100644
--- a/lib/ssl/test/Makefile
+++ b/lib/ssl/test/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2017. All Rights Reserved.
+# Copyright Ericsson AB 1999-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
# Application version
# ----------------------------------------------------
include ../vsn.mk
-VSN=$(GS_VSN)
+VSN=$(SSL_VSN)
# ----------------------------------------------------
# Target Specs
@@ -37,13 +37,18 @@ VSN=$(GS_VSN)
MODULES = \
ssl_test_lib \
+ ssl_bench_test_lib \
+ ssl_dist_test_lib \
ssl_alpn_handshake_SUITE \
ssl_basic_SUITE \
ssl_bench_SUITE \
ssl_cipher_SUITE \
+ ssl_cipher_suite_SUITE \
+ openssl_server_cipher_suite_SUITE\
ssl_certificate_verify_SUITE\
ssl_crl_SUITE\
ssl_dist_SUITE \
+ ssl_dist_bench_SUITE \
ssl_engine_SUITE\
ssl_handshake_SUITE \
ssl_npn_hello_SUITE \
@@ -54,15 +59,21 @@ MODULES = \
ssl_session_cache_SUITE \
ssl_to_openssl_SUITE \
ssl_ECC_SUITE \
+ ssl_ECC_openssl_SUITE \
+ ssl_ECC\
ssl_upgrade_SUITE\
ssl_sni_SUITE \
- make_certs\
- x509_test
+ ssl_eqc_SUITE \
+ ssl_rfc_5869_SUITE \
+ make_certs \
+ x509_test \
+ inet_crypto_dist
ERL_FILES = $(MODULES:%=%.erl)
-HRL_FILES =
+HRL_FILES = \
+ ssl_dist_test_lib.hrl
HRL_FILES_SRC = \
ssl_api.hrl\
@@ -138,7 +149,7 @@ release_tests_spec: opt
$(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(HRL_FILES_NEEDED_IN_TEST) $(COVER_FILE) "$(RELSYSDIR)"
$(INSTALL_DATA) ssl.spec ssl_bench.spec ssl.cover "$(RELSYSDIR)"
chmod -R u+w "$(RELSYSDIR)"
- @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
+ @tar cf - *_SUITE_data property_test | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/ssl/test/inet_crypto_dist.erl b/lib/ssl/test/inet_crypto_dist.erl
new file mode 100644
index 0000000000..63c19d9438
--- /dev/null
+++ b/lib/ssl/test/inet_crypto_dist.erl
@@ -0,0 +1,1541 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% -------------------------------------------------------------------------
+%%
+%% Module for encrypted Erlang protocol - a minimal encrypted
+%% distribution protocol based on only a shared secret
+%% and the crypto application
+%%
+-module(inet_crypto_dist).
+-define(DIST_NAME, inet_crypto).
+-define(DIST_PROTO, crypto).
+-define(DRIVER, inet_tcp).
+-define(FAMILY, inet).
+
+-export([listen/1, accept/1, accept_connection/5,
+ setup/5, close/1, select/1, is_node_name/1]).
+
+%% Generalized dist API, for sibling IPv6 module inet6_crypto_dist
+-export([gen_listen/2, gen_accept/2, gen_accept_connection/6,
+ gen_setup/6, gen_close/2, gen_select/2]).
+
+-export([nodelay/0]).
+
+%% Debug
+%%%-compile(export_all).
+-export([dbg/0, test_server/0, test_client/1]).
+
+-include_lib("kernel/include/net_address.hrl").
+-include_lib("kernel/include/dist.hrl").
+-include_lib("kernel/include/dist_util.hrl").
+
+-define(PACKET_SIZE, 65536).
+-define(BUFFER_SIZE, (?PACKET_SIZE bsl 4)).
+
+%% -------------------------------------------------------------------------
+
+-record(params,
+ {socket,
+ dist_handle,
+ hmac_algorithm = sha256,
+ aead_cipher = aes_gcm,
+ rekey_key,
+ iv = 12,
+ key = 16,
+ tag_len = 16,
+ rekey_interval = 262144
+ }).
+
+params(Socket) ->
+ #params{socket = Socket}.
+
+
+-record(key_pair,
+ {type = ecdh,
+ %% The curve choice greatly affects setup time,
+ %% we really want an Edwards curve but that would
+ %% require a very new openssl version.
+ %% Twisted brainpool curves (*t1) are faster than
+ %% non-twisted (*r1), 256 is much faster than 384,
+ %% and so on...
+%%% params = brainpoolP384t1,
+ params = brainpoolP256t1,
+ public,
+ private}).
+
+-define(KEY_PAIR_LIFE_TIME, 3600000). % 1 hour
+-define(KEY_PAIR_LIFE_COUNT, 256). % Number of connection setups
+
+
+%% -------------------------------------------------------------------------
+%% Keep the node's public/private key pair in the process state
+%% of a key pair server linked to the acceptor process.
+%% Create the key pair the first time it is needed
+%% so crypto gets time to start first.
+%%
+
+start_key_pair_server() ->
+ monitor_dist_proc(
+ spawn_link(
+ fun () ->
+ register(?MODULE, self()),
+ key_pair_server()
+ end)).
+
+key_pair_server() ->
+ key_pair_server(undefined, undefined, undefined).
+%%
+key_pair_server(KeyPair) ->
+ key_pair_server(
+ KeyPair,
+ erlang:start_timer(?KEY_PAIR_LIFE_TIME, self(), discard),
+ ?KEY_PAIR_LIFE_COUNT).
+%%
+key_pair_server(_KeyPair, Timer, 0) ->
+ cancel_timer(Timer),
+ key_pair_server();
+key_pair_server(KeyPair, Timer, Count) ->
+ receive
+ {Pid, Tag, get_key_pair} ->
+ case KeyPair of
+ undefined ->
+ KeyPair_1 = generate_key_pair(),
+ Pid ! {Tag, KeyPair_1},
+ key_pair_server(KeyPair_1);
+ #key_pair{} ->
+ Pid ! {Tag, KeyPair},
+ key_pair_server(KeyPair, Timer, Count - 1)
+ end;
+ {Pid, Tag, get_new_key_pair} ->
+ cancel_timer(Timer),
+ KeyPair_1 = generate_key_pair(),
+ Pid ! {Tag, KeyPair_1},
+ key_pair_server(KeyPair_1);
+ {timeout, Timer, discard} when is_reference(Timer) ->
+ key_pair_server()
+ end.
+
+generate_key_pair() ->
+ #key_pair{type = Type, params = Params} = #key_pair{},
+ {Public, Private} =
+ crypto:generate_key(Type, Params),
+ #key_pair{public = Public, private = Private}.
+
+cancel_timer(undefined) ->
+ ok;
+cancel_timer(Timer) ->
+ case erlang:cancel_timer(Timer) of
+ false ->
+ receive
+ {timeout, Timer, _} -> ok
+ end;
+ _RemainingTime ->
+ ok
+ end.
+
+get_key_pair() ->
+ call_key_pair_server(get_key_pair).
+
+get_new_key_pair() ->
+ call_key_pair_server(get_new_key_pair).
+
+call_key_pair_server(Request) ->
+ Pid = whereis(?MODULE),
+ Ref = erlang:monitor(process, Pid),
+ Pid ! {self(), Ref, Request},
+ receive
+ {Ref, Reply} ->
+ erlang:demonitor(Ref, [flush]),
+ Reply;
+ {'DOWN', Ref, process, Pid, Reason} ->
+ error(Reason)
+ end.
+
+compute_shared_secret(
+ #key_pair{
+ type = PublicKeyType,
+ params = PublicKeyParams,
+ private = PrivKey}, PubKey) ->
+ %%
+ crypto:compute_key(PublicKeyType, PubKey, PrivKey, PublicKeyParams).
+
+%% -------------------------------------------------------------------------
+%% Erlang distribution plugin structure explained to myself
+%% -------
+%% These are the processes involved in the distribution:
+%% * net_kernel
+%% * The Acceptor
+%% * The Controller | Handshaker | Ticker
+%% * The DistCtrl process that may be split into:
+%% + The Output controller
+%% + The Input controller
+%% For the regular inet_tcp_dist distribution module, DistCtrl
+%% is not one or two processes, but one port - a gen_tcp socket
+%%
+%% When the VM is started with the argument "-proto_dist inet_crypto"
+%% net_kernel registers the module inet_crypto_dist acli,oams distribution
+%% module. net_kernel calls listen/1 to create a listen socket
+%% and then accept/1 with the listen socket as argument to spawn
+%% the Acceptor process, which is linked to net_kernel. Apparently
+%% the listen socket is owned by net_kernel - I wonder if it could
+%% be owned by the Acceptor process instead...
+%%
+%% The Acceptor process calls blocking accept on the listen socket
+%% and when an incoming socket is returned it spawns the DistCtrl
+%% process a linked to the Acceptor. The ownership of the accepted
+%% socket is transferred to the DistCtrl process.
+%% A message is sent to net_kernel to inform it that an incoming
+%% connection has appeared and the Acceptor awaits a reply from net_kernel.
+%%
+%% net_kernel then calls accept_connection/5 to spawn the Controller |
+%% Handshaker | Ticker process that is linked to net_kernel.
+%% The Controller then awaits a message from the Acceptor process.
+%%
+%% When net_kernel has spawned the Controller it replies with a message
+%% to the Acceptor that then calls DistCtrl to changes its links
+%% so DistCtrl ends up linked to the Controller and not to the Acceptor.
+%% The Acceptor then sends a message to the Controller. The Controller
+%% then changes role into the Handshaker creates a #hs_data{} record
+%% and calls dist_util:handshake_other_started/1. After this
+%% the Acceptor goes back into a blocking accept on the listen socket.
+%%
+%% For the regular distribution inet_tcp_dist DistCtrl is a gen_tcp socket
+%% and when it is a process it also acts as a socket. The #hs_data{}
+%% record used by dist_util presents a set of funs that are used
+%% by dist_util to perform the distribution handshake. These funs
+%% make sure to transfer the handshake messages through the DistCtrl
+%% "socket".
+%%
+%% When the handshake is finished a fun for this purpose in #hs_data{}
+%% is called, which tells DistCtrl that it does not need to be prepared
+%% for any more #hs_data{} handshake calls. The DistCtrl process in this
+%% module then spawns the Input controller process that gets ownership
+%% of the connection's gen_tcp socket and changes into {active, N} mode
+%% so now it gets all incoming traffic and delivers that to the VM.
+%% The original DistCtrl process changes role into the Output controller
+%% process and starts asking the VM for outbound messages and transfers
+%% them on the connection socket.
+%%
+%% The Handshaker now changes into the Ticker role, and uses only two
+%% functions in the #hs_data{} record; one to get socket statistics
+%% and one to send a tick. None of these may block for any reason
+%% in particular not for a congested socket since that would destroy
+%% connection supervision.
+%%
+%%
+%% For an connection net_kernel calls setup/5 which spawns the
+%% Controller process as linked to net_kernel. This Controller process
+%% connects to the other node's listen socket and when that is succesful
+%% spawns the DistCtrl process as linked to the controller and transfers
+%% socket ownership to it.
+%%
+%% Then the Controller creates the #hs_data{} record and calls
+%% dist_util:handshake_we_started/1 which changes the process role
+%% into Handshaker.
+%%
+%% When the distribution handshake is finished the procedure is just
+%% as for an incoming connection above.
+%%
+%%
+%% To sum it up.
+%%
+%% There is an Acceptor process that is linked to net_kernel and
+%% informs it when new connections arrive.
+%%
+%% net_kernel spawns Controllers for incoming and for outgoing connections.
+%% these Controllers use the DistCtrl processes to do distribution
+%% handshake and after that becomes Tickers that supervise the connection.
+%%
+%% The Controller | Handshaker | Ticker is linked to net_kernel, and to
+%% DistCtrl, one or both. If any of these connection processes would die
+%% all others should be killed by the links. Therefore none of them may
+%% terminate with reason 'normal'.
+%% -------------------------------------------------------------------------
+
+-compile({inline, [socket_options/0]}).
+socket_options() ->
+ [binary, {active, false}, {packet, 2}, {nodelay, true},
+ {sndbuf, ?BUFFER_SIZE}, {recbuf, ?BUFFER_SIZE},
+ {buffer, ?BUFFER_SIZE}].
+
+%% -------------------------------------------------------------------------
+%% select/1 is called by net_kernel to ask if this distribution protocol
+%% is willing to handle Node
+%%
+
+select(Node) ->
+ gen_select(Node, ?DRIVER).
+
+gen_select(Node, Driver) ->
+ case dist_util:split_node(Node) of
+ {node, _, Host} ->
+ case Driver:getaddr(Host) of
+ {ok, _} -> true;
+ _ -> false
+ end;
+ _ ->
+ false
+ end.
+
+%% -------------------------------------------------------------------------
+
+is_node_name(Node) ->
+ dist_util:is_node_name(Node).
+
+%% -------------------------------------------------------------------------
+%% Called by net_kernel to create a listen socket for this
+%% distribution protocol. This listen socket is used by
+%% the Acceptor process.
+%%
+
+listen(Name) ->
+ gen_listen(Name, ?DRIVER).
+
+gen_listen(Name, Driver) ->
+ case inet_tcp_dist:gen_listen(Driver, Name) of
+ {ok, {Socket, Address, Creation}} ->
+ inet:setopts(Socket, socket_options()),
+ {ok,
+ {Socket, Address#net_address{protocol = ?DIST_PROTO}, Creation}};
+ Other ->
+ Other
+ end.
+
+%% -------------------------------------------------------------------------
+%% Called by net_kernel to spawn the Acceptor process that awaits
+%% new connection in a blocking accept and informs net_kernel
+%% when a new connection has appeared, and starts the DistCtrl
+%% "socket" process for the connection.
+%%
+
+accept(Listen) ->
+ gen_accept(Listen, ?DRIVER).
+
+gen_accept(Listen, Driver) ->
+ NetKernel = self(),
+ %%
+ %% Spawn Acceptor process
+ %%
+ monitor_dist_proc(
+ spawn_opt(
+ fun () ->
+ start_key_pair_server(),
+ accept_loop(Listen, Driver, NetKernel)
+ end,
+ [link, {priority, max}])).
+
+accept_loop(Listen, Driver, NetKernel) ->
+ case Driver:accept(trace(Listen)) of
+ {ok, Socket} ->
+ wait_for_code_server(),
+ Timeout = net_kernel:connecttime(),
+ DistCtrl = start_dist_ctrl(trace(Socket), Timeout),
+ %% DistCtrl is a "socket"
+ NetKernel !
+ trace({accept,
+ self(), DistCtrl, Driver:family(), ?DIST_PROTO}),
+ receive
+ {NetKernel, controller, Controller} ->
+ call_dist_ctrl(DistCtrl, {controller, Controller, self()}),
+ Controller ! {self(), controller, Socket};
+ {NetKernel, unsupported_protocol} ->
+ exit(unsupported_protocol)
+ end,
+ accept_loop(Listen, Driver, NetKernel);
+ AcceptError ->
+ exit({accept, AcceptError})
+ end.
+
+wait_for_code_server() ->
+ %% This is an ugly hack. Starting encryption on a connection
+ %% requires the crypto module to be loaded. Loading the crypto
+ %% module triggers its on_load function, which calls
+ %% code:priv_dir/1 to find the directory where its NIF library is.
+ %% However, distribution is started earlier than the code server,
+ %% so the code server is not necessarily started yet, and
+ %% code:priv_dir/1 might fail because of that, if we receive
+ %% an incoming connection on the distribution port early enough.
+ %%
+ %% If the on_load function of a module fails, the module is
+ %% unloaded, and the function call that triggered loading it fails
+ %% with 'undef', which is rather confusing.
+ %%
+ %% So let's avoid that by waiting for the code server to start.
+ %%
+ case whereis(code_server) of
+ undefined ->
+ timer:sleep(10),
+ wait_for_code_server();
+ Pid when is_pid(Pid) ->
+ ok
+ end.
+
+%% -------------------------------------------------------------------------
+%% Called by net_kernel when a new connection has appeared, to spawn
+%% a Controller process that performs the handshake with the new node,
+%% and then becomes the Ticker connection supervisor.
+%% -------------------------------------------------------------------------
+
+accept_connection(Acceptor, DistCtrl, MyNode, Allowed, SetupTime) ->
+ gen_accept_connection(
+ Acceptor, DistCtrl, MyNode, Allowed, SetupTime, ?DRIVER).
+
+gen_accept_connection(
+ Acceptor, DistCtrl, MyNode, Allowed, SetupTime, Driver) ->
+ NetKernel = self(),
+ %%
+ %% Spawn Controller/handshaker/ticker process
+ %%
+ monitor_dist_proc(
+ spawn_opt(
+ fun() ->
+ do_accept(
+ Acceptor, DistCtrl,
+ trace(MyNode), Allowed, SetupTime, Driver, NetKernel)
+ end,
+ [link, {priority, max}])).
+
+do_accept(
+ Acceptor, DistCtrl, MyNode, Allowed, SetupTime, Driver, NetKernel) ->
+ %%
+ receive
+ {Acceptor, controller, Socket} ->
+ Timer = dist_util:start_timer(SetupTime),
+ HSData =
+ hs_data_common(
+ NetKernel, MyNode, DistCtrl, Timer,
+ Socket, Driver:family()),
+ HSData_1 =
+ HSData#hs_data{
+ this_node = MyNode,
+ this_flags = 0,
+ allowed = Allowed},
+ dist_util:handshake_other_started(trace(HSData_1))
+ end.
+
+%% -------------------------------------------------------------------------
+%% Called by net_kernel to spawn a Controller process that sets up
+%% a new connection to another Erlang node, performs the handshake
+%% with the other it, and then becomes the Ticker process
+%% that supervises the connection.
+%% -------------------------------------------------------------------------
+
+setup(Node, Type, MyNode, LongOrShortNames, SetupTime) ->
+ gen_setup(Node, Type, MyNode, LongOrShortNames, SetupTime, ?DRIVER).
+
+gen_setup(Node, Type, MyNode, LongOrShortNames, SetupTime, Driver) ->
+ NetKernel = self(),
+ %%
+ %% Spawn Controller/handshaker/ticker process
+ %%
+ monitor_dist_proc(
+ spawn_opt(
+ setup_fun(
+ Node, Type, MyNode, LongOrShortNames, SetupTime, Driver, NetKernel),
+ [link, {priority, max}])).
+
+-spec setup_fun(_,_,_,_,_,_,_) -> fun(() -> no_return()).
+setup_fun(
+ Node, Type, MyNode, LongOrShortNames, SetupTime, Driver, NetKernel) ->
+ %%
+ fun() ->
+ do_setup(
+ trace(Node), Type, MyNode, LongOrShortNames, SetupTime,
+ Driver, NetKernel)
+ end.
+
+-spec do_setup(_,_,_,_,_,_,_) -> no_return().
+do_setup(
+ Node, Type, MyNode, LongOrShortNames, SetupTime, Driver, NetKernel) ->
+ %%
+ {Name, Address} = split_node(Driver, Node, LongOrShortNames),
+ ErlEpmd = net_kernel:epmd_module(),
+ {ARMod, ARFun} = get_address_resolver(ErlEpmd, Driver),
+ Timer = trace(dist_util:start_timer(SetupTime)),
+ case ARMod:ARFun(Name, Address, Driver:family()) of
+ {ok, Ip, TcpPort, Version} ->
+ do_setup_connect(
+ Node, Type, MyNode, Timer, Driver, NetKernel,
+ Ip, TcpPort, Version);
+ {ok, Ip} ->
+ case ErlEpmd:port_please(Name, Ip) of
+ {port, TcpPort, Version} ->
+ do_setup_connect(
+ Node, Type, MyNode, Timer, Driver, NetKernel,
+ Ip, TcpPort, trace(Version));
+ Other ->
+ _ = trace(
+ {ErlEpmd, port_please, [Name, Ip], Other}),
+ ?shutdown(Node)
+ end;
+ Other ->
+ _ = trace(
+ {ARMod, ARFun, [Name, Address, Driver:family()],
+ Other}),
+ ?shutdown(Node)
+ end.
+
+-spec do_setup_connect(_,_,_,_,_,_,_,_,_) -> no_return().
+
+do_setup_connect(
+ Node, Type, MyNode, Timer, Driver, NetKernel,
+ Ip, TcpPort, Version) ->
+ dist_util:reset_timer(Timer),
+ ConnectOpts = trace(connect_options(socket_options())),
+ case Driver:connect(Ip, TcpPort, ConnectOpts) of
+ {ok, Socket} ->
+ DistCtrl =
+ try start_dist_ctrl(Socket, net_kernel:connecttime())
+ catch error : {dist_ctrl, _} = DistCtrlError ->
+ _ = trace(DistCtrlError),
+ ?shutdown(Node)
+ end,
+ %% DistCtrl is a "socket"
+ HSData =
+ hs_data_common(
+ NetKernel, MyNode, DistCtrl, Timer,
+ Socket, Driver:family()),
+ HSData_1 =
+ HSData#hs_data{
+ other_node = Node,
+ this_flags = 0,
+ other_version = Version,
+ request_type = Type},
+ dist_util:handshake_we_started(trace(HSData_1));
+ ConnectError ->
+ _ = trace(
+ {Driver, connect, [Ip, TcpPort, ConnectOpts],
+ ConnectError}),
+ ?shutdown(Node)
+ end.
+
+%% -------------------------------------------------------------------------
+%% close/1 is only called by net_kernel on the socket returned by listen/1.
+
+close(Socket) ->
+ gen_close(Socket, ?DRIVER).
+
+gen_close(Socket, Driver) ->
+ Driver:close(trace(Socket)).
+
+%% -------------------------------------------------------------------------
+
+
+hs_data_common(NetKernel, MyNode, DistCtrl, Timer, Socket, Family) ->
+ %% Field 'socket' below is set to DistCtrl, which makes
+ %% the distribution handshake process (ticker) call
+ %% the funs below with DistCtrl as the S argument.
+ %% So, S =:= DistCtrl below...
+ #hs_data{
+ kernel_pid = NetKernel,
+ this_node = MyNode,
+ socket = DistCtrl,
+ timer = Timer,
+ %%
+ f_send = % -> ok | {error, closed}=>?shutdown()
+ fun (S, Packet) when S =:= DistCtrl ->
+ try call_dist_ctrl(S, {send, Packet})
+ catch error : {dist_ctrl, Reason} ->
+ _ = trace(Reason),
+ {error, closed}
+ end
+ end,
+ f_recv = % -> {ok, List} | Other=>?shutdown()
+ fun (S, 0, infinity) when S =:= DistCtrl ->
+ try call_dist_ctrl(S, recv) of
+ {ok, Bin} when is_binary(Bin) ->
+ {ok, binary_to_list(Bin)};
+ Error ->
+ Error
+ catch error : {dist_ctrl, Reason} ->
+ {error, trace(Reason)}
+ end
+ end,
+ f_setopts_pre_nodeup =
+ fun (S) when S =:= DistCtrl ->
+ ok
+ end,
+ f_setopts_post_nodeup =
+ fun (S) when S =:= DistCtrl ->
+ ok
+ end,
+ f_getll =
+ fun (S) when S =:= DistCtrl ->
+ {ok, S} %% DistCtrl is the distribution port
+ end,
+ f_address = % -> #net_address{} | ?shutdown()
+ fun (S, Node) when S =:= DistCtrl ->
+ try call_dist_ctrl(S, peername) of
+ {ok, Address} ->
+ case dist_util:split_node(Node) of
+ {node, _, Host} ->
+ #net_address{
+ address = Address,
+ host = Host,
+ protocol = ?DIST_PROTO,
+ family = Family};
+ _ ->
+ ?shutdown(Node)
+ end;
+ Error ->
+ _ = trace(Error),
+ ?shutdown(Node)
+ catch error : {dist_ctrl, Reason} ->
+ _ = trace(Reason),
+ ?shutdown(Node)
+ end
+ end,
+ f_handshake_complete = % -> ok | ?shutdown()
+ fun (S, Node, DistHandle) when S =:= DistCtrl ->
+ try call_dist_ctrl(S, {handshake_complete, DistHandle})
+ catch error : {dist_ctrl, Reason} ->
+ _ = trace(Reason),
+ ?shutdown(Node)
+ end
+ end,
+ %%
+ %% mf_tick/1, mf_getstat/1, mf_setopts/2 and mf_getopts/2
+ %% are called by the ticker any time after f_handshake_complete/3
+ %% so they may not block the caller even for congested socket
+ mf_tick =
+ fun (S) when S =:= DistCtrl ->
+ S ! dist_tick
+ end,
+ mf_getstat = % -> {ok, RecvCnt, SendCnt, SendPend} | Other=>ignore_it
+ fun (S) when S =:= DistCtrl ->
+ case
+ inet:getstat(Socket, [recv_cnt, send_cnt, send_pend])
+ of
+ {ok, Stat} ->
+ split_stat(Stat, 0, 0, 0);
+ Error ->
+ trace(Error)
+ end
+ end,
+ mf_setopts =
+ fun (S, Opts) when S =:= DistCtrl ->
+ inet:setopts(Socket, setopts_filter(Opts))
+ end,
+ mf_getopts =
+ fun (S, Opts) when S =:= DistCtrl ->
+ inet:getopts(Socket, Opts)
+ end}.
+
+setopts_filter(Opts) ->
+ [Opt ||
+ Opt <- Opts,
+ case Opt of
+ {K, _} when K =:= active; K =:= deliver; K =:= packet -> false;
+ K when K =:= list; K =:= binary -> false;
+ K when K =:= inet; K =:= inet6 -> false;
+ _ -> true
+ end].
+
+split_stat([{recv_cnt, R}|Stat], _, W, P) ->
+ split_stat(Stat, R, W, P);
+split_stat([{send_cnt, W}|Stat], R, _, P) ->
+ split_stat(Stat, R, W, P);
+split_stat([{send_pend, P}|Stat], R, W, _) ->
+ split_stat(Stat, R, W, P);
+split_stat([], R, W, P) ->
+ {ok, R, W, P}.
+
+%% ------------------------------------------------------------
+%% Determine if EPMD module supports address resolving. Default
+%% is to use inet_tcp:getaddr/2.
+%% ------------------------------------------------------------
+get_address_resolver(EpmdModule, _Driver) ->
+ case erlang:function_exported(EpmdModule, address_please, 3) of
+ true -> {EpmdModule, address_please};
+ _ -> {erl_epmd, address_please}
+ end.
+
+
+%% If Node is illegal terminate the connection setup!!
+split_node(Driver, Node, LongOrShortNames) ->
+ case dist_util:split_node(Node) of
+ {node, Name, Host} ->
+ check_node(Driver, Node, Name, Host, LongOrShortNames);
+ {host, _} ->
+ error_logger:error_msg(
+ "** Nodename ~p illegal, no '@' character **~n",
+ [Node]),
+ ?shutdown2(Node, trace({illegal_node_n@me, Node}));
+ _ ->
+ error_logger:error_msg(
+ "** Nodename ~p illegal **~n", [Node]),
+ ?shutdown2(Node, trace({illegal_node_name, Node}))
+ end.
+
+check_node(Driver, Node, Name, Host, LongOrShortNames) ->
+ case string:split(Host, ".", all) of
+ [_] when LongOrShortNames =:= longnames ->
+ case Driver:parse_address(Host) of
+ {ok, _} ->
+ {Name, Host};
+ _ ->
+ error_logger:error_msg(
+ "** System running to use "
+ "fully qualified hostnames **~n"
+ "** Hostname ~s is illegal **~n",
+ [Host]),
+ ?shutdown2(Node, trace({not_longnames, Host}))
+ end;
+ [_, _|_] when LongOrShortNames =:= shortnames ->
+ error_logger:error_msg(
+ "** System NOT running to use "
+ "fully qualified hostnames **~n"
+ "** Hostname ~s is illegal **~n",
+ [Host]),
+ ?shutdown2(Node, trace({not_shortnames, Host}));
+ _ ->
+ {Name, Host}
+ end.
+
+%% -------------------------------------------------------------------------
+
+connect_options(Opts) ->
+ case application:get_env(kernel, inet_dist_connect_options) of
+ {ok, ConnectOpts} ->
+ Opts ++ setopts_filter(ConnectOpts);
+ _ ->
+ Opts
+ end.
+
+%% we may not always want the nodelay behaviour
+%% for performance reasons
+nodelay() ->
+ case application:get_env(kernel, dist_nodelay) of
+ undefined ->
+ {nodelay, true};
+ {ok, true} ->
+ {nodelay, true};
+ {ok, false} ->
+ {nodelay, false};
+ _ ->
+ {nodelay, true}
+ end.
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% The DistCtrl process(es).
+%%
+%% At net_kernel handshake_complete spawns off the input controller that
+%% takes over the socket ownership, and itself becomes the output controller
+%%
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%% XXX Missing to "productified":
+%%% * Cryptoanalysis by experts, this is crypto amateur work.
+%%% * Is it useful over inet_tls_dist; i.e to not have to bother
+%%% with certificates but instead manage a secret cluster cookie?
+%%% * An application to belong to (kernel)
+%%% * Restart and/or code reload policy (not needed in kernel)
+%%% * Fitting into the epmd/Erlang distro protocol version framework
+%%% (something needs to be created for multiple protocols, epmd,
+%%% multiple address families, fallback to previous version, etc)
+
+
+%% Debug client and server
+
+test_server() ->
+ {ok, Listen} = gen_tcp:listen(0, socket_options()),
+ {ok, Port} = inet:port(Listen),
+ io:format(?MODULE_STRING":test_client(~w).~n", [Port]),
+ {ok, Socket} = gen_tcp:accept(Listen),
+ test(Socket).
+
+test_client(Port) ->
+ {ok, Socket} = gen_tcp:connect(localhost, Port, socket_options()),
+ test(Socket).
+
+test(Socket) ->
+ start_dist_ctrl(Socket, 10000).
+
+%% -------------------------------------------------------------------------
+
+start_dist_ctrl(Socket, Timeout) ->
+ Secret = atom_to_binary(auth:get_cookie(), latin1),
+ Controller = self(),
+ Server =
+ monitor_dist_proc(
+ spawn_opt(
+ fun () ->
+ receive
+ {?MODULE, From, start} ->
+ {SendParams, RecvParams} =
+ init(Socket, Secret),
+ reply(From, self()),
+ handshake(SendParams, 1, RecvParams, 1, Controller)
+ end
+ end,
+ [link,
+ {priority, max},
+ {message_queue_data, off_heap},
+ {fullsweep_after, 0}])),
+ ok = gen_tcp:controlling_process(Socket, Server),
+ call_dist_ctrl(Server, start, Timeout).
+
+
+call_dist_ctrl(Server, Msg) ->
+ call_dist_ctrl(Server, Msg, infinity).
+%%
+call_dist_ctrl(Server, Msg, Timeout) ->
+ Ref = erlang:monitor(process, Server),
+ Server ! {?MODULE, {Ref, self()}, Msg},
+ receive
+ {Ref, Res} ->
+ erlang:demonitor(Ref, [flush]),
+ Res;
+ {'DOWN', Ref, process, Server, Reason} ->
+ error({dist_ctrl, Reason})
+ after Timeout -> % Timeout < infinity is only used by start_dist_ctrl/2
+ receive
+ {'DOWN', Ref, process, Server, _} ->
+ receive {Ref, _} -> ok after 0 -> ok end,
+ error({dist_ctrl, timeout})
+ %% Server will be killed by link
+ end
+ end.
+
+reply({Ref, Pid}, Msg) ->
+ Pid ! {Ref, Msg},
+ ok.
+
+%% -------------------------------------------------------------------------
+
+-define(TCP_ACTIVE, 16).
+-define(CHUNK_SIZE, (?PACKET_SIZE - 512)).
+
+-define(HANDSHAKE_CHUNK, 1).
+-define(DATA_CHUNK, 2).
+-define(TICK_CHUNK, 3).
+-define(REKEY_CHUNK, 4).
+
+%% -------------------------------------------------------------------------
+%% Crypto strategy
+%% -------
+%% The crypto strategy is as simple as possible to get an encrypted
+%% connection as benchmark reference. It is geared around AEAD
+%% ciphers in particular AES-GCM.
+%%
+%% The init message and the start message must fit in the TCP buffers
+%% since both sides start with sending the init message, waits
+%% for the other end's init message, sends the start message
+%% and waits for the other end's start message. So if the send
+%% blocks we have a deadlock.
+%%
+%% The init + start sequence tries to implement Password Encrypted
+%% Key Exchange using a node public/private key pair and the
+%% shared secret (the Cookie) to create session encryption keys
+%% that can not be re-created if the shared secret is compromized,
+%% which should create forward secrecy. You need both nodes'
+%% key pairs and the shared secret to decrypt the traffic
+%% between the nodes.
+%%
+%% All exchanged messages uses {packet, 2} i.e 16 bit size header.
+%%
+%% The init message contains a random number and encrypted: the public key
+%% and two random numbers. The encryption is done with Key and IV hashed
+%% from the unencrypted random number and the shared secret.
+%%
+%% The other node's public key is used with the own node's private
+%% key to create a shared key that is hashed with one of the encrypted
+%% random numbers from each side to create Key and IV for the session.
+%%
+%% The start message contains the two encrypted random numbers
+%% this time encrypted with the session keys for verification
+%% by the other side, plus the rekey interval. The rekey interval
+%% is just there to get an early check for if the other side's
+%% maximum rekey interal is acceptable, it is just an embryo
+%% of some better check. Any side may rekey earlier but if the
+%% rekey interval is exceeded the connection fails.
+%%
+%% Subsequent encrypted messages has the sequence number and the length
+%% of the message as AAD data, and an incrementing IV. These messages
+%% has got a message type that differentiates data from ticks and rekeys.
+%% Ticks have a random size in an attempt to make them less obvious to spot.
+%%
+%% Rekeying is done by the sender that creates a new key pair and
+%% a new shared secret from the other end's public key and with
+%% this and the current key and iv hashes a new key and iv.
+%% The new public key is sent to the other end that uses it
+%% and its old private key to create the same new shared
+%% secret and from that a new key and iv.
+%% So the receiver keeps its private key, and the sender keeps
+%% the receivers public key for the connection's life time.
+%% While the sender generates a new key pair at every rekey,
+%% which changes the shared secret at every rekey.
+%%
+%% The only reaction to errors is to crash noisily (?) wich will bring
+%% down the connection and hopefully produce something useful
+%% in the local log, but all the other end sees is a closed connection.
+%% -------------------------------------------------------------------------
+
+init(Socket, Secret) ->
+ #key_pair{public = PubKey} = KeyPair = get_key_pair(),
+ Params = params(Socket),
+ {R2, R3, Msg} = init_msg(Params, PubKey, Secret),
+ ok = gen_tcp:send(Socket, Msg),
+ init_recv(Params, Secret, KeyPair, R2, R3).
+
+init_recv(
+ #params{socket = Socket, iv = IVLen} = Params, Secret, KeyPair, R2, R3) ->
+ %%
+ {ok, InitMsg} = gen_tcp:recv(Socket, 0),
+ IVSaltLen = IVLen - 6,
+ try
+ case init_msg(Params, Secret, KeyPair, R2, R3, InitMsg) of
+ {#params{iv = <<IV2ASalt:IVSaltLen/binary, IV2ANo:48>>} =
+ SendParams,
+ RecvParams, SendStartMsg} ->
+ ok = gen_tcp:send(Socket, SendStartMsg),
+ {ok, RecvStartMsg} = gen_tcp:recv(Socket, 0),
+ #params{
+ iv = <<IV2BSalt:IVSaltLen/binary, IV2BNo:48>>} =
+ RecvParams_1 =
+ start_msg(RecvParams, R2, R3, RecvStartMsg),
+ {SendParams#params{iv = {IV2ASalt, IV2ANo}},
+ RecvParams_1#params{iv = {IV2BSalt, IV2BNo}}}
+ end
+ catch
+ error : Reason : Stacktrace->
+ _ = trace({Reason, Stacktrace}),
+ exit(connection_closed)
+ end.
+
+
+
+init_msg(
+ #params{
+ hmac_algorithm = HmacAlgo,
+ aead_cipher = AeadCipher,
+ key = KeyLen,
+ iv = IVLen,
+ tag_len = TagLen}, PubKeyA, Secret) ->
+ %%
+ RLen = KeyLen + IVLen,
+ <<R1A:RLen/binary, R2A:RLen/binary, R3A:RLen/binary>> =
+ crypto:strong_rand_bytes(3 * RLen),
+ {Key1A, IV1A} = hmac_key_iv(HmacAlgo, R1A, Secret, KeyLen, IVLen),
+ Plaintext = [R2A, R3A, PubKeyA],
+ MsgLen = byte_size(R1A) + TagLen + iolist_size(Plaintext),
+ AAD = [<<MsgLen:32>>, R1A],
+ {Ciphertext, Tag} =
+ crypto:block_encrypt(AeadCipher, Key1A, IV1A, {AAD, Plaintext, TagLen}),
+ Msg = [R1A, Tag, Ciphertext],
+ {R2A, R3A, Msg}.
+%%
+init_msg(
+ #params{
+ hmac_algorithm = HmacAlgo,
+ aead_cipher = AeadCipher,
+ key = KeyLen,
+ iv = IVLen,
+ tag_len = TagLen,
+ rekey_interval = RekeyInterval} = Params,
+ Secret, KeyPair, R2A, R3A, Msg) ->
+ %%
+ RLen = KeyLen + IVLen,
+ case Msg of
+ <<R1B:RLen/binary, Tag:TagLen/binary, Ciphertext/binary>> ->
+ {Key1B, IV1B} = hmac_key_iv(HmacAlgo, R1B, Secret, KeyLen, IVLen),
+ MsgLen = byte_size(Msg),
+ AAD = [<<MsgLen:32>>, R1B],
+ case
+ crypto:block_decrypt(
+ AeadCipher, Key1B, IV1B, {AAD, Ciphertext, Tag})
+ of
+ <<R2B:RLen/binary, R3B:RLen/binary, PubKeyB/binary>> ->
+ SharedSecret = compute_shared_secret(KeyPair, PubKeyB),
+ %%
+ {Key2A, IV2A} =
+ hmac_key_iv(
+ HmacAlgo, SharedSecret, [R2A, R3B], KeyLen, IVLen),
+ SendParams =
+ Params#params{
+ rekey_key = PubKeyB,
+ key = Key2A, iv = IV2A},
+ %%
+ StartCleartext = [R2B, R3B, <<RekeyInterval:32>>],
+ StartMsgLen = TagLen + iolist_size(StartCleartext),
+ StartAAD = <<StartMsgLen:32>>,
+ {StartCiphertext, StartTag} =
+ crypto:block_encrypt(
+ AeadCipher, Key2A, IV2A,
+ {StartAAD, StartCleartext, TagLen}),
+ StartMsg = [StartTag, StartCiphertext],
+ %%
+ {Key2B, IV2B} =
+ hmac_key_iv(
+ HmacAlgo, SharedSecret, [R2B, R3A], KeyLen, IVLen),
+ RecvParams =
+ Params#params{
+ rekey_key = KeyPair,
+ key = Key2B, iv = IV2B},
+ %%
+ {SendParams, RecvParams, StartMsg}
+ end
+ end.
+
+start_msg(
+ #params{
+ aead_cipher = AeadCipher,
+ key = Key2B,
+ iv = IV2B,
+ tag_len = TagLen,
+ rekey_interval = RekeyIntervalA} = RecvParams, R2A, R3A, Msg) ->
+ %%
+ case Msg of
+ <<Tag:TagLen/binary, Ciphertext/binary>> ->
+ KeyLen = byte_size(Key2B),
+ IVLen = byte_size(IV2B),
+ RLen = KeyLen + IVLen,
+ MsgLen = byte_size(Msg),
+ AAD = <<MsgLen:32>>,
+ case
+ crypto:block_decrypt(
+ AeadCipher, Key2B, IV2B, {AAD, Ciphertext, Tag})
+ of
+ <<R2A:RLen/binary, R3A:RLen/binary, RekeyIntervalB:32>>
+ when RekeyIntervalA =< (RekeyIntervalB bsl 2),
+ RekeyIntervalB =< (RekeyIntervalA bsl 2) ->
+ RecvParams#params{rekey_interval = RekeyIntervalB}
+ end
+ end.
+
+hmac_key_iv(HmacAlgo, MacKey, Data, KeyLen, IVLen) ->
+ <<Key:KeyLen/binary, IV:IVLen/binary>> =
+ crypto:hmac(HmacAlgo, MacKey, Data, KeyLen + IVLen),
+ {Key, IV}.
+
+%% -------------------------------------------------------------------------
+%% net_kernel distribution handshake in progress
+%%
+
+handshake(
+ SendParams, SendSeq,
+ #params{socket = Socket} = RecvParams, RecvSeq, Controller) ->
+ receive
+ {?MODULE, From, {controller, Controller_1, Parent}} ->
+ Result = link(Controller_1),
+ true = unlink(Parent),
+ reply(From, Result),
+ handshake(SendParams, SendSeq, RecvParams, RecvSeq, Controller_1);
+ {?MODULE, From, {handshake_complete, DistHandle}} ->
+ InputHandler =
+ monitor_dist_proc(
+ spawn_opt(
+ fun () ->
+ link(Controller),
+ receive
+ DistHandle ->
+ ok =
+ inet:setopts(
+ Socket,
+ [{active, ?TCP_ACTIVE},
+ nodelay()]),
+ input_handler(
+ RecvParams#params{
+ dist_handle = DistHandle},
+ RecvSeq, empty_q(), infinity)
+ end
+ end,
+ [link,
+ {priority, normal},
+ {message_queue_data, off_heap},
+ {fullsweep_after, 0}])),
+ _ = monitor(process, InputHandler), % For the benchmark test
+ ok = gen_tcp:controlling_process(Socket, InputHandler),
+ ok = erlang:dist_ctrl_input_handler(DistHandle, InputHandler),
+ InputHandler ! DistHandle,
+ crypto:rand_seed_alg(crypto_cache),
+ reply(From, ok),
+ process_flag(priority, normal),
+ erlang:dist_ctrl_get_data_notification(DistHandle),
+ output_handler(
+ SendParams#params{dist_handle = DistHandle}, SendSeq);
+ %%
+ {?MODULE, From, {send, Data}} ->
+ case
+ encrypt_and_send_chunk(
+ SendParams, SendSeq, [?HANDSHAKE_CHUNK, Data])
+ of
+ {SendParams_1, SendSeq_1, ok} ->
+ reply(From, ok),
+ handshake(
+ SendParams_1, SendSeq_1, RecvParams, RecvSeq,
+ Controller);
+ {_, _, Error} ->
+ reply(From, {error, closed}),
+ death_row({send, trace(Error)})
+ end;
+ {?MODULE, From, recv} ->
+ case recv_and_decrypt_chunk(RecvParams, RecvSeq) of
+ {RecvParams_1, RecvSeq_1, {ok, _} = Reply} ->
+ reply(From, Reply),
+ handshake(
+ SendParams, SendSeq, RecvParams_1, RecvSeq_1,
+ Controller);
+ {_, _, Error} ->
+ reply(From, Error),
+ death_row({recv, trace(Error)})
+ end;
+ {?MODULE, From, peername} ->
+ reply(From, inet:peername(Socket)),
+ handshake(SendParams, SendSeq, RecvParams, RecvSeq, Controller);
+ %%
+ _Alien ->
+ handshake(SendParams, SendSeq, RecvParams, RecvSeq, Controller)
+ end.
+
+recv_and_decrypt_chunk(#params{socket = Socket} = RecvParams, RecvSeq) ->
+ case gen_tcp:recv(Socket, 0) of
+ {ok, Chunk} ->
+ case decrypt_chunk(RecvParams, RecvSeq, Chunk) of
+ <<?HANDSHAKE_CHUNK, Cleartext/binary>> ->
+ {RecvParams, RecvSeq + 1, {ok, Cleartext}};
+ OtherChunk when is_binary(OtherChunk) ->
+ {RecvParams, RecvSeq + 1, {error, decrypt_error}};
+ #params{} = RecvParams_1 ->
+ recv_and_decrypt_chunk(RecvParams_1, 0);
+ error ->
+ {RecvParams, RecvSeq, {error, decrypt_error}}
+ end;
+ Error ->
+ {RecvParams, RecvSeq, Error}
+ end.
+
+%% -------------------------------------------------------------------------
+%% Output handler process
+%%
+%% The game here is to flush all dist_data and dist_tick messages,
+%% prioritize dist_data over dist_tick, and to not use selective receive
+
+output_handler(Params, Seq) ->
+ receive
+ Msg ->
+ case Msg of
+ dist_data ->
+ output_handler_data(Params, Seq);
+ dist_tick ->
+ output_handler_tick(Params, Seq);
+ Other ->
+ %% Ignore
+ _ = trace(Other),
+ output_handler(Params, Seq)
+ end
+ end.
+
+output_handler_data(Params, Seq) ->
+ receive
+ Msg ->
+ case Msg of
+ dist_data ->
+ output_handler_data(Params, Seq);
+ dist_tick ->
+ output_handler_data(Params, Seq);
+ Other ->
+ %% Ignore
+ _ = trace(Other),
+ output_handler_data(Params, Seq)
+ end
+ after 0 ->
+ DistHandle = Params#params.dist_handle,
+ Q = get_data(DistHandle, empty_q()),
+ {Params_1, Seq_1} = output_handler_send(Params, Seq, Q),
+ erlang:dist_ctrl_get_data_notification(DistHandle),
+ output_handler(Params_1, Seq_1)
+ end.
+
+output_handler_tick(Params, Seq) ->
+ receive
+ Msg ->
+ case Msg of
+ dist_data ->
+ output_handler_data(Params, Seq);
+ dist_tick ->
+ output_handler_tick(Params, Seq);
+ Other ->
+ %% Ignore
+ _ = trace(Other),
+ output_handler_tick(Params, Seq)
+ end
+ after 0 ->
+ TickSize = 7 + rand:uniform(56),
+ TickData = binary:copy(<<0>>, TickSize),
+ case
+ encrypt_and_send_chunk(Params, Seq, [?TICK_CHUNK, TickData])
+ of
+ {Params_1, Seq_1, ok} ->
+ output_handler(Params_1, Seq_1);
+ {_, _, Error} ->
+ _ = trace(Error),
+ death_row()
+ end
+ end.
+
+output_handler_send(Params, Seq, {_, Size, _} = Q) ->
+ if
+ ?CHUNK_SIZE < Size ->
+ output_handler_send(Params, Seq, Q, ?CHUNK_SIZE);
+ true ->
+ case get_data(Params#params.dist_handle, Q) of
+ {_, 0, _} ->
+ {Params, Seq};
+ {_, Size, _} = Q_1 -> % Got no more
+ output_handler_send(Params, Seq, Q_1, Size);
+ Q_1 ->
+ output_handler_send(Params, Seq, Q_1)
+ end
+ end.
+
+output_handler_send(Params, Seq, Q, Size) ->
+ {Cleartext, Q_1} = deq_iovec(Size, Q),
+ case
+ encrypt_and_send_chunk(Params, Seq, [?DATA_CHUNK, Cleartext])
+ of
+ {Params_1, Seq_1, ok} ->
+ output_handler_send(Params_1, Seq_1, Q_1);
+ {_, _, Error} ->
+ _ = trace(Error),
+ death_row()
+ end.
+
+%% -------------------------------------------------------------------------
+%% Input handler process
+%%
+%% Here is T = 0|infinity to steer if we should try to receive
+%% more data or not; start with infinity, and when we get some
+%% data try with 0 to see if more is waiting
+
+input_handler(#params{socket = Socket} = Params, Seq, Q, T) ->
+ receive
+ Msg ->
+ case Msg of
+ {tcp_passive, Socket} ->
+ ok = inet:setopts(Socket, [{active, ?TCP_ACTIVE}]),
+ Q_1 =
+ case T of
+ 0 ->
+ deliver_data(Params#params.dist_handle, Q);
+ infinity ->
+ Q
+ end,
+ input_handler(Params, Seq, Q_1, infinity);
+ {tcp, Socket, Chunk} ->
+ input_chunk(Params, Seq, Q, T, Chunk);
+ {tcp_closed, Socket} ->
+ exit(connection_closed);
+ Other ->
+ %% Ignore...
+ _ = trace(Other),
+ input_handler(Params, Seq, Q, T)
+ end
+ after T ->
+ Q_1 = deliver_data(Params#params.dist_handle, Q),
+ input_handler(Params, Seq, Q_1, infinity)
+ end.
+
+input_chunk(Params, Seq, Q, T, Chunk) ->
+ case decrypt_chunk(Params, Seq, Chunk) of
+ <<?DATA_CHUNK, Cleartext/binary>> ->
+ input_handler(Params, Seq + 1, enq_binary(Cleartext, Q), 0);
+ <<?TICK_CHUNK, _/binary>> ->
+ input_handler(Params, Seq + 1, Q, T);
+ OtherChunk when is_binary(OtherChunk) ->
+ _ = trace(invalid_chunk),
+ exit(connection_closed);
+ #params{} = Params_1 ->
+ input_handler(Params_1, 0, Q, T);
+ error ->
+ _ = trace(decrypt_error),
+ exit(connection_closed)
+ end.
+
+%% -------------------------------------------------------------------------
+%% erlang:dist_ctrl_* helpers
+
+%% Get data for sending from the VM and place it in a queue
+%%
+get_data(DistHandle, {Front, Size, Rear}) ->
+ get_data(DistHandle, Front, Size, Rear).
+%%
+get_data(DistHandle, Front, Size, Rear) ->
+ case erlang:dist_ctrl_get_data(DistHandle) of
+ none ->
+ {Front, Size, Rear};
+ Bin when is_binary(Bin) ->
+ Len = byte_size(Bin),
+ get_data(
+ DistHandle, Front, Size + 4 + Len,
+ [Bin, <<Len:32>>|Rear]);
+ [Bin1, Bin2] ->
+ Len = byte_size(Bin1) + byte_size(Bin2),
+ get_data(
+ DistHandle, Front, Size + 4 + Len,
+ [Bin2, Bin1, <<Len:32>>|Rear]);
+ Iovec ->
+ Len = iolist_size(Iovec),
+ get_data(
+ DistHandle, Front, Size + 4 + Len,
+ lists:reverse(Iovec, [<<Len:32>>|Rear]))
+ end.
+
+%% De-packet and deliver received data to the VM from a queue
+%%
+deliver_data(DistHandle, Q) ->
+ case Q of
+ {[], Size, []} ->
+ Size = 0, % Assert
+ Q;
+ {[], Size, Rear} ->
+ [Bin|Front] = lists:reverse(Rear),
+ deliver_data(DistHandle, Front, Size, [], Bin);
+ {[Bin|Front], Size, Rear} ->
+ deliver_data(DistHandle, Front, Size, Rear, Bin)
+ end.
+%%
+deliver_data(DistHandle, Front, Size, Rear, Bin) ->
+ case Bin of
+ <<DataSizeA:32, DataA:DataSizeA/binary,
+ DataSizeB:32, DataB:DataSizeB/binary, Rest/binary>> ->
+ erlang:dist_ctrl_put_data(DistHandle, DataA),
+ erlang:dist_ctrl_put_data(DistHandle, DataB),
+ deliver_data(
+ DistHandle,
+ Front, Size - (4 + DataSizeA + 4 + DataSizeB), Rear,
+ Rest);
+ <<DataSize:32, Data:DataSize/binary, Rest/binary>> ->
+ erlang:dist_ctrl_put_data(DistHandle, Data),
+ deliver_data(DistHandle, Front, Size - (4 + DataSize), Rear, Rest);
+ <<DataSize:32, FirstData/binary>> ->
+ TotalSize = 4 + DataSize,
+ if
+ TotalSize =< Size ->
+ BinSize = byte_size(Bin),
+ {MoreData, Q} =
+ deq_iovec(
+ TotalSize - BinSize,
+ Front, Size - BinSize, Rear),
+ erlang:dist_ctrl_put_data(DistHandle, [FirstData|MoreData]),
+ deliver_data(DistHandle, Q);
+ true -> % Incomplete data
+ {[Bin|Front], Size, Rear}
+ end;
+ <<_/binary>> ->
+ BinSize = byte_size(Bin),
+ if
+ 4 =< Size -> % Fragmented header - extract a header bin
+ {RestHeader, {Front_1, _Size_1, Rear_1}} =
+ deq_iovec(4 - BinSize, Front, Size - BinSize, Rear),
+ Header = iolist_to_binary([Bin|RestHeader]),
+ deliver_data(DistHandle, Front_1, Size, Rear_1, Header);
+ true -> % Incomplete header
+ {[Bin|Front], Size, Rear}
+ end
+ end.
+
+%% -------------------------------------------------------------------------
+%% Encryption and decryption helpers
+
+encrypt_and_send_chunk(
+ #params{
+ socket = Socket,
+ rekey_interval = Seq,
+ rekey_key = PubKeyB,
+ key = Key,
+ iv = {IVSalt, IVNo},
+ hmac_algorithm = HmacAlgo} = Params,
+ Seq, Cleartext) ->
+ %%
+ KeyLen = byte_size(Key),
+ IVSaltLen = byte_size(IVSalt),
+ #key_pair{public = PubKeyA} = KeyPair = get_new_key_pair(),
+ case
+ gen_tcp:send(
+ Socket, encrypt_chunk(Params, Seq, [?REKEY_CHUNK, PubKeyA]))
+ of
+ ok ->
+ SharedSecret = compute_shared_secret(KeyPair, PubKeyB),
+ IV = <<(IVNo + Seq):48>>,
+ {Key_1, <<IVSalt_1:IVSaltLen/binary, IVNo_1:48>>} =
+ hmac_key_iv(
+ HmacAlgo, SharedSecret, [Key, IVSalt, IV],
+ KeyLen, IVSaltLen + 6),
+ Params_1 = Params#params{key = Key_1, iv = {IVSalt_1, IVNo_1}},
+ Result =
+ gen_tcp:send(Socket, encrypt_chunk(Params_1, 0, Cleartext)),
+ {Params_1, 1, Result};
+ SendError ->
+ {Params, Seq + 1, SendError}
+ end;
+encrypt_and_send_chunk(#params{socket = Socket} = Params, Seq, Cleartext) ->
+ Result = gen_tcp:send(Socket, encrypt_chunk(Params, Seq, Cleartext)),
+ {Params, Seq + 1, Result}.
+
+encrypt_chunk(
+ #params{
+ aead_cipher = AeadCipher,
+ iv = {IVSalt, IVNo}, key = Key, tag_len = TagLen}, Seq, Cleartext) ->
+ %%
+ ChunkLen = iolist_size(Cleartext) + TagLen,
+ AAD = <<Seq:32, ChunkLen:32>>,
+ IVBin = <<IVSalt/binary, (IVNo + Seq):48>>,
+ {Ciphertext, CipherTag} =
+ crypto:block_encrypt(AeadCipher, Key, IVBin, {AAD, Cleartext, TagLen}),
+ Chunk = [Ciphertext,CipherTag],
+ Chunk.
+
+decrypt_chunk(
+ #params{
+ aead_cipher = AeadCipher,
+ iv = {IVSalt, IVNo}, key = Key, tag_len = TagLen} = Params, Seq, Chunk) ->
+ %%
+ ChunkLen = byte_size(Chunk),
+ if
+ ChunkLen < TagLen ->
+ error;
+ true ->
+ AAD = <<Seq:32, ChunkLen:32>>,
+ IVBin = <<IVSalt/binary, (IVNo + Seq):48>>,
+ CiphertextLen = ChunkLen - TagLen,
+ case Chunk of
+ <<Ciphertext:CiphertextLen/binary,
+ CipherTag:TagLen/binary>> ->
+ block_decrypt(
+ Params, Seq, AeadCipher, Key, IVBin,
+ {AAD, Ciphertext, CipherTag});
+ _ ->
+ error
+ end
+ end.
+
+block_decrypt(
+ #params{
+ rekey_key = #key_pair{public = PubKeyA} = KeyPair,
+ rekey_interval = RekeyInterval} = Params,
+ Seq, AeadCipher, Key, IV, Data) ->
+ %%
+ case crypto:block_decrypt(AeadCipher, Key, IV, Data) of
+ <<?REKEY_CHUNK, Rest/binary>> ->
+ PubKeyLen = byte_size(PubKeyA),
+ case Rest of
+ <<PubKeyB:PubKeyLen/binary>> ->
+ SharedSecret = compute_shared_secret(KeyPair, PubKeyB),
+ KeyLen = byte_size(Key),
+ IVLen = byte_size(IV),
+ IVSaltLen = IVLen - 6,
+ {Key_1, <<IVSalt:IVSaltLen/binary, IVNo:48>>} =
+ hmac_key_iv(
+ Params#params.hmac_algorithm,
+ SharedSecret, [Key, IV], KeyLen, IVLen),
+ Params#params{iv = {IVSalt, IVNo}, key = Key_1};
+ _ ->
+ error
+ end;
+ Chunk when is_binary(Chunk) ->
+ case Seq of
+ RekeyInterval ->
+ %% This was one chunk too many without rekeying
+ error;
+ _ ->
+ Chunk
+ end;
+ error ->
+ error
+ end.
+
+%% -------------------------------------------------------------------------
+%% Queue of binaries i.e an iovec queue
+
+empty_q() ->
+ {[], 0, []}.
+
+enq_binary(Bin, {Front, Size, Rear}) ->
+ {Front, Size + byte_size(Bin), [Bin|Rear]}.
+
+deq_iovec(GetSize, {Front, Size, Rear}) when GetSize =< Size ->
+ deq_iovec(GetSize, Front, Size, Rear, []).
+%%
+deq_iovec(GetSize, Front, Size, Rear) ->
+ deq_iovec(GetSize, Front, Size, Rear, []).
+%%
+deq_iovec(GetSize, [], Size, Rear, Acc) ->
+ deq_iovec(GetSize, lists:reverse(Rear), Size, [], Acc);
+deq_iovec(GetSize, [Bin|Front], Size, Rear, Acc) ->
+ BinSize = byte_size(Bin),
+ if
+ BinSize < GetSize ->
+ deq_iovec(
+ GetSize - BinSize, Front, Size - BinSize, Rear, [Bin|Acc]);
+ GetSize < BinSize ->
+ {Bin1,Bin2} = erlang:split_binary(Bin, GetSize),
+ {lists:reverse(Acc, [Bin1]), {[Bin2|Front], Size - GetSize, Rear}};
+ true ->
+ {lists:reverse(Acc, [Bin]), {Front, Size - BinSize, Rear}}
+ end.
+
+%% -------------------------------------------------------------------------
+
+death_row() -> death_row(connection_closed).
+%%
+death_row(normal) -> death_row(connection_closed);
+death_row(Reason) -> receive after 5000 -> exit(Reason) end.
+
+%% -------------------------------------------------------------------------
+
+%% Trace point
+trace(Term) -> Term.
+
+%% Keep an eye on this Pid (debug)
+-ifndef(undefined).
+monitor_dist_proc(Pid) ->
+ Pid.
+-else.
+monitor_dist_proc(Pid) ->
+ spawn(
+ fun () ->
+ MRef = erlang:monitor(process, Pid),
+ receive
+ {'DOWN', MRef, _, _, normal} ->
+ error_logger:error_report(
+ [dist_proc_died,
+ {reason, normal},
+ {pid, Pid}]);
+ {'DOWN', MRef, _, _, Reason} ->
+ error_logger:info_report(
+ [dist_proc_died,
+ {reason, Reason},
+ {pid, Pid}])
+ end
+ end),
+ Pid.
+-endif.
+
+dbg() ->
+ dbg:stop(),
+ dbg:tracer(),
+ dbg:p(all, c),
+ dbg:tpl(?MODULE, trace, cx),
+ dbg:tpl(erlang, dist_ctrl_get_data_notification, cx),
+ dbg:tpl(erlang, dist_ctrl_get_data, cx),
+ dbg:tpl(erlang, dist_ctrl_put_data, cx),
+ ok.
diff --git a/lib/ssl/test/make_certs.erl b/lib/ssl/test/make_certs.erl
index ecbacc1590..76bf0fa895 100644
--- a/lib/ssl/test/make_certs.erl
+++ b/lib/ssl/test/make_certs.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -19,7 +19,7 @@
%%
-module(make_certs).
--compile([export_all]).
+-compile([export_all, nowarn_export_all]).
%-export([all/1, all/2, rootCA/2, intermediateCA/3, endusers/3, enduser/3, revoke/3, gencrl/2, verify/3]).
@@ -34,14 +34,15 @@
ecc_certs = false,
issuing_distribution_point = false,
crl_port = 8000,
- openssl_cmd = "openssl"}).
+ openssl_cmd = "openssl",
+ hostname = "host.example.com"}).
default_config() ->
- #config{}.
+ #config{hostname = net_adm:localhost()}.
make_config(Args) ->
- make_config(Args, #config{}).
+ make_config(Args, default_config()).
make_config([], C) ->
C;
@@ -66,7 +67,9 @@ make_config([{ecc_certs, Bool}|T], C) when is_boolean(Bool) ->
make_config([{issuing_distribution_point, Bool}|T], C) when is_boolean(Bool) ->
make_config(T, C#config{issuing_distribution_point = Bool});
make_config([{openssl_cmd, Cmd}|T], C) when is_list(Cmd) ->
- make_config(T, C#config{openssl_cmd = Cmd}).
+ make_config(T, C#config{openssl_cmd = Cmd});
+make_config([{hostname, Hostname}|T], C) when is_list(Hostname) ->
+ make_config(T, C#config{hostname = Hostname}).
all([DataDir, PrivDir]) ->
@@ -186,6 +189,18 @@ gencrl(Root, CA, C, CrlHours) ->
Env = [{"ROOTDIR", filename:absname(Root)}],
cmd(Cmd, Env).
+%% This function sets the number of seconds until the next CRL is due.
+gencrl_sec(Root, CA, C, CrlSecs) ->
+ CACnfFile = filename:join([Root, CA, "ca.cnf"]),
+ CACRLFile = filename:join([Root, CA, "crl.pem"]),
+ Cmd = [C#config.openssl_cmd, " ca"
+ " -gencrl ",
+ " -crlsec ", integer_to_list(CrlSecs),
+ " -out ", CACRLFile,
+ " -config ", CACnfFile],
+ Env = [{"ROOTDIR", filename:absname(Root)}],
+ cmd(Cmd, Env).
+
can_generate_expired_crls(C) ->
%% OpenSSL can generate CRLs with an expiration date in the past,
%% if we pass a negative number for -crlhours. However, LibreSSL
@@ -362,7 +377,7 @@ req_cnf(Root, C) ->
"default_bits = ", integer_to_list(C#config.default_bits), "\n"
"RANDFILE = $ROOTDIR/RAND\n"
"encrypt_key = no\n"
- "default_md = md5\n"
+ "default_md = sha1\n"
"#string_mask = pkix\n"
"x509_extensions = ca_ext\n"
"prompt = no\n"
@@ -384,8 +399,11 @@ req_cnf(Root, C) ->
"subjectKeyIdentifier = hash\n"
"subjectAltName = email:copy\n"].
-ca_cnf(Root, C = #config{issuing_distribution_point = true}) ->
- Hostname = net_adm:localhost(),
+ca_cnf(
+ Root,
+ #config{
+ issuing_distribution_point = true,
+ hostname = Hostname} = C) ->
["# Purpose: Configuration for CAs.\n"
"\n"
"ROOTDIR = " ++ Root ++ "\n"
@@ -409,7 +427,7 @@ ca_cnf(Root, C = #config{issuing_distribution_point = true}) ->
["crl_extensions = crl_ext\n" || C#config.v2_crls],
"unique_subject = no\n"
"default_days = 3600\n"
- "default_md = md5\n"
+ "default_md = sha1\n"
"preserve = no\n"
"policy = policy_match\n"
"\n"
@@ -464,8 +482,12 @@ ca_cnf(Root, C = #config{issuing_distribution_point = true}) ->
"crlDistributionPoints=@crl_section\n"
];
-ca_cnf(Root, C = #config{issuing_distribution_point = false}) ->
- Hostname = net_adm:localhost(),
+ca_cnf(
+ Root,
+ #config{
+ issuing_distribution_point = false,
+ hostname = Hostname
+ } = C) ->
["# Purpose: Configuration for CAs.\n"
"\n"
"ROOTDIR = " ++ Root ++ "\n"
@@ -489,7 +511,7 @@ ca_cnf(Root, C = #config{issuing_distribution_point = false}) ->
["crl_extensions = crl_ext\n" || C#config.v2_crls],
"unique_subject = no\n"
"default_days = 3600\n"
- "default_md = md5\n"
+ "default_md = sha1\n"
"preserve = no\n"
"policy = policy_match\n"
"\n"
diff --git a/lib/ssl/test/openssl_server_cipher_suite_SUITE.erl b/lib/ssl/test/openssl_server_cipher_suite_SUITE.erl
new file mode 100644
index 0000000000..6ce34ce7fa
--- /dev/null
+++ b/lib/ssl/test/openssl_server_cipher_suite_SUITE.erl
@@ -0,0 +1,774 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+-module(openssl_server_cipher_suite_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+all() ->
+ [
+ {group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}
+ ].
+
+groups() ->
+ %% TODO: Enable SRP, PSK suites (needs OpenSSL s_server conf)
+ %% TODO: Enable all "kex" on DTLS
+ [
+ {'tlsv1.2', [], kex()},
+ {'tlsv1.1', [], kex()},
+ {'tlsv1', [], kex()},
+ {'sslv3', [], kex()},
+ {'dtlsv1.2', [], dtls_kex()},
+ {'dtlsv1', [], dtls_kex()},
+ {dhe_rsa, [],[dhe_rsa_3des_ede_cbc,
+ dhe_rsa_aes_128_cbc,
+ dhe_rsa_aes_256_cbc,
+ dhe_rsa_chacha20_poly1305
+ ]},
+ {ecdhe_rsa, [], [ecdhe_rsa_3des_ede_cbc,
+ ecdhe_rsa_aes_128_cbc,
+ ecdhe_rsa_aes_128_gcm,
+ ecdhe_rsa_aes_256_cbc,
+ ecdhe_rsa_aes_256_gcm,
+ ecdhe_rsa_chacha20_poly1305
+ ]},
+ {ecdhe_ecdsa, [],[ecdhe_ecdsa_rc4_128,
+ ecdhe_ecdsa_3des_ede_cbc,
+ ecdhe_ecdsa_aes_128_cbc,
+ ecdhe_ecdsa_aes_128_gcm,
+ ecdhe_ecdsa_aes_256_cbc,
+ ecdhe_ecdsa_aes_256_gcm,
+ ecdhe_ecdsa_chacha20_poly1305
+ ]},
+ {rsa, [], [rsa_3des_ede_cbc,
+ rsa_aes_128_cbc,
+ rsa_aes_256_cbc,
+ rsa_rc4_128
+ ]},
+ {dhe_dss, [], [dhe_dss_3des_ede_cbc,
+ dhe_dss_aes_128_cbc,
+ dhe_dss_aes_256_cbc]},
+ %% {srp_rsa, [], [srp_rsa_3des_ede_cbc,
+ %% srp_rsa_aes_128_cbc,
+ %% srp_rsa_aes_256_cbc]},
+ %% {srp_dss, [], [srp_dss_3des_ede_cbc,
+ %% srp_dss_aes_128_cbc,
+ %% srp_dss_aes_256_cbc]},
+ %% {rsa_psk, [], [rsa_psk_3des_ede_cbc,
+ %% rsa_psk_rc4_128,
+ %% rsa_psk_aes_128_cbc,
+ %% rsa_psk_aes_256_cbc
+ %% ]},
+ {dh_anon, [], [dh_anon_rc4_128,
+ dh_anon_3des_ede_cbc,
+ dh_anon_aes_128_cbc,
+ dh_anon_aes_128_gcm,
+ dh_anon_aes_256_cbc,
+ dh_anon_aes_256_gcm]},
+ {ecdh_anon, [], [ecdh_anon_3des_ede_cbc,
+ ecdh_anon_aes_128_cbc,
+ ecdh_anon_aes_256_cbc
+ ]}
+ %% {srp_anon, [], [srp_anon_3des_ede_cbc,
+ %% srp_anon_aes_128_cbc,
+ %% srp_anon_aes_256_cbc]},
+ %% {psk, [], [psk_3des_ede_cbc,
+ %% psk_rc4_128,
+ %% psk_aes_128_cbc,
+ %% psk_aes_128_ccm,
+ %% psk_aes_128_ccm_8,
+ %% psk_aes_256_cbc,
+ %% psk_aes_256_ccm,
+ %% psk_aes_256_ccm_8
+ %% ]},
+ %% {dhe_psk, [], [dhe_psk_3des_ede_cbc,
+ %% dhe_psk_rc4_128,
+ %% dhe_psk_aes_128_cbc,
+ %% dhe_psk_aes_128_ccm,
+ %% dhe_psk_aes_128_ccm_8,
+ %% dhe_psk_aes_256_cbc,
+ %% dhe_psk_aes_256_ccm,
+ %% dhe_psk_aes_256_ccm_8
+ %% ]},
+ %% {ecdhe_psk, [], [ecdhe_psk_3des_ede_cbc,
+ %% ecdhe_psk_rc4_128,
+ %% ecdhe_psk_aes_128_cbc,
+ %% ecdhe_psk_aes_128_ccm,
+ %% ecdhe_psk_aes_128_ccm_8,
+ %% ecdhe_psk_aes_256_cbc
+ %% ]}
+ ].
+
+kex() ->
+ rsa() ++ ecdsa() ++ dss() ++ anonymous().
+
+dtls_kex() -> %% Should be all kex in the future
+ dtls_rsa() ++ dss() ++ anonymous().
+
+rsa() ->
+ [{group, dhe_rsa},
+ {group, ecdhe_rsa},
+ {group, rsa} %%, {group, srp_rsa},
+ %%{group, rsa_psk}
+ ].
+
+dtls_rsa() ->
+ [
+ {group, rsa}
+ %%,{group, rsa_psk}
+ ].
+
+ecdsa() ->
+ [{group, ecdhe_ecdsa}].
+
+dss() ->
+ [{group, dhe_dss}
+ %%{group, srp_dss}
+ ].
+
+anonymous() ->
+ [{group, dh_anon},
+ {group, ecdh_anon}
+ %% {group, psk},
+ %%{group, dhe_psk},
+ %%{group, ecdhe_psk}
+ %%{group, srp_anon}
+ ].
+
+init_per_suite(Config) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ Config
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto).
+
+%%--------------------------------------------------------------------
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:supports_ssl_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:check_sane_openssl_version(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, Config),
+ do_init_per_group(GroupName, Config);
+ false ->
+ {skip, openssl_does_not_support_version}
+ end;
+ false ->
+ {skip, {openssl_does_not_support, GroupName}}
+ end;
+ false ->
+ do_init_per_group(GroupName, Config)
+ end.
+
+do_init_per_group(GroupName, Config) when GroupName == ecdh_anon;
+ GroupName == ecdhe_rsa;
+ GroupName == ecdhe_psk ->
+ case proplists:get_bool(ecdh, proplists:get_value(public_keys, crypto:supports())) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing EC crypto support"}
+ end;
+do_init_per_group(ecdhe_ecdsa = GroupName, Config) ->
+ PKAlg = proplists:get_value(public_keys, crypto:supports()),
+ case lists:member(ecdh, PKAlg) andalso lists:member(ecdsa, PKAlg) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing EC crypto support"}
+ end;
+do_init_per_group(dhe_dss = GroupName, Config) ->
+ PKAlg = proplists:get_value(public_keys, crypto:supports()),
+ case lists:member(dss, PKAlg) andalso lists:member(dh, PKAlg) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing DSS crypto support"}
+ end;
+do_init_per_group(srp_dss = GroupName, Config) ->
+ PKAlg = proplists:get_value(public_keys, crypto:supports()),
+ case lists:member(dss, PKAlg) andalso lists:member(srp, PKAlg) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing DSS_SRP crypto support"}
+ end;
+do_init_per_group(GroupName, Config) when GroupName == srp_anon;
+ GroupName == srp_rsa ->
+ PKAlg = proplists:get_value(public_keys, crypto:supports()),
+ case lists:member(srp, PKAlg) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing SRP crypto support"}
+ end;
+do_init_per_group(dhe_psk = GroupName, Config) ->
+ PKAlg = proplists:get_value(public_keys, crypto:supports()),
+ case lists:member(dh, PKAlg) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing SRP crypto support"}
+ end;
+do_init_per_group(GroupName, Config0) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, end_per_group(GroupName, Config0));
+ false ->
+ init_certs(GroupName, Config0)
+ end.
+
+end_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:clean_tls_version(Config);
+ false ->
+ Config
+ end.
+
+init_per_testcase(TestCase, Config) when TestCase == psk_3des_ede_cbc;
+ TestCase == srp_anon_3des_ede_cbc;
+ TestCase == dhe_psk_3des_ede_cbc;
+ TestCase == ecdhe_psk_3des_ede_cbc;
+ TestCase == srp_rsa_3des_ede_cbc;
+ TestCase == srp_dss_3des_ede_cbc;
+ TestCase == rsa_psk_3des_ede_cbc;
+ TestCase == rsa_3des_ede_cbc;
+ TestCase == dhe_rsa_3des_ede_cbc;
+ TestCase == dhe_dss_3des_ede_cbc;
+ TestCase == ecdhe_rsa_3des_ede_cbc;
+ TestCase == srp_anon_dss_3des_ede_cbc;
+ TestCase == dh_anon_3des_ede_cbc;
+ TestCase == ecdh_anon_3des_ede_cbc;
+ TestCase == ecdhe_ecdsa_3des_ede_cbc ->
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ case lists:member(des_ede3, SupCiphers) of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, "Missing 3DES crypto support"}
+ end;
+init_per_testcase(TestCase, Config) when TestCase == psk_rc4_128;
+ TestCase == ecdhe_psk_rc4_128;
+ TestCase == dhe_psk_rc4_128;
+ TestCase == rsa_psk_rc4_128;
+ TestCase == rsa_rc4_128;
+ TestCase == ecdhe_rsa_rc4_128;
+ TestCase == ecdhe_ecdsa_rc4_128;
+ TestCase == dh_anon_rc4_128 ->
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ case lists:member(rc4, SupCiphers) of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, "Missing RC4 crypto support"}
+ end;
+init_per_testcase(TestCase, Config) when TestCase == psk_aes_128_ccm_8;
+ TestCase == rsa_psk_aes_128_ccm_8;
+ TestCase == psk_aes_128_ccm_8;
+ TestCase == dhe_psk_aes_128_ccm_8;
+ TestCase == ecdhe_psk_aes_128_ccm_8 ->
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ case lists:member(aes_128_ccm, SupCiphers) of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, "Missing AES_128_CCM crypto support"}
+ end;
+init_per_testcase(TestCase, Config) when TestCase == psk_aes_256_ccm_8;
+ TestCase == rsa_psk_aes_256_ccm_8;
+ TestCase == psk_aes_256_ccm_8;
+ TestCase == dhe_psk_aes_256_ccm_8;
+ TestCase == ecdhe_psk_aes_256_ccm_8 ->
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ case lists:member(aes_256_ccm, SupCiphers) of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, "Missing AES_256_CCM crypto support"}
+ end;
+init_per_testcase(TestCase, Config) ->
+ Cipher = ssl_test_lib:test_cipher(TestCase, Config),
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ case lists:member(Cipher, SupCiphers) of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, {Cipher, SupCiphers}}
+ end.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Initializtion ------------------------------------------
+%%--------------------------------------------------------------------
+init_certs(srp_rsa, Config) ->
+ {ClientOpts, ServerOpts} = ssl_test_lib:make_rsa_cert_chains([{server_chain, ssl_test_lib:default_cert_chain_conf()},
+ {client_chain, ssl_test_lib:default_cert_chain_conf()}],
+ Config, ""),
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, undefined}} | ServerOpts],
+ client_config => [{srp_identity, {"Test-User", "secret"}} | ClientOpts]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(srp_anon, Config) ->
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, undefined}}],
+ client_config => [{srp_identity, {"Test-User", "secret"}}]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(rsa_psk, Config) ->
+ Ext = x509_test:extensions([{key_usage, [digitalSignature, keyEncipherment]}]),
+ {ClientOpts, ServerOpts} = ssl_test_lib:make_rsa_cert_chains([{server_chain,
+ [[ssl_test_lib:digest()],[ssl_test_lib:digest()],
+ [ssl_test_lib:digest(), {extensions, Ext}]]},
+ {client_chain, ssl_test_lib:default_cert_chain_conf()}],
+ Config, "_peer_keyEncipherment"),
+ PskSharedSecret = <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>,
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, PskSharedSecret}} | ServerOpts],
+ client_config => [{psk_identity, "Test-User"},
+ {user_lookup_fun, {fun ssl_test_lib:user_lookup/3, PskSharedSecret}} | ClientOpts]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(rsa, Config) ->
+ Ext = x509_test:extensions([{key_usage, [digitalSignature, keyEncipherment]}]),
+ {ClientOpts, ServerOpts} = ssl_test_lib:make_rsa_cert_chains([{server_chain,
+ [[ssl_test_lib:digest()],[ssl_test_lib:digest()],
+ [ssl_test_lib:digest(), {extensions, Ext}]]}
+ ],
+ Config, "_peer_keyEncipherment"),
+ [{tls_config, #{server_config => ServerOpts,
+ client_config => ClientOpts}} |
+ proplists:delete(tls_config, Config)];
+init_certs(dhe_dss, Config) ->
+ {ClientOpts, ServerOpts} = ssl_test_lib:make_dsa_cert_chains([{server_chain, ssl_test_lib:default_cert_chain_conf()},
+ {client_chain, ssl_test_lib:default_cert_chain_conf()}],
+ Config, ""),
+ [{tls_config, #{server_config => ServerOpts,
+ client_config => ClientOpts}} |
+ proplists:delete(tls_config, Config)];
+init_certs(srp_dss, Config) ->
+ {ClientOpts, ServerOpts} = ssl_test_lib:make_dsa_cert_chains([{server_chain, ssl_test_lib:default_cert_chain_conf()},
+ {client_chain, ssl_test_lib:default_cert_chain_conf()}],
+ Config, ""),
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, undefined}} | ServerOpts],
+ client_config => [{srp_identity, {"Test-User", "secret"}} | ClientOpts]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(GroupName, Config) when GroupName == dhe_rsa;
+ GroupName == ecdhe_rsa ->
+ {ClientOpts, ServerOpts} = ssl_test_lib:make_rsa_cert_chains([{server_chain, ssl_test_lib:default_cert_chain_conf()},
+ {client_chain, ssl_test_lib:default_cert_chain_conf()}],
+ Config, ""),
+ [{tls_config, #{server_config => ServerOpts,
+ client_config => ClientOpts}} |
+ proplists:delete(tls_config, Config)];
+init_certs(GroupName, Config) when GroupName == dhe_ecdsa;
+ GroupName == ecdhe_ecdsa ->
+ {ClientOpts, ServerOpts} = ssl_test_lib:make_ecc_cert_chains([{server_chain, ssl_test_lib:default_cert_chain_conf()},
+ {client_chain, ssl_test_lib:default_cert_chain_conf()}],
+ Config, ""),
+ [{tls_config, #{server_config => ServerOpts,
+ client_config => ClientOpts}} |
+ proplists:delete(tls_config, Config)];
+init_certs(GroupName, Config) when GroupName == psk;
+ GroupName == dhe_psk;
+ GroupName == ecdhe_psk ->
+ PskSharedSecret = <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>,
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, PskSharedSecret}}],
+ client_config => [{psk_identity, "Test-User"},
+ {user_lookup_fun, {fun ssl_test_lib:user_lookup/3, PskSharedSecret}}]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(srp, Config) ->
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, undefined}}],
+ client_config => [{srp_identity, {"Test-User", "secret"}}]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(_GroupName, Config) ->
+ %% Anonymous does not need certs
+ [{tls_config, #{server_config => [],
+ client_config => []}} |
+ proplists:delete(tls_config, Config)].
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% SRP --------------------------------------------------------
+%%--------------------------------------------------------------------
+srp_rsa_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_rsa, '3des_ede_cbc', Config).
+
+srp_rsa_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_rsa, 'aes_128_cbc', Config).
+
+srp_rsa_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_rsa, 'aes_256_cbc', Config).
+
+srp_dss_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_dss, '3des_ede_cbc', Config).
+
+srp_dss_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_dss, 'aes_128_cbc', Config).
+
+srp_dss_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_dss, 'aes_256_cbc', Config).
+
+%%--------------------------------------------------------------------
+%% PSK --------------------------------------------------------
+%%--------------------------------------------------------------------
+rsa_psk_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, '3des_ede_cbc', Config).
+
+rsa_psk_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_128_cbc', Config).
+
+rsa_psk_aes_128_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_128_ccm', Config).
+
+rsa_psk_aes_128_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_128_ccm_8', Config).
+
+rsa_psk_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_256_cbc', Config).
+
+rsa_psk_aes_256_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_256_ccm', Config).
+
+rsa_psk_aes_256_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_256_ccm_8', Config).
+
+rsa_psk_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'rc4_128', Config).
+
+%%--------------------------------------------------------------------
+%% RSA --------------------------------------------------------
+%%--------------------------------------------------------------------
+rsa_des_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'des_cbc', Config).
+
+rsa_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, '3des_ede_cbc', Config).
+
+rsa_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'aes_128_cbc', Config).
+
+rsa_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'aes_256_cbc', Config).
+
+rsa_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'aes_128_gcm', Config).
+
+rsa_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'aes_256_gcm', Config).
+
+rsa_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'rc4_128', Config).
+%%--------------------------------------------------------------------
+%% DHE_RSA --------------------------------------------------------
+%%--------------------------------------------------------------------
+dhe_rsa_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, '3des_ede_cbc', Config).
+
+dhe_rsa_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, 'aes_128_cbc', Config).
+
+dhe_rsa_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, 'aes_128_gcm', Config).
+
+dhe_rsa_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, 'aes_256_cbc', Config).
+
+dhe_rsa_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, 'aes_256_gcm', Config).
+
+dhe_rsa_chacha20_poly1305(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, 'chacha20_poly1305', Config).
+%%--------------------------------------------------------------------
+%% ECDHE_RSA --------------------------------------------------------
+%%--------------------------------------------------------------------
+ecdhe_rsa_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, '3des_ede_cbc', Config).
+
+ecdhe_rsa_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'aes_128_cbc', Config).
+
+ecdhe_rsa_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'aes_128_gcm', Config).
+
+ecdhe_rsa_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'aes_256_cbc', Config).
+
+ecdhe_rsa_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'aes_256_gcm', Config).
+
+ecdhe_rsa_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'rc4_128', Config).
+
+ecdhe_rsa_chacha20_poly1305(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'chacha20_poly1305', Config).
+
+%%--------------------------------------------------------------------
+%% ECDHE_ECDSA --------------------------------------------------------
+%%--------------------------------------------------------------------
+ecdhe_ecdsa_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'rc4_128', Config).
+
+ecdhe_ecdsa_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, '3des_ede_cbc', Config).
+
+ecdhe_ecdsa_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'aes_128_cbc', Config).
+
+ecdhe_ecdsa_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'aes_128_gcm', Config).
+
+ecdhe_ecdsa_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'aes_256_cbc', Config).
+
+ecdhe_ecdsa_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'aes_256_gcm', Config).
+
+ecdhe_ecdsa_chacha20_poly1305(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'chacha20_poly1305', Config).
+%%--------------------------------------------------------------------
+%% DHE_DSS --------------------------------------------------------
+%%--------------------------------------------------------------------
+dhe_dss_des_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, 'des_cbc', Config).
+
+dhe_dss_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, '3des_ede_cbc', Config).
+
+dhe_dss_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, 'aes_128_cbc', Config).
+
+dhe_dss_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, 'aes_256_cbc', Config).
+
+dhe_dss_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, 'aes_128_gcm', Config).
+
+dhe_dss_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, 'aes_256_gcm', Config).
+
+%%--------------------------------------------------------------------
+%% Anonymous --------------------------------------------------------
+%%--------------------------------------------------------------------
+dh_anon_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, '3des_ede_cbc', Config).
+
+dh_anon_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, 'aes_128_cbc', Config).
+
+dh_anon_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, 'aes_128_gcm', Config).
+
+dh_anon_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, 'aes_256_cbc', Config).
+
+dh_anon_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, 'aes_256_gcm', Config).
+
+dh_anon_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, 'rc4_128', Config).
+
+ecdh_anon_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdh_anon, '3des_ede_cbc', Config).
+
+ecdh_anon_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdh_anon, 'aes_128_cbc', Config).
+
+ecdh_anon_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdh_anon, 'aes_256_cbc', Config).
+
+srp_anon_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_anon, '3des_ede_cbc', Config).
+
+srp_anon_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_anon, 'aes_128_cbc', Config).
+
+srp_anon_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_anon, 'aes_256_cbc', Config).
+
+dhe_psk_des_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'des_cbc', Config).
+
+dhe_psk_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'rc4_128', Config).
+
+dhe_psk_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, '3des_ede_cbc', Config).
+
+dhe_psk_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_128_cbc', Config).
+
+dhe_psk_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_256_cbc', Config).
+
+dhe_psk_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_128_gcm', Config).
+
+dhe_psk_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_256_gcm', Config).
+
+dhe_psk_aes_128_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_128_ccm', Config).
+
+dhe_psk_aes_256_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_256_ccm', Config).
+
+dhe_psk_aes_128_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_128_ccm_8', Config).
+
+dhe_psk_aes_256_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_256_ccm_8', Config).
+
+ecdhe_psk_des_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'des_cbc', Config).
+
+ecdhe_psk_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'rc4_128', Config).
+
+ecdhe_psk_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, '3des_ede_cbc', Config).
+
+ecdhe_psk_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_128_cbc', Config).
+
+ecdhe_psk_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_256_cbc', Config).
+
+ecdhe_psk_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_128_gcm', Config).
+
+ecdhe_psk_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_256_gcm', Config).
+
+ecdhe_psk_aes_128_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_128_ccm', Config).
+
+ecdhe_psk_aes_128_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_128_ccm_8', Config).
+
+psk_des_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'des_cbc', Config).
+
+psk_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'rc4_128', Config).
+
+psk_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(psk, '3des_ede_cbc', Config).
+
+psk_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_128_cbc', Config).
+
+psk_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_256_cbc', Config).
+
+psk_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_128_gcm', Config).
+
+psk_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_256_gcm', Config).
+
+psk_aes_128_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_128_ccm', Config).
+
+psk_aes_256_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_256_ccm', Config).
+
+psk_aes_128_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_128_ccm_8', Config).
+
+psk_aes_256_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_256_ccm_8', Config).
+
+%%--------------------------------------------------------------------
+%% Internal functions ----------------------------------------------
+%%--------------------------------------------------------------------
+run_ciphers_test(Kex, Cipher, Config) ->
+ Version = ssl_test_lib:protocol_version(Config),
+ TestCiphers = test_ciphers(Kex, Cipher, Version),
+
+ case TestCiphers of
+ [_|_] ->
+ lists:foreach(fun(TestCipher) ->
+ cipher_suite_test(TestCipher, Version, Config)
+ end, TestCiphers);
+ [] ->
+ {skip, {not_sup, Kex, Cipher, Version}}
+ end.
+
+cipher_suite_test(CipherSuite, _Version, Config) ->
+ #{server_config := SOpts,
+ client_config := COpts} = proplists:get_value(tls_config, Config),
+ ServerOpts = ssl_test_lib:ssl_options(SOpts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(COpts, Config),
+ ct:log("Testing CipherSuite ~p~n", [CipherSuite]),
+ ct:log("Server Opts ~p~n", [ServerOpts]),
+ ct:log("Client Opts ~p~n", [ClientOpts]),
+ ssl_test_lib:basic_test([{ciphers, [CipherSuite]} | COpts], SOpts, [{client_type, erlang},
+ {server_type, openssl} | Config]).
+
+
+test_ciphers(Kex, Cipher, Version) ->
+ Ciphers = ssl:filter_cipher_suites(ssl:cipher_suites(default, Version) ++ ssl:cipher_suites(anonymous, Version),
+ [{key_exchange,
+ fun(Kex0) when Kex0 == Kex -> true;
+ (_) -> false
+ end},
+ {cipher,
+ fun(Cipher0) when Cipher0 == Cipher -> true;
+ (_) -> false
+ end}]),
+ ct:log("Version ~p Testing ~p~n", [Version, Ciphers]),
+ OpenSSLCiphers = openssl_ciphers(),
+ ct:log("OpenSSLCiphers ~p~n", [OpenSSLCiphers]),
+ lists:filter(fun(C) ->
+ ct:log("Cipher ~p~n", [C]),
+ lists:member(ssl_cipher_format:suite_map_to_openssl_str(C), OpenSSLCiphers)
+ end, Ciphers).
+
+
+openssl_ciphers() ->
+ Str = os:cmd("openssl ciphers"),
+ string:split(string:strip(Str, right, $\n), ":", all).
diff --git a/lib/ssl/test/property_test/ssl_eqc_cipher_format.erl b/lib/ssl/test/property_test/ssl_eqc_cipher_format.erl
new file mode 100644
index 0000000000..f225065ba6
--- /dev/null
+++ b/lib/ssl/test/property_test/ssl_eqc_cipher_format.erl
@@ -0,0 +1,96 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. 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(ssl_eqc_cipher_format).
+
+-compile(export_all).
+
+-proptest(eqc).
+-proptest([triq,proper]).
+
+-ifndef(EQC).
+-ifndef(PROPER).
+-ifndef(TRIQ).
+-define(EQC,true).
+-endif.
+-endif.
+-endif.
+
+-ifdef(EQC).
+-include_lib("eqc/include/eqc.hrl").
+-define(MOD_eqc,eqc).
+
+-else.
+-ifdef(PROPER).
+-include_lib("proper/include/proper.hrl").
+-define(MOD_eqc,proper).
+
+-else.
+-ifdef(TRIQ).
+-define(MOD_eqc,triq).
+-include_lib("triq/include/triq.hrl").
+
+-endif.
+-endif.
+-endif.
+
+-define('TLS_v1.3', 'tlsv1.3').
+-define('TLS_v1.2', 'tlsv1.2').
+-define('TLS_v1.1', 'tlsv1.1').
+-define('TLS_v1', 'tlsv1').
+-define('SSL_v3', 'sslv3').
+
+%%--------------------------------------------------------------------
+%% Properties --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+prop_tls_cipher_suite_rfc_name() ->
+ ?FORALL({CipherSuite, TLSVersion}, ?LET(Version, tls_version(), {cipher_suite(Version), Version}),
+ case ssl:str_to_suite(ssl:suite_to_str(CipherSuite)) of
+ CipherSuite ->
+ true;
+ _ ->
+ false
+ end
+ ).
+
+prop_tls_cipher_suite_openssl_name() ->
+ ?FORALL({CipherSuite, TLSVersion}, ?LET(Version, tls_version(), {cipher_suite(Version), Version}),
+ case ssl:str_to_suite(ssl:suite_to_openssl_str(CipherSuite)) of
+ CipherSuite ->
+ true;
+ _ ->
+ false
+ end
+ ).
+
+
+%%--------------------------------------------------------------------
+%% Generators -----------------------------------------------
+%%--------------------------------------------------------------------
+tls_version() ->
+ oneof([?'TLS_v1.2', ?'TLS_v1.1', ?'TLS_v1', ?'SSL_v3']).
+
+cipher_suite(Version) ->
+ oneof(cipher_suites(Version)).
+
+cipher_suites(Version) ->
+ ssl:cipher_suites(all, Version).
+
diff --git a/lib/ssl/test/property_test/ssl_eqc_handshake.erl b/lib/ssl/test/property_test/ssl_eqc_handshake.erl
new file mode 100644
index 0000000000..38a4b7fb11
--- /dev/null
+++ b/lib/ssl/test/property_test/ssl_eqc_handshake.erl
@@ -0,0 +1,812 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018-2018. 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(ssl_eqc_handshake).
+
+-compile(export_all).
+
+-proptest(eqc).
+-proptest([triq,proper]).
+
+-ifndef(EQC).
+-ifndef(PROPER).
+-ifndef(TRIQ).
+-define(EQC,true).
+-endif.
+-endif.
+-endif.
+
+-ifdef(EQC).
+-include_lib("eqc/include/eqc.hrl").
+-define(MOD_eqc,eqc).
+
+-else.
+-ifdef(PROPER).
+-include_lib("proper/include/proper.hrl").
+-define(MOD_eqc,proper).
+
+-else.
+-ifdef(TRIQ).
+-define(MOD_eqc,triq).
+-include_lib("triq/include/triq.hrl").
+
+-endif.
+-endif.
+-endif.
+
+-include_lib("kernel/include/inet.hrl").
+-include_lib("ssl/src/tls_handshake_1_3.hrl").
+-include_lib("ssl/src/tls_handshake.hrl").
+-include_lib("ssl/src/ssl_handshake.hrl").
+-include_lib("ssl/src/ssl_alert.hrl").
+-include_lib("ssl/src/ssl_internal.hrl").
+
+-define('TLS_v1.3', {3,4}).
+-define('TLS_v1.2', {3,3}).
+-define('TLS_v1.1', {3,2}).
+-define('TLS_v1', {3,1}).
+-define('SSL_v3', {3,0}).
+
+%%--------------------------------------------------------------------
+%% Properties --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+prop_tls_hs_encode_decode() ->
+ ?FORALL({Handshake, TLSVersion}, ?LET(Version, tls_version(), {tls_msg(Version), Version}),
+ try
+ [Type, _Length, Data] = tls_handshake:encode_handshake(Handshake, TLSVersion),
+ case tls_handshake:decode_handshake(TLSVersion, Type, Data) of
+ Handshake ->
+ true;
+ _ ->
+ false
+ end
+ catch
+ throw:#alert{} ->
+ true
+ end
+ ).
+
+%%--------------------------------------------------------------------
+%% Message Generators -----------------------------------------------
+%%--------------------------------------------------------------------
+
+tls_msg(?'TLS_v1.3'= Version) ->
+ oneof([client_hello(Version),
+ server_hello(Version),
+ %%new_session_ticket()
+ #end_of_early_data{},
+ encrypted_extensions(),
+ certificate_1_3(),
+ %%certificate_request_1_3,
+ certificate_verify_1_3(),
+ finished(),
+ key_update()
+ ]);
+tls_msg(Version) ->
+ oneof([
+ #hello_request{},
+ client_hello(Version),
+ server_hello(Version),
+ certificate(),
+ %%server_key_exchange()
+ certificate_request(Version),
+ #server_hello_done{},
+ %%certificate_verify()
+ %%client_key_exchange()
+ finished()
+ ]).
+
+%%
+%% Shared messages
+%%
+client_hello(?'TLS_v1.3' = Version) ->
+ #client_hello{session_id = session_id(),
+ client_version = ?'TLS_v1.2',
+ cipher_suites = cipher_suites(Version),
+ compression_methods = compressions(Version),
+ random = client_random(Version),
+ extensions = client_hello_extensions(Version)
+ };
+client_hello(Version) ->
+ #client_hello{session_id = session_id(),
+ client_version = Version,
+ cipher_suites = cipher_suites(Version),
+ compression_methods = compressions(Version),
+ random = client_random(Version),
+ extensions = client_hello_extensions(Version)
+ }.
+
+server_hello(?'TLS_v1.3' = Version) ->
+ #server_hello{server_version = ?'TLS_v1.2',
+ session_id = session_id(),
+ random = server_random(Version),
+ cipher_suite = cipher_suite(Version),
+ compression_method = compression(Version),
+ extensions = server_hello_extensions(Version)
+ };
+server_hello(Version) ->
+ #server_hello{server_version = Version,
+ session_id = session_id(),
+ random = server_random(Version),
+ cipher_suite = cipher_suite(Version),
+ compression_method = compression(Version),
+ extensions = server_hello_extensions(Version)
+ }.
+
+certificate() ->
+ #certificate{
+ asn1_certificates = certificate_chain()
+ }.
+
+certificate_1_3() ->
+ ?LET(Certs, certificate_chain(),
+ #certificate_1_3{
+ certificate_request_context = certificate_request_context(),
+ certificate_list = certificate_entries(Certs, [])
+ }).
+
+certificate_verify_1_3() ->
+ ?LET(Certs, certificate_chain(),
+ #certificate_verify_1_3{
+ algorithm = sig_scheme(),
+ signature = signature()
+ }).
+
+finished() ->
+ ?LET(Size, digest_size(),
+ #finished{verify_data = crypto:strong_rand_bytes(Size)}).
+
+%%
+%% TLS 1.0-1.2 messages
+%%
+
+
+
+%%
+%% TLS 1.3 messages
+%%
+
+encrypted_extensions() ->
+ ?LET(Exts, extensions(?'TLS_v1.3', encrypted_extensions),
+ #encrypted_extensions{extensions = Exts}).
+
+
+key_update() ->
+ #key_update{request_update = request_update()}.
+
+
+%%--------------------------------------------------------------------
+%% Messge Data Generators -------------------------------------------
+%%--------------------------------------------------------------------
+
+tls_version() ->
+ oneof([?'TLS_v1.3', ?'TLS_v1.2', ?'TLS_v1.1', ?'TLS_v1', ?'SSL_v3']).
+
+cipher_suite(Version) ->
+ oneof(cipher_suites(Version)).
+
+cipher_suites(Version) ->
+ ssl_cipher:suites(Version).
+
+session_id() ->
+ crypto:strong_rand_bytes(?NUM_OF_SESSION_ID_BYTES).
+
+compression(Version) ->
+ oneof(compressions(Version)).
+
+compressions(_) ->
+ ssl_record:compressions().
+
+client_random(_) ->
+ crypto:strong_rand_bytes(32).
+
+server_random(_) ->
+ crypto:strong_rand_bytes(32).
+
+
+client_hello_extensions(Version) ->
+ ?LET(Exts, extensions(Version, client_hello),
+ maps:merge(ssl_handshake:empty_extensions(Version, client_hello),
+ Exts)).
+
+server_hello_extensions(Version) ->
+ ?LET(Exts, extensions(Version, server_hello),
+ maps:merge(ssl_handshake:empty_extensions(Version, server_hello),
+ Exts)).
+
+key_share_client_hello() ->
+ oneof([undefined]).
+ %%oneof([#key_share_client_hello{}, undefined]).
+
+key_share_server_hello() ->
+ oneof([undefined]).
+ %%oneof([#key_share_server_hello{}, undefined]).
+
+pre_shared_keyextension() ->
+ oneof([undefined]).
+ %%oneof([#pre_shared_keyextension{},undefined]).
+
+%% +--------------------------------------------------+-------------+
+%% | Extension | TLS 1.3 |
+%% +--------------------------------------------------+-------------+
+%% | server_name [RFC6066] | CH, EE |
+%% | | |
+%% | max_fragment_length [RFC6066] | CH, EE |
+%% | | |
+%% | status_request [RFC6066] | CH, CR, CT |
+%% | | |
+%% | supported_groups [RFC7919] | CH, EE |
+%% | | |
+%% | signature_algorithms (RFC 8446) | CH, CR |
+%% | | |
+%% | use_srtp [RFC5764] | CH, EE |
+%% | | |
+%% | heartbeat [RFC6520] | CH, EE |
+%% | | |
+%% | application_layer_protocol_negotiation [RFC7301] | CH, EE |
+%% | | |
+%% | signed_certificate_timestamp [RFC6962] | CH, CR, CT |
+%% | | |
+%% | client_certificate_type [RFC7250] | CH, EE |
+%% | | |
+%% | server_certificate_type [RFC7250] | CH, EE |
+%% | | |
+%% | padding [RFC7685] | CH |
+%% | | |
+%% | key_share (RFC 8446) | CH, SH, HRR |
+%% | | |
+%% | pre_shared_key (RFC 8446) | CH, SH |
+%% | | |
+%% | psk_key_exchange_modes (RFC 8446) | CH |
+%% | | |
+%% | early_data (RFC 8446) | CH, EE, NST |
+%% | | |
+%% | cookie (RFC 8446) | CH, HRR |
+%% | | |
+%% | supported_versions (RFC 8446) | CH, SH, HRR |
+%% | | |
+%% | certificate_authorities (RFC 8446) | CH, CR |
+%% | | |
+%% | oid_filters (RFC 8446) | CR |
+%% | | |
+%% | post_handshake_auth (RFC 8446) | CH |
+%% | | |
+%% | signature_algorithms_cert (RFC 8446) | CH, CR |
+%% +--------------------------------------------------+-------------+
+extensions(?'TLS_v1.3' = Version, client_hello) ->
+ ?LET({
+ ServerName,
+ %% MaxFragmentLength,
+ %% StatusRequest,
+ SupportedGroups,
+ SignatureAlgorithms,
+ %% UseSrtp,
+ %% Heartbeat,
+ ALPN,
+ %% SignedCertTimestamp,
+ %% ClientCertiticateType,
+ %% ServerCertificateType,
+ %% Padding,
+ KeyShare,
+ %% PreSharedKey,
+ %% PSKKeyExchangeModes,
+ %% EarlyData,
+ %% Cookie,
+ SupportedVersions,
+ %% CertAuthorities,
+ %% PostHandshakeAuth,
+ SignatureAlgorithmsCert
+ },
+ {
+ oneof([server_name(), undefined]),
+ %% oneof([max_fragment_length(), undefined]),
+ %% oneof([status_request(), undefined]),
+ oneof([supported_groups(Version), undefined]),
+ oneof([signature_algs(Version), undefined]),
+ %% oneof([use_srtp(), undefined]),
+ %% oneof([heartbeat(), undefined]),
+ oneof([alpn(), undefined]),
+ %% oneof([signed_cert_timestamp(), undefined]),
+ %% oneof([client_cert_type(), undefined]),
+ %% oneof([server_cert_type(), undefined]),
+ %% oneof([padding(), undefined]),
+ oneof([key_share(client_hello), undefined]),
+ %% oneof([pre_shared_key(), undefined]),
+ %% oneof([psk_key_exchange_modes(), undefined]),
+ %% oneof([early_data(), undefined]),
+ %% oneof([cookie(), undefined]),
+ oneof([client_hello_versions(Version)]),
+ %% oneof([cert_authorities(), undefined]),
+ %% oneof([post_handshake_auth(), undefined]),
+ oneof([signature_algs_cert(), undefined])
+ },
+ maps:filter(fun(_, undefined) ->
+ false;
+ (_,_) ->
+ true
+ end,
+ #{
+ sni => ServerName,
+ %% max_fragment_length => MaxFragmentLength,
+ %% status_request => StatusRequest,
+ elliptic_curves => SupportedGroups,
+ signature_algs => SignatureAlgorithms,
+ %% use_srtp => UseSrtp,
+ %% heartbeat => Heartbeat,
+ alpn => ALPN,
+ %% signed_cert_timestamp => SignedCertTimestamp,
+ %% client_cert_type => ClientCertificateType,
+ %% server_cert_type => ServerCertificateType,
+ %% padding => Padding,
+ key_share => KeyShare,
+ %% pre_shared_key => PreSharedKey,
+ %% psk_key_exhange_modes => PSKKeyExchangeModes,
+ %% early_data => EarlyData,
+ %% cookie => Cookie,
+ client_hello_versions => SupportedVersions,
+ %% cert_authorities => CertAuthorities,
+ %% post_handshake_auth => PostHandshakeAuth,
+ signature_algs_cert => SignatureAlgorithmsCert
+ }));
+extensions(?'SSL_v3', client_hello) ->
+ #{};
+extensions(Version, client_hello) ->
+ ?LET({
+ SNI,
+ ECPoitF,
+ ECCurves,
+ ALPN,
+ NextP,
+ SRP
+ %% RenegotiationInfo
+ },
+ {
+ oneof([sni(), undefined]),
+ oneof([ec_point_formats(), undefined]),
+ oneof([elliptic_curves(Version), undefined]),
+ oneof([alpn(), undefined]),
+ oneof([next_protocol_negotiation(), undefined]),
+ oneof([srp(), undefined])
+ %% oneof([renegotiation_info(), undefined])
+ },
+ maps:filter(fun(_, undefined) ->
+ false;
+ (_,_) ->
+ true
+ end,
+ #{
+ sni => SNI,
+ ec_point_formats => ECPoitF,
+ elliptic_curves => ECCurves,
+ alpn => ALPN,
+ next_protocol_negotiation => NextP,
+ srp => SRP
+ %% renegotiation_info => RenegotiationInfo
+ }));
+extensions(?'TLS_v1.3' = Version, server_hello) ->
+ ?LET({
+ KeyShare,
+ %% PreSharedKeys,
+ SupportedVersions
+ },
+ {
+ oneof([key_share(server_hello), undefined]),
+ %% oneof([pre_shared_keys(), undefined]),
+ oneof([server_hello_selected_version()])
+ },
+ maps:filter(fun(_, undefined) ->
+ false;
+ (_,_) ->
+ true
+ end,
+ #{
+ key_share => KeyShare,
+ %% pre_shared_keys => PreSharedKeys,
+ server_hello_selected_version => SupportedVersions
+ }));
+extensions(Version, server_hello) ->
+ ?LET({
+ ECPoitF,
+ ALPN,
+ NextP
+ %% RenegotiationInfo,
+ },
+ {
+ oneof([ec_point_formats(), undefined]),
+ oneof([alpn(), undefined]),
+ oneof([next_protocol_negotiation(), undefined])
+ %% oneof([renegotiation_info(), undefined]),
+ },
+ maps:filter(fun(_, undefined) ->
+ false;
+ (_,_) ->
+ true
+ end,
+ #{
+ ec_point_formats => ECPoitF,
+ alpn => ALPN,
+ next_protocol_negotiation => NextP
+ %% renegotiation_info => RenegotiationInfo
+ }));
+extensions(?'TLS_v1.3' = Version, encrypted_extensions) ->
+ ?LET({
+ ServerName,
+ %% MaxFragmentLength,
+ SupportedGroups,
+ %% UseSrtp,
+ %% Heartbeat,
+ ALPN
+ %% ClientCertiticateType,
+ %% ServerCertificateType,
+ %% EarlyData
+ },
+ {
+ oneof([server_name(), undefined]),
+ %% oneof([max_fragment_length(), undefined]),
+ oneof([supported_groups(Version), undefined]),
+ %% oneof([use_srtp(), undefined]),
+ %% oneof([heartbeat(), undefined]),
+ oneof([alpn(), undefined])
+ %% oneof([client_cert_type(), undefined]),
+ %% oneof([server_cert_type(), undefined]),
+ %% oneof([early_data(), undefined])
+ },
+ maps:filter(fun(_, undefined) ->
+ false;
+ (_,_) ->
+ true
+ end,
+ #{
+ sni => ServerName,
+ %% max_fragment_length => MaxFragmentLength,
+ elliptic_curves => SupportedGroups,
+ %% use_srtp => UseSrtp,
+ %% heartbeat => Heartbeat,
+ alpn => ALPN
+ %% client_cert_type => ClientCertificateType,
+ %% server_cert_type => ServerCertificateType,
+ %% early_data => EarlyData
+ })).
+
+server_name() ->
+ ?LET(ServerName, sni(),
+ ServerName).
+ %% sni().
+
+signature_algs_cert() ->
+ ?LET(List, sig_scheme_list(),
+ #signature_algorithms_cert{signature_scheme_list = List}).
+
+signature_algorithms() ->
+ ?LET(List, sig_scheme_list(),
+ #signature_algorithms{signature_scheme_list = List}).
+
+sig_scheme_list() ->
+ oneof([[rsa_pkcs1_sha256],
+ [rsa_pkcs1_sha256, ecdsa_sha1],
+ [rsa_pkcs1_sha256,
+ rsa_pkcs1_sha384,
+ rsa_pkcs1_sha512,
+ ecdsa_secp256r1_sha256,
+ ecdsa_secp384r1_sha384,
+ ecdsa_secp521r1_sha512,
+ rsa_pss_rsae_sha256,
+ rsa_pss_rsae_sha384,
+ rsa_pss_rsae_sha512,
+ rsa_pss_pss_sha256,
+ rsa_pss_pss_sha384,
+ rsa_pss_pss_sha512,
+ rsa_pkcs1_sha1,
+ ecdsa_sha1]
+ ]).
+
+sig_scheme() ->
+ oneof([rsa_pkcs1_sha256,
+ rsa_pkcs1_sha384,
+ rsa_pkcs1_sha512,
+ ecdsa_secp256r1_sha256,
+ ecdsa_secp384r1_sha384,
+ ecdsa_secp521r1_sha512,
+ rsa_pss_rsae_sha256,
+ rsa_pss_rsae_sha384,
+ rsa_pss_rsae_sha512,
+ rsa_pss_pss_sha256,
+ rsa_pss_pss_sha384,
+ rsa_pss_pss_sha512,
+ rsa_pkcs1_sha1,
+ ecdsa_sha1]).
+
+signature() ->
+ <<44,119,215,137,54,84,156,26,121,212,64,173,189,226,
+ 191,46,76,89,204,2,78,79,163,228,90,21,89,179,4,198,
+ 109,14,52,26,230,22,56,8,170,129,86,0,7,132,245,81,
+ 181,131,62,70,79,167,112,85,14,171,175,162,110,29,
+ 212,198,45,188,83,176,251,197,224,104,95,74,89,59,
+ 26,60,63,79,238,196,137,65,23,199,127,145,176,184,
+ 216,3,48,116,172,106,97,83,227,172,246,137,91,79,
+ 173,119,169,60,67,1,177,117,9,93,38,86,232,253,73,
+ 140,17,147,130,110,136,245,73,10,91,70,105,53,225,
+ 158,107,60,190,30,14,26,92,147,221,60,117,104,53,70,
+ 142,204,7,131,11,183,192,120,246,243,68,99,147,183,
+ 49,149,48,188,8,218,17,150,220,121,2,99,194,140,35,
+ 13,249,201,37,216,68,45,87,58,18,10,106,11,132,241,
+ 71,170,225,216,197,212,29,107,36,80,189,184,202,56,
+ 86,213,45,70,34,74,71,48,137,79,212,194,172,151,57,
+ 57,30,126,24,157,198,101,220,84,162,89,105,185,245,
+ 76,105,212,176,25,6,148,49,194,106,253,241,212,200,
+ 37,154,227,53,49,216,72,82,163>>.
+
+client_hello_versions(?'TLS_v1.3') ->
+ ?LET(SupportedVersions,
+ oneof([[{3,4}],
+ %% This list breaks the property but can be used for negative tests
+ %% [{3,3},{3,4}],
+ [{3,4},{3,3}],
+ [{3,4},{3,3},{3,2},{3,1},{3,0}]
+ ]),
+ #client_hello_versions{versions = SupportedVersions});
+client_hello_versions(_) ->
+ ?LET(SupportedVersions,
+ oneof([[{3,3}],
+ [{3,3},{3,2}],
+ [{3,3},{3,2},{3,1},{3,0}]
+ ]),
+ #client_hello_versions{versions = SupportedVersions}).
+
+server_hello_selected_version() ->
+ #server_hello_selected_version{selected_version = {3,4}}.
+
+request_update() ->
+ oneof([?UPDATE_NOT_REQUESTED, ?UPDATE_REQUESTED]).
+
+certificate_chain()->
+ Conf = cert_conf(),
+ ?LET(Chain,
+ choose_certificate_chain(Conf),
+ Chain).
+
+choose_certificate_chain(#{server_config := ServerConf,
+ client_config := ClientConf}) ->
+ oneof([certificate_chain(ServerConf), certificate_chain(ClientConf)]).
+
+certificate_request_context() ->
+ oneof([<<>>,
+ <<1>>,
+ <<"foobar">>
+ ]).
+certificate_entries([], Acc) ->
+ lists:reverse(Acc);
+certificate_entries([Cert | Rest], Acc) ->
+ certificate_entries(Rest, [certificate_entry(Cert) | Acc]).
+
+certificate_entry(Cert) ->
+ #certificate_entry{data = Cert,
+ extensions = certificate_entry_extensions()
+ }.
+certificate_entry_extensions() ->
+ #{}.
+
+certificate_chain(Conf) ->
+ CAs = proplists:get_value(cacerts, Conf),
+ Cert = proplists:get_value(cert, Conf),
+ %% Middle argument are of correct type but will not be used
+ {ok, _, Chain} = ssl_certificate:certificate_chain(Cert, ets:new(foo, []), make_ref(), CAs),
+ Chain.
+
+cert_conf()->
+ Hostname = net_adm:localhost(),
+ {ok, #hostent{h_addr_list = [_IP |_]}} = inet:gethostbyname(net_adm:localhost()),
+ public_key:pkix_test_data(#{server_chain =>
+ #{root => [{key, ssl_test_lib:hardcode_rsa_key(1)}],
+ intermediates => [[{key, ssl_test_lib:hardcode_rsa_key(2)}]],
+ peer => [{extensions, [#'Extension'{extnID =
+ ?'id-ce-subjectAltName',
+ extnValue = [{dNSName, Hostname}],
+ critical = false}]},
+ {key, ssl_test_lib:hardcode_rsa_key(3)}
+ ]},
+ client_chain =>
+ #{root => [{key, ssl_test_lib:hardcode_rsa_key(4)}],
+ intermediates => [[{key, ssl_test_lib:hardcode_rsa_key(5)}]],
+ peer => [{key, ssl_test_lib:hardcode_rsa_key(6)}]}}).
+
+certificate_request(Version) ->
+ #certificate_request{certificate_types = certificate_types(Version),
+ hashsign_algorithms = hashsign_algorithms(Version),
+ certificate_authorities = certificate_authorities()}.
+
+certificate_types(?'TLS_v1.3') ->
+ iolist_to_binary([<<?BYTE(?ECDSA_SIGN)>>, <<?BYTE(?RSA_SIGN)>>]);
+certificate_types(?'TLS_v1.2') ->
+ iolist_to_binary([<<?BYTE(?ECDSA_SIGN)>>, <<?BYTE(?RSA_SIGN)>>, <<?BYTE(?DSS_SIGN)>>]);
+certificate_types(_) ->
+ iolist_to_binary([<<?BYTE(?ECDSA_SIGN)>>, <<?BYTE(?RSA_SIGN)>>, <<?BYTE(?DSS_SIGN)>>]).
+
+
+
+signature_algs({3,4}) ->
+ ?LET(Algs, signature_algorithms(),
+ Algs);
+signature_algs({3,3} = Version) ->
+ #hash_sign_algos{hash_sign_algos = hash_alg_list(Version)};
+signature_algs(Version) when Version < {3,3} ->
+ undefined.
+
+
+
+hashsign_algorithms({_, N} = Version) when N >= 3 ->
+ #hash_sign_algos{hash_sign_algos = hash_alg_list(Version)};
+hashsign_algorithms(_) ->
+ undefined.
+
+hash_alg_list(Version) ->
+ ?LET(NumOf, choose(1,15),
+ ?LET(List, [hash_alg(Version) || _ <- lists:seq(1,NumOf)],
+ lists:usort(List)
+ )).
+
+hash_alg(Version) ->
+ ?LET(Alg, sign_algorithm(Version),
+ {hash_algorithm(Version, Alg), Alg}
+ ).
+
+hash_algorithm(?'TLS_v1.3', _) ->
+ oneof([sha, sha224, sha256, sha384, sha512]);
+hash_algorithm(?'TLS_v1.2', rsa) ->
+ oneof([sha, sha224, sha256, sha384, sha512]);
+hash_algorithm(_, rsa) ->
+ oneof([md5, sha, sha224, sha256, sha384, sha512]);
+hash_algorithm(_, ecdsa) ->
+ oneof([sha, sha224, sha256, sha384, sha512]);
+hash_algorithm(_, dsa) ->
+ sha.
+
+sign_algorithm(?'TLS_v1.3') ->
+ oneof([rsa, ecdsa]);
+sign_algorithm(_) ->
+ oneof([rsa, dsa, ecdsa]).
+
+certificate_authorities() ->
+ #{server_config := ServerConf} = cert_conf(),
+ Authorities = proplists:get_value(cacerts, ServerConf),
+ Enc = fun(#'OTPCertificate'{tbsCertificate=TBSCert}) ->
+ OTPSubj = TBSCert#'OTPTBSCertificate'.subject,
+ DNEncodedBin = public_key:pkix_encode('Name', OTPSubj, otp),
+ DNEncodedLen = byte_size(DNEncodedBin),
+ <<?UINT16(DNEncodedLen), DNEncodedBin/binary>>
+ end,
+ list_to_binary([Enc(public_key:pkix_decode_cert(DERCert, otp)) || DERCert <- Authorities]).
+
+digest_size()->
+ oneof([160,224,256,384,512]).
+
+key_share_entry() ->
+ undefined.
+ %%#key_share_entry{}.
+
+server_hello_selected_version(Version) ->
+ #server_hello_selected_version{selected_version = Version}.
+
+sni() ->
+ #sni{hostname = net_adm:localhost()}.
+
+ec_point_formats() ->
+ #ec_point_formats{ec_point_format_list = ec_point_format_list()}.
+
+ec_point_format_list() ->
+ [?ECPOINT_UNCOMPRESSED].
+
+elliptic_curves({_, Minor}) when Minor < 4 ->
+ Curves = tls_v1:ecc_curves(Minor),
+ #elliptic_curves{elliptic_curve_list = Curves}.
+
+%% RFC 8446 (TLS 1.3) renamed the "elliptic_curve" extension.
+supported_groups({_, Minor}) when Minor >= 4 ->
+ SupportedGroups = tls_v1:groups(Minor),
+ #supported_groups{supported_groups = SupportedGroups}.
+
+
+alpn() ->
+ ?LET(ExtD, alpn_protocols(), #alpn{extension_data = ExtD}).
+
+alpn_protocols() ->
+ oneof([<<"spdy/2">>, <<"spdy/3">>, <<"http/2">>, <<"http/1.0">>, <<"http/1.1">>]).
+
+next_protocol_negotiation() ->
+ %% Predecessor to APLN
+ ?LET(ExtD, alpn_protocols(), #next_protocol_negotiation{extension_data = ExtD}).
+
+srp() ->
+ ?LET(Name, gen_name(), #srp{username = list_to_binary(Name)}).
+
+renegotiation_info() ->
+ #renegotiation_info{renegotiated_connection = 0}.
+
+gen_name() ->
+ ?LET(Size, choose(1,10), gen_string(Size)).
+
+gen_char() ->
+ choose($a,$z).
+
+gen_string(N) ->
+ gen_string(N, []).
+
+gen_string(0, Acc) ->
+ Acc;
+gen_string(N, Acc) ->
+ ?LET(Char, gen_char(), gen_string(N-1, [Char | Acc])).
+
+key_share(client_hello) ->
+ ?LET(ClientShares, key_share_entry_list(),
+ #key_share_client_hello{
+ client_shares = ClientShares});
+key_share(server_hello) ->
+ ?LET([ServerShare], key_share_entry_list(1),
+ #key_share_server_hello{
+ server_share = ServerShare}).
+
+key_share_entry_list() ->
+ Max = length(ssl:groups()),
+ ?LET(Size, choose(1,Max), key_share_entry_list(Size)).
+%%
+key_share_entry_list(N) ->
+ key_share_entry_list(N, ssl:groups(), []).
+%%
+key_share_entry_list(0, _Pool, Acc) ->
+ Acc;
+key_share_entry_list(N, Pool, Acc) ->
+ R = rand:uniform(length(Pool)),
+ G = lists:nth(R, Pool),
+ P = generate_public_key(G),
+ KeyShareEntry =
+ #key_share_entry{
+ group = G,
+ key_exchange = P},
+ key_share_entry_list(N - 1, Pool -- [G], [KeyShareEntry|Acc]).
+
+%% TODO: fix curve generation
+generate_public_key(Group)
+ when Group =:= secp256r1 orelse
+ Group =:= secp384r1 orelse
+ Group =:= secp521r1 orelse
+ Group =:= x448 orelse
+ Group =:= x25519 ->
+ #'ECPrivateKey'{publicKey = PublicKey} =
+ public_key:generate_key({namedCurve, secp256r1}),
+ PublicKey;
+generate_public_key(Group) ->
+ {PublicKey, _} =
+ public_key:generate_key(ssl_dh_groups:dh_params(Group)),
+ PublicKey.
+
+groups() ->
+ Max = length(ssl:groups()),
+ ?LET(Size, choose(1,Max), group_list(Size)).
+
+group_list(N) ->
+ group_list(N, ssl:groups(), []).
+%%
+group_list(0, _Pool, Acc) ->
+ Acc;
+group_list(N, Pool, Acc) ->
+ R = rand:uniform(length(Pool)),
+ G = lists:nth(R, Pool),
+ group_list(N - 1, Pool -- [G], [G|Acc]).
diff --git a/lib/ssl/test/ssl.spec b/lib/ssl/test/ssl.spec
index 0ad94e22bc..15587abecd 100644
--- a/lib/ssl/test/ssl.spec
+++ b/lib/ssl/test/ssl.spec
@@ -1,5 +1,12 @@
-{suites,"../ssl_test",all}.
-{skip_cases, "../ssl_test",
- ssl_bench_SUITE, [setup_sequential, setup_concurrent, payload_simple,
- use_pem_cache, bypass_pem_cache],
- "Benchmarks run separately"}.
+% {merge_tests,false}.
+{alias,dir,"../ssl_test"}.
+
+{suites,dir,all}.
+{skip_groups,dir,ssl_bench_SUITE,setup,"Benchmarks run separately"}.
+{skip_groups,dir,ssl_bench_SUITE,payload,"Benchmarks run separately"}.
+{skip_groups,dir,ssl_bench_SUITE,pem_cache,"Benchmarks run separately"}.
+{skip_groups,dir,ssl_dist_bench_SUITE,setup,"Benchmarks run separately"}.
+{skip_groups,dir,ssl_dist_bench_SUITE,roundtrip,"Benchmarks run separately"}.
+{skip_groups,dir,ssl_dist_bench_SUITE,throughput,"Benchmarks run separately"}.
+{skip_groups,dir,ssl_dist_bench_SUITE,sched_utilization,"Benchmarks run separately"}.
+
diff --git a/lib/ssl/test/ssl_ECC.erl b/lib/ssl/test/ssl_ECC.erl
new file mode 100644
index 0000000000..36d949f74b
--- /dev/null
+++ b/lib/ssl/test/ssl_ECC.erl
@@ -0,0 +1,172 @@
+
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+-module(ssl_ECC).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+%% Test diffrent certificate chain types, note that it is the servers
+%% chain that affect what cipher suit that will be choosen
+
+%% ECDH_RSA
+client_ecdh_rsa_server_ecdh_rsa(Config) when is_list(Config) ->
+ Ext = x509_test:extensions([{key_usage, [keyAgreement]}]),
+ Suites = all_rsa_suites(Config),
+ Default = ssl_test_lib:default_cert_chain_conf(),
+ {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain,
+ [[], [], [{extensions, Ext}]]},
+ {client_chain, Default}],
+ ecdh_rsa, ecdh_rsa, Config),
+ ssl_test_lib:basic_test(ssl_test_lib:ssl_options(COpts, Config),
+ ssl_test_lib:ssl_options(SOpts, Config),
+ [{check_keyex, ecdh_rsa}, {ciphers, Suites} | proplists:delete(check_keyex, Config)]).
+client_ecdhe_rsa_server_ecdh_rsa(Config) when is_list(Config) ->
+ Ext = x509_test:extensions([{key_usage, [keyAgreement]}]),
+ Suites = all_rsa_suites(Config),
+ Default = ssl_test_lib:default_cert_chain_conf(),
+ {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain,
+ [[], [], [{extensions, Ext}]]},
+ {client_chain, Default}],
+ ecdhe_rsa, ecdh_rsa, Config),
+ ssl_test_lib:basic_test(ssl_test_lib:ssl_options(COpts, Config),
+ ssl_test_lib:ssl_options(SOpts, Config),
+ [{check_keyex, ecdh_rsa}, {ciphers, Suites} | proplists:delete(check_keyex, Config)]).
+client_ecdhe_ecdsa_server_ecdh_rsa(Config) when is_list(Config) ->
+ Ext = x509_test:extensions([{key_usage, [keyAgreement]}]),
+ Suites = all_rsa_suites(Config),
+ Default = ssl_test_lib:default_cert_chain_conf(),
+ {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain,
+ [[], [], [{extensions, Ext}]]},
+ {client_chain, Default}],
+ ecdhe_ecdsa, ecdh_rsa, Config),
+ ssl_test_lib:basic_test(ssl_test_lib:ssl_options(COpts, Config),
+ ssl_test_lib:ssl_options(SOpts, Config),
+ [{check_keyex, ecdh_rsa}, {ciphers, Suites} | proplists:delete(check_keyex, Config)]).
+
+%% ECDHE_RSA
+client_ecdh_rsa_server_ecdhe_rsa(Config) when is_list(Config) ->
+ Ext = x509_test:extensions([{key_usage, [digitalSignature]}]),
+ Default = ssl_test_lib:default_cert_chain_conf(),
+ {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain,
+ [[], [], [{extensions, Ext}]]},
+ {client_chain, Default}],
+ ecdh_rsa, ecdhe_rsa, Config),
+ ssl_test_lib:basic_test(ssl_test_lib:ssl_options(COpts, Config),
+ ssl_test_lib:ssl_options(SOpts, Config),
+ [{check_keyex, ecdhe_rsa} | proplists:delete(check_keyex, Config)]).
+client_ecdhe_rsa_server_ecdhe_rsa(Config) when is_list(Config) ->
+ Ext = x509_test:extensions([{key_usage, [digitalSignature]}]),
+ Default = ssl_test_lib:default_cert_chain_conf(),
+ {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain,
+ [[], [], [{extensions, Ext}]]},
+ {client_chain, Default}],
+ ecdhe_rsa, ecdhe_rsa, Config),
+ ssl_test_lib:basic_test(ssl_test_lib:ssl_options(COpts, Config),
+ ssl_test_lib:ssl_options(SOpts, Config),
+ [{check_keyex, ecdhe_rsa} | proplists:delete(check_keyex, Config)]).
+client_ecdhe_ecdsa_server_ecdhe_rsa(Config) when is_list(Config) ->
+ Ext = x509_test:extensions([{key_usage, [digitalSignature]}]),
+ Default = ssl_test_lib:default_cert_chain_conf(),
+ {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain,
+ [[], [], [{extensions, Ext}]]},
+ {client_chain, Default}],
+ ecdh_ecdsa, ecdhe_rsa, Config),
+ ssl_test_lib:basic_test(ssl_test_lib:ssl_options(COpts, Config),
+ ssl_test_lib:ssl_options(SOpts, Config),
+ [{check_keyex, ecdhe_rsa} | proplists:delete(check_keyex, Config)]).
+
+%% ECDH_ECDSA
+client_ecdh_ecdsa_server_ecdh_ecdsa(Config) when is_list(Config) ->
+ Ext = x509_test:extensions([{key_usage, [keyAgreement]}]),
+ {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain,
+ [[], [], [{extensions, Ext}]]},
+ {client_chain,
+ ssl_test_lib:default_cert_chain_conf()}],
+ ecdh_ecdsa, ecdh_ecdsa, Config),
+ ssl_test_lib:basic_test(ssl_test_lib:ssl_options(COpts, Config),
+ ssl_test_lib:ssl_options(SOpts, Config),
+ [{check_keyex, ecdh_ecdsa} | proplists:delete(check_keyex, Config)]).
+client_ecdhe_rsa_server_ecdh_ecdsa(Config) when is_list(Config) ->
+ Ext = x509_test:extensions([{key_usage, [keyAgreement]}]),
+ {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain,
+ [[], [], [{extensions, Ext}]]},
+ {client_chain,
+ ssl_test_lib:default_cert_chain_conf()}],
+ ecdhe_rsa, ecdh_ecdsa, Config),
+ ssl_test_lib:basic_test(ssl_test_lib:ssl_options(COpts, Config),
+ ssl_test_lib:ssl_options(SOpts, Config),
+ [{check_keyex, ecdh_ecdsa} | proplists:delete(check_keyex, Config)]).
+
+client_ecdhe_ecdsa_server_ecdh_ecdsa(Config) when is_list(Config) ->
+ Ext = x509_test:extensions([{key_usage, [keyAgreement]}]),
+ {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain,
+ [[], [], [{extensions, Ext}]]},
+ {client_chain,
+ ssl_test_lib:default_cert_chain_conf()}],
+ ecdhe_ecdsa, ecdh_ecdsa, Config),
+ ssl_test_lib:basic_test(ssl_test_lib:ssl_options(COpts, Config),
+ ssl_test_lib:ssl_options(SOpts, Config),
+ [{check_keyex, ecdh_ecdsa} | proplists:delete(check_keyex, Config)]).
+
+%% ECDHE_ECDSA
+client_ecdh_rsa_server_ecdhe_ecdsa(Config) when is_list(Config) ->
+ Ext = x509_test:extensions([{key_usage, [digitalSignature]}]),
+ Default = ssl_test_lib:default_cert_chain_conf(),
+ {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain,
+ [[], [], [{extensions, Ext}]]},
+ {client_chain, Default}],
+ ecdh_rsa, ecdhe_ecdsa, Config),
+ ssl_test_lib:basic_test(ssl_test_lib:ssl_options(COpts, Config),
+ ssl_test_lib:ssl_options(SOpts, Config),
+ [{check_keyex, ecdhe_ecdsa} | proplists:delete(check_keyex, Config)]).
+client_ecdh_ecdsa_server_ecdhe_ecdsa(Config) when is_list(Config) ->
+ Ext = x509_test:extensions([{key_usage, [digitalSignature]}]),
+ Default = ssl_test_lib:default_cert_chain_conf(),
+ {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain,
+ [[], [], [{extensions, Ext}]]},
+ {client_chain, Default}],
+ ecdh_ecdsa, ecdhe_ecdsa, Config),
+ ssl_test_lib:basic_test(ssl_test_lib:ssl_options(COpts, Config),
+ ssl_test_lib:ssl_options(SOpts, Config),
+ [{check_keyex, ecdhe_ecdsa} | proplists:delete(check_keyex, Config)]).
+client_ecdhe_ecdsa_server_ecdhe_ecdsa(Config) when is_list(Config) ->
+ Ext = x509_test:extensions([{key_usage, [digitalSignature]}]),
+ Default = ssl_test_lib:default_cert_chain_conf(),
+ {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain,
+ [[], [], [{extensions, Ext}]]},
+ {client_chain, Default}],
+ ecdhe_ecdsa, ecdhe_ecdsa, Config),
+ ssl_test_lib:basic_test(ssl_test_lib:ssl_options(COpts, Config),
+ ssl_test_lib:ssl_options(SOpts, Config),
+ [{check_keyex, ecdhe_ecdsa} | proplists:delete(check_keyex, Config)]).
+
+all_rsa_suites(Config) ->
+ Version = proplists:get_value(tls_version, Config),
+ All = ssl:cipher_suites(all, Version),
+ Default = ssl:cipher_suites(default, Version),
+ RSASuites = ssl:filter_cipher_suites(All,[{key_exchange, fun(rsa) -> true;(_) -> false end}]),
+ ssl:append_cipher_suites(RSASuites, Default).
diff --git a/lib/ssl/test/ssl_ECC_SUITE.erl b/lib/ssl/test/ssl_ECC_SUITE.erl
index f38c0a7416..d02888793c 100644
--- a/lib/ssl/test/ssl_ECC_SUITE.erl
+++ b/lib/ssl/test/ssl_ECC_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -43,79 +43,15 @@ all() ->
groups() ->
[
- {'tlsv1.2', [], all_versions_groups()},
- {'tlsv1.1', [], all_versions_groups()},
- {'tlsv1', [], all_versions_groups()},
- {'dtlsv1.2', [], all_versions_groups()},
- {'dtlsv1', [], all_versions_groups()},
- {'erlang_server', [], openssl_key_cert_combinations()},
- %%{'erlang_client', [], openssl_key_cert_combinations()},
- {'erlang', [], key_cert_combinations() ++ misc()
- ++ ecc_negotiation()}
- ].
-
-all_versions_groups ()->
- [{group, 'erlang_server'},
- %%{group, 'erlang_client'},
- {group, 'erlang'}
+ {'tlsv1.2', [], [mix_sign | test_cases()]},
+ {'tlsv1.1', [], test_cases()},
+ {'tlsv1', [], test_cases()},
+ {'dtlsv1.2', [], [mix_sign | test_cases()]},
+ {'dtlsv1', [], test_cases()}
].
-
-openssl_key_cert_combinations() ->
- ECDH_RSA = case ssl_test_lib:openssl_filter("ECDH-RSA") of
- [] ->
- [];
- _ ->
- server_ecdh_rsa()
- end,
-
- ECDHE_RSA = case ssl_test_lib:openssl_filter("ECDHE-RSA") of
- [] ->
- [];
- _ ->
- server_ecdhe_rsa()
- end,
- ECDH_ECDSA = case ssl_test_lib:openssl_filter("ECDH-ECDSA") of
- [] ->
- [];
- _ ->
- server_ecdhe_ecdsa()
- end,
-
- ECDHE_ECDSA = case ssl_test_lib:openssl_filter("ECDHE-ECDSA") of
- [] ->
- [];
- _ ->
- server_ecdhe_ecdsa()
- end,
- ECDH_RSA ++ ECDHE_RSA ++ ECDH_ECDSA ++ ECDHE_ECDSA.
-
-key_cert_combinations() ->
- server_ecdh_rsa() ++
- server_ecdhe_rsa() ++
- server_ecdh_ecdsa() ++
- server_ecdhe_ecdsa().
-
-server_ecdh_rsa() ->
- [client_ecdh_rsa_server_ecdh_rsa,
- client_ecdhe_rsa_server_ecdh_rsa,
- client_ecdhe_ecdsa_server_ecdh_rsa].
-
-server_ecdhe_rsa() ->
- [client_ecdh_rsa_server_ecdhe_rsa,
- client_ecdhe_rsa_server_ecdhe_rsa,
- client_ecdhe_ecdsa_server_ecdhe_rsa].
-
-server_ecdh_ecdsa() ->
- [client_ecdh_ecdsa_server_ecdh_ecdsa,
- client_ecdhe_rsa_server_ecdh_ecdsa,
- client_ecdhe_ecdsa_server_ecdh_ecdsa].
-
-server_ecdhe_ecdsa() ->
- [client_ecdh_rsa_server_ecdhe_ecdsa,
- client_ecdh_ecdsa_server_ecdhe_ecdsa,
- client_ecdhe_ecdsa_server_ecdhe_ecdsa].
-
+test_cases()->
+ misc() ++ ecc_negotiation().
misc()->
[client_ecdsa_server_ecdsa_with_raw_key].
@@ -142,9 +78,14 @@ init_per_suite(Config0) ->
end_per_suite(Config0),
try crypto:start() of
ok ->
- Config0
+ case ssl_test_lib:sufficient_crypto_support(cipher_ec) of
+ true ->
+ Config0;
+ false ->
+ {skip, "Crypto does not support ECC"}
+ end
catch _:_ ->
- {skip, "Crypto did not start"}
+ {skip, "Crypto did not start"}
end.
end_per_suite(_Config) ->
@@ -152,52 +93,14 @@ end_per_suite(_Config) ->
application:stop(crypto).
%%--------------------------------------------------------------------
-init_per_group(erlang_client = Group, Config) ->
- case ssl_test_lib:is_sane_ecc(openssl) of
- true ->
- common_init_per_group(Group, [{server_type, openssl},
- {client_type, erlang} | Config]);
- false ->
- {skip, "Known ECC bug in openssl"}
- end;
-
-init_per_group(erlang_server = Group, Config) ->
- case ssl_test_lib:is_sane_ecc(openssl) of
- true ->
- common_init_per_group(Group, [{server_type, erlang},
- {client_type, openssl} | Config]);
- false ->
- {skip, "Known ECC bug in openssl"}
- end;
-
-init_per_group(erlang = Group, Config) ->
- case ssl_test_lib:sufficient_crypto_support(Group) of
- true ->
- common_init_per_group(Group, [{server_type, erlang},
- {client_type, erlang} | Config]);
- false ->
- {skip, "Crypto does not support ECC"}
- end;
-
-init_per_group(openssl = Group, Config) ->
- case ssl_test_lib:sufficient_crypto_support(Group) of
- true ->
- common_init_per_group(Group, [{server_type, openssl},
- {client_type, openssl} | Config]);
- false ->
- {skip, "Crypto does not support ECC"}
- end;
-
-init_per_group(Group, Config) ->
- common_init_per_group(Group, Config).
-
-common_init_per_group(GroupName, Config) ->
+init_per_group(GroupName, Config) ->
case ssl_test_lib:is_tls_version(GroupName) of
true ->
- Config0 = ssl_test_lib:init_tls_version(GroupName, Config),
- [{tls_version, GroupName} | Config0];
- _ ->
- openssl_check(GroupName, Config)
+ [{tls_version, GroupName},
+ {server_type, erlang},
+ {client_type, erlang} | ssl_test_lib:init_tls_version(GroupName, Config)];
+ _ ->
+ Config
end.
end_per_group(GroupName, Config0) ->
@@ -215,7 +118,7 @@ init_per_testcase(TestCase, Config) ->
ssl_test_lib:ct_log_supported_protocol_versions(Config),
ct:log("Ciphers: ~p~n ", [ ssl:cipher_suites()]),
end_per_testcase(TestCase, Config),
- ssl_test_lib:clean_start(),
+ ssl:start(),
ct:timetrap({seconds, 15}),
Config.
@@ -226,104 +129,16 @@ end_per_testcase(_TestCase, Config) ->
%%--------------------------------------------------------------------
%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
-
%% Test diffrent certificate chain types, note that it is the servers
%% chain that affect what cipher suit that will be choosen
-%% ECDH_RSA
-client_ecdh_rsa_server_ecdh_rsa(Config) when is_list(Config) ->
- Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
- {client_chain, Default}],
- ecdh_rsa, ecdh_rsa, Config),
- basic_test(COpts, SOpts, [{check_keyex, ecdh_rsa} | proplists:delete(check_keyex, Config)]).
-client_ecdhe_rsa_server_ecdh_rsa(Config) when is_list(Config) ->
- Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
- {client_chain, Default}],
- ecdhe_rsa, ecdh_rsa, Config),
- basic_test(COpts, SOpts, [{check_keyex, ecdh_rsa} | proplists:delete(check_keyex, Config)]).
-client_ecdhe_ecdsa_server_ecdh_rsa(Config) when is_list(Config) ->
- Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
- {client_chain, Default}],
- ecdhe_ecdsa, ecdh_rsa, Config),
- basic_test(COpts, SOpts, [{check_keyex, ecdh_rsa} | proplists:delete(check_keyex, Config)]).
-
-%% ECDHE_RSA
-client_ecdh_rsa_server_ecdhe_rsa(Config) when is_list(Config) ->
- Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
- {client_chain, Default}],
- ecdh_rsa, ecdhe_rsa, Config),
- basic_test(COpts, SOpts, [{check_keyex, ecdhe_rsa} | proplists:delete(check_keyex, Config)]).
-client_ecdhe_rsa_server_ecdhe_rsa(Config) when is_list(Config) ->
- Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
- {client_chain, Default}],
- ecdhe_rsa, ecdhe_rsa, Config),
- basic_test(COpts, SOpts, [{check_keyex, ecdhe_rsa} | proplists:delete(check_keyex, Config)]).
-client_ecdhe_ecdsa_server_ecdhe_rsa(Config) when is_list(Config) ->
- Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
- {client_chain, Default}],
- ecdh_ecdsa, ecdhe_rsa, Config),
- basic_test(COpts, SOpts, [{check_keyex, ecdhe_rsa} | proplists:delete(check_keyex, Config)]).
-
-%% ECDH_ECDSA
-client_ecdh_ecdsa_server_ecdh_ecdsa(Config) when is_list(Config) ->
- Ext = x509_test:extensions([{key_usage, [keyEncipherment]}]),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain,
- [[], [], [{extensions, Ext}]]},
- {client_chain,
- ssl_test_lib:default_cert_chain_conf()}],
- ecdh_ecdsa, ecdh_ecdsa, Config),
- basic_test(COpts, SOpts,
- [{check_keyex, ecdh_ecdsa} | proplists:delete(check_keyex, Config)]).
-client_ecdhe_rsa_server_ecdh_ecdsa(Config) when is_list(Config) ->
- Ext = x509_test:extensions([{key_usage, [keyEncipherment]}]),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain,
- [[], [], [{extensions, Ext}]]},
- {client_chain,
- ssl_test_lib:default_cert_chain_conf()}],
- ecdhe_rsa, ecdh_ecdsa, Config),
- basic_test(COpts, SOpts, [{check_keyex, ecdh_ecdsa} | proplists:delete(check_keyex, Config)]).
-
-client_ecdhe_ecdsa_server_ecdh_ecdsa(Config) when is_list(Config) ->
- Ext = x509_test:extensions([{key_usage, [keyEncipherment]}]),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain,
- [[], [], [{extensions, Ext}]]},
- {client_chain,
- ssl_test_lib:default_cert_chain_conf()}],
- ecdhe_ecdsa, ecdh_ecdsa, Config),
- basic_test(COpts, SOpts,
- [{check_keyex, ecdh_ecdsa} | proplists:delete(check_keyex, Config)]).
-
-%% ECDHE_ECDSA
-client_ecdh_rsa_server_ecdhe_ecdsa(Config) when is_list(Config) ->
- Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
- {client_chain, Default}],
- ecdh_rsa, ecdhe_ecdsa, Config),
- basic_test(COpts, SOpts, [{check_keyex, ecdhe_ecdsa} | proplists:delete(check_keyex, Config)]).
-client_ecdh_ecdsa_server_ecdhe_ecdsa(Config) when is_list(Config) ->
- Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
- {client_chain, Default}],
- ecdh_ecdsa, ecdhe_ecdsa, Config),
- basic_test(COpts, SOpts, [{check_keyex, ecdhe_ecdsa} | proplists:delete(check_keyex, Config)]).
-client_ecdhe_ecdsa_server_ecdhe_ecdsa(Config) when is_list(Config) ->
- Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
- {client_chain, Default}],
- ecdhe_ecdsa, ecdhe_ecdsa, Config),
- basic_test(COpts, SOpts, [{check_keyex, ecdhe_ecdsa} | proplists:delete(check_keyex, Config)]).
-
client_ecdsa_server_ecdsa_with_raw_key(Config) when is_list(Config) ->
Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
+ {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
{client_chain, Default}]
, ecdhe_ecdsa, ecdhe_ecdsa, Config),
+ COpts = ssl_test_lib:ssl_options(COpts0, Config),
+ SOpts = ssl_test_lib:ssl_options(SOpts0, Config),
ServerKeyFile = proplists:get_value(keyfile, SOpts),
{ok, PemBin} = file:read_file(ServerKeyFile),
PemEntries = public_key:pem_decode(PemBin),
@@ -331,331 +146,234 @@ client_ecdsa_server_ecdsa_with_raw_key(Config) when is_list(Config) ->
ServerKey = {'ECPrivateKey', Key},
SType = proplists:get_value(server_type, Config),
CType = proplists:get_value(client_type, Config),
- {Server, Port} = start_server_with_raw_key(SType,
- [{key, ServerKey} | proplists:delete(keyfile, SOpts)],
- Config),
- Client = start_client(CType, Port, COpts, Config),
- check_result(Server, SType, Client, CType),
- close(Server, Client).
+ {Server, Port} = ssl_test_lib:start_server_with_raw_key(SType,
+ [{key, ServerKey} | proplists:delete(keyfile, SOpts)],
+ Config),
+ Client = ssl_test_lib:start_client(CType, Port, COpts, Config),
+ ssl_test_lib:gen_check_result(Server, SType, Client, CType),
+ ssl_test_lib:stop(Server, Client).
ecc_default_order(Config) ->
Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
- {client_chain, Default}],
- ecdhe_ecdsa, ecdhe_ecdsa, Config),
+ DefaultCurve = pubkey_cert_records:namedCurves(hd(tls_v1:ecc_curves(1))),
+ {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
+ {client_chain, Default}],
+ ecdhe_ecdsa, ecdhe_ecdsa,
+ Config, DefaultCurve),
+ COpts = ssl_test_lib:ssl_options(COpts0, Config),
+ SOpts = ssl_test_lib:ssl_options(SOpts0, Config),
ECCOpts = [],
- case supported_eccs([{eccs, [sect571r1]}]) of
- true -> ecc_test(sect571r1, COpts, SOpts, [], ECCOpts, Config);
+ case ssl_test_lib:supported_eccs([{eccs, [DefaultCurve]}]) of
+ true -> ssl_test_lib:ecc_test(DefaultCurve, COpts, SOpts, [], ECCOpts, Config);
false -> {skip, "unsupported named curves"}
end.
ecc_default_order_custom_curves(Config) ->
Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
- {client_chain, Default}],
- ecdhe_ecdsa, ecdhe_ecdsa, Config),
- ECCOpts = [{eccs, [secp256r1, sect571r1]}],
- case supported_eccs(ECCOpts) of
- true -> ecc_test(sect571r1, COpts, SOpts, [], ECCOpts, Config);
+ DefaultCurve = pubkey_cert_records:namedCurves(hd(tls_v1:ecc_curves(1))),
+ {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
+ {client_chain, Default}],
+ ecdhe_ecdsa, ecdhe_ecdsa,
+ Config, DefaultCurve),
+ COpts = ssl_test_lib:ssl_options(COpts0, Config),
+ SOpts = ssl_test_lib:ssl_options(SOpts0, Config),
+ ECCOpts = [{eccs, [secp256r1, DefaultCurve]}],
+ case ssl_test_lib:supported_eccs(ECCOpts) of
+ true -> ssl_test_lib:ecc_test(DefaultCurve, COpts, SOpts, [], ECCOpts, Config);
false -> {skip, "unsupported named curves"}
end.
ecc_client_order(Config) ->
Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
- {client_chain, Default}],
- ecdhe_ecdsa, ecdhe_ecdsa, Config),
+ DefaultCurve = pubkey_cert_records:namedCurves(hd(tls_v1:ecc_curves(1))),
+ {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
+ {client_chain, Default}],
+ ecdhe_ecdsa, ecdhe_ecdsa,
+ Config, DefaultCurve),
+ COpts = ssl_test_lib:ssl_options(COpts0, Config),
+ SOpts = ssl_test_lib:ssl_options(SOpts0, Config),
ECCOpts = [{honor_ecc_order, false}],
- case supported_eccs([{eccs, [sect571r1]}]) of
- true -> ecc_test(sect571r1, COpts, SOpts, [], ECCOpts, Config);
+ case ssl_test_lib:supported_eccs([{eccs, [DefaultCurve]}]) of
+ true -> ssl_test_lib:ecc_test(DefaultCurve, COpts, SOpts, [], ECCOpts, Config);
false -> {skip, "unsupported named curves"}
end.
ecc_client_order_custom_curves(Config) ->
Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
+ DefaultCurve = pubkey_cert_records:namedCurves(hd(tls_v1:ecc_curves(1))),
+ {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
{client_chain, Default}],
- ecdhe_ecdsa, ecdhe_ecdsa, Config),
- ECCOpts = [{honor_ecc_order, false}, {eccs, [secp256r1, sect571r1]}],
- case supported_eccs(ECCOpts) of
- true -> ecc_test(sect571r1, COpts, SOpts, [], ECCOpts, Config);
+ ecdhe_ecdsa, ecdhe_ecdsa,
+ Config, DefaultCurve),
+ COpts = ssl_test_lib:ssl_options(COpts0, Config),
+ SOpts = ssl_test_lib:ssl_options(SOpts0, Config),
+ ECCOpts = [{honor_ecc_order, false}, {eccs, [secp256r1, DefaultCurve]}],
+ case ssl_test_lib:supported_eccs(ECCOpts) of
+ true -> ssl_test_lib:ecc_test(DefaultCurve, COpts, SOpts, [], ECCOpts, Config);
false -> {skip, "unsupported named curves"}
end.
ecc_unknown_curve(Config) ->
Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
+ {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
{client_chain, Default}],
ecdhe_ecdsa, ecdhe_ecdsa, Config),
+ COpts = ssl_test_lib:ssl_options(COpts0, Config),
+ SOpts = ssl_test_lib:ssl_options(SOpts0, Config),
ECCOpts = [{eccs, ['123_fake_curve']}],
- ecc_test_error(COpts, SOpts, [], ECCOpts, Config).
+ ssl_test_lib:ecc_test_error(COpts, SOpts, [], ECCOpts, Config).
client_ecdh_rsa_server_ecdhe_ecdsa_server_custom(Config) ->
Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
+ DefaultCurve = pubkey_cert_records:namedCurves(hd(tls_v1:ecc_curves(1))),
+ {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
{client_chain, Default}],
- ecdh_rsa, ecdhe_ecdsa, Config),
- ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}],
- case supported_eccs(ECCOpts) of
- true -> ecc_test(secp256r1, COpts, SOpts, [], ECCOpts, Config);
+ ecdh_rsa, ecdhe_ecdsa, Config),
+ COpts = ssl_test_lib:ssl_options(COpts0, Config),
+ SOpts = ssl_test_lib:ssl_options(SOpts0, Config),
+ ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, DefaultCurve]}],
+ case ssl_test_lib:supported_eccs(ECCOpts) of
+ true -> ssl_test_lib:ecc_test(secp256r1, COpts, SOpts, [], ECCOpts, Config);
false -> {skip, "unsupported named curves"}
end.
client_ecdh_rsa_server_ecdhe_rsa_server_custom(Config) ->
Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
- {client_chain, Default}],
- ecdh_rsa, ecdhe_rsa, Config),
- ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}],
- case supported_eccs(ECCOpts) of
- true -> ecc_test(undefined, COpts, SOpts, [], ECCOpts, Config);
+ DefaultCurve = pubkey_cert_records:namedCurves(hd(tls_v1:ecc_curves(1))),
+ {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
+ {client_chain, Default}],
+ ecdh_rsa, ecdhe_rsa, Config),
+ COpts = ssl_test_lib:ssl_options(COpts0, Config),
+ SOpts = ssl_test_lib:ssl_options(SOpts0, Config),
+ ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, DefaultCurve]}],
+
+ case ssl_test_lib:supported_eccs(ECCOpts) of
+ true -> ssl_test_lib:ecc_test(secp256r1, COpts, SOpts, [], ECCOpts, Config);
false -> {skip, "unsupported named curves"}
end.
client_ecdhe_rsa_server_ecdhe_ecdsa_server_custom(Config) ->
Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
- {client_chain, Default}],
- ecdhe_rsa, ecdhe_ecdsa, Config),
- ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}],
- case supported_eccs(ECCOpts) of
- true -> ecc_test(secp256r1, COpts, SOpts, [], ECCOpts, Config);
+ DefaultCurve = pubkey_cert_records:namedCurves(hd(tls_v1:ecc_curves(1))),
+ {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
+ {client_chain, Default}],
+ ecdhe_rsa, ecdhe_ecdsa, Config),
+ COpts = ssl_test_lib:ssl_options(COpts0, Config),
+ SOpts = ssl_test_lib:ssl_options(SOpts0, Config),
+ ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, DefaultCurve]}],
+ case ssl_test_lib:supported_eccs(ECCOpts) of
+ true -> ssl_test_lib:ecc_test(secp256r1, COpts, SOpts, [], ECCOpts, Config);
false -> {skip, "unsupported named curves"}
end.
client_ecdhe_rsa_server_ecdhe_rsa_server_custom(Config) ->
Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
- {client_chain, Default}],
- ecdhe_rsa, ecdhe_rsa, Config),
- ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}],
- case supported_eccs(ECCOpts) of
- true -> ecc_test(undefined, COpts, SOpts, [], ECCOpts, Config);
+ DefaultCurve = pubkey_cert_records:namedCurves(hd(tls_v1:ecc_curves(1))),
+ {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
+ {client_chain, Default}],
+ ecdhe_rsa, ecdhe_rsa, Config),
+
+ COpts = ssl_test_lib:ssl_options(COpts0, Config),
+ SOpts = ssl_test_lib:ssl_options(SOpts0, Config),
+ ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, DefaultCurve]}],
+ case ssl_test_lib:supported_eccs(ECCOpts) of
+ true -> ssl_test_lib:ecc_test(secp256r1, COpts, SOpts, [], ECCOpts, Config);
false -> {skip, "unsupported named curves"}
end.
client_ecdhe_rsa_server_ecdh_rsa_server_custom(Config) ->
Default = ssl_test_lib:default_cert_chain_conf(),
+ DefaultCurve = pubkey_cert_records:namedCurves(hd(tls_v1:ecc_curves(1))),
Ext = x509_test:extensions([{key_usage, [keyEncipherment]}]),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, [[], [], [{extensions, Ext}]]},
- {client_chain, Default}],
- ecdhe_rsa, ecdh_rsa, Config),
- ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}],
- case supported_eccs(ECCOpts) of
- true -> ecc_test(undefined, COpts, SOpts, [], ECCOpts, Config);
+ {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, [[], [], [{extensions, Ext}]]},
+ {client_chain, Default}],
+ ecdhe_rsa, ecdh_rsa, Config),
+
+ COpts = ssl_test_lib:ssl_options(COpts0, Config),
+ SOpts = ssl_test_lib:ssl_options(SOpts0, Config),
+ ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, DefaultCurve]}],
+ Expected = secp256r1, %% The certificate curve
+
+ case ssl_test_lib:supported_eccs(ECCOpts) of
+ true -> ssl_test_lib:ecc_test(Expected, COpts, SOpts, [], ECCOpts, Config);
false -> {skip, "unsupported named curves"}
end.
client_ecdhe_ecdsa_server_ecdhe_ecdsa_server_custom(Config) ->
Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
+ DefaultCurve = pubkey_cert_records:namedCurves(hd(tls_v1:ecc_curves(1))),
+ {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
{client_chain, Default}],
- ecdhe_ecdsa, ecdhe_ecdsa, Config),
- ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}],
- case supported_eccs(ECCOpts) of
- true -> ecc_test(secp256r1, COpts, SOpts, [], ECCOpts, Config);
+ ecdhe_ecdsa, ecdhe_ecdsa, Config),
+ COpts = ssl_test_lib:ssl_options(COpts0, Config),
+ SOpts = ssl_test_lib:ssl_options(SOpts0, Config),
+ ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, DefaultCurve]}],
+ case ssl_test_lib:supported_eccs(ECCOpts) of
+ true -> ssl_test_lib:ecc_test(secp256r1, COpts, SOpts, [], ECCOpts, Config);
false -> {skip, "unsupported named curves"}
end.
client_ecdhe_ecdsa_server_ecdhe_rsa_server_custom(Config) ->
Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
- {client_chain, Default}],
- ecdhe_ecdsa, ecdhe_rsa, Config),
- ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}],
- case supported_eccs(ECCOpts) of
- true -> ecc_test(undefined, COpts, SOpts, [], ECCOpts, Config);
+ DefaultCurve = pubkey_cert_records:namedCurves(hd(tls_v1:ecc_curves(1))),
+ {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
+ {client_chain, Default}],
+ ecdhe_ecdsa, ecdhe_rsa, Config),
+ COpts = ssl_test_lib:ssl_options(COpts0, Config),
+ SOpts = ssl_test_lib:ssl_options(SOpts0, Config),
+ ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, DefaultCurve]}],
+ case ssl_test_lib:supported_eccs(ECCOpts) of
+ true -> ssl_test_lib:ecc_test(secp256r1, COpts, SOpts, [], ECCOpts, Config);
false -> {skip, "unsupported named curves"}
end.
client_ecdhe_ecdsa_server_ecdhe_ecdsa_client_custom(Config) ->
Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
+ DefaultCurve = pubkey_cert_records:namedCurves(hd(tls_v1:ecc_curves(1))),
+ {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
{client_chain, Default}],
- ecdhe_ecdsa, ecdhe_ecdsa, Config),
- ECCOpts = [{eccs, [secp256r1, sect571r1]}],
- case supported_eccs(ECCOpts) of
- true -> ecc_test(secp256r1, COpts, SOpts, ECCOpts, [], Config);
+ ecdhe_ecdsa, ecdhe_ecdsa, Config),
+ COpts = ssl_test_lib:ssl_options(COpts0, Config),
+ SOpts = ssl_test_lib:ssl_options(SOpts0, Config),
+ ECCOpts = [{eccs, [secp256r1, DefaultCurve]}],
+ case ssl_test_lib:supported_eccs(ECCOpts) of
+ true -> ssl_test_lib:ecc_test(secp256r1, COpts, SOpts, ECCOpts, [], Config);
false -> {skip, "unsupported named curves"}
end.
client_ecdhe_rsa_server_ecdhe_ecdsa_client_custom(Config) ->
Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
- {client_chain, Default}],
- ecdhe_rsa, ecdhe_ecdsa, Config),
- ECCOpts = [{eccs, [secp256r1, sect571r1]}],
- case supported_eccs(ECCOpts) of
- true -> ecc_test(secp256r1, COpts, SOpts, ECCOpts, [], Config);
+ DefaultCurve = pubkey_cert_records:namedCurves(hd(tls_v1:ecc_curves(1))),
+ {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
+ {client_chain, Default}],
+ ecdhe_rsa, ecdhe_ecdsa, Config),
+ COpts = ssl_test_lib:ssl_options(COpts0, Config),
+ SOpts = ssl_test_lib:ssl_options(SOpts0, Config),
+ ECCOpts = [{eccs, [secp256r1, DefaultCurve]}],
+ case ssl_test_lib:supported_eccs(ECCOpts) of
+ true -> ssl_test_lib:ecc_test(secp256r1, COpts, SOpts, ECCOpts, [], Config);
false -> {skip, "unsupported named curves"}
end.
-%%--------------------------------------------------------------------
-%% Internal functions ------------------------------------------------
-%%--------------------------------------------------------------------
-basic_test(COpts, SOpts, Config) ->
- SType = proplists:get_value(server_type, Config),
- CType = proplists:get_value(client_type, Config),
- {Server, Port} = start_server(SType, SOpts, Config),
- Client = start_client(CType, Port, COpts, Config),
- check_result(Server, SType, Client, CType),
- close(Server, Client).
-
-
-ecc_test(Expect, COpts, SOpts, CECCOpts, SECCOpts, Config) ->
- {Server, Port} = start_server_ecc(erlang, SOpts, Expect, SECCOpts, Config),
- Client = start_client_ecc(erlang, Port, COpts, Expect, CECCOpts, Config),
- ssl_test_lib:check_result(Server, ok, Client, ok),
- close(Server, Client).
-
-ecc_test_error(COpts, SOpts, CECCOpts, SECCOpts, Config) ->
- {Server, Port} = start_server_ecc_error(erlang, SOpts, SECCOpts, Config),
- Client = start_client_ecc_error(erlang, Port, COpts, CECCOpts, Config),
- Error = {error, {tls_alert, "insufficient security"}},
- ssl_test_lib:check_result(Server, Error, Client, Error).
-
-
-start_client(openssl, Port, ClientOpts, _Config) ->
- Cert = proplists:get_value(certfile, ClientOpts),
- Key = proplists:get_value(keyfile, ClientOpts),
- CA = proplists:get_value(cacertfile, ClientOpts),
- Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
- Exe = "openssl",
- Args = ["s_client", "-verify", "2", "-port", integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cert", Cert, "-CAfile", CA,
- "-key", Key, "-host","localhost", "-msg", "-debug"],
-
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
- true = port_command(OpenSslPort, "Hello world"),
- OpenSslPort;
-
-start_client(erlang, Port, ClientOpts, Config) ->
- {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
- KeyEx = proplists:get_value(check_keyex, Config, false),
- ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, check_key_exchange_send_active, [KeyEx]}},
- {options, [{verify, verify_peer} | ClientOpts]}]).
-
-
-start_client_ecc(erlang, Port, ClientOpts, Expect, ECCOpts, Config) ->
- {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
- ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, check_ecc, [client, Expect]}},
- {options,
- ECCOpts ++
- [{verify, verify_peer} | ClientOpts]}]).
-
-start_client_ecc_error(erlang, Port, ClientOpts, ECCOpts, Config) ->
- {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
- ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {options,
- ECCOpts ++
- [{verify, verify_peer} | ClientOpts]}]).
-
-
-start_server(openssl, ServerOpts, _Config) ->
- Cert = proplists:get_value(certfile, ServerOpts),
- Key = proplists:get_value(keyfile, ServerOpts),
- CA = proplists:get_value(cacertfile, ServerOpts),
- Port = ssl_test_lib:inet_port(node()),
- Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version),
- "-verify", "2", "-cert", Cert, "-CAfile", CA,
- "-key", Key, "-msg", "-debug"],
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
- true = port_command(OpenSslPort, "Hello world"),
- {OpenSslPort, Port};
-start_server(erlang, ServerOpts, Config) ->
- {_, ServerNode, _} = ssl_test_lib:run_where(Config),
- KeyEx = proplists:get_value(check_keyex, Config, false),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib,
- check_key_exchange_send_active,
- [KeyEx]}},
- {options, [{verify, verify_peer} | ServerOpts]}]),
- {Server, ssl_test_lib:inet_port(Server)}.
-
-start_server_with_raw_key(erlang, ServerOpts, Config) ->
- {_, ServerNode, _} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib,
- send_recv_result_active,
- []}},
- {options,
- [{verify, verify_peer} | ServerOpts]}]),
- {Server, ssl_test_lib:inet_port(Server)}.
-
-start_server_ecc(erlang, ServerOpts, Expect, ECCOpts, Config) ->
- {_, ServerNode, _} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, check_ecc, [server, Expect]}},
- {options,
- ECCOpts ++
- [{verify, verify_peer} | ServerOpts]}]),
- {Server, ssl_test_lib:inet_port(Server)}.
-
-start_server_ecc_error(erlang, ServerOpts, ECCOpts, Config) ->
- {_, ServerNode, _} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {options,
- ECCOpts ++
- [{verify, verify_peer} | ServerOpts]}]),
- {Server, ssl_test_lib:inet_port(Server)}.
-
-check_result(Server, erlang, Client, erlang) ->
- ssl_test_lib:check_result(Server, ok, Client, ok);
-check_result(Server, erlang, _, _) ->
- ssl_test_lib:check_result(Server, ok);
-check_result(_, _, Client, erlang) ->
- ssl_test_lib:check_result(Client, ok);
-check_result(_,openssl, _, openssl) ->
- ok.
-
-openssl_check(erlang, Config) ->
- Config;
-openssl_check(_, Config) ->
- TLSVersion = proplists:get_value(tls_version, Config),
- case ssl_test_lib:check_sane_openssl_version(TLSVersion) of
- true ->
- Config;
- false ->
- {skip, "TLS version not supported by openssl"}
- end.
-
-close(Port1, Port2) when is_port(Port1), is_port(Port2) ->
- ssl_test_lib:close_port(Port1),
- ssl_test_lib:close_port(Port2);
-close(Port, Pid) when is_port(Port) ->
- ssl_test_lib:close_port(Port),
- ssl_test_lib:close(Pid);
-close(Pid, Port) when is_port(Port) ->
- ssl_test_lib:close_port(Port),
- ssl_test_lib:close(Pid);
-close(Client, Server) ->
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-supported_eccs(Opts) ->
- ToCheck = proplists:get_value(eccs, Opts, []),
- Supported = ssl:eccs(),
- lists:all(fun(Curve) -> lists:member(Curve, Supported) end, ToCheck).
-
-check_ecc(SSL, Role, Expect) ->
- {ok, Data} = ssl:connection_information(SSL),
- case lists:keyfind(ecc, 1, Data) of
- {ecc, {named_curve, Expect}} -> ok;
- false when Expect =:= undefined -> ok;
- Other -> {error, Role, Expect, Other}
- end.
+mix_sign(Config) ->
+ mix_sign_rsa_peer(Config),
+ mix_sign_ecdsa_peer(Config).
+
+mix_sign_ecdsa_peer(Config) ->
+ {COpts0, SOpts0} = ssl_test_lib:make_mix_cert([{mix, peer_ecc} |Config]),
+ COpts = ssl_test_lib:ssl_options(COpts0, Config),
+ SOpts = ssl_test_lib:ssl_options(SOpts0, Config),
+ ECDHE_ECDSA =
+ ssl:filter_cipher_suites(ssl:cipher_suites(default, 'tlsv1.2'),
+ [{key_exchange, fun(ecdhe_ecdsa) -> true; (_) -> false end}]),
+ ssl_test_lib:basic_test(COpts, [{ciphers, ECDHE_ECDSA} | SOpts], Config).
+
+mix_sign_rsa_peer(Config) ->
+ {COpts0, SOpts0} = ssl_test_lib:make_mix_cert([{mix, peer_rsa} |Config]),
+ COpts = ssl_test_lib:ssl_options(COpts0, Config),
+ SOpts = ssl_test_lib:ssl_options(SOpts0, Config),
+ ECDHE_RSA =
+ ssl:filter_cipher_suites(ssl:cipher_suites(default, 'tlsv1.2'),
+ [{key_exchange, fun(ecdhe_rsa) -> true; (_) -> false end}]),
+ ssl_test_lib:basic_test(COpts, [{ciphers, ECDHE_RSA} | SOpts], Config).
+
diff --git a/lib/ssl/test/ssl_ECC_openssl_SUITE.erl b/lib/ssl/test/ssl_ECC_openssl_SUITE.erl
new file mode 100644
index 0000000000..68d4e910fd
--- /dev/null
+++ b/lib/ssl/test/ssl_ECC_openssl_SUITE.erl
@@ -0,0 +1,132 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+-module(ssl_ECC_openssl_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+all() ->
+ case ssl_test_lib:openssl_sane_dtls() of
+ true ->
+ [{group, 'tlsv1.2'},
+ {group, 'dtlsv1.2'}];
+ false ->
+ [{group, 'tlsv1.2'}]
+ end.
+
+groups() ->
+ case ssl_test_lib:openssl_sane_dtls() of
+ true ->
+ [{'tlsv1.2', [], [mix_sign]},
+ {'dtlsv1.2', [], [mix_sign]}];
+ false ->
+ [{'tlsv1.2', [], [mix_sign]}]
+ end.
+
+%%--------------------------------------------------------------------
+init_per_suite(Config0) ->
+ end_per_suite(Config0),
+ try crypto:start() of
+ ok ->
+ case ssl_test_lib:sufficient_crypto_support(cipher_ec) of
+ true ->
+ Config0;
+ false ->
+ {skip, "Openssl does not support ECC"}
+ end
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ application:stop(ssl),
+ application:stop(crypto).
+
+%%--------------------------------------------------------------------
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:check_sane_openssl_version(GroupName) of
+ true ->
+ [{tls_version, GroupName},
+ {server_type, erlang},
+ {client_type, openssl} | ssl_test_lib:init_tls_version(GroupName, Config)];
+ false ->
+ {skip, openssl_does_not_support_version}
+ end;
+ _ ->
+ Config
+ end.
+
+end_per_group(GroupName, Config0) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ Config = ssl_test_lib:clean_tls_version(Config0),
+ proplists:delete(tls_version, Config);
+ false ->
+ Config0
+ end.
+
+%%--------------------------------------------------------------------
+init_per_testcase(skip, Config) ->
+ Config;
+init_per_testcase(TestCase, Config) ->
+ ssl_test_lib:ct_log_supported_protocol_versions(Config),
+ Version = proplists:get_value(tls_version, Config),
+ ct:log("Ciphers: ~p~n ", [ssl:cipher_suites(default, Version)]),
+ end_per_testcase(TestCase, Config),
+ ssl:start(),
+ ct:timetrap({seconds, 30}),
+ Config.
+
+end_per_testcase(_TestCase, Config) ->
+ application:stop(ssl),
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+skip(Config) when is_list(Config) ->
+ {skip, openssl_does_not_support_ECC}.
+
+mix_sign(Config) ->
+ {COpts0, SOpts0} = ssl_test_lib:make_mix_cert(Config),
+ COpts = ssl_test_lib:ssl_options(COpts0, Config),
+ SOpts = ssl_test_lib:ssl_options(SOpts0, Config),
+ ECDHE_ECDSA =
+ ssl:filter_cipher_suites(ssl:cipher_suites(default, 'tlsv1.2'),
+ [{key_exchange, fun(ecdhe_ecdsa) -> true; (_) -> false end}]),
+ ssl_test_lib:basic_test(COpts, [{ciphers, ECDHE_ECDSA} | SOpts], [{client_type, erlang},
+ {server_type, openssl} | Config]).
+
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
diff --git a/lib/ssl/test/ssl_alpn_handshake_SUITE.erl b/lib/ssl/test/ssl_alpn_handshake_SUITE.erl
index 055f05a900..dfc780479e 100644
--- a/lib/ssl/test/ssl_alpn_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_alpn_handshake_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -153,41 +153,41 @@ protocols_must_be_a_binary_list(Config) when is_list(Config) ->
empty_client(Config) when is_list(Config) ->
run_failing_handshake(Config,
- [{alpn_advertised_protocols, []}],
- [{alpn_preferred_protocols, [<<"spdy/2">>, <<"spdy/3">>, <<"http/2">>]}],
- {connect_failed,{tls_alert,"no application protocol"}}).
+ [{alpn_advertised_protocols, []}],
+ [{alpn_preferred_protocols, [<<"spdy/2">>, <<"spdy/3">>, <<"http/2">>]}],
+ no_application_protocol).
%--------------------------------------------------------------------------------
empty_server(Config) when is_list(Config) ->
run_failing_handshake(Config,
- [{alpn_advertised_protocols, [<<"http/1.0">>, <<"http/1.1">>]}],
- [{alpn_preferred_protocols, []}],
- {connect_failed,{tls_alert,"no application protocol"}}).
+ [{alpn_advertised_protocols, [<<"http/1.0">>, <<"http/1.1">>]}],
+ [{alpn_preferred_protocols, []}],
+ no_application_protocol).
%--------------------------------------------------------------------------------
empty_client_empty_server(Config) when is_list(Config) ->
run_failing_handshake(Config,
- [{alpn_advertised_protocols, []}],
- [{alpn_preferred_protocols, []}],
- {connect_failed,{tls_alert,"no application protocol"}}).
+ [{alpn_advertised_protocols, []}],
+ [{alpn_preferred_protocols, []}],
+ no_application_protocol).
%--------------------------------------------------------------------------------
no_matching_protocol(Config) when is_list(Config) ->
run_failing_handshake(Config,
- [{alpn_advertised_protocols, [<<"http/1.0">>, <<"http/1.1">>]}],
- [{alpn_preferred_protocols, [<<"spdy/2">>, <<"spdy/3">>, <<"http/2">>]}],
- {connect_failed,{tls_alert,"no application protocol"}}).
+ [{alpn_advertised_protocols, [<<"http/1.0">>, <<"http/1.1">>]}],
+ [{alpn_preferred_protocols, [<<"spdy/2">>, <<"spdy/3">>, <<"http/2">>]}],
+ no_application_protocol).
%--------------------------------------------------------------------------------
client_alpn_and_server_alpn(Config) when is_list(Config) ->
run_handshake(Config,
- [{alpn_advertised_protocols, [<<"http/1.0">>, <<"http/1.1">>]}],
- [{alpn_preferred_protocols, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}],
- {ok, <<"http/1.1">>}).
+ [{alpn_advertised_protocols, [<<"http/1.0">>, <<"http/1.1">>]}],
+ [{alpn_preferred_protocols, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}],
+ {ok, <<"http/1.1">>}).
%--------------------------------------------------------------------------------
@@ -262,52 +262,12 @@ client_renegotiate(Config) when is_list(Config) ->
%--------------------------------------------------------------------------------
session_reused(Config) when is_list(Config)->
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
ClientOpts = [{alpn_advertised_protocols, [<<"http/1.0">>]}] ++ ClientOpts0,
ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
ServerOpts = [{alpn_preferred_protocols, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}] ++ ServerOpts0,
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, session_info_result, []}},
- {options, ServerOpts}]),
-
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, no_result_msg, []}},
- {options, ClientOpts}]),
-
- SessionInfo =
- receive
- {Server, Info} ->
- Info
- end,
-
- Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
-
- %% Make sure session is registered
- ct:sleep(?SLEEP),
-
- Client1 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, session_info_result, []}},
- {from, self()}, {options, ClientOpts}]),
-
- receive
- {Client1, SessionInfo} ->
- ok;
- {Client1, Other} ->
- ct:fail(Other)
- end,
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client),
- ssl_test_lib:close(Client1).
-
+ ssl_test_lib:reuse_session(ClientOpts, ServerOpts, Config).
%--------------------------------------------------------------------------------
alpn_not_supported_client(Config) when is_list(Config) ->
@@ -337,23 +297,23 @@ alpn_not_supported_server(Config) when is_list(Config)->
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
-run_failing_handshake(Config, ClientExtraOpts, ServerExtraOpts, ExpectedResult) ->
+run_failing_handshake(Config, ClientExtraOpts, ServerExtraOpts, ExpectedAlert) ->
ClientOpts = ClientExtraOpts ++ ssl_test_lib:ssl_options(client_rsa_opts, Config),
ServerOpts = ServerExtraOpts ++ ssl_test_lib:ssl_options(server_rsa_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {?MODULE, placeholder, []}},
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
- ExpectedResult
- = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, placeholder, []}},
- {options, ClientOpts}]).
+ Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, placeholder, []}},
+ {options, ClientOpts}]),
+ ssl_test_lib:check_client_alert(Server, Client, ExpectedAlert).
run_handshake(Config, ClientExtraOpts, ServerExtraOpts, ExpectedProtocol) ->
Data = "hello world",
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index ce62017a7e..20d9f28512 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,6 +29,7 @@
-include_lib("public_key/include/public_key.hrl").
-include("ssl_api.hrl").
+-include("ssl_cipher.hrl").
-include("ssl_internal.hrl").
-include("ssl_alert.hrl").
-include("ssl_internal.hrl").
@@ -53,7 +54,8 @@ all() ->
{group, options_tls},
{group, session},
{group, 'dtlsv1.2'},
- {group, 'dtlsv1'},
+ {group, 'dtlsv1'},
+ {group, 'tlsv1.3'},
{group, 'tlsv1.2'},
{group, 'tlsv1.1'},
{group, 'tlsv1'},
@@ -67,17 +69,16 @@ groups() ->
{options_tls, [], options_tests_tls()},
{'dtlsv1.2', [], all_versions_groups()},
{'dtlsv1', [], all_versions_groups()},
+ {'tlsv1.3', [], tls13_test_group()},
{'tlsv1.2', [], all_versions_groups() ++ tls_versions_groups() ++ [conf_signature_algs, no_common_signature_algs]},
{'tlsv1.1', [], all_versions_groups() ++ tls_versions_groups()},
{'tlsv1', [], all_versions_groups() ++ tls_versions_groups() ++ rizzo_tests()},
{'sslv3', [], all_versions_groups() ++ tls_versions_groups() ++ rizzo_tests() ++ [tls_ciphersuite_vs_version]},
{api,[], api_tests()},
{api_tls,[], api_tests_tls()},
- {tls_ciphers,[], tls_cipher_tests()},
{session, [], session_tests()},
{renegotiate, [], renegotiate_tests()},
{ciphers, [], cipher_tests()},
- {ciphers_ec, [], cipher_tests_ec()},
{error_handling_tests, [], error_handling_tests()},
{error_handling_tests_tls, [], error_handling_tests_tls()}
].
@@ -85,14 +86,12 @@ groups() ->
tls_versions_groups ()->
[
{group, api_tls},
- {group, tls_ciphers},
{group, error_handling_tests_tls}].
all_versions_groups ()->
[{group, api},
{group, renegotiate},
{group, ciphers},
- {group, ciphers_ec},
{group, error_handling_tests}].
@@ -108,7 +107,8 @@ basic_tests() ->
clear_pem_cache,
defaults,
fallback,
- cipher_format
+ cipher_format,
+ suite_to_str
].
basic_tests_tls() ->
@@ -146,8 +146,7 @@ options_tests_tls() ->
tls_tcp_reuseaddr].
api_tests() ->
- [connection_info,
- secret_connection_info,
+ [secret_connection_info,
connection_information,
peercert,
peercert_with_client_cert,
@@ -164,7 +163,12 @@ api_tests() ->
accept_pool,
prf,
socket_options,
- cipher_suites
+ active_n,
+ cipher_suites,
+ handshake_continue,
+ handshake_continue_timeout,
+ hello_client_cancel,
+ hello_server_cancel
].
api_tests_tls() ->
@@ -194,6 +198,7 @@ renegotiate_tests() ->
[client_renegotiate,
server_renegotiate,
client_secure_renegotiate,
+ client_secure_renegotiate_fallback,
client_renegotiate_reused_session,
server_renegotiate_reused_session,
client_no_wrap_sequence_number,
@@ -202,41 +207,21 @@ renegotiate_tests() ->
renegotiate_dos_mitigate_passive,
renegotiate_dos_mitigate_absolute].
-tls_cipher_tests() ->
- [rc4_rsa_cipher_suites,
- rc4_ecdh_rsa_cipher_suites,
- rc4_ecdsa_cipher_suites].
-
cipher_tests() ->
[old_cipher_suites,
- cipher_suites_mix,
- ciphers_rsa_signed_certs,
- ciphers_rsa_signed_certs_openssl_names,
- ciphers_dsa_signed_certs,
- ciphers_dsa_signed_certs_openssl_names,
- anonymous_cipher_suites,
- psk_cipher_suites,
- psk_with_hint_cipher_suites,
- psk_anon_cipher_suites,
- psk_anon_with_hint_cipher_suites,
- srp_cipher_suites,
- srp_anon_cipher_suites,
- srp_dsa_cipher_suites,
- des_rsa_cipher_suites,
- des_ecdh_rsa_cipher_suites,
+ cipher_suites_mix,
default_reject_anonymous].
-cipher_tests_ec() ->
- [ciphers_ecdsa_signed_certs,
- ciphers_ecdsa_signed_certs_openssl_names,
- ciphers_ecdh_rsa_signed_certs,
- ciphers_ecdh_rsa_signed_certs_openssl_names].
-
error_handling_tests()->
[close_transport_accept,
recv_active,
recv_active_once,
- recv_error_handling
+ recv_active_n,
+ recv_error_handling,
+ call_in_error_state,
+ close_in_error_state,
+ abuse_transport_accept_socket,
+ controlling_process_transport_accept_socket
].
error_handling_tests_tls()->
@@ -256,6 +241,26 @@ rizzo_tests() ->
rizzo_zero_n,
rizzo_disabled].
+%% For testing TLS 1.3 features and possible regressions
+tls13_test_group() ->
+ [tls13_enable_client_side,
+ tls13_enable_server_side,
+ tls_record_1_3_encode_decode,
+ tls13_finished_verify_data,
+ tls13_1_RTT_handshake,
+ tls13_basic_ssl_server_openssl_client,
+ tls13_custom_groups_ssl_server_openssl_client,
+ tls13_hello_retry_request_ssl_server_openssl_client,
+ tls13_client_auth_empty_cert_alert_ssl_server_openssl_client,
+ tls13_client_auth_empty_cert_ssl_server_openssl_client,
+ tls13_client_auth_ssl_server_openssl_client,
+ tls13_hrr_client_auth_empty_cert_alert_ssl_server_openssl_client,
+ tls13_hrr_client_auth_empty_cert_ssl_server_openssl_client,
+ tls13_hrr_client_auth_ssl_server_openssl_client,
+ tls13_unsupported_sign_algo_client_auth_ssl_server_openssl_client,
+ tls13_unsupported_sign_algo_cert_client_auth_ssl_server_openssl_client,
+ tls13_connection_information].
+
%%--------------------------------------------------------------------
init_per_suite(Config0) ->
catch crypto:stop(),
@@ -267,7 +272,8 @@ init_per_suite(Config0) ->
proplists:get_value(priv_dir, Config0)),
Config1 = ssl_test_lib:make_dsa_cert(Config0),
Config2 = ssl_test_lib:make_ecdsa_cert(Config1),
- Config = ssl_test_lib:make_ecdh_rsa_cert(Config2),
+ Config3 = ssl_test_lib:make_rsa_cert(Config2),
+ Config = ssl_test_lib:make_ecdh_rsa_cert(Config3),
ssl_test_lib:cert_options(Config)
catch _:_ ->
{skip, "Crypto did not start"}
@@ -284,10 +290,12 @@ init_per_group(GroupName, Config) when GroupName == basic_tls;
GroupName == options;
GroupName == basic;
GroupName == session;
- GroupName == error_handling_tests_tls
+ GroupName == error_handling_tests_tls;
+ GroupName == tls13_test_group
->
ssl_test_lib:clean_tls_version(Config);
init_per_group(GroupName, Config) ->
+ ssl_test_lib:clean_tls_version(Config),
case ssl_test_lib:is_tls_version(GroupName) andalso ssl_test_lib:sufficient_crypto_support(GroupName) of
true ->
ssl_test_lib:init_tls_version(GroupName, Config);
@@ -371,26 +379,7 @@ init_per_testcase(TestCase, Config) when TestCase == client_renegotiate;
ct:timetrap({seconds, ?SEC_RENEGOTIATION_TIMEOUT + 5}),
Config;
-init_per_testcase(TestCase, Config) when TestCase == psk_cipher_suites;
- TestCase == psk_with_hint_cipher_suites;
- TestCase == ciphers_rsa_signed_certs;
- TestCase == ciphers_rsa_signed_certs_openssl_names;
- TestCase == ciphers_ecdh_rsa_signed_certs_openssl_names;
- TestCase == ciphers_ecdh_rsa_signed_certs;
- TestCase == ciphers_dsa_signed_certs;
- TestCase == ciphers_dsa_signed_certs_openssl_names;
- TestCase == anonymous_cipher_suites;
- TestCase == ciphers_ecdsa_signed_certs;
- TestCase == ciphers_ecdsa_signed_certs_openssl_names;
- TestCase == anonymous_cipher_suites;
- TestCase == psk_anon_cipher_suites;
- TestCase == psk_anon_with_hint_cipher_suites;
- TestCase == srp_cipher_suites;
- TestCase == srp_anon_cipher_suites;
- TestCase == srp_dsa_cipher_suites;
- TestCase == des_rsa_cipher_suites;
- TestCase == des_ecdh_rsa_cipher_suites;
- TestCase == versions_option;
+init_per_testcase(TestCase, Config) when TestCase == versions_option;
TestCase == tls_tcp_connect_big ->
ssl_test_lib:ct_log_supported_protocol_versions(Config),
ct:timetrap({seconds, 60}),
@@ -467,6 +456,8 @@ init_per_testcase(TestCase, Config) when TestCase == tls_ssl_accept_timeout;
TestCase == tls_client_closes_socket;
TestCase == tls_closed_in_active_once;
TestCase == tls_downgrade ->
+ ssl:stop(),
+ ssl:start(),
ssl_test_lib:ct_log_supported_protocol_versions(Config),
ct:timetrap({seconds, 15}),
Config;
@@ -558,11 +549,10 @@ alerts(Config) when is_list(Config) ->
Alerts = [?ALERT_REC(?WARNING, ?CLOSE_NOTIFY) |
[?ALERT_REC(?FATAL, Desc) || Desc <- Descriptions]],
lists:foreach(fun(Alert) ->
- case ssl_alert:alert_txt(Alert) of
- Txt when is_list(Txt) ->
- ok;
- Other ->
- ct:fail({unexpected, Other})
+ try ssl_alert:alert_txt(Alert)
+ catch
+ C:E:T ->
+ ct:fail({unexpected, {C, E, T}})
end
end, Alerts).
%%--------------------------------------------------------------------
@@ -601,7 +591,16 @@ new_options_in_accept(Config) when is_list(Config) ->
[_ , _ | ServerSslOpts] = ssl_test_lib:ssl_options(server_opts, Config), %% Remove non ssl opts
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Version = ssl_test_lib:protocol_options(Config, [{tls, sslv3}, {dtls, dtlsv1}]),
- Cipher = ssl_test_lib:protocol_options(Config, [{tls, {rsa,rc4_128,sha}}, {dtls, {rsa,aes_128_cbc,sha}}]),
+ Cipher = ssl_test_lib:protocol_options(Config, [{tls, #{key_exchange =>rsa,
+ cipher => rc4_128,
+ mac => sha,
+ prf => default_prf
+ }},
+ {dtls, #{key_exchange =>rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf
+ }}]),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
{ssl_extra_opts, [{versions, [Version]},
@@ -626,6 +625,110 @@ new_options_in_accept(Config) when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+handshake_continue() ->
+ [{doc, "Test API function ssl:handshake_continue/3"}].
+handshake_continue(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ssl_test_lib:ssl_options([{reuseaddr, true}, {handshake, hello}],
+ Config)},
+ {continue_options, proplists:delete(reuseaddr, ServerOpts)}
+ ]),
+
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ssl_test_lib:ssl_options([{handshake, hello}],
+ Config)},
+ {continue_options, proplists:delete(reuseaddr, ClientOpts)}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%------------------------------------------------------------------
+handshake_continue_timeout() ->
+ [{doc, "Test API function ssl:handshake_continue/3 with short timeout"}].
+handshake_continue_timeout(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {timeout, 1},
+ {options, ssl_test_lib:ssl_options([{reuseaddr, true}, {handshake, hello}],
+ Config)},
+ {continue_options, proplists:delete(reuseaddr, ServerOpts)}
+ ]),
+
+ Port = ssl_test_lib:inet_port(Server),
+
+
+ {connect_failed, _} = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Server, {error,timeout}),
+ ssl_test_lib:close(Server).
+
+
+%%--------------------------------------------------------------------
+hello_client_cancel() ->
+ [{doc, "Test API function ssl:handshake_cancel/1 on the client side"}].
+hello_client_cancel(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, ssl_test_lib:ssl_options([{handshake, hello}], Config)},
+ {continue_options, proplists:delete(reuseaddr, ServerOpts)}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+
+ %% That is ssl:handshake_cancel returns ok
+ {connect_failed, ok} = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {options, ssl_test_lib:ssl_options([{handshake, hello}], Config)},
+ {continue_options, cancel}]),
+ ssl_test_lib:check_server_alert(Server, user_canceled).
+%%--------------------------------------------------------------------
+hello_server_cancel() ->
+ [{doc, "Test API function ssl:handshake_cancel/1 on the server side"}].
+hello_server_cancel(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, ssl_test_lib:ssl_options([{handshake, hello}], Config)},
+ {continue_options, cancel}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+
+ {connect_failed, _} = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {options, ssl_test_lib:ssl_options([{handshake, hello}], Config)},
+ {continue_options, proplists:delete(reuseaddr, ClientOpts)}]),
+
+ ssl_test_lib:check_result(Server, ok).
+
%%--------------------------------------------------------------------
prf() ->
[{doc,"Test that ssl:prf/5 uses the negotiated PRF."}].
@@ -647,46 +750,11 @@ prf(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-connection_info() ->
- [{doc,"Test the API function ssl:connection_information/2"}].
-connection_info(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, connection_info_result, []}},
- {options, ServerOpts}]),
-
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, connection_info_result, []}},
- {options,
- [{ciphers,[{rsa, aes_128_cbc, sha}]} |
- ClientOpts]}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- Version = ssl_test_lib:protocol_version(Config),
-
- ServerMsg = ClientMsg = {ok, {Version, {rsa, aes_128_cbc, sha}}},
-
- ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-
secret_connection_info() ->
[{doc,"Test the API function ssl:connection_information/2"}].
secret_connection_info(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
@@ -767,42 +835,30 @@ controlling_process(Config) when is_list(Config) ->
ClientMsg = "Server hello",
ServerMsg = "Client hello",
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE,
- controlling_process_result, [self(),
- ServerMsg]}},
- {options, ServerOpts}]),
+ Server = ssl_test_lib:start_server([
+ {node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE,
+ controlling_process_result, [self(),
+ ServerMsg]}},
+ {options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
+ {Client, CSocket} = ssl_test_lib:start_client([return_socket,
+ {node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
{mfa, {?MODULE,
controlling_process_result, [self(),
ClientMsg]}},
{options, ClientOpts}]),
-
+
ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
+ [self(), Client, Server]),
- receive
- {ssl, _, "S"} ->
- receive_s_rizzo_duong_beast();
- {ssl, _, ServerMsg} ->
- receive
- {ssl, _, ClientMsg} ->
- ok
- end;
- {ssl, _, "C"} ->
- receive_c_rizzo_duong_beast();
- {ssl, _, ClientMsg} ->
- receive
- {ssl, _, ServerMsg} ->
- ok
- end;
- Unexpected ->
- ct:fail(Unexpected)
- end,
+ ServerMsg = ssl_test_lib:active_recv(CSocket, length(ServerMsg)),
+ %% We do not have the TLS server socket but all messages form the client
+ %% socket are now read, so ramining are form the server socket
+ ClientMsg = ssl_active_recv(length(ClientMsg)),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
@@ -959,7 +1015,7 @@ controller_dies(Config) when is_list(Config) ->
{mfa, {?MODULE,
controller_dies_result, [self(),
ClientMsg]}},
- {options, [{reuseaddr,true}|ClientOpts]}]),
+ {options, ClientOpts}]),
ct:sleep(?SLEEP), %% so that they are connected
exit(Server, killed),
@@ -984,7 +1040,7 @@ tls_client_closes_socket(Config) when is_list(Config) ->
Connect = fun() ->
{ok, _Socket} = rpc:call(ClientNode, gen_tcp, connect,
- [Hostname, Port, TcpOpts]),
+ [Hostname, Port, [binary]]),
%% Make sure that ssl_accept is called before
%% client process ends and closes socket.
ct:sleep(?SLEEP)
@@ -1026,16 +1082,19 @@ tls_closed_in_active_once(Config) when is_list(Config) ->
end.
tls_closed_in_active_once_loop(Socket) ->
- ssl:setopts(Socket, [{active, once}]),
- receive
- {ssl, Socket, _} ->
- tls_closed_in_active_once_loop(Socket);
- {ssl_closed, Socket} ->
- ok
- after 5000 ->
- no_ssl_closed_received
+ case ssl:setopts(Socket, [{active, once}]) of
+ ok ->
+ receive
+ {ssl, Socket, _} ->
+ tls_closed_in_active_once_loop(Socket);
+ {ssl_closed, Socket} ->
+ ok
+ after 5000 ->
+ no_ssl_closed_received
+ end;
+ {error, closed} ->
+ ok
end.
-
%%--------------------------------------------------------------------
connect_dist() ->
[{doc,"Test a simple connect as is used by distribution"}].
@@ -1114,16 +1173,15 @@ fallback(Config) when is_list(Config) ->
Port = ssl_test_lib:inet_port(Server),
- Client =
- ssl_test_lib:start_client_error([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {from, self()}, {options,
- [{fallback, true},
- {versions, ['tlsv1']}
- | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, {error,{tls_alert,"inappropriate fallback"}},
- Client, {error,{tls_alert,"inappropriate fallback"}}).
+ Client =
+ ssl_test_lib:start_client_error([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {from, self()}, {options,
+ [{fallback, true},
+ {versions, ['tlsv1']}
+ | ClientOpts]}]),
+ ssl_test_lib:check_server_alert(Server, Client, inappropriate_fallback).
+
%%--------------------------------------------------------------------
cipher_format() ->
@@ -1136,7 +1194,27 @@ cipher_format(Config) when is_list(Config) ->
ssl:close(Socket1),
{ok, Socket2} = ssl:listen(0, [{ciphers, ssl:cipher_suites(openssl)}]),
ssl:close(Socket2).
-
+
+%%--------------------------------------------------------------------
+suite_to_str() ->
+ [{doc, "Test that the suite_to_str API works"}].
+suite_to_str(Config) when is_list(Config) ->
+ "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" =
+ ssl:suite_to_str(#{key_exchange => null,
+ cipher => null,
+ mac => null,
+ prf => null}),
+ "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" =
+ ssl:suite_to_str(#{key_exchange => ecdhe_ecdsa,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256}),
+ "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256" =
+ ssl:suite_to_str(#{key_exchange => ecdh_rsa,
+ cipher => aes_128_cbc,
+ mac => sha256,
+ prf => sha256}).
+
%%--------------------------------------------------------------------
peername() ->
@@ -1293,6 +1371,14 @@ cipher_suites() ->
" and prepend|append_cipher_suites/2"}].
cipher_suites(Config) when is_list(Config) ->
+ MandatoryCipherSuiteTLS1_0TLS1_1 = #{key_exchange => rsa,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf},
+ MandatoryCipherSuiteTLS1_0TLS1_2 = #{key_exchange =>rsa,
+ cipher => 'aes_128_cbc',
+ mac => sha,
+ prf => default_prf},
Version = ssl_test_lib:protocol_version(Config),
All = [_|_] = ssl:cipher_suites(all, Version),
Default = [_|_] = ssl:cipher_suites(default, Version),
@@ -1334,8 +1420,9 @@ cipher_suites(Config) when is_list(Config) ->
true = lists:member(Cipher, Default),
false = lists:member(Cipher, Rest1),
[] = lists:dropwhile(fun(X) -> not lists:member(X, Default) end, Anonymous),
- [] = lists:dropwhile(fun(X) -> not lists:member(X, All) end, Anonymous).
-
+ [] = lists:dropwhile(fun(X) -> not lists:member(X, All) end, Anonymous),
+ true = lists:member(MandatoryCipherSuiteTLS1_0TLS1_1, All),
+ true = lists:member(MandatoryCipherSuiteTLS1_0TLS1_2, All).
%%--------------------------------------------------------------------
@@ -1343,20 +1430,20 @@ old_cipher_suites() ->
[{doc,"Test API function cipher_suites/0"}].
old_cipher_suites(Config) when is_list(Config) ->
- MandatoryCipherSuite = {rsa,'3des_ede_cbc',sha},
+ MandatoryCipherSuite = {rsa, '3des_ede_cbc', sha},
[_|_] = Suites = ssl:cipher_suites(),
- true = lists:member(MandatoryCipherSuite, Suites),
Suites = ssl:cipher_suites(erlang),
- [_|_] =ssl:cipher_suites(openssl).
+ [_|_] = ssl:cipher_suites(openssl),
+ true = lists:member(MandatoryCipherSuite, ssl:cipher_suites(all)).
%%--------------------------------------------------------------------
cipher_suites_mix() ->
[{doc,"Test to have old and new cipher suites at the same time"}].
cipher_suites_mix(Config) when is_list(Config) ->
- CipherSuites = [{ecdh_rsa,aes_128_cbc,sha256,sha256}, {rsa,aes_128_cbc,sha}],
- ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
+ CipherSuites = [{dhe_rsa,aes_128_cbc,sha256,sha256}, {dhe_rsa,aes_128_cbc,sha}],
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -1745,14 +1832,12 @@ eccs() ->
eccs(Config) when is_list(Config) ->
[_|_] = All = ssl:eccs(),
- [] = SSL3 = ssl:eccs({3,0}),
- [_|_] = Tls = ssl:eccs({3,1}),
- [_|_] = Tls1 = ssl:eccs({3,2}),
- [_|_] = Tls2 = ssl:eccs({3,3}),
[] = SSL3 = ssl:eccs(sslv3),
[_|_] = Tls = ssl:eccs(tlsv1),
[_|_] = Tls1 = ssl:eccs('tlsv1.1'),
[_|_] = Tls2 = ssl:eccs('tlsv1.2'),
+ [_|_] = Tls1 = ssl:eccs('dtlsv1'),
+ [_|_] = Tls2 = ssl:eccs('dtlsv1.2'),
%% ordering is currently unverified by the test
true = lists:sort(All) =:= lists:usort(SSL3 ++ Tls ++ Tls1 ++ Tls2),
ok.
@@ -1799,7 +1884,7 @@ tls_send_close(Config) when is_list(Config) ->
{options, [{active, false} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
{ok, TcpS} = rpc:call(ClientNode, gen_tcp, connect,
- [Hostname,Port,[binary, {active, false}, {reuseaddr, true}]]),
+ [Hostname,Port,[binary, {active, false}]]),
{ok, SslS} = rpc:call(ClientNode, ssl, connect,
[TcpS,[{active, false}|ClientOpts]]),
@@ -1866,7 +1951,7 @@ recv_active(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
recv_active_once() ->
- [{doc,"Test recv on active socket"}].
+ [{doc,"Test recv on active (once) socket"}].
recv_active_once(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
@@ -1891,6 +1976,178 @@ recv_active_once(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
+recv_active_n() ->
+ [{doc,"Test recv on active (n) socket"}].
+
+recv_active_n(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, try_recv_active_once, []}},
+ {options, [{active, 1} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client =
+ ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, try_recv_active_once, []}},
+ {options, [{active, 1} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+%% Test case adapted from gen_tcp_misc_SUITE.
+active_n() ->
+ [{doc,"Test {active,N} option"}].
+
+active_n(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ Port = ssl_test_lib:inet_port(node()),
+ N = 3,
+ LS = ok(ssl:listen(Port, [{active,N}|ServerOpts])),
+ [{active,N}] = ok(ssl:getopts(LS, [active])),
+ active_n_common(LS, N),
+ Self = self(),
+ spawn_link(fun() ->
+ S0 = ok(ssl:transport_accept(LS)),
+ {ok, S} = ssl:handshake(S0),
+ ok = ssl:setopts(S, [{active,N}]),
+ [{active,N}] = ok(ssl:getopts(S, [active])),
+ ssl:controlling_process(S, Self),
+ Self ! {server, S}
+ end),
+ C = ok(ssl:connect("localhost", Port, [{active,N}|ClientOpts])),
+ [{active,N}] = ok(ssl:getopts(C, [active])),
+ S = receive
+ {server, S0} -> S0
+ after
+ 1000 ->
+ exit({error, connect})
+ end,
+ active_n_common(C, N),
+ active_n_common(S, N),
+ ok = ssl:setopts(C, [{active,N}]),
+ ok = ssl:setopts(S, [{active,N}]),
+ ReceiveMsg = fun(Socket, Msg) ->
+ receive
+ {ssl,Socket,Msg} ->
+ ok;
+ {ssl,Socket,Begin} ->
+ receive
+ {ssl,Socket,End} ->
+ Msg = Begin ++ End,
+ ok
+ after 1000 ->
+ exit(timeout)
+ end
+ after 1000 ->
+ exit(timeout)
+ end
+ end,
+ repeat(3, fun(I) ->
+ Msg = "message "++integer_to_list(I),
+ ok = ssl:send(C, Msg),
+ ReceiveMsg(S, Msg),
+ ok = ssl:send(S, Msg),
+ ReceiveMsg(C, Msg)
+ end),
+ receive
+ {ssl_passive,S} ->
+ [{active,false}] = ok(ssl:getopts(S, [active]))
+ after
+ 1000 ->
+ exit({error,ssl_passive})
+ end,
+ receive
+ {ssl_passive,C} ->
+ [{active,false}] = ok(ssl:getopts(C, [active]))
+ after
+ 1000 ->
+ exit({error,ssl_passive})
+ end,
+ LS2 = ok(ssl:listen(0, [{active,0}])),
+ receive
+ {ssl_passive,LS2} ->
+ [{active,false}] = ok(ssl:getopts(LS2, [active]))
+ after
+ 1000 ->
+ exit({error,ssl_passive})
+ end,
+ ok = ssl:close(LS2),
+ ok = ssl:close(C),
+ ok = ssl:close(S),
+ ok = ssl:close(LS),
+ ok.
+
+active_n_common(S, N) ->
+ ok = ssl:setopts(S, [{active,-N}]),
+ receive
+ {ssl_passive, S} -> ok
+ after
+ 1000 ->
+ error({error,ssl_passive_failure})
+ end,
+ [{active,false}] = ok(ssl:getopts(S, [active])),
+ ok = ssl:setopts(S, [{active,0}]),
+ receive
+ {ssl_passive, S} -> ok
+ after
+ 1000 ->
+ error({error,ssl_passive_failure})
+ end,
+ ok = ssl:setopts(S, [{active,32767}]),
+ {error,{options,_}} = ssl:setopts(S, [{active,1}]),
+ {error,{options,_}} = ssl:setopts(S, [{active,-32769}]),
+ ok = ssl:setopts(S, [{active,-32768}]),
+ receive
+ {ssl_passive, S} -> ok
+ after
+ 1000 ->
+ error({error,ssl_passive_failure})
+ end,
+ [{active,false}] = ok(ssl:getopts(S, [active])),
+ ok = ssl:setopts(S, [{active,N}]),
+ ok = ssl:setopts(S, [{active,true}]),
+ [{active,true}] = ok(ssl:getopts(S, [active])),
+ receive
+ _ -> error({error,active_n})
+ after
+ 0 ->
+ ok
+ end,
+ ok = ssl:setopts(S, [{active,N}]),
+ ok = ssl:setopts(S, [{active,once}]),
+ [{active,once}] = ok(ssl:getopts(S, [active])),
+ receive
+ _ -> error({error,active_n})
+ after
+ 0 ->
+ ok
+ end,
+ {error,{options,_}} = ssl:setopts(S, [{active,32768}]),
+ ok = ssl:setopts(S, [{active,false}]),
+ [{active,false}] = ok(ssl:getopts(S, [active])),
+ ok.
+
+ok({ok,V}) -> V.
+
+repeat(N, Fun) ->
+ repeat(N, N, Fun).
+
+repeat(N, T, Fun) when is_integer(N), N > 0 ->
+ Fun(T-N),
+ repeat(N-1, T, Fun);
+repeat(_, _, _) ->
+ ok.
+
+%%--------------------------------------------------------------------
dh_params() ->
[{doc,"Test to specify DH-params file in server."}].
@@ -1943,7 +2200,7 @@ tls_upgrade(Config) when is_list(Config) ->
{host, Hostname},
{from, self()},
{mfa, {?MODULE, upgrade_result, []}},
- {tcp_options, TcpOpts},
+ {tcp_options, [binary]},
{ssl_options, ClientOpts}]),
ct:log("Testcase ~p, Client ~p Server ~p ~n",
@@ -2015,15 +2272,21 @@ tls_downgrade(Config) when is_list(Config) ->
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
- {mfa, {?MODULE, tls_downgrade_result, []}},
+ {mfa, {?MODULE, tls_downgrade_result, [self()]}},
{options, [{active, false} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
- {mfa, {?MODULE, tls_downgrade_result, []}},
+ {mfa, {?MODULE, tls_downgrade_result, [self()]}},
{options, [{active, false} |ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ready, Client, ready),
+
+ Server ! go,
+ Client ! go,
+
ssl_test_lib:check_result(Server, ok, Client, ok),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
@@ -2261,8 +2524,8 @@ invalid_options() ->
[{doc,"Test what happens when we give invalid options"}].
invalid_options(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Check = fun(Client, Server, {versions, [sslv2, sslv3]} = Option) ->
@@ -2277,27 +2540,28 @@ invalid_options(Config) when is_list(Config) ->
{error, {options, Option}})
end,
- TestOpts = [{versions, [sslv2, sslv3]},
- {verify, 4},
- {verify_fun, function},
- {fail_if_no_peer_cert, 0},
- {verify_client_once, 1},
- {depth, four},
- {certfile, 'cert.pem'},
- {keyfile,'key.pem' },
- {password, foo},
- {cacertfile, ""},
- {dhfile,'dh.pem' },
- {ciphers, [{foo, bar, sha, ignore}]},
- {reuse_session, foo},
- {reuse_sessions, 0},
- {renegotiate_at, "10"},
- {mode, depech},
- {packet, 8.0},
- {packet_size, "2"},
- {header, a},
- {active, trice},
- {key, 'key.pem' }],
+ TestOpts =
+ [{versions, [sslv2, sslv3]},
+ {verify, 4},
+ {verify_fun, function},
+ {fail_if_no_peer_cert, 0},
+ {verify_client_once, 1},
+ {depth, four},
+ {certfile, 'cert.pem'},
+ {keyfile,'key.pem' },
+ {password, foo},
+ {cacertfile, ""},
+ {dhfile,'dh.pem' },
+ {ciphers, [{foo, bar, sha, ignore}]},
+ {reuse_session, foo},
+ {reuse_sessions, 0},
+ {renegotiate_at, "10"},
+ {mode, depech},
+ {packet, 8.0},
+ {packet_size, "2"},
+ {header, a},
+ {active, trice},
+ {key, 'key.pem' }],
[begin
Server =
@@ -2392,126 +2656,6 @@ tls_shutdown_error(Config) when is_list(Config) ->
ok = ssl:close(Listen),
{error, closed} = ssl:shutdown(Listen, read_write).
-%%-------------------------------------------------------------------
-ciphers_rsa_signed_certs() ->
- [{doc,"Test all rsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_rsa_signed_certs(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:rsa_suites(crypto),
- run_suites(Ciphers, Config, rsa).
-%%-------------------------------------------------------------------
-ciphers_rsa_signed_certs_openssl_names() ->
- [{doc,"Test all rsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_rsa_signed_certs_openssl_names(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:openssl_rsa_suites(),
- run_suites(Ciphers, Config, rsa).
-
-%%-------------------------------------------------------------------
-ciphers_dsa_signed_certs() ->
- [{doc,"Test all dsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_dsa_signed_certs(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:dsa_suites(NVersion),
- run_suites(Ciphers, Config, dsa).
-%%-------------------------------------------------------------------
-ciphers_dsa_signed_certs_openssl_names() ->
- [{doc,"Test all dsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_dsa_signed_certs_openssl_names(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:openssl_dsa_suites(),
- run_suites(Ciphers, Config, dsa).
-%%-------------------------------------------------------------------
-anonymous_cipher_suites()->
- [{doc,"Test the anonymous ciphersuites"}].
-anonymous_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:anonymous_suites(NVersion),
- run_suites(Ciphers, Config, anonymous).
-%%-------------------------------------------------------------------
-psk_cipher_suites() ->
- [{doc, "Test the PSK ciphersuites WITHOUT server supplied identity hint"}].
-psk_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:psk_suites(NVersion),
- run_suites(Ciphers, Config, psk).
-%%-------------------------------------------------------------------
-psk_with_hint_cipher_suites()->
- [{doc, "Test the PSK ciphersuites WITH server supplied identity hint"}].
-psk_with_hint_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:psk_suites(NVersion),
- run_suites(Ciphers, Config, psk_with_hint).
-%%-------------------------------------------------------------------
-psk_anon_cipher_suites() ->
- [{doc, "Test the anonymous PSK ciphersuites WITHOUT server supplied identity hint"}].
-psk_anon_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:psk_anon_suites(NVersion),
- run_suites(Ciphers, Config, psk_anon).
-%%-------------------------------------------------------------------
-psk_anon_with_hint_cipher_suites()->
- [{doc, "Test the anonymous PSK ciphersuites WITH server supplied identity hint"}].
-psk_anon_with_hint_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:psk_anon_suites(NVersion),
- run_suites(Ciphers, Config, psk_anon_with_hint).
-%%-------------------------------------------------------------------
-srp_cipher_suites()->
- [{doc, "Test the SRP ciphersuites"}].
-srp_cipher_suites(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:srp_suites(),
- run_suites(Ciphers, Config, srp).
-%%-------------------------------------------------------------------
-srp_anon_cipher_suites()->
- [{doc, "Test the anonymous SRP ciphersuites"}].
-srp_anon_cipher_suites(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:srp_anon_suites(),
- run_suites(Ciphers, Config, srp_anon).
-%%-------------------------------------------------------------------
-srp_dsa_cipher_suites()->
- [{doc, "Test the SRP DSA ciphersuites"}].
-srp_dsa_cipher_suites(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:srp_dss_suites(),
- run_suites(Ciphers, Config, srp_dsa).
-%%-------------------------------------------------------------------
-rc4_rsa_cipher_suites()->
- [{doc, "Test the RC4 ciphersuites"}].
-rc4_rsa_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = [S || {rsa,_,_} = S <- ssl_test_lib:rc4_suites(NVersion)],
- run_suites(Ciphers, Config, rc4_rsa).
-%-------------------------------------------------------------------
-rc4_ecdh_rsa_cipher_suites()->
- [{doc, "Test the RC4 ciphersuites"}].
-rc4_ecdh_rsa_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = [S || {ecdh_rsa,_,_} = S <- ssl_test_lib:rc4_suites(NVersion)],
- run_suites(Ciphers, Config, rc4_ecdh_rsa).
-
-%%-------------------------------------------------------------------
-rc4_ecdsa_cipher_suites()->
- [{doc, "Test the RC4 ciphersuites"}].
-rc4_ecdsa_cipher_suites(Config) when is_list(Config) ->
- NVersion = tls_record:highest_protocol_version([]),
- Ciphers = [S || {ecdhe_ecdsa,_,_} = S <- ssl_test_lib:rc4_suites(NVersion)],
- run_suites(Ciphers, Config, rc4_ecdsa).
-
-%%-------------------------------------------------------------------
-des_rsa_cipher_suites()->
- [{doc, "Test the des_rsa ciphersuites"}].
-des_rsa_cipher_suites(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:des_suites(Config),
- run_suites(Ciphers, Config, des_rsa).
-%-------------------------------------------------------------------
-des_ecdh_rsa_cipher_suites()->
- [{doc, "Test ECDH rsa signed ciphersuites"}].
-des_ecdh_rsa_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:des_suites(NVersion),
- run_suites(Ciphers, Config, des_dhe_rsa).
-
%%--------------------------------------------------------------------
default_reject_anonymous()->
[{doc,"Test that by default anonymous cipher suites are rejected "}].
@@ -2522,225 +2666,88 @@ default_reject_anonymous(Config) when is_list(Config) ->
Version = ssl_test_lib:protocol_version(Config),
TLSVersion = ssl_test_lib:tls_version(Version),
- [CipherSuite | _] = ssl_test_lib:anonymous_suites(TLSVersion),
+ [CipherSuite | _] = ssl_test_lib:ecdh_dh_anonymous_suites(TLSVersion),
Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
{from, self()},
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {options,
- [{ciphers,[CipherSuite]} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, {error, {tls_alert, "insufficient security"}},
- Client, {error, {tls_alert, "insufficient security"}}).
-
-%%--------------------------------------------------------------------
-ciphers_ecdsa_signed_certs() ->
- [{doc, "Test all ecdsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_ecdsa_signed_certs(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:ecdsa_suites(NVersion),
- run_suites(Ciphers, Config, ecdsa).
-%%--------------------------------------------------------------------
-ciphers_ecdsa_signed_certs_openssl_names() ->
- [{doc, "Test all ecdsa ssl cipher suites in highest support ssl/tls version"}].
+ {host, Hostname},
+ {from, self()},
+ {options,
+ [{ciphers,[CipherSuite]} |
+ ClientOpts]}]),
-ciphers_ecdsa_signed_certs_openssl_names(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:openssl_ecdsa_suites(),
- run_suites(Ciphers, Config, ecdsa).
-%%--------------------------------------------------------------------
-ciphers_ecdh_rsa_signed_certs() ->
- [{doc, "Test all ecdh_rsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_ecdh_rsa_signed_certs(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:ecdh_rsa_suites(NVersion),
- run_suites(Ciphers, Config, ecdh_rsa).
-%%--------------------------------------------------------------------
-ciphers_ecdh_rsa_signed_certs_openssl_names() ->
- [{doc, "Test all ecdh_rsa ssl cipher suites in highest support ssl/tls version"}].
+ ssl_test_lib:check_server_alert(Server, Client, insufficient_security).
-ciphers_ecdh_rsa_signed_certs_openssl_names(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:openssl_ecdh_rsa_suites(),
- run_suites(Ciphers, Config, ecdh_rsa).
%%--------------------------------------------------------------------
reuse_session() ->
[{doc,"Test reuse of sessions (short handshake)"}].
reuse_session(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, session_info_result, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client0 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, no_result, []}},
- {from, self()}, {options, ClientOpts}]),
- SessionInfo =
- receive
- {Server, Info} ->
- Info
- end,
-
- Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
-
- %% Make sure session is registered
- ct:sleep(?SLEEP),
-
- Client1 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, session_info_result, []}},
- {from, self()}, {options, ClientOpts}]),
- receive
- {Client1, SessionInfo} ->
- ok;
- {Client1, Other} ->
- ct:log("Expected: ~p, Unexpected: ~p~n",
- [SessionInfo, Other]),
- ct:fail(session_not_reused)
- end,
-
- Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
-
- Client2 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, session_info_result, []}},
- {from, self()}, {options, [{reuse_sessions, false}
- | ClientOpts]}]),
- receive
- {Client2, SessionInfo} ->
- ct:fail(
- session_reused_when_session_reuse_disabled_by_client);
- {Client2, _} ->
- ok
- end,
-
- ssl_test_lib:close(Server),
-
- Server1 =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, session_info_result, []}},
- {options, [{reuse_sessions, false} | ServerOpts]}]),
-
- Port1 = ssl_test_lib:inet_port(Server1),
- Client3 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port1}, {host, Hostname},
- {mfa, {ssl_test_lib, no_result, []}},
- {from, self()}, {options, ClientOpts}]),
-
- SessionInfo1 =
- receive
- {Server1, Info1} ->
- Info1
- end,
-
- Server1 ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
-
- %% Make sure session is registered
- ct:sleep(?SLEEP),
-
- Client4 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port1}, {host, Hostname},
- {mfa, {ssl_test_lib, session_info_result, []}},
- {from, self()}, {options, ClientOpts}]),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- receive
- {Client4, SessionInfo1} ->
- ct:fail(
- session_reused_when_session_reuse_disabled_by_server);
- {Client4, _Other} ->
- ct:log("OTHER: ~p ~n", [_Other]),
- ok
- end,
-
- ssl_test_lib:close(Server1),
- ssl_test_lib:close(Client0),
- ssl_test_lib:close(Client1),
- ssl_test_lib:close(Client2),
- ssl_test_lib:close(Client3),
- ssl_test_lib:close(Client4).
-
+ ssl_test_lib:reuse_session(ClientOpts, ServerOpts, Config).
%%--------------------------------------------------------------------
reuse_session_expired() ->
[{doc,"Test sessions is not reused when it has expired"}].
reuse_session_expired(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+
+ Server0 =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
- {mfa, {ssl_test_lib, session_info_result, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client0 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, no_result, []}},
- {from, self()}, {options, ClientOpts}]),
- SessionInfo =
- receive
- {Server, Info} ->
- Info
- end,
-
- Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {tcp_options, [{active, false}]},
+ {options, ServerOpts}]),
+ Port0 = ssl_test_lib:inet_port(Server0),
- %% Make sure session is registered
- ct:sleep(?SLEEP),
-
- Client1 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, session_info_result, []}},
- {from, self()}, {options, ClientOpts}]),
+ Client0 = ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port0}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_id, []}},
+ {from, self()}, {options, [{reuse_sessions, save} | ClientOpts]}]),
+ Server0 ! listen,
+
+ Client1 = ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port0}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_id, []}},
+ {from, self()}, {options, ClientOpts}]),
+
+ SID = receive
+ {Client0, Id0} ->
+ Id0
+ end,
+
receive
- {Client1, SessionInfo} ->
- ok;
- {Client1, Other} ->
- ct:log("Expected: ~p, Unexpected: ~p~n",
- [SessionInfo, Other]),
- ct:fail(session_not_reused)
+ {Client1, SID} ->
+ ok
+ after ?SLEEP ->
+ ct:fail(session_not_reused)
end,
- Server ! listen,
-
+ Server0 ! listen,
+
%% Make sure session is unregistered due to expiration
- ct:sleep((?EXPIRE+1)),
- [{session_id, Id} |_] = SessionInfo,
+ ct:sleep((?EXPIRE*2)),
- make_sure_expired(Hostname, Port, Id),
+ make_sure_expired(Hostname, Port0, SID),
Client2 =
ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, session_info_result, []}},
+ {port, Port0}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_id, []}},
{from, self()}, {options, ClientOpts}]),
receive
- {Client2, SessionInfo} ->
+ {Client2, SID} ->
ct:fail(session_reused_when_session_expired);
{Client2, _} ->
ok
end,
process_flag(trap_exit, false),
- ssl_test_lib:close(Server),
+ ssl_test_lib:close(Server0),
ssl_test_lib:close(Client0),
ssl_test_lib:close(Client1),
ssl_test_lib:close(Client2).
@@ -2749,24 +2756,24 @@ make_sure_expired(Host, Port, Id) ->
{status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
[_, _,_, _, Prop] = StatusInfo,
State = ssl_test_lib:state(Prop),
- Cache = element(2, State),
+ ClientCache = element(2, State),
- case ssl_session_cache:lookup(Cache, {{Host, Port}, Id}) of
+ case ssl_session_cache:lookup(ClientCache, {{Host, Port}, Id}) of
undefined ->
- ok;
+ ok;
#session{is_resumable = false} ->
- ok;
+ ok;
_ ->
ct:sleep(?SLEEP),
- make_sure_expired(Host, Port, Id)
+ make_sure_expired(Host, Port, Id)
end.
%%--------------------------------------------------------------------
server_does_not_want_to_reuse_session() ->
[{doc,"Test reuse of sessions (short handshake)"}].
server_does_not_want_to_reuse_session(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server =
@@ -2869,6 +2876,36 @@ client_secure_renegotiate(Config) when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+client_secure_renegotiate_fallback() ->
+ [{doc,"Test that we can set secure_renegotiate to false that is "
+ "fallback option, we however do not have a insecure server to test against!"}].
+client_secure_renegotiate_fallback(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From erlang to erlang",
+
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
+ {options, [{secure_renegotiate, false} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ renegotiate, [Data]}},
+ {options, [{reuse_sessions, false},
+ {secure_renegotiate, false}| ClientOpts]}]),
+
+ ssl_test_lib:check_result(Client, ok, Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
server_renegotiate() ->
@@ -3038,10 +3075,10 @@ der_input(Config) when is_list(Config) ->
Size = ets:info(CADb, size),
- SeverVerifyOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ SeverVerifyOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
{ServerCert, ServerKey, ServerCaCerts, DHParams} = der_input_opts([{dhfile, DHParamFile} |
SeverVerifyOpts]),
- ClientVerifyOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ClientVerifyOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
{ClientCert, ClientKey, ClientCaCerts, DHParams} = der_input_opts([{dhfile, DHParamFile} |
ClientVerifyOpts]),
ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true},
@@ -3124,7 +3161,7 @@ no_reuses_session_server_restart_new_cert(Config) when is_list(Config) ->
ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
{from, self()},
{mfa, {ssl_test_lib, no_result, []}},
- {options, DsaServerOpts}]),
+ {options, [{reuseaddr, true} | DsaServerOpts]}]),
Client1 =
ssl_test_lib:start_client([{node, ClientNode},
@@ -3185,7 +3222,7 @@ no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) ->
ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
{from, self()},
{mfa, {ssl_test_lib, no_result, []}},
- {options, NewServerOpts1}]),
+ {options, [{reuseaddr, true} | NewServerOpts1]}]),
Client1 =
ssl_test_lib:start_client([{node, ClientNode},
{port, Port}, {host, Hostname},
@@ -3202,18 +3239,25 @@ no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
defaults(Config) when is_list(Config)->
- [_,
- {supported, Supported},
- {available, Available}]
- = ssl:versions(),
- true = lists:member(sslv3, Available),
- false = lists:member(sslv3, Supported),
+ Versions = ssl:versions(),
+ true = lists:member(sslv3, proplists:get_value(available, Versions)),
+ false = lists:member(sslv3, proplists:get_value(supported, Versions)),
+ true = lists:member('tlsv1', proplists:get_value(available, Versions)),
+ false = lists:member('tlsv1', proplists:get_value(supported, Versions)),
+ true = lists:member('tlsv1.1', proplists:get_value(available, Versions)),
+ false = lists:member('tlsv1.1', proplists:get_value(supported, Versions)),
+ true = lists:member('tlsv1.2', proplists:get_value(available, Versions)),
+ true = lists:member('tlsv1.2', proplists:get_value(supported, Versions)),
false = lists:member({rsa,rc4_128,sha}, ssl:cipher_suites()),
true = lists:member({rsa,rc4_128,sha}, ssl:cipher_suites(all)),
false = lists:member({rsa,des_cbc,sha}, ssl:cipher_suites()),
true = lists:member({rsa,des_cbc,sha}, ssl:cipher_suites(all)),
false = lists:member({dhe_rsa,des_cbc,sha}, ssl:cipher_suites()),
- true = lists:member({dhe_rsa,des_cbc,sha}, ssl:cipher_suites(all)).
+ true = lists:member({dhe_rsa,des_cbc,sha}, ssl:cipher_suites(all)),
+ true = lists:member('dtlsv1.2', proplists:get_value(available_dtls, Versions)),
+ true = lists:member('dtlsv1', proplists:get_value(available_dtls, Versions)),
+ true = lists:member('dtlsv1.2', proplists:get_value(supported_dtls, Versions)),
+ false = lists:member('dtlsv1', proplists:get_value(supported_dtls, Versions)).
%%--------------------------------------------------------------------
reuseaddr() ->
@@ -3299,16 +3343,50 @@ tls_tcp_reuseaddr(Config) when is_list(Config) ->
honor_server_cipher_order() ->
[{doc,"Test API honor server cipher order."}].
honor_server_cipher_order(Config) when is_list(Config) ->
- ClientCiphers = [{rsa, aes_128_cbc, sha}, {rsa, aes_256_cbc, sha}],
- ServerCiphers = [{rsa, aes_256_cbc, sha}, {rsa, aes_128_cbc, sha}],
-honor_cipher_order(Config, true, ServerCiphers, ClientCiphers, {rsa, aes_256_cbc, sha}).
+ ClientCiphers = [#{key_exchange => dhe_rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf},
+ #{key_exchange => dhe_rsa,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf}],
+ ServerCiphers = [#{key_exchange => dhe_rsa,
+ cipher => aes_256_cbc,
+ mac =>sha,
+ prf => default_prf},
+ #{key_exchange => dhe_rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf}],
+ honor_cipher_order(Config, true, ServerCiphers, ClientCiphers, #{key_exchange => dhe_rsa,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf}).
honor_client_cipher_order() ->
[{doc,"Test API honor server cipher order."}].
honor_client_cipher_order(Config) when is_list(Config) ->
- ClientCiphers = [{rsa, aes_128_cbc, sha}, {rsa, aes_256_cbc, sha}],
- ServerCiphers = [{rsa, aes_256_cbc, sha}, {rsa, aes_128_cbc, sha}],
-honor_cipher_order(Config, false, ServerCiphers, ClientCiphers, {rsa, aes_128_cbc, sha}).
+ ClientCiphers = [#{key_exchange => dhe_rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf},
+ #{key_exchange => dhe_rsa,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf}],
+ ServerCiphers = [#{key_exchange => dhe_rsa,
+ cipher => aes_256_cbc,
+ mac =>sha,
+ prf => default_prf},
+ #{key_exchange => dhe_rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf}],
+honor_cipher_order(Config, false, ServerCiphers, ClientCiphers, #{key_exchange => dhe_rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf}).
honor_cipher_order(Config, Honor, ServerCiphers, ClientCiphers, Expected) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
@@ -3340,7 +3418,7 @@ honor_cipher_order(Config, Honor, ServerCiphers, ClientCiphers, Expected) ->
%%--------------------------------------------------------------------
tls_ciphersuite_vs_version() ->
- [{doc,"Test a SSLv3 client can not negotiate a TLSv* cipher suite."}].
+ [{doc,"Test a SSLv3 client cannot negotiate a TLSv* cipher suite."}].
tls_ciphersuite_vs_version(Config) when is_list(Config) ->
{_ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -3364,7 +3442,7 @@ tls_ciphersuite_vs_version(Config) when is_list(Config) ->
>>),
{ok, <<22, RecMajor:8, RecMinor:8, _RecLen:16, 2, HelloLen:24>>} = gen_tcp:recv(Socket, 9, 10000),
{ok, <<HelloBin:HelloLen/binary>>} = gen_tcp:recv(Socket, HelloLen, 5000),
- ServerHello = tls_handshake:decode_handshake({RecMajor, RecMinor}, 2, HelloBin, false),
+ ServerHello = tls_handshake:decode_handshake({RecMajor, RecMinor}, 2, HelloBin),
case ServerHello of
#server_hello{server_version = {3,0}, cipher_suite = <<0,57>>} ->
ok;
@@ -3383,14 +3461,14 @@ conf_signature_algs(Config) when is_list(Config) ->
ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {ssl_test_lib, send_recv_result, []}},
- {options, [{active, false}, {signature_algs, [{sha256, rsa}]} | ServerOpts]}]),
+ {options, [{active, false}, {signature_algs, [{sha, rsa}]} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Client =
ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
{mfa, {ssl_test_lib, send_recv_result, []}},
- {options, [{active, false}, {signature_algs, [{sha256, rsa}]} | ClientOpts]}]),
+ {options, [{active, false}, {signature_algs, [{sha, rsa}]} | ClientOpts]}]),
ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
@@ -3418,14 +3496,13 @@ no_common_signature_algs(Config) when is_list(Config) ->
| ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {options, [{signature_algs, [{sha384, rsa}]}
- | ClientOpts]}]),
+ {host, Hostname},
+ {from, self()},
+ {options, [{signature_algs, [{sha384, rsa}]}
+ | ClientOpts]}]),
- ssl_test_lib:check_result(Server, {error, {tls_alert, "insufficient security"}},
- Client, {error, {tls_alert, "insufficient security"}}).
-
+ ssl_test_lib:check_server_alert(Server, Client, insufficient_security).
+
%%--------------------------------------------------------------------
tls_dont_crash_on_handshake_garbage() ->
@@ -3455,7 +3532,7 @@ tls_dont_crash_on_handshake_garbage(Config) ->
<<22, 3,3, 5:16, 92,64,37,228,209>> % garbage
]),
% Send unexpected change_cipher_spec
- ok = gen_tcp:send(Socket, <<20, 0,0,12, 111,40,244,7,137,224,16,109,197,110,249,152>>),
+ ok = gen_tcp:send(Socket, <<20, 3,3, 12:16, 111,40,244,7,137,224,16,109,197,110,249,152>>),
% Ensure we receive an alert, not sudden disconnect
{ok, <<21, _/binary>>} = drop_handshakes(Socket, 1000).
@@ -3487,7 +3564,7 @@ hibernate(Config) ->
{mfa, {ssl_test_lib, send_recv_result_active, []}},
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
- {Client, #sslsocket{pid=Pid}} = ssl_test_lib:start_client([return_socket,
+ {Client, #sslsocket{pid=[Pid|_]}} = ssl_test_lib:start_client([return_socket,
{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
@@ -3530,7 +3607,7 @@ hibernate_right_away(Config) ->
Server1 = ssl_test_lib:start_server(StartServerOpts),
Port1 = ssl_test_lib:inet_port(Server1),
- {Client1, #sslsocket{pid = Pid1}} = ssl_test_lib:start_client(StartClientOpts ++
+ {Client1, #sslsocket{pid = [Pid1|_]}} = ssl_test_lib:start_client(StartClientOpts ++
[{port, Port1}, {options, [{hibernate_after, 0}|ClientOpts]}]),
ssl_test_lib:check_result(Server1, ok, Client1, ok),
@@ -3542,7 +3619,7 @@ hibernate_right_away(Config) ->
Server2 = ssl_test_lib:start_server(StartServerOpts),
Port2 = ssl_test_lib:inet_port(Server2),
- {Client2, #sslsocket{pid = Pid2}} = ssl_test_lib:start_client(StartClientOpts ++
+ {Client2, #sslsocket{pid = [Pid2|_]}} = ssl_test_lib:start_client(StartClientOpts ++
[{port, Port2}, {options, [{hibernate_after, 1}|ClientOpts]}]),
ssl_test_lib:check_result(Server2, ok, Client2, ok),
@@ -3575,7 +3652,7 @@ listen_socket(Config) ->
{error, enotconn} = ssl:peername(ListenSocket),
{error, enotconn} = ssl:peercert(ListenSocket),
{error, enotconn} = ssl:renegotiate(ListenSocket),
- {error, enotconn} = ssl:prf(ListenSocket, 'master_secret', <<"Label">>, client_random, 256),
+ {error, enotconn} = ssl:prf(ListenSocket, 'master_secret', <<"Label">>, [client_random], 256),
{error, enotconn} = ssl:shutdown(ListenSocket, read_write),
ok = ssl:close(ListenSocket).
@@ -3778,18 +3855,18 @@ tls_tcp_error_propagation_in_active_mode(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
- {Client, #sslsocket{pid=Pid} = SslSocket} = ssl_test_lib:start_client([return_socket,
- {node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, receive_msg, []}},
- {options, ClientOpts}]),
-
+ {Client, #sslsocket{pid=[Pid|_]} = SslSocket} = ssl_test_lib:start_client([return_socket,
+ {node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, receive_msg, []}},
+ {options, ClientOpts}]),
+
{status, _, _, StatusInfo} = sys:get_status(Pid),
[_, _,_, _, Prop] = StatusInfo,
State = ssl_test_lib:state(Prop),
- Socket = element(11, State),
-
+ StaticEnv = element(2, State),
+ Socket = element(11, StaticEnv),
%% Fake tcp error
Pid ! {tcp_error, Socket, etimedout},
@@ -3817,6 +3894,108 @@ recv_error_handling(Config) when is_list(Config) ->
ssl:close(SslSocket),
ssl_test_lib:check_result(Server, ok).
+
+
+%%--------------------------------------------------------------------
+call_in_error_state() ->
+ [{doc,"Special case of call error handling"}].
+call_in_error_state(Config) when is_list(Config) ->
+ ServerOpts0 = ssl_test_lib:ssl_options(server_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = [{cacertfile, "foo.pem"} | proplists:delete(cacertfile, ServerOpts0)],
+ Pid = spawn_link(?MODULE, run_error_server, [[self() | ServerOpts]]),
+ receive
+ {Pid, Port} ->
+ spawn_link(?MODULE, run_client_error, [[Port, ClientOpts]])
+ end,
+ receive
+ {error, closed} ->
+ ok;
+ Other ->
+ ct:fail(Other)
+ end.
+
+run_client_error([Port, Opts]) ->
+ ssl:connect("localhost", Port, Opts).
+
+run_error_server([ Pid | Opts]) ->
+ {ok, Listen} = ssl:listen(0, Opts),
+ {ok,{_, Port}} = ssl:sockname(Listen),
+ Pid ! {self(), Port},
+ {ok, Socket} = ssl:transport_accept(Listen),
+ Pid ! ssl:controlling_process(Socket, self()).
+
+%%--------------------------------------------------------------------
+
+close_in_error_state() ->
+ [{doc,"Special case of closing socket in error state"}].
+close_in_error_state(Config) when is_list(Config) ->
+ ServerOpts0 = ssl_test_lib:ssl_options(server_opts, Config),
+ ServerOpts = [{cacertfile, "foo.pem"} | proplists:delete(cacertfile, ServerOpts0)],
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ _ = spawn_link(?MODULE, run_error_server_close, [[self() | ServerOpts]]),
+ receive
+ {_Pid, Port} ->
+ spawn_link(?MODULE, run_client_error, [[Port, ClientOpts]])
+ end,
+ receive
+ ok ->
+ ok;
+ Other ->
+ ct:fail(Other)
+ end.
+%%--------------------------------------------------------------------
+abuse_transport_accept_socket() ->
+ [{doc,"Only ssl:handshake and ssl:controlling_process is allowed for transport_accept:sockets"}].
+abuse_transport_accept_socket(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server_transport_abuse_socket([{node, ServerNode},
+ {port, 0},
+ {from, self()},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ClientOpts}]),
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+
+%%--------------------------------------------------------------------
+controlling_process_transport_accept_socket() ->
+ [{doc,"Only ssl:handshake and ssl:controlling_process is allowed for transport_accept:sockets"}].
+controlling_process_transport_accept_socket(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server_transport_control([{node, ServerNode},
+ {port, 0},
+ {from, self()},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ _Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {options, ClientOpts}]),
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server).
+
+%%--------------------------------------------------------------------
+run_error_server_close([Pid | Opts]) ->
+ {ok, Listen} = ssl:listen(0, Opts),
+ {ok,{_, Port}} = ssl:sockname(Listen),
+ Pid ! {self(), Port},
+ {ok, Socket} = ssl:transport_accept(Listen),
+ Pid ! ssl:close(Socket).
+
%%--------------------------------------------------------------------
rizzo() ->
@@ -3837,6 +4016,8 @@ rizzo(Config) when is_list(Config) ->
{cipher,
fun(rc4_128) ->
false;
+ (chacha20_poly1305) ->
+ false;
(_) ->
true
end}]),
@@ -3879,6 +4060,9 @@ rizzo_one_n_minus_one(Config) when is_list(Config) ->
{cipher,
fun(rc4_128) ->
false;
+ %% TODO: remove this clause when chacha is fixed!
+ (chacha20_poly1305) ->
+ false;
(_) ->
true
end}]),
@@ -4020,8 +4204,7 @@ tls_versions_option(Config) when is_list(Config) ->
{Server, _} ->
ok
end,
-
- ssl_test_lib:check_result(ErrClient, {error, {tls_alert, "protocol version"}}).
+ ssl_test_lib:check_client_alert(ErrClient, protocol_version).
%%--------------------------------------------------------------------
@@ -4036,17 +4219,17 @@ unordered_protocol_versions_server(Config) when is_list(Config) ->
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
- {mfa, {?MODULE, connection_info_result, []}},
+ {mfa, {?MODULE, protocol_info_result, []}},
{options, [{versions, ['tlsv1.1', 'tlsv1.2']} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
- {mfa, {?MODULE, connection_info_result, []}},
+ {mfa, {?MODULE, protocol_info_result, []}},
{options, ClientOpts}]),
- CipherSuite = first_rsa_suite(ssl:cipher_suites()),
- ServerMsg = ClientMsg = {ok, {'tlsv1.2', CipherSuite}},
+
+ ServerMsg = ClientMsg = {ok,'tlsv1.2'},
ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg).
%%--------------------------------------------------------------------
@@ -4061,18 +4244,17 @@ unordered_protocol_versions_client(Config) when is_list(Config) ->
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
- {mfa, {?MODULE, connection_info_result, []}},
+ {mfa, {?MODULE, protocol_info_result, []}},
{options, ServerOpts }]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
- {mfa, {?MODULE, connection_info_result, []}},
+ {mfa, {?MODULE, protocol_info_result, []}},
{options, [{versions, ['tlsv1.1', 'tlsv1.2']} | ClientOpts]}]),
-
- CipherSuite = first_rsa_suite(ssl:cipher_suites()),
- ServerMsg = ClientMsg = {ok, {'tlsv1.2', CipherSuite}},
+
+ ServerMsg = ClientMsg = {ok, 'tlsv1.2'},
ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg).
%%--------------------------------------------------------------------
@@ -4183,6 +4365,1292 @@ accept_pool(Config) when is_list(Config) ->
ssl_test_lib:close(Client1),
ssl_test_lib:close(Client2).
+%%--------------------------------------------------------------------
+%% TLS 1.3
+%%--------------------------------------------------------------------
+
+tls13_enable_client_side() ->
+ [{doc,"Test that a TLS 1.3 client can connect to a TLS 1.2 server."}].
+
+tls13_enable_client_side(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, protocol_info_result, []}},
+ {options, [{versions,
+ ['tlsv1.1', 'tlsv1.2']} | ServerOpts] }]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, protocol_info_result, []}},
+ {options, [{versions,
+ ['tlsv1.2', 'tlsv1.3']} | ClientOpts]}]),
+
+ ServerMsg = ClientMsg = {ok, 'tlsv1.2'},
+ ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg).
+
+tls13_enable_server_side() ->
+ [{doc,"Test that a TLS 1.2 client can connect to a TLS 1.3 server."}].
+
+tls13_enable_server_side(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, protocol_info_result, []}},
+ {options, [{versions,
+ ['tlsv1.2', 'tlsv1.3']} | ServerOpts] }]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, protocol_info_result, []}},
+ {options, [{versions,
+ ['tlsv1.2', 'tlsv1.1']} | ClientOpts]}]),
+
+ ServerMsg = ClientMsg = {ok, 'tlsv1.2'},
+ ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg).
+
+tls_record_1_3_encode_decode() ->
+ [{doc,"Test TLS 1.3 record encode/decode functions"}].
+
+tls_record_1_3_encode_decode(_Config) ->
+ ConnectionStates =
+ #{current_read =>
+ #{beast_mitigation => one_n_minus_one,
+ cipher_state =>
+ {cipher_state,
+ <<14,172,111,243,199,170,242,203,126,205,34,93,122,115,226,14,
+ 15,117,155,48,24,112,61,15,113,208,127,51,179,227,194,232>>,
+ <<197,54,168,218,54,91,157,58,30,201,197,142,51,58,53,231,228,
+ 131,57,122,170,78,82,196,30,48,23,16,95,255,185,236>>,
+ undefined,undefined,undefined,16},
+ client_verify_data => undefined,compression_state => undefined,
+ mac_secret => undefined,secure_renegotiation => undefined,
+ security_parameters =>
+ {security_parameters,
+ <<19,2>>,
+ 0,8,2,undefined,undefined,undefined,undefined,undefined,
+ sha384,undefined,undefined,
+ {handshake_secret,
+ <<128,229,186,211,62,127,182,20,62,166,233,23,135,64,121,
+ 3,104,251,214,161,253,31,3,2,232,37,8,221,189,72,64,218,
+ 121,41,112,148,254,34,68,164,228,60,161,201,132,55,56,
+ 157>>},
+ undefined,
+ <<92,24,205,75,244,60,136,212,250,32,214,20,37,3,213,87,61,207,
+ 147,61,168,145,177,118,160,153,33,53,48,108,191,174>>,
+ undefined},
+ sequence_number => 0,server_verify_data => undefined},
+ current_write =>
+ #{beast_mitigation => one_n_minus_one,
+ cipher_state =>
+ {cipher_state,
+ <<14,172,111,243,199,170,242,203,126,205,34,93,122,115,226,14,
+ 15,117,155,48,24,112,61,15,113,208,127,51,179,227,194,232>>,
+ <<197,54,168,218,54,91,157,58,30,201,197,142,51,58,53,231,228,
+ 131,57,122,170,78,82,196,30,48,23,16,95,255,185,236>>,
+ undefined,undefined,undefined,16},
+ client_verify_data => undefined,compression_state => undefined,
+ mac_secret => undefined,secure_renegotiation => undefined,
+ security_parameters =>
+ {security_parameters,
+ <<19,2>>,
+ 0,8,2,undefined,undefined,undefined,undefined,undefined,
+ sha384,undefined,undefined,
+ {handshake_secret,
+ <<128,229,186,211,62,127,182,20,62,166,233,23,135,64,121,
+ 3,104,251,214,161,253,31,3,2,232,37,8,221,189,72,64,218,
+ 121,41,112,148,254,34,68,164,228,60,161,201,132,55,56,
+ 157>>},
+ undefined,
+ <<92,24,205,75,244,60,136,212,250,32,214,20,37,3,213,87,61,207,
+ 147,61,168,145,177,118,160,153,33,53,48,108,191,174>>,
+ undefined},
+ sequence_number => 0,server_verify_data => undefined}},
+
+ PlainText = [11,
+ <<0,2,175>>,
+ <<0,0,2,171,0,2,166,48,130,2,162,48,130,1,138,2,9,0,186,57,220,137,88,255,
+ 191,235,48,13,6,9,42,134,72,134,247,13,1,1,11,5,0,48,18,49,16,48,14,6,3,85,
+ 4,3,12,7,84,101,115,116,32,67,65,48,30,23,13,49,56,48,53,48,52,49,52,49,50,
+ 51,56,90,23,13,50,56,48,50,48,52,49,52,49,50,51,56,90,48,20,49,18,48,16,6,
+ 3,85,4,3,12,9,108,111,99,97,108,104,111,115,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,169,40,
+ 144,176,121,63,134,97,144,126,243,183,225,157,37,131,183,225,87,243,23,88,
+ 230,70,9,134,32,147,7,27,167,98,51,81,224,75,199,12,229,251,195,207,75,179,
+ 181,78,128,3,255,44,58,39,43,172,142,45,186,58,51,65,187,199,154,153,245,
+ 70,133,137,1,27,87,42,116,65,251,129,109,145,233,97,171,71,54,213,185,74,
+ 209,166,11,218,189,119,206,86,170,60,212,213,85,189,30,50,215,23,185,53,
+ 132,238,132,176,198,250,139,251,198,221,225,128,109,113,23,220,39,143,71,
+ 30,59,189,51,244,61,158,214,146,180,196,103,169,189,221,136,78,129,216,148,
+ 2,9,8,65,37,224,215,233,13,209,21,235,20,143,33,74,59,53,208,90,152,94,251,
+ 54,114,171,39,88,230,227,158,211,135,37,182,67,205,161,59,20,138,58,253,15,
+ 53,48,8,157,9,95,197,9,177,116,21,54,9,125,78,109,182,83,20,16,234,223,116,
+ 41,155,123,87,77,17,120,153,246,239,124,130,105,219,166,146,242,151,66,198,
+ 75,72,63,28,246,86,16,244,223,22,36,50,15,247,222,98,6,152,136,154,72,150,
+ 73,127,2,3,1,0,1,48,13,6,9,42,134,72,134,247,13,1,1,11,5,0,3,130,1,1,0,76,
+ 33,54,160,229,219,219,193,150,116,245,252,18,39,235,145,86,12,167,171,52,
+ 117,166,30,83,5,216,245,177,217,247,95,1,136,94,246,212,108,248,230,111,
+ 225,202,189,6,129,8,70,128,245,18,204,215,87,82,129,253,227,122,66,182,184,
+ 189,30,193,169,144,218,216,109,105,110,215,144,60,104,162,178,101,164,218,
+ 122,60,37,41,143,57,150,52,59,51,112,238,113,239,168,114,69,183,143,154,73,
+ 61,58,80,247,172,95,251,55,28,186,28,200,206,230,118,243,92,202,189,49,76,
+ 124,252,76,0,247,112,85,194,69,59,222,163,228,103,49,110,104,109,251,155,
+ 138,9,37,167,49,189,48,134,52,158,185,129,24,96,153,196,251,90,206,76,239,
+ 175,119,174,165,133,108,222,125,237,125,187,149,152,83,190,16,202,94,202,
+ 201,40,218,22,254,63,189,41,174,97,140,203,70,18,196,118,237,175,134,79,78,
+ 246,2,61,54,77,186,112,32,17,193,192,188,217,252,215,200,7,245,180,179,132,
+ 183,212,229,155,15,152,206,135,56,81,88,3,123,244,149,110,182,72,109,70,62,
+ 146,152,146,151,107,126,216,210,9,93,0,0>>],
+
+ {[_Header|Encoded], _} = tls_record_1_3:encode_plain_text(22, PlainText, ConnectionStates),
+ CipherText = #ssl_tls{type = 23, version = {3,3}, fragment = Encoded},
+
+ {#ssl_tls{type = 22, version = {3,4}, fragment = DecodedText}, _} =
+ tls_record_1_3:decode_cipher_text(CipherText, ConnectionStates),
+
+ DecodedText = iolist_to_binary(PlainText),
+ ct:log("Decoded: ~p ~n", [DecodedText]),
+ ok.
+
+tls13_1_RTT_handshake() ->
+ [{doc,"Test TLS 1.3 1-RTT Handshake"}].
+
+tls13_1_RTT_handshake(_Config) ->
+ %% ConnectionStates with NULL cipher
+ ConnStatesNull =
+ #{current_write =>
+ #{security_parameters =>
+ #security_parameters{cipher_suite = ?TLS_NULL_WITH_NULL_NULL},
+ sequence_number => 0
+ }
+ },
+
+ %% {client} construct a ClientHello handshake message:
+ %%
+ %% ClientHello (196 octets): 01 00 00 c0 03 03 cb 34 ec b1 e7 81 63
+ %% ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 ec 18 a2 ef 62 83
+ %% 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 00 91 00 00 00 0b
+ %% 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 00 00 0a 00 14 00
+ %% 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 23
+ %% 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d e5 60 e4 bd 43 d2
+ %% 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a
+ %% af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e 04 03 05 03 06 03
+ %% 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02 01 04 02 05 02 06
+ %% 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01
+ %%
+ %% {client} send handshake record:
+ %%
+ %% payload (196 octets): 01 00 00 c0 03 03 cb 34 ec b1 e7 81 63 ba
+ %% 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 ec 18 a2 ef 62 83 02
+ %% 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 00 91 00 00 00 0b 00
+ %% 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 00 00 0a 00 14 00 12
+ %% 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 23 00
+ %% 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d e5 60 e4 bd 43 d2 3d
+ %% 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a af
+ %% 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e 04 03 05 03 06 03 02
+ %% 03 08 04 08 05 08 06 04 01 05 01 06 01 02 01 04 02 05 02 06 02
+ %% 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01
+ %%
+ %% complete record (201 octets): 16 03 01 00 c4 01 00 00 c0 03 03 cb
+ %% 34 ec b1 e7 81 63 ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12
+ %% ec 18 a2 ef 62 83 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00
+ %% 00 91 00 00 00 0b 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01
+ %% 00 00 0a 00 14 00 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02
+ %% 01 03 01 04 00 23 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d
+ %% e5 60 e4 bd 43 d2 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d
+ %% 54 13 69 1e 52 9a af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e
+ %% 04 03 05 03 06 03 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02
+ %% 01 04 02 05 02 06 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01
+ ClientHello =
+ hexstr2bin("01 00 00 c0 03 03 cb 34 ec b1 e7 81 63
+ ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 ec 18 a2 ef 62 83
+ 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 00 91 00 00 00 0b
+ 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 00 00 0a 00 14 00
+ 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 23
+ 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d e5 60 e4 bd 43 d2
+ 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a
+ af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e 04 03 05 03 06 03
+ 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02 01 04 02 05 02 06
+ 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01"),
+
+ ClientHelloRecord =
+ %% Current implementation always sets
+ %% legacy_record_version to Ox0303
+ hexstr2bin("16 03 03 00 c4 01 00 00 c0 03 03 cb
+ 34 ec b1 e7 81 63 ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12
+ ec 18 a2 ef 62 83 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00
+ 00 91 00 00 00 0b 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01
+ 00 00 0a 00 14 00 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02
+ 01 03 01 04 00 23 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d
+ e5 60 e4 bd 43 d2 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d
+ 54 13 69 1e 52 9a af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e
+ 04 03 05 03 06 03 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02
+ 01 04 02 05 02 06 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01"),
+
+ {CHEncrypted, _} =
+ tls_record:encode_handshake(ClientHello, {3,4}, ConnStatesNull),
+ ClientHelloRecord = iolist_to_binary(CHEncrypted),
+
+ %% {server} extract secret "early":
+ %%
+ %% salt: 0 (all zero octets)
+ %%
+ %% IKM (32 octets): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ %% 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ %%
+ %% secret (32 octets): 33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c
+ %% e2 10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a
+ HKDFAlgo = sha256,
+ Salt = binary:copy(<<?BYTE(0)>>, 32),
+ IKM = binary:copy(<<?BYTE(0)>>, 32),
+ EarlySecret =
+ hexstr2bin("33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c
+ e2 10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a"),
+
+ {early_secret, EarlySecret} = tls_v1:key_schedule(early_secret, HKDFAlgo, {psk, Salt}),
+
+ %% {client} create an ephemeral x25519 key pair:
+ %%
+ %% private key (32 octets): 49 af 42 ba 7f 79 94 85 2d 71 3e f2 78
+ %% 4b cb ca a7 91 1d e2 6a dc 56 42 cb 63 45 40 e7 ea 50 05
+ %%
+ %% public key (32 octets): 99 38 1d e5 60 e4 bd 43 d2 3d 8e 43 5a 7d
+ %% ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a af 2c
+ CPublicKey =
+ hexstr2bin("99 38 1d e5 60 e4 bd 43 d2 3d 8e 43 5a 7d
+ ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a af 2c"),
+
+ %% {server} create an ephemeral x25519 key pair:
+ %%
+ %% private key (32 octets): b1 58 0e ea df 6d d5 89 b8 ef 4f 2d 56
+ %% 52 57 8c c8 10 e9 98 01 91 ec 8d 05 83 08 ce a2 16 a2 1e
+ %%
+ %% public key (32 octets): c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6
+ %% 72 e1 56 d6 cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f
+ SPrivateKey =
+ hexstr2bin("b1 58 0e ea df 6d d5 89 b8 ef 4f 2d 56
+ 52 57 8c c8 10 e9 98 01 91 ec 8d 05 83 08 ce a2 16 a2 1e"),
+
+ SPublicKey =
+ hexstr2bin("c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6
+ 72 e1 56 d6 cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f"),
+
+ %% {server} construct a ServerHello handshake message:
+ %%
+ %% ServerHello (90 octets): 02 00 00 56 03 03 a6 af 06 a4 12 18 60
+ %% dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 34 da c1 55 77 2e
+ %% d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00 1d 00 20 c9 82 88
+ %% 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 cc 25 3b 83 3d f1
+ %% dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04
+ ServerHello =
+ hexstr2bin("02 00 00 56 03 03 a6 af 06 a4 12 18 60
+ dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 34 da c1 55 77 2e
+ d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00 1d 00 20 c9 82 88
+ 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 cc 25 3b 83 3d f1
+ dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04"),
+
+ %% {server} derive secret for handshake "tls13 derived":
+ %%
+ %% PRK (32 octets): 33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c e2
+ %% 10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a
+ %%
+ %% hash (32 octets): e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24
+ %% 27 ae 41 e4 64 9b 93 4c a4 95 99 1b 78 52 b8 55
+ %%
+ %% info (49 octets): 00 20 0d 74 6c 73 31 33 20 64 65 72 69 76 65 64
+ %% 20 e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 27 ae 41 e4
+ %% 64 9b 93 4c a4 95 99 1b 78 52 b8 55
+ %%
+ %% expanded (32 octets): 6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba
+ %% b6 97 16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba
+ Hash =
+ hexstr2bin("e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24
+ 27 ae 41 e4 64 9b 93 4c a4 95 99 1b 78 52 b8 55"),
+
+ Hash = crypto:hash(HKDFAlgo, <<>>),
+
+ Info =
+ hexstr2bin("00 20 0d 74 6c 73 31 33 20 64 65 72 69 76 65 64
+ 20 e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 27 ae 41 e4
+ 64 9b 93 4c a4 95 99 1b 78 52 b8 55"),
+
+ Info = tls_v1:create_info(<<"derived">>, Hash, ssl_cipher:hash_size(HKDFAlgo)),
+
+ Expanded =
+ hexstr2bin("6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba
+ b6 97 16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba"),
+
+ Expanded = tls_v1:derive_secret(EarlySecret, <<"derived">>, <<>>, HKDFAlgo),
+
+ %% {server} extract secret "handshake":
+ %%
+ %% salt (32 octets): 6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba b6 97
+ %% 16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba
+ %%
+ %% IKM (32 octets): 8b d4 05 4f b5 5b 9d 63 fd fb ac f9 f0 4b 9f 0d
+ %% 35 e6 d6 3f 53 75 63 ef d4 62 72 90 0f 89 49 2d
+ %%
+ %% secret (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b
+ %% 01 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac
+
+ %% salt = Expanded
+ HandshakeIKM =
+ hexstr2bin("8b d4 05 4f b5 5b 9d 63 fd fb ac f9 f0 4b 9f 0d
+ 35 e6 d6 3f 53 75 63 ef d4 62 72 90 0f 89 49 2d"),
+
+ HandshakeSecret =
+ hexstr2bin("1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b
+ 01 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac"),
+
+ HandshakeIKM = crypto:compute_key(ecdh, CPublicKey, SPrivateKey, x25519),
+
+ {handshake_secret, HandshakeSecret} =
+ tls_v1:key_schedule(handshake_secret, HKDFAlgo, HandshakeIKM,
+ {early_secret, EarlySecret}),
+
+ %% {server} derive secret "tls13 c hs traffic":
+ %%
+ %% PRK (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b 01
+ %% 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac
+ %%
+ %% hash (32 octets): 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 ed
+ %% d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8
+ %%
+ %% info (54 octets): 00 20 12 74 6c 73 31 33 20 63 20 68 73 20 74 72
+ %% 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58
+ %% ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8
+ %%
+ %% expanded (32 octets): b3 ed db 12 6e 06 7f 35 a7 80 b3 ab f4 5e
+ %% 2d 8f 3b 1a 95 07 38 f5 2e 96 00 74 6a 0e 27 a5 5a 21
+
+ %% PRK = HandshakeSecret
+ CHSTHash =
+ hexstr2bin("86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 ed
+ d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8"),
+
+ CHSTInfo =
+ hexstr2bin("00 20 12 74 6c 73 31 33 20 63 20 68 73 20 74 72
+ 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58
+ ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8"),
+
+ CHSTrafficSecret =
+ hexstr2bin(" b3 ed db 12 6e 06 7f 35 a7 80 b3 ab f4 5e
+ 2d 8f 3b 1a 95 07 38 f5 2e 96 00 74 6a 0e 27 a5 5a 21"),
+
+ CHSH = <<ClientHello/binary,ServerHello/binary>>,
+ CHSTHash = crypto:hash(HKDFAlgo, CHSH),
+ CHSTInfo = tls_v1:create_info(<<"c hs traffic">>, CHSTHash, ssl_cipher:hash_size(HKDFAlgo)),
+
+ CHSTrafficSecret =
+ tls_v1:client_handshake_traffic_secret(HKDFAlgo, {handshake_secret, HandshakeSecret}, CHSH),
+
+ %% {server} derive secret "tls13 s hs traffic":
+ %%
+ %% PRK (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b 01
+ %% 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac
+ %%
+ %% hash (32 octets): 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 ed
+ %% d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8
+ %%
+ %% info (54 octets): 00 20 12 74 6c 73 31 33 20 73 20 68 73 20 74 72
+ %% 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58
+ %% ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8
+ %%
+ %% expanded (32 octets): b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d
+ %% 37 b4 e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38
+
+ %% PRK = HandshakeSecret
+ %% hash = CHSTHash
+ SHSTInfo =
+ hexstr2bin("00 20 12 74 6c 73 31 33 20 73 20 68 73 20 74 72
+ 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58
+ ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8"),
+
+ SHSTrafficSecret =
+ hexstr2bin("b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d
+ 37 b4 e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38"),
+
+ SHSTInfo = tls_v1:create_info(<<"s hs traffic">>, CHSTHash, ssl_cipher:hash_size(HKDFAlgo)),
+
+ SHSTrafficSecret =
+ tls_v1:server_handshake_traffic_secret(HKDFAlgo, {handshake_secret, HandshakeSecret}, CHSH),
+
+
+ %% {server} derive secret for master "tls13 derived":
+ %%
+ %% PRK (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b 01
+ %% 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac
+ %%
+ %% hash (32 octets): e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24
+ %% 27 ae 41 e4 64 9b 93 4c a4 95 99 1b 78 52 b8 55
+ %%
+ %% info (49 octets): 00 20 0d 74 6c 73 31 33 20 64 65 72 69 76 65 64
+ %% 20 e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 27 ae 41 e4
+ %% 64 9b 93 4c a4 95 99 1b 78 52 b8 55
+ %%
+ %% expanded (32 octets): 43 de 77 e0 c7 77 13 85 9a 94 4d b9 db 25
+ %% 90 b5 31 90 a6 5b 3e e2 e4 f1 2d d7 a0 bb 7c e2 54 b4
+
+ %% PRK = HandshakeSecret
+ %% hash = Hash
+ %% info = Info
+ MasterDeriveSecret =
+ hexstr2bin("43 de 77 e0 c7 77 13 85 9a 94 4d b9 db 25
+ 90 b5 31 90 a6 5b 3e e2 e4 f1 2d d7 a0 bb 7c e2 54 b4"),
+
+ MasterDeriveSecret = tls_v1:derive_secret(HandshakeSecret, <<"derived">>, <<>>, HKDFAlgo),
+
+ %% {server} extract secret "master":
+ %%
+ %% salt (32 octets): 43 de 77 e0 c7 77 13 85 9a 94 4d b9 db 25 90 b5
+ %% 31 90 a6 5b 3e e2 e4 f1 2d d7 a0 bb 7c e2 54 b4
+ %%
+ %% IKM (32 octets): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ %% 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ %%
+ %% secret (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a
+ %% 47 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19
+
+ %% salt = MasterDeriveSecret
+ %% IKM = IKM
+ MasterSecret =
+ hexstr2bin("18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a
+ 47 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19"),
+
+ {master_secret, MasterSecret} =
+ tls_v1:key_schedule(master_secret, HKDFAlgo, {handshake_secret, HandshakeSecret}),
+
+ %% {server} send handshake record:
+ %%
+ %% payload (90 octets): 02 00 00 56 03 03 a6 af 06 a4 12 18 60 dc 5e
+ %% 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 34 da c1 55 77 2e d3 e2
+ %% 69 28 00 13 01 00 00 2e 00 33 00 24 00 1d 00 20 c9 82 88 76 11
+ %% 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 cc 25 3b 83 3d f1 dd 69
+ %% b1 b0 4e 75 1f 0f 00 2b 00 02 03 04
+ %%
+ %% complete record (95 octets): 16 03 03 00 5a 02 00 00 56 03 03 a6
+ %% af 06 a4 12 18 60 dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14
+ %% 34 da c1 55 77 2e d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00
+ %% 1d 00 20 c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6
+ %% cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04
+
+ %% payload = ServerHello
+ ServerHelloRecord =
+ hexstr2bin("16 03 03 00 5a 02 00 00 56 03 03 a6
+ af 06 a4 12 18 60 dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14
+ 34 da c1 55 77 2e d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00
+ 1d 00 20 c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6
+ cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04"),
+
+ {SHEncrypted, _} =
+ tls_record:encode_handshake(ServerHello, {3,4}, ConnStatesNull),
+ ServerHelloRecord = iolist_to_binary(SHEncrypted),
+
+ %% {server} derive write traffic keys for handshake data:
+ %%
+ %% PRK (32 octets): b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d 37 b4
+ %% e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38
+ %%
+ %% key info (13 octets): 00 10 09 74 6c 73 31 33 20 6b 65 79 00
+ %%
+ %% key expanded (16 octets): 3f ce 51 60 09 c2 17 27 d0 f2 e4 e8 6e
+ %% e4 03 bc
+ %%
+ %% iv info (12 octets): 00 0c 08 74 6c 73 31 33 20 69 76 00
+ %%
+ %% iv expanded (12 octets): 5d 31 3e b2 67 12 76 ee 13 00 0b 30
+
+ %% PRK = SHSTrafficSecret
+ WriteKeyInfo =
+ hexstr2bin("00 10 09 74 6c 73 31 33 20 6b 65 79 00"),
+
+ WriteKey =
+ hexstr2bin("3f ce 51 60 09 c2 17 27 d0 f2 e4 e8 6e e4 03 bc"),
+
+ WriteIVInfo =
+ hexstr2bin("00 0c 08 74 6c 73 31 33 20 69 76 00"),
+
+ WriteIV =
+ hexstr2bin(" 5d 31 3e b2 67 12 76 ee 13 00 0b 30"),
+
+ Cipher = aes_128_gcm, %% TODO: get from ServerHello
+
+ WriteKeyInfo = tls_v1:create_info(<<"key">>, <<>>, ssl_cipher:key_material(Cipher)),
+ %% TODO: remove hardcoded IV size
+ WriteIVInfo = tls_v1:create_info(<<"iv">>, <<>>, 12),
+
+ {WriteKey, WriteIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, SHSTrafficSecret),
+
+ %% {server} construct an EncryptedExtensions handshake message:
+ %%
+ %% EncryptedExtensions (40 octets): 08 00 00 24 00 22 00 0a 00 14 00
+ %% 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 1c
+ %% 00 02 40 01 00 00 00 00
+ %%
+ %% {server} construct a Certificate handshake message:
+ %%
+ %% Certificate (445 octets): 0b 00 01 b9 00 00 01 b5 00 01 b0 30 82
+ %% 01 ac 30 82 01 15 a0 03 02 01 02 02 01 02 30 0d 06 09 2a 86 48
+ %% 86 f7 0d 01 01 0b 05 00 30 0e 31 0c 30 0a 06 03 55 04 03 13 03
+ %% 72 73 61 30 1e 17 0d 31 36 30 37 33 30 30 31 32 33 35 39 5a 17
+ %% 0d 32 36 30 37 33 30 30 31 32 33 35 39 5a 30 0e 31 0c 30 0a 06
+ %% 03 55 04 03 13 03 72 73 61 30 81 9f 30 0d 06 09 2a 86 48 86 f7
+ %% 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 b4 bb 49 8f
+ %% 82 79 30 3d 98 08 36 39 9b 36 c6 98 8c 0c 68 de 55 e1 bd b8 26
+ %% d3 90 1a 24 61 ea fd 2d e4 9a 91 d0 15 ab bc 9a 95 13 7a ce 6c
+ %% 1a f1 9e aa 6a f9 8c 7c ed 43 12 09 98 e1 87 a8 0e e0 cc b0 52
+ %% 4b 1b 01 8c 3e 0b 63 26 4d 44 9a 6d 38 e2 2a 5f da 43 08 46 74
+ %% 80 30 53 0e f0 46 1c 8c a9 d9 ef bf ae 8e a6 d1 d0 3e 2b d1 93
+ %% ef f0 ab 9a 80 02 c4 74 28 a6 d3 5a 8d 88 d7 9f 7f 1e 3f 02 03
+ %% 01 00 01 a3 1a 30 18 30 09 06 03 55 1d 13 04 02 30 00 30 0b 06
+ %% 03 55 1d 0f 04 04 03 02 05 a0 30 0d 06 09 2a 86 48 86 f7 0d 01
+ %% 01 0b 05 00 03 81 81 00 85 aa d2 a0 e5 b9 27 6b 90 8c 65 f7 3a
+ %% 72 67 17 06 18 a5 4c 5f 8a 7b 33 7d 2d f7 a5 94 36 54 17 f2 ea
+ %% e8 f8 a5 8c 8f 81 72 f9 31 9c f3 6b 7f d6 c5 5b 80 f2 1a 03 01
+ %% 51 56 72 60 96 fd 33 5e 5e 67 f2 db f1 02 70 2e 60 8c ca e6 be
+ %% c1 fc 63 a4 2a 99 be 5c 3e b7 10 7c 3c 54 e9 b9 eb 2b d5 20 3b
+ %% 1c 3b 84 e0 a8 b2 f7 59 40 9b a3 ea c9 d9 1d 40 2d cc 0c c8 f8
+ %% 96 12 29 ac 91 87 b4 2b 4d e1 00 00
+ %%
+ %% {server} construct a CertificateVerify handshake message:
+ %%
+ %% CertificateVerify (136 octets): 0f 00 00 84 08 04 00 80 5a 74 7c
+ %% 5d 88 fa 9b d2 e5 5a b0 85 a6 10 15 b7 21 1f 82 4c d4 84 14 5a
+ %% b3 ff 52 f1 fd a8 47 7b 0b 7a bc 90 db 78 e2 d3 3a 5c 14 1a 07
+ %% 86 53 fa 6b ef 78 0c 5e a2 48 ee aa a7 85 c4 f3 94 ca b6 d3 0b
+ %% be 8d 48 59 ee 51 1f 60 29 57 b1 54 11 ac 02 76 71 45 9e 46 44
+ %% 5c 9e a5 8c 18 1e 81 8e 95 b8 c3 fb 0b f3 27 84 09 d3 be 15 2a
+ %% 3d a5 04 3e 06 3d da 65 cd f5 ae a2 0d 53 df ac d4 2f 74 f3
+ EncryptedExtensions =
+ hexstr2bin("08 00 00 24 00 22 00 0a 00 14 00
+ 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 1c
+ 00 02 40 01 00 00 00 00"),
+
+ Certificate =
+ hexstr2bin("0b 00 01 b9 00 00 01 b5 00 01 b0 30 82
+ 01 ac 30 82 01 15 a0 03 02 01 02 02 01 02 30 0d 06 09 2a 86 48
+ 86 f7 0d 01 01 0b 05 00 30 0e 31 0c 30 0a 06 03 55 04 03 13 03
+ 72 73 61 30 1e 17 0d 31 36 30 37 33 30 30 31 32 33 35 39 5a 17
+ 0d 32 36 30 37 33 30 30 31 32 33 35 39 5a 30 0e 31 0c 30 0a 06
+ 03 55 04 03 13 03 72 73 61 30 81 9f 30 0d 06 09 2a 86 48 86 f7
+ 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 b4 bb 49 8f
+ 82 79 30 3d 98 08 36 39 9b 36 c6 98 8c 0c 68 de 55 e1 bd b8 26
+ d3 90 1a 24 61 ea fd 2d e4 9a 91 d0 15 ab bc 9a 95 13 7a ce 6c
+ 1a f1 9e aa 6a f9 8c 7c ed 43 12 09 98 e1 87 a8 0e e0 cc b0 52
+ 4b 1b 01 8c 3e 0b 63 26 4d 44 9a 6d 38 e2 2a 5f da 43 08 46 74
+ 80 30 53 0e f0 46 1c 8c a9 d9 ef bf ae 8e a6 d1 d0 3e 2b d1 93
+ ef f0 ab 9a 80 02 c4 74 28 a6 d3 5a 8d 88 d7 9f 7f 1e 3f 02 03
+ 01 00 01 a3 1a 30 18 30 09 06 03 55 1d 13 04 02 30 00 30 0b 06
+ 03 55 1d 0f 04 04 03 02 05 a0 30 0d 06 09 2a 86 48 86 f7 0d 01
+ 01 0b 05 00 03 81 81 00 85 aa d2 a0 e5 b9 27 6b 90 8c 65 f7 3a
+ 72 67 17 06 18 a5 4c 5f 8a 7b 33 7d 2d f7 a5 94 36 54 17 f2 ea
+ e8 f8 a5 8c 8f 81 72 f9 31 9c f3 6b 7f d6 c5 5b 80 f2 1a 03 01
+ 51 56 72 60 96 fd 33 5e 5e 67 f2 db f1 02 70 2e 60 8c ca e6 be
+ c1 fc 63 a4 2a 99 be 5c 3e b7 10 7c 3c 54 e9 b9 eb 2b d5 20 3b
+ 1c 3b 84 e0 a8 b2 f7 59 40 9b a3 ea c9 d9 1d 40 2d cc 0c c8 f8
+ 96 12 29 ac 91 87 b4 2b 4d e1 00 00"),
+
+ CertificateVerify =
+ hexstr2bin("0f 00 00 84 08 04 00 80 5a 74 7c
+ 5d 88 fa 9b d2 e5 5a b0 85 a6 10 15 b7 21 1f 82 4c d4 84 14 5a
+ b3 ff 52 f1 fd a8 47 7b 0b 7a bc 90 db 78 e2 d3 3a 5c 14 1a 07
+ 86 53 fa 6b ef 78 0c 5e a2 48 ee aa a7 85 c4 f3 94 ca b6 d3 0b
+ be 8d 48 59 ee 51 1f 60 29 57 b1 54 11 ac 02 76 71 45 9e 46 44
+ 5c 9e a5 8c 18 1e 81 8e 95 b8 c3 fb 0b f3 27 84 09 d3 be 15 2a
+ 3d a5 04 3e 06 3d da 65 cd f5 ae a2 0d 53 df ac d4 2f 74 f3"),
+
+ %% {server} calculate finished "tls13 finished":
+ %%
+ %% PRK (32 octets): b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d 37 b4
+ %% e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38
+ %%
+ %% hash (0 octets): (empty)
+ %%
+ %% info (18 octets): 00 20 0e 74 6c 73 31 33 20 66 69 6e 69 73 68 65
+ %% 64 00
+ %%
+ %% expanded (32 octets): 00 8d 3b 66 f8 16 ea 55 9f 96 b5 37 e8 85
+ %% c3 1f c0 68 bf 49 2c 65 2f 01 f2 88 a1 d8 cd c1 9f c8
+ %%
+ %% finished (32 octets): 9b 9b 14 1d 90 63 37 fb d2 cb dc e7 1d f4
+ %% de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07 18
+
+ %% PRK = SHSTrafficSecret
+ FInfo =
+ hexstr2bin("00 20 0e 74 6c 73 31 33 20 66 69 6e 69 73 68 65
+ 64 00"),
+
+ FExpanded =
+ hexstr2bin("00 8d 3b 66 f8 16 ea 55 9f 96 b5 37 e8 85
+ c3 1f c0 68 bf 49 2c 65 2f 01 f2 88 a1 d8 cd c1 9f c8"),
+
+ FinishedVerifyData =
+ hexstr2bin("9b 9b 14 1d 90 63 37 fb d2 cb dc e7 1d f4
+ de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07 18"),
+
+ FInfo = tls_v1:create_info(<<"finished">>, <<>>, ssl_cipher:hash_size(HKDFAlgo)),
+
+ FExpanded = tls_v1:finished_key(SHSTrafficSecret, HKDFAlgo),
+
+ MessageHistory0 = [CertificateVerify,
+ Certificate,
+ EncryptedExtensions,
+ ServerHello,
+ ClientHello],
+
+ FinishedVerifyData = tls_v1:finished_verify_data(FExpanded, HKDFAlgo, MessageHistory0),
+
+ %% {server} construct a Finished handshake message:
+ %%
+ %% Finished (36 octets): 14 00 00 20 9b 9b 14 1d 90 63 37 fb d2 cb
+ %% dc e7 1d f4 de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07
+ %% 18
+ FinishedHSBin =
+ hexstr2bin("14 00 00 20 9b 9b 14 1d 90 63 37 fb d2 cb
+ dc e7 1d f4 de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07
+ 18"),
+
+ FinishedHS = #finished{verify_data = FinishedVerifyData},
+
+ FinishedIOList = tls_handshake:encode_handshake(FinishedHS, {3,4}),
+ FinishedHSBin = iolist_to_binary(FinishedIOList),
+
+ %% {server} derive secret "tls13 c ap traffic":
+ %%
+ %% PRK (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47
+ %% 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19
+ %%
+ %% hash (32 octets): 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a
+ %% 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13
+ %%
+ %% info (54 octets): 00 20 12 74 6c 73 31 33 20 63 20 61 70 20 74 72
+ %% 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b
+ %% 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13
+ %%
+ %% expanded (32 octets): 9e 40 64 6c e7 9a 7f 9d c0 5a f8 88 9b ce
+ %% 65 52 87 5a fa 0b 06 df 00 87 f7 92 eb b7 c1 75 04 a5
+
+ %% PRK = MasterSecret
+ CAPTHash =
+ hexstr2bin("96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a
+ 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"),
+ CAPTInfo =
+ hexstr2bin("00 20 12 74 6c 73 31 33 20 63 20 61 70 20 74 72
+ 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b
+ 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"),
+
+ CAPTrafficSecret =
+ hexstr2bin("9e 40 64 6c e7 9a 7f 9d c0 5a f8 88 9b ce
+ 65 52 87 5a fa 0b 06 df 00 87 f7 92 eb b7 c1 75 04 a5"),
+
+ CHSF = <<ClientHello/binary,
+ ServerHello/binary,
+ EncryptedExtensions/binary,
+ Certificate/binary,
+ CertificateVerify/binary,
+ FinishedHSBin/binary>>,
+
+ CAPTHash = crypto:hash(HKDFAlgo, CHSF),
+
+ CAPTInfo =
+ tls_v1:create_info(<<"c ap traffic">>, CAPTHash, ssl_cipher:hash_size(HKDFAlgo)),
+
+ CAPTrafficSecret =
+ tls_v1:client_application_traffic_secret_0(HKDFAlgo, {master_secret, MasterSecret}, CHSF),
+
+ %% {server} derive secret "tls13 s ap traffic":
+ %%
+ %% PRK (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47
+ %% 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19
+ %%
+ %% hash (32 octets): 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a
+ %% 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13
+ %%
+ %% info (54 octets): 00 20 12 74 6c 73 31 33 20 73 20 61 70 20 74 72
+ %% 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b
+ %% 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13
+ %%
+ %% expanded (32 octets): a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9
+ %% 50 32 82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43
+
+ %% PRK = MasterSecret
+ %% hash = CAPTHash
+ SAPTInfo =
+ hexstr2bin(" 00 20 12 74 6c 73 31 33 20 73 20 61 70 20 74 72
+ 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b
+ 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"),
+
+ SAPTrafficSecret =
+ hexstr2bin("a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9
+ 50 32 82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43"),
+
+ SAPTInfo =
+ tls_v1:create_info(<<"s ap traffic">>, CAPTHash, ssl_cipher:hash_size(HKDFAlgo)),
+
+ SAPTrafficSecret =
+ tls_v1:server_application_traffic_secret_0(HKDFAlgo, {master_secret, MasterSecret}, CHSF),
+
+ %% {server} derive secret "tls13 exp master":
+ %%
+ %% PRK (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47
+ %% 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19
+ %%
+ %% hash (32 octets): 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a
+ %% 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13
+ %%
+ %% info (52 octets): 00 20 10 74 6c 73 31 33 20 65 78 70 20 6d 61 73
+ %% 74 65 72 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a 00
+ %% 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13
+ %%
+ %% expanded (32 octets): fe 22 f8 81 17 6e da 18 eb 8f 44 52 9e 67
+ %% 92 c5 0c 9a 3f 89 45 2f 68 d8 ae 31 1b 43 09 d3 cf 50
+
+ %% PRK = MasterSecret
+ %% hash = CAPTHash
+ ExporterInfo =
+ hexstr2bin("00 20 10 74 6c 73 31 33 20 65 78 70 20 6d 61 73
+ 74 65 72 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a 00
+ 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"),
+
+ ExporterMasterSecret =
+ hexstr2bin("fe 22 f8 81 17 6e da 18 eb 8f 44 52 9e 67
+ 92 c5 0c 9a 3f 89 45 2f 68 d8 ae 31 1b 43 09 d3 cf 50"),
+
+ ExporterInfo =
+ tls_v1:create_info(<<"exp master">>, CAPTHash, ssl_cipher:hash_size(HKDFAlgo)),
+
+ ExporterMasterSecret =
+ tls_v1:exporter_master_secret(HKDFAlgo, {master_secret, MasterSecret}, CHSF),
+
+ %% {server} derive write traffic keys for application data:
+ %%
+ %% PRK (32 octets): a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9 50 32
+ %% 82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43
+ %%
+ %% key info (13 octets): 00 10 09 74 6c 73 31 33 20 6b 65 79 00
+ %%
+ %% key expanded (16 octets): 9f 02 28 3b 6c 9c 07 ef c2 6b b9 f2 ac
+ %% 92 e3 56
+ %%
+ %% iv info (12 octets): 00 0c 08 74 6c 73 31 33 20 69 76 00
+ %%
+ %% iv expanded (12 octets): cf 78 2b 88 dd 83 54 9a ad f1 e9 84
+
+ %% PRK = SAPTrafficsecret
+ %% key info = WriteKeyInfo
+ %% iv info = WrtieIVInfo
+ SWKey =
+ hexstr2bin("9f 02 28 3b 6c 9c 07 ef c2 6b b9 f2 ac 92 e3 56"),
+
+ SWIV =
+ hexstr2bin("cf 78 2b 88 dd 83 54 9a ad f1 e9 84"),
+
+ {SWKey, SWIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, SAPTrafficSecret),
+
+ %% {server} derive read traffic keys for handshake data:
+ %%
+ %% PRK (32 octets): b3 ed db 12 6e 06 7f 35 a7 80 b3 ab f4 5e 2d 8f
+ %% 3b 1a 95 07 38 f5 2e 96 00 74 6a 0e 27 a5 5a 21
+ %%
+ %% key info (13 octets): 00 10 09 74 6c 73 31 33 20 6b 65 79 00
+ %%
+ %% key expanded (16 octets): db fa a6 93 d1 76 2c 5b 66 6a f5 d9 50
+ %% 25 8d 01
+ %%
+ %% iv info (12 octets): 00 0c 08 74 6c 73 31 33 20 69 76 00
+ %%
+ %% iv expanded (12 octets): 5b d3 c7 1b 83 6e 0b 76 bb 73 26 5f
+
+ %% PRK = CHSTrafficsecret
+ %% key info = WriteKeyInfo
+ %% iv info = WrtieIVInfo
+ SRKey =
+ hexstr2bin("db fa a6 93 d1 76 2c 5b 66 6a f5 d9 50 25 8d 01"),
+
+ SRIV =
+ hexstr2bin("5b d3 c7 1b 83 6e 0b 76 bb 73 26 5f"),
+
+ {SRKey, SRIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, CHSTrafficSecret).
+
+
+tls13_finished_verify_data() ->
+ [{doc,"Test TLS 1.3 Finished message handling"}].
+
+tls13_finished_verify_data(_Config) ->
+ ClientHello =
+ hexstr2bin("01 00 00 c6 03 03 00 01 02 03 04 05 06 07 08 09
+ 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19
+ 1a 1b 1c 1d 1e 1f 20 e0 e1 e2 e3 e4 e5 e6 e7 e8
+ e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8
+ f9 fa fb fc fd fe ff 00 06 13 01 13 02 13 03 01
+ 00 00 77 00 00 00 18 00 16 00 00 13 65 78 61 6d
+ 70 6c 65 2e 75 6c 66 68 65 69 6d 2e 6e 65 74 00
+ 0a 00 08 00 06 00 1d 00 17 00 18 00 0d 00 14 00
+ 12 04 03 08 04 04 01 05 03 08 05 05 01 08 06 06
+ 01 02 01 00 33 00 26 00 24 00 1d 00 20 35 80 72
+ d6 36 58 80 d1 ae ea 32 9a df 91 21 38 38 51 ed
+ 21 a2 8e 3b 75 e9 65 d0 d2 cd 16 62 54 00 2d 00
+ 02 01 01 00 2b 00 03 02 03 04"),
+
+ ServerHello =
+ hexstr2bin("02 00 00 76 03 03 70 71 72 73 74 75 76 77 78 79
+ 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89
+ 8a 8b 8c 8d 8e 8f 20 e0 e1 e2 e3 e4 e5 e6 e7 e8
+ e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8
+ f9 fa fb fc fd fe ff 13 01 00 00 2e 00 33 00 24
+ 00 1d 00 20 9f d7 ad 6d cf f4 29 8d d3 f9 6d 5b
+ 1b 2a f9 10 a0 53 5b 14 88 d7 f8 fa bb 34 9a 98
+ 28 80 b6 15 00 2b 00 02 03 04"),
+
+ EncryptedExtensions =
+ hexstr2bin("08 00 00 02 00 00"),
+
+ Certificate =
+ hexstr2bin("0b 00 03 2e 00 00 03 2a 00 03 25 30 82 03 21 30
+ 82 02 09 a0 03 02 01 02 02 08 15 5a 92 ad c2 04
+ 8f 90 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05
+ 00 30 22 31 0b 30 09 06 03 55 04 06 13 02 55 53
+ 31 13 30 11 06 03 55 04 0a 13 0a 45 78 61 6d 70
+ 6c 65 20 43 41 30 1e 17 0d 31 38 31 30 30 35 30
+ 31 33 38 31 37 5a 17 0d 31 39 31 30 30 35 30 31
+ 33 38 31 37 5a 30 2b 31 0b 30 09 06 03 55 04 06
+ 13 02 55 53 31 1c 30 1a 06 03 55 04 03 13 13 65
+ 78 61 6d 70 6c 65 2e 75 6c 66 68 65 69 6d 2e 6e
+ 65 74 30 82 01 22 30 0d 06 09 2a 86 48 86 f7 0d
+ 01 01 01 05 00 03 82 01 0f 00 30 82 01 0a 02 82
+ 01 01 00 c4 80 36 06 ba e7 47 6b 08 94 04 ec a7
+ b6 91 04 3f f7 92 bc 19 ee fb 7d 74 d7 a8 0d 00
+ 1e 7b 4b 3a 4a e6 0f e8 c0 71 fc 73 e7 02 4c 0d
+ bc f4 bd d1 1d 39 6b ba 70 46 4a 13 e9 4a f8 3d
+ f3 e1 09 59 54 7b c9 55 fb 41 2d a3 76 52 11 e1
+ f3 dc 77 6c aa 53 37 6e ca 3a ec be c3 aa b7 3b
+ 31 d5 6c b6 52 9c 80 98 bc c9 e0 28 18 e2 0b f7
+ f8 a0 3a fd 17 04 50 9e ce 79 bd 9f 39 f1 ea 69
+ ec 47 97 2e 83 0f b5 ca 95 de 95 a1 e6 04 22 d5
+ ee be 52 79 54 a1 e7 bf 8a 86 f6 46 6d 0d 9f 16
+ 95 1a 4c f7 a0 46 92 59 5c 13 52 f2 54 9e 5a fb
+ 4e bf d7 7a 37 95 01 44 e4 c0 26 87 4c 65 3e 40
+ 7d 7d 23 07 44 01 f4 84 ff d0 8f 7a 1f a0 52 10
+ d1 f4 f0 d5 ce 79 70 29 32 e2 ca be 70 1f df ad
+ 6b 4b b7 11 01 f4 4b ad 66 6a 11 13 0f e2 ee 82
+ 9e 4d 02 9d c9 1c dd 67 16 db b9 06 18 86 ed c1
+ ba 94 21 02 03 01 00 01 a3 52 30 50 30 0e 06 03
+ 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 03
+ 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 03
+ 02 06 08 2b 06 01 05 05 07 03 01 30 1f 06 03 55
+ 1d 23 04 18 30 16 80 14 89 4f de 5b cc 69 e2 52
+ cf 3e a3 00 df b1 97 b8 1d e1 c1 46 30 0d 06 09
+ 2a 86 48 86 f7 0d 01 01 0b 05 00 03 82 01 01 00
+ 59 16 45 a6 9a 2e 37 79 e4 f6 dd 27 1a ba 1c 0b
+ fd 6c d7 55 99 b5 e7 c3 6e 53 3e ff 36 59 08 43
+ 24 c9 e7 a5 04 07 9d 39 e0 d4 29 87 ff e3 eb dd
+ 09 c1 cf 1d 91 44 55 87 0b 57 1d d1 9b df 1d 24
+ f8 bb 9a 11 fe 80 fd 59 2b a0 39 8c de 11 e2 65
+ 1e 61 8c e5 98 fa 96 e5 37 2e ef 3d 24 8a fd e1
+ 74 63 eb bf ab b8 e4 d1 ab 50 2a 54 ec 00 64 e9
+ 2f 78 19 66 0d 3f 27 cf 20 9e 66 7f ce 5a e2 e4
+ ac 99 c7 c9 38 18 f8 b2 51 07 22 df ed 97 f3 2e
+ 3e 93 49 d4 c6 6c 9e a6 39 6d 74 44 62 a0 6b 42
+ c6 d5 ba 68 8e ac 3a 01 7b dd fc 8e 2c fc ad 27
+ cb 69 d3 cc dc a2 80 41 44 65 d3 ae 34 8c e0 f3
+ 4a b2 fb 9c 61 83 71 31 2b 19 10 41 64 1c 23 7f
+ 11 a5 d6 5c 84 4f 04 04 84 99 38 71 2b 95 9e d6
+ 85 bc 5c 5d d6 45 ed 19 90 94 73 40 29 26 dc b4
+ 0e 34 69 a1 59 41 e8 e2 cc a8 4b b6 08 46 36 a0
+ 00 00"),
+
+ CertificateVerify =
+ hexstr2bin("0f 00 01 04 08 04 01 00 17 fe b5 33 ca 6d 00 7d
+ 00 58 25 79 68 42 4b bc 3a a6 90 9e 9d 49 55 75
+ 76 a5 20 e0 4a 5e f0 5f 0e 86 d2 4f f4 3f 8e b8
+ 61 ee f5 95 22 8d 70 32 aa 36 0f 71 4e 66 74 13
+ 92 6e f4 f8 b5 80 3b 69 e3 55 19 e3 b2 3f 43 73
+ df ac 67 87 06 6d cb 47 56 b5 45 60 e0 88 6e 9b
+ 96 2c 4a d2 8d ab 26 ba d1 ab c2 59 16 b0 9a f2
+ 86 53 7f 68 4f 80 8a ef ee 73 04 6c b7 df 0a 84
+ fb b5 96 7a ca 13 1f 4b 1c f3 89 79 94 03 a3 0c
+ 02 d2 9c bd ad b7 25 12 db 9c ec 2e 5e 1d 00 e5
+ 0c af cf 6f 21 09 1e bc 4f 25 3c 5e ab 01 a6 79
+ ba ea be ed b9 c9 61 8f 66 00 6b 82 44 d6 62 2a
+ aa 56 88 7c cf c6 6a 0f 38 51 df a1 3a 78 cf f7
+ 99 1e 03 cb 2c 3a 0e d8 7d 73 67 36 2e b7 80 5b
+ 00 b2 52 4f f2 98 a4 da 48 7c ac de af 8a 23 36
+ c5 63 1b 3e fa 93 5b b4 11 e7 53 ca 13 b0 15 fe
+ c7 e4 a7 30 f1 36 9f 9e"),
+
+ BaseKey =
+ hexstr2bin("a2 06 72 65 e7 f0 65 2a 92 3d 5d 72 ab 04 67 c4
+ 61 32 ee b9 68 b6 a3 2d 31 1c 80 58 68 54 88 14"),
+
+ VerifyData =
+ hexstr2bin("ea 6e e1 76 dc cc 4a f1 85 9e 9e 4e 93 f7 97 ea
+ c9 a7 8c e4 39 30 1e 35 27 5a d4 3f 3c dd bd e3"),
+
+ Messages = [CertificateVerify,
+ Certificate,
+ EncryptedExtensions,
+ ServerHello,
+ ClientHello],
+
+ FinishedKey = tls_v1:finished_key(BaseKey, sha256),
+ VerifyData = tls_v1:finished_verify_data(FinishedKey, sha256, Messages).
+
+tls13_basic_ssl_server_openssl_client() ->
+ [{doc,"Test TLS 1.3 basic connection between ssl server and openssl s_client"}].
+
+tls13_basic_ssl_server_openssl_client(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ServerOpts0],
+ {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
+
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+tls13_custom_groups_ssl_server_openssl_client() ->
+ [{doc,"Test that ssl server can select a common group for key-exchange"}].
+
+tls13_custom_groups_ssl_server_openssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups, [x448, secp256r1, secp384r1]}|ServerOpts0],
+ {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ ClientOpts = [{groups,"P-384:P-256:X25519"}|ClientOpts0],
+ Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
+
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+tls13_hello_retry_request_ssl_server_openssl_client() ->
+ [{doc,"Test that ssl server can request a new group when the client's first key share"
+ "is not supported"}].
+
+tls13_hello_retry_request_ssl_server_openssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups, [x448, x25519]}|ServerOpts0],
+ {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ ClientOpts = [{groups,"P-256:X25519"}|ClientOpts0],
+ Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
+
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+tls13_client_auth_empty_cert_alert_ssl_server_openssl_client() ->
+ [{doc,"TLS 1.3: Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to true."}].
+
+tls13_client_auth_empty_cert_alert_ssl_server_openssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ %% Delete Client Cert and Key
+ ClientOpts1 = proplists:delete(certfile, ClientOpts0),
+ ClientOpts = proplists:delete(keyfile, ClientOpts1),
+
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {fail_if_no_peer_cert, true}|ServerOpts0],
+ {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
+
+ ssl_test_lib:check_result(Server,
+ {error,
+ {tls_alert,
+ {certificate_required,
+ "received SERVER ALERT: Fatal - Certificate required - certificate_required"}}}),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+tls13_client_auth_empty_cert_ssl_server_openssl_client() ->
+ [{doc,"TLS 1.3: Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to false."}].
+
+tls13_client_auth_empty_cert_ssl_server_openssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ %% Delete Client Cert and Key
+ ClientOpts1 = proplists:delete(certfile, ClientOpts0),
+ ClientOpts = proplists:delete(keyfile, ClientOpts1),
+
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {fail_if_no_peer_cert, false}|ServerOpts0],
+ {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
+
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
+tls13_client_auth_ssl_server_openssl_client() ->
+ [{doc,"TLS 1.3: Test client authentication."}].
+
+tls13_client_auth_ssl_server_openssl_client(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {fail_if_no_peer_cert, true}|ServerOpts0],
+ {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
+
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
+tls13_hrr_client_auth_empty_cert_alert_ssl_server_openssl_client() ->
+ [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to true."}].
+
+tls13_hrr_client_auth_empty_cert_alert_ssl_server_openssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ %% Delete Client Cert and Key
+ ClientOpts1 = proplists:delete(certfile, ClientOpts0),
+ ClientOpts2 = proplists:delete(keyfile, ClientOpts1),
+ ClientOpts = [{groups,"P-256:X25519"}|ClientOpts2],
+
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {fail_if_no_peer_cert, true},
+ {supported_groups, [x448, x25519]}|ServerOpts0],
+ {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
+
+ ssl_test_lib:check_result(Server,
+ {error,
+ {tls_alert,
+ {certificate_required,
+ "received SERVER ALERT: Fatal - Certificate required - certificate_required"}}}),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
+tls13_hrr_client_auth_empty_cert_ssl_server_openssl_client() ->
+ [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to false."}].
+
+tls13_hrr_client_auth_empty_cert_ssl_server_openssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ %% Delete Client Cert and Key
+ ClientOpts1 = proplists:delete(certfile, ClientOpts0),
+ ClientOpts2 = proplists:delete(keyfile, ClientOpts1),
+ ClientOpts = [{groups,"P-256:X25519"}|ClientOpts2],
+
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {fail_if_no_peer_cert, false},
+ {supported_groups, [x448, x25519]}|ServerOpts0],
+ {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
+
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
+tls13_hrr_client_auth_ssl_server_openssl_client() ->
+ [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication."}].
+
+tls13_hrr_client_auth_ssl_server_openssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ClientOpts = [{groups,"P-256:X25519"}|ClientOpts0],
+
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {fail_if_no_peer_cert, true},
+ {supported_groups, [x448, x25519]}|ServerOpts0],
+ {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
+
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
+tls13_unsupported_sign_algo_client_auth_ssl_server_openssl_client() ->
+ [{doc,"TLS 1.3: Test client authentication with unsupported signature_algorithm"}].
+
+tls13_unsupported_sign_algo_client_auth_ssl_server_openssl_client(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ %% Skip rsa_pkcs1_sha256!
+ {signature_algs, [rsa_pkcs1_sha384, rsa_pkcs1_sha512]},
+ {fail_if_no_peer_cert, true}|ServerOpts0],
+ {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
+
+ ssl_test_lib:check_result(
+ Server,
+ {error,
+ {tls_alert,
+ {insufficient_security,
+ "received SERVER ALERT: Fatal - Insufficient Security - "
+ "\"No suitable signature algorithm\""}}}),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
+%% Triggers Client Alert as openssl s_client does not have a certificate with a
+%% signature algorithm supported by the server (signature_algorithms_cert extension
+%% of CertificateRequest does not contain the algorithm of the client certificate).
+tls13_unsupported_sign_algo_cert_client_auth_ssl_server_openssl_client() ->
+ [{doc,"TLS 1.3: Test client authentication with unsupported signature_algorithm_cert"}].
+
+tls13_unsupported_sign_algo_cert_client_auth_ssl_server_openssl_client(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {log_level, debug},
+ {verify, verify_peer},
+ {signature_algs, [rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pss_rsae_sha256]},
+ %% Skip rsa_pkcs1_sha256!
+ {signature_algs_cert, [rsa_pkcs1_sha384, rsa_pkcs1_sha512]},
+ {fail_if_no_peer_cert, true}|ServerOpts0],
+ {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
+
+ ssl_test_lib:check_result(
+ Server,
+ {error,
+ {tls_alert,
+ {illegal_parameter,
+ "received CLIENT ALERT: Fatal - Illegal Parameter"}}}),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
+tls13_connection_information() ->
+ [{doc,"Test the API function ssl:connection_information/1 in a TLS 1.3 connection"}].
+
+tls13_connection_information(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ServerOpts0],
+ {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, connection_information_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
+
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
@@ -4197,8 +5665,8 @@ tcp_send_recv_result(Socket) ->
ok.
basic_verify_test_no_close(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -4341,19 +5809,24 @@ recv_close(Socket) ->
send_recv_result_active_rizzo(Socket) ->
ssl:send(Socket, "Hello world"),
- receive
- {ssl, Socket, "H"} ->
- receive
- {ssl, Socket, "ello world"} ->
- ok
- end
- end.
+ "Hello world" = ssl_test_lib:active_recv(Socket, 11),
+ ok.
send_recv_result_active_no_rizzo(Socket) ->
ssl:send(Socket, "Hello world"),
+ "Hello world" = ssl_test_lib:active_recv(Socket, 11),
+ ok.
+
+
+ssl_active_recv(N) ->
+ ssl_active_recv(N, []).
+
+ssl_active_recv(0, Acc) ->
+ Acc;
+ssl_active_recv(N, Acc) ->
receive
- {ssl, Socket, "Hello world"} ->
- ok
+ {ssl, _, Bytes} ->
+ ssl_active_recv(N-length(Bytes), Acc ++ Bytes)
end.
result_ok(_Socket) ->
@@ -4377,16 +5850,7 @@ renegotiate_reuse_session(Socket, Data) ->
renegotiate(Socket, Data).
renegotiate_immediately(Socket) ->
- receive
- {ssl, Socket, "Hello world"} ->
- ok;
- %% Handle 1/n-1 splitting countermeasure Rizzo/Duong-Beast
- {ssl, Socket, "H"} ->
- receive
- {ssl, Socket, "ello world"} ->
- ok
- end
- end,
+ _ = ssl_test_lib:active_recv(Socket, 11),
ok = ssl:renegotiate(Socket),
{error, renegotiation_rejected} = ssl:renegotiate(Socket),
ct:sleep(?RENEGOTIATION_DISABLE_TIME + ?SLEEP),
@@ -4396,16 +5860,7 @@ renegotiate_immediately(Socket) ->
ok.
renegotiate_rejected(Socket) ->
- receive
- {ssl, Socket, "Hello world"} ->
- ok;
- %% Handle 1/n-1 splitting countermeasure Rizzo/Duong-Beast
- {ssl, Socket, "H"} ->
- receive
- {ssl, Socket, "ello world"} ->
- ok
- end
- end,
+ _ = ssl_test_lib:active_recv(Socket, 11),
{error, renegotiation_rejected} = ssl:renegotiate(Socket),
{error, renegotiation_rejected} = ssl:renegotiate(Socket),
ct:sleep(?RENEGOTIATION_DISABLE_TIME +1),
@@ -4580,17 +6035,11 @@ session_loop(Sess) ->
erlang_ssl_receive(Socket, Data) ->
- receive
- {ssl, Socket, Data} ->
- io:format("Received ~p~n",[Data]),
- ok;
- {ssl, Socket, Byte} when length(Byte) == 1 -> %% Handle 1/n-1 splitting countermeasure Rizzo/Duong-Beast
- io:format("Received ~p~n",[Byte]),
- erlang_ssl_receive(Socket, tl(Data));
- Other ->
- ct:fail({unexpected_message, Other})
- after timer:seconds(?SEC_RENEGOTIATION_TIMEOUT) * test_server:timetrap_scale_factor() ->
- ct:fail({did_not_get, Data})
+ case ssl_test_lib:active_recv(Socket, length(Data)) of
+ Data ->
+ ok;
+ Other ->
+ ct:fail({{expected, Data}, {got, Other}})
end.
receive_msg(_) ->
@@ -4607,28 +6056,6 @@ controlling_process_result(Socket, Pid, Msg) ->
ssl:send(Socket, Msg),
no_result_msg.
-receive_s_rizzo_duong_beast() ->
- receive
- {ssl, _, "erver hello"} ->
- receive
- {ssl, _, "C"} ->
- receive
- {ssl, _, "lient hello"} ->
- ok
- end
- end
- end.
-receive_c_rizzo_duong_beast() ->
- receive
- {ssl, _, "lient hello"} ->
- receive
- {ssl, _, "S"} ->
- receive
- {ssl, _, "erver hello"} ->
- ok
- end
- end
- end.
controller_dies_result(_Socket, _Pid, _Msg) ->
receive Result -> Result end.
@@ -4708,129 +6135,6 @@ client_server_opts(#{key_exchange := KeyAlgo}, Config) when KeyAlgo == ecdh_rsa
{ssl_test_lib:ssl_options(client_opts, Config),
ssl_test_lib:ssl_options(server_ecdh_rsa_opts, Config)}.
-run_suites(Ciphers, Config, Type) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Version = ssl_test_lib:protocol_version(Config),
- ct:log("Running cipher suites ~p~n", [Ciphers]),
- {ClientOpts, ServerOpts} =
- case Type of
- rsa ->
- {ssl_test_lib:ssl_options(client_verification_opts, Config),
- ssl_test_lib:ssl_options(server_verification_opts, Config)};
- dsa ->
- {ssl_test_lib:ssl_options(client_verification_opts, Config),
- ssl_test_lib:ssl_options(server_dsa_opts, Config)};
- anonymous ->
- %% No certs in opts!
- {ssl_test_lib:ssl_options(client_verification_opts, Config),
- [{reuseaddr, true}, {ciphers, ssl_test_lib:anonymous_suites(NVersion)} |
- ssl_test_lib:ssl_options([], Config)]};
- psk ->
- {ssl_test_lib:ssl_options(client_psk, Config),
- [{ciphers, ssl_test_lib:psk_suites(NVersion)} |
- ssl_test_lib:ssl_options(server_psk, Config)]};
- psk_with_hint ->
- {ssl_test_lib:ssl_options(client_psk, Config),
- [{ciphers, ssl_test_lib:psk_suites(NVersion)} |
- ssl_test_lib:ssl_options(server_psk_hint, Config)
- ]};
- psk_anon ->
- {ssl_test_lib:ssl_options(client_psk, Config),
- [{ciphers, ssl_test_lib:psk_anon_suites(NVersion)} |
- ssl_test_lib:ssl_options(server_psk_anon, Config)]};
- psk_anon_with_hint ->
- {ssl_test_lib:ssl_options(client_psk, Config),
- [{ciphers, ssl_test_lib:psk_anon_suites(NVersion)} |
- ssl_test_lib:ssl_options(server_psk_anon_hint, Config)]};
- srp ->
- {ssl_test_lib:ssl_options(client_srp, Config),
- ssl_test_lib:ssl_options(server_srp, Config)};
- srp_anon ->
- {ssl_test_lib:ssl_options(client_srp, Config),
- ssl_test_lib:ssl_options(server_srp_anon, Config)};
- srp_dsa ->
- {ssl_test_lib:ssl_options(client_srp_dsa, Config),
- ssl_test_lib:ssl_options(server_srp_dsa, Config)};
- ecdsa ->
- {ssl_test_lib:ssl_options(client_verification_opts, Config),
- ssl_test_lib:ssl_options(server_ecdsa_opts, Config)};
- ecdh_rsa ->
- {ssl_test_lib:ssl_options(client_verification_opts, Config),
- ssl_test_lib:ssl_options(server_ecdh_rsa_opts, Config)};
- rc4_rsa ->
- {ssl_test_lib:ssl_options(client_verification_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_verification_opts, Config)]};
- rc4_ecdh_rsa ->
- {ssl_test_lib:ssl_options(client_verification_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_ecdh_rsa_opts, Config)]};
- rc4_ecdsa ->
- {ssl_test_lib:ssl_options(client_verification_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_ecdsa_opts, Config)]};
- des_dhe_rsa ->
- {ssl_test_lib:ssl_options(client_verification_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_verification_opts, Config)]};
- des_rsa ->
- {ssl_test_lib:ssl_options(client_verification_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_verification_opts, Config)]}
- end,
-
- Result = lists:map(fun(Cipher) ->
- cipher(Cipher, Version, Config, ClientOpts, ServerOpts) end,
- ssl_test_lib:filter_suites(Ciphers, Version)),
- case lists:flatten(Result) of
- [] ->
- ok;
- Error ->
- ct:log("Cipher suite errors: ~p~n", [Error]),
- ct:fail(cipher_suite_failed_see_test_case_log)
- end.
-
-erlang_cipher_suite(Suite) when is_list(Suite)->
- ssl_cipher:erl_suite_definition(ssl_cipher:openssl_suite(Suite));
-erlang_cipher_suite(Suite) ->
- Suite.
-
-cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
- %% process_flag(trap_exit, true),
- ct:log("Testing CipherSuite ~p~n", [CipherSuite]),
- ct:log("Server Opts ~p~n", [ServerOpts]),
- ct:log("Client Opts ~p~n", [ClientOpts]),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- ErlangCipherSuite = erlang_cipher_suite(CipherSuite),
-
- ConnectionInfo = {ok, {Version, ErlangCipherSuite}},
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}},
- {options,
- [{ciphers,[CipherSuite]} |
- ClientOpts]}]),
-
- Result = ssl_test_lib:wait_for_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client),
-
- case Result of
- ok ->
- [];
- Error ->
- [{ErlangCipherSuite, Error}]
- end.
-
connection_information_result(Socket) ->
{ok, Info = [_ | _]} = ssl:connection_information(Socket),
case length(Info) > 3 of
@@ -4843,8 +6147,13 @@ connection_information_result(Socket) ->
end.
connection_info_result(Socket) ->
- {ok, Info} = ssl:connection_information(Socket, [protocol, cipher_suite]),
- {ok, {proplists:get_value(protocol, Info), proplists:get_value(cipher_suite, Info)}}.
+ {ok, Info} = ssl:connection_information(Socket, [protocol, selected_cipher_suite]),
+ {ok, {proplists:get_value(protocol, Info), proplists:get_value(selected_cipher_suite, Info)}}.
+
+protocol_info_result(Socket) ->
+ {ok, [{protocol, PVersion}]} = ssl:connection_information(Socket, [protocol]),
+ {ok, PVersion}.
+
version_info_result(Socket) ->
{ok, [{version, Version}]} = ssl:connection_information(Socket, [version]),
{ok, Version}.
@@ -4863,23 +6172,28 @@ connect_dist_c(S) ->
{ok, Test} = ssl:recv(S, 0, 10000),
ok.
-tls_downgrade_result(Socket) ->
+tls_downgrade_result(Socket, Pid) ->
ok = ssl_test_lib:send_recv_result(Socket),
+ Pid ! {self(), ready},
+ receive
+ go ->
+ ok
+ end,
case ssl:close(Socket, {self(), 10000}) of
{ok, TCPSocket} ->
- inet:setopts(TCPSocket, [{active, true}]),
+ inet:setopts(TCPSocket, [{active, true}]),
gen_tcp:send(TCPSocket, "Downgraded"),
- receive
- {tcp, TCPSocket, <<"Downgraded">>} ->
- ok;
- {tcp_closed, TCPSocket} ->
- ct:pal("Peer timed out, downgrade aborted"),
- ok;
- Other ->
- {error, Other}
- end;
+ receive
+ {tcp, TCPSocket, <<"Downgraded">>} ->
+ ok;
+ {tcp_closed, TCPSocket} ->
+ ct:fail("Peer timed out, downgrade aborted"),
+ ok;
+ Other ->
+ {error, Other}
+ end;
{error, timeout} ->
- ct:pal("Timed out, downgrade aborted"),
+ ct:fail("Timed out, downgrade aborted"),
ok;
Fail ->
{error, Fail}
@@ -4887,8 +6201,14 @@ tls_downgrade_result(Socket) ->
tls_close(Socket) ->
ok = ssl_test_lib:send_recv_result(Socket),
- ok = ssl:close(Socket, 5000).
-
+ case ssl:close(Socket, 5000) of
+ ok ->
+ ok;
+ {error, closed} ->
+ ok;
+ Other ->
+ ct:fail(Other)
+ end.
%% First two clauses handles 1/n-1 splitting countermeasure Rizzo/Duong-Beast
treashold(N, {3,0}) ->
@@ -4904,14 +6224,14 @@ get_invalid_inet_option(Socket) ->
tls_shutdown_result(Socket, server) ->
ssl:send(Socket, "Hej"),
- ssl:shutdown(Socket, write),
+ ok = ssl:shutdown(Socket, write),
{ok, "Hej hopp"} = ssl:recv(Socket, 8),
ok;
tls_shutdown_result(Socket, client) ->
- {ok, "Hej"} = ssl:recv(Socket, 3),
ssl:send(Socket, "Hej hopp"),
- ssl:shutdown(Socket, write),
+ ok = ssl:shutdown(Socket, write),
+ {ok, "Hej"} = ssl:recv(Socket, 3),
ok.
tls_shutdown_write_result(Socket, server) ->
@@ -4967,20 +6287,6 @@ try_recv_active_once(Socket) ->
{error, einval} = ssl:recv(Socket, 11),
ok.
-first_rsa_suite([{ecdhe_rsa, _, _} = Suite | _]) ->
- Suite;
-first_rsa_suite([{dhe_rsa, _, _} = Suite| _]) ->
- Suite;
-first_rsa_suite([{rsa, _, _} = Suite| _]) ->
- Suite;
-first_rsa_suite([{ecdhe_rsa, _, _, _} = Suite | _]) ->
- Suite;
-first_rsa_suite([{dhe_rsa, _, _, _} = Suite| _]) ->
- Suite;
-first_rsa_suite([{rsa, _, _, _} = Suite| _]) ->
- Suite;
-first_rsa_suite([_ | Rest]) ->
- first_rsa_suite(Rest).
wait_for_send(Socket) ->
%% Make sure TLS process processed send message event
@@ -4992,3 +6298,31 @@ tls_or_dtls('dtlsv1.2') ->
dtls;
tls_or_dtls(_) ->
tls.
+
+hexstr2int(S) ->
+ B = hexstr2bin(S),
+ Bits = size(B) * 8,
+ <<Integer:Bits/integer>> = B,
+ Integer.
+
+hexstr2bin(S) when is_binary(S) ->
+ hexstr2bin(S, <<>>);
+hexstr2bin(S) ->
+ hexstr2bin(list_to_binary(S), <<>>).
+%%
+hexstr2bin(<<>>, Acc) ->
+ Acc;
+hexstr2bin(<<C,T/binary>>, Acc) when C =:= 32; %% SPACE
+ C =:= 10; %% LF
+ C =:= 13 -> %% CR
+ hexstr2bin(T, Acc);
+hexstr2bin(<<X,Y,T/binary>>, Acc) ->
+ I = hex2int(X) * 16 + hex2int(Y),
+ hexstr2bin(T, <<Acc/binary,I>>).
+
+hex2int(C) when $0 =< C, C =< $9 ->
+ C - $0;
+hex2int(C) when $A =< C, C =< $F ->
+ C - $A + 10;
+hex2int(C) when $a =< C, C =< $f ->
+ C - $a + 10.
diff --git a/lib/ssl/test/ssl_bench.spec b/lib/ssl/test/ssl_bench.spec
index d2f75b4203..217cc6fc83 100644
--- a/lib/ssl/test/ssl_bench.spec
+++ b/lib/ssl/test/ssl_bench.spec
@@ -1 +1,2 @@
-{suites,"../ssl_test",[ssl_bench_SUITE]}.
+{suites,"../ssl_test",[ssl_bench_SUITE, ssl_dist_bench_SUITE]}.
+{skip_groups,"../ssl_test",ssl_bench_SUITE,basic,"Benchmarks run separately"}.
diff --git a/lib/ssl/test/ssl_bench_SUITE.erl b/lib/ssl/test/ssl_bench_SUITE.erl
index ae2928b1c3..35efa2b8a3 100644
--- a/lib/ssl/test/ssl_bench_SUITE.erl
+++ b/lib/ssl/test/ssl_bench_SUITE.erl
@@ -25,10 +25,11 @@
suite() -> [{ct_hooks,[{ts_install_cth,[{nodenames,2}]}]}].
-all() -> [{group, setup}, {group, payload}, {group, pem_cache}].
+all() -> [{group, basic}, {group, setup}, {group, payload}, {group, pem_cache}].
groups() ->
- [{setup, [{repeat, 3}], [setup_sequential, setup_concurrent]},
+ [{basic, [], [basic_pem_cache]},
+ {setup, [{repeat, 3}], [setup_sequential, setup_concurrent]},
{payload, [{repeat, 3}], [payload_simple]},
{pem_cache, [{repeat, 3}], [use_pem_cache, bypass_pem_cache]}
].
@@ -40,39 +41,33 @@ end_per_group(_GroupName, _Config) ->
ok.
init_per_suite(Config) ->
- try
- Server = setup(ssl, node()),
- [{server_node, Server}|Config]
- catch _:_ ->
- {skipped, "Benchmark machines only"}
+ ct:timetrap({minutes, 1}),
+ case node() of
+ nonode@nohost ->
+ {skipped, "Node not distributed"};
+ _ ->
+ ssl_test_lib:clean_start(),
+ [{server_node, ssl_bench_test_lib:setup(perf_server)}|Config]
end.
end_per_suite(_Config) ->
ok.
-init_per_testcase(use_pem_cache, Conf) ->
+init_per_testcase(TC, Conf) when TC =:= use_pem_cache;
+ TC =:= bypass_pem_cache;
+ TC =:= basic_pem_cache ->
case bypass_pem_cache_supported() of
false -> {skipped, "PEM cache bypass support required"};
true ->
application:set_env(ssl, bypass_pem_cache, false),
Conf
end;
-init_per_testcase(bypass_pem_cache, Conf) ->
- case bypass_pem_cache_supported() of
- false -> {skipped, "PEM cache bypass support required"};
- true ->
- application:set_env(ssl, bypass_pem_cache, true),
- Conf
- end;
init_per_testcase(_Func, Conf) ->
Conf.
-end_per_testcase(use_pem_cache, _Config) ->
- case bypass_pem_cache_supported() of
- false -> ok;
- true -> application:set_env(ssl, bypass_pem_cache, false)
- end;
-end_per_testcase(bypass_pem_cache, _Config) ->
+end_per_testcase(TC, _Config) when TC =:= use_pem_cache;
+ TC =:= bypass_pem_cache;
+ TC =:= basic_pem_cache ->
case bypass_pem_cache_supported() of
false -> ok;
true -> application:set_env(ssl, bypass_pem_cache, false)
@@ -118,6 +113,9 @@ payload_simple(Config) ->
{suite, "ssl"}, {name, "Payload simple"}]}),
ok.
+basic_pem_cache(_Config) ->
+ do_test(ssl, pem_cache, 10, 5, node()).
+
use_pem_cache(_Config) ->
{ok, Result} = do_test(ssl, pem_cache, 100, 500, node()),
ct_event:notify(#event{name = benchmark_data,
@@ -132,10 +130,10 @@ bypass_pem_cache(_Config) ->
ssl() ->
- test(ssl, ?COUNT, node()).
+ test(ssl, ?COUNT).
-test(Type, Count, Host) ->
- Server = setup(Type, Host),
+test(Type, Count) ->
+ Server = ssl_bench_test_lib:setup(perf_server),
(do_test(Type, setup_connection, Count * 20, 1, Server)),
(do_test(Type, setup_connection, Count, 100, Server)),
(do_test(Type, payload, Count*300, 10, Server)),
@@ -166,7 +164,7 @@ do_test(Type, TC, Loop, ParallellConnections, Server) ->
end
end,
Spawn = fun(Id) ->
- Pid = spawn(fun() -> Test(Id) end),
+ Pid = spawn_link(fun() -> Test(Id) end),
receive {Pid, init} -> Pid end
end,
Pids = [Spawn(Id) || Id <- lists:seq(ParallellConnections, 1, -1)],
@@ -183,42 +181,42 @@ do_test(Type, TC, Loop, ParallellConnections, Server) ->
{ok, TestPerSecond}.
server_init(ssl, setup_connection, _, _, Server) ->
- {ok, Socket} = ssl:listen(0, ssl_opts(listen)),
- {ok, {_Host, Port}} = ssl:sockname(Socket),
+ {ok, LSocket} = ssl:listen(0, ssl_opts(listen)),
+ {ok, {_Host, Port}} = ssl:sockname(LSocket),
{ok, Host} = inet:gethostname(),
?FPROF_SERVER andalso start_profile(fprof, [whereis(ssl_manager), new]),
%%?EPROF_SERVER andalso start_profile(eprof, [ssl_connection_sup, ssl_manager]),
?EPROF_SERVER andalso start_profile(eprof, [ssl_manager]),
Server ! {self(), {init, Host, Port}},
Test = fun(TSocket) ->
- ok = ssl:ssl_accept(TSocket),
- ssl:close(TSocket)
+ {ok, Socket} = ssl:handshake(TSocket),
+ ssl:close(Socket)
end,
- setup_server_connection(Socket, Test);
+ setup_server_connection(LSocket, Test);
server_init(ssl, payload, Loop, _, Server) ->
- {ok, Socket} = ssl:listen(0, ssl_opts(listen)),
- {ok, {_Host, Port}} = ssl:sockname(Socket),
+ {ok, LSocket} = ssl:listen(0, ssl_opts(listen)),
+ {ok, {_Host, Port}} = ssl:sockname(LSocket),
{ok, Host} = inet:gethostname(),
Server ! {self(), {init, Host, Port}},
Test = fun(TSocket) ->
- ok = ssl:ssl_accept(TSocket),
+ {ok, Socket} = ssl:handshake(TSocket),
Size = byte_size(msg()),
- server_echo(TSocket, Size, Loop),
- ssl:close(TSocket)
+ server_echo(Socket, Size, Loop),
+ ssl:close(Socket)
end,
- setup_server_connection(Socket, Test);
+ setup_server_connection(LSocket, Test);
server_init(ssl, pem_cache, Loop, _, Server) ->
- {ok, Socket} = ssl:listen(0, ssl_opts(listen_der)),
- {ok, {_Host, Port}} = ssl:sockname(Socket),
+ {ok, LSocket} = ssl:listen(0, ssl_opts(listen_der)),
+ {ok, {_Host, Port}} = ssl:sockname(LSocket),
{ok, Host} = inet:gethostname(),
Server ! {self(), {init, Host, Port}},
Test = fun(TSocket) ->
- ok = ssl:ssl_accept(TSocket),
+ {ok, Socket} = ssl:handshake(TSocket),
Size = byte_size(msg()),
- server_echo(TSocket, Size, Loop),
- ssl:close(TSocket)
+ server_echo(Socket, Size, Loop),
+ ssl:close(Socket)
end,
- setup_server_connection(Socket, Test);
+ setup_server_connection(LSocket, Test);
server_init(Type, Tc, _, _, Server) ->
io:format("No server init code for ~p ~p~n",[Type, Tc]),
@@ -294,47 +292,6 @@ msg() ->
"asdlkjsafsdfoierwlejsdlkfjsdf">>.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-setup(_Type, nonode@nohost) ->
- exit(dist_not_enabled);
-setup(Type, _This) ->
- Host = case os:getenv(?remote_host) of
- false ->
- {ok, This} = inet:gethostname(),
- This;
- RemHost ->
- RemHost
- end,
- Node = list_to_atom("perf_server@" ++ Host),
- SlaveArgs = case init:get_argument(pa) of
- {ok, PaPaths} ->
- lists:append([" -pa " ++ P || [P] <- PaPaths]);
- _ -> []
- end,
- %% io:format("Slave args: ~p~n",[SlaveArgs]),
- Prog =
- case os:find_executable("erl") of
- false -> "erl";
- P -> P
- end,
- io:format("Prog = ~p~n", [Prog]),
-
- case net_adm:ping(Node) of
- pong -> ok;
- pang ->
- {ok, Node} = slave:start(Host, perf_server, SlaveArgs, no_link, Prog)
- end,
- Path = code:get_path(),
- true = rpc:call(Node, code, set_path, [Path]),
- ok = rpc:call(Node, ?MODULE, setup_server, [Type, node()]),
- io:format("Client (~p) using ~s~n",[node(), code:which(ssl)]),
- (Node =:= node()) andalso restrict_schedulers(client),
- Node.
-
-setup_server(_Type, ClientNode) ->
- (ClientNode =:= node()) andalso restrict_schedulers(server),
- io:format("Server (~p) using ~s~n",[node(), code:which(ssl)]),
- ok.
-
ensure_all_started(App, Ack) ->
case application:start(App) of
@@ -358,13 +315,6 @@ setup_server_init(Type, Tc, Loop, PC) ->
unlink(Pid),
Res.
-restrict_schedulers(Type) ->
- %% We expect this to run on 8 core machine
- Extra0 = 1,
- Extra = if (Type =:= server) -> -Extra0; true -> Extra0 end,
- Scheds = erlang:system_info(schedulers),
- erlang:system_flag(schedulers_online, (Scheds div 2) + Extra).
-
tc(Fun, Mod, Line) ->
case timer:tc(Fun) of
{_,{'EXIT',Reason}} ->
diff --git a/lib/ssl/test/ssl_bench_test_lib.erl b/lib/ssl/test/ssl_bench_test_lib.erl
new file mode 100644
index 0000000000..47bcd41608
--- /dev/null
+++ b/lib/ssl/test/ssl_bench_test_lib.erl
@@ -0,0 +1,75 @@
+%%%-------------------------------------------------------------------
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(ssl_bench_test_lib).
+
+%% API
+-export([setup/1]).
+
+%% Internal exports
+-export([setup_server/1]).
+
+-define(remote_host, "NETMARKS_REMOTE_HOST").
+
+setup(Name) ->
+ Host = case os:getenv(?remote_host) of
+ false ->
+ {ok, This} = inet:gethostname(),
+ This;
+ RemHost ->
+ RemHost
+ end,
+ Node = list_to_atom(atom_to_list(Name) ++ "@" ++ Host),
+ SlaveArgs = case init:get_argument(pa) of
+ {ok, PaPaths} ->
+ lists:append([" -pa " ++ P || [P] <- PaPaths]);
+ _ -> []
+ end,
+ %% io:format("Slave args: ~p~n",[SlaveArgs]),
+ Prog =
+ case os:find_executable("erl") of
+ false -> "erl";
+ P -> P
+ end,
+ io:format("Prog = ~p~n", [Prog]),
+
+ case net_adm:ping(Node) of
+ pong -> ok;
+ pang ->
+ {ok, Node} =
+ slave:start(Host, Name, SlaveArgs, no_link, Prog)
+ end,
+ Path = code:get_path(),
+ true = rpc:call(Node, code, set_path, [Path]),
+ ok = rpc:call(Node, ?MODULE, setup_server, [node()]),
+ io:format("Client (~p) using ~ts~n",[node(), code:which(ssl)]),
+ (Node =:= node()) andalso restrict_schedulers(client),
+ Node.
+
+setup_server(ClientNode) ->
+ (ClientNode =:= node()) andalso restrict_schedulers(server),
+ io:format("Server (~p) using ~ts~n",[node(), code:which(ssl)]),
+ ok.
+
+restrict_schedulers(Type) ->
+ %% We expect this to run on 8 core machine
+ Extra0 = 1,
+ Extra = if (Type =:= server) -> -Extra0; true -> Extra0 end,
+ Scheds = erlang:system_info(schedulers),
+ erlang:system_flag(schedulers_online, (Scheds div 2) + Extra).
diff --git a/lib/ssl/test/ssl_certificate_verify_SUITE.erl b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
index 0bc265fa10..55dee9a48f 100644
--- a/lib/ssl/test/ssl_certificate_verify_SUITE.erl
+++ b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -40,14 +40,22 @@
%%--------------------------------------------------------------------
all() ->
[
- {group, tls},
- {group, dtls}
+ {group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}
].
groups() ->
[
- {tls, [], all_protocol_groups()},
- {dtls, [], all_protocol_groups()},
+ {'tlsv1.2', [], all_protocol_groups()},
+ {'tlsv1.1', [], all_protocol_groups()},
+ {'tlsv1', [], all_protocol_groups()},
+ {'sslv3', [], all_protocol_groups()},
+ {'dtlsv1.2', [], all_protocol_groups()},
+ {'dtlsv1', [], all_protocol_groups()},
{active, [], tests()},
{active_once, [], tests()},
{passive, [], tests()},
@@ -65,6 +73,7 @@ tests() ->
verify_none,
server_require_peer_cert_ok,
server_require_peer_cert_fail,
+ server_require_peer_cert_empty_ok,
server_require_peer_cert_partial_chain,
server_require_peer_cert_allow_partial_chain,
server_require_peer_cert_do_not_allow_partial_chain,
@@ -78,7 +87,10 @@ tests() ->
extended_key_usage_verify_server,
critical_extension_verify_client,
critical_extension_verify_server,
- critical_extension_verify_none].
+ critical_extension_verify_none,
+ customize_hostname_check,
+ incomplete_chain
+ ].
error_handling_tests()->
[client_with_cert_cipher_suites_handshake,
@@ -104,24 +116,6 @@ end_per_suite(_Config) ->
ssl:stop(),
application:stop(crypto).
-init_per_group(tls, Config0) ->
- Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
- ssl:stop(),
- application:load(ssl),
- application:set_env(ssl, protocol_version, Version),
- ssl:start(),
- Config = ssl_test_lib:init_tls_version(Version, Config0),
- [{version, tls_record:protocol_version(Version)} | Config];
-
-init_per_group(dtls, Config0) ->
- Version = dtls_record:protocol_version(dtls_record:highest_protocol_version([])),
- ssl:stop(),
- application:load(ssl),
- application:set_env(ssl, protocol_version, Version),
- ssl:start(),
- Config = ssl_test_lib:init_tls_version(Version, Config0),
- [{version, dtls_record:protocol_version(Version)} | Config];
-
init_per_group(active, Config) ->
[{active, true}, {receive_function, send_recv_result_active} | Config];
init_per_group(active_once, Config) ->
@@ -130,20 +124,30 @@ init_per_group(passive, Config) ->
[{active, false}, {receive_function, send_recv_result} | Config];
init_per_group(error_handling, Config) ->
[{active, false}, {receive_function, send_recv_result} | Config];
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:sufficient_crypto_support(GroupName) of
+ true ->
+ [{version, GroupName} | ssl_test_lib:init_tls_version(GroupName, Config)];
+ false ->
+ {skip, "Missing crypto support"}
+ end
+ end.
-init_per_group(_, Config) ->
- Config.
-
-end_per_group(GroupName, Config) when GroupName == tls;
- GroupName == dtls ->
- ssl_test_lib:clean_tls_version(Config);
-end_per_group(_GroupName, Config) ->
- Config.
+end_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:clean_tls_version(Config);
+ false ->
+ Config
+ end.
init_per_testcase(_TestCase, Config) ->
ssl:stop(),
ssl:start(),
ssl_test_lib:ct_log_supported_protocol_versions(Config),
+ ct:pal(" ~p", [ dtls_record:supported_protocol_versions()]),
ct:timetrap({seconds, 10}),
Config.
@@ -295,15 +299,37 @@ server_require_peer_cert_fail(Config) when is_list(Config) ->
{host, Hostname},
{from, self()},
{options, [{active, Active} | BadClientOpts]}]),
- receive
- {Server, {error, {tls_alert, "handshake failure"}}} ->
- receive
- {Client, {error, {tls_alert, "handshake failure"}}} ->
- ok;
- {Client, {error, closed}} ->
- ok
- end
- end.
+
+ ssl_test_lib:check_server_alert(Server, Client, handshake_failure).
+
+%%--------------------------------------------------------------------
+server_require_peer_cert_empty_ok() ->
+ [{doc,"Test server option fail_if_no_peer_cert when peer sends cert"}].
+
+server_require_peer_cert_empty_ok(Config) when is_list(Config) ->
+ ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, false}
+ | ssl_test_lib:ssl_options(server_rsa_opts, Config)],
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ Active = proplists:get_value(active, Config),
+ ReceiveFunction = proplists:get_value(receive_function, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ ClientOpts = proplists:delete(keyfile, proplists:delete(certfile, ClientOpts0)),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, ReceiveFunction, []}},
+ {options, [{active, Active} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, ReceiveFunction, []}},
+ {options, [{active, Active} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
@@ -333,15 +359,8 @@ server_require_peer_cert_partial_chain(Config) when is_list(Config) ->
{options, [{active, Active},
{cacerts, [RootCA]} |
proplists:delete(cacertfile, ClientOpts)]}]),
- receive
- {Server, {error, {tls_alert, "unknown ca"}}} ->
- receive
- {Client, {error, {tls_alert, "unknown ca"}}} ->
- ok;
- {Client, {error, closed}} ->
- ok
- end
- end.
+ ssl_test_lib:check_server_alert(Server, Client, unknown_ca).
+
%%--------------------------------------------------------------------
server_require_peer_cert_allow_partial_chain() ->
[{doc, "Server trusts intermediat CA and accepts a partial chain. (partial_chain option)"}].
@@ -414,17 +433,7 @@ server_require_peer_cert_do_not_allow_partial_chain(Config) when is_list(Config)
{from, self()},
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
-
- receive
- {Server, {error, {tls_alert, "unknown ca"}}} ->
- receive
- {Client, {error, {tls_alert, "unknown ca"}}} ->
- ok;
- {Client, {error, closed}} ->
- ok
- end
- end.
-
+ ssl_test_lib:check_server_alert(Server, Client, unknown_ca).
%%--------------------------------------------------------------------
server_require_peer_cert_partial_chain_fun_fail() ->
[{doc, "If parial_chain fun crashes, treat it as if it returned unkown_ca"}].
@@ -439,7 +448,7 @@ server_require_peer_cert_partial_chain_fun_fail(Config) when is_list(Config) ->
[{_,_,_}, {_, IntermidiateCA, _} | _] = public_key:pem_decode(ServerCAs),
PartialChain = fun(_CertChain) ->
- ture = false %% crash on purpose
+ true = false %% crash on purpose
end,
Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
@@ -455,16 +464,7 @@ server_require_peer_cert_partial_chain_fun_fail(Config) when is_list(Config) ->
{from, self()},
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
-
- receive
- {Server, {error, {tls_alert, "unknown ca"}}} ->
- receive
- {Client, {error, {tls_alert, "unknown ca"}}} ->
- ok;
- {Client, {error, closed}} ->
- ok
- end
- end.
+ ssl_test_lib:check_server_alert(Server, Client, unknown_ca).
%%--------------------------------------------------------------------
verify_fun_always_run_client() ->
@@ -482,7 +482,7 @@ verify_fun_always_run_client(Config) when is_list(Config) ->
Port = ssl_test_lib:inet_port(Server),
%% If user verify fun is called correctly we fail the connection.
- %% otherwise we can not tell this case apart form where we miss
+ %% otherwise we cannot tell this case apart form where we miss
%% to call users verify fun
FunAndState = {fun(_,{extension, _}, UserState) ->
{unknown, UserState};
@@ -503,14 +503,8 @@ verify_fun_always_run_client(Config) when is_list(Config) ->
[{verify, verify_peer},
{verify_fun, FunAndState}
| ClientOpts]}]),
- %% Server error may be {tls_alert,"handshake failure"} or closed depending on timing
- %% this is not a bug it is a circumstance of how tcp works!
- receive
- {Server, ServerError} ->
- ct:log("Server Error ~p~n", [ServerError])
- end,
- ssl_test_lib:check_result(Client, {error, {tls_alert, "handshake failure"}}).
+ ssl_test_lib:check_client_alert(Server, Client, handshake_failure).
%%--------------------------------------------------------------------
verify_fun_always_run_server() ->
@@ -521,7 +515,7 @@ verify_fun_always_run_server(Config) when is_list(Config) ->
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
%% If user verify fun is called correctly we fail the connection.
- %% otherwise we can not tell this case apart form where we miss
+ %% otherwise we cannot tell this case apart form where we miss
%% to call users verify fun
FunAndState = {fun(_,{extension, _}, UserState) ->
{unknown, UserState};
@@ -549,16 +543,8 @@ verify_fun_always_run_server(Config) when is_list(Config) ->
{mfa, {ssl_test_lib,
no_result, []}},
{options, ClientOpts}]),
-
- %% Client error may be {tls_alert, "handshake failure" } or closed depending on timing
- %% this is not a bug it is a circumstance of how tcp works!
- receive
- {Client, ClientError} ->
- ct:log("Client Error ~p~n", [ClientError])
- end,
-
- ssl_test_lib:check_result(Server, {error, {tls_alert, "handshake failure"}}).
-
+
+ ssl_test_lib:check_client_alert(Server, Client, handshake_failure).
%%--------------------------------------------------------------------
cert_expired() ->
@@ -588,8 +574,7 @@ cert_expired(Config) when is_list(Config) ->
{from, self()},
{options, [{verify, verify_peer}, {active, Active} | ClientOpts]}]),
- tcp_delivery_workaround(Server, {error, {tls_alert, "certificate expired"}},
- Client, {error, {tls_alert, "certificate expired"}}).
+ ssl_test_lib:check_client_alert(Server, Client, certificate_expired).
two_digits_str(N) when N < 10 ->
lists:flatten(io_lib:format("0~p", [N]));
@@ -695,12 +680,8 @@ critical_extension_verify_server(Config) when is_list(Config) ->
{options, [{verify, verify_none}, {active, Active} | ClientOpts]}]),
%% This certificate has a critical extension that we don't
- %% understand. Therefore, verification should fail.
-
- tcp_delivery_workaround(Server, {error, {tls_alert, "unsupported certificate"}},
- Client, {error, {tls_alert, "unsupported certificate"}}),
-
- ssl_test_lib:close(Server).
+ %% understand. Therefore, verification should fail.
+ ssl_test_lib:check_server_alert(Server, Client, unsupported_certificate).
%%--------------------------------------------------------------------
critical_extension_verify_client() ->
@@ -731,12 +712,7 @@ critical_extension_verify_client(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, ReceiveFunction, []}},
{options, [{verify, verify_peer}, {active, Active} | ClientOpts]}]),
- %% This certificate has a critical extension that we don't
- %% understand. Therefore, verification should fail.
- ssl_test_lib:check_result(Server, {error, {tls_alert, "unsupported certificate"}},
- Client, {error, {tls_alert, "unsupported certificate"}}),
-
- ssl_test_lib:close(Server).
+ ssl_test_lib:check_client_alert(Server, Client, unsupported_certificate).
%%--------------------------------------------------------------------
critical_extension_verify_none() ->
@@ -876,10 +852,7 @@ invalid_signature_server(Config) when is_list(Config) ->
{host, Hostname},
{from, self()},
{options, [{verify, verify_peer} | ClientOpts]}]),
-
- tcp_delivery_workaround(Server, {error, {tls_alert, "unknown ca"}},
- Client, {error, {tls_alert, "unknown ca"}}).
-
+ ssl_test_lib:check_server_alert(Server, Client, unknown_ca).
%%--------------------------------------------------------------------
invalid_signature_client() ->
@@ -914,9 +887,7 @@ invalid_signature_client(Config) when is_list(Config) ->
{from, self()},
{options, NewClientOpts}]),
- tcp_delivery_workaround(Server, {error, {tls_alert, "unknown ca"}},
- Client, {error, {tls_alert, "unknown ca"}}).
-
+ ssl_test_lib:check_client_alert(Server, Client, unknown_ca).
%%--------------------------------------------------------------------
@@ -930,6 +901,7 @@ client_with_cert_cipher_suites_handshake(Config) when is_list(Config) ->
Config, "_sign_only_extensions"),
ClientOpts = ssl_test_lib:ssl_options(ClientOpts0, Config),
ServerOpts = ssl_test_lib:ssl_options(ServerOpts0, Config),
+ TLSVersion = ssl_test_lib:protocol_version(Config, tuple),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
@@ -938,7 +910,7 @@ client_with_cert_cipher_suites_handshake(Config) when is_list(Config) ->
send_recv_result_active, []}},
{options, [{active, true},
{ciphers,
- ssl_test_lib:rsa_non_signed_suites(proplists:get_value(version, Config))}
+ ssl_test_lib:rsa_non_signed_suites(TLSVersion)}
| ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
@@ -1001,16 +973,7 @@ unknown_server_ca_fail(Config) when is_list(Config) ->
[{verify, verify_peer},
{verify_fun, FunAndState}
| ClientOpts]}]),
- receive
- {Client, {error, {tls_alert, "unknown ca"}}} ->
- receive
- {Server, {error, {tls_alert, "unknown ca"}}} ->
- ok;
- {Server, {error, closed}} ->
- ok
- end
- end.
-
+ ssl_test_lib:check_client_alert(Server, Client, unknown_ca).
%%--------------------------------------------------------------------
unknown_server_ca_accept_verify_none() ->
@@ -1115,44 +1078,87 @@ unknown_server_ca_accept_backwardscompatibility(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
+
+customize_hostname_check() ->
+ [{doc,"Test option customize_hostname_check."}].
+customize_hostname_check(Config) when is_list(Config) ->
+ Ext = [#'Extension'{extnID = ?'id-ce-subjectAltName',
+ extnValue = [{dNSName, "*.example.org"}],
+ critical = false}
+ ],
+ {ClientOpts0, ServerOpts0} = ssl_test_lib:make_rsa_cert_chains([{server_chain,
+ [[],
+ [],
+ [{extensions, Ext}]
+ ]}],
+ Config, "https_hostname_convention"),
+ ClientOpts = ssl_test_lib:ssl_options(ClientOpts0, Config),
+ ServerOpts = ssl_test_lib:ssl_options(ServerOpts0, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ CustomFun = public_key:pkix_verify_hostname_match_fun(https),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options,
+ [{server_name_indication, "other.example.org"},
+ {customize_hostname_check,
+ [{match_fun, CustomFun}]} | ClientOpts]
+ }]),
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
+
+ Client1 = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ClientOpts}
+ ]),
+ ssl_test_lib:check_client_alert(Server, Client1, handshake_failure).
+
+incomplete_chain() ->
+ [{doc,"Test option verify_peer"}].
+incomplete_chain(Config) when is_list(Config) ->
+ DefConf = ssl_test_lib:default_cert_chain_conf(),
+ CertChainConf = ssl_test_lib:gen_conf(rsa, rsa, DefConf, DefConf),
+ #{server_config := ServerConf,
+ client_config := ClientConf} = public_key:pkix_test_data(CertChainConf),
+ [ServerRoot| _] = ServerCas = proplists:get_value(cacerts, ServerConf),
+ ClientCas = proplists:get_value(cacerts, ClientConf),
+
+ Active = proplists:get_value(active, Config),
+ ReceiveFunction = proplists:get_value(receive_function, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, ReceiveFunction, []}},
+ {options, [{active, Active}, {verify, verify_peer},
+ {cacerts, [ServerRoot]} |
+ proplists:delete(cacerts, ServerConf)]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, ReceiveFunction, []}},
+ {options, [{active, Active},
+ {verify, verify_peer},
+ {cacerts, ServerCas ++ ClientCas} |
+ proplists:delete(cacerts, ClientConf)]}]),
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+
+%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
-tcp_delivery_workaround(Server, ServerMsg, Client, ClientMsg) ->
- receive
- {Server, ServerMsg} ->
- client_msg(Client, ClientMsg);
- {Client, ClientMsg} ->
- server_msg(Server, ServerMsg);
- {Client, {error,closed}} ->
- server_msg(Server, ServerMsg);
- {Server, {error,closed}} ->
- client_msg(Client, ClientMsg)
- end.
-
-client_msg(Client, ClientMsg) ->
- receive
- {Client, ClientMsg} ->
- ok;
- {Client, {error,closed}} ->
- ct:log("client got close"),
- ok;
- {Client, {error, Reason}} ->
- ct:log("client got econnaborted: ~p", [Reason]),
- ok;
- Unexpected ->
- ct:fail(Unexpected)
- end.
-server_msg(Server, ServerMsg) ->
- receive
- {Server, ServerMsg} ->
- ok;
- {Server, {error,closed}} ->
- ct:log("server got close"),
- ok;
- {Server, {error, Reason}} ->
- ct:log("server got econnaborted: ~p", [Reason]),
- ok;
- Unexpected ->
- ct:fail(Unexpected)
- end.
diff --git a/lib/ssl/test/ssl_cipher_suite_SUITE.erl b/lib/ssl/test/ssl_cipher_suite_SUITE.erl
new file mode 100644
index 0000000000..51788c29e7
--- /dev/null
+++ b/lib/ssl/test/ssl_cipher_suite_SUITE.erl
@@ -0,0 +1,759 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+-module(ssl_cipher_suite_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+all() ->
+ [
+ {group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}
+ ].
+
+groups() ->
+ [
+ {'tlsv1.2', [], kex()},
+ {'tlsv1.1', [], kex()},
+ {'tlsv1', [], kex()},
+ {'sslv3', [], kex()},
+ {'dtlsv1.2', [], kex()},
+ {'dtlsv1', [], kex()},
+ {dhe_rsa, [],[dhe_rsa_3des_ede_cbc,
+ dhe_rsa_aes_128_cbc,
+ dhe_rsa_aes_256_cbc,
+ dhe_rsa_chacha20_poly1305
+ ]},
+ {ecdhe_rsa, [], [ecdhe_rsa_3des_ede_cbc,
+ ecdhe_rsa_aes_128_cbc,
+ ecdhe_rsa_aes_128_gcm,
+ ecdhe_rsa_aes_256_cbc,
+ ecdhe_rsa_aes_256_gcm,
+ ecdhe_rsa_chacha20_poly1305
+ ]},
+ {ecdhe_ecdsa, [],[ecdhe_ecdsa_rc4_128,
+ ecdhe_ecdsa_3des_ede_cbc,
+ ecdhe_ecdsa_aes_128_cbc,
+ ecdhe_ecdsa_aes_128_gcm,
+ ecdhe_ecdsa_aes_256_cbc,
+ ecdhe_ecdsa_aes_256_gcm,
+ ecdhe_ecdsa_chacha20_poly1305
+ ]},
+ {rsa, [], [rsa_3des_ede_cbc,
+ rsa_aes_128_cbc,
+ rsa_aes_256_cbc,
+ rsa_rc4_128
+ ]},
+ {dhe_dss, [], [dhe_dss_3des_ede_cbc,
+ dhe_dss_aes_128_cbc,
+ dhe_dss_aes_256_cbc]},
+ {srp_rsa, [], [srp_rsa_3des_ede_cbc,
+ srp_rsa_aes_128_cbc,
+ srp_rsa_aes_256_cbc]},
+ {srp_dss, [], [srp_dss_3des_ede_cbc,
+ srp_dss_aes_128_cbc,
+ srp_dss_aes_256_cbc]},
+ {rsa_psk, [], [rsa_psk_3des_ede_cbc,
+ rsa_psk_rc4_128,
+ rsa_psk_aes_128_cbc,
+ rsa_psk_aes_256_cbc
+ ]},
+ {dh_anon, [], [dh_anon_rc4_128,
+ dh_anon_3des_ede_cbc,
+ dh_anon_aes_128_cbc,
+ dh_anon_aes_128_gcm,
+ dh_anon_aes_256_cbc,
+ dh_anon_aes_256_gcm]},
+ {ecdh_anon, [], [ecdh_anon_3des_ede_cbc,
+ ecdh_anon_aes_128_cbc,
+ ecdh_anon_aes_256_cbc
+ ]},
+ {srp_anon, [], [srp_anon_3des_ede_cbc,
+ srp_anon_aes_128_cbc,
+ srp_anon_aes_256_cbc]},
+ {psk, [], [psk_3des_ede_cbc,
+ psk_rc4_128,
+ psk_aes_128_cbc,
+ psk_aes_128_ccm,
+ psk_aes_128_ccm_8,
+ psk_aes_256_cbc,
+ psk_aes_256_ccm,
+ psk_aes_256_ccm_8
+ ]},
+ {dhe_psk, [], [dhe_psk_3des_ede_cbc,
+ dhe_psk_rc4_128,
+ dhe_psk_aes_128_cbc,
+ dhe_psk_aes_128_ccm,
+ dhe_psk_aes_128_ccm_8,
+ dhe_psk_aes_256_cbc,
+ dhe_psk_aes_256_ccm,
+ dhe_psk_aes_256_ccm_8
+ ]},
+ {ecdhe_psk, [], [ecdhe_psk_3des_ede_cbc,
+ ecdhe_psk_rc4_128,
+ ecdhe_psk_aes_128_cbc,
+ ecdhe_psk_aes_128_ccm,
+ ecdhe_psk_aes_128_ccm_8,
+ ecdhe_psk_aes_256_cbc
+ ]}
+ ].
+
+kex() ->
+ rsa() ++ ecdsa() ++ dss() ++ anonymous().
+
+rsa() ->
+ [{group, dhe_rsa},
+ {group, ecdhe_rsa},
+ {group, rsa},
+ {group, srp_rsa},
+ {group, rsa_psk}
+ ].
+
+ecdsa() ->
+ [{group, ecdhe_ecdsa}].
+
+dss() ->
+ [{group, dhe_dss},
+ {group, srp_dss}].
+
+anonymous() ->
+ [{group, dh_anon},
+ {group, ecdh_anon},
+ {group, psk},
+ {group, dhe_psk},
+ {group, ecdhe_psk},
+ {group, srp_anon}
+ ].
+
+init_per_suite(Config) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ Config
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto).
+
+
+init_per_group(GroupName, Config) when GroupName == ecdh_anon;
+ GroupName == ecdhe_rsa;
+ GroupName == ecdhe_psk ->
+ case proplists:get_bool(ecdh, proplists:get_value(public_keys, crypto:supports())) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing EC crypto support"}
+ end;
+init_per_group(ecdhe_ecdsa = GroupName, Config) ->
+ PKAlg = proplists:get_value(public_keys, crypto:supports()),
+ case lists:member(ecdh, PKAlg) andalso lists:member(ecdsa, PKAlg) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing EC crypto support"}
+ end;
+init_per_group(dhe_dss = GroupName, Config) ->
+ PKAlg = proplists:get_value(public_keys, crypto:supports()),
+ case lists:member(dss, PKAlg) andalso lists:member(dh, PKAlg) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing DSS crypto support"}
+ end;
+init_per_group(srp_dss = GroupName, Config) ->
+ PKAlg = proplists:get_value(public_keys, crypto:supports()),
+ case lists:member(dss, PKAlg) andalso lists:member(srp, PKAlg) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing DSS_SRP crypto support"}
+ end;
+init_per_group(GroupName, Config) when GroupName == srp_anon;
+ GroupName == srp_rsa ->
+ PKAlg = proplists:get_value(public_keys, crypto:supports()),
+ case lists:member(srp, PKAlg) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing SRP crypto support"}
+ end;
+init_per_group(dhe_psk = GroupName, Config) ->
+ PKAlg = proplists:get_value(public_keys, crypto:supports()),
+ case lists:member(dh, PKAlg) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing SRP crypto support"}
+ end;
+init_per_group(GroupName, Config0) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, end_per_group(GroupName, Config0));
+ false ->
+ init_certs(GroupName, Config0)
+ end.
+
+end_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:clean_tls_version(Config);
+ false ->
+ Config
+ end.
+
+init_per_testcase(TestCase, Config) when TestCase == psk_3des_ede_cbc;
+ TestCase == srp_anon_3des_ede_cbc;
+ TestCase == dhe_psk_3des_ede_cbc;
+ TestCase == ecdhe_psk_3des_ede_cbc;
+ TestCase == srp_rsa_3des_ede_cbc;
+ TestCase == srp_dss_3des_ede_cbc;
+ TestCase == rsa_psk_3des_ede_cbc;
+ TestCase == rsa_3des_ede_cbc;
+ TestCase == dhe_rsa_3des_ede_cbc;
+ TestCase == dhe_dss_3des_ede_cbc;
+ TestCase == ecdhe_rsa_3des_ede_cbc;
+ TestCase == srp_anon_dss_3des_ede_cbc;
+ TestCase == dh_anon_3des_ede_cbc;
+ TestCase == ecdh_anon_3des_ede_cbc;
+ TestCase == ecdhe_ecdsa_3des_ede_cbc ->
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ case lists:member(des_ede3, SupCiphers) of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, "Missing 3DES crypto support"}
+ end;
+init_per_testcase(TestCase, Config) when TestCase == psk_rc4_128;
+ TestCase == ecdhe_psk_rc4_128;
+ TestCase == dhe_psk_rc4_128;
+ TestCase == rsa_psk_rc4_128;
+ TestCase == rsa_rc4_128;
+ TestCase == ecdhe_rsa_rc4_128;
+ TestCase == ecdhe_ecdsa_rc4_128;
+ TestCase == dh_anon_rc4_128 ->
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ case lists:member(rc4, SupCiphers) of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, "Missing RC4 crypto support"}
+ end;
+init_per_testcase(TestCase, Config) when TestCase == psk_aes_128_ccm_8;
+ TestCase == rsa_psk_aes_128_ccm_8;
+ TestCase == psk_aes_128_ccm_8;
+ TestCase == dhe_psk_aes_128_ccm_8;
+ TestCase == ecdhe_psk_aes_128_ccm_8 ->
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ case lists:member(aes_128_ccm, SupCiphers) of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, "Missing AES_128_CCM crypto support"}
+ end;
+init_per_testcase(TestCase, Config) when TestCase == psk_aes_256_ccm_8;
+ TestCase == rsa_psk_aes_256_ccm_8;
+ TestCase == psk_aes_256_ccm_8;
+ TestCase == dhe_psk_aes_256_ccm_8;
+ TestCase == ecdhe_psk_aes_256_ccm_8 ->
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ case lists:member(aes_256_ccm, SupCiphers) of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, "Missing AES_256_CCM crypto support"}
+ end;
+init_per_testcase(TestCase, Config) ->
+ Cipher = ssl_test_lib:test_cipher(TestCase, Config),
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ case lists:member(Cipher, SupCiphers) of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, {Cipher, SupCiphers}}
+ end.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Initializtion ------------------------------------------
+%%--------------------------------------------------------------------
+
+init_certs(srp_rsa, Config) ->
+ DefConf = ssl_test_lib:default_cert_chain_conf(),
+ CertChainConf = ssl_test_lib:gen_conf(rsa, rsa, DefConf, DefConf),
+ #{server_config := ServerOpts,
+ client_config := ClientOpts}
+ = public_key:pkix_test_data(CertChainConf),
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, undefined}} | ServerOpts],
+ client_config => [{srp_identity, {"Test-User", "secret"}} | ClientOpts]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(srp_anon, Config) ->
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, undefined}}],
+ client_config => [{srp_identity, {"Test-User", "secret"}}]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(rsa_psk, Config) ->
+ ClientExt = x509_test:extensions([{key_usage, [digitalSignature, keyEncipherment]}]),
+ {ClientOpts, ServerOpts} = ssl_test_lib:make_rsa_cert_chains([{server_chain,
+ [[],[],[{extensions, ClientExt}]]}],
+ Config, "_peer_keyEncipherment"),
+ PskSharedSecret = <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>,
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, PskSharedSecret}} | ServerOpts],
+ client_config => [{psk_identity, "Test-User"},
+ {user_lookup_fun, {fun ssl_test_lib:user_lookup/3, PskSharedSecret}} | ClientOpts]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(rsa, Config) ->
+ ClientExt = x509_test:extensions([{key_usage, [digitalSignature, keyEncipherment]}]),
+ {ClientOpts, ServerOpts} = ssl_test_lib:make_rsa_cert_chains([{server_chain,
+ [[],[],[{extensions, ClientExt}]]}],
+ Config, "_peer_keyEncipherment"),
+ [{tls_config, #{server_config => ServerOpts,
+ client_config => ClientOpts}} |
+ proplists:delete(tls_config, Config)];
+init_certs(dhe_dss, Config) ->
+ DefConf = ssl_test_lib:default_cert_chain_conf(),
+ CertChainConf = ssl_test_lib:gen_conf(dsa, dsa, DefConf, DefConf),
+ #{server_config := ServerOpts,
+ client_config := ClientOpts}
+ = public_key:pkix_test_data(CertChainConf),
+ [{tls_config, #{server_config => ServerOpts,
+ client_config => ClientOpts}} |
+ proplists:delete(tls_config, Config)];
+init_certs(srp_dss, Config) ->
+ DefConf = ssl_test_lib:default_cert_chain_conf(),
+ CertChainConf = ssl_test_lib:gen_conf(dsa, dsa, DefConf, DefConf),
+ #{server_config := ServerOpts,
+ client_config := ClientOpts}
+ = public_key:pkix_test_data(CertChainConf),
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, undefined}} | ServerOpts],
+ client_config => [{srp_identity, {"Test-User", "secret"}} | ClientOpts]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(GroupName, Config) when GroupName == dhe_rsa;
+ GroupName == ecdhe_rsa ->
+ DefConf = ssl_test_lib:default_cert_chain_conf(),
+ CertChainConf = ssl_test_lib:gen_conf(rsa, rsa, DefConf, DefConf),
+ #{server_config := ServerOpts,
+ client_config := ClientOpts}
+ = public_key:pkix_test_data(CertChainConf),
+ [{tls_config, #{server_config => ServerOpts,
+ client_config => ClientOpts}} |
+ proplists:delete(tls_config, Config)];
+init_certs(GroupName, Config) when GroupName == dhe_ecdsa;
+ GroupName == ecdhe_ecdsa ->
+ DefConf = ssl_test_lib:default_cert_chain_conf(),
+ CertChainConf = ssl_test_lib:gen_conf(ecdsa, ecdsa, DefConf, DefConf),
+ #{server_config := ServerOpts,
+ client_config := ClientOpts}
+ = public_key:pkix_test_data(CertChainConf),
+ [{tls_config, #{server_config => ServerOpts,
+ client_config => ClientOpts}} |
+ proplists:delete(tls_config, Config)];
+init_certs(GroupName, Config) when GroupName == psk;
+ GroupName == dhe_psk;
+ GroupName == ecdhe_psk ->
+ PskSharedSecret = <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>,
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, PskSharedSecret}}],
+ client_config => [{psk_identity, "Test-User"},
+ {user_lookup_fun, {fun ssl_test_lib:user_lookup/3, PskSharedSecret}}]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(srp, Config) ->
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun ssl_test_lib:user_lookup/3, undefined}}],
+ client_config => [{srp_identity, {"Test-User", "secret"}}]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(_GroupName, Config) ->
+ %% Anonymous does not need certs
+ [{tls_config, #{server_config => [],
+ client_config => []}} |
+ proplists:delete(tls_config, Config)].
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% SRP --------------------------------------------------------
+%%--------------------------------------------------------------------
+srp_rsa_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_rsa, '3des_ede_cbc', Config).
+
+srp_rsa_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_rsa, 'aes_128_cbc', Config).
+
+srp_rsa_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_rsa, 'aes_256_cbc', Config).
+
+srp_dss_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_dss, '3des_ede_cbc', Config).
+
+srp_dss_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_dss, 'aes_128_cbc', Config).
+
+srp_dss_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_dss, 'aes_256_cbc', Config).
+
+%%--------------------------------------------------------------------
+%% PSK --------------------------------------------------------
+%%--------------------------------------------------------------------
+rsa_psk_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, '3des_ede_cbc', Config).
+
+rsa_psk_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_128_cbc', Config).
+
+rsa_psk_aes_128_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_128_ccm', Config).
+
+rsa_psk_aes_128_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_128_ccm_8', Config).
+
+rsa_psk_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_256_cbc', Config).
+
+rsa_psk_aes_256_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_256_ccm', Config).
+
+rsa_psk_aes_256_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_256_ccm_8', Config).
+
+rsa_psk_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'rc4_128', Config).
+
+%%--------------------------------------------------------------------
+%% RSA --------------------------------------------------------
+%%--------------------------------------------------------------------
+rsa_des_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'des_cbc', Config).
+
+rsa_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, '3des_ede_cbc', Config).
+
+rsa_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'aes_128_cbc', Config).
+
+rsa_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'aes_256_cbc', Config).
+
+rsa_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'aes_128_gcm', Config).
+
+rsa_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'aes_256_gcm', Config).
+
+rsa_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'rc4_128', Config).
+%%--------------------------------------------------------------------
+%% DHE_RSA --------------------------------------------------------
+%%--------------------------------------------------------------------
+dhe_rsa_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, '3des_ede_cbc', Config).
+
+dhe_rsa_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, 'aes_128_cbc', Config).
+
+dhe_rsa_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, 'aes_128_gcm', Config).
+
+dhe_rsa_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, 'aes_256_cbc', Config).
+
+dhe_rsa_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, 'aes_256_gcm', Config).
+
+dhe_rsa_chacha20_poly1305(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, 'chacha20_poly1305', Config).
+%%--------------------------------------------------------------------
+%% ECDHE_RSA --------------------------------------------------------
+%%--------------------------------------------------------------------
+ecdhe_rsa_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, '3des_ede_cbc', Config).
+
+ecdhe_rsa_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'aes_128_cbc', Config).
+
+ecdhe_rsa_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'aes_128_gcm', Config).
+
+ecdhe_rsa_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'aes_256_cbc', Config).
+
+ecdhe_rsa_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'aes_256_gcm', Config).
+
+ecdhe_rsa_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'rc4_128', Config).
+
+ecdhe_rsa_chacha20_poly1305(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'chacha20_poly1305', Config).
+
+%%--------------------------------------------------------------------
+%% ECDHE_ECDSA --------------------------------------------------------
+%%--------------------------------------------------------------------
+ecdhe_ecdsa_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'rc4_128', Config).
+
+ecdhe_ecdsa_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, '3des_ede_cbc', Config).
+
+ecdhe_ecdsa_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'aes_128_cbc', Config).
+
+ecdhe_ecdsa_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'aes_128_gcm', Config).
+
+ecdhe_ecdsa_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'aes_256_cbc', Config).
+
+ecdhe_ecdsa_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'aes_256_gcm', Config).
+
+ecdhe_ecdsa_chacha20_poly1305(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'chacha20_poly1305', Config).
+%%--------------------------------------------------------------------
+%% DHE_DSS --------------------------------------------------------
+%%--------------------------------------------------------------------
+dhe_dss_des_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, 'des_cbc', Config).
+
+dhe_dss_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, '3des_ede_cbc', Config).
+
+dhe_dss_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, 'aes_128_cbc', Config).
+
+dhe_dss_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, 'aes_256_cbc', Config).
+
+dhe_dss_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, 'aes_128_gcm', Config).
+
+dhe_dss_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, 'aes_256_gcm', Config).
+
+%%--------------------------------------------------------------------
+%% Anonymous --------------------------------------------------------
+%%--------------------------------------------------------------------
+dh_anon_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, '3des_ede_cbc', Config).
+
+dh_anon_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, 'aes_128_cbc', Config).
+
+dh_anon_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, 'aes_128_gcm', Config).
+
+dh_anon_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, 'aes_256_cbc', Config).
+
+dh_anon_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, 'aes_256_gcm', Config).
+
+dh_anon_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, 'rc4_128', Config).
+
+ecdh_anon_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdh_anon, '3des_ede_cbc', Config).
+
+ecdh_anon_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdh_anon, 'aes_128_cbc', Config).
+
+ecdh_anon_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdh_anon, 'aes_256_cbc', Config).
+
+srp_anon_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_anon, '3des_ede_cbc', Config).
+
+srp_anon_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_anon, 'aes_128_cbc', Config).
+
+srp_anon_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_anon, 'aes_256_cbc', Config).
+
+dhe_psk_des_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'des_cbc', Config).
+
+dhe_psk_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'rc4_128', Config).
+
+dhe_psk_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, '3des_ede_cbc', Config).
+
+dhe_psk_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_128_cbc', Config).
+
+dhe_psk_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_256_cbc', Config).
+
+dhe_psk_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_128_gcm', Config).
+
+dhe_psk_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_256_gcm', Config).
+
+dhe_psk_aes_128_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_128_ccm', Config).
+
+dhe_psk_aes_256_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_256_ccm', Config).
+
+dhe_psk_aes_128_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_128_ccm_8', Config).
+
+dhe_psk_aes_256_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_256_ccm_8', Config).
+
+ecdhe_psk_des_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'des_cbc', Config).
+
+ecdhe_psk_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'rc4_128', Config).
+
+ecdhe_psk_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, '3des_ede_cbc', Config).
+
+ecdhe_psk_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_128_cbc', Config).
+
+ecdhe_psk_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_256_cbc', Config).
+
+ecdhe_psk_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_128_gcm', Config).
+
+ecdhe_psk_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_256_gcm', Config).
+
+ecdhe_psk_aes_128_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_128_ccm', Config).
+
+ecdhe_psk_aes_128_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_128_ccm_8', Config).
+
+psk_des_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'des_cbc', Config).
+
+psk_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'rc4_128', Config).
+
+psk_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(psk, '3des_ede_cbc', Config).
+
+psk_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_128_cbc', Config).
+
+psk_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_256_cbc', Config).
+
+psk_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_128_gcm', Config).
+
+psk_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_256_gcm', Config).
+
+psk_aes_128_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_128_ccm', Config).
+
+psk_aes_256_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_256_ccm', Config).
+
+psk_aes_128_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_128_ccm_8', Config).
+
+psk_aes_256_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_256_ccm_8', Config).
+
+%%--------------------------------------------------------------------
+%% Internal functions ----------------------------------------------
+%%--------------------------------------------------------------------
+run_ciphers_test(Kex, Cipher, Config) ->
+ Version = ssl_test_lib:protocol_version(Config),
+ TestCiphers = test_ciphers(Kex, Cipher, Version),
+
+ case TestCiphers of
+ [_|_] ->
+ lists:foreach(fun(TestCipher) ->
+ cipher_suite_test(TestCipher, Version, Config)
+ end, TestCiphers);
+ [] ->
+ {skip, {not_sup, Kex, Cipher, Version}}
+ end.
+
+cipher_suite_test(ErlangCipherSuite, Version, Config) ->
+ #{server_config := SOpts,
+ client_config := COpts} = proplists:get_value(tls_config, Config),
+ ServerOpts = ssl_test_lib:ssl_options(SOpts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(COpts, Config),
+ ct:log("Testing CipherSuite ~p~n", [ErlangCipherSuite]),
+ ct:log("Server Opts ~p~n", [ServerOpts]),
+ ct:log("Client Opts ~p~n", [ClientOpts]),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ ConnectionInfo = {ok, {Version, ErlangCipherSuite}},
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}},
+ {options, [{versions, [Version]}, {ciphers, [ErlangCipherSuite]} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}},
+ {options, [{versions, [Version]}, {ciphers, [ErlangCipherSuite]} |
+ ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+
+test_ciphers(Kex, Cipher, Version) ->
+ ssl:filter_cipher_suites(ssl:cipher_suites(all, Version) ++ ssl:cipher_suites(anonymous, Version),
+ [{key_exchange,
+ fun(Kex0) when Kex0 == Kex -> true;
+ (_) -> false
+ end},
+ {cipher,
+ fun(Cipher0) when Cipher0 == Cipher -> true;
+ (_) -> false
+ end}]).
+
diff --git a/lib/ssl/test/ssl_crl_SUITE.erl b/lib/ssl/test/ssl_crl_SUITE.erl
index 668c76e38d..b2fd3874a8 100644
--- a/lib/ssl/test/ssl_crl_SUITE.erl
+++ b/lib/ssl/test/ssl_crl_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -238,7 +238,7 @@ crl_verify_revoked(Config) when is_list(Config) ->
end,
crl_verify_error(Hostname, ServerNode, ServerOpts, ClientNode, ClientOpts,
- "certificate revoked").
+ certificate_revoked).
crl_verify_no_crl() ->
[{doc,"Verify a simple CRL chain when the CRL is missing"}].
@@ -277,10 +277,10 @@ crl_verify_no_crl(Config) when is_list(Config) ->
%% The error "revocation status undetermined" gets turned
%% into "bad certificate".
crl_verify_error(Hostname, ServerNode, ServerOpts, ClientNode, ClientOpts,
- "bad certificate");
+ bad_certificate);
peer ->
crl_verify_error(Hostname, ServerNode, ServerOpts, ClientNode, ClientOpts,
- "bad certificate");
+ bad_certificate);
best_effort ->
%% In "best effort" mode, we consider the certificate not
%% to be revoked if we can't find the appropriate CRL.
@@ -341,7 +341,7 @@ crl_hash_dir_collision(Config) when is_list(Config) ->
%% First certificate revoked; first fails, second succeeds.
crl_verify_error(Hostname, ServerNode, ServerOpts1, ClientNode, ClientOpts,
- "certificate revoked"),
+ certificate_revoked),
crl_verify_valid(Hostname, ServerNode, ServerOpts2, ClientNode, ClientOpts),
make_certs:revoke(PrivDir, CA2, "collision-client-2", CertsConfig),
@@ -352,9 +352,9 @@ crl_hash_dir_collision(Config) when is_list(Config) ->
%% Second certificate revoked; both fail.
crl_verify_error(Hostname, ServerNode, ServerOpts1, ClientNode, ClientOpts,
- "certificate revoked"),
+ certificate_revoked),
crl_verify_error(Hostname, ServerNode, ServerOpts2, ClientNode, ClientOpts,
- "certificate revoked"),
+ certificate_revoked),
ok.
@@ -383,8 +383,11 @@ crl_hash_dir_expired(Config) when is_list(Config) ->
{verify, verify_peer}],
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- %% First make a CRL that expired yesterday.
- make_certs:gencrl(PrivDir, CA, CertsConfig, -24),
+ %% First make a CRL that will expire in one second.
+ make_certs:gencrl_sec(PrivDir, CA, CertsConfig, 1),
+ %% Sleep until the next CRL is due
+ ct:sleep({seconds, 1}),
+
CrlDir = filename:join(PrivDir, "crls"),
populate_crl_hash_dir(PrivDir, CrlDir,
[{CA, "1627b4b0"}],
@@ -397,10 +400,10 @@ crl_hash_dir_expired(Config) when is_list(Config) ->
%% The error "revocation status undetermined" gets turned
%% into "bad certificate".
crl_verify_error(Hostname, ServerNode, ServerOpts, ClientNode, ClientOpts,
- "bad certificate");
+ bad_certificate);
peer ->
crl_verify_error(Hostname, ServerNode, ServerOpts, ClientNode, ClientOpts,
- "bad certificate");
+ bad_certificate);
best_effort ->
%% In "best effort" mode, we consider the certificate not
%% to be revoked if we can't find the appropriate CRL.
@@ -448,11 +451,8 @@ crl_verify_error(Hostname, ServerNode, ServerOpts, ClientNode, ClientOpts, Expec
{host, Hostname},
{from, self()},
{options, ClientOpts}]),
- receive
- {Server, AlertOrClose} ->
- ct:pal("Server Alert or Close ~p", [AlertOrClose])
- end,
- ssl_test_lib:check_result(Client, {error, {tls_alert, ExpectedAlert}}).
+
+ ssl_test_lib:check_client_alert(Server, Client, ExpectedAlert).
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
diff --git a/lib/ssl/test/ssl_dist_SUITE.erl b/lib/ssl/test/ssl_dist_SUITE.erl
index 8740e8c8f0..003e1fc448 100644
--- a/lib/ssl/test/ssl_dist_SUITE.erl
+++ b/lib/ssl/test/ssl_dist_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -22,20 +22,21 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("public_key/include/public_key.hrl").
+-include("ssl_dist_test_lib.hrl").
%% Note: This directive should only be used in test suites.
--compile(export_all).
+-compile([export_all, nowarn_export_all]).
-define(DEFAULT_TIMETRAP_SECS, 240).
-define(AWAIT_SSL_NODE_UP_TIMEOUT, 30000).
--record(node_handle,
- {connection_handler,
- socket,
- name,
- nodename}
- ).
+-import(ssl_dist_test_lib,
+ [tstsrvr_format/2, send_to_tstcntrl/1,
+ apply_on_ssl_node/4, apply_on_ssl_node/2,
+ stop_ssl_node/1]).
+start_ssl_node_name(Name, Args) ->
+ ssl_dist_test_lib:start_ssl_node(Name, Args).
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
@@ -140,11 +141,14 @@ basic_test(NH1, NH2, _) ->
apply_on_ssl_node(
NH1,
fun () ->
- tstsrvr_format("Hi from ~p!~n", [node()]),
- send_to_tstcntrl({Ref, self()}),
+ tstsrvr_format(
+ "Hi from ~p!~n", [node()]),
+ send_to_tstcntrl(
+ {Ref, self()}),
receive
{From, ping} ->
- tstsrvr_format("Received ping ~p!~n", [node()]),
+ tstsrvr_format(
+ "Received ping ~p!~n", [node()]),
From ! {self(), pong}
end
end)
@@ -154,7 +158,8 @@ basic_test(NH1, NH2, _) ->
ok = apply_on_ssl_node(
NH2,
fun () ->
- tstsrvr_format("Hi from ~p!~n", [node()]),
+ tstsrvr_format(
+ "Hi from ~p!~n", [node()]),
SslPid ! {self(), ping},
receive
{SslPid, pong} ->
@@ -183,7 +188,8 @@ payload_test(NH1, NH2, _) ->
apply_on_ssl_node(
NH1,
fun () ->
- send_to_tstcntrl({Ref, self()}),
+ send_to_tstcntrl(
+ {Ref, self()}),
receive
{From, Msg} ->
From ! {self(), Msg}
@@ -616,12 +622,6 @@ gen_dist_test(Test, Config) ->
%% ssl_node side api
%%
-tstsrvr_format(Fmt, ArgList) ->
- send_to_tstsrvr({format, Fmt, ArgList}).
-
-send_to_tstcntrl(Message) ->
- send_to_tstsrvr({message, Message}).
-
try_setting_priority(TestFun, Config) ->
Prio = 1,
case gen_udp:open(0, [{priority,Prio}]) of
@@ -653,44 +653,6 @@ inet_ports() ->
%% test_server side api
%%
-apply_on_ssl_node(Node, M, F, A) when is_atom(M), is_atom(F), is_list(A) ->
- Ref = make_ref(),
- send_to_ssl_node(Node, {apply, self(), Ref, M, F, A}),
- receive
- {Ref, Result} ->
- Result
- end.
-
-apply_on_ssl_node(Node, Fun) when is_function(Fun, 0) ->
- Ref = make_ref(),
- send_to_ssl_node(Node, {apply, self(), Ref, Fun}),
- receive
- {Ref, Result} ->
- Result
- end.
-
-stop_ssl_node(#node_handle{connection_handler = Handler,
- socket = Socket,
- name = Name}) ->
- ?t:format("Trying to stop ssl node ~s.~n", [Name]),
- Mon = erlang:monitor(process, Handler),
- unlink(Handler),
- case gen_tcp:send(Socket, term_to_binary(stop)) of
- ok ->
- receive
- {'DOWN', Mon, process, Handler, Reason} ->
- case Reason of
- normal ->
- ok;
- _ ->
- ct:pal("Down ~p ~n", [Reason])
- end
- end;
- Error ->
- erlang:demonitor(Mon, [flush]),
- ct:pal("Warning ~p ~n", [Error])
- end.
-
start_ssl_node(Config) ->
start_ssl_node(Config, "").
@@ -698,29 +660,8 @@ start_ssl_node(Config, XArgs) ->
Name = mk_node_name(Config),
SSL = proplists:get_value(ssl_opts, Config),
SSLDistOpts = setup_dist_opts(Config),
- start_ssl_node_raw(Name, SSL ++ " " ++ SSLDistOpts ++ XArgs).
-
-start_ssl_node_raw(Name, Args) ->
- {ok, LSock} = gen_tcp:listen(0,
- [binary, {packet, 4}, {active, false}]),
- {ok, ListenPort} = inet:port(LSock),
- CmdLine = mk_node_cmdline(ListenPort, Name, Args),
- ?t:format("Attempting to start ssl node ~ts: ~ts~n", [Name, CmdLine]),
- case open_port({spawn, CmdLine}, []) of
- Port when is_port(Port) ->
- unlink(Port),
- erlang:port_close(Port),
- case await_ssl_node_up(Name, LSock) of
- #node_handle{} = NodeHandle ->
- ?t:format("Ssl node ~s started.~n", [Name]),
- NodeName = list_to_atom(Name ++ "@" ++ host_name()),
- NodeHandle#node_handle{nodename = NodeName};
- Error ->
- exit({failed_to_start_node, Name, Error})
- end;
- Error ->
- exit({failed_to_start_node, Name, Error})
- end.
+ start_ssl_node_name(
+ Name, SSL ++ " " ++ SSLDistOpts ++ XArgs).
cache_crls_on_ssl_nodes(PrivDir, CANames, NHs) ->
[begin
@@ -739,11 +680,6 @@ cache_crls_on_ssl_nodes(PrivDir, CANames, NHs) ->
%% command line creation
%%
-host_name() ->
- [$@ | Host] = lists:dropwhile(fun ($@) -> false; (_) -> true end,
- atom_to_list(node())),
- Host.
-
mk_node_name(Config) ->
N = erlang:unique_integer([positive]),
Case = proplists:get_value(testcase, Config),
@@ -753,225 +689,6 @@ mk_node_name(Config) ->
++ "_"
++ integer_to_list(N).
-mk_node_cmdline(ListenPort, Name, Args) ->
- Static = "-detached -noinput",
- Pa = filename:dirname(code:which(?MODULE)),
- Prog = case catch init:get_argument(progname) of
- {ok,[[P]]} -> P;
- _ -> exit(no_progname_argument_found)
- end,
- NameSw = case net_kernel:longnames() of
- false -> "-sname ";
- _ -> "-name "
- end,
- {ok, Pwd} = file:get_cwd(),
- "\"" ++ Prog ++ "\" "
- ++ Static ++ " "
- ++ NameSw ++ " " ++ Name ++ " "
- ++ "-pa " ++ Pa ++ " "
- ++ "-run application start crypto -run application start public_key "
- ++ "-eval 'net_kernel:verbose(1)' "
- ++ "-run " ++ atom_to_list(?MODULE) ++ " cnct2tstsrvr "
- ++ host_name() ++ " "
- ++ integer_to_list(ListenPort) ++ " "
- ++ Args ++ " "
- ++ "-env ERL_CRASH_DUMP " ++ Pwd ++ "/erl_crash_dump." ++ Name ++ " "
- ++ "-kernel error_logger \"{file,\\\"" ++ Pwd ++ "/error_log." ++ Name ++ "\\\"}\" "
- ++ "-setcookie " ++ atom_to_list(erlang:get_cookie()).
-
-%%
-%% Connection handler test_server side
-%%
-
-await_ssl_node_up(Name, LSock) ->
- case gen_tcp:accept(LSock, ?AWAIT_SSL_NODE_UP_TIMEOUT) of
- timeout ->
- gen_tcp:close(LSock),
- ?t:format("Timeout waiting for ssl node ~s to come up~n",
- [Name]),
- timeout;
- {ok, Socket} ->
- gen_tcp:close(LSock),
- case gen_tcp:recv(Socket, 0) of
- {ok, Bin} ->
- check_ssl_node_up(Socket, Name, Bin);
- {error, closed} ->
- gen_tcp:close(Socket),
- exit({lost_connection_with_ssl_node_before_up, Name})
- end;
- {error, Error} ->
- gen_tcp:close(LSock),
- exit({accept_failed, Error})
- end.
-
-check_ssl_node_up(Socket, Name, Bin) ->
- case catch binary_to_term(Bin) of
- {'EXIT', _} ->
- gen_tcp:close(Socket),
- exit({bad_data_received_from_ssl_node, Name, Bin});
- {ssl_node_up, NodeName} ->
- case list_to_atom(Name++"@"++host_name()) of
- NodeName ->
- Parent = self(),
- Go = make_ref(),
- %% Spawn connection handler on test server side
- Pid = spawn_link(
- fun () ->
- receive Go -> ok end,
- tstsrvr_con_loop(Name, Socket, Parent)
- end),
- ok = gen_tcp:controlling_process(Socket, Pid),
- Pid ! Go,
- #node_handle{connection_handler = Pid,
- socket = Socket,
- name = Name};
- _ ->
- exit({unexpected_ssl_node_connected, NodeName})
- end;
- Msg ->
- exit({unexpected_msg_instead_of_ssl_node_up, Name, Msg})
- end.
-
-send_to_ssl_node(#node_handle{connection_handler = Hndlr}, Term) ->
- Hndlr ! {relay_to_ssl_node, term_to_binary(Term)},
- ok.
-
-tstsrvr_con_loop(Name, Socket, Parent) ->
- inet:setopts(Socket,[{active,once}]),
- receive
- {relay_to_ssl_node, Data} when is_binary(Data) ->
- case gen_tcp:send(Socket, Data) of
- ok ->
- ok;
- _Error ->
- gen_tcp:close(Socket),
- exit({failed_to_relay_data_to_ssl_node, Name, Data})
- end;
- {tcp, Socket, Bin} ->
- case catch binary_to_term(Bin) of
- {'EXIT', _} ->
- gen_tcp:close(Socket),
- exit({bad_data_received_from_ssl_node, Name, Bin});
- {format, FmtStr, ArgList} ->
- ?t:format(FmtStr, ArgList);
- {message, Msg} ->
- ?t:format("Got message ~p", [Msg]),
- Parent ! Msg;
- {apply_res, To, Ref, Res} ->
- To ! {Ref, Res};
- bye ->
- ?t:format("Ssl node ~s stopped.~n", [Name]),
- gen_tcp:close(Socket),
- exit(normal);
- Unknown ->
- exit({unexpected_message_from_ssl_node, Name, Unknown})
- end;
- {tcp_closed, Socket} ->
- gen_tcp:close(Socket),
- exit({lost_connection_with_ssl_node, Name})
- end,
- tstsrvr_con_loop(Name, Socket, Parent).
-
-%%
-%% Connection handler ssl_node side
-%%
-
-% cnct2tstsrvr() is called via command line arg -run ...
-cnct2tstsrvr([Host, Port]) when is_list(Host), is_list(Port) ->
- %% Spawn connection handler on ssl node side
- ConnHandler
- = spawn(fun () ->
- case catch gen_tcp:connect(Host,
- list_to_integer(Port),
- [binary,
- {packet, 4},
- {active, false}]) of
- {ok, Socket} ->
- notify_ssl_node_up(Socket),
- ets:new(test_server_info,
- [set,
- public,
- named_table,
- {keypos, 1}]),
- ets:insert(test_server_info,
- {test_server_handler, self()}),
- ssl_node_con_loop(Socket);
- Error ->
- halt("Failed to connect to test server " ++
- lists:flatten(io_lib:format("Host:~p ~n Port:~p~n Error:~p~n",
- [Host, Port, Error])))
- end
- end),
- spawn(fun () ->
- Mon = erlang:monitor(process, ConnHandler),
- receive
- {'DOWN', Mon, process, ConnHandler, Reason} ->
- receive after 1000 -> ok end,
- halt("test server connection handler terminated: " ++
- lists:flatten(io_lib:format("~p", [Reason])))
- end
- end).
-
-notify_ssl_node_up(Socket) ->
- case catch gen_tcp:send(Socket,
- term_to_binary({ssl_node_up, node()})) of
- ok -> ok;
- _ -> halt("Failed to notify test server that I'm up")
- end.
-
-send_to_tstsrvr(Term) ->
- case catch ets:lookup_element(test_server_info, test_server_handler, 2) of
- Hndlr when is_pid(Hndlr) ->
- Hndlr ! {relay_to_test_server, term_to_binary(Term)}, ok;
- _ ->
- receive after 200 -> ok end,
- send_to_tstsrvr(Term)
- end.
-
-ssl_node_con_loop(Socket) ->
- inet:setopts(Socket,[{active,once}]),
- receive
- {relay_to_test_server, Data} when is_binary(Data) ->
- case gen_tcp:send(Socket, Data) of
- ok ->
- ok;
- _Error ->
- gen_tcp:close(Socket),
- halt("Failed to relay data to test server")
- end;
- {tcp, Socket, Bin} ->
- case catch binary_to_term(Bin) of
- {'EXIT', _} ->
- gen_tcp:close(Socket),
- halt("test server sent me bad data");
- {apply, From, Ref, M, F, A} ->
- spawn_link(
- fun () ->
- send_to_tstsrvr({apply_res,
- From,
- Ref,
- (catch apply(M, F, A))})
- end);
- {apply, From, Ref, Fun} ->
- spawn_link(fun () ->
- send_to_tstsrvr({apply_res,
- From,
- Ref,
- (catch Fun())})
- end);
- stop ->
- gen_tcp:send(Socket, term_to_binary(bye)),
- gen_tcp:close(Socket),
- init:stop(),
- receive after infinity -> ok end;
- _Unknown ->
- halt("test server sent me an unexpected message")
- end;
- {tcp_closed, Socket} ->
- halt("Lost connection to test server")
- end,
- ssl_node_con_loop(Socket).
-
%%
%% Setup ssl dist info
%%
@@ -1007,7 +724,8 @@ setup_certs(Config) ->
ok = file:make_dir(NodeDir),
ok = file:make_dir(RGenDir),
make_randfile(RGenDir),
- {ok, _} = make_certs:all(RGenDir, NodeDir),
+ [Hostname|_] = string:split(net_adm:localhost(), ".", all),
+ {ok, _} = make_certs:all(RGenDir, NodeDir, [{hostname,Hostname}]),
SDir = filename:join([NodeDir, "server"]),
SC = filename:join([SDir, "cert.pem"]),
SK = filename:join([SDir, "key.pem"]),
diff --git a/lib/ssl/test/ssl_dist_bench_SUITE.erl b/lib/ssl/test/ssl_dist_bench_SUITE.erl
new file mode 100644
index 0000000000..67944c74d2
--- /dev/null
+++ b/lib/ssl/test/ssl_dist_bench_SUITE.erl
@@ -0,0 +1,874 @@
+%%%-------------------------------------------------------------------
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(ssl_dist_bench_SUITE).
+
+-include_lib("common_test/include/ct_event.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+%% CT meta
+-export([suite/0, all/0, groups/0,
+ init_per_suite/1, end_per_suite/1,
+ init_per_group/2, end_per_group/2,
+ init_per_testcase/2, end_per_testcase/2]).
+
+%% Test cases
+-export(
+ [setup/1,
+ roundtrip/1,
+ sched_utilization/1,
+ throughput_0/1,
+ throughput_64/1,
+ throughput_1024/1,
+ throughput_4096/1,
+ throughput_16384/1,
+ throughput_65536/1,
+ throughput_262144/1,
+ throughput_1048576/1]).
+
+%% Debug
+-export([payload/1, roundtrip_runner/3, setup_runner/3, throughput_runner/4]).
+
+%%%-------------------------------------------------------------------
+
+suite() -> [{ct_hooks, [{ts_install_cth, [{nodenames, 2}]}]}].
+
+all() ->
+ [{group, ssl},
+ {group, crypto},
+ {group, plain}].
+
+groups() ->
+ [{ssl, all_groups()},
+ {crypto, all_groups()},
+ {plain, all_groups()},
+ %%
+ {setup, [{repeat, 1}], [setup]},
+ {roundtrip, [{repeat, 1}], [roundtrip]},
+ {sched_utilization,[{repeat, 1}], [sched_utilization]},
+ {throughput, [{repeat, 1}],
+ [throughput_0,
+ throughput_64,
+ throughput_1024,
+ throughput_4096,
+ throughput_16384,
+ throughput_65536,
+ throughput_262144,
+ throughput_1048576]}].
+
+all_groups() ->
+ [{group, setup},
+ {group, roundtrip},
+ {group, throughput},
+ {group, sched_utilization}
+ ].
+
+init_per_suite(Config) ->
+ Digest = sha1,
+ ECCurve = secp521r1,
+ TLSVersion = 'tlsv1.2',
+ TLSCipher = {ecdhe_ecdsa,aes_128_cbc,sha256,sha256},
+ %%
+ Node = node(),
+ try
+ Node =/= nonode@nohost orelse
+ throw({skipped,"Node not distributed"}),
+ verify_node_src_addr(),
+ {supported, SSLVersions} =
+ lists:keyfind(supported, 1, ssl:versions()),
+ lists:member(TLSVersion, SSLVersions) orelse
+ throw(
+ {skipped,
+ "SSL does not support " ++ term_to_string(TLSVersion)}),
+ lists:member(ECCurve, ssl:eccs(TLSVersion)) orelse
+ throw(
+ {skipped,
+ "SSL does not support " ++ term_to_string(ECCurve)}),
+ lists:member(TLSCipher, ssl:cipher_suites()) orelse
+ throw(
+ {skipped,
+ "SSL does not support " ++ term_to_string(TLSCipher)})
+ of
+ _ ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ %%
+ [_, HostA] = split_node(Node),
+ NodeAName = ?MODULE_STRING ++ "_node_a",
+ NodeAString = NodeAName ++ "@" ++ HostA,
+ NodeAConfFile = filename:join(PrivDir, NodeAString ++ ".conf"),
+ NodeA = list_to_atom(NodeAString),
+ %%
+ ServerNode = ssl_bench_test_lib:setup(dist_server),
+ [_, HostB] = split_node(ServerNode),
+ NodeBName = ?MODULE_STRING ++ "_node_b",
+ NodeBString = NodeBName ++ "@" ++ HostB,
+ NodeBConfFile = filename:join(PrivDir, NodeBString ++ ".conf"),
+ NodeB = list_to_atom(NodeBString),
+ %%
+ CertOptions =
+ [{digest, Digest},
+ {key, {namedCurve, ECCurve}}],
+ RootCert =
+ public_key:pkix_test_root_cert(
+ ?MODULE_STRING ++ " ROOT CA", CertOptions),
+ SSLConf =
+ [{verify, verify_peer},
+ {versions, [TLSVersion]},
+ {ciphers, [TLSCipher]}],
+ ServerConf =
+ [{fail_if_no_peer_cert, true},
+ {verify_fun,
+ {fun inet_tls_dist:verify_client/3,[]}}
+ | SSLConf],
+ ClientConf = SSLConf,
+ %%
+ write_node_conf(
+ NodeAConfFile, NodeA, ServerConf, ClientConf,
+ CertOptions, RootCert),
+ write_node_conf(
+ NodeBConfFile, NodeB, ServerConf, ClientConf,
+ CertOptions, RootCert),
+ %%
+ [{node_a_name, NodeAName},
+ {node_a, NodeA},
+ {node_a_dist_args,
+ "-proto_dist inet_tls "
+ "-ssl_dist_optfile " ++ NodeAConfFile ++ " "},
+ {node_b_name, NodeBName},
+ {node_b, NodeB},
+ {node_b_dist_args,
+ "-proto_dist inet_tls "
+ "-ssl_dist_optfile " ++ NodeBConfFile ++ " "},
+ {server_node, ServerNode}
+ |Config]
+ catch
+ throw:Result ->
+ Result
+ end.
+
+end_per_suite(Config) ->
+ ServerNode = proplists:get_value(server_node, Config),
+ slave:stop(ServerNode).
+
+init_per_group(ssl, Config) ->
+ [{ssl_dist, true}, {ssl_dist_prefix, "SSL"}|Config];
+init_per_group(crypto, Config) ->
+ [{ssl_dist, false}, {ssl_dist_prefix, "Crypto"},
+ {ssl_dist_args,
+ "-proto_dist inet_crypto"}
+ |Config];
+init_per_group(plain, Config) ->
+ [{ssl_dist, false}, {ssl_dist_prefix, "Plain"}|Config];
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, _Config) ->
+ ok.
+
+init_per_testcase(_Func, Conf) ->
+ Conf.
+
+end_per_testcase(_Func, _Conf) ->
+ ok.
+
+-define(COUNT, 400).
+
+%%%-------------------------------------------------------------------
+%%% CommonTest API helpers
+
+verify_node_src_addr() ->
+ Msg = "Hello, world!",
+ {ok,Host} = inet:gethostname(),
+ {ok,DstAddr} = inet:getaddr(Host, inet),
+ {ok,Socket} = gen_udp:open(0, [{active,false}]),
+ {ok,Port} = inet:port(Socket),
+ ok = gen_udp:send(Socket, DstAddr, Port, Msg),
+ case gen_udp:recv(Socket, length(Msg) + 1, 1000) of
+ {ok,{DstAddr,Port,Msg}} ->
+ ok;
+ {ok,{SrcAddr,Port,Msg}} ->
+ throw({skipped,
+ "Src and dst address mismatch: " ++
+ term_to_string(SrcAddr) ++ " =:= " ++
+ term_to_string(DstAddr)});
+ Weird ->
+ error(Weird)
+ end.
+
+write_node_conf(
+ ConfFile, Node, ServerConf, ClientConf, CertOptions, RootCert) ->
+ [Name,Host] = split_node(Node),
+ Conf =
+ public_key:pkix_test_data(
+ #{root => RootCert,
+ peer =>
+ [{extensions,
+ [
+ #'Extension'{
+ extnID = ?'id-ce-subjectAltName',
+ extnValue = [{dNSName, Host}],
+ critical = true},
+ #'Extension'{
+ extnID = ?'id-ce-subjectAltName',
+ extnValue =
+ [{directoryName,
+ {rdnSequence,
+ [[#'AttributeTypeAndValue'{
+ type = ?'id-at-commonName',
+ value =
+ {utf8String,
+ unicode:characters_to_binary(
+ Name, utf8)
+ }
+ }]]}}],
+ critical = true}
+ ]} | CertOptions]}),
+ NodeConf =
+ [{server, ServerConf ++ Conf}, {client, ClientConf ++ Conf}],
+ {ok, Fd} = file:open(ConfFile, [write]),
+ ok = file:change_mode(ConfFile, 8#400),
+ io:format(Fd, "~p.~n", [NodeConf]),
+ ok = file:close(Fd).
+
+split_node(Node) ->
+ string:split(atom_to_list(Node), "@").
+
+%%%-------------------------------------------------------------------
+%%% Test cases
+
+%%-----------------------
+%% Connection setup speed
+
+setup(Config) ->
+ run_nodepair_test(fun setup/5, Config).
+
+setup(A, B, Prefix, HA, HB) ->
+ Rounds = 50,
+ [] = ssl_apply(HA, erlang, nodes, []),
+ [] = ssl_apply(HB, erlang, nodes, []),
+ {SetupTime, CycleTime} =
+ ssl_apply(HA, fun () -> setup_runner(A, B, Rounds) end),
+ ok = ssl_apply(HB, fun () -> setup_wait_nodedown(A, 10000) end),
+ %% [] = ssl_apply(HA, erlang, nodes, []),
+ %% [] = ssl_apply(HB, erlang, nodes, []),
+ SetupSpeed = round((Rounds*1000000*1000) / SetupTime),
+ CycleSpeed = round((Rounds*1000000*1000) / CycleTime),
+ _ = report(Prefix++" Setup", SetupSpeed, "setups/1000s"),
+ report(Prefix++" Setup Cycle", CycleSpeed, "cycles/1000s").
+
+%% Runs on node A against rex in node B
+setup_runner(A, B, Rounds) ->
+ StartTime = start_time(),
+ SetupTime = setup_loop(A, B, 0, Rounds),
+ {microseconds(SetupTime), microseconds(elapsed_time(StartTime))}.
+
+setup_loop(_A, _B, T, 0) ->
+ T;
+setup_loop(A, B, T, N) ->
+ StartTime = start_time(),
+ [N,A] = [N|rpc:block_call(B, erlang, nodes, [])],
+ Time = elapsed_time(StartTime),
+ [N,B] = [N|erlang:nodes()],
+ Mref = erlang:monitor(process, {rex,B}),
+ true = net_kernel:disconnect(B),
+ receive
+ {'DOWN',Mref,process,_,_} ->
+ [] = erlang:nodes(),
+ setup_loop(A, B, Time + T, N - 1)
+ end.
+
+setup_wait_nodedown(A, Time) ->
+ ok = net_kernel:monitor_nodes(true),
+ case nodes() of
+ [] ->
+ ok;
+ [A] ->
+ receive
+ {nodedown,A} ->
+ ok;
+ Unexpected ->
+ {error,{unexpected,Unexpected}}
+ after Time ->
+ {error,timeout}
+ end
+ end.
+
+
+%%----------------
+%% Roundtrip speed
+
+roundtrip(Config) ->
+ run_nodepair_test(fun roundtrip/5, Config).
+
+roundtrip(A, B, Prefix, HA, HB) ->
+ Rounds = 40000,
+ [] = ssl_apply(HA, erlang, nodes, []),
+ [] = ssl_apply(HB, erlang, nodes, []),
+ ok = ssl_apply(HA, net_kernel, allow, [[B]]),
+ ok = ssl_apply(HB, net_kernel, allow, [[A]]),
+ Time = ssl_apply(HA, fun () -> roundtrip_runner(A, B, Rounds) end),
+ [B] = ssl_apply(HA, erlang, nodes, []),
+ [A] = ssl_apply(HB, erlang, nodes, []),
+ Speed = round((Rounds*1000000) / Time),
+ report(Prefix++" Roundtrip", Speed, "pings/s").
+
+%% Runs on node A and spawns a server on node B
+roundtrip_runner(A, B, Rounds) ->
+ ClientPid = self(),
+ [A] = rpc:call(B, erlang, nodes, []),
+ ServerPid =
+ erlang:spawn(
+ B,
+ fun () -> roundtrip_server(ClientPid, Rounds) end),
+ ServerMon = erlang:monitor(process, ServerPid),
+ microseconds(
+ roundtrip_client(ServerPid, ServerMon, start_time(), Rounds)).
+
+roundtrip_server(_Pid, 0) ->
+ ok;
+roundtrip_server(Pid, N) ->
+ receive
+ N ->
+ Pid ! N,
+ roundtrip_server(Pid, N-1)
+ end.
+
+roundtrip_client(_Pid, Mon, StartTime, 0) ->
+ Time = elapsed_time(StartTime),
+ receive
+ {'DOWN', Mon, _, _, normal} ->
+ Time;
+ {'DOWN', Mon, _, _, Other} ->
+ exit(Other)
+ end;
+roundtrip_client(Pid, Mon, StartTime, N) ->
+ Pid ! N,
+ receive
+ N ->
+ roundtrip_client(Pid, Mon, StartTime, N - 1)
+ end.
+
+%%---------------------------------------
+%% Scheduler utilization at constant load
+
+
+sched_utilization(Config) ->
+ run_nodepair_test(
+ fun(A, B, Prefix, HA, HB) ->
+ sched_utilization(A, B, Prefix, HA, HB, proplists:get_value(ssl_dist, Config))
+ end, Config).
+
+sched_utilization(A, B, Prefix, HA, HB, SSL) ->
+ [] = ssl_apply(HA, erlang, nodes, []),
+ [] = ssl_apply(HB, erlang, nodes, []),
+ {ClientMsacc, ServerMsacc, Msgs} =
+ ssl_apply(HA, fun () -> sched_util_runner(A, B, SSL) end),
+ [B] = ssl_apply(HA, erlang, nodes, []),
+ [A] = ssl_apply(HB, erlang, nodes, []),
+ msacc:print(ClientMsacc),
+ msacc:print(ServerMsacc),
+ ct:pal("Got ~p busy_dist_port msgs",[length(Msgs)]),
+ ct:log("Stats of B from A: ~p",
+ [ssl_apply(HA, net_kernel, node_info, [B])]),
+ ct:log("Stats of A from B: ~p",
+ [ssl_apply(HB, net_kernel, node_info, [A])]),
+ SchedUtilClient =
+ round(10000 * msacc:stats(system_runtime,ClientMsacc) /
+ msacc:stats(system_realtime,ClientMsacc)),
+ SchedUtilServer =
+ round(10000 * msacc:stats(system_runtime,ServerMsacc) /
+ msacc:stats(system_realtime,ServerMsacc)),
+ Verdict =
+ case Msgs of
+ [] ->
+ "";
+ _ ->
+ " ???"
+ end,
+ {comment, ClientComment} =
+ report(Prefix ++ " Sched Utilization Client" ++ Verdict,
+ SchedUtilClient, "/100 %" ++ Verdict),
+ {comment, ServerComment} =
+ report(Prefix++" Sched Utilization Server" ++ Verdict,
+ SchedUtilServer, "/100 %" ++ Verdict),
+ {comment, "Client " ++ ClientComment ++ ", Server " ++ ServerComment}.
+
+%% Runs on node A and spawns a server on node B
+%% We want to avoid getting busy_dist_port as it hides the true SU usage
+%% of the receiver and sender.
+sched_util_runner(A, B, true) ->
+ sched_util_runner(A, B, 250);
+sched_util_runner(A, B, false) ->
+ sched_util_runner(A, B, 250);
+sched_util_runner(A, B, Senders) ->
+ Payload = payload(5),
+ [A] = rpc:call(B, erlang, nodes, []),
+ ServerPids =
+ [erlang:spawn_link(
+ B, fun () -> throughput_server() end)
+ || _ <- lists:seq(1, Senders)],
+ ServerMsacc =
+ erlang:spawn(
+ B,
+ fun() ->
+ receive
+ {start,Pid} ->
+ msacc:start(10000),
+ receive
+ {done,Pid} ->
+ Pid ! {self(),msacc:stats()}
+ end
+ end
+ end),
+ erlang:system_monitor(self(),[busy_dist_port]),
+ %% We spawn 250 senders which should mean that we
+ %% have a load of 250 msgs/msec
+ [spawn_link(
+ fun() ->
+ throughput_client(Pid, Payload)
+ end) || Pid <- ServerPids],
+ %%
+ receive after 1000 -> ok end,
+ ServerMsacc ! {start,self()},
+ msacc:start(10000),
+ ClientMsaccStats = msacc:stats(),
+ receive after 1000 -> ok end,
+ ServerMsacc ! {done,self()},
+ ServerMsaccStats = receive {ServerMsacc,Stats} -> Stats end,
+ %%
+ {ClientMsaccStats,ServerMsaccStats, flush()}.
+
+flush() ->
+ receive
+ M ->
+ [M | flush()]
+ after 0 ->
+ []
+ end.
+
+throughput_server() ->
+ receive _ -> ok end,
+ receive _ -> ok end,
+ receive _ -> ok end,
+ receive _ -> ok end,
+ receive _ -> ok end,
+ receive _ -> ok end,
+ receive _ -> ok end,
+ receive _ -> ok end,
+ receive _ -> ok end,
+ receive _ -> ok end,
+ throughput_server().
+
+throughput_client(Pid, Payload) ->
+ Pid ! Payload,
+ receive after 1 -> throughput_client(Pid, Payload) end.
+
+%%-----------------
+%% Throughput speed
+
+throughput_0(Config) ->
+ run_nodepair_test(
+ fun (A, B, Prefix, HA, HB) ->
+ throughput(A, B, Prefix, HA, HB, 500000, 0)
+ end, Config).
+
+throughput_64(Config) ->
+ run_nodepair_test(
+ fun (A, B, Prefix, HA, HB) ->
+ throughput(A, B, Prefix, HA, HB, 500000, 64)
+ end, Config).
+
+throughput_1024(Config) ->
+ run_nodepair_test(
+ fun (A, B, Prefix, HA, HB) ->
+ throughput(A, B, Prefix, HA, HB, 100000, 1024)
+ end, Config).
+
+throughput_4096(Config) ->
+ run_nodepair_test(
+ fun (A, B, Prefix, HA, HB) ->
+ throughput(A, B, Prefix, HA, HB, 50000, 4096)
+ end, Config).
+
+throughput_16384(Config) ->
+ run_nodepair_test(
+ fun (A, B, Prefix, HA, HB) ->
+ throughput(A, B, Prefix, HA, HB, 10000, 16384)
+ end, Config).
+
+throughput_65536(Config) ->
+ run_nodepair_test(
+ fun (A, B, Prefix, HA, HB) ->
+ throughput(A, B, Prefix, HA, HB, 2000, 65536)
+ end, Config).
+
+throughput_262144(Config) ->
+ run_nodepair_test(
+ fun (A, B, Prefix, HA, HB) ->
+ throughput(A, B, Prefix, HA, HB, 500, 262144)
+ end, Config).
+
+throughput_1048576(Config) ->
+ run_nodepair_test(
+ fun (A, B, Prefix, HA, HB) ->
+ throughput(A, B, Prefix, HA, HB, 200, 1048576)
+ end, Config).
+
+throughput(A, B, Prefix, HA, HB, Packets, Size) ->
+ [] = ssl_apply(HA, erlang, nodes, []),
+ [] = ssl_apply(HB, erlang, nodes, []),
+ #{time := Time,
+ client_dist_stats := ClientDistStats,
+ client_msacc_stats := ClientMsaccStats,
+ client_prof := ClientProf,
+ server_msacc_stats := ServerMsaccStats,
+ server_prof := ServerProf,
+ server_gc_before := Server_GC_Before,
+ server_gc_after := Server_GC_After} =
+ ssl_apply(HA, fun () -> throughput_runner(A, B, Packets, Size) end),
+ [B] = ssl_apply(HA, erlang, nodes, []),
+ [A] = ssl_apply(HB, erlang, nodes, []),
+ ClientMsaccStats =:= undefined orelse
+ msacc:print(ClientMsaccStats),
+ io:format("ClientDistStats: ~p~n", [ClientDistStats]),
+ Overhead =
+ 50 % Distribution protocol headers (empirical) (TLS+=54)
+ + byte_size(erlang:term_to_binary([0|<<>>])), % Benchmark overhead
+ Bytes = Packets * (Size + Overhead),
+ io:format("~w bytes, ~.4g s~n", [Bytes,Time/1000000]),
+ SizeString = integer_to_list(Size),
+ ClientMsaccStats =:= undefined orelse
+ report(
+ Prefix ++ " Sender_RelativeCoreLoad_" ++ SizeString,
+ round(msacc:stats(system_runtime, ClientMsaccStats)
+ * 1000000 / Bytes),
+ "ps/byte"),
+ ServerMsaccStats =:= undefined orelse
+ begin
+ report(
+ Prefix ++ " Receiver_RelativeCoreLoad_" ++ SizeString,
+ round(msacc:stats(system_runtime, ServerMsaccStats)
+ * 1000000 / Bytes),
+ "ps/byte"),
+ msacc:print(ServerMsaccStats)
+ end,
+ io:format("******* ClientProf:~n", []), prof_print(ClientProf),
+ io:format("******* ServerProf:~n", []), prof_print(ServerProf),
+ io:format("******* Server GC Before:~n~p~n", [Server_GC_Before]),
+ io:format("******* Server GC After:~n~p~n", [Server_GC_After]),
+ Speed = round((Bytes * 1000000) / (1024 * Time)),
+ report(Prefix ++ " Throughput_" ++ SizeString, Speed, "kB/s").
+
+%% Runs on node A and spawns a server on node B
+throughput_runner(A, B, Rounds, Size) ->
+ Payload = payload(Size),
+ [A] = rpc:call(B, erlang, nodes, []),
+ ClientPid = self(),
+ ServerPid =
+ erlang:spawn_opt(
+ B,
+ fun () -> throughput_server(ClientPid, Rounds) end,
+ [{message_queue_data, off_heap}]),
+ ServerMon = erlang:monitor(process, ServerPid),
+ msacc_available() andalso
+ begin
+ msacc:stop(),
+ msacc:reset(),
+ msacc:start(),
+ ok
+ end,
+ prof_start(),
+ #{time := Time} = Result =
+ throughput_client(ServerPid, ServerMon, Payload, Rounds),
+ prof_stop(),
+ MsaccStats =
+ case msacc_available() of
+ true ->
+ MStats = msacc:stats(),
+ msacc:stop(),
+ MStats;
+ false ->
+ undefined
+ end,
+ Prof = prof_end(),
+ [{_Node,Socket}] = dig_dist_node_sockets(),
+ DistStats = inet:getstat(Socket),
+ Result#{time := microseconds(Time),
+ client_dist_stats => DistStats,
+ client_msacc_stats => MsaccStats,
+ client_prof => Prof}.
+
+dig_dist_node_sockets() ->
+ [case DistCtrl of
+ {_Node,Socket} = NodeSocket when is_port(Socket) ->
+ NodeSocket;
+ {Node,DistCtrlPid} when is_pid(DistCtrlPid) ->
+ [{links,DistCtrlLinks}] = process_info(DistCtrlPid, [links]),
+ case [S || S <- DistCtrlLinks, is_port(S)] of
+ [Socket] ->
+ {Node,Socket};
+ [] ->
+ [{monitors,[{process,DistSenderPid}]}] =
+ process_info(DistCtrlPid, [monitors]),
+ [{links,DistSenderLinks}] =
+ process_info(DistSenderPid, [links]),
+ [Socket] = [S || S <- DistSenderLinks, is_port(S)],
+ {Node,Socket}
+ end
+ end || DistCtrl <- erlang:system_info(dist_ctrl)].
+
+
+throughput_server(Pid, N) ->
+ GC_Before = get_server_gc_info(),
+ %% dbg:tracer(port, dbg:trace_port(file, "throughput_server_gc.log")),
+ %% dbg:p(TLSDistReceiver, garbage_collection),
+ msacc_available() andalso
+ begin
+ msacc:stop(),
+ msacc:reset(),
+ msacc:start(),
+ ok
+ end,
+ prof_start(),
+ throughput_server_loop(Pid, GC_Before, N).
+
+throughput_server_loop(_Pid, GC_Before, 0) ->
+ prof_stop(),
+ MsaccStats =
+ case msacc_available() of
+ true ->
+ msacc:stop(),
+ MStats = msacc:stats(),
+ msacc:reset(),
+ MStats;
+ false ->
+ undefined
+ end,
+ Prof = prof_end(),
+ %% dbg:flush_trace_port(),
+ exit(#{server_msacc_stats => MsaccStats,
+ server_prof => Prof,
+ server_gc_before => GC_Before,
+ server_gc_after => get_server_gc_info()});
+throughput_server_loop(Pid, GC_Before, N) ->
+ receive
+ Msg ->
+ case Msg of
+ {Pid, N, _} ->
+ throughput_server_loop(Pid, GC_Before, N - 1);
+ Other ->
+ erlang:error({self(),?FUNCTION_NAME,Other})
+ end
+ end.
+
+get_server_gc_info() ->
+ case whereis(ssl_connection_sup_dist) of
+ undefined ->
+ undefined;
+ SupPid ->
+ [{_Id,TLSDistReceiver,_Type,_Modules}|_] =
+ supervisor:which_children(SupPid),
+ erlang:process_info(
+ TLSDistReceiver, [garbage_collection,garbage_collection_info])
+ end.
+
+throughput_client(Pid, Mon, Payload, N) ->
+ throughput_client_loop(Pid, Mon, Payload, N, start_time()).
+
+throughput_client_loop(_Pid, Mon, _Payload, 0, StartTime) ->
+ receive
+ {'DOWN', Mon, _, _, #{} = Result} ->
+ Result#{time => elapsed_time(StartTime)};
+ {'DOWN', Mon, _, _, Other} ->
+ exit(Other)
+ end;
+throughput_client_loop(Pid, Mon, Payload, N, StartTime) ->
+ Pid ! {self(), N, Payload},
+ throughput_client_loop(Pid, Mon, Payload, N - 1, StartTime).
+
+
+-define(prof, none). % none | cprof | eprof
+
+-if(?prof =:= cprof).
+prof_start() ->
+ cprof:stop(),
+ cprof:start(),
+ ok.
+-elif(?prof =:= eprof).
+prof_start() ->
+ catch eprof:stop(),
+ {ok,_} = eprof:start(),
+ profiling = eprof:start_profiling(processes()),
+ ok.
+-elif(?prof =:= none).
+prof_start() ->
+ ok.
+-endif.
+
+-if(?prof =:= cprof).
+prof_stop() ->
+ cprof:pause(),
+ ok.
+-elif(?prof =:= eprof).
+prof_stop() ->
+ _ = eprof:stop_profiling(),
+ ok.
+-elif(?prof =:= none).
+prof_stop() ->
+ ok.
+-endif.
+
+-if(?prof =:= cprof).
+prof_end() ->
+ Prof = cprof:analyse(),
+ cprof:stop(),
+ Prof.
+-elif(?prof =:= eprof).
+prof_end() ->
+ eprof:dump_data().
+-elif(?prof =:= none).
+prof_end() ->
+ [].
+-endif.
+
+-if(?prof =:= cprof).
+prof_print(Prof) ->
+ io:format("~p.~n", [Prof]).
+-elif(?prof =:= eprof).
+prof_print(Dump) ->
+ eprof:analyze(undefined, total, [], Dump).
+-elif(?prof =:= none).
+prof_print([]) ->
+ ok.
+-endif.
+
+%%%-------------------------------------------------------------------
+%%% Test cases helpers
+
+run_nodepair_test(TestFun, Config) ->
+ A = proplists:get_value(node_a, Config),
+ B = proplists:get_value(node_b, Config),
+ Prefix = proplists:get_value(ssl_dist_prefix, Config),
+ HA = start_ssl_node_a(Config),
+ HB = start_ssl_node_b(Config),
+ try TestFun(A, B, Prefix, HA, HB)
+ after
+ stop_ssl_node_a(HA),
+ stop_ssl_node_b(HB, Config),
+ ok
+ end.
+
+ssl_apply(Handle, M, F, Args) ->
+ case ssl_dist_test_lib:apply_on_ssl_node(Handle, M, F, Args) of
+ {'EXIT',Reason} ->
+ error(Reason);
+ Result ->
+ Result
+ end.
+
+ssl_apply(Handle, Fun) ->
+ case ssl_dist_test_lib:apply_on_ssl_node(Handle, Fun) of
+ {'EXIT',Reason} ->
+ error(Reason);
+ Result ->
+ Result
+ end.
+
+start_ssl_node_a(Config) ->
+ Name = proplists:get_value(node_a_name, Config),
+ Args = get_node_args(node_a_dist_args, Config),
+ ssl_dist_test_lib:start_ssl_node(Name, Args).
+
+start_ssl_node_b(Config) ->
+ Name = proplists:get_value(node_b_name, Config),
+ Args = get_node_args(node_b_dist_args, Config),
+ ServerNode = proplists:get_value(server_node, Config),
+ rpc:call(
+ ServerNode, ssl_dist_test_lib, start_ssl_node, [Name, Args]).
+
+stop_ssl_node_a(HA) ->
+ ssl_dist_test_lib:stop_ssl_node(HA).
+
+stop_ssl_node_b(HB, Config) ->
+ ServerNode = proplists:get_value(server_node, Config),
+ rpc:call(ServerNode, ssl_dist_test_lib, stop_ssl_node, [HB]).
+
+get_node_args(Tag, Config) ->
+ case proplists:get_value(ssl_dist, Config) of
+ true ->
+ proplists:get_value(Tag, Config);
+ false ->
+ proplists:get_value(ssl_dist_args, Config, "")
+ end.
+
+
+
+payload(Size) ->
+ iolist_to_binary(
+ [case Size bsr 8 of
+ 0 ->
+ [];
+ Blocks ->
+ payload(Blocks, create_binary(256))
+ end | create_binary(Size band 255)]).
+%%
+payload(0, _) ->
+ [];
+payload(Blocks, Block) ->
+ Half = payload(Blocks bsr 1, Block),
+ [Half, Half |
+ if
+ Blocks band 1 =:= 1 ->
+ Block;
+ true ->
+ []
+ end].
+
+create_binary(Size) ->
+ create_binary(Size, <<>>).
+%%
+create_binary(0, Bin) ->
+ Bin;
+create_binary(Size, Bin) ->
+ NextSize = Size - 1,
+ create_binary(NextSize, <<Bin/binary, NextSize>>).
+
+start_time() ->
+ erlang:system_time().
+
+elapsed_time(StartTime) ->
+ erlang:system_time() - StartTime.
+
+microseconds(Time) ->
+ erlang:convert_time_unit(Time, native, microsecond).
+
+report(Name, Value, Unit) ->
+ ct:pal("~s: ~w ~s", [Name, Value, Unit]),
+ ct_event:notify(
+ #event{
+ name = benchmark_data,
+ data = [{value, Value}, {suite, "ssl_dist"}, {name, Name}]}),
+ {comment, term_to_string(Value) ++ " " ++ Unit}.
+
+term_to_string(Term) ->
+ unicode:characters_to_list(
+ io_lib:write(Term, [{encoding, unicode}])).
+
+msacc_available() ->
+ msacc:available().
diff --git a/lib/ssl/test/ssl_dist_test_lib.erl b/lib/ssl/test/ssl_dist_test_lib.erl
new file mode 100644
index 0000000000..b8b805b2c4
--- /dev/null
+++ b/lib/ssl/test/ssl_dist_test_lib.erl
@@ -0,0 +1,346 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(ssl_dist_test_lib).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
+-include("ssl_dist_test_lib.hrl").
+
+-export([tstsrvr_format/2, send_to_tstcntrl/1]).
+-export([apply_on_ssl_node/4, apply_on_ssl_node/2]).
+-export([stop_ssl_node/1, start_ssl_node/2]).
+%%
+-export([cnct2tstsrvr/1]).
+
+-define(AWAIT_SSL_NODE_UP_TIMEOUT, 30000).
+
+
+
+%% ssl_node side api
+%%
+
+tstsrvr_format(Fmt, ArgList) ->
+ send_to_tstsrvr({format, Fmt, ArgList}).
+
+send_to_tstcntrl(Message) ->
+ send_to_tstsrvr({message, Message}).
+
+
+%%
+%% test_server side api
+%%
+
+apply_on_ssl_node(
+ #node_handle{connection_handler = Hndlr} = Node,
+ M, F, A) when is_atom(M), is_atom(F), is_list(A) ->
+ Ref = erlang:monitor(process, Hndlr),
+ apply_on_ssl_node(Node, Ref, {apply, self(), Ref, M, F, A}).
+
+apply_on_ssl_node(
+ #node_handle{connection_handler = Hndlr} = Node,
+ Fun) when is_function(Fun, 0) ->
+ Ref = erlang:monitor(process, Hndlr),
+ apply_on_ssl_node(Node, Ref, {apply, self(), Ref, Fun}).
+
+apply_on_ssl_node(Node, Ref, Msg) ->
+ send_to_ssl_node(Node, Msg),
+ receive
+ {'DOWN', Ref, process, Hndlr, Reason} ->
+ exit({handler_died, Hndlr, Reason});
+ {Ref, Result} ->
+ Result
+ end.
+
+stop_ssl_node(#node_handle{connection_handler = Handler,
+ socket = Socket,
+ name = Name}) ->
+ ?t:format("Trying to stop ssl node ~s.~n", [Name]),
+ Mon = erlang:monitor(process, Handler),
+ unlink(Handler),
+ case gen_tcp:send(Socket, term_to_binary(stop)) of
+ ok ->
+ receive
+ {'DOWN', Mon, process, Handler, Reason} ->
+ case Reason of
+ normal ->
+ ok;
+ _ ->
+ ct:pal(
+ "stop_ssl_node/1 ~s Down ~p ~n",
+ [Name,Reason])
+ end
+ end;
+ Error ->
+ erlang:demonitor(Mon, [flush]),
+ ct:pal("stop_ssl_node/1 ~s Warning ~p ~n", [Name,Error])
+ end.
+
+start_ssl_node(Name, Args) ->
+ {ok, LSock} = gen_tcp:listen(0,
+ [binary, {packet, 4}, {active, false}]),
+ {ok, ListenPort} = inet:port(LSock),
+ CmdLine = mk_node_cmdline(ListenPort, Name, Args),
+ ?t:format("Attempting to start ssl node ~ts: ~ts~n", [Name, CmdLine]),
+ case open_port({spawn, CmdLine}, []) of
+ Port when is_port(Port) ->
+ unlink(Port),
+ erlang:port_close(Port),
+ case await_ssl_node_up(Name, LSock) of
+ #node_handle{} = NodeHandle ->
+ ?t:format("Ssl node ~s started.~n", [Name]),
+ NodeName = list_to_atom(Name ++ "@" ++ host_name()),
+ NodeHandle#node_handle{nodename = NodeName};
+ Error ->
+ exit({failed_to_start_node, Name, Error})
+ end;
+ Error ->
+ exit({failed_to_start_node, Name, Error})
+ end.
+
+host_name() ->
+ [_, Host] = string:split(atom_to_list(node()), "@"),
+ %% [$@ | Host] = lists:dropwhile(fun ($@) -> false; (_) -> true end,
+ %% atom_to_list(node())),
+ Host.
+
+mk_node_cmdline(ListenPort, Name, Args) ->
+ Static = "-detached -noinput",
+ Pa = filename:dirname(code:which(?MODULE)),
+ Prog = case catch init:get_argument(progname) of
+ {ok,[[P]]} -> P;
+ _ -> exit(no_progname_argument_found)
+ end,
+ NameSw = case net_kernel:longnames() of
+ false -> "-sname ";
+ _ -> "-name "
+ end,
+ {ok, Pwd} = file:get_cwd(),
+ "\"" ++ Prog ++ "\" "
+ ++ Static ++ " "
+ ++ NameSw ++ " " ++ Name ++ " "
+ ++ "-pa " ++ Pa ++ " "
+ ++ "-run application start crypto -run application start public_key "
+ ++ "-eval 'net_kernel:verbose(1)' "
+ ++ "-run " ++ atom_to_list(?MODULE) ++ " cnct2tstsrvr "
+ ++ host_name() ++ " "
+ ++ integer_to_list(ListenPort) ++ " "
+ ++ Args ++ " "
+ ++ "-env ERL_CRASH_DUMP " ++ Pwd ++ "/erl_crash_dump." ++ Name ++ " "
+ ++ "-kernel inet_dist_connect_options \"[{recbuf,12582912},{sndbuf,12582912},{high_watermark,8388608},{low_watermark,4194304}]\" "
+ ++ "-kernel inet_dist_listen_options \"[{recbuf,12582912},{sndbuf,12582912},{high_watermark,8388608},{low_watermark,4194304}]\" "
+ ++ "-kernel error_logger \"{file,\\\"" ++ Pwd ++ "/error_log." ++ Name ++ "\\\"}\" "
+ ++ "-setcookie " ++ atom_to_list(erlang:get_cookie()).
+
+%%
+%% Connection handler test_server side
+%%
+
+await_ssl_node_up(Name, LSock) ->
+ case gen_tcp:accept(LSock, ?AWAIT_SSL_NODE_UP_TIMEOUT) of
+ {ok, Socket} ->
+ gen_tcp:close(LSock),
+ case gen_tcp:recv(Socket, 0) of
+ {ok, Bin} ->
+ check_ssl_node_up(Socket, Name, Bin);
+ {error, closed} ->
+ gen_tcp:close(Socket),
+ exit({lost_connection_with_ssl_node_before_up, Name})
+ end;
+ {error, Error} ->
+ gen_tcp:close(LSock),
+ ?t:format("Accept failed for ssl node ~s: ~p~n", [Name,Error]),
+ exit({accept_failed, Error})
+ end.
+
+check_ssl_node_up(Socket, Name, Bin) ->
+ case catch binary_to_term(Bin) of
+ {'EXIT', _} ->
+ gen_tcp:close(Socket),
+ exit({bad_data_received_from_ssl_node, Name, Bin});
+ {ssl_node_up, NodeName} ->
+ case list_to_atom(Name++"@"++host_name()) of
+ NodeName ->
+ Parent = self(),
+ Go = make_ref(),
+ %% Spawn connection handler on test server side
+ Pid = spawn(
+ fun () ->
+ link(group_leader()),
+ receive Go -> ok end,
+ process_flag(trap_exit, true),
+ tstsrvr_con_loop(Name, Socket, Parent)
+ end),
+ ok = gen_tcp:controlling_process(Socket, Pid),
+ Pid ! Go,
+ #node_handle{connection_handler = Pid,
+ socket = Socket,
+ name = Name};
+ _ ->
+ exit({unexpected_ssl_node_connected, NodeName})
+ end;
+ Msg ->
+ exit({unexpected_msg_instead_of_ssl_node_up, Name, Msg})
+ end.
+
+send_to_ssl_node(#node_handle{connection_handler = Hndlr}, Term) ->
+ Hndlr ! {relay_to_ssl_node, term_to_binary(Term)},
+ ok.
+
+tstsrvr_con_loop(Name, Socket, Parent) ->
+ ok = inet:setopts(Socket,[{active,once}]),
+ receive
+ {relay_to_ssl_node, Data} when is_binary(Data) ->
+ case gen_tcp:send(Socket, Data) of
+ ok ->
+ ok;
+ _Error ->
+ gen_tcp:close(Socket),
+ exit({failed_to_relay_data_to_ssl_node, Name, Data})
+ end;
+ {tcp, Socket, Bin} ->
+ try binary_to_term(Bin) of
+ {format, FmtStr, ArgList} ->
+ ?t:format(FmtStr, ArgList);
+ {message, Msg} ->
+ ?t:format("Got message ~p", [Msg]),
+ Parent ! Msg;
+ {apply_res, To, Ref, Res} ->
+ To ! {Ref, Res};
+ bye ->
+ {error, closed} = gen_tcp:recv(Socket, 0),
+ ?t:format("Ssl node ~s stopped.~n", [Name]),
+ gen_tcp:close(Socket),
+ exit(normal);
+ Unknown ->
+ exit({unexpected_message_from_ssl_node, Name, Unknown})
+ catch
+ error : _ ->
+ gen_tcp:close(Socket),
+ exit({bad_data_received_from_ssl_node, Name, Bin})
+ end;
+ {tcp_closed, Socket} ->
+ gen_tcp:close(Socket),
+ exit({lost_connection_with_ssl_node, Name});
+ {'EXIT', Parent, Reason} ->
+ exit({'EXIT', parent, Reason});
+ Unknown ->
+ exit({unknown, Unknown})
+ end,
+ tstsrvr_con_loop(Name, Socket, Parent).
+
+%%
+%% Connection handler ssl_node side
+%%
+
+% cnct2tstsrvr() is called via command line arg -run ...
+cnct2tstsrvr([Host, Port]) when is_list(Host), is_list(Port) ->
+ %% Spawn connection handler on ssl node side
+ ConnHandler
+ = spawn(fun () ->
+ case catch gen_tcp:connect(Host,
+ list_to_integer(Port),
+ [binary,
+ {packet, 4},
+ {active, false}]) of
+ {ok, Socket} ->
+ notify_ssl_node_up(Socket),
+ ets:new(test_server_info,
+ [set,
+ public,
+ named_table,
+ {keypos, 1}]),
+ ets:insert(test_server_info,
+ {test_server_handler, self()}),
+ ssl_node_con_loop(Socket);
+ Error ->
+ halt("Failed to connect to test server " ++
+ lists:flatten(io_lib:format("Host:~p ~n Port:~p~n Error:~p~n",
+ [Host, Port, Error])))
+ end
+ end),
+ spawn(fun () ->
+ Mon = erlang:monitor(process, ConnHandler),
+ receive
+ {'DOWN', Mon, process, ConnHandler, Reason} ->
+ receive after 1000 -> ok end,
+ halt("test server connection handler terminated: " ++
+ lists:flatten(io_lib:format("~p", [Reason])))
+ end
+ end).
+
+notify_ssl_node_up(Socket) ->
+ case catch gen_tcp:send(Socket,
+ term_to_binary({ssl_node_up, node()})) of
+ ok -> ok;
+ _ -> halt("Failed to notify test server that I'm up")
+ end.
+
+send_to_tstsrvr(Term) ->
+ case catch ets:lookup_element(test_server_info, test_server_handler, 2) of
+ Hndlr when is_pid(Hndlr) ->
+ Hndlr ! {relay_to_test_server, term_to_binary(Term)}, ok;
+ _ ->
+ receive after 200 -> ok end,
+ send_to_tstsrvr(Term)
+ end.
+
+ssl_node_con_loop(Socket) ->
+ inet:setopts(Socket,[{active,once}]),
+ receive
+ {relay_to_test_server, Data} when is_binary(Data) ->
+ case gen_tcp:send(Socket, Data) of
+ ok ->
+ ok;
+ _Error ->
+ gen_tcp:close(Socket),
+ halt("Failed to relay data to test server")
+ end;
+ {tcp, Socket, Bin} ->
+ case catch binary_to_term(Bin) of
+ {'EXIT', _} ->
+ gen_tcp:close(Socket),
+ halt("test server sent me bad data");
+ {apply, From, Ref, M, F, A} ->
+ spawn_link(
+ fun () ->
+ send_to_tstsrvr({apply_res,
+ From,
+ Ref,
+ (catch apply(M, F, A))})
+ end);
+ {apply, From, Ref, Fun} ->
+ spawn_link(fun () ->
+ send_to_tstsrvr({apply_res,
+ From,
+ Ref,
+ (catch Fun())})
+ end);
+ stop ->
+ gen_tcp:send(Socket, term_to_binary(bye)),
+ init:stop(),
+ receive after infinity -> ok end;
+ _Unknown ->
+ halt("test server sent me an unexpected message")
+ end;
+ {tcp_closed, Socket} ->
+ halt("Lost connection to test server")
+ end,
+ ssl_node_con_loop(Socket).
diff --git a/lib/ssl/test/ssl_dist_test_lib.hrl b/lib/ssl/test/ssl_dist_test_lib.hrl
new file mode 100644
index 0000000000..86b9b37026
--- /dev/null
+++ b/lib/ssl/test/ssl_dist_test_lib.hrl
@@ -0,0 +1,26 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-record(node_handle,
+ {connection_handler,
+ socket,
+ name,
+ nodename}
+ ).
diff --git a/lib/ssl/test/ssl_engine_SUITE.erl b/lib/ssl/test/ssl_engine_SUITE.erl
index 71891356e8..a39a62e550 100644
--- a/lib/ssl/test/ssl_engine_SUITE.erl
+++ b/lib/ssl/test/ssl_engine_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2017-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -46,10 +46,17 @@ init_per_suite(Config) ->
ssl_test_lib:clean_start(),
case crypto:get_test_engine() of
{ok, EngineName} ->
- try crypto:engine_load(<<"dynamic">>,
- [{<<"SO_PATH">>, EngineName},
- <<"LOAD">>],
- []) of
+ try
+ %% The test engine has it's own fake rsa sign/verify that
+ %% you don't want to use, so exclude it from methods to load:
+ Methods =
+ crypto:engine_get_all_methods() -- [engine_method_rsa],
+ crypto:engine_load(<<"dynamic">>,
+ [{<<"SO_PATH">>, EngineName},
+ <<"LOAD">>],
+ [],
+ Methods)
+ of
{ok, Engine} ->
[{engine, Engine} |Config];
{error, Reason} ->
@@ -90,12 +97,14 @@ end_per_testcase(_TestCase, Config) ->
private_key(Config) when is_list(Config) ->
ClientFileBase = filename:join([proplists:get_value(priv_dir, Config), "client_engine"]),
ServerFileBase = filename:join([proplists:get_value(priv_dir, Config), "server_engine"]),
+ Ext = x509_test:extensions([{key_usage, [digitalSignature, keyEncipherment]}]),
#{server_config := ServerConf,
client_config := ClientConf} = GenCertData =
public_key:pkix_test_data(#{server_chain =>
#{root => [{key, ssl_test_lib:hardcode_rsa_key(1)}],
intermediates => [[{key, ssl_test_lib:hardcode_rsa_key(2)}]],
- peer => [{key, ssl_test_lib:hardcode_rsa_key(3)}
+ peer => [{extensions, Ext},
+ {key, ssl_test_lib:hardcode_rsa_key(3)}
]},
client_chain =>
#{root => [{key, ssl_test_lib:hardcode_rsa_key(4)}],
@@ -117,8 +126,29 @@ private_key(Config) when is_list(Config) ->
EngineServerConf = [{key, #{algorithm => rsa,
engine => Engine,
key_id => ServerKey}} | proplists:delete(key, ServerConf)],
+
+ EngineFileClientConf = [{key, #{algorithm => rsa,
+ engine => Engine,
+ key_id => ClientKey}} |
+ proplists:delete(keyfile, FileClientConf)],
+
+ EngineFileServerConf = [{key, #{algorithm => rsa,
+ engine => Engine,
+ key_id => ServerKey}} |
+ proplists:delete(keyfile, FileServerConf)],
+
%% Test with engine
test_tls_connection(EngineServerConf, EngineClientConf, Config),
+
+ %% Test with engine and rsa keyexchange
+ RSASuites = all_kex_rsa_suites([{tls_version, 'tlsv1.2'} | Config]),
+
+ test_tls_connection([{ciphers, RSASuites}, {versions, ['tlsv1.2']} | EngineServerConf],
+ [{ciphers, RSASuites}, {versions, ['tlsv1.2']} | EngineClientConf], Config),
+
+ %% Test with engine and present file arugments
+ test_tls_connection(EngineFileServerConf, EngineFileClientConf, Config),
+
%% Test that sofware fallback is available
test_tls_connection(ServerConf, [{reuse_sessions, false} |ClientConf], Config).
@@ -145,3 +175,8 @@ test_tls_connection(ServerConf, ClientConf, Config) ->
ssl_test_lib:check_result(Server, ok, Client, ok),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
+
+all_kex_rsa_suites(Config) ->
+ Version = proplists:get_value(tls_version, Config),
+ All = ssl:cipher_suites(all, Version),
+ ssl:filter_cipher_suites(All,[{key_exchange, fun(rsa) -> true;(_) -> false end}]).
diff --git a/lib/ssl/test/ssl_eqc_SUITE.erl b/lib/ssl/test/ssl_eqc_SUITE.erl
new file mode 100644
index 0000000000..bfdb1a3d54
--- /dev/null
+++ b/lib/ssl/test/ssl_eqc_SUITE.erl
@@ -0,0 +1,70 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2015-2015. 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(ssl_eqc_SUITE).
+
+-compile(export_all).
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+all() ->
+ [
+ tls_handshake_encoding,
+ tls_cipher_suite_names,
+ tls_cipher_openssl_suite_names
+ ].
+
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ ct_property_test:init_per_suite(Config).
+end_per_suite(Config) ->
+ Config.
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_,Config) ->
+ Config.
+
+init_per_testcase(_, Config0) ->
+ Config0.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+tls_handshake_encoding(Config) when is_list(Config) ->
+ %% manual test: proper:quickcheck(ssl_eqc_handshake:prop_tls_hs_encode_decode()).
+ true = ct_property_test:quickcheck(ssl_eqc_handshake:prop_tls_hs_encode_decode(),
+ Config).
+
+tls_cipher_suite_names(Config) when is_list(Config) ->
+ %% manual test: proper:quickcheck(ssl_eqc_cipher_format:prop_tls_cipher_suite_rfc_name()).
+ true = ct_property_test:quickcheck(ssl_eqc_cipher_format:prop_tls_cipher_suite_rfc_name(),
+ Config).
+
+tls_cipher_openssl_suite_names(Config) when is_list(Config) ->
+ %% manual test: proper:quickcheck(ssl_eqc_handshake:prop_tls_cipher_suite_openssl_name()).
+ true = ct_property_test:quickcheck(ssl_eqc_cipher_format:prop_tls_cipher_suite_openssl_name(),
+ Config).
diff --git a/lib/ssl/test/ssl_handshake_SUITE.erl b/lib/ssl/test/ssl_handshake_SUITE.erl
index 9658cb5f56..1b432970b6 100644
--- a/lib/ssl/test/ssl_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_handshake_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,6 +25,8 @@
-compile(export_all).
-include_lib("common_test/include/ct.hrl").
+-include("ssl_alert.hrl").
+-include("ssl_handshake.hrl").
-include("ssl_internal.hrl").
-include("tls_handshake.hrl").
-include_lib("public_key/include/public_key.hrl").
@@ -33,7 +35,6 @@
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
all() -> [decode_hello_handshake,
- decode_hello_handshake_version_confusion,
decode_single_hello_extension_correctly,
decode_supported_elliptic_curves_hello_extension_correctly,
decode_unknown_hello_extension_correctly,
@@ -41,7 +42,9 @@ all() -> [decode_hello_handshake,
decode_single_hello_sni_extension_correctly,
decode_empty_server_sni_correctly,
select_proper_tls_1_2_rsa_default_hashsign,
- ignore_hassign_extension_pre_tls_1_2].
+ ignore_hassign_extension_pre_tls_1_2,
+ unorded_chain, signature_algorithms,
+ encode_decode_srp].
%%--------------------------------------------------------------------
init_per_suite(Config) ->
@@ -55,7 +58,9 @@ init_per_group(_GroupName, Config) ->
end_per_group(_,Config) ->
Config.
-init_per_testcase(ignore_hassign_extension_pre_tls_1_2, Config0) ->
+init_per_testcase(TC, Config0) when
+ TC =:= ignore_hassign_extension_pre_tls_1_2 orelse
+ TC =:= signature_algorithms ->
catch crypto:stop(),
try crypto:start() of
ok ->
@@ -101,25 +106,16 @@ decode_hello_handshake(_Config) ->
Version = {3, 0},
{Records, _Buffer} = tls_handshake:get_tls_handshake(Version, HelloPacket, <<>>,
- #ssl_options{v2_hello_compatible = false}),
+ #ssl_options{}),
{Hello, _Data} = hd(Records),
- #renegotiation_info{renegotiated_connection = <<0>>}
- = (Hello#server_hello.extensions)#hello_extensions.renegotiation_info.
-
-
-decode_hello_handshake_version_confusion(_) ->
- HelloPacket = <<3,3,0,0,0,0,0,63,210,235,149,6,244,140,108,13,177,74,16,218,33,108,219,41,73,228,3,82,132,123,73,144,118,100,0,0,32,192,4,0,10,192,45,192,38,0,47,192,18,0,163,0,22,0,165,192,29,192,18,192,30,0,103,0,57,192,48,0,47,1,0>>,
- Version = {3,3},
- ClientHello = 1,
- Hello = tls_handshake:decode_handshake({3,3}, ClientHello, HelloPacket, false),
- Hello = tls_handshake:decode_handshake({3,3}, ClientHello, HelloPacket, true).
+ Extensions = Hello#server_hello.extensions,
+ #{renegotiation_info := #renegotiation_info{renegotiated_connection = <<0>>}} = Extensions.
decode_single_hello_extension_correctly(_Config) ->
Renegotiation = <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(1), 0>>,
- Extensions = ssl_handshake:decode_hello_extensions(Renegotiation),
- #renegotiation_info{renegotiated_connection = <<0>>}
- = Extensions#hello_extensions.renegotiation_info.
+ Extensions = ssl_handshake:decode_extensions(Renegotiation, {3,3}, undefined),
+ #{renegotiation_info := #renegotiation_info{renegotiated_connection = <<0>>}} = Extensions.
decode_supported_elliptic_curves_hello_extension_correctly(_Config) ->
% List of supported and unsupported curves (RFC4492:S5.1.1)
@@ -130,37 +126,34 @@ decode_supported_elliptic_curves_hello_extension_correctly(_Config) ->
Len = ListLen + 2,
Extension = <<?UINT16(?ELLIPTIC_CURVES_EXT), ?UINT16(Len), ?UINT16(ListLen), EllipticCurveList/binary>>,
% after decoding we should see only valid curves
- #hello_extensions{elliptic_curves = DecodedCurves} = ssl_handshake:decode_hello_extensions(Extension),
- #elliptic_curves{elliptic_curve_list = [?sect233k1, ?sect193r2]} = DecodedCurves.
+ Extensions = ssl_handshake:decode_hello_extensions(Extension, {3,2}, {3,2}, client),
+ #{elliptic_curves := #elliptic_curves{elliptic_curve_list = [?sect233k1, ?sect193r2]}} = Extensions.
decode_unknown_hello_extension_correctly(_Config) ->
FourByteUnknown = <<16#CA,16#FE, ?UINT16(4), 3, 0, 1, 2>>,
Renegotiation = <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(1), 0>>,
- Extensions = ssl_handshake:decode_hello_extensions(<<FourByteUnknown/binary, Renegotiation/binary>>),
- #renegotiation_info{renegotiated_connection = <<0>>}
- = Extensions#hello_extensions.renegotiation_info.
+ Extensions = ssl_handshake:decode_hello_extensions(<<FourByteUnknown/binary, Renegotiation/binary>>, {3,2}, {3,2}, client),
+ #{renegotiation_info := #renegotiation_info{renegotiated_connection = <<0>>}} = Extensions.
+
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),
+ Encoded = ssl_handshake:encode_extensions([#sni{hostname = "test.com"}]),
HelloExt = Encoded.
decode_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>>,
- Decoded = ssl_handshake:decode_hello_extensions(SNI),
- Exts = Decoded.
+ Decoded = ssl_handshake:decode_hello_extensions(SNI, {3,3}, {3,3}, client),
+ #{sni := #sni{hostname = "test.com"}} = Decoded.
decode_empty_server_sni_correctly(_Config) ->
- Exts = #hello_extensions{sni = ""},
SNI = <<?UINT16(?SNI_EXT),?UINT16(0)>>,
- Decoded = ssl_handshake:decode_hello_extensions(SNI),
- Exts = Decoded.
+ Decoded = ssl_handshake:decode_hello_extensions(SNI, {3,3}, {3,3}, server),
+ #{sni := #sni{hostname = ""}} = Decoded.
select_proper_tls_1_2_rsa_default_hashsign(_Config) ->
@@ -175,11 +168,107 @@ ignore_hassign_extension_pre_tls_1_2(Config) ->
Opts = proplists:get_value(server_opts, Config),
CertFile = proplists:get_value(certfile, Opts),
[{_, Cert, _}] = ssl_test_lib:pem_to_der(CertFile),
- HashSigns = #hash_sign_algos{hash_sign_algos = [{sha512, rsa}, {sha, dsa}]},
- {sha512, rsa} = ssl_handshake:select_hashsign(HashSigns, Cert, ecdhe_rsa, tls_v1:default_signature_algs({3,3}), {3,3}),
+ HashSigns = #hash_sign_algos{hash_sign_algos = [{sha512, rsa}, {sha, dsa}, {sha, rsa}]},
+ {sha512, rsa} = ssl_handshake:select_hashsign({HashSigns, undefined}, Cert, ecdhe_rsa, tls_v1:default_signature_algs({3,3}), {3,3}),
%%% Ignore
- {md5sha, rsa} = ssl_handshake:select_hashsign(HashSigns, Cert, ecdhe_rsa, tls_v1:default_signature_algs({3,2}), {3,2}),
- {md5sha, rsa} = ssl_handshake:select_hashsign(HashSigns, Cert, ecdhe_rsa, tls_v1:default_signature_algs({3,0}), {3,0}).
+ {md5sha, rsa} = ssl_handshake:select_hashsign({HashSigns, undefined}, Cert, ecdhe_rsa, tls_v1:default_signature_algs({3,2}), {3,2}),
+ {md5sha, rsa} = ssl_handshake:select_hashsign({HashSigns, undefined}, Cert, ecdhe_rsa, tls_v1:default_signature_algs({3,0}), {3,0}).
+
+unorded_chain(Config) when is_list(Config) ->
+ DefConf = ssl_test_lib:default_cert_chain_conf(),
+ CertChainConf = ssl_test_lib:gen_conf(rsa, rsa, DefConf, DefConf),
+ #{server_config := ServerConf,
+ client_config := _ClientConf} = public_key:pkix_test_data(CertChainConf),
+ PeerCert = proplists:get_value(cert, ServerConf),
+ CaCerts = [_, C1, C2] = proplists:get_value(cacerts, ServerConf),
+ {ok, ExtractedCerts} = ssl_pkix_db:extract_trusted_certs({der, CaCerts}),
+ UnordedChain = case public_key:pkix_is_self_signed(C1) of
+ true ->
+ [C1, C2];
+ false ->
+ [C2, C1]
+ end,
+ OrderedChain = [PeerCert | lists:reverse(UnordedChain)],
+ {ok, _, OrderedChain} =
+ ssl_certificate:certificate_chain(PeerCert, ets:new(foo, []), ExtractedCerts, UnordedChain).
+
+encode_decode_srp(_Config) ->
+ Exts = #{srp => #srp{username = <<"foo">>},
+ sni => #sni{hostname = "bar"},
+ renegotiation_info => undefined,
+ signature_algs => undefined,
+ alpn => undefined,
+ next_protocol_negotiation => undefined,
+ ec_point_formats => undefined,
+ elliptic_curves => undefined
+ },
+ EncodedExts0 = <<0,20, % Length
+ 0,12, % SRP extension
+ 0,4, % Length
+ 3, % srp_I length
+ 102,111,111, % username = "foo"
+ 0,0, % SNI extension
+ 0,8, % Length
+ 0,6, % ServerNameLength
+ 0, % NameType (host_name)
+ 0,3, % HostNameLength
+ 98,97,114>>, % hostname = "bar"
+ EncodedExts0 = <<?UINT16(_),EncodedExts/binary>> =
+ ssl_handshake:encode_hello_extensions(Exts),
+ Exts = ssl_handshake:decode_hello_extensions(EncodedExts, {3,3}, {3,3}, client).
+
+signature_algorithms(Config) ->
+ Opts = proplists:get_value(server_opts, Config),
+ CertFile = proplists:get_value(certfile, Opts),
+ io:format("Cert = ~p~n", [CertFile]),
+ [{_, Cert, _}] = ssl_test_lib:pem_to_der(CertFile),
+ HashSigns0 = #hash_sign_algos{
+ hash_sign_algos = [{sha512, rsa},
+ {sha, dsa},
+ {sha, rsa}]},
+ Schemes0 = #signature_algorithms_cert{
+ signature_scheme_list = [rsa_pkcs1_sha1,
+ ecdsa_sha1]},
+ {sha512, rsa} = ssl_handshake:select_hashsign(
+ {HashSigns0, Schemes0},
+ Cert, ecdhe_rsa,
+ tls_v1:default_signature_algs({3,3}),
+ {3,3}),
+ HashSigns1 = #hash_sign_algos{
+ hash_sign_algos = [{sha, dsa},
+ {sha, rsa}]},
+ {sha, rsa} = ssl_handshake:select_hashsign(
+ {HashSigns1, Schemes0},
+ Cert, ecdhe_rsa,
+ tls_v1:default_signature_algs({3,3}),
+ {3,3}),
+ Schemes1 = #signature_algorithms_cert{
+ signature_scheme_list = [rsa_pkcs1_sha256,
+ ecdsa_sha1]},
+ %% Signature not supported
+ #alert{} = ssl_handshake:select_hashsign(
+ {HashSigns1, Schemes1},
+ Cert, ecdhe_rsa,
+ tls_v1:default_signature_algs({3,3}),
+ {3,3}),
+ %% No scheme, hashsign is used
+ {sha, rsa} = ssl_handshake:select_hashsign(
+ {HashSigns1, undefined},
+ Cert, ecdhe_rsa,
+ tls_v1:default_signature_algs({3,3}),
+ {3,3}),
+ HashSigns2 = #hash_sign_algos{
+ hash_sign_algos = [{sha, dsa}]},
+ %% Signature not supported
+ #alert{} = ssl_handshake:select_hashsign(
+ {HashSigns2, Schemes1},
+ Cert, ecdhe_rsa,
+ tls_v1:default_signature_algs({3,3}),
+ {3,3}).
+
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
is_supported(Hash) ->
Algos = crypto:supports(),
diff --git a/lib/ssl/test/ssl_npn_handshake_SUITE.erl b/lib/ssl/test/ssl_npn_handshake_SUITE.erl
index 6bf2aa2786..878e983bb9 100644
--- a/lib/ssl/test/ssl_npn_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_npn_handshake_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -64,13 +64,12 @@ next_protocol_not_supported() ->
npn_not_supported_server
].
-init_per_suite(Config) ->
+init_per_suite(Config0) ->
catch crypto:stop(),
try crypto:start() of
ok ->
ssl_test_lib:clean_start(),
- {ok, _} = make_certs:all(proplists:get_value(data_dir, Config),
- proplists:get_value(priv_dir, Config)),
+ Config = ssl_test_lib:make_rsa_cert(Config0),
ssl_test_lib:cert_options(Config)
catch _:_ ->
{skip, "Crypto did not start"}
@@ -196,10 +195,10 @@ client_negotiate_server_does_not_support(Config) when is_list(Config) ->
renegotiate_from_client_after_npn_handshake(Config) when is_list(Config) ->
Data = "hello world",
- ClientOpts0 = ssl_test_lib:ssl_options(client_opts, Config),
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
ClientOpts = [{client_preferred_next_protocols,
{client, [<<"http/1.0">>], <<"http/1.1">>}}] ++ ClientOpts0,
- ServerOpts0 = ssl_test_lib:ssl_options(server_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
ServerOpts = [{next_protocols_advertised,
[<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}] ++ ServerOpts0,
ExpectedProtocol = {ok, <<"http/1.0">>},
@@ -221,7 +220,7 @@ renegotiate_from_client_after_npn_handshake(Config) when is_list(Config) ->
%--------------------------------------------------------------------------------
npn_not_supported_client(Config) when is_list(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_opts, Config),
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
PrefProtocols = {client_preferred_next_protocols,
{client, [<<"http/1.0">>], <<"http/1.1">>}},
ClientOpts = [PrefProtocols] ++ ClientOpts0,
@@ -236,7 +235,7 @@ npn_not_supported_client(Config) when is_list(Config) ->
%--------------------------------------------------------------------------------
npn_not_supported_server(Config) when is_list(Config)->
- ServerOpts0 = ssl_test_lib:ssl_options(server_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
AdvProtocols = {next_protocols_advertised, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]},
ServerOpts = [AdvProtocols] ++ ServerOpts0,
@@ -244,63 +243,24 @@ npn_not_supported_server(Config) when is_list(Config)->
%--------------------------------------------------------------------------------
npn_handshake_session_reused(Config) when is_list(Config)->
- ClientOpts0 = ssl_test_lib:ssl_options(client_opts, Config),
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
ClientOpts = [{client_preferred_next_protocols,
{client, [<<"http/1.0">>], <<"http/1.1">>}}] ++ ClientOpts0,
- ServerOpts0 = ssl_test_lib:ssl_options(server_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
ServerOpts =[{next_protocols_advertised,
[<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}] ++ ServerOpts0,
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, session_info_result, []}},
- {options, ServerOpts}]),
-
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, no_result_msg, []}},
- {options, ClientOpts}]),
-
- SessionInfo =
- receive
- {Server, Info} ->
- Info
- end,
-
- Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
-
- %% Make sure session is registered
- ct:sleep(?SLEEP),
-
- Client1 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, session_info_result, []}},
- {from, self()}, {options, ClientOpts}]),
-
- receive
- {Client1, SessionInfo} ->
- ok;
- {Client1, Other} ->
- ct:fail(Other)
- end,
+ ssl_test_lib:reuse_session(ClientOpts, ServerOpts, Config).
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client),
- ssl_test_lib:close(Client1).
-
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
run_npn_handshake(Config, ClientExtraOpts, ServerExtraOpts, ExpectedProtocol) ->
Data = "hello world",
- ClientOpts0 = ssl_test_lib:ssl_options(client_opts, Config),
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
ClientOpts = ClientExtraOpts ++ ClientOpts0,
- ServerOpts0 = ssl_test_lib:ssl_options(server_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
ServerOpts = ServerExtraOpts ++ ServerOpts0,
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
diff --git a/lib/ssl/test/ssl_npn_hello_SUITE.erl b/lib/ssl/test/ssl_npn_hello_SUITE.erl
index 35af666e9e..46734ba180 100644
--- a/lib/ssl/test/ssl_npn_hello_SUITE.erl
+++ b/lib/ssl/test/ssl_npn_hello_SUITE.erl
@@ -71,44 +71,46 @@ encode_and_decode_client_hello_test(Config) ->
Version = ssl_test_lib:protocol_version(Config),
{[{DecodedHandshakeMessage, _Raw}], _} =
tls_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>, #ssl_options{}),
- NextProtocolNegotiation = (DecodedHandshakeMessage#client_hello.extensions)#hello_extensions.next_protocol_negotiation,
- NextProtocolNegotiation = undefined.
+ Extensions = DecodedHandshakeMessage#client_hello.extensions,
+ #{next_protocol_negotiation := undefined} = Extensions.
%%--------------------------------------------------------------------
encode_and_decode_npn_client_hello_test(Config) ->
HandShakeData = create_client_handshake(#next_protocol_negotiation{extension_data = <<>>}),
Version = ssl_test_lib:protocol_version(Config),
{[{DecodedHandshakeMessage, _Raw}], _} =
tls_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>, #ssl_options{}),
- NextProtocolNegotiation = (DecodedHandshakeMessage#client_hello.extensions)#hello_extensions.next_protocol_negotiation,
- NextProtocolNegotiation = #next_protocol_negotiation{extension_data = <<>>}.
+ Extensions = DecodedHandshakeMessage#client_hello.extensions,
+ #{next_protocol_negotiation := #next_protocol_negotiation{extension_data = <<>>}} = Extensions.
%%--------------------------------------------------------------------
encode_and_decode_server_hello_test(Config) ->
HandShakeData = create_server_handshake(undefined),
Version = ssl_test_lib:protocol_version(Config),
{[{DecodedHandshakeMessage, _Raw}], _} =
tls_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>, #ssl_options{}),
- NextProtocolNegotiation = (DecodedHandshakeMessage#server_hello.extensions)#hello_extensions.next_protocol_negotiation,
- NextProtocolNegotiation = undefined.
+ Extensions = DecodedHandshakeMessage#server_hello.extensions,
+ #{next_protocol_negotiation := undefined} = Extensions.
+
%%--------------------------------------------------------------------
encode_and_decode_npn_server_hello_test(Config) ->
HandShakeData = create_server_handshake(#next_protocol_negotiation{extension_data = <<6, "spdy/2">>}),
Version = ssl_test_lib:protocol_version(Config),
{[{DecodedHandshakeMessage, _Raw}], _} =
tls_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>, #ssl_options{}),
- NextProtocolNegotiation = (DecodedHandshakeMessage#server_hello.extensions)#hello_extensions.next_protocol_negotiation,
- ct:log("~p ~n", [NextProtocolNegotiation]),
- NextProtocolNegotiation = #next_protocol_negotiation{extension_data = <<6, "spdy/2">>}.
+ Extensions = DecodedHandshakeMessage#server_hello.extensions,
+ ct:log("~p ~n", [Extensions]),
+ #{next_protocol_negotiation := #next_protocol_negotiation{extension_data = <<6, "spdy/2">>}} = Extensions.
%%--------------------------------------------------------------------
create_server_hello_with_no_advertised_protocols_test(_Config) ->
- Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(), #hello_extensions{}),
- undefined = (Hello#server_hello.extensions)#hello_extensions.next_protocol_negotiation.
+ Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(), #{}),
+ Extensions = Hello#server_hello.extensions,
+ #{} = Extensions.
%%--------------------------------------------------------------------
create_server_hello_with_advertised_protocols_test(_Config) ->
Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(),
- #hello_extensions{next_protocol_negotiation = [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>]}),
- [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>] =
- (Hello#server_hello.extensions)#hello_extensions.next_protocol_negotiation.
+ #{next_protocol_negotiation => [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>]}),
+ Extensions = Hello#server_hello.extensions,
+ #{next_protocol_negotiation := [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>]} = Extensions.
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
@@ -120,9 +122,8 @@ create_client_handshake(Npn) ->
session_id = <<>>,
cipher_suites = [?TLS_DHE_DSS_WITH_DES_CBC_SHA],
compression_methods = "",
- extensions = #hello_extensions{
- next_protocol_negotiation = Npn,
- renegotiation_info = #renegotiation_info{}}
+ extensions = #{next_protocol_negotiation => Npn,
+ renegotiation_info => #renegotiation_info{}}
}, Vsn).
create_server_handshake(Npn) ->
@@ -133,9 +134,8 @@ create_server_handshake(Npn) ->
session_id = <<>>,
cipher_suite = ?TLS_DHE_DSS_WITH_DES_CBC_SHA,
compression_method = 1,
- extensions = #hello_extensions{
- next_protocol_negotiation = Npn,
- renegotiation_info = #renegotiation_info{}}
+ extensions = #{next_protocol_negotiation => Npn,
+ renegotiation_info => #renegotiation_info{}}
}, Vsn).
create_connection_states() ->
@@ -146,5 +146,5 @@ create_connection_states() ->
}
},
current_read => #{secure_renegotiation => false
- }
+ }
}.
diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl
index 3261244ace..6d26b2df33 100644
--- a/lib/ssl/test/ssl_packet_SUITE.erl
+++ b/lib/ssl/test/ssl_packet_SUITE.erl
@@ -141,6 +141,7 @@ socket_active_packet_tests() ->
packet_4_active_some_big,
packet_wait_active,
packet_size_active,
+ packet_switch,
%% inet header option should be deprecated!
header_decode_one_byte_active,
header_decode_two_bytes_active,
@@ -702,6 +703,34 @@ packet_size_passive(Config) when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+packet_switch() ->
+ [{doc,"Test packet option {packet, 2} followd by {packet, 4}"}].
+
+packet_switch(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, send_switch_packet ,["Hello World", 4]}},
+ {options, [{nodelay, true},{packet, 2} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, recv_switch_packet, ["Hello World", 4]}},
+ {options, [{nodelay, true}, {packet, 2} |
+ ClientOpts]}]),
+
+ ssl_test_lib:check_result(Client, ok, Server, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+
%%--------------------------------------------------------------------
packet_cdr_decode() ->
[{doc,"Test setting the packet option {packet, cdr}, {mode, binary}"}].
@@ -2093,26 +2122,13 @@ active_once_packet(Socket, Data, N) ->
active_once_packet(Socket, Data, N-1).
active_raw(Socket, Data, N) ->
- active_raw(Socket, Data, N, []).
-
-active_raw(_Socket, _, 0, _) ->
+ active_raw(Socket, (length(Data) * N)).
+active_raw(_Socket, 0) ->
ok;
-active_raw(Socket, Data, N, Acc) ->
+active_raw(Socket, N) ->
receive
- {ssl, Socket, Byte} when length(Byte) == 1 ->
- receive
- {ssl, Socket, _} ->
- active_raw(Socket, Data, N -1)
- end;
- {ssl, Socket, Data} ->
- active_raw(Socket, Data, N-1, []);
- {ssl, Socket, Other} ->
- case Acc ++ Other of
- Data ->
- active_raw(Socket, Data, N-1, []);
- NewAcc ->
- active_raw(Socket, Data, NewAcc)
- end
+ {ssl, Socket, Bytes} ->
+ active_raw(Socket, N-length(Bytes))
end.
active_packet(Socket, _, 0) ->
@@ -2286,3 +2302,26 @@ client_reject_packet_opt(Config, PacketOpt) ->
ClientOpts]}]),
ssl_test_lib:check_result(Client, {error, {options, {not_supported, PacketOpt}}}).
+
+
+send_switch_packet(SslSocket, Data, NextPacket) ->
+ ssl:send(SslSocket, Data),
+ receive
+ {ssl, SslSocket, "Hello World"} ->
+ ssl:setopts(SslSocket, [{packet, NextPacket}]),
+ ssl:send(SslSocket, Data),
+ receive
+ {ssl, SslSocket, "Hello World"} ->
+ ok
+ end
+ end.
+recv_switch_packet(SslSocket, Data, NextPacket) ->
+ receive
+ {ssl, SslSocket, "Hello World"} ->
+ ssl:send(SslSocket, Data),
+ ssl:setopts(SslSocket, [{packet, NextPacket}]),
+ receive
+ {ssl, SslSocket, "Hello World"} ->
+ ssl:send(SslSocket, Data)
+ end
+ end.
diff --git a/lib/ssl/test/ssl_payload_SUITE.erl b/lib/ssl/test/ssl_payload_SUITE.erl
index ef05241759..27b9c258a0 100644
--- a/lib/ssl/test/ssl_payload_SUITE.erl
+++ b/lib/ssl/test/ssl_payload_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -64,14 +64,18 @@ payload_tests() ->
server_echos_active_huge,
client_echos_passive_huge,
client_echos_active_once_huge,
- client_echos_active_huge].
+ client_echos_active_huge,
+ client_active_once_server_close].
init_per_suite(Config) ->
catch crypto:stop(),
try crypto:start() of
ok ->
ssl_test_lib:clean_start(),
- {ok, _} = make_certs:all(proplists:get_value(data_dir, Config), proplists:get_value(priv_dir, Config)),
+ {ok, _} =
+ make_certs:all(
+ proplists:get_value(data_dir, Config),
+ proplists:get_value(priv_dir, Config)),
ssl_test_lib:cert_options(Config)
catch _:_ ->
{skip, "Crypto did not start"}
@@ -103,12 +107,13 @@ end_per_group(GroupName, Config) ->
Config
end.
-init_per_testcase(TestCase, Config) when TestCase == server_echos_passive_huge;
- TestCase == server_echos_active_once_huge;
- TestCase == server_echos_active_huge;
- TestCase == client_echos_passive_huge;
- TestCase == client_echos_active_once_huge;
- TestCase == client_echos_active_huge ->
+init_per_testcase(TestCase, Config)
+ when TestCase == server_echos_passive_huge;
+ TestCase == server_echos_active_once_huge;
+ TestCase == server_echos_active_huge;
+ TestCase == client_echos_passive_huge;
+ TestCase == client_echos_active_once_huge;
+ TestCase == client_echos_active_huge ->
case erlang:system_info(system_architecture) of
"sparc-sun-solaris2.10" ->
{skip,"Will take to long time on an old Sparc"};
@@ -117,12 +122,13 @@ init_per_testcase(TestCase, Config) when TestCase == server_echos_passive_huge;
Config
end;
-init_per_testcase(TestCase, Config) when TestCase == server_echos_passive_big;
- TestCase == server_echos_active_once_big;
- TestCase == server_echos_active_big;
- TestCase == client_echos_passive_big;
- TestCase == client_echos_active_once_big;
- TestCase == client_echos_active_big ->
+init_per_testcase(TestCase, Config)
+ when TestCase == server_echos_passive_big;
+ TestCase == server_echos_active_once_big;
+ TestCase == server_echos_active_big;
+ TestCase == client_echos_passive_big;
+ TestCase == client_echos_active_once_big;
+ TestCase == client_echos_active_big ->
ct:timetrap({seconds, 60}),
Config;
@@ -144,11 +150,10 @@ server_echos_passive_small(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Str = "1234567890",
-
- server_echos_passive(Str, 1000, ClientOpts, ServerOpts,
- ClientNode, ServerNode, Hostname).
+ %%
+ Data = binary:copy(<<"1234567890">>, 100),
+ server_echos_passive(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
%%--------------------------------------------------------------------
@@ -160,11 +165,10 @@ server_echos_active_once_small(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Str = "1234567890",
-
- server_echos_active_once(Str, 1000, ClientOpts, ServerOpts,
- ClientNode, ServerNode, Hostname).
+ %%
+ Data = binary:copy(<<"1234567890">>, 100),
+ server_echos_active_once(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
%%--------------------------------------------------------------------
@@ -176,11 +180,10 @@ server_echos_active_small(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Str = "1234567890",
-
- server_echos_active(Str, 1000, ClientOpts, ServerOpts,
- ClientNode, ServerNode, Hostname).
+ %%
+ Data = binary:copy(<<"1234567890">>, 100),
+ server_echos_active(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
%%--------------------------------------------------------------------
client_echos_passive_small() ->
@@ -191,11 +194,10 @@ client_echos_passive_small(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Str = "1234567890",
-
- client_echos_passive(Str, 1000, ClientOpts, ServerOpts, ClientNode,
- ServerNode, Hostname).
+ %%
+ Data = binary:copy(<<"1234567890">>, 100),
+ client_echos_passive(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
%%--------------------------------------------------------------------
client_echos_active_once_small() ->
@@ -206,11 +208,10 @@ client_echos_active_once_small(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Str = "1234567890",
-
- client_echos_active_once(Str, 1000, ClientOpts, ServerOpts, ClientNode,
- ServerNode, Hostname).
+ %%
+ Data = binary:copy(<<"1234567890">>, 100),
+ client_echos_active_once(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
%%--------------------------------------------------------------------
client_echos_active_small() ->
@@ -221,11 +222,10 @@ client_echos_active_small(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Str = "1234567890",
-
- client_echos_active(Str, 1000, ClientOpts, ServerOpts, ClientNode,
- ServerNode, Hostname).
+ %%
+ Data = binary:copy(<<"1234567890">>, 100),
+ client_echos_active(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
%%--------------------------------------------------------------------
@@ -237,11 +237,10 @@ server_echos_passive_big(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Str = "1234567890",
-
- server_echos_passive(Str, 50000, ClientOpts, ServerOpts, ClientNode,
- ServerNode, Hostname).
+ %%
+ Data = binary:copy(<<"1234567890">>, 5000),
+ server_echos_passive(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
%%--------------------------------------------------------------------
@@ -253,11 +252,10 @@ server_echos_active_once_big(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Str = "1234567890",
-
- server_echos_active_once(Str, 50000, ClientOpts, ServerOpts, ClientNode,
- ServerNode, Hostname).
+ %%
+ Data = binary:copy(<<"1234567890">>, 5000),
+ server_echos_active_once(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
%%--------------------------------------------------------------------
@@ -269,11 +267,10 @@ server_echos_active_big(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Str = "1234567890",
-
- server_echos_active(Str, 50000, ClientOpts, ServerOpts, ClientNode,
- ServerNode, Hostname).
+ %%
+ Data = binary:copy(<<"1234567890">>, 5000),
+ server_echos_active(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
%%--------------------------------------------------------------------
client_echos_passive_big() ->
@@ -284,11 +281,10 @@ client_echos_passive_big(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Str = "1234567890",
-
- client_echos_passive(Str, 50000, ClientOpts, ServerOpts, ClientNode,
- ServerNode, Hostname).
+ %%
+ Data = binary:copy(<<"1234567890">>, 5000),
+ client_echos_passive(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
%%--------------------------------------------------------------------
client_echos_active_once_big() ->
@@ -299,11 +295,10 @@ client_echos_active_once_big(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Str = "1234567890",
-
- client_echos_active_once(Str, 50000, ClientOpts, ServerOpts, ClientNode,
- ServerNode, Hostname).
+ %%
+ Data = binary:copy(<<"1234567890">>, 5000),
+ client_echos_active_once(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
%%--------------------------------------------------------------------
client_echos_active_big() ->
@@ -314,11 +309,10 @@ client_echos_active_big(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Str = "1234567890",
-
- client_echos_active(Str, 50000, ClientOpts, ServerOpts, ClientNode,
- ServerNode, Hostname).
+ %%
+ Data = binary:copy(<<"1234567890">>, 5000),
+ client_echos_active(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
%%--------------------------------------------------------------------
server_echos_passive_huge() ->
@@ -329,11 +323,10 @@ server_echos_passive_huge(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Str = "1234567890",
-
- server_echos_passive(Str, 500000, ClientOpts, ServerOpts, ClientNode,
- ServerNode, Hostname).
+ %%
+ Data = binary:copy(<<"1234567890">>, 50000),
+ server_echos_passive(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
%%--------------------------------------------------------------------
server_echos_active_once_huge() ->
@@ -344,11 +337,10 @@ server_echos_active_once_huge(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Str = "1234567890",
-
- server_echos_active_once(Str, 500000, ClientOpts, ServerOpts, ClientNode,
- ServerNode, Hostname).
+ %%
+ Data = binary:copy(<<"1234567890">>, 50000),
+ server_echos_active_once(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
%%--------------------------------------------------------------------
server_echos_active_huge() ->
@@ -359,11 +351,10 @@ server_echos_active_huge(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Str = "1234567890",
-
- server_echos_active(Str, 500000, ClientOpts, ServerOpts, ClientNode,
- ServerNode, Hostname).
+ %%
+ Data = binary:copy(<<"1234567890">>, 50000),
+ server_echos_active(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
%%--------------------------------------------------------------------
client_echos_passive_huge() ->
@@ -374,10 +365,10 @@ client_echos_passive_huge(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Str = "1234567890",
- client_echos_passive(Str, 500000, ClientOpts, ServerOpts, ClientNode,
- ServerNode, Hostname).
+ %%
+ Data = binary:copy(<<"1234567890">>, 50000),
+ client_echos_passive(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
%%--------------------------------------------------------------------
client_echos_active_once_huge() ->
@@ -388,10 +379,10 @@ client_echos_active_once_huge(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Str = "1234567890",
- client_echos_active_once(Str, 500000, ClientOpts, ServerOpts, ClientNode,
- ServerNode, Hostname).
+ %%
+ Data = binary:copy(<<"1234567890">>, 50000),
+ client_echos_active_once(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
%%--------------------------------------------------------------------
client_echos_active_huge() ->
@@ -402,293 +393,264 @@ client_echos_active_huge(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ %%
+ Data = binary:copy(<<"1234567890">>, 50000),
+ client_echos_active(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
+
+
+%%--------------------------------------------------------------------
+client_active_once_server_close() ->
+ [{doc, "Server sends 500000 bytes and immediately after closes the connection"
+ "Make sure client recives all data if possible"}].
- Str = "1234567890",
- client_echos_active(Str, 500000, ClientOpts, ServerOpts, ClientNode,
- ServerNode, Hostname).
+client_active_once_server_close(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ %%
+ Data = binary:copy(<<"1234567890">>, 50000),
+ client_active_once_server_close(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname).
+
+
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
-server_echos_passive(Data, Length, ClientOpts, ServerOpts,
- ClientNode, ServerNode, Hostname) ->
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa,
- {?MODULE, echoer,
- [Data, Length]}},
- {options,
- [{active, false},{mode, binary}
- | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa,
- {?MODULE, sender,
- [Data,
- Length]}},
- {options,
- [{active, false}, {mode, binary} |
- ClientOpts]}]),
+server_echos_passive(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname) ->
+ Length = byte_size(Data),
+ Server =
+ ssl_test_lib:start_server(
+ [{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, echoer, [Length]}},
+ {options, [{active, false}, {mode, binary} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client =
+ ssl_test_lib:start_client(
+ [{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, sender, [Data]}},
+ {options, [{active, false}, {mode, binary} | ClientOpts]}]),
+ %%
ssl_test_lib:check_result(Server, ok, Client, ok),
-
+ %%
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
-server_echos_active_once(Data, Length, ClientOpts, ServerOpts, ClientNode,
- ServerNode, Hostname) ->
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa,
- {?MODULE, echoer_once,
- [Data, Length]}},
- {options, [{active, once},
- {mode, binary}|
- ServerOpts]}]),
+server_echos_active_once(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname) ->
+ Length = byte_size(Data),
+ Server =
+ ssl_test_lib:start_server(
+ [{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, echoer_active_once, [Length]}},
+ {options, [{active, once}, {mode, binary} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa,
- {?MODULE, sender_once,
- [Data, Length]}},
- {options, [{active, once},
- {mode, binary} |
- ClientOpts]}]),
+ Client =
+ ssl_test_lib:start_client(
+ [{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, sender_active_once, [Data]}},
+ {options, [{active, once}, {mode, binary} | ClientOpts]}]),
+ %%
ssl_test_lib:check_result(Server, ok, Client, ok),
-
+ %%
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
-server_echos_active(Data, Length, ClientOpts, ServerOpts,
- ClientNode, ServerNode, Hostname) ->
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa,
- {?MODULE, echoer_active,
- [Data, Length]}},
- {options,
- [{active, true},
- {mode, binary} | ServerOpts]}]),
+server_echos_active(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname) ->
+ Length = byte_size(Data),
+ Server =
+ ssl_test_lib:start_server(
+ [{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, echoer_active, [Length]}},
+ {options, [{active, true}, {mode, binary} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa,
- {?MODULE, sender_active,
- [Data,
- Length]}},
- {options,
- [{active, true}, {mode, binary}
- | ClientOpts]}]),
+ Client =
+ ssl_test_lib:start_client(
+ [{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, sender_active, [Data]}},
+ {options, [{active, true}, {mode, binary} | ClientOpts]}]),
+ %%
ssl_test_lib:check_result(Server, ok, Client, ok),
-
+ %%
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
-client_echos_passive(Data, Length, ClientOpts, ServerOpts,
- ClientNode, ServerNode, Hostname) ->
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa,
- {?MODULE, sender,
- [Data, Length]}},
- {options,
- [{active, false}, {mode, binary} |
- ServerOpts]}]),
+client_echos_passive(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname) ->
+ Length = byte_size(Data),
+ Server =
+ ssl_test_lib:start_server(
+ [{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, sender, [Data]}},
+ {options, [{active, false}, {mode, binary} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa,
- {?MODULE, echoer,
- [Data,
- Length]}},
- {options,
- [{active, false}, {mode, binary}
- | ClientOpts]}]),
+ Client =
+ ssl_test_lib:start_client(
+ [{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, echoer, [Length]}},
+ {options, [{active, false}, {mode, binary} | ClientOpts]}]),
+ %%
ssl_test_lib:check_result(Server, ok, Client, ok),
-
+ %%
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
-client_echos_active_once(Data, Length,
- ClientOpts, ServerOpts, ClientNode, ServerNode,
- Hostname) ->
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa,
- {?MODULE, sender_once,
- [Data, Length]}},
- {options, [{active, once},
- {mode, binary} |
- ServerOpts]}]),
+client_echos_active_once(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname) ->
+ Length = byte_size(Data),
+ Server =
+ ssl_test_lib:start_server(
+ [{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, sender_active_once, [Data]}},
+ {options, [{active, once}, {mode, binary} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa,
- {?MODULE, echoer_once,
- [Data,
- Length]}},
- {options,[{active, once},
- {mode, binary}
- | ClientOpts]}]),
+ Client =
+ ssl_test_lib:start_client(
+ [{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, echoer_active_once, [Length]}},
+ {options,[{active, once}, {mode, binary} | ClientOpts]}]),
+ %%
ssl_test_lib:check_result(Server, ok, Client, ok),
-
+ %%
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
-client_echos_active(Data, Length, ClientOpts, ServerOpts, ClientNode,
- ServerNode,
- Hostname) ->
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa,
- {?MODULE, sender_active,
- [Data, Length]}},
- {options, [{active, true},
- {mode, binary}
- | ServerOpts]}]),
+client_echos_active(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname) ->
+ Length = byte_size(Data),
+ Server =
+ ssl_test_lib:start_server(
+ [{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, sender_active, [Data]}},
+ {options, [{active, true}, {mode, binary} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa,
- {?MODULE, echoer_active,
- [Data,
- Length]}},
- {options, [{active, true},
- {mode, binary}
- | ClientOpts]}]),
+ Client =
+ ssl_test_lib:start_client(
+ [{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, echoer_active, [Length]}},
+ {options, [{active, true}, {mode, binary} | ClientOpts]}]),
+ %
ssl_test_lib:check_result(Server, ok, Client, ok),
-
+ %%
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
-send(_, _, _, 0,_) ->
+client_active_once_server_close(
+ Data, ClientOpts, ServerOpts, ClientNode, ServerNode, Hostname) ->
+ Length = byte_size(Data),
+ Server =
+ ssl_test_lib:start_server(
+ [{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, send_close, [Data]}},
+ {options, [{active, once}, {mode, binary} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client =
+ ssl_test_lib:start_client(
+ [{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, active_once_recv, [Length]}},
+ {options,[{active, once}, {mode, binary} | ClientOpts]}]),
+ %%
+ ssl_test_lib:check_result(Server, ok, Client, ok).
+
+send(_Socket, _Data, 0, _) ->
ok;
-send(Socket, Data, Size, Repeate,F) ->
- NewData = lists:duplicate(Size div 10, Data),
- ssl:send(Socket, NewData),
- F(),
- send(Socket, Data, Size, Repeate - 1,F).
-
-sender(Socket, Data, Size) ->
- ok = send(Socket, Data, Size, 100, fun() -> do_recv(Socket, Data, Size, <<>>, false) end),
+send(Socket, Data, Count, RecvEcho) ->
+ ok = ssl:send(Socket, Data),
+ RecvEcho(),
+ send(Socket, Data, Count - 1, RecvEcho).
+
+send_close(Socket, Data) ->
+ ok = ssl:send(Socket, Data),
+ ssl:close(Socket).
+
+sender(Socket, Data) ->
ct:log("Sender recv: ~p~n", [ssl:getopts(Socket, [active])]),
- ok.
-
-sender_once(Socket, Data, Size) ->
- send(Socket, Data, Size, 100,
- fun() -> do_active_once(Socket, Data, Size, <<>>, false) end),
- ct:log("Sender active once: ~p~n",
- [ssl:getopts(Socket, [active])]),
- ok.
-
-sender_active(Socket, Data, Size) ->
- F = fun() -> do_active(Socket, Data, Size, <<>>, false) end,
- send(Socket, Data, Size, 100, F),
+ send(Socket, Data, 100,
+ fun() ->
+ ssl_test_lib:recv_disregard(Socket, byte_size(Data))
+ end).
+
+sender_active_once(Socket, Data) ->
+ ct:log("Sender active once: ~p~n", [ssl:getopts(Socket, [active])]),
+ send(Socket, Data, 100,
+ fun() ->
+ ssl_test_lib:active_once_disregard(Socket, byte_size(Data))
+ end).
+
+sender_active(Socket, Data) ->
ct:log("Sender active: ~p~n", [ssl:getopts(Socket, [active])]),
- ok.
+ send(Socket, Data, 100,
+ fun() ->
+ ssl_test_lib:active_disregard(Socket, byte_size(Data))
+ end).
-echoer(Socket, Data, Size) ->
+echoer(Socket, Size) ->
ct:log("Echoer recv: ~p~n", [ssl:getopts(Socket, [active])]),
- echo(fun() -> do_recv(Socket, Data, Size, <<>>, true) end, 100).
+ echo_recv(Socket, Size * 100).
-echoer_once(Socket, Data, Size) ->
- ct:log("Echoer active once: ~p ~n",
- [ssl:getopts(Socket, [active])]),
- echo(fun() -> do_active_once(Socket, Data, Size, <<>>, true) end, 100).
+echoer_active_once(Socket, Size) ->
+ ct:log("Echoer active once: ~p~n", [ssl:getopts(Socket, [active])]),
+ echo_active_once(Socket, Size * 100).
-echoer_active(Socket, Data, Size) ->
+echoer_active(Socket, Size) ->
ct:log("Echoer active: ~p~n", [ssl:getopts(Socket, [active])]),
- echo(fun() -> do_active(Socket, Data, Size, <<>>, true) end, 100).
-
-echo(_Fun, 0) -> ok;
-echo(Fun, N) ->
- Fun(),
- echo(Fun, N-1).
+ echo_active(Socket, Size * 100).
-do_recv(_Socket, _Data, 0, _Acc, true) ->
+%% Receive Size bytes
+echo_recv(_Socket, 0) ->
ok;
-do_recv(_Socket, Data, 0, Acc, false) ->
- Data = lists:sublist(binary_to_list(Acc), 10);
+echo_recv(Socket, Size) ->
+ {ok, Data} = ssl:recv(Socket, 0),
+ ok = ssl:send(Socket, Data),
+ echo_recv(Socket, Size - byte_size(Data)).
-do_recv(Socket, Data, Size, Acc, Echo) ->
- {ok, NewData} = ssl:recv(Socket, 0),
- NewSize = size(NewData),
- case Echo of
- true ->
- ssl:send(Socket, NewData),
- NewSize = size(NewData),
- do_recv(Socket, Data, Size - NewSize, [], Echo);
- false ->
- case size(Acc) < 10 of
- true ->
- do_recv(Socket, Data, Size - NewSize,
- <<Acc/binary, NewData/binary>>, Echo);
- false ->
- do_recv(Socket, Data, Size - NewSize, Acc, Echo)
- end
- end.
-
-do_active_once(_Socket, _Data, 0, _Acc, true) ->
+%% Receive Size bytes
+echo_active_once(_Socket, 0) ->
ok;
-do_active_once(_Socket, Data, 0, Acc, false) ->
- Data = lists:sublist(binary_to_list(Acc), 10);
-
-do_active_once(Socket, Data, Size, Acc, Echo) ->
- receive
- {ssl, Socket, NewData} ->
- NewSize = size(NewData),
- case Echo of
- true ->
- ssl:send(Socket, NewData),
- ssl:setopts(Socket, [{active, once}]),
- do_active_once(Socket, Data, Size - NewSize, [], Echo);
- false ->
- case size(Acc) < 10 of
- true ->
- ssl:setopts(Socket, [{active, once}]),
- do_active_once(Socket, Data, Size - NewSize,
- <<Acc/binary, NewData/binary>>,
- Echo);
- false ->
- ssl:setopts(Socket, [{active, once}]),
- do_active_once(Socket, Data,
- Size - NewSize, Acc, Echo)
- end
- end
+echo_active_once(Socket, Size) ->
+ receive
+ {ssl, Socket, Data} ->
+ ok = ssl:send(Socket, Data),
+ NewSize = Size - byte_size(Data),
+ ssl:setopts(Socket, [{active, once}]),
+ echo_active_once(Socket, NewSize)
end.
-
-do_active(_Socket, _Data, 0, _Acc, true) ->
+
+%% Receive Size bytes
+echo_active(_Socket, 0) ->
ok;
-do_active(_Socket, Data, 0, Acc, false) ->
- Data = lists:sublist(binary_to_list(Acc), 10);
-
-do_active(Socket, Data, Size, Acc, Echo) ->
- receive
- {ssl, Socket, NewData} ->
- NewSize = size(NewData),
- case Echo of
- true ->
- ssl:send(Socket, NewData),
- do_active(Socket, Data, Size - NewSize, [], Echo);
- false ->
- case size(Acc) < 10 of
- true ->
- do_active(Socket, Data, Size - NewSize,
- <<Acc/binary, NewData/binary>>,
- Echo);
- false ->
- do_active(Socket, Data,
- Size - NewSize, Acc, Echo)
- end
- end
- end.
+echo_active(Socket, Size) ->
+ receive
+ {ssl, Socket, Data} ->
+ ok = ssl:send(Socket, Data),
+ echo_active(Socket, Size - byte_size(Data))
+ end.
+
diff --git a/lib/ssl/test/ssl_pem_cache_SUITE.erl b/lib/ssl/test/ssl_pem_cache_SUITE.erl
index 96b15d9b51..6f11e2bbe8 100644
--- a/lib/ssl/test/ssl_pem_cache_SUITE.erl
+++ b/lib/ssl/test/ssl_pem_cache_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -34,7 +34,7 @@
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
all() ->
- [pem_cleanup].
+ [pem_cleanup, invalid_insert].
groups() ->
[].
@@ -44,11 +44,8 @@ init_per_suite(Config0) ->
try crypto:start() of
ok ->
ssl_test_lib:clean_start(),
- %% make rsa certs using oppenssl
- {ok, _} = make_certs:all(proplists:get_value(data_dir, Config0),
- proplists:get_value(priv_dir, Config0)),
- Config1 = ssl_test_lib:make_dsa_cert(Config0),
- ssl_test_lib:cert_options(Config1)
+ %% make rsa certs
+ ssl_test_lib:make_rsa_cert(Config0)
catch _:_ ->
{skip, "Crypto did not start"}
end.
@@ -68,6 +65,10 @@ init_per_testcase(pem_cleanup = Case, Config) ->
application:set_env(ssl, ssl_pem_cache_clean, ?CLEANUP_INTERVAL),
ssl:start(),
ct:timetrap({minutes, 1}),
+ Config;
+init_per_testcase(_, Config) ->
+ ssl:start(),
+ ct:timetrap({seconds, 5}),
Config.
end_per_testcase(_TestCase, Config) ->
@@ -82,8 +83,8 @@ pem_cleanup() ->
[{doc, "Test pem cache invalidate mechanism"}].
pem_cleanup(Config)when is_list(Config) ->
process_flag(trap_exit, true),
- ClientOpts = proplists:get_value(client_verification_opts, Config),
- ServerOpts = proplists:get_value(server_verification_opts, Config),
+ ClientOpts = proplists:get_value(client_rsa_verify_opts, Config),
+ ServerOpts = proplists:get_value(server_rsa_verify_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server =
@@ -108,7 +109,34 @@ pem_cleanup(Config)when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client),
false = Size == Size1.
-
+
+invalid_insert() ->
+ [{doc, "Test that insert of invalid pem does not cause empty cache entry"}].
+invalid_insert(Config)when is_list(Config) ->
+ process_flag(trap_exit, true),
+
+ ClientOpts = proplists:get_value(client_rsa_verify_opts, Config),
+ ServerOpts = proplists:get_value(server_rsa_verify_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ BadClientOpts = [{cacertfile, "tmp/does_not_exist.pem"} | proplists:delete(cacertfile, ClientOpts)],
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ ssl_test_lib:start_client_error([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {from, self()}, {options, BadClientOpts}]),
+ ssl_test_lib:close(Server),
+ 1 = ssl_pkix_db:db_size(get_fileref_db()).
+
+
+
+%%--------------------------------------------------------------------
+%% Internal funcations
+%%--------------------------------------------------------------------
+
get_pem_cache() ->
{status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
[_, _,_, _, Prop] = StatusInfo,
@@ -120,6 +148,16 @@ get_pem_cache() ->
undefined
end.
+get_fileref_db() ->
+ {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
+ [_, _,_, _, Prop] = StatusInfo,
+ State = ssl_test_lib:state(Prop),
+ case element(6, State) of
+ [_CertDb, {FileRefDb,_} | _] ->
+ FileRefDb;
+ _ ->
+ undefined
+ end.
later()->
DateTime = calendar:now_to_local_time(os:timestamp()),
Gregorian = calendar:datetime_to_gregorian_seconds(DateTime),
diff --git a/lib/ssl/test/ssl_rfc_5869_SUITE.erl b/lib/ssl/test/ssl_rfc_5869_SUITE.erl
new file mode 100644
index 0000000000..8b2d1c2082
--- /dev/null
+++ b/lib/ssl/test/ssl_rfc_5869_SUITE.erl
@@ -0,0 +1,316 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+-module(ssl_rfc_5869_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+all() ->
+ [sha_256_basic,
+ sha_256_long,
+ sha_256_no_salt,
+ sha_basic,
+ sha_long,
+ sha_no_salt,
+ sha_default_salt
+ ].
+
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ Config
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ application:stop(crypto).
+
+%%--------------------------------------------------------------------
+init_per_testcase(_TestCase, Config) ->
+ ct:timetrap({seconds, 5}),
+ Config.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+sha_256_basic() ->
+ [{doc, "Basic test case with SHA-256"}].
+sha_256_basic(Config) when is_list(Config) ->
+ %% Hash = SHA-256
+ %% IKM = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b (22 octets)
+ %% salt = 0x000102030405060708090a0b0c (13 octets)
+ %% info = 0xf0f1f2f3f4f5f6f7f8f9 (10 octets)
+ %% L = 42
+ %% PRK = 0x077709362c2e32df0ddc3f0dc47bba63
+ %% 90b6c73bb50f9c3122ec844ad7c2b3e5 (32 octets)
+ %% OKM = 0x3cb25f25faacd57a90434f64d0362f2a
+ %% 2d2d0a90cf1a5a4c5db02d56ecc4c5bf
+ %% 34007208d5b887185865 (42 octets)
+ IKM = hexstr2bin("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
+ Salt = hexstr2bin("000102030405060708090a0b0c"),
+ Info = hexstr2bin("f0f1f2f3f4f5f6f7f8f9"),
+ PRK = hexstr2bin("077709362c2e32df0ddc3f0dc47bba63"
+ "90b6c73bb50f9c3122ec844ad7c2b3e5"),
+ OKM = hexstr2bin("3cb25f25faacd57a90434f64d0362f2a"
+ "2d2d0a90cf1a5a4c5db02d56ecc4c5bf"
+ "34007208d5b887185865"),
+ hkdf_test(sha256, Salt, IKM, PRK, Info, 42, OKM).
+
+sha_256_long() ->
+ [{doc, "Test with SHA-256 and longer inputs/outputs"}].
+sha_256_long(Config) when is_list(Config) ->
+ %% Hash = SHA-256
+ %% IKM = 0x000102030405060708090a0b0c0d0e0f
+ %% 101112131415161718191a1b1c1d1e1f
+ %% 202122232425262728292a2b2c2d2e2f
+ %% 303132333435363738393a3b3c3d3e3f
+ %% 404142434445464748494a4b4c4d4e4f (80 octets)
+ %% salt = 0x606162636465666768696a6b6c6d6e6f
+ %% 707172737475767778797a7b7c7d7e7f
+ %% 808182838485868788898a8b8c8d8e8f
+ %% 909192939495969798999a9b9c9d9e9f
+ %% a0a1a2a3a4a5a6a7a8a9aaabacadaeaf (80 octets)
+ %% info = 0xb0b1b2b3b4b5b6b7b8b9babbbcbdbebf
+ %% c0c1c2c3c4c5c6c7c8c9cacbcccdcecf
+ %% d0d1d2d3d4d5d6d7d8d9dadbdcdddedf
+ %% e0e1e2e3e4e5e6e7e8e9eaebecedeeef
+ %% f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff (80 octets)
+ %% L = 82
+
+ %% PRK = 0x06a6b88c5853361a06104c9ceb35b45c
+ %% ef760014904671014a193f40c15fc244 (32 octets)
+ %% OKM = 0xb11e398dc80327a1c8e7f78c596a4934
+ %% 4f012eda2d4efad8a050cc4c19afa97c
+ %% 59045a99cac7827271cb41c65e590e09
+ %% da3275600c2f09b8367793a9aca3db71
+ %% cc30c58179ec3e87c14c01d5c1f3434f
+ %% 1d87 (82 octets)
+ IKM = hexstr2bin("000102030405060708090a0b0c0d0e0f"
+ "101112131415161718191a1b1c1d1e1f"
+ "202122232425262728292a2b2c2d2e2f"
+ "303132333435363738393a3b3c3d3e3f"
+ "404142434445464748494a4b4c4d4e4f"
+ ),
+ Salt = hexstr2bin("606162636465666768696a6b6c6d6e6f"
+ "707172737475767778797a7b7c7d7e7f"
+ "808182838485868788898a8b8c8d8e8f"
+ "909192939495969798999a9b9c9d9e9f"
+ "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
+ ),
+ Info = hexstr2bin("b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
+ "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
+ "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
+ "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
+ "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"
+ ),
+ PRK = hexstr2bin("06a6b88c5853361a06104c9ceb35b45c"
+ "ef760014904671014a193f40c15fc244"),
+ OKM = hexstr2bin("b11e398dc80327a1c8e7f78c596a4934"
+ "4f012eda2d4efad8a050cc4c19afa97c"
+ "59045a99cac7827271cb41c65e590e09"
+ "da3275600c2f09b8367793a9aca3db71"
+ "cc30c58179ec3e87c14c01d5c1f3434f"
+ "1d87"
+ ),
+ hkdf_test(sha256, Salt, IKM, PRK, Info, 82, OKM).
+sha_256_no_salt() ->
+ [{doc, "Test with SHA-256 and zero-length salt/info"}].
+sha_256_no_salt(Config) when is_list(Config) ->
+ %% Hash = SHA-256
+ %% IKM = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b (22 octets)
+ %% salt = (0 octets)
+ %% info = (0 octets)
+ %% L = 42
+
+ %% PRK = 0x19ef24a32c717b167f33a91d6f648bdf
+ %% 96596776afdb6377ac434c1c293ccb04 (32 octets)
+ %% OKM = 0x8da4e775a563c18f715f802a063c5a31
+ %% b8a11f5c5ee1879ec3454e5f3c738d2d
+ %% 9d201395faa4b61a96c8 (42 octets)
+ IKM = hexstr2bin("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
+ Salt = <<>>,
+ Info = <<>>,
+ PRK = hexstr2bin("19ef24a32c717b167f33a91d6f648bdf"
+ "96596776afdb6377ac434c1c293ccb04"),
+ OKM = hexstr2bin("8da4e775a563c18f715f802a063c5a31"
+ "b8a11f5c5ee1879ec3454e5f3c738d2d"
+ "9d201395faa4b61a96c8"),
+ hkdf_test(sha256, Salt, IKM, PRK, Info, 42, OKM).
+
+sha_basic() ->
+ [{doc, " Basic test case with SHA-1"}].
+sha_basic(Config) when is_list(Config) ->
+ %% Hash = SHA-1
+ %% IKM = 0x0b0b0b0b0b0b0b0b0b0b0b (11 octets)
+ %% salt = 0x000102030405060708090a0b0c (13 octets)
+ %% info = 0xf0f1f2f3f4f5f6f7f8f9 (10 octets)
+ %% L = 42
+
+ %% PRK = 0x9b6c18c432a7bf8f0e71c8eb88f4b30baa2ba243 (20 octets)
+ %% OKM = 0x085a01ea1b10f36933068b56efa5ad81
+ %% a4f14b822f5b091568a9cdd4f155fda2
+ %% c22e422478d305f3f896 (42 octets)
+ IKM = hexstr2bin("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
+ Salt = hexstr2bin("000102030405060708090a0b0c"),
+ Info = hexstr2bin("f0f1f2f3f4f5f6f7f8f9"),
+ PRK = hexstr2bin("077709362c2e32df0ddc3f0dc47bba63"
+ "90b6c73bb50f9c3122ec844ad7c2b3e5"),
+ OKM = hexstr2bin("3cb25f25faacd57a90434f64d0362f2a"
+ "2d2d0a90cf1a5a4c5db02d56ecc4c5bf"
+ "34007208d5b887185865"),
+ hkdf_test(sha256, Salt, IKM, PRK, Info, 42, OKM).
+
+sha_long() ->
+ [{doc, "Test with SHA-1 and longer inputs/outputs"}].
+sha_long(Config) when is_list(Config) ->
+ %% Hash = SHA-1
+ %% IKM = 0x000102030405060708090a0b0c0d0e0f
+ %% 101112131415161718191a1b1c1d1e1f
+ %% 202122232425262728292a2b2c2d2e2f
+ %% 303132333435363738393a3b3c3d3e3f
+ %% 404142434445464748494a4b4c4d4e4f (80 octets)
+ %% salt = 0x606162636465666768696a6b6c6d6e6f
+ %% 707172737475767778797a7b7c7d7e7f
+ %% 808182838485868788898a8b8c8d8e8f
+ %% 909192939495969798999a9b9c9d9e9f
+ %% a0a1a2a3a4a5a6a7a8a9aaabacadaeaf (80 octets)
+ %% info = 0xb0b1b2b3b4b5b6b7b8b9babbbcbdbebf
+ %% c0c1c2c3c4c5c6c7c8c9cacbcccdcecf
+ %% d0d1d2d3d4d5d6d7d8d9dadbdcdddedf
+ %% e0e1e2e3e4e5e6e7e8e9eaebecedeeef
+ %% f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff (80 octets)
+ %% L = 82
+
+ %% PRK = 0x8adae09a2a307059478d309b26c4115a224cfaf6 (20 octets)
+ %% OKM = 0x0bd770a74d1160f7c9f12cd5912a06eb
+ %% ff6adcae899d92191fe4305673ba2ffe
+ %% 8fa3f1a4e5ad79f3f334b3b202b2173c
+ %% 486ea37ce3d397ed034c7f9dfeb15c5e
+ %% 927336d0441f4c4300e2cff0d0900b52
+ %% d3b4 (82 octets)
+ IKM = hexstr2bin("000102030405060708090a0b0c0d0e0f"
+ "101112131415161718191a1b1c1d1e1f"
+ "202122232425262728292a2b2c2d2e2f"
+ "303132333435363738393a3b3c3d3e3f"
+ "404142434445464748494a4b4c4d4e4f"
+ ),
+ Salt = hexstr2bin("606162636465666768696a6b6c6d6e6f"
+ "707172737475767778797a7b7c7d7e7f"
+ "808182838485868788898a8b8c8d8e8f"
+ "909192939495969798999a9b9c9d9e9f"
+ "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
+ ),
+ Info = hexstr2bin("b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
+ "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
+ "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
+ "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
+ "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"
+ ),
+ PRK = hexstr2bin("8adae09a2a307059478d309b26c4115a224cfaf6"),
+ OKM = hexstr2bin("0bd770a74d1160f7c9f12cd5912a06eb"
+ "ff6adcae899d92191fe4305673ba2ffe"
+ "8fa3f1a4e5ad79f3f334b3b202b2173c"
+ "486ea37ce3d397ed034c7f9dfeb15c5e"
+ "927336d0441f4c4300e2cff0d0900b52"
+ "d3b4"
+ ),
+ hkdf_test(sha, Salt, IKM, PRK, Info, 82, OKM).
+
+sha_no_salt() ->
+ [{doc, "Test with SHA-1 and zero-length salt/info"}].
+sha_no_salt(Config) when is_list(Config) ->
+ %% Hash = SHA-1
+ %% IKM = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b (22 octets)
+ %% salt = (0 octets)
+ %% info = (0 octets)
+ %% L = 42
+
+ %% PRK = 0xda8c8a73c7fa77288ec6f5e7c297786aa0d32d01 (20 octets)
+ %% OKM = 0x0ac1af7002b3d761d1e55298da9d0506
+ %% b9ae52057220a306e07b6b87e8df21d0
+ %% ea00033de03984d34918 (42 octets)
+ IKM = hexstr2bin("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
+ Salt = <<>>,
+ Info = <<>>,
+ PRK = hexstr2bin("da8c8a73c7fa77288ec6f5e7c297786aa0d32d01"),
+ OKM = hexstr2bin("0ac1af7002b3d761d1e55298da9d0506"
+ "b9ae52057220a306e07b6b87e8df21d0"
+ "ea00033de03984d34918"),
+ hkdf_test(sha, Salt, IKM, PRK, Info, 42, OKM).
+
+
+sha_default_salt() ->
+ [{doc, "Test with SHA-1, salt not provided (defaults to HashLen zero octets),
+ zero-length info"}].
+sha_default_salt(Config) when is_list(Config) ->
+ %% Hash = SHA-1
+ %% IKM = 0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c (22 octets)
+ %% salt = not provided (defaults to HashLen zero octets)
+ %% info = (0 octets)
+ %% L = 42
+
+ %% PRK = 0x2adccada18779e7c2077ad2eb19d3f3e731385dd (20 octets)
+ %% OKM = 0x2c91117204d745f3500d636a62f64f0a
+ %% b3bae548aa53d423b0d1f27ebba6f5e5
+ %% 673a081d70cce7acfc48 (42 octets)
+ IKM = hexstr2bin("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"),
+ Salt = binary:copy(<<0>>, 20),
+ Info = <<>>,
+ PRK = hexstr2bin("2adccada18779e7c2077ad2eb19d3f3e731385dd"),
+ OKM = hexstr2bin("2c91117204d745f3500d636a62f64f0a"
+ "b3bae548aa53d423b0d1f27ebba6f5e5"
+ "673a081d70cce7acfc48"),
+ hkdf_test(sha, Salt, IKM, PRK, Info, 42, OKM).
+
+hkdf_test(HashAlg, Salt, KeyingMaterial, PsedoRandKey, ContextInfo, Length, Key) ->
+ PsedoRandKey = tls_v1:hkdf_extract(HashAlg, Salt, KeyingMaterial),
+ Key = tls_v1:hkdf_expand(PsedoRandKey, ContextInfo, Length, HashAlg).
+
+hexstr2bin(S) when is_binary(S) ->
+ list_to_binary(hexstr2list(binary_to_list(S)));
+hexstr2bin(S) ->
+ list_to_binary(hexstr2list(S)).
+
+hexstr2list([$ |T]) ->
+ hexstr2list(T);
+hexstr2list([X,Y|T]) ->
+ [mkint(X)*16 + mkint(Y) | hexstr2list(T)];
+hexstr2list([]) ->
+ [].
+mkint(C) when $0 =< C, C =< $9 ->
+ C - $0;
+mkint(C) when $A =< C, C =< $F ->
+ C - $A + 10;
+mkint(C) when $a =< C, C =< $f ->
+ C - $a + 10.
diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl
index 9862b3ce64..b71b15b028 100644
--- a/lib/ssl/test/ssl_session_cache_SUITE.erl
+++ b/lib/ssl/test/ssl_session_cache_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -48,7 +48,8 @@ all() ->
session_cache_process_list,
session_cache_process_mnesia,
client_unique_session,
- max_table_size
+ max_table_size,
+ save_specific_session
].
groups() ->
@@ -60,10 +61,7 @@ init_per_suite(Config0) ->
ok ->
ssl_test_lib:clean_start(),
%% make rsa certs using
- {ok, _} = make_certs:all(proplists:get_value(data_dir, Config0),
- proplists:get_value(priv_dir, Config0)),
- Config = ssl_test_lib:make_dsa_cert(Config0),
- ssl_test_lib:cert_options(Config)
+ ssl_test_lib:make_rsa_cert(Config0)
catch _:_ ->
{skip, "Crypto did not start"}
end.
@@ -97,7 +95,10 @@ init_per_testcase(session_cleanup, Config) ->
init_per_testcase(client_unique_session, Config) ->
ct:timetrap({seconds, 40}),
Config;
-
+init_per_testcase(save_specific_session, Config) ->
+ ssl_test_lib:clean_start(),
+ ct:timetrap({seconds, 5}),
+ Config;
init_per_testcase(max_table_size, Config) ->
ssl:stop(),
application:load(ssl),
@@ -141,7 +142,7 @@ end_per_testcase(max_table_size, Config) ->
end_per_testcase(default_action, Config);
end_per_testcase(Case, Config) when Case == session_cache_process_list;
Case == session_cache_process_mnesia ->
- ets:delete(ssl_test),
+ catch ets:delete(ssl_test),
Config;
end_per_testcase(_, Config) ->
Config.
@@ -154,8 +155,8 @@ client_unique_session() ->
"sets up many connections"}].
client_unique_session(Config) when is_list(Config) ->
process_flag(trap_exit, true),
- ClientOpts = proplists:get_value(client_opts, Config),
- ServerOpts = proplists:get_value(server_opts, Config),
+ ClientOpts = proplists:get_value(client_rsa_verify_opts, Config),
+ ServerOpts = proplists:get_value(server_rsa_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server =
ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
@@ -164,8 +165,7 @@ client_unique_session(Config) when is_list(Config) ->
{tcp_options, [{active, false}]},
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
- LastClient = clients_start(Server,
- ClientNode, Hostname, Port, ClientOpts, client_unique_session, 20),
+ LastClient = clients_start(Server, ClientNode, Hostname, Port, ClientOpts, 20),
receive
{LastClient, {ok, _}} ->
ok
@@ -185,8 +185,8 @@ session_cleanup() ->
"does not grow and grow ..."}].
session_cleanup(Config) when is_list(Config) ->
process_flag(trap_exit, true),
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server =
@@ -254,13 +254,75 @@ session_cache_process_mnesia(Config) when is_list(Config) ->
session_cache_process(mnesia,Config).
%%--------------------------------------------------------------------
+save_specific_session() ->
+ [{doc, "Test that we can save a specific client session"
+ }].
+save_specific_session(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ ClientOpts = proplists:get_value(client_rsa_verify_opts, Config),
+ ServerOpts = proplists:get_value(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {tcp_options, [{active, false}]},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client1 = ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_id, []}},
+ {from, self()}, {options, ClientOpts}]),
+ Server ! listen,
+
+ Client2 = ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_id, []}},
+ {from, self()}, {options, [{reuse_sessions, save} | ClientOpts]}]),
+ SessionID1 =
+ receive
+ {Client1, S1} ->
+ S1
+ end,
+
+ SessionID2 =
+ receive
+ {Client2, S2} ->
+ S2
+ end,
+
+ true = SessionID1 =/= SessionID2,
+
+ {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
+ [_, _,_, _, Prop] = StatusInfo,
+ State = ssl_test_lib:state(Prop),
+ ClientCache = element(2, State),
+ 2 = ssl_session_cache:size(ClientCache),
+
+ Server ! listen,
+
+ Client3 = ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_id, []}},
+ {from, self()}, {options, [{reuse_session, SessionID2} | ClientOpts]}]),
+ receive
+ {Client3, SessionID2} ->
+ ok;
+ {Client3, SessionID3}->
+ ct:fail({got, SessionID3, expected, SessionID2});
+ Other ->
+ ct:fail({got,Other})
+ end.
+
+%%--------------------------------------------------------------------
max_table_size() ->
[{doc,"Test max limit on session table"}].
max_table_size(Config) when is_list(Config) ->
process_flag(trap_exit, true),
- ClientOpts = proplists:get_value(client_verification_opts, Config),
- ServerOpts = proplists:get_value(server_verification_opts, Config),
+ ClientOpts = proplists:get_value(client_rsa_verify_opts, Config),
+ ServerOpts = proplists:get_value(server_rsa_verify_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server =
ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
@@ -270,7 +332,7 @@ max_table_size(Config) when is_list(Config) ->
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
LastClient = clients_start(Server,
- ClientNode, Hostname, Port, ClientOpts, max_table_size, 20),
+ ClientNode, Hostname, Port, ClientOpts, 20),
receive
{LastClient, {ok, _}} ->
ok
@@ -426,25 +488,27 @@ session_loop(Sess) ->
%%--------------------------------------------------------------------
session_cache_process(_Type,Config) when is_list(Config) ->
- ssl_basic_SUITE:reuse_session(Config).
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ ssl_test_lib:reuse_session(ClientOpts, ServerOpts, Config).
-clients_start(_Server, ClientNode, Hostname, Port, ClientOpts, Test, 0) ->
+clients_start(_Server, ClientNode, Hostname, Port, ClientOpts, 0) ->
%% Make sure session is registered
ct:sleep(?SLEEP * 2),
ssl_test_lib:start_client([{node, ClientNode},
{port, Port}, {host, Hostname},
{mfa, {?MODULE, connection_info_result, []}},
- {from, self()}, {options, test_copts(Test, 0, ClientOpts)}]);
-clients_start(Server, ClientNode, Hostname, Port, ClientOpts, Test, N) ->
+ {from, self()}, {options, ClientOpts}]);
+clients_start(Server, ClientNode, Hostname, Port, ClientOpts, N) ->
spawn_link(ssl_test_lib, start_client,
[[{node, ClientNode},
{port, Port}, {host, Hostname},
{mfa, {ssl_test_lib, no_result, []}},
- {from, self()}, {options, test_copts(Test, N, ClientOpts)}]]),
+ {from, self()}, {options, ClientOpts}]]),
Server ! listen,
wait_for_server(),
- clients_start(Server, ClientNode, Hostname, Port, ClientOpts, Test, N-1).
+ clients_start(Server, ClientNode, Hostname, Port, ClientOpts, N-1).
connection_info_result(Socket) ->
ssl:connection_information(Socket, [protocol, cipher_suite]).
@@ -481,21 +545,3 @@ get_delay_timers() ->
wait_for_server() ->
ct:sleep(100).
-
-
-test_copts(_, 0, ClientOpts) ->
- ClientOpts;
-test_copts(max_table_size, N, ClientOpts) ->
- Version = tls_record:highest_protocol_version([]),
- CipherSuites = %%lists:map(fun(X) -> ssl_cipher:suite_definition(X) end, ssl_cipher:filter_suites(ssl_cipher:suites(Version))),
-[ Y|| Y = {Alg,_, _, _} <- lists:map(fun(X) -> ssl_cipher:suite_definition(X) end, ssl_cipher:filter_suites(ssl_cipher:suites(Version))), Alg =/= ecdhe_ecdsa, Alg =/= ecdh_ecdsa, Alg =/= ecdh_rsa, Alg =/= ecdhe_rsa, Alg =/= dhe_dss, Alg =/= dss],
- case length(CipherSuites) of
- M when M >= N ->
- Cipher = lists:nth(N, CipherSuites),
- ct:pal("~p",[Cipher]),
- [{ciphers, [Cipher]} | ClientOpts];
- _ ->
- ClientOpts
- end;
-test_copts(_, _, ClientOpts) ->
- ClientOpts.
diff --git a/lib/ssl/test/ssl_sni_SUITE.erl b/lib/ssl/test/ssl_sni_SUITE.erl
index 7e78c41444..7629d75100 100644
--- a/lib/ssl/test/ssl_sni_SUITE.erl
+++ b/lib/ssl/test/ssl_sni_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -236,8 +236,8 @@ dns_name_reuse(Config) ->
{mfa, {ssl_test_lib, session_info_result, []}},
{from, self()}, {options, [{verify, verify_peer} | ClientConf]}]),
- ssl_test_lib:check_result(Client1, {error, {tls_alert, "handshake failure"}}),
- ssl_test_lib:close(Client0).
+ ssl_test_lib:check_client_alert(Client1, handshake_failure).
+
%%--------------------------------------------------------------------
%% Internal Functions ------------------------------------------------
%%--------------------------------------------------------------------
@@ -370,8 +370,8 @@ unsuccessfull_connect(ServerOptions, ClientOptions, Hostname0, Config) ->
{from, self()},
{options, ClientOptions}]),
- ssl_test_lib:check_result(Server, {error, {tls_alert, "handshake failure"}},
- Client, {error, {tls_alert, "handshake failure"}}).
+ ssl_test_lib:check_server_alert(Server, Client, handshake_failure).
+
host_name(undefined, Hostname) ->
Hostname;
host_name(Hostname, _) ->
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index f9cc976815..3b161a0c8a 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,9 +26,11 @@
%% Note: This directive should only be used in test suites.
-compile(export_all).
+-compile(nowarn_export_all).
-record(sslsocket, { fd = nil, pid = nil}).
-define(SLEEP, 1000).
+-define(DEFAULT_CURVE, secp256r1).
%% For now always run locally
run_where(_) ->
@@ -49,20 +51,20 @@ node_to_hostip(Node) ->
Address.
start_server(Args) ->
- Result = spawn_link(?MODULE, run_server, [Args]),
+ Node = proplists:get_value(node, Args),
+ Result = spawn_link(Node, ?MODULE, run_server, [Args]),
receive
{listen, up} ->
Result
end.
run_server(Opts) ->
- Node = proplists:get_value(node, Opts),
Port = proplists:get_value(port, Opts),
Options = proplists:get_value(options, Opts),
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
ct:log("~p:~p~nssl:listen(~p, ~p)~n", [?MODULE,?LINE, Port, Options]),
- {ok, ListenSocket} = rpc:call(Node, Transport, listen, [Port, Options]),
+ {ok, ListenSocket} = Transport:listen(Port, Options),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
run_server(ListenSocket, Opts).
@@ -79,18 +81,21 @@ run_server(ListenSocket, Opts, N) ->
Pid ! {accepter, N, Server},
run_server(ListenSocket, Opts, N-1).
-do_run_server(_, {error, timeout} = Result, Opts) ->
+do_run_server(_, {error, _} = Result, Opts) ->
+ ct:log("Server error result ~p~n", [Result]),
+ Pid = proplists:get_value(from, Opts),
+ Pid ! {self(), Result};
+do_run_server(_, ok = Result, Opts) ->
+ ct:log("Server cancel result ~p~n", [Result]),
Pid = proplists:get_value(from, Opts),
Pid ! {self(), Result};
-
do_run_server(ListenSocket, AcceptSocket, Opts) ->
- Node = proplists:get_value(node, Opts),
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
{Module, Function, Args} = proplists:get_value(mfa, Opts),
ct:log("~p:~p~nServer: apply(~p,~p,~p)~n",
- [?MODULE,?LINE, Module, Function, [AcceptSocket | Args]]),
- case rpc:call(Node, Module, Function, [AcceptSocket | Args]) of
+ [?MODULE,?LINE, Module, Function, [AcceptSocket | Args]]),
+ case apply(Module, Function, [AcceptSocket | Args]) of
no_result_msg ->
ok;
Msg ->
@@ -104,8 +109,8 @@ do_run_server(ListenSocket, AcceptSocket, Opts) ->
run_server(ListenSocket, [MFA | proplists:delete(mfa, Opts)]);
close ->
ct:log("~p:~p~nServer closing ~p ~n", [?MODULE,?LINE, self()]),
- Result = rpc:call(Node, Transport, close, [AcceptSocket], 500),
- Result1 = rpc:call(Node, Transport, close, [ListenSocket], 500),
+ Result = Transport:close(AcceptSocket),
+ Result1 = Transport:close(ListenSocket),
ct:log("~p:~p~nResult ~p : ~p ~n", [?MODULE,?LINE, Result, Result1]);
{ssl_closed, _} ->
ok
@@ -117,7 +122,8 @@ connect(#sslsocket{} = ListenSocket, Opts) ->
ReconnectTimes = proplists:get_value(reconnect_times, Opts, 0),
Timeout = proplists:get_value(timeout, Opts, infinity),
SslOpts = proplists:get_value(ssl_extra_opts, Opts, []),
- AcceptSocket = connect(ListenSocket, Node, 1 + ReconnectTimes, dummy, Timeout, SslOpts),
+ ContOpts = proplists:get_value(continue_options, Opts, []),
+ AcceptSocket = connect(ListenSocket, Node, 1 + ReconnectTimes, dummy, Timeout, SslOpts, ContOpts),
case ReconnectTimes of
0 ->
AcceptSocket;
@@ -125,37 +131,113 @@ connect(#sslsocket{} = ListenSocket, Opts) ->
remove_close_msg(ReconnectTimes),
AcceptSocket
end;
-connect(ListenSocket, Opts) ->
- Node = proplists:get_value(node, Opts),
+connect(ListenSocket, _Opts) ->
ct:log("~p:~p~ngen_tcp:accept(~p)~n", [?MODULE,?LINE, ListenSocket]),
- {ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept,
- [ListenSocket]),
+ {ok, AcceptSocket} = gen_tcp:accept(ListenSocket),
AcceptSocket.
-connect(_, _, 0, AcceptSocket, _, _) ->
+connect(_, _, 0, AcceptSocket, _, _, _) ->
AcceptSocket;
-
-connect(ListenSocket, Node, N, _, Timeout, []) ->
+connect(ListenSocket, Node, _N, _, Timeout, SslOpts, cancel) ->
+ ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
+ {ok, AcceptSocket} = ssl:transport_accept(ListenSocket),
+ ct:log("~p:~p~nssl:handshake(~p,~p,~p)~n", [?MODULE,?LINE, AcceptSocket, SslOpts,Timeout]),
+
+ case ssl:handshake(AcceptSocket, SslOpts, Timeout) of
+ {ok, Socket0, Ext} ->
+ ct:log("Ext ~p:~n", [Ext]),
+ ct:log("~p:~p~nssl:handshake_cancel(~p)~n", [?MODULE,?LINE, Socket0]),
+ ssl:handshake_cancel(Socket0);
+ Result ->
+ ct:log("~p:~p~nssl:handshake@~p ret ~p",[?MODULE,?LINE, Node,Result]),
+ Result
+ end;
+connect(ListenSocket, Node, N, _, Timeout, SslOpts, [_|_] =ContOpts) ->
ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
- {ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept,
- [ListenSocket]),
+ {ok, AcceptSocket} = ssl:transport_accept(ListenSocket),
+ ct:log("~p:~p~nssl:handshake(~p,~p,~p)~n", [?MODULE,?LINE, AcceptSocket, SslOpts,Timeout]),
+
+ case ssl:handshake(AcceptSocket, SslOpts, Timeout) of
+ {ok, Socket0, Ext} ->
+ ct:log("Ext ~p:~n", [Ext]),
+ ct:log("~p:~p~nssl:handshake_continue(~p,~p,~p)~n", [?MODULE,?LINE, Socket0, ContOpts,Timeout]),
+ case ssl:handshake_continue(Socket0, ContOpts, Timeout) of
+ {ok, Socket} ->
+ connect(ListenSocket, Node, N-1, Socket, Timeout, SslOpts, ContOpts);
+ Error ->
+ ct:log("~p:~p~nssl:handshake_continue@~p ret ~p",[?MODULE,?LINE, Node,Error]),
+ Error
+ end;
+ Result ->
+ ct:log("~p:~p~nssl:handshake@~p ret ~p",[?MODULE,?LINE, Node,Result]),
+ Result
+ end;
+connect(ListenSocket, Node, N, _, Timeout, [], ContOpts) ->
+ ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
+ {ok, AcceptSocket} = ssl:transport_accept(ListenSocket),
ct:log("~p:~p~nssl:ssl_accept(~p, ~p)~n", [?MODULE,?LINE, AcceptSocket, Timeout]),
- case rpc:call(Node, ssl, ssl_accept, [AcceptSocket, Timeout]) of
- ok ->
- connect(ListenSocket, Node, N-1, AcceptSocket, Timeout, []);
+ case ssl:handshake(AcceptSocket, Timeout) of
+ {ok, Socket} ->
+ connect(ListenSocket, Node, N-1, Socket, Timeout, [], ContOpts);
Result ->
- ct:log("~p:~p~nssl:ssl_accept@~p ret ~p",[?MODULE,?LINE, Node,Result]),
+ ct:log("~p:~p~nssl:handshake@~p ret ~p",[?MODULE,?LINE, Node,Result]),
Result
end;
-connect(ListenSocket, Node, _, _, Timeout, Opts) ->
+connect(ListenSocket, _Node, _, _, Timeout, Opts, _) ->
ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
- {ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept,
- [ListenSocket]),
- ct:log("ssl:ssl_accept(~p,~p, ~p)~n", [AcceptSocket, Opts, Timeout]),
- rpc:call(Node, ssl, ssl_accept, [AcceptSocket, Opts, Timeout]),
+ {ok, AcceptSocket} = ssl:transport_accept(ListenSocket),
+ ct:log("ssl:handshake(~p,~p, ~p)~n", [AcceptSocket, Opts, Timeout]),
+ ssl:handshake(AcceptSocket, Opts, Timeout),
AcceptSocket.
+
+start_server_transport_abuse_socket(Args) ->
+ Node = proplists:get_value(node, Args),
+ Result = spawn_link(Node, ?MODULE, transport_accept_abuse, [Args]),
+ receive
+ {listen, up} ->
+ Result
+ end.
+
+start_server_transport_control(Args) ->
+ Node = proplists:get_value(node, Args),
+ Result = spawn_link(Node, ?MODULE, transport_switch_control, [Args]),
+ receive
+ {listen, up} ->
+ Result
+ end.
+
+
+transport_accept_abuse(Opts) ->
+ Port = proplists:get_value(port, Opts),
+ Options = proplists:get_value(options, Opts),
+ Pid = proplists:get_value(from, Opts),
+ Transport = proplists:get_value(transport, Opts, ssl),
+ ct:log("~p:~p~nssl:listen(~p, ~p)~n", [?MODULE,?LINE, Port, Options]),
+ {ok, ListenSocket} = Transport:listen(Port, Options),
+ Pid ! {listen, up},
+ send_selected_port(Pid, Port, ListenSocket),
+ {ok, AcceptSocket} = ssl:transport_accept(ListenSocket),
+ {error, _} = ssl:connection_information(AcceptSocket),
+ _ = ssl:handshake(AcceptSocket, infinity),
+ Pid ! {self(), ok}.
+
+
+transport_switch_control(Opts) ->
+ Port = proplists:get_value(port, Opts),
+ Options = proplists:get_value(options, Opts),
+ Pid = proplists:get_value(from, Opts),
+ Transport = proplists:get_value(transport, Opts, ssl),
+ ct:log("~p:~p~nssl:listen(~p, ~p)~n", [?MODULE,?LINE, Port, Options]),
+ {ok, ListenSocket} = Transport:listen(Port, Options),
+ Pid ! {listen, up},
+ send_selected_port(Pid, Port, ListenSocket),
+ {ok, AcceptSocket} = ssl:transport_accept(ListenSocket),
+ ok = ssl:controlling_process(AcceptSocket, self()),
+ Pid ! {self(), ok}.
+
+
remove_close_msg(0) ->
ok;
remove_close_msg(ReconnectTimes) ->
@@ -165,7 +247,8 @@ remove_close_msg(ReconnectTimes) ->
end.
start_client(Args) ->
- Result = spawn_link(?MODULE, run_client_init, [lists:delete(return_socket, Args)]),
+ Node = proplists:get_value(node, Args),
+ Result = spawn_link(Node, ?MODULE, run_client_init, [lists:delete(return_socket, Args)]),
receive
{connected, Socket} ->
case lists:member(return_socket, Args) of
@@ -187,9 +270,18 @@ run_client(Opts) ->
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
Options = proplists:get_value(options, Opts),
+ ContOpts = proplists:get_value(continue_options, Opts, []),
ct:log("~p:~p~n~p:connect(~p, ~p)@~p~n", [?MODULE,?LINE, Transport, Host, Port, Node]),
ct:log("SSLOpts: ~p", [Options]),
- case rpc:call(Node, Transport, connect, [Host, Port, Options]) of
+ case ContOpts of
+ [] ->
+ client_loop(Node, Host, Port, Pid, Transport, Options, Opts);
+ _ ->
+ client_cont_loop(Node, Host, Port, Pid, Transport, Options, ContOpts, Opts)
+ end.
+
+client_loop(_Node, Host, Port, Pid, Transport, Options, Opts) ->
+ case Transport:connect(Host, Port, Options) of
{ok, Socket} ->
Pid ! {connected, Socket},
ct:log("~p:~p~nClient: connected~n", [?MODULE,?LINE]),
@@ -199,7 +291,7 @@ run_client(Opts) ->
{Module, Function, Args} = proplists:get_value(mfa, Opts),
ct:log("~p:~p~nClient: apply(~p,~p,~p)~n",
[?MODULE,?LINE, Module, Function, [Socket | Args]]),
- case rpc:call(Node, Module, Function, [Socket | Args]) of
+ case apply(Module, Function, [Socket | Args]) of
no_result_msg ->
ok;
Msg ->
@@ -209,7 +301,7 @@ run_client(Opts) ->
receive
close ->
ct:log("~p:~p~nClient closing~n", [?MODULE,?LINE]),
- rpc:call(Node, Transport, close, [Socket]);
+ Transport:close(Socket);
{ssl_closed, Socket} ->
ok;
{gen_tcp, closed} ->
@@ -239,12 +331,43 @@ run_client(Opts) ->
end;
{error, Reason} ->
ct:log("~p:~p~nClient: connection failed: ~p ~n", [?MODULE,?LINE, Reason]),
- Pid ! {connect_failed, Reason};
- {badrpc,BadRPC} ->
- ct:log("~p:~p~nBad rpc: ~p",[?MODULE,?LINE, BadRPC]),
- Pid ! {connect_failed, {badrpc,BadRPC}}
+ Pid ! {connect_failed, Reason}
end.
+client_cont_loop(_Node, Host, Port, Pid, Transport, Options, cancel, _Opts) ->
+ case Transport:connect(Host, Port, Options) of
+ {ok, Socket, _} ->
+ Result = Transport:handshake_cancel(Socket),
+ ct:log("~p:~p~nClient: Cancel: ~p ~n", [?MODULE,?LINE, Result]),
+ Pid ! {connect_failed, Result};
+ {error, Reason} ->
+ ct:log("~p:~p~nClient: connection failed: ~p ~n", [?MODULE,?LINE, Reason]),
+ Pid ! {connect_failed, Reason}
+ end;
+
+client_cont_loop(_Node, Host, Port, Pid, Transport, Options, ContOpts, Opts) ->
+ case Transport:connect(Host, Port, Options) of
+ {ok, Socket0, _} ->
+ ct:log("~p:~p~nClient: handshake_continue(~p, ~p, infinity) ~n", [?MODULE, ?LINE, Socket0, ContOpts]),
+ case Transport:handshake_continue(Socket0, ContOpts) of
+ {ok, Socket} ->
+ Pid ! {connected, Socket},
+ {Module, Function, Args} = proplists:get_value(mfa, Opts),
+ ct:log("~p:~p~nClient: apply(~p,~p,~p)~n",
+ [?MODULE,?LINE, Module, Function, [Socket | Args]]),
+ case apply(Module, Function, [Socket | Args]) of
+ no_result_msg ->
+ ok;
+ Msg ->
+ ct:log("~p:~p~nClient Msg: ~p ~n", [?MODULE,?LINE, Msg]),
+ Pid ! {self(), Msg}
+ end
+ end;
+ {error, Reason} ->
+ ct:log("~p:~p~nClient: connection failed: ~p ~n", [?MODULE,?LINE, Reason]),
+ Pid ! {connect_failed, Reason}
+ end.
+
close(Pid) ->
ct:log("~p:~p~nClose ~p ~n", [?MODULE,?LINE, Pid]),
Monitor = erlang:monitor(process, Pid),
@@ -304,6 +427,37 @@ check_result(Pid, Msg) ->
{got, Unexpected}},
ct:fail(Reason)
end.
+check_server_alert(Pid, Alert) ->
+ receive
+ {Pid, {error, {tls_alert, {Alert, _}}}} ->
+ ok
+ end.
+check_server_alert(Server, Client, Alert) ->
+ receive
+ {Server, {error, {tls_alert, {Alert, _}}}} ->
+ receive
+ {Client, {error, {tls_alert, {Alert, _}}}} ->
+ ok;
+ {Client, {error, closed}} ->
+ ok
+ end
+ end.
+check_client_alert(Pid, Alert) ->
+ receive
+ {Pid, {error, {tls_alert, {Alert, _}}}} ->
+ ok
+ end.
+check_client_alert(Server, Client, Alert) ->
+ receive
+ {Client, {error, {tls_alert, {Alert, _}}}} ->
+ receive
+ {Server, {error, {tls_alert, {Alert, _}}}} ->
+ ok;
+ {Server, {error, closed}} ->
+ ok
+ end
+ end.
+
wait_for_result(Server, ServerMsg, Client, ClientMsg) ->
receive
@@ -349,13 +503,6 @@ wait_for_result(Pid, Msg) ->
%% Unexpected
end.
-user_lookup(psk, _Identity, UserState) ->
- {ok, UserState};
-user_lookup(srp, Username, _UserState) ->
- Salt = ssl_cipher:random_bytes(16),
- UserPassHash = crypto:hash(sha, [Salt, crypto:hash(sha, [Username, <<$:>>, <<"secret">>])]),
- {ok, {srp_1024, Salt, UserPassHash}}.
-
cert_options(Config) ->
ClientCaCertFile = filename:join([proplists:get_value(priv_dir, Config),
"client", "cacerts.pem"]),
@@ -390,7 +537,7 @@ cert_options(Config) ->
{client_verification_opts, [{cacertfile, ServerCaCertFile},
{certfile, ClientCertFile},
{keyfile, ClientKeyFile},
- {ssl_imp, new}]},
+ {verify, verify_peer}]},
{client_verification_opts_digital_signature_only, [{cacertfile, ServerCaCertFile},
{certfile, ClientCertFileDigitalSignatureOnly},
{keyfile, ClientKeyFile},
@@ -484,10 +631,47 @@ make_rsa_cert_chains(UserConf, Config, Suffix) ->
[{reuseaddr, true}, {verify, verify_peer} | ServerConf]
}.
+make_ecc_cert_chains(UserConf, Config, Suffix) ->
+ ClientChain = proplists:get_value(client_chain, UserConf, default_cert_chain_conf()),
+ ServerChain = proplists:get_value(server_chain, UserConf, default_cert_chain_conf()),
+ CertChainConf = gen_conf(ecdsa, ecdsa, ClientChain, ServerChain),
+ ClientFileBase = filename:join([proplists:get_value(priv_dir, Config), "ecdsa" ++ Suffix]),
+ ServerFileBase = filename:join([proplists:get_value(priv_dir, Config), "ecdsa" ++ Suffix]),
+ GenCertData = public_key:pkix_test_data(CertChainConf),
+ [{server_config, ServerConf},
+ {client_config, ClientConf}] =
+ x509_test:gen_pem_config_files(GenCertData, ClientFileBase, ServerFileBase),
+ {[{verify, verify_peer} | ClientConf],
+ [{reuseaddr, true}, {verify, verify_peer} | ServerConf]
+ }.
+
+
+make_dsa_cert_chains(UserConf, Config, Suffix) ->
+ CryptoSupport = crypto:supports(),
+ case proplists:get_bool(dss, proplists:get_value(public_keys, CryptoSupport)) of
+ true ->
+ ClientChain = proplists:get_value(client_chain, UserConf, default_cert_chain_conf()),
+ ServerChain = proplists:get_value(server_chain, UserConf, default_cert_chain_conf()),
+ CertChainConf = gen_conf(dsa, dsa, ClientChain, ServerChain),
+ ClientFileBase = filename:join([proplists:get_value(priv_dir, Config), "dsa" ++ Suffix]),
+ ServerFileBase = filename:join([proplists:get_value(priv_dir, Config), "dsa" ++ Suffix]),
+ GenCertData = public_key:pkix_test_data(CertChainConf),
+ [{server_config, ServerConf},
+ {client_config, ClientConf}] =
+ x509_test:gen_pem_config_files(GenCertData, ClientFileBase, ServerFileBase),
+ {[{verify, verify_peer} | ClientConf],
+ [{reuseaddr, true}, {verify, verify_peer} | ServerConf]};
+ false ->
+ Config
+ end.
+
make_ec_cert_chains(UserConf, ClientChainType, ServerChainType, Config) ->
+ make_ec_cert_chains(UserConf, ClientChainType, ServerChainType, Config, ?DEFAULT_CURVE).
+%%
+make_ec_cert_chains(UserConf, ClientChainType, ServerChainType, Config, Curve) ->
ClientChain = proplists:get_value(client_chain, UserConf, default_cert_chain_conf()),
ServerChain = proplists:get_value(server_chain, UserConf, default_cert_chain_conf()),
- CertChainConf = gen_conf(ClientChainType, ServerChainType, ClientChain, ServerChain),
+ CertChainConf = gen_conf(ClientChainType, ServerChainType, ClientChain, ServerChain, Curve),
ClientFileBase = filename:join([proplists:get_value(priv_dir, Config), atom_to_list(ClientChainType)]),
ServerFileBase = filename:join([proplists:get_value(priv_dir, Config), atom_to_list(ServerChainType)]),
GenCertData = public_key:pkix_test_data(CertChainConf),
@@ -502,12 +686,27 @@ default_cert_chain_conf() ->
%% Use only default options
[[],[],[]].
+
gen_conf(ClientChainType, ServerChainType, UserClient, UserServer) ->
+ gen_conf(ClientChainType, ServerChainType, UserClient, UserServer, ?DEFAULT_CURVE).
+%%
+gen_conf(mix, mix, UserClient, UserServer, _) ->
ClientTag = conf_tag("client"),
ServerTag = conf_tag("server"),
- DefaultClient = chain_spec(client, ClientChainType),
- DefaultServer = chain_spec(server, ServerChainType),
+ DefaultClient = default_cert_chain_conf(),
+ DefaultServer = default_cert_chain_conf(),
+
+ ClientConf = merge_chain_spec(UserClient, DefaultClient, []),
+ ServerConf = merge_chain_spec(UserServer, DefaultServer, []),
+
+ new_format([{ClientTag, ClientConf}, {ServerTag, ServerConf}]);
+gen_conf(ClientChainType, ServerChainType, UserClient, UserServer, Curve) ->
+ ClientTag = conf_tag("client"),
+ ServerTag = conf_tag("server"),
+
+ DefaultClient = chain_spec(client, ClientChainType, Curve),
+ DefaultServer = chain_spec(server, ServerChainType, Curve),
ClientConf = merge_chain_spec(UserClient, DefaultClient, []),
ServerConf = merge_chain_spec(UserServer, DefaultServer, []),
@@ -529,43 +728,43 @@ proplist_to_map([Head | Rest]) ->
conf_tag(Role) ->
list_to_atom(Role ++ "_chain").
-chain_spec(_Role, ecdh_rsa) ->
+chain_spec(_Role, ecdh_rsa, Curve) ->
Digest = {digest, appropriate_sha(crypto:supports())},
- CurveOid = hd(tls_v1:ecc_curves(0)),
+ CurveOid = pubkey_cert_records:namedCurves(Curve),
[[Digest, {key, {namedCurve, CurveOid}}],
[Digest, {key, hardcode_rsa_key(1)}],
[Digest, {key, {namedCurve, CurveOid}}]];
-chain_spec(_Role, ecdhe_ecdsa) ->
+chain_spec(_Role, ecdhe_ecdsa, Curve) ->
Digest = {digest, appropriate_sha(crypto:supports())},
- CurveOid = hd(tls_v1:ecc_curves(0)),
+ CurveOid = pubkey_cert_records:namedCurves(Curve),
[[Digest, {key, {namedCurve, CurveOid}}],
[Digest, {key, {namedCurve, CurveOid}}],
[Digest, {key, {namedCurve, CurveOid}}]];
-chain_spec(_Role, ecdh_ecdsa) ->
+chain_spec(_Role, ecdh_ecdsa, Curve) ->
Digest = {digest, appropriate_sha(crypto:supports())},
- CurveOid = hd(tls_v1:ecc_curves(0)),
+ CurveOid = pubkey_cert_records:namedCurves(Curve),
[[Digest, {key, {namedCurve, CurveOid}}],
[Digest, {key, {namedCurve, CurveOid}}],
[Digest, {key, {namedCurve, CurveOid}}]];
-chain_spec(_Role, ecdhe_rsa) ->
+chain_spec(_Role, ecdhe_rsa, _) ->
Digest = {digest, appropriate_sha(crypto:supports())},
[[Digest, {key, hardcode_rsa_key(1)}],
[Digest, {key, hardcode_rsa_key(2)}],
[Digest, {key, hardcode_rsa_key(3)}]];
-chain_spec(_Role, ecdsa) ->
+chain_spec(_Role, ecdsa, Curve) ->
Digest = {digest, appropriate_sha(crypto:supports())},
- CurveOid = hd(tls_v1:ecc_curves(0)),
+ CurveOid = pubkey_cert_records:namedCurves(Curve),
[[Digest, {key, {namedCurve, CurveOid}}],
[Digest, {key, {namedCurve, CurveOid}}],
[Digest, {key, {namedCurve, CurveOid}}]];
-chain_spec(_Role, rsa) ->
+chain_spec(_Role, rsa, _) ->
Digest = {digest, appropriate_sha(crypto:supports())},
[[Digest, {key, hardcode_rsa_key(1)}],
[Digest, {key, hardcode_rsa_key(2)}],
[Digest, {key, hardcode_rsa_key(3)}]];
-chain_spec(_Role, dsa) ->
+chain_spec(_Role, dsa, _) ->
Digest = {digest, appropriate_sha(crypto:supports())},
[[Digest, {key, hardcode_dsa_key(1)}],
[Digest, {key, hardcode_dsa_key(2)}],
@@ -595,6 +794,46 @@ merge_spec(User, Default, [Conf | Rest], Acc) ->
merge_spec(User, Default, Rest, [{Conf, Value} | Acc])
end.
+make_mix_cert(Config) ->
+ Ext = x509_test:extensions([{key_usage, [digitalSignature]}]),
+ Digest = {digest, appropriate_sha(crypto:supports())},
+ CurveOid = pubkey_cert_records:namedCurves(?DEFAULT_CURVE),
+ Mix = proplists:get_value(mix, Config, peer_ecc),
+ ClientChainType =ServerChainType = mix,
+ {ClientChain, ServerChain} = mix(Mix, Digest, CurveOid, Ext),
+ CertChainConf = gen_conf(ClientChainType, ServerChainType, ClientChain, ServerChain),
+ ClientFileBase = filename:join([proplists:get_value(priv_dir, Config), "mix" ++ atom_to_list(Mix)]),
+ ServerFileBase = filename:join([proplists:get_value(priv_dir, Config), "mix" ++ atom_to_list(Mix)]),
+ GenCertData = public_key:pkix_test_data(CertChainConf),
+ [{server_config, ServerConf},
+ {client_config, ClientConf}] =
+ x509_test:gen_pem_config_files(GenCertData, ClientFileBase, ServerFileBase),
+ {[{verify, verify_peer} | ClientConf],
+ [{reuseaddr, true}, {verify, verify_peer} | ServerConf]
+ }.
+
+mix(peer_ecc, Digest, CurveOid, Ext) ->
+ ClientChain = [[Digest, {key, {namedCurve, CurveOid}}],
+ [Digest, {key, hardcode_rsa_key(1)}],
+ [Digest, {key, {namedCurve, CurveOid}}, {extensions, Ext}]
+ ],
+ ServerChain = [[Digest, {key, {namedCurve, CurveOid}}],
+ [Digest, {key, hardcode_rsa_key(2)}],
+ [Digest, {key, {namedCurve, CurveOid}},{extensions, Ext}]
+ ],
+ {ClientChain, ServerChain};
+
+mix(peer_rsa, Digest, CurveOid, Ext) ->
+ ClientChain = [[Digest, {key, {namedCurve, CurveOid}}],
+ [Digest, {key, {namedCurve, CurveOid}}],
+ [Digest, {key, hardcode_rsa_key(1)}, {extensions, Ext}]
+ ],
+ ServerChain = [[Digest, {key, {namedCurve, CurveOid}}],
+ [Digest, {key, {namedCurve, CurveOid}}],
+ [Digest, {key, hardcode_rsa_key(2)},{extensions, Ext}]
+ ],
+ {ClientChain, ServerChain}.
+
make_ecdsa_cert(Config) ->
CryptoSupport = crypto:supports(),
case proplists:get_bool(ecdsa, proplists:get_value(public_keys, CryptoSupport)) of
@@ -641,7 +880,8 @@ make_rsa_cert(Config) ->
Config
end.
appropriate_sha(CryptoSupport) ->
- case proplists:get_bool(sha256, CryptoSupport) of
+ Hashes = proplists:get_value(hashs, CryptoSupport),
+ case lists:member(sha256, Hashes) of
true ->
sha256;
false ->
@@ -679,14 +919,14 @@ make_ecdh_rsa_cert(Config) ->
end.
start_upgrade_server(Args) ->
- Result = spawn_link(?MODULE, run_upgrade_server, [Args]),
+ Node = proplists:get_value(node, Args),
+ Result = spawn_link(Node, ?MODULE, run_upgrade_server, [Args]),
receive
{listen, up} ->
Result
end.
run_upgrade_server(Opts) ->
- Node = proplists:get_value(node, Opts),
Port = proplists:get_value(port, Opts),
TimeOut = proplists:get_value(timeout, Opts, infinity),
TcpOptions = proplists:get_value(tcp_options, Opts),
@@ -694,43 +934,41 @@ run_upgrade_server(Opts) ->
Pid = proplists:get_value(from, Opts),
ct:log("~p:~p~ngen_tcp:listen(~p, ~p)~n", [?MODULE,?LINE, Port, TcpOptions]),
- {ok, ListenSocket} = rpc:call(Node, gen_tcp, listen, [Port, TcpOptions]),
+ {ok, ListenSocket} = gen_tcp:listen(Port, TcpOptions),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
ct:log("~p:~p~ngen_tcp:accept(~p)~n", [?MODULE,?LINE, ListenSocket]),
- {ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, [ListenSocket]),
+ {ok, AcceptSocket} = gen_tcp:accept(ListenSocket),
try
{ok, SslAcceptSocket} = case TimeOut of
infinity ->
- ct:log("~p:~p~nssl:ssl_accept(~p, ~p)~n",
+ ct:log("~p:~p~nssl:handshake(~p, ~p)~n",
[?MODULE,?LINE, AcceptSocket, SslOptions]),
- rpc:call(Node, ssl, ssl_accept,
- [AcceptSocket, SslOptions]);
+ ssl:handshake(AcceptSocket, SslOptions);
_ ->
- ct:log("~p:~p~nssl:ssl_accept(~p, ~p, ~p)~n",
+ ct:log("~p:~p~nssl:handshake(~p, ~p, ~p)~n",
[?MODULE,?LINE, AcceptSocket, SslOptions, TimeOut]),
- rpc:call(Node, ssl, ssl_accept,
- [AcceptSocket, SslOptions, TimeOut])
+ ssl:handshake(AcceptSocket, SslOptions, TimeOut)
end,
{Module, Function, Args} = proplists:get_value(mfa, Opts),
- Msg = rpc:call(Node, Module, Function, [SslAcceptSocket | Args]),
+ Msg = apply(Module, Function, [SslAcceptSocket | Args]),
ct:log("~p:~p~nUpgrade Server Msg: ~p ~n", [?MODULE,?LINE, Msg]),
Pid ! {self(), Msg},
receive
close ->
ct:log("~p:~p~nUpgrade Server closing~n", [?MODULE,?LINE]),
- rpc:call(Node, ssl, close, [SslAcceptSocket])
+ ssl:close(SslAcceptSocket)
end
catch error:{badmatch, Error} ->
Pid ! {self(), Error}
end.
start_upgrade_client(Args) ->
- spawn_link(?MODULE, run_upgrade_client, [Args]).
+ Node = proplists:get_value(node, Args),
+ spawn_link(Node, ?MODULE, run_upgrade_client, [Args]).
run_upgrade_client(Opts) ->
- Node = proplists:get_value(node, Opts),
Host = proplists:get_value(host, Opts),
Port = proplists:get_value(port, Opts),
Pid = proplists:get_value(from, Opts),
@@ -739,34 +977,34 @@ run_upgrade_client(Opts) ->
ct:log("~p:~p~ngen_tcp:connect(~p, ~p, ~p)~n",
[?MODULE,?LINE, Host, Port, TcpOptions]),
- {ok, Socket} = rpc:call(Node, gen_tcp, connect, [Host, Port, TcpOptions]),
+ {ok, Socket} = gen_tcp:connect(Host, Port, TcpOptions),
send_selected_port(Pid, Port, Socket),
ct:log("~p:~p~nssl:connect(~p, ~p)~n", [?MODULE,?LINE, Socket, SslOptions]),
- {ok, SslSocket} = rpc:call(Node, ssl, connect, [Socket, SslOptions]),
+ {ok, SslSocket} = ssl:connect(Socket, SslOptions),
{Module, Function, Args} = proplists:get_value(mfa, Opts),
ct:log("~p:~p~napply(~p, ~p, ~p)~n",
[?MODULE,?LINE, Module, Function, [SslSocket | Args]]),
- Msg = rpc:call(Node, Module, Function, [SslSocket | Args]),
+ Msg = apply(Module, Function, [SslSocket | Args]),
ct:log("~p:~p~nUpgrade Client Msg: ~p ~n", [?MODULE,?LINE, Msg]),
Pid ! {self(), Msg},
receive
close ->
ct:log("~p:~p~nUpgrade Client closing~n", [?MODULE,?LINE]),
- rpc:call(Node, ssl, close, [SslSocket])
+ ssl:close(SslSocket)
end.
start_upgrade_server_error(Args) ->
- Result = spawn_link(?MODULE, run_upgrade_server_error, [Args]),
+ Node = proplists:get_value(node, Args),
+ Result = spawn_link(Node,?MODULE, run_upgrade_server_error, [Args]),
receive
{listen, up} ->
Result
end.
run_upgrade_server_error(Opts) ->
- Node = proplists:get_value(node, Opts),
Port = proplists:get_value(port, Opts),
TimeOut = proplists:get_value(timeout, Opts, infinity),
TcpOptions = proplists:get_value(tcp_options, Opts),
@@ -774,22 +1012,20 @@ run_upgrade_server_error(Opts) ->
Pid = proplists:get_value(from, Opts),
ct:log("~p:~p~ngen_tcp:listen(~p, ~p)~n", [?MODULE,?LINE, Port, TcpOptions]),
- {ok, ListenSocket} = rpc:call(Node, gen_tcp, listen, [Port, TcpOptions]),
+ {ok, ListenSocket} = gen_tcp:listen(Port, TcpOptions),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
ct:log("~p:~p~ngen_tcp:accept(~p)~n", [?MODULE,?LINE, ListenSocket]),
- {ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, [ListenSocket]),
+ {ok, AcceptSocket} = gen_tcp:accept(ListenSocket),
Error = case TimeOut of
infinity ->
- ct:log("~p:~p~nssl:ssl_accept(~p, ~p)~n",
+ ct:log("~p:~p~nssl:handshake(~p, ~p)~n",
[?MODULE,?LINE, AcceptSocket, SslOptions]),
- rpc:call(Node, ssl, ssl_accept,
- [AcceptSocket, SslOptions]);
+ ssl:handshake(AcceptSocket, SslOptions);
_ ->
- ct:log("~p:~p~nssl:ssl_accept(~p, ~p, ~p)~n",
+ ct:log("~p:~p~nssl:ssl_handshake(~p, ~p, ~p)~n",
[?MODULE,?LINE, AcceptSocket, SslOptions, TimeOut]),
- rpc:call(Node, ssl, ssl_accept,
- [AcceptSocket, SslOptions, TimeOut])
+ ssl:handshake(AcceptSocket, SslOptions, TimeOut)
end,
Pid ! {self(), Error}.
@@ -801,32 +1037,31 @@ start_server_error(Args) ->
end.
run_server_error(Opts) ->
- Node = proplists:get_value(node, Opts),
Port = proplists:get_value(port, Opts),
Options = proplists:get_value(options, Opts),
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
ct:log("~p:~p~nssl:listen(~p, ~p)~n", [?MODULE,?LINE, Port, Options]),
- case rpc:call(Node, Transport, listen, [Port, Options]) of
+ case Transport:listen(Port, Options) of
{ok, #sslsocket{} = ListenSocket} ->
%% To make sure error_client will
%% get {error, closed} and not {error, connection_refused}
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
ct:log("~p:~p~nssl:transport_accept(~p)~n", [?MODULE,?LINE, ListenSocket]),
- case rpc:call(Node, Transport, transport_accept, [ListenSocket]) of
+ case Transport:transport_accept(ListenSocket) of
{error, _} = Error ->
Pid ! {self(), Error};
{ok, AcceptSocket} ->
ct:log("~p:~p~nssl:ssl_accept(~p)~n", [?MODULE,?LINE, AcceptSocket]),
- Error = rpc:call(Node, ssl, ssl_accept, [AcceptSocket]),
+ Error = ssl:handshake(AcceptSocket),
Pid ! {self(), Error}
end;
{ok, ListenSocket} ->
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
ct:log("~p:~p~n~p:accept(~p)~n", [?MODULE,?LINE, Transport, ListenSocket]),
- case rpc:call(Node, Transport, accept, [ListenSocket]) of
+ case Transport:accept(ListenSocket) of
{error, _} = Error ->
Pid ! {self(), Error}
end;
@@ -838,17 +1073,17 @@ run_server_error(Opts) ->
end.
start_client_error(Args) ->
- spawn_link(?MODULE, run_client_error, [Args]).
+ Node = proplists:get_value(node, Args),
+ spawn_link(Node, ?MODULE, run_client_error, [Args]).
run_client_error(Opts) ->
- Node = proplists:get_value(node, Opts),
Host = proplists:get_value(host, Opts),
Port = proplists:get_value(port, Opts),
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
Options = proplists:get_value(options, Opts),
ct:log("~p:~p~nssl:connect(~p, ~p, ~p)~n", [?MODULE,?LINE, Host, Port, Options]),
- Error = rpc:call(Node, Transport, connect, [Host, Port, Options]),
+ Error = Transport:connect(Host, Port, Options),
Pid ! {self(), Error}.
accepters(N) ->
@@ -862,6 +1097,222 @@ accepters(Acc, N) ->
accepters([Server| Acc], N-1)
end.
+
+basic_test(COpts, SOpts, Config) ->
+ SType = proplists:get_value(server_type, Config),
+ CType = proplists:get_value(client_type, Config),
+ {Server, Port} = start_server(SType, COpts, SOpts, Config),
+ Client = start_client(CType, Port, COpts, Config),
+ gen_check_result(Server, SType, Client, CType),
+ stop(Server, Client).
+
+ecc_test(Expect, COpts, SOpts, CECCOpts, SECCOpts, Config) ->
+ {Server, Port} = start_server_ecc(erlang, SOpts, Expect, SECCOpts, Config),
+ Client = start_client_ecc(erlang, Port, COpts, Expect, CECCOpts, Config),
+ check_result(Server, ok, Client, ok),
+ stop(Server, Client).
+
+ecc_test_error(COpts, SOpts, CECCOpts, SECCOpts, Config) ->
+ {Server, Port} = start_server_ecc_error(erlang, SOpts, SECCOpts, Config),
+ Client = start_client_ecc_error(erlang, Port, COpts, CECCOpts, Config),
+ check_server_alert(Server, Client, insufficient_security).
+
+start_basic_client(openssl, Version, Port, ClientOpts) ->
+ Cert = proplists:get_value(certfile, ClientOpts),
+ Key = proplists:get_value(keyfile, ClientOpts),
+ CA = proplists:get_value(cacertfile, ClientOpts),
+ Groups0 = proplists:get_value(groups, ClientOpts),
+ Exe = "openssl",
+ Args0 = ["s_client", "-verify", "2", "-port", integer_to_list(Port),
+ ssl_test_lib:version_flag(Version),
+ "-CAfile", CA, "-host", "localhost", "-msg", "-debug"],
+ Args1 =
+ case Groups0 of
+ undefined ->
+ Args0;
+ G ->
+ Args0 ++ ["-groups", G]
+ end,
+ Args =
+ case {Cert, Key} of
+ {C, K} when C =:= undefined orelse
+ K =:= undefined ->
+ Args1;
+ {C, K} ->
+ Args1 ++ ["-cert", C, "-key", K]
+ end,
+
+ OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
+ true = port_command(OpenSslPort, "Hello world"),
+ OpenSslPort.
+
+start_client(openssl, Port, ClientOpts, Config) ->
+ Cert = proplists:get_value(certfile, ClientOpts),
+ Key = proplists:get_value(keyfile, ClientOpts),
+ CA = proplists:get_value(cacertfile, ClientOpts),
+ Version = ssl_test_lib:protocol_version(Config),
+ Exe = "openssl",
+ Args0 = ["s_client", "-verify", "2", "-port", integer_to_list(Port),
+ ssl_test_lib:version_flag(Version),
+ "-cert", Cert, "-CAfile", CA,
+ "-key", Key, "-host","localhost", "-msg", "-debug"],
+ Args = maybe_force_ipv4(Args0),
+ OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
+ true = port_command(OpenSslPort, "Hello world"),
+ OpenSslPort;
+
+start_client(erlang, Port, ClientOpts, Config) ->
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+ KeyEx = proplists:get_value(check_keyex, Config, false),
+ ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, check_key_exchange_send_active, [KeyEx]}},
+ {options, ClientOpts}]).
+
+%% Workaround for running tests on machines where openssl
+%% s_client would use an IPv6 address with localhost. As
+%% this test suite and the ssl application is not prepared
+%% for that we have to force s_client to use IPv4 if
+%% OpenSSL supports IPv6.
+maybe_force_ipv4(Args0) ->
+ case is_ipv6_supported() of
+ true ->
+ Args0 ++ ["-4"];
+ false ->
+ Args0
+ end.
+
+start_client_ecc(erlang, Port, ClientOpts, Expect, ECCOpts, Config) ->
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+ ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, check_ecc, [client, Expect]}},
+ {options,
+ ECCOpts ++
+ [{verify, verify_peer} | ClientOpts]}]).
+
+start_client_ecc_error(erlang, Port, ClientOpts, ECCOpts, Config) ->
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+ ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {options,
+ ECCOpts ++
+ [{verify, verify_peer} | ClientOpts]}]).
+
+
+start_server(openssl, ClientOpts, ServerOpts, Config) ->
+ Port = inet_port(node()),
+ Version = protocol_version(Config),
+ Exe = "openssl",
+ CertArgs = openssl_cert_options(ServerOpts),
+ [Cipher|_] = proplists:get_value(ciphers, ClientOpts, ssl:cipher_suites(default,Version)),
+ Args = ["s_server", "-accept", integer_to_list(Port), "-cipher",
+ ssl_cipher_format:suite_map_to_openssl_str(Cipher),
+ ssl_test_lib:version_flag(Version)] ++ CertArgs ++ ["-msg", "-debug"],
+ OpenSslPort = portable_open_port(Exe, Args),
+ true = port_command(OpenSslPort, "Hello world"),
+ {OpenSslPort, Port};
+start_server(erlang, _, ServerOpts, Config) ->
+ {_, ServerNode, _} = ssl_test_lib:run_where(Config),
+ KeyEx = proplists:get_value(check_keyex, Config, false),
+ Server = start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ check_key_exchange_send_active,
+ [KeyEx]}},
+ {options, [{verify, verify_peer} | ServerOpts]}]),
+ {Server, inet_port(Server)}.
+
+start_server_with_raw_key(erlang, ServerOpts, Config) ->
+ {_, ServerNode, _} = ssl_test_lib:run_where(Config),
+ Server = start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ send_recv_result_active,
+ []}},
+ {options,
+ [{verify, verify_peer} | ServerOpts]}]),
+ {Server, inet_port(Server)}.
+
+start_server_ecc(erlang, ServerOpts, Expect, ECCOpts, Config) ->
+ {_, ServerNode, _} = run_where(Config),
+ Server = start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, check_ecc, [server, Expect]}},
+ {options,
+ ECCOpts ++
+ [{verify, verify_peer} | ServerOpts]}]),
+ {Server, inet_port(Server)}.
+
+start_server_ecc_error(erlang, ServerOpts, ECCOpts, Config) ->
+ {_, ServerNode, _} = run_where(Config),
+ Server = start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options,
+ ECCOpts ++
+ [{verify, verify_peer} | ServerOpts]}]),
+ {Server, inet_port(Server)}.
+
+gen_check_result(Server, erlang, Client, erlang) ->
+ check_result(Server, ok, Client, ok);
+gen_check_result(Server, erlang, _, _) ->
+ check_result(Server, ok);
+gen_check_result(_, _, Client, erlang) ->
+ check_result(Client, ok);
+gen_check_result(_,openssl, _, openssl) ->
+ ok.
+
+stop(Port1, Port2) when is_port(Port1), is_port(Port2) ->
+ close_port(Port1),
+ close_port(Port2);
+stop(Port, Pid) when is_port(Port) ->
+ close_port(Port),
+ close(Pid);
+stop(Pid, Port) when is_port(Port) ->
+ close_port(Port),
+ close(Pid);
+stop(Client, Server) ->
+ close(Server),
+ close(Client).
+
+
+openssl_cert_options(ServerOpts) ->
+ Cert = proplists:get_value(certfile, ServerOpts, undefined),
+ Key = proplists:get_value(keyfile, ServerOpts, undefined),
+ CA = proplists:get_value(cacertfile, ServerOpts, undefined),
+ case CA of
+ undefined ->
+ case cert_option("-cert", Cert) ++ cert_option("-key", Key) of
+ [] ->
+ ["-nocert"];
+ Other ->
+ Other
+ end;
+ _ ->
+ cert_option("-cert", Cert) ++ cert_option("-CAfile", CA) ++
+ cert_option("-key", Key) ++ ["-verify", "2"]
+ end.
+
+cert_option(_, undefined) ->
+ [];
+cert_option(Opt, Value) ->
+ [Opt, Value].
+
+supported_eccs(Opts) ->
+ ToCheck = proplists:get_value(eccs, Opts, []),
+ Supported = ssl:eccs(),
+ lists:all(fun(Curve) -> lists:member(Curve, Supported) end, ToCheck).
+
+check_ecc(SSL, Role, Expect) ->
+ {ok, Data} = ssl:connection_information(SSL),
+ case lists:keyfind(ecc, 1, Data) of
+ {ecc, {named_curve, Expect}} -> ok;
+ Other -> {error, Role, Expect, Other}
+ end.
+
inet_port(Pid) when is_pid(Pid)->
receive
{Pid, {port, Port}} ->
@@ -930,13 +1381,13 @@ rsa_suites(CounterPart) ->
lists:member(cipher_atom(Cipher), Ciphers);
({ecdhe_rsa, Cipher, _}) when ECC == true ->
lists:member(cipher_atom(Cipher), Ciphers);
+ ({ecdhe_rsa, Cipher, _,_}) when ECC == true ->
+ lists:member(cipher_atom(Cipher), Ciphers);
({rsa, Cipher, _, _}) ->
lists:member(cipher_atom(Cipher), Ciphers);
({dhe_rsa, Cipher, _,_}) ->
lists:member(cipher_atom(Cipher), Ciphers);
- ({ecdhe_rsa, Cipher, _,_}) when ECC == true ->
- lists:member(cipher_atom(Cipher), Ciphers);
- (_) ->
+ (_) ->
false
end,
common_ciphers(CounterPart)).
@@ -946,13 +1397,13 @@ common_ciphers(crypto) ->
common_ciphers(openssl) ->
OpenSslSuites =
string:tokens(string:strip(os:cmd("openssl ciphers"), right, $\n), ":"),
- [ssl_cipher:erl_suite_definition(S)
+ [ssl_cipher_format:suite_bin_to_map(S)
|| S <- ssl_cipher:suites(tls_record:highest_protocol_version([])),
- lists:member(ssl_cipher:openssl_suite_name(S), OpenSslSuites)
+ lists:member(ssl_cipher_format:suite_map_to_openssl_str(ssl_cipher_format:suite_bin_to_map(S)), OpenSslSuites)
].
available_suites(Version) ->
- [ssl_cipher:erl_suite_definition(Suite) ||
+ [ssl_cipher_format:suite_bin_to_map(Suite) ||
Suite <- ssl_cipher:filter_suites(ssl_cipher:suites(Version))].
@@ -1024,24 +1475,52 @@ string_regex_filter(Str, Search) when is_list(Str) ->
string_regex_filter(_Str, _Search) ->
false.
-anonymous_suites(Version) ->
- ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:anonymous_suites(Version)],[]).
+ecdh_dh_anonymous_suites(Version) ->
+ ssl:filter_cipher_suites([ssl_cipher_format:suite_bin_to_map(S) || S <- ssl_cipher:anonymous_suites(Version)],
+ [{key_exchange,
+ fun(dh_anon) ->
+ true;
+ (ecdh_anon) ->
+ true;
+ (_) ->
+ false
+ end}]).
+psk_suites({3,_} = Version) ->
+ ssl:filter_cipher_suites([ssl_cipher_format:suite_bin_to_map(S) || S <- ssl_cipher:psk_suites(Version)], []);
psk_suites(Version) ->
- ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:psk_suites(Version)], []).
+ ssl:filter_cipher_suites(psk_suites(dtls_v1:corresponding_tls_version(Version)),
+ [{cipher,
+ fun(rc4_128) ->
+ false;
+ (_) ->
+ true
+ end}]).
-psk_anon_suites(Version) ->
- ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:psk_suites_anon(Version)],
+psk_anon_suites({3,_} = Version) ->
+ ssl:filter_cipher_suites([ssl_cipher_format:suite_bin_to_map(S) || S <- ssl_cipher:psk_suites_anon(Version)],
[{key_exchange,
fun(psk) ->
true;
- (psk_dhe) ->
+ (dhe_psk) ->
+ true;
+ (ecdhe_psk) ->
true;
(_) ->
false
+ end}]);
+
+psk_anon_suites(Version) ->
+ ssl:filter_cipher_suites(psk_anon_suites(dtls_v1:corresponding_tls_version(Version)),
+ [{cipher,
+ fun(rc4_128) ->
+ false;
+ (_) ->
+ true
end}]).
+
srp_suites() ->
- ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:srp_suites()],
+ ssl:filter_cipher_suites([ssl_cipher_format:suite_bin_to_map(S) || S <- ssl_cipher:srp_suites()],
[{key_exchange,
fun(srp_rsa) ->
true;
@@ -1049,21 +1528,25 @@ srp_suites() ->
false
end}]).
srp_anon_suites() ->
- ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:srp_suites_anon()],
+ ssl:filter_cipher_suites([ssl_cipher_format:suite_bin_to_map(S) || S <- ssl_cipher:srp_suites_anon()],
[]).
srp_dss_suites() ->
- ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:srp_suites()],
+ ssl:filter_cipher_suites([ssl_cipher_format:suite_bin_to_map(S) || S <- ssl_cipher:srp_suites()],
[{key_exchange,
fun(srp_dss) ->
true;
(_) ->
false
end}]).
+chacha_suites(Version) ->
+ [ssl_cipher_format:suite_bin_to_map(S) || S <- ssl_cipher:filter_suites(ssl_cipher:chacha_suites(Version))].
+
+
rc4_suites(Version) ->
- ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <-ssl_cipher:rc4_suites(Version)], []).
+ ssl:filter_cipher_suites([ssl_cipher_format:suite_bin_to_map(S) || S <-ssl_cipher:rc4_suites(Version)], []).
des_suites(Version) ->
- ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <-ssl_cipher:des_suites(Version)], []).
+ ssl:filter_cipher_suites([ssl_cipher_format:suite_bin_to_map(S) || S <-ssl_cipher:des_suites(Version)], []).
tuple_to_map({Kex, Cipher, Mac}) ->
#{key_exchange => Kex,
@@ -1086,24 +1569,18 @@ der_to_pem(File, Entries) ->
cipher_result(Socket, Result) ->
{ok, Info} = ssl:connection_information(Socket),
- Result = {ok, {proplists:get_value(protocol, Info), proplists:get_value(cipher_suite, Info)}},
+ Result = {ok, {proplists:get_value(protocol, Info), proplists:get_value(selected_cipher_suite, Info)}},
ct:log("~p:~p~nSuccessfull connect: ~p~n", [?MODULE,?LINE, Result]),
%% Importante to send two packets here
%% to properly test "cipher state" handling
- ssl:send(Socket, "Hello\n"),
- receive
- {ssl, Socket, "H"} ->
- ssl:send(Socket, " world\n"),
- receive_rizzo_duong_beast();
- {ssl, Socket, "Hello\n"} ->
- ssl:send(Socket, " world\n"),
- receive
- {ssl, Socket, " world\n"} ->
- ok
- end;
- Other ->
- {unexpected, Other}
- end.
+ Hello = "Hello\n",
+ World = " world\n",
+ ssl:send(Socket, Hello),
+ ct:sleep(500),
+ ssl:send(Socket, World),
+ Expected = Hello ++ World,
+ Expected = active_recv(Socket, length(Expected)),
+ ok.
session_info_result(Socket) ->
{ok, Info} = ssl:connection_information(Socket, [session_id, cipher_suite]),
@@ -1176,15 +1653,17 @@ init_tls_version(Version, Config) ->
clean_tls_version(Config) ->
proplists:delete(protocol_opts, proplists:delete(protocol, Config)).
-
+
+sufficient_crypto_support(Version)
+ when Version == 'tlsv1.3' ->
+ CryptoSupport = crypto:supports(),
+ lists:member(rsa_pkcs1_pss_padding, proplists:get_value(rsa_opts, CryptoSupport)) andalso
+ lists:member(x448, proplists:get_value(curves, CryptoSupport));
sufficient_crypto_support(Version)
when Version == 'tlsv1.2'; Version == 'dtlsv1.2' ->
CryptoSupport = crypto:supports(),
proplists:get_bool(sha256, proplists:get_value(hashs, CryptoSupport));
-sufficient_crypto_support(Group) when Group == ciphers_ec; %% From ssl_basic_SUITE
- Group == erlang_server; %% From ssl_ECC_SUITE
- Group == erlang_client; %% From ssl_ECC_SUITE
- Group == erlang -> %% From ssl_ECC_SUITE
+sufficient_crypto_support(cipher_ec) ->
CryptoSupport = crypto:supports(),
proplists:get_bool(ecdh, proplists:get_value(public_keys, CryptoSupport));
sufficient_crypto_support(_) ->
@@ -1193,46 +1672,113 @@ sufficient_crypto_support(_) ->
check_key_exchange_send_active(Socket, false) ->
send_recv_result_active(Socket);
check_key_exchange_send_active(Socket, KeyEx) ->
- {ok, [{cipher_suite, Suite}]} = ssl:connection_information(Socket, [cipher_suite]),
- true = check_key_exchange(Suite, KeyEx),
+ {ok, Info} =
+ ssl:connection_information(Socket, [cipher_suite, protocol]),
+ Suite = proplists:get_value(cipher_suite, Info),
+ Version = proplists:get_value(protocol, Info),
+ true = check_key_exchange(Suite, KeyEx, Version),
send_recv_result_active(Socket).
-check_key_exchange({KeyEx,_, _}, KeyEx) ->
+check_key_exchange({KeyEx,_, _}, KeyEx, _) ->
+ ct:pal("Kex: ~p", [KeyEx]),
true;
-check_key_exchange({KeyEx,_,_,_}, KeyEx) ->
+check_key_exchange({KeyEx,_,_,_}, KeyEx, _) ->
+ ct:pal("Kex: ~p", [KeyEx]),
true;
-check_key_exchange(KeyEx1, KeyEx2) ->
- ct:pal("Negotiated ~p Expected ~p", [KeyEx1, KeyEx2]),
- false.
-
-send_recv_result_active(Socket) ->
- ssl:send(Socket, "Hello world"),
- receive
- {ssl, Socket, "H"} ->
- receive
- {ssl, Socket, "ello world"} ->
- ok
- end;
- {ssl, Socket, "Hello world"} ->
- ok
+check_key_exchange(KeyEx1, KeyEx2, Version) ->
+ ct:pal("Kex: ~p ~p", [KeyEx1, KeyEx2]),
+ case Version of
+ 'tlsv1.2' ->
+ v_1_2_check(element(1, KeyEx1), KeyEx2);
+ 'dtlsv1.2' ->
+ v_1_2_check(element(1, KeyEx1), KeyEx2);
+ _ ->
+ ct:pal("Negotiated ~p Expected ~p", [KeyEx1, KeyEx2]),
+ false
end.
+v_1_2_check(ecdh_ecdsa, ecdh_rsa) ->
+ true;
+v_1_2_check(ecdh_rsa, ecdh_ecdsa) ->
+ true;
+v_1_2_check(_, _) ->
+ false.
+
send_recv_result(Socket) ->
- ssl:send(Socket, "Hello world"),
- {ok,"Hello world"} = ssl:recv(Socket, 11),
+ Data = "Hello world",
+ ssl:send(Socket, Data),
+ {ok, Data} = ssl:recv(Socket, length(Data)),
+ ok.
+
+send_recv_result_active(Socket) ->
+ Data = "Hello world",
+ ssl:send(Socket, Data),
+ Data = active_recv(Socket, length(Data)),
ok.
send_recv_result_active_once(Socket) ->
- ssl:send(Socket, "Hello world"),
- receive
- {ssl, Socket, "H"} ->
- ssl:setopts(Socket, [{active, once}]),
- receive
- {ssl, Socket, "ello world"} ->
- ok
- end;
- {ssl, Socket, "Hello world"} ->
- ok
+ Data = "Hello world",
+ ssl:send(Socket, Data),
+ active_once_recv_list(Socket, length(Data)).
+
+active_recv(Socket, N) ->
+ active_recv(Socket, N, []).
+
+active_recv(_Socket, 0, Acc) ->
+ Acc;
+active_recv(Socket, N, Acc) ->
+ receive
+ {ssl, Socket, Bytes} ->
+ active_recv(Socket, N-length(Bytes), Acc ++ Bytes)
+ end.
+
+active_once_recv(_Socket, 0) ->
+ ok;
+active_once_recv(Socket, N) ->
+ receive
+ {ssl, Socket, Bytes} ->
+ ssl:setopts(Socket, [{active, once}]),
+ active_once_recv(Socket, N-byte_size(Bytes))
+ end.
+
+active_once_recv_list(_Socket, 0) ->
+ ok;
+active_once_recv_list(Socket, N) ->
+ receive
+ {ssl, Socket, Bytes} ->
+ ssl:setopts(Socket, [{active, once}]),
+ active_once_recv_list(Socket, N-length(Bytes))
+ end.
+recv_disregard(_Socket, 0) ->
+ ok;
+recv_disregard(Socket, N) ->
+ {ok, Bytes} = ssl:recv(Socket, 0),
+ recv_disregard(Socket, N-byte_size(Bytes)).
+
+active_disregard(_Socket, 0) ->
+ ok;
+active_disregard(Socket, N) ->
+ receive
+ {ssl, Socket, Bytes} ->
+ active_disregard(Socket, N-byte_size(Bytes))
+ end.
+active_once_disregard(_Socket, 0) ->
+ ok;
+active_once_disregard(Socket, N) ->
+ receive
+ {ssl, Socket, Bytes} ->
+ ssl:setopts(Socket, [{active, once}]),
+ active_once_disregard(Socket, N-byte_size(Bytes))
+ end.
+
+is_ipv6_supported() ->
+ case os:cmd("openssl version") of
+ "OpenSSL 0.9.8" ++ _ -> % Does not support IPv6
+ false;
+ "OpenSSL 1.0" ++ _ -> % Does not support IPv6
+ false;
+ _ ->
+ true
end.
is_sane_ecc(openssl) ->
@@ -1264,7 +1810,16 @@ is_sane_ecc(crypto) ->
true
end;
is_sane_ecc(_) ->
- true.
+ sufficient_crypto_support(cipher_ec).
+
+is_sane_oppenssl_client() ->
+ [{_,_, Bin}] = crypto:info_lib(),
+ case binary_to_list(Bin) of
+ "OpenSSL 0.9" ++ _ ->
+ false;
+ _ ->
+ true
+ end.
is_fips(openssl) ->
VersionStr = os:cmd("openssl version"),
@@ -1320,8 +1875,50 @@ openssl_dsa_support() ->
true;
"LibreSSL" ++ _ ->
false;
+ "OpenSSL 1.1" ++ _Rest ->
+ false;
"OpenSSL 1.0.1" ++ Rest ->
- hd(Rest) >= s;
+ hd(Rest) >= $s;
+ _ ->
+ true
+ end.
+
+%% Acctual support is tested elsewhere, this is to exclude some LibreSSL and OpenSSL versions
+openssl_sane_dtls() ->
+ case os:cmd("openssl version") of
+ "OpenSSL 0." ++ _ ->
+ false;
+ "OpenSSL 1.0.1s-freebsd" ++ _ ->
+ false;
+ "OpenSSL 1.0.2k-freebsd" ++ _ ->
+ false;
+ "OpenSSL 1.0.2" ++ _ ->
+ false;
+ "OpenSSL 1.0.0" ++ _ ->
+ false;
+ "OpenSSL" ++ _ ->
+ true;
+ "LibreSSL 2.7" ++ _ ->
+ true;
+ _ ->
+ false
+ end.
+openssl_sane_client_cert() ->
+ case os:cmd("openssl version") of
+ "LibreSSL 2.5.2" ++ _ ->
+ true;
+ "LibreSSL 2.4" ++ _ ->
+ false;
+ "LibreSSL 2.3" ++ _ ->
+ false;
+ "LibreSSL 2.1" ++ _ ->
+ false;
+ "LibreSSL 2.0" ++ _ ->
+ false;
+ "OpenSSL 1.0.1s-freebsd" ->
+ false;
+ "OpenSSL 1.0.0" ++ _ ->
+ false;
_ ->
true
end.
@@ -1332,6 +1929,18 @@ check_sane_openssl_version(Version) ->
case {Version, os:cmd("openssl version")} of
{'sslv3', "OpenSSL 1.0.2" ++ _} ->
false;
+ {'dtlsv1', "OpenSSL 0" ++ _} ->
+ false;
+ {'dtlsv1.2', "OpenSSL 0" ++ _} ->
+ false;
+ {'dtlsv1.2', "OpenSSL 1.0.2" ++ _} ->
+ false;
+ {'dtlsv1', "OpenSSL 1.0.0" ++ _} ->
+ false;
+ {'dtlsv1', _} ->
+ not is_fips(openssl);
+ {'dtlsv1.2', _} ->
+ not is_fips(openssl);
{_, "OpenSSL 1.0.2" ++ _} ->
true;
{_, "OpenSSL 1.0.1" ++ _} ->
@@ -1340,18 +1949,10 @@ check_sane_openssl_version(Version) ->
false;
{'tlsv1.1', "OpenSSL 1.0.0" ++ _} ->
false;
- {'dtlsv1.2', "OpenSSL 1.0.0" ++ _} ->
- false;
- {'dtlsv1', "OpenSSL 1.0.0" ++ _} ->
- false;
{'tlsv1.2', "OpenSSL 0" ++ _} ->
false;
{'tlsv1.1', "OpenSSL 0" ++ _} ->
false;
- {'dtlsv1', "OpenSSL 0" ++ _} ->
- false;
- {'dtlsv1.2', "OpenSSL 0" ++ _} ->
- false;
{_, _} ->
true
end;
@@ -1384,6 +1985,8 @@ version_flag('tlsv1.1') ->
"-tls1_1";
version_flag('tlsv1.2') ->
"-tls1_2";
+version_flag('tlsv1.3') ->
+ "-tls1_3";
version_flag(sslv3) ->
"-ssl3";
version_flag(sslv2) ->
@@ -1394,10 +1997,10 @@ version_flag('dtlsv1') ->
"-dtls1".
filter_suites([Cipher | _] = Ciphers, AtomVersion) when is_list(Cipher)->
- filter_suites([ssl_cipher:openssl_suite(S) || S <- Ciphers],
+ filter_suites([ssl_cipher_format:suite_openssl_str_to_map(S) || S <- Ciphers],
AtomVersion);
filter_suites([Cipher | _] = Ciphers, AtomVersion) when is_binary(Cipher)->
- filter_suites([ssl_cipher:erl_suite_definition(S) || S <- Ciphers],
+ filter_suites([ssl_cipher_format:suite_bin_to_map(S) || S <- Ciphers],
AtomVersion);
filter_suites(Ciphers0, AtomVersion) ->
Version = tls_version(AtomVersion),
@@ -1409,7 +2012,7 @@ filter_suites(Ciphers0, AtomVersion) ->
++ ssl_cipher:srp_suites_anon()
++ ssl_cipher:rc4_suites(Version),
Supported1 = ssl_cipher:filter_suites(Supported0),
- Supported2 = [ssl_cipher:erl_suite_definition(S) || S <- Supported1],
+ Supported2 = [ssl_cipher_format:suite_bin_to_map(S) || S <- Supported1],
[Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported2)].
-define(OPENSSL_QUIT, "Q\n").
@@ -1462,8 +2065,13 @@ supports_ssl_tls_version(sslv2 = Version) ->
VersionFlag = version_flag(Version),
Exe = "openssl",
Args = ["s_client", VersionFlag],
+ [{trap_exit, Trap}] = process_info(self(), [trap_exit]),
+ process_flag(trap_exit, true),
Port = ssl_test_lib:portable_open_port(Exe, Args),
- do_supports_ssl_tls_version(Port, "")
+ Bool = do_supports_ssl_tls_version(Port, ""),
+ consume_port_exit(Port),
+ process_flag(trap_exit, Trap),
+ Bool
end;
supports_ssl_tls_version(Version) ->
@@ -1479,13 +2087,11 @@ do_supports_ssl_tls_version(Port, Acc) ->
case Acc ++ Data of
"unknown option" ++ _ ->
false;
- Error when length(Error) >= 11 ->
- case lists:member("error", string:tokens(Data, ":")) of
- true ->
- false;
- false ->
- do_supports_ssl_tls_version(Port, Error)
- end;
+ "s_client: Option unknown" ++ _->
+ false;
+ Info when length(Info) >= 24 ->
+ ct:pal("~p", [Info]),
+ true;
_ ->
do_supports_ssl_tls_version(Port, Acc ++ Data)
end
@@ -1555,10 +2161,14 @@ is_psk_anon_suite({psk, _,_}) ->
true;
is_psk_anon_suite({dhe_psk,_,_}) ->
true;
+is_psk_anon_suite({ecdhe_psk,_,_}) ->
+ true;
is_psk_anon_suite({psk, _,_,_}) ->
true;
is_psk_anon_suite({dhe_psk, _,_,_}) ->
true;
+is_psk_anon_suite({ecdhe_psk, _,_,_}) ->
+ true;
is_psk_anon_suite(_) ->
false.
@@ -1577,6 +2187,12 @@ tls_version('dtlsv1.2' = Atom) ->
tls_version(Atom) ->
tls_record:protocol_version(Atom).
+consume_port_exit(OpenSSLPort) ->
+ receive
+ {'EXIT', OpenSSLPort, _} ->
+ ok
+ end.
+
hardcode_rsa_key(1) ->
#'RSAPrivateKey'{
version = 'two-prime',
@@ -1676,3 +2292,154 @@ hardcode_dsa_key(3) ->
y = 48598545580251057979126570873881530215432219542526130654707948736559463436274835406081281466091739849794036308281564299754438126857606949027748889019480936572605967021944405048011118039171039273602705998112739400664375208228641666852589396502386172780433510070337359132965412405544709871654840859752776060358,
x = 1457508827177594730669011716588605181448418352823}.
+tcp_delivery_workaround(Server, ServerMsg, Client, ClientMsg) ->
+ receive
+ {Server, ServerMsg} ->
+ client_msg(Client, ClientMsg);
+ {Client, ClientMsg} ->
+ server_msg(Server, ServerMsg);
+ {Client, {error,closed}} ->
+ server_msg(Server, ServerMsg);
+ {Server, {error,closed}} ->
+ client_msg(Client, ClientMsg)
+ end.
+client_msg(Client, ClientMsg) ->
+ receive
+ {Client, ClientMsg} ->
+ ok;
+ {Client, {error,closed}} ->
+ ct:log("client got close"),
+ ok;
+ {Client, {error, Reason}} ->
+ ct:log("client got econnaborted: ~p", [Reason]),
+ ok;
+ Unexpected ->
+ ct:fail(Unexpected)
+ end.
+server_msg(Server, ServerMsg) ->
+ receive
+ {Server, ServerMsg} ->
+ ok;
+ {Server, {error,closed}} ->
+ ct:log("server got close"),
+ ok;
+ {Server, {error, Reason}} ->
+ ct:log("server got econnaborted: ~p", [Reason]),
+ ok;
+ Unexpected ->
+ ct:fail(Unexpected)
+ end.
+
+session_id(Socket) ->
+ {ok, [{session_id, ID}]} = ssl:connection_information(Socket, [session_id]),
+ ID.
+
+reuse_session(ClientOpts, ServerOpts, Config) ->
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server0 =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {tcp_options, [{active, false}]},
+ {options, ServerOpts}]),
+ Port0 = ssl_test_lib:inet_port(Server0),
+
+ Client0 = ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port0}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_id, []}},
+ {from, self()}, {options, [{reuse_sessions, save} | ClientOpts]}]),
+ Server0 ! listen,
+
+ Client1 = ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port0}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_id, []}},
+ {from, self()}, {options, ClientOpts}]),
+
+ SID = receive
+ {Client0, Id0} ->
+ Id0
+ end,
+
+ receive
+ {Client1, SID} ->
+ ok
+ after ?SLEEP ->
+ ct:fail(session_not_reused)
+ end,
+
+ Server0 ! listen,
+
+ Client2 =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port0}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_id, []}},
+ {from, self()}, {options, [{reuse_sessions, false}
+ | ClientOpts]}]),
+ receive
+ {Client2, SID} ->
+ ct:fail(session_reused_when_session_reuse_disabled_by_client);
+ {Client2, _} ->
+ ok
+ end,
+
+ ssl_test_lib:close(Server0),
+ ssl_test_lib:close(Client0),
+ ssl_test_lib:close(Client1),
+ ssl_test_lib:close(Client2),
+
+ Server1 =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {tcp_options, [{active, false}]},
+ {options, [{reuse_sessions, false} |ServerOpts]}]),
+ Port1 = ssl_test_lib:inet_port(Server1),
+
+ Client3 = ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port1}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_id, []}},
+ {from, self()}, {options, [{reuse_sessions, save} | ClientOpts]}]),
+ SID1 = receive
+ {Client3, Id3} ->
+ Id3
+ end,
+
+ Server1 ! listen,
+
+ Client4 =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port1}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_id, []}},
+ {from, self()}, {options, ClientOpts}]),
+
+ receive
+ {Client4, SID1} ->
+ ct:fail(session_reused_when_session_reuse_disabled_by_server);
+ {Client4, _} ->
+ ok
+ end,
+
+ ssl_test_lib:close(Server1),
+ ssl_test_lib:close(Client3),
+ ssl_test_lib:close(Client4).
+
+user_lookup(psk, _Identity, UserState) ->
+ {ok, UserState};
+user_lookup(srp, Username, _UserState) ->
+ Salt = ssl_cipher:random_bytes(16),
+ UserPassHash = crypto:hash(sha, [Salt, crypto:hash(sha, [Username, <<$:>>, <<"secret">>])]),
+ {ok, {srp_1024, Salt, UserPassHash}}.
+
+test_cipher(TestCase, Config) ->
+ [{name, Group} |_] = proplists:get_value(tc_group_properties, Config),
+ list_to_atom(re:replace(atom_to_list(TestCase), atom_to_list(Group) ++ "_", "", [{return, list}])).
+
+digest() ->
+ case application:get_env(ssl, protocol_version, application:get_env(ssl, dtls_protocol_version)) of
+ Ver when Ver == 'tlsv1.2';
+ Ver == 'dtlsv1.2' ->
+ {digest, sha256};
+ _ ->
+ {digest, sha1}
+ end.
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index dcdea6beb5..07abddbcf7 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -37,33 +37,39 @@
%%--------------------------------------------------------------------
all() ->
- [
- {group, basic},
- {group, 'tlsv1.2'},
- {group, 'tlsv1.1'},
- {group, 'tlsv1'},
- {group, 'sslv3'},
- {group, 'dtlsv1.2'},
- {group, 'dtlsv1'}
- ].
+ case ssl_test_lib:openssl_sane_dtls() of
+ true ->
+ [{group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}];
+ false ->
+ [{group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'}]
+ end.
groups() ->
- [{basic, [], basic_tests()},
- {'tlsv1.2', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
- {'tlsv1.1', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
- {'tlsv1', [], all_versions_tests()++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
- {'sslv3', [], all_versions_tests()},
- {'dtlsv1.2', [], dtls_all_versions_tests()},
- {'dtlsv1', [], dtls_all_versions_tests()}
- ].
-
-basic_tests() ->
- [basic_erlang_client_openssl_server,
- basic_erlang_server_openssl_client,
- expired_session,
- ssl2_erlang_server_openssl_client_comp
- ].
-
+ case ssl_test_lib:openssl_sane_dtls() of
+ true ->
+ [{'tlsv1.2', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
+ {'tlsv1.1', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
+ {'tlsv1', [], all_versions_tests()++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
+ {'sslv3', [], all_versions_tests()},
+ {'dtlsv1.2', [], dtls_all_versions_tests()},
+ {'dtlsv1', [], dtls_all_versions_tests()}
+ ];
+ false ->
+ [{'tlsv1.2', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
+ {'tlsv1.1', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
+ {'tlsv1', [], all_versions_tests()++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
+ {'sslv3', [], all_versions_tests()}
+ ]
+ end.
+
all_versions_tests() ->
[
erlang_client_openssl_server,
@@ -75,6 +81,7 @@ all_versions_tests() ->
erlang_server_openssl_client_anon_with_cert,
erlang_server_openssl_client_reuse_session,
erlang_client_openssl_server_renegotiate,
+ erlang_client_openssl_server_renegotiate_after_client_data,
erlang_client_openssl_server_nowrap_seqnum,
erlang_server_openssl_client_nowrap_seqnum,
erlang_client_openssl_server_no_server_ca_cert,
@@ -86,9 +93,20 @@ all_versions_tests() ->
expired_session,
ssl2_erlang_server_openssl_client
].
+
dtls_all_versions_tests() ->
- [
- erlang_client_openssl_server,
+ case ssl_test_lib:openssl_sane_client_cert() of
+ true ->
+ [erlang_server_openssl_client_client_cert,
+ erlang_client_openssl_server_no_server_ca_cert,
+ erlang_client_openssl_server_client_cert
+ | dtls_all_versions_tests_2()];
+ false ->
+ dtls_all_versions_tests_2()
+ end.
+
+dtls_all_versions_tests_2() ->
+ [erlang_client_openssl_server,
erlang_server_openssl_client,
erlang_client_openssl_server_dsa_cert,
erlang_server_openssl_client_dsa_cert,
@@ -99,12 +117,8 @@ dtls_all_versions_tests() ->
erlang_client_openssl_server_renegotiate,
erlang_client_openssl_server_nowrap_seqnum,
erlang_server_openssl_client_nowrap_seqnum,
- erlang_client_openssl_server_no_server_ca_cert,
- erlang_client_openssl_server_client_cert,
- erlang_server_openssl_client_client_cert,
ciphers_rsa_signed_certs,
ciphers_dsa_signed_certs
- %%erlang_client_bad_openssl_server,
%%expired_session
].
@@ -141,13 +155,13 @@ sni_server_tests() ->
init_per_suite(Config0) ->
case os:find_executable("openssl") of
- false ->
- {skip, "Openssl not found"};
- _ ->
- ct:pal("Version: ~p", [os:cmd("openssl version")]),
- catch crypto:stop(),
- try crypto:start() of
- ok ->
+ false ->
+ {skip, "Openssl not found"};
+ _ ->
+ ct:pal("Version: ~p", [os:cmd("openssl version")]),
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
ssl_test_lib:clean_start(),
Config =
case ssl_test_lib:openssl_dsa_support() of
@@ -158,49 +172,42 @@ init_per_suite(Config0) ->
ssl_test_lib:make_rsa_cert(Config0)
end,
ssl_test_lib:cipher_restriction(Config)
- catch _:_ ->
- {skip, "Crypto did not start"}
- end
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end
end.
end_per_suite(_Config) ->
ssl:stop(),
application:stop(crypto).
-init_per_group(basic, Config0) ->
- Config = ssl_test_lib:clean_tls_version(Config0),
- case ssl_test_lib:supports_ssl_tls_version(sslv2) of
- true ->
- [{v2_hello_compatible, true} | Config];
- false ->
- [{v2_hello_compatible, false} | Config]
- end;
+
init_per_group(GroupName, Config) ->
case ssl_test_lib:is_tls_version(GroupName) of
- true ->
+ true ->
case ssl_test_lib:supports_ssl_tls_version(GroupName) of
- true ->
+ true ->
case ssl_test_lib:check_sane_openssl_version(GroupName) of
- true ->
+ true ->
ssl_test_lib:init_tls_version(GroupName, Config);
- false ->
+ false ->
{skip, openssl_does_not_support_version}
end;
false ->
{skip, openssl_does_not_support_version}
end;
- _ ->
- ssl:start(),
- Config
+ _ ->
+ ssl:start(),
+ Config
end.
end_per_group(GroupName, Config) ->
- case ssl_test_lib:is_tls_version(GroupName) of
- true ->
- ssl_test_lib:clean_tls_version(Config);
- false ->
- Config
- end.
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:clean_tls_version(Config);
+ false ->
+ Config
+ end.
init_per_testcase(expired_session, Config) ->
ct:timetrap(?EXPIRE * 1000 * 5),
@@ -208,19 +215,19 @@ init_per_testcase(expired_session, Config) ->
application:load(ssl),
application:set_env(ssl, session_lifetime, ?EXPIRE),
ssl:start(),
- Config;
+ Config;
init_per_testcase(TestCase, Config) when
TestCase == ciphers_dsa_signed_certs;
TestCase == erlang_client_openssl_server_dsa_cert;
TestCase == erlang_server_openssl_client_dsa_cert;
- TestCase == erlang_client_openssl_server_dsa_cert;
+ TestCase == erlang_client_openssl_server_dsa_cert;
TestCase == erlang_server_openssl_client_dsa_cert ->
- case ssl_test_lib:openssl_dsa_support() of
+ case ssl_test_lib:openssl_dsa_support() andalso ssl_test_lib:is_sane_oppenssl_client() of
true ->
special_init(TestCase, Config);
false ->
- {skip, "DSA not supported by OpenSSL"}
+ {skip, "DSA not supported by OpenSSL"}
end;
init_per_testcase(TestCase, Config) ->
ct:timetrap({seconds, 35}),
@@ -234,69 +241,69 @@ special_init(TestCase, Config) when
special_init(TestCase, Config)
when TestCase == erlang_client_openssl_server_renegotiate;
TestCase == erlang_client_openssl_server_nowrap_seqnum;
- TestCase == erlang_server_openssl_client_nowrap_seqnum
- ->
+ TestCase == erlang_server_openssl_client_nowrap_seqnum;
+ TestCase == erlang_client_openssl_server_renegotiate_after_client_data
+ ->
{ok, Version} = application:get_env(ssl, protocol_version),
check_sane_openssl_renegotaite(Config, Version);
-special_init(Case, Config) when Case == ssl2_erlang_server_openssl_client;
- Case == ssl2_erlang_server_openssl_client_comp ->
+special_init(ssl2_erlang_server_openssl_client, Config) ->
case ssl_test_lib:supports_ssl_tls_version(sslv2) of
- true ->
- Config;
- false ->
- {skip, "sslv2 not supported by openssl"}
- end;
+ true ->
+ Config;
+ false ->
+ {skip, "sslv2 not supported by openssl"}
+ end;
special_init(TestCase, Config)
- when TestCase == erlang_client_alpn_openssl_server_alpn;
- TestCase == erlang_server_alpn_openssl_client_alpn;
- TestCase == erlang_client_alpn_openssl_server;
- TestCase == erlang_client_openssl_server_alpn;
- TestCase == erlang_server_alpn_openssl_client;
- TestCase == erlang_server_openssl_client_alpn ->
+ when TestCase == erlang_client_alpn_openssl_server_alpn;
+ TestCase == erlang_server_alpn_openssl_client_alpn;
+ TestCase == erlang_client_alpn_openssl_server;
+ TestCase == erlang_client_openssl_server_alpn;
+ TestCase == erlang_server_alpn_openssl_client;
+ TestCase == erlang_server_openssl_client_alpn ->
check_openssl_alpn_support(Config);
special_init(TestCase, Config)
- when TestCase == erlang_client_alpn_openssl_server_alpn_renegotiate;
- TestCase == erlang_server_alpn_openssl_client_alpn_renegotiate ->
- {ok, Version} = application:get_env(ssl, protocol_version),
- case check_sane_openssl_renegotaite(Config, Version) of
- {skip, _} = Skip ->
- Skip;
- _ ->
- check_openssl_alpn_support(Config)
- end;
+ when TestCase == erlang_client_alpn_openssl_server_alpn_renegotiate;
+ TestCase == erlang_server_alpn_openssl_client_alpn_renegotiate ->
+ {ok, Version} = application:get_env(ssl, protocol_version),
+ case check_sane_openssl_renegotaite(Config, Version) of
+ {skip, _} = Skip ->
+ Skip;
+ _ ->
+ check_openssl_alpn_support(Config)
+ end;
special_init(TestCase, Config)
- when TestCase == erlang_client_alpn_npn_openssl_server_alpn_npn;
- TestCase == erlang_server_alpn_npn_openssl_client_alpn_npn ->
+ when TestCase == erlang_client_alpn_npn_openssl_server_alpn_npn;
+ TestCase == erlang_server_alpn_npn_openssl_client_alpn_npn ->
case check_openssl_alpn_support(Config) of
{skip, _} = Skip ->
Skip;
_ ->
- check_openssl_npn_support(Config)
+ check_openssl_npn_support(Config)
end;
special_init(TestCase, Config)
- when TestCase == erlang_client_openssl_server_npn;
- TestCase == erlang_server_openssl_client_npn;
- TestCase == erlang_server_openssl_client_npn_only_server;
- TestCase == erlang_server_openssl_client_npn_only_client;
- TestCase == erlang_client_openssl_server_npn_only_client;
- TestCase == erlang_client_openssl_server_npn_only_server ->
+ when TestCase == erlang_client_openssl_server_npn;
+ TestCase == erlang_server_openssl_client_npn;
+ TestCase == erlang_server_openssl_client_npn_only_server;
+ TestCase == erlang_server_openssl_client_npn_only_client;
+ TestCase == erlang_client_openssl_server_npn_only_client;
+ TestCase == erlang_client_openssl_server_npn_only_server ->
check_openssl_npn_support(Config);
special_init(TestCase, Config)
when TestCase == erlang_server_openssl_client_npn_renegotiate;
TestCase == erlang_client_openssl_server_npn_renegotiate ->
{ok, Version} = application:get_env(ssl, protocol_version),
- case check_sane_openssl_renegotaite(Config, Version) of
- {skip, _} = Skip ->
- Skip;
- _ ->
- check_openssl_npn_support(Config)
- end;
+ case check_sane_openssl_renegotaite(Config, Version) of
+ {skip, _} = Skip ->
+ Skip;
+ _ ->
+ check_openssl_npn_support(Config)
+ end;
special_init(TestCase, Config0)
when TestCase == erlang_server_openssl_client_sni_match;
@@ -305,105 +312,41 @@ special_init(TestCase, Config0)
TestCase == erlang_server_openssl_client_sni_match_fun;
TestCase == erlang_server_openssl_client_sni_no_match_fun;
TestCase == erlang_server_openssl_client_sni_no_header_fun ->
- RsaOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config0),
+ RsaOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config0),
Config = [{sni_server_opts, [{sni_hosts,
[{"a.server", [
{certfile, proplists:get_value(certfile, RsaOpts)},
{keyfile, proplists:get_value(keyfile, RsaOpts)}
]},
{"b.server", [
- {certfile, proplists:get_value(certfile, RsaOpts)},
+ {certfile, proplists:get_value(certfile, RsaOpts)},
{keyfile, proplists:get_value(keyfile, RsaOpts)}
]}
]}]} | Config0],
check_openssl_sni_support(Config);
-
+special_init(TestCase, Config)
+ when TestCase == erlang_server_openssl_client;
+ TestCase == erlang_server_openssl_client_client_cert;
+ TestCase == erlang_server_openssl_client_reuse_session ->
+ case ssl_test_lib:is_sane_oppenssl_client() of
+ true ->
+ Config;
+ false ->
+ {skip, "Broken OpenSSL client"}
+ end;
special_init(_, Config) ->
- Config.
+ Config.
end_per_testcase(reuse_session_expired, Config) ->
application:unset_env(ssl, session_lifetime),
- Config;
+ Config;
end_per_testcase(_, Config) ->
Config.
%%--------------------------------------------------------------------
%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
-basic_erlang_client_openssl_server() ->
- [{doc,"Test erlang client with openssl server"}].
-basic_erlang_client_openssl_server(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
-
- {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From openssl to erlang",
-
- Port = ssl_test_lib:inet_port(node()),
- CertFile = proplists:get_value(certfile, ServerOpts),
- KeyFile = proplists:get_value(keyfile, ServerOpts),
-
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port),
- "-cert", CertFile, "-key", KeyFile],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
-
- ssl_test_lib:wait_for_openssl_server(Port, tls),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- erlang_ssl_receive, [Data]}},
- {options, ClientOpts}]),
- true = port_command(OpensslPort, Data),
-
- ssl_test_lib:check_result(Client, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpensslPort),
- ssl_test_lib:close(Client),
- process_flag(trap_exit, false).
-
-%%--------------------------------------------------------------------
-basic_erlang_server_openssl_client() ->
- [{doc,"Test erlang server with openssl client"}].
-basic_erlang_server_openssl_client(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- V2Compat = proplists:get_value(v2_hello_compatible, Config),
-
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From openssl to erlang",
- ct:pal("v2_hello_compatible: ~p", [V2Compat]),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
- {options,[{v2_hello_compatible, V2Compat} | ServerOpts]}]),
-
- Port = ssl_test_lib:inet_port(Server),
-
- Exe = "openssl",
- Args = ["s_client", "-connect", hostname_format(Hostname) ++
- ":" ++ integer_to_list(Port) | workaround_openssl_s_clinent()],
-
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
- true = port_command(OpenSslPort, Data),
-
- ssl_test_lib:check_result(Server, ok),
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(OpenSslPort),
- process_flag(trap_exit, false).
-
-%%--------------------------------------------------------------------
erlang_client_openssl_server() ->
[{doc,"Test erlang client with openssl server"}].
erlang_client_openssl_server(Config) when is_list(Config) ->
@@ -421,19 +364,19 @@ erlang_client_openssl_server(Config) when is_list(Config) ->
Version = ssl_test_lib:protocol_version(Config),
Exe = "openssl",
Args = ["s_server", "-accept", integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cert", CertFile, "-key", KeyFile],
-
+ ssl_test_lib:version_flag(Version),
+ "-cert", CertFile, "-key", KeyFile],
+
OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- erlang_ssl_receive, [Data]}},
- {options, ClientOpts}]),
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ erlang_ssl_receive, [Data]}},
+ {options, ClientOpts}]),
true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok),
@@ -449,24 +392,24 @@ erlang_server_openssl_client() ->
erlang_server_openssl_client(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
-
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
Data = "From openssl to erlang",
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
- {options, ServerOpts}]),
+ {from, self()},
+ {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
+ {options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
Version = ssl_test_lib:protocol_version(Config),
Exe = "openssl",
Args = ["s_client", "-connect", hostname_format(Hostname) ++":" ++ integer_to_list(Port),
- ssl_test_lib:version_flag(Version)],
-
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
+ ssl_test_lib:version_flag(Version)],
+ OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
true = port_command(OpenSslPort, Data),
ssl_test_lib:check_result(Server, ok),
@@ -483,8 +426,8 @@ erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_dsa_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_dsa_verify_opts, Config),
- {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
-
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+
Data = "From openssl to erlang",
Port = ssl_test_lib:inet_port(node()),
@@ -494,27 +437,27 @@ erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) ->
Version = ssl_test_lib:protocol_version(Config),
Exe = "openssl",
Args = ["s_server", "-accept", integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cert", CertFile, "-CAfile", CaCertFile,
- "-key", KeyFile, "-Verify", "2", "-msg"],
+ ssl_test_lib:version_flag(Version),
+ "-cert", CertFile, "-CAfile", CaCertFile,
+ "-key", KeyFile, "-Verify", "2", "-msg"],
OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- erlang_ssl_receive, [Data]}},
- {options, ClientOpts}]),
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ erlang_ssl_receive, [Data]}},
+ {options, ClientOpts}]),
true = port_command(OpensslPort, Data),
- ssl_test_lib:check_result(Client, ok),
-
+ ssl_test_lib:check_result(Client, ok),
+
%% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpensslPort),
+ ssl_test_lib:close_port(OpensslPort),
ssl_test_lib:close(Client),
process_flag(trap_exit, false),
ok.
@@ -534,17 +477,17 @@ erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) ->
KeyFile = proplists:get_value(keyfile, ClientOpts),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
- {options, ServerOpts}]),
+ {from, self()},
+ {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
+ {options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
Version = ssl_test_lib:protocol_version(Config),
Exe = "openssl",
Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cert", CertFile,
- "-CAfile", CaCertFile,
- "-key", KeyFile, "-msg"],
+ ssl_test_lib:version_flag(Version),
+ "-cert", CertFile,
+ "-CAfile", CaCertFile,
+ "-key", KeyFile, "-msg"],
OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
true = port_command(OpenSslPort, Data),
@@ -556,125 +499,140 @@ erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) ->
ssl_test_lib:close_port(OpenSslPort),
process_flag(trap_exit, false).
-%%--------------------------------------------------------------------
+ %%--------------------------------------------------------------------
erlang_client_openssl_server_anon() ->
- [{doc,"Test erlang client with openssl server, anonymous"}].
+ [{doc,"Test erlang client with openssl server, anonymous"}].
erlang_client_openssl_server_anon(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
+ process_flag(trap_exit, true),
%% OpenSSL expects a certificate and key, even if the cipher spec
%% is restructed to aNULL, so we use 'server_rsa_opts' here
ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
ClientOpts = ssl_test_lib:ssl_options(client_anon_opts, Config),
VersionTuple = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:anonymous_suites(VersionTuple),
+ Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(VersionTuple),
- {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From openssl to erlang",
-
- Port = ssl_test_lib:inet_port(node()),
- CertFile = proplists:get_value(certfile, ServerOpts),
- KeyFile = proplists:get_value(keyfile, ServerOpts),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cert", CertFile, "-key", KeyFile,
- "-cipher", "aNULL", "-msg"],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- erlang_ssl_receive, [Data]}},
- {options, [{ciphers, Ciphers} | ClientOpts]}]),
-
- true = port_command(OpensslPort, Data),
-
- ssl_test_lib:check_result(Client, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpensslPort),
- ssl_test_lib:close(Client),
- process_flag(trap_exit, false),
- ok.
+ case openssl_has_common_ciphers(Ciphers) of
+ false ->
+ {skip, not_supported_by_openssl};
+ true ->
+
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From openssl to erlang",
+
+ Port = ssl_test_lib:inet_port(node()),
+ CertFile = proplists:get_value(certfile, ServerOpts),
+ KeyFile = proplists:get_value(keyfile, ServerOpts),
+ Version = ssl_test_lib:protocol_version(Config),
+ Exe = "openssl",
+ Args = ["s_server", "-accept", integer_to_list(Port),
+ ssl_test_lib:version_flag(Version),
+ "-cert", CertFile, "-key", KeyFile,
+ "-cipher", "aNULL", "-msg"],
+
+ OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ erlang_ssl_receive, [Data]}},
+ {options, [{ciphers, Ciphers} | ClientOpts]}]),
+
+ true = port_command(OpensslPort, Data),
+
+ ssl_test_lib:check_result(Client, ok),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close_port(OpensslPort),
+ ssl_test_lib:close(Client),
+ process_flag(trap_exit, false)
+ end.
%%--------------------------------------------------------------------
erlang_server_openssl_client_anon() ->
[{doc,"Test erlang server with openssl client, anonymous"}].
erlang_server_openssl_client_anon(Config) when is_list(Config) ->
+
process_flag(trap_exit, true),
ServerOpts = ssl_test_lib:ssl_options(server_anon_opts, Config),
VersionTuple = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:anonymous_suites(VersionTuple),
-
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From openssl to erlang",
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
- {options, [{ciphers, Ciphers} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cipher", "aNULL", "-msg"],
-
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
- true = port_command(OpenSslPort, Data),
-
- ssl_test_lib:check_result(Server, ok),
+ Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(VersionTuple),
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(OpenSslPort),
- process_flag(trap_exit, false).
+ case openssl_has_common_ciphers(Ciphers) of
+ false ->
+ {skip, not_supported_by_openssl};
+ true ->
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From openssl to erlang",
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
+ {options, [{ciphers, Ciphers} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Version = ssl_test_lib:protocol_version(Config),
+ Exe = "openssl",
+ Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
+ ssl_test_lib:version_flag(Version),
+ "-cipher", "aNULL", "-msg"],
+
+ OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
+ true = port_command(OpenSslPort, Data),
+
+ ssl_test_lib:check_result(Server, ok),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(OpenSslPort),
+ process_flag(trap_exit, false)
+ end.
- %%--------------------------------------------------------------------
- erlang_server_openssl_client_anon_with_cert() ->
- [{doc,"Test erlang server with openssl client, anonymous (with cert)"}].
- erlang_server_openssl_client_anon_with_cert(Config) when is_list(Config) ->
+%%--------------------------------------------------------------------
+erlang_server_openssl_client_anon_with_cert() ->
+ [{doc,"Test erlang server with openssl client, anonymous (with cert)"}].
+erlang_server_openssl_client_anon_with_cert(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
VersionTuple = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:anonymous_suites(VersionTuple),
-
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From openssl to erlang",
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
- {options, [{ciphers, Ciphers} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cipher", "aNULL", "-msg"],
-
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
- true = port_command(OpenSslPort, Data),
-
- ssl_test_lib:check_result(Server, ok),
+ Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(VersionTuple),
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(OpenSslPort),
- process_flag(trap_exit, false).
-
-%%--------------------------------------------------------------------
+ case openssl_has_common_ciphers(Ciphers) of
+ false ->
+ {skip, not_supported_by_openssl};
+ true ->
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From openssl to erlang",
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
+ {options, [{ciphers, Ciphers} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Version = ssl_test_lib:protocol_version(Config),
+ Exe = "openssl",
+ Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
+ ssl_test_lib:version_flag(Version),
+ "-cipher", "aNULL", "-msg"],
+
+ OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
+ true = port_command(OpenSslPort, Data),
+
+ ssl_test_lib:check_result(Server, ok),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(OpenSslPort),
+ process_flag(trap_exit, false)
+ end.
+ %%--------------------------------------------------------------------
erlang_server_openssl_client_reuse_session() ->
[{doc, "Test erlang server with openssl client that reconnects with the"
- "same session id, to test reusing of sessions."}].
+ "same session id, to test reusing of sessions."}].
erlang_server_openssl_client_reuse_session(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
@@ -684,18 +642,18 @@ erlang_server_openssl_client_reuse_session(Config) when is_list(Config) ->
Data = "From openssl to erlang",
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
- {reconnect_times, 5},
- {options, ServerOpts}]),
+ {from, self()},
+ {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
+ {reconnect_times, 5},
+ {options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
Version = ssl_test_lib:protocol_version(Config),
-
+
Exe = "openssl",
Args = ["s_client", "-connect", hostname_format(Hostname)
++ ":" ++ integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-reconnect"],
+ ssl_test_lib:version_flag(Version),
+ "-reconnect"],
OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
@@ -706,7 +664,7 @@ erlang_server_openssl_client_reuse_session(Config) when is_list(Config) ->
%% Clean close down! Server needs to be closed first !!
ssl_test_lib:close(Server),
ssl_test_lib:close_port(OpenSslPort),
- process_flag(trap_exit, false),
+ process_flag(trap_exit, false),
ok.
%%--------------------------------------------------------------------
@@ -715,8 +673,8 @@ erlang_client_openssl_server_renegotiate() ->
[{doc,"Test erlang client when openssl server issuses a renegotiate"}].
erlang_client_openssl_server_renegotiate(Config) when is_list(Config) ->
process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
{ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
@@ -725,75 +683,126 @@ erlang_client_openssl_server_renegotiate(Config) when is_list(Config) ->
Port = ssl_test_lib:inet_port(node()),
CertFile = proplists:get_value(certfile, ServerOpts),
+ CaCertFile = proplists:get_value(cacertfile, ServerOpts),
KeyFile = proplists:get_value(keyfile, ServerOpts),
Version = ssl_test_lib:protocol_version(Config),
Exe = "openssl",
Args = ["s_server", "-accept", integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cert", CertFile, "-key", KeyFile, "-msg"],
+ ssl_test_lib:version_flag(Version),
+ "-CAfile", CaCertFile,
+ "-cert", CertFile, "-key", KeyFile, "-msg"],
OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- delayed_send, [[ErlData, OpenSslData]]}},
- {options, ClientOpts}]),
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ delayed_send, [[ErlData, OpenSslData]]}},
+ {options, ClientOpts}]),
true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
ct:sleep(?SLEEP),
true = port_command(OpensslPort, OpenSslData),
ssl_test_lib:check_result(Client, ok),
-
- %% Clean close down! Server needs to be closed first !!
+
+ %% Clean close down! Server needs to be closed first !!
ssl_test_lib:close_port(OpensslPort),
ssl_test_lib:close(Client),
- process_flag(trap_exit, false),
+ process_flag(trap_exit, false),
+ ok.
+%%--------------------------------------------------------------------
+erlang_client_openssl_server_renegotiate_after_client_data() ->
+ [{doc,"Test erlang client when openssl server issuses a renegotiate after reading client data"}].
+erlang_client_openssl_server_renegotiate_after_client_data(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+
+ ErlData = "From erlang to openssl",
+ OpenSslData = "From openssl to erlang",
+
+ Port = ssl_test_lib:inet_port(node()),
+ CaCertFile = proplists:get_value(cacertfile, ServerOpts),
+ CertFile = proplists:get_value(certfile, ServerOpts),
+ KeyFile = proplists:get_value(keyfile, ServerOpts),
+ Version = ssl_test_lib:protocol_version(Config),
+
+ Exe = "openssl",
+ Args = ["s_server", "-accept", integer_to_list(Port),
+ ssl_test_lib:version_flag(Version),
+ "-CAfile", CaCertFile,
+ "-cert", CertFile, "-key", KeyFile, "-msg"],
+
+ OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ send_wait_send, [[ErlData, OpenSslData]]}},
+ {options, ClientOpts}]),
+
+ true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
+ ct:sleep(?SLEEP),
+ true = port_command(OpensslPort, OpenSslData),
+
+ ssl_test_lib:check_result(Client, ok),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close_port(OpensslPort),
+ ssl_test_lib:close(Client),
+ process_flag(trap_exit, false),
ok.
%%--------------------------------------------------------------------
erlang_client_openssl_server_nowrap_seqnum() ->
[{doc, "Test that erlang client will renegotiate session when",
- "max sequence number celing is about to be reached. Although"
- "in the testcase we use the test option renegotiate_at"
- " to lower treashold substantially."}].
+ "max sequence number celing is about to be reached. Although"
+ "in the testcase we use the test option renegotiate_at"
+ " to lower treashold substantially."}].
erlang_client_openssl_server_nowrap_seqnum(Config) when is_list(Config) ->
process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
{ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
-
+
ErlData = "From erlang to openssl\n",
N = 10,
Port = ssl_test_lib:inet_port(node()),
+ CaCertFile = proplists:get_value(cacertfile, ServerOpts),
CertFile = proplists:get_value(certfile, ServerOpts),
KeyFile = proplists:get_value(keyfile, ServerOpts),
Version = ssl_test_lib:protocol_version(Config),
Exe = "openssl",
Args = ["s_server", "-accept", integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cert", CertFile, "-key", KeyFile, "-msg"],
-
+ ssl_test_lib:version_flag(Version),
+ "-CAfile", CaCertFile,
+ "-cert", CertFile, "-key", KeyFile, "-msg"],
+
OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib,
- trigger_renegotiate, [[ErlData, N+2]]}},
- {options, [{reuse_sessions, false},
- {renegotiate_at, N} | ClientOpts]}]),
-
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ trigger_renegotiate, [[ErlData, N+2]]}},
+ {options, [{reuse_sessions, false},
+ {renegotiate_at, N} | ClientOpts]}]),
+
ssl_test_lib:check_result(Client, ok),
%% Clean close down! Server needs to be closed first !!
@@ -803,37 +812,37 @@ erlang_client_openssl_server_nowrap_seqnum(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
erlang_server_openssl_client_nowrap_seqnum() ->
[{doc, "Test that erlang client will renegotiate session when",
- "max sequence number celing is about to be reached. Although"
- "in the testcase we use the test option renegotiate_at"
- " to lower treashold substantially."}].
+ "max sequence number celing is about to be reached. Although"
+ "in the testcase we use the test option renegotiate_at"
+ " to lower treashold substantially."}].
erlang_server_openssl_client_nowrap_seqnum(Config) when is_list(Config) ->
process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
{_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
+
Data = "From openssl to erlang",
-
+
N = 10,
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib,
- trigger_renegotiate, [[Data, N+2]]}},
- {options, [{renegotiate_at, N}, {reuse_sessions, false} | ServerOpts]}]),
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ trigger_renegotiate, [[Data, N+2]]}},
+ {options, [{renegotiate_at, N}, {reuse_sessions, false} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Version = ssl_test_lib:protocol_version(Config),
Exe = "openssl",
Args = ["s_client","-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-msg"],
-
+ ssl_test_lib:version_flag(Version),
+ "-msg"],
+
OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
true = port_command(OpenSslPort, Data),
-
+
ssl_test_lib:check_result(Server, ok),
-
+
%% Clean close down! Server needs to be closed first !!
ssl_test_lib:close(Server),
ssl_test_lib:close_port(OpenSslPort),
@@ -843,15 +852,15 @@ erlang_server_openssl_client_nowrap_seqnum(Config) when is_list(Config) ->
erlang_client_openssl_server_no_server_ca_cert() ->
[{doc, "Test erlang client when openssl server sends a cert chain not"
- "including the ca cert. Explicitly test this even if it is"
- "implicitly tested eleswhere."}].
+ "including the ca cert. Explicitly test this even if it is"
+ "implicitly tested eleswhere."}].
erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
{ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
-
+
Data = "From openssl to erlang",
Port = ssl_test_lib:inet_port(node()),
@@ -860,22 +869,22 @@ erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) ->
Version = ssl_test_lib:protocol_version(Config),
Exe = "openssl",
Args = ["s_server", "-accept", integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cert", CertFile, "-key", KeyFile, "-msg"],
-
+ ssl_test_lib:version_flag(Version),
+ "-cert", CertFile, "-key", KeyFile, "-msg"],
+
OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
+
ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- erlang_ssl_receive, [Data]}},
- {options, ClientOpts}]),
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ erlang_ssl_receive, [Data]}},
+ {options, ClientOpts}]),
true = port_command(OpensslPort, Data),
-
+
ssl_test_lib:check_result(Client, ok),
%% Clean close down! Server needs to be closed first !!
@@ -892,9 +901,9 @@ erlang_client_openssl_server_client_cert(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
{ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
-
+
Data = "From openssl to erlang",
-
+
Port = ssl_test_lib:inet_port(node()),
CertFile = proplists:get_value(certfile, ServerOpts),
CaCertFile = proplists:get_value(cacertfile, ServerOpts),
@@ -902,31 +911,30 @@ erlang_client_openssl_server_client_cert(Config) when is_list(Config) ->
Version = ssl_test_lib:protocol_version(Config),
Exe = "openssl",
Args = ["s_server", "-accept", integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cert", CertFile, "-CAfile", CaCertFile,
- "-key", KeyFile, "-Verify", "2"],
-
+ ssl_test_lib:version_flag(Version),
+ "-cert", CertFile, "-CAfile", CaCertFile,
+ "-key", KeyFile, "-Verify", "2"],
+
OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- erlang_ssl_receive, [Data]}},
- {options, ClientOpts}]),
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ erlang_ssl_receive, [Data]}},
+ {options, ClientOpts}]),
true = port_command(OpensslPort, Data),
-
+
ssl_test_lib:check_result(Client, ok),
-
+
%% Clean close down! Server needs to be closed first !!
ssl_test_lib:close_port(OpensslPort),
ssl_test_lib:close(Client),
process_flag(trap_exit, false).
%%--------------------------------------------------------------------
-
erlang_server_openssl_client_client_cert() ->
[{doc,"Test erlang server with openssl client when client sends cert"}].
erlang_server_openssl_client_client_cert(Config) when is_list(Config) ->
@@ -935,39 +943,38 @@ erlang_server_openssl_client_client_cert(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
{_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
+
Data = "From openssl to erlang",
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE,
- erlang_ssl_receive, [Data]}},
- {options,
- [{verify , verify_peer}
- | ServerOpts]}]),
+ {from, self()},
+ {mfa, {?MODULE,
+ erlang_ssl_receive, [Data]}},
+ {options,
+ [{verify , verify_peer}
+ | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
-
+
CaCertFile = proplists:get_value(cacertfile, ClientOpts),
CertFile = proplists:get_value(certfile, ClientOpts),
KeyFile = proplists:get_value(keyfile, ClientOpts),
Version = ssl_test_lib:protocol_version(Config),
Exe = "openssl",
Args = ["s_client", "-cert", CertFile,
- "-CAfile", CaCertFile,
- "-key", KeyFile,"-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
- ssl_test_lib:version_flag(Version)],
+ "-CAfile", CaCertFile,
+ "-key", KeyFile,"-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
+ ssl_test_lib:version_flag(Version)],
OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
true = port_command(OpenSslPort, Data),
ssl_test_lib:check_result(Server, ok),
-
+
%% Clean close down! Server needs to be closed first !!
ssl_test_lib:close_port(OpenSslPort),
ssl_test_lib:close(Server),
process_flag(trap_exit, false).
%%--------------------------------------------------------------------
-
erlang_server_erlang_client_client_cert() ->
[{doc,"Test erlang server with erlang client when client sends cert"}].
erlang_server_erlang_client_client_cert(Config) when is_list(Config) ->
@@ -976,30 +983,30 @@ erlang_server_erlang_client_client_cert(Config) when is_list(Config) ->
ClientOpts = proplists:get_value(client_rsa_verify_opts, Config),
Version = ssl_test_lib:protocol_version(Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
+
Data = "From erlang to erlang",
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE,
- erlang_ssl_receive,
- %% Due to 1/n-1 splitting countermeasure Rizzo/Duong-Beast
- [Data]}},
- {options,
- [{verify , verify_peer}
- | ServerOpts]}]),
+ {from, self()},
+ {mfa, {?MODULE,
+ erlang_ssl_receive,
+ %% Due to 1/n-1 splitting countermeasure Rizzo/Duong-Beast
+ [Data]}},
+ {options,
+ [{verify , verify_peer}
+ | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
-
+
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- %% Due to 1/n-1 splitting countermeasure Rizzo/Duong-Beast
- {mfa, {ssl, send, [Data]}},
- {options,
- [{versions, [Version]} | ClientOpts]}]),
-
+ {host, Hostname},
+ {from, self()},
+ %% Due to 1/n-1 splitting countermeasure Rizzo/Duong-Beast
+ {mfa, {ssl, send, [Data]}},
+ {options,
+ [{versions, [Version]} | ClientOpts]}]),
+
ssl_test_lib:check_result(Server, ok, Client, ok),
-
+
ssl_test_lib:close(Server),
ssl_test_lib:close(Client),
process_flag(trap_exit, false).
@@ -1031,43 +1038,43 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
{ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
-
+
Port = ssl_test_lib:inet_port(node()),
CertFile = proplists:get_value(certfile, ServerOpts),
KeyFile = proplists:get_value(keyfile, ServerOpts),
Version = ssl_test_lib:protocol_version(Config),
Exe = "openssl",
Args = ["s_server", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version),
- "-cert", CertFile, "-key", KeyFile],
+ "-cert", CertFile, "-key", KeyFile],
OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
+
ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
+
Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, server_sent_garbage, []}},
- {options,
- [{versions, [Version]} | ClientOpts]}]),
-
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, server_sent_garbage, []}},
+ {options,
+ [{versions, [Version]} | ClientOpts]}]),
+
%% Send garbage
true = port_command(OpensslPort, ?OPENSSL_GARBAGE),
ct:sleep(?SLEEP),
Client0 ! server_sent_garbage,
-
+
ssl_test_lib:check_result(Client0, true),
-
+
ssl_test_lib:close(Client0),
-
+
%% Make sure openssl does not hang and leave zombie process
Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, no_result_msg, []}},
- {options,
- [{versions, [Version]} | ClientOpts]}]),
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options,
+ [{versions, [Version]} | ClientOpts]}]),
%% Clean close down! Server needs to be closed first !!
ssl_test_lib:close_port(OpensslPort),
@@ -1092,38 +1099,38 @@ expired_session(Config) when is_list(Config) ->
Exe = "openssl",
Args = ["s_server", "-accept", integer_to_list(Port),
- "-cert", CertFile,"-key", KeyFile],
-
+ "-cert", CertFile,"-key", KeyFile],
+
OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
ssl_test_lib:wait_for_openssl_server(Port, tls),
-
+
Client0 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, no_result, []}},
- {from, self()}, {options, ClientOpts}]),
-
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {from, self()}, {options, ClientOpts}]),
+
ssl_test_lib:close(Client0),
%% Make sure session is registered
ct:sleep(?SLEEP),
Client1 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, no_result, []}},
- {from, self()}, {options, ClientOpts}]),
-
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {from, self()}, {options, ClientOpts}]),
+
ssl_test_lib:close(Client1),
%% Make sure session is unregistered due to expiration
ct:sleep((?EXPIRE+1) * 1000),
-
+
Client2 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, no_result, []}},
- {from, self()}, {options, ClientOpts}]),
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {from, self()}, {options, ClientOpts}]),
%% Clean close down! Server needs to be closed first !!
ssl_test_lib:close_port(OpensslPort),
@@ -1139,52 +1146,21 @@ ssl2_erlang_server_openssl_client(Config) when is_list(Config) ->
ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
{_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Exe = "openssl",
- Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
- "-ssl2", "-msg"],
-
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ct:log("Ports ~p~n", [[erlang:port_info(P) || P <- erlang:ports()]]),
- consume_port_exit(OpenSslPort),
- ssl_test_lib:check_result(Server, {error, {tls_alert, "bad record mac"}}),
- process_flag(trap_exit, false).
-%%--------------------------------------------------------------------
-ssl2_erlang_server_openssl_client_comp() ->
- [{doc,"Test that ssl v2 clients are rejected"}].
-
-ssl2_erlang_server_openssl_client_comp(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- V2Compat = proplists:get_value(v2_hello_compatible, Config),
-
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
-
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From openssl to erlang",
Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {options, [{v2_hello_compatible, V2Compat} | ServerOpts]}]),
+ {from, self()},
+ {options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
-
+
Exe = "openssl",
Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
- "-ssl2", "-msg"],
-
+ "-ssl2", "-msg"],
+
OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
- true = port_command(OpenSslPort, Data),
-
+
ct:log("Ports ~p~n", [[erlang:port_info(P) || P <- erlang:ports()]]),
- consume_port_exit(OpenSslPort),
- ssl_test_lib:check_result(Server, {error, {tls_alert, "protocol version"}}),
+ ssl_test_lib:consume_port_exit(OpenSslPort),
+ ssl_test_lib:check_server_alert(Server, unexpected_message),
process_flag(trap_exit, false).
%%--------------------------------------------------------------------
@@ -1485,6 +1461,7 @@ send_and_hostname(SSLSocket) ->
end.
erlang_server_openssl_client_sni_test(Config, SNIHostname, ExpectedSNIHostname, ExpectedCN) ->
+ Version = ssl_test_lib:protocol_version(Config),
ct:log("Start running handshake, Config: ~p, SNIHostname: ~p, ExpectedSNIHostname: ~p, ExpectedCN: ~p", [Config, SNIHostname, ExpectedSNIHostname, ExpectedCN]),
ServerOptions = proplists:get_value(sni_server_opts, Config) ++ proplists:get_value(server_rsa_opts, Config),
{_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -1495,9 +1472,9 @@ erlang_server_openssl_client_sni_test(Config, SNIHostname, ExpectedSNIHostname,
Exe = "openssl",
ClientArgs = case SNIHostname of
undefined ->
- openssl_client_args(ssl_test_lib:supports_ssl_tls_version(sslv2), Hostname,Port);
+ openssl_client_args(Version, Hostname,Port);
_ ->
- openssl_client_args(ssl_test_lib:supports_ssl_tls_version(sslv2), Hostname, Port, SNIHostname)
+ openssl_client_args(Version, Hostname, Port, SNIHostname)
end,
ClientPort = ssl_test_lib:portable_open_port(Exe, ClientArgs),
@@ -1508,6 +1485,7 @@ erlang_server_openssl_client_sni_test(Config, SNIHostname, ExpectedSNIHostname,
erlang_server_openssl_client_sni_test_sni_fun(Config, SNIHostname, ExpectedSNIHostname, ExpectedCN) ->
+ Version = ssl_test_lib:protocol_version(Config),
ct:log("Start running handshake for sni_fun, Config: ~p, SNIHostname: ~p, ExpectedSNIHostname: ~p, ExpectedCN: ~p", [Config, SNIHostname, ExpectedSNIHostname, ExpectedCN]),
[{sni_hosts, ServerSNIConf}] = proplists:get_value(sni_server_opts, Config),
SNIFun = fun(Domain) -> proplists:get_value(Domain, ServerSNIConf, undefined) end,
@@ -1520,9 +1498,9 @@ erlang_server_openssl_client_sni_test_sni_fun(Config, SNIHostname, ExpectedSNIHo
Exe = "openssl",
ClientArgs = case SNIHostname of
undefined ->
- openssl_client_args(ssl_test_lib:supports_ssl_tls_version(sslv2), Hostname,Port);
+ openssl_client_args(Version, Hostname,Port);
_ ->
- openssl_client_args(ssl_test_lib:supports_ssl_tls_version(sslv2), Hostname, Port, SNIHostname)
+ openssl_client_args(Version, Hostname, Port, SNIHostname)
end,
ClientPort = ssl_test_lib:portable_open_port(Exe, ClientArgs),
@@ -1590,8 +1568,8 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
start_erlang_client_and_openssl_server_with_opts(Config, ErlangClientOpts, OpensslServerOpts, Data, Callback) ->
process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
ClientOpts = ErlangClientOpts ++ ClientOpts0,
{ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
@@ -1599,6 +1577,7 @@ start_erlang_client_and_openssl_server_with_opts(Config, ErlangClientOpts, Opens
Data = "From openssl to erlang",
Port = ssl_test_lib:inet_port(node()),
+ CaCertFile = proplists:get_value(cacertfile, ServerOpts),
CertFile = proplists:get_value(certfile, ServerOpts),
KeyFile = proplists:get_value(keyfile, ServerOpts),
Version = ssl_test_lib:protocol_version(Config),
@@ -1608,10 +1587,12 @@ start_erlang_client_and_openssl_server_with_opts(Config, ErlangClientOpts, Opens
[] ->
["s_server", "-accept",
integer_to_list(Port), ssl_test_lib:version_flag(Version),
+ "-CAfile", CaCertFile,
"-cert", CertFile,"-key", KeyFile];
[Opt, Value] ->
["s_server", Opt, Value, "-accept",
integer_to_list(Port), ssl_test_lib:version_flag(Version),
+ "-CAfile", CaCertFile,
"-cert", CertFile,"-key", KeyFile]
end,
@@ -1636,8 +1617,8 @@ start_erlang_client_and_openssl_server_with_opts(Config, ErlangClientOpts, Opens
start_erlang_client_and_openssl_server_for_alpn_negotiation(Config, Data, Callback) ->
process_flag(trap_exit, true),
- ServerOpts = proplists:get_value(server_rsa_opts, Config),
- ClientOpts0 = proplists:get_value(client_rsa_opts, Config),
+ ServerOpts = proplists:get_value(server_rsa_verify_opts, Config),
+ ClientOpts0 = proplists:get_value(client_rsa_verify_opts, Config),
ClientOpts = [{alpn_advertised_protocols, [<<"spdy/2">>]} | ClientOpts0],
{ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
@@ -1645,12 +1626,14 @@ start_erlang_client_and_openssl_server_for_alpn_negotiation(Config, Data, Callba
Data = "From openssl to erlang",
Port = ssl_test_lib:inet_port(node()),
+ CaCertFile = proplists:get_value(cacertfile, ServerOpts),
CertFile = proplists:get_value(certfile, ServerOpts),
KeyFile = proplists:get_value(keyfile, ServerOpts),
Version = ssl_test_lib:protocol_version(Config),
Exe = "openssl",
Args = ["s_server", "-msg", "-alpn", "http/1.1,spdy/2", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version),
+ "-CAfile", CaCertFile,
"-cert", CertFile, "-key", KeyFile],
OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
@@ -1768,8 +1751,8 @@ start_erlang_server_and_openssl_client_for_alpn_npn_negotiation(Config, Data, Ca
start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, Callback) ->
process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
ClientOpts = [{client_preferred_next_protocols, {client, [<<"spdy/2">>], <<"http/1.1">>}} | ClientOpts0],
{ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
@@ -1777,6 +1760,7 @@ start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, Callbac
Data = "From openssl to erlang",
Port = ssl_test_lib:inet_port(node()),
+ CaCertFile = proplists:get_value(cacertfile, ServerOpts),
CertFile = proplists:get_value(certfile, ServerOpts),
KeyFile = proplists:get_value(keyfile, ServerOpts),
Version = ssl_test_lib:protocol_version(Config),
@@ -1784,6 +1768,7 @@ start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, Callbac
Exe = "openssl",
Args = ["s_server", "-msg", "-nextprotoneg", "http/1.1,spdy/2", "-accept", integer_to_list(Port),
ssl_test_lib:version_flag(Version),
+ "-CAfile", CaCertFile,
"-cert", CertFile, "-key", KeyFile],
OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
@@ -1874,6 +1859,11 @@ erlang_ssl_receive(Socket, Data) ->
ct:log("Connection info: ~p~n",
[ssl:connection_information(Socket)]),
receive
+ {ssl, Socket, "R\n"} ->
+ %% Swallow s_client renegotiation command.
+ %% openssl s_client connected commands can appear on
+ %% server side with some openssl versions.
+ erlang_ssl_receive(Socket,Data);
{ssl, Socket, Data} ->
io:format("Received ~p~n",[Data]),
%% open_ssl server sometimes hangs waiting in blocking read
@@ -1912,16 +1902,28 @@ server_sent_garbage(Socket) ->
{error, closed} == ssl:send(Socket, "data")
end.
+
+send_wait_send(Socket, [ErlData, OpenSslData]) ->
+ ssl:send(Socket, ErlData),
+ ct:sleep(?SLEEP),
+ ssl:send(Socket, ErlData),
+ erlang_ssl_receive(Socket, OpenSslData).
check_openssl_sni_support(Config) ->
HelpText = os:cmd("openssl s_client --help"),
- case string:str(HelpText, "-servername") of
- 0 ->
- {skip, "Current openssl doesn't support SNI"};
- _ ->
- Config
+ case ssl_test_lib:is_sane_oppenssl_client() of
+ true ->
+ case string:str(HelpText, "-servername") of
+ 0 ->
+ {skip, "Current openssl doesn't support SNI"};
+ _ ->
+ Config
+ end;
+ false ->
+ {skip, "Current openssl doesn't support SNI or extension handling is flawed"}
end.
+
check_openssl_npn_support(Config) ->
HelpText = os:cmd("openssl s_client --help"),
case string:str(HelpText, "nextprotoneg") of
@@ -1987,23 +1989,13 @@ workaround_openssl_s_clinent() ->
[]
end.
-openssl_client_args(false, Hostname, Port) ->
- ["s_client", "-connect", Hostname ++ ":" ++ integer_to_list(Port)];
-openssl_client_args(true, Hostname, Port) ->
- ["s_client", "-no_ssl2", "-connect", Hostname ++ ":" ++ integer_to_list(Port)].
+openssl_client_args(Version, Hostname, Port) ->
+ ["s_client", "-connect", Hostname ++ ":" ++ integer_to_list(Port), ssl_test_lib:version_flag(Version)].
-openssl_client_args(false, Hostname, Port, ServerName) ->
+openssl_client_args(Version, Hostname, Port, ServerName) ->
["s_client", "-connect", Hostname ++ ":" ++
- integer_to_list(Port), "-servername", ServerName];
-openssl_client_args(true, Hostname, Port, ServerName) ->
- ["s_client", "-no_ssl2", "-connect", Hostname ++ ":" ++
- integer_to_list(Port), "-servername", ServerName].
-
-consume_port_exit(OpenSSLPort) ->
- receive
- {'EXIT', OpenSSLPort, _} ->
- ok
- end.
+ integer_to_list(Port), ssl_test_lib:version_flag(Version), "-servername", ServerName].
+
hostname_format(Hostname) ->
case lists:member($., Hostname) of
@@ -2012,3 +2004,18 @@ hostname_format(Hostname) ->
false ->
"localhost"
end.
+
+
+openssl_has_common_ciphers(Ciphers) ->
+ OCiphers = ssl_test_lib:common_ciphers(openssl),
+ has_common_ciphers(Ciphers, OCiphers).
+
+has_common_ciphers([], _) ->
+ false;
+has_common_ciphers([Cipher | Rest], OCiphers) ->
+ case lists:member(Cipher, OCiphers) of
+ true ->
+ true;
+ _ ->
+ has_common_ciphers(Rest, OCiphers)
+ end.
diff --git a/lib/ssl/test/ssl_upgrade_SUITE.erl b/lib/ssl/test/ssl_upgrade_SUITE.erl
index 875399db76..ead18aeb73 100644
--- a/lib/ssl/test/ssl_upgrade_SUITE.erl
+++ b/lib/ssl/test/ssl_upgrade_SUITE.erl
@@ -47,10 +47,7 @@ init_per_suite(Config0) ->
{skip, Reason} ->
{skip, Reason};
Config ->
- Result =
- {ok, _} = make_certs:all(proplists:get_value(data_dir, Config),
- proplists:get_value(priv_dir, Config)),
- ssl_test_lib:cert_options(Config)
+ ssl_test_lib:make_rsa_cert(Config)
end
catch _:_ ->
{skip, "Crypto did not start"}
@@ -149,8 +146,8 @@ use_connection(Socket) ->
end.
soft_start_connection(Config, ResulProxy) ->
- ClientOpts = proplists:get_value(client_verification_opts, Config),
- ServerOpts = proplists:get_value(server_verification_opts, Config),
+ ClientOpts = proplists:get_value(client_rsa_verify_opts, Config),
+ ServerOpts = proplists:get_value(server_rsa_verify_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = start_server([{node, ServerNode}, {port, 0},
{from, ResulProxy},
@@ -166,8 +163,8 @@ soft_start_connection(Config, ResulProxy) ->
{Server, Client}.
restart_start_connection(Config, ResulProxy) ->
- ClientOpts = proplists:get_value(client_verification_opts, Config),
- ServerOpts = proplists:get_value(server_verification_opts, Config),
+ ClientOpts = proplists:get_value(client_rsa_verify_opts, Config),
+ ServerOpts = proplists:get_value(server_rsa_verify_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = start_server([{node, ServerNode}, {port, 0},
{from, ResulProxy},
diff --git a/lib/ssl/test/x509_test.erl b/lib/ssl/test/x509_test.erl
index fea01efdaf..faf223ae35 100644
--- a/lib/ssl/test/x509_test.erl
+++ b/lib/ssl/test/x509_test.erl
@@ -22,7 +22,7 @@
-module(x509_test).
- -include_lib("public_key/include/public_key.hrl").
+-include_lib("public_key/include/public_key.hrl").
-export([extensions/1, gen_pem_config_files/3]).
diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk
index 2ece6ef2d5..3c66ffd852 100644
--- a/lib/ssl/vsn.mk
+++ b/lib/ssl/vsn.mk
@@ -1 +1 @@
-SSL_VSN = 8.2.4
+SSL_VSN = 9.3
diff --git a/lib/stdlib/doc/src/Makefile b/lib/stdlib/doc/src/Makefile
index e7ea38c5c3..4541b4a463 100644
--- a/lib/stdlib/doc/src/Makefile
+++ b/lib/stdlib/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2017. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -71,7 +71,6 @@ XML_REF3_FILES = \
gen_statem.xml \
io.xml \
io_lib.xml \
- lib.xml \
lists.xml \
log_mf_h.xml \
maps.xml \
@@ -98,6 +97,7 @@ XML_REF3_FILES = \
sys.xml \
timer.xml \
unicode.xml \
+ uri_string.xml \
win32reg.xml \
zip.xml
@@ -155,6 +155,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(MAN6DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
@@ -162,7 +163,7 @@ clean clean_docs:
rm -f errs core *~
$(SPECDIR)/specs_erl_id_trans.xml:
- escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \
+ $(gen_verbose)escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \
-o$(dir $@) -module erl_id_trans
# ----------------------------------------------------
diff --git a/lib/stdlib/doc/src/array.xml b/lib/stdlib/doc/src/array.xml
index db0ab42372..aa1577a067 100644
--- a/lib/stdlib/doc/src/array.xml
+++ b/lib/stdlib/doc/src/array.xml
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>array.xml</file>
</header>
- <module>array</module>
+ <module since="">array</module>
<modulesummary>Functional, extendible arrays.</modulesummary>
<description>
<p>Functional, extendible arrays. Arrays can have fixed size, or can grow
@@ -137,7 +137,7 @@ A3 = array:fix(A2).</pre>
<funcs>
<func>
- <name name="default" arity="1"/>
+ <name name="default" arity="1" since=""/>
<fsummary>Get the value used for uninitialized entries.</fsummary>
<desc><marker id="default-1"/>
<p>Gets the value used for uninitialized entries.</p>
@@ -146,7 +146,7 @@ A3 = array:fix(A2).</pre>
</func>
<func>
- <name name="fix" arity="1"/>
+ <name name="fix" arity="1" since=""/>
<fsummary>Fix the array size.</fsummary>
<desc><marker id="fix-1"/>
<p>Fixes the array size. This prevents it from growing automatically
@@ -157,7 +157,7 @@ A3 = array:fix(A2).</pre>
</func>
<func>
- <name name="foldl" arity="3"/>
+ <name name="foldl" arity="3" since=""/>
<fsummary>Fold the array elements using the specified function and initial
accumulator value.</fsummary>
<desc><marker id="foldl-3"/>
@@ -172,7 +172,7 @@ A3 = array:fix(A2).</pre>
</func>
<func>
- <name name="foldr" arity="3"/>
+ <name name="foldr" arity="3" since=""/>
<fsummary>Fold the array elements right-to-left using the specified
function and initial accumulator value.</fsummary>
<desc><marker id="foldr-3"/>
@@ -186,7 +186,7 @@ A3 = array:fix(A2).</pre>
</func>
<func>
- <name name="from_list" arity="1"/>
+ <name name="from_list" arity="1" since=""/>
<fsummary>Equivalent to <c>from_list(List, undefined)</c>.</fsummary>
<desc><marker id="from_list-1"/>
<p>Equivalent to
@@ -195,7 +195,7 @@ A3 = array:fix(A2).</pre>
</func>
<func>
- <name name="from_list" arity="2"/>
+ <name name="from_list" arity="2" since=""/>
<fsummary>Convert a list to an extendible array.</fsummary>
<desc><marker id="from_list-2"/>
<p>Converts a list to an extendible array. <c><anno>Default</anno></c>
@@ -208,7 +208,7 @@ A3 = array:fix(A2).</pre>
</func>
<func>
- <name name="from_orddict" arity="1"/>
+ <name name="from_orddict" arity="1" since=""/>
<fsummary>Equivalent to <c>from_orddict(Orddict, undefined)</c>.
</fsummary>
<desc><marker id="from_orddict-1"/>
@@ -218,7 +218,7 @@ A3 = array:fix(A2).</pre>
</func>
<func>
- <name name="from_orddict" arity="2"/>
+ <name name="from_orddict" arity="2" since=""/>
<fsummary>Convert an ordered list of pairs <c>{Index, Value}</c> to a
corresponding extendible array.</fsummary>
<desc><marker id="from_orddict-2"/>
@@ -234,7 +234,7 @@ A3 = array:fix(A2).</pre>
</func>
<func>
- <name name="get" arity="2"/>
+ <name name="get" arity="2" since=""/>
<fsummary>Get the value of entry <c>I</c>.</fsummary>
<desc><marker id="get-2"/>
<p>Gets the value of entry <c><anno>I</anno></c>. If
@@ -249,7 +249,7 @@ A3 = array:fix(A2).</pre>
</func>
<func>
- <name name="is_array" arity="1"/>
+ <name name="is_array" arity="1" since=""/>
<fsummary>Returns <c>true</c> if <c>X</c> is an array, otherwise
<c>false</c>.</fsummary>
<desc><marker id="is_array-1"/>
@@ -261,7 +261,7 @@ A3 = array:fix(A2).</pre>
</func>
<func>
- <name name="is_fix" arity="1"/>
+ <name name="is_fix" arity="1" since=""/>
<fsummary>Check if the array has fixed size.</fsummary>
<desc><marker id="is_fix-1"/>
<p>Checks if the array has fixed size. Returns <c>true</c> if the array
@@ -271,7 +271,7 @@ A3 = array:fix(A2).</pre>
</func>
<func>
- <name name="map" arity="2"/>
+ <name name="map" arity="2" since=""/>
<fsummary>Map the specified function onto each array element.</fsummary>
<desc><marker id="map-2"/>
<p>Maps the specified function onto each array element. The elements are
@@ -285,7 +285,7 @@ A3 = array:fix(A2).</pre>
</func>
<func>
- <name name="new" arity="0"/>
+ <name name="new" arity="0" since=""/>
<fsummary>Create a new, extendible array with initial size zero.
</fsummary>
<desc><marker id="new-0"/>
@@ -296,7 +296,7 @@ A3 = array:fix(A2).</pre>
</func>
<func>
- <name name="new" arity="1"/>
+ <name name="new" arity="1" since=""/>
<fsummary>Create a new array according to the specified options.
</fsummary>
<desc><marker id="new-1"/>
@@ -346,7 +346,7 @@ array:new([{size,10},{fixed,false},{default,-1}])</pre>
</func>
<func>
- <name name="new" arity="2"/>
+ <name name="new" arity="2" since=""/>
<fsummary>Create a new array according to the specified size and options.
</fsummary>
<desc><marker id="new-2"/>
@@ -370,7 +370,7 @@ array:new(100, {default,0})</pre>
</func>
<func>
- <name name="relax" arity="1"/>
+ <name name="relax" arity="1" since=""/>
<fsummary>Make the array resizable.</fsummary>
<desc><marker id="relax-1"/>
<p>Makes the array resizable. (Reverses the effects of
@@ -380,7 +380,7 @@ array:new(100, {default,0})</pre>
</func>
<func>
- <name name="reset" arity="2"/>
+ <name name="reset" arity="2" since=""/>
<fsummary>Reset entry <c>I</c> to the default value for the array.
</fsummary>
<desc><marker id="reset-2"/>
@@ -399,7 +399,7 @@ array:new(100, {default,0})</pre>
</func>
<func>
- <name name="resize" arity="1"/>
+ <name name="resize" arity="1" since=""/>
<fsummary>Change the array size to that reported by <c>sparse_size/1</c>.
</fsummary>
<desc><marker id="resize-1"/>
@@ -413,7 +413,7 @@ array:new(100, {default,0})</pre>
</func>
<func>
- <name name="resize" arity="2"/>
+ <name name="resize" arity="2" since=""/>
<fsummary>Change the array size.</fsummary>
<desc><marker id="resize-2"/>
<p>Change the array size. If <c><anno>Size</anno></c> is not a
@@ -424,7 +424,7 @@ array:new(100, {default,0})</pre>
</func>
<func>
- <name name="set" arity="3"/>
+ <name name="set" arity="3" since=""/>
<fsummary>Set entry <c>I</c> of the array to <c>Value</c>.</fsummary>
<desc><marker id="set-3"/>
<p>Sets entry <c><anno>I</anno></c> of the array to
@@ -441,7 +441,7 @@ array:new(100, {default,0})</pre>
</func>
<func>
- <name name="size" arity="1"/>
+ <name name="size" arity="1" since=""/>
<fsummary>Get the number of entries in the array.</fsummary>
<desc><marker id="size-1"/>
<p>Gets the number of entries in the array. Entries are numbered from
@@ -454,7 +454,7 @@ array:new(100, {default,0})</pre>
</func>
<func>
- <name name="sparse_foldl" arity="3"/>
+ <name name="sparse_foldl" arity="3" since=""/>
<fsummary>Fold the array elements using the specified function and initial
accumulator value, skipping default-valued entries.</fsummary>
<desc><marker id="sparse_foldl-3"/>
@@ -469,7 +469,7 @@ array:new(100, {default,0})</pre>
</func>
<func>
- <name name="sparse_foldr" arity="3"/>
+ <name name="sparse_foldr" arity="3" since=""/>
<fsummary>Fold the array elements right-to-left using the specified
function and initial accumulator value, skipping default-valued
entries.</fsummary>
@@ -485,7 +485,7 @@ array:new(100, {default,0})</pre>
</func>
<func>
- <name name="sparse_map" arity="2"/>
+ <name name="sparse_map" arity="2" since=""/>
<fsummary>Map the specified function onto each array element, skipping
default-valued entries.</fsummary>
<desc><marker id="sparse_map-2"/>
@@ -498,7 +498,7 @@ array:new(100, {default,0})</pre>
</func>
<func>
- <name name="sparse_size" arity="1"/>
+ <name name="sparse_size" arity="1" since=""/>
<fsummary>Get the number of entries in the array up until the last
non-default-valued entry.</fsummary>
<desc><marker id="sparse_size-1"/>
@@ -512,7 +512,7 @@ array:new(100, {default,0})</pre>
</func>
<func>
- <name name="sparse_to_list" arity="1"/>
+ <name name="sparse_to_list" arity="1" since=""/>
<fsummary>Convert the array to a list, skipping default-valued entries.
</fsummary>
<desc><marker id="sparse_to_list-1"/>
@@ -522,7 +522,7 @@ array:new(100, {default,0})</pre>
</func>
<func>
- <name name="sparse_to_orddict" arity="1"/>
+ <name name="sparse_to_orddict" arity="1" since=""/>
<fsummary>Convert the array to an ordered list of pairs <c>{Index,
Value}</c>, skipping default-valued entries.</fsummary>
<desc><marker id="sparse_to_orddict-1"/>
@@ -534,7 +534,7 @@ array:new(100, {default,0})</pre>
</func>
<func>
- <name name="to_list" arity="1"/>
+ <name name="to_list" arity="1" since=""/>
<fsummary>Convert the array to a list.</fsummary>
<desc><marker id="to_list-1"/>
<p>Converts the array to a list.</p>
@@ -545,7 +545,7 @@ array:new(100, {default,0})</pre>
</func>
<func>
- <name name="to_orddict" arity="1"/>
+ <name name="to_orddict" arity="1" since=""/>
<fsummary>Convert the array to an ordered list of pairs <c>{Index,
Value}</c>.</fsummary>
<desc><marker id="to_orddict-1"/>
diff --git a/lib/stdlib/doc/src/assert_hrl.xml b/lib/stdlib/doc/src/assert_hrl.xml
index 33f29f38da..fb27954235 100644
--- a/lib/stdlib/doc/src/assert_hrl.xml
+++ b/lib/stdlib/doc/src/assert_hrl.xml
@@ -4,7 +4,7 @@
<fileref>
<header>
<copyright>
- <year>2012</year><year>2017</year>
+ <year>2012</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -46,7 +46,7 @@
is the macro name, for example, <c>assertEqual</c>. <c>Info</c> is a list
of tagged values, such as <c>[{module, M}, {line, L}, ...]</c>, which
gives more information about the location and cause of the exception. All
- entries in the <c>Info</c> list are optional; do not rely programatically
+ entries in the <c>Info</c> list are optional; do not rely programmatically
on any of them being present.</p>
<p>Each assert macro has a corresponding version with an extra argument,
diff --git a/lib/stdlib/doc/src/base64.xml b/lib/stdlib/doc/src/base64.xml
index cfa1ecc006..479072ba4f 100644
--- a/lib/stdlib/doc/src/base64.xml
+++ b/lib/stdlib/doc/src/base64.xml
@@ -29,7 +29,7 @@
<rev></rev>
<file>base64.xml</file>
</header>
- <module>base64</module>
+ <module since="">base64</module>
<modulesummary>Provides base64 encode and decode, see
RFC 2045.</modulesummary>
<description>
@@ -51,10 +51,10 @@
<funcs>
<func>
- <name name="decode" arity="1"/>
- <name name="decode_to_string" arity="1"/>
- <name name="mime_decode" arity="1"/>
- <name name="mime_decode_to_string" arity="1"/>
+ <name name="decode" arity="1" since=""/>
+ <name name="decode_to_string" arity="1" since=""/>
+ <name name="mime_decode" arity="1" since=""/>
+ <name name="mime_decode_to_string" arity="1" since=""/>
<fsummary>Decode a base64 encoded string to data.</fsummary>
<type variable="Base64" name_i="1"/>
<type variable="Data" name_i="1"/>
@@ -69,8 +69,8 @@
</func>
<func>
- <name name="encode" arity="1"/>
- <name name="encode_to_string" arity="1"/>
+ <name name="encode" arity="1" since=""/>
+ <name name="encode_to_string" arity="1" since=""/>
<fsummary>Encode data into base64.</fsummary>
<type variable="Data"/>
<type variable="Base64" name_i="1"/>
diff --git a/lib/stdlib/doc/src/beam_lib.xml b/lib/stdlib/doc/src/beam_lib.xml
index 26d0724aaf..bb44ca3201 100644
--- a/lib/stdlib/doc/src/beam_lib.xml
+++ b/lib/stdlib/doc/src/beam_lib.xml
@@ -28,7 +28,7 @@
<date>1999-10-30</date>
<rev>PA1</rev>
</header>
- <module>beam_lib</module>
+ <module since="">beam_lib</module>
<modulesummary>An interface to the BEAM file format.</modulesummary>
<description>
<p>This module provides an interface to files created by
@@ -180,8 +180,8 @@ io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).</code>
<name name="beam"/>
<desc>
<p>Each of the functions described below accept either the
- module name, the filename, or a binary containing the BEAM
- module.</p>
+ filename (as a string) or a binary containing the BEAM
+ module.</p>
</desc>
</datatype>
<datatype>
@@ -267,7 +267,7 @@ io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).</code>
<funcs>
<func>
- <name name="all_chunks" arity="1"/>
+ <name name="all_chunks" arity="1" since="OTP 18.2"/>
<fsummary>Read all chunks from a BEAM file or binary</fsummary>
<desc>
<p>Reads chunk data for all chunks.</p>
@@ -275,7 +275,7 @@ io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).</code>
</func>
<func>
- <name name="build_module" arity="1"/>
+ <name name="build_module" arity="1" since="OTP 18.2"/>
<fsummary>Create a BEAM module from a list of chunks.</fsummary>
<desc>
<p>Builds a BEAM module (as a binary) from a list of chunks.</p>
@@ -283,7 +283,7 @@ io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).</code>
</func>
<func>
- <name name="chunks" arity="2"/>
+ <name name="chunks" arity="2" since=""/>
<fsummary>Read selected chunks from a BEAM file or binary.</fsummary>
<desc>
<p>Reads chunk data for selected chunks references. The order of
@@ -293,7 +293,7 @@ io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).</code>
</func>
<func>
- <name name="chunks" arity="3"/>
+ <name name="chunks" arity="3" since=""/>
<fsummary>Read selected chunks from a BEAM file or binary.</fsummary>
<desc>
<p>Reads chunk data for selected chunks references. The order of
@@ -312,7 +312,7 @@ io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).</code>
</func>
<func>
- <name name="clear_crypto_key_fun" arity="0"/>
+ <name name="clear_crypto_key_fun" arity="0" since=""/>
<fsummary>Unregister the current crypto key fun.</fsummary>
<desc>
<p>Unregisters the crypto key fun and terminates the process
@@ -327,7 +327,7 @@ io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).</code>
</func>
<func>
- <name name="cmp" arity="2"/>
+ <name name="cmp" arity="2" since=""/>
<fsummary>Compare two BEAM files.</fsummary>
<type name="cmp_rsn"/>
<desc>
@@ -341,7 +341,7 @@ io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).</code>
</func>
<func>
- <name name="cmp_dirs" arity="2"/>
+ <name name="cmp_dirs" arity="2" since=""/>
<fsummary>Compare the BEAM files in two directories.</fsummary>
<desc>
<p>Compares the BEAM files in
@@ -359,7 +359,7 @@ io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).</code>
</func>
<func>
- <name name="crypto_key_fun" arity="1"/>
+ <name name="crypto_key_fun" arity="1" since=""/>
<fsummary>Register a fun that provides a crypto key.</fsummary>
<type name="crypto_fun"/>
<type name="crypto_fun_arg"/>
@@ -398,7 +398,7 @@ CryptoKeyFun(clear) -> term()</code>
</func>
<func>
- <name name="diff_dirs" arity="2"/>
+ <name name="diff_dirs" arity="2" since=""/>
<fsummary>Compare the BEAM files in two directories.</fsummary>
<desc>
<p>Compares the BEAM files in two directories as
@@ -409,7 +409,7 @@ CryptoKeyFun(clear) -> term()</code>
</func>
<func>
- <name name="format_error" arity="1"/>
+ <name name="format_error" arity="1" since=""/>
<fsummary>Return an English description of a BEAM read error reply.
</fsummary>
<desc>
@@ -422,7 +422,7 @@ CryptoKeyFun(clear) -> term()</code>
</func>
<func>
- <name name="info" arity="1"/>
+ <name name="info" arity="1" since=""/>
<fsummary>Information about a BEAM file.</fsummary>
<desc>
<p>Returns a list containing some information about a BEAM file
@@ -449,7 +449,7 @@ CryptoKeyFun(clear) -> term()</code>
</func>
<func>
- <name name="md5" arity="1"/>
+ <name name="md5" arity="1" since=""/>
<fsummary>Read the module version of the BEAM file.</fsummary>
<desc>
<p>Calculates an MD5 redundancy check for the code of the module
@@ -458,7 +458,7 @@ CryptoKeyFun(clear) -> term()</code>
</func>
<func>
- <name name="strip" arity="1"/>
+ <name name="strip" arity="1" since=""/>
<fsummary>Remove chunks not needed by the loader from a BEAM file.
</fsummary>
<desc>
@@ -470,7 +470,19 @@ CryptoKeyFun(clear) -> term()</code>
</func>
<func>
- <name name="strip_files" arity="1"/>
+ <name name="strip" arity="2" since=""/>
+ <fsummary>Remove chunks not needed by the loader from a BEAM file.
+ </fsummary>
+ <desc>
+ <p>Removes all chunks from a BEAM
+ file except those needed by the loader or passed in. In particular,
+ the debug information (chunk <c>debug_info</c> and <c>abstract_code</c>)
+ is removed.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="strip_files" arity="1" since=""/>
<fsummary>Removes chunks not needed by the loader from BEAM files.
</fsummary>
<desc>
@@ -483,7 +495,20 @@ CryptoKeyFun(clear) -> term()</code>
</func>
<func>
- <name name="strip_release" arity="1"/>
+ <name name="strip_files" arity="2" since=""/>
+ <fsummary>Removes chunks not needed by the loader from BEAM files.
+ </fsummary>
+ <desc>
+ <p>Removes all chunks except
+ those needed by the loader or passed in from BEAM files. In particular,
+ the debug information (chunk <c>debug_info</c> and <c>abstract_code</c>)
+ is removed. The returned list contains one element for each
+ specified filename, in the same order as in <c>Files</c>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="strip_release" arity="1" since=""/>
<fsummary>Remove chunks not needed by the loader from all BEAM files of
a release.</fsummary>
<desc>
@@ -497,7 +522,21 @@ CryptoKeyFun(clear) -> term()</code>
</func>
<func>
- <name name="version" arity="1"/>
+ <name name="strip_release" arity="2" since=""/>
+ <fsummary>Remove chunks not needed by the loader from all BEAM files of
+ a release.</fsummary>
+ <desc>
+ <p>Removes all chunks
+ except those needed by the loader or passed in from the BEAM files of a
+ release. <c><anno>Dir</anno></c> is to be the installation root
+ directory. For example, the current OTP release can be
+ stripped with the call
+ <c>beam_lib:strip_release(code:root_dir())</c>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="version" arity="1" since=""/>
<fsummary>Read the module version of the BEAM file.</fsummary>
<desc>
<p>Returns the module version or versions. A version is defined by
diff --git a/lib/stdlib/doc/src/binary.xml b/lib/stdlib/doc/src/binary.xml
index 6a86d6c7ba..f3d4edd30f 100644
--- a/lib/stdlib/doc/src/binary.xml
+++ b/lib/stdlib/doc/src/binary.xml
@@ -34,7 +34,7 @@
<rev>A</rev>
<file>binary.xml</file>
</header>
- <module>binary</module>
+ <module since="OTP R14B">binary</module>
<modulesummary>Library for handling binary data.</modulesummary>
<description>
@@ -79,7 +79,7 @@
<funcs>
<func>
- <name name="at" arity="2"/>
+ <name name="at" arity="2" since="OTP R14B"/>
<fsummary>Return the byte at a specific position in a binary.</fsummary>
<desc>
<p>Returns the byte at position <c><anno>Pos</anno></c> (zero-based) in
@@ -90,7 +90,7 @@
</func>
<func>
- <name name="bin_to_list" arity="1"/>
+ <name name="bin_to_list" arity="1" since="OTP R14B"/>
<fsummary>Convert a binary to a list of integers.</fsummary>
<desc>
<p>Same as <c>bin_to_list(<anno>Subject</anno>, {0,byte_size(<anno>Subject</anno>)})</c>.</p>
@@ -98,7 +98,7 @@
</func>
<func>
- <name name="bin_to_list" arity="2"/>
+ <name name="bin_to_list" arity="2" since="OTP R14B"/>
<fsummary>Convert a binary to a list of integers.</fsummary>
<desc>
<p>Converts <c><anno>Subject</anno></c> to a list of <c>byte()</c>s, each
@@ -118,7 +118,7 @@
</func>
<func>
- <name name="bin_to_list" arity="3"/>
+ <name name="bin_to_list" arity="3" since="OTP R14B"/>
<fsummary>Convert a binary to a list of integers.</fsummary>
<desc>
<p>Same as<c> bin_to_list(<anno>Subject</anno>, {<anno>Pos</anno>, <anno>Len</anno>})</c>.</p>
@@ -126,7 +126,7 @@
</func>
<func>
- <name name="compile_pattern" arity="1"/>
+ <name name="compile_pattern" arity="1" since="OTP R14B"/>
<fsummary>Precompile a binary search pattern.</fsummary>
<desc>
<p>Builds an internal structure representing a compilation of a
@@ -158,7 +158,7 @@
</func>
<func>
- <name name="copy" arity="1"/>
+ <name name="copy" arity="1" since="OTP R14B"/>
<fsummary>Create a duplicate of a binary.</fsummary>
<desc>
<p>Same as <c>copy(<anno>Subject</anno>, 1)</c>.</p>
@@ -166,7 +166,7 @@
</func>
<func>
- <name name="copy" arity="2"/>
+ <name name="copy" arity="2" since="OTP R14B"/>
<fsummary>Duplicate a binary <c>N</c> times and create a new.</fsummary>
<desc>
<p>Creates a binary with the content of <c><anno>Subject</anno></c>
@@ -193,7 +193,7 @@
</func>
<func>
- <name name="decode_unsigned" arity="1"/>
+ <name name="decode_unsigned" arity="1" since="OTP R14B"/>
<fsummary>Decode a whole binary into an integer of arbitrary size.
</fsummary>
<desc>
@@ -202,7 +202,7 @@
</func>
<func>
- <name name="decode_unsigned" arity="2"/>
+ <name name="decode_unsigned" arity="2" since="OTP R14B"/>
<fsummary>Decode a whole binary into an integer of arbitrary size.
</fsummary>
<desc>
@@ -219,7 +219,7 @@
</func>
<func>
- <name name="encode_unsigned" arity="1"/>
+ <name name="encode_unsigned" arity="1" since="OTP R14B"/>
<fsummary>Encode an unsigned integer into the minimal binary.</fsummary>
<desc>
<p>Same as <c>encode_unsigned(<anno>Unsigned</anno>, big)</c>.</p>
@@ -227,7 +227,7 @@
</func>
<func>
- <name name="encode_unsigned" arity="2"/>
+ <name name="encode_unsigned" arity="2" since="OTP R14B"/>
<fsummary>Encode an unsigned integer into the minimal binary.</fsummary>
<desc>
<p>Converts a positive integer to the smallest possible
@@ -243,7 +243,7 @@
</func>
<func>
- <name name="first" arity="1"/>
+ <name name="first" arity="1" since="OTP R14B"/>
<fsummary>Return the first byte of a binary.</fsummary>
<desc>
<p>Returns the first byte of binary <c><anno>Subject</anno></c> as an
@@ -253,7 +253,7 @@
</func>
<func>
- <name name="last" arity="1"/>
+ <name name="last" arity="1" since="OTP R14B"/>
<fsummary>Return the last byte of a binary.</fsummary>
<desc>
<p>Returns the last byte of binary <c><anno>Subject</anno></c> as an
@@ -263,7 +263,7 @@
</func>
<func>
- <name name="list_to_bin" arity="1"/>
+ <name name="list_to_bin" arity="1" since="OTP R14B"/>
<fsummary>Convert a list of integers and binaries to a binary.</fsummary>
<desc>
<p>Works exactly as
@@ -273,7 +273,7 @@
</func>
<func>
- <name name="longest_common_prefix" arity="1"/>
+ <name name="longest_common_prefix" arity="1" since="OTP R14B"/>
<fsummary>Return length of longest common prefix for a set of binaries.
</fsummary>
<desc>
@@ -294,7 +294,7 @@
</func>
<func>
- <name name="longest_common_suffix" arity="1"/>
+ <name name="longest_common_suffix" arity="1" since="OTP R14B"/>
<fsummary>Return length of longest common suffix for a set of binaries.
</fsummary>
<desc>
@@ -315,7 +315,7 @@
</func>
<func>
- <name name="match" arity="2"/>
+ <name name="match" arity="2" since="OTP R14B"/>
<fsummary>Search for the first match of a pattern in a binary.</fsummary>
<desc>
<p>Same as <c>match(<anno>Subject</anno>, <anno>Pattern</anno>, [])</c>.
@@ -324,7 +324,7 @@
</func>
<func>
- <name name="match" arity="3"/>
+ <name name="match" arity="3" since="OTP R14B"/>
<fsummary>Search for the first match of a pattern in a binary.</fsummary>
<type name="part"/>
<desc>
@@ -372,7 +372,7 @@
</func>
<func>
- <name name="matches" arity="2"/>
+ <name name="matches" arity="2" since="OTP R14B"/>
<fsummary>Search for all matches of a pattern in a binary.</fsummary>
<desc>
<p>Same as <c>matches(<anno>Subject</anno>, <anno>Pattern</anno>, [])</c>.
@@ -381,7 +381,7 @@
</func>
<func>
- <name name="matches" arity="3"/>
+ <name name="matches" arity="3" since="OTP R14B"/>
<fsummary>Search for all matches of a pattern in a binary.</fsummary>
<type name="part"/>
<desc>
@@ -425,7 +425,7 @@
</func>
<func>
- <name name="part" arity="2"/>
+ <name name="part" arity="2" since="OTP R14B"/>
<fsummary>Extract a part of a binary.</fsummary>
<desc>
<p>Extracts the part of binary <c><anno>Subject</anno></c> described by
@@ -453,7 +453,7 @@
</func>
<func>
- <name name="part" arity="3"/>
+ <name name="part" arity="3" since="OTP R14B"/>
<fsummary>Extract a part of a binary.</fsummary>
<desc>
<p>Same as <c>part(<anno>Subject</anno>, {<anno>Pos</anno>,
@@ -462,7 +462,7 @@
</func>
<func>
- <name name="referenced_byte_size" arity="1"/>
+ <name name="referenced_byte_size" arity="1" since="OTP R14B"/>
<fsummary>Determine the size of the binary pointed out by a subbinary.
</fsummary>
<desc>
@@ -525,7 +525,7 @@ store(Binary, GBSet) ->
</func>
<func>
- <name name="replace" arity="3"/>
+ <name name="replace" arity="3" since="OTP R14B"/>
<fsummary>Replace bytes in a binary according to a pattern.</fsummary>
<desc>
<p>Same as <c>replace(<anno>Subject</anno>, <anno>Pattern</anno>, <anno>Replacement</anno>,[])</c>.</p>
@@ -533,7 +533,7 @@ store(Binary, GBSet) ->
</func>
<func>
- <name name="replace" arity="4"/>
+ <name name="replace" arity="4" since="OTP R14B"/>
<fsummary>Replace bytes in a binary according to a pattern.</fsummary>
<type_desc variable="OnePos">An integer() =&lt; byte_size(<anno>Replacement</anno>)
</type_desc>
@@ -575,7 +575,7 @@ store(Binary, GBSet) ->
</func>
<func>
- <name name="split" arity="2"/>
+ <name name="split" arity="2" since="OTP R14B"/>
<fsummary>Split a binary according to a pattern.</fsummary>
<desc>
<p>Same as <c>split(<anno>Subject</anno>, <anno>Pattern</anno>,
@@ -584,7 +584,7 @@ store(Binary, GBSet) ->
</func>
<func>
- <name name="split" arity="3"/>
+ <name name="split" arity="3" since="OTP R14B"/>
<fsummary>Split a binary according to a pattern.</fsummary>
<desc>
<p>Splits <c><anno>Subject</anno></c> into a list of binaries based on
diff --git a/lib/stdlib/doc/src/c.xml b/lib/stdlib/doc/src/c.xml
index 7666699183..29edc373c7 100644
--- a/lib/stdlib/doc/src/c.xml
+++ b/lib/stdlib/doc/src/c.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -28,7 +28,7 @@
<date>1996-10-30</date>
<rev>B</rev>
</header>
- <module>c</module>
+ <module since="">c</module>
<modulesummary>Command interface module.</modulesummary>
<description>
<p>This module enables users to enter the short form of
@@ -41,7 +41,7 @@
<funcs>
<func>
- <name name="bt" arity="1"/>
+ <name name="bt" arity="1" since=""/>
<fsummary>Stack backtrace for a process.</fsummary>
<desc>
<p>Stack backtrace for a process. Equivalent to
@@ -50,9 +50,9 @@
</func>
<func>
- <name name="c" arity="1"/>
- <name name="c" arity="2"/>
- <name name="c" arity="3"/>
+ <name name="c" arity="1" since=""/>
+ <name name="c" arity="2" since=""/>
+ <name name="c" arity="3" since="OTP 20.0"/>
<fsummary>Compile and load a file or module.</fsummary>
<desc>
<p>Compiles and then purges and loads the code for a module.
@@ -80,7 +80,7 @@
</func>
<func>
- <name name="cd" arity="1"/>
+ <name name="cd" arity="1" since=""/>
<fsummary>Change working directory.</fsummary>
<desc>
<p>Changes working directory to <c><anno>Dir</anno></c>, which can be a
@@ -94,7 +94,16 @@
</func>
<func>
- <name name="flush" arity="0"/>
+ <name name="erlangrc" arity="1" since="OTP 21.0"/>
+ <fsummary>Load an erlang resource file.</fsummary>
+ <desc>
+ <p>Search <c>PathList</c> and load <c>.erlang</c> resource file if
+ found.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="flush" arity="0" since=""/>
<fsummary>Flush any messages sent to the shell.</fsummary>
<desc>
<p>Flushes any messages sent to the shell.</p>
@@ -102,7 +111,7 @@
</func>
<func>
- <name name="help" arity="0"/>
+ <name name="help" arity="0" since=""/>
<fsummary>Help information.</fsummary>
<desc>
<p>Displays help information: all valid shell internal commands,
@@ -111,8 +120,8 @@
</func>
<func>
- <name name="i" arity="0"/>
- <name name="ni" arity="0"/>
+ <name name="i" arity="0" since=""/>
+ <name name="ni" arity="0" since=""/>
<fsummary>System information.</fsummary>
<desc>
<p><c>i/0</c> displays system information, listing
@@ -122,7 +131,7 @@
</func>
<func>
- <name name="i" arity="3"/>
+ <name name="i" arity="3" since=""/>
<fsummary>Information about pid &lt;X.Y.Z&gt;.</fsummary>
<desc>
<p>Displays information about a process, Equivalent to
@@ -132,7 +141,7 @@
</func>
<func>
- <name name="l" arity="1"/>
+ <name name="l" arity="1" since=""/>
<fsummary>Load or reload a module.</fsummary>
<desc>
<p>Purges and loads, or reloads, a module by calling
@@ -145,7 +154,7 @@
</func>
<func>
- <name>lc(Files) -> ok</name>
+ <name since="">lc(Files) -> ok</name>
<fsummary>Compile a list of files.</fsummary>
<type>
<v>Files = [File]</v>
@@ -162,7 +171,7 @@
</func>
<func>
- <name name="lm" arity="0"/>
+ <name name="lm" arity="0" since="OTP 20.0"/>
<fsummary>Loads all modified modules.</fsummary>
<desc>
<p>Reloads all currently loaded modules that have changed on disk (see <c>mm()</c>).
@@ -171,7 +180,7 @@
</func>
<func>
- <name name="ls" arity="0"/>
+ <name name="ls" arity="0" since=""/>
<fsummary>List files in the current directory.</fsummary>
<desc>
<p>Lists files in the current directory.</p>
@@ -179,7 +188,7 @@
</func>
<func>
- <name name="ls" arity="1"/>
+ <name name="ls" arity="1" since=""/>
<fsummary>List files in a directory or a single file.</fsummary>
<desc>
<p>Lists files in directory <c><anno>Dir</anno></c> or, if <c>Dir</c>
@@ -188,7 +197,7 @@
</func>
<func>
- <name name="m" arity="0"/>
+ <name name="m" arity="0" since=""/>
<fsummary>Which modules are loaded.</fsummary>
<desc>
<p>Displays information about the loaded modules, including
@@ -197,7 +206,7 @@
</func>
<func>
- <name name="m" arity="1"/>
+ <name name="m" arity="1" since=""/>
<fsummary>Information about a module.</fsummary>
<desc>
<p>Displays information about <c><anno>Module</anno></c>.</p>
@@ -205,7 +214,7 @@
</func>
<func>
- <name name="mm" arity="0"/>
+ <name name="mm" arity="0" since="OTP 20.0"/>
<fsummary>Lists all modified modules.</fsummary>
<desc>
<p>Lists all modified modules. Shorthand for
@@ -214,7 +223,7 @@
</func>
<func>
- <name name="memory" arity="0"/>
+ <name name="memory" arity="0" since=""/>
<fsummary>Memory allocation information.</fsummary>
<desc>
<p>Memory allocation information. Equivalent to
@@ -223,8 +232,8 @@
</func>
<func>
- <name name="memory" arity="1" clause_i="1"/>
- <name name="memory" arity="1" clause_i="2"/>
+ <name name="memory" arity="1" clause_i="1" since=""/>
+ <name name="memory" arity="1" clause_i="2" since=""/>
<fsummary>Memory allocation information.</fsummary>
<desc>
<p>Memory allocation information. Equivalent to
@@ -233,8 +242,8 @@
</func>
<func>
- <name name="nc" arity="1"/>
- <name name="nc" arity="2"/>
+ <name name="nc" arity="1" since=""/>
+ <name name="nc" arity="2" since=""/>
<fsummary>Compile and load code in a file on all nodes.</fsummary>
<desc>
<p>Compiles and then loads the code for a file on all nodes.
@@ -246,7 +255,7 @@ compile:file(<anno>File</anno>, <anno>Options</anno> ++ [report_errors, report_w
</func>
<func>
- <name name="nl" arity="1"/>
+ <name name="nl" arity="1" since=""/>
<fsummary>Load module on all nodes.</fsummary>
<desc>
<p>Loads <c><anno>Module</anno></c> on all nodes.</p>
@@ -254,7 +263,7 @@ compile:file(<anno>File</anno>, <anno>Options</anno> ++ [report_errors, report_w
</func>
<func>
- <name name="pid" arity="3"/>
+ <name name="pid" arity="3" since=""/>
<fsummary>Convert <c>X,Y,Z</c> to a pid.</fsummary>
<desc>
<p>Converts <c><anno>X</anno></c>, <c><anno>Y</anno></c>,
@@ -264,7 +273,7 @@ compile:file(<anno>File</anno>, <anno>Options</anno> ++ [report_errors, report_w
</func>
<func>
- <name name="pwd" arity="0"/>
+ <name name="pwd" arity="0" since=""/>
<fsummary>Print working directory.</fsummary>
<desc>
<p>Prints the name of the working directory.</p>
@@ -272,7 +281,7 @@ compile:file(<anno>File</anno>, <anno>Options</anno> ++ [report_errors, report_w
</func>
<func>
- <name name="q" arity="0"/>
+ <name name="q" arity="0" since=""/>
<fsummary>Quit - shorthand for <c>init:stop()</c>.</fsummary>
<desc>
<p>This function is shorthand for <c>init:stop()</c>, that is,
@@ -281,8 +290,8 @@ compile:file(<anno>File</anno>, <anno>Options</anno> ++ [report_errors, report_w
</func>
<func>
- <name name="regs" arity="0"/>
- <name name="nregs" arity="0"/>
+ <name name="regs" arity="0" since=""/>
+ <name name="nregs" arity="0" since=""/>
<fsummary>Information about registered processes.</fsummary>
<desc>
<p><c>regs/0</c> displays information about all registered
@@ -292,7 +301,7 @@ compile:file(<anno>File</anno>, <anno>Options</anno> ++ [report_errors, report_w
</func>
<func>
- <name name="uptime" arity="0"/>
+ <name name="uptime" arity="0" since="OTP 18.0"/>
<fsummary>Print node uptime.</fsummary>
<desc>
<p>Prints the node uptime (as specified by
@@ -301,7 +310,7 @@ compile:file(<anno>File</anno>, <anno>Options</anno> ++ [report_errors, report_w
</func>
<func>
- <name>xm(ModSpec) -> void()</name>
+ <name since="">xm(ModSpec) -> void()</name>
<fsummary>Cross-reference check a module.</fsummary>
<type>
<v>ModSpec = Module | Filename</v>
@@ -316,7 +325,7 @@ compile:file(<anno>File</anno>, <anno>Options</anno> ++ [report_errors, report_w
</func>
<func>
- <name>y(File) -> YeccRet</name>
+ <name since="">y(File) -> YeccRet</name>
<fsummary>Generate an LALR-1 parser.</fsummary>
<type>
<v>File = name()</v>
@@ -335,7 +344,7 @@ yecc:file(File)</code>
</func>
<func>
- <name>y(File, Options) -> YeccRet</name>
+ <name since="">y(File, Options) -> YeccRet</name>
<fsummary>Generate an LALR-1 parser.</fsummary>
<type>
<v>File = name()</v>
diff --git a/lib/stdlib/doc/src/calendar.xml b/lib/stdlib/doc/src/calendar.xml
index 65b3edcdf6..6308420c52 100644
--- a/lib/stdlib/doc/src/calendar.xml
+++ b/lib/stdlib/doc/src/calendar.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -28,7 +28,7 @@
<date>1996-11-05</date>
<rev>B</rev>
</header>
- <module>calendar</module>
+ <module since="">calendar</module>
<modulesummary>Local and universal time, day of the week, date and time
conversions.</modulesummary>
<description>
@@ -128,8 +128,8 @@
<funcs>
<func>
- <name name="date_to_gregorian_days" arity="1"/>
- <name name="date_to_gregorian_days" arity="3"/>
+ <name name="date_to_gregorian_days" arity="1" since=""/>
+ <name name="date_to_gregorian_days" arity="3" since=""/>
<fsummary>Compute the number of days from year 0 up to the specified
date.</fsummary>
<type variable="Date" name_i="1"/>
@@ -143,7 +143,7 @@
</func>
<func>
- <name name="datetime_to_gregorian_seconds" arity="1"/>
+ <name name="datetime_to_gregorian_seconds" arity="1" since=""/>
<fsummary>Compute the number of seconds from year 0 up to the specified
date and time.</fsummary>
<desc>
@@ -153,8 +153,8 @@
</func>
<func>
- <name name="day_of_the_week" arity="1"/>
- <name name="day_of_the_week" arity="3"/>
+ <name name="day_of_the_week" arity="1" since=""/>
+ <name name="day_of_the_week" arity="3" since=""/>
<fsummary>Compute the day of the week.</fsummary>
<type variable="Date" name_i="1"/>
<type variable="Year"/>
@@ -169,7 +169,7 @@
</func>
<func>
- <name name="gregorian_days_to_date" arity="1"/>
+ <name name="gregorian_days_to_date" arity="1" since=""/>
<fsummary>Compute the date from the number of gregorian days.</fsummary>
<desc>
<p>Computes the date from the specified number of gregorian days.</p>
@@ -177,7 +177,7 @@
</func>
<func>
- <name name="gregorian_seconds_to_datetime" arity="1"/>
+ <name name="gregorian_seconds_to_datetime" arity="1" since=""/>
<fsummary>Compute the date and time from the number of gregorian seconds.
</fsummary>
<desc>
@@ -187,7 +187,7 @@
</func>
<func>
- <name name="is_leap_year" arity="1"/>
+ <name name="is_leap_year" arity="1" since=""/>
<fsummary>Check if the year is a leap year.</fsummary>
<desc>
<p>Checks if the specified year is a leap year.</p>
@@ -195,7 +195,7 @@
</func>
<func>
- <name name="iso_week_number" arity="0"/>
+ <name name="iso_week_number" arity="0" since="OTP R14B02"/>
<fsummary>Compute the ISO week number for the actual date.</fsummary>
<desc>
<p>Returns tuple <c>{Year, WeekNum}</c> representing
@@ -206,7 +206,7 @@
</func>
<func>
- <name name="iso_week_number" arity="1"/>
+ <name name="iso_week_number" arity="1" since="OTP R14B02"/>
<fsummary>Compute the ISO week number for the specified date.</fsummary>
<desc>
<p>Returns tuple <c>{Year, WeekNum}</c> representing
@@ -215,7 +215,7 @@
</func>
<func>
- <name name="last_day_of_the_month" arity="2"/>
+ <name name="last_day_of_the_month" arity="2" since=""/>
<fsummary>Compute the number of days in a month.</fsummary>
<desc>
<p>Computes the number of days in a month.</p>
@@ -223,7 +223,7 @@
</func>
<func>
- <name name="local_time" arity="0"/>
+ <name name="local_time" arity="0" since=""/>
<fsummary>Compute local time.</fsummary>
<desc>
<p>Returns the local time reported by
@@ -232,7 +232,7 @@
</func>
<func>
- <name name="local_time_to_universal_time" arity="1"/>
+ <name name="local_time_to_universal_time" arity="1" since=""/>
<fsummary>Convert from local time to universal time (deprecated).
</fsummary>
<desc>
@@ -253,7 +253,7 @@
</func>
<func>
- <name name="local_time_to_universal_time_dst" arity="1"/>
+ <name name="local_time_to_universal_time_dst" arity="1" since=""/>
<fsummary>Convert from local time to universal time(s).</fsummary>
<desc>
<p>Converts from local time to Universal Coordinated Time (UTC).
@@ -285,7 +285,7 @@
</func>
<func>
- <name name="now_to_datetime" arity="1"/>
+ <name name="now_to_datetime" arity="1" since=""/>
<fsummary>Convert now to date and time.</fsummary>
<desc>
<p>Returns Universal Coordinated Time (UTC)
@@ -296,7 +296,7 @@
</func>
<func>
- <name name="now_to_local_time" arity="1"/>
+ <name name="now_to_local_time" arity="1" since=""/>
<fsummary>Convert now to local date and time.</fsummary>
<desc>
<p>Returns local date and time converted from the return value from
@@ -306,7 +306,7 @@
</func>
<func>
- <name name="now_to_universal_time" arity="1"/>
+ <name name="now_to_universal_time" arity="1" since=""/>
<fsummary>Convert now to date and time.</fsummary>
<desc>
<p>Returns Universal Coordinated Time (UTC)
@@ -317,7 +317,33 @@
</func>
<func>
- <name name="seconds_to_daystime" arity="1"/>
+ <name name="rfc3339_to_system_time" arity="1" since="OTP 21.0"/>
+ <name name="rfc3339_to_system_time" arity="2" since="OTP 21.0"/>
+ <fsummary>Convert from RFC 3339 timestamp to system time.</fsummary>
+ <type name="rfc3339_string"/>
+ <type name="rfc3339_time_unit"/>
+ <desc>
+ <p>Converts an RFC 3339 timestamp into system time. The data format
+ of RFC 3339 timestamps is described by
+ <url href="https://www.ietf.org/rfc/rfc3339.txt">RFC 3339</url>.</p>
+ <p>Valid option:</p>
+ <taglist>
+ <tag><c>{unit, Unit}</c></tag>
+ <item><p>The time unit of the return value.
+ The default is <c>second</c>.</p>
+ </item>
+ </taglist>
+ <pre>
+1> <input>calendar:rfc3339_to_system_time("2018-02-01T16:17:58+01:00").</input>
+1517498278
+2> <input>calendar:rfc3339_to_system_time("2018-02-01 15:18:02.088Z",
+ [{unit, nanosecond}]).</input>
+1517498282088000000</pre>
+ </desc>
+ </func>
+
+ <func>
+ <name name="seconds_to_daystime" arity="1" since=""/>
<fsummary>Compute days and time from seconds.</fsummary>
<desc>
<p>Converts a specified number of seconds into days, hours, minutes,
@@ -328,7 +354,7 @@
</func>
<func>
- <name name="seconds_to_time" arity="1"/>
+ <name name="seconds_to_time" arity="1" since=""/>
<fsummary>Compute time from seconds.</fsummary>
<type name="secs_per_day"/>
<desc>
@@ -339,7 +365,76 @@
</func>
<func>
- <name name="time_difference" arity="2"/>
+ <name name="system_time_to_local_time" arity="2" since="OTP 21.0"/>
+ <fsummary>Convert system time to local date and time.</fsummary>
+ <desc>
+ <p>Converts a specified system time into local date and time.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="system_time_to_rfc3339" arity="1" since="OTP 21.0"/>
+ <name name="system_time_to_rfc3339" arity="2" since="OTP 21.0"/>
+ <fsummary>Convert from system to RFC 3339 timestamp.</fsummary>
+ <type name="offset"/>
+ <type name="rfc3339_string"/>
+ <type name="rfc3339_time_unit"/>
+ <desc>
+ <p>Converts a system time into an RFC 3339 timestamp. The data format
+ of RFC 3339 timestamps is described by
+ <url href="https://www.ietf.org/rfc/rfc3339.txt">RFC 3339</url>.
+ The data format of offsets is also described by RFC 3339.</p>
+ <p>Valid options:</p>
+ <taglist>
+ <tag><c>{offset, Offset}</c></tag>
+ <item><p>The offset, either a string or an integer, to be
+ included in the formatted string.
+ An empty string, which is the default, is interpreted
+ as local time. A non-empty string is included as is.
+ The time unit of the integer is the same as the one
+ of <c><anno>Time</anno></c>.</p>
+ </item>
+ <tag><c>{time_designator, Character}</c></tag>
+ <item><p>The character used as time designator, that is,
+ the date and time separator. The default is <c>$T</c>.</p>
+ </item>
+ <tag><c>{unit, Unit}</c></tag>
+ <item><p>The time unit of <c><anno>Time</anno></c>. The
+ default is <c>second</c>. If some other unit is given
+ (<c>millisecond</c>, <c>microsecond</c>, or
+ <c>nanosecond</c>), the formatted string includes a
+ fraction of a second. The number of fractional second
+ digits is three, six, or nine depending on what time unit
+ is chosen. Notice that trailing zeros are not removed from
+ the fraction.
+ </p>
+ </item>
+ </taglist>
+ <pre>
+1> <input>calendar:system_time_to_rfc3339(erlang:system_time(second)).</input>
+"2018-04-23T14:56:28+02:00"
+2> <input>calendar:system_time_to_rfc3339(erlang:system_time(second),
+ [{offset, "-02:00"}]).</input>
+"2018-04-23T10:56:52-02:00"
+3> <input>calendar:system_time_to_rfc3339(erlang:system_time(second),
+ [{offset, -7200}]).</input>
+"2018-04-23T10:57:05-02:00"
+4> <input>calendar:system_time_to_rfc3339(erlang:system_time(millisecond),
+ [{unit, millisecond}, {time_designator, $\s}, {offset, "Z"}]).</input>
+"2018-04-23 12:57:20.482Z"</pre>
+ </desc>
+ </func>
+
+ <func>
+ <name name="system_time_to_universal_time" arity="2" since="OTP 21.0"/>
+ <fsummary>Convert system time to universal date and time.</fsummary>
+ <desc>
+ <p>Converts a specified system time into universal date and time.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="time_difference" arity="2" since=""/>
<fsummary>Compute the difference between two times (deprecated).
</fsummary>
<desc>
@@ -354,7 +449,7 @@
</func>
<func>
- <name name="time_to_seconds" arity="1"/>
+ <name name="time_to_seconds" arity="1" since=""/>
<fsummary>Compute the number of seconds since midnight up to the
specified time.</fsummary>
<type name="secs_per_day"/>
@@ -365,7 +460,7 @@
</func>
<func>
- <name name="universal_time" arity="0"/>
+ <name name="universal_time" arity="0" since=""/>
<fsummary>Compute universal time.</fsummary>
<desc>
<p>Returns the Universal Coordinated Time (UTC)
@@ -375,7 +470,7 @@
</func>
<func>
- <name name="universal_time_to_local_time" arity="1"/>
+ <name name="universal_time_to_local_time" arity="1" since=""/>
<fsummary>Convert from universal time to local time.</fsummary>
<desc>
<p>Converts from Universal Coordinated Time (UTC) to local time.
@@ -385,8 +480,8 @@
</func>
<func>
- <name name="valid_date" arity="1"/>
- <name name="valid_date" arity="3"/>
+ <name name="valid_date" arity="1" since=""/>
+ <name name="valid_date" arity="3" since=""/>
<fsummary>Check if a date is valid</fsummary>
<type variable="Date" name_i="1"/>
<type variable="Year"/>
@@ -418,7 +513,7 @@
<title>Date and Time Source</title>
<p>Local time is obtained from the Erlang BIF <c>localtime/0</c>.
Universal time is computed from the BIF <c>universaltime/0</c>.</p>
- <p>The following fapply:</p>
+ <p>The following apply:</p>
<list type="bulleted">
<item>There are 86400 seconds in a day.</item>
<item>There are 365 days in an ordinary year.</item>
diff --git a/lib/stdlib/doc/src/dets.xml b/lib/stdlib/doc/src/dets.xml
index eb6e32aecf..8b9502a3b1 100644
--- a/lib/stdlib/doc/src/dets.xml
+++ b/lib/stdlib/doc/src/dets.xml
@@ -32,7 +32,7 @@
<rev>B</rev>
<file>dets.xml</file>
</header>
- <module>dets</module>
+ <module since="">dets</module>
<modulesummary>A disk-based term storage.</modulesummary>
<description>
<p>This module provides a term storage on file. The
@@ -188,7 +188,7 @@
<funcs>
<func>
- <name name="all" arity="0"/>
+ <name name="all" arity="0" since=""/>
<fsummary>Return a list of the names of all open Dets tables on
this node.</fsummary>
<desc>
@@ -197,7 +197,7 @@
</func>
<func>
- <name name="bchunk" arity="2"/>
+ <name name="bchunk" arity="2" since=""/>
<fsummary>Return a chunk of objects stored in a Dets table.
</fsummary>
<desc>
@@ -227,7 +227,7 @@
</func>
<func>
- <name name="close" arity="1"/>
+ <name name="close" arity="1" since=""/>
<fsummary>Close a Dets table.</fsummary>
<desc>
<p>Closes a table. Only processes that have opened a table are
@@ -239,7 +239,7 @@
</func>
<func>
- <name name="delete" arity="2"/>
+ <name name="delete" arity="2" since=""/>
<fsummary>Delete all objects with a specified key from a Dets
table.</fsummary>
<desc>
@@ -249,7 +249,7 @@
</func>
<func>
- <name name="delete_all_objects" arity="1"/>
+ <name name="delete_all_objects" arity="1" since=""/>
<fsummary>Delete all objects from a Dets table.</fsummary>
<desc>
<p>Deletes all objects from a table in almost constant time.
@@ -259,7 +259,7 @@
</func>
<func>
- <name name="delete_object" arity="2"/>
+ <name name="delete_object" arity="2" since=""/>
<fsummary>Delete a specified object from a Dets table.</fsummary>
<desc>
<p>Deletes all instances of a specified object from a table. If a
@@ -270,7 +270,7 @@
</func>
<func>
- <name name="first" arity="1"/>
+ <name name="first" arity="1" since=""/>
<fsummary>Return the first key stored in a Dets table.</fsummary>
<desc>
<p>Returns the first key stored in table <c><anno>Name</anno></c>
@@ -295,8 +295,8 @@
</func>
<func>
- <name name="foldl" arity="3"/>
- <name name="foldr" arity="3"/>
+ <name name="foldl" arity="3" since=""/>
+ <name name="foldr" arity="3" since=""/>
<fsummary>Fold a function over a Dets table.</fsummary>
<desc>
<p>Calls <c><anno>Function</anno></c> on successive elements of
@@ -309,7 +309,7 @@
</func>
<func>
- <name name="from_ets" arity="2"/>
+ <name name="from_ets" arity="2" since=""/>
<fsummary>Replace the objects of a Dets table with the objects
of an ETS table.</fsummary>
<desc>
@@ -322,7 +322,7 @@
</func>
<func>
- <name name="info" arity="1"/>
+ <name name="info" arity="1" since=""/>
<fsummary>Return information about a Dets table.</fsummary>
<desc>
<p>Returns information about table <c><anno>Name</anno></c>
@@ -354,7 +354,7 @@
</func>
<func>
- <name name="info" arity="2"/>
+ <name name="info" arity="2" since=""/>
<fsummary>Return the information associated with a specified item for
a Dets table.</fsummary>
<desc>
@@ -455,8 +455,8 @@
</func>
<func>
- <name name="init_table" arity="2"/>
- <name name="init_table" arity="3"/>
+ <name name="init_table" arity="2" since=""/>
+ <name name="init_table" arity="3" since=""/>
<fsummary>Replace all objects of a Dets table.</fsummary>
<desc>
<p>Replaces the existing objects of table <c><anno>Name</anno></c>
@@ -516,7 +516,7 @@
</func>
<func>
- <name name="insert" arity="2"/>
+ <name name="insert" arity="2" since=""/>
<fsummary>Insert one or more objects into a Dets table.</fsummary>
<desc>
<p>Inserts one or more objects into the table <c><anno>Name</anno></c>.
@@ -527,7 +527,7 @@
</func>
<func>
- <name name="insert_new" arity="2"/>
+ <name name="insert_new" arity="2" since=""/>
<fsummary>Insert one or more objects into a Dets table.</fsummary>
<desc>
<p>Inserts one or more objects into table <c><anno>Name</anno></c>.
@@ -539,7 +539,7 @@
</func>
<func>
- <name name="is_compatible_bchunk_format" arity="2"/>
+ <name name="is_compatible_bchunk_format" arity="2" since=""/>
<fsummary>Test compatibility of chunk data of a table.</fsummary>
<desc>
<p>Returns <c>true</c> if it would be possible to initialize
@@ -554,7 +554,7 @@
</func>
<func>
- <name name="is_dets_file" arity="1"/>
+ <name name="is_dets_file" arity="1" since=""/>
<fsummary>Test for a Dets table.</fsummary>
<desc>
<p>Returns <c>true</c> if file <c><anno>Filename</anno></c>
@@ -563,7 +563,7 @@
</func>
<func>
- <name name="lookup" arity="2"/>
+ <name name="lookup" arity="2" since=""/>
<fsummary>Return all objects with a specified key stored in a
Dets table.</fsummary>
<desc>
@@ -590,7 +590,7 @@ ok
</func>
<func>
- <name name="match" arity="1"/>
+ <name name="match" arity="1" since=""/>
<fsummary>Match a chunk of objects stored in a Dets table and
return a list of variable bindings.</fsummary>
<desc>
@@ -606,7 +606,7 @@ ok
</func>
<func>
- <name name="match" arity="2"/>
+ <name name="match" arity="2" since=""/>
<fsummary>Match the objects stored in a Dets table and return a
list of variable bindings.</fsummary>
<desc>
@@ -622,7 +622,7 @@ ok
</func>
<func>
- <name name="match" arity="3"/>
+ <name name="match" arity="3" since=""/>
<fsummary>Match the first chunk of objects stored in a Dets table
and return a list of variable bindings.</fsummary>
<desc>
@@ -654,7 +654,7 @@ ok
</func>
<func>
- <name name="match_delete" arity="2"/>
+ <name name="match_delete" arity="2" since=""/>
<fsummary>Delete all objects that match a given pattern from a
Dets table.</fsummary>
<desc>
@@ -667,7 +667,7 @@ ok
</func>
<func>
- <name name="match_object" arity="1"/>
+ <name name="match_object" arity="1" since=""/>
<fsummary>Match a chunk of objects stored in a Dets table and
return a list of objects.</fsummary>
<desc>
@@ -683,7 +683,7 @@ ok
</func>
<func>
- <name name="match_object" arity="2"/>
+ <name name="match_object" arity="2" since=""/>
<fsummary>Match the objects stored in a Dets table and return
a list of objects.</fsummary>
<desc>
@@ -702,7 +702,7 @@ ok
</func>
<func>
- <name name="match_object" arity="3"/>
+ <name name="match_object" arity="3" since=""/>
<fsummary>Match the first chunk of objects stored in a Dets table
and return a list of objects.</fsummary>
<desc>
@@ -735,7 +735,7 @@ ok
</func>
<func>
- <name name="member" arity="2"/>
+ <name name="member" arity="2" since=""/>
<fsummary>Test for occurrence of a key in a Dets table.</fsummary>
<desc>
<p>Works like <seealso marker="#lookup/2"><c>lookup/2</c></seealso>,
@@ -746,7 +746,7 @@ ok
</func>
<func>
- <name name="next" arity="2"/>
+ <name name="next" arity="2" since=""/>
<fsummary>Return the next key in a Dets table.</fsummary>
<desc>
<p>Returns either the key following <c><anno>Key1</anno></c> in table
@@ -760,7 +760,7 @@ ok
</func>
<func>
- <name name="open_file" arity="1"/>
+ <name name="open_file" arity="1" since=""/>
<fsummary>Open an existing Dets table.</fsummary>
<desc>
<p>Opens an existing table. If the table is not properly closed,
@@ -770,7 +770,7 @@ ok
</func>
<func>
- <name name="open_file" arity="2"/>
+ <name name="open_file" arity="2" since=""/>
<fsummary>Open a Dets table.</fsummary>
<desc>
<p>Opens a table. An empty Dets table is created if no file
@@ -872,7 +872,7 @@ ok
</func>
<func>
- <name name="pid2name" arity="1"/>
+ <name name="pid2name" arity="1" since=""/>
<fsummary>Return the name of the Dets table handled by a pid.</fsummary>
<desc>
<p>Returns the table name given the pid of a process
@@ -883,7 +883,7 @@ ok
</func>
<func>
- <name name="repair_continuation" arity="2"/>
+ <name name="repair_continuation" arity="2" since=""/>
<fsummary>Repair a continuation from <c>select/1</c> or <c>select/3</c>.
</fsummary>
<desc>
@@ -917,7 +917,7 @@ ok
</func>
<func>
- <name name="safe_fixtable" arity="2"/>
+ <name name="safe_fixtable" arity="2" since=""/>
<fsummary>Fix a Dets table for safe traversal.</fsummary>
<desc>
<p>If <c><anno>Fix</anno></c> is <c>true</c>, table
@@ -945,7 +945,7 @@ ok
</func>
<func>
- <name name="select" arity="1"/>
+ <name name="select" arity="1" since=""/>
<fsummary>Apply a match specification to some objects stored in a
Dets table.</fsummary>
<desc>
@@ -962,7 +962,7 @@ ok
</func>
<func>
- <name name="select" arity="2"/>
+ <name name="select" arity="2" since=""/>
<fsummary>Apply a match specification to all objects stored in a
Dets table.</fsummary>
<desc>
@@ -984,7 +984,7 @@ ok
</func>
<func>
- <name name="select" arity="3"/>
+ <name name="select" arity="3" since=""/>
<fsummary>Apply a match specification to the first chunk of objects
stored in a Dets table.</fsummary>
<desc>
@@ -1019,7 +1019,7 @@ ok
</func>
<func>
- <name name="select_delete" arity="2"/>
+ <name name="select_delete" arity="2" since=""/>
<fsummary>Delete all objects that match a given pattern from a
Dets table.</fsummary>
<desc>
@@ -1036,7 +1036,7 @@ ok
</func>
<func>
- <name name="slot" arity="2"/>
+ <name name="slot" arity="2" since=""/>
<fsummary>Return the list of objects associated with a slot of a
Dets table.</fsummary>
<desc>
@@ -1049,7 +1049,7 @@ ok
</func>
<func>
- <name name="sync" arity="1"/>
+ <name name="sync" arity="1" since=""/>
<fsummary>Ensure that all updates made to a Dets table are written
to disk.</fsummary>
<desc>
@@ -1064,8 +1064,8 @@ ok
</func>
<func>
- <name name="table" arity="1"/>
- <name name="table" arity="2"/>
+ <name name="table" arity="1" since=""/>
+ <name name="table" arity="2" since=""/>
<fsummary>Return a QLC query handle.</fsummary>
<desc>
<p>Returns a Query List
@@ -1090,8 +1090,8 @@ ok
</item>
<item>
<p><c>select</c> - The table is traversed by calling
- <seealso marker="dets:select/3"><c>dets:select/3</c></seealso> and
- <seealso marker="dets:select/1"><c>dets:select/1</c></seealso>.
+ <seealso marker="dets#select/3"><c>dets:select/3</c></seealso> and
+ <seealso marker="dets#select/1"><c>dets:select/1</c></seealso>.
Option <c>n_objects</c> determines the number of objects
returned (the third argument of <c>select/3</c>). The
match specification (the second argument of
@@ -1140,7 +1140,7 @@ true</pre>
</func>
<func>
- <name name="to_ets" arity="2"/>
+ <name name="to_ets" arity="2" since=""/>
<fsummary>Insert all objects of a Dets table into an ETS
table.</fsummary>
<desc>
@@ -1153,7 +1153,7 @@ true</pre>
</func>
<func>
- <name name="traverse" arity="2"/>
+ <name name="traverse" arity="2" since=""/>
<fsummary>Apply a function to all or some objects stored in a Dets
table.</fsummary>
<desc>
@@ -1192,7 +1192,7 @@ fun(X) -> {continue, X} end.</pre>
</func>
<func>
- <name name="update_counter" arity="3"/>
+ <name name="update_counter" arity="3" since=""/>
<fsummary>Update a counter object stored in a Dets table.
</fsummary>
<desc>
diff --git a/lib/stdlib/doc/src/dict.xml b/lib/stdlib/doc/src/dict.xml
index c229a18721..95a98cef12 100644
--- a/lib/stdlib/doc/src/dict.xml
+++ b/lib/stdlib/doc/src/dict.xml
@@ -28,7 +28,7 @@
<date>1997-01-15</date>
<rev>B</rev>
</header>
- <module>dict</module>
+ <module since="">dict</module>
<modulesummary>Key-value dictionary.</modulesummary>
<description>
<p>This module provides a <c>Key</c>-<c>Value</c> dictionary.
@@ -55,7 +55,7 @@
<funcs>
<func>
- <name name="append" arity="3"/>
+ <name name="append" arity="3" since=""/>
<fsummary>Append a value to keys in a dictionary.</fsummary>
<desc>
<p>Appends a new <c><anno>Value</anno></c> to the current list
@@ -65,7 +65,7 @@
</func>
<func>
- <name name="append_list" arity="3"/>
+ <name name="append_list" arity="3" since=""/>
<fsummary>Append new values to keys in a dictionary.</fsummary>
<desc>
<p>Appends a list of values <c><anno>ValList</anno></c> to
@@ -77,7 +77,7 @@
</func>
<func>
- <name name="erase" arity="2"/>
+ <name name="erase" arity="2" since=""/>
<fsummary>Erase a key from a dictionary.</fsummary>
<desc>
<p>Erases all items with a given key from a dictionary.</p>
@@ -85,7 +85,7 @@
</func>
<func>
- <name name="fetch" arity="2"/>
+ <name name="fetch" arity="2" since=""/>
<fsummary>Look up values in a dictionary.</fsummary>
<desc>
<p>Returns the value associated with <c><anno>Key</anno></c>
@@ -98,7 +98,7 @@
</func>
<func>
- <name name="fetch_keys" arity="1"/>
+ <name name="fetch_keys" arity="1" since=""/>
<fsummary>Return all keys in a dictionary.</fsummary>
<desc>
<p>Returns a list of all keys in dictionary <c>Dict</c>.</p>
@@ -106,7 +106,7 @@
</func>
<func>
- <name name="take" arity="2"/>
+ <name name="take" arity="2" since="OTP 20.0"/>
<fsummary>Return value and new dictionary without element with this value.</fsummary>
<desc>
<p>This function returns value from dictionary and a
@@ -116,7 +116,7 @@
</func>
<func>
- <name name="filter" arity="2"/>
+ <name name="filter" arity="2" since=""/>
<fsummary>Select elements that satisfy a predicate.</fsummary>
<desc>
<p><c><anno>Dict2</anno></c> is a dictionary of all keys and values in
@@ -127,7 +127,7 @@
</func>
<func>
- <name name="find" arity="2"/>
+ <name name="find" arity="2" since=""/>
<fsummary>Search for a key in a dictionary.</fsummary>
<desc>
<p>Searches for a key in dictionary <c>Dict</c>. Returns
@@ -139,7 +139,7 @@
</func>
<func>
- <name name="fold" arity="3"/>
+ <name name="fold" arity="3" since=""/>
<fsummary>Fold a function over a dictionary.</fsummary>
<desc>
<p>Calls <c><anno>Fun</anno></c> on successive keys and values of
@@ -153,7 +153,7 @@
</func>
<func>
- <name name="from_list" arity="1"/>
+ <name name="from_list" arity="1" since=""/>
<fsummary>Convert a list of pairs to a dictionary.</fsummary>
<desc>
<p>Converts the <c><anno>Key</anno></c>-<c><anno>Value</anno></c> list
@@ -162,7 +162,7 @@
</func>
<func>
- <name name="is_empty" arity="1"/>
+ <name name="is_empty" arity="1" since="OTP 17.0"/>
<fsummary>Return <c>true</c> if the dictionary is empty.</fsummary>
<desc>
<p>Returns <c>true</c> if dictionary <c><anno>Dict</anno></c> has no
@@ -171,7 +171,7 @@
</func>
<func>
- <name name="is_key" arity="2"/>
+ <name name="is_key" arity="2" since=""/>
<fsummary>Test if a key is in a dictionary.</fsummary>
<desc>
<p>Tests if <c><anno>Key</anno></c> is contained in
@@ -180,7 +180,7 @@
</func>
<func>
- <name name="map" arity="2"/>
+ <name name="map" arity="2" since=""/>
<fsummary>Map a function over a dictionary.</fsummary>
<desc>
<p>Calls <c><anno>Fun</anno></c> on successive keys and values
@@ -190,7 +190,7 @@
</func>
<func>
- <name name="merge" arity="3"/>
+ <name name="merge" arity="3" since=""/>
<fsummary>Merge two dictionaries.</fsummary>
<desc>
<p>Merges two dictionaries, <c><anno>Dict1</anno></c> and
@@ -209,7 +209,7 @@ merge(Fun, D1, D2) ->
</func>
<func>
- <name name="new" arity="0"/>
+ <name name="new" arity="0" since=""/>
<fsummary>Create a dictionary.</fsummary>
<desc>
<p>Creates a new dictionary.</p>
@@ -217,7 +217,7 @@ merge(Fun, D1, D2) ->
</func>
<func>
- <name name="size" arity="1"/>
+ <name name="size" arity="1" since=""/>
<fsummary>Return the number of elements in a dictionary.</fsummary>
<desc>
<p>Returns the number of elements in dictionary
@@ -226,7 +226,7 @@ merge(Fun, D1, D2) ->
</func>
<func>
- <name name="store" arity="3"/>
+ <name name="store" arity="3" since=""/>
<fsummary>Store a value in a dictionary.</fsummary>
<desc>
<p>Stores a <c><anno>Key</anno></c>-<c><anno>Value</anno></c> pair in
@@ -237,7 +237,7 @@ merge(Fun, D1, D2) ->
</func>
<func>
- <name name="to_list" arity="1"/>
+ <name name="to_list" arity="1" since=""/>
<fsummary>Convert a dictionary to a list of pairs.</fsummary>
<desc>
<p>Converts dictionary <c>Dict</c> to a list representation.</p>
@@ -245,7 +245,7 @@ merge(Fun, D1, D2) ->
</func>
<func>
- <name name="update" arity="3"/>
+ <name name="update" arity="3" since=""/>
<fsummary>Update a value in a dictionary.</fsummary>
<desc>
<p>Updates a value in a dictionary by calling <c><anno>Fun</anno></c> on
@@ -255,7 +255,7 @@ merge(Fun, D1, D2) ->
</func>
<func>
- <name name="update" arity="4"/>
+ <name name="update" arity="4" since=""/>
<fsummary>Update a value in a dictionary.</fsummary>
<desc>
<p>Updates a value in a dictionary by calling <c><anno>Fun</anno></c> on
@@ -269,7 +269,7 @@ append(Key, Val, D) ->
</func>
<func>
- <name name="update_counter" arity="3"/>
+ <name name="update_counter" arity="3" since=""/>
<fsummary>Increment a value in a dictionary.</fsummary>
<desc>
<p>Adds <c><anno>Increment</anno></c> to the value associated with
diff --git a/lib/stdlib/doc/src/digraph.xml b/lib/stdlib/doc/src/digraph.xml
index db96beed6c..cf2c0844c9 100644
--- a/lib/stdlib/doc/src/digraph.xml
+++ b/lib/stdlib/doc/src/digraph.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,7 +32,7 @@
<rev>C</rev>
<file>digraph.xml</file>
</header>
- <module>digraph</module>
+ <module since="">digraph</module>
<modulesummary>Directed graphs.</modulesummary>
<description>
<p>This module provides a version of labeled
@@ -144,9 +144,9 @@
<funcs>
<func>
- <name name="add_edge" arity="3"/>
- <name name="add_edge" arity="4"/>
- <name name="add_edge" arity="5"/>
+ <name name="add_edge" arity="3" since=""/>
+ <name name="add_edge" arity="4" since=""/>
+ <name name="add_edge" arity="5" since=""/>
<fsummary>Add an edge to a digraph.</fsummary>
<type name="add_edge_err_rsn"/>
<desc>
@@ -183,9 +183,9 @@
</func>
<func>
- <name name="add_vertex" arity="1"/>
- <name name="add_vertex" arity="2"/>
- <name name="add_vertex" arity="3"/>
+ <name name="add_vertex" arity="1" since=""/>
+ <name name="add_vertex" arity="2" since=""/>
+ <name name="add_vertex" arity="3" since=""/>
<fsummary>Add or modify a vertex of a digraph.</fsummary>
<desc>
<p><c>add_vertex/3</c> creates (or modifies) vertex
@@ -204,7 +204,7 @@
</func>
<func>
- <name name="del_edge" arity="2"/>
+ <name name="del_edge" arity="2" since=""/>
<fsummary>Delete an edge from a digraph.</fsummary>
<desc>
<p>Deletes edge <c><anno>E</anno></c> from digraph
@@ -213,7 +213,7 @@
</func>
<func>
- <name name="del_edges" arity="2"/>
+ <name name="del_edges" arity="2" since=""/>
<fsummary>Delete edges from a digraph.</fsummary>
<desc>
<p>Deletes the edges in list <c><anno>Edges</anno></c> from digraph
@@ -222,7 +222,7 @@
</func>
<func>
- <name name="del_path" arity="3"/>
+ <name name="del_path" arity="3" since=""/>
<fsummary>Delete paths from a digraph.</fsummary>
<desc>
<p>Deletes edges from digraph <c><anno>G</anno></c> until there are no
@@ -252,7 +252,7 @@
</func>
<func>
- <name name="del_vertex" arity="2"/>
+ <name name="del_vertex" arity="2" since=""/>
<fsummary>Delete a vertex from a digraph.</fsummary>
<desc>
<p>Deletes vertex <c><anno>V</anno></c> from digraph
@@ -265,7 +265,7 @@
</func>
<func>
- <name name="del_vertices" arity="2"/>
+ <name name="del_vertices" arity="2" since=""/>
<fsummary>Delete vertices from a digraph.</fsummary>
<desc>
<p>Deletes the vertices in list <c><anno>Vertices</anno></c> from
@@ -274,7 +274,7 @@
</func>
<func>
- <name name="delete" arity="1"/>
+ <name name="delete" arity="1" since=""/>
<fsummary>Delete a digraph.</fsummary>
<desc>
<p>Deletes digraph <c><anno>G</anno></c>. This call is important
@@ -285,7 +285,7 @@
</func>
<func>
- <name name="edge" arity="2"/>
+ <name name="edge" arity="2" since=""/>
<fsummary>Return the vertices and the label of an edge of a digraph.
</fsummary>
<desc>
@@ -303,7 +303,7 @@
</func>
<func>
- <name name="edges" arity="1"/>
+ <name name="edges" arity="1" since=""/>
<fsummary>Return all edges of a digraph.</fsummary>
<desc>
<p>Returns a list of all edges of digraph <c><anno>G</anno></c>, in
@@ -312,7 +312,7 @@
</func>
<func>
- <name name="edges" arity="2"/>
+ <name name="edges" arity="2" since=""/>
<fsummary>Return the edges emanating from or incident on a vertex of
a digraph.</fsummary>
<desc>
@@ -324,7 +324,7 @@
</func>
<func>
- <name name="get_cycle" arity="2"/>
+ <name name="get_cycle" arity="2" since=""/>
<fsummary>Find one cycle in a digraph.</fsummary>
<desc>
<p>If a <seealso marker="#simple_cycle">simple cycle</seealso> of
@@ -341,7 +341,7 @@
</func>
<func>
- <name name="get_path" arity="3"/>
+ <name name="get_path" arity="3" since=""/>
<fsummary>Find one path in a digraph.</fsummary>
<desc>
<p>Tries to find
@@ -357,7 +357,7 @@
</func>
<func>
- <name name="get_short_cycle" arity="2"/>
+ <name name="get_short_cycle" arity="2" since=""/>
<fsummary>Find one short cycle in a digraph.</fsummary>
<desc>
<p>Tries to find an as short as possible
@@ -375,7 +375,7 @@
</func>
<func>
- <name name="get_short_path" arity="3"/>
+ <name name="get_short_path" arity="3" since=""/>
<fsummary>Find one short path in a digraph.</fsummary>
<desc>
<p>Tries to find an as short as possible
@@ -392,7 +392,7 @@
</func>
<func>
- <name name="in_degree" arity="2"/>
+ <name name="in_degree" arity="2" since=""/>
<fsummary>Return the in-degree of a vertex of a digraph.</fsummary>
<desc>
<p>Returns the <seealso marker="#in_degree">in-degree</seealso> of
@@ -401,7 +401,7 @@
</func>
<func>
- <name name="in_edges" arity="2"/>
+ <name name="in_edges" arity="2" since=""/>
<fsummary>Return all edges incident on a vertex of a digraph.</fsummary>
<desc>
<p>Returns a list of all
@@ -412,7 +412,7 @@
</func>
<func>
- <name name="in_neighbours" arity="2"/>
+ <name name="in_neighbours" arity="2" since=""/>
<fsummary>Return all in-neighbors of a vertex of a digraph.</fsummary>
<desc>
<p>Returns a list of
@@ -423,7 +423,7 @@
</func>
<func>
- <name name="info" arity="1"/>
+ <name name="info" arity="1" since=""/>
<fsummary>Return information about a digraph.</fsummary>
<type name="d_cyclicity"/>
<type name="d_protection"/>
@@ -453,7 +453,7 @@
</func>
<func>
- <name name="new" arity="0"/>
+ <name name="new" arity="0" since=""/>
<fsummary>Return a protected empty digraph, where cycles are allowed.
</fsummary>
<desc>
@@ -462,7 +462,7 @@
</func>
<func>
- <name name="new" arity="1"/>
+ <name name="new" arity="1" since=""/>
<fsummary>Create a new empty digraph.</fsummary>
<type variable="Type"/>
<type name="d_type"/>
@@ -492,7 +492,7 @@
</func>
<func>
- <name name="no_edges" arity="1"/>
+ <name name="no_edges" arity="1" since=""/>
<fsummary>Return the number of edges of a digraph.</fsummary>
<desc>
<p>Returns the number of edges of digraph <c><anno>G</anno></c>.</p>
@@ -500,7 +500,7 @@
</func>
<func>
- <name name="no_vertices" arity="1"/>
+ <name name="no_vertices" arity="1" since=""/>
<fsummary>Return the number of vertices of a digraph.</fsummary>
<desc>
<p>Returns the number of vertices of digraph <c><anno>G</anno></c>.</p>
@@ -508,7 +508,7 @@
</func>
<func>
- <name name="out_degree" arity="2"/>
+ <name name="out_degree" arity="2" since=""/>
<fsummary>Return the out-degree of a vertex of a digraph.</fsummary>
<desc>
<p>Returns the <seealso marker="#out_degree">out-degree</seealso> of
@@ -517,7 +517,7 @@
</func>
<func>
- <name name="out_edges" arity="2"/>
+ <name name="out_edges" arity="2" since=""/>
<fsummary>Return all edges emanating from a vertex of a digraph.
</fsummary>
<desc>
@@ -529,7 +529,7 @@
</func>
<func>
- <name name="out_neighbours" arity="2"/>
+ <name name="out_neighbours" arity="2" since=""/>
<fsummary>Return all out-neighbors of a vertex of a digraph.</fsummary>
<desc>
<p>Returns a list of
@@ -540,7 +540,7 @@
</func>
<func>
- <name name="vertex" arity="2"/>
+ <name name="vertex" arity="2" since=""/>
<fsummary>Return the label of a vertex of a digraph.</fsummary>
<desc>
<p>Returns <c>{<anno>V</anno>,&nbsp;<anno>Label</anno>}</c>,
@@ -553,7 +553,7 @@
</func>
<func>
- <name name="vertices" arity="1"/>
+ <name name="vertices" arity="1" since=""/>
<fsummary>Return all vertices of a digraph.</fsummary>
<desc>
<p>Returns a list of all vertices of digraph <c><anno>G</anno></c>, in
diff --git a/lib/stdlib/doc/src/digraph_utils.xml b/lib/stdlib/doc/src/digraph_utils.xml
index cb316e5b93..a23b02c6c1 100644
--- a/lib/stdlib/doc/src/digraph_utils.xml
+++ b/lib/stdlib/doc/src/digraph_utils.xml
@@ -32,7 +32,7 @@
<rev>PA1</rev>
<file>digraph_utils.xml</file>
</header>
- <module>digraph_utils</module>
+ <module since="">digraph_utils</module>
<modulesummary>Algorithms for directed graphs.</modulesummary>
<description>
<p>This module provides algorithms based on depth-first traversal of
@@ -154,7 +154,7 @@
<funcs>
<func>
- <name name="arborescence_root" arity="1"/>
+ <name name="arborescence_root" arity="1" since=""/>
<fsummary>Check if a digraph is an arborescence.</fsummary>
<desc>
<p>Returns <c>{yes, <anno>Root</anno>}</c> if <c><anno>Root</anno></c>
@@ -164,7 +164,7 @@
</func>
<func>
- <name name="components" arity="1"/>
+ <name name="components" arity="1" since=""/>
<fsummary>Return the components of a digraph.</fsummary>
<desc>
<p>Returns a list
@@ -177,7 +177,7 @@
</func>
<func>
- <name name="condensation" arity="1"/>
+ <name name="condensation" arity="1" since=""/>
<fsummary>Return a condensed graph of a digraph.</fsummary>
<desc>
<p>Creates a digraph where the vertices are
@@ -202,7 +202,7 @@
</func>
<func>
- <name name="cyclic_strong_components" arity="1"/>
+ <name name="cyclic_strong_components" arity="1" since=""/>
<fsummary>Return the cyclic strong components of a digraph.</fsummary>
<desc>
<p>Returns a list of <seealso marker="#strong_components">strongly
@@ -218,7 +218,7 @@
</func>
<func>
- <name name="is_acyclic" arity="1"/>
+ <name name="is_acyclic" arity="1" since=""/>
<fsummary>Check if a digraph is acyclic.</fsummary>
<desc>
<p>Returns <c>true</c> if and only if digraph
@@ -228,7 +228,7 @@
</func>
<func>
- <name name="is_arborescence" arity="1"/>
+ <name name="is_arborescence" arity="1" since=""/>
<fsummary>Check if a digraph is an arborescence.</fsummary>
<desc>
<p>Returns <c>true</c> if and only if digraph
@@ -238,7 +238,7 @@
</func>
<func>
- <name name="is_tree" arity="1"/>
+ <name name="is_tree" arity="1" since=""/>
<fsummary>Check if a digraph is a tree.</fsummary>
<desc>
<p>Returns <c>true</c> if and only if digraph
@@ -248,7 +248,7 @@
</func>
<func>
- <name name="loop_vertices" arity="1"/>
+ <name name="loop_vertices" arity="1" since=""/>
<fsummary>Return the vertices of a digraph included in some loop.
</fsummary>
<desc>
@@ -258,7 +258,7 @@
</func>
<func>
- <name name="postorder" arity="1"/>
+ <name name="postorder" arity="1" since=""/>
<fsummary>Return the vertices of a digraph in postorder.</fsummary>
<desc>
<p>Returns all vertices of digraph <c><anno>Digraph</anno></c>.
@@ -273,7 +273,7 @@
</func>
<func>
- <name name="preorder" arity="1"/>
+ <name name="preorder" arity="1" since=""/>
<fsummary>Return the vertices of a digraph in preorder.</fsummary>
<desc>
<p>Returns all vertices of digraph <c><anno>Digraph</anno></c>.
@@ -285,7 +285,7 @@
</func>
<func>
- <name name="reachable" arity="2"/>
+ <name name="reachable" arity="2" since=""/>
<fsummary>Return the vertices reachable from some vertices of a digraph.
</fsummary>
<desc>
@@ -300,7 +300,7 @@
</func>
<func>
- <name name="reachable_neighbours" arity="2"/>
+ <name name="reachable_neighbours" arity="2" since=""/>
<fsummary>Return the neighbors reachable from some vertices of a
digraph.</fsummary>
<desc>
@@ -316,7 +316,7 @@
</func>
<func>
- <name name="reaching" arity="2"/>
+ <name name="reaching" arity="2" since=""/>
<fsummary>Return the vertices that reach some vertices of a digraph.
</fsummary>
<desc>
@@ -330,7 +330,7 @@
</func>
<func>
- <name name="reaching_neighbours" arity="2"/>
+ <name name="reaching_neighbours" arity="2" since=""/>
<fsummary>Return the neighbors that reach some vertices of a digraph.
</fsummary>
<desc>
@@ -345,7 +345,7 @@
</func>
<func>
- <name name="strong_components" arity="1"/>
+ <name name="strong_components" arity="1" since=""/>
<fsummary>Return the strong components of a digraph.</fsummary>
<desc>
<p>Returns a list of <seealso marker="#strong_components">strongly
@@ -359,8 +359,8 @@
</func>
<func>
- <name name="subgraph" arity="2"/>
- <name name="subgraph" arity="3"/>
+ <name name="subgraph" arity="2" since=""/>
+ <name name="subgraph" arity="3" since=""/>
<fsummary>Return a subgraph of a digraph.</fsummary>
<desc>
<p>Creates a maximal <seealso marker="#subgraph">subgraph</seealso>
@@ -371,7 +371,7 @@
the default, the type of <c><anno>Digraph</anno></c> is used
for the subgraph as well. Otherwise the option value of <c>type</c>
is used as argument to
- <seealso marker="digraph:new/1"><c>digraph:new/1</c></seealso>.</p>
+ <seealso marker="digraph#new/1"><c>digraph:new/1</c></seealso>.</p>
<p>If the value of option <c>keep_labels</c> is <c>true</c>,
which is the default,
the <seealso marker="#label">labels</seealso> of vertices and edges
@@ -387,7 +387,7 @@
</func>
<func>
- <name name="topsort" arity="1"/>
+ <name name="topsort" arity="1" since=""/>
<fsummary>Return a topological sorting of the vertices of a digraph.
</fsummary>
<desc>
diff --git a/lib/stdlib/doc/src/epp.xml b/lib/stdlib/doc/src/epp.xml
index 1dc0161398..110c1cea2c 100644
--- a/lib/stdlib/doc/src/epp.xml
+++ b/lib/stdlib/doc/src/epp.xml
@@ -32,7 +32,7 @@
<rev>B</rev>
<file>epp.xml</file>
</header>
- <module>epp</module>
+ <module since="">epp</module>
<modulesummary>An Erlang code preprocessor.</modulesummary>
<description>
<p>The Erlang code preprocessor includes functions that are used by the
@@ -76,7 +76,7 @@
<funcs>
<func>
- <name name="close" arity="1"/>
+ <name name="close" arity="1" since=""/>
<fsummary>Close the preprocessing of the file associated with <c>Epp</c>.
</fsummary>
<desc>
@@ -85,7 +85,7 @@
</func>
<func>
- <name name="default_encoding" arity="0"/>
+ <name name="default_encoding" arity="0" since="OTP R16B"/>
<fsummary>Return the default encoding of Erlang source files.</fsummary>
<desc>
<p>Returns the default encoding of Erlang source files.</p>
@@ -93,7 +93,7 @@
</func>
<func>
- <name name="encoding_to_string" arity="1"/>
+ <name name="encoding_to_string" arity="1" since="OTP R16B"/>
<fsummary>Return a string representation of an encoding.</fsummary>
<desc>
<p>Returns a string representation of an encoding. The string
@@ -107,7 +107,7 @@
</func>
<func>
- <name name="format_error" arity="1"/>
+ <name name="format_error" arity="1" since="OTP R14B03"/>
<fsummary>Format an error descriptor.</fsummary>
<desc>
<p>Takes an <c><anno>ErrorDescriptor</anno></c> and returns
@@ -120,10 +120,14 @@
</func>
<func>
- <name name="open" arity="1"/>
+ <name name="open" arity="1" since="OTP 17.0"/>
<fsummary>Open a file for preprocessing.</fsummary>
<desc>
<p>Opens a file for preprocessing.</p>
+ <p>If you want to change the file name of the implicit -file()
+ attributes inserted during preprocessing, you can do with
+ <c>{source_name, <anno>SourceName</anno>}</c>. If unset it will
+ default to the name of the opened file.</p>
<p>If <c>extra</c> is specified in
<c><anno>Options</anno></c>, the return value is
<c>{ok, <anno>Epp</anno>, <anno>Extra</anno>}</c> instead
@@ -132,7 +136,7 @@
</func>
<func>
- <name name="open" arity="2"/>
+ <name name="open" arity="2" since=""/>
<fsummary>Open a file for preprocessing.</fsummary>
<desc>
<p>Equivalent to
@@ -141,7 +145,7 @@
</func>
<func>
- <name name="open" arity="3"/>
+ <name name="open" arity="3" since=""/>
<fsummary>Open a file for preprocessing.</fsummary>
<desc>
<p>Equivalent to <c>epp:open([{name, FileName}, {includes, IncludePath},
@@ -150,7 +154,7 @@
</func>
<func>
- <name name="parse_erl_form" arity="1"/>
+ <name name="parse_erl_form" arity="1" since=""/>
<fsummary>Return the next Erlang form from the opened Erlang source file.
</fsummary>
<type name="warning_info"/>
@@ -163,12 +167,16 @@
</func>
<func>
- <name name="parse_file" arity="2"/>
+ <name name="parse_file" arity="2" since="OTP 17.0"/>
<fsummary>Preprocess and parse an Erlang source file.</fsummary>
<desc>
<p>Preprocesses and parses an Erlang source file.
Notice that tuple <c>{eof, <anno>Line</anno>}</c> returned at the
end of the file is included as a "form".</p>
+ <p>If you want to change the file name of the implicit -file()
+ attributes inserted during preprocessing, you can do with
+ <c>{source_name, <anno>SourceName</anno>}</c>. If unset it will
+ default to the name of the opened file.</p>
<p>If <c>extra</c> is specified in
<c><anno>Options</anno></c>, the return value is
<c>{ok, [<anno>Form</anno>], <anno>Extra</anno>}</c> instead
@@ -177,7 +185,7 @@
</func>
<func>
- <name name="parse_file" arity="3"/>
+ <name name="parse_file" arity="3" since=""/>
<fsummary>Preprocess and parse an Erlang source file.</fsummary>
<desc>
<p>Equivalent to <c>epp:parse_file(FileName, [{includes, IncludePath},
@@ -186,8 +194,8 @@
</func>
<func>
- <name name="read_encoding" arity="1"/>
- <name name="read_encoding" arity="2"/>
+ <name name="read_encoding" arity="1" since="OTP R16B"/>
+ <name name="read_encoding" arity="2" since="OTP R16B"/>
<fsummary>Read the encoding from a file.</fsummary>
<desc>
<p>Read the <seealso marker="#encoding">encoding</seealso> from
@@ -201,8 +209,8 @@
</func>
<func>
- <name name="read_encoding_from_binary" arity="1"/>
- <name name="read_encoding_from_binary" arity="2"/>
+ <name name="read_encoding_from_binary" arity="1" since="OTP R16B"/>
+ <name name="read_encoding_from_binary" arity="2" since="OTP R16B"/>
<fsummary>Read the encoding from a binary.</fsummary>
<desc>
<p>Read the <seealso marker="#encoding">encoding</seealso> from
@@ -216,7 +224,7 @@
</func>
<func>
- <name name="set_encoding" arity="1"/>
+ <name name="set_encoding" arity="1" since="OTP R16B"/>
<fsummary>Read and set the encoding of an I/O device.</fsummary>
<desc>
<p>Reads the <seealso marker="#encoding">encoding</seealso> from
@@ -231,7 +239,7 @@
</func>
<func>
- <name name="set_encoding" arity="2"/>
+ <name name="set_encoding" arity="2" since="OTP 17.0"/>
<fsummary>Read and set the encoding of an I/O device.</fsummary>
<desc>
<p>Reads the <seealso marker="#encoding">encoding</seealso> from
diff --git a/lib/stdlib/doc/src/erl_anno.xml b/lib/stdlib/doc/src/erl_anno.xml
index f316f63d98..dff93619ab 100644
--- a/lib/stdlib/doc/src/erl_anno.xml
+++ b/lib/stdlib/doc/src/erl_anno.xml
@@ -34,7 +34,7 @@
<rev>A</rev>
<file>erl_anno.xml</file>
</header>
- <module>erl_anno</module>
+ <module since="OTP 18.0">erl_anno</module>
<modulesummary>Abstract datatype for the annotations of the Erlang Compiler.
</modulesummary>
@@ -135,7 +135,7 @@
<funcs>
<func>
- <name name="column" arity="1"/>
+ <name name="column" arity="1" since="OTP 18.0"/>
<fsummary>Return the column.</fsummary>
<type name="column"></type>
<desc>
@@ -144,7 +144,7 @@
</func>
<func>
- <name name="end_location" arity="1"/>
+ <name name="end_location" arity="1" since="OTP 18.0"/>
<fsummary>Return the end location of the text.</fsummary>
<type name="location"></type>
<desc>
@@ -155,7 +155,7 @@
</func>
<func>
- <name name="file" arity="1"/>
+ <name name="file" arity="1" since="OTP 18.0"/>
<fsummary>Return the filename.</fsummary>
<type name="filename"></type>
<desc>
@@ -165,7 +165,7 @@
</func>
<func>
- <name name="from_term" arity="1"/>
+ <name name="from_term" arity="1" since="OTP 18.0"/>
<fsummary>Return annotations given a term.</fsummary>
<desc>
<p>Returns annotations with representation <anno>Term</anno>.</p>
@@ -174,7 +174,7 @@
</func>
<func>
- <name name="generated" arity="1"/>
+ <name name="generated" arity="1" since="OTP 18.0"/>
<fsummary>Return the generated Boolean.</fsummary>
<type name="generated"></type>
<desc>
@@ -185,7 +185,7 @@
</func>
<func>
- <name name="is_anno" arity="1"/>
+ <name name="is_anno" arity="1" since="OTP 18.0"/>
<fsummary>Test for a collection of annotations.</fsummary>
<desc>
<p>Returns <c>true</c> if <anno>Term</anno> is a collection of
@@ -194,7 +194,7 @@
</func>
<func>
- <name name="line" arity="1"/>
+ <name name="line" arity="1" since="OTP 18.0"/>
<fsummary>Return the line.</fsummary>
<type name="line"></type>
<desc>
@@ -203,7 +203,7 @@
</func>
<func>
- <name name="location" arity="1"/>
+ <name name="location" arity="1" since="OTP 18.0"/>
<fsummary>Return the location.</fsummary>
<type name="location"></type>
<desc>
@@ -212,7 +212,7 @@
</func>
<func>
- <name name="new" arity="1"/>
+ <name name="new" arity="1" since="OTP 18.0"/>
<fsummary>Create a new collection of annotations.</fsummary>
<type name="location"></type>
<desc>
@@ -221,7 +221,7 @@
</func>
<func>
- <name name="set_file" arity="2"/>
+ <name name="set_file" arity="2" since="OTP 18.0"/>
<fsummary>Modify the filename.</fsummary>
<type name="filename"></type>
<desc>
@@ -230,7 +230,7 @@
</func>
<func>
- <name name="set_generated" arity="2"/>
+ <name name="set_generated" arity="2" since="OTP 18.0"/>
<fsummary>Modify the generated marker.</fsummary>
<type name="generated"></type>
<desc>
@@ -240,7 +240,7 @@
</func>
<func>
- <name name="set_line" arity="2"/>
+ <name name="set_line" arity="2" since="OTP 18.0"/>
<fsummary>Modify the line.</fsummary>
<type name="line"></type>
<desc>
@@ -249,7 +249,7 @@
</func>
<func>
- <name name="set_location" arity="2"/>
+ <name name="set_location" arity="2" since="OTP 18.0"/>
<fsummary>Modify the location.</fsummary>
<type name="location"></type>
<desc>
@@ -258,7 +258,7 @@
</func>
<func>
- <name name="set_record" arity="2"/>
+ <name name="set_record" arity="2" since="OTP 18.0"/>
<fsummary>Modify the record marker.</fsummary>
<type name="record"></type>
<desc>
@@ -267,7 +267,7 @@
</func>
<func>
- <name name="set_text" arity="2"/>
+ <name name="set_text" arity="2" since="OTP 18.0"/>
<fsummary>Modify the text.</fsummary>
<type name="text"></type>
<desc>
@@ -276,7 +276,7 @@
</func>
<func>
- <name name="text" arity="1"/>
+ <name name="text" arity="1" since="OTP 18.0"/>
<fsummary>Return the text.</fsummary>
<type name="text"></type>
<desc>
@@ -286,7 +286,7 @@
</func>
<func>
- <name name="to_term" arity="1"/>
+ <name name="to_term" arity="1" since="OTP 18.0"/>
<fsummary>Return the term representing a collection of annotations.
</fsummary>
<desc>
diff --git a/lib/stdlib/doc/src/erl_eval.xml b/lib/stdlib/doc/src/erl_eval.xml
index 1c0f7f062f..813cbecd89 100644
--- a/lib/stdlib/doc/src/erl_eval.xml
+++ b/lib/stdlib/doc/src/erl_eval.xml
@@ -32,7 +32,7 @@
<rev>B</rev>
<file>erl_eval.xml</file>
</header>
- <module>erl_eval</module>
+ <module since="">erl_eval</module>
<modulesummary>The Erlang meta interpreter.</modulesummary>
<description>
<p>This module provides an interpreter for Erlang expressions. The
@@ -96,7 +96,7 @@
<funcs>
<func>
- <name name="add_binding" arity="3"/>
+ <name name="add_binding" arity="3" since=""/>
<fsummary>Add a binding.</fsummary>
<desc>
<p>Adds binding <c><anno>Name</anno>=<anno>Value</anno></c>
@@ -106,7 +106,7 @@
</func>
<func>
- <name name="binding" arity="2"/>
+ <name name="binding" arity="2" since=""/>
<fsummary>Return bindings.</fsummary>
<desc>
<p>Returns the binding of <c><anno>Name</anno></c>
@@ -115,7 +115,7 @@
</func>
<func>
- <name name="bindings" arity="1"/>
+ <name name="bindings" arity="1" since=""/>
<fsummary>Return bindings.</fsummary>
<desc>
<p>Returns the list of bindings contained in the binding
@@ -124,7 +124,7 @@
</func>
<func>
- <name name="del_binding" arity="2"/>
+ <name name="del_binding" arity="2" since=""/>
<fsummary>Delete a binding.</fsummary>
<desc>
<p>Removes the binding of <c><anno>Name</anno></c>
@@ -134,10 +134,10 @@
</func>
<func>
- <name name="expr" arity="2"/>
- <name name="expr" arity="3"/>
- <name name="expr" arity="4"/>
- <name name="expr" arity="5"/>
+ <name name="expr" arity="2" since=""/>
+ <name name="expr" arity="3" since=""/>
+ <name name="expr" arity="4" since=""/>
+ <name name="expr" arity="5" since=""/>
<fsummary>Evaluate expression.</fsummary>
<desc>
<p>Evaluates <c><anno>Expression</anno></c> with the set of bindings
@@ -157,9 +157,9 @@
</func>
<func>
- <name name="expr_list" arity="2"/>
- <name name="expr_list" arity="3"/>
- <name name="expr_list" arity="4"/>
+ <name name="expr_list" arity="2" since=""/>
+ <name name="expr_list" arity="3" since=""/>
+ <name name="expr_list" arity="4" since=""/>
<fsummary>Evaluate a list of expressions.</fsummary>
<desc>
<p>Evaluates a list of expressions in parallel, using the same
@@ -174,9 +174,9 @@
</func>
<func>
- <name name="exprs" arity="2"/>
- <name name="exprs" arity="3"/>
- <name name="exprs" arity="4"/>
+ <name name="exprs" arity="2" since=""/>
+ <name name="exprs" arity="3" since=""/>
+ <name name="exprs" arity="4" since=""/>
<fsummary>Evaluate expressions.</fsummary>
<desc>
<p>Evaluates <c><anno>Expressions</anno></c> with the set of bindings
@@ -197,7 +197,7 @@
</func>
<func>
- <name name="new_bindings" arity="0"/>
+ <name name="new_bindings" arity="0" since=""/>
<fsummary>Return a bindings structure.</fsummary>
<desc>
<p>Returns an empty binding structure.</p>
diff --git a/lib/stdlib/doc/src/erl_expand_records.xml b/lib/stdlib/doc/src/erl_expand_records.xml
index b6aa75ed03..20e5f1960b 100644
--- a/lib/stdlib/doc/src/erl_expand_records.xml
+++ b/lib/stdlib/doc/src/erl_expand_records.xml
@@ -34,7 +34,7 @@
<rev>PA1</rev>
<file>erl_expand_records.xml</file>
</header>
- <module>erl_expand_records</module>
+ <module since="">erl_expand_records</module>
<modulesummary>Expands records in a module.</modulesummary>
<description>
<p>This module expands records in a module.</p>
@@ -42,7 +42,7 @@
<funcs>
<func>
- <name name="module" arity="2"/>
+ <name name="module" arity="2" since=""/>
<fsummary>Expand all records in a module.</fsummary>
<desc>
<p>Expands all records in a module to use explicit tuple
diff --git a/lib/stdlib/doc/src/erl_id_trans.xml b/lib/stdlib/doc/src/erl_id_trans.xml
index 16952a9582..ec66842ac0 100644
--- a/lib/stdlib/doc/src/erl_id_trans.xml
+++ b/lib/stdlib/doc/src/erl_id_trans.xml
@@ -34,7 +34,7 @@
<rev>B</rev>
<file>erl_id_trans.xml</file>
</header>
- <module>erl_id_trans</module>
+ <module since="">erl_id_trans</module>
<modulesummary>An identity parse transform.</modulesummary>
<description>
<p>This module performs an identity parse transformation of Erlang code.
@@ -46,7 +46,7 @@
<funcs>
<func>
- <name>parse_transform(Forms, Options) -> Forms</name>
+ <name since="">parse_transform(Forms, Options) -> Forms</name>
<fsummary>Transform Erlang forms.</fsummary>
<type>
<v>Forms = [<seealso marker="erl_parse#type-abstract_form">erl_parse:abstract_form()</seealso>
diff --git a/lib/stdlib/doc/src/erl_internal.xml b/lib/stdlib/doc/src/erl_internal.xml
index 17cd0fb240..77551ffed7 100644
--- a/lib/stdlib/doc/src/erl_internal.xml
+++ b/lib/stdlib/doc/src/erl_internal.xml
@@ -34,7 +34,7 @@
<rev>B</rev>
<file>erl_internal.xml</file>
</header>
- <module>erl_internal</module>
+ <module since="">erl_internal</module>
<modulesummary>Internal Erlang definitions.</modulesummary>
<description>
<p>This module defines Erlang BIFs, guard tests, and operators.
@@ -44,7 +44,7 @@
<funcs>
<func>
- <name name="add_predefined_functions" arity="1"/>
+ <name name="add_predefined_functions" arity="1" since="OTP 20.0"/>
<fsummary>Add code for pre-defined functions.</fsummary>
<desc>
<p>Adds to <c><anno>Forms</anno></c> the code for the standard
@@ -54,7 +54,7 @@
</func>
<func>
- <name name="arith_op" arity="2"/>
+ <name name="arith_op" arity="2" since=""/>
<fsummary>Test for an arithmetic operator.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>OpName</anno>/<anno>Arity</anno></c>
@@ -63,7 +63,7 @@
</func>
<func>
- <name name="bif" arity="2"/>
+ <name name="bif" arity="2" since=""/>
<fsummary>Test for an Erlang BIF.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Name</anno>/<anno>Arity</anno></c>
@@ -73,7 +73,7 @@
</func>
<func>
- <name name="bool_op" arity="2"/>
+ <name name="bool_op" arity="2" since=""/>
<fsummary>Test for a Boolean operator.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>OpName</anno>/<anno>Arity</anno></c>
@@ -82,7 +82,7 @@
</func>
<func>
- <name name="comp_op" arity="2"/>
+ <name name="comp_op" arity="2" since=""/>
<fsummary>Test for a comparison operator.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>OpName</anno>/<anno>Arity</anno></c>
@@ -91,7 +91,7 @@
</func>
<func>
- <name name="guard_bif" arity="2"/>
+ <name name="guard_bif" arity="2" since=""/>
<fsummary>Test for an Erlang BIF allowed in guards.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Name</anno>/<anno>Arity</anno></c> is
@@ -100,7 +100,7 @@
</func>
<func>
- <name name="list_op" arity="2"/>
+ <name name="list_op" arity="2" since=""/>
<fsummary>Test for a list operator.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>OpName</anno>/<anno>Arity</anno></c>
@@ -109,7 +109,7 @@
</func>
<func>
- <name name="op_type" arity="2"/>
+ <name name="op_type" arity="2" since=""/>
<fsummary>Return operator type.</fsummary>
<desc>
<p>Returns the <c><anno>Type</anno></c> of operator that
@@ -120,7 +120,7 @@
</func>
<func>
- <name name="send_op" arity="2"/>
+ <name name="send_op" arity="2" since=""/>
<fsummary>Test for a send operator.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>OpName</anno>/<anno>Arity</anno></c>
@@ -129,7 +129,7 @@
</func>
<func>
- <name name="type_test" arity="2"/>
+ <name name="type_test" arity="2" since=""/>
<fsummary>Test for a valid type test.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Name</anno>/<anno>Arity</anno></c> is
diff --git a/lib/stdlib/doc/src/erl_lint.xml b/lib/stdlib/doc/src/erl_lint.xml
index 77cb7a9916..12eaafc3a8 100644
--- a/lib/stdlib/doc/src/erl_lint.xml
+++ b/lib/stdlib/doc/src/erl_lint.xml
@@ -32,7 +32,7 @@
<rev>B</rev>
<file>erl_lint.xml</file>
</header>
- <module>erl_lint</module>
+ <module since="">erl_lint</module>
<modulesummary>The Erlang code linter.</modulesummary>
<description>
<p>This module is used to check Erlang code for illegal syntax and
@@ -78,7 +78,7 @@
<funcs>
<func>
- <name name="format_error" arity="1"/>
+ <name name="format_error" arity="1" since=""/>
<fsummary>Format an error descriptor.</fsummary>
<desc>
<p>Takes an <c><anno>ErrorDescriptor</anno></c> and returns a string
@@ -90,7 +90,7 @@
</func>
<func>
- <name name="is_guard_test" arity="1"/>
+ <name name="is_guard_test" arity="1" since=""/>
<fsummary>Test for a guard test.</fsummary>
<desc>
<p>Tests if <c><anno>Expr</anno></c> is a legal guard test.
@@ -102,9 +102,9 @@
</func>
<func>
- <name name="module" arity="1"/>
- <name name="module" arity="2"/>
- <name name="module" arity="3"/>
+ <name name="module" arity="1" since=""/>
+ <name name="module" arity="2" since=""/>
+ <name name="module" arity="3" since=""/>
<fsummary>Check a module for errors.</fsummary>
<desc>
<p>Checks all the forms in a module for errors. It returns:</p>
diff --git a/lib/stdlib/doc/src/erl_parse.xml b/lib/stdlib/doc/src/erl_parse.xml
index 647f36883c..8142e5c0aa 100644
--- a/lib/stdlib/doc/src/erl_parse.xml
+++ b/lib/stdlib/doc/src/erl_parse.xml
@@ -32,7 +32,7 @@
<rev>B</rev>
<file>erl_parse.xml</file>
</header>
- <module>erl_parse</module>
+ <module since="">erl_parse</module>
<modulesummary>The Erlang parser.</modulesummary>
<description>
<p>This module is the basic Erlang parser that converts tokens into
@@ -89,7 +89,7 @@
<funcs>
<func>
- <name name="abstract" arity="1"/>
+ <name name="abstract" arity="1" since=""/>
<fsummary>Convert an Erlang term into an abstract form.</fsummary>
<desc>
<p>Converts the Erlang data structure <c><anno>Data</anno></c> into an
@@ -102,7 +102,7 @@
</func>
<func>
- <name name="abstract" arity="2"/>
+ <name name="abstract" arity="2" since="OTP R16B01"/>
<fsummary>Convert an Erlang term into an abstract form.</fsummary>
<type name="encoding_func"/>
<desc>
@@ -124,7 +124,7 @@
</func>
<func>
- <name name="anno_from_term" arity="1"/>
+ <name name="anno_from_term" arity="1" since="OTP 18.0"/>
<fsummary>Return annotations as terms.</fsummary>
<desc>
<p>Assumes that <c><anno>Term</anno></c> is a term with the same
@@ -140,7 +140,7 @@
</func>
<func>
- <name name="anno_to_term" arity="1"/>
+ <name name="anno_to_term" arity="1" since="OTP 18.0"/>
<fsummary>Return the representation of annotations.</fsummary>
<desc>
<p>Returns a term where each collection of annotations
@@ -154,7 +154,7 @@
</func>
<func>
- <name name="fold_anno" arity="3"/>
+ <name name="fold_anno" arity="3" since="OTP 18.0"/>
<fsummary>Fold a function over the annotations of an <c>erl_parse</c> tree.
</fsummary>
<desc>
@@ -171,7 +171,7 @@
</func>
<func>
- <name>format_error(ErrorDescriptor) -> Chars</name>
+ <name since="">format_error(ErrorDescriptor) -> Chars</name>
<fsummary>Format an error descriptor.</fsummary>
<type>
<v>ErrorDescriptor = <seealso
@@ -188,7 +188,7 @@
</func>
<func>
- <name name="map_anno" arity="2"/>
+ <name name="map_anno" arity="2" since="OTP 18.0"/>
<fsummary>Map a function over the annotations of an <c>erl_parse</c> tree.
</fsummary>
<desc>
@@ -201,7 +201,7 @@
</func>
<func>
- <name name="mapfold_anno" arity="3"/>
+ <name name="mapfold_anno" arity="3" since="OTP 18.0"/>
<fsummary>Map and fold a function over the annotations of an
<c>erl_parse</c> tree.</fsummary>
<desc>
@@ -220,7 +220,7 @@
</func>
<func>
- <name name="new_anno" arity="1"/>
+ <name name="new_anno" arity="1" since="OTP 18.0"/>
<fsummary>Create new annotations.</fsummary>
<desc>
<p>Assumes that <c><anno>Term</anno></c> is a term with the same
@@ -236,7 +236,7 @@
</func>
<func>
- <name name="normalise" arity="1"/>
+ <name name="normalise" arity="1" since=""/>
<fsummary>Convert abstract form to an Erlang term.</fsummary>
<desc>
<p>Converts the abstract form <c><anno>AbsTerm</anno></c> of a
@@ -247,7 +247,7 @@
</func>
<func>
- <name name="parse_exprs" arity="1"/>
+ <name name="parse_exprs" arity="1" since=""/>
<fsummary>Parse Erlang expressions.</fsummary>
<desc>
<p>Parses <c><anno>Tokens</anno></c> as if it was a list of expressions.
@@ -267,7 +267,7 @@
</func>
<func>
- <name name="parse_form" arity="1"/>
+ <name name="parse_form" arity="1" since=""/>
<fsummary>Parse an Erlang form.</fsummary>
<desc>
<p>Parses <c><anno>Tokens</anno></c> as if it was a form. Returns one
@@ -287,7 +287,7 @@
</func>
<func>
- <name name="parse_term" arity="1"/>
+ <name name="parse_term" arity="1" since=""/>
<fsummary>Parse an Erlang term.</fsummary>
<desc>
<p>Parses <c><anno>Tokens</anno></c> as if it was a term. Returns
@@ -307,8 +307,8 @@
</func>
<func>
- <name name="tokens" arity="1"/>
- <name name="tokens" arity="2"/>
+ <name name="tokens" arity="1" since=""/>
+ <name name="tokens" arity="2" since=""/>
<fsummary>Generate a list of tokens for an expression.</fsummary>
<desc>
<p>Generates a list of tokens representing the abstract
diff --git a/lib/stdlib/doc/src/erl_pp.xml b/lib/stdlib/doc/src/erl_pp.xml
index 77a7f1e8d1..0a46139db6 100644
--- a/lib/stdlib/doc/src/erl_pp.xml
+++ b/lib/stdlib/doc/src/erl_pp.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>1996</year>
- <year>2016</year>
+ <year>2019</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -34,7 +34,7 @@
<rev>B</rev>
<file>erl_pp.xml</file>
</header>
- <module>erl_pp</module>
+ <module since="">erl_pp</module>
<modulesummary>The Erlang pretty printer.</modulesummary>
<description>
<p>The functions in this module are used to generate
@@ -65,6 +65,10 @@
</datatype>
<datatype>
<name name="option"/>
+ <desc>
+ <p>The option <c>quote_singleton_atom_types</c>
+ is used to add quotes to all singleton atom types.</p>
+ </desc>
</datatype>
<datatype>
<name name="options"/>
@@ -73,8 +77,8 @@
<funcs>
<func>
- <name name="attribute" arity="1"/>
- <name name="attribute" arity="2"/>
+ <name name="attribute" arity="1" since=""/>
+ <name name="attribute" arity="2" since=""/>
<fsummary>Pretty print an attribute.</fsummary>
<desc>
<p>Same as <seealso marker="#form/1"><c>form/1,2</c></seealso>,
@@ -83,10 +87,10 @@
</func>
<func>
- <name name="expr" arity="1"/>
- <name name="expr" arity="2"/>
- <name name="expr" arity="3"/>
- <name name="expr" arity="4"/>
+ <name name="expr" arity="1" since=""/>
+ <name name="expr" arity="2" since=""/>
+ <name name="expr" arity="3" since=""/>
+ <name name="expr" arity="4" since=""/>
<fsummary>Pretty print one <c>Expression</c>.</fsummary>
<desc>
<p>Prints one expression. It is useful for implementing hooks (see
@@ -96,9 +100,9 @@
</func>
<func>
- <name name="exprs" arity="1"/>
- <name name="exprs" arity="2"/>
- <name name="exprs" arity="3"/>
+ <name name="exprs" arity="1" since=""/>
+ <name name="exprs" arity="2" since=""/>
+ <name name="exprs" arity="3" since=""/>
<fsummary>Pretty print <c>Expressions</c>.</fsummary>
<desc>
<p>Same as <seealso marker="#form/1"><c>form/1,2</c></seealso>,
@@ -108,8 +112,8 @@
</func>
<func>
- <name name="form" arity="1"/>
- <name name="form" arity="2"/>
+ <name name="form" arity="1" since=""/>
+ <name name="form" arity="2" since=""/>
<fsummary>Pretty print a form.</fsummary>
<desc>
<p>Pretty prints a
@@ -120,8 +124,8 @@
</func>
<func>
- <name name="function" arity="1"/>
- <name name="function" arity="2"/>
+ <name name="function" arity="1" since=""/>
+ <name name="function" arity="2" since=""/>
<fsummary>Pretty print a function.</fsummary>
<desc>
<p>Same as <seealso marker="#form/1"><c>form/1,2</c></seealso>,
@@ -130,8 +134,8 @@
</func>
<func>
- <name name="guard" arity="1"/>
- <name name="guard" arity="2"/>
+ <name name="guard" arity="1" since=""/>
+ <name name="guard" arity="2" since=""/>
<fsummary>Pretty print a guard.</fsummary>
<desc>
<p>Same as <seealso marker="#form/1"><c>form/1,2</c></seealso>,
diff --git a/lib/stdlib/doc/src/erl_scan.xml b/lib/stdlib/doc/src/erl_scan.xml
index 137ccd3416..38111f73bc 100644
--- a/lib/stdlib/doc/src/erl_scan.xml
+++ b/lib/stdlib/doc/src/erl_scan.xml
@@ -32,7 +32,7 @@
<rev>B</rev>
<file>erl_scan.xml</file>
</header>
- <module>erl_scan</module>
+ <module since="">erl_scan</module>
<modulesummary>The Erlang token scanner.</modulesummary>
<description>
<p>This module contains functions for tokenizing (scanning) characters into
@@ -74,7 +74,7 @@
<funcs>
<func>
- <name name="category" arity="1"/>
+ <name name="category" arity="1" since="OTP 18.0"/>
<fsummary>Return the category.</fsummary>
<desc>
<p>Returns the category of <c><anno>Token</anno></c>.</p>
@@ -82,7 +82,7 @@
</func>
<func>
- <name name="column" arity="1"/>
+ <name name="column" arity="1" since="OTP 18.0"/>
<fsummary>Return the column.</fsummary>
<desc>
<p>Returns the column of <c><anno>Token</anno></c>'s
@@ -91,7 +91,7 @@
</func>
<func>
- <name name="end_location" arity="1"/>
+ <name name="end_location" arity="1" since="OTP 18.0"/>
<fsummary>Return the end location of the text.</fsummary>
<desc>
<p>Returns the end location of the text of
@@ -101,7 +101,7 @@
</func>
<func>
- <name name="format_error" arity="1"/>
+ <name name="format_error" arity="1" since=""/>
<fsummary>Format an error descriptor.</fsummary>
<desc>
<p>Uses an <c><anno>ErrorDescriptor</anno></c> and returns a string
@@ -113,7 +113,7 @@
</func>
<func>
- <name name="line" arity="1"/>
+ <name name="line" arity="1" since="OTP 18.0"/>
<fsummary>Return the line.</fsummary>
<desc>
<p>Returns the line of <c><anno>Token</anno></c>'s collection
@@ -122,7 +122,7 @@
</func>
<func>
- <name name="location" arity="1"/>
+ <name name="location" arity="1" since="OTP 18.0"/>
<fsummary>Return the location.</fsummary>
<desc>
<p>Returns the location of <c><anno>Token</anno></c>'s
@@ -131,7 +131,7 @@
</func>
<func>
- <name name="reserved_word" arity="1"/>
+ <name name="reserved_word" arity="1" since=""/>
<fsummary>Test for a reserved word.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Atom</anno></c> is an
@@ -140,9 +140,9 @@
</func>
<func>
- <name name="string" arity="1"/>
- <name name="string" arity="2"/>
- <name name="string" arity="3"/>
+ <name name="string" arity="1" since=""/>
+ <name name="string" arity="2" since=""/>
+ <name name="string" arity="3" since=""/>
<fsummary>Scan a string and return the Erlang tokens.</fsummary>
<desc>
<p>Takes the list of characters <c><anno>String</anno></c> and tries to
@@ -229,7 +229,7 @@
</func>
<func>
- <name name="symbol" arity="1"/>
+ <name name="symbol" arity="1" since="OTP 18.0"/>
<fsummary>Return the symbol.</fsummary>
<desc>
<p>Returns the symbol of <c><anno>Token</anno></c>.</p>
@@ -237,7 +237,7 @@
</func>
<func>
- <name name="text" arity="1"/>
+ <name name="text" arity="1" since="OTP 18.0"/>
<fsummary>Return the text.</fsummary>
<desc>
<p>Returns the text of <c><anno>Token</anno></c>'s collection
@@ -247,8 +247,8 @@
</func>
<func>
- <name name="tokens" arity="3"/>
- <name name="tokens" arity="4"/>
+ <name name="tokens" arity="3" since=""/>
+ <name name="tokens" arity="4" since=""/>
<fsummary>Re-entrant scanner.</fsummary>
<type name="char_spec"/>
<type name="return_cont"/>
diff --git a/lib/stdlib/doc/src/erl_tar.xml b/lib/stdlib/doc/src/erl_tar.xml
index 337028568a..ea8173748a 100644
--- a/lib/stdlib/doc/src/erl_tar.xml
+++ b/lib/stdlib/doc/src/erl_tar.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2003</year><year>2017</year>
+ <year>2003</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>erl_tar.xml</file>
</header>
- <module>erl_tar</module>
+ <module since="">erl_tar</module>
<modulesummary>Unix 'tar' utility for reading and writing tar archives.
</modulesummary>
<description>
@@ -90,8 +90,8 @@
<section>
<title>Other Storage Media</title>
- <p>The <seealso marker="inets:ftp"><c>ftp</c></seealso>
- module (Inets) normally accesses the tar file on disk using
+ <p>The <seealso marker="ftp:ftp"><c>ftp</c></seealso>
+ module normally accesses the tar file on disk using
the <seealso marker="kernel:file"><c>file</c></seealso> module.
When other needs arise, you can define your own low-level Erlang
functions to perform the writing and reading on the storage media;
@@ -127,7 +127,7 @@
<funcs>
<func>
- <name>add(TarDescriptor, Filename, Options) -> RetValue</name>
+ <name since="">add(TarDescriptor, Filename, Options) -> RetValue</name>
<fsummary>Add a file to an open tar file.</fsummary>
<type>
<v>TarDescriptor = term()</v>
@@ -136,6 +136,9 @@
<v>Filename = filename()|{NameInArchive,FilenameOrBin}</v>
<v>Options = [Option]</v>
<v>Option = dereference|verbose|{chunks,ChunkSize}</v>
+ <v>|{atime,non_neg_integer()}|{mtime,non_neg_integer()}</v>
+ <v>|{ctime,non_neg_integer()}|{uid,non_neg_integer()}</v>
+ <v>|{gid,non_neg_integer()}</v>
<v>ChunkSize = positive_integer()</v>
<v>RetValue = ok|{error,{Filename,Reason}}</v>
<v>Reason = term()</v>
@@ -167,12 +170,48 @@
<seealso marker="ssh:ssh_sftp#open_tar/3">
<c>ssh_sftp:open_tar/3</c></seealso>.</p>
</item>
+ <tag><c>{atime,non_neg_integer()}</c></tag>
+ <item>
+ <p>Sets the last time, as
+ <seealso marker="erts:time_correction#POSIX_Time">
+ POSIX time</seealso>, when the file was read. See also
+ <seealso marker="kernel:file#read_file_info/1">
+ <c>file:read_file_info/1</c></seealso>.</p>
+ </item>
+ <tag><c>{mtime,non_neg_integer()}</c></tag>
+ <item>
+ <p>Sets the last time, as
+ <seealso marker="erts:time_correction#POSIX_Time">
+ POSIX time</seealso>, when the file was written. See also
+ <seealso marker="kernel:file#read_file_info/1">
+ <c>file:read_file_info/1</c></seealso>.</p>
+ </item>
+ <tag><c>{ctime,non_neg_integer()}</c></tag>
+ <item>
+ <p>Sets the time, as
+ <seealso marker="erts:time_correction#POSIX_Time">
+ POSIX time</seealso>, when the file was created. See also
+ <seealso marker="kernel:file#read_file_info/1">
+ <c>file:read_file_info/1</c></seealso>.</p>
+ </item>
+ <tag><c>{uid,non_neg_integer()}</c></tag>
+ <item>
+ <p>Sets the file owner.
+ <seealso marker="kernel:file#read_file_info/1">
+ <c>file:read_file_info/1</c></seealso>.</p>
+ </item>
+ <tag><c>{gid,non_neg_integer()}</c></tag>
+ <item>
+ <p>Sets the group that the file owner belongs to.
+ <seealso marker="kernel:file#read_file_info/1">
+ <c>file:read_file_info/1</c></seealso>.</p>
+ </item>
</taglist>
</desc>
</func>
<func>
- <name>add(TarDescriptor, FilenameOrBin, NameInArchive, Options) ->
+ <name since="">add(TarDescriptor, FilenameOrBin, NameInArchive, Options) ->
RetValue </name>
<fsummary>Add a file to an open tar file.</fsummary>
<type>
@@ -194,7 +233,7 @@
</func>
<func>
- <name>close(TarDescriptor)</name>
+ <name since="">close(TarDescriptor)</name>
<fsummary>Close an open tar file.</fsummary>
<type>
<v>TarDescriptor = term()</v>
@@ -206,7 +245,7 @@
</func>
<func>
- <name>create(Name, FileList) ->RetValue </name>
+ <name since="">create(Name, FileList) ->RetValue </name>
<fsummary>Create a tar archive.</fsummary>
<type>
<v>Name = filename()</v>
@@ -225,7 +264,7 @@
</func>
<func>
- <name>create(Name, FileList, OptionList)</name>
+ <name since="">create(Name, FileList, OptionList)</name>
<fsummary>Create a tar archive with options.</fsummary>
<type>
<v>Name = filename()</v>
@@ -276,7 +315,7 @@
</func>
<func>
- <name>extract(Name) -> RetValue</name>
+ <name since="">extract(Name) -> RetValue</name>
<fsummary>Extract all files from a tar file.</fsummary>
<type>
<v>Name = filename() | {binary,binary()} | {file,Fd}</v>
@@ -300,7 +339,7 @@
</func>
<func>
- <name>extract(Name, OptionList)</name>
+ <name since="">extract(Name, OptionList)</name>
<fsummary>Extract files from a tar file.</fsummary>
<type>
<v>Name = filename() | {binary,binary()} | {file,Fd}</v>
@@ -372,19 +411,19 @@
</func>
<func>
- <name>format_error(Reason) -> string()</name>
+ <name since="">format_error(Reason) -> string()</name>
<fsummary>Convert error term to a readable string.</fsummary>
<type>
<v>Reason = term()</v>
</type>
<desc>
- <p>Cconverts an error reason term to a human-readable error message
+ <p>Converts an error reason term to a human-readable error message
string.</p>
</desc>
</func>
<func>
- <name>init(UserPrivate, AccessMode, Fun) ->
+ <name since="OTP 17.4">init(UserPrivate, AccessMode, Fun) ->
{ok,TarDescriptor} | {error,Reason}</name>
<fsummary>Create a <c>TarDescriptor</c> used in subsequent tar operations
when defining own low-level storage access functions.</fsummary>
@@ -479,7 +518,7 @@ erl_tar:close(TarDesc)</code>
</func>
<func>
- <name>open(Name, OpenModeList) -> RetValue</name>
+ <name since="">open(Name, OpenModeList) -> RetValue</name>
<fsummary>Open a tar file for writing.</fsummary>
<type>
<v>Name = filename()</v>
@@ -526,7 +565,7 @@ erl_tar:close(TarDesc)</code>
</func>
<func>
- <name>table(Name) -> RetValue</name>
+ <name since="">table(Name) -> RetValue</name>
<fsummary>Retrieve the name of all files in a tar file.</fsummary>
<type>
<v>Name = filename()|{binary,binary()}|{file,file_descriptor()}</v>
@@ -539,7 +578,7 @@ erl_tar:close(TarDesc)</code>
</func>
<func>
- <name>table(Name, Options)</name>
+ <name since="">table(Name, Options)</name>
<fsummary>Retrieve name and information of all files in a tar file.
</fsummary>
<type>
@@ -551,7 +590,7 @@ erl_tar:close(TarDesc)</code>
</func>
<func>
- <name>t(Name)</name>
+ <name since="">t(Name)</name>
<fsummary>Print the name of each file in a tar file.</fsummary>
<type>
<v>Name = filename()|{binary,binary()}|{file,file_descriptor()}</v>
@@ -563,7 +602,7 @@ erl_tar:close(TarDesc)</code>
</func>
<func>
- <name>tt(Name)</name>
+ <name since="">tt(Name)</name>
<fsummary>Print name and information for each file in a tar file.
</fsummary>
<type>
diff --git a/lib/stdlib/doc/src/ets.xml b/lib/stdlib/doc/src/ets.xml
index 51e35cd2df..2cb677785d 100644
--- a/lib/stdlib/doc/src/ets.xml
+++ b/lib/stdlib/doc/src/ets.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>ets</module>
+ <module since="">ets</module>
<modulesummary>Built-in term storage.</modulesummary>
<description>
<p>This module is an interface to the Erlang built-in term storage
@@ -49,14 +49,16 @@
associated with each key. A <c>bag</c> or <c>duplicate_bag</c> table can
have many objects associated with each key.</p>
+ <marker id="max_ets_tables"></marker>
<note>
<p>
The number of tables stored at one Erlang node <em>used</em> to
be limited. This is no longer the case (except by memory usage).
The previous default limit was about 1400 tables and
could be increased by setting the environment variable
- <c>ERL_MAX_ETS_TABLES</c> before starting the Erlang runtime
- system. This hard limit has been removed, but it is currently
+ <c>ERL_MAX_ETS_TABLES</c> or the command line option
+ <seealso marker="erts:erl#+e"><c>+e</c></seealso> before starting the
+ Erlang runtime system. This hard limit has been removed, but it is currently
useful to set the <c>ERL_MAX_ETS_TABLES</c> anyway. It should be
set to an approximate of the maximum amount of tables used. This since
an internal table for named tables is sized using this value. If
@@ -136,23 +138,96 @@
operation. In database terms the isolation level can be seen as
"serializable", as if all isolated operations are carried out serially,
one after the other in a strict order.</p>
+ </section>
- <p>No other support is available within this module that would guarantee
- consistency between objects. However, function
- <seealso marker="#safe_fixtable/2"><c>safe_fixtable/2</c></seealso>
- can be used to guarantee that a sequence of
- <seealso marker="#first/1"><c>first/1</c></seealso> and
- <seealso marker="#next/2"><c>next/2</c></seealso> calls traverse the
- table without errors and that each existing object in the table is
- visited exactly once, even if another (or the same) process
- simultaneously deletes or inserts objects into the table.
- Nothing else is guaranteed; in particular objects that are inserted
- or deleted during such a traversal can be visited once or not at all.
- Functions that internally traverse over a table, like
- <seealso marker="#select/1"><c>select</c></seealso> and
- <seealso marker="#match/1"><c>match</c></seealso>,
- give the same guarantee as
- <seealso marker="#safe_fixtable/2"><c>safe_fixtable</c></seealso>.</p>
+ <section><marker id="traversal"></marker>
+ <title>Table traversal</title>
+ <p>There are different ways to traverse through the objects of a table.</p>
+ <list type="bulleted">
+ <item><p><em>Single-step</em> traversal one key at at time, using
+ <seealso marker="#first/1"><c>first/1</c></seealso>,
+ <seealso marker="#next/2"><c>next/2</c></seealso>,
+ <seealso marker="#last/1"><c>last/1</c></seealso> and
+ <seealso marker="#prev/2"><c>prev/2</c></seealso>.</p>
+ </item>
+ <item><p>Search with simple <em>match patterns</em>, using
+ <seealso marker="#match/1"><c>match/1/2/3</c></seealso>,
+ <seealso marker="#match_delete/2"><c>match_delete/2</c></seealso> and
+ <seealso marker="#match_object/1"><c>match_object/1/2/3</c></seealso>.</p>
+ </item>
+ <item><p>Search with more powerful <em>match specifications</em>, using
+ <seealso marker="#select/1"><c>select/1/2/3</c></seealso>,
+ <seealso marker="#select_count/2"><c>select_count/2</c></seealso>,
+ <seealso marker="#select_delete/2"><c>select_delete/2</c></seealso>,
+ <seealso marker="#select_replace/2"><c>select_replace/2</c></seealso> and
+ <seealso marker="#select_reverse/1"><c>select_reverse/1/2/3</c></seealso>.</p>
+ </item>
+ <item><p><em>Table conversions</em>, using
+ <seealso marker="#tab2file/2"><c>tab2file/2/3</c></seealso> and
+ <seealso marker="#tab2list/1"><c>tab2list/1</c></seealso>.</p>
+ </item>
+ </list>
+ <p>None of these ways of table traversal will guarantee a consistent table snapshot
+ if the table is also updated during the traversal. Moreover, traversals not
+ done in a <em>safe</em> way, on tables where keys are inserted or deleted
+ during the traversal, may yield the following undesired effects:</p>
+ <list type="bulleted">
+ <item><p>Any key may be missed.</p></item>
+ <item><p>Any key may be found more than once.</p></item>
+ <item><p>The traversal may fail with <c>badarg</c> exception if keys are deleted.</p>
+ </item>
+ </list>
+ <p>A table traversal is <em>safe</em> if either</p>
+ <list type="bulleted">
+ <item><p>the table is of type <c>ordered_set</c>.</p>
+ </item>
+ <item><p>the entire table traversal is done within one ETS function
+ call.</p>
+ </item>
+ <item><p>function <seealso marker="#safe_fixtable/2"><c>safe_fixtable/2</c></seealso>
+ is used to keep the table fixated during the entire traversal.</p>
+ </item>
+ </list>
+ <note>
+ <p>Even though the access of a single object is always guaranteed to be
+ <seealso marker="#concurrency">atomic and isolated</seealso>, each traversal
+ through a table to find the next key is not done with such guarantees. This is often
+ not a problem, but may cause rare subtle "unexpected" effects if a concurrent
+ process inserts objects during a traversal. For example, consider one
+ process doing</p>
+<pre>
+ets:new(t, [ordered_set, named_table]),
+ets:insert(t, {1}),
+ets:insert(t, {2}),
+ets:insert(t, {3}),
+</pre>
+ <p>A concurrent call to <c>ets:first(t)</c>, done by another
+ process, may then in rare cases return <c>2</c> even though
+ <c>2</c> has never existed in the table ordered as the first key. In
+ the same way, a concurrent call to <c>ets:next(t, 1)</c> may return
+ <c>3</c> even though <c>3</c> never existed in the table
+ ordered directly after <c>1</c>.</p>
+ <p>Effects like this are improbable but possible. The probability will
+ further be reduced (if not vanish) if table option
+ <seealso marker="#new_2_write_concurrency"><c>write_concurrency</c></seealso>
+ is not enabled. This can also only be a potential concern for
+ <c>ordered_set</c> where the traversal order is defined.</p>
+ </note>
+ <p>Traversals using <c>match</c> and <c>select</c> functions may not need to
+ scan the entire table depending on how the key is specified. A match
+ pattern with a <em>fully bound key</em> (without any match variables) will
+ optimize the operation to a single key lookup without any table traversal
+ at all. For <c>ordered_set</c> a <em>partially bound key</em> will limit the
+ traversal to only scan a subset of the table based on term order. A
+ partially bound key is either a list or a tuple with a prefix that is fully
+ bound. Example:</p>
+<pre>
+1> <input>T = ets:new(t,[ordered_set]), ets:insert(T, {"555-1234", "John Smith"}).</input>
+true
+2> <input>%% Efficient search of all with area code 555</input>
+2> <input>ets:match(T,{[$5,$5,$5,$- |'$1'],'$2'}).</input>
+[["1234","John Smith"]]
+</pre>
</section>
<section>
@@ -205,7 +280,7 @@
<funcs>
<func>
- <name name="all" arity="0"/>
+ <name name="all" arity="0" since=""/>
<fsummary>Return a list of all ETS tables.</fsummary>
<desc>
<p>Returns a list of all tables at the node. Named tables are
@@ -220,7 +295,7 @@
</func>
<func>
- <name name="delete" arity="1"/>
+ <name name="delete" arity="1" since=""/>
<fsummary>Delete an entire ETS table.</fsummary>
<desc>
<p>Deletes the entire table <c><anno>Tab</anno></c>.</p>
@@ -228,7 +303,7 @@
</func>
<func>
- <name name="delete" arity="2"/>
+ <name name="delete" arity="2" since=""/>
<fsummary>Delete all objects with a specified key from an ETS
table.</fsummary>
<desc>
@@ -238,7 +313,7 @@
</func>
<func>
- <name name="delete_all_objects" arity="1"/>
+ <name name="delete_all_objects" arity="1" since=""/>
<fsummary>Delete all objects in an ETS table.</fsummary>
<desc>
<p>Delete all objects in the ETS table <c><anno>Tab</anno></c>.
@@ -248,7 +323,7 @@
</func>
<func>
- <name name="delete_object" arity="2"/>
+ <name name="delete_object" arity="2" since=""/>
<fsummary>Deletes a specific from an ETS table.</fsummary>
<desc>
<p>Delete the exact object <c><anno>Object</anno></c> from the
@@ -260,7 +335,7 @@
</func>
<func>
- <name name="file2tab" arity="1"/>
+ <name name="file2tab" arity="1" since=""/>
<fsummary>Read an ETS table from a file.</fsummary>
<desc>
<p>Reads a file produced by <seealso marker="#tab2file/2">
@@ -272,7 +347,7 @@
</func>
<func>
- <name name="file2tab" arity="2"/>
+ <name name="file2tab" arity="2" since=""/>
<fsummary>Read an ETS table from a file.</fsummary>
<desc>
<p>Reads a file produced by <seealso marker="#tab2file/2">
@@ -304,7 +379,7 @@
</func>
<func>
- <name name="first" arity="1"/>
+ <name name="first" arity="1" since=""/>
<fsummary>Return the first key in an ETS table.</fsummary>
<desc>
<p>Returns the first key <c><anno>Key</anno></c> in table
@@ -319,7 +394,7 @@
</func>
<func>
- <name name="foldl" arity="3"/>
+ <name name="foldl" arity="3" since=""/>
<fsummary>Fold a function over an ETS table.</fsummary>
<desc>
<p><c><anno>Acc0</anno></c> is returned if the table is empty.
@@ -335,7 +410,7 @@
</func>
<func>
- <name name="foldr" arity="3"/>
+ <name name="foldr" arity="3" since=""/>
<fsummary>Fold a function over an ETS table.</fsummary>
<desc>
<p><c><anno>Acc0</anno></c> is returned if the table is empty.
@@ -351,7 +426,7 @@
</func>
<func>
- <name name="from_dets" arity="2"/>
+ <name name="from_dets" arity="2" since=""/>
<fsummary>Fill an ETS table with objects from a Dets
table.</fsummary>
<desc>
@@ -365,7 +440,7 @@
</func>
<func>
- <name name="fun2ms" arity="1"/>
+ <name name="fun2ms" arity="1" since=""/>
<fsummary>Pseudo function that transforms fun syntax to a match
specification.</fsummary>
<desc>
@@ -434,7 +509,7 @@ Error: fun containing local Erlang function calls
</func>
<func>
- <name name="give_away" arity="3"/>
+ <name name="give_away" arity="3" since=""/>
<fsummary>Change owner of a table.</fsummary>
<desc>
<p>Make process <c><anno>Pid</anno></c> the new owner of table
@@ -452,7 +527,7 @@ Error: fun containing local Erlang function calls
</func>
<func>
- <name name="i" arity="0"/>
+ <name name="i" arity="0" since=""/>
<fsummary>Display information about all ETS tables on a terminal.
</fsummary>
<desc>
@@ -461,7 +536,7 @@ Error: fun containing local Erlang function calls
</func>
<func>
- <name name="i" arity="1"/>
+ <name name="i" arity="1" since=""/>
<fsummary>Browse an ETS table on a terminal.</fsummary>
<desc>
<p>Browses table <c><anno>Tab</anno></c> on a terminal.</p>
@@ -469,7 +544,7 @@ Error: fun containing local Erlang function calls
</func>
<func>
- <name name="info" arity="1"/>
+ <name name="info" arity="1" since=""/>
<fsummary>Return information about an <c>table</c>.</fsummary>
<desc>
<p>Returns information about table <c><anno>Tab</anno></c> as a list of
@@ -487,6 +562,11 @@ Error: fun containing local Erlang function calls
<p>The pid of the heir of the table, or <c>none</c> if no heir
is set.</p>
</item>
+ <tag><c>{id,</c><seealso marker="#type-tid">
+ <c>tid()</c></seealso><c>}</c></tag>
+ <item>
+ <p>The table identifier.</p>
+ </item>
<tag><c>{keypos, integer() >= 1}</c></tag>
<item>
<p>The key position.</p>
@@ -540,7 +620,7 @@ Error: fun containing local Erlang function calls
</func>
<func>
- <name name="info" arity="2"/>
+ <name name="info" arity="2" since=""/>
<fsummary>Return the information associated with the specified item for
an ETS table.</fsummary>
<desc>
@@ -562,12 +642,11 @@ Error: fun containing local Erlang function calls
<p><marker id="info_2_safe_fixed_monotonic_time"/></p>
<p><c>Item=safe_fixed|safe_fixed_monotonic_time,
Value={FixationTime,Info}|false</c></p>
- <p>If the table has been fixed using
+ <p>If the table is fixed using
<seealso marker="#safe_fixtable/2">
<c>safe_fixtable/2</c></seealso>,
the call returns a tuple where <c>FixationTime</c> is the
- time when the table was first fixed by a process, which either
- is or is not one of the processes it is fixed by now.</p>
+ last time when the table changed from unfixed to fixed.</p>
<p>The format and value of <c>FixationTime</c> depends on
<c>Item</c>:</p>
<taglist>
@@ -599,20 +678,26 @@ Error: fun containing local Erlang function calls
table is fixed by now. <c>RefCount</c> is the value
of the reference counter and it keeps track of how many times
the table has been fixed by the process.</p>
- <p>If the table never has been fixed, the call returns
- <c>false</c>.</p>
+ <p>Table fixations are not limited to <seealso marker="#safe_fixtable/2">
+ <c>safe_fixtable/2</c></seealso>. Temporary fixations may also
+ be done by for example <seealso marker="#traversal">traversing
+ functions</seealso> like <c>select</c> and <c>match</c>. Such
+ table fixations are automatically released before the
+ corresponding functions returns, but they may be seen by a
+ concurrent call to
+ <c>ets:info(T,safe_fixed|safe_fixed_monotonic_time)</c>.</p>
+ <p>If the table is not fixed at all, the call returns <c>false</c>.</p>
</item>
<item>
<p><c>Item=stats, Value=tuple()</c></p>
- <p>Returns internal statistics about <c>set</c>, <c>bag</c>, and
- <c>duplicate_bag</c> tables on an internal format used by OTP
- test suites. Not for production use.</p></item>
+ <p>Returns internal statistics about tables on an internal format
+ used by OTP test suites. Not for production use.</p></item>
</list>
</desc>
</func>
<func>
- <name name="init_table" arity="2"/>
+ <name name="init_table" arity="2" since=""/>
<fsummary>Replace all objects of an ETS table.</fsummary>
<desc>
<p>Replaces the existing objects of table <c><anno>Tab</anno></c> with
@@ -642,7 +727,7 @@ Error: fun containing local Erlang function calls
</func>
<func>
- <name name="insert" arity="2"/>
+ <name name="insert" arity="2" since=""/>
<fsummary>Insert an object into an ETS table.</fsummary>
<desc>
<p>Inserts the object or all of the objects in list
@@ -674,7 +759,7 @@ Error: fun containing local Erlang function calls
</func>
<func>
- <name name="insert_new" arity="2"/>
+ <name name="insert_new" arity="2" since=""/>
<fsummary>Insert an object into an ETS table if the key is not
already present.</fsummary>
<desc>
@@ -693,7 +778,7 @@ Error: fun containing local Erlang function calls
</func>
<func>
- <name name="is_compiled_ms" arity="1"/>
+ <name name="is_compiled_ms" arity="1" since=""/>
<fsummary>Check if an Erlang term is the result of
<c>match_spec_compile</c>.</fsummary>
<desc>
@@ -725,7 +810,7 @@ ets:is_compiled_ms(Broken).</code>
</func>
<func>
- <name name="last" arity="1"/>
+ <name name="last" arity="1" since=""/>
<fsummary>Return the last key in an ETS table of type
<c>ordered_set</c>.</fsummary>
<desc>
@@ -740,7 +825,7 @@ ets:is_compiled_ms(Broken).</code>
</func>
<func>
- <name name="lookup" arity="2"/>
+ <name name="lookup" arity="2" since=""/>
<fsummary>Return all objects with a specified key in an ETS table.
</fsummary>
<desc>
@@ -780,7 +865,7 @@ ets:is_compiled_ms(Broken).</code>
</func>
<func>
- <name name="lookup_element" arity="3"/>
+ <name name="lookup_element" arity="3" since=""/>
<fsummary>Return the <c>Pos</c>:th element of all objects with a
specified key in an ETS table.</fsummary>
<desc>
@@ -803,7 +888,7 @@ ets:is_compiled_ms(Broken).</code>
</func>
<func>
- <name name="match" arity="1"/>
+ <name name="match" arity="1" since=""/>
<fsummary>Continues matching objects in an ETS table.</fsummary>
<desc>
<p>Continues a match started with
@@ -817,7 +902,7 @@ ets:is_compiled_ms(Broken).</code>
</func>
<func>
- <name name="match" arity="2"/>
+ <name name="match" arity="2" since=""/>
<fsummary>Match the objects in an ETS table against a pattern.
</fsummary>
<desc>
@@ -849,7 +934,7 @@ ets:is_compiled_ms(Broken).</code>
</func>
<func>
- <name name="match" arity="3"/>
+ <name name="match" arity="3" since=""/>
<fsummary>Match the objects in an ETS table against a pattern
and return part of the answers.</fsummary>
<desc>
@@ -864,11 +949,14 @@ ets:is_compiled_ms(Broken).</code>
<seealso marker="#first/1"><c>first/1</c></seealso> and
<seealso marker="#next/2"><c>next/2</c></seealso>.</p>
<p>If the table is empty, <c>'$end_of_table'</c> is returned.</p>
+ <p>Use <seealso marker="#safe_fixtable/2"><c>safe_fixtable/2</c></seealso>
+ to guarantee <seealso marker="#traversal">safe traversal</seealso>
+ for subsequent calls to <seealso marker="#match/1"><c>match/1</c></seealso>.</p>
</desc>
</func>
<func>
- <name name="match_delete" arity="2"/>
+ <name name="match_delete" arity="2" since=""/>
<fsummary>Delete all objects that match a specified pattern from an
ETS table.</fsummary>
<desc>
@@ -879,7 +967,7 @@ ets:is_compiled_ms(Broken).</code>
</func>
<func>
- <name name="match_object" arity="1"/>
+ <name name="match_object" arity="1" since=""/>
<fsummary>Continues matching objects in an ETS table.</fsummary>
<desc>
<p>Continues a match started with
@@ -894,7 +982,7 @@ ets:is_compiled_ms(Broken).</code>
</func>
<func>
- <name name="match_object" arity="2"/>
+ <name name="match_object" arity="2" since=""/>
<fsummary>Match the objects in an ETS table against a pattern.
</fsummary>
<desc>
@@ -913,7 +1001,7 @@ ets:is_compiled_ms(Broken).</code>
</func>
<func>
- <name name="match_object" arity="3"/>
+ <name name="match_object" arity="3" since=""/>
<fsummary>Match the objects in an ETS table against a pattern and
return part of the answers.</fsummary>
<desc>
@@ -929,11 +1017,15 @@ ets:is_compiled_ms(Broken).</code>
<seealso marker="#first/1"><c>first/1</c></seealso> and
<seealso marker="#next/2"><c>next/2</c></seealso>.</p>
<p>If the table is empty, <c>'$end_of_table'</c> is returned.</p>
+ <p>Use <seealso marker="#safe_fixtable/2"><c>safe_fixtable/2</c></seealso>
+ to guarantee <seealso marker="#traversal">safe traversal</seealso>
+ for subsequent calls to <seealso marker="#match_object/1">
+ <c>match_object/1</c></seealso>.</p>
</desc>
</func>
<func>
- <name name="match_spec_compile" arity="1"/>
+ <name name="match_spec_compile" arity="1" since=""/>
<fsummary>Compile a match specification into its internal representation.
</fsummary>
<desc>
@@ -961,7 +1053,7 @@ ets:is_compiled_ms(Broken).</code>
</func>
<func>
- <name name="match_spec_run" arity="2"/>
+ <name name="match_spec_run" arity="2" since=""/>
<fsummary>Perform matching, using a compiled match specification on a
list of terms.</fsummary>
<desc>
@@ -998,7 +1090,7 @@ ets:select(Table, MatchSpec),</code>
</func>
<func>
- <name name="member" arity="2"/>
+ <name name="member" arity="2" since=""/>
<fsummary>Tests for occurrence of a key in an ETS table.</fsummary>
<desc>
<p>Works like <seealso marker="#lookup/2"><c>lookup/2</c></seealso>,
@@ -1009,14 +1101,14 @@ ets:select(Table, MatchSpec),</code>
</func>
<func>
- <name name="new" arity="2"/>
+ <name name="new" arity="2" since=""/>
<fsummary>Create a new ETS table.</fsummary>
<desc>
<p>Creates a new table and returns a table identifier that can
be used in subsequent operations. The table identifier can be
sent to other processes so that a table can be shared between
different processes within a node.</p>
- <p>Parameter <c><anno>Options</anno></c> is a list of atoms that
+ <p>Parameter <c><anno>Options</anno></c> is a list of options that
specifies table type, access rights, key position, and whether the
table is named. Default values are used for omitted options.
This means that not specifying any options (<c>[]</c>) is the same
@@ -1074,10 +1166,13 @@ ets:select(Table, MatchSpec),</code>
</item>
<tag><c>named_table</c></tag>
<item>
- <p>If this option is present, name <c><anno>Name</anno></c> is
- associated with the table identifier. The name can then
- be used instead of the table identifier in subsequent
- operations.</p>
+ <p>If this option is present, the table is registered under its
+ <c><anno>Name</anno></c> which can then be used instead of the
+ table identifier in subsequent operations.</p>
+ <p>The function will also return the <c><anno>Name</anno></c>
+ instead of the table identifier. To get the table identifier of a
+ named table, use
+ <seealso marker="#whereis/1"><c>whereis/1</c></seealso>.</p>
</item>
<tag><c>{keypos,<anno>Pos</anno>}</c></tag>
<item>
@@ -1125,11 +1220,17 @@ ets:select(Table, MatchSpec),</code>
Functions that makes such promises over many objects (like
<seealso marker="#insert/2"><c>insert/2</c></seealso>)
gain less (or nothing) from this option.</p>
- <p>Table type <c>ordered_set</c> is not affected by this option.
- Also, the memory consumption inflicted by
- both <c>write_concurrency</c> and <c>read_concurrency</c> is a
- constant overhead per table. This overhead can be especially
- large when both options are combined.</p>
+ <p>The memory consumption inflicted by both <c>write_concurrency</c>
+ and <c>read_concurrency</c> is a constant overhead per table for
+ <c>set</c>, <c>bag</c> and <c>duplicate_bag</c>. For
+ <c>ordered_set</c> the memory overhead depends on the number
+ of inserted objects and the amount of actual detected
+ concurrency in runtime. The memory overhead can be especially
+ large when both options are combined.</p>
+ <note>
+ <p>Prior to stdlib-3.7 (OTP-22.0) <c>write_concurrency</c> had no
+ effect on <c>ordered_set</c>.</p>
+ </note>
<marker id="new_2_read_concurrency"></marker>
</item>
<tag><c>{read_concurrency,boolean()}</c></tag>
@@ -1170,7 +1271,7 @@ ets:select(Table, MatchSpec),</code>
</func>
<func>
- <name name="next" arity="2"/>
+ <name name="next" arity="2" since=""/>
<fsummary>Return the next key in an ETS table.</fsummary>
<desc>
<p>Returns the next key <c><anno>Key2</anno></c>, following key
@@ -1182,17 +1283,18 @@ ets:select(Table, MatchSpec),</code>
<p>To find the first key in the table, use
<seealso marker="#first/1"><c>first/1</c></seealso>.</p>
<p>Unless a table of type <c>set</c>, <c>bag</c>, or
- <c>duplicate_bag</c> is protected using
+ <c>duplicate_bag</c> is fixated using
<seealso marker="#safe_fixtable/2"><c>safe_fixtable/2</c></seealso>,
- a traversal can fail if
- concurrent updates are made to the table. For table
- type <c>ordered_set</c>, the function returns the next key in
- order, even if the object does no longer exist.</p>
+ a call to <c>next/2</c> will fail if <c><anno>Key1</anno></c> no longer
+ exists in the table. For table type <c>ordered_set</c>, the function
+ always returns the next key after <c><anno>Key1</anno></c> in term
+ order, regardless whether <c><anno>Key1</anno></c> ever existed in the
+ table.</p>
</desc>
</func>
<func>
- <name name="prev" arity="2"/>
+ <name name="prev" arity="2" since=""/>
<fsummary>Return the previous key in an ETS table of type
<c>ordered_set</c>.</fsummary>
<desc>
@@ -1202,13 +1304,13 @@ ets:select(Table, MatchSpec),</code>
table types, the function is synonymous to
<seealso marker="#next/2"><c>next/2</c></seealso>.
If no previous key exists, <c>'$end_of_table'</c> is returned.</p>
- <p>To find the last key in the table, use
+ <p>To find the last key in an <c>ordered_set</c> table, use
<seealso marker="#last/1"><c>last/1</c></seealso>.</p>
</desc>
</func>
<func>
- <name name="rename" arity="2"/>
+ <name name="rename" arity="2" since=""/>
<fsummary>Rename a named ETS table.</fsummary>
<desc>
<p>Renames the named table <c><anno>Tab</anno></c> to the new name
@@ -1218,7 +1320,7 @@ ets:select(Table, MatchSpec),</code>
</func>
<func>
- <name name="repair_continuation" arity="2"/>
+ <name name="repair_continuation" arity="2" since=""/>
<fsummary>Repair a continuation from <c>ets:select/1 or ets:select/3</c>
that has passed through external representation.</fsummary>
<desc>
@@ -1273,11 +1375,20 @@ ets:select(ets:repair_continuation(Broken,MS)).</code>
</func>
<func>
- <name name="safe_fixtable" arity="2"/>
+ <name name="safe_fixtable" arity="2" since=""/>
<fsummary>Fix an ETS table for safe traversal.</fsummary>
<desc>
<p>Fixes a table of type <c>set</c>, <c>bag</c>, or
- <c>duplicate_bag</c> for safe traversal.</p>
+ <c>duplicate_bag</c> for <seealso marker="#traversal">
+ safe traversal</seealso> using
+ <seealso marker="#first/1"><c>first/1</c></seealso> &amp;
+ <seealso marker="#next/2"><c>next/2</c></seealso>,
+ <seealso marker="#match/3"><c>match/3</c></seealso> &amp;
+ <seealso marker="#match/1"><c>match/1</c></seealso>,
+ <seealso marker="#match_object/3"><c>match_object/3</c></seealso> &amp;
+ <seealso marker="#match_object/1"><c>match_object/1</c></seealso>, or
+ <seealso marker="#select/3"><c>select/3</c></seealso> &amp;
+ <seealso marker="#select/1"><c>select/1</c></seealso>.</p>
<p>A process fixes a table by calling
<c>safe_fixtable(<anno>Tab</anno>, true)</c>. The table remains
fixed until the process releases it by calling
@@ -1290,11 +1401,11 @@ ets:select(ets:repair_continuation(Broken,MS)).</code>
<p>When a table is fixed, a sequence of
<seealso marker="#first/1"><c>first/1</c></seealso> and
<seealso marker="#next/2"><c>next/2</c></seealso> calls are
- guaranteed to succeed, and each object in
- the table is returned only once, even if objects
- are removed or inserted during the traversal. The keys for new
- objects inserted during the traversal <em>can</em> be returned by
- <c>next/2</c> (it depends on the internal ordering of the keys).</p>
+ guaranteed to succeed even if keys are removed during the
+ traversal. The keys for objects inserted or deleted during a
+ traversal may or may not be returned by <c>next/2</c> depending on
+ the ordering of keys within the table and if the key exists at the time
+ <c>next/2</c> is called.</p>
<p><em>Example:</em></p>
<code type="none">
clean_all_with_value(Tab,X) ->
@@ -1312,7 +1423,7 @@ clean_all_with_value(Tab,X,Key) ->
true
end,
clean_all_with_value(Tab,X,ets:next(Tab,Key)).</code>
- <p>Notice that no deleted objects are removed from a
+ <p>Notice that deleted objects are not freed from a
fixed table until it has been released. If a process fixes a
table but never releases it, the memory used by the deleted
objects is never freed. The performance of operations on
@@ -1322,14 +1433,14 @@ clean_all_with_value(Tab,X,Key) ->
<c>info(Tab, safe_fixed_monotonic_time)</c></seealso>. A system with
many processes fixing tables can need a monitor that sends alarms
when tables have been fixed for too long.</p>
- <p>Notice that for table type <c>ordered_set</c>,
- <c>safe_fixtable/2</c> is not necessary, as calls to
- <c>first/1</c> and <c>next/2</c> always succeed.</p>
+ <p>Notice that <c>safe_fixtable/2</c> is not necessary for table type
+ <c>ordered_set</c> and for traversals done by a single ETS function call,
+ like <seealso marker="#select/2"><c>select/2</c></seealso>.</p>
</desc>
</func>
<func>
- <name name="select" arity="1"/>
+ <name name="select" arity="1" since=""/>
<fsummary>Continue matching objects in an ETS table.</fsummary>
<desc>
<p>Continues a match started with
@@ -1343,7 +1454,7 @@ clean_all_with_value(Tab,X,Key) ->
</func>
<func>
- <name name="select" arity="2"/>
+ <name name="select" arity="2" since=""/>
<fsummary>Match the objects in an ETS table against a
match specification.</fsummary>
<desc>
@@ -1438,7 +1549,7 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code>
</func>
<func>
- <name name="select" arity="3"/>
+ <name name="select" arity="3" since=""/>
<fsummary>Match the objects in an ETS table against a match
specification and return part of the answers.</fsummary>
<desc>
@@ -1452,12 +1563,15 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code>
table, which is still faster than traversing the table object by
object using <seealso marker="#first/1"><c>first/1</c></seealso>
and <seealso marker="#next/2"><c>next/2</c></seealso>.</p>
- <p>If the table is empty, <c>'$end_of_table'</c> is returned.</p>
+ <p>If the table is empty, <c>'$end_of_table'</c> is returned.</p>
+ <p>Use <seealso marker="#safe_fixtable/2"><c>safe_fixtable/2</c></seealso>
+ to guarantee <seealso marker="#traversal">safe traversal</seealso>
+ for subsequent calls to <seealso marker="#select/1"><c>select/1</c></seealso>.</p>
</desc>
</func>
<func>
- <name name="select_count" arity="2"/>
+ <name name="select_count" arity="2" since=""/>
<fsummary>Match the objects in an ETS table against a match
specification and return the number of objects for which the match
specification returned <c>true</c>.</fsummary>
@@ -1476,7 +1590,7 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code>
</func>
<func>
- <name name="select_delete" arity="2"/>
+ <name name="select_delete" arity="2" since=""/>
<fsummary>Match the objects in an ETS table against a match
specification and delete objects where the match specification
returns <c>true</c>.</fsummary>
@@ -1500,7 +1614,7 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code>
</func>
<func>
- <name name="select_replace" arity="2"/>
+ <name name="select_replace" arity="2" since="OTP 20.0"/>
<fsummary>Match and replace objects atomically in an ETS table</fsummary>
<desc>
<p>Matches the objects in the table <c><anno>Tab</anno></c> using a
@@ -1509,7 +1623,7 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code>
the match specification result.</p>
<p>The match-and-replace operation for each individual object is guaranteed to be
<seealso marker="#concurrency">atomic and isolated</seealso>. The
- <c>select_replace</c> table iteration as a whole, like all other select functions,
+ <c>select_replace</c> table traversal as a whole, like all other select functions,
does not give such guarantees.</p>
<p>The match specifiction must be guaranteed to <em>retain the key</em>
of any matched object. If not, <c>select_replace</c> will fail with <c>badarg</c>
@@ -1539,7 +1653,7 @@ Success = (1 =:= ets:select_replace(T, [{Old, [], [{const, New}]}])),
</func>
<func>
- <name name="select_reverse" arity="1"/>
+ <name name="select_reverse" arity="1" since="OTP R14B"/>
<fsummary>Continue matching objects in an ETS table.</fsummary>
<desc>
<p>Continues a match started with <seealso marker="#select_reverse/3">
@@ -1572,7 +1686,7 @@ Success = (1 =:= ets:select_replace(T, [{Old, [], [{const, New}]}])),
</func>
<func>
- <name name="select_reverse" arity="2"/>
+ <name name="select_reverse" arity="2" since="OTP R14B"/>
<fsummary>Match the objects in an ETS table against a
match specification.</fsummary>
<desc>
@@ -1584,7 +1698,7 @@ Success = (1 =:= ets:select_replace(T, [{Old, [], [{const, New}]}])),
</func>
<func>
- <name name="select_reverse" arity="3"/>
+ <name name="select_reverse" arity="3" since="OTP R14B"/>
<fsummary>Match the objects in an ETS table against a
match specification and return part of the answers.</fsummary>
<desc>
@@ -1602,7 +1716,7 @@ Success = (1 =:= ets:select_replace(T, [{Old, [], [{const, New}]}])),
</func>
<func>
- <name name="setopts" arity="2"/>
+ <name name="setopts" arity="2" since=""/>
<fsummary>Set table options.</fsummary>
<desc>
<p>Sets table options. The only allowed option to be set after the
@@ -1613,7 +1727,7 @@ Success = (1 =:= ets:select_replace(T, [{Old, [], [{const, New}]}])),
</func>
<func>
- <name name="slot" arity="2"/>
+ <name name="slot" arity="2" since=""/>
<fsummary>Return all objects in a specified slot of an ETS table.
</fsummary>
<desc>
@@ -1638,7 +1752,7 @@ Success = (1 =:= ets:select_replace(T, [{Old, [], [{const, New}]}])),
</func>
<func>
- <name name="tab2file" arity="2"/>
+ <name name="tab2file" arity="2" since=""/>
<fsummary>Dump an ETS table to a file.</fsummary>
<desc>
<p>Dumps table <c><anno>Tab</anno></c> to file
@@ -1649,7 +1763,7 @@ Success = (1 =:= ets:select_replace(T, [{Old, [], [{const, New}]}])),
</func>
<func>
- <name name="tab2file" arity="3"/>
+ <name name="tab2file" arity="3" since=""/>
<fsummary>Dump an ETS table to a file.</fsummary>
<desc>
<p>Dumps table <c><anno>Tab</anno></c> to file
@@ -1696,7 +1810,7 @@ Success = (1 =:= ets:select_replace(T, [{Old, [], [{const, New}]}])),
</func>
<func>
- <name name="tab2list" arity="1"/>
+ <name name="tab2list" arity="1" since=""/>
<fsummary>Return a list of all objects in an ETS table.</fsummary>
<desc>
<p>Returns a list of all objects in table <c><anno>Tab</anno></c>.</p>
@@ -1704,7 +1818,7 @@ Success = (1 =:= ets:select_replace(T, [{Old, [], [{const, New}]}])),
</func>
<func>
- <name name="tabfile_info" arity="1"/>
+ <name name="tabfile_info" arity="1" since=""/>
<fsummary>Return a list of all objects in an ETS table.</fsummary>
<desc>
<p>Returns information about the table dumped to file by
@@ -1782,8 +1896,8 @@ Success = (1 =:= ets:select_replace(T, [{Old, [], [{const, New}]}])),
</func>
<func>
- <name name="table" arity="1"/>
- <name name="table" arity="2"/>
+ <name name="table" arity="1" since=""/>
+ <name name="table" arity="2" since=""/>
<fsummary>Return a QLC query handle.</fsummary>
<desc>
<p>Returns a Query List
@@ -1859,7 +1973,7 @@ true</pre>
</func>
<func>
- <name name="take" arity="2"/>
+ <name name="take" arity="2" since="OTP 18.0"/>
<fsummary>Return and remove all objects with a specified key from an
ETS table.</fsummary>
<desc>
@@ -1874,7 +1988,7 @@ true</pre>
</desc>
</func>
<func>
- <name name="test_ms" arity="2"/>
+ <name name="test_ms" arity="2" since=""/>
<fsummary>Test a match specification for use in <c>select/2</c>.
</fsummary>
<desc>
@@ -1901,7 +2015,7 @@ true</pre>
</func>
<func>
- <name name="to_dets" arity="2"/>
+ <name name="to_dets" arity="2" since=""/>
<fsummary>Fill a Dets table with objects from an ETS table.
</fsummary>
<desc>
@@ -1912,12 +2026,12 @@ true</pre>
</func>
<func>
- <name name="update_counter" arity="3" clause_i="1"/>
- <name name="update_counter" arity="4" clause_i="1"/>
- <name name="update_counter" arity="3" clause_i="2"/>
- <name name="update_counter" arity="4" clause_i="2"/>
- <name name="update_counter" arity="3" clause_i="3"/>
- <name name="update_counter" arity="4" clause_i="3"/>
+ <name name="update_counter" arity="3" clause_i="1" since=""/>
+ <name name="update_counter" arity="4" clause_i="1" since="OTP 18.0"/>
+ <name name="update_counter" arity="3" clause_i="2" since=""/>
+ <name name="update_counter" arity="4" clause_i="2" since="OTP 18.0"/>
+ <name name="update_counter" arity="3" clause_i="3" since=""/>
+ <name name="update_counter" arity="4" clause_i="3" since="OTP 18.0"/>
<fsummary>Update a counter object in an ETS table.</fsummary>
<type variable="Tab"/>
<type variable="Key"/>
@@ -1930,9 +2044,8 @@ true</pre>
<p>This function provides an efficient way to update one or more
counters, without the trouble of having to look up an object, update
the object by incrementing an element, and insert the resulting
- object into the table again. (The update is done atomically,
- that is, no process
- can access the ETS table in the middle of the operation.)</p>
+ object into the table again. The operation is guaranteed to be
+ <seealso marker="#concurrency">atomic and isolated</seealso>.</p>
<p>This function destructively update the object with key
<c><anno>Key</anno></c> in table <c><anno>Tab</anno></c> by adding
<c><anno>Incr</anno></c> to the element at position
@@ -1961,7 +2074,7 @@ true</pre>
The return value is a list of the new counter values from each
update operation in the same order as in the operation list. If an
empty list is specified, nothing is updated and an empty list is
- returned. If the function fails, no updates is done.</p>
+ returned. If the function fails, no updates are done.</p>
<p>The specified <c><anno>Key</anno></c> is used to identify the object
by either <em>matching</em> the key of an object in a <c>set</c>
table, or <em>compare equal</em> to the key of an object in an
@@ -1996,8 +2109,8 @@ true</pre>
</func>
<func>
- <name name="update_element" arity="3" clause_i="1"/>
- <name name="update_element" arity="3" clause_i="2"/>
+ <name name="update_element" arity="3" clause_i="1" since=""/>
+ <name name="update_element" arity="3" clause_i="2" since=""/>
<fsummary>Update the <c>Pos</c>:th element of the object with a
specified key in an ETS table.</fsummary>
<type variable="Tab"/>
@@ -2037,6 +2150,21 @@ true</pre>
</list>
</desc>
</func>
+
+ <func>
+ <name name="whereis" arity="1" since="OTP 21.0"/>
+ <fsummary>Retrieves the tid() of a named table.</fsummary>
+ <desc>
+ <p>This function returns the
+ <seealso marker="#type-tid"><c>tid()</c></seealso> of the named table
+ identified by <c><anno>TableName</anno></c>, or <c>undefined</c> if
+ no such table exists. The <c>tid()</c> can be used in place of the
+ table name in all operations, which is slightly faster since the name
+ does not have to be resolved on each call.</p>
+ <p>If the table is deleted, the <c>tid()</c> will be invalid even if
+ another named table is created with the same name.</p>
+ </desc>
+ </func>
</funcs>
</erlref>
diff --git a/lib/stdlib/doc/src/file_sorter.xml b/lib/stdlib/doc/src/file_sorter.xml
index e988d58c2f..942d98fe61 100644
--- a/lib/stdlib/doc/src/file_sorter.xml
+++ b/lib/stdlib/doc/src/file_sorter.xml
@@ -32,7 +32,7 @@
<rev>PA1</rev>
<file>file_sorter.xml</file>
</header>
- <module>file_sorter</module>
+ <module since="">file_sorter</module>
<modulesummary>File sorter.</modulesummary>
<description>
<p>This module contains functions for sorting terms on files, merging
@@ -334,8 +334,8 @@ output(L) ->
<funcs>
<func>
- <name name="check" arity="1"/>
- <name name="check" arity="2"/>
+ <name name="check" arity="1" since=""/>
+ <name name="check" arity="2" since=""/>
<fsummary>Check whether terms on files are sorted.</fsummary>
<desc>
<p>Checks files for sortedness. If a file is not sorted, the
@@ -347,8 +347,8 @@ output(L) ->
</func>
<func>
- <name name="keycheck" arity="2"/>
- <name name="keycheck" arity="3"/>
+ <name name="keycheck" arity="2" since=""/>
+ <name name="keycheck" arity="3" since=""/>
<fsummary>Check whether terms on files are sorted by key.</fsummary>
<desc>
<p>Checks files for sortedness. If a file is not sorted, the
@@ -360,8 +360,8 @@ output(L) ->
</func>
<func>
- <name name="keymerge" arity="3"/>
- <name name="keymerge" arity="4"/>
+ <name name="keymerge" arity="3" since=""/>
+ <name name="keymerge" arity="4" since=""/>
<fsummary>Merge terms on files by key.</fsummary>
<desc>
<p>Merges tuples on files. Each input file is assumed to be
@@ -372,7 +372,7 @@ output(L) ->
</func>
<func>
- <name name="keysort" arity="2"/>
+ <name name="keysort" arity="2" since=""/>
<fsummary>Sort terms on files by key.</fsummary>
<desc>
<p>Sorts tuples on files.</p>
@@ -382,8 +382,8 @@ output(L) ->
</func>
<func>
- <name name="keysort" arity="3"/>
- <name name="keysort" arity="4"/>
+ <name name="keysort" arity="3" since=""/>
+ <name name="keysort" arity="4" since=""/>
<fsummary>Sort terms on files by key.</fsummary>
<desc>
<p>Sorts tuples on files. The sort is performed on the
@@ -397,8 +397,8 @@ output(L) ->
</func>
<func>
- <name name="merge" arity="2"/>
- <name name="merge" arity="3"/>
+ <name name="merge" arity="2" since=""/>
+ <name name="merge" arity="3" since=""/>
<fsummary>Merge terms on files.</fsummary>
<desc>
<p>Merges terms on files. Each input file is assumed to be
@@ -409,7 +409,7 @@ output(L) ->
</func>
<func>
- <name name="sort" arity="1"/>
+ <name name="sort" arity="1" since=""/>
<fsummary>Sort terms on files.</fsummary>
<desc>
<p>Sorts terms on files.</p>
@@ -419,8 +419,8 @@ output(L) ->
</func>
<func>
- <name name="sort" arity="2"/>
- <name name="sort" arity="3"/>
+ <name name="sort" arity="2" since=""/>
+ <name name="sort" arity="3" since=""/>
<fsummary>Sort terms on files.</fsummary>
<desc>
<p>Sorts terms on files.</p>
diff --git a/lib/stdlib/doc/src/filelib.xml b/lib/stdlib/doc/src/filelib.xml
index 11762a3c5a..5df415834f 100644
--- a/lib/stdlib/doc/src/filelib.xml
+++ b/lib/stdlib/doc/src/filelib.xml
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>filelib.xml</file>
</header>
- <module>filelib</module>
+ <module since="">filelib</module>
<modulesummary>File utilities, such as wildcard matching of filenames.
</modulesummary>
<description>
@@ -45,6 +45,30 @@
<p>For more information about raw filenames, see the
<seealso marker="kernel:file"><c>file</c></seealso> module.</p>
+
+ <note>
+ <p>
+ Functionality in this module generally assumes valid input and
+ does not necessarily fail on input that does not use a valid
+ encoding, but may instead very likely produce invalid output.
+ </p>
+ <p>
+ File operations used to accept filenames containing
+ null characters (integer value zero). This caused
+ the name to be truncated and in some cases arguments
+ to primitive operations to be mixed up. Filenames
+ containing null characters inside the filename
+ are now <em>rejected</em> and will cause primitive
+ file operations to fail.
+ </p>
+ </note>
+ <warning><p>
+ Currently null characters at the end of the filename
+ will be accepted by primitive file operations. Such
+ filenames are however still documented as invalid. The
+ implementation will also change in the future and
+ reject such filenames.
+ </p></warning>
</description>
<datatypes>
@@ -70,7 +94,7 @@
<funcs>
<func>
- <name name="ensure_dir" arity="1"/>
+ <name name="ensure_dir" arity="1" since=""/>
<fsummary>Ensure that all parent directories for a file or directory
exist.</fsummary>
<desc>
@@ -84,7 +108,7 @@
</func>
<func>
- <name name="file_size" arity="1"/>
+ <name name="file_size" arity="1" since=""/>
<fsummary>Return the size in bytes of a file.</fsummary>
<desc>
<p>Returns the size of the specified file.</p>
@@ -92,7 +116,7 @@
</func>
<func>
- <name name="fold_files" arity="5"/>
+ <name name="fold_files" arity="5" since=""/>
<fsummary>Fold over all files matching a regular expression.</fsummary>
<desc>
<p>Folds function <c><anno>Fun</anno></c> over all (regular) files
@@ -118,7 +142,7 @@
</func>
<func>
- <name name="is_dir" arity="1"/>
+ <name name="is_dir" arity="1" since=""/>
<fsummary>Test whether <c>Name</c> refers to a directory.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Name</anno></c>
@@ -127,7 +151,7 @@
</func>
<func>
- <name name="is_file" arity="1"/>
+ <name name="is_file" arity="1" since=""/>
<fsummary>Test whether <c>Name</c> refers to a file or directory.
</fsummary>
<desc>
@@ -137,7 +161,7 @@
</func>
<func>
- <name name="is_regular" arity="1"/>
+ <name name="is_regular" arity="1" since=""/>
<fsummary>Test whether <c>Name</c> refers to a (regular) file.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Name</anno></c>
@@ -146,7 +170,7 @@
</func>
<func>
- <name name="last_modified" arity="1"/>
+ <name name="last_modified" arity="1" since=""/>
<fsummary>Return the local date and time when a file was last modified.
</fsummary>
<desc>
@@ -156,7 +180,7 @@
</func>
<func>
- <name name="wildcard" arity="1"/>
+ <name name="wildcard" arity="1" since=""/>
<fsummary>Match filenames using Unix-style wildcards.</fsummary>
<desc>
<p>Returns a list of all files that match Unix-style wildcard string
@@ -193,6 +217,11 @@
<p>Other characters represent themselves. Only filenames that
have exactly the same character in the same position match.
Matching is case-sensitive, for example, "a" does not match "A".</p>
+ <p>Directory separators must always be written as <c>/</c>, even on
+ Windows.</p>
+ <p>A character preceded by <c>\</c> loses its special meaning. Note
+ that <c>\</c> must be written as <c>\\</c> in a string literal.
+ For example, "\\?*" will match any filename starting with <c>?</c>.</p>
<p>Notice that multiple "*" characters are allowed
(as in Unix wildcards, but opposed to Windows/DOS wildcards).</p>
<p><em>Examples:</em></p>
@@ -223,7 +252,7 @@ filelib:wildcard("lib/**/*.{erl,hrl}")</code>
</func>
<func>
- <name name="wildcard" arity="2"/>
+ <name name="wildcard" arity="2" since=""/>
<fsummary>Match filenames using Unix-style wildcards starting at a
specified directory.</fsummary>
<desc>
@@ -234,8 +263,8 @@ filelib:wildcard("lib/**/*.{erl,hrl}")</code>
</func>
<func>
- <name name="find_file" arity="2"/>
- <name name="find_file" arity="3"/>
+ <name name="find_file" arity="2" since="OTP 20.0"/>
+ <name name="find_file" arity="3" since="OTP 20.0"/>
<fsummary>Find a file relative to a given directory.</fsummary>
<desc>
<p>Looks for a file of the given name by applying suffix rules to
@@ -249,7 +278,7 @@ filelib:wildcard("lib/**/*.{erl,hrl}")</code>
</desc>
</func>
<func>
- <name name="find_source" arity="1"/>
+ <name name="find_source" arity="1" since="OTP 20.0"/>
<fsummary>Find the source file for a given object file.</fsummary>
<desc>
<p>Equivalent to <c>find_source(Base, Dir)</c>, where <c>Dir</c> is
@@ -258,8 +287,8 @@ filelib:wildcard("lib/**/*.{erl,hrl}")</code>
</desc>
</func>
<func>
- <name name="find_source" arity="2"/>
- <name name="find_source" arity="3"/>
+ <name name="find_source" arity="2" since="OTP 20.0"/>
+ <name name="find_source" arity="3" since="OTP 20.0"/>
<fsummary>Find a source file relative to a given directory.</fsummary>
<desc>
<p>Applies file extension specific rules to find the source file for
diff --git a/lib/stdlib/doc/src/filename.xml b/lib/stdlib/doc/src/filename.xml
index 1135a6dd80..60b7eb3436 100644
--- a/lib/stdlib/doc/src/filename.xml
+++ b/lib/stdlib/doc/src/filename.xml
@@ -28,7 +28,7 @@
<date>1997-11-13</date>
<rev>B</rev>
</header>
- <module>filename</module>
+ <module since="">filename</module>
<modulesummary>Filename manipulation functions.</modulesummary>
<description>
<p>This module provides functions
@@ -46,7 +46,10 @@
filename by removing redundant directory separators, use
<seealso marker="#join/1"><c>join/1</c></seealso>.</p>
- <p>The module supports raw filenames in the way that if a binary is
+ <p>
+ The module supports
+ <seealso marker="unicode_usage#notes-about-raw-filenames">raw
+ filenames</seealso> in the way that if a binary is
present, or the filename cannot be interpreted according to the return
value of <seealso marker="kernel:file#native_name_encoding/0">
<c>file:native_name_encoding/0</c></seealso>, a raw filename is also
@@ -56,16 +59,35 @@
(the join operation is performed of course). For more information
about raw filenames, see the
<seealso marker="kernel:file"><c>file</c></seealso> module.</p>
+
+ <note>
+ <p>
+ Functionality in this module generally assumes valid input and
+ does not necessarily fail on input that does not use a valid
+ encoding, but may instead very likely produce invalid output.
+ </p>
+ <p>
+ File operations used to accept filenames containing
+ null characters (integer value zero). This caused
+ the name to be truncated and in some cases arguments
+ to primitive operations to be mixed up. Filenames
+ containing null characters inside the filename
+ are now <em>rejected</em> and will cause primitive
+ file operations to fail.
+ </p>
+ </note>
+ <warning><p>
+ Currently null characters at the end of the filename
+ will be accepted by primitive file operations. Such
+ filenames are however still documented as invalid. The
+ implementation will also change in the future and
+ reject such filenames.
+ </p></warning>
</description>
- <datatypes>
- <datatype>
- <name name="basedir_type"/>
- </datatype>
- </datatypes>
<funcs>
<func>
- <name name="absname" arity="1"/>
+ <name name="absname" arity="1" since=""/>
<fsummary>Convert a filename to an absolute name, relative the working
directory.</fsummary>
<desc>
@@ -97,7 +119,7 @@
</func>
<func>
- <name name="absname" arity="2"/>
+ <name name="absname" arity="2" since=""/>
<fsummary>Convert a filename to an absolute name, relative a specified
directory.</fsummary>
<desc>
@@ -108,7 +130,7 @@
</func>
<func>
- <name name="absname_join" arity="2"/>
+ <name name="absname_join" arity="2" since=""/>
<fsummary>Join an absolute directory with a relative filename.</fsummary>
<desc>
<p>Joins an absolute directory with a relative filename. Similar to
@@ -122,18 +144,37 @@
</func>
<func>
- <name name="basedir" arity="2"/>
- <fsummary>Equivalent to <c>basedir(<anno>Type</anno>,<anno>Application</anno>,#{})</c>.</fsummary>
+ <name name="basedir" arity="2" clause_i="1" since="OTP 19.0"/>
+ <name name="basedir" arity="2" clause_i="2" since="OTP 19.0"/>
+ <fsummary>Equivalent to <c>basedir(<anno>PathType</anno>,
+ <anno>Application</anno>,#{})</c> or
+ <c>basedir(<anno>PathsType</anno>, <anno>Application</anno>,#{})</c>.
+ </fsummary>
+ <type variable="PathType" name_i="1"/>
+ <type name="basedir_path_type"/>
+ <type variable="PathsType" name_i="2"/>
+ <type name="basedir_paths_type"/>
+ <type variable="Application"/>
<desc>
<p>
- Equivalent to <seealso marker="#basedir-3">
- basedir(<anno>Type</anno>, <anno>Application</anno>, #{})</seealso>.
+ Equivalent to <seealso marker="#basedir_3_1">
+ basedir(<anno>PathType</anno>, <anno>Application</anno>, #{})</seealso>
+ or <seealso marker="#basedir_3_2">
+basedir(<anno>PathsType</anno>, <anno>Application</anno>, #{})</seealso>.
</p>
</desc>
</func>
<func>
- <name name="basedir" arity="3"/>
+ <name name="basedir" arity="3" clause_i="1" anchor="basedir_3_1" since="OTP 19.0"/>
+ <name name="basedir" arity="3" clause_i="2" anchor="basedir_3_2" since="OTP 19.0"/>
<fsummary></fsummary>
+ <type variable="PathType" name_i="1"/>
+ <type name="basedir_path_type"/>
+ <type variable="PathsType" name_i="2"/>
+ <type name="basedir_paths_type"/>
+ <type variable="Application"/>
+ <type variable="Opts"/>
+ <type name="basedir_opts"/>
<desc><marker id="basedir-3"/>
<p>
Returns a suitable path, or paths, for a given type. If
@@ -273,7 +314,7 @@ true
</desc>
</func>
<func>
- <name name="basename" arity="1"/>
+ <name name="basename" arity="1" since=""/>
<fsummary>Return the last component of a filename.</fsummary>
<desc>
<p>Returns the last component of <c><anno>Filename</anno></c>, or
@@ -291,7 +332,7 @@ true
</func>
<func>
- <name name="basename" arity="2"/>
+ <name name="basename" arity="2" since=""/>
<fsummary>Return the last component of a filename, stripped of the
specified extension.</fsummary>
<desc>
@@ -316,7 +357,7 @@ true
</func>
<func>
- <name name="dirname" arity="1"/>
+ <name name="dirname" arity="1" since=""/>
<fsummary>Return the directory part of a path name.</fsummary>
<desc>
<p>Returns the directory part of <c><anno>Filename</anno></c>.</p>
@@ -333,7 +374,7 @@ true
</func>
<func>
- <name name="extension" arity="1"/>
+ <name name="extension" arity="1" since=""/>
<fsummary>Return the file extension.</fsummary>
<desc>
<p>Returns the file extension of <c><anno>Filename</anno></c>,
@@ -349,8 +390,8 @@ true
</func>
<func>
- <name name="find_src" arity="1"/>
- <name name="find_src" arity="2"/>
+ <name name="find_src" arity="1" since=""/>
+ <name name="find_src" arity="2" since=""/>
<fsummary>Find the filename and compiler options for a module.</fsummary>
<desc>
<p>Finds the source filename and compiler options for a module.
@@ -397,7 +438,7 @@ true
</func>
<func>
- <name name="flatten" arity="1"/>
+ <name name="flatten" arity="1" since=""/>
<fsummary>Convert a filename to a flat string.</fsummary>
<desc>
<p>Converts a possibly deep list filename consisting of
@@ -407,7 +448,7 @@ true
</func>
<func>
- <name name="join" arity="1"/>
+ <name name="join" arity="1" since=""/>
<fsummary>Join a list of filename components with directory separators.
</fsummary>
<desc>
@@ -435,7 +476,7 @@ true
</func>
<func>
- <name name="join" arity="2"/>
+ <name name="join" arity="2" since=""/>
<fsummary>Join two filename components with directory separators.
</fsummary>
<desc>
@@ -446,7 +487,7 @@ true
</func>
<func>
- <name name="nativename" arity="1"/>
+ <name name="nativename" arity="1" since=""/>
<fsummary>Return the native form of a file path.</fsummary>
<desc>
<p>Converts <c><anno>Path</anno></c> to a form accepted by the command
@@ -465,7 +506,7 @@ true
</func>
<func>
- <name name="pathtype" arity="1"/>
+ <name name="pathtype" arity="1" since=""/>
<fsummary>Return the path type.</fsummary>
<desc>
<p>Returns the path type, which is one of the following:</p>
@@ -495,8 +536,8 @@ true
</func>
<func>
- <name name="rootname" arity="1"/>
- <name name="rootname" arity="2"/>
+ <name name="rootname" arity="1" since=""/>
+ <name name="rootname" arity="2" since=""/>
<fsummary>Remove a filename extension.</fsummary>
<desc>
<p>Removes a filename extension. <c>rootname/2</c> works as
@@ -505,7 +546,7 @@ true
<p><em>Examples:</em></p>
<pre>
20> <input>filename:rootname("/beam.src/kalle").</input>
-/beam.src/kalle"
+"/beam.src/kalle"
21> <input>filename:rootname("/beam.src/foo.erl").</input>
"/beam.src/foo"
22> <input>filename:rootname("/beam.src/foo.erl", ".erl").</input>
@@ -516,7 +557,7 @@ true
</func>
<func>
- <name name="safe_relative_path" arity="1"/>
+ <name name="safe_relative_path" arity="1" since="OTP 19.3"/>
<fsummary>Sanitize a relative path to avoid directory traversal attacks.</fsummary>
<desc>
<p>Sanitizes the relative path by eliminating ".." and "."
@@ -543,7 +584,7 @@ unsafe</pre>
</func>
<func>
- <name name="split" arity="1"/>
+ <name name="split" arity="1" since=""/>
<fsummary>Split a filename into its path components.</fsummary>
<desc>
<p>Returns a list whose elements are the path components of
@@ -558,6 +599,7 @@ unsafe</pre>
["a:/","msdev","include"]</pre>
</desc>
</func>
+
</funcs>
</erlref>
diff --git a/lib/stdlib/doc/src/gb_sets.xml b/lib/stdlib/doc/src/gb_sets.xml
index 7bfe477a11..a9596c6e4d 100644
--- a/lib/stdlib/doc/src/gb_sets.xml
+++ b/lib/stdlib/doc/src/gb_sets.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2001</year><year>2016</year>
+ <year>2001</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>gb_sets</module>
+ <module since="">gb_sets</module>
<modulesummary>General balanced trees.</modulesummary>
<description>
<p>This module provides ordered sets using Prof. Arne Andersson's
@@ -83,6 +83,8 @@
</item>
<item><seealso marker="#is_element/2"><c>is_element/2</c></seealso>
</item>
+ <item><seealso marker="#is_empty/1"><c>is_empty/1</c></seealso>
+ </item>
<item><seealso marker="#is_set/1"><c>is_set/1</c></seealso>
</item>
<item><seealso marker="#is_subset/2"><c>is_subset/2</c></seealso>
@@ -121,8 +123,8 @@
<funcs>
<func>
- <name name="add" arity="2"/>
- <name name="add_element" arity="2"/>
+ <name name="add" arity="2" since=""/>
+ <name name="add_element" arity="2" since=""/>
<fsummary>Add a (possibly existing) element to a set.</fsummary>
<desc>
<p>Returns a new set formed from <c><anno>Set1</anno></c> with
@@ -133,7 +135,7 @@
</func>
<func>
- <name name="balance" arity="1"/>
+ <name name="balance" arity="1" since=""/>
<fsummary>Rebalance tree representation of a set.</fsummary>
<desc>
<p>Rebalances the tree representation of <c><anno>Set1</anno></c>.
@@ -147,7 +149,7 @@
</func>
<func>
- <name name="del_element" arity="2"/>
+ <name name="del_element" arity="2" since=""/>
<fsummary>Remove a (possibly non-existing) element from a set.</fsummary>
<desc>
<p>Returns a new set formed from <c><anno>Set1</anno></c> with
@@ -158,7 +160,7 @@
</func>
<func>
- <name name="delete" arity="2"/>
+ <name name="delete" arity="2" since=""/>
<fsummary>Remove an element from a set.</fsummary>
<desc>
<p>Returns a new set formed from <c><anno>Set1</anno></c> with
@@ -169,7 +171,7 @@
</func>
<func>
- <name name="delete_any" arity="2"/>
+ <name name="delete_any" arity="2" since=""/>
<fsummary>Remove a (possibly non-existing) element from a set.</fsummary>
<desc>
<p>Returns a new set formed from <c><anno>Set1</anno></c> with
@@ -180,7 +182,7 @@
</func>
<func>
- <name name="difference" arity="2"/>
+ <name name="difference" arity="2" since=""/>
<fsummary>Return the difference of two sets.</fsummary>
<desc>
<p>Returns only the elements of <c><anno>Set1</anno></c> that are not
@@ -189,7 +191,7 @@
</func>
<func>
- <name name="empty" arity="0"/>
+ <name name="empty" arity="0" since=""/>
<fsummary>Return an empty set.</fsummary>
<desc>
<p>Returns a new empty set.</p>
@@ -197,7 +199,7 @@
</func>
<func>
- <name name="filter" arity="2"/>
+ <name name="filter" arity="2" since=""/>
<fsummary>Filter set elements.</fsummary>
<desc>
<p>Filters elements in <c><anno>Set1</anno></c> using predicate function
@@ -206,7 +208,7 @@
</func>
<func>
- <name name="fold" arity="3"/>
+ <name name="fold" arity="3" since=""/>
<fsummary>Fold over set elements.</fsummary>
<desc>
<p>Folds <c><anno>Function</anno></c> over every element in
@@ -216,7 +218,7 @@
</func>
<func>
- <name name="from_list" arity="1"/>
+ <name name="from_list" arity="1" since=""/>
<fsummary>Convert a list into a set.</fsummary>
<desc>
<p>Returns a set of the elements in <c><anno>List</anno></c>, where
@@ -225,7 +227,7 @@
</func>
<func>
- <name name="from_ordset" arity="1"/>
+ <name name="from_ordset" arity="1" since=""/>
<fsummary>Make a set from an ordset list.</fsummary>
<desc>
<p>Turns an ordered-set list <c><anno>List</anno></c> into a set.
@@ -234,7 +236,7 @@
</func>
<func>
- <name name="insert" arity="2"/>
+ <name name="insert" arity="2" since=""/>
<fsummary>Add a new element to a set.</fsummary>
<desc>
<p>Returns a new set formed from <c><anno>Set1</anno></c> with
@@ -245,7 +247,7 @@
</func>
<func>
- <name name="intersection" arity="1"/>
+ <name name="intersection" arity="1" since=""/>
<fsummary>Return the intersection of a list of sets.</fsummary>
<desc>
<p>Returns the intersection of the non-empty list of sets.</p>
@@ -253,7 +255,7 @@
</func>
<func>
- <name name="intersection" arity="2"/>
+ <name name="intersection" arity="2" since=""/>
<fsummary>Return the intersection of two sets.</fsummary>
<desc>
<p>Returns the intersection of <c><anno>Set1</anno></c> and
@@ -262,7 +264,7 @@
</func>
<func>
- <name name="is_disjoint" arity="2"/>
+ <name name="is_disjoint" arity="2" since=""/>
<fsummary>Check whether two sets are disjoint.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Set1</anno></c> and
@@ -272,7 +274,7 @@
</func>
<func>
- <name name="is_element" arity="2"/>
+ <name name="is_element" arity="2" since=""/>
<fsummary>Test for membership of a set.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Element</anno></c> is an element of
@@ -281,7 +283,7 @@
</func>
<func>
- <name name="is_empty" arity="1"/>
+ <name name="is_empty" arity="1" since=""/>
<fsummary>Test for empty set.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Set</anno></c> is an empty set,
@@ -290,7 +292,7 @@
</func>
<func>
- <name name="is_member" arity="2"/>
+ <name name="is_member" arity="2" since=""/>
<fsummary>Test for membership of a set.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Element</anno></c> is an element of
@@ -299,7 +301,7 @@
</func>
<func>
- <name name="is_set" arity="1"/>
+ <name name="is_set" arity="1" since=""/>
<fsummary>Test for a set.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Term</anno></c> appears to be a set,
@@ -308,7 +310,7 @@
</func>
<func>
- <name name="is_subset" arity="2"/>
+ <name name="is_subset" arity="2" since=""/>
<fsummary>Test for subset.</fsummary>
<desc>
<p>Returns <c>true</c> when every element of <c><anno>Set1</anno></c> is
@@ -317,7 +319,7 @@
</func>
<func>
- <name name="iterator" arity="1"/>
+ <name name="iterator" arity="1" since=""/>
<fsummary>Return an iterator for a set.</fsummary>
<desc>
<p>Returns an iterator that can be used for traversing the entries of
@@ -334,7 +336,7 @@
</func>
<func>
- <name name="iterator_from" arity="2"/>
+ <name name="iterator_from" arity="2" since="OTP 18.0"/>
<fsummary>Return an iterator for a set starting from a specified element.
</fsummary>
<desc>
@@ -349,7 +351,7 @@
</func>
<func>
- <name name="largest" arity="1"/>
+ <name name="largest" arity="1" since=""/>
<fsummary>Return largest element.</fsummary>
<desc>
<p>Returns the largest element in <c><anno>Set</anno></c>. Assumes that
@@ -358,7 +360,7 @@
</func>
<func>
- <name name="new" arity="0"/>
+ <name name="new" arity="0" since=""/>
<fsummary>Return an empty set.</fsummary>
<desc>
<p>Returns a new empty set.</p>
@@ -366,7 +368,7 @@
</func>
<func>
- <name name="next" arity="1"/>
+ <name name="next" arity="1" since=""/>
<fsummary>Traverse a set with an iterator.</fsummary>
<desc>
<p>Returns <c>{<anno>Element</anno>, <anno>Iter2</anno>}</c>, where
@@ -379,7 +381,7 @@
</func>
<func>
- <name name="singleton" arity="1"/>
+ <name name="singleton" arity="1" since=""/>
<fsummary>Return a set with one element.</fsummary>
<desc>
<p>Returns a set containing only element <c><anno>Element</anno></c>.
@@ -388,7 +390,7 @@
</func>
<func>
- <name name="size" arity="1"/>
+ <name name="size" arity="1" since=""/>
<fsummary>Return the number of elements in a set.</fsummary>
<desc>
<p>Returns the number of elements in <c><anno>Set</anno></c>.</p>
@@ -396,7 +398,7 @@
</func>
<func>
- <name name="smallest" arity="1"/>
+ <name name="smallest" arity="1" since=""/>
<fsummary>Return smallest element.</fsummary>
<desc>
<p>Returns the smallest element in <c><anno>Set</anno></c>. Assumes that
@@ -405,7 +407,7 @@
</func>
<func>
- <name name="subtract" arity="2"/>
+ <name name="subtract" arity="2" since=""/>
<fsummary>Return the difference of two sets.</fsummary>
<desc>
<p>Returns only the elements of <c><anno>Set1</anno></c> that are not
@@ -414,7 +416,7 @@
</func>
<func>
- <name name="take_largest" arity="1"/>
+ <name name="take_largest" arity="1" since=""/>
<fsummary>Extract largest element.</fsummary>
<desc>
<p>Returns <c>{<anno>Element</anno>, <anno>Set2</anno>}</c>, where
@@ -426,7 +428,7 @@
</func>
<func>
- <name name="take_smallest" arity="1"/>
+ <name name="take_smallest" arity="1" since=""/>
<fsummary>Extract smallest element.</fsummary>
<desc>
<p>Returns <c>{<anno>Element</anno>, <anno>Set2</anno>}</c>, where
@@ -438,7 +440,7 @@
</func>
<func>
- <name name="to_list" arity="1"/>
+ <name name="to_list" arity="1" since=""/>
<fsummary>Convert a set into a list.</fsummary>
<desc>
<p>Returns the elements of <c><anno>Set</anno></c> as a list.</p>
@@ -446,7 +448,7 @@
</func>
<func>
- <name name="union" arity="1"/>
+ <name name="union" arity="1" since=""/>
<fsummary>Return the union of a list of sets.</fsummary>
<desc>
<p>Returns the merged (union) set of the list of sets.</p>
@@ -454,7 +456,7 @@
</func>
<func>
- <name name="union" arity="2"/>
+ <name name="union" arity="2" since=""/>
<fsummary>Return the union of two sets.</fsummary>
<desc>
<p>Returns the merged (union) set of <c><anno>Set1</anno></c> and
diff --git a/lib/stdlib/doc/src/gb_trees.xml b/lib/stdlib/doc/src/gb_trees.xml
index 5cfff021c1..08aa1865e8 100644
--- a/lib/stdlib/doc/src/gb_trees.xml
+++ b/lib/stdlib/doc/src/gb_trees.xml
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>gb_trees</module>
+ <module since="">gb_trees</module>
<modulesummary>General balanced trees.</modulesummary>
<description>
<p>This module provides Prof. Arne Andersson's General
@@ -42,11 +42,8 @@
<section>
<title>Data Structure</title>
- <code type="none">
-{Size, Tree}</code>
-
- <p><c>Tree</c> is composed of nodes of the form <c>{Key, Value, Smaller,
- Bigger}</c> and the "empty tree" node <c>nil</c>.</p>
+ <p>Trees and iterators are built using opaque data structures that should
+ not be pattern-matched from outside this module.</p>
<p>There is no attempt to balance trees after deletions. As
deletions do not increase the height of a tree, this should be OK.</p>
@@ -75,7 +72,7 @@
<funcs>
<func>
- <name name="balance" arity="1"/>
+ <name name="balance" arity="1" since=""/>
<fsummary>Rebalance a tree.</fsummary>
<desc>
<p>Rebalances <c><anno>Tree1</anno></c>. Notice that this is
@@ -88,7 +85,7 @@
</func>
<func>
- <name name="delete" arity="2"/>
+ <name name="delete" arity="2" since=""/>
<fsummary>Remove a node from a tree.</fsummary>
<desc>
<p>Removes the node with key <c><anno>Key</anno></c> from
@@ -98,7 +95,7 @@
</func>
<func>
- <name name="delete_any" arity="2"/>
+ <name name="delete_any" arity="2" since=""/>
<fsummary>Remove a (possibly non-existing) node from a tree.</fsummary>
<desc>
<p>Removes the node with key <c><anno>Key</anno></c> from
@@ -109,7 +106,7 @@
</func>
<func>
- <name name="take" arity="2"/>
+ <name name="take" arity="2" since="OTP 20.0"/>
<fsummary>Returns a value and new tree without node with key <c>Key</c>.</fsummary>
<desc>
<p>Returns a value <c><anno>Value</anno></c> from node with key <c><anno>Key</anno></c>
@@ -120,7 +117,7 @@
</func>
<func>
- <name name="take_any" arity="2"/>
+ <name name="take_any" arity="2" since="OTP 20.0"/>
<fsummary>Returns a value and new tree without node with key <c>Key</c>.</fsummary>
<desc>
<p>Returns a value <c><anno>Value</anno></c> from node with key <c><anno>Key</anno></c>
@@ -131,7 +128,7 @@
</func>
<func>
- <name name="empty" arity="0"/>
+ <name name="empty" arity="0" since=""/>
<fsummary>Return an empty tree.</fsummary>
<desc>
<p>Returns a new empty tree.</p>
@@ -139,7 +136,7 @@
</func>
<func>
- <name name="enter" arity="3"/>
+ <name name="enter" arity="3" since=""/>
<fsummary>Insert or update key with value in a tree.</fsummary>
<desc>
<p>Inserts <c><anno>Key</anno></c> with value <c><anno>Value</anno></c>
@@ -151,7 +148,7 @@
</func>
<func>
- <name name="from_orddict" arity="1"/>
+ <name name="from_orddict" arity="1" since=""/>
<fsummary>Make a tree from an orddict.</fsummary>
<desc>
<p>Turns an ordered list <c><anno>List</anno></c> of key-value tuples
@@ -160,7 +157,7 @@
</func>
<func>
- <name name="get" arity="2"/>
+ <name name="get" arity="2" since=""/>
<fsummary>Look up a key in a tree, if present.</fsummary>
<desc>
<p>Retrieves the value stored with <c><anno>Key</anno></c> in
@@ -171,7 +168,7 @@
</func>
<func>
- <name name="insert" arity="3"/>
+ <name name="insert" arity="3" since=""/>
<fsummary>Insert a new key and value in a tree.</fsummary>
<desc>
<p>Inserts <c><anno>Key</anno></c> with value <c><anno>Value</anno></c>
@@ -182,7 +179,7 @@
</func>
<func>
- <name name="is_defined" arity="2"/>
+ <name name="is_defined" arity="2" since=""/>
<fsummary>Test for membership of a tree.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Key</anno></c> is present in
@@ -191,7 +188,7 @@
</func>
<func>
- <name name="is_empty" arity="1"/>
+ <name name="is_empty" arity="1" since=""/>
<fsummary>Test for empty tree.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Tree</anno></c> is an empty tree,
@@ -200,7 +197,7 @@
</func>
<func>
- <name name="iterator" arity="1"/>
+ <name name="iterator" arity="1" since=""/>
<fsummary>Return an iterator for a tree.</fsummary>
<desc>
<p>Returns an iterator that can be used for traversing the
@@ -218,7 +215,7 @@
</func>
<func>
- <name name="iterator_from" arity="2"/>
+ <name name="iterator_from" arity="2" since="OTP 18.0"/>
<fsummary>Return an iterator for a tree starting from a specified key.
</fsummary>
<desc>
@@ -233,7 +230,7 @@
</func>
<func>
- <name name="keys" arity="1"/>
+ <name name="keys" arity="1" since=""/>
<fsummary>Return a list of the keys in a tree.</fsummary>
<desc>
<p>Returns the keys in <c><anno>Tree</anno></c> as an ordered list.</p>
@@ -241,7 +238,7 @@
</func>
<func>
- <name name="largest" arity="1"/>
+ <name name="largest" arity="1" since=""/>
<fsummary>Return largest key and value.</fsummary>
<desc>
<p>Returns <c>{<anno>Key</anno>, <anno>Value</anno>}</c>, where
@@ -253,7 +250,7 @@
</func>
<func>
- <name name="lookup" arity="2"/>
+ <name name="lookup" arity="2" since=""/>
<fsummary>Look up a key in a tree.</fsummary>
<desc>
<p>Looks up <c><anno>Key</anno></c> in <c><anno>Tree</anno></c>.
@@ -263,7 +260,7 @@
</func>
<func>
- <name name="map" arity="2"/>
+ <name name="map" arity="2" since=""/>
<fsummary>Return largest key and value.</fsummary>
<desc>
<p>Maps function F(<anno>K</anno>, <anno>V1</anno>) -> <anno>V2</anno>
@@ -275,7 +272,7 @@
</func>
<func>
- <name name="next" arity="1"/>
+ <name name="next" arity="1" since=""/>
<fsummary>Traverse a tree with an iterator.</fsummary>
<desc>
<p>Returns <c>{<anno>Key</anno>, <anno>Value</anno>,
@@ -288,7 +285,7 @@
</func>
<func>
- <name name="size" arity="1"/>
+ <name name="size" arity="1" since=""/>
<fsummary>Return the number of nodes in a tree.</fsummary>
<desc>
<p>Returns the number of nodes in <c><anno>Tree</anno></c>.</p>
@@ -296,7 +293,7 @@
</func>
<func>
- <name name="smallest" arity="1"/>
+ <name name="smallest" arity="1" since=""/>
<fsummary>Return smallest key and value.</fsummary>
<desc>
<p>Returns <c>{<anno>Key</anno>, <anno>Value</anno>}</c>, where
@@ -308,7 +305,7 @@
</func>
<func>
- <name name="take_largest" arity="1"/>
+ <name name="take_largest" arity="1" since=""/>
<fsummary>Extract largest key and value.</fsummary>
<desc>
<p>Returns <c>{<anno>Key</anno>, <anno>Value</anno>,
@@ -321,7 +318,7 @@
</func>
<func>
- <name name="take_smallest" arity="1"/>
+ <name name="take_smallest" arity="1" since=""/>
<fsummary>Extract smallest key and value.</fsummary>
<desc>
<p>Returns <c>{<anno>Key</anno>, <anno>Value</anno>,
@@ -334,7 +331,7 @@
</func>
<func>
- <name name="to_list" arity="1"/>
+ <name name="to_list" arity="1" since=""/>
<fsummary>Convert a tree into a list.</fsummary>
<desc>
<p>Converts a tree into an ordered list of key-value tuples.</p>
@@ -342,7 +339,7 @@
</func>
<func>
- <name name="update" arity="3"/>
+ <name name="update" arity="3" since=""/>
<fsummary>Update a key to new value in a tree.</fsummary>
<desc>
<p>Updates <c><anno>Key</anno></c> to value <c><anno>Value</anno></c>
@@ -352,7 +349,7 @@
</func>
<func>
- <name name="values" arity="1"/>
+ <name name="values" arity="1" since=""/>
<fsummary>Return a list of the values in a tree.</fsummary>
<desc>
<p>Returns the values in <c><anno>Tree</anno></c> as an ordered list,
diff --git a/lib/stdlib/doc/src/gen_event.xml b/lib/stdlib/doc/src/gen_event.xml
index 012737c390..2915c4f507 100644
--- a/lib/stdlib/doc/src/gen_event.xml
+++ b/lib/stdlib/doc/src/gen_event.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>gen_event</module>
+ <module since="">gen_event</module>
<modulesummary>Generic event handling behavior.</modulesummary>
<description>
<p>This behavior module provides event handling functionality. It
@@ -130,7 +130,7 @@ gen_event:stop -----> Module:terminate/2
<funcs>
<func>
- <name>add_handler(EventMgrRef, Handler, Args) -> Result</name>
+ <name since="">add_handler(EventMgrRef, Handler, Args) -> Result</name>
<fsummary>Add an event handler to a generic event manager.</fsummary>
<type>
<v>EventMgrRef = Name | {Name,Node} | {global,GlobalName}
@@ -178,7 +178,7 @@ gen_event:stop -----> Module:terminate/2
</func>
<func>
- <name>add_sup_handler(EventMgrRef, Handler, Args) -> Result</name>
+ <name since="">add_sup_handler(EventMgrRef, Handler, Args) -> Result</name>
<fsummary>Add a supervised event handler to a generic event manager.
</fsummary>
<type>
@@ -207,7 +207,7 @@ gen_event:stop -----> Module:terminate/2
</item>
<item>
<p>If the event handler is deleted later, the event manager
- sends a message<c>{gen_event_EXIT,Handler,Reason}</c> to
+ sends a message <c>{gen_event_EXIT,Handler,Reason}</c> to
the calling process. <c>Reason</c> is one of the following:</p>
<list type="bulleted">
<item>
@@ -241,8 +241,8 @@ gen_event:stop -----> Module:terminate/2
</func>
<func>
- <name>call(EventMgrRef, Handler, Request) -> Result</name>
- <name>call(EventMgrRef, Handler, Request, Timeout) -> Result</name>
+ <name since="">call(EventMgrRef, Handler, Request) -> Result</name>
+ <name since="">call(EventMgrRef, Handler, Request, Timeout) -> Result</name>
<fsummary>Make a synchronous call to a generic event manager.</fsummary>
<type>
<v>EventMgrRef = Name | {Name,Node} | {global,GlobalName}
@@ -285,7 +285,7 @@ gen_event:stop -----> Module:terminate/2
</func>
<func>
- <name>delete_handler(EventMgrRef, Handler, Args) -> Result</name>
+ <name since="">delete_handler(EventMgrRef, Handler, Args) -> Result</name>
<fsummary>Delete an event handler from a generic event manager.</fsummary>
<type>
<v>EventMgrRef = Name | {Name,Node} | {global,GlobalName}
@@ -318,8 +318,8 @@ gen_event:stop -----> Module:terminate/2
</func>
<func>
- <name>notify(EventMgrRef, Event) -> ok</name>
- <name>sync_notify(EventMgrRef, Event) -> ok</name>
+ <name since="">notify(EventMgrRef, Event) -> ok</name>
+ <name since="">sync_notify(EventMgrRef, Event) -> ok</name>
<fsummary>Notify an event manager about an event.</fsummary>
<type>
<v>EventMgrRef = Name | {Name,Node} | {global,GlobalName}
@@ -349,9 +349,9 @@ gen_event:stop -----> Module:terminate/2
</func>
<func>
- <name>start() -> Result</name>
- <name>start(EventMgrName | Options) -> Result</name>
- <name>start(EventMgrName, Options) -> Result</name>
+ <name since="">start() -> Result</name>
+ <name since="">start(EventMgrName | Options) -> Result</name>
+ <name since="OTP 20.0">start(EventMgrName, Options) -> Result</name>
<fsummary>Create a stand-alone event manager process.</fsummary>
<type>
<v>EventMgrName = {local,Name} | {global,GlobalName} | {via,Module,ViaName}</v>
@@ -375,9 +375,9 @@ gen_event:stop -----> Module:terminate/2
</func>
<func>
- <name>start_link() -> Result</name>
- <name>start_link(EventMgrName | Options) -> Result</name>
- <name>start_link(EventMgrName, Options) -> Result</name>
+ <name since="">start_link() -> Result</name>
+ <name since="">start_link(EventMgrName | Options) -> Result</name>
+ <name since="OTP 20.0">start_link(EventMgrName, Options) -> Result</name>
<fsummary>Create a generic event manager process in a supervision tree.
</fsummary>
<type>
@@ -436,8 +436,8 @@ gen_event:stop -----> Module:terminate/2
</func>
<func>
- <name>stop(EventMgrRef) -> ok</name>
- <name>stop(EventMgrRef, Reason, Timeout) -> ok</name>
+ <name since="">stop(EventMgrRef) -> ok</name>
+ <name since="OTP 18.0">stop(EventMgrRef, Reason, Timeout) -> ok</name>
<fsummary>Terminate a generic event manager.</fsummary>
<type>
<v>EventMgrRef = Name | {Name,Node} | {global,GlobalName}
@@ -458,8 +458,7 @@ gen_event:stop -----> Module:terminate/2
with the expected reason. Any other reason than <c>normal</c>,
<c>shutdown</c>, or <c>{shutdown,Term}</c> causes an
error report to be issued using
- <seealso marker="kernel:error_logger#format/2">
- <c>error_logger:format/2</c></seealso>.
+ <seealso marker="kernel:logger"><c>logger(3)</c></seealso>.
The default <c>Reason</c> is <c>normal</c>.</p>
<p><c>Timeout</c> is an integer greater than zero that
specifies how many milliseconds to wait for the event manager to
@@ -475,7 +474,7 @@ gen_event:stop -----> Module:terminate/2
</func>
<func>
- <name>swap_handler(EventMgrRef, {Handler1,Args1}, {Handler2,Args2}) -> Result</name>
+ <name since="">swap_handler(EventMgrRef, {Handler1,Args1}, {Handler2,Args2}) -> Result</name>
<fsummary>Replace an event handler in a generic event manager.</fsummary>
<type>
<v>EventMgrRef = Name | {Name,Node} | {global,GlobalName}
@@ -522,7 +521,7 @@ gen_event:stop -----> Module:terminate/2
</func>
<func>
- <name>swap_sup_handler(EventMgrRef, {Handler1,Args1}, {Handler2,Args2}) -> Result</name>
+ <name since="">swap_sup_handler(EventMgrRef, {Handler1,Args1}, {Handler2,Args2}) -> Result</name>
<fsummary>Replace an event handler in a generic event manager.</fsummary>
<type>
<v>EventMgrRef = Name | {Name,Node} | {global,GlobalName}
@@ -547,7 +546,7 @@ gen_event:stop -----> Module:terminate/2
</func>
<func>
- <name>which_handlers(EventMgrRef) -> [Handler]</name>
+ <name since="">which_handlers(EventMgrRef) -> [Handler]</name>
<fsummary>Return all event handlers installed in a generic event manager.
</fsummary>
<type>
@@ -576,7 +575,7 @@ gen_event:stop -----> Module:terminate/2
<funcs>
<func>
- <name>Module:code_change(OldVsn, State, Extra) -> {ok, NewState}</name>
+ <name since="">Module:code_change(OldVsn, State, Extra) -> {ok, NewState}</name>
<fsummary>Update the internal state during upgrade/downgrade.</fsummary>
<type>
<v>OldVsn = Vsn | {down, Vsn}</v>
@@ -612,7 +611,7 @@ gen_event:stop -----> Module:terminate/2
</func>
<func>
- <name>Module:format_status(Opt, [PDict, State]) -> Status</name>
+ <name since="OTP R14B">Module:format_status(Opt, [PDict, State]) -> Status</name>
<fsummary>Optional function for providing a term describing the
current event handler state.</fsummary>
<type>
@@ -668,7 +667,7 @@ gen_event:stop -----> Module:terminate/2
</func>
<func>
- <name>Module:handle_call(Request, State) -> Result</name>
+ <name since="">Module:handle_call(Request, State) -> Result</name>
<fsummary>Handle a synchronous request.</fsummary>
<type>
<v>Request = term()</v>
@@ -699,7 +698,7 @@ gen_event:stop -----> Module:terminate/2
</func>
<func>
- <name>Module:handle_event(Event, State) -> Result</name>
+ <name since="">Module:handle_event(Event, State) -> Result</name>
<fsummary>Handle an event.</fsummary>
<type>
<v>Event = term()</v>
@@ -757,7 +756,7 @@ gen_event:stop -----> Module:terminate/2
</func>
<func>
- <name>Module:handle_info(Info, State) -> Result</name>
+ <name since="">Module:handle_info(Info, State) -> Result</name>
<fsummary>Handle an incoming message.</fsummary>
<type>
<v>Info = term()</v>
@@ -776,7 +775,7 @@ gen_event:stop -----> Module:terminate/2
<p>This callback is optional, so callback modules need not
export it. The <c>gen_event</c> module provides a default
implementation of this function that logs about the unexpected
- <c>Info</c> message, drops it and returns <c>{noreply, State}</c>.</p>
+ <c>Info</c> message, drops it and returns <c>{ok, State}</c>.</p>
</note>
<p>This function is called for each installed event handler when
an event manager receives any other message than an event or
@@ -789,7 +788,7 @@ gen_event:stop -----> Module:terminate/2
</func>
<func>
- <name>Module:init(InitArgs) -> {ok,State} | {ok,State,hibernate} | {error,Reason}</name>
+ <name since="">Module:init(InitArgs) -> {ok,State} | {ok,State,hibernate} | {error,Reason}</name>
<fsummary>Initialize an event handler.</fsummary>
<type>
<v>InitArgs = Args | {Args,Term}</v>
@@ -826,7 +825,7 @@ gen_event:stop -----> Module:terminate/2
</func>
<func>
- <name>Module:terminate(Arg, State) -> term()</name>
+ <name since="">Module:terminate(Arg, State) -> term()</name>
<fsummary>Clean up before deletion.</fsummary>
<type>
<v>Arg = Args | {stop,Reason} | stop | remove_handler</v>
diff --git a/lib/stdlib/doc/src/gen_server.xml b/lib/stdlib/doc/src/gen_server.xml
index 7d137fc772..a4554d7657 100644
--- a/lib/stdlib/doc/src/gen_server.xml
+++ b/lib/stdlib/doc/src/gen_server.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>gen_server</module>
+ <module since="">gen_server</module>
<modulesummary>Generic server behavior.</modulesummary>
<description>
<p>This behavior module provides the server of a client-server
@@ -60,6 +60,8 @@ gen_server:abcast -----> Module:handle_cast/2
- -----> Module:handle_info/2
+- -----> Module:handle_continue/2
+
- -----> Module:terminate/2
- -----> Module:code_change/3</pre>
@@ -88,12 +90,19 @@ gen_server:abcast -----> Module:handle_cast/2
implies at least two garbage collections (when hibernating and
shortly after waking up) and is not something you want to do
between each call to a busy server.</p>
+
+ <p>If the <c>gen_server</c> process needs to perform an action
+ immediately after initialization or to break the execution of a
+ callback into multiple steps, it can return <c>{continue,Continue}</c>
+ in place of the time-out or hibernation value, which will immediately
+ invoke the <c>handle_continue/2</c> callback.</p>
+
</description>
<funcs>
<func>
- <name>abcast(Name, Request) -> abcast</name>
- <name>abcast(Nodes, Name, Request) -> abcast</name>
+ <name since="">abcast(Name, Request) -> abcast</name>
+ <name since="">abcast(Nodes, Name, Request) -> abcast</name>
<fsummary>Send an asynchronous request to many generic servers.</fsummary>
<type>
<v>Nodes = [Node]</v>
@@ -115,8 +124,8 @@ gen_server:abcast -----> Module:handle_cast/2
</func>
<func>
- <name>call(ServerRef, Request) -> Reply</name>
- <name>call(ServerRef, Request, Timeout) -> Reply</name>
+ <name since="">call(ServerRef, Request) -> Reply</name>
+ <name since="">call(ServerRef, Request, Timeout) -> Reply</name>
<fsummary>Make a synchronous call to a generic server.</fsummary>
<type>
<v>ServerRef = Name | {Name,Node} | {global,GlobalName}</v>
@@ -166,7 +175,7 @@ gen_server:abcast -----> Module:handle_cast/2
</func>
<func>
- <name>cast(ServerRef, Request) -> ok</name>
+ <name since="">cast(ServerRef, Request) -> ok</name>
<fsummary>Send an asynchronous request to a generic server.</fsummary>
<type>
<v>ServerRef = Name | {Name,Node} | {global,GlobalName}</v>
@@ -191,10 +200,10 @@ gen_server:abcast -----> Module:handle_cast/2
</func>
<func>
- <name>enter_loop(Module, Options, State)</name>
- <name>enter_loop(Module, Options, State, ServerName)</name>
- <name>enter_loop(Module, Options, State, Timeout)</name>
- <name>enter_loop(Module, Options, State, ServerName, Timeout)</name>
+ <name since="">enter_loop(Module, Options, State)</name>
+ <name since="">enter_loop(Module, Options, State, ServerName)</name>
+ <name since="">enter_loop(Module, Options, State, Timeout)</name>
+ <name since="">enter_loop(Module, Options, State, ServerName, Timeout)</name>
<fsummary>Enter the <c>gen_server</c> receive loop.</fsummary>
<type>
<v>Module = atom()</v>
@@ -239,9 +248,9 @@ gen_server:abcast -----> Module:handle_cast/2
</func>
<func>
- <name>multi_call(Name, Request) -> Result</name>
- <name>multi_call(Nodes, Name, Request) -> Result</name>
- <name>multi_call(Nodes, Name, Request, Timeout) -> Result</name>
+ <name since="">multi_call(Name, Request) -> Result</name>
+ <name since="">multi_call(Nodes, Name, Request) -> Result</name>
+ <name since="">multi_call(Nodes, Name, Request, Timeout) -> Result</name>
<fsummary>Make a synchronous call to many generic servers.</fsummary>
<type>
<v>Nodes = [Node]</v>
@@ -298,7 +307,7 @@ gen_server:abcast -----> Module:handle_cast/2
</func>
<func>
- <name>reply(Client, Reply) -> Result</name>
+ <name since="">reply(Client, Reply) -> Result</name>
<fsummary>Send a reply to a client.</fsummary>
<type>
<v>Client - see below</v>
@@ -323,8 +332,8 @@ gen_server:abcast -----> Module:handle_cast/2
</func>
<func>
- <name>start(Module, Args, Options) -> Result</name>
- <name>start(ServerName, Module, Args, Options) -> Result</name>
+ <name since="">start(Module, Args, Options) -> Result</name>
+ <name since="">start(ServerName, Module, Args, Options) -> Result</name>
<fsummary>Create a standalone <c>gen_server</c> process.</fsummary>
<type>
<v>ServerName = {local,Name} | {global,GlobalName}</v>
@@ -352,8 +361,8 @@ gen_server:abcast -----> Module:handle_cast/2
</func>
<func>
- <name>start_link(Module, Args, Options) -> Result</name>
- <name>start_link(ServerName, Module, Args, Options) -> Result</name>
+ <name since="">start_link(Module, Args, Options) -> Result</name>
+ <name since="">start_link(ServerName, Module, Args, Options) -> Result</name>
<fsummary>Create a <c>gen_server</c> process in a supervision tree.
</fsummary>
<type>
@@ -457,8 +466,8 @@ gen_server:abcast -----> Module:handle_cast/2
</func>
<func>
- <name>stop(ServerRef) -> ok</name>
- <name>stop(ServerRef, Reason, Timeout) -> ok</name>
+ <name since="OTP 18.0">stop(ServerRef) -> ok</name>
+ <name since="OTP 18.0">stop(ServerRef, Reason, Timeout) -> ok</name>
<fsummary>Synchronously stop a generic server.</fsummary>
<type>
<v>ServerRef = Name | {Name,Node} | {global,GlobalName}</v>
@@ -477,8 +486,7 @@ gen_server:abcast -----> Module:handle_cast/2
with the expected reason. Any other reason than <c>normal</c>,
<c>shutdown</c>, or <c>{shutdown,Term}</c> causes an
error report to be issued using
- <seealso marker="kernel:error_logger#format/2">
- <c>error_logger:format/2</c></seealso>.
+ <seealso marker="kernel:logger"><c>logger(3)</c></seealso>.
The default <c>Reason</c> is <c>normal</c>.</p>
<p><c>Timeout</c> is an integer greater than zero that
specifies how many milliseconds to wait for the server to
@@ -500,7 +508,7 @@ gen_server:abcast -----> Module:handle_cast/2
<funcs>
<func>
- <name>Module:code_change(OldVsn, State, Extra) -> {ok, NewState} | {error, Reason}</name>
+ <name since="">Module:code_change(OldVsn, State, Extra) -> {ok, NewState} | {error, Reason}</name>
<fsummary>Update the internal state during upgrade/downgrade.</fsummary>
<type>
<v>OldVsn = Vsn | {down, Vsn}</v>
@@ -542,7 +550,7 @@ gen_server:abcast -----> Module:handle_cast/2
</func>
<func>
- <name>Module:format_status(Opt, [PDict, State]) -> Status</name>
+ <name since="OTP R13B04">Module:format_status(Opt, [PDict, State]) -> Status</name>
<fsummary>Optional function for providing a term describing the
current <c>gen_server</c> status.</fsummary>
<type>
@@ -602,7 +610,7 @@ gen_server:abcast -----> Module:handle_cast/2
</func>
<func>
- <name>Module:handle_call(Request, From, State) -> Result</name>
+ <name since="">Module:handle_call(Request, From, State) -> Result</name>
<fsummary>Handle a synchronous request.</fsummary>
<type>
<v>Request = term()</v>
@@ -610,12 +618,15 @@ gen_server:abcast -----> Module:handle_cast/2
<v>State = term()</v>
<v>Result = {reply,Reply,NewState} | {reply,Reply,NewState,Timeout}</v>
<v>&nbsp;&nbsp;| {reply,Reply,NewState,hibernate}</v>
+ <v>&nbsp;&nbsp;| {reply,Reply,NewState,{continue,Continue}}</v>
<v>&nbsp;&nbsp;| {noreply,NewState} | {noreply,NewState,Timeout}</v>
<v>&nbsp;&nbsp;| {noreply,NewState,hibernate}</v>
+ <v>&nbsp;&nbsp;| {noreply,NewState,{continue,Continue}}</v>
<v>&nbsp;&nbsp;| {stop,Reason,Reply,NewState} | {stop,Reason,NewState}</v>
<v>&nbsp;Reply = term()</v>
<v>&nbsp;NewState = term()</v>
<v>&nbsp;Timeout = int()>=0 | infinity</v>
+ <v>&nbsp;Continue = term()</v>
<v>&nbsp;Reason = term()</v>
</type>
<desc>
@@ -666,16 +677,18 @@ gen_server:abcast -----> Module:handle_cast/2
</func>
<func>
- <name>Module:handle_cast(Request, State) -> Result</name>
+ <name since="">Module:handle_cast(Request, State) -> Result</name>
<fsummary>Handle an asynchronous request.</fsummary>
<type>
<v>Request = term()</v>
<v>State = term()</v>
<v>Result = {noreply,NewState} | {noreply,NewState,Timeout}</v>
<v>&nbsp;&nbsp;| {noreply,NewState,hibernate}</v>
+ <v>&nbsp;&nbsp;| {noreply,NewState,{continue,Continue}}</v>
<v>&nbsp;&nbsp;| {stop,Reason,NewState}</v>
<v>&nbsp;NewState = term()</v>
<v>&nbsp;Timeout = int()>=0 | infinity</v>
+ <v>&nbsp;Continue = term()</v>
<v>&nbsp;Reason = term()</v>
</type>
<desc>
@@ -690,13 +703,49 @@ gen_server:abcast -----> Module:handle_cast/2
</func>
<func>
- <name>Module:handle_info(Info, State) -> Result</name>
+ <name since="OTP 21.0">Module:handle_continue(Continue, State) -> Result</name>
+ <fsummary>Handle a continue instruction.</fsummary>
+ <type>
+ <v>Continue = term()</v>
+ <v>State = term()</v>
+ <v>Result = {noreply,NewState} | {noreply,NewState,Timeout}</v>
+ <v>&nbsp;&nbsp;| {noreply,NewState,hibernate}</v>
+ <v>&nbsp;&nbsp;| {noreply,NewState,{continue,Continue}}</v>
+ <v>&nbsp;&nbsp;| {stop,Reason,NewState}</v>
+ <v>&nbsp;NewState = term()</v>
+ <v>&nbsp;Timeout = int()>=0 | infinity</v>
+ <v>&nbsp;Continue = term()</v>
+ <v>&nbsp;Reason = normal | term()</v>
+ </type>
+ <desc>
+ <note>
+ <p>This callback is optional, so callback modules need to
+ export it only if they return <c>{continue,Continue}</c>
+ from another callback. If continue is used and the callback
+ is not implemented, the process will exit with <c>undef</c>
+ error.</p>
+ </note>
+ <p>This function is called by a <c>gen_server</c> process whenever
+ a previous callback returns <c>{continue, Continue}</c>.
+ <c>handle_continue/2</c> is invoked immediately after the previous
+ callback, which makes it useful for performing work after
+ initialization or for splitting the work in a callback in
+ multiple steps, updating the process state along the way.</p>
+ <p>For a description of the other arguments and possible return values,
+ see <seealso marker="#Module:handle_call/3">
+ <c>Module:handle_call/3</c></seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">Module:handle_info(Info, State) -> Result</name>
<fsummary>Handle an incoming message.</fsummary>
<type>
<v>Info = timeout | term()</v>
<v>State = term()</v>
<v>Result = {noreply,NewState} | {noreply,NewState,Timeout}</v>
<v>&nbsp;&nbsp;| {noreply,NewState,hibernate}</v>
+ <v>&nbsp;&nbsp;| {noreply,NewState,{continue,Continue}}</v>
<v>&nbsp;&nbsp;| {stop,Reason,NewState}</v>
<v>&nbsp;NewState = term()</v>
<v>&nbsp;Timeout = int()>=0 | infinity</v>
@@ -721,12 +770,12 @@ gen_server:abcast -----> Module:handle_cast/2
</func>
<func>
- <name>Module:init(Args) -> Result</name>
+ <name since="">Module:init(Args) -> Result</name>
<fsummary>Initialize process and internal state.</fsummary>
<type>
<v>Args = term()</v>
<v>Result = {ok,State} | {ok,State,Timeout} | {ok,State,hibernate}</v>
- <v>&nbsp;| {stop,Reason} | ignore</v>
+ <v>&nbsp;| {ok,State,{continue,Continue}} | {stop,Reason} | ignore</v>
<v>&nbsp;State = term()</v>
<v>&nbsp;Timeout = int()>=0 | infinity</v>
<v>&nbsp;Reason = term()</v>
@@ -762,7 +811,7 @@ gen_server:abcast -----> Module:handle_cast/2
</func>
<func>
- <name>Module:terminate(Reason, State)</name>
+ <name since="">Module:terminate(Reason, State)</name>
<fsummary>Clean up before termination.</fsummary>
<type>
<v>Reason = normal | shutdown | {shutdown,term()} | term()</v>
@@ -811,8 +860,7 @@ gen_server:abcast -----> Module:handle_cast/2
<c>shutdown</c>, or <c>{shutdown,Term}</c>, the <c>gen_server</c>
process is assumed to terminate because of an error and
an error report is issued using
- <seealso marker="kernel:error_logger#format/2">
- <c>error_logger:format/2</c></seealso>.</p>
+ <seealso marker="kernel:logger"><c>logger(3)</c></seealso>.</p>
</desc>
</func>
</funcs>
diff --git a/lib/stdlib/doc/src/gen_statem.xml b/lib/stdlib/doc/src/gen_statem.xml
index 574f488e91..6f6849a19d 100644
--- a/lib/stdlib/doc/src/gen_statem.xml
+++ b/lib/stdlib/doc/src/gen_statem.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2016</year><year>2017</year>
+ <year>2016</year><year>2019</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -28,11 +28,72 @@
<date></date>
<rev></rev>
</header>
- <module>gen_statem</module>
+ <module since="OTP 19.0">gen_statem</module>
<modulesummary>Generic state machine behavior.</modulesummary>
<description>
<p>
- This behavior module provides a state machine. Two
+ <c>gen_statem</c> provides a generic state machine behaviour
+ and replaces its predecessor
+ <seealso marker="gen_fsm"><c>gen_fsm</c></seealso>
+ since Erlang/OTP 20.0.
+ </p>
+ <p>
+ This reference manual describes types generated from the types
+ in the <c>gen_statem</c> source code, so they are correct.
+ However, the generated descriptions also reflect the type hiearchy,
+ which makes them kind of hard to read.
+ </p>
+ <p>
+ To get an overview of the concepts and operation of <c>gen_statem</c>,
+ do read the
+ <seealso marker="doc/design_principles:statem">
+ <c>gen_statem</c>&nbsp;Behaviour
+ </seealso>
+ in
+ <seealso marker="doc/design_principles:users_guide">
+ OTP Design Principles
+ </seealso>
+ which frequently links back to this reference manual to avoid
+ containing detailed facts that may rot by age.
+ </p>
+ <note>
+ <p>
+ This behavior appeared in Erlang/OTP 19.0.
+ In OTP 19.1 a backwards incompatible change of
+ the return tuple from
+ <seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
+ was made and the mandatory callback function
+ <seealso marker="#Module:callback_mode/0">
+ <c>Module:callback_mode/0</c>
+ </seealso>
+ was introduced. In OTP 20.0 the
+ <seealso marker="#type-generic_timeout"><c>generic timeouts</c></seealso>
+ were added.
+ </p>
+ </note>
+ <p>
+ <c>gen_statem</c> has got the same features that
+ <seealso marker="gen_fsm"><c>gen_fsm</c></seealso>
+ had and adds some really useful:
+ </p>
+ <list type="bulleted">
+ <item>Co-located state code</item>
+ <item>Arbitrary term state</item>
+ <item>Event postponing</item>
+ <item>Self-generated events</item>
+ <item>State time-out</item>
+ <item>Multiple generic named time-outs</item>
+ <item>Absolute time-out time</item>
+ <item>Automatic state enter calls</item>
+ <item>
+ Reply from other state than the request, <c>sys</c> traceable
+ </item>
+ <item>Multiple <c>sys</c> traceable replies</item>
+ </list>
+
+
+ <p>
+ Two
<seealso marker="#type-callback_mode"><em>callback modes</em></seealso>
are supported:
</p>
@@ -50,34 +111,6 @@
</p>
</item>
</list>
- <note>
- <p>
- This is a new behavior in Erlang/OTP 19.0.
- It has been thoroughly reviewed, is stable enough
- to be used by at least two heavy OTP applications,
- and is here to stay.
- Depending on user feedback, we do not expect
- but can find it necessary to make minor
- not backward compatible changes into Erlang/OTP 20.0.
- </p>
- </note>
- <p>
- The <c>gen_statem</c> behavior replaces
- <seealso marker="gen_fsm"><c>gen_fsm</c> </seealso> in Erlang/OTP 20.0.
- It has the same features and adds some really useful:
- </p>
- <list type="bulleted">
- <item>Gathered state code.</item>
- <item>Arbitrary term state.</item>
- <item>Event postponing.</item>
- <item>Self-generated events.</item>
- <item>State time-out.</item>
- <item>Multiple generic named time-outs.</item>
- <item>Absolute time-out time.</item>
- <item>Automatic state enter calls.</item>
- <item>Reply from other state than the request.</item>
- <item>Multiple <c>sys</c> traceable replies.</item>
- </list>
<p>
The callback model(s) for <c>gen_statem</c> differs from
the one for <seealso marker="gen_fsm"><c>gen_fsm</c></seealso>,
@@ -134,7 +167,7 @@ erlang:'!' -----> Module:StateName/3
</p>
<marker id="state callback"/>
<p>
- The "<em>state callback</em>" for a specific
+ The <em>state callback</em> for a specific
<seealso marker="#type-state">state</seealso>
in a <c>gen_statem</c> is the callback function that is called
for all events in this state. It is selected depending on which
@@ -146,9 +179,9 @@ erlang:'!' -----> Module:StateName/3
When the
<seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
is <c>state_functions</c>, the state must be an atom and
- is used as the state callback name; see
+ is used as the <em>state callback</em> name; see
<seealso marker="#Module:StateName/3"><c>Module:StateName/3</c></seealso>.
- This gathers all code for a specific state
+ This co-locates all code for a specific state
in one function as the <c>gen_statem</c> engine
branches depending on state name.
Note the fact that the callback function
@@ -159,7 +192,7 @@ erlang:'!' -----> Module:StateName/3
When the
<seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
is <c>handle_event_function</c>, the state can be any term
- and the state callback name is
+ and the <em>state callback</em> name is
<seealso marker="#Module:handle_event/4"><c>Module:handle_event/4</c></seealso>.
This makes it easy to branch depending on state or event as you desire.
Be careful about which events you handle in which
@@ -167,12 +200,36 @@ erlang:'!' -----> Module:StateName/3
forever creating an infinite busy loop.
</p>
<p>
- The <c>gen_statem</c> enqueues incoming events in order of arrival
- and presents these to the
- <seealso marker="#state callback">state callback</seealso>
- in that order. The state callback can postpone an event
- so it is not retried in the current state.
- After a state change the queue restarts with the postponed events.
+ When <c>gen_statem</c> receives a process message it is
+ converted into an event and the
+ <seealso marker="#state callback"><em>state callback</em></seealso>
+ is called with the event as two arguments: type and content.
+ When the
+ <seealso marker="#state callback"><em>state callback</em></seealso>
+ has processed the event it returns to <c>gen_statem</c>
+ which does a <em>state transition</em>.
+ If this <em>state transition</em> is to a different state,
+ that is: <c>NextState =/= State</c>, it is a <em>state change</em>.
+ </p>
+ <p>
+ The
+ <seealso marker="#state callback"><em>state callback</em></seealso>
+ may return
+ <seealso marker="#type-action"><em>transition actions</em></seealso>
+ for <c>gen_statem</c>
+ to execute during the <em>state transition</em>,
+ for example to reply to a
+ <seealso marker="#call/2"><c>gen_statem:call/2,3</c></seealso>.
+ </p>
+ <p>
+ One of the possible <em>transition actions</em>
+ is to postpone the current event.
+ Then it is not retried in the current state.
+ The <c>gen_statem</c> engine keeps a queue of events
+ divided into the postponed events
+ and the events still to process.
+ After a <em>state change</em> the queue restarts
+ with the postponed events.
</p>
<p>
The <c>gen_statem</c> event queue model is sufficient
@@ -182,13 +239,17 @@ erlang:'!' -----> Module:StateName/3
to entering a new receive statement.
</p>
<p>
- The <seealso marker="#state callback">state callback</seealso>
+ The
+ <seealso marker="#state callback"><em>state callback</em></seealso>
can insert events using the
- <seealso marker="#type-action"><c>action()</c></seealso>
+ <seealso marker="#type-action"><em>transition actions</em></seealso>
<c>next_event</c>
- and such an event is inserted as the next to present
- to the state callback. That is, as if it is
- the oldest incoming event. A dedicated
+ and such an event is inserted in the event queue
+ as the next to call the
+ <seealso marker="#state callback"><em>state callback</em></seealso>
+ with.
+ That is, as if it is the oldest incoming event.
+ A dedicated
<seealso marker="#type-event_type"><c>event_type()</c></seealso>
<c>internal</c> can be used for such events making them impossible
to mistake for external events.
@@ -203,22 +264,26 @@ erlang:'!' -----> Module:StateName/3
<p>
The <c>gen_statem</c> engine can automatically
make a specialized call to the
- <seealso marker="#state callback">state callback</seealso>
+ <seealso marker="#state callback"><em>state callback</em></seealso>
whenever a new state is entered; see
<seealso marker="#type-state_enter"><c>state_enter()</c></seealso>.
This is for writing code common to all state entries.
- Another way to do it is to insert events at state transitions,
- but you have to do so everywhere it is needed.
+ Another way to do it is to explicitly insert an event
+ at the <em>state transition</em>,
+ and/or to use a dedicated <em>state transition</em> function,
+ but that is something you will have to remember
+ at every <em>state transition</em> to the state(s) that need it.
</p>
<note>
<p>If you in <c>gen_statem</c>, for example, postpone
- an event in one state and then call another state callback
- of yours, you have not changed states and hence the postponed event
- is not retried, which is logical but can be confusing.
+ an event in one state and then call another <em>state callback</em>
+ of yours, you have not done a <em>state change</em>
+ and hence the postponed event is not retried,
+ which is logical but can be confusing.
</p>
</note>
<p>
- For the details of a state transition, see type
+ For the details of a <em>state transition</em>, see type
<seealso marker="#type-transition_option"><c>transition_option()</c></seealso>.
</p>
<p>
@@ -241,7 +306,8 @@ erlang:'!' -----> Module:StateName/3
The <c>gen_statem</c> process can go into hibernation; see
<seealso marker="proc_lib#hibernate/3"><c>proc_lib:hibernate/3</c></seealso>.
It is done when a
- <seealso marker="#state callback">state callback</seealso> or
+ <seealso marker="#state callback"><em>state callback</em></seealso>
+ or
<seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
specifies <c>hibernate</c> in the returned
<seealso marker="#type-action"><c>Actions</c></seealso>
@@ -252,6 +318,17 @@ erlang:'!' -----> Module:StateName/3
to use after every event; see
<seealso marker="erts:erlang#hibernate/3"><c>erlang:hibernate/3</c></seealso>.
</p>
+ <p>
+ There is also a server start option
+ <seealso marker="#type-enter_loop_opt">
+ <c>{hibernate_after, Timeout}</c>
+ </seealso>
+ for
+ <seealso marker="#start/3"><c>start/3,4</c></seealso>,
+ <seealso marker="#start_link/3"><c>start_link/3,4</c></seealso> or
+ <seealso marker="#enter_loop/4"><c>enter_loop/4,5,6</c></seealso>,
+ that may be used to automatically hibernate the server.
+ </p>
</description>
<section>
@@ -438,36 +515,6 @@ handle_event(_, _, State, Data) ->
</desc>
</datatype>
<datatype>
- <name name="debug_opt"/>
- <desc>
- <p>
- Debug option that can be used when starting
- a <c>gen_statem</c> server through,
- <seealso marker="#enter_loop/4"><c>enter_loop/4-6</c></seealso>.
- </p>
- <p>
- For every entry in <c><anno>Dbgs</anno></c>,
- the corresponding function in
- <seealso marker="sys"><c>sys</c></seealso> is called.
- </p>
- </desc>
- </datatype>
- <datatype>
- <name name="hibernate_after_opt"/>
- <desc>
- <p>
- hibernate_after option that can be used when starting
- a <c>gen_statem</c> server through,
- <seealso marker="#enter_loop/4"><c>enter_loop/4-6</c></seealso>.
- </p>
- <p>If option<seealso marker="#type-hibernate_after_opt"><c>{hibernate_after,HibernateAfterTimeout}</c></seealso> is present, the <c>gen_statem</c>
- process awaits any message for <c>HibernateAfterTimeout</c> milliseconds and
- if no message is received, the process goes into hibernation automatically
- (by calling <seealso marker="proc_lib#hibernate/3"><c>proc_lib:hibernate/3</c></seealso>).
- </p>
- </desc>
- </datatype>
- <datatype>
<name name="start_opt"/>
<desc>
<p>
@@ -487,6 +534,37 @@ handle_event(_, _, State, Data) ->
</desc>
</datatype>
<datatype>
+ <name name="enter_loop_opt"/>
+ <desc>
+ <p>
+ Options that can be used when starting
+ a <c>gen_statem</c> server through,
+ <seealso marker="#enter_loop/4"><c>enter_loop/4-6</c></seealso>.
+ </p>
+ <taglist>
+ <tag><c>hibernate_after</c></tag>
+ <item>
+ <p>
+ <c>HibernateAfterTimeout</c>
+ specifies that the <c>gen_statem</c> process awaits
+ any message for <c>HibernateAfterTimeout</c> milliseconds and
+ if no message is received, the process goes into hibernation
+ automatically (by calling
+ <seealso marker="proc_lib#hibernate/3"><c>proc_lib:hibernate/3</c></seealso>).
+ </p>
+ </item>
+ <tag><c>debug</c></tag>
+ <item>
+ <p>
+ For every entry in <c><anno>Dbgs</anno></c>,
+ the corresponding function in
+ <seealso marker="sys"><c>sys</c></seealso> is called.
+ </p>
+ </item>
+ </taglist>
+ </desc>
+ </datatype>
+ <datatype>
<name name="from"/>
<desc>
<p>
@@ -506,7 +584,7 @@ handle_event(_, _, State, Data) ->
<seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
is <c>handle_event_function</c>,
the state can be any term.
- After a state change (<c>NextState =/= State</c>),
+ After a <em>state change</em> (<c>NextState =/= State</c>),
all postponed events are retried.
</p>
</desc>
@@ -519,7 +597,7 @@ handle_event(_, _, State, Data) ->
<seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
is <c>state_functions</c>,
the state must be of this type.
- After a state change (<c>NextState =/= State</c>),
+ After a <em>state change</em> (<c>NextState =/= State</c>),
all postponed events are retried.
</p>
</desc>
@@ -550,7 +628,7 @@ handle_event(_, _, State, Data) ->
</p>
<p>
<c>internal</c> events can only be generated by the
- state machine itself through the state transition action
+ state machine itself through the <em>transition action</em>
<seealso marker="#type-action"><c>next_event</c></seealso>.
</p>
</desc>
@@ -588,9 +666,9 @@ handle_event(_, _, State, Data) ->
This is the return type from
<seealso marker="#Module:callback_mode/0"><c>Module:callback_mode/0</c></seealso>
and selects
- <seealso marker="#type-callback_mode">callback mode</seealso>
+ <seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
and whether to do
- <seealso marker="#type-state_enter">state enter calls</seealso>,
+ <seealso marker="#type-state_enter"><em>state enter calls</em></seealso>,
or not.
</p>
</desc>
@@ -639,13 +717,15 @@ handle_event(_, _, State, Data) ->
If
<seealso marker="#Module:callback_mode/0"><c>Module:callback_mode/0</c></seealso>
returns a list containing <c>state_enter</c>,
- the <c>gen_statem</c> engine will, at every state change,
+ the <c>gen_statem</c> engine will, at every <em>state change</em>,
call the
<seealso marker="#state callback">state callback</seealso>
with arguments <c>(enter, OldState, Data)</c>.
This may look like an event but is really a call
- performed after the previous state callback returned
- and before any event is delivered to the new state callback.
+ performed after the previous
+ <seealso marker="#state callback"><em>state callback</em></seealso>
+ returned and before any event is delivered to the new
+ <seealso marker="#state callback"><em>state callback</em></seealso>.
See
<seealso marker="#Module:StateName/3"><c>Module:StateName/3</c></seealso>
and
@@ -658,27 +738,27 @@ handle_event(_, _, State, Data) ->
<seealso marker="#type-state_callback_result">
<c>repeat_state_and_data</c>
</seealso>
- tuple from the state callback.
+ tuple from the <em>state callback</em>.
</p>
<p>
If
<seealso marker="#Module:callback_mode/0"><c>Module:callback_mode/0</c></seealso>
- does not return such a list, no state enter calls are done.
+ does not return such a list, no <em>state enter calls</em> are done.
</p>
<p>
If
<seealso marker="#Module:code_change/4"><c>Module:code_change/4</c></seealso>
- should transform the state to a state with a different
- name it is still regarded as the same state so this
- does not cause a state enter call.
+ should transform the state,
+ it is regarded as a state rename and not a <em>state change</em>,
+ which will not cause a <em>state enter call</em>.
</p>
<p>
- Note that a state enter call <em>will</em> be done
+ Note that a <em>state enter call</em> <em>will</em> be done
right before entering the initial state even though this
- formally is not a state change.
- In this case <c>OldState</c> will be the same as <c>State</c>,
- which can not happen for a subsequent state change,
- but will happen when repeating the state enter call.
+ actually is not a <em>state change</em>.
+ In this case <c>OldState =:= State</c>,
+ which cannot happen for a subsequent state change,
+ but will happen when repeating the <em>state enter call</em>.
</p>
</desc>
</datatype>
@@ -688,12 +768,22 @@ handle_event(_, _, State, Data) ->
<p>
Transition options can be set by
<seealso marker="#type-action">actions</seealso>
- and they modify how the state transition is done:
+ and modify the <em>state transition</em>.
+ The <em>state transition</em> takes place when the
+ <seealso marker="#state callback"><em>state callback</em></seealso>
+ has processed an event and returns.
+ Here are the sequence of steps for a <em>state transition</em>:
</p>
<list type="ordered">
<item>
<p>
- If the state changes, is the initial state,
+ If
+ <seealso marker="#type-state_enter">
+ <em>state enter calls</em>
+ </seealso>
+ are used, and either:
+ the state changes, it is the initial state,
+ or one of the callback results
<seealso marker="#type-state_callback_result">
<c>repeat_state</c>
</seealso>
@@ -701,16 +791,21 @@ handle_event(_, _, State, Data) ->
<seealso marker="#type-state_callback_result">
<c>repeat_state_and_data</c>
</seealso>
- is used, and also
- <seealso marker="#type-state_enter"><em>state enter calls</em></seealso>
- are used, the <c>gen_statem</c> calls
+ is used; the <c>gen_statem</c> calls
the new state callback with arguments
- <seealso marker="#type-state_enter">(enter, OldState, Data)</seealso>.
+ <seealso marker="#type-state_enter"><c>(enter, OldState, Data)</c></seealso>.
+ </p>
+ <p>
Any
- <seealso marker="#type-enter_action"><c>actions</c></seealso>
+ <seealso marker="#type-enter_action">actions</seealso>
returned from this call are handled as if they were
- appended to the actions
- returned by the state callback that changed states.
+ appended to the actions
+ returned by the state callback that caused the state entry.
+ </p>
+ <p>
+ Should this <em>state enter call</em> return any of
+ the mentioned <c>repeat_*</c> callback results
+ it is repeated again, with the updated <c>Data</c>.
</p>
</item>
<item>
@@ -730,7 +825,8 @@ handle_event(_, _, State, Data) ->
</item>
<item>
<p>
- If the state changes, the queue of incoming events
+ If this is a <em>state change</em>,
+ the queue of incoming events
is reset to start with the oldest postponed.
</p>
</item>
@@ -739,7 +835,7 @@ handle_event(_, _, State, Data) ->
All events stored with
<seealso marker="#type-action"><c>action()</c></seealso>
<c>next_event</c>
- are inserted to be processed before the other queued events.
+ are inserted to be processed before previously queued events.
</p>
</item>
<item>
@@ -753,7 +849,9 @@ handle_event(_, _, State, Data) ->
delivered to the state machine before any external
not yet received event so if there is such a time-out requested,
the corresponding time-out zero event is enqueued as
- the newest event.
+ the newest received event;
+ that is after already queued events
+ such as inserted and postponed events.
</p>
<p>
Any event cancels an
@@ -762,7 +860,7 @@ handle_event(_, _, State, Data) ->
if the event queue is empty.
</p>
<p>
- A state change cancels a
+ A <em>state change</em> cancels a
<seealso marker="#type-state_timeout"><c>state_timeout()</c></seealso>
and any new transition option of this type
belongs to the new state.
@@ -771,7 +869,7 @@ handle_event(_, _, State, Data) ->
<item>
<p>
If there are enqueued events the
- <seealso marker="#state callback">state callback</seealso>
+ <seealso marker="#state callback"><em>state callback</em></seealso>
for the possibly new state
is called with the oldest enqueued event,
and we start again from the top of this list.
@@ -789,9 +887,9 @@ handle_event(_, _, State, Data) ->
the next incoming message awakens the <c>gen_statem</c>,
but if it is a system event it goes right back into hibernation.
When a new message arrives the
- <seealso marker="#state callback">state callback</seealso>
+ <seealso marker="#state callback"><em>state callback</em></seealso>
is called with the corresponding event,
- and we start again from the top of this list.
+ and we start again from the top of this sequence.
</p>
</item>
</list>
@@ -802,7 +900,7 @@ handle_event(_, _, State, Data) ->
<desc>
<p>
If <c>true</c>, postpones the current event and retries
- it when the state changes
+ it after a <em>state change</em>
(<c>NextState =/= State</c>).
</p>
</desc>
@@ -816,13 +914,19 @@ handle_event(_, _, State, Data) ->
<seealso marker="proc_lib#hibernate/3"><c>proc_lib:hibernate/3</c></seealso>
before going into <c>receive</c>
to wait for a new external event.
- If there are enqueued events,
- to prevent receiving any new event, an
- <seealso marker="erts:erlang#garbage_collect/0"><c>erlang:garbage_collect/0</c></seealso>
- is done instead to simulate
- that the <c>gen_statem</c> entered hibernation
- and immediately got awakened by the oldest enqueued event.
</p>
+ <note>
+ <p>
+ If there are enqueued events to process
+ when hibrnation is requested,
+ this is optimized by not hibernating but instead calling
+ <seealso marker="erts:erlang#garbage_collect/0">
+ <c>erlang:garbage_collect/0</c>
+ </seealso>
+ to simulate that the <c>gen_statem</c> entered hibernation
+ and immediately got awakened by an enqueued event.
+ </p>
+ </note>
</desc>
</datatype>
<datatype>
@@ -857,7 +961,7 @@ handle_event(_, _, State, Data) ->
no timer is actually started,
instead the the time-out event is enqueued to ensure
that it gets processed before any not yet
- received external event.
+ received external event, but after already queued events.
</p>
<p>
Note that it is not possible nor needed to cancel this time-out,
@@ -943,7 +1047,9 @@ handle_event(_, _, State, Data) ->
If <c>Abs</c> is <c>true</c> an absolute timer is started,
and if it is <c>false</c> a relative, which is the default.
See
- <seealso marker="erts:erlang#start_timer/4"><c>erlang:start_timer/4</c></seealso>
+ <seealso marker="erts:erlang#start_timer/4">
+ <c>erlang:start_timer/4</c>
+ </seealso>
for details.
</p>
<p>
@@ -954,9 +1060,9 @@ handle_event(_, _, State, Data) ->
<name name="action"/>
<desc>
<p>
- These state transition actions can be invoked by
+ These <em>transition actions</em> can be invoked by
returning them from the
- <seealso marker="#state callback">state callback</seealso>
+ <seealso marker="#state callback"><em>state callback</em></seealso>
when it is called with an
<seealso marker="#type-event_type">event</seealso>,
from
@@ -969,7 +1075,9 @@ handle_event(_, _, State, Data) ->
</p>
<p>
Actions that set
- <seealso marker="#type-transition_option">transition options</seealso>
+ <seealso marker="#type-transition_option">
+ transition options
+ </seealso>
override any previous of the same type,
so the last in the containing list wins.
For example, the last
@@ -981,9 +1089,11 @@ handle_event(_, _, State, Data) ->
<item>
<p>
Sets the
- <seealso marker="#type-transition_option"><c>transition_option()</c></seealso>
+ <seealso marker="#type-transition_option">
+ <c>transition_option()</c>
+ </seealso>
<seealso marker="#type-postpone"><c>postpone()</c></seealso>
- for this state transition.
+ for this <em>state transition</em>.
This action is ignored when returned from
<seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
or given to
@@ -994,7 +1104,11 @@ handle_event(_, _, State, Data) ->
<tag><c>next_event</c></tag>
<item>
<p>
- Stores the specified <c><anno>EventType</anno></c>
+ This action does not set any
+ <seealso marker="#type-transition_option">
+ <c>transition_option()</c>
+ </seealso>
+ but instead stores the specified <c><anno>EventType</anno></c>
and <c><anno>EventContent</anno></c> for insertion after all
actions have been executed.
</p>
@@ -1018,9 +1132,9 @@ handle_event(_, _, State, Data) ->
<name name="enter_action"/>
<desc>
<p>
- These state transition actions can be invoked by
+ These <em>transition actions</em> can be invoked by
returning them from the
- <seealso marker="#state callback">state callback</seealso>, from
+ <seealso marker="#state callback"><em>state callback</em></seealso>, from
<seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
or by giving them to
<seealso marker="#enter_loop/5"><c>enter_loop/5,6</c></seealso>.
@@ -1044,7 +1158,7 @@ handle_event(_, _, State, Data) ->
Sets the
<seealso marker="#type-transition_option"><c>transition_option()</c></seealso>
<seealso marker="#type-hibernate"><c>hibernate()</c></seealso>
- for this state transition.
+ for this <em>state transition</em>.
</p>
</item>
</taglist>
@@ -1054,9 +1168,9 @@ handle_event(_, _, State, Data) ->
<name name="timeout_action"/>
<desc>
<p>
- These state transition actions can be invoked by
+ These <em>transition actions</em> can be invoked by
returning them from the
- <seealso marker="#state callback">state callback</seealso>, from
+ <seealso marker="#state callback"><em>state callback</em></seealso>, from
<seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
or by giving them to
<seealso marker="#enter_loop/5"><c>enter_loop/5,6</c></seealso>.
@@ -1066,15 +1180,15 @@ handle_event(_, _, State, Data) ->
<seealso marker="#type-transition_option">transition options</seealso>.
</p>
<taglist>
- <tag><c>Timeout</c></tag>
+ <tag><c>Time</c></tag>
<item>
<p>
- Short for <c>{timeout,Timeout,Timeout}</c>, that is,
+ Short for <c>{timeout,Time,Time}</c>, that is,
the time-out message is the time-out time.
This form exists to make the
- <seealso marker="#state callback">state callback</seealso>
- return value <c>{next_state,NextState,NewData,Timeout}</c>
- allowed like for <c>gen_fsm</c>'s
+ <seealso marker="#state callback"><em>state callback</em></seealso>
+ return value <c>{next_state,NextState,NewData,Time}</c>
+ allowed like for <c>gen_fsm</c>.
</p>
</item>
<tag><c>timeout</c></tag>
@@ -1118,20 +1232,24 @@ handle_event(_, _, State, Data) ->
<name name="reply_action"/>
<desc>
<p>
- This state transition action can be invoked by
+ This <em>transition action</em> can be invoked by
returning it from the
- <seealso marker="#state callback">state callback</seealso>, from
+ <seealso marker="#state callback"><em>state callback</em></seealso>, from
<seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
or by giving it to
<seealso marker="#enter_loop/5"><c>enter_loop/5,6</c></seealso>.
</p>
<p>
- It replies to a caller waiting for a reply in
+ It does not set any
+ <seealso marker="#type-transition_option">
+ <c>transition_option()</c>
+ </seealso>
+ but instead replies to a caller waiting for a reply in
<seealso marker="#call/2"><c>call/2</c></seealso>.
<c><anno>From</anno></c> must be the term from argument
<seealso marker="#type-event_type"><c>{call,<anno>From</anno>}</c></seealso>
in a call to a
- <seealso marker="#state callback">state callback</seealso>.
+ <seealso marker="#state callback"><em>state callback</em></seealso>.
</p>
<p>
Note that using this action from
@@ -1140,7 +1258,7 @@ handle_event(_, _, State, Data) ->
<seealso marker="#enter_loop/5"><c>enter_loop/5,6</c></seealso>
would be weird on the border of witchcraft
since there has been no earlier call to a
- <seealso marker="#state callback">state callback</seealso>
+ <seealso marker="#state callback"><em>state callback</em></seealso>
in this server.
</p>
</desc>
@@ -1160,7 +1278,7 @@ handle_event(_, _, State, Data) ->
The <seealso marker="#type-action"><c>Actions</c></seealso>
are executed when entering the first
<seealso marker="#type-state">state</seealso> just as for a
- <seealso marker="#state callback">state callback</seealso>,
+ <seealso marker="#state callback"><em>state callback</em></seealso>,
except that the action <c>postpone</c> is forced to
<c>false</c> since there is no event to postpone.
</p>
@@ -1177,7 +1295,7 @@ handle_event(_, _, State, Data) ->
<desc>
<p>
<c><anno>State</anno></c> is the current state
- and it can not be changed since the state callback
+ and it cannot be changed since the state callback
was called with a
<seealso marker="#type-state_enter"><em>state enter call</em></seealso>.
</p>
@@ -1213,11 +1331,13 @@ handle_event(_, _, State, Data) ->
<tag><c>next_state</c></tag>
<item>
<p>
- The <c>gen_statem</c> does a state transition to
+ The <c>gen_statem</c> does a <em>state transition</em> to
<c><anno>NextState</anno></c>
(which can be the same as the current state),
sets <c><anno>NewData</anno></c>,
and executes all <c><anno>Actions</anno></c>.
+ If <c><anno>NextState</anno> =/= CurrentState</c>
+ the <em>state transition</em> is a <em>state change</em>.
</p>
</item>
</taglist>
@@ -1239,54 +1359,33 @@ handle_event(_, _, State, Data) ->
<tag><c>keep_state</c></tag>
<item>
<p>
- The <c>gen_statem</c> keeps the current state, or
- does a state transition to the current state if you like,
- sets <c><anno>NewData</anno></c>,
- and executes all <c><anno>Actions</anno></c>.
- This is the same as
+ The same as
<c>{next_state,CurrentState,<anno>NewData</anno>,<anno>Actions</anno>}</c>.
</p>
</item>
<tag><c>keep_state_and_data</c></tag>
<item>
<p>
- The <c>gen_statem</c> keeps the current state or
- does a state transition to the current state if you like,
- keeps the current server data,
- and executes all <c><anno>Actions</anno></c>.
- This is the same as
- <c>{next_state,CurrentState,CurrentData,<anno>Actions</anno>}</c>.
+ The same as
+ <c>{keep_state,CurrentData,<anno>Actions</anno>}</c>.
</p>
</item>
<tag><c>repeat_state</c></tag>
<item>
<p>
- The <c>gen_statem</c> keeps the current state, or
- does a state transition to the current state if you like,
- sets <c><anno>NewData</anno></c>,
- and executes all <c><anno>Actions</anno></c>.
If the <c>gen_statem</c> runs with
<seealso marker="#type-state_enter"><em>state enter calls</em></seealso>,
- the state enter call is repeated, see type
+ the <em>state enter call</em> is repeated, see type
<seealso marker="#type-transition_option"><c>transition_option()</c></seealso>,
- otherwise <c>repeat_state</c> is the same as
+ other than that <c>repeat_state</c> is the same as
<c>keep_state</c>.
</p>
</item>
<tag><c>repeat_state_and_data</c></tag>
<item>
<p>
- The <c>gen_statem</c> keeps the current state and data, or
- does a state transition to the current state if you like,
- and executes all <c><anno>Actions</anno></c>.
- This is the same as
+ The same as
<c>{repeat_state,CurrentData,<anno>Actions</anno>}</c>.
- If the <c>gen_statem</c> runs with
- <seealso marker="#type-state_enter"><em>state enter calls</em></seealso>,
- the state enter call is repeated, see type
- <seealso marker="#type-transition_option"><c>transition_option()</c></seealso>,
- otherwise <c>repeat_state_and_data</c> is the same as
- <c>keep_state_and_data</c>.
</p>
</item>
<tag><c>stop</c></tag>
@@ -1319,8 +1418,8 @@ handle_event(_, _, State, Data) ->
<funcs>
<func>
- <name name="call" arity="2"/>
- <name name="call" arity="3"/>
+ <name name="call" arity="2" since="OTP 19.0"/>
+ <name name="call" arity="3" since="OTP 19.0"/>
<fsummary>Make a synchronous call to a <c>gen_statem</c>.</fsummary>
<desc>
<p>
@@ -1329,14 +1428,15 @@ handle_event(_, _, State, Data) ->
by sending a request
and waiting until its reply arrives.
The <c>gen_statem</c> calls the
- <seealso marker="#state callback">state callback</seealso> with
+ <seealso marker="#state callback"><em>state callback</em></seealso>
+ with
<seealso marker="#type-event_type"><c>event_type()</c></seealso>
<c>{call,From}</c> and event content
<c><anno>Request</anno></c>.
</p>
<p>
A <c><anno>Reply</anno></c> is generated when a
- <seealso marker="#state callback">state callback</seealso>
+ <seealso marker="#state callback"><em>state callback</em></seealso>
returns with
<c>{reply,From,<anno>Reply</anno>}</c> as one
<seealso marker="#type-action"><c>action()</c></seealso>,
@@ -1369,7 +1469,7 @@ handle_event(_, _, State, Data) ->
<c><anno>T</anno></c> is the time-out time.
<c>{clean_timeout,<anno>T</anno>}</c> works like
just <c>T</c> described in the note above
- and uses a proxy process for <c>T &lt; infinity</c>,
+ and uses a proxy process
while <c>{dirty_timeout,<anno>T</anno>}</c>
bypasses the proxy process which is more lightweight.
</p>
@@ -1379,8 +1479,12 @@ handle_event(_, _, State, Data) ->
with <c>{dirty_timeout,<anno>T</anno>}</c>
to avoid that the calling process dies when the call
times out, you will have to be prepared to handle
- a late reply.
- So why not just let the calling process die?
+ a late reply. Note that there is an odd chance
+ to get a late reply even with
+ <c>{dirty_timeout,infinity}</c> or <c>infinity</c>
+ for example in the event of network problems.
+ So why not just let the calling process die
+ by not catching the exception?
</p>
</note>
<p>
@@ -1391,7 +1495,7 @@ handle_event(_, _, State, Data) ->
</func>
<func>
- <name name="cast" arity="2"/>
+ <name name="cast" arity="2" since="OTP 19.0"/>
<fsummary>Send an asynchronous event to a <c>gen_statem</c>.</fsummary>
<desc>
<p>
@@ -1401,7 +1505,8 @@ handle_event(_, _, State, Data) ->
ignoring if the destination node or <c>gen_statem</c>
does not exist.
The <c>gen_statem</c> calls the
- <seealso marker="#state callback">state callback</seealso> with
+ <seealso marker="#state callback"><em>state callback</em></seealso>
+ with
<seealso marker="#type-event_type"><c>event_type()</c></seealso>
<c>cast</c> and event content
<c><anno>Msg</anno></c>.
@@ -1410,7 +1515,7 @@ handle_event(_, _, State, Data) ->
</func>
<func>
- <name name="enter_loop" arity="4"/>
+ <name name="enter_loop" arity="4" since="OTP 19.1"/>
<fsummary>Enter the <c>gen_statem</c> receive loop.</fsummary>
<desc>
<p>
@@ -1424,7 +1529,7 @@ handle_event(_, _, State, Data) ->
</func>
<func>
- <name name="enter_loop" arity="5"/>
+ <name name="enter_loop" arity="5" since="OTP 19.0"/>
<fsummary>Enter the <c>gen_statem</c> receive loop.</fsummary>
<desc>
<p>
@@ -1448,7 +1553,7 @@ handle_event(_, _, State, Data) ->
</func>
<func>
- <name name="enter_loop" arity="6"/>
+ <name name="enter_loop" arity="6" since="OTP 19.0"/>
<fsummary>Enter the <c>gen_statem</c> receive loop.</fsummary>
<desc>
<p>
@@ -1505,8 +1610,8 @@ handle_event(_, _, State, Data) ->
</func>
<func>
- <name name="reply" arity="1"/>
- <name name="reply" arity="2"/>
+ <name name="reply" arity="1" since="OTP 19.0"/>
+ <name name="reply" arity="2" since="OTP 19.0"/>
<fsummary>Reply to a caller.</fsummary>
<desc>
<p>
@@ -1515,18 +1620,18 @@ handle_event(_, _, State, Data) ->
<seealso marker="#call/2"><c>call/2</c></seealso>
when the reply cannot be defined in
the return value of a
- <seealso marker="#state callback">state callback</seealso>.
+ <seealso marker="#state callback"><em>state callback</em></seealso>.
</p>
<p>
<c><anno>From</anno></c> must be the term from argument
<seealso marker="#type-event_type"><c>{call,<anno>From</anno>}</c></seealso>
to the
- <seealso marker="#state callback">state callback</seealso>.
+ <seealso marker="#state callback"><em>state callback</em></seealso>.
A reply or multiple replies canalso be sent
using one or several
<seealso marker="#type-reply_action"><c>reply_action()</c></seealso>s
from a
- <seealso marker="#state callback">state callback</seealso>.
+ <seealso marker="#state callback"><em>state callback</em></seealso>.
</p>
<note>
<p>
@@ -1538,8 +1643,8 @@ handle_event(_, _, State, Data) ->
</func>
<func>
- <name name="start" arity="3"/>
- <name name="start" arity="4"/>
+ <name name="start" arity="3" since="OTP 19.0"/>
+ <name name="start" arity="4" since="OTP 19.0"/>
<fsummary>Create a standalone <c>gen_statem</c> process.</fsummary>
<desc>
<p>
@@ -1559,8 +1664,8 @@ handle_event(_, _, State, Data) ->
</func>
<func>
- <name name="start_link" arity="3"/>
- <name name="start_link" arity="4"/>
+ <name name="start_link" arity="3" since="OTP 19.0"/>
+ <name name="start_link" arity="4" since="OTP 19.0"/>
<fsummary>Create a linked <c>gen_statem</c> process.</fsummary>
<desc>
<p>
@@ -1598,7 +1703,11 @@ handle_event(_, _, State, Data) ->
<list type="bulleted">
<item>
<p>
- If option <c>{timeout,Time}</c> is present in
+ If option
+ <seealso marker="#type-start_opt">
+ <c>{timeout,Time}</c>
+ </seealso>
+ is present in
<c><anno>Opts</anno></c>, the <c>gen_statem</c>
is allowed to spend <c>Time</c> milliseconds initializing
or it terminates and the start function returns
@@ -1606,23 +1715,33 @@ handle_event(_, _, State, Data) ->
</p>
</item>
<item>
- <p>If option<seealso marker="#type-hibernate_after_opt"><c>{hibernate_after,HibernateAfterTimeout}</c></seealso> is present, the <c>gen_statem</c>
- process awaits any message for <c>HibernateAfterTimeout</c> milliseconds and
- if no message is received, the process goes into hibernation automatically
- (by calling <seealso marker="proc_lib#hibernate/3"><c>proc_lib:hibernate/3</c></seealso>).
+ <p>If option
+ <seealso marker="#type-enter_loop_opt">
+ <c>{hibernate_after,HibernateAfterTimeout}</c>
+ </seealso>
+ is present, the <c>gen_statem</c>
+ process awaits any message for <c>HibernateAfterTimeout</c> milliseconds and
+ if no message is received, the process goes into hibernation automatically
+ (by calling <seealso marker="proc_lib#hibernate/3"><c>proc_lib:hibernate/3</c></seealso>).
</p>
</item>
<item>
<p>
If option
- <seealso marker="#type-debug_opt"><c>{debug,Dbgs}</c></seealso>
+ <seealso marker="#type-enter_loop_opt">
+ <c>{debug,Dbgs}</c>
+ </seealso>
is present in <c><anno>Opts</anno></c>, debugging through
<seealso marker="sys"><c>sys</c></seealso> is activated.
</p>
</item>
<item>
<p>
- If option <c>{spawn_opt,SpawnOpts}</c> is present in
+ If option
+ <seealso marker="#type-start_opt">
+ <c>{spawn_opt,SpawnOpts}</c>
+ </seealso>
+ is present in
<c><anno>Opts</anno></c>, <c>SpawnOpts</c> is passed
as option list to
<seealso marker="erts:erlang#spawn_opt/2"><c>erlang:spawn_opt/2</c></seealso>,
@@ -1667,7 +1786,7 @@ handle_event(_, _, State, Data) ->
</func>
<func>
- <name name="stop" arity="1"/>
+ <name name="stop" arity="1" since="OTP 19.0"/>
<fsummary>Synchronously stop a generic server.</fsummary>
<desc>
<p>
@@ -1678,7 +1797,7 @@ handle_event(_, _, State, Data) ->
</func>
<func>
- <name name="stop" arity="3"/>
+ <name name="stop" arity="3" since="OTP 19.0"/>
<fsummary>Synchronously stop a generic server.</fsummary>
<desc>
<p>
@@ -1695,7 +1814,7 @@ handle_event(_, _, State, Data) ->
with the expected reason. Any other reason than <c>normal</c>,
<c>shutdown</c>, or <c>{shutdown,Term}</c> causes an
error report to be issued through
- <seealso marker="kernel:error_logger#format/2"><c>error_logger:format/2</c></seealso>.
+ <seealso marker="kernel:logger"><c>logger(3)</c></seealso>.
The default <c><anno>Reason</anno></c> is <c>normal</c>.
</p>
<p>
@@ -1724,7 +1843,7 @@ handle_event(_, _, State, Data) ->
<funcs>
<func>
- <name>Module:callback_mode() -> CallbackMode</name>
+ <name since="OTP 19.1">Module:callback_mode() -> CallbackMode</name>
<fsummary>Update the internal state during upgrade/downgrade.</fsummary>
<type>
<v>
@@ -1743,7 +1862,7 @@ handle_event(_, _, State, Data) ->
for efficiency reasons, so this function is only called
once after server start and after code change,
but before the first
- <seealso marker="#state callback">state callback</seealso>
+ <seealso marker="#state callback"><em>state callback</em></seealso>
in the current code version is called.
More occasions may be added in future versions
of <c>gen_statem</c>.
@@ -1775,7 +1894,7 @@ handle_event(_, _, State, Data) ->
</func>
<func>
- <name>Module:code_change(OldVsn, OldState, OldData, Extra) ->
+ <name since="OTP 19.0">Module:code_change(OldVsn, OldState, OldData, Extra) ->
Result
</name>
<fsummary>Update the internal state during upgrade/downgrade.</fsummary>
@@ -1800,7 +1919,7 @@ handle_event(_, _, State, Data) ->
<p>
This callback is optional, so callback modules need not export it.
If a release upgrade/downgrade with
- <c>Change={advanced,Extra}</c>
+ <c>Change = {advanced,Extra}</c>
specified in the <c>.appup</c> file is made
when <c>code_change/4</c> is not implemented
the process will crash with exit reason <c>undef</c>.
@@ -1810,7 +1929,7 @@ handle_event(_, _, State, Data) ->
This function is called by a <c>gen_statem</c> when it is to
update its internal state during a release upgrade/downgrade,
that is, when the instruction <c>{update,Module,Change,...}</c>,
- where <c>Change={advanced,Extra}</c>, is specified in the
+ where <c>Change = {advanced,Extra}</c>, is specified in the
<seealso marker="sasl:appup"><c>appup</c></seealso>
file. For more information, see
<seealso marker="doc/design_principles:release_handling#instr">OTP Design Principles</seealso>.
@@ -1839,7 +1958,7 @@ handle_event(_, _, State, Data) ->
<p>
If the function returns a failure <c>Reason</c>, the ongoing
upgrade fails and rolls back to the old release.
- Note that <c>Reason</c> can not be an <c>{ok,_,_}</c> tuple
+ Note that <c>Reason</c> cannot be an <c>{ok,_,_}</c> tuple
since that will be regarded as a
<c>{ok,NewState,NewData}</c> tuple,
and that a tuple matching <c>{ok,_}</c>
@@ -1850,13 +1969,13 @@ handle_event(_, _, State, Data) ->
<p>
Also note when upgrading a <c>gen_statem</c>,
this function and hence
- the <c>Change={advanced,Extra}</c> parameter in the
+ the <c>Change = {advanced,Extra}</c> parameter in the
<seealso marker="sasl:appup"><c>appup</c></seealso> file
is not only needed to update the internal state
or to act on the <c>Extra</c> argument.
It is also needed if an upgrade or downgrade should change
<seealso marker="#type-callback_mode"><em>callback mode</em></seealso>,
- or else the callback mode after the code change
+ or else the <em>callback mode</em> after the code change
will not be honoured,
most probably causing a server crash.
</p>
@@ -1864,7 +1983,7 @@ handle_event(_, _, State, Data) ->
</func>
<func>
- <name>Module:init(Args) -> Result(StateType)</name>
+ <name since="OTP 19.0">Module:init(Args) -> Result(StateType)</name>
<fsummary>
Initializing process and internal state.
</fsummary>
@@ -1891,7 +2010,7 @@ handle_event(_, _, State, Data) ->
</p>
<note>
<p>
- Note that if the <c>gen_statem</c> is started trough
+ Note that if the <c>gen_statem</c> is started through
<seealso marker="proc_lib"><c>proc_lib</c></seealso>
and
<seealso marker="#enter_loop/4"><c>enter_loop/4-6</c></seealso>,
@@ -1906,7 +2025,7 @@ init(Args) -> erlang:error(not_implemented, [Args]).</pre>
</func>
<func>
- <name>Module:format_status(Opt, [PDict,State,Data]) ->
+ <name since="OTP 19.0">Module:format_status(Opt, [PDict,State,Data]) ->
Status
</name>
<fsummary>Optional function for providing a term describing the
@@ -2005,16 +2124,16 @@ init(Args) -> erlang:error(not_implemented, [Args]).</pre>
</func>
<func>
- <name>Module:StateName(enter, OldState, Data) ->
+ <name since="OTP 19.0">Module:StateName(enter, OldState, Data) ->
StateEnterResult(StateName)
</name>
- <name>Module:StateName(EventType, EventContent, Data) ->
+ <name since="OTP 19.0">Module:StateName(EventType, EventContent, Data) ->
StateFunctionResult
</name>
- <name>Module:handle_event(enter, OldState, State, Data) ->
+ <name since="OTP 19.0">Module:handle_event(enter, OldState, State, Data) ->
StateEnterResult(State)
</name>
- <name>Module:handle_event(EventType, EventContent, State, Data) ->
+ <name since="OTP 19.0">Module:handle_event(EventType, EventContent, State, Data) ->
HandleEventResult
</name>
<fsummary>Handle an event.</fsummary>
@@ -2065,7 +2184,7 @@ init(Args) -> erlang:error(not_implemented, [Args]).</pre>
<seealso marker="#type-event_type"><c>{call,From}</c></seealso>,
the caller waits for a reply. The reply can be sent
from this or from any other
- <seealso marker="#state callback">state callback</seealso>
+ <seealso marker="#state callback"><em>state callback</em></seealso>
by returning with <c>{reply,From,Reply}</c> in
<seealso marker="#type-action"><c>Actions</c></seealso>, in
<seealso marker="#type-reply_action"><c>Replies</c></seealso>,
@@ -2090,9 +2209,9 @@ init(Args) -> erlang:error(not_implemented, [Args]).</pre>
</p>
<p>
When the <c>gen_statem</c> runs with
- <seealso marker="#type-state_enter">state enter calls</seealso>,
+ <seealso marker="#type-state_enter"><em>state enter calls</em></seealso>,
these functions are also called with arguments
- <c>(enter, OldState, ...)</c> whenever the state changes.
+ <c>(enter, OldState, ...)</c> during every <em>state change</em>.
In this case there are some restrictions on the
<seealso marker="#type-enter_action">actions</seealso>
that may be returned:
@@ -2105,23 +2224,27 @@ init(Args) -> erlang:error(not_implemented, [Args]).</pre>
You may also not change states from this call.
Should you return <c>{next_state,NextState, ...}</c>
with <c>NextState =/= State</c> the <c>gen_statem</c> crashes.
- It is possible to use <c>{repeat_state, ...}</c>,
- <c>{repeat_state_and_data,_}</c> or
- <c>repeat_state_and_data</c> but all of them makes little
+ Note that it is actually allowed to use
+ <c>{repeat_state, NewData, ...}</c> although it makes little
sense since you immediately will be called again with a new
<em>state enter call</em> making this just a weird way
of looping, and there are better ways to loop in Erlang.
+ If you do not update <c>NewData</c> and have some
+ loop termination condition, or if you use
+ <c>{repeat_state_and_data, _}</c> or
+ <c>repeat_state_and_data</c> you have an infinite loop!
You are advised to use <c>{keep_state,...}</c>,
<c>{keep_state_and_data,_}</c> or
- <c>keep_state_and_data</c> since you can not change states
- from a <em>state enter call</em> anyway.
+ <c>keep_state_and_data</c>
+ since changing states from a <em>state enter call</em>
+ is not possible anyway.
</p>
<p>
Note the fact that you can use
<seealso marker="erts:erlang#throw/1"><c>throw</c></seealso>
to return the result, which can be useful.
For example to bail out with <c>throw(keep_state_and_data)</c>
- from deep within complex code that can not
+ from deep within complex code that cannot
return <c>{next_state,State,Data}</c> because
<c>State</c> or <c>Data</c> is no longer in scope.
</p>
@@ -2129,7 +2252,7 @@ init(Args) -> erlang:error(not_implemented, [Args]).</pre>
</func>
<func>
- <name>Module:terminate(Reason, State, Data) -> Ignored</name>
+ <name since="OTP 19.0">Module:terminate(Reason, State, Data) -> Ignored</name>
<fsummary>Clean up before termination.</fsummary>
<type>
<v>Reason = normal | shutdown | {shutdown,term()} | term()</v>
@@ -2199,7 +2322,7 @@ init(Args) -> erlang:error(not_implemented, [Args]).</pre>
<c>shutdown</c>, or <c>{shutdown,Term}</c>,
the <c>gen_statem</c> is assumed to terminate because of an error
and an error report is issued using
- <seealso marker="kernel:error_logger#format/2"><c>error_logger:format/2</c></seealso>.
+ <seealso marker="kernel:logger"><c>logger(3)</c></seealso>.
</p>
</desc>
</func>
diff --git a/lib/stdlib/doc/src/io.xml b/lib/stdlib/doc/src/io.xml
index 64fcf4379f..d69e808586 100644
--- a/lib/stdlib/doc/src/io.xml
+++ b/lib/stdlib/doc/src/io.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>io</module>
+ <module since="">io</module>
<modulesummary>Standard I/O server interface functions.</modulesummary>
<description>
<p>This module provides an interface to standard Erlang I/O servers.
@@ -104,8 +104,8 @@
<funcs>
<func>
- <name name="columns" arity="0"/>
- <name name="columns" arity="1"/>
+ <name name="columns" arity="0" since=""/>
+ <name name="columns" arity="1" since=""/>
<fsummary>Get the number of columns of an I/O device.</fsummary>
<desc>
<p>Retrieves the number of columns of the
@@ -116,12 +116,12 @@
</func>
<func>
- <name name="format" arity="1"/>
- <name name="format" arity="2"/>
- <name name="format" arity="3"/>
- <name name="fwrite" arity="1"/>
- <name name="fwrite" arity="2"/>
- <name name="fwrite" arity="3"/>
+ <name name="format" arity="1" since=""/>
+ <name name="format" arity="2" since=""/>
+ <name name="format" arity="3" since=""/>
+ <name name="fwrite" arity="1" since=""/>
+ <name name="fwrite" arity="2" since=""/>
+ <name name="fwrite" arity="3" since=""/>
<fsummary>Write formatted output.</fsummary>
<desc>
<p>Writes the items in <c><anno>Data</anno></c> (<c>[]</c>) on the
@@ -137,11 +137,11 @@
Hello world!
ok</pre>
<p>The general format of a control sequence is <c>~F.P.PadModC</c>.</p>
- <p>Character <c>C</c> determines the type of control sequence
- to be used, <c>F</c> and <c>P</c> are optional numeric
- arguments. If <c>F</c>, <c>P</c>, or <c>Pad</c> is <c>*</c>,
- the next argument in <c>Data</c> is used as the numeric value
- of <c>F</c> or <c>P</c>.</p>
+ <p>The character <c>C</c> determines the type of control sequence
+ to be used. It is the only required field. All of <c>F</c>,
+ <c>P</c>, <c>Pad</c>, and <c>Mod</c> are optional. For example,
+ to use a <c>#</c> for <c>Pad</c> but use the default values for
+ <c>F</c> and <c>P</c>, you can write <c>~..#C</c>.</p>
<list type="bulleted">
<item>
<p><c>F</c> is the <c>field width</c> of the printed argument. A
@@ -167,13 +167,26 @@ ok</pre>
The default padding character is <c>' '</c> (space).</p>
</item>
<item>
- <p><c>Mod</c> is the control sequence modifier. It is either a
- single character (<c>t</c>, for Unicode
- translation, and <c>l</c>, for stopping <c>p</c> and
- <c>P</c> from detecting printable characters)
- that changes the interpretation of <c>Data</c>.</p>
+ <p><c>Mod</c> is the control sequence modifier. This is
+ one or more characters that change the interpretation of
+ <c>Data</c>. The current modifiers are <c>t</c>, for Unicode
+ translation, and <c>l</c>, for stopping <c>p</c> and <c>P</c>
+ from detecting printable characters.</p>
</item>
</list>
+ <p>If <c>F</c>, <c>P</c>, or <c>Pad</c> is a <c>*</c> character,
+ the next argument in <c>Data</c> is used as the value.
+ For example:</p>
+ <pre>
+1> <input>io:fwrite("~*.*.0f~n",[9, 5, 3.14159265]).</input>
+003.14159
+ok</pre>
+ <p>To use a literal <c>*</c> character as <c>Pad</c>, it must be
+ passed as an argument:</p>
+ <pre>
+2> <input>io:fwrite("~*.*.*f~n",[9, 5, $*, 3.14159265]).</input>
+**3.14159
+ok</pre>
<p><em>Available control sequences:</em></p>
<taglist>
<tag><c>~</c></tag>
@@ -257,8 +270,9 @@ ok</pre>
\x{400}
ok
5> <input>io:fwrite("~s~n",[[1024]]).</input>
-** exception exit: {badarg,[{io,format,[&lt;0.26.0&gt;,"~s~n",[[1024]]]},
- ...</pre>
+** exception error: bad argument
+ in function io:format/3
+ called as io:format(&lt;0.53.0>,"~s~n",[[1024]])</pre>
</item>
<tag><c>w</c></tag>
<item>
@@ -276,10 +290,9 @@ ok
<c>~w</c>, but breaks terms whose printed representation
is longer than one line into many lines and indents each
line sensibly. Left-justification is not supported.
- It also tries to detect lists of
- printable characters and to output these as strings. The
- Unicode translation modifier is used for determining
- what characters are printable, for example:</p>
+ It also tries to detect flat lists of
+ printable characters and output these as strings.
+ For example:</p>
<pre>
1> <input>T = [{attributes,[[{id,age,1.50000},{mode,explicit},</input>
<input>{typename,"INTEGER"}], [{id,cho},{mode,explicit},{typename,'Cho'}]]},</input>
@@ -301,7 +314,7 @@ ok
{mode,implicit}]
ok</pre>
<p>The field width specifies the maximum line length.
- Defaults to 80. The precision specifies the initial
+ It defaults to 80. The precision specifies the initial
indentation of the term. It defaults to the number of
characters printed on this line in the <em>same</em> call to
<seealso marker="#write/1"><c>write/1</c></seealso> or
@@ -319,11 +332,22 @@ Here T = [{attributes,[[{id,age,1.5},
{tag,{'PRIVATE',3}},
{mode,implicit}]
ok</pre>
+
+ <p>As from Erlang/OTP 21.0, a field width of value
+ <c>0</c> can be used for specifying that a line is
+ infinitely long, which means that no line breaks
+ are inserted. For example:</p>
+
+ <pre>
+5> <input>io:fwrite("~0p~n", [lists:seq(1, 30)]).</input>
+[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]
+ok</pre>
+
<p>When the modifier <c>l</c> is specified, no detection of
printable character lists takes place, for example:</p>
<pre>
-5> <input>S = [{a,"a"}, {b, "b"}].</input>
-6> <input>io:fwrite("~15p~n", [S]).</input>
+6> <input>S = [{a,"a"}, {b, "b"}],
+ io:fwrite("~15p~n", [S]).</input>
[{a,"a"},
{b,"b"}]
ok
@@ -331,18 +355,53 @@ ok
[{a,[97]},
{b,[98]}]
ok</pre>
- <p>Binaries that look like UTF-8 encoded strings are
- output with the string syntax if the Unicode translation
- modifier is specified:</p>
+ <p>The Unicode translation modifier <c>t</c> specifies how to treat
+ characters outside the Latin-1 range of codepoints, in
+ atoms, strings, and binaries. For example, printing an atom
+ containing a character &gt; 255:</p>
+ <pre>
+8> <input>io:fwrite("~p~n",[list_to_atom([1024])]).</input>
+'\x{400}'
+ok
+9> <input>io:fwrite("~tp~n",[list_to_atom([1024])]).</input>
+'Ѐ'
+ok</pre>
+ <p>By default, Erlang only detects lists of characters
+ in the Latin-1 range as strings, but the <c>+pc unicode</c>
+ flag can be used to change this (see <seealso
+ marker="#printable_range/0">
+ <c>printable_range/0</c></seealso> for details). For example:</p>
<pre>
-9> <input>io:fwrite("~p~n",[[1024]]).</input>
+10> <input>io:fwrite("~p~n",[[214]]).</input>
+"Ö"
+ok
+11> <input>io:fwrite("~p~n",[[1024]]).</input>
+[1024]
+ok
+12> <input>io:fwrite("~tp~n",[[1024]]).</input>
+[1024]
+ok
+</pre>
+ <p>but if Erlang was started with <c>+pc unicode</c>:</p>
+ <pre>
+13> <input>io:fwrite("~p~n",[[1024]]).</input>
[1024]
-10> <input>io:fwrite("~tp~n",[[1024]]).</input>
-"\x{400}"
-11> <input>io:fwrite("~tp~n", [&lt;&lt;128,128&gt;&gt;]).</input>
+ok
+14> <input>io:fwrite("~tp~n",[[1024]]).</input>
+"Ѐ"
+ok</pre>
+ <p>Similarly, binaries that look like UTF-8 encoded strings
+ are output with the binary string syntax if the <c>t</c>
+ modifier is specified:</p>
+ <pre>
+15> <input>io:fwrite("~p~n", [&lt;&lt;208,128&gt;&gt;]).</input>
+&lt;&lt;208,128&gt;&gt;
+ok
+16> <input>io:fwrite("~tp~n", [&lt;&lt;208,128&gt;&gt;]).</input>
+&lt;&lt;"Ѐ"/utf8&gt;&gt;
+ok
+17> <input>io:fwrite("~tp~n", [&lt;&lt;128,128&gt;&gt;]).</input>
&lt;&lt;128,128&gt;&gt;
-12> <input>io:fwrite("~tp~n", [&lt;&lt;208,128&gt;&gt;]).</input>
-&lt;&lt;"\x{400}"/utf8&gt;&gt;
ok</pre>
</item>
<tag><c>W</c></tag>
@@ -454,12 +513,9 @@ ok</pre>
abc def 'abc def' {foo,1} A
ok
2> <input>io:fwrite("~s", [65]).</input>
-** exception exit: {badarg,[{io,format,[&lt;0.22.0>,"~s","A"]},
- {erl_eval,do_apply,5},
- {shell,exprs,6},
- {shell,eval_exprs,6},
- {shell,eval_loop,3}]}
- in function io:o_request/2</pre>
+** exception error: bad argument
+ in function io:format/3
+ called as io:format(&lt;0.53.0>,"~s","A")</pre>
<p>In this example, an attempt was made to output the single
character 65 with the aid of the string formatting directive
<c>"~s"</c>.</p>
@@ -467,8 +523,8 @@ ok
</func>
<func>
- <name name="fread" arity="2"/>
- <name name="fread" arity="3"/>
+ <name name="fread" arity="2" since=""/>
+ <name name="fread" arity="3" since=""/>
<fsummary>Read formatted input.</fsummary>
<type name="server_no_data"/>
<desc>
@@ -634,8 +690,8 @@ enter><input>:</input> <input>alan</input> <input>:</input> <input>joe</in
</func>
<func>
- <name name="get_chars" arity="2"/>
- <name name="get_chars" arity="3"/>
+ <name name="get_chars" arity="2" since=""/>
+ <name name="get_chars" arity="3" since=""/>
<fsummary>Read a specified number of characters.</fsummary>
<type name="server_no_data"/>
<desc>
@@ -666,8 +722,8 @@ enter><input>:</input> <input>alan</input> <input>:</input> <input>joe</in
</func>
<func>
- <name name="get_line" arity="1"/>
- <name name="get_line" arity="2"/>
+ <name name="get_line" arity="1" since=""/>
+ <name name="get_line" arity="2" since=""/>
<fsummary>Read a line.</fsummary>
<type name="server_no_data"/>
<desc>
@@ -698,8 +754,8 @@ enter><input>:</input> <input>alan</input> <input>:</input> <input>joe</in
</func>
<func>
- <name name="getopts" arity="0"/>
- <name name="getopts" arity="1"/>
+ <name name="getopts" arity="0" since=""/>
+ <name name="getopts" arity="1" since=""/>
<fsummary>Get the supported options and values from an I/O server.
</fsummary>
<desc>
@@ -725,8 +781,8 @@ enter><input>:</input> <input>alan</input> <input>:</input> <input>joe</in
</func>
<func>
- <name name="nl" arity="0"/>
- <name name="nl" arity="1"/>
+ <name name="nl" arity="0" since=""/>
+ <name name="nl" arity="1" since=""/>
<fsummary>Write a newline.</fsummary>
<desc>
<p>Writes new line to the standard output
@@ -735,10 +791,10 @@ enter><input>:</input> <input>alan</input> <input>:</input> <input>joe</in
</func>
<func>
- <name name="parse_erl_exprs" arity="1"/>
- <name name="parse_erl_exprs" arity="2"/>
- <name name="parse_erl_exprs" arity="3"/>
- <name name="parse_erl_exprs" arity="4"/>
+ <name name="parse_erl_exprs" arity="1" since=""/>
+ <name name="parse_erl_exprs" arity="2" since=""/>
+ <name name="parse_erl_exprs" arity="3" since=""/>
+ <name name="parse_erl_exprs" arity="4" since="OTP R16B"/>
<fsummary>Read, tokenize, and parse Erlang expressions.</fsummary>
<type name="parse_ret"/>
<type name="server_no_data"/>
@@ -788,10 +844,10 @@ enter><input>abc("hey".</input>
</func>
<func>
- <name name="parse_erl_form" arity="1"/>
- <name name="parse_erl_form" arity="2"/>
- <name name="parse_erl_form" arity="3"/>
- <name name="parse_erl_form" arity="4"/>
+ <name name="parse_erl_form" arity="1" since=""/>
+ <name name="parse_erl_form" arity="2" since=""/>
+ <name name="parse_erl_form" arity="3" since=""/>
+ <name name="parse_erl_form" arity="4" since="OTP R16B"/>
<fsummary>Read, tokenize, and parse an Erlang form.</fsummary>
<type name="parse_form_ret"/>
<type name="server_no_data"/>
@@ -832,7 +888,7 @@ enter><input>abc("hey".</input>
</func>
<func>
- <name name="printable_range" arity="0"/>
+ <name name="printable_range" arity="0" since="OTP R16B"/>
<fsummary>Get user-requested printable character range.</fsummary>
<desc>
<p>Returns the user-requested range of printable Unicode characters.</p>
@@ -862,8 +918,8 @@ enter><input>abc("hey".</input>
</func>
<func>
- <name name="put_chars" arity="1"/>
- <name name="put_chars" arity="2"/>
+ <name name="put_chars" arity="1" since=""/>
+ <name name="put_chars" arity="2" since=""/>
<fsummary>Write a list of characters.</fsummary>
<desc>
<p>Writes the characters of <c><anno>CharData</anno></c> to the I/O
@@ -872,8 +928,8 @@ enter><input>abc("hey".</input>
</func>
<func>
- <name name="read" arity="1"/>
- <name name="read" arity="2"/>
+ <name name="read" arity="1" since=""/>
+ <name name="read" arity="2" since=""/>
<fsummary>Read a term.</fsummary>
<type name="server_no_data"/>
<desc>
@@ -904,8 +960,8 @@ enter><input>abc("hey".</input>
</func>
<func>
- <name name="read" arity="3"/>
- <name name="read" arity="4"/>
+ <name name="read" arity="3" since=""/>
+ <name name="read" arity="4" since="OTP R16B"/>
<fsummary>Read a term.</fsummary>
<type name="server_no_data"/>
<desc>
@@ -941,8 +997,8 @@ enter><input>abc("hey".</input>
</func>
<func>
- <name name="rows" arity="0"/>
- <name name="rows" arity="1"/>
+ <name name="rows" arity="0" since=""/>
+ <name name="rows" arity="1" since=""/>
<fsummary>Get the number of rows of an I/O device.</fsummary>
<desc>
<p>Retrieves the number of rows of <c><anno>IoDevice</anno></c>
@@ -953,10 +1009,10 @@ enter><input>abc("hey".</input>
</func>
<func>
- <name name="scan_erl_exprs" arity="1"/>
- <name name="scan_erl_exprs" arity="2"/>
- <name name="scan_erl_exprs" arity="3"/>
- <name name="scan_erl_exprs" arity="4"/>
+ <name name="scan_erl_exprs" arity="1" since=""/>
+ <name name="scan_erl_exprs" arity="2" since=""/>
+ <name name="scan_erl_exprs" arity="3" since=""/>
+ <name name="scan_erl_exprs" arity="4" since="OTP R16B"/>
<fsummary>Read and tokenize Erlang expressions.</fsummary>
<type name="server_no_data"/>
<desc>
@@ -1004,10 +1060,10 @@ enter><input>1.0er.</input>
</func>
<func>
- <name name="scan_erl_form" arity="1"/>
- <name name="scan_erl_form" arity="2"/>
- <name name="scan_erl_form" arity="3"/>
- <name name="scan_erl_form" arity="4"/>
+ <name name="scan_erl_form" arity="1" since=""/>
+ <name name="scan_erl_form" arity="2" since=""/>
+ <name name="scan_erl_form" arity="3" since=""/>
+ <name name="scan_erl_form" arity="4" since="OTP R16B"/>
<fsummary>Read and tokenize an Erlang form.</fsummary>
<type name="server_no_data"/>
<desc>
@@ -1027,8 +1083,8 @@ enter><input>1.0er.</input>
</func>
<func>
- <name name="setopts" arity="1"/>
- <name name="setopts" arity="2"/>
+ <name name="setopts" arity="1" since=""/>
+ <name name="setopts" arity="2" since=""/>
<fsummary>Set options.</fsummary>
<desc>
<p>Set options for the standard I/O device
@@ -1142,8 +1198,8 @@ fun("") -> {yes, "quit", []};
</func>
<func>
- <name name="write" arity="1"/>
- <name name="write" arity="2"/>
+ <name name="write" arity="1" since=""/>
+ <name name="write" arity="2" since=""/>
<fsummary>Write a term.</fsummary>
<desc>
<p>Writes term <c><anno>Term</anno></c> to the standard output
diff --git a/lib/stdlib/doc/src/io_lib.xml b/lib/stdlib/doc/src/io_lib.xml
index bc1d77ac83..4d527f8ed3 100644
--- a/lib/stdlib/doc/src/io_lib.xml
+++ b/lib/stdlib/doc/src/io_lib.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>io_lib</module>
+ <module since="">io_lib</module>
<modulesummary>I/O library functions.</modulesummary>
<description>
<p>This module contains functions for converting to and from
@@ -52,6 +52,9 @@
</desc>
</datatype>
<datatype>
+ <name name="chars_limit"/>
+ </datatype>
+ <datatype>
<name name="depth"/>
</datatype>
<datatype>
@@ -96,7 +99,7 @@
<funcs>
<func>
- <name name="build_text" arity="1"/>
+ <name name="build_text" arity="1" since="OTP 18.0"/>
<fsummary>Build the output text for a preparsed format list.</fsummary>
<desc>
<p>For details, see
@@ -105,7 +108,7 @@
</func>
<func>
- <name name="char_list" arity="1"/>
+ <name name="char_list" arity="1" since=""/>
<fsummary>Test for a list of characters.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Term</anno></c> is a flat list of
@@ -114,7 +117,7 @@
</func>
<func>
- <name name="deep_char_list" arity="1"/>
+ <name name="deep_char_list" arity="1" since=""/>
<fsummary>Test for a deep list of characters.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Term</anno></c> is a, possibly deep,
@@ -123,7 +126,7 @@
</func>
<func>
- <name name="deep_latin1_char_list" arity="1"/>
+ <name name="deep_latin1_char_list" arity="1" since="OTP R16B"/>
<fsummary>Test for a deep list of characters.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Term</anno></c> is a, possibly deep,
@@ -133,8 +136,8 @@
</func>
<func>
- <name name="format" arity="2"/>
- <name name="fwrite" arity="2"/>
+ <name name="format" arity="2" since=""/>
+ <name name="fwrite" arity="2" since=""/>
<fsummary>Write formatted output.</fsummary>
<desc>
<p>Returns a character list that represents <c><anno>Data</anno></c>
@@ -153,7 +156,32 @@
</func>
<func>
- <name name="fread" arity="2"/>
+ <name name="format" arity="3" since="OTP 21.0"/>
+ <name name="fwrite" arity="3" since="OTP 21.0"/>
+ <fsummary>Write formatted output.</fsummary>
+ <desc>
+ <p>Returns a character list that represents <c><anno>Data</anno></c>
+ formatted in accordance with <c><anno>Format</anno></c> in
+ the same way as
+ <seealso marker="#fwrite/2"><c>fwrite/2</c></seealso> and
+ <seealso marker="#format/2"><c>format/2</c></seealso>,
+ but takes an extra argument, a list of options.</p>
+ <p>Valid option:</p>
+ <taglist>
+ <tag><c>{chars_limit, <anno>CharsLimit</anno>}</c></tag>
+ <item>
+ <p>A soft limit on the number of characters returned.
+ When the number of characters is reached, remaining
+ structures are replaced by "<c>...</c>".
+ <c><anno>CharsLimit</anno></c> defaults to -1, which
+ means no limit on the number of characters returned.</p>
+ </item>
+ </taglist>
+ </desc>
+ </func>
+
+ <func>
+ <name name="fread" arity="2" since=""/>
<fsummary>Read formatted input.</fsummary>
<desc>
<p>Tries to read <c><anno>String</anno></c> in accordance with the
@@ -194,7 +222,7 @@
</func>
<func>
- <name name="fread" arity="3"/>
+ <name name="fread" arity="3" since=""/>
<fsummary>Re-entrant formatted reader</fsummary>
<desc>
<p>This is the re-entrant formatted reader. The continuation of
@@ -240,7 +268,7 @@
</func>
<func>
- <name name="indentation" arity="2"/>
+ <name name="indentation" arity="2" since=""/>
<fsummary>Indentation after printing string.</fsummary>
<desc>
<p>Returns the indentation if <c><anno>String</anno></c> has been
@@ -249,7 +277,7 @@
</func>
<func>
- <name name="latin1_char_list" arity="1"/>
+ <name name="latin1_char_list" arity="1" since="OTP R16B"/>
<fsummary>Test for a list of ISO Latin-1 characters.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Term</anno></c> is a flat list of
@@ -258,7 +286,7 @@
</func>
<func>
- <name name="nl" arity="0"/>
+ <name name="nl" arity="0" since=""/>
<fsummary>Write a newline.</fsummary>
<desc>
<p>Returns a character list that represents a new line character.</p>
@@ -266,8 +294,8 @@
</func>
<func>
- <name name="print" arity="1"/>
- <name name="print" arity="4"/>
+ <name name="print" arity="1" since=""/>
+ <name name="print" arity="4" since=""/>
<fsummary>Pretty print a term.</fsummary>
<desc>
<p>Returns a list of characters that represents
@@ -287,7 +315,7 @@
</func>
<func>
- <name name="printable_latin1_list" arity="1"/>
+ <name name="printable_latin1_list" arity="1" since="OTP R16B"/>
<fsummary>Test for a list of printable ISO Latin-1 characters.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Term</anno></c> is a flat list of
@@ -296,7 +324,7 @@
</func>
<func>
- <name name="printable_list" arity="1"/>
+ <name name="printable_list" arity="1" since=""/>
<fsummary>Test for a list of printable characters.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Term</anno></c> is a flat list of
@@ -310,7 +338,7 @@
</func>
<func>
- <name name="printable_unicode_list" arity="1"/>
+ <name name="printable_unicode_list" arity="1" since="OTP R16B"/>
<fsummary>Test for a list of printable Unicode characters.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Term</anno></c> is a flat list of
@@ -319,7 +347,7 @@
</func>
<func>
- <name name="scan_format" arity="2"/>
+ <name name="scan_format" arity="2" since="OTP 18.0"/>
<fsummary>Parse all control sequences in the format string.</fsummary>
<desc>
<p>Returns a list corresponding to the specified format string,
@@ -345,7 +373,7 @@
</func>
<func>
- <name name="unscan_format" arity="1"/>
+ <name name="unscan_format" arity="1" since="OTP 18.0"/>
<fsummary>Revert a preparsed format list to a plain character list
and a list of arguments.</fsummary>
<desc>
@@ -355,28 +383,35 @@
</func>
<func>
- <name name="write" arity="1"/>
- <name name="write" arity="2" clause_i="1"/>
- <name name="write" arity="2" clause_i="2"/>
+ <name name="write" arity="1" since=""/>
+ <name name="write" arity="2" clause_i="1" since=""/>
+ <name name="write" arity="2" clause_i="2" since="OTP 20.0"/>
<fsummary>Write a term.</fsummary>
<desc>
<p>Returns a character list that represents <c><anno>Term</anno></c>.
- Argument <c><anno>Depth</anno></c> controls the depth of the
+ Option <c><anno>Depth</anno></c> controls the depth of the
structures written. When the specified depth is reached,
everything below this level is replaced by "<c>...</c>".
<c><anno>Depth</anno></c> defaults to -1, which means
- no limitation.</p>
+ no limitation. Option <c><anno>CharsLimit</anno></c> puts a
+ soft limit on the number of characters returned. When the
+ number of characters is reached, remaining structures are
+ replaced by "<c>...</c>". <c><anno>CharsLimit</anno></c>
+ defaults to -1, which means no limit on the number of
+ characters returned.</p>
<p><em>Example:</em></p>
<pre>
1> <input>lists:flatten(io_lib:write({1,[2],[3],[4,5],6,7,8,9})).</input>
"{1,[2],[3],[4,5],6,7,8,9}"
2> <input>lists:flatten(io_lib:write({1,[2],[3],[4,5],6,7,8,9}, 5)).</input>
-"{1,[2],[3],[...],...}"</pre>
+"{1,[2],[3],[...],...}"
+3> <input>lists:flatten(io_lib:write({[1,2,3],[4,5],6,7,8,9}, [{chars_limit,20}])).</input>
+"{[1,2|...],[4|...],...}"</pre>
</desc>
</func>
<func>
- <name name="write_atom" arity="1"/>
+ <name name="write_atom" arity="1" since=""/>
<fsummary>Write an atom.</fsummary>
<desc>
<p>Returns the list of characters needed to print atom
@@ -385,7 +420,7 @@
</func>
<func>
- <name name="write_atom_as_latin1" arity="1"/>
+ <name name="write_atom_as_latin1" arity="1" since="OTP 20.0"/>
<fsummary>Write an atom.</fsummary>
<desc>
<p>Returns the list of characters needed to print atom
@@ -395,7 +430,7 @@
</func>
<func>
- <name name="write_char" arity="1"/>
+ <name name="write_char" arity="1" since=""/>
<fsummary>Write a character.</fsummary>
<desc>
<p>Returns the list of characters needed to print a character
@@ -404,7 +439,7 @@
</func>
<func>
- <name name="write_char_as_latin1" arity="1"/>
+ <name name="write_char_as_latin1" arity="1" since="OTP R16B"/>
<fsummary>Write a character.</fsummary>
<desc>
<p>Returns the list of characters needed to print a character
@@ -414,7 +449,7 @@
</func>
<func>
- <name name="write_latin1_char" arity="1"/>
+ <name name="write_latin1_char" arity="1" since="OTP R16B"/>
<fsummary>Write an ISO Latin-1 character.</fsummary>
<desc>
<p>Returns the list of characters needed to print a character
@@ -423,7 +458,7 @@
</func>
<func>
- <name name="write_latin1_string" arity="1"/>
+ <name name="write_latin1_string" arity="1" since="OTP R16B"/>
<fsummary>Write an ISO Latin-1 string.</fsummary>
<desc>
<p>Returns the list of characters needed to print
@@ -432,7 +467,7 @@
</func>
<func>
- <name name="write_string" arity="1"/>
+ <name name="write_string" arity="1" since=""/>
<fsummary>Write a string.</fsummary>
<desc>
<p>Returns the list of characters needed to print
@@ -441,7 +476,7 @@
</func>
<func>
- <name name="write_string_as_latin1" arity="1"/>
+ <name name="write_string_as_latin1" arity="1" since="OTP R16B"/>
<fsummary>Write a string.</fsummary>
<desc>
<p>Returns the list of characters needed to print
diff --git a/lib/stdlib/doc/src/lib.xml b/lib/stdlib/doc/src/lib.xml
deleted file mode 100644
index 58dad7c9e0..0000000000
--- a/lib/stdlib/doc/src/lib.xml
+++ /dev/null
@@ -1,103 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1996</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>lib</title>
- <prepared></prepared>
- <docno></docno>
- <date></date>
- <rev></rev>
- </header>
- <module>lib</module>
- <modulesummary>Useful library functions.</modulesummary>
- <description>
- <warning>
- <p>This module is retained for backward compatibility. It can disappear
- without warning in a future Erlang/OTP release.</p>
- </warning>
- </description>
-
- <funcs>
- <func>
- <name name="error_message" arity="2"/>
- <fsummary>Print error message.</fsummary>
- <desc>
- <p>Prints error message <c><anno>Args</anno></c> in accordance with
- <c><anno>Format</anno></c>. Similar to
- <seealso marker="io#format/1"><c>io:format/2</c></seealso>.</p>
- </desc>
- </func>
-
- <func>
- <name name="flush_receive" arity="0"/>
- <fsummary>Flush messages.</fsummary>
- <desc>
- <p>Flushes the message buffer of the current process.</p>
- </desc>
- </func>
-
- <func>
- <name name="nonl" arity="1"/>
- <fsummary>Remove last newline.</fsummary>
- <desc>
- <p>Removes the last newline character, if any, in
- <c><anno>String1</anno></c>.</p>
- </desc>
- </func>
-
- <func>
- <name name="progname" arity="0"/>
- <fsummary>Return name of Erlang start script.</fsummary>
- <desc>
- <p>Returns the name of the script that started the current
- Erlang session.</p>
- </desc>
- </func>
-
- <func>
- <name name="send" arity="2"/>
- <fsummary>Send a message.</fsummary>
- <desc>
- <p>Makes it possible to send a message using the <c>apply/3</c> BIF.</p>
- </desc>
- </func>
-
- <func>
- <name name="sendw" arity="2"/>
- <fsummary>Send a message and wait for an answer.</fsummary>
- <desc>
- <p>As <seealso marker="#send/2"><c>send/2</c></seealso>,
- but waits for an answer. It is implemented as follows:</p>
- <code type="none">
-sendw(To, Msg) ->
- To ! {self(),Msg},
- receive
- Reply -> Reply
- end.</code>
- <p>The returned message is not necessarily a reply to the sent
- message.</p>
- </desc>
- </func>
- </funcs>
-</erlref>
-
diff --git a/lib/stdlib/doc/src/lists.xml b/lib/stdlib/doc/src/lists.xml
index 7efafedc82..2755fb3dce 100644
--- a/lib/stdlib/doc/src/lists.xml
+++ b/lib/stdlib/doc/src/lists.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2019</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -28,7 +28,7 @@
<date>1996-09-28</date>
<rev>A</rev>
</header>
- <module>lists</module>
+ <module since="">lists</module>
<modulesummary>List processing functions.</modulesummary>
<description>
<p>This module contains functions for list processing.</p>
@@ -63,7 +63,7 @@
<funcs>
<func>
- <name name="all" arity="2"/>
+ <name name="all" arity="2" since=""/>
<fsummary>Return <c>true</c> if all elements in a list satisfy
<c>Pred</c>.</fsummary>
<desc>
@@ -74,7 +74,7 @@
</func>
<func>
- <name name="any" arity="2"/>
+ <name name="any" arity="2" since=""/>
<fsummary>Return <c>true</c> if any of the elements in a list
satisfies <c>Pred</c>.</fsummary>
<desc>
@@ -85,7 +85,7 @@
</func>
<func>
- <name name="append" arity="1"/>
+ <name name="append" arity="1" since=""/>
<fsummary>Append a list of lists.</fsummary>
<desc>
<p>Returns a list in which all the sublists of
@@ -98,7 +98,7 @@
</func>
<func>
- <name name="append" arity="2"/>
+ <name name="append" arity="2" since=""/>
<fsummary>Append two lists.</fsummary>
<desc>
<p>Returns a new list <c><anno>List3</anno></c>, which is made from
@@ -113,7 +113,7 @@
</func>
<func>
- <name name="concat" arity="1"/>
+ <name name="concat" arity="1" since=""/>
<fsummary>Concatenate a list of atoms.</fsummary>
<desc>
<p>Concatenates the text representation of the elements of
@@ -127,7 +127,7 @@
</func>
<func>
- <name name="delete" arity="2"/>
+ <name name="delete" arity="2" since=""/>
<fsummary>Delete an element from a list.</fsummary>
<desc>
<p>Returns a copy of <c><anno>List1</anno></c> where the first element
@@ -137,7 +137,7 @@
</func>
<func>
- <name name="droplast" arity="1"/>
+ <name name="droplast" arity="1" since="OTP 17.0"/>
<fsummary>Drop the last element of a list.</fsummary>
<desc>
<p>Drops the last element of a <c><anno>List</anno></c>. The list is to
@@ -147,7 +147,7 @@
</func>
<func>
- <name name="dropwhile" arity="2"/>
+ <name name="dropwhile" arity="2" since=""/>
<fsummary>Drop elements from a list while a predicate is <c>true</c>.
</fsummary>
<desc>
@@ -159,7 +159,7 @@
</func>
<func>
- <name name="duplicate" arity="2"/>
+ <name name="duplicate" arity="2" since=""/>
<fsummary>Make <c>N</c> copies of element.</fsummary>
<desc>
<p>Returns a list containing <c><anno>N</anno></c> copies of term
@@ -172,7 +172,7 @@
</func>
<func>
- <name name="filter" arity="2"/>
+ <name name="filter" arity="2" since=""/>
<fsummary>Select elements that satisfy a predicate.</fsummary>
<desc>
<p><c><anno>List2</anno></c> is a list of all elements
@@ -182,7 +182,7 @@
</func>
<func>
- <name name="filtermap" arity="2"/>
+ <name name="filtermap" arity="2" since="OTP R16B01"/>
<fsummary>Filter and map elements that satisfy a function.</fsummary>
<desc>
<p>Calls <c><anno>Fun</anno>(<anno>Elem</anno>)</c> on successive
@@ -211,7 +211,7 @@ filtermap(Fun, List1) ->
</func>
<func>
- <name name="flatlength" arity="1"/>
+ <name name="flatlength" arity="1" since=""/>
<fsummary>Length of flattened deep list.</fsummary>
<desc>
<p>Equivalent to <c>length(flatten(<anno>DeepList</anno>))</c>, but
@@ -220,7 +220,7 @@ filtermap(Fun, List1) ->
</func>
<func>
- <name name="flatmap" arity="2"/>
+ <name name="flatmap" arity="2" since=""/>
<fsummary>Map and flatten in one pass.</fsummary>
<desc>
<p>Takes a function from <c><anno>A</anno></c>s to lists of
@@ -241,7 +241,7 @@ flatmap(Fun, List1) ->
</func>
<func>
- <name name="flatten" arity="1"/>
+ <name name="flatten" arity="1" since=""/>
<fsummary>Flatten a deep list.</fsummary>
<desc>
<p>Returns a flattened version of <c><anno>DeepList</anno></c>.</p>
@@ -249,7 +249,7 @@ flatmap(Fun, List1) ->
</func>
<func>
- <name name="flatten" arity="2"/>
+ <name name="flatten" arity="2" since=""/>
<fsummary>Flatten a deep list.</fsummary>
<desc>
<p>Returns a flattened version of <c><anno>DeepList</anno></c> with tail
@@ -258,7 +258,7 @@ flatmap(Fun, List1) ->
</func>
<func>
- <name name="foldl" arity="3"/>
+ <name name="foldl" arity="3" since=""/>
<fsummary>Fold a function over a list.</fsummary>
<desc>
<p>Calls <c><anno>Fun</anno>(<anno>Elem</anno>, <anno>AccIn</anno>)</c>
@@ -278,7 +278,7 @@ flatmap(Fun, List1) ->
</func>
<func>
- <name name="foldr" arity="3"/>
+ <name name="foldr" arity="3" since=""/>
<fsummary>Fold a function over a list.</fsummary>
<desc>
<p>Like <seealso marker="#foldl/3"><c>foldl/3</c></seealso>, but the
@@ -297,7 +297,7 @@ flatmap(Fun, List1) ->
</func>
<func>
- <name name="join" arity="2"/>
+ <name name="join" arity="2" since="OTP 19.0"/>
<fsummary>Insert an element between elements in a list</fsummary>
<desc>
<p>Inserts <c><anno>Sep</anno></c> between each element in <c><anno>List1</anno></c>. Has no
@@ -312,7 +312,7 @@ flatmap(Fun, List1) ->
</desc>
</func>
<func>
- <name name="foreach" arity="2"/>
+ <name name="foreach" arity="2" since=""/>
<fsummary>Apply a function to each element of a list.</fsummary>
<desc>
<p>Calls <c><anno>Fun</anno>(<anno>Elem</anno>)</c> for each element
@@ -324,7 +324,7 @@ flatmap(Fun, List1) ->
</func>
<func>
- <name name="keydelete" arity="3"/>
+ <name name="keydelete" arity="3" since=""/>
<fsummary>Delete an element from a list of tuples.</fsummary>
<type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc>
<desc>
@@ -336,7 +336,7 @@ flatmap(Fun, List1) ->
</func>
<func>
- <name name="keyfind" arity="3"/>
+ <name name="keyfind" arity="3" since=""/>
<fsummary>Search for an element in a list of tuples.</fsummary>
<type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc>
<desc>
@@ -349,7 +349,7 @@ flatmap(Fun, List1) ->
</func>
<func>
- <name name="keymap" arity="3"/>
+ <name name="keymap" arity="3" since=""/>
<fsummary>Map a function over a list of tuples.</fsummary>
<type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc>
<desc>
@@ -368,7 +368,7 @@ flatmap(Fun, List1) ->
</func>
<func>
- <name name="keymember" arity="3"/>
+ <name name="keymember" arity="3" since=""/>
<fsummary>Test for membership of a list of tuples.</fsummary>
<type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc>
<desc>
@@ -379,7 +379,7 @@ flatmap(Fun, List1) ->
</func>
<func>
- <name name="keymerge" arity="3"/>
+ <name name="keymerge" arity="3" since=""/>
<fsummary>Merge two key-sorted lists of tuples.</fsummary>
<type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc>
<desc>
@@ -395,7 +395,7 @@ flatmap(Fun, List1) ->
</func>
<func>
- <name name="keyreplace" arity="4"/>
+ <name name="keyreplace" arity="4" since=""/>
<fsummary>Replace an element in a list of tuples.</fsummary>
<type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc>
<desc>
@@ -407,7 +407,7 @@ flatmap(Fun, List1) ->
</func>
<func>
- <name name="keysearch" arity="3"/>
+ <name name="keysearch" arity="3" since=""/>
<fsummary>Search for an element in a list of tuples.</fsummary>
<type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc>
<desc>
@@ -425,7 +425,7 @@ flatmap(Fun, List1) ->
</func>
<func>
- <name name="keysort" arity="2"/>
+ <name name="keysort" arity="2" since=""/>
<fsummary>Sort a list of tuples.</fsummary>
<type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc>
<desc>
@@ -436,7 +436,7 @@ flatmap(Fun, List1) ->
</func>
<func>
- <name name="keystore" arity="4"/>
+ <name name="keystore" arity="4" since=""/>
<fsummary>Store an element in a list of tuples.</fsummary>
<type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc>
<desc>
@@ -452,7 +452,7 @@ flatmap(Fun, List1) ->
</func>
<func>
- <name name="keytake" arity="3"/>
+ <name name="keytake" arity="3" since=""/>
<fsummary>Extract an element from a list of tuples.</fsummary>
<type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc>
<desc>
@@ -467,7 +467,7 @@ flatmap(Fun, List1) ->
</func>
<func>
- <name name="last" arity="1"/>
+ <name name="last" arity="1" since=""/>
<fsummary>Return last element in a list.</fsummary>
<desc>
<p>Returns the last element in <c><anno>List</anno></c>.</p>
@@ -475,7 +475,7 @@ flatmap(Fun, List1) ->
</func>
<func>
- <name name="map" arity="2"/>
+ <name name="map" arity="2" since=""/>
<fsummary>Map a function over a list.</fsummary>
<desc>
<p>Takes a function from <c><anno>A</anno></c>s to
@@ -488,7 +488,7 @@ flatmap(Fun, List1) ->
</func>
<func>
- <name name="mapfoldl" arity="3"/>
+ <name name="mapfoldl" arity="3" since=""/>
<fsummary>Map and fold in one pass.</fsummary>
<desc>
<p>Combines the operations of
@@ -504,7 +504,7 @@ flatmap(Fun, List1) ->
</func>
<func>
- <name name="mapfoldr" arity="3"/>
+ <name name="mapfoldr" arity="3" since=""/>
<fsummary>Map and fold in one pass.</fsummary>
<desc>
<p>Combines the operations of
@@ -514,7 +514,7 @@ flatmap(Fun, List1) ->
</func>
<func>
- <name name="max" arity="1"/>
+ <name name="max" arity="1" since=""/>
<fsummary>Return maximum element of a list.</fsummary>
<desc>
<p>Returns the first element of <c><anno>List</anno></c> that compares
@@ -524,7 +524,7 @@ flatmap(Fun, List1) ->
</func>
<func>
- <name name="member" arity="2"/>
+ <name name="member" arity="2" since=""/>
<fsummary>Test for membership of a list.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Elem</anno></c> matches some element
@@ -533,7 +533,7 @@ flatmap(Fun, List1) ->
</func>
<func>
- <name name="merge" arity="1"/>
+ <name name="merge" arity="1" since=""/>
<fsummary>Merge a list of sorted lists.</fsummary>
<desc>
<p>Returns the sorted list formed by merging all the sublists of
@@ -546,7 +546,7 @@ flatmap(Fun, List1) ->
</func>
<func>
- <name name="merge" arity="2"/>
+ <name name="merge" arity="2" since=""/>
<fsummary>Merge two sorted lists.</fsummary>
<desc>
<p>Returns the sorted list formed by merging <c><anno>List1</anno></c>
@@ -559,7 +559,7 @@ flatmap(Fun, List1) ->
</func>
<func>
- <name name="merge" arity="3"/>
+ <name name="merge" arity="3" since=""/>
<fsummary>Merge two sorted list.</fsummary>
<desc>
<p>Returns the sorted list formed by merging <c><anno>List1</anno></c>
@@ -577,7 +577,7 @@ flatmap(Fun, List1) ->
</func>
<func>
- <name name="merge3" arity="3"/>
+ <name name="merge3" arity="3" since=""/>
<fsummary>Merge three sorted lists.</fsummary>
<desc>
<p>Returns the sorted list formed by merging <c><anno>List1</anno></c>,
@@ -593,7 +593,7 @@ flatmap(Fun, List1) ->
</func>
<func>
- <name name="min" arity="1"/>
+ <name name="min" arity="1" since=""/>
<fsummary>Return minimum element of a list.</fsummary>
<desc>
<p>Returns the first element of <c><anno>List</anno></c> that compares
@@ -603,7 +603,7 @@ flatmap(Fun, List1) ->
</func>
<func>
- <name name="nth" arity="2"/>
+ <name name="nth" arity="2" since=""/>
<fsummary>Return the <c>N</c>th element of a list.</fsummary>
<type_desc variable="N">1..length(<anno>List</anno>)</type_desc>
<desc>
@@ -617,7 +617,7 @@ c</pre>
</func>
<func>
- <name name="nthtail" arity="2"/>
+ <name name="nthtail" arity="2" since=""/>
<fsummary>Return the <c>N</c>th tail of a list.</fsummary>
<type_desc variable="N">0..length(<anno>List</anno>)</type_desc>
<desc>
@@ -638,7 +638,7 @@ c</pre>
</func>
<func>
- <name name="partition" arity="2"/>
+ <name name="partition" arity="2" since=""/>
<fsummary>Partition a list into two lists based on a predicate.</fsummary>
<desc>
<p>Partitions <c><anno>List</anno></c> into two lists, where the first
@@ -658,7 +658,7 @@ c</pre>
</func>
<func>
- <name name="prefix" arity="2"/>
+ <name name="prefix" arity="2" since=""/>
<fsummary>Test for list prefix.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>List1</anno></c> is a prefix of
@@ -667,7 +667,7 @@ c</pre>
</func>
<func>
- <name name="reverse" arity="1"/>
+ <name name="reverse" arity="1" since=""/>
<fsummary>Reverse a list.</fsummary>
<desc>
<p>Returns a list with the elements in <c><anno>List1</anno></c>
@@ -676,7 +676,7 @@ c</pre>
</func>
<func>
- <name name="reverse" arity="2"/>
+ <name name="reverse" arity="2" since=""/>
<fsummary>Reverse a list appending a tail.</fsummary>
<desc>
<p>Returns a list with the elements in <c><anno>List1</anno></c>
@@ -689,8 +689,20 @@ c</pre>
</func>
<func>
- <name name="seq" arity="2"/>
- <name name="seq" arity="3"/>
+ <name name="search" arity="2" since="OTP 21.0"/>
+ <fsummary>Find the first element that satisfies a predicate.</fsummary>
+ <desc>
+ <p>If there is a <c><anno>Value</anno></c> in <c><anno>List</anno></c>
+ such that <c><anno>Pred</anno>(<anno>Value</anno>)</c> returns
+ <c>true</c>, returns <c>{value, <anno>Value</anno>}</c>
+ for the first such <c><anno>Value</anno></c>,
+ otherwise returns <c>false</c>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="seq" arity="2" since=""/>
+ <name name="seq" arity="3" since=""/>
<fsummary>Generate a sequence of integers.</fsummary>
<desc>
<p>Returns a sequence of integers that starts with
@@ -736,7 +748,7 @@ length(lists:seq(From, To, Incr)) =:= (To - From + Incr) div Incr</code>
</func>
<func>
- <name name="sort" arity="1"/>
+ <name name="sort" arity="1" since=""/>
<fsummary>Sort a list.</fsummary>
<desc>
<p>Returns a list containing the sorted elements of
@@ -745,7 +757,7 @@ length(lists:seq(From, To, Incr)) =:= (To - From + Incr) div Incr</code>
</func>
<func>
- <name name="sort" arity="2"/>
+ <name name="sort" arity="2" since=""/>
<fsummary>Sort a list.</fsummary>
<desc>
<p>Returns a list containing the sorted elements of
@@ -759,7 +771,7 @@ length(lists:seq(From, To, Incr)) =:= (To - From + Incr) div Incr</code>
</func>
<func>
- <name name="split" arity="2"/>
+ <name name="split" arity="2" since=""/>
<fsummary>Split a list into two lists.</fsummary>
<type_desc variable="N">0..length(<anno>List1</anno>)</type_desc>
<desc>
@@ -771,7 +783,7 @@ length(lists:seq(From, To, Incr)) =:= (To - From + Incr) div Incr</code>
</func>
<func>
- <name name="splitwith" arity="2"/>
+ <name name="splitwith" arity="2" since=""/>
<fsummary>Split a list into two lists based on a predicate.</fsummary>
<desc>
<p>Partitions <c><anno>List</anno></c> into two lists according to
@@ -792,7 +804,7 @@ splitwith(Pred, List) ->
</func>
<func>
- <name name="sublist" arity="2"/>
+ <name name="sublist" arity="2" since=""/>
<fsummary>Return a sublist of a certain length, starting at the first
position.</fsummary>
<desc>
@@ -804,7 +816,7 @@ splitwith(Pred, List) ->
</func>
<func>
- <name name="sublist" arity="3"/>
+ <name name="sublist" arity="3" since=""/>
<fsummary>Return a sublist starting at a specified position and with a
specified number of elements.</fsummary>
<type_desc variable="Start">1..(length(<anno>List1</anno>)+1)</type_desc>
@@ -826,7 +838,7 @@ splitwith(Pred, List) ->
</func>
<func>
- <name name="subtract" arity="2"/>
+ <name name="subtract" arity="2" since=""/>
<fsummary>Subtract the element in one list from another list.</fsummary>
<desc>
<p>Returns a new list <c><anno>List3</anno></c> that is a copy of
@@ -838,19 +850,11 @@ splitwith(Pred, List) ->
> <input>lists:subtract("123212", "212").</input>
"312".</pre>
<p><c>lists:subtract(A, B)</c> is equivalent to <c>A -- B</c>.</p>
- <warning>
- <p>The complexity of <c>lists:subtract(A, B)</c> is proportional to
- <c>length(A)*length(B)</c>, meaning that it is very slow if both
- <c>A</c> and <c>B</c> are long lists. (If both lists are long, it
- is a much better choice to use ordered lists and
- <seealso marker="ordsets#subtract/2">
- <c>ordsets:subtract/2</c></seealso>.</p>
- </warning>
</desc>
</func>
<func>
- <name name="suffix" arity="2"/>
+ <name name="suffix" arity="2" since=""/>
<fsummary>Test for list suffix.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>List1</anno></c> is a suffix of
@@ -859,7 +863,7 @@ splitwith(Pred, List) ->
</func>
<func>
- <name name="sum" arity="1"/>
+ <name name="sum" arity="1" since=""/>
<fsummary>Return the sum of elements in a list.</fsummary>
<desc>
<p>Returns the sum of the elements in <c><anno>List</anno></c>.</p>
@@ -867,7 +871,7 @@ splitwith(Pred, List) ->
</func>
<func>
- <name name="takewhile" arity="2"/>
+ <name name="takewhile" arity="2" since=""/>
<fsummary>Take elements from a list while a predicate is <c>true</c>.
</fsummary>
<desc>
@@ -880,7 +884,7 @@ splitwith(Pred, List) ->
</func>
<func>
- <name name="ukeymerge" arity="3"/>
+ <name name="ukeymerge" arity="3" since=""/>
<fsummary>Merge two key-sorted lists of tuples, removing duplicates.
</fsummary>
<type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc>
@@ -898,7 +902,7 @@ splitwith(Pred, List) ->
</func>
<func>
- <name name="ukeysort" arity="2"/>
+ <name name="ukeysort" arity="2" since=""/>
<fsummary>Sort a list of tuples, removing duplicates.</fsummary>
<type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc>
<desc>
@@ -910,7 +914,7 @@ splitwith(Pred, List) ->
</func>
<func>
- <name name="umerge" arity="1"/>
+ <name name="umerge" arity="1" since=""/>
<fsummary>Merge a list of sorted lists, removing duplicates.</fsummary>
<desc>
<p>Returns the sorted list formed by merging all the sublists
@@ -923,7 +927,7 @@ splitwith(Pred, List) ->
</func>
<func>
- <name name="umerge" arity="2"/>
+ <name name="umerge" arity="2" since=""/>
<fsummary>Merge two sorted lists, removing duplicates.</fsummary>
<desc>
<p>Returns the sorted list formed by merging <c><anno>List1</anno></c>
@@ -937,7 +941,7 @@ splitwith(Pred, List) ->
</func>
<func>
- <name name="umerge" arity="3"/>
+ <name name="umerge" arity="3" since=""/>
<fsummary>Merge two sorted lists, removing duplicates.</fsummary>
<desc>
<p>Returns the sorted list formed by merging <c><anno>List1</anno></c>
@@ -954,7 +958,7 @@ splitwith(Pred, List) ->
</func>
<func>
- <name name="umerge3" arity="3"/>
+ <name name="umerge3" arity="3" since=""/>
<fsummary>Merge three sorted lists, removing duplicates.</fsummary>
<desc>
<p>Returns the sorted list formed by merging <c><anno>List1</anno></c>,
@@ -969,7 +973,7 @@ splitwith(Pred, List) ->
</func>
<func>
- <name name="unzip" arity="1"/>
+ <name name="unzip" arity="1" since=""/>
<fsummary>Unzip a list of two-tuples into two lists.</fsummary>
<desc>
<p>"Unzips" a list of two-tuples into two lists, where the first
@@ -979,7 +983,7 @@ splitwith(Pred, List) ->
</func>
<func>
- <name name="unzip3" arity="1"/>
+ <name name="unzip3" arity="1" since=""/>
<fsummary>Unzip a list of three-tuples into three lists.</fsummary>
<desc>
<p>"Unzips" a list of three-tuples into three lists, where
@@ -990,7 +994,7 @@ splitwith(Pred, List) ->
</func>
<func>
- <name name="usort" arity="1"/>
+ <name name="usort" arity="1" since=""/>
<fsummary>Sort a list, removing duplicates.</fsummary>
<desc>
<p>Returns a list containing the sorted elements of
@@ -1000,7 +1004,7 @@ splitwith(Pred, List) ->
</func>
<func>
- <name name="usort" arity="2"/>
+ <name name="usort" arity="2" since=""/>
<fsummary>Sort a list, removing duplicates.</fsummary>
<desc>
<p>Returns a list containing the sorted elements of
@@ -1015,7 +1019,7 @@ splitwith(Pred, List) ->
</func>
<func>
- <name name="zip" arity="2"/>
+ <name name="zip" arity="2" since=""/>
<fsummary>Zip two lists into a list of two-tuples.</fsummary>
<desc>
<p>"Zips" two lists of equal length into one list of two-tuples,
@@ -1026,7 +1030,7 @@ splitwith(Pred, List) ->
</func>
<func>
- <name name="zip3" arity="3"/>
+ <name name="zip3" arity="3" since=""/>
<fsummary>Zip three lists into a list of three-tuples.</fsummary>
<desc>
<p>"Zips" three lists of equal length into one list of
@@ -1038,7 +1042,7 @@ splitwith(Pred, List) ->
</func>
<func>
- <name name="zipwith" arity="3"/>
+ <name name="zipwith" arity="3" since=""/>
<fsummary>Zip two lists into one list according to a fun.</fsummary>
<desc>
<p>Combines the elements of two lists of equal length into one list.
@@ -1055,7 +1059,7 @@ splitwith(Pred, List) ->
</func>
<func>
- <name name="zipwith3" arity="4"/>
+ <name name="zipwith3" arity="4" since=""/>
<fsummary>Zip three lists into one list according to a fun.</fsummary>
<desc>
<p>Combines the elements of three lists of equal length into one
diff --git a/lib/stdlib/doc/src/log_mf_h.xml b/lib/stdlib/doc/src/log_mf_h.xml
index edc3d31025..b922006cc0 100644
--- a/lib/stdlib/doc/src/log_mf_h.xml
+++ b/lib/stdlib/doc/src/log_mf_h.xml
@@ -34,7 +34,7 @@
<rev>A</rev>
<file>log_mf_h.xml</file>
</header>
- <module>log_mf_h</module>
+ <module since="">log_mf_h</module>
<modulesummary>An event handler that logs events to disk.</modulesummary>
<description>
<p>This module is a <c>gen_event</c> handler module that can be installed
@@ -60,8 +60,8 @@
<funcs>
<func>
- <name name="init" arity="3"/>
- <name name="init" arity="4"/>
+ <name name="init" arity="3" since=""/>
+ <name name="init" arity="4" since=""/>
<fsummary>Initiate the event handler.</fsummary>
<desc>
<p>Initiates the event handler. Returns <c><anno>Args</anno></c>, which
diff --git a/lib/stdlib/doc/src/maps.xml b/lib/stdlib/doc/src/maps.xml
index 8c7270816b..8e88882b56 100644
--- a/lib/stdlib/doc/src/maps.xml
+++ b/lib/stdlib/doc/src/maps.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2013</year><year>2016</year>
+ <year>2013</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -27,22 +27,42 @@
<date>2014-02-28</date>
<rev>A</rev>
</header>
- <module>maps</module>
+ <module since="OTP 17.0">maps</module>
<modulesummary>Maps processing functions.</modulesummary>
<description>
<p>This module contains functions for maps processing.</p>
</description>
+ <datatypes>
+ <datatype>
+ <name name="iterator" n_vars="2"/>
+ <desc>
+ <p>An iterator representing the associations in a map with keys of type
+ <c><anno>Key</anno></c> and values of type <c><anno>Value</anno></c>.</p>
+ <p>Created using <seealso marker="#iterator-1"><c>maps:iterator/1</c></seealso>.</p>
+ <p>Consumed by <seealso marker="#next-1"><c>maps:next/1</c></seealso>,
+ <seealso marker="#filter-2"><c>maps:filter/2</c></seealso>,
+ <seealso marker="#fold-3"><c>maps:fold/3</c></seealso> and
+ <seealso marker="#map-2"><c>maps:map/2</c></seealso>.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="iterator" n_vars="0"/>
+ </datatype>
+ </datatypes>
+
<funcs>
<func>
- <name name="filter" arity="2"/>
+ <name name="filter" arity="2" since="OTP 18.0"/>
<fsummary>Select pairs that satisfy a predicate.</fsummary>
<desc>
- <p>Returns a map <c><anno>Map2</anno></c> for which predicate
- <c><anno>Pred</anno></c> holds true in <c><anno>Map1</anno></c>.</p>
+ <p>Returns a map <c><anno>Map</anno></c> for which predicate
+ <c><anno>Pred</anno></c> holds true in <c><anno>MapOrIter</anno></c>.</p>
<p>The call fails with a <c>{badmap,Map}</c> exception if
- <c><anno>Map1</anno></c> is not a map, or with <c>badarg</c> if
- <c><anno>Pred</anno></c> is not a function of arity 2.</p>
+ <c><anno>MapOrIter</anno></c> is not a map or valid iterator,
+ or with <c>badarg</c> if <c><anno>Pred</anno></c> is not a
+ function of arity 2.</p>
<p><em>Example:</em></p>
<code type="none">
> M = #{a => 2, b => 3, c=> 4, "a" => 1, "b" => 2, "c" => 4},
@@ -53,7 +73,7 @@
</func>
<func>
- <name name="find" arity="2"/>
+ <name name="find" arity="2" since="OTP 17.0"/>
<fsummary></fsummary>
<desc>
<p>Returns a tuple <c>{ok, Value}</c>, where <c><anno>Value</anno></c>
@@ -72,16 +92,20 @@
</func>
<func>
- <name name="fold" arity="3"/>
+ <name name="fold" arity="3" since="OTP 17.0"/>
<fsummary></fsummary>
<desc>
- <p>Calls <c>F(K, V, AccIn)</c> for every <c><anno>K</anno></c> to value
- <c><anno>V</anno></c> association in <c><anno>Map</anno></c> in
- any order. Function <c>fun F/3</c> must return a new
- accumulator, which is passed to the next successive call.
- This function returns the final value of the accumulator. The initial
- accumulator value <c><anno>Init</anno></c> is returned if the map is
- empty.</p>
+ <p>Calls <c>F(Key, Value, AccIn)</c> for every <c><anno>Key</anno></c>
+ to value <c><anno>Value</anno></c> association in
+ <c><anno>MapOrIter</anno></c> in any order. Function <c>fun F/3</c>
+ must return a new accumulator, which is passed to the next successive
+ call. This function returns the final value of the accumulator.
+ The initial accumulator value <c><anno>Init</anno></c> is returned
+ if the map is empty.</p>
+ <p>The call fails with a <c>{badmap,Map}</c> exception if
+ <c><anno>MapOrIter</anno></c> is not a map or valid iterator,
+ or with <c>badarg</c> if <c><anno>Fun</anno></c> is not a
+ function of arity 3.</p>
<p><em>Example:</em></p>
<code type="none">
> Fun = fun(K,V,AccIn) when is_list(K) -> AccIn + V end,
@@ -92,7 +116,7 @@
</func>
<func>
- <name name="from_list" arity="1"/>
+ <name name="from_list" arity="1" since="OTP 17.0"/>
<fsummary></fsummary>
<desc>
<p>Takes a list of key-value tuples elements and builds a map. The
@@ -109,7 +133,7 @@
</func>
<func>
- <name name="get" arity="2"/>
+ <name name="get" arity="2" since="OTP 17.0"/>
<fsummary></fsummary>
<desc>
<p>Returns value <c><anno>Value</anno></c> associated with
@@ -128,7 +152,7 @@
</func>
<func>
- <name name="get" arity="3"/>
+ <name name="get" arity="3" since="OTP 17.1"/>
<fsummary></fsummary>
<desc>
<p>Returns value <c><anno>Value</anno></c> associated with
@@ -149,7 +173,7 @@ val1
</func>
<func>
- <name name="is_key" arity="2"/>
+ <name name="is_key" arity="2" since="OTP 17.0"/>
<fsummary></fsummary>
<desc>
<p>Returns <c>true</c> if map <c><anno>Map</anno></c> contains
@@ -169,7 +193,33 @@ false</code>
</func>
<func>
- <name name="keys" arity="1"/>
+ <name name="iterator" arity="1" since="OTP 21.0"/>
+ <fsummary>Create a map iterator.</fsummary>
+ <desc>
+ <p>Returns a map iterator <c><anno>Iterator</anno></c> that can
+ be used by <seealso marker="#next-1"><c>maps:next/1</c></seealso>
+ to traverse the key-value associations in a map. When iterating
+ over a map, the memory usage is guaranteed to be bounded no matter
+ the size of the map.</p>
+ <p>The call fails with a <c>{badmap,Map}</c> exception if
+ <c><anno>Map</anno></c> is not a map.</p>
+ <p><em>Example:</em></p>
+ <code type="none">
+> M = #{ a => 1, b => 2 }.
+#{a => 1,b => 2}
+> I = maps:iterator(M), ok.
+ok
+> {K1, V1, I2} = maps:next(I), {K1, V1}.
+{a,1}
+> {K2, V2, I3} = maps:next(I2),{K2, V2}.
+{b,2}
+> maps:next(I3).
+none</code>
+ </desc>
+ </func>
+
+ <func>
+ <name name="keys" arity="1" since="OTP 17.0"/>
<fsummary></fsummary>
<desc>
<p>Returns a complete list of keys, in any order, which resides
@@ -185,15 +235,20 @@ false</code>
</func>
<func>
- <name name="map" arity="2"/>
+ <name name="map" arity="2" since="OTP 17.0"/>
<fsummary></fsummary>
<desc>
- <p>Produces a new map <c><anno>Map2</anno></c> by calling function
- <c>fun F(K, V1)</c> for every <c><anno>K</anno></c> to value
- <c><anno>V1</anno></c> association in <c><anno>Map1</anno></c> in
- any order. Function <c>fun F/2</c> must return value
- <c><anno>V2</anno></c> to be associated with key <c><anno>K</anno></c>
- for the new map <c><anno>Map2</anno></c>.</p>
+ <p>Produces a new map <c><anno>Map</anno></c> by calling function
+ <c>fun F(Key, Value1)</c> for every <c><anno>Key</anno></c> to value
+ <c><anno>Value1</anno></c> association in
+ <c><anno>MapOrIter</anno></c> in any order. Function <c>fun Fun/2</c>
+ must return value <c><anno>Value2</anno></c> to be associated with
+ key <c><anno>Key</anno></c> for the new map
+ <c><anno>Map</anno></c>.</p>
+ <p>The call fails with a <c>{badmap,Map}</c> exception if
+ <c><anno>MapOrIter</anno></c> is not a map or valid iterator,
+ or with <c>badarg</c> if <c><anno>Fun</anno></c> is not a
+ function of arity 2.</p>
<p><em>Example:</em></p>
<code type="none">
> Fun = fun(K,V1) when is_list(K) -> V1*2 end,
@@ -204,7 +259,7 @@ false</code>
</func>
<func>
- <name name="merge" arity="2"/>
+ <name name="merge" arity="2" since="OTP 17.0"/>
<fsummary></fsummary>
<desc>
<p>Merges two maps into a single map <c><anno>Map3</anno></c>. If two
@@ -222,7 +277,7 @@ false</code>
</func>
<func>
- <name name="new" arity="0"/>
+ <name name="new" arity="0" since="OTP 17.0"/>
<fsummary></fsummary>
<desc>
<p>Returns a new empty map.</p>
@@ -234,7 +289,36 @@ false</code>
</func>
<func>
- <name name="put" arity="3"/>
+ <name name="next" arity="1" since="OTP 21.0"/>
+ <fsummary>Get the next key and value from an iterator.</fsummary>
+ <desc>
+ <p>Returns the next key-value association in
+ <c><anno>Iterator</anno></c> and a new iterator for the
+ remaining associations in the iterator.
+ </p>
+ <p>
+ If there are no more associations in the iterator,
+ <c>none</c> is returned.
+ </p>
+ <p><em>Example:</em></p>
+ <code type="none">
+> Map = #{a => 1, b => 2, c => 3}.
+#{a => 1,b => 2,c => 3}
+> I = maps:iterator(Map), ok.
+ok
+> {K1, V1, I1} = maps:next(I), {K1, V1}.
+{a,1}
+> {K2, V2, I2} = maps:next(I1), {K2, V2}.
+{b,2}
+> {K3, V3, I3} = maps:next(I2), {K3, V3}.
+{c,3}
+> maps:next(I3).
+none</code>
+ </desc>
+ </func>
+
+ <func>
+ <name name="put" arity="3" since="OTP 17.0"/>
<fsummary></fsummary>
<desc>
<p>Associates <c><anno>Key</anno></c> with value
@@ -258,7 +342,7 @@ false</code>
</func>
<func>
- <name name="remove" arity="2"/>
+ <name name="remove" arity="2" since="OTP 17.0"/>
<fsummary></fsummary>
<desc>
<p>Removes the <c><anno>Key</anno></c>, if it exists, and its
@@ -278,7 +362,7 @@ false</code>
</func>
<func>
- <name name="size" arity="1"/>
+ <name name="size" arity="1" since="OTP 17.0"/>
<fsummary></fsummary>
<desc>
<p>Returns the number of key-value associations in
@@ -292,7 +376,7 @@ false</code>
</func>
<func>
- <name name="take" arity="2"/>
+ <name name="take" arity="2" since="OTP 19.0"/>
<fsummary></fsummary>
<desc>
<p>The function removes the <c><anno>Key</anno></c>, if it
@@ -317,7 +401,7 @@ error</code>
</func>
<func>
- <name name="to_list" arity="1"/>
+ <name name="to_list" arity="1" since="OTP 17.0"/>
<fsummary></fsummary>
<desc>
<p>Returns a list of pairs representing the key-value associations of
@@ -334,7 +418,7 @@ error</code>
</func>
<func>
- <name name="update" arity="3"/>
+ <name name="update" arity="3" since="OTP 17.0"/>
<fsummary></fsummary>
<desc>
<p>If <c><anno>Key</anno></c> exists in <c><anno>Map1</anno></c>, the
@@ -354,7 +438,7 @@ error</code>
</func>
<func>
- <name name="update_with" arity="3"/>
+ <name name="update_with" arity="3" since="OTP 19.0"/>
<fsummary></fsummary>
<desc>
<p>Update a value in a <c><anno>Map1</anno></c> associated
@@ -373,7 +457,7 @@ error</code>
</func>
<func>
- <name name="update_with" arity="4"/>
+ <name name="update_with" arity="4" since="OTP 19.0"/>
<fsummary></fsummary>
<desc>
<p>Update a value in a <c><anno>Map1</anno></c> associated
@@ -393,7 +477,7 @@ error</code>
</func>
<func>
- <name name="values" arity="1"/>
+ <name name="values" arity="1" since="OTP 17.0"/>
<fsummary></fsummary>
<desc>
<p>Returns a complete list of values, in arbitrary order, contained in
@@ -409,7 +493,7 @@ error</code>
</func>
<func>
- <name name="with" arity="2"/>
+ <name name="with" arity="2" since="OTP 17.3"/>
<fsummary></fsummary>
<desc>
<p>Returns a new map <c><anno>Map2</anno></c> with the keys <c>K1</c>
@@ -426,7 +510,7 @@ error</code>
</func>
<func>
- <name name="without" arity="2"/>
+ <name name="without" arity="2" since="OTP 17.0"/>
<fsummary></fsummary>
<desc>
<p>Returns a new map <c><anno>Map2</anno></c> without keys <c>K1</c>
diff --git a/lib/stdlib/doc/src/math.xml b/lib/stdlib/doc/src/math.xml
index b4f096217a..d89310e2c8 100644
--- a/lib/stdlib/doc/src/math.xml
+++ b/lib/stdlib/doc/src/math.xml
@@ -34,7 +34,7 @@
<rev>B</rev>
<file>math.xml</file>
</header>
- <module>math</module>
+ <module since="">math</module>
<modulesummary>Mathematical functions.</modulesummary>
<description>
<p>This module provides an interface to a number of mathematical
@@ -50,28 +50,28 @@
<funcs>
<func>
- <name name="acos" arity="1"/>
- <name name="acosh" arity="1"/>
- <name name="asin" arity="1"/>
- <name name="asinh" arity="1"/>
- <name name="atan" arity="1"/>
- <name name="atan2" arity="2"/>
- <name name="atanh" arity="1"/>
- <name name="ceil" arity="1"/>
- <name name="cos" arity="1"/>
- <name name="cosh" arity="1"/>
- <name name="exp" arity="1"/>
- <name name="floor" arity="1"/>
- <name name="fmod" arity="2"/>
- <name name="log" arity="1"/>
- <name name="log10" arity="1"/>
- <name name="log2" arity="1"/>
- <name name="pow" arity="2"/>
- <name name="sin" arity="1"/>
- <name name="sinh" arity="1"/>
- <name name="sqrt" arity="1"/>
- <name name="tan" arity="1"/>
- <name name="tanh" arity="1"/>
+ <name name="acos" arity="1" since=""/>
+ <name name="acosh" arity="1" since=""/>
+ <name name="asin" arity="1" since=""/>
+ <name name="asinh" arity="1" since=""/>
+ <name name="atan" arity="1" since=""/>
+ <name name="atan2" arity="2" since=""/>
+ <name name="atanh" arity="1" since=""/>
+ <name name="ceil" arity="1" since="OTP 20.0"/>
+ <name name="cos" arity="1" since=""/>
+ <name name="cosh" arity="1" since=""/>
+ <name name="exp" arity="1" since=""/>
+ <name name="floor" arity="1" since="OTP 20.0"/>
+ <name name="fmod" arity="2" since="OTP 20.0"/>
+ <name name="log" arity="1" since=""/>
+ <name name="log10" arity="1" since=""/>
+ <name name="log2" arity="1" since="OTP 18.0"/>
+ <name name="pow" arity="2" since=""/>
+ <name name="sin" arity="1" since=""/>
+ <name name="sinh" arity="1" since=""/>
+ <name name="sqrt" arity="1" since=""/>
+ <name name="tan" arity="1" since=""/>
+ <name name="tanh" arity="1" since=""/>
<fsummary>Diverse math functions.</fsummary>
<type variable="X" name_i="6"/>
<type variable="Y" name_i="6"/>
@@ -82,7 +82,7 @@
</func>
<func>
- <name name="erf" arity="1"/>
+ <name name="erf" arity="1" since=""/>
<fsummary>Error function.</fsummary>
<desc>
<p>Returns the error function of <c><anno>X</anno></c>, where:</p>
@@ -92,7 +92,7 @@ erf(X) = 2/sqrt(pi)*integral from 0 to X of exp(-t*t) dt.</pre>
</func>
<func>
- <name name="erfc" arity="1"/>
+ <name name="erfc" arity="1" since=""/>
<fsummary>Another error function.</fsummary>
<desc>
<p><c>erfc(X)</c> returns <c>1.0</c> - <c>erf(X)</c>, computed by
@@ -101,7 +101,7 @@ erf(X) = 2/sqrt(pi)*integral from 0 to X of exp(-t*t) dt.</pre>
</func>
<func>
- <name name="pi" arity="0"/>
+ <name name="pi" arity="0" since=""/>
<fsummary>A useful number.</fsummary>
<desc>
<p>A useful number.</p>
diff --git a/lib/stdlib/doc/src/ms_transform.xml b/lib/stdlib/doc/src/ms_transform.xml
index 0a05fa37c5..65cc150507 100644
--- a/lib/stdlib/doc/src/ms_transform.xml
+++ b/lib/stdlib/doc/src/ms_transform.xml
@@ -32,7 +32,7 @@
<rev>C</rev>
<file>ms_transform.xml</file>
</header>
- <module>ms_transform</module>
+ <module since="">ms_transform</module>
<modulesummary>A parse transformation that translates fun syntax into match
specifications.</modulesummary>
<description>
@@ -731,7 +731,7 @@ ets:select(Table, [{{'$1',test,'$2'},[],['$_']}]).</code>
<funcs>
<func>
- <name name="format_error" arity="1"/>
+ <name name="format_error" arity="1" since=""/>
<fsummary>Error formatting function as required by the parse transformation interface.</fsummary>
<desc>
<p>Takes an error code returned by one of the other functions
@@ -741,7 +741,7 @@ ets:select(Table, [{{'$1',test,'$2'},[],['$_']}]).</code>
</func>
<func>
- <name name="parse_transform" arity="2"/>
+ <name name="parse_transform" arity="2" since=""/>
<fsummary>Transforms Erlang abstract format containing calls to
ets/dbg:fun2ms/1 into literal match specifications.</fsummary>
<type_desc variable="Options">Option list, required but not used.
@@ -762,7 +762,7 @@ ets:select(Table, [{{'$1',test,'$2'},[],['$_']}]).</code>
</func>
<func>
- <name name="transform_from_shell" arity="3"/>
+ <name name="transform_from_shell" arity="3" since=""/>
<fsummary>Used when transforming funs created in the shell into
match_specifications.</fsummary>
<type_desc variable="BoundEnvironment">List of variable bindings in the
diff --git a/lib/stdlib/doc/src/notes.xml b/lib/stdlib/doc/src/notes.xml
index bf6b06859e..605a9f224d 100644
--- a/lib/stdlib/doc/src/notes.xml
+++ b/lib/stdlib/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,6 +31,932 @@
</header>
<p>This document describes the changes made to the STDLIB application.</p>
+<section><title>STDLIB 3.9</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Fix a bug in <c>string:lexemes/2</c>. </p> <p> The
+ bug was found when optimizing the handling of deep lists
+ of Unicode characters in the <c>string</c> module. </p>
+ <p>
+ Own Id: OTP-15649</p>
+ </item>
+ <item>
+ <p>A bug has been fixed in the <c>maps</c> implementation
+ that could cause a crash or memory usage to grow until
+ the machine ran out of memory. This could happen when
+ inserting a new key-value pair with a key <c>K1</c>
+ containing a binary <c>B1</c> into a map <c>M</c> having
+ a key <c>K2</c> with a binary <c>B2</c> if the following
+ conditions were met:</p> <list> <item><c>B1 =/=
+ B2</c></item> <item><c>size(B1) >= 4294967296</c></item>
+ <item><c>size(B2) >= 4294967296</c></item>
+ <item><c>size(M) >= 32</c></item> <item><c>(size(B1) rem
+ 4294967296) == (size(B2) rem 4294967296)</c></item>
+ <item>the first <c>(size(B1) rem 4294967296)</c> bytes
+ are the same both in <c>B1</c> and <c>B2</c></item>
+ <item>substituting <c>B1</c> in <c>K1</c> with <c>B2</c>
+ would create a term with the same value as
+ <c>K2</c></item> </list> <p>The root cause of the problem
+ is that the <c>maps</c> implementation only hashed the
+ first <c>(X rem 4294967296)</c> bytes of binaries so that
+ different binaries could get the same hash value
+ independently of the hash seed.</p>
+ <p>
+ Own Id: OTP-15707</p>
+ </item>
+ <item>
+ <p> Since the introduction of the stack trace variable,
+ the Erlang Pretty Printer has left out the exception
+ class <c>throw</c> even when the stack trace variable
+ cannot be left out, which is not correct Erlang code. The
+ fix is to always include the exception class
+ <c>throw</c>. </p>
+ <p>
+ Own Id: OTP-15751</p>
+ </item>
+ <item>
+ <p><c>record_info/2</c> is a pseudo-function that
+ requires literal arguments known at compile time.
+ Therefore, the following usage is illegal: <c>fun
+ record/info/2</c>. The compiler would crash when during
+ compilation of that kind of code. Corrected to issue a
+ compilation error.</p>
+ <p>
+ Own Id: OTP-15760 Aux Id: ERL-907 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> A new <c>rand</c> module algorithm, <c>exro928ss</c>
+ (Xoroshiro928**), has been implemented. It has got a
+ really long period and good statistical quality for all
+ output bits, while still being only about 50% slower than
+ the default algorithm. </p><p> The same generator is also
+ used as a long period counter in a new <c>crypto</c>
+ plugin for the <c>rand</c> module, algorithm
+ <c>crypto_aes</c>. This plugin uses AES-256 to scramble
+ the counter which buries any detectable statistical
+ artifacts. Scrambling is done in chunks which are cached
+ to get good amortized speed (about half of the default
+ algorithm). </p>
+ <p>
+ Own Id: OTP-14461 Aux Id: PR-1857 </p>
+ </item>
+ <item>
+ <p>
+ Types related to server naming and starting have been
+ exported from <c>gen_statem</c>. These are:
+ <c>server_name/0</c>, <c>server_ref/0</c>,
+ <c>start_opt/0</c>, <c>start_ret/0</c> and
+ <c>enter_loop_opt/0</c>.</p>
+ <p>
+ Own Id: OTP-14724 Aux Id: PR-2056 </p>
+ </item>
+ <item>
+ <p>
+ The default algorithm for the <c>rand</c> module has been
+ changed to <c>exsss</c> (Xorshift116**) which is a
+ combination of the Xorshift116 (<c>exsp</c>) state update
+ and a new scrambler "StarStar" from the 2018 paper
+ "Scrambled Linear Pseudorandom Number Generators" by
+ David Blackman and Sebastiano Vigna. This combination
+ should not have the caveat of weak low bits that the
+ previous default algorithm(s) have had, with the cost of
+ about 10% lower speed. See GitHub pull request #1969.</p>
+ <p>
+ Own Id: OTP-14731 Aux Id: PR-1969 </p>
+ </item>
+ <item>
+ <p>
+ The generic state machine behaviour <c>gen_statem</c> has
+ gotten code cleanup and documentation improvements from
+ GitHub Pull Request #1855, even though the PR itself was
+ rejected.</p>
+ <p>
+ Own Id: OTP-14737 Aux Id: PR-1855 </p>
+ </item>
+ <item>
+ <p>
+ Update Unicode specification to version 11.0.</p>
+ <p>
+ Own Id: OTP-15111</p>
+ </item>
+ <item>
+ <p>
+ ETS option <c>write_concurrency</c> now also affects and
+ improves the scalability of <c>ordered_set</c> tables.
+ The implementation is based on a data structure called
+ contention adapting search tree, where the lock
+ granularity adapts to the actual amount of concurrency
+ exploited by the applications in runtime.</p>
+ <p>
+ Own Id: OTP-15128</p>
+ </item>
+ <item>
+ <p>
+ Optimized <c>maps:new/0</c> with trivial Erlang
+ implementation, making use of literal terms (the empty
+ map) not needing dynamic heap allocation.</p>
+ <p>
+ Own Id: OTP-15200 Aux Id: PR-1878 </p>
+ </item>
+ <item>
+ <p>The <c>gen_*</c> behaviours have been changed so that
+ if logging of the last N messages through
+ <c>sys:log/2,3</c> is active for the server, this log is
+ included in the terminate report.</p> <p>To accomplish
+ this the format of "System Events" as defined in the man
+ page for <c>sys</c> has been clarified and cleaned up, a
+ new function <c>sys:get_log/1</c> has been added, and
+ <c>sys:get_debug/3</c> has been deprecated. Due to these
+ changes, code that relies on the internal badly
+ documented format of "System Events", need to be
+ corrected.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15381</p>
+ </item>
+ <item>
+ <p>
+ The <c>gen_statem</c> behaviour engine loop has been
+ optimized for better performance in particular when the
+ callback module returns some actions, that is better
+ performance for more realistic applications than the Echo
+ Benchmark.</p>
+ <p>
+ Own Id: OTP-15452</p>
+ </item>
+ <item>
+ <p> Do not allow function specifications for functions
+ residing in other modules. </p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15563 Aux Id: ERL-845, OTP-15562 </p>
+ </item>
+ <item>
+ <p>
+ The <c>persistent_term</c> functions <c>put/2</c> and
+ <c>erase/1</c> are now yielding.</p>
+ <p>
+ Own Id: OTP-15615</p>
+ </item>
+ <item>
+ <p>Previously, all ETS tables used centralized counter
+ variables to keep track of the number of items stored and
+ the amount of memory consumed. These counters can cause
+ scalability problems (especially on big NUMA systems).
+ This change adds an implementation of a decentralized
+ counter and modifies the implementation of ETS so that
+ ETS tables of type <c>ordered_set</c> with
+ <c>write_concurrency</c> enabled use the decentralized
+ counter. Experiments indicate that this change
+ substantially improves the scalability of ETS
+ <c>ordered_set</c> tables with <c>write_concurrency</c>
+ enabled in scenarios with frequent <c>ets:insert/2</c>
+ and <c>ets:delete/2</c> calls.</p>
+ <p>
+ Own Id: OTP-15623 Aux Id: PR-2190 </p>
+ </item>
+ <item>
+ <p> Use <c>ssh</c> instead of <c>rsh</c> as the default
+ remote shell. </p>
+ <p>
+ Own Id: OTP-15633 Aux Id: PR-1787 </p>
+ </item>
+ <item>
+ <p>Added <c>beam_lib:strip/2</c> and friends, which
+ accept a list of chunks that should be preserved when
+ stripping.</p>
+ <p>
+ Own Id: OTP-15680 Aux Id: PR-2114 </p>
+ </item>
+ <item>
+ <p> Optimize printing of maps with <c>io_lib:write()</c>.
+ Also optimize pretty printing of strings (<c>~s</c> and
+ <c>~ts</c>) when limiting the output with the
+ <c>chars_limit</c> option. </p>
+ <p>
+ Own Id: OTP-15705</p>
+ </item>
+ <item>
+ <p> There are new compiler options <c>nowarn_removed</c>
+ and <c>{nowarn_removed,Items}</c> to suppress warnings
+ for functions and modules that have been removed from
+ OTP.</p>
+ <p>
+ Own Id: OTP-15749 Aux Id: ERL-904 </p>
+ </item>
+ <item>
+ <p> Let the Erlang Pretty Printer put atomic parts on the
+ same line. </p>
+ <p>
+ Own Id: OTP-15755</p>
+ </item>
+ <item>
+ <p> Add option <c>quote_singleton_atom_types</c> to the
+ Erlang Pretty Printer's functions. Setting the option to
+ <c>true</c> adds quotes to all singleton atom types. </p>
+ <p>
+ Own Id: OTP-15756</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>STDLIB 3.8.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A bug in gen_statem has been fixed where the internal
+ timeout message could arrive as an info to the callback
+ module during high load due to incorrect use of
+ asynchronous timer cancel.</p>
+ <p>
+ Own Id: OTP-15295</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>STDLIB 3.8.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a performance regression when reading files
+ opened with the <c>compressed</c> flag.</p>
+ <p>
+ Own Id: OTP-15706 Aux Id: ERIERL-336 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>STDLIB 3.8</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Fix a bug in the Erlang Pretty Printer: long atom
+ names in combination with <c>&lt;&lt;&gt;&gt;</c> could
+ cause a crash. </p>
+ <p>
+ Own Id: OTP-15592 Aux Id: ERL-818 </p>
+ </item>
+ <item>
+ <p> Fix bugs that could cause wrong results or bad
+ performance when formatting lists of characters using the
+ control sequences <c>p</c> or <c>P</c> and limiting the
+ output with the option <c>chars_limit</c>. </p>
+ <p>
+ Own Id: OTP-15639</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Improved ETS documentation about safe table traversal and
+ the partially bound key optimization for
+ <c>ordered_set</c>.</p>
+ <p>
+ Own Id: OTP-15545 Aux Id: PR-2103, PR-2139 </p>
+ </item>
+ <item>
+ <p> Optimize <c>calendar:gregorian_days_to_date/1</c>.
+ </p>
+ <p>
+ Own Id: OTP-15572 Aux Id: PR-2121 </p>
+ </item>
+ <item>
+ <p> Optimize functions
+ <c>calendar:rfc3339_to_system_time()</c> and
+ <c>calendar:system_time_to_rfc3339()</c>. </p>
+ <p>
+ Own Id: OTP-15630</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>STDLIB 3.7.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Optimize pretty printing of terms. The slower
+ behaviour was introduced in Erlang/OTP 20. </p>
+ <p>
+ Own Id: OTP-15573 Aux Id: ERIERL-306 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>STDLIB 3.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Document <c>bit_size</c> in match specifications and
+ allow it in <c>ets:fun2ms</c>.</p>
+ <p>
+ Own Id: OTP-15343 Aux Id: PR-1962 </p>
+ </item>
+ <item>
+ <p>The <c>beam()</c> type in <c>beam_lib</c> is defined
+ as <c>module() | file:filename() | binary()</c>. The
+ <c>module()</c> is misleading. Giving the module name as
+ an atom will only work if the BEAM file is in a current
+ directory.</p>
+ <p>To avoid confusion, <c>module()</c> has been removed
+ from the type. That means that there will be a Dialyzer
+ warning for code that call <c>beam_lib</c> with an atom
+ as filename, but the calls will still work.</p>
+ <p>
+ Own Id: OTP-15378 Aux Id: ERL-696 </p>
+ </item>
+ <item>
+ <p>
+ <c>unicode_util</c> crashed on certain emoji grapheme
+ clusters in binary strings.</p>
+ <p>
+ Own Id: OTP-15428 Aux Id: ERL-777 </p>
+ </item>
+ <item>
+ <p>When an external fun was used, warnings for unused
+ variables could be suppressed.</p>
+ <p>
+ Own Id: OTP-15437 Aux Id: ERL-762 </p>
+ </item>
+ <item>
+ <p>
+ Fix reduction count in lists:member/2</p>
+ <p>
+ Own Id: OTP-15474 Aux Id: ERIERL-229 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>When specified, the <c>+{source,Name}</c> option will
+ now override the actual file name in stack traces,
+ instead of only affecting the return value of
+ <c>Mod:module_info()</c>.</p>
+ <p>The <c>+deterministic</c> flag will also affect stack
+ traces now, omitting all path information except the file
+ name, fixing a long-standing issue where deterministic
+ builds required deterministic paths.</p>
+ <p>
+ Own Id: OTP-15245 Aux Id: ERL-706 </p>
+ </item>
+ <item>
+ <p>List subtraction (The <c>--</c> operator) will now
+ yield properly on large inputs.</p>
+ <p>
+ Own Id: OTP-15371</p>
+ </item>
+ <item>
+ <p>
+ <c>calendar:system_time_to_rfc3339/1,2</c> no longer
+ remove trailing zeros from fractions.</p>
+ <p>
+ Own Id: OTP-15464</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>STDLIB 3.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>The specs of <c>filename:basedir/2,3</c> are
+ corrected.</p>
+ <p>
+ Own Id: OTP-15252 Aux Id: ERL-667 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> Let <c>dets:open_file()</c> exit with a <c>badarg</c>
+ message if given a raw file name (a binary). </p>
+ <p>
+ Own Id: OTP-15253 Aux Id: OTP-13229, ERL-55 </p>
+ </item>
+ <item>
+ <p> The <c>Format</c> argument of the formatting
+ functions in modules <c>io</c> and <c>io_lib</c> is
+ accepted even if it is, for example, a list of binaries.
+ This is how it used to be before Erlang/OTP 21.0. </p>
+ <p>
+ Own Id: OTP-15304</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>STDLIB 3.5.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Fix a bug that could cause a crash when formatting a
+ list of non-characters using the control sequences
+ <c>p</c> or <c>P</c> and limiting the output with the
+ option <c>chars_limit</c>. </p>
+ <p>
+ Own Id: OTP-15159</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>STDLIB 3.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p><c>gen_statem</c> improvements.</p> <p> When using an
+ exception that is valid but not allowed in a state enter
+ call, the reason has been changed from
+ <c>{bad_action_from_state_function,Action}</c> to
+ <c>{bad_state_enter_action_from_state_function,Action}</c>.
+ </p><p> Timer parsing has been improved. Many erroneous
+ timeout tuples was not handled correctly. </p><p> The
+ documentation has been updated, in particular the User's
+ Guide and the pointer to it from the Reference Manual is
+ much more obvious. </p>
+ <p>
+ Own Id: OTP-14015</p>
+ </item>
+ <item>
+ <p>
+ The type specifications for <c>file:posix/0</c> and
+ <c>inet:posix/0</c> have been updated according to which
+ errors file and socket operations should be able to
+ return.</p>
+ <p>
+ Own Id: OTP-14019 Aux Id: ERL-550 </p>
+ </item>
+ <item>
+ <p> File operations used to accept <seealso
+ marker="kernel:file#type-name_all">filenames</seealso>
+ containing null characters (integer value zero). This
+ caused the name to be truncated and in some cases
+ arguments to primitive operations to be mixed up.
+ Filenames containing null characters inside the filename
+ are now <em>rejected</em> and will cause primitive file
+ operations to fail. </p> <p> Also environment variable
+ operations used to accept <seealso
+ marker="kernel:os#type-env_var_name">names</seealso> and
+ <seealso
+ marker="kernel:os#type-env_var_value">values</seealso> of
+ environment variables containing null characters (integer
+ value zero). This caused operations to silently produce
+ erroneous results. Environment variable names and values
+ containing null characters inside the name or value are
+ now <em>rejected</em> and will cause environment variable
+ operations to fail. </p> <p>Primitive environment
+ variable operations also used to accept the <c>$=</c>
+ character in environment variable names causing various
+ problems. <c>$=</c> characters in environment variable
+ names are now also <em>rejected</em>. </p> <p>Also
+ <seealso
+ marker="kernel:os#cmd/1"><c>os:cmd/1</c></seealso> now
+ reject null characters inside its <seealso
+ marker="kernel:os#type-os_command">command</seealso>.
+ </p> <p><seealso
+ marker="erts:erlang#open_port/2"><c>erlang:open_port/2</c></seealso>
+ will also reject null characters inside the port name
+ from now on.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14543 Aux Id: ERL-370 </p>
+ </item>
+ <item>
+ <p> Make <c>io_lib:unscan_format/1</c> work with pad char
+ and default precision. </p>
+ <p>
+ Own Id: OTP-14958 Aux Id: PR-1735 </p>
+ </item>
+ <item>
+ <p> The control sequence modifiers <c>t</c> and <c>l</c>
+ can be used together in the same control sequence which
+ makes it possible to have Unicode atoms and no detection
+ of printable character lists at the same time. </p>
+ <p>
+ Own Id: OTP-14971 Aux Id: PR-1743 </p>
+ </item>
+ <item>
+ <p> Fix a bug in the Erlang code linter: the check of
+ guard expressions no longer returns <c>false</c> if the
+ map syntax is used. The bug affected the Erlang shell,
+ the Debugger, and other modules evaluating abstract code.
+ </p>
+ <p>
+ Own Id: OTP-15035 Aux Id: ERL-613 </p>
+ </item>
+ <item>
+ <p>
+ A sys debug fun of type {Fun,State} should not be
+ possible to install twice. This was, however, possible if
+ the current State was 'undefined', which was mistaken for
+ non-existing fun. This has been corrected.</p>
+ <p>
+ Own Id: OTP-15049</p>
+ </item>
+ <item>
+ <p>
+ Fix <c>io:putchars/2</c> stacktrace rewriting at errors
+ to point to a valid function.</p>
+ <p>
+ Own Id: OTP-15101</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The <c>gen_server</c> has gotten a new callback
+ <c>handle_continue/2</c> for check pointing the state.
+ This is useful at least when implementing behaviours on
+ top of <c>gen_server</c> and for some start up scenarios.</p>
+ <p>
+ Own Id: OTP-13019 Aux Id: PR-1490 </p>
+ </item>
+ <item>
+ <p> The semantics of timeout parameter
+ <c>{clean_timeout,infinity}</c> to
+ <c>gen_statem:call/3</c> has been changed to use a proxy
+ process for the call. With this change
+ <c>clean_timeout</c> implicates a proxy process with no
+ exceptions. This may be a hard to observe
+ incompatibility: in the presence of network problems a
+ late reply could arrive in the caller's message queue
+ when catching errors. That will not happen after this
+ correction. </p><p> The semantics of timeout parameter
+ <c>infinity</c> has not been changed. </p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-13073 Aux Id: PR-1595 </p>
+ </item>
+ <item>
+ <p>A new logging API is added to Erlang/OTP, see the
+ <seealso
+ marker="kernel:logger"><c>logger(3)</c></seealso> manual
+ page, and section <seealso
+ marker="kernel:logger_chapter">Logging</seealso> in the
+ Kernel User's Guide.</p>
+ <p>Calls to <c>error_logger</c> are automatically
+ redirected to the new API, and legacy error logger event
+ handlers can still be used. It is, however, recommended
+ to use the Logger API directly when writing new code.</p>
+ <p>Notice the following potential incompatibilities:</p>
+ <list> <item><p>Kernel configuration parameters
+ <c>error_logger</c> still works, but is overruled if the
+ default handler's output destination is configured with
+ Kernel configuration parameter <c>logger</c>.</p> <p>In
+ general, parameters for configuring error logger are
+ overwritten by new parameters for configuring
+ Logger.</p></item> <item><p>The concept of SASL error
+ logging is deprecated, meaning that by default the SASL
+ application does not affect which log events are
+ logged.</p> <p>By default, supervisor reports and crash
+ reports are logged by the default Logger handler started
+ by Kernel, and end up at the same destination (terminal
+ or file) as other standard log event from Erlang/OTP.</p>
+ <p>Progress reports are not logged by default, but can be
+ enabled by setting the primary log level to info, for
+ example with the Kernel configuration parameter
+ <c>logger_level</c>.</p> <p>To obtain backwards
+ compatibility with the SASL error logging functionality
+ from earlier releases, set Kernel configuration parameter
+ <c>logger_sasl_compatible</c> to <c>true</c>. This
+ prevents the default Logger handler from logging any
+ supervisor-, crash-, or progress reports. Instead, SASL
+ adds a separate Logger handler during application start,
+ which takes care of these log events. The SASL
+ configuration parameters <c>sasl_error_logger</c> and
+ <c>sasl_errlog_type</c> specify the destination (terminal
+ or file) and severity level to log for these
+ events.</p></item></list>
+ <p>
+ Since Logger is new in Erlang/OTP 21.0, we do reserve the
+ right to introduce changes to the Logger API and
+ functionality in patches following this release. These
+ changes might or might not be backwards compatible with
+ the initial version.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-13295</p>
+ </item>
+ <item>
+ <p> Add functions
+ <c>calendar:system_time_to_local_time/2</c> and
+ <c>calendar:system_time_to_universal_time/2</c>. </p>
+ <p>
+ Own Id: OTP-13413</p>
+ </item>
+ <item>
+ <p> Functions <c>rand:uniform_real/0</c> and
+ <c>rand:uniform_real_s/1</c> have been added. They
+ produce uniformly distributed numbers in the range <c>0.0
+ =&lt; X &lt; 1.0</c> that are as close to random real
+ numbers as Normalized IEEE 754 Double Precision allows.
+ Because the random real number exactly <c>0.0</c> is
+ infinitely improbable they will never return exactly
+ <c>0.0</c>. </p><p> These properties are useful when you
+ need to call for example <c>math:log(X)</c> or <c>1 /
+ X</c> on a random value <c>X</c>, since that will never
+ fail with a number from these new functions. </p>
+ <p>
+ Own Id: OTP-13764 Aux Id: PR-1574 </p>
+ </item>
+ <item>
+ <p>
+ Added maps:iterator/0 and maps:next/1 to be used for
+ iterating over the key-value associations in a map.</p>
+ <p>
+ Own Id: OTP-14012</p>
+ </item>
+ <item>
+ <p>Changed the default behaviour of <c>.erlang</c>
+ loading: <c>.erlang</c> is no longer loaded from the
+ current directory. <c>c:erlangrc(PathList)</c> can be
+ used to search and load an <c>.erlang</c> file from user
+ specified directories.</p> <p><c>escript</c>,
+ <c>erlc</c>, <c>dialyzer</c> and <c>typer</c> no longer
+ load an <c>.erlang</c> at all.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14439</p>
+ </item>
+ <item>
+ <p>
+ Added new uri_string module to stdlib for handling URIs
+ (RFC 3986).</p>
+ <p>
+ Own Id: OTP-14496</p>
+ </item>
+ <item>
+ <p>
+ Update Unicode specification to version 10.0.</p>
+ <p>
+ Own Id: OTP-14503</p>
+ </item>
+ <item>
+ <p><c>filelib:wildcard()</c> now allows characters with a
+ special meaning to be escaped using backslashes.</p>
+ <p>This is an incompatible change, but note that the use
+ of backslashes in wildcards would already work
+ differently on Windows and Unix. Existing calls to
+ <c>filelib:wildcard()</c> needs to be updated. On
+ Windows, directory separators must always be written as a
+ slash.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14577</p>
+ </item>
+ <item>
+ <p>
+ The supervisor now stores its child specifications in a
+ map instead of a list. This causes a significant
+ improvement when starting many children under a
+ non-simple_one_for_one supervisor.</p>
+ <p>
+ Own Id: OTP-14586</p>
+ </item>
+ <item>
+ <p> The <c>base64</c> module is optimized. </p> <p> Note
+ that the functions <c>encode/1</c>, <c>decode/1</c>, and
+ <c>mime_decode/1</c> fail unless called with an argument
+ of the documented type. They used to accept any
+ <c>iodata()</c>. </p>
+ <p>
+ Own Id: OTP-14624 Aux Id: PR-1565 </p>
+ </item>
+ <item>
+ <p> Add function <c>lists:search/2</c>. </p>
+ <p>
+ Own Id: OTP-14675 Aux Id: PR-102 </p>
+ </item>
+ <item>
+ <p>
+ uri_string module extended with functions for handling
+ application/x-www-form-urlencoded query strings based on
+ the HTML5 specification.</p>
+ <p>
+ Own Id: OTP-14747</p>
+ </item>
+ <item>
+ <p> Add functions
+ <c>calendar:rfc3339_to_system_time/1,2</c> and
+ <c>calendar:system_time_to_rfc3339/1,2</c>. </p>
+ <p>
+ Own Id: OTP-14764</p>
+ </item>
+ <item>
+ <p> The stack traces returned by the functions of the
+ <c>erl_eval</c> module more accurately reflect where the
+ exception occurred. </p>
+ <p>
+ Own Id: OTP-14826 Aux Id: PR 1540 </p>
+ </item>
+ <item>
+ <p> Add options <c>atime</c>, <c>mtime</c>, <c>ctime</c>,
+ <c>uid</c>, and <c>gid</c> to the <c>erl_tar:add/3,4</c>
+ functions. </p>
+ <p>
+ Own Id: OTP-14834 Aux Id: PR 1608 </p>
+ </item>
+ <item>
+ <p>Added <c>ets:whereis/1</c> for retrieving the table
+ identifier of a named table.</p>
+ <p>
+ Own Id: OTP-14884</p>
+ </item>
+ <item>
+ <p>
+ Improved URI normalization functions in the uri_string
+ module.</p>
+ <p>
+ Own Id: OTP-14910</p>
+ </item>
+ <item>
+ <p> The new functions <c>io_lib:fwrite/3</c> and
+ <c>io_lib:format/3</c> take a third argument, an option
+ list. The only option is <c>chars_limit</c>, which is
+ used for limiting the number of returned characters. The
+ limit is soft, which means that the number of returned
+ characters exceeds the limit with at most a smallish
+ amount. If the limit is set, the functions
+ <c>format/3</c> and <c>fwrite/3</c> try to distribute the
+ number of characters evenly over the control sequences
+ <c>pPswW</c>. Furthermore, the control sequences
+ <c>pPwP</c> try to distribute the number of characters
+ evenly over substructures. </p> <p> A modification of the
+ control sequences <c>pPwW</c> is that even if there is no
+ limit on the number of returned characters, all
+ associations of a map are printed to the same depth. The
+ aim is to give a more consistent output as the order of
+ map keys is not defined. As before, if the depth is less
+ than the number of associations of a map, the selection
+ of associations to print is arbitrary. </p>
+ <p>
+ Own Id: OTP-14983</p>
+ </item>
+ <item>
+ <p> Add functions <c>ordsets:is_empty/1</c> and
+ <c>sets:is_empty/1</c>. </p>
+ <p>
+ Own Id: OTP-14996 Aux Id: ERL-557, PR-1703 </p>
+ </item>
+ <item>
+ <p>
+ Improve performance of <c>string:uppercase/1</c>,
+ <c>string:lowercase/1</c> and <c>string:casefold/1</c>
+ when handling ASCII characters.</p>
+ <p>
+ Own Id: OTP-14998</p>
+ </item>
+ <item>
+ <p>External funs with literal values for module, name,
+ and arity (e.g. <c>erlang:abs/1</c>) are now treated as
+ literals. That means more efficient code that produces
+ less garbage on the heap.</p>
+ <p>
+ Own Id: OTP-15003</p>
+ </item>
+ <item>
+ <p>
+ sys:statistics(Pid,get) did not report 'out' messages
+ from gen_server. This is now corrected.</p>
+ <p>
+ Own Id: OTP-15047</p>
+ </item>
+ <item>
+ <p>
+ A sys debug function can now have the format
+ {Id,Fun,State} in addition to the old {Fun,State}. This
+ allows installing multiple instances of a debug fun.</p>
+ <p>
+ Own Id: OTP-15048</p>
+ </item>
+ <item>
+ <p> The <c>lib</c> module is removed:</p> <list
+ type="bulleted"> <item><c>lib:error_message/2</c> is
+ removed.</item> <item><c>lib:flush_receive/0</c> is
+ removed.</item> <item><c>lib:nonl/1</c> is
+ removed.</item> <item><c>lib:progname/0</c> is replaced
+ by <c>ct:get_progname/0</c>.</item>
+ <item><c>lib:send/2</c> is removed.</item>
+ <item><c>lib:sendw/2</c> is removed.</item> </list>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15072 Aux Id: PR 1786, OTP-15114 </p>
+ </item>
+ <item>
+ <p>
+ Function <c>ets:delete_all_objects/1</c> now yields the
+ scheduler thread for large tables that take significant
+ time to clear. This to improve real time characteristics
+ of other runnable processes.</p>
+ <p>
+ Own Id: OTP-15078</p>
+ </item>
+ <item>
+ <p> In control sequences of the functions
+ <c>io:fwrite/2,3</c> and <c>io_lib:fwrite/2,3</c>
+ containing <c>p</c> or <c>P</c>, a field width of value
+ <c>0</c> means that no line breaks are inserted. This is
+ in contrast to the old behaviour, where <c>0</c> used to
+ insert line breaks after every subterm. To insert line
+ breaks after every subterm, a field width of value
+ <c>1</c> can be used. </p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15103 Aux Id: ERL-607 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>STDLIB 3.4.5.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>List subtraction (The <c>--</c> operator) will now
+ yield properly on large inputs.</p>
+ <p>
+ Own Id: OTP-15371</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>STDLIB 3.4.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The <c>Module:init/1</c> function in <c>gen_statem</c>
+ may return an actions list containing any action, but an
+ erroneous check only allowed state enter actions so e.g
+ <c>{next_event,internal,event}</c> caused a server crash.
+ This bug has been fixed.</p>
+ <p>
+ Own Id: OTP-13995</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>STDLIB 3.4.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -1166,6 +2092,21 @@
</section>
+<section><title>STDLIB 2.8.0.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>List subtraction (The <c>--</c> operator) will now
+ yield properly on large inputs.</p>
+ <p>
+ Own Id: OTP-15371</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>STDLIB 2.8</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -3202,7 +4143,7 @@
you use erlang:halt/2 with an integer first argument and
an option list containing {flush,false} as the second
argument. Note that now is flushing not dependant of the
- exit code, and you can not only flush async threads
+ exit code, and you cannot only flush async threads
operations which we deemed as a strange behaviour anyway.
</p>
<p>Also, erlang:halt/1,2 has gotten a new feature: If the
@@ -3716,9 +4657,9 @@
Supervisors should not save child-specs for temporary
processes when they terminate as they should not be
restarted. Saving the temporary child spec will result in
- that you can not start a new temporary process with the
+ that you cannot start a new temporary process with the
same child spec as an already terminated temporary
- process. Since R14B02 you can not restart a temporary
+ process. Since R14B02 you cannot restart a temporary
temporary process as arguments are no longer saved, it
has however always been semantically incorrect to restart
a temporary process. Thanks to Filipe David Manana for
@@ -7335,4 +8276,3 @@
</section>
</section>
</chapter>
-
diff --git a/lib/stdlib/doc/src/orddict.xml b/lib/stdlib/doc/src/orddict.xml
index 26bbf499c6..27ccccee7e 100644
--- a/lib/stdlib/doc/src/orddict.xml
+++ b/lib/stdlib/doc/src/orddict.xml
@@ -32,7 +32,7 @@
<rev>B</rev>
<file>orddict.xml</file>
</header>
- <module>orddict</module>
+ <module since="">orddict</module>
<modulesummary>Key-value dictionary as ordered list.</modulesummary>
<description>
<p>This module provides a <c>Key</c>-<c>Value</c> dictionary.
@@ -61,7 +61,7 @@
<funcs>
<func>
- <name name="append" arity="3"/>
+ <name name="append" arity="3" since=""/>
<fsummary>Append a value to keys in a dictionary.</fsummary>
<desc>
<p>Appends a new <c><anno>Value</anno></c> to the current list
@@ -73,7 +73,7 @@
</func>
<func>
- <name name="append_list" arity="3"/>
+ <name name="append_list" arity="3" since=""/>
<fsummary>Append new values to keys in a dictionary.</fsummary>
<desc>
<p>Appends a list of values <c><anno>ValList</anno></c> to
@@ -85,7 +85,7 @@
</func>
<func>
- <name name="erase" arity="2"/>
+ <name name="erase" arity="2" since=""/>
<fsummary>Erase a key from a dictionary.</fsummary>
<desc>
<p>Erases all items with a specified key from a dictionary.</p>
@@ -93,7 +93,7 @@
</func>
<func>
- <name name="fetch" arity="2"/>
+ <name name="fetch" arity="2" since=""/>
<fsummary>Look up values in a dictionary.</fsummary>
<desc>
<p>Returns the value associated with <c><anno>Key</anno></c>
@@ -105,7 +105,7 @@
</func>
<func>
- <name name="fetch_keys" arity="1"/>
+ <name name="fetch_keys" arity="1" since=""/>
<fsummary>Return all keys in a dictionary.</fsummary>
<desc>
<p>Returns a list of all keys in a dictionary.</p>
@@ -113,7 +113,7 @@
</func>
<func>
- <name name="take" arity="2"/>
+ <name name="take" arity="2" since="OTP 20.0"/>
<fsummary>Return value and new dictionary without element with this value.</fsummary>
<desc>
<p>This function returns value from dictionary and new dictionary without this value.
@@ -122,7 +122,7 @@
</func>
<func>
- <name name="filter" arity="2"/>
+ <name name="filter" arity="2" since=""/>
<fsummary>Select elements that satisfy a predicate.</fsummary>
<desc>
<p><c><anno>Orddict2</anno></c> is a dictionary of all keys and values
@@ -133,7 +133,7 @@
</func>
<func>
- <name name="find" arity="2"/>
+ <name name="find" arity="2" since=""/>
<fsummary>Search for a key in a dictionary.</fsummary>
<desc>
<p>Searches for a key in a dictionary. Returns
@@ -145,7 +145,7 @@
</func>
<func>
- <name name="fold" arity="3"/>
+ <name name="fold" arity="3" since=""/>
<fsummary>Fold a function over a dictionary.</fsummary>
<desc>
<p>Calls <c><anno>Fun</anno></c> on successive keys and values of
@@ -157,7 +157,7 @@
</func>
<func>
- <name name="from_list" arity="1"/>
+ <name name="from_list" arity="1" since=""/>
<fsummary>Convert a list of pairs to a dictionary.</fsummary>
<desc>
<p>Converts the <c><anno>Key</anno></c>-<c><anno>Value</anno></c> list
@@ -166,7 +166,7 @@
</func>
<func>
- <name name="is_empty" arity="1"/>
+ <name name="is_empty" arity="1" since="OTP 17.0"/>
<fsummary>Return true if the dictionary is empty.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Orddict</anno></c> has no elements,
@@ -175,7 +175,7 @@
</func>
<func>
- <name name="is_key" arity="2"/>
+ <name name="is_key" arity="2" since=""/>
<fsummary>Test if a key is in a dictionary.</fsummary>
<desc>
<p>Tests if <c><anno>Key</anno></c> is contained in
@@ -184,7 +184,7 @@
</func>
<func>
- <name name="map" arity="2"/>
+ <name name="map" arity="2" since=""/>
<fsummary>Map a function over a dictionary.</fsummary>
<desc>
<p>Calls <c><anno>Fun</anno></c> on successive keys and values of
@@ -193,7 +193,7 @@
</func>
<func>
- <name name="merge" arity="3"/>
+ <name name="merge" arity="3" since=""/>
<fsummary>Merge two dictionaries.</fsummary>
<desc>
<p>Merges two dictionaries, <c><anno>Orddict1</anno></c> and
@@ -212,7 +212,7 @@ merge(Fun, D1, D2) ->
</func>
<func>
- <name name="new" arity="0"/>
+ <name name="new" arity="0" since=""/>
<fsummary>Create a dictionary.</fsummary>
<desc>
<p>Creates a new dictionary.</p>
@@ -220,7 +220,7 @@ merge(Fun, D1, D2) ->
</func>
<func>
- <name name="size" arity="1"/>
+ <name name="size" arity="1" since=""/>
<fsummary>Return the number of elements in an ordered dictionary.
</fsummary>
<desc>
@@ -229,7 +229,7 @@ merge(Fun, D1, D2) ->
</func>
<func>
- <name name="store" arity="3"/>
+ <name name="store" arity="3" since=""/>
<fsummary>Store a value in a dictionary.</fsummary>
<desc>
<p>Stores a <c><anno>Key</anno></c>-<c><anno>Value</anno></c> pair in a
@@ -240,7 +240,7 @@ merge(Fun, D1, D2) ->
</func>
<func>
- <name name="to_list" arity="1"/>
+ <name name="to_list" arity="1" since=""/>
<fsummary>Convert a dictionary to a list of pairs.</fsummary>
<desc>
<p>Converts a dictionary to a list representation.</p>
@@ -248,7 +248,7 @@ merge(Fun, D1, D2) ->
</func>
<func>
- <name name="update" arity="3"/>
+ <name name="update" arity="3" since=""/>
<fsummary>Update a value in a dictionary.</fsummary>
<desc>
<p>Updates a value in a dictionary by calling <c><anno>Fun</anno></c>
@@ -258,7 +258,7 @@ merge(Fun, D1, D2) ->
</func>
<func>
- <name name="update" arity="4"/>
+ <name name="update" arity="4" since=""/>
<fsummary>Update a value in a dictionary.</fsummary>
<desc>
<p>Updates a value in a dictionary by calling <c><anno>Fun</anno></c>
@@ -273,7 +273,7 @@ append(Key, Val, D) ->
</func>
<func>
- <name name="update_counter" arity="3"/>
+ <name name="update_counter" arity="3" since=""/>
<fsummary>Increment a value in a dictionary.</fsummary>
<desc>
<p>Adds <c><anno>Increment</anno></c> to the value associated with
diff --git a/lib/stdlib/doc/src/ordsets.xml b/lib/stdlib/doc/src/ordsets.xml
index 7b590932e4..fbe334c009 100644
--- a/lib/stdlib/doc/src/ordsets.xml
+++ b/lib/stdlib/doc/src/ordsets.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>ordsets.xml</file>
</header>
- <module>ordsets</module>
+ <module since="">ordsets</module>
<modulesummary>Functions for manipulating sets as ordered lists.
</modulesummary>
<description>
@@ -60,7 +60,7 @@
<funcs>
<func>
- <name name="add_element" arity="2"/>
+ <name name="add_element" arity="2" since=""/>
<fsummary>Add an element to an <c>Ordset</c>.</fsummary>
<desc>
<p>Returns a new ordered set formed from <c><anno>Ordset1</anno></c>
@@ -69,7 +69,7 @@
</func>
<func>
- <name name="del_element" arity="2"/>
+ <name name="del_element" arity="2" since=""/>
<fsummary>Remove an element from an <c>Ordset</c>.</fsummary>
<desc>
<p>Returns <c><anno>Ordset1</anno></c>, but with
@@ -78,7 +78,7 @@
</func>
<func>
- <name name="filter" arity="2"/>
+ <name name="filter" arity="2" since=""/>
<fsummary>Filter set elements.</fsummary>
<desc>
<p>Filters elements in <c><anno>Ordset1</anno></c> with boolean function
@@ -87,7 +87,7 @@
</func>
<func>
- <name name="fold" arity="3"/>
+ <name name="fold" arity="3" since=""/>
<fsummary>Fold over set elements.</fsummary>
<desc>
<p>Folds <c><anno>Function</anno></c> over every element in
@@ -97,7 +97,7 @@
</func>
<func>
- <name name="from_list" arity="1"/>
+ <name name="from_list" arity="1" since=""/>
<fsummary>Convert a list into an <c>Ordset</c>.</fsummary>
<desc>
<p>Returns an ordered set of the elements in <c><anno>List</anno></c>.
@@ -106,7 +106,7 @@
</func>
<func>
- <name name="intersection" arity="1"/>
+ <name name="intersection" arity="1" since=""/>
<fsummary>Return the intersection of a list of <c>Ordsets</c></fsummary>
<desc>
<p>Returns the intersection of the non-empty list of sets.</p>
@@ -114,7 +114,7 @@
</func>
<func>
- <name name="intersection" arity="2"/>
+ <name name="intersection" arity="2" since=""/>
<fsummary>Return the intersection of two <c>Ordsets</c>.</fsummary>
<desc>
<p>Returns the intersection of <c><anno>Ordset1</anno></c> and
@@ -123,7 +123,7 @@
</func>
<func>
- <name name="is_disjoint" arity="2"/>
+ <name name="is_disjoint" arity="2" since=""/>
<fsummary>Check whether two <c>Ordsets</c> are disjoint.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Ordset1</anno></c> and
@@ -133,7 +133,7 @@
</func>
<func>
- <name name="is_element" arity="2"/>
+ <name name="is_element" arity="2" since=""/>
<fsummary>Test for membership of an <c>Ordset</c>.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Element</anno></c> is an element of
@@ -142,7 +142,16 @@
</func>
<func>
- <name name="is_set" arity="1"/>
+ <name name="is_empty" arity="1" since="OTP 21.0"/>
+ <fsummary>Test for empty set.</fsummary>
+ <desc>
+ <p>Returns <c>true</c> if <c><anno>Ordset</anno></c> is an empty set,
+ otherwise <c>false</c>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="is_set" arity="1" since=""/>
<fsummary>Test for an <c>Ordset</c>.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Ordset</anno></c> is an ordered set
@@ -151,7 +160,7 @@
</func>
<func>
- <name name="is_subset" arity="2"/>
+ <name name="is_subset" arity="2" since=""/>
<fsummary>Test for subset.</fsummary>
<desc>
<p>Returns <c>true</c> when every element of <c><anno>Ordset1</anno></c>
@@ -161,7 +170,7 @@
</func>
<func>
- <name name="new" arity="0"/>
+ <name name="new" arity="0" since=""/>
<fsummary>Return an empty set.</fsummary>
<desc>
<p>Returns a new empty ordered set.</p>
@@ -169,7 +178,7 @@
</func>
<func>
- <name name="size" arity="1"/>
+ <name name="size" arity="1" since=""/>
<fsummary>Return the number of elements in a set.</fsummary>
<desc>
<p>Returns the number of elements in <c><anno>Ordset</anno></c>.</p>
@@ -177,7 +186,7 @@
</func>
<func>
- <name name="subtract" arity="2"/>
+ <name name="subtract" arity="2" since=""/>
<fsummary>Return the difference of two <c>Ordsets</c>.</fsummary>
<desc>
<p>Returns only the elements of <c><anno>Ordset1</anno></c> that are not
@@ -186,7 +195,7 @@
</func>
<func>
- <name name="to_list" arity="1"/>
+ <name name="to_list" arity="1" since=""/>
<fsummary>Convert an <c>Ordset</c> into a list.</fsummary>
<desc>
<p>Returns the elements of <c><anno>Ordset</anno></c> as a list.</p>
@@ -194,7 +203,7 @@
</func>
<func>
- <name name="union" arity="1"/>
+ <name name="union" arity="1" since=""/>
<fsummary>Return the union of a list of <c>Ordsets</c>.</fsummary>
<desc>
<p>Returns the merged (union) set of the list of sets.</p>
@@ -202,7 +211,7 @@
</func>
<func>
- <name name="union" arity="2"/>
+ <name name="union" arity="2" since=""/>
<fsummary>Return the union of two <c>Ordsets</c>.</fsummary>
<desc>
<p>Returns the merged (union) set of <c><anno>Ordset1</anno></c> and
diff --git a/lib/stdlib/doc/src/pool.xml b/lib/stdlib/doc/src/pool.xml
index 05d12ade28..675ee08bfb 100644
--- a/lib/stdlib/doc/src/pool.xml
+++ b/lib/stdlib/doc/src/pool.xml
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>pool</module>
+ <module since="">pool</module>
<modulesummary>Load distribution facility.</modulesummary>
<description>
<p>This module can be used to run a set of Erlang nodes as a pool
@@ -54,7 +54,7 @@
<funcs>
<func>
- <name name="attach" arity="1"/>
+ <name name="attach" arity="1" since=""/>
<fsummary>Ensure that a pool master is running.</fsummary>
<desc>
<p>Ensures that a pool master is running and includes
@@ -63,7 +63,7 @@
</func>
<func>
- <name name="get_node" arity="0"/>
+ <name name="get_node" arity="0" since=""/>
<fsummary>Return the node with the expected lowest future load.</fsummary>
<desc>
<p>Returns the node with the expected lowest future load.</p>
@@ -71,7 +71,7 @@
</func>
<func>
- <name name="get_nodes" arity="0"/>
+ <name name="get_nodes" arity="0" since=""/>
<fsummary>Return a list of the current member nodes of the pool.
</fsummary>
<desc>
@@ -80,7 +80,7 @@
</func>
<func>
- <name name="pspawn" arity="3"/>
+ <name name="pspawn" arity="3" since=""/>
<fsummary>Spawn a process on the pool node with expected lowest future
load.</fsummary>
<desc>
@@ -90,7 +90,7 @@
</func>
<func>
- <name name="pspawn_link" arity="3"/>
+ <name name="pspawn_link" arity="3" since=""/>
<fsummary>Spawn and link to a process on the pool node with expected
lowest future load.</fsummary>
<desc>
@@ -100,8 +100,8 @@
</func>
<func>
- <name name="start" arity="1"/>
- <name name="start" arity="2"/>
+ <name name="start" arity="1" since=""/>
+ <name name="start" arity="2" since=""/>
<fsummary>>Start a new pool.</fsummary>
<desc>
<p>Starts a new pool. The file <c>.hosts.erlang</c> is read to
@@ -122,7 +122,7 @@
</func>
<func>
- <name name="stop" arity="0"/>
+ <name name="stop" arity="0" since=""/>
<fsummary>Stop the pool and kill all the slave nodes.</fsummary>
<desc>
<p>Stops the pool and kills all the slave nodes.</p>
diff --git a/lib/stdlib/doc/src/proc_lib.xml b/lib/stdlib/doc/src/proc_lib.xml
index cb152d1935..bb983903a9 100644
--- a/lib/stdlib/doc/src/proc_lib.xml
+++ b/lib/stdlib/doc/src/proc_lib.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>proc_lib</module>
+ <module since="">proc_lib</module>
<modulesummary>Functions for asynchronous and synchronous start of processes
adhering to the OTP design principles.</modulesummary>
<description>
@@ -59,18 +59,17 @@
<p>When a process that is started using <c>proc_lib</c> terminates
abnormally (that is, with another exit reason than <c>normal</c>,
<c>shutdown</c>, or <c>{shutdown,Term}</c>), a <em>crash report</em>
- is generated, which is written to terminal by the default SASL
- event handler. That is, the crash report is normally only visible
- if the SASL application is started; see
- <seealso marker="sasl:sasl_app"><c>sasl(6)</c></seealso> and section
+ is generated, which is written to terminal by the default logger
+ handler setup by Kernel. For more information about how crash reports
+ were logged prior to Erlang/OTP 21.0, see
<seealso marker="sasl:error_logging">SASL Error Logging</seealso>
in the SASL User's Guide.</p>
<p>Unlike in "plain Erlang", <c>proc_lib</c> processes will not generate
<em>error reports</em>, which are written to the terminal by the
- emulator and do not require SASL to be started. All exceptions are
+ emulator. All exceptions are
converted to <em>exits</em> which are ignored by the default
- <c>error_logger</c> handler.</p>
+ <c>logger</c> handler.</p>
<p>The crash report contains the previously stored information, such
as ancestors and initial function, the termination reason, and
@@ -103,7 +102,7 @@
<funcs>
<func>
- <name name="format" arity="1"/>
+ <name name="format" arity="1" since=""/>
<fsummary>Format a crash report.</fsummary>
<desc>
<p>Equivalent to <seealso marker="#format/2">
@@ -112,15 +111,25 @@
</func>
<func>
- <name name="format" arity="2"/>
+ <name name="format" arity="2" since="OTP R16B"/>
<fsummary>Format a crash report.</fsummary>
<desc>
- <p>This function can be used by a user-defined event handler to
+ <note>
+ <p>This function is deprecated in the sense that
+ the <c>error_logger</c> is no longer the preferred
+ interface for logging in Erlang/OTP. A
+ new <seealso marker="kernel:logger_chapter">logging
+ API</seealso> was added in Erlang/OTP 21.0, but
+ legacy <c>error_logger</c> handlers can still be used. New
+ Logger handlers do not need to use this function, since
+ the formatting callback (<c>report_cb</c>) is included as
+ metadata in the log event.</p>
+ </note>
+ <p>This function can be used by a user-defined legacy
+ <c>error_logger</c> event handler to
format a crash report. The crash report is sent using
- <seealso marker="kernel:error_logger#error_report/2">
- <c>error_logger:error_report(crash_report,
- <anno>CrashReport</anno>)</c></seealso>.
- That is, the event to be handled is of the format
+ <seealso marker="kernel:logger">
+ <c>logger(3)</c></seealso>, and the event to be handled is of the format
<c>{error_report, GL, {Pid, crash_report,
<anno>CrashReport</anno>}}</c>,
where <c>GL</c> is the group leader pid of process
@@ -129,10 +138,22 @@
</func>
<func>
- <name name="format" arity="3"/>
+ <name name="format" arity="3" since="OTP 18.1"/>
<fsummary>Format a crash report.</fsummary>
<desc>
- <p>This function can be used by a user-defined event handler to
+ <note>
+ <p>This function is deprecated in the sense that
+ the <c>error_logger</c> is no longer the preferred
+ interface for logging in Erlang/OTP. A
+ new <seealso marker="kernel:logger_chapter">logging
+ API</seealso> was added in Erlang/OTP 21.0, but
+ legacy <c>error_logger</c> handlers can still be used. New
+ Logger handlers do not need to used this function, since
+ the formatting callback (<c>report_cb</c>) is included as
+ metadata in the log event.</p>
+ </note>
+ <p>This function can be used by a user-defined legacy
+ <c>error_logger</c> event handler to
format a crash report. When <anno>Depth</anno> is specified as a
positive integer, it is used in the format string to
limit the output as follows: <c>io_lib:format("~P",
@@ -141,11 +162,11 @@
</func>
<func>
- <name name="hibernate" arity="3"/>
+ <name name="hibernate" arity="3" since=""/>
<fsummary>Hibernate a process until a message is sent to it.</fsummary>
<desc>
<p>This function does the same as (and does call) the
- <seealso marker="erts:erlang#erlang:hibernate/3">
+ <seealso marker="erts:erlang#hibernate/3">
<c>hibernate/3</c></seealso> BIF,
but ensures that exception handling and logging continues to
work as expected when the process wakes up.</p>
@@ -155,8 +176,8 @@
</func>
<func>
- <name name="init_ack" arity="1"/>
- <name name="init_ack" arity="2"/>
+ <name name="init_ack" arity="1" since=""/>
+ <name name="init_ack" arity="2" since=""/>
<fsummary>Used by a process when it has started.</fsummary>
<desc>
<p>This function must be used by a process that has been started by
@@ -193,7 +214,7 @@ init(Parent) ->
</func>
<func>
- <name name="initial_call" arity="1"/>
+ <name name="initial_call" arity="1" since=""/>
<fsummary>Extract the initial call of a <c>proc_lib</c>spawned process.
</fsummary>
<desc>
@@ -223,10 +244,10 @@ init(Parent) ->
</func>
<func>
- <name name="spawn" arity="1"/>
- <name name="spawn" arity="2"/>
- <name name="spawn" arity="3"/>
- <name name="spawn" arity="4"/>
+ <name name="spawn" arity="1" since=""/>
+ <name name="spawn" arity="2" since=""/>
+ <name name="spawn" arity="3" since=""/>
+ <name name="spawn" arity="4" since=""/>
<fsummary>Spawn a new process.</fsummary>
<type variable="Node"/>
<type variable="Fun" name_i="1"/>
@@ -241,10 +262,10 @@ init(Parent) ->
</func>
<func>
- <name name="spawn_link" arity="1"/>
- <name name="spawn_link" arity="2"/>
- <name name="spawn_link" arity="3"/>
- <name name="spawn_link" arity="4"/>
+ <name name="spawn_link" arity="1" since=""/>
+ <name name="spawn_link" arity="2" since=""/>
+ <name name="spawn_link" arity="3" since=""/>
+ <name name="spawn_link" arity="4" since=""/>
<fsummary>Spawn and link to a new process.</fsummary>
<type variable="Node"/>
<type variable="Fun" name_i="1"/>
@@ -260,10 +281,10 @@ init(Parent) ->
</func>
<func>
- <name name="spawn_opt" arity="2"/>
- <name name="spawn_opt" arity="3"/>
- <name name="spawn_opt" arity="4"/>
- <name name="spawn_opt" arity="5"/>
+ <name name="spawn_opt" arity="2" since=""/>
+ <name name="spawn_opt" arity="3" since=""/>
+ <name name="spawn_opt" arity="4" since=""/>
+ <name name="spawn_opt" arity="5" since=""/>
<fsummary>Spawn a new process with specified options.</fsummary>
<type variable="Node"/>
<type variable="Fun" name_i="1"/>
@@ -285,12 +306,12 @@ init(Parent) ->
</func>
<func>
- <name name="start" arity="3"/>
- <name name="start" arity="4"/>
- <name name="start" arity="5"/>
- <name name="start_link" arity="3"/>
- <name name="start_link" arity="4"/>
- <name name="start_link" arity="5"/>
+ <name name="start" arity="3" since=""/>
+ <name name="start" arity="4" since=""/>
+ <name name="start" arity="5" since=""/>
+ <name name="start_link" arity="3" since=""/>
+ <name name="start_link" arity="4" since=""/>
+ <name name="start_link" arity="5" since=""/>
<fsummary>Start a new process synchronously.</fsummary>
<desc>
<p>Starts a new process synchronously. Spawns the process and
@@ -320,7 +341,7 @@ init(Parent) ->
</func>
<func>
- <name name="stop" arity="1"/>
+ <name name="stop" arity="1" since="OTP 18.0"/>
<fsummary>Terminate a process synchronously.</fsummary>
<type variable="Process"/>
<desc>
@@ -330,7 +351,7 @@ init(Parent) ->
</func>
<func>
- <name name="stop" arity="3"/>
+ <name name="stop" arity="3" since="OTP 18.0"/>
<fsummary>Terminate a process synchronously.</fsummary>
<type variable="Process"/>
<type variable="Reason"/>
@@ -354,7 +375,7 @@ init(Parent) ->
</func>
<func>
- <name name="translate_initial_call" arity="1"/>
+ <name name="translate_initial_call" arity="1" since=""/>
<fsummary>Extract and translate the initial call of a
<c>proc_lib</c>spawned process.</fsummary>
<desc>
@@ -395,6 +416,8 @@ init(Parent) ->
<title>See Also</title>
<p><seealso marker="kernel:error_logger">
<c>error_logger(3)</c></seealso></p>
+ <p><seealso marker="kernel:logger">
+ <c>logger(3)</c></seealso></p>
</section>
</erlref>
diff --git a/lib/stdlib/doc/src/proplists.xml b/lib/stdlib/doc/src/proplists.xml
index f9a54bf804..4465103469 100644
--- a/lib/stdlib/doc/src/proplists.xml
+++ b/lib/stdlib/doc/src/proplists.xml
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>proplists.xml</file>
</header>
- <module>proplists</module>
+ <module since="">proplists</module>
<modulesummary>Support functions for property lists.</modulesummary>
<description>
<p>Property lists are ordinary lists containing entries in the form
@@ -57,11 +57,16 @@
<datatype>
<name name="property"/>
</datatype>
+
+ <datatype>
+ <name name="proplist"/>
+ </datatype>
+
</datatypes>
<funcs>
<func>
- <name name="append_values" arity="2"/>
+ <name name="append_values" arity="2" since=""/>
<fsummary></fsummary>
<desc>
<p>Similar to
@@ -79,7 +84,7 @@ append_values(a, [{a, [1,2]}, {b, 0}, {a, 3}, {c, -1}, {a, [4]}])</code>
</func>
<func>
- <name name="compact" arity="1"/>
+ <name name="compact" arity="1" since=""/>
<fsummary></fsummary>
<desc>
<p>Minimizes the representation of all entries in the list. This is
@@ -91,7 +96,7 @@ append_values(a, [{a, [1,2]}, {b, 0}, {a, 3}, {c, -1}, {a, [4]}])</code>
</func>
<func>
- <name name="delete" arity="2"/>
+ <name name="delete" arity="2" since=""/>
<fsummary></fsummary>
<desc>
<p>Deletes all entries associated with <c><anno>Key</anno></c> from
@@ -100,7 +105,7 @@ append_values(a, [{a, [1,2]}, {b, 0}, {a, 3}, {c, -1}, {a, [4]}])</code>
</func>
<func>
- <name name="expand" arity="2"/>
+ <name name="expand" arity="2" since=""/>
<fsummary></fsummary>
<desc>
<p>Expands particular properties to corresponding sets of
@@ -133,7 +138,7 @@ expand([{{foo, true}, [bar, baz]}], [{foo, false}, fie, foo, fum])</code>
</func>
<func>
- <name name="get_all_values" arity="2"/>
+ <name name="get_all_values" arity="2" since=""/>
<fsummary></fsummary>
<desc>
<p>Similar to
@@ -145,7 +150,7 @@ expand([{{foo, true}, [bar, baz]}], [{foo, false}, fie, foo, fum])</code>
</func>
<func>
- <name name="get_bool" arity="2"/>
+ <name name="get_bool" arity="2" since=""/>
<fsummary></fsummary>
<desc>
<p>Returns the value of a boolean key/value option. If
@@ -159,7 +164,7 @@ expand([{{foo, true}, [bar, baz]}], [{foo, false}, fie, foo, fum])</code>
</func>
<func>
- <name name="get_keys" arity="1"/>
+ <name name="get_keys" arity="1" since=""/>
<fsummary></fsummary>
<desc>
<p>Returns an unordered list of the keys used in
@@ -168,7 +173,7 @@ expand([{{foo, true}, [bar, baz]}], [{foo, false}, fie, foo, fum])</code>
</func>
<func>
- <name name="get_value" arity="2"/>
+ <name name="get_value" arity="2" since=""/>
<fsummary></fsummary>
<desc>
<p>Equivalent to
@@ -177,7 +182,7 @@ expand([{{foo, true}, [bar, baz]}], [{foo, false}, fie, foo, fum])</code>
</func>
<func>
- <name name="get_value" arity="3"/>
+ <name name="get_value" arity="3" since=""/>
<fsummary></fsummary>
<desc>
<p>Returns the value of a simple key/value property in
@@ -194,7 +199,7 @@ expand([{{foo, true}, [bar, baz]}], [{foo, false}, fie, foo, fum])</code>
</func>
<func>
- <name name="is_defined" arity="2"/>
+ <name name="is_defined" arity="2" since=""/>
<fsummary></fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>List</anno></c> contains at least
@@ -204,7 +209,7 @@ expand([{{foo, true}, [bar, baz]}], [{foo, false}, fie, foo, fum])</code>
</func>
<func>
- <name name="lookup" arity="2"/>
+ <name name="lookup" arity="2" since=""/>
<fsummary></fsummary>
<desc>
<p>Returns the first entry associated with <c><anno>Key</anno></c> in
@@ -219,7 +224,7 @@ expand([{{foo, true}, [bar, baz]}], [{foo, false}, fie, foo, fum])</code>
</func>
<func>
- <name name="lookup_all" arity="2"/>
+ <name name="lookup_all" arity="2" since=""/>
<fsummary></fsummary>
<desc>
<p>Returns the list of all entries associated with
@@ -231,7 +236,7 @@ expand([{{foo, true}, [bar, baz]}], [{foo, false}, fie, foo, fum])</code>
</func>
<func>
- <name name="normalize" arity="2"/>
+ <name name="normalize" arity="2" since=""/>
<fsummary></fsummary>
<desc>
<p>Passes <c><anno>ListIn</anno></c> through a sequence of
@@ -263,7 +268,7 @@ expand([{{foo, true}, [bar, baz]}], [{foo, false}, fie, foo, fum])</code>
</func>
<func>
- <name name="property" arity="1"/>
+ <name name="property" arity="1" since=""/>
<fsummary></fsummary>
<desc>
<p>Creates a normal form (minimal) representation of a property. If
@@ -276,7 +281,7 @@ expand([{{foo, true}, [bar, baz]}], [{foo, false}, fie, foo, fum])</code>
</func>
<func>
- <name name="property" arity="2"/>
+ <name name="property" arity="2" since=""/>
<fsummary></fsummary>
<desc>
<p>Creates a normal form (minimal) representation of a simple key/value
@@ -289,7 +294,7 @@ expand([{{foo, true}, [bar, baz]}], [{foo, false}, fie, foo, fum])</code>
</func>
<func>
- <name name="split" arity="2"/>
+ <name name="split" arity="2" since=""/>
<fsummary></fsummary>
<desc>
<p>Partitions <c><anno>List</anno></c> into a list of sublists and a
@@ -310,7 +315,7 @@ split([{c, 2}, {e, 1}, a, {c, 3, 4}, d, {b, 5}, b], [a, b, c])</code>
</func>
<func>
- <name name="substitute_aliases" arity="2"/>
+ <name name="substitute_aliases" arity="2" since=""/>
<fsummary></fsummary>
<desc>
<p>Substitutes keys of properties. For each entry in
@@ -332,7 +337,7 @@ split([{c, 2}, {e, 1}, a, {c, 3, 4}, d, {b, 5}, b], [a, b, c])</code>
</func>
<func>
- <name name="substitute_negations" arity="2"/>
+ <name name="substitute_negations" arity="2" since=""/>
<fsummary></fsummary>
<desc>
<p>Substitutes keys of boolean-valued properties and
@@ -360,7 +365,7 @@ split([{c, 2}, {e, 1}, a, {c, 3, 4}, d, {b, 5}, b], [a, b, c])</code>
</func>
<func>
- <name name="unfold" arity="1"/>
+ <name name="unfold" arity="1" since=""/>
<fsummary></fsummary>
<desc>
<p>Unfolds all occurrences of atoms in <c><anno>ListIn</anno></c> to
diff --git a/lib/stdlib/doc/src/qlc.xml b/lib/stdlib/doc/src/qlc.xml
index fe14a6334c..34f7c5bab9 100644
--- a/lib/stdlib/doc/src/qlc.xml
+++ b/lib/stdlib/doc/src/qlc.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2004</year><year>2016</year>
+ <year>2004</year><year>2019</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,7 +32,7 @@
<rev>PA1</rev>
<file>qlc.xml</file>
</header>
- <module>qlc</module>
+ <module since="">qlc</module>
<modulesummary>Query interface to Mnesia, ETS, Dets, and so on.
</modulesummary>
<description>
@@ -581,11 +581,13 @@ gb_iter(I0, N, EFun) ->
<input>{K} &lt;- ets:table(E1),</input>
<input>K == 2.71 orelse K == a]),</input>
<input>io:format("~s~n", [qlc:info(Q1)]).</input>
-ets:match_spec_run(lists:flatmap(fun(V) ->
- ets:lookup(20493, V)
- end,
- [a,2.71]),
- ets:match_spec_compile([{{'$1'},[],['$1']}]))</pre>
+ets:match_spec_run(
+ lists:flatmap(fun(V) ->
+ ets:lookup(#Ref&lt;0.3098908599.2283929601.256025>,
+ V)
+ end,
+ [a, 2.71]),
+ ets:match_spec_compile([{{'$1'}, [], ['$1']}]))</pre>
<p>In the example, operator <c>==/2</c> has been handled
exactly as <c>=:=/2</c> would have been handled. However,
@@ -607,9 +609,10 @@ ets:match_spec_run(lists:flatmap(fun(V) ->
<input>end,</input>
<input>Q2 = F2({2,2}),</input>
<input>io:format("~s~n", [qlc:info(Q2)]).</input>
-ets:table(53264,
+ets:table(#Ref&lt;0.3098908599.2283929601.256125>,
[{traverse,
- {select,[{{'$1','$2'},[{'==','$1',{const,{2,2}}}],['$2']}]}}])
+ {select,
+ [{{'$1', '$2'}, [{'==', '$1', {const, {2, 2}}}], ['$2']}]}}])
3> <input>lists:sort(qlc:e(Q2)).</input>
[a,b,c]</pre>
@@ -629,8 +632,9 @@ ets:table(53264,
<input>end,</input>
<input>Q3 = F3({2,2}),</input>
<input>io:format("~s~n", [qlc:info(Q3)]).</input>
-ets:match_spec_run(ets:lookup(86033, {2,2}),
- ets:match_spec_compile([{{'$1','$2'},[],['$2']}]))
+ets:match_spec_run(ets:lookup(#Ref&lt;0.3098908599.2283929601.256211>,
+ {2, 2}),
+ ets:match_spec_compile([{{'$1', '$2'}, [], ['$2']}]))
5> <input>qlc:e(Q3).</input>
[b]</pre>
@@ -720,7 +724,7 @@ ets:match_spec_run(ets:lookup(86033, {2,2}),
<funcs>
<func>
- <name name="append" arity="1"/>
+ <name name="append" arity="1" since=""/>
<fsummary>Return a query handle.</fsummary>
<desc>
<p>Returns a query handle. When evaluating query handle
@@ -731,7 +735,7 @@ ets:match_spec_run(ets:lookup(86033, {2,2}),
</func>
<func>
- <name name="append" arity="2"/>
+ <name name="append" arity="2" since=""/>
<fsummary>Return a query handle.</fsummary>
<desc>
<p>Returns a query handle. When evaluating query handle
@@ -744,8 +748,8 @@ ets:match_spec_run(ets:lookup(86033, {2,2}),
</func>
<func>
- <name name="cursor" arity="1"/>
- <name name="cursor" arity="2"/>
+ <name name="cursor" arity="1" since=""/>
+ <name name="cursor" arity="2" since=""/>
<fsummary>Create a query cursor.</fsummary>
<desc>
<p>Creates a query cursor and
@@ -777,7 +781,7 @@ ok</pre>
</func>
<func>
- <name name="delete_cursor" arity="1"/>
+ <name name="delete_cursor" arity="1" since=""/>
<fsummary>Delete a query cursor.</fsummary>
<desc>
<p>Deletes a query cursor. Only the owner of the cursor can
@@ -786,10 +790,10 @@ ok</pre>
</func>
<func>
- <name name="e" arity="1"/>
- <name name="e" arity="2"/>
- <name name="eval" arity="1"/>
- <name name="eval" arity="2"/>
+ <name name="e" arity="1" since=""/>
+ <name name="e" arity="2" since=""/>
+ <name name="eval" arity="1" since=""/>
+ <name name="eval" arity="2" since=""/>
<fsummary>Return all answers to a query.</fsummary>
<desc>
<p>Evaluates a query handle in the
@@ -805,8 +809,8 @@ ok</pre>
</func>
<func>
- <name name="fold" arity="3"/>
- <name name="fold" arity="4"/>
+ <name name="fold" arity="3" since=""/>
+ <name name="fold" arity="4" since=""/>
<fsummary>Fold a function over the answers to a query.</fsummary>
<desc>
<p>Calls <c><anno>Function</anno></c> on successive answers to
@@ -830,7 +834,7 @@ ok</pre>
</func>
<func>
- <name name="format_error" arity="1"/>
+ <name name="format_error" arity="1" since=""/>
<fsummary>Return an English description of a an error tuple.</fsummary>
<desc>
<p>Returns a descriptive string in English of an error tuple
@@ -841,8 +845,8 @@ ok</pre>
</func>
<func>
- <name name="info" arity="1"/>
- <name name="info" arity="2"/>
+ <name name="info" arity="1" since=""/>
+ <name name="info" arity="2" since=""/>
<fsummary>Return code describing a query handle.</fsummary>
<desc>
<p>Returns information about a
@@ -892,21 +896,21 @@ begin
V1 =
qlc:q([
SQV ||
- SQV &lt;- [x,y]
+ SQV &lt;- [x, y]
],
- [{unique,true}]),
+ [{unique, true}]),
V2 =
qlc:q([
SQV ||
- SQV &lt;- [a,b]
+ SQV &lt;- [a, b]
],
- [{unique,true}]),
+ [{unique, true}]),
qlc:q([
{X,Y} ||
X &lt;- V1,
Y &lt;- V2
],
- [{unique,true}])
+ [{unique, true}])
end</pre>
<p>In the following example QLC <c>V2</c> has
been inserted to show the joined generators and the join
@@ -927,27 +931,29 @@ begin
V1 =
qlc:q([
P0 ||
- P0 = {W,Y} &lt;- ets:table(17)
+ P0 = {W, Y} &lt;-
+ ets:table(#Ref&lt;0.3098908599.2283929601.256549>)
]),
V2 =
qlc:q([
- [G1|G2] ||
+ [G1 | G2] ||
G2 &lt;- V1,
- G1 &lt;- ets:table(16),
+ G1 &lt;-
+ ets:table(#Ref&lt;0.3098908599.2283929601.256548>),
element(2, G1) =:= element(1, G2)
],
- [{join,lookup}]),
+ [{join, lookup}]),
qlc:q([
- {X,Z,W} ||
- [{X,Z}|{W,Y}] &lt;- V2
+ {X, Z, W} ||
+ [{X, Z} | {W, Y}] &lt;- V2
])
end</pre>
</desc>
</func>
<func>
- <name name="keysort" arity="2"/>
- <name name="keysort" arity="3"/>
+ <name name="keysort" arity="2" since=""/>
+ <name name="keysort" arity="3" since=""/>
<fsummary>Return a query handle.</fsummary>
<desc>
<p>Returns a query handle. When evaluating query handle
@@ -967,8 +973,8 @@ end</pre>
</func>
<func>
- <name name="next_answers" arity="1"/>
- <name name="next_answers" arity="2"/>
+ <name name="next_answers" arity="1" since=""/>
+ <name name="next_answers" arity="2" since=""/>
<fsummary>Return some or all answers to a query.</fsummary>
<desc>
<p>Returns some or all of the remaining answers to a query
@@ -983,8 +989,8 @@ end</pre>
</func>
<func>
- <name name="q" arity="1"/>
- <name name="q" arity="2"/>
+ <name name="q" arity="1" since=""/>
+ <name name="q" arity="2" since=""/>
<fsummary>Return a handle for a query list comprehension.</fsummary>
<desc>
<p>Returns a query handle for a QLC.
@@ -1080,27 +1086,27 @@ begin
V1 =
qlc:q([
P0 ||
- P0 = {X,Z} &lt;-
- qlc:keysort(1, [{a,1},{b,4},{c,6}], [])
+ P0 = {X, Z} &lt;-
+ qlc:keysort(1, [{a, 1}, {b, 4}, {c, 6}], [])
]),
V2 =
qlc:q([
P0 ||
- P0 = {W,Y} &lt;-
- qlc:keysort(2, [{2,a},{3,b},{4,c}], [])
+ P0 = {W, Y} &lt;-
+ qlc:keysort(2, [{2, a}, {3, b}, {4, c}], [])
]),
V3 =
qlc:q([
- [G1|G2] ||
+ [G1 | G2] ||
G1 &lt;- V1,
G2 &lt;- V2,
element(1, G1) == element(2, G2)
],
- [{join,merge},{cache,list}]),
+ [{join, merge}, {cache, list}]),
qlc:q([
- {A,X,Z,W} ||
- A &lt;- [a,b,c],
- [{X,Z}|{W,Y}] &lt;- V3,
+ {A, X, Z, W} ||
+ A &lt;- [a, b, c],
+ [{X, Z} | {W, Y}] &lt;- V3,
X =:= Y
])
end</pre>
@@ -1141,14 +1147,21 @@ ets:match_spec_run(
gb_trees:lookup(K,
gb_trees:from_orddict([]))
of
- {value,V} ->
- [{K,V}];
+ {value, V} ->
+ [{K, V}];
none ->
[]
end
end,
- [{1,a},{1,b},{1,c},{2,a},{2,b},{2,c}]),
- ets:match_spec_compile([{{{'$1','$2'},'_'},[],['$1']}]))</pre>
+ [{1, a},
+ {1, b},
+ {1, c},
+ {2, a},
+ {2, b},
+ {2, c}]),
+ ets:match_spec_compile([{{{'$1', '$2'}, '_'},
+ [],
+ ['$1']}]))</pre>
<p>Options:</p>
<list type="bulleted">
<item>
@@ -1188,8 +1201,8 @@ ets:match_spec_run(
</func>
<func>
- <name name="sort" arity="1"/>
- <name name="sort" arity="2"/>
+ <name name="sort" arity="1" since=""/>
+ <name name="sort" arity="2" since=""/>
<fsummary>Return a query handle.</fsummary>
<desc>
<p>Returns a query handle. When evaluating query handle
@@ -1208,9 +1221,9 @@ ets:match_spec_run(
</func>
<func>
- <name name="string_to_handle" arity="1"/>
- <name name="string_to_handle" arity="2"/>
- <name name="string_to_handle" arity="3"/>
+ <name name="string_to_handle" arity="1" since=""/>
+ <name name="string_to_handle" arity="2" since=""/>
+ <name name="string_to_handle" arity="3" since=""/>
<fsummary>Return a handle for a query list comprehension.</fsummary>
<desc>
<p>A string version of <seealso marker="#q/1"><c>q/1,2</c></seealso>.
@@ -1238,7 +1251,7 @@ ets:match_spec_run(
</func>
<func>
- <name name="table" arity="2"/>
+ <name name="table" arity="2" since=""/>
<fsummary>Return a query handle for a table.</fsummary>
<desc>
<p>Returns a query handle for a QLC table.
diff --git a/lib/stdlib/doc/src/queue.xml b/lib/stdlib/doc/src/queue.xml
index 9f3aff03a3..89cce6d85b 100644
--- a/lib/stdlib/doc/src/queue.xml
+++ b/lib/stdlib/doc/src/queue.xml
@@ -32,7 +32,7 @@
<rev>B</rev>
<file>queue.xml</file>
</header>
- <module>queue</module>
+ <module since="">queue</module>
<modulesummary>Abstract data type for FIFO queues.</modulesummary>
<description>
<p>This module provides (double-ended) FIFO queues
@@ -113,7 +113,7 @@
<funcs>
<func>
- <name name="filter" arity="2"/>
+ <name name="filter" arity="2" since=""/>
<fsummary>Filter a queue.</fsummary>
<desc>
<p>Returns a queue <c><anno>Q2</anno></c> that is the result of calling
@@ -134,7 +134,7 @@
</func>
<func>
- <name name="from_list" arity="1"/>
+ <name name="from_list" arity="1" since=""/>
<fsummary>Convert a list to a queue.</fsummary>
<desc>
<p>Returns a queue containing the items in <c><anno>L</anno></c> in the
@@ -144,7 +144,7 @@
</func>
<func>
- <name name="in" arity="2"/>
+ <name name="in" arity="2" since=""/>
<fsummary>Insert an item at the rear of a queue.</fsummary>
<desc>
<p>Inserts <c><anno>Item</anno></c> at the rear of queue
@@ -154,7 +154,7 @@
</func>
<func>
- <name name="in_r" arity="2"/>
+ <name name="in_r" arity="2" since=""/>
<fsummary>Insert an item at the front of a queue.</fsummary>
<desc>
<p>Inserts <c><anno>Item</anno></c> at the front of queue
@@ -164,16 +164,16 @@
</func>
<func>
- <name name="is_empty" arity="1"/>
+ <name name="is_empty" arity="1" since=""/>
<fsummary>Test if a queue is empty.</fsummary>
<desc>
<p>Tests if <c><anno>Q</anno></c> is empty and returns <c>true</c> if
- so, otherwise otherwise.</p>
+ so, otherwise <c>false</c>.</p>
</desc>
</func>
<func>
- <name name="is_queue" arity="1"/>
+ <name name="is_queue" arity="1" since=""/>
<fsummary>Test if a term is a queue.</fsummary>
<desc>
<p>Tests if <c><anno>Term</anno></c> is a queue and returns <c>true</c>
@@ -182,7 +182,7 @@
</func>
<func>
- <name name="join" arity="2"/>
+ <name name="join" arity="2" since=""/>
<fsummary>Join two queues.</fsummary>
<desc>
<p>Returns a queue <c><anno>Q3</anno></c> that is the result of joining
@@ -192,7 +192,7 @@
</func>
<func>
- <name name="len" arity="1"/>
+ <name name="len" arity="1" since=""/>
<fsummary>Get the length of a queue.</fsummary>
<desc>
<p>Calculates and returns the length of queue <c><anno>Q</anno></c>.</p>
@@ -200,7 +200,7 @@
</func>
<func>
- <name name="member" arity="2"/>
+ <name name="member" arity="2" since=""/>
<fsummary>Test if an item is in a queue.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Item</anno></c> matches some element
@@ -209,7 +209,7 @@
</func>
<func>
- <name name="new" arity="0"/>
+ <name name="new" arity="0" since=""/>
<fsummary>Create an empty queue.</fsummary>
<desc>
<p>Returns an empty queue.</p>
@@ -217,7 +217,7 @@
</func>
<func>
- <name name="out" arity="1"/>
+ <name name="out" arity="1" since=""/>
<fsummary>Remove the front item from a queue.</fsummary>
<desc>
<p>Removes the item at the front of queue <c><anno>Q1</anno></c>.
@@ -230,7 +230,7 @@
</func>
<func>
- <name name="out_r" arity="1"/>
+ <name name="out_r" arity="1" since=""/>
<fsummary>Remove the rear item from a queue.</fsummary>
<desc>
<p>Removes the item at the rear of queue <c><anno>Q1</anno></c>.
@@ -242,7 +242,7 @@
</func>
<func>
- <name name="reverse" arity="1"/>
+ <name name="reverse" arity="1" since=""/>
<fsummary>Reverse a queue.</fsummary>
<desc>
<p>Returns a queue <c><anno>Q2</anno></c> containing the items of
@@ -251,7 +251,7 @@
</func>
<func>
- <name name="split" arity="2"/>
+ <name name="split" arity="2" since=""/>
<fsummary>Split a queue in two.</fsummary>
<desc>
<p>Splits <c><anno>Q1</anno></c> in two. The <c><anno>N</anno></c>
@@ -261,7 +261,7 @@
</func>
<func>
- <name name="to_list" arity="1"/>
+ <name name="to_list" arity="1" since=""/>
<fsummary>Convert a queue to a list.</fsummary>
<desc>
<p>Returns a list of the items in the queue in the same order;
@@ -276,7 +276,7 @@
<funcs>
<func>
- <name name="drop" arity="1"/>
+ <name name="drop" arity="1" since=""/>
<fsummary>Remove the front item from a queue.</fsummary>
<desc>
<p>Returns a queue <c><anno>Q2</anno></c> that is the result of removing
@@ -286,7 +286,7 @@
</func>
<func>
- <name name="drop_r" arity="1"/>
+ <name name="drop_r" arity="1" since=""/>
<fsummary>Remove the rear item from a queue.</fsummary>
<desc>
<p>Returns a queue <c><anno>Q2</anno></c> that is the result of removing
@@ -296,7 +296,7 @@
</func>
<func>
- <name name="get" arity="1"/>
+ <name name="get" arity="1" since=""/>
<fsummary>Return the front item of a queue.</fsummary>
<desc>
<p>Returns <c><anno>Item</anno></c> at the front of queue
@@ -306,7 +306,7 @@
</func>
<func>
- <name name="get_r" arity="1"/>
+ <name name="get_r" arity="1" since=""/>
<fsummary>Return the rear item of a queue.</fsummary>
<desc>
<p>Returns <c><anno>Item</anno></c> at the rear of queue
@@ -316,7 +316,7 @@
</func>
<func>
- <name name="peek" arity="1"/>
+ <name name="peek" arity="1" since=""/>
<fsummary>Return the front item of a queue.</fsummary>
<desc>
<p>Returns tuple <c>{value, <anno>Item</anno>}</c>, where
@@ -326,7 +326,7 @@
</func>
<func>
- <name name="peek_r" arity="1"/>
+ <name name="peek_r" arity="1" since=""/>
<fsummary>Return the rear item of a queue.</fsummary>
<desc>
<p>Returns tuple <c>{value, <anno>Item</anno>}</c>, where
@@ -342,7 +342,7 @@
<funcs>
<func>
- <name name="cons" arity="2"/>
+ <name name="cons" arity="2" since=""/>
<fsummary>Insert an item at the head of a queue.</fsummary>
<desc>
<p>Inserts <c><anno>Item</anno></c> at the head of queue
@@ -352,7 +352,7 @@
</func>
<func>
- <name name="daeh" arity="1"/>
+ <name name="daeh" arity="1" since=""/>
<fsummary>Return the tail item of a queue.</fsummary>
<desc>
<p>Returns the tail item of queue <c><anno>Q</anno></c>.</p>
@@ -361,7 +361,7 @@
</func>
<func>
- <name name="head" arity="1"/>
+ <name name="head" arity="1" since=""/>
<fsummary>Return the item at the head of a queue.</fsummary>
<desc>
<p>Returns <c><anno>Item</anno></c> from the head of queue
@@ -371,7 +371,7 @@
</func>
<func>
- <name name="init" arity="1"/>
+ <name name="init" arity="1" since=""/>
<fsummary>Remove the tail item from a queue.</fsummary>
<desc>
<p>Returns a queue <c><anno>Q2</anno></c> that is the result of removing
@@ -381,7 +381,7 @@
</func>
<func>
- <name name="lait" arity="1"/>
+ <name name="lait" arity="1" since=""/>
<fsummary>Remove the tail item from a queue.</fsummary>
<desc>
<p>Returns a queue <c><anno>Q2</anno></c> that is the result of removing
@@ -392,7 +392,7 @@
</func>
<func>
- <name name="last" arity="1"/>
+ <name name="last" arity="1" since=""/>
<fsummary>Return the tail item of a queue.</fsummary>
<desc>
<p>Returns the tail item of queue <c><anno>Q</anno></c>.</p>
@@ -401,7 +401,7 @@
</func>
<func>
- <name name="liat" arity="1"/>
+ <name name="liat" arity="1" since=""/>
<fsummary>Remove the tail item from a queue.</fsummary>
<desc>
<p>Returns a queue <c><anno>Q2</anno></c> that is the result of removing
@@ -411,7 +411,7 @@
</func>
<func>
- <name name="snoc" arity="2"/>
+ <name name="snoc" arity="2" since=""/>
<fsummary>Insert an item at the tail of a queue.</fsummary>
<desc>
<p>Inserts <c><anno>Item</anno></c> as the tail item of queue
@@ -421,7 +421,7 @@
</func>
<func>
- <name name="tail" arity="1"/>
+ <name name="tail" arity="1" since=""/>
<fsummary>Remove the head item from a queue.</fsummary>
<desc>
<p>Returns a queue <c><anno>Q2</anno></c> that is the result of removing
diff --git a/lib/stdlib/doc/src/rand.xml b/lib/stdlib/doc/src/rand.xml
index 89fb858823..b4737b48f8 100644
--- a/lib/stdlib/doc/src/rand.xml
+++ b/lib/stdlib/doc/src/rand.xml
@@ -32,31 +32,77 @@
<rev>A</rev>
<file>rand.xml</file>
</header>
- <module>rand</module>
+ <module since="OTP 18.0">rand</module>
<modulesummary>Pseudo random number generation.</modulesummary>
<description>
<p>
This module provides a pseudo random number generator.
The module contains a number of algorithms.
- The uniform distribution algorithms use the
+ The uniform distribution algorithms are based on the
<url href="http://xorshift.di.unimi.it">
- xoroshiro116+ and xorshift1024* algorithms by Sebastiano Vigna.
+ Xoroshiro and Xorshift algorithms
</url>
+ by Sebastiano Vigna.
The normal distribution algorithm uses the
<url href="http://www.jstatsoft.org/v05/i08">
Ziggurat Method by Marsaglia and Tsang
</url>
on top of the uniform distribution algorithm.
</p>
- <p>For some algorithms, jump functions are provided for generating
- non-overlapping sequences for parallel computations.
- The jump functions perform calculations
- equivalent to perform a large number of repeated calls
- for calculating new states. </p>
+ <p>
+ For most algorithms, jump functions are provided for generating
+ non-overlapping sequences for parallel computations.
+ The jump functions perform calculations
+ equivalent to perform a large number of repeated calls
+ for calculating new states.
+ </p>
<p>The following algorithms are provided:</p>
<taglist>
+ <tag><c>exsss</c></tag>
+ <item>
+ <p>Xorshift116**, 58 bits precision and period of 2^116-1</p>
+ <p>Jump function: equivalent to 2^64 calls</p>
+ <p>
+ This is the Xorshift116 generator combined with the StarStar scrambler
+ from the 2018 paper by David Blackman and Sebastiano Vigna:
+ <url href="http://vigna.di.unimi.it/ftp/papers/ScrambledLinear.pdf">
+ Scrambled Linear Pseudorandom Number Generators
+ </url>
+ </p>
+ <p>
+ The generator does not need 58-bit rotates so it is faster
+ than the Xoroshiro116 generator, and when combined with
+ the StarStar scrambler it does not have any weak low bits
+ like <c>exrop</c> (Xoroshiro116+).
+ </p>
+ <p>
+ Alas, this combination is about 10% slower than <c>exrop</c>,
+ but is despite that the default algorithm thanks to its
+ statistical qualities.
+ </p>
+ </item>
+ <tag><c>exro928ss</c></tag>
+ <item>
+ <p>Xoroshiro928**, 58 bits precision and a period of 2^928-1</p>
+ <p>Jump function: equivalent to 2^512 calls</p>
+ <p>
+ This is a 58 bit version of Xoroshiro1024**,
+ from the 2018 paper by David Blackman and Sebastiano Vigna:
+ <url href="http://vigna.di.unimi.it/ftp/papers/ScrambledLinear.pdf">
+ Scrambled Linear Pseudorandom Number Generators
+ </url>
+ that on a 64 bit Erlang system executes only about 40% slower than
+ the default <c>exsss</c> algorithm but with much longer period
+ and better statistical properties, and on the flip side
+ a larger state.
+ </p>
+ <p>
+ Many thanks to Sebastiano Vigna for his help with
+ the 58 bit adaption.
+ </p>
+ </item>
<tag><c>exrop</c></tag>
<item>
<p>Xoroshiro116+, 58 bits precision and period of 2^116-1</p>
@@ -83,7 +129,7 @@
</taglist>
<p>
- The default algorithm is <c>exrop</c> (Xoroshiro116+).
+ The default algorithm is <c>exsss</c> (Xorshift116**).
If a specific algorithm is
required, ensure to always use <seealso marker="#seed-1">
<c>seed/1</c></seealso> to initialize the state.
@@ -133,8 +179,9 @@
variable <c>rand_seed</c> to remember the current state.</p>
<p>If a process calls
- <seealso marker="#uniform-0"><c>uniform/0</c></seealso> or
- <seealso marker="#uniform-1"><c>uniform/1</c></seealso> without
+ <seealso marker="#uniform-0"><c>uniform/0</c></seealso>,
+ <seealso marker="#uniform-1"><c>uniform/1</c></seealso> or
+ <seealso marker="#uniform_real-0"><c>uniform_real/0</c></seealso> without
setting a seed first, <seealso marker="#seed-1"><c>seed/1</c></seealso>
is called automatically with the default algorithm and creates a
non-constant seed.</p>
@@ -153,25 +200,32 @@ R1 = rand:uniform(),</pre>
<p>Use a specified algorithm:</p>
<pre>
-_ = rand:seed(exs1024s),
+_ = rand:seed(exs928ss),
R2 = rand:uniform(),</pre>
<p>Use a specified algorithm with a constant seed:</p>
<pre>
-_ = rand:seed(exs1024s, {123, 123534, 345345}),
+_ = rand:seed(exs928ss, {123, 123534, 345345}),
R3 = rand:uniform(),</pre>
<p>Use the functional API with a non-constant seed:</p>
<pre>
-S0 = rand:seed_s(exrop),
+S0 = rand:seed_s(exsss),
{R4, S1} = rand:uniform_s(S0),</pre>
+ <p>Textbook basic form Box-Muller standard normal deviate</p>
+
+ <pre>
+R5 = rand:uniform_real(),
+R6 = rand:uniform(),
+SND0 = math:sqrt(-2 * math:log(R5)) * math:cos(math:pi() * R6)</pre>
+
<p>Create a standard normal deviate:</p>
<pre>
-{SND0, S2} = rand:normal_s(S1),</pre>
+{SND1, S2} = rand:normal_s(S1),</pre>
<p>Create a normal deviate with mean -3 and variance 0.5:</p>
@@ -187,8 +241,9 @@ S0 = rand:seed_s(exrop),
</note>
<p>
- For all these generators the lowest bit(s) has got
- a slightly less random behaviour than all other bits.
+ For all these generators except <c>exro928ss</c> and <c>exsss</c>
+ the lowest bit(s) has got a slightly less
+ random behaviour than all other bits.
1 bit for <c>exrop</c> (and <c>exsp</c>),
and 3 bits for <c>exs1024s</c>.
See for example the explanation in the
@@ -203,7 +258,7 @@ up to (and included) 16TB, with the exception of binary rank tests,
which fail due to the lowest bit being an LFSR; all other bits pass all
tests. We suggest to use a sign test to extract a random Boolean value.</pre>
<p>
- If this is a problem; to generate a boolean
+ If this is a problem; to generate a boolean with these algorithms
use something like this:
</p>
<pre>(rand:uniform(16) > 8)</pre>
@@ -246,26 +301,55 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre>
</desc>
</datatype>
<datatype>
- <name name="exs64_state"/>
- <desc><p>Algorithm specific internal state</p></desc>
+ <name name="seed"/>
+ <desc>
+ <p>
+ A seed value for the generator.
+ </p>
+ <p>
+ A list of integers sets the generator's internal state directly,
+ after algorithm-dependent checks of the value
+ and masking to the proper word size.
+ </p>
+ <p>
+ An integer is used as the initial state for a SplitMix64 generator.
+ The output values of that is then used for setting
+ the generator's internal state
+ after masking to the proper word size
+ and if needed avoiding zero values.
+ </p>
+ <p>
+ A traditional 3-tuple of integers seed is passed through
+ algorithm-dependent hashing functions to create
+ the generator's initial state.
+ </p>
+ </desc>
</datatype>
<datatype>
<name name="exsplus_state"/>
<desc><p>Algorithm specific internal state</p></desc>
</datatype>
<datatype>
- <name name="exs1024_state"/>
+ <name name="exro928_state"/>
<desc><p>Algorithm specific internal state</p></desc>
</datatype>
<datatype>
<name name="exrop_state"/>
<desc><p>Algorithm specific internal state</p></desc>
</datatype>
+ <datatype>
+ <name name="exs1024_state"/>
+ <desc><p>Algorithm specific internal state</p></desc>
+ </datatype>
+ <datatype>
+ <name name="exs64_state"/>
+ <desc><p>Algorithm specific internal state</p></desc>
+ </datatype>
</datatypes>
<funcs>
<func>
- <name name="export_seed" arity="0"/>
+ <name name="export_seed" arity="0" since="OTP 18.0"/>
<fsummary>Export the random number generation state.</fsummary>
<desc><marker id="export_seed-0"/>
<p>Returns the random number state in an external format.
@@ -274,7 +358,7 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre>
</func>
<func>
- <name name="export_seed_s" arity="1"/>
+ <name name="export_seed_s" arity="1" since="OTP 18.0"/>
<fsummary>Export the random number generation state.</fsummary>
<desc><marker id="export_seed_s-1"/>
<p>Returns the random number generator state in an external format.
@@ -283,7 +367,7 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre>
</func>
<func>
- <name name="jump" arity="0"/>
+ <name name="jump" arity="0" since="OTP 20.0"/>
<fsummary>Return the seed after performing jump calculation
to the state in the process dictionary.</fsummary>
<desc><marker id="jump-0" />
@@ -298,7 +382,7 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre>
</func>
<func>
- <name name="jump" arity="1"/>
+ <name name="jump" arity="1" since="OTP 20.0"/>
<fsummary>Return the seed after performing jump calculation.</fsummary>
<desc><marker id="jump-1" />
<p>Returns the state after performing jump calculation
@@ -310,7 +394,7 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre>
</func>
<func>
- <name name="normal" arity="0"/>
+ <name name="normal" arity="0" since="OTP 18.0"/>
<fsummary>Return a standard normal distributed random float.</fsummary>
<desc>
<p>Returns a standard normal deviate float (that is, the mean
@@ -320,7 +404,7 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre>
</func>
<func>
- <name name="normal" arity="2"/>
+ <name name="normal" arity="2" since="OTP 20.0"/>
<fsummary>Return a normal distributed random float.</fsummary>
<desc>
<p>Returns a normal N(Mean, Variance) deviate float
@@ -329,7 +413,7 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre>
</func>
<func>
- <name name="normal_s" arity="1"/>
+ <name name="normal_s" arity="1" since="OTP 18.0"/>
<fsummary>Return a standard normal distributed random float.</fsummary>
<desc>
<p>Returns, for a specified state, a standard normal
@@ -339,7 +423,7 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre>
</func>
<func>
- <name name="normal_s" arity="3"/>
+ <name name="normal_s" arity="3" since="OTP 20.0"/>
<fsummary>Return a normal distributed random float.</fsummary>
<desc>
<p>Returns, for a specified state, a normal N(Mean, Variance)
@@ -348,7 +432,7 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre>
</func>
<func>
- <name name="seed" arity="1"/>
+ <name name="seed" arity="1" since="OTP 18.0"/>
<fsummary>Seed random number generator.</fsummary>
<desc>
<marker id="seed-1"/>
@@ -364,7 +448,7 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre>
</func>
<func>
- <name name="seed" arity="2"/>
+ <name name="seed" arity="2" since="OTP 18.0"/>
<fsummary>Seed the random number generation.</fsummary>
<desc>
<p>Seeds random number generation with the specified algorithm and
@@ -373,7 +457,7 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre>
</func>
<func>
- <name name="seed_s" arity="1"/>
+ <name name="seed_s" arity="1" since="OTP 18.0"/>
<fsummary>Seed random number generator.</fsummary>
<desc>
<p>
@@ -388,7 +472,7 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre>
</func>
<func>
- <name name="seed_s" arity="2"/>
+ <name name="seed_s" arity="2" since="OTP 18.0"/>
<fsummary>Seed the random number generation.</fsummary>
<desc>
<p>Seeds random number generation with the specified algorithm and
@@ -397,7 +481,7 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre>
</func>
<func>
- <name name="uniform" arity="0"/>
+ <name name="uniform" arity="0" since="OTP 18.0"/>
<fsummary>Return a random float.</fsummary>
<desc><marker id="uniform-0"/>
<p>
@@ -414,7 +498,8 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre>
This function may return exactly <c>0.0</c> which can be
fatal for certain applications. If that is undesired
you can use <c>(1.0 - rand:uniform())</c> to get the
- interval <c>0.0 &lt; <anno>X</anno> =&lt; 1.0</c>.
+ interval <c>0.0 &lt; <anno>X</anno> =&lt; 1.0</c>, or instead use
+ <seealso marker="#uniform_real-0"><c>uniform_real/0</c></seealso>.
</p>
<p>
If neither endpoint is desired you can test and re-try
@@ -432,7 +517,43 @@ end.</pre>
</func>
<func>
- <name name="uniform" arity="1"/>
+ <name name="uniform_real" arity="0" since="OTP 21.0"/>
+ <fsummary>Return a random float.</fsummary>
+ <desc><marker id="uniform_real-0"/>
+ <p>
+ Returns a random float
+ uniformly distributed in the value range
+ <c>DBL_MIN =&lt; <anno>X</anno> &lt; 1.0</c>
+ and updates the state in the process dictionary.
+ </p>
+ <p>
+ Conceptually, a random real number <c>R</c> is generated
+ from the interval <c>0 =&lt; R &lt; 1</c> and then the
+ closest rounded down normalized number
+ in the IEEE 754 Double precision format
+ is returned.
+ </p>
+ <note>
+ <p>
+ The generated numbers from this function has got better
+ granularity for small numbers than the regular
+ <seealso marker="#uniform-0"><c>uniform/0</c></seealso>
+ because all bits in the mantissa are random.
+ This property, in combination with the fact that exactly zero
+ is never returned is useful for algoritms doing for example
+ <c>1.0 / <anno>X</anno></c> or <c>math:log(<anno>X</anno>)</c>.
+ </p>
+ </note>
+ <p>
+ See
+ <seealso marker="#uniform_real_s-1"><c>uniform_real_s/1</c></seealso>
+ for more explanation.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="uniform" arity="1" since="OTP 18.0"/>
<fsummary>Return a random integer.</fsummary>
<desc><marker id="uniform-1"/>
<p>Returns, for a specified integer <c><anno>N</anno> >= 1</c>,
@@ -443,7 +564,7 @@ end.</pre>
</func>
<func>
- <name name="uniform_s" arity="1"/>
+ <name name="uniform_s" arity="1" since="OTP 18.0"/>
<fsummary>Return a random float.</fsummary>
<desc>
<p>
@@ -460,7 +581,8 @@ end.</pre>
This function may return exactly <c>0.0</c> which can be
fatal for certain applications. If that is undesired
you can use <c>(1.0 - rand:uniform(State))</c> to get the
- interval <c>0.0 &lt; <anno>X</anno> =&lt; 1.0</c>.
+ interval <c>0.0 &lt; <anno>X</anno> =&lt; 1.0</c>, or instead use
+ <seealso marker="#uniform_real_s-1"><c>uniform_real_s/1</c></seealso>.
</p>
<p>
If neither endpoint is desired you can test and re-try
@@ -478,7 +600,69 @@ end.</pre>
</func>
<func>
- <name name="uniform_s" arity="2"/>
+ <name name="uniform_real_s" arity="1" since="OTP 21.0"/>
+ <fsummary>Return a random float.</fsummary>
+ <desc>
+ <p>
+ Returns, for a specified state, a random float
+ uniformly distributed in the value range
+ <c>DBL_MIN =&lt; <anno>X</anno> &lt; 1.0</c>
+ and updates the state in the process dictionary.
+ </p>
+ <p>
+ Conceptually, a random real number <c>R</c> is generated
+ from the interval <c>0 =&lt; R &lt; 1</c> and then the
+ closest rounded down normalized number
+ in the IEEE 754 Double precision format
+ is returned.
+ </p>
+ <note>
+ <p>
+ The generated numbers from this function has got better
+ granularity for small numbers than the regular
+ <seealso marker="#uniform_s-1"><c>uniform_s/1</c></seealso>
+ because all bits in the mantissa are random.
+ This property, in combination with the fact that exactly zero
+ is never returned is useful for algoritms doing for example
+ <c>1.0 / <anno>X</anno></c> or <c>math:log(<anno>X</anno>)</c>.
+ </p>
+ </note>
+ <p>
+ The concept implicates that the probability to get
+ exactly zero is extremely low; so low that this function
+ is in fact guaranteed to never return zero. The smallest
+ number that it might return is <c>DBL_MIN</c>, which is
+ 2.0^(-1022).
+ </p>
+ <p>
+ The value range stated at the top of this function
+ description is technically correct, but
+ <c>0.0 =&lt; <anno>X</anno> &lt; 1.0</c>
+ is a better description of the generated numbers'
+ statistical distribution. Except that exactly 0.0
+ is never returned, which is not possible to observe
+ statistically.
+ </p>
+ <p>
+ For example; for all sub ranges
+ <c>N*2.0^(-53) =&lt; X &lt; (N+1)*2.0^(-53)</c>
+ where
+ <c>0 =&lt; integer(N) &lt; 2.0^53</c>
+ the probability is the same.
+ Compare that with the form of the numbers generated by
+ <seealso marker="#uniform_s-1"><c>uniform_s/1</c></seealso>.
+ </p>
+ <p>
+ Having to generate extra random bits for
+ small numbers costs a little performance.
+ This function is about 20% slower than the regular
+ <seealso marker="#uniform_s-1"><c>uniform_s/1</c></seealso>
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="uniform_s" arity="2" since="OTP 18.0"/>
<fsummary>Return a random integer.</fsummary>
<desc>
<p>Returns, for a specified integer <c><anno>N</anno> >= 1</c>
diff --git a/lib/stdlib/doc/src/random.xml b/lib/stdlib/doc/src/random.xml
index 8d090d20b3..f0261ed009 100644
--- a/lib/stdlib/doc/src/random.xml
+++ b/lib/stdlib/doc/src/random.xml
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>random.xml</file>
</header>
- <module>random</module>
+ <module since="">random</module>
<modulesummary>Pseudo-random number generation.</modulesummary>
<description>
<p>This module provides a random number generator. The method is attributed
@@ -73,7 +73,7 @@
<funcs>
<func>
- <name name="seed" arity="0"/>
+ <name name="seed" arity="0" since=""/>
<fsummary>Seed random number generation with default values.</fsummary>
<desc>
<p>Seeds random number generation with default (fixed) values
@@ -82,7 +82,7 @@
</func>
<func>
- <name name="seed" arity="1"/>
+ <name name="seed" arity="1" since=""/>
<fsummary>Seed random number generator.</fsummary>
<desc>
<p><c>seed({<anno>A1</anno>, <anno>A2</anno>, <anno>A3</anno>})</c>
@@ -92,7 +92,7 @@
</func>
<func>
- <name name="seed" arity="3"/>
+ <name name="seed" arity="3" since=""/>
<fsummary>Seed random number generator.</fsummary>
<desc>
<p>Seeds random number generation with integer values in the process
@@ -116,7 +116,7 @@ random:seed(erlang:phash2([node()]),
</func>
<func>
- <name name="seed0" arity="0"/>
+ <name name="seed0" arity="0" since=""/>
<fsummary>Return default state for random number generation.</fsummary>
<desc>
<p>Returns the default state.</p>
@@ -124,7 +124,7 @@ random:seed(erlang:phash2([node()]),
</func>
<func>
- <name name="uniform" arity="0"/>
+ <name name="uniform" arity="0" since=""/>
<fsummary>Return a random float.</fsummary>
<desc>
<p>Returns a random float uniformly distributed between <c>0.0</c>
@@ -133,7 +133,7 @@ random:seed(erlang:phash2([node()]),
</func>
<func>
- <name name="uniform" arity="1"/>
+ <name name="uniform" arity="1" since=""/>
<fsummary>Return a random integer.</fsummary>
<desc>
<p>Returns, for a specified integer <c><anno>N</anno> >= 1</c>,
@@ -144,7 +144,7 @@ random:seed(erlang:phash2([node()]),
</func>
<func>
- <name name="uniform_s" arity="1"/>
+ <name name="uniform_s" arity="1" since=""/>
<fsummary>Return a random float.</fsummary>
<desc>
<p>Returns, for a specified state, a random float uniformly
@@ -153,7 +153,7 @@ random:seed(erlang:phash2([node()]),
</func>
<func>
- <name name="uniform_s" arity="2"/>
+ <name name="uniform_s" arity="2" since=""/>
<fsummary>Return a random integer.</fsummary>
<desc>
<p>Returns, for a specified integer <c><anno>N</anno> >= 1</c> and a
diff --git a/lib/stdlib/doc/src/re.xml b/lib/stdlib/doc/src/re.xml
index 078ca0e38c..b04434492d 100644
--- a/lib/stdlib/doc/src/re.xml
+++ b/lib/stdlib/doc/src/re.xml
@@ -34,7 +34,7 @@
<rev>A</rev>
<file>re.xml</file>
</header>
- <module>re</module>
+ <module since="">re</module>
<modulesummary>Perl-like regular expressions for Erlang.</modulesummary>
<description>
<p>This module contains regular expression matching functions for
@@ -79,7 +79,7 @@
<funcs>
<func>
- <name name="version" arity="0"/>
+ <name name="version" arity="0" since="OTP 20.0"/>
<fsummary>Gives the PCRE version of the system in a string format</fsummary>
<desc>
<p>The return of this function is a string with the PCRE version of the system that was used in the Erlang/OTP compilation.</p>
@@ -87,7 +87,7 @@
</func>
<func>
- <name name="compile" arity="1"/>
+ <name name="compile" arity="1" since=""/>
<fsummary>Compile a regular expression into a match program</fsummary>
<desc>
<p>The same as <c>compile(<anno>Regexp</anno>,[])</c></p>
@@ -95,7 +95,7 @@
</func>
<func>
- <name name="compile" arity="2"/>
+ <name name="compile" arity="2" since=""/>
<fsummary>Compile a regular expression into a match program.</fsummary>
<desc>
<p>Compiles a regular expression, with the syntax
@@ -304,7 +304,7 @@
</func>
<func>
- <name name="inspect" arity="2"/>
+ <name name="inspect" arity="2" since="OTP 17.0"/>
<fsummary>Inspects a compiled regular expression.</fsummary>
<desc>
<p>Takes a compiled regular expression and an item, and returns the
@@ -348,7 +348,7 @@
</func>
<func>
- <name name="replace" arity="3"/>
+ <name name="replace" arity="3" since=""/>
<fsummary>Match a subject against regular expression and replace matching
elements with Replacement.</fsummary>
<desc>
@@ -358,7 +358,7 @@
</func>
<func>
- <name name="replace" arity="4"/>
+ <name name="replace" arity="4" since=""/>
<fsummary>Match a subject against regular expression and replace matching
elements with Replacement.</fsummary>
<desc>
@@ -408,7 +408,7 @@ re:replace("abcd","c","[\\&amp;]",[{return,list}]).</code>
</func>
<func>
- <name name="run" arity="2"/>
+ <name name="run" arity="2" since=""/>
<fsummary>Match a subject against regular expression and capture
subpatterns.</fsummary>
<desc>
@@ -417,7 +417,7 @@ re:replace("abcd","c","[\\&amp;]",[{return,list}]).</code>
</func>
<func>
- <name name="run" arity="3"/>
+ <name name="run" arity="3" since=""/>
<fsummary>Match a subject against regular expression and capture
subpatterns.</fsummary>
<type_desc variable="CompileOpt">See <seealso marker="#compile_options">
@@ -992,7 +992,7 @@ re:run("cacb","c(a|b)",[global,{capture,[1],list}]).</code>
</func>
<func>
- <name name="split" arity="2"/>
+ <name name="split" arity="2" since=""/>
<fsummary>Split a string by tokens specified as a regular expression.
</fsummary>
<desc>
@@ -1001,7 +1001,7 @@ re:run("cacb","c(a|b)",[global,{capture,[1],list}]).</code>
</func>
<func>
- <name name="split" arity="3"/>
+ <name name="split" arity="3" since=""/>
<fsummary>Split a string by tokens specified as a regular expression</fsummary>
<type_desc variable="CompileOpt">See <seealso marker="#compile_options">
<c>compile/2</c></seealso>.</type_desc>
diff --git a/lib/stdlib/doc/src/ref_man.xml b/lib/stdlib/doc/src/ref_man.xml
index 878a3babc5..8d61833d1f 100644
--- a/lib/stdlib/doc/src/ref_man.xml
+++ b/lib/stdlib/doc/src/ref_man.xml
@@ -4,7 +4,7 @@
<application xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -66,7 +66,6 @@
<xi:include href="gen_statem.xml"/>
<xi:include href="io.xml"/>
<xi:include href="io_lib.xml"/>
- <xi:include href="lib.xml"/>
<xi:include href="lists.xml"/>
<xi:include href="log_mf_h.xml"/>
<xi:include href="maps.xml"/>
@@ -93,6 +92,7 @@
<xi:include href="sys.xml"/>
<xi:include href="timer.xml"/>
<xi:include href="unicode.xml"/>
+ <xi:include href="uri_string.xml"/>
<xi:include href="win32reg.xml"/>
<xi:include href="zip.xml"/>
</application>
diff --git a/lib/stdlib/doc/src/sets.xml b/lib/stdlib/doc/src/sets.xml
index 4934bed365..07ce41b7a7 100644
--- a/lib/stdlib/doc/src/sets.xml
+++ b/lib/stdlib/doc/src/sets.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2000</year><year>2017</year>
+ <year>2000</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>sets.xml</file>
</header>
- <module>sets</module>
+ <module since="">sets</module>
<modulesummary>Functions for set manipulation.</modulesummary>
<description>
<p>Sets are collections of elements with no duplicate elements.
@@ -59,7 +59,7 @@
<funcs>
<func>
- <name name="add_element" arity="2"/>
+ <name name="add_element" arity="2" since=""/>
<fsummary>Add an element to a <c>Set</c>.</fsummary>
<desc>
<p>Returns a new set formed from <c><anno>Set1</anno></c> with
@@ -68,7 +68,7 @@
</func>
<func>
- <name name="del_element" arity="2"/>
+ <name name="del_element" arity="2" since=""/>
<fsummary>Remove an element from a <c>Set</c>.</fsummary>
<desc>
<p>Returns <c><anno>Set1</anno></c>, but with
@@ -77,7 +77,7 @@
</func>
<func>
- <name name="filter" arity="2"/>
+ <name name="filter" arity="2" since=""/>
<fsummary>Filter set elements.</fsummary>
<desc>
<p>Filters elements in <c><anno>Set1</anno></c> with boolean function
@@ -86,7 +86,7 @@
</func>
<func>
- <name name="fold" arity="3"/>
+ <name name="fold" arity="3" since=""/>
<fsummary>Fold over set elements.</fsummary>
<desc>
<p>Folds <c><anno>Function</anno></c> over every element in
@@ -96,7 +96,7 @@
</func>
<func>
- <name name="from_list" arity="1"/>
+ <name name="from_list" arity="1" since=""/>
<fsummary>Convert a list into a <c>Set</c>.</fsummary>
<desc>
<p>Returns a set of the elements in <c><anno>List</anno></c>.</p>
@@ -104,7 +104,7 @@
</func>
<func>
- <name name="intersection" arity="1"/>
+ <name name="intersection" arity="1" since=""/>
<fsummary>Return the intersection of a list of <c>Sets</c>.</fsummary>
<desc>
<p>Returns the intersection of the non-empty list of sets.</p>
@@ -112,7 +112,7 @@
</func>
<func>
- <name name="intersection" arity="2"/>
+ <name name="intersection" arity="2" since=""/>
<fsummary>Return the intersection of two <c>Sets</c>.</fsummary>
<desc>
<p>Returns the intersection of <c><anno>Set1</anno></c> and
@@ -121,7 +121,7 @@
</func>
<func>
- <name name="is_disjoint" arity="2"/>
+ <name name="is_disjoint" arity="2" since=""/>
<fsummary>Check whether two <c>Sets</c> are disjoint.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Set1</anno></c> and
@@ -131,7 +131,7 @@
</func>
<func>
- <name name="is_element" arity="2"/>
+ <name name="is_element" arity="2" since=""/>
<fsummary>Test for membership of a <c>Set</c>.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Element</anno></c> is an element of
@@ -140,7 +140,16 @@
</func>
<func>
- <name name="is_set" arity="1"/>
+ <name name="is_empty" arity="1" since="OTP 21.0"/>
+ <fsummary>Test for empty set.</fsummary>
+ <desc>
+ <p>Returns <c>true</c> if <c><anno>Set</anno></c> is an empty set,
+ otherwise <c>false</c>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="is_set" arity="1" since=""/>
<fsummary>Test for a <c>Set</c>.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Set</anno></c> is a set of
@@ -149,7 +158,7 @@
</func>
<func>
- <name name="is_subset" arity="2"/>
+ <name name="is_subset" arity="2" since=""/>
<fsummary>Test for subset.</fsummary>
<desc>
<p>Returns <c>true</c> when every element of <c><anno>Set1</anno></c> is
@@ -158,7 +167,7 @@
</func>
<func>
- <name name="new" arity="0"/>
+ <name name="new" arity="0" since=""/>
<fsummary>Return an empty set.</fsummary>
<desc>
<p>Returns a new empty set.</p>
@@ -166,7 +175,7 @@
</func>
<func>
- <name name="size" arity="1"/>
+ <name name="size" arity="1" since=""/>
<fsummary>Return the number of elements in a set.</fsummary>
<desc>
<p>Returns the number of elements in <c><anno>Set</anno></c>.</p>
@@ -174,7 +183,7 @@
</func>
<func>
- <name name="subtract" arity="2"/>
+ <name name="subtract" arity="2" since=""/>
<fsummary>Return the difference of two <c>Sets</c>.</fsummary>
<desc>
<p>Returns only the elements of <c><anno>Set1</anno></c> that are not
@@ -183,7 +192,7 @@
</func>
<func>
- <name name="to_list" arity="1"/>
+ <name name="to_list" arity="1" since=""/>
<fsummary>Convert a <c>Set</c>into a list.</fsummary>
<desc>
<p>Returns the elements of <c><anno>Set</anno></c> as a list.
@@ -192,7 +201,7 @@
</func>
<func>
- <name name="union" arity="1"/>
+ <name name="union" arity="1" since=""/>
<fsummary>Return the union of a list of <c>Sets</c>.</fsummary>
<desc>
<p>Returns the merged (union) set of the list of sets.</p>
@@ -200,7 +209,7 @@
</func>
<func>
- <name name="union" arity="2"/>
+ <name name="union" arity="2" since=""/>
<fsummary>Return the union of two <c>Sets</c>.</fsummary>
<desc>
<p>Returns the merged (union) set of <c><anno>Set1</anno></c> and
diff --git a/lib/stdlib/doc/src/shell.xml b/lib/stdlib/doc/src/shell.xml
index 2593d3690b..50a0968531 100644
--- a/lib/stdlib/doc/src/shell.xml
+++ b/lib/stdlib/doc/src/shell.xml
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>shell.xml</file>
</header>
- <module>shell</module>
+ <module since="">shell</module>
<modulesummary>The Erlang shell.</modulesummary>
<description>
<p>This module provides an Erlang shell.</p>
@@ -874,7 +874,7 @@ q - quit erlang
<funcs>
<func>
- <name>catch_exception(Bool) -> boolean()</name>
+ <name since="">catch_exception(Bool) -> boolean()</name>
<fsummary>Set the exception handling of the shell.</fsummary>
<type>
<v>Bool = boolean()</v>
@@ -892,7 +892,7 @@ q - quit erlang
</func>
<func>
- <name name="history" arity="1"/>
+ <name name="history" arity="1" since=""/>
<fsummary>Set the number of previous commands to keep.</fsummary>
<desc>
<p>Sets the number of previous commands to keep in the
@@ -902,7 +902,7 @@ q - quit erlang
</func>
<func>
- <name name="prompt_func" arity="1"/>
+ <name name="prompt_func" arity="1" since="OTP R13B04"/>
<fsummary>Set the shell prompt.</fsummary>
<desc>
<p>Sets the shell prompt function to <c><anno>PromptFunc</anno></c>.
@@ -911,7 +911,7 @@ q - quit erlang
</func>
<func>
- <name name="results" arity="1"/>
+ <name name="results" arity="1" since=""/>
<fsummary>Set the number of previous results to keep.</fsummary>
<desc>
<p>Sets the number of results from previous commands to keep in
@@ -921,7 +921,7 @@ q - quit erlang
</func>
<func>
- <name name="start_restricted" arity="1"/>
+ <name name="start_restricted" arity="1" since=""/>
<fsummary>Exit a normal shell and starts a restricted shell.</fsummary>
<desc>
<p>Exits a normal shell and starts a restricted shell.
@@ -936,7 +936,7 @@ q - quit erlang
</func>
<func>
- <name name="stop_restricted" arity="0"/>
+ <name name="stop_restricted" arity="0" since=""/>
<fsummary>Exit a restricted shell and starts a normal shell.</fsummary>
<desc>
<p>Exits a restricted shell and starts a normal shell. The function
@@ -945,7 +945,7 @@ q - quit erlang
</func>
<func>
- <name name="strings" arity="1"/>
+ <name name="strings" arity="1" since="OTP R16B"/>
<fsummary>Set the shell's string recognition flag.</fsummary>
<desc>
<p>Sets pretty printing of lists to <c><anno>Strings</anno></c>.
diff --git a/lib/stdlib/doc/src/slave.xml b/lib/stdlib/doc/src/slave.xml
index e53ec8231b..f9e42ad47d 100644
--- a/lib/stdlib/doc/src/slave.xml
+++ b/lib/stdlib/doc/src/slave.xml
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>slave</module>
+ <module since="">slave</module>
<modulesummary>Functions for starting and controlling slave nodes.
</modulesummary>
<description>
@@ -39,23 +39,30 @@
done through the master.</p>
<p>Slave nodes on other hosts than the current one are started with
- the <c>rsh</c> program. The user must be allowed to <c>rsh</c> to
+ the <c>ssh</c> program. The user must be allowed to <c>ssh</c> to
the remote hosts without being prompted for a password. This can
- be arranged in a number of ways (for details, see the <c>rsh</c>
+ be arranged in a number of ways (for details, see the <c>ssh</c>
documentation). A slave node started on the same host
as the master inherits certain environment values from the master,
such as the current directory and the environment variables. For
what can be assumed about the environment when a slave is started
- on another host, see the documentation for the <c>rsh</c>
+ on another host, see the documentation for the <c>ssh</c>
program.</p>
- <p>An alternative to the <c>rsh</c> program can be specified on
+ <p>An alternative to the <c>ssh</c> program can be specified on
the command line to
- <seealso marker="erts:erl#erl"><c>erl(1)</c></seealso> as follows:</p>
+ <seealso marker="erts:erl"><c>erl(1)</c></seealso> as follows:</p>
<pre>
-rsh Program</pre>
+ <p>Note that the command specified with the <c>-rsh</c> flag is
+ treated as a file name which may contain spaces. It is thus not
+ possible to include any command line options. The remote node will
+ be launched as <c>"$RSH" "$REMOTE_HOSTNAME" erl -detached -noinput
+ ...</c>, so the
+ <c>erl</c> command must be found in the path on the remote host.</p>
+
<p>The slave node is to use the same file system at the master. At
least, Erlang/OTP is to be installed in the same place on both
computers and the same version of Erlang is to be used.</p>
@@ -68,7 +75,7 @@
<funcs>
<func>
- <name>pseudo([Master | ServerList]) -> ok</name>
+ <name since="">pseudo([Master | ServerList]) -> ok</name>
<fsummary>Start a number of pseudo servers.</fsummary>
<type>
<v>Master = node()</v>
@@ -84,7 +91,7 @@
</func>
<func>
- <name name="pseudo" arity="2"/>
+ <name name="pseudo" arity="2" since=""/>
<fsummary>Start a number of pseudo servers.</fsummary>
<desc>
<p>Starts a number of pseudo servers. A pseudo server is a
@@ -102,7 +109,7 @@ rpc:call(N, slave, pseudo, [node(), [pxw_server]]).</code>
</func>
<func>
- <name name="relay" arity="1"/>
+ <name name="relay" arity="1" since=""/>
<fsummary>Run a pseudo server.</fsummary>
<desc>
<p>Runs a pseudo server. This function never returns any value
@@ -113,9 +120,9 @@ rpc:call(N, slave, pseudo, [node(), [pxw_server]]).</code>
</func>
<func>
- <name name="start" arity="1"/>
- <name name="start" arity="2"/>
- <name name="start" arity="3"/>
+ <name name="start" arity="1" since=""/>
+ <name name="start" arity="2" since=""/>
+ <name name="start" arity="3" since=""/>
<fsummary>Start a slave node on a host.</fsummary>
<desc>
<p>Starts a slave node on host <c><anno>Host</anno></c>. Host names
@@ -133,7 +140,7 @@ rpc:call(N, slave, pseudo, [node(), [pxw_server]]).</code>
<p>Argument <c><anno>Args</anno></c> is used to set <c>erl</c>
command-line arguments. If provided, it is passed to the new
node and can be used for a variety of purposes; see
- <seealso marker="erts:erl#erl"><c>erl(1)</c></seealso>.</p>
+ <seealso marker="erts:erl"><c>erl(1)</c></seealso>.</p>
<p>As an example, suppose that you want to start a slave node at
host <c>H</c> with node name <c>Name@H</c> and
want the slave node to have the following properties:</p>
@@ -166,7 +173,9 @@ slave:start(H, Name, Arg).</code>
</item>
<tag><c>no_rsh</c></tag>
<item>
- <p>There is no <c>rsh</c> program on the computer.</p>
+ <p>No remote shell program was found on the computer. Note
+ that <c>ssh</c> is used by default, but this can be overridden
+ with the <c>-rsh</c> flag.</p>
</item>
<tag><c>{already_running, <anno>Node</anno>}</c></tag>
<item>
@@ -178,9 +187,9 @@ slave:start(H, Name, Arg).</code>
</func>
<func>
- <name name="start_link" arity="1"/>
- <name name="start_link" arity="2"/>
- <name name="start_link" arity="3"/>
+ <name name="start_link" arity="1" since=""/>
+ <name name="start_link" arity="2" since=""/>
+ <name name="start_link" arity="3" since=""/>
<fsummary>Start and link to a slave node on a host.</fsummary>
<desc>
<p>Starts a slave node in the same way as <c>start/1,2,3</c>,
@@ -193,7 +202,7 @@ slave:start(H, Name, Arg).</code>
</func>
<func>
- <name name="stop" arity="1"/>
+ <name name="stop" arity="1" since=""/>
<fsummary>Stop (kill) a node.</fsummary>
<desc>
<p>Stops (kills) a node.</p>
diff --git a/lib/stdlib/doc/src/sofs.xml b/lib/stdlib/doc/src/sofs.xml
index 4cf1984d46..a0759d2f52 100644
--- a/lib/stdlib/doc/src/sofs.xml
+++ b/lib/stdlib/doc/src/sofs.xml
@@ -32,7 +32,7 @@
<rev>PA1</rev>
<file>sofs.xml</file>
</header>
- <module>sofs</module>
+ <module since="">sofs</module>
<modulesummary>Functions for manipulating sets of sets.</modulesummary>
<description>
<p>This module provides operations on finite sets and
@@ -456,8 +456,8 @@ fun(S) -> sofs:partition(1, S) end
<funcs>
<func>
- <name name="a_function" arity="1"/>
- <name name="a_function" arity="2"/>
+ <name name="a_function" arity="1" since=""/>
+ <name name="a_function" arity="2" since=""/>
<fsummary>Create a function.</fsummary>
<desc>
<p>Creates a <seealso marker="#function">function</seealso>.
@@ -470,7 +470,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="canonical_relation" arity="1"/>
+ <name name="canonical_relation" arity="1" since=""/>
<fsummary>Return the canonical map.</fsummary>
<desc>
<p>Returns the binary relation containing the elements
@@ -490,7 +490,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="composite" arity="2"/>
+ <name name="composite" arity="2" since=""/>
<fsummary>Return the composite of two functions.</fsummary>
<desc>
<p>Returns the <seealso marker="#composite">composite</seealso> of
@@ -506,7 +506,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="constant_function" arity="2"/>
+ <name name="constant_function" arity="2" since=""/>
<fsummary>Create the function that maps each element of a
set onto another set.</fsummary>
<desc>
@@ -522,7 +522,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="converse" arity="1"/>
+ <name name="converse" arity="1" since=""/>
<fsummary>Return the converse of a binary relation.</fsummary>
<desc>
<p>Returns the <seealso marker="#converse">converse</seealso>
@@ -536,7 +536,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="difference" arity="2"/>
+ <name name="difference" arity="2" since=""/>
<fsummary>Return the difference of two sets.</fsummary>
<desc>
<p>Returns the <seealso marker="#difference">difference</seealso> of
@@ -545,8 +545,8 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="digraph_to_family" arity="1"/>
- <name name="digraph_to_family" arity="2"/>
+ <name name="digraph_to_family" arity="1" since=""/>
+ <name name="digraph_to_family" arity="2" since=""/>
<fsummary>Create a family from a directed graph.</fsummary>
<desc>
<p>Creates a <seealso marker="#family">family</seealso> from
@@ -565,7 +565,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="domain" arity="1"/>
+ <name name="domain" arity="1" since=""/>
<fsummary>Return the domain of a binary relation.</fsummary>
<desc>
<p>Returns the <seealso marker="#domain">domain</seealso> of
@@ -579,7 +579,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="drestriction" arity="2"/>
+ <name name="drestriction" arity="2" since=""/>
<fsummary>Return a restriction of a binary relation.</fsummary>
<desc>
<p>Returns the difference between the binary relation
@@ -598,7 +598,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="drestriction" arity="3"/>
+ <name name="drestriction" arity="3" since=""/>
<fsummary>Return a restriction of a relation.</fsummary>
<desc>
<p>Returns a subset of <c><anno>Set1</anno></c> containing those
@@ -618,7 +618,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="empty_set" arity="0"/>
+ <name name="empty_set" arity="0" since=""/>
<fsummary>Return the untyped empty set.</fsummary>
<desc>
<p>Returns the <seealso marker="#sets_definition">untyped empty
@@ -628,7 +628,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="extension" arity="3"/>
+ <name name="extension" arity="3" since=""/>
<fsummary>Extend the domain of a binary relation.</fsummary>
<desc>
<p>Returns the <seealso marker="#extension">extension</seealso> of
@@ -648,8 +648,8 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="family" arity="1"/>
- <name name="family" arity="2"/>
+ <name name="family" arity="1" since=""/>
+ <name name="family" arity="2" since=""/>
<fsummary>Create a family of subsets.</fsummary>
<desc>
<p>Creates a <seealso marker="#family">family of subsets</seealso>.
@@ -662,7 +662,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="family_difference" arity="2"/>
+ <name name="family_difference" arity="2" since=""/>
<fsummary>Return the difference of two families.</fsummary>
<desc>
<p>If <c><anno>Family1</anno></c> and <c><anno>Family2</anno></c>
@@ -683,7 +683,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="family_domain" arity="1"/>
+ <name name="family_domain" arity="1" since=""/>
<fsummary>Return a family of domains.</fsummary>
<desc>
<p>If <c><anno>Family1</anno></c> is
@@ -704,7 +704,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="family_field" arity="1"/>
+ <name name="family_field" arity="1" since=""/>
<fsummary>Return a family of fields.</fsummary>
<desc>
<p>If <c><anno>Family1</anno></c> is
@@ -728,7 +728,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="family_intersection" arity="1"/>
+ <name name="family_intersection" arity="1" since=""/>
<fsummary>Return the intersection of a family
of sets of sets.</fsummary>
<desc>
@@ -752,7 +752,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="family_intersection" arity="2"/>
+ <name name="family_intersection" arity="2" since=""/>
<fsummary>Return the intersection of two families.</fsummary>
<desc>
<p>If <c><anno>Family1</anno></c> and <c><anno>Family2</anno></c>
@@ -772,7 +772,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="family_projection" arity="2"/>
+ <name name="family_projection" arity="2" since=""/>
<fsummary>Return a family of modified subsets.</fsummary>
<desc>
<p>If <c><anno>Family1</anno></c> is
@@ -791,7 +791,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="family_range" arity="1"/>
+ <name name="family_range" arity="1" since=""/>
<fsummary>Return a family of ranges.</fsummary>
<desc>
<p>If <c><anno>Family1</anno></c> is
@@ -812,7 +812,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="family_specification" arity="2"/>
+ <name name="family_specification" arity="2" since=""/>
<fsummary>Select a subset of a family using a predicate.</fsummary>
<desc>
<p>If <c><anno>Family1</anno></c> is
@@ -837,8 +837,8 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="family_to_digraph" arity="1"/>
- <name name="family_to_digraph" arity="2"/>
+ <name name="family_to_digraph" arity="1" since=""/>
+ <name name="family_to_digraph" arity="2" since=""/>
<fsummary>Create a directed graph from a family.</fsummary>
<desc>
<p>Creates a directed graph from
@@ -863,7 +863,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="family_to_relation" arity="1"/>
+ <name name="family_to_relation" arity="1" since=""/>
<fsummary>Create a binary relation from a family.</fsummary>
<desc>
<p>If <c><anno>Family</anno></c> is
@@ -881,7 +881,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="family_union" arity="1"/>
+ <name name="family_union" arity="1" since=""/>
<fsummary>Return the union of a family of sets of sets.</fsummary>
<desc>
<p>If <c><anno>Family1</anno></c> is
@@ -904,7 +904,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="family_union" arity="2"/>
+ <name name="family_union" arity="2" since=""/>
<fsummary>Return the union of two families.</fsummary>
<desc>
<p>If <c><anno>Family1</anno></c> and <c><anno>Family2</anno></c>
@@ -926,7 +926,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="field" arity="1"/>
+ <name name="field" arity="1" since=""/>
<fsummary>Return the field of a binary relation.</fsummary>
<desc>
<p>Returns the <seealso marker="#field">field</seealso> of the
@@ -942,7 +942,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="from_external" arity="2"/>
+ <name name="from_external" arity="2" since=""/>
<fsummary>Create a set.</fsummary>
<desc>
<p>Creates a set from the <seealso marker="#external_set">external
@@ -955,7 +955,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="from_sets" arity="1" clause_i="1"/>
+ <name name="from_sets" arity="1" clause_i="1" since=""/>
<fsummary>Create a set out of a list of sets.</fsummary>
<desc>
<p>Returns the <seealso marker="#sets_definition">unordered
@@ -971,7 +971,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="from_sets" arity="1" clause_i="2"/>
+ <name name="from_sets" arity="1" clause_i="2" since=""/>
<fsummary>Create an ordered set out of a tuple of sets.</fsummary>
<desc>
<p>Returns the <seealso marker="#sets_definition">ordered
@@ -981,8 +981,8 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="from_term" arity="1"/>
- <name name="from_term" arity="2"/>
+ <name name="from_term" arity="1" since=""/>
+ <name name="from_term" arity="2" since=""/>
<fsummary>Create a set.</fsummary>
<desc>
<p><marker id="from_term"></marker>Creates an element
@@ -1031,7 +1031,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="image" arity="2"/>
+ <name name="image" arity="2" since=""/>
<fsummary>Return the image of a set under a binary relation.</fsummary>
<desc>
<p>Returns the <seealso marker="#image">image</seealso> of
@@ -1047,7 +1047,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="intersection" arity="1"/>
+ <name name="intersection" arity="1" since=""/>
<fsummary>Return the intersection of a set of sets.</fsummary>
<desc>
<p>Returns
@@ -1059,7 +1059,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="intersection" arity="2"/>
+ <name name="intersection" arity="2" since=""/>
<fsummary>Return the intersection of two sets.</fsummary>
<desc>
<p>Returns
@@ -1069,7 +1069,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="intersection_of_family" arity="1"/>
+ <name name="intersection_of_family" arity="1" since=""/>
<fsummary>Return the intersection of a family.</fsummary>
<desc>
<p>Returns the intersection of
@@ -1086,7 +1086,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="inverse" arity="1"/>
+ <name name="inverse" arity="1" since=""/>
<fsummary>Return the inverse of a function.</fsummary>
<desc>
<p>Returns the <seealso marker="#inverse">inverse</seealso>
@@ -1100,7 +1100,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="inverse_image" arity="2"/>
+ <name name="inverse_image" arity="2" since=""/>
<fsummary>Return the inverse image of a set under
a binary relation.</fsummary>
<desc>
@@ -1117,7 +1117,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="is_a_function" arity="1"/>
+ <name name="is_a_function" arity="1" since=""/>
<fsummary>Test for a function.</fsummary>
<desc>
<p>Returns <c>true</c> if the binary relation <c><anno>BinRel</anno></c>
@@ -1127,7 +1127,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="is_disjoint" arity="2"/>
+ <name name="is_disjoint" arity="2" since=""/>
<fsummary>Test for disjoint sets.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Set1</anno></c>
@@ -1138,7 +1138,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="is_empty_set" arity="1"/>
+ <name name="is_empty_set" arity="1" since=""/>
<fsummary>Test for an empty set.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>AnySet</anno></c> is an empty
@@ -1147,7 +1147,7 @@ fun(S) -> sofs:partition(1, S) end
</func>
<func>
- <name name="is_equal" arity="2"/>
+ <name name="is_equal" arity="2" since=""/>
<fsummary>Test two sets for equality.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>AnySet1</anno></c>
@@ -1164,7 +1164,7 @@ true</pre>
</func>
<func>
- <name name="is_set" arity="1"/>
+ <name name="is_set" arity="1" since=""/>
<fsummary>Test for an unordered set.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>AnySet</anno></c> is
@@ -1175,7 +1175,7 @@ true</pre>
</func>
<func>
- <name name="is_sofs_set" arity="1"/>
+ <name name="is_sofs_set" arity="1" since=""/>
<fsummary>Test for an unordered set.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Term</anno></c> is
@@ -1185,7 +1185,7 @@ true</pre>
</func>
<func>
- <name name="is_subset" arity="2"/>
+ <name name="is_subset" arity="2" since=""/>
<fsummary>Test two sets for subset.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>Set1</anno></c> is
@@ -1195,7 +1195,7 @@ true</pre>
</func>
<func>
- <name name="is_type" arity="1"/>
+ <name name="is_type" arity="1" since=""/>
<fsummary>Test for a type.</fsummary>
<desc>
<p>Returns <c>true</c> if term <c><anno>Term</anno></c> is
@@ -1204,7 +1204,7 @@ true</pre>
</func>
<func>
- <name name="join" arity="4"/>
+ <name name="join" arity="4" since=""/>
<fsummary>Return the join of two relations.</fsummary>
<desc>
<p>Returns the <seealso marker="#natural_join">natural
@@ -1221,7 +1221,7 @@ true</pre>
</func>
<func>
- <name name="multiple_relative_product" arity="2"/>
+ <name name="multiple_relative_product" arity="2" since=""/>
<fsummary>Return the multiple relative product of a tuple of binary
relations and a relation.</fsummary>
<desc>
@@ -1242,7 +1242,7 @@ true</pre>
</func>
<func>
- <name name="no_elements" arity="1"/>
+ <name name="no_elements" arity="1" since=""/>
<fsummary>Return the number of elements of a set.</fsummary>
<desc>
<p>Returns the number of elements of the ordered or unordered
@@ -1251,7 +1251,7 @@ true</pre>
</func>
<func>
- <name name="partition" arity="1"/>
+ <name name="partition" arity="1" since=""/>
<fsummary>Return the coarsest partition given a set of sets.</fsummary>
<desc>
<p>Returns the <seealso marker="#partition">partition</seealso> of
@@ -1268,7 +1268,7 @@ true</pre>
</func>
<func>
- <name name="partition" arity="2"/>
+ <name name="partition" arity="2" since=""/>
<fsummary>Return a partition of a set.</fsummary>
<desc>
<p>Returns the <seealso marker="#partition">partition</seealso> of
@@ -1284,7 +1284,7 @@ true</pre>
</func>
<func>
- <name name="partition" arity="3"/>
+ <name name="partition" arity="3" since=""/>
<fsummary>Return a partition of a set.</fsummary>
<desc>
<p>Returns a pair of sets that, regarded as constituting a
@@ -1307,7 +1307,7 @@ true</pre>
</func>
<func>
- <name name="partition_family" arity="2"/>
+ <name name="partition_family" arity="2" since=""/>
<fsummary>Return a family indexing a partition.</fsummary>
<desc>
<p>Returns <seealso marker="#family">family</seealso>
@@ -1328,7 +1328,7 @@ true</pre>
</func>
<func>
- <name name="product" arity="1"/>
+ <name name="product" arity="1" since=""/>
<fsummary>Return the Cartesian product of a tuple of sets.</fsummary>
<desc>
<p>Returns the <seealso marker="#Cartesian_product_tuple">Cartesian
@@ -1347,7 +1347,7 @@ true</pre>
</func>
<func>
- <name name="product" arity="2"/>
+ <name name="product" arity="2" since=""/>
<fsummary>Return the Cartesian product of two sets.</fsummary>
<desc>
<p>Returns the <seealso marker="#Cartesian_product">Cartesian
@@ -1365,7 +1365,7 @@ true</pre>
</func>
<func>
- <name name="projection" arity="2"/>
+ <name name="projection" arity="2" since=""/>
<fsummary>Return a set of substituted elements.</fsummary>
<desc>
<p>Returns the set created by substituting each element of
@@ -1384,7 +1384,7 @@ true</pre>
</func>
<func>
- <name name="range" arity="1"/>
+ <name name="range" arity="1" since=""/>
<fsummary>Return the range of a binary relation.</fsummary>
<desc>
<p>Returns the <seealso marker="#range">range</seealso> of the
@@ -1398,8 +1398,8 @@ true</pre>
</func>
<func>
- <name name="relation" arity="1"/>
- <name name="relation" arity="2"/>
+ <name name="relation" arity="1" since=""/>
+ <name name="relation" arity="2" since=""/>
<fsummary>Create a relation.</fsummary>
<desc>
<p>Creates a <seealso marker="#relation">relation</seealso>.
@@ -1417,7 +1417,7 @@ true</pre>
</func>
<func>
- <name name="relation_to_family" arity="1"/>
+ <name name="relation_to_family" arity="1" since=""/>
<fsummary>Create a family from a binary relation.</fsummary>
<desc>
<p>Returns <seealso marker="#family">family</seealso>
@@ -1435,8 +1435,8 @@ true</pre>
</func>
<func>
- <name name="relative_product" arity="1"/>
- <name name="relative_product" arity="2" clause_i="1"/>
+ <name name="relative_product" arity="1" since=""/>
+ <name name="relative_product" arity="2" clause_i="1" since=""/>
<fsummary>Return the relative product of a list of binary relations
and a binary relation.</fsummary>
<desc>
@@ -1466,7 +1466,7 @@ true</pre>
</func>
<func>
- <name name="relative_product" arity="2" clause_i="2"/>
+ <name name="relative_product" arity="2" clause_i="2" since=""/>
<fsummary>Return the relative product of
two binary relations.</fsummary>
<desc>
@@ -1477,7 +1477,7 @@ true</pre>
</func>
<func>
- <name name="relative_product1" arity="2"/>
+ <name name="relative_product1" arity="2" since=""/>
<fsummary>Return the relative_product of
two binary relations.</fsummary>
<desc>
@@ -1498,7 +1498,7 @@ true</pre>
</func>
<func>
- <name name="restriction" arity="2"/>
+ <name name="restriction" arity="2" since=""/>
<fsummary>Return a restriction of a binary relation.</fsummary>
<desc>
<p>Returns the <seealso marker="#restriction">restriction</seealso> of
@@ -1514,7 +1514,7 @@ true</pre>
</func>
<func>
- <name name="restriction" arity="3"/>
+ <name name="restriction" arity="3" since=""/>
<fsummary>Return a restriction of a set.</fsummary>
<desc>
<p>Returns a subset of <c><anno>Set1</anno></c> containing those
@@ -1530,8 +1530,8 @@ true</pre>
</func>
<func>
- <name name="set" arity="1"/>
- <name name="set" arity="2"/>
+ <name name="set" arity="1" since=""/>
+ <name name="set" arity="2" since=""/>
<fsummary>Create a set of atoms or any type of sets.</fsummary>
<desc>
<p>Creates an <seealso marker="#sets_definition">unordered
@@ -1543,7 +1543,7 @@ true</pre>
</func>
<func>
- <name name="specification" arity="2"/>
+ <name name="specification" arity="2" since=""/>
<fsummary>Select a subset using a predicate.</fsummary>
<desc>
<p>Returns the set containing every element
@@ -1564,7 +1564,7 @@ true</pre>
</func>
<func>
- <name name="strict_relation" arity="1"/>
+ <name name="strict_relation" arity="1" since=""/>
<fsummary>Return the strict relation corresponding to
a given relation.</fsummary>
<desc>
@@ -1580,7 +1580,7 @@ true</pre>
</func>
<func>
- <name name="substitution" arity="2"/>
+ <name name="substitution" arity="2" since=""/>
<fsummary>Return a function with a given set as domain.</fsummary>
<desc>
<p>Returns a function, the domain of which
@@ -1629,7 +1629,7 @@ images2(SetOfSets, BinRel) ->
</func>
<func>
- <name name="symdiff" arity="2"/>
+ <name name="symdiff" arity="2" since=""/>
<fsummary>Return the symmetric difference of two sets.</fsummary>
<desc>
<p>Returns the <seealso marker="#symmetric_difference">symmetric
@@ -1645,7 +1645,7 @@ images2(SetOfSets, BinRel) ->
</func>
<func>
- <name name="symmetric_partition" arity="2"/>
+ <name name="symmetric_partition" arity="2" since=""/>
<fsummary>Return a partition of two sets.</fsummary>
<desc>
<p>Returns a triple of sets:</p>
@@ -1666,7 +1666,7 @@ images2(SetOfSets, BinRel) ->
</func>
<func>
- <name name="to_external" arity="1"/>
+ <name name="to_external" arity="1" since=""/>
<fsummary>Return the elements of a set.</fsummary>
<desc>
<p>Returns the <seealso marker="#external_set">external
@@ -1675,7 +1675,7 @@ images2(SetOfSets, BinRel) ->
</func>
<func>
- <name name="to_sets" arity="1"/>
+ <name name="to_sets" arity="1" since=""/>
<fsummary>Return a list or a tuple of the elements of a set.</fsummary>
<desc>
<p>Returns the elements of the ordered set <c><anno>ASet</anno></c>
@@ -1686,7 +1686,7 @@ images2(SetOfSets, BinRel) ->
</func>
<func>
- <name name="type" arity="1"/>
+ <name name="type" arity="1" since=""/>
<fsummary>Return the type of a set.</fsummary>
<desc>
<p>Returns the <seealso marker="#type">type</seealso> of an
@@ -1695,7 +1695,7 @@ images2(SetOfSets, BinRel) ->
</func>
<func>
- <name name="union" arity="1"/>
+ <name name="union" arity="1" since=""/>
<fsummary>Return the union of a set of sets.</fsummary>
<desc>
<p>Returns the <seealso marker="#union_n">union</seealso> of the
@@ -1704,7 +1704,7 @@ images2(SetOfSets, BinRel) ->
</func>
<func>
- <name name="union" arity="2"/>
+ <name name="union" arity="2" since=""/>
<fsummary>Return the union of two sets.</fsummary>
<desc>
<p>Returns the <seealso marker="#union">union</seealso> of
@@ -1713,7 +1713,7 @@ images2(SetOfSets, BinRel) ->
</func>
<func>
- <name name="union_of_family" arity="1"/>
+ <name name="union_of_family" arity="1" since=""/>
<fsummary>Return the union of a family.</fsummary>
<desc>
<p>Returns the union of <seealso marker="#family">family</seealso>
@@ -1727,7 +1727,7 @@ images2(SetOfSets, BinRel) ->
</func>
<func>
- <name name="weak_relation" arity="1"/>
+ <name name="weak_relation" arity="1" since=""/>
<fsummary>Return the weak relation corresponding to
a given relation.</fsummary>
<desc>
diff --git a/lib/stdlib/doc/src/specs.xml b/lib/stdlib/doc/src/specs.xml
index 45b207b13d..fd2d625685 100644
--- a/lib/stdlib/doc/src/specs.xml
+++ b/lib/stdlib/doc/src/specs.xml
@@ -33,7 +33,6 @@
<xi:include href="../specs/specs_gen_statem.xml"/>
<xi:include href="../specs/specs_io.xml"/>
<xi:include href="../specs/specs_io_lib.xml"/>
- <xi:include href="../specs/specs_lib.xml"/>
<xi:include href="../specs/specs_lists.xml"/>
<xi:include href="../specs/specs_log_mf_h.xml"/>
<xi:include href="../specs/specs_maps.xml"/>
@@ -60,6 +59,7 @@
<xi:include href="../specs/specs_sys.xml"/>
<xi:include href="../specs/specs_timer.xml"/>
<xi:include href="../specs/specs_unicode.xml"/>
+ <xi:include href="../specs/specs_uri_string.xml"/>
<xi:include href="../specs/specs_win32reg.xml"/>
<xi:include href="../specs/specs_zip.xml"/>
</specs>
diff --git a/lib/stdlib/doc/src/string.xml b/lib/stdlib/doc/src/string.xml
index 9d5edd9ecf..d102191a57 100644
--- a/lib/stdlib/doc/src/string.xml
+++ b/lib/stdlib/doc/src/string.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>string.xml</file>
</header>
- <module>string</module>
+ <module since="">string</module>
<modulesummary>String processing functions.</modulesummary>
<description>
<p>This module provides functions for string processing.</p>
@@ -111,8 +111,8 @@
<c>unicode:chardata()</c></seealso> and operate on grapheme
clusters. The <seealso marker="#oldapi"> <c>old
functions</c></seealso> that only work on Latin-1 lists as input
- are still available but should not be
- used. They will be deprecated in Erlang/OTP 21.
+ are still available but should not be used, they will be
+ deprecated in a future release.
</p>
</description>
@@ -130,7 +130,7 @@
<funcs>
<func>
- <name name="casefold" arity="1"/>
+ <name name="casefold" arity="1" since="OTP 20.0"/>
<fsummary>Convert a string to a comparable string.</fsummary>
<desc>
<p>
@@ -147,7 +147,7 @@
</func>
<func>
- <name name="chomp" arity="1"/>
+ <name name="chomp" arity="1" since="OTP 20.0"/>
<fsummary>Remove trailing end of line control characters.</fsummary>
<desc>
<p>
@@ -164,9 +164,9 @@
</func>
<func>
- <name name="equal" arity="2"/>
- <name name="equal" arity="3"/>
- <name name="equal" arity="4"/>
+ <name name="equal" arity="2" since=""/>
+ <name name="equal" arity="3" since="OTP 20.0"/>
+ <name name="equal" arity="4" since="OTP 20.0"/>
<fsummary>Test string equality.</fsummary>
<desc>
<p>
@@ -201,8 +201,8 @@ true</pre>
</func>
<func>
- <name name="find" arity="2"/>
- <name name="find" arity="3"/>
+ <name name="find" arity="2" since="OTP 20.0"/>
+ <name name="find" arity="3" since="OTP 20.0"/>
<fsummary>Find start of substring.</fsummary>
<desc>
<p>
@@ -230,7 +230,7 @@ nomatch</pre>
</func>
<func>
- <name name="is_empty" arity="1"/>
+ <name name="is_empty" arity="1" since="OTP 20.0"/>
<fsummary>Check if the string is empty.</fsummary>
<desc>
<p>Returns <c>true</c> if <c><anno>String</anno></c> is the
@@ -245,7 +245,7 @@ true</pre>
</func>
<func>
- <name name="length" arity="1"/>
+ <name name="length" arity="1" since="OTP 20.0"/>
<fsummary>Calculate length of the string.</fsummary>
<desc>
<p>
@@ -261,7 +261,7 @@ true</pre>
</func>
<func>
- <name name="lexemes" arity="2"/>
+ <name name="lexemes" arity="2" since="OTP 20.0"/>
<fsummary>Split string into lexemes.</fsummary>
<desc>
<p>
@@ -287,7 +287,7 @@ true</pre>
</func>
<func>
- <name name="lowercase" arity="1"/>
+ <name name="lowercase" arity="1" since="OTP 20.0"/>
<fsummary>Convert a string to lowercase</fsummary>
<desc>
<p>
@@ -306,7 +306,7 @@ true</pre>
</func>
<func>
- <name name="next_codepoint" arity="1"/>
+ <name name="next_codepoint" arity="1" since="OTP 20.0"/>
<fsummary>Pick the first codepoint.</fsummary>
<desc>
<p>
@@ -323,7 +323,7 @@ true</pre>
</func>
<func>
- <name name="next_grapheme" arity="1"/>
+ <name name="next_grapheme" arity="1" since="OTP 20.0"/>
<fsummary>Pick the first grapheme cluster.</fsummary>
<desc>
<p>
@@ -340,7 +340,7 @@ true</pre>
</func>
<func>
- <name name="nth_lexeme" arity="3"/>
+ <name name="nth_lexeme" arity="3" since="OTP 20.0"/>
<fsummary>Pick the nth lexeme.</fsummary>
<desc>
<p>Returns lexeme number <c><anno>N</anno></c> in
@@ -355,9 +355,9 @@ true</pre>
</func>
<func>
- <name name="pad" arity="2"/>
- <name name="pad" arity="3"/>
- <name name="pad" arity="4"/>
+ <name name="pad" arity="2" since="OTP 20.0"/>
+ <name name="pad" arity="3" since="OTP 20.0"/>
+ <name name="pad" arity="4" since="OTP 20.0"/>
<fsummary>Pad a string to given length.</fsummary>
<desc>
<p>
@@ -381,7 +381,7 @@ true</pre>
</func>
<func>
- <name name="prefix" arity="2"/>
+ <name name="prefix" arity="2" since="OTP 20.0"/>
<fsummary>Remove prefix from string.</fsummary>
<desc>
<p>
@@ -400,8 +400,8 @@ nomatch</pre>
</func>
<func>
- <name name="replace" arity="3"/>
- <name name="replace" arity="4"/>
+ <name name="replace" arity="3" since="OTP 20.0"/>
+ <name name="replace" arity="4" since="OTP 20.0"/>
<fsummary>Replace a pattern in string.</fsummary>
<desc>
<p>
@@ -423,7 +423,7 @@ nomatch</pre>
</func>
<func>
- <name name="reverse" arity="1"/>
+ <name name="reverse" arity="1" since="OTP 20.0"/>
<fsummary>Reverses a string</fsummary>
<desc>
<p>
@@ -439,8 +439,8 @@ ÖÄÅ</pre>
</func>
<func>
- <name name="slice" arity="2"/>
- <name name="slice" arity="3"/>
+ <name name="slice" arity="2" since="OTP 20.0"/>
+ <name name="slice" arity="3" since="OTP 20.0"/>
<fsummary>Extract a part of string</fsummary>
<desc>
<p>Returns a substring of <c><anno>String</anno></c> of
@@ -459,8 +459,8 @@ ÖÄÅ</pre>
</func>
<func>
- <name name="split" arity="2"/>
- <name name="split" arity="3"/>
+ <name name="split" arity="2" since="OTP 20.0"/>
+ <name name="split" arity="3" since="OTP 20.0"/>
<fsummary>Split a string into substrings.</fsummary>
<desc>
<p>
@@ -482,9 +482,9 @@ ÖÄÅ</pre>
</func>
<func>
- <name name="take" arity="2"/>
- <name name="take" arity="3"/>
- <name name="take" arity="4"/>
+ <name name="take" arity="2" since="OTP 20.0"/>
+ <name name="take" arity="3" since="OTP 20.0"/>
+ <name name="take" arity="4" since="OTP 20.0"/>
<fsummary>Take leading or trailing parts.</fsummary>
<desc>
<p>Takes characters from <c><anno>String</anno></c> as long as
@@ -508,7 +508,7 @@ ÖÄÅ</pre>
</func>
<func>
- <name name="titlecase" arity="1"/>
+ <name name="titlecase" arity="1" since="OTP 20.0"/>
<fsummary>Convert a string to titlecase.</fsummary>
<desc>
<p>
@@ -522,7 +522,7 @@ ÖÄÅ</pre>
</func>
<func>
- <name name="to_float" arity="1"/>
+ <name name="to_float" arity="1" since=""/>
<fsummary>Return a float whose text representation is the integers
(ASCII values) of a string.</fsummary>
<desc>
@@ -544,7 +544,7 @@ ÖÄÅ</pre>
</func>
<func>
- <name name="to_integer" arity="1"/>
+ <name name="to_integer" arity="1" since=""/>
<fsummary>Return an integer whose text representation is the integers
(ASCII values) of a string.</fsummary>
<desc>
@@ -566,7 +566,7 @@ ÖÄÅ</pre>
</func>
<func>
- <name name="to_graphemes" arity="1"/>
+ <name name="to_graphemes" arity="1" since="OTP 20.0"/>
<fsummary>Convert a string to a list of grapheme clusters.</fsummary>
<desc>
<p>
@@ -582,9 +582,9 @@ ÖÄÅ</pre>
</func>
<func>
- <name name="trim" arity="1"/>
- <name name="trim" arity="2"/>
- <name name="trim" arity="3"/>
+ <name name="trim" arity="1" since="OTP 20.0"/>
+ <name name="trim" arity="2" since="OTP 20.0"/>
+ <name name="trim" arity="3" since="OTP 20.0"/>
<fsummary>Trim leading or trailing, or both, characters.</fsummary>
<desc>
<p>
@@ -594,7 +594,7 @@ ÖÄÅ</pre>
or <c>both</c>, indicates from which direction characters
are to be removed.
</p>
- <p> Default <c><anno>Characters</anno></c> are the set of
+ <p> Default <c><anno>Characters</anno></c> is the set of
nonbreakable whitespace codepoints, defined as
Pattern_White_Space in
<url href="http://unicode.org/reports/tr31/">Unicode Standard Annex #31</url>.
@@ -616,7 +616,7 @@ ÖÄÅ</pre>
</func>
<func>
- <name name="uppercase" arity="1"/>
+ <name name="uppercase" arity="1" since="OTP 20.0"/>
<fsummary>Convert a string to uppercase.</fsummary>
<desc>
<p>
@@ -641,7 +641,7 @@ ÖÄÅ</pre>
<note><p>
The functions are kept for backward compatibility, but are
not recommended.
- They will be deprecated in Erlang/OTP 21.
+ They will be deprecated in a future release.
</p>
<p>Any undocumented functions in <c>string</c> are not to be used.</p>
</note>
@@ -649,8 +649,8 @@ ÖÄÅ</pre>
<funcs>
<func>
- <name name="centre" arity="2"/>
- <name name="centre" arity="3"/>
+ <name name="centre" arity="2" since=""/>
+ <name name="centre" arity="3" since=""/>
<fsummary>Center a string.</fsummary>
<desc>
<p>Returns a string, where <c><anno>String</anno></c> is centered in the
@@ -664,8 +664,8 @@ ÖÄÅ</pre>
</func>
<func>
- <name name="chars" arity="2"/>
- <name name="chars" arity="3"/>
+ <name name="chars" arity="2" since=""/>
+ <name name="chars" arity="3" since=""/>
<fsummary>Return a string consisting of numbers of characters.</fsummary>
<desc>
<p>Returns a string consisting of <c><anno>Number</anno></c> characters
@@ -678,7 +678,7 @@ ÖÄÅ</pre>
</func>
<func>
- <name name="chr" arity="2"/>
+ <name name="chr" arity="2" since=""/>
<fsummary>Return the index of the first occurrence of
a character in a string.</fsummary>
<desc>
@@ -692,7 +692,7 @@ ÖÄÅ</pre>
</func>
<func>
- <name name="concat" arity="2"/>
+ <name name="concat" arity="2" since=""/>
<fsummary>Concatenate two strings.</fsummary>
<desc>
<p>Concatenates <c><anno>String1</anno></c> and
@@ -712,7 +712,7 @@ ÖÄÅ</pre>
</func>
<func>
- <name name="copies" arity="2"/>
+ <name name="copies" arity="2" since=""/>
<fsummary>Copy a string.</fsummary>
<desc>
<p>Returns a string containing <c><anno>String</anno></c> repeated
@@ -724,7 +724,7 @@ ÖÄÅ</pre>
</func>
<func>
- <name name="cspan" arity="2"/>
+ <name name="cspan" arity="2" since=""/>
<fsummary>Span characters at start of a string.</fsummary>
<desc>
<p>Returns the length of the maximum initial segment of
@@ -741,7 +741,7 @@ ÖÄÅ</pre>
</func>
<func>
- <name name="join" arity="2"/>
+ <name name="join" arity="2" since=""/>
<fsummary>Join a list of strings with separator.</fsummary>
<desc>
<p>Returns a string with the elements of <c><anno>StringList</anno></c>
@@ -757,8 +757,8 @@ ÖÄÅ</pre>
</func>
<func>
- <name name="left" arity="2"/>
- <name name="left" arity="3"/>
+ <name name="left" arity="2" since=""/>
+ <name name="left" arity="3" since=""/>
<fsummary>Adjust left end of a string.</fsummary>
<desc>
<p>Returns <c><anno>String</anno></c> with the length adjusted in
@@ -778,7 +778,7 @@ ÖÄÅ</pre>
</func>
<func>
- <name name="len" arity="1"/>
+ <name name="len" arity="1" since=""/>
<fsummary>Return the length of a string.</fsummary>
<desc>
<p>Returns the number of characters in <c><anno>String</anno></c>.</p>
@@ -789,7 +789,7 @@ ÖÄÅ</pre>
</func>
<func>
- <name name="rchr" arity="2"/>
+ <name name="rchr" arity="2" since=""/>
<fsummary>Return the index of the last occurrence of
a character in a string.</fsummary>
<desc>
@@ -803,8 +803,8 @@ ÖÄÅ</pre>
</func>
<func>
- <name name="right" arity="2"/>
- <name name="right" arity="3"/>
+ <name name="right" arity="2" since=""/>
+ <name name="right" arity="3" since=""/>
<fsummary>Adjust right end of a string.</fsummary>
<desc>
<p>Returns <c><anno>String</anno></c> with the length adjusted in
@@ -823,7 +823,7 @@ ÖÄÅ</pre>
</func>
<func>
- <name name="rstr" arity="2"/>
+ <name name="rstr" arity="2" since=""/>
<fsummary>Find the index of a substring.</fsummary>
<desc>
<p>Returns the position where the last occurrence of
@@ -841,7 +841,7 @@ ÖÄÅ</pre>
</func>
<func>
- <name name="span" arity="2"/>
+ <name name="span" arity="2" since=""/>
<fsummary>Span characters at start of a string.</fsummary>
<desc>
<p>Returns the length of the maximum initial segment of
@@ -858,7 +858,7 @@ ÖÄÅ</pre>
</func>
<func>
- <name name="str" arity="2"/>
+ <name name="str" arity="2" since=""/>
<fsummary>Find the index of a substring.</fsummary>
<desc>
<p>Returns the position where the first occurrence of
@@ -876,9 +876,9 @@ ÖÄÅ</pre>
</func>
<func>
- <name name="strip" arity="1"/>
- <name name="strip" arity="2"/>
- <name name="strip" arity="3"/>
+ <name name="strip" arity="1" since=""/>
+ <name name="strip" arity="2" since=""/>
+ <name name="strip" arity="3" since=""/>
<fsummary>Strip leading or trailing characters.</fsummary>
<desc>
<p>Returns a string, where leading or trailing, or both, blanks or a
@@ -898,8 +898,8 @@ ÖÄÅ</pre>
</func>
<func>
- <name name="sub_string" arity="2"/>
- <name name="sub_string" arity="3"/>
+ <name name="sub_string" arity="2" since=""/>
+ <name name="sub_string" arity="3" since=""/>
<fsummary>Extract a substring.</fsummary>
<desc>
<p>Returns a substring of <c><anno>String</anno></c>, starting at
@@ -916,8 +916,8 @@ sub_string("Hello World", 4, 8).
</func>
<func>
- <name name="substr" arity="2"/>
- <name name="substr" arity="3"/>
+ <name name="substr" arity="2" since=""/>
+ <name name="substr" arity="3" since=""/>
<fsummary>Return a substring of a string.</fsummary>
<desc>
<p>Returns a substring of <c><anno>String</anno></c>, starting at
@@ -934,8 +934,8 @@ sub_string("Hello World", 4, 8).
</func>
<func>
- <name name="sub_word" arity="2"/>
- <name name="sub_word" arity="3"/>
+ <name name="sub_word" arity="2" since=""/>
+ <name name="sub_word" arity="3" since=""/>
<fsummary>Extract subword.</fsummary>
<desc>
<p>Returns the word in position <c><anno>Number</anno></c> of
@@ -952,10 +952,10 @@ sub_string("Hello World", 4, 8).
</func>
<func>
- <name name="to_lower" arity="1" clause_i="1"/>
- <name name="to_lower" arity="1" clause_i="2"/>
- <name name="to_upper" arity="1" clause_i="1"/>
- <name name="to_upper" arity="1" clause_i="2"/>
+ <name name="to_lower" arity="1" clause_i="1" since=""/>
+ <name name="to_lower" arity="1" clause_i="2" since=""/>
+ <name name="to_upper" arity="1" clause_i="1" since=""/>
+ <name name="to_upper" arity="1" clause_i="2" since=""/>
<fsummary>Convert case of string (ISO/IEC 8859-1).</fsummary>
<type variable="String" name_i="1"/>
<type variable="Result" name_i="1"/>
@@ -974,7 +974,7 @@ sub_string("Hello World", 4, 8).
</func>
<func>
- <name name="tokens" arity="2"/>
+ <name name="tokens" arity="2" since=""/>
<fsummary>Split string into tokens.</fsummary>
<desc>
<p>Returns a list of tokens in <c><anno>String</anno></c>, separated
@@ -994,8 +994,8 @@ sub_string("Hello World", 4, 8).
</func>
<func>
- <name name="words" arity="1"/>
- <name name="words" arity="2"/>
+ <name name="words" arity="1" since=""/>
+ <name name="words" arity="2" since=""/>
<fsummary>Count blank separated words.</fsummary>
<desc>
<p>Returns the number of words in <c><anno>String</anno></c>, separated
diff --git a/lib/stdlib/doc/src/supervisor.xml b/lib/stdlib/doc/src/supervisor.xml
index 6d5065ca02..f15b1a2dd3 100644
--- a/lib/stdlib/doc/src/supervisor.xml
+++ b/lib/stdlib/doc/src/supervisor.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>supervisor</module>
+ <module since="">supervisor</module>
<modulesummary>Generic supervisor behavior.</modulesummary>
<description>
<p>This behavior module provides a supervisor, a process that
@@ -208,8 +208,16 @@ child_spec() = #{id => child_id(), % mandatory
the child process is unconditionally terminated using
<c>exit(Child,kill)</c>.</p>
<p>If the child process is another supervisor, the shutdown time
- is to be set to <c>infinity</c> to give the subtree ample
- time to shut down. It is also allowed to set it to <c>infinity</c>,
+ must be set to <c>infinity</c> to give the subtree ample
+ time to shut down.</p>
+ <warning>
+ <p>Setting the shutdown time to anything other
+ than <c>infinity</c> for a child of type <c>supervisor</c>
+ can cause a race condition where the child in question
+ unlinks its own children, but fails to terminate them
+ before it is killed.</p>
+ </warning>
+ <p>It is also allowed to set it to <c>infinity</c>,
if the child process is a worker.</p>
<warning>
<p>Be careful when setting the shutdown time to
@@ -310,7 +318,7 @@ child_spec() = #{id => child_id(), % mandatory
<funcs>
<func>
- <name name="check_childspecs" arity="1"/>
+ <name name="check_childspecs" arity="1" since=""/>
<fsummary>Check if children specifications are syntactically correct.
</fsummary>
<desc>
@@ -321,7 +329,7 @@ child_spec() = #{id => child_id(), % mandatory
</func>
<func>
- <name name="count_children" arity="1"/>
+ <name name="count_children" arity="1" since="OTP R13B04"/>
<fsummary>Return counts for the number of child specifications,
active children, supervisors, and workers.</fsummary>
<desc>
@@ -358,7 +366,7 @@ child_spec() = #{id => child_id(), % mandatory
</func>
<func>
- <name name="delete_child" arity="2"/>
+ <name name="delete_child" arity="2" since=""/>
<fsummary>Delete a child specification from a supervisor.</fsummary>
<desc>
<p>Tells supervisor <c><anno>SupRef</anno></c> to delete the child
@@ -379,7 +387,7 @@ child_spec() = #{id => child_id(), % mandatory
</func>
<func>
- <name name="get_childspec" arity="2"/>
+ <name name="get_childspec" arity="2" since="OTP 18.0"/>
<fsummary>Return the child specification map for the specified
child.</fsummary>
<desc>
@@ -392,7 +400,7 @@ child_spec() = #{id => child_id(), % mandatory
</func>
<func>
- <name name="restart_child" arity="2"/>
+ <name name="restart_child" arity="2" since=""/>
<fsummary>Restart a terminated child process belonging to a supervisor.
</fsummary>
<desc>
@@ -428,7 +436,7 @@ child_spec() = #{id => child_id(), % mandatory
</func>
<func>
- <name name="start_child" arity="2"/>
+ <name name="start_child" arity="2" since=""/>
<fsummary>Dynamically add a child process to a supervisor.</fsummary>
<type name="startchild_ret"/>
<type name="startchild_err"/>
@@ -495,8 +503,8 @@ child_spec() = #{id => child_id(), % mandatory
</func>
<func>
- <name name="start_link" arity="2"/>
- <name name="start_link" arity="3"/>
+ <name name="start_link" arity="2" since=""/>
+ <name name="start_link" arity="3" since=""/>
<fsummary>Create a supervisor process.</fsummary>
<type name="startlink_ret"/>
<type name="startlink_err"/>
@@ -576,7 +584,7 @@ child_spec() = #{id => child_id(), % mandatory
</func>
<func>
- <name name="terminate_child" arity="2"/>
+ <name name="terminate_child" arity="2" since=""/>
<fsummary>Terminate a child process belonging to a supervisor.</fsummary>
<desc>
<p>Tells supervisor <c><anno>SupRef</anno></c> to terminate the
@@ -613,7 +621,7 @@ child_spec() = #{id => child_id(), % mandatory
</func>
<func>
- <name name="which_children" arity="1"/>
+ <name name="which_children" arity="1" since=""/>
<fsummary>Return information about all children specifications and
child processes belonging to a supervisor.</fsummary>
<desc>
@@ -658,7 +666,7 @@ child_spec() = #{id => child_id(), % mandatory
<funcs>
<func>
- <name>Module:init(Args) -> Result</name>
+ <name since="">Module:init(Args) -> Result</name>
<fsummary>Return a supervisor specification.</fsummary>
<type>
<v>Args = term()</v>
diff --git a/lib/stdlib/doc/src/supervisor_bridge.xml b/lib/stdlib/doc/src/supervisor_bridge.xml
index c4c1b37548..ee5d97fea1 100644
--- a/lib/stdlib/doc/src/supervisor_bridge.xml
+++ b/lib/stdlib/doc/src/supervisor_bridge.xml
@@ -30,7 +30,7 @@
<date></date>
<rev></rev>
</header>
- <module>supervisor_bridge</module>
+ <module since="">supervisor_bridge</module>
<modulesummary>Generic supervisor bridge behavior.</modulesummary>
<description>
<p>This behavior module provides a supervisor bridge, a process
@@ -57,8 +57,8 @@
<funcs>
<func>
- <name name="start_link" arity="2"/>
- <name name="start_link" arity="3"/>
+ <name name="start_link" arity="2" since=""/>
+ <name name="start_link" arity="3" since=""/>
<fsummary>Create a supervisor bridge process.</fsummary>
<desc>
<p>Creates a supervisor bridge process, linked to the calling process,
@@ -133,7 +133,7 @@
<funcs>
<func>
- <name>Module:init(Args) -> Result</name>
+ <name since="">Module:init(Args) -> Result</name>
<fsummary>Initialize process and start subsystem.</fsummary>
<type>
<v>Args = term()</v>
@@ -164,7 +164,7 @@
</func>
<func>
- <name>Module:terminate(Reason, State)</name>
+ <name since="">Module:terminate(Reason, State)</name>
<fsummary>Clean up and stop subsystem.</fsummary>
<type>
<v>Reason = shutdown | term()</v>
diff --git a/lib/stdlib/doc/src/sys.xml b/lib/stdlib/doc/src/sys.xml
index 64d8789016..e22ca89ef5 100644
--- a/lib/stdlib/doc/src/sys.xml
+++ b/lib/stdlib/doc/src/sys.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2019</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,7 +32,7 @@
<rev></rev>
<file>sys.xml</file>
</header>
- <module>sys</module>
+ <module since="">sys</module>
<modulesummary>A functional interface to system messages.</modulesummary>
<description>
<p>This module contains functions for sending system messages used by
@@ -102,7 +102,7 @@
then treated in the debug function. For example, <c>trace</c>
formats the system events to the terminal.
</p>
- <p>Three predefined system events are used when a
+ <p>Four predefined system events are used when a
process receives or sends a message. The process can also define its
own system events. It is always up to the process itself
to format these events.</p>
@@ -114,6 +114,154 @@
</datatype>
<datatype>
<name name="system_event"/>
+ <desc>
+ <taglist>
+ <tag><c>{in,<anno>Msg</anno>}</c></tag>
+ <item>
+ <p>
+ Is produced by <c>gen_server</c> and <c>gen_event</c>
+ when the message <c>Msg</c> arrives.
+ </p>
+ </item>
+ <tag><c>{in,<anno>Msg</anno>,<anno>State</anno>}</c></tag>
+ <item>
+ <p>
+ Is produced by <c>gen_statem</c>
+ when the message <c>Msg</c> arrives in state <c>State</c>.
+ </p>
+ <p>
+ For <c>gen_statem</c> the <c><anno>Msg</anno></c> term is
+ an <c>{EventType,EventContent}</c> tuple.
+ </p>
+ </item>
+ <tag><c>{out,<anno>Msg</anno>,<anno>To</anno>}</c></tag>
+ <item>
+ <p>
+ Is produced by <c>gen_statem</c> when the reply <c>Msg</c>
+ is sent back to <c>To</c> by returning
+ a <c>{reply,To,Msg}</c> action from the callback module.
+ </p>
+ <p>
+ <c><anno>To</anno></c> is of the same type
+ as the first argument to <c>gen_statem:reply/2</c>.
+ </p>
+ </item>
+ <tag>
+ <c>{out,<anno>Msg</anno>,<anno>To</anno>,<anno>State</anno>}</c>
+ </tag>
+ <item>
+ <p>
+ Is produced by <c>gen_server</c>
+ when the reply <c><anno>Msg</anno></c>
+ is sent back to <c><anno>To</anno></c>
+ by returning a <c>{reply,...}</c> tuple
+ from the callback module.
+ </p>
+ <p>
+ <c><anno>To</anno></c> is of the same type
+ as the first argument to <c>gen_server:reply/2</c>.
+ </p>
+ <p>
+ <c><anno>State</anno></c> is the new server state.
+ </p>
+ </item>
+ <tag>
+ <c>{noreply,<anno>State</anno>}</c>
+ </tag>
+ <item>
+ <p>
+ Is produced by <c>gen_server</c>
+ when a <c>{noreply,...}</c> tuple is returned
+ from the callback module.
+ </p>
+ <p>
+ <c><anno>State</anno></c> is the new server state.
+ </p>
+ </item>
+ <tag>
+ <c>{continue,<anno>Continuation</anno>}</c>
+ </tag>
+ <item>
+ <p>
+ Is produced by <c>gen_server</c>
+ when a <c>{continue,<anno>Continuation</anno>}</c>
+ tuple is returned from the callback module.
+ </p>
+ </item>
+ <tag>
+ <c>{code_change,<anno>Event</anno>,<anno>State</anno>}</c>
+ </tag>
+ <item>
+ <p>
+ Is produced by <c>gen_statem</c>
+ when the message <c><anno>Event</anno></c>
+ arrives in state <c><anno>State</anno></c>
+ as the first event after a code change.
+ </p>
+ <p>
+ <c><anno>Event</anno></c> is
+ an <c>{EventType,EventContent}</c> tuple.
+ </p>
+ </item>
+ <tag>
+ <c>
+ {postpone,<anno>Event</anno>,<anno>State</anno>,<anno>NextState</anno>}
+ </c>
+ </tag>
+ <item>
+ <p>
+ Is produced by <c>gen_statem</c>
+ when the message <c><anno>Event</anno></c>
+ is postponed in state <c><anno>State</anno></c>.
+ <c><anno>NextState</anno></c> is the new state.
+ </p>
+ <p>
+ <c><anno>Event</anno></c> is
+ an <c>{EventType,EventContent}</c> tuple.
+ </p>
+ </item>
+ <tag>
+ <c>
+ {consume,<anno>Event</anno>,<anno>State</anno>,<anno>NextState</anno>}
+ </c>
+ </tag>
+ <item>
+ <p>
+ Is produced by <c>gen_statem</c>
+ when the message <c><anno>Event</anno></c>
+ is consumed in state <c><anno>State</anno></c>.
+ <c><anno>NextState</anno></c> is the new state.
+ </p>
+ <p>
+ <c><anno>Event</anno></c> is
+ an <c>{EventType,EventContent}</c> tuple.
+ </p>
+ </item>
+ <tag>
+ <c>
+ {enter,<anno>State</anno>}
+ </c>
+ </tag>
+ <item>
+ <p>
+ Is produced by <c>gen_statem</c>
+ when the first state <c><anno>State</anno></c> is entered.
+ </p>
+ </item>
+ <tag>
+ <c>
+ {terminate,<anno>Reason</anno>,<anno>State</anno>}
+ </c>
+ </tag>
+ <item>
+ <p>
+ Is produced by <c>gen_statem</c>
+ when it terminates with reason <c><anno>Reason</anno></c>
+ in state <c><anno>State</anno></c>.
+ </p>
+ </item>
+ </taglist>
+ </desc>
</datatype>
<datatype>
<name name="dbg_opt"/>
@@ -123,14 +271,17 @@
<name name="dbg_fun"/>
</datatype>
<datatype>
+ <name name="debug_option"/>
+ </datatype>
+ <datatype>
<name name="format_fun"/>
</datatype>
</datatypes>
<funcs>
<func>
- <name name="change_code" arity="4"/>
- <name name="change_code" arity="5"/>
+ <name name="change_code" arity="4" since=""/>
+ <name name="change_code" arity="5" since=""/>
<fsummary>Send the code change system message to the process.</fsummary>
<desc>
<p>Tells the process to change code. The process must be
@@ -143,8 +294,8 @@
</func>
<func>
- <name name="get_state" arity="1"/>
- <name name="get_state" arity="2"/>
+ <name name="get_state" arity="1" since="OTP R16B01"/>
+ <name name="get_state" arity="2" since="OTP R16B01"/>
<fsummary>Get the state of the process.</fsummary>
<desc>
<p>Gets the state of the process.</p>
@@ -227,8 +378,8 @@
</func>
<func>
- <name name="get_status" arity="1"/>
- <name name="get_status" arity="2"/>
+ <name name="get_status" arity="1" since=""/>
+ <name name="get_status" arity="2" since=""/>
<fsummary>Get the status of the process.</fsummary>
<desc>
<p>Gets the status of the process.</p>
@@ -265,8 +416,8 @@
</func>
<func>
- <name name="install" arity="2"/>
- <name name="install" arity="3"/>
+ <name name="install" arity="2" since=""/>
+ <name name="install" arity="3" since=""/>
<fsummary>Install a debug function in the process.</fsummary>
<desc>
<p>Enables installation of alternative debug functions. An example of
@@ -276,13 +427,15 @@
<p><c><anno>Func</anno></c> is called whenever a system event is
generated. This function is to return <c>done</c>, or a new
<c>Func</c> state. In the first case, the function is removed. It is
- also removed if the function fails.</p>
+ also removed if the function fails. If one debug function should be
+ installed more times, a unique <c><anno>FuncId</anno></c> must be
+ specified for each installation.</p>
</desc>
</func>
<func>
- <name name="log" arity="2"/>
- <name name="log" arity="3"/>
+ <name name="log" arity="2" since=""/>
+ <name name="log" arity="3" since=""/>
<fsummary>Log system events in memory.</fsummary>
<desc>
<p>Turns the logging of system events on or off. If on, a
@@ -300,8 +453,8 @@
</func>
<func>
- <name name="log_to_file" arity="2"/>
- <name name="log_to_file" arity="3"/>
+ <name name="log_to_file" arity="2" since=""/>
+ <name name="log_to_file" arity="3" since=""/>
<fsummary>Log system events to the specified file.</fsummary>
<desc>
<p>Enables or disables the logging of all system events in text
@@ -313,8 +466,8 @@
</func>
<func>
- <name name="no_debug" arity="1"/>
- <name name="no_debug" arity="2"/>
+ <name name="no_debug" arity="1" since=""/>
+ <name name="no_debug" arity="2" since=""/>
<fsummary>Turn off debugging.</fsummary>
<desc>
<p>Turns off all debugging for the process. This includes
@@ -325,19 +478,19 @@
</func>
<func>
- <name name="remove" arity="2"/>
- <name name="remove" arity="3"/>
+ <name name="remove" arity="2" since=""/>
+ <name name="remove" arity="3" since=""/>
<fsummary>Remove a debug function from the process.</fsummary>
<desc>
<p>Removes an installed debug function from the
- process. <c><anno>Func</anno></c> must be the same as previously
- installed.</p>
+ process. <c><anno>Func</anno></c> or <c><anno>FuncId</anno></c> must be
+ the same as previously installed.</p>
</desc>
</func>
<func>
- <name name="replace_state" arity="2"/>
- <name name="replace_state" arity="3"/>
+ <name name="replace_state" arity="2" since="OTP R16B01"/>
+ <name name="replace_state" arity="3" since="OTP R16B01"/>
<fsummary>Replace the state of the process.</fsummary>
<desc>
<p>Replaces the state of the process, and returns the new state.</p>
@@ -449,8 +602,8 @@
</func>
<func>
- <name name="resume" arity="1"/>
- <name name="resume" arity="2"/>
+ <name name="resume" arity="1" since=""/>
+ <name name="resume" arity="2" since=""/>
<fsummary>Resume a suspended process.</fsummary>
<desc>
<p>Resumes a suspended process.</p>
@@ -458,8 +611,8 @@
</func>
<func>
- <name name="statistics" arity="2"/>
- <name name="statistics" arity="3"/>
+ <name name="statistics" arity="2" since=""/>
+ <name name="statistics" arity="3" since=""/>
<fsummary>Enable or disable the collections of statistics.</fsummary>
<desc>
<p>Enables or disables the collection of statistics. If
@@ -469,8 +622,8 @@
</func>
<func>
- <name name="suspend" arity="1"/>
- <name name="suspend" arity="2"/>
+ <name name="suspend" arity="1" since=""/>
+ <name name="suspend" arity="2" since=""/>
<fsummary>Suspend the process.</fsummary>
<desc>
<p>Suspends the process. When the process is suspended, it
@@ -480,8 +633,8 @@
</func>
<func>
- <name name="terminate" arity="2"/>
- <name name="terminate" arity="3"/>
+ <name name="terminate" arity="2" since="OTP 18.0"/>
+ <name name="terminate" arity="3" since="OTP 18.0"/>
<fsummary>Terminate the process.</fsummary>
<desc>
<p>Orders the process to terminate with the
@@ -492,8 +645,8 @@
</func>
<func>
- <name name="trace" arity="2"/>
- <name name="trace" arity="3"/>
+ <name name="trace" arity="2" since=""/>
+ <name name="trace" arity="3" since=""/>
<fsummary>Print all system events on <c>standard_io</c>.</fsummary>
<desc>
<p>Prints all system events on <c>standard_io</c>. The events are
@@ -516,7 +669,7 @@
<funcs>
<func>
- <name name="debug_options" arity="1"/>
+ <name name="debug_options" arity="1" since=""/>
<fsummary>Convert a list of options to a debug structure.</fsummary>
<desc>
<p>Can be used by a process that initiates a debug
@@ -527,9 +680,15 @@
</func>
<func>
- <name name="get_debug" arity="3"/>
+ <name name="get_debug" arity="3" since=""/>
<fsummary>Get the data associated with a debug option.</fsummary>
<desc>
+ <warning>
+ <p>
+ <c>get_debug/3</c> is deprecated since it returns
+ data of an internal type only useful for debugging.
+ </p>
+ </warning>
<p>Gets the data associated with a debug option.
<c><anno>Default</anno></c>
is returned if <c><anno>Item</anno></c> is not found. Can be
@@ -539,7 +698,7 @@
</func>
<func>
- <name name="handle_debug" arity="4"/>
+ <name name="handle_debug" arity="4" since=""/>
<fsummary>Generate a system event.</fsummary>
<desc>
<p>This function is called by a process when it generates a
@@ -554,7 +713,7 @@
</func>
<func>
- <name name="handle_system_msg" arity="6"/>
+ <name name="handle_system_msg" arity="6" since=""/>
<fsummary>Take care of system messages.</fsummary>
<desc>
<p>This function is used by a process module to take care of system
@@ -592,7 +751,7 @@
</func>
<func>
- <name name="print_log" arity="1"/>
+ <name name="print_log" arity="1" since=""/>
<fsummary>Print the logged events in the debug structure.</fsummary>
<desc>
<p>Prints the logged system events in the debug structure,
@@ -603,7 +762,19 @@
</func>
<func>
- <name>Module:system_code_change(Misc, Module, OldVsn, Extra) ->
+ <name name="get_log" arity="1" since="OTP-22.0"/>
+ <fsummary>Return the logged events in the debug structure.</fsummary>
+ <desc>
+ <p>
+ Returns the logged system events in the debug structure,
+ that is the last argument to
+ <seealso marker="#handle_debug/4"><c>handle_debug/4</c></seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">Module:system_code_change(Misc, Module, OldVsn, Extra) ->
{ok, NMisc}</name>
<fsummary>Called when the process is to perform a code change.</fsummary>
<type>
@@ -626,7 +797,7 @@
</func>
<func>
- <name>Module:system_continue(Parent, Debug, Misc) -> none()</name>
+ <name since="">Module:system_continue(Parent, Debug, Misc) -> none()</name>
<fsummary>Called when the process is to continue its execution.</fsummary>
<type>
<v>Parent = pid()</v>
@@ -642,7 +813,7 @@
</func>
<func>
- <name>Module:system_get_state(Misc) -> {ok, State}</name>
+ <name since="OTP 17.0">Module:system_get_state(Misc) -> {ok, State}</name>
<fsummary>Called when the process is to return its current state.
</fsummary>
<type>
@@ -659,7 +830,7 @@
</func>
<func>
- <name>Module:system_replace_state(StateFun, Misc) ->
+ <name since="OTP 17.0">Module:system_replace_state(StateFun, Misc) ->
{ok, NState, NMisc}</name>
<fsummary>Called when the process is to replace its current state.
</fsummary>
@@ -679,7 +850,7 @@
</func>
<func>
- <name>Module:system_terminate(Reason, Parent, Debug, Misc) -> none()</name>
+ <name since="">Module:system_terminate(Reason, Parent, Debug, Misc) -> none()</name>
<fsummary>Called when the process is to terminate.</fsummary>
<type>
<v>Reason = term()</v>
diff --git a/lib/stdlib/doc/src/timer.xml b/lib/stdlib/doc/src/timer.xml
index 350847bf7d..165eecfbb0 100644
--- a/lib/stdlib/doc/src/timer.xml
+++ b/lib/stdlib/doc/src/timer.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,7 +32,7 @@
<rev>D</rev>
<file>timer.xml</file>
</header>
- <module>timer</module>
+ <module since="">timer</module>
<modulesummary>Timer functions.</modulesummary>
<description>
<p>This module provides useful functions related to time. Unless otherwise
@@ -62,7 +62,7 @@
<funcs>
<func>
- <name name="apply_after" arity="4"/>
+ <name name="apply_after" arity="4" since=""/>
<fsummary>Apply <c>Module:Function(Arguments)</c> after a specified
<c>Time</c>.</fsummary>
<desc>
@@ -75,7 +75,7 @@
</func>
<func>
- <name name="apply_interval" arity="4"/>
+ <name name="apply_interval" arity="4" since=""/>
<fsummary>Evaluate <c>Module:Function(Arguments)</c> repeatedly at
intervals of <c>Time</c>.</fsummary>
<desc>
@@ -88,7 +88,7 @@
</func>
<func>
- <name name="cancel" arity="1"/>
+ <name name="cancel" arity="1" since=""/>
<fsummary>Cancel a previously requested time-out identified by
<c>TRef</c>.</fsummary>
<desc>
@@ -101,8 +101,8 @@
</func>
<func>
- <name name="exit_after" arity="2"/>
- <name name="exit_after" arity="3"/>
+ <name name="exit_after" arity="2" since=""/>
+ <name name="exit_after" arity="3" since=""/>
<fsummary>Send an exit signal with <c>Reason</c> after a specified
<c>Time</c>.</fsummary>
<desc>
@@ -117,7 +117,7 @@
</func>
<func>
- <name name="hms" arity="3"/>
+ <name name="hms" arity="3" since=""/>
<fsummary>Convert <c>Hours</c>+<c>Minutes</c>+<c>Seconds</c> to
<c>Milliseconds</c>.</fsummary>
<desc>
@@ -127,7 +127,7 @@
</func>
<func>
- <name name="hours" arity="1"/>
+ <name name="hours" arity="1" since=""/>
<fsummary>Convert <c>Hours</c> to <c>Milliseconds</c>.</fsummary>
<desc>
<p>Returns the number of milliseconds in <c><anno>Hours</anno></c>.</p>
@@ -135,8 +135,8 @@
</func>
<func>
- <name name="kill_after" arity="1"/>
- <name name="kill_after" arity="2"/>
+ <name name="kill_after" arity="1" since=""/>
+ <name name="kill_after" arity="2" since=""/>
<fsummary>Send an exit signal with <c>Reason</c> after a specified
<c>Time</c>.</fsummary>
<desc>
@@ -148,7 +148,7 @@
</func>
<func>
- <name name="minutes" arity="1"/>
+ <name name="minutes" arity="1" since=""/>
<fsummary>Converts <c>Minutes</c> to <c>Milliseconds</c>.</fsummary>
<desc>
<p>Returns the number of milliseconds in
@@ -157,7 +157,7 @@
</func>
<func>
- <name name="now_diff" arity="2"/>
+ <name name="now_diff" arity="2" since=""/>
<fsummary>Calculate time difference between time stamps.</fsummary>
<type_desc variable="Tdiff">In microseconds</type_desc>
<desc>
@@ -173,7 +173,7 @@
</func>
<func>
- <name name="seconds" arity="1"/>
+ <name name="seconds" arity="1" since=""/>
<fsummary>Convert <c>Seconds</c> to <c>Milliseconds</c>.</fsummary>
<desc>
<p>Returns the number of milliseconds in
@@ -182,8 +182,8 @@
</func>
<func>
- <name name="send_after" arity="2"/>
- <name name="send_after" arity="3"/>
+ <name name="send_after" arity="2" since=""/>
+ <name name="send_after" arity="3" since=""/>
<fsummary>Send <c>Message</c> to <c>Pid</c> after a specified
<c>Time</c>.</fsummary>
<desc>
@@ -206,8 +206,8 @@
</func>
<func>
- <name name="send_interval" arity="2"/>
- <name name="send_interval" arity="3"/>
+ <name name="send_interval" arity="2" since=""/>
+ <name name="send_interval" arity="3" since=""/>
<fsummary>Send <c>Message</c> repeatedly at intervals of <c>Time</c>.
</fsummary>
<desc>
@@ -231,7 +231,7 @@
</func>
<func>
- <name name="sleep" arity="1"/>
+ <name name="sleep" arity="1" since=""/>
<fsummary>Suspend the calling process for <c>Time</c> milliseconds.
</fsummary>
<desc>
@@ -244,7 +244,7 @@
</func>
<func>
- <name name="start" arity="0"/>
+ <name name="start" arity="0" since=""/>
<fsummary>Start a global timer server (named <c>timer_server</c>).
</fsummary>
<desc>
@@ -258,9 +258,9 @@
</func>
<func>
- <name name="tc" arity="1"/>
- <name name="tc" arity="2"/>
- <name name="tc" arity="3"/>
+ <name name="tc" arity="1" since="OTP R14B03"/>
+ <name name="tc" arity="2" since="OTP R14B"/>
+ <name name="tc" arity="3" since=""/>
<fsummary>Measure the real time it takes to evaluate <c>apply(Module,
Function, Arguments)</c> or <c>apply(Fun, Arguments)</c>.</fsummary>
<type_desc variable="Time">In microseconds</type_desc>
@@ -270,8 +270,8 @@
<item>
<p>Evaluates <c>apply(<anno>Module</anno>, <anno>Function</anno>,
<anno>Arguments</anno>)</c> and measures the elapsed real time as
- reported by <seealso marker="kernel:os#timestamp/0">
- <c>os:timestamp/0</c></seealso>.</p>
+ reported by <seealso marker="erts:erlang#monotonic_time/0">
+ <c>erlang:monotonic_time/0</c></seealso>.</p>
<p>Returns <c>{<anno>Time</anno>, <anno>Value</anno>}</c>, where
<c><anno>Time</anno></c> is the elapsed real time in
<em>microseconds</em>, and <c><anno>Value</anno></c> is what is
diff --git a/lib/stdlib/doc/src/unicode.xml b/lib/stdlib/doc/src/unicode.xml
index d822aca89c..b7696a4b7e 100644
--- a/lib/stdlib/doc/src/unicode.xml
+++ b/lib/stdlib/doc/src/unicode.xml
@@ -30,7 +30,7 @@
<date></date>
<rev></rev>
</header>
- <module>unicode</module>
+ <module since="">unicode</module>
<modulesummary>Functions for converting Unicode characters.</modulesummary>
<description>
<p>This module contains functions for converting between different character
@@ -139,7 +139,7 @@
<funcs>
<func>
- <name name="bom_to_encoding" arity="1"/>
+ <name name="bom_to_encoding" arity="1" since=""/>
<fsummary>Identify UTF byte order marks in a binary.</fsummary>
<type name="endian"/>
<type_desc variable="Bin">
@@ -156,7 +156,7 @@
</func>
<func>
- <name name="characters_to_binary" arity="1"/>
+ <name name="characters_to_binary" arity="1" since=""/>
<fsummary>Convert a collection of characters to a UTF-8 binary.</fsummary>
<desc>
<p>Same as <c>characters_to_binary(<anno>Data</anno>, unicode,
@@ -165,7 +165,7 @@
</func>
<func>
- <name name="characters_to_binary" arity="2"/>
+ <name name="characters_to_binary" arity="2" since=""/>
<fsummary>Convert a collection of characters to a UTF-8 binary.</fsummary>
<desc>
<p>Same as <c>characters_to_binary(<anno>Data</anno>,
@@ -174,7 +174,7 @@
</func>
<func>
- <name name="characters_to_binary" arity="3"/>
+ <name name="characters_to_binary" arity="3" since=""/>
<fsummary>Convert a collection of characters to a UTF-8 binary.</fsummary>
<desc>
<p>Behaves as <seealso marker="#characters_to_list/2">
@@ -211,7 +211,7 @@
</func>
<func>
- <name name="characters_to_list" arity="1"/>
+ <name name="characters_to_list" arity="1" since=""/>
<fsummary>Convert a collection of characters to a list of Unicode
characters.</fsummary>
<desc>
@@ -220,7 +220,7 @@
</func>
<func>
- <name name="characters_to_list" arity="2"/>
+ <name name="characters_to_list" arity="2" since=""/>
<fsummary>Convert a collection of characters to a list of Unicode
characters.</fsummary>
<desc>
@@ -367,7 +367,7 @@ decode_data(Data) ->
</func>
<func>
- <name name="characters_to_nfc_list" arity="1"/>
+ <name name="characters_to_nfc_list" arity="1" since="OTP 20.0"/>
<fsummary>Normalize characters to a list of canonical equivalent
composed Unicode characters.</fsummary>
<desc>
@@ -386,7 +386,7 @@ decode_data(Data) ->
</func>
<func>
- <name name="characters_to_nfc_binary" arity="1"/>
+ <name name="characters_to_nfc_binary" arity="1" since="OTP 20.0"/>
<fsummary>Normalize characters to a utf8 binary of canonical equivalent
composed Unicode characters.</fsummary>
<desc>
@@ -404,7 +404,7 @@ decode_data(Data) ->
</func>
<func>
- <name name="characters_to_nfd_list" arity="1"/>
+ <name name="characters_to_nfd_list" arity="1" since="OTP 20.0"/>
<fsummary>Normalize characters to a list of canonical equivalent
decomposed Unicode characters.</fsummary>
<desc>
@@ -423,7 +423,7 @@ decode_data(Data) ->
</func>
<func>
- <name name="characters_to_nfd_binary" arity="1"/>
+ <name name="characters_to_nfd_binary" arity="1" since="OTP 20.0"/>
<fsummary>Normalize characters to a utf8 binary of canonical equivalent
decomposed Unicode characters.</fsummary>
<desc>
@@ -441,7 +441,7 @@ decode_data(Data) ->
</func>
<func>
- <name name="characters_to_nfkc_list" arity="1"/>
+ <name name="characters_to_nfkc_list" arity="1" since="OTP 20.0"/>
<fsummary>Normalize characters to a list of canonical equivalent
composed Unicode characters.</fsummary>
<desc>
@@ -460,7 +460,7 @@ decode_data(Data) ->
</func>
<func>
- <name name="characters_to_nfkc_binary" arity="1"/>
+ <name name="characters_to_nfkc_binary" arity="1" since="OTP 20.0"/>
<fsummary>Normalize characters to a utf8 binary of compatibly equivalent
composed Unicode characters.</fsummary>
<desc>
@@ -478,7 +478,7 @@ decode_data(Data) ->
</func>
<func>
- <name name="characters_to_nfkd_list" arity="1"/>
+ <name name="characters_to_nfkd_list" arity="1" since="OTP 20.0"/>
<fsummary>Normalize characters to a list of compatibly equivalent
decomposed Unicode characters.</fsummary>
<desc>
@@ -497,7 +497,7 @@ decode_data(Data) ->
</func>
<func>
- <name name="characters_to_nfkd_binary" arity="1"/>
+ <name name="characters_to_nfkd_binary" arity="1" since="OTP 20.0"/>
<fsummary>Normalize characters to a utf8 binary of compatibly equivalent
decomposed Unicode characters.</fsummary>
<desc>
@@ -515,7 +515,7 @@ decode_data(Data) ->
</func>
<func>
- <name name="encoding_to_bom" arity="1"/>
+ <name name="encoding_to_bom" arity="1" since=""/>
<fsummary>Create a binary UTF byte order mark from encoding.</fsummary>
<type_desc variable="Bin">
A <c>binary()</c> such that <c>byte_size(<anno>Bin</anno>) >= 4</c>.
diff --git a/lib/stdlib/doc/src/unicode_usage.xml b/lib/stdlib/doc/src/unicode_usage.xml
index 26dc46719e..789e063c12 100644
--- a/lib/stdlib/doc/src/unicode_usage.xml
+++ b/lib/stdlib/doc/src/unicode_usage.xml
@@ -719,8 +719,8 @@ Eshell V5.10.1 (abort with ^G)
</section>
<section>
- <title>Unicode Filenames</title>
<marker id="unicode_file_names"/>
+ <title>Unicode Filenames</title>
<p>Most modern operating systems support Unicode filenames in some way.
There are many different ways to do this and Erlang by default treats the
different approaches differently:</p>
@@ -855,8 +855,12 @@ Eshell V5.10.1 (abort with ^G)
</note>
<section>
- <title>Notes About Raw Filenames</title>
<marker id="notes-about-raw-filenames"/>
+ <title>Notes About Raw Filenames</title>
+ <note><p>
+ Note that raw filenames <em>not</em> necessarily are encoded the
+ same way as on the OS level.
+ </p></note>
<p>Raw filenames were introduced together with Unicode filename support
in ERTS 5.8.2 (Erlang/OTP R14B01). The reason &quot;raw
filenames&quot; were introduced in the system was
diff --git a/lib/stdlib/doc/src/uri_string.xml b/lib/stdlib/doc/src/uri_string.xml
new file mode 100644
index 0000000000..ad443486c5
--- /dev/null
+++ b/lib/stdlib/doc/src/uri_string.xml
@@ -0,0 +1,359 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2017</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ </legalnotice>
+
+ <title>uri_string</title>
+ <prepared>Péter Dimitrov</prepared>
+ <docno>1</docno>
+ <date>2018-02-07</date>
+ <rev>A</rev>
+ </header>
+ <module since="OTP 21.0">uri_string</module>
+ <modulesummary>URI processing functions.</modulesummary>
+ <description>
+ <p>This module contains functions for parsing and handling URIs
+ (<url href="https://www.ietf.org/rfc/rfc3986.txt">RFC 3986</url>) and
+ form-urlencoded query strings (<url href="https://www.w3.org/TR/html52/">HTML 5.2</url>).
+ </p>
+ <p>
+ Parsing and serializing non-UTF-8 form-urlencoded query strings are also supported
+ (<url href="https://www.w3.org/TR/html50/">HTML 5.0</url>).
+ </p>
+ <p>A URI is an identifier consisting of a sequence of characters matching the syntax
+ rule named <em>URI</em> in <url href="https://www.ietf.org/rfc/rfc3986.txt">RFC 3986</url>.
+ </p>
+ <p> The generic URI syntax consists of a hierarchical sequence of components referred
+ to as the scheme, authority, path, query, and fragment:</p>
+ <pre>
+ URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
+ hier-part = "//" authority path-abempty
+ / path-absolute
+ / path-rootless
+ / path-empty
+ scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+ authority = [ userinfo "@" ] host [ ":" port ]
+ userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
+
+ reserved = gen-delims / sub-delims
+ gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
+ sub-delims = "!" / "$" / "&amp;" / "'" / "(" / ")"
+ / "*" / "+" / "," / ";" / "="
+
+ unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+ </pre><br></br>
+ <p>The interpretation of a URI depends only on the characters used and not on how those
+ characters are represented in a network protocol.</p>
+ <p>The functions implemented by this module cover the following use cases:</p>
+ <list type="bulleted">
+ <item>Parsing URIs into its components and returing a map<br></br>
+ <seealso marker="#parse/1"><c>parse/1</c></seealso>
+ </item>
+ <item>Recomposing a map of URI components into a URI string<br></br>
+ <seealso marker="#recompose/1"><c>recompose/1</c></seealso>
+ </item>
+ <item>Changing inbound binary and percent-encoding of URIs<br></br>
+ <seealso marker="#transcode/2"><c>transcode/2</c></seealso>
+ </item>
+ <item>Transforming URIs into a normalized form<br></br>
+ <seealso marker="#normalize/1"><c>normalize/1</c></seealso><br></br>
+ <seealso marker="#normalize/2"><c>normalize/2</c></seealso>
+ </item>
+ <item>Composing form-urlencoded query strings from a list of key-value pairs<br></br>
+ <seealso marker="#compose_query/1"><c>compose_query/1</c></seealso><br></br>
+ <seealso marker="#compose_query/2"><c>compose_query/2</c></seealso>
+ </item>
+ <item>Dissecting form-urlencoded query strings into a list of key-value pairs<br></br>
+ <seealso marker="#dissect_query/1"><c>dissect_query/1</c></seealso>
+ </item>
+ </list>
+ <p>There are four different encodings present during the handling of URIs:</p>
+ <list type="bulleted">
+ <item>Inbound binary encoding in binaries</item>
+ <item>Inbound percent-encoding in lists and binaries</item>
+ <item>Outbound binary encoding in binaries</item>
+ <item>Outbound percent-encoding in lists and binaries</item>
+ </list>
+ <p>Functions with <c>uri_string()</c> argument accept lists, binaries and
+ mixed lists (lists with binary elements) as input type. All of the functions but
+ <c>transcode/2</c> expects input as lists of unicode codepoints, UTF-8 encoded binaries
+ and UTF-8 percent-encoded URI parts ("%C3%B6" corresponds to the unicode character "ö").</p>
+ <p>Unless otherwise specified the return value type and encoding are the same as the input
+ type and encoding. That is, binary input returns binary output, list input returns a list
+ output but mixed input returns list output.</p>
+ <p>In case of lists there is only percent-encoding. In binaries, however, both binary encoding
+ and percent-encoding shall be considered. <c>transcode/2</c> provides the means to convert
+ between the supported encodings, it takes a <c>uri_string()</c> and a list of options
+ specifying inbound and outbound encodings.</p>
+ <p><url href="https://www.ietf.org/rfc/rfc3986.txt">RFC 3986</url> does not mandate any specific
+ character encoding and it is usually defined by the protocol or surrounding text. This library
+ takes the same assumption, binary and percent-encoding are handled as one configuration unit,
+ they cannot be set to different values.</p>
+ </description>
+
+ <datatypes>
+ <datatype>
+ <name name="error"/>
+ <desc>
+ <p>Error tuple indicating the type of error. Possible values of the second component:</p>
+ <list type="bulleted">
+ <item><c>invalid_character</c></item>
+ <item><c>invalid_encoding</c></item>
+ <item><c>invalid_input</c></item>
+ <item><c>invalid_map</c></item>
+ <item><c>invalid_percent_encoding</c></item>
+ <item><c>invalid_scheme</c></item>
+ <item><c>invalid_uri</c></item>
+ <item><c>invalid_utf8</c></item>
+ <item><c>missing_value</c></item>
+ </list>
+ <p>The third component is a term providing additional information about the
+ cause of the error.</p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="uri_map"/>
+ <desc>
+ <p>Map holding the main components of a URI.</p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="uri_string"/>
+ <desc>
+ <p>List of unicode codepoints, a UTF-8 encoded binary, or a mix of the two,
+ representing an <url href="https://www.ietf.org/rfc/rfc3986.txt">RFC 3986</url>
+ compliant URI (<em>percent-encoded form</em>).
+ A URI is a sequence of characters from a very limited set: the letters of
+ the basic Latin alphabet, digits, and a few special characters.</p>
+ </desc>
+ </datatype>
+ </datatypes>
+
+ <funcs>
+
+ <func>
+ <name name="compose_query" arity="1" since="OTP 21.0"/>
+ <fsummary>Compose urlencoded query string.</fsummary>
+ <desc>
+ <p>Composes a form-urlencoded <c><anno>QueryString</anno></c> based on a
+ <c><anno>QueryList</anno></c>, a list of non-percent-encoded key-value pairs.
+ Form-urlencoding is defined in section
+ 4.10.21.6 of the <url href="https://www.w3.org/TR/html52/">HTML 5.2</url>
+ specification and in section 4.10.22.6 of the
+ <url href="https://www.w3.org/TR/html50/">HTML 5.0</url> specification for
+ non-UTF-8 encodings.
+ </p>
+ <p>See also the opposite operation <seealso marker="#dissect_query/1">
+ <c>dissect_query/1</c></seealso>.
+ </p>
+ <p><em>Example:</em></p>
+ <pre>
+1> <input>uri_string:compose_query([{"foo bar","1"},{"city","örebro"}]).</input>
+<![CDATA["foo+bar=1&city=%C3%B6rebro"]]>
+2> <![CDATA[uri_string:compose_query([{<<"foo bar">>,<<"1">>},
+2> {<<"city">>,<<"örebro"/utf8>>}]).]]>
+<![CDATA[<<"foo+bar=1&city=%C3%B6rebro">>]]>
+ </pre>
+ </desc>
+ </func>
+
+ <func>
+ <name name="compose_query" arity="2" since="OTP 21.0"/>
+ <fsummary>Compose urlencoded query string.</fsummary>
+ <desc>
+ <p>Same as <c>compose_query/1</c> but with an additional
+ <c><anno>Options</anno></c> parameter, that controls the encoding ("charset")
+ used by the encoding algorithm. There are two supported encodings: <c>utf8</c>
+ (or <c>unicode</c>) and <c>latin1</c>.
+ </p>
+ <p>Each character in the entry's name and value that cannot be expressed using
+ the selected character encoding, is replaced by a string consisting of a U+0026
+ AMPERSAND character (<![CDATA[&]]>), a "#" (U+0023) character, one or more ASCII
+ digits representing the Unicode code point of the character in base ten, and
+ finally a ";" (U+003B) character.
+ </p>
+ <p>Bytes that are out of the range 0x2A, 0x2D, 0x2E, 0x30 to 0x39, 0x41 to 0x5A, 0x5F,
+ 0x61 to 0x7A, are percent-encoded (U+0025 PERCENT SIGN character (%) followed by
+ uppercase ASCII hex digits representing the hexadecimal value of the byte).
+ </p>
+ <p>See also the opposite operation <seealso marker="#dissect_query/1">
+ <c>dissect_query/1</c></seealso>.
+ </p>
+ <p><em>Example:</em></p>
+ <pre>
+1> <input>uri_string:compose_query([{"foo bar","1"},{"city","örebro"}],</input>
+1> [{encoding, latin1}]).
+<![CDATA["foo+bar=1&city=%F6rebro"
+2> uri_string:compose_query([{<<"foo bar">>,<<"1">>},
+2> {<<"city">>,<<"東京"/utf8>>}], [{encoding, latin1}]).]]>
+<![CDATA[<<"foo+bar=1&city=%26%2326481%3B%26%2320140%3B">>]]>
+ </pre>
+ </desc>
+ </func>
+
+ <func>
+ <name name="dissect_query" arity="1" since="OTP 21.0"/>
+ <fsummary>Dissect query string.</fsummary>
+ <desc>
+ <p>Dissects an urlencoded <c><anno>QueryString</anno></c> and returns a
+ <c><anno>QueryList</anno></c>, a list of non-percent-encoded key-value pairs.
+ Form-urlencoding is defined in section
+ 4.10.21.6 of the <url href="https://www.w3.org/TR/html52/">HTML 5.2</url>
+ specification and in section 4.10.22.6 of the
+ <url href="https://www.w3.org/TR/html50/">HTML 5.0</url> specification for
+ non-UTF-8 encodings.
+ </p>
+ <p>See also the opposite operation <seealso marker="#compose_query/1">
+ <c>compose_query/1</c></seealso>.
+ </p>
+ <p><em>Example:</em></p>
+ <pre>
+1> <input><![CDATA[uri_string:dissect_query("foo+bar=1&city=%C3%B6rebro").]]></input>
+[{"foo bar","1"},{"city","örebro"}]
+2> <![CDATA[uri_string:dissect_query(<<"foo+bar=1&city=%26%2326481%3B%26%2320140%3B">>).]]>
+<![CDATA[[{<<"foo bar">>,<<"1">>},
+ {<<"city">>,<<230,157,177,228,186,172>>}] ]]>
+ </pre>
+ </desc>
+ </func>
+
+ <func>
+ <name name="normalize" arity="1" since="OTP 21.0"/>
+ <fsummary>Syntax-based normalization.</fsummary>
+ <desc>
+ <p>Transforms an <c><anno>URI</anno></c> into a normalized form
+ using Syntax-Based Normalization as defined by
+ <url href="https://www.ietf.org/rfc/rfc3986.txt">RFC 3986</url>.</p>
+ <p>This function implements case normalization, percent-encoding
+ normalization, path segment normalization and scheme based normalization
+ for HTTP(S) with basic support for FTP, SSH, SFTP and TFTP.</p>
+ <p><em>Example:</em></p>
+ <pre>
+1> <input>uri_string:normalize("/a/b/c/./../../g").</input>
+"/a/g"
+2> <![CDATA[uri_string:normalize(<<"mid/content=5/../6">>).]]>
+<![CDATA[<<"mid/6">>]]>
+3> uri_string:normalize("http://localhost:80").
+"https://localhost/"
+4> <input>uri_string:normalize(#{scheme => "http",port => 80,path => "/a/b/c/./../../g",</input>
+4> host => "localhost-örebro"}).
+"http://localhost-%C3%B6rebro/a/g"
+ </pre>
+ </desc>
+ </func>
+
+ <func>
+ <name name="normalize" arity="2" since="OTP 21.0"/>
+ <fsummary>Syntax-based normalization.</fsummary>
+ <desc>
+ <p>Same as <c>normalize/1</c> but with an additional
+ <c><anno>Options</anno></c> parameter, that controls if the normalized URI
+ shall be returned as an uri_map().
+ There is one supported option: <c>return_map</c>.
+ </p>
+ <p><em>Example:</em></p>
+ <pre>
+1> <input>uri_string:normalize("/a/b/c/./../../g", [return_map]).</input>
+#{path => "/a/g"}
+2> <![CDATA[uri_string:normalize(<<"mid/content=5/../6">>, [return_map]).]]>
+<![CDATA[#{path => <<"mid/6">>}]]>
+3> uri_string:normalize("http://localhost:80", [return_map]).
+#{scheme => "http",path => "/",host => "localhost"}
+4> <input>uri_string:normalize(#{scheme => "http",port => 80,path => "/a/b/c/./../../g",</input>
+4> host => "localhost-örebro"}, [return_map]).
+#{scheme => "http",path => "/a/g",host => "localhost-örebro"}
+ </pre>
+ </desc>
+ </func>
+
+ <func>
+ <name name="parse" arity="1" since="OTP 21.0"/>
+ <fsummary>Parse URI into a map.</fsummary>
+ <desc>
+ <p>Parses an <url href="https://www.ietf.org/rfc/rfc3986.txt">RFC 3986</url>
+ compliant <c>uri_string()</c> into a <c>uri_map()</c>, that holds the parsed
+ components of the <c>URI</c>.
+ If parsing fails, an error tuple is returned.</p>
+ <p>See also the opposite operation <seealso marker="#recompose/1">
+ <c>recompose/1</c></seealso>.</p>
+ <p><em>Example:</em></p>
+ <pre>
+1> <input>uri_string:parse("foo://[email protected]:8042/over/there?name=ferret#nose").</input>
+#{fragment => "nose",host => "example.com",
+ path => "/over/there",port => 8042,query => "name=ferret",
+ scheme => foo,userinfo => "user"}
+2> <![CDATA[uri_string:parse(<<"foo://[email protected]:8042/over/there?name=ferret">>).]]>
+<![CDATA[#{host => <<"example.com">>,path => <<"/over/there">>,
+ port => 8042,query => <<"name=ferret">>,scheme => <<"foo">>,
+ userinfo => <<"user">>}]]>
+ </pre>
+ </desc>
+ </func>
+
+ <func>
+ <name name="recompose" arity="1" since="OTP 21.0"/>
+ <fsummary>Recompose URI.</fsummary>
+ <desc>
+ <p>Creates an <url href="https://www.ietf.org/rfc/rfc3986.txt">RFC 3986</url> compliant
+ <c><anno>URIString</anno></c> (percent-encoded), based on the components of
+ <c><anno>URIMap</anno></c>.
+ If the <c><anno>URIMap</anno></c> is invalid, an error tuple is returned.</p>
+ <p>See also the opposite operation <seealso marker="#parse/1">
+ <c>parse/1</c></seealso>.</p>
+ <p><em>Example:</em></p>
+ <pre>
+1> <input>URIMap = #{fragment => "nose", host => "example.com", path => "/over/there",</input>
+1> port => 8042, query => "name=ferret", scheme => "foo", userinfo => "user"}.
+#{fragment => "top",host => "example.com",
+ path => "/over/there",port => 8042,query => "?name=ferret",
+ scheme => foo,userinfo => "user"}
+
+2> <input>uri_string:recompose(URIMap).</input>
+"foo://example.com:8042/over/there?name=ferret#nose"</pre>
+ </desc>
+ </func>
+
+ <func>
+ <name name="transcode" arity="2" since="OTP 21.0"/>
+ <fsummary>Transcode URI.</fsummary>
+ <desc>
+ <p>Transcodes an <url href="https://www.ietf.org/rfc/rfc3986.txt">RFC 3986</url>
+ compliant <c><anno>URIString</anno></c>,
+ where <c><anno>Options</anno></c> is a list of tagged tuples, specifying the inbound
+ (<c>in_encoding</c>) and outbound (<c>out_encoding</c>) encodings. <c>in_encoding</c>
+ and <c>out_encoding</c> specifies both binary encoding and percent-encoding for the
+ input and output data. Mixed encoding, where binary encoding is not the same as
+ percent-encoding, is not supported.
+ If an argument is invalid, an error tuple is returned.</p>
+ <p><em>Example:</em></p>
+ <pre>
+1> <input><![CDATA[uri_string:transcode(<<"foo%00%00%00%F6bar"/utf32>>,]]></input>
+1> [{in_encoding, utf32},{out_encoding, utf8}]).
+<![CDATA[<<"foo%C3%B6bar"/utf8>>]]>
+2> uri_string:transcode("foo%F6bar", [{in_encoding, latin1},
+2> {out_encoding, utf8}]).
+"foo%C3%B6bar"
+ </pre>
+ </desc>
+ </func>
+
+ </funcs>
+</erlref>
diff --git a/lib/stdlib/doc/src/win32reg.xml b/lib/stdlib/doc/src/win32reg.xml
index f4a4fa1626..5e2aed6062 100644
--- a/lib/stdlib/doc/src/win32reg.xml
+++ b/lib/stdlib/doc/src/win32reg.xml
@@ -32,7 +32,7 @@
<rev>PA1</rev>
<file>win32reg.xml</file>
</header>
- <module>win32reg</module>
+ <module since="">win32reg</module>
<modulesummary>Provides access to the registry on Windows.</modulesummary>
<description>
<p>This module provides read and write access to the
@@ -112,7 +112,7 @@ hkdd HKEY_DYN_DATA</pre>
<funcs>
<func>
- <name name="change_key" arity="2"/>
+ <name name="change_key" arity="2" since=""/>
<fsummary>Move to a key in the registry.</fsummary>
<desc>
<p>Changes the current key to another key. Works like <c>cd</c>.
@@ -122,7 +122,7 @@ hkdd HKEY_DYN_DATA</pre>
</func>
<func>
- <name name="change_key_create" arity="2"/>
+ <name name="change_key_create" arity="2" since=""/>
<fsummary>Move to a key, create it if it is not there.</fsummary>
<desc>
<p>Creates a key, or just changes to it, if it is already there. Works
@@ -133,7 +133,7 @@ hkdd HKEY_DYN_DATA</pre>
</func>
<func>
- <name name="close" arity="1"/>
+ <name name="close" arity="1" since=""/>
<fsummary>Close the registry.</fsummary>
<desc>
<p>Closes the registry. After that, the <c><anno>RegHandle</anno></c>
@@ -142,7 +142,7 @@ hkdd HKEY_DYN_DATA</pre>
</func>
<func>
- <name name="current_key" arity="1"/>
+ <name name="current_key" arity="1" since=""/>
<fsummary>Return the path to the current key.</fsummary>
<desc>
<p>Returns the path to the current key. This is the equivalent of
@@ -153,7 +153,7 @@ hkdd HKEY_DYN_DATA</pre>
</func>
<func>
- <name name="delete_key" arity="1"/>
+ <name name="delete_key" arity="1" since=""/>
<fsummary>Delete the current key.</fsummary>
<desc>
<p>Deletes the current key, if it is valid. Calls the Win32 API
@@ -166,7 +166,7 @@ hkdd HKEY_DYN_DATA</pre>
</func>
<func>
- <name name="delete_value" arity="2"/>
+ <name name="delete_value" arity="2" since=""/>
<fsummary>Delete the named value on the current key.</fsummary>
<desc>
<p>Deletes a named value on the current key. The atom <c>default</c> is
@@ -176,7 +176,7 @@ hkdd HKEY_DYN_DATA</pre>
</func>
<func>
- <name name="expand" arity="1"/>
+ <name name="expand" arity="1" since=""/>
<fsummary>Expand a string with environment variables.</fsummary>
<desc>
<p>Expands a string containing environment variables between percent
@@ -189,7 +189,7 @@ hkdd HKEY_DYN_DATA</pre>
</func>
<func>
- <name name="format_error" arity="1"/>
+ <name name="format_error" arity="1" since=""/>
<fsummary>Convert a POSIX error code to a string.</fsummary>
<desc>
<p>Converts a POSIX error code to a string
@@ -198,7 +198,7 @@ hkdd HKEY_DYN_DATA</pre>
</func>
<func>
- <name name="open" arity="1"/>
+ <name name="open" arity="1" since=""/>
<fsummary>Open the registry for reading or writing.</fsummary>
<desc>
<p>Opens the registry for reading or writing. The current key is the
@@ -211,7 +211,7 @@ hkdd HKEY_DYN_DATA</pre>
</func>
<func>
- <name name="set_value" arity="3"/>
+ <name name="set_value" arity="3" since=""/>
<fsummary>Set value at the current registry key with specified name.
</fsummary>
<desc>
@@ -230,7 +230,7 @@ hkdd HKEY_DYN_DATA</pre>
</func>
<func>
- <name name="sub_keys" arity="1"/>
+ <name name="sub_keys" arity="1" since=""/>
<fsummary>Get subkeys to the current key.</fsummary>
<desc>
<p>Returns a list of subkeys to the current key. Calls the Win32
@@ -240,7 +240,7 @@ hkdd HKEY_DYN_DATA</pre>
</func>
<func>
- <name name="value" arity="2"/>
+ <name name="value" arity="2" since=""/>
<fsummary>Get the named value on the current key.</fsummary>
<desc>
<p>Retrieves the named value (or default) on the current key.
@@ -251,7 +251,7 @@ hkdd HKEY_DYN_DATA</pre>
</func>
<func>
- <name name="values" arity="1"/>
+ <name name="values" arity="1" since=""/>
<fsummary>Get all values on the current key.</fsummary>
<desc>
<p>Retrieves a list of all values on the current key. The values
diff --git a/lib/stdlib/doc/src/zip.xml b/lib/stdlib/doc/src/zip.xml
index 0b5eac1e16..bb2ed7727a 100644
--- a/lib/stdlib/doc/src/zip.xml
+++ b/lib/stdlib/doc/src/zip.xml
@@ -32,7 +32,7 @@
<rev>PA1</rev>
<file>zip.xml</file>
</header>
- <module>zip</module>
+ <module since="">zip</module>
<modulesummary>Utility for reading and creating 'zip' archives.
</modulesummary>
<description>
@@ -180,7 +180,7 @@
<funcs>
<func>
- <name name="foldl" arity="3"/>
+ <name name="foldl" arity="3" since="OTP R14B"/>
<fsummary>Fold a function over all files in a zip archive.</fsummary>
<desc>
<p>Calls <c><anno>Fun</anno>(<anno>FileInArchive</anno>, <anno>GetInfo
@@ -234,10 +234,10 @@
</func>
<func>
- <name name="list_dir" arity="1"/>
- <name name="list_dir" arity="2"/>
- <name name="table" arity="1" />
- <name name="table" arity="2"/>
+ <name name="list_dir" arity="1" since=""/>
+ <name name="list_dir" arity="2" since=""/>
+ <name name="table" arity="1" since=""/>
+ <name name="table" arity="2" since=""/>
<fsummary>Retrieve the name of all files in a zip archive.</fsummary>
<desc>
<p><c>list_dir/1</c> retrieves all filenames in the zip archive
@@ -263,7 +263,7 @@
</func>
<func>
- <name name="t" arity="1"/>
+ <name name="t" arity="1" since=""/>
<fsummary>Print the name of each file in a zip archive.</fsummary>
<desc>
<p>Prints all filenames in the zip archive <c><anno>Archive</anno></c>
@@ -272,7 +272,7 @@
</func>
<func>
- <name name="tt" arity="1"/>
+ <name name="tt" arity="1" since=""/>
<fsummary>Print name and information for each file in a zip archive.
</fsummary>
<desc>
@@ -283,10 +283,10 @@
</func>
<func>
- <name name="unzip" arity="1"/>
- <name name="unzip" arity="2"/>
- <name name="extract" arity="1"/>
- <name name="extract" arity="2"/>
+ <name name="unzip" arity="1" since=""/>
+ <name name="unzip" arity="2" since=""/>
+ <name name="extract" arity="1" since=""/>
+ <name name="extract" arity="2" since=""/>
<fsummary>Extract files from a zip archive.</fsummary>
<desc>
<p><c>unzip/1</c> extracts all files from a zip archive.</p>
@@ -353,10 +353,10 @@
</func>
<func>
- <name name="zip" arity="2"/>
- <name name="zip" arity="3"/>
- <name name="create" arity="2"/>
- <name name="create" arity="3"/>
+ <name name="zip" arity="2" since=""/>
+ <name name="zip" arity="3" since=""/>
+ <name name="create" arity="2" since=""/>
+ <name name="create" arity="3" since=""/>
<fsummary>Create a zip archive with options.</fsummary>
<desc>
<p>Creates a zip archive containing the files specified in
@@ -481,7 +481,7 @@
</func>
<func>
- <name name="zip_close" arity="1"/>
+ <name name="zip_close" arity="1" since=""/>
<fsummary>Close an open archive.</fsummary>
<desc>
<p>Closes a zip archive, previously opened with
@@ -492,8 +492,8 @@
</func>
<func>
- <name name="zip_get" arity="1"/>
- <name name="zip_get" arity="2"/>
+ <name name="zip_get" arity="1" since=""/>
+ <name name="zip_get" arity="2" since=""/>
<fsummary>Extract files from an open archive.</fsummary>
<desc>
<p>Extracts one or all files from an open archive.</p>
@@ -505,7 +505,7 @@
</func>
<func>
- <name name="zip_list_dir" arity="1"/>
+ <name name="zip_list_dir" arity="1" since=""/>
<fsummary>Return a table of files in open zip archive.</fsummary>
<desc>
<p>Returns the file list of an open zip archive. The first returned
@@ -514,8 +514,8 @@
</func>
<func>
- <name name="zip_open" arity="1"/>
- <name name="zip_open" arity="2"/>
+ <name name="zip_open" arity="1" since=""/>
+ <name name="zip_open" arity="2" since=""/>
<fsummary>Open an archive and return a handle to it.</fsummary>
<desc>
<p>Opens a zip archive, and reads and saves its directory. This
diff --git a/lib/stdlib/include/assert.hrl b/lib/stdlib/include/assert.hrl
index 2fbaeba0b2..28d25c6589 100644
--- a/lib/stdlib/include/assert.hrl
+++ b/lib/stdlib/include/assert.hrl
@@ -140,7 +140,7 @@
-endif.
%% This is mostly a convenience which gives more detailed reports.
-%% Note: Guard is a guarded pattern, and can not be used for value.
+%% Note: Guard is a guarded pattern, and cannot be used for value.
-ifdef(NOASSERT).
-define(assertMatch(Guard, Expr), ok).
-define(assertMatch(Guard, Expr, Comment), ok).
@@ -289,7 +289,7 @@
end).
-endif.
-%% Note: Class and Term are patterns, and can not be used for value.
+%% Note: Class and Term are patterns, and cannot be used for value.
%% Term can be a guarded pattern, but Class cannot.
-ifdef(NOASSERT).
-define(assertException(Class, Term, Expr), ok).
@@ -309,7 +309,7 @@
{unexpected_success, __V}]})
catch
Class:Term -> ok;
- __C:__T ->
+ __C:__T:__S ->
erlang:error({assertException,
[{module, ?MODULE},
{line, ?LINE},
@@ -318,8 +318,7 @@
"{ "++(??Class)++" , "++(??Term)
++" , [...] }"},
{unexpected_exception,
- {__C, __T,
- erlang:get_stacktrace()}}]})
+ {__C, __T, __S}}]})
end
end)())
end).
@@ -338,7 +337,7 @@
{unexpected_success, __V}]})
catch
Class:Term -> ok;
- __C:__T ->
+ __C:__T:__S ->
erlang:error({assertException,
[{module, ?MODULE},
{line, ?LINE},
@@ -348,8 +347,7 @@
"{ "++(??Class)++" , "++(??Term)
++" , [...] }"},
{unexpected_exception,
- {__C, __T,
- erlang:get_stacktrace()}}]})
+ {__C, __T, __S}}]})
end
end)())
end).
@@ -366,7 +364,7 @@
?assertException(throw, Term, Expr, Comment)).
%% This is the inverse case of assertException, for convenience.
-%% Note: Class and Term are patterns, and can not be used for value.
+%% Note: Class and Term are patterns, and cannot be used for value.
%% Both Class and Term can be guarded patterns.
-ifdef(NOASSERT).
-define(assertNotException(Class, Term, Expr), ok).
@@ -378,7 +376,7 @@
try (Expr) of
_ -> ok
catch
- __C:__T ->
+ __C:__T:__S ->
case __C of
Class ->
case __T of
@@ -391,9 +389,7 @@
"{ "++(??Class)++" , "
++(??Term)++" , [...] }"},
{unexpected_exception,
- {__C, __T,
- erlang:get_stacktrace()
- }}]});
+ {__C, __T, __S}}]});
_ -> ok
end;
_ -> ok
@@ -407,7 +403,7 @@
try (Expr) of
_ -> ok
catch
- __C:__T ->
+ __C:__T:__S ->
case __C of
Class ->
case __T of
@@ -421,9 +417,7 @@
"{ "++(??Class)++" , "
++(??Term)++" , [...] }"},
{unexpected_exception,
- {__C, __T,
- erlang:get_stacktrace()
- }}]});
+ {__C, __T, __S}}]});
_ -> ok
end;
_ -> ok
diff --git a/lib/stdlib/src/Makefile b/lib/stdlib/src/Makefile
index bf836203ec..86003c953d 100644
--- a/lib/stdlib/src/Makefile
+++ b/lib/stdlib/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2017. All Rights Reserved.
+# Copyright Ericsson AB 1996-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -62,6 +62,7 @@ MODULES= \
erl_anno \
erl_bits \
erl_compile \
+ erl_error \
erl_eval \
erl_expand_records \
erl_internal \
@@ -91,7 +92,6 @@ MODULES= \
io_lib_format \
io_lib_fread \
io_lib_pretty \
- lib \
lists \
log_mf_h \
maps \
@@ -121,6 +121,7 @@ MODULES= \
timer \
unicode \
unicode_util \
+ uri_string \
win32reg \
zip
@@ -154,8 +155,10 @@ APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
ifeq ($(NATIVE_LIBS_ENABLED),yes)
ERL_COMPILE_FLAGS += +native
+else
+ERL_COMPILE_FLAGS += -Werror
endif
-ERL_COMPILE_FLAGS += -I../include -I../../kernel/include -Werror
+ERL_COMPILE_FLAGS += -I../include -I../../kernel/include
# ----------------------------------------------------
# Targets
@@ -175,6 +178,7 @@ docs:
primary_bootstrap_compiler: \
$(BOOTSTRAP_COMPILER)/ebin/epp.beam \
$(BOOTSTRAP_COMPILER)/ebin/erl_anno.beam \
+ $(BOOTSTRAP_COMPILER)/ebin/erl_error.beam \
$(BOOTSTRAP_COMPILER)/ebin/erl_scan.beam \
$(BOOTSTRAP_COMPILER)/ebin/erl_parse.beam \
$(BOOTSTRAP_COMPILER)/ebin/erl_lint.beam \
@@ -237,6 +241,13 @@ $(EBIN)/erl_tar.beam: ../../kernel/include/file.hrl erl_tar.hrl
$(EBIN)/file_sorter.beam: ../../kernel/include/file.hrl
$(EBIN)/filelib.beam: ../../kernel/include/file.hrl
$(EBIN)/filename.beam: ../../kernel/include/file.hrl
+$(EBIN)/gen_event.beam: ../../kernel/include/logger.hrl
+$(EBIN)/gen_fsm.beam: ../../kernel/include/logger.hrl
+$(EBIN)/gen_server.beam: ../../kernel/include/logger.hrl
+$(EBIN)/gen_statem.beam: ../../kernel/include/logger.hrl
+$(EBIN)/proc_lib.beam: ../../kernel/include/logger.hrl
$(EBIN)/qlc_pt.beam: ../include/ms_transform.hrl
$(EBIN)/shell.beam: ../../kernel/include/file.hrl
+$(EBIN)/supervisor.beam: ../../kernel/include/logger.hrl
+$(EBIN)/supervisor_bridge.beam: ../../kernel/include/logger.hrl
$(EBIN)/zip.beam: ../include/zip.hrl ../../kernel/include/file.hrl
diff --git a/lib/stdlib/src/array.erl b/lib/stdlib/src/array.erl
index a237eaa489..1504326c61 100644
--- a/lib/stdlib/src/array.erl
+++ b/lib/stdlib/src/array.erl
@@ -126,11 +126,12 @@
%% per write than base 10, but the speedup is only 21%.)
-define(DEFAULT, undefined).
--define(LEAFSIZE, 10). % the "base"
--define(NODESIZE, ?LEAFSIZE). % (no reason to have a different size)
+-define(LEAFSIZE, 10). % the "base" (assumed to be > 1)
+-define(NODESIZE, ?LEAFSIZE). % must not be LEAFSIZE-1; keep same as leaf
-define(NODEPATTERN(S), {_,_,_,_,_,_,_,_,_,_,S}). % NODESIZE+1 elements!
--define(NEW_NODE(S), % beware of argument duplication!
- setelement((?NODESIZE+1),erlang:make_tuple((?NODESIZE+1),(S)),(S))).
+-define(NEW_NODE(E,S), % general case (currently unused)
+ setelement((?NODESIZE+1),erlang:make_tuple((?NODESIZE+1),(E)),(S))).
+-define(NEW_NODE(S), erlang:make_tuple((?NODESIZE+1),(S))). % when E = S
-define(NEW_LEAF(D), erlang:make_tuple(?LEAFSIZE,(D))).
-define(NODELEAFS, ?NODESIZE*?LEAFSIZE).
@@ -290,7 +291,7 @@ new(Size, Fixed, Default) ->
end,
#array{size = Size, max = M, default = Default, elements = E}.
--spec find_max(integer(), integer()) -> integer().
+-spec find_max(integer(), non_neg_integer()) -> non_neg_integer().
find_max(I, M) when I >= M ->
find_max(I, ?extend(M));
@@ -605,7 +606,7 @@ grow(I, E, M) ->
grow_1(I, E, M).
grow_1(I, E, M) when I >= M ->
- grow(I, setelement(1, ?NEW_NODE(M), E), ?extend(M));
+ grow_1(I, setelement(1, ?NEW_NODE(M), E), ?extend(M));
grow_1(_I, E, M) ->
{E, M}.
@@ -1631,12 +1632,11 @@ foldl_test_() ->
?_assert(foldl(Sum, 0, from_list(lists:seq(0,10))) =:= 55),
?_assert(foldl(Reverse, [], from_list(lists:seq(0,1000)))
=:= lists:reverse(lists:seq(0,1000))),
- ?_assert({999,[N0*100+1+2,N0*2+1+1,0]} =:=
- foldl(Vals, {0,[]},
+ ?_assertEqual({N0*100+1-2,[N0*100+1+2,N0*2+1+1,0]},
+ foldl(Vals, {0,[]},
set(N0*100+1,2,
set(N0*2+1,1,
set(0,0,new())))))
-
].
-endif.
@@ -1786,12 +1786,11 @@ foldr_test_() ->
?_assert(foldr(Sum, 0, from_list(lists:seq(0,10))) =:= 55),
?_assert(foldr(List, [], from_list(lists:seq(0,1000)))
=:= lists:seq(0,1000)),
- ?_assert({999,[0,N0*2+1+1,N0*100+1+2]} =:=
- foldr(Vals, {0,[]},
+ ?_assertEqual({N0*100+1-2,[0,N0*2+1+1,N0*100+1+2]},
+ foldr(Vals, {0,[]},
set(N0*100+1,2,
set(N0*2+1,1,
set(0,0,new())))))
-
].
-endif.
diff --git a/lib/stdlib/src/base64.erl b/lib/stdlib/src/base64.erl
index 5885745fb1..6ea4147abf 100644
--- a/lib/stdlib/src/base64.erl
+++ b/lib/stdlib/src/base64.erl
@@ -24,22 +24,11 @@
-export([encode/1, decode/1, mime_decode/1,
encode_to_string/1, decode_to_string/1, mime_decode_to_string/1]).
-%%-------------------------------------------------------------------------
%% The following type is a subtype of string() for return values
%% of (some) functions of this module.
-%%-------------------------------------------------------------------------
-
-type ascii_string() :: [1..255].
-type ascii_binary() :: binary().
-%%-------------------------------------------------------------------------
-%% encode_to_string(ASCII) -> Base64String
-%% ASCII - string() | binary()
-%% Base64String - string()
-%%
-%% Description: Encodes a plain ASCII string (or binary) into base64.
-%%-------------------------------------------------------------------------
-
-spec encode_to_string(Data) -> Base64String when
Data :: ascii_string() | ascii_binary(),
Base64String :: ascii_string().
@@ -47,107 +36,89 @@
encode_to_string(Bin) when is_binary(Bin) ->
encode_to_string(binary_to_list(Bin));
encode_to_string(List) when is_list(List) ->
- encode_l(List).
-
-%%-------------------------------------------------------------------------
-%% encode(ASCII) -> Base64
-%% ASCII - string() | binary()
-%% Base64 - binary()
-%%
-%% Description: Encodes a plain ASCII string (or binary) into base64.
-%%-------------------------------------------------------------------------
+ encode_list_to_string(List).
-spec encode(Data) -> Base64 when
Data :: ascii_string() | ascii_binary(),
Base64 :: ascii_binary().
encode(Bin) when is_binary(Bin) ->
- encode_binary(Bin);
+ encode_binary(Bin, <<>>);
encode(List) when is_list(List) ->
- list_to_binary(encode_l(List)).
+ encode_list(List, <<>>).
--spec encode_l(ascii_string()) -> ascii_string().
-
-encode_l([]) ->
+encode_list_to_string([]) ->
[];
-encode_l([A]) ->
- [b64e(A bsr 2),
- b64e((A band 3) bsl 4), $=, $=];
-encode_l([A,B]) ->
- [b64e(A bsr 2),
- b64e(((A band 3) bsl 4) bor (B bsr 4)),
- b64e((B band 15) bsl 2), $=];
-encode_l([A,B,C|Ls]) ->
- BB = (A bsl 16) bor (B bsl 8) bor C,
+encode_list_to_string([B1]) ->
+ [b64e(B1 bsr 2),
+ b64e((B1 band 3) bsl 4), $=, $=];
+encode_list_to_string([B1,B2]) ->
+ [b64e(B1 bsr 2),
+ b64e(((B1 band 3) bsl 4) bor (B2 bsr 4)),
+ b64e((B2 band 15) bsl 2), $=];
+encode_list_to_string([B1,B2,B3|Ls]) ->
+ BB = (B1 bsl 16) bor (B2 bsl 8) bor B3,
[b64e(BB bsr 18),
b64e((BB bsr 12) band 63),
b64e((BB bsr 6) band 63),
- b64e(BB band 63) | encode_l(Ls)].
-
-encode_binary(Bin) ->
- Split = 3*(byte_size(Bin) div 3),
- <<Main0:Split/binary,Rest/binary>> = Bin,
- Main = << <<(b64e(C)):8>> || <<C:6>> <= Main0 >>,
- case Rest of
- <<A:6,B:6,C:4>> ->
- <<Main/binary,(b64e(A)):8,(b64e(B)):8,(b64e(C bsl 2)):8,$=:8>>;
- <<A:6,B:2>> ->
- <<Main/binary,(b64e(A)):8,(b64e(B bsl 4)):8,$=:8,$=:8>>;
- <<>> ->
- Main
- end.
+ b64e(BB band 63) | encode_list_to_string(Ls)].
-%%-------------------------------------------------------------------------
-%% mime_decode(Base64) -> ASCII
-%% decode(Base64) -> ASCII
-%% Base64 - string() | binary()
-%% ASCII - binary()
-%%
-%% Description: Decodes an base64 encoded string to plain ASCII.
-%% mime_decode strips away all characters not Base64 before converting,
-%% whereas decode crashes if an illegal character is found
-%%-------------------------------------------------------------------------
+encode_binary(<<>>, A) ->
+ A;
+encode_binary(<<B1:8>>, A) ->
+ <<A/bits,(b64e(B1 bsr 2)):8,(b64e((B1 band 3) bsl 4)):8,$=:8,$=:8>>;
+encode_binary(<<B1:8, B2:8>>, A) ->
+ <<A/bits,(b64e(B1 bsr 2)):8,
+ (b64e(((B1 band 3) bsl 4) bor (B2 bsr 4))):8,
+ (b64e((B2 band 15) bsl 2)):8, $=:8>>;
+encode_binary(<<B1:8, B2:8, B3:8, Ls/bits>>, A) ->
+ BB = (B1 bsl 16) bor (B2 bsl 8) bor B3,
+ encode_binary(Ls,
+ <<A/bits,(b64e(BB bsr 18)):8,
+ (b64e((BB bsr 12) band 63)):8,
+ (b64e((BB bsr 6) band 63)):8,
+ (b64e(BB band 63)):8>>).
+
+encode_list([], A) ->
+ A;
+encode_list([B1], A) ->
+ <<A/bits,(b64e(B1 bsr 2)):8,(b64e((B1 band 3) bsl 4)):8,$=:8,$=:8>>;
+encode_list([B1,B2], A) ->
+ <<A/bits,(b64e(B1 bsr 2)):8,
+ (b64e(((B1 band 3) bsl 4) bor (B2 bsr 4))):8,
+ (b64e((B2 band 15) bsl 2)):8, $=:8>>;
+encode_list([B1,B2,B3|Ls], A) ->
+ BB = (B1 bsl 16) bor (B2 bsl 8) bor B3,
+ encode_list(Ls,
+ <<A/bits,(b64e(BB bsr 18)):8,
+ (b64e((BB bsr 12) band 63)):8,
+ (b64e((BB bsr 6) band 63)):8,
+ (b64e(BB band 63)):8>>).
+
+%% mime_decode strips away all characters not Base64 before
+%% converting, whereas decode crashes if an illegal character is found
-spec decode(Base64) -> Data when
Base64 :: ascii_string() | ascii_binary(),
Data :: ascii_binary().
decode(Bin) when is_binary(Bin) ->
- decode_binary(<<>>, Bin);
+ decode_binary(Bin, <<>>);
decode(List) when is_list(List) ->
- list_to_binary(decode_l(List)).
+ decode_list(List, <<>>).
-spec mime_decode(Base64) -> Data when
Base64 :: ascii_string() | ascii_binary(),
Data :: ascii_binary().
mime_decode(Bin) when is_binary(Bin) ->
- mime_decode_binary(<<>>, Bin);
+ mime_decode_binary(Bin, <<>>);
mime_decode(List) when is_list(List) ->
- mime_decode(list_to_binary(List)).
-
--spec decode_l(ascii_string()) -> ascii_string().
-
-decode_l(List) ->
- L = strip_spaces(List, []),
- decode(L, []).
-
--spec mime_decode_l(ascii_string()) -> ascii_string().
+ mime_decode_list(List, <<>>).
-mime_decode_l(List) ->
- L = strip_illegal(List, [], 0),
- decode(L, []).
-
-%%-------------------------------------------------------------------------
-%% mime_decode_to_string(Base64) -> ASCII
-%% decode_to_string(Base64) -> ASCII
-%% Base64 - string() | binary()
-%% ASCII - binary()
-%%
-%% Description: Decodes an base64 encoded string to plain ASCII.
-%% mime_decode strips away all characters not Base64 before converting,
-%% whereas decode crashes if an illegal character is found
-%%-------------------------------------------------------------------------
+%% mime_decode_to_string strips away all characters not Base64 before
+%% converting, whereas decode_to_string crashes if an illegal
+%% character is found
-spec decode_to_string(Base64) -> DataString when
Base64 :: ascii_string() | ascii_binary(),
@@ -156,7 +127,7 @@ mime_decode_l(List) ->
decode_to_string(Bin) when is_binary(Bin) ->
decode_to_string(binary_to_list(Bin));
decode_to_string(List) when is_list(List) ->
- decode_l(List).
+ decode_list_to_string(List).
-spec mime_decode_to_string(Base64) -> DataString when
Base64 :: ascii_string() | ascii_binary(),
@@ -165,202 +136,326 @@ decode_to_string(List) when is_list(List) ->
mime_decode_to_string(Bin) when is_binary(Bin) ->
mime_decode_to_string(binary_to_list(Bin));
mime_decode_to_string(List) when is_list(List) ->
- mime_decode_l(List).
-
-%% One-based decode map.
--define(DECODE_MAP,
- {bad,bad,bad,bad,bad,bad,bad,bad,ws,ws,bad,bad,ws,bad,bad, %1-15
- bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad, %16-31
- ws,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,62,bad,bad,bad,63, %32-47
- 52,53,54,55,56,57,58,59,60,61,bad,bad,bad,eq,bad,bad, %48-63
- bad,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,
- 15,16,17,18,19,20,21,22,23,24,25,bad,bad,bad,bad,bad,
- bad,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
- 41,42,43,44,45,46,47,48,49,50,51,bad,bad,bad,bad,bad,
- bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,
- bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,
- bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,
- bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,
- bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,
- bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,
- bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,
- bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad}).
-
-decode_binary(Result0, <<C:8,T0/bits>>) ->
- case element(C, ?DECODE_MAP) of
- bad ->
- erlang:error({badarg,C});
- ws ->
- decode_binary(Result0, T0);
- eq ->
- case strip_ws(T0) of
- <<$=:8,T/binary>> ->
- <<>> = strip_ws(T),
- Split = byte_size(Result0) - 1,
- <<Result:Split/bytes,_:4>> = Result0,
- Result;
- T ->
- <<>> = strip_ws(T),
- Split = byte_size(Result0) - 1,
- <<Result:Split/bytes,_:2>> = Result0,
- Result
- end;
- Bits ->
- decode_binary(<<Result0/bits,Bits:6>>, T0)
- end;
-decode_binary(Result, <<>>) ->
- true = is_binary(Result),
- Result.
+ mime_decode_list_to_string(List).
%% Skipping pad character if not at end of string. Also liberal about
%% excess padding and skipping of other illegal (non-base64 alphabet)
%% characters. See section 3.3 of RFC4648
-mime_decode_binary(Result, <<0:8,T/bits>>) ->
- mime_decode_binary(Result, T);
-mime_decode_binary(Result0, <<C:8,T/bits>>) ->
- case element(C, ?DECODE_MAP) of
- Bits when is_integer(Bits) ->
- mime_decode_binary(<<Result0/bits,Bits:6>>, T);
+mime_decode_list([0 | Cs], A) ->
+ mime_decode_list(Cs, A);
+mime_decode_list([C1 | Cs], A) ->
+ case b64d(C1) of
+ B1 when is_integer(B1) -> mime_decode_list(Cs, A, B1);
+ _ -> mime_decode_list(Cs, A) % eq is padding
+ end;
+mime_decode_list([], A) ->
+ A.
+
+mime_decode_list([0 | Cs], A, B1) ->
+ mime_decode_list(Cs, A, B1);
+mime_decode_list([C2 | Cs], A, B1) ->
+ case b64d(C2) of
+ B2 when is_integer(B2) ->
+ mime_decode_list(Cs, A, B1, B2);
+ _ -> mime_decode_list(Cs, A, B1) % eq is padding
+ end.
+
+mime_decode_list([0 | Cs], A, B1, B2) ->
+ mime_decode_list(Cs, A, B1, B2);
+mime_decode_list([C3 | Cs], A, B1, B2) ->
+ case b64d(C3) of
+ B3 when is_integer(B3) ->
+ mime_decode_list(Cs, A, B1, B2, B3);
+ eq=B3 ->
+ mime_decode_list_after_eq(Cs, A, B1, B2, B3);
+ _ -> mime_decode_list(Cs, A, B1, B2)
+ end.
+
+mime_decode_list([0 | Cs], A, B1, B2, B3) ->
+ mime_decode_list(Cs, A, B1, B2, B3);
+mime_decode_list([C4 | Cs], A, B1, B2, B3) ->
+ case b64d(C4) of
+ B4 when is_integer(B4) ->
+ mime_decode_list(Cs, <<A/bits,B1:6,B2:6,B3:6,B4:6>>);
eq ->
- mime_decode_binary_after_eq(Result0, T, false);
- _ ->
- mime_decode_binary(Result0, T)
+ mime_decode_list_after_eq(Cs, A, B1, B2, B3);
+ _ -> mime_decode_list(Cs, A, B1, B2, B3)
+ end.
+
+mime_decode_list_after_eq([0 | Cs], A, B1, B2, B3) ->
+ mime_decode_list_after_eq(Cs, A, B1, B2, B3);
+mime_decode_list_after_eq([C | Cs], A, B1, B2, B3) ->
+ case b64d(C) of
+ B when is_integer(B) ->
+ %% More valid data, skip the eq as invalid
+ case B3 of
+ eq -> mime_decode_list(Cs, A, B1, B2, B);
+ _ -> mime_decode_list(Cs, <<A/bits,B1:6,B2:6,B3:6,B:6>>)
+ end;
+ _ -> mime_decode_list_after_eq(Cs, A, B1, B2, B3)
end;
-mime_decode_binary(Result, _) ->
- true = is_binary(Result),
- Result.
-
-mime_decode_binary_after_eq(Result, <<0:8,T/bits>>, Eq) ->
- mime_decode_binary_after_eq(Result, T, Eq);
-mime_decode_binary_after_eq(Result0, <<C:8,T/bits>>, Eq) ->
- case element(C, ?DECODE_MAP) of
- bad ->
- mime_decode_binary_after_eq(Result0, T, Eq);
- ws ->
- mime_decode_binary_after_eq(Result0, T, Eq);
+mime_decode_list_after_eq([], A, B1, B2, eq) ->
+ <<A/bits,B1:6,(B2 bsr 4):2>>;
+mime_decode_list_after_eq([], A, B1, B2, B3) ->
+ <<A/bits,B1:6,B2:6,(B3 bsr 2):4>>.
+
+mime_decode_binary(<<0:8, Cs/bits>>, A) ->
+ mime_decode_binary(Cs, A);
+mime_decode_binary(<<C1:8, Cs/bits>>, A) ->
+ case b64d(C1) of
+ B1 when is_integer(B1) -> mime_decode_binary(Cs, A, B1);
+ _ -> mime_decode_binary(Cs, A) % eq is padding
+ end;
+mime_decode_binary(<<>>, A) ->
+ A.
+
+mime_decode_binary(<<0:8, Cs/bits>>, A, B1) ->
+ mime_decode_binary(Cs, A, B1);
+mime_decode_binary(<<C2:8, Cs/bits>>, A, B1) ->
+ case b64d(C2) of
+ B2 when is_integer(B2) ->
+ mime_decode_binary(Cs, A, B1, B2);
+ _ -> mime_decode_binary(Cs, A, B1) % eq is padding
+ end.
+
+mime_decode_binary(<<0:8, Cs/bits>>, A, B1, B2) ->
+ mime_decode_binary(Cs, A, B1, B2);
+mime_decode_binary(<<C3:8, Cs/bits>>, A, B1, B2) ->
+ case b64d(C3) of
+ B3 when is_integer(B3) ->
+ mime_decode_binary(Cs, A, B1, B2, B3);
+ eq=B3 ->
+ mime_decode_binary_after_eq(Cs, A, B1, B2, B3);
+ _ -> mime_decode_binary(Cs, A, B1, B2)
+ end.
+
+mime_decode_binary(<<0:8, Cs/bits>>, A, B1, B2, B3) ->
+ mime_decode_binary(Cs, A, B1, B2, B3);
+mime_decode_binary(<<C4:8, Cs/bits>>, A, B1, B2, B3) ->
+ case b64d(C4) of
+ B4 when is_integer(B4) ->
+ mime_decode_binary(Cs, <<A/bits,B1:6,B2:6,B3:6,B4:6>>);
eq ->
- mime_decode_binary_after_eq(Result0, T, true);
- Bits when is_integer(Bits) ->
+ mime_decode_binary_after_eq(Cs, A, B1, B2, B3);
+ _ -> mime_decode_binary(Cs, A, B1, B2, B3)
+ end.
+
+mime_decode_binary_after_eq(<<0:8, Cs/bits>>, A, B1, B2, B3) ->
+ mime_decode_binary_after_eq(Cs, A, B1, B2, B3);
+mime_decode_binary_after_eq(<<C:8, Cs/bits>>, A, B1, B2, B3) ->
+ case b64d(C) of
+ B when is_integer(B) ->
%% More valid data, skip the eq as invalid
- mime_decode_binary(<<Result0/bits,Bits:6>>, T)
+ case B3 of
+ eq -> mime_decode_binary(Cs, A, B1, B2, B);
+ _ -> mime_decode_binary(Cs, <<A/bits,B1:6,B2:6,B3:6,B:6>>)
+ end;
+ _ -> mime_decode_binary_after_eq(Cs, A, B1, B2, B3)
+ end;
+mime_decode_binary_after_eq(<<>>, A, B1, B2, eq) ->
+ <<A/bits,B1:6,(B2 bsr 4):2>>;
+mime_decode_binary_after_eq(<<>>, A, B1, B2, B3) ->
+ <<A/bits,B1:6,B2:6,(B3 bsr 2):4>>.
+
+mime_decode_list_to_string([0 | Cs]) ->
+ mime_decode_list_to_string(Cs);
+mime_decode_list_to_string([C1 | Cs]) ->
+ case b64d(C1) of
+ B1 when is_integer(B1) -> mime_decode_list_to_string(Cs, B1);
+ _ -> mime_decode_list_to_string(Cs) % eq is padding
end;
-mime_decode_binary_after_eq(Result0, <<>>, Eq) ->
- %% No more valid data.
- case bit_size(Result0) rem 8 of
- 0 ->
- %% '====' is not uncommon.
- Result0;
- 4 when Eq ->
- %% enforce at least one more '=' only ignoring illegals and spacing
- Split = byte_size(Result0) - 1,
- <<Result:Split/bytes,_:4>> = Result0,
- Result;
- 2 ->
- %% remove 2 bits
- Split = byte_size(Result0) - 1,
- <<Result:Split/bytes,_:2>> = Result0,
- Result
+mime_decode_list_to_string([]) ->
+ [].
+
+mime_decode_list_to_string([0 | Cs], B1) ->
+ mime_decode_list_to_string(Cs, B1);
+mime_decode_list_to_string([C2 | Cs], B1) ->
+ case b64d(C2) of
+ B2 when is_integer(B2) ->
+ mime_decode_list_to_string(Cs, B1, B2);
+ _ -> mime_decode_list_to_string(Cs, B1) % eq is padding
end.
-decode([], A) -> A;
-decode([$=,$=,C2,C1|Cs], A) ->
- Bits2x6 = (b64d(C1) bsl 18) bor (b64d(C2) bsl 12),
- Octet1 = Bits2x6 bsr 16,
- decode(Cs, [Octet1|A]);
-decode([$=,C3,C2,C1|Cs], A) ->
- Bits3x6 = (b64d(C1) bsl 18) bor (b64d(C2) bsl 12)
- bor (b64d(C3) bsl 6),
- Octet1 = Bits3x6 bsr 16,
- Octet2 = (Bits3x6 bsr 8) band 16#ff,
- decode(Cs, [Octet1,Octet2|A]);
-decode([C4,C3,C2,C1| Cs], A) ->
- Bits4x6 = (b64d(C1) bsl 18) bor (b64d(C2) bsl 12)
- bor (b64d(C3) bsl 6) bor b64d(C4),
- Octet1 = Bits4x6 bsr 16,
- Octet2 = (Bits4x6 bsr 8) band 16#ff,
- Octet3 = Bits4x6 band 16#ff,
- decode(Cs, [Octet1,Octet2,Octet3|A]).
+mime_decode_list_to_string([0 | Cs], B1, B2) ->
+ mime_decode_list_to_string(Cs, B1, B2);
+mime_decode_list_to_string([C3 | Cs], B1, B2) ->
+ case b64d(C3) of
+ B3 when is_integer(B3) ->
+ mime_decode_list_to_string(Cs, B1, B2, B3);
+ eq=B3 -> mime_decode_list_to_string_after_eq(Cs, B1, B2, B3);
+ _ -> mime_decode_list_to_string(Cs, B1, B2)
+ end.
-%%%========================================================================
-%%% Internal functions
-%%%========================================================================
+mime_decode_list_to_string([0 | Cs], B1, B2, B3) ->
+ mime_decode_list_to_string(Cs, B1, B2, B3);
+mime_decode_list_to_string([C4 | Cs], B1, B2, B3) ->
+ case b64d(C4) of
+ B4 when is_integer(B4) ->
+ Bits4x6 = (B1 bsl 18) bor (B2 bsl 12) bor (B3 bsl 6) bor B4,
+ Octet1 = Bits4x6 bsr 16,
+ Octet2 = (Bits4x6 bsr 8) band 16#ff,
+ Octet3 = Bits4x6 band 16#ff,
+ [Octet1, Octet2, Octet3 | mime_decode_list_to_string(Cs)];
+ eq ->
+ mime_decode_list_to_string_after_eq(Cs, B1, B2, B3);
+ _ -> mime_decode_list_to_string(Cs, B1, B2, B3)
+ end.
-strip_spaces([], A) -> A;
-strip_spaces([$\s|Cs], A) -> strip_spaces(Cs, A);
-strip_spaces([$\t|Cs], A) -> strip_spaces(Cs, A);
-strip_spaces([$\r|Cs], A) -> strip_spaces(Cs, A);
-strip_spaces([$\n|Cs], A) -> strip_spaces(Cs, A);
-strip_spaces([C|Cs], A) -> strip_spaces(Cs, [C | A]).
-
-strip_ws(<<$\t,T/binary>>) ->
- strip_ws(T);
-strip_ws(<<$\n,T/binary>>) ->
- strip_ws(T);
-strip_ws(<<$\r,T/binary>>) ->
- strip_ws(T);
-strip_ws(<<$\s,T/binary>>) ->
- strip_ws(T);
-strip_ws(T) -> T.
+mime_decode_list_to_string_after_eq([0 | Cs], B1, B2, B3) ->
+ mime_decode_list_to_string_after_eq(Cs, B1, B2, B3);
+mime_decode_list_to_string_after_eq([C | Cs], B1, B2, B3) ->
+ case b64d(C) of
+ B when is_integer(B) ->
+ %% More valid data, skip the eq as invalid
+ case B3 of
+ eq -> mime_decode_list_to_string(Cs, B1, B2, B);
+ _ ->
+ Bits4x6 = (B1 bsl 18) bor (B2 bsl 12) bor (B3 bsl 6) bor B,
+ Octet1 = Bits4x6 bsr 16,
+ Octet2 = (Bits4x6 bsr 8) band 16#ff,
+ Octet3 = Bits4x6 band 16#ff,
+ [Octet1, Octet2, Octet3 | mime_decode_list_to_string(Cs)]
+ end;
+ _ -> mime_decode_list_to_string_after_eq(Cs, B1, B2, B3)
+ end;
+mime_decode_list_to_string_after_eq([], B1, B2, eq) ->
+ binary_to_list(<<B1:6,(B2 bsr 4):2>>);
+mime_decode_list_to_string_after_eq([], B1, B2, B3) ->
+ binary_to_list(<<B1:6,B2:6,(B3 bsr 2):4>>).
+
+decode_list([C1 | Cs], A) ->
+ case b64d(C1) of
+ ws -> decode_list(Cs, A);
+ B1 -> decode_list(Cs, A, B1)
+ end;
+decode_list([], A) ->
+ A.
-%% Skipping pad character if not at end of string. Also liberal about
-%% excess padding and skipping of other illegal (non-base64 alphabet)
-%% characters. See section 3.3 of RFC4648
-strip_illegal([], A, _Cnt) ->
+decode_list([C2 | Cs], A, B1) ->
+ case b64d(C2) of
+ ws -> decode_list(Cs, A, B1);
+ B2 -> decode_list(Cs, A, B1, B2)
+ end.
+
+decode_list([C3 | Cs], A, B1, B2) ->
+ case b64d(C3) of
+ ws -> decode_list(Cs, A, B1, B2);
+ B3 -> decode_list(Cs, A, B1, B2, B3)
+ end.
+
+decode_list([C4 | Cs], A, B1, B2, B3) ->
+ case b64d(C4) of
+ ws -> decode_list(Cs, A, B1, B2, B3);
+ eq when B3 =:= eq -> only_ws(Cs, <<A/bits,B1:6,(B2 bsr 4):2>>);
+ eq -> only_ws(Cs, <<A/bits,B1:6,B2:6,(B3 bsr 2):4>>);
+ B4 -> decode_list(Cs, <<A/bits,B1:6,B2:6,B3:6,B4:6>>)
+ end.
+
+decode_binary(<<C1:8, Cs/bits>>, A) ->
+ case b64d(C1) of
+ ws -> decode_binary(Cs, A);
+ B1 -> decode_binary(Cs, A, B1)
+ end;
+decode_binary(<<>>, A) ->
+ A.
+
+decode_binary(<<C2:8, Cs/bits>>, A, B1) ->
+ case b64d(C2) of
+ ws -> decode_binary(Cs, A, B1);
+ B2 -> decode_binary(Cs, A, B1, B2)
+ end.
+
+decode_binary(<<C3:8, Cs/bits>>, A, B1, B2) ->
+ case b64d(C3) of
+ ws -> decode_binary(Cs, A, B1, B2);
+ B3 -> decode_binary(Cs, A, B1, B2, B3)
+ end.
+
+decode_binary(<<C4:8, Cs/bits>>, A, B1, B2, B3) ->
+ case b64d(C4) of
+ ws -> decode_binary(Cs, A, B1, B2, B3);
+ eq when B3 =:= eq -> only_ws_binary(Cs, <<A/bits,B1:6,(B2 bsr 4):2>>);
+ eq -> only_ws_binary(Cs, <<A/bits,B1:6,B2:6,(B3 bsr 2):4>>);
+ B4 -> decode_binary(Cs, <<A/bits,B1:6,B2:6,B3:6,B4:6>>)
+ end.
+
+only_ws_binary(<<>>, A) ->
A;
-strip_illegal([0|Cs], A, Cnt) ->
- strip_illegal(Cs, A, Cnt);
-strip_illegal([C|Cs], A, Cnt) ->
- case element(C, ?DECODE_MAP) of
- bad ->
- strip_illegal(Cs, A, Cnt);
- ws ->
- strip_illegal(Cs, A, Cnt);
- eq ->
- case {tail_contains_more(Cs, false), Cnt rem 4} of
- {{[], _}, 0} ->
- A; %% Ignore extra =
- {{[], true}, 2} ->
- [$=|[$=|A]]; %% 'XX=='
- {{[], _}, 3} ->
- [$=|A]; %% 'XXX='
- {{[H|T], _}, _} ->
- %% more data, skip equals
- strip_illegal(T, [H|A], Cnt+1)
- end;
- _ ->
- strip_illegal(Cs, [C|A], Cnt+1)
+only_ws_binary(<<C:8, Cs/bits>>, A) ->
+ case b64d(C) of
+ ws -> only_ws_binary(Cs, A)
end.
-%% Search the tail for more valid data and remember if we saw
-%% another equals along the way.
-tail_contains_more([], Eq) ->
- {[], Eq};
-tail_contains_more(<<>>, Eq) ->
- {<<>>, Eq};
-tail_contains_more([C|T]=More, Eq) ->
- case element(C, ?DECODE_MAP) of
- bad ->
- tail_contains_more(T, Eq);
- ws ->
- tail_contains_more(T, Eq);
- eq ->
- tail_contains_more(T, true);
- _ ->
- {More, Eq}
+decode_list_to_string([C1 | Cs]) ->
+ case b64d(C1) of
+ ws -> decode_list_to_string(Cs);
+ B1 -> decode_list_to_string(Cs, B1)
end;
-tail_contains_more(<<C:8,T/bits>> =More, Eq) ->
- case element(C, ?DECODE_MAP) of
- bad ->
- tail_contains_more(T, Eq);
- ws ->
- tail_contains_more(T, Eq);
- eq ->
- tail_contains_more(T, true);
- _ ->
- {More, Eq}
+decode_list_to_string([]) ->
+ [].
+
+decode_list_to_string([C2 | Cs], B1) ->
+ case b64d(C2) of
+ ws -> decode_list_to_string(Cs, B1);
+ B2 -> decode_list_to_string(Cs, B1, B2)
end.
-
+
+decode_list_to_string([C3 | Cs], B1, B2) ->
+ case b64d(C3) of
+ ws -> decode_list_to_string(Cs, B1, B2);
+ B3 -> decode_list_to_string(Cs, B1, B2, B3)
+ end.
+
+decode_list_to_string([C4 | Cs], B1, B2, B3) ->
+ case b64d(C4) of
+ ws ->
+ decode_list_to_string(Cs, B1, B2, B3);
+ eq when B3 =:= eq ->
+ only_ws(Cs, binary_to_list(<<B1:6,(B2 bsr 4):2>>));
+ eq ->
+ only_ws(Cs, binary_to_list(<<B1:6,B2:6,(B3 bsr 2):4>>));
+ B4 ->
+ Bits4x6 = (B1 bsl 18) bor (B2 bsl 12) bor (B3 bsl 6) bor B4,
+ Octet1 = Bits4x6 bsr 16,
+ Octet2 = (Bits4x6 bsr 8) band 16#ff,
+ Octet3 = Bits4x6 band 16#ff,
+ [Octet1, Octet2, Octet3 | decode_list_to_string(Cs)]
+ end.
+
+only_ws([], A) ->
+ A;
+only_ws([C | Cs], A) ->
+ case b64d(C) of
+ ws -> only_ws(Cs, A)
+ end.
+
+%%%========================================================================
+%%% Internal functions
+%%%========================================================================
+
%% accessors
+-compile({inline, [{b64d, 1}]}).
+%% One-based decode map.
+b64d(X) ->
+ element(X,
+ {bad,bad,bad,bad,bad,bad,bad,bad,ws,ws,bad,bad,ws,bad,bad, %1-15
+ bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad, %16-31
+ ws,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,62,bad,bad,bad,63, %32-47
+ 52,53,54,55,56,57,58,59,60,61,bad,bad,bad,eq,bad,bad, %48-63
+ bad,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,
+ 15,16,17,18,19,20,21,22,23,24,25,bad,bad,bad,bad,bad,
+ bad,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
+ 41,42,43,44,45,46,47,48,49,50,51,bad,bad,bad,bad,bad,
+ bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,
+ bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,
+ bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,
+ bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,
+ bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,
+ bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,
+ bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,
+ bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad}).
+
+-compile({inline, [{b64e, 1}]}).
b64e(X) ->
element(X+1,
{$A, $B, $C, $D, $E, $F, $G, $H, $I, $J, $K, $L, $M, $N,
@@ -368,9 +463,3 @@ b64e(X) ->
$a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n,
$o, $p, $q, $r, $s, $t, $u, $v, $w, $x, $y, $z,
$0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $+, $/}).
-
-
-b64d(X) ->
- b64d_ok(element(X, ?DECODE_MAP)).
-
-b64d_ok(I) when is_integer(I) -> I.
diff --git a/lib/stdlib/src/beam_lib.erl b/lib/stdlib/src/beam_lib.erl
index 06c15fceda..aa992f17ab 100644
--- a/lib/stdlib/src/beam_lib.erl
+++ b/lib/stdlib/src/beam_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,8 +32,12 @@
all_chunks/1,
diff_dirs/2,
strip/1,
+ strip/2,
strip_files/1,
+ strip_files/2,
strip_release/1,
+ strip_release/2,
+ significant_chunks/0,
build_module/1,
version/1,
md5/1,
@@ -53,7 +57,7 @@
%%-------------------------------------------------------------------------
--type beam() :: module() | file:filename() | binary().
+-type beam() :: file:filename() | binary().
-type debug_info() :: {DbgiVersion :: atom(), Backend :: module(), Data :: term()} | 'no_debug_info'.
-type forms() :: [erl_parse:abstract_form() | erl_parse:form_info()].
@@ -148,7 +152,8 @@ chunks(File, Chunks, Options) ->
try read_chunk_data(File, Chunks, Options)
catch Error -> Error end.
--spec all_chunks(beam()) -> {'ok', 'beam_lib', [{chunkid(), dataB()}]}.
+-spec all_chunks(beam()) ->
+ {'ok', 'beam_lib', [{chunkid(), dataB()}]} | {'error', 'beam_lib', info_rsn()}.
all_chunks(File) ->
read_all_chunks(File).
@@ -187,7 +192,16 @@ diff_dirs(Dir1, Dir2) ->
Beam2 :: beam().
strip(FileName) ->
- try strip_file(FileName)
+ strip(FileName, []).
+
+-spec strip(Beam1, AdditionalChunks) ->
+ {'ok', {module(), Beam2}} | {'error', 'beam_lib', info_rsn()} when
+ Beam1 :: beam(),
+ AdditionalChunks :: [chunkid()],
+ Beam2 :: beam().
+
+strip(FileName, AdditionalChunks) ->
+ try strip_file(FileName, AdditionalChunks)
catch Error -> Error end.
-spec strip_files(Files) ->
@@ -195,8 +209,17 @@ strip(FileName) ->
Files :: [beam()],
Beam :: beam().
-strip_files(Files) when is_list(Files) ->
- try strip_fils(Files)
+strip_files(Files) ->
+ strip_files(Files, []).
+
+-spec strip_files(Files, AdditionalChunks) ->
+ {'ok', [{module(), Beam}]} | {'error', 'beam_lib', info_rsn()} when
+ Files :: [beam()],
+ AdditionalChunks :: [chunkid()],
+ Beam :: beam().
+
+strip_files(Files, AdditionalChunks) when is_list(Files) ->
+ try strip_fils(Files, AdditionalChunks)
catch Error -> Error end.
-spec strip_release(Dir) ->
@@ -206,7 +229,17 @@ strip_files(Files) when is_list(Files) ->
Reason :: {'not_a_directory', term()} | info_rsn().
strip_release(Root) ->
- catch strip_rel(Root).
+ strip_release(Root, []).
+
+-spec strip_release(Dir, AdditionalChunks) ->
+ {'ok', [{module(), file:filename()}]}
+ | {'error', 'beam_lib', Reason} when
+ Dir :: atom() | file:filename(),
+ AdditionalChunks :: [chunkid()],
+ Reason :: {'not_a_directory', term()} | info_rsn().
+
+strip_release(Root, AdditionalChunks) ->
+ catch strip_rel(Root, AdditionalChunks).
-spec version(Beam) ->
{'ok', {module(), [Version :: term()]}} |
@@ -400,17 +433,17 @@ cmp_lists([{Id, C1} | R1], [{Id, C2} | R2]) ->
cmp_lists(_, _) ->
error(different_chunks).
-strip_rel(Root) ->
+strip_rel(Root, AdditionalChunks) ->
ok = assert_directory(Root),
- strip_fils(filelib:wildcard(filename:join(Root, "lib/*/ebin/*.beam"))).
+ strip_fils(filelib:wildcard(filename:join(Root, "lib/*/ebin/*.beam")), AdditionalChunks).
%% -> {ok, [{Mod, BinaryOrFileName}]} | throw(Error)
-strip_fils(Files) ->
- {ok, [begin {ok, Reply} = strip_file(F), Reply end || F <- Files]}.
+strip_fils(Files, AdditionalChunks) ->
+ {ok, [begin {ok, Reply} = strip_file(F, AdditionalChunks), Reply end || F <- Files]}.
%% -> {ok, {Mod, FileName}} | {ok, {Mod, binary()}} | throw(Error)
-strip_file(File) ->
- {ok, {Mod, Chunks}} = read_significant_chunks(File, significant_chunks()),
+strip_file(File, AdditionalChunks) ->
+ {ok, {Mod, Chunks}} = read_significant_chunks(File, AdditionalChunks ++ significant_chunks()),
{ok, Stripped0} = build_module(Chunks),
Stripped = compress(Stripped0),
case File of
@@ -689,30 +722,31 @@ chunk_to_data(debug_info=Id, Chunk, File, _Cs, AtomTable, Mod) ->
<<0:8,N:8,Mode0:N/binary,Rest/binary>> ->
Mode = binary_to_atom(Mode0, utf8),
Term = decrypt_chunk(Mode, Mod, File, Id, Rest),
- {AtomTable, {Id, Term}};
+ {AtomTable, {Id, anno_from_term(Term)}};
_ ->
case catch binary_to_term(Chunk) of
{'EXIT', _} ->
error({invalid_chunk, File, chunk_name_to_id(Id, File)});
Term ->
- {AtomTable, {Id, Term}}
+ {AtomTable, {Id, anno_from_term(Term)}}
end
end;
chunk_to_data(abstract_code=Id, Chunk, File, _Cs, AtomTable, Mod) ->
+ %% Before Erlang/OTP 20.0.
case Chunk of
<<>> ->
{AtomTable, {Id, no_abstract_code}};
<<0:8,N:8,Mode0:N/binary,Rest/binary>> ->
Mode = binary_to_atom(Mode0, utf8),
Term = decrypt_chunk(Mode, Mod, File, Id, Rest),
- {AtomTable, {Id, anno_from_term(Term)}};
+ {AtomTable, {Id, old_anno_from_term(Term)}};
_ ->
case catch binary_to_term(Chunk) of
{'EXIT', _} ->
error({invalid_chunk, File, chunk_name_to_id(Id, File)});
Term ->
try
- {AtomTable, {Id, anno_from_term(Term)}}
+ {AtomTable, {Id, old_anno_from_term(Term)}}
catch
_:_ ->
error({invalid_chunk, File,
@@ -946,14 +980,24 @@ decrypt_chunk(Type, Module, File, Id, Bin) ->
error({key_missing_or_invalid, File, Id})
end.
-anno_from_term({raw_abstract_v1, Forms}) ->
+old_anno_from_term({raw_abstract_v1, Forms}) ->
{raw_abstract_v1, anno_from_forms(Forms)};
-anno_from_term({Tag, Forms}) when Tag =:= abstract_v1; Tag =:= abstract_v2 ->
+old_anno_from_term({Tag, Forms}) when Tag =:= abstract_v1;
+ Tag =:= abstract_v2 ->
try {Tag, anno_from_forms(Forms)}
catch
_:_ ->
{Tag, Forms}
end;
+old_anno_from_term(T) ->
+ T.
+
+anno_from_term({debug_info_v1=Tag1, erl_abstract_code=Tag2, {Forms, Opts}}) ->
+ try {Tag1, Tag2, {anno_from_forms(Forms), Opts}}
+ catch
+ _:_ ->
+ {Tag1, Tag2, {Forms, Opts}}
+ end;
anno_from_term(T) ->
T.
diff --git a/lib/stdlib/src/binary.erl b/lib/stdlib/src/binary.erl
index 6a64133b45..52b9fedc9c 100644
--- a/lib/stdlib/src/binary.erl
+++ b/lib/stdlib/src/binary.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -47,23 +47,39 @@ at(_, _) ->
-spec bin_to_list(Subject) -> [byte()] when
Subject :: binary().
-bin_to_list(_) ->
- erlang:nif_error(undef).
+bin_to_list(Subject) ->
+ binary_to_list(Subject).
-spec bin_to_list(Subject, PosLen) -> [byte()] when
Subject :: binary(),
PosLen :: part().
-bin_to_list(_, _) ->
- erlang:nif_error(undef).
+bin_to_list(Subject, {Pos, Len}) ->
+ bin_to_list(Subject, Pos, Len);
+bin_to_list(_Subject, _BadArg) ->
+ erlang:error(badarg).
-spec bin_to_list(Subject, Pos, Len) -> [byte()] when
Subject :: binary(),
Pos :: non_neg_integer(),
Len :: integer().
-bin_to_list(_, _, _) ->
- erlang:nif_error(undef).
+bin_to_list(Subject, Pos, Len) when not is_binary(Subject);
+ not is_integer(Pos);
+ not is_integer(Len) ->
+ %% binary_to_list/3 allows bitstrings as long as the slice fits, and we
+ %% want to badarg when Pos/Len aren't integers instead of raising badarith
+ %% when adjusting args for binary_to_list/3.
+ erlang:error(badarg);
+bin_to_list(Subject, Pos, 0) when Pos >= 0, Pos =< byte_size(Subject) ->
+ %% binary_to_list/3 doesn't handle this case.
+ [];
+bin_to_list(_Subject, _Pos, 0) ->
+ erlang:error(badarg);
+bin_to_list(Subject, Pos, Len) when Len < 0 ->
+ bin_to_list(Subject, Pos + Len, -Len);
+bin_to_list(Subject, Pos, Len) when Len > 0 ->
+ binary_to_list(Subject, Pos + 1, Pos + Len).
-spec compile_pattern(Pattern) -> cp() when
Pattern :: binary() | [binary()].
diff --git a/lib/stdlib/src/c.erl b/lib/stdlib/src/c.erl
index c04a201ce1..0362b72536 100644
--- a/lib/stdlib/src/c.erl
+++ b/lib/stdlib/src/c.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -564,7 +564,7 @@ display_info(Pid) ->
Other
end,
Reds = fetch(reductions, Info),
- LM = length(fetch(messages, Info)),
+ LM = fetch(message_queue_len, Info),
HS = fetch(heap_size, Info),
SS = fetch(stack_size, Info),
iformat(w(Pid), mfa_string(Call),
@@ -668,19 +668,23 @@ lm() ->
[l(M) || M <- mm()].
%% erlangrc(Home)
-%% Try to run a ".erlang" file, first in the current directory
-%% else in home directory.
+%% Try to run a ".erlang" file in home directory.
+
+-spec erlangrc() -> {ok, file:filename()} | {error, term()}.
erlangrc() ->
case init:get_argument(home) of
{ok,[[Home]]} ->
erlangrc([Home]);
_ ->
- f_p_e(["."], ".erlang")
+ {error, enoent}
end.
-erlangrc([Home]) ->
- f_p_e([".",Home], ".erlang").
+-spec erlangrc(PathList) -> {ok, file:filename()} | {error, term()}
+ when PathList :: [Dir :: file:name()].
+
+erlangrc([Home|_]=Paths) when is_list(Home) ->
+ f_p_e(Paths, ".erlang").
error(Fmt, Args) ->
error_logger:error_msg(Fmt, Args).
@@ -692,11 +696,11 @@ f_p_e(P, F) ->
{error, E={Line, _Mod, _Term}} ->
error("file:path_eval(~tp,~tp): error on line ~p: ~ts~n",
[P, F, Line, file:format_error(E)]),
- ok;
+ {error, E};
{error, E} ->
error("file:path_eval(~tp,~tp): ~ts~n",
[P, F, file:format_error(E)]),
- ok;
+ {error, E};
Other ->
Other
end.
@@ -882,7 +886,7 @@ portinfo(Id) ->
procline(Name, Info, Pid) ->
Call = initial_call(Info),
Reds = fetch(reductions, Info),
- LM = length(fetch(messages, Info)),
+ LM = fetch(message_queue_len, Info),
procformat(io_lib:format("~tw",[Name]),
io_lib:format("~w",[Pid]),
io_lib:format("~ts",[mfa_string(Call)]),
@@ -1030,8 +1034,8 @@ appcall(App, M, F, Args) ->
try
apply(M, F, Args)
catch
- error:undef ->
- case erlang:get_stacktrace() of
+ error:undef:S ->
+ case S of
[{M,F,Args,_}|_] ->
Arity = length(Args),
io:format("Call to ~w:~w/~w in application ~w failed.\n",
diff --git a/lib/stdlib/src/calendar.erl b/lib/stdlib/src/calendar.erl
index 55a0cfc9a1..3a8fe2211b 100644
--- a/lib/stdlib/src/calendar.erl
+++ b/lib/stdlib/src/calendar.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -39,8 +39,14 @@
now_to_datetime/1, % = now_to_universal_time/1
now_to_local_time/1,
now_to_universal_time/1,
+ rfc3339_to_system_time/1,
+ rfc3339_to_system_time/2,
seconds_to_daystime/1,
seconds_to_time/1,
+ system_time_to_local_time/2,
+ system_time_to_universal_time/2,
+ system_time_to_rfc3339/1,
+ system_time_to_rfc3339/2,
time_difference/2,
time_to_seconds/1,
universal_time/0,
@@ -55,10 +61,13 @@
-define(SECONDS_PER_DAY, 86400).
-define(DAYS_PER_YEAR, 365).
-define(DAYS_PER_LEAP_YEAR, 366).
--define(DAYS_PER_4YEARS, 1461).
--define(DAYS_PER_100YEARS, 36524).
--define(DAYS_PER_400YEARS, 146097).
+%% -define(DAYS_PER_4YEARS, 1461).
+%% -define(DAYS_PER_100YEARS, 36524).
+%% -define(DAYS_PER_400YEARS, 146097).
-define(DAYS_FROM_0_TO_1970, 719528).
+-define(DAYS_FROM_0_TO_10000, 2932897).
+-define(SECONDS_FROM_0_TO_1970, (?DAYS_FROM_0_TO_1970*?SECONDS_PER_DAY)).
+-define(SECONDS_FROM_0_TO_10000, (?DAYS_FROM_0_TO_10000*?SECONDS_PER_DAY)).
%%----------------------------------------------------------------------
%% Types
@@ -83,6 +92,13 @@
-type datetime1970() :: {{year1970(),month(),day()},time()}.
-type yearweeknum() :: {year(),weeknum()}.
+-type rfc3339_string() :: [byte(), ...].
+%% By design 'native' is not supported:
+-type rfc3339_time_unit() :: 'microsecond'
+ | 'millisecond'
+ | 'nanosecond'
+ | 'second'.
+
%%----------------------------------------------------------------------
%% All dates are according the the Gregorian calendar. In this module
@@ -309,8 +325,7 @@ local_time_to_universal_time_dst(DateTime) ->
-spec now_to_datetime(Now) -> datetime1970() when
Now :: erlang:timestamp().
now_to_datetime({MSec, Sec, _uSec}) ->
- Sec0 = MSec*1000000 + Sec + ?DAYS_FROM_0_TO_1970*?SECONDS_PER_DAY,
- gregorian_seconds_to_datetime(Sec0).
+ system_time_to_datetime(MSec*1000000 + Sec).
-spec now_to_universal_time(Now) -> datetime1970() when
Now :: erlang:timestamp().
@@ -328,6 +343,37 @@ now_to_local_time({MSec, Sec, _uSec}) ->
erlang:universaltime_to_localtime(
now_to_universal_time({MSec, Sec, _uSec})).
+-spec rfc3339_to_system_time(DateTimeString) -> integer() when
+ DateTimeString :: rfc3339_string().
+
+rfc3339_to_system_time(DateTimeString) ->
+ rfc3339_to_system_time(DateTimeString, []).
+
+-spec rfc3339_to_system_time(DateTimeString, Options) -> integer() when
+ DateTimeString :: rfc3339_string(),
+ Options :: [Option],
+ Option :: {'unit', rfc3339_time_unit()}.
+
+rfc3339_to_system_time(DateTimeString, Options) ->
+ Unit = proplists:get_value(unit, Options, second),
+ %% _T is the character separating the date and the time:
+ [Y1, Y2, Y3, Y4, $-, Mon1, Mon2, $-, D1, D2, _T,
+ H1, H2, $:, Min1, Min2, $:, S1, S2 | TimeStr] = DateTimeString,
+ Hour = list_to_integer([H1, H2]),
+ Min = list_to_integer([Min1, Min2]),
+ Sec = list_to_integer([S1, S2]),
+ Year = list_to_integer([Y1, Y2, Y3, Y4]),
+ Month = list_to_integer([Mon1, Mon2]),
+ Day = list_to_integer([D1, D2]),
+ DateTime = {{Year, Month, Day}, {Hour, Min, Sec}},
+ IsFractionChar = fun(C) -> C >= $0 andalso C =< $9 orelse C =:= $. end,
+ {FractionStr, UtcOffset} = lists:splitwith(IsFractionChar, TimeStr),
+ Time = datetime_to_system_time(DateTime),
+ Secs = Time - offset_adjustment(Time, second, UtcOffset),
+ check(DateTimeString, Options, Secs),
+ ScaledEpoch = erlang:convert_time_unit(Secs, second, Unit),
+ ScaledEpoch + copy_sign(fraction(Unit, FractionStr), ScaledEpoch).
+
%% seconds_to_daystime(Secs) = {Days, {Hour, Minute, Second}}
@@ -363,6 +409,56 @@ seconds_to_time(Secs) when Secs >= 0, Secs < ?SECONDS_PER_DAY ->
Second = Secs1 rem ?SECONDS_PER_MINUTE,
{Hour, Minute, Second}.
+-spec system_time_to_local_time(Time, TimeUnit) -> datetime() when
+ Time :: integer(),
+ TimeUnit :: erlang:time_unit().
+
+system_time_to_local_time(Time, TimeUnit) ->
+ UniversalDate = system_time_to_universal_time(Time, TimeUnit),
+ erlang:universaltime_to_localtime(UniversalDate).
+
+-spec system_time_to_universal_time(Time, TimeUnit) -> datetime() when
+ Time :: integer(),
+ TimeUnit :: erlang:time_unit().
+
+system_time_to_universal_time(Time, TimeUnit) ->
+ Secs = erlang:convert_time_unit(Time, TimeUnit, second),
+ system_time_to_datetime(Secs).
+
+-spec system_time_to_rfc3339(Time) -> DateTimeString when
+ Time :: integer(),
+ DateTimeString :: rfc3339_string().
+
+system_time_to_rfc3339(Time) ->
+ system_time_to_rfc3339(Time, []).
+
+-type offset() :: [byte()] | (Time :: integer()).
+-spec system_time_to_rfc3339(Time, Options) -> DateTimeString when
+ Time :: integer(), % Since Epoch
+ Options :: [Option],
+ Option :: {'offset', offset()}
+ | {'time_designator', byte()}
+ | {'unit', rfc3339_time_unit()},
+ DateTimeString :: rfc3339_string().
+
+system_time_to_rfc3339(Time, Options) ->
+ Unit = proplists:get_value(unit, Options, second),
+ OffsetOption = proplists:get_value(offset, Options, ""),
+ T = proplists:get_value(time_designator, Options, $T),
+ AdjustmentSecs = offset_adjustment(Time, Unit, OffsetOption),
+ Offset = offset(OffsetOption, AdjustmentSecs),
+ Adjustment = erlang:convert_time_unit(AdjustmentSecs, second, Unit),
+ AdjustedTime = Time + Adjustment,
+ Factor = factor(Unit),
+ Secs = AdjustedTime div Factor,
+ check(Time, Options, Secs),
+ DateTime = system_time_to_datetime(Secs),
+ {{Year, Month, Day}, {Hour, Min, Sec}} = DateTime,
+ FractionStr = fraction_str(Factor, AdjustedTime),
+ L = [pad4(Year), "-", pad2(Month), "-", pad2(Day), [T],
+ pad2(Hour), ":", pad2(Min), ":", pad2(Sec), FractionStr, Offset],
+ lists:append(L).
+
%% time_difference(T1, T2) = Tdiff
%%
%% Returns the difference between two {Date, Time} structures.
@@ -438,24 +534,41 @@ valid_date({Y, M, D}) ->
%% day_to_year(DayOfEpoch) = {Year, DayOfYear}
%%
-%% The idea here is to first guess a year, and then adjust. Although
-%% the implementation is recursive, at most 1 or 2 recursive steps
+%% The idea here is to first set the upper and lower bounds for a year,
+%% and then adjust a range by interpolation search. Although complexity
+%% of the algorithm is log(log(n)), at most 1 or 2 recursive steps
%% are taken.
-%% If DayOfEpoch is very large, we need far more than 1 or 2 iterations,
-%% since we just subtract a yearful of days at a time until we're there.
%%
-spec day_to_year(non_neg_integer()) -> {year(), day_of_year()}.
day_to_year(DayOfEpoch) when DayOfEpoch >= 0 ->
- Y0 = DayOfEpoch div ?DAYS_PER_YEAR,
- {Y1, D1} = dty(Y0, DayOfEpoch, dy(Y0)),
+ YMax = DayOfEpoch div ?DAYS_PER_YEAR,
+ YMin = DayOfEpoch div ?DAYS_PER_LEAP_YEAR,
+ {Y1, D1} = dty(YMin, YMax, DayOfEpoch, dy(YMin), dy(YMax)),
{Y1, DayOfEpoch - D1}.
--spec dty(year(), non_neg_integer(), non_neg_integer()) ->
+-spec dty(year(), year(), non_neg_integer(), non_neg_integer(),
+ non_neg_integer()) ->
{year(), non_neg_integer()}.
-dty(Y, D1, D2) when D1 < D2 ->
- dty(Y-1, D1, dy(Y-1));
-dty(Y, _D1, D2) ->
- {Y, D2}.
+dty(Min, Max, _D1, DMin, _DMax) when Min == Max ->
+ {Min, DMin};
+dty(Min, Max, D1, DMin, DMax) ->
+ Diff = Max - Min,
+ Mid = Min + (Diff * (D1 - DMin)) div (DMax - DMin),
+ MidLength =
+ case is_leap_year(Mid) of
+ true -> ?DAYS_PER_LEAP_YEAR;
+ false -> ?DAYS_PER_YEAR
+ end,
+ case dy(Mid) of
+ D2 when D1 < D2 ->
+ NewMax = Mid - 1,
+ dty(Min, NewMax, D1, DMin, dy(NewMax));
+ D2 when D1 - D2 >= MidLength ->
+ NewMin = Mid + 1,
+ dty(NewMin, Max, D1, dy(NewMin), DMax);
+ D2 ->
+ {Mid, D2}
+ end.
%%
%% The Gregorian days of the iso week 01 day 1 for a given year.
@@ -550,3 +663,102 @@ df(Year, _) ->
true -> 1;
false -> 0
end.
+
+check(_Arg, _Options, Secs) when Secs >= - ?SECONDS_FROM_0_TO_1970,
+ Secs < ?SECONDS_FROM_0_TO_10000 ->
+ ok;
+check(Arg, Options, _Secs) ->
+ erlang:error({badarg, [Arg, Options]}).
+
+datetime_to_system_time(DateTime) ->
+ datetime_to_gregorian_seconds(DateTime) - ?SECONDS_FROM_0_TO_1970.
+
+system_time_to_datetime(Seconds) ->
+ gregorian_seconds_to_datetime(Seconds + ?SECONDS_FROM_0_TO_1970).
+
+offset(OffsetOption, Secs0) when OffsetOption =:= "";
+ is_integer(OffsetOption) ->
+ Sign = case Secs0 < 0 of
+ true -> $-;
+ false -> $+
+ end,
+ Secs = abs(Secs0),
+ Hour = Secs div 3600,
+ Min = (Secs rem 3600) div 60,
+ [Sign | lists:append([pad2(Hour), ":", pad2(Min)])];
+offset(OffsetOption, _Secs) ->
+ OffsetOption.
+
+offset_adjustment(Time, Unit, OffsetString) when is_list(OffsetString) ->
+ offset_string_adjustment(Time, Unit, OffsetString);
+offset_adjustment(_Time, Unit, Offset) when is_integer(Offset) ->
+ erlang:convert_time_unit(Offset, Unit, second).
+
+offset_string_adjustment(Time, Unit, "") ->
+ local_offset(Time, Unit);
+offset_string_adjustment(_Time, _Unit, "Z") ->
+ 0;
+offset_string_adjustment(_Time, _Unit, "z") ->
+ 0;
+offset_string_adjustment(_Time, _Unit, Tz) ->
+ [Sign, H1, H2, $:, M1, M2] = Tz,
+ Hour = list_to_integer([H1, H2]),
+ Min = list_to_integer([M1, M2]),
+ Adjustment = 3600 * Hour + 60 * Min,
+ case Sign of
+ $- -> -Adjustment;
+ $+ -> Adjustment
+ end.
+
+local_offset(SystemTime, Unit) ->
+ %% Not optimized for special cases.
+ UniversalTime = system_time_to_universal_time(SystemTime, Unit),
+ LocalTime = erlang:universaltime_to_localtime(UniversalTime),
+ LocalSecs = datetime_to_gregorian_seconds(LocalTime),
+ UniversalSecs = datetime_to_gregorian_seconds(UniversalTime),
+ LocalSecs - UniversalSecs.
+
+fraction_str(1, _Time) ->
+ "";
+fraction_str(Factor, Time) ->
+ Fraction = Time rem Factor,
+ S = integer_to_list(abs(Fraction)),
+ [$. | pad(log10(Factor) - length(S), S)].
+
+fraction(second, _) ->
+ 0;
+fraction(_, "") ->
+ 0;
+fraction(Unit, FractionStr) ->
+ round(factor(Unit) * list_to_float([$0|FractionStr])).
+
+copy_sign(N1, N2) when N2 < 0 -> -N1;
+copy_sign(N1, _N2) -> N1.
+
+factor(second) -> 1;
+factor(millisecond) -> 1000;
+factor(microsecond) -> 1000000;
+factor(nanosecond) -> 1000000000.
+
+log10(1000) -> 3;
+log10(1000000) -> 6;
+log10(1000000000) -> 9.
+
+pad(0, S) ->
+ S;
+pad(I, S) ->
+ [$0 | pad(I - 1, S)].
+
+pad2(N) when N < 10 ->
+ [$0 | integer_to_list(N)];
+pad2(N) ->
+ integer_to_list(N).
+
+pad4(N) when N < 10 ->
+ [$0, $0, $0 | integer_to_list(N)];
+pad4(N) when N < 100 ->
+ [$0, $0 | integer_to_list(N)];
+pad4(N) when N < 1000 ->
+ [$0 | integer_to_list(N)];
+pad4(N) ->
+ integer_to_list(N).
diff --git a/lib/stdlib/src/dets.erl b/lib/stdlib/src/dets.erl
index 4e3fe0e5c1..0488c2bef2 100644
--- a/lib/stdlib/src/dets.erl
+++ b/lib/stdlib/src/dets.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -616,12 +616,18 @@ next(Tab, Key) ->
%% Assuming that a file already exists, open it with the
%% parameters as already specified in the file itself.
%% Return a ref leading to the file.
-open_file(File) ->
- case dets_server:open_file(to_list(File)) of
- badarg -> % Should not happen.
- erlang:error(dets_process_died, [File]);
- Reply ->
- einval(Reply, [File])
+open_file(File0) ->
+ File = to_list(File0),
+ case is_list(File) of
+ true ->
+ case dets_server:open_file(File) of
+ badarg -> % Should not happen.
+ erlang:error(dets_process_died, [File]);
+ Reply ->
+ einval(Reply, [File])
+ end;
+ false ->
+ erlang:error(badarg, [File0])
end.
-spec open_file(Name, Args) -> {'ok', Name} | {'error', Reason} when
@@ -1088,6 +1094,7 @@ defaults(Tab, Args) ->
debug = false},
Fun = fun repl/2,
Defaults = lists:foldl(Fun, Defaults0, Args),
+ true = is_list(Defaults#open_args.file),
is_comp_min_max(Defaults).
to_list(T) when is_atom(T) -> atom_to_list(T);
@@ -1112,9 +1119,7 @@ repl({delayed_write, {Delay,Size} = C}, Defs)
Defs#open_args{delayed_write = C};
repl({estimated_no_objects, I}, Defs) ->
repl({min_no_slots, I}, Defs);
-repl({file, File}, Defs) when is_list(File) ->
- Defs#open_args{file = File};
-repl({file, File}, Defs) when is_atom(File) ->
+repl({file, File}, Defs) ->
Defs#open_args{file = to_list(File)};
repl({keypos, P}, Defs) when is_integer(P), P > 0 ->
Defs#open_args{keypos =P};
@@ -1288,8 +1293,8 @@ init(Parent, Server) ->
catch
exit:normal ->
exit(normal);
- _:Bad ->
- bug_found(no_name, Op, Bad, From),
+ _:Bad:Stacktrace ->
+ bug_found(no_name, Op, Bad, Stacktrace, From),
exit(Bad) % give up
end
end.
@@ -1371,8 +1376,8 @@ do_apply_op(Op, From, Head, N) ->
catch
exit:normal ->
exit(normal);
- _:Bad ->
- bug_found(Head#head.name, Op, Bad, From),
+ _:Bad:Stacktrace ->
+ bug_found(Head#head.name, Op, Bad, Stacktrace, From),
open_file_loop(Head, N)
end.
@@ -1581,7 +1586,7 @@ apply_op(Op, From, Head, N) ->
ok
end.
-bug_found(Name, Op, Bad, From) ->
+bug_found(Name, Op, Bad, Stacktrace, From) ->
case dets_utils:debug_mode() of
true ->
%% If stream_op/5 found more requests, this is not
@@ -1590,7 +1595,7 @@ bug_found(Name, Op, Bad, From) ->
("** dets: Bug was found when accessing table ~tw,~n"
"** dets: operation was ~tp and reply was ~tw.~n"
"** dets: Stacktrace: ~tw~n",
- [Name, Op, Bad, erlang:get_stacktrace()]);
+ [Name, Op, Bad, Stacktrace]);
false ->
error_logger:format
("** dets: Bug was found when accessing table ~tw~n",
diff --git a/lib/stdlib/src/dets_utils.erl b/lib/stdlib/src/dets_utils.erl
index 17f55ebdc2..12394bd1ad 100644
--- a/lib/stdlib/src/dets_utils.erl
+++ b/lib/stdlib/src/dets_utils.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -377,7 +377,8 @@ corrupt_reason(Head, Reason0) ->
no_disk_map ->
Reason0;
DM ->
- ST = erlang:get_stacktrace(),
+ {current_stacktrace, ST} =
+ erlang:process_info(self(), current_stacktrace),
PD = get(),
{Reason0, ST, PD, DM}
end,
diff --git a/lib/stdlib/src/edlin.erl b/lib/stdlib/src/edlin.erl
index 5df9c504f9..f027d05f55 100644
--- a/lib/stdlib/src/edlin.erl
+++ b/lib/stdlib/src/edlin.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl
index b8e48bff6c..181a524db6 100644
--- a/lib/stdlib/src/epp.erl
+++ b/lib/stdlib/src/epp.erl
@@ -38,7 +38,7 @@
-type epp_handle() :: pid().
-type source_encoding() :: latin1 | utf8.
--type ifdef() :: 'ifdef' | 'ifndef' | 'else'.
+-type ifdef() :: 'ifdef' | 'ifndef' | 'if' | 'else'.
-type name() :: atom().
-type argspec() :: 'none' %No arguments
@@ -117,6 +117,7 @@ open(Name, File, StartLocation, Path, Pdm) ->
{'ok', Epp} | {'ok', Epp, Extra} | {'error', ErrorDescriptor} when
Options :: [{'default_encoding', DefEncoding :: source_encoding()} |
{'includes', IncludePath :: [DirectoryName :: file:name()]} |
+ {'source_name', SourceName :: file:name()} |
{'macros', PredefMacros :: macros()} |
{'name',FileName :: file:name()} |
'extra'],
@@ -221,6 +222,8 @@ format_error({illegal_function,Macro}) ->
io_lib:format("?~s can only be used within a function", [Macro]);
format_error({illegal_function_usage,Macro}) ->
io_lib:format("?~s must not begin a form", [Macro]);
+format_error(elif_after_else) ->
+ "'elif' following 'else'";
format_error({'NYI',What}) ->
io_lib:format("not yet implemented '~s'", [What]);
format_error({error,Term}) ->
@@ -246,6 +249,7 @@ parse_file(Ifile, Path, Predefs) ->
{'ok', [Form]} | {'ok', [Form], Extra} | {error, OpenError} when
FileName :: file:name(),
Options :: [{'includes', IncludePath :: [DirectoryName :: file:name()]} |
+ {'source_name', SourceName :: file:name()} |
{'macros', PredefMacros :: macros()} |
{'default_encoding', DefEncoding :: source_encoding()} |
'extra'],
@@ -479,7 +483,7 @@ com_enc(_B, _Fun, _N, L, Ps) ->
com_enc_end([L | Ps]).
com_enc_end(Ps0) ->
- Ps = lists:reverse([lists:reverse(string:to_lower(P)) || P <- Ps0]),
+ Ps = lists:reverse([lists:reverse(lowercase(P)) || P <- Ps0]),
com_encoding(Ps).
com_encoding(["latin","1"|_]) ->
@@ -489,6 +493,9 @@ com_encoding(["utf","8"|_]) ->
com_encoding(_) ->
throw(no). % Don't try any further
+lowercase(S) ->
+ unicode:characters_to_list(string:lowercase(S)).
+
normalize_typed_record_fields([]) ->
{typed, []};
normalize_typed_record_fields(Fields) ->
@@ -535,9 +542,10 @@ server(Pid, Name, Options, #epp{pre_opened=PreOpened}=St) ->
init_server(Pid, Name, Options, St)
end.
-init_server(Pid, Name, Options, St0) ->
+init_server(Pid, FileName, Options, St0) ->
+ SourceName = proplists:get_value(source_name, Options, FileName),
Pdm = proplists:get_value(macros, Options, []),
- Ms0 = predef_macros(Name),
+ Ms0 = predef_macros(FileName),
case user_predef(Pdm, Ms0) of
{ok,Ms1} ->
#epp{file = File, location = AtLocation} = St0,
@@ -547,14 +555,14 @@ init_server(Pid, Name, Options, St0) ->
epp_reply(Pid, {ok,self(),Encoding}),
%% ensure directory of current source file is
%% first in path
- Path = [filename:dirname(Name) |
+ Path = [filename:dirname(FileName) |
proplists:get_value(includes, Options, [])],
- St = St0#epp{delta=0, name=Name, name2=Name,
+ St = St0#epp{delta=0, name=SourceName, name2=SourceName,
path=Path, macs=Ms1,
default_encoding=DefEncoding},
From = wait_request(St),
Anno = erl_anno:new(AtLocation),
- enter_file_reply(From, file_name(Name), Anno,
+ enter_file_reply(From, file_name(SourceName), Anno,
AtLocation, code),
wait_req_scan(St);
{error,E} ->
@@ -568,6 +576,7 @@ init_server(Pid, Name, Options, St0) ->
predef_macros(File) ->
Machine = list_to_atom(erlang:system_info(machine)),
Anno = line1(),
+ OtpVersion = list_to_integer(erlang:system_info(otp_release)),
Defs = [{'FILE', {none,[{string,Anno,File}]}},
{'FUNCTION_NAME', undefined},
{'FUNCTION_ARITY', undefined},
@@ -577,7 +586,8 @@ predef_macros(File) ->
{'BASE_MODULE', undefined},
{'BASE_MODULE_STRING', undefined},
{'MACHINE', {none,[{atom,Anno,Machine}]}},
- {Machine, {none,[{atom,Anno,true}]}}
+ {Machine, {none,[{atom,Anno,true}]}},
+ {'OTP_RELEASE', {none,[{integer,Anno,OtpVersion}]}}
],
maps:from_list(Defs).
@@ -1082,21 +1092,118 @@ scan_else(_Toks, Else, From, St) ->
epp_reply(From, {error,{loc(Else),epp,{bad,'else'}}}),
wait_req_scan(St).
-%% scan_if(Tokens, EndifToken, From, EppState)
+%% scan_if(Tokens, IfToken, From, EppState)
%% Handle the conditional parsing of a file.
-%% Report a badly formed if test and then treat as false macro.
+scan_if([{'(',_}|_]=Toks, If, From, St) ->
+ try eval_if(Toks, St) of
+ true ->
+ scan_toks(From, St#epp{istk=['if'|St#epp.istk]});
+ _ ->
+ skip_toks(From, St, ['if'])
+ catch
+ throw:Error0 ->
+ Error = case Error0 of
+ {_,erl_parse,_} ->
+ {error,Error0};
+ _ ->
+ {error,{loc(If),epp,Error0}}
+ end,
+ epp_reply(From, Error),
+ wait_req_skip(St, ['if'])
+ end;
scan_if(_Toks, If, From, St) ->
- epp_reply(From, {error,{loc(If),epp,{'NYI','if'}}}),
+ epp_reply(From, {error,{loc(If),epp,{bad,'if'}}}),
wait_req_skip(St, ['if']).
+eval_if(Toks0, St) ->
+ Toks = expand_macros(Toks0, St),
+ Es1 = case erl_parse:parse_exprs(Toks) of
+ {ok,Es0} -> Es0;
+ {error,E} -> throw(E)
+ end,
+ Es = rewrite_expr(Es1, St),
+ assert_guard_expr(Es),
+ Bs = erl_eval:new_bindings(),
+ LocalFun = fun(_Name, _Args) ->
+ error(badarg)
+ end,
+ try erl_eval:exprs(Es, Bs, {value,LocalFun}) of
+ {value,Res,_} ->
+ Res
+ catch
+ _:_ ->
+ false
+ end.
+
+assert_guard_expr([E0]) ->
+ E = rewrite_expr(E0, none),
+ case erl_lint:is_guard_expr(E) of
+ false ->
+ throw({bad,'if'});
+ true ->
+ ok
+ end;
+assert_guard_expr(_) ->
+ throw({bad,'if'}).
+
+%% Dual-purpose rewriting function. When the second argument is
+%% an #epp{} record, calls to defined(Symbol) will be evaluated.
+%% When the second argument is 'none', legal calls to our built-in
+%% functions are eliminated in order to turn the expression into
+%% a legal guard expression.
+
+rewrite_expr({call,_,{atom,_,defined},[N0]}, #epp{macs=Macs}) ->
+ %% Evaluate defined(Symbol).
+ N = case N0 of
+ {var,_,N1} -> N1;
+ {atom,_,N1} -> N1;
+ _ -> throw({bad,'if'})
+ end,
+ {atom,0,maps:is_key(N, Macs)};
+rewrite_expr({call,_,{atom,_,Name},As0}, none) ->
+ As = rewrite_expr(As0, none),
+ Arity = length(As),
+ case erl_internal:bif(Name, Arity) andalso
+ not erl_internal:guard_bif(Name, Arity) of
+ false ->
+ %% A guard BIF, an -if built-in, or an unknown function.
+ %% Eliminate the call so that erl_lint will not complain.
+ %% The call might fail later at evaluation time.
+ to_conses(As);
+ true ->
+ %% An auto-imported BIF (not guard BIF). Not allowed.
+ throw({bad,'if'})
+ end;
+rewrite_expr([H|T], St) ->
+ [rewrite_expr(H, St)|rewrite_expr(T, St)];
+rewrite_expr(Tuple, St) when is_tuple(Tuple) ->
+ list_to_tuple(rewrite_expr(tuple_to_list(Tuple), St));
+rewrite_expr(Other, _) ->
+ Other.
+
+to_conses([H|T]) ->
+ {cons,0,H,to_conses(T)};
+to_conses([]) ->
+ {nil,0}.
+
%% scan_elif(Tokens, EndifToken, From, EppState)
%% Handle the conditional parsing of a file.
%% Report a badly formed if test and then treat as false macro.
scan_elif(_Toks, Elif, From, St) ->
- epp_reply(From, {error,{loc(Elif),epp,{'NYI','elif'}}}),
- wait_req_scan(St).
+ case St#epp.istk of
+ ['else'|Cis] ->
+ epp_reply(From, {error,{loc(Elif),
+ epp,{illegal,"unbalanced",'elif'}}}),
+ wait_req_skip(St#epp{istk=Cis}, ['else']);
+ [_I|Cis] ->
+ skip_toks(From, St#epp{istk=Cis}, ['elif']);
+ [] ->
+ epp_reply(From, {error,{loc(Elif),epp,
+ {illegal,"unbalanced",elif}}}),
+ wait_req_scan(St)
+ end.
%% scan_endif(Tokens, EndifToken, From, EppState)
%% If we are in an if body then exit it, else report an error.
@@ -1155,6 +1262,8 @@ skip_toks(From, St, [I|Sis]) ->
skip_toks(From, St#epp{location=Cl}, ['if',I|Sis]);
{ok,[{'-',_Lh},{atom,_Le,'else'}=Else|_Toks],Cl}->
skip_else(Else, From, St#epp{location=Cl}, [I|Sis]);
+ {ok,[{'-',_Lh},{atom,_Le,'elif'}=Elif|Toks],Cl}->
+ skip_elif(Toks, Elif, From, St#epp{location=Cl}, [I|Sis]);
{ok,[{'-',_Lh},{atom,_Le,endif}|_Toks],Cl} ->
skip_toks(From, St#epp{location=Cl}, Sis);
{ok,_Toks,Cl} ->
@@ -1185,11 +1294,21 @@ skip_toks(From, St, []) ->
skip_else(Else, From, St, ['else'|Sis]) ->
epp_reply(From, {error,{loc(Else),epp,{illegal,"repeated",'else'}}}),
wait_req_skip(St, ['else'|Sis]);
+skip_else(_Else, From, St, ['elif'|Sis]) ->
+ skip_toks(From, St, ['else'|Sis]);
skip_else(_Else, From, St, [_I]) ->
scan_toks(From, St#epp{istk=['else'|St#epp.istk]});
skip_else(_Else, From, St, Sis) ->
skip_toks(From, St, Sis).
+skip_elif(_Toks, Elif, From, St, ['else'|_]=Sis) ->
+ epp_reply(From, {error,{loc(Elif),epp,elif_after_else}}),
+ wait_req_skip(St, Sis);
+skip_elif(Toks, Elif, From, St, [_I]) ->
+ scan_if(Toks, Elif, From, St);
+skip_elif(_Toks, _Elif, From, St, Sis) ->
+ skip_toks(From, St, Sis).
+
%% macro_pars(Tokens, ArgStack)
%% macro_expansion(Tokens, Anno)
%% Extract the macro parameters and the expansion from a macro definition.
diff --git a/lib/stdlib/src/erl_compile.erl b/lib/stdlib/src/erl_compile.erl
index 18d7548fdc..f781312ca2 100644
--- a/lib/stdlib/src/erl_compile.erl
+++ b/lib/stdlib/src/erl_compile.erl
@@ -188,6 +188,8 @@ parse_dep_option("", T) ->
{[makedep,{makedep_output,standard_io}],T};
parse_dep_option("D", T) ->
{[makedep],T};
+parse_dep_option("MD", T) ->
+ {[makedep_side_effect],T};
parse_dep_option("F"++Opt, T0) ->
{File,T} = get_option("MF", Opt, T0),
{[makedep,{makedep_output,File}],T};
@@ -221,6 +223,7 @@ usage() ->
"the dependencies"},
{"-MP","add a phony target for each dependency"},
{"-MD","same as -M -MT file (with default 'file')"},
+ {"-MMD","generate dependencies as a side-effect"},
{"-o name","name output directory or file"},
{"-pa path","add path to the front of Erlang's code path"},
{"-pz path","add path to the end of Erlang's code path"},
diff --git a/lib/stdlib/src/erl_error.erl b/lib/stdlib/src/erl_error.erl
new file mode 100644
index 0000000000..fdcb9e824c
--- /dev/null
+++ b/lib/stdlib/src/erl_error.erl
@@ -0,0 +1,421 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(erl_error).
+
+-export([format_exception/6, format_exception/7,
+ format_stacktrace/4, format_stacktrace/5,
+ format_call/4, format_call/5, format_fun/1, format_fun/2]).
+
+%%% Formatting of exceptions, mfa:s and funs.
+
+%% -> iolist() (no \n at end)
+%% I is the current column, starting from 1 (it will be used
+%% as indentation whenever newline has been inserted);
+%% Class, Reason and StackTrace are the exception;
+%% FormatFun = fun(Term, I) -> iolist() formats terms;
+%% StackFun = fun(Mod, Fun, Arity) -> boolean() is used for trimming the
+%% end of the stack (typically calls to erl_eval are skipped).
+format_exception(I, Class, Reason, StackTrace, StackFun, FormatFun) ->
+ format_exception(I, Class, Reason, StackTrace, StackFun, FormatFun,
+ latin1).
+
+%% -> iolist() | unicode:charlist() (no \n at end)
+%% FormatFun = fun(Term, I) -> iolist() | unicode:charlist().
+format_exception(I, Class, Reason, StackTrace, StackFun, FormatFun, Encoding)
+ when is_integer(I), I >= 1, is_function(StackFun, 3),
+ is_function(FormatFun, 2) ->
+ S = n_spaces(I-1),
+ {Term,Trace1,Trace} = analyze_exception(Class, Reason, StackTrace),
+ Expl0 = explain_reason(Term, Class, Trace1, FormatFun, S, Encoding),
+ FormatString = case Encoding of
+ latin1 -> "~s~s";
+ _ -> "~s~ts"
+ end,
+ Expl = io_lib:fwrite(FormatString, [exited(Class), Expl0]),
+ case format_stacktrace1(S, Trace, FormatFun, StackFun, Encoding) of
+ [] -> Expl;
+ Stack -> [Expl, $\n, Stack]
+ end.
+
+%% -> iolist() (no \n at end)
+format_stacktrace(I, StackTrace, StackFun, FormatFun) ->
+ format_stacktrace(I, StackTrace, StackFun, FormatFun, latin1).
+
+%% -> iolist() | unicode:charlist() (no \n at end)
+format_stacktrace(I, StackTrace, StackFun, FormatFun, Encoding)
+ when is_integer(I), I >= 1, is_function(StackFun, 3),
+ is_function(FormatFun, 2) ->
+ S = n_spaces(I-1),
+ format_stacktrace1(S, StackTrace, FormatFun, StackFun, Encoding).
+
+%% -> iolist() (no \n at end)
+format_call(I, ForMForFun, As, FormatFun) ->
+ format_call(I, ForMForFun, As, FormatFun, latin1).
+
+%% -> iolist() | unicode:charlist() (no \n at end)
+format_call(I, ForMForFun, As, FormatFun, Enc)
+ when is_integer(I), I >= 1, is_list(As), is_function(FormatFun, 2) ->
+ format_call("", n_spaces(I-1), ForMForFun, As, FormatFun, Enc).
+
+%% -> iolist() (no \n at end)
+format_fun(Fun) ->
+ format_fun(Fun, latin1).
+
+%% -> iolist() (no \n at end)
+format_fun(Fun, Enc) when is_function(Fun) ->
+ {module, M} = erlang:fun_info(Fun, module),
+ {name, F} = erlang:fun_info(Fun, name),
+ {arity, A} = erlang:fun_info(Fun, arity),
+ case erlang:fun_info(Fun, type) of
+ {type, local} when F =:= "" ->
+ io_lib:fwrite(<<"~w">>, [Fun]);
+ {type, local} when M =:= erl_eval ->
+ io_lib:fwrite(<<"interpreted function with arity ~w">>, [A]);
+ {type, local} ->
+ mfa_to_string(M, F, A, Enc);
+ {type, external} ->
+ mfa_to_string(M, F, A, Enc)
+ end.
+
+analyze_exception(error, Term, Stack) ->
+ case {is_stacktrace(Stack), Stack, Term} of
+ {true, [{_,_,As,_}=MFAL|MFAs], function_clause} when is_list(As) ->
+ {Term,[MFAL],MFAs};
+ {true, [{shell,F,A,_}], function_clause} when is_integer(A) ->
+ {Term, [{F,A}], []};
+ {true, [{_,_,_,_}=MFAL|MFAs], undef} ->
+ {Term,[MFAL],MFAs};
+ {true, _, _} ->
+ {Term,[],Stack};
+ {false, _, _} ->
+ {{Term,Stack},[],[]}
+ end;
+analyze_exception(_Class, Term, Stack) ->
+ case is_stacktrace(Stack) of
+ true ->
+ {Term,[],Stack};
+ false ->
+ {{Term,Stack},[],[]}
+ end.
+
+is_stacktrace([]) ->
+ true;
+is_stacktrace([{M,F,A,I}|Fs])
+ when is_atom(M), is_atom(F), is_integer(A), is_list(I) ->
+ is_stacktrace(Fs);
+is_stacktrace([{M,F,As,I}|Fs])
+ when is_atom(M), is_atom(F), length(As) >= 0, is_list(I) ->
+ is_stacktrace(Fs);
+is_stacktrace(_) ->
+ false.
+
+%% ERTS exit codes (some of them are also returned by erl_eval):
+explain_reason(badarg, error, [], _PF, _S, _Enc) ->
+ <<"bad argument">>;
+explain_reason({badarg,V}, error=Cl, [], PF, S, _Enc) -> % orelse, andalso
+ format_value(V, <<"bad argument: ">>, Cl, PF, S);
+explain_reason(badarith, error, [], _PF, _S, _Enc) ->
+ <<"an error occurred when evaluating an arithmetic expression">>;
+explain_reason({badarity,{Fun,As}}, error, [], _PF, _S, Enc)
+ when is_function(Fun) ->
+ %% Only the arity is displayed, not the arguments As.
+ io_lib:fwrite(<<"~ts called with ~s">>,
+ [format_fun(Fun, Enc), argss(length(As))]);
+explain_reason({badfun,Term}, error=Cl, [], PF, S, _Enc) ->
+ format_value(Term, <<"bad function ">>, Cl, PF, S);
+explain_reason({badmatch,Term}, error=Cl, [], PF, S, _Enc) ->
+ Str = <<"no match of right hand side value ">>,
+ format_value(Term, Str, Cl, PF, S);
+explain_reason({case_clause,V}, error=Cl, [], PF, S, _Enc) ->
+ %% "there is no case clause with a true guard sequence and a
+ %% pattern matching..."
+ format_value(V, <<"no case clause matching ">>, Cl, PF, S);
+explain_reason(function_clause, error, [{F,A}], _PF, _S, _Enc) ->
+ %% Shell commands
+ FAs = io_lib:fwrite(<<"~w/~w">>, [F, A]),
+ [<<"no function clause matching call to ">> | FAs];
+explain_reason(function_clause, error=Cl, [{M,F,As,Loc}], PF, S, Enc) ->
+ Str = <<"no function clause matching ">>,
+ [format_errstr_call(Str, Cl, {M,F}, As, PF, S, Enc),$\s|location(Loc)];
+explain_reason(if_clause, error, [], _PF, _S, _Enc) ->
+ <<"no true branch found when evaluating an if expression">>;
+explain_reason(noproc, error, [], _PF, _S, _Enc) ->
+ <<"no such process or port">>;
+explain_reason(notalive, error, [], _PF, _S, _Enc) ->
+ <<"the node cannot be part of a distributed system">>;
+explain_reason(system_limit, error, [], _PF, _S, _Enc) ->
+ <<"a system limit has been reached">>;
+explain_reason(timeout_value, error, [], _PF, _S, _Enc) ->
+ <<"bad receive timeout value">>;
+explain_reason({try_clause,V}, error=Cl, [], PF, S, _Enc) ->
+ %% "there is no try clause with a true guard sequence and a
+ %% pattern matching..."
+ format_value(V, <<"no try clause matching ">>, Cl, PF, S);
+explain_reason(undef, error, [{M,F,A,_}], _PF, _S, Enc) ->
+ %% Only the arity is displayed, not the arguments, if there are any.
+ io_lib:fwrite(<<"undefined function ~ts">>,
+ [mfa_to_string(M, F, n_args(A), Enc)]);
+explain_reason({shell_undef,F,A,_}, error, [], _PF, _S, Enc) ->
+ %% Give nicer reports for undefined shell functions
+ %% (but not when the user actively calls shell_default:F(...)).
+ FS = to_string(F, Enc),
+ io_lib:fwrite(<<"undefined shell command ~ts/~w">>, [FS, n_args(A)]);
+%% Exit codes returned by erl_eval only:
+explain_reason({argument_limit,_Fun}, error, [], _PF, _S, _Enc) ->
+ io_lib:fwrite(<<"limit of number of arguments to interpreted function"
+ " exceeded">>, []);
+explain_reason({bad_filter,V}, error=Cl, [], PF, S, _Enc) ->
+ format_value(V, <<"bad filter ">>, Cl, PF, S);
+explain_reason({bad_generator,V}, error=Cl, [], PF, S, _Enc) ->
+ format_value(V, <<"bad generator ">>, Cl, PF, S);
+explain_reason({unbound,V}, error, [], _PF, _S, _Enc) ->
+ io_lib:fwrite(<<"variable ~w is unbound">>, [V]);
+%% Exit codes local to the shell module (restricted shell):
+explain_reason({restricted_shell_bad_return, V}, exit=Cl, [], PF, S, _Enc) ->
+ Str = <<"restricted shell module returned bad value ">>,
+ format_value(V, Str, Cl, PF, S);
+explain_reason({restricted_shell_disallowed,{ForMF,As}},
+ exit=Cl, [], PF, S, Enc) ->
+ %% ForMF can be a fun, but not a shell fun.
+ Str = <<"restricted shell does not allow ">>,
+ format_errstr_call(Str, Cl, ForMF, As, PF, S, Enc);
+explain_reason(restricted_shell_started, exit, [], _PF, _S, _Enc) ->
+ <<"restricted shell starts now">>;
+explain_reason(restricted_shell_stopped, exit, [], _PF, _S, _Enc) ->
+ <<"restricted shell stopped">>;
+%% Other exit code:
+explain_reason(Reason, Class, [], PF, S, _Enc) ->
+ PF(Reason, (iolist_size(S)+1) + exited_size(Class)).
+
+n_args(A) when is_integer(A) ->
+ A;
+n_args(As) when is_list(As) ->
+ length(As).
+
+argss(0) ->
+ <<"no arguments">>;
+argss(1) ->
+ <<"one argument">>;
+argss(2) ->
+ <<"two arguments">>;
+argss(I) ->
+ io_lib:fwrite(<<"~w arguments">>, [I]).
+
+format_stacktrace1(S0, Stack0, PF, SF, Enc) ->
+ Stack1 = lists:dropwhile(fun({M,F,A,_}) -> SF(M, F, A)
+ end, lists:reverse(Stack0)),
+ S = [" " | S0],
+ Stack = lists:reverse(Stack1),
+ format_stacktrace2(S, Stack, 1, PF, Enc).
+
+format_stacktrace2(S, [{M,F,A,L}|Fs], N, PF, Enc) when is_integer(A) ->
+ [io_lib:fwrite(<<"~s~s ~ts ~ts">>,
+ [sep(N, S), origin(N, M, F, A),
+ mfa_to_string(M, F, A, Enc),
+ location(L)])
+ | format_stacktrace2(S, Fs, N + 1, PF, Enc)];
+format_stacktrace2(S, [{M,F,As,_}|Fs], N, PF, Enc) when is_list(As) ->
+ A = length(As),
+ CalledAs = [S,<<" called as ">>],
+ C = format_call("", CalledAs, {M,F}, As, PF, Enc),
+ [io_lib:fwrite(<<"~s~s ~ts\n~s~ts">>,
+ [sep(N, S), origin(N, M, F, A),
+ mfa_to_string(M, F, A, Enc),
+ CalledAs, C])
+ | format_stacktrace2(S, Fs, N + 1, PF, Enc)];
+format_stacktrace2(_S, [], _N, _PF, _Enc) ->
+ "".
+
+location(L) ->
+ File = proplists:get_value(file, L),
+ Line = proplists:get_value(line, L),
+ if
+ File =/= undefined, Line =/= undefined ->
+ io_lib:format("(~ts, line ~w)", [File, Line]);
+ true ->
+ ""
+ end.
+
+sep(1, S) -> S;
+sep(_, S) -> [$\n | S].
+
+origin(1, M, F, A) ->
+ case is_op({M, F}, n_args(A)) of
+ {yes, F} -> <<"in operator ">>;
+ no -> <<"in function ">>
+ end;
+origin(_N, _M, _F, _A) ->
+ <<"in call from">>.
+
+format_errstr_call(ErrStr, Class, ForMForFun, As, PF, Pre0, Enc) ->
+ Pre1 = [Pre0 | n_spaces(exited_size(Class))],
+ format_call(ErrStr, Pre1, ForMForFun, As, PF, Enc).
+
+format_call(ErrStr, Pre1, ForMForFun, As, PF, Enc) ->
+ Arity = length(As),
+ [ErrStr |
+ case is_op(ForMForFun, Arity) of
+ {yes,Op} ->
+ format_op(ErrStr, Pre1, Op, As, PF, Enc);
+ no ->
+ MFs = mf_to_string(ForMForFun, Arity, Enc),
+ I1 = string:length([Pre1,ErrStr|MFs]),
+ S1 = pp_arguments(PF, As, I1, Enc),
+ S2 = pp_arguments(PF, As, string:length([Pre1|MFs]), Enc),
+ Long = count_nl(pp_arguments(PF, [a2345,b2345], I1, Enc)) > 0,
+ case Long or (count_nl(S2) < count_nl(S1)) of
+ true ->
+ [$\n, Pre1, MFs, S2];
+ false ->
+ [MFs, S1]
+ end
+ end].
+
+format_op(ErrStr, Pre, Op, [A1], PF, _Enc) ->
+ OpS = io_lib:fwrite(<<"~s ">>, [Op]),
+ I1 = iolist_size([ErrStr,Pre,OpS]),
+ [OpS | PF(A1, I1+1)];
+format_op(ErrStr, Pre, Op, [A1, A2], PF, Enc) ->
+ I1 = iolist_size([ErrStr,Pre]),
+ S1 = PF(A1, I1+1),
+ S2 = PF(A2, I1+1),
+ OpS = atom_to_list(Op),
+ Pre1 = [$\n | n_spaces(I1)],
+ case count_nl(S1) > 0 of
+ true ->
+ [S1,Pre1,OpS,Pre1|S2];
+ false ->
+ OpS2 = io_lib:fwrite(<<" ~s ">>, [Op]),
+ Size1 = iolist_size([ErrStr,Pre|OpS2]),
+ {Size2,S1_2} = size(Enc, S1),
+ S2_2 = PF(A2, Size1+Size2+1),
+ case count_nl(S2) < count_nl(S2_2) of
+ true ->
+ [S1_2,Pre1,OpS,Pre1|S2];
+ false ->
+ [S1_2,OpS2|S2_2]
+ end
+ end.
+
+pp_arguments(PF, As, I, Enc) ->
+ case {As, printable_list(Enc, As)} of
+ {[Int | T], true} ->
+ L = integer_to_list(Int),
+ Ll = length(L),
+ A = list_to_atom(lists:duplicate(Ll, $a)),
+ S0 = unicode:characters_to_list(PF([A | T], I+1), Enc),
+ brackets_to_parens([$[,L,string:slice(S0, 1+Ll)], Enc);
+ _ ->
+ brackets_to_parens(PF(As, I+1), Enc)
+ end.
+
+brackets_to_parens(S, Enc) ->
+ B = unicode:characters_to_binary(S, Enc),
+ Sz = byte_size(B) - 2,
+ <<$[,R:Sz/binary,$]>> = B,
+ [$(,R,$)].
+
+printable_list(latin1, As) ->
+ io_lib:printable_latin1_list(As);
+printable_list(_, As) ->
+ io_lib:printable_list(As).
+
+mfa_to_string(M, F, A, Enc) ->
+ io_lib:fwrite(<<"~ts/~w">>, [mf_to_string({M, F}, A, Enc), A]).
+
+mf_to_string({M, F}, A, Enc) ->
+ case erl_internal:bif(M, F, A) of
+ true ->
+ io_lib:fwrite(<<"~w">>, [F]);
+ false ->
+ case is_op({M, F}, A) of
+ {yes, '/'} ->
+ io_lib:fwrite(<<"~w">>, [F]);
+ {yes, F} ->
+ atom_to_list(F);
+ no ->
+ FS = to_string(F, Enc),
+ io_lib:fwrite(<<"~w:~ts">>, [M, FS])
+ end
+ end;
+mf_to_string(Fun, _A, Enc) when is_function(Fun) ->
+ format_fun(Fun, Enc);
+mf_to_string(F, _A, Enc) ->
+ FS = to_string(F, Enc),
+ io_lib:fwrite(<<"~ts">>, [FS]).
+
+format_value(V, ErrStr, Class, PF, S) ->
+ Pre1Sz = exited_size(Class),
+ S1 = PF(V, Pre1Sz + iolist_size([S, ErrStr])+1),
+ [ErrStr | case count_nl(S1) of
+ N1 when N1 > 1 ->
+ S2 = PF(V, iolist_size(S) + 1 + Pre1Sz),
+ case count_nl(S2) < N1 of
+ true ->
+ [$\n, S, n_spaces(Pre1Sz) | S2];
+ false ->
+ S1
+ end;
+ _ ->
+ S1
+ end].
+
+%% Handles deep lists, but not all iolists.
+count_nl([E | Es]) ->
+ count_nl(E) + count_nl(Es);
+count_nl($\n) ->
+ 1;
+count_nl(Bin) when is_binary(Bin) ->
+ count_nl(binary_to_list(Bin));
+count_nl(_) ->
+ 0.
+
+n_spaces(N) ->
+ lists:duplicate(N, $\s).
+
+is_op(ForMForFun, A) ->
+ try
+ {erlang,F} = ForMForFun,
+ _ = erl_internal:op_type(F, A),
+ {yes,F}
+ catch error:_ -> no
+ end.
+
+exited_size(Class) ->
+ iolist_size(exited(Class)).
+
+exited(error) ->
+ <<"exception error: ">>;
+exited(exit) ->
+ <<"exception exit: ">>;
+exited(throw) ->
+ <<"exception throw: ">>.
+
+to_string(A, latin1) ->
+ io_lib:write_atom_as_latin1(A);
+to_string(A, _) ->
+ io_lib:write_atom(A).
+
+size(latin1, S) ->
+ {iolist_size(S),S};
+size(_, S0) ->
+ S = unicode:characters_to_list(S0, unicode),
+ true = is_list(S),
+ {string:length(S),S}.
diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl
index eafee346eb..2066b2f60f 100644
--- a/lib/stdlib/src/erl_eval.erl
+++ b/lib/stdlib/src/erl_eval.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -27,8 +27,9 @@
-export([exprs/2,exprs/3,exprs/4,expr/2,expr/3,expr/4,expr/5,
expr_list/2,expr_list/3,expr_list/4]).
-export([new_bindings/0,bindings/1,binding/2,add_binding/3,del_binding/2]).
-
--export([is_constant_expr/1, partial_eval/1]).
+-export([extended_parse_exprs/1, extended_parse_term/1,
+ subst_values_for_vars/2]).
+-export([is_constant_expr/1, partial_eval/1, eval_str/1]).
%% Is used by standalone Erlang (escript).
%% Also used by shell.erl.
@@ -69,6 +70,9 @@
-type(non_local_function_handler() :: {value, nlfun_handler()}
| none).
+-define(STACKTRACE,
+ element(2, erlang:process_info(self(), current_stacktrace))).
+
%% exprs(ExpressionSeq, Bindings)
%% exprs(ExpressionSeq, Bindings, LocalFuncHandler)
%% exprs(ExpressionSeq, Bindings, LocalFuncHandler, ExternalFuncHandler)
@@ -90,7 +94,7 @@ exprs(Exprs, Bs) ->
ok ->
exprs(Exprs, Bs, none, none, none);
{error,{_Line,_Mod,Error}} ->
- erlang:raise(error, Error, [{?MODULE,exprs,2}])
+ erlang:raise(error, Error, ?STACKTRACE)
end.
-spec(exprs(Expressions, Bindings, LocalFunctionHandler) ->
@@ -141,7 +145,7 @@ expr(E, Bs) ->
ok ->
expr(E, Bs, none, none, none);
{error,{_Line,_Mod,Error}} ->
- erlang:raise(error, Error, [{?MODULE,expr,2}])
+ erlang:raise(error, Error, ?STACKTRACE)
end.
-spec(expr(Expression, Bindings, LocalFunctionHandler) ->
@@ -182,7 +186,7 @@ check_command(Es, Bs) ->
fun_data(F) when is_function(F) ->
case erlang:fun_info(F, module) of
- {module,erl_eval} ->
+ {module,?MODULE} ->
case erlang:fun_info(F, env) of
{env,[{FBs,_FLf,_FEf,FCs}]} ->
{fun_data,FBs,FCs};
@@ -209,8 +213,8 @@ expr({var,_,V}, Bs, _Lf, _Ef, RBs) ->
case binding(V, Bs) of
{value,Val} ->
ret_expr(Val, Bs, RBs);
- unbound -> % Should not happen.
- erlang:raise(error, {unbound,V}, stacktrace())
+ unbound -> % Cannot not happen if checked by erl_lint
+ erlang:raise(error, {unbound,V}, ?STACKTRACE)
end;
expr({char,_,C}, Bs, _Lf, _Ef, RBs) ->
ret_expr(C, Bs, RBs);
@@ -236,13 +240,13 @@ expr({tuple,_,Es}, Bs0, Lf, Ef, RBs) ->
{Vs,Bs} = expr_list(Es, Bs0, Lf, Ef),
ret_expr(list_to_tuple(Vs), Bs, RBs);
expr({record_field,_,_,Name,_}, _Bs, _Lf, _Ef, _RBs) ->
- erlang:raise(error, {undef_record,Name}, stacktrace());
+ erlang:raise(error, {undef_record,Name}, ?STACKTRACE);
expr({record_index,_,Name,_}, _Bs, _Lf, _Ef, _RBs) ->
- erlang:raise(error, {undef_record,Name}, stacktrace());
+ erlang:raise(error, {undef_record,Name}, ?STACKTRACE);
expr({record,_,Name,_}, _Bs, _Lf, _Ef, _RBs) ->
- erlang:raise(error, {undef_record,Name}, stacktrace());
+ erlang:raise(error, {undef_record,Name}, ?STACKTRACE);
expr({record,_,_,Name,_}, _Bs, _Lf, _Ef, _RBs) ->
- erlang:raise(error, {undef_record,Name}, stacktrace());
+ erlang:raise(error, {undef_record,Name}, ?STACKTRACE);
%% map
expr({map,_,Binding,Es}, Bs0, Lf, Ef, RBs) ->
@@ -281,7 +285,7 @@ expr({'fun',_Line,{function,Mod0,Name0,Arity0}}, Bs0, Lf, Ef, RBs) ->
ret_expr(F, Bs, RBs);
expr({'fun',_Line,{function,Name,Arity}}, _Bs0, _Lf, _Ef, _RBs) -> % R8
%% Don't know what to do...
- erlang:raise(error, undef, [{erl_eval,Name,Arity}|stacktrace()]);
+ erlang:raise(error, undef, [{?MODULE,Name,Arity}|?STACKTRACE]);
expr({'fun',Line,{clauses,Cs}} = Ex, Bs, Lf, Ef, RBs) ->
%% Save only used variables in the function environment.
%% {value,L,V} are hidden while lint finds used variables.
@@ -325,8 +329,9 @@ expr({'fun',Line,{clauses,Cs}} = Ex, Bs, Lf, Ef, RBs) ->
20 -> fun (A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T) ->
eval_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T], Info) end;
_Other ->
- erlang:raise(error, {'argument_limit',{'fun',Line,Cs}},
- stacktrace())
+ L = erl_anno:location(Line),
+ erlang:raise(error, {'argument_limit',{'fun',L,to_terms(Cs)}},
+ ?STACKTRACE)
end,
ret_expr(F, Bs, RBs);
expr({named_fun,Line,Name,Cs} = Ex, Bs, Lf, Ef, RBs) ->
@@ -377,8 +382,10 @@ expr({named_fun,Line,Name,Cs} = Ex, Bs, Lf, Ef, RBs) ->
eval_named_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T],
RF, Info) end;
_Other ->
- erlang:raise(error, {'argument_limit',{named_fun,Line,Name,Cs}},
- stacktrace())
+ L = erl_anno:location(Line),
+ erlang:raise(error, {'argument_limit',
+ {named_fun,L,Name,to_terms(Cs)}},
+ ?STACKTRACE)
end,
ret_expr(F, Bs, RBs);
expr({call,_,{remote,_,{atom,_,qlc},{atom,_,q}},[{lc,_,_E,_Qs}=LC | As0]},
@@ -422,25 +429,28 @@ expr({call,_,Func0,As0}, Bs0, Lf, Ef, RBs) -> % function or {Mod,Fun}
{As,Bs2} = expr_list(As0, Bs1, Lf, Ef),
case Func of
{M,F} when is_atom(M), is_atom(F) ->
- erlang:raise(error, {badfun,Func}, stacktrace());
+ erlang:raise(error, {badfun,Func}, ?STACKTRACE);
_ ->
do_apply(Func, As, Bs2, Ef, RBs)
end;
expr({'catch',_,Expr}, Bs0, Lf, Ef, RBs) ->
- Ref = make_ref(),
- case catch {Ref,expr(Expr, Bs0, Lf, Ef, none)} of
- {Ref,{value,V,Bs}} -> % Nothing was thrown (guaranteed).
- ret_expr(V, Bs, RBs);
- Other ->
- ret_expr(Other, Bs0, RBs)
+ try expr(Expr, Bs0, Lf, Ef, none) of
+ {value,V,Bs} ->
+ ret_expr(V, Bs, RBs)
+ catch
+ throw:Term ->
+ ret_expr(Term, Bs0, RBs);
+ exit:Reason ->
+ ret_expr({'EXIT',Reason}, Bs0, RBs);
+ error:Reason:Stacktrace ->
+ ret_expr({'EXIT',{Reason,Stacktrace}}, Bs0, RBs)
end;
expr({match,_,Lhs,Rhs0}, Bs0, Lf, Ef, RBs) ->
{value,Rhs,Bs1} = expr(Rhs0, Bs0, Lf, Ef, none),
case match(Lhs, Rhs, Bs1) of
{match,Bs} ->
ret_expr(Rhs, Bs, RBs);
- nomatch ->
- erlang:raise(error, {badmatch,Rhs}, stacktrace())
+ nomatch -> erlang:raise(error, {badmatch,Rhs}, ?STACKTRACE)
end;
expr({op,_,Op,A0}, Bs0, Lf, Ef, RBs) ->
{value,A,Bs} = expr(A0, Bs0, Lf, Ef, none),
@@ -452,7 +462,7 @@ expr({op,_,'andalso',L0,R0}, Bs0, Lf, Ef, RBs) ->
{value,R,_} = expr(R0, Bs1, Lf, Ef, none),
R;
false -> false;
- _ -> erlang:raise(error, {badarg,L}, stacktrace())
+ _ -> erlang:raise(error, {badarg,L}, ?STACKTRACE)
end,
ret_expr(V, Bs1, RBs);
expr({op,_,'orelse',L0,R0}, Bs0, Lf, Ef, RBs) ->
@@ -462,7 +472,7 @@ expr({op,_,'orelse',L0,R0}, Bs0, Lf, Ef, RBs) ->
false ->
{value,R,_} = expr(R0, Bs1, Lf, Ef, none),
R;
- _ -> erlang:raise(error, {badarg,L}, stacktrace())
+ _ -> erlang:raise(error, {badarg,L}, ?STACKTRACE)
end,
ret_expr(V, Bs1, RBs);
expr({op,_,Op,L0,R0}, Bs0, Lf, Ef, RBs) ->
@@ -474,7 +484,7 @@ expr({bin,_,Fs}, Bs0, Lf, Ef, RBs) ->
{value,V,Bs} = eval_bits:expr_grp(Fs, Bs0, EvalFun),
ret_expr(V, Bs, RBs);
expr({remote,_,_,_}, _Bs, _Lf, _Ef, _RBs) ->
- erlang:raise(error, {badexpr,':'}, stacktrace());
+ erlang:raise(error, {badexpr,':'}, ?STACKTRACE);
expr({value,_,Val}, Bs, _Lf, _Ef, RBs) -> % Special case straight values.
ret_expr(Val, Bs, RBs).
@@ -570,7 +580,7 @@ local_func(Func, As, _Bs, {M,F,Eas}, _Ef, RBs) ->
local_func2(apply(M, F, [Func,As|Eas]), RBs);
%% Default unknown function handler to undefined function.
local_func(Func, As0, _Bs0, none, _Ef, _RBs) ->
- erlang:raise(error, undef, [{erl_eval,Func,length(As0)}|stacktrace()]).
+ erlang:raise(error, undef, [{?MODULE,Func,length(As0)}|?STACKTRACE]).
local_func2({value,V,Bs}, RBs) ->
ret_expr(V, Bs, RBs);
@@ -637,7 +647,7 @@ do_apply(Func, As, Bs0, Ef, RBs) ->
{{arity, Arity}, Arity} ->
eval_fun(FCs, As, FBs, FLf, FEf, NRBs);
_ ->
- erlang:raise(error, {badarity,{Func,As}},stacktrace())
+ erlang:raise(error, {badarity,{Func,As}},?STACKTRACE)
end;
{{env,[{FBs,FLf,FEf,FCs,FName}]},_} ->
NRBs = if
@@ -648,7 +658,7 @@ do_apply(Func, As, Bs0, Ef, RBs) ->
{{arity, Arity}, Arity} ->
eval_named_fun(FCs, As, FBs, FLf, FEf, FName, Func, NRBs);
_ ->
- erlang:raise(error, {badarity,{Func,As}},stacktrace())
+ erlang:raise(error, {badarity,{Func,As}},?STACKTRACE)
end;
{no_env,none} when RBs =:= value ->
%% Make tail recursive calls when possible.
@@ -730,7 +740,7 @@ eval_generate([V|Rest], P, Bs0, Lf, Ef, CompFun, Acc) ->
eval_generate([], _P, _Bs0, _Lf, _Ef, _CompFun, Acc) ->
Acc;
eval_generate(Term, _P, _Bs0, _Lf, _Ef, _CompFun, _Acc) ->
- erlang:raise(error, {bad_generator,Term}, stacktrace()).
+ erlang:raise(error, {bad_generator,Term}, ?STACKTRACE).
eval_b_generate(<<_/bitstring>>=Bin, P, Bs0, Lf, Ef, CompFun, Acc) ->
Mfun = match_fun(Bs0),
@@ -746,7 +756,7 @@ eval_b_generate(<<_/bitstring>>=Bin, P, Bs0, Lf, Ef, CompFun, Acc) ->
Acc
end;
eval_b_generate(Term, _P, _Bs0, _Lf, _Ef, _CompFun, _Acc) ->
- erlang:raise(error, {bad_generator,Term}, stacktrace()).
+ erlang:raise(error, {bad_generator,Term}, ?STACKTRACE).
eval_filter(F, Bs0, Lf, Ef, CompFun, Acc) ->
case erl_lint:is_guard_test(F) of
@@ -760,7 +770,7 @@ eval_filter(F, Bs0, Lf, Ef, CompFun, Acc) ->
{value,true,Bs1} -> CompFun(Bs1);
{value,false,_} -> Acc;
{value,V,_} ->
- erlang:raise(error, {bad_filter,V}, stacktrace())
+ erlang:raise(error, {bad_filter,V}, ?STACKTRACE)
end
end.
@@ -816,7 +826,7 @@ eval_fun([{clause,_,H,G,B}|Cs], As, Bs0, Lf, Ef, RBs) ->
end;
eval_fun([], As, _Bs, _Lf, _Ef, _RBs) ->
erlang:raise(error, function_clause,
- [{?MODULE,'-inside-an-interpreted-fun-',As}|stacktrace()]).
+ [{?MODULE,'-inside-an-interpreted-fun-',As}|?STACKTRACE]).
eval_named_fun(As, Fun, {Bs0,Lf,Ef,Cs,Name}) ->
@@ -836,7 +846,7 @@ eval_named_fun([{clause,_,H,G,B}|Cs], As, Bs0, Lf, Ef, Name, Fun, RBs) ->
end;
eval_named_fun([], As, _Bs, _Lf, _Ef, _Name, _Fun, _RBs) ->
erlang:raise(error, function_clause,
- [{?MODULE,'-inside-an-interpreted-fun-',As}|stacktrace()]).
+ [{?MODULE,'-inside-an-interpreted-fun-',As}|?STACKTRACE]).
%% expr_list(ExpressionList, Bindings)
@@ -894,13 +904,13 @@ if_clauses([{clause,_,[],G,B}|Cs], Bs, Lf, Ef, RBs) ->
false -> if_clauses(Cs, Bs, Lf, Ef, RBs)
end;
if_clauses([], _Bs, _Lf, _Ef, _RBs) ->
- erlang:raise(error, if_clause, stacktrace()).
+ erlang:raise(error, if_clause, ?STACKTRACE).
%% try_clauses(Body, CaseClauses, CatchClauses, AfterBody, Bindings,
%% LocalFuncHandler, ExtFuncHandler, RBs)
-%% When/if variable bindings between the different parts of a
-%% try-catch expression are introduced this will have to be rewritten.
+
try_clauses(B, Cases, Catches, AB, Bs, Lf, Ef, RBs) ->
+ check_stacktrace_vars(Catches, Bs),
try exprs(B, Bs, Lf, Ef, none) of
{value,V,Bs1} when Cases =:= [] ->
ret_expr(V, Bs1, RBs);
@@ -909,23 +919,18 @@ try_clauses(B, Cases, Catches, AB, Bs, Lf, Ef, RBs) ->
{B2,Bs2} ->
exprs(B2, Bs2, Lf, Ef, RBs);
nomatch ->
- erlang:raise(error, {try_clause,V}, stacktrace())
+ erlang:raise(error, {try_clause,V}, ?STACKTRACE)
end
catch
- Class:Reason when Catches =:= [] ->
- %% Rethrow
- erlang:raise(Class, Reason, stacktrace());
- Class:Reason ->
-%%% %% Set stacktrace
-%%% try erlang:raise(Class, Reason, stacktrace())
-%%% catch _:_ -> ok
-%%% end,
- V = {Class,Reason,erlang:get_stacktrace()},
- case match_clause(Catches, [V],Bs, Lf, Ef) of
+ Class:Reason:Stacktrace when Catches =:= [] ->
+ erlang:raise(Class, Reason, Stacktrace);
+ Class:Reason:Stacktrace ->
+ V = {Class,Reason,Stacktrace},
+ case match_clause(Catches, [V], Bs, Lf, Ef) of
{B2,Bs2} ->
exprs(B2, Bs2, Lf, Ef, RBs);
nomatch ->
- erlang:raise(Class, Reason, stacktrace())
+ erlang:raise(Class, Reason, Stacktrace)
end
after
if AB =:= [] ->
@@ -935,6 +940,23 @@ try_clauses(B, Cases, Catches, AB, Bs, Lf, Ef, RBs) ->
end
end.
+check_stacktrace_vars([{clause,_,[{tuple,_,[_,_,STV]}],_,_}|Cs], Bs) ->
+ case STV of
+ {var,_,V} ->
+ case binding(V, Bs) of
+ {value, _} ->
+ erlang:raise(error, stacktrace_bound, ?STACKTRACE);
+ unbound ->
+ check_stacktrace_vars(Cs, Bs)
+ end;
+ _ ->
+ erlang:raise(error,
+ {illegal_stacktrace_variable,STV},
+ ?STACKTRACE)
+ end;
+check_stacktrace_vars([], _Bs) ->
+ ok.
+
%% case_clauses(Value, Clauses, Bindings, LocalFuncHandler, ExtFuncHandler,
%% RBs)
@@ -943,7 +965,7 @@ case_clauses(Val, Cs, Bs, Lf, Ef, RBs) ->
{B, Bs1} ->
exprs(B, Bs1, Lf, Ef, RBs);
nomatch ->
- erlang:raise(error, {case_clause,Val}, stacktrace())
+ erlang:raise(error, {case_clause,Val}, ?STACKTRACE)
end.
%%
@@ -1018,7 +1040,7 @@ guard0([G|Gs], Bs0, Lf, Ef) ->
{value,false,_} -> false
end;
false ->
- erlang:raise(error, guard_expr, stacktrace())
+ erlang:raise(error, guard_expr, ?STACKTRACE)
end;
guard0([], _Bs, _Lf, _Ef) -> true.
@@ -1073,7 +1095,7 @@ match(Pat, Term, Bs) ->
match(Pat, Term, Bs, BBs) ->
case catch match1(Pat, Term, Bs, BBs) of
invalid ->
- erlang:raise(error, {illegal_pattern,Pat}, stacktrace());
+ erlang:raise(error, {illegal_pattern,to_term(Pat)}, ?STACKTRACE);
Other ->
Other
end.
@@ -1254,7 +1276,7 @@ merge_bindings(Bs1, Bs2) ->
case orddict:find(Name, Bs) of
{ok,Val} -> Bs; %Already with SAME value
{ok,V1} ->
- erlang:raise(error, {badmatch,V1}, stacktrace());
+ erlang:raise(error, {badmatch,V1}, ?STACKTRACE);
error -> orddict:store(Name, Val, Bs)
end end,
Bs2, orddict:to_list(Bs1)).
@@ -1264,10 +1286,234 @@ merge_bindings(Bs1, Bs2) ->
%% fun (Name, Val, Bs) ->
%% case orddict:find(Name, Bs) of
%% {ok,Val} -> orddict:erase(Name, Bs);
-%% {ok,V1} -> erlang:raise(error,{badmatch,V1},stacktrace());
+%% {ok,V1} -> erlang:raise(error,{badmatch,V1},?STACKTRACE);
%% error -> Bs
%% end
%% end, Bs2, Bs1).
+
+to_terms(Abstrs) ->
+ [to_term(Abstr) || Abstr <- Abstrs].
+
+to_term(Abstr) ->
+ erl_parse:anno_to_term(Abstr).
+
+%% Substitute {value, A, Item} for {var, A, Var}, preserving A.
+%% {value, A, Item} is a shell/erl_eval convention, and for example
+%% the linter cannot handle it.
+
+-spec subst_values_for_vars(ExprList, Bindings) -> [term()] when
+ ExprList :: [erl_parse:abstract_expr()],
+ Bindings :: binding_struct().
+
+subst_values_for_vars({var, A, V}=Var, Bs) ->
+ case erl_eval:binding(V, Bs) of
+ {value, Value} ->
+ {value, A, Value};
+ unbound ->
+ Var
+ end;
+subst_values_for_vars(L, Bs) when is_list(L) ->
+ [subst_values_for_vars(E, Bs) || E <- L];
+subst_values_for_vars(T, Bs) when is_tuple(T) ->
+ list_to_tuple(subst_values_for_vars(tuple_to_list(T), Bs));
+subst_values_for_vars(T, _Bs) ->
+ T.
+
+%% `Tokens' is assumed to have been scanned with the 'text' option.
+%% The annotations of the returned expressions are locations.
+%%
+%% Can handle pids, ports, references, and external funs ("items").
+%% Known items are represented by variables in the erl_parse tree, and
+%% the items themselves are stored in the returned bindings.
+
+-spec extended_parse_exprs(Tokens) ->
+ {'ok', ExprList, Bindings} | {'error', ErrorInfo} when
+ Tokens :: [erl_scan:token()],
+ ExprList :: [erl_parse:abstract_expr()],
+ Bindings :: erl_eval:binding_struct(),
+ ErrorInfo :: erl_parse:error_info().
+
+extended_parse_exprs(Tokens) ->
+ Ts = tokens_fixup(Tokens),
+ case erl_parse:parse_exprs(Ts) of
+ {ok, Exprs0} ->
+ {Exprs, Bs} = expr_fixup(Exprs0),
+ {ok, reset_expr_anno(Exprs), Bs};
+ _ErrorInfo ->
+ erl_parse:parse_exprs(reset_token_anno(Ts))
+ end.
+
+tokens_fixup([]) -> [];
+tokens_fixup([T|Ts]=Ts0) ->
+ try token_fixup(Ts0) of
+ {NewT, NewTs} ->
+ [NewT|tokens_fixup(NewTs)]
+ catch
+ _:_ ->
+ [T|tokens_fixup(Ts)]
+ end.
+
+token_fixup(Ts) ->
+ {AnnoL, NewTs, FixupTag} = unscannable(Ts),
+ String = lists:append([erl_anno:text(A) || A <- AnnoL]),
+ _ = (fixup_fun(FixupTag))(String),
+ NewAnno = erl_anno:set_text(fixup_text(FixupTag), hd(AnnoL)),
+ {{string, NewAnno, String}, NewTs}.
+
+unscannable([{'#', A1}, {var, A2, 'Fun'}, {'<', A3}, {atom, A4, _},
+ {'.', A5}, {float, A6, _}, {'>', A7}|Ts]) ->
+ {[A1, A2, A3, A4, A5, A6, A7], Ts, function};
+unscannable([{'#', A1}, {var, A2, 'Fun'}, {'<', A3}, {atom, A4, _},
+ {'.', A5}, {atom, A6, _}, {'.', A7}, {integer, A8, _},
+ {'>', A9}|Ts]) ->
+ {[A1, A2, A3, A4, A5, A6, A7, A8, A9], Ts, function};
+unscannable([{'<', A1}, {float, A2, _}, {'.', A3}, {integer, A4, _},
+ {'>', A5}|Ts]) ->
+ {[A1, A2, A3, A4, A5], Ts, pid};
+unscannable([{'#', A1}, {var, A2, 'Port'}, {'<', A3}, {float, A4, _},
+ {'>', A5}|Ts]) ->
+ {[A1, A2, A3, A4, A5], Ts, port};
+unscannable([{'#', A1}, {var, A2, 'Ref'}, {'<', A3}, {float, A4, _},
+ {'.', A5}, {float, A6, _}, {'>', A7}|Ts]) ->
+ {[A1, A2, A3, A4, A5, A6, A7], Ts, reference}.
+
+expr_fixup(Expr0) ->
+ {Expr, Bs, _} = expr_fixup(Expr0, erl_eval:new_bindings(), 1),
+ {Expr, Bs}.
+
+expr_fixup({string,A,S}=T, Bs0, I) ->
+ try string_fixup(A, S) of
+ Value ->
+ Var = new_var(I),
+ Bs = erl_eval:add_binding(Var, Value, Bs0),
+ {{var, A, Var}, Bs, I+1}
+ catch
+ _:_ ->
+ {T, Bs0, I}
+ end;
+expr_fixup(Tuple, Bs0, I0) when is_tuple(Tuple) ->
+ {L, Bs, I} = expr_fixup(tuple_to_list(Tuple), Bs0, I0),
+ {list_to_tuple(L), Bs, I};
+expr_fixup([E0|Es0], Bs0, I0) ->
+ {E, Bs1, I1} = expr_fixup(E0, Bs0, I0),
+ {Es, Bs, I} = expr_fixup(Es0, Bs1, I1),
+ {[E|Es], Bs, I};
+expr_fixup(T, Bs, I) ->
+ {T, Bs, I}.
+
+string_fixup(A, S) ->
+ Text = erl_anno:text(A),
+ FixupTag = fixup_tag(Text, S),
+ (fixup_fun(FixupTag))(S).
+
+new_var(I) ->
+ list_to_atom(lists:concat(['__ExtendedParseExprs_', I, '__'])).
+
+reset_token_anno(Tokens) ->
+ [setelement(2, T, (reset_anno())(element(2, T))) || T <- Tokens].
+
+reset_expr_anno(Exprs) ->
+ [erl_parse:map_anno(reset_anno(), E) || E <- Exprs].
+
+reset_anno() ->
+ fun(A) -> erl_anno:new(erl_anno:location(A)) end.
+
+fixup_fun(function) -> fun function/1;
+fixup_fun(pid) -> fun erlang:list_to_pid/1;
+fixup_fun(port) -> fun erlang:list_to_port/1;
+fixup_fun(reference) -> fun erlang:list_to_ref/1.
+
+function(S) ->
+ %% External function.
+ {ok, [_, _, _,
+ {atom, _, Module}, _,
+ {atom, _, Function}, _,
+ {integer, _, Arity}|_], _} = erl_scan:string(S),
+ erlang:make_fun(Module, Function, Arity).
+
+fixup_text(function) -> "function";
+fixup_text(pid) -> "pid";
+fixup_text(port) -> "port";
+fixup_text(reference) -> "reference".
+
+fixup_tag("function", "#"++_) -> function;
+fixup_tag("pid", "<"++_) -> pid;
+fixup_tag("port", "#"++_) -> port;
+fixup_tag("reference", "#"++_) -> reference.
+
+%%% End of extended_parse_exprs.
+
+%% `Tokens' is assumed to have been scanned with the 'text' option.
+%%
+%% Can handle pids, ports, references, and external funs.
+
+-spec extended_parse_term(Tokens) ->
+ {'ok', Term} | {'error', ErrorInfo} when
+ Tokens :: [erl_scan:token()],
+ Term :: term(),
+ ErrorInfo :: erl_parse:error_info().
+
+extended_parse_term(Tokens) ->
+ case extended_parse_exprs(Tokens) of
+ {ok, [Expr], Bindings} ->
+ try normalise(Expr, Bindings) of
+ Term ->
+ {ok, Term}
+ catch
+ _:_ ->
+ Loc = erl_anno:location(element(2, Expr)),
+ {error,{Loc,?MODULE,"bad term"}}
+ end;
+ {ok, [_,Expr|_], _Bindings} ->
+ Loc = erl_anno:location(element(2, Expr)),
+ {error,{Loc,?MODULE,"bad term"}};
+ {error, _} = Error ->
+ Error
+ end.
+
+%% From erl_parse.
+normalise({var, _, V}, Bs) ->
+ {value, Value} = erl_eval:binding(V, Bs),
+ Value;
+normalise({char,_,C}, _Bs) -> C;
+normalise({integer,_,I}, _Bs) -> I;
+normalise({float,_,F}, _Bs) -> F;
+normalise({atom,_,A}, _Bs) -> A;
+normalise({string,_,S}, _Bs) -> S;
+normalise({nil,_}, _Bs) -> [];
+normalise({bin,_,Fs}, Bs) ->
+ {value, B, _} =
+ eval_bits:expr_grp(Fs, [],
+ fun(E, _) ->
+ {value, normalise(E, Bs), []}
+ end, [], true),
+ B;
+normalise({cons,_,Head,Tail}, Bs) ->
+ [normalise(Head, Bs)|normalise(Tail, Bs)];
+normalise({tuple,_,Args}, Bs) ->
+ list_to_tuple(normalise_list(Args, Bs));
+normalise({map,_,Pairs}, Bs) ->
+ maps:from_list(lists:map(fun
+ %% only allow '=>'
+ ({map_field_assoc,_,K,V}) ->
+ {normalise(K, Bs),normalise(V, Bs)}
+ end, Pairs));
+%% Special case for unary +/-.
+normalise({op,_,'+',{char,_,I}}, _Bs) -> I;
+normalise({op,_,'+',{integer,_,I}}, _Bs) -> I;
+normalise({op,_,'+',{float,_,F}}, _Bs) -> F;
+normalise({op,_,'-',{char,_,I}}, _Bs) -> -I; %Weird, but compatible!
+normalise({op,_,'-',{integer,_,I}}, _Bs) -> -I;
+normalise({op,_,'-',{float,_,F}}, _Bs) -> -F;
+normalise({'fun',_,{function,{atom,_,M},{atom,_,F},{integer,_,A}}}, _Bs) ->
+ %% Since "#Fun<M.F.A>" is recognized, "fun M:F/A" should be too.
+ fun M:F/A.
+
+normalise_list([H|T], Bs) ->
+ [normalise(H, Bs)|normalise_list(T, Bs)];
+normalise_list([], _Bs) ->
+ [].
+
%%----------------------------------------------------------------------------
%%
%% Evaluate expressions:
@@ -1320,13 +1566,53 @@ ev_expr({cons,_,H,T}) -> [ev_expr(H) | ev_expr(T)].
%% true = erl_internal:guard_bif(F, length(As)),
%% apply(erlang, F, [ev_expr(X) || X <- As]);
+%% eval_str(InStr) -> {ok, OutStr} | {error, ErrStr'}
+%% InStr must represent a body
+%% Note: If InStr is a binary it has to be a Latin-1 string.
+%% If you have a UTF-8 encoded binary you have to call
+%% unicode:characters_to_list/1 before the call to eval_str().
+
+-define(result(F,D), lists:flatten(io_lib:format(F, D))).
+
+-spec eval_str(string() | unicode:latin1_binary()) ->
+ {'ok', string()} | {'error', string()}.
+
+eval_str(Str) when is_list(Str) ->
+ case erl_scan:tokens([], Str, 0) of
+ {more, _} ->
+ {error, "Incomplete form (missing .<cr>)??"};
+ {done, {ok, Toks, _}, Rest} ->
+ case all_white(Rest) of
+ true ->
+ case erl_parse:parse_exprs(Toks) of
+ {ok, Exprs} ->
+ case catch erl_eval:exprs(Exprs, erl_eval:new_bindings()) of
+ {value, Val, _} ->
+ {ok, Val};
+ Other ->
+ {error, ?result("*** eval: ~p", [Other])}
+ end;
+ {error, {_Line, Mod, Args}} ->
+ Msg = ?result("*** ~ts",[Mod:format_error(Args)]),
+ {error, Msg}
+ end;
+ false ->
+ {error, ?result("Non-white space found after "
+ "end-of-form :~ts", [Rest])}
+ end
+ end;
+eval_str(Bin) when is_binary(Bin) ->
+ eval_str(binary_to_list(Bin)).
+
+all_white([$\s|T]) -> all_white(T);
+all_white([$\n|T]) -> all_white(T);
+all_white([$\t|T]) -> all_white(T);
+all_white([]) -> true;
+all_white(_) -> false.
+
ret_expr(_Old, New) ->
%% io:format("~w: reduced ~s => ~s~n",
%% [line(Old), erl_pp:expr(Old), erl_pp:expr(New)]),
New.
line(Expr) -> element(2, Expr).
-
-%% {?MODULE,expr,3} is still the stacktrace, despite the
-%% fact that expr() now takes two, three or four arguments...
-stacktrace() -> [{?MODULE,expr,3}].
diff --git a/lib/stdlib/src/erl_internal.erl b/lib/stdlib/src/erl_internal.erl
index 89b97b901e..939abaff00 100644
--- a/lib/stdlib/src/erl_internal.erl
+++ b/lib/stdlib/src/erl_internal.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -74,8 +74,10 @@ guard_bif(element, 2) -> true;
guard_bif(float, 1) -> true;
guard_bif(floor, 1) -> true;
guard_bif(hd, 1) -> true;
+guard_bif(is_map_key, 2) -> true;
guard_bif(length, 1) -> true;
guard_bif(map_size, 1) -> true;
+guard_bif(map_get, 2) -> true;
guard_bif(node, 0) -> true;
guard_bif(node, 1) -> true;
guard_bif(round, 1) -> true;
@@ -314,6 +316,7 @@ bif(is_function, 2) -> true;
bif(is_integer, 1) -> true;
bif(is_list, 1) -> true;
bif(is_map, 1) -> true;
+bif(is_map_key, 2) -> true;
bif(is_number, 1) -> true;
bif(is_pid, 1) -> true;
bif(is_port, 1) -> true;
@@ -337,6 +340,7 @@ bif(list_to_tuple, 1) -> true;
bif(load_module, 2) -> true;
bif(make_ref, 0) -> true;
bif(map_size,1) -> true;
+bif(map_get,2) -> true;
bif(max,2) -> true;
bif(min,2) -> true;
bif(module_loaded, 1) -> true;
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index 9cd4727dc3..0cd0aef124 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -79,6 +79,8 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) ->
-type fa() :: {atom(), arity()}. % function+arity
-type ta() :: {atom(), arity()}. % type+arity
+-type module_or_mfa() :: module() | mfa().
+
-record(typeinfo, {attr, line}).
%% Usage of records, functions, and imports. The variable table, which
@@ -93,13 +95,6 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) ->
}).
-%% Are we outside or inside a catch or try/catch?
--type catch_scope() :: 'none'
- | 'after_old_catch'
- | 'after_try'
- | 'wrong_part_of_try'
- | 'try_catch'.
-
%% Define the lint state record.
%% 'called' and 'exports' contain {Line, {Function, Arity}},
%% the other function collections contain {Function, Arity}.
@@ -122,6 +117,8 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) ->
:: erl_anno:anno(),
clashes=[], %Exported functions named as BIFs
not_deprecated=[], %Not considered deprecated
+ not_removed=gb_sets:empty() %Not considered removed
+ :: gb_sets:set(module_or_mfa()),
func=[], %Current function
warn_format=0, %Warn format calls
enabled_warnings=[], %All enabled warnings (ordset).
@@ -144,8 +141,7 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) ->
:: dict:dict(ta(), #typeinfo{}),
exp_types=gb_sets:empty() %Exported types
:: gb_sets:set(ta()),
- catch_scope = none %Inside/outside try or catch
- :: catch_scope()
+ in_try_head=false :: boolean() %In a try head.
}).
-type lint_state() :: #lint{}.
@@ -232,15 +228,6 @@ format_error({redefine_old_bif_import,{F,A}}) ->
format_error({redefine_bif_import,{F,A}}) ->
io_lib:format("import directive overrides auto-imported BIF ~w/~w~n"
" - use \"-compile({no_auto_import,[~w/~w]}).\" to resolve name clash", [F,A,F,A]);
-format_error({get_stacktrace,wrong_part_of_try}) ->
- "erlang:get_stacktrace/0 used in the wrong part of 'try' expression. "
- "(Use it in the block between 'catch' and 'end'.)";
-format_error({get_stacktrace,after_old_catch}) ->
- "erlang:get_stacktrace/0 used following an old-style 'catch' "
- "may stop working in a future release. (Use it inside 'try'.)";
-format_error({get_stacktrace,after_try}) ->
- "erlang:get_stacktrace/0 used following a 'try' expression "
- "may stop working in a future release. (Use it inside 'try'.)";
format_error({deprecated, MFA, ReplacementMFA, Rel}) ->
io_lib:format("~s is deprecated and will be removed in ~s; use ~s",
[format_mfa(MFA), Rel, format_mfa(ReplacementMFA)]);
@@ -312,6 +299,10 @@ format_error({unused_var, V}) ->
io_lib:format("variable ~w is unused", [V]);
format_error({variable_in_record_def,V}) ->
io_lib:format("variable ~w in record definition", [V]);
+format_error({stacktrace_guard,V}) ->
+ io_lib:format("stacktrace variable ~w must not be used in a guard", [V]);
+format_error({stacktrace_bound,V}) ->
+ io_lib:format("stacktrace variable ~w must not be previously bound", [V]);
%% --- binaries ---
format_error({undefined_bittype,Type}) ->
io_lib:format("bit type ~tw undefined", [Type]);
@@ -395,6 +386,8 @@ format_error({redefine_callback, {F, A}}) ->
format_error({bad_callback, {M, F, A}}) ->
io_lib:format("explicit module not allowed for callback ~tw:~tw/~w",
[M, F, A]);
+format_error({bad_module, {M, F, A}}) ->
+ io_lib:format("spec for function ~w:~tw/~w from other module", [M, F, A]);
format_error({spec_fun_undefined, {F, A}}) ->
io_lib:format("spec for undefined function ~tw/~w", [F, A]);
format_error({missing_spec, {F,A}}) ->
@@ -587,8 +580,8 @@ start(File, Opts) ->
{missing_spec_all,
bool_option(warn_missing_spec_all, nowarn_missing_spec_all,
false, Opts)},
- {get_stacktrace,
- bool_option(warn_get_stacktrace, nowarn_get_stacktrace,
+ {removed,
+ bool_option(warn_removed, nowarn_removed,
true, Opts)}
],
Enabled1 = [Category || {Category,true} <- Enabled0],
@@ -686,8 +679,9 @@ forms(Forms0, St0) ->
no_auto = AutoImportSuppressed}),
St2 = bif_clashes(Forms, St1),
St3 = not_deprecated(Forms, St2),
- St4 = foldl(fun form/2, pre_scan(Forms, St3), Forms),
- post_traversal_check(Forms, St4).
+ St4 = not_removed(Forms, St3),
+ St5 = foldl(fun form/2, pre_scan(Forms, St4), Forms),
+ post_traversal_check(Forms, St5).
pre_scan([{attribute,L,compile,C} | Fs], St) ->
case is_warn_enabled(export_all, St) andalso
@@ -847,19 +841,39 @@ bif_clashes(Forms, #lint{nowarn_bif_clash=Nowarn} = St) ->
%% not_deprecated(Forms, State0) -> State
-not_deprecated(Forms, St0) ->
+not_deprecated(Forms, #lint{compile=Opts}=St0) ->
%% There are no line numbers in St0#lint.compile.
MFAsL = [{MFA,L} ||
{attribute, L, compile, Args} <- Forms,
{nowarn_deprecated_function, MFAs0} <- lists:flatten([Args]),
MFA <- lists:flatten([MFAs0])],
- Nowarn = [MFA || {MFA,_L} <- MFAsL],
+ Nowarn = [MFA ||
+ {nowarn_deprecated_function, MFAs0} <- Opts,
+ MFA <- lists:flatten([MFAs0])],
ML = [{M,L} || {{M,_F,_A},L} <- MFAsL, is_atom(M)],
St1 = foldl(fun ({M,L}, St2) ->
check_module_name(M, L, St2)
end, St0, ML),
St1#lint{not_deprecated = ordsets:from_list(Nowarn)}.
+%% not_removed(Forms, State0) -> State
+
+not_removed(Forms, #lint{compile=Opts}=St0) ->
+ %% There are no line numbers in St0#lint.compile.
+ MFAsL = [{MFA,L} ||
+ {attribute, L, compile, Args} <- Forms,
+ {nowarn_removed, MFAs0} <- lists:flatten([Args]),
+ MFA <- lists:flatten([MFAs0])],
+ Nowarn = [MFA ||
+ {nowarn_removed, MFAs0} <- Opts,
+ MFA <- lists:flatten([MFAs0])],
+ St1 = foldl(fun ({{M, _F, _A}, L}, St2) ->
+ check_module_name(M, L, St2);
+ ({M,L}, St2) ->
+ check_module_name(M, L, St2)
+ end, St0, MFAsL),
+ St1#lint{not_removed = gb_sets:from_list(Nowarn)}.
+
%% The nowarn_bif_clash directive is not only deprecated, it's actually an error from R14A
disallowed_compile_flags(Forms, St0) ->
%% There are (still) no line numbers in St0#lint.compile.
@@ -1421,7 +1435,7 @@ call_function(Line, F, A, #lint{usage=Usage0,called=Cd,func=Func,file=File}=St)
%% function(Line, Name, Arity, Clauses, State) -> State.
function(Line, Name, Arity, Cs, St0) ->
- St1 = St0#lint{func={Name,Arity},catch_scope=none},
+ St1 = St0#lint{func={Name,Arity}},
St2 = define_function(Line, Name, Arity, St1),
clauses(Cs, St2).
@@ -2111,6 +2125,10 @@ is_gexpr({cons,_L,H,T}, Info) -> is_gexpr_list([H,T], Info);
is_gexpr({tuple,_L,Es}, Info) -> is_gexpr_list(Es, Info);
%%is_gexpr({struct,_L,_Tag,Es}, Info) ->
%% is_gexpr_list(Es, Info);
+is_gexpr({map,_L,Es}, Info) ->
+ is_map_fields(Es, Info);
+is_gexpr({map,_L,Src,Es}, Info) ->
+ is_gexpr(Src, Info) andalso is_map_fields(Es, Info);
is_gexpr({record_index,_L,_Name,Field}, Info) ->
is_gexpr(Field, Info);
is_gexpr({record_field,_L,Rec,_Name,Field}, Info) ->
@@ -2153,6 +2171,14 @@ is_gexpr_op(Op, A) ->
is_gexpr_list(Es, Info) -> all(fun (E) -> is_gexpr(E, Info) end, Es).
+is_map_fields([{Tag,_,K,V}|Fs], Info) when Tag =:= map_field_assoc;
+ Tag =:= map_field_exact ->
+ is_gexpr(K, Info) andalso
+ is_gexpr(V, Info) andalso
+ is_map_fields(Fs, Info);
+is_map_fields([], _Info) -> true;
+is_map_fields(_T, _Info) -> false.
+
is_gexpr_fields(Fs, L, Name, {RDs,_}=Info) ->
IFs = case dict:find(Name, RDs) of
{ok,{_Line,Fields}} -> Fs ++ init_fields(Fs, L, Fields);
@@ -2252,6 +2278,9 @@ expr({'fun',Line,Body}, Vt, St) ->
case Body of
{clauses,Cs} ->
fun_clauses(Cs, Vt, St);
+ {function,record_info,2} ->
+ %% It is illegal to call record_info/2 with unknown arguments.
+ {[],add_error(Line, illegal_record_info, St)};
{function,F,A} ->
%% BifClash - Fun expression
%% N.B. Only allows BIFs here as well, NO IMPORTS!!
@@ -2266,8 +2295,7 @@ expr({'fun',Line,Body}, Vt, St) ->
{[],St};
{function,M,F,A} ->
%% New in R15.
- {Bvt, St1} = expr_list([M,F,A], Vt, St),
- {vtupdate(Bvt, Vt),St1}
+ expr_list([M,F,A], Vt, St)
end;
expr({named_fun,_,'_',Cs}, Vt, St) ->
fun_clauses(Cs, Vt, St);
@@ -2362,7 +2390,7 @@ expr({call,Line,F,As}, Vt, St0) ->
expr({'try',Line,Es,Scs,Ccs,As}, Vt, St0) ->
%% Currently, we don't allow any exports because later
%% passes cannot handle exports in combination with 'after'.
- {Evt0,St1} = exprs(Es, Vt, St0#lint{catch_scope=wrong_part_of_try}),
+ {Evt0,St1} = exprs(Es, Vt, St0),
TryLine = {'try',Line},
Uvt = vtunsafe(TryLine, Evt0, Vt),
Evt1 = vtupdate(Uvt, Evt0),
@@ -2374,12 +2402,11 @@ expr({'try',Line,Es,Scs,Ccs,As}, Vt, St0) ->
{Avt0,St} = exprs(As, vtupdate(Evt2, Vt), St2),
Avt1 = vtupdate(vtunsafe(TryLine, Avt0, Vt), Avt0),
Avt = vtmerge(Evt2, Avt1),
- {Avt,St#lint{catch_scope=after_try}};
+ {Avt,St};
expr({'catch',Line,E}, Vt, St0) ->
%% No new variables added, flag new variables as unsafe.
{Evt,St} = expr(E, Vt, St0),
- {vtupdate(vtunsafe({'catch',Line}, Evt, Vt), Evt),
- St#lint{catch_scope=after_old_catch}};
+ {vtupdate(vtunsafe({'catch',Line}, Evt, Vt), Evt),St};
expr({match,_Line,P,E}, Vt, St0) ->
{Evt,St1} = expr(E, Vt, St0),
{Pvt,Bvt,St2} = pattern(P, vtupdate(Evt, Vt), St1),
@@ -2985,7 +3012,13 @@ spec_decl(Line, MFA0, TypeSpecs, St00 = #lint{specs = Specs, module = Mod}) ->
St1 = St0#lint{specs = dict:store(MFA, Line, Specs)},
case dict:is_key(MFA, Specs) of
true -> add_error(Line, {redefine_spec, MFA0}, St1);
- false -> check_specs(TypeSpecs, spec_wrong_arity, Arity, St1)
+ false ->
+ case MFA of
+ {Mod, _, _} ->
+ check_specs(TypeSpecs, spec_wrong_arity, Arity, St1);
+ _ ->
+ add_error(Line, {bad_module, MFA}, St1)
+ end
end.
%% callback_decl(Line, Fun, Types, State) -> State.
@@ -3218,11 +3251,11 @@ is_module_dialyzer_option(Option) ->
try_clauses(Scs, Ccs, In, Vt, St0) ->
{Csvt0,St1} = icrt_clauses(Scs, Vt, St0),
- St2 = St1#lint{catch_scope=try_catch},
+ St2 = St1#lint{in_try_head=true},
{Csvt1,St3} = icrt_clauses(Ccs, Vt, St2),
Csvt = Csvt0 ++ Csvt1,
UpdVt = icrt_export(Csvt, Vt, In, St3),
- {UpdVt,St3}.
+ {UpdVt,St3#lint{in_try_head=false}}.
%% icrt_clauses(Clauses, In, ImportVarTable, State) ->
%% {UpdVt,State}.
@@ -3238,13 +3271,30 @@ icrt_clauses(Cs, In, Vt, St0) ->
icrt_clauses(Cs, Vt, St) ->
mapfoldl(fun (C, St0) -> icrt_clause(C, Vt, St0) end, St, Cs).
-icrt_clause({clause,_Line,H,G,B}, Vt0, #lint{catch_scope=Scope}=St0) ->
- {Hvt,Binvt,St1} = head(H, Vt0, St0),
- Vt1 = vtupdate(Hvt, Binvt),
- {Gvt,St2} = guard(G, vtupdate(Vt1, Vt0), St1),
- Vt2 = vtupdate(Gvt, Vt1),
- {Bvt,St3} = exprs(B, vtupdate(Vt2, Vt0), St2),
- {vtupdate(Bvt, Vt2),St3#lint{catch_scope=Scope}}.
+icrt_clause({clause,_Line,H,G,B}, Vt0, St0) ->
+ Vt1 = taint_stack_var(Vt0, H, St0),
+ {Hvt,Binvt,St1} = head(H, Vt1, St0),
+ Vt2 = vtupdate(Hvt, Binvt),
+ Vt3 = taint_stack_var(Vt2, H, St0),
+ {Gvt,St2} = guard(G, vtupdate(Vt3, Vt0), St1#lint{in_try_head=false}),
+ Vt4 = vtupdate(Gvt, Vt2),
+ {Bvt,St3} = exprs(B, vtupdate(Vt4, Vt0), St2),
+ {vtupdate(Bvt, Vt4),St3}.
+
+taint_stack_var(Vt, Pat, #lint{in_try_head=true}) ->
+ [{tuple,_,[_,_,{var,_,Stk}]}] = Pat,
+ case Stk of
+ '_' ->
+ Vt;
+ _ ->
+ lists:map(fun({V,{bound,Used,Lines}}) when V =:= Stk ->
+ {V,{stacktrace,Used,Lines}};
+ (B) ->
+ B
+ end, Vt)
+ end;
+taint_stack_var(Vt, _Pat, #lint{in_try_head=false}) ->
+ Vt.
icrt_export(Vts, Vt, {Tag,Attrs}, St) ->
{_File,Loc} = loc(Attrs, St),
@@ -3484,6 +3534,9 @@ pat_var(V, Line, Vt, Bvt, St) ->
{[{V,{bound,used,Ls}}],[],
%% As this is matching, exported vars are risky.
add_warning(Line, {exported_var,V,From}, St)};
+ {ok,{stacktrace,_Usage,Ls}} ->
+ {[{V,{bound,used,Ls}}],[],
+ add_error(Line, {stacktrace_bound,V}, St)};
error when St#lint.recdef_top ->
{[],[{V,{bound,unused,[Line]}}],
add_error(Line, {variable_in_record_def,V}, St)};
@@ -3541,6 +3594,9 @@ expr_var(V, Line, Vt, St) ->
false ->
{[{V,{{export,From},used,Ls}}],St}
end;
+ {ok,{stacktrace,_Usage,Ls}} ->
+ {[{V,{bound,used,Ls}}],
+ add_error(Line, {stacktrace_guard,V}, St)};
error ->
{[{V,{bound,used,[Line]}}],
add_error(Line, {unbound_var,V}, St)}
@@ -3708,8 +3764,7 @@ has_wildcard_field([]) -> false.
check_remote_function(Line, M, F, As, St0) ->
St1 = deprecated_function(Line, M, F, As, St0),
St2 = check_qlc_hrl(Line, M, F, As, St1),
- St3 = check_get_stacktrace(Line, M, F, As, St2),
- format_function(Line, M, F, As, St3).
+ format_function(Line, M, F, As, St2).
%% check_qlc_hrl(Line, ModName, FuncName, [Arg], State) -> State
%% Add warning if qlc:q/1,2 has been called but qlc.hrl has not
@@ -3751,29 +3806,22 @@ deprecated_function(Line, M, F, As, St) ->
add_warning(Line, {deprecated, MFA, Replacement, Rel}, St)
end;
{removed, String} when is_list(String) ->
- add_warning(Line, {removed, MFA, String}, St);
+ add_removed_warning(Line, MFA, {removed, MFA, String}, St);
{removed, Replacement, Rel} ->
- add_warning(Line, {removed, MFA, Replacement, Rel}, St);
+ add_removed_warning(Line, MFA, {removed, MFA, Replacement, Rel}, St);
no ->
St
end.
-check_get_stacktrace(Line, erlang, get_stacktrace, [], St) ->
- case St of
- #lint{catch_scope=none} ->
- St;
- #lint{catch_scope=try_catch} ->
- St;
- #lint{catch_scope=Scope} ->
- case is_warn_enabled(get_stacktrace, St) of
- false ->
- St;
- true ->
- add_warning(Line, {get_stacktrace,Scope}, St)
- end
- end;
-check_get_stacktrace(_, _, _, _, St) ->
- St.
+add_removed_warning(Line, {M, _, _}=MFA, Warning, #lint{not_removed=NotRemoved}=St) ->
+ case is_warn_enabled(removed, St) andalso
+ not gb_sets:is_element(M, NotRemoved) andalso
+ not gb_sets:is_element(MFA, NotRemoved) of
+ true ->
+ add_warning(Line, Warning, St);
+ false ->
+ St
+ end.
-dialyzer({no_match, deprecated_type/5}).
@@ -3910,10 +3958,9 @@ check_format_string(Fmt) ->
extract_sequences(Fmt, []).
extract_sequences(Fmt, Need0) ->
- case string:chr(Fmt, $~) of
- 0 -> {ok,lists:reverse(Need0)}; %That's it
- Pos ->
- Fmt1 = string:substr(Fmt, Pos+1), %Skip ~
+ case string:find(Fmt, [$~]) of
+ nomatch -> {ok,lists:reverse(Need0)}; %That's it
+ [$~|Fmt1] ->
case extract_sequence(1, Fmt1, Need0) of
{ok,Need1,Rest} -> extract_sequences(Rest, Need1);
Error -> Error
@@ -3944,6 +3991,8 @@ extract_sequence(3, [$.,_|Fmt], Need) ->
extract_sequence(4, Fmt, Need);
extract_sequence(3, Fmt, Need) ->
extract_sequence(4, Fmt, Need);
+extract_sequence(4, [$t, $l | Fmt], Need) ->
+ extract_sequence(4, [$l, $t | Fmt], Need);
extract_sequence(4, [$t, $c | Fmt], Need) ->
extract_sequence(5, [$c|Fmt], Need);
extract_sequence(4, [$t, $s | Fmt], Need) ->
@@ -3960,8 +4009,14 @@ extract_sequence(4, [$t, C | _Fmt], _Need) ->
{error,"invalid control ~t" ++ [C]};
extract_sequence(4, [$l, $p | Fmt], Need) ->
extract_sequence(5, [$p|Fmt], Need);
+extract_sequence(4, [$l, $t, $p | Fmt], Need) ->
+ extract_sequence(5, [$p|Fmt], Need);
extract_sequence(4, [$l, $P | Fmt], Need) ->
extract_sequence(5, [$P|Fmt], Need);
+extract_sequence(4, [$l, $t, $P | Fmt], Need) ->
+ extract_sequence(5, [$P|Fmt], Need);
+extract_sequence(4, [$l, $t, C | _Fmt], _Need) ->
+ {error,"invalid control ~lt" ++ [C]};
extract_sequence(4, [$l, C | _Fmt], _Need) ->
{error,"invalid control ~l" ++ [C]};
extract_sequence(4, Fmt, Need) ->
diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl
index 6e72d64acc..4ad94f2507 100644
--- a/lib/stdlib/src/erl_parse.yrl
+++ b/lib/stdlib/src/erl_parse.yrl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,6 +29,10 @@ clause_args clause_guard clause_body
expr expr_100 expr_150 expr_160 expr_200 expr_300 expr_400 expr_500
expr_600 expr_700 expr_800
expr_max
+pat_expr pat_expr_200 pat_expr_300 pat_expr_400 pat_expr_500
+pat_expr_600 pat_expr_700 pat_expr_800
+pat_expr_max map_pat_expr record_pat_expr
+pat_argument_list pat_exprs
list tail
list_comprehension lc_expr lc_exprs
binary_comprehension
@@ -37,7 +41,7 @@ record_expr record_tuple record_field record_fields
map_expr map_tuple map_field map_field_assoc map_field_exact map_fields map_key
if_expr if_clause if_clauses case_expr cr_clause cr_clauses receive_expr
fun_expr fun_clause fun_clauses atom_or_var integer_or_var
-try_expr try_catch try_clause try_clauses
+try_expr try_catch try_clause try_clauses try_opt_stacktrace
function_call argument_list
exprs guard
atomic strings
@@ -66,7 +70,7 @@ char integer float atom string var
'spec' 'callback' % helper
dot.
-Expect 2.
+Expect 0.
Rootsymbol form.
@@ -210,7 +214,7 @@ function_clause -> atom clause_args clause_guard clause_body :
{clause,?anno('$1'),element(3, '$1'),'$2','$3','$4'}.
-clause_args -> argument_list : element(1, '$1').
+clause_args -> pat_argument_list : element(1, '$1').
clause_guard -> 'when' guard : '$2'.
clause_guard -> '$empty' : [].
@@ -275,6 +279,53 @@ expr_max -> receive_expr : '$1'.
expr_max -> fun_expr : '$1'.
expr_max -> try_expr : '$1'.
+pat_expr -> pat_expr_200 '=' pat_expr : {match,?anno('$2'),'$1','$3'}.
+pat_expr -> pat_expr_200 : '$1'.
+
+pat_expr_200 -> pat_expr_300 comp_op pat_expr_300 :
+ ?mkop2('$1', '$2', '$3').
+pat_expr_200 -> pat_expr_300 : '$1'.
+
+pat_expr_300 -> pat_expr_400 list_op pat_expr_300 :
+ ?mkop2('$1', '$2', '$3').
+pat_expr_300 -> pat_expr_400 : '$1'.
+
+pat_expr_400 -> pat_expr_400 add_op pat_expr_500 :
+ ?mkop2('$1', '$2', '$3').
+pat_expr_400 -> pat_expr_500 : '$1'.
+
+pat_expr_500 -> pat_expr_500 mult_op pat_expr_600 :
+ ?mkop2('$1', '$2', '$3').
+pat_expr_500 -> pat_expr_600 : '$1'.
+
+pat_expr_600 -> prefix_op pat_expr_700 :
+ ?mkop1('$1', '$2').
+pat_expr_600 -> map_pat_expr : '$1'.
+pat_expr_600 -> pat_expr_700 : '$1'.
+
+pat_expr_700 -> record_pat_expr : '$1'.
+pat_expr_700 -> pat_expr_800 : '$1'.
+
+pat_expr_800 -> pat_expr_max : '$1'.
+
+pat_expr_max -> var : '$1'.
+pat_expr_max -> atomic : '$1'.
+pat_expr_max -> list : '$1'.
+pat_expr_max -> binary : '$1'.
+pat_expr_max -> tuple : '$1'.
+pat_expr_max -> '(' pat_expr ')' : '$2'.
+
+map_pat_expr -> '#' map_tuple :
+ {map, ?anno('$1'),'$2'}.
+map_pat_expr -> pat_expr_max '#' map_tuple :
+ {map, ?anno('$2'),'$1','$3'}.
+map_pat_expr -> map_pat_expr '#' map_tuple :
+ {map, ?anno('$2'),'$1','$3'}.
+
+record_pat_expr -> '#' atom '.' atom :
+ {record_index,?anno('$1'),element(3, '$2'),'$4'}.
+record_pat_expr -> '#' atom record_tuple :
+ {record,?anno('$1'),element(3, '$2'),'$3'}.
list -> '[' ']' : {nil,?anno('$1')}.
list -> '[' expr tail : {cons,?anno('$1'),'$2','$3'}.
@@ -397,6 +448,10 @@ case_expr -> 'case' expr 'of' cr_clauses 'end' :
cr_clauses -> cr_clause : ['$1'].
cr_clauses -> cr_clause ';' cr_clauses : ['$1' | '$3'].
+%% FIXME: merl in syntax_tools depends on patterns in a 'case' being
+%% full expressions. Therefore, we can't use pat_expr here. There
+%% should be a better way.
+
cr_clause -> expr clause_guard clause_body :
{clause,?anno('$1'),['$1'],'$2','$3'}.
@@ -424,11 +479,11 @@ integer_or_var -> var : '$1'.
fun_clauses -> fun_clause : ['$1'].
fun_clauses -> fun_clause ';' fun_clauses : ['$1' | '$3'].
-fun_clause -> argument_list clause_guard clause_body :
+fun_clause -> pat_argument_list clause_guard clause_body :
{Args,Anno} = '$1',
{clause,Anno,'fun',Args,'$2','$3'}.
-fun_clause -> var argument_list clause_guard clause_body :
+fun_clause -> var pat_argument_list clause_guard clause_body :
{clause,element(2, '$1'),element(3, '$1'),element(1, '$2'),'$3','$4'}.
try_expr -> 'try' exprs 'of' cr_clauses try_catch :
@@ -446,24 +501,31 @@ try_catch -> 'after' exprs 'end' :
try_clauses -> try_clause : ['$1'].
try_clauses -> try_clause ';' try_clauses : ['$1' | '$3'].
-try_clause -> expr clause_guard clause_body :
+try_clause -> pat_expr clause_guard clause_body :
A = ?anno('$1'),
{clause,A,[{tuple,A,[{atom,A,throw},'$1',{var,A,'_'}]}],'$2','$3'}.
-try_clause -> atom ':' expr clause_guard clause_body :
+try_clause -> atom ':' pat_expr try_opt_stacktrace clause_guard clause_body :
A = ?anno('$1'),
- {clause,A,[{tuple,A,['$1','$3',{var,A,'_'}]}],'$4','$5'}.
-try_clause -> var ':' expr clause_guard clause_body :
+ {clause,A,[{tuple,A,['$1','$3',{var,A,'$4'}]}],'$5','$6'}.
+try_clause -> var ':' pat_expr try_opt_stacktrace clause_guard clause_body :
A = ?anno('$1'),
- {clause,A,[{tuple,A,['$1','$3',{var,A,'_'}]}],'$4','$5'}.
+ {clause,A,[{tuple,A,['$1','$3',{var,A,'$4'}]}],'$5','$6'}.
+try_opt_stacktrace -> ':' var : element(3, '$2').
+try_opt_stacktrace -> '$empty' : '_'.
argument_list -> '(' ')' : {[],?anno('$1')}.
argument_list -> '(' exprs ')' : {'$2',?anno('$1')}.
+pat_argument_list -> '(' ')' : {[],?anno('$1')}.
+pat_argument_list -> '(' pat_exprs ')' : {'$2',?anno('$1')}.
exprs -> expr : ['$1'].
exprs -> expr ',' exprs : ['$1' | '$3'].
+pat_exprs -> pat_expr : ['$1'].
+pat_exprs -> pat_expr ',' pat_exprs : ['$1' | '$3'].
+
guard -> exprs : ['$1'].
guard -> exprs ';' guard : ['$1'|'$3'].
@@ -779,7 +841,7 @@ Erlang code.
-type af_record_field(T) :: {'record_field', anno(), af_field_name(), T}.
-type af_map_pattern() ::
- {'map', anno(), [af_assoc_exact(abstract_expr)]}.
+ {'map', anno(), [af_assoc_exact(abstract_expr())]}.
-type abstract_type() :: af_annotated_type()
| af_atom()
@@ -810,7 +872,7 @@ Erlang code.
-type af_fun_type() :: {'type', anno(), 'fun', []}
| {'type', anno(), 'fun', [{'type', anno(), 'any'} |
abstract_type()]}
- | {'type', anno(), 'fun', af_function_type()}.
+ | af_function_type().
-type af_integer_range_type() ::
{'type', anno(), 'range', [af_singleton_integer_type()]}.
@@ -862,10 +924,11 @@ Erlang code.
-type af_function_constraint() :: [af_constraint()].
-type af_constraint() :: {'type', anno(), 'constraint',
- af_lit_atom('is_subtype'),
- [af_type_variable() | abstract_type()]}. % [V, T]
+ [af_lit_atom('is_subtype') |
+ [af_type_variable() | abstract_type()]]}. % [IsSubtype, [V, T]]
-type af_singleton_integer_type() :: af_integer()
+ | af_character()
| af_unary_op(af_singleton_integer_type())
| af_binary_op(af_singleton_integer_type()).
@@ -918,7 +981,7 @@ Erlang code.
-type af_unary_op(T) :: {'op', anno(), unary_op(), T}.
--type unary_op() :: '+' | '*' | 'bnot' | 'not'.
+-type unary_op() :: '+' | '-' | 'bnot' | 'not'.
%% See also lib/stdlib/{src/erl_bits.erl,include/erl_bits.hrl}.
-type type_specifier_list() :: 'default' | [type_specifier(), ...].
@@ -1315,6 +1378,8 @@ normalise({map,_,Pairs}=M) ->
({map_field_assoc,_,K,V}) -> {normalise(K),normalise(V)};
(_) -> erlang:error({badarg,M})
end, Pairs));
+normalise({'fun',_,{function,{atom,_,M},{atom,_,F},{integer,_,A}}}) ->
+ fun M:F/A;
%% Special case for unary +/-.
normalise({op,_,'+',{char,_,I}}) -> I;
normalise({op,_,'+',{integer,_,I}}) -> I;
diff --git a/lib/stdlib/src/erl_posix_msg.erl b/lib/stdlib/src/erl_posix_msg.erl
index bfafca1ff7..b9ed4a3a9d 100644
--- a/lib/stdlib/src/erl_posix_msg.erl
+++ b/lib/stdlib/src/erl_posix_msg.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -64,6 +64,7 @@ message_1(eduppkg) -> <<"duplicate package name">>;
message_1(eexist) -> <<"file already exists">>;
message_1(efault) -> <<"bad address in system call argument">>;
message_1(efbig) -> <<"file too large">>;
+message_1(eftype) -> <<"EFTYPE">>;
message_1(ehostdown) -> <<"host is down">>;
message_1(ehostunreach) -> <<"host is unreachable">>;
message_1(eidrm) -> <<"identifier removed">>;
@@ -80,9 +81,9 @@ message_1(el2hlt) -> <<"level 2 halted">>;
message_1(el2nsync) -> <<"level 2 not synchronized">>;
message_1(el3hlt) -> <<"level 3 halted">>;
message_1(el3rst) -> <<"level 3 reset">>;
-message_1(elibacc) -> <<"can not access a needed shared library">>;
+message_1(elibacc) -> <<"cannot access a needed shared library">>;
message_1(elibbad) -> <<"accessing a corrupted shared library">>;
-message_1(elibexec) -> <<"can not exec a shared library directly">>;
+message_1(elibexec) -> <<"cannot exec a shared library directly">>;
message_1(elibmax) ->
<<"attempting to link in more shared libraries than system limit">>;
message_1(elibscn) -> <<".lib section in a.out corrupted">>;
@@ -115,6 +116,7 @@ message_1(enopkg) -> <<"package not installed">>;
message_1(enoprotoopt) -> <<"bad proocol option">>;
message_1(enospc) -> <<"no space left on device">>;
message_1(enosr) -> <<"out of stream resources or not a stream device">>;
+message_1(enostr) -> <<"not a stream">>;
message_1(enosym) -> <<"unresolved symbol name">>;
message_1(enosys) -> <<"function not implemented">>;
message_1(enotblk) -> <<"block device required">>;
@@ -128,6 +130,7 @@ message_1(enotty) -> <<"inappropriate device for ioctl">>;
message_1(enotuniq) -> <<"name not unique on network">>;
message_1(enxio) -> <<"no such device or address">>;
message_1(eopnotsupp) -> <<"operation not supported on socket">>;
+message_1(eoverflow) -> <<"offset too large for file system">>;
message_1(eperm) -> <<"not owner">>;
message_1(epfnosupport) -> <<"protocol family not supported">>;
message_1(epipe) -> <<"broken pipe">>;
@@ -167,4 +170,6 @@ message_1(ewouldblock) -> <<"operation would block">>;
message_1(exdev) -> <<"cross-domain link">>;
message_1(exfull) -> <<"message tables full">>;
message_1(nxdomain) -> <<"non-existing domain">>;
+message_1(exbadport) -> <<"inet_drv bad port state">>;
+message_1(exbadseq) -> <<"inet_drv bad request sequence">>;
message_1(_) -> <<"unknown POSIX error">>.
diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl
index ee5e7a11bf..255c0ae81f 100644
--- a/lib/stdlib/src/erl_pp.erl
+++ b/lib/stdlib/src/erl_pp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,7 +26,7 @@
attribute/1,attribute/2,function/1,function/2,
guard/1,guard/2,exprs/1,exprs/2,exprs/3,expr/1,expr/2,expr/3,expr/4]).
--import(lists, [append/1,foldr/3,mapfoldl/3,reverse/1,reverse/2]).
+-import(lists, [append/1,foldr/3,map/2,mapfoldl/3,reverse/1,reverse/2]).
-import(io_lib, [write/1,format/2]).
-import(erl_parse, [inop_prec/1,preop_prec/1,func_prec/0,max_prec/0,
type_inop_prec/1, type_preop_prec/1]).
@@ -41,10 +41,11 @@
io_lib:chars())).
-type(option() :: {hook, hook_function()}
- | {encoding, latin1 | unicode | utf8}).
+ | {encoding, latin1 | unicode | utf8}
+ | {quote_singleton_atom_types, boolean()}).
-type(options() :: hook_function() | [option()]).
--record(pp, {value_fun, string_fun, char_fun}).
+-record(pp, {value_fun, singleton_atom_type_fun, string_fun, char_fun}).
-record(options, {hook, encoding, opts}).
@@ -59,7 +60,7 @@
_ -> ?TEST(T)
end).
-define(EXPRS_TEST(L),
- [?TEST(E) || E <- L]).
+ _ = [?TEST(E) || E <- L]).
-define(TEST(T),
%% Assumes that erl_anno has been compiled with DEBUG=true.
%% erl_pp does not use the annoations, but test it anyway.
@@ -206,22 +207,43 @@ options(Hook) ->
#options{hook = Hook, encoding = encoding([]), opts = Hook}.
state(Options) when is_list(Options) ->
+ Quote = proplists:get_bool(quote_singleton_atom_types, Options),
case encoding(Options) of
- latin1 -> state();
- unicode -> unicode_state()
+ latin1 -> latin1_state(Quote);
+ unicode -> unicode_state(Quote)
end;
state(_Hook) ->
- state().
+ latin1_state(false).
-state() ->
+latin1_state(Quote) ->
Options = [{encoding,latin1}],
- #pp{value_fun = fun(V) -> io_lib_pretty:print(V, Options) end,
+ ValueFun = fun(V) -> io_lib_pretty:print(V, Options) end,
+ SingletonFun =
+ case Quote of
+ true ->
+ fun(A) ->
+ io_lib:write_string_as_latin1(atom_to_list(A), $')
+ end; %'
+ false ->
+ ValueFun
+ end,
+ #pp{value_fun = ValueFun,
+ singleton_atom_type_fun = SingletonFun,
string_fun = fun io_lib:write_string_as_latin1/1,
char_fun = fun io_lib:write_char_as_latin1/1}.
-unicode_state() ->
+unicode_state(Quote) ->
Options = [{encoding,unicode}],
- #pp{value_fun = fun(V) -> io_lib_pretty:print(V, Options) end,
+ ValueFun = fun(V) -> io_lib_pretty:print(V, Options) end,
+ SingletonFun =
+ case Quote of
+ true ->
+ fun(A) -> io_lib:write_string(atom_to_list(A), $') end; %'
+ false ->
+ ValueFun
+ end,
+ #pp{value_fun = ValueFun,
+ singleton_atom_type_fun = SingletonFun,
string_fun = fun io_lib:write_string/1,
char_fun = fun io_lib:write_char/1}.
@@ -237,13 +259,20 @@ lform({attribute,Line,Name,Arg}, Opts) ->
lform({function,Line,Name,Arity,Clauses}, Opts) ->
lfunction({function,Line,Name,Arity,Clauses}, Opts);
%% These are specials to make it easier for the compiler.
-lform({error,E}, _Opts) ->
- leaf(format("~p\n", [{error,E}]));
-lform({warning,W}, _Opts) ->
- leaf(format("~p\n", [{warning,W}]));
+lform({error,_}=E, Opts) ->
+ message(E, Opts);
+lform({warning,_}=W, Opts) ->
+ message(W, Opts);
lform({eof,_Line}, _Opts) ->
$\n.
+message(M, #options{encoding = Encoding}) ->
+ F = case Encoding of
+ latin1 -> "~p\n";
+ unicode -> "~tp\n"
+ end,
+ leaf(format(F, [M])).
+
lattribute({attribute,_Line,type,Type}, Opts) ->
[typeattr(type, Type, Opts),leaf(".\n")];
lattribute({attribute,_Line,opaque,Type}, Opts) ->
@@ -343,7 +372,7 @@ ltype({user_type,Line,T,Ts}, _) ->
ltype({remote_type,Line,[M,F,Ts]}, _) ->
simple_type({remote,Line,M,F}, Ts);
ltype({atom,_,T}, _) ->
- {atom,T};
+ {singleton_atom_type,T};
ltype(E, P) ->
lexpr(E, P, options(none)).
@@ -353,7 +382,12 @@ binary_type(I1, I2) ->
P = max_prec(),
E1 = [[leaf("_:"),lexpr(I1, P, options(none))] || B],
E2 = [[leaf("_:_*"),lexpr(I2, P, options(none))] || U],
- {seq,'<<','>>',[$,],E1++E2}.
+ case E1++E2 of
+ [] ->
+ leaf("<<>>");
+ Es ->
+ {seq,'<<','>>',[$,],Es}
+ end.
map_type(Fs) ->
{first,[$#],map_pair_types(Fs)}.
@@ -379,6 +413,8 @@ typed(B, Type) ->
{_L,_P,R} = type_inop_prec('::'),
{list,[{cstep,[B,' ::'],ltype(Type, R)}]}.
+tuple_type([], _) ->
+ leaf("{}");
tuple_type(Ts, F) ->
{seq,${,$},[$,],ltypes(Ts, F, 0)}.
@@ -447,7 +483,7 @@ pname(A) when is_atom(A) ->
write(A).
falist([]) ->
- [leaf("[]")];
+ ['[]'];
falist(Falist) ->
L = [begin
{Name,Arity} = Fa,
@@ -555,22 +591,22 @@ lexpr({map, _, Map, Fs}, Prec, Opts) ->
El = {first,[Rl,$#],map_fields(Fs, Opts)},
maybe_paren(P, Prec, El);
lexpr({block,_,Es}, _, Opts) ->
- {list,[{step,'begin',body(Es, Opts)},'end']};
+ {list,[{step,'begin',body(Es, Opts)},{reserved,'end'}]};
lexpr({'if',_,Cs}, _, Opts) ->
- {list,[{step,'if',if_clauses(Cs, Opts)},'end']};
+ {list,[{step,'if',if_clauses(Cs, Opts)},{reserved,'end'}]};
lexpr({'case',_,Expr,Cs}, _, Opts) ->
- {list,[{step,{list,[{step,'case',lexpr(Expr, Opts)},'of']},
+ {list,[{step,{list,[{step,'case',lexpr(Expr, Opts)},{reserved,'of'}]},
cr_clauses(Cs, Opts)},
- 'end']};
+ {reserved,'end'}]};
lexpr({'cond',_,Cs}, _, Opts) ->
- {list,[{step,leaf("cond"),cond_clauses(Cs, Opts)},'end']};
+ {list,[{step,leaf("cond"),cond_clauses(Cs, Opts)},{reserved,'end'}]};
lexpr({'receive',_,Cs}, _, Opts) ->
- {list,[{step,'receive',cr_clauses(Cs, Opts)},'end']};
+ {list,[{step,'receive',cr_clauses(Cs, Opts)},{reserved,'end'}]};
lexpr({'receive',_,Cs,To,ToOpt}, _, Opts) ->
Al = {list,[{step,[lexpr(To, Opts),' ->'],body(ToOpt, Opts)}]},
{list,[{step,'receive',cr_clauses(Cs, Opts)},
{step,'after',Al},
- 'end']};
+ {reserved,'end'}]};
lexpr({'fun',_,{function,F,A}}, _Prec, _Opts) ->
[leaf("fun "),{atom,F},leaf(format("/~w", [A]))];
lexpr({'fun',L,{function,_,_}=Func,Extra}, Prec, Opts) ->
@@ -589,17 +625,17 @@ lexpr({'fun',_,{function,M,F,A}}, _Prec, Opts) ->
ArityItem = lexpr(A, Opts),
["fun ",NameItem,$:,CallItem,$/,ArityItem];
lexpr({'fun',_,{clauses,Cs}}, _Prec, Opts) ->
- {list,[{first,'fun',fun_clauses(Cs, Opts, unnamed)},'end']};
+ {list,[{first,'fun',fun_clauses(Cs, Opts, unnamed)},{reserved,'end'}]};
lexpr({named_fun,_,Name,Cs}, _Prec, Opts) ->
- {list,[{first,['fun', " "],fun_clauses(Cs, Opts, {named, Name})},'end']};
+ {list,[{first,['fun', " "],fun_clauses(Cs, Opts, {named, Name})},
+ {reserved,'end'}]};
lexpr({'fun',_,{clauses,Cs},Extra}, _Prec, Opts) ->
{force_nl,fun_info(Extra),
- {list,[{first,'fun',fun_clauses(Cs, Opts, unnamed)},'end']}};
+ {list,[{first,'fun',fun_clauses(Cs, Opts, unnamed)},{reserved,'end'}]}};
lexpr({named_fun,_,Name,Cs,Extra}, _Prec, Opts) ->
{force_nl,fun_info(Extra),
- {list,[{first,['fun', " "],fun_clauses(Cs, Opts, {named, Name})},'end']}};
-lexpr({'query',_,Lc}, _Prec, Opts) ->
- {list,[{step,leaf("query"),lexpr(Lc, 0, Opts)},'end']};
+ {list,[{first,['fun', " "],fun_clauses(Cs, Opts, {named, Name})},
+ {reserved,'end'}]}};
lexpr({call,_,{remote,_,{atom,_,M},{atom,_,F}=N}=Name,Args}, Prec, Opts) ->
case erl_internal:bif(M, F, length(Args)) of
true ->
@@ -614,7 +650,7 @@ lexpr({'try',_,Es,Scs,Ccs,As}, _, Opts) ->
Scs =:= [] ->
{step,'try',body(Es, Opts)};
true ->
- {step,{list,[{step,'try',body(Es, Opts)},'of']},
+ {step,{list,[{step,'try',body(Es, Opts)},{reserved,'of'}]},
cr_clauses(Scs, Opts)}
end,
if
@@ -629,7 +665,7 @@ lexpr({'try',_,Es,Scs,Ccs,As}, _, Opts) ->
true ->
{step,'after',body(As, Opts)}
end,
- 'end']};
+ {reserved,'end'}]};
lexpr({'catch',_,Expr}, Prec, Opts) ->
{P,R} = preop_prec('catch'),
El = {list,[{step,'catch',lexpr(Expr, R, Opts)}]},
@@ -642,7 +678,7 @@ lexpr({match,_,Lhs,Rhs}, Prec, Opts) ->
maybe_paren(P, Prec, El);
lexpr({op,_,Op,Arg}, Prec, Opts) ->
{P,R} = preop_prec(Op),
- Ol = leaf(format("~s ", [Op])),
+ Ol = {reserved, leaf(format("~s ", [Op]))},
El = [Ol,lexpr(Arg, R, Opts)],
maybe_paren(P, Prec, El);
lexpr({op,_,Op,Larg,Rarg}, Prec, Opts) when Op =:= 'orelse';
@@ -650,14 +686,14 @@ lexpr({op,_,Op,Larg,Rarg}, Prec, Opts) when Op =:= 'orelse';
%% Breaks lines since R12B.
{L,P,R} = inop_prec(Op),
Ll = lexpr(Larg, L, Opts),
- Ol = leaf(format("~s", [Op])),
+ Ol = {reserved, leaf(format("~s", [Op]))},
Lr = lexpr(Rarg, R, Opts),
El = {prefer_nl,[[]],[Ll,Ol,Lr]},
maybe_paren(P, Prec, El);
lexpr({op,_,Op,Larg,Rarg}, Prec, Opts) ->
{L,P,R} = inop_prec(Op),
Ll = lexpr(Larg, L, Opts),
- Ol = leaf(format("~s", [Op])),
+ Ol = {reserved, leaf(format("~s", [Op]))},
Lr = lexpr(Rarg, R, Opts),
El = {list,[Ll,Ol,Lr]},
maybe_paren(P, Prec, El);
@@ -692,6 +728,8 @@ fun_info(Extra) ->
%% BITS:
+bit_grp([], _Opts) ->
+ leaf("<<>>");
bit_grp(Fs, Opts) ->
append([['<<'], [bit_elems(Fs, Opts)], ['>>']]).
@@ -875,16 +913,18 @@ lc_qual(Q, Opts) ->
lexpr(Q, 0, Opts).
proper_list(Es, Opts) ->
- {seq,$[,$],$,,lexprs(Es, Opts)}.
+ {seq,$[,$],[$,],lexprs(Es, Opts)}.
improper_list(Es, Opts) ->
- {seq,$[,$],{$,,$|},lexprs(Es, Opts)}.
+ {seq,$[,$],[{$,,' |'}],lexprs(Es, Opts)}.
tuple(L, Opts) ->
tuple(L, fun lexpr/2, Opts).
+tuple([], _F, _Opts) ->
+ leaf("{}");
tuple(Es, F, Opts) ->
- {seq,${,$},$,,lexprs(Es, F, Opts)}.
+ {seq,${,$},[$,],lexprs(Es, F, Opts)}.
args(As, Opts) ->
{seq,$(,$),[$,],lexprs(As, Opts)}.
@@ -904,7 +944,7 @@ maybe_paren(_P, _Prec, Expr) ->
Expr.
leaf(S) ->
- {leaf,chars_size(S),S}.
+ {leaf,string:length(S),S}.
%%% Do the formatting. Currently nothing fancy. Could probably have
%%% done it in one single pass.
@@ -932,6 +972,7 @@ frmt(Item, I, PP) ->
%%% - {prefer_nl,Sep,IPs}: forces linebreak between Is unlesss negative
%%% indentation.
%%% - {atom,A}: an atom
+%%% - {singleton_atom_type,A}: an singleton atom type
%%% - {char,C}: a character
%%% - {string,S}: a string.
%%% - {value,T}: a term.
@@ -964,7 +1005,7 @@ f({seq,Before,After,Sep,LItems}, I0, ST, WT, PP) ->
Sizes = BSizeL ++ SizeL,
NSepChars = if
is_list(Sep), Sep =/= [] ->
- erlang:max(0, length(CharsL)-1);
+ erlang:max(0, length(CharsL)-1); % not string:length
true ->
0
end,
@@ -976,8 +1017,10 @@ f({seq,Before,After,Sep,LItems}, I0, ST, WT, PP) ->
end,
{BCharsL++Chars,Size};
no ->
- {BCharsL++insert_newlines(CharsSizeL, I, ST),
- nsz(lists:last(Sizes), I0)}
+ CharsList = handle_step(CharsSizeL, I, ST),
+ {LChars, LSize} =
+ maybe_newlines(CharsList, LItems, I, NSepChars, ST),
+ {[BCharsL,LChars],nsz(LSize, I0)}
end;
f({force_nl,_ExtraInfoItem,Item}, I, ST, WT, PP) when I < 0 ->
%% Extra info is a comment; cannot have that on the same line
@@ -993,23 +1036,28 @@ f({prefer_nl,Sep,LItems}, I0, ST, WT, PP) ->
Sizes =:= [] ->
{[], 0};
true ->
- {insert_newlines(CharsSize2L, I0, ST),nsz(lists:last(Sizes), I0)}
+ {insert_newlines(CharsSize2L, I0, ST),
+ nsz(lists:last(Sizes), I0)}
end;
f({value,V}, I, ST, WT, PP) ->
f(write_a_value(V, PP), I, ST, WT, PP);
f({atom,A}, I, ST, WT, PP) ->
f(write_an_atom(A, PP), I, ST, WT, PP);
+f({singleton_atom_type,A}, I, ST, WT, PP) ->
+ f(write_a_singleton_atom_type(A, PP), I, ST, WT, PP);
f({char,C}, I, ST, WT, PP) ->
f(write_a_char(C, PP), I, ST, WT, PP);
f({string,S}, I, ST, WT, PP) ->
f(write_a_string(S, I, PP), I, ST, WT, PP);
+f({reserved,R}, I, ST, WT, PP) ->
+ f(R, I, ST, WT, PP);
f({hook,HookExpr,Precedence,Func,Options}, I, _ST, _WT, _PP) ->
Chars = Func(HookExpr, I, Precedence, Options),
{Chars,indentation(Chars, I)};
f({ehook,HookExpr,Precedence,{Mod,Func,Eas}=ModFuncEas}, I, _ST, _WT, _PP) ->
Chars = apply(Mod, Func, [HookExpr,I,Precedence,ModFuncEas|Eas]),
{Chars,indentation(Chars, I)};
-f(WordName, _I, _ST, WT, _PP) -> % when is_atom(WordName)
+f(WordName, _I, _ST, WT, _PP) when is_atom(WordName) ->
word(WordName, WT).
-define(IND, 4).
@@ -1031,12 +1079,18 @@ fl(CItems, Sep0, I0, After, ST, WT, PP) ->
true ->
[CharSize1,f([Item2,S], incr(I0, ?IND), ST, WT, PP)]
end;
+ ({reserved,Word}, S) ->
+ [f([Word,S], I0, ST, WT, PP),{[],0}];
(Item, S) ->
[f([Item,S], I0, ST, WT, PP),{[],0}]
end,
- {Sep,LastSep} = case Sep0 of {_,_} -> Sep0; _ -> {Sep0,Sep0} end,
+ {Sep,LastSep} = sep(Sep0),
fl1(CItems, F, Sep, LastSep, After).
+sep([{S,LS}]) -> {[S],[LS]};
+sep({_,_}=Sep) -> Sep;
+sep(S) -> {S, S}.
+
fl1([CItem], F, _Sep, _LastSep, After) ->
[F(CItem,After)];
fl1([CItem1,CItem2], F, _Sep, LastSep, After) ->
@@ -1062,20 +1116,64 @@ unz1(CharSizes) ->
nonzero(CharSizes) ->
lists:filter(fun({_,Sz}) -> Sz =/= 0 end, CharSizes).
-insert_newlines(CharsSizesL, I, ST) when I >= 0 ->
- insert_nl(foldr(fun([{_C1,0},{_C2,0}], A) ->
- A;
- ([{C1,_Sz1},{_C2,0}], A) ->
- [C1|A];
- ([{C1,_Sz1},{C2,Sz2}], A) when Sz2 > 0 ->
- [insert_nl([C1,C2], I+?IND, ST)|A]
- end, [], CharsSizesL), I, ST).
+maybe_newlines([{Chars,Size}], [], _I, _NSepChars, _ST) ->
+ {Chars,Size};
+maybe_newlines(CharsSizeList, Items, I, NSepChars, ST) when I >= 0 ->
+ maybe_sep(CharsSizeList, Items, I, NSepChars, nl_indent(I, ST)).
+
+maybe_sep([{Chars1,Size1}|CharsSizeL], [Item|Items], I0, NSepChars, Sep) ->
+ I1 = case classify_item(Item) of
+ atomic ->
+ I0 + Size1;
+ _ ->
+ ?MAXLINE+1
+ end,
+ maybe_sep1(CharsSizeL, Items, I0, I1, Sep, NSepChars, Size1, [Chars1]).
+
+maybe_sep1([{Chars,Size}|CharsSizeL], [Item|Items],
+ I0, I, Sep, NSepChars, Sz0, A) ->
+ case classify_item(Item) of
+ atomic when is_integer(Size) ->
+ Size1 = Size + 1,
+ I1 = I + Size1,
+ if
+ I1 =< ?MAXLINE ->
+ A1 = if
+ NSepChars > 0 -> [Chars,$\s|A];
+ true -> [Chars|A]
+ end,
+ maybe_sep1(CharsSizeL, Items, I0, I1, Sep, NSepChars,
+ Sz0 + Size1, A1);
+ true ->
+ A1 = [Chars,Sep|A],
+ maybe_sep1(CharsSizeL, Items, I0, I0 + Size, Sep,
+ NSepChars, Size1, A1)
+ end;
+ _ ->
+ A1 = [Chars,Sep|A],
+ maybe_sep1(CharsSizeL, Items, I0, ?MAXLINE+1, Sep, NSepChars,
+ 0, A1)
+ end;
+maybe_sep1(_CharsSizeL, _Items, _Io, _I, _Sep, _NSepChars, Sz, A) ->
+ {lists:reverse(A), Sz}.
+insert_newlines(CharsSizesL, I, ST) when I >= 0 ->
+ {CharsL, _} = unz1(handle_step(CharsSizesL, I, ST)),
+ insert_nl(CharsL, I, ST).
+
+handle_step(CharsSizesL, I, ST) ->
+ map(fun([{_C1,0},{_C2,0}]) ->
+ {[], 0};
+ ([{C1,Sz1},{_C2,0}]) ->
+ {C1, Sz1};
+ ([{C1,Sz1},{C2,Sz2}]) when Sz2 > 0 ->
+ {insert_nl([C1,C2], I+?IND, ST),line_size([Sz1,Sz2])}
+ end, CharsSizesL).
insert_nl(CharsL, I, ST) ->
insert_sep(CharsL, nl_indent(I, ST)).
-insert_sep([Chars1 | CharsL], Sep) ->
+insert_sep([Chars1|CharsL], Sep) ->
[Chars1 | [[Sep,Chars] || Chars <- CharsL]].
nl_indent(0, _T) ->
@@ -1083,6 +1181,12 @@ nl_indent(0, _T) ->
nl_indent(I, T) when I > 0 ->
[$\n|spaces(I, T)].
+classify_item({atom, _}) -> atomic;
+classify_item({singleton_atom_type, _}) -> atomic;
+classify_item(Atom) when is_atom(Atom) -> atomic;
+classify_item({leaf, _, _}) -> atomic;
+classify_item(_) -> complex.
+
same_line(I0, SizeL, NSepChars) ->
try
Size = lists:sum(SizeL) + NSepChars,
@@ -1120,7 +1224,7 @@ incr(I, Incr) ->
I+Incr.
indentation(E, I) when I < 0 ->
- chars_size(E);
+ string:length(E);
indentation(E, I0) ->
I = io_lib_format:indentation(E, I0),
case has_nl(E) of
@@ -1143,6 +1247,9 @@ write_a_value(V, PP) ->
write_an_atom(A, PP) ->
flat_leaf(write_atom(A, PP)).
+write_a_singleton_atom_type(A, PP) ->
+ flat_leaf(write_singleton_atom_type(A, PP)).
+
write_a_char(C, PP) ->
flat_leaf(write_char(C, PP)).
@@ -1157,19 +1264,19 @@ write_a_string(S, I, PP) ->
write_a_string([], _N, _Len, _PP) ->
[];
write_a_string(S, N, Len, PP) ->
- SS = string:sub_string(S, 1, N),
+ SS = string:slice(S, 0, N),
Sl = write_string(SS, PP),
- case (chars_size(Sl) > Len) and (N > ?MIN_SUBSTRING) of
+ case (string:length(Sl) > Len) and (N > ?MIN_SUBSTRING) of
true ->
write_a_string(S, N-1, Len, PP);
false ->
[flat_leaf(Sl) |
- write_a_string(lists:nthtail(length(SS), S), Len, Len, PP)]
+ write_a_string(string:slice(S, string:length(SS)), Len, Len, PP)]
end.
flat_leaf(S) ->
L = lists:flatten(S),
- {leaf,length(L),L}.
+ {leaf,string:length(L),L}.
write_value(V, PP) ->
(PP#pp.value_fun)(V).
@@ -1177,6 +1284,9 @@ write_value(V, PP) ->
write_atom(A, PP) ->
(PP#pp.value_fun)(A).
+write_singleton_atom_type(A, PP) ->
+ (PP#pp.singleton_atom_type_fun)(A).
+
write_string(S, PP) ->
(PP#pp.string_fun)(S).
@@ -1190,15 +1300,6 @@ write_char(C, PP) ->
a0() ->
erl_anno:new(0).
-chars_size([C | Es]) when is_integer(C) ->
- 1 + chars_size(Es);
-chars_size([E | Es]) ->
- chars_size(E) + chars_size(Es);
-chars_size([]) ->
- 0;
-chars_size(B) when is_binary(B) ->
- byte_size(B).
-
-define(N_SPACES, 30).
spacetab() ->
diff --git a/lib/stdlib/src/erl_scan.erl b/lib/stdlib/src/erl_scan.erl
index 47223b129c..4774c4bf19 100644
--- a/lib/stdlib/src/erl_scan.erl
+++ b/lib/stdlib/src/erl_scan.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -752,7 +752,7 @@ scan_string(Cs, St, Line, Col, Toks, {Wcs,Str,Line0,Col0}) ->
{char_error,Ncs,Error,Nline,Ncol,EndCol} ->
scan_error(Error, Nline, Ncol, Nline, EndCol, Ncs);
{error,Nline,Ncol,Nwcs,Ncs} ->
- Estr = string:substr(Nwcs, 1, 16), % Expanded escape chars.
+ Estr = string:slice(Nwcs, 0, 16), % Expanded escape chars.
scan_error({string,$\",Estr}, Line0, Col0, Nline, Ncol, Ncs); %"
{Ncs,Nline,Ncol,Nstr,Nwcs} ->
Anno = anno(Line0, Col0, St, Nstr),
@@ -767,7 +767,7 @@ scan_qatom(Cs, St, Line, Col, Toks, {Wcs,Str,Line0,Col0}) ->
{char_error,Ncs,Error,Nline,Ncol,EndCol} ->
scan_error(Error, Nline, Ncol, Nline, EndCol, Ncs);
{error,Nline,Ncol,Nwcs,Ncs} ->
- Estr = string:substr(Nwcs, 1, 16), % Expanded escape chars.
+ Estr = string:slice(Nwcs, 0, 16), % Expanded escape chars.
scan_error({string,$\',Estr}, Line0, Col0, Nline, Ncol, Ncs); %'
{Ncs,Nline,Ncol,Nstr,Nwcs} ->
case catch list_to_atom(Nwcs) of
diff --git a/lib/stdlib/src/erl_tar.erl b/lib/stdlib/src/erl_tar.erl
index 5ee584d612..7064fcacfa 100644
--- a/lib/stdlib/src/erl_tar.erl
+++ b/lib/stdlib/src/erl_tar.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -324,7 +324,7 @@ do_open(Name, Mode) when is_list(Mode) ->
open1({binary,Bin}, read, _Raw, Opts) when is_binary(Bin) ->
case file:open(Bin, [ram,binary,read]) of
{ok,File} ->
- _ = [ram_file:uncompress(File) || Opts =:= [compressed]],
+ _ = [ram_file:uncompress(File) || lists:member(compressed, Opts)],
{ok, #reader{handle=File,access=read,func=fun file_op/2}};
Error ->
Error
@@ -357,7 +357,7 @@ open_mode([read|Rest], false, Raw, Opts) ->
open_mode([write|Rest], false, Raw, Opts) ->
open_mode(Rest, write, Raw, Opts);
open_mode([compressed|Rest], Access, Raw, Opts) ->
- open_mode(Rest, Access, Raw, [compressed|Opts]);
+ open_mode(Rest, Access, Raw, [compressed,read_ahead|Opts]);
open_mode([cooked|Rest], Access, _Raw, Opts) ->
open_mode(Rest, Access, [], Opts);
open_mode([], Access, Raw, Opts) ->
@@ -457,26 +457,61 @@ add(Reader, NameOrBin, NameInArchive, Options)
do_add(#reader{access=write}=Reader, Name, NameInArchive, Options)
when is_list(NameInArchive), is_list(Options) ->
- RF = fun(F) -> file:read_link_info(F, [{time, posix}]) end,
+ RF = apply_file_info_opts_fun(Options, read_link_info),
Opts = #add_opts{read_info=RF},
- add1(Reader, Name, NameInArchive, add_opts(Options, Opts));
+ add1(Reader, Name, NameInArchive, add_opts(Options, Options, Opts));
do_add(#reader{access=read},_,_,_) ->
{error, eacces};
do_add(Reader,_,_,_) ->
{error, {badarg, Reader}}.
-add_opts([dereference|T], Opts) ->
- RF = fun(F) -> file:read_file_info(F, [{time, posix}]) end,
- add_opts(T, Opts#add_opts{read_info=RF});
-add_opts([verbose|T], Opts) ->
- add_opts(T, Opts#add_opts{verbose=true});
-add_opts([{chunks,N}|T], Opts) ->
- add_opts(T, Opts#add_opts{chunk_size=N});
-add_opts([_|T], Opts) ->
- add_opts(T, Opts);
-add_opts([], Opts) ->
+add_opts([dereference|T], AllOptions, Opts) ->
+ RF = apply_file_info_opts_fun(AllOptions, read_file_info),
+ add_opts(T, AllOptions, Opts#add_opts{read_info=RF});
+add_opts([verbose|T], AllOptions, Opts) ->
+ add_opts(T, AllOptions, Opts#add_opts{verbose=true});
+add_opts([{chunks,N}|T], AllOptions, Opts) ->
+ add_opts(T, AllOptions, Opts#add_opts{chunk_size=N});
+add_opts([{atime,Value}|T], AllOptions, Opts) ->
+ add_opts(T, AllOptions, Opts#add_opts{atime=Value});
+add_opts([{mtime,Value}|T], AllOptions, Opts) ->
+ add_opts(T, AllOptions, Opts#add_opts{mtime=Value});
+add_opts([{ctime,Value}|T], AllOptions, Opts) ->
+ add_opts(T, AllOptions, Opts#add_opts{ctime=Value});
+add_opts([{uid,Value}|T], AllOptions, Opts) ->
+ add_opts(T, AllOptions, Opts#add_opts{uid=Value});
+add_opts([{gid,Value}|T], AllOptions, Opts) ->
+ add_opts(T, AllOptions, Opts#add_opts{gid=Value});
+add_opts([_|T], AllOptions, Opts) ->
+ add_opts(T, AllOptions, Opts);
+add_opts([], _AllOptions, Opts) ->
Opts.
+apply_file_info_opts(Opts, {ok, FileInfo}) ->
+ {ok, do_apply_file_info_opts(Opts, FileInfo)};
+apply_file_info_opts(_Opts, Other) ->
+ Other.
+
+do_apply_file_info_opts([{atime,Value}|T], FileInfo) ->
+ do_apply_file_info_opts(T, FileInfo#file_info{atime=Value});
+do_apply_file_info_opts([{mtime,Value}|T], FileInfo) ->
+ do_apply_file_info_opts(T, FileInfo#file_info{mtime=Value});
+do_apply_file_info_opts([{ctime,Value}|T], FileInfo) ->
+ do_apply_file_info_opts(T, FileInfo#file_info{ctime=Value});
+do_apply_file_info_opts([{uid,Value}|T], FileInfo) ->
+ do_apply_file_info_opts(T, FileInfo#file_info{uid=Value});
+do_apply_file_info_opts([{gid,Value}|T], FileInfo) ->
+ do_apply_file_info_opts(T, FileInfo#file_info{gid=Value});
+do_apply_file_info_opts([_|T], FileInfo) ->
+ do_apply_file_info_opts(T, FileInfo);
+do_apply_file_info_opts([], FileInfo) ->
+ FileInfo.
+
+apply_file_info_opts_fun(Options, InfoFunction) ->
+ fun(F) ->
+ apply_file_info_opts(Options, file:InfoFunction(F, [{time, posix}]))
+ end.
+
add1(#reader{}=Reader, Name, NameInArchive, #add_opts{read_info=ReadInfo}=Opts)
when is_list(Name) ->
Res = case ReadInfo(Name) of
@@ -515,9 +550,11 @@ add1(Reader, Bin, NameInArchive, Opts) when is_binary(Bin) ->
name = NameInArchive,
size = byte_size(Bin),
typeflag = ?TYPE_REGULAR,
- atime = Now,
- mtime = Now,
- ctime = Now,
+ atime = add_opts_time(Opts#add_opts.atime, Now),
+ mtime = add_opts_time(Opts#add_opts.mtime, Now),
+ ctime = add_opts_time(Opts#add_opts.ctime, Now),
+ uid = Opts#add_opts.uid,
+ gid = Opts#add_opts.gid,
mode = 8#100644},
{ok, Reader2} = add_header(Reader, Header, Opts),
Padding = skip_padding(byte_size(Bin)),
@@ -527,6 +564,9 @@ add1(Reader, Bin, NameInArchive, Opts) when is_binary(Bin) ->
{error, Reason} -> {error, {NameInArchive, Reason}}
end.
+add_opts_time(undefined, Now) -> Now;
+add_opts_time(Time, _Now) -> Time.
+
add_directory(Reader, DirName, NameInArchive, Info, Opts) ->
case file:list_dir(DirName) of
{ok, []} ->
@@ -1650,8 +1690,12 @@ write_file(Name, Bin) ->
case file:write_file(Name, Bin) of
ok -> ok;
{error,enoent} ->
- ok = make_dirs(Name, file),
- write_file(Name, Bin);
+ case make_dirs(Name, file) of
+ ok ->
+ write_file(Name, Bin);
+ {error,Reason} ->
+ throw({error, Reason})
+ end;
{error,Reason} ->
throw({error, Reason})
end.
diff --git a/lib/stdlib/src/erl_tar.hrl b/lib/stdlib/src/erl_tar.hrl
index cff0c2f500..5d6cecbb66 100644
--- a/lib/stdlib/src/erl_tar.hrl
+++ b/lib/stdlib/src/erl_tar.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,7 +21,12 @@
-record(add_opts, {
read_info, %% Fun to use for read file/link info.
chunk_size = 0, %% For file reading when sending to sftp. 0=do not chunk
- verbose = false}). %% Verbose on/off.
+ verbose = false, %% Verbose on/off.
+ atime = undefined,
+ mtime = undefined,
+ ctime = undefined,
+ uid = 0,
+ gid = 0}).
-type add_opts() :: #add_opts{}.
%% Options used when reading a tar archive.
@@ -36,7 +41,12 @@
-type add_opt() :: dereference |
verbose |
- {chunks, pos_integer()}.
+ {chunks, pos_integer()} |
+ {atime, non_neg_integer()} |
+ {mtime, non_neg_integer()} |
+ {ctime, non_neg_integer()} |
+ {uid, non_neg_integer()} |
+ {gid, non_neg_integer()}.
-type extract_opt() :: {cwd, string()} |
{files, [string()]} |
diff --git a/lib/stdlib/src/escript.erl b/lib/stdlib/src/escript.erl
index 2b9d8ff65b..3f14894b55 100644
--- a/lib/stdlib/src/escript.erl
+++ b/lib/stdlib/src/escript.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -224,8 +224,8 @@ return_sections(S, Bin) ->
normalize_section(Name, undefined) ->
{Name, undefined};
normalize_section(shebang, "#!" ++ Chars) ->
- Chopped = string:strip(Chars, right, $\n),
- Stripped = string:strip(Chopped, both),
+ Chopped = string:trim(Chars, trailing, "$\n"),
+ Stripped = string:trim(Chopped, both),
if
Stripped =:= ?SHEBANG ->
{shebang, default};
@@ -233,8 +233,8 @@ normalize_section(shebang, "#!" ++ Chars) ->
{shebang, Stripped}
end;
normalize_section(comment, Chars) ->
- Chopped = string:strip(Chars, right, $\n),
- Stripped = string:strip(string:strip(Chopped, left, $%), both),
+ Chopped = string:trim(Chars, trailing, "$\n"),
+ Stripped = string:trim(string:trim(Chopped, leading, "$%"), both),
if
Stripped =:= ?COMMENT ->
{comment, default};
@@ -242,8 +242,8 @@ normalize_section(comment, Chars) ->
{comment, Stripped}
end;
normalize_section(emu_args, "%%!" ++ Chars) ->
- Chopped = string:strip(Chars, right, $\n),
- Stripped = string:strip(Chopped, both),
+ Chopped = string:trim(Chars, trailing, "$\n"),
+ Stripped = string:trim(Chopped, both),
{emu_args, Stripped};
normalize_section(Name, Chars) ->
{Name, Chars}.
@@ -283,8 +283,7 @@ start(EscriptOptions) ->
throw:Str ->
io:format("escript: ~ts\n", [Str]),
my_halt(127);
- _:Reason ->
- Stk = erlang:get_stacktrace(),
+ _:Reason:Stk ->
io:format("escript: Internal error: ~tp\n", [Reason]),
io:format("~tp\n", [Stk]),
my_halt(127)
@@ -759,8 +758,8 @@ run(Module, Args) ->
Module:main(Args),
my_halt(0)
catch
- Class:Reason ->
- fatal(format_exception(Class, Reason))
+ Class:Reason:StackTrace ->
+ fatal(format_exception(Class, Reason, StackTrace))
end.
-spec interpret(_, _, _, _) -> no_return().
@@ -793,8 +792,8 @@ interpret(Forms, HasRecs, File, Args) ->
end}),
my_halt(0)
catch
- Class:Reason ->
- fatal(format_exception(Class, Reason))
+ Class:Reason:StackTrace ->
+ fatal(format_exception(Class, Reason, StackTrace))
end.
report_errors(Errors) ->
@@ -873,7 +872,7 @@ eval_exprs([E|Es], Bs0, Lf, Ef, RBs) ->
{value,_V,Bs} = erl_eval:expr(E, Bs0, Lf, Ef, RBs1),
eval_exprs(Es, Bs, Lf, Ef, RBs).
-format_exception(Class, Reason) ->
+format_exception(Class, Reason, StackTrace) ->
Enc = encoding(),
P = case Enc of
latin1 -> "P";
@@ -882,9 +881,8 @@ format_exception(Class, Reason) ->
PF = fun(Term, I) ->
io_lib:format("~." ++ integer_to_list(I) ++ P, [Term, 50])
end,
- StackTrace = erlang:get_stacktrace(),
StackFun = fun(M, _F, _A) -> (M =:= erl_eval) or (M =:= ?MODULE) end,
- lib:format_exception(1, Class, Reason, StackTrace, StackFun, PF, Enc).
+ erl_error:format_exception(1, Class, Reason, StackTrace, StackFun, PF, Enc).
encoding() ->
[{encoding, Encoding}] = enc(),
@@ -916,8 +914,8 @@ hidden_apply(App, M, F, Args) ->
try
apply(fun() -> M end(), F, Args)
catch
- error:undef ->
- case erlang:get_stacktrace() of
+ error:undef:StackTrace ->
+ case StackTrace of
[{M,F,Args,_} | _] ->
Arity = length(Args),
Text = io_lib:format("Call to ~w:~w/~w in application ~w failed.\n",
diff --git a/lib/stdlib/src/ets.erl b/lib/stdlib/src/ets.erl
index 42fa8ede92..29f907ad73 100644
--- a/lib/stdlib/src/ets.erl
+++ b/lib/stdlib/src/ets.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -73,10 +73,13 @@
select_count/2, select_delete/2, select_replace/2, select_reverse/1,
select_reverse/2, select_reverse/3, setopts/2, slot/2,
take/2,
- update_counter/3, update_counter/4, update_element/3]).
+ update_counter/3, update_counter/4, update_element/3,
+ whereis/1]).
%% internal exports
--export([internal_request_all/0]).
+-export([internal_request_all/0,
+ internal_delete_all/2,
+ internal_select_delete/2]).
-spec all() -> [Tab] when
Tab :: tab().
@@ -115,7 +118,15 @@ delete(_, _) ->
-spec delete_all_objects(Tab) -> true when
Tab :: tab().
-delete_all_objects(_) ->
+delete_all_objects(Tab) ->
+ _ = ets:internal_delete_all(Tab, undefined),
+ true.
+
+-spec internal_delete_all(Tab, undefined) -> NumDeleted when
+ Tab :: tab(),
+ NumDeleted :: non_neg_integer().
+
+internal_delete_all(_, _) ->
erlang:nif_error(undef).
-spec delete_object(Tab, Object) -> true when
@@ -145,6 +156,7 @@ give_away(_, _, _) ->
InfoList :: [InfoTuple],
InfoTuple :: {compressed, boolean()}
| {heir, pid() | none}
+ | {id, tid()}
| {keypos, pos_integer()}
| {memory, non_neg_integer()}
| {name, atom()}
@@ -162,7 +174,7 @@ info(_) ->
-spec info(Tab, Item) -> Value | undefined when
Tab :: tab(),
- Item :: compressed | fixed | heir | keypos | memory
+ Item :: compressed | fixed | heir | id | keypos | memory
| name | named_table | node | owner | protection
| safe_fixed | safe_fixed_monotonic_time | size | stats | type
| write_concurrency | read_concurrency,
@@ -376,7 +388,17 @@ select_count(_, _) ->
MatchSpec :: match_spec(),
NumDeleted :: non_neg_integer().
-select_delete(_, _) ->
+select_delete(Tab, [{'_',[],[true]}]) ->
+ ets:internal_delete_all(Tab, undefined);
+select_delete(Tab, MatchSpec) ->
+ ets:internal_select_delete(Tab, MatchSpec).
+
+-spec internal_select_delete(Tab, MatchSpec) -> NumDeleted when
+ Tab :: tab(),
+ MatchSpec :: match_spec(),
+ NumDeleted :: non_neg_integer().
+
+internal_select_delete(_, _) ->
erlang:nif_error(undef).
-spec select_replace(Tab, MatchSpec) -> NumReplaced when
@@ -512,6 +534,11 @@ update_counter(_, _, _, _) ->
update_element(_, _, _) ->
erlang:nif_error(undef).
+-spec whereis(TableName) -> tid() | undefined when
+ TableName :: atom().
+whereis(_) ->
+ erlang:nif_error(undef).
+
%%% End of BIFs
-opaque comp_match_spec() :: reference().
@@ -882,10 +909,10 @@ tab2file(Tab, File, Options) ->
_ = disk_log:close(Name),
_ = file:delete(File),
exit(ExReason);
- error:ErReason ->
+ error:ErReason:StackTrace ->
_ = disk_log:close(Name),
_ = file:delete(File),
- erlang:raise(error,ErReason,erlang:get_stacktrace())
+ erlang:raise(error,ErReason,StackTrace)
end
catch
throw:TReason2 ->
@@ -1060,9 +1087,9 @@ file2tab(File, Opts) ->
exit:ExReason ->
ets:delete(Tab),
exit(ExReason);
- error:ErReason ->
+ error:ErReason:StackTrace ->
ets:delete(Tab),
- erlang:raise(error,ErReason,erlang:get_stacktrace())
+ erlang:raise(error,ErReason,StackTrace)
end
after
_ = disk_log:close(Name)
@@ -1719,7 +1746,7 @@ get_line(P, Default) ->
line_string(Binary) when is_binary(Binary) -> unicode:characters_to_list(Binary);
line_string(Other) -> Other.
-nonl(S) -> string:strip(S, right, $\n).
+nonl(S) -> string:trim(S, trailing, "$\n").
print_number(Tab, Key, Num) ->
Os = ets:lookup(Tab, Key),
@@ -1748,7 +1775,7 @@ do_display_item(_Height, Width, I, Opos) ->
L = to_string(I),
L2 = if
length(L) > Width - 8 ->
- string:substr(L, 1, Width-13) ++ " ...";
+ string:slice(L, 0, Width-13) ++ " ...";
true ->
L
end,
diff --git a/lib/stdlib/src/eval_bits.erl b/lib/stdlib/src/eval_bits.erl
index 631faa3be5..bb86a65c72 100644
--- a/lib/stdlib/src/eval_bits.erl
+++ b/lib/stdlib/src/eval_bits.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,6 +25,9 @@
-export([expr_grp/3,expr_grp/5,match_bits/6,
match_bits/7,bin_gen/6]).
+-define(STACKTRACE,
+ element(2, erlang:process_info(self(), current_stacktrace))).
+
%% Types used in this module:
%% @type bindings(). An abstract structure for bindings between
%% variables and values (the environment)
@@ -93,9 +96,9 @@ eval_exp_field1(V, Size, Unit, Type, Endian, Sign) ->
eval_exp_field(V, Size, Unit, Type, Endian, Sign)
catch
error:system_limit ->
- error(system_limit);
+ erlang:raise(error, system_limit, ?STACKTRACE);
error:_ ->
- error(badarg)
+ erlang:raise(error, badarg, ?STACKTRACE)
end.
eval_exp_field(Val, Size, Unit, integer, little, signed) ->
@@ -131,7 +134,7 @@ eval_exp_field(Val, all, Unit, binary, _, _) ->
Size when Size rem Unit =:= 0 ->
<<Val:Size/binary-unit:1>>;
_ ->
- error(badarg)
+ erlang:raise(error, badarg, ?STACKTRACE)
end;
eval_exp_field(Val, Size, Unit, binary, _, _) ->
<<Val:(Size*Unit)/binary-unit:1>>.
@@ -377,12 +380,12 @@ make_bit_type(Line, default, Type0) ->
{ok,all,Bt} -> {{atom,Line,all},erl_bits:as_list(Bt)};
{ok,undefined,Bt} -> {{atom,Line,undefined},erl_bits:as_list(Bt)};
{ok,Size,Bt} -> {{integer,Line,Size},erl_bits:as_list(Bt)};
- {error,Reason} -> error(Reason)
+ {error,Reason} -> erlang:raise(error, Reason, ?STACKTRACE)
end;
make_bit_type(_Line, Size, Type0) -> %Size evaluates to an integer or 'all'
case erl_bits:set_bit_type(Size, Type0) of
{ok,Size,Bt} -> {Size,erl_bits:as_list(Bt)};
- {error,Reason} -> error(Reason)
+ {error,Reason} -> erlang:raise(error, Reason, ?STACKTRACE)
end.
match_check_size(Mfun, Size, Bs) ->
@@ -405,9 +408,3 @@ match_check_size(_, {value,_,_}, _Bs, _AllowAll) ->
ok; %From the debugger.
match_check_size(_, _, _Bs, _AllowAll) ->
throw(invalid).
-
-%% error(Reason) -> exception thrown
-%% Throw a nice-looking exception, similar to exceptions from erl_eval.
-error(Reason) ->
- erlang:raise(error, Reason, [{erl_eval,expr,3}]).
-
diff --git a/lib/stdlib/src/file_sorter.erl b/lib/stdlib/src/file_sorter.erl
index 3aeaff8dc4..191e050538 100644
--- a/lib/stdlib/src/file_sorter.erl
+++ b/lib/stdlib/src/file_sorter.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1314,9 +1314,9 @@ infun(W) ->
{cont, W#w{in = NFun}, Objs};
Error ->
error(Error, W1)
- catch Class:Reason ->
+ catch Class:Reason:Stacktrace ->
cleanup(W1),
- erlang:raise(Class, Reason, erlang:get_stacktrace())
+ erlang:raise(Class, Reason, Stacktrace)
end.
outfun(A, #w{inout_value = Val} = W) when Val =/= no_value ->
@@ -1336,9 +1336,9 @@ outfun(A, W) ->
W#w{out = NF};
Error ->
error(Error, W1)
- catch Class:Reason ->
+ catch Class:Reason:Stacktrace ->
cleanup(W1),
- erlang:raise(Class, Reason, erlang:get_stacktrace())
+ erlang:raise(Class, Reason, Stacktrace)
end.
is_keypos(Keypos) when is_integer(Keypos), Keypos > 0 ->
diff --git a/lib/stdlib/src/filelib.erl b/lib/stdlib/src/filelib.erl
index a9c055f72d..de839be5cf 100644
--- a/lib/stdlib/src/filelib.erl
+++ b/lib/stdlib/src/filelib.erl
@@ -365,11 +365,18 @@ do_list_dir(Dir, Mod) -> eval_list_dir(Dir, Mod).
%%% Compiling a wildcard.
+
+%% Define characters used for escaping a \.
+-define(ESCAPE_PREFIX, $@).
+-define(ESCAPE_CHARACTER, [?ESCAPE_PREFIX,$e]).
+-define(ESCAPED_ESCAPE_PREFIX, [?ESCAPE_PREFIX,?ESCAPE_PREFIX]).
+
%% Only for debugging.
compile_wildcard(Pattern) when is_list(Pattern) ->
{compiled_wildcard,?HANDLE_ERROR(compile_wildcard(Pattern, "."))}.
-compile_wildcard(Pattern, Cwd0) ->
+compile_wildcard(Pattern0, Cwd0) ->
+ Pattern = convert_escapes(Pattern0),
[Root|Rest] = filename:split(Pattern),
case filename:pathtype(Root) of
relative ->
@@ -409,7 +416,8 @@ compile_join({cwd,Cwd}, File0) ->
compile_join({root,PrefixLen,Root}, File) ->
{root,PrefixLen,filename:join(Root, File)}.
-compile_part(Part) ->
+compile_part(Part0) ->
+ Part = wrap_escapes(Part0),
compile_part(Part, false, []).
compile_part_to_sep(Part) ->
@@ -445,6 +453,8 @@ compile_part([${|Rest], Upto, Result) ->
error ->
compile_part(Rest, Upto, [${|Result])
end;
+compile_part([{escaped,X}|Rest], Upto, Result) ->
+ compile_part(Rest, Upto, [X|Result]);
compile_part([X|Rest], Upto, Result) ->
compile_part(Rest, Upto, [X|Result]);
compile_part([], _Upto, Result) ->
@@ -461,6 +471,8 @@ compile_charset1([Lower, $-, Upper|Rest], Ordset) when Lower =< Upper ->
compile_charset1(Rest, compile_range(Lower, Upper, Ordset));
compile_charset1([$]|Rest], Ordset) ->
{ok, {one_of, gb_sets:from_ordset(Ordset)}, Rest};
+compile_charset1([{escaped,X}|Rest], Ordset) ->
+ compile_charset1(Rest, ordsets:add_element(X, Ordset));
compile_charset1([X|Rest], Ordset) ->
compile_charset1(Rest, ordsets:add_element(X, Ordset));
compile_charset1([], _Ordset) ->
@@ -486,6 +498,32 @@ compile_alt(Pattern, Result) ->
error
end.
+%% Convert backslashes to an illegal Unicode character to
+%% protect in from filename:split/1.
+
+convert_escapes([?ESCAPE_PREFIX|T]) ->
+ ?ESCAPED_ESCAPE_PREFIX ++ convert_escapes(T);
+convert_escapes([$\\|T]) ->
+ ?ESCAPE_CHARACTER ++ convert_escapes(T);
+convert_escapes([H|T]) ->
+ [H|convert_escapes(T)];
+convert_escapes([]) ->
+ [].
+
+%% Wrap each escape in a tuple to remove the special meaning for
+%% the character that follows.
+
+wrap_escapes(?ESCAPED_ESCAPE_PREFIX ++ T) ->
+ [?ESCAPE_PREFIX|wrap_escapes(T)];
+wrap_escapes(?ESCAPE_CHARACTER ++ [C|T]) ->
+ [{escaped,C}|wrap_escapes(T)];
+wrap_escapes(?ESCAPE_CHARACTER) ->
+ [];
+wrap_escapes([H|T]) ->
+ [H|wrap_escapes(T)];
+wrap_escapes([]) ->
+ [].
+
badpattern(Reason) ->
error({badpattern,Reason}).
diff --git a/lib/stdlib/src/filename.erl b/lib/stdlib/src/filename.erl
index ee807dfd09..b7b7b562ab 100644
--- a/lib/stdlib/src/filename.erl
+++ b/lib/stdlib/src/filename.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -34,6 +34,38 @@
%% we flatten the arguments immediately on function entry as that makes
%% it easier to ensure that the code works.
+%%
+%% *** Requirements on Raw Filename Format ***
+%%
+%% These requirements are due to the 'filename' module
+%% in stdlib. This since it is documented that it
+%% should be able to operate on raw filenames as well
+%% as ordinary filenames.
+%%
+%% A raw filename *must* be a byte sequence where:
+%% 1. Codepoints 0-127 (7-bit ascii) *must* be encoded
+%% as a byte with the corresponding value. That is,
+%% the most significant bit in the byte encoding the
+%% codepoint is never set.
+%% 2. Codepoints greater than 127 *must* be encoded
+%% with the most significant bit set in *every* byte
+%% encoding it.
+%%
+%% Latin1 and UTF-8 meet these requirements while
+%% UTF-16 and UTF-32 don't.
+%%
+%% On Windows filenames are natively stored as malformed
+%% UTF-16LE (lonely surrogates may appear). A more correct
+%% description than UTF-16 would be an array of 16-bit
+%% words... In order to meet the requirements of the
+%% raw file format we convert the malformed UTF-16LE to
+%% malformed UTF-8 which meet the requirements.
+%%
+%% Note that these requirements are today only OTP
+%% internal (erts-stdlib internal) requirements that
+%% could be changed.
+%%
+
-export([absname/1, absname/2, absname_join/2,
basename/1, basename/2, dirname/1,
extension/1, join/1, join/2, pathtype/1,
@@ -41,6 +73,7 @@
safe_relative_path/1]).
-export([find_src/1, find_src/2]). % deprecated
-export([basedir/2, basedir/3]).
+-export([validate/1]).
%% Undocumented and unsupported exports.
-export([append/2]).
@@ -979,24 +1012,33 @@ filename_string_to_binary(List) ->
%% basedir
%% http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
--type basedir_type() :: 'user_cache' | 'user_config' | 'user_data'
- | 'user_log'
- | 'site_config' | 'site_data'.
+-type basedir_path_type() :: 'user_cache' | 'user_config' | 'user_data'
+ | 'user_log'.
+-type basedir_paths_type() :: 'site_config' | 'site_data'.
+
+-type basedir_opts() :: #{author => string() | binary(),
+ os => 'windows' | 'darwin' | 'linux',
+ version => string() | binary()}.
--spec basedir(Type,Application) -> file:filename_all() when
- Type :: basedir_type(),
+-spec basedir(PathType,Application) -> file:filename_all() when
+ PathType :: basedir_path_type(),
+ Application :: string() | binary();
+ (PathsType,Application) -> [file:filename_all()] when
+ PathsType :: basedir_paths_type(),
Application :: string() | binary().
basedir(Type,Application) when is_atom(Type), is_list(Application) orelse
is_binary(Application) ->
basedir(Type, Application, #{}).
--spec basedir(Type,Application,Opts) -> file:filename_all() when
- Type :: basedir_type(),
+-spec basedir(PathType,Application,Opts) -> file:filename_all() when
+ PathType :: basedir_path_type(),
Application :: string() | binary(),
- Opts :: #{author => string() | binary(),
- os => 'windows' | 'darwin' | 'linux',
- version => string() | binary()}.
+ Opts :: basedir_opts();
+ (PathsType,Application,Opts) -> [file:filename_all()] when
+ PathsType :: basedir_paths_type(),
+ Application :: string() | binary(),
+ Opts :: basedir_opts().
basedir(Type,Application,Opts) when is_atom(Type), is_map(Opts),
is_list(Application) orelse
@@ -1053,10 +1095,10 @@ basedir_linux(Type) ->
user_log -> getenv("XDG_CACHE_HOME", ?basedir_linux_user_log, true);
site_data ->
Base = getenv("XDG_DATA_DIRS",?basedir_linux_site_data,false),
- string:tokens(Base,":");
+ string:lexemes(Base, ":");
site_config ->
Base = getenv("XDG_CONFIG_DIRS",?basedir_linux_site_config,false),
- string:tokens(Base,":")
+ string:lexemes(Base, ":")
end.
-define(basedir_darwin_user_data, "Library/Application Support").
@@ -1152,3 +1194,72 @@ basedir_os_type() ->
{win32,_} -> windows;
_ -> linux
end.
+
+%%
+%% validate/1
+%%
+
+-spec validate(FileName) -> boolean() when
+ FileName :: file:name_all().
+
+validate(FileName) when is_binary(FileName) ->
+ %% Raw filename...
+ validate_bin(FileName);
+validate(FileName) when is_list(FileName);
+ is_atom(FileName) ->
+ validate_list(FileName,
+ file:native_name_encoding(),
+ os:type()).
+
+validate_list(FileName, Enc, Os) ->
+ try
+ true = validate_list(FileName, Enc, Os, 0) > 0
+ catch
+ _ : _ -> false
+ end.
+
+validate_list([], _Enc, _Os, Chars) ->
+ Chars;
+validate_list(C, Enc, Os, Chars) when is_integer(C) ->
+ validate_char(C, Enc, Os),
+ Chars+1;
+validate_list(A, Enc, Os, Chars) when is_atom(A) ->
+ validate_list(atom_to_list(A), Enc, Os, Chars);
+validate_list([H|T], Enc, Os, Chars) ->
+ NewChars = validate_list(H, Enc, Os, Chars),
+ validate_list(T, Enc, Os, NewChars).
+
+%% C is always an integer...
+% validate_char(C, _, _) when not is_integer(C) ->
+% throw(invalid);
+validate_char(C, _, _) when C < 1 ->
+ throw(invalid); %% No negative or null characters...
+validate_char(C, latin1, _) when C > 255 ->
+ throw(invalid);
+validate_char(C, utf8, _) when C >= 16#110000 ->
+ throw(invalid);
+validate_char(C, utf8, {win32, _}) when C > 16#ffff ->
+ throw(invalid); %% invalid win wchar...
+validate_char(_C, utf8, {win32, _}) ->
+ ok; %% Range below is accepted on windows...
+validate_char(C, utf8, _) when 16#D800 =< C, C =< 16#DFFF ->
+ throw(invalid); %% invalid unicode range...
+validate_char(_, _, _) ->
+ ok.
+
+validate_bin(Bin) ->
+ %% Raw filename. That is, we do not interpret
+ %% the encoding, but we still do not accept
+ %% null characters...
+ try
+ true = validate_bin(Bin, 0) > 0
+ catch
+ _ : _ -> false
+ end.
+
+validate_bin(<<>>, Bs) ->
+ Bs;
+validate_bin(<<0, _Rest/binary>>, _Bs) ->
+ throw(invalid); %% No null characters allowed...
+validate_bin(<<_B, Rest/binary>>, Bs) ->
+ validate_bin(Rest, Bs+1).
diff --git a/lib/stdlib/src/gen.erl b/lib/stdlib/src/gen.erl
index 33af0aed8f..a7f743bd4c 100644
--- a/lib/stdlib/src/gen.erl
+++ b/lib/stdlib/src/gen.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -49,6 +49,7 @@
| {'logfile', string()}.
-type option() :: {'timeout', timeout()}
| {'debug', [debug_flag()]}
+ | {'hibernate_after', timeout()}
| {'spawn_opt', [proc_lib:spawn_option()]}.
-type options() :: [option()].
@@ -147,57 +148,36 @@ init_it2(GenMod, Starter, Parent, Name, Mod, Args, Options) ->
call(Process, Label, Request) ->
call(Process, Label, Request, ?default_timeout).
+%% Optimize a common case.
+call(Process, Label, Request, Timeout) when is_pid(Process),
+ Timeout =:= infinity orelse is_integer(Timeout) andalso Timeout >= 0 ->
+ do_call(Process, Label, Request, Timeout);
call(Process, Label, Request, Timeout)
when Timeout =:= infinity; is_integer(Timeout), Timeout >= 0 ->
Fun = fun(Pid) -> do_call(Pid, Label, Request, Timeout) end,
do_for_proc(Process, Fun).
-do_call(Process, Label, Request, Timeout) ->
- try erlang:monitor(process, Process) of
- Mref ->
- %% If the monitor/2 call failed to set up a connection to a
- %% remote node, we don't want the '!' operator to attempt
- %% to set up the connection again. (If the monitor/2 call
- %% failed due to an expired timeout, '!' too would probably
- %% have to wait for the timeout to expire.) Therefore,
- %% use erlang:send/3 with the 'noconnect' option so that it
- %% will fail immediately if there is no connection to the
- %% remote node.
-
- catch erlang:send(Process, {Label, {self(), Mref}, Request},
- [noconnect]),
- receive
- {Mref, Reply} ->
- erlang:demonitor(Mref, [flush]),
- {ok, Reply};
- {'DOWN', Mref, _, _, noconnection} ->
- Node = get_node(Process),
- exit({nodedown, Node});
- {'DOWN', Mref, _, _, Reason} ->
- exit(Reason)
- after Timeout ->
- erlang:demonitor(Mref, [flush]),
- exit(timeout)
- end
- catch
- error:_ ->
- %% Node (C/Java?) is not supporting the monitor.
- %% The other possible case -- this node is not distributed
- %% -- should have been handled earlier.
- %% Do the best possible with monitor_node/2.
- %% This code may hang indefinitely if the Process
- %% does not exist. It is only used for featureweak remote nodes.
- Node = get_node(Process),
- monitor_node(Node, true),
- receive
- {nodedown, Node} ->
- monitor_node(Node, false),
- exit({nodedown, Node})
- after 0 ->
- Tag = make_ref(),
- Process ! {Label, {self(), Tag}, Request},
- wait_resp(Node, Tag, Timeout)
- end
+do_call(Process, Label, Request, Timeout) when is_atom(Process) =:= false ->
+ Mref = erlang:monitor(process, Process),
+
+ %% OTP-21:
+ %% Auto-connect is asynchronous. But we still use 'noconnect' to make sure
+ %% we send on the monitored connection, and not trigger a new auto-connect.
+ %%
+ erlang:send(Process, {Label, {self(), Mref}, Request}, [noconnect]),
+
+ receive
+ {Mref, Reply} ->
+ erlang:demonitor(Mref, [flush]),
+ {ok, Reply};
+ {'DOWN', Mref, _, _, noconnection} ->
+ Node = get_node(Process),
+ exit({nodedown, Node});
+ {'DOWN', Mref, _, _, Reason} ->
+ exit(Reason)
+ after Timeout ->
+ erlang:demonitor(Mref, [flush]),
+ exit(timeout)
end.
get_node(Process) ->
@@ -212,19 +192,6 @@ get_node(Process) ->
node(Process)
end.
-wait_resp(Node, Tag, Timeout) ->
- receive
- {Tag, Reply} ->
- monitor_node(Node, false),
- {ok, Reply};
- {nodedown, Node} ->
- monitor_node(Node, false),
- exit({nodedown, Node})
- after Timeout ->
- monitor_node(Node, false),
- exit(timeout)
- end.
-
%%
%% Send a reply to the client.
%%
diff --git a/lib/stdlib/src/gen_event.erl b/lib/stdlib/src/gen_event.erl
index 73e4457bd0..8213282867 100644
--- a/lib/stdlib/src/gen_event.erl
+++ b/lib/stdlib/src/gen_event.erl
@@ -47,16 +47,19 @@
system_replace_state/2,
format_status/2]).
+%% logger callback
+-export([format_log/1]).
+
-export_type([handler/0, handler_args/0, add_handler_ret/0,
del_handler_ret/0]).
--import(error_logger, [error_msg/2]).
-
-record(handler, {module :: atom(),
id = false,
state,
supervised = false :: 'false' | pid()}).
+-include("logger.hrl").
+
%%%=========================================================================
%%% API
%%%=========================================================================
@@ -119,7 +122,7 @@
-type add_handler_ret() :: ok | term() | {'EXIT',term()}.
-type del_handler_ret() :: ok | term() | {'EXIT',term()}.
--type emgr_name() :: {'local', atom()} | {'global', atom()}
+-type emgr_name() :: {'local', atom()} | {'global', term()}
| {'via', atom(), term()}.
-type debug_flag() :: 'trace' | 'log' | 'statistics' | 'debug'
| {'logfile', string()}.
@@ -127,7 +130,7 @@
| {'debug', [debug_flag()]}
| {'spawn_opt', [proc_lib:spawn_option()]}
| {'hibernate_after', timeout()}.
--type emgr_ref() :: atom() | {atom(), atom()} | {'global', atom()}
+-type emgr_ref() :: atom() | {atom(), atom()} | {'global', term()}
| {'via', atom(), term()} | pid().
-type start_ret() :: {'ok', pid()} | {'error', term()}.
@@ -143,7 +146,7 @@
%% start_link()
%% start_link(MgrName | Options)
%% start_link(MgrName, Options)
-%% MgrName ::= {local, atom()} | {global, atom()} | {via, atom(), term()}
+%% MgrName ::= {local, atom()} | {global, term()} | {via, atom(), term()}
%% Options ::= [{timeout, Timeout} | {debug, [Flag]} | {spawn_opt,SOpts}]
%% Flag ::= trace | log | {logfile, File} | statistics | debug
%% (debug == log && statistics)
@@ -583,9 +586,13 @@ server_update(Handler1, Func, Event, SName) ->
remove, SName, normal),
no;
{'EXIT', {undef, [{Mod1, handle_info, [_,_], _}|_]}} ->
- error_logger:warning_msg("** Undefined handle_info in ~tp~n"
- "** Unhandled message: ~tp~n", [Mod1, Event]),
- {ok, Handler1};
+ ?LOG_WARNING(#{label=>{gen_event,no_handle_info},
+ module=>Mod1,
+ message=>Event},
+ #{domain=>[otp],
+ report_cb=>fun gen_event:format_log/1,
+ error_logger=>#{tag=>warning_msg}}), % warningmap??
+ {ok, Handler1};
Other ->
do_terminate(Mod1, Handler1, {error, Other}, State,
Event, SName, crash),
@@ -737,6 +744,23 @@ report_error(_Handler, normal, _, _, _) -> ok;
report_error(_Handler, shutdown, _, _, _) -> ok;
report_error(_Handler, {swapped,_,_}, _, _, _) -> ok;
report_error(Handler, Reason, State, LastIn, SName) ->
+ ?LOG_ERROR(#{label=>{gen_event,terminate},
+ handler=>handler(Handler),
+ name=>SName,
+ last_message=>LastIn,
+ state=>format_status(terminate,Handler#handler.module,
+ get(),State),
+ reason=>Reason},
+ #{domain=>[otp],
+ report_cb=>fun gen_event:format_log/1,
+ error_logger=>#{tag=>error}}).
+
+format_log(#{label:={gen_event,terminate},
+ handler:=Handler,
+ name:=SName,
+ last_message:=LastIn,
+ state:=State,
+ reason:=Reason}) ->
Reason1 =
case Reason of
{'EXIT',{undef,[{M,F,A,L}|MFAs]}} ->
@@ -756,23 +780,18 @@ report_error(Handler, Reason, State, LastIn, SName) ->
_ ->
Reason
end,
- Mod = Handler#handler.module,
- FmtState = case erlang:function_exported(Mod, format_status, 2) of
- true ->
- Args = [get(), State],
- case catch Mod:format_status(terminate, Args) of
- {'EXIT', _} -> State;
- Else -> Else
- end;
- _ ->
- State
- end,
- error_msg("** gen_event handler ~p crashed.~n"
- "** Was installed in ~tp~n"
- "** Last event was: ~tp~n"
- "** When handler state == ~tp~n"
- "** Reason == ~tp~n",
- [handler(Handler),SName,LastIn,FmtState,Reason1]).
+ {"** gen_event handler ~p crashed.~n"
+ "** Was installed in ~tp~n"
+ "** Last event was: ~tp~n"
+ "** When handler state == ~tp~n"
+ "** Reason == ~tp~n",
+ [Handler,SName,LastIn,State,Reason1]};
+format_log(#{label:={gen_event,no_handle_info},
+ module:=Mod,
+ message:=Msg}) ->
+ {"** Undefined handle_info in ~tp~n"
+ "** Unhandled message: ~tp~n",
+ [Mod, Msg]}.
handler(Handler) when not Handler#handler.id ->
Handler#handler.module;
@@ -805,17 +824,21 @@ format_status(Opt, StatusData) ->
[PDict, SysState, Parent, _Debug, [ServerName, MSL, _HibernateAfterTimeout, _Hib]] = StatusData,
Header = gen:format_status_header("Status for event handler",
ServerName),
- FmtMSL = [case erlang:function_exported(Mod, format_status, 2) of
- true ->
- Args = [PDict, State],
- case catch Mod:format_status(Opt, Args) of
- {'EXIT', _} -> MSL;
- Else -> MS#handler{state = Else}
- end;
- _ ->
- MS
- end || #handler{module = Mod, state = State} = MS <- MSL],
+ FmtMSL = [MS#handler{state=format_status(Opt, Mod, PDict, State)}
+ || #handler{module = Mod, state = State} = MS <- MSL],
[{header, Header},
{data, [{"Status", SysState},
{"Parent", Parent}]},
{items, {"Installed handlers", FmtMSL}}].
+
+format_status(Opt, Mod, PDict, State) ->
+ case erlang:function_exported(Mod, format_status, 2) of
+ true ->
+ Args = [PDict, State],
+ case catch Mod:format_status(Opt, Args) of
+ {'EXIT', _} -> State;
+ Else -> Else
+ end;
+ false ->
+ State
+ end.
diff --git a/lib/stdlib/src/gen_fsm.erl b/lib/stdlib/src/gen_fsm.erl
index 8c7db65563..1e18710738 100644
--- a/lib/stdlib/src/gen_fsm.erl
+++ b/lib/stdlib/src/gen_fsm.erl
@@ -105,6 +105,8 @@
%%%
%%% ---------------------------------------------------
+-include("logger.hrl").
+
-export([start/3, start/4,
start_link/3, start_link/4,
stop/1, stop/3,
@@ -124,27 +126,28 @@
system_replace_state/2,
format_status/2]).
--deprecated({start, 3, next_major_release}).
--deprecated({start, 4, next_major_release}).
--deprecated({start_link, 3, next_major_release}).
--deprecated({start_link, 4, next_major_release}).
--deprecated({stop, 1, next_major_release}).
--deprecated({stop, 3, next_major_release}).
--deprecated({send_event, 2, next_major_release}).
--deprecated({sync_send_event, 2, next_major_release}).
--deprecated({sync_send_event, 3, next_major_release}).
--deprecated({send_all_state_event, 2, next_major_release}).
--deprecated({sync_send_all_state_event, 2, next_major_release}).
--deprecated({sync_send_all_state_event, 3, next_major_release}).
--deprecated({reply, 2, next_major_release}).
--deprecated({start_timer, 2, next_major_release}).
--deprecated({send_event_after, 2, next_major_release}).
--deprecated({cancel_timer, 1, next_major_release}).
--deprecated({enter_loop, 4, next_major_release}).
--deprecated({enter_loop, 5, next_major_release}).
--deprecated({enter_loop, 6, next_major_release}).
-
--import(error_logger, [format/2]).
+%% logger callback
+-export([format_log/1]).
+
+-deprecated({start, 3, eventually}).
+-deprecated({start, 4, eventually}).
+-deprecated({start_link, 3, eventually}).
+-deprecated({start_link, 4, eventually}).
+-deprecated({stop, 1, eventually}).
+-deprecated({stop, 3, eventually}).
+-deprecated({send_event, 2, eventually}).
+-deprecated({sync_send_event, 2, eventually}).
+-deprecated({sync_send_event, 3, eventually}).
+-deprecated({send_all_state_event, 2, eventually}).
+-deprecated({sync_send_all_state_event, 2, eventually}).
+-deprecated({sync_send_all_state_event, 3, eventually}).
+-deprecated({reply, 2, eventually}).
+-deprecated({start_timer, 2, eventually}).
+-deprecated({send_event_after, 2, eventually}).
+-deprecated({cancel_timer, 1, eventually}).
+-deprecated({enter_loop, 4, eventually}).
+-deprecated({enter_loop, 5, eventually}).
+-deprecated({enter_loop, 6, eventually}).
%%% ---------------------------------------------------
%%% Interface functions.
@@ -408,12 +411,13 @@ decode_msg(Msg,Parent, Name, StateName, StateData, Mod, Time, HibernateAfterTime
sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug,
[Name, StateName, StateData, Mod, Time, HibernateAfterTimeout], Hib);
{'EXIT', Parent, Reason} ->
- terminate(Reason, Name, Msg, Mod, StateName, StateData, Debug);
+ terminate(
+ Reason, Name, undefined, Msg, Mod, StateName, StateData, Debug);
_Msg when Debug =:= [] ->
handle_msg(Msg, Parent, Name, StateName, StateData, Mod, Time, HibernateAfterTimeout);
_Msg ->
Debug1 = sys:handle_debug(Debug, fun print_event/3,
- {Name, StateName}, {in, Msg}),
+ Name, {in, Msg, StateName}),
handle_msg(Msg, Parent, Name, StateName, StateData,
Mod, Time, HibernateAfterTimeout, Debug1)
end.
@@ -428,7 +432,7 @@ system_continue(Parent, Debug, [Name, StateName, StateData, Mod, Time, Hibernate
system_terminate(Reason, _Parent, Debug,
[Name, StateName, StateData, Mod, _Time, _HibernateAfterTimeout]) ->
- terminate(Reason, Name, [], Mod, StateName, StateData, Debug).
+ terminate(Reason, Name, undefined, [], Mod, StateName, StateData, Debug).
system_code_change([Name, StateName, StateData, Mod, Time, HibernateAfterTimeout],
_Module, OldVsn, Extra) ->
@@ -449,7 +453,7 @@ system_replace_state(StateFun, [Name, StateName, StateData, Mod, Time, Hibernate
%% Format debug messages. Print them as the call-back module sees
%% them, not as the real erlang messages. Use trace for that.
%%-----------------------------------------------------------------
-print_event(Dev, {in, Msg}, {Name, StateName}) ->
+print_event(Dev, {in, Msg, StateName}, Name) ->
case Msg of
{'$gen_event', Event} ->
io:format(Dev, "*DBG* ~tp got event ~tp in state ~tw~n",
@@ -458,6 +462,16 @@ print_event(Dev, {in, Msg}, {Name, StateName}) ->
io:format(Dev,
"*DBG* ~tp got all_state_event ~tp in state ~tw~n",
[Name, Event, StateName]);
+ {'$gen_sync_event', {From,_Tag}, Event} ->
+ io:format(Dev,
+ "*DBG* ~tp got sync_event ~tp "
+ "from ~tw in state ~tw~n",
+ [Name, Event, From, StateName]);
+ {'$gen_sync_all_state_event', {From,_Tag}, Event} ->
+ io:format(Dev,
+ "*DBG* ~tp got sync_all_state_event ~tp "
+ "from ~tw in state ~tw~n",
+ [Name, Event, From, StateName]);
{timeout, Ref, {'$gen_timer', Message}} ->
io:format(Dev,
"*DBG* ~tp got timer ~tp in state ~tw~n",
@@ -470,11 +484,11 @@ print_event(Dev, {in, Msg}, {Name, StateName}) ->
io:format(Dev, "*DBG* ~tp got ~tp in state ~tw~n",
[Name, Msg, StateName])
end;
-print_event(Dev, {out, Msg, To, StateName}, Name) ->
+print_event(Dev, {out, Msg, {To,_Tag}, StateName}, Name) ->
io:format(Dev, "*DBG* ~tp sent ~tp to ~tw~n"
" and switched to state ~tw~n",
[Name, Msg, To, StateName]);
-print_event(Dev, return, {Name, StateName}) ->
+print_event(Dev, {noreply, StateName}, Name) ->
io:format(Dev, "*DBG* ~tp switched to state ~tw~n",
[Name, StateName]).
@@ -492,21 +506,25 @@ handle_msg(Msg, Parent, Name, StateName, StateData, Mod, _Time, HibernateAfterTi
reply(From, Reply),
loop(Parent, Name, NStateName, NStateData, Mod, Time1, HibernateAfterTimeout, []);
{stop, Reason, NStateData} ->
- terminate(Reason, Name, Msg, Mod, StateName, NStateData, []);
+ terminate(Reason, Name, From, Msg, Mod, StateName, NStateData, []);
{stop, Reason, Reply, NStateData} when From =/= undefined ->
- {'EXIT', R} = (catch terminate(Reason, Name, Msg, Mod,
+ {'EXIT', R} = (catch terminate(Reason, Name, From, Msg, Mod,
StateName, NStateData, [])),
reply(From, Reply),
exit(R);
{'EXIT', {undef, [{Mod, handle_info, [_,_,_], _}|_]}} ->
- error_logger:warning_msg("** Undefined handle_info in ~p~n"
- "** Unhandled message: ~tp~n", [Mod, Msg]),
+ ?LOG_WARNING(#{label=>{gen_fsm,no_handle_info},
+ module=>Mod,
+ message=>Msg},
+ #{domain=>[otp],
+ report_cb=>fun gen_fsm:format_log/1,
+ error_logger=>#{tag=>warning_msg}}),
loop(Parent, Name, StateName, StateData, Mod, infinity, HibernateAfterTimeout, []);
{'EXIT', What} ->
- terminate(What, Name, Msg, Mod, StateName, StateData, []);
+ terminate(What, Name, From, Msg, Mod, StateName, StateData, []);
Reply ->
terminate({bad_return_value, Reply},
- Name, Msg, Mod, StateName, StateData, [])
+ Name, From, Msg, Mod, StateName, StateData, [])
end.
handle_msg(Msg, Parent, Name, StateName, StateData, Mod, _Time, HibernateAfterTimeout, Debug) ->
@@ -514,11 +532,11 @@ handle_msg(Msg, Parent, Name, StateName, StateData, Mod, _Time, HibernateAfterTi
case catch dispatch(Msg, Mod, StateName, StateData) of
{next_state, NStateName, NStateData} ->
Debug1 = sys:handle_debug(Debug, fun print_event/3,
- {Name, NStateName}, return),
+ Name, {noreply, NStateName}),
loop(Parent, Name, NStateName, NStateData, Mod, infinity, HibernateAfterTimeout, Debug1);
{next_state, NStateName, NStateData, Time1} ->
Debug1 = sys:handle_debug(Debug, fun print_event/3,
- {Name, NStateName}, return),
+ Name, {noreply, NStateName}),
loop(Parent, Name, NStateName, NStateData, Mod, Time1, HibernateAfterTimeout, Debug1);
{reply, Reply, NStateName, NStateData} when From =/= undefined ->
Debug1 = reply(Name, From, Reply, Debug, NStateName),
@@ -527,17 +545,18 @@ handle_msg(Msg, Parent, Name, StateName, StateData, Mod, _Time, HibernateAfterTi
Debug1 = reply(Name, From, Reply, Debug, NStateName),
loop(Parent, Name, NStateName, NStateData, Mod, Time1, HibernateAfterTimeout, Debug1);
{stop, Reason, NStateData} ->
- terminate(Reason, Name, Msg, Mod, StateName, NStateData, Debug);
+ terminate(
+ Reason, Name, From, Msg, Mod, StateName, NStateData, Debug);
{stop, Reason, Reply, NStateData} when From =/= undefined ->
- {'EXIT', R} = (catch terminate(Reason, Name, Msg, Mod,
+ {'EXIT', R} = (catch terminate(Reason, Name, From, Msg, Mod,
StateName, NStateData, Debug)),
_ = reply(Name, From, Reply, Debug, StateName),
exit(R);
{'EXIT', What} ->
- terminate(What, Name, Msg, Mod, StateName, StateData, Debug);
+ terminate(What, Name, From, Msg, Mod, StateName, StateData, Debug);
Reply ->
terminate({bad_return_value, Reply},
- Name, Msg, Mod, StateName, StateData, Debug)
+ Name, From, Msg, Mod, StateName, StateData, Debug)
end.
dispatch({'$gen_event', Event}, Mod, StateName, StateData) ->
@@ -564,24 +583,25 @@ from(_) -> undefined.
reply({To, Tag}, Reply) ->
catch To ! {Tag, Reply}.
-reply(Name, {To, Tag}, Reply, Debug, StateName) ->
- reply({To, Tag}, Reply),
+reply(Name, From, Reply, Debug, StateName) ->
+ reply(From, Reply),
sys:handle_debug(Debug, fun print_event/3, Name,
- {out, Reply, To, StateName}).
+ {out, Reply, From, StateName}).
%%% ---------------------------------------------------
%%% Terminate the server.
%%% ---------------------------------------------------
--spec terminate(term(), _, _, atom(), _, _, _) -> no_return().
+-spec terminate(term(), _, _, _, atom(), _, _, _) -> no_return().
-terminate(Reason, Name, Msg, Mod, StateName, StateData, Debug) ->
+terminate(Reason, Name, From, Msg, Mod, StateName, StateData, Debug) ->
case erlang:function_exported(Mod, terminate, 3) of
true ->
case catch Mod:terminate(Reason, StateName, StateData) of
{'EXIT', R} ->
FmtStateData = format_status(terminate, Mod, get(), StateData),
- error_info(R, Name, Msg, StateName, FmtStateData, Debug),
+ error_info(
+ R, Name, From, Msg, StateName, FmtStateData, Debug),
exit(R);
_ ->
ok
@@ -598,11 +618,51 @@ terminate(Reason, Name, Msg, Mod, StateName, StateData, Debug) ->
exit(Shutdown);
_ ->
FmtStateData1 = format_status(terminate, Mod, get(), StateData),
- error_info(Reason,Name,Msg,StateName,FmtStateData1,Debug),
+ error_info(
+ Reason, Name, From, Msg, StateName, FmtStateData1, Debug),
exit(Reason)
end.
-error_info(Reason, Name, Msg, StateName, StateData, Debug) ->
+error_info(Reason, Name, From, Msg, StateName, StateData, Debug) ->
+ Log = sys:get_log(Debug),
+ ?LOG_ERROR(#{label=>{gen_fsm,terminate},
+ name=>Name,
+ last_message=>Msg,
+ state_name=>StateName,
+ state_data=>StateData,
+ log=>Log,
+ reason=>Reason,
+ client_info=>client_stacktrace(From)},
+ #{domain=>[otp],
+ report_cb=>fun gen_fsm:format_log/1,
+ error_logger=>#{tag=>error}}),
+ ok.
+
+client_stacktrace(undefined) ->
+ undefined;
+client_stacktrace({Pid,_Tag}) ->
+ client_stacktrace(Pid);
+client_stacktrace(Pid) when is_pid(Pid), node(Pid) =:= node() ->
+ case process_info(Pid, [current_stacktrace, registered_name]) of
+ undefined ->
+ {Pid,dead};
+ [{current_stacktrace, Stacktrace}, {registered_name, []}] ->
+ {Pid,{Pid,Stacktrace}};
+ [{current_stacktrace, Stacktrace}, {registered_name, Name}] ->
+ {Pid,{Name,Stacktrace}}
+ end;
+client_stacktrace(Pid) when is_pid(Pid) ->
+ {Pid,remote}.
+
+
+format_log(#{label:={gen_fsm,terminate},
+ name:=Name,
+ last_message:=Msg,
+ state_name:=StateName,
+ state_data:=StateData,
+ log:=Log,
+ reason:=Reason,
+ client_info:=ClientInfo}) ->
Reason1 =
case Reason of
{undef,[{M,F,A,L}|MFAs]} ->
@@ -620,23 +680,39 @@ error_info(Reason, Name, Msg, StateName, StateData, Debug) ->
_ ->
Reason
end,
- Str = "** State machine ~tp terminating \n" ++
- get_msg_str(Msg) ++
- "** When State == ~tp~n"
- "** Data == ~tp~n"
- "** Reason for termination = ~n** ~tp~n",
- format(Str, [Name, get_msg(Msg), StateName, StateData, Reason1]),
- sys:print_log(Debug),
- ok.
+ {ClientFmt,ClientArgs} = format_client_log(ClientInfo),
+ {"** State machine ~tp terminating \n" ++
+ get_msg_str(Msg) ++
+ "** When State == ~tp~n"
+ "** Data == ~tp~n"
+ "** Reason for termination ==~n** ~tp~n" ++
+ case Log of
+ [] -> [];
+ _ -> "** Log ==~n** ~tp~n"
+ end ++ ClientFmt,
+ [Name|error_logger:limit_term(get_msg(Msg))] ++
+ [StateName,
+ error_logger:limit_term(StateData),
+ error_logger:limit_term(Reason1) |
+ case Log of
+ [] -> [];
+ _ -> [[error_logger:limit_term(D) || D <- Log]]
+ end] ++ ClientArgs};
+format_log(#{label:={gen_fsm,no_handle_info},
+ module:=Mod,
+ message:=Msg}) ->
+ {"** Undefined handle_info in ~p~n"
+ "** Unhandled message: ~tp~n",
+ [Mod, error_logger:limit_term(Msg)]}.
get_msg_str({'$gen_event', _Event}) ->
"** Last event in was ~tp~n";
-get_msg_str({'$gen_sync_event', _Event}) ->
- "** Last sync event in was ~tp~n";
+get_msg_str({'$gen_sync_event', _From, _Event}) ->
+ "** Last sync event in was ~tp from ~tw~n";
get_msg_str({'$gen_all_state_event', _Event}) ->
"** Last event in was ~tp (for all states)~n";
-get_msg_str({'$gen_sync_all_state_event', _Event}) ->
- "** Last sync event in was ~tp (for all states)~n";
+get_msg_str({'$gen_sync_all_state_event', _From, _Event}) ->
+ "** Last sync event in was ~tp (for all states) from ~tw~n";
get_msg_str({timeout, _Ref, {'$gen_timer', _Msg}}) ->
"** Last timer event in was ~tp~n";
get_msg_str({timeout, _Ref, {'$gen_event', _Msg}}) ->
@@ -644,13 +720,24 @@ get_msg_str({timeout, _Ref, {'$gen_event', _Msg}}) ->
get_msg_str(_Msg) ->
"** Last message in was ~tp~n".
-get_msg({'$gen_event', Event}) -> Event;
-get_msg({'$gen_sync_event', Event}) -> Event;
-get_msg({'$gen_all_state_event', Event}) -> Event;
-get_msg({'$gen_sync_all_state_event', Event}) -> Event;
-get_msg({timeout, Ref, {'$gen_timer', Msg}}) -> {timeout, Ref, Msg};
-get_msg({timeout, _Ref, {'$gen_event', Event}}) -> Event;
-get_msg(Msg) -> Msg.
+get_msg({'$gen_event', Event}) -> [Event];
+get_msg({'$gen_sync_event', {From,_Tag}, Event}) -> [Event,From];
+get_msg({'$gen_all_state_event', Event}) -> [Event];
+get_msg({'$gen_sync_all_state_event', {From,_Tag}, Event}) -> [Event,From];
+get_msg({timeout, Ref, {'$gen_timer', Msg}}) -> [{timeout, Ref, Msg}];
+get_msg({timeout, _Ref, {'$gen_event', Event}}) -> [Event];
+get_msg(Msg) -> [Msg].
+
+format_client_log(undefined) ->
+ {"", []};
+format_client_log({From,dead}) ->
+ {"** Client ~p is dead~n", [From]};
+format_client_log({From,remote}) ->
+ {"** Client ~p is remote on node ~p~n", [From, node(From)]};
+format_client_log({_From,{Name,Stacktrace}}) ->
+ {"** Client ~tp stacktrace~n"
+ "** ~tp~n",
+ [Name, error_logger:limit_term(Stacktrace)]}.
%%-----------------------------------------------------------------
%% Status information
@@ -660,18 +747,18 @@ format_status(Opt, StatusData) ->
StatusData,
Header = gen:format_status_header("Status for state machine",
Name),
- Log = sys:get_debug(log, Debug, []),
- Specfic = format_status(Opt, Mod, PDict, StateData),
- Specfic = case format_status(Opt, Mod, PDict, StateData) of
- S when is_list(S) -> S;
- S -> [S]
- end,
+ Log = sys:get_log(Debug),
+ Specific =
+ case format_status(Opt, Mod, PDict, StateData) of
+ S when is_list(S) -> S;
+ S -> [S]
+ end,
[{header, Header},
{data, [{"Status", SysState},
{"Parent", Parent},
{"Logged events", Log},
{"StateName", StateName}]} |
- Specfic].
+ Specific].
format_status(Opt, Mod, PDict, State) ->
DefStatus = case Opt of
diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl
index 7daa7a9fe4..c7b6406f54 100644
--- a/lib/stdlib/src/gen_server.erl
+++ b/lib/stdlib/src/gen_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -104,35 +104,44 @@
system_replace_state/2,
format_status/2]).
+%% logger callback
+-export([format_log/1]).
+
%% Internal exports
-export([init_it/6]).
+-include("logger.hrl").
+
-define(
STACKTRACE(),
- try throw(ok) catch _ -> erlang:get_stacktrace() end).
+ element(2, erlang:process_info(self(), current_stacktrace))).
%%%=========================================================================
%%% API
%%%=========================================================================
-callback init(Args :: term()) ->
- {ok, State :: term()} | {ok, State :: term(), timeout() | hibernate} |
+ {ok, State :: term()} | {ok, State :: term(), timeout() | hibernate | {continue, term()}} |
{stop, Reason :: term()} | ignore.
-callback handle_call(Request :: term(), From :: {pid(), Tag :: term()},
State :: term()) ->
{reply, Reply :: term(), NewState :: term()} |
- {reply, Reply :: term(), NewState :: term(), timeout() | hibernate} |
+ {reply, Reply :: term(), NewState :: term(), timeout() | hibernate | {continue, term()}} |
{noreply, NewState :: term()} |
- {noreply, NewState :: term(), timeout() | hibernate} |
+ {noreply, NewState :: term(), timeout() | hibernate | {continue, term()}} |
{stop, Reason :: term(), Reply :: term(), NewState :: term()} |
{stop, Reason :: term(), NewState :: term()}.
-callback handle_cast(Request :: term(), State :: term()) ->
{noreply, NewState :: term()} |
- {noreply, NewState :: term(), timeout() | hibernate} |
+ {noreply, NewState :: term(), timeout() | hibernate | {continue, term()}} |
{stop, Reason :: term(), NewState :: term()}.
-callback handle_info(Info :: timeout | term(), State :: term()) ->
{noreply, NewState :: term()} |
- {noreply, NewState :: term(), timeout() | hibernate} |
+ {noreply, NewState :: term(), timeout() | hibernate | {continue, term()}} |
+ {stop, Reason :: term(), NewState :: term()}.
+-callback handle_continue(Info :: term(), State :: term()) ->
+ {noreply, NewState :: term()} |
+ {noreply, NewState :: term(), timeout() | hibernate | {continue, term()}} |
{stop, Reason :: term(), NewState :: term()}.
-callback terminate(Reason :: (normal | shutdown | {shutdown, term()} |
term()),
@@ -149,7 +158,7 @@
Status :: term().
-optional_callbacks(
- [handle_info/2, terminate/2, code_change/3, format_status/2]).
+ [handle_info/2, handle_continue/2, terminate/2, code_change/3, format_status/2]).
%%% -----------------------------------------------------------------
%%% Starts a generic server.
@@ -157,7 +166,7 @@
%%% start(Name, Mod, Args, Options)
%%% start_link(Mod, Args, Options)
%%% start_link(Name, Mod, Args, Options) where:
-%%% Name ::= {local, atom()} | {global, atom()} | {via, atom(), term()}
+%%% Name ::= {local, atom()} | {global, term()} | {via, atom(), term()}
%%% Mod ::= atom(), callback module implementing the 'real' server
%%% Args ::= term(), init arguments (to Mod:init/1)
%%% Options ::= [{timeout, Timeout} | {debug, [Flag]}]
@@ -309,7 +318,7 @@ enter_loop(Mod, Options, State, ServerName, Timeout) ->
Name = gen:get_proc_name(ServerName),
Parent = gen:get_parent(),
Debug = gen:debug_options(Name, Options),
- HibernateAfterTimeout = gen:hibernate_after(Options),
+ HibernateAfterTimeout = gen:hibernate_after(Options),
loop(Parent, Name, State, Mod, Timeout, HibernateAfterTimeout, Debug).
%%%========================================================================
@@ -365,7 +374,7 @@ init_it(Mod, Args) ->
{ok, Mod:init(Args)}
catch
throw:R -> {ok, R};
- Class:R -> {'EXIT', Class, R, erlang:get_stacktrace()}
+ Class:R:S -> {'EXIT', Class, R, S}
end.
%%%========================================================================
@@ -374,6 +383,19 @@ init_it(Mod, Args) ->
%%% ---------------------------------------------------
%%% The MAIN loop.
%%% ---------------------------------------------------
+
+loop(Parent, Name, State, Mod, {continue, Continue} = Msg, HibernateAfterTimeout, Debug) ->
+ Reply = try_dispatch(Mod, handle_continue, Continue, State),
+ case Debug of
+ [] ->
+ handle_common_reply(Reply, Parent, Name, undefined, Msg, Mod,
+ HibernateAfterTimeout, State);
+ _ ->
+ Debug1 = sys:handle_debug(Debug, fun print_event/3, Name, Msg),
+ handle_common_reply(Reply, Parent, Name, undefined, Msg, Mod,
+ HibernateAfterTimeout, State, Debug1)
+ end;
+
loop(Parent, Name, State, Mod, hibernate, HibernateAfterTimeout, Debug) ->
proc_lib:hibernate(?MODULE,wake_hib,[Parent, Name, State, Mod, HibernateAfterTimeout, Debug]);
@@ -420,12 +442,11 @@ decode_msg(Msg, Parent, Name, State, Mod, Time, HibernateAfterTimeout, Debug, Hi
%%% Send/receive functions
%%% ---------------------------------------------------
do_send(Dest, Msg) ->
- case catch erlang:send(Dest, Msg, [noconnect]) of
- noconnect ->
- spawn(erlang, send, [Dest,Msg]);
- Other ->
- Other
- end.
+ try erlang:send(Dest, Msg)
+ catch
+ error:_ -> ok
+ end,
+ ok.
do_multi_call(Nodes, Name, Req, infinity) ->
Tag = make_ref(),
@@ -617,18 +638,22 @@ try_dispatch(Mod, Func, Msg, State) ->
catch
throw:R ->
{ok, R};
- error:undef = R when Func == handle_info ->
+ error:undef = R:Stacktrace when Func == handle_info ->
case erlang:function_exported(Mod, handle_info, 2) of
false ->
- error_logger:warning_msg("** Undefined handle_info in ~p~n"
- "** Unhandled message: ~tp~n",
- [Mod, Msg]),
+ ?LOG_WARNING(
+ #{label=>{gen_server,no_handle_info},
+ module=>Mod,
+ message=>Msg},
+ #{domain=>[otp],
+ report_cb=>fun gen_server:format_log/1,
+ error_logger=>#{tag=>warning_msg}}),
{ok, {noreply, State}};
true ->
- {'EXIT', error, R, erlang:get_stacktrace()}
+ {'EXIT', error, R, Stacktrace}
end;
- Class:R ->
- {'EXIT', Class, R, erlang:get_stacktrace()}
+ Class:R:Stacktrace ->
+ {'EXIT', Class, R, Stacktrace}
end.
try_handle_call(Mod, Msg, From, State) ->
@@ -637,8 +662,8 @@ try_handle_call(Mod, Msg, From, State) ->
catch
throw:R ->
{ok, R};
- Class:R ->
- {'EXIT', Class, R, erlang:get_stacktrace()}
+ Class:R:Stacktrace ->
+ {'EXIT', Class, R, Stacktrace}
end.
try_terminate(Mod, Reason, State) ->
@@ -649,8 +674,8 @@ try_terminate(Mod, Reason, State) ->
catch
throw:R ->
{ok, R};
- Class:R ->
- {'EXIT', Class, R, erlang:get_stacktrace()}
+ Class:R:Stacktrace ->
+ {'EXIT', Class, R, Stacktrace}
end;
false ->
{ok, ok}
@@ -748,10 +773,10 @@ handle_common_reply(Reply, Parent, Name, From, Msg, Mod, HibernateAfterTimeout,
terminate({bad_return_value, BadReply}, ?STACKTRACE(), Name, From, Msg, Mod, State, Debug)
end.
-reply(Name, {To, Tag}, Reply, State, Debug) ->
- reply({To, Tag}, Reply),
+reply(Name, From, Reply, State, Debug) ->
+ reply(From, Reply),
sys:handle_debug(Debug, fun print_event/3, Name,
- {out, Reply, To, State} ).
+ {out, Reply, From, State} ).
%%-----------------------------------------------------------------
@@ -785,7 +810,7 @@ system_replace_state(StateFun, [Name, State, Mod, Time, HibernateAfterTimeout])
print_event(Dev, {in, Msg}, Name) ->
case Msg of
{'$gen_call', {From, _Tag}, Call} ->
- io:format(Dev, "*DBG* ~tp got call ~tp from ~w~n",
+ io:format(Dev, "*DBG* ~tp got call ~tp from ~tw~n",
[Name, Call, From]);
{'$gen_cast', Cast} ->
io:format(Dev, "*DBG* ~tp got cast ~tp~n",
@@ -793,8 +818,8 @@ print_event(Dev, {in, Msg}, Name) ->
_ ->
io:format(Dev, "*DBG* ~tp got ~tp~n", [Name, Msg])
end;
-print_event(Dev, {out, Msg, To, State}, Name) ->
- io:format(Dev, "*DBG* ~tp sent ~tp to ~w, new state ~tp~n",
+print_event(Dev, {out, Msg, {To,_Tag}, State}, Name) ->
+ io:format(Dev, "*DBG* ~tp sent ~tp to ~tw, new state ~tp~n",
[Name, Msg, To, State]);
print_event(Dev, {noreply, State}, Name) ->
io:format(Dev, "*DBG* ~tp new state ~tp~n", [Name, State]);
@@ -833,8 +858,7 @@ terminate(Class, Reason, Stacktrace, ReportReason, Name, From, Msg, Mod, State,
Reply = try_terminate(Mod, terminate_reason(Class, Reason, Stacktrace), State),
case Reply of
{'EXIT', C, R, S} ->
- FmtState = format_status(terminate, Mod, get(), State),
- error_info({R, S}, Name, From, Msg, FmtState, Debug),
+ error_info({R, S}, Name, From, Msg, Mod, State, Debug),
erlang:raise(C, R, S);
_ ->
case {Class, Reason} of
@@ -842,8 +866,7 @@ terminate(Class, Reason, Stacktrace, ReportReason, Name, From, Msg, Mod, State,
{exit, shutdown} -> ok;
{exit, {shutdown,_}} -> ok;
_ ->
- FmtState = format_status(terminate, Mod, get(), State),
- error_info(ReportReason, Name, From, Msg, FmtState, Debug)
+ error_info(ReportReason, Name, From, Msg, Mod, State, Debug)
end
end,
case Stacktrace of
@@ -856,12 +879,48 @@ terminate(Class, Reason, Stacktrace, ReportReason, Name, From, Msg, Mod, State,
terminate_reason(error, Reason, Stacktrace) -> {Reason, Stacktrace};
terminate_reason(exit, Reason, _Stacktrace) -> Reason.
-error_info(_Reason, application_controller, _From, _Msg, _State, _Debug) ->
+error_info(_Reason, application_controller, _From, _Msg, _Mod, _State, _Debug) ->
%% OTP-5811 Don't send an error report if it's the system process
%% application_controller which is terminating - let init take care
%% of it instead
ok;
-error_info(Reason, Name, From, Msg, State, Debug) ->
+error_info(Reason, Name, From, Msg, Mod, State, Debug) ->
+ Log = sys:get_log(Debug),
+ ?LOG_ERROR(#{label=>{gen_server,terminate},
+ name=>Name,
+ last_message=>Msg,
+ state=>format_status(terminate, Mod, get(), State),
+ log=>format_log_state(Mod, Log),
+ reason=>Reason,
+ client_info=>client_stacktrace(From)},
+ #{domain=>[otp],
+ report_cb=>fun gen_server:format_log/1,
+ error_logger=>#{tag=>error}}),
+ ok.
+
+client_stacktrace(undefined) ->
+ undefined;
+client_stacktrace({From,_Tag}) ->
+ client_stacktrace(From);
+client_stacktrace(From) when is_pid(From), node(From) =:= node() ->
+ case process_info(From, [current_stacktrace, registered_name]) of
+ undefined ->
+ {From,dead};
+ [{current_stacktrace, Stacktrace}, {registered_name, []}] ->
+ {From,{From,Stacktrace}};
+ [{current_stacktrace, Stacktrace}, {registered_name, Name}] ->
+ {From,{Name,Stacktrace}}
+ end;
+client_stacktrace(From) when is_pid(From) ->
+ {From,remote}.
+
+format_log(#{label:={gen_server,terminate},
+ name:=Name,
+ last_message:=Msg,
+ state:=State,
+ log:=Log,
+ reason:=Reason,
+ client_info:=Client}) ->
Reason1 =
case Reason of
{undef,[{M,F,A,L}|MFAs]} ->
@@ -877,36 +936,41 @@ error_info(Reason, Name, From, Msg, State, Debug) ->
end
end;
_ ->
- error_logger:limit_term(Reason)
+ Reason
end,
- {ClientFmt, ClientArgs} = client_stacktrace(From),
- LimitedState = error_logger:limit_term(State),
- error_logger:format("** Generic server ~tp terminating \n"
- "** Last message in was ~tp~n"
- "** When Server state == ~tp~n"
- "** Reason for termination == ~n** ~tp~n" ++ ClientFmt,
- [Name, Msg, LimitedState, Reason1] ++ ClientArgs),
- sys:print_log(Debug),
- ok.
-client_stacktrace(undefined) ->
+ {ClientFmt,ClientArgs} = format_client_log(Client),
+ [LimitedMsg,LimitedState,LimitedReason|LimitedLog] =
+ [error_logger:limit_term(D) || D <- [Msg,State,Reason1|Log]],
+ {"** Generic server ~tp terminating \n"
+ "** Last message in was ~tp~n"
+ "** When Server state == ~tp~n"
+ "** Reason for termination ==~n** ~tp~n" ++
+ case LimitedLog of
+ [] -> [];
+ _ -> "** Log ==~n** ~tp~n"
+ end ++ ClientFmt,
+ [Name, LimitedMsg, LimitedState, LimitedReason] ++
+ case LimitedLog of
+ [] -> [];
+ _ -> [LimitedLog]
+ end ++ ClientArgs};
+format_log(#{label:={gen_server,no_handle_info},
+ module:=Mod,
+ message:=Msg}) ->
+ {"** Undefined handle_info in ~p~n"
+ "** Unhandled message: ~tp~n",
+ [Mod, error_logger:limit_term(Msg)]}.
+
+format_client_log(undefined) ->
{"", []};
-client_stacktrace({From, _Tag}) ->
- client_stacktrace(From);
-client_stacktrace(From) when is_pid(From), node(From) =:= node() ->
- case process_info(From, [current_stacktrace, registered_name]) of
- undefined ->
- {"** Client ~p is dead~n", [From]};
- [{current_stacktrace, Stacktrace}, {registered_name, []}] ->
- {"** Client ~p stacktrace~n"
- "** ~tp~n",
- [From, Stacktrace]};
- [{current_stacktrace, Stacktrace}, {registered_name, Name}] ->
- {"** Client ~tp stacktrace~n"
- "** ~tp~n",
- [Name, Stacktrace]}
- end;
-client_stacktrace(From) when is_pid(From) ->
- {"** Client ~p is remote on node ~p~n", [From, node(From)]}.
+format_client_log({From,dead}) ->
+ {"** Client ~p is dead~n", [From]};
+format_client_log({From,remote}) ->
+ {"** Client ~p is remote on node ~p~n", [From, node(From)]};
+format_client_log({_From,{Name,Stacktrace}}) ->
+ {"** Client ~tp stacktrace~n"
+ "** ~tp~n",
+ [Name, error_logger:limit_term(Stacktrace)]}.
%%-----------------------------------------------------------------
%% Status information
@@ -914,16 +978,25 @@ client_stacktrace(From) when is_pid(From) ->
format_status(Opt, StatusData) ->
[PDict, SysState, Parent, Debug, [Name, State, Mod, _Time, _HibernateAfterTimeout]] = StatusData,
Header = gen:format_status_header("Status for generic server", Name),
- Log = sys:get_debug(log, Debug, []),
- Specfic = case format_status(Opt, Mod, PDict, State) of
+ Log = sys:get_log(Debug),
+ Specific = case format_status(Opt, Mod, PDict, State) of
S when is_list(S) -> S;
S -> [S]
end,
[{header, Header},
{data, [{"Status", SysState},
{"Parent", Parent},
- {"Logged events", Log}]} |
- Specfic].
+ {"Logged events", format_log_state(Mod, Log)}]} |
+ Specific].
+
+format_log_state(Mod, Log) ->
+ [case Event of
+ {out,Msg,From,State} ->
+ {out,Msg,From,format_status(terminate, Mod, get(), State)};
+ {noreply,State} ->
+ {noreply,format_status(terminate, Mod, get(), State)};
+ _ -> Event
+ end || Event <- Log].
format_status(Opt, Mod, PDict, State) ->
DefStatus = case Opt of
diff --git a/lib/stdlib/src/gen_statem.erl b/lib/stdlib/src/gen_statem.erl
index b1d99e2e14..49911eac2c 100644
--- a/lib/stdlib/src/gen_statem.erl
+++ b/lib/stdlib/src/gen_statem.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2016-2018. All Rights Reserved.
+%% Copyright Ericsson AB 2016-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -19,6 +19,8 @@
%%
-module(gen_statem).
+-include("logger.hrl").
+
%% API
-export(
[start/3,start/4,start_link/3,start_link/4,
@@ -44,6 +46,9 @@
-export(
[wakeup_from_hibernate/3]).
+%% logger callback
+-export([format_log/1]).
+
%% Type exports for templates and callback modules
-export_type(
[event_type/0,
@@ -62,6 +67,14 @@
%% Type that is exported just to be documented
-export_type([transition_option/0]).
+%% Type exports for start_link & friends
+-export_type(
+ [server_name/0,
+ server_ref/0,
+ start_opt/0,
+ start_ret/0,
+ enter_loop_opt/0]).
+
%%%==========================================================================
%%% Interface functions.
%%%==========================================================================
@@ -143,7 +156,7 @@
timeout_action() |
reply_action().
-type timeout_action() ::
- (Timeout :: event_timeout()) | % {timeout,Timeout}
+ (Time :: event_timeout()) | % {timeout,Time,Time}
{'timeout', % Set the event_timeout option
Time :: event_timeout(), EventContent :: term()} |
{'timeout', % Set the event_timeout option
@@ -298,7 +311,7 @@
(Reason :: term()).
%% Format the callback module state in some sensible that is
-%% often condensed way. For StatusOption =:= 'normal' the perferred
+%% often condensed way. For StatusOption =:= 'normal' the preferred
%% return term is [{data,[{"State",FormattedState}]}], and for
%% StatusOption =:= 'terminate' it is just FormattedState.
-callback format_status(
@@ -325,9 +338,11 @@
%% Type validation functions
+%% - return true if the value is of the type, false otherwise
-compile(
{inline,
- [callback_mode/1, state_enter/1, from/1, event_type/1]}).
+ [callback_mode/1, state_enter/1,
+ event_type/1, from/1, timeout_event_type/1]}).
%%
callback_mode(CallbackMode) ->
case CallbackMode of
@@ -344,97 +359,99 @@ state_enter(StateEnter) ->
false
end.
%%
-from({Pid,_}) when is_pid(Pid) -> true;
-from(_) -> false.
-%%
-event_type({call,From}) ->
- from(From);
event_type(Type) ->
case Type of
{call,From} -> from(From);
+ %%
cast -> true;
info -> true;
- timeout -> true;
- state_timeout -> true;
internal -> true;
- {timeout,_} -> true;
- _ -> false
+ _ -> timeout_event_type(Type)
+ end.
+%%
+from({Pid,_}) when is_pid(Pid) -> true;
+from(_) -> false.
+%%
+timeout_event_type(Type) ->
+ case Type of
+ timeout -> true;
+ state_timeout -> true;
+ {timeout,_Name} -> true;
+ _ -> false
end.
+-define(
+ relative_timeout(T),
+ ((is_integer(T) andalso 0 =< (T)) orelse (T) =:= infinity)).
+
+-define(
+ absolute_timeout(T),
+ (is_integer(T) orelse (T) =:= infinity)).
-define(
STACKTRACE(),
- try throw(ok) catch _ -> erlang:get_stacktrace() end).
+ element(2, erlang:process_info(self(), current_stacktrace))).
-define(not_sys_debug, []).
%%
%% This is a macro to only evaluate arguments if Debug =/= [].
-%% Debug is evaluated multiple times.
+%% Debug is evaluated 2 times.
-define(
- sys_debug(Debug, NameState, Entry),
+ sys_debug(Debug, Extra, SystemEvent),
case begin Debug end of
?not_sys_debug ->
begin Debug end;
_ ->
- sys_debug(begin Debug end, begin NameState end, begin Entry end)
+ sys_debug(
+ begin Debug end, begin Extra end, begin SystemEvent end)
end).
--record(state,
+-record(params,
{callback_mode = undefined :: callback_mode() | undefined,
state_enter = false :: boolean(),
+ parent :: pid(),
module :: atom(),
- name :: atom(),
- state :: term(),
- data :: term(),
+ name :: atom() | pid(),
+ hibernate_after = infinity :: timeout()
+ }).
+
+-record(state,
+ {state_data = {undefined,undefined} ::
+ {State :: term(),Data :: term()},
postponed = [] :: [{event_type(),term()}],
- %%
- timer_refs = #{} :: % timer ref => the timer's event type
- #{reference() => timeout_event_type()},
- timer_types = #{} :: % timer's event type => timer ref
- #{timeout_event_type() => reference()},
- cancel_timers = 0 :: non_neg_integer(),
- %% We add a timer to both timer_refs and timer_types
- %% when we start it. When we request an asynchronous
- %% timer cancel we remove it from timer_types. When
- %% the timer cancel message arrives we remove it from
- %% timer_refs.
- %%
- hibernate = false :: boolean(),
- hibernate_after = infinity :: timeout()}).
-
--record(trans_opts,
- {hibernate = false,
- postpone = false,
- timeouts_r = [],
- next_events_r = []}).
+ timers = {#{},#{}} ::
+ {%% TimerRef => TimeoutType
+ TimerRefs :: #{reference() => timeout_event_type()},
+ %% TimeoutType => TimerRef
+ TimeoutTypes :: #{timeout_event_type() => reference()}},
+ hibernate = false :: boolean()
+ }).
%%%==========================================================================
%%% API
-type server_name() ::
- {'global', GlobalName :: term()}
+ {'global', GlobalName :: term()}
| {'via', RegMod :: module(), Name :: term()}
| {'local', atom()}.
-type server_ref() ::
- pid()
+ pid()
| (LocalName :: atom())
| {Name :: atom(), Node :: atom()}
| {'global', GlobalName :: term()}
| {'via', RegMod :: module(), ViaName :: term()}.
--type debug_opt() ::
- {'debug',
- Dbgs ::
- ['trace' | 'log' | 'statistics' | 'debug'
- | {'logfile', string()}]}.
--type hibernate_after_opt() ::
- {'hibernate_after', HibernateAfterTimeout :: timeout()}.
-type start_opt() ::
- debug_opt()
- | {'timeout', Time :: timeout()}
- | hibernate_after_opt()
- | {'spawn_opt', [proc_lib:spawn_option()]}.
--type start_ret() :: {'ok', pid()} | 'ignore' | {'error', term()}.
+ {'timeout', Time :: timeout()}
+ | {'spawn_opt', [proc_lib:spawn_option()]}
+ | enter_loop_opt().
+-type start_ret() ::
+ {'ok', pid()}
+ | 'ignore'
+ | {'error', term()}.
+-type enter_loop_opt() ::
+ {'hibernate_after', HibernateAfterTimeout :: timeout()}
+ | {'debug', Dbgs :: [sys:debug_option()]}.
@@ -517,8 +534,6 @@ call(ServerRef, Request, infinity = T = Timeout) ->
call_dirty(ServerRef, Request, Timeout, T);
call(ServerRef, Request, {dirty_timeout, T} = Timeout) ->
call_dirty(ServerRef, Request, Timeout, T);
-call(ServerRef, Request, {clean_timeout, infinity = T} = Timeout) ->
- call_dirty(ServerRef, Request, Timeout, T);
call(ServerRef, Request, {clean_timeout, T} = Timeout) ->
call_clean(ServerRef, Request, Timeout, T);
call(ServerRef, Request, {_, _} = Timeout) ->
@@ -549,14 +564,14 @@ reply({To,Tag}, Reply) when is_pid(To) ->
%% started by proc_lib into a state machine using
%% the same arguments as you would have returned from init/1
-spec enter_loop(
- Module :: module(), Opts :: [debug_opt() | hibernate_after_opt()],
+ Module :: module(), Opts :: [enter_loop_opt()],
State :: state(), Data :: data()) ->
no_return().
enter_loop(Module, Opts, State, Data) ->
enter_loop(Module, Opts, State, Data, self()).
%%
-spec enter_loop(
- Module :: module(), Opts :: [debug_opt() | hibernate_after_opt()],
+ Module :: module(), Opts :: [enter_loop_opt()],
State :: state(), Data :: data(),
Server_or_Actions ::
server_name() | pid() | [action()]) ->
@@ -570,7 +585,7 @@ enter_loop(Module, Opts, State, Data, Server_or_Actions) ->
end.
%%
-spec enter_loop(
- Module :: module(), Opts :: [debug_opt() | hibernate_after_opt()],
+ Module :: module(), Opts :: [enter_loop_opt()],
State :: state(), Data :: data(),
Server :: server_name() | pid(),
Actions :: [action()] | action()) ->
@@ -578,7 +593,12 @@ enter_loop(Module, Opts, State, Data, Server_or_Actions) ->
enter_loop(Module, Opts, State, Data, Server, Actions) ->
is_atom(Module) orelse error({atom,Module}),
Parent = gen:get_parent(),
- enter(Module, Opts, State, Data, Server, Actions, Parent).
+ Name = gen:get_proc_name(Server),
+ Debug = gen:debug_options(Name, Opts),
+ HibernateAfterTimeout = gen:hibernate_after(Opts),
+ enter(
+ Parent, Debug, Module, Name, HibernateAfterTimeout,
+ State, Data, Actions).
%%---------------------------------------------------------------------------
%% API helpers
@@ -592,11 +612,11 @@ call_dirty(ServerRef, Request, Timeout, T) ->
{ok,Reply} ->
Reply
catch
- Class:Reason ->
+ Class:Reason:Stacktrace ->
erlang:raise(
Class,
{Reason,{?MODULE,call,[ServerRef,Request,Timeout]}},
- erlang:get_stacktrace())
+ Stacktrace)
end.
call_clean(ServerRef, Request, Timeout, T) ->
@@ -610,9 +630,8 @@ call_clean(ServerRef, Request, Timeout, T) ->
ServerRef, '$gen_call', Request, T) of
Result ->
{Ref,Result}
- catch Class:Reason ->
- {Ref,Class,Reason,
- erlang:get_stacktrace()}
+ catch Class:Reason:Stacktrace ->
+ {Ref,Class,Reason,Stacktrace}
end
end),
Mref = monitor(process, Pid),
@@ -644,48 +663,36 @@ replies([]) ->
%% Might actually not send the message in case of caught exception
send(Proc, Msg) ->
- try erlang:send(Proc, Msg, [noconnect]) of
- noconnect ->
- _ = spawn(erlang, send, [Proc,Msg]),
- ok;
- ok ->
- ok
+ try erlang:send(Proc, Msg)
catch
- _:_ ->
- ok
- end.
+ error:_ -> ok
+ end,
+ ok.
%% Here the init_it/6 and enter_loop/5,6,7 functions converge
-enter(Module, Opts, State, Data, Server, Actions, Parent) ->
+enter(
+ Parent, Debug, Module, Name, HibernateAfterTimeout,
+ State, Data, Actions) ->
%% The values should already have been type checked
- Name = gen:get_proc_name(Server),
- Debug = gen:debug_options(Name, Opts),
- HibernateAfterTimeout = gen:hibernate_after(Opts),
- Events = [],
- Event = {internal,init_state},
+ Q = [{internal,init_state}],
%% We enforce {postpone,false} to ensure that
%% our fake Event gets discarded, thought it might get logged
- NewActions = listify(Actions) ++ [{postpone,false}],
- S =
- #state{
+ Actions_1 = listify(Actions) ++ [{postpone,false}],
+ P =
+ #params{
+ parent = Parent,
module = Module,
name = Name,
- state = State,
- data = Data,
hibernate_after = HibernateAfterTimeout},
- CallEnter = true,
- NewDebug = ?sys_debug(Debug, {Name,State}, {enter,Event,State}),
- case call_callback_mode(S) of
- #state{} = NewS ->
- loop_event_actions(
- Parent, NewDebug, NewS,
- Events, Event, State, Data, #trans_opts{},
- NewActions, CallEnter);
- [Class,Reason,Stacktrace] ->
- terminate(
- Class, Reason, Stacktrace, NewDebug,
- S, [Event|Events])
- end.
+ S = #state{state_data = {State,Data}},
+ Debug_1 = ?sys_debug(Debug, Name, {enter,State}),
+ loop_callback_mode(
+ P, Debug_1, S, Q, {State,Data},
+ %% Tunneling Actions through CallbackEvent here...
+ %% Special path to go to action handling, after first
+ %% finding out the callback mode. CallbackEvent is
+ %% a 2-tuple and Actions a list, which achieves this distinction.
+ Actions_1).
%%%==========================================================================
%%% gen callbacks
@@ -693,35 +700,46 @@ enter(Module, Opts, State, Data, Server, Actions, Parent) ->
init_it(Starter, self, ServerRef, Module, Args, Opts) ->
init_it(Starter, self(), ServerRef, Module, Args, Opts);
init_it(Starter, Parent, ServerRef, Module, Args, Opts) ->
+ Name = gen:get_proc_name(ServerRef),
+ Debug = gen:debug_options(Name, Opts),
+ HibernateAfterTimeout = gen:hibernate_after(Opts),
try Module:init(Args) of
Result ->
- init_result(Starter, Parent, ServerRef, Module, Result, Opts)
+ init_result(
+ Starter, Parent, ServerRef, Module, Result,
+ Name, Debug, HibernateAfterTimeout)
catch
Result ->
- init_result(Starter, Parent, ServerRef, Module, Result, Opts);
- Class:Reason ->
- Stacktrace = erlang:get_stacktrace(),
- Name = gen:get_proc_name(ServerRef),
+ init_result(
+ Starter, Parent, ServerRef, Module, Result,
+ Name, Debug, HibernateAfterTimeout);
+ Class:Reason:Stacktrace ->
gen:unregister_name(ServerRef),
proc_lib:init_ack(Starter, {error,Reason}),
error_info(
- Class, Reason, Stacktrace,
- #state{name = Name},
- [], undefined),
+ Class, Reason, Stacktrace, Debug,
+ #params{parent = Parent, name = Name, module = Module},
+ #state{}, []),
erlang:raise(Class, Reason, Stacktrace)
end.
%%---------------------------------------------------------------------------
%% gen callbacks helpers
-init_result(Starter, Parent, ServerRef, Module, Result, Opts) ->
+init_result(
+ Starter, Parent, ServerRef, Module, Result,
+ Name, Debug, HibernateAfterTimeout) ->
case Result of
{ok,State,Data} ->
proc_lib:init_ack(Starter, {ok,self()}),
- enter(Module, Opts, State, Data, ServerRef, [], Parent);
+ enter(
+ Parent, Debug, Module, Name, HibernateAfterTimeout,
+ State, Data, []);
{ok,State,Data,Actions} ->
proc_lib:init_ack(Starter, {ok,self()}),
- enter(Module, Opts, State, Data, ServerRef, Actions, Parent);
+ enter(
+ Parent, Debug, Module, Name, HibernateAfterTimeout,
+ State, Data, Actions);
{stop,Reason} ->
gen:unregister_name(ServerRef),
proc_lib:init_ack(Starter, {error,Reason}),
@@ -731,31 +749,34 @@ init_result(Starter, Parent, ServerRef, Module, Result, Opts) ->
proc_lib:init_ack(Starter, ignore),
exit(normal);
_ ->
- Name = gen:get_proc_name(ServerRef),
gen:unregister_name(ServerRef),
Error = {bad_return_from_init,Result},
proc_lib:init_ack(Starter, {error,Error}),
error_info(
- error, Error, ?STACKTRACE(),
- #state{name = Name},
- [], undefined),
+ error, Error, ?STACKTRACE(), Debug,
+ #params{parent = Parent, name = Name, module = Module},
+ #state{}, []),
exit(Error)
end.
%%%==========================================================================
%%% sys callbacks
+%%%
+%%% We use {P,S} as state (Misc) for the sys module,
+%%% wrap/unwrap it for the server loop* and update
+%%% P#params{parent = Parent}.
-system_continue(Parent, Debug, S) ->
- loop(Parent, Debug, S).
+system_continue(Parent, Debug, {P,S}) ->
+ loop(update_parent(P, Parent), Debug, S).
-system_terminate(Reason, _Parent, Debug, S) ->
- terminate(exit, Reason, ?STACKTRACE(), Debug, S, []).
+system_terminate(Reason, Parent, Debug, {P,S}) ->
+ terminate(
+ exit, Reason, ?STACKTRACE(),
+ update_parent(P, Parent), Debug, S, []).
system_code_change(
- #state{
- module = Module,
- state = State,
- data = Data} = S,
+ {#params{module = Module} = P,
+ #state{state_data = {State,Data}} = S},
_Mod, OldVsn, Extra) ->
case
try Module:code_change(OldVsn, State, Data, Extra)
@@ -765,44 +786,54 @@ system_code_change(
of
{ok,NewState,NewData} ->
{ok,
- S#state{
- callback_mode = undefined,
- state = NewState,
- data = NewData}};
+ {P#params{callback_mode = undefined},
+ S#state{state_data = {NewState,NewData}}}};
{ok,_} = Error ->
error({case_clause,Error});
Error ->
Error
end.
-system_get_state(#state{state = State, data = Data}) ->
- {ok,{State,Data}}.
+system_get_state({_P,#state{state_data = State_Data}}) ->
+ {ok,State_Data}.
system_replace_state(
- StateFun,
- #state{
- state = State,
- data = Data} = S) ->
- {NewState,NewData} = Result = StateFun({State,Data}),
- {ok,Result,S#state{state = NewState, data = NewData}}.
+ StateFun, {P,#state{state_data = State_Data} = S}) ->
+ %%
+ NewState_NewData = StateFun(State_Data),
+ {ok,NewState_NewData,{P,S#state{state_data = NewState_NewData}}}.
format_status(
Opt,
[PDict,SysState,Parent,Debug,
- #state{name = Name, postponed = P} = S]) ->
+ {#params{name = Name} = P,
+ #state{postponed = Postponed} = S}]) ->
Header = gen:format_status_header("Status for state machine", Name),
- Log = sys:get_debug(log, Debug, []),
+ Log = sys:get_log(Debug),
[{header,Header},
{data,
[{"Status",SysState},
{"Parent",Parent},
{"Logged Events",Log},
- {"Postponed",P}]} |
- case format_status(Opt, PDict, S) of
+ {"Postponed",Postponed}]} |
+ case format_status(Opt, PDict, update_parent(P, Parent), S) of
L when is_list(L) -> L;
T -> [T]
end].
+%% Update #params.parent only if it differs. This should not
+%% be possible today (OTP-22.0), but could happen for example
+%% if someone implements changing a server's parent
+%% in a new sys call.
+-compile({inline, update_parent/2}).
+update_parent(P, Parent) ->
+ case P of
+ #params{parent = Parent} ->
+ P;
+ #params{} ->
+ P#params{parent = Parent}
+ end.
+
%%---------------------------------------------------------------------------
%% Format debug messages. Print them as the call-back module sees
%% them, not as the real erlang messages. Use trace for that.
@@ -811,34 +842,46 @@ format_status(
sys_debug(Debug, NameState, Entry) ->
sys:handle_debug(Debug, fun print_event/3, NameState, Entry).
-print_event(Dev, {in,Event}, {Name,State}) ->
- io:format(
- Dev, "*DBG* ~tp receive ~ts in state ~tp~n",
- [Name,event_string(Event),State]);
-print_event(Dev, {out,Reply,{To,_Tag}}, {Name,State}) ->
- io:format(
- Dev, "*DBG* ~tp send ~tp to ~p from state ~tp~n",
- [Name,Reply,To,State]);
-print_event(Dev, {terminate,Reason}, {Name,State}) ->
- io:format(
- Dev, "*DBG* ~tp terminate ~tp in state ~tp~n",
- [Name,Reason,State]);
-print_event(Dev, {Tag,Event,NextState}, {Name,State}) ->
- StateString =
- case NextState of
- State ->
- io_lib:format("~tp", [State]);
- _ ->
- io_lib:format("~tp => ~tp", [State,NextState])
- end,
- io:format(
- Dev, "*DBG* ~tp ~tw ~ts in state ~ts~n",
- [Name,Tag,event_string(Event),StateString]).
+print_event(Dev, SystemEvent, Name) ->
+ case SystemEvent of
+ {in,Event,State} ->
+ io:format(
+ Dev, "*DBG* ~tp receive ~ts in state ~tp~n",
+ [Name,event_string(Event),State]);
+ {code_change,Event,State} ->
+ io:format(
+ Dev, "*DBG* ~tp receive ~ts after code change in state ~tp~n",
+ [Name,event_string(Event),State]);
+ {out,Reply,{To,_Tag}} ->
+ io:format(
+ Dev, "*DBG* ~tp send ~tp to ~tw~n",
+ [Name,Reply,To]);
+ {enter,State} ->
+ io:format(
+ Dev, "*DBG* ~tp enter in state ~tp~n",
+ [Name,State]);
+ {terminate,Reason,State} ->
+ io:format(
+ Dev, "*DBG* ~tp terminate ~tp in state ~tp~n",
+ [Name,Reason,State]);
+ {Tag,Event,State,NextState}
+ when Tag =:= postpone; Tag =:= consume ->
+ StateString =
+ case NextState of
+ State ->
+ io_lib:format("~tp", [State]);
+ _ ->
+ io_lib:format("~tp => ~tp", [State,NextState])
+ end,
+ io:format(
+ Dev, "*DBG* ~tp ~tw ~ts in state ~ts~n",
+ [Name,Tag,event_string(Event),StateString])
+ end.
event_string(Event) ->
case Event of
{{call,{Pid,_Tag}},Request} ->
- io_lib:format("call ~tp from ~w", [Request,Pid]);
+ io_lib:format("call ~tp from ~tw", [Request,Pid]);
{EventType,EventContent} ->
io_lib:format("~tw ~tp", [EventType,EventContent])
end.
@@ -846,918 +889,1169 @@ event_string(Event) ->
%%%==========================================================================
%%% Internal callbacks
-wakeup_from_hibernate(Parent, Debug, S) ->
+wakeup_from_hibernate(P, Debug, S) ->
%% It is a new message that woke us up so we have to receive it now
- loop_receive(Parent, Debug, S).
+ loop_receive(P, Debug, S).
%%%==========================================================================
-%%% State Machine engine implementation of proc_lib/gen server
+%%% State Machine engine implementation on proc_lib/gen
%% Server loop, consists of all loop* functions
%% and detours through sys:handle_system_message/7 and proc_lib:hibernate/3
+%%
+%% The loop tries to keep all temporary values in arguments
+%% and takes shortcuts for ?not_sys_debug, empty lists, etc.
+%% The engine state #state{} is picked apart during the loop,
+%% new values are kept in arguments, and a new #state{} is
+%% composed at the end of the loop. #params{} collect engine
+%% state fields that rarely changes.
+%%
+%% The loop is optimized a bit for staying in the loop, assuming that
+%% system events are rare. So a detour to sys requires re-packing
+%% of the engine state.
%% Entry point for system_continue/3
-loop(Parent, Debug, #state{hibernate = true, cancel_timers = 0} = S) ->
- loop_hibernate(Parent, Debug, S);
-loop(Parent, Debug, S) ->
- loop_receive(Parent, Debug, S).
+%%
+loop(P, Debug, #state{hibernate = true} = S) ->
+ loop_hibernate(P, Debug, S);
+loop(P, Debug, S) ->
+ loop_receive(P, Debug, S).
-loop_hibernate(Parent, Debug, S) ->
+%% Go to hibernation
+%%
+loop_hibernate(P, Debug, S) ->
%%
%% Does not return but restarts process at
%% wakeup_from_hibernate/3 that jumps to loop_receive/3
%%
- proc_lib:hibernate(
- ?MODULE, wakeup_from_hibernate, [Parent,Debug,S]),
+ proc_lib:hibernate(?MODULE, wakeup_from_hibernate, [P, Debug, S]),
error(
{should_not_have_arrived_here_but_instead_in,
- {wakeup_from_hibernate,3}}).
+ {?MODULE,wakeup_from_hibernate,3}}).
+
%% Entry point for wakeup_from_hibernate/3
+%%
+%% Receive a new process message
+%%
loop_receive(
- Parent, Debug, #state{hibernate_after = HibernateAfterTimeout} = S) ->
+ #params{hibernate_after = HibernateAfterTimeout} = P, Debug, S) ->
%%
receive
Msg ->
case Msg of
+ {'$gen_call',From,Request} ->
+ loop_receive_result(P, Debug, S, {{call,From},Request});
+ {'$gen_cast',Cast} ->
+ loop_receive_result(P, Debug, S, {cast,Cast});
+ %%
+ {timeout,TimerRef,TimeoutMsg} ->
+ {TimerRefs,TimeoutTypes} = S#state.timers,
+ case TimerRefs of
+ #{TimerRef := TimeoutType} ->
+ %% Our timer
+ Timers =
+ {maps:remove(TimerRef, TimerRefs),
+ maps:remove(TimeoutType, TimeoutTypes)},
+ S_1 = S#state{timers = Timers},
+ loop_receive_result(
+ P, Debug, S_1, {TimeoutType,TimeoutMsg});
+ #{} ->
+ loop_receive_result(P, Debug, S, {info,Msg})
+ end;
+ %%
{system,Pid,Req} ->
%% Does not return but tail recursively calls
%% system_continue/3 that jumps to loop/3
sys:handle_system_msg(
- Req, Pid, Parent, ?MODULE, Debug, S,
+ Req, Pid, P#params.parent, ?MODULE, Debug,
+ {P,S},
S#state.hibernate);
- {'EXIT',Parent,Reason} = EXIT ->
- %% EXIT is not a 2-tuple therefore
- %% not an event but this will stand out
- %% in the crash report...
- Q = [EXIT],
- terminate(exit, Reason, ?STACKTRACE(), Debug, S, Q);
- {timeout,TimerRef,TimerMsg} ->
- #state{
- timer_refs = TimerRefs,
- timer_types = TimerTypes} = S,
- case TimerRefs of
- #{TimerRef := TimerType} ->
- %% We know of this timer; is it a running
- %% timer or a timer being cancelled that
- %% managed to send a late timeout message?
- case TimerTypes of
- #{TimerType := TimerRef} ->
- %% The timer type maps back to this
- %% timer ref, so it was a running timer
- %% Unregister the triggered timeout
- NewTimerRefs =
- maps:remove(TimerRef, TimerRefs),
- NewTimerTypes =
- maps:remove(TimerType, TimerTypes),
- loop_receive_result(
- Parent, Debug,
- S#state{
- timer_refs = NewTimerRefs,
- timer_types = NewTimerTypes},
- TimerType, TimerMsg);
- _ ->
- %% This was a late timeout message
- %% from timer being cancelled, so
- %% ignore it and expect a cancel_timer
- %% msg shortly
- loop_receive(Parent, Debug, S)
- end;
- _ ->
- %% Not our timer; present it as an event
- loop_receive_result(Parent, Debug, S, info, Msg)
- end;
- {cancel_timer,TimerRef,_} ->
- #state{
- timer_refs = TimerRefs,
- cancel_timers = CancelTimers,
- hibernate = Hibernate} = S,
- case TimerRefs of
- #{TimerRef := _} ->
- %% We must have requested a cancel
- %% of this timer so it is already
- %% removed from TimerTypes
- NewTimerRefs =
- maps:remove(TimerRef, TimerRefs),
- NewCancelTimers = CancelTimers - 1,
- NewS =
- S#state{
- timer_refs = NewTimerRefs,
- cancel_timers = NewCancelTimers},
- if
- Hibernate =:= true, NewCancelTimers =:= 0 ->
- %% No more cancel_timer msgs to expect;
- %% we can hibernate
- loop_hibernate(Parent, Debug, NewS);
- NewCancelTimers >= 0 -> % Assert
- loop_receive(Parent, Debug, NewS)
- end;
- _ ->
- %% Not our cancel_timer msg;
- %% present it as an event
- loop_receive_result(Parent, Debug, S, info, Msg)
- end;
- _ ->
- %% External msg
- case Msg of
- {'$gen_call',From,Request} ->
- loop_receive_result(
- Parent, Debug, S, {call,From}, Request);
- {'$gen_cast',Cast} ->
- loop_receive_result(Parent, Debug, S, cast, Cast);
+ {'EXIT',Pid,Reason} ->
+ case P#params.parent of
+ Pid ->
+ terminate(
+ exit, Reason, ?STACKTRACE(), P, Debug, S, []);
_ ->
- loop_receive_result(Parent, Debug, S, info, Msg)
- end
+ loop_receive_result(P, Debug, S, {info,Msg})
+ end;
+ %%
+ _ ->
+ loop_receive_result(P, Debug, S, {info,Msg})
end
after
- HibernateAfterTimeout ->
- loop_hibernate(Parent, Debug, S)
+ HibernateAfterTimeout ->
+ loop_hibernate(P, Debug, S)
end.
-loop_receive_result(Parent, ?not_sys_debug, S, Type, Content) ->
+%% We have received an event
+%%
+loop_receive_result(P, ?not_sys_debug = Debug, S, Event) ->
%% Here is the queue of not yet handled events created
Events = [],
- loop_event(Parent, ?not_sys_debug, S, Events, Type, Content);
+ loop_event(P, Debug, S, Event, Events);
loop_receive_result(
- Parent, Debug, #state{name = Name, state = State} = S, Type, Content) ->
- NewDebug = sys_debug(Debug, {Name,State}, {in,{Type,Content}}),
+ #params{name = Name, callback_mode = CallbackMode} = P, Debug,
+ #state{state_data = {State,_Data}} = S, Event) ->
+ Debug_1 =
+ case CallbackMode of
+ undefined ->
+ sys_debug(Debug, Name, {code_change,Event,State});
+ _ ->
+ sys_debug(Debug, Name, {in,Event,State})
+ end,
%% Here is the queue of not yet handled events created
Events = [],
- loop_event(Parent, NewDebug, S, Events, Type, Content).
+ loop_event(P, Debug_1, S, Event, Events).
-%% Entry point for handling an event, received or enqueued
+%% Handle one event; received or enqueued
+%%
loop_event(
- Parent, Debug, #state{hibernate = Hibernate} = S,
- Events, Type, Content) ->
+ P, Debug, #state{hibernate = true} = S, Event, Events) ->
%%
- case Hibernate of
- true ->
- %%
- %% If (this old) Hibernate is true here it can only be
- %% because it was set from an event action
- %% and we did not go into hibernation since there were
- %% events in queue, so we do what the user
- %% might rely on i.e collect garbage which
- %% would have happened if we actually hibernated
- %% and immediately was awakened.
- %%
- _ = garbage_collect(),
- loop_event_state_function(
- Parent, Debug, S, Events, Type, Content);
- false ->
- loop_event_state_function(
- Parent, Debug, S, Events, Type, Content)
- end.
+ %% If (this old) Hibernate is true here it can only be
+ %% because it was set from an event action
+ %% and we did not go into hibernation since there were
+ %% events in queue, so we do what the user
+ %% might rely on i.e collect garbage which
+ %% would have happened if we actually hibernated
+ %% and immediately was awakened.
+ %%
+ _ = garbage_collect(),
+ loop_event_handler(P, Debug, S, Event, Events);
+loop_event(P, Debug, S, Event, Events) ->
+ loop_event_handler(P, Debug, S, Event, Events).
-%% Call the state function
-loop_event_state_function(
- Parent, Debug,
- #state{state = State, data = Data} = S,
- Events, Type, Content) ->
+%% Call the state function, eventually
+%%
+-compile({inline, [loop_event_handler/5]}).
+loop_event_handler(
+ P, Debug, #state{state_data = State_Data} = S, Event, Events) ->
%%
%% The field 'hibernate' in S is now invalid and will be
- %% restored when looping back to loop/3 or loop_event/6.
+ %% restored when looping back to loop/3 or loop_event/5.
%%
- Event = {Type,Content},
- TransOpts = false,
- case call_state_function(S, Type, Content, State, Data) of
- {Result, NewS} ->
- loop_event_result(
- Parent, Debug, NewS,
- Events, Event, State, Data, TransOpts, Result);
- [Class,Reason,Stacktrace] ->
- terminate(
- Class, Reason, Stacktrace, Debug, S, [Event|Events])
- end.
+ Q = [Event|Events],
+ loop_callback_mode(P, Debug, S, Q, State_Data, Event).
-%% Make a state enter call to the state function
-loop_event_state_enter(
- Parent, Debug, #state{state = PrevState} = S,
- Events, Event, NextState, NewData, TransOpts) ->
+%% Figure out the callback mode
+%%
+loop_callback_mode(
+ #params{callback_mode = undefined} = P, Debug, S,
+ Q, State_Data, CallbackEvent) ->
%%
- case call_state_function(S, enter, PrevState, NextState, NewData) of
- {Result, NewS} ->
- loop_event_result(
- Parent, Debug, NewS,
- Events, Event, NextState, NewData, TransOpts, Result);
- [Class,Reason,Stacktrace] ->
+ Module = P#params.module,
+ try Module:callback_mode() of
+ CallbackMode ->
+ loop_callback_mode_result(
+ P, Debug, S,
+ Q, State_Data, CallbackEvent,
+ CallbackMode, listify(CallbackMode), undefined, false)
+ catch
+ CallbackMode ->
+ loop_callback_mode_result(
+ P, Debug, S,
+ Q, State_Data, CallbackEvent,
+ CallbackMode, listify(CallbackMode), undefined, false);
+ Class:Reason:Stacktrace ->
terminate(
- Class, Reason, Stacktrace, Debug, S, [Event|Events])
+ Class, Reason, Stacktrace, P, Debug, S, Q)
+ end;
+loop_callback_mode(P, Debug, S, Q, State_Data, CallbackEvent) ->
+ loop_state_callback(P, Debug, S, Q, State_Data, CallbackEvent).
+
+%% Check the result of Module:callback_mode()
+%%
+loop_callback_mode_result(
+ P, Debug, S, Q, State_Data, CallbackEvent,
+ CallbackMode, [H|T], NewCallbackMode, NewStateEnter) ->
+ %%
+ case callback_mode(H) of
+ true ->
+ loop_callback_mode_result(
+ P, Debug, S, Q, State_Data, CallbackEvent,
+ CallbackMode, T, H, NewStateEnter);
+ false ->
+ case state_enter(H) of
+ true ->
+ loop_callback_mode_result(
+ P, Debug, S, Q, State_Data, CallbackEvent,
+ CallbackMode, T, NewCallbackMode, true);
+ false ->
+ terminate(
+ error,
+ {bad_return_from_callback_mode,CallbackMode},
+ ?STACKTRACE(),
+ P, Debug, S, Q)
+ end
+ end;
+loop_callback_mode_result(
+ P, Debug, S, Q, State_Data, CallbackEvent,
+ CallbackMode, [], NewCallbackMode, NewStateEnter) ->
+ %%
+ case NewCallbackMode of
+ undefined ->
+ terminate(
+ error,
+ {bad_return_from_callback_mode,CallbackMode},
+ ?STACKTRACE(),
+ P, Debug, S, Q);
+ _ ->
+ P_1 =
+ P#params{
+ callback_mode = NewCallbackMode,
+ state_enter = NewStateEnter},
+ loop_state_callback(
+ P_1, Debug, S, Q, State_Data, CallbackEvent)
end.
-%% Process the result from the state function.
-%% When TransOpts =:= false it was a state function call,
-%% otherwise it is an option tuple and it was a state enter call.
+
+%% Make a state enter call to the state function, we loop back here
+%% from further down if state enter calls are enabled
+%%
+loop_state_enter(
+ P, Debug, #state{state_data = {PrevState,_PrevData}} = S,
+ Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone) ->
+ %%
+ StateCall = false,
+ CallbackEvent = {enter,PrevState},
+ loop_state_callback(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ StateCall, CallbackEvent).
+
+%% Make a state call (not state enter call) to the state function
+%%
+loop_state_callback(P, Debug, S, Q, State_Data, CallbackEvent) ->
+ NextEventsR = [],
+ Hibernate = false,
+ TimeoutsR = [],
+ Postpone = false,
+ StateCall = true,
+ loop_state_callback(
+ P, Debug, S, Q, State_Data,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ StateCall, CallbackEvent).
+%%
+loop_state_callback(
+ #params{callback_mode = CallbackMode, module = Module} = P,
+ Debug, S, Q, {State,Data} = State_Data,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ StateCall, {Type,Content}) ->
+ try
+ case CallbackMode of
+ state_functions ->
+ Module:State(Type, Content, Data);
+ handle_event_function ->
+ Module:handle_event(Type, Content, State, Data)
+ end
+ of
+ Result ->
+ loop_state_callback_result(
+ P, Debug, S, Q, State_Data,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ StateCall, Result)
+ catch
+ Result ->
+ loop_state_callback_result(
+ P, Debug, S, Q, State_Data,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ StateCall, Result);
+ Class:Reason:Stacktrace ->
+ terminate(Class, Reason, Stacktrace, P, Debug, S, Q)
+ end;
+loop_state_callback(
+ P, Debug, S, Q, State_Data,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ StateCall, Actions) when is_list(Actions) ->
+ %% Tunneled actions from enter/8
+ CallEnter = true,
+ loop_actions_list(
+ P, Debug, S, Q, State_Data,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ CallEnter, StateCall, Actions).
+
+%% Process the result from the state function
%%
-loop_event_result(
- Parent, Debug, S,
- Events, Event, State, Data, TransOpts, Result) ->
+loop_state_callback_result(
+ P, Debug, S, Q, {State,_Data} = State_Data,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ StateCall, Result) ->
%%
case Result of
{next_state,State,NewData} ->
- loop_event_actions(
- Parent, Debug, S,
- Events, Event, State, NewData, TransOpts,
- [], false);
+ loop_actions(
+ P, Debug, S, Q, {State,NewData},
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ false);
{next_state,NextState,NewData}
- when TransOpts =:= false ->
- loop_event_actions(
- Parent, Debug, S,
- Events, Event, NextState, NewData, TransOpts,
- [], true);
+ when StateCall ->
+ loop_actions(
+ P, Debug, S, Q, {NextState,NewData},
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ true);
+ {next_state,_NextState,_NewData} ->
+ terminate(
+ error,
+ {bad_state_enter_return_from_state_function,Result},
+ ?STACKTRACE(), P, Debug,
+ S#state{
+ state_data = State_Data,
+ hibernate = Hibernate},
+ Q);
{next_state,State,NewData,Actions} ->
- loop_event_actions(
- Parent, Debug, S,
- Events, Event, State, NewData, TransOpts,
- Actions, false);
+ loop_actions(
+ P, Debug, S, Q, {State,NewData},
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ false, StateCall, Actions);
{next_state,NextState,NewData,Actions}
- when TransOpts =:= false ->
- loop_event_actions(
- Parent, Debug, S,
- Events, Event, NextState, NewData, TransOpts,
- Actions, true);
+ when StateCall ->
+ loop_actions(
+ P, Debug, S, Q, {NextState,NewData},
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ true, StateCall, Actions);
+ {next_state,_NextState,_NewData,_Actions} ->
+ terminate(
+ error,
+ {bad_state_enter_return_from_state_function,Result},
+ ?STACKTRACE(), P, Debug,
+ S#state{
+ state_data = State_Data,
+ hibernate = Hibernate},
+ Q);
%%
{keep_state,NewData} ->
- loop_event_actions(
- Parent, Debug, S,
- Events, Event, State, NewData, TransOpts,
- [], false);
+ loop_actions(
+ P, Debug, S, Q, {State,NewData},
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ false);
{keep_state,NewData,Actions} ->
- loop_event_actions(
- Parent, Debug, S,
- Events, Event, State, NewData, TransOpts,
- Actions, false);
+ loop_actions(
+ P, Debug, S, Q, {State,NewData},
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ false, StateCall, Actions);
%%
keep_state_and_data ->
- loop_event_actions(
- Parent, Debug, S,
- Events, Event, State, Data, TransOpts,
- [], false);
+ loop_actions(
+ P, Debug, S, Q, State_Data,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ false);
{keep_state_and_data,Actions} ->
- loop_event_actions(
- Parent, Debug, S,
- Events, Event, State, Data, TransOpts,
- Actions, false);
+ loop_actions(
+ P, Debug, S, Q, State_Data,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ false, StateCall, Actions);
%%
{repeat_state,NewData} ->
- loop_event_actions(
- Parent, Debug, S,
- Events, Event, State, NewData, TransOpts,
- [], true);
+ loop_actions(
+ P, Debug, S, Q, {State,NewData},
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ true);
{repeat_state,NewData,Actions} ->
- loop_event_actions(
- Parent, Debug, S,
- Events, Event, State, NewData, TransOpts,
- Actions, true);
+ loop_actions(
+ P, Debug, S, Q, {State,NewData},
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ true, StateCall, Actions);
%%
repeat_state_and_data ->
- loop_event_actions(
- Parent, Debug, S,
- Events, Event, State, Data, TransOpts,
- [], true);
+ loop_actions(
+ P, Debug, S, Q, State_Data,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ true);
{repeat_state_and_data,Actions} ->
- loop_event_actions(
- Parent, Debug, S,
- Events, Event, State, Data, TransOpts,
- Actions, true);
+ loop_actions(
+ P, Debug, S, Q, State_Data,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ true, StateCall, Actions);
%%
stop ->
terminate(
- exit, normal, ?STACKTRACE(), Debug,
+ exit, normal, ?STACKTRACE(), P, Debug,
S#state{
- state = State, data = Data,
- hibernate = hibernate_in_trans_opts(TransOpts)},
- [Event|Events]);
+ state_data = State_Data,
+ hibernate = Hibernate},
+ Q);
{stop,Reason} ->
terminate(
- exit, Reason, ?STACKTRACE(), Debug,
+ exit, Reason, ?STACKTRACE(), P, Debug,
S#state{
- state = State, data = Data,
- hibernate = hibernate_in_trans_opts(TransOpts)},
- [Event|Events]);
+ state_data = State_Data,
+ hibernate = Hibernate},
+ Q);
{stop,Reason,NewData} ->
terminate(
- exit, Reason, ?STACKTRACE(), Debug,
+ exit, Reason, ?STACKTRACE(), P, Debug,
S#state{
- state = State, data = NewData,
- hibernate = hibernate_in_trans_opts(TransOpts)},
- [Event|Events]);
+ state_data = {State,NewData},
+ hibernate = Hibernate},
+ Q);
%%
{stop_and_reply,Reason,Replies} ->
reply_then_terminate(
- exit, Reason, ?STACKTRACE(), Debug,
+ exit, Reason, ?STACKTRACE(), P, Debug,
S#state{
- state = State, data = Data,
- hibernate = hibernate_in_trans_opts(TransOpts)},
- [Event|Events], Replies);
+ state_data = State_Data,
+ hibernate = Hibernate},
+ Q, Replies);
{stop_and_reply,Reason,Replies,NewData} ->
reply_then_terminate(
- exit, Reason, ?STACKTRACE(), Debug,
+ exit, Reason, ?STACKTRACE(), P, Debug,
S#state{
- state = State, data = NewData,
- hibernate = hibernate_in_trans_opts(TransOpts)},
- [Event|Events], Replies);
+ state_data = {State,NewData},
+ hibernate = Hibernate},
+ Q, Replies);
%%
_ ->
terminate(
error,
{bad_return_from_state_function,Result},
- ?STACKTRACE(), Debug,
+ ?STACKTRACE(), P, Debug,
S#state{
- state = State, data = Data,
- hibernate = hibernate_in_trans_opts(TransOpts)},
- [Event|Events])
+ state_data = State_Data,
+ hibernate = Hibernate},
+ Q)
end.
--compile({inline, [hibernate_in_trans_opts/1]}).
-hibernate_in_trans_opts(false) ->
- (#trans_opts{})#trans_opts.hibernate;
-hibernate_in_trans_opts(#trans_opts{hibernate = Hibernate}) ->
- Hibernate.
-
%% Ensure that Actions are a list
-loop_event_actions(
- Parent, Debug, S,
- Events, Event, NextState, NewerData, TransOpts,
- Actions, CallEnter) ->
- loop_event_actions_list(
- Parent, Debug, S,
- Events, Event, NextState, NewerData, TransOpts,
- listify(Actions), CallEnter).
-
-%% Process actions from the state function
-loop_event_actions_list(
- Parent, Debug, #state{state_enter = StateEnter} = S,
- Events, Event, NextState, NewerData, TransOpts,
- Actions, CallEnter) ->
+%%
+loop_actions(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ CallEnter, _StateCall, []) ->
+ loop_actions(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ CallEnter);
+loop_actions(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ CallEnter, StateCall, Actions) ->
%%
- case parse_actions(TransOpts, Debug, S, Actions) of
- {NewDebug,NewTransOpts}
- when StateEnter, CallEnter ->
- loop_event_state_enter(
- Parent, NewDebug, S,
- Events, Event, NextState, NewerData, NewTransOpts);
- {NewDebug,NewTransOpts} ->
- loop_event_done(
- Parent, NewDebug, S,
- Events, Event, NextState, NewerData, NewTransOpts);
- [Class,Reason,Stacktrace,NewDebug] ->
- terminate(
- Class, Reason, Stacktrace, NewDebug,
- S#state{
- state = NextState,
- data = NewerData,
- hibernate = TransOpts#trans_opts.hibernate},
- [Event|Events])
+ loop_actions_list(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ CallEnter, StateCall, listify(Actions)).
+%%
+%% Shortcut for no actions
+-compile({inline, [loop_actions/10]}).
+loop_actions(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ CallEnter) ->
+ %%
+ %% Shortcut for no actions
+ case CallEnter andalso P#params.state_enter of
+ true ->
+ loop_state_enter(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone);
+ false ->
+ loop_state_transition(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone)
end.
-parse_actions(false, Debug, S, Actions) ->
- parse_actions(true, Debug, S, Actions, #trans_opts{});
-parse_actions(TransOpts, Debug, S, Actions) ->
- parse_actions(false, Debug, S, Actions, TransOpts).
+%% Process the returned actions
%%
-parse_actions(_StateCall, Debug, _S, [], TransOpts) ->
- {Debug,TransOpts};
-parse_actions(StateCall, Debug, S, [Action|Actions], TransOpts) ->
+loop_actions_list(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ CallEnter, _StateCall, []) ->
+ %%
+ case P#params.state_enter of
+ true when CallEnter ->
+ loop_state_enter(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone);
+ _ ->
+ loop_state_transition(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone)
+ end;
+loop_actions_list(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ CallEnter, StateCall, [Action|Actions]) ->
+ %%
case Action of
%% Actual actions
{reply,From,Reply} ->
- parse_actions_reply(
- StateCall, Debug, S, Actions, TransOpts, From, Reply);
+ loop_actions_reply(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ CallEnter, StateCall, Actions,
+ From, Reply);
%%
%% Actions that set options
- {hibernate,NewHibernate} when is_boolean(NewHibernate) ->
- parse_actions(
- StateCall, Debug, S, Actions,
- TransOpts#trans_opts{hibernate = NewHibernate});
+ {hibernate,Hibernate_1} when is_boolean(Hibernate_1) ->
+ loop_actions_list(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate_1, TimeoutsR, Postpone,
+ CallEnter, StateCall, Actions);
hibernate ->
- parse_actions(
- StateCall, Debug, S, Actions,
- TransOpts#trans_opts{hibernate = true});
+ loop_actions_list(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, true, TimeoutsR, Postpone,
+ CallEnter, StateCall, Actions);
%%
- {postpone,NewPostpone} when not NewPostpone orelse StateCall ->
- parse_actions(
- StateCall, Debug, S, Actions,
- TransOpts#trans_opts{postpone = NewPostpone});
+ {postpone,Postpone_1} when not Postpone_1 orelse StateCall ->
+ loop_actions_list(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone_1,
+ CallEnter, StateCall, Actions);
postpone when StateCall ->
- parse_actions(
- StateCall, Debug, S, Actions,
- TransOpts#trans_opts{postpone = true});
+ loop_actions_list(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, true,
+ CallEnter, StateCall, Actions);
+ postpone ->
+ terminate(
+ error,
+ {bad_state_enter_action_from_state_function,Action},
+ ?STACKTRACE(), P, Debug,
+ S#state{
+ state_data = NextState_NewData,
+ hibernate = Hibernate},
+ Q);
%%
{next_event,Type,Content} ->
- parse_actions_next_event(
- StateCall, Debug, S, Actions, TransOpts, Type, Content);
+ loop_actions_next_event(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ CallEnter, StateCall, Actions, Type, Content);
%%
- _ ->
- parse_actions_timeout(
- StateCall, Debug, S, Actions, TransOpts, Action)
+ Timeout ->
+ loop_actions_timeout(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ CallEnter, StateCall, Actions, Timeout)
end.
-parse_actions_reply(
- StateCall, ?not_sys_debug, S, Actions, TransOpts,
+%% Process a reply action
+%%
+loop_actions_reply(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ CallEnter, StateCall, Actions,
From, Reply) ->
%%
case from(From) of
true ->
+ %% No need for a separate ?not_sys_debug clause here
+ %% since the external call to erlang:'!'/2 in reply/2
+ %% will cause swap out of all live registers anyway
reply(From, Reply),
- parse_actions(StateCall, ?not_sys_debug, S, Actions, TransOpts);
+ Debug_1 = ?sys_debug(Debug, P#params.name, {out,Reply,From}),
+ loop_actions_list(
+ P, Debug_1, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ CallEnter, StateCall, Actions);
false ->
- [error,
- {bad_action_from_state_function,{reply,From,Reply}},
- ?STACKTRACE(),
- ?not_sys_debug]
- end;
-parse_actions_reply(
- StateCall, Debug, #state{name = Name, state = State} = S,
- Actions, TransOpts, From, Reply) ->
- %%
- case from(From) of
- true ->
- reply(From, Reply),
- NewDebug = sys_debug(Debug, {Name,State}, {out,Reply,From}),
- parse_actions(StateCall, NewDebug, S, Actions, TransOpts);
- false ->
- [error,
- {bad_action_from_state_function,{reply,From,Reply}},
- ?STACKTRACE(),
- Debug]
+ terminate(
+ error,
+ {bad_action_from_state_function,{reply,From,Reply}},
+ ?STACKTRACE(), P, Debug,
+ S#state{
+ state_data = NextState_NewData,
+ hibernate = Hibernate},
+ Q)
end.
-parse_actions_next_event(
- StateCall, ?not_sys_debug, S,
- Actions, TransOpts, Type, Content) ->
- case event_type(Type) of
- true when StateCall ->
- NextEventsR = TransOpts#trans_opts.next_events_r,
- parse_actions(
- StateCall, ?not_sys_debug, S, Actions,
- TransOpts#trans_opts{
- next_events_r = [{Type,Content}|NextEventsR]});
- _ ->
- [error,
- {bad_action_from_state_function,{next_events,Type,Content}},
- ?STACKTRACE(),
- ?not_sys_debug]
- end;
-parse_actions_next_event(
- StateCall, Debug, #state{name = Name, state = State} = S,
- Actions, TransOpts, Type, Content) ->
+%% Process a next_event action
+%%
+loop_actions_next_event(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ CallEnter, StateCall, Actions, Type, Content) ->
case event_type(Type) of
true when StateCall ->
- NewDebug = sys_debug(Debug, {Name,State}, {in,{Type,Content}}),
- NextEventsR = TransOpts#trans_opts.next_events_r,
- parse_actions(
- StateCall, NewDebug, S, Actions,
- TransOpts#trans_opts{
- next_events_r = [{Type,Content}|NextEventsR]});
+ NextEvent = {Type,Content},
+ case Debug of
+ ?not_sys_debug ->
+ loop_actions_list(
+ P, Debug, S, Q, NextState_NewData,
+ [NextEvent|NextEventsR],
+ Hibernate, TimeoutsR, Postpone,
+ CallEnter, StateCall, Actions);
+ _ ->
+ Name = P#params.name,
+ {State,_Data} = S#state.state_data,
+ Debug_1 =
+ sys_debug(Debug, Name, {in,{Type,Content},State}),
+ loop_actions_list(
+ P, Debug_1, S, Q, NextState_NewData,
+ [NextEvent|NextEventsR],
+ Hibernate, TimeoutsR, Postpone,
+ CallEnter, StateCall, Actions)
+ end;
_ ->
- [error,
- {bad_action_from_state_function,{next_events,Type,Content}},
- ?STACKTRACE(),
- Debug]
+ terminate(
+ error,
+ {if
+ StateCall ->
+ bad_action_from_state_function;
+ true ->
+ bad_state_enter_action_from_state_function
+ end,
+ {next_event,Type,Content}},
+ ?STACKTRACE(), P, Debug,
+ S#state{
+ state_data = NextState_NewData,
+ hibernate = Hibernate},
+ Q)
end.
-parse_actions_timeout(
- StateCall, Debug, S, Actions, TransOpts,
- {TimerType,Time,TimerMsg,TimerOpts} = AbsoluteTimeout) ->
+%% Process a timeout action, or also any unrecognized action
+%%
+loop_actions_timeout(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ CallEnter, StateCall, Actions,
+ {TimeoutType,Time,TimeoutMsg,TimeoutOpts} = Timeout) ->
%%
- case classify_timer(Time, listify(TimerOpts)) of
- absolute ->
- parse_actions_timeout_add(
- StateCall, Debug, S, Actions,
- TransOpts, AbsoluteTimeout);
- relative ->
- RelativeTimeout = {TimerType,Time,TimerMsg},
- parse_actions_timeout_add(
- StateCall, Debug, S, Actions,
- TransOpts, RelativeTimeout);
- badarg ->
- [error,
- {bad_action_from_state_function,AbsoluteTimeout},
- ?STACKTRACE(),
- Debug]
+ case timeout_event_type(TimeoutType) of
+ true ->
+ case listify(TimeoutOpts) of
+ %% Optimization cases
+ [] when ?relative_timeout(Time) ->
+ RelativeTimeout = {TimeoutType,Time,TimeoutMsg},
+ loop_actions_list(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate,
+ [RelativeTimeout|TimeoutsR], Postpone,
+ CallEnter, StateCall, Actions);
+ [{abs,true}] when ?absolute_timeout(Time) ->
+ loop_actions_list(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate,
+ [Timeout|TimeoutsR], Postpone,
+ CallEnter, StateCall, Actions);
+ [{abs,false}] when ?relative_timeout(Time) ->
+ RelativeTimeout = {TimeoutType,Time,TimeoutMsg},
+ loop_actions_list(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate,
+ [RelativeTimeout|TimeoutsR], Postpone,
+ CallEnter, StateCall, Actions);
+ %% Generic case
+ TimeoutOptsList ->
+ case parse_timeout_opts_abs(TimeoutOptsList) of
+ true when ?absolute_timeout(Time) ->
+ loop_actions_list(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate,
+ [Timeout|TimeoutsR], Postpone,
+ CallEnter, StateCall, Actions);
+ false when ?relative_timeout(Time) ->
+ RelativeTimeout =
+ {TimeoutType,Time,TimeoutMsg},
+ loop_actions_list(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate,
+ [RelativeTimeout|TimeoutsR], Postpone,
+ CallEnter, StateCall, Actions);
+ badarg ->
+ terminate(
+ error,
+ {bad_action_from_state_function,Timeout},
+ ?STACKTRACE(), P, Debug,
+ S#state{
+ state_data = NextState_NewData,
+ hibernate = Hibernate},
+ Q)
+ end
+ end;
+ false ->
+ terminate(
+ error,
+ {bad_action_from_state_function,Timeout},
+ ?STACKTRACE(), P, Debug,
+ S#state{
+ state_data = NextState_NewData,
+ hibernate = Hibernate},
+ Q)
end;
-parse_actions_timeout(
- StateCall, Debug, S, Actions, TransOpts,
- {_,Time,_} = RelativeTimeout) ->
- case classify_timer(Time, []) of
- relative ->
- parse_actions_timeout_add(
- StateCall, Debug, S, Actions,
- TransOpts, RelativeTimeout);
- badarg ->
- [error,
- {bad_action_from_state_function,RelativeTimeout},
- ?STACKTRACE(),
- Debug]
+loop_actions_timeout(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ CallEnter, StateCall, Actions,
+ {TimeoutType,Time,_} = Timeout) ->
+ %%
+ case timeout_event_type(TimeoutType) of
+ true when ?relative_timeout(Time) ->
+ loop_actions_list(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate,
+ [Timeout|TimeoutsR], Postpone,
+ CallEnter, StateCall, Actions);
+ _ ->
+ terminate(
+ error,
+ {bad_action_from_state_function,Timeout},
+ ?STACKTRACE(), P, Debug,
+ S#state{
+ state_data = NextState_NewData,
+ hibernate = Hibernate},
+ Q)
end;
-parse_actions_timeout(
- StateCall, Debug, S, Actions, TransOpts,
- Timeout) ->
- case classify_timer(Timeout, []) of
- relative ->
- parse_actions_timeout_add(
- StateCall, Debug, S, Actions, TransOpts, Timeout);
- badarg ->
- [error,
- {bad_action_from_state_function,Timeout},
- ?STACKTRACE(),
- Debug]
+loop_actions_timeout(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ CallEnter, StateCall, Actions, Time) ->
+ %%
+ if
+ ?relative_timeout(Time) ->
+ RelativeTimeout = {timeout,Time,Time},
+ loop_actions_list(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate,
+ [RelativeTimeout|TimeoutsR], Postpone,
+ CallEnter, StateCall, Actions);
+ true ->
+ terminate(
+ error,
+ {bad_action_from_state_function,Time},
+ ?STACKTRACE(), P, Debug,
+ S#state{
+ state_data = NextState_NewData,
+ hibernate = Hibernate},
+ Q)
end.
-parse_actions_timeout_add(
- StateCall, Debug, S, Actions,
- #trans_opts{timeouts_r = TimeoutsR} = TransOpts, Timeout) ->
- parse_actions(
- StateCall, Debug, S, Actions,
- TransOpts#trans_opts{timeouts_r = [Timeout|TimeoutsR]}).
-
%% Do the state transition
-loop_event_done(
- Parent, ?not_sys_debug,
- #state{postponed = P} = S,
- Events, Event, NextState, NewData,
- #trans_opts{
- postpone = Postpone, hibernate = Hibernate,
- timeouts_r = [], next_events_r = []}) ->
- %%
- %% Optimize the simple cases
- %% i.e no timer changes, no inserted events and no debug,
- %% by duplicate stripped down code
- %%
- %% Fast path
- %%
- case Postpone of
- true ->
- loop_event_done_fast(
- Parent, Hibernate,
- S,
- Events, [Event|P], NextState, NewData);
- false ->
- loop_event_done_fast(
- Parent, Hibernate,
- S,
- Events, P, NextState, NewData)
- end;
-loop_event_done(
- Parent, Debug_0,
- #state{
- state = State, postponed = P_0,
- timer_refs = TimerRefs_0, timer_types = TimerTypes_0,
- cancel_timers = CancelTimers_0} = S,
- Events_0, Event_0, NextState, NewData,
- #trans_opts{
- hibernate = Hibernate, timeouts_r = TimeoutsR,
- postpone = Postpone, next_events_r = NextEventsR}) ->
+%%
+loop_state_transition(
+ P, Debug, #state{state_data = {State,_Data}, postponed = Postponed} = S,
+ [Event|Events], {NextState,_NewData} = NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone) ->
%%
%% All options have been collected and next_events are buffered.
%% Do the actual state transition.
%%
- %% Full feature path
- %%
- [Debug_1|P_1] = % Move current event to postponed if Postpone
+ Postponed_1 = % Move current event to postponed if Postpone
case Postpone of
true ->
- [?sys_debug(
- Debug_0,
- {S#state.name,State},
- {postpone,Event_0,State}),
- Event_0|P_0];
+ [Event|Postponed];
false ->
- [?sys_debug(
- Debug_0,
- {S#state.name,State},
- {consume,Event_0,State})|P_0]
+ Postponed
end,
- {Events_2,P_2,Timers_2} =
- %% Move all postponed events to queue,
- %% cancel the event timer,
- %% and cancel the state timeout if the state changes
- if
- NextState =:= State ->
- {Events_0,P_1,
- cancel_timer_by_type(
- timeout, {TimerTypes_0,CancelTimers_0})};
- true ->
- {lists:reverse(P_1, Events_0),
- [],
- cancel_timer_by_type(
- state_timeout,
- cancel_timer_by_type(
- timeout, {TimerTypes_0,CancelTimers_0}))}
- %% The state timer is removed from TimerTypes
- %% but remains in TimerRefs until we get
- %% the cancel_timer msg
- end,
- {TimerRefs_3,{TimerTypes_3,CancelTimers_3},TimeoutEvents} =
- %% Stop and start timers
- parse_timers(TimerRefs_0, Timers_2, TimeoutsR),
- %% Place next events last in reversed queue
- Events_3R = lists:reverse(Events_2, NextEventsR),
- %% Enqueue immediate timeout events
- Events_4R = prepend_timeout_events(TimeoutEvents, Events_3R),
- loop_event_done(
- Parent, Debug_1,
- S#state{
- state = NextState,
- data = NewData,
- postponed = P_2,
- timer_refs = TimerRefs_3,
- timer_types = TimerTypes_3,
- cancel_timers = CancelTimers_3,
- hibernate = Hibernate},
- lists:reverse(Events_4R)).
-
-%% Fast path
-%%
-loop_event_done_fast(
- Parent, Hibernate,
- #state{
- state = NextState,
- timer_types = #{timeout := _} = TimerTypes,
- cancel_timers = CancelTimers} = S,
- Events, P, NextState, NewData) ->
+ case Debug of
+ ?not_sys_debug ->
+ %% Optimization for no sys_debug
+ %% - avoid calling sys_debug/3
+ if
+ NextState =:= State ->
+ loop_keep_state(
+ P, Debug, S,
+ Events, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postponed_1);
+ true ->
+ loop_state_change(
+ P, Debug, S,
+ Events, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postponed_1)
+ end;
+ _ ->
+ %% With sys_debug
+ Name = P#params.name,
+ Debug_1 =
+ case Postpone of
+ true ->
+ sys_debug(
+ Debug, Name,
+ {postpone,Event,State,NextState});
+ false ->
+ sys_debug(
+ Debug, Name,
+ {consume,Event,State,NextState})
+ end,
+ if
+ NextState =:= State ->
+ loop_keep_state(
+ P, Debug_1, S,
+ Events, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postponed_1);
+ true ->
+ loop_state_change(
+ P, Debug_1, S,
+ Events, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postponed_1)
+ end
+ end.
+
+%% State transition to the same state
+%%
+loop_keep_state(
+ P, Debug, #state{timers = {TimerRefs,TimeoutTypes} = Timers} = S,
+ Events, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postponed) ->
%%
- %% Same state, event timeout active
+ %% Cancel event timeout
%%
- loop_event_done_fast(
- Parent, Hibernate, S,
- Events, P, NextState, NewData,
- cancel_timer_by_type(
- timeout, {TimerTypes,CancelTimers}));
-loop_event_done_fast(
- Parent, Hibernate,
- #state{state = NextState} = S,
- Events, P, NextState, NewData) ->
+ case TimeoutTypes of
+ %% Optimization
+ %% - only cancel timer when there is a timer to cancel
+ #{timeout := TimerRef} ->
+ %% Event timeout active
+ loop_next_events(
+ P, Debug, S,
+ Events, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postponed,
+ cancel_timer_by_ref_and_type(
+ TimerRef, timeout, TimerRefs, TimeoutTypes));
+ _ ->
+ %% No event timeout active
+ loop_next_events(
+ P, Debug, S,
+ Events, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postponed,
+ Timers)
+ end.
+
+%% State transition to a different state
+%%
+loop_state_change(
+ P, Debug, S, Events, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postponed) ->
%%
- %% Same state
+ %% Retry postponed events
%%
- loop_event_done(
- Parent, ?not_sys_debug,
- S#state{
- data = NewData,
- postponed = P,
- hibernate = Hibernate},
- Events);
-loop_event_done_fast(
- Parent, Hibernate,
- #state{
- timer_types = #{timeout := _} = TimerTypes,
- cancel_timers = CancelTimers} = S,
- Events, P, NextState, NewData) ->
+ case Postponed of
+ [] ->
+ loop_state_change(
+ P, Debug, S,
+ Events, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR);
+ [E1] ->
+ loop_state_change(
+ P, Debug, S,
+ [E1|Events], NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR);
+ [E2,E1] ->
+ loop_state_change(
+ P, Debug, S,
+ [E1,E2|Events], NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR);
+ _ ->
+ loop_state_change(
+ P, Debug, S,
+ lists:reverse(Postponed, Events), NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR)
+ end.
+%%
+loop_state_change(
+ P, Debug, #state{timers = {TimerRefs,TimeoutTypes} = Timers} = S,
+ Events, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR) ->
%%
- %% State change, event timeout active
+ %% Cancel state and event timeout
%%
- loop_event_done_fast(
- Parent, Hibernate, S,
- lists:reverse(P, Events), [], NextState, NewData,
- cancel_timer_by_type(
- state_timeout,
- cancel_timer_by_type(
- timeout, {TimerTypes,CancelTimers})));
-loop_event_done_fast(
- Parent, Hibernate,
- #state{
- timer_types = #{state_timeout := _} = TimerTypes,
- cancel_timers = CancelTimers} = S,
- Events, P, NextState, NewData) ->
+ case TimeoutTypes of
+ %% Optimization
+ %% - only cancel timeout when there is an active timeout
+ %%
+ #{state_timeout := TimerRef} ->
+ %% State timeout active
+ %% - cancel event timeout too since it is faster than inspecting
+ loop_next_events(
+ P, Debug, S, Events, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, [],
+ cancel_timer_by_type(
+ timeout,
+ cancel_timer_by_ref_and_type(
+ TimerRef, state_timeout, TimerRefs, TimeoutTypes)));
+ #{timeout := TimerRef} ->
+ %% Event timeout active but not state timeout
+ %% - cancel event timeout only
+ loop_next_events(
+ P, Debug, S, Events, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, [],
+ cancel_timer_by_ref_and_type(
+ TimerRef, timeout, TimerRefs, TimeoutTypes));
+ _ ->
+ %% No state nor event timeout active.
+ loop_next_events(
+ P, Debug, S, Events, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, [],
+ Timers)
+ end.
+
+%% Continue state transition with processing of
+%% inserted events and timeout events
+%%
+loop_next_events(
+ P, Debug, S,
+ Events, NextState_NewData,
+ NextEventsR, Hibernate, [], Postponed,
+ Timers) ->
%%
- %% State change, state timeout active
+ %% Optimization when there are no timeout actions
+ %% hence no timeout zero events to append to Events
+ %% - avoid loop_timeouts
+ loop_done(
+ P, Debug,
+ S#state{
+ state_data = NextState_NewData,
+ postponed = Postponed,
+ timers = Timers,
+ hibernate = Hibernate},
+ NextEventsR, Events);
+loop_next_events(
+ P, Debug, S,
+ Events, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postponed,
+ Timers) ->
%%
- loop_event_done_fast(
- Parent, Hibernate, S,
- lists:reverse(P, Events), [], NextState, NewData,
- cancel_timer_by_type(
- state_timeout,
- cancel_timer_by_type(
- timeout, {TimerTypes,CancelTimers})));
-loop_event_done_fast(
- Parent, Hibernate,
- #state{} = S,
- Events, P, NextState, NewData) ->
+ Seen = #{},
+ TimeoutEvents = [],
+ loop_timeouts(
+ P, Debug, S,
+ Events, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postponed,
+ Timers, Seen, TimeoutEvents).
+
+%% Continue state transition with processing of timeout events
+%%
+loop_timeouts(
+ P, Debug, S,
+ Events, NextState_NewData,
+ NextEventsR, Hibernate, [], Postponed,
+ Timers, _Seen, TimeoutEvents) ->
%%
- %% State change, no timeout to automatically cancel
+ S_1 =
+ S#state{
+ state_data = NextState_NewData,
+ postponed = Postponed,
+ timers = Timers,
+ hibernate = Hibernate},
+ case TimeoutEvents of
+ [] ->
+ loop_done(P, Debug, S_1, NextEventsR, Events);
+ _ ->
+ case Events of
+ [] ->
+ loop_prepend_timeout_events(
+ P, Debug, S_1, TimeoutEvents,
+ NextEventsR);
+ [E1] ->
+ loop_prepend_timeout_events(
+ P, Debug, S_1, TimeoutEvents,
+ [E1|NextEventsR]);
+ [E2,E1] ->
+ loop_prepend_timeout_events(
+ P, Debug, S_1, TimeoutEvents,
+ [E1,E2|NextEventsR]);
+ _ ->
+ loop_prepend_timeout_events(
+ P, Debug, S_1, TimeoutEvents,
+ lists:reverse(Events, NextEventsR))
+ end
+ end;
+loop_timeouts(
+ P, Debug, S,
+ Events, NextState_NewData,
+ NextEventsR, Hibernate, [Timeout|TimeoutsR], Postponed,
+ Timers, Seen, TimeoutEvents) ->
%%
- loop_event_done(
- Parent, ?not_sys_debug,
- S#state{
- state = NextState,
- data = NewData,
- postponed = [],
- hibernate = Hibernate},
- lists:reverse(P, Events)).
-%%
-%% Fast path
-%%
-loop_event_done_fast(
- Parent, Hibernate, S,
- Events, P, NextState, NewData,
- {TimerTypes,CancelTimers}) ->
+ case Timeout of
+ {TimeoutType,Time,TimeoutMsg} ->
+ %% Relative timeout
+ case Seen of
+ #{TimeoutType := _} ->
+ %% Type seen before - ignore
+ loop_timeouts(
+ P, Debug, S,
+ Events, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postponed,
+ Timers, Seen, TimeoutEvents);
+ #{} ->
+ loop_timeouts(
+ P, Debug, S,
+ Events, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postponed,
+ Timers, Seen, TimeoutEvents,
+ TimeoutType, Time, TimeoutMsg, [])
+ end;
+ {TimeoutType,Time,TimeoutMsg,TimeoutOpts} ->
+ %% Absolute timeout
+ case Seen of
+ #{TimeoutType := _} ->
+ %% Type seen before - ignore
+ loop_timeouts(
+ P, Debug, S,
+ Events, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postponed,
+ Timers, Seen, TimeoutEvents);
+ #{} ->
+ loop_timeouts(
+ P, Debug, S,
+ Events, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postponed,
+ Timers, Seen, TimeoutEvents,
+ TimeoutType, Time, TimeoutMsg, listify(TimeoutOpts))
+ end
+ end.
+%%
+loop_timeouts(
+ P, Debug, S,
+ Events, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postponed,
+ Timers, Seen, TimeoutEvents,
+ TimeoutType, Time, TimeoutMsg, TimeoutOpts) ->
%%
- loop_event_done(
- Parent, ?not_sys_debug,
- S#state{
- state = NextState,
- data = NewData,
- postponed = P,
- timer_types = TimerTypes,
- cancel_timers = CancelTimers,
- hibernate = Hibernate},
- Events).
-
-loop_event_done(Parent, Debug, S, Q) ->
+ case Time of
+ infinity ->
+ %% Cancel any running timer
+ loop_timeouts_cancel(
+ P, Debug, S,
+ Events, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postponed,
+ Timers, Seen, TimeoutEvents,
+ TimeoutType);
+ 0 when TimeoutOpts =:= [] ->
+ %% Relative timeout zero
+ %% - cancel any running timer
+ %% handle timeout zero events later
+ %%
+ loop_timeouts_cancel(
+ P, Debug, S,
+ Events, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postponed,
+ Timers, Seen, [{TimeoutType,TimeoutMsg}|TimeoutEvents],
+ TimeoutType);
+ _ ->
+ %% (Re)start the timer
+ TimerRef =
+ erlang:start_timer(Time, self(), TimeoutMsg, TimeoutOpts),
+ {TimerRefs,TimeoutTypes} = Timers,
+ case TimeoutTypes of
+ #{TimeoutType := OldTimerRef} ->
+ %% Cancel the running timer,
+ %% update the timeout type,
+ %% insert the new timer ref,
+ %% and remove the old timer ref
+ Timers_1 =
+ {maps:remove(
+ OldTimerRef,
+ TimerRefs#{TimerRef => TimeoutType}),
+ TimeoutTypes#{TimeoutType := TimerRef}},
+ cancel_timer(OldTimerRef),
+ loop_timeouts(
+ P, Debug, S,
+ Events, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postponed,
+ Timers_1, Seen#{TimeoutType => true}, TimeoutEvents);
+ #{} ->
+ %% Insert the new timer type and ref
+ Timers_1 =
+ {TimerRefs#{TimerRef => TimeoutType},
+ TimeoutTypes#{TimeoutType => TimerRef}},
+ loop_timeouts(
+ P, Debug, S,
+ Events, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postponed,
+ Timers_1, Seen#{TimeoutType => true}, TimeoutEvents)
+ end
+ end.
+
+%% Loop helper to cancel a timeout
+%%
+loop_timeouts_cancel(
+ P, Debug, S,
+ Events, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postponed,
+ {TimerRefs,TimeoutTypes} = Timers, Seen, TimeoutEvents,
+ TimeoutType) ->
+ %% This function body should have been:
+ %% Timers_1 = cancel_timer_by_type(TimeoutType, Timers),
+ %% loop_timeouts(
+ %% P, Debug, S,
+ %% Events, NextState_NewData,
+ %% NextEventsR, Hibernate, TimeoutsR, Postponed,
+ %% Timers_1, Seen#{TimeoutType => true}, TimeoutEvents).
+ %%
+ %% Explicitly separate cases to get separate code paths for when
+ %% the map key exists vs. not, since otherwise the external call
+ %% to erlang:cancel_timer/1 and to map:remove/2 within
+ %% cancel_timer_by_type/2 would cause all live registers
+ %% to be saved to and restored from the stack also for
+ %% the case when the map key TimeoutType does not exist
+ case TimeoutTypes of
+ #{TimeoutType := TimerRef} ->
+ Timers_1 =
+ cancel_timer_by_ref_and_type(
+ TimerRef, TimeoutType, TimerRefs, TimeoutTypes),
+ loop_timeouts(
+ P, Debug, S,
+ Events, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postponed,
+ Timers_1, Seen#{TimeoutType => true}, TimeoutEvents);
+ #{} ->
+ loop_timeouts(
+ P, Debug, S,
+ Events, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postponed,
+ Timers, Seen#{TimeoutType => true}, TimeoutEvents)
+ end.
+
+%% Continue state transition with prepending timeout zero events
+%% before event queue reversal i.e appending timeout zero events
+%%
+loop_prepend_timeout_events(P, Debug, S, TimeoutEvents, EventsR) ->
+ {Debug_1,Events_1R} =
+ prepend_timeout_events(P, Debug, S, TimeoutEvents, EventsR),
+ loop_done(P, Debug_1, S, Events_1R, []).
+
+%% Place inserted events first in the event queue
+%%
+loop_done(P, Debug, S, NextEventsR, Events) ->
+ case NextEventsR of
+ [] ->
+ loop_done(P, Debug, S, Events);
+ [E1] ->
+ loop_done(P, Debug, S, [E1|Events]);
+ [E2,E1] ->
+ loop_done(P, Debug, S, [E1,E2|Events]);
+ _ ->
+ loop_done(P, Debug, S, lists:reverse(NextEventsR, Events))
+ end.
+%%
+%% State transition is done, keep looping if there are
+%% enqueued events, otherwise get a new event
+%%
+loop_done(P, Debug, S, Q) ->
+%%% io:format(
+%%% "loop_done: state_data = ~p,~n"
+%%% " postponed = ~p, Q = ~p,~n",
+%%% " timers = ~p.~n"
+%%% [S#state.state_data,,S#state.postponed,Q,S#state.timers]),
case Q of
[] ->
%% Get a new event
- loop(Parent, Debug, S);
- [{Type,Content}|Events] ->
+ loop(P, Debug, S);
+ [Event|Events] ->
%% Loop until out of enqueued events
- loop_event(Parent, Debug, S, Events, Type, Content)
+ loop_event(P, Debug, S, Event, Events)
end.
-
%%---------------------------------------------------------------------------
%% Server loop helpers
-call_callback_mode(#state{module = Module} = S) ->
- try Module:callback_mode() of
- CallbackMode ->
- callback_mode_result(S, CallbackMode)
- catch
- CallbackMode ->
- callback_mode_result(S, CallbackMode);
- Class:Reason ->
- [Class,Reason,erlang:get_stacktrace()]
- end.
-
-callback_mode_result(S, CallbackMode) ->
- callback_mode_result(
- S, CallbackMode, listify(CallbackMode), undefined, false).
-%%
-callback_mode_result(_S, CallbackMode, [], undefined, _StateEnter) ->
- [error,
- {bad_return_from_callback_mode,CallbackMode},
- ?STACKTRACE()];
-callback_mode_result(S, _CallbackMode, [], CBMode, StateEnter) ->
- S#state{callback_mode = CBMode, state_enter = StateEnter};
-callback_mode_result(S, CallbackMode, [H|T], CBMode, StateEnter) ->
- case callback_mode(H) of
- true ->
- callback_mode_result(S, CallbackMode, T, H, StateEnter);
- false ->
- case state_enter(H) of
- true ->
- callback_mode_result(S, CallbackMode, T, CBMode, true);
- false ->
- [error,
- {bad_return_from_callback_mode,CallbackMode},
- ?STACKTRACE()]
- end
- end.
-
-
-call_state_function(
- #state{callback_mode = undefined} = S, Type, Content, State, Data) ->
- case call_callback_mode(S) of
- #state{} = NewS ->
- call_state_function(NewS, Type, Content, State, Data);
- Error ->
- Error
- end;
-call_state_function(
- #state{callback_mode = CallbackMode, module = Module} = S,
- Type, Content, State, Data) ->
- try
- case CallbackMode of
- state_functions ->
- Module:State(Type, Content, Data);
- handle_event_function ->
- Module:handle_event(Type, Content, State, Data)
- end
- of
- Result ->
- {Result,S}
- catch
- Result ->
- {Result,S};
- Class:Reason ->
- [Class,Reason,erlang:get_stacktrace()]
- end.
-
-
-%% -> absolute | relative | badarg
-classify_timer(Time, Opts) ->
- classify_timer(Time, Opts, false).
-%%
-classify_timer(Time, [], Abs) ->
- case Abs of
- true when
- is_integer(Time);
- Time =:= infinity ->
- absolute;
- false when
- is_integer(Time), 0 =< Time;
- Time =:= infinity ->
- relative;
- _ ->
- badarg
- end;
-classify_timer(Time, [{abs,Abs}|Opts], _) when is_boolean(Abs) ->
- classify_timer(Time, Opts, Abs);
-classify_timer(_, Opts, _) when is_list(Opts) ->
- badarg.
-
-%% Stop and start timers as well as create timeout zero events
-%% and pending event timer
+%% Parse an option list for erlang:start_timer/4 to figure out
+%% if the timeout will be absolute or relative
%%
-%% Stop and start timers non-event timers
-parse_timers(TimerRefs, Timers, TimeoutsR) ->
- parse_timers(TimerRefs, Timers, TimeoutsR, #{}, []).
+parse_timeout_opts_abs(Opts) ->
+ parse_timeout_opts_abs(Opts, false).
%%
-parse_timers(
- TimerRefs, Timers, [], _Seen, TimeoutEvents) ->
- %%
- {TimerRefs,Timers,TimeoutEvents};
-parse_timers(
- TimerRefs, Timers, [Timeout|TimeoutsR], Seen, TimeoutEvents) ->
- %%
- case Timeout of
- {TimerType,Time,TimerMsg,TimerOpts} ->
- %% Absolute timer
- parse_timers(
- TimerRefs, Timers, TimeoutsR, Seen, TimeoutEvents,
- TimerType, Time, TimerMsg, listify(TimerOpts));
- %% Relative timers below
- {TimerType,0,TimerMsg} ->
- parse_timers(
- TimerRefs, Timers, TimeoutsR, Seen, TimeoutEvents,
- TimerType, zero, TimerMsg, []);
- {TimerType,Time,TimerMsg} ->
- parse_timers(
- TimerRefs, Timers, TimeoutsR, Seen, TimeoutEvents,
- TimerType, Time, TimerMsg, []);
- 0 ->
- parse_timers(
- TimerRefs, Timers, TimeoutsR, Seen, TimeoutEvents,
- timeout, zero, 0, []);
- Time ->
- parse_timers(
- TimerRefs, Timers, TimeoutsR, Seen, TimeoutEvents,
- timeout, Time, Time, [])
- end.
-
-parse_timers(
- TimerRefs, Timers, TimeoutsR, Seen, TimeoutEvents,
- TimerType, Time, TimerMsg, TimerOpts) ->
- case Seen of
- #{TimerType := _} ->
- %% Type seen before - ignore
- parse_timers(
- TimerRefs, Timers, TimeoutsR, Seen, TimeoutEvents);
- #{} ->
- %% Unseen type - handle
- NewSeen = Seen#{TimerType => true},
- case Time of
- infinity ->
- %% Cancel any running timer
- parse_timers(
- TimerRefs, cancel_timer_by_type(TimerType, Timers),
- TimeoutsR, NewSeen, TimeoutEvents);
- zero ->
- %% Cancel any running timer
- %% Handle zero time timeouts later
- parse_timers(
- TimerRefs, cancel_timer_by_type(TimerType, Timers),
- TimeoutsR, NewSeen,
- [{TimerType,TimerMsg}|TimeoutEvents]);
- _ ->
- %% (Re)start the timer
- TimerRef =
- erlang:start_timer(
- Time, self(), TimerMsg, TimerOpts),
- case Timers of
- {#{TimerType := OldTimerRef} = TimerTypes,
- CancelTimers} ->
- %% Cancel the running timer
- cancel_timer(OldTimerRef),
- NewCancelTimers = CancelTimers + 1,
- %% Insert the new timer into
- %% both TimerRefs and TimerTypes
- parse_timers(
- TimerRefs#{TimerRef => TimerType},
- {TimerTypes#{TimerType => TimerRef},
- NewCancelTimers},
- TimeoutsR, NewSeen, TimeoutEvents);
- {#{} = TimerTypes,CancelTimers} ->
- %% Insert the new timer into
- %% both TimerRefs and TimerTypes
- parse_timers(
- TimerRefs#{TimerRef => TimerType},
- {TimerTypes#{TimerType => TimerRef},
- CancelTimers},
- TimeoutsR, NewSeen, TimeoutEvents)
- end
- end
+parse_timeout_opts_abs(Opts, Abs) ->
+ case Opts of
+ [] ->
+ Abs;
+ [{abs,Abs_1}|Opts] when is_boolean(Abs_1) ->
+ parse_timeout_opts_abs(Opts, Abs_1);
+ _ ->
+ badarg
end.
%% Enqueue immediate timeout events (timeout 0 events)
@@ -1767,74 +2061,102 @@ parse_timers(
%% so if there are enqueued events before the event timer
%% timeout 0 event - the event timer is cancelled hence no event.
%%
-%% Other (state_timeout) timeout 0 events that are after
-%% the event timer timeout 0 events are considered to
+%% Other (state_timeout and {timeout,Name}) timeout 0 events
+%% that are after an event timer timeout 0 event are considered to
%% belong to timers that were started after the event timer
%% timeout 0 event fired, so they do not cancel the event timer.
%%
-prepend_timeout_events([], EventsR) ->
- EventsR;
-prepend_timeout_events([{timeout,_} = TimeoutEvent|TimeoutEvents], []) ->
- prepend_timeout_events(TimeoutEvents, [TimeoutEvent]);
-prepend_timeout_events([{timeout,_}|TimeoutEvents], EventsR) ->
+prepend_timeout_events(_P, Debug, _S, [], EventsR) ->
+ {Debug,EventsR};
+prepend_timeout_events(
+ P, Debug, S, [{timeout,_} = TimeoutEvent|TimeoutEvents], []) ->
+ %% Prepend this since there are no other events in queue
+ case Debug of
+ ?not_sys_debug ->
+ prepend_timeout_events(
+ P, Debug, S, TimeoutEvents, [TimeoutEvent]);
+ _ ->
+ {State,_Data} = S#state.state_data,
+ Debug_1 =
+ sys_debug(
+ Debug, P#params.name, {in,TimeoutEvent,State}),
+ prepend_timeout_events(
+ P, Debug_1, S, TimeoutEvents, [TimeoutEvent])
+ end;
+prepend_timeout_events(
+ P, Debug, S, [{timeout,_}|TimeoutEvents], EventsR) ->
%% Ignore since there are other events in queue
%% so they have cancelled the event timeout 0.
- prepend_timeout_events(TimeoutEvents, EventsR);
-prepend_timeout_events([TimeoutEvent|TimeoutEvents], EventsR) ->
+ prepend_timeout_events(P, Debug, S, TimeoutEvents, EventsR);
+prepend_timeout_events(
+ P, Debug, S, [TimeoutEvent|TimeoutEvents], EventsR) ->
%% Just prepend all others
- prepend_timeout_events(TimeoutEvents, [TimeoutEvent|EventsR]).
+ case Debug of
+ ?not_sys_debug ->
+ prepend_timeout_events(
+ P, Debug, S, TimeoutEvents, [TimeoutEvent|EventsR]);
+ _ ->
+ {State,_Data} = S#state.state_data,
+ Debug_1 =
+ sys_debug(
+ Debug, P#params.name, {in,TimeoutEvent,State}),
+ prepend_timeout_events(
+ P, Debug_1, S, TimeoutEvents, [TimeoutEvent|EventsR])
+ end.
%%---------------------------------------------------------------------------
%% Server helpers
-reply_then_terminate(Class, Reason, Stacktrace, Debug, S, Q, Replies) ->
+reply_then_terminate(Class, Reason, Stacktrace, P, Debug, S, Q, Replies) ->
do_reply_then_terminate(
- Class, Reason, Stacktrace, Debug, S, Q, listify(Replies)).
+ Class, Reason, Stacktrace, P, Debug, S, Q, listify(Replies)).
%%
do_reply_then_terminate(
- Class, Reason, Stacktrace, Debug, S, Q, []) ->
- terminate(Class, Reason, Stacktrace, Debug, S, Q);
+ Class, Reason, Stacktrace, P, Debug, S, Q, []) ->
+ terminate(Class, Reason, Stacktrace, P, Debug, S, Q);
do_reply_then_terminate(
- Class, Reason, Stacktrace, Debug, S, Q, [R|Rs]) ->
+ Class, Reason, Stacktrace, P, Debug, S, Q, [R|Rs]) ->
case R of
- {reply,{_To,_Tag}=From,Reply} ->
- reply(From, Reply),
- NewDebug =
- ?sys_debug(
- Debug,
- begin
- #state{name = Name, state = State} = S,
- {Name,State}
- end,
- {out,Reply,From}),
- do_reply_then_terminate(
- Class, Reason, Stacktrace, NewDebug, S, Q, Rs);
+ {reply,From,Reply} ->
+ case from(From) of
+ true ->
+ reply(From, Reply),
+ Debug_1 =
+ ?sys_debug(
+ Debug,
+ P#params.name,
+ {out,Reply,From}),
+ do_reply_then_terminate(
+ Class, Reason, Stacktrace, P, Debug_1, S, Q, Rs);
+ false ->
+ terminate(
+ error,
+ {bad_reply_action_from_state_function,R},
+ ?STACKTRACE(),
+ P, Debug, S, Q)
+ end;
_ ->
terminate(
error,
{bad_reply_action_from_state_function,R},
?STACKTRACE(),
- Debug, S, Q)
+ P, Debug, S, Q)
end.
terminate(
- Class, Reason, Stacktrace, Debug,
- #state{module = Module, state = State, data = Data} = S,
- Q) ->
+ Class, Reason, Stacktrace,
+ #params{module = Module} = P, Debug,
+ #state{state_data = {State,Data}} = S, Q) ->
case erlang:function_exported(Module, terminate, 3) of
true ->
try Module:terminate(Reason, State, Data) of
_ -> ok
catch
_ -> ok;
- C:R ->
- ST = erlang:get_stacktrace(),
- error_info(
- C, R, ST, S, Q,
- format_status(terminate, get(), S)),
- sys:print_log(Debug),
+ C:R:ST ->
+ error_info(C, R, ST, Debug, P, S, Q),
erlang:raise(C, R, ST)
end;
false ->
@@ -1843,16 +2165,13 @@ terminate(
_ =
case Reason of
normal ->
- terminate_sys_debug(Debug, S, State, Reason);
+ terminate_sys_debug(Debug, P, State, Reason);
shutdown ->
- terminate_sys_debug(Debug, S, State, Reason);
+ terminate_sys_debug(Debug, P, State, Reason);
{shutdown,_} ->
- terminate_sys_debug(Debug, S, State, Reason);
+ terminate_sys_debug(Debug, P, State, Reason);
_ ->
- error_info(
- Class, Reason, Stacktrace, S, Q,
- format_status(terminate, get(), S)),
- sys:print_log(Debug)
+ error_info(Class, Reason, Stacktrace, Debug, P, S, Q)
end,
case Stacktrace of
[] ->
@@ -1861,18 +2180,67 @@ terminate(
erlang:raise(Class, Reason, Stacktrace)
end.
-terminate_sys_debug(Debug, S, State, Reason) ->
- ?sys_debug(Debug, {S#state.name,State}, {terminate,Reason}).
+terminate_sys_debug(Debug, P, State, Reason) ->
+ ?sys_debug(Debug, P#params.name, {terminate,Reason,State}).
error_info(
- Class, Reason, Stacktrace,
- #state{
+ Class, Reason, Stacktrace, Debug,
+ #params{
name = Name,
callback_mode = CallbackMode,
- state_enter = StateEnter,
- postponed = P},
- Q, FmtData) ->
+ state_enter = StateEnter} = P,
+ #state{postponed = Postponed} = S,
+ Q) ->
+ Log = sys:get_log(Debug),
+ ?LOG_ERROR(#{label=>{gen_statem,terminate},
+ name=>Name,
+ queue=>Q,
+ postponed=>Postponed,
+ callback_mode=>CallbackMode,
+ state_enter=>StateEnter,
+ state=>format_status(terminate, get(), P, S),
+ log=>Log,
+ reason=>{Class,Reason,Stacktrace},
+ client_info=>client_stacktrace(Q)},
+ #{domain=>[otp],
+ report_cb=>fun gen_statem:format_log/1,
+ error_logger=>#{tag=>error}}).
+
+client_stacktrace([]) ->
+ undefined;
+client_stacktrace([{{call,{Pid,_Tag}},_Req}|_]) when is_pid(Pid) ->
+ if
+ node(Pid) =:= node() ->
+ case
+ process_info(Pid, [current_stacktrace, registered_name])
+ of
+ undefined ->
+ {Pid,dead};
+ [{current_stacktrace, Stacktrace},
+ {registered_name, []}] ->
+ {Pid,{Pid,Stacktrace}};
+ [{current_stacktrace, Stacktrace},
+ {registered_name, Name}] ->
+ {Pid,{Name,Stacktrace}}
+ end;
+ true ->
+ {Pid,remote}
+ end;
+client_stacktrace([_|_]) ->
+ undefined.
+
+
+format_log(#{label:={gen_statem,terminate},
+ name:=Name,
+ queue:=Q,
+ postponed:=Postponed,
+ callback_mode:=CallbackMode,
+ state_enter:=StateEnter,
+ state:=FmtData,
+ log:=Log,
+ reason:={Class,Reason,Stacktrace},
+ client_info:=ClientInfo}) ->
{FixedReason,FixedStacktrace} =
case Stacktrace of
[{M,F,Args,_}|ST]
@@ -1892,14 +2260,12 @@ error_info(
true ->
{Reason,Stacktrace};
false ->
- {{'function not exported',{M,F,Arity}},
- ST}
+ {{'function not exported',{M,F,Arity}},ST}
end
end;
_ -> {Reason,Stacktrace}
end,
- [LimitedP, LimitedFmtData, LimitedFixedReason] =
- [error_logger:limit_term(D) || D <- [P, FmtData, FixedReason]],
+ {ClientFmt,ClientArgs} = format_client_log(ClientInfo),
CBMode =
case StateEnter of
true ->
@@ -1907,53 +2273,72 @@ error_info(
false ->
CallbackMode
end,
- error_logger:format(
- "** State machine ~tp terminating~n" ++
- case Q of
- [] -> "";
- _ -> "** Last event = ~tp~n"
- end ++
- "** When server state = ~tp~n" ++
- "** Reason for termination = ~w:~tp~n" ++
- "** Callback mode = ~p~n" ++
- case Q of
- [_,_|_] -> "** Queued = ~tp~n";
- _ -> ""
- end ++
- case P of
- [] -> "";
- _ -> "** Postponed = ~tp~n"
- end ++
- case FixedStacktrace of
- [] -> "";
- _ -> "** Stacktrace =~n** ~tp~n"
- end,
- [Name |
- case Q of
- [] -> [];
- [Event|_] -> [Event]
- end] ++
- [LimitedFmtData,
- Class,LimitedFixedReason,
- CBMode] ++
- case Q of
- [_|[_|_] = Events] -> [Events];
- _ -> []
- end ++
- case P of
- [] -> [];
- _ -> [LimitedP]
- end ++
- case FixedStacktrace of
- [] -> [];
- _ -> [FixedStacktrace]
- end).
+ {"** State machine ~tp terminating~n" ++
+ case Q of
+ [] -> "";
+ _ -> "** Last event = ~tp~n"
+ end ++
+ "** When server state = ~tp~n" ++
+ "** Reason for termination = ~w:~tp~n" ++
+ "** Callback mode = ~p~n" ++
+ case Q of
+ [_,_|_] -> "** Queued = ~tp~n";
+ _ -> ""
+ end ++
+ case Postponed of
+ [] -> "";
+ _ -> "** Postponed = ~tp~n"
+ end ++
+ case FixedStacktrace of
+ [] -> "";
+ _ -> "** Stacktrace =~n** ~tp~n"
+ end ++
+ case Log of
+ [] -> "";
+ _ -> "** Log =~n** ~tp~n"
+ end ++ ClientFmt,
+ [Name |
+ case Q of
+ [] -> [];
+ [Event|_] -> [error_logger:limit_term(Event)]
+ end] ++
+ [error_logger:limit_term(FmtData),
+ Class,error_logger:limit_term(FixedReason),
+ CBMode] ++
+ case Q of
+ [_|[_|_] = Events] -> [error_logger:limit_term(Events)];
+ _ -> []
+ end ++
+ case Postponed of
+ [] -> [];
+ _ -> [error_logger:limit_term(Postponed)]
+ end ++
+ case FixedStacktrace of
+ [] -> [];
+ _ -> [error_logger:limit_term(FixedStacktrace)]
+ end ++
+ case Log of
+ [] -> [];
+ _ -> [[error_logger:limit_term(T) || T <- Log]]
+ end ++ ClientArgs}.
+
+format_client_log(undefined) ->
+ {"", []};
+format_client_log({Pid,dead}) ->
+ {"** Client ~p is dead~n", [Pid]};
+format_client_log({Pid,remote}) ->
+ {"** Client ~p is remote on node ~p~n", [Pid, node(Pid)]};
+format_client_log({_Pid,{Name,Stacktrace}}) ->
+ {"** Client ~tp stacktrace~n"
+ "** ~tp~n",
+ [Name, error_logger:limit_term(Stacktrace)]}.
%% Call Module:format_status/2 or return a default value
format_status(
Opt, PDict,
- #state{module = Module, state = State, data = Data}) ->
+ #params{module = Module},
+ #state{state_data = {State,Data} = State_Data}) ->
case erlang:function_exported(Module, format_status, 2) of
true ->
try Module:format_status(Opt, [PDict,State,Data])
@@ -1961,21 +2346,21 @@ format_status(
Result -> Result;
_:_ ->
format_status_default(
- Opt, State,
- atom_to_list(Module) ++ ":format_status/2 crashed")
+ Opt,
+ {State,
+ atom_to_list(Module) ++ ":format_status/2 crashed"})
end;
false ->
- format_status_default(Opt, State, Data)
+ format_status_default(Opt, State_Data)
end.
-%% The default Module:format_status/2
-format_status_default(Opt, State, Data) ->
- StateData = {State,Data},
+%% The default Module:format_status/3
+format_status_default(Opt, State_Data) ->
case Opt of
terminate ->
- StateData;
+ State_Data;
_ ->
- [{data,[{"State",StateData}]}]
+ [{data,[{"State",State_Data}]}]
end.
-compile({inline, [listify/1]}).
@@ -1984,24 +2369,41 @@ listify(Item) when is_list(Item) ->
listify(Item) ->
[Item].
+
+-define(cancel_timer(TimerRef),
+ case erlang:cancel_timer(TimerRef) of
+ false ->
+ %% No timer found and we have not seen the timeout message
+ receive
+ {timeout,(TimerRef),_} ->
+ ok
+ end;
+ _ ->
+ %% Timer was running
+ ok
+ end).
+
+-compile({inline, [cancel_timer/1]}).
+cancel_timer(TimerRef) ->
+ ?cancel_timer(TimerRef).
+
%% Cancel timer if running, otherwise no op
%%
-%% This is an asynchronous cancel so the timer is not really cancelled
-%% until we get a cancel_timer msg i.e {cancel_timer,TimerRef,_}.
-%% In the mean time we might get a timeout message.
-%%
-%% Remove the timer from TimerTypes.
-%% When we get the cancel_timer msg we remove it from TimerRefs.
+%% Remove the timer from Timers
-compile({inline, [cancel_timer_by_type/2]}).
-cancel_timer_by_type(TimerType, {TimerTypes,CancelTimers} = TT_CT) ->
- case TimerTypes of
- #{TimerType := TimerRef} ->
- ok = erlang:cancel_timer(TimerRef, [{async,true}]),
- {maps:remove(TimerType, TimerTypes),CancelTimers + 1};
- #{} ->
- TT_CT
+cancel_timer_by_type(TimeoutType, {TimerRefs,TimeoutTypes} = Timers) ->
+ case TimeoutTypes of
+ #{TimeoutType := TimerRef} ->
+ ?cancel_timer(TimerRef),
+ {maps:remove(TimerRef, TimerRefs),
+ maps:remove(TimeoutType, TimeoutTypes)};
+ #{} ->
+ Timers
end.
--compile({inline, [cancel_timer/1]}).
-cancel_timer(TimerRef) ->
- ok = erlang:cancel_timer(TimerRef, [{async,true}]).
+-compile({inline, [cancel_timer_by_ref_and_type/4]}).
+cancel_timer_by_ref_and_type(
+ TimerRef, TimeoutType, TimerRefs, TimeoutTypes) ->
+ ?cancel_timer(TimerRef),
+ {maps:remove(TimerRef, TimerRefs),
+ maps:remove(TimeoutType, TimeoutTypes)}.
diff --git a/lib/stdlib/src/io.erl b/lib/stdlib/src/io.erl
index f510f61e9f..63c9a6bddf 100644
--- a/lib/stdlib/src/io.erl
+++ b/lib/stdlib/src/io.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -86,7 +86,16 @@ put_chars(Chars) ->
CharData :: unicode:chardata().
put_chars(Io, Chars) ->
- o_request(Io, {put_chars,unicode,Chars}, put_chars).
+ put_chars(Io, unicode, Chars).
+
+%% This function is here to make the erlang:raise in o_request actually raise to
+%% a valid function.
+-spec put_chars(IoDevice, Encoding, CharData) -> 'ok' when
+ IoDevice :: device(),
+ Encoding :: unicode,
+ CharData :: unicode:chardata().
+put_chars(Io, Encoding, Chars) ->
+ o_request(Io, {put_chars,Encoding,Chars}, put_chars).
-spec nl() -> 'ok'.
diff --git a/lib/stdlib/src/io_lib.erl b/lib/stdlib/src/io_lib.erl
index 50bf959db5..21d66c5529 100644
--- a/lib/stdlib/src/io_lib.erl
+++ b/lib/stdlib/src/io_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -60,11 +60,12 @@
-module(io_lib).
--export([fwrite/2,fread/2,fread/3,format/2]).
--export([scan_format/2,unscan_format/1,build_text/1]).
+-export([fwrite/2,fwrite/3,fread/2,fread/3,format/2,format/3]).
+-export([scan_format/2,unscan_format/1,build_text/1,build_text/2]).
-export([print/1,print/4,indentation/2]).
-export([write/1,write/2,write/3,nl/0,format_prompt/1,format_prompt/2]).
+-export([write_binary/3]).
-export([write_atom/1,write_string/1,write_string/2,write_latin1_string/1,
write_latin1_string/2, write_char/1, write_latin1_char/1]).
@@ -86,8 +87,10 @@
-export([limit_term/2]).
+-export([chars_length/1]).
+
-export_type([chars/0, latin1_string/0, continuation/0,
- fread_error/0, fread_item/0, format_spec/0]).
+ fread_error/0, fread_item/0, format_spec/0, chars_limit/0]).
%%----------------------------------------------------------------------
@@ -135,6 +138,18 @@
fwrite(Format, Args) ->
format(Format, Args).
+-type chars_limit() :: integer().
+
+-spec fwrite(Format, Data, Options) -> chars() when
+ Format :: io:format(),
+ Data :: [term()],
+ Options :: [Option],
+ Option :: {'chars_limit', CharsLimit},
+ CharsLimit :: chars_limit().
+
+fwrite(Format, Args, Options) ->
+ format(Format, Args, Options).
+
-spec fread(Format, String) -> Result when
Format :: string(),
String :: string(),
@@ -165,11 +180,26 @@ fread(Cont, Chars, Format) ->
Data :: [term()].
format(Format, Args) ->
- case catch io_lib_format:fwrite(Format, Args) of
- {'EXIT',_} ->
- erlang:error(badarg, [Format, Args]);
- Other ->
- Other
+ try io_lib_format:fwrite(Format, Args)
+ catch
+ C:R:S ->
+ test_modules_loaded(C, R, S),
+ erlang:error(badarg, [Format, Args])
+ end.
+
+-spec format(Format, Data, Options) -> chars() when
+ Format :: io:format(),
+ Data :: [term()],
+ Options :: [Option],
+ Option :: {'chars_limit', CharsLimit},
+ CharsLimit :: chars_limit().
+
+format(Format, Args, Options) ->
+ try io_lib_format:fwrite(Format, Args, Options)
+ catch
+ C:R:S ->
+ test_modules_loaded(C, R, S),
+ erlang:error(badarg, [Format, Args])
end.
-spec scan_format(Format, Data) -> FormatList when
@@ -180,7 +210,9 @@ format(Format, Args) ->
scan_format(Format, Args) ->
try io_lib_format:scan(Format, Args)
catch
- _:_ -> erlang:error(badarg, [Format, Args])
+ C:R:S ->
+ test_modules_loaded(C, R, S),
+ erlang:error(badarg, [Format, Args])
end.
-spec unscan_format(FormatList) -> {Format, Data} when
@@ -195,7 +227,37 @@ unscan_format(FormatList) ->
FormatList :: [char() | format_spec()].
build_text(FormatList) ->
- io_lib_format:build(FormatList).
+ try io_lib_format:build(FormatList)
+ catch
+ C:R:S ->
+ test_modules_loaded(C, R, S),
+ erlang:error(badarg, [FormatList])
+ end.
+
+-spec build_text(FormatList, Options) -> chars() when
+ FormatList :: [char() | format_spec()],
+ Options :: [Option],
+ Option :: {'chars_limit', CharsLimit},
+ CharsLimit :: chars_limit().
+
+build_text(FormatList, Options) ->
+ try io_lib_format:build(FormatList, Options)
+ catch
+ C:R:S ->
+ test_modules_loaded(C, R, S),
+ erlang:error(badarg, [FormatList, Options])
+ end.
+
+%% Failure to load a module must not be labeled as badarg.
+%% C, R, and S are included so that the original error, which could be
+%% a bug in io_lib_format, can be found by tracing on
+%% test_modules_loaded/3.
+test_modules_loaded(_C, _R, _S) ->
+ Modules = [io_lib_format, io_lib_pretty, string, unicode],
+ case code:ensure_modules_loaded(Modules) of
+ ok -> ok;
+ Error -> erlang:error(Error)
+ end.
-spec print(Term) -> chars() when
Term :: term().
@@ -240,7 +302,7 @@ format_prompt(Prompt, Encoding) ->
do_format_prompt(add_modifier(Encoding, "p"), [Prompt]).
do_format_prompt(Format, Args) ->
- case catch io_lib:format(Format, Args) of
+ case catch format(Format, Args) of
{'EXIT',_} -> "???";
List -> List
end.
@@ -259,7 +321,8 @@ add_modifier(_, C) ->
-spec write(Term) -> chars() when
Term :: term().
-write(Term) -> write(Term, -1).
+write(Term) ->
+ write1(Term, -1, latin1).
-spec write(term(), depth(), boolean()) -> chars().
@@ -274,16 +337,29 @@ write(Term, D, false) ->
(Term, Options) -> chars() when
Term :: term(),
Options :: [Option],
- Option :: {'depth', Depth}
+ Option :: {'chars_limit', CharsLimit}
+ | {'depth', Depth}
| {'encoding', 'latin1' | 'utf8' | 'unicode'},
+ CharsLimit :: chars_limit(),
Depth :: depth().
write(Term, Options) when is_list(Options) ->
Depth = get_option(depth, Options, -1),
Encoding = get_option(encoding, Options, epp:default_encoding()),
- write1(Term, Depth, Encoding);
+ CharsLimit = get_option(chars_limit, Options, -1),
+ if
+ Depth =:= 0; CharsLimit =:= 0 ->
+ "...";
+ CharsLimit < 0 ->
+ write1(Term, Depth, Encoding);
+ CharsLimit > 0 ->
+ RecDefFun = fun(_, _) -> no end,
+ If = io_lib_pretty:intermediate
+ (Term, Depth, CharsLimit, RecDefFun, Encoding, _Str=false),
+ io_lib_pretty:write(If)
+ end;
write(Term, Depth) ->
- write1(Term, Depth, latin1).
+ write(Term, [{depth, Depth}, {encoding, latin1}]).
write1(_Term, 0, _E) -> "...";
write1(Term, _D, _E) when is_integer(Term) -> integer_to_list(Term);
@@ -300,7 +376,7 @@ write1([H|T], D, E) ->
if
D =:= 1 -> "[...]";
true ->
- [$[,[write1(H, D-1, E)|write_tail(T, D-1, E, $|)],$]]
+ [$[,[write1(H, D-1, E)|write_tail(T, D-1, E)],$]]
end;
write1(F, _D, _E) when is_function(F) ->
erlang:fun_to_list(F);
@@ -311,20 +387,24 @@ write1(T, D, E) when is_tuple(T) ->
D =:= 1 -> "{...}";
true ->
[${,
- [write1(element(1, T), D-1, E)|
- write_tail(tl(tuple_to_list(T)), D-1, E, $,)],
+ [write1(element(1, T), D-1, E)|write_tuple(T, 2, D-1, E)],
$}]
end.
-%% write_tail(List, Depth, CharacterBeforeDots)
+%% write_tail(List, Depth, Encoding)
%% Test the terminating case first as this looks better with depth.
-write_tail([], _D, _E, _S) -> "";
-write_tail(_, 1, _E, S) -> [S | "..."];
-write_tail([H|T], D, E, S) ->
- [$,,write1(H, D-1, E)|write_tail(T, D-1, E, S)];
-write_tail(Other, D, E, S) ->
- [S,write1(Other, D-1, E)].
+write_tail([], _D, _E) -> "";
+write_tail(_, 1, _E) -> [$| | "..."];
+write_tail([H|T], D, E) ->
+ [$,,write1(H, D-1, E)|write_tail(T, D-1, E)];
+write_tail(Other, D, E) ->
+ [$|,write1(Other, D-1, E)].
+
+write_tuple(T, I, _D, _E) when I > tuple_size(T) -> "";
+write_tuple(_, _I, 1, _E) -> [$, | "..."];
+write_tuple(T, I, D, E) ->
+ [$,,write1(element(I, T), D-1, E)|write_tuple(T, I+1, D-1, E)].
write_port(Port) ->
erlang:port_to_list(Port).
@@ -332,33 +412,55 @@ write_port(Port) ->
write_ref(Ref) ->
erlang:ref_to_list(Ref).
+write_map(_, 1, _E) -> "#{}";
write_map(Map, D, E) when is_integer(D) ->
- [$#,${,write_map_body(maps:to_list(Map), D, E),$}].
+ I = maps:iterator(Map),
+ case maps:next(I) of
+ {K, V, NextI} ->
+ D0 = D - 1,
+ W = write_map_assoc(K, V, D0, E),
+ [$#,${,[W | write_map_body(NextI, D0, D0, E)],$}];
+ none -> "#{}"
+ end.
-write_map_body(_, 0, _E) -> "...";
-write_map_body([], _, _E) -> [];
-write_map_body([{K,V}], D, E) -> write_map_assoc(K, V, D, E);
-write_map_body([{K,V}|KVs], D, E) ->
- [write_map_assoc(K, V, D, E),$, | write_map_body(KVs, D-1, E)].
+write_map_body(_, 1, _D0, _E) -> ",...";
+write_map_body(I, D, D0, E) ->
+ case maps:next(I) of
+ {K, V, NextI} ->
+ W = write_map_assoc(K, V, D0, E),
+ [$,,W|write_map_body(NextI, D - 1, D0, E)];
+ none -> ""
+ end.
write_map_assoc(K, V, D, E) ->
- [write1(K, D - 1, E),"=>",write1(V, D-1, E)].
+ [write1(K, D, E)," => ",write1(V, D, E)].
write_binary(B, D) when is_integer(D) ->
- [$<,$<,write_binary_body(B, D),$>,$>].
-
-write_binary_body(<<>>, _D) ->
- "";
-write_binary_body(_B, 1) ->
- "...";
-write_binary_body(<<X:8>>, _D) ->
- [integer_to_list(X)];
-write_binary_body(<<X:8,Rest/bitstring>>, D) ->
- [integer_to_list(X),$,|write_binary_body(Rest, D-1)];
-write_binary_body(B, _D) ->
+ {S, _} = write_binary(B, D, -1),
+ S.
+
+write_binary(B, D, T) ->
+ {S, Rest} = write_binary_body(B, D, tsub(T, 4), []),
+ {[$<,$<,lists:reverse(S),$>,$>], Rest}.
+
+write_binary_body(<<>> = B, _D, _T, Acc) ->
+ {Acc, B};
+write_binary_body(B, D, T, Acc) when D =:= 1; T =:= 0->
+ {["..."|Acc], B};
+write_binary_body(<<X:8>>, _D, _T, Acc) ->
+ {[integer_to_list(X)|Acc], <<>>};
+write_binary_body(<<X:8,Rest/bitstring>>, D, T, Acc) ->
+ S = integer_to_list(X),
+ write_binary_body(Rest, D-1, tsub(T, length(S) + 1), [$,,S|Acc]);
+write_binary_body(B, _D, _T, Acc) ->
L = bit_size(B),
<<X:L>> = B,
- [integer_to_list(X),$:,integer_to_list(L)].
+ {[integer_to_list(L),$:,integer_to_list(X)|Acc], <<>>}.
+
+%% Make sure T does not change sign.
+tsub(T, _) when T < 0 -> T;
+tsub(T, E) when T >= E -> T - E;
+tsub(_, _) -> 0.
get_option(Key, TupleList, Default) ->
case lists:keyfind(Key, 1, TupleList) of
@@ -931,7 +1033,7 @@ limit_term(Term, Depth) ->
limit(_, 0) -> '...';
limit([H|T]=L, D) ->
if
- D =:= 1 -> '...';
+ D =:= 1 -> ['...'];
true ->
case printable_list(L) of
true -> L;
@@ -944,10 +1046,10 @@ limit(Term, D) when is_map(Term) ->
limit({}=T, _D) -> T;
limit(T, D) when is_tuple(T) ->
if
- D =:= 1 -> '...';
+ D =:= 1 -> {'...'};
true ->
list_to_tuple([limit(element(1, T), D-1)|
- limit_tail(tl(tuple_to_list(T)), D-1)])
+ limit_tuple(T, 2, D-1)])
end;
limit(<<_/bitstring>>=Term, D) -> limit_bitstring(Term, D);
limit(Term, _D) -> Term.
@@ -959,23 +1061,36 @@ limit_tail([H|T], D) ->
limit_tail(Other, D) ->
limit(Other, D-1).
+limit_tuple(T, I, _D) when I > tuple_size(T) -> [];
+limit_tuple(_, _I, 1) -> ['...'];
+limit_tuple(T, I, D) ->
+ [limit(element(I, T), D-1)|limit_tuple(T, I+1, D-1)].
+
%% Cannot limit maps properly since there is no guarantee that
%% maps:from_list() creates a map with the same internal ordering of
-%% the selected associations as in Map.
+%% the selected associations as in Map. Instead of subtracting one
+%% from the depth as the map associations are traversed (as is done
+%% for tuples and lists), the same depth is applied to each and every
+%% (returned) association.
limit_map(Map, D) ->
- maps:from_list(erts_internal:maps_to_list(Map, D)).
-%% maps:from_list(limit_map_body(erts_internal:maps_to_list(Map, D), D)).
-
-%% limit_map_body(_, 0) -> [{'...', '...'}];
-%% limit_map_body([], _) -> [];
-%% limit_map_body([{K,V}], D) -> [limit_map_assoc(K, V, D)];
-%% limit_map_body([{K,V}|KVs], D) ->
-%% [limit_map_assoc(K, V, D) | limit_map_body(KVs, D-1)].
+ %% Keep one extra association to make sure the final ',...' is included.
+ limit_map_body(maps:iterator(Map), D + 1, D, []).
+
+limit_map_body(_I, 0, _D0, Acc) ->
+ maps:from_list(Acc);
+limit_map_body(I, D, D0, Acc) ->
+ case maps:next(I) of
+ {K, V, NextI} ->
+ limit_map_body(NextI, D-1, D0, [limit_map_assoc(K, V, D0) | Acc]);
+ none ->
+ maps:from_list(Acc)
+ end.
-%% limit_map_assoc(K, V, D) ->
-%% {limit(K, D-1), limit(V, D-1)}.
+limit_map_assoc(K, V, D) ->
+ %% Keep keys as are to avoid creating duplicated keys.
+ {K, limit(V, D - 1)}.
-limit_bitstring(B, _D) -> B. %% Keeps all printable binaries.
+limit_bitstring(B, _D) -> B. % Keeps all printable binaries.
test_limit(_, 0) -> throw(limit);
test_limit([H|T]=L, D) when is_integer(D) ->
@@ -1011,18 +1126,35 @@ test_limit_tuple(T, I, Sz, D) ->
test_limit(element(I, T), D-1),
test_limit_tuple(T, I+1, Sz, D-1).
-test_limit_map(_Map, _D) -> ok.
-%% test_limit_map_body(erts_internal:maps_to_list(Map, D), D).
-
-%% test_limit_map_body(_, 0) -> throw(limit);
-%% test_limit_map_body([], _) -> ok;
-%% test_limit_map_body([{K,V}], D) -> test_limit_map_assoc(K, V, D);
-%% test_limit_map_body([{K,V}|KVs], D) ->
-%% test_limit_map_assoc(K, V, D),
-%% test_limit_map_body(KVs, D-1).
+test_limit_map(Map, D) ->
+ test_limit_map_body(maps:iterator(Map), D).
+
+test_limit_map_body(_I, 0) -> throw(limit); % cannot happen
+test_limit_map_body(I, D) ->
+ case maps:next(I) of
+ {K, V, NextI} ->
+ test_limit_map_assoc(K, V, D),
+ test_limit_map_body(NextI, D-1);
+ none ->
+ ok
+ end.
-%% test_limit_map_assoc(K, V, D) ->
-%% test_limit(K, D-1),
-%% test_limit(V, D-1).
+test_limit_map_assoc(K, V, D) ->
+ test_limit(K, D - 1),
+ test_limit(V, D - 1).
test_limit_bitstring(_, _) -> ok.
+
+-spec chars_length(chars()) -> non_neg_integer().
+%% Optimized for deep lists S such that deep_latin1_char_list(S) is
+%% true. No binaries allowed! It is assumed that $\r is never followed
+%% by $\n if S is an iolist() (string:length() assigns such a
+%% sub-sequence length 1).
+chars_length(S) ->
+ try
+ %% true = deep_latin1_char_list(S),
+ iolist_size(S)
+ catch
+ _:_ ->
+ string:length(S)
+ end.
diff --git a/lib/stdlib/src/io_lib_format.erl b/lib/stdlib/src/io_lib_format.erl
index 4b2d15c8b3..157cc07e19 100644
--- a/lib/stdlib/src/io_lib_format.erl
+++ b/lib/stdlib/src/io_lib_format.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,7 +21,8 @@
%% Formatting functions of io library.
--export([fwrite/2,fwrite_g/1,indentation/2,scan/2,unscan/1,build/1]).
+-export([fwrite/2,fwrite/3,fwrite_g/1,indentation/2,scan/2,unscan/1,
+ build/1, build/2]).
%% Format the arguments in Args after string Format. Just generate
%% an error if there is an error in the arguments.
@@ -37,22 +38,48 @@
%% and it also splits the handling of the control characters into two
%% parts.
--spec fwrite(Format, Data) -> FormatList when
+-spec fwrite(Format, Data) -> io_lib:chars() when
Format :: io:format(),
- Data :: [term()],
- FormatList :: [char() | io_lib:format_spec()].
+ Data :: [term()].
fwrite(Format, Args) ->
build(scan(Format, Args)).
+-spec fwrite(Format, Data, Options) -> io_lib:chars() when
+ Format :: io:format(),
+ Data :: [term()],
+ Options :: [Option],
+ Option :: {'chars_limit', CharsLimit},
+ CharsLimit :: io_lib:chars_limit().
+
+fwrite(Format, Args, Options) ->
+ build(scan(Format, Args), Options).
+
%% Build the output text for a pre-parsed format list.
-spec build(FormatList) -> io_lib:chars() when
FormatList :: [char() | io_lib:format_spec()].
build(Cs) ->
- Pc = pcount(Cs),
- build(Cs, Pc, 0).
+ build(Cs, []).
+
+-spec build(FormatList, Options) -> io_lib:chars() when
+ FormatList :: [char() | io_lib:format_spec()],
+ Options :: [Option],
+ Option :: {'chars_limit', CharsLimit},
+ CharsLimit :: io_lib:chars_limit().
+
+build(Cs, Options) ->
+ CharsLimit = get_option(chars_limit, Options, -1),
+ Res1 = build_small(Cs),
+ {P, S, W, Other} = count_small(Res1),
+ case P + S + W of
+ 0 ->
+ Res1;
+ NumOfLimited ->
+ RemainingChars = sub(CharsLimit, Other),
+ build_limited(Res1, P, NumOfLimited, RemainingChars, 0)
+ end.
%% Parse all control sequences in the format string.
@@ -95,7 +122,7 @@ print([]) ->
[].
print(C, F, Ad, P, Pad, Encoding, Strings) ->
- [$~] ++ print_field_width(F, Ad) ++ print_precision(P) ++
+ [$~] ++ print_field_width(F, Ad) ++ print_precision(P, Pad) ++
print_pad_char(Pad) ++ print_encoding(Encoding) ++
print_strings(Strings) ++ [C].
@@ -103,8 +130,9 @@ print_field_width(none, _Ad) -> "";
print_field_width(F, left) -> integer_to_list(-F);
print_field_width(F, right) -> integer_to_list(F).
-print_precision(none) -> "";
-print_precision(P) -> [$. | integer_to_list(P)].
+print_precision(none, $\s) -> "";
+print_precision(none, _Pad) -> "."; % pad must be second dot
+print_precision(P, _Pad) -> [$. | integer_to_list(P)].
print_pad_char($\s) -> ""; % default, no need to make explicit
print_pad_char(Pad) -> [$., Pad].
@@ -126,25 +154,23 @@ collect_cseq(Fmt0, Args0) ->
{F,Ad,Fmt1,Args1} = field_width(Fmt0, Args0),
{P,Fmt2,Args2} = precision(Fmt1, Args1),
{Pad,Fmt3,Args3} = pad_char(Fmt2, Args2),
- {Encoding,Fmt4,Args4} = encoding(Fmt3, Args3),
- {Strings,Fmt5,Args5} = strings(Fmt4, Args4),
- {C,As,Fmt6,Args6} = collect_cc(Fmt5, Args5),
- FormatSpec = #{control_char => C, args => As, width => F, adjust => Ad,
- precision => P, pad_char => Pad, encoding => Encoding,
- strings => Strings},
- {FormatSpec,Fmt6,Args6}.
-
-encoding([$t|Fmt],Args) ->
- true = hd(Fmt) =/= $l,
- {unicode,Fmt,Args};
-encoding(Fmt,Args) ->
- {latin1,Fmt,Args}.
-
-strings([$l|Fmt],Args) ->
- true = hd(Fmt) =/= $t,
- {false,Fmt,Args};
-strings(Fmt,Args) ->
- {true,Fmt,Args}.
+ Spec0 = #{width => F,
+ adjust => Ad,
+ precision => P,
+ pad_char => Pad,
+ encoding => latin1,
+ strings => true},
+ {Spec1,Fmt4} = modifiers(Fmt3, Spec0),
+ {C,As,Fmt5,Args4} = collect_cc(Fmt4, Args3),
+ Spec2 = Spec1#{control_char => C, args => As},
+ {Spec2,Fmt5,Args4}.
+
+modifiers([$t|Fmt], Spec) ->
+ modifiers(Fmt, Spec#{encoding => unicode});
+modifiers([$l|Fmt], Spec) ->
+ modifiers(Fmt, Spec#{strings => false});
+modifiers(Fmt, Spec) ->
+ {Spec, Fmt}.
field_width([$-|Fmt0], Args0) ->
{F,Fmt,Args} = field_value(Fmt0, Args0),
@@ -203,40 +229,83 @@ collect_cc([$~|Fmt], Args) when is_list(Args) -> {$~,[],Fmt,Args};
collect_cc([$n|Fmt], Args) when is_list(Args) -> {$n,[],Fmt,Args};
collect_cc([$i|Fmt], [A|Args]) -> {$i,[A],Fmt,Args}.
-%% pcount([ControlC]) -> Count.
-%% Count the number of print requests.
-
-pcount(Cs) -> pcount(Cs, 0).
-
-pcount([#{control_char := $p}|Cs], Acc) -> pcount(Cs, Acc+1);
-pcount([#{control_char := $P}|Cs], Acc) -> pcount(Cs, Acc+1);
-pcount([_|Cs], Acc) -> pcount(Cs, Acc);
-pcount([], Acc) -> Acc.
-
-%% build([Control], Pc, Indentation) -> io_lib:chars().
+%% count_small([ControlC]) -> Count.
+%% Count the number of big (pPwWsS) print requests and
+%% number of characters of other print (small) requests.
+
+count_small(Cs) ->
+ count_small(Cs, #{p => 0, s => 0, w => 0, other => 0}).
+
+count_small([#{control_char := $p}|Cs], #{p := P} = Cnts) ->
+ count_small(Cs, Cnts#{p := P + 1});
+count_small([#{control_char := $P}|Cs], #{p := P} = Cnts) ->
+ count_small(Cs, Cnts#{p := P + 1});
+count_small([#{control_char := $w}|Cs], #{w := W} = Cnts) ->
+ count_small(Cs, Cnts#{w := W + 1});
+count_small([#{control_char := $W}|Cs], #{w := W} = Cnts) ->
+ count_small(Cs, Cnts#{w := W + 1});
+count_small([#{control_char := $s}|Cs], #{w := W} = Cnts) ->
+ count_small(Cs, Cnts#{w := W + 1});
+count_small([S|Cs], #{other := Other} = Cnts) when is_list(S);
+ is_binary(S) ->
+ count_small(Cs, Cnts#{other := Other + io_lib:chars_length(S)});
+count_small([C|Cs], #{other := Other} = Cnts) when is_integer(C) ->
+ count_small(Cs, Cnts#{other := Other + 1});
+count_small([], #{p := P, s := S, w := W, other := Other}) ->
+ {P, S, W, Other}.
+
+%% build_small([Control]) -> io_lib:chars().
+%% Interpret the control structures, but only the small ones.
+%% The big ones are saved for later.
+%% build_limited([Control], NumberOfPps, NumberOfLimited,
+%% CharsLimit, Indentation)
%% Interpret the control structures. Count the number of print
%% remaining and only calculate indentation when necessary. Must also
%% be smart when calculating indentation for characters in format.
-build([#{control_char := C, args := As, width := F, adjust := Ad,
- precision := P, pad_char := Pad, encoding := Enc,
- strings := Str} | Cs], Pc0, I) ->
- S = control(C, As, F, Ad, P, Pad, Enc, Str, I),
- Pc1 = decr_pc(C, Pc0),
+build_small([#{control_char := C, args := As, width := F, adjust := Ad,
+ precision := P, pad_char := Pad, encoding := Enc}=CC | Cs]) ->
+ case control_small(C, As, F, Ad, P, Pad, Enc) of
+ not_small -> [CC | build_small(Cs)];
+ S -> lists:flatten(S) ++ build_small(Cs)
+ end;
+build_small([C|Cs]) -> [C|build_small(Cs)];
+build_small([]) -> [].
+
+build_limited([#{control_char := C, args := As, width := F, adjust := Ad,
+ precision := P, pad_char := Pad, encoding := Enc,
+ strings := Str} | Cs], NumOfPs0, Count0, MaxLen0, I) ->
+ MaxChars = if
+ MaxLen0 < 0 -> MaxLen0;
+ true -> MaxLen0 div Count0
+ end,
+ S = control_limited(C, As, F, Ad, P, Pad, Enc, Str, MaxChars, I),
+ NumOfPs = decr_pc(C, NumOfPs0),
+ Count = Count0 - 1,
+ MaxLen = if
+ MaxLen0 < 0 -> % optimization
+ MaxLen0;
+ true ->
+ Len = io_lib:chars_length(S),
+ sub(MaxLen0, Len)
+ end,
if
- Pc1 > 0 -> [S|build(Cs, Pc1, indentation(S, I))];
- true -> [S|build(Cs, Pc1, I)]
+ NumOfPs > 0 -> [S|build_limited(Cs, NumOfPs, Count,
+ MaxLen, indentation(S, I))];
+ true -> [S|build_limited(Cs, NumOfPs, Count, MaxLen, I)]
end;
-build([$\n|Cs], Pc, _I) -> [$\n|build(Cs, Pc, 0)];
-build([$\t|Cs], Pc, I) -> [$\t|build(Cs, Pc, ((I + 8) div 8) * 8)];
-build([C|Cs], Pc, I) -> [C|build(Cs, Pc, I+1)];
-build([], _Pc, _I) -> [].
+build_limited([$\n|Cs], NumOfPs, Count, MaxLen, _I) ->
+ [$\n|build_limited(Cs, NumOfPs, Count, MaxLen, 0)];
+build_limited([$\t|Cs], NumOfPs, Count, MaxLen, I) ->
+ [$\t|build_limited(Cs, NumOfPs, Count, MaxLen, ((I + 8) div 8) * 8)];
+build_limited([C|Cs], NumOfPs, Count, MaxLen, I) ->
+ [C|build_limited(Cs, NumOfPs, Count, MaxLen, I+1)];
+build_limited([], _, _, _, _) -> [].
decr_pc($p, Pc) -> Pc - 1;
decr_pc($P, Pc) -> Pc - 1;
decr_pc(_, Pc) -> Pc.
-
%% Calculate the indentation of the end of a string given its start
%% indentation. We assume tabs at 8 cols.
@@ -252,67 +321,74 @@ indentation([C|Cs], I) ->
indentation(Cs, indentation(C, I));
indentation([], I) -> I.
-%% control(FormatChar, [Argument], FieldWidth, Adjust, Precision, PadChar,
-%% Encoding, Indentation) -> String
-%% This is the main dispatch function for the various formatting commands.
-%% Field widths and precisions have already been calculated.
-
-control($w, [A], F, Adj, P, Pad, Enc, _Str, _I) ->
- term(io_lib:write(A, [{depth,-1}, {encoding, Enc}]), F, Adj, P, Pad);
-control($p, [A], F, Adj, P, Pad, Enc, Str, I) ->
- print(A, -1, F, Adj, P, Pad, Enc, Str, I);
-control($W, [A,Depth], F, Adj, P, Pad, Enc, _Str, _I) when is_integer(Depth) ->
- term(io_lib:write(A, [{depth,Depth}, {encoding, Enc}]), F, Adj, P, Pad);
-control($P, [A,Depth], F, Adj, P, Pad, Enc, Str, I) when is_integer(Depth) ->
- print(A, Depth, F, Adj, P, Pad, Enc, Str, I);
-control($s, [A], F, Adj, P, Pad, latin1, _Str, _I) when is_atom(A) ->
+%% control_small(FormatChar, [Argument], FieldWidth, Adjust, Precision,
+%% PadChar, Encoding) -> String
+%% control_limited(FormatChar, [Argument], FieldWidth, Adjust, Precision,
+%% PadChar, Encoding, StringP, ChrsLim, Indentation) -> String
+%% These are the dispatch functions for the various formatting controls.
+
+control_small($s, [A], F, Adj, P, Pad, latin1=Enc) when is_atom(A) ->
L = iolist_to_chars(atom_to_list(A)),
- string(L, F, Adj, P, Pad);
-control($s, [A], F, Adj, P, Pad, unicode, _Str, _I) when is_atom(A) ->
- string(atom_to_list(A), F, Adj, P, Pad);
-control($s, [L0], F, Adj, P, Pad, latin1, _Str, _I) ->
- L = iolist_to_chars(L0),
- string(L, F, Adj, P, Pad);
-control($s, [L0], F, Adj, P, Pad, unicode, _Str, _I) ->
- L = cdata_to_chars(L0),
- uniconv(string(L, F, Adj, P, Pad));
-control($e, [A], F, Adj, P, Pad, _Enc, _Str, _I) when is_float(A) ->
+ string(L, F, Adj, P, Pad, Enc);
+control_small($s, [A], F, Adj, P, Pad, unicode=Enc) when is_atom(A) ->
+ string(atom_to_list(A), F, Adj, P, Pad, Enc);
+control_small($e, [A], F, Adj, P, Pad, _Enc) when is_float(A) ->
fwrite_e(A, F, Adj, P, Pad);
-control($f, [A], F, Adj, P, Pad, _Enc, _Str, _I) when is_float(A) ->
+control_small($f, [A], F, Adj, P, Pad, _Enc) when is_float(A) ->
fwrite_f(A, F, Adj, P, Pad);
-control($g, [A], F, Adj, P, Pad, _Enc, _Str, _I) when is_float(A) ->
+control_small($g, [A], F, Adj, P, Pad, _Enc) when is_float(A) ->
fwrite_g(A, F, Adj, P, Pad);
-control($b, [A], F, Adj, P, Pad, _Enc, _Str, _I) when is_integer(A) ->
+control_small($b, [A], F, Adj, P, Pad, _Enc) when is_integer(A) ->
unprefixed_integer(A, F, Adj, base(P), Pad, true);
-control($B, [A], F, Adj, P, Pad, _Enc, _Str, _I) when is_integer(A) ->
+control_small($B, [A], F, Adj, P, Pad, _Enc) when is_integer(A) ->
unprefixed_integer(A, F, Adj, base(P), Pad, false);
-control($x, [A,Prefix], F, Adj, P, Pad, _Enc, _Str, _I) when is_integer(A),
- is_atom(Prefix) ->
+control_small($x, [A,Prefix], F, Adj, P, Pad, _Enc) when is_integer(A),
+ is_atom(Prefix) ->
prefixed_integer(A, F, Adj, base(P), Pad, atom_to_list(Prefix), true);
-control($x, [A,Prefix], F, Adj, P, Pad, _Enc, _Str, _I) when is_integer(A) ->
+control_small($x, [A,Prefix], F, Adj, P, Pad, _Enc) when is_integer(A) ->
true = io_lib:deep_char_list(Prefix), %Check if Prefix a character list
prefixed_integer(A, F, Adj, base(P), Pad, Prefix, true);
-control($X, [A,Prefix], F, Adj, P, Pad, _Enc, _Str, _I) when is_integer(A),
- is_atom(Prefix) ->
+control_small($X, [A,Prefix], F, Adj, P, Pad, _Enc) when is_integer(A),
+ is_atom(Prefix) ->
prefixed_integer(A, F, Adj, base(P), Pad, atom_to_list(Prefix), false);
-control($X, [A,Prefix], F, Adj, P, Pad, _Enc, _Str, _I) when is_integer(A) ->
+control_small($X, [A,Prefix], F, Adj, P, Pad, _Enc) when is_integer(A) ->
true = io_lib:deep_char_list(Prefix), %Check if Prefix a character list
prefixed_integer(A, F, Adj, base(P), Pad, Prefix, false);
-control($+, [A], F, Adj, P, Pad, _Enc, _Str, _I) when is_integer(A) ->
+control_small($+, [A], F, Adj, P, Pad, _Enc) when is_integer(A) ->
Base = base(P),
Prefix = [integer_to_list(Base), $#],
prefixed_integer(A, F, Adj, Base, Pad, Prefix, true);
-control($#, [A], F, Adj, P, Pad, _Enc, _Str, _I) when is_integer(A) ->
+control_small($#, [A], F, Adj, P, Pad, _Enc) when is_integer(A) ->
Base = base(P),
Prefix = [integer_to_list(Base), $#],
prefixed_integer(A, F, Adj, Base, Pad, Prefix, false);
-control($c, [A], F, Adj, P, Pad, unicode, _Str, _I) when is_integer(A) ->
+control_small($c, [A], F, Adj, P, Pad, unicode) when is_integer(A) ->
char(A, F, Adj, P, Pad);
-control($c, [A], F, Adj, P, Pad, _Enc, _Str, _I) when is_integer(A) ->
+control_small($c, [A], F, Adj, P, Pad, _Enc) when is_integer(A) ->
char(A band 255, F, Adj, P, Pad);
-control($~, [], F, Adj, P, Pad, _Enc, _Str, _I) -> char($~, F, Adj, P, Pad);
-control($n, [], F, Adj, P, Pad, _Enc, _Str, _I) -> newline(F, Adj, P, Pad);
-control($i, [_A], _F, _Adj, _P, _Pad, _Enc, _Str, _I) -> [].
+control_small($~, [], F, Adj, P, Pad, _Enc) -> char($~, F, Adj, P, Pad);
+control_small($n, [], F, Adj, P, Pad, _Enc) -> newline(F, Adj, P, Pad);
+control_small($i, [_A], _F, _Adj, _P, _Pad, _Enc) -> [];
+control_small(_C, _As, _F, _Adj, _P, _Pad, _Enc) -> not_small.
+
+control_limited($s, [L0], F, Adj, P, Pad, latin1=Enc, _Str, CL, _I) ->
+ L = iolist_to_chars(L0, F, CL),
+ string(L, limit_field(F, CL), Adj, P, Pad, Enc);
+control_limited($s, [L0], F, Adj, P, Pad, unicode=Enc, _Str, CL, _I) ->
+ L = cdata_to_chars(L0, F, CL),
+ uniconv(string(L, limit_field(F, CL), Adj, P, Pad, Enc));
+control_limited($w, [A], F, Adj, P, Pad, Enc, _Str, CL, _I) ->
+ Chars = io_lib:write(A, [{depth, -1}, {encoding, Enc}, {chars_limit, CL}]),
+ term(Chars, F, Adj, P, Pad);
+control_limited($p, [A], F, Adj, P, Pad, Enc, Str, CL, I) ->
+ print(A, -1, F, Adj, P, Pad, Enc, Str, CL, I);
+control_limited($W, [A,Depth], F, Adj, P, Pad, Enc, _Str, CL, _I)
+ when is_integer(Depth) ->
+ Chars = io_lib:write(A, [{depth, Depth}, {encoding, Enc}, {chars_limit, CL}]),
+ term(Chars, F, Adj, P, Pad);
+control_limited($P, [A,Depth], F, Adj, P, Pad, Enc, Str, CL, I)
+ when is_integer(Depth) ->
+ print(A, Depth, F, Adj, P, Pad, Enc, Str, CL, I).
-ifdef(UNICODE_AS_BINARIES).
uniconv(C) ->
@@ -335,7 +411,7 @@ base(B) when is_integer(B) ->
term(T, none, _Adj, none, _Pad) -> T;
term(T, none, Adj, P, Pad) -> term(T, P, Adj, P, Pad);
term(T, F, Adj, P0, Pad) ->
- L = string:length(T),
+ L = io_lib:chars_length(T),
P = erlang:min(L, case P0 of none -> F; _ -> min(P0, F) end),
if
L > P ->
@@ -349,12 +425,13 @@ term(T, F, Adj, P0, Pad) ->
%% Print a term. Field width sets maximum line length, Precision sets
%% initial indentation.
-print(T, D, none, Adj, P, Pad, E, Str, I) ->
- print(T, D, 80, Adj, P, Pad, E, Str, I);
-print(T, D, F, Adj, none, Pad, E, Str, I) ->
- print(T, D, F, Adj, I+1, Pad, E, Str, I);
-print(T, D, F, right, P, _Pad, Enc, Str, _I) ->
- Options = [{column, P},
+print(T, D, none, Adj, P, Pad, E, Str, ChLim, I) ->
+ print(T, D, 80, Adj, P, Pad, E, Str, ChLim, I);
+print(T, D, F, Adj, none, Pad, E, Str, ChLim, I) ->
+ print(T, D, F, Adj, I+1, Pad, E, Str, ChLim, I);
+print(T, D, F, right, P, _Pad, Enc, Str, ChLim, _I) ->
+ Options = [{chars_limit, ChLim},
+ {column, P},
{line_length, F},
{depth, D},
{encoding, Enc},
@@ -380,7 +457,7 @@ float_e(_Fl, {Ds,E}, P) ->
{Fs,false} -> [Fs|float_exp(E-1)]
end.
-%% float_man([Digit], Icount, Dcount) -> {[Chars],CarryFlag}.
+%% float_man([Digit], Icount, Dcount) -> {[Char],CarryFlag}.
%% Generate the characters in the mantissa from the digits with Icount
%% characters before the '.' and Dcount decimals. Handle carry and let
%% caller decide what to do at top.
@@ -395,7 +472,7 @@ float_man([D|Ds], I, Dc) ->
{Cs,false} -> {[D|Cs],false}
end;
float_man([], I, Dc) -> %Pad with 0's
- {string:chars($0, I, [$.|string:chars($0, Dc)]),false}.
+ {lists:duplicate(I, $0) ++ [$.|lists:duplicate(Dc, $0)],false}.
float_man([D|_], 0) when D >= $5 -> {[],true};
float_man([_|_], 0) -> {[],false};
@@ -405,7 +482,7 @@ float_man([D|Ds], Dc) ->
{Cs,true} -> {[D+1|Cs],false};
{Cs,false} -> {[D|Cs],false}
end;
-float_man([], Dc) -> {string:chars($0, Dc),false}. %Pad with 0's
+float_man([], Dc) -> {lists:duplicate(Dc, $0),false}. %Pad with 0's
%% float_exp(Exponent) -> [Char].
%% Generate the exponent of a floating point number. Always include sign.
@@ -429,7 +506,7 @@ fwrite_f(Fl, F, Adj, P, Pad) when P >= 1 ->
float_f(Fl, Fd, P) when Fl < 0.0 ->
[$-|float_f(-Fl, Fd, P)];
float_f(Fl, {Ds,E}, P) when E =< 0 ->
- float_f(Fl, {string:chars($0, -E+1, Ds),1}, P); %Prepend enough 0's
+ float_f(Fl, {lists:duplicate(-E+1, $0)++Ds,1}, P); %Prepend enough 0's
float_f(_Fl, {Ds,E}, P) ->
case float_man(Ds, E, P) of
{Fs,true} -> "1" ++ Fs; %Handle carry
@@ -641,7 +718,10 @@ fwrite_g(Fl, F, Adj, P, Pad) when P >= 1 ->
end.
-%% iolist_to_chars(iolist()) -> deep_char_list()
+iolist_to_chars(Cs, F, CharsLimit) when CharsLimit < 0; CharsLimit >= F ->
+ iolist_to_chars(Cs);
+iolist_to_chars(Cs, _, CharsLimit) ->
+ limit_iolist_to_chars(Cs, sub(CharsLimit, 3), [], normal). % three dots
iolist_to_chars([C|Cs]) when is_integer(C), C >= $\000, C =< $\377 ->
[C | iolist_to_chars(Cs)];
@@ -652,12 +732,34 @@ iolist_to_chars([]) ->
iolist_to_chars(B) when is_binary(B) ->
binary_to_list(B).
-%% cdata() :: clist() | cbinary()
-%% clist() :: maybe_improper_list(char() | cbinary() | clist(),
-%% cbinary() | nil())
-%% cbinary() :: unicode:unicode_binary() | unicode:latin1_binary()
+limit_iolist_to_chars(Cs, 0, S, normal) ->
+ L = limit_iolist_to_chars(Cs, 4, S, final),
+ case iolist_size(L) of
+ N when N < 4 -> L;
+ 4 -> "..."
+ end;
+limit_iolist_to_chars(_Cs, 0, _S, final) -> [];
+limit_iolist_to_chars([C|Cs], Limit, S, Mode) when C >= $\000, C =< $\377 ->
+ [C | limit_iolist_to_chars(Cs, Limit - 1, S, Mode)];
+limit_iolist_to_chars([I|Cs], Limit, S, Mode) ->
+ limit_iolist_to_chars(I, Limit, [Cs|S], Mode);
+limit_iolist_to_chars([], _Limit, [], _Mode) ->
+ [];
+limit_iolist_to_chars([], Limit, [Cs|S], Mode) ->
+ limit_iolist_to_chars(Cs, Limit, S, Mode);
+limit_iolist_to_chars(B, Limit, S, Mode) when is_binary(B) ->
+ case byte_size(B) of
+ Sz when Sz > Limit ->
+ {B1, B2} = split_binary(B, Limit),
+ [binary_to_list(B1) | limit_iolist_to_chars(B2, 0, S, Mode)];
+ Sz ->
+ [binary_to_list(B) | limit_iolist_to_chars([], Limit-Sz, S, Mode)]
+ end.
-%% cdata_to_chars(cdata()) -> io_lib:deep_char_list()
+cdata_to_chars(Cs, F, CharsLimit) when CharsLimit < 0; CharsLimit >= F ->
+ cdata_to_chars(Cs);
+cdata_to_chars(Cs, _, CharsLimit) ->
+ limit_cdata_to_chars(Cs, sub(CharsLimit, 3), normal). % three dots
cdata_to_chars([C|Cs]) when is_integer(C), C >= $\000 ->
[C | cdata_to_chars(Cs)];
@@ -671,32 +773,58 @@ cdata_to_chars(B) when is_binary(B) ->
_ -> binary_to_list(B)
end.
+limit_cdata_to_chars(Cs, 0, normal) ->
+ L = limit_cdata_to_chars(Cs, 4, final),
+ case string:length(L) of
+ N when N < 4 -> L;
+ 4 -> "..."
+ end;
+limit_cdata_to_chars(_Cs, 0, final) -> [];
+limit_cdata_to_chars(Cs, Limit, Mode) ->
+ case string:next_grapheme(Cs) of
+ {error, <<C,Cs1/binary>>} ->
+ %% This is how ~ts handles Latin1 binaries with option
+ %% chars_limit.
+ [C | limit_cdata_to_chars(Cs1, Limit - 1, Mode)];
+ {error, [C|Cs1]} -> % not all versions of module string return this
+ [C | limit_cdata_to_chars(Cs1, Limit - 1, Mode)];
+ [] ->
+ [];
+ [GC|Cs1] ->
+ [GC | limit_cdata_to_chars(Cs1, Limit - 1, Mode)]
+ end.
+
+limit_field(F, CharsLimit) when CharsLimit < 0; F =:= none ->
+ F;
+limit_field(F, CharsLimit) ->
+ max(3, min(F, CharsLimit)).
+
%% string(String, Field, Adjust, Precision, PadChar)
-string(S, none, _Adj, none, _Pad) -> S;
-string(S, F, Adj, none, Pad) ->
- string_field(S, F, Adj, string:length(S), Pad);
-string(S, none, _Adj, P, Pad) ->
- string_field(S, P, left, string:length(S), Pad);
-string(S, F, Adj, P, Pad) when F >= P ->
- N = string:length(S),
+string(S, none, _Adj, none, _Pad, _Enc) -> S;
+string(S, F, Adj, none, Pad, Enc) ->
+ string_field(S, F, Adj, io_lib:chars_length(S), Pad, Enc);
+string(S, none, _Adj, P, Pad, Enc) ->
+ string_field(S, P, left, io_lib:chars_length(S), Pad, Enc);
+string(S, F, Adj, P, Pad, Enc) when F >= P ->
+ N = io_lib:chars_length(S),
if F > P ->
if N > P ->
- adjust(flat_trunc(S, P), chars(Pad, F-P), Adj);
+ adjust(flat_trunc(S, P, Enc), chars(Pad, F-P), Adj);
N < P ->
adjust([S|chars(Pad, P-N)], chars(Pad, F-P), Adj);
true -> % N == P
adjust(S, chars(Pad, F-P), Adj)
end;
true -> % F == P
- string_field(S, F, Adj, N, Pad)
+ string_field(S, F, Adj, N, Pad, Enc)
end.
-string_field(S, F, _Adj, N, _Pad) when N > F ->
- flat_trunc(S, F);
-string_field(S, F, Adj, N, Pad) when N < F ->
+string_field(S, F, _Adj, N, _Pad, Enc) when N > F ->
+ flat_trunc(S, F, Enc);
+string_field(S, F, Adj, N, Pad, _Enc) when N < F ->
adjust(S, chars(Pad, F-N), Adj);
-string_field(S, _, _, _, _) -> % N == F
+string_field(S, _, _, _, _, _) -> % N == F
S.
%% unprefixed_integer(Int, Field, Adjust, Base, PadChar, Lowercase)
@@ -748,10 +876,13 @@ adjust(Data, Pad, right) -> [Pad|Data].
%% Flatten and truncate a deep list to at most N elements.
-flat_trunc(List, N) when is_integer(N), N >= 0 ->
+flat_trunc(List, N, latin1) when is_integer(N), N >= 0 ->
+ {S, _} = lists:split(N, lists:flatten(List)),
+ S;
+flat_trunc(List, N, unicode) when is_integer(N), N >= 0 ->
string:slice(List, 0, N).
-%% A deep version of string:chars/2,3
+%% A deep version of lists:duplicate/2
chars(_C, 0) ->
[];
@@ -784,3 +915,15 @@ lowercase([H|T]) ->
[H|lowercase(T)];
lowercase([]) ->
[].
+
+%% Make sure T does change sign.
+sub(T, _) when T < 0 -> T;
+sub(T, E) when T >= E -> T - E;
+sub(_, _) -> 0.
+
+get_option(Key, TupleList, Default) ->
+ case lists:keyfind(Key, 1, TupleList) of
+ false -> Default;
+ {Key, Value} -> Value;
+ _ -> Default
+ end.
diff --git a/lib/stdlib/src/io_lib_pretty.erl b/lib/stdlib/src/io_lib_pretty.erl
index 505613b80e..b1a5991bf0 100644
--- a/lib/stdlib/src/io_lib_pretty.erl
+++ b/lib/stdlib/src/io_lib_pretty.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,6 +26,9 @@
-export([print/1,print/2,print/3,print/4,print/5,print/6]).
+%% To be used by io_lib only.
+-export([intermediate/6, write/1]).
+
%%%
%%% Exported functions
%%%
@@ -45,20 +48,23 @@ print(Term) ->
%% Used by the shell for printing records and for Unicode.
-type rec_print_fun() :: fun((Tag :: atom(), NFields :: non_neg_integer()) ->
- no | [FieldName :: atom()]).
+ 'no' | [FieldName :: atom()]).
-type column() :: integer().
+-type encoding() :: epp:source_encoding() | 'unicode'.
-type line_length() :: pos_integer().
-type depth() :: integer().
--type max_chars() :: integer().
+-type line_max_chars() :: integer().
+-type chars_limit() :: integer().
-type chars() :: io_lib:chars().
--type option() :: {column, column()}
- | {line_length, line_length()}
- | {depth, depth()}
- | {max_chars, max_chars()}
- | {record_print_fun, rec_print_fun()}
- | {strings, boolean()}
- | {encoding, latin1 | utf8 | unicode}.
+-type option() :: {'chars_limit', chars_limit()}
+ | {'column', column()}
+ | {'depth', depth()}
+ | {'encoding', encoding()}
+ | {'line_length', line_length()}
+ | {'line_max_chars', line_max_chars()}
+ | {'record_print_fun', rec_print_fun()}
+ | {'strings', boolean()}.
-type options() :: [option()].
-spec print(term(), rec_print_fun()) -> chars();
@@ -68,11 +74,12 @@ print(Term, Options) when is_list(Options) ->
Col = get_option(column, Options, 1),
Ll = get_option(line_length, Options, 80),
D = get_option(depth, Options, -1),
- M = get_option(max_chars, Options, -1),
+ M = get_option(line_max_chars, Options, -1),
+ T = get_option(chars_limit, Options, -1),
RecDefFun = get_option(record_print_fun, Options, no_fun),
Encoding = get_option(encoding, Options, epp:default_encoding()),
Strings = get_option(strings, Options, true),
- print(Term, Col, Ll, D, M, RecDefFun, Encoding, Strings);
+ print(Term, Col, Ll, D, M, T, RecDefFun, Encoding, Strings);
print(Term, RecDefFun) ->
print(Term, -1, RecDefFun).
@@ -84,38 +91,48 @@ print(Term, Depth, RecDefFun) ->
-spec print(term(), column(), line_length(), depth()) -> chars().
print(Term, Col, Ll, D) ->
- print(Term, Col, Ll, D, _M=-1, no_fun, latin1, true).
+ print(Term, Col, Ll, D, _M=-1, _T=-1, no_fun, latin1, true).
-spec print(term(), column(), line_length(), depth(), rec_print_fun()) ->
chars().
print(Term, Col, Ll, D, RecDefFun) ->
print(Term, Col, Ll, D, _M=-1, RecDefFun).
--spec print(term(), column(), line_length(), depth(), max_chars(),
+-spec print(term(), column(), line_length(), depth(), line_max_chars(),
rec_print_fun()) -> chars().
print(Term, Col, Ll, D, M, RecDefFun) ->
- print(Term, Col, Ll, D, M, RecDefFun, latin1, true).
+ print(Term, Col, Ll, D, M, _T=-1, RecDefFun, latin1, true).
%% D = Depth, default -1 (infinite), or LINEMAX=30 when printing from shell
+%% T = chars_limit, that is, maximal number of characters, default -1
+%% Used together with D to limit the output. It is possible that
+%% more than T characters are returned.
%% Col = current column, default 1
%% Ll = line length/~p field width, default 80
%% M = CHAR_MAX (-1 if no max, 60 when printing from shell)
-print(_, _, _, 0, _M, _RF, _Enc, _Str) -> "...";
-print(Term, Col, Ll, D, M, RecDefFun, Enc, Str) when Col =< 0 ->
+print(_, _, _, 0, _M, _T, _RF, _Enc, _Str) -> "...";
+print(_, _, _, _D, _M, 0, _RF, _Enc, _Str) -> "...";
+print(Term, Col, Ll, D, M, T, RecDefFun, Enc, Str) when Col =< 0 ->
%% ensure Col is at least 1
- print(Term, 1, Ll, D, M, RecDefFun, Enc, Str);
-print(Atom, _Col, _Ll, _D, _M, _RF, Enc, _Str) when is_atom(Atom) ->
+ print(Term, 1, Ll, D, M, T, RecDefFun, Enc, Str);
+print(Atom, _Col, _Ll, _D, _M, _T, _RF, Enc, _Str) when is_atom(Atom) ->
write_atom(Atom, Enc);
-print(Term, Col, Ll, D, M0, RecDefFun, Enc, Str) when is_tuple(Term);
- is_list(Term);
- is_map(Term);
- is_bitstring(Term) ->
+print(Term, Col, Ll, D, M0, T, RecDefFun, Enc, Str) when is_tuple(Term);
+ is_list(Term);
+ is_map(Term);
+ is_bitstring(Term) ->
%% preprocess and compute total number of chars
- If = {_S, Len} = print_length(Term, D, RecDefFun, Enc, Str),
+ {_, Len, _Dots, _} = If =
+ case T < 0 of
+ true -> print_length(Term, D, T, RecDefFun, Enc, Str);
+ false -> intermediate(Term, D, T, RecDefFun, Enc, Str)
+ end,
%% use Len as CHAR_MAX if M0 = -1
M = max_cs(M0, Len),
if
+ Ll =:= 0 ->
+ write(If);
Len < Ll - Col, Len =< M ->
%% write the whole thing on a single line when there is room
write(If);
@@ -126,7 +143,7 @@ print(Term, Col, Ll, D, M0, RecDefFun, Enc, Str) when is_tuple(Term);
1),
pp(If, Col, Ll, M, TInd, indent(Col), 0, 0)
end;
-print(Term, _Col, _Ll, _D, _M, _RF, _Enc, _Str) ->
+print(Term, _Col, _Ll, _D, _M, _T, _RF, _Enc, _Str) ->
%% atomic data types (bignums, atoms, ...) are never truncated
io_lib:write(Term).
@@ -147,28 +164,28 @@ max_cs(M, _Len) ->
?ATM(element(3, element(1, Pair)))). % Value
-define(ATM_FLD(Field), ?ATM(element(4, element(1, Field)))).
-pp({_S, Len} = If, Col, Ll, M, _TInd, _Ind, LD, W)
+pp({_S,Len,_,_} = If, Col, Ll, M, _TInd, _Ind, LD, W)
when Len < Ll - Col - LD, Len + W + LD =< M ->
write(If);
-pp({{list,L}, _Len}, Col, Ll, M, TInd, Ind, LD, W) ->
+pp({{list,L}, _Len, _, _}, Col, Ll, M, TInd, Ind, LD, W) ->
[$[, pp_list(L, Col + 1, Ll, M, TInd, indent(1, Ind), LD, $|, W + 1), $]];
-pp({{tuple,true,L}, _Len}, Col, Ll, M, TInd, Ind, LD, W) ->
+pp({{tuple,true,L}, _Len, _, _}, Col, Ll, M, TInd, Ind, LD, W) ->
[${, pp_tag_tuple(L, Col, Ll, M, TInd, Ind, LD, W + 1), $}];
-pp({{tuple,false,L}, _Len}, Col, Ll, M, TInd, Ind, LD, W) ->
+pp({{tuple,false,L}, _Len, _, _}, Col, Ll, M, TInd, Ind, LD, W) ->
[${, pp_list(L, Col + 1, Ll, M, TInd, indent(1, Ind), LD, $,, W + 1), $}];
-pp({{map,Pairs},_Len}, Col, Ll, M, TInd, Ind, LD, W) ->
+pp({{map,Pairs}, _Len, _, _}, Col, Ll, M, TInd, Ind, LD, W) ->
[$#, ${, pp_map(Pairs, Col + 2, Ll, M, TInd, indent(2, Ind), LD, W + 1),
$}];
-pp({{record,[{Name,NLen} | L]}, _Len}, Col, Ll, M, TInd, Ind, LD, W) ->
+pp({{record,[{Name,NLen} | L]}, _Len, _, _}, Col, Ll, M, TInd, Ind, LD, W) ->
[Name, ${, pp_record(L, NLen, Col, Ll, M, TInd, Ind, LD, W + NLen+1), $}];
-pp({{bin,S}, _Len}, Col, Ll, M, _TInd, Ind, LD, W) ->
+pp({{bin,S}, _Len, _, _}, Col, Ll, M, _TInd, Ind, LD, W) ->
pp_binary(S, Col + 2, Ll, M, indent(2, Ind), LD, W);
-pp({S, _Len}, _Col, _Ll, _M, _TInd, _Ind, _LD, _W) ->
+pp({S,_Len,_,_}, _Col, _Ll, _M, _TInd, _Ind, _LD, _W) ->
S.
%% Print a tagged tuple by indenting the rest of the elements
%% differently to the tag. Tuple has size >= 2.
-pp_tag_tuple([{Tag,Tlen} | L], Col, Ll, M, TInd, Ind, LD, W) ->
+pp_tag_tuple([{Tag,Tlen,_,_} | L], Col, Ll, M, TInd, Ind, LD, W) ->
%% this uses TInd
TagInd = Tlen + 2,
Tcol = Col + TagInd,
@@ -184,18 +201,18 @@ pp_tag_tuple([{Tag,Tlen} | L], Col, Ll, M, TInd, Ind, LD, W) ->
end.
pp_map([], _Col, _Ll, _M, _TInd, _Ind, _LD, _W) ->
- "";
-pp_map({dots, _}, _Col, _Ll, _M, _TInd, _Ind, _LD, _W) ->
- "...";
+ ""; % cannot happen
+pp_map({dots, _, _, _}, _Col, _Ll, _M, _TInd, _Ind, _LD, _W) ->
+ "..."; % cannot happen
pp_map([P | Ps], Col, Ll, M, TInd, Ind, LD, W) ->
{PS, PW} = pp_pair(P, Col, Ll, M, TInd, Ind, last_depth(Ps, LD), W),
[PS | pp_pairs_tail(Ps, Col, Col + PW, Ll, M, TInd, Ind, LD, PW)].
pp_pairs_tail([], _Col0, _Col, _Ll, _M, _TInd, _Ind, _LD, _W) ->
"";
-pp_pairs_tail({dots, _}, _Col0, _Col, _M, _Ll, _TInd, _Ind, _LD, _W) ->
+pp_pairs_tail({dots, _, _, _}, _Col0, _Col, _M, _Ll, _TInd, _Ind, _LD, _W) ->
",...";
-pp_pairs_tail([{_, Len}=P | Ps], Col0, Col, Ll, M, TInd, Ind, LD, W) ->
+pp_pairs_tail([{_, Len, _, _}=P | Ps], Col0, Col, Ll, M, TInd, Ind, LD, W) ->
LD1 = last_depth(Ps, LD),
ELen = 1 + Len,
if
@@ -209,7 +226,7 @@ pp_pairs_tail([{_, Len}=P | Ps], Col0, Col, Ll, M, TInd, Ind, LD, W) ->
pp_pairs_tail(Ps, Col0, Col0 + PW, Ll, M, TInd, Ind, LD, PW)]
end.
-pp_pair({_, Len}=Pair, Col, Ll, M, _TInd, _Ind, LD, W)
+pp_pair({_, Len, _, _}=Pair, Col, Ll, M, _TInd, _Ind, LD, W)
when Len < Ll - Col - LD, Len + W + LD =< M ->
{write_pair(Pair), if
?ATM_PAIR(Pair) ->
@@ -217,7 +234,7 @@ pp_pair({_, Len}=Pair, Col, Ll, M, _TInd, _Ind, LD, W)
true ->
Ll % force nl
end};
-pp_pair({{map_pair, K, V}, _Len}, Col0, Ll, M, TInd, Ind0, LD, W) ->
+pp_pair({{map_pair, K, V}, _Len, _, _}, Col0, Ll, M, TInd, Ind0, LD, W) ->
I = map_value_indent(TInd),
Ind = indent(I, Ind0),
{[pp(K, Col0, Ll, M, TInd, Ind0, LD, W), " =>\n",
@@ -225,7 +242,7 @@ pp_pair({{map_pair, K, V}, _Len}, Col0, Ll, M, TInd, Ind0, LD, W) ->
pp_record([], _Nlen, _Col, _Ll, _M, _TInd, _Ind, _LD, _W) ->
"";
-pp_record({dots, _}, _Nlen, _Col, _Ll, _M, _TInd, _Ind, _LD, _W) ->
+pp_record({dots, _, _, _}, _Nlen, _Col, _Ll, _M, _TInd, _Ind, _LD, _W) ->
"...";
pp_record([F | Fs], Nlen, Col0, Ll, M, TInd, Ind0, LD, W0) ->
Nind = Nlen + 1,
@@ -235,9 +252,9 @@ pp_record([F | Fs], Nlen, Col0, Ll, M, TInd, Ind0, LD, W0) ->
pp_fields_tail([], _Col0, _Col, _Ll, _M, _TInd, _Ind, _LD, _W) ->
"";
-pp_fields_tail({dots, _}, _Col0, _Col, _M, _Ll, _TInd, _Ind, _LD, _W) ->
+pp_fields_tail({dots, _, _ ,_}, _Col0, _Col, _M, _Ll, _TInd, _Ind, _LD, _W) ->
",...";
-pp_fields_tail([{_, Len}=F | Fs], Col0, Col, Ll, M, TInd, Ind, LD, W) ->
+pp_fields_tail([{_, Len, _, _}=F | Fs], Col0, Col, Ll, M, TInd, Ind, LD, W) ->
LD1 = last_depth(Fs, LD),
ELen = 1 + Len,
if
@@ -251,7 +268,7 @@ pp_fields_tail([{_, Len}=F | Fs], Col0, Col, Ll, M, TInd, Ind, LD, W) ->
pp_fields_tail(Fs, Col0, Col0 + FW, Ll, M, TInd, Ind, LD, FW)]
end.
-pp_field({_, Len}=Fl, Col, Ll, M, _TInd, _Ind, LD, W)
+pp_field({_, Len, _, _}=Fl, Col, Ll, M, _TInd, _Ind, LD, W)
when Len < Ll - Col - LD, Len + W + LD =< M ->
{write_field(Fl), if
?ATM_FLD(Fl) ->
@@ -259,7 +276,7 @@ pp_field({_, Len}=Fl, Col, Ll, M, _TInd, _Ind, LD, W)
true ->
Ll % force nl
end};
-pp_field({{field, Name, NameL, F}, _Len}, Col0, Ll, M, TInd, Ind0, LD, W0) ->
+pp_field({{field, Name, NameL, F},_,_, _}, Col0, Ll, M, TInd, Ind0, LD, W0) ->
{Col, Ind, S, W} = rec_indent(NameL, TInd, Col0, Ind0, W0 + NameL),
Sep = case S of
[$\n | _] -> " =";
@@ -286,15 +303,15 @@ rec_indent(RInd, TInd, Col0, Ind0, W0) ->
end,
{Col, Ind, S, W}.
-pp_list({dots, _}, _Col0, _Ll, _M, _TInd, _Ind, _LD, _S, _W) ->
+pp_list({dots, _, _, _}, _Col0, _Ll, _M, _TInd, _Ind, _LD, _S, _W) ->
"...";
pp_list([E | Es], Col0, Ll, M, TInd, Ind, LD, S, W) ->
{ES, WE} = pp_element(E, Col0, Ll, M, TInd, Ind, last_depth(Es, LD), W),
[ES | pp_tail(Es, Col0, Col0 + WE, Ll, M, TInd, Ind, LD, S, W + WE)].
pp_tail([], _Col0, _Col, _Ll, _M, _TInd, _Ind, _LD, _S, _W) ->
- "";
-pp_tail([{_, Len}=E | Es], Col0, Col, Ll, M, TInd, Ind, LD, S, W) ->
+ [];
+pp_tail([{_, Len, _, _}=E | Es], Col0, Col, Ll, M, TInd, Ind, LD, S, W) ->
LD1 = last_depth(Es, LD),
ELen = 1 + Len,
if
@@ -307,9 +324,9 @@ pp_tail([{_, Len}=E | Es], Col0, Col, Ll, M, TInd, Ind, LD, S, W) ->
[$,, $\n, Ind, ES |
pp_tail(Es, Col0, Col0 + WE, Ll, M, TInd, Ind, LD, S, WE)]
end;
-pp_tail({dots, _}, _Col0, _Col, _Ll, _M, _TInd, _Ind, _LD, S, _W) ->
+pp_tail({dots, _, _, _}, _Col0, _Col, _Ll, _M, _TInd, _Ind, _LD, S, _W) ->
[S | "..."];
-pp_tail({_, Len}=E, _Col0, Col, Ll, M, _TInd, _Ind, LD, S, W)
+pp_tail({_, Len, _, _}=E, _Col0, Col, Ll, M, _TInd, _Ind, LD, S, W)
when Len + 1 < Ll - Col - (LD + 1),
Len + 1 + W + (LD + 1) =< M,
?ATM(E) ->
@@ -317,7 +334,7 @@ pp_tail({_, Len}=E, _Col0, Col, Ll, M, _TInd, _Ind, LD, S, W)
pp_tail(E, Col0, _Col, Ll, M, TInd, Ind, LD, S, _W) ->
[S, $\n, Ind | pp(E, Col0, Ll, M, TInd, Ind, LD + 1, 0)].
-pp_element({_, Len}=E, Col, Ll, M, _TInd, _Ind, LD, W)
+pp_element({_, Len, _, _}=E, Col, Ll, M, _TInd, _Ind, LD, W)
when Len < Ll - Col - LD, Len + W + LD =< M, ?ATM(E) ->
{write(E), Len};
pp_element(E, Col, Ll, M, TInd, Ind, LD, W) ->
@@ -348,42 +365,42 @@ pp_binary(S, N, _N0, Ind) ->
end.
%% write the whole thing on a single line
-write({{tuple, _IsTagged, L}, _}) ->
+write({{tuple, _IsTagged, L}, _, _, _}) ->
[${, write_list(L, $,), $}];
-write({{list, L}, _}) ->
+write({{list, L}, _, _, _}) ->
[$[, write_list(L, $|), $]];
-write({{map, Pairs}, _}) ->
+write({{map, Pairs}, _, _, _}) ->
[$#,${, write_list(Pairs, $,), $}];
-write({{map_pair, _K, _V}, _}=Pair) ->
+write({{map_pair, _K, _V}, _, _, _}=Pair) ->
write_pair(Pair);
-write({{record, [{Name,_} | L]}, _}) ->
+write({{record, [{Name,_} | L]}, _, _, _}) ->
[Name, ${, write_fields(L), $}];
-write({{bin, S}, _}) ->
+write({{bin, S}, _, _, _}) ->
S;
-write({S, _}) ->
+write({S, _, _, _}) ->
S.
-write_pair({{map_pair, K, V}, _}) ->
+write_pair({{map_pair, K, V}, _, _, _}) ->
[write(K), " => ", write(V)].
write_fields([]) ->
"";
-write_fields({dots, _}) ->
+write_fields({dots, _, _, _}) ->
"...";
write_fields([F | Fs]) ->
[write_field(F) | write_fields_tail(Fs)].
write_fields_tail([]) ->
"";
-write_fields_tail({dots, _}) ->
+write_fields_tail({dots, _, _, _}) ->
",...";
write_fields_tail([F | Fs]) ->
[$,, write_field(F) | write_fields_tail(Fs)].
-write_field({{field, Name, _NameL, F}, _}) ->
+write_field({{field, Name, _NameL, F}, _, _, _}) ->
[Name, " = " | write(F)].
-write_list({dots, _}, _S) ->
+write_list({dots, _, _, _}, _S) ->
"...";
write_list([E | Es], S) ->
[write(E) | write_tail(Es, S)].
@@ -392,182 +409,376 @@ write_tail([], _S) ->
[];
write_tail([E | Es], S) ->
[$,, write(E) | write_tail(Es, S)];
-write_tail({dots, _}, S) ->
+write_tail({dots, _, _, _}, S) ->
[S | "..."];
write_tail(E, S) ->
[S | write(E)].
+-type more() :: fun((chars_limit(), DeltaDepth :: non_neg_integer()) ->
+ intermediate_format()).
+
+-type if_list() :: maybe_improper_list(intermediate_format(),
+ {'dots', non_neg_integer(),
+ non_neg_integer(), more()}).
+
+-type intermediate_format() ::
+ {chars()
+ | {'bin', chars()}
+ | 'dots'
+ | {'field', Name :: chars(), NameLen :: non_neg_integer(),
+ intermediate_format()}
+ | {'list', if_list()}
+ | {'map', if_list()}
+ | {'map_pair', K :: intermediate_format(),
+ V :: intermediate_format()}
+ | {'record', [{Name :: chars(), NameLen :: non_neg_integer()}
+ | if_list()]}
+ | {'tuple', IsTagged :: boolean(), if_list()},
+ Len :: non_neg_integer(),
+ NumOfDots :: non_neg_integer(),
+ More :: more() | 'no_more'
+ }.
+
+-spec intermediate(term(), depth(), pos_integer(), rec_print_fun(),
+ encoding(), boolean()) -> intermediate_format().
+
+intermediate(Term, D, T, RF, Enc, Str) when T > 0 ->
+ D0 = 1,
+ If = print_length(Term, D0, T, RF, Enc, Str),
+ case If of
+ {_, Len, Dots, _} when Dots =:= 0; Len > T; D =:= 1 ->
+ If;
+ _ ->
+ find_upper(If, Term, T, D0, 2, D, RF, Enc, Str)
+ end.
+
+find_upper(Lower, Term, T, Dl, Dd, D, RF, Enc, Str) ->
+ Dd2 = Dd * 2,
+ D1 = case D < 0 of
+ true -> Dl + Dd2;
+ false -> min(Dl + Dd2, D)
+ end,
+ If = expand(Lower, T, D1 - Dl),
+ case If of
+ {_, _, _Dots=0, _} -> % even if Len > T
+ If;
+ {_, Len, _, _} when Len =< T, D1 < D orelse D < 0 ->
+ find_upper(If, Term, T, D1, Dd2, D, RF, Enc, Str);
+ _ ->
+ search_depth(Lower, If, Term, T, Dl, D1, RF, Enc, Str)
+ end.
+
+%% Lower has NumOfDots > 0 and Len =< T.
+%% Upper has NumOfDots > 0 and Len > T.
+search_depth(Lower, Upper, _Term, T, Dl, Du, _RF, _Enc, _Str)
+ when Du - Dl =:= 1 ->
+ %% The returned intermediate format has Len >= T.
+ case Lower of
+ {_, T, _, _} ->
+ Lower;
+ _ ->
+ Upper
+ end;
+search_depth(Lower, Upper, Term, T, Dl, Du, RF, Enc, Str) ->
+ D1 = (Dl + Du) div 2,
+ If = expand(Lower, T, D1 - Dl),
+ case If of
+ {_, Len, _, _} when Len > T ->
+ %% Len can be greater than Upper's length.
+ %% This is a bit expensive since the work to
+ %% crate Upper is wasted. It is the price
+ %% to pay to get a more balanced output.
+ search_depth(Lower, If, Term, T, Dl, D1, RF, Enc, Str);
+ _ ->
+ search_depth(If, Upper, Term, T, D1, Du, RF, Enc, Str)
+ end.
+
%% The depth (D) is used for extracting and counting the characters to
%% print. The structure is kept so that the returned intermediate
%% format can be formatted. The separators (list, tuple, record, map) are
%% counted but need to be added later.
%% D =/= 0
-print_length([], _D, _RF, _Enc, _Str) ->
- {"[]", 2};
-print_length({}, _D, _RF, _Enc, _Str) ->
- {"{}", 2};
-print_length(#{}=M, _D, _RF, _Enc, _Str) when map_size(M) =:= 0 ->
- {"#{}", 3};
-print_length(Atom, _D, _RF, Enc, _Str) when is_atom(Atom) ->
+print_length([], _D, _T, _RF, _Enc, _Str) ->
+ {"[]", 2, 0, no_more};
+print_length({}, _D, _T, _RF, _Enc, _Str) ->
+ {"{}", 2, 0, no_more};
+print_length(#{}=M, _D, _T, _RF, _Enc, _Str) when map_size(M) =:= 0 ->
+ {"#{}", 3, 0, no_more};
+print_length(Atom, _D, _T, _RF, Enc, _Str) when is_atom(Atom) ->
S = write_atom(Atom, Enc),
- {S, lists:flatlength(S)};
-print_length(List, D, RF, Enc, Str) when is_list(List) ->
+ {S, io_lib:chars_length(S), 0, no_more};
+print_length(List, D, T, RF, Enc, Str) when is_list(List) ->
%% only flat lists are "printable"
- case Str andalso printable_list(List, D, Enc) of
+ case Str andalso printable_list(List, D, T, Enc) of
true ->
%% print as string, escaping double-quotes in the list
S = write_string(List, Enc),
- {S, length(S)};
- %% Truncated lists could break some existing code.
- % {true, Prefix} ->
- % S = write_string(Prefix, Enc),
- % {[S | "..."], 3 + length(S)};
+ {S, io_lib:chars_length(S), 0, no_more};
+ {true, Prefix} ->
+ %% Truncated lists when T < 0 could break some existing code.
+ S = write_string(Prefix, Enc),
+ %% NumOfDots = 0 to avoid looping--increasing the depth
+ %% does not make Prefix longer.
+ {[S | "..."], 3 + io_lib:chars_length(S), 0, no_more};
false ->
- print_length_list(List, D, RF, Enc, Str)
+ case print_length_list(List, D, T, RF, Enc, Str) of
+ {What, Len, Dots, _More} when Dots > 0 ->
+ More = fun(T1, Dd) ->
+ ?FUNCTION_NAME(List, D+Dd, T1, RF, Enc, Str)
+ end,
+ {What, Len, Dots, More};
+ If ->
+ If
+ end
end;
-print_length(Fun, _D, _RF, _Enc, _Str) when is_function(Fun) ->
+print_length(Fun, _D, _T, _RF, _Enc, _Str) when is_function(Fun) ->
S = io_lib:write(Fun),
- {S, iolist_size(S)};
-print_length(R, D, RF, Enc, Str) when is_atom(element(1, R)),
- is_function(RF) ->
+ {S, iolist_size(S), 0, no_more};
+print_length(R, D, T, RF, Enc, Str) when is_atom(element(1, R)),
+ is_function(RF) ->
case RF(element(1, R), tuple_size(R) - 1) of
no ->
- print_length_tuple(R, D, RF, Enc, Str);
+ print_length_tuple(R, D, T, RF, Enc, Str);
RDefs ->
- print_length_record(R, D, RF, RDefs, Enc, Str)
+ print_length_record(R, D, T, RF, RDefs, Enc, Str)
end;
-print_length(Tuple, D, RF, Enc, Str) when is_tuple(Tuple) ->
- print_length_tuple(Tuple, D, RF, Enc, Str);
-print_length(Map, D, RF, Enc, Str) when is_map(Map) ->
- print_length_map(Map, D, RF, Enc, Str);
-print_length(<<>>, _D, _RF, _Enc, _Str) ->
- {"<<>>", 4};
-print_length(<<_/bitstring>>, 1, _RF, _Enc, _Str) ->
- {"<<...>>", 7};
-print_length(<<_/bitstring>>=Bin, D, _RF, Enc, Str) ->
- case bit_size(Bin) rem 8 of
- 0 ->
- D1 = D - 1,
- case Str andalso printable_bin(Bin, D1, Enc) of
- {true, List} when is_list(List) ->
- S = io_lib:write_string(List, $"), %"
- {[$<,$<,S,$>,$>], 4 + length(S)};
- {false, List} when is_list(List) ->
- S = io_lib:write_string(List, $"), %"
- {[$<,$<,S,"/utf8>>"], 9 + length(S)};
- {true, true, Prefix} ->
- S = io_lib:write_string(Prefix, $"), %"
- {[$<,$<, S | "...>>"], 7 + length(S)};
- {false, true, Prefix} ->
- S = io_lib:write_string(Prefix, $"), %"
- {[$<,$<, S | "/utf8...>>"], 12 + length(S)};
- false ->
- S = io_lib:write(Bin, D),
- {{bin,S}, iolist_size(S)}
- end;
- _ ->
- S = io_lib:write(Bin, D),
- {{bin,S}, iolist_size(S)}
+print_length(Tuple, D, T, RF, Enc, Str) when is_tuple(Tuple) ->
+ print_length_tuple(Tuple, D, T, RF, Enc, Str);
+print_length(Map, D, T, RF, Enc, Str) when is_map(Map) ->
+ print_length_map(Map, D, T, RF, Enc, Str);
+print_length(<<>>, _D, _T, _RF, _Enc, _Str) ->
+ {"<<>>", 4, 0, no_more};
+print_length(<<_/bitstring>> = Bin, 1, _T, RF, Enc, Str) ->
+ More = fun(T1, Dd) -> ?FUNCTION_NAME(Bin, 1+Dd, T1, RF, Enc, Str) end,
+ {"<<...>>", 7, 3, More};
+print_length(<<_/bitstring>> = Bin, D, T, RF, Enc, Str) ->
+ D1 = D - 1,
+ case
+ Str andalso
+ (bit_size(Bin) rem 8) =:= 0 andalso
+ printable_bin0(Bin, D1, tsub(T, 6), Enc)
+ of
+ {true, List} when is_list(List) ->
+ S = io_lib:write_string(List, $"), %"
+ {[$<,$<,S,$>,$>], 4 + length(S), 0, no_more};
+ {false, List} when is_list(List) ->
+ S = io_lib:write_string(List, $"), %"
+ {[$<,$<,S,"/utf8>>"], 9 + io_lib:chars_length(S), 0, no_more};
+ {true, true, Prefix} ->
+ S = io_lib:write_string(Prefix, $"), %"
+ More = fun(T1, Dd) ->
+ ?FUNCTION_NAME(Bin, D+Dd, T1, RF, Enc, Str)
+ end,
+ {[$<,$<,S|"...>>"], 7 + length(S), 3, More};
+ {false, true, Prefix} ->
+ S = io_lib:write_string(Prefix, $"), %"
+ More = fun(T1, Dd) ->
+ ?FUNCTION_NAME(Bin, D+Dd, T1, RF, Enc, Str)
+ end,
+ {[$<,$<,S|"/utf8...>>"], 12 + io_lib:chars_length(S), 3, More};
+ false ->
+ case io_lib:write_binary(Bin, D, T) of
+ {S, <<>>} ->
+ {{bin, S}, iolist_size(S), 0, no_more};
+ {S, _Rest} ->
+ More = fun(T1, Dd) ->
+ ?FUNCTION_NAME(Bin, D+Dd, T1, RF, Enc, Str)
+ end,
+ {{bin, S}, iolist_size(S), 3, More}
+ end
end;
-print_length(Term, _D, _RF, _Enc, _Str) ->
+print_length(Term, _D, _T, _RF, _Enc, _Str) ->
S = io_lib:write(Term),
%% S can contain unicode, so iolist_size(S) cannot be used here
- {S, string:length(S)}.
-
-print_length_map(_Map, 1, _RF, _Enc, _Str) ->
- {"#{...}", 6};
-print_length_map(Map, D, RF, Enc, Str) when is_map(Map) ->
- Pairs = print_length_map_pairs(erts_internal:maps_to_list(Map, D), D, RF, Enc, Str),
- {{map, Pairs}, list_length(Pairs, 3)}.
-
-print_length_map_pairs([], _D, _RF, _Enc, _Str) ->
+ {S, io_lib:chars_length(S), 0, no_more}.
+
+print_length_map(Map, 1, _T, RF, Enc, Str) ->
+ More = fun(T1, Dd) -> ?FUNCTION_NAME(Map, 1+Dd, T1, RF, Enc, Str) end,
+ {"#{...}", 6, 3, More};
+print_length_map(Map, D, T, RF, Enc, Str) when is_map(Map) ->
+ Next = maps:next(maps:iterator(Map)),
+ PairsS = print_length_map_pairs(Next, D, D - 1, tsub(T, 3), RF, Enc, Str),
+ {Len, Dots} = list_length(PairsS, 3, 0),
+ {{map, PairsS}, Len, Dots, no_more}.
+
+print_length_map_pairs(none, _D, _D0, _T, _RF, _Enc, _Str) ->
[];
-print_length_map_pairs(_Pairs, 1, _RF, _Enc, _Str) ->
- {dots, 3};
-print_length_map_pairs([{K, V} | Pairs], D, RF, Enc, Str) ->
- [print_length_map_pair(K, V, D - 1, RF, Enc, Str) |
- print_length_map_pairs(Pairs, D - 1, RF, Enc, Str)].
-
-print_length_map_pair(K, V, D, RF, Enc, Str) ->
- {KS, KL} = print_length(K, D, RF, Enc, Str),
- {VS, VL} = print_length(V, D, RF, Enc, Str),
+print_length_map_pairs(Term, D, D0, T, RF, Enc, Str) when D =:= 1; T =:= 0->
+ More = fun(T1, Dd) ->
+ ?FUNCTION_NAME(Term, D+Dd, D0, T1, RF, Enc, Str)
+ end,
+ {dots, 3, 3, More};
+print_length_map_pairs({K, V, Iter}, D, D0, T, RF, Enc, Str) ->
+ Pair1 = print_length_map_pair(K, V, D0, tsub(T, 1), RF, Enc, Str),
+ {_, Len1, _, _} = Pair1,
+ Next = maps:next(Iter),
+ [Pair1 |
+ print_length_map_pairs(Next, D - 1, D0, tsub(T, Len1+1), RF, Enc, Str)].
+
+print_length_map_pair(K, V, D, T, RF, Enc, Str) ->
+ {_, KL, KD, _} = P1 = print_length(K, D, T, RF, Enc, Str),
KL1 = KL + 4,
- {{map_pair, {KS, KL1}, {VS, VL}}, KL1 + VL}.
-
-print_length_tuple(_Tuple, 1, _RF, _Enc, _Str) ->
- {"{...}", 5};
-print_length_tuple(Tuple, D, RF, Enc, Str) ->
- L = print_length_list1(tuple_to_list(Tuple), D, RF, Enc, Str),
+ {_, VL, VD, _} = P2 = print_length(V, D, tsub(T, KL1), RF, Enc, Str),
+ {{map_pair, P1, P2}, KL1 + VL, KD + VD, no_more}.
+
+print_length_tuple(Tuple, 1, _T, RF, Enc, Str) ->
+ More = fun(T1, Dd) -> ?FUNCTION_NAME(Tuple, 1+Dd, T1, RF, Enc, Str) end,
+ {"{...}", 5, 3, More};
+print_length_tuple(Tuple, D, T, RF, Enc, Str) ->
+ L = print_length_tuple1(Tuple, 1, D, tsub(T, 2), RF, Enc, Str),
IsTagged = is_atom(element(1, Tuple)) and (tuple_size(Tuple) > 1),
- {{tuple,IsTagged,L}, list_length(L, 2)}.
+ {Len, Dots} = list_length(L, 2, 0),
+ {{tuple,IsTagged,L}, Len, Dots, no_more}.
-print_length_record(_Tuple, 1, _RF, _RDefs, _Enc, _Str) ->
- {"{...}", 5};
-print_length_record(Tuple, D, RF, RDefs, Enc, Str) ->
+print_length_tuple1(Tuple, I, _D, _T, _RF, _Enc, _Str)
+ when I > tuple_size(Tuple) ->
+ [];
+print_length_tuple1(Tuple, I, D, T, RF, Enc, Str) when D =:= 1; T =:= 0->
+ More = fun(T1, Dd) -> ?FUNCTION_NAME(Tuple, I, D+Dd, T1, RF, Enc, Str) end,
+ {dots, 3, 3, More};
+print_length_tuple1(Tuple, I, D, T, RF, Enc, Str) ->
+ E = element(I, Tuple),
+ T1 = tsub(T, 1),
+ {_, Len1, _, _} = Elem1 = print_length(E, D - 1, T1, RF, Enc, Str),
+ T2 = tsub(T1, Len1),
+ [Elem1 | print_length_tuple1(Tuple, I + 1, D - 1, T2, RF, Enc, Str)].
+
+print_length_record(Tuple, 1, _T, RF, RDefs, Enc, Str) ->
+ More = fun(T1, Dd) ->
+ ?FUNCTION_NAME(Tuple, 1+Dd, T1, RF, RDefs, Enc, Str)
+ end,
+ {"{...}", 5, 3, More};
+print_length_record(Tuple, D, T, RF, RDefs, Enc, Str) ->
Name = [$# | write_atom(element(1, Tuple), Enc)],
- NameL = length(Name),
- Elements = tl(tuple_to_list(Tuple)),
- L = print_length_fields(RDefs, D - 1, Elements, RF, Enc, Str),
- {{record, [{Name,NameL} | L]}, list_length(L, NameL + 2)}.
-
-print_length_fields([], _D, [], _RF, _Enc, _Str) ->
+ NameL = io_lib:chars_length(Name),
+ T1 = tsub(T, NameL+2),
+ L = print_length_fields(RDefs, D - 1, T1, Tuple, 2, RF, Enc, Str),
+ {Len, Dots} = list_length(L, NameL + 2, 0),
+ {{record, [{Name,NameL} | L]}, Len, Dots, no_more}.
+
+print_length_fields([], _D, _T, Tuple, I, _RF, _Enc, _Str)
+ when I > tuple_size(Tuple) ->
[];
-print_length_fields(_, 1, _, _RF, _Enc, _Str) ->
- {dots, 3};
-print_length_fields([Def | Defs], D, [E | Es], RF, Enc, Str) ->
- [print_length_field(Def, D - 1, E, RF, Enc, Str) |
- print_length_fields(Defs, D - 1, Es, RF, Enc, Str)].
-
-print_length_field(Def, D, E, RF, Enc, Str) ->
+print_length_fields(Term, D, T, Tuple, I, RF, Enc, Str)
+ when D =:= 1; T =:= 0 ->
+ More = fun(T1, Dd) ->
+ ?FUNCTION_NAME(Term, D+Dd, T1, Tuple, I, RF, Enc, Str)
+ end,
+ {dots, 3, 3, More};
+print_length_fields([Def | Defs], D, T, Tuple, I, RF, Enc, Str) ->
+ E = element(I, Tuple),
+ T1 = tsub(T, 1),
+ Field1 = print_length_field(Def, D - 1, T1, E, RF, Enc, Str),
+ {_, Len1, _, _} = Field1,
+ T2 = tsub(T1, Len1),
+ [Field1 |
+ print_length_fields(Defs, D - 1, T2, Tuple, I + 1, RF, Enc, Str)].
+
+print_length_field(Def, D, T, E, RF, Enc, Str) ->
Name = write_atom(Def, Enc),
- {S, L} = print_length(E, D, RF, Enc, Str),
- NameL = length(Name) + 3,
- {{field, Name, NameL, {S, L}}, NameL + L}.
+ NameL = io_lib:chars_length(Name) + 3,
+ {_, Len, Dots, _} =
+ Field = print_length(E, D, tsub(T, NameL), RF, Enc, Str),
+ {{field, Name, NameL, Field}, NameL + Len, Dots, no_more}.
-print_length_list(List, D, RF, Enc, Str) ->
- L = print_length_list1(List, D, RF, Enc, Str),
- {{list, L}, list_length(L, 2)}.
+print_length_list(List, D, T, RF, Enc, Str) ->
+ L = print_length_list1(List, D, tsub(T, 2), RF, Enc, Str),
+ {Len, Dots} = list_length(L, 2, 0),
+ {{list, L}, Len, Dots, no_more}.
-print_length_list1([], _D, _RF, _Enc, _Str) ->
+print_length_list1([], _D, _T, _RF, _Enc, _Str) ->
[];
-print_length_list1(_, 1, _RF, _Enc, _Str) ->
- {dots, 3};
-print_length_list1([E | Es], D, RF, Enc, Str) ->
- [print_length(E, D - 1, RF, Enc, Str) |
- print_length_list1(Es, D - 1, RF, Enc, Str)];
-print_length_list1(E, D, RF, Enc, Str) ->
- print_length(E, D - 1, RF, Enc, Str).
-
-list_length([], Acc) ->
- Acc;
-list_length([{_, Len} | Es], Acc) ->
- list_length_tail(Es, Acc + Len);
-list_length({_, Len}, Acc) ->
- Acc + Len.
-
-list_length_tail([], Acc) ->
- Acc;
-list_length_tail([{_,Len} | Es], Acc) ->
- list_length_tail(Es, Acc + 1 + Len);
-list_length_tail({_, Len}, Acc) ->
- Acc + 1 + Len.
+print_length_list1(Term, D, T, RF, Enc, Str) when D =:= 1; T =:= 0->
+ More = fun(T1, Dd) -> ?FUNCTION_NAME(Term, D+Dd, T1, RF, Enc, Str) end,
+ {dots, 3, 3, More};
+print_length_list1([E | Es], D, T, RF, Enc, Str) ->
+ {_, Len1, _, _} = Elem1 = print_length(E, D - 1, tsub(T, 1), RF, Enc, Str),
+ [Elem1 | print_length_list1(Es, D - 1, tsub(T, Len1 + 1), RF, Enc, Str)];
+print_length_list1(E, D, T, RF, Enc, Str) ->
+ print_length(E, D - 1, T, RF, Enc, Str).
+
+list_length([], Acc, DotsAcc) ->
+ {Acc, DotsAcc};
+list_length([{_, Len, Dots, _} | Es], Acc, DotsAcc) ->
+ list_length_tail(Es, Acc + Len, DotsAcc + Dots);
+list_length({_, Len, Dots, _}, Acc, DotsAcc) ->
+ {Acc + Len, DotsAcc + Dots}.
+
+list_length_tail([], Acc, DotsAcc) ->
+ {Acc, DotsAcc};
+list_length_tail([{_, Len, Dots, _} | Es], Acc, DotsAcc) ->
+ list_length_tail(Es, Acc + 1 + Len, DotsAcc + Dots);
+list_length_tail({_, Len, Dots, _}, Acc, DotsAcc) ->
+ {Acc + 1 + Len, DotsAcc + Dots}.
%% ?CHARS printable characters has depth 1.
-define(CHARS, 4).
%% only flat lists are "printable"
-printable_list(_L, 1, _Enc) ->
+printable_list(_L, 1, _T, _Enc) ->
false;
-printable_list(L, _D, latin1) ->
+printable_list(L, _D, T, latin1) when T < 0 ->
io_lib:printable_latin1_list(L);
-printable_list(L, _D, _Uni) ->
+printable_list(L, _D, T, latin1) when T >= 0 ->
+ N = tsub(T, 2),
+ case printable_latin1_list(L, N) of
+ all ->
+ true;
+ 0 ->
+ {L1, _} = lists:split(N, L),
+ {true, L1};
+ _NC ->
+ false
+ end;
+printable_list(L, _D, T, _Unicode) when T >= 0 ->
+ N = tsub(T, 2),
+ %% Be careful not to traverse more of L than necessary.
+ try string:slice(L, 0, N) of
+ "" ->
+ false;
+ Prefix ->
+ case is_flat(L, lists:flatlength(Prefix)) of
+ true ->
+ case string:equal(Prefix, L) of
+ true ->
+ io_lib:printable_list(L);
+ false ->
+ io_lib:printable_list(Prefix)
+ andalso {true, Prefix}
+ end;
+ false ->
+ false
+ end
+ catch _:_ -> false
+ end;
+printable_list(L, _D, T, _Uni) when T < 0->
io_lib:printable_list(L).
-printable_bin(Bin, D, Enc) when D >= 0, ?CHARS * D =< byte_size(Bin) ->
- printable_bin(Bin, erlang:min(?CHARS * D, byte_size(Bin)), D, Enc);
-printable_bin(Bin, D, Enc) ->
- printable_bin(Bin, byte_size(Bin), D, Enc).
+is_flat(_L, 0) ->
+ true;
+is_flat([C|Cs], N) when is_integer(C) ->
+ is_flat(Cs, N - 1);
+is_flat(_, _N) ->
+ false.
+
+printable_bin0(Bin, D, T, Enc) ->
+ Len = case D >= 0 of
+ true ->
+ %% Use byte_size() also if Enc =/= latin1.
+ DChars = erlang:min(?CHARS * D, byte_size(Bin)),
+ case T >= 0 of
+ true ->
+ erlang:min(T, DChars);
+ false ->
+ DChars
+ end;
+ false when T < 0 ->
+ byte_size(Bin);
+ false when T >= 0 -> % cannot happen
+ T
+ end,
+ printable_bin(Bin, Len, D, Enc).
printable_bin(Bin, Len, D, latin1) ->
N = erlang:min(20, Len),
@@ -619,7 +830,7 @@ printable_bin1(Bin, Start, Len) ->
end.
%% -> all | integer() >=0. Adopted from io_lib.erl.
-% printable_latin1_list([_ | _], 0) -> 0;
+printable_latin1_list([_ | _], 0) -> 0;
printable_latin1_list([C | Cs], N) when C >= $\s, C =< $~ ->
printable_latin1_list(Cs, N - 1);
printable_latin1_list([C | Cs], N) when C >= $\240, C =< $\377 ->
@@ -679,28 +890,70 @@ write_string(S, latin1) ->
write_string(S, _Uni) ->
io_lib:write_string(S, $"). %"
+expand({_, _, _Dots=0, no_more} = If, _T, _Dd) -> If;
+%% expand({{list,L}, _Len, _, no_more}, T, Dd) ->
+%% {NL, NLen, NDots} = expand_list(L, T, Dd, 2),
+%% {{list,NL}, NLen, NDots, no_more};
+expand({{tuple,IsTagged,L}, _Len, _, no_more}, T, Dd) ->
+ {NL, NLen, NDots} = expand_list(L, T, Dd, 2),
+ {{tuple,IsTagged,NL}, NLen, NDots, no_more};
+expand({{map, Pairs}, _Len, _, no_more}, T, Dd) ->
+ {NPairs, NLen, NDots} = expand_list(Pairs, T, Dd, 3),
+ {{map, NPairs}, NLen, NDots, no_more};
+expand({{map_pair, K, V}, _Len, _, no_more}, T, Dd) ->
+ {_, KL, KD, _} = P1 = expand(K, tsub(T, 1), Dd),
+ KL1 = KL + 4,
+ {_, VL, VD, _} = P2 = expand(V, tsub(T, KL1), Dd),
+ {{map_pair, P1, P2}, KL1 + VL, KD + VD, no_more};
+expand({{record, [{Name,NameL} | L]}, _Len, _, no_more}, T, Dd) ->
+ {NL, NLen, NDots} = expand_list(L, T, Dd, NameL + 2),
+ {{record, [{Name,NameL} | NL]}, NLen, NDots, no_more};
+expand({{field, Name, NameL, Field}, _Len, _, no_more}, T, Dd) ->
+ F = {_S, L, Dots, _} = expand(Field, tsub(T, NameL), Dd),
+ {{field, Name, NameL, F}, NameL + L, Dots, no_more};
+expand({_, _, _, More}, T, Dd) ->
+ More(T, Dd).
+
+expand_list(Ifs, T, Dd, L0) ->
+ L = expand_list(Ifs, tsub(T, L0), Dd),
+ {Len, Dots} = list_length(L, L0, 0),
+ {L, Len, Dots}.
+
+expand_list([], _T, _Dd) ->
+ [];
+expand_list([If | Ifs], T, Dd) ->
+ {_, Len1, _, _} = Elem1 = expand(If, tsub(T, 1), Dd),
+ [Elem1 | expand_list(Ifs, tsub(T, Len1 + 1), Dd)];
+expand_list({_, _, _, More}, T, Dd) ->
+ More(T, Dd).
+
+%% Make sure T does not change sign.
+tsub(T, _) when T < 0 -> T;
+tsub(T, E) when T >= E -> T - E;
+tsub(_, _) -> 0.
+
%% Throw 'no_good' if the indentation exceeds half the line length
%% unless there is room for M characters on the line.
-cind({_S, Len}, Col, Ll, M, Ind, LD, W) when Len < Ll - Col - LD,
- Len + W + LD =< M ->
+cind({_S, Len, _, _}, Col, Ll, M, Ind, LD, W) when Len < Ll - Col - LD,
+ Len + W + LD =< M ->
Ind;
-cind({{list,L}, _Len}, Col, Ll, M, Ind, LD, W) ->
+cind({{list,L}, _Len, _, _}, Col, Ll, M, Ind, LD, W) ->
cind_list(L, Col + 1, Ll, M, Ind, LD, W + 1);
-cind({{tuple,true,L}, _Len}, Col, Ll, M, Ind, LD, W) ->
+cind({{tuple,true,L}, _Len, _ ,_}, Col, Ll, M, Ind, LD, W) ->
cind_tag_tuple(L, Col, Ll, M, Ind, LD, W + 1);
-cind({{tuple,false,L}, _Len}, Col, Ll, M, Ind, LD, W) ->
+cind({{tuple,false,L}, _Len, _, _}, Col, Ll, M, Ind, LD, W) ->
cind_list(L, Col + 1, Ll, M, Ind, LD, W + 1);
-cind({{map,Pairs},_Len}, Col, Ll, M, Ind, LD, W) ->
+cind({{map,Pairs}, _Len, _, _}, Col, Ll, M, Ind, LD, W) ->
cind_map(Pairs, Col + 2, Ll, M, Ind, LD, W + 2);
-cind({{record,[{_Name,NLen} | L]}, _Len}, Col, Ll, M, Ind, LD, W) ->
+cind({{record,[{_Name,NLen} | L]}, _Len, _, _}, Col, Ll, M, Ind, LD, W) ->
cind_record(L, NLen, Col, Ll, M, Ind, LD, W + NLen + 1);
-cind({{bin,_S}, _Len}, _Col, _Ll, _M, Ind, _LD, _W) ->
+cind({{bin,_S}, _Len, _, _}, _Col, _Ll, _M, Ind, _LD, _W) ->
Ind;
-cind({_S, _Len}, _Col, _Ll, _M, Ind, _LD, _W) ->
+cind({_S,_Len,_,_}, _Col, _Ll, _M, Ind, _LD, _W) ->
Ind.
-cind_tag_tuple([{_Tag,Tlen} | L], Col, Ll, M, Ind, LD, W) ->
+cind_tag_tuple([{_Tag,Tlen,_,_} | L], Col, Ll, M, Ind, LD, W) ->
TagInd = Tlen + 2,
Tcol = Col + TagInd,
if
@@ -722,9 +975,9 @@ cind_map([P | Ps], Col, Ll, M, Ind, LD, W) ->
PW = cind_pair(P, Col, Ll, M, Ind, last_depth(Ps, LD), W),
cind_pairs_tail(Ps, Col, Col + PW, Ll, M, Ind, LD, W + PW);
cind_map(_, _Col, _Ll, _M, Ind, _LD, _W) ->
- Ind.
+ Ind. % cannot happen
-cind_pairs_tail([{_, Len}=P | Ps], Col0, Col, Ll, M, Ind, LD, W) ->
+cind_pairs_tail([{_, Len, _, _} = P | Ps], Col0, Col, Ll, M, Ind, LD, W) ->
LD1 = last_depth(Ps, LD),
ELen = 1 + Len,
if
@@ -738,7 +991,7 @@ cind_pairs_tail([{_, Len}=P | Ps], Col0, Col, Ll, M, Ind, LD, W) ->
cind_pairs_tail(_, _Col0, _Col, _Ll, _M, Ind, _LD, _W) ->
Ind.
-cind_pair({{map_pair, _Key, _Value}, Len}=Pair, Col, Ll, M, _Ind, LD, W)
+cind_pair({{map_pair, _Key, _Value}, Len, _, _}=Pair, Col, Ll, M, _Ind, LD, W)
when Len < Ll - Col - LD, Len + W + LD =< M ->
if
?ATM_PAIR(Pair) ->
@@ -746,7 +999,7 @@ cind_pair({{map_pair, _Key, _Value}, Len}=Pair, Col, Ll, M, _Ind, LD, W)
true ->
Ll
end;
-cind_pair({{map_pair, K, V}, _Len}, Col0, Ll, M, Ind, LD, W0) ->
+cind_pair({{map_pair, K, V}, _Len, _, _}, Col0, Ll, M, Ind, LD, W0) ->
cind(K, Col0, Ll, M, Ind, LD, W0),
I = map_value_indent(Ind),
cind(V, Col0 + I, Ll, M, Ind, LD, 0),
@@ -768,7 +1021,7 @@ cind_record([F | Fs], Nlen, Col0, Ll, M, Ind, LD, W0) ->
cind_record(_, _Nlen, _Col, _Ll, _M, Ind, _LD, _W) ->
Ind.
-cind_fields_tail([{_, Len}=F | Fs], Col0, Col, Ll, M, Ind, LD, W) ->
+cind_fields_tail([{_, Len, _, _} = F | Fs], Col0, Col, Ll, M, Ind, LD, W) ->
LD1 = last_depth(Fs, LD),
ELen = 1 + Len,
if
@@ -782,7 +1035,7 @@ cind_fields_tail([{_, Len}=F | Fs], Col0, Col, Ll, M, Ind, LD, W) ->
cind_fields_tail(_, _Col0, _Col, _Ll, _M, Ind, _LD, _W) ->
Ind.
-cind_field({{field, _N, _NL, _F}, Len}=Fl, Col, Ll, M, _Ind, LD, W)
+cind_field({{field, _N, _NL, _F}, Len, _, _}=Fl, Col, Ll, M, _Ind, LD, W)
when Len < Ll - Col - LD, Len + W + LD =< M ->
if
?ATM_FLD(Fl) ->
@@ -790,7 +1043,7 @@ cind_field({{field, _N, _NL, _F}, Len}=Fl, Col, Ll, M, _Ind, LD, W)
true ->
Ll
end;
-cind_field({{field, _Name, NameL, F}, _Len}, Col0, Ll, M, Ind, LD, W0) ->
+cind_field({{field, _Name, NameL, F},_Len,_,_}, Col0, Ll, M, Ind, LD, W0) ->
{Col, W} = cind_rec(NameL, Col0, Ll, M, Ind, W0 + NameL),
cind(F, Col, Ll, M, Ind, LD, W),
Ll.
@@ -813,7 +1066,7 @@ cind_rec(RInd, Col0, Ll, M, Ind, W0) ->
throw(no_good)
end.
-cind_list({dots, _}, _Col0, _Ll, _M, Ind, _LD, _W) ->
+cind_list({dots, _, _, _}, _Col0, _Ll, _M, Ind, _LD, _W) ->
Ind;
cind_list([E | Es], Col0, Ll, M, Ind, LD, W) ->
WE = cind_element(E, Col0, Ll, M, Ind, last_depth(Es, LD), W),
@@ -821,7 +1074,7 @@ cind_list([E | Es], Col0, Ll, M, Ind, LD, W) ->
cind_tail([], _Col0, _Col, _Ll, _M, Ind, _LD, _W) ->
Ind;
-cind_tail([{_, Len}=E | Es], Col0, Col, Ll, M, Ind, LD, W) ->
+cind_tail([{_, Len, _, _} = E | Es], Col0, Col, Ll, M, Ind, LD, W) ->
LD1 = last_depth(Es, LD),
ELen = 1 + Len,
if
@@ -832,9 +1085,9 @@ cind_tail([{_, Len}=E | Es], Col0, Col, Ll, M, Ind, LD, W) ->
WE = cind_element(E, Col0, Ll, M, Ind, LD1, 0),
cind_tail(Es, Col0, Col0 + WE, Ll, M, Ind, LD, WE)
end;
-cind_tail({dots, _}, _Col0, _Col, _Ll, _M, Ind, _LD, _W) ->
+cind_tail({dots, _, _, _}, _Col0, _Col, _Ll, _M, Ind, _LD, _W) ->
Ind;
-cind_tail({_, Len}=E, _Col0, Col, Ll, M, Ind, LD, W)
+cind_tail({_, Len, _, _}=E, _Col0, Col, Ll, M, Ind, LD, W)
when Len + 1 < Ll - Col - (LD + 1),
Len + 1 + W + (LD + 1) =< M,
?ATM(E) ->
@@ -842,7 +1095,7 @@ cind_tail({_, Len}=E, _Col0, Col, Ll, M, Ind, LD, W)
cind_tail(E, _Col0, Col, Ll, M, Ind, LD, _W) ->
cind(E, Col, Ll, M, Ind, LD + 1, 0).
-cind_element({_, Len}=E, Col, Ll, M, _Ind, LD, W)
+cind_element({_, Len, _, _}=E, Col, Ll, M, _Ind, LD, W)
when Len < Ll - Col - LD, Len + W + LD =< M, ?ATM(E) ->
Len;
cind_element(E, Col, Ll, M, Ind, LD, W) ->
diff --git a/lib/stdlib/src/lib.erl b/lib/stdlib/src/lib.erl
deleted file mode 100644
index be11e86100..0000000000
--- a/lib/stdlib/src/lib.erl
+++ /dev/null
@@ -1,746 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
--module(lib).
-
--export([flush_receive/0, error_message/2, progname/0, nonl/1, send/2,
- sendw/2, eval_str/1]).
-
--export([extended_parse_exprs/1, extended_parse_term/1,
- subst_values_for_vars/2]).
-
--export([format_exception/6, format_exception/7,
- format_stacktrace/4, format_stacktrace/5,
- format_call/4, format_call/5, format_fun/1, format_fun/2]).
-
--spec flush_receive() -> 'ok'.
-
-flush_receive() ->
- receive
- _Any ->
- flush_receive()
- after
- 0 ->
- ok
- end.
-
-%%
-%% Functions for doing standard system format i/o.
-%%
--spec error_message(Format, Args) -> 'ok' when
- Format :: io:format(),
- Args :: [term()].
-
-error_message(Format, Args) ->
- io:format(<<"** ~ts **\n">>, [io_lib:format(Format, Args)]).
-
-%% Return the name of the script that starts (this) erlang
-%%
--spec progname() -> atom().
-
-progname() ->
- case init:get_argument(progname) of
- {ok, [[Prog]]} ->
- list_to_atom(Prog);
- _Other ->
- no_prog_name
- end.
-
--spec nonl(String1) -> String2 when
- String1 :: string(),
- String2 :: string().
-
-nonl([10]) -> [];
-nonl([]) -> [];
-nonl([H|T]) -> [H|nonl(T)].
-
--spec send(To, Msg) -> Msg when
- To :: pid() | atom() | {atom(), node()},
- Msg :: term().
-
-send(To, Msg) -> To ! Msg.
-
--spec sendw(To, Msg) -> term() when
- To :: pid() | atom() | {atom(), node()},
- Msg :: term().
-
-sendw(To, Msg) ->
- To ! {self(), Msg},
- receive
- Reply -> Reply
- end.
-
-%% eval_str(InStr) -> {ok, OutStr} | {error, ErrStr'}
-%% InStr must represent a body
-%% Note: If InStr is a binary it has to be a Latin-1 string.
-%% If you have a UTF-8 encoded binary you have to call
-%% unicode:characters_to_list/1 before the call to eval_str().
-
--define(result(F,D), lists:flatten(io_lib:format(F, D))).
-
--spec eval_str(string() | unicode:latin1_binary()) ->
- {'ok', string()} | {'error', string()}.
-
-eval_str(Str) when is_list(Str) ->
- case erl_scan:tokens([], Str, 0) of
- {more, _} ->
- {error, "Incomplete form (missing .<cr>)??"};
- {done, {ok, Toks, _}, Rest} ->
- case all_white(Rest) of
- true ->
- case erl_parse:parse_exprs(Toks) of
- {ok, Exprs} ->
- case catch erl_eval:exprs(Exprs, erl_eval:new_bindings()) of
- {value, Val, _} ->
- {ok, Val};
- Other ->
- {error, ?result("*** eval: ~p", [Other])}
- end;
- {error, {_Line, Mod, Args}} ->
- Msg = ?result("*** ~ts",[Mod:format_error(Args)]),
- {error, Msg}
- end;
- false ->
- {error, ?result("Non-white space found after "
- "end-of-form :~ts", [Rest])}
- end
- end;
-eval_str(Bin) when is_binary(Bin) ->
- eval_str(binary_to_list(Bin)).
-
-all_white([$\s|T]) -> all_white(T);
-all_white([$\n|T]) -> all_white(T);
-all_white([$\t|T]) -> all_white(T);
-all_white([]) -> true;
-all_white(_) -> false.
-
-%% `Tokens' is assumed to have been scanned with the 'text' option.
-%% The annotations of the returned expressions are locations.
-%%
-%% Can handle pids, ports, references, and external funs ("items").
-%% Known items are represented by variables in the erl_parse tree, and
-%% the items themselves are stored in the returned bindings.
-
--spec extended_parse_exprs(Tokens) ->
- {'ok', ExprList, Bindings} | {'error', ErrorInfo} when
- Tokens :: [erl_scan:token()],
- ExprList :: [erl_parse:abstract_expr()],
- Bindings :: erl_eval:binding_struct(),
- ErrorInfo :: erl_parse:error_info().
-
-extended_parse_exprs(Tokens) ->
- Ts = tokens_fixup(Tokens),
- case erl_parse:parse_exprs(Ts) of
- {ok, Exprs0} ->
- {Exprs, Bs} = expr_fixup(Exprs0),
- {ok, reset_expr_anno(Exprs), Bs};
- _ErrorInfo ->
- erl_parse:parse_exprs(reset_token_anno(Ts))
- end.
-
-tokens_fixup([]) -> [];
-tokens_fixup([T|Ts]=Ts0) ->
- try token_fixup(Ts0) of
- {NewT, NewTs} ->
- [NewT|tokens_fixup(NewTs)]
- catch
- _:_ ->
- [T|tokens_fixup(Ts)]
- end.
-
-token_fixup(Ts) ->
- {AnnoL, NewTs, FixupTag} = unscannable(Ts),
- String = lists:append([erl_anno:text(A) || A <- AnnoL]),
- _ = (fixup_fun(FixupTag))(String),
- NewAnno = erl_anno:set_text(fixup_text(FixupTag), hd(AnnoL)),
- {{string, NewAnno, String}, NewTs}.
-
-unscannable([{'#', A1}, {var, A2, 'Fun'}, {'<', A3}, {atom, A4, _},
- {'.', A5}, {float, A6, _}, {'>', A7}|Ts]) ->
- {[A1, A2, A3, A4, A5, A6, A7], Ts, function};
-unscannable([{'#', A1}, {var, A2, 'Fun'}, {'<', A3}, {atom, A4, _},
- {'.', A5}, {atom, A6, _}, {'.', A7}, {integer, A8, _},
- {'>', A9}|Ts]) ->
- {[A1, A2, A3, A4, A5, A6, A7, A8, A9], Ts, function};
-unscannable([{'<', A1}, {float, A2, _}, {'.', A3}, {integer, A4, _},
- {'>', A5}|Ts]) ->
- {[A1, A2, A3, A4, A5], Ts, pid};
-unscannable([{'#', A1}, {var, A2, 'Port'}, {'<', A3}, {float, A4, _},
- {'>', A5}|Ts]) ->
- {[A1, A2, A3, A4, A5], Ts, port};
-unscannable([{'#', A1}, {var, A2, 'Ref'}, {'<', A3}, {float, A4, _},
- {'.', A5}, {float, A6, _}, {'>', A7}|Ts]) ->
- {[A1, A2, A3, A4, A5, A6, A7], Ts, reference}.
-
-expr_fixup(Expr0) ->
- {Expr, Bs, _} = expr_fixup(Expr0, erl_eval:new_bindings(), 1),
- {Expr, Bs}.
-
-expr_fixup({string,A,S}=T, Bs0, I) ->
- try string_fixup(A, S) of
- Value ->
- Var = new_var(I),
- Bs = erl_eval:add_binding(Var, Value, Bs0),
- {{var, A, Var}, Bs, I+1}
- catch
- _:_ ->
- {T, Bs0, I}
- end;
-expr_fixup(Tuple, Bs0, I0) when is_tuple(Tuple) ->
- {L, Bs, I} = expr_fixup(tuple_to_list(Tuple), Bs0, I0),
- {list_to_tuple(L), Bs, I};
-expr_fixup([E0|Es0], Bs0, I0) ->
- {E, Bs1, I1} = expr_fixup(E0, Bs0, I0),
- {Es, Bs, I} = expr_fixup(Es0, Bs1, I1),
- {[E|Es], Bs, I};
-expr_fixup(T, Bs, I) ->
- {T, Bs, I}.
-
-string_fixup(A, S) ->
- Text = erl_anno:text(A),
- FixupTag = fixup_tag(Text, S),
- (fixup_fun(FixupTag))(S).
-
-new_var(I) ->
- list_to_atom(lists:concat(['__ExtendedParseExprs_', I, '__'])).
-
-reset_token_anno(Tokens) ->
- [setelement(2, T, (reset_anno())(element(2, T))) || T <- Tokens].
-
-reset_expr_anno(Exprs) ->
- [erl_parse:map_anno(reset_anno(), E) || E <- Exprs].
-
-reset_anno() ->
- fun(A) -> erl_anno:new(erl_anno:location(A)) end.
-
-fixup_fun(function) -> fun function/1;
-fixup_fun(pid) -> fun erlang:list_to_pid/1;
-fixup_fun(port) -> fun erlang:list_to_port/1;
-fixup_fun(reference) -> fun erlang:list_to_ref/1.
-
-function(S) ->
- %% External function.
- {ok, [_, _, _,
- {atom, _, Module}, _,
- {atom, _, Function}, _,
- {integer, _, Arity}|_], _} = erl_scan:string(S),
- erlang:make_fun(Module, Function, Arity).
-
-fixup_text(function) -> "function";
-fixup_text(pid) -> "pid";
-fixup_text(port) -> "port";
-fixup_text(reference) -> "reference".
-
-fixup_tag("function", "#"++_) -> function;
-fixup_tag("pid", "<"++_) -> pid;
-fixup_tag("port", "#"++_) -> port;
-fixup_tag("reference", "#"++_) -> reference.
-
-%%% End of extended_parse_exprs.
-
-%% `Tokens' is assumed to have been scanned with the 'text' option.
-%%
-%% Can handle pids, ports, references, and external funs.
-
--spec extended_parse_term(Tokens) ->
- {'ok', Term} | {'error', ErrorInfo} when
- Tokens :: [erl_scan:token()],
- Term :: term(),
- ErrorInfo :: erl_parse:error_info().
-
-extended_parse_term(Tokens) ->
- case extended_parse_exprs(Tokens) of
- {ok, [Expr], Bindings} ->
- try normalise(Expr, Bindings) of
- Term ->
- {ok, Term}
- catch
- _:_ ->
- Loc = erl_anno:location(element(2, Expr)),
- {error,{Loc,?MODULE,"bad term"}}
- end;
- {ok, [_,Expr|_], _Bindings} ->
- Loc = erl_anno:location(element(2, Expr)),
- {error,{Loc,?MODULE,"bad term"}};
- {error, _} = Error ->
- Error
- end.
-
-%% From erl_parse.
-normalise({var, _, V}, Bs) ->
- {value, Value} = erl_eval:binding(V, Bs),
- Value;
-normalise({char,_,C}, _Bs) -> C;
-normalise({integer,_,I}, _Bs) -> I;
-normalise({float,_,F}, _Bs) -> F;
-normalise({atom,_,A}, _Bs) -> A;
-normalise({string,_,S}, _Bs) -> S;
-normalise({nil,_}, _Bs) -> [];
-normalise({bin,_,Fs}, Bs) ->
- {value, B, _} =
- eval_bits:expr_grp(Fs, [],
- fun(E, _) ->
- {value, normalise(E, Bs), []}
- end, [], true),
- B;
-normalise({cons,_,Head,Tail}, Bs) ->
- [normalise(Head, Bs)|normalise(Tail, Bs)];
-normalise({tuple,_,Args}, Bs) ->
- list_to_tuple(normalise_list(Args, Bs));
-normalise({map,_,Pairs}, Bs) ->
- maps:from_list(lists:map(fun
- %% only allow '=>'
- ({map_field_assoc,_,K,V}) ->
- {normalise(K, Bs),normalise(V, Bs)}
- end, Pairs));
-%% Special case for unary +/-.
-normalise({op,_,'+',{char,_,I}}, _Bs) -> I;
-normalise({op,_,'+',{integer,_,I}}, _Bs) -> I;
-normalise({op,_,'+',{float,_,F}}, _Bs) -> F;
-normalise({op,_,'-',{char,_,I}}, _Bs) -> -I; %Weird, but compatible!
-normalise({op,_,'-',{integer,_,I}}, _Bs) -> -I;
-normalise({op,_,'-',{float,_,F}}, _Bs) -> -F;
-normalise({'fun',_,{function,{atom,_,M},{atom,_,F},{integer,_,A}}}, _Bs) ->
- %% Since "#Fun<M.F.A>" is recognized, "fun M:F/A" should be too.
- fun M:F/A.
-
-normalise_list([H|T], Bs) ->
- [normalise(H, Bs)|normalise_list(T, Bs)];
-normalise_list([], _Bs) ->
- [].
-
-%% To be used on ExprList and Bindings returned from extended_parse_exprs().
-%% Substitute {value, A, Item} for {var, A, ExtendedParseVar}.
-%% {value, A, Item} is a shell/erl_eval convention, and for example
-%% the linter cannot handle it.
-
--spec subst_values_for_vars(ExprList, Bindings) -> [term()] when
- ExprList :: [erl_parse:abstract_expr()],
- Bindings :: erl_eval:binding_struct().
-
-subst_values_for_vars({var, A, V}=Var, Bs) ->
- case erl_eval:binding(V, Bs) of
- {value, Value} ->
- {value, A, Value};
- unbound ->
- Var
- end;
-subst_values_for_vars(L, Bs) when is_list(L) ->
- [subst_values_for_vars(E, Bs) || E <- L];
-subst_values_for_vars(T, Bs) when is_tuple(T) ->
- list_to_tuple(subst_values_for_vars(tuple_to_list(T), Bs));
-subst_values_for_vars(T, _Bs) ->
- T.
-
-%%% Formatting of exceptions, mfa:s and funs.
-
-%% -> iolist() (no \n at end)
-%% I is the current column, starting from 1 (it will be used
-%% as indentation whenever newline has been inserted);
-%% Class, Reason and StackTrace are the exception;
-%% FormatFun = fun(Term, I) -> iolist() formats terms;
-%% StackFun = fun(Mod, Fun, Arity) -> boolean() is used for trimming the
-%% end of the stack (typically calls to erl_eval are skipped).
-format_exception(I, Class, Reason, StackTrace, StackFun, FormatFun) ->
- format_exception(I, Class, Reason, StackTrace, StackFun, FormatFun,
- latin1).
-
-%% -> iolist() | unicode:charlist() (no \n at end)
-%% FormatFun = fun(Term, I) -> iolist() | unicode:charlist().
-format_exception(I, Class, Reason, StackTrace, StackFun, FormatFun, Encoding)
- when is_integer(I), I >= 1, is_function(StackFun, 3),
- is_function(FormatFun, 2) ->
- S = n_spaces(I-1),
- {Term,Trace1,Trace} = analyze_exception(Class, Reason, StackTrace),
- Expl0 = explain_reason(Term, Class, Trace1, FormatFun, S, Encoding),
- FormatString = case Encoding of
- latin1 -> "~s~s";
- _ -> "~s~ts"
- end,
- Expl = io_lib:fwrite(FormatString, [exited(Class), Expl0]),
- case format_stacktrace1(S, Trace, FormatFun, StackFun, Encoding) of
- [] -> Expl;
- Stack -> [Expl, $\n, Stack]
- end.
-
-%% -> iolist() (no \n at end)
-format_stacktrace(I, StackTrace, StackFun, FormatFun) ->
- format_stacktrace(I, StackTrace, StackFun, FormatFun, latin1).
-
-%% -> iolist() | unicode:charlist() (no \n at end)
-format_stacktrace(I, StackTrace, StackFun, FormatFun, Encoding)
- when is_integer(I), I >= 1, is_function(StackFun, 3),
- is_function(FormatFun, 2) ->
- S = n_spaces(I-1),
- format_stacktrace1(S, StackTrace, FormatFun, StackFun, Encoding).
-
-%% -> iolist() (no \n at end)
-format_call(I, ForMForFun, As, FormatFun) ->
- format_call(I, ForMForFun, As, FormatFun, latin1).
-
-%% -> iolist() | unicode:charlist() (no \n at end)
-format_call(I, ForMForFun, As, FormatFun, Enc)
- when is_integer(I), I >= 1, is_list(As), is_function(FormatFun, 2) ->
- format_call("", n_spaces(I-1), ForMForFun, As, FormatFun, Enc).
-
-%% -> iolist() (no \n at end)
-format_fun(Fun) ->
- format_fun(Fun, latin1).
-
-%% -> iolist() (no \n at end)
-format_fun(Fun, Enc) when is_function(Fun) ->
- {module, M} = erlang:fun_info(Fun, module),
- {name, F} = erlang:fun_info(Fun, name),
- {arity, A} = erlang:fun_info(Fun, arity),
- case erlang:fun_info(Fun, type) of
- {type, local} when F =:= "" ->
- io_lib:fwrite(<<"~w">>, [Fun]);
- {type, local} when M =:= erl_eval ->
- io_lib:fwrite(<<"interpreted function with arity ~w">>, [A]);
- {type, local} ->
- mfa_to_string(M, F, A, Enc);
- {type, external} ->
- mfa_to_string(M, F, A, Enc)
- end.
-
-analyze_exception(error, Term, Stack) ->
- case {is_stacktrace(Stack), Stack, Term} of
- {true, [{_,_,As,_}=MFAL|MFAs], function_clause} when is_list(As) ->
- {Term,[MFAL],MFAs};
- {true, [{shell,F,A,_}], function_clause} when is_integer(A) ->
- {Term, [{F,A}], []};
- {true, [{_,_,_,_}=MFAL|MFAs], undef} ->
- {Term,[MFAL],MFAs};
- {true, _, _} ->
- {Term,[],Stack};
- {false, _, _} ->
- {{Term,Stack},[],[]}
- end;
-analyze_exception(_Class, Term, Stack) ->
- case is_stacktrace(Stack) of
- true ->
- {Term,[],Stack};
- false ->
- {{Term,Stack},[],[]}
- end.
-
-is_stacktrace([]) ->
- true;
-is_stacktrace([{M,F,A,I}|Fs])
- when is_atom(M), is_atom(F), is_integer(A), is_list(I) ->
- is_stacktrace(Fs);
-is_stacktrace([{M,F,As,I}|Fs])
- when is_atom(M), is_atom(F), length(As) >= 0, is_list(I) ->
- is_stacktrace(Fs);
-is_stacktrace(_) ->
- false.
-
-%% ERTS exit codes (some of them are also returned by erl_eval):
-explain_reason(badarg, error, [], _PF, _S, _Enc) ->
- <<"bad argument">>;
-explain_reason({badarg,V}, error=Cl, [], PF, S, _Enc) -> % orelse, andalso
- format_value(V, <<"bad argument: ">>, Cl, PF, S);
-explain_reason(badarith, error, [], _PF, _S, _Enc) ->
- <<"an error occurred when evaluating an arithmetic expression">>;
-explain_reason({badarity,{Fun,As}}, error, [], _PF, _S, Enc)
- when is_function(Fun) ->
- %% Only the arity is displayed, not the arguments As.
- io_lib:fwrite(<<"~ts called with ~s">>,
- [format_fun(Fun, Enc), argss(length(As))]);
-explain_reason({badfun,Term}, error=Cl, [], PF, S, _Enc) ->
- format_value(Term, <<"bad function ">>, Cl, PF, S);
-explain_reason({badmatch,Term}, error=Cl, [], PF, S, _Enc) ->
- Str = <<"no match of right hand side value ">>,
- format_value(Term, Str, Cl, PF, S);
-explain_reason({case_clause,V}, error=Cl, [], PF, S, _Enc) ->
- %% "there is no case clause with a true guard sequence and a
- %% pattern matching..."
- format_value(V, <<"no case clause matching ">>, Cl, PF, S);
-explain_reason(function_clause, error, [{F,A}], _PF, _S, _Enc) ->
- %% Shell commands
- FAs = io_lib:fwrite(<<"~w/~w">>, [F, A]),
- [<<"no function clause matching call to ">> | FAs];
-explain_reason(function_clause, error=Cl, [{M,F,As,Loc}], PF, S, Enc) ->
- Str = <<"no function clause matching ">>,
- [format_errstr_call(Str, Cl, {M,F}, As, PF, S, Enc),$\s|location(Loc)];
-explain_reason(if_clause, error, [], _PF, _S, _Enc) ->
- <<"no true branch found when evaluating an if expression">>;
-explain_reason(noproc, error, [], _PF, _S, _Enc) ->
- <<"no such process or port">>;
-explain_reason(notalive, error, [], _PF, _S, _Enc) ->
- <<"the node cannot be part of a distributed system">>;
-explain_reason(system_limit, error, [], _PF, _S, _Enc) ->
- <<"a system limit has been reached">>;
-explain_reason(timeout_value, error, [], _PF, _S, _Enc) ->
- <<"bad receive timeout value">>;
-explain_reason({try_clause,V}, error=Cl, [], PF, S, _Enc) ->
- %% "there is no try clause with a true guard sequence and a
- %% pattern matching..."
- format_value(V, <<"no try clause matching ">>, Cl, PF, S);
-explain_reason(undef, error, [{M,F,A,_}], _PF, _S, Enc) ->
- %% Only the arity is displayed, not the arguments, if there are any.
- io_lib:fwrite(<<"undefined function ~ts">>,
- [mfa_to_string(M, F, n_args(A), Enc)]);
-explain_reason({shell_undef,F,A,_}, error, [], _PF, _S, Enc) ->
- %% Give nicer reports for undefined shell functions
- %% (but not when the user actively calls shell_default:F(...)).
- FS = to_string(F, Enc),
- io_lib:fwrite(<<"undefined shell command ~ts/~w">>, [FS, n_args(A)]);
-%% Exit codes returned by erl_eval only:
-explain_reason({argument_limit,_Fun}, error, [], _PF, _S, _Enc) ->
- io_lib:fwrite(<<"limit of number of arguments to interpreted function"
- " exceeded">>, []);
-explain_reason({bad_filter,V}, error=Cl, [], PF, S, _Enc) ->
- format_value(V, <<"bad filter ">>, Cl, PF, S);
-explain_reason({bad_generator,V}, error=Cl, [], PF, S, _Enc) ->
- format_value(V, <<"bad generator ">>, Cl, PF, S);
-explain_reason({unbound,V}, error, [], _PF, _S, _Enc) ->
- io_lib:fwrite(<<"variable ~w is unbound">>, [V]);
-%% Exit codes local to the shell module (restricted shell):
-explain_reason({restricted_shell_bad_return, V}, exit=Cl, [], PF, S, _Enc) ->
- Str = <<"restricted shell module returned bad value ">>,
- format_value(V, Str, Cl, PF, S);
-explain_reason({restricted_shell_disallowed,{ForMF,As}},
- exit=Cl, [], PF, S, Enc) ->
- %% ForMF can be a fun, but not a shell fun.
- Str = <<"restricted shell does not allow ">>,
- format_errstr_call(Str, Cl, ForMF, As, PF, S, Enc);
-explain_reason(restricted_shell_started, exit, [], _PF, _S, _Enc) ->
- <<"restricted shell starts now">>;
-explain_reason(restricted_shell_stopped, exit, [], _PF, _S, _Enc) ->
- <<"restricted shell stopped">>;
-%% Other exit code:
-explain_reason(Reason, Class, [], PF, S, _Enc) ->
- PF(Reason, (iolist_size(S)+1) + exited_size(Class)).
-
-n_args(A) when is_integer(A) ->
- A;
-n_args(As) when is_list(As) ->
- length(As).
-
-argss(0) ->
- <<"no arguments">>;
-argss(1) ->
- <<"one argument">>;
-argss(2) ->
- <<"two arguments">>;
-argss(I) ->
- io_lib:fwrite(<<"~w arguments">>, [I]).
-
-format_stacktrace1(S0, Stack0, PF, SF, Enc) ->
- Stack1 = lists:dropwhile(fun({M,F,A,_}) -> SF(M, F, A)
- end, lists:reverse(Stack0)),
- S = [" " | S0],
- Stack = lists:reverse(Stack1),
- format_stacktrace2(S, Stack, 1, PF, Enc).
-
-format_stacktrace2(S, [{M,F,A,L}|Fs], N, PF, Enc) when is_integer(A) ->
- [io_lib:fwrite(<<"~s~s ~ts ~ts">>,
- [sep(N, S), origin(N, M, F, A),
- mfa_to_string(M, F, A, Enc),
- location(L)])
- | format_stacktrace2(S, Fs, N + 1, PF, Enc)];
-format_stacktrace2(S, [{M,F,As,_}|Fs], N, PF, Enc) when is_list(As) ->
- A = length(As),
- CalledAs = [S,<<" called as ">>],
- C = format_call("", CalledAs, {M,F}, As, PF, Enc),
- [io_lib:fwrite(<<"~s~s ~ts\n~s~ts">>,
- [sep(N, S), origin(N, M, F, A),
- mfa_to_string(M, F, A, Enc),
- CalledAs, C])
- | format_stacktrace2(S, Fs, N + 1, PF, Enc)];
-format_stacktrace2(_S, [], _N, _PF, _Enc) ->
- "".
-
-location(L) ->
- File = proplists:get_value(file, L),
- Line = proplists:get_value(line, L),
- if
- File =/= undefined, Line =/= undefined ->
- io_lib:format("(~ts, line ~w)", [File, Line]);
- true ->
- ""
- end.
-
-sep(1, S) -> S;
-sep(_, S) -> [$\n | S].
-
-origin(1, M, F, A) ->
- case is_op({M, F}, n_args(A)) of
- {yes, F} -> <<"in operator ">>;
- no -> <<"in function ">>
- end;
-origin(_N, _M, _F, _A) ->
- <<"in call from">>.
-
-format_errstr_call(ErrStr, Class, ForMForFun, As, PF, Pre0, Enc) ->
- Pre1 = [Pre0 | n_spaces(exited_size(Class))],
- format_call(ErrStr, Pre1, ForMForFun, As, PF, Enc).
-
-format_call(ErrStr, Pre1, ForMForFun, As, PF, Enc) ->
- Arity = length(As),
- [ErrStr |
- case is_op(ForMForFun, Arity) of
- {yes,Op} ->
- format_op(ErrStr, Pre1, Op, As, PF, Enc);
- no ->
- MFs = mf_to_string(ForMForFun, Arity, Enc),
- I1 = string:length([Pre1,ErrStr|MFs]),
- S1 = pp_arguments(PF, As, I1, Enc),
- S2 = pp_arguments(PF, As, string:length([Pre1|MFs]), Enc),
- Long = count_nl(pp_arguments(PF, [a2345,b2345], I1, Enc)) > 0,
- case Long or (count_nl(S2) < count_nl(S1)) of
- true ->
- [$\n, Pre1, MFs, S2];
- false ->
- [MFs, S1]
- end
- end].
-
-format_op(ErrStr, Pre, Op, [A1], PF, _Enc) ->
- OpS = io_lib:fwrite(<<"~s ">>, [Op]),
- I1 = iolist_size([ErrStr,Pre,OpS]),
- [OpS | PF(A1, I1+1)];
-format_op(ErrStr, Pre, Op, [A1, A2], PF, Enc) ->
- I1 = iolist_size([ErrStr,Pre]),
- S1 = PF(A1, I1+1),
- S2 = PF(A2, I1+1),
- OpS = atom_to_list(Op),
- Pre1 = [$\n | n_spaces(I1)],
- case count_nl(S1) > 0 of
- true ->
- [S1,Pre1,OpS,Pre1|S2];
- false ->
- OpS2 = io_lib:fwrite(<<" ~s ">>, [Op]),
- Size1 = iolist_size([ErrStr,Pre|OpS2]),
- {Size2,S1_2} = size(Enc, S1),
- S2_2 = PF(A2, Size1+Size2+1),
- case count_nl(S2) < count_nl(S2_2) of
- true ->
- [S1_2,Pre1,OpS,Pre1|S2];
- false ->
- [S1_2,OpS2|S2_2]
- end
- end.
-
-pp_arguments(PF, As, I, Enc) ->
- case {As, printable_list(Enc, As)} of
- {[Int | T], true} ->
- L = integer_to_list(Int),
- Ll = length(L),
- A = list_to_atom(lists:duplicate(Ll, $a)),
- S0 = unicode:characters_to_list(PF([A | T], I+1), Enc),
- brackets_to_parens([$[,L,string:sub_string(S0, 2+Ll)], Enc);
- _ ->
- brackets_to_parens(PF(As, I+1), Enc)
- end.
-
-brackets_to_parens(S, Enc) ->
- B = unicode:characters_to_binary(S, Enc),
- Sz = byte_size(B) - 2,
- <<$[,R:Sz/binary,$]>> = B,
- [$(,R,$)].
-
-printable_list(latin1, As) ->
- io_lib:printable_latin1_list(As);
-printable_list(_, As) ->
- io_lib:printable_list(As).
-
-mfa_to_string(M, F, A, Enc) ->
- io_lib:fwrite(<<"~ts/~w">>, [mf_to_string({M, F}, A, Enc), A]).
-
-mf_to_string({M, F}, A, Enc) ->
- case erl_internal:bif(M, F, A) of
- true ->
- io_lib:fwrite(<<"~w">>, [F]);
- false ->
- case is_op({M, F}, A) of
- {yes, '/'} ->
- io_lib:fwrite(<<"~w">>, [F]);
- {yes, F} ->
- atom_to_list(F);
- no ->
- FS = to_string(F, Enc),
- io_lib:fwrite(<<"~w:~ts">>, [M, FS])
- end
- end;
-mf_to_string(Fun, _A, Enc) when is_function(Fun) ->
- format_fun(Fun, Enc);
-mf_to_string(F, _A, Enc) ->
- FS = to_string(F, Enc),
- io_lib:fwrite(<<"~ts">>, [FS]).
-
-format_value(V, ErrStr, Class, PF, S) ->
- Pre1Sz = exited_size(Class),
- S1 = PF(V, Pre1Sz + iolist_size([S, ErrStr])+1),
- [ErrStr | case count_nl(S1) of
- N1 when N1 > 1 ->
- S2 = PF(V, iolist_size(S) + 1 + Pre1Sz),
- case count_nl(S2) < N1 of
- true ->
- [$\n, S, n_spaces(Pre1Sz) | S2];
- false ->
- S1
- end;
- _ ->
- S1
- end].
-
-%% Handles deep lists, but not all iolists.
-count_nl([E | Es]) ->
- count_nl(E) + count_nl(Es);
-count_nl($\n) ->
- 1;
-count_nl(Bin) when is_binary(Bin) ->
- count_nl(binary_to_list(Bin));
-count_nl(_) ->
- 0.
-
-n_spaces(N) ->
- lists:duplicate(N, $\s).
-
-is_op(ForMForFun, A) ->
- try
- {erlang,F} = ForMForFun,
- _ = erl_internal:op_type(F, A),
- {yes,F}
- catch error:_ -> no
- end.
-
-exited_size(Class) ->
- iolist_size(exited(Class)).
-
-exited(error) ->
- <<"exception error: ">>;
-exited(exit) ->
- <<"exception exit: ">>;
-exited(throw) ->
- <<"exception throw: ">>.
-
-to_string(A, latin1) ->
- io_lib:write_atom_as_latin1(A);
-to_string(A, _) ->
- io_lib:write_atom(A).
-
-size(latin1, S) ->
- {iolist_size(S),S};
-size(_, S0) ->
- S = unicode:characters_to_list(S0, unicode),
- true = is_list(S),
- {string:length(S),S}.
diff --git a/lib/stdlib/src/lists.erl b/lib/stdlib/src/lists.erl
index af9d63ddd6..06c90c0280 100644
--- a/lib/stdlib/src/lists.erl
+++ b/lib/stdlib/src/lists.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -38,8 +38,8 @@
-export([all/2,any/2,map/2,flatmap/2,foldl/3,foldr/3,filter/2,
partition/2,zf/2,filtermap/2,
- mapfoldl/3,mapfoldr/3,foreach/2,takewhile/2,dropwhile/2,splitwith/2,
- split/2,
+ mapfoldl/3,mapfoldr/3,foreach/2,takewhile/2,dropwhile/2,
+ search/2, splitwith/2,split/2,
join/2]).
%%% BIFs
@@ -1399,6 +1399,19 @@ dropwhile(Pred, [Hd|Tail]=Rest) ->
end;
dropwhile(Pred, []) when is_function(Pred, 1) -> [].
+-spec search(Pred, List) -> {value, Value} | false when
+ Pred :: fun((T) -> boolean()),
+ List :: [T],
+ Value :: T.
+
+search(Pred, [Hd|Tail]) ->
+ case Pred(Hd) of
+ true -> {value, Hd};
+ false -> search(Pred, Tail)
+ end;
+search(Pred, []) when is_function(Pred, 1) ->
+ false.
+
-spec splitwith(Pred, List) -> {List1, List2} when
Pred :: fun((T) -> boolean()),
List :: [T],
diff --git a/lib/stdlib/src/maps.erl b/lib/stdlib/src/maps.erl
index 5dafdb282a..51965ddb57 100644
--- a/lib/stdlib/src/maps.erl
+++ b/lib/stdlib/src/maps.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,16 +21,28 @@
-module(maps).
-export([get/3, filter/2,fold/3,
- map/2, size/1,
+ map/2, size/1, new/0,
update_with/3, update_with/4,
- without/2, with/2]).
+ without/2, with/2,
+ iterator/1, next/1]).
%% BIFs
-export([get/2, find/2, from_list/1,
is_key/2, keys/1, merge/2,
- new/0, put/3, remove/2, take/2,
+ put/3, remove/2, take/2,
to_list/1, update/3, values/1]).
+-opaque iterator(Key, Value) :: {Key, Value, iterator(Key, Value)} | none
+ | nonempty_improper_list(integer(), #{Key => Value}).
+
+-type iterator() :: iterator(term(), term()).
+
+-export_type([iterator/2, iterator/0]).
+
+-dialyzer({no_improper_lists, iterator/1}).
+
+-define(IS_ITERATOR(I), is_tuple(I) andalso tuple_size(I) == 3; I == none; is_integer(hd(I)) andalso is_map(tl(I))).
+
%% Shadowed by erl_bif_types: maps:get/2
-spec get(Key,Map) -> Value when
Key :: term(),
@@ -39,11 +51,8 @@
get(_,_) -> erlang:nif_error(undef).
-
-spec find(Key,Map) -> {ok, Value} | error when
- Key :: term(),
- Map :: map(),
- Value :: term().
+ Map :: #{Key => Value, _ => _}.
find(_,_) -> erlang:nif_error(undef).
@@ -66,9 +75,8 @@ is_key(_,_) -> erlang:nif_error(undef).
-spec keys(Map) -> Keys when
- Map :: map(),
- Keys :: [Key],
- Key :: term().
+ Map :: #{Key => _},
+ Keys :: [Key].
keys(_) -> erlang:nif_error(undef).
@@ -82,13 +90,6 @@ keys(_) -> erlang:nif_error(undef).
merge(_,_) -> erlang:nif_error(undef).
-
--spec new() -> Map when
- Map :: map().
-
-new() -> erlang:nif_error(undef).
-
-
%% Shadowed by erl_bif_types: maps:put/3
-spec put(Key,Value,Map1) -> Map2 when
Key :: term(),
@@ -107,132 +108,151 @@ put(_,_,_) -> erlang:nif_error(undef).
remove(_,_) -> erlang:nif_error(undef).
-spec take(Key,Map1) -> {Value,Map2} | error when
- Key :: term(),
- Map1 :: map(),
- Value :: term(),
- Map2 :: map().
+ Map1 :: #{Key => Value, _ => _},
+ Map2 :: #{_ => _}.
take(_,_) -> erlang:nif_error(undef).
-%% Shadowed by erl_bif_types: maps:to_list/1
-spec to_list(Map) -> [{Key,Value}] when
- Map :: map(),
- Key :: term(),
- Value :: term().
+ Map :: #{Key => Value}.
-to_list(_) -> erlang:nif_error(undef).
+to_list(Map) when is_map(Map) ->
+ to_list_internal(erts_internal:map_next(0, Map, []));
+to_list(Map) ->
+ erlang:error({badmap,Map},[Map]).
+to_list_internal([Iter, Map | Acc]) when is_integer(Iter) ->
+ to_list_internal(erts_internal:map_next(Iter, Map, Acc));
+to_list_internal(Acc) ->
+ Acc.
%% Shadowed by erl_bif_types: maps:update/3
-spec update(Key,Value,Map1) -> Map2 when
- Key :: term(),
- Value :: term(),
- Map1 :: map(),
- Map2 :: map().
+ Map1 :: #{Key := _, _ => _},
+ Map2 :: #{Key := Value, _ => _}.
update(_,_,_) -> erlang:nif_error(undef).
-spec values(Map) -> Values when
- Map :: map(),
- Values :: [Value],
- Value :: term().
+ Map :: #{_ => Value},
+ Values :: [Value].
values(_) -> erlang:nif_error(undef).
%% End of BIFs
+-spec new() -> Map when
+ Map :: #{}.
+
+new() -> #{}.
+
-spec update_with(Key,Fun,Map1) -> Map2 when
- Key :: term(),
- Map1 :: map(),
- Map2 :: map(),
- Fun :: fun((Value1 :: term()) -> Value2 :: term()).
+ Map1 :: #{Key := Value1, _ => _},
+ Map2 :: #{Key := Value2, _ => _},
+ Fun :: fun((Value1) -> Value2).
update_with(Key,Fun,Map) when is_function(Fun,1), is_map(Map) ->
- try maps:get(Key,Map) of
- Val -> maps:update(Key,Fun(Val),Map)
- catch
- error:{badkey,_} ->
- erlang:error({badkey,Key},[Key,Fun,Map])
+ case Map of
+ #{Key := Value} -> Map#{Key := Fun(Value)};
+ #{} -> erlang:error({badkey,Key},[Key,Fun,Map])
end;
update_with(Key,Fun,Map) ->
erlang:error(error_type(Map),[Key,Fun,Map]).
-spec update_with(Key,Fun,Init,Map1) -> Map2 when
- Key :: term(),
- Map1 :: Map1,
- Map2 :: Map2,
- Fun :: fun((Value1 :: term()) -> Value2 :: term()),
- Init :: term().
+ Map1 :: #{Key => Value1, _ => _},
+ Map2 :: #{Key := Value2 | Init, _ => _},
+ Fun :: fun((Value1) -> Value2).
update_with(Key,Fun,Init,Map) when is_function(Fun,1), is_map(Map) ->
- case maps:find(Key,Map) of
- {ok,Val} -> maps:update(Key,Fun(Val),Map);
- error -> maps:put(Key,Init,Map)
+ case Map of
+ #{Key := Value} -> Map#{Key := Fun(Value)};
+ #{} -> Map#{Key => Init}
end;
update_with(Key,Fun,Init,Map) ->
erlang:error(error_type(Map),[Key,Fun,Init,Map]).
-spec get(Key, Map, Default) -> Value | Default when
- Key :: term(),
- Map :: map(),
- Value :: term(),
- Default :: term().
+ Map :: #{Key => Value, _ => _}.
get(Key,Map,Default) when is_map(Map) ->
- case maps:find(Key, Map) of
- {ok, Value} ->
- Value;
- error ->
- Default
+ case Map of
+ #{Key := Value} -> Value;
+ #{} -> Default
end;
get(Key,Map,Default) ->
erlang:error({badmap,Map},[Key,Map,Default]).
--spec filter(Pred,Map1) -> Map2 when
+-spec filter(Pred, MapOrIter) -> Map when
Pred :: fun((Key, Value) -> boolean()),
- Key :: term(),
- Value :: term(),
- Map1 :: map(),
- Map2 :: map().
+ MapOrIter :: #{Key => Value} | iterator(Key, Value),
+ Map :: #{Key => Value}.
filter(Pred,Map) when is_function(Pred,2), is_map(Map) ->
- maps:from_list([{K,V}||{K,V}<-maps:to_list(Map),Pred(K,V)]);
+ maps:from_list(filter_1(Pred, iterator(Map)));
+filter(Pred,Iterator) when is_function(Pred,2), ?IS_ITERATOR(Iterator) ->
+ maps:from_list(filter_1(Pred, Iterator));
filter(Pred,Map) ->
erlang:error(error_type(Map),[Pred,Map]).
-
--spec fold(Fun,Init,Map) -> Acc when
- Fun :: fun((K, V, AccIn) -> AccOut),
+filter_1(Pred, Iter) ->
+ case next(Iter) of
+ {K, V, NextIter} ->
+ case Pred(K,V) of
+ true ->
+ [{K,V} | filter_1(Pred, NextIter)];
+ false ->
+ filter_1(Pred, NextIter)
+ end;
+ none ->
+ []
+ end.
+
+-spec fold(Fun,Init,MapOrIter) -> Acc when
+ Fun :: fun((Key, Value, AccIn) -> AccOut),
Init :: term(),
- Acc :: term(),
- AccIn :: term(),
- AccOut :: term(),
- Map :: map(),
- K :: term(),
- V :: term().
+ Acc :: AccOut,
+ AccIn :: Init | AccOut,
+ MapOrIter :: #{Key => Value} | iterator(Key, Value).
fold(Fun,Init,Map) when is_function(Fun,3), is_map(Map) ->
- lists:foldl(fun({K,V},A) -> Fun(K,V,A) end,Init,maps:to_list(Map));
+ fold_1(Fun,Init,iterator(Map));
+fold(Fun,Init,Iterator) when is_function(Fun,3), ?IS_ITERATOR(Iterator) ->
+ fold_1(Fun,Init,Iterator);
fold(Fun,Init,Map) ->
- erlang:error(error_type(Map),[Fun,Init,Map]).
+ erlang:error(error_type_iter(Map),[Fun,Init,Map]).
--spec map(Fun,Map1) -> Map2 when
- Fun :: fun((K, V1) -> V2),
- Map1 :: map(),
- Map2 :: map(),
- K :: term(),
- V1 :: term(),
- V2 :: term().
+fold_1(Fun, Acc, Iter) ->
+ case next(Iter) of
+ {K, V, NextIter} ->
+ fold_1(Fun, Fun(K,V,Acc), NextIter);
+ none ->
+ Acc
+ end.
+
+-spec map(Fun,MapOrIter) -> Map when
+ Fun :: fun((Key, Value1) -> Value2),
+ MapOrIter :: #{Key => Value1} | iterator(Key, Value1),
+ Map :: #{Key => Value2}.
map(Fun,Map) when is_function(Fun, 2), is_map(Map) ->
- maps:from_list([{K,Fun(K,V)}||{K,V}<-maps:to_list(Map)]);
+ maps:from_list(map_1(Fun, iterator(Map)));
+map(Fun,Iterator) when is_function(Fun, 2), ?IS_ITERATOR(Iterator) ->
+ maps:from_list(map_1(Fun, Iterator));
map(Fun,Map) ->
- erlang:error(error_type(Map),[Fun,Map]).
+ erlang:error(error_type_iter(Map),[Fun,Map]).
+map_1(Fun, Iter) ->
+ case next(Iter) of
+ {K, V, NextIter} ->
+ [{K, Fun(K, V)} | map_1(Fun, NextIter)];
+ none ->
+ []
+ end.
-spec size(Map) -> non_neg_integer() when
Map :: map().
@@ -242,6 +262,24 @@ size(Map) when is_map(Map) ->
size(Val) ->
erlang:error({badmap,Val},[Val]).
+-spec iterator(Map) -> Iterator when
+ Map :: #{Key => Value},
+ Iterator :: iterator(Key, Value).
+
+iterator(M) when is_map(M) -> [0 | M];
+iterator(M) -> erlang:error({badmap, M}, [M]).
+
+-spec next(Iterator) -> {Key, Value, NextIterator} | 'none' when
+ Iterator :: iterator(Key, Value),
+ NextIterator :: iterator(Key, Value).
+next({K, V, I}) ->
+ {K, V, I};
+next([Path | Map]) when is_integer(Path), is_map(Map) ->
+ erts_internal:map_next(Path, Map, iterator);
+next(none) ->
+ none;
+next(Iter) ->
+ erlang:error(badarg, [Iter]).
-spec without(Ks,Map1) -> Map2 when
Ks :: [K],
@@ -250,30 +288,29 @@ size(Val) ->
K :: term().
without(Ks,M) when is_list(Ks), is_map(M) ->
- lists:foldl(fun(K, M1) -> ?MODULE:remove(K, M1) end, M, Ks);
+ lists:foldl(fun maps:remove/2, M, Ks);
without(Ks,M) ->
erlang:error(error_type(M),[Ks,M]).
-
-spec with(Ks, Map1) -> Map2 when
Ks :: [K],
- Map1 :: map(),
- Map2 :: map(),
- K :: term().
+ Map1 :: #{K => V, _ => _},
+ Map2 :: #{K => V}.
with(Ks,Map1) when is_list(Ks), is_map(Map1) ->
- Fun = fun(K, List) ->
- case ?MODULE:find(K, Map1) of
- {ok, V} ->
- [{K, V} | List];
- error ->
- List
- end
- end,
- ?MODULE:from_list(lists:foldl(Fun, [], Ks));
+ maps:from_list(with_1(Ks, Map1));
with(Ks,M) ->
erlang:error(error_type(M),[Ks,M]).
+with_1([K|Ks], Map) ->
+ case Map of
+ #{K := V} -> [{K,V}|with_1(Ks, Map)];
+ #{} -> with_1(Ks, Map)
+ end;
+with_1([], _Map) -> [].
error_type(M) when is_map(M) -> badarg;
error_type(V) -> {badmap, V}.
+
+error_type_iter(M) when is_map(M); ?IS_ITERATOR(M) -> badarg;
+error_type_iter(V) -> {badmap, V}.
diff --git a/lib/stdlib/src/ms_transform.erl b/lib/stdlib/src/ms_transform.erl
index 6616e957c0..97ec785c62 100644
--- a/lib/stdlib/src/ms_transform.erl
+++ b/lib/stdlib/src/ms_transform.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -224,10 +224,12 @@ transform_from_shell(Dialect, Clauses, BoundEnvironment) ->
%% Called when translating during compiling
%%
--spec parse_transform(Forms, Options) -> Forms2 when
+-spec parse_transform(Forms, Options) -> Forms2 | Errors | Warnings when
Forms :: [erl_parse:abstract_form() | erl_parse:form_info()],
Forms2 :: [erl_parse:abstract_form() | erl_parse:form_info()],
- Options :: term().
+ Options :: term(),
+ Errors :: {error, ErrInfo :: [tuple()], WarnInfo :: []},
+ Warnings :: {warning, Forms2, WarnInfo :: [tuple()]}.
parse_transform(Forms, _Options) ->
SaveFilename = setup_filename(),
@@ -554,8 +556,8 @@ tg({call, Line, {remote,_,{atom,_,erlang},{atom, Line2, FunName}},ParaList},
FunName,length(ParaList)}})
end;
tg({call, Line, {remote,_,{atom,_,ModuleName},
- {atom, _, FunName}},_ParaList},B) ->
- throw({error,Line,{?ERR_GENREMOTECALL+B#tgd.eb,ModuleName,FunName}});
+ {atom, _, FunName}},ParaList},B) ->
+ throw({error,Line,{?ERR_GENREMOTECALL+B#tgd.eb,ModuleName,FunName,length(ParaList)}});
tg({cons,Line, H, T},B) ->
{cons, Line, tg(H,B), tg(T,B)};
tg({nil, Line},_B) ->
@@ -929,6 +931,7 @@ bool_test(is_port,1) -> true;
bool_test(is_reference,1) -> true;
bool_test(is_tuple,1) -> true;
bool_test(is_map,1) -> true;
+bool_test(is_map_key, 2) -> true;
bool_test(is_binary,1) -> true;
bool_test(is_function,1) -> true;
bool_test(is_record,2) -> true;
@@ -943,7 +946,9 @@ real_guard_function(node,0) -> true;
real_guard_function(node,1) -> true;
real_guard_function(round,1) -> true;
real_guard_function(size,1) -> true;
+real_guard_function(bit_size,1) -> true;
real_guard_function(map_size,1) -> true;
+real_guard_function(map_get,2) -> true;
real_guard_function(tl,1) -> true;
real_guard_function(trunc,1) -> true;
real_guard_function(self,0) -> true;
@@ -1115,5 +1120,3 @@ normalise_list([H|T]) ->
[normalise(H)|normalise_list(T)];
normalise_list([]) ->
[].
-
-
diff --git a/lib/stdlib/src/ordsets.erl b/lib/stdlib/src/ordsets.erl
index 569407f5ef..176047079b 100644
--- a/lib/stdlib/src/ordsets.erl
+++ b/lib/stdlib/src/ordsets.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -19,7 +19,7 @@
-module(ordsets).
--export([new/0,is_set/1,size/1,to_list/1,from_list/1]).
+-export([new/0,is_set/1,size/1,is_empty/1,to_list/1,from_list/1]).
-export([is_element/2,add_element/2,del_element/2]).
-export([union/2,union/1,intersection/2,intersection/1]).
-export([is_disjoint/2]).
@@ -60,6 +60,13 @@ is_set([], _) -> true.
size(S) -> length(S).
+%% is_empty(OrdSet) -> boolean().
+%% Return 'true' if OrdSet is an empty set, otherwise 'false'.
+-spec is_empty(Ordset) -> boolean() when
+ Ordset :: ordset(_).
+
+is_empty(S) -> S=:=[].
+
%% to_list(OrdSet) -> [Elem].
%% Return the elements in OrdSet as a list.
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index 5b488cc677..fa34f19637 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -44,8 +44,19 @@ obsolete(Module, Name, Arity) ->
no
end.
-obsolete_1(net, _, _) ->
- {deprecated, "module 'net' obsolete; use 'net_adm'"};
+obsolete_1(net, call, 4) ->
+ {deprecated, {rpc, call, 4}};
+obsolete_1(net, cast, 4) ->
+ {deprecated, {rpc, cast, 4}};
+obsolete_1(net, broadcast, 3) ->
+ {deprecated, {rpc, eval_everywhere, 3}};
+obsolete_1(net, ping, 1) ->
+ {deprecated, {net_adm, ping, 1}};
+obsolete_1(net, sleep, 1) ->
+ {deprecated, "Use 'receive after T -> ok end' instead"};
+obsolete_1(net, relay, 1) ->
+ {deprecated, {slave, relay, 1}};
+
obsolete_1(erlang, now, 0) ->
{deprecated,
@@ -55,6 +66,14 @@ obsolete_1(erlang, now, 0) ->
obsolete_1(calendar, local_time_to_universal_time, 1) ->
{deprecated, {calendar, local_time_to_universal_time_dst, 1}};
+%% *** STDLIB added in OTP 22 ***
+
+obsolete_1(sys, get_debug, 3) ->
+ {deprecated,
+ "Deprecated function. "
+ "Incorrectly documented and in fact only for internal use. "
+ "Can often be replaced with sys:get_log/1."};
+
%% *** STDLIB added in OTP 20 ***
obsolete_1(gen_fsm, start, 3) ->
@@ -304,90 +323,6 @@ obsolete_1(snmp, N, A) ->
obsolete_1(snmpa, old_info_format, 1) ->
{deprecated, "Deprecated; (will be removed in OTP 18); use \"new\" format instead"};
-obsolete_1(snmpm, agent_info, 3) ->
- {removed, {snmpm, agent_info, 2}, "R16B"};
-obsolete_1(snmpm, update_agent_info, 5) ->
- {removed, {snmpm, update_agent_info, 4}, "R16B"};
-obsolete_1(snmpm, g, 3) ->
- {removed, {snmpm, sync_get, 3}, "R16B"};
-obsolete_1(snmpm, g, 4) ->
- {removed, {snmpm, sync_get, [3,4]}, "R16B"};
-obsolete_1(snmpm, g, 5) ->
- {removed, {snmpm, sync_get, [4,5]}, "R16B"};
-obsolete_1(snmpm, g, 6) ->
- {removed, {snmpm, sync_get, [5,6]}, "R16B"};
-obsolete_1(snmpm, g, 7) ->
- {removed, {snmpm, sync_get, 6}, "R16B"};
-obsolete_1(snmpm, ag, 3) ->
- {removed, {snmpm, async_get, 3}, "R16B"};
-obsolete_1(snmpm, ag, 4) ->
- {removed, {snmpm, async_get, [3,4]}, "R16B"};
-obsolete_1(snmpm, ag, 5) ->
- {removed, {snmpm, async_get, [4,5]}, "R16B"};
-obsolete_1(snmpm, ag, 6) ->
- {removed, {snmpm, async_get, [5,6]}, "R16B"};
-obsolete_1(snmpm, ag, 7) ->
- {removed, {snmpm, async_get, 6}, "R16B"};
-obsolete_1(snmpm, gn, 3) ->
- {removed, {snmpm, sync_get_next, 3}, "R16B"};
-obsolete_1(snmpm, gn, 4) ->
- {removed, {snmpm, sync_get_next, [3,4]}, "R16B"};
-obsolete_1(snmpm, gn, 5) ->
- {removed, {snmpm, sync_get_next, [4,5]}, "R16B"};
-obsolete_1(snmpm, gn, 6) ->
- {removed, {snmpm, sync_get_next, [5,6]}, "R16B"};
-obsolete_1(snmpm, gn, 7) ->
- {removed, {snmpm, sync_get_next, 6}, "R16B"};
-obsolete_1(snmpm, agn, 3) ->
- {removed, {snmpm, async_get_next, 3}, "R16B"};
-obsolete_1(snmpm, agn, 4) ->
- {removed, {snmpm, async_get_next, [3,4]}, "R16B"};
-obsolete_1(snmpm, agn, 5) ->
- {removed, {snmpm, async_get_next, [4,5]}, "R16B"};
-obsolete_1(snmpm, agn, 6) ->
- {removed, {snmpm, async_get_next, [5,6]}, "R16B"};
-obsolete_1(snmpm, agn, 7) ->
- {removed, {snmpm, async_get_next, 6}, "R16B"};
-obsolete_1(snmpm, s, 3) ->
- {removed, {snmpm, sync_set, 3}, "R16B"};
-obsolete_1(snmpm, s, 4) ->
- {removed, {snmpm, sync_set, [3,4]}, "R16B"};
-obsolete_1(snmpm, s, 5) ->
- {removed, {snmpm, sync_set, [4,5]}, "R16B"};
-obsolete_1(snmpm, s, 6) ->
- {removed, {snmpm, sync_set, [5,6]}, "R16B"};
-obsolete_1(snmpm, s, 7) ->
- {removed, {snmpm, sync_set, 6}, "R16B"};
-obsolete_1(snmpm, as, 3) ->
- {removed, {snmpm, async_set, 3}, "R16B"};
-obsolete_1(snmpm, as, 4) ->
- {removed, {snmpm, async_set, [3,4]}, "R16B"};
-obsolete_1(snmpm, as, 5) ->
- {removed, {snmpm, async_set, [4,5]}, "R16B"};
-obsolete_1(snmpm, as, 6) ->
- {removed, {snmpm, async_set, [5,6]}, "R16B"};
-obsolete_1(snmpm, as, 7) ->
- {removed, {snmpm, async_set, 6}, "R16B"};
-obsolete_1(snmpm, gb, 5) ->
- {removed, {snmpm, sync_get_bulk, 5}, "R16B"};
-obsolete_1(snmpm, gb, 6) ->
- {removed, {snmpm, sync_get_bulk, [5,6]}, "R16B"};
-obsolete_1(snmpm, gb, 7) ->
- {removed, {snmpm, sync_get_bulk, [6,7]}, "R16B"};
-obsolete_1(snmpm, gb, 8) ->
- {removed, {snmpm, sync_get_bulk, [7,8]}, "R16B"};
-obsolete_1(snmpm, gb, 9) ->
- {removed, {snmpm, sync_get_bulk, 8}, "R16B"};
-obsolete_1(snmpm, agb, 5) ->
- {removed, {snmpm, async_get_bulk, 5}, "R16B"};
-obsolete_1(snmpm, agb, 6) ->
- {removed, {snmpm, async_get_bulk, [5,6]}, "R16B"};
-obsolete_1(snmpm, agb, 7) ->
- {removed, {snmpm, async_get_bulk, [6,7]}, "R16B"};
-obsolete_1(snmpm, agb, 8) ->
- {removed, {snmpm, async_get_bulk, [7,8]}, "R16B"};
-obsolete_1(snmpm, agb, 9) ->
- {removed, {snmpm, async_get_bulk, 8}, "R16B"};
%% *** MEGACO ***
@@ -398,10 +333,9 @@ obsolete_1(megaco, format_versions, 1) ->
%% *** OS-MON-MIB ***
-obsolete_1(os_mon_mib, init, 1) ->
- {deprecated, {os_mon_mib, load, 1}};
-obsolete_1(os_mon_mib, stop, 1) ->
- {deprecated, {os_mon_mib, unload, 1}};
+%% FIXME: Remove this warning in OTP 24.
+obsolete_1(os_mon_mib, _, _) ->
+ {removed, "was removed in 22.0"};
obsolete_1(auth, is_auth, 1) ->
{deprecated, {net_adm, ping, 1}};
@@ -414,64 +348,6 @@ obsolete_1(auth, node_cookie, 1) ->
obsolete_1(auth, node_cookie, 2) ->
{deprecated, "Deprecated; use erlang:set_cookie/2 and net_adm:ping/1 instead"};
-obsolete_1(http, request, 1) -> {removed,{httpc,request,1},"R15B"};
-obsolete_1(http, request, 2) -> {removed,{httpc,request,2},"R15B"};
-obsolete_1(http, request, 4) -> {removed,{httpc,request,4},"R15B"};
-obsolete_1(http, request, 5) -> {removed,{httpc,request,5},"R15B"};
-obsolete_1(http, cancel_request, 1) -> {removed,{httpc,cancel_request,1},"R15B"};
-obsolete_1(http, cancel_request, 2) -> {removed,{httpc,cancel_request,2},"R15B"};
-obsolete_1(http, set_option, 2) -> {removed,{httpc,set_option,2},"R15B"};
-obsolete_1(http, set_option, 3) -> {removed,{httpc,set_option,3},"R15B"};
-obsolete_1(http, set_options, 1) -> {removed,{httpc,set_options,1},"R15B"};
-obsolete_1(http, set_options, 2) -> {removed,{httpc,set_options,2},"R15B"};
-obsolete_1(http, verify_cookies, 2) -> {removed,{httpc,store_cookies,2},"R15B"};
-obsolete_1(http, verify_cookies, 3) -> {removed,{httpc,store_cookies,3},"R15B"};
-obsolete_1(http, cookie_header, 1) -> {removed,{httpc,cookie_header,1},"R15B"};
-obsolete_1(http, cookie_header, 2) -> {removed,{httpc,cookie_header,2},"R15B"};
-obsolete_1(http, stream_next, 1) -> {removed,{httpc,stream_next,1},"R15B"};
-obsolete_1(http, default_profile, 0) -> {removed,{httpc,default_profile,0},"R15B"};
-
-%% Added in R13A.
-obsolete_1(regexp, _, _) ->
- {removed, "removed in R15; use the re module instead"};
-
-%% Added in R13B04.
-obsolete_1(erlang, concat_binary, 1) ->
- {removed,{erlang,list_to_binary,1},"R15B"};
-
-%% Added in R14A.
-obsolete_1(ssl, peercert, 2) ->
- {removed ,"removed in R15A; use ssl:peercert/1 and public_key:pkix_decode_cert/2 instead"};
-
-%% Added in R14B.
-obsolete_1(public_key, pem_to_der, 1) ->
- {removed,"removed in R15A; use file:read_file/1 and public_key:pem_decode/1"};
-obsolete_1(public_key, decode_private_key, A) when A =:= 1; A =:= 2 ->
- {removed, "removed in R15A; use public_key:pem_entry_decode/1"};
-
-%% Added in R14B03.
-obsolete_1(docb_gen, _, _) ->
- {removed,"the DocBuilder application was removed in R15B"};
-obsolete_1(docb_transform, _, _) ->
- {removed,"the DocBuilder application was removed in R15B"};
-obsolete_1(docb_xml_check, _, _) ->
- {removed,"the DocBuilder application was removed in R15B"};
-
-%% Added in R15B
-obsolete_1(asn1rt, F, _) when F == load_driver; F == unload_driver ->
- {removed,"removed (will be removed in OTP 18); has no effect as drivers are no longer used"};
-obsolete_1(ssl, pid, 1) ->
- {removed,"was removed in R16; is no longer needed"};
-obsolete_1(inviso, _, _) ->
- {removed,"the inviso application was removed in R16"};
-
-%% Added in R15B01.
-obsolete_1(ssh, sign_data, 2) ->
- {removed,"removed in R16A; use public_key:pem_decode/1, public_key:pem_entry_decode/1 "
- "and public_key:sign/3 instead"};
-obsolete_1(ssh, verify_data, 3) ->
- {removed,"removed in R16A; use public_key:ssh_decode/1, and public_key:verify/4 instead"};
-
%% Added in R16
obsolete_1(wxCalendarCtrl, enableYearChange, _) -> %% wx bug documented?
{deprecated,"deprecated function not available in wxWidgets-2.9 and later"};
@@ -592,10 +468,8 @@ obsolete_1(queue, lait, 1) ->
%% Removed in OTP 19.
-obsolete_1(overload, _, _) ->
- {removed, "removed in OTP 19"};
obsolete_1(rpc, safe_multi_server_call, A) when A =:= 2; A =:= 3 ->
- {removed, {rpc, multi_server_call, A}, "removed in OTP 19"};
+ {removed, {rpc, multi_server_call, A}, "19.0"};
%% Added in OTP 20.
@@ -604,11 +478,25 @@ obsolete_1(filename, find_src, 1) ->
obsolete_1(filename, find_src, 2) ->
{deprecated, "deprecated; use filelib:find_source/3 instead"};
+obsolete_1(erlang, get_stacktrace, 0) ->
+ {deprecated, "deprecated; use the new try/catch syntax for retrieving the stack backtrace"};
+
%% Removed in OTP 20.
obsolete_1(erlang, hash, 2) ->
{removed, {erlang, phash2, 2}, "20.0"};
+%% Add in OTP 21.
+
+obsolete_1(ssl, ssl_accept, 1) ->
+ {deprecated, "deprecated; use ssl:handshake/1 instead"};
+obsolete_1(ssl, ssl_accept, 2) ->
+ {deprecated, "deprecated; use ssl:handshake/2 instead"};
+obsolete_1(ssl, ssl_accept, 3) ->
+ {deprecated, "deprecated; use ssl:handshake/3 instead"};
+obsolete_1(otp_mib, F, _) when F =:= load; F =:= unload ->
+ {deprecated, "deprecated; functionality will be removed in a future release"};
+
%% not obsolete
obsolete_1(_, _, _) ->
diff --git a/lib/stdlib/src/pool.erl b/lib/stdlib/src/pool.erl
index 05950a1d7c..599be55607 100644
--- a/lib/stdlib/src/pool.erl
+++ b/lib/stdlib/src/pool.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,7 +25,7 @@
%% with the least load !!!!
%% This function is callable from any node including the master
%% That is part of the pool
-%% nodes are scheduled on a per usgae basis and per load basis,
+%% nodes are scheduled on a per usage basis and per load basis,
%% Whenever we use a node, we put at the end of the queue, and whenever
%% a node report a change in load, we insert it accordingly
@@ -197,7 +197,7 @@ pure_insert({Load,Node},[{L,N}|Tail]) when Load < L ->
pure_insert(L,[H|T]) -> [H|pure_insert(L,T)].
%% Really should not measure the contributions from
-%% the back ground processes here .... which we do :-(
+%% the background processes here .... which we do :-(
%% We don't have to monitor the master, since we're slaves anyway
statistic_collector() ->
@@ -213,7 +213,7 @@ statistic_collector(I) ->
stat_loop(M, 999999)
end.
-%% Do not tell the master about our load if it has not changed
+%% Do not tell the master about our load if it has not changed
stat_loop(M, Old) ->
sleep(2000),
diff --git a/lib/stdlib/src/proc_lib.erl b/lib/stdlib/src/proc_lib.erl
index 8e10cbe93b..cfbaf8b242 100644
--- a/lib/stdlib/src/proc_lib.erl
+++ b/lib/stdlib/src/proc_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -30,7 +30,7 @@
start/3, start/4, start/5, start_link/3, start_link/4, start_link/5,
hibernate/3,
init_ack/1, init_ack/2,
- init_p/3,init_p/5,format/1,format/2,format/3,
+ init_p/3,init_p/5,format/1,format/2,format/3,report_cb/2,
initial_call/1,
translate_initial_call/1,
stop/1, stop/3]).
@@ -40,6 +40,8 @@
-export_type([spawn_option/0]).
+-include("logger.hrl").
+
%%-----------------------------------------------------------------------------
-type priority_level() :: 'high' | 'low' | 'max' | 'normal'.
@@ -231,8 +233,8 @@ init_p(Parent, Ancestors, Fun) when is_function(Fun) ->
try
Fun()
catch
- Class:Reason ->
- exit_p(Class, Reason, erlang:get_stacktrace())
+ Class:Reason:Stacktrace ->
+ exit_p(Class, Reason, Stacktrace)
end.
-spec init_p(pid(), [pid()], atom(), atom(), [term()]) -> term().
@@ -246,8 +248,8 @@ init_p_do_apply(M, F, A) ->
try
apply(M, F, A)
catch
- Class:Reason ->
- exit_p(Class, Reason, erlang:get_stacktrace())
+ Class:Reason:Stacktrace ->
+ exit_p(Class, Reason, Stacktrace)
end.
-spec wake_up(atom(), atom(), [term()]) -> term().
@@ -256,8 +258,8 @@ wake_up(M, F, A) when is_atom(M), is_atom(F), is_list(A) ->
try
apply(M, F, A)
catch
- Class:Reason ->
- exit_p(Class, Reason, erlang:get_stacktrace())
+ Class:Reason:Stacktrace ->
+ exit_p(Class, Reason, Stacktrace)
end.
exit_p(Class, Reason, Stacktrace) ->
@@ -503,10 +505,13 @@ crash_report(exit, normal, _, _) -> ok;
crash_report(exit, shutdown, _, _) -> ok;
crash_report(exit, {shutdown,_}, _, _) -> ok;
crash_report(Class, Reason, StartF, Stacktrace) ->
- OwnReport = my_info(Class, Reason, StartF, Stacktrace),
- LinkReport = linked_info(self()),
- Rep = [OwnReport,LinkReport],
- error_logger:error_report(crash_report, Rep).
+ ?LOG_ERROR(#{label=>{proc_lib,crash},
+ report=>[my_info(Class, Reason, StartF, Stacktrace),
+ linked_info(self())]},
+ #{domain=>[otp,sasl],
+ report_cb=>fun proc_lib:report_cb/2,
+ logger_formatter=>#{title=>"CRASH REPORT"},
+ error_logger=>#{tag=>error_report,type=>crash_report}}).
my_info(Class, Reason, [], Stacktrace) ->
my_info_1(Class, Reason, Stacktrace);
@@ -742,9 +747,20 @@ check({badrpc,Error}) -> Error;
check(Res) -> Res.
%%% -----------------------------------------------------------
-%%% Format (and write) a generated crash info structure.
+%%% Format a generated crash info structure.
%%% -----------------------------------------------------------
+-spec report_cb(CrashReport,FormatOpts) -> unicode:chardata() when
+ CrashReport :: #{label => {proc_lib,crash},
+ report => [term()]},
+ FormatOpts :: logger:report_cb_config().
+report_cb(#{label:={proc_lib,crash}, report:=CrashReport}, Extra) ->
+ Default = #{chars_limit => unlimited,
+ depth => unlimited,
+ single_line => false,
+ encoding => utf8},
+ do_format(CrashReport, maps:merge(Default,Extra)).
+
-spec format(CrashReport) -> string() when
CrashReport :: [term()].
format(CrashReport) ->
@@ -762,32 +778,51 @@ format(CrashReport, Encoding) ->
Encoding :: latin1 | unicode | utf8,
Depth :: unlimited | pos_integer().
-format([OwnReport,LinkReport], Encoding, Depth) ->
- Extra = {Encoding,Depth},
- MyIndent = " ",
+format(CrashReport, Encoding, Depth) ->
+ do_format(CrashReport, #{chars_limit => unlimited,
+ depth => Depth,
+ encoding => Encoding,
+ single_line => false}).
+
+do_format([OwnReport,LinkReport], #{single_line:=Single}=Extra) ->
+ Indent = if Single -> "";
+ true -> " "
+ end,
+ MyIndent = Indent ++ Indent,
+ Sep = nl(Single,"; "),
OwnFormat = format_report(OwnReport, MyIndent, Extra),
- LinkFormat = format_link_report(LinkReport, MyIndent, Extra),
- Str = io_lib:format(" crasher:~n~ts neighbours:~n~ts",
- [OwnFormat, LinkFormat]),
+ LinkFormat = lists:join(Sep,format_link_report(LinkReport, MyIndent, Extra)),
+ Nl = nl(Single," "),
+ Str = io_lib:format("~scrasher:"++Nl++"~ts"++Sep++"~sneighbours:"++Nl++"~ts",
+ [Indent,OwnFormat,Indent,LinkFormat]),
lists:flatten(Str).
-format_link_report([Link|Reps], Indent, Extra) ->
+format_link_report([Link|Reps], Indent0, #{single_line:=Single}=Extra) ->
Rep = case Link of
{neighbour,Rep0} -> Rep0;
_ -> Link
end,
+ Indent = if Single -> "";
+ true -> Indent0
+ end,
LinkIndent = [" ",Indent],
- [Indent,"neighbour:\n",format_report(Rep, LinkIndent, Extra)|
+ [[Indent,"neighbour:",nl(Single," "),format_report(Rep, LinkIndent, Extra)]|
format_link_report(Reps, Indent, Extra)];
format_link_report(Rep, Indent, Extra) ->
format_report(Rep, Indent, Extra).
-format_report(Rep, Indent, Extra) when is_list(Rep) ->
- format_rep(Rep, Indent, Extra);
-format_report(Rep, Indent, {Enc,unlimited}) ->
- io_lib:format("~s~"++modifier(Enc)++"p~n", [Indent, Rep]);
-format_report(Rep, Indent, {Enc,Depth}) ->
- io_lib:format("~s~"++modifier(Enc)++"P~n", [Indent, Rep, Depth]).
+format_report(Rep, Indent, #{single_line:=Single}=Extra) when is_list(Rep) ->
+ lists:join(nl(Single,", "),format_rep(Rep, Indent, Extra));
+format_report(Rep, Indent0, #{encoding:=Enc,depth:=Depth,
+ chars_limit:=Limit,single_line:=Single}) ->
+ {P,Tl} = p(Enc,Depth),
+ {Indent,Width} = if Single -> {"","0"};
+ true -> {Indent0,""}
+ end,
+ Opts = if is_integer(Limit) -> [{chars_limit,Limit}];
+ true -> []
+ end,
+ io_lib:format("~s~"++Width++P, [Indent, Rep | Tl], Opts).
format_rep([{initial_call,InitialCall}|Rep], Indent, Extra) ->
[format_mfa(Indent, InitialCall, Extra)|format_rep(Rep, Indent, Extra)];
@@ -799,19 +834,32 @@ format_rep([{Tag,Data}|Rep], Indent, Extra) ->
format_rep(_, _, _Extra) ->
[].
-format_exception(Class, Reason, StackTrace, {Enc,_}=Extra) ->
+format_exception(Class, Reason, StackTrace,
+ #{encoding:=Enc,depth:=Depth,chars_limit:=Limit,
+ single_line:=Single}=Extra) ->
PF = pp_fun(Extra),
StackFun = fun(M, _F, _A) -> (M =:= erl_eval) or (M =:= ?MODULE) end,
- %% EI = " exception: ",
- EI = " ",
- [EI, lib:format_exception(1+length(EI), Class, Reason,
- StackTrace, StackFun, PF, Enc), "\n"].
+ if Single ->
+ {P,Tl} = p(Enc,Depth),
+ Opts = if is_integer(Limit) -> [{chars_limit,Limit}];
+ true -> []
+ end,
+ [atom_to_list(Class), ": ",
+ io_lib:format("~0"++P,[{Reason,StackTrace}|Tl],Opts)];
+ true ->
+ EI = " ",
+ [EI, erl_error:format_exception(1+length(EI), Class, Reason,
+ StackTrace, StackFun, PF, Enc)]
+ end.
-format_mfa(Indent, {M,F,Args}=StartF, {Enc,_}=Extra) ->
+format_mfa(Indent0, {M,F,Args}=StartF, #{encoding:=Enc,single_line:=Single}=Extra) ->
+ Indent = if Single -> "";
+ true -> Indent0
+ end,
try
A = length(Args),
[Indent,"initial call: ",atom_to_list(M),$:,to_string(F, Enc),$/,
- integer_to_list(A),"\n"]
+ integer_to_list(A)]
catch
error:_ ->
format_tag(Indent, initial_call, StartF, Extra)
@@ -822,15 +870,29 @@ to_string(A, latin1) ->
to_string(A, _) ->
io_lib:write_atom(A).
-pp_fun({Enc,Depth}) ->
+pp_fun(#{encoding:=Enc,depth:=Depth,chars_limit:=Limit,single_line:=Single}) ->
{P,Tl} = p(Enc, Depth),
+ Width = if Single -> "0";
+ true -> ""
+ end,
+ Opts = if is_integer(Limit) -> [{chars_limit,Limit}];
+ true -> []
+ end,
fun(Term, I) ->
- io_lib:format("~." ++ integer_to_list(I) ++ P, [Term|Tl])
+ io_lib:format("~" ++ Width ++ "." ++ integer_to_list(I) ++ P,
+ [Term|Tl], Opts)
end.
-format_tag(Indent, Tag, Data, {Enc,Depth}) ->
+format_tag(Indent0, Tag, Data, #{encoding:=Enc,depth:=Depth,chars_limit:=Limit,single_line:=Single}) ->
{P,Tl} = p(Enc, Depth),
- io_lib:format("~s~p: ~80.18" ++ P ++ "\n", [Indent, Tag, Data|Tl]).
+ {Indent,Width} = if Single -> {"","0"};
+ true -> {Indent0,""}
+ end,
+ Opts = if is_integer(Limit) -> [{chars_limit,Limit}];
+ true -> []
+ end,
+ io_lib:format("~s~" ++ Width ++ "p: ~" ++ Width ++ ".18" ++ P,
+ [Indent, Tag, Data|Tl], Opts).
p(Encoding, Depth) ->
{Letter, Tl} = case Depth of
@@ -843,6 +905,8 @@ p(Encoding, Depth) ->
modifier(latin1) -> "";
modifier(_) -> "t".
+nl(true,Else) -> Else;
+nl(false,_) -> "\n".
%%% -----------------------------------------------------------
%%% Stop a process and wait for it to terminate
diff --git a/lib/stdlib/src/qlc.erl b/lib/stdlib/src/qlc.erl
index f11f9d0a0b..a1c1117e31 100644
--- a/lib/stdlib/src/qlc.erl
+++ b/lib/stdlib/src/qlc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -301,11 +301,11 @@ eval(QH, Options) ->
post_funs(Post)
end
end
- catch Term ->
- case erlang:get_stacktrace() of
+ catch throw:Term:Stacktrace ->
+ case Stacktrace of
[?THROWN_ERROR | _] ->
Term;
- Stacktrace ->
+ _ ->
erlang:raise(throw, Term, Stacktrace)
end
end
@@ -359,11 +359,11 @@ fold(Fun, Acc0, QH, Options) ->
post_funs(Post)
end
end
- catch Term ->
- case erlang:get_stacktrace() of
+ catch throw:Term:Stacktrace ->
+ case Stacktrace of
[?THROWN_ERROR | _] ->
Term;
- Stacktrace ->
+ _ ->
erlang:raise(throw, Term, Stacktrace)
end
end
@@ -457,11 +457,11 @@ info(QH, Options) ->
debug -> % Not documented. Intended for testing only.
Info
end
- catch Term ->
- case erlang:get_stacktrace() of
+ catch throw:Term:Stacktrace ->
+ case Stacktrace of
[?THROWN_ERROR | _] ->
Term;
- Stacktrace ->
+ _ ->
erlang:raise(throw, Term, Stacktrace)
end
end
@@ -638,7 +638,7 @@ string_to_handle(Str, Options, Bindings) when is_list(Str) ->
case erl_scan:string(Str, 1, [text]) of
{ok, Tokens, _} ->
ScanRes =
- case lib:extended_parse_exprs(Tokens) of
+ case erl_eval:extended_parse_exprs(Tokens) of
{ok, [Expr0], SBs} ->
{ok, Expr0, SBs};
{ok, _ExprList, _SBs} ->
@@ -1056,9 +1056,9 @@ cursor_process(H, GUnique, GCache, TmpDir, SpawnOptions, MaxList, TmpUsage) ->
Prep = prepare_qlc(H, not_a_list, GUnique, GCache,
TmpDir, MaxList, TmpUsage),
setup_qlc(Prep, Setup)
- catch Class:Reason ->
- Parent ! {self(), {caught, Class, Reason,
- erlang:get_stacktrace()}},
+ catch Class:Reason:Stacktrace ->
+ Parent ! {self(),
+ {caught, Class, Reason, Stacktrace}},
exit(normal)
end,
Parent ! {self(), ok},
@@ -1075,8 +1075,8 @@ parent_fun(Pid, Parent) ->
{TPid, {parent_fun, Fun}} ->
V = try
{value, Fun()}
- catch Class:Reason ->
- {parent_fun_caught, Class, Reason, erlang:get_stacktrace()}
+ catch Class:Reason:Stacktrace ->
+ {parent_fun_caught, Class, Reason, Stacktrace}
end,
TPid ! {Parent, V},
parent_fun(Pid, Parent);
@@ -1101,9 +1101,9 @@ reply(Parent, MonRef, Post, Cont) ->
throw_error(Cont)
end
catch
- Class:Reason ->
+ Class:Reason:Stacktrace ->
post_funs(Post),
- Message = {caught, Class, Reason, erlang:get_stacktrace()},
+ Message = {caught, Class, Reason, Stacktrace},
Parent ! {self(), Message},
exit(normal)
end,
@@ -1196,8 +1196,8 @@ abstract1({table, TableDesc}, _NElements, _Depth, _A) ->
{ok, Tokens, _} =
erl_scan:string(lists:flatten(TableDesc++"."), 1, [text]),
{ok, Es, Bs} =
- lib:extended_parse_exprs(Tokens),
- [Expr] = lib:subst_values_for_vars(Es, Bs),
+ erl_eval:extended_parse_exprs(Tokens),
+ [Expr] = erl_eval:subst_values_for_vars(Es, Bs),
special(Expr);
false -> % abstract expression
TableDesc
@@ -1392,9 +1392,8 @@ next_loop(Pid, L, N) when N =/= 0 ->
{caught, throw, Error, [?THROWN_ERROR | _]} ->
Error;
{caught, Class, Reason, Stacktrace} ->
- CurrentStacktrace = try erlang:error(foo)
- catch error:_ -> erlang:get_stacktrace()
- end,
+ {current_stacktrace, CurrentStacktrace} =
+ erlang:process_info(self(), current_stacktrace),
erlang:raise(Class, Reason, Stacktrace ++ CurrentStacktrace);
error ->
erlang:error({qlc_cursor_pid_no_longer_exists, Pid})
@@ -2627,9 +2626,9 @@ table_handle(#qlc_table{trav_fun = TraverseFun, trav_MS = TravMS,
Parent =:= self() ->
try
ParentFun()
- catch Class:Reason ->
+ catch Class:Reason:Stacktrace ->
post_funs(Post),
- erlang:raise(Class, Reason, erlang:get_stacktrace())
+ erlang:raise(Class, Reason, Stacktrace)
end;
true ->
case monitor_request(Parent, {parent_fun, ParentFun}) of
@@ -3033,9 +3032,9 @@ file_sort_handle(H, Kp, SortOptions, TmpDir, Compressed, Post, LocalPost) ->
{terms, BTerms} ->
try
{[binary_to_term(B) || B <- BTerms], Post, LocalPost}
- catch Class:Reason ->
+ catch Class:Reason:Stacktrace ->
post_funs(Post),
- erlang:raise(Class, Reason, erlang:get_stacktrace())
+ erlang:raise(Class, Reason, Stacktrace)
end
end.
@@ -3045,9 +3044,9 @@ do_sort(In, Out, Sort, SortOptions, Post) ->
{error, Reason} -> throw_reason(Reason);
Reply -> Reply
end
- catch Class:Term ->
+ catch Class:Term:Stacktrace ->
post_funs(Post),
- erlang:raise(Class, Term, erlang:get_stacktrace())
+ erlang:raise(Class, Term, Stacktrace)
end.
do_sort(In, Out, sort, SortOptions) ->
@@ -3750,7 +3749,7 @@ maybe_error_logger(Name, Why) ->
expand_stacktrace(),
Trimmer = fun(M, _F, _A) -> M =:= erl_eval end,
Formater = fun(Term, I) -> io_lib:print(Term, I, 80, -1) end,
- X = lib:format_stacktrace(1, Stacktrace, Trimmer, Formater),
+ X = erl_error:format_stacktrace(1, Stacktrace, Trimmer, Formater),
error_logger:Name("qlc: temporary file was needed for ~w\n~ts\n",
[Why, lists:flatten(X)]).
@@ -3797,9 +3796,9 @@ call(undefined, _Arg, Default, _Post) ->
call(Fun, Arg, _Default, Post) ->
try
Fun(Arg)
- catch Class:Reason ->
+ catch Class:Reason:Stacktrace ->
post_funs(Post),
- erlang:raise(Class, Reason, erlang:get_stacktrace())
+ erlang:raise(Class, Reason, Stacktrace)
end.
grd(undefined, _Arg) ->
diff --git a/lib/stdlib/src/rand.erl b/lib/stdlib/src/rand.erl
index 7a8a5e6d4a..3a9a1e007b 100644
--- a/lib/stdlib/src/rand.erl
+++ b/lib/stdlib/src/rand.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,8 +21,8 @@
%% Multiple PRNG module for Erlang/OTP
%% Copyright (c) 2015-2016 Kenji Rikitake
%%
-%% exrop (xoroshiro116+) added and statistical distribution
-%% improvements by the Erlang/OTP team 2017
+%% exrop (xoroshiro116+) added, statistical distribution
+%% improvements and uniform_real added by the Erlang/OTP team 2017
%% =====================================================================
-module(rand).
@@ -30,16 +30,26 @@
-export([seed_s/1, seed_s/2, seed/1, seed/2,
export_seed/0, export_seed_s/1,
uniform/0, uniform/1, uniform_s/1, uniform_s/2,
+ uniform_real/0, uniform_real_s/1,
jump/0, jump/1,
- normal/0, normal/2, normal_s/1, normal_s/3
+ normal/0, normal/2, normal_s/1, normal_s/3
]).
--compile({inline, [exs64_next/1, exsplus_next/1,
+%% Test, dev and internal
+-export([exro928_jump_2pow512/1, exro928_jump_2pow20/1,
+ exro928_seed/1, exro928_next/1, exro928_next_state/1,
+ format_jumpconst58/1, seed58/2]).
+
+%% Debug
+-export([make_float/3, float2str/1, bc64/1]).
+
+-compile({inline, [exs64_next/1, exsplus_next/1, exsss_next/1,
exs1024_next/1, exs1024_calc/2,
+ exro928_next_state/4,
exrop_next/1, exrop_next_s/2,
get_52/1, normal_kiwi/1]}).
--define(DEFAULT_ALG_HANDLER, exrop).
+-define(DEFAULT_ALG_HANDLER, exsss).
-define(SEED_DICT, rand_seed).
%% =====================================================================
@@ -60,6 +70,10 @@
%% N i evaluated 3 times
(?BSL((Bits), (X), (N)) bor ((X) bsr ((Bits)-(N))))).
+-define(
+ BC(V, N),
+ bc((V), ?BIT((N) - 1), N)).
+
%%-define(TWO_POW_MINUS53, (math:pow(2, -53))).
-define(TWO_POW_MINUS53, 1.11022302462515657e-16).
@@ -72,8 +86,8 @@
%% This depends on the algorithm handler function
-type alg_state() ::
- exs64_state() | exsplus_state() | exs1024_state() |
- exrop_state() | term().
+ exsplus_state() | exro928_state() | exrop_state() | exs1024_state() |
+ exs64_state() | term().
%% This is the algorithm handling definition within this module,
%% and the type to use for plugins.
@@ -84,14 +98,21 @@
%% The 'bits' field indicates how many bits the integer
%% returned from 'next' has got, i.e 'next' shall return
%% an random integer in the range 0..(2^Bits - 1).
-%% At least 53 bits is required for the floating point
-%% producing fallbacks. This field is only used when
-%% the 'uniform' or 'uniform_n' fields are not defined.
+%% At least 55 bits is required for the floating point
+%% producing fallbacks, but 56 bits would be more future proof.
%%
%% The fields 'next', 'uniform' and 'uniform_n'
-%% implement the algorithm. If 'uniform' or 'uinform_n'
+%% implement the algorithm. If 'uniform' or 'uniform_n'
%% is not present there is a fallback using 'next' and either
-%% 'bits' or the deprecated 'max'.
+%% 'bits' or the deprecated 'max'. The 'next' function
+%% must generate a word with at least 56 good random bits.
+%%
+%% The 'weak_low_bits' field indicate how many bits are of
+%% lesser quality and they will not be used by the floating point
+%% producing functions, nor by the range producing functions
+%% when more bits are needed, to avoid weak bits in the middle
+%% of the generated bits. The lowest bits from the range
+%% functions still have the generator's quality.
%%
-type alg_handler() ::
#{type := alg(),
@@ -109,14 +130,17 @@
%% Algorithm state
-type state() :: {alg_handler(), alg_state()}.
--type builtin_alg() :: exs64 | exsplus | exsp | exs1024 | exs1024s | exrop.
+-type builtin_alg() ::
+ exsss | exro928ss | exrop | exs1024s | exsp | exs64 | exsplus | exs1024.
-type alg() :: builtin_alg() | atom().
-type export_state() :: {alg(), alg_state()}.
+-type seed() :: [integer()] | integer() | {integer(), integer(), integer()}.
-export_type(
[builtin_alg/0, alg/0, alg_handler/0, alg_state/0,
- state/0, export_state/0]).
+ state/0, export_state/0, seed/0]).
-export_type(
- [exs64_state/0, exsplus_state/0, exs1024_state/0, exrop_state/0]).
+ [exsplus_state/0, exro928_state/0, exrop_state/0, exs1024_state/0,
+ exs64_state/0]).
%% =====================================================================
%% Range macro and helper
@@ -148,11 +172,7 @@
%% For ranges larger than the algorithm bit size
uniform_range(Range, #{next:=Next, bits:=Bits} = Alg, R, V) ->
- WeakLowBits =
- case Alg of
- #{weak_low_bits:=WLB} -> WLB;
- #{} -> 0
- end,
+ WeakLowBits = maps:get(weak_low_bits, Alg, 0),
%% Maybe waste the lowest bit(s) when shifting in new bits
Shift = Bits - WeakLowBits,
ShiftMask = bnot ?MASK(WeakLowBits),
@@ -218,12 +238,12 @@ export_seed() ->
end.
-spec export_seed_s(State :: state()) -> export_state().
-export_seed_s({#{type:=Alg}, Seed}) -> {Alg, Seed}.
+export_seed_s({#{type:=Alg}, AlgState}) -> {Alg, AlgState}.
%% seed(Alg) seeds RNG with runtime dependent values
%% and return the NEW state
-%% seed({Alg,Seed}) setup RNG with a previously exported seed
+%% seed({Alg,AlgState}) setup RNG with a previously exported seed
%% and return the NEW state
-spec seed(
@@ -235,11 +255,11 @@ seed(Alg) ->
-spec seed_s(
AlgOrStateOrExpState :: builtin_alg() | state() | export_state()) ->
state().
-seed_s({AlgHandler, _Seed} = State) when is_map(AlgHandler) ->
+seed_s({AlgHandler, _AlgState} = State) when is_map(AlgHandler) ->
State;
-seed_s({Alg0, Seed}) ->
- {Alg,_SeedFun} = mk_alg(Alg0),
- {Alg, Seed};
+seed_s({Alg, AlgState}) when is_atom(Alg) ->
+ {AlgHandler,_SeedFun} = mk_alg(Alg),
+ {AlgHandler,AlgState};
seed_s(Alg) ->
seed_s(Alg, {erlang:phash2([{node(),self()}]),
erlang:system_time(),
@@ -248,19 +268,15 @@ seed_s(Alg) ->
%% seed/2: seeds RNG with the algorithm and given values
%% and returns the NEW state.
--spec seed(
- Alg :: builtin_alg(), Seed :: {integer(), integer(), integer()}) ->
- state().
-seed(Alg0, S0) ->
- seed_put(seed_s(Alg0, S0)).
+-spec seed(Alg :: builtin_alg(), Seed :: seed()) -> state().
+seed(Alg, Seed) ->
+ seed_put(seed_s(Alg, Seed)).
--spec seed_s(
- Alg :: builtin_alg(), Seed :: {integer(), integer(), integer()}) ->
- state().
-seed_s(Alg0, S0 = {_, _, _}) ->
- {Alg, Seed} = mk_alg(Alg0),
- AS = Seed(S0),
- {Alg, AS}.
+-spec seed_s(Alg :: builtin_alg(), Seed :: seed()) -> state().
+seed_s(Alg, Seed) ->
+ {AlgHandler,SeedFun} = mk_alg(Alg),
+ AlgState = SeedFun(Seed),
+ {AlgHandler,AlgState}.
%%% uniform/0, uniform/1, uniform_s/1, uniform_s/2 are all
%%% uniformly distributed random numbers.
@@ -270,8 +286,8 @@ seed_s(Alg0, S0 = {_, _, _}) ->
-spec uniform() -> X :: float().
uniform() ->
- {X, Seed} = uniform_s(seed_get()),
- _ = seed_put(Seed),
+ {X, State} = uniform_s(seed_get()),
+ _ = seed_put(State),
X.
%% uniform/1: given an integer N >= 1,
@@ -280,8 +296,8 @@ uniform() ->
-spec uniform(N :: pos_integer()) -> X :: pos_integer().
uniform(N) ->
- {X, Seed} = uniform_s(N, seed_get()),
- _ = seed_put(Seed),
+ {X, State} = uniform_s(N, seed_get()),
+ _ = seed_put(State),
X.
%% uniform_s/1: given a state, uniform_s/1
@@ -297,7 +313,7 @@ uniform_s({#{bits:=Bits, next:=Next} = Alg, R0}) ->
{(V bsr (Bits - 53)) * ?TWO_POW_MINUS53, {Alg, R1}};
uniform_s({#{max:=Max, next:=Next} = Alg, R0}) ->
{V, R1} = Next(R0),
- %% Old broken algorithm with non-uniform density
+ %% Old algorithm with non-uniform density
{V / (Max + 1), {Alg, R1}}.
@@ -317,7 +333,7 @@ uniform_s(N, {#{bits:=Bits, next:=Next} = Alg, R0})
?uniform_range(N, Alg, R1, V, MaxMinusN, I);
uniform_s(N, {#{max:=Max, next:=Next} = Alg, R0})
when is_integer(N), 1 =< N ->
- %% Old broken algorithm with skewed probability
+ %% Old algorithm with skewed probability
%% and gap in ranges > Max
{V, R1} = Next(R0),
if
@@ -328,6 +344,189 @@ uniform_s(N, {#{max:=Max, next:=Next} = Alg, R0})
{trunc(F * N) + 1, {Alg, R1}}
end.
+%% uniform_real/0: returns a random float X where 0.0 < X =< 1.0,
+%% updating the state in the process dictionary.
+
+-spec uniform_real() -> X :: float().
+uniform_real() ->
+ {X, Seed} = uniform_real_s(seed_get()),
+ _ = seed_put(Seed),
+ X.
+
+%% uniform_real_s/1: given a state, uniform_s/1
+%% returns a random float X where 0.0 < X =< 1.0,
+%% and a new state.
+%%
+%% This function does not use the same form of uniformity
+%% as the uniform_s/1 function.
+%%
+%% Instead, this function does not generate numbers with equal
+%% distance in the interval, but rather tries to keep all mantissa
+%% bits random also for small numbers, meaning that the distance
+%% between possible numbers decreases when the numbers
+%% approaches 0.0, as does the possibility for a particular
+%% number. Hence uniformity is preserved.
+%%
+%% To generate 56 bits at the time instead of 53 is actually
+%% a speed optimization since the probability to have to
+%% generate a second word decreases by 1/2 for every extra bit.
+%%
+%% This function generates normalized numbers, so the smallest number
+%% that can be generated is 2^-1022 with the distance 2^-1074
+%% to the next to smallest number, compared to 2^-53 for uniform_s/1.
+%%
+%% This concept of uniformity should work better for applications
+%% where you need to calculate 1.0/X or math:log(X) since those
+%% operations benefits from larger precision approaching 0.0,
+%% and that this function does not return 0.0 nor denormalized
+%% numbers very close to 0.0. The log() operation in The Box-Muller
+%% transformation for normal distribution is an example of this.
+%%
+%%-define(TWO_POW_MINUS55, (math:pow(2, -55))).
+%%-define(TWO_POW_MINUS110, (math:pow(2, -110))).
+%%-define(TWO_POW_MINUS55, 2.7755575615628914e-17).
+%%-define(TWO_POW_MINUS110, 7.7037197775489436e-34).
+%%
+-spec uniform_real_s(State :: state()) -> {X :: float(), NewState :: state()}.
+uniform_real_s({#{bits:=Bits, next:=Next} = Alg, R0}) ->
+ %% Generate a 56 bit number without using the weak low bits.
+ %%
+ %% Be sure to use only 53 bits when multiplying with
+ %% math:pow(2.0, -N) to avoid rounding which would make
+ %% "even" floats more probable than "odd".
+ %%
+ {V1, R1} = Next(R0),
+ M1 = V1 bsr (Bits - 56),
+ if
+ ?BIT(55) =< M1 ->
+ %% We have 56 bits - waste 3
+ {(M1 bsr 3) * math:pow(2.0, -53), {Alg, R1}};
+ ?BIT(54) =< M1 ->
+ %% We have 55 bits - waste 2
+ {(M1 bsr 2) * math:pow(2.0, -54), {Alg, R1}};
+ ?BIT(53) =< M1 ->
+ %% We have 54 bits - waste 1
+ {(M1 bsr 1) * math:pow(2.0, -55), {Alg, R1}};
+ ?BIT(52) =< M1 ->
+ %% We have 53 bits - use all
+ {M1 * math:pow(2.0, -56), {Alg, R1}};
+ true ->
+ %% Need more bits
+ {V2, R2} = Next(R1),
+ uniform_real_s(Alg, Next, M1, -56, R2, V2, Bits)
+ end;
+uniform_real_s({#{max:=_, next:=Next} = Alg, R0}) ->
+ %% Generate a 56 bit number.
+ %% Ignore the weak low bits for these old algorithms,
+ %% just produce something reasonable.
+ %%
+ %% Be sure to use only 53 bits when multiplying with
+ %% math:pow(2.0, -N) to avoid rounding which would make
+ %% "even" floats more probable than "odd".
+ %%
+ {V1, R1} = Next(R0),
+ M1 = ?MASK(56, V1),
+ if
+ ?BIT(55) =< M1 ->
+ %% We have 56 bits - waste 3
+ {(M1 bsr 3) * math:pow(2.0, -53), {Alg, R1}};
+ ?BIT(54) =< M1 ->
+ %% We have 55 bits - waste 2
+ {(M1 bsr 2) * math:pow(2.0, -54), {Alg, R1}};
+ ?BIT(53) =< M1 ->
+ %% We have 54 bits - waste 1
+ {(M1 bsr 1) * math:pow(2.0, -55), {Alg, R1}};
+ ?BIT(52) =< M1 ->
+ %% We have 53 bits - use all
+ {M1 * math:pow(2.0, -56), {Alg, R1}};
+ true ->
+ %% Need more bits
+ {V2, R2} = Next(R1),
+ uniform_real_s(Alg, Next, M1, -56, R2, V2, 56)
+ end.
+
+uniform_real_s(Alg, _Next, M0, -1064, R1, V1, Bits) -> % 19*56
+ %% This is a very theoretical bottom case.
+ %% The odds of getting here is about 2^-1008,
+ %% through a white box test case, or thanks to
+ %% a malfunctioning PRNG producing 18 56-bit zeros in a row.
+ %%
+ %% Fill up to 53 bits, we have at most 52
+ B0 = (53 - ?BC(M0, 52)), % Missing bits
+ {(((M0 bsl B0) bor (V1 bsr (Bits - B0))) * math:pow(2.0, -1064 - B0)),
+ {Alg, R1}};
+uniform_real_s(Alg, Next, M0, BitNo, R1, V1, Bits) ->
+ if
+ %% Optimize the most probable.
+ %% Fill up to 53 bits.
+ ?BIT(51) =< M0 ->
+ %% We have 52 bits in M0 - need 1
+ {(((M0 bsl 1) bor (V1 bsr (Bits - 1)))
+ * math:pow(2.0, BitNo - 1)),
+ {Alg, R1}};
+ ?BIT(50) =< M0 ->
+ %% We have 51 bits in M0 - need 2
+ {(((M0 bsl 2) bor (V1 bsr (Bits - 2)))
+ * math:pow(2.0, BitNo - 2)),
+ {Alg, R1}};
+ ?BIT(49) =< M0 ->
+ %% We have 50 bits in M0 - need 3
+ {(((M0 bsl 3) bor (V1 bsr (Bits - 3)))
+ * math:pow(2.0, BitNo - 3)),
+ {Alg, R1}};
+ M0 == 0 ->
+ M1 = V1 bsr (Bits - 56),
+ if
+ ?BIT(55) =< M1 ->
+ %% We have 56 bits - waste 3
+ {(M1 bsr 3) * math:pow(2.0, BitNo - 53), {Alg, R1}};
+ ?BIT(54) =< M1 ->
+ %% We have 55 bits - waste 2
+ {(M1 bsr 2) * math:pow(2.0, BitNo - 54), {Alg, R1}};
+ ?BIT(53) =< M1 ->
+ %% We have 54 bits - waste 1
+ {(M1 bsr 1) * math:pow(2.0, BitNo - 55), {Alg, R1}};
+ ?BIT(52) =< M1 ->
+ %% We have 53 bits - use all
+ {M1 * math:pow(2.0, BitNo - 56), {Alg, R1}};
+ BitNo =:= -1008 ->
+ %% Endgame
+ %% For the last round we cannot have 14 zeros or more
+ %% at the top of M1 because then we will underflow,
+ %% so we need at least 43 bits
+ if
+ ?BIT(42) =< M1 ->
+ %% We have 43 bits - get the last bits
+ uniform_real_s(Alg, Next, M1, BitNo - 56, R1);
+ true ->
+ %% Would underflow 2^-1022 - start all over
+ %%
+ %% We could just crash here since the odds for
+ %% the PRNG being broken is much higher than
+ %% for a good PRNG generating this many zeros
+ %% in a row. Maybe we should write an error
+ %% report or call this a system limit...?
+ uniform_real_s({Alg, R1})
+ end;
+ true ->
+ %% Need more bits
+ uniform_real_s(Alg, Next, M1, BitNo - 56, R1)
+ end;
+ true ->
+ %% Fill up to 53 bits
+ B0 = 53 - ?BC(M0, 49), % Number of bits we need to append
+ {(((M0 bsl B0) bor (V1 bsr (Bits - B0)))
+ * math:pow(2.0, BitNo - B0)),
+ {Alg, R1}}
+ end.
+%%
+uniform_real_s(#{bits:=Bits} = Alg, Next, M0, BitNo, R0) ->
+ {V1, R1} = Next(R0),
+ uniform_real_s(Alg, Next, M0, BitNo, R1, V1, Bits);
+uniform_real_s(#{max:=_} = Alg, Next, M0, BitNo, R0) ->
+ {V1, R1} = Next(R0),
+ uniform_real_s(Alg, Next, M0, BitNo, R1, ?MASK(56, V1), 56).
+
%% jump/1: given a state, jump/1
%% returns a new state which is equivalent to that
%% after a large number of call defined for each algorithm.
@@ -419,6 +618,11 @@ mk_alg(exsp) ->
uniform=>fun exsp_uniform/1, uniform_n=>fun exsp_uniform/2,
jump=>fun exsplus_jump/1},
fun exsplus_seed/1};
+mk_alg(exsss) ->
+ {#{type=>exsss, bits=>58, next=>fun exsss_next/1,
+ uniform=>fun exsss_uniform/1, uniform_n=>fun exsss_uniform/2,
+ jump=>fun exsplus_jump/1},
+ fun exsss_seed/1};
mk_alg(exs1024) ->
{#{type=>exs1024, max=>?MASK(64), next=>fun exs1024_next/1,
jump=>fun exs1024_jump/1},
@@ -431,7 +635,13 @@ mk_alg(exrop) ->
{#{type=>exrop, bits=>58, weak_low_bits=>1, next=>fun exrop_next/1,
uniform=>fun exrop_uniform/1, uniform_n=>fun exrop_uniform/2,
jump=>fun exrop_jump/1},
- fun exrop_seed/1}.
+ fun exrop_seed/1};
+mk_alg(exro928ss) ->
+ {#{type=>exro928ss, bits=>58, next=>fun exro928ss_next/1,
+ uniform=>fun exro928ss_uniform/1,
+ uniform_n=>fun exro928ss_uniform/2,
+ jump=>fun exro928_jump/1},
+ fun exro928_seed/1}.
%% =====================================================================
%% exs64 PRNG: Xorshift64*
@@ -441,6 +651,14 @@ mk_alg(exrop) ->
-opaque exs64_state() :: uint64().
+exs64_seed(L) when is_list(L) ->
+ [R] = seed64_nz(1, L),
+ R;
+exs64_seed(A) when is_integer(A) ->
+ [R] = seed64(1, ?MASK(64, A)),
+ R;
+%%
+%% Traditional integer triplet seed
exs64_seed({A1, A2, A3}) ->
{V1, _} = exs64_next((?MASK(32, A1) * 4294967197 + 1)),
{V2, _} = exs64_next((?MASK(32, A2) * 4294967231 + 1)),
@@ -462,11 +680,49 @@ exs64_next(R) ->
%% 58 bits fits into an immediate on 64bits erlang and is thus much faster.
%% Modification of the original Xorshift128+ algorithm to 116
%% by Sebastiano Vigna, a lot of thanks for his help and work.
+%%
+%% Reference C code for Xorshift116+ and Xorshift116**
+%%
+%% #include <stdint.h>
+%%
+%% #define MASK(b, v) (((UINT64_C(1) << (b)) - 1) & (v))
+%% #define BSL(b, v, n) (MASK((b)-(n), (v)) << (n))
+%% #define ROTL(b, v, n) (BSL((b), (v), (n)) | ((v) >> ((b)-(n))))
+%%
+%% uint64_t s[2];
+%%
+%% uint64_t next(void) {
+%% uint64_t s1 = s[0];
+%% const uint64_t s0 = s[1];
+%%
+%% s1 ^= BSL(58, s1, 24); // a
+%% s1 ^= s0 ^ (s1 >> 11) ^ (s0 >> 41); // b, c
+%% s[0] = s0;
+%% s[1] = s1;
+%%
+%% const uint64_t result_plus = MASK(58, s0 + s1);
+%% uint64_t result_starstar = s0;
+%% result_starstar = MASK(58, result_starstar * 5);
+%% result_starstar = ROTL(58, result_starstar, 7);
+%% result_starstar = MASK(58, result_starstar * 9);
+%%
+%% return result_plus;
+%% return result_starstar;
+%% }
+%%
%% =====================================================================
-opaque exsplus_state() :: nonempty_improper_list(uint58(), uint58()).
-dialyzer({no_improper_lists, exsplus_seed/1}).
+exsplus_seed(L) when is_list(L) ->
+ [S0,S1] = seed58_nz(2, L),
+ [S0|S1];
+exsplus_seed(X) when is_integer(X) ->
+ [S0,S1] = seed58(2, ?MASK(64, X)),
+ [S0|S1];
+%%
+%% Traditional integer triplet seed
exsplus_seed({A1, A2, A3}) ->
{_, R1} = exsplus_next(
[?MASK(58, (A1 * 4294967197) + 1)|
@@ -476,16 +732,62 @@ exsplus_seed({A1, A2, A3}) ->
tl(R1)]),
R2.
+-dialyzer({no_improper_lists, exsss_seed/1}).
+
+exsss_seed(L) when is_list(L) ->
+ [S0,S1] = seed58_nz(2, L),
+ [S0|S1];
+exsss_seed(X) when is_integer(X) ->
+ [S0,S1] = seed58(2, ?MASK(64, X)),
+ [S0|S1];
+%%
+%% Seed from traditional integer triple - mix into splitmix
+exsss_seed({A1, A2, A3}) ->
+ {_, X0} = seed58(?MASK(64, A1)),
+ {S0, X1} = seed58(?MASK(64, A2) bxor X0),
+ {S1, _} = seed58(?MASK(64, A3) bxor X1),
+ [S0|S1].
+
+%% Advance Xorshift116 state one step
+-define(
+ exs_next(S0, S1, S1_b),
+ begin
+ S1_b = S1 bxor ?BSL(58, S1, 24),
+ S1_b bxor S0 bxor (S1_b bsr 11) bxor (S0 bsr 41)
+ end).
+
+-define(
+ scramble_starstar(S, V_a, V_b),
+ begin
+ %% The multiply by add shifted trick avoids creating bignums
+ %% which improves performance significantly
+ %%
+ V_a = ?MASK(58, S + ?BSL(58, S, 2)), % V_a = S * 5
+ V_b = ?ROTL(58, V_a, 7),
+ ?MASK(58, V_b + ?BSL(58, V_b, 3)) % V_b * 9
+ end).
+
-dialyzer({no_improper_lists, exsplus_next/1}).
-%% Advance xorshift116+ state for one step and generate 58bit unsigned integer
+%% Advance state and generate 58bit unsigned integer
-spec exsplus_next(exsplus_state()) -> {uint58(), exsplus_state()}.
exsplus_next([S1|S0]) ->
%% Note: members s0 and s1 are swapped here
- S11 = S1 bxor ?BSL(58, S1, 24),
- S12 = S11 bxor S0 bxor (S11 bsr 11) bxor (S0 bsr 41),
- {?MASK(58, S0 + S12), [S0|S12]}.
+ NewS1 = ?exs_next(S0, S1, S1_1),
+ {?MASK(58, S0 + NewS1), [S0|NewS1]}.
+%% %% Note: members s0 and s1 are swapped here
+%% S11 = S1 bxor ?BSL(58, S1, 24),
+%% S12 = S11 bxor S0 bxor (S11 bsr 11) bxor (S0 bsr 41),
+%% {?MASK(58, S0 + S12), [S0|S12]}.
+
+-dialyzer({no_improper_lists, exsss_next/1}).
+-spec exsss_next(exsplus_state()) -> {uint58(), exsplus_state()}.
+exsss_next([S1|S0]) ->
+ %% Note: members s0 and s1 are swapped here
+ NewS1 = ?exs_next(S0, S1, S1_1),
+ {?scramble_starstar(S0, V_0, V_1), [S0|NewS1]}.
+%% {?MASK(58, S0 + NewS1), [S0|NewS1]}.
exsp_uniform({Alg, R0}) ->
{I, R1} = exsplus_next(R0),
@@ -493,18 +795,48 @@ exsp_uniform({Alg, R0}) ->
%% randomness quality than the others
{(I bsr (58-53)) * ?TWO_POW_MINUS53, {Alg, R1}}.
+exsss_uniform({Alg, R0}) ->
+ {I, R1} = exsss_next(R0),
+ {(I bsr (58-53)) * ?TWO_POW_MINUS53, {Alg, R1}}.
+
exsp_uniform(Range, {Alg, R}) ->
{V, R1} = exsplus_next(R),
MaxMinusRange = ?BIT(58) - Range,
?uniform_range(Range, Alg, R1, V, MaxMinusRange, I).
+exsss_uniform(Range, {Alg, R}) ->
+ {V, R1} = exsss_next(R),
+ MaxMinusRange = ?BIT(58) - Range,
+ ?uniform_range(Range, Alg, R1, V, MaxMinusRange, I).
-%% This is the jump function for the exsplus generator, equivalent
+
+%% This is the jump function for the exs* generators,
+%% i.e the Xorshift116 generators, equivalent
%% to 2^64 calls to next/1; it can be used to generate 2^52
%% non-overlapping subsequences for parallel computations.
%% Note: the jump function takes 116 times of the execution time of
%% next/1.
-
+%%
+%% #include <stdint.h>
+%%
+%% void jump(void) {
+%% static const uint64_t JUMP[] = { 0x02f8ea6bc32c797,
+%% 0x345d2a0f85f788c };
+%% int i, b;
+%% uint64_t s0 = 0;
+%% uint64_t s1 = 0;
+%% for(i = 0; i < sizeof JUMP / sizeof *JUMP; i++)
+%% for(b = 0; b < 58; b++) {
+%% if (JUMP[i] & 1ULL << b) {
+%% s0 ^= s[0];
+%% s1 ^= s[1];
+%% }
+%% next();
+%% }
+%% s[0] = s0;
+%% s[1] = s1;
+%% }
+%%
%% -define(JUMPCONST, 16#000d174a83e17de2302f8ea6bc32c797).
%% split into 58-bit chunks
%% and two iterative executions
@@ -514,7 +846,8 @@ exsp_uniform(Range, {Alg, R}) ->
-define(JUMPELEMLEN, 58).
-dialyzer({no_improper_lists, exsplus_jump/1}).
--spec exsplus_jump(state()) -> state().
+-spec exsplus_jump({alg_handler(), exsplus_state()}) ->
+ {alg_handler(), exsplus_state()}.
exsplus_jump({Alg, S}) ->
{S1, AS1} = exsplus_jump(S, [0|0], ?JUMPCONST1, ?JUMPELEMLEN),
{_, AS2} = exsplus_jump(S1, AS1, ?JUMPCONST2, ?JUMPELEMLEN),
@@ -541,6 +874,12 @@ exsplus_jump(S, [AS0|AS1], J, N) ->
-opaque exs1024_state() :: {list(uint64()), list(uint64())}.
+exs1024_seed(L) when is_list(L) ->
+ {seed64_nz(16, L), []};
+exs1024_seed(X) when is_integer(X) ->
+ {seed64(16, ?MASK(64, X)), []};
+%%
+%% Seed from traditional triple, remain backwards compatible
exs1024_seed({A1, A2, A3}) ->
B1 = ?MASK(21, (?MASK(21, A1) + 1) * 2097131),
B2 = ?MASK(21, (?MASK(21, A2) + 1) * 2097133),
@@ -612,8 +951,8 @@ exs1024_next({[H], RL}) ->
-define(JUMPTOTALLEN, 1024).
-define(RINGLEN, 16).
--spec exs1024_jump(state()) -> state().
-
+-spec exs1024_jump({alg_handler(), exs1024_state()}) ->
+ {alg_handler(), exs1024_state()}.
exs1024_jump({Alg, {L, RL}}) ->
P = length(RL),
AS = exs1024_jump({L, RL},
@@ -638,6 +977,195 @@ exs1024_jump({L, RL}, AS, JL, J, N, TN) ->
end.
%% =====================================================================
+%% exro928ss PRNG: Xoroshiro928**
+%%
+%% Reference URL: http://vigna.di.unimi.it/ftp/papers/ScrambledLinear.pdf
+%% i.e the Xoroshiro1024 generator with ** scrambler
+%% with {S, R, T} = {5, 7, 9} as recommended in the paper.
+%%
+%% {A, B, C} were tried out and selected as {44, 9, 45}
+%% and the jump coefficients calculated.
+%%
+%% Standard jump function pseudocode:
+%%
+%% Jump constant j = 0xb10773cb...44085302f77130ca
+%% Generator state: s
+%% New generator state: t = 0
+%% foreach bit in j, low to high:
+%% if the bit is one:
+%% t ^= s
+%% next s
+%% s = t
+%%
+%% Generator used for reference value calculation:
+%%
+%% #include <stdint.h>
+%% #include <stdio.h>
+%%
+%% int p = 0;
+%% uint64_t s[16];
+%%
+%% #define MASK(x) ((x) & ((UINT64_C(1) << 58) - 1))
+%% static __inline uint64_t rotl(uint64_t x, int n) {
+%% return MASK(x << n) | (x >> (58 - n));
+%% }
+%%
+%% uint64_t next() {
+%% const int q = p;
+%% const uint64_t s0 = s[p = (p + 1) & 15];
+%% uint64_t s15 = s[q];
+%%
+%% const uint64_t result_starstar = MASK(rotl(MASK(s0 * 5), 7) * 9);
+%%
+%% s15 ^= s0;
+%% s[q] = rotl(s0, 44) ^ s15 ^ MASK(s15 << 9);
+%% s[p] = rotl(s15, 45);
+%%
+%% return result_starstar;
+%% }
+%%
+%% static const uint64_t jump_2pow512[15] =
+%% { 0x44085302f77130ca, 0xba05381fdfd14902, 0x10a1de1d7d6813d2,
+%% 0xb83fe51a1eb3be19, 0xa81b0090567fd9f0, 0x5ac26d5d20f9b49f,
+%% 0x4ddd98ee4be41e01, 0x0657e19f00d4b358, 0xf02f778573cf0f0a,
+%% 0xb45a3a8a3cef3cc0, 0x6e62a33cc2323831, 0xbcb3b7c4cc049c53,
+%% 0x83f240c6007e76ce, 0xe19f5fc1a1504acd, 0x00000000b10773cb };
+%%
+%% static const uint64_t jump_2pow20[15] =
+%% { 0xbdb966a3daf905e6, 0x644807a56270cf78, 0xda90f4a806c17e9e,
+%% 0x4a426866bfad3c77, 0xaf699c306d8e7566, 0x8ebc73c700b8b091,
+%% 0xc081a7bf148531fb, 0xdc4d3af15f8a4dfd, 0x90627c014098f4b6,
+%% 0x06df2eb1feaf0fb6, 0x5bdeb1a5a90f2e6b, 0xa480c5878c3549bd,
+%% 0xff45ef33c82f3d48, 0xa30bebc15fefcc78, 0x00000000cb3d181c };
+%%
+%% void jump(const uint64_t *jump) {
+%% uint64_t j, t[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+%% int m, n, k;
+%% for (m = 0; m < 15; m++, jump++) {
+%% for (n = 0, j = *jump; n < 64; n++, j >>= 1) {
+%% if ((j & 1) != 0) {
+%% for (k = 0; k < 16; k++) {
+%% t[k] ^= s[(p + k) & 15];
+%% }
+%% }
+%% next();
+%% }
+%% }
+%% for (k = 0; k < 16; k++) {
+%% s[(p + k) & 15] = t[k];
+%% }
+%% }
+%%
+%% =====================================================================
+
+-opaque exro928_state() :: {list(uint58()), list(uint58())}.
+
+-spec exro928_seed(
+ list(uint58()) | integer() | {integer(), integer(), integer()}) ->
+ exro928_state().
+exro928_seed(L) when is_list(L) ->
+ {seed58_nz(16, L), []};
+exro928_seed(X) when is_integer(X) ->
+ {seed58(16, ?MASK(64, X)), []};
+%%
+%% Seed from traditional integer triple - mix into splitmix
+exro928_seed({A1, A2, A3}) ->
+ {S0, X0} = seed58(?MASK(64, A1)),
+ {S1, X1} = seed58(?MASK(64, A2) bxor X0),
+ {S2, X2} = seed58(?MASK(64, A3) bxor X1),
+ {[S0,S1,S2|seed58(13, X2)], []}.
+
+
+%% Update the state and calculate output word
+-spec exro928ss_next(exro928_state()) -> {uint58(), exro928_state()}.
+exro928ss_next({[S15,S0|Ss], Rs}) ->
+ SR = exro928_next_state(Ss, Rs, S15, S0),
+ %%
+ %% {S, R, T} = {5, 7, 9}
+ %% const uint64_t result_starstar = rotl(s0 * S, R) * T;
+ %%
+ {?scramble_starstar(S0, V_0, V_1), SR};
+%% %% The multiply by add shifted trick avoids creating bignums
+%% %% which improves performance significantly
+%% %%
+%% V0 = ?MASK(58, S0 + ?BSL(58, S0, 2)), % V0 = S0 * 5
+%% V1 = ?ROTL(58, V0, 7),
+%% V = ?MASK(58, V1 + ?BSL(58, V1, 3)), % V = V1 * 9
+%% {V, SR};
+exro928ss_next({[S15], Rs}) ->
+ exro928ss_next({[S15|lists:reverse(Rs)], []}).
+
+-spec exro928_next(exro928_state()) -> {{uint58(),uint58()}, exro928_state()}.
+exro928_next({[S15,S0|Ss], Rs}) ->
+ SR = exro928_next_state(Ss, Rs, S15, S0),
+ {{S15,S0}, SR};
+exro928_next({[S15], Rs}) ->
+ exro928_next({[S15|lists:reverse(Rs)], []}).
+
+%% Just update the state
+-spec exro928_next_state(exro928_state()) -> exro928_state().
+exro928_next_state({[S15,S0|Ss], Rs}) ->
+ exro928_next_state(Ss, Rs, S15, S0);
+exro928_next_state({[S15], Rs}) ->
+ [S0|Ss] = lists:reverse(Rs),
+ exro928_next_state(Ss, [], S15, S0).
+
+exro928_next_state(Ss, Rs, S15, S0) ->
+ %% {A, B, C} = {44, 9, 45},
+ %% s15 ^= s0;
+ %% NewS15: s[q] = rotl(s0, A) ^ s15 ^ (s15 << B);
+ %% NewS0: s[p] = rotl(s15, C);
+ %%
+ Q = S15 bxor S0,
+ NewS15 = ?ROTL(58, S0, 44) bxor Q bxor ?BSL(58, Q, 9),
+ NewS0 = ?ROTL(58, Q, 45),
+ {[NewS0|Ss], [NewS15|Rs]}.
+
+
+exro928ss_uniform({Alg, SR}) ->
+ {V, NewSR} = exro928ss_next(SR),
+ {(V bsr (58-53)) * ?TWO_POW_MINUS53, {Alg, NewSR}}.
+
+exro928ss_uniform(Range, {Alg, SR}) ->
+ {V, NewSR} = exro928ss_next(SR),
+ MaxMinusRange = ?BIT(58) - Range,
+ ?uniform_range(Range, Alg, NewSR, V, MaxMinusRange, I).
+
+
+-spec exro928_jump({alg_handler(), exro928_state()}) ->
+ {alg_handler(), exro928_state()}.
+exro928_jump({Alg, SR}) ->
+ {Alg,exro928_jump_2pow512(SR)}.
+
+-spec exro928_jump_2pow512(exro928_state()) -> exro928_state().
+exro928_jump_2pow512(SR) ->
+ polyjump(
+ SR, fun exro928_next_state/1,
+ %% 2^512
+ [16#4085302F77130CA, 16#54E07F7F4524091,
+ 16#5E1D7D6813D2BA0, 16#4687ACEF8644287,
+ 16#4567FD9F0B83FE5, 16#43E6D27EA06C024,
+ 16#641E015AC26D5D2, 16#6CD61377663B92F,
+ 16#70A0657E19F00D4, 16#43C0BDDE15CF3C3,
+ 16#745A3A8A3CEF3CC, 16#58A8CF308C8E0C6,
+ 16#7B7C4CC049C536E, 16#431801F9DB3AF2C,
+ 16#41A1504ACD83F24, 16#6C41DCF2F867D7F]).
+
+-spec exro928_jump_2pow20(exro928_state()) -> exro928_state().
+exro928_jump_2pow20(SR) ->
+ polyjump(
+ SR, fun exro928_next_state/1,
+ %% 2^20
+ [16#5B966A3DAF905E6, 16#601E9589C33DE2F,
+ 16#74A806C17E9E644, 16#59AFEB4F1DF6A43,
+ 16#46D8E75664A4268, 16#42E2C246BDA670C,
+ 16#4531FB8EBC73C70, 16#537F702069EFC52,
+ 16#4B6DC4D3AF15F8A, 16#5A4189F0050263D,
+ 16#46DF2EB1FEAF0FB, 16#77AC696A43CB9AC,
+ 16#4C5878C3549BD5B, 16#7CCF20BCF522920,
+ 16#415FEFCC78FF45E, 16#72CF460728C2FAF]).
+
+%% =====================================================================
%% exrop PRNG: Xoroshiro116+
%%
%% Reference URL: http://xorshift.di.unimi.it/
@@ -705,6 +1233,15 @@ exs1024_jump({L, RL}, AS, JL, J, N, TN) ->
-opaque exrop_state() :: nonempty_improper_list(uint58(), uint58()).
-dialyzer({no_improper_lists, exrop_seed/1}).
+
+exrop_seed(L) when is_list(L) ->
+ [S0,S1] = seed58_nz(2, L),
+ [S0|S1];
+exrop_seed(X) when is_integer(X) ->
+ [S0,S1] = seed58(2, ?MASK(64, X)),
+ [S0|S1];
+%%
+%% Traditional integer triplet seed
exrop_seed({A1, A2, A3}) ->
[_|S1] =
exrop_next_s(
@@ -768,6 +1305,142 @@ exrop_jump([S__0|S__1] = _S, S0, S1, J, Js) ->
end.
%% =====================================================================
+%% Mask and fill state list, ensure not all zeros
+%% =====================================================================
+
+seed58_nz(N, Ss) ->
+ seed_nz(N, Ss, 58, false).
+
+seed64_nz(N, Ss) ->
+ seed_nz(N, Ss, 64, false).
+
+seed_nz(_N, [], _M, false) ->
+ erlang:error(zero_seed);
+seed_nz(0, [_|_], _M, _NZ) ->
+ erlang:error(too_many_seed_integers);
+seed_nz(0, [], _M, _NZ) ->
+ [];
+seed_nz(N, [], M, true) ->
+ [0|seed_nz(N - 1, [], M, true)];
+seed_nz(N, [S|Ss], M, NZ) ->
+ if
+ is_integer(S) ->
+ R = ?MASK(M, S),
+ [R|seed_nz(N - 1, Ss, M, NZ orelse R =/= 0)];
+ true ->
+ erlang:error(non_integer_seed)
+ end.
+
+%% =====================================================================
+%% Splitmix seeders, lowest bits of SplitMix64, zeros skipped
+%% =====================================================================
+
+-spec seed58(non_neg_integer(), uint64()) -> list(uint58()).
+seed58(0, _X) ->
+ [];
+seed58(N, X) ->
+ {Z,NewX} = seed58(X),
+ [Z|seed58(N - 1, NewX)].
+%%
+seed58(X_0) ->
+ {Z0,X} = splitmix64_next(X_0),
+ case ?MASK(58, Z0) of
+ 0 ->
+ seed58(X);
+ Z ->
+ {Z,X}
+ end.
+
+-spec seed64(non_neg_integer(), uint64()) -> list(uint64()).
+seed64(0, _X) ->
+ [];
+seed64(N, X) ->
+ {Z,NewX} = seed64(X),
+ [Z|seed64(N - 1, NewX)].
+%%
+seed64(X_0) ->
+ {Z,X} = ZX = splitmix64_next(X_0),
+ if
+ Z =:= 0 ->
+ seed64(X);
+ true ->
+ ZX
+ end.
+
+%% The SplitMix64 generator:
+%%
+%% uint64_t splitmix64_next() {
+%% uint64_t z = (x += 0x9e3779b97f4a7c15);
+%% z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
+%% z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
+%% return z ^ (z >> 31);
+%% }
+%%
+splitmix64_next(X_0) ->
+ X = ?MASK(64, X_0 + 16#9e3779b97f4a7c15),
+ Z_0 = ?MASK(64, (X bxor (X bsr 30)) * 16#bf58476d1ce4e5b9),
+ Z_1 = ?MASK(64, (Z_0 bxor (Z_0 bsr 27)) * 16#94d049bb133111eb),
+ {?MASK(64, Z_1 bxor (Z_1 bsr 31)),X}.
+
+%% =====================================================================
+%% Polynomial jump with a jump constant word list,
+%% high bit in each word marking top of word,
+%% SR is a {Forward, Reverse} queue tuple with Forward never empty
+%% =====================================================================
+
+polyjump({Ss, Rs} = SR, NextState, JumpConst) ->
+ %% Create new state accumulator T
+ Ts = lists:duplicate(length(Ss) + length(Rs), 0),
+ polyjump(SR, NextState, JumpConst, Ts).
+%%
+%% Foreach jump word
+polyjump(_SR, _NextState, [], Ts) ->
+ %% Return new calculated state
+ {Ts, []};
+polyjump(SR, NextState, [J|Js], Ts) ->
+ polyjump(SR, NextState, Js, Ts, J).
+%%
+%% Foreach bit in jump word until top bit
+polyjump(SR, NextState, Js, Ts, 1) ->
+ polyjump(SR, NextState, Js, Ts);
+polyjump({Ss, Rs} = SR, NextState, Js, Ts, J) when J =/= 0 ->
+ NewSR = NextState(SR),
+ NewJ = J bsr 1,
+ case ?MASK(1, J) of
+ 0 ->
+ polyjump(NewSR, NextState, Js, Ts, NewJ);
+ 1 ->
+ %% Xor this state onto T
+ polyjump(NewSR, NextState, Js, xorzip_sr(Ts, Ss, Rs), NewJ)
+ end.
+
+xorzip_sr([], [], undefined) ->
+ [];
+xorzip_sr(Ts, [], Rs) ->
+ xorzip_sr(Ts, lists:reverse(Rs), undefined);
+xorzip_sr([T|Ts], [S|Ss], Rs) ->
+ [T bxor S|xorzip_sr(Ts, Ss, Rs)].
+
+%% =====================================================================
+
+format_jumpconst58(String) ->
+ ReOpts = [{newline,any},{capture,all_but_first,binary},global],
+ {match,Matches} = re:run(String, "0x([a-zA-Z0-9]+)", ReOpts),
+ format_jumcons58_matches(lists:reverse(Matches), 0).
+
+format_jumcons58_matches([], J) ->
+ format_jumpconst58_value(J);
+format_jumcons58_matches([[Bin]|Matches], J) ->
+ NewJ = (J bsl 64) bor binary_to_integer(Bin, 16),
+ format_jumcons58_matches(Matches, NewJ).
+
+format_jumpconst58_value(0) ->
+ ok;
+format_jumpconst58_value(J) ->
+ io:format("16#~s,~n", [integer_to_list(?MASK(58, J) bor ?BIT(58), 16)]),
+ format_jumpconst58_value(J bsr 58).
+
+%% =====================================================================
%% Ziggurat cont
%% =====================================================================
-define(NOR_R, 3.6541528853610087963519472518).
@@ -1025,3 +1698,42 @@ normal_fi(Indx) ->
1.0214971439701471e-02,8.6165827693987316e-03,7.0508754713732268e-03,
5.5224032992509968e-03,4.0379725933630305e-03,2.6090727461021627e-03,
1.2602859304985975e-03}).
+
+%%%bitcount64(0) -> 0;
+%%%bitcount64(V) -> 1 + bitcount(V, 64).
+%%%
+%%%-define(
+%%% BITCOUNT(V, N),
+%%% bitcount(V, N) ->
+%%% if
+%%% (1 bsl ((N) bsr 1)) =< (V) ->
+%%% ((N) bsr 1) + bitcount((V) bsr ((N) bsr 1), ((N) bsr 1));
+%%% true ->
+%%% bitcount((V), ((N) bsr 1))
+%%% end).
+%%%?BITCOUNT(V, 64);
+%%%?BITCOUNT(V, 32);
+%%%?BITCOUNT(V, 16);
+%%%?BITCOUNT(V, 8);
+%%%?BITCOUNT(V, 4);
+%%%?BITCOUNT(V, 2);
+%%%bitcount(_, 1) -> 0.
+
+bc64(V) -> ?BC(V, 64).
+
+%% Linear from high bit - higher probability first gives faster execution
+bc(V, B, N) when B =< V -> N;
+bc(V, B, N) -> bc(V, B bsr 1, N - 1).
+
+make_float(S, E, M) ->
+ <<F/float>> = <<S:1, E:11, M:52>>,
+ F.
+
+float2str(N) ->
+ <<S:1, E:11, M:52>> = <<(float(N))/float>>,
+ lists:flatten(
+ io_lib:format(
+ "~c~c.~13.16.0bE~b",
+ [case S of 1 -> $-; 0 -> $+ end,
+ case E of 0 -> $0; _ -> $1 end,
+ M, E - 16#3ff])).
diff --git a/lib/stdlib/src/sets.erl b/lib/stdlib/src/sets.erl
index c65a13b22e..8adb9016e2 100644
--- a/lib/stdlib/src/sets.erl
+++ b/lib/stdlib/src/sets.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -37,7 +37,7 @@
-module(sets).
%% Standard interface.
--export([new/0,is_set/1,size/1,to_list/1,from_list/1]).
+-export([new/0,is_set/1,size/1,is_empty/1,to_list/1,from_list/1]).
-export([is_element/2,add_element/2,del_element/2]).
-export([union/2,union/1,intersection/2,intersection/1]).
-export([is_disjoint/2]).
@@ -96,6 +96,12 @@ is_set(_) -> false.
Set :: set().
size(S) -> S#set.size.
+%% is_empty(Set) -> boolean().
+%% Return 'true' if Set is an empty set, otherwise 'false'.
+-spec is_empty(Set) -> boolean() when
+ Set :: set().
+is_empty(S) -> S#set.size=:=0.
+
%% to_list(Set) -> [Elem].
%% Return the elements in Set as a list.
-spec to_list(Set) -> List when
diff --git a/lib/stdlib/src/shell.erl b/lib/stdlib/src/shell.erl
index ad4984b64c..c73cf22943 100644
--- a/lib/stdlib/src/shell.erl
+++ b/lib/stdlib/src/shell.erl
@@ -230,7 +230,7 @@ server_loop(N0, Eval_0, Bs00, RT, Ds00, History0, Results0) ->
{Res,Eval0} = get_command(Prompt, Eval_1, Bs0, RT, Ds0),
case Res of
{ok,Es0,XBs} ->
- Es1 = lib:subst_values_for_vars(Es0, XBs),
+ Es1 = erl_eval:subst_values_for_vars(Es0, XBs),
case expand_hist(Es1, N) of
{ok,Es} ->
{V,Eval,Bs,Ds} = shell_cmd(Es, Eval0, Bs0, RT, Ds0, cmd),
@@ -280,7 +280,7 @@ get_command(Prompt, Eval, Bs, RT, Ds) ->
io:scan_erl_exprs(group_leader(), Prompt, 1, [text])
of
{ok,Toks,_EndPos} ->
- lib:extended_parse_exprs(Toks);
+ erl_eval:extended_parse_exprs(Toks);
{eof,_EndPos} ->
eof;
{error,ErrorInfo,_EndPos} ->
@@ -589,7 +589,7 @@ report_exception(Class, Severity, {Reason,Stacktrace}, RT) ->
PF = fun(Term, I1) -> pp(Term, I1, RT) end,
SF = fun(M, _F, _A) -> (M =:= erl_eval) or (M =:= ?MODULE) end,
Enc = encoding(),
- Str = lib:format_exception(I, Class, Reason, Stacktrace, SF, PF, Enc),
+ Str = erl_error:format_exception(I, Class, Reason, Stacktrace, SF, PF, Enc),
io:requests([{put_chars, latin1, Tag},
{put_chars, unicode, Str},
nl]).
@@ -645,8 +645,7 @@ eval_exprs(Es, Shell, Bs0, RT, Lf, Ef, W) ->
catch
exit:normal ->
exit(normal);
- Class:Reason ->
- Stacktrace = erlang:get_stacktrace(),
+ Class:Reason:Stacktrace ->
M = {self(),Class,{Reason,Stacktrace}},
case do_catch(Class, Reason) of
true ->
@@ -807,8 +806,8 @@ restrict_handlers(RShMod, Shell, RT) ->
-define(BAD_RETURN(M, F, V),
try erlang:error(reason)
- catch _:_ -> erlang:raise(exit, {restricted_shell_bad_return,V},
- [{M,F,3} | erlang:get_stacktrace()])
+ catch _:_:S -> erlang:raise(exit, {restricted_shell_bad_return,V},
+ [{M,F,3} | S])
end).
local_allowed(F, As, RShMod, Bs, Shell, RT) when is_atom(F) ->
@@ -1417,7 +1416,7 @@ pp(V, I, D, RT) ->
true
end,
io_lib_pretty:print(V, ([{column, I}, {line_length, columns()},
- {depth, D}, {max_chars, ?CHAR_MAX},
+ {depth, D}, {line_max_chars, ?CHAR_MAX},
{strings, Strings},
{record_print_fun, record_print_fun(RT)}]
++ enc())).
diff --git a/lib/stdlib/src/slave.erl b/lib/stdlib/src/slave.erl
index d7cf6386f5..4791e3ebda 100644
--- a/lib/stdlib/src/slave.erl
+++ b/lib/stdlib/src/slave.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -104,18 +104,17 @@ relay1(Pid) ->
%% this to work is that the 'erl' program can be found in PATH.
%%
%% If the master and slave are on different hosts, start/N uses
-%% the 'rsh' program to spawn an Erlang node on the other host.
+%% the 'ssh' program to spawn an Erlang node on the other host.
%% Alternative, if the master was started as
%% 'erl -sname xxx -rsh my_rsh...', then 'my_rsh' will be used instead
-%% of 'rsh' (this is useful for systems where the rsh program is named
-%% 'remsh').
+%% of 'ssh' (this is useful for systems still using rsh or remsh).
%%
%% For this to work, the following conditions must be fulfilled:
%%
-%% 1. There must be an Rsh program on computer; if not an error
+%% 1. There must be an ssh program on computer; if not an error
%% is returned.
%%
-%% 2. The hosts must be configured to allowed 'rsh' access without
+%% 2. The hosts must be configured to allow 'ssh' access without
%% prompts for password.
%%
%% The slave node will have its filer and user server redirected
@@ -187,7 +186,7 @@ start_link(Host, Name, Args) ->
start(Host, Name, Args, self()).
start(Host0, Name, Args, LinkTo) ->
- Prog = lib:progname(),
+ Prog = progname(),
start(Host0, Name, Args, LinkTo, Prog).
start(Host0, Name, Args, LinkTo, Prog) ->
@@ -286,7 +285,7 @@ register_unique_name(Number) ->
%% Makes up the command to start the nodes.
%% If the node should run on the local host, there is
-%% no need to use rsh.
+%% no need to use a remote shell.
mk_cmd(Host, Name, Args, Waiter, Prog0) ->
Prog = quote_progname(Prog0),
@@ -296,7 +295,6 @@ mk_cmd(Host, Name, Args, Waiter, Prog0) ->
" -s slave slave_start ", node(),
" ", Waiter,
" ", Args]),
-
case after_char($@, atom_to_list(node())) of
Host ->
{ok, BasicCmd};
@@ -309,6 +307,15 @@ mk_cmd(Host, Name, Args, Waiter, Prog0) ->
end
end.
+%% Return the name of the script that starts (this) erlang
+progname() ->
+ case init:get_argument(progname) of
+ {ok, [[Prog]]} ->
+ Prog;
+ _Other ->
+ "no_prog_name"
+ end.
+
%% This is an attempt to distinguish between spaces in the program
%% path and spaces that separate arguments. The program is quoted to
%% allow spaces in the path.
@@ -317,10 +324,10 @@ mk_cmd(Host, Name, Args, Waiter, Prog0) ->
%% (through start/5) or if the -program switch to beam is used and
%% includes arguments (typically done by cerl in OTP test environment
%% in order to ensure that slave/peer nodes are started with the same
-%% emulator and flags as the test node. The return from lib:progname()
+%% emulator and flags as the test node. The result from progname()
%% could then typically be '/<full_path_to>/cerl -gcov').
quote_progname(Progname) ->
- do_quote_progname(string:tokens(to_list(Progname)," ")).
+ do_quote_progname(string:lexemes(to_list(Progname)," ")).
do_quote_progname([Prog]) ->
"\""++Prog++"\"";
@@ -334,9 +341,7 @@ do_quote_progname([Prog,Arg|Args]) ->
lists:flatten(lists:map(fun(X) -> [" ",X] end, [Arg|Args]))
end.
-%% Give the user an opportunity to run another program,
-%% than the "rsh". On HP-UX rsh is called remsh; thus HP users
-%% must start erlang as erl -rsh remsh.
+%% Give the user an opportunity to run another program than "ssh".
%%
%% Also checks that the given program exists.
%%
@@ -346,7 +351,7 @@ rsh() ->
Rsh =
case init:get_argument(rsh) of
{ok, [[Prog]]} -> Prog;
- _ -> "rsh"
+ _ -> "ssh"
end,
case os:find_executable(Rsh) of
false -> {error, no_rsh};
diff --git a/lib/stdlib/src/stdlib.app.src b/lib/stdlib/src/stdlib.app.src
index 3c449d3cb9..ecb514e9f3 100644
--- a/lib/stdlib/src/stdlib.app.src
+++ b/lib/stdlib/src/stdlib.app.src
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -43,6 +43,7 @@
erl_anno,
erl_bits,
erl_compile,
+ erl_error,
erl_eval,
erl_expand_records,
erl_internal,
@@ -71,7 +72,6 @@
io_lib_format,
io_lib_fread,
io_lib_pretty,
- lib,
lists,
log_mf_h,
maps,
@@ -101,13 +101,14 @@
timer,
unicode,
unicode_util,
+ uri_string,
win32reg,
zip]},
{registered,[timer_server,rsh_starter,take_over_monitor,pool_master,
dets]},
{applications, [kernel]},
{env, []},
- {runtime_dependencies, ["sasl-3.0","kernel-5.0","erts-9.0","crypto-3.3",
+ {runtime_dependencies, ["sasl-3.0","kernel-6.0","erts-10.4","crypto-3.3",
"compiler-5.0"]}
]}.
diff --git a/lib/stdlib/src/stdlib.appup.src b/lib/stdlib/src/stdlib.appup.src
index 800c2c61f3..7038cc159c 100644
--- a/lib/stdlib/src/stdlib.appup.src
+++ b/lib/stdlib/src/stdlib.appup.src
@@ -16,11 +16,38 @@
%% limitations under the License.
%%
%% %CopyrightEnd%
+%%
+%% We allow upgrade from, and downgrade to all previous
+%% versions from the following OTP releases:
+%% - OTP 21
+%% - OTP 22
+%%
+%% We also allow upgrade from, and downgrade to all
+%% versions that have branched off from the above
+%% stated previous versions.
+%%
{"%VSN%",
- %% Up from - max one major revision back
- [{<<"3\\.[0-3](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-19.*
- {<<"3\\.4(\\.[0-9]+)*">>,[restart_new_emulator]}], % OTP-20.*
- %% Down to - max one major revision back
- [{<<"3\\.[0-3](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-19.*
- {<<"3\\.4(\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-20.*
-}.
+ [{<<"^3\\.5$">>,[restart_new_emulator]},
+ {<<"^3\\.5\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^3\\.5\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^3\\.6$">>,[restart_new_emulator]},
+ {<<"^3\\.6\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^3\\.7$">>,[restart_new_emulator]},
+ {<<"^3\\.7\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^3\\.7\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^3\\.8$">>,[restart_new_emulator]},
+ {<<"^3\\.8\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^3\\.8\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^3\\.8\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}],
+ [{<<"^3\\.5$">>,[restart_new_emulator]},
+ {<<"^3\\.5\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^3\\.5\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^3\\.6$">>,[restart_new_emulator]},
+ {<<"^3\\.6\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^3\\.7$">>,[restart_new_emulator]},
+ {<<"^3\\.7\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^3\\.7\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^3\\.8$">>,[restart_new_emulator]},
+ {<<"^3\\.8\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^3\\.8\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
+ {<<"^3\\.8\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}]}.
diff --git a/lib/stdlib/src/string.erl b/lib/stdlib/src/string.erl
index 6f5e617230..a418754caf 100644
--- a/lib/stdlib/src/string.erl
+++ b/lib/stdlib/src/string.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -88,7 +88,6 @@
%%% May be removed
-export([list_to_float/1, list_to_integer/1]).
-
%% Uses bifs: string:list_to_float/1 and string:list_to_integer/1
-spec list_to_float(String) -> {Float, Rest} | {'error', Reason} when
String :: string(),
@@ -129,7 +128,8 @@ length(CD) ->
to_graphemes(CD0) ->
case unicode_util:gc(CD0) of
[GC|CD] -> [GC|to_graphemes(CD)];
- [] -> []
+ [] -> [];
+ {error, Err} -> error({badarg, Err})
end.
%% Compare two strings return boolean, assumes that the input are
@@ -324,16 +324,36 @@ take(Str, Sep0, true, trailing) ->
%% Uppercase all chars in Str
-spec uppercase(String::unicode:chardata()) -> unicode:chardata().
uppercase(CD) when is_list(CD) ->
- uppercase_list(CD);
-uppercase(CD) when is_binary(CD) ->
- uppercase_bin(CD,<<>>).
+ try uppercase_list(CD, false)
+ catch unchanged -> CD
+ end;
+uppercase(<<CP1/utf8, Rest/binary>>=Orig) ->
+ try uppercase_bin(CP1, Rest, false) of
+ List -> unicode:characters_to_binary(List)
+ catch unchanged -> Orig
+ end;
+uppercase(<<>>) ->
+ <<>>;
+uppercase(Bin) ->
+ error({badarg, Bin}).
+
%% Lowercase all chars in Str
-spec lowercase(String::unicode:chardata()) -> unicode:chardata().
lowercase(CD) when is_list(CD) ->
- lowercase_list(CD);
-lowercase(CD) when is_binary(CD) ->
- lowercase_bin(CD,<<>>).
+ try lowercase_list(CD, false)
+ catch unchanged -> CD
+ end;
+lowercase(<<CP1/utf8, Rest/binary>>=Orig) ->
+ try lowercase_bin(CP1, Rest, false) of
+ List -> unicode:characters_to_binary(List)
+ catch unchanged -> Orig
+ end;
+lowercase(<<>>) ->
+ <<>>;
+lowercase(Bin) ->
+ error({badarg, Bin}).
+
%% Make a titlecase of the first char in Str
-spec titlecase(String::unicode:chardata()) -> unicode:chardata().
@@ -353,9 +373,18 @@ titlecase(CD) when is_binary(CD) ->
%% Make a comparable string of the Str should be used for equality tests only
-spec casefold(String::unicode:chardata()) -> unicode:chardata().
casefold(CD) when is_list(CD) ->
- casefold_list(CD);
-casefold(CD) when is_binary(CD) ->
- casefold_bin(CD,<<>>).
+ try casefold_list(CD, false)
+ catch unchanged -> CD
+ end;
+casefold(<<CP1/utf8, Rest/binary>>=Orig) ->
+ try casefold_bin(CP1, Rest, false) of
+ List -> unicode:characters_to_binary(List)
+ catch unchanged -> Orig
+ end;
+casefold(<<>>) ->
+ <<>>;
+casefold(Bin) ->
+ error({badarg, Bin}).
-spec to_integer(String) -> {Int, Rest} | {'error', Reason} when
String :: unicode:chardata(),
@@ -524,7 +553,8 @@ length_1([CP1|[CP2|_]=Cont], N) when ?ASCII_LIST(CP1,CP2) ->
length_1(Str, N) ->
case unicode_util:gc(Str) of
[] -> N;
- [_|Rest] -> length_1(Rest, N+1)
+ [_|Rest] -> length_1(Rest, N+1);
+ {error, Err} -> error({badarg, Err})
end.
length_b(<<CP2/utf8, Rest/binary>>, CP1, N)
@@ -534,7 +564,8 @@ length_b(Bin0, CP1, N) ->
[_|Bin1] = unicode_util:gc([CP1|Bin0]),
case unicode_util:cp(Bin1) of
[] -> N+1;
- [CP3|Bin] -> length_b(Bin, CP3, N+1)
+ [CP3|Bin] -> length_b(Bin, CP3, N+1);
+ {error, Err} -> error({badarg, Err})
end.
equal_1([A|AR], [B|BR]) when is_integer(A), is_integer(B) ->
@@ -579,7 +610,8 @@ reverse_1([CP1|[CP2|_]=Cont], Acc) when ?ASCII_LIST(CP1,CP2) ->
reverse_1(CD, Acc) ->
case unicode_util:gc(CD) of
[GC|Rest] -> reverse_1(Rest, [GC|Acc]);
- [] -> Acc
+ [] -> Acc;
+ {error, Err} -> error({badarg, Err})
end.
reverse_b(<<CP2/utf8, Rest/binary>>, CP1, Acc)
@@ -589,7 +621,8 @@ reverse_b(Bin0, CP1, Acc) ->
[GC|Bin1] = unicode_util:gc([CP1|Bin0]),
case unicode_util:cp(Bin1) of
[] -> [GC|Acc];
- [CP3|Bin] -> reverse_b(Bin, CP3, [GC|Acc])
+ [CP3|Bin] -> reverse_b(Bin, CP3, [GC|Acc]);
+ {error, Err} -> error({badarg, Err})
end.
slice_l0(<<CP1/utf8, Bin/binary>>, N) when N > 0 ->
@@ -602,7 +635,8 @@ slice_l([CP1|[CP2|_]=Cont], N) when ?ASCII_LIST(CP1,CP2),N > 0 ->
slice_l(CD, N) when N > 0 ->
case unicode_util:gc(CD) of
[_|Cont] -> slice_l(Cont, N-1);
- [] -> []
+ [] -> [];
+ {error, Err} -> error({badarg, Err})
end;
slice_l(Cont, 0) ->
Cont.
@@ -614,7 +648,8 @@ slice_lb(Bin, CP1, N) ->
if N > 1 ->
case unicode_util:cp(Rest) of
[CP2|Cont] -> slice_lb(Cont, CP2, N-1);
- [] -> <<>>
+ [] -> <<>>;
+ {error, Err} -> error({badarg, Err})
end;
N =:= 1 ->
Rest
@@ -627,7 +662,10 @@ slice_trail(Orig, N) when is_binary(Orig) ->
Sz = byte_size(Orig) - Length,
<<Keep:Sz/binary, _/binary>> = Orig,
Keep;
- _ -> <<>>
+ <<_, _/binary>> when N > 0 ->
+ error({badarg, Orig});
+ _ ->
+ <<>>
end;
slice_trail(CD, N) when is_list(CD) ->
slice_list(CD, N).
@@ -637,7 +675,8 @@ slice_list([CP1|[CP2|_]=Cont], N) when ?ASCII_LIST(CP1,CP2),N > 0 ->
slice_list(CD, N) when N > 0 ->
case unicode_util:gc(CD) of
[GC|Cont] -> append(GC, slice_list(Cont, N-1));
- [] -> []
+ [] -> [];
+ {error, Err} -> error({badarg, Err})
end;
slice_list(_, 0) ->
[].
@@ -648,57 +687,145 @@ slice_bin(CD, CP1, N) when N > 0 ->
[_|Bin] = unicode_util:gc([CP1|CD]),
case unicode_util:cp(Bin) of
[CP2|Cont] -> slice_bin(Cont, CP2, N-1);
- [] -> 0
+ [] -> 0;
+ {error, Err} -> error({badarg, Err})
end;
slice_bin(CD, CP1, 0) ->
byte_size(CD)+byte_size(<<CP1/utf8>>).
-uppercase_list(CPs0) ->
+uppercase_list([CP1|[CP2|_]=Cont], _Changed) when $a =< CP1, CP1 =< $z, CP2 < 256 ->
+ [CP1-32|uppercase_list(Cont, true)];
+uppercase_list([CP1|[CP2|_]=Cont], Changed) when CP1 < 128, CP2 < 256 ->
+ [CP1|uppercase_list(Cont, Changed)];
+uppercase_list([], true) ->
+ [];
+uppercase_list([], false) ->
+ throw(unchanged);
+uppercase_list(CPs0, Changed) ->
case unicode_util:uppercase(CPs0) of
- [Char|CPs] -> append(Char,uppercase_list(CPs));
- [] -> []
+ [Char|CPs] when Char =:= hd(CPs0) -> [Char|uppercase_list(CPs, Changed)];
+ [Char|CPs] -> append(Char,uppercase_list(CPs, true));
+ [] -> uppercase_list([], Changed)
end.
-uppercase_bin(CPs0, Acc) ->
- case unicode_util:uppercase(CPs0) of
- [Char|CPs] when is_integer(Char) ->
- uppercase_bin(CPs, <<Acc/binary, Char/utf8>>);
- [Chars|CPs] ->
- uppercase_bin(CPs, <<Acc/binary,
- << <<CP/utf8>> || CP <- Chars>>/binary >>);
- [] -> Acc
+uppercase_bin(CP1, <<CP2/utf8, Bin/binary>>, _Changed)
+ when $a =< CP1, CP1 =< $z, CP2 < 256 ->
+ [CP1-32|uppercase_bin(CP2, Bin, true)];
+uppercase_bin(CP1, <<CP2/utf8, Bin/binary>>, Changed)
+ when CP1 < 128, CP2 < 256 ->
+ [CP1|uppercase_bin(CP2, Bin, Changed)];
+uppercase_bin(CP1, Bin, Changed) ->
+ case unicode_util:uppercase([CP1|Bin]) of
+ [CP1|CPs] ->
+ case unicode_util:cp(CPs) of
+ [Next|Rest] ->
+ [CP1|uppercase_bin(Next, Rest, Changed)];
+ [] when Changed ->
+ [CP1];
+ [] ->
+ throw(unchanged);
+ {error, Err} ->
+ error({badarg, Err})
+ end;
+ [Char|CPs] ->
+ case unicode_util:cp(CPs) of
+ [Next|Rest] ->
+ [Char|uppercase_bin(Next, Rest, true)];
+ [] ->
+ [Char];
+ {error, Err} ->
+ error({badarg, Err})
+ end
end.
-lowercase_list(CPs0) ->
+lowercase_list([CP1|[CP2|_]=Cont], _Changed) when $A =< CP1, CP1 =< $Z, CP2 < 256 ->
+ [CP1+32|lowercase_list(Cont, true)];
+lowercase_list([CP1|[CP2|_]=Cont], Changed) when CP1 < 128, CP2 < 256 ->
+ [CP1|lowercase_list(Cont, Changed)];
+lowercase_list([], true) ->
+ [];
+lowercase_list([], false) ->
+ throw(unchanged);
+lowercase_list(CPs0, Changed) ->
case unicode_util:lowercase(CPs0) of
- [Char|CPs] -> append(Char,lowercase_list(CPs));
- [] -> []
+ [Char|CPs] when Char =:= hd(CPs0) -> [Char|lowercase_list(CPs, Changed)];
+ [Char|CPs] -> append(Char,lowercase_list(CPs, true));
+ [] -> lowercase_list([], Changed)
end.
-lowercase_bin(CPs0, Acc) ->
- case unicode_util:lowercase(CPs0) of
- [Char|CPs] when is_integer(Char) ->
- lowercase_bin(CPs, <<Acc/binary, Char/utf8>>);
- [Chars|CPs] ->
- lowercase_bin(CPs, <<Acc/binary,
- << <<CP/utf8>> || CP <- Chars>>/binary >>);
- [] -> Acc
+lowercase_bin(CP1, <<CP2/utf8, Bin/binary>>, _Changed)
+ when $A =< CP1, CP1 =< $Z, CP2 < 256 ->
+ [CP1+32|lowercase_bin(CP2, Bin, true)];
+lowercase_bin(CP1, <<CP2/utf8, Bin/binary>>, Changed)
+ when CP1 < 128, CP2 < 256 ->
+ [CP1|lowercase_bin(CP2, Bin, Changed)];
+lowercase_bin(CP1, Bin, Changed) ->
+ case unicode_util:lowercase([CP1|Bin]) of
+ [CP1|CPs] ->
+ case unicode_util:cp(CPs) of
+ [Next|Rest] ->
+ [CP1|lowercase_bin(Next, Rest, Changed)];
+ [] when Changed ->
+ [CP1];
+ [] ->
+ throw(unchanged);
+ {error, Err} ->
+ error({badarg, Err})
+ end;
+ [Char|CPs] ->
+ case unicode_util:cp(CPs) of
+ [Next|Rest] ->
+ [Char|lowercase_bin(Next, Rest, true)];
+ [] ->
+ [Char];
+ {error, Err} ->
+ error({badarg, Err})
+ end
end.
-casefold_list(CPs0) ->
+casefold_list([CP1|[CP2|_]=Cont], _Changed) when $A =< CP1, CP1 =< $Z, CP2 < 256 ->
+ [CP1+32|casefold_list(Cont, true)];
+casefold_list([CP1|[CP2|_]=Cont], Changed) when CP1 < 128, CP2 < 256 ->
+ [CP1|casefold_list(Cont, Changed)];
+casefold_list([], true) ->
+ [];
+casefold_list([], false) ->
+ throw(unchanged);
+casefold_list(CPs0, Changed) ->
case unicode_util:casefold(CPs0) of
- [Char|CPs] -> append(Char, casefold_list(CPs));
- [] -> []
+ [Char|CPs] when Char =:= hd(CPs0) -> [Char|casefold_list(CPs, Changed)];
+ [Char|CPs] -> append(Char,casefold_list(CPs, true));
+ [] -> casefold_list([], Changed)
end.
-casefold_bin(CPs0, Acc) ->
- case unicode_util:casefold(CPs0) of
- [Char|CPs] when is_integer(Char) ->
- casefold_bin(CPs, <<Acc/binary, Char/utf8>>);
- [Chars|CPs] ->
- casefold_bin(CPs, <<Acc/binary,
- << <<CP/utf8>> || CP <- Chars>>/binary >>);
- [] -> Acc
+casefold_bin(CP1, <<CP2/utf8, Bin/binary>>, _Changed)
+ when $A =< CP1, CP1 =< $Z, CP2 < 256 ->
+ [CP1+32|casefold_bin(CP2, Bin, true)];
+casefold_bin(CP1, <<CP2/utf8, Bin/binary>>, Changed)
+ when CP1 < 128, CP2 < 256 ->
+ [CP1|casefold_bin(CP2, Bin, Changed)];
+casefold_bin(CP1, Bin, Changed) ->
+ case unicode_util:casefold([CP1|Bin]) of
+ [CP1|CPs] ->
+ case unicode_util:cp(CPs) of
+ [Next|Rest] ->
+ [CP1|casefold_bin(Next, Rest, Changed)];
+ [] when Changed ->
+ [CP1];
+ [] ->
+ throw(unchanged);
+ {error, Err} ->
+ error({badarg, Err})
+ end;
+ [Char|CPs] ->
+ case unicode_util:cp(CPs) of
+ [Next|Rest] ->
+ [Char|casefold_bin(Next, Rest, true)];
+ [] ->
+ [Char];
+ {error, Err} ->
+ error({badarg, Err})
+ end
end.
%% Fast path for ascii searching for one character in lists
@@ -1152,18 +1279,20 @@ split_1(Bin, [_C|_]=Needle, Start, Where, Curr0, Acc) ->
end
end.
-lexemes_m([CP|_]=Cs0, {GCs,CPs,_}=Seps, Ts) when is_integer(CP) ->
+lexemes_m([CP|_]=Cs0, {GCs,CPs,_}=Seps0, Ts) when is_integer(CP) ->
case lists:member(CP, CPs) of
true ->
[GC|Cs2] = unicode_util:gc(Cs0),
case lists:member(GC, GCs) of
true ->
- lexemes_m(Cs2, Seps, Ts);
+ lexemes_m(Cs2, Seps0, Ts);
false ->
+ Seps = search_compile(Seps0),
{Lexeme,Rest} = lexeme_pick(Cs0, Seps, []),
lexemes_m(Rest, Seps, [Lexeme|Ts])
end;
false ->
+ Seps = search_compile(Seps0),
{Lexeme,Rest} = lexeme_pick(Cs0, Seps, []),
lexemes_m(Rest, Seps, [Lexeme|Ts])
end;
@@ -1537,7 +1666,9 @@ bin_search_inv_1(<<CP1/utf8, BinRest/binary>>=Bin0, Cont, Sep) ->
bin_search_inv_1(<<>>, Cont, _Sep) ->
{nomatch, Cont};
bin_search_inv_1([], Cont, _Sep) ->
- {nomatch, Cont}.
+ {nomatch, Cont};
+bin_search_inv_1(Bin, _, _) ->
+ error({badarg, Bin}).
bin_search_inv_n(<<CP1/utf8, BinRest/binary>>=Bin0, Cont, Seps) ->
@@ -1569,7 +1700,9 @@ bin_search_inv_n(<<CP1/utf8, BinRest/binary>>=Bin0, Cont, Seps) ->
bin_search_inv_n(<<>>, Cont, _Sep) ->
{nomatch, Cont};
bin_search_inv_n([], Cont, _Sep) ->
- {nomatch, Cont}.
+ {nomatch, Cont};
+bin_search_inv_n(Bin, _, _) ->
+ error({badarg, Bin}).
bin_search_str(Bin0, Start, [], SearchCPs) ->
Compiled = binary:compile_pattern(unicode:characters_to_binary(SearchCPs)),
diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl
index 7920e55930..1ac7334830 100644
--- a/lib/stdlib/src/supervisor.erl
+++ b/lib/stdlib/src/supervisor.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -31,11 +31,24 @@
%% Internal exports
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3, format_status/2]).
--export([try_again_restart/2]).
%% For release_handler only
-export([get_callback_module/1]).
+-include("logger.hrl").
+
+-define(report_error(Error, Reason, Child, SupName),
+ ?LOG_ERROR(#{label=>{supervisor,Error},
+ report=>[{supervisor,SupName},
+ {errorContext,Error},
+ {reason,Reason},
+ {offender,extract_child(Child)}]},
+ #{domain=>[otp,sasl],
+ report_cb=>fun logger:format_otp_report/1,
+ logger_formatter=>#{title=>"SUPERVISOR REPORT"},
+ error_logger=>#{tag=>error_report,
+ type=>supervisor_report}})).
+
%%--------------------------------------------------------------------------
-export_type([sup_flags/0, child_spec/0, startchild_ret/0, strategy/0]).
@@ -79,6 +92,7 @@
| {RestartStrategy :: strategy(),
Intensity :: non_neg_integer(),
Period :: pos_integer()}.
+-type children() :: {Ids :: [child_id()], Db :: #{child_id() => child_rec()}}.
%%--------------------------------------------------------------------------
%% Defaults
@@ -96,7 +110,7 @@
pid = undefined :: child()
| {restarting, pid() | undefined}
| [pid()],
- name :: child_id(),
+ id :: child_id(),
mfargs :: mfargs(),
restart_type :: restart(),
shutdown :: shutdown(),
@@ -104,16 +118,11 @@
modules = [] :: modules()}).
-type child_rec() :: #child{}.
--define(DICTS, dict).
--define(DICT, dict:dict).
--define(SETS, sets).
--define(SET, sets:set).
-
-record(state, {name,
strategy :: strategy() | 'undefined',
- children = [] :: [child_rec()],
- dynamics :: {'dict', ?DICT(pid(), list())}
- | {'set', ?SET(pid())}
+ children = {[],#{}} :: children(), % Ids in start order
+ dynamics :: {'maps', #{pid() => list()}}
+ | {'sets', sets:set(pid())}
| 'undefined',
intensity :: non_neg_integer() | 'undefined',
period :: pos_integer() | 'undefined',
@@ -124,6 +133,9 @@
-type state() :: #state{}.
-define(is_simple(State), State#state.strategy =:= simple_one_for_one).
+-define(is_temporary(_Child_), _Child_#child.restart_type=:=temporary).
+-define(is_transient(_Child_), _Child_#child.restart_type=:=transient).
+-define(is_permanent(_Child_), _Child_#child.restart_type=:=permanent).
-callback init(Args :: term()) ->
{ok, {SupFlags :: sup_flags(), [ChildSpec :: child_spec()]}}
@@ -179,16 +191,16 @@ start_child(Supervisor, ChildSpec) ->
| {'error', Error},
Error :: 'running' | 'restarting' | 'not_found' | 'simple_one_for_one' |
term().
-restart_child(Supervisor, Name) ->
- call(Supervisor, {restart_child, Name}).
+restart_child(Supervisor, Id) ->
+ call(Supervisor, {restart_child, Id}).
-spec delete_child(SupRef, Id) -> Result when
SupRef :: sup_ref(),
Id :: child_id(),
Result :: 'ok' | {'error', Error},
Error :: 'running' | 'restarting' | 'not_found' | 'simple_one_for_one'.
-delete_child(Supervisor, Name) ->
- call(Supervisor, {delete_child, Name}).
+delete_child(Supervisor, Id) ->
+ call(Supervisor, {delete_child, Id}).
%%-----------------------------------------------------------------
%% Func: terminate_child/2
@@ -202,16 +214,16 @@ delete_child(Supervisor, Name) ->
Id :: pid() | child_id(),
Result :: 'ok' | {'error', Error},
Error :: 'not_found' | 'simple_one_for_one'.
-terminate_child(Supervisor, Name) ->
- call(Supervisor, {terminate_child, Name}).
+terminate_child(Supervisor, Id) ->
+ call(Supervisor, {terminate_child, Id}).
-spec get_childspec(SupRef, Id) -> Result when
SupRef :: sup_ref(),
Id :: pid() | child_id(),
Result :: {'ok', child_spec()} | {'error', Error},
Error :: 'not_found'.
-get_childspec(Supervisor, Name) ->
- call(Supervisor, {get_childspec, Name}).
+get_childspec(Supervisor, Id) ->
+ call(Supervisor, {get_childspec, Id}).
-spec which_children(SupRef) -> [{Id,Child,Type,Modules}] when
SupRef :: sup_ref(),
@@ -246,17 +258,6 @@ check_childspecs(ChildSpecs) when is_list(ChildSpecs) ->
check_childspecs(X) -> {error, {badarg, X}}.
%%%-----------------------------------------------------------------
-%%% Called by restart/2
--spec try_again_restart(SupRef, Child) -> ok when
- SupRef :: sup_ref(),
- Child :: child_id() | pid().
-try_again_restart(Supervisor, Child) ->
- cast(Supervisor, {try_again_restart, Child}).
-
-cast(Supervisor, Req) ->
- gen_server:cast(Supervisor, Req).
-
-%%%-----------------------------------------------------------------
%%% Called by release_handler during upgrade
-spec get_callback_module(Pid) -> Module when
Pid :: pid(),
@@ -325,7 +326,7 @@ init_children(State, StartSpec) ->
init_dynamic(State, [StartSpec]) ->
case check_startspec([StartSpec]) of
{ok, Children} ->
- {ok, State#state{children = Children}};
+ {ok, dyn_init(State#state{children = Children})};
Error ->
{stop, {start_spec, Error}}
end;
@@ -334,35 +335,34 @@ init_dynamic(_State, StartSpec) ->
%%-----------------------------------------------------------------
%% Func: start_children/2
-%% Args: Children = [child_rec()] in start order
+%% Args: Children = children() % Ids in start order
%% SupName = {local, atom()} | {global, atom()} | {pid(), Mod}
-%% Purpose: Start all children. The new list contains #child's
+%% Purpose: Start all children. The new map contains #child's
%% with pids.
%% Returns: {ok, NChildren} | {error, NChildren, Reason}
-%% NChildren = [child_rec()] in termination order (reversed
-%% start order)
+%% NChildren = children() % Ids in termination order
+%% (reversed start order)
%%-----------------------------------------------------------------
-start_children(Children, SupName) -> start_children(Children, [], SupName).
-
-start_children([Child|Chs], NChildren, SupName) ->
- case do_start_child(SupName, Child) of
- {ok, undefined} when Child#child.restart_type =:= temporary ->
- start_children(Chs, NChildren, SupName);
- {ok, Pid} ->
- start_children(Chs, [Child#child{pid = Pid}|NChildren], SupName);
- {ok, Pid, _Extra} ->
- start_children(Chs, [Child#child{pid = Pid}|NChildren], SupName);
- {error, Reason} ->
- report_error(start_error, Reason, Child, SupName),
- {error, lists:reverse(Chs) ++ [Child | NChildren],
- {failed_to_start_child,Child#child.name,Reason}}
- end;
-start_children([], NChildren, _SupName) ->
- {ok, NChildren}.
+start_children(Children, SupName) ->
+ Start =
+ fun(Id,Child) ->
+ case do_start_child(SupName, Child) of
+ {ok, undefined} when ?is_temporary(Child) ->
+ remove;
+ {ok, Pid} ->
+ {update,Child#child{pid = Pid}};
+ {ok, Pid, _Extra} ->
+ {update,Child#child{pid = Pid}};
+ {error, Reason} ->
+ ?report_error(start_error, Reason, Child, SupName),
+ {abort,{failed_to_start_child,Id,Reason}}
+ end
+ end,
+ children_map(Start,Children).
do_start_child(SupName, Child) ->
#child{mfargs = {M, F, Args}} = Child,
- case catch apply(M, F, Args) of
+ case do_start_child_i(M, F, Args) of
{ok, Pid} when is_pid(Pid) ->
NChild = Child#child{pid = Pid},
report_progress(NChild, SupName),
@@ -371,10 +371,8 @@ do_start_child(SupName, Child) ->
NChild = Child#child{pid = Pid},
report_progress(NChild, SupName),
{ok, Pid, Extra};
- ignore ->
- {ok, undefined};
- {error, What} -> {error, What};
- What -> {error, What}
+ Other ->
+ Other
end.
do_start_child_i(M, F, A) ->
@@ -400,17 +398,17 @@ do_start_child_i(M, F, A) ->
-spec handle_call(call(), term(), state()) -> {'reply', term(), state()}.
handle_call({start_child, EArgs}, _From, State) when ?is_simple(State) ->
- Child = hd(State#state.children),
+ Child = get_dynamic_child(State),
#child{mfargs = {M, F, A}} = Child,
Args = A ++ EArgs,
case do_start_child_i(M, F, Args) of
{ok, undefined} ->
{reply, {ok, undefined}, State};
{ok, Pid} ->
- NState = save_dynamic_child(Child#child.restart_type, Pid, Args, State),
+ NState = dyn_store(Pid, Args, State),
{reply, {ok, Pid}, NState};
{ok, Pid, Extra} ->
- NState = save_dynamic_child(Child#child.restart_type, Pid, Args, State),
+ NState = dyn_store(Pid, Args, State),
{reply, {ok, Pid, Extra}, NState};
What ->
{reply, What, State}
@@ -426,121 +424,94 @@ handle_call({start_child, ChildSpec}, _From, State) ->
end;
%% terminate_child for simple_one_for_one can only be done with pid
-handle_call({terminate_child, Name}, _From, State) when not is_pid(Name),
- ?is_simple(State) ->
+handle_call({terminate_child, Id}, _From, State) when not is_pid(Id),
+ ?is_simple(State) ->
{reply, {error, simple_one_for_one}, State};
-handle_call({terminate_child, Name}, _From, State) ->
- case get_child(Name, State, ?is_simple(State)) of
- {value, Child} ->
- case do_terminate(Child, State#state.name) of
- #child{restart_type=RT} when RT=:=temporary; ?is_simple(State) ->
- {reply, ok, state_del_child(Child, State)};
- NChild ->
- {reply, ok, replace_child(NChild, State)}
- end;
- false ->
+handle_call({terminate_child, Id}, _From, State) ->
+ case find_child(Id, State) of
+ {ok, Child} ->
+ do_terminate(Child, State#state.name),
+ {reply, ok, del_child(Child, State)};
+ error ->
{reply, {error, not_found}, State}
end;
%% restart_child request is invalid for simple_one_for_one supervisors
-handle_call({restart_child, _Name}, _From, State) when ?is_simple(State) ->
+handle_call({restart_child, _Id}, _From, State) when ?is_simple(State) ->
{reply, {error, simple_one_for_one}, State};
-handle_call({restart_child, Name}, _From, State) ->
- case get_child(Name, State) of
- {value, Child} when Child#child.pid =:= undefined ->
+handle_call({restart_child, Id}, _From, State) ->
+ case find_child(Id, State) of
+ {ok, Child} when Child#child.pid =:= undefined ->
case do_start_child(State#state.name, Child) of
{ok, Pid} ->
- NState = replace_child(Child#child{pid = Pid}, State),
+ NState = set_pid(Pid, Id, State),
{reply, {ok, Pid}, NState};
{ok, Pid, Extra} ->
- NState = replace_child(Child#child{pid = Pid}, State),
+ NState = set_pid(Pid, Id, State),
{reply, {ok, Pid, Extra}, NState};
Error ->
{reply, Error, State}
end;
- {value, #child{pid=?restarting(_)}} ->
+ {ok, #child{pid=?restarting(_)}} ->
{reply, {error, restarting}, State};
- {value, _} ->
+ {ok, _} ->
{reply, {error, running}, State};
_ ->
{reply, {error, not_found}, State}
end;
%% delete_child request is invalid for simple_one_for_one supervisors
-handle_call({delete_child, _Name}, _From, State) when ?is_simple(State) ->
+handle_call({delete_child, _Id}, _From, State) when ?is_simple(State) ->
{reply, {error, simple_one_for_one}, State};
-handle_call({delete_child, Name}, _From, State) ->
- case get_child(Name, State) of
- {value, Child} when Child#child.pid =:= undefined ->
- NState = remove_child(Child, State),
+handle_call({delete_child, Id}, _From, State) ->
+ case find_child(Id, State) of
+ {ok, Child} when Child#child.pid =:= undefined ->
+ NState = remove_child(Id, State),
{reply, ok, NState};
- {value, #child{pid=?restarting(_)}} ->
+ {ok, #child{pid=?restarting(_)}} ->
{reply, {error, restarting}, State};
- {value, _} ->
+ {ok, _} ->
{reply, {error, running}, State};
_ ->
{reply, {error, not_found}, State}
end;
-handle_call({get_childspec, Name}, _From, State) ->
- case get_child(Name, State, ?is_simple(State)) of
- {value, Child} ->
+handle_call({get_childspec, Id}, _From, State) ->
+ case find_child(Id, State) of
+ {ok, Child} ->
{reply, {ok, child_to_spec(Child)}, State};
- false ->
+ error ->
{reply, {error, not_found}, State}
end;
-handle_call(which_children, _From, #state{children = [#child{restart_type = temporary,
- child_type = CT,
- modules = Mods}]} =
- State) when ?is_simple(State) ->
- Reply = lists:map(fun(Pid) -> {undefined, Pid, CT, Mods} end,
- ?SETS:to_list(dynamics_db(temporary, State#state.dynamics))),
- {reply, Reply, State};
-
-handle_call(which_children, _From, #state{children = [#child{restart_type = RType,
- child_type = CT,
- modules = Mods}]} =
- State) when ?is_simple(State) ->
- Reply = lists:map(fun({?restarting(_),_}) -> {undefined,restarting,CT,Mods};
- ({Pid, _}) -> {undefined, Pid, CT, Mods} end,
- ?DICTS:to_list(dynamics_db(RType, State#state.dynamics))),
+handle_call(which_children, _From, State) when ?is_simple(State) ->
+ #child{child_type = CT,modules = Mods} = get_dynamic_child(State),
+ Reply = dyn_map(fun(?restarting(_)) -> {undefined, restarting, CT, Mods};
+ (Pid) -> {undefined, Pid, CT, Mods}
+ end, State),
{reply, Reply, State};
handle_call(which_children, _From, State) ->
Resp =
- lists:map(fun(#child{pid = ?restarting(_), name = Name,
- child_type = ChildType, modules = Mods}) ->
- {Name, restarting, ChildType, Mods};
- (#child{pid = Pid, name = Name,
- child_type = ChildType, modules = Mods}) ->
- {Name, Pid, ChildType, Mods}
- end,
- State#state.children),
+ children_to_list(
+ fun(Id,#child{pid = ?restarting(_),
+ child_type = ChildType, modules = Mods}) ->
+ {Id, restarting, ChildType, Mods};
+ (Id,#child{pid = Pid,
+ child_type = ChildType, modules = Mods}) ->
+ {Id, Pid, ChildType, Mods}
+ end,
+ State#state.children),
{reply, Resp, State};
-
-handle_call(count_children, _From, #state{children = [#child{restart_type = temporary,
- child_type = CT}]} = State)
+handle_call(count_children, _From, #state{dynamic_restarts = Restarts} = State)
when ?is_simple(State) ->
- Sz = ?SETS:size(dynamics_db(temporary, State#state.dynamics)),
- Reply = case CT of
- supervisor -> [{specs, 1}, {active, Sz},
- {supervisors, Sz}, {workers, 0}];
- worker -> [{specs, 1}, {active, Sz},
- {supervisors, 0}, {workers, Sz}]
- end,
- {reply, Reply, State};
-
-handle_call(count_children, _From, #state{dynamic_restarts = Restarts,
- children = [#child{restart_type = RType,
- child_type = CT}]} = State)
- when ?is_simple(State) ->
- Sz = ?DICTS:size(dynamics_db(RType, State#state.dynamics)),
- Active = Sz - Restarts,
+ #child{child_type = CT} = get_dynamic_child(State),
+ Sz = dyn_size(State),
+ Active = Sz - Restarts, % Restarts is always 0 for temporary children
Reply = case CT of
supervisor -> [{specs, 1}, {active, Active},
{supervisors, Sz}, {workers, 0}];
@@ -552,16 +523,15 @@ handle_call(count_children, _From, #state{dynamic_restarts = Restarts,
handle_call(count_children, _From, State) ->
%% Specs and children are together on the children list...
{Specs, Active, Supers, Workers} =
- lists:foldl(fun(Child, Counts) ->
- count_child(Child, Counts)
- end, {0,0,0,0}, State#state.children),
+ children_fold(fun(_Id, Child, Counts) ->
+ count_child(Child, Counts)
+ end, {0,0,0,0}, State#state.children),
%% Reformat counts to a property list.
Reply = [{specs, Specs}, {active, Active},
{supervisors, Supers}, {workers, Workers}],
{reply, Reply, State}.
-
count_child(#child{pid = Pid, child_type = worker},
{Specs, Active, Supers, Workers}) ->
case is_pid(Pid) andalso is_process_alive(Pid) of
@@ -575,34 +545,15 @@ count_child(#child{pid = Pid, child_type = supervisor},
false -> {Specs+1, Active, Supers+1, Workers}
end.
-
%%% If a restart attempt failed, this message is cast
%%% from restart/2 in order to give gen_server the chance to
%%% check it's inbox before trying again.
--spec handle_cast({try_again_restart, child_id() | pid()}, state()) ->
+-spec handle_cast({try_again_restart, child_id() | {'restarting',pid()}}, state()) ->
{'noreply', state()} | {stop, shutdown, state()}.
-handle_cast({try_again_restart,Pid}, #state{children=[Child]}=State)
- when ?is_simple(State) ->
- RT = Child#child.restart_type,
- RPid = restarting(Pid),
- case dynamic_child_args(RPid, RT, State#state.dynamics) of
- {ok, Args} ->
- {M, F, _} = Child#child.mfargs,
- NChild = Child#child{pid = RPid, mfargs = {M, F, Args}},
- case restart(NChild,State) of
- {ok, State1} ->
- {noreply, State1};
- {shutdown, State1} ->
- {stop, shutdown, State1}
- end;
- error ->
- {noreply, State}
- end;
-
-handle_cast({try_again_restart,Name}, State) ->
- case lists:keyfind(Name,#child.name,State#state.children) of
- Child = #child{pid=?restarting(_)} ->
+handle_cast({try_again_restart,TryAgainId}, State) ->
+ case find_child_and_args(TryAgainId, State) of
+ {ok, Child = #child{pid=?restarting(_)}} ->
case restart(Child,State) of
{ok, State1} ->
{noreply, State1};
@@ -628,8 +579,9 @@ handle_info({'EXIT', Pid, Reason}, State) ->
end;
handle_info(Msg, State) ->
- error_logger:error_msg("Supervisor received unexpected message: ~tp~n",
- [Msg]),
+ ?LOG_ERROR("Supervisor received unexpected message: ~tp~n",[Msg],
+ #{domain=>[otp],
+ error_logger=>#{tag=>error}}),
{noreply, State}.
%%
@@ -637,10 +589,8 @@ handle_info(Msg, State) ->
%%
-spec terminate(term(), state()) -> 'ok'.
-terminate(_Reason, #state{children=[Child]} = State) when ?is_simple(State) ->
- terminate_dynamic_children(Child, dynamics_db(Child#child.restart_type,
- State#state.dynamics),
- State#state.name);
+terminate(_Reason, State) when ?is_simple(State) ->
+ terminate_dynamic_children(State);
terminate(_Reason, State) ->
terminate_children(State#state.children, State#state.name).
@@ -675,8 +625,8 @@ code_change(_, State, _) ->
update_childspec(State, StartSpec) when ?is_simple(State) ->
case check_startspec(StartSpec) of
- {ok, [Child]} ->
- {ok, State#state{children = [Child]}};
+ {ok, {[_],_}=Children} ->
+ {ok, State#state{children = Children}};
Error ->
{error, Error}
end;
@@ -690,39 +640,36 @@ update_childspec(State, StartSpec) ->
{error, Error}
end.
-update_childspec1([Child|OldC], Children, KeepOld) ->
- case update_chsp(Child, Children) of
- {ok,NewChildren} ->
- update_childspec1(OldC, NewChildren, KeepOld);
+update_childspec1({[Id|OldIds], OldDb}, {Ids,Db}, KeepOld) ->
+ case update_chsp(maps:get(Id,OldDb), Db) of
+ {ok,NewDb} ->
+ update_childspec1({OldIds,OldDb}, {Ids,NewDb}, KeepOld);
false ->
- update_childspec1(OldC, Children, [Child|KeepOld])
+ update_childspec1({OldIds,OldDb}, {Ids,Db}, [Id|KeepOld])
end;
-update_childspec1([], Children, KeepOld) ->
+update_childspec1({[],OldDb}, {Ids,Db}, KeepOld) ->
+ KeepOldDb = maps:with(KeepOld,OldDb),
%% Return them in (kept) reverse start order.
- lists:reverse(Children ++ KeepOld).
-
-update_chsp(OldCh, Children) ->
- case lists:map(fun(Ch) when OldCh#child.name =:= Ch#child.name ->
- Ch#child{pid = OldCh#child.pid};
- (Ch) ->
- Ch
- end,
- Children) of
- Children ->
- false; % OldCh not found in new spec.
- NewC ->
- {ok, NewC}
+ {lists:reverse(Ids ++ KeepOld),maps:merge(KeepOldDb,Db)}.
+
+update_chsp(#child{id=Id}=OldChild, NewDb) ->
+ case maps:find(Id, NewDb) of
+ {ok,Child} ->
+ {ok,NewDb#{Id => Child#child{pid = OldChild#child.pid}}};
+ error -> % Id not found in new spec.
+ false
end.
+
%%% ---------------------------------------------------
%%% Start a new child.
%%% ---------------------------------------------------
handle_start_child(Child, State) ->
- case get_child(Child#child.name, State) of
- false ->
+ case find_child(Child#child.id, State) of
+ error ->
case do_start_child(State#state.name, Child) of
- {ok, undefined} when Child#child.restart_type =:= temporary ->
+ {ok, undefined} when ?is_temporary(Child) ->
{{ok, undefined}, State};
{ok, Pid} ->
{{ok, Pid}, save_child(Child#child{pid = Pid}, State)};
@@ -731,9 +678,9 @@ handle_start_child(Child, State) ->
{error, What} ->
{{error, {What, Child}}, State}
end;
- {value, OldChild} when is_pid(OldChild#child.pid) ->
+ {ok, OldChild} when is_pid(OldChild#child.pid) ->
{{error, {already_started, OldChild#child.pid}}, State};
- {value, _OldChild} ->
+ {ok, _OldChild} ->
{{error, already_present}, State}
end.
@@ -742,188 +689,157 @@ handle_start_child(Child, State) ->
%%% Returns: {ok, state()} | {shutdown, state()}
%%% ---------------------------------------------------
-restart_child(Pid, Reason, #state{children = [Child]} = State) when ?is_simple(State) ->
- RestartType = Child#child.restart_type,
- case dynamic_child_args(Pid, RestartType, State#state.dynamics) of
- {ok, Args} ->
- {M, F, _} = Child#child.mfargs,
- NChild = Child#child{pid = Pid, mfargs = {M, F, Args}},
- do_restart(RestartType, Reason, NChild, State);
- error ->
- {ok, State}
- end;
-
restart_child(Pid, Reason, State) ->
- Children = State#state.children,
- case lists:keyfind(Pid, #child.pid, Children) of
- #child{restart_type = RestartType} = Child ->
- do_restart(RestartType, Reason, Child, State);
- false ->
+ case find_child_and_args(Pid, State) of
+ {ok, Child} ->
+ do_restart(Reason, Child, State);
+ error ->
{ok, State}
end.
-do_restart(permanent, Reason, Child, State) ->
- report_error(child_terminated, Reason, Child, State#state.name),
+do_restart(Reason, Child, State) when ?is_permanent(Child) ->
+ ?report_error(child_terminated, Reason, Child, State#state.name),
restart(Child, State);
-do_restart(_, normal, Child, State) ->
- NState = state_del_child(Child, State),
+do_restart(normal, Child, State) ->
+ NState = del_child(Child, State),
{ok, NState};
-do_restart(_, shutdown, Child, State) ->
- NState = state_del_child(Child, State),
+do_restart(shutdown, Child, State) ->
+ NState = del_child(Child, State),
{ok, NState};
-do_restart(_, {shutdown, _Term}, Child, State) ->
- NState = state_del_child(Child, State),
+do_restart({shutdown, _Term}, Child, State) ->
+ NState = del_child(Child, State),
{ok, NState};
-do_restart(transient, Reason, Child, State) ->
- report_error(child_terminated, Reason, Child, State#state.name),
+do_restart(Reason, Child, State) when ?is_transient(Child) ->
+ ?report_error(child_terminated, Reason, Child, State#state.name),
restart(Child, State);
-do_restart(temporary, Reason, Child, State) ->
- report_error(child_terminated, Reason, Child, State#state.name),
- NState = state_del_child(Child, State),
+do_restart(Reason, Child, State) when ?is_temporary(Child) ->
+ ?report_error(child_terminated, Reason, Child, State#state.name),
+ NState = del_child(Child, State),
{ok, NState}.
restart(Child, State) ->
case add_restart(State) of
{ok, NState} ->
case restart(NState#state.strategy, Child, NState) of
- {try_again,NState2} ->
+ {{try_again, TryAgainId}, NState2} ->
%% Leaving control back to gen_server before
%% trying again. This way other incoming requsts
%% for the supervisor can be handled - e.g. a
%% shutdown request for the supervisor or the
%% child.
- Id = if ?is_simple(State) -> Child#child.pid;
- true -> Child#child.name
- end,
- ok = try_again_restart(self(), Id),
- {ok,NState2};
- {try_again, NState2, #child{name=ChName}} ->
- ok = try_again_restart(self(), ChName),
+ try_again_restart(TryAgainId),
{ok,NState2};
Other ->
Other
end;
{terminate, NState} ->
- report_error(shutdown, reached_max_restart_intensity,
+ ?report_error(shutdown, reached_max_restart_intensity,
Child, State#state.name),
- {shutdown, remove_child(Child, NState)}
+ {shutdown, del_child(Child, NState)}
end.
restart(simple_one_for_one, Child, State0) ->
#child{pid = OldPid, mfargs = {M, F, A}} = Child,
- State = case OldPid of
+ State1 = case OldPid of
?restarting(_) ->
NRes = State0#state.dynamic_restarts - 1,
State0#state{dynamic_restarts = NRes};
_ ->
State0
end,
- Dynamics = ?DICTS:erase(OldPid, dynamics_db(Child#child.restart_type,
- State#state.dynamics)),
+ State2 = dyn_erase(OldPid, State1),
case do_start_child_i(M, F, A) of
{ok, Pid} ->
- DynamicsDb = {dict, ?DICTS:store(Pid, A, Dynamics)},
- NState = State#state{dynamics = DynamicsDb},
+ NState = dyn_store(Pid, A, State2),
{ok, NState};
{ok, Pid, _Extra} ->
- DynamicsDb = {dict, ?DICTS:store(Pid, A, Dynamics)},
- NState = State#state{dynamics = DynamicsDb},
+ NState = dyn_store(Pid, A, State2),
{ok, NState};
{error, Error} ->
- NRestarts = State#state.dynamic_restarts + 1,
- DynamicsDb = {dict, ?DICTS:store(restarting(OldPid), A, Dynamics)},
- NState = State#state{dynamic_restarts = NRestarts,
- dynamics = DynamicsDb},
- report_error(start_error, Error, Child, State#state.name),
- {try_again, NState}
+ ROldPid = restarting(OldPid),
+ NRestarts = State2#state.dynamic_restarts + 1,
+ State3 = State2#state{dynamic_restarts = NRestarts},
+ NState = dyn_store(ROldPid, A, State3),
+ ?report_error(start_error, Error, Child, NState#state.name),
+ {{try_again, ROldPid}, NState}
end;
-restart(one_for_one, Child, State) ->
+restart(one_for_one, #child{id=Id} = Child, State) ->
OldPid = Child#child.pid,
case do_start_child(State#state.name, Child) of
{ok, Pid} ->
- NState = replace_child(Child#child{pid = Pid}, State),
+ NState = set_pid(Pid, Id, State),
{ok, NState};
{ok, Pid, _Extra} ->
- NState = replace_child(Child#child{pid = Pid}, State),
+ NState = set_pid(Pid, Id, State),
{ok, NState};
{error, Reason} ->
- NState = replace_child(Child#child{pid = restarting(OldPid)}, State),
- report_error(start_error, Reason, Child, State#state.name),
- {try_again, NState}
+ NState = set_pid(restarting(OldPid), Id, State),
+ ?report_error(start_error, Reason, Child, State#state.name),
+ {{try_again,Id}, NState}
end;
-restart(rest_for_one, Child, State) ->
- {ChAfter, ChBefore} = split_child(Child#child.pid, State#state.children),
- ChAfter2 = terminate_children(ChAfter, State#state.name),
- case start_children(ChAfter2, State#state.name) of
- {ok, ChAfter3} ->
- {ok, State#state{children = ChAfter3 ++ ChBefore}};
- {error, ChAfter3, {failed_to_start_child, ChName, _Reason}}
- when ChName =:= Child#child.name ->
- NChild = Child#child{pid=restarting(Child#child.pid)},
- NState = State#state{children = ChAfter3 ++ ChBefore},
- {try_again, replace_child(NChild,NState)};
- {error, ChAfter3, {failed_to_start_child, ChName, _Reason}} ->
- NChild = lists:keyfind(ChName, #child.name, ChAfter3),
- NChild2 = NChild#child{pid=?restarting(undefined)},
- NState = State#state{children = ChAfter3 ++ ChBefore},
- {try_again, replace_child(NChild2,NState), NChild2}
- end;
-restart(one_for_all, Child, State) ->
- Children1 = del_child(Child#child.pid, State#state.children),
- Children2 = terminate_children(Children1, State#state.name),
- case start_children(Children2, State#state.name) of
- {ok, NChs} ->
- {ok, State#state{children = NChs}};
- {error, NChs, {failed_to_start_child, ChName, _Reason}}
- when ChName =:= Child#child.name ->
- NChild = Child#child{pid=restarting(Child#child.pid)},
- NState = State#state{children = NChs},
- {try_again, replace_child(NChild,NState)};
- {error, NChs, {failed_to_start_child, ChName, _Reason}} ->
- NChild = lists:keyfind(ChName, #child.name, NChs),
- NChild2 = NChild#child{pid=?restarting(undefined)},
- NState = State#state{children = NChs},
- {try_again, replace_child(NChild2,NState), NChild2}
+restart(rest_for_one, #child{id=Id} = Child, #state{name=SupName} = State) ->
+ {ChAfter, ChBefore} = split_child(Id, State#state.children),
+ {Return, ChAfter2} = restart_multiple_children(Child, ChAfter, SupName),
+ {Return, State#state{children = append(ChAfter2,ChBefore)}};
+restart(one_for_all, Child, #state{name=SupName} = State) ->
+ Children1 = del_child(Child#child.id, State#state.children),
+ {Return, NChildren} = restart_multiple_children(Child, Children1, SupName),
+ {Return, State#state{children = NChildren}}.
+
+restart_multiple_children(Child, Children, SupName) ->
+ Children1 = terminate_children(Children, SupName),
+ case start_children(Children1, SupName) of
+ {ok, NChildren} ->
+ {ok, NChildren};
+ {error, NChildren, {failed_to_start_child, FailedId, _Reason}} ->
+ NewPid = if FailedId =:= Child#child.id ->
+ restarting(Child#child.pid);
+ true ->
+ ?restarting(undefined)
+ end,
+ {{try_again, FailedId}, set_pid(NewPid,FailedId,NChildren)}
end.
restarting(Pid) when is_pid(Pid) -> ?restarting(Pid);
restarting(RPid) -> RPid.
+-spec try_again_restart(child_id() | {'restarting',pid()}) -> 'ok'.
+try_again_restart(TryAgainId) ->
+ gen_server:cast(self(), {try_again_restart, TryAgainId}).
+
%%-----------------------------------------------------------------
%% Func: terminate_children/2
-%% Args: Children = [child_rec()] in termination order
+%% Args: Children = children() % Ids in termination order
%% SupName = {local, atom()} | {global, atom()} | {pid(),Mod}
-%% Returns: NChildren = [child_rec()] in
-%% startup order (reversed termination order)
+%% Returns: NChildren = children() % Ids in startup order
+%% % (reversed termination order)
%%-----------------------------------------------------------------
terminate_children(Children, SupName) ->
- terminate_children(Children, SupName, []).
-
-%% Temporary children should not be restarted and thus should
-%% be skipped when building the list of terminated children, although
-%% we do want them to be shut down as many functions from this module
-%% use this function to just clear everything.
-terminate_children([Child = #child{restart_type=temporary} | Children], SupName, Res) ->
- _ = do_terminate(Child, SupName),
- terminate_children(Children, SupName, Res);
-terminate_children([Child | Children], SupName, Res) ->
- NChild = do_terminate(Child, SupName),
- terminate_children(Children, SupName, [NChild | Res]);
-terminate_children([], _SupName, Res) ->
- Res.
+ Terminate =
+ fun(_Id,Child) when ?is_temporary(Child) ->
+ %% Temporary children should not be restarted and thus should
+ %% be skipped when building the list of terminated children.
+ do_terminate(Child, SupName),
+ remove;
+ (_Id,Child) ->
+ do_terminate(Child, SupName),
+ {update,Child#child{pid=undefined}}
+ end,
+ {ok,NChildren} = children_map(Terminate, Children),
+ NChildren.
do_terminate(Child, SupName) when is_pid(Child#child.pid) ->
case shutdown(Child#child.pid, Child#child.shutdown) of
ok ->
ok;
- {error, normal} when Child#child.restart_type =/= permanent ->
+ {error, normal} when not (?is_permanent(Child)) ->
ok;
{error, OtherReason} ->
- report_error(shutdown_error, OtherReason, Child, SupName)
+ ?report_error(shutdown_error, OtherReason, Child, SupName)
end,
- Child#child{pid = undefined};
-do_terminate(Child, _SupName) ->
- Child#child{pid = undefined}.
+ ok;
+do_terminate(_Child, _SupName) ->
+ ok.
%%-----------------------------------------------------------------
%% Shutdowns a child. We must check the EXIT value
@@ -996,66 +912,50 @@ monitor_child(Pid) ->
ok
end.
-
%%-----------------------------------------------------------------
-%% Func: terminate_dynamic_children/3
-%% Args: Child = child_rec()
-%% Dynamics = ?DICT() | ?SET()
-%% SupName = {local, atom()} | {global, atom()} | {pid(),Mod}
+%% Func: terminate_dynamic_children/1
+%% Args: State
%% Returns: ok
%%
-%%
%% Shutdown all dynamic children. This happens when the supervisor is
%% stopped. Because the supervisor can have millions of dynamic children, we
-%% can have an significative overhead here.
+%% can have a significative overhead here.
%%-----------------------------------------------------------------
-terminate_dynamic_children(Child, Dynamics, SupName) ->
- {Pids, EStack0} = monitor_dynamic_children(Child, Dynamics),
- Sz = ?SETS:size(Pids),
+terminate_dynamic_children(State) ->
+ Child = get_dynamic_child(State),
+ {Pids, EStack0} = monitor_dynamic_children(Child,State),
+ Sz = sets:size(Pids),
EStack = case Child#child.shutdown of
brutal_kill ->
- ?SETS:fold(fun(P, _) -> exit(P, kill) end, ok, Pids),
+ sets:fold(fun(P, _) -> exit(P, kill) end, ok, Pids),
wait_dynamic_children(Child, Pids, Sz, undefined, EStack0);
infinity ->
- ?SETS:fold(fun(P, _) -> exit(P, shutdown) end, ok, Pids),
+ sets:fold(fun(P, _) -> exit(P, shutdown) end, ok, Pids),
wait_dynamic_children(Child, Pids, Sz, undefined, EStack0);
Time ->
- ?SETS:fold(fun(P, _) -> exit(P, shutdown) end, ok, Pids),
+ sets:fold(fun(P, _) -> exit(P, shutdown) end, ok, Pids),
TRef = erlang:start_timer(Time, self(), kill),
wait_dynamic_children(Child, Pids, Sz, TRef, EStack0)
end,
%% Unroll stacked errors and report them
- ?DICTS:fold(fun(Reason, Ls, _) ->
- report_error(shutdown_error, Reason,
- Child#child{pid=Ls}, SupName)
- end, ok, EStack).
-
-
-monitor_dynamic_children(#child{restart_type=temporary}, Dynamics) ->
- ?SETS:fold(fun(P, {Pids, EStack}) ->
- case monitor_child(P) of
- ok ->
- {?SETS:add_element(P, Pids), EStack};
- {error, normal} ->
- {Pids, EStack};
- {error, Reason} ->
- {Pids, ?DICTS:append(Reason, P, EStack)}
- end
- end, {?SETS:new(), ?DICTS:new()}, Dynamics);
-monitor_dynamic_children(#child{restart_type=RType}, Dynamics) ->
- ?DICTS:fold(fun(P, _, {Pids, EStack}) when is_pid(P) ->
- case monitor_child(P) of
- ok ->
- {?SETS:add_element(P, Pids), EStack};
- {error, normal} when RType =/= permanent ->
- {Pids, EStack};
- {error, Reason} ->
- {Pids, ?DICTS:append(Reason, P, EStack)}
- end;
- (?restarting(_), _, {Pids, EStack}) ->
- {Pids, EStack}
- end, {?SETS:new(), ?DICTS:new()}, Dynamics).
-
+ dict:fold(fun(Reason, Ls, _) ->
+ ?report_error(shutdown_error, Reason,
+ Child#child{pid=Ls}, State#state.name)
+ end, ok, EStack).
+
+monitor_dynamic_children(Child,State) ->
+ dyn_fold(fun(P,{Pids, EStack}) when is_pid(P) ->
+ case monitor_child(P) of
+ ok ->
+ {sets:add_element(P, Pids), EStack};
+ {error, normal} when not (?is_permanent(Child)) ->
+ {Pids, EStack};
+ {error, Reason} ->
+ {Pids, dict:append(Reason, P, EStack)}
+ end;
+ (?restarting(_), {Pids, EStack}) ->
+ {Pids, EStack}
+ end, {sets:new(), dict:new()}, State).
wait_dynamic_children(_Child, _Pids, 0, undefined, EStack) ->
EStack;
@@ -1073,39 +973,38 @@ wait_dynamic_children(#child{shutdown=brutal_kill} = Child, Pids, Sz,
TRef, EStack) ->
receive
{'DOWN', _MRef, process, Pid, killed} ->
- wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1,
+ wait_dynamic_children(Child, sets:del_element(Pid, Pids), Sz-1,
TRef, EStack);
{'DOWN', _MRef, process, Pid, Reason} ->
- wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1,
- TRef, ?DICTS:append(Reason, Pid, EStack))
+ wait_dynamic_children(Child, sets:del_element(Pid, Pids), Sz-1,
+ TRef, dict:append(Reason, Pid, EStack))
end;
-wait_dynamic_children(#child{restart_type=RType} = Child, Pids, Sz,
- TRef, EStack) ->
+wait_dynamic_children(Child, Pids, Sz, TRef, EStack) ->
receive
{'DOWN', _MRef, process, Pid, shutdown} ->
- wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1,
+ wait_dynamic_children(Child, sets:del_element(Pid, Pids), Sz-1,
TRef, EStack);
{'DOWN', _MRef, process, Pid, {shutdown, _}} ->
- wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1,
+ wait_dynamic_children(Child, sets:del_element(Pid, Pids), Sz-1,
TRef, EStack);
- {'DOWN', _MRef, process, Pid, normal} when RType =/= permanent ->
- wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1,
+ {'DOWN', _MRef, process, Pid, normal} when not (?is_permanent(Child)) ->
+ wait_dynamic_children(Child, sets:del_element(Pid, Pids), Sz-1,
TRef, EStack);
{'DOWN', _MRef, process, Pid, Reason} ->
- wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1,
- TRef, ?DICTS:append(Reason, Pid, EStack));
+ wait_dynamic_children(Child, sets:del_element(Pid, Pids), Sz-1,
+ TRef, dict:append(Reason, Pid, EStack));
{timeout, TRef, kill} ->
- ?SETS:fold(fun(P, _) -> exit(P, kill) end, ok, Pids),
+ sets:fold(fun(P, _) -> exit(P, kill) end, ok, Pids),
wait_dynamic_children(Child, Pids, Sz, undefined, EStack)
end.
%%-----------------------------------------------------------------
-%% Child/State manipulating functions.
+%% Access #state.children
%%-----------------------------------------------------------------
%% Note we do not want to save the parameter list for temporary processes as
@@ -1113,114 +1012,184 @@ wait_dynamic_children(#child{restart_type=RType} = Child, Pids, Sz,
%% Especially for dynamic children to simple_one_for_one supervisors
%% it could become very costly as it is not uncommon to spawn
%% very many such processes.
-save_child(#child{restart_type = temporary,
- mfargs = {M, F, _}} = Child, #state{children = Children} = State) ->
- State#state{children = [Child#child{mfargs = {M, F, undefined}} |Children]};
-save_child(Child, #state{children = Children} = State) ->
- State#state{children = [Child |Children]}.
-
-save_dynamic_child(temporary, Pid, _, #state{dynamics = Dynamics} = State) ->
- DynamicsDb = dynamics_db(temporary, Dynamics),
- State#state{dynamics = {set, ?SETS:add_element(Pid, DynamicsDb)}};
-save_dynamic_child(RestartType, Pid, Args, #state{dynamics = Dynamics} = State) ->
- DynamicsDb = dynamics_db(RestartType, Dynamics),
- State#state{dynamics = {dict, ?DICTS:store(Pid, Args, DynamicsDb)}}.
-
-dynamics_db(temporary, undefined) ->
- ?SETS:new();
-dynamics_db(_, undefined) ->
- ?DICTS:new();
-dynamics_db(_, {_Tag, DynamicsDb}) ->
- DynamicsDb.
-
-dynamic_child_args(_Pid, temporary, _DynamicsDb) ->
- {ok, undefined};
-dynamic_child_args(Pid, _RT, {dict, DynamicsDb}) ->
- ?DICTS:find(Pid, DynamicsDb);
-dynamic_child_args(_Pid, _RT, undefined) ->
- error.
-
-state_del_child(#child{pid = Pid, restart_type = temporary}, State) when ?is_simple(State) ->
- NDynamics = ?SETS:del_element(Pid, dynamics_db(temporary, State#state.dynamics)),
- State#state{dynamics = {set, NDynamics}};
-state_del_child(#child{pid = Pid, restart_type = RType}, State) when ?is_simple(State) ->
- NDynamics = ?DICTS:erase(Pid, dynamics_db(RType, State#state.dynamics)),
- State#state{dynamics = {dict, NDynamics}};
-state_del_child(Child, State) ->
- NChildren = del_child(Child#child.name, State#state.children),
- State#state{children = NChildren}.
-
-del_child(Name, [Ch|Chs]) when Ch#child.name =:= Name, Ch#child.restart_type =:= temporary ->
- Chs;
-del_child(Name, [Ch|Chs]) when Ch#child.name =:= Name ->
- [Ch#child{pid = undefined} | Chs];
-del_child(Pid, [Ch|Chs]) when Ch#child.pid =:= Pid, Ch#child.restart_type =:= temporary ->
- Chs;
-del_child(Pid, [Ch|Chs]) when Ch#child.pid =:= Pid ->
- [Ch#child{pid = undefined} | Chs];
-del_child(Name, [Ch|Chs]) ->
- [Ch|del_child(Name, Chs)];
-del_child(_, []) ->
- [].
+-spec save_child(child_rec(), state()) -> state().
+save_child(#child{mfargs = {M, F, _}} = Child, State) when ?is_temporary(Child) ->
+ do_save_child(Child#child{mfargs = {M, F, undefined}}, State);
+save_child(Child, State) ->
+ do_save_child(Child, State).
+
+-spec do_save_child(child_rec(), state()) -> state().
+do_save_child(#child{id = Id} = Child, #state{children = {Ids,Db}} = State) ->
+ State#state{children = {[Id|Ids],Db#{Id => Child}}}.
+
+-spec del_child(child_rec(), state()) -> state();
+ (child_id(), children()) -> children().
+del_child(#child{pid = Pid}, State) when ?is_simple(State) ->
+ dyn_erase(Pid,State);
+del_child(Child, State) when is_record(Child,child), is_record(State,state) ->
+ NChildren = del_child(Child#child.id, State#state.children),
+ State#state{children = NChildren};
+del_child(Id, {Ids,Db}) ->
+ case maps:get(Id, Db) of
+ Child when Child#child.restart_type =:= temporary ->
+ {lists:delete(Id, Ids), maps:remove(Id, Db)};
+ Child ->
+ {Ids, Db#{Id=>Child#child{pid=undefined}}}
+ end.
-%% Chs = [S4, S3, Ch, S1, S0]
-%% Ret: {[S4, S3, Ch], [S1, S0]}
-split_child(Name, Chs) ->
- split_child(Name, Chs, []).
-
-split_child(Name, [Ch|Chs], After) when Ch#child.name =:= Name ->
- {lists:reverse([Ch#child{pid = undefined} | After]), Chs};
-split_child(Pid, [Ch|Chs], After) when Ch#child.pid =:= Pid ->
- {lists:reverse([Ch#child{pid = undefined} | After]), Chs};
-split_child(Name, [Ch|Chs], After) ->
- split_child(Name, Chs, [Ch | After]);
-split_child(_, [], After) ->
- {lists:reverse(After), []}.
-
-get_child(Name, State) ->
- get_child(Name, State, false).
-
-get_child(Pid, State, AllowPid) when AllowPid, is_pid(Pid) ->
- get_dynamic_child(Pid, State);
-get_child(Name, State, _) ->
- lists:keysearch(Name, #child.name, State#state.children).
-
-get_dynamic_child(Pid, #state{children=[Child], dynamics=Dynamics}) ->
- case is_dynamic_pid(Pid, Dynamics) of
- true ->
- {value, Child#child{pid=Pid}};
- false ->
- RPid = restarting(Pid),
- case is_dynamic_pid(RPid, Dynamics) of
- true ->
- {value, Child#child{pid=RPid}};
- false ->
+%% In: {[S4, S3, Ch, S1, S0],Db}
+%% Ret: {{[S4, S3, Ch],Db1}, {[S1, S0],Db2}}
+%% Db1 and Db2 contain the keys in the lists they are associated with.
+-spec split_child(child_id(), children()) -> {children(), children()}.
+split_child(Id, {Ids,Db}) ->
+ {IdsAfter,IdsBefore} = split_ids(Id, Ids, []),
+ DbBefore = maps:with(IdsBefore,Db),
+ #{Id:=Ch} = DbAfter = maps:with(IdsAfter,Db),
+ {{IdsAfter,DbAfter#{Id=>Ch#child{pid=undefined}}},{IdsBefore,DbBefore}}.
+
+split_ids(Id, [Id|Ids], After) ->
+ {lists:reverse([Id|After]), Ids};
+split_ids(Id, [Other|Ids], After) ->
+ split_ids(Id, Ids, [Other | After]).
+
+%% Find the child record for a given Pid (dynamic child) or Id
+%% (non-dynamic child). This is called from the API functions.
+-spec find_child(pid() | child_id(), state()) -> {ok,child_rec()} | error.
+find_child(Pid, State) when is_pid(Pid), ?is_simple(State) ->
+ case find_dynamic_child(Pid, State) of
+ error ->
+ case find_dynamic_child(restarting(Pid), State) of
+ error ->
case erlang:is_process_alive(Pid) of
- true -> false;
- false -> {value, Child}
- end
- end
+ true -> error;
+ false -> {ok, get_dynamic_child(State)}
+ end;
+ Other ->
+ Other
+ end;
+ Other ->
+ Other
+ end;
+find_child(Id, #state{children = {_Ids,Db}}) ->
+ maps:find(Id, Db).
+
+%% Get the child record - either by child id or by pid. If
+%% simple_one_for_one, then insert the pid and args into the returned
+%% child record. This is called when trying to restart the child.
+-spec find_child_and_args(IdOrPid, state()) -> {ok, child_rec()} | error when
+ IdOrPid :: pid() | {restarting,pid()} | child_id().
+find_child_and_args(Pid, State) when ?is_simple(State) ->
+ case find_dynamic_child(Pid, State) of
+ {ok,#child{mfargs={M,F,_}} = Child} ->
+ {ok, Args} = dyn_args(Pid, State),
+ {ok, Child#child{mfargs = {M, F, Args}}};
+ error ->
+ error
+ end;
+find_child_and_args(Pid, State) when is_pid(Pid) ->
+ find_child_by_pid(Pid, State);
+find_child_and_args(Id, #state{children={_Ids,Db}}) ->
+ maps:find(Id, Db).
+
+%% Given the pid, find the child record for a dynamic child, and
+%% include the pid in the returned record.
+-spec find_dynamic_child(IdOrPid, state()) -> {ok, child_rec()} | error when
+ IdOrPid :: pid() | {restarting,pid()} | child_id().
+find_dynamic_child(Pid, State) ->
+ case dyn_exists(Pid, State) of
+ true ->
+ Child = get_dynamic_child(State),
+ {ok, Child#child{pid=Pid}};
+ false ->
+ error
end.
-is_dynamic_pid(Pid, {dict, Dynamics}) ->
- ?DICTS:is_key(Pid, Dynamics);
-is_dynamic_pid(Pid, {set, Dynamics}) ->
- ?SETS:is_element(Pid, Dynamics);
-is_dynamic_pid(_Pid, undefined) ->
- false.
-
-replace_child(Child, State) ->
- Chs = do_replace_child(Child, State#state.children),
- State#state{children = Chs}.
-
-do_replace_child(Child, [Ch|Chs]) when Ch#child.name =:= Child#child.name ->
- [Child | Chs];
-do_replace_child(Child, [Ch|Chs]) ->
- [Ch|do_replace_child(Child, Chs)].
+%% Given the pid, find the child record for a non-dyanamic child.
+-spec find_child_by_pid(IdOrPid, state()) -> {ok,child_rec()} | error when
+ IdOrPid :: pid() | {restarting,pid()}.
+find_child_by_pid(Pid,#state{children={_Ids,Db}}) ->
+ Fun = fun(_Id,#child{pid=P}=Ch,_) when P =:= Pid ->
+ throw(Ch);
+ (_,_,error) ->
+ error
+ end,
+ try maps:fold(Fun,error,Db)
+ catch throw:Child -> {ok,Child}
+ end.
-remove_child(Child, State) ->
- Chs = lists:keydelete(Child#child.name, #child.name, State#state.children),
- State#state{children = Chs}.
+%% Get the child record from a simple_one_for_one supervisor - no pid
+%% It is assumed that the child can always be found
+-spec get_dynamic_child(state()) -> child_rec().
+get_dynamic_child(#state{children={[Id],Db}}) ->
+ #{Id := Child} = Db,
+ Child.
+
+%% Update pid in the given child record and store it in the process state
+-spec set_pid(term(), child_id(), state()) -> state();
+ (term(), child_id(), children()) -> children().
+set_pid(Pid, Id, #state{children=Children} = State) ->
+ State#state{children = set_pid(Pid, Id, Children)};
+set_pid(Pid, Id, {Ids, Db}) ->
+ NewDb = maps:update_with(Id, fun(Child) -> Child#child{pid=Pid} end, Db),
+ {Ids,NewDb}.
+
+%% Remove the Id and the child record from the process state
+-spec remove_child(child_id(), state()) -> state().
+remove_child(Id, #state{children={Ids,Db}} = State) ->
+ NewIds = lists:delete(Id,Ids),
+ NewDb = maps:remove(Id,Db),
+ State#state{children = {NewIds,NewDb}}.
+
+%% In the order of Ids, traverse the children and update each child
+%% according to the return value of the Fun.
+%% On error, abort and return the merge of the old and the updated map.
+%% NOTE: The returned list of Ids is reverted compared to the input.
+-spec children_map(Fun, children()) -> {ok, children()} |
+ {error,children(),Reason} when
+ Fun :: fun((child_id(),child_rec()) -> {update,child_rec()} |
+ remove |
+ {abort, Reason}),
+ Reason :: term().
+children_map(Fun,{Ids,Db}) ->
+ children_map(Fun, Ids, Db, []).
+
+children_map(Fun,[Id|Ids],Db,Acc) ->
+ case Fun(Id,maps:get(Id,Db)) of
+ {update,Child} ->
+ children_map(Fun,Ids,Db#{Id => Child},[Id|Acc]);
+ remove ->
+ children_map(Fun,Ids,maps:remove(Id,Db),Acc);
+ {abort,Reason} ->
+ {error,{lists:reverse(Ids)++[Id|Acc],Db},Reason}
+ end;
+children_map(_Fun,[],Db,Acc) ->
+ {ok,{Acc,Db}}.
+
+%% In the order of Ids, map over all children and return the list
+-spec children_to_list(Fun, children()) -> List when
+ Fun :: fun((child_id(), child_rec()) -> Elem),
+ List :: list(Elem),
+ Elem :: term().
+children_to_list(Fun,{Ids,Db}) ->
+ children_to_list(Fun, Ids, Db, []).
+children_to_list(Fun,[Id|Ids],Db,Acc) ->
+ children_to_list(Fun,Ids,Db,[Fun(Id,maps:get(Id,Db))|Acc]);
+children_to_list(_Fun,[],_Db,Acc) ->
+ lists:reverse(Acc).
+
+%% The order is not important - so ignore Ids
+-spec children_fold(Fun, Acc0, children()) -> Acc1 when
+ Fun :: fun((child_id(), child_rec(), AccIn) -> AccOut),
+ Acc0 :: term(),
+ Acc1 :: term(),
+ AccIn :: term(),
+ AccOut :: term().
+children_fold(Fun,Init,{_Ids,Db}) ->
+ maps:fold(Fun, Init, Db).
+
+-spec append(children(), children()) -> children().
+append({Ids1,Db1},{Ids2,Db2}) ->
+ {Ids1++Ids2,maps:merge(Db1,Db2)}.
%%-----------------------------------------------------------------
%% Func: init_state/4
@@ -1290,27 +1259,27 @@ supname(N, _) -> N.
%%% Returns: {ok, [child_rec()]} | Error
%%% ------------------------------------------------------
-check_startspec(Children) -> check_startspec(Children, []).
+check_startspec(Children) -> check_startspec(Children, [], #{}).
-check_startspec([ChildSpec|T], Res) ->
+check_startspec([ChildSpec|T], Ids, Db) ->
case check_childspec(ChildSpec) of
- {ok, Child} ->
- case lists:keymember(Child#child.name, #child.name, Res) of
+ {ok, #child{id=Id}=Child} ->
+ case maps:is_key(Id, Db) of
%% The error message duplicate_child_name is kept for
%% backwards compatibility, although
%% duplicate_child_id would be more correct.
- true -> {duplicate_child_name, Child#child.name};
- false -> check_startspec(T, [Child | Res])
+ true -> {duplicate_child_name, Id};
+ false -> check_startspec(T, [Id | Ids], Db#{Id=>Child})
end;
Error -> Error
end;
-check_startspec([], Res) ->
- {ok, lists:reverse(Res)}.
+check_startspec([], Ids, Db) ->
+ {ok, {lists:reverse(Ids),Db}}.
check_childspec(ChildSpec) when is_map(ChildSpec) ->
catch do_check_childspec(maps:merge(?default_child_spec,ChildSpec));
-check_childspec({Name, Func, RestartType, Shutdown, ChildType, Mods}) ->
- check_childspec(#{id => Name,
+check_childspec({Id, Func, RestartType, Shutdown, ChildType, Mods}) ->
+ check_childspec(#{id => Id,
start => Func,
restart => RestartType,
shutdown => Shutdown,
@@ -1320,15 +1289,15 @@ check_childspec(X) -> {invalid_child_spec, X}.
do_check_childspec(#{restart := RestartType,
type := ChildType} = ChildSpec)->
- Name = case ChildSpec of
- #{id := N} -> N;
+ Id = case ChildSpec of
+ #{id := I} -> I;
_ -> throw(missing_id)
end,
Func = case ChildSpec of
#{start := F} -> F;
_ -> throw(missing_start)
end,
- validName(Name),
+ validId(Id),
validFunc(Func),
validRestartType(RestartType),
validChildType(ChildType),
@@ -1343,14 +1312,14 @@ do_check_childspec(#{restart := RestartType,
_ -> {M,_,_} = Func, [M]
end,
validMods(Mods),
- {ok, #child{name = Name, mfargs = Func, restart_type = RestartType,
+ {ok, #child{id = Id, mfargs = Func, restart_type = RestartType,
shutdown = Shutdown, child_type = ChildType, modules = Mods}}.
validChildType(supervisor) -> true;
validChildType(worker) -> true;
validChildType(What) -> throw({invalid_child_type, What}).
-validName(_Name) -> true.
+validId(_Id) -> true.
validFunc({M, F, A}) when is_atom(M),
is_atom(F),
@@ -1379,13 +1348,13 @@ validMods(Mods) when is_list(Mods) ->
Mods);
validMods(Mods) -> throw({invalid_modules, Mods}).
-child_to_spec(#child{name = Name,
+child_to_spec(#child{id = Id,
mfargs = Func,
restart_type = RestartType,
shutdown = Shutdown,
child_type = ChildType,
modules = Mods}) ->
- #{id => Name,
+ #{id => Id,
start => Func,
restart => RestartType,
shutdown => Shutdown,
@@ -1431,37 +1400,75 @@ inPeriod(Then, Now, Period) ->
%%% ------------------------------------------------------
%%% Error and progress reporting.
%%% ------------------------------------------------------
-
-report_error(Error, Reason, Child, SupName) ->
- ErrorMsg = [{supervisor, SupName},
- {errorContext, Error},
- {reason, Reason},
- {offender, extract_child(Child)}],
- error_logger:error_report(supervisor_report, ErrorMsg).
-
-
extract_child(Child) when is_list(Child#child.pid) ->
[{nb_children, length(Child#child.pid)},
- {id, Child#child.name},
+ {id, Child#child.id},
{mfargs, Child#child.mfargs},
{restart_type, Child#child.restart_type},
{shutdown, Child#child.shutdown},
{child_type, Child#child.child_type}];
extract_child(Child) ->
[{pid, Child#child.pid},
- {id, Child#child.name},
+ {id, Child#child.id},
{mfargs, Child#child.mfargs},
{restart_type, Child#child.restart_type},
{shutdown, Child#child.shutdown},
{child_type, Child#child.child_type}].
report_progress(Child, SupName) ->
- Progress = [{supervisor, SupName},
- {started, extract_child(Child)}],
- error_logger:info_report(progress, Progress).
+ ?LOG_INFO(#{label=>{supervisor,progress},
+ report=>[{supervisor,SupName},
+ {started,extract_child(Child)}]},
+ #{domain=>[otp,sasl],
+ report_cb=>fun logger:format_otp_report/1,
+ logger_formatter=>#{title=>"PROGRESS REPORT"},
+ error_logger=>#{tag=>info_report,type=>progress}}).
format_status(terminate, [_PDict, State]) ->
State;
format_status(_, [_PDict, State]) ->
[{data, [{"State", State}]},
{supervisor, [{"Callback", State#state.module}]}].
+
+%%%-----------------------------------------------------------------
+%%% Dynamics database access
+dyn_size(#state{dynamics = {Mod,Db}}) ->
+ Mod:size(Db).
+
+dyn_erase(Pid,#state{dynamics={sets,Db}}=State) ->
+ State#state{dynamics={sets,sets:del_element(Pid,Db)}};
+dyn_erase(Pid,#state{dynamics={maps,Db}}=State) ->
+ State#state{dynamics={maps,maps:remove(Pid,Db)}}.
+
+dyn_store(Pid,_,#state{dynamics={sets,Db}}=State) ->
+ State#state{dynamics={sets,sets:add_element(Pid,Db)}};
+dyn_store(Pid,Args,#state{dynamics={maps,Db}}=State) ->
+ State#state{dynamics={maps,Db#{Pid => Args}}}.
+
+dyn_fold(Fun,Init,#state{dynamics={sets,Db}}) ->
+ sets:fold(Fun,Init,Db);
+dyn_fold(Fun,Init,#state{dynamics={maps,Db}}) ->
+ maps:fold(fun(Pid,_,Acc) -> Fun(Pid,Acc) end, Init, Db).
+
+dyn_map(Fun, #state{dynamics={sets,Db}}) ->
+ lists:map(Fun, sets:to_list(Db));
+dyn_map(Fun, #state{dynamics={maps,Db}}) ->
+ lists:map(Fun, maps:keys(Db)).
+
+dyn_exists(Pid, #state{dynamics={sets, Db}}) ->
+ sets:is_element(Pid, Db);
+dyn_exists(Pid, #state{dynamics={maps, Db}}) ->
+ maps:is_key(Pid, Db).
+
+dyn_args(_Pid, #state{dynamics={sets, _Db}}) ->
+ {ok,undefined};
+dyn_args(Pid, #state{dynamics={maps, Db}}) ->
+ maps:find(Pid, Db).
+
+dyn_init(State) ->
+ dyn_init(get_dynamic_child(State),State).
+
+dyn_init(Child,State) when ?is_temporary(Child) ->
+ State#state{dynamics={sets,sets:new()}};
+dyn_init(_Child,State) ->
+ State#state{dynamics={maps,maps:new()}}.
diff --git a/lib/stdlib/src/supervisor_bridge.erl b/lib/stdlib/src/supervisor_bridge.erl
index af1e046d30..21ba6f53af 100644
--- a/lib/stdlib/src/supervisor_bridge.erl
+++ b/lib/stdlib/src/supervisor_bridge.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,6 +21,8 @@
-behaviour(gen_server).
+-include("logger.hrl").
+
%% External exports
-export([start_link/2, start_link/3]).
%% Internal exports
@@ -129,13 +131,22 @@ terminate_pid(Reason, #state{mod = Mod, child_state = ChildState}) ->
Mod:terminate(Reason, ChildState).
report_progress(Pid, Mod, StartArgs, SupName) ->
- Progress = [{supervisor, SupName},
- {started, [{pid, Pid}, {mfa, {Mod, init, [StartArgs]}}]}],
- error_logger:info_report(progress, Progress).
+ ?LOG_INFO(#{label=>{supervisor,progress},
+ report=>[{supervisor, SupName},
+ {started, [{pid, Pid},
+ {mfa, {Mod, init, [StartArgs]}}]}]},
+ #{domain=>[otp,sasl],
+ report_cb=>fun logger:format_otp_report/1,
+ logger_formatter=>#{title=>"PROGRESS REPORT"},
+ error_logger=>#{tag=>info_report,type=>progress}}).
report_error(Error, Reason, #state{name = Name, pid = Pid, mod = Mod}) ->
- ErrorMsg = [{supervisor, Name},
- {errorContext, Error},
- {reason, Reason},
- {offender, [{pid, Pid}, {mod, Mod}]}],
- error_logger:error_report(supervisor_report, ErrorMsg).
+ ?LOG_ERROR(#{label=>{supervisor,error},
+ report=>[{supervisor, Name},
+ {errorContext, Error},
+ {reason, Reason},
+ {offender, [{pid, Pid}, {mod, Mod}]}]},
+ #{domain=>[otp,sasl],
+ report_cb=>fun logger:format_otp_report/1,
+ logger_formatter=>#{title=>"SUPERVISOR REPORT"},
+ error_logger=>#{tag=>error_report,type=>supervisor_report}}).
diff --git a/lib/stdlib/src/sys.erl b/lib/stdlib/src/sys.erl
index 0c578acf21..6ff9aa33b4 100644
--- a/lib/stdlib/src/sys.erl
+++ b/lib/stdlib/src/sys.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -30,21 +30,30 @@
log_to_file/2, log_to_file/3, no_debug/1, no_debug/2,
install/2, install/3, remove/2, remove/3]).
-export([handle_system_msg/6, handle_system_msg/7, handle_debug/4,
- print_log/1, get_debug/3, debug_options/1, suspend_loop_hib/6]).
+ print_log/1, get_log/1, get_debug/3, debug_options/1, suspend_loop_hib/6]).
+-deprecated([{get_debug,3,eventually}]).
%%-----------------------------------------------------------------
%% Types
%%-----------------------------------------------------------------
--export_type([dbg_opt/0]).
+-export_type([dbg_opt/0, dbg_fun/0, debug_option/0]).
-type name() :: pid() | atom()
| {'global', term()}
| {'via', module(), term()}.
-type system_event() :: {'in', Msg :: _}
- | {'in', Msg :: _, From :: _}
+ | {'in', Msg :: _, State :: _}
| {'out', Msg :: _, To :: _}
- | term().
+ | {'out', Msg :: _, To :: _, State :: _}
+ | {'noreply', State :: _}
+ | {'continue', Continuation :: _}
+ | {'code_change', Event :: _, State :: _}
+ | {'postpone', Event :: _, State :: _, NextState :: _}
+ | {'consume', Event :: _, State :: _, NextState :: _}
+ | {'enter', State :: _}
+ | {'terminate', Reason :: _, State :: _}
+ | term().
-opaque dbg_opt() :: {'trace', 'true'}
| {'log',
{N :: non_neg_integer(),
@@ -56,7 +65,8 @@
MessagesIn :: non_neg_integer(),
MessagesOut :: non_neg_integer()}}
| {'log_to_file', file:io_device()}
- | {Func :: dbg_fun(), FuncState :: term()}.
+ | {Func :: dbg_fun(), FuncState :: term()}
+ | {FuncId :: term(), Func :: dbg_fun(), FuncState :: term()}.
-type dbg_fun() :: fun((FuncState :: _,
Event :: system_event(),
ProcState :: _) -> 'done' | (NewFuncState :: _)).
@@ -65,6 +75,16 @@
Event :: system_event(),
Extra :: term()) -> any()).
+-type debug_option() ::
+ 'trace'
+ | 'log'
+ | {'log', N :: pos_integer()}
+ | 'statistics'
+ | {'log_to_file', FileName :: file:name()}
+ | {'install',
+ {Func :: dbg_fun(), FuncState :: term()}
+ | {FuncId :: term(), Func :: dbg_fun(), FuncState :: term()}}.
+
%%-----------------------------------------------------------------
%% System messages
%%-----------------------------------------------------------------
@@ -267,33 +287,41 @@ no_debug(Name, Timeout) -> send_system_msg(Name, {debug, no_debug}, Timeout).
-spec install(Name, FuncSpec) -> 'ok' when
Name :: name(),
- FuncSpec :: {Func, FuncState},
+ FuncSpec :: {Func, FuncState} | {FuncId, Func, FuncState},
+ FuncId :: term(),
Func :: dbg_fun(),
FuncState :: term().
install(Name, {Func, FuncState}) ->
- send_system_msg(Name, {debug, {install, {Func, FuncState}}}).
+ send_system_msg(Name, {debug, {install, {Func, FuncState}}});
+install(Name, {FuncId, Func, FuncState}) ->
+ send_system_msg(Name, {debug, {install, {FuncId, Func, FuncState}}}).
-spec install(Name, FuncSpec, Timeout) -> 'ok' when
Name :: name(),
- FuncSpec :: {Func, FuncState},
+ FuncSpec :: {Func, FuncState} | {FuncId, Func, FuncState},
+ FuncId :: term(),
Func :: dbg_fun(),
FuncState :: term(),
Timeout :: timeout().
install(Name, {Func, FuncState}, Timeout) ->
- send_system_msg(Name, {debug, {install, {Func, FuncState}}}, Timeout).
+ send_system_msg(Name, {debug, {install, {Func, FuncState}}}, Timeout);
+install(Name, {FuncId, Func, FuncState}, Timeout) ->
+ send_system_msg(Name, {debug, {install, {FuncId, Func, FuncState}}}, Timeout).
--spec remove(Name, Func) -> 'ok' when
+-spec remove(Name, Func | FuncId) -> 'ok' when
Name :: name(),
- Func :: dbg_fun().
-remove(Name, Func) ->
- send_system_msg(Name, {debug, {remove, Func}}).
+ Func :: dbg_fun(),
+ FuncId :: term().
+remove(Name, FuncOrFuncId) ->
+ send_system_msg(Name, {debug, {remove, FuncOrFuncId}}).
--spec remove(Name, Func, Timeout) -> 'ok' when
+-spec remove(Name, Func | FuncId, Timeout) -> 'ok' when
Name :: name(),
Func :: dbg_fun(),
+ FuncId :: term(),
Timeout :: timeout().
-remove(Name, Func, Timeout) ->
- send_system_msg(Name, {debug, {remove, Func}}, Timeout).
+remove(Name, FuncOrFuncId, Timeout) ->
+ send_system_msg(Name, {debug, {remove, FuncOrFuncId}}, Timeout).
%%-----------------------------------------------------------------
%% All system messages sent are on the form {system, From, Msg}
@@ -375,24 +403,41 @@ handle_system_msg(SysState, Msg, From, Parent, Mod, Debug, Misc, Hib) ->
FormFunc :: format_fun(),
Extra :: term(),
Event :: system_event().
-handle_debug([{trace, true} | T], FormFunc, State, Event) ->
+handle_debug([{trace, true} = DbgOpt | T], FormFunc, State, Event) ->
print_event({Event, State, FormFunc}),
- [{trace, true} | handle_debug(T, FormFunc, State, Event)];
-handle_debug([{log, {N, LogData}} | T], FormFunc, State, Event) ->
- NLogData = [{Event, State, FormFunc} | trim(N, LogData)],
- [{log, {N, NLogData}} | handle_debug(T, FormFunc, State, Event)];
-handle_debug([{log_to_file, Fd} | T], FormFunc, State, Event) ->
+ [DbgOpt | handle_debug(T, FormFunc, State, Event)];
+handle_debug([{log, NLog} | T], FormFunc, State, Event) ->
+ Item = {Event, State, FormFunc},
+ [{log, nlog_put(Item, NLog)} | handle_debug(T, FormFunc, State, Event)];
+handle_debug([{log_to_file, Fd} = DbgOpt | T], FormFunc, State, Event) ->
print_event(Fd, {Event, State, FormFunc}),
- [{log_to_file, Fd} | handle_debug(T, FormFunc, State, Event)];
+ [DbgOpt | handle_debug(T, FormFunc, State, Event)];
handle_debug([{statistics, StatData} | T], FormFunc, State, Event) ->
NStatData = stat(Event, StatData),
[{statistics, NStatData} | handle_debug(T, FormFunc, State, Event)];
+handle_debug([{FuncId, {Func, FuncState}} | T], FormFunc, State, Event) ->
+ try Func(FuncState, Event, State) of
+ done -> handle_debug(T, FormFunc, State, Event);
+ NFuncState ->
+ [{FuncId, {Func, NFuncState}} |
+ handle_debug(T, FormFunc, State, Event)]
+ catch
+ done -> handle_debug(T, FormFunc, State, Event);
+ NFuncState ->
+ [{FuncId, {Func, NFuncState}} |
+ handle_debug(T, FormFunc, State, Event)];
+ _:_ -> handle_debug(T, FormFunc, State, Event)
+ end;
handle_debug([{Func, FuncState} | T], FormFunc, State, Event) ->
- case catch Func(FuncState, Event, State) of
+ try Func(FuncState, Event, State) of
done -> handle_debug(T, FormFunc, State, Event);
- {'EXIT', _} -> handle_debug(T, FormFunc, State, Event);
- NFuncState ->
+ NFuncState ->
[{Func, NFuncState} | handle_debug(T, FormFunc, State, Event)]
+ catch
+ done -> handle_debug(T, FormFunc, State, Event);
+ NFuncState ->
+ [{Func, NFuncState} | handle_debug(T, FormFunc, State, Event)];
+ _:_ -> handle_debug(T, FormFunc, State, Event)
end;
handle_debug([], _FormFunc, _State, _Event) ->
[].
@@ -509,19 +554,19 @@ debug_cmd({trace, true}, Debug) ->
debug_cmd({trace, false}, Debug) ->
{ok, remove_debug(trace, Debug)};
debug_cmd({log, true}, Debug) ->
- {_N, Logs} = get_debug(log, Debug, {0, []}),
- {ok, install_debug(log, {10, trim(10, Logs)}, Debug)};
-debug_cmd({log, {true, N}}, Debug) when is_integer(N), N > 0 ->
- {_N, Logs} = get_debug(log, Debug, {0, []}),
- {ok, install_debug(log, {N, trim(N, Logs)}, Debug)};
+ NLog = get_debug(log, Debug, nlog_new()),
+ {ok, install_debug(log, nlog_new(NLog), Debug)};
+debug_cmd({log, {true, N}}, Debug) when is_integer(N), 1 =< N ->
+ NLog = get_debug(log, Debug, nlog_new(N)),
+ {ok, install_debug(log, nlog_new(N, NLog), Debug)};
debug_cmd({log, false}, Debug) ->
{ok, remove_debug(log, Debug)};
debug_cmd({log, print}, Debug) ->
print_log(Debug),
{ok, Debug};
debug_cmd({log, get}, Debug) ->
- {_N, Logs} = get_debug(log, Debug, {0, []}),
- {{ok, lists:reverse(Logs)}, Debug};
+ NLog = get_debug(log, Debug, nlog_new()),
+ {{ok, [Event || {Event, _State, _FormFunc} <- nlog_get(NLog)]}, Debug};
debug_cmd({log_to_file, false}, Debug) ->
NDebug = close_log_file(Debug),
{ok, NDebug};
@@ -544,8 +589,10 @@ debug_cmd(no_debug, Debug) ->
{ok, []};
debug_cmd({install, {Func, FuncState}}, Debug) ->
{ok, install_debug(Func, FuncState, Debug)};
-debug_cmd({remove, Func}, Debug) ->
- {ok, remove_debug(Func, Debug)};
+debug_cmd({install, {FuncId, Func, FuncState}}, Debug) ->
+ {ok, install_debug(FuncId, {Func, FuncState}, Debug)};
+debug_cmd({remove, FuncOrFuncId}, Debug) ->
+ {ok, remove_debug(FuncOrFuncId, Debug)};
debug_cmd(_Unknown, Debug) ->
{unknown_debug, Debug}.
@@ -573,18 +620,16 @@ get_stat(_) ->
stat({in, _Msg}, {Time, Reds, In, Out}) -> {Time, Reds, In+1, Out};
stat({in, _Msg, _From}, {Time, Reds, In, Out}) -> {Time, Reds, In+1, Out};
stat({out, _Msg, _To}, {Time, Reds, In, Out}) -> {Time, Reds, In, Out+1};
+stat({out, _Msg, _To, _State}, {Time, Reds, In, Out}) -> {Time, Reds, In, Out+1};
stat(_, StatData) -> StatData.
-trim(N, LogData) ->
- lists:sublist(LogData, 1, N-1).
-
%%-----------------------------------------------------------------
%% Debug structure manipulating functions
%%-----------------------------------------------------------------
install_debug(Item, Data, Debug) ->
- case get_debug2(Item, Debug, undefined) of
- undefined -> [{Item, Data} | Debug];
- _ -> Debug
+ case lists:keysearch(Item, 1, Debug) of
+ false -> [{Item, Data} | Debug];
+ _ -> Debug
end.
remove_debug(Item, Debug) -> lists:keydelete(Item, 1, Debug).
@@ -605,9 +650,14 @@ get_debug2(Item, Debug, Default) ->
-spec print_log(Debug) -> 'ok' when
Debug :: [dbg_opt()].
print_log(Debug) ->
- {_N, Logs} = get_debug(log, Debug, {0, []}),
- lists:foreach(fun print_event/1,
- lists:reverse(Logs)).
+ NLog = get_debug(log, Debug, nlog_new()),
+ lists:foreach(fun print_event/1, nlog_get(NLog)).
+
+-spec get_log(Debug) -> [system_event()] when
+ Debug :: [dbg_opt()].
+get_log(Debug) ->
+ NLog = get_debug(log, Debug, nlog_new()),
+ [Event || {Event, _State, _FormFunc} <- nlog_get(NLog)].
close_log_file(Debug) ->
case get_debug2(log_to_file, Debug, []) of
@@ -619,6 +669,74 @@ close_log_file(Debug) ->
end.
%%-----------------------------------------------------------------
+%% Keep the last N Log functions
+%%-----------------------------------------------------------------
+%%
+%% Streamlined Okasaki queue as base for "keep the last N" log.
+%%
+%% To the reverse list head we cons new items.
+%% The forward list contains elements in insertion order,
+%% so the head is the oldest and the one to drop off
+%% when the log is full.
+%%
+%% Here is how we can get away with only using one cons cell
+%% to wrap the forward and reverse list, and the log size:
+%%
+%% A full log does not need a counter; we just cons one
+%% and drop one:
+%%
+%% [ReverseList|ForwardList]
+%%
+%% A non-full log is filling up to N elements;
+%% use a down counter instead of a list as first element:
+%%
+%% [RemainingToFullCount|ReverseList]
+
+nlog_new() ->
+ nlog_new(10).
+%%
+nlog_new([_|_] = NLog) ->
+ nlog_new(10, NLog);
+nlog_new(N) ->
+ [N]. % Empty log size N >= 1
+%%
+nlog_new(N, NLog) ->
+ lists:foldl(
+ fun (Item, NL) -> nlog_put(Item, NL) end,
+ nlog_new(N),
+ nlog_get(NLog)).
+
+%%
+nlog_put(Item, NLog) ->
+ case NLog of
+ [R|FF] when is_list(R) ->
+ %% Full log
+ case FF of
+ [_|F] ->
+ %% Cons to reverse list, drop from forward list
+ [[Item|R]|F];
+ [] ->
+ %% Create new forward list from reverse list,
+ %% create new empty reverse list
+ [_|F] = lists:reverse(R, [Item]),
+ [[]|F]
+ end;
+ [1|R] ->
+ %% Log now gets full
+ [[Item|R]];
+ [J|R] ->
+ %% Filling up to N elements
+ [J - 1,Item|R]
+ end.
+
+nlog_get([[]|F]) ->
+ F;
+nlog_get([[_|_] = R|F]) ->
+ F ++ lists:reverse(R);
+nlog_get([_J|R]) ->
+ lists:reverse(R).
+
+%%-----------------------------------------------------------------
%% Func: debug_options/1
%% Purpose: Initiate a debug structure. Called by a process that
%% wishes to initiate the debug structure without the
@@ -626,27 +744,16 @@ close_log_file(Debug) ->
%% Returns: [debug_opts()]
%%-----------------------------------------------------------------
--spec debug_options(Options) -> [dbg_opt()] when
- Options :: [Opt],
- Opt :: 'trace'
- | 'log'
- | {'log', pos_integer()}
- | 'statistics'
- | {'log_to_file', FileName}
- | {'install', FuncSpec},
- FileName :: file:name(),
- FuncSpec :: {Func, FuncState},
- Func :: dbg_fun(),
- FuncState :: term().
+-spec debug_options([Opt :: debug_option()]) -> [dbg_opt()].
debug_options(Options) ->
debug_options(Options, []).
debug_options([trace | T], Debug) ->
debug_options(T, install_debug(trace, true, Debug));
debug_options([log | T], Debug) ->
- debug_options(T, install_debug(log, {10, []}, Debug));
+ debug_options(T, install_debug(log, nlog_new(), Debug));
debug_options([{log, N} | T], Debug) when is_integer(N), N > 0 ->
- debug_options(T, install_debug(log, {N, []}, Debug));
+ debug_options(T, install_debug(log, nlog_new(N), Debug));
debug_options([statistics | T], Debug) ->
debug_options(T, install_debug(statistics, init_stat(), Debug));
debug_options([{log_to_file, FileName} | T], Debug) ->
@@ -658,6 +765,8 @@ debug_options([{log_to_file, FileName} | T], Debug) ->
end;
debug_options([{install, {Func, FuncState}} | T], Debug) ->
debug_options(T, install_debug(Func, FuncState, Debug));
+debug_options([{install, {FuncId, Func, FuncState}} | T], Debug) ->
+ debug_options(T, install_debug(FuncId, {Func, FuncState}, Debug));
debug_options([_ | T], Debug) ->
debug_options(T, Debug);
debug_options([], Debug) ->
diff --git a/lib/stdlib/src/uri_string.erl b/lib/stdlib/src/uri_string.erl
new file mode 100644
index 0000000000..d33dc89af8
--- /dev/null
+++ b/lib/stdlib/src/uri_string.erl
@@ -0,0 +1,2153 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+%% [RFC 3986, Chapter 2.2. Reserved Characters]
+%%
+%% reserved = gen-delims / sub-delims
+%%
+%% gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
+%%
+%% sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
+%% / "*" / "+" / "," / ";" / "="
+%%
+%%
+%% [RFC 3986, Chapter 2.3. Unreserved Characters]
+%%
+%% unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+%%
+%%
+%% [RFC 3986, Chapter 3. Syntax Components]
+%%
+%% The generic URI syntax consists of a hierarchical sequence of
+%% components referred to as the scheme, authority, path, query, and
+%% fragment.
+%%
+%% URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
+%%
+%% hier-part = "//" authority path-abempty
+%% / path-absolute
+%% / path-rootless
+%% / path-empty
+%%
+%% The scheme and path components are required, though the path may be
+%% empty (no characters). When authority is present, the path must
+%% either be empty or begin with a slash ("/") character. When
+%% authority is not present, the path cannot begin with two slash
+%% characters ("//"). These restrictions result in five different ABNF
+%% rules for a path (Section 3.3), only one of which will match any
+%% given URI reference.
+%%
+%% The following are two example URIs and their component parts:
+%%
+%% foo://example.com:8042/over/there?name=ferret#nose
+%% \_/ \______________/\_________/ \_________/ \__/
+%% | | | | |
+%% scheme authority path query fragment
+%% | _____________________|__
+%% / \ / \
+%% urn:example:animal:ferret:nose
+%%
+%%
+%% [RFC 3986, Chapter 3.1. Scheme]
+%%
+%% Each URI begins with a scheme name that refers to a specification for
+%% assigning identifiers within that scheme.
+%%
+%% scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+%%
+%%
+%% [RFC 3986, Chapter 3.2. Authority]
+%%
+%% Many URI schemes include a hierarchical element for a naming
+%% authority so that governance of the name space defined by the
+%% remainder of the URI is delegated to that authority (which may, in
+%% turn, delegate it further).
+%%
+%% authority = [ userinfo "@" ] host [ ":" port ]
+%%
+%%
+%% [RFC 3986, Chapter 3.2.1. User Information]
+%%
+%% The userinfo subcomponent may consist of a user name and, optionally,
+%% scheme-specific information about how to gain authorization to access
+%% the resource. The user information, if present, is followed by a
+%% commercial at-sign ("@") that delimits it from the host.
+%%
+%% userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
+%%
+%%
+%% [RFC 3986, Chapter 3.2.2. Host]
+%%
+%% The host subcomponent of authority is identified by an IP literal
+%% encapsulated within square brackets, an IPv4 address in dotted-
+%% decimal form, or a registered name.
+%%
+%% host = IP-literal / IPv4address / reg-name
+%%
+%% IP-literal = "[" ( IPv6address / IPvFuture ) "]"
+%%
+%% IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
+%%
+%% IPv6address = 6( h16 ":" ) ls32
+%% / "::" 5( h16 ":" ) ls32
+%% / [ h16 ] "::" 4( h16 ":" ) ls32
+%% / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
+%% / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
+%% / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
+%% / [ *4( h16 ":" ) h16 ] "::" ls32
+%% / [ *5( h16 ":" ) h16 ] "::" h16
+%% / [ *6( h16 ":" ) h16 ] "::"
+%%
+%% ls32 = ( h16 ":" h16 ) / IPv4address
+%% ; least-significant 32 bits of address
+%%
+%% h16 = 1*4HEXDIG
+%% ; 16 bits of address represented in hexadecimal
+%%
+%% IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
+%%
+%% dec-octet = DIGIT ; 0-9
+%% / %x31-39 DIGIT ; 10-99
+%% / "1" 2DIGIT ; 100-199
+%% / "2" %x30-34 DIGIT ; 200-249
+%% / "25" %x30-35 ; 250-255
+%%
+%% reg-name = *( unreserved / pct-encoded / sub-delims )
+%%
+%%
+%% [RFC 3986, Chapter 3.2.2. Port]
+%%
+%% The port subcomponent of authority is designated by an optional port
+%% number in decimal following the host and delimited from it by a
+%% single colon (":") character.
+%%
+%% port = *DIGIT
+%%
+%%
+%% [RFC 3986, Chapter 3.3. Path]
+%%
+%% The path component contains data, usually organized in hierarchical
+%% form, that, along with data in the non-hierarchical query component
+%% (Section 3.4), serves to identify a resource within the scope of the
+%% URI's scheme and naming authority (if any). The path is terminated
+%% by the first question mark ("?") or number sign ("#") character, or
+%% by the end of the URI.
+%%
+%% path = path-abempty ; begins with "/" or is empty
+%% / path-absolute ; begins with "/" but not "//"
+%% / path-noscheme ; begins with a non-colon segment
+%% / path-rootless ; begins with a segment
+%% / path-empty ; zero characters
+%%
+%% path-abempty = *( "/" segment )
+%% path-absolute = "/" [ segment-nz *( "/" segment ) ]
+%% path-noscheme = segment-nz-nc *( "/" segment )
+%% path-rootless = segment-nz *( "/" segment )
+%% path-empty = 0<pchar>
+%% segment = *pchar
+%% segment-nz = 1*pchar
+%% segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
+%% ; non-zero-length segment without any colon ":"
+%%
+%% pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+%%
+%%
+%% [RFC 3986, Chapter 3.4. Query]
+%%
+%% The query component contains non-hierarchical data that, along with
+%% data in the path component (Section 3.3), serves to identify a
+%% resource within the scope of the URI's scheme and naming authority
+%% (if any). The query component is indicated by the first question
+%% mark ("?") character and terminated by a number sign ("#") character
+%% or by the end of the URI.
+%%
+%% query = *( pchar / "/" / "?" )
+%%
+%%
+%% [RFC 3986, Chapter 3.5. Fragment]
+%%
+%% The fragment identifier component of a URI allows indirect
+%% identification of a secondary resource by reference to a primary
+%% resource and additional identifying information.
+%%
+%% fragment = *( pchar / "/" / "?" )
+%%
+%%
+%% [RFC 3986, Chapter 4.1. URI Reference]
+%%
+%% URI-reference is used to denote the most common usage of a resource
+%% identifier.
+%%
+%% URI-reference = URI / relative-ref
+%%
+%%
+%% [RFC 3986, Chapter 4.2. Relative Reference]
+%%
+%% A relative reference takes advantage of the hierarchical syntax
+%% (Section 1.2.3) to express a URI reference relative to the name space
+%% of another hierarchical URI.
+%%
+%% relative-ref = relative-part [ "?" query ] [ "#" fragment ]
+%%
+%% relative-part = "//" authority path-abempty
+%% / path-absolute
+%% / path-noscheme
+%% / path-empty
+%%
+%%
+%% [RFC 3986, Chapter 4.3. Absolute URI]
+%%
+%% Some protocol elements allow only the absolute form of a URI without
+%% a fragment identifier. For example, defining a base URI for later
+%% use by relative references calls for an absolute-URI syntax rule that
+%% does not allow a fragment.
+%%
+%% absolute-URI = scheme ":" hier-part [ "?" query ]
+%%
+-module(uri_string).
+
+%%-------------------------------------------------------------------------
+%% External API
+%%-------------------------------------------------------------------------
+-export([compose_query/1, compose_query/2,
+ dissect_query/1, normalize/1, normalize/2, parse/1,
+ recompose/1, transcode/2]).
+-export_type([error/0, uri_map/0, uri_string/0]).
+
+
+%%-------------------------------------------------------------------------
+%% Internal API
+%%-------------------------------------------------------------------------
+-export([is_host/1, is_path/1]). % suppress warnings
+
+
+%%-------------------------------------------------------------------------
+%% Macros
+%%-------------------------------------------------------------------------
+-define(CHAR(Char), <<Char/utf8>>).
+-define(STRING_EMPTY, <<>>).
+-define(STRING(MatchStr), <<MatchStr/binary>>).
+-define(STRING_REST(MatchStr, Rest), <<MatchStr/utf8, Rest/binary>>).
+
+-define(DEC2HEX(X),
+ if ((X) >= 0) andalso ((X) =< 9) -> (X) + $0;
+ ((X) >= 10) andalso ((X) =< 15) -> (X) + $A - 10
+ end).
+
+-define(HEX2DEC(X),
+ if ((X) >= $0) andalso ((X) =< $9) -> (X) - $0;
+ ((X) >= $A) andalso ((X) =< $F) -> (X) - $A + 10;
+ ((X) >= $a) andalso ((X) =< $f) -> (X) - $a + 10
+ end).
+
+
+%%%=========================================================================
+%%% API
+%%%=========================================================================
+
+%%-------------------------------------------------------------------------
+%% URI compliant with RFC 3986
+%% ASCII %x21 - %x7A ("!" - "z") except
+%% %x34 " double quote
+%% %x60 < less than
+%% %x62 > greater than
+%% %x92 \ backslash
+%% %x94 ^ caret / circumflex
+%% %x96 ` grave / accent
+%%-------------------------------------------------------------------------
+-type uri_string() :: iodata().
+-type error() :: {error, atom(), term()}.
+
+
+%%-------------------------------------------------------------------------
+%% RFC 3986, Chapter 3. Syntax Components
+%%-------------------------------------------------------------------------
+-type uri_map() ::
+ #{fragment => unicode:chardata(),
+ host => unicode:chardata(),
+ path => unicode:chardata(),
+ port => non_neg_integer() | undefined,
+ query => unicode:chardata(),
+ scheme => unicode:chardata(),
+ userinfo => unicode:chardata()} | #{}.
+
+
+%%-------------------------------------------------------------------------
+%% Normalize URIs
+%%-------------------------------------------------------------------------
+-spec normalize(URI) -> NormalizedURI when
+ URI :: uri_string() | uri_map(),
+ NormalizedURI :: uri_string()
+ | error().
+normalize(URIMap) ->
+ try normalize(URIMap, [])
+ catch
+ throw:{error, Atom, RestData} -> {error, Atom, RestData}
+ end.
+
+
+-spec normalize(URI, Options) -> NormalizedURI when
+ URI :: uri_string() | uri_map(),
+ Options :: [return_map],
+ NormalizedURI :: uri_string() | uri_map().
+normalize(URIMap, []) when is_map(URIMap) ->
+ recompose(normalize_map(URIMap));
+normalize(URIMap, [return_map]) when is_map(URIMap) ->
+ normalize_map(URIMap);
+normalize(URIString, []) ->
+ case parse(URIString) of
+ Value when is_map(Value) ->
+ recompose(normalize_map(Value));
+ Error ->
+ Error
+ end;
+normalize(URIString, [return_map]) ->
+ case parse(URIString) of
+ Value when is_map(Value) ->
+ normalize_map(Value);
+ Error ->
+ Error
+ end.
+
+
+%%-------------------------------------------------------------------------
+%% Parse URIs
+%%-------------------------------------------------------------------------
+-spec parse(URIString) -> URIMap when
+ URIString :: uri_string(),
+ URIMap :: uri_map()
+ | error().
+parse(URIString) when is_binary(URIString) ->
+ try parse_uri_reference(URIString, #{})
+ catch
+ throw:{error, Atom, RestData} -> {error, Atom, RestData}
+ end;
+parse(URIString) when is_list(URIString) ->
+ try
+ Binary = unicode:characters_to_binary(URIString),
+ Map = parse_uri_reference(Binary, #{}),
+ convert_mapfields_to_list(Map)
+ catch
+ throw:{error, Atom, RestData} -> {error, Atom, RestData}
+ end.
+
+
+%%-------------------------------------------------------------------------
+%% Recompose URIs
+%%-------------------------------------------------------------------------
+-spec recompose(URIMap) -> URIString when
+ URIMap :: uri_map(),
+ URIString :: uri_string()
+ | error().
+recompose(Map) ->
+ case is_valid_map(Map) of
+ false ->
+ {error, invalid_map, Map};
+ true ->
+ try
+ T0 = update_scheme(Map, empty),
+ T1 = update_userinfo(Map, T0),
+ T2 = update_host(Map, T1),
+ T3 = update_port(Map, T2),
+ T4 = update_path(Map, T3),
+ T5 = update_query(Map, T4),
+ update_fragment(Map, T5)
+ catch
+ throw:{error, Atom, RestData} -> {error, Atom, RestData}
+ end
+ end.
+
+
+%%-------------------------------------------------------------------------
+%% Transcode URIs
+%%-------------------------------------------------------------------------
+-spec transcode(URIString, Options) -> Result when
+ URIString :: uri_string(),
+ Options :: [{in_encoding, unicode:encoding()}|{out_encoding, unicode:encoding()}],
+ Result :: uri_string()
+ | error().
+transcode(URIString, Options) when is_binary(URIString) ->
+ try
+ InEnc = proplists:get_value(in_encoding, Options, utf8),
+ OutEnc = proplists:get_value(out_encoding, Options, utf8),
+ List = convert_to_list(URIString, InEnc),
+ Output = transcode(List, [], InEnc, OutEnc),
+ convert_to_binary(Output, utf8, OutEnc)
+ catch
+ throw:{error, Atom, RestData} -> {error, Atom, RestData}
+ end;
+transcode(URIString, Options) when is_list(URIString) ->
+ InEnc = proplists:get_value(in_encoding, Options, utf8),
+ OutEnc = proplists:get_value(out_encoding, Options, utf8),
+ Flattened = flatten_list(URIString, InEnc),
+ try transcode(Flattened, [], InEnc, OutEnc)
+ catch
+ throw:{error, Atom, RestData} -> {error, Atom, RestData}
+ end.
+
+
+%%-------------------------------------------------------------------------
+%% Functions for working with the query part of a URI as a list
+%% of key/value pairs.
+%% HTML 5.2 - 4.10.21.6 URL-encoded form data - WHATWG URL (10 Jan 2018) - UTF-8
+%% HTML 5.0 - 4.10.22.6 URL-encoded form data - non UTF-8
+%%-------------------------------------------------------------------------
+
+%%-------------------------------------------------------------------------
+%% Compose urlencoded query string from a list of unescaped key/value pairs.
+%% (application/x-www-form-urlencoded encoding algorithm)
+%%-------------------------------------------------------------------------
+-spec compose_query(QueryList) -> QueryString when
+ QueryList :: [{unicode:chardata(), unicode:chardata() | true}],
+ QueryString :: uri_string()
+ | error().
+compose_query(List) ->
+ compose_query(List, [{encoding, utf8}]).
+
+
+-spec compose_query(QueryList, Options) -> QueryString when
+ QueryList :: [{unicode:chardata(), unicode:chardata() | true}],
+ Options :: [{encoding, atom()}],
+ QueryString :: uri_string()
+ | error().
+compose_query([],_Options) ->
+ [];
+compose_query(List, Options) ->
+ try compose_query(List, Options, false, <<>>)
+ catch
+ throw:{error, Atom, RestData} -> {error, Atom, RestData}
+ end.
+%%
+compose_query([{Key,true}|Rest], Options, IsList, Acc) ->
+ Separator = get_separator(Rest),
+ K = form_urlencode(Key, Options),
+ IsListNew = IsList orelse is_list(Key),
+ compose_query(Rest, Options, IsListNew, <<Acc/binary,K/binary,Separator/binary>>);
+compose_query([{Key,Value}|Rest], Options, IsList, Acc) ->
+ Separator = get_separator(Rest),
+ K = form_urlencode(Key, Options),
+ V = form_urlencode(Value, Options),
+ IsListNew = IsList orelse is_list(Key) orelse is_list(Value),
+ compose_query(Rest, Options, IsListNew, <<Acc/binary,K/binary,"=",V/binary,Separator/binary>>);
+compose_query([], _Options, IsList, Acc) ->
+ case IsList of
+ true -> convert_to_list(Acc, utf8);
+ false -> Acc
+ end.
+
+
+%%-------------------------------------------------------------------------
+%% Dissect a query string into a list of unescaped key/value pairs.
+%% (application/x-www-form-urlencoded decoding algorithm)
+%%-------------------------------------------------------------------------
+-spec dissect_query(QueryString) -> QueryList when
+ QueryString :: uri_string(),
+ QueryList :: [{unicode:chardata(), unicode:chardata() | true}]
+ | error().
+dissect_query(<<>>) ->
+ [];
+dissect_query([]) ->
+ [];
+dissect_query(QueryString) when is_list(QueryString) ->
+ try
+ B = convert_to_binary(QueryString, utf8, utf8),
+ dissect_query_key(B, true, [], <<>>, <<>>)
+ catch
+ throw:{error, Atom, RestData} -> {error, Atom, RestData}
+ end;
+dissect_query(QueryString) ->
+ try dissect_query_key(QueryString, false, [], <<>>, <<>>)
+ catch
+ throw:{error, Atom, RestData} -> {error, Atom, RestData}
+ end.
+
+
+%%%========================================================================
+%%% Internal functions
+%%%========================================================================
+
+%%-------------------------------------------------------------------------
+%% Converts Map fields to lists
+%%-------------------------------------------------------------------------
+convert_mapfields_to_list(Map) ->
+ Fun = fun (_, V) when is_binary(V) -> unicode:characters_to_list(V);
+ (_, V) -> V end,
+ maps:map(Fun, Map).
+
+
+%%-------------------------------------------------------------------------
+%% [RFC 3986, Chapter 4.1. URI Reference]
+%%
+%% URI-reference is used to denote the most common usage of a resource
+%% identifier.
+%%
+%% URI-reference = URI / relative-ref
+%%-------------------------------------------------------------------------
+-spec parse_uri_reference(binary(), uri_map()) -> uri_map().
+parse_uri_reference(<<>>, _) -> #{path => <<>>};
+parse_uri_reference(URIString, URI) ->
+ try parse_scheme_start(URIString, URI)
+ catch
+ throw:{_,_,_} ->
+ parse_relative_part(URIString, URI)
+ end.
+
+
+%%-------------------------------------------------------------------------
+%% [RFC 3986, Chapter 4.2. Relative Reference]
+%%
+%% A relative reference takes advantage of the hierarchical syntax
+%% (Section 1.2.3) to express a URI reference relative to the name space
+%% of another hierarchical URI.
+%%
+%% relative-ref = relative-part [ "?" query ] [ "#" fragment ]
+%%
+%% relative-part = "//" authority path-abempty
+%% / path-absolute
+%% / path-noscheme
+%% / path-empty
+%%-------------------------------------------------------------------------
+-spec parse_relative_part(binary(), uri_map()) -> uri_map().
+parse_relative_part(?STRING_REST("//", Rest), URI) ->
+ %% Parse userinfo - "//" is NOT part of authority
+ try parse_userinfo(Rest, URI) of
+ {T, URI1} ->
+ Userinfo = calculate_parsed_userinfo(Rest, T),
+ URI2 = maybe_add_path(URI1),
+ URI2#{userinfo => Userinfo}
+ catch
+ throw:{_,_,_} ->
+ {T, URI1} = parse_host(Rest, URI),
+ Host = calculate_parsed_host_port(Rest, T),
+ URI2 = maybe_add_path(URI1),
+ URI2#{host => remove_brackets(Host)}
+ end;
+parse_relative_part(?STRING_REST($/, Rest), URI) ->
+ {T, URI1} = parse_segment(Rest, URI), % path-absolute
+ Path = calculate_parsed_part(Rest, T),
+ URI1#{path => ?STRING_REST($/, Path)};
+parse_relative_part(?STRING_REST($?, Rest), URI) ->
+ {T, URI1} = parse_query(Rest, URI), % path-empty ?query
+ Query = calculate_parsed_query_fragment(Rest, T),
+ URI2 = maybe_add_path(URI1),
+ URI2#{query => Query};
+parse_relative_part(?STRING_REST($#, Rest), URI) ->
+ {T, URI1} = parse_fragment(Rest, URI), % path-empty
+ Fragment = calculate_parsed_query_fragment(Rest, T),
+ URI2 = maybe_add_path(URI1),
+ URI2#{fragment => Fragment};
+parse_relative_part(?STRING_REST(Char, Rest), URI) ->
+ case is_segment_nz_nc(Char) of
+ true ->
+ {T, URI1} = parse_segment_nz_nc(Rest, URI), % path-noscheme
+ Path = calculate_parsed_part(Rest, T),
+ URI1#{path => ?STRING_REST(Char, Path)};
+ false -> throw({error,invalid_uri,[Char]})
+ end.
+
+
+%%-------------------------------------------------------------------------
+%% [RFC 3986, Chapter 3.3. Path]
+%%
+%% The path component contains data, usually organized in hierarchical
+%% form, that, along with data in the non-hierarchical query component
+%% (Section 3.4), serves to identify a resource within the scope of the
+%% URI's scheme and naming authority (if any). The path is terminated
+%% by the first question mark ("?") or number sign ("#") character, or
+%% by the end of the URI.
+%%
+%% path = path-abempty ; begins with "/" or is empty
+%% / path-absolute ; begins with "/" but not "//"
+%% / path-noscheme ; begins with a non-colon segment
+%% / path-rootless ; begins with a segment
+%% / path-empty ; zero characters
+%%
+%% path-abempty = *( "/" segment )
+%% path-absolute = "/" [ segment-nz *( "/" segment ) ]
+%% path-noscheme = segment-nz-nc *( "/" segment )
+%% path-rootless = segment-nz *( "/" segment )
+%% path-empty = 0<pchar>
+%% segment = *pchar
+%% segment-nz = 1*pchar
+%% segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
+%% ; non-zero-length segment without any colon ":"
+%%
+%% pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+%%-------------------------------------------------------------------------
+
+%%-------------------------------------------------------------------------
+%% path-abempty
+%%-------------------------------------------------------------------------
+-spec parse_segment(binary(), uri_map()) -> {binary(), uri_map()}.
+parse_segment(?STRING_REST($/, Rest), URI) ->
+ parse_segment(Rest, URI); % segment
+parse_segment(?STRING_REST($?, Rest), URI) ->
+ {T, URI1} = parse_query(Rest, URI), % ?query
+ Query = calculate_parsed_query_fragment(Rest, T),
+ {Rest, URI1#{query => Query}};
+parse_segment(?STRING_REST($#, Rest), URI) ->
+ {T, URI1} = parse_fragment(Rest, URI),
+ Fragment = calculate_parsed_query_fragment(Rest, T),
+ {Rest, URI1#{fragment => Fragment}};
+parse_segment(?STRING_REST(Char, Rest), URI) ->
+ case is_pchar(Char) of
+ true -> parse_segment(Rest, URI);
+ false -> throw({error,invalid_uri,[Char]})
+ end;
+parse_segment(?STRING_EMPTY, URI) ->
+ {?STRING_EMPTY, URI}.
+
+
+%%-------------------------------------------------------------------------
+%% path-noscheme
+%%-------------------------------------------------------------------------
+-spec parse_segment_nz_nc(binary(), uri_map()) -> {binary(), uri_map()}.
+parse_segment_nz_nc(?STRING_REST($/, Rest), URI) ->
+ parse_segment(Rest, URI); % segment
+parse_segment_nz_nc(?STRING_REST($?, Rest), URI) ->
+ {T, URI1} = parse_query(Rest, URI), % ?query
+ Query = calculate_parsed_query_fragment(Rest, T),
+ {Rest, URI1#{query => Query}};
+parse_segment_nz_nc(?STRING_REST($#, Rest), URI) ->
+ {T, URI1} = parse_fragment(Rest, URI),
+ Fragment = calculate_parsed_query_fragment(Rest, T),
+ {Rest, URI1#{fragment => Fragment}};
+parse_segment_nz_nc(?STRING_REST(Char, Rest), URI) ->
+ case is_segment_nz_nc(Char) of
+ true -> parse_segment_nz_nc(Rest, URI);
+ false -> throw({error,invalid_uri,[Char]})
+ end;
+parse_segment_nz_nc(?STRING_EMPTY, URI) ->
+ {?STRING_EMPTY, URI}.
+
+
+%% Check if char is pchar.
+-spec is_pchar(char()) -> boolean().
+is_pchar($%) -> true; % pct-encoded
+is_pchar($:) -> true;
+is_pchar($@) -> true;
+is_pchar(Char) -> is_unreserved(Char) orelse is_sub_delim(Char).
+
+%% Check if char is segment_nz_nc.
+-spec is_segment_nz_nc(char()) -> boolean().
+is_segment_nz_nc($%) -> true; % pct-encoded
+is_segment_nz_nc($@) -> true;
+is_segment_nz_nc(Char) -> is_unreserved(Char) orelse is_sub_delim(Char).
+
+
+%%-------------------------------------------------------------------------
+%% [RFC 3986, Chapter 3.1. Scheme]
+%%
+%% Each URI begins with a scheme name that refers to a specification for
+%% assigning identifiers within that scheme.
+%%
+%% scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+%%-------------------------------------------------------------------------
+-spec parse_scheme_start(binary(), uri_map()) -> uri_map().
+parse_scheme_start(?STRING_REST(Char, Rest), URI) ->
+ case is_alpha(Char) of
+ true -> {T, URI1} = parse_scheme(Rest, URI),
+ Scheme = calculate_parsed_scheme(Rest, T),
+ URI2 = maybe_add_path(URI1),
+ URI2#{scheme => ?STRING_REST(Char, Scheme)};
+ false -> throw({error,invalid_uri,[Char]})
+ end.
+
+%% Add path component if it missing after parsing the URI.
+%% According to the URI specification there is always a
+%% path component in every URI-reference and it can be
+%% empty.
+maybe_add_path(Map) ->
+ case maps:is_key(path, Map) of
+ false ->
+ Map#{path => <<>>};
+ _Else ->
+ Map
+ end.
+
+
+
+-spec parse_scheme(binary(), uri_map()) -> {binary(), uri_map()}.
+parse_scheme(?STRING_REST($:, Rest), URI) ->
+ {_, URI1} = parse_hier(Rest, URI),
+ {Rest, URI1};
+parse_scheme(?STRING_REST(Char, Rest), URI) ->
+ case is_scheme(Char) of
+ true -> parse_scheme(Rest, URI);
+ false -> throw({error,invalid_uri,[Char]})
+ end;
+parse_scheme(?STRING_EMPTY, _URI) ->
+ throw({error,invalid_uri,<<>>}).
+
+
+%% Check if char is allowed in scheme
+-spec is_scheme(char()) -> boolean().
+is_scheme($+) -> true;
+is_scheme($-) -> true;
+is_scheme($.) -> true;
+is_scheme(Char) -> is_alpha(Char) orelse is_digit(Char).
+
+
+%%-------------------------------------------------------------------------
+%% hier-part = "//" authority path-abempty
+%% / path-absolute
+%% / path-rootless
+%% / path-empty
+%%-------------------------------------------------------------------------
+-spec parse_hier(binary(), uri_map()) -> {binary(), uri_map()}.
+parse_hier(?STRING_REST("//", Rest), URI) ->
+ % Parse userinfo - "//" is NOT part of authority
+ try parse_userinfo(Rest, URI) of
+ {T, URI1} ->
+ Userinfo = calculate_parsed_userinfo(Rest, T),
+ {Rest, URI1#{userinfo => Userinfo}}
+ catch
+ throw:{_,_,_} ->
+ {T, URI1} = parse_host(Rest, URI),
+ Host = calculate_parsed_host_port(Rest, T),
+ {Rest, URI1#{host => remove_brackets(Host)}}
+ end;
+parse_hier(?STRING_REST($/, Rest), URI) ->
+ {T, URI1} = parse_segment(Rest, URI), % path-absolute
+ Path = calculate_parsed_part(Rest, T),
+ {Rest, URI1#{path => ?STRING_REST($/, Path)}};
+parse_hier(?STRING_REST($?, Rest), URI) ->
+ {T, URI1} = parse_query(Rest, URI), % path-empty ?query
+ Query = calculate_parsed_query_fragment(Rest, T),
+ {Rest, URI1#{query => Query}};
+parse_hier(?STRING_REST($#, Rest), URI) ->
+ {T, URI1} = parse_fragment(Rest, URI), % path-empty
+ Fragment = calculate_parsed_query_fragment(Rest, T),
+ {Rest, URI1#{fragment => Fragment}};
+parse_hier(?STRING_REST(Char, Rest), URI) -> % path-rootless
+ case is_pchar(Char) of
+ true -> % segment_nz
+ {T, URI1} = parse_segment(Rest, URI),
+ Path = calculate_parsed_part(Rest, T),
+ {Rest, URI1#{path => ?STRING_REST(Char, Path)}};
+ false -> throw({error,invalid_uri,[Char]})
+ end;
+parse_hier(?STRING_EMPTY, URI) ->
+ {<<>>, URI}.
+
+
+%%-------------------------------------------------------------------------
+%% [RFC 3986, Chapter 3.2. Authority]
+%%
+%% Many URI schemes include a hierarchical element for a naming
+%% authority so that governance of the name space defined by the
+%% remainder of the URI is delegated to that authority (which may, in
+%% turn, delegate it further).
+%%
+%% The authority component is preceded by a double slash ("//") and is
+%% terminated by the next slash ("/"), question mark ("?"), or number
+%% sign ("#") character, or by the end of the URI.
+%%
+%% authority = [ userinfo "@" ] host [ ":" port ]
+%%
+%%
+%% [RFC 3986, Chapter 3.2.1. User Information]
+%%
+%% The userinfo subcomponent may consist of a user name and, optionally,
+%% scheme-specific information about how to gain authorization to access
+%% the resource. The user information, if present, is followed by a
+%% commercial at-sign ("@") that delimits it from the host.
+%%
+%% userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
+%%-------------------------------------------------------------------------
+-spec parse_userinfo(binary(), uri_map()) -> {binary(), uri_map()}.
+parse_userinfo(?CHAR($@), URI) ->
+ {?STRING_EMPTY, URI#{host => <<>>}};
+parse_userinfo(?STRING_REST($@, Rest), URI) ->
+ {T, URI1} = parse_host(Rest, URI),
+ Host = calculate_parsed_host_port(Rest, T),
+ {Rest, URI1#{host => remove_brackets(Host)}};
+parse_userinfo(?STRING_REST(Char, Rest), URI) ->
+ case is_userinfo(Char) of
+ true -> parse_userinfo(Rest, URI);
+ false -> throw({error,invalid_uri,[Char]})
+ end;
+parse_userinfo(?STRING_EMPTY, _URI) ->
+ %% URI cannot end in userinfo state
+ throw({error,invalid_uri,<<>>}).
+
+
+%% Check if char is allowed in userinfo
+-spec is_userinfo(char()) -> boolean().
+is_userinfo($%) -> true; % pct-encoded
+is_userinfo($:) -> true;
+is_userinfo(Char) -> is_unreserved(Char) orelse is_sub_delim(Char).
+
+
+%%-------------------------------------------------------------------------
+%% [RFC 3986, Chapter 3.2.2. Host]
+%%
+%% The host subcomponent of authority is identified by an IP literal
+%% encapsulated within square brackets, an IPv4 address in dotted-
+%% decimal form, or a registered name.
+%%
+%% host = IP-literal / IPv4address / reg-name
+%%
+%% IP-literal = "[" ( IPv6address / IPvFuture ) "]"
+%%
+%% IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
+%%
+%% IPv6address = 6( h16 ":" ) ls32
+%% / "::" 5( h16 ":" ) ls32
+%% / [ h16 ] "::" 4( h16 ":" ) ls32
+%% / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
+%% / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
+%% / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
+%% / [ *4( h16 ":" ) h16 ] "::" ls32
+%% / [ *5( h16 ":" ) h16 ] "::" h16
+%% / [ *6( h16 ":" ) h16 ] "::"
+%%
+%% ls32 = ( h16 ":" h16 ) / IPv4address
+%% ; least-significant 32 bits of address
+%%
+%% h16 = 1*4HEXDIG
+%% ; 16 bits of address represented in hexadecimal
+%%
+%% IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
+%%
+%% dec-octet = DIGIT ; 0-9
+%% / %x31-39 DIGIT ; 10-99
+%% / "1" 2DIGIT ; 100-199
+%% / "2" %x30-34 DIGIT ; 200-249
+%% / "25" %x30-35 ; 250-255
+%%
+%% reg-name = *( unreserved / pct-encoded / sub-delims )
+%%-------------------------------------------------------------------------
+-spec parse_host(binary(), uri_map()) -> {binary(), uri_map()}.
+parse_host(?STRING_REST($:, Rest), URI) ->
+ {T, URI1} = parse_port(Rest, URI),
+ H = calculate_parsed_host_port(Rest, T),
+ Port = get_port(H),
+ {Rest, URI1#{port => Port}};
+parse_host(?STRING_REST($/, Rest), URI) ->
+ {T, URI1} = parse_segment(Rest, URI), % path-abempty
+ Path = calculate_parsed_part(Rest, T),
+ {Rest, URI1#{path => ?STRING_REST($/, Path)}};
+parse_host(?STRING_REST($?, Rest), URI) ->
+ {T, URI1} = parse_query(Rest, URI), % path-empty ?query
+ Query = calculate_parsed_query_fragment(Rest, T),
+ {Rest, URI1#{query => Query}};
+parse_host(?STRING_REST($[, Rest), URI) ->
+ parse_ipv6_bin(Rest, [], URI);
+parse_host(?STRING_REST($#, Rest), URI) ->
+ {T, URI1} = parse_fragment(Rest, URI), % path-empty
+ Fragment = calculate_parsed_query_fragment(Rest, T),
+ {Rest, URI1#{fragment => Fragment}};
+parse_host(?STRING_REST(Char, Rest), URI) ->
+ case is_digit(Char) of
+ true ->
+ try parse_ipv4_bin(Rest, [Char], URI)
+ catch
+ throw:{_,_,_} ->
+ parse_reg_name(?STRING_REST(Char, Rest), URI)
+ end;
+ false -> parse_reg_name(?STRING_REST(Char, Rest), URI)
+ end;
+parse_host(?STRING_EMPTY, URI) ->
+ {?STRING_EMPTY, URI}.
+
+
+-spec parse_reg_name(binary(), uri_map()) -> {binary(), uri_map()}.
+parse_reg_name(?STRING_REST($:, Rest), URI) ->
+ {T, URI1} = parse_port(Rest, URI),
+ H = calculate_parsed_host_port(Rest, T),
+ Port = get_port(H),
+ {Rest, URI1#{port => Port}};
+parse_reg_name(?STRING_REST($/, Rest), URI) ->
+ {T, URI1} = parse_segment(Rest, URI), % path-abempty
+ Path = calculate_parsed_part(Rest, T),
+ {Rest, URI1#{path => ?STRING_REST($/, Path)}};
+parse_reg_name(?STRING_REST($?, Rest), URI) ->
+ {T, URI1} = parse_query(Rest, URI), % path-empty ?query
+ Query = calculate_parsed_query_fragment(Rest, T),
+ {Rest, URI1#{query => Query}};
+parse_reg_name(?STRING_REST($#, Rest), URI) ->
+ {T, URI1} = parse_fragment(Rest, URI), % path-empty
+ Fragment = calculate_parsed_query_fragment(Rest, T),
+ {Rest, URI1#{fragment => Fragment}};
+parse_reg_name(?STRING_REST(Char, Rest), URI) ->
+ case is_reg_name(Char) of
+ true -> parse_reg_name(Rest, URI);
+ false -> throw({error,invalid_uri,[Char]})
+ end;
+parse_reg_name(?STRING_EMPTY, URI) ->
+ {?STRING_EMPTY, URI}.
+
+%% Check if char is allowed in reg-name
+-spec is_reg_name(char()) -> boolean().
+is_reg_name($%) -> true;
+is_reg_name(Char) -> is_unreserved(Char) orelse is_sub_delim(Char).
+
+
+-spec parse_ipv4_bin(binary(), list(), uri_map()) -> {binary(), uri_map()}.
+parse_ipv4_bin(?STRING_REST($:, Rest), Acc, URI) ->
+ _ = validate_ipv4_address(lists:reverse(Acc)),
+ {T, URI1} = parse_port(Rest, URI),
+ H = calculate_parsed_host_port(Rest, T),
+ Port = get_port(H),
+ {Rest, URI1#{port => Port}};
+parse_ipv4_bin(?STRING_REST($/, Rest), Acc, URI) ->
+ _ = validate_ipv4_address(lists:reverse(Acc)),
+ {T, URI1} = parse_segment(Rest, URI), % path-abempty
+ Path = calculate_parsed_part(Rest, T),
+ {Rest, URI1#{path => ?STRING_REST($/, Path)}};
+parse_ipv4_bin(?STRING_REST($?, Rest), Acc, URI) ->
+ _ = validate_ipv4_address(lists:reverse(Acc)),
+ {T, URI1} = parse_query(Rest, URI), % path-empty ?query
+ Query = calculate_parsed_query_fragment(Rest, T),
+ {Rest, URI1#{query => Query}};
+parse_ipv4_bin(?STRING_REST($#, Rest), Acc, URI) ->
+ _ = validate_ipv4_address(lists:reverse(Acc)),
+ {T, URI1} = parse_fragment(Rest, URI), % path-empty
+ Fragment = calculate_parsed_query_fragment(Rest, T),
+ {Rest, URI1#{fragment => Fragment}};
+parse_ipv4_bin(?STRING_REST(Char, Rest), Acc, URI) ->
+ case is_ipv4(Char) of
+ true -> parse_ipv4_bin(Rest, [Char|Acc], URI);
+ false -> throw({error,invalid_uri,[Char]})
+ end;
+parse_ipv4_bin(?STRING_EMPTY, Acc, URI) ->
+ _ = validate_ipv4_address(lists:reverse(Acc)),
+ {?STRING_EMPTY, URI}.
+
+
+%% Check if char is allowed in IPv4 addresses
+-spec is_ipv4(char()) -> boolean().
+is_ipv4($.) -> true;
+is_ipv4(Char) -> is_digit(Char).
+
+-spec validate_ipv4_address(list()) -> list().
+validate_ipv4_address(Addr) ->
+ case inet:parse_ipv4strict_address(Addr) of
+ {ok, _} -> Addr;
+ {error, _} -> throw({error,invalid_uri,Addr})
+ end.
+
+
+-spec parse_ipv6_bin(binary(), list(), uri_map()) -> {binary(), uri_map()}.
+parse_ipv6_bin(?STRING_REST($], Rest), Acc, URI) ->
+ _ = validate_ipv6_address(lists:reverse(Acc)),
+ parse_ipv6_bin_end(Rest, URI);
+parse_ipv6_bin(?STRING_REST(Char, Rest), Acc, URI) ->
+ case is_ipv6(Char) of
+ true -> parse_ipv6_bin(Rest, [Char|Acc], URI);
+ false -> throw({error,invalid_uri,[Char]})
+ end;
+parse_ipv6_bin(?STRING_EMPTY, _Acc, _URI) ->
+ throw({error,invalid_uri,<<>>}).
+
+%% Check if char is allowed in IPv6 addresses
+-spec is_ipv6(char()) -> boolean().
+is_ipv6($:) -> true;
+is_ipv6($.) -> true;
+is_ipv6(Char) -> is_hex_digit(Char).
+
+
+-spec parse_ipv6_bin_end(binary(), uri_map()) -> {binary(), uri_map()}.
+parse_ipv6_bin_end(?STRING_REST($:, Rest), URI) ->
+ {T, URI1} = parse_port(Rest, URI),
+ H = calculate_parsed_host_port(Rest, T),
+ Port = get_port(H),
+ {Rest, URI1#{port => Port}};
+parse_ipv6_bin_end(?STRING_REST($/, Rest), URI) ->
+ {T, URI1} = parse_segment(Rest, URI), % path-abempty
+ Path = calculate_parsed_part(Rest, T),
+ {Rest, URI1#{path => ?STRING_REST($/, Path)}};
+parse_ipv6_bin_end(?STRING_REST($?, Rest), URI) ->
+ {T, URI1} = parse_query(Rest, URI), % path-empty ?query
+ Query = calculate_parsed_query_fragment(Rest, T),
+ {Rest, URI1#{query => Query}};
+parse_ipv6_bin_end(?STRING_REST($#, Rest), URI) ->
+ {T, URI1} = parse_fragment(Rest, URI), % path-empty
+ Fragment = calculate_parsed_query_fragment(Rest, T),
+ {Rest, URI1#{fragment => Fragment}};
+parse_ipv6_bin_end(?STRING_REST(Char, Rest), URI) ->
+ case is_ipv6(Char) of
+ true -> parse_ipv6_bin_end(Rest, URI);
+ false -> throw({error,invalid_uri,[Char]})
+ end;
+parse_ipv6_bin_end(?STRING_EMPTY, URI) ->
+ {?STRING_EMPTY, URI}.
+
+-spec validate_ipv6_address(list()) -> list().
+validate_ipv6_address(Addr) ->
+ case inet:parse_ipv6strict_address(Addr) of
+ {ok, _} -> Addr;
+ {error, _} -> throw({error,invalid_uri,Addr})
+ end.
+
+
+%%-------------------------------------------------------------------------
+%% [RFC 3986, Chapter 3.2.2. Port]
+%%
+%% The port subcomponent of authority is designated by an optional port
+%% number in decimal following the host and delimited from it by a
+%% single colon (":") character.
+%%
+%% port = *DIGIT
+%%-------------------------------------------------------------------------
+-spec parse_port(binary(), uri_map()) -> {binary(), uri_map()}.
+parse_port(?STRING_REST($/, Rest), URI) ->
+ {T, URI1} = parse_segment(Rest, URI), % path-abempty
+ Path = calculate_parsed_part(Rest, T),
+ {Rest, URI1#{path => ?STRING_REST($/, Path)}};
+parse_port(?STRING_REST($?, Rest), URI) ->
+ {T, URI1} = parse_query(Rest, URI), % path-empty ?query
+ Query = calculate_parsed_query_fragment(Rest, T),
+ {Rest, URI1#{query => Query}};
+parse_port(?STRING_REST($#, Rest), URI) ->
+ {T, URI1} = parse_fragment(Rest, URI), % path-empty
+ Fragment = calculate_parsed_query_fragment(Rest, T),
+ {Rest, URI1#{fragment => Fragment}};
+parse_port(?STRING_REST(Char, Rest), URI) ->
+ case is_digit(Char) of
+ true -> parse_port(Rest, URI);
+ false -> throw({error,invalid_uri,[Char]})
+ end;
+parse_port(?STRING_EMPTY, URI) ->
+ {?STRING_EMPTY, URI}.
+
+
+%%-------------------------------------------------------------------------
+%% [RFC 3986, Chapter 3.4. Query]
+%%
+%% The query component contains non-hierarchical data that, along with
+%% data in the path component (Section 3.3), serves to identify a
+%% resource within the scope of the URI's scheme and naming authority
+%% (if any). The query component is indicated by the first question
+%% mark ("?") character and terminated by a number sign ("#") character
+%% or by the end of the URI.
+%%
+%% query = *( pchar / "/" / "?" )
+%%-------------------------------------------------------------------------
+-spec parse_query(binary(), uri_map()) -> {binary(), uri_map()}.
+parse_query(?STRING_REST($#, Rest), URI) ->
+ {T, URI1} = parse_fragment(Rest, URI),
+ Fragment = calculate_parsed_query_fragment(Rest, T),
+ {Rest, URI1#{fragment => Fragment}};
+parse_query(?STRING_REST(Char, Rest), URI) ->
+ case is_query(Char) of
+ true -> parse_query(Rest, URI);
+ false -> throw({error,invalid_uri,[Char]})
+ end;
+parse_query(?STRING_EMPTY, URI) ->
+ {?STRING_EMPTY, URI}.
+
+
+%% Check if char is allowed in query
+-spec is_query(char()) -> boolean().
+is_query($/) -> true;
+is_query($?) -> true;
+is_query(Char) -> is_pchar(Char).
+
+
+%%-------------------------------------------------------------------------
+%% [RFC 3986, Chapter 3.5. Fragment]
+%%
+%% The fragment identifier component of a URI allows indirect
+%% identification of a secondary resource by reference to a primary
+%% resource and additional identifying information.
+%%
+%% fragment = *( pchar / "/" / "?" )
+%%-------------------------------------------------------------------------
+-spec parse_fragment(binary(), uri_map()) -> {binary(), uri_map()}.
+parse_fragment(?STRING_REST(Char, Rest), URI) ->
+ case is_fragment(Char) of
+ true -> parse_fragment(Rest, URI);
+ false -> throw({error,invalid_uri,[Char]})
+ end;
+parse_fragment(?STRING_EMPTY, URI) ->
+ {?STRING_EMPTY, URI}.
+
+
+%% Check if char is allowed in fragment
+-spec is_fragment(char()) -> boolean().
+is_fragment($/) -> true;
+is_fragment($?) -> true;
+is_fragment(Char) -> is_pchar(Char).
+
+
+%%-------------------------------------------------------------------------
+%% [RFC 3986, Chapter 2.2. Reserved Characters]
+%%
+%% reserved = gen-delims / sub-delims
+%%
+%% gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
+%%
+%% sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
+%% / "*" / "+" / "," / ";" / "="
+%%
+%%-------------------------------------------------------------------------
+
+%% Return true if input char is reserved.
+-spec is_reserved(char()) -> boolean().
+is_reserved($:) -> true;
+is_reserved($/) -> true;
+is_reserved($?) -> true;
+is_reserved($#) -> true;
+is_reserved($[) -> true;
+is_reserved($]) -> true;
+is_reserved($@) -> true;
+
+is_reserved($!) -> true;
+is_reserved($$) -> true;
+is_reserved($&) -> true;
+is_reserved($') -> true;
+is_reserved($() -> true;
+is_reserved($)) -> true;
+
+is_reserved($*) -> true;
+is_reserved($+) -> true;
+is_reserved($,) -> true;
+is_reserved($;) -> true;
+is_reserved($=) -> true;
+is_reserved(_) -> false.
+
+
+%% Check if char is sub-delim.
+-spec is_sub_delim(char()) -> boolean().
+is_sub_delim($!) -> true;
+is_sub_delim($$) -> true;
+is_sub_delim($&) -> true;
+is_sub_delim($') -> true;
+is_sub_delim($() -> true;
+is_sub_delim($)) -> true;
+
+is_sub_delim($*) -> true;
+is_sub_delim($+) -> true;
+is_sub_delim($,) -> true;
+is_sub_delim($;) -> true;
+is_sub_delim($=) -> true;
+is_sub_delim(_) -> false.
+
+
+%%-------------------------------------------------------------------------
+%% [RFC 3986, Chapter 2.3. Unreserved Characters]
+%%
+%% unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+%%
+%%-------------------------------------------------------------------------
+-spec is_unreserved(char()) -> boolean().
+is_unreserved($-) -> true;
+is_unreserved($.) -> true;
+is_unreserved($_) -> true;
+is_unreserved($~) -> true;
+is_unreserved(Char) -> is_alpha(Char) orelse is_digit(Char).
+
+-spec is_alpha(char()) -> boolean().
+is_alpha(C)
+ when $A =< C, C =< $Z;
+ $a =< C, C =< $z -> true;
+is_alpha(_) -> false.
+
+-spec is_digit(char()) -> boolean().
+is_digit(C)
+ when $0 =< C, C =< $9 -> true;
+is_digit(_) -> false.
+
+-spec is_hex_digit(char()) -> boolean().
+is_hex_digit(C)
+ when $0 =< C, C =< $9;$a =< C, C =< $f;$A =< C, C =< $F -> true;
+is_hex_digit(_) -> false.
+
+
+%% Remove enclosing brackets from binary
+-spec remove_brackets(binary()) -> binary().
+remove_brackets(<<$[/utf8, Rest/binary>>) ->
+ {H,T} = split_binary(Rest, byte_size(Rest) - 1),
+ case T =:= <<$]/utf8>> of
+ true -> H;
+ false -> Rest
+ end;
+remove_brackets(Addr) -> Addr.
+
+
+%%-------------------------------------------------------------------------
+%% Helper functions for calculating the parsed binary.
+%%-------------------------------------------------------------------------
+-spec calculate_parsed_scheme(binary(), binary()) -> binary().
+calculate_parsed_scheme(Input, <<>>) ->
+ strip_last_char(Input, [$:]);
+calculate_parsed_scheme(Input, Unparsed) ->
+ get_parsed_binary(Input, Unparsed).
+
+
+-spec calculate_parsed_part(binary(), binary()) -> binary().
+calculate_parsed_part(Input, <<>>) ->
+ strip_last_char(Input, [$?,$#]);
+calculate_parsed_part(Input, Unparsed) ->
+ get_parsed_binary(Input, Unparsed).
+
+
+-spec calculate_parsed_userinfo(binary(), binary()) -> binary().
+calculate_parsed_userinfo(Input, <<>>) ->
+ strip_last_char(Input, [$?,$#,$@]);
+calculate_parsed_userinfo(Input, Unparsed) ->
+ get_parsed_binary(Input, Unparsed).
+
+
+-spec calculate_parsed_host_port(binary(), binary()) -> binary().
+calculate_parsed_host_port(Input, <<>>) ->
+ strip_last_char(Input, [$:,$?,$#,$/]);
+calculate_parsed_host_port(Input, Unparsed) ->
+ get_parsed_binary(Input, Unparsed).
+
+
+calculate_parsed_query_fragment(Input, <<>>) ->
+ strip_last_char(Input, [$#]);
+calculate_parsed_query_fragment(Input, Unparsed) ->
+ get_parsed_binary(Input, Unparsed).
+
+
+get_port(<<>>) ->
+ undefined;
+get_port(B) ->
+ try binary_to_integer(B)
+ catch
+ error:badarg ->
+ throw({error, invalid_uri, B})
+ end.
+
+
+%% Strip last char if it is in list
+%%
+%% This function is optimized for speed: parse/1 is about 10% faster than
+%% with an alternative implementation based on lists and sets.
+strip_last_char(<<>>, _) -> <<>>;
+strip_last_char(Input, [C0]) ->
+ case binary:last(Input) of
+ C0 ->
+ init_binary(Input);
+ _Else ->
+ Input
+ end;
+strip_last_char(Input, [C0,C1]) ->
+ case binary:last(Input) of
+ C0 ->
+ init_binary(Input);
+ C1 ->
+ init_binary(Input);
+ _Else ->
+ Input
+ end;
+strip_last_char(Input, [C0,C1,C2]) ->
+ case binary:last(Input) of
+ C0 ->
+ init_binary(Input);
+ C1 ->
+ init_binary(Input);
+ C2 ->
+ init_binary(Input);
+ _Else ->
+ Input
+ end;
+strip_last_char(Input, [C0,C1,C2,C3]) ->
+ case binary:last(Input) of
+ C0 ->
+ init_binary(Input);
+ C1 ->
+ init_binary(Input);
+ C2 ->
+ init_binary(Input);
+ C3 ->
+ init_binary(Input);
+ _Else ->
+ Input
+ end.
+
+
+%% Get parsed binary
+get_parsed_binary(Input, Unparsed) ->
+ {First, _} = split_binary(Input, byte_size(Input) - byte_size_exl_head(Unparsed)),
+ First.
+
+
+%% Return all bytes of the binary except the last one. The binary must be non-empty.
+init_binary(B) ->
+ {Init, _} =
+ split_binary(B, byte_size(B) - 1),
+ Init.
+
+
+%% Returns the size of a binary exluding the first element.
+%% Used in calls to split_binary().
+-spec byte_size_exl_head(binary()) -> number().
+byte_size_exl_head(<<>>) -> 0;
+byte_size_exl_head(Binary) -> byte_size(Binary) + 1.
+
+
+%%-------------------------------------------------------------------------
+%% [RFC 3986, Chapter 2.1. Percent-Encoding]
+%%
+%% A percent-encoding mechanism is used to represent a data octet in a
+%% component when that octet's corresponding character is outside the
+%% allowed set or is being used as a delimiter of, or within, the
+%% component. A percent-encoded octet is encoded as a character
+%% triplet, consisting of the percent character "%" followed by the two
+%% hexadecimal digits representing that octet's numeric value. For
+%% example, "%20" is the percent-encoding for the binary octet
+%% "00100000" (ABNF: %x20), which in US-ASCII corresponds to the space
+%% character (SP). Section 2.4 describes when percent-encoding and
+%% decoding is applied.
+%%
+%% pct-encoded = "%" HEXDIG HEXDIG
+%%-------------------------------------------------------------------------
+
+%%-------------------------------------------------------------------------
+%% Percent-encode
+%%-------------------------------------------------------------------------
+
+%% Only validates as scheme cannot have percent-encoded characters
+-spec encode_scheme(list()|binary()) -> list() | binary().
+encode_scheme([]) ->
+ throw({error,invalid_scheme,""});
+encode_scheme(<<>>) ->
+ throw({error,invalid_scheme,<<>>});
+encode_scheme(Scheme) ->
+ case validate_scheme(Scheme) of
+ true -> Scheme;
+ false -> throw({error,invalid_scheme,Scheme})
+ end.
+
+-spec encode_userinfo(list()|binary()) -> list() | binary().
+encode_userinfo(Cs) ->
+ encode(Cs, fun is_userinfo/1).
+
+-spec encode_host(list()|binary()) -> list() | binary().
+encode_host(Cs) ->
+ case classify_host(Cs) of
+ regname -> Cs;
+ ipv4 -> Cs;
+ ipv6 -> bracket_ipv6(Cs);
+ other -> encode(Cs, fun is_reg_name/1)
+ end.
+
+-spec encode_path(list()|binary()) -> list() | binary().
+encode_path(Cs) ->
+ encode(Cs, fun is_path/1).
+
+-spec encode_query(list()|binary()) -> list() | binary().
+encode_query(Cs) ->
+ encode(Cs, fun is_query/1).
+
+-spec encode_fragment(list()|binary()) -> list() | binary().
+encode_fragment(Cs) ->
+ encode(Cs, fun is_fragment/1).
+
+%%-------------------------------------------------------------------------
+%% Helper funtions for percent-decode
+%%-------------------------------------------------------------------------
+
+-spec decode(list()|binary()) -> list() | binary().
+decode(Cs) ->
+ decode(Cs, <<>>).
+%%
+decode(L, Acc) when is_list(L) ->
+ B0 = unicode:characters_to_binary(L),
+ B1 = decode(B0, Acc),
+ unicode:characters_to_list(B1);
+decode(<<$%,C0,C1,Cs/binary>>, Acc) ->
+ case is_hex_digit(C0) andalso is_hex_digit(C1) of
+ true ->
+ B = ?HEX2DEC(C0)*16+?HEX2DEC(C1),
+ case is_reserved(B) of
+ true ->
+ %% [2.2] Characters in the reserved set are protected from
+ %% normalization.
+ %% [2.1] For consistency, URI producers and normalizers should
+ %% use uppercase hexadecimal digits for all percent-
+ %% encodings.
+ H0 = hex_to_upper(C0),
+ H1 = hex_to_upper(C1),
+ decode(Cs, <<Acc/binary,$%,H0,H1>>);
+ false ->
+ decode(Cs, <<Acc/binary, B>>)
+ end;
+ false -> throw({error,invalid_percent_encoding,<<$%,C0,C1>>})
+ end;
+decode(<<C,Cs/binary>>, Acc) ->
+ decode(Cs, <<Acc/binary, C>>);
+decode(<<>>, Acc) ->
+ check_utf8(Acc).
+
+%% Returns Cs if it is utf8 encoded.
+check_utf8(Cs) ->
+ case unicode:characters_to_list(Cs) of
+ {incomplete,_,_} ->
+ throw({error,invalid_utf8,Cs});
+ {error,_,_} ->
+ throw({error,invalid_utf8,Cs});
+ _ -> Cs
+ end.
+
+%% Convert hex digit to uppercase form
+hex_to_upper(H) when $a =< H, H =< $f ->
+ H - 32;
+hex_to_upper(H) when $0 =< H, H =< $9;$A =< H, H =< $F->
+ H;
+hex_to_upper(H) ->
+ throw({error,invalid_input, H}).
+
+%% Check if char is allowed in host
+-spec is_host(char()) -> boolean().
+is_host($:) -> true;
+is_host(Char) -> is_unreserved(Char) orelse is_sub_delim(Char).
+
+%% Check if char is allowed in path
+-spec is_path(char()) -> boolean().
+is_path($/) -> true;
+is_path(Char) -> is_pchar(Char).
+
+
+%%-------------------------------------------------------------------------
+%% Helper functions for percent-encode
+%%-------------------------------------------------------------------------
+-spec encode(list()|binary(), fun()) -> list() | binary().
+encode(Component, Fun) when is_list(Component) ->
+ B = unicode:characters_to_binary(Component),
+ unicode:characters_to_list(encode(B, Fun, <<>>));
+encode(Component, Fun) when is_binary(Component) ->
+ encode(Component, Fun, <<>>).
+%%
+encode(<<Char/utf8, Rest/binary>>, Fun, Acc) ->
+ C = encode_codepoint_binary(Char, Fun),
+ encode(Rest, Fun, <<Acc/binary,C/binary>>);
+encode(<<Char, Rest/binary>>, _Fun, _Acc) ->
+ throw({error,invalid_input,<<Char,Rest/binary>>});
+encode(<<>>, _Fun, Acc) ->
+ Acc.
+
+
+-spec encode_codepoint_binary(integer(), fun()) -> binary().
+encode_codepoint_binary(C, Fun) ->
+ case Fun(C) of
+ false -> percent_encode_binary(C);
+ true -> <<C>>
+ end.
+
+
+-spec percent_encode_binary(integer()) -> binary().
+percent_encode_binary(Code) ->
+ percent_encode_binary(<<Code/utf8>>, <<>>).
+
+
+percent_encode_binary(<<A:4,B:4,Rest/binary>>, Acc) ->
+ percent_encode_binary(Rest, <<Acc/binary,$%,(?DEC2HEX(A)),(?DEC2HEX(B))>>);
+percent_encode_binary(<<>>, Acc) ->
+ Acc.
+
+
+%%-------------------------------------------------------------------------
+%%-------------------------------------------------------------------------
+validate_scheme([]) -> true;
+validate_scheme([H|T]) ->
+ case is_scheme(H) of
+ true -> validate_scheme(T);
+ false -> false
+ end;
+validate_scheme(<<>>) -> true;
+validate_scheme(<<H, Rest/binary>>) ->
+ case is_scheme(H) of
+ true -> validate_scheme(Rest);
+ false -> false
+ end.
+
+
+%%-------------------------------------------------------------------------
+%% Classifies hostname into the following categories:
+%% regname, ipv4 - address does not contain reserved characters to be
+%% percent-encoded
+%% ipv6 - address does not contain reserved characters but it shall be
+%% encolsed in brackets
+%% other - address shall be percent-encoded
+%%-------------------------------------------------------------------------
+classify_host([]) -> other;
+classify_host(Addr) when is_binary(Addr) ->
+ A = unicode:characters_to_list(Addr),
+ classify_host_ipv6(A);
+classify_host(Addr) ->
+ classify_host_ipv6(Addr).
+
+classify_host_ipv6(Addr) ->
+ case is_ipv6_address(Addr) of
+ true -> ipv6;
+ false -> classify_host_ipv4(Addr)
+ end.
+
+classify_host_ipv4(Addr) ->
+ case is_ipv4_address(Addr) of
+ true -> ipv4;
+ false -> classify_host_regname(Addr)
+ end.
+
+classify_host_regname([]) -> regname;
+classify_host_regname([H|T]) ->
+ case is_reg_name(H) of
+ true -> classify_host_regname(T);
+ false -> other
+ end.
+
+is_ipv4_address(Addr) ->
+ case inet:parse_ipv4strict_address(Addr) of
+ {ok, _} -> true;
+ {error, _} -> false
+ end.
+
+is_ipv6_address(Addr) ->
+ case inet:parse_ipv6strict_address(Addr) of
+ {ok, _} -> true;
+ {error, _} -> false
+ end.
+
+bracket_ipv6(Addr) when is_binary(Addr) ->
+ concat(<<$[,Addr/binary>>,<<$]>>);
+bracket_ipv6(Addr) when is_list(Addr) ->
+ [$[|Addr] ++ "]".
+
+
+%%-------------------------------------------------------------------------
+%% Helper funtions for recompose
+%%-------------------------------------------------------------------------
+
+%%-------------------------------------------------------------------------
+%% Checks if input Map has valid combination of fields that can be
+%% recomposed into a URI.
+%%
+%% The implementation is based on a decision tree that fulfills the
+%% following rules:
+%% - 'path' shall always be present in the input map
+%% URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
+%% hier-part = "//" authority path-abempty
+%% / path-absolute
+%% / path-rootless
+%% / path-empty
+%% - 'host' shall be present in the input map when 'path' starts with
+%% two slashes ("//")
+%% path = path-abempty ; begins with "/" or is empty
+%% / path-absolute ; begins with "/" but not "//"
+%% / path-noscheme ; begins with a non-colon segment
+%% / path-rootless ; begins with a segment
+%% / path-empty ; zero characters
+%% path-abempty = *( "/" segment )
+%% segment = *pchar
+%% - 'host' shall be present if userinfo or port is present in input map
+%% authority = [ userinfo "@" ] host [ ":" port ]
+%% - All fields shall be valid (scheme, userinfo, host, port, path, query
+%% or fragment).
+%%-------------------------------------------------------------------------
+is_valid_map(#{path := Path} = Map) ->
+ ((starts_with_two_slash(Path) andalso is_valid_map_host(Map))
+ orelse
+ (maps:is_key(userinfo, Map) andalso is_valid_map_host(Map))
+ orelse
+ (maps:is_key(port, Map) andalso is_valid_map_host(Map))
+ orelse
+ all_fields_valid(Map));
+is_valid_map(#{}) ->
+ false.
+
+
+is_valid_map_host(Map) ->
+ maps:is_key(host, Map) andalso all_fields_valid(Map).
+
+
+all_fields_valid(Map) ->
+ Fun = fun(scheme, _, Acc) -> Acc;
+ (userinfo, _, Acc) -> Acc;
+ (host, _, Acc) -> Acc;
+ (port, _, Acc) -> Acc;
+ (path, _, Acc) -> Acc;
+ (query, _, Acc) -> Acc;
+ (fragment, _, Acc) -> Acc;
+ (_, _, _) -> false
+ end,
+ maps:fold(Fun, true, Map).
+
+
+starts_with_two_slash([$/,$/|_]) ->
+ true;
+starts_with_two_slash(?STRING_REST("//", _)) ->
+ true;
+starts_with_two_slash(_) -> false.
+
+
+update_scheme(#{scheme := Scheme}, _) ->
+ add_colon_postfix(encode_scheme(Scheme));
+update_scheme(#{}, _) ->
+ empty.
+
+
+update_userinfo(#{userinfo := Userinfo}, empty) ->
+ add_auth_prefix(encode_userinfo(Userinfo));
+update_userinfo(#{userinfo := Userinfo}, URI) ->
+ concat(URI,add_auth_prefix(encode_userinfo(Userinfo)));
+update_userinfo(#{}, empty) ->
+ empty;
+update_userinfo(#{}, URI) ->
+ URI.
+
+
+update_host(#{host := Host}, empty) ->
+ add_auth_prefix(encode_host(Host));
+update_host(#{host := Host} = Map, URI) ->
+ concat(URI,add_host_prefix(Map, encode_host(Host)));
+update_host(#{}, empty) ->
+ empty;
+update_host(#{}, URI) ->
+ URI.
+
+
+%% URI cannot be empty for ports. E.g. ":8080" is not a valid URI
+update_port(#{port := undefined}, URI) ->
+ concat(URI, <<":">>);
+update_port(#{port := Port}, URI) ->
+ concat(URI,add_colon(encode_port(Port)));
+update_port(#{}, URI) ->
+ URI.
+
+
+update_path(#{path := Path}, empty) ->
+ encode_path(Path);
+update_path(#{path := Path}, URI) ->
+ concat(URI,encode_path(Path));
+update_path(#{}, empty) ->
+ empty;
+update_path(#{}, URI) ->
+ URI.
+
+
+update_query(#{query := Query}, empty) ->
+ encode_query(Query);
+update_query(#{query := Query}, URI) ->
+ concat(URI,add_question_mark(encode_query(Query)));
+update_query(#{}, empty) ->
+ empty;
+update_query(#{}, URI) ->
+ URI.
+
+
+update_fragment(#{fragment := Fragment}, empty) ->
+ add_hashmark(encode_fragment(Fragment));
+update_fragment(#{fragment := Fragment}, URI) ->
+ concat(URI,add_hashmark(encode_fragment(Fragment)));
+update_fragment(#{}, empty) ->
+ "";
+update_fragment(#{}, URI) ->
+ URI.
+
+%%-------------------------------------------------------------------------
+%% Concatenates its arguments that can be lists and binaries.
+%% The result is a list if at least one of its argument is a list and
+%% binary otherwise.
+%%-------------------------------------------------------------------------
+concat(A, B) when is_binary(A), is_binary(B) ->
+ <<A/binary, B/binary>>;
+concat(A, B) when is_binary(A), is_list(B) ->
+ unicode:characters_to_list(A) ++ B;
+concat(A, B) when is_list(A) ->
+ A ++ maybe_to_list(B).
+
+add_hashmark(Comp) when is_binary(Comp) ->
+ <<$#, Comp/binary>>;
+add_hashmark(Comp) when is_list(Comp) ->
+ [$#|Comp].
+
+add_question_mark(Comp) when is_binary(Comp) ->
+ <<$?, Comp/binary>>;
+add_question_mark(Comp) when is_list(Comp) ->
+ [$?|Comp].
+
+add_colon(Comp) when is_binary(Comp) ->
+ <<$:, Comp/binary>>.
+
+add_colon_postfix(Comp) when is_binary(Comp) ->
+ <<Comp/binary,$:>>;
+add_colon_postfix(Comp) when is_list(Comp) ->
+ Comp ++ ":".
+
+add_auth_prefix(Comp) when is_binary(Comp) ->
+ <<"//", Comp/binary>>;
+add_auth_prefix(Comp) when is_list(Comp) ->
+ [$/,$/|Comp].
+
+add_host_prefix(#{userinfo := _}, Host) when is_binary(Host) ->
+ <<$@,Host/binary>>;
+add_host_prefix(#{}, Host) when is_binary(Host) ->
+ <<"//",Host/binary>>;
+add_host_prefix(#{userinfo := _}, Host) when is_list(Host) ->
+ [$@|Host];
+add_host_prefix(#{}, Host) when is_list(Host) ->
+ [$/,$/|Host].
+
+maybe_to_list(Comp) when is_binary(Comp) -> unicode:characters_to_list(Comp);
+maybe_to_list(Comp) -> Comp.
+
+encode_port(Port) ->
+ integer_to_binary(Port).
+
+%%-------------------------------------------------------------------------
+%% Helper functions for transcode
+%%-------------------------------------------------------------------------
+
+%%-------------------------------------------------------------------------
+%% uri_string:transcode(<<"x%00%00%00%F6"/utf32>>).
+%% 1. Convert (transcode/2) input to list form (list of unicode codepoints)
+%% "x%00%00%00%F6"
+%% 2. Accumulate characters until percent-encoded segment (transcode/4).
+%% Acc = "x"
+%% 3. Convert percent-encoded triplets to binary form (transcode_pct/4)
+%% <<0,0,0,246>>
+%% 4. Transcode in-encoded binary to out-encoding (utf32 -> utf8):
+%% <<195,182>>
+%% 5. Percent-encode out-encoded binary:
+%% <<"%C3%B6"/utf8>> = <<37,67,51,37,66,54>>
+%% 6. Convert binary to list form, reverse it and append the accumulator
+%% "6B%3C%" + "x"
+%% 7. Reverse Acc and return it
+%%-------------------------------------------------------------------------
+transcode([$%,_C0,_C1|_Rest] = L, Acc, InEnc, OutEnc) ->
+ transcode_pct(L, Acc, <<>>, InEnc, OutEnc);
+transcode([_C|_Rest] = L, Acc, InEnc, OutEnc) ->
+ transcode(L, Acc, [], InEnc, OutEnc).
+%%
+transcode([$%,_C0,_C1|_Rest] = L, Acc, List, InEncoding, OutEncoding) ->
+ transcode_pct(L, List ++ Acc, <<>>, InEncoding, OutEncoding);
+transcode([C|Rest], Acc, List, InEncoding, OutEncoding) ->
+ transcode(Rest, Acc, [C|List], InEncoding, OutEncoding);
+transcode([], Acc, List, _InEncoding, _OutEncoding) ->
+ lists:reverse(List ++ Acc).
+
+
+%% Transcode percent-encoded segment
+transcode_pct([$%,C0,C1|Rest] = L, Acc, B, InEncoding, OutEncoding) ->
+ case is_hex_digit(C0) andalso is_hex_digit(C1) of
+ true ->
+ Int = ?HEX2DEC(C0)*16+?HEX2DEC(C1),
+ transcode_pct(Rest, Acc, <<B/binary, Int>>, InEncoding, OutEncoding);
+ false -> throw({error, invalid_percent_encoding,L})
+ end;
+transcode_pct([_C|_Rest] = L, Acc, B, InEncoding, OutEncoding) ->
+ OutBinary = convert_to_binary(B, InEncoding, OutEncoding),
+ PctEncUtf8 = percent_encode_segment(OutBinary),
+ Out = lists:reverse(convert_to_list(PctEncUtf8, utf8)),
+ transcode(L, Out ++ Acc, [], InEncoding, OutEncoding);
+transcode_pct([], Acc, B, InEncoding, OutEncoding) ->
+ OutBinary = convert_to_binary(B, InEncoding, OutEncoding),
+ PctEncUtf8 = percent_encode_segment(OutBinary),
+ Out = convert_to_list(PctEncUtf8, utf8),
+ lists:reverse(Acc) ++ Out.
+
+
+%% Convert to binary
+convert_to_binary(Binary, InEncoding, OutEncoding) ->
+ case unicode:characters_to_binary(Binary, InEncoding, OutEncoding) of
+ {error, _List, RestData} ->
+ throw({error, invalid_input, RestData});
+ {incomplete, _List, RestData} ->
+ throw({error, invalid_input, RestData});
+ Result ->
+ Result
+ end.
+
+
+%% Convert to list
+convert_to_list(Binary, InEncoding) ->
+ case unicode:characters_to_list(Binary, InEncoding) of
+ {error, _List, RestData} ->
+ throw({error, invalid_input, RestData});
+ {incomplete, _List, RestData} ->
+ throw({error, invalid_input, RestData});
+ Result ->
+ Result
+ end.
+
+
+%% Flatten input list
+flatten_list([], _) ->
+ [];
+flatten_list(L, InEnc) ->
+ flatten_list(L, InEnc, []).
+%%
+flatten_list([H|T], InEnc, Acc) when is_binary(H) ->
+ L = convert_to_list(H, InEnc),
+ flatten_list(T, InEnc, lists:reverse(L) ++ Acc);
+flatten_list([H|T], InEnc, Acc) when is_list(H) ->
+ flatten_list(H ++ T, InEnc, Acc);
+flatten_list([H|T], InEnc, Acc) ->
+ flatten_list(T, InEnc, [H|Acc]);
+flatten_list([], _InEnc, Acc) ->
+ lists:reverse(Acc);
+flatten_list(Arg, _, _) ->
+ throw({error, invalid_input, Arg}).
+
+
+percent_encode_segment(Segment) ->
+ percent_encode_binary(Segment, <<>>).
+
+
+%%-------------------------------------------------------------------------
+%% Helper functions for compose_query
+%%-------------------------------------------------------------------------
+
+%% Returns separator to be used between key-value pairs
+get_separator(L) when length(L) =:= 0 ->
+ <<>>;
+get_separator(_L) ->
+ <<"&">>.
+
+
+%% HTML 5.2 - 4.10.21.6 URL-encoded form data - WHATWG URL (10 Jan 2018) - UTF-8
+%% HTML 5.0 - 4.10.22.6 URL-encoded form data - encoding (non UTF-8)
+form_urlencode(Cs, [{encoding, latin1}]) when is_list(Cs) ->
+ B = convert_to_binary(Cs, utf8, utf8),
+ html5_byte_encode(base10_encode(B));
+form_urlencode(Cs, [{encoding, latin1}]) when is_binary(Cs) ->
+ html5_byte_encode(base10_encode(Cs));
+form_urlencode(Cs, [{encoding, Encoding}])
+ when is_list(Cs), Encoding =:= utf8; Encoding =:= unicode ->
+ B = convert_to_binary(Cs, utf8, Encoding),
+ html5_byte_encode(B);
+form_urlencode(Cs, [{encoding, Encoding}])
+ when is_binary(Cs), Encoding =:= utf8; Encoding =:= unicode ->
+ html5_byte_encode(Cs);
+form_urlencode(Cs, [{encoding, Encoding}]) when is_list(Cs); is_binary(Cs) ->
+ throw({error,invalid_encoding, Encoding});
+form_urlencode(Cs, _) ->
+ throw({error,invalid_input, Cs}).
+
+
+%% For each character in the entry's name and value that cannot be expressed using
+%% the selected character encoding, replace the character by a string consisting of
+%% a U+0026 AMPERSAND character (&), a "#" (U+0023) character, one or more ASCII
+%% digits representing the Unicode code point of the character in base ten, and
+%% finally a ";" (U+003B) character.
+base10_encode(Cs) ->
+ base10_encode(Cs, <<>>).
+%%
+base10_encode(<<>>, Acc) ->
+ Acc;
+base10_encode(<<H/utf8,T/binary>>, Acc) when H > 255 ->
+ Base10 = convert_to_binary(integer_to_list(H,10), utf8, utf8),
+ base10_encode(T, <<Acc/binary,"&#",Base10/binary,$;>>);
+base10_encode(<<H/utf8,T/binary>>, Acc) ->
+ base10_encode(T, <<Acc/binary,H>>).
+
+
+html5_byte_encode(B) ->
+ html5_byte_encode(B, <<>>).
+%%
+html5_byte_encode(<<>>, Acc) ->
+ Acc;
+html5_byte_encode(<<$ ,T/binary>>, Acc) ->
+ html5_byte_encode(T, <<Acc/binary,$+>>);
+html5_byte_encode(<<H,T/binary>>, Acc) ->
+ case is_url_char(H) of
+ true ->
+ html5_byte_encode(T, <<Acc/binary,H>>);
+ false ->
+ <<A:4,B:4>> = <<H>>,
+ html5_byte_encode(T, <<Acc/binary,$%,(?DEC2HEX(A)),(?DEC2HEX(B))>>)
+ end;
+html5_byte_encode(H, _Acc) ->
+ throw({error,invalid_input, H}).
+
+
+%% Return true if input char can appear in form-urlencoded string
+%% Allowed chararacters:
+%% 0x2A, 0x2D, 0x2E, 0x30 to 0x39, 0x41 to 0x5A,
+%% 0x5F, 0x61 to 0x7A
+is_url_char(C)
+ when C =:= 16#2A; C =:= 16#2D;
+ C =:= 16#2E; C =:= 16#5F;
+ 16#30 =< C, C =< 16#39;
+ 16#41 =< C, C =< 16#5A;
+ 16#61 =< C, C =< 16#7A -> true;
+is_url_char(_) -> false.
+
+
+%%-------------------------------------------------------------------------
+%% Helper functions for dissect_query
+%%-------------------------------------------------------------------------
+dissect_query_key(<<$=,T/binary>>, IsList, Acc, Key, Value) ->
+ dissect_query_value(T, IsList, Acc, Key, Value);
+dissect_query_key(<<"&#",T/binary>>, IsList, Acc, Key, Value) ->
+ dissect_query_key(T, IsList, Acc, <<Key/binary,"&#">>, Value);
+dissect_query_key(T = <<$&,_/binary>>, IsList, Acc, Key, <<>>) ->
+ dissect_query_value(T, IsList, Acc, Key, true);
+dissect_query_key(<<H,T/binary>>, IsList, Acc, Key, Value) ->
+ dissect_query_key(T, IsList, Acc, <<Key/binary,H>>, Value);
+dissect_query_key(T = <<>>, IsList, Acc, Key, <<>>) ->
+ dissect_query_value(T, IsList, Acc, Key, true).
+
+dissect_query_value(<<$&,T/binary>>, IsList, Acc, Key, Value) ->
+ K = form_urldecode(IsList, Key),
+ V = form_urldecode(IsList, Value),
+ dissect_query_key(T, IsList, [{K,V}|Acc], <<>>, <<>>);
+dissect_query_value(<<H,T/binary>>, IsList, Acc, Key, Value) ->
+ dissect_query_value(T, IsList, Acc, Key, <<Value/binary,H>>);
+dissect_query_value(<<>>, IsList, Acc, Key, Value) ->
+ K = form_urldecode(IsList, Key),
+ V = form_urldecode(IsList, Value),
+ lists:reverse([{K,V}|Acc]).
+
+%% HTML 5.2 - 4.10.21.6 URL-encoded form data - WHATWG URL (10 Jan 2018) - UTF-8
+%% HTML 5.0 - 4.10.22.6 URL-encoded form data - decoding (non UTF-8)
+form_urldecode(_, true) ->
+ true;
+form_urldecode(true, B) ->
+ Result = base10_decode(form_urldecode(B, <<>>)),
+ convert_to_list(Result, utf8);
+form_urldecode(false, B) ->
+ base10_decode(form_urldecode(B, <<>>));
+form_urldecode(<<>>, Acc) ->
+ Acc;
+form_urldecode(<<$+,T/binary>>, Acc) ->
+ form_urldecode(T, <<Acc/binary,$ >>);
+form_urldecode(<<$%,C0,C1,T/binary>>, Acc) ->
+ case is_hex_digit(C0) andalso is_hex_digit(C1) of
+ true ->
+ V = ?HEX2DEC(C0)*16+?HEX2DEC(C1),
+ form_urldecode(T, <<Acc/binary, V>>);
+ false ->
+ L = convert_to_list(<<$%,C0,C1,T/binary>>, utf8),
+ throw({error, invalid_percent_encoding, L})
+ end;
+form_urldecode(<<H/utf8,T/binary>>, Acc) ->
+ form_urldecode(T, <<Acc/binary,H/utf8>>);
+form_urldecode(<<H,_/binary>>, _Acc) ->
+ throw({error, invalid_character, [H]}).
+
+base10_decode(Cs) ->
+ base10_decode(Cs, <<>>).
+%
+base10_decode(<<>>, Acc) ->
+ Acc;
+base10_decode(<<"&#",T/binary>>, Acc) ->
+ base10_decode_unicode(T, Acc);
+base10_decode(<<H/utf8,T/binary>>, Acc) ->
+ base10_decode(T,<<Acc/binary,H/utf8>>);
+base10_decode(<<H,_/binary>>, _) ->
+ throw({error, invalid_input, [H]}).
+
+
+base10_decode_unicode(B, Acc) ->
+ base10_decode_unicode(B, 0, Acc).
+%%
+base10_decode_unicode(<<H/utf8,T/binary>>, Codepoint, Acc) when $0 =< H, H =< $9 ->
+ Res = Codepoint * 10 + (H - $0),
+ base10_decode_unicode(T, Res, Acc);
+base10_decode_unicode(<<$;,T/binary>>, Codepoint, Acc) ->
+ base10_decode(T, <<Acc/binary,Codepoint/utf8>>);
+base10_decode_unicode(<<H,_/binary>>, _, _) ->
+ throw({error, invalid_input, [H]}).
+
+
+%%-------------------------------------------------------------------------
+%% Helper functions for normalize
+%%-------------------------------------------------------------------------
+
+normalize_map(URIMap) ->
+ normalize_path_segment(
+ normalize_scheme_based(
+ normalize_percent_encoding(
+ normalize_case(URIMap)))).
+
+
+%% 6.2.2.1. Case Normalization
+normalize_case(#{scheme := Scheme, host := Host} = Map) ->
+ Map#{scheme => to_lower(Scheme),
+ host => to_lower(Host)};
+normalize_case(#{host := Host} = Map) ->
+ Map#{host => to_lower(Host)};
+normalize_case(#{scheme := Scheme} = Map) ->
+ Map#{scheme => to_lower(Scheme)};
+normalize_case(#{} = Map) ->
+ Map.
+
+
+%% 6.2.2.2. Percent-Encoding Normalization
+normalize_percent_encoding(Map) ->
+ Fun = fun (K,V) when K =:= userinfo; K =:= host; K =:= path;
+ K =:= query; K =:= fragment ->
+ decode(V);
+ %% Handle port and scheme
+ (_,V) ->
+ V
+ end,
+ maps:map(Fun, Map).
+
+
+to_lower(Cs) when is_list(Cs) ->
+ B = convert_to_binary(Cs, utf8, utf8),
+ convert_to_list(to_lower(B), utf8);
+to_lower(Cs) when is_binary(Cs) ->
+ to_lower(Cs, <<>>).
+%%
+to_lower(<<C,Cs/binary>>, Acc) when $A =< C, C =< $Z ->
+ to_lower(Cs, <<Acc/binary,(C + 32)>>);
+to_lower(<<C,Cs/binary>>, Acc) ->
+ to_lower(Cs, <<Acc/binary,C>>);
+to_lower(<<>>, Acc) ->
+ Acc.
+
+
+%% 6.2.2.3. Path Segment Normalization
+%% 5.2.4. Remove Dot Segments
+normalize_path_segment(Map) ->
+ Path = maps:get(path, Map, undefined),
+ Map#{path => remove_dot_segments(Path)}.
+
+
+remove_dot_segments(Path) when is_binary(Path) ->
+ remove_dot_segments(Path, <<>>);
+remove_dot_segments(Path) when is_list(Path) ->
+ B = convert_to_binary(Path, utf8, utf8),
+ B1 = remove_dot_segments(B, <<>>),
+ convert_to_list(B1, utf8).
+%%
+remove_dot_segments(<<>>, Output) ->
+ Output;
+remove_dot_segments(<<"../",T/binary>>, Output) ->
+ remove_dot_segments(T, Output);
+remove_dot_segments(<<"./",T/binary>>, Output) ->
+ remove_dot_segments(T, Output);
+remove_dot_segments(<<"/./",T/binary>>, Output) ->
+ remove_dot_segments(<<$/,T/binary>>, Output);
+remove_dot_segments(<<"/.">>, Output) ->
+ remove_dot_segments(<<$/>>, Output);
+remove_dot_segments(<<"/../",T/binary>>, Output) ->
+ Out1 = remove_last_segment(Output),
+ remove_dot_segments(<<$/,T/binary>>, Out1);
+remove_dot_segments(<<"/..">>, Output) ->
+ Out1 = remove_last_segment(Output),
+ remove_dot_segments(<<$/>>, Out1);
+remove_dot_segments(<<$.>>, Output) ->
+ remove_dot_segments(<<>>, Output);
+remove_dot_segments(<<"..">>, Output) ->
+ remove_dot_segments(<<>>, Output);
+remove_dot_segments(Input, Output) ->
+ {First, Rest} = first_path_segment(Input),
+ remove_dot_segments(Rest, <<Output/binary,First/binary>>).
+
+
+first_path_segment(Input) ->
+ F = first_path_segment(Input, <<>>),
+ split_binary(Input, byte_size(F)).
+%%
+first_path_segment(<<$/,T/binary>>, Acc) ->
+ first_path_segment_end(<<T/binary>>, <<Acc/binary,$/>>);
+first_path_segment(<<C,T/binary>>, Acc) ->
+ first_path_segment_end(<<T/binary>>, <<Acc/binary,C>>).
+
+
+first_path_segment_end(<<>>, Acc) ->
+ Acc;
+first_path_segment_end(<<$/,_/binary>>, Acc) ->
+ Acc;
+first_path_segment_end(<<C,T/binary>>, Acc) ->
+ first_path_segment_end(<<T/binary>>, <<Acc/binary,C>>).
+
+
+remove_last_segment(<<>>) ->
+ <<>>;
+remove_last_segment(B) ->
+ {Init, Last} = split_binary(B, byte_size(B) - 1),
+ case Last of
+ <<$/>> ->
+ Init;
+ _Char ->
+ remove_last_segment(Init)
+ end.
+
+
+%% RFC 3986, 6.2.3. Scheme-Based Normalization
+normalize_scheme_based(Map) ->
+ Scheme = maps:get(scheme, Map, undefined),
+ Port = maps:get(port, Map, undefined),
+ Path= maps:get(path, Map, undefined),
+ normalize_scheme_based(Map, Scheme, Port, Path).
+%%
+normalize_scheme_based(Map, Scheme, Port, Path)
+ when Scheme =:= "http"; Scheme =:= <<"http">> ->
+ normalize_http(Map, Port, Path);
+normalize_scheme_based(Map, Scheme, Port, Path)
+ when Scheme =:= "https"; Scheme =:= <<"https">> ->
+ normalize_https(Map, Port, Path);
+normalize_scheme_based(Map, Scheme, Port, _Path)
+ when Scheme =:= "ftp"; Scheme =:= <<"ftp">> ->
+ normalize_ftp(Map, Port);
+normalize_scheme_based(Map, Scheme, Port, _Path)
+ when Scheme =:= "ssh"; Scheme =:= <<"ssh">> ->
+ normalize_ssh_sftp(Map, Port);
+normalize_scheme_based(Map, Scheme, Port, _Path)
+ when Scheme =:= "sftp"; Scheme =:= <<"sftp">> ->
+ normalize_ssh_sftp(Map, Port);
+normalize_scheme_based(Map, Scheme, Port, _Path)
+ when Scheme =:= "tftp"; Scheme =:= <<"tftp">> ->
+ normalize_tftp(Map, Port);
+normalize_scheme_based(Map, _, _, _) ->
+ Map.
+
+
+normalize_http(Map, Port, Path) ->
+ M1 = normalize_port(Map, Port, 80),
+ normalize_http_path(M1, Path).
+
+
+normalize_https(Map, Port, Path) ->
+ M1 = normalize_port(Map, Port, 443),
+ normalize_http_path(M1, Path).
+
+
+normalize_ftp(Map, Port) ->
+ normalize_port(Map, Port, 21).
+
+
+normalize_ssh_sftp(Map, Port) ->
+ normalize_port(Map, Port, 22).
+
+
+normalize_tftp(Map, Port) ->
+ normalize_port(Map, Port, 69).
+
+
+normalize_port(Map, Port, Default) ->
+ case Port of
+ Default ->
+ maps:remove(port, Map);
+ _Else ->
+ Map
+ end.
+
+
+normalize_http_path(Map, Path) ->
+ case Path of
+ "" ->
+ Map#{path => "/"};
+ <<>> ->
+ Map#{path => <<"/">>};
+ _Else ->
+ Map
+ end.
diff --git a/lib/stdlib/src/zip.erl b/lib/stdlib/src/zip.erl
index 81f927f399..a922bf3fbe 100644
--- a/lib/stdlib/src/zip.erl
+++ b/lib/stdlib/src/zip.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -457,8 +457,7 @@ do_zip(F, Files, Options) ->
Out3 = Output({close, F}, Out2),
{ok, Out3}
catch
- C:R ->
- Stk = erlang:get_stacktrace(),
+ C:R:Stk ->
zlib:close(Z),
Output({close, F}, Out0),
erlang:raise(C, R, Stk)
diff --git a/lib/stdlib/test/Makefile b/lib/stdlib/test/Makefile
index 7b79dcf04d..712b1b92fb 100644
--- a/lib/stdlib/test/Makefile
+++ b/lib/stdlib/test/Makefile
@@ -69,6 +69,7 @@ MODULES= \
sets_test_lib \
sofs_SUITE \
stdlib_SUITE \
+ stdlib_bench_SUITE \
string_SUITE \
supervisor_1 \
supervisor_2 \
@@ -86,6 +87,8 @@ MODULES= \
timer_simple_SUITE \
unicode_SUITE \
unicode_util_SUITE \
+ uri_string_SUITE \
+ uri_string_property_test_SUITE \
win32reg_SUITE \
y2k_SUITE \
select_SUITE \
@@ -93,13 +96,12 @@ MODULES= \
random_unicode_list \
random_iolist \
error_logger_forwarder \
- maps_SUITE
+ maps_SUITE \
+ zzz_SUITE
-ERL_FILES= $(MODULES:%=%.erl)
+ERTS_MODULES= erts_test_utils
-TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-
-INSTALL_PROGS= $(TARGET_FILES)
+ERL_FILES= $(MODULES:%=%.erl) $(ERTS_MODULES:%=$(ERL_TOP)/erts/emulator/test/%.erl)
# ----------------------------------------------------
# Release directory specification
@@ -124,7 +126,7 @@ COVERFILE=stdlib.cover
# ----------------------------------------------------
make_emakefile:
- $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES) \
+ $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES) $(ERTS_MODULES) \
> $(EMAKEFILE)
tests debug opt: make_emakefile
@@ -146,9 +148,9 @@ release_spec: opt
release_tests_spec: make_emakefile
$(INSTALL_DIR) "$(RELSYSDIR)"
- $(INSTALL_DATA) stdlib.spec $(EMAKEFILE) \
+ $(INSTALL_DATA) stdlib.spec stdlib_bench.spec $(EMAKEFILE) \
$(ERL_FILES) $(COVERFILE) "$(RELSYSDIR)"
chmod -R u+w "$(RELSYSDIR)"
- @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
+ @tar cf - *_SUITE_data property_test | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/stdlib/test/array_SUITE.erl b/lib/stdlib/test/array_SUITE.erl
index 5836f275ba..df520ebb54 100644
--- a/lib/stdlib/test/array_SUITE.erl
+++ b/lib/stdlib/test/array_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -141,10 +141,10 @@ t(What) ->
io:format("Test ~p ~n",[T]),
try
?MODULE:T([])
- catch _E:_R ->
+ catch _E:_R:_S ->
Line = get(test_server_loc),
io:format("Failed ~p:~p ~p ~p~n ~p~n",
- [T,Line,_E,_R, erlang:get_stacktrace()])
+ [T,Line,_E,_R,_S])
end
end, What).
@@ -161,8 +161,8 @@ extract_tests() ->
end,
[Call(Test) || Test <- Tests],
io:format("Tests ~p~n", [Tests])
- catch _:Err ->
- io:format("Error: ~p ~p~n", [Err, erlang:get_stacktrace()])
+ catch _:Err:Stacktrace ->
+ io:format("Error: ~p ~p~n", [Err, Stacktrace])
end,
file:close(In),
file:close(Out).
diff --git a/lib/stdlib/test/base64_SUITE.erl b/lib/stdlib/test/base64_SUITE.erl
index 48b3f5f959..1fc4c3fc0e 100644
--- a/lib/stdlib/test/base64_SUITE.erl
+++ b/lib/stdlib/test/base64_SUITE.erl
@@ -97,10 +97,9 @@ base64_otp_5635(Config) when is_list(Config) ->
<<"===">> = base64:decode(base64:encode("===")),
ok.
%%-------------------------------------------------------------------------
-%% OTP-6279: Guard needed so that function fails in a correct
-%% way for faulty input, i.e. function_clause.
+%% OTP-6279: Make sure illegal characters are rejected when decoding.
base64_otp_6279(Config) when is_list(Config) ->
- {'EXIT',{function_clause, _}} = (catch base64:decode("dGVzda==a")),
+ {'EXIT',_} = (catch base64:decode("dGVzda==a")),
ok.
%%-------------------------------------------------------------------------
%% Encode and decode big binaries.
@@ -115,48 +114,61 @@ big(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
%% Make sure illegal characters are rejected when decoding.
illegal(Config) when is_list(Config) ->
- {'EXIT',{function_clause, _}} = (catch base64:decode("()")),
+ %% A few samples with different error reasons. Nothing can be
+ %% assumed about the reason for the crash.
+ {'EXIT',_} = (catch base64:decode("()")),
+ {'EXIT',_} = (catch base64:decode(<<19:8,20:8,21:8,22:8>>)),
+ {'EXIT',_} = (catch base64:decode([19,20,21,22])),
+ {'EXIT',_} = (catch base64:decode_to_string(<<19:8,20:8,21:8,22:8>>)),
+ {'EXIT',_} = (catch base64:decode_to_string([19,20,21,22])),
ok.
%%-------------------------------------------------------------------------
%% mime_decode and mime_decode_to_string have different implementations
-%% so test both with the same input separately. Both functions have
-%% the same implementation for binary/string arguments.
+%% so test both with the same input separately.
%%
%% Test base64:mime_decode/1.
mime_decode(Config) when is_list(Config) ->
+ MimeDecode = fun(In) ->
+ Out = base64:mime_decode(In),
+ Out = base64:mime_decode(binary_to_list(In))
+ end,
%% Test correct padding
- <<"one">> = base64:mime_decode(<<"b25l">>),
- <<"on">> = base64:mime_decode(<<"b24=">>),
- <<"o">> = base64:mime_decode(<<"bw==">>),
+ <<"one">> = MimeDecode(<<"b25l">>),
+ <<"on">> = MimeDecode(<<"b24=">>),
+ <<"o">> = MimeDecode(<<"bw==">>),
%% Test 1 extra padding
- <<"one">> = base64:mime_decode(<<"b25l= =">>),
- <<"on">> = base64:mime_decode(<<"b24== =">>),
- <<"o">> = base64:mime_decode(<<"bw=== =">>),
+ <<"one">> = MimeDecode(<<"b25l= =">>),
+ <<"on">> = MimeDecode(<<"b24== =">>),
+ <<"o">> = MimeDecode(<<"bw=== =">>),
%% Test 2 extra padding
- <<"one">> = base64:mime_decode(<<"b25l===">>),
- <<"on">> = base64:mime_decode(<<"b24====">>),
- <<"o">> = base64:mime_decode(<<"bw=====">>),
+ <<"one">> = MimeDecode(<<"b25l===">>),
+ <<"on">> = MimeDecode(<<"b24====">>),
+ <<"o">> = MimeDecode(<<"bw=====">>),
%% Test misc embedded padding
- <<"one">> = base64:mime_decode(<<"b2=5l===">>),
- <<"on">> = base64:mime_decode(<<"b=24====">>),
- <<"o">> = base64:mime_decode(<<"b=w=====">>),
+ <<"one">> = MimeDecode(<<"b2=5l===">>),
+ <<"on">> = MimeDecode(<<"b=24====">>),
+ <<"o">> = MimeDecode(<<"b=w=====">>),
%% Test misc white space and illegals with embedded padding
- <<"one">> = base64:mime_decode(<<" b~2=\r\n5()l===">>),
- <<"on">> = base64:mime_decode(<<"\tb =2\"¤4=¤= ==">>),
- <<"o">> = base64:mime_decode(<<"\nb=w=====">>),
+ <<"one">> = MimeDecode(<<" b~2=\r\n5()l===">>),
+ <<"on">> = MimeDecode(<<"\tb =2\"¤4=¤= ==">>),
+ <<"o">> = MimeDecode(<<"\nb=w=====">>),
%% Two pads
<<"Aladdin:open sesame">> =
- base64:mime_decode("QWxhZGRpbjpvc()GVuIHNlc2FtZQ=="),
+ MimeDecode(<<"QWxhZGRpbjpvc()GVuIHNlc2FtZQ==">>),
%% One pad to ignore, followed by more text
- <<"Hello World!!">> = base64:mime_decode(<<"SGVsb)(G8gV29ybGQ=h IQ= =">>),
+ <<"Hello World!!">> = MimeDecode(<<"SGVsb)(G8gV29ybGQ=h IQ= =">>),
%% No pad
<<"Aladdin:open sesam">> =
- base64:mime_decode("QWxhZGRpbjpvcG¤\")(VuIHNlc2Ft"),
+ MimeDecode(<<"QWxhZGRpbjpvcG¤\")(VuIHNlc2Ft">>),
%% Encoded base 64 strings may be divided by non base 64 chars.
%% In this cases whitespaces.
<<"0123456789!@#0^&*();:<>,. []{}">> =
- base64:mime_decode(
+ MimeDecode(
<<"MDEy MzQ1Njc4 \tOSFAIzBeJ \nio)(oKTs6 PD4sLi \r\nBbXXt9">>),
+ %% Zeroes
+ <<"012">> = MimeDecode(<<"\000M\000D\000E\000y=\000">>),
+ <<"o">> = MimeDecode(<<"bw==\000">>),
+ <<"o">> = MimeDecode(<<"bw=\000=">>),
ok.
%%-------------------------------------------------------------------------
@@ -165,39 +177,48 @@ mime_decode(Config) when is_list(Config) ->
%% Test base64:mime_decode_to_string/1.
mime_decode_to_string(Config) when is_list(Config) ->
+ MimeDecodeToString =
+ fun(In) ->
+ Out = base64:mime_decode_to_string(In),
+ Out = base64:mime_decode_to_string(binary_to_list(In))
+ end,
%% Test correct padding
- "one" = base64:mime_decode_to_string(<<"b25l">>),
- "on" = base64:mime_decode_to_string(<<"b24=">>),
- "o" = base64:mime_decode_to_string(<<"bw==">>),
+ "one" = MimeDecodeToString(<<"b25l">>),
+ "on" = MimeDecodeToString(<<"b24=">>),
+ "o" = MimeDecodeToString(<<"bw==">>),
%% Test 1 extra padding
- "one" = base64:mime_decode_to_string(<<"b25l= =">>),
- "on" = base64:mime_decode_to_string(<<"b24== =">>),
- "o" = base64:mime_decode_to_string(<<"bw=== =">>),
+ "one" = MimeDecodeToString(<<"b25l= =">>),
+ "on" = MimeDecodeToString(<<"b24== =">>),
+ "o" = MimeDecodeToString(<<"bw=== =">>),
%% Test 2 extra padding
- "one" = base64:mime_decode_to_string(<<"b25l===">>),
- "on" = base64:mime_decode_to_string(<<"b24====">>),
- "o" = base64:mime_decode_to_string(<<"bw=====">>),
+ "one" = MimeDecodeToString(<<"b25l===">>),
+ "on" = MimeDecodeToString(<<"b24====">>),
+ "o" = MimeDecodeToString(<<"bw=====">>),
%% Test misc embedded padding
- "one" = base64:mime_decode_to_string(<<"b2=5l===">>),
- "on" = base64:mime_decode_to_string(<<"b=24====">>),
- "o" = base64:mime_decode_to_string(<<"b=w=====">>),
+ "one" = MimeDecodeToString(<<"b2=5l===">>),
+ "on" = MimeDecodeToString(<<"b=24====">>),
+ "o" = MimeDecodeToString(<<"b=w=====">>),
%% Test misc white space and illegals with embedded padding
- "one" = base64:mime_decode_to_string(<<" b~2=\r\n5()l===">>),
- "on" = base64:mime_decode_to_string(<<"\tb =2\"¤4=¤= ==">>),
- "o" = base64:mime_decode_to_string(<<"\nb=w=====">>),
+ "one" = MimeDecodeToString(<<" b~2=\r\n5()l===">>),
+ "on" = MimeDecodeToString(<<"\tb =2\"¤4=¤= ==">>),
+ "o" = MimeDecodeToString(<<"\nb=w=====">>),
%% Two pads
"Aladdin:open sesame" =
- base64:mime_decode_to_string("QWxhZGRpbjpvc()GVuIHNlc2FtZQ=="),
+ MimeDecodeToString(<<"QWxhZGRpbjpvc()GVuIHNlc2FtZQ==">>),
%% One pad to ignore, followed by more text
- "Hello World!!" = base64:mime_decode_to_string(<<"SGVsb)(G8gV29ybGQ=h IQ= =">>),
+ "Hello World!!" = MimeDecodeToString(<<"SGVsb)(G8gV29ybGQ=h IQ= =">>),
%% No pad
"Aladdin:open sesam" =
- base64:mime_decode_to_string("QWxhZGRpbjpvcG¤\")(VuIHNlc2Ft"),
+ MimeDecodeToString(<<"QWxhZGRpbjpvcG¤\")(VuIHNlc2Ft">>),
%% Encoded base 64 strings may be divided by non base 64 chars.
%% In this cases whitespaces.
"0123456789!@#0^&*();:<>,. []{}" =
- base64:mime_decode_to_string(
+ MimeDecodeToString(
<<"MDEy MzQ1Njc4 \tOSFAIzBeJ \nio)(oKTs6 PD4sLi \r\nBbXXt9">>),
+ %% Zeroes
+ "012" = MimeDecodeToString(<<"\000M\000D\000E\000y=\000">>),
+ "o" = MimeDecodeToString(<<"bw==\000">>),
+ "o" = MimeDecodeToString(<<"bw=\000=">>),
ok.
%%-------------------------------------------------------------------------
diff --git a/lib/stdlib/test/beam_lib_SUITE.erl b/lib/stdlib/test/beam_lib_SUITE.erl
index 73219f8fd8..4b2694320e 100644
--- a/lib/stdlib/test/beam_lib_SUITE.erl
+++ b/lib/stdlib/test/beam_lib_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -35,7 +35,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
- normal/1, error/1, cmp/1, cmp_literals/1, strip/1, otp_6711/1,
+ normal/1, error/1, cmp/1, cmp_literals/1, strip/1, strip_add_chunks/1, otp_6711/1,
building/1, md5/1, encrypted_abstr/1, encrypted_abstr_file/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
@@ -45,7 +45,7 @@ suite() ->
{timetrap,{minutes,2}}].
all() ->
- [error, normal, cmp, cmp_literals, strip, otp_6711,
+ [error, normal, cmp, cmp_literals, strip, strip_add_chunks, otp_6711,
building, md5, encrypted_abstr, encrypted_abstr_file].
groups() ->
@@ -78,7 +78,7 @@ normal(Conf) when is_list(Conf) ->
BeamFile = Simple ++ ".beam",
simple_file(Source),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
P0 = pps(),
do_normal(Source, PrivDir, BeamFile, []),
@@ -95,7 +95,7 @@ normal(Conf) when is_list(Conf) ->
file:delete(BeamFile),
file:delete(Source),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
true = (P0 == pps()),
ok.
@@ -173,7 +173,7 @@ error(Conf) when is_list(Conf) ->
WrongFile = Simple ++ "foo.beam",
simple_file(Source),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
P0 = pps(),
{ok,_} = compile:file(Source, [{outdir,PrivDir},debug_info]),
ACopy = filename:join(PrivDir, "a_copy.beam"),
@@ -213,7 +213,7 @@ error(Conf) when is_list(Conf) ->
%% we have eliminated them.
ok = file:write_file(BeamFile, <<"FOR1",5:32,"BEAMfel">>),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
true = (P0 == pps()),
file:delete(Source),
file:delete(WrongFile),
@@ -273,7 +273,7 @@ cmp(Conf) when is_list(Conf) ->
{Source2D1, BeamFile2D1} = make_beam(Dir1, simple2, concat),
{SourceD2, BeamFileD2} = make_beam(Dir2, simple, concat),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
P0 = pps(),
%% cmp
@@ -300,7 +300,7 @@ cmp(Conf) when is_list(Conf) ->
ver(not_a_directory, beam_lib:diff_dirs(foo, bar)),
true = (P0 == pps()),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
delete_files([SourceD1, BeamFileD1, Source2D1,
BeamFile2D1, SourceD2, BeamFileD2]),
@@ -321,7 +321,7 @@ cmp_literals(Conf) when is_list(Conf) ->
{SourceD1, BeamFileD1} = make_beam(Dir1, simple, constant),
{SourceD2, BeamFileD2} = make_beam(Dir2, simple, constant2),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
P0 = pps(),
%% cmp
@@ -334,7 +334,7 @@ cmp_literals(Conf) when is_list(Conf) ->
ver(chunks_different, beam_lib:cmp(B1, B2)),
true = (P0 == pps()),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
delete_files([SourceD1, BeamFileD1, SourceD2, BeamFileD2]),
@@ -351,7 +351,7 @@ strip(Conf) when is_list(Conf) ->
{Source4D1, BeamFile4D1} = make_beam(PrivDir, constant, constant),
{Source5D1, BeamFile5D1} = make_beam(PrivDir, lines, lines),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
P0 = pps(),
%% strip binary
@@ -392,7 +392,7 @@ strip(Conf) when is_list(Conf) ->
(catch lines:t(atom)),
true = (P0 == pps()),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
delete_files([SourceD1, BeamFileD1,
Source2D1, BeamFile2D1,
@@ -401,6 +401,69 @@ strip(Conf) when is_list(Conf) ->
Source5D1, BeamFile5D1]),
ok.
+strip_add_chunks(Conf) when is_list(Conf) ->
+ PrivDir = ?privdir,
+ {SourceD1, BeamFileD1} = make_beam(PrivDir, simple, member),
+ {Source2D1, BeamFile2D1} = make_beam(PrivDir, simple2, concat),
+ {Source3D1, BeamFile3D1} = make_beam(PrivDir, make_fun, make_fun),
+ {Source4D1, BeamFile4D1} = make_beam(PrivDir, constant, constant),
+ {Source5D1, BeamFile5D1} = make_beam(PrivDir, lines, lines),
+
+ NoOfTables = erlang:system_info(ets_count),
+ P0 = pps(),
+
+ %% strip binary
+ verify(not_a_beam_file, beam_lib:strip(<<>>)),
+ {ok, B1} = file:read_file(BeamFileD1),
+ {ok, {simple, NB1}} = beam_lib:strip(B1),
+
+ BId1 = chunk_ids(B1),
+ NBId1 = chunk_ids(NB1),
+ true = length(BId1) > length(NBId1),
+ compare_chunks(B1, NB1, NBId1),
+
+ %% Keep all the extra chunks
+ ExtraChunks = ["Abst" , "Dbgi" , "Attr" , "CInf" , "LocT" , "Atom" ],
+ {ok, {simple, AB1}} = beam_lib:strip(B1, ExtraChunks),
+ ABId1 = chunk_ids(AB1),
+ true = length(BId1) == length(ABId1),
+ compare_chunks(B1, AB1, ABId1),
+
+ %% strip file - Keep extra chunks
+ verify(file_error, beam_lib:strip(foo)),
+ {ok, {simple, _}} = beam_lib:strip(BeamFileD1, ExtraChunks),
+ compare_chunks(B1, BeamFileD1, ABId1),
+
+ %% strip_files
+ {ok, B2} = file:read_file(BeamFile2D1),
+ {ok, [{simple,_},{simple2,_}]} = beam_lib:strip_files([B1, B2], ExtraChunks),
+ {ok, [{simple,_},{simple2,_},{make_fun,_},{constant,_}]} =
+ beam_lib:strip_files([BeamFileD1, BeamFile2D1, BeamFile3D1, BeamFile4D1], ExtraChunks),
+
+ %% check that each module can be loaded.
+ {module, simple} = code:load_abs(filename:rootname(BeamFileD1)),
+ {module, simple2} = code:load_abs(filename:rootname(BeamFile2D1)),
+ {module, make_fun} = code:load_abs(filename:rootname(BeamFile3D1)),
+ {module, constant} = code:load_abs(filename:rootname(BeamFile4D1)),
+
+ %% check that line number information is still present after stripping
+ {module, lines} = code:load_abs(filename:rootname(BeamFile5D1)),
+ {'EXIT',{badarith,[{lines,t,1,Info}|_]}} = (catch lines:t(atom)),
+ false = code:purge(lines),
+ true = code:delete(lines),
+ {ok, {lines,BeamFile5D1}} = beam_lib:strip(BeamFile5D1),
+ {module, lines} = code:load_abs(filename:rootname(BeamFile5D1)),
+ {'EXIT',{badarith,[{lines,t,1,Info}|_]}} = (catch lines:t(atom)),
+
+ true = (P0 == pps()),
+ NoOfTables = erlang:system_info(ets_count),
+
+ delete_files([SourceD1, BeamFileD1,
+ Source2D1, BeamFile2D1,
+ Source3D1, BeamFile3D1,
+ Source4D1, BeamFile4D1,
+ Source5D1, BeamFile5D1]),
+ ok.
otp_6711(Conf) when is_list(Conf) ->
{'EXIT',{function_clause,_}} = (catch {a, beam_lib:info(3)}),
@@ -457,7 +520,7 @@ building(Conf) when is_list(Conf) ->
{SourceD1, BeamFileD1} = make_beam(Dir1, building, member),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
P0 = pps(),
%% read all chunks
@@ -487,7 +550,7 @@ building(Conf) when is_list(Conf) ->
end, ChunkIds),
true = (P0 == pps()),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
delete_files([SourceD1, BeamFileD1, BeamFileD2]),
file:del_dir(Dir1),
@@ -535,7 +598,7 @@ encrypted_abstr_1(Conf) ->
%% Avoid getting an extra port when crypto starts erl_ddll.
erl_ddll:start(),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
P0 = pps(),
Key = "#a_crypto_key",
@@ -549,7 +612,7 @@ encrypted_abstr_1(Conf) ->
ok = crypto:stop(), %To get rid of extra ets tables.
file:delete(BeamFile),
file:delete(Source),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
true = (P0 == pps()),
ok.
@@ -658,7 +721,7 @@ encrypted_abstr_file_1(Conf) ->
%% Avoid getting an extra port when crypto starts erl_ddll.
erl_ddll:start(),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
P0 = pps(),
Key = "Long And niCe 99Krypto Key",
@@ -676,7 +739,7 @@ encrypted_abstr_file_1(Conf) ->
file:delete(filename:join(PrivDir, ".erlang.crypt")),
file:delete(BeamFile),
file:delete(Source),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
true = (P0 == pps()),
ok.
@@ -729,6 +792,7 @@ make_beam(Dir, Module, F) ->
FileBase = filename:join(Dir, atom_to_list(Module)),
Source = FileBase ++ ".erl",
BeamFile = FileBase ++ ".beam",
+ file:delete(BeamFile),
simple_file(Source, Module, F),
{ok, _} = compile:file(Source, [{outdir,Dir}, debug_info, report]),
{Source, BeamFile}.
diff --git a/lib/stdlib/test/binary_module_SUITE.erl b/lib/stdlib/test/binary_module_SUITE.erl
index c5cfea5e9e..9b2033ec4a 100644
--- a/lib/stdlib/test/binary_module_SUITE.erl
+++ b/lib/stdlib/test/binary_module_SUITE.erl
@@ -22,7 +22,8 @@
-export([all/0, suite/0,
interesting/1,scope_return/1,random_ref_comp/1,random_ref_sr_comp/1,
random_ref_fla_comp/1,parts/1, bin_to_list/1, list_to_bin/1,
- copy/1, referenced/1,guard/1,encode_decode/1,badargs/1,longest_common_trap/1]).
+ copy/1, referenced/1,guard/1,encode_decode/1,badargs/1,longest_common_trap/1,
+ check_no_invalid_read_bug/1]).
-export([random_number/1, make_unaligned/1]).
@@ -36,7 +37,7 @@ all() ->
[scope_return,interesting, random_ref_fla_comp, random_ref_sr_comp,
random_ref_comp, parts, bin_to_list, list_to_bin, copy,
referenced, guard, encode_decode, badargs,
- longest_common_trap].
+ longest_common_trap, check_no_invalid_read_bug].
-define(MASK_ERROR(EXPR),mask_error((catch (EXPR)))).
@@ -754,8 +755,9 @@ list_to_bin(Config) when is_list(Config) ->
copy(Config) when is_list(Config) ->
<<1,2,3>> = binary:copy(<<1,2,3>>),
RS = random_string({1,10000}),
- RS = RS2 = binary:copy(RS),
- false = erts_debug:same(RS,RS2),
+ RS2 = binary:copy(RS),
+ true = RS =:= RS2,
+ false = erts_debug:same(RS, RS2),
<<>> = ?MASK_ERROR(binary:copy(<<1,2,3>>,0)),
badarg = ?MASK_ERROR(binary:copy(<<1,2,3:3>>,2)),
badarg = ?MASK_ERROR(binary:copy([],0)),
@@ -1361,3 +1363,13 @@ make_unaligned2(Bin0) when is_binary(Bin0) ->
Bin.
id(I) -> I.
+
+check_no_invalid_read_bug(Config) when is_list(Config) ->
+ check_no_invalid_read_bug(24);
+check_no_invalid_read_bug(60) ->
+ ok;
+check_no_invalid_read_bug(I) ->
+ N = 1 bsl I,
+ binary:encode_unsigned(N+N),
+ binary:encode_unsigned(N+N, little),
+ check_no_invalid_read_bug(I+1).
diff --git a/lib/stdlib/test/c_SUITE.erl b/lib/stdlib/test/c_SUITE.erl
index f01988478c..bd84cdd228 100644
--- a/lib/stdlib/test/c_SUITE.erl
+++ b/lib/stdlib/test/c_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/test/calendar_SUITE.erl b/lib/stdlib/test/calendar_SUITE.erl
index 20053dfe54..224c0d5625 100644
--- a/lib/stdlib/test/calendar_SUITE.erl
+++ b/lib/stdlib/test/calendar_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,23 +24,29 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
gregorian_days/1,
+ big_gregorian_days/1,
gregorian_seconds/1,
day_of_the_week/1,
day_of_the_week_calibrate/1,
leap_years/1,
last_day_of_the_month/1,
local_time_to_universal_time_dst/1,
- iso_week_number/1]).
+ iso_week_number/1,
+ system_time/1, rfc3339/1]).
-define(START_YEAR, 1947).
-define(END_YEAR, 2012).
+-define(BIG_START_YEAR, 20000000).
+-define(BIG_END_YEAR, 20000020).
+
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[gregorian_days, gregorian_seconds, day_of_the_week,
day_of_the_week_calibrate, leap_years,
- last_day_of_the_month, local_time_to_universal_time_dst, iso_week_number].
+ last_day_of_the_month, local_time_to_universal_time_dst,
+ iso_week_number, system_time, rfc3339, big_gregorian_days].
groups() ->
[].
@@ -65,6 +71,14 @@ gregorian_days(Config) when is_list(Config) ->
MaxDays = calendar:date_to_gregorian_days({?END_YEAR, 1, 1}),
check_gregorian_days(Days, MaxDays).
+%% Tests that date_to_gregorian_days and gregorian_days_to_date
+%% are each others inverses from ?BIG_START_YEAR-01-01 up to ?BIG_END_YEAR-01-01.
+%% At the same time valid_date is tested.
+big_gregorian_days(Config) when is_list(Config) ->
+ Days = calendar:date_to_gregorian_days({?BIG_START_YEAR, 1, 1}),
+ MaxDays = calendar:date_to_gregorian_days({?BIG_END_YEAR, 1, 1}),
+ check_gregorian_days(Days, MaxDays).
+
%% Tests that datetime_to_gregorian_seconds and
%% gregorian_seconds_to_date are each others inverses for a sampled
%% number of seconds from ?START_YEAR-01-01 up to ?END_YEAR-01-01: We check
@@ -157,10 +171,167 @@ local_time_to_universal_time_dst_x(Config) when is_list(Config) ->
iso_week_number(Config) when is_list(Config) ->
check_iso_week_number().
+system_time(Config) when is_list(Config) ->
+ EpochDate = {{1970,1,1}, {0,0,0}},
+ Epoch = calendar:datetime_to_gregorian_seconds(EpochDate),
+ Y0 = {{0,1,1},{0,0,0}},
+
+ EpochDate = calendar:system_time_to_universal_time(0, second),
+ 0 = calendar:datetime_to_gregorian_seconds(Y0),
+ Y0 = calendar:system_time_to_universal_time(-Epoch, second),
+
+ T = erlang:system_time(second),
+ UDate = calendar:system_time_to_universal_time(T, second),
+ LDate = erlang:universaltime_to_localtime(UDate),
+ LDate = calendar:system_time_to_local_time(T, second),
+
+ ok.
+
+rfc3339(Config) when is_list(Config) ->
+ Ms = [{unit, millisecond}],
+ Mys = [{unit, microsecond}],
+ Ns = [{unit, nanosecond}],
+ S = [{unit, second}],
+ D = [{time_designator, $\s}],
+ Z = [{offset, "Z"}],
+
+ "1985-04-12T23:20:50.520Z" = test_parse("1985-04-12T23:20:50.52Z", Ms),
+ "1985-04-12T23:20:50.520Z" = test_parse("1985-04-12t23:20:50.52z", Ms),
+ "1985-04-12T21:20:50.520Z" =
+ test_parse("1985-04-12T23:20:50.52+02:00", Ms),
+ "1985-04-12T23:20:50Z" = test_parse("1985-04-12T23:20:50.52Z", S),
+ "1985-04-12T23:20:50.520Z" = test_parse("1985-04-12T23:20:50.52Z", Ms),
+ "1985-04-12T23:20:50.520000Z" =
+ test_parse("1985-04-12t23:20:50.52z", Mys),
+ "1985-04-12 21:20:50.520000000Z" =
+ test_parse("1985-04-12 23:20:50.52+02:00", Ns++D),
+ "1985-04-12T23:20:50Z" = test_parse("1985-04-12T23:20:50.52Z"),
+ "1996-12-20T00:39:57Z" = test_parse("1996-12-19T16:39:57-08:00"),
+ "1991-01-01T00:00:00Z" = test_parse("1990-12-31T23:59:60Z"),
+ "1991-01-01T08:00:00Z" = test_parse("1990-12-31T23:59:60-08:00"),
+
+ "1996-12-20T00:39:57Z" = test_parse("1996-12-19T16:39:57-08:00"),
+ %% The leap second is not handled:
+ "1991-01-01T00:00:00Z" = test_parse("1990-12-31T23:59:60Z"),
+
+ "9999-12-31T23:59:59Z" = do_format_z(253402300799, []),
+ "9999-12-31T23:59:59.999Z" = do_format_z(253402300799*1000+999, Ms),
+ "9999-12-31T23:59:59.999999Z" =
+ do_format_z(253402300799*1000000+999999, Mys),
+ "9999-12-31T23:59:59.999999999Z" =
+ do_format_z(253402300799*1000000000+999999999, Ns),
+ {'EXIT', _} = (catch do_format_z(253402300799+1, [])),
+ {'EXIT', _} = (catch do_parse("9999-12-31T23:59:60Z", [])),
+ {'EXIT', _} = (catch do_format_z(253402300799*1000000000+999999999+1, Ns)),
+ 253402300799 = do_parse("9999-12-31T23:59:59Z", []),
+
+ "0000-01-01T00:00:00Z" = test_parse("0000-01-01T00:00:00.0+00:00"),
+ "9999-12-31T00:00:00Z" = test_parse("9999-12-31T00:00:00.0+00:00"),
+ "1584-03-04T00:00:00Z" = test_parse("1584-03-04T00:00:00.0+00:00"),
+ "1900-01-01T00:00:00Z" = test_parse("1900-01-01T00:00:00.0+00:00"),
+ "2016-01-24T00:00:00Z" = test_parse("2016-01-24T00:00:00.0+00:00"),
+ "1970-01-01T00:00:00Z" = test_parse("1970-01-01T00:00:00Z"),
+ "1970-01-02T00:00:00Z" = test_parse("1970-01-01T23:59:60Z"),
+ "1970-01-02T00:00:00Z" = test_parse("1970-01-01T23:59:60.5Z"),
+ "1970-01-02T00:00:00Z" = test_parse("1970-01-01T23:59:60.55Z"),
+ "1970-01-02T00:00:00.550Z" = test_parse("1970-01-01T23:59:60.55Z", Ms),
+ "1970-01-02T00:00:00.550000Z" =
+ test_parse("1970-01-01T23:59:60.55Z", Mys),
+ "1970-01-02T00:00:00.550000000Z" =
+ test_parse("1970-01-01T23:59:60.55Z", Ns),
+ "1970-01-02T00:00:00.999999Z" =
+ test_parse("1970-01-01T23:59:60.999999Z", Mys),
+ "1970-01-02T00:00:01.000Z" =
+ test_parse("1970-01-01T23:59:60.999999Z", Ms),
+ "1970-01-01T00:00:00Z" = test_parse("1970-01-01T00:00:00+00:00"),
+ "1970-01-01T00:00:00Z" = test_parse("1970-01-01T00:00:00-00:00"),
+ "1969-12-31T00:01:00Z" = test_parse("1970-01-01T00:00:00+23:59"),
+ "1918-11-11T09:00:00.000000Z" =
+ test_parse("1918-11-11T11:00:00+02:00", Mys),
+ "1970-01-01T00:00:00.000001Z" =
+ test_parse("1970-01-01T00:00:00.000001Z", Mys),
+
+ test_time(erlang:system_time(second), []),
+ test_time(erlang:system_time(second), Z),
+ test_time(erlang:system_time(second), Z ++ S),
+ test_time(erlang:system_time(second), [{offset, "+02:20"}]),
+ test_time(erlang:system_time(millisecond), Ms),
+ test_time(erlang:system_time(microsecond), Mys++[{offset, "-02:20"}]),
+
+ 946720800 = TO = do_parse("2000-01-01 10:00:00Z", []),
+ Str = "2000-01-01T10:02:00+00:02",
+ Str = do_format(TO, [{offset, 120}]),
+ "2000-01-01T10:02:00.000+00:02" =
+ do_format(TO * 1000, [{offset, 120 * 1000}]++Ms),
+ "2000-01-01T10:02:00.000000+00:02" =
+ do_format(TO * 1000 * 1000, [{offset, 120 * 1000 * 1000}]++Mys),
+ "2000-01-01T10:02:00.000000000+00:02" =
+ do_format(TO * 1000 * 1000 * 1000,
+ [{offset, 120 * 1000 * 1000 * 1000}]++Ns),
+
+ NStr = "2000-01-01T09:58:00-00:02",
+ NStr = do_format(TO, [{offset, -120}]),
+ "2000-01-01T09:58:00.000-00:02" =
+ do_format(TO * 1000, [{offset, -120 * 1000}]++Ms),
+ "2000-01-01T09:58:00.000000-00:02" =
+ do_format(TO * 1000 * 1000, [{offset, -120 * 1000 * 1000}]++Mys),
+ "2000-01-01T09:58:00.000000000-00:02" =
+ do_format(TO * 1000 * 1000 * 1000,
+ [{offset, -120 * 1000 * 1000 * 1000}]++Ns),
+
+ 543210000 = do_parse("1970-01-01T00:00:00.54321Z", Ns),
+ 54321000 = do_parse("1970-01-01T00:00:00.054321Z", Ns),
+ 543210 = do_parse("1970-01-01T00:00:00.54321Z", Mys),
+ 543 = do_parse("1970-01-01T00:00:00.54321Z", Ms),
+ 0 = do_parse("1970-01-01T00:00:00.000001Z", Ms),
+ 1 = do_parse("1970-01-01T00:00:00.000001Z", Mys),
+ 1000 = do_parse("1970-01-01T00:00:00.000001Z", Ns),
+ 0 = do_parse("1970-01-01Q00:00:00.00049Z", Ms),
+ 1 = do_parse("1970-01-01Q00:00:00.0005Z", Ms),
+ 6543210 = do_parse("1970-01-01T00:00:06.54321Z", Mys),
+ 298815132000000 = do_parse("1979-06-21T12:12:12Z", Mys),
+ -1613826000000000 = do_parse("1918-11-11T11:00:00Z", Mys),
+ -1613833200000000 = do_parse("1918-11-11T11:00:00+02:00", Mys),
+ -1613833200000000 = do_parse("1918-11-11T09:00:00Z", Mys),
+
+ "1970-01-01T00:00:00.000000Z" = do_format_z(0, Mys),
+ "1970-01-01T00:00:01Z" = do_format_z(1, S),
+ "1970-01-01T00:00:00.001Z" = do_format_z(1, Ms),
+ "1970-01-01T00:00:00.000001Z" = do_format_z(1, Mys),
+ "1970-01-01T00:00:00.000000001Z" = do_format_z(1, Ns),
+ "1970-01-01T00:00:01.000000Z" = do_format_z(1000000, Mys),
+ "1970-01-01T00:00:00.543210Z" = do_format_z(543210, Mys),
+ "1970-01-01T00:00:00.543Z" = do_format_z(543, Ms),
+ "1970-01-01T00:00:00.543210000Z" = do_format_z(543210000, Ns),
+ "1970-01-01T00:00:06.543210Z" = do_format_z(6543210, Mys),
+ "1979-06-21T12:12:12.000000Z" = do_format_z(298815132000000, Mys),
+ "1918-11-11T13:00:00.000000Z" = do_format_z(-1613818800000000, Mys),
+ ok.
+
%%
%% LOCAL FUNCTIONS
%%
+test_parse(String) ->
+ test_parse(String, []).
+
+test_parse(String, Options) ->
+ T = do_parse(String, Options),
+ calendar:system_time_to_rfc3339(T, [{offset, "Z"} | Options]).
+
+do_parse(String, Options) ->
+ calendar:rfc3339_to_system_time(String, Options).
+
+test_time(Time, Options) ->
+ F = calendar:system_time_to_rfc3339(Time, Options),
+ Time = calendar:rfc3339_to_system_time(F, Options).
+
+do_format_z(Time, Options) ->
+ do_format(Time, [{offset, "Z"}|Options]).
+
+do_format(Time, Options) ->
+ calendar:system_time_to_rfc3339(Time, Options).
+
%% check_gregorian_days
%%
check_gregorian_days(Days, MaxDays) when Days < MaxDays ->
diff --git a/lib/stdlib/test/dets_SUITE.erl b/lib/stdlib/test/dets_SUITE.erl
index d667bd82a2..65977a764a 100644
--- a/lib/stdlib/test/dets_SUITE.erl
+++ b/lib/stdlib/test/dets_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -3275,16 +3275,16 @@ otp_8856(Config) when is_list(Config) ->
{ok, _} = dets:open_file(Tab, [{type, bag}, {file, File}]),
spawn(fun()-> Me ! {1, dets:insert(Tab, [])} end),
spawn(fun()-> Me ! {2, dets:insert_new(Tab, [])} end),
- ok = dets:close(Tab),
receive {1, ok} -> ok end,
receive {2, true} -> ok end,
+ ok = dets:close(Tab),
file:delete(File),
{ok, _} = dets:open_file(Tab, [{type, set}, {file, File}]),
spawn(fun() -> dets:delete(Tab, 0) end),
spawn(fun() -> Me ! {3, dets:insert_new(Tab, {0,0})} end),
- ok = dets:close(Tab),
receive {3, true} -> ok end,
+ ok = dets:close(Tab),
file:delete(File),
ok.
@@ -3417,6 +3417,7 @@ otp_11709(Config) when is_list(Config) ->
ok.
%% OTP-13229. open_file() exits with badarg when given binary file name.
+%% Also OTP-15253.
otp_13229(_Config) ->
F = <<"binfile.tab">>,
try dets:open_file(name, [{file, F}]) of
@@ -3425,6 +3426,20 @@ otp_13229(_Config) ->
catch
error:badarg ->
ok
+ end,
+ try dets:open_file(F, []) of % OTP-15253
+ R2 ->
+ exit({open_succeeded, R2})
+ catch
+ error:badarg ->
+ ok
+ end,
+ try dets:open_file(F) of
+ R3 ->
+ exit({open_succeeded, R3})
+ catch
+ error:badarg ->
+ ok
end.
%% OTP-13260. Race when opening a table.
diff --git a/lib/stdlib/test/epp_SUITE.erl b/lib/stdlib/test/epp_SUITE.erl
index 9123bf2f28..a90beed4f3 100644
--- a/lib/stdlib/test/epp_SUITE.erl
+++ b/lib/stdlib/test/epp_SUITE.erl
@@ -28,7 +28,8 @@
otp_8130/1, overload_mac/1, otp_8388/1, otp_8470/1,
otp_8562/1, otp_8665/1, otp_8911/1, otp_10302/1, otp_10820/1,
otp_11728/1, encoding/1, extends/1, function_macro/1,
- test_error/1, test_warning/1, otp_14285/1]).
+ test_error/1, test_warning/1, otp_14285/1,
+ test_if/1,source_name/1]).
-export([epp_parse_erl_form/2]).
@@ -69,7 +70,7 @@ all() ->
overload_mac, otp_8388, otp_8470, otp_8562,
otp_8665, otp_8911, otp_10302, otp_10820, otp_11728,
encoding, extends, function_macro, test_error, test_warning,
- otp_14285].
+ otp_14285, test_if, source_name].
groups() ->
[{upcase_mac, [], [upcase_mac_1, upcase_mac_2]},
@@ -799,7 +800,8 @@ otp_8130(Config) when is_list(Config) ->
PreDefMacs = macs(Epp),
['BASE_MODULE','BASE_MODULE_STRING','BEAM','FILE',
'FUNCTION_ARITY','FUNCTION_NAME',
- 'LINE','MACHINE','MODULE','MODULE_STRING'] = PreDefMacs,
+ 'LINE','MACHINE','MODULE','MODULE_STRING',
+ 'OTP_RELEASE'] = PreDefMacs,
{ok,[{'-',_},{atom,_,file}|_]} = epp:scan_erl_form(Epp),
{ok,[{'-',_},{atom,_,module}|_]} = epp:scan_erl_form(Epp),
{ok,[{atom,_,t}|_]} = epp:scan_erl_form(Epp),
@@ -952,27 +954,7 @@ ifdef(Config) ->
{define_c5,
<<"-\ndefine a.\n">>,
- {errors,[{{2,1},epp,{bad,define}}],[]}},
-
- {define_c6,
- <<"\n-if.\n"
- "-endif.\n">>,
- {errors,[{{2,2},epp,{'NYI','if'}}],[]}},
-
- {define_c7,
- <<"-ifndef(a).\n"
- "-elif.\n"
- "-endif.\n">>,
- {errors,[{{2,2},epp,{'NYI',elif}}],[]}},
-
- {define_c7,
- <<"-ifndef(a).\n"
- "-if.\n"
- "-elif.\n"
- "-endif.\n"
- "-endif.\n"
- "t() -> a.\n">>,
- {errors,[{{2,2},epp,{'NYI','if'}}],[]}}
+ {errors,[{{2,1},epp,{bad,define}}],[]}}
],
[] = compile(Config, Cs),
@@ -1117,6 +1099,147 @@ test_warning(Config) ->
[] = compile(Config, Cs),
ok.
+%% OTP-12847: Test the -if and -elif directives and the built-in
+%% function defined(Symbol).
+test_if(Config) ->
+ Cs = [{if_1c,
+ <<"-if.\n"
+ "-endif.\n"
+ "-if no_parentheses.\n"
+ "-endif.\n"
+ "-if(syntax error.\n"
+ "-endif.\n"
+ "-if(true).\n"
+ "-if(a+3).\n"
+ "syntax error not triggered here.\n"
+ "-endif.\n">>,
+ {errors,[{1,epp,{bad,'if'}},
+ {3,epp,{bad,'if'}},
+ {5,erl_parse,["syntax error before: ","error"]},
+ {11,epp,{illegal,"unterminated",'if'}}],
+ []}},
+
+ {if_2c, %Bad guard expressions.
+ <<"-if(is_list(integer_to_list(42))).\n" %Not guard BIF.
+ "-endif.\n"
+ "-if(begin true end).\n"
+ "-endif.\n">>,
+ {errors,[{1,epp,{bad,'if'}},
+ {3,epp,{bad,'if'}}],
+ []}},
+
+ {if_3c, %Invalid use of defined/1.
+ <<"-if defined(42).\n"
+ "-endif.\n">>,
+ {errors,[{1,epp,{bad,'if'}}],[]}},
+
+ {if_4c,
+ <<"-elif OTP_RELEASE > 18.\n">>,
+ {errors,[{1,epp,{illegal,"unbalanced",'elif'}}],[]}},
+
+ {if_5c,
+ <<"-ifdef(not_defined_today).\n"
+ "-else.\n"
+ "-elif OTP_RELEASE > 18.\n"
+ "-endif.\n">>,
+ {errors,[{3,epp,{illegal,"unbalanced",'elif'}}],[]}},
+
+ {if_6c,
+ <<"-if(defined(OTP_RELEASE)).\n"
+ "-else.\n"
+ "-elif(true).\n"
+ "-endif.\n">>,
+ {errors,[{3,epp,elif_after_else}],[]}},
+
+ {if_7c,
+ <<"-if(begin true end).\n" %Not a guard expression.
+ "-endif.\n">>,
+ {errors,[{1,epp,{bad,'if'}}],[]}}
+
+ ],
+ [] = compile(Config, Cs),
+
+ Ts = [{if_1,
+ <<"-if(?OTP_RELEASE > 18).\n"
+ "t() -> ok.\n"
+ "-else.\n"
+ "a bug.\n"
+ "-endif.\n">>,
+ ok},
+
+ {if_2,
+ <<"-if(false).\n"
+ "a bug.\n"
+ "-elif(?OTP_RELEASE > 18).\n"
+ "t() -> ok.\n"
+ "-else.\n"
+ "a bug.\n"
+ "-endif.\n">>,
+ ok},
+
+ {if_3,
+ <<"-if(true).\n"
+ "t() -> ok.\n"
+ "-elif(?OTP_RELEASE > 18).\n"
+ "a bug.\n"
+ "-else.\n"
+ "a bug.\n"
+ "-endif.\n">>,
+ ok},
+
+ {if_4,
+ <<"-define(a, 1).\n"
+ "-if(defined(a) andalso defined(OTP_RELEASE)).\n"
+ "t() -> ok.\n"
+ "-else.\n"
+ "a bug.\n"
+ "-endif.\n">>,
+ ok},
+
+ {if_5,
+ <<"-if(defined(a)).\n"
+ "a bug.\n"
+ "-else.\n"
+ "t() -> ok.\n"
+ "-endif.\n">>,
+ ok},
+
+ {if_6,
+ <<"-if(defined(not_defined_today)).\n"
+ " -if(true).\n"
+ " bug1.\n"
+ " -elif(true).\n"
+ " bug2.\n"
+ " -elif(true).\n"
+ " bug3.\n"
+ " -else.\n"
+ " bug4.\n"
+ " -endif.\n"
+ "-else.\n"
+ "t() -> ok.\n"
+ "-endif.\n">>,
+ ok},
+
+ {if_7,
+ <<"-if(not_builtin()).\n"
+ "a bug.\n"
+ "-else.\n"
+ "t() -> ok.\n"
+ "-endif.\n">>,
+ ok},
+
+ {if_8,
+ <<"-if(42).\n" %Not boolean.
+ "a bug.\n"
+ "-else.\n"
+ "t() -> ok.\n"
+ "-endif.\n">>,
+ ok}
+ ],
+ [] = run(Config, Ts),
+
+ ok.
+
%% Advanced test on overloading macros.
overload_mac(Config) when is_list(Config) ->
Cs = [
@@ -1249,7 +1372,7 @@ otp_8562(Config) when is_list(Config) ->
otp_8911(Config) when is_list(Config) ->
case test_server:is_cover() of
true ->
- {skip, "Testing cover, so can not run when cover is already running"};
+ {skip, "Testing cover, so cannot run when cover is already running"};
false ->
do_otp_8911(Config)
end.
@@ -1579,6 +1702,18 @@ function_macro(Config) ->
ok.
+source_name(Config) when is_list(Config) ->
+ DataDir = proplists:get_value(data_dir, Config),
+ File = filename:join(DataDir, "source_name.erl"),
+
+ source_name_1(File, "/test/gurka.erl"),
+ source_name_1(File, "gaffel.erl"),
+
+ ok.
+
+source_name_1(File, Expected) ->
+ Res = epp:parse_file(File, [{source_name, Expected}]),
+ {ok, [{attribute,_,file,{Expected,_}} | _Forms]} = Res.
check(Config, Tests) ->
eval_tests(Config, fun check_test/2, Tests).
diff --git a/lib/stdlib/test/epp_SUITE_data/source_name.erl b/lib/stdlib/test/epp_SUITE_data/source_name.erl
new file mode 100644
index 0000000000..71ad2dddb9
--- /dev/null
+++ b/lib/stdlib/test/epp_SUITE_data/source_name.erl
@@ -0,0 +1,27 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(source_name).
+-export([ok/0]).
+
+%% Changing source name should not affect headers
+-include("bar.hrl").
+
+ok() -> ok.
diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl
index c3ef4eb051..2436c8091c 100644
--- a/lib/stdlib/test/erl_eval_SUITE.erl
+++ b/lib/stdlib/test/erl_eval_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -41,12 +41,14 @@
otp_8133/1,
otp_10622/1,
otp_13228/1,
+ otp_14826/1,
funs/1,
try_catch/1,
eval_expr_5/1,
zero_width/1,
eep37/1,
- eep43/1]).
+ eep43/1,
+ otp_15035/1]).
%%
%% Define to run outside of test server
@@ -57,6 +59,7 @@
-export([count_down/2, count_down_fun/0, do_apply/2,
local_func/3, local_func_value/2]).
+-export([simple/0]).
-ifdef(STANDALONE).
-define(config(A,B),config(A,B)).
@@ -83,9 +86,9 @@ all() ->
pattern_expr, match_bin, guard_3, guard_4, guard_5, lc,
simple_cases, unary_plus, apply_atom, otp_5269,
otp_6539, otp_6543, otp_6787, otp_6977, otp_7550,
- otp_8133, otp_10622, otp_13228,
+ otp_8133, otp_10622, otp_13228, otp_14826,
funs, try_catch, eval_expr_5, zero_width,
- eep37, eep43].
+ eep37, eep43, otp_15035].
groups() ->
[].
@@ -988,6 +991,183 @@ otp_13228(_Config) ->
EFH = {value, fun({io, fwrite}, [atom]) -> io_fwrite end},
{value, worked, []} = parse_and_run("foo(io:fwrite(atom)).", LFH, EFH).
+%% OTP-14826: more accurate stacktrace.
+otp_14826(_Config) ->
+ backtrace_check("fun(P) when is_pid(P) -> true end(a).",
+ function_clause,
+ [{erl_eval,'-inside-an-interpreted-fun-',[a],[]},
+ {erl_eval,eval_fun,6},
+ ?MODULE]),
+ backtrace_check("B.",
+ {unbound_var, 'B'},
+ [{erl_eval,expr,2}, ?MODULE]),
+ backtrace_check("B.",
+ {unbound, 'B'},
+ [{erl_eval,expr,5}, ?MODULE],
+ none, none),
+ backtrace_check("1/0.",
+ badarith,
+ [{erlang,'/',[1,0],[]},
+ {erl_eval,do_apply,6}]),
+ backtrace_catch("catch 1/0.",
+ badarith,
+ [{erlang,'/',[1,0],[]},
+ {erl_eval,do_apply,6}]),
+ check(fun() -> catch exit(foo) end,
+ "catch exit(foo).",
+ {'EXIT', foo}),
+ check(fun() -> catch throw(foo) end,
+ "catch throw(foo).",
+ foo),
+ backtrace_check("try 1/0 after foo end.",
+ badarith,
+ [{erlang,'/',[1,0],[]},
+ {erl_eval,do_apply,6}]),
+ backtrace_catch("catch (try 1/0 after foo end).",
+ badarith,
+ [{erlang,'/',[1,0],[]},
+ {erl_eval,do_apply,6}]),
+ backtrace_catch("try catch 1/0 after foo end.",
+ badarith,
+ [{erlang,'/',[1,0],[]},
+ {erl_eval,do_apply,6}]),
+ backtrace_check("try a of b -> bar after foo end.",
+ {try_clause,a},
+ [{erl_eval,try_clauses,8}]),
+ check(fun() -> X = try foo:bar() catch A:B:C -> {A,B} end, X end,
+ "try foo:bar() catch A:B:C -> {A,B} end.",
+ {error, undef}),
+ backtrace_check("C = 4, try foo:bar() catch A:B:C -> {A,B,C} end.",
+ stacktrace_bound,
+ [{erl_eval,check_stacktrace_vars,2},
+ {erl_eval,try_clauses,8}],
+ none, none),
+ backtrace_catch("catch (try a of b -> bar after foo end).",
+ {try_clause,a},
+ [{erl_eval,try_clauses,8}]),
+ backtrace_check("try 1/0 catch exit:a -> foo end.",
+ badarith,
+ [{erlang,'/',[1,0],[]},
+ {erl_eval,do_apply,6}]),
+ Es = [{'try',1,[{call,1,{remote,1,{atom,1,foo},{atom,1,bar}},[]}],
+ [],
+ [{clause,1,[{tuple,1,[{var,1,'A'},{var,1,'B'},{atom,1,'C'}]}],
+ [],[{tuple,1,[{var,1,'A'},{var,1,'B'},{atom,1,'C'}]}]}],[]}],
+ try
+ erl_eval:exprs(Es, [], none, none),
+ ct:fail(stacktrace_variable)
+ catch
+ error:{illegal_stacktrace_variable,{atom,1,'C'}}:S ->
+ [{erl_eval,check_stacktrace_vars,2,_},
+ {erl_eval,try_clauses,8,_}|_] = S
+ end,
+ backtrace_check("{1,1} = {A = 1, A = 2}.",
+ {badmatch, 1},
+ [erl_eval, {lists,foldl,3}]),
+ backtrace_check("case a of a when foo:bar() -> x end.",
+ guard_expr,
+ [{erl_eval,guard0,4}], none, none),
+ backtrace_check("case a of foo() -> ok end.",
+ {illegal_pattern,{call,1,{atom,1,foo},[]}},
+ [{erl_eval,match,4}], none, none),
+ backtrace_check("case a of b -> ok end.",
+ {case_clause,a},
+ [{erl_eval,case_clauses,6}, ?MODULE]),
+ backtrace_check("if a =:= b -> ok end.",
+ if_clause,
+ [{erl_eval,if_clauses,5}, ?MODULE]),
+ backtrace_check("fun A(b) -> ok end(a).",
+ function_clause,
+ [{erl_eval,'-inside-an-interpreted-fun-',[a],[]},
+ {erl_eval,eval_named_fun,8},
+ ?MODULE]),
+ backtrace_check("[A || A <- a].",
+ {bad_generator, a},
+ [{erl_eval,eval_generate,7}, {erl_eval, eval_lc, 6}]),
+ backtrace_check("<< <<A>> || <<A>> <= a>>.",
+ {bad_generator, a},
+ [{erl_eval,eval_b_generate,7}, {erl_eval, eval_bc, 6}]),
+ backtrace_check("[A || A <- [1], begin a end].",
+ {bad_filter, a},
+ [{erl_eval,eval_filter,6}, {erl_eval, eval_generate, 7}]),
+ fun() ->
+ {'EXIT', {{badarity, {_Fun, []}}, BT}} =
+ (catch parse_and_run("fun(A) -> A end().")),
+ check_backtrace([{erl_eval,do_apply,5}, ?MODULE], BT)
+ end(),
+ fun() ->
+ {'EXIT', {{badarity, {_Fun, []}}, BT}} =
+ (catch parse_and_run("fun F(A) -> A end().")),
+ check_backtrace([{erl_eval,do_apply,5}, ?MODULE], BT)
+ end(),
+ backtrace_check("foo().",
+ undef,
+ [{erl_eval,foo,0},{erl_eval,local_func,6}],
+ none, none),
+ backtrace_check("a orelse false.",
+ {badarg, a},
+ [{erl_eval,expr,5}, ?MODULE]),
+ backtrace_check("a andalso false.",
+ {badarg, a},
+ [{erl_eval,expr,5}, ?MODULE]),
+ backtrace_check("t = u.",
+ {badmatch, u},
+ [{erl_eval,expr,5}, ?MODULE]),
+ backtrace_check("{math,sqrt}(2).",
+ {badfun, {math,sqrt}},
+ [{erl_eval,expr,5}, ?MODULE]),
+ backtrace_check("erl_eval_SUITE:simple().",
+ simple,
+ [{?MODULE,simple1,0},{?MODULE,simple,0},erl_eval]),
+ Args = [{integer,1,I} || I <- lists:seq(1, 30)],
+ backtrace_check("fun(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,"
+ "19,20,21,22,23,24,25,26,27,28,29,30) -> a end.",
+ {argument_limit,
+ {'fun',1,[{clause,1,Args,[],[{atom,1,a}]}]}},
+ [{erl_eval,expr,5}, ?MODULE]),
+ backtrace_check("fun F(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,"
+ "19,20,21,22,23,24,25,26,27,28,29,30) -> a end.",
+ {argument_limit,
+ {named_fun,1,'F',[{clause,1,Args,[],[{atom,1,a}]}]}},
+ [{erl_eval,expr,5}, ?MODULE]),
+ backtrace_check("#r{}.",
+ {undef_record,r},
+ [{erl_eval,expr,5}, ?MODULE],
+ none, none),
+ %% eval_bits
+ backtrace_check("<<100:8/bitstring>>.",
+ badarg,
+ [{eval_bits,eval_exp_field1,6},
+ eval_bits,eval_bits,erl_eval]),
+ backtrace_check("<<100:8/foo>>.",
+ {undefined_bittype,foo},
+ [{eval_bits,make_bit_type,3},eval_bits,
+ eval_bits,erl_eval],
+ none, none),
+ backtrace_check("B = <<\"foo\">>, <<B/binary-unit:7>>.",
+ badarg,
+ [{eval_bits,eval_exp_field1,6},
+ eval_bits,eval_bits,erl_eval],
+ none, none),
+ ok.
+
+simple() ->
+ A = simple1(),
+ {A}.
+
+simple1() ->
+ %% If the compiler could see that this function would always
+ %% throw an error exception, it would rewrite simple() like this:
+ %%
+ %% simple() -> simple1().
+ %%
+ %% That would change the stacktrace. To prevent the compiler from
+ %% doing that optimization, we must obfuscate the code.
+ case get(a_key_that_is_not_defined) of
+ undefined -> erlang:error(simple);
+ WillNeverHappen -> WillNeverHappen
+ end.
+
%% Simple cases, just to cover some code.
funs(Config) when is_list(Config) ->
do_funs(none, none),
@@ -1437,6 +1617,55 @@ eep43(Config) when is_list(Config) ->
error_check("(#{})#{nonexisting:=value}.", {badkey,nonexisting}),
ok.
+otp_15035(Config) when is_list(Config) ->
+ check(fun() ->
+ fun() when #{} ->
+ a;
+ () when #{a => b} ->
+ b;
+ () when #{a => b} =:= #{a => b} ->
+ c
+ end()
+ end,
+ "fun() when #{} ->
+ a;
+ () when #{a => b} ->
+ b;
+ () when #{a => b} =:= #{a => b} ->
+ c
+ end().",
+ c),
+ check(fun() ->
+ F = fun(M) when M#{} ->
+ a;
+ (M) when M#{a => b} ->
+ b;
+ (M) when M#{a := b} ->
+ c;
+ (M) when M#{a := b} =:= M#{a := b} ->
+ d;
+ (M) when M#{a => b} =:= M#{a => b} ->
+ e
+ end,
+ {F(#{}), F(#{a => b})}
+ end,
+ "fun() ->
+ F = fun(M) when M#{} ->
+ a;
+ (M) when M#{a => b} ->
+ b;
+ (M) when M#{a := b} ->
+ c;
+ (M) when M#{a := b} =:= M#{a := b} ->
+ d;
+ (M) when M#{a => b} =:= M#{a => b} ->
+ e
+ end,
+ {F(#{}), F(#{a => b})}
+ end().",
+ {e, d}),
+ ok.
+
%% Check the string in different contexts: as is; in fun; from compiled code.
check(F, String, Result) ->
check1(F, String, Result),
@@ -1488,6 +1717,43 @@ error_check(String, Result, LFH, EFH) ->
ct:fail({eval, Other, Result})
end.
+backtrace_check(String, Result, Backtrace) ->
+ case catch parse_and_run(String) of
+ {'EXIT', {Result, BT}} ->
+ check_backtrace(Backtrace, BT);
+ Other ->
+ ct:fail({eval, Other, Result})
+ end.
+
+backtrace_check(String, Result, Backtrace, LFH, EFH) ->
+ case catch parse_and_run(String, LFH, EFH) of
+ {'EXIT', {Result, BT}} ->
+ check_backtrace(Backtrace, BT);
+ Other ->
+ ct:fail({eval, Other, Result})
+ end.
+
+backtrace_catch(String, Result, Backtrace) ->
+ case parse_and_run(String) of
+ {value, {'EXIT', {Result, BT}}, _Bindings} ->
+ check_backtrace(Backtrace, BT);
+ Other ->
+ ct:fail({eval, Other, Result})
+ end.
+
+check_backtrace([B1|Backtrace], [B2|BT]) ->
+ case {B1, B2} of
+ {M, {M,_,_,_}} ->
+ ok;
+ {{M,F,A}, {M,F,A,_}} ->
+ ok;
+ {B, B} ->
+ ok
+ end,
+ check_backtrace(Backtrace, BT);
+check_backtrace([], _) ->
+ ok.
+
eval_string(String) ->
{value, Result, _} = parse_and_run(String),
Result.
@@ -1499,8 +1765,8 @@ parse_and_run(String) ->
parse_and_run(String, LFH, EFH) ->
{ok,Tokens,_} = erl_scan:string(String),
- {ok, [Expr]} = erl_parse:parse_exprs(Tokens),
- erl_eval:expr(Expr, [], LFH, EFH).
+ {ok, Exprs} = erl_parse:parse_exprs(Tokens),
+ erl_eval:exprs(Exprs, [], LFH, EFH).
no_final_dot(S) ->
case lists:reverse(S) of
diff --git a/lib/stdlib/test/erl_internal_SUITE.erl b/lib/stdlib/test/erl_internal_SUITE.erl
index 789a9d4363..7d9df1f989 100644
--- a/lib/stdlib/test/erl_internal_SUITE.erl
+++ b/lib/stdlib/test/erl_internal_SUITE.erl
@@ -80,7 +80,7 @@ callbacks(application) ->
callbacks(gen_server) ->
[{init,1}, {handle_call,3}, {handle_cast,2},
{handle_info,2}, {terminate,2}, {code_change,3},
- {format_status,2}];
+ {format_status,2}, {handle_continue, 2}];
callbacks(gen_fsm) ->
[{init,1}, {handle_event,3}, {handle_sync_event,4},
{handle_info,3}, {terminate,3}, {code_change,4},
@@ -101,7 +101,7 @@ callbacks(supervisor) ->
optional_callbacks(application) ->
[];
optional_callbacks(gen_server) ->
- [{handle_info, 2}, {terminate, 2}, {code_change, 3}, {format_status, 2}];
+ [{handle_info, 2}, {handle_continue, 2}, {terminate, 2}, {code_change, 3}, {format_status, 2}];
optional_callbacks(gen_fsm) ->
[{handle_info, 3}, {terminate, 3}, {code_change, 4}, {format_status, 2}];
optional_callbacks(gen_event) ->
diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl
index 272a71432a..e7882e0daf 100644
--- a/lib/stdlib/test/erl_lint_SUITE.erl
+++ b/lib/stdlib/test/erl_lint_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -66,7 +66,9 @@
otp_11851/1,otp_11879/1,otp_13230/1,
record_errors/1, otp_11879_cont/1,
non_latin1_module/1, otp_14323/1,
- get_stacktrace/1, otp_14285/1, otp_14378/1]).
+ stacktrace_syntax/1,
+ otp_14285/1, otp_14378/1,
+ external_funs/1,otp_15456/1,otp_15563/1]).
suite() ->
[{ct_hooks,[ts_install_cth]},
@@ -87,7 +89,8 @@ all() ->
maps, maps_type, maps_parallel_match,
otp_11851, otp_11879, otp_13230,
record_errors, otp_11879_cont, non_latin1_module, otp_14323,
- get_stacktrace, otp_14285, otp_14378].
+ stacktrace_syntax, otp_14285, otp_14378, external_funs,
+ otp_15456, otp_15563].
groups() ->
[{unused_vars_warn, [],
@@ -2106,17 +2109,93 @@ otp_5362(Config) when is_list(Config) ->
{calendar,local_time_to_universal_time_dst,1}, "a future release"}}]}},
{call_removed_function,
- <<"t(X) -> regexp:match(X).">>,
+ <<"t(X) -> erlang:hash(X, 10000).">>,
[],
{warnings,
- [{1,erl_lint,{removed,{regexp,match,1},
- "removed in R15; use the re module instead"}}]}}
+ [{1,erl_lint,{removed,{erlang,hash,2},{erlang,phash2,2},"20.0"}}]}},
+
+ {nowarn_call_removed_function_1,
+ <<"t(X) -> erlang:hash(X, 10000).">>,
+ [{nowarn_removed,{erlang,hash,2}}],
+ []},
+
+ {nowarn_call_removed_function_2,
+ <<"t(X) -> os_mon_mib:any_function_really(erlang:hash(X, 10000)).">>,
+ [nowarn_removed],
+ []},
+
+ {call_removed_module,
+ <<"t(X) -> os_mon_mib:any_function_really(X).">>,
+ [],
+ {warnings,[{1,erl_lint,
+ {removed,{os_mon_mib,any_function_really,1},
+ "was removed in 22.0"}}]}},
+
+ {nowarn_call_removed_module,
+ <<"t(X) -> os_mon_mib:any_function_really(X).">>,
+ [{nowarn_removed,os_mon_mib}],
+ []}
],
[] = run(Config, Ts),
ok.
+%% OTP-15456. All compiler options can now be given in the option list
+%% (as opposed to only in files).
+otp_15456(Config) when is_list(Config) ->
+ Ts = [
+ %% {nowarn_deprecated_function,[{M,F,A}]} can now be given
+ %% in the option list as well as in an attribute.
+ %% Wherever it occurs, it is not affected by
+ %% warn_deprecated_function.
+ {otp_15456_1,
+ <<"-compile({nowarn_deprecated_function,{erlang,now,0}}).
+ -export([foo/0]).
+
+ foo() ->
+ {erlang:now(), random:seed0(), random:seed(1, 2, 3),
+ random:uniform(), random:uniform(42)}.
+ ">>,
+ {[{nowarn_deprecated_function,{random,seed0,0}},
+ {nowarn_deprecated_function,[{random,uniform,0},
+ {random,uniform,1}]},
+ %% There should be no warnings when attempting to
+ %% turn of warnings for functions that are not
+ %% deprecated or not used in the module.
+ {nowarn_deprecated_function,{random,uniform_s,1}},
+ {nowarn_deprecated_function,{erlang,abs,1}},
+ warn_deprecated_function]},
+ {warnings,[{5,erl_lint,
+ {deprecated,{random,seed,3},
+ "the 'random' module is deprecated; "
+ "use the 'rand' module instead"}}]}},
+
+ %% {nowarn_unused_function,[{M,F,A}]} can be given
+ %% in the option list as well as in an attribute.
+ %% It was incorrectly documented to only work when
+ %% given in an attribute.
+ {otp_15456_2,
+ <<"-compile({nowarn_unused_function,foo/0}).
+ foo() -> ok.
+ bar() -> ok.
+ foobar() -> ok.
+ barf(_) -> ok.
+ other() -> ok.
+ ">>,
+ {[{nowarn_unused_function,[{bar,0},{foobar,0}]},
+ {nowarn_unused_function,{barf,1}},
+ %% There should be no warnings when attempting to
+ %% turn of warnings for unused functions that are not
+ %% defined in the module.
+ {nowarn_unused_function,{not_defined_in_module,1}},
+ warn_unused_function]},
+ {warnings,[{6,erl_lint,{unused_function,{other,0}}}]}
+ }],
+
+ [] = run(Config, Ts),
+ ok.
+
%% OTP-5371. Aliases for bit syntax expressions are no longer allowed.
otp_5371(Config) when is_list(Config) ->
Ts = [{otp_5371_1,
@@ -2729,7 +2808,7 @@ bif_clash(Config) when is_list(Config) ->
[],
{errors,[{2,erl_lint,{call_to_redefined_old_bif,{size,1}}}],[]}},
- %% Verify that warnings can not be turned off in the old way.
+ %% Verify that warnings cannot be turned off in the old way.
{clash2,
<<"-export([t/1,size/1]).
t(X) ->
@@ -3497,10 +3576,12 @@ basic_errors(Config) ->
{illegal_record_info,
<<"f1() -> record_info(42, record).
- f2() -> record_info(shoe_size, record).">>,
+ f2() -> record_info(shoe_size, record).
+ f3() -> fun record_info/2.">>,
[],
{errors,[{1,erl_lint,illegal_record_info},
- {2,erl_lint,illegal_record_info}],[]}},
+ {2,erl_lint,illegal_record_info},
+ {3,erl_lint,illegal_record_info}],[]}},
{illegal_expr,
<<"f() -> a:b.">>,
@@ -3929,6 +4010,8 @@ non_latin1_module(Config) ->
format_error(non_latin1_module_unsupported),
BadCallback =
{bad_callback,{'кирилли́ческий атом','кирилли́ческий атом',0}},
+ BadModule =
+ {bad_module,{'кирилли́ческий атом','кирилли́ческий атом',0}},
"explicit module not allowed for callback "
"'кирилли́ческий атом':'кирилли́ческий атом'/0" =
format_error(BadCallback),
@@ -3971,6 +4054,7 @@ non_latin1_module(Config) ->
{11,erl_lint,illegal_guard_expr},
{15,erl_lint,non_latin1_module_unsupported},
{17,erl_lint,non_latin1_module_unsupported},
+ {17,erl_lint,BadModule},
{20,erl_lint,non_latin1_module_unsupported},
{23,erl_lint,non_latin1_module_unsupported},
{25,erl_lint,non_latin1_module_unsupported}],
@@ -4054,82 +4138,40 @@ otp_14323(Config) ->
[] = run(Config, Ts),
ok.
-get_stacktrace(Config) ->
- Ts = [{old_catch,
+stacktrace_syntax(Config) ->
+ Ts = [{guard,
<<"t1() ->
- catch error(foo),
- erlang:get_stacktrace().
+ try error(foo)
+ catch _:_:Stk when is_number(Stk) -> ok
+ end.
">>,
[],
- {warnings,[{3,erl_lint,{get_stacktrace,after_old_catch}}]}},
- {nowarn_get_stacktrace,
+ {errors,[{3,erl_lint,{stacktrace_guard,'Stk'}}],[]}},
+ {bound,
<<"t1() ->
- catch error(foo),
- erlang:get_stacktrace().
- ">>,
- [nowarn_get_stacktrace],
- []},
- {try_catch,
- <<"t1(X) ->
- try abs(X) of
- _ ->
- erlang:get_stacktrace()
- catch
- _:_ -> ok
- end.
-
- t2() ->
+ Stk = [],
try error(foo)
- catch _:_ -> ok
- end,
- erlang:get_stacktrace().
-
- t3() ->
- try error(foo)
- catch _:_ ->
- try error(bar)
- catch _:_ ->
- ok
- end,
- erlang:get_stacktrace()
- end.
-
- no_warning(X) ->
- try
- abs(X)
- catch
- _:_ ->
- erlang:get_stacktrace()
+ catch _:_:Stk -> ok
end.
">>,
[],
- {warnings,[{4,erl_lint,{get_stacktrace,wrong_part_of_try}},
- {13,erl_lint,{get_stacktrace,after_try}},
- {22,erl_lint,{get_stacktrace,after_try}}]}},
- {multiple_catch_clauses,
- <<"maybe_error(Arg) ->
- try 5 / Arg
- catch
- error:badarith ->
- _Stacktrace = erlang:get_stacktrace(),
- try io:nl()
- catch
- error:_ -> io:format('internal error')
- end;
- error:badarg ->
- _Stacktrace = erlang:get_stacktrace(),
- try io:format(qwe)
- catch
- error:_ -> io:format('internal error')
- end
- end.
- ">>,
+ {errors,[{4,erl_lint,{stacktrace_bound,'Stk'}}],[]}},
+ {guard_and_bound,
+ <<"t1() ->
+ Stk = [],
+ try error(foo)
+ catch _:_:Stk when is_integer(Stk) -> ok
+ end.
+ ">>,
[],
- []}],
+ {errors,[{4,erl_lint,{stacktrace_bound,'Stk'}},
+ {4,erl_lint,{stacktrace_guard,'Stk'}}],[]}}
+ ],
run(Config, Ts),
ok.
+
%% Unicode atoms.
otp_14285(Config) ->
%% A small sample of all the errors and warnings in module erl_lint.
@@ -4175,6 +4217,36 @@ otp_14285(Config) ->
run(Config, Ts),
ok.
+external_funs(Config) when is_list(Config) ->
+ Ts = [{external_funs_1,
+ %% ERL-762: Unused variable warning not being emitted.
+ <<"f() ->
+ BugVar = process_info(self()),
+ if true -> fun m:f/1 end.
+ f(M, F) ->
+ BugVar = process_info(self()),
+ if true -> fun M:F/1 end.">>,
+ [],
+ {warnings,[{2,erl_lint,{unused_var,'BugVar'}},
+ {5,erl_lint,{unused_var,'BugVar'}}]}}],
+ run(Config, Ts),
+ ok.
+
+otp_15563(Config) when is_list(Config) ->
+ Ts = [{otp_15563,
+ <<"-type deep_list(A) :: [A | deep_list(A)].
+ -spec lists:flatten(deep_list(A)) -> [A].
+ -callback lists:concat([_]) -> string().
+ -spec ?MODULE:foo() -> any().
+ foo() -> a.
+ ">>,
+ [warn_unused_vars],
+ {errors,[{2,erl_lint,{bad_module,{lists,flatten,1}}},
+ {3,erl_lint,{bad_callback,{lists,concat,1}}}],
+ []}}],
+ [] = run(Config, Ts),
+ ok.
+
format_error(E) ->
lists:flatten(erl_lint:format_error(E)).
diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl
index dda8d0a12e..c0cfd26925 100644
--- a/lib/stdlib/test/erl_pp_SUITE.erl
+++ b/lib/stdlib/test/erl_pp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -47,11 +47,12 @@
hook/1,
neg_indent/1,
maps_syntax/1,
+ quoted_atom_types/1,
otp_6321/1, otp_6911/1, otp_6914/1, otp_8150/1, otp_8238/1,
otp_8473/1, otp_8522/1, otp_8567/1, otp_8664/1, otp_9147/1,
otp_10302/1, otp_10820/1, otp_11100/1, otp_11861/1, pr_1014/1,
- otp_13662/1, otp_14285/1]).
+ otp_13662/1, otp_14285/1, otp_15592/1, otp_15751/1, otp_15755/1]).
%% Internal export.
-export([ehook/6]).
@@ -74,14 +75,14 @@ groups() ->
[{expr, [],
[func, call, recs, try_catch, if_then, receive_after,
bits, head_tail, cond1, block, case1, ops,
- messages, maps_syntax
+ messages, maps_syntax, quoted_atom_types
]},
{attributes, [], [misc_attrs, import_export, dialyzer_attrs]},
{tickets, [],
[otp_6321, otp_6911, otp_6914, otp_8150, otp_8238,
otp_8473, otp_8522, otp_8567, otp_8664, otp_9147,
otp_10302, otp_10820, otp_11100, otp_11861, pr_1014, otp_13662,
- otp_14285]}].
+ otp_14285, otp_15592, otp_15751, otp_15755]}].
init_per_suite(Config) ->
Config.
@@ -473,10 +474,10 @@ cond1(Config) when is_list(Config) ->
[{tuple,5,[{atom,5,x},{atom,5,y}]}]}]},
CChars = flat_expr1(C),
"cond\n"
- " {foo,bar} ->\n"
- " [a,b];\n"
+ " {foo, bar} ->\n"
+ " [a, b];\n"
" true ->\n"
- " {x,y}\n"
+ " {x, y}\n"
"end" = CChars,
ok.
@@ -711,7 +712,7 @@ otp_6321(Config) when is_list(Config) ->
Str = "S = hopp, {hej, S}. ",
{done, {ok, Tokens, _EndLine}, ""} = erl_scan:tokens("", Str, _L=1),
{ok, Exprs} = erl_parse:parse_exprs(Tokens),
- "S = hopp, {hej,S}" = lists:flatten(erl_pp:exprs(Exprs)),
+ "S = hopp, {hej, S}" = lists:flatten(erl_pp:exprs(Exprs)),
ok.
%% OTP_6911. More newlines.
@@ -828,7 +829,7 @@ type_examples() ->
"(t24()) -> D when is_subtype(D, atom()),"
" is_subtype(D, t14()),"
" is_subtype(D, '\\'t::4'()).">>},
- {ex32,<<"-spec mod:t2() -> any(). ">>},
+ {ex32,<<"-spec erl_pp_test:t2() -> any(). ">>},
{ex33,<<"-opaque attributes_data() :: "
"[{'column', column()} | {'line', info_line()} |"
" {'text', string()}] | {line(),column()}. ">>},
@@ -912,6 +913,21 @@ maps_syntax(Config) when is_list(Config) ->
ok = pp_forms(F),
ok.
+quoted_atom_types(Config) when is_list(Config) ->
+ Q = [{quote_singleton_atom_types, true}],
+ U = [{encoding,unicode}],
+ L = [{encoding,latin1}],
+ F = "-type t() :: a | a().",
+ "-type t() :: 'a' | a().\n" =
+ lists:flatten(parse_and_pp_forms(F, Q ++ L)),
+ "-type t() :: 'a' | a().\n" =
+ lists:flatten(parse_and_pp_forms(F, Q ++ U)),
+ UF = "-type t() :: '\x{400}' | '\x{400}'().",
+ "-type t() :: '\\x{400}' | '\\x{400}'().\n" =
+ lists:flatten(parse_and_pp_forms(UF, Q ++ L)),
+ "-type t() :: '\x{400}' | '\x{400}'().\n" =
+ lists:flatten(parse_and_pp_forms(UF, Q ++ U)),
+ ok.
%% OTP_8567. Avoid duplicated 'undefined' in record field types.
otp_8567(Config) when is_list(Config) ->
@@ -1096,7 +1112,7 @@ otp_11861(Config) when is_list(Config) ->
A3 = erl_anno:new(3),
"-optional_callbacks([bar/0]).\n" =
pf({attribute,A3,optional_callbacks,[{bar,0}]}),
- "-optional_callbacks([{bar,1,bad}]).\n" =
+ "-optional_callbacks([{bar, 1, bad}]).\n" =
pf({attribute,A3,optional_callbacks,[{bar,1,bad}]}),
ok.
@@ -1167,6 +1183,84 @@ otp_14285(_Config) ->
[{encoding,latin1}])),
ok.
+otp_15592(_Config) ->
+ ok = pp_expr(<<"long12345678901234567890123456789012345678901234"
+ "56789012345678901234:f(<<>>)">>),
+ ok.
+
+otp_15751(_Config) ->
+ ok = pp_expr(<<"try foo:bar()
+ catch
+ Reason : Stacktrace ->
+ {Reason, Stacktrace}
+ end">>),
+ ok = pp_expr(<<"try foo:bar()
+ catch
+ throw: Reason : Stacktrace ->
+ {Reason, Stacktrace}
+ end">>),
+ ok = pp_expr(<<"try foo:bar()
+ catch
+ Reason : _ ->
+ Reason
+ end">>),
+ ok = pp_expr(<<"try foo:bar()
+ catch
+ throw: Reason : _ ->
+ Reason
+ end">>),
+ ok = pp_expr(<<"try foo:bar()
+ catch
+ Reason ->
+ Reason
+ end">>),
+ ok = pp_expr(<<"try foo:bar()
+ catch
+ throw: Reason ->
+ Reason
+ end">>),
+ ok.
+
+otp_15755(_Config) ->
+ "[{a, b}, c, {d, e} | t]" =
+ flat_parse_and_pp_expr("[{a, b}, c, {d, e} | t]", 0, []),
+ "[{a, b},\n c, d,\n {d, e},\n 1, 2.0,\n {d, e},\n <<>>, {},\n {d, e},\n"
+ " [], [],\n {d, e} |\n t]" =
+ flat_parse_and_pp_expr("[{a,b},c,d,{d,e},1,2.0,{d,e},<<>>,"
+ "{},{d,e},[],[],{d,e}|t]", 0, []),
+ "[{a, b},\n c, d,\n {d, e},\n 1, 2.0,\n {d, e},\n <<>>, {},\n {d, e},\n"
+ " [], [], d, e | t]" =
+ flat_parse_and_pp_expr("[{a,b},c,d,{d,e},1,2.0,{d,e},<<>>,"
+ "{},{d,e},[],[],d,e|t]", 0, []),
+
+ "-type t() ::
+ a | b | c | a | b | a | b | a | b | a | b | a | b | a | b |
+ a | b | a | b | a | b.\n" =
+ lists:flatten(parse_and_pp_forms(
+ "-type t() :: a | b | c| a | b | a | b | a | b | a |"
+ " b | a | b | a | b | a | b | a | b |a | b.", [])),
+
+ "-type t() ::
+ {dict, 0, 16, 16, 8, 80, 48,
+ {[], [], [], [], [], [], [], [], [], [], [], [], [], [], [],
+ []},
+ {{[], [], [], [], [], [], [], [], [], [], [], [], [], [], []}}}.\n" =
+ lists:flatten(parse_and_pp_forms(
+ "-type t() :: {dict,0,16,16,8,80,48,"
+ "{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},"
+ "{{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]}}}.", [])),
+
+ "-type t() ::
+ {{a},
+ 0, 16,
+ {16},
+ 8, 80, 48, a, b, e, f, 'sf s sdf', [], {},
+ {[]}}.\n" =
+ lists:flatten(parse_and_pp_forms(
+ "-type t() :: {{a}, 0, 16, {16}, 8, 80, 48, a, b, e, f,"
+ " 'sf s sdf', [], {}, {[]}}.", [])),
+ ok.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
compile(Config, Tests) ->
@@ -1298,6 +1392,9 @@ pp_expr(List, Options) when is_list(List) ->
not_ok
end.
+flat_parse_and_pp_expr(String, Indent, Options) ->
+ lists:flatten(parse_and_pp_expr(String, Indent, Options)).
+
parse_and_pp_expr(String, Indent, Options) ->
StringDot = lists:flatten(String) ++ ".",
erl_pp:expr(parse_expr(StringDot), Indent, Options).
diff --git a/lib/stdlib/test/error_logger_h_SUITE.erl b/lib/stdlib/test/error_logger_h_SUITE.erl
index 1f2a9fda0b..bf9b6d9ad6 100644
--- a/lib/stdlib/test/error_logger_h_SUITE.erl
+++ b/lib/stdlib/test/error_logger_h_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -62,6 +62,7 @@ logfile(Config) ->
error_logger:logfile({open,Log}),
ok = rpc:call(Node, erlang, apply, [fun gen_events/1,[Ev]]),
AtNode = iolist_to_binary(["** at node ",atom_to_list(Node)," **"]),
+ timer:sleep(1000), % some time get all log events in the log
error_logger:logfile(close),
analyse_events(Log, Ev, [AtNode], unlimited),
@@ -124,6 +125,7 @@ tty(Config) ->
ok = rpc:call(Node, erlang, apply, [fun gen_events/1,[Ev]]),
tty_log_close(),
AtNode = iolist_to_binary(["** at node ",atom_to_list(Node)," **"]),
+ timer:sleep(1000), % some time get all log events in the log
analyse_events(Log, Ev, [AtNode], unlimited),
test_server:stop_node(Node),
@@ -207,7 +209,7 @@ event_templates() ->
gen_events(Ev) ->
io:format("node = ~p\n", [node()]),
io:format("group leader = ~p\n", [group_leader()]),
- io:format("~p\n", [gen_event:which_handlers(error_logger)]),
+ io:format("~p\n", [error_logger:which_report_handlers()]),
call_error_logger(Ev),
{Pid,Ref} = spawn_monitor(fun() -> error(ouch) end),
@@ -240,6 +242,7 @@ analyse_events(Log, Ev, AtNode, Depth) ->
call_error_logger([{F,Args}|T]) ->
apply(error_logger, F, Args),
+ timer:sleep(10),
call_error_logger(T);
call_error_logger([]) -> ok.
@@ -257,8 +260,7 @@ match_output([Item|T], Lines0, AtNode, Depth) ->
Lines ->
match_output(T, Lines, AtNode, Depth)
catch
- C:E ->
- Stk = erlang:get_stacktrace(),
+ C:E:Stk ->
io:format("ITEM: ~p", [Item]),
io:format("LINES: ~p", [Lines0]),
erlang:raise(C, E, Stk)
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index 1a8260b041..dd49288417 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@
-export([default/1,setbag/1,badnew/1,verybadnew/1,named/1,keypos2/1,
privacy/1]).
-export([empty/1,badinsert/1]).
--export([time_lookup/1,badlookup/1,lookup_order/1]).
+-export([badlookup/1,lookup_order/1]).
-export([delete_elem/1,delete_tab/1,delete_large_tab/1,
delete_large_named_table/1,
evil_delete/1,baddelete/1,match_delete/1,table_leak/1]).
@@ -41,7 +41,9 @@
-export([t_delete_object/1, t_init_table/1, t_whitebox/1,
select_bound_chunk/1,
t_delete_all_objects/1, t_insert_list/1, t_test_ms/1,
- t_select_delete/1,t_select_replace/1,t_ets_dets/1]).
+ t_select_delete/1,t_select_replace/1,t_select_replace_next_bug/1,t_ets_dets/1]).
+-export([test_table_size_concurrency/1,test_table_memory_concurrency/1,
+ test_delete_table_while_size_snapshot/1, test_delete_table_while_size_snapshot_helper/0]).
-export([ordered/1, ordered_match/1, interface_equality/1,
fixtable_next/1, fixtable_insert/1, rename/1, rename_unnamed/1, evil_rename/1,
@@ -55,9 +57,12 @@
-export([t_repair_continuation/1]).
-export([t_match_spec_run/1]).
-export([t_bucket_disappears/1]).
+-export([t_named_select/1]).
+-export([select_fixtab_owner_change/1]).
-export([otp_5340/1]).
-export([otp_6338/1]).
-export([otp_6842_select_1000/1]).
+-export([select_mbuf_trapping/1]).
-export([otp_7665/1]).
-export([meta_wb/1]).
-export([grow_shrink/1, grow_pseudo_deleted/1, shrink_pseudo_deleted/1]).
@@ -65,7 +70,12 @@
meta_lookup_named_read/1, meta_lookup_named_write/1,
meta_newdel_unnamed/1, meta_newdel_named/1]).
-export([smp_insert/1, smp_fixed_delete/1, smp_unfix_fix/1, smp_select_delete/1,
- smp_select_replace/1, otp_8166/1, otp_8732/1]).
+ smp_ordered_iteration/1,
+ smp_select_replace/1, otp_8166/1, otp_8732/1, delete_unfix_race/1]).
+-export([throughput_benchmark/0,
+ throughput_benchmark/1,
+ test_throughput_benchmark/1,
+ long_throughput_benchmark/1]).
-export([exit_large_table_owner/1,
exit_many_large_table_owner/1,
exit_many_tables_owner/1,
@@ -78,6 +88,7 @@
-export([ets_all/1]).
-export([massive_ets_all/1]).
-export([take/1]).
+-export([whereis_table/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
%% Convenience for manual testing
@@ -85,7 +96,9 @@
-export([t_select_reverse/1]).
+-include_lib("stdlib/include/ms_transform.hrl"). % ets:fun2ms
-include_lib("common_test/include/ct.hrl").
+-include_lib("common_test/include/ct_event.hrl").
-define(m(A,B), assert_eq(A,B)).
-define(heap_binary_size, 64).
@@ -122,12 +135,16 @@ all() ->
select_bound_chunk,
t_init_table, t_whitebox, t_delete_all_objects,
t_insert_list, t_test_ms, t_select_delete, t_select_replace,
+ t_select_replace_next_bug,
t_ets_dets, memory, t_select_reverse, t_bucket_disappears,
+ t_named_select, select_fixtab_owner_change,
select_fail, t_insert_new, t_repair_continuation,
otp_5340, otp_6338, otp_6842_select_1000, otp_7665,
+ select_mbuf_trapping,
otp_8732, meta_wb, grow_shrink, grow_pseudo_deleted,
shrink_pseudo_deleted, {group, meta_smp}, smp_insert,
- smp_fixed_delete, smp_unfix_fix, smp_select_replace,
+ smp_fixed_delete, smp_unfix_fix, smp_select_replace,
+ smp_ordered_iteration,
smp_select_delete, otp_8166, exit_large_table_owner,
exit_many_large_table_owner, exit_many_tables_owner,
exit_many_many_tables_owner, write_concurrency, heir,
@@ -137,14 +154,22 @@ all() ->
otp_9423,
ets_all,
massive_ets_all,
- take].
+ take,
+ whereis_table,
+ delete_unfix_race,
+ test_throughput_benchmark,
+ {group, benchmark},
+ test_table_size_concurrency,
+ test_table_memory_concurrency,
+ test_delete_table_while_size_snapshot].
+
groups() ->
[{new, [],
[default, setbag, badnew, verybadnew, named, keypos2,
privacy]},
{insert, [], [empty, badinsert]},
- {lookup, [], [time_lookup, badlookup, lookup_order]},
+ {lookup, [], [badlookup, lookup_order]},
{lookup_element, [], [lookup_element_mult]},
{delete, [],
[delete_elem, delete_tab, delete_large_tab,
@@ -165,20 +190,76 @@ groups() ->
{meta_smp, [],
[meta_lookup_unnamed_read, meta_lookup_unnamed_write,
meta_lookup_named_read, meta_lookup_named_write,
- meta_newdel_unnamed, meta_newdel_named]}].
+ meta_newdel_unnamed, meta_newdel_named]},
+ {benchmark, [],
+ [long_throughput_benchmark]}].
init_per_suite(Config) ->
erts_debug:set_internal_state(available_internal_state, true),
+ erts_debug:set_internal_state(ets_force_trap, true),
Config.
end_per_suite(_Config) ->
stop_spawn_logger(),
+ erts_debug:set_internal_state(ets_force_trap, false),
catch erts_debug:set_internal_state(available_internal_state, false),
ok.
+init_per_group(benchmark, Config) ->
+ P = self(),
+ %% Spawn owner of ETS table that is alive until end_per_group is run
+ EtsProcess =
+ spawn(
+ fun()->
+ Tab = ets:new(ets_benchmark_result_summary_tab, [public]),
+ P ! {the_table, Tab},
+ receive
+ kill -> ok
+ end
+ end),
+ Tab = receive {the_table, T} -> T end,
+ CounterNames = [nr_of_benchmarks,
+ total_throughput,
+ nr_of_set_benchmarks,
+ total_throughput_set,
+ nr_of_ordered_set_benchmarks,
+ total_throughput_ordered_set],
+ lists:foreach(fun(CtrName) ->
+ ets:insert(Tab, {CtrName, 0.0})
+ end,
+ CounterNames),
+ [{ets_benchmark_result_summary_tab, Tab},
+ {ets_benchmark_result_summary_tab_process, EtsProcess} | Config];
init_per_group(_GroupName, Config) ->
Config.
+end_per_group(benchmark, Config) ->
+ T = proplists:get_value(ets_benchmark_result_summary_tab, Config),
+ EtsProcess = proplists:get_value(ets_benchmark_result_summary_tab_process, Config),
+ Report =
+ fun(NOfBenchmarksCtr, TotThroughoutCtr, Name) ->
+ Average =
+ ets:lookup_element(T, TotThroughoutCtr, 2) /
+ ets:lookup_element(T, NOfBenchmarksCtr, 2),
+ io:format("~p ~p~n", [Name, Average]),
+ ct_event:notify(
+ #event{name = benchmark_data,
+ data = [{suite,"ets_bench"},
+ {name, Name},
+ {value, Average}]})
+ end,
+ Report(nr_of_benchmarks,
+ total_throughput,
+ "Average Throughput"),
+ Report(nr_of_set_benchmarks,
+ total_throughput_set,
+ "Average Throughput Set"),
+ Report(nr_of_ordered_set_benchmarks,
+ total_throughput_ordered_set,
+ "Average Throughput Ordered Set"),
+ ets:delete(T),
+ EtsProcess ! kill,
+ Config;
end_per_group(_GroupName, Config) ->
Config.
@@ -203,6 +284,95 @@ t_bucket_disappears_do(Opts) ->
true = ets:delete(abcd),
verify_etsmem(EtsMem).
+%% OTP-21: Test that select/1 fails if named table was deleted and recreated
+%% and succeeds if table was renamed.
+t_named_select(_Config) ->
+ repeat_for_opts(fun t_named_select_do/1).
+
+t_named_select_do(Opts) ->
+ EtsMem = etsmem(),
+ T = t_name_tid_select,
+ ets_new(T, [named_table | Opts]),
+ ets:insert(T, {1,11}),
+ ets:insert(T, {2,22}),
+ ets:insert(T, {3,33}),
+ MS = [{{'$1', 22}, [], ['$1']}],
+ {[2], Cont1} = ets:select(T, MS, 1),
+ ets:delete(T),
+ {'EXIT',{badarg,_}} = (catch ets:select(Cont1)),
+ ets_new(T, [named_table | Opts]),
+ {'EXIT',{badarg,_}} = (catch ets:select(Cont1)),
+
+ true = ets:insert_new(T, {1,22}),
+ true = ets:insert_new(T, {2,22}),
+ true = ets:insert_new(T, {4,22}),
+ {[A,B], Cont2} = ets:select(T, MS, 2),
+ ets:rename(T, abcd),
+ {[C], '$end_of_table'} = ets:select(Cont2),
+ 7 = A + B + C,
+
+ true = ets:delete(abcd),
+ verify_etsmem(EtsMem).
+
+
+%% Verify select and friends release fixtab as they should
+%% even when owneship is changed between traps.
+select_fixtab_owner_change(_Config) ->
+ T = ets:new(xxx, [protected]),
+ NKeys = 2000,
+ [ets:insert(T,{K,K band 7}) || K <- lists:seq(1,NKeys)],
+
+ %% Buddy and Papa will ping-pong table ownership between them
+ %% and the aim is to give Buddy the table when he is
+ %% in the middle of a yielding select* call.
+ {Buddy,_} = spawn_opt(fun() -> sfoc_buddy_loop(T, 1, undefined) end,
+ [link,monitor]),
+
+ sfoc_papa_loop(T, Buddy),
+
+ receive {'DOWN', _, process, Buddy, _} -> ok end,
+ ets:delete(T),
+ ok.
+
+sfoc_buddy_loop(T, I, State0) ->
+ receive
+ {'ETS-TRANSFER', T, Papa, _} ->
+ ets:give_away(T, Papa, State0),
+ case State0 of
+ done ->
+ ok;
+ _ ->
+ State1 = sfoc_traverse(T, I, State0),
+ %% Verify no fixation left
+ {I, false} = {I, ets:info(T, safe_fixed_monotonic_time)},
+ sfoc_buddy_loop(T, I+1, State1)
+ end
+ end.
+
+sfoc_papa_loop(T, Buddy) ->
+ ets:give_away(T, Buddy, "Catch!"),
+ receive
+ {'ETS-TRANSFER', T, Buddy, State} ->
+ case State of
+ done ->
+ ok;
+ _ ->
+ sfoc_papa_loop(T, Buddy)
+ end
+ end.
+
+sfoc_traverse(T, 1, S) ->
+ ets:select(T, [{{'$1',7}, [], ['$1']}]), S;
+sfoc_traverse(T, 2, S) ->
+ 0 = ets:select_count(T, [{{'$1',7}, [], [false]}]), S;
+sfoc_traverse(T, 3, _) ->
+ Limit = ets:info(T, size) div 2,
+ {_, Continuation} = ets:select(T, [{{'$1',7}, [], ['$1']}],
+ Limit),
+ Continuation;
+sfoc_traverse(_T, 4, Continuation) ->
+ _ = ets:select(Continuation),
+ done.
%% Check ets:match_spec_run/2.
t_match_spec_run(Config) when is_list(Config) ->
@@ -664,7 +834,11 @@ adjust_xmem([_T1,_T2,_T3,_T4], {A0,B0,C0,D0} = _Mem0, EstCnt) ->
{TabSz, EstSz} = erts_debug:get_internal_state('DbTable_words'),
HTabSz = TabSz + EstCnt*EstSz,
- {A0+TabSz, B0+HTabSz, C0+HTabSz, D0+HTabSz}.
+ OrdSetExtra = case erlang:system_info(wordsize) of
+ 8 -> 40; % larger stack on 64 bit architectures
+ _ -> 0
+ end,
+ {A0+TabSz+OrdSetExtra, B0+HTabSz, C0+HTabSz, D0+HTabSz}.
%% Misc. whitebox tests
t_whitebox(Config) when is_list(Config) ->
@@ -698,11 +872,11 @@ whitebox_2(Opts) ->
ets:delete(T2),
ok.
-select_bound_chunk(Config) ->
+select_bound_chunk(_Config) ->
repeat_for_opts(fun select_bound_chunk_do/1, [all_types]).
select_bound_chunk_do(Opts) ->
- T = ets:new(x, Opts),
+ T = ets_new(x, Opts),
ets:insert(T, [{key, 1}]),
{[{key, 1}], '$end_of_table'} = ets:select(T, [{{key,1},[],['$_']}], 100000),
ok.
@@ -748,35 +922,92 @@ check_badarg({'EXIT', {badarg, [{M,F,A,_} | _]}}, M, F, Args) ->
%% Test ets:delete_all_objects/1.
t_delete_all_objects(Config) when is_list(Config) ->
EtsMem = etsmem(),
- repeat_for_opts(fun t_delete_all_objects_do/1),
+ repeat_for_opts_all_set_table_types(fun t_delete_all_objects_do/1),
verify_etsmem(EtsMem).
get_kept_objects(T) ->
case ets:info(T,stats) of
- false ->
- 0;
{_,_,_,_,_,_,KO} ->
- KO
+ KO;
+ _ ->
+ 0
end.
t_delete_all_objects_do(Opts) ->
- T=ets_new(x,Opts),
- filltabint(T,4000),
+ KeyRange = 4000,
+ T=ets_new(x, Opts, KeyRange),
+ filltabint(T,KeyRange),
O=ets:first(T),
ets:next(T,O),
ets:safe_fixtable(T,true),
true = ets:delete_all_objects(T),
'$end_of_table' = ets:next(T,O),
0 = ets:info(T,size),
- 4000 = get_kept_objects(T),
+ case ets:info(T,type) of
+ ordered_set -> ok;
+ _ -> KeyRange = get_kept_objects(T)
+ end,
ets:safe_fixtable(T,false),
0 = ets:info(T,size),
0 = get_kept_objects(T),
- filltabint(T,4000),
- 4000 = ets:info(T,size),
+ filltabint(T, KeyRange),
+ KeyRange = ets:info(T,size),
true = ets:delete_all_objects(T),
0 = ets:info(T,size),
- ets:delete(T).
+ ets:delete(T),
+
+ %% Test delete_all_objects is atomic
+ T2 = ets_new(t_delete_all_objects, [public | Opts]),
+ Self = self(),
+ Inserters = [spawn_link(fun() -> inserter(T2, 100*1000, 1, Self) end) || _ <- [1,2,3,4]],
+ [receive {Ipid, running} -> ok end || Ipid <- Inserters],
+
+ ets:delete_all_objects(T2),
+ erlang:yield(),
+ [Ipid ! stop || Ipid <- Inserters],
+ Result = [receive {Ipid, stopped, Highest} -> {Ipid,Highest} end || Ipid <- Inserters],
+
+ %% Verify unbroken sequences of objects inserted _after_ ets:delete_all_objects.
+ Sum = lists:foldl(fun({Ipid, Highest}, AccSum) ->
+ %% ets:fun2ms(fun({{K,Ipid}}) when K =< Highest -> true end),
+ AliveMS = [{{{'$1',Ipid}},[{'=<','$1',{const,Highest}}],[true]}],
+ Alive = ets:select_count(T2, AliveMS),
+ Lowest = Highest - (Alive-1),
+
+ %% ets:fun2ms(fun({{K,Ipid}}) when K < Lowest -> true end)
+ DeletedMS = [{{{'$1',Ipid}},[{'<','$1',{const,Lowest}}],[true]}],
+ 0 = ets:select_count(T2, DeletedMS),
+ AccSum + Alive
+ end,
+ 0,
+ Result),
+ ok = case ets:info(T2, size) of
+ Sum -> ok;
+ Size ->
+ io:format("Sum = ~p\nSize = ~p\n", [Sum, Size]),
+ {Sum,Size}
+ end,
+
+ ets:delete(T2).
+
+inserter(_, 0, _, _) ->
+ ok;
+inserter(T, N, Next, Papa) ->
+ case Next of
+ 10*1000 ->
+ Papa ! {self(), running};
+ _ ->
+ ok
+ end,
+
+ ets:insert(T, {{Next, self()}}),
+ receive
+ stop ->
+ Papa ! {self(), stopped, Next},
+ ok
+ after 0 ->
+ inserter(T, N-1, Next+1, Papa)
+ end.
%% Test ets:delete_object/2.
@@ -1373,6 +1604,25 @@ t_select_replace(Config) when is_list(Config) ->
verify_etsmem(EtsMem).
+%% OTP-15346: Bug caused select_replace of bound key to corrupt static stack
+%% used by ets:next and ets:prev.
+t_select_replace_next_bug(Config) when is_list(Config) ->
+ T = ets:new(k, [ordered_set]),
+ [ets:insert(T, {I, value}) || I <- lists:seq(1,10)],
+ 1 = ets:first(T),
+
+ %% Make sure select_replace does not leave pointer
+ %% to deallocated {2,value} in static stack.
+ MS = [{{2,value}, [], [{{2,"new_value"}}]}],
+ 1 = ets:select_replace(T, MS),
+
+ %% This would crash or give wrong result at least on DEBUG emulator
+ %% where deallocated memory is overwritten.
+ 2 = ets:next(T, 1),
+
+ ets:delete(T).
+
+
%% Test that partly bound keys gives faster matches.
partly_bound(Config) when is_list(Config) ->
case os:type() of
@@ -1682,7 +1932,7 @@ do_random_test() ->
ets:delete(Set),
verify_etsmem(EtsMem).
-%% Ttest various variants of update_element.
+%% Test various variants of update_element.
update_element(Config) when is_list(Config) ->
EtsMem = etsmem(),
repeat_for_opts(fun update_element_opts/1),
@@ -2259,17 +2509,29 @@ write_concurrency(Config) when is_list(Config) ->
Yes6 = ets_new(foo,[duplicate_bag,protected,{write_concurrency,true}]),
No3 = ets_new(foo,[duplicate_bag,private,{write_concurrency,true}]),
- No4 = ets_new(foo,[ordered_set,public,{write_concurrency,true}]),
- No5 = ets_new(foo,[ordered_set,protected,{write_concurrency,true}]),
- No6 = ets_new(foo,[ordered_set,private,{write_concurrency,true}]),
-
- No7 = ets_new(foo,[public,{write_concurrency,false}]),
- No8 = ets_new(foo,[protected,{write_concurrency,false}]),
+ Yes7 = ets_new(foo,[ordered_set,public,{write_concurrency,true}]),
+ Yes8 = ets_new(foo,[ordered_set,protected,{write_concurrency,true}]),
+ Yes9 = ets_new(foo,[ordered_set,{write_concurrency,true}]),
+ Yes10 = ets_new(foo,[{write_concurrency,true},ordered_set,public]),
+ Yes11 = ets_new(foo,[{write_concurrency,true},ordered_set,protected]),
+ Yes12 = ets_new(foo,[set,{write_concurrency,false},
+ {write_concurrency,true},ordered_set,public]),
+ Yes13 = ets_new(foo,[private,public,set,{write_concurrency,false},
+ {write_concurrency,true},ordered_set]),
+ No4 = ets_new(foo,[ordered_set,private,{write_concurrency,true}]),
+ No5 = ets_new(foo,[ordered_set,public,{write_concurrency,false}]),
+ No6 = ets_new(foo,[ordered_set,protected,{write_concurrency,false}]),
+ No7 = ets_new(foo,[ordered_set,private,{write_concurrency,false}]),
+
+ No8 = ets_new(foo,[public,{write_concurrency,false}]),
+ No9 = ets_new(foo,[protected,{write_concurrency,false}]),
YesMem = ets:info(Yes1,memory),
NoHashMem = ets:info(No1,memory),
+ YesTreeMem = ets:info(Yes7,memory),
NoTreeMem = ets:info(No4,memory),
- io:format("YesMem=~p NoHashMem=~p NoTreeMem=~p\n",[YesMem,NoHashMem,NoTreeMem]),
+ io:format("YesMem=~p NoHashMem=~p NoTreeMem=~p YesTreeMem=~p\n",[YesMem,NoHashMem,
+ NoTreeMem,YesTreeMem]),
YesMem = ets:info(Yes2,memory),
YesMem = ets:info(Yes3,memory),
@@ -2278,18 +2540,24 @@ write_concurrency(Config) when is_list(Config) ->
YesMem = ets:info(Yes6,memory),
NoHashMem = ets:info(No2,memory),
NoHashMem = ets:info(No3,memory),
+ YesTreeMem = ets:info(Yes7,memory),
+ YesTreeMem = ets:info(Yes8,memory),
+ YesTreeMem = ets:info(Yes9,memory),
+ YesTreeMem = ets:info(Yes10,memory),
+ YesTreeMem = ets:info(Yes11,memory),
+ YesTreeMem = ets:info(Yes12,memory),
+ YesTreeMem = ets:info(Yes13,memory),
+ NoTreeMem = ets:info(No4,memory),
NoTreeMem = ets:info(No5,memory),
NoTreeMem = ets:info(No6,memory),
- NoHashMem = ets:info(No7,memory),
+ NoTreeMem = ets:info(No7,memory),
NoHashMem = ets:info(No8,memory),
+ NoHashMem = ets:info(No9,memory),
- case erlang:system_info(smp_support) of
- true ->
- true = YesMem > NoHashMem,
- true = YesMem > NoTreeMem;
- false ->
- true = YesMem =:= NoHashMem
- end,
+ true = YesMem > NoHashMem,
+ true = YesMem > NoTreeMem,
+ true = YesMem > YesTreeMem,
+ true = YesTreeMem < NoTreeMem,
{'EXIT',{badarg,_}} = (catch ets_new(foo,[public,{write_concurrency,foo}])),
{'EXIT',{badarg,_}} = (catch ets_new(foo,[public,{write_concurrency}])),
@@ -2297,8 +2565,8 @@ write_concurrency(Config) when is_list(Config) ->
{'EXIT',{badarg,_}} = (catch ets_new(foo,[public,write_concurrency])),
lists:foreach(fun(T) -> ets:delete(T) end,
- [Yes1,Yes2,Yes3,Yes4,Yes5,Yes6,
- No1,No2,No3,No4,No5,No6,No7,No8]),
+ [Yes1,Yes2,Yes3,Yes4,Yes5,Yes6,Yes7,Yes8,Yes9,Yes10,Yes11,Yes12,Yes13,
+ No1,No2,No3,No4,No5,No6,No7,No8,No9]),
verify_etsmem(EtsMem),
ok.
@@ -2943,41 +3211,43 @@ pick_all_backwards(T) ->
%% Small test case for both set and bag type ets tables.
setbag(Config) when is_list(Config) ->
EtsMem = etsmem(),
- Set = ets_new(set,[set]),
- Bag = ets_new(bag,[bag]),
- Key = {foo,bar},
-
- %% insert some value
- ets:insert(Set,{Key,val1}),
- ets:insert(Bag,{Key,val1}),
-
- %% insert new value for same key again
- ets:insert(Set,{Key,val2}),
- ets:insert(Bag,{Key,val2}),
-
- %% check
- [{Key,val2}] = ets:lookup(Set,Key),
- [{Key,val1},{Key,val2}] = ets:lookup(Bag,Key),
-
- true = ets:delete(Set),
- true = ets:delete(Bag),
+ lists:foreach(fun(SetType) ->
+ Set = ets_new(SetType,[SetType]),
+ Bag = ets_new(bag,[bag]),
+ Key = {foo,bar},
+
+ %% insert some value
+ ets:insert(Set,{Key,val1}),
+ ets:insert(Bag,{Key,val1}),
+
+ %% insert new value for same key again
+ ets:insert(Set,{Key,val2}),
+ ets:insert(Bag,{Key,val2}),
+
+ %% check
+ [{Key,val2}] = ets:lookup(Set,Key),
+ [{Key,val1},{Key,val2}] = ets:lookup(Bag,Key),
+
+ true = ets:delete(Set),
+ true = ets:delete(Bag)
+ end, [set, cat_ord_set,stim_cat_ord_set,ordered_set]),
verify_etsmem(EtsMem).
%% Test case to check proper return values for illegal ets_new() calls.
badnew(Config) when is_list(Config) ->
EtsMem = etsmem(),
- {'EXIT',{badarg,_}} = (catch ets_new(12,[])),
- {'EXIT',{badarg,_}} = (catch ets_new({a,b},[])),
- {'EXIT',{badarg,_}} = (catch ets_new(name,[foo])),
- {'EXIT',{badarg,_}} = (catch ets_new(name,{bag})),
- {'EXIT',{badarg,_}} = (catch ets_new(name,bag)),
+ {'EXIT',{badarg,_}} = (catch ets:new(12,[])),
+ {'EXIT',{badarg,_}} = (catch ets:new({a,b},[])),
+ {'EXIT',{badarg,_}} = (catch ets:new(name,[foo])),
+ {'EXIT',{badarg,_}} = (catch ets:new(name,{bag})),
+ {'EXIT',{badarg,_}} = (catch ets:new(name,bag)),
verify_etsmem(EtsMem).
%% OTP-2314. Test case to check that a non-proper list does not
%% crash the emulator.
verybadnew(Config) when is_list(Config) ->
EtsMem = etsmem(),
- {'EXIT',{badarg,_}} = (catch ets_new(verybad,[set|protected])),
+ {'EXIT',{badarg,_}} = (catch ets:new(verybad,[set|protected])),
verify_etsmem(EtsMem).
%% Small check to see if named tables work.
@@ -2993,11 +3263,13 @@ named(Config) when is_list(Config) ->
%% Test case to check if specified keypos works.
keypos2(Config) when is_list(Config) ->
EtsMem = etsmem(),
- Tab = make_table(foo,
- [set,{keypos,2}],
- [{val,key}, {val2,key}]),
- [{val2,key}] = ets:lookup(Tab,key),
- true = ets:delete(Tab),
+ lists:foreach(fun(SetType) ->
+ Tab = make_table(foo,
+ [SetType,{keypos,2}],
+ [{val,key}, {val2,key}]),
+ [{val2,key}] = ets:lookup(Tab,key),
+ true = ets:delete(Tab)
+ end, [set, cat_ord_set,stim_cat_ord_set,ordered_set]),
verify_etsmem(EtsMem).
%% Privacy check. Check that a named(public/private/protected) table
@@ -3089,7 +3361,7 @@ rotate_tuple(Tuple, N) ->
%% Check lookup in an empty table and lookup of a non-existing key.
empty(Config) when is_list(Config) ->
- repeat_for_opts(fun empty_do/1).
+ repeat_for_opts_all_table_types(fun empty_do/1).
empty_do(Opts) ->
EtsMem = etsmem(),
@@ -3102,7 +3374,7 @@ empty_do(Opts) ->
%% Check proper return values for illegal insert operations.
badinsert(Config) when is_list(Config) ->
- repeat_for_opts(fun badinsert_do/1).
+ repeat_for_opts_all_table_types(fun badinsert_do/1).
badinsert_do(Opts) ->
EtsMem = etsmem(),
@@ -3122,31 +3394,6 @@ badinsert_do(Opts) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Test lookup timing.
-time_lookup(Config) when is_list(Config) ->
- %% just for timing, really
- EtsMem = etsmem(),
- Values = repeat_for_opts(fun time_lookup_do/1),
- verify_etsmem(EtsMem),
- {comment,lists:flatten(io_lib:format(
- "~p ets lookups/s",[Values]))}.
-
-time_lookup_do(Opts) ->
- Tab = ets_new(foo,Opts),
- fill_tab(Tab,foo),
- ets:insert(Tab,{{a,key},foo}),
- N = 100000,
- {Time,_} = timer:tc(fun() -> time_lookup_many(N, Tab) end),
- Seconds = Time / 1000000,
- true = ets:delete(Tab),
- round(N / Seconds). % lookups/s
-
-time_lookup_many(0, _Tab) ->
- ok;
-time_lookup_many(N, Tab) ->
- ets:lookup(Tab, {a,key}),
- time_lookup_many(N-1, Tab).
-
%% Check proper return values from bad lookups in existing/non existing
%% ets tables.
badlookup(Config) when is_list(Config) ->
@@ -3323,19 +3570,29 @@ delete_tab_do(Opts) ->
%% Check that ets:delete/1 works and that other processes can run.
delete_large_tab(Config) when is_list(Config) ->
- ct:timetrap({minutes,30}), %% valgrind needs a lot
- Data = [{erlang:phash2(I, 16#ffffff),I} || I <- lists:seq(1, 200000)],
+ ct:timetrap({minutes,60}), %% valgrind needs a lot
+ KeyRange = 16#ffffff,
+ Data = [{erlang:phash2(I, KeyRange),I} || I <- lists:seq(1, 200000)],
EtsMem = etsmem(),
- repeat_for_opts(fun(Opts) -> delete_large_tab_do(Opts,Data) end),
+ repeat_for_opts(fun(Opts) -> delete_large_tab_do(key_range(Opts,KeyRange),
+ Data) end),
verify_etsmem(EtsMem).
delete_large_tab_do(Opts,Data) ->
delete_large_tab_1(foo_hash, Opts, Data, false),
delete_large_tab_1(foo_tree, [ordered_set | Opts], Data, false),
- delete_large_tab_1(foo_hash, Opts, Data, true).
+ delete_large_tab_1(foo_tree, [stim_cat_ord_set | Opts], Data, false),
+ delete_large_tab_1(foo_hash_fix, Opts, Data, true).
delete_large_tab_1(Name, Flags, Data, Fix) ->
+ case is_redundant_opts_combo(Flags) of
+ true -> skip;
+ false ->
+ delete_large_tab_2(Name, Flags, Data, Fix)
+ end.
+
+delete_large_tab_2(Name, Flags, Data, Fix) ->
Tab = ets_new(Name, Flags),
ets:insert(Tab, Data),
@@ -3394,18 +3651,30 @@ delete_large_tab_1(Name, Flags, Data, Fix) ->
%% Delete a large name table and try to create a new table with
%% the same name in another process.
delete_large_named_table(Config) when is_list(Config) ->
- Data = [{erlang:phash2(I, 16#ffffff),I} || I <- lists:seq(1, 200000)],
+ KeyRange = 16#ffffff,
+ Data = [{erlang:phash2(I, KeyRange),I} || I <- lists:seq(1, 200000)],
EtsMem = etsmem(),
- repeat_for_opts(fun(Opts) -> delete_large_named_table_do(Opts,Data) end),
+ repeat_for_opts(fun(Opts) ->
+ delete_large_named_table_do(key_range(Opts,KeyRange),
+ Data)
+ end),
verify_etsmem(EtsMem),
ok.
delete_large_named_table_do(Opts,Data) ->
delete_large_named_table_1(foo_hash, [named_table | Opts], Data, false),
delete_large_named_table_1(foo_tree, [ordered_set,named_table | Opts], Data, false),
+ delete_large_named_table_1(foo_tree, [stim_cat_ord_set,named_table | Opts], Data, false),
delete_large_named_table_1(foo_hash, [named_table | Opts], Data, true).
delete_large_named_table_1(Name, Flags, Data, Fix) ->
+ case is_redundant_opts_combo(Flags) of
+ true -> skip;
+ false ->
+ delete_large_named_table_2(Name, Flags, Data, Fix)
+ end.
+
+delete_large_named_table_2(Name, Flags, Data, Fix) ->
Tab = ets_new(Name, Flags),
ets:insert(Tab, Data),
@@ -3429,8 +3698,12 @@ delete_large_named_table_1(Name, Flags, Data, Fix) ->
%% Delete a large table, and kill the process during the delete.
evil_delete(Config) when is_list(Config) ->
- Data = [{I,I*I} || I <- lists:seq(1, 100000)],
- repeat_for_opts(fun(Opts) -> evil_delete_do(Opts,Data) end).
+ KeyRange = 100000,
+ Data = [{I,I*I} || I <- lists:seq(1, KeyRange)],
+ repeat_for_opts(fun(Opts) ->
+ evil_delete_do(key_range(Opts,KeyRange),
+ Data)
+ end).
evil_delete_do(Opts,Data) ->
EtsMem = etsmem(),
@@ -3440,16 +3713,27 @@ evil_delete_do(Opts,Data) ->
verify_etsmem(EtsMem),
evil_delete_owner(foo_tree, [ordered_set | Opts], Data, false),
verify_etsmem(EtsMem),
+ evil_delete_owner(foo_catree, [stim_cat_ord_set | Opts], Data, false),
+ verify_etsmem(EtsMem),
TabA = evil_delete_not_owner(foo_hash, Opts, Data, false),
verify_etsmem(EtsMem),
TabB = evil_delete_not_owner(foo_hash, Opts, Data, true),
verify_etsmem(EtsMem),
TabC = evil_delete_not_owner(foo_tree, [ordered_set | Opts], Data, false),
verify_etsmem(EtsMem),
+ TabD = evil_delete_not_owner(foo_catree, [stim_cat_ord_set | Opts], Data, false),
+ verify_etsmem(EtsMem),
lists:foreach(fun(T) -> undefined = ets:info(T) end,
- [TabA,TabB,TabC]).
+ [TabA,TabB,TabC,TabD]).
evil_delete_not_owner(Name, Flags, Data, Fix) ->
+ case is_redundant_opts_combo(Flags) of
+ true -> skip;
+ false ->
+ evil_delete_not_owner_1(Name, Flags, Data, Fix)
+ end.
+
+evil_delete_not_owner_1(Name, Flags, Data, Fix) ->
io:format("Not owner: ~p, fix = ~p", [Name,Fix]),
Tab = ets_new(Name, [public|Flags]),
ets:insert(Tab, Data),
@@ -3475,6 +3759,13 @@ evil_delete_not_owner(Name, Flags, Data, Fix) ->
Tab.
evil_delete_owner(Name, Flags, Data, Fix) ->
+ case is_redundant_opts_combo(Flags) of
+ true -> skip;
+ false ->
+ evil_delete_owner_1(Name, Flags, Data, Fix)
+ end.
+
+evil_delete_owner_1(Name, Flags, Data, Fix) ->
Fun = fun() ->
Tab = ets_new(Name, [public|Flags]),
ets:insert(Tab, Data),
@@ -3652,7 +3943,7 @@ verify_rescheduling_exit(Config, ForEachData, Flags, Fix, NOTabs, NOProcs) ->
XScheds = count_exit_sched(TP),
io:format("~p XScheds=~p~n",
[TP, XScheds]),
- true = XScheds >= 5
+ true = XScheds >= 3
end,
TPs),
stop_loopers(LPs),
@@ -3662,7 +3953,7 @@ verify_rescheduling_exit(Config, ForEachData, Flags, Fix, NOTabs, NOProcs) ->
%% Make sure that slots for ets tables are cleared properly.
table_leak(Config) when is_list(Config) ->
- repeat_for_opts(fun(Opts) -> table_leak_1(Opts,20000) end).
+ repeat_for_opts_all_non_stim_table_types(fun(Opts) -> table_leak_1(Opts,20000) end).
table_leak_1(_,0) -> ok;
table_leak_1(Opts,N) ->
@@ -3725,7 +4016,7 @@ match_delete3_do(Opts) ->
%% Test ets:first/1 & ets:next/2.
firstnext(Config) when is_list(Config) ->
- repeat_for_opts(fun firstnext_do/1).
+ repeat_for_opts_all_set_table_types(fun firstnext_do/1).
firstnext_do(Opts) ->
EtsMem = etsmem(),
@@ -3747,15 +4038,20 @@ firstnext_collect(Tab,Key,List) ->
%% Tests ets:first/1 & ets:next/2.
firstnext_concurrent(Config) when is_list(Config) ->
- register(master, self()),
- ets_init(?MODULE, 20),
- [dynamic_go() || _ <- lists:seq(1, 2)],
- receive
- after 5000 -> ok
- end.
+ lists:foreach(
+ fun(TableType) ->
+ register(master, self()),
+ TableName = list_to_atom(atom_to_list(?MODULE) ++ atom_to_list(TableType)),
+ ets_init(TableName, 20, TableType),
+ [dynamic_go(TableName) || _ <- lists:seq(1, 2)],
+ receive
+ after 5000 -> ok
+ end,
+ unregister(master)
+ end, repeat_for_opts_atom2list(ord_set_types)).
-ets_init(Tab, N) ->
- ets_new(Tab, [named_table,public,ordered_set]),
+ets_init(Tab, N, TableType) ->
+ ets_new(Tab, [named_table,public,TableType]),
cycle(Tab, lists:seq(1,N+1)).
cycle(_Tab, [H|T]) when H > length(T)-> ok;
@@ -3763,9 +4059,9 @@ cycle(Tab, L) ->
ets:insert(Tab,list_to_tuple(L)),
cycle(Tab, tl(L)++[hd(L)]).
-dynamic_go() -> my_spawn_link(fun dynamic_init/0).
+dynamic_go(TableName) -> my_spawn_link(fun() -> dynamic_init(TableName) end).
-dynamic_init() -> [dyn_lookup(?MODULE) || _ <- lists:seq(1, 10)].
+dynamic_init(TableName) -> [dyn_lookup(TableName) || _ <- lists:seq(1, 10)].
dyn_lookup(T) -> dyn_lookup(T, ets:first(T)).
@@ -3783,7 +4079,7 @@ dyn_lookup(T, K) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
slot(Config) when is_list(Config) ->
- repeat_for_opts(fun slot_do/1).
+ repeat_for_opts_all_set_table_types(fun slot_do/1).
slot_do(Opts) ->
EtsMem = etsmem(),
@@ -3791,6 +4087,11 @@ slot_do(Opts) ->
fill_tab(Tab,foo),
Elts = ets:info(Tab,size),
Elts = slot_loop(Tab,0,0),
+ case ets:info(Tab, type) of
+ ordered_set ->
+ '$end_of_table' = ets:slot(Tab,Elts);
+ _ -> ok
+ end,
true = ets:delete(Tab),
verify_etsmem(EtsMem).
@@ -3808,7 +4109,7 @@ slot_loop(Tab,SlotNo,EltsSoFar) ->
match1(Config) when is_list(Config) ->
- repeat_for_opts(fun match1_do/1).
+ repeat_for_opts_all_set_table_types(fun match1_do/1).
match1_do(Opts) ->
EtsMem = etsmem(),
@@ -3871,7 +4172,7 @@ match2_do(Opts) ->
%% Some ets:match_object tests.
match_object(Config) when is_list(Config) ->
- repeat_for_opts(fun match_object_do/1).
+ repeat_for_opts_all_set_table_types(fun match_object_do/1).
match_object_do(Opts) ->
EtsMem = etsmem(),
@@ -3971,23 +4272,16 @@ match_object_do(Opts) ->
%% Tests that db_match_object does not generate a `badarg' when
%% resuming a search with no previous matches.
match_object2(Config) when is_list(Config) ->
- repeat_for_opts(fun match_object2_do/1).
+ repeat_for_opts_all_table_types(fun match_object2_do/1).
match_object2_do(Opts) ->
EtsMem = etsmem(),
- Tab = ets_new(foo, [bag, {keypos, 2} | Opts]),
- fill_tab2(Tab, 0, 13005), % match_db_object does 1000
+ KeyRange = 13005,
+ Tab = ets_new(foo, [{keypos, 2} | Opts], KeyRange),
+ fill_tab2(Tab, 0, KeyRange), % match_db_object does 1000
% elements per pass, might
% change in the future.
- case catch ets:match_object(Tab, {hej, '$1'}) of
- {'EXIT', _} ->
- ets:delete(Tab),
- ct:fail("match_object EXIT:ed");
- [] ->
- io:format("Nothing matched.");
- List ->
- io:format("Matched:~p~n",[List])
- end,
+ [] = ets:match_object(Tab, {hej, '$1'}),
ets:delete(Tab),
verify_etsmem(EtsMem).
@@ -3996,18 +4290,21 @@ match_object2_do(Opts) ->
%% OTP-3319. Test tab2list.
tab2list(Config) when is_list(Config) ->
- EtsMem = etsmem(),
- Tab = make_table(foo,
- [ordered_set],
- [{a,b}, {c,b}, {b,b}, {a,c}]),
- [{a,c},{b,b},{c,b}] = ets:tab2list(Tab),
- true = ets:delete(Tab),
- verify_etsmem(EtsMem).
+ repeat_for_all_ord_set_table_types(
+ fun(Opts) ->
+ EtsMem = etsmem(),
+ Tab = make_table(foo,
+ Opts,
+ [{a,b}, {c,b}, {b,b}, {a,c}]),
+ [{a,c},{b,b},{c,b}] = ets:tab2list(Tab),
+ true = ets:delete(Tab),
+ verify_etsmem(EtsMem)
+ end).
%% Simple general small test. If this fails, ets is in really bad
%% shape.
misc1(Config) when is_list(Config) ->
- repeat_for_opts(fun misc1_do/1).
+ repeat_for_opts_all_table_types(fun misc1_do/1).
misc1_do(Opts) ->
EtsMem = etsmem(),
@@ -4025,7 +4322,7 @@ misc1_do(Opts) ->
%% Check the safe_fixtable function.
safe_fixtable(Config) when is_list(Config) ->
- repeat_for_opts(fun safe_fixtable_do/1).
+ repeat_for_opts_all_table_types(fun safe_fixtable_do/1).
safe_fixtable_do(Opts) ->
EtsMem = etsmem(),
@@ -4083,10 +4380,42 @@ safe_fixtable_do(Opts) ->
%% Tests ets:info result for required tuples.
info(Config) when is_list(Config) ->
- repeat_for_opts(fun info_do/1).
+ repeat_for_opts_all_table_types(fun info_do/1).
info_do(Opts) ->
EtsMem = etsmem(),
+ TableType = lists:foldl(
+ fun(Item, Curr) ->
+ case Item of
+ set -> set;
+ ordered_set -> ordered_set;
+ cat_ord_set -> ordered_set;
+ stim_cat_ord_set -> ordered_set;
+ bag -> bag;
+ duplicate_bag -> duplicate_bag;
+ _ -> Curr
+ end
+ end, set, Opts),
+ PublicOrCurr =
+ fun(Curr) ->
+ case lists:member({write_concurrency, false}, Opts) or
+ lists:member(private, Opts) or
+ lists:member(protected, Opts) of
+ true -> Curr;
+ false -> public
+ end
+ end,
+ Protection = lists:foldl(
+ fun(Item, Curr) ->
+ case Item of
+ public -> public;
+ protected -> protected;
+ private -> private;
+ cat_ord_set -> PublicOrCurr(Curr); %% Special items
+ stim_cat_ord_set -> PublicOrCurr(Curr);
+ _ -> Curr
+ end
+ end, protected, Opts),
MeMyselfI=self(),
ThisNode=node(),
Tab = ets_new(foobar, [{keypos, 2} | Opts]),
@@ -4100,10 +4429,11 @@ info_do(Opts) ->
{value, {size, 0}} = lists:keysearch(size, 1, Res),
{value, {node, ThisNode}} = lists:keysearch(node, 1, Res),
{value, {named_table, false}} = lists:keysearch(named_table, 1, Res),
- {value, {type, set}} = lists:keysearch(type, 1, Res),
+ {value, {type, TableType}} = lists:keysearch(type, 1, Res),
{value, {keypos, 2}} = lists:keysearch(keypos, 1, Res),
- {value, {protection, protected}} =
+ {value, {protection, Protection}} =
lists:keysearch(protection, 1, Res),
+ {value, {id, Tab}} = lists:keysearch(id, 1, Res),
true = ets:delete(Tab),
undefined = ets:info(non_existing_table_xxyy),
undefined = ets:info(non_existing_table_xxyy,type),
@@ -4113,6 +4443,131 @@ info_do(Opts) ->
undefined = ets:info(non_existing_table_xxyy,safe_fixed),
verify_etsmem(EtsMem).
+size_loop(_T, 0, _, _) ->
+ ok;
+size_loop(T, I, PrevSize, WhatToTest) ->
+ Size = ets:info(T, WhatToTest),
+ case Size < PrevSize of
+ true -> ct:fail("Bad ets:info/2");
+ _ -> ok
+ end,
+ size_loop(T, I -1, Size, WhatToTest).
+
+add_loop(_T, 0) ->
+ ok;
+add_loop(T, I) ->
+ ets:insert(T, {I}),
+ add_loop(T, I -1).
+
+
+test_table_counter_concurrency(WhatToTest) ->
+ IntStatePrevOn =
+ erts_debug:set_internal_state(available_internal_state, true),
+ ItemsToAdd = 1000000,
+ SizeLoopSize = 1000,
+ T = ets:new(k, [public, ordered_set, {write_concurrency, true}]),
+ erts_debug:set_internal_state(ets_debug_random_split_join, {T, false}),
+ 0 = ets:info(T, size),
+ P = self(),
+ SpawnedSizeProcs =
+ [spawn_link(fun() ->
+ size_loop(T, SizeLoopSize, 0, WhatToTest),
+ P ! done
+ end)
+ || _ <- lists:seq(1, 6)],
+ spawn_link(fun() ->
+ add_loop(T, ItemsToAdd),
+ P ! done_add
+ end),
+ [receive
+ done -> ok;
+ done_add -> ok
+ end
+ || _ <- [ok|SpawnedSizeProcs]],
+ case WhatToTest =:= size of
+ true ->
+ ItemsToAdd = ets:info(T, size);
+ _ ->
+ ok
+ end,
+ erts_debug:set_internal_state(available_internal_state, IntStatePrevOn),
+ ok.
+
+test_table_size_concurrency(Config) when is_list(Config) ->
+ test_table_counter_concurrency(size).
+
+test_table_memory_concurrency(Config) when is_list(Config) ->
+ test_table_counter_concurrency(memory).
+
+%% Tests that calling the ets:delete operation on a table T with
+%% decentralized counters works while ets:info(T, size) operations are
+%% active
+test_delete_table_while_size_snapshot(Config) when is_list(Config) ->
+ %% Run test case in a slave node as other test suites in stdlib
+ %% depend on that pids are ordered in creation order which is no
+ %% longer the case when many processes have been started before
+ Node = start_slave(),
+ ok = rpc:call(Node, ?MODULE, test_delete_table_while_size_snapshot_helper, []),
+ test_server:stop_node(Node),
+ ok.
+
+test_delete_table_while_size_snapshot_helper()->
+ TopParent = self(),
+ repeat_par(
+ fun() ->
+ Table = ets:new(t, [public, ordered_set,
+ {write_concurrency, true}]),
+ Parent = self(),
+ NrOfSizeProcs = 100,
+ Pids = [ spawn(fun()-> size_process(Table, Parent) end)
+ || _ <- lists:seq(1, NrOfSizeProcs)],
+ timer:sleep(1),
+ ets:delete(Table),
+ [receive
+ table_gone -> ok;
+ Problem -> TopParent ! Problem
+ end || _ <- Pids]
+ end,
+ 15000),
+ receive
+ Problem -> throw(Problem)
+ after 0 -> ok
+ end.
+
+size_process(Table, Parent) ->
+ try ets:info(Table, size) of
+ N when is_integer(N) ->
+ size_process(Table, Parent);
+ undefined -> Parent ! table_gone;
+ E -> Parent ! {got_unexpected, E}
+ catch
+ E -> Parent ! {got_unexpected_exception, E}
+ end.
+
+start_slave() ->
+ MicroSecs = erlang:monotonic_time(),
+ Name = "ets_" ++ integer_to_list(MicroSecs),
+ Pa = filename:dirname(code:which(?MODULE)),
+ {ok, Node} = test_server:start_node(list_to_atom(Name), slave, [{args, "-pa " ++ Pa}]),
+ Node.
+
+repeat_par(FunToRepeat, NrOfTimes) ->
+ repeat_par_help(FunToRepeat, NrOfTimes, NrOfTimes).
+
+repeat_par_help(_FunToRepeat, 0, OrgNrOfTimes) ->
+ repeat(fun()-> receive done -> ok end end, OrgNrOfTimes);
+repeat_par_help(FunToRepeat, NrOfTimes, OrgNrOfTimes) ->
+ Parent = self(),
+ case NrOfTimes rem 5 of
+ 0 -> timer:sleep(1);
+ _ -> ok
+ end,
+ spawn(fun()->
+ FunToRepeat(),
+ Parent ! done
+ end),
+ repeat_par_help(FunToRepeat, NrOfTimes-1, OrgNrOfTimes).
+
%% Test various duplicate_bags stuff.
dups(Config) when is_list(Config) ->
repeat_for_opts(fun dups_do/1).
@@ -4146,20 +4601,29 @@ dups_do(Opts) ->
%% Test the ets:tab2file function on an empty ets table.
tab2file(Config) when is_list(Config) ->
FName = filename:join([proplists:get_value(priv_dir, Config),"tab2file_case"]),
- tab2file_do(FName, []),
- tab2file_do(FName, [{sync,true}]),
- tab2file_do(FName, [{sync,false}]),
- {'EXIT',{{badmatch,{error,_}},_}} = (catch tab2file_do(FName, [{sync,yes}])),
- {'EXIT',{{badmatch,{error,_}},_}} = (catch tab2file_do(FName, [sync])),
+ tab2file_do(FName, [], set),
+ tab2file_do(FName, [], ordered_set),
+ tab2file_do(FName, [], cat_ord_set),
+ tab2file_do(FName, [], stim_cat_ord_set),
+ tab2file_do(FName, [{sync,true}], set),
+ tab2file_do(FName, [{sync,false}], set),
+ {'EXIT',{{badmatch,{error,_}},_}} = (catch tab2file_do(FName, [{sync,yes}], set)),
+ {'EXIT',{{badmatch,{error,_}},_}} = (catch tab2file_do(FName, [sync], set)),
ok.
-tab2file_do(FName, Opts) ->
+tab2file_do(FName, Opts, TableType) ->
%% Write an empty ets table to a file, read back and check properties.
- Tab = ets_new(ets_SUITE_foo_tab, [named_table, set, public,
+ Tab = ets_new(ets_SUITE_foo_tab, [named_table, TableType, public,
{keypos, 2},
compressed,
{write_concurrency,true},
{read_concurrency,true}]),
+ ActualTableType =
+ case TableType of
+ cat_ord_set -> ordered_set;
+ stim_cat_ord_set -> ordered_set;
+ _ -> TableType
+ end,
catch file:delete(FName),
Res = ets:tab2file(Tab, FName, Opts),
true = ets:delete(Tab),
@@ -4170,7 +4634,7 @@ tab2file_do(FName, Opts) ->
public = ets:info(Tab2, protection),
true = ets:info(Tab2, named_table),
2 = ets:info(Tab2, keypos),
- set = ets:info(Tab2, type),
+ ActualTableType = ets:info(Tab2, type),
true = ets:info(Tab2, compressed),
Smp = erlang:system_info(smp_support),
Smp = ets:info(Tab2, read_concurrency),
@@ -4183,14 +4647,15 @@ tab2file_do(FName, Opts) ->
tab2file2(Config) when is_list(Config) ->
repeat_for_opts(fun(Opts) ->
tab2file2_do(Opts, Config)
- end, [[set,bag],compressed]).
+ end, [[stim_cat_ord_set,cat_ord_set,set,bag],compressed]).
tab2file2_do(Opts, Config) ->
EtsMem = etsmem(),
- Tab = ets_new(ets_SUITE_foo_tab, [named_table, private,
- {keypos, 2} | Opts]),
+ KeyRange = 10000,
+ Tab = ets_new(ets_SUITE_foo_tab, [named_table, private, {keypos, 2} | Opts],
+ KeyRange),
FName = filename:join([proplists:get_value(priv_dir, Config),"tab2file2_case"]),
- ok = fill_tab2(Tab, 0, 10000), % Fill up the table (grucho mucho!)
+ ok = fill_tab2(Tab, 0, KeyRange), % Fill up the table (grucho mucho!)
Len = length(ets:tab2list(Tab)),
Mem = ets:info(Tab, memory),
Type = ets:info(Tab, type),
@@ -4244,13 +4709,14 @@ fill_tab2(Tab, Val, Num) ->
%% Test verification of tables with object count extended_info.
tabfile_ext1(Config) when is_list(Config) ->
- repeat_for_opts(fun(Opts) -> tabfile_ext1_do(Opts, Config) end).
+ repeat_for_opts_all_set_table_types(fun(Opts) -> tabfile_ext1_do(Opts, Config) end).
tabfile_ext1_do(Opts,Config) ->
FName = filename:join([proplists:get_value(priv_dir, Config),"nisse.dat"]),
FName2 = filename:join([proplists:get_value(priv_dir, Config),"countflip.dat"]),
- L = lists:seq(1,10),
- T = ets_new(x,Opts),
+ KeyRange = 10,
+ L = lists:seq(1,KeyRange),
+ T = ets_new(x,Opts,KeyRange),
Name = make_ref(),
[ets:insert(T,{X,integer_to_list(X)}) || X <- L],
ok = ets:tab2file(T,FName,[{extended_info,[object_count]}]),
@@ -4282,13 +4748,14 @@ tabfile_ext1_do(Opts,Config) ->
%% Test verification of tables with md5sum extended_info.
tabfile_ext2(Config) when is_list(Config) ->
- repeat_for_opts(fun(Opts) -> tabfile_ext2_do(Opts,Config) end).
+ repeat_for_opts_all_set_table_types(fun(Opts) -> tabfile_ext2_do(Opts,Config) end).
tabfile_ext2_do(Opts,Config) ->
FName = filename:join([proplists:get_value(priv_dir, Config),"olle.dat"]),
FName2 = filename:join([proplists:get_value(priv_dir, Config),"bitflip.dat"]),
- L = lists:seq(1,10),
- T = ets_new(x,Opts),
+ KeyRange = 10,
+ L = lists:seq(1, KeyRange),
+ T = ets_new(x, Opts, KeyRange),
Name = make_ref(),
[ets:insert(T,{X,integer_to_list(X)}) || X <- L],
ok = ets:tab2file(T,FName,[{extended_info,[md5sum]}]),
@@ -4319,71 +4786,77 @@ tabfile_ext2_do(Opts,Config) ->
%% Test verification of (named) tables without extended info.
tabfile_ext3(Config) when is_list(Config) ->
- FName = filename:join([proplists:get_value(priv_dir, Config),"namn.dat"]),
- FName2 = filename:join([proplists:get_value(priv_dir, Config),"ncountflip.dat"]),
- L = lists:seq(1,10),
- Name = make_ref(),
- ?MODULE = ets_new(?MODULE,[named_table]),
- [ets:insert(?MODULE,{X,integer_to_list(X)}) || X <- L],
- ets:tab2file(?MODULE,FName),
- {error,cannot_create_table} = ets:file2tab(FName),
- true = ets:delete(?MODULE),
- {ok,?MODULE} = ets:file2tab(FName),
- true = ets:delete(?MODULE),
- disk_log:open([{name,Name},{file,FName}]),
- {_,[H2|T2]} = disk_log:chunk(Name,start),
- disk_log:close(Name),
- NewT2=lists:keydelete(8,1,T2),
- file:delete(FName2),
- disk_log:open([{name,Name},{file,FName2},{mode,read_write}]),
- disk_log:log_terms(Name,[H2|NewT2]),
- disk_log:close(Name),
- 9 = length(ets:tab2list(element(2,ets:file2tab(FName2)))),
- true = ets:delete(?MODULE),
- {error,invalid_object_count} = ets:file2tab(FName2,[{verify,true}]),
- {'EXIT',_} = (catch ets:delete(?MODULE)),
- {ok,_} = ets:tabfile_info(FName2),
- {ok,_} = ets:tabfile_info(FName),
- file:delete(FName),
- file:delete(FName2),
+ repeat_for_all_set_table_types(
+ fun(Opts) ->
+ FName = filename:join([proplists:get_value(priv_dir, Config),"namn.dat"]),
+ FName2 = filename:join([proplists:get_value(priv_dir, Config),"ncountflip.dat"]),
+ L = lists:seq(1,10),
+ Name = make_ref(),
+ ?MODULE = ets_new(?MODULE,[named_table|Opts]),
+ [ets:insert(?MODULE,{X,integer_to_list(X)}) || X <- L],
+ ets:tab2file(?MODULE,FName),
+ {error,cannot_create_table} = ets:file2tab(FName),
+ true = ets:delete(?MODULE),
+ {ok,?MODULE} = ets:file2tab(FName),
+ true = ets:delete(?MODULE),
+ disk_log:open([{name,Name},{file,FName}]),
+ {_,[H2|T2]} = disk_log:chunk(Name,start),
+ disk_log:close(Name),
+ NewT2=lists:keydelete(8,1,T2),
+ file:delete(FName2),
+ disk_log:open([{name,Name},{file,FName2},{mode,read_write}]),
+ disk_log:log_terms(Name,[H2|NewT2]),
+ disk_log:close(Name),
+ 9 = length(ets:tab2list(element(2,ets:file2tab(FName2)))),
+ true = ets:delete(?MODULE),
+ {error,invalid_object_count} = ets:file2tab(FName2,[{verify,true}]),
+ {'EXIT',_} = (catch ets:delete(?MODULE)),
+ {ok,_} = ets:tabfile_info(FName2),
+ {ok,_} = ets:tabfile_info(FName),
+ file:delete(FName),
+ file:delete(FName2)
+ end),
ok.
%% Tests verification of large table with md5 sum.
tabfile_ext4(Config) when is_list(Config) ->
- FName = filename:join([proplists:get_value(priv_dir, Config),"bauta.dat"]),
- LL = lists:seq(1,10000),
- TL = ets_new(x,[]),
- Name2 = make_ref(),
- [ets:insert(TL,{X,integer_to_list(X)}) || X <- LL],
- ok = ets:tab2file(TL,FName,[{extended_info,[md5sum]}]),
- {ok, Name2} = disk_log:open([{name, Name2}, {file, FName},
- {mode, read_only}]),
- {C,[_|_]} = disk_log:chunk(Name2,start),
- {_,[_|_]} = disk_log:chunk(Name2,C),
- disk_log:close(Name2),
- true = lists:sort(ets:tab2list(TL)) =:=
- lists:sort(ets:tab2list(element(2,ets:file2tab(FName)))),
- Res = [begin
- {ok,FD} = file:open(FName,[binary,read,write]),
- {ok, Bin} = file:pread(FD,0,1000),
- <<B1:N/binary,Ch:8,B2/binary>> = Bin,
- Ch2 = (Ch + 1) rem 255,
- Bin2 = <<B1/binary,Ch2:8,B2/binary>>,
- ok = file:pwrite(FD,0,Bin2),
- ok = file:close(FD),
- X = case ets:file2tab(FName) of
- {ok,TL2} ->
- true = lists:sort(ets:tab2list(TL)) =/=
- lists:sort(ets:tab2list(TL2));
- _ ->
- totally_broken
- end,
- {error,Y} = ets:file2tab(FName,[{verify,true}]),
- ets:tab2file(TL,FName,[{extended_info,[md5sum]}]),
- {X,Y}
- end || N <- lists:seq(500,600)],
- io:format("~p~n",[Res]),
- file:delete(FName),
+ repeat_for_all_set_table_types(
+ fun(Opts) ->
+ FName = filename:join([proplists:get_value(priv_dir, Config),"bauta.dat"]),
+ LL = lists:seq(1,10000),
+ TL = ets_new(x,Opts),
+ Name2 = make_ref(),
+ [ets:insert(TL,{X,integer_to_list(X)}) || X <- LL],
+ ok = ets:tab2file(TL,FName,[{extended_info,[md5sum]}]),
+ {ok, Name2} = disk_log:open([{name, Name2}, {file, FName},
+ {mode, read_only}]),
+ {C,[_|_]} = disk_log:chunk(Name2,start),
+ {_,[_|_]} = disk_log:chunk(Name2,C),
+ disk_log:close(Name2),
+ true = lists:sort(ets:tab2list(TL)) =:=
+ lists:sort(ets:tab2list(element(2,ets:file2tab(FName)))),
+ Res = [begin
+ {ok,FD} = file:open(FName,[binary,read,write]),
+ {ok, Bin} = file:pread(FD,0,1000),
+ <<B1:N/binary,Ch:8,B2/binary>> = Bin,
+ Ch2 = (Ch + 1) rem 255,
+ Bin2 = <<B1/binary,Ch2:8,B2/binary>>,
+ ok = file:pwrite(FD,0,Bin2),
+ ok = file:close(FD),
+ X = case ets:file2tab(FName) of
+ {ok,TL2} ->
+ true = lists:sort(ets:tab2list(TL)) =/=
+ lists:sort(ets:tab2list(TL2));
+ _ ->
+ totally_broken
+ end,
+ {error,Y} = ets:file2tab(FName,[{verify,true}]),
+ ets:tab2file(TL,FName,[{extended_info,[md5sum]}]),
+ {X,Y}
+ end || N <- lists:seq(500,600)],
+ io:format("~p~n",[Res]),
+ file:delete(FName)
+ end),
ok.
%% Test that no disk_log is left open when file has been corrupted.
@@ -4447,13 +4920,14 @@ make_sub_binary(List, Num) when is_list(List) ->
%% Perform multiple lookups for every key in a large table.
heavy_lookup(Config) when is_list(Config) ->
- repeat_for_opts(fun heavy_lookup_do/1).
+ repeat_for_opts_all_set_table_types(fun heavy_lookup_do/1).
heavy_lookup_do(Opts) ->
EtsMem = etsmem(),
- Tab = ets_new(foobar_table, [set, protected, {keypos, 2} | Opts]),
- ok = fill_tab2(Tab, 0, 7000),
- _ = [do_lookup(Tab, 6999) || _ <- lists:seq(1, 50)],
+ KeyRange = 7000,
+ Tab = ets_new(foobar_table, [{keypos, 2} | Opts], KeyRange),
+ ok = fill_tab2(Tab, 0, KeyRange),
+ _ = [do_lookup(Tab, KeyRange-1) || _ <- lists:seq(1, 50)],
true = ets:delete(Tab),
verify_etsmem(EtsMem).
@@ -4470,15 +4944,16 @@ do_lookup(Tab, N) ->
%% Perform multiple lookups for every element in a large table.
heavy_lookup_element(Config) when is_list(Config) ->
- repeat_for_opts(fun heavy_lookup_element_do/1).
+ repeat_for_opts_all_set_table_types(fun heavy_lookup_element_do/1).
heavy_lookup_element_do(Opts) ->
EtsMem = etsmem(),
- Tab = ets_new(foobar_table, [set, protected, {keypos, 2} | Opts]),
- ok = fill_tab2(Tab, 0, 7000),
+ KeyRange = 7000,
+ Tab = ets_new(foobar_table, [{keypos, 2} | Opts], KeyRange),
+ ok = fill_tab2(Tab, 0, KeyRange),
%% lookup ALL elements 50 times
Laps = 50 div syrup_factor(),
- _ = [do_lookup_element(Tab, 6999, 1) || _ <- lists:seq(1, Laps)],
+ _ = [do_lookup_element(Tab, KeyRange-1, 1) || _ <- lists:seq(1, Laps)],
true = ets:delete(Tab),
verify_etsmem(EtsMem).
@@ -4497,15 +4972,15 @@ do_lookup_element(Tab, N, M) ->
heavy_concurrent(Config) when is_list(Config) ->
- ct:timetrap({minutes,30}), %% valgrind needs a lot of time
- repeat_for_opts(fun do_heavy_concurrent/1).
+ ct:timetrap({minutes,120}), %% valgrind needs a lot of time
+ repeat_for_opts_all_set_table_types(fun do_heavy_concurrent/1).
do_heavy_concurrent(Opts) ->
- Size = 10000,
+ KeyRange = 10000,
Laps = 10000 div syrup_factor(),
EtsMem = etsmem(),
- Tab = ets_new(blupp, [set, public, {keypos, 2} | Opts]),
- ok = fill_tab2(Tab, 0, Size),
+ Tab = ets_new(blupp, [public, {keypos, 2} | Opts], KeyRange),
+ ok = fill_tab2(Tab, 0, KeyRange),
Procs = lists:map(
fun (N) ->
my_spawn_link(
@@ -4538,48 +5013,68 @@ do_heavy_concurrent_proc(Tab, N, Offs) ->
fold_empty(Config) when is_list(Config) ->
- EtsMem = etsmem(),
- Tab = make_table(a, [], []),
- [] = ets:foldl(fun(_X) -> exit(hej) end, [], Tab),
- [] = ets:foldr(fun(_X) -> exit(hej) end, [], Tab),
- true = ets:delete(Tab),
- verify_etsmem(EtsMem).
+ repeat_for_opts_all_set_table_types(
+ fun(Opts) ->
+ EtsMem = etsmem(),
+ Tab = make_table(a, Opts, []),
+ [] = ets:foldl(fun(_X) -> exit(hej) end, [], Tab),
+ [] = ets:foldr(fun(_X) -> exit(hej) end, [], Tab),
+ true = ets:delete(Tab),
+ verify_etsmem(EtsMem)
+ end),
+ ok.
foldl(Config) when is_list(Config) ->
- EtsMem = etsmem(),
- L = [{a,1}, {c,3}, {b,2}],
- LS = lists:sort(L),
- Tab = make_table(a, [bag], L),
- LS = lists:sort(ets:foldl(fun(E,A) -> [E|A] end, [], Tab)),
- true = ets:delete(Tab),
- verify_etsmem(EtsMem).
+ repeat_for_opts_all_table_types(
+ fun(Opts) ->
+ EtsMem = etsmem(),
+ L = [{a,1}, {c,3}, {b,2}],
+ LS = lists:sort(L),
+ Tab = make_table(a, Opts, L),
+ LS = lists:sort(ets:foldl(fun(E,A) -> [E|A] end, [], Tab)),
+ true = ets:delete(Tab),
+ verify_etsmem(EtsMem)
+ end),
+ ok.
foldr(Config) when is_list(Config) ->
- EtsMem = etsmem(),
- L = [{a,1}, {c,3}, {b,2}],
- LS = lists:sort(L),
- Tab = make_table(a, [bag], L),
- LS = lists:sort(ets:foldr(fun(E,A) -> [E|A] end, [], Tab)),
- true = ets:delete(Tab),
- verify_etsmem(EtsMem).
+ repeat_for_opts_all_table_types(
+ fun(Opts) ->
+ EtsMem = etsmem(),
+ L = [{a,1}, {c,3}, {b,2}],
+ LS = lists:sort(L),
+ Tab = make_table(a, Opts, L),
+ LS = lists:sort(ets:foldr(fun(E,A) -> [E|A] end, [], Tab)),
+ true = ets:delete(Tab),
+ verify_etsmem(EtsMem)
+ end),
+ ok.
foldl_ordered(Config) when is_list(Config) ->
- EtsMem = etsmem(),
- L = [{a,1}, {c,3}, {b,2}],
- LS = lists:sort(L),
- Tab = make_table(a, [ordered_set], L),
- LS = lists:reverse(ets:foldl(fun(E,A) -> [E|A] end, [], Tab)),
- true = ets:delete(Tab),
- verify_etsmem(EtsMem).
+ repeat_for_opts_all_ord_set_table_types(
+ fun(Opts) ->
+ EtsMem = etsmem(),
+ L = [{a,1}, {c,3}, {b,2}],
+ LS = lists:sort(L),
+ Tab = make_table(a, Opts, L),
+ LS = lists:reverse(ets:foldl(fun(E,A) -> [E|A] end, [], Tab)),
+ true = ets:delete(Tab),
+ verify_etsmem(EtsMem)
+ end),
+ ok.
foldr_ordered(Config) when is_list(Config) ->
- EtsMem = etsmem(),
- L = [{a,1}, {c,3}, {b,2}],
- LS = lists:sort(L),
- Tab = make_table(a, [ordered_set], L),
- LS = ets:foldr(fun(E,A) -> [E|A] end, [], Tab),
- true = ets:delete(Tab),
- verify_etsmem(EtsMem).
+ repeat_for_opts_all_ord_set_table_types(
+ fun(Opts) ->
+ EtsMem = etsmem(),
+ L = [{a,1}, {c,3}, {b,2}],
+ LS = lists:sort(L),
+ Tab = make_table(a, Opts, L),
+ LS = ets:foldr(fun(E,A) -> [E|A] end, [], Tab),
+ true = ets:delete(Tab),
+ verify_etsmem(EtsMem)
+ end),
+ ok.
%% Test ets:member BIF.
member(Config) when is_list(Config) ->
@@ -4764,6 +5259,7 @@ filltabint(Tab,0) ->
filltabint(Tab,N) ->
ets:insert(Tab,{N,integer_to_list(N)}),
filltabint(Tab,N-1).
+
filltabint2(Tab,0) ->
Tab;
filltabint2(Tab,N) ->
@@ -4978,27 +5474,31 @@ gen_dets_filename(Config,N) ->
"testdets_" ++ integer_to_list(N) ++ ".dets").
otp_6842_select_1000(Config) when is_list(Config) ->
- Tab = ets_new(xxx,[ordered_set]),
- [ets:insert(Tab,{X,X}) || X <- lists:seq(1,10000)],
- AllTrue = lists:duplicate(10,true),
- AllTrue =
- [ length(
- element(1,
- ets:select(Tab,[{'_',[],['$_']}],X*1000))) =:=
- X*1000 || X <- lists:seq(1,10) ],
- Sequences = [[1000,1000,1000,1000,1000,1000,1000,1000,1000,1000],
- [2000,2000,2000,2000,2000],
- [3000,3000,3000,1000],
- [4000,4000,2000],
- [5000,5000],
- [6000,4000],
- [7000,3000],
- [8000,2000],
- [9000,1000],
- [10000]],
- AllTrue = [ check_seq(Tab, ets:select(Tab,[{'_',[],['$_']}],hd(L)),L) ||
- L <- Sequences ],
- ets:delete(Tab),
+ repeat_for_opts_all_ord_set_table_types(
+ fun(Opts) ->
+ KeyRange = 10000,
+ Tab = ets_new(xxx, Opts, KeyRange),
+ [ets:insert(Tab,{X,X}) || X <- lists:seq(1,KeyRange)],
+ AllTrue = lists:duplicate(10,true),
+ AllTrue =
+ [ length(
+ element(1,
+ ets:select(Tab,[{'_',[],['$_']}],X*1000))) =:=
+ X*1000 || X <- lists:seq(1,10) ],
+ Sequences = [[1000,1000,1000,1000,1000,1000,1000,1000,1000,1000],
+ [2000,2000,2000,2000,2000],
+ [3000,3000,3000,1000],
+ [4000,4000,2000],
+ [5000,5000],
+ [6000,4000],
+ [7000,3000],
+ [8000,2000],
+ [9000,1000],
+ [10000]],
+ AllTrue = [ check_seq(Tab, ets:select(Tab,[{'_',[],['$_']}],hd(L)),L) ||
+ L <- Sequences ],
+ ets:delete(Tab)
+ end),
ok.
check_seq(_,'$end_of_table',[]) ->
@@ -5010,17 +5510,76 @@ check_seq(A,B,C) ->
false.
otp_6338(Config) when is_list(Config) ->
- L = binary_to_term(<<131,108,0,0,0,2,104,2,108,0,0,0,2,103,100,0,19,112,112,
- 98,49,95,98,115,49,50,64,98,108,97,100,101,95,48,95,53,
- 0,0,33,50,0,0,0,4,1,98,0,0,23,226,106,100,0,4,101,120,
- 105,116,104,2,108,0,0,0,2,104,2,100,0,3,115,98,109,100,
- 0,19,112,112,98,50,95,98,115,49,50,64,98,108,97,100,
- 101,95,48,95,56,98,0,0,18,231,106,100,0,4,114,101,99,
- 118,106>>),
- T = ets_new(xxx,[ordered_set]),
- lists:foreach(fun(X) -> ets:insert(T,X) end,L),
- [[4839,recv]] = ets:match(T,{[{sbm,ppb2_bs12@blade_0_8},'$1'],'$2'}),
- ets:delete(T).
+ repeat_for_opts_all_ord_set_table_types(
+ fun(Opts) ->
+ L = binary_to_term(<<131,108,0,0,0,2,104,2,108,0,0,0,2,103,100,0,19,112,112,
+ 98,49,95,98,115,49,50,64,98,108,97,100,101,95,48,95,53,
+ 0,0,33,50,0,0,0,4,1,98,0,0,23,226,106,100,0,4,101,120,
+ 105,116,104,2,108,0,0,0,2,104,2,100,0,3,115,98,109,100,
+ 0,19,112,112,98,50,95,98,115,49,50,64,98,108,97,100,
+ 101,95,48,95,56,98,0,0,18,231,106,100,0,4,114,101,99,
+ 118,106>>),
+ T = ets_new(xxx,Opts),
+ lists:foreach(fun(X) -> ets:insert(T,X) end,L),
+ [[4839,recv]] = ets:match(T,{[{sbm,ppb2_bs12@blade_0_8},'$1'],'$2'}),
+ ets:delete(T)
+ end),
+ ok.
+
+%% OTP-15660: Verify select not doing excessive trapping
+%% when process have mbuf heap fragments.
+select_mbuf_trapping(Config) when is_list(Config) ->
+ select_mbuf_trapping_do(set),
+ select_mbuf_trapping_do(ordered_set).
+
+select_mbuf_trapping_do(Type) ->
+ T = ets:new(xxx, [Type]),
+ NKeys = 50,
+ [ets:insert(T, {K, value}) || K <- lists:seq(1,NKeys)],
+
+ {priority, Prio} = process_info(self(), priority),
+ Tracee = self(),
+ [SchedTracer]
+ = start_loopers(1, Prio,
+ fun (SC) ->
+ receive
+ {trace, Tracee, out, _} ->
+ SC+1;
+ done ->
+ Tracee ! {schedule_count, SC},
+ exit(normal)
+ end
+ end,
+ 0),
+
+ erlang:garbage_collect(),
+ 1 = erlang:trace(self(), true, [running,{tracer,SchedTracer}]),
+
+ %% Artificially create an mbuf heap fragment
+ MbufTerm = "Frag me up",
+ MbufTerm = erts_debug:set_internal_state(mbuf, MbufTerm),
+
+ Keys = ets:select(T, [{{'$1', value}, [], ['$1']}]),
+ NKeys = length(Keys),
+
+ 1 = erlang:trace(self(), false, [running]),
+ Ref = erlang:trace_delivered(Tracee),
+ receive
+ {trace_delivered, Tracee, Ref} ->
+ SchedTracer ! done
+ end,
+ receive
+ {schedule_count, N} ->
+ io:format("~p context switches: ~p", [Type,N]),
+ if
+ N < 3 -> ok;
+ true -> ct:fail(failed)
+ end
+ end,
+ true = ets:delete(T),
+ ok.
+
+
%% Elements could come in the wrong order in a bag if a rehash occurred.
otp_5340(Config) when is_list(Config) ->
@@ -5090,7 +5649,7 @@ otp_7665_act(Tab,Min,Max,DelNr) ->
%% Whitebox testing of meta name table hashing.
meta_wb(Config) when is_list(Config) ->
EtsMem = etsmem(),
- repeat_for_opts(fun meta_wb_do/1),
+ repeat_for_opts_all_non_stim_table_types(fun meta_wb_do/1),
verify_etsmem(EtsMem).
@@ -5159,13 +5718,16 @@ colliding_names(Name) ->
%% OTP_6913: Grow and shrink.
grow_shrink(Config) when is_list(Config) ->
- EtsMem = etsmem(),
-
- Set = ets_new(a, [set]),
- grow_shrink_0(0, 3071, 3000, 5000, Set),
- ets:delete(Set),
-
- verify_etsmem(EtsMem).
+ repeat_for_all_set_table_types(
+ fun(Opts) ->
+ EtsMem = etsmem(),
+
+ Set = ets_new(a, Opts, 5000),
+ grow_shrink_0(0, 3071, 3000, 5000, Set),
+ ets:delete(Set),
+
+ verify_etsmem(EtsMem)
+ end).
grow_shrink_0(N, _, _, Max, _) when N >= Max ->
ok;
@@ -5189,7 +5751,7 @@ grow_shrink_3(N, ShrinkTo, T) ->
true = ets:delete(T, N),
grow_shrink_3(N-1, ShrinkTo, T).
-%% Grow a table that still contains pseudo-deleted objects.
+%% Grow a hash table that still contains pseudo-deleted objects.
grow_pseudo_deleted(Config) when is_list(Config) ->
only_if_smp(fun() -> grow_pseudo_deleted_do() end).
@@ -5242,7 +5804,7 @@ grow_pseudo_deleted_do(Type) ->
ets:delete(T),
process_flag(scheduler,0).
-%% Shrink a table that still contains pseudo-deleted objects.
+%% Shrink a hash table that still contains pseudo-deleted objects.
shrink_pseudo_deleted(Config) when is_list(Config) ->
only_if_smp(fun()->shrink_pseudo_deleted_do() end).
@@ -5362,10 +5924,16 @@ meta_newdel_named(Config) when is_list(Config) ->
%% Concurrent insert's on same table.
smp_insert(Config) when is_list(Config) ->
- ets_new(smp_insert,[named_table,public,{write_concurrency,true}]),
+ repeat_for_opts(fun smp_insert_do/1,
+ [[set,ordered_set,stim_cat_ord_set]]).
+
+smp_insert_do(Opts) ->
+ KeyRange = 10000,
+ ets_new(smp_insert,[named_table,public,{write_concurrency,true}|Opts],
+ KeyRange),
InitF = fun(_) -> ok end,
- ExecF = fun(_) -> true = ets:insert(smp_insert,{rand:uniform(10000)})
- end,
+ ExecF = fun(_) -> true = ets:insert(smp_insert,{rand:uniform(KeyRange)})
+ end,
FiniF = fun(_) -> ok end,
run_smp_workers(InitF,ExecF,FiniF,100000),
verify_table_load(smp_insert),
@@ -5373,7 +5941,7 @@ smp_insert(Config) when is_list(Config) ->
%% Concurrent deletes on same fixated table.
smp_fixed_delete(Config) when is_list(Config) ->
- only_if_smp(fun()->smp_fixed_delete_do() end).
+ only_if_smp(fun() -> smp_fixed_delete_do() end).
smp_fixed_delete_do() ->
T = ets_new(foo,[public,{write_concurrency,true}]),
@@ -5384,25 +5952,73 @@ smp_fixed_delete_do() ->
Buckets = num_of_buckets(T),
InitF = fun([ProcN,NumOfProcs|_]) -> {ProcN,NumOfProcs} end,
ExecF = fun({Key,_}) when Key > NumOfObjs ->
- [end_of_work];
- ({Key,Increment}) ->
- true = ets:delete(T,Key),
- {Key+Increment,Increment}
- end,
+ [end_of_work];
+ ({Key,Increment}) ->
+ true = ets:delete(T,Key),
+ {Key+Increment,Increment}
+ end,
FiniF = fun(_) -> ok end,
run_sched_workers(InitF,ExecF,FiniF,NumOfObjs),
0 = ets:info(T,size),
true = ets:info(T,fixed),
Buckets = num_of_buckets(T),
- NumOfObjs = get_kept_objects(T),
+ case ets:info(T,type) of
+ set -> NumOfObjs = get_kept_objects(T);
+ _ -> ok
+ end,
ets:safe_fixtable(T,false),
%% Will fail as unfix does not shrink the table:
%%Mem = ets:info(T,memory),
%%verify_table_load(T),
ets:delete(T).
+%% ERL-720
+%% Provoke race between ets:delete and table unfix (by select_count)
+%% that caused ets_misc memory counter to indicate false leak.
+delete_unfix_race(Config) when is_list(Config) ->
+ EtsMem = etsmem(),
+ Table = ets:new(t,[set,public,{write_concurrency,true}]),
+ InsertOp =
+ fun() ->
+ receive stop ->
+ false
+ after 0 ->
+ ets:insert(Table, {rand:uniform(10)}),
+ true
+ end
+ end,
+ DeleteOp =
+ fun() ->
+ receive stop ->
+ false
+ after 0 ->
+ ets:delete(Table, rand:uniform(10)),
+ true
+ end
+ end,
+ SelectOp =
+ fun() ->
+ ets:select_count(Table, ets:fun2ms(fun(X) -> true end))
+ end,
+ Main = self(),
+ Ins = spawn(fun()-> repeat_while(InsertOp), Main ! self() end),
+ Del = spawn(fun()-> repeat_while(DeleteOp), Main ! self() end),
+ spawn(fun()->
+ repeat(SelectOp, 10000),
+ Del ! stop,
+ Ins ! stop
+ end),
+ [receive Pid -> ok end || Pid <- [Ins,Del]],
+ ets:delete(Table),
+ verify_etsmem(EtsMem).
+
num_of_buckets(T) ->
- element(1,ets:info(T,stats)).
+ case ets:info(T,type) of
+ set -> element(1,ets:info(T,stats));
+ bag -> element(1,ets:info(T,stats));
+ duplicate_bag -> element(1,ets:info(T,stats));
+ _ -> ok
+ end.
%% Fixate hash table while other process is busy doing unfix.
smp_unfix_fix(Config) when is_list(Config) ->
@@ -5567,106 +6183,126 @@ otp_8166_zombie_creator(T,Deleted) ->
verify_table_load(T) ->
- Stats = ets:info(T,stats),
- {Buckets,AvgLen,StdDev,ExpSD,_MinLen,_MaxLen,_} = Stats,
- ok = if
- AvgLen > 1.2 ->
- io:format("Table overloaded: Stats=~p\n~p\n",
- [Stats, ets:info(T)]),
- false;
-
- Buckets>256, AvgLen < 0.47 ->
- io:format("Table underloaded: Stats=~p\n~p\n",
- [Stats, ets:info(T)]),
- false;
-
- StdDev > ExpSD*2 ->
- io:format("Too large standard deviation (poor hashing?),"
- " stats=~p\n~p\n",[Stats, ets:info(T)]),
- false;
-
- true ->
- io:format("Stats = ~p\n",[Stats]),
- ok
- end.
+ case ets:info(T,type) of
+ ordered_set -> ok;
+ _ ->
+ Stats = ets:info(T,stats),
+ {Buckets,AvgLen,StdDev,ExpSD,_MinLen,_MaxLen,_} = Stats,
+ ok = if
+ AvgLen > 1.2 ->
+ io:format("Table overloaded: Stats=~p\n~p\n",
+ [Stats, ets:info(T)]),
+ false;
+
+ Buckets>256, AvgLen < 0.47 ->
+ io:format("Table underloaded: Stats=~p\n~p\n",
+ [Stats, ets:info(T)]),
+ false;
+
+ StdDev > ExpSD*2 ->
+ io:format("Too large standard deviation (poor hashing?),"
+ " stats=~p\n~p\n",[Stats, ets:info(T)]),
+ false;
+
+ true ->
+ io:format("Stats = ~p\n",[Stats]),
+ ok
+ end
+ end.
%% ets:select on a tree with NIL key object.
otp_8732(Config) when is_list(Config) ->
- Tab = ets_new(noname,[ordered_set]),
- filltabstr(Tab,999),
- ets:insert(Tab,{[],"nasty NIL object"}),
- [] = ets:match(Tab,{'_',nomatch}), %% Will hang if bug not fixed
+ repeat_for_all_ord_set_table_types(
+ fun(Opts) ->
+ KeyRange = 999,
+ KeyFun = fun(K) -> integer_to_list(K) end,
+ Tab = ets_new(noname,Opts, KeyRange, KeyFun),
+ filltabstr(Tab, KeyRange),
+ ets:insert(Tab,{[],"nasty NIL object"}),
+ [] = ets:match(Tab,{'_',nomatch}) %% Will hang if bug not fixed
+ end),
ok.
%% Run concurrent select_delete (and inserts) on same table.
smp_select_delete(Config) when is_list(Config) ->
- T = ets_new(smp_select_delete,[named_table,public,{write_concurrency,true}]),
- Mod = 17,
- Zeros = erlang:make_tuple(Mod,0),
- InitF = fun(_) -> Zeros end,
- ExecF = fun(Diffs0) ->
- case rand:uniform(20) of
- 1 ->
- Mod = 17,
- Eq = rand:uniform(Mod) - 1,
- Deleted = ets:select_delete(T,
- [{{'_', '$1'},
- [{'=:=', {'rem', '$1', Mod}, Eq}],
- [true]}]),
- Diffs1 = setelement(Eq+1, Diffs0,
- element(Eq+1,Diffs0) - Deleted),
- Diffs1;
- _ ->
- Key = rand:uniform(10000),
- Eq = Key rem Mod,
- case ets:insert_new(T,{Key,Key}) of
- true ->
- Diffs1 = setelement(Eq+1, Diffs0,
- element(Eq+1,Diffs0)+1),
- Diffs1;
- false -> Diffs0
- end
- end
- end,
- FiniF = fun(Result) -> Result end,
- Results = run_sched_workers(InitF,ExecF,FiniF,20000),
- TotCnts = lists:foldl(fun(Diffs, Sum) -> add_lists(Sum,tuple_to_list(Diffs)) end,
- lists:duplicate(Mod, 0), Results),
- io:format("TotCnts = ~p\n",[TotCnts]),
- LeftInTab = lists:foldl(fun(N,Sum) -> Sum+N end,
- 0, TotCnts),
- io:format("LeftInTab = ~p\n",[LeftInTab]),
- LeftInTab = ets:info(T,size),
- lists:foldl(fun(Cnt,Eq) ->
- WasCnt = ets:select_count(T,
- [{{'_', '$1'},
- [{'=:=', {'rem', '$1', Mod}, Eq}],
- [true]}]),
- io:format("~p: ~p =?= ~p\n",[Eq,Cnt,WasCnt]),
- Cnt = WasCnt,
- Eq+1
- end,
- 0, TotCnts),
- %% May fail as select_delete does not shrink table (enough)
- %%verify_table_load(T),
- LeftInTab = ets:select_delete(T, [{{'$1','$1'}, [], [true]}]),
- 0 = ets:info(T,size),
- false = ets:info(T,fixed),
- ets:delete(T).
+ repeat_for_opts(fun smp_select_delete_do/1,
+ [[set,ordered_set,stim_cat_ord_set],
+ read_concurrency, compressed]).
+
+smp_select_delete_do(Opts) ->
+ KeyRange = 10000,
+ begin % indentation
+ T = ets_new(smp_select_delete,[named_table,public,{write_concurrency,true}|Opts],
+ KeyRange),
+ Mod = 17,
+ Zeros = erlang:make_tuple(Mod,0),
+ InitF = fun(_) -> Zeros end,
+ ExecF = fun(Diffs0) ->
+ case rand:uniform(20) of
+ 1 ->
+ Mod = 17,
+ Eq = rand:uniform(Mod) - 1,
+ Deleted = ets:select_delete(T,
+ [{{'_', '$1'},
+ [{'=:=', {'rem', '$1', Mod}, Eq}],
+ [true]}]),
+ Diffs1 = setelement(Eq+1, Diffs0,
+ element(Eq+1,Diffs0) - Deleted),
+ Diffs1;
+ _ ->
+ Key = rand:uniform(KeyRange),
+ Eq = Key rem Mod,
+ case ets:insert_new(T,{Key,Key}) of
+ true ->
+ Diffs1 = setelement(Eq+1, Diffs0,
+ element(Eq+1,Diffs0)+1),
+ Diffs1;
+ false -> Diffs0
+ end
+ end
+ end,
+ FiniF = fun(Result) -> Result end,
+ Results = run_sched_workers(InitF,ExecF,FiniF,20000),
+ TotCnts = lists:foldl(fun(Diffs, Sum) -> add_lists(Sum,tuple_to_list(Diffs)) end,
+ lists:duplicate(Mod, 0), Results),
+ io:format("TotCnts = ~p\n",[TotCnts]),
+ LeftInTab = lists:foldl(fun(N,Sum) -> Sum+N end,
+ 0, TotCnts),
+ io:format("LeftInTab = ~p\n",[LeftInTab]),
+ LeftInTab = ets:info(T,size),
+ lists:foldl(fun(Cnt,Eq) ->
+ WasCnt = ets:select_count(T,
+ [{{'_', '$1'},
+ [{'=:=', {'rem', '$1', Mod}, Eq}],
+ [true]}]),
+ io:format("~p: ~p =?= ~p\n",[Eq,Cnt,WasCnt]),
+ Cnt = WasCnt,
+ Eq+1
+ end,
+ 0, TotCnts),
+ %% May fail as select_delete does not shrink table (enough)
+ %%verify_table_load(T),
+ LeftInTab = ets:select_delete(T, [{{'$1','$1'}, [], [true]}]),
+ 0 = ets:info(T,size),
+ false = ets:info(T,fixed),
+ ets:delete(T)
+ end, % indentation
+ ok.
smp_select_replace(Config) when is_list(Config) ->
repeat_for_opts(fun smp_select_replace_do/1,
- [[set,ordered_set,duplicate_bag]]).
+ [[set,ordered_set,stim_cat_ord_set,duplicate_bag]]).
smp_select_replace_do(Opts) ->
+ KeyRange = 20,
T = ets_new(smp_select_replace,
- [public, {write_concurrency, true} | Opts]),
- ObjCount = 20,
+ [public, {write_concurrency, true} | Opts],
+ KeyRange),
InitF = fun (_) -> 0 end,
ExecF = fun (Cnt0) ->
- CounterId = rand:uniform(ObjCount),
+ CounterId = rand:uniform(KeyRange),
Match = [{{'$1', '$2'},
[{'=:=', '$1', CounterId}],
[{{'$1', {'+', '$2', 1}}}]}],
@@ -5690,15 +6326,143 @@ smp_select_replace_do(Opts) ->
FinalCounts = ets:select(T, [{{'_', '$1'}, [], ['$1']}]),
Total = lists:sum(FinalCounts),
Total = lists:sum(Results),
- ObjCount = ets:select_delete(T, [{{'_', '_'}, [], [true]}]),
+ KeyRange = ets:select_delete(T, [{{'_', '_'}, [], [true]}]),
0 = ets:info(T, size),
true = ets:delete(T),
ok.
+%% Iterate ordered_set with write_concurrency
+%% and make sure we hit all "stable" long lived keys
+%% while "volatile" objects are randomly inserted and deleted.
+smp_ordered_iteration(Config) when is_list(Config) ->
+ repeat_for_opts(fun smp_ordered_iteration_do/1,
+ [[cat_ord_set,stim_cat_ord_set]]).
+
+
+smp_ordered_iteration_do(Opts) ->
+ KeyRange = 1000,
+ OffHeap = erts_test_utils:mk_ext_pid({a@b,1}, 4711, 1),
+ KeyFun = fun(K, Type) ->
+ {K div 10, K rem 10, Type, OffHeap}
+ end,
+ StimKeyFun = fun(K) ->
+ KeyFun(K, element(rand:uniform(3),
+ {stable, other, volatile}))
+ end,
+ T = ets_new(smp_ordered_iteration, [public, {write_concurrency,true} | Opts],
+ KeyRange, StimKeyFun),
+ NStable = KeyRange div 4,
+ prefill_table(T, KeyRange, NStable, fun(K) -> {KeyFun(K, stable), 0} end),
+ NStable = ets:info(T, size),
+ NVolatile = KeyRange div 2,
+ prefill_table(T, KeyRange, NVolatile, fun(K) -> {KeyFun(K, volatile), 0} end),
+
+ InitF = fun (_) -> #{insert => 0, delete => 0,
+ select_delete_bk => 0, select_delete_pbk => 0,
+ select_replace_bk => 0, select_replace_pbk => 0}
+ end,
+ ExecF = fun (Counters) ->
+ K = rand:uniform(KeyRange),
+ Key = KeyFun(K, volatile),
+ Acc = case rand:uniform(22) of
+ R when R =< 10 ->
+ ets:insert(T, {Key}),
+ incr_counter(insert, Counters);
+ R when R =< 15 ->
+ ets:delete(T, Key),
+ incr_counter(delete, Counters);
+ R when R =< 19 ->
+ %% Delete bound key
+ ets:select_delete(T, [{{Key, '_'}, [], [true]}]),
+ incr_counter(select_delete_bk, Counters);
+ R when R =< 20 ->
+ %% Delete partially bound key
+ ets:select_delete(T, [{{{K div 10, '_', volatile, '_'}, '_'}, [], [true]}]),
+ incr_counter(select_delete_pbk, Counters);
+ R when R =< 21 ->
+ %% Replace bound key
+ ets:select_replace(T, [{{Key, '$1'}, [],
+ [{{{const,Key}, {'+','$1',1}}}]}]),
+ incr_counter(select_replace_bk, Counters);
+ _ ->
+ %% Replace partially bound key
+ ets:select_replace(T, [{{{K div 10, '_', volatile, '_'}, '$1'}, [],
+ [{{{element,1,'$_'}, {'+','$1',1}}}]}]),
+ incr_counter(select_replace_pbk, Counters)
+ end,
+ receive stop ->
+ [end_of_work | Acc]
+ after 0 ->
+ Acc
+ end
+ end,
+ FiniF = fun (Acc) -> Acc end,
+ Pids = run_sched_workers(InitF, ExecF, FiniF, infinite),
+ timer:send_after(1000, stop),
+
+ Log2ChunkMax = math:log2(NStable*2),
+ Rounds = fun Loop(N) ->
+ MS = [{{{'_', '_', stable, '_'}, '_'}, [], [true]}],
+ NStable = ets:select_count(T, MS),
+ NStable = count_stable(T, next, ets:first(T), 0),
+ NStable = count_stable(T, prev, ets:last(T), 0),
+ NStable = length(ets:select(T, MS)),
+ NStable = length(ets:select_reverse(T, MS)),
+ Chunk = round(math:pow(2, rand:uniform()*Log2ChunkMax)),
+ NStable = ets_select_chunks_count(T, MS, Chunk),
+ receive stop -> N
+ after 0 -> Loop(N+1)
+ end
+ end (1),
+ [P ! stop || P <- Pids],
+ Results = wait_pids(Pids),
+ io:format("Ops = ~p\n", [maps_sum(Results)]),
+ io:format("Diff = ~p\n", [ets:info(T,size) - NStable - NVolatile]),
+ io:format("Stats = ~p\n", [ets:info(T,stats)]),
+ io:format("Rounds = ~p\n", [Rounds]),
+ true = ets:delete(T),
+
+ %% Verify no leakage of offheap key data
+ ok = erts_test_utils:check_node_dist(),
+ ok.
+
+incr_counter(Name, Counters) ->
+ Counters#{Name => maps:get(Name, Counters, 0) + 1}.
+
+count_stable(T, Next, {_, _, stable, _}=Key, N) ->
+ count_stable(T, Next, ets:Next(T, Key), N+1);
+count_stable(T, Next, {_, _, volatile, _}=Key, N) ->
+ count_stable(T, Next, ets:Next(T, Key), N);
+count_stable(_, _, '$end_of_table', N) ->
+ N.
+
+ets_select_chunks_count(T, MS, Chunk) ->
+ ets_select_chunks_count(ets:select(T, MS, Chunk), 0).
+
+ets_select_chunks_count('$end_of_table', N) ->
+ N;
+ets_select_chunks_count({List, Continuation}, N) ->
+ ets_select_chunks_count(ets:select(Continuation),
+ length(List) + N).
+
+maps_sum([Ma | Tail]) when is_map(Ma) ->
+ maps_sum([lists:sort(maps:to_list(Ma)) | Tail]);
+maps_sum([La, Mb | Tail]) ->
+ Lab = lists:zipwith(fun({K,Va}, {K,Vb}) -> {K,Va+Vb} end,
+ La,
+ lists:sort(maps:to_list(Mb))),
+ maps_sum([Lab | Tail]);
+maps_sum([L]) ->
+ L.
+
+
+
+
%% Test different types.
types(Config) when is_list(Config) ->
init_externals(),
- repeat_for_opts(fun types_do/1, [[set,ordered_set],compressed]).
+ repeat_for_opts(fun types_do/1, [repeat_for_opts_atom2list(set_types),
+ compressed]).
types_do(Opts) ->
EtsMem = etsmem(),
@@ -5725,7 +6489,7 @@ types_do(Opts) ->
%% OTP-9932: Memory overwrite when inserting large integers in compressed bag.
%% Will crash with segv on 64-bit opt if not fixed.
otp_9932(Config) when is_list(Config) ->
- T = ets:new(xxx, [bag, compressed]),
+ T = ets_new(xxx, [bag, compressed]),
Fun = fun(N) ->
Key = {1316110174588445 bsl N,1316110174588583 bsl N},
S = {Key, Key},
@@ -5741,48 +6505,56 @@ otp_9932(Config) when is_list(Config) ->
%% vm-deadlock caused by race between ets:delete and others on
%% write_concurrency table.
otp_9423(Config) when is_list(Config) ->
- InitF = fun(_) -> {0,0} end,
- ExecF = fun({S,F}) ->
- receive
- stop ->
- io:format("~p got stop\n", [self()]),
- [end_of_work | {"Succeded=",S,"Failed=",F}]
- after 0 ->
- %%io:format("~p (~p) doing lookup\n", [self(), {S,F}]),
- try ets:lookup(otp_9423, key) of
- [] -> {S+1,F}
- catch
- error:badarg -> {S,F+1}
- end
- end
- end,
- FiniF = fun(R) -> R end,
- case run_smp_workers(InitF, ExecF, FiniF, infinite, 1) of
- Pids when is_list(Pids) ->
- %%[P ! start || P <- Pids],
- repeat(fun() -> ets:new(otp_9423, [named_table, public, {write_concurrency,true}]),
- ets:delete(otp_9423)
- end, 10000),
- [P ! stop || P <- Pids],
- wait_pids(Pids),
- ok;
+ repeat_for_all_non_stim_set_table_types(
+ fun(Opts) ->
+ InitF = fun(_) -> {0,0} end,
+ ExecF = fun({S,F}) ->
+ receive
+ stop ->
+ io:format("~p got stop\n", [self()]),
+ [end_of_work | {"Succeded=",S,"Failed=",F}]
+ after 0 ->
+ %%io:format("~p (~p) doing lookup\n", [self(), {S,F}]),
+ try ets:lookup(otp_9423, key) of
+ [] -> {S+1,F}
+ catch
+ error:badarg -> {S,F+1}
+ end
+ end
+ end,
+ FiniF = fun(R) -> R end,
+ case run_smp_workers(InitF, ExecF, FiniF, infinite, 1) of
+ Pids when is_list(Pids) ->
+ %%[P ! start || P <- Pids],
+ repeat(fun() -> ets_new(otp_9423, [named_table, public,
+ {write_concurrency,true}|Opts]),
+ ets:delete(otp_9423)
+ end, 10000),
+ [P ! stop || P <- Pids],
+ wait_pids(Pids),
+ ok;
+
+ Skipped -> Skipped
+ end
+ end).
- Skipped -> Skipped
- end.
%% Corrupted binary in compressed table
otp_10182(Config) when is_list(Config) ->
- Bin = <<"aHR0cDovL2hvb3RzdWl0ZS5jb20vYy9wcm8tYWRyb2xsLWFi">>,
- Key = {test, Bin},
- Value = base64:decode(Bin),
- In = {Key,Value},
- Db = ets:new(undefined, [set, protected, {read_concurrency, true}, compressed]),
- ets:insert(Db, In),
- [Out] = ets:lookup(Db, Key),
- io:format("In : ~p\nOut: ~p\n", [In,Out]),
- ets:delete(Db),
- In = Out.
+ repeat_for_opts_all_table_types(
+ fun(Opts) ->
+ Bin = <<"aHR0cDovL2hvb3RzdWl0ZS5jb20vYy9wcm8tYWRyb2xsLWFi">>,
+ Key = {test, Bin},
+ Value = base64:decode(Bin),
+ In = {Key,Value},
+ Db = ets_new(undefined, Opts),
+ ets:insert(Db, In),
+ [Out] = ets:lookup(Db, Key),
+ io:format("In : ~p\nOut: ~p\n", [In,Out]),
+ ets:delete(Db),
+ In = Out
+ end).
%% Test that ets:all include/exclude tables that we know are created/deleted
ets_all(Config) when is_list(Config) ->
@@ -5873,19 +6645,23 @@ take(Config) when is_list(Config) ->
ets:insert(T1, {{'not',<<"immediate">>},ok}),
[{{'not',<<"immediate">>},ok}] = ets:take(T1, {'not',<<"immediate">>}),
%% Same with ordered tables.
- T2 = ets_new(b, [ordered_set]),
- [] = ets:take(T2, foo),
- ets:insert(T2, {foo,bar}),
- [] = ets:take(T2, bar),
- [{foo,bar}] = ets:take(T2, foo),
- [] = ets:tab2list(T2),
- ets:insert(T2, {{'not',<<"immediate">>},ok}),
- [{{'not',<<"immediate">>},ok}] = ets:take(T2, {'not',<<"immediate">>}),
- %% Arithmetically-equal keys.
- ets:insert(T2, [{1.0,float},{2,integer}]),
- [{1.0,float}] = ets:take(T2, 1),
- [{2,integer}] = ets:take(T2, 2.0),
- [] = ets:tab2list(T2),
+ repeat_for_all_ord_set_table_types(
+ fun(Opts) ->
+ T2 = ets_new(b, Opts),
+ [] = ets:take(T2, foo),
+ ets:insert(T2, {foo,bar}),
+ [] = ets:take(T2, bar),
+ [{foo,bar}] = ets:take(T2, foo),
+ [] = ets:tab2list(T2),
+ ets:insert(T2, {{'not',<<"immediate">>},ok}),
+ [{{'not',<<"immediate">>},ok}] = ets:take(T2, {'not',<<"immediate">>}),
+ %% Arithmetically-equal keys.
+ ets:insert(T2, [{1.0,float},{2,integer}]),
+ [{1.0,float}] = ets:take(T2, 1),
+ [{2,integer}] = ets:take(T2, 2.0),
+ [] = ets:tab2list(T2),
+ ets:delete(T2)
+ end),
%% Same with bag.
T3 = ets_new(c, [bag]),
ets:insert(T3, [{1,1},{1,2},{3,3}]),
@@ -5893,14 +6669,552 @@ take(Config) when is_list(Config) ->
[{3,3}] = ets:take(T3, 3),
[] = ets:tab2list(T3),
ets:delete(T1),
- ets:delete(T2),
ets:delete(T3),
ok.
+whereis_table(Config) when is_list(Config) ->
+ %% Do we return 'undefined' when the named table doesn't exist?
+ undefined = ets:whereis(whereis_test),
-%%
-%% Utility functions:
-%%
+ %% Does the tid() refer to the same table as the name?
+ whereis_test = ets:new(whereis_test, [named_table]),
+ Tid = ets:whereis(whereis_test),
+
+ ets:insert(whereis_test, [{hello}, {there}]),
+
+ [[{hello}],[{there}]] = ets:match(whereis_test, '$1'),
+ [[{hello}],[{there}]] = ets:match(Tid, '$1'),
+
+ true = ets:delete_all_objects(Tid),
+
+ [] = ets:match(whereis_test, '$1'),
+ [] = ets:match(Tid, '$1'),
+
+ %% Does the name disappear when deleted through the tid()?
+ true = ets:delete(Tid),
+ undefined = ets:info(whereis_test),
+ {'EXIT',{badarg, _}} = (catch ets:match(whereis_test, '$1')),
+
+ %% Is the old tid() broken when the table is re-created with the same
+ %% name?
+ whereis_test = ets:new(whereis_test, [named_table]),
+ [] = ets:match(whereis_test, '$1'),
+ {'EXIT',{badarg, _}} = (catch ets:match(Tid, '$1')),
+
+ ok.
+
+
+%% The following help functions are used by
+%% throughput_benchmark. They are declared on the top level beacuse
+%% declaring them as function local funs cause a scalability issue.
+get_op([{_,O}], _RandNum) ->
+ O;
+get_op([{Prob,O}|Rest], RandNum) ->
+ case RandNum < Prob of
+ true -> O;
+ false -> get_op(Rest, RandNum)
+ end.
+do_op(Table, ProbHelpTab, Range, Operations) ->
+ RandNum = rand:uniform(),
+ Op = get_op(ProbHelpTab, RandNum),
+ #{ Op := TheOp} = Operations,
+ TheOp(Table, Range).
+do_work(WorksDoneSoFar, Table, ProbHelpTab, Range, Operations) ->
+ receive
+ stop -> WorksDoneSoFar
+ after
+ 0 -> do_op(Table, ProbHelpTab, Range, Operations),
+ do_work(WorksDoneSoFar + 1, Table, ProbHelpTab, Range, Operations)
+ end.
+
+prefill_table(T, KeyRange, Num, ObjFun) ->
+ Seed = rand:uniform(KeyRange),
+ %%io:format("prefill_table: Seed = ~p\n", [Seed]),
+ RState = unique_rand_start(KeyRange, Seed),
+ prefill_table_loop(T, RState, Num, ObjFun).
+
+prefill_table_loop(_, _, 0, _) ->
+ ok;
+prefill_table_loop(T, RS0, N, ObjFun) ->
+ {Key, RS1} = unique_rand_next(RS0),
+ ets:insert(T, ObjFun(Key)),
+ prefill_table_loop(T, RS1, N-1, ObjFun).
+
+-record(ets_throughput_bench_config,
+ {benchmark_duration_ms = 3000,
+ recover_time_ms = 1000,
+ thread_counts = not_set,
+ key_ranges = [1000000],
+ scenarios =
+ [
+ [
+ {0.5, insert},
+ {0.5, delete}
+ ],
+ [
+ {0.1, insert},
+ {0.1, delete},
+ {0.8, lookup}
+ ],
+ [
+ {0.01, insert},
+ {0.01, delete},
+ {0.98, lookup}
+ ],
+ [
+ {1.0, lookup}
+ ],
+ [
+ {0.1, insert},
+ {0.1, delete},
+ {0.4, lookup},
+ {0.4, nextseq10}
+ ],
+ [
+ {0.1, insert},
+ {0.1, delete},
+ {0.4, lookup},
+ {0.4, nextseq100}
+ ],
+ [
+ {0.1, insert},
+ {0.1, delete},
+ {0.4, lookup},
+ {0.4, nextseq1000}
+ ],
+ [
+ {1.0, nextseq1000}
+ ],
+ [
+ {0.1, insert},
+ {0.1, delete},
+ {0.79, lookup},
+ {0.01, selectAll}
+ ],
+ [
+ {0.1, insert},
+ {0.1, delete},
+ {0.7999, lookup},
+ {0.0001, selectAll}
+ ],
+ [
+ {0.1, insert},
+ {0.1, delete},
+ {0.799999, lookup},
+ {0.000001, selectAll}
+ ],
+ [
+ {0.1, insert},
+ {0.1, delete},
+ {0.79, lookup},
+ {0.01, partial_select1000}
+ ],
+ [
+ {0.1, insert},
+ {0.1, delete},
+ {0.7999, lookup},
+ {0.0001, partial_select1000}
+ ],
+ [
+ {0.1, insert},
+ {0.1, delete},
+ {0.799999, lookup},
+ {0.000001, partial_select1000}
+ ]
+ ],
+ table_types =
+ [
+ [ordered_set, public],
+ [ordered_set, public, {write_concurrency, true}],
+ [ordered_set, public, {read_concurrency, true}],
+ [ordered_set, public, {write_concurrency, true}, {read_concurrency, true}],
+ [set, public],
+ [set, public, {write_concurrency, true}],
+ [set, public, {read_concurrency, true}],
+ [set, public, {write_concurrency, true}, {read_concurrency, true}]
+ ],
+ etsmem_fun = fun() -> ok end,
+ verify_etsmem_fun = fun(_) -> true end,
+ notify_res_fun = fun(_Name, _Throughput) -> ok end,
+ print_result_paths_fun =
+ fun(ResultPath, _LatestResultPath) ->
+ Comment =
+ io_lib:format("<a href=\"file:///~s\">Result visualization</a>",[ResultPath]),
+ {comment, Comment}
+ end
+ }).
+
+stdout_notify_res(ResultPath, LatestResultPath) ->
+ io:format("Result Location: /~s~n", [ResultPath]),
+ io:format("Latest Result Location: ~s~n", [LatestResultPath]).
+
+throughput_benchmark() ->
+ throughput_benchmark(
+ #ets_throughput_bench_config{
+ print_result_paths_fun = fun stdout_notify_res/2}).
+
+throughput_benchmark(
+ #ets_throughput_bench_config{
+ benchmark_duration_ms = BenchmarkDurationMs,
+ recover_time_ms = RecoverTimeMs,
+ thread_counts = ThreadCountsOpt,
+ key_ranges = KeyRanges,
+ scenarios = Scenarios,
+ table_types = TableTypes,
+ etsmem_fun = ETSMemFun,
+ verify_etsmem_fun = VerifyETSMemFun,
+ notify_res_fun = NotifyResFun,
+ print_result_paths_fun = PrintResultPathsFun}) ->
+ NrOfSchedulers = erlang:system_info(schedulers),
+ %% Definitions of operations that are supported by the benchmark
+ NextSeqOp =
+ fun (T, KeyRange, SeqSize) ->
+ Start = rand:uniform(KeyRange),
+ Last =
+ lists:foldl(
+ fun(_, Prev) ->
+ case Prev of
+ '$end_of_table'-> ok;
+ _ ->
+ try ets:next(T, Prev) of
+ Normal -> Normal
+ catch
+ error:badarg ->
+ % sets (not ordered_sets) cannot handle when the argument
+ % to next is not in the set
+ rand:uniform(KeyRange)
+ end
+ end
+ end,
+ Start,
+ lists:seq(1, SeqSize)),
+ case Last =:= -1 of
+ true -> io:format("Will never be printed");
+ false -> ok
+ end
+ end,
+ PartialSelectOp =
+ fun (T, KeyRange, SeqSize) ->
+ Start = rand:uniform(KeyRange),
+ Last = Start + SeqSize,
+ case -1 =:= ets:select_count(T,
+ ets:fun2ms(fun({X}) when X > Start andalso X =< Last -> true end)) of
+ true -> io:format("Will never be printed");
+ false -> ok
+ end
+
+ end,
+ %% Mapping benchmark operation names to their corresponding functions that do them
+ Operations =
+ #{insert =>
+ fun(T,KeyRange) ->
+ Num = rand:uniform(KeyRange),
+ ets:insert(T, {Num})
+ end,
+ delete =>
+ fun(T,KeyRange) ->
+ Num = rand:uniform(KeyRange),
+ ets:delete(T, Num)
+ end,
+ lookup =>
+ fun(T,KeyRange) ->
+ Num = rand:uniform(KeyRange),
+ ets:lookup(T, Num)
+ end,
+ nextseq10 =>
+ fun(T,KeyRange) -> NextSeqOp(T,KeyRange,10) end,
+ nextseq100 =>
+ fun(T,KeyRange) -> NextSeqOp(T,KeyRange,100) end,
+ nextseq1000 =>
+ fun(T,KeyRange) -> NextSeqOp(T,KeyRange,1000) end,
+ selectAll =>
+ fun(T,_KeyRange) ->
+ case -1 =:= ets:select_count(T, ets:fun2ms(fun(_X) -> true end)) of
+ true -> io:format("Will never be printed");
+ false -> ok
+ end
+ end,
+ partial_select1000 =>
+ fun(T,KeyRange) -> PartialSelectOp(T,KeyRange,1000) end
+ },
+ %% Helper functions
+ CalculateThreadCounts = fun Calculate([Count|Rest]) ->
+ case Count > NrOfSchedulers of
+ true -> lists:reverse(Rest);
+ false -> Calculate([Count*2,Count|Rest])
+ end
+ end,
+ CalculateOpsProbHelpTab =
+ fun Calculate([{_, OpName}], _) ->
+ [{1.0, OpName}];
+ Calculate([{OpPropability, OpName}|Res], Current) ->
+ NewCurrent = Current + OpPropability,
+ [{NewCurrent, OpName}| Calculate(Res, NewCurrent)]
+ end,
+ RenderScenario =
+ fun R([], StringSoFar) ->
+ StringSoFar;
+ R([{Fraction, Operation}], StringSoFar) ->
+ io_lib:format("~s ~f% ~p",[StringSoFar, Fraction * 100.0, Operation]);
+ R([{Fraction, Operation}|Rest], StringSoFar) ->
+ R(Rest,
+ io_lib:format("~s ~f% ~p, ",[StringSoFar, Fraction * 100.0, Operation]))
+ end,
+ SafeFixTableIfRequired =
+ fun(Table, Scenario, On) ->
+ case set =:= ets:info(Table, type) of
+ true ->
+ HasNotRequiringOp =
+ lists:search(
+ fun({_,nextseq10}) -> true;
+ ({_,nextseq100}) -> true;
+ ({_,nextseq1000}) -> true;
+ (_) -> false
+ end, Scenario),
+ case HasNotRequiringOp of
+ false -> ok;
+ _ -> ets:safe_fixtable(Table, On)
+ end;
+ false -> ok
+ end
+ end,
+ DataHolder =
+ fun DataHolderFun(Data)->
+ receive
+ {get_data, Pid} -> Pid ! {ets_bench_data, Data};
+ D -> DataHolderFun([Data,D])
+ end
+ end,
+ DataHolderPid = spawn_link(fun()-> DataHolder([]) end),
+ PrintData =
+ fun (Str, List) ->
+ io:format(Str, List),
+ DataHolderPid ! io_lib:format(Str, List)
+ end,
+ GetData =
+ fun () ->
+ DataHolderPid ! {get_data, self()},
+ receive {ets_bench_data, Data} -> Data end
+ end,
+ %% Function that runs a benchmark instance and returns the number
+ %% of operations that were performed
+ RunBenchmark =
+ fun({NrOfProcs, TableConfig, Scenario, Range, Duration}) ->
+ ProbHelpTab = CalculateOpsProbHelpTab(Scenario, 0),
+ Table = ets:new(t, TableConfig),
+ Nobj = Range div 2,
+ prefill_table(Table, Range, Nobj, fun(K) -> {K} end),
+ Nobj = ets:info(Table, size),
+ SafeFixTableIfRequired(Table, Scenario, true),
+ ParentPid = self(),
+ Worker =
+ fun() ->
+ receive start -> ok end,
+ WorksDone =
+ do_work(0, Table, ProbHelpTab, Range, Operations),
+ ParentPid ! WorksDone
+ end,
+ ChildPids =
+ lists:map(fun(_N) ->spawn_link(Worker)end, lists:seq(1, NrOfProcs)),
+ lists:foreach(fun(Pid) -> Pid ! start end, ChildPids),
+ timer:sleep(Duration),
+ lists:foreach(fun(Pid) -> Pid ! stop end, ChildPids),
+ TotalWorksDone = lists:foldl(
+ fun(_, Sum) ->
+ receive
+ Count -> Sum + Count
+ end
+ end, 0, ChildPids),
+ SafeFixTableIfRequired(Table, Scenario, false),
+ ets:delete(Table),
+ TotalWorksDone
+ end,
+ RunBenchmarkInSepProcess =
+ fun(ParameterTuple) ->
+ P = self(),
+ spawn_link(fun()-> P ! {bench_result, RunBenchmark(ParameterTuple)} end),
+ Result = receive {bench_result, Res} -> Res end,
+ timer:sleep(RecoverTimeMs),
+ Result
+ end,
+ RunBenchmarkAndReport =
+ fun(ThreadCount,
+ TableType,
+ Scenario,
+ KeyRange,
+ Duration) ->
+ Result = RunBenchmarkInSepProcess({ThreadCount,
+ TableType,
+ Scenario,
+ KeyRange,
+ Duration}),
+ Throughput = Result/(Duration/1000.0),
+ PrintData("; ~f",[Throughput]),
+ Name = io_lib:format("Scenario: ~w, Key Range Size: ~w, "
+ "# of Processes: ~w, Table Type: ~w",
+ [Scenario, KeyRange, ThreadCount, TableType]),
+ NotifyResFun(Name, Throughput)
+ end,
+ ThreadCounts =
+ case ThreadCountsOpt of
+ not_set ->
+ CalculateThreadCounts([1]);
+ _ -> ThreadCountsOpt
+ end,
+ %% Run the benchmark
+ PrintData("# Each instance of the benchmark runs for ~w seconds:~n", [BenchmarkDurationMs/1000]),
+ PrintData("# The result of a benchmark instance is presented as a number representing~n",[]),
+ PrintData("# the number of operations performed per second:~n~n~n",[]),
+ PrintData("# To plot graphs for the results below:~n",[]),
+ PrintData("# 1. Open \"$ERL_TOP/lib/stdlib/test/ets_SUITE_data/visualize_throughput.html\" in a web browser~n",[]),
+ PrintData("# 2. Copy the lines between \"#BENCHMARK STARTED$\" and \"#BENCHMARK ENDED$\" below~n",[]),
+ PrintData("# 3. Paste the lines copied in step 2 to the text box in the browser window opened in~n",[]),
+ PrintData("# step 1 and press the Render button~n~n",[]),
+ PrintData("#BENCHMARK STARTED$~n",[]),
+ EtsMem = ETSMemFun(),
+ %% The following loop runs all benchmark scenarios and prints the results (i.e, operations/second)
+ lists:foreach(
+ fun(KeyRange) ->
+ lists:foreach(
+ fun(Scenario) ->
+ PrintData("Scenario: ~s | Key Range Size: ~w$~n",
+ [RenderScenario(Scenario, ""), KeyRange]),
+ lists:foreach(
+ fun(ThreadCount) ->
+ PrintData("; ~w",[ThreadCount])
+ end,
+ ThreadCounts),
+ PrintData("$~n",[]),
+ lists:foreach(
+ fun(TableType) ->
+ PrintData("~w ",[TableType]),
+ lists:foreach(
+ fun(ThreadCount) ->
+ RunBenchmarkAndReport(ThreadCount,
+ TableType,
+ Scenario,
+ KeyRange,
+ BenchmarkDurationMs)
+ end,
+ ThreadCounts),
+ PrintData("$~n",[])
+ end,
+ TableTypes)
+ end,
+ Scenarios)
+ end,
+ KeyRanges),
+ PrintData("~n#BENCHMARK ENDED$~n~n",[]),
+ VerifyETSMemFun(EtsMem),
+ DataDir = filename:join(filename:dirname(code:which(?MODULE)), "ets_SUITE_data"),
+ TemplatePath = filename:join(DataDir, "visualize_throughput.html"),
+ {ok, Template} = file:read_file(TemplatePath),
+ OutputData = string:replace(Template, "#bench_data_placeholder", GetData()),
+ OutputPath1 = filename:join(DataDir, "ets_bench_result.html"),
+ {{Year, Month, Day}, {Hour, Minute, Second}} = calendar:now_to_datetime(erlang:timestamp()),
+ StrTime = lists:flatten(io_lib:format("~4..0w-~2..0w-~2..0wT~2..0w:~2..0w:~2..0w",[Year,Month,Day,Hour,Minute,Second])),
+ OutputPath2 = filename:join(DataDir, io_lib:format("ets_bench_result_~s.html", [StrTime])),
+ file:write_file(OutputPath1, OutputData),
+ file:write_file(OutputPath2, OutputData),
+ PrintResultPathsFun(OutputPath2, OutputPath1).
+
+test_throughput_benchmark(Config) when is_list(Config) ->
+ throughput_benchmark(
+ #ets_throughput_bench_config{
+ benchmark_duration_ms = 100,
+ recover_time_ms = 0,
+ thread_counts = [1, erlang:system_info(schedulers)],
+ key_ranges = [50000],
+ etsmem_fun = fun etsmem/0,
+ verify_etsmem_fun = fun verify_etsmem/1}).
+
+long_throughput_benchmark(Config) when is_list(Config) ->
+ N = erlang:system_info(schedulers),
+ throughput_benchmark(
+ #ets_throughput_bench_config{
+ benchmark_duration_ms = 3000,
+ recover_time_ms = 1000,
+ thread_counts = [1, N div 2, N],
+ key_ranges = [1000000],
+ scenarios =
+ [
+ [
+ {0.5, insert},
+ {0.5, delete}
+ ],
+ [
+ {0.1, insert},
+ {0.1, delete},
+ {0.8, lookup}
+ ],
+ [
+ {0.01, insert},
+ {0.01, delete},
+ {0.98, lookup}
+ ],
+ [
+ {0.1, insert},
+ {0.1, delete},
+ {0.4, lookup},
+ {0.4, nextseq100}
+ ],
+ [
+ {0.1, insert},
+ {0.1, delete},
+ {0.79, lookup},
+ {0.01, selectAll}
+ ],
+ [
+ {0.1, insert},
+ {0.1, delete},
+ {0.79, lookup},
+ {0.01, partial_select1000}
+ ]
+ ],
+ table_types =
+ [
+ [ordered_set, public, {write_concurrency, true}, {read_concurrency, true}],
+ [set, public, {write_concurrency, true}, {read_concurrency, true}]
+ ],
+ etsmem_fun = fun etsmem/0,
+ verify_etsmem_fun = fun verify_etsmem/1,
+ notify_res_fun =
+ fun(Name, Throughput) ->
+ SummaryTable =
+ proplists:get_value(ets_benchmark_result_summary_tab, Config),
+ AddToSummaryCounter =
+ case SummaryTable of
+ undefined ->
+ fun(_, _) ->
+ ok
+ end;
+ Tab ->
+ fun(CounterName, ToAdd) ->
+ OldVal = ets:lookup_element(Tab, CounterName, 2),
+ NewVal = OldVal + ToAdd,
+ ets:insert(Tab, {CounterName, NewVal})
+ end
+ end,
+ Record =
+ fun(NoOfBenchsCtr, TotThrputCtr) ->
+ AddToSummaryCounter(NoOfBenchsCtr, 1),
+ AddToSummaryCounter(TotThrputCtr, Throughput)
+ end,
+ Record(nr_of_benchmarks, total_throughput),
+ case string:find(Name, "ordered_set") of
+ nomatch ->
+ Record(nr_of_set_benchmarks, total_throughput_set);
+ _ ->
+ Record(nr_of_ordered_set_benchmarks,
+ total_throughput_ordered_set)
+ end,
+ ct_event:notify(
+ #event{name = benchmark_data,
+ data = [{suite,"ets_bench"},
+ {name, Name},
+ {value,Throughput}]})
+ end
+ }).
add_lists(L1,L2) ->
add_lists(L1,L2,[]).
@@ -5912,16 +7226,11 @@ add_lists([E1|T1], [E2|T2], Acc) ->
run_smp_workers(InitF,ExecF,FiniF,Laps) ->
run_smp_workers(InitF,ExecF,FiniF,Laps, 0).
run_smp_workers(InitF,ExecF,FiniF,Laps, Exclude) ->
- case erlang:system_info(smp_support) of
- true ->
- case erlang:system_info(schedulers_online) of
- N when N > Exclude ->
- run_workers_do(InitF,ExecF,FiniF,Laps, N - Exclude);
- _ ->
- {skipped, "Too few schedulers online"}
- end;
- false ->
- {skipped,"No smp support"}
+ case erlang:system_info(schedulers_online) of
+ N when N > Exclude ->
+ run_workers_do(InitF,ExecF,FiniF,Laps, N - Exclude);
+ _ ->
+ {skipped, "Too few schedulers online"}
end.
run_sched_workers(InitF,ExecF,FiniF,Laps) ->
@@ -5966,8 +7275,11 @@ wait_pids(Pids, Acc) ->
{Pid,Result} ->
true = lists:member(Pid,Pids),
Others = lists:delete(Pid,Pids),
- io:format("wait_pid got ~p from ~p, still waiting for ~p\n",[Result,Pid,Others]),
+ %%io:format("wait_pid got ~p from ~p\n",[Result,Pid]),
wait_pids(Others,[Result | Acc])
+ after 60*1000 ->
+ io:format("Still waiting for workers ~p\n",[Pids]),
+ wait_pids(Pids, Acc)
end.
@@ -5991,48 +7303,25 @@ wait_for_memory_deallocations() ->
wait_for_memory_deallocations()
end.
-
etsmem() ->
- wait_for_memory_deallocations(),
-
- AllTabs = lists:map(fun(T) -> {T,ets:info(T,name),ets:info(T,size),
- ets:info(T,memory),ets:info(T,type)}
- end, ets:all()),
-
- EtsAllocInfo = erlang:system_info({allocator,ets_alloc}),
- ErlangMemoryEts = try erlang:memory(ets) catch error:notsup -> notsup end,
-
- Mem =
- {ErlangMemoryEts,
- case EtsAllocInfo of
- false -> undefined;
- MemInfo ->
- CS = lists:foldl(
- fun ({instance, _, L}, Acc) ->
- {value,{mbcs,MBCS}} = lists:keysearch(mbcs, 1, L),
- {value,{sbcs,SBCS}} = lists:keysearch(sbcs, 1, L),
- NewAcc = [MBCS, SBCS | Acc],
- case lists:keysearch(mbcs_pool, 1, L) of
- {value,{mbcs_pool, MBCS_POOL}} ->
- [MBCS_POOL|NewAcc];
- _ -> NewAcc
- end
- end,
- [],
- MemInfo),
- lists:foldl(
- fun(L, {Bl0,BlSz0}) ->
- {value,BlTup} = lists:keysearch(blocks, 1, L),
- blocks = element(1, BlTup),
- Bl = element(2, BlTup),
- {value,BlSzTup} = lists:keysearch(blocks_size, 1, L),
- blocks_size = element(1, BlSzTup),
- BlSz = element(2, BlSzTup),
- {Bl0+Bl,BlSz0+BlSz}
- end, {0,0}, CS)
- end},
- {Mem,AllTabs}.
+ % The following is done twice to avoid an inconsistent memory
+ % "snapshot" (see verify_etsmem/2).
+ lists:foldl(
+ fun(_,_) ->
+ wait_for_memory_deallocations(),
+
+ AllTabs = lists:map(fun(T) -> {T,ets:info(T,name),ets:info(T,size),
+ ets:info(T,memory),ets:info(T,type)}
+ end, ets:all()),
+ EtsAllocSize = erts_debug:alloc_blocks_size(ets_alloc),
+ ErlangMemoryEts = try erlang:memory(ets) catch error:notsup -> notsup end,
+
+ Mem = {ErlangMemoryEts, EtsAllocSize},
+ {Mem, AllTabs}
+ end,
+ not_used,
+ lists:seq(1,2)).
verify_etsmem(MI) ->
wait_for_test_procs(),
@@ -6053,15 +7342,15 @@ verify_etsmem({MemInfo,AllTabs}, Try) ->
end;
{MemInfo2, AllTabs2} ->
- io:format("Expected: ~p", [MemInfo]),
- io:format("Actual: ~p", [MemInfo2]),
- io:format("Changed tables before: ~p\n",[AllTabs -- AllTabs2]),
- io:format("Changed tables after: ~p\n", [AllTabs2 -- AllTabs]),
+ io:format("#Expected: ~p", [MemInfo]),
+ io:format("#Actual: ~p", [MemInfo2]),
+ io:format("#Changed tables before: ~p\n",[AllTabs -- AllTabs2]),
+ io:format("#Changed tables after: ~p\n", [AllTabs2 -- AllTabs]),
case Try < 2 of
true ->
- io:format("\nThis discrepancy could be caused by an "
+ io:format("\n#This discrepancy could be caused by an "
"inconsistent memory \"snapshot\""
- "\nTry again...\n", []),
+ "\n#Try again...\n", []),
verify_etsmem({MemInfo, AllTabs}, Try+1);
false ->
ct:fail("Failed memory check")
@@ -6096,20 +7385,23 @@ spawn_logger(Procs) ->
ok;
(Proc) ->
Mon = erlang:monitor(process, Proc),
- receive
+ ok = receive
{'DOWN', Mon, _, _, _} ->
ok
after 0 ->
case Kill of
true -> exit(Proc, kill);
- _ ->
- erlang:display({"Waiting for 'DOWN' from", Proc,
- process_info(Proc),
- pid_status(Proc)})
+ _ -> ok
end,
receive
{'DOWN', Mon, _, _, _} ->
ok
+ after 5000 ->
+ io:format("Waiting for 'DOWN' from ~w, status=~w\n"
+ "info = ~p\n", [Proc,
+ pid_status(Proc),
+ process_info(Proc)]),
+ timeout
end
end
end, Procs),
@@ -6245,11 +7537,9 @@ spawn_monitor_with_pid(Pid, Fun, N) ->
only_if_smp(Func) ->
only_if_smp(2, Func).
only_if_smp(Schedulers, Func) ->
- case {erlang:system_info(smp_support),
- erlang:system_info(schedulers_online)} of
- {false,_} -> {skip,"No smp support"};
- {true,N} when N < Schedulers -> {skip,"Too few schedulers online"};
- {true,_} -> Func()
+ case erlang:system_info(schedulers_online) of
+ N when N < Schedulers -> {skip,"Too few schedulers online"};
+ _ -> Func()
end.
%% Copy-paste from emulator/test/binary_SUITE.erl
@@ -6395,7 +7685,7 @@ very_big_num(0, Result) ->
Result.
make_port() ->
- open_port({spawn, "efile"}, [eof]).
+ hd(erlang:ports()).
make_pid() ->
spawn_link(fun sleeper/0).
@@ -6534,22 +7824,49 @@ make_unaligned_sub_binary(List) ->
repeat_for_opts(F) ->
repeat_for_opts(F, [write_concurrency, read_concurrency, compressed]).
+repeat_for_opts_all_table_types(F) ->
+ repeat_for_opts(F, [all_types, write_concurrency, read_concurrency, compressed]).
+
+repeat_for_opts_all_non_stim_table_types(F) ->
+ repeat_for_opts(F, [all_non_stim_types, write_concurrency, read_concurrency, compressed]).
+
+repeat_for_opts_all_set_table_types(F) ->
+ repeat_for_opts(F, [set_types, write_concurrency, read_concurrency, compressed]).
+
+repeat_for_all_set_table_types(F) ->
+ repeat_for_opts(F, [set_types]).
+
+repeat_for_all_ord_set_table_types(F) ->
+ repeat_for_opts(F, [ord_set_types]).
+
+repeat_for_all_non_stim_set_table_types(F) ->
+ repeat_for_opts(F, [all_non_stim_set_types]).
+
+repeat_for_opts_all_ord_set_table_types(F) ->
+ repeat_for_opts(F, [ord_set_types, write_concurrency, read_concurrency, compressed]).
+
repeat_for_opts(F, OptGenList) when is_function(F, 1) ->
repeat_for_opts(F, OptGenList, []).
repeat_for_opts(F, [], Acc) ->
lists:foldl(fun(Opts, RV_Acc) ->
OptList = lists:filter(fun(E) -> E =/= void end, Opts),
- io:format("Calling with options ~p\n",[OptList]),
- RV = F(OptList),
- case RV_Acc of
- {comment,_} -> RV_Acc;
- _ -> case RV of
- {comment,_} -> RV;
- _ -> [RV | RV_Acc]
- end
- end
- end, [], Acc);
+ case is_redundant_opts_combo(OptList) of
+ true ->
+ %%io:format("Ignoring redundant options ~p\n",[OptList]),
+ ok;
+ false ->
+ io:format("Calling with options ~p\n",[OptList]),
+ RV = F(OptList),
+ case RV_Acc of
+ {comment,_} -> RV_Acc;
+ _ -> case RV of
+ {comment,_} -> RV;
+ _ -> [RV | RV_Acc]
+ end
+ end
+ end
+ end, [], Acc);
repeat_for_opts(F, [OptList | Tail], []) when is_list(OptList) ->
repeat_for_opts(F, Tail, [[Opt] || Opt <- OptList]);
repeat_for_opts(F, [OptList | Tail], AccList) when is_list(OptList) ->
@@ -6557,14 +7874,127 @@ repeat_for_opts(F, [OptList | Tail], AccList) when is_list(OptList) ->
repeat_for_opts(F, [Atom | Tail], AccList) when is_atom(Atom) ->
repeat_for_opts(F, [repeat_for_opts_atom2list(Atom) | Tail ], AccList).
-repeat_for_opts_atom2list(all_types) -> [set,ordered_set,bag,duplicate_bag];
+repeat_for_opts_atom2list(set_types) -> [set,ordered_set,stim_cat_ord_set,cat_ord_set];
+repeat_for_opts_atom2list(ord_set_types) -> [ordered_set,stim_cat_ord_set,cat_ord_set];
+repeat_for_opts_atom2list(all_types) -> [set,ordered_set,stim_cat_ord_set,cat_ord_set,bag,duplicate_bag];
+repeat_for_opts_atom2list(all_non_stim_types) -> [set,ordered_set,cat_ord_set,bag,duplicate_bag];
+repeat_for_opts_atom2list(all_non_stim_set_types) -> [set,ordered_set,cat_ord_set];
repeat_for_opts_atom2list(write_concurrency) -> [{write_concurrency,false},{write_concurrency,true}];
repeat_for_opts_atom2list(read_concurrency) -> [{read_concurrency,false},{read_concurrency,true}];
repeat_for_opts_atom2list(compressed) -> [compressed,void].
-ets_new(Name, Opts) ->
- %%ets:new(Name, [compressed | Opts]).
- ets:new(Name, Opts).
+is_redundant_opts_combo(Opts) ->
+ (lists:member(stim_cat_ord_set, Opts) orelse
+ lists:member(cat_ord_set, Opts))
+ andalso
+ (lists:member({write_concurrency, false}, Opts) orelse
+ lists:member(private, Opts) orelse
+ lists:member(protected, Opts)).
+
+%% Add fake table option with info about key range.
+%% Will be consumed by ets_new and used for stim_cat_ord_set.
+key_range(Opts, KeyRange) ->
+ [{key_range, KeyRange} | Opts].
+
+ets_new(Name, Opts0) ->
+ {KeyRange, Opts1} = case lists:keytake(key_range, 1, Opts0) of
+ {value, {key_range, KR}, Rest1} ->
+ {KR, Rest1};
+ false ->
+ {1000*1000, Opts0}
+ end,
+ ets_new(Name, Opts1, KeyRange).
+
+ets_new(Name, Opts, KeyRange) ->
+ ets_new(Name, Opts, KeyRange, fun id/1).
+
+ets_new(Name, Opts0, KeyRange, KeyFun) ->
+ {CATree, Stimulate, RevOpts} =
+ lists:foldl(fun(cat_ord_set, {false, false, Lacc}) ->
+ {true, false, [ordered_set | Lacc]};
+ (stim_cat_ord_set, {false, false, Lacc}) ->
+ {true, true, [ordered_set | Lacc]};
+ (Other, {CAT, STIM, Lacc}) ->
+ {CAT, STIM, [Other | Lacc]}
+ end,
+ {false, false, []},
+ Opts0),
+ Opts = lists:reverse(RevOpts),
+ EtsNewHelper =
+ fun (UseOpts) ->
+ case get(ets_new_opts) of
+ UseOpts ->
+ silence; %% suppress identical table opts spam
+ _ ->
+ put(ets_new_opts, UseOpts),
+ io:format("ets:new(~p, ~p)~n", [Name, UseOpts])
+ end,
+ ets:new(Name, UseOpts)
+ end,
+ case CATree andalso
+ (not lists:member({write_concurrency, false}, Opts)) andalso
+ (not lists:member(private, Opts)) andalso
+ (not lists:member(protected, Opts)) of
+ true ->
+ NewOpts1 =
+ case lists:member({write_concurrency, true}, Opts) of
+ true -> Opts;
+ false -> [{write_concurrency, true}|Opts]
+ end,
+ NewOpts2 =
+ case lists:member(public, NewOpts1) of
+ true -> NewOpts1;
+ false -> [public|NewOpts1]
+ end,
+ T = EtsNewHelper(NewOpts2),
+ case Stimulate of
+ false -> ok;
+ true -> stimulate_contention(T, KeyRange, KeyFun)
+ end,
+ T;
+ false ->
+ EtsNewHelper(Opts)
+ end.
+
+% The purpose of this function is to stimulate fine grained locking in
+% tables of types ordered_set with the write_concurrency options
+% turned on. The erts_debug feature 'ets_force_split' is used to easier
+% generate a routing tree with fine grained locking without having to
+% provoke lots of actual lock contentions.
+stimulate_contention(Tid, KeyRange, KeyFun) ->
+ T = case Tid of
+ A when is_atom(A) -> ets:whereis(A);
+ _ -> Tid
+ end,
+ erts_debug:set_internal_state(ets_force_split, {T, true}),
+ Num = case KeyRange > 50 of
+ true -> 50;
+ false -> KeyRange
+ end,
+ Seed = rand:uniform(KeyRange),
+ %%io:format("prefill_table: Seed = ~p\n", [Seed]),
+ RState = unique_rand_start(KeyRange, Seed),
+ stim_inserter_loop(T, RState, Num, KeyFun),
+ Num = ets:info(T, size),
+ ets:match_delete(T, {'$1','$1','$1'}),
+ 0 = ets:info(T, size),
+ erts_debug:set_internal_state(ets_force_split, {T, false}),
+ case ets:info(T,stats) of
+ {0, _, _} ->
+ io:format("No routing nodes in table?\n"
+ "Debug feature 'ets_force_split' does not seem to work.\n", []),
+ ct:fail("No ets_force_split?");
+ Stats ->
+ io:format("stimulated ordered_set: ~p\n", [Stats])
+ end.
+
+stim_inserter_loop(_, _, 0, _) ->
+ ok;
+stim_inserter_loop(T, RS0, N, KeyFun) ->
+ {K, RS1} = unique_rand_next(RS0),
+ Key = KeyFun(K),
+ ets:insert(T, {Key, Key, Key}),
+ stim_inserter_loop(T, RS1, N-1, KeyFun).
do_tc(Do, Report) ->
T1 = erlang:monotonic_time(),
@@ -6578,3 +8008,50 @@ syrup_factor() ->
valgrind -> 20;
_ -> 1
end.
+
+
+%%
+%% This is a pseudo random number generator for UNIQUE integers.
+%% All integers between 1 and Max will be generated before it repeat itself.
+%% It's a variant of this one using quadratic residues by Jeff Preshing:
+%% http://preshing.com/20121224/how-to-generate-a-sequence-of-unique-random-integers/
+%%
+unique_rand_start(Max, Seed) ->
+ L = lists:dropwhile(fun(P) -> P < Max end,
+ primes_3mod4()),
+ [P | _] = case L of
+ [] ->
+ error("Random range too large");
+ _ ->
+ L
+ end,
+ 3 = P rem 4,
+ {0, {Max, P, Seed}}.
+
+unique_rand_next({N, {Max, P, Seed}=Const}) ->
+ case dquad(P, N, Seed) + 1 of
+ RND when RND > Max -> % Too large, skip
+ unique_rand_next({N+1, Const});
+ RND ->
+ {RND, {N+1, Const}}
+ end.
+
+%% A one-to-one relation between all integers 0 =< X < Prime
+%% if Prime rem 4 == 3.
+quad(Prime, X) ->
+ Rem = X*X rem Prime,
+ case 2*X < Prime of
+ true ->
+ Rem;
+ false ->
+ Prime - Rem
+ end.
+
+dquad(Prime, X, Seed) ->
+ quad(Prime, (quad(Prime, X) + Seed) rem Prime).
+
+%% Primes where P rem 4 == 3.
+primes_3mod4() ->
+ [103, 211, 503, 1019, 2003, 5003, 10007, 20011, 50023,
+ 100003, 200003, 500083, 1000003, 2000003, 5000011,
+ 10000019, 20000003, 50000047, 100000007].
diff --git a/lib/stdlib/test/ets_SUITE_data/visualize_throughput.html b/lib/stdlib/test/ets_SUITE_data/visualize_throughput.html
new file mode 100644
index 0000000000..27d6849c60
--- /dev/null
+++ b/lib/stdlib/test/ets_SUITE_data/visualize_throughput.html
@@ -0,0 +1,253 @@
+<!doctype html>
+<html lang="en">
+
+<!-- %% -->
+<!-- %% %CopyrightBegin% -->
+<!-- %% -->
+<!-- %% Copyright Ericsson AB and Kjell Winblad 1996-2018. All Rights Reserved. -->
+<!-- %% -->
+<!-- %% Licensed under the Apache License, Version 2.0 (the "License"); -->
+<!-- %% you may not use this file except in compliance with the License. -->
+<!-- %% You may obtain a copy of the License at -->
+<!-- %% -->
+<!-- %% http://www.apache.org/licenses/LICENSE-2.0 -->
+<!-- %% -->
+<!-- %% Unless required by applicable law or agreed to in writing, software -->
+<!-- %% distributed under the License is distributed on an "AS IS" BASIS, -->
+<!-- %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -->
+<!-- %% See the License for the specific language governing permissions and -->
+<!-- %% limitations under the License. -->
+<!-- %% -->
+<!-- %% %CopyrightEnd% -->
+<!-- %% -->
+<!-- %% Author: Kjell Winblad -->
+<!-- %% -->
+
+ <head>
+ <meta charset="utf-8">
+ <title>ETS Benchmark Result Viewer</title>
+ </head>
+
+ <body>
+ <div id="insertPlaceholder"></div>
+ <h1>ETS Benchmark Result Viewer</h1>
+ <p>
+ This page generates graphs from data produced by the ETS benchmark which is defined in the function <code>ets_SUITE:throughput_benchmark/0</code> (see "<code>$ERL_TOP/lib/stdlib/test/ets_SUITE.erl</code>").
+ </p>
+ <p>
+ Note that one can paste results from several benchmark runs into the field below. Results from the same scenario but from different benchmark runs will be relabeled and ploted in the same graph automatically. This makes comparisons of different ETS versions easy.
+ </p>
+ <p>
+ Note also that that lines can be hidden by clicking on the corresponding label.
+ </p>
+ Paste the generated data in the field below and press the Render button:
+ <br>
+ <textarea id="dataField" rows="4" cols="50">#bench_data_placeholder</textarea>
+ <br>
+ <input type="checkbox" id="barPlot"> Bar Plot
+ <br>
+ <input type="checkbox" id="sameSpacing" checked> Same X Spacing Between Points
+ <br>
+ <input type="checkbox" class="showCheck" value="[ordered_set,public]" checked> Show <code>[ordered_set,public]</code>
+ <br>
+ <input type="checkbox" class="showCheck" value="[ordered_set,public,{write_concurrency,true}]" checked> Show <code>[ordered_set,public,{write_concurrency,true}]</code>
+ <br>
+ <input type="checkbox" class="showCheck" value="[ordered_set,public,{read_concurrency,true}]" checked> Show <code>[ordered_set,public,{read_concurrency,true}]</code>
+ <br>
+ <input type="checkbox" class="showCheck" value="[ordered_set,public,{write_concurrency,true},{read_concurrency,true}]" checked> Show <code>[ordered_set,public,{write_concurrency,true},{read_concurrency,true}]</code>
+ <br>
+ <input type="checkbox" class="showCheck" value="[set,public]" checked> Show <code>[set,public]</code>
+ <br>
+ <input type="checkbox" class="showCheck" value="[set,public,{write_concurrency,true}]" checked> Show <code>[set,public,{write_concurrency,true}]</code>
+ <br>
+ <input type="checkbox" class="showCheck" value="[set,public,{read_concurrency,true}]" checked> Show <code>[set,public,{read_concurrency,true}]</code>
+ <br>
+ <input type="checkbox" class="showCheck" value="[set,public,{write_concurrency,true},{read_concurrency,true}]" checked> Show <code>[set,public,{write_concurrency,true},{read_concurrency,true}]</code>
+ <br>
+ <button id="renderButton" type="button">Render</button>
+
+ <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
+ integrity="sha256-3edrmyuQ0w65f8gfBsqowzjJe2iM6n0nKciPUp8y+7E="
+ crossorigin="anonymous"></script>
+ <script>
+ var loading = false;
+ function toggleLoadingScreen(){
+ if(loading){
+ $("#loading").remove();
+ loading = false;
+ }else{
+ $('<div id="loading">'+
+ '<span style="position: fixed; top: 50%;left: 50%;color: white;"><b>Loading...</b></span>'+
+ '</div>')
+ .css({position: "fixed",
+ top: 0,
+ left: 0,
+ width: "100%",
+ height: "100%",
+ 'background-color': "#000",
+ filter:"alpha(opacity=50)",
+ '-moz-opacity':"0.5",
+ '-khtml-opacity': "0.5",
+ opacity: "0.5",
+ 'z-index': "10000"})
+ .appendTo(document.body);
+ loading = true;
+
+ }
+ }
+ //Start loading screen before downloading plotly which is quite large
+ toggleLoadingScreen();
+ </script>
+ <script src="https://cdn.plot.ly/plotly-1.5.0.min.js"></script>
+ <script>
+ String.prototype.replaceAll = function(search, replacement) {
+ var target = this;
+ return target.split(search).join(replacement);
+ };
+ String.prototype.myTrim = function() {
+ var target = this;
+ return target.replace(/^\s+|\s+$/g, '');
+ };
+ function plotGraph(lines, sameSpacing, barPlot, prefix) {
+ var xvals = null;
+ var data = [];
+ while(lines.length > 0 &&
+ (lines[0].myTrim() == "" ||
+ lines[0].myTrim().indexOf(";") !== -1)){
+ var line = lines.shift().myTrim();
+ if(line == "" || line.startsWith("#")){
+ continue;
+ } else if(line.startsWith(";")) {
+ xvals = line.split(";")
+ xvals.shift(); // Remove first
+ xvals = $.map(xvals, function (i){
+ if(sameSpacing){
+ return "_"+i.myTrim();
+ }else{
+ return parseInt(i.myTrim(), 10);
+ }
+ });
+ }else{
+ line = line.split(";")
+ var label = prefix + line.shift().myTrim();
+ var yvals = $.map(line, function (i){
+ return parseFloat(i.myTrim(), 10);
+ });
+ var trace = {
+ x: xvals,
+ y: yvals,
+ mode: 'lines+markers',
+ name: label
+ };
+ if(barPlot){
+ trace['type'] = "bar";
+ }
+ data.push(trace);
+ }
+
+ }
+ return data;
+ }
+ function plotGraphs(){
+ var insertPlaceholder = $("#insertPlaceholder");
+ var sameSpacing = $('#sameSpacing').is(":checked");
+ var barPlot = $('#barPlot').is(":checked");
+ var lines = $("#dataField").val();
+ $('.showCheck').each(function() {
+ var item = $(this);
+ if(!item.is(":checked")){
+ lines = lines.replaceAll(item.val(), "#"+item.val())
+ }
+ });
+ lines = lines.split("$");
+ var nrOfGraphs = 0;
+ var scenarioDataMap = {};
+ var scenarioNrOfVersionsMap = {};
+ var scenarioList = [];
+ while(lines.length > 0){
+ var line = lines.shift().myTrim();
+ if(line == ""){
+ continue;
+ } else if(line.startsWith("Scenario:")) {
+ nrOfGraphs = nrOfGraphs + 1;
+ var name = line;
+ if(scenarioDataMap[name] === undefined){
+ scenarioDataMap[name] = [];
+ scenarioNrOfVersionsMap[name] = 0;
+ scenarioList.push(line);
+ }
+ scenarioNrOfVersionsMap[name] = scenarioNrOfVersionsMap[name] + 1;
+ var prefix = undefined;
+ if(scenarioNrOfVersionsMap[name] === 1){
+ prefix = "";
+ }else{
+ prefix = "Ver: " + scenarioNrOfVersionsMap[name] + " ";
+ }
+ scenarioDataMap[name] =
+ scenarioDataMap[name].concat(
+ plotGraph(lines, sameSpacing, barPlot, prefix));
+ }
+ }
+ $.each(scenarioList,
+ function( index, name ) {
+ var nrOfGraphs = index + 1;
+ var data = scenarioDataMap[name];
+ $( "<div class='added' id='graph"+nrOfGraphs+"'>")
+ .insertBefore( insertPlaceholder );
+ $( "<button type='button' class='added' id='fullscreenButton"+nrOfGraphs+"'>Fill screen</button>")
+ .insertBefore( insertPlaceholder );
+ $( "<span class='added'><br><hr><br></span>")
+ .insertBefore( insertPlaceholder );
+ var layout = {
+ title:name,
+ xaxis: {
+ title: '# of Processes'
+ },
+ yaxis: {
+ title: 'Operations/Second'
+ }
+
+ };
+
+ $("#fullscreenButton"+nrOfGraphs).click(
+ function(){
+ $('#graph'+nrOfGraphs).replaceWith(
+ $("<div class='added' id='graph"+nrOfGraphs+"'>"));
+ layout = $.extend({}, layout, {
+ width:$(window).width()-40,
+ height:$(window).height()-40
+ });
+ Plotly.newPlot('graph'+nrOfGraphs, data, layout);
+ });
+ Plotly.newPlot('graph'+nrOfGraphs, data, layout);
+
+ });
+
+
+ }
+ $(document).ready(function(){
+ $('#renderButton').click(
+ function(){
+ toggleLoadingScreen();
+ setTimeout(function(){
+ try {
+ $( ".added" ).remove();
+ plotGraphs();
+ toggleLoadingScreen();
+ } catch(e){
+ toggleLoadingScreen();
+ console.log(e);
+ alert("Error happened when parsing data.\n" +
+ "See console for more info");
+ }
+ }, 10);
+ });
+ setTimeout(function(){
+ $( ".added" ).remove();
+ plotGraphs();
+ toggleLoadingScreen();
+ }, 10);
+ });
+ </script>
+ </body>
+</html>
diff --git a/lib/stdlib/test/filelib_SUITE.erl b/lib/stdlib/test/filelib_SUITE.erl
index afaf2404fa..7403d52881 100644
--- a/lib/stdlib/test/filelib_SUITE.erl
+++ b/lib/stdlib/test/filelib_SUITE.erl
@@ -33,6 +33,8 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("kernel/include/file.hrl").
+-define(PRIM_FILE, prim_file).
+
init_per_testcase(_Case, Config) ->
Config.
@@ -120,7 +122,7 @@ wcc(Wc, Error) ->
do_wildcard_1(Dir, Wcf0) ->
do_wildcard_2(Dir, Wcf0),
Wcf = fun(Wc0) ->
- Wc = filename:join(Dir, Wc0),
+ Wc = Dir ++ "/" ++ Wc0,
L = Wcf0(Wc),
[subtract_dir(N, Dir) || N <- L]
end,
@@ -268,8 +270,37 @@ do_wildcard_9(Dir, Wcf) ->
%% Cleanup.
del(Files),
[ok = file:del_dir(D) || D <- lists:reverse(Dirs)],
- ok.
+ do_wildcard_10(Dir, Wcf).
+
+%% ERL-451/OTP-14577: Escape characters using \\.
+do_wildcard_10(Dir, Wcf) ->
+ All0 = ["{abc}","abc","def","---","z--","@a,b","@c"],
+ All = case os:type() of
+ {unix,_} ->
+ %% '?' is allowed in file names on Unix, but
+ %% not on Windows.
+ ["?q"|All0];
+ _ ->
+ All0
+ end,
+ Files = mkfiles(lists:reverse(All), Dir),
+ ["{abc}"] = Wcf("\\{a*"),
+ ["{abc}"] = Wcf("\\{abc}"),
+ ["abc","def","z--"] = Wcf("[a-z]*"),
+ ["---","abc","z--"] = Wcf("[a\\-z]*"),
+ ["@a,b","@c"] = Wcf("@{a\\,b,c}"),
+ ["@c"] = Wcf("@{a,b,c}"),
+
+ case os:type() of
+ {unix,_} ->
+ ["?q"] = Wcf("\\?q");
+ _ ->
+ [] = Wcf("\\?q")
+ end,
+
+ del(Files),
+ ok.
fold_files(Config) when is_list(Config) ->
Dir = filename:join(proplists:get_value(priv_dir, Config), "fold_files"),
@@ -417,10 +448,10 @@ wildcard_symlink(Config) when is_list(Config) ->
erl_prim_loader)),
["sub","symlink"] =
basenames(Dir, filelib:wildcard(filename:join(Dir, "*"),
- prim_file)),
+ ?PRIM_FILE)),
["symlink"] =
basenames(Dir, filelib:wildcard(filename:join(Dir, "symlink"),
- prim_file)),
+ ?PRIM_FILE)),
ok = file:delete(AFile),
%% The symlink should still be visible even when its target
%% has been deleted.
@@ -436,10 +467,10 @@ wildcard_symlink(Config) when is_list(Config) ->
erl_prim_loader)),
["sub","symlink"] =
basenames(Dir, filelib:wildcard(filename:join(Dir, "*"),
- prim_file)),
+ ?PRIM_FILE)),
["symlink"] =
basenames(Dir, filelib:wildcard(filename:join(Dir, "symlink"),
- prim_file)),
+ ?PRIM_FILE)),
ok
end.
@@ -468,17 +499,17 @@ is_file_symlink(Config) ->
ok ->
true = filelib:is_dir(DirAlias),
true = filelib:is_dir(DirAlias, erl_prim_loader),
- true = filelib:is_dir(DirAlias, prim_file),
+ true = filelib:is_dir(DirAlias, ?PRIM_FILE),
true = filelib:is_file(DirAlias),
true = filelib:is_file(DirAlias, erl_prim_loader),
- true = filelib:is_file(DirAlias, prim_file),
+ true = filelib:is_file(DirAlias, ?PRIM_FILE),
ok = file:make_symlink(AFile,FileAlias),
true = filelib:is_file(FileAlias),
true = filelib:is_file(FileAlias, erl_prim_loader),
- true = filelib:is_file(FileAlias, prim_file),
+ true = filelib:is_file(FileAlias, ?PRIM_FILE),
true = filelib:is_regular(FileAlias),
true = filelib:is_regular(FileAlias, erl_prim_loader),
- true = filelib:is_regular(FileAlias, prim_file),
+ true = filelib:is_regular(FileAlias, ?PRIM_FILE),
ok
end.
@@ -499,11 +530,11 @@ file_props_symlink(Config) ->
{_,_} = LastMod = filelib:last_modified(AFile),
LastMod = filelib:last_modified(Alias),
LastMod = filelib:last_modified(Alias, erl_prim_loader),
- LastMod = filelib:last_modified(Alias, prim_file),
+ LastMod = filelib:last_modified(Alias, ?PRIM_FILE),
FileSize = filelib:file_size(AFile),
FileSize = filelib:file_size(Alias),
FileSize = filelib:file_size(Alias, erl_prim_loader),
- FileSize = filelib:file_size(Alias, prim_file)
+ FileSize = filelib:file_size(Alias, ?PRIM_FILE)
end.
find_source(Config) when is_list(Config) ->
diff --git a/lib/stdlib/test/gen_fsm_SUITE.erl b/lib/stdlib/test/gen_fsm_SUITE.erl
index 41ee3246f5..62d9d0e0ae 100644
--- a/lib/stdlib/test/gen_fsm_SUITE.erl
+++ b/lib/stdlib/test/gen_fsm_SUITE.erl
@@ -124,8 +124,10 @@ start2(Config) when is_list(Config) ->
{ok, Pid0} = gen_fsm:start(gen_fsm_SUITE, [], []),
ok = do_func_test(Pid0),
ok = do_sync_func_test(Pid0),
+ MRef = monitor(process,Pid0),
shutdown_stopped =
gen_fsm:sync_send_all_state_event(Pid0, stop_shutdown),
+ receive {'DOWN',MRef,_,_,shutdown} -> ok end,
{'EXIT', {noproc,_}} =
(catch gen_fsm:sync_send_event(Pid0, hej)),
@@ -519,14 +521,16 @@ error_format_status(Config) when is_list(Config) ->
error_logger_forwarder:register(),
OldFl = process_flag(trap_exit, true),
StateData = "called format_status",
+ Parent = self(),
{ok, Pid} = gen_fsm:start(gen_fsm_SUITE, {state_data, StateData}, []),
%% bad return value in the gen_fsm loop
{'EXIT',{{bad_return_value, badreturn},_}} =
(catch gen_fsm:sync_send_event(Pid, badreturn)),
receive
{error,_GroupLeader,{Pid,
- "** State machine"++_,
- [Pid,{_,_,badreturn},idle,{formatted,StateData},_]}} ->
+ "** State machine "++_,
+ [Pid,badreturn,Parent,idle,{formatted,StateData},
+ {bad_return_value,badreturn}|_]}} ->
ok;
Other ->
io:format("Unexpected: ~p", [Other]),
@@ -539,12 +543,14 @@ terminate_crash_format(Config) when is_list(Config) ->
error_logger_forwarder:register(),
OldFl = process_flag(trap_exit, true),
StateData = crash_terminate,
+ Parent = self(),
{ok, Pid} = gen_fsm:start(gen_fsm_SUITE, {state_data, StateData}, []),
stop_it(Pid),
receive
{error,_GroupLeader,{Pid,
- "** State machine"++_,
- [Pid,{_,_,_},idle,{formatted, StateData},_]}} ->
+ "** State machine "++_,
+ [Pid,stop,Parent,idle,{formatted, StateData},
+ {crash,terminate}|_]}} ->
ok;
Other ->
io:format("Unexpected: ~p", [Other]),
diff --git a/lib/stdlib/test/gen_server_SUITE.erl b/lib/stdlib/test/gen_server_SUITE.erl
index 7d9561db24..e29195e895 100644
--- a/lib/stdlib/test/gen_server_SUITE.erl
+++ b/lib/stdlib/test/gen_server_SUITE.erl
@@ -27,7 +27,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2]).
-export([start/1, crash/1, call/1, cast/1, cast_fast/1,
- info/1, abcast/1, multicall/1, multicall_down/1,
+ continue/1, info/1, abcast/1, multicall/1, multicall_down/1,
call_remote1/1, call_remote2/1, call_remote3/1,
call_remote_n1/1, call_remote_n2/1, call_remote_n3/1, spec_init/1,
spec_init_local_registered_parent/1,
@@ -37,7 +37,8 @@
get_state/1, replace_state/1, call_with_huge_message_queue/1,
undef_handle_call/1, undef_handle_cast/1, undef_handle_info/1,
undef_init/1, undef_code_change/1, undef_terminate1/1,
- undef_terminate2/1, undef_in_terminate/1, undef_in_handle_info/1
+ undef_terminate2/1, undef_in_terminate/1, undef_in_handle_info/1,
+ undef_handle_continue/1
]).
-export([stop1/1, stop2/1, stop3/1, stop4/1, stop5/1, stop6/1, stop7/1,
@@ -52,7 +53,7 @@
%% The gen_server behaviour
--export([init/1, handle_call/3, handle_cast/2,
+-export([init/1, handle_call/3, handle_cast/2, handle_continue/2,
handle_info/2, code_change/3, terminate/2, format_status/2]).
suite() ->
@@ -61,7 +62,7 @@ suite() ->
all() ->
[start, {group,stop}, crash, call, cast, cast_fast, info, abcast,
- multicall, multicall_down, call_remote1, call_remote2,
+ continue, multicall, multicall_down, call_remote1, call_remote2,
call_remote3, call_remote_n1, call_remote_n2,
call_remote_n3, spec_init,
spec_init_local_registered_parent,
@@ -76,7 +77,7 @@ groups() ->
[{stop, [],
[stop1, stop2, stop3, stop4, stop5, stop6, stop7, stop8, stop9, stop10]},
{undef_callbacks, [],
- [undef_handle_call, undef_handle_cast, undef_handle_info,
+ [undef_handle_call, undef_handle_cast, undef_handle_info, undef_handle_continue,
undef_init, undef_code_change, undef_terminate1, undef_terminate2]}].
@@ -458,6 +459,47 @@ call(Config) when is_list(Config) ->
ok.
%% --------------------------------------
+%% Test handle_continue.
+%% --------------------------------------
+
+continue(Config) when is_list(Config) ->
+ {ok, Pid} = gen_server:start_link(gen_server_SUITE, {continue, self()}, []),
+ [{Pid, continue}, {Pid, after_continue}] = read_replies(Pid),
+
+ gen_server:call(Pid, {continue_reply, self()}),
+ [{Pid, continue}, {Pid, after_continue}] = read_replies(Pid),
+
+ gen_server:call(Pid, {continue_noreply, self()}),
+ [{Pid, continue}, {Pid, after_continue}] = read_replies(Pid),
+
+ gen_server:cast(Pid, {continue_noreply, self()}),
+ [{Pid, continue}, {Pid, after_continue}] = read_replies(Pid),
+
+ Pid ! {continue_noreply, self()},
+ [{Pid, continue}, {Pid, after_continue}] = read_replies(Pid),
+
+ Pid ! {continue_continue, self()},
+ [{Pid, before_continue}, {Pid, continue}, {Pid, after_continue}] = read_replies(Pid),
+
+ Ref = monitor(process, Pid),
+ Pid ! continue_stop,
+ verify_down_reason(Ref, Pid, normal).
+
+read_replies(Pid) ->
+ receive
+ {Pid, ack} -> read_replies()
+ after
+ 1000 -> ct:fail({continue, ack})
+ end.
+
+read_replies() ->
+ receive
+ Msg -> [Msg | read_replies()]
+ after
+ 0 -> []
+ end.
+
+%% --------------------------------------
%% Test call to nonexisting processes on remote nodes
%% --------------------------------------
@@ -1346,7 +1388,7 @@ echo_loop() ->
%% Test the default implementation of terminate if the callback module
%% does not export it
undef_terminate1(Config) when is_list(Config) ->
- {ok, Server} = gen_server:start(oc_server, [], []),
+ {ok, Server} = oc_server:start(),
MRef = monitor(process, Server),
ok = gen_server:stop(Server),
ok = verify_down_reason(MRef, Server, normal).
@@ -1354,7 +1396,7 @@ undef_terminate1(Config) when is_list(Config) ->
%% Test the default implementation of terminate if the callback module
%% does not export it
undef_terminate2(Config) when is_list(Config) ->
- {ok, Server} = gen_server:start(oc_server, [], []),
+ {ok, Server} = oc_server:start(),
MRef = monitor(process, Server),
ok = gen_server:stop(Server, {error, test}, infinity),
ok = verify_down_reason(MRef, Server, {error, test}).
@@ -1377,7 +1419,7 @@ undef_init(_Config) ->
%% The upgrade should fail if code_change is expected in the callback module
%% but not exported, but the server should continue with the old code
undef_code_change(Config) when is_list(Config) ->
- {ok, Server} = gen_server:start(oc_server, [], []),
+ {ok, Server} = oc_server:start(),
{error, {'EXIT', {undef, [{oc_server, code_change, [_, _, _], _}|_]}}}
= fake_upgrade(Server, ?MODULE),
true = is_process_alive(Server).
@@ -1385,7 +1427,7 @@ undef_code_change(Config) when is_list(Config) ->
%% The server should crash if the handle_call callback is
%% not exported in the callback module
undef_handle_call(_Config) ->
- {ok, Server} = gen_server:start(oc_server, [], []),
+ {ok, Server} = oc_server:start(),
try
gen_server:call(Server, call_msg),
ct:fail(should_crash)
@@ -1397,17 +1439,25 @@ undef_handle_call(_Config) ->
%% The server should crash if the handle_cast callback is
%% not exported in the callback module
undef_handle_cast(_Config) ->
- {ok, Server} = gen_server:start(oc_server, [], []),
+ {ok, Server} = oc_server:start(),
MRef = monitor(process, Server),
gen_server:cast(Server, cast_msg),
verify_undef_down(MRef, Server, oc_server, handle_cast),
ok.
+%% The server should crash if the handle_continue callback is
+%% not exported in the callback module
+undef_handle_continue(_Config) ->
+ {ok, Server} = oc_server:start(continue),
+ MRef = monitor(process, Server),
+ verify_undef_down(MRef, Server, oc_server, handle_continue),
+ ok.
+
%% The server should log but not crash if the handle_info callback is
%% calling an undefined function
undef_handle_info(Config) when is_list(Config) ->
error_logger_forwarder:register(),
- {ok, Server} = gen_server:start(oc_server, [], []),
+ {ok, Server} = oc_server:start(),
Server ! hej,
wait_until_processed(Server, hej, 10),
true = is_process_alive(Server),
@@ -1570,8 +1620,11 @@ init(hibernate) ->
init(sleep) ->
ct:sleep(1000),
{ok, []};
+init({continue, Pid}) ->
+ self() ! {after_continue, Pid},
+ {ok, [], {continue, {message, Pid}}};
init({state,State}) ->
- {ok, State}.
+ {ok,State}.
handle_call(started_p, _From, State) ->
io:format("FROZ"),
@@ -1604,6 +1657,12 @@ handle_call(shutdown_reason, _From, _State) ->
handle_call({call_undef_fun, Mod, Fun}, _From, State) ->
Mod:Fun(),
{reply, ok, State};
+handle_call({continue_reply, Pid}, _From, State) ->
+ self() ! {after_continue, Pid},
+ {reply, ok, State, {continue, {message, Pid}}};
+handle_call({continue_noreply, Pid}, From, State) ->
+ self() ! {after_continue, Pid},
+ {noreply, State, {continue, {message, Pid, From}}};
handle_call(stop_shutdown_reason, _From, State) ->
{stop,{shutdown,stop_reason},State}.
@@ -1620,6 +1679,9 @@ handle_cast(hibernate_later, _State) ->
handle_cast({call_undef_fun, Mod, Fun}, State) ->
Mod:Fun(),
{noreply, State};
+handle_cast({continue_noreply, Pid}, State) ->
+ self() ! {after_continue, Pid},
+ {noreply, State, {continue, {message, Pid}}};
handle_cast({From, stop}, State) ->
io:format("BAZ"),
{stop, {From,stopped}, State}.
@@ -1657,9 +1719,34 @@ handle_info(continue, From) ->
{noreply, []};
handle_info({From, stop}, State) ->
{stop, {From,stopped_info}, State};
+handle_info({after_continue, Pid}, State) ->
+ Pid ! {self(), after_continue},
+ Pid ! {self(), ack},
+ {noreply, State};
+handle_info({continue_noreply, Pid}, State) ->
+ self() ! {after_continue, Pid},
+ {noreply, State, {continue, {message, Pid}}};
+handle_info({continue_continue, Pid}, State) ->
+ {noreply, State, {continue, {continue, Pid}}};
+handle_info(continue_stop, State) ->
+ {noreply, State, {continue, stop}};
handle_info(_Info, State) ->
{noreply, State}.
+handle_continue({continue, Pid}, State) ->
+ Pid ! {self(), before_continue},
+ self() ! {after_continue, Pid},
+ {noreply, State, {continue, {message, Pid}}};
+handle_continue(stop, State) ->
+ {stop, normal, State};
+handle_continue({message, Pid}, State) ->
+ Pid ! {self(), continue},
+ {noreply, State};
+handle_continue({message, Pid, From}, State) ->
+ Pid ! {self(), continue},
+ gen_server:reply(From, ok),
+ {noreply, State}.
+
code_change(_OldVsn,
{new, {undef_in_code_change, {Mod, Fun}}} = State,
_Extra) ->
diff --git a/lib/stdlib/test/gen_server_SUITE_data/oc_server.erl b/lib/stdlib/test/gen_server_SUITE_data/oc_server.erl
index 4ba37987f3..7b92a49bf6 100644
--- a/lib/stdlib/test/gen_server_SUITE_data/oc_server.erl
+++ b/lib/stdlib/test/gen_server_SUITE_data/oc_server.erl
@@ -22,7 +22,7 @@
-behaviour(gen_server).
%% API
--export([start/0]).
+-export([start/0, start/1]).
%% gen_server callbacks
-export([init/1]).
@@ -30,8 +30,12 @@
-record(state, {}).
start() ->
- gen_server:start({local, ?MODULE}, ?MODULE, [], []).
+ gen_server:start(?MODULE, ok, []).
-init([]) ->
- {ok, #state{}}.
+start(continue) ->
+ gen_server:start(?MODULE, continue, []).
+init(ok) ->
+ {ok, #state{}};
+init(continue) ->
+ {ok, #state{}, {continue, continue}}.
diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl
index 5b9daecfd3..16cf8f43f9 100644
--- a/lib/stdlib/test/gen_statem_SUITE.erl
+++ b/lib/stdlib/test/gen_statem_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2016-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2016-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,7 +21,7 @@
-include_lib("common_test/include/ct.hrl").
--compile(export_all).
+-compile([export_all, nowarn_export_all]).
-behaviour(gen_statem).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -60,7 +60,8 @@ tcs(start) ->
tcs(stop) ->
[stop1, stop2, stop3, stop4, stop5, stop6, stop7, stop8, stop9, stop10];
tcs(abnormal) ->
- [abnormal1, abnormal1clean, abnormal1dirty, abnormal2];
+ [abnormal1, abnormal1clean, abnormal1dirty,
+ abnormal2, abnormal3, abnormal4];
tcs(sys) ->
[sys1, call_format_status,
error_format_status, terminate_crash_format,
@@ -120,7 +121,8 @@ end_per_testcase(_CaseName, Config) ->
start1(Config) ->
%%OldFl = process_flag(trap_exit, true),
- {ok,Pid0} = gen_statem:start_link(?MODULE, start_arg(Config, []), []),
+ {ok,Pid0} =
+ gen_statem:start_link(?MODULE, start_arg(Config, []), [{debug,[trace]}]),
ok = do_func_test(Pid0),
ok = do_sync_func_test(Pid0),
stop_it(Pid0),
@@ -134,7 +136,8 @@ start1(Config) ->
%% anonymous w. shutdown
start2(Config) ->
%% Dont link when shutdown
- {ok,Pid0} = gen_statem:start(?MODULE, start_arg(Config, []), []),
+ {ok,Pid0} =
+ gen_statem:start(?MODULE, start_arg(Config, []), []),
ok = do_func_test(Pid0),
ok = do_sync_func_test(Pid0),
stopped = gen_statem:call(Pid0, {stop,shutdown}),
@@ -510,7 +513,9 @@ abnormal1dirty(Config) ->
%% trap exit since we must link to get the real bad_return_ error
abnormal2(Config) ->
OldFl = process_flag(trap_exit, true),
- {ok,Pid} = gen_statem:start_link(?MODULE, start_arg(Config, []), []),
+ {ok,Pid} =
+ gen_statem:start_link(
+ ?MODULE, start_arg(Config, []), [{debug,[log]}]),
%% bad return value in the gen_statem loop
{{{bad_return_from_state_function,badreturn},_},_} =
@@ -524,6 +529,47 @@ abnormal2(Config) ->
process_flag(trap_exit, OldFl),
ok = verify_empty_msgq().
+%% Check that bad return actions makes the stm crash. Note that we must
+%% trap exit since we must link to get the real bad_return_ error
+abnormal3(Config) ->
+ OldFl = process_flag(trap_exit, true),
+ {ok,Pid} =
+ gen_statem:start_link(
+ ?MODULE, start_arg(Config, []), [{debug,[log]}]),
+
+ %% bad return value in the gen_statem loop
+ {{{bad_action_from_state_function,badaction},_},_} =
+ ?EXPECT_FAILURE(gen_statem:call(Pid, badaction), Reason),
+ receive
+ {'EXIT',Pid,{{bad_action_from_state_function,badaction},_}} -> ok
+ after 5000 ->
+ ct:fail(gen_statem_did_not_die)
+ end,
+
+ process_flag(trap_exit, OldFl),
+ ok = verify_empty_msgq().
+
+%% Check that bad timeout actions makes the stm crash. Note that we must
+%% trap exit since we must link to get the real bad_return_ error
+abnormal4(Config) ->
+ OldFl = process_flag(trap_exit, true),
+ {ok,Pid} =
+ gen_statem:start_link(
+ ?MODULE, start_arg(Config, []), [{debug,[log]}]),
+
+ %% bad return value in the gen_statem loop
+ BadTimeout = {badtimeout,4711,ouch},
+ {{{bad_action_from_state_function,BadTimeout},_},_} =
+ ?EXPECT_FAILURE(gen_statem:call(Pid, BadTimeout), Reason),
+ receive
+ {'EXIT',Pid,{{bad_action_from_state_function,BadTimeout},_}} -> ok
+ after 5000 ->
+ ct:fail(gen_statem_did_not_die)
+ end,
+
+ process_flag(trap_exit, OldFl),
+ ok = verify_empty_msgq().
+
shutdown(Config) ->
process_flag(trap_exit, true),
@@ -603,51 +649,80 @@ state_enter(_Config) ->
end,
start =>
fun (enter, Prev, N) ->
- Self ! {enter,start,Prev,N},
+ Self ! {N,enter,start,Prev},
{keep_state,N + 1};
(internal, Prev, N) ->
- Self ! {internal,start,Prev,N},
+ Self ! {N,internal,start,Prev},
{keep_state,N + 1};
+ (timeout, M, N) ->
+ {keep_state, N + 1,
+ {reply, {Self,N}, {timeout,M}}};
({call,From}, repeat, N) ->
{repeat_state,N + 1,
- [{reply,From,{repeat,start,N}}]};
+ [{reply,From,{N,repeat,start}}]};
({call,From}, echo, N) ->
{next_state,wait,N + 1,
- {reply,From,{echo,start,N}}};
+ [{reply,From,{N,echo,start}},{timeout,0,N}]};
({call,From}, {stop,Reason}, N) ->
{stop_and_reply,Reason,
- [{reply,From,{stop,N}}],N + 1}
+ [{reply,From,{N,stop}}],N + 1}
end,
wait =>
fun (enter, Prev, N) when N < 5 ->
{repeat_state,N + 1,
- {reply,{Self,N},{enter,Prev}}};
+ [{reply,{Self,N},{enter,Prev}},
+ {timeout,0,N},
+ {state_timeout,0,N}]};
(enter, Prev, N) ->
- Self ! {enter,wait,Prev,N},
- {keep_state,N + 1};
+ Self ! {N,enter,wait,Prev},
+ {keep_state,N + 1,
+ [{timeout,0,N},
+ {state_timeout,0,N}]};
+ (timeout, M, N) ->
+ {keep_state, N + 1,
+ {reply, {Self,N}, {timeout,M}}};
+ (state_timeout, M, N) ->
+ {keep_state, N + 1,
+ {reply, {Self,N}, {state_timeout,M}}};
({call,From}, repeat, N) ->
{repeat_state_and_data,
- [{reply,From,{repeat,wait,N}}]};
+ [{reply,From,{N,repeat,wait}},
+ {timeout,0,N}]};
({call,From}, echo, N) ->
{next_state,start,N + 1,
[{next_event,internal,wait},
- {reply,From,{echo,wait,N}}]}
+ {reply,From,{N,echo,wait}}]}
end},
{ok,STM} =
gen_statem:start_link(
- ?MODULE, {map_statem,Machine,[state_enter]}, []),
-
- [{enter,start,start,1}] = flush(),
- {echo,start,2} = gen_statem:call(STM, echo),
- [{3,{enter,start}},{4,{enter,start}},{enter,wait,start,5}] = flush(),
- {wait,[6|_]} = sys:get_state(STM),
- {repeat,wait,6} = gen_statem:call(STM, repeat),
- [{enter,wait,wait,6}] = flush(),
- {echo,wait,7} = gen_statem:call(STM, echo),
- [{enter,start,wait,8},{internal,start,wait,9}] = flush(),
- {repeat,start,10} = gen_statem:call(STM, repeat),
- [{enter,start,start,11}] = flush(),
- {stop,12} = gen_statem:call(STM, {stop,bye}),
+ ?MODULE, {map_statem,Machine,[state_enter]},
+ [{debug,[trace,{log,17}]}]),
+ ok = sys:log(STM, false),
+ ok = sys:log(STM, true),
+
+ [{1,enter,start,start}] = flush(),
+ {2,echo,start} = gen_statem:call(STM, echo),
+ [{3,{enter,start}},
+ {4,{enter,start}},
+ {5,enter,wait,start},
+ {6,{timeout,5}},
+ {7,{state_timeout,5}}] = flush(),
+ {wait,[8|_]} = sys:get_state(STM),
+ {8,repeat,wait} = gen_statem:call(STM, repeat),
+ [{8,enter,wait,wait},
+ {9,{timeout,8}},
+ {10,{state_timeout,8}}] = flush(),
+ {11,echo,wait} = gen_statem:call(STM, echo),
+ [{12,enter,start,wait},
+ {13,internal,start,wait}] = flush(),
+ {14,repeat,start} = gen_statem:call(STM, repeat),
+ [{15,enter,start,start}] = flush(),
+
+ {ok,Log} = sys:log(STM, get),
+ io:format("sys:log ~p~n", [Log]),
+ ok = sys:log(STM, print),
+
+ {16,stop} = gen_statem:call(STM, {stop,bye}),
[{'EXIT',STM,bye}] = flush(),
{noproc,_} =
@@ -832,9 +907,14 @@ event_types(_Config) ->
%% Abusing the internal format of From...
#{init =>
fun () ->
- {ok, start, undefined}
+ {ok, start1, undefined,
+ [{next_event,internal,0}]}
end,
- start =>
+ start1 =>
+ fun (internal, 0, undefined) ->
+ {next_state, start2, undefined}
+ end,
+ start2 =>
fun ({call,_} = Call, Req, undefined) ->
{next_state, state1, undefined,
[{next_event,internal,1},
@@ -1404,7 +1484,8 @@ enter_loop(_Config) ->
%% Locally registered process + {local,Name}
{ok,Pid1a} =
- proc_lib:start_link(?MODULE, enter_loop, [local,local]),
+ proc_lib:start_link(
+ ?MODULE, enter_loop, [local,local,[{debug,[{log,7}]}]]),
yes = gen_statem:call(Pid1a, 'alive?'),
stopped = gen_statem:call(Pid1a, stop),
receive
@@ -1416,7 +1497,8 @@ enter_loop(_Config) ->
%% Unregistered process + {local,Name}
{ok,Pid1b} =
- proc_lib:start_link(?MODULE, enter_loop, [anon,local]),
+ proc_lib:start_link(
+ ?MODULE, enter_loop, [anon,local,[{debug,[log]}]]),
receive
{'EXIT',Pid1b,process_not_registered} ->
ok
@@ -1525,6 +1607,9 @@ enter_loop(_Config) ->
ok = verify_empty_msgq().
enter_loop(Reg1, Reg2) ->
+ enter_loop(Reg1, Reg2, []).
+%%
+enter_loop(Reg1, Reg2, Opts) ->
process_flag(trap_exit, true),
case Reg1 of
local -> register(armitage, self());
@@ -1536,15 +1621,15 @@ enter_loop(Reg1, Reg2) ->
case Reg2 of
local ->
gen_statem:enter_loop(
- ?MODULE, [], state0, [], {local,armitage});
+ ?MODULE, Opts, state0, [], {local,armitage});
global ->
gen_statem:enter_loop(
- ?MODULE, [], state0, [], {global,armitage});
+ ?MODULE, Opts, state0, [], {global,armitage});
via ->
gen_statem:enter_loop(
- ?MODULE, [], state0, [], {via, dummy_via, armitage});
+ ?MODULE, Opts, state0, [], {via, dummy_via, armitage});
anon ->
- gen_statem:enter_loop(?MODULE, [], state0, [])
+ gen_statem:enter_loop(?MODULE, Opts, state0, [])
end.
undef_code_change(_Config) ->
@@ -1576,7 +1661,9 @@ undef_terminate2(_Config) ->
undef_in_terminate(_Config) ->
Data = {undef_in_terminate, {?MODULE, terminate}},
- {ok, Statem} = gen_statem:start(?MODULE, {data, Data}, []),
+ {ok, Statem} =
+ gen_statem:start(
+ ?MODULE, {data, Data}, [{debug,[log]}]),
try
gen_statem:stop(Statem),
ct:fail(should_crash)
@@ -1801,10 +1888,12 @@ idle(cast, {connect,Pid}, Data) ->
idle({call,From}, connect, Data) ->
gen_statem:reply(From, accept),
{next_state,wfor_conf,Data,infinity}; % NoOp timeout just to test API
-idle(cast, badreturn, _Data) ->
- badreturn;
idle({call,_From}, badreturn, _Data) ->
badreturn;
+idle({call,_From}, badaction, Data) ->
+ {keep_state, Data, [badaction]};
+idle({call,_From}, {badtimeout,_,_} = BadTimeout, Data) ->
+ {keep_state, Data, BadTimeout};
idle({call,From}, {delayed_answer,T}, Data) ->
receive
after T ->
@@ -2040,9 +2129,9 @@ handle_event(Type, Event, State, Data) ->
Result ->
wrap_result(Result)
catch
- throw:Result ->
+ throw:Result:Stacktrace ->
erlang:raise(
- throw, wrap_result(Result), erlang:get_stacktrace())
+ throw, wrap_result(Result), Stacktrace)
end.
unwrap_state([State]) ->
diff --git a/lib/stdlib/test/id_transform_SUITE.erl b/lib/stdlib/test/id_transform_SUITE.erl
index 186df41d3f..0addf09461 100644
--- a/lib/stdlib/test/id_transform_SUITE.erl
+++ b/lib/stdlib/test/id_transform_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/test/io_SUITE.erl b/lib/stdlib/test/io_SUITE.erl
index 16e3dba969..9b6d8d7401 100644
--- a/lib/stdlib/test/io_SUITE.erl
+++ b/lib/stdlib/test/io_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -31,9 +31,10 @@
otp_10836/1, io_lib_width_too_small/1,
io_with_huge_message_queue/1, format_string/1,
maps/1, coverage/1, otp_14178_unicode_atoms/1, otp_14175/1,
- otp_14285/1, limit_term/1]).
+ otp_14285/1, limit_term/1, otp_14983/1, otp_15103/1, otp_15076/1,
+ otp_15159/1, otp_15639/1, otp_15705/1]).
--export([pretty/2]).
+-export([pretty/2, trf/3]).
%%-define(debug, true).
@@ -63,7 +64,8 @@ all() ->
io_lib_print_binary_depth_one, otp_10302, otp_10755, otp_10836,
io_lib_width_too_small, io_with_huge_message_queue,
format_string, maps, coverage, otp_14178_unicode_atoms, otp_14175,
- otp_14285, limit_term].
+ otp_14285, limit_term, otp_14983, otp_15103, otp_15076, otp_15159,
+ otp_15639, otp_15705].
%% Error cases for output.
error_1(Config) when is_list(Config) ->
@@ -1750,7 +1752,7 @@ printable_range(Suite) when is_list(Suite) ->
PrettyOptions = [{column,1},
{line_length,109},
{depth,30},
- {max_chars,60},
+ {line_max_chars,60},
{record_print_fun,
fun(_,_) -> no end},
{encoding,unicode}],
@@ -1808,7 +1810,7 @@ rpc_call_max(Node, M, F, Args) ->
%% Make sure that a bad specification for a printable range is rejected.
bad_printable_range(Config) when is_list(Config) ->
- Cmd = lists:concat([lib:progname()," +pcunnnnnicode -run erlang halt"]),
+ Cmd = ct:get_progname() ++ " +pcunnnnnicode -run erlang halt",
P = open_port({spawn, Cmd}, [stderr_to_stdout, {line, 200}]),
ok = receive
{P, {data, {eol , "bad range of printable characters" ++ _}}} ->
@@ -1886,7 +1888,7 @@ otp_10302(Suite) when is_list(Suite) ->
pretty(Term, Depth) when is_integer(Depth) ->
Opts = [{column, 1}, {line_length, 20},
- {depth, Depth}, {max_chars, 60},
+ {depth, Depth}, {line_max_chars, 60},
{record_print_fun, fun rfd/2},
{encoding, unicode}],
pretty(Term, Opts);
@@ -1905,29 +1907,61 @@ otp_10836(Suite) when is_list(Suite) ->
%% OTP-10755. The 'l' modifier
otp_10755(Suite) when is_list(Suite) ->
+ %% printing plain ascii characters
S = "string",
"\"string\"" = fmt("~p", [S]),
"[115,116,114,105,110,103]" = fmt("~lp", [S]),
"\"string\"" = fmt("~P", [S, 2]),
"[115|...]" = fmt("~lP", [S, 2]),
- {'EXIT',{badarg,_}} = (catch fmt("~ltp", [S])),
- {'EXIT',{badarg,_}} = (catch fmt("~tlp", [S])),
- {'EXIT',{badarg,_}} = (catch fmt("~ltP", [S])),
- {'EXIT',{badarg,_}} = (catch fmt("~tlP", [S])),
+ %% printing latin1 chars, with and without modifiers
+ T = {[255],list_to_atom([255]),[a,b,c]},
+ "{\"ÿ\",ÿ,[a,b,c]}" = fmt("~p", [T]),
+ "{\"ÿ\",ÿ,[a,b,c]}" = fmt("~tp", [T]),
+ "{[255],ÿ,[a,b,c]}" = fmt("~lp", [T]),
+ "{[255],ÿ,[a,b,c]}" = fmt("~ltp", [T]),
+ "{[255],ÿ,[a,b,c]}" = fmt("~tlp", [T]),
+ "{\"ÿ\",ÿ,...}" = fmt("~P", [T,3]),
+ "{\"ÿ\",ÿ,...}" = fmt("~tP", [T,3]),
+ "{[255],ÿ,...}" = fmt("~lP", [T,3]),
+ "{[255],ÿ,...}" = fmt("~ltP", [T,3]),
+ "{[255],ÿ,...}" = fmt("~tlP", [T,3]),
+ %% printing unicode chars, with and without modifiers
+ U = {[666],list_to_atom([666]),[a,b,c]},
+ "{[666],'\\x{29A}',[a,b,c]}" = fmt("~p", [U]),
+ case io:printable_range() of
+ unicode ->
+ "{\"ʚ\",'ʚ',[a,b,c]}" = fmt("~tp", [U]),
+ "{\"ʚ\",'ʚ',...}" = fmt("~tP", [U,3]);
+ latin1 ->
+ "{[666],'ʚ',[a,b,c]}" = fmt("~tp", [U]),
+ "{[666],'ʚ',...}" = fmt("~tP", [U,3])
+ end,
+ "{[666],'\\x{29A}',[a,b,c]}" = fmt("~lp", [U]),
+ "{[666],'ʚ',[a,b,c]}" = fmt("~ltp", [U]),
+ "{[666],'ʚ',[a,b,c]}" = fmt("~tlp", [U]),
+ "{[666],'\\x{29A}',...}" = fmt("~P", [U,3]),
+ "{[666],'\\x{29A}',...}" = fmt("~lP", [U,3]),
+ "{[666],'ʚ',...}" = fmt("~ltP", [U,3]),
+ "{[666],'ʚ',...}" = fmt("~tlP", [U,3]),
+ %% the compiler should catch uses of ~l with other than pP
Text =
"-module(l_mod).\n"
"-export([t/0]).\n"
"t() ->\n"
" S = \"string\",\n"
- " io:format(\"~ltp\", [S]),\n"
- " io:format(\"~tlp\", [S]),\n"
- " io:format(\"~ltP\", [S, 1]),\n"
- " io:format(\"~tlP\", [S, 1]).\n",
+ " io:format(\"~lw\", [S]),\n"
+ " io:format(\"~lW\", [S, 1]),\n"
+ " io:format(\"~ltw\", [S]),\n"
+ " io:format(\"~tlw\", [S]),\n"
+ " io:format(\"~ltW\", [S, 1]),\n"
+ " io:format(\"~tlW\", [S, 1]).\n",
{ok,l_mod,[{_File,Ws}]} = compile_file("l_mod.erl", Text, Suite),
- ["format string invalid (invalid control ~lt)",
- "format string invalid (invalid control ~tl)",
- "format string invalid (invalid control ~lt)",
- "format string invalid (invalid control ~tl)"] =
+ ["format string invalid (invalid control ~lw)",
+ "format string invalid (invalid control ~lW)",
+ "format string invalid (invalid control ~ltw)",
+ "format string invalid (invalid control ~ltw)",
+ "format string invalid (invalid control ~ltW)",
+ "format string invalid (invalid control ~ltW)"] =
[lists:flatten(M:format_error(E)) || {_L,M,E} <- Ws],
ok.
@@ -2005,6 +2039,7 @@ writes(N, F1) ->
format_string(_Config) ->
%% All but padding is tested by fmt/2.
+ "xxxxxxxsss" = fmt("~10..xs", ["sss"]),
"xxxxxxsssx" = fmt("~10.4.xs", ["sss"]),
"xxxxxxsssx" = fmt("~10.4.*s", [$x, "sss"]),
ok.
@@ -2020,19 +2055,19 @@ maps(_Config) ->
%% in a map with more than one element.
"#{}" = fmt("~w", [#{}]),
- "#{a=>b}" = fmt("~w", [#{a=>b}]),
- re_fmt(<<"#\\{(a=>b|c=>d),[.][.][.]=>[.][.][.]\\}">>,
- "~W", [#{a=>b,c=>d},2]),
- re_fmt(<<"#\\{(a=>b|c=>d|e=>f),[.][.][.]=>[.][.][.],[.][.][.]\\}">>,
- "~W", [#{a=>b,c=>d,e=>f},2]),
+ "#{a => b}" = fmt("~w", [#{a=>b}]),
+ re_fmt(<<"#\\{(a => b),[.][.][.]\\}">>,
+ "~W", [#{a => b,c => d},2]),
+ re_fmt(<<"#\\{(a => b),[.][.][.]\\}">>,
+ "~W", [#{a => b,c => d,e => f},2]),
"#{}" = fmt("~p", [#{}]),
- "#{a => b}" = fmt("~p", [#{a=>b}]),
- "#{...}" = fmt("~P", [#{a=>b},1]),
+ "#{a => b}" = fmt("~p", [#{a => b}]),
+ "#{...}" = fmt("~P", [#{a => b},1]),
re_fmt(<<"#\\{(a => b|c => d),[.][.][.]\\}">>,
- "~P", [#{a=>b,c=>d},2]),
+ "~P", [#{a => b,c => d},2]),
re_fmt(<<"#\\{(a => b|c => d|e => f),[.][.][.]\\}">>,
- "~P", [#{a=>b,c=>d,e=>f},2]),
+ "~P", [#{a => b,c => d,e => f},2]),
List = [{I,I*I} || I <- lists:seq(1, 20)],
Map = maps:from_list(List),
@@ -2140,8 +2175,8 @@ otp_14175(_Config) ->
"#{}" = p(#{}, 1),
"#{...}" = p(#{a => 1}, 1),
"#{#{} => a}" = p(#{#{} => a}, 2),
- "#{a => 1,...}" = p(#{a => 1, b => 2}, 2),
- "#{a => 1,b => 2}" = p(#{a => 1, b => 2}, -1),
+ mt("#{a => 1,...}", p(#{a => 1, b => 2}, 2)),
+ mt("#{a => 1,b => 2}", p(#{a => 1, b => 2}, -1)),
M = #{kaaaaaaaaaaaaaaaaaaa => v1,kbbbbbbbbbbbbbbbbbbb => v2,
kccccccccccccccccccc => v3,kddddddddddddddddddd => v4,
@@ -2384,19 +2419,36 @@ limit_term(_Config) ->
{_, 2} = limt({a,b,c,[d,e]}, 2),
{_, 2} = limt({a,b,c,[d,e]}, 3),
{_, 2} = limt({a,b,c,[d,e]}, 4),
+ T0 = [1|{a,b,c}],
+ {_, 2} = limt(T0, 2),
+ {_, 2} = limt(T0, 3),
+ {_, 2} = limt(T0, 4),
{_, 1} = limt(<<"foo">>, 18),
+ {_, 2} = limt({"",[1,2]}, 3),
+ {_, 2} = limt({"",{1,2}}, 3),
+ true = limt_pp({"123456789012345678901234567890",{1,2}}, 3),
ok = blimt(<<"123456789012345678901234567890">>),
+ true = limt_pp(<<"123456789012345678901234567890">>, 3),
+ {_, 2} = limt({<<"kljlkjsl">>,[1,2,3,4]}, 4),
{_, 1} = limt(<<7:3>>, 2),
{_, 1} = limt(<<7:21>>, 2),
{_, 1} = limt([], 2),
{_, 1} = limt({}, 2),
+ {_, 1} = limt({"", ""}, 4),
{_, 1} = limt(#{}, 2),
- {_, 1} = limt(#{[] => {}}, 2),
+ {_, 2} = limt(#{[] => {}}, 1),
+ {_, 2} = limt(#{[] => {}}, 2),
{_, 1} = limt(#{[] => {}}, 3),
T = #{[] => {},[a] => [b]},
- {_, 1} = limt(T, 2),
- {_, 1} = limt(T, 3),
+ {_, 1} = limt(T, 0),
+ {_, 2} = limt(T, 1),
+ {_, 2} = limt(T, 2),
+ {_, 2} = limt(T, 3),
{_, 1} = limt(T, 4),
+ T2 = #{[] => {},{} => []},
+ {_, 2} = limt(T2, 1),
+ {_, 2} = limt(T2, 2),
+ {_, 1} = limt(T2, 3),
ok.
blimt(Binary) ->
@@ -2430,3 +2482,229 @@ limt(Term, Depth) when is_integer(Depth) ->
form(Term, Depth) ->
lists:flatten(io_lib:format("~W", [Term, Depth])).
+
+limt_pp(Term, Depth) when is_integer(Depth) ->
+ T1 = io_lib:limit_term(Term, Depth),
+ S = pp(Term, Depth),
+ S1 = pp(T1, Depth),
+ S1 =:= S.
+
+pp(Term, Depth) ->
+ lists:flatten(io_lib:format("~P", [Term, Depth])).
+
+otp_14983(_Config) ->
+ trunc_depth(-1, fun trp/3),
+ trunc_depth(10, fun trp/3),
+ trunc_depth(-1, fun trw/3),
+ trunc_depth(10, fun trw/3),
+ trunc_depth_p(-1),
+ trunc_depth_p(10),
+ trunc_string(),
+ ok.
+
+trunc_string() ->
+ "str " = trf("str ", [], 10),
+ "str str" = trf("str ~s", ["str"], 6),
+ "str ..." = trf("str ~s", ["str1"], 6),
+ "str str" = trf("str ~s", ["str"], 7),
+ "str str" = trf("str ~8s", ["str"], 6),
+ "str ..." = trf("str ~8s", ["str1"], 6),
+ Pa = filename:dirname(code:which(?MODULE)),
+ {ok, UNode} = test_server:start_node(printable_range_unicode, slave,
+ [{args, " +pc unicode -pa " ++ Pa}]),
+ U = "кирилли́ческий атом",
+ UFun = fun(Format, Args, CharsLimit) ->
+ rpc:call(UNode,
+ ?MODULE, trf, [Format, Args, CharsLimit])
+ end,
+ "str кир" = UFun("str ~3ts", [U], 7),
+ "str ..." = UFun("str ~3ts", [U], 6),
+ "str ..." = UFun("str ~30ts", [U], 6),
+ "str кир..." = UFun("str ~30ts", [U], 10),
+ "str кирилл..." = UFun("str ~30ts", [U], 13),
+ "str кирилли́..." = UFun("str ~30ts", [U], 14),
+ "str кирилли́ч..." = UFun("str ~30ts", [U], 15),
+ "\"кирилли́ческ\"..." = UFun("~tp", [U], 13),
+ BU = <<"кирилли́ческий атом"/utf8>>,
+ "<<\"кирилли́\"/utf8...>>" = UFun("~tp", [BU], 20),
+ "<<\"кирилли́\"/utf8...>>" = UFun("~tp", [BU], 21),
+ "<<\"кирилли́ческ\"/utf8...>>" = UFun("~tp", [BU], 22),
+ test_server:stop_node(UNode).
+
+trunc_depth(D, Fun) ->
+ "..." = Fun("", D, 0),
+ "[]" = Fun("", D, 1),
+
+ "#{}" = Fun(#{}, D, 1),
+ "#{a => 1}" = Fun(#{a => 1}, D, 7),
+ "#{...}" = Fun(#{a => 1}, D, 5),
+ "#{a => 1}" = Fun(#{a => 1}, D, 6),
+ A = lists:seq(1, 1000),
+ M = #{A => A, {A,A} => {A,A}},
+ "#{...}" = Fun(M, D, 6),
+ "#{{...} => {...},...}" = Fun(M, D, 7),
+ "#{{[...],...} => {[...],...},...}" = Fun(M, D, 22),
+ "#{{[...],...} => {[...],...},[...] => [...]}" = Fun(M, D, 31),
+ "#{{[...],...} => {[...],...},[...] => [...]}" = Fun(M, D, 33),
+ "#{{[1|...],[...]} => {[1|...],[...]},[1,2|...] => [...]}" =
+ Fun(M, D, 50),
+
+ "..." = Fun({c, 1, 2}, D, 0),
+ "{...}" = Fun({c, 1, 2}, D, 1),
+
+ "..." = Fun({}, D, 0),
+ "{}" = Fun({}, D, 1),
+ T = {A, A, A},
+ "{...}" = Fun(T, D, 5),
+ "{[...],...}" = Fun(T, D, 6),
+ "{[1|...],[...],...}" = Fun(T, D, 12),
+ "{[1,2|...],[1|...],...}" = Fun(T, D, 20),
+ "{[1,2|...],[1|...],[...]}" = Fun(T, D, 21),
+ "{[1,2,3|...],[1,2|...],[1|...]}" = Fun(T, D, 28),
+
+ "{[1],[1,2|...]}" = Fun({[1],[1,2,3,4]}, D, 14).
+
+trunc_depth_p(D) ->
+ UOpts = [{record_print_fun, fun rfd/2},
+ {encoding, unicode}],
+ LOpts = [{record_print_fun, fun rfd/2},
+ {encoding, latin1}],
+ trunc_depth_p(D, UOpts),
+ trunc_depth_p(D, LOpts).
+
+trunc_depth_p(D, Opts) ->
+ "[...]" = trp("abcdefg", D, 4, Opts),
+ "\"abc\"..." = trp("abcdefg", D, 5, Opts),
+ "\"abcdef\"..." = trp("abcdefg", D, 8, Opts),
+ "\"abcdefg\"" = trp("abcdefg", D, 9, Opts),
+ "\"abcdefghijkl\"" = trp("abcdefghijkl", D, -1, Opts),
+ AZ = lists:seq($A, $Z),
+ AZb = list_to_binary(AZ),
+ AZbS = "<<\"" ++ AZ ++ "\">>",
+ AZbS = trp(AZb, D, -1),
+ "<<\"ABCDEFGH\"...>>" = trp(AZb, D, 17, Opts), % 4 chars even if D = -1...
+ "<<\"ABCDEFGHIJKL\"...>>" = trp(AZb, D, 18, Opts),
+ B1 = <<"abcdef",0:8>>,
+ "<<\"ab\"...>>" = trp(B1, D, 8, Opts),
+ "<<\"abcdef\"...>>" = trp(B1, D, 14, Opts),
+ "<<97,98,99,100,...>>" = trp(B1, D, 16, Opts),
+ "<<97,98,99,100,101,102,0>>" = trp(B1, D, -1, Opts),
+ B2 = <<AZb/binary,0:8>>,
+ "<<\"AB\"...>>" = trp(B2, D, 8, Opts),
+ "<<\"ABCDEFGH\"...>>" = trp(B2, D, 14, Opts),
+ "<<65,66,67,68,69,70,71,72,0>>" = trp(<<"ABCDEFGH",0:8>>, D, -1, Opts),
+ "<<97,0,107,108,...>>" = trp(<<"a",0:8,"kllkjlksdjfsj">>, D, 20, Opts),
+
+ A = lists:seq(1, 1000),
+ "#c{...}" = trp({c, 1, 2}, D, 6),
+ "#c{...}" = trp({c, 1, 2}, D, 7),
+ "#c{f1 = [...],...}" = trp({c, A, A}, D, 18),
+ "#c{f1 = [1|...],f2 = [...]}" = trp({c, A, A}, D, 19),
+ "#c{f1 = [1,2|...],f2 = [1|...]}" = trp({c, A, A}, D, 31),
+ "#c{f1 = [1,2,3|...],f2 = [1,2|...]}" = trp({c, A, A}, D, 32).
+
+trp(Term, D, T) ->
+ trp(Term, D, T, [{record_print_fun, fun rfd/2}]).
+
+trp(Term, D, T, Opts) ->
+ R = io_lib_pretty:print(Term, [{depth, D},
+ {chars_limit, T}|Opts]),
+ lists:flatten(io_lib:format("~s", [R])).
+
+trw(Term, D, T) ->
+ lists:flatten(io_lib:format("~W", [Term, D], [{chars_limit, T}])).
+
+trf(Format, Args, T) ->
+ trf(Format, Args, T, [{record_print_fun, fun rfd/2}]).
+
+trf(Format, Args, T, Opts) ->
+ lists:flatten(io_lib:format(Format, Args, [{chars_limit, T}|Opts])).
+
+otp_15103(_Config) ->
+ T = lists:duplicate(5, {a,b,c}),
+
+ S1 = io_lib:format("~0p", [T]),
+ "[{a,b,c},{a,b,c},{a,b,c},{a,b,c},{a,b,c}]" = lists:flatten(S1),
+ S2 = io_lib:format("~-0p", [T]),
+ "[{a,b,c},{a,b,c},{a,b,c},{a,b,c},{a,b,c}]" = lists:flatten(S2),
+ S3 = io_lib:format("~1p", [T]),
+ "[{a,\n b,\n c},\n {a,\n b,\n c},\n {a,\n b,\n c},\n {a,\n b,\n"
+ " c},\n {a,\n b,\n c}]" = lists:flatten(S3),
+
+ S4 = io_lib:format("~0P", [T, 5]),
+ "[{a,b,c},{a,b,...},{a,...},{...}|...]" = lists:flatten(S4),
+ S5 = io_lib:format("~1P", [T, 5]),
+ "[{a,\n b,\n c},\n {a,\n b,...},\n {a,...},\n {...}|...]" =
+ lists:flatten(S5),
+ ok.
+
+otp_15159(_Config) ->
+ "[atom]" =
+ lists:flatten(io_lib:format("~p", [[atom]], [{chars_limit,5}])),
+ ok.
+
+otp_15076(_Config) ->
+ {'EXIT', {badarg, _}} = (catch io_lib:format("~c", [a])),
+ L = io_lib:scan_format("~c", [a]),
+ {"~c", [a]} = io_lib:unscan_format(L),
+ {'EXIT', {badarg, _}} = (catch io_lib:build_text(L)),
+ {'EXIT', {badarg, _}} = (catch io_lib:build_text(L, [])),
+ ok.
+
+otp_15639(_Config) ->
+ L = lists:duplicate(10, "a"),
+ LOpts = [{encoding, latin1}, {chars_limit, 10}],
+ UOpts = [{encoding, unicode}, {chars_limit, 10}],
+ "[[...]|...]" = pretty(L, LOpts),
+ "[[...]|...]" = pretty(L, UOpts),
+ "[\"a\",[...]|...]" =
+ pretty(L, [{chars_limit, 12}, {encoding, latin1}]),
+ "[\"a\",[...]|...]" =
+ pretty(L, [{chars_limit, 12}, {encoding, unicode}]),
+
+ %% Latin-1
+ "\"12345678\"" = pretty("12345678", LOpts),
+ "\"12345678\"..." = pretty("123456789", LOpts),
+ "\"\\r\\n123456\"..." = pretty("\r\n1234567", LOpts),
+ "\"\\r1234567\"..." = pretty("\r12345678", LOpts),
+ "\"\\r\\n123456\"..." = pretty("\r\n12345678", LOpts),
+ "\"12345678\"..." = pretty("12345678"++[x], LOpts),
+ "[49,50|...]" = pretty("1234567"++[x], LOpts),
+ "[49,x]" = pretty("1"++[x], LOpts),
+ "[[...]|...]" = pretty(["1","2","3","4","5","6","7","8"], LOpts),
+ %% Unicode
+ "\"12345678\"" = pretty("12345678", UOpts),
+ "\"12345678\"..." = pretty("123456789", UOpts),
+ "\"\\r\\n1234567\"" = pretty("\r\n1234567", UOpts),
+ "\"\\r1234567\"..." = pretty("\r12345678", UOpts),
+ "\"\\r\\n1234567\"..." = pretty("\r\n12345678", UOpts),
+ "[49,50|...]" = pretty("12345678"++[x], UOpts),
+ "\"12345678\"..." = pretty("123456789"++[x], UOpts),
+ "[[...]|...]" = pretty(["1","2","3","4","5","6","7","8"], UOpts),
+ ok.
+
+otp_15705(_Config) ->
+ L = [<<"an">>,["at"],[["om"]]],
+ "..." = trf("~s", [L], 0),
+ "..." = trf("~s", [L], 1),
+ "..." = trf("~s", [L], 2),
+ "..." = trf("~s", [L], 3),
+ "a..." = trf("~s", [L], 4),
+ "an..." = trf("~s", [L], 5),
+ "anatom" = trf("~s", [L], 6),
+ L2 = ["a",[<<"na">>],[["tom"]]],
+ "..." = trf("~s", [L2], 3),
+ "a..." = trf("~s", [L2], 4),
+ "an..." = trf("~s", [L2], 5),
+ "anatom" = trf("~s", [L2], 6),
+
+ A = [[<<"äpple"/utf8>>, "plus", <<"äpple">>]],
+ "äp..." = trf("~ts", [A], 5),
+ "äppleplusäpple" = trf("~ts", [A], 14),
+ U = [["ки"],"рилл","и́ческий атом"],
+ "ки..." = trf("~ts", [U], 5),
+ "кирилли́ческий..." = trf("~ts", [U], 16),
+ "кирилли́ческий атом" = trf("~ts", [U], 20),
+
+ "|кирилли́чес|" = trf("|~10ts|", [U], -1),
+ ok.
diff --git a/lib/stdlib/test/lists_SUITE.erl b/lib/stdlib/test/lists_SUITE.erl
index 7c99244b36..5dab6f6697 100644
--- a/lib/stdlib/test/lists_SUITE.erl
+++ b/lib/stdlib/test/lists_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -57,7 +57,7 @@
filter_partition/1,
join/1,
otp_5939/1, otp_6023/1, otp_6606/1, otp_7230/1,
- suffix/1, subtract/1, droplast/1, hof/1]).
+ suffix/1, subtract/1, droplast/1, search/1, hof/1]).
%% Sort randomized lists until stopped.
%%
@@ -121,7 +121,7 @@ groups() ->
{zip, [parallel], [zip_unzip, zip_unzip3, zipwith, zipwith3]},
{misc, [parallel], [reverse, member, dropwhile, takewhile,
filter_partition, suffix, subtract, join,
- hof, droplast]}
+ hof, droplast, search]}
].
init_per_suite(Config) ->
@@ -158,6 +158,20 @@ append_2(Config) when is_list(Config) ->
"abcdef"=lists:append("abc", "def"),
[hej, du]=lists:append([hej], [du]),
[10, [elem]]=lists:append([10], [[elem]]),
+
+ %% Trapping, both crashing and otherwise.
+ [append_trapping_1(N) || N <- lists:seq(0, 20)],
+
+ ok.
+
+append_trapping_1(N) ->
+ List = lists:duplicate(N + (1 bsl N), gurka),
+ ImproperList = List ++ crash,
+
+ {'EXIT',_} = (catch (ImproperList ++ [])),
+
+ [3, 2, 1 | List] = lists:reverse(List ++ [1, 2, 3]),
+
ok.
%% Tests the lists:reverse() implementation. The function is
@@ -1679,7 +1693,7 @@ make_fun() ->
receive {Pid, Fun} -> Fun end.
make_fun(Pid) ->
- Pid ! {self(), fun make_fun/1}.
+ Pid ! {self(), fun (X) -> {X, Pid} end}.
fun_pid(Fun) ->
erlang:fun_info(Fun, pid).
@@ -2597,6 +2611,20 @@ subtract(Config) when is_list(Config) ->
{'EXIT',_} = (catch sub([a|b], [])),
{'EXIT',_} = (catch sub([a|b], [a])),
+ %% Trapping, both crashing and otherwise.
+ [sub_trapping(N) || N <- lists:seq(0, 18)],
+
+ %% The current implementation chooses which algorithm to use based on
+ %% certain thresholds, and we need proper coverage for all corner cases.
+ [sub_thresholds(N) || N <- lists:seq(0, 32)],
+
+ %% Trapping, both crashing and otherwise.
+ [sub_trapping(N) || N <- lists:seq(0, 18)],
+
+ %% The current implementation chooses which algorithm to use based on
+ %% certain thresholds, and we need proper coverage for all corner cases.
+ [sub_thresholds(N) || N <- lists:seq(0, 32)],
+
ok.
sub_non_matching(A, B) ->
@@ -2606,6 +2634,41 @@ sub(A, B) ->
Res = A -- B,
Res = lists:subtract(A, B).
+sub_trapping(N) ->
+ List = lists:duplicate(N + (1 bsl N), gurka),
+ ImproperList = List ++ crash,
+
+ {'EXIT',_} = (catch sub_trapping_1(ImproperList, [])),
+ {'EXIT',_} = (catch sub_trapping_1(List, ImproperList)),
+
+ List = List -- lists:duplicate(N + (1 bsl N), gaffel),
+ ok = sub_trapping_1(List, []).
+
+sub_trapping_1([], _) -> ok;
+sub_trapping_1(L, R) -> sub_trapping_1(L -- R, [gurka | R]).
+
+sub_thresholds(N) ->
+ %% This needs to be long enough to cause trapping.
+ OtherLen = 1 bsl 18,
+ Other = lists:seq(0, OtherLen - 1),
+
+ Disjoint = lists:seq(-N, -1),
+ Subset = lists:seq(1, N),
+
+ %% LHS is disjoint from RHS, so all elements must be retained.
+ Disjoint = Disjoint -- Other,
+
+ %% LHS is covered by RHS, so all elements must be removed.
+ [] = Subset -- Other,
+
+ %% RHS is disjoint from LHS, so all elements must be retained.
+ Other = Other -- Disjoint,
+
+ %% RHS is covered by LHS, so N elements must be removed.
+ N = OtherLen - length(Other -- Subset),
+
+ ok.
+
%% Test lists:droplast/1
droplast(Config) when is_list(Config) ->
[] = lists:droplast([x]),
@@ -2615,6 +2678,20 @@ droplast(Config) when is_list(Config) ->
ok.
+%% Test lists:search/2
+search(Config) when is_list(Config) ->
+ F = fun(I) -> I rem 2 =:= 0 end,
+ F2 = fun(A, B) -> A > B end,
+
+ {value, 2} = lists:search(F, [1,2,3,4]),
+ false = lists:search(F, [1,3,5,7]),
+ false = lists:search(F, []),
+
+ %% Error cases.
+ {'EXIT',{function_clause,_}} = (catch lists:search(badfun, [])),
+ {'EXIT',{function_clause,_}} = (catch lists:search(F2, [])),
+ ok.
+
%% Briefly test the common high-order functions to ensure they
%% are covered.
hof(Config) when is_list(Config) ->
diff --git a/lib/stdlib/test/maps_SUITE.erl b/lib/stdlib/test/maps_SUITE.erl
index 42e669a799..6f3cd8bf1b 100644
--- a/lib/stdlib/test/maps_SUITE.erl
+++ b/lib/stdlib/test/maps_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -30,6 +30,7 @@
-export([t_update_with_3/1, t_update_with_4/1,
t_get_3/1, t_filter_2/1,
t_fold_3/1,t_map_2/1,t_size_1/1,
+ t_iterator_1/1,
t_with_2/1,t_without_2/1]).
%%-define(badmap(V,F,Args), {'EXIT', {{badmap,V}, [{maps,F,Args,_}|_]}}).
@@ -47,6 +48,7 @@ all() ->
[t_update_with_3,t_update_with_4,
t_get_3,t_filter_2,
t_fold_3,t_map_2,t_size_1,
+ t_iterator_1,
t_with_2,t_without_2].
t_update_with_3(Config) when is_list(Config) ->
@@ -106,6 +108,8 @@ t_without_2(_Config) ->
%% error case
?badmap(a,without,[[a,b],a]) = (catch maps:without([a,b],id(a))),
?badmap(a,without,[{a,b},a]) = (catch maps:without({a,b},id(a))),
+ ?badmap({0,<<>>,97},without,[[],{0,<<>>,97}]) = (catch maps:without([], {0,<<>>,97})),
+ ?badmap({0,<<>>,97},without,[[false, -20, -8],{0,<<>>,97}]) = (catch maps:without([false, -20, -8], {0, <<>>, 97})),
?badarg(without,[a,#{}]) = (catch maps:without(a,#{})),
ok.
@@ -118,6 +122,8 @@ t_with_2(_Config) ->
%% error case
?badmap(a,with,[[a,b],a]) = (catch maps:with([a,b],id(a))),
?badmap(a,with,[{a,b},a]) = (catch maps:with({a,b},id(a))),
+ ?badmap({0,<<>>,97},with,[[],{0,<<>>,97}]) = (catch maps:with([], {0,<<>>,97})),
+ ?badmap({0,<<>>,97},with,[[false, -20, -8],{0,<<>>,97}]) = (catch maps:with([false, -20, -8], {0, <<>>, 97})),
?badarg(with,[a,#{}]) = (catch maps:with(a,#{})),
ok.
@@ -127,6 +133,8 @@ t_filter_2(Config) when is_list(Config) ->
Pred2 = fun(K,V) -> is_list(K) andalso (V rem 2) =:= 0 end,
#{a := 2,c := 4} = maps:filter(Pred1,M),
#{"b" := 2,"c" := 4} = maps:filter(Pred2,M),
+ #{a := 2,c := 4} = maps:filter(Pred1,maps:iterator(M)),
+ #{"b" := 2,"c" := 4} = maps:filter(Pred2,maps:iterator(M)),
%% error case
?badmap(a,filter,[_,a]) = (catch maps:filter(fun(_,_) -> ok end,id(a))),
?badarg(filter,[<<>>,#{}]) = (catch maps:filter(id(<<>>),#{})),
@@ -139,6 +147,8 @@ t_fold_3(Config) when is_list(Config) ->
Tot0 = lists:sum(Vs),
Tot1 = maps:fold(fun({k,_},V,A) -> A + V end, 0, M0),
true = Tot0 =:= Tot1,
+ Tot2 = maps:fold(fun({k,_},V,A) -> A + V end, 0, maps:iterator(M0)),
+ true = Tot0 =:= Tot2,
%% error case
?badmap(a,fold,[_,0,a]) = (catch maps:fold(fun(_,_,_) -> ok end,0,id(a))),
@@ -151,12 +161,48 @@ t_map_2(Config) when is_list(Config) ->
#{ {k,1} := 1, {k,200} := 200} = M0,
M1 = maps:map(fun({k,_},V) -> V + 42 end, M0),
#{ {k,1} := 43, {k,200} := 242} = M1,
+ M2 = maps:map(fun({k,_},V) -> V + 42 end, maps:iterator(M0)),
+ #{ {k,1} := 43, {k,200} := 242} = M2,
%% error case
?badmap(a,map,[_,a]) = (catch maps:map(fun(_,_) -> ok end, id(a))),
?badarg(map,[<<>>,#{}]) = (catch maps:map(id(<<>>),#{})),
ok.
+t_iterator_1(Config) when is_list(Config) ->
+
+ %% Small map test
+ M0 = #{ a => 1, b => 2 },
+ I0 = maps:iterator(M0),
+ {K1,V1,I1} = maps:next(I0),
+ {K2,V2,I2} = maps:next(I1),
+ none = maps:next(I2),
+
+ KVList = lists:sort([{K1,V1},{K2,V2}]),
+ KVList = lists:sort(maps:to_list(M0)),
+
+ %% Large map test
+
+ Vs2 = lists:seq(1,200),
+ M2 = maps:from_list([{{k,I},I}||I<-Vs2]),
+ KVList2 = lists:sort(iter_kv(maps:iterator(M2))),
+ KVList2 = lists:sort(maps:to_list(M2)),
+
+ %% Larger map test
+
+ Vs3 = lists:seq(1,10000),
+ M3 = maps:from_list([{{k,I},I}||I<-Vs3]),
+ KVList3 = lists:sort(iter_kv(maps:iterator(M3))),
+ KVList3 = lists:sort(maps:to_list(M3)),
+ ok.
+
+iter_kv(I) ->
+ case maps:next(I) of
+ none ->
+ [];
+ {K,V,NI} ->
+ [{K,V} | iter_kv(NI)]
+ end.
t_size_1(Config) when is_list(Config) ->
0 = maps:size(#{}),
diff --git a/lib/stdlib/test/proc_lib_SUITE.erl b/lib/stdlib/test/proc_lib_SUITE.erl
index 7686889360..127b1317e4 100644
--- a/lib/stdlib/test/proc_lib_SUITE.erl
+++ b/lib/stdlib/test/proc_lib_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -446,8 +446,8 @@ init_dont_hang(Config) when is_list(Config) ->
StartLinkRes = proc_lib:start(?MODULE, init_dont_hang_init, [self()], 1000),
StartLinkRes = proc_lib:start(?MODULE, init_dont_hang_init, [self()], 1000, []),
ok
- catch _:Error ->
- io:format("Error ~p /= ~p ~n",[erlang:get_stacktrace(), StartLinkRes]),
+ catch _:Error:Stacktrace ->
+ io:format("Error ~p /= ~p ~n",[Stacktrace, StartLinkRes]),
exit(Error)
end.
@@ -542,16 +542,18 @@ system_terminate(Reason,_Parent,_Deb,_State) ->
t_format(_Config) ->
- error_logger:tty(false),
+ {ok,#{level:=Level}} = logger:get_handler_config(default),
+ logger:set_handler_config(default,level,none),
+ error_logger:add_report_handler(?MODULE, self()),
try
t_format()
after
- error_logger:tty(true)
+ error_logger:delete_report_handler(?MODULE),
+ logger:set_handler_config(default,level,Level)
end,
ok.
t_format() ->
- error_logger:add_report_handler(?MODULE, self()),
Pid = proc_lib:spawn(fun '\x{aaa}t_format_looper'/0),
HugeData = gb_sets:from_list(lists:seq(1, 100)),
SomeData1 = list_to_atom([246]),
@@ -584,11 +586,12 @@ t_format() ->
ok.
t_format_arbitrary(_Config) ->
- error_logger:tty(false),
+ {ok,#{level:=Level}} = logger:get_handler_config(default),
+ logger:set_handler_config(default,level,none),
try
t_format_arbitrary()
after
- error_logger:tty(true)
+ logger:set_handler_config(default,level,Level)
end,
ok.
diff --git a/lib/stdlib/test/property_test/README b/lib/stdlib/test/property_test/README
new file mode 100644
index 0000000000..57602bf719
--- /dev/null
+++ b/lib/stdlib/test/property_test/README
@@ -0,0 +1,12 @@
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%% %%%
+%%% WARNING %%%
+%%% %%%
+%%% This is experimental code which may be changed or removed %%%
+%%% anytime without any warning. %%%
+%%% %%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+The test in this directory are written assuming that the user has a QuickCheck license. They are to be run manually. Some may be possible to be run with other tools, e.g. PropEr.
+
diff --git a/lib/stdlib/test/property_test/uri_string_recompose.erl b/lib/stdlib/test/property_test/uri_string_recompose.erl
new file mode 100644
index 0000000000..39fadf23c2
--- /dev/null
+++ b/lib/stdlib/test/property_test/uri_string_recompose.erl
@@ -0,0 +1,571 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(uri_string_recompose).
+
+-compile(export_all).
+
+-proptest(eqc).
+-proptest([triq,proper]).
+
+-ifndef(EQC).
+-ifndef(PROPER).
+-ifndef(TRIQ).
+-define(EQC,true).
+-endif.
+-endif.
+-endif.
+
+-ifdef(EQC).
+-include_lib("eqc/include/eqc.hrl").
+-define(MOD_eqc,eqc).
+
+-else.
+-ifdef(PROPER).
+-include_lib("proper/include/proper.hrl").
+-define(MOD_eqc,proper).
+
+-else.
+-ifdef(TRIQ).
+-define(MOD_eqc,triq).
+-include_lib("triq/include/triq.hrl").
+
+-endif.
+-endif.
+-endif.
+
+
+-define(STRING_REST(MatchStr, Rest), <<MatchStr/utf8, Rest/binary>>).
+
+-define(SCHEME, {scheme, scheme()}).
+-define(USER, {userinfo, unicode()}).
+-define(HOST, {host, host_map()}).
+-define(PORT, {port, port()}).
+-define(PATH_ABE, {path, path_abempty_map()}).
+-define(PATH_ABS, {path, path_absolute_map()}).
+-define(PATH_NOS, {path, path_noscheme_map()}).
+-define(PATH_ROO, {path, path_rootless_map()}).
+-define(PATH_EMP, {path, path_empty_map()}).
+-define(QUERY, {query, query_map()}).
+-define(FRAGMENT, {fragment, fragment_map()}).
+
+%% Non-unicode
+-define(USER_NU, {userinfo, non_unicode()}).
+-define(HOST_NU, {host, host_map_nu()}).
+-define(PATH_ABE_NU, {path, path_abempty_map_nu()}).
+-define(PATH_ABS_NU, {path, path_absolute_map_nu()}).
+-define(PATH_NOS_NU, {path, path_noscheme_map_nu()}).
+-define(PATH_ROO_NU, {path, path_rootless_map_nu()}).
+-define(QUERY_NU, {query, query_map_nu()}).
+-define(FRAGMENT_NU, {fragment, fragment_map_nu()}).
+
+%%%========================================================================
+%%% Properties
+%%%========================================================================
+
+prop_recompose() ->
+ ?FORALL(Map, map_no_unicode(),
+ Map =:= uri_string:parse(uri_string:recompose(Map))).
+
+prop_normalize() ->
+ ?FORALL(Map, map(),
+ uri_string:normalize(Map, [return_map]) =:=
+ uri_string:normalize(uri_string:parse(uri_string:recompose(Map)),
+ [return_map])).
+
+%% Stats
+prop_map_key_length_collect() ->
+ ?FORALL(List, map(),
+ collect(length(maps:keys(List)), true)).
+
+prop_map_collect() ->
+ ?FORALL(List, map(),
+ collect(lists:sort(maps:keys(List)), true)).
+
+prop_scheme_collect() ->
+ ?FORALL(List, scheme(),
+ collect(length(List), true)).
+
+
+%%%========================================================================
+%%% Generators
+%%%========================================================================
+
+map() ->
+ ?LET(Gen, comp_proplist(), proplist_to_map(Gen)).
+
+map_no_unicode() ->
+ ?LET(Gen, comp_proplist_nu(), proplist_to_map(Gen)).
+
+comp_proplist() ->
+ frequency([
+ {2, [?SCHEME,?PATH_ABS]},
+ {2, [?SCHEME,?PATH_ROO]},
+ {2, [?SCHEME,?PATH_EMP]},
+ {2, [?SCHEME,?HOST,?PATH_ABE]},
+ {2, [?SCHEME,?USER,?HOST,?PATH_ABE]},
+ {2, [?SCHEME,?HOST,?PORT,?PATH_ABE]},
+ {2, [?SCHEME,?USER,?HOST,?PORT,?PATH_ABE]},
+
+ {2, [?PATH_ABS]},
+ {2, [?PATH_NOS]},
+ {2, [?PATH_EMP]},
+ {2, [?HOST,?PATH_ABE]},
+ {2, [?USER,?HOST,?PATH_ABE]},
+ {2, [?HOST,?PORT,?PATH_ABE]},
+ {2, [?USER,?HOST,?PORT,?PATH_ABE]},
+
+
+ {2, [?SCHEME,?PATH_ABS,?QUERY]},
+ {2, [?SCHEME,?PATH_ROO,?QUERY]},
+ {2, [?SCHEME,?PATH_EMP,?QUERY]},
+ {2, [?SCHEME,?HOST,?PATH_ABE,?QUERY]},
+ {2, [?SCHEME,?USER,?HOST,?PATH_ABE,?QUERY]},
+ {2, [?SCHEME,?HOST,?PORT,?PATH_ABE,?QUERY]},
+ {2, [?SCHEME,?USER,?HOST,?PORT,?PATH_ABE,?QUERY]},
+
+ {2, [?PATH_ABS,?QUERY]},
+ {2, [?PATH_NOS,?QUERY]},
+ {2, [?PATH_EMP,?QUERY]},
+ {2, [?HOST,?PATH_ABE,?QUERY]},
+ {2, [?USER,?HOST,?PATH_ABE,?QUERY]},
+ {2, [?HOST,?PORT,?PATH_ABE,?QUERY]},
+ {2, [?USER,?HOST,?PORT,?PATH_ABE,?QUERY]},
+
+
+ {2, [?SCHEME,?PATH_ABS,?FRAGMENT]},
+ {2, [?SCHEME,?PATH_ROO,?FRAGMENT]},
+ {2, [?SCHEME,?PATH_EMP,?FRAGMENT]},
+ {2, [?SCHEME,?HOST,?PATH_ABE,?FRAGMENT]},
+ {2, [?SCHEME,?USER,?HOST,?PATH_ABE,?FRAGMENT]},
+ {2, [?SCHEME,?HOST,?PORT,?PATH_ABE,?FRAGMENT]},
+ {2, [?SCHEME,?USER,?HOST,?PORT,?PATH_ABE,?FRAGMENT]},
+
+ {2, [?PATH_ABS,?FRAGMENT]},
+ {2, [?PATH_NOS,?FRAGMENT]},
+ {2, [?PATH_EMP,?FRAGMENT]},
+ {2, [?HOST,?PATH_ABE,?FRAGMENT]},
+ {2, [?USER,?HOST,?PATH_ABE,?FRAGMENT]},
+ {2, [?HOST,?PORT,?PATH_ABE,?FRAGMENT]},
+ {2, [?USER,?HOST,?PORT,?PATH_ABE,?FRAGMENT]},
+
+
+ {2, [?SCHEME,?PATH_ABS,?QUERY,?FRAGMENT]},
+ {2, [?SCHEME,?PATH_ROO,?QUERY,?FRAGMENT]},
+ {2, [?SCHEME,?PATH_EMP,?QUERY,?FRAGMENT]},
+ {2, [?SCHEME,?HOST,?PATH_ABE,?QUERY,?FRAGMENT]},
+ {2, [?SCHEME,?USER,?HOST,?PATH_ABE,?QUERY,?FRAGMENT]},
+ {2, [?SCHEME,?HOST,?PORT,?PATH_ABE,?QUERY,?FRAGMENT]},
+ {2, [?SCHEME,?USER,?HOST,?PORT,?PATH_ABE,?QUERY,?FRAGMENT]},
+
+ {2, [?PATH_ABS,?QUERY,?FRAGMENT]},
+ {2, [?PATH_NOS,?QUERY,?FRAGMENT]},
+ {2, [?PATH_EMP,?QUERY,?FRAGMENT]},
+ {2, [?HOST,?PATH_ABE,?QUERY,?FRAGMENT]},
+ {2, [?USER,?HOST,?PATH_ABE,?QUERY,?FRAGMENT]},
+ {2, [?HOST,?PORT,?PATH_ABE,?QUERY,?FRAGMENT]},
+ {2, [?USER,?HOST,?PORT,?PATH_ABE,?QUERY,?FRAGMENT]}
+ ]).
+
+comp_proplist_nu() ->
+ frequency([
+ {2, [?SCHEME,?PATH_ABS_NU]},
+ {2, [?SCHEME,?PATH_ROO_NU]},
+ {2, [?SCHEME,?PATH_EMP]},
+ {2, [?SCHEME,?HOST_NU,?PATH_ABE_NU]},
+ {2, [?SCHEME,?USER_NU,?HOST_NU,?PATH_ABE_NU]},
+ {2, [?SCHEME,?HOST_NU,?PORT,?PATH_ABE_NU]},
+ {2, [?SCHEME,?USER_NU,?HOST_NU,?PORT,?PATH_ABE_NU]},
+
+ {2, [?PATH_ABS_NU]},
+ {2, [?PATH_NOS_NU]},
+ {2, [?PATH_EMP]},
+ {2, [?HOST_NU,?PATH_ABE_NU]},
+ {2, [?USER_NU,?HOST_NU,?PATH_ABE_NU]},
+ {2, [?HOST_NU,?PORT,?PATH_ABE_NU]},
+ {2, [?USER_NU,?HOST_NU,?PORT,?PATH_ABE_NU]},
+
+
+ {2, [?SCHEME,?PATH_ABS_NU,?QUERY_NU]},
+ {2, [?SCHEME,?PATH_ROO_NU,?QUERY_NU]},
+ {2, [?SCHEME,?PATH_EMP,?QUERY_NU]},
+ {2, [?SCHEME,?HOST_NU,?PATH_ABE_NU,?QUERY_NU]},
+ {2, [?SCHEME,?USER_NU,?HOST_NU,?PATH_ABE_NU,?QUERY_NU]},
+ {2, [?SCHEME,?HOST_NU,?PORT,?PATH_ABE_NU,?QUERY_NU]},
+ {2, [?SCHEME,?USER_NU,?HOST_NU,?PORT,?PATH_ABE_NU,?QUERY_NU]},
+
+ {2, [?PATH_ABS_NU,?QUERY_NU]},
+ {2, [?PATH_NOS_NU,?QUERY_NU]},
+ {2, [?PATH_EMP,?QUERY_NU]},
+ {2, [?HOST_NU,?PATH_ABE_NU,?QUERY_NU]},
+ {2, [?USER_NU,?HOST_NU,?PATH_ABE_NU,?QUERY_NU]},
+ {2, [?HOST_NU,?PORT,?PATH_ABE_NU,?QUERY_NU]},
+ {2, [?USER_NU,?HOST_NU,?PORT,?PATH_ABE_NU,?QUERY_NU]},
+
+
+ {2, [?SCHEME,?PATH_ABS_NU,?FRAGMENT_NU]},
+ {2, [?SCHEME,?PATH_ROO_NU,?FRAGMENT_NU]},
+ {2, [?SCHEME,?PATH_EMP,?FRAGMENT_NU]},
+ {2, [?SCHEME,?HOST_NU,?PATH_ABE_NU,?FRAGMENT_NU]},
+ {2, [?SCHEME,?USER_NU,?HOST_NU,?PATH_ABE_NU,?FRAGMENT_NU]},
+ {2, [?SCHEME,?HOST_NU,?PORT,?PATH_ABE_NU,?FRAGMENT_NU]},
+ {2, [?SCHEME,?USER_NU,?HOST_NU,?PORT,?PATH_ABE_NU,?FRAGMENT_NU]},
+
+ {2, [?PATH_ABS_NU,?FRAGMENT_NU]},
+ {2, [?PATH_NOS_NU,?FRAGMENT_NU]},
+ {2, [?PATH_EMP,?FRAGMENT_NU]},
+ {2, [?HOST_NU,?PATH_ABE_NU,?FRAGMENT_NU]},
+ {2, [?USER_NU,?HOST_NU,?PATH_ABE_NU,?FRAGMENT_NU]},
+ {2, [?HOST_NU,?PORT,?PATH_ABE_NU,?FRAGMENT_NU]},
+ {2, [?USER_NU,?HOST_NU,?PORT,?PATH_ABE_NU,?FRAGMENT_NU]},
+
+
+ {2, [?SCHEME,?PATH_ABS_NU,?QUERY_NU,?FRAGMENT_NU]},
+ {2, [?SCHEME,?PATH_ROO_NU,?QUERY_NU,?FRAGMENT_NU]},
+ {2, [?SCHEME,?PATH_EMP,?QUERY_NU,?FRAGMENT_NU]},
+ {2, [?SCHEME,?HOST_NU,?PATH_ABE_NU,?QUERY_NU,?FRAGMENT_NU]},
+ {2, [?SCHEME,?USER_NU,?HOST_NU,?PATH_ABE_NU,?QUERY_NU,?FRAGMENT_NU]},
+ {2, [?SCHEME,?HOST_NU,?PORT,?PATH_ABE_NU,?QUERY_NU,?FRAGMENT_NU]},
+ {2, [?SCHEME,?USER_NU,?HOST_NU,?PORT,?PATH_ABE_NU,?QUERY_NU,?FRAGMENT_NU]},
+
+ {2, [?PATH_ABS_NU,?QUERY_NU,?FRAGMENT_NU]},
+ {2, [?PATH_NOS_NU,?QUERY_NU,?FRAGMENT_NU]},
+ {2, [?PATH_EMP,?QUERY_NU,?FRAGMENT_NU]},
+ {2, [?HOST_NU,?PATH_ABE_NU,?QUERY_NU,?FRAGMENT_NU]},
+ {2, [?USER_NU,?HOST_NU,?PATH_ABE_NU,?QUERY_NU,?FRAGMENT_NU]},
+ {2, [?HOST_NU,?PORT,?PATH_ABE_NU,?QUERY_NU,?FRAGMENT_NU]},
+ {2, [?USER_NU,?HOST_NU,?PORT,?PATH_ABE_NU,?QUERY_NU,?FRAGMENT_NU]}
+ ]).
+
+
+%%-------------------------------------------------------------------------
+%% Path
+%%-------------------------------------------------------------------------
+path_abempty_map() ->
+ frequency([{90, path_abe_map()},
+ {10, path_empty_map()}]).
+
+path_abempty_map_nu() ->
+ frequency([{90, path_abe_map_nu()},
+ {10, path_empty_map()}]).
+
+
+path_abe_map() ->
+ ?SIZED(Length, path_abe_map(Length, [])).
+%%
+path_abe_map(0, Segments) ->
+ ?LET(Gen, Segments, lists:append(Gen));
+path_abe_map(N, Segments) ->
+ path_abe_map(N-1, [slash(),segment()|Segments]).
+
+path_abe_map_nu() ->
+ ?SIZED(Length, path_abe_map_nu(Length, [])).
+%%
+path_abe_map_nu(0, Segments) ->
+ ?LET(Gen, Segments, lists:append(Gen));
+path_abe_map_nu(N, Segments) ->
+ path_abe_map_nu(N-1, [slash(),segment_nu()|Segments]).
+
+
+path_absolute_map() ->
+ ?SIZED(Length, path_absolute_map(Length, [])).
+%%
+path_absolute_map(0, Segments) ->
+ ?LET(Gen, [slash(),segment_nz()|Segments], lists:append(Gen));
+path_absolute_map(N, Segments) ->
+ path_absolute_map(N-1, [slash(),segment()|Segments]).
+
+path_absolute_map_nu() ->
+ ?SIZED(Length, path_absolute_map_nu(Length, [])).
+%%
+path_absolute_map_nu(0, Segments) ->
+ ?LET(Gen, [slash(),segment_nz_nu()|Segments], lists:append(Gen));
+path_absolute_map_nu(N, Segments) ->
+ path_absolute_map_nu(N-1, [slash(),segment_nu()|Segments]).
+
+
+path_noscheme_map() ->
+ ?SIZED(Length, path_noscheme_map(Length, [])).
+%%
+path_noscheme_map(0, Segments) ->
+ ?LET(Gen, [segment_nz_nc()|Segments], lists:append(Gen));
+path_noscheme_map(N, Segments) ->
+ path_noscheme_map(N-1, [slash(),segment()|Segments]).
+
+path_noscheme_map_nu() ->
+ ?SIZED(Length, path_noscheme_map_nu(Length, [])).
+%%
+path_noscheme_map_nu(0, Segments) ->
+ ?LET(Gen, [segment_nz_nc_nu()|Segments], lists:append(Gen));
+path_noscheme_map_nu(N, Segments) ->
+ path_noscheme_map_nu(N-1, [slash(),segment_nu()|Segments]).
+
+
+path_rootless_map() ->
+ ?SIZED(Length, path_rootless_map(Length, [])).
+%%
+path_rootless_map(0, Segments) ->
+ ?LET(Gen, [segment_nz()|Segments], lists:append(Gen));
+path_rootless_map(N, Segments) ->
+ path_rootless_map(N-1, [slash(),segment()|Segments]).
+
+path_rootless_map_nu() ->
+ ?SIZED(Length, path_rootless_map_nu(Length, [])).
+%%
+path_rootless_map_nu(0, Segments) ->
+ ?LET(Gen, [segment_nz_nu()|Segments], lists:append(Gen));
+path_rootless_map_nu(N, Segments) ->
+ path_rootless_map_nu(N-1, [slash(),segment_nu()|Segments]).
+
+
+segment_nz() ->
+ non_empty(segment()).
+
+segment_nz_nu() ->
+ non_empty(segment_nu()).
+
+
+segment_nz_nc() ->
+ ?LET(Gen,
+ non_empty(list(frequency([{30, unreserved()},
+ {10, ptc_encoded_reserved()},
+ {10, sub_delims()},
+ {10, unicode_char()},
+ {5, oneof([$@])}
+ ]))),
+ lists:flatten(Gen)).
+
+segment_nz_nc_nu() ->
+ ?LET(Gen,
+ non_empty(list(frequency([{30, unreserved()},
+ {10, ptc_encoded_reserved()},
+ {10, sub_delims()},
+ {5, oneof([$@])}
+ ]))),
+ lists:flatten(Gen)).
+
+segment() ->
+ ?LET(Gen,
+ list(frequency([{30, unreserved()},
+ {10, ptc_encoded_reserved()},
+ {10, sub_delims()},
+ {10, unicode_char()},
+ {5, oneof([$:, $@])}
+ ])),
+ lists:flatten(Gen)).
+
+segment_nu() ->
+ ?LET(Gen,
+ list(frequency([{30, unreserved()},
+ {10, ptc_encoded_reserved()},
+ {10, sub_delims()},
+ {5, oneof([$:, $@])}
+ ])),
+ lists:flatten(Gen)).
+
+slash() ->
+ "/".
+
+path_empty_map() ->
+ "".
+
+
+%%-------------------------------------------------------------------------
+%% Host
+%%-------------------------------------------------------------------------
+host_map() ->
+ frequency([{30, reg_name()},
+ {30, ip_address()}
+ ]).
+
+host_map_nu() ->
+ frequency([{30, reg_name_nu()},
+ {30, ip_address()}
+ ]).
+
+reg_name() ->
+ ?LET(Gen,
+ list(frequency([{30, alpha()},
+ {10, sub_delims()},
+ {10, ptc_encoded_reserved()},
+ {10, unicode_char()}
+ ])),
+ lists:flatten(Gen)).
+
+reg_name_nu() ->
+ ?LET(Gen,
+ list(frequency([{30, alpha()},
+ {10, sub_delims()},
+ {10, ptc_encoded_reserved()}
+ ])),
+ lists:flatten(Gen)).
+
+
+ip_address() ->
+ oneof(["127.0.0.1", "::127.0.0.1",
+ "2001:0db8:0000:0000:0000:0000:1428:07ab",
+ "2001:0db8:0000:0000:0000::1428:07ab",
+ "2001:0db8:0:0:0:0:1428:07ab",
+ "2001:0db8:0::0:1428:07ab"]).
+
+%% Generating only reg-names
+host_uri() ->
+ ?LET(Gen,
+ non_empty(list(frequency([{30, unreserved()},
+ {10, sub_delims()},
+ {10, ptc_encoded_reserved()},
+ {10, pct_encoded()}
+ ]))),
+ lists:flatten(Gen)).
+
+%%-------------------------------------------------------------------------
+%% Port, Query, Fragment
+%%-------------------------------------------------------------------------
+port() ->
+ frequency([{10, undefined},
+ {10, range(1,65535)}
+ ]).
+
+query_map() ->
+ unicode().
+
+query_map_nu() ->
+ non_unicode().
+
+
+query_uri() ->
+ [$?| non_empty(list(frequency([{20, pchar()},
+ {5, oneof([$/, $?])} % punctuation
+ ])))].
+
+fragment_map() ->
+ unicode().
+
+fragment_map_nu() ->
+ non_unicode().
+
+
+fragment_uri() ->
+ [$?| non_empty(list(frequency([{20, pchar()},
+ {5, oneof([$/, $?])} % punctuation
+ ])))].
+
+
+%%-------------------------------------------------------------------------
+%% Scheme
+%%-------------------------------------------------------------------------
+scheme() ->
+ ?SIZED(Length, scheme_start(Length, [])).
+%%
+scheme_start(0, L) ->
+ ?LET(Gen, L, lists:reverse(Gen));
+scheme_start(N, L) ->
+ scheme(N-1,[alpha()|L]).
+
+scheme(0, L) ->
+ ?LET(Gen, L, lists:reverse(Gen));
+scheme(N, L) ->
+ scheme(N-1, [scheme_char()|L]).
+
+
+%%-------------------------------------------------------------------------
+%% Misc
+%%-------------------------------------------------------------------------
+unicode() ->
+ list(frequency([{20, alpha()}, % alpha
+ {10, digit()}, % digit
+ {10, unicode_char()} % unicode
+ ])).
+
+non_unicode() ->
+ list(frequency([{20, alpha()}, % alpha
+ {10, digit()} % digit
+ ])).
+
+scheme_char() ->
+ frequency([{20, alpha()}, % alpha
+ {20, digit()}, % digit
+ {5, oneof([$+, $-, $.])} % punctuation
+ ]).
+
+sub_delims() ->
+ oneof([$!, $$, $&, $', $(, $),
+ $*, $+, $,,$;, $=]).
+
+pchar() ->
+ frequency([{20, unreserved()},
+ {5, ptc_encoded_reserved()},
+ {5, pct_encoded()},
+ {5, sub_delims()},
+ {1, oneof([$:, $@])} % punctuation
+ ]).
+
+unreserved() ->
+ frequency([{20, alpha()},
+ {5, digit()},
+ {1, oneof([$-, $., $_, $~])} % punctuation
+ ]).
+
+unicode_char() ->
+ range(913, 1023).
+
+alpha() ->
+ frequency([{20, range($a, $z)}, % letters
+ {20, range($A, $Z)}]). % letters
+
+digit() ->
+ range($0, $9). % numbers
+
+pct_encoded() ->
+ oneof(["%C3%A4", "%C3%A5", "%C3%B6"]).
+
+%%-------------------------------------------------------------------------
+%% [RFC 3986, Chapter 2.2. Reserved Characters]
+%%
+%% reserved = gen-delims / sub-delims
+%%
+%% gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
+%% 3A 2F 3F 23 5B 5D 40
+%% sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
+%% 21 24 26 27 28 29
+%% / "*" / "+" / "," / ";" / "="
+%% 2A 2B 2C 3B 3D
+%%-------------------------------------------------------------------------
+ptc_encoded_reserved() ->
+ oneof(["%3A","%2F","%3F","%23","%5B","%5D","%40",
+ "%21","%24","%26","%27","%28","%29",
+ "%2A","%2B","%2C","%3B","3D"]).
+
+%%%========================================================================
+%%% Helpers
+%%%========================================================================
+proplist_to_map(L) ->
+ lists:foldl(fun({K,V},M) -> M#{K => V};
+ (_,M) -> M
+ end, #{}, L).
+
+map_scheme_host_to_lower(Map) ->
+ Fun = fun (scheme,V) ->
+ string:to_lower(V);
+ (host,V) ->
+ string:to_lower(V);
+ (_,V) ->
+ V
+ end,
+ maps:map(Fun, Map).
diff --git a/lib/stdlib/test/qlc_SUITE.erl b/lib/stdlib/test/qlc_SUITE.erl
index 949142ec77..8a43f15d2c 100644
--- a/lib/stdlib/test/qlc_SUITE.erl
+++ b/lib/stdlib/test/qlc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1695,28 +1695,7 @@ sort(Config) when is_list(Config) ->
[true || I <- lists:seq(1, 50000), not ets:insert(E, {I, I})],
H = qlc:q([{X,Y} || X <- [a,b], Y <- qlc:sort(ets:table(E))]),
100000 = length(qlc:e(H)),
- ets:delete(E)">>,
-
- begin
- TmpDir = ?privdir,
- [<<"TE = process_flag(trap_exit, true),
- E = ets:new(foo, []),
- [true || I <- lists:seq(1, 50000), not ets:insert(E, {I, I})],
- Ports = erlang:ports(),
- H = qlc:q([{X,Y} || X <- [a,b],
- begin
- [P] = erlang:ports() -- Ports,
- exit(P, port_exit),
- true
- end,
- Y <- qlc:sort(ets:table(E),
- [{tmpdir,\"">>,
- TmpDir, <<"\"}])]),
- {error, qlc, {file_error, _, _}} = (catch qlc:e(H)),
- receive {'EXIT', _, port_exit} -> ok end,
- ets:delete(E),
- process_flag(trap_exit, TE)">>]
- end
+ ets:delete(E)">>
],
run(Config, Ts),
@@ -2457,7 +2436,7 @@ info(Config) when is_list(Config) ->
<<"{'EXIT', {badarg, _}} =
(catch qlc:info([X || {X} <- []], {n_elements, 0})),
L = lists:seq(1, 1000),
- \"[1,2,3,4,5,6,7,8,9,10|'...']\" = qlc:info(L, {n_elements, 10}),
+ \"[1, 2, 3, 4, 5, 6, 7, 8, 9, 10 | '...']\" = qlc:info(L, {n_elements, 10}),
{cons,A1,{integer,A2,1},{atom,A3,'...'}} =
qlc:info(L, [{n_elements, 1},{format,abstract_code}]),
1 = erl_anno:line(A1),
@@ -2468,8 +2447,8 @@ info(Config) when is_list(Config) ->
{atom,_,'...'}}}},
{call,_,_,_}]} =
qlc:info(Q, [{n_elements, 3},{format,abstract_code}]),
- \"ets:match_spec_run([a,b,c,d,e,f],\n\"
- \" ets:match_spec_compile([{'$1',[true],\"
+ \"ets:match_spec_run([a, b, c, d, e, f],\n\"
+ \" ets:match_spec_compile([{'$1', [true], \"
\"[{{'$1'}}]}]))\" =
qlc:info(Q, [{n_elements, infinity}])">>,
@@ -3184,19 +3163,13 @@ lookup2(Config) when is_list(Config) ->
[a] = lookup_keys(Q)
end, [{a},{b},{c}])">>,
- {cres,
- <<"etsc(fun(E) ->
+ <<"etsc(fun(E) ->
Q = qlc:q([X || {X}=Y <- ets:table(E),
element(2, Y) == b,
X =:= 1]),
[] = qlc:e(Q),
false = lookup_keys(Q)
- end, [{1,b},{2,3}])">>,
- %% {warnings,[{2,sys_core_fold,nomatch_guard},
- %% {3,qlc,nomatch_filter},
- %% {3,sys_core_fold,{eval_failure,badarg}}]}},
- {warnings,[{2,sys_core_fold,nomatch_guard},
- {3,sys_core_fold,{eval_failure,badarg}}]}},
+ end, [{1,b},{2,3}])">>,
<<"etsc(fun(E) ->
Q = qlc:q([X || {X} <- ets:table(E), element(1,{X}) =:= 1]),
@@ -6574,7 +6547,7 @@ otp_7114(Config) when is_list(Config) ->
otp_7232(Config) when is_list(Config) ->
Ts = [<<"L = [fun math:sqrt/1, list_to_pid(\"<0.4.1>\"),
erlang:make_ref()],
- \"[fun math:sqrt/1,<0.4.1>,#Ref<\" ++ _ = qlc:info(L),
+ \"[fun math:sqrt/1, <0.4.1>, #Ref<\" ++ _ = qlc:info(L),
{call,_,
{remote,_,{atom,_,qlc},{atom,_,sort}},
[{cons,_,
@@ -6590,7 +6563,7 @@ otp_7232(Config) when is_list(Config) ->
\"qlc:sort([55296,56296],[{order,fun'-function/0-fun-2-'/2}])\" =
format_info(Q, true),
AC = qlc:info(Q, {format, abstract_code}),
- \"qlc:sort([55296,56296], [{order,fun '-function/0-fun-2-'/2}])\" =
+ \"qlc:sort([55296, 56296], [{order, fun '-function/0-fun-2-'/2}])\" =
binary_to_list(iolist_to_binary(erl_pp:expr(AC)))">>,
%% OTP-7234. erl_parse:abstract() handles bit strings
@@ -7115,21 +7088,21 @@ manpage(Config) when is_list(Config) ->
\" V1 =\n\"
\" qlc:q([ \n\"
\" SQV ||\n\"
- \" SQV <- [x,y]\n\"
+ \" SQV <- [x, y]\n\"
\" ],\n\"
- \" [{unique,true}]),\n\"
+ \" [{unique, true}]),\n\"
\" V2 =\n\"
\" qlc:q([ \n\"
\" SQV ||\n\"
- \" SQV <- [a,b]\n\"
+ \" SQV <- [a, b]\n\"
\" ],\n\"
- \" [{unique,true}]),\n\"
+ \" [{unique, true}]),\n\"
\" qlc:q([ \n\"
- \" {X,Y} ||\n\"
+ \" {X, Y} ||\n\"
\" X <- V1,\n\"
\" Y <- V2\n\"
\" ],\n\"
- \" [{unique,true}])\n\"
+ \" [{unique, true}])\n\"
\"end\",
true = B =:= qlc:info(QH, unique_all)">>,
@@ -7145,19 +7118,19 @@ manpage(Config) when is_list(Config) ->
\" V1 =\n\"
\" qlc:q([ \n\"
\" P0 ||\n\"
- \" P0 = {W,Y} <- ets:table(_)\n\"
+ \" P0 = {W, Y} <- ets:table(_)\n\"
\" ]),\n\"
\" V2 =\n\"
\" qlc:q([ \n\"
- \" [G1|G2] ||\n\"
+ \" [G1 | G2] ||\n\"
\" G2 <- V1,\n\"
\" G1 <- ets:table(_),\n\"
\" element(2, G1) =:= element(1, G2)\n\"
\" ],\n\"
- \" [{join,lookup}]),\n\"
+ \" [{join, lookup}]),\n\"
\" qlc:q([ \n\"
- \" {X,Z,W} ||\n\"
- \" [{X,Z}|{W,Y}] <- V2\n\"
+ \" {X, Z, W} ||\n\"
+ \" [{X, Z} | {W, Y}] <- V2\n\"
\" ])\n\"
\"end\",
Info1 =
@@ -7182,25 +7155,28 @@ manpage(Config) when is_list(Config) ->
\" V1 =\n\"
\" qlc:q([ \n\"
\" P0 ||\n\"
- \" P0 = {X,Z} <- qlc:keysort(1, [{a,1},{b,4},{c,6}], [])\n\"
+ \" P0 = {X, Z} <-\n\"
+ \" qlc:keysort(1, [{a, 1}, {b, 4}, {c, 6}], [])\n\"
\" ]),\n\"
\" V2 =\n\"
\" qlc:q([ \n\"
\" P0 ||\n\"
- \" P0 = {W,Y} <- qlc:keysort(2, [{2,a},{3,b},{4,c}], [])\n\"
+ \" P0 = {W, Y} <-\n\"
+ \" qlc:keysort(2, [{2, a}, {3, b}, {4, c}], [])\n\"
+
\" ]),\n\"
\" V3 =\n\"
\" qlc:q([ \n\"
- \" [G1|G2] ||\n\"
+ \" [G1 | G2] ||\n\"
\" G1 <- V1,\n\"
\" G2 <- V2,\n\"
\" element(1, G1) == element(2, G2)\n\"
\" ],\n\"
- \" [{join,merge},{cache,list}]),\n\"
+ \" [{join, merge}, {cache, list}]),\n\"
\" qlc:q([ \n\"
- \" {A,X,Z,W} ||\n\"
- \" A <- [a,b,c],\n\"
- \" [{X,Z}|{W,Y}] <- V3,\n\"
+ \" {A, X, Z, W} ||\n\"
+ \" A <- [a, b, c],\n\"
+ \" [{X, Z} | {W, Y}] <- V3,\n\"
\" X =:= Y\n\"
\" ])\n\"
\"end\",
@@ -7242,14 +7218,21 @@ manpage(Config) when is_list(Config) ->
gb_trees:lookup(K,
gb_trees:from_orddict([]))
of
- {value,V} ->
- [{K,V}];
+ {value, V} ->
+ [{K, V}];
none ->
[]
end
end,
- [{1,a},{1,b},{1,c},{2,a},{2,b},{2,c}]),
- ets:match_spec_compile([{{{'$1','$2'},'_'},[],['$1']}]))\",
+ [{1, a},
+ {1, b},
+ {1, c},
+ {2, a},
+ {2, b},
+ {2, c}]),
+ ets:match_spec_compile([{{{'$1', '$2'}, '_'},
+ [],
+ ['$1']}]))\",
L = qlc:info(QH)">>
],
run(Config, Ts),
@@ -7489,7 +7472,7 @@ strip_qlc_call(H) ->
strip_qlc_call2(H) ->
S = qlc:info(H, {flat, false}),
{ok, Tokens, _EndLine} = erl_scan:string(S++".", 1, [text]),
- {ok, [Expr], Bs} = lib:extended_parse_exprs(Tokens),
+ {ok, [Expr], Bs} = erl_eval:extended_parse_exprs(Tokens),
{case Expr of
{call,_,{remote,_,{atom,_,qlc},{atom,_,q}},[LC]} ->
{qlc, lists:flatten([erl_pp:expr(LC), "."]), []};
@@ -7510,7 +7493,7 @@ strip_qlc_call2(H) ->
join_info_count(H) ->
S = qlc:info(H, {flat, false}),
{ok, Tokens, _EndLine} = erl_scan:string(S++".", 1, [text]),
- {ok, [Expr], _Bs} = lib:extended_parse_exprs(Tokens),
+ {ok, [Expr], _Bs} = erl_eval:extended_parse_exprs(Tokens),
#ji{nmerge = Nmerge, nlookup = Nlookup,
nkeysort = NKeysort, nnested_loop = Nnested_loop} =
ji(Expr, #ji{}),
@@ -7554,7 +7537,7 @@ lookup_keys({generate,_,Q}, L) ->
lookup_keys(Q, L);
lookup_keys({table,Chars}, L) when is_list(Chars) ->
{ok, Tokens, _} = erl_scan:string(lists:flatten(Chars++"."), 1, [text]),
- {ok, [Expr], _Bs} = lib:extended_parse_exprs(Tokens),
+ {ok, [Expr], _Bs} = erl_eval:extended_parse_exprs(Tokens),
case Expr of
{call,_,_,[_fun,AKs]} ->
case erl_parse:normalise(AKs) of
diff --git a/lib/stdlib/test/rand_SUITE.erl b/lib/stdlib/test/rand_SUITE.erl
index 432293b656..7685c17967 100644
--- a/lib/stdlib/test/rand_SUITE.erl
+++ b/lib/stdlib/test/rand_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,18 +21,7 @@
-compile({nowarn_deprecated_function,[{random,seed,1},
{random,uniform_s,1},
{random,uniform_s,2}]}).
-
--export([all/0, suite/0, groups/0, group/1]).
-
--export([interval_int/1, interval_float/1, seed/1,
- api_eq/1, reference/1,
- basic_stats_uniform_1/1, basic_stats_uniform_2/1,
- basic_stats_standard_normal/1,
- basic_stats_normal/1,
- plugin/1, measure/1,
- reference_jump_state/1, reference_jump_procdict/1]).
-
--export([test/0, gen/1]).
+-compile([export_all, nowarn_export_all]).
-include_lib("common_test/include/ct.hrl").
@@ -47,20 +36,30 @@ all() ->
api_eq,
reference,
{group, basic_stats},
+ {group, distr_stats},
+ uniform_real_conv,
plugin, measure,
- {group, reference_jump}
+ {group, reference_jump},
+ short_jump
].
groups() ->
[{basic_stats, [parallel],
[basic_stats_uniform_1, basic_stats_uniform_2,
basic_stats_standard_normal]},
+ {distr_stats, [parallel],
+ [stats_standard_normal_box_muller,
+ stats_standard_normal_box_muller_2,
+ stats_standard_normal]},
{reference_jump, [parallel],
[reference_jump_state, reference_jump_procdict]}].
group(basic_stats) ->
%% valgrind needs a lot of time
[{timetrap,{minutes,10}}];
+group(distr_stats) ->
+ %% valgrind needs a lot of time
+ [{timetrap,{minutes,10}}];
group(reference_jump) ->
%% valgrind needs a lot of time
[{timetrap,{minutes,10}}].
@@ -73,14 +72,14 @@ test() ->
try
ok = ?MODULE:Test([]),
io:format("~p: ok~n", [Test])
- catch _:Reason ->
+ catch _:Reason:Stacktrace ->
io:format("Failed: ~p: ~p ~p~n",
- [Test, Reason, erlang:get_stacktrace()])
+ [Test, Reason, Stacktrace])
end
end, Tests).
algs() ->
- [exs64, exsplus, exsp, exrop, exs1024, exs1024s].
+ [exsss, exrop, exsp, exs1024s, exs64, exsplus, exs1024, exro928ss].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -89,8 +88,8 @@ seed(Config) when is_list(Config) ->
Algs = algs(),
Test = fun(Alg) ->
try seed_1(Alg)
- catch _:Reason ->
- ct:fail({Alg, Reason, erlang:get_stacktrace()})
+ catch _:Reason:Stacktrace ->
+ ct:fail({Alg, Reason, Stacktrace})
end
end,
[Test(Alg) || Alg <- Algs],
@@ -101,7 +100,7 @@ seed_1(Alg) ->
_ = rand:uniform(),
S00 = get(rand_seed),
erase(),
- _ = rand:uniform(),
+ _ = rand:uniform_real(),
false = S00 =:= get(rand_seed), %% hopefully
%% Choosing algo and seed
@@ -110,7 +109,7 @@ seed_1(Alg) ->
S0 = get(rand_seed),
S0 = rand:seed_s(Alg, {0, 0, 0}),
%% Check that process_dict should not be used for seed_s functionality
- _ = rand:seed_s(Alg, {1, 0, 0}),
+ _ = rand:seed_s(Alg, 4711),
S0 = get(rand_seed),
%% Test export
ES0 = rand:export_seed(),
@@ -228,11 +227,13 @@ interval_float(Config) when is_list(Config) ->
interval_float_1(0) -> ok;
interval_float_1(N) ->
X = rand:uniform(),
+ Y = rand:uniform_real(),
if
- 0.0 =< X, X < 1.0 ->
+ 0.0 =< X, X < 1.0, 0.0 < Y, Y < 1.0 ->
ok;
true ->
- io:format("X=~p 0=<~p<1.0~n", [X,X]),
+ io:format("X=~p 0.0=<~p<1.0~n", [X,X]),
+ io:format("Y=~p 0.0<~p<1.0~n", [Y,Y]),
exit({X, rand:export_seed()})
end,
interval_float_1(N-1).
@@ -245,31 +246,43 @@ reference(Config) when is_list(Config) ->
ok.
reference_1(Alg) ->
- Refval = reference_val(Alg),
- Testval = gen(Alg),
- case Refval =:= Testval of
- true -> ok;
- false when Refval =:= not_implemented ->
- exit({not_implemented,Alg});
- false ->
- io:format("Failed: ~p~n",[Alg]),
- io:format("Length ~p ~p~n",[length(Refval), length(Testval)]),
- io:format("Head ~p ~p~n",[hd(Refval), hd(Testval)]),
- exit(wrong_value)
+ Refval = reference_val(Alg),
+ if
+ Refval =:= not_implemented -> Refval;
+ true ->
+ case gen(Alg) of
+ Refval ->
+ io:format("Ok: ~p~n",[Alg]),
+ ok;
+ Testval ->
+ io:format("Failed: ~p~n",[Alg]),
+ io:format("Length ~p ~p~n",[length(Refval), length(Testval)]),
+ io:format("Head ~p ~p~n",[hd(Refval), hd(Testval)]),
+ show_wrong(Refval, Testval),
+ exit(wrong_value)
+ end
end.
+show_wrong([], []) ->
+ ok;
+show_wrong([H|T1], [H|T2]) ->
+ show_wrong(T1, T2);
+show_wrong([H1|_], [H2|_]) ->
+ io:format("Wrong ~p ~p~n",[H1,H2]).
+
+
gen(Algo) ->
State =
- case Algo of
- exs64 -> %% Printed with orig 'C' code and this seed
- rand:seed_s({exs64, 12345678});
- _ when Algo =:= exsplus; Algo =:= exsp; Algo =:= exrop ->
+ if
+ Algo =:= exs64 -> %% Printed with orig 'C' code and this seed
+ rand:seed_s(exs64, [12345678]);
+ Algo =:= exsplus; Algo =:= exsp; Algo =:= exrop; Algo =:= exsss ->
%% Printed with orig 'C' code and this seed
- rand:seed_s({Algo, [12345678|12345678]});
- _ when Algo =:= exs1024; Algo =:= exs1024s ->
+ rand:seed_s(Algo, [12345678,12345678]);
+ Algo =:= exs1024; Algo =:= exs1024s; Algo =:= exro928ss ->
%% Printed with orig 'C' code and this seed
- rand:seed_s({Algo, {lists:duplicate(16, 12345678), []}});
- _ ->
+ rand:seed_s(Algo, lists:duplicate(16, 12345678));
+ true ->
rand:seed(Algo, {100, 200, 300})
end,
Max = range(State),
@@ -334,7 +347,13 @@ basic_stats_normal(Config) when is_list(Config) ->
IntendedMeanVariancePairs).
basic_uniform_1(N, S0, Sum, A0) when N > 0 ->
- {X,S} = rand:uniform_s(S0),
+ {X,S} =
+ case N band 1 of
+ 0 ->
+ rand:uniform_s(S0);
+ 1 ->
+ rand:uniform_real_s(S0)
+ end,
I = trunc(X*100),
A = array:set(I, 1+array:get(I,A0), A0),
basic_uniform_1(N-1, S, Sum+X, A);
@@ -399,6 +418,352 @@ normal_s(Mean, Variance, State0) when Mean == 0, Variance == 1 ->
normal_s(Mean, Variance, State0) ->
rand:normal_s(Mean, Variance, State0).
+
+
+-dialyzer({no_improper_lists, stats_standard_normal_box_muller/1}).
+stats_standard_normal_box_muller(Config) when is_list(Config) ->
+ try math:erfc(1.0) of
+ _ ->
+ TwoPi = 2.0 * math:pi(),
+ NormalS =
+ fun
+ ([S0]) ->
+ {U1, S1} = rand:uniform_real_s(S0),
+ R = math:sqrt(-2.0 * math:log(U1)),
+ {U2, S2} = rand:uniform_s(S1),
+ T = TwoPi * U2,
+ Z0 = R * math:cos(T),
+ Z1 = R * math:sin(T),
+ {Z0, [S2|Z1]};
+ ([S|Z]) ->
+ {Z, [S]}
+ end,
+ State = [rand:seed(exsss)],
+ stats_standard_normal(NormalS, State, 3)
+ catch error:_ ->
+ {skip, "math:erfc/1 not supported"}
+ end.
+
+-dialyzer({no_improper_lists, stats_standard_normal_box_muller_2/1}).
+stats_standard_normal_box_muller_2(Config) when is_list(Config) ->
+ try math:erfc(1.0) of
+ _ ->
+ TwoPi = 2.0 * math:pi(),
+ NormalS =
+ fun
+ ([S0]) ->
+ {U0, S1} = rand:uniform_s(S0),
+ U1 = 1.0 - U0,
+ R = math:sqrt(-2.0 * math:log(U1)),
+ {U2, S2} = rand:uniform_s(S1),
+ T = TwoPi * U2,
+ Z0 = R * math:cos(T),
+ Z1 = R * math:sin(T),
+ {Z0, [S2|Z1]};
+ ([S|Z]) ->
+ {Z, [S]}
+ end,
+ State = [rand:seed(exsss)],
+ stats_standard_normal(NormalS, State, 3)
+ catch error:_ ->
+ {skip, "math:erfc/1 not supported"}
+ end.
+
+
+stats_standard_normal(Config) when is_list(Config) ->
+ Retries = 7,
+ try math:erfc(1.0) of
+ _ ->
+ stats_standard_normal(
+ fun rand:normal_s/1, rand:seed_s(exsss), Retries)
+ catch error:_ ->
+ {skip, "math:erfc/1 not supported"}
+ end.
+%%
+stats_standard_normal(Fun, S, Retries) ->
+%%%
+%%% ct config:
+%%% {rand_SUITE, [{stats_standard_normal,[{seconds, 8}, {std_devs, 4.0}]}]}.
+%%%
+ Seconds = ct:get_config({?MODULE, ?FUNCTION_NAME, seconds}, 8),
+ StdDevs =
+ ct:get_config(
+ {?MODULE, ?FUNCTION_NAME, std_devs},
+ 4.0), % probability erfc(4.0/sqrt(2)) (1/15787) to fail a bucket
+%%%
+ ct:timetrap({seconds, Seconds + 120}),
+ %% Buckets is chosen to get a range where the the probability to land
+ %% in the top catch-all bucket is not vanishingly low, but with
+ %% these values it is about 1/25 of the probability for the low bucket
+ %% (closest to 0).
+ %%
+ %% Rounds is calculated so the expected value for the low
+ %% bucket will be at least TargetHits.
+ %%
+ InvDelta = 512,
+ Buckets = 4 * InvDelta, % 4 std devs range
+ TargetHits = 1024,
+ Sqrt2 = math:sqrt(2.0),
+ W = InvDelta * Sqrt2,
+ P0 = math:erf(1 / W),
+ Rounds = TargetHits * ceil(1.0 / P0),
+ Histogram = array:new({default, 0}),
+ ct:pal(
+ "Running standard normal test against ~w std devs for ~w seconds...",
+ [StdDevs, Seconds]),
+ StopTime = erlang:monotonic_time(second) + Seconds,
+ {PositiveHistogram, NegativeHistogram, Outlier, TotalRounds, NewS} =
+ stats_standard_normal(
+ InvDelta, Buckets, Histogram, Histogram, 0.0,
+ Fun, S, Rounds, StopTime, Rounds, 0),
+ Precision = math:sqrt(TotalRounds * P0) / StdDevs,
+ TopP = math:erfc(Buckets / W),
+ TopPrecision = math:sqrt(TotalRounds * TopP) / StdDevs,
+ OutlierProbability = math:erfc(Outlier / Sqrt2) * TotalRounds,
+ InvOP = 1.0 / OutlierProbability,
+ ct:pal(
+ "Total rounds: ~w, tolerance: 1/~.2f..1/~.2f, "
+ "outlier: ~.2f, probability 1/~.2f.",
+ [TotalRounds, Precision, TopPrecision, Outlier, InvOP]),
+ case
+ {bucket_error, TotalRounds,
+ check_histogram(
+ W, TotalRounds, StdDevs, PositiveHistogram, Buckets),
+ check_histogram(
+ W, TotalRounds, StdDevs, NegativeHistogram, Buckets)}
+ of
+ {_, _, [], []} when InvOP < 100 ->
+ {comment, {tp, TopPrecision, op, InvOP}};
+ {_, _, [], []} ->
+ %% If the probability for getting this Outlier is lower than
+ %% 1/100, then this is fishy!
+ stats_standard_normal(
+ Fun, NewS, Retries, {outlier_fishy, InvOP});
+ BucketErrors ->
+ stats_standard_normal(
+ Fun, NewS, Retries, BucketErrors)
+ end.
+%%
+stats_standard_normal(Fun, S, Retries, Failure) ->
+ case Retries - 1 of
+ 0 ->
+ ct:fail(Failure);
+ NewRetries ->
+ ct:pal("Retry due to TC glitch: ~p", [Failure]),
+ stats_standard_normal(Fun, S, NewRetries)
+ end.
+%%
+stats_standard_normal(
+ InvDelta, Buckets, PositiveHistogram, NegativeHistogram, Outlier,
+ Fun, S, 0, StopTime, Rounds, TotalRounds) ->
+ case erlang:monotonic_time(second) of
+ Now when Now < StopTime ->
+ stats_standard_normal(
+ InvDelta, Buckets,
+ PositiveHistogram, NegativeHistogram, Outlier,
+ Fun, S, Rounds, StopTime, Rounds, TotalRounds + Rounds);
+ _ ->
+ {PositiveHistogram, NegativeHistogram,
+ Outlier, TotalRounds + Rounds, S}
+ end;
+stats_standard_normal(
+ InvDelta, Buckets, PositiveHistogram, NegativeHistogram, Outlier,
+ Fun, S, Count, StopTime, Rounds, TotalRounds) ->
+ case Fun(S) of
+ {X, NewS} when 0.0 =< X ->
+ Bucket = min(Buckets, floor(X * InvDelta)),
+ stats_standard_normal(
+ InvDelta, Buckets,
+ increment_bucket(Bucket, PositiveHistogram),
+ NegativeHistogram, max(Outlier, X),
+ Fun, NewS, Count - 1, StopTime, Rounds, TotalRounds);
+ {MinusX, NewS} ->
+ X = -MinusX,
+ Bucket = min(Buckets, floor(X * InvDelta)),
+ stats_standard_normal(
+ InvDelta, Buckets,
+ PositiveHistogram,
+ increment_bucket(Bucket, NegativeHistogram), max(Outlier, X),
+ Fun, NewS, Count - 1, StopTime, Rounds, TotalRounds)
+ end.
+
+increment_bucket(Bucket, Array) ->
+ array:set(Bucket, array:get(Bucket, Array) + 1, Array).
+
+check_histogram(W, Rounds, StdDevs, Histogram, Buckets) ->
+ TargetP = 0.5 * math:erfc(Buckets / W),
+ P = 0.0,
+ N = 0,
+ check_histogram(
+ W, Rounds, StdDevs, Histogram, TargetP,
+ Buckets, Buckets, P, N).
+%%
+check_histogram(
+ _W, _Rounds, _StdDevs, _Histogram, _TargetP,
+ 0, _PrevBucket, _PrevP, _PrevN) ->
+ [];
+check_histogram(
+ W, Rounds, StdDevs, Histogram, TargetP,
+ Bucket, PrevBucket, PrevP, PrevN) ->
+ N = PrevN + array:get(Bucket, Histogram),
+ P = 0.5 * math:erfc(Bucket / W),
+ BucketP = P - PrevP,
+ if
+ BucketP < TargetP ->
+ check_histogram(
+ W, Rounds, StdDevs, Histogram, TargetP,
+ Bucket - 1, PrevBucket, PrevP, N);
+ true ->
+ Exp = BucketP * Rounds,
+ Var = Rounds * BucketP*(1.0 - BucketP),
+ Threshold = StdDevs * math:sqrt(Var),
+ LowerLimit = floor(Exp - Threshold),
+ UpperLimit = ceil(Exp + Threshold),
+ if
+ N < LowerLimit; UpperLimit < N ->
+ [#{bucket => {Bucket, PrevBucket}, n => N,
+ lower => LowerLimit, upper => UpperLimit} |
+ check_histogram(
+ W, Rounds, StdDevs, Histogram, TargetP,
+ Bucket - 1, Bucket, P, 0)];
+ true ->
+ check_histogram(
+ W, Rounds, StdDevs, Histogram, TargetP,
+ Bucket - 1, Bucket, P, 0)
+ end
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% White box test of the conversion to float
+
+uniform_real_conv(Config) when is_list(Config) ->
+ [begin
+%% ct:pal("~13.16.0bx~3.16.0b: ~p~n", [M,E,Gen]),
+ uniform_real_conv_check(M, E, Gen)
+ end || {M, E, Gen} <- uniform_real_conv_data()],
+ uniform_real_scan(0),
+ uniform_real_scan(3).
+
+uniform_real_conv_data() ->
+ [{16#fffffffffffff, -1, [16#3ffffffffffffff]},
+ {16#fffffffffffff, -1, [16#3ffffffffffffe0]},
+ {16#ffffffffffffe, -1, [16#3ffffffffffffdf]},
+ %%
+ {16#0000000000000, -1, [16#200000000000000]},
+ {16#fffffffffffff, -2, [16#1ffffffffffffff]},
+ {16#fffffffffffff, -2, [16#1fffffffffffff0]},
+ {16#ffffffffffffe, -2, [16#1ffffffffffffef]},
+ %%
+ {16#0000000000000, -2, [16#100000000000000]},
+ {16#fffffffffffff, -3, [16#0ffffffffffffff]},
+ {16#fffffffffffff, -3, [16#0fffffffffffff8]},
+ {16#ffffffffffffe, -3, [16#0fffffffffffff7]},
+ %%
+ {16#0000000000000, -3, [16#080000000000000]},
+ {16#fffffffffffff, -4, [16#07fffffffffffff]},
+ {16#fffffffffffff, -4, [16#07ffffffffffffc]},
+ {16#ffffffffffffe, -4, [16#07ffffffffffffb]},
+ %%
+ {16#0000000000000, -4, [16#040000000000000]},
+ {16#fffffffffffff, -5, [16#03fffffffffffff,16#3ffffffffffffff]},
+ {16#fffffffffffff, -5, [16#03ffffffffffffe,16#200000000000000]},
+ {16#ffffffffffffe, -5, [16#03fffffffffffff,16#1ffffffffffffff]},
+ {16#ffffffffffffe, -5, [16#03fffffffffffff,16#100000000000000]},
+ %%
+ {16#0000000000001, -56, [16#000000000000007,16#00000000000007f]},
+ {16#0000000000001, -56, [16#000000000000004,16#000000000000040]},
+ {16#0000000000000, -57, [16#000000000000003,16#20000000000001f]},
+ {16#0000000000000, -57, [16#000000000000000,16#200000000000000]},
+ {16#fffffffffffff, -58, [16#000000000000003,16#1ffffffffffffff]},
+ {16#fffffffffffff, -58, [16#000000000000000,16#1fffffffffffff0]},
+ {16#ffffffffffffe, -58, [16#000000000000000,16#1ffffffffffffef]},
+ {16#ffffffffffffe, -58, [16#000000000000000,16#1ffffffffffffe0]},
+ %%
+ {16#0000000000000, -58, [16#000000000000000,16#10000000000000f]},
+ {16#0000000000000, -58, [16#000000000000000,16#100000000000000]},
+ {2#11001100000000000000000000000000000000000011000000011, % 53 bits
+ -1022,
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, % 18 zeros
+ 2#1100110000000000000000000000000000000000001 bsl 2, % 43 bits
+ 2#1000000011 bsl (56-10+2)]}, % 10 bits
+ {0, -1, % 0.5 after retry
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, % 18 zeros
+ 2#111111111111111111111111111111111111111111 bsl 2, % 42 bits - retry
+ 16#200000000000003]}]. % 0.5
+
+-define(UNIFORM_REAL_SCAN_PATTERN, (16#19000000000009)). % 53 bits
+-define(UNIFORM_REAL_SCAN_NUMBER, (1021)).
+
+uniform_real_scan_template(K) ->
+ <<0:?UNIFORM_REAL_SCAN_NUMBER,
+ ?UNIFORM_REAL_SCAN_PATTERN:53,K:2,0:1>>.
+
+uniform_real_scan(K) ->
+ Templ = uniform_real_scan_template(K),
+ N = ?UNIFORM_REAL_SCAN_NUMBER,
+ uniform_real_scan(Templ, N, K).
+
+uniform_real_scan(Templ, N, K) when 0 =< N ->
+ <<_:N/bits,T/bits>> = Templ,
+ Data = uniform_real_scan_data(T, K),
+ uniform_real_conv_check(
+ ?UNIFORM_REAL_SCAN_PATTERN, N - 1 - ?UNIFORM_REAL_SCAN_NUMBER, Data),
+ uniform_real_scan(Templ, N - 1, K);
+uniform_real_scan(_, _, _) ->
+ ok.
+
+uniform_real_scan_data(Templ, K) ->
+ case Templ of
+ <<X:56, T/bits>> ->
+ B = rand:bc64(X),
+ [(X bsl 2) bor K |
+ if
+ 53 =< B ->
+ [];
+ true ->
+ uniform_real_scan_data(T, K)
+ end];
+ _ ->
+ <<X:56, _/bits>> = <<Templ/bits, 0:56>>,
+ [(X bsl 2) bor K]
+ end.
+
+uniform_real_conv_check(M, E, Gen) ->
+ <<F/float>> = <<0:1, (E + 16#3ff):11, M:52>>,
+ try uniform_real_gen(Gen) of
+ F -> F;
+ FF ->
+ ct:pal(
+ "~s =/= ~s: ~s~n",
+ [rand:float2str(FF), rand:float2str(F),
+ [["16#",integer_to_list(G,16),$\s]||G<-Gen]]),
+ ct:fail({neq, FF, F})
+ catch
+ Error:Reason:Stacktrace ->
+ ct:pal(
+ "~w:~p ~s: ~s~n",
+ [Error, Reason, rand:float2str(F),
+ [["16#",integer_to_list(G,16),$\s]||G<-Gen]]),
+ ct:fail({Error, Reason, F, Stacktrace})
+ end.
+
+
+uniform_real_gen(Gen) ->
+ State = rand_state(Gen),
+ {F, {#{type := rand_SUITE_list},[]}} = rand:uniform_real_s(State),
+ F.
+
+uniform_gen(Range, Gen) ->
+ State = rand_state(Gen),
+ {N, {#{type := rand_SUITE_list},[]}} = rand:uniform_s(Range, State),
+ N.
+
+%% Loaded dice for white box tests
+rand_state(Gen) ->
+ {#{type => rand_SUITE_list, bits => 58, weak_low_bits => 1,
+ next => fun ([H|T]) -> {H, T} end},
+ Gen}.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Test that the user can write algorithms.
@@ -459,221 +824,303 @@ measure(Config) ->
{skip,{will_not_run_in_scaled_time,Scale}}
end.
+-define(CHECK_UNIFORM_RANGE(Gen, Range, X, St),
+ case (Gen) of
+ {(X), (St)} when is_integer(X), 1 =< (X), (X) =< (Range) ->
+ St
+ end).
+-define(CHECK_UNIFORM(Gen, X, St),
+ case (Gen) of
+ {(X), (St)} when is_float(X), 0.0 =< (X), (X) < 1.0 ->
+ St
+ end).
+-define(CHECK_UNIFORM_NZ(Gen, X, St),
+ case (Gen) of
+ {(X), (St)} when is_float(X), 0.0 < (X), (X) =< 1.0 ->
+ St
+ end).
+-define(CHECK_NORMAL(Gen, X, St),
+ case (Gen) of
+ {(X), (St)} when is_float(X) ->
+ St
+ end).
+
do_measure(_Config) ->
- Algos =
+ Algs =
+ algs() ++
try crypto:strong_rand_bytes(1) of
- <<_>> -> [crypto64, crypto]
+ <<_>> ->
+ [crypto64, crypto_cache, crypto_aes, crypto]
catch
error:low_entropy -> [];
error:undef -> []
- end ++ algs(),
+ end,
%%
- ct:pal("RNG uniform integer performance~n",[]),
- TMark1 =
+ ct:pal("~nRNG uniform integer range 10000 performance~n",[]),
+ _ =
measure_1(
- random,
fun (_) -> 10000 end,
- undefined,
- fun (Range, State) ->
- {int, random:uniform_s(Range, State)}
- end),
+ fun (State, Range, Mod) ->
+ measure_loop(
+ fun (St0) ->
+ ?CHECK_UNIFORM_RANGE(
+ Mod:uniform_s(Range, St0), Range,
+ X, St1)
+ end,
+ State)
+ end,
+ Algs),
+ %%
+ ct:pal("~nRNG uniform integer 32 bit performance~n",[]),
_ =
- [measure_1(
- Algo,
- fun (_) -> 10000 end,
- TMark1,
- fun (Range, State) ->
- {int, rand:uniform_s(Range, State)}
- end) || Algo <- Algos],
+ measure_1(
+ fun (_) -> 1 bsl 32 end,
+ fun (State, Range, Mod) ->
+ measure_loop(
+ fun (St0) ->
+ ?CHECK_UNIFORM_RANGE(
+ Mod:uniform_s(Range, St0), Range,
+ X, St1)
+ end,
+ State)
+ end,
+ Algs),
%%
ct:pal("~nRNG uniform integer half range performance~n",[]),
- HalfRangeFun = fun (State) -> half_range(State) end,
- TMark2 =
- measure_1(
- random,
- HalfRangeFun,
- undefined,
- fun (Range, State) ->
- {int, random:uniform_s(Range, State)}
- end),
_ =
- [measure_1(
- Algo,
- HalfRangeFun,
- TMark2,
- fun (Range, State) ->
- {int, rand:uniform_s(Range, State)}
- end) || Algo <- Algos],
- %%
- ct:pal("~nRNG uniform integer half range + 1 performance~n",[]),
- HalfRangePlus1Fun = fun (State) -> half_range(State) + 1 end,
- TMark3 =
measure_1(
- random,
- HalfRangePlus1Fun,
- undefined,
- fun (Range, State) ->
- {int, random:uniform_s(Range, State)}
- end),
+ fun (State) -> half_range(State) end,
+ fun (State, Range, Mod) ->
+ measure_loop(
+ fun (St0) ->
+ ?CHECK_UNIFORM_RANGE(
+ Mod:uniform_s(Range, St0), Range,
+ X, St1)
+ end,
+ State)
+ end,
+ Algs),
+ %%
+ ct:pal("~nRNG uniform integer half range + 1 performance~n",[]),
_ =
- [measure_1(
- Algo,
- HalfRangePlus1Fun,
- TMark3,
- fun (Range, State) ->
- {int, rand:uniform_s(Range, State)}
- end) || Algo <- Algos],
+ measure_1(
+ fun (State) -> half_range(State) + 1 end,
+ fun (State, Range, Mod) ->
+ measure_loop(
+ fun (St0) ->
+ ?CHECK_UNIFORM_RANGE(
+ Mod:uniform_s(Range, St0), Range,
+ X, St1)
+ end,
+ State)
+ end,
+ Algs),
%%
ct:pal("~nRNG uniform integer full range - 1 performance~n",[]),
- FullRangeMinus1Fun = fun (State) -> (half_range(State) bsl 1) - 1 end,
- TMark4 =
- measure_1(
- random,
- FullRangeMinus1Fun,
- undefined,
- fun (Range, State) ->
- {int, random:uniform_s(Range, State)}
- end),
_ =
- [measure_1(
- Algo,
- FullRangeMinus1Fun,
- TMark4,
- fun (Range, State) ->
- {int, rand:uniform_s(Range, State)}
- end) || Algo <- Algos],
+ measure_1(
+ fun (State) -> (half_range(State) bsl 1) - 1 end,
+ fun (State, Range, Mod) ->
+ measure_loop(
+ fun (St0) ->
+ ?CHECK_UNIFORM_RANGE(
+ Mod:uniform_s(Range, St0), Range,
+ X, St1)
+ end,
+ State)
+ end,
+ Algs),
%%
ct:pal("~nRNG uniform integer full range performance~n",[]),
- FullRangeFun = fun (State) -> half_range(State) bsl 1 end,
- TMark5 =
- measure_1(
- random,
- FullRangeFun,
- undefined,
- fun (Range, State) ->
- {int, random:uniform_s(Range, State)}
- end),
_ =
- [measure_1(
- Algo,
- FullRangeFun,
- TMark5,
- fun (Range, State) ->
- {int, rand:uniform_s(Range, State)}
- end) || Algo <- Algos],
+ measure_1(
+ fun (State) -> half_range(State) bsl 1 end,
+ fun (State, Range, Mod) ->
+ measure_loop(
+ fun (St0) ->
+ ?CHECK_UNIFORM_RANGE(
+ Mod:uniform_s(Range, St0), Range,
+ X, St1)
+ end,
+ State)
+ end,
+ Algs),
%%
ct:pal("~nRNG uniform integer full range + 1 performance~n",[]),
- FullRangePlus1Fun = fun (State) -> (half_range(State) bsl 1) + 1 end,
- TMark6 =
- measure_1(
- random,
- FullRangePlus1Fun,
- undefined,
- fun (Range, State) ->
- {int, random:uniform_s(Range, State)}
- end),
_ =
- [measure_1(
- Algo,
- FullRangePlus1Fun,
- TMark6,
- fun (Range, State) ->
- {int, rand:uniform_s(Range, State)}
- end) || Algo <- Algos],
+ measure_1(
+ fun (State) -> (half_range(State) bsl 1) + 1 end,
+ fun (State, Range, Mod) ->
+ measure_loop(
+ fun (St0) ->
+ ?CHECK_UNIFORM_RANGE(
+ Mod:uniform_s(Range, St0), Range,
+ X, St1)
+ end,
+ State)
+ end,
+ Algs),
%%
ct:pal("~nRNG uniform integer double range performance~n",[]),
- DoubleRangeFun = fun (State) -> half_range(State) bsl 2 end,
- TMark7 =
- measure_1(
- random,
- DoubleRangeFun,
- undefined,
- fun (Range, State) ->
- {int, random:uniform_s(Range, State)}
- end),
_ =
- [measure_1(
- Algo,
- DoubleRangeFun,
- TMark7,
- fun (Range, State) ->
- {int, rand:uniform_s(Range, State)}
- end) || Algo <- Algos],
+ measure_1(
+ fun (State) ->
+ half_range(State) bsl 2
+ end,
+ fun (State, Range, Mod) ->
+ measure_loop(
+ fun (St0) ->
+ ?CHECK_UNIFORM_RANGE(
+ Mod:uniform_s(Range, St0), Range,
+ X, St1)
+ end,
+ State)
+ end,
+ Algs),
%%
ct:pal("~nRNG uniform integer double range + 1 performance~n",[]),
- DoubleRangePlus1Fun = fun (State) -> (half_range(State) bsl 2) + 1 end,
- TMark8 =
+ _ =
measure_1(
- random,
- DoubleRangePlus1Fun,
- undefined,
- fun (Range, State) ->
- {int, random:uniform_s(Range, State)}
- end),
+ fun (State) ->
+ (half_range(State) bsl 2) + 1
+ end,
+ fun (State, Range, Mod) ->
+ measure_loop(
+ fun (St0) ->
+ ?CHECK_UNIFORM_RANGE(
+ Mod:uniform_s(Range, St0), Range,
+ X, St1)
+ end,
+ State)
+ end,
+ Algs),
+ %%
+ ct:pal("~nRNG uniform integer 64 bit performance~n",[]),
_ =
- [measure_1(
- Algo,
- DoubleRangePlus1Fun,
- TMark8,
- fun (Range, State) ->
- {int, rand:uniform_s(Range, State)}
- end) || Algo <- Algos],
+ measure_1(
+ fun (_) -> 1 bsl 64 end,
+ fun (State, Range, Mod) ->
+ measure_loop(
+ fun (St0) ->
+ ?CHECK_UNIFORM_RANGE(
+ Mod:uniform_s(Range, St0), Range,
+ X, St1)
+ end,
+ State)
+ end,
+ Algs),
%%
ct:pal("~nRNG uniform float performance~n",[]),
- TMark9 =
+ _ =
measure_1(
- random,
fun (_) -> 0 end,
- undefined,
- fun (_, State) ->
- {uniform, random:uniform_s(State)}
- end),
+ fun (State, _, Mod) ->
+ measure_loop(
+ fun (St0) ->
+ ?CHECK_UNIFORM(Mod:uniform_s(St0), X, St)
+ end,
+ State)
+ end,
+ Algs),
+ %%
+ ct:pal("~nRNG uniform_real float performance~n",[]),
_ =
- [measure_1(
- Algo,
- fun (_) -> 0 end,
- TMark9,
- fun (_, State) ->
- {uniform, rand:uniform_s(State)}
- end) || Algo <- Algos],
+ measure_1(
+ fun (_) -> 0 end,
+ fun (State, _, Mod) ->
+ measure_loop(
+ fun (St0) ->
+ ?CHECK_UNIFORM(Mod:uniform_real_s(St0), X, St)
+ end,
+ State)
+ end,
+ Algs),
%%
ct:pal("~nRNG normal float performance~n",[]),
- io:format("~.12w: not implemented (too few bits)~n", [random]),
- _ = [measure_1(
- Algo,
- fun (_) -> 0 end,
- TMark9,
- fun (_, State) ->
- {normal, rand:normal_s(State)}
- end) || Algo <- Algos],
+ [TMarkNormalFloat|_] =
+ measure_1(
+ fun (_) -> 0 end,
+ fun (State, _, Mod) ->
+ measure_loop(
+ fun (St0) ->
+ ?CHECK_NORMAL(Mod:normal_s(St0), X, St1)
+ end,
+ State)
+ end,
+ Algs),
+ %% Just for fun try an implementation of the Box-Muller
+ %% transformation for creating normal distribution floats
+ %% to compare with our Ziggurat implementation.
+ %% Generates two numbers per call that we add so they
+ %% will not be optimized away. Hence the benchmark time
+ %% is twice what it should be.
+ TwoPi = 2 * math:pi(),
+ _ =
+ measure_1(
+ fun (_) -> 0 end,
+ fun (State, _, Mod) ->
+ measure_loop(
+ fun (State0) ->
+ {U1, State1} = Mod:uniform_real_s(State0),
+ {U2, State2} = Mod:uniform_s(State1),
+ R = math:sqrt(-2.0 * math:log(U1)),
+ T = TwoPi * U2,
+ Z0 = R * math:cos(T),
+ Z1 = R * math:sin(T),
+ ?CHECK_NORMAL({Z0 + Z1, State2}, X, State3)
+ end,
+ State)
+ end,
+ exsss, TMarkNormalFloat),
+ ok.
+
+-define(LOOP_MEASURE, (?LOOP div 5)).
+
+measure_loop(Fun, State) ->
+ measure_loop(Fun, State, ?LOOP_MEASURE).
+%%
+measure_loop(Fun, State, N) when 0 < N ->
+ measure_loop(Fun, Fun(State), N-1);
+measure_loop(_, _, _) ->
ok.
-measure_1(Algo, RangeFun, TMark, Gen) ->
+measure_1(RangeFun, Fun, Algs) ->
+ TMark = measure_1(RangeFun, Fun, hd(Algs), undefined),
+ [TMark] ++
+ [measure_1(RangeFun, Fun, Alg, TMark) || Alg <- tl(Algs)].
+
+measure_1(RangeFun, Fun, Alg, TMark) ->
Parent = self(),
- Seed =
- case Algo of
+ {Mod, State} =
+ case Alg of
crypto64 ->
- crypto64_seed();
+ {rand, crypto64_seed()};
+ crypto_cache ->
+ {rand, crypto:rand_seed_alg(crypto_cache)};
crypto ->
- crypto:rand_seed_s();
+ {rand, crypto:rand_seed_s()};
+ crypto_aes ->
+ {rand,
+ crypto:rand_seed_alg(
+ crypto_aes, crypto:strong_rand_bytes(256))};
random ->
- random:seed(os:timestamp()), get(random_seed);
+ {random, random:seed(os:timestamp()), get(random_seed)};
_ ->
- rand:seed_s(Algo)
+ {rand, rand:seed_s(Alg)}
end,
- Range = RangeFun(Seed),
+ Range = RangeFun(State),
Pid = spawn_link(
fun() ->
- Fun = fun() -> measure_2(?LOOP, Range, Seed, Gen) end,
- {Time, ok} = timer:tc(Fun),
+ {Time, ok} = timer:tc(fun () -> Fun(State, Range, Mod) end),
Percent =
case TMark of
undefined -> 100;
_ -> (Time * 100 + 50) div TMark
end,
io:format(
- "~.12w: ~p ns ~p% [16#~.16b]~n",
- [Algo, (Time * 1000 + 500) div ?LOOP, Percent, Range]),
+ "~.20w: ~p ns ~p% [16#~.16b]~n",
+ [Alg, (Time * 1000 + 500) div ?LOOP_MEASURE,
+ Percent, Range]),
Parent ! {self(), Time},
normal
end),
@@ -681,21 +1128,6 @@ measure_1(Algo, RangeFun, TMark, Gen) ->
{Pid, Msg} -> Msg
end.
-measure_2(N, Range, State0, Fun) when N > 0 ->
- case Fun(Range, State0) of
- {int, {Random, State}}
- when is_integer(Random), Random >= 1, Random =< Range ->
- measure_2(N-1, Range, State, Fun);
- {uniform, {Random, State}}
- when is_float(Random), 0.0 =< Random, Random < 1.0 ->
- measure_2(N-1, Range, State, Fun);
- {normal, {Random, State}} when is_float(Random) ->
- measure_2(N-1, Range, State, Fun);
- Res ->
- exit({error, Res, State0})
- end;
-measure_2(0, _, _, _) -> ok.
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% The jump sequence tests has two parts
%% for those with the functional API (jump/1)
@@ -711,104 +1143,156 @@ reference_jump_state(Config) when is_list(Config) ->
ok.
reference_jump_1(Alg) ->
- Refval = reference_jump_val(Alg),
- Testval = gen_jump_1(Alg),
- case Refval =:= Testval of
- true -> ok;
- false ->
- io:format("Failed: ~p~n",[Alg]),
- io:format("Length ~p ~p~n",[length(Refval), length(Testval)]),
- io:format("Head ~p ~p~n",[hd(Refval), hd(Testval)]),
- io:format("Vals ~p ~p~n",[Refval, Testval]),
- exit(wrong_value)
+ Refval = reference_jump_val(Alg),
+ if
+ Refval =:= not_implemented -> Refval;
+ true ->
+ case gen_jump_1(Alg) of
+ Refval -> ok;
+ Testval ->
+ io:format(
+ "Failed: ~p~n",[Alg]),
+ io:format(
+ "Length ~p ~p~n",
+ [length(Refval), length(Testval)]),
+ io:format(
+ "Head ~p ~p~n",[hd(Refval), hd(Testval)]),
+ io:format(
+ "Vals ~p ~p~n",[Refval, Testval]),
+ exit(wrong_value)
+ end
end.
gen_jump_1(Algo) ->
- State =
- case Algo of
- exs64 -> %% Test exception of not_implemented notice
- try rand:jump(rand:seed_s(exs64))
- catch
- error:not_implemented -> not_implemented
- end;
- _ when Algo =:= exsplus; Algo =:= exsp; Algo =:= exrop ->
- %% Printed with orig 'C' code and this seed
- rand:seed_s({Algo, [12345678|12345678]});
- _ when Algo =:= exs1024; Algo =:= exs1024s ->
- %% Printed with orig 'C' code and this seed
- rand:seed_s({Algo, {lists:duplicate(16, 12345678), []}});
- _ -> % unimplemented
- not_implemented
- end,
- case State of
- not_implemented -> [not_implemented];
- _ ->
- Max = range(State),
- gen_jump_1(?LOOP_JUMP, State, Max, [])
+ case Algo of
+ exs64 -> %% Test exception of not_implemented notice
+ try rand:jump(rand:seed_s(exs64))
+ catch
+ error:not_implemented -> [error_not_implemented]
+ end;
+ _ when Algo =:= exsplus; Algo =:= exsp; Algo =:= exrop; Algo =:= exsss ->
+ %% Printed with orig 'C' code and this seed
+ gen_jump_2(
+ rand:seed_s(Algo, [12345678,12345678]));
+ _ when Algo =:= exs1024; Algo =:= exs1024s; Algo =:= exro928ss ->
+ %% Printed with orig 'C' code and this seed
+ gen_jump_2(
+ rand:seed_s(Algo, lists:duplicate(16, 12345678)))
end.
-gen_jump_1(N, State0, Max, Acc) when N > 0 ->
+gen_jump_2(State) ->
+ Max = range(State),
+ gen_jump_3(?LOOP_JUMP, State, Max, []).
+
+gen_jump_3(N, State0, Max, Acc) when N > 0 ->
{_, State1} = rand:uniform_s(Max, State0),
{Random, State2} = rand:uniform_s(Max, rand:jump(State1)),
case N rem (?LOOP_JUMP div 100) of
- 0 -> gen_jump_1(N-1, State2, Max, [Random|Acc]);
- _ -> gen_jump_1(N-1, State2, Max, Acc)
+ 0 -> gen_jump_3(N-1, State2, Max, [Random|Acc]);
+ _ -> gen_jump_3(N-1, State2, Max, Acc)
end;
-gen_jump_1(_, _, _, Acc) -> lists:reverse(Acc).
+gen_jump_3(_, _, _, Acc) -> lists:reverse(Acc).
%% Check if each algorithm generates the proper jump sequence
%% with the internal state in the process dictionary.
reference_jump_procdict(Config) when is_list(Config) ->
- [reference_jump_0(Alg) || Alg <- algs()],
+ [reference_jump_p1(Alg) || Alg <- algs()],
ok.
-reference_jump_0(Alg) ->
+reference_jump_p1(Alg) ->
Refval = reference_jump_val(Alg),
- Testval = gen_jump_0(Alg),
- case Refval =:= Testval of
- true -> ok;
- false ->
- io:format("Failed: ~p~n",[Alg]),
- io:format("Length ~p ~p~n",[length(Refval), length(Testval)]),
- io:format("Head ~p ~p~n",[hd(Refval), hd(Testval)]),
- exit(wrong_value)
+ if
+ Refval =:= not_implemented -> Refval;
+ true ->
+ case gen_jump_p1(Alg) of
+ Refval -> ok;
+ Testval ->
+ io:format("Failed: ~p~n",[Alg]),
+ io:format("Length ~p ~p~n",[length(Refval), length(Testval)]),
+ io:format("Head ~p ~p~n",[hd(Refval), hd(Testval)]),
+ exit(wrong_value)
+ end
end.
-gen_jump_0(Algo) ->
- Seed = case Algo of
- exs64 -> %% Test exception of not_implemented notice
- try
- _ = rand:seed(exs64),
- rand:jump()
- catch
- error:not_implemented -> not_implemented
- end;
- _ when Algo =:= exsplus; Algo =:= exsp; Algo =:= exrop ->
- %% Printed with orig 'C' code and this seed
- rand:seed({Algo, [12345678|12345678]});
- _ when Algo =:= exs1024; Algo =:= exs1024s ->
- %% Printed with orig 'C' code and this seed
- rand:seed({Algo, {lists:duplicate(16, 12345678), []}});
- _ -> % unimplemented
- not_implemented
- end,
- case Seed of
- not_implemented -> [not_implemented];
- _ ->
- Max = range(Seed),
- gen_jump_0(?LOOP_JUMP, Max, [])
+gen_jump_p1(Algo) ->
+ case Algo of
+ exs64 -> %% Test exception of not_implemented notice
+ try
+ _ = rand:seed(exs64),
+ rand:jump()
+ catch
+ error:not_implemented -> [error_not_implemented]
+ end;
+ _ when Algo =:= exsplus; Algo =:= exsp; Algo =:= exrop; Algo =:= exsss ->
+ %% Printed with orig 'C' code and this seed
+ gen_jump_p2(
+ rand:seed(Algo, [12345678,12345678]));
+ _ when Algo =:= exs1024; Algo =:= exs1024s; Algo =:= exro928ss ->
+ %% Printed with orig 'C' code and this seed
+ gen_jump_p2(
+ rand:seed(Algo, lists:duplicate(16, 12345678)))
end.
-gen_jump_0(N, Max, Acc) when N > 0 ->
+gen_jump_p2(Seed) ->
+ Max = range(Seed),
+ gen_jump_p3(?LOOP_JUMP, Max, []).
+
+gen_jump_p3(N, Max, Acc) when N > 0 ->
_ = rand:uniform(Max),
_ = rand:jump(),
Random = rand:uniform(Max),
case N rem (?LOOP_JUMP div 100) of
- 0 -> gen_jump_0(N-1, Max, [Random|Acc]);
- _ -> gen_jump_0(N-1, Max, Acc)
+ 0 -> gen_jump_p3(N-1, Max, [Random|Acc]);
+ _ -> gen_jump_p3(N-1, Max, Acc)
end;
-gen_jump_0(_, _, Acc) -> lists:reverse(Acc).
+gen_jump_p3(_, _, Acc) -> lists:reverse(Acc).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+short_jump(Config) when is_list(Config) ->
+ Seed = erlang:system_time(),
+ short_jump(
+ rand:seed_s(exro928ss, Seed),
+ fun ({Alg,AlgState}) ->
+ {Alg,rand:exro928_jump_2pow20(AlgState)}
+ end),
+ short_jump(
+ crypto:rand_seed_alg_s(crypto_aes, integer_to_list(Seed)),
+ fun ({Alg,AlgState}) ->
+ {Alg,crypto:rand_plugin_aes_jump_2pow20(AlgState)}
+ end),
+ ok.
+
+short_jump({#{bits := Bits},_} = State_0, Jump2Pow20) ->
+ Range = 1 bsl Bits,
+ State_1 = repeat(7, Range, State_0),
+ %%
+ State_2a = repeat(1 bsl 20, Range, State_1),
+ State_2b = Jump2Pow20(State_1),
+ check(17, Range, State_2a, State_2b),
+ %%
+ {_,State_3a} = rand:uniform_s(Range, State_2a),
+ State_4a = Jump2Pow20(State_3a),
+ State_4b = repeat((1 bsl 20) + 1, Range, State_2b),
+ check(17, Range, State_4a, State_4b).
+
+repeat(0, _Range, State) ->
+ State;
+repeat(N, Range, State) ->
+ {_, NewState} = rand:uniform_s(Range, State),
+ repeat(N - 1, Range, NewState).
+
+check(0, _Range, _StateA, _StateB) ->
+ ok;
+check(N, Range, StateA, StateB) ->
+ {V,NewStateA} = rand:uniform_s(Range, StateA),
+ case rand:uniform_s(Range, StateB) of
+ {V,NewStateB} ->
+ check(N - 1, Range, NewStateA, NewStateB);
+ {Wrong,_} ->
+ ct:fail({Wrong,neq,V,for,N})
+ end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Data
@@ -893,6 +1377,34 @@ reference_val(exsplus) ->
16#3dd493b8012970f,16#be13bed1e00e5c,16#ceef033b74ae10,16#3da38c6a50abe03,
16#15cbd1a421c7a8c,16#22794e3ec6ef3b1,16#26154d26e7ea99f,16#3a66681359a6ab6];
+reference_val(exsss) ->
+ [16#108e8d5b01,16#33b72092117209a,16#224d4d2961a2d0a,16#2c4c81aac3da48d,
+ 16#2f4bc39bfc36f3a,16#41826d4c4d243a,16#19871b8bb4e23ee,16#3e2112cdf9384b1,
+ 16#69801943bf91ab,16#2de1a603c31ec45,16#a90ca1991b831e,16#51ca29571a69a7,
+ 16#93ce3e511906cf,16#93ebc5768aef75,16#2412f284b902ae7,16#1ac10e758410c52,
+ 16#3f32494560368f6,16#39a5e82dcf0de95,16#3f4b14d59cc6a21,16#3174668db0b36ae,
+ 16#1449812fb8bd54e,16#eaca1f8ece51e1,16#2564b2545fd23c1,16#3cf3a2d2217e0d7,
+ 16#226f4164ba1d054,16#10dac9ae207ceef,16#17f2c4b2d40fcb9,16#1c1b282d386fdcb,
+ 16#a264f450ba2912,16#2a0a1dd67e52666,16#2be84eb835cb1e1,16#2a1cd9aa16ccc37,
+ 16#7dd5e8c2b3f490,16#254a3db4976c05b,16#2a0a67971ec1e63,16#13a0cbf7c0eed8a,
+ 16#3192d7edc0a20bc,16#2705ad756292e84,16#3ec429a18119c81,16#25944b38baa975b,
+ 16#291dcc43e3256f4,16#30d10b759237db,16#c1522a652058a,16#8ef1e9378381e6,
+ 16#1f442f33c2439f4,16#186087710a73818,16#12887f94b2b8387,16#3e42e8b1f3c9b4b,
+ 16#e462859d55f9d8,16#2356ae85be908de,16#15e96a927b3bc52,16#35c6dc52511ce46,
+ 16#7bc0624ce66e01,16#33ab7d95b738322,16#26f01effc182aa0,16#1b66ae7eaafea88,
+ 16#278f3dc14943b90,16#22178bc8d8faf28,16#396c37d53c11985,16#5e0d79d0b10f18,
+ 16#1be3de3b5675ec,16#d4db298f1f4b50,16#2da6cb99bb5c7b1,16#130b2dc17d03be8,
+ 16#f1847e7e059e9f,16#2da6591788326e7,16#222e4a18c24211c,16#949213ca49baab,
+ 16#b5129fec56f6a2,16#30f25f1e926f43e,16#1ddd8d04445fb4d,16#15995b542514150,
+ 16#1595fe879296296,16#e2f237a488453b,16#23e5cd2d6047890,16#3a5dc88fc954666,
+ 16#89bca9969b103,16#5e6893cd35dc63,16#1fed534feeeef5a,16#26f40e2147ee558,
+ 16#30c131a00625837,16#2618a7e617422e9,16#23630b297e45e7,16#1143b17502f3219,
+ 16#15607dac41168da,16#2886bdc314b3fb8,16#465d1cc1536546,16#30b09123e3a02e4,
+ 16#245a375f810be52,16#6a1b0792376a03,16#221425f59f2470f,16#867ce16dfac81c,
+ 16#9c62d95fae9b58,16#380381db1394426,16#34908dedc01c324,16#1f0ff517089b561,
+ 16#1571366dd873d32,16#3ee353dc56e192,16#15a1dee8d889b11,16#41036ad76d9888
+ ];
+
reference_val(exsp) ->
reference_val(exsplus);
reference_val(exs1024s) ->
@@ -959,7 +1471,50 @@ reference_val(exrop) ->
250789092615679985,78848633178610658,72059442721196128,
98223942961505519,191144652663779840,
102425686803727694,89058927716079076,80721467542933080,
- 8462479817391645,2774921106204163].
+ 8462479817391645,2774921106204163];
+
+reference_val(exro928ss) ->
+%% Same as for exrop, but this state init:
+%% for (n = 0; n < 16; n++) {
+%% s[n] = 12345678;
+ [16#000000108e8d5b01,16#03604028f2769dff,16#007f92f60bc7170c,
+ 16#035ea81a9898a5e2,16#0104c90c5a0c8178,16#0313514025cca717,
+ 16#03c5506b2a2e98cf,16#0098a5405961552e,16#004ad29eabb785a0,
+ 16#033ea8ec4efb8058,16#00b21545e62bef1c,16#0333fc5320703482,
+ 16#02c3c650e51a8d47,16#03a3b7fc848c9cda,16#03775adea6cddff5,
+ 16#01ae5499c9049973,16#03d3c90e5504e16b,16#0383cd6b6cb852e6,
+ 16#009c8d0996ef543a,16#0059cf671371af60,16#03dfd68ed980b719,
+ 16#0290f2a0acf2c5b0,16#029061df18d63b55,16#02e702ea4b45137b,
+ 16#029a0ccca604d848,16#01664c7cd31f0fa6,16#00dced83e60ccddc,
+ 16#008764d2c9a05f3e,16#02b9ca5f6a80c4ba,16#02daf93d2c566750,
+ 16#0147d326ead18ace,16#014b452efc19297f,16#0242d3f7a7237eca,
+ 16#0141bb68c2abce39,16#02d798e1230baf45,16#0216bf8f25c1ec2d,
+ 16#003a43ea733f1e1f,16#036c75390db736f3,16#028cca5f5f48c6f9,
+ 16#0186e4a17174d6cf,16#02152679dfa4c25c,16#01429b9f15e3b9d6,
+ 16#0134a61411d22bb0,16#01593f7d970d1c94,16#0205a7d8a305490f,
+ 16#01dd092272595a9c,16#0028c95208aad2d4,16#016347c25cc24162,
+ 16#025306acfb891309,16#0207a07e2bebef2f,16#024ee78d86ff5288,
+ 16#030b53192db97613,16#03f765cb9e98e611,16#025ec35a1e237377,
+ 16#03d81fd73102ef6f,16#0242dc8fea9a68b2,16#00abb876c1d4ea1b,
+ 16#00871ffd2b7e45fb,16#03593ff73c9be08d,16#00b96b2b8aca3688,
+ 16#0174aba957b7cf7b,16#012b7a5d4cf4a5b7,16#032a5260f2123db8,
+ 16#00f9374d88ee0080,16#030df39bec2ad657,16#00dce0cb81d006c4,
+ 16#038213b806303c76,16#03940aafdbfabf84,16#0398dbb26aeba037,
+ 16#01eb28d61951587f,16#00fed3d2aacfeef4,16#03499587547d6e40,
+ 16#01b192fe6e979e3c,16#00e974bf5f0a26d0,16#012ed94f76459c83,
+ 16#02d76859e7a82587,16#00d1d2c7b791f51b,16#03988058017a031b,
+ 16#00bbcf4b59d8e86d,16#015ed8b73a1b767c,16#0277283ea6a5ee74,
+ 16#002211460dd6d422,16#001ad62761ee9fbd,16#037311b44518b067,
+ 16#02b5ed61bf70904e,16#011862a05c1929fa,16#014be68683c3bab4,
+ 16#025c29aa5c508b07,16#00895c6106f97378,16#026ce91a3d671c7f,
+ 16#02591f4c74784293,16#02f0ed2a70bc1853,16#00a2762ff614bfbc,
+ 16#008f4e354f0c20d4,16#038b66fb587ed430,16#00636296e188de89,
+ 16#0278fadd143e74f5,16#029697ccf1b3a4c2,16#011eccb273404458,
+ 16#03f204064a9fe0c0];
+
+reference_val(_) ->
+ not_implemented.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -990,6 +1545,33 @@ reference_jump_val(exsplus) ->
12504080415362731, 45083100453836317, 270968267812126657, 93505647407734103,
252852934678537969, 258758309277167202, 74250882143432077, 141629095984552833];
+reference_jump_val(exsss) ->
+ [16#304ae783d40db2b,16#1dfb196b3a5600a,16#2a24116effc6a0d,16#1f138d68c56725,
+ 16#9360a445e2f989,16#32ed8080390e242,16#294ca85a270cff6,16#1418e6296a88bf,
+ 16#114fae3dc578ba7,16#479c42c760eb72,16#334a40655df22d6,16#e7a85dd4d37d72,
+ 16#181db16c8925c77,16#1b8a5a8afd16cbd,16#329107bf9777a39,16#2fc915c08535e42,
+ 16#16696d142c6078,16#2e2a2601c919448,16#2246150d1000568,16#26109007cb3dd44,
+ 16#3761360723e3175,16#169abd352db74de,16#1c97d520983684f,16#12455f0adee8c66,
+ 16#46719cff00622d,16#1fc92792ed4e437,16#18e2edae21affb5,16#3a67fa9e3e7d46e,
+ 16#1313fdc2728aa74,16#1c1a2b577581db8,16#db49357ea196b1,16#10e219a21d93fc7,
+ 16#3c43abede083666,16#3eef5055a58bbf9,16#1975056f95d90e3,16#3916c133ab16d87,
+ 16#2bc0bea891c26f1,16#391e4b369fc6b36,16#183f83155a359f6,16#1d9f137e9d2e488,
+ 16#ef084de5f4cd3c,16#36a9cf7e29e55d3,16#19eca704e0409a7,16#1bdb99902896c69,
+ 16#21777e2ad128203,16#5d0369ec0563e4,16#36db40b863bd74a,16#33feb71b7515159,
+ 16#208d923ce26f257,16#3841b32891c082d,16#2748f224c2ba226,16#2fcd93b2daf79bb,
+ 16#2c8e6cacad58ec4,16#39850131a1a85f,16#134648d6eea624d,16#2e102e197d5725c,
+ 16#12ac280fa744758,16#1c18266c7442d16,16#22b5f91b15fe17e,16#316740ca870f7c8,
+ 16#720ed4836c426,16#1aac0f738d04f8c,16#34fcd2a647b462c,16#3d430ac755114a3,
+ 16#3692e3670fdf2a,16#265279ab0fc0a15,16#10bd883dee80945,16#10e7843413175e4,
+ 16#b291deba08cee2,16#3915a8234caf11,16#34b911b96707dbd,16#ae63fcda15fde6,
+ 16#b13b9091e82e41,16#29de1b6d70dc04f,16#23fbcbc409617e8,16#1389a0738061066,
+ 16#360f39af790f5d1,16#f436da2a7d12f5,16#2d06ba8da21e08,16#3601a6492b887d,
+ 16#2b2590b8c6cc186,16#f8d613b6904464,16#e5456786e46b78,16#201b8b1f96ed80c,
+ 16#1b75b86d9b843f2,16#2e8bfaa7243a630,16#125ff068a78c3b4,16#3875a28c48bd26e,
+ 16#f09a06941fc9d7,16#107c4de8ca77744,16#357c34144bb9ed6,16#3ccc55d3ebb3378,
+ 16#28db7cea7d3fdee,16#3197fd0b49f6370,16#11af6fedb708ea6,16#2bde0382e37469e,
+ 16#10666171abddb3f,16#1a8876c1f4e78a8,16#169c0efd4422043,16#1501c49abf0440f];
+
reference_jump_val(exs1024) ->
[2655961906500790629, 17003395417078685063, 10466831598958356428, 7603399148503548021,
1650550950190587188, 12294992315080723704, 15743995773860389219, 5492181000145247327,
@@ -1021,7 +1603,7 @@ reference_jump_val(exsp) ->
reference_jump_val(exsplus);
reference_jump_val(exs1024s) ->
reference_jump_val(exs1024);
-reference_jump_val(exs64) -> [not_implemented];
+reference_jump_val(exs64) -> [error_not_implemented];
reference_jump_val(exrop) ->
%% #include <stdint.h>
%% #include <stdio.h>
@@ -1086,7 +1668,50 @@ reference_jump_val(exrop) ->
250227633882474729,171181147785250210,55437891969696407,
241227318715885854,77323084015890802,
1663590009695191,234064400749487599,222983191707424780,
- 254956809144783896,203898972156838252].
+ 254956809144783896,203898972156838252];
+
+reference_jump_val(exro928ss) ->
+%% Same as for exrop, but this state init:
+%% for (n = 0; n < 16; n++) {
+%% s[n] = 12345678;
+ [16#031ee449e53b6689,16#001afeee12813137,16#005e2172711df36b,
+ 16#02850aea3a595d36,16#0029705187e891c7,16#001794badd489667,
+ 16#00ab621be15be56c,16#024b663a6924786b,16#03cab70b8ab854bf,
+ 16#01daa37601285320,16#02db955a53c40e89,16#01fbef51d5c65891,
+ 16#02fecf4116ed5f77,16#0349c2057246ac5d,16#01217f257c4fa148,
+ 16#0367ee84d020697d,16#01d5cf647fe23335,16#020941838adfb750,
+ 16#02c2da26b1d7b3e5,16#00d1583d34cea6c0,16#038be9cb5b527f50,
+ 16#00bfa93c1d7f4864,16#03778912a4f56b14,16#037fcabc483fa5c5,
+ 16#00a3c9de6aaf5fc7,16#03600b883b2f2b42,16#03797a99ffddfdfb,
+ 16#0189fead429945b7,16#0103ac90cd912508,16#03e3d872fd950d64,
+ 16#0214fc3e77dc2f02,16#02a084f4f0e580ca,16#035d2fe72266a7f3,
+ 16#02887c49ae7e41a4,16#0011dc026af83c51,16#02d28bfd32c2c517,
+ 16#022e4165c33ad4f3,16#01f053cf0687b052,16#035315e6e53c8918,
+ 16#01255312da07b572,16#0237f1da11ec9221,16#02faf2e282fb1fb1,
+ 16#0227423ec1787ebc,16#011fa5eb1505571c,16#0275ff9eaaa1abdd,
+ 16#03e2d032c3981cb4,16#0181bb32d51d3072,16#01b1d3939b9f16ec,
+ 16#0259f09f55d1112f,16#0396464a2767e428,16#039777c0368bdb9e,
+ 16#0320925f35f36c5f,16#02a35289e0af1248,16#02e80bd4bc72254b,
+ 16#00a8b11af1674d68,16#027735036100a69e,16#03c8c268ded7f254,
+ 16#03de80aa57c65217,16#00f2247754d24000,16#005582a42b467f89,
+ 16#0031906569729477,16#00fd523f2ca4fefe,16#00ad223113d1e336,
+ 16#0238ddf026cbfca9,16#028b98211cfed876,16#0354353ebcc0de9a,
+ 16#009ee370c1e154f4,16#033131af3b8a7f88,16#032291baa45801e3,
+ 16#00941fc2b45eb217,16#035d6a61fa101647,16#03fdb51f736f1bbc,
+ 16#0232f7b98539faa0,16#0311b35319e3a61e,16#0048356b17860eb5,
+ 16#01a205b2554ce71e,16#03f873ea136e29d6,16#003c67d5c3df5ffd,
+ 16#00cd19e7a8641648,16#0149a8c54e4ba45e,16#0329498d134d2f6a,
+ 16#03b69421ae65ee2b,16#01a8d20b59447429,16#006b2292571032a2,
+ 16#00c193b17da22ba5,16#01faa7ab62181249,16#00acd401cd596a00,
+ 16#005b5086c3531402,16#0259113d5d3d058d,16#00bef3f3ce4a43b2,
+ 16#014837a4070b893c,16#00460a26ac2eeec1,16#026219a8b8c63d7e,
+ 16#03c7b8ed032cf5a6,16#004da912a1fff131,16#0297de3716215741,
+ 16#0079fb9b4c715466,16#00a73bad4ae5a356,16#0072e606c0d4ab86,
+ 16#02374382d5f9bd2e];
+
+reference_jump_val(_) ->
+ not_implemented.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/stdlib/test/rand_Xoroshiro928ss_dev.txt b/lib/stdlib/test/rand_Xoroshiro928ss_dev.txt
new file mode 100644
index 0000000000..150f37fcfa
--- /dev/null
+++ b/lib/stdlib/test/rand_Xoroshiro928ss_dev.txt
@@ -0,0 +1,343 @@
+%CopyrightBegin%
+
+Copyright Ericsson AB 2015-2017. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+%CopyrightEnd%
+
+
+Memorable facts from designing the Xoroshiro928** generator
+===========================================================
+AKA: exro928ss in the rand module
+
+Author: Raimo Niskanen, for the Erlang/OTP team @ Ericsson.
+
+Reference URL: http://vigna.di.unimi.it/ftp/papers/ScrambledLinear.pdf
+i.e the Xoroshiro1024 generator with ** scrambler:
+
+ int p;
+ uint64_t s[16];
+
+ const int q = p;
+ const uint64_t s0 = s[p = (p + 1) & 15];
+
+ uint64_t s15 = s[q];
+
+ const uint64_t result_starstar = rotl(s0 * S, R) * T;
+
+ s15 ^= s0;
+ s[q] = rotl(s0, A) ^ s15 ^ (s15 << B);
+ s[p] = rotl(s15, C);
+
+Where {S, R, T} = {5, 7, 9} as recommended in the paper.
+
+We want to scale down to 58 bit words (16 of them)
+so we get a generator with period 2^928 - 1.
+
+{A, B, C} were deduced as follows
+---------------------------------
+
+First, to find which triplets that give a full period generator
+one have to factor 2^928 - 1.
+
+https://www.alpertron.com.ar/ECM.HTM actually could do that
+and gave the result:
+
+ Value
+ 2^928 - 1
+
+ 2269 007733 883335 972287 082669 296112 915239 349672 942191 252221 331572
+ 442536 403137 824056 312817 862695 551072 066953 619064 625508 194663
+ 368599 769448 406663 254670 871573 830845 597595 897613 333042 429214
+ 224697 474472 410882 236254 024057 110212 260250 671521 235807 709272
+ 244389 361641 091086 035023 229622 419455 (280 digits) = 3 × 5 × 17 × 59 ×
+ 233 × 257 × 929 × 1103 × 2089 × 5569 × 8353 × 59393 × 65537 × 3 033169 ×
+ 39 594977 × 107 367629 × 536 903681 × 748 264961 × 2245 984577 × 239
+ 686663 718401 × 15 929619 591127 520827 829953 × 82280 195167 144119
+ 832390 568177 × 6033 312171 721035 031651 315652 130497 (34 digits) × 18
+ 774318 450142 955120 650303 957350 521748 903233 (44 digits) × 15 694604
+ 006012 505869 851221 169365 594050 637743 819041 (50 digits)
+
+Sebastiano Vigna from that calculated all full period triplets, at the
+end of this document, and the ones with the highest degree were:
+
+ 23-25-12 411
+ 36-2-35 411
+ 55-5-54 411
+ 14-19-11 415
+ 34-37-5 415
+ 37-3-56 415
+ 55-11-54 417
+ 30-3-41 419
+ 11-45-50 423
+ 50-19-47 423
+ 52-27-13 427
+ 54-9-25 433
+ 56-43-35 433
+ 44-9-45 441
+
+All these candidates were tested with TestU01-1.2.3:
+
+ http://simul.iro.umontreal.ca/testu01/tu01.html
+
+A plugin was created with parameters for {A, B, C} and, since
+TestU01 is a 32-bit test tool, with parameters to reverse
+the generated bits or not, and to take the 32 highest or lowest
+bits from the reversed or non-reversed 58 bit output.
+
+The generators were seeded with a SplitMix64 generator like the
+one used for seeding this generator in the rand module,
+taking the 58 lowest bits and wasting all zero values.
+
+3 runs were made with all candidates and all four bit selection variants.
+For these runs the seeder was initialized with 12345678, 876543212345678
+and 1234567890.
+
+After all these runs the candidate with the highest degree: 44-9-45
+had not gotten any suspicious p-value at all. All the other
+got p-values around 5.0e-4 worst 9.8e-6 suggesting only random
+failures, so they would probably have worked about as well.
+
+Finally 44-9-45 was run through PractRand-0.93:
+
+ http://pracrand.sourceforge.net/
+
+Again, all 4 bit selection variants of 32 bits were run.
+Random failures with p-values around e-3..e-4 for the "smaller"
+tests, but for 8, 16 and 32 TB tests no anomalies were found
+(with the internal seeder masked to 58 bits):
+
+ Xoroshiro928High seed: 0x3178ec5d
+ Xoroshiro928Low seed: 0xa9a04fb9
+ Xoroshiro928ReverseHigh seed: 0xfa0bdbab
+ Xoroshiro928ReverseLow seed: 0xada51705
+
+
+Then, S. Vigna calculated the 2^512 jump coefficient as well
+as a 2^20 jump coefficient (for testing purposes) for 44-9-45.
+
+2^512:
+ { 0x44085302f77130ca, 0xba05381fdfd14902, 0x10a1de1d7d6813d2,
+ 0xb83fe51a1eb3be19, 0xa81b0090567fd9f0, 0x5ac26d5d20f9b49f,
+ 0x4ddd98ee4be41e01, 0x0657e19f00d4b358, 0xf02f778573cf0f0a,
+ 0xb45a3a8a3cef3cc0, 0x6e62a33cc2323831, 0xbcb3b7c4cc049c53,
+ 0x83f240c6007e76ce, 0xe19f5fc1a1504acd, 0x00000000b10773cb }
+
+2^20:
+ { 0xbdb966a3daf905e6, 0x644807a56270cf78, 0xda90f4a806c17e9e,
+ 0x4a426866bfad3c77, 0xaf699c306d8e7566, 0x8ebc73c700b8b091,
+ 0xc081a7bf148531fb, 0xdc4d3af15f8a4dfd, 0x90627c014098f4b6,
+ 0x06df2eb1feaf0fb6, 0x5bdeb1a5a90f2e6b, 0xa480c5878c3549bd,
+ 0xff45ef33c82f3d48, 0xa30bebc15fefcc78, 0x00000000cb3d181c }
+
+Standard jump function pseudocode:
+
+ Jump constant j = 0xb10773cb...44085302f77130ca
+ Generator state: s
+ New generator state: t = 0
+ foreach bit in j, low to high:
+ if the bit is one:
+ t ^= s
+ next s
+ s = t
+
+
+The complete list of full period constants
+------------------------------------------
+
+29-48-54 27 x^928 + x^874 + x^870 + x^840 + x^814 + x^784 + x^759 + x^750 + x^724 + x^720 + x^634 + x^630 + x^600 + x^574 + x^544 + x^519 + x^510 + x^484 + x^480 + x^390 + x^360 + x^270 + x^240 + x^150 + x^120 + x^30 + 1
+
+29-18-56 65 x^928 + x^870 + x^850 + x^840 + x^832 + x^821 + x^802 + x^791 + x^761 + x^750 + x^734 + x^731 + x^720 + x^712 + x^701 + x^686 + x^674 + x^671 + x^663 + x^641 + x^630 + x^611 + x^610 + x^603 + x^600 + x^596 + x^577 + x^566 + x^547 + x^524 + x^517 + x^510 + x^487 + x^480 + x^476 + x^464 + x^457 + x^446 + x^427 + x^423 + x^397 + x^390 + x^367 + x^363 + x^360 + x^356 + x^352 + x^341 + x^326 + x^322 + x^311 + x^281 + x^270 + x^251 + x^240 + x^236 + x^232 + x^221 + x^191 + x^161 + x^150 + x^131 + x^120 + x^30 + 1
+
+29-32-36 81 x^928 + x^874 + x^870 + x^840 + x^820 + x^819 + x^794 + x^790 + x^770 + x^765 + x^764 + x^760 + x^754 + x^750 + x^740 + x^739 + x^735 + x^734 + x^730 + x^709 + x^704 + x^674 + x^670 + x^665 + x^660 + x^650 + x^649 + x^635 + x^634 + x^619 + x^614 + x^605 + x^595 + x^585 + x^584 + x^579 + x^564 + x^555 + x^545 + x^540 + x^524 + x^515 + x^514 + x^495 + x^490 + x^485 + x^460 + x^455 + x^435 + x^425 + x^400 + x^395 + x^375 + x^370 + x^365 + x^340 + x^315 + x^310 + x^305 + x^300 + x^290 + x^285 + x^275 + x^260 + x^250 + x^245 + x^240 + x^215 + x^190 + x^180 + x^170 + x^150 + x^130 + x^120 + x^115 + x^105 + x^100 + x^75 + x^40 + x^30 + 1
+
+39-10-20 105 x^928 + x^898 + x^870 + x^841 + x^840 + x^808 + x^783 + x^782 + x^781 + x^780 + x^778 + x^754 + x^752 + x^724 + x^721 + x^720 + x^696 + x^692 + x^688 + x^667 + x^666 + x^661 + x^660 + x^658 + x^638 + x^636 + x^632 + x^609 + x^607 + x^606 + x^605 + x^604 + x^601 + x^600 + x^580 + x^578 + x^576 + x^572 + x^568 + x^549 + x^548 + x^541 + x^540 + x^538 + x^516 + x^512 + x^489 + x^485 + x^484 + x^481 + x^480 + x^456 + x^452 + x^448 + x^429 + x^428 + x^421 + x^420 + x^418 + x^400 + x^398 + x^396 + x^392 + x^368 + x^365 + x^364 + x^336 + x^328 + x^319 + x^318 + x^315 + x^314 + x^298 + x^286 + x^278 + x^276 + x^274 + x^255 + x^254 + x^249 + x^245 + x^228 + x^226 + x^220 + x^208 + x^199 + x^198 + x^189 + x^188 + x^178 + x^168 + x^166 + x^160 + x^129 + x^128 + x^108 + x^100 + x^88 + x^79 + x^78 + x^69 + x^68 + x^58 + x^40 + 1
+
+4-4-9 149 x^928 + x^898 + x^886 + x^870 + x^856 + x^826 + x^823 + x^808 + x^796 + x^793 + x^784 + x^778 + x^772 + x^766 + x^760 + x^754 + x^751 + x^742 + x^736 + x^734 + x^724 + x^713 + x^709 + x^706 + x^703 + x^694 + x^691 + x^688 + x^676 + x^674 + x^673 + x^664 + x^662 + x^658 + x^653 + x^641 + x^640 + x^634 + x^632 + x^631 + x^620 + x^614 + x^611 + x^608 + x^604 + x^602 + x^599 + x^590 + x^583 + x^581 + x^578 + x^574 + x^572 + x^571 + x^569 + x^568 + x^561 + x^554 + x^553 + x^551 + x^544 + x^542 + x^540 + x^538 + x^532 + x^531 + x^518 + x^514 + x^512 + x^502 + x^498 + x^489 + x^488 + x^484 + x^482 + x^480 + x^479 + x^468 + x^463 + x^456 + x^454 + x^452 + x^449 + x^448 + x^438 + x^433 + x^429 + x^424 + x^422 + x^420 + x^418 + x^408 + x^406 + x^401 + x^396 + x^394 + x^392 + x^380 + x^378 + x^376 + x^371 + x^367 + x^364 + x^362 + x^360 + x^350 + x^348 + x^346 + x^341 + x^334 + x^332 + x^328 + x^318 + x^311 + x^307 + x^304 + x^302 + x^300 + x^298 + x^288 + x^274 + x^272 + x^254 + x^249 + x^242 + x^240 + x^233 + x^212 + x^208 + x^189 + x^180 + x^178 + x^166 + x^152 + x^143 + x^136 + x^127 + x^122 + x^120 + x^113 + x^106 + x^88 + x^83 + x^81 + x^67 + x^58 + x^51 + x^14 + 1
+
+44-44-45 157 x^928 + x^898 + x^870 + x^850 + x^830 + x^820 + x^808 + x^800 + x^790 + x^782 + x^778 + x^777 + x^760 + x^757 + x^752 + x^747 + x^742 + x^727 + x^702 + x^694 + x^689 + x^688 + x^679 + x^674 + x^659 + x^658 + x^657 + x^644 + x^642 + x^637 + x^634 + x^627 + x^619 + x^612 + x^607 + x^606 + x^601 + x^596 + x^594 + x^591 + x^590 + x^584 + x^576 + x^568 + x^566 + x^561 + x^560 + x^556 + x^554 + x^546 + x^541 + x^539 + x^538 + x^518 + x^516 + x^511 + x^509 + x^503 + x^502 + x^499 + x^496 + x^488 + x^476 + x^471 + x^468 + x^466 + x^464 + x^448 + x^446 + x^441 + x^436 + x^421 + x^420 + x^415 + x^411 + x^408 + x^404 + x^400 + x^388 + x^383 + x^381 + x^379 + x^376 + x^363 + x^358 + x^356 + x^354 + x^346 + x^344 + x^340 + x^333 + x^330 + x^328 + x^325 + x^316 + x^312 + x^307 + x^305 + x^302 + x^284 + x^282 + x^277 + x^270 + x^268 + x^267 + x^256 + x^252 + x^249 + x^245 + x^244 + x^239 + x^238 + x^236 + x^231 + x^228 + x^226 + x^224 + x^222 + x^215 + x^208 + x^207 + x^205 + x^203 + x^201 + x^199 + x^196 + x^194 + x^192 + x^189 + x^185 + x^184 + x^182 + x^180 + x^175 + x^171 + x^168 + x^166 + x^162 + x^161 + x^155 + x^152 + x^150 + x^141 + x^134 + x^132 + x^131 + x^127 + x^122 + x^111 + x^104 + x^92 + x^90 + x^83 + x^81 + x^58 + x^37 + 1
+
+40-40-7 167 x^928 + x^898 + x^870 + x^866 + x^838 + x^836 + x^807 + x^806 + x^804 + x^778 + x^777 + x^774 + x^745 + x^744 + x^742 + x^718 + x^714 + x^713 + x^712 + x^687 + x^658 + x^657 + x^656 + x^655 + x^654 + x^626 + x^620 + x^619 + x^598 + x^596 + x^592 + x^591 + x^589 + x^566 + x^564 + x^563 + x^562 + x^560 + x^558 + x^538 + x^534 + x^530 + x^529 + x^504 + x^503 + x^502 + x^500 + x^499 + x^498 + x^496 + x^478 + x^474 + x^470 + x^469 + x^443 + x^442 + x^441 + x^439 + x^438 + x^436 + x^434 + x^432 + x^418 + x^416 + x^414 + x^410 + x^409 + x^407 + x^406 + x^405 + x^402 + x^386 + x^383 + x^380 + x^374 + x^373 + x^372 + x^370 + x^356 + x^350 + x^349 + x^348 + x^347 + x^346 + x^345 + x^340 + x^328 + x^326 + x^324 + x^323 + x^321 + x^316 + x^314 + x^308 + x^298 + x^296 + x^294 + x^289 + x^285 + x^283 + x^282 + x^281 + x^280 + x^278 + x^263 + x^262 + x^259 + x^257 + x^255 + x^251 + x^249 + x^248 + x^246 + x^233 + x^232 + x^229 + x^220 + x^218 + x^217 + x^216 + x^208 + x^202 + x^201 + x^199 + x^195 + x^190 + x^188 + x^187 + x^186 + x^178 + x^172 + x^169 + x^167 + x^162 + x^161 + x^159 + x^158 + x^157 + x^146 + x^142 + x^139 + x^135 + x^125 + x^123 + x^116 + x^112 + x^107 + x^105 + x^94 + x^93 + x^88 + x^86 + x^84 + x^82 + x^75 + x^73 + x^69 + x^64 + x^58 + x^56 + x^54 + x^52 + x^43 + x^41 + x^39 + x^32 + 1
+
+47-47-18 217 x^928 + x^898 + x^871 + x^870 + x^843 + x^842 + x^841 + x^813 + x^812 + x^811 + x^808 + x^787 + x^786 + x^785 + x^783 + x^781 + x^778 + x^759 + x^757 + x^754 + x^753 + x^751 + x^729 + x^727 + x^726 + x^723 + x^721 + x^701 + x^700 + x^699 + x^697 + x^693 + x^691 + x^688 + x^673 + x^672 + x^670 + x^667 + x^663 + x^661 + x^658 + x^647 + x^644 + x^641 + x^637 + x^633 + x^631 + x^618 + x^617 + x^614 + x^613 + x^612 + x^611 + x^610 + x^607 + x^603 + x^601 + x^586 + x^585 + x^582 + x^581 + x^580 + x^577 + x^573 + x^571 + x^568 + x^562 + x^560 + x^556 + x^555 + x^554 + x^553 + x^551 + x^547 + x^543 + x^541 + x^538 + x^532 + x^530 + x^528 + x^524 + x^522 + x^521 + x^517 + x^513 + x^511 + x^506 + x^504 + x^502 + x^500 + x^497 + x^495 + x^491 + x^487 + x^483 + x^481 + x^478 + x^474 + x^472 + x^467 + x^466 + x^465 + x^461 + x^457 + x^453 + x^451 + x^444 + x^438 + x^437 + x^436 + x^435 + x^431 + x^427 + x^423 + x^412 + x^408 + x^407 + x^405 + x^401 + x^397 + x^390 + x^384 + x^377 + x^375 + x^371 + x^367 + x^366 + x^365 + x^363 + x^362 + x^360 + x^358 + x^356 + x^352 + x^350 + x^347 + x^345 + x^341 + x^337 + x^336 + x^334 + x^332 + x^324 + x^317 + x^315 + x^311 + x^307 + x^306 + x^305 + x^304 + x^302 + x^300 + x^298 + x^296 + x^287 + x^285 + x^281 + x^279 + x^277 + x^276 + x^274 + x^268 + x^266 + x^257 + x^255 + x^247 + x^244 + x^242 + x^240 + x^238 + x^234 + x^227 + x^221 + x^219 + x^216 + x^214 + x^206 + x^197 + x^195 + x^193 + x^182 + x^176 + x^161 + x^156 + x^152 + x^146 + x^139 + x^133 + x^116 + x^111 + x^109 + x^107 + x^96 + x^94 + x^92 + x^90 + x^88 + x^85 + x^81 + x^79 + x^77 + x^73 + x^66 + x^64 + x^62 + x^60 + x^53 + x^51 + x^47 + x^45 + x^36 + x^34 + x^32 + x^19 + x^17 + x^15 + 1
+
+31-52-54 249 x^928 + x^898 + x^872 + x^870 + x^842 + x^841 + x^838 + x^836 + x^812 + x^810 + x^782 + x^781 + x^779 + x^778 + x^774 + x^753 + x^752 + x^750 + x^748 + x^723 + x^722 + x^721 + x^719 + x^717 + x^714 + x^712 + x^694 + x^690 + x^689 + x^688 + x^686 + x^684 + x^664 + x^663 + x^662 + x^661 + x^660 + x^658 + x^657 + x^656 + x^655 + x^654 + x^653 + x^652 + x^650 + x^634 + x^633 + x^631 + x^630 + x^629 + x^628 + x^622 + x^604 + x^599 + x^597 + x^596 + x^593 + x^592 + x^590 + x^588 + x^570 + x^567 + x^566 + x^562 + x^560 + x^536 + x^534 + x^533 + x^531 + x^530 + x^526 + x^513 + x^512 + x^510 + x^509 + x^508 + x^507 + x^506 + x^505 + x^504 + x^502 + x^498 + x^483 + x^482 + x^481 + x^479 + x^478 + x^476 + x^466 + x^464 + x^454 + x^445 + x^438 + x^424 + x^423 + x^422 + x^421 + x^419 + x^418 + x^411 + x^404 + x^402 + x^394 + x^393 + x^392 + x^391 + x^390 + x^387 + x^386 + x^383 + x^380 + x^379 + x^378 + x^377 + x^376 + x^374 + x^364 + x^362 + x^361 + x^359 + x^357 + x^356 + x^355 + x^354 + x^351 + x^349 + x^348 + x^347 + x^345 + x^342 + x^340 + x^332 + x^330 + x^329 + x^328 + x^327 + x^325 + x^324 + x^323 + x^321 + x^319 + x^318 + x^316 + x^314 + x^312 + x^302 + x^301 + x^300 + x^296 + x^295 + x^294 + x^291 + x^289 + x^287 + x^286 + x^283 + x^278 + x^266 + x^265 + x^264 + x^263 + x^262 + x^260 + x^259 + x^255 + x^250 + x^234 + x^232 + x^229 + x^227 + x^226 + x^225 + x^222 + x^218 + x^216 + x^208 + x^204 + x^200 + x^198 + x^197 + x^195 + x^194 + x^193 + x^190 + x^188 + x^178 + x^174 + x^173 + x^172 + x^171 + x^170 + x^169 + x^168 + x^166 + x^165 + x^164 + x^162 + x^161 + x^160 + x^159 + x^158 + x^157 + x^156 + x^154 + x^142 + x^141 + x^139 + x^138 + x^135 + x^131 + x^128 + x^126 + x^116 + x^112 + x^110 + x^107 + x^106 + x^105 + x^104 + x^102 + x^100 + x^98 + x^96 + x^95 + x^94 + x^92 + x^88 + x^80 + x^79 + x^76 + x^74 + x^73 + x^71 + x^70 + x^69 + x^66 + x^65 + x^64 + x^56 + x^54 + x^48 + x^46 + x^45 + x^43 + x^38 + x^35 + x^33 + x^30 + 1
+
+57-54-32 249 x^928 + x^898 + x^870 + x^855 + x^848 + x^834 + x^826 + x^825 + x^808 + x^806 + x^805 + x^804 + x^798 + x^796 + x^788 + x^778 + x^776 + x^775 + x^766 + x^763 + x^756 + x^752 + x^745 + x^742 + x^736 + x^735 + x^734 + x^731 + x^715 + x^714 + x^713 + x^705 + x^703 + x^694 + x^688 + x^684 + x^682 + x^671 + x^660 + x^658 + x^652 + x^642 + x^641 + x^639 + x^634 + x^630 + x^621 + x^620 + x^616 + x^612 + x^609 + x^604 + x^602 + x^593 + x^591 + x^584 + x^579 + x^570 + x^568 + x^566 + x^565 + x^562 + x^558 + x^554 + x^550 + x^544 + x^536 + x^535 + x^533 + x^530 + x^529 + x^528 + x^524 + x^522 + x^517 + x^512 + x^505 + x^496 + x^494 + x^492 + x^491 + x^489 + x^480 + x^478 + x^475 + x^471 + x^464 + x^461 + x^454 + x^452 + x^450 + x^446 + x^445 + x^441 + x^438 + x^437 + x^436 + x^434 + x^430 + x^429 + x^427 + x^425 + x^420 + x^418 + x^416 + x^415 + x^413 + x^411 + x^409 + x^402 + x^397 + x^394 + x^392 + x^388 + x^386 + x^384 + x^377 + x^375 + x^371 + x^368 + x^367 + x^365 + x^364 + x^363 + x^362 + x^360 + x^358 + x^356 + x^353 + x^351 + x^346 + x^342 + x^341 + x^338 + x^335 + x^333 + x^330 + x^328 + x^326 + x^325 + x^317 + x^307 + x^304 + x^300 + x^296 + x^295 + x^293 + x^292 + x^288 + x^286 + x^285 + x^284 + x^283 + x^278 + x^277 + x^276 + x^273 + x^271 + x^270 + x^262 + x^261 + x^255 + x^253 + x^249 + x^248 + x^246 + x^245 + x^240 + x^236 + x^232 + x^231 + x^227 + x^224 + x^223 + x^221 + x^220 + x^217 + x^216 + x^212 + x^208 + x^205 + x^204 + x^198 + x^196 + x^192 + x^191 + x^190 + x^189 + x^187 + x^186 + x^178 + x^176 + x^175 + x^171 + x^169 + x^165 + x^160 + x^159 + x^158 + x^154 + x^152 + x^150 + x^148 + x^146 + x^144 + x^141 + x^134 + x^132 + x^131 + x^129 + x^127 + x^125 + x^123 + x^120 + x^118 + x^114 + x^113 + x^111 + x^106 + x^104 + x^103 + x^102 + x^101 + x^100 + x^99 + x^97 + x^95 + x^93 + x^88 + x^85 + x^77 + x^67 + x^62 + x^60 + x^55 + x^54 + x^53 + x^52 + x^51 + x^50 + x^48 + x^46 + x^40 + x^37 + x^33 + x^28 + x^27 + x^24 + 1
+
+1-38-28 251 x^928 + x^898 + x^870 + x^866 + x^836 + x^834 + x^832 + x^818 + x^808 + x^806 + x^804 + x^797 + x^788 + x^778 + x^776 + x^770 + x^767 + x^765 + x^738 + x^736 + x^733 + x^724 + x^717 + x^708 + x^706 + x^703 + x^701 + x^690 + x^688 + x^685 + x^678 + x^677 + x^676 + x^674 + x^672 + x^664 + x^658 + x^656 + x^652 + x^647 + x^645 + x^640 + x^626 + x^624 + x^621 + x^620 + x^616 + x^610 + x^608 + x^604 + x^600 + x^594 + x^593 + x^592 + x^590 + x^580 + x^578 + x^576 + x^575 + x^574 + x^572 + x^568 + x^566 + x^565 + x^564 + x^562 + x^560 + x^558 + x^552 + x^550 + x^549 + x^548 + x^544 + x^541 + x^538 + x^536 + x^533 + x^532 + x^529 + x^526 + x^522 + x^520 + x^519 + x^517 + x^514 + x^513 + x^509 + x^508 + x^504 + x^501 + x^494 + x^493 + x^484 + x^482 + x^469 + x^468 + x^466 + x^461 + x^453 + x^452 + x^448 + x^447 + x^436 + x^428 + x^424 + x^422 + x^420 + x^416 + x^414 + x^413 + x^412 + x^409 + x^408 + x^406 + x^405 + x^404 + x^400 + x^399 + x^397 + x^393 + x^391 + x^388 + x^385 + x^382 + x^381 + x^376 + x^374 + x^372 + x^370 + x^368 + x^366 + x^365 + x^360 + x^350 + x^349 + x^344 + x^341 + x^340 + x^336 + x^335 + x^334 + x^333 + x^332 + x^328 + x^326 + x^322 + x^319 + x^318 + x^308 + x^304 + x^300 + x^298 + x^293 + x^292 + x^290 + x^289 + x^287 + x^284 + x^281 + x^279 + x^278 + x^272 + x^271 + x^269 + x^264 + x^263 + x^261 + x^256 + x^254 + x^253 + x^250 + x^240 + x^238 + x^234 + x^229 + x^228 + x^226 + x^223 + x^221 + x^218 + x^213 + x^210 + x^208 + x^204 + x^198 + x^197 + x^196 + x^194 + x^191 + x^188 + x^186 + x^180 + x^176 + x^174 + x^172 + x^170 + x^169 + x^167 + x^165 + x^161 + x^159 + x^157 + x^153 + x^150 + x^149 + x^148 + x^145 + x^136 + x^135 + x^134 + x^133 + x^132 + x^130 + x^128 + x^127 + x^125 + x^122 + x^120 + x^118 + x^113 + x^110 + x^109 + x^108 + x^100 + x^96 + x^94 + x^92 + x^90 + x^88 + x^86 + x^85 + x^84 + x^81 + x^80 + x^72 + x^70 + x^66 + x^58 + x^53 + x^45 + x^36 + x^34 + x^32 + x^30 + x^24 + x^20 + x^16 + x^12 + x^8 + x^2 + 1
+
+47-57-20 279 x^928 + x^898 + x^880 + x^870 + x^864 + x^851 + x^850 + x^846 + x^830 + x^821 + x^820 + x^817 + x^812 + x^808 + x^807 + x^804 + x^796 + x^790 + x^783 + x^782 + x^777 + x^773 + x^762 + x^757 + x^753 + x^744 + x^743 + x^739 + x^731 + x^728 + x^714 + x^713 + x^710 + x^709 + x^705 + x^701 + x^694 + x^692 + x^688 + x^684 + x^683 + x^675 + x^672 + x^671 + x^668 + x^662 + x^660 + x^654 + x^653 + x^646 + x^642 + x^641 + x^637 + x^626 + x^624 + x^623 + x^608 + x^607 + x^603 + x^598 + x^593 + x^592 + x^590 + x^585 + x^578 + x^577 + x^574 + x^573 + x^572 + x^569 + x^568 + x^567 + x^563 + x^559 + x^558 + x^555 + x^551 + x^548 + x^547 + x^542 + x^539 + x^538 + x^537 + x^536 + x^535 + x^532 + x^530 + x^529 + x^525 + x^524 + x^521 + x^518 + x^517 + x^506 + x^505 + x^501 + x^496 + x^491 + x^490 + x^487 + x^471 + x^467 + x^462 + x^456 + x^452 + x^448 + x^446 + x^441 + x^440 + x^437 + x^433 + x^428 + x^420 + x^412 + x^411 + x^404 + x^403 + x^402 + x^401 + x^399 + x^398 + x^396 + x^394 + x^381 + x^378 + x^376 + x^371 + x^370 + x^366 + x^365 + x^360 + x^355 + x^354 + x^351 + x^348 + x^346 + x^344 + x^342 + x^340 + x^339 + x^337 + x^335 + x^333 + x^331 + x^330 + x^329 + x^328 + x^327 + x^320 + x^318 + x^313 + x^307 + x^299 + x^298 + x^297 + x^296 + x^295 + x^294 + x^293 + x^291 + x^283 + x^282 + x^281 + x^280 + x^279 + x^277 + x^276 + x^266 + x^265 + x^264 + x^263 + x^262 + x^261 + x^259 + x^258 + x^257 + x^256 + x^251 + x^248 + x^247 + x^242 + x^240 + x^235 + x^234 + x^233 + x^231 + x^230 + x^229 + x^227 + x^225 + x^224 + x^219 + x^214 + x^212 + x^210 + x^206 + x^204 + x^203 + x^200 + x^196 + x^195 + x^194 + x^192 + x^191 + x^190 + x^188 + x^185 + x^182 + x^178 + x^176 + x^173 + x^159 + x^158 + x^157 + x^156 + x^151 + x^146 + x^144 + x^143 + x^142 + x^140 + x^138 + x^136 + x^131 + x^130 + x^128 + x^127 + x^126 + x^123 + x^122 + x^118 + x^117 + x^115 + x^114 + x^113 + x^108 + x^105 + x^99 + x^98 + x^94 + x^90 + x^88 + x^87 + x^86 + x^84 + x^82 + x^81 + x^80 + x^79 + x^78 + x^75 + x^74 + x^72 + x^71 + x^70 + x^65 + x^64 + x^58 + x^57 + x^56 + x^55 + x^52 + x^50 + x^48 + x^47 + x^46 + x^45 + x^42 + x^39 + x^26 + x^24 + x^23 + x^22 + x^20 + x^18 + x^15 + x^8 + x^4 + 1
+
+3-16-56 281 x^928 + x^898 + x^882 + x^870 + x^836 + x^820 + x^816 + x^808 + x^803 + x^802 + x^799 + x^778 + x^773 + x^770 + x^762 + x^757 + x^754 + x^753 + x^750 + x^737 + x^733 + x^720 + x^717 + x^713 + x^700 + x^688 + x^683 + x^680 + x^679 + x^674 + x^660 + x^658 + x^656 + x^654 + x^653 + x^650 + x^646 + x^644 + x^641 + x^640 + x^637 + x^634 + x^633 + x^623 + x^618 + x^617 + x^616 + x^613 + x^597 + x^590 + x^585 + x^584 + x^581 + x^577 + x^574 + x^572 + x^563 + x^562 + x^560 + x^555 + x^554 + x^553 + x^551 + x^547 + x^544 + x^537 + x^536 + x^533 + x^525 + x^521 + x^520 + x^519 + x^517 + x^515 + x^513 + x^510 + x^508 + x^505 + x^502 + x^501 + x^498 + x^493 + x^490 + x^485 + x^480 + x^477 + x^476 + x^475 + x^472 + x^469 + x^461 + x^458 + x^453 + x^449 + x^448 + x^445 + x^444 + x^442 + x^435 + x^433 + x^432 + x^431 + x^426 + x^425 + x^422 + x^420 + x^418 + x^412 + x^411 + x^409 + x^405 + x^403 + x^401 + x^400 + x^397 + x^393 + x^385 + x^381 + x^368 + x^366 + x^365 + x^362 + x^361 + x^359 + x^356 + x^353 + x^350 + x^346 + x^341 + x^338 + x^335 + x^334 + x^333 + x^332 + x^328 + x^326 + x^325 + x^323 + x^322 + x^320 + x^319 + x^317 + x^316 + x^315 + x^313 + x^312 + x^310 + x^309 + x^307 + x^305 + x^300 + x^295 + x^293 + x^291 + x^290 + x^289 + x^288 + x^286 + x^285 + x^282 + x^277 + x^274 + x^273 + x^266 + x^265 + x^263 + x^261 + x^259 + x^255 + x^253 + x^251 + x^248 + x^247 + x^246 + x^242 + x^241 + x^239 + x^234 + x^233 + x^232 + x^230 + x^229 + x^228 + x^226 + x^225 + x^224 + x^222 + x^218 + x^217 + x^215 + x^212 + x^210 + x^208 + x^206 + x^205 + x^203 + x^201 + x^200 + x^194 + x^193 + x^191 + x^189 + x^183 + x^181 + x^180 + x^178 + x^177 + x^176 + x^174 + x^172 + x^171 + x^169 + x^167 + x^166 + x^163 + x^162 + x^159 + x^157 + x^155 + x^151 + x^150 + x^149 + x^147 + x^140 + x^139 + x^138 + x^137 + x^136 + x^134 + x^131 + x^128 + x^127 + x^126 + x^121 + x^119 + x^118 + x^117 + x^111 + x^106 + x^104 + x^102 + x^101 + x^99 + x^98 + x^91 + x^90 + x^88 + x^86 + x^85 + x^81 + x^79 + x^75 + x^74 + x^73 + x^72 + x^71 + x^69 + x^68 + x^65 + x^64 + x^63 + x^62 + x^61 + x^58 + x^57 + x^56 + x^55 + x^51 + x^50 + x^49 + x^41 + x^38 + x^36 + x^34 + x^33 + x^32 + x^24 + x^21 + x^9 + x^6 + 1
+
+10-38-9 285 x^928 + x^898 + x^870 + x^841 + x^840 + x^838 + x^836 + x^811 + x^810 + x^781 + x^777 + x^774 + x^751 + x^748 + x^723 + x^721 + x^720 + x^719 + x^718 + x^717 + x^716 + x^714 + x^712 + x^694 + x^692 + x^691 + x^688 + x^686 + x^664 + x^663 + x^661 + x^660 + x^659 + x^657 + x^652 + x^650 + x^632 + x^631 + x^630 + x^628 + x^627 + x^625 + x^624 + x^623 + x^605 + x^604 + x^603 + x^599 + x^597 + x^594 + x^593 + x^591 + x^590 + x^588 + x^576 + x^575 + x^574 + x^572 + x^571 + x^570 + x^569 + x^567 + x^565 + x^560 + x^544 + x^543 + x^542 + x^540 + x^539 + x^537 + x^535 + x^531 + x^526 + x^514 + x^510 + x^509 + x^507 + x^506 + x^505 + x^504 + x^503 + x^502 + x^498 + x^485 + x^484 + x^478 + x^474 + x^471 + x^470 + x^468 + x^466 + x^464 + x^458 + x^455 + x^452 + x^450 + x^449 + x^448 + x^445 + x^441 + x^439 + x^428 + x^419 + x^416 + x^415 + x^411 + x^407 + x^406 + x^405 + x^404 + x^402 + x^398 + x^392 + x^388 + x^385 + x^384 + x^383 + x^382 + x^381 + x^380 + x^379 + x^376 + x^374 + x^364 + x^359 + x^357 + x^356 + x^355 + x^354 + x^353 + x^351 + x^349 + x^346 + x^345 + x^343 + x^340 + x^338 + x^334 + x^328 + x^326 + x^325 + x^324 + x^321 + x^320 + x^319 + x^318 + x^315 + x^314 + x^312 + x^306 + x^298 + x^297 + x^295 + x^294 + x^293 + x^291 + x^288 + x^287 + x^286 + x^285 + x^283 + x^282 + x^281 + x^278 + x^276 + x^274 + x^270 + x^269 + x^268 + x^263 + x^261 + x^256 + x^255 + x^254 + x^244 + x^242 + x^237 + x^236 + x^235 + x^234 + x^233 + x^232 + x^229 + x^225 + x^222 + x^219 + x^216 + x^214 + x^212 + x^210 + x^209 + x^208 + x^207 + x^206 + x^202 + x^198 + x^194 + x^193 + x^192 + x^191 + x^190 + x^184 + x^182 + x^178 + x^176 + x^175 + x^174 + x^173 + x^168 + x^166 + x^164 + x^160 + x^159 + x^157 + x^154 + x^152 + x^151 + x^150 + x^145 + x^144 + x^142 + x^136 + x^135 + x^134 + x^129 + x^128 + x^122 + x^121 + x^119 + x^118 + x^116 + x^114 + x^113 + x^112 + x^111 + x^108 + x^105 + x^103 + x^100 + x^98 + x^97 + x^95 + x^94 + x^92 + x^89 + x^88 + x^87 + x^85 + x^84 + x^83 + x^78 + x^76 + x^74 + x^73 + x^71 + x^70 + x^69 + x^67 + x^66 + x^64 + x^61 + x^59 + x^57 + x^56 + x^54 + x^53 + x^51 + x^49 + x^48 + x^46 + x^45 + x^43 + x^42 + x^41 + x^40 + x^38 + x^37 + x^36 + x^35 + x^34 + x^33 + x^32 + x^30 + x^4 + 1
+
+15-22-28 289 x^928 + x^898 + x^870 + x^838 + x^821 + x^806 + x^805 + x^792 + x^790 + x^778 + x^774 + x^762 + x^745 + x^744 + x^718 + x^697 + x^682 + x^672 + x^670 + x^667 + x^666 + x^658 + x^656 + x^653 + x^652 + x^651 + x^650 + x^642 + x^641 + x^638 + x^637 + x^623 + x^608 + x^607 + x^598 + x^594 + x^588 + x^575 + x^574 + x^573 + x^566 + x^565 + x^564 + x^563 + x^562 + x^557 + x^548 + x^547 + x^542 + x^538 + x^533 + x^531 + x^529 + x^526 + x^517 + x^516 + x^514 + x^513 + x^505 + x^504 + x^503 + x^502 + x^501 + x^499 + x^498 + x^497 + x^488 + x^487 + x^484 + x^483 + x^482 + x^474 + x^470 + x^468 + x^467 + x^466 + x^464 + x^457 + x^454 + x^453 + x^449 + x^447 + x^444 + x^443 + x^442 + x^441 + x^440 + x^439 + x^437 + x^436 + x^435 + x^428 + x^427 + x^426 + x^425 + x^422 + x^418 + x^417 + x^414 + x^409 + x^406 + x^405 + x^392 + x^391 + x^389 + x^388 + x^387 + x^386 + x^379 + x^378 + x^374 + x^372 + x^371 + x^368 + x^367 + x^362 + x^361 + x^358 + x^357 + x^354 + x^350 + x^349 + x^347 + x^342 + x^341 + x^340 + x^334 + x^333 + x^332 + x^331 + x^330 + x^329 + x^328 + x^327 + x^324 + x^323 + x^320 + x^319 + x^313 + x^308 + x^307 + x^305 + x^303 + x^302 + x^301 + x^300 + x^299 + x^298 + x^297 + x^296 + x^295 + x^294 + x^293 + x^292 + x^288 + x^287 + x^286 + x^283 + x^282 + x^280 + x^279 + x^278 + x^277 + x^276 + x^271 + x^269 + x^268 + x^267 + x^266 + x^265 + x^255 + x^254 + x^253 + x^249 + x^247 + x^241 + x^238 + x^237 + x^236 + x^235 + x^226 + x^225 + x^224 + x^223 + x^220 + x^219 + x^215 + x^214 + x^212 + x^210 + x^209 + x^205 + x^202 + x^201 + x^200 + x^199 + x^197 + x^190 + x^186 + x^182 + x^181 + x^180 + x^177 + x^174 + x^173 + x^172 + x^171 + x^170 + x^169 + x^168 + x^165 + x^163 + x^161 + x^160 + x^158 + x^155 + x^153 + x^151 + x^150 + x^146 + x^143 + x^142 + x^137 + x^136 + x^135 + x^131 + x^130 + x^128 + x^127 + x^126 + x^125 + x^124 + x^123 + x^122 + x^120 + x^119 + x^117 + x^114 + x^113 + x^111 + x^105 + x^104 + x^103 + x^102 + x^101 + x^99 + x^97 + x^93 + x^90 + x^89 + x^88 + x^87 + x^86 + x^84 + x^83 + x^82 + x^81 + x^80 + x^79 + x^77 + x^75 + x^72 + x^71 + x^70 + x^69 + x^68 + x^65 + x^60 + x^59 + x^58 + x^55 + x^54 + x^52 + x^51 + x^50 + x^48 + x^43 + x^42 + x^40 + x^39 + x^30 + x^28 + x^27 + x^24 + x^23 + x^19 + x^16 + x^15 + 1
+
+12-41-35 291 x^928 + x^898 + x^886 + x^873 + x^870 + x^860 + x^856 + x^847 + x^844 + x^834 + x^830 + x^826 + x^818 + x^817 + x^805 + x^804 + x^796 + x^795 + x^791 + x^784 + x^782 + x^779 + x^769 + x^765 + x^762 + x^758 + x^756 + x^753 + x^752 + x^743 + x^739 + x^736 + x^735 + x^732 + x^731 + x^730 + x^727 + x^726 + x^723 + x^722 + x^717 + x^713 + x^710 + x^705 + x^701 + x^700 + x^692 + x^685 + x^683 + x^680 + x^676 + x^671 + x^663 + x^659 + x^657 + x^654 + x^653 + x^645 + x^642 + x^637 + x^632 + x^628 + x^624 + x^623 + x^619 + x^616 + x^615 + x^612 + x^610 + x^607 + x^606 + x^603 + x^598 + x^597 + x^594 + x^593 + x^590 + x^589 + x^585 + x^580 + x^577 + x^576 + x^572 + x^567 + x^564 + x^560 + x^559 + x^556 + x^550 + x^545 + x^543 + x^538 + x^537 + x^534 + x^533 + x^532 + x^528 + x^520 + x^516 + x^513 + x^508 + x^507 + x^506 + x^504 + x^499 + x^496 + x^491 + x^490 + x^487 + x^486 + x^485 + x^481 + x^477 + x^474 + x^466 + x^465 + x^457 + x^452 + x^448 + x^447 + x^446 + x^438 + x^436 + x^435 + x^434 + x^430 + x^425 + x^422 + x^421 + x^417 + x^413 + x^409 + x^404 + x^395 + x^393 + x^392 + x^388 + x^387 + x^386 + x^384 + x^382 + x^380 + x^379 + x^374 + x^373 + x^370 + x^367 + x^366 + x^362 + x^361 + x^358 + x^357 + x^354 + x^353 + x^352 + x^350 + x^349 + x^345 + x^344 + x^343 + x^340 + x^337 + x^336 + x^332 + x^331 + x^328 + x^324 + x^323 + x^317 + x^315 + x^314 + x^313 + x^311 + x^305 + x^302 + x^298 + x^297 + x^296 + x^295 + x^292 + x^291 + x^288 + x^283 + x^280 + x^276 + x^275 + x^272 + x^268 + x^266 + x^262 + x^259 + x^258 + x^255 + x^251 + x^250 + x^242 + x^241 + x^240 + x^232 + x^227 + x^225 + x^224 + x^223 + x^216 + x^214 + x^212 + x^211 + x^210 + x^206 + x^203 + x^198 + x^189 + x^188 + x^177 + x^176 + x^175 + x^173 + x^168 + x^164 + x^162 + x^160 + x^159 + x^156 + x^155 + x^154 + x^152 + x^149 + x^147 + x^146 + x^145 + x^142 + x^139 + x^138 + x^137 + x^134 + x^132 + x^130 + x^124 + x^123 + x^122 + x^115 + x^113 + x^112 + x^111 + x^110 + x^108 + x^106 + x^103 + x^102 + x^98 + x^97 + x^96 + x^95 + x^94 + x^92 + x^91 + x^90 + x^88 + x^85 + x^80 + x^78 + x^77 + x^76 + x^73 + x^71 + x^70 + x^69 + x^68 + x^67 + x^65 + x^64 + x^63 + x^54 + x^53 + x^52 + x^51 + x^50 + x^49 + x^48 + x^47 + x^44 + x^43 + x^42 + x^40 + x^39 + x^31 + x^30 + x^29 + x^21 + x^13 + 1
+
+35-54-56 293 x^928 + x^898 + x^870 + x^862 + x^832 + x^826 + x^808 + x^796 + x^794 + x^790 + x^778 + x^765 + x^758 + x^754 + x^734 + x^729 + x^728 + x^722 + x^718 + x^715 + x^706 + x^700 + x^699 + x^698 + x^693 + x^686 + x^682 + x^676 + x^673 + x^672 + x^669 + x^668 + x^662 + x^658 + x^656 + x^655 + x^652 + x^650 + x^649 + x^646 + x^645 + x^642 + x^639 + x^638 + x^636 + x^630 + x^622 + x^614 + x^613 + x^612 + x^610 + x^608 + x^607 + x^600 + x^596 + x^595 + x^592 + x^590 + x^589 + x^587 + x^582 + x^574 + x^571 + x^568 + x^566 + x^560 + x^558 + x^554 + x^553 + x^552 + x^548 + x^544 + x^542 + x^538 + x^536 + x^534 + x^530 + x^528 + x^527 + x^524 + x^523 + x^522 + x^520 + x^518 + x^516 + x^515 + x^511 + x^506 + x^499 + x^497 + x^493 + x^492 + x^490 + x^487 + x^482 + x^478 + x^474 + x^467 + x^462 + x^461 + x^452 + x^445 + x^442 + x^439 + x^437 + x^436 + x^433 + x^428 + x^427 + x^422 + x^418 + x^413 + x^412 + x^410 + x^409 + x^407 + x^406 + x^403 + x^401 + x^398 + x^396 + x^392 + x^390 + x^386 + x^384 + x^383 + x^382 + x^380 + x^378 + x^377 + x^373 + x^372 + x^371 + x^366 + x^365 + x^362 + x^353 + x^352 + x^350 + x^348 + x^346 + x^344 + x^342 + x^340 + x^338 + x^336 + x^335 + x^334 + x^332 + x^331 + x^328 + x^326 + x^320 + x^318 + x^317 + x^316 + x^313 + x^312 + x^311 + x^310 + x^308 + x^304 + x^300 + x^299 + x^298 + x^296 + x^295 + x^293 + x^290 + x^288 + x^284 + x^282 + x^275 + x^271 + x^269 + x^268 + x^266 + x^265 + x^264 + x^263 + x^262 + x^260 + x^259 + x^253 + x^250 + x^247 + x^246 + x^244 + x^242 + x^240 + x^239 + x^238 + x^235 + x^233 + x^232 + x^228 + x^227 + x^226 + x^224 + x^221 + x^220 + x^218 + x^216 + x^214 + x^212 + x^208 + x^203 + x^199 + x^198 + x^196 + x^195 + x^194 + x^193 + x^192 + x^189 + x^187 + x^182 + x^178 + x^176 + x^175 + x^173 + x^168 + x^167 + x^166 + x^163 + x^161 + x^160 + x^156 + x^152 + x^150 + x^148 + x^146 + x^140 + x^138 + x^135 + x^133 + x^131 + x^130 + x^129 + x^128 + x^127 + x^126 + x^125 + x^123 + x^122 + x^120 + x^118 + x^116 + x^115 + x^113 + x^112 + x^109 + x^106 + x^105 + x^104 + x^103 + x^101 + x^100 + x^95 + x^94 + x^92 + x^84 + x^82 + x^80 + x^79 + x^77 + x^76 + x^74 + x^71 + x^69 + x^68 + x^66 + x^65 + x^64 + x^63 + x^55 + x^54 + x^53 + x^49 + x^48 + x^46 + x^45 + x^43 + x^42 + x^41 + x^40 + x^38 + x^36 + x^34 + x^24 + x^18 + x^6 + 1
+
+44-42-5 307 x^928 + x^898 + x^880 + x^870 + x^856 + x^850 + x^839 + x^832 + x^826 + x^820 + x^816 + x^815 + x^808 + x^792 + x^791 + x^790 + x^784 + x^779 + x^778 + x^768 + x^762 + x^760 + x^756 + x^754 + x^753 + x^747 + x^744 + x^738 + x^737 + x^736 + x^731 + x^726 + x^723 + x^720 + x^719 + x^717 + x^713 + x^707 + x^696 + x^693 + x^689 + x^688 + x^682 + x^678 + x^677 + x^670 + x^666 + x^665 + x^663 + x^660 + x^658 + x^657 + x^653 + x^646 + x^633 + x^630 + x^628 + x^624 + x^617 + x^616 + x^612 + x^611 + x^606 + x^605 + x^604 + x^603 + x^600 + x^599 + x^597 + x^594 + x^592 + x^588 + x^587 + x^586 + x^582 + x^580 + x^576 + x^575 + x^568 + x^563 + x^556 + x^552 + x^546 + x^544 + x^542 + x^540 + x^539 + x^537 + x^534 + x^533 + x^526 + x^522 + x^521 + x^520 + x^518 + x^517 + x^516 + x^514 + x^511 + x^510 + x^508 + x^505 + x^503 + x^494 + x^492 + x^488 + x^485 + x^481 + x^475 + x^474 + x^470 + x^467 + x^464 + x^463 + x^462 + x^454 + x^452 + x^449 + x^447 + x^446 + x^444 + x^443 + x^442 + x^439 + x^438 + x^437 + x^432 + x^431 + x^430 + x^427 + x^426 + x^424 + x^422 + x^419 + x^418 + x^413 + x^410 + x^409 + x^406 + x^404 + x^401 + x^398 + x^396 + x^393 + x^392 + x^391 + x^390 + x^389 + x^385 + x^383 + x^380 + x^379 + x^376 + x^374 + x^372 + x^370 + x^368 + x^367 + x^366 + x^365 + x^364 + x^363 + x^361 + x^358 + x^355 + x^354 + x^353 + x^349 + x^348 + x^347 + x^344 + x^343 + x^342 + x^341 + x^338 + x^337 + x^336 + x^334 + x^332 + x^329 + x^328 + x^318 + x^317 + x^312 + x^310 + x^308 + x^307 + x^306 + x^305 + x^304 + x^299 + x^296 + x^294 + x^293 + x^291 + x^289 + x^281 + x^280 + x^278 + x^277 + x^276 + x^274 + x^272 + x^270 + x^267 + x^265 + x^264 + x^263 + x^260 + x^253 + x^252 + x^251 + x^250 + x^247 + x^242 + x^241 + x^239 + x^234 + x^233 + x^231 + x^230 + x^229 + x^224 + x^223 + x^222 + x^217 + x^214 + x^212 + x^210 + x^209 + x^208 + x^203 + x^200 + x^199 + x^198 + x^196 + x^195 + x^192 + x^191 + x^186 + x^185 + x^184 + x^181 + x^180 + x^179 + x^178 + x^177 + x^176 + x^175 + x^172 + x^171 + x^170 + x^169 + x^168 + x^166 + x^165 + x^161 + x^160 + x^159 + x^151 + x^146 + x^144 + x^143 + x^142 + x^141 + x^139 + x^137 + x^136 + x^135 + x^133 + x^131 + x^130 + x^120 + x^116 + x^114 + x^113 + x^108 + x^107 + x^106 + x^104 + x^101 + x^98 + x^97 + x^96 + x^91 + x^90 + x^89 + x^87 + x^82 + x^80 + x^78 + x^73 + x^72 + x^67 + x^62 + x^58 + x^56 + x^55 + x^53 + x^49 + x^46 + x^44 + x^39 + x^32 + x^26 + x^17 + 1
+
+18-7-29 311 x^928 + x^926 + x^920 + x^918 + x^912 + x^910 + x^904 + x^902 + x^898 + x^896 + x^894 + x^890 + x^888 + x^886 + x^882 + x^880 + x^878 + x^874 + x^872 + x^870 + x^866 + x^858 + x^850 + x^842 + x^808 + x^806 + x^792 + x^790 + x^778 + x^776 + x^774 + x^762 + x^760 + x^758 + x^746 + x^730 + x^688 + x^686 + x^680 + x^678 + x^669 + x^667 + x^661 + x^659 + x^658 + x^656 + x^655 + x^654 + x^651 + x^650 + x^648 + x^647 + x^646 + x^643 + x^626 + x^618 + x^611 + x^605 + x^595 + x^589 + x^587 + x^575 + x^569 + x^568 + x^566 + x^561 + x^553 + x^541 + x^539 + x^538 + x^537 + x^536 + x^534 + x^533 + x^515 + x^511 + x^509 + x^507 + x^506 + x^503 + x^501 + x^497 + x^495 + x^493 + x^489 + x^485 + x^483 + x^481 + x^479 + x^475 + x^473 + x^471 + x^469 + x^457 + x^455 + x^453 + x^451 + x^449 + x^448 + x^447 + x^446 + x^443 + x^440 + x^439 + x^438 + x^437 + x^435 + x^433 + x^432 + x^431 + x^429 + x^426 + x^425 + x^424 + x^421 + x^418 + x^417 + x^416 + x^415 + x^414 + x^412 + x^409 + x^408 + x^406 + x^405 + x^404 + x^401 + x^398 + x^396 + x^395 + x^393 + x^392 + x^390 + x^388 + x^387 + x^380 + x^379 + x^377 + x^376 + x^372 + x^371 + x^370 + x^369 + x^367 + x^364 + x^363 + x^362 + x^361 + x^359 + x^358 + x^354 + x^352 + x^350 + x^349 + x^348 + x^341 + x^340 + x^337 + x^336 + x^335 + x^331 + x^330 + x^328 + x^326 + x^320 + x^319 + x^318 + x^317 + x^315 + x^314 + x^313 + x^312 + x^310 + x^308 + x^307 + x^302 + x^301 + x^299 + x^297 + x^295 + x^293 + x^291 + x^287 + x^284 + x^283 + x^282 + x^281 + x^280 + x^279 + x^278 + x^274 + x^271 + x^267 + x^266 + x^264 + x^263 + x^257 + x^256 + x^255 + x^252 + x^251 + x^250 + x^246 + x^241 + x^240 + x^239 + x^234 + x^233 + x^231 + x^230 + x^229 + x^226 + x^225 + x^224 + x^223 + x^222 + x^218 + x^216 + x^214 + x^212 + x^211 + x^206 + x^203 + x^202 + x^199 + x^198 + x^197 + x^193 + x^191 + x^190 + x^188 + x^185 + x^183 + x^181 + x^180 + x^179 + x^176 + x^171 + x^169 + x^167 + x^158 + x^156 + x^155 + x^154 + x^153 + x^151 + x^150 + x^148 + x^145 + x^143 + x^142 + x^141 + x^138 + x^133 + x^132 + x^130 + x^127 + x^125 + x^123 + x^121 + x^118 + x^109 + x^108 + x^105 + x^104 + x^103 + x^102 + x^100 + x^97 + x^95 + x^94 + x^92 + x^90 + x^85 + x^84 + x^82 + x^80 + x^76 + x^74 + x^73 + x^71 + x^70 + x^68 + x^67 + x^66 + x^65 + x^64 + x^61 + x^59 + x^57 + x^55 + x^53 + x^52 + x^48 + x^47 + x^45 + x^41 + x^38 + x^36 + x^34 + x^31 + x^28 + x^26 + x^24 + x^22 + x^18 + x^16 + x^12 + x^10 + x^2 + 1
+
+48-55-49 313 x^928 + x^898 + x^894 + x^893 + x^870 + x^864 + x^860 + x^858 + x^838 + x^836 + x^832 + x^831 + x^830 + x^828 + x^804 + x^802 + x^796 + x^794 + x^778 + x^774 + x^773 + x^770 + x^769 + x^768 + x^741 + x^740 + x^737 + x^736 + x^734 + x^732 + x^731 + x^718 + x^712 + x^711 + x^706 + x^704 + x^702 + x^701 + x^684 + x^681 + x^679 + x^678 + x^676 + x^675 + x^672 + x^671 + x^669 + x^658 + x^656 + x^654 + x^653 + x^652 + x^651 + x^647 + x^646 + x^645 + x^621 + x^618 + x^617 + x^616 + x^615 + x^614 + x^611 + x^610 + x^609 + x^598 + x^596 + x^592 + x^590 + x^589 + x^583 + x^582 + x^580 + x^579 + x^576 + x^561 + x^559 + x^558 + x^557 + x^554 + x^548 + x^547 + x^545 + x^538 + x^534 + x^533 + x^531 + x^529 + x^527 + x^526 + x^524 + x^522 + x^521 + x^515 + x^512 + x^500 + x^497 + x^486 + x^484 + x^478 + x^474 + x^470 + x^469 + x^468 + x^467 + x^466 + x^465 + x^464 + x^462 + x^460 + x^458 + x^456 + x^454 + x^453 + x^450 + x^444 + x^438 + x^436 + x^435 + x^434 + x^433 + x^432 + x^429 + x^424 + x^422 + x^421 + x^418 + x^416 + x^413 + x^412 + x^407 + x^406 + x^405 + x^404 + x^402 + x^399 + x^398 + x^397 + x^396 + x^394 + x^392 + x^391 + x^388 + x^384 + x^380 + x^378 + x^377 + x^375 + x^373 + x^372 + x^371 + x^364 + x^359 + x^356 + x^354 + x^353 + x^352 + x^351 + x^350 + x^347 + x^343 + x^342 + x^340 + x^339 + x^334 + x^331 + x^328 + x^327 + x^325 + x^324 + x^322 + x^316 + x^312 + x^311 + x^310 + x^308 + x^306 + x^305 + x^304 + x^302 + x^301 + x^300 + x^298 + x^297 + x^295 + x^294 + x^292 + x^291 + x^290 + x^289 + x^288 + x^282 + x^280 + x^279 + x^278 + x^277 + x^276 + x^275 + x^273 + x^271 + x^268 + x^264 + x^261 + x^258 + x^256 + x^254 + x^253 + x^251 + x^249 + x^248 + x^246 + x^245 + x^244 + x^242 + x^241 + x^240 + x^239 + x^237 + x^236 + x^232 + x^231 + x^229 + x^228 + x^227 + x^226 + x^224 + x^223 + x^219 + x^216 + x^215 + x^211 + x^210 + x^207 + x^206 + x^204 + x^203 + x^199 + x^198 + x^194 + x^188 + x^187 + x^186 + x^182 + x^181 + x^180 + x^174 + x^171 + x^170 + x^168 + x^165 + x^164 + x^160 + x^152 + x^151 + x^150 + x^149 + x^148 + x^147 + x^144 + x^143 + x^142 + x^141 + x^139 + x^134 + x^129 + x^127 + x^124 + x^121 + x^119 + x^115 + x^108 + x^107 + x^105 + x^104 + x^103 + x^102 + x^95 + x^94 + x^90 + x^89 + x^88 + x^86 + x^84 + x^79 + x^77 + x^73 + x^72 + x^69 + x^66 + x^64 + x^63 + x^62 + x^60 + x^57 + x^56 + x^55 + x^54 + x^53 + x^52 + x^50 + x^49 + x^48 + x^46 + x^45 + x^41 + x^36 + x^34 + x^31 + x^29 + x^28 + x^26 + x^25 + 1
+
+40-44-57 319 x^928 + x^898 + x^870 + x^846 + x^822 + x^819 + x^808 + x^800 + x^794 + x^792 + x^786 + x^778 + x^770 + x^764 + x^759 + x^748 + x^746 + x^740 + x^732 + x^716 + x^713 + x^697 + x^696 + x^691 + x^686 + x^674 + x^664 + x^661 + x^658 + x^650 + x^648 + x^645 + x^644 + x^636 + x^629 + x^626 + x^624 + x^623 + x^621 + x^620 + x^618 + x^615 + x^594 + x^593 + x^591 + x^590 + x^586 + x^583 + x^580 + x^579 + x^577 + x^575 + x^574 + x^572 + x^571 + x^568 + x^564 + x^563 + x^561 + x^558 + x^556 + x^555 + x^553 + x^550 + x^547 + x^545 + x^544 + x^542 + x^541 + x^538 + x^536 + x^533 + x^528 + x^526 + x^525 + x^522 + x^519 + x^513 + x^512 + x^510 + x^509 + x^508 + x^507 + x^504 + x^503 + x^501 + x^495 + x^488 + x^487 + x^485 + x^484 + x^483 + x^482 + x^480 + x^479 + x^474 + x^473 + x^471 + x^470 + x^466 + x^463 + x^460 + x^458 + x^457 + x^454 + x^453 + x^450 + x^449 + x^446 + x^444 + x^443 + x^441 + x^440 + x^439 + x^436 + x^434 + x^433 + x^432 + x^431 + x^430 + x^427 + x^425 + x^424 + x^422 + x^420 + x^417 + x^416 + x^415 + x^413 + x^412 + x^411 + x^410 + x^409 + x^408 + x^407 + x^406 + x^405 + x^403 + x^398 + x^397 + x^395 + x^392 + x^390 + x^387 + x^386 + x^385 + x^383 + x^375 + x^370 + x^369 + x^368 + x^367 + x^365 + x^364 + x^363 + x^360 + x^359 + x^357 + x^356 + x^353 + x^351 + x^349 + x^342 + x^340 + x^339 + x^336 + x^335 + x^329 + x^327 + x^326 + x^324 + x^323 + x^320 + x^319 + x^318 + x^317 + x^316 + x^315 + x^312 + x^311 + x^307 + x^306 + x^302 + x^299 + x^298 + x^297 + x^295 + x^294 + x^293 + x^291 + x^290 + x^287 + x^285 + x^284 + x^283 + x^282 + x^281 + x^279 + x^277 + x^276 + x^275 + x^272 + x^271 + x^268 + x^266 + x^263 + x^262 + x^261 + x^255 + x^251 + x^249 + x^248 + x^245 + x^244 + x^243 + x^240 + x^239 + x^238 + x^236 + x^235 + x^234 + x^230 + x^229 + x^228 + x^227 + x^226 + x^224 + x^221 + x^217 + x^214 + x^212 + x^209 + x^208 + x^204 + x^202 + x^201 + x^197 + x^194 + x^193 + x^192 + x^191 + x^189 + x^188 + x^185 + x^184 + x^182 + x^181 + x^178 + x^176 + x^173 + x^172 + x^171 + x^169 + x^166 + x^163 + x^161 + x^160 + x^158 + x^156 + x^155 + x^154 + x^152 + x^151 + x^149 + x^148 + x^146 + x^145 + x^144 + x^142 + x^141 + x^134 + x^132 + x^129 + x^122 + x^121 + x^119 + x^117 + x^116 + x^113 + x^112 + x^110 + x^109 + x^103 + x^102 + x^101 + x^100 + x^97 + x^95 + x^94 + x^93 + x^92 + x^91 + x^87 + x^86 + x^85 + x^84 + x^81 + x^80 + x^75 + x^74 + x^71 + x^70 + x^68 + x^66 + x^63 + x^52 + x^51 + x^50 + x^47 + x^45 + x^44 + x^43 + x^39 + x^38 + x^34 + x^24 + x^16 + x^8 + 1
+
+21-52-12 321 x^928 + x^898 + x^870 + x^868 + x^856 + x^838 + x^828 + x^826 + x^816 + x^815 + x^808 + x^804 + x^786 + x^784 + x^778 + x^748 + x^744 + x^736 + x^734 + x^733 + x^732 + x^731 + x^726 + x^722 + x^718 + x^710 + x^706 + x^704 + x^703 + x^694 + x^692 + x^691 + x^688 + x^683 + x^680 + x^679 + x^678 + x^674 + x^672 + x^668 + x^664 + x^660 + x^658 + x^656 + x^653 + x^649 + x^648 + x^644 + x^643 + x^638 + x^632 + x^630 + x^625 + x^623 + x^619 + x^618 + x^616 + x^615 + x^613 + x^610 + x^607 + x^606 + x^602 + x^601 + x^600 + x^595 + x^593 + x^589 + x^588 + x^586 + x^585 + x^580 + x^579 + x^578 + x^571 + x^570 + x^566 + x^565 + x^564 + x^563 + x^560 + x^559 + x^555 + x^554 + x^550 + x^548 + x^547 + x^546 + x^544 + x^543 + x^541 + x^539 + x^538 + x^537 + x^535 + x^531 + x^530 + x^529 + x^522 + x^520 + x^514 + x^513 + x^509 + x^507 + x^504 + x^501 + x^500 + x^499 + x^498 + x^496 + x^495 + x^494 + x^492 + x^491 + x^490 + x^486 + x^483 + x^480 + x^479 + x^476 + x^473 + x^469 + x^466 + x^463 + x^460 + x^459 + x^457 + x^451 + x^449 + x^443 + x^441 + x^440 + x^436 + x^433 + x^432 + x^431 + x^424 + x^420 + x^418 + x^416 + x^414 + x^411 + x^410 + x^409 + x^408 + x^406 + x^404 + x^403 + x^401 + x^400 + x^398 + x^393 + x^390 + x^388 + x^385 + x^384 + x^381 + x^375 + x^372 + x^366 + x^365 + x^361 + x^358 + x^356 + x^354 + x^352 + x^347 + x^346 + x^341 + x^340 + x^338 + x^335 + x^334 + x^333 + x^331 + x^330 + x^326 + x^323 + x^320 + x^319 + x^318 + x^317 + x^315 + x^312 + x^311 + x^309 + x^305 + x^303 + x^301 + x^299 + x^297 + x^296 + x^295 + x^290 + x^289 + x^283 + x^282 + x^277 + x^276 + x^273 + x^268 + x^267 + x^266 + x^264 + x^262 + x^261 + x^260 + x^256 + x^254 + x^251 + x^250 + x^247 + x^245 + x^244 + x^243 + x^240 + x^238 + x^235 + x^234 + x^233 + x^231 + x^229 + x^225 + x^224 + x^217 + x^212 + x^211 + x^209 + x^208 + x^205 + x^204 + x^202 + x^200 + x^198 + x^196 + x^195 + x^191 + x^190 + x^188 + x^187 + x^186 + x^182 + x^181 + x^180 + x^175 + x^174 + x^172 + x^171 + x^170 + x^169 + x^166 + x^164 + x^158 + x^154 + x^153 + x^152 + x^149 + x^148 + x^147 + x^146 + x^144 + x^142 + x^141 + x^140 + x^138 + x^137 + x^136 + x^135 + x^133 + x^131 + x^127 + x^125 + x^123 + x^122 + x^121 + x^120 + x^119 + x^115 + x^113 + x^112 + x^111 + x^106 + x^102 + x^101 + x^100 + x^98 + x^96 + x^95 + x^93 + x^92 + x^91 + x^90 + x^89 + x^88 + x^87 + x^81 + x^79 + x^76 + x^72 + x^71 + x^70 + x^64 + x^60 + x^57 + x^56 + x^55 + x^54 + x^50 + x^49 + x^48 + x^47 + x^43 + x^39 + x^38 + x^30 + x^29 + x^26 + x^25 + x^14 + x^10 + 1
+
+25-44-4 331 x^928 + x^898 + x^870 + x^866 + x^862 + x^859 + x^836 + x^834 + x^829 + x^822 + x^808 + x^806 + x^804 + x^800 + x^799 + x^798 + x^797 + x^795 + x^778 + x^776 + x^770 + x^769 + x^767 + x^762 + x^753 + x^739 + x^735 + x^734 + x^731 + x^721 + x^713 + x^709 + x^708 + x^706 + x^705 + x^703 + x^701 + x^698 + x^688 + x^679 + x^677 + x^676 + x^674 + x^670 + x^669 + x^667 + x^666 + x^661 + x^659 + x^658 + x^649 + x^647 + x^645 + x^643 + x^642 + x^638 + x^635 + x^633 + x^629 + x^626 + x^624 + x^620 + x^618 + x^617 + x^614 + x^611 + x^605 + x^603 + x^598 + x^596 + x^594 + x^593 + x^590 + x^587 + x^581 + x^580 + x^579 + x^571 + x^570 + x^568 + x^566 + x^562 + x^558 + x^557 + x^551 + x^550 + x^548 + x^547 + x^546 + x^544 + x^542 + x^541 + x^539 + x^536 + x^533 + x^532 + x^530 + x^527 + x^526 + x^525 + x^524 + x^523 + x^521 + x^520 + x^519 + x^518 + x^517 + x^515 + x^514 + x^513 + x^507 + x^506 + x^504 + x^501 + x^497 + x^493 + x^492 + x^490 + x^488 + x^483 + x^482 + x^481 + x^478 + x^477 + x^476 + x^475 + x^473 + x^467 + x^466 + x^465 + x^463 + x^462 + x^461 + x^460 + x^456 + x^454 + x^453 + x^452 + x^450 + x^448 + x^446 + x^444 + x^443 + x^442 + x^433 + x^426 + x^423 + x^422 + x^420 + x^419 + x^416 + x^413 + x^412 + x^411 + x^410 + x^406 + x^404 + x^403 + x^402 + x^401 + x^400 + x^398 + x^396 + x^395 + x^392 + x^391 + x^389 + x^387 + x^386 + x^385 + x^380 + x^372 + x^366 + x^365 + x^363 + x^362 + x^359 + x^357 + x^354 + x^353 + x^352 + x^348 + x^346 + x^345 + x^342 + x^340 + x^338 + x^335 + x^334 + x^333 + x^332 + x^325 + x^324 + x^323 + x^320 + x^319 + x^318 + x^314 + x^312 + x^309 + x^308 + x^303 + x^302 + x^301 + x^299 + x^295 + x^294 + x^292 + x^291 + x^290 + x^289 + x^286 + x^284 + x^279 + x^278 + x^274 + x^273 + x^268 + x^266 + x^265 + x^263 + x^261 + x^257 + x^256 + x^255 + x^254 + x^253 + x^248 + x^245 + x^244 + x^241 + x^240 + x^237 + x^235 + x^234 + x^233 + x^232 + x^230 + x^229 + x^228 + x^226 + x^223 + x^222 + x^220 + x^218 + x^214 + x^212 + x^211 + x^209 + x^207 + x^206 + x^203 + x^202 + x^201 + x^200 + x^199 + x^198 + x^196 + x^191 + x^189 + x^184 + x^178 + x^177 + x^176 + x^175 + x^172 + x^171 + x^169 + x^166 + x^165 + x^162 + x^161 + x^159 + x^157 + x^156 + x^155 + x^150 + x^149 + x^148 + x^147 + x^143 + x^142 + x^141 + x^140 + x^137 + x^136 + x^135 + x^133 + x^131 + x^130 + x^129 + x^127 + x^126 + x^125 + x^124 + x^123 + x^120 + x^113 + x^112 + x^108 + x^105 + x^104 + x^98 + x^96 + x^92 + x^90 + x^82 + x^81 + x^80 + x^78 + x^76 + x^74 + x^73 + x^68 + x^66 + x^64 + x^62 + x^60 + x^58 + x^54 + x^42 + x^38 + x^36 + x^32 + x^26 + x^18 + x^16 + x^10 + x^8 + x^2 + 1
+
+16-8-37 341 x^928 + x^898 + x^870 + x^842 + x^814 + x^808 + x^788 + x^786 + x^784 + x^778 + x^777 + x^775 + x^773 + x^762 + x^756 + x^751 + x^745 + x^736 + x^723 + x^721 + x^717 + x^715 + x^713 + x^710 + x^700 + x^697 + x^693 + x^691 + x^688 + x^685 + x^678 + x^674 + x^673 + x^672 + x^667 + x^654 + x^650 + x^647 + x^645 + x^644 + x^643 + x^642 + x^641 + x^635 + x^634 + x^632 + x^631 + x^630 + x^622 + x^621 + x^618 + x^615 + x^614 + x^612 + x^608 + x^605 + x^604 + x^603 + x^601 + x^596 + x^595 + x^592 + x^590 + x^589 + x^588 + x^587 + x^586 + x^585 + x^584 + x^583 + x^581 + x^579 + x^578 + x^576 + x^575 + x^573 + x^571 + x^569 + x^565 + x^564 + x^561 + x^560 + x^557 + x^556 + x^555 + x^554 + x^552 + x^544 + x^543 + x^540 + x^535 + x^533 + x^530 + x^528 + x^527 + x^524 + x^522 + x^520 + x^519 + x^517 + x^516 + x^515 + x^514 + x^513 + x^510 + x^509 + x^508 + x^507 + x^503 + x^502 + x^500 + x^497 + x^496 + x^493 + x^491 + x^490 + x^486 + x^480 + x^477 + x^476 + x^475 + x^474 + x^473 + x^472 + x^471 + x^467 + x^464 + x^463 + x^461 + x^458 + x^457 + x^453 + x^446 + x^444 + x^441 + x^439 + x^436 + x^434 + x^433 + x^432 + x^430 + x^427 + x^426 + x^422 + x^418 + x^417 + x^416 + x^414 + x^412 + x^411 + x^410 + x^405 + x^404 + x^401 + x^399 + x^396 + x^395 + x^392 + x^391 + x^390 + x^388 + x^387 + x^386 + x^385 + x^384 + x^383 + x^378 + x^377 + x^375 + x^373 + x^372 + x^371 + x^366 + x^364 + x^358 + x^357 + x^356 + x^352 + x^348 + x^345 + x^342 + x^340 + x^339 + x^338 + x^336 + x^335 + x^331 + x^330 + x^329 + x^327 + x^324 + x^323 + x^322 + x^321 + x^320 + x^317 + x^316 + x^315 + x^314 + x^310 + x^307 + x^306 + x^303 + x^297 + x^295 + x^294 + x^293 + x^292 + x^291 + x^290 + x^288 + x^286 + x^284 + x^283 + x^282 + x^278 + x^276 + x^275 + x^274 + x^269 + x^268 + x^267 + x^263 + x^262 + x^261 + x^260 + x^259 + x^258 + x^256 + x^251 + x^249 + x^248 + x^247 + x^245 + x^242 + x^241 + x^239 + x^238 + x^236 + x^235 + x^234 + x^233 + x^232 + x^230 + x^229 + x^225 + x^224 + x^223 + x^222 + x^220 + x^218 + x^216 + x^214 + x^213 + x^212 + x^211 + x^209 + x^206 + x^201 + x^200 + x^199 + x^197 + x^196 + x^194 + x^193 + x^190 + x^186 + x^184 + x^181 + x^180 + x^179 + x^178 + x^177 + x^176 + x^175 + x^169 + x^168 + x^166 + x^164 + x^160 + x^158 + x^157 + x^156 + x^153 + x^152 + x^147 + x^146 + x^136 + x^134 + x^132 + x^129 + x^126 + x^125 + x^124 + x^123 + x^122 + x^120 + x^119 + x^116 + x^114 + x^112 + x^108 + x^107 + x^106 + x^104 + x^102 + x^98 + x^95 + x^91 + x^85 + x^84 + x^82 + x^81 + x^80 + x^79 + x^77 + x^76 + x^73 + x^72 + x^70 + x^62 + x^60 + x^59 + x^58 + x^56 + x^55 + x^53 + x^49 + x^44 + x^42 + x^41 + x^39 + x^38 + x^35 + x^34 + x^32 + x^28 + x^26 + x^24 + x^22 + 1
+
+17-12-36 341 x^928 + x^898 + x^870 + x^868 + x^860 + x^848 + x^838 + x^830 + x^829 + x^806 + x^798 + x^797 + x^789 + x^788 + x^772 + x^770 + x^767 + x^762 + x^761 + x^756 + x^751 + x^749 + x^748 + x^746 + x^742 + x^740 + x^738 + x^730 + x^726 + x^721 + x^718 + x^716 + x^714 + x^710 + x^709 + x^707 + x^706 + x^705 + x^696 + x^688 + x^684 + x^681 + x^677 + x^676 + x^674 + x^669 + x^666 + x^664 + x^659 + x^658 + x^657 + x^656 + x^655 + x^654 + x^651 + x^650 + x^647 + x^645 + x^639 + x^637 + x^636 + x^634 + x^631 + x^627 + x^625 + x^624 + x^622 + x^621 + x^619 + x^615 + x^614 + x^608 + x^605 + x^601 + x^599 + x^597 + x^596 + x^594 + x^593 + x^592 + x^591 + x^588 + x^587 + x^586 + x^585 + x^583 + x^582 + x^580 + x^578 + x^577 + x^576 + x^575 + x^574 + x^573 + x^572 + x^569 + x^568 + x^567 + x^565 + x^564 + x^561 + x^560 + x^559 + x^558 + x^557 + x^554 + x^553 + x^546 + x^545 + x^543 + x^542 + x^541 + x^539 + x^538 + x^536 + x^533 + x^530 + x^529 + x^527 + x^526 + x^525 + x^521 + x^520 + x^513 + x^509 + x^508 + x^504 + x^501 + x^500 + x^499 + x^498 + x^497 + x^496 + x^494 + x^488 + x^486 + x^484 + x^480 + x^479 + x^478 + x^475 + x^471 + x^469 + x^466 + x^463 + x^458 + x^456 + x^455 + x^452 + x^450 + x^449 + x^445 + x^437 + x^436 + x^433 + x^432 + x^430 + x^428 + x^426 + x^425 + x^423 + x^417 + x^416 + x^415 + x^413 + x^401 + x^400 + x^395 + x^394 + x^392 + x^391 + x^387 + x^386 + x^385 + x^384 + x^383 + x^379 + x^375 + x^373 + x^372 + x^371 + x^368 + x^366 + x^361 + x^360 + x^359 + x^358 + x^357 + x^354 + x^352 + x^350 + x^349 + x^348 + x^347 + x^345 + x^344 + x^343 + x^340 + x^334 + x^332 + x^330 + x^328 + x^327 + x^325 + x^323 + x^321 + x^318 + x^317 + x^316 + x^315 + x^314 + x^311 + x^310 + x^309 + x^308 + x^307 + x^306 + x^304 + x^299 + x^298 + x^296 + x^295 + x^294 + x^292 + x^291 + x^288 + x^287 + x^286 + x^282 + x^281 + x^280 + x^272 + x^271 + x^268 + x^267 + x^262 + x^256 + x^253 + x^252 + x^250 + x^244 + x^242 + x^241 + x^240 + x^238 + x^234 + x^233 + x^232 + x^231 + x^229 + x^228 + x^227 + x^226 + x^223 + x^222 + x^221 + x^220 + x^219 + x^218 + x^217 + x^215 + x^214 + x^212 + x^211 + x^208 + x^206 + x^203 + x^201 + x^199 + x^198 + x^195 + x^194 + x^193 + x^192 + x^189 + x^185 + x^182 + x^180 + x^179 + x^177 + x^176 + x^173 + x^172 + x^170 + x^164 + x^163 + x^160 + x^157 + x^155 + x^153 + x^152 + x^150 + x^147 + x^146 + x^139 + x^137 + x^132 + x^131 + x^127 + x^126 + x^125 + x^123 + x^122 + x^120 + x^115 + x^113 + x^111 + x^109 + x^107 + x^106 + x^104 + x^103 + x^101 + x^100 + x^99 + x^98 + x^97 + x^94 + x^88 + x^85 + x^78 + x^77 + x^76 + x^71 + x^68 + x^66 + x^64 + x^51 + x^47 + x^45 + x^39 + x^38 + x^36 + x^31 + x^30 + x^26 + x^24 + x^22 + x^20 + x^15 + 1
+
+2-30-27 343 x^928 + x^898 + x^881 + x^870 + x^868 + x^866 + x^851 + x^838 + x^819 + x^817 + x^808 + x^806 + x^804 + x^778 + x^776 + x^774 + x^772 + x^761 + x^759 + x^755 + x^753 + x^748 + x^742 + x^740 + x^731 + x^725 + x^718 + x^716 + x^712 + x^710 + x^706 + x^695 + x^693 + x^691 + x^689 + x^688 + x^682 + x^678 + x^674 + x^665 + x^663 + x^661 + x^658 + x^657 + x^652 + x^646 + x^644 + x^642 + x^641 + x^637 + x^629 + x^628 + x^627 + x^626 + x^625 + x^618 + x^616 + x^614 + x^612 + x^611 + x^610 + x^607 + x^601 + x^598 + x^597 + x^593 + x^592 + x^588 + x^580 + x^579 + x^577 + x^575 + x^573 + x^571 + x^569 + x^568 + x^566 + x^564 + x^563 + x^562 + x^561 + x^560 + x^554 + x^552 + x^550 + x^548 + x^543 + x^539 + x^538 + x^536 + x^534 + x^531 + x^530 + x^529 + x^528 + x^524 + x^521 + x^519 + x^517 + x^515 + x^513 + x^509 + x^508 + x^507 + x^505 + x^502 + x^500 + x^499 + x^498 + x^497 + x^492 + x^491 + x^487 + x^486 + x^484 + x^479 + x^478 + x^477 + x^476 + x^473 + x^470 + x^468 + x^466 + x^465 + x^464 + x^458 + x^454 + x^450 + x^448 + x^447 + x^446 + x^445 + x^439 + x^436 + x^435 + x^434 + x^433 + x^432 + x^428 + x^426 + x^422 + x^420 + x^416 + x^415 + x^413 + x^411 + x^409 + x^407 + x^406 + x^404 + x^399 + x^396 + x^392 + x^389 + x^384 + x^383 + x^382 + x^381 + x^379 + x^377 + x^376 + x^374 + x^372 + x^370 + x^367 + x^359 + x^355 + x^352 + x^347 + x^346 + x^344 + x^342 + x^341 + x^339 + x^338 + x^336 + x^335 + x^334 + x^328 + x^327 + x^324 + x^320 + x^318 + x^316 + x^314 + x^313 + x^309 + x^308 + x^304 + x^303 + x^300 + x^298 + x^297 + x^296 + x^294 + x^292 + x^287 + x^286 + x^284 + x^283 + x^282 + x^278 + x^276 + x^272 + x^269 + x^266 + x^265 + x^264 + x^261 + x^256 + x^252 + x^250 + x^248 + x^247 + x^245 + x^244 + x^243 + x^242 + x^239 + x^238 + x^237 + x^236 + x^235 + x^234 + x^233 + x^231 + x^229 + x^226 + x^225 + x^224 + x^220 + x^219 + x^216 + x^213 + x^212 + x^210 + x^205 + x^204 + x^203 + x^201 + x^199 + x^197 + x^194 + x^192 + x^191 + x^190 + x^189 + x^188 + x^186 + x^184 + x^183 + x^182 + x^178 + x^177 + x^176 + x^175 + x^173 + x^171 + x^170 + x^169 + x^166 + x^165 + x^163 + x^162 + x^161 + x^157 + x^156 + x^155 + x^153 + x^152 + x^150 + x^148 + x^147 + x^146 + x^144 + x^143 + x^141 + x^139 + x^137 + x^134 + x^133 + x^129 + x^128 + x^127 + x^126 + x^125 + x^123 + x^119 + x^117 + x^116 + x^115 + x^114 + x^113 + x^111 + x^110 + x^102 + x^101 + x^100 + x^99 + x^97 + x^96 + x^94 + x^93 + x^89 + x^88 + x^84 + x^83 + x^81 + x^78 + x^74 + x^72 + x^71 + x^69 + x^67 + x^62 + x^61 + x^59 + x^57 + x^56 + x^55 + x^53 + x^51 + x^47 + x^44 + x^42 + x^39 + x^37 + x^36 + x^35 + x^33 + x^30 + x^26 + x^24 + x^23 + x^21 + x^19 + x^18 + x^17 + x^16 + x^10 + x^8 + x^2 + 1
+
+26-55-39 345 x^928 + x^904 + x^898 + x^870 + x^861 + x^856 + x^851 + x^850 + x^831 + x^821 + x^820 + x^818 + x^813 + x^802 + x^796 + x^794 + x^790 + x^788 + x^783 + x^778 + x^775 + x^772 + x^770 + x^765 + x^760 + x^754 + x^746 + x^745 + x^741 + x^740 + x^736 + x^735 + x^734 + x^732 + x^731 + x^729 + x^727 + x^723 + x^722 + x^721 + x^716 + x^715 + x^710 + x^708 + x^705 + x^701 + x^699 + x^686 + x^685 + x^684 + x^681 + x^679 + x^678 + x^676 + x^674 + x^673 + x^672 + x^668 + x^664 + x^663 + x^661 + x^660 + x^658 + x^656 + x^650 + x^648 + x^645 + x^643 + x^641 + x^638 + x^637 + x^636 + x^632 + x^622 + x^621 + x^618 + x^616 + x^615 + x^614 + x^612 + x^608 + x^603 + x^600 + x^598 + x^595 + x^594 + x^593 + x^591 + x^590 + x^589 + x^588 + x^585 + x^582 + x^581 + x^576 + x^574 + x^571 + x^569 + x^568 + x^564 + x^562 + x^557 + x^556 + x^553 + x^550 + x^549 + x^548 + x^547 + x^546 + x^545 + x^544 + x^543 + x^538 + x^535 + x^530 + x^525 + x^520 + x^517 + x^515 + x^514 + x^510 + x^509 + x^506 + x^501 + x^497 + x^495 + x^489 + x^486 + x^484 + x^483 + x^482 + x^480 + x^479 + x^476 + x^474 + x^473 + x^471 + x^470 + x^469 + x^467 + x^464 + x^462 + x^460 + x^453 + x^452 + x^450 + x^449 + x^448 + x^446 + x^444 + x^443 + x^441 + x^436 + x^435 + x^434 + x^433 + x^432 + x^429 + x^428 + x^427 + x^424 + x^419 + x^418 + x^417 + x^416 + x^413 + x^412 + x^410 + x^407 + x^404 + x^403 + x^401 + x^399 + x^398 + x^397 + x^396 + x^394 + x^393 + x^392 + x^390 + x^386 + x^385 + x^383 + x^379 + x^378 + x^377 + x^376 + x^375 + x^373 + x^372 + x^366 + x^362 + x^359 + x^357 + x^355 + x^354 + x^351 + x^350 + x^347 + x^346 + x^344 + x^340 + x^339 + x^338 + x^337 + x^333 + x^332 + x^331 + x^330 + x^328 + x^326 + x^325 + x^323 + x^319 + x^315 + x^314 + x^313 + x^311 + x^310 + x^308 + x^307 + x^306 + x^304 + x^301 + x^300 + x^298 + x^296 + x^294 + x^293 + x^292 + x^291 + x^290 + x^286 + x^283 + x^280 + x^277 + x^274 + x^272 + x^265 + x^264 + x^263 + x^261 + x^260 + x^258 + x^255 + x^252 + x^251 + x^250 + x^249 + x^247 + x^245 + x^244 + x^241 + x^238 + x^235 + x^234 + x^230 + x^228 + x^225 + x^221 + x^218 + x^212 + x^211 + x^210 + x^208 + x^206 + x^204 + x^203 + x^202 + x^199 + x^198 + x^196 + x^195 + x^193 + x^188 + x^186 + x^184 + x^183 + x^177 + x^176 + x^167 + x^166 + x^165 + x^163 + x^161 + x^160 + x^158 + x^156 + x^153 + x^151 + x^146 + x^144 + x^141 + x^140 + x^134 + x^133 + x^129 + x^128 + x^127 + x^124 + x^123 + x^121 + x^119 + x^117 + x^115 + x^114 + x^113 + x^112 + x^111 + x^110 + x^109 + x^105 + x^104 + x^103 + x^100 + x^99 + x^93 + x^92 + x^91 + x^86 + x^84 + x^81 + x^80 + x^77 + x^75 + x^72 + x^71 + x^70 + x^68 + x^66 + x^65 + x^64 + x^61 + x^54 + x^53 + x^47 + x^45 + x^36 + x^35 + x^34 + x^32 + x^29 + x^18 + x^7 + 1
+
+40-36-23 345 x^928 + x^898 + x^886 + x^870 + x^862 + x^844 + x^838 + x^826 + x^820 + x^816 + x^814 + x^808 + x^797 + x^792 + x^791 + x^790 + x^784 + x^778 + x^777 + x^772 + x^768 + x^767 + x^766 + x^762 + x^761 + x^756 + x^753 + x^749 + x^747 + x^744 + x^742 + x^738 + x^735 + x^734 + x^726 + x^724 + x^723 + x^720 + x^712 + x^702 + x^701 + x^695 + x^689 + x^684 + x^683 + x^681 + x^677 + x^675 + x^670 + x^669 + x^664 + x^663 + x^660 + x^659 + x^658 + x^653 + x^648 + x^646 + x^644 + x^634 + x^629 + x^628 + x^627 + x^626 + x^625 + x^622 + x^621 + x^617 + x^616 + x^611 + x^609 + x^605 + x^604 + x^603 + x^602 + x^597 + x^595 + x^594 + x^593 + x^592 + x^586 + x^585 + x^584 + x^578 + x^575 + x^574 + x^573 + x^572 + x^571 + x^569 + x^565 + x^563 + x^561 + x^559 + x^557 + x^555 + x^554 + x^547 + x^545 + x^543 + x^539 + x^537 + x^536 + x^535 + x^534 + x^529 + x^528 + x^527 + x^525 + x^524 + x^521 + x^520 + x^519 + x^518 + x^517 + x^515 + x^514 + x^512 + x^510 + x^509 + x^508 + x^507 + x^506 + x^504 + x^503 + x^501 + x^499 + x^496 + x^494 + x^490 + x^489 + x^487 + x^485 + x^484 + x^482 + x^481 + x^480 + x^479 + x^478 + x^477 + x^475 + x^473 + x^470 + x^466 + x^465 + x^464 + x^463 + x^460 + x^457 + x^456 + x^454 + x^453 + x^452 + x^447 + x^446 + x^442 + x^441 + x^439 + x^436 + x^434 + x^432 + x^430 + x^428 + x^427 + x^423 + x^421 + x^416 + x^415 + x^414 + x^413 + x^411 + x^408 + x^405 + x^402 + x^401 + x^399 + x^396 + x^394 + x^393 + x^391 + x^390 + x^389 + x^388 + x^387 + x^386 + x^384 + x^381 + x^379 + x^378 + x^377 + x^375 + x^374 + x^372 + x^369 + x^367 + x^366 + x^364 + x^363 + x^361 + x^360 + x^359 + x^358 + x^356 + x^355 + x^354 + x^353 + x^352 + x^349 + x^345 + x^343 + x^342 + x^338 + x^336 + x^335 + x^334 + x^333 + x^331 + x^329 + x^328 + x^327 + x^320 + x^318 + x^317 + x^316 + x^312 + x^307 + x^304 + x^303 + x^300 + x^298 + x^296 + x^295 + x^294 + x^293 + x^291 + x^290 + x^288 + x^287 + x^286 + x^285 + x^284 + x^276 + x^275 + x^274 + x^273 + x^272 + x^271 + x^269 + x^268 + x^266 + x^263 + x^262 + x^259 + x^257 + x^255 + x^254 + x^251 + x^248 + x^246 + x^244 + x^240 + x^238 + x^237 + x^235 + x^234 + x^232 + x^228 + x^226 + x^225 + x^224 + x^222 + x^220 + x^217 + x^213 + x^212 + x^211 + x^209 + x^208 + x^207 + x^202 + x^200 + x^199 + x^198 + x^192 + x^190 + x^187 + x^183 + x^182 + x^180 + x^175 + x^172 + x^171 + x^170 + x^169 + x^167 + x^166 + x^165 + x^164 + x^163 + x^160 + x^157 + x^154 + x^153 + x^152 + x^150 + x^149 + x^148 + x^147 + x^146 + x^144 + x^142 + x^140 + x^137 + x^136 + x^134 + x^132 + x^129 + x^128 + x^124 + x^119 + x^117 + x^116 + x^115 + x^110 + x^108 + x^106 + x^103 + x^98 + x^88 + x^82 + x^76 + x^75 + x^74 + x^69 + x^68 + x^64 + x^62 + x^51 + x^47 + x^46 + x^39 + x^32 + x^23 + x^22 + 1
+
+24-36-37 347 x^928 + x^898 + x^878 + x^870 + x^854 + x^830 + x^824 + x^821 + x^818 + x^816 + x^813 + x^808 + x^806 + x^800 + x^792 + x^791 + x^789 + x^783 + x^780 + x^778 + x^776 + x^768 + x^765 + x^759 + x^753 + x^750 + x^747 + x^745 + x^744 + x^741 + x^740 + x^736 + x^734 + x^729 + x^721 + x^717 + x^715 + x^714 + x^708 + x^705 + x^704 + x^702 + x^699 + x^694 + x^690 + x^688 + x^684 + x^682 + x^681 + x^680 + x^679 + x^670 + x^669 + x^666 + x^664 + x^663 + x^660 + x^652 + x^649 + x^646 + x^645 + x^643 + x^639 + x^636 + x^634 + x^633 + x^631 + x^629 + x^627 + x^622 + x^621 + x^620 + x^614 + x^613 + x^612 + x^611 + x^610 + x^609 + x^605 + x^603 + x^601 + x^600 + x^599 + x^596 + x^593 + x^590 + x^587 + x^586 + x^585 + x^584 + x^583 + x^582 + x^581 + x^579 + x^577 + x^573 + x^565 + x^564 + x^563 + x^562 + x^561 + x^560 + x^559 + x^558 + x^557 + x^554 + x^550 + x^549 + x^546 + x^545 + x^544 + x^543 + x^542 + x^539 + x^538 + x^536 + x^535 + x^534 + x^529 + x^527 + x^525 + x^524 + x^523 + x^521 + x^519 + x^518 + x^516 + x^515 + x^512 + x^510 + x^505 + x^504 + x^503 + x^501 + x^500 + x^499 + x^493 + x^492 + x^488 + x^484 + x^483 + x^479 + x^474 + x^472 + x^470 + x^465 + x^464 + x^459 + x^457 + x^455 + x^454 + x^450 + x^440 + x^435 + x^434 + x^433 + x^427 + x^426 + x^424 + x^421 + x^420 + x^419 + x^414 + x^413 + x^412 + x^409 + x^407 + x^406 + x^405 + x^403 + x^401 + x^400 + x^399 + x^398 + x^395 + x^393 + x^391 + x^390 + x^388 + x^383 + x^381 + x^376 + x^374 + x^370 + x^367 + x^365 + x^363 + x^359 + x^356 + x^355 + x^353 + x^352 + x^348 + x^347 + x^346 + x^345 + x^344 + x^343 + x^342 + x^339 + x^336 + x^330 + x^327 + x^326 + x^325 + x^324 + x^323 + x^321 + x^318 + x^316 + x^315 + x^314 + x^312 + x^311 + x^310 + x^302 + x^300 + x^298 + x^295 + x^294 + x^292 + x^284 + x^282 + x^279 + x^278 + x^277 + x^276 + x^271 + x^268 + x^267 + x^266 + x^265 + x^264 + x^262 + x^260 + x^256 + x^253 + x^250 + x^249 + x^248 + x^244 + x^243 + x^242 + x^239 + x^236 + x^235 + x^232 + x^231 + x^229 + x^227 + x^226 + x^222 + x^220 + x^219 + x^216 + x^215 + x^214 + x^213 + x^211 + x^209 + x^208 + x^204 + x^202 + x^200 + x^199 + x^198 + x^196 + x^193 + x^191 + x^190 + x^189 + x^188 + x^187 + x^186 + x^179 + x^178 + x^177 + x^176 + x^175 + x^174 + x^170 + x^169 + x^167 + x^163 + x^162 + x^161 + x^160 + x^153 + x^150 + x^149 + x^147 + x^145 + x^140 + x^138 + x^136 + x^135 + x^133 + x^131 + x^130 + x^128 + x^127 + x^119 + x^117 + x^113 + x^111 + x^110 + x^108 + x^104 + x^103 + x^102 + x^101 + x^100 + x^99 + x^97 + x^96 + x^93 + x^88 + x^87 + x^86 + x^85 + x^84 + x^83 + x^82 + x^80 + x^78 + x^77 + x^72 + x^71 + x^70 + x^67 + x^66 + x^64 + x^63 + x^62 + x^61 + x^59 + x^58 + x^56 + x^54 + x^53 + x^50 + x^47 + x^46 + x^38 + x^24 + x^16 + 1
+
+26-38-9 353 x^928 + x^898 + x^875 + x^870 + x^848 + x^822 + x^808 + x^806 + x^800 + x^798 + x^797 + x^795 + x^792 + x^788 + x^778 + x^776 + x^769 + x^767 + x^765 + x^762 + x^758 + x^756 + x^747 + x^741 + x^732 + x^730 + x^728 + x^727 + x^723 + x^719 + x^714 + x^712 + x^711 + x^709 + x^706 + x^703 + x^700 + x^697 + x^695 + x^689 + x^688 + x^686 + x^684 + x^682 + x^680 + x^678 + x^676 + x^674 + x^673 + x^667 + x^666 + x^664 + x^661 + x^658 + x^653 + x^652 + x^649 + x^648 + x^646 + x^645 + x^635 + x^634 + x^633 + x^629 + x^626 + x^625 + x^620 + x^616 + x^614 + x^612 + x^611 + x^610 + x^607 + x^606 + x^604 + x^603 + x^599 + x^595 + x^594 + x^591 + x^583 + x^580 + x^578 + x^577 + x^572 + x^569 + x^568 + x^567 + x^566 + x^564 + x^559 + x^558 + x^555 + x^554 + x^550 + x^549 + x^548 + x^543 + x^542 + x^541 + x^539 + x^533 + x^532 + x^531 + x^528 + x^527 + x^526 + x^523 + x^519 + x^518 + x^515 + x^514 + x^513 + x^512 + x^511 + x^510 + x^509 + x^508 + x^507 + x^506 + x^502 + x^497 + x^495 + x^491 + x^488 + x^487 + x^485 + x^483 + x^482 + x^481 + x^478 + x^477 + x^476 + x^475 + x^473 + x^469 + x^466 + x^463 + x^462 + x^460 + x^458 + x^457 + x^456 + x^451 + x^447 + x^444 + x^443 + x^442 + x^440 + x^438 + x^437 + x^435 + x^433 + x^432 + x^430 + x^427 + x^424 + x^418 + x^417 + x^416 + x^414 + x^410 + x^409 + x^403 + x^401 + x^398 + x^397 + x^396 + x^394 + x^393 + x^391 + x^389 + x^388 + x^386 + x^385 + x^384 + x^382 + x^381 + x^380 + x^375 + x^374 + x^368 + x^364 + x^363 + x^359 + x^358 + x^357 + x^356 + x^354 + x^350 + x^349 + x^347 + x^346 + x^339 + x^337 + x^336 + x^334 + x^332 + x^330 + x^329 + x^328 + x^327 + x^326 + x^325 + x^324 + x^320 + x^318 + x^317 + x^315 + x^313 + x^309 + x^307 + x^305 + x^304 + x^303 + x^300 + x^299 + x^295 + x^293 + x^290 + x^288 + x^286 + x^285 + x^281 + x^279 + x^277 + x^274 + x^273 + x^269 + x^267 + x^266 + x^265 + x^263 + x^262 + x^257 + x^256 + x^255 + x^251 + x^249 + x^247 + x^246 + x^243 + x^241 + x^237 + x^236 + x^233 + x^230 + x^228 + x^227 + x^226 + x^225 + x^224 + x^223 + x^222 + x^221 + x^220 + x^212 + x^211 + x^210 + x^209 + x^208 + x^205 + x^204 + x^202 + x^201 + x^200 + x^197 + x^192 + x^191 + x^186 + x^184 + x^183 + x^181 + x^177 + x^175 + x^174 + x^170 + x^167 + x^165 + x^164 + x^162 + x^156 + x^154 + x^149 + x^148 + x^147 + x^144 + x^143 + x^142 + x^141 + x^139 + x^138 + x^137 + x^133 + x^131 + x^130 + x^128 + x^127 + x^126 + x^120 + x^116 + x^115 + x^113 + x^111 + x^108 + x^107 + x^105 + x^101 + x^99 + x^97 + x^95 + x^91 + x^90 + x^88 + x^87 + x^85 + x^81 + x^79 + x^78 + x^75 + x^72 + x^71 + x^70 + x^69 + x^66 + x^65 + x^63 + x^59 + x^57 + x^55 + x^54 + x^52 + x^51 + x^50 + x^49 + x^46 + x^44 + x^43 + x^39 + x^36 + x^34 + x^33 + x^32 + x^31 + x^30 + x^26 + x^24 + x^22 + x^16 + x^14 + x^8 + x^6 + 1
+
+31-6-30 353 x^928 + x^898 + x^870 + x^834 + x^814 + x^796 + x^790 + x^788 + x^784 + x^774 + x^772 + x^770 + x^762 + x^760 + x^756 + x^748 + x^740 + x^734 + x^732 + x^728 + x^727 + x^726 + x^718 + x^716 + x^712 + x^707 + x^701 + x^700 + x^697 + x^692 + x^688 + x^686 + x^684 + x^682 + x^681 + x^678 + x^677 + x^676 + x^674 + x^671 + x^670 + x^668 + x^665 + x^660 + x^658 + x^655 + x^652 + x^651 + x^650 + x^649 + x^646 + x^642 + x^641 + x^639 + x^638 + x^637 + x^636 + x^635 + x^630 + x^625 + x^624 + x^623 + x^622 + x^621 + x^620 + x^619 + x^617 + x^612 + x^611 + x^610 + x^609 + x^608 + x^607 + x^606 + x^604 + x^601 + x^598 + x^597 + x^593 + x^592 + x^591 + x^590 + x^582 + x^579 + x^578 + x^572 + x^570 + x^567 + x^566 + x^565 + x^563 + x^561 + x^559 + x^558 + x^555 + x^554 + x^544 + x^543 + x^542 + x^540 + x^539 + x^536 + x^533 + x^529 + x^528 + x^525 + x^522 + x^517 + x^516 + x^512 + x^511 + x^510 + x^507 + x^505 + x^502 + x^501 + x^499 + x^494 + x^492 + x^491 + x^489 + x^488 + x^487 + x^486 + x^484 + x^483 + x^481 + x^480 + x^476 + x^473 + x^469 + x^468 + x^466 + x^465 + x^464 + x^457 + x^451 + x^449 + x^448 + x^445 + x^444 + x^441 + x^440 + x^438 + x^436 + x^435 + x^433 + x^432 + x^431 + x^428 + x^425 + x^422 + x^420 + x^418 + x^414 + x^413 + x^412 + x^411 + x^410 + x^406 + x^405 + x^402 + x^401 + x^400 + x^394 + x^390 + x^389 + x^387 + x^384 + x^382 + x^380 + x^376 + x^375 + x^372 + x^371 + x^370 + x^369 + x^366 + x^363 + x^362 + x^361 + x^359 + x^357 + x^356 + x^354 + x^352 + x^351 + x^349 + x^347 + x^346 + x^344 + x^343 + x^342 + x^341 + x^340 + x^338 + x^337 + x^336 + x^334 + x^333 + x^331 + x^328 + x^323 + x^322 + x^318 + x^315 + x^313 + x^312 + x^310 + x^309 + x^308 + x^307 + x^301 + x^300 + x^298 + x^296 + x^295 + x^294 + x^292 + x^287 + x^285 + x^284 + x^283 + x^282 + x^279 + x^276 + x^275 + x^272 + x^270 + x^269 + x^268 + x^267 + x^263 + x^261 + x^259 + x^258 + x^256 + x^250 + x^248 + x^247 + x^246 + x^245 + x^244 + x^240 + x^239 + x^238 + x^237 + x^236 + x^235 + x^232 + x^231 + x^230 + x^229 + x^226 + x^223 + x^220 + x^217 + x^216 + x^213 + x^212 + x^210 + x^208 + x^205 + x^204 + x^201 + x^195 + x^194 + x^192 + x^191 + x^189 + x^188 + x^182 + x^181 + x^177 + x^175 + x^174 + x^173 + x^171 + x^169 + x^167 + x^162 + x^161 + x^159 + x^158 + x^154 + x^153 + x^148 + x^146 + x^145 + x^144 + x^143 + x^142 + x^141 + x^140 + x^139 + x^138 + x^135 + x^134 + x^133 + x^122 + x^119 + x^118 + x^115 + x^111 + x^110 + x^108 + x^107 + x^106 + x^105 + x^101 + x^99 + x^97 + x^96 + x^95 + x^94 + x^93 + x^92 + x^90 + x^87 + x^84 + x^83 + x^80 + x^74 + x^73 + x^71 + x^70 + x^67 + x^66 + x^63 + x^55 + x^53 + x^52 + x^51 + x^49 + x^45 + x^44 + x^43 + x^40 + x^35 + x^34 + x^33 + x^32 + x^27 + x^25 + x^24 + x^22 + x^21 + x^20 + x^17 + x^16 + x^11 + x^4 + 1
+
+54-21-7 353 x^928 + x^898 + x^870 + x^861 + x^860 + x^859 + x^858 + x^846 + x^842 + x^837 + x^836 + x^835 + x^831 + x^830 + x^829 + x^828 + x^822 + x^818 + x^811 + x^810 + x^808 + x^807 + x^804 + x^798 + x^792 + x^788 + x^781 + x^778 + x^758 + x^756 + x^751 + x^750 + x^746 + x^745 + x^740 + x^739 + x^738 + x^722 + x^720 + x^716 + x^703 + x^701 + x^696 + x^695 + x^688 + x^686 + x^674 + x^666 + x^659 + x^658 + x^656 + x^655 + x^654 + x^649 + x^644 + x^643 + x^641 + x^637 + x^632 + x^630 + x^629 + x^626 + x^623 + x^621 + x^620 + x^618 + x^614 + x^613 + x^606 + x^601 + x^599 + x^597 + x^595 + x^592 + x^591 + x^589 + x^588 + x^586 + x^584 + x^582 + x^577 + x^576 + x^575 + x^568 + x^567 + x^565 + x^564 + x^562 + x^558 + x^556 + x^553 + x^551 + x^550 + x^548 + x^547 + x^541 + x^540 + x^535 + x^534 + x^528 + x^527 + x^526 + x^522 + x^521 + x^520 + x^517 + x^514 + x^512 + x^510 + x^504 + x^503 + x^502 + x^498 + x^497 + x^496 + x^487 + x^482 + x^474 + x^473 + x^469 + x^468 + x^466 + x^463 + x^462 + x^459 + x^454 + x^453 + x^452 + x^451 + x^447 + x^442 + x^441 + x^433 + x^431 + x^430 + x^429 + x^426 + x^424 + x^423 + x^422 + x^421 + x^419 + x^417 + x^415 + x^412 + x^411 + x^409 + x^405 + x^402 + x^397 + x^396 + x^393 + x^392 + x^391 + x^385 + x^384 + x^382 + x^381 + x^380 + x^370 + x^369 + x^367 + x^365 + x^364 + x^361 + x^359 + x^356 + x^355 + x^351 + x^350 + x^349 + x^343 + x^342 + x^341 + x^340 + x^339 + x^338 + x^336 + x^335 + x^333 + x^332 + x^331 + x^330 + x^326 + x^325 + x^324 + x^323 + x^318 + x^317 + x^315 + x^313 + x^310 + x^309 + x^306 + x^301 + x^300 + x^298 + x^295 + x^294 + x^293 + x^292 + x^291 + x^290 + x^289 + x^288 + x^282 + x^281 + x^278 + x^277 + x^276 + x^275 + x^273 + x^271 + x^268 + x^266 + x^265 + x^263 + x^261 + x^260 + x^259 + x^257 + x^252 + x^249 + x^247 + x^244 + x^243 + x^238 + x^236 + x^232 + x^231 + x^229 + x^228 + x^227 + x^226 + x^225 + x^224 + x^221 + x^220 + x^219 + x^215 + x^214 + x^211 + x^209 + x^207 + x^204 + x^201 + x^198 + x^196 + x^195 + x^194 + x^193 + x^191 + x^189 + x^186 + x^185 + x^182 + x^181 + x^179 + x^178 + x^174 + x^173 + x^172 + x^170 + x^168 + x^166 + x^164 + x^162 + x^160 + x^159 + x^156 + x^155 + x^154 + x^152 + x^151 + x^149 + x^148 + x^147 + x^146 + x^145 + x^143 + x^140 + x^134 + x^133 + x^130 + x^129 + x^128 + x^126 + x^124 + x^123 + x^122 + x^121 + x^119 + x^118 + x^117 + x^116 + x^115 + x^113 + x^110 + x^107 + x^106 + x^105 + x^104 + x^103 + x^102 + x^101 + x^99 + x^97 + x^96 + x^95 + x^94 + x^93 + x^92 + x^91 + x^90 + x^89 + x^86 + x^85 + x^82 + x^81 + x^80 + x^79 + x^78 + x^76 + x^73 + x^71 + x^69 + x^65 + x^63 + x^60 + x^58 + x^57 + x^56 + x^55 + x^54 + x^52 + x^49 + x^47 + x^46 + x^45 + x^43 + x^42 + x^40 + x^39 + x^38 + x^36 + x^33 + x^32 + x^28 + x^25 + x^19 + x^18 + x^7 + 1
+
+8-36-47 355 x^928 + x^898 + x^870 + x^860 + x^856 + x^830 + x^818 + x^814 + x^813 + x^808 + x^800 + x^797 + x^796 + x^792 + x^788 + x^783 + x^778 + x^776 + x^772 + x^771 + x^770 + x^767 + x^766 + x^762 + x^755 + x^750 + x^740 + x^737 + x^736 + x^734 + x^730 + x^729 + x^724 + x^719 + x^711 + x^710 + x^707 + x^706 + x^698 + x^693 + x^692 + x^690 + x^688 + x^687 + x^680 + x^676 + x^674 + x^673 + x^672 + x^669 + x^665 + x^663 + x^662 + x^658 + x^657 + x^656 + x^653 + x^651 + x^650 + x^648 + x^647 + x^642 + x^635 + x^632 + x^631 + x^630 + x^627 + x^625 + x^624 + x^623 + x^622 + x^620 + x^619 + x^618 + x^609 + x^600 + x^595 + x^593 + x^592 + x^591 + x^589 + x^587 + x^583 + x^582 + x^579 + x^578 + x^577 + x^574 + x^570 + x^566 + x^565 + x^561 + x^559 + x^558 + x^557 + x^556 + x^555 + x^552 + x^550 + x^548 + x^544 + x^542 + x^541 + x^540 + x^537 + x^536 + x^534 + x^533 + x^532 + x^531 + x^528 + x^527 + x^525 + x^524 + x^521 + x^519 + x^518 + x^517 + x^516 + x^515 + x^514 + x^513 + x^512 + x^511 + x^509 + x^507 + x^505 + x^504 + x^502 + x^501 + x^497 + x^496 + x^493 + x^492 + x^491 + x^490 + x^488 + x^486 + x^485 + x^480 + x^478 + x^476 + x^475 + x^473 + x^469 + x^468 + x^467 + x^466 + x^463 + x^462 + x^453 + x^452 + x^451 + x^449 + x^447 + x^446 + x^445 + x^444 + x^443 + x^440 + x^438 + x^437 + x^436 + x^435 + x^427 + x^426 + x^423 + x^421 + x^419 + x^416 + x^411 + x^410 + x^409 + x^408 + x^406 + x^405 + x^404 + x^403 + x^402 + x^400 + x^398 + x^397 + x^395 + x^391 + x^390 + x^389 + x^385 + x^384 + x^380 + x^378 + x^377 + x^374 + x^373 + x^372 + x^370 + x^367 + x^366 + x^365 + x^363 + x^361 + x^360 + x^354 + x^352 + x^351 + x^350 + x^347 + x^342 + x^339 + x^337 + x^334 + x^333 + x^330 + x^328 + x^326 + x^324 + x^323 + x^315 + x^314 + x^309 + x^306 + x^304 + x^302 + x^298 + x^297 + x^296 + x^295 + x^293 + x^291 + x^289 + x^284 + x^282 + x^281 + x^279 + x^275 + x^274 + x^273 + x^269 + x^267 + x^265 + x^263 + x^261 + x^260 + x^259 + x^257 + x^256 + x^254 + x^252 + x^248 + x^247 + x^246 + x^244 + x^243 + x^242 + x^241 + x^238 + x^235 + x^234 + x^232 + x^229 + x^227 + x^225 + x^224 + x^223 + x^219 + x^217 + x^215 + x^211 + x^208 + x^206 + x^205 + x^203 + x^200 + x^197 + x^195 + x^190 + x^189 + x^187 + x^185 + x^176 + x^174 + x^172 + x^169 + x^165 + x^160 + x^159 + x^158 + x^156 + x^155 + x^154 + x^153 + x^152 + x^150 + x^146 + x^141 + x^139 + x^137 + x^135 + x^132 + x^131 + x^130 + x^127 + x^124 + x^120 + x^119 + x^116 + x^114 + x^111 + x^110 + x^109 + x^108 + x^105 + x^102 + x^99 + x^98 + x^95 + x^94 + x^93 + x^92 + x^90 + x^87 + x^86 + x^76 + x^75 + x^74 + x^72 + x^70 + x^68 + x^67 + x^65 + x^64 + x^63 + x^60 + x^59 + x^58 + x^57 + x^54 + x^51 + x^50 + x^48 + x^46 + x^45 + x^44 + x^43 + x^41 + x^39 + x^38 + x^36 + x^30 + x^27 + x^26 + x^24 + x^18 + x^14 + x^12 + 1
+
+44-14-41 357 x^928 + x^898 + x^870 + x^856 + x^852 + x^847 + x^831 + x^822 + x^817 + x^814 + x^808 + x^796 + x^795 + x^792 + x^784 + x^778 + x^777 + x^775 + x^772 + x^771 + x^766 + x^763 + x^756 + x^754 + x^747 + x^746 + x^745 + x^744 + x^742 + x^736 + x^733 + x^732 + x^730 + x^727 + x^726 + x^724 + x^721 + x^717 + x^716 + x^715 + x^714 + x^711 + x^705 + x^704 + x^694 + x^693 + x^691 + x^684 + x^682 + x^678 + x^674 + x^670 + x^664 + x^662 + x^655 + x^653 + x^647 + x^645 + x^644 + x^643 + x^637 + x^636 + x^635 + x^633 + x^631 + x^627 + x^626 + x^625 + x^624 + x^620 + x^618 + x^605 + x^604 + x^603 + x^601 + x^597 + x^588 + x^585 + x^583 + x^578 + x^575 + x^574 + x^569 + x^568 + x^567 + x^566 + x^565 + x^563 + x^558 + x^556 + x^554 + x^553 + x^552 + x^551 + x^550 + x^548 + x^544 + x^543 + x^542 + x^539 + x^538 + x^537 + x^535 + x^533 + x^532 + x^530 + x^528 + x^525 + x^523 + x^521 + x^520 + x^516 + x^515 + x^514 + x^513 + x^510 + x^509 + x^506 + x^504 + x^502 + x^497 + x^496 + x^491 + x^487 + x^485 + x^484 + x^482 + x^481 + x^480 + x^473 + x^471 + x^470 + x^468 + x^466 + x^464 + x^463 + x^462 + x^461 + x^459 + x^458 + x^455 + x^452 + x^450 + x^449 + x^447 + x^446 + x^443 + x^442 + x^440 + x^438 + x^436 + x^435 + x^432 + x^429 + x^428 + x^423 + x^420 + x^418 + x^417 + x^416 + x^413 + x^412 + x^411 + x^410 + x^407 + x^406 + x^405 + x^403 + x^402 + x^401 + x^400 + x^397 + x^396 + x^393 + x^392 + x^391 + x^390 + x^389 + x^386 + x^385 + x^384 + x^382 + x^380 + x^378 + x^376 + x^371 + x^370 + x^369 + x^368 + x^365 + x^364 + x^363 + x^359 + x^358 + x^357 + x^356 + x^353 + x^351 + x^350 + x^349 + x^348 + x^346 + x^345 + x^343 + x^342 + x^340 + x^339 + x^338 + x^335 + x^333 + x^332 + x^327 + x^324 + x^322 + x^317 + x^316 + x^315 + x^313 + x^311 + x^308 + x^307 + x^306 + x^304 + x^303 + x^301 + x^300 + x^299 + x^296 + x^294 + x^293 + x^292 + x^291 + x^290 + x^289 + x^284 + x^281 + x^279 + x^278 + x^276 + x^275 + x^273 + x^272 + x^271 + x^269 + x^266 + x^264 + x^260 + x^258 + x^256 + x^255 + x^251 + x^250 + x^248 + x^247 + x^244 + x^243 + x^241 + x^240 + x^239 + x^236 + x^235 + x^233 + x^232 + x^230 + x^226 + x^224 + x^223 + x^221 + x^220 + x^218 + x^217 + x^216 + x^215 + x^211 + x^210 + x^209 + x^208 + x^206 + x^204 + x^201 + x^200 + x^197 + x^196 + x^192 + x^187 + x^185 + x^183 + x^182 + x^181 + x^179 + x^178 + x^177 + x^175 + x^173 + x^170 + x^169 + x^168 + x^166 + x^159 + x^158 + x^157 + x^155 + x^154 + x^150 + x^149 + x^146 + x^144 + x^139 + x^138 + x^134 + x^132 + x^131 + x^128 + x^125 + x^123 + x^122 + x^120 + x^119 + x^116 + x^115 + x^111 + x^110 + x^109 + x^108 + x^101 + x^100 + x^99 + x^97 + x^96 + x^93 + x^92 + x^90 + x^87 + x^77 + x^74 + x^71 + x^70 + x^63 + x^58 + x^56 + x^54 + x^53 + x^52 + x^51 + x^50 + x^46 + x^42 + x^40 + x^38 + x^37 + x^36 + x^30 + x^28 + x^26 + x^14 + x^12 + 1
+
+22-40-11 359 x^928 + x^898 + x^870 + x^829 + x^816 + x^814 + x^808 + x^803 + x^799 + x^786 + x^784 + x^778 + x^777 + x^773 + x^764 + x^762 + x^743 + x^738 + x^736 + x^734 + x^725 + x^723 + x^719 + x^713 + x^710 + x^708 + x^699 + x^691 + x^688 + x^686 + x^684 + x^682 + x^673 + x^672 + x^665 + x^661 + x^657 + x^656 + x^654 + x^652 + x^650 + x^648 + x^645 + x^644 + x^642 + x^639 + x^637 + x^633 + x^631 + x^630 + x^626 + x^624 + x^622 + x^621 + x^620 + x^619 + x^618 + x^615 + x^614 + x^612 + x^611 + x^609 + x^606 + x^605 + x^604 + x^603 + x^601 + x^600 + x^599 + x^598 + x^594 + x^591 + x^587 + x^586 + x^585 + x^582 + x^580 + x^578 + x^577 + x^576 + x^572 + x^562 + x^561 + x^559 + x^558 + x^557 + x^556 + x^554 + x^553 + x^552 + x^550 + x^549 + x^548 + x^545 + x^543 + x^541 + x^540 + x^537 + x^535 + x^534 + x^533 + x^531 + x^530 + x^528 + x^527 + x^526 + x^522 + x^521 + x^518 + x^517 + x^516 + x^515 + x^514 + x^512 + x^511 + x^510 + x^509 + x^508 + x^507 + x^501 + x^499 + x^494 + x^491 + x^490 + x^489 + x^488 + x^486 + x^484 + x^483 + x^481 + x^480 + x^479 + x^478 + x^476 + x^475 + x^474 + x^472 + x^471 + x^469 + x^468 + x^466 + x^465 + x^464 + x^463 + x^461 + x^459 + x^457 + x^450 + x^449 + x^448 + x^446 + x^445 + x^439 + x^438 + x^437 + x^436 + x^435 + x^433 + x^431 + x^430 + x^429 + x^427 + x^426 + x^423 + x^418 + x^417 + x^415 + x^413 + x^403 + x^402 + x^401 + x^399 + x^398 + x^397 + x^395 + x^394 + x^393 + x^386 + x^382 + x^379 + x^378 + x^377 + x^368 + x^367 + x^366 + x^364 + x^363 + x^362 + x^360 + x^359 + x^356 + x^354 + x^352 + x^344 + x^343 + x^342 + x^341 + x^340 + x^337 + x^336 + x^331 + x^330 + x^325 + x^323 + x^321 + x^320 + x^319 + x^318 + x^315 + x^313 + x^311 + x^310 + x^308 + x^306 + x^303 + x^302 + x^300 + x^298 + x^297 + x^296 + x^294 + x^293 + x^292 + x^291 + x^290 + x^288 + x^286 + x^285 + x^283 + x^278 + x^277 + x^275 + x^274 + x^273 + x^271 + x^269 + x^268 + x^267 + x^265 + x^261 + x^260 + x^259 + x^257 + x^256 + x^255 + x^254 + x^251 + x^249 + x^248 + x^245 + x^244 + x^242 + x^240 + x^238 + x^237 + x^236 + x^231 + x^229 + x^227 + x^225 + x^224 + x^223 + x^222 + x^221 + x^216 + x^215 + x^213 + x^211 + x^205 + x^202 + x^196 + x^194 + x^193 + x^192 + x^191 + x^190 + x^184 + x^180 + x^179 + x^178 + x^177 + x^176 + x^175 + x^174 + x^171 + x^169 + x^164 + x^162 + x^161 + x^160 + x^155 + x^153 + x^149 + x^143 + x^142 + x^139 + x^138 + x^135 + x^134 + x^133 + x^132 + x^130 + x^128 + x^127 + x^126 + x^124 + x^123 + x^120 + x^118 + x^117 + x^115 + x^114 + x^113 + x^112 + x^111 + x^109 + x^108 + x^107 + x^104 + x^103 + x^101 + x^98 + x^95 + x^93 + x^92 + x^89 + x^88 + x^86 + x^82 + x^80 + x^76 + x^75 + x^69 + x^67 + x^65 + x^64 + x^60 + x^58 + x^57 + x^55 + x^53 + x^50 + x^49 + x^47 + x^46 + x^45 + x^44 + x^43 + x^42 + x^39 + x^37 + x^36 + x^35 + x^34 + x^32 + x^24 + x^22 + x^20 + 1
+
+33-20-8 359 x^928 + x^898 + x^874 + x^870 + x^845 + x^840 + x^824 + x^808 + x^794 + x^790 + x^787 + x^786 + x^780 + x^778 + x^764 + x^762 + x^761 + x^760 + x^756 + x^752 + x^741 + x^737 + x^736 + x^734 + x^731 + x^729 + x^728 + x^726 + x^720 + x^716 + x^712 + x^710 + x^707 + x^706 + x^703 + x^700 + x^697 + x^696 + x^688 + x^686 + x^683 + x^682 + x^681 + x^675 + x^671 + x^669 + x^667 + x^666 + x^660 + x^658 + x^657 + x^654 + x^653 + x^652 + x^649 + x^647 + x^646 + x^640 + x^639 + x^637 + x^636 + x^634 + x^629 + x^628 + x^627 + x^625 + x^624 + x^618 + x^613 + x^609 + x^608 + x^607 + x^600 + x^598 + x^597 + x^596 + x^595 + x^594 + x^593 + x^592 + x^591 + x^589 + x^587 + x^586 + x^585 + x^583 + x^582 + x^581 + x^580 + x^579 + x^577 + x^570 + x^567 + x^562 + x^554 + x^553 + x^550 + x^549 + x^548 + x^547 + x^546 + x^545 + x^544 + x^542 + x^539 + x^537 + x^535 + x^533 + x^531 + x^530 + x^524 + x^523 + x^521 + x^520 + x^517 + x^516 + x^512 + x^511 + x^504 + x^503 + x^502 + x^501 + x^497 + x^494 + x^492 + x^490 + x^489 + x^486 + x^480 + x^478 + x^477 + x^476 + x^475 + x^472 + x^467 + x^465 + x^463 + x^462 + x^461 + x^460 + x^459 + x^458 + x^456 + x^452 + x^449 + x^447 + x^446 + x^442 + x^440 + x^439 + x^438 + x^437 + x^436 + x^435 + x^434 + x^433 + x^432 + x^431 + x^430 + x^429 + x^426 + x^425 + x^423 + x^422 + x^421 + x^420 + x^415 + x^414 + x^413 + x^412 + x^411 + x^410 + x^408 + x^404 + x^402 + x^400 + x^399 + x^398 + x^395 + x^394 + x^392 + x^390 + x^387 + x^386 + x^385 + x^383 + x^379 + x^377 + x^376 + x^374 + x^373 + x^372 + x^371 + x^368 + x^366 + x^365 + x^362 + x^361 + x^360 + x^359 + x^358 + x^350 + x^347 + x^342 + x^341 + x^338 + x^337 + x^335 + x^331 + x^330 + x^326 + x^325 + x^322 + x^321 + x^320 + x^319 + x^318 + x^317 + x^312 + x^311 + x^308 + x^307 + x^305 + x^303 + x^301 + x^298 + x^295 + x^292 + x^289 + x^286 + x^282 + x^280 + x^277 + x^273 + x^271 + x^270 + x^265 + x^263 + x^262 + x^261 + x^260 + x^257 + x^253 + x^252 + x^251 + x^249 + x^248 + x^247 + x^246 + x^245 + x^243 + x^240 + x^239 + x^236 + x^234 + x^230 + x^228 + x^226 + x^225 + x^224 + x^222 + x^220 + x^219 + x^218 + x^215 + x^214 + x^213 + x^210 + x^205 + x^203 + x^201 + x^195 + x^194 + x^192 + x^191 + x^187 + x^185 + x^184 + x^183 + x^181 + x^178 + x^176 + x^174 + x^173 + x^172 + x^171 + x^170 + x^168 + x^165 + x^164 + x^163 + x^160 + x^157 + x^155 + x^154 + x^153 + x^152 + x^151 + x^150 + x^149 + x^148 + x^139 + x^138 + x^135 + x^134 + x^132 + x^131 + x^129 + x^128 + x^127 + x^126 + x^125 + x^122 + x^121 + x^119 + x^118 + x^115 + x^114 + x^111 + x^110 + x^106 + x^103 + x^101 + x^99 + x^98 + x^95 + x^91 + x^90 + x^89 + x^83 + x^78 + x^77 + x^75 + x^74 + x^70 + x^65 + x^64 + x^61 + x^56 + x^55 + x^52 + x^51 + x^49 + x^46 + x^41 + x^38 + x^36 + x^35 + x^34 + x^32 + x^29 + x^28 + x^27 + x^23 + x^16 + x^12 + x^8 + x^4 + 1
+
+6-42-43 359 x^928 + x^898 + x^877 + x^870 + x^847 + x^846 + x^844 + x^822 + x^808 + x^799 + x^794 + x^793 + x^790 + x^786 + x^778 + x^775 + x^774 + x^772 + x^771 + x^769 + x^766 + x^764 + x^750 + x^749 + x^748 + x^747 + x^744 + x^743 + x^742 + x^739 + x^736 + x^724 + x^721 + x^718 + x^715 + x^712 + x^710 + x^706 + x^702 + x^699 + x^695 + x^693 + x^692 + x^689 + x^687 + x^685 + x^684 + x^683 + x^682 + x^679 + x^674 + x^671 + x^670 + x^668 + x^667 + x^664 + x^662 + x^653 + x^652 + x^650 + x^649 + x^645 + x^644 + x^642 + x^639 + x^638 + x^637 + x^634 + x^633 + x^630 + x^624 + x^622 + x^619 + x^618 + x^616 + x^614 + x^613 + x^611 + x^610 + x^609 + x^608 + x^603 + x^601 + x^598 + x^595 + x^592 + x^589 + x^587 + x^586 + x^585 + x^584 + x^583 + x^582 + x^578 + x^574 + x^572 + x^568 + x^567 + x^565 + x^562 + x^561 + x^559 + x^558 + x^557 + x^555 + x^554 + x^550 + x^549 + x^547 + x^545 + x^541 + x^534 + x^528 + x^527 + x^523 + x^520 + x^518 + x^515 + x^510 + x^503 + x^502 + x^501 + x^500 + x^499 + x^498 + x^497 + x^496 + x^495 + x^494 + x^492 + x^489 + x^486 + x^483 + x^482 + x^479 + x^476 + x^475 + x^473 + x^472 + x^468 + x^467 + x^465 + x^464 + x^463 + x^461 + x^459 + x^458 + x^455 + x^452 + x^451 + x^450 + x^449 + x^448 + x^446 + x^445 + x^444 + x^443 + x^441 + x^440 + x^437 + x^434 + x^431 + x^430 + x^429 + x^425 + x^423 + x^422 + x^421 + x^419 + x^418 + x^417 + x^411 + x^408 + x^406 + x^405 + x^403 + x^401 + x^398 + x^397 + x^396 + x^393 + x^390 + x^382 + x^378 + x^376 + x^373 + x^372 + x^370 + x^369 + x^366 + x^361 + x^359 + x^358 + x^356 + x^354 + x^352 + x^351 + x^350 + x^349 + x^348 + x^347 + x^344 + x^340 + x^339 + x^336 + x^335 + x^333 + x^332 + x^329 + x^325 + x^324 + x^322 + x^321 + x^317 + x^316 + x^311 + x^310 + x^309 + x^303 + x^302 + x^301 + x^299 + x^298 + x^295 + x^294 + x^290 + x^289 + x^288 + x^287 + x^283 + x^282 + x^280 + x^279 + x^278 + x^277 + x^272 + x^271 + x^270 + x^268 + x^263 + x^261 + x^260 + x^259 + x^257 + x^256 + x^254 + x^250 + x^248 + x^247 + x^245 + x^244 + x^243 + x^241 + x^239 + x^238 + x^237 + x^235 + x^231 + x^230 + x^229 + x^228 + x^226 + x^225 + x^224 + x^221 + x^219 + x^217 + x^214 + x^210 + x^209 + x^208 + x^205 + x^204 + x^202 + x^199 + x^196 + x^191 + x^190 + x^189 + x^186 + x^184 + x^183 + x^180 + x^179 + x^178 + x^177 + x^175 + x^174 + x^170 + x^168 + x^167 + x^166 + x^165 + x^164 + x^162 + x^161 + x^160 + x^159 + x^157 + x^154 + x^153 + x^151 + x^143 + x^137 + x^135 + x^134 + x^129 + x^127 + x^126 + x^122 + x^121 + x^119 + x^118 + x^113 + x^111 + x^106 + x^104 + x^101 + x^100 + x^99 + x^98 + x^96 + x^92 + x^91 + x^90 + x^83 + x^82 + x^81 + x^79 + x^75 + x^74 + x^72 + x^71 + x^68 + x^64 + x^63 + x^60 + x^57 + x^56 + x^54 + x^52 + x^51 + x^49 + x^48 + x^46 + x^45 + x^43 + x^42 + x^39 + x^38 + x^37 + x^36 + x^32 + x^28 + x^26 + x^24 + x^16 + x^14 + 1
+
+33-22-4 361 x^928 + x^898 + x^870 + x^832 + x^822 + x^812 + x^808 + x^805 + x^802 + x^792 + x^784 + x^778 + x^775 + x^774 + x^762 + x^757 + x^756 + x^754 + x^746 + x^744 + x^740 + x^738 + x^736 + x^732 + x^728 + x^726 + x^720 + x^716 + x^711 + x^701 + x^697 + x^692 + x^684 + x^682 + x^680 + x^678 + x^673 + x^672 + x^671 + x^670 + x^658 + x^655 + x^653 + x^652 + x^651 + x^644 + x^637 + x^636 + x^630 + x^626 + x^622 + x^615 + x^613 + x^612 + x^611 + x^610 + x^608 + x^607 + x^606 + x^600 + x^599 + x^594 + x^593 + x^592 + x^590 + x^589 + x^588 + x^587 + x^586 + x^585 + x^583 + x^580 + x^578 + x^577 + x^574 + x^569 + x^567 + x^564 + x^562 + x^561 + x^559 + x^554 + x^553 + x^552 + x^549 + x^548 + x^544 + x^543 + x^538 + x^537 + x^536 + x^535 + x^533 + x^530 + x^525 + x^524 + x^523 + x^522 + x^521 + x^519 + x^517 + x^516 + x^515 + x^514 + x^511 + x^507 + x^506 + x^500 + x^499 + x^498 + x^496 + x^494 + x^487 + x^486 + x^485 + x^483 + x^480 + x^473 + x^468 + x^466 + x^465 + x^464 + x^463 + x^461 + x^460 + x^454 + x^452 + x^448 + x^447 + x^445 + x^441 + x^440 + x^439 + x^438 + x^436 + x^435 + x^434 + x^433 + x^429 + x^427 + x^425 + x^423 + x^421 + x^420 + x^418 + x^416 + x^415 + x^413 + x^411 + x^410 + x^409 + x^408 + x^404 + x^402 + x^401 + x^399 + x^397 + x^396 + x^393 + x^391 + x^390 + x^388 + x^387 + x^386 + x^383 + x^381 + x^380 + x^379 + x^376 + x^375 + x^374 + x^371 + x^370 + x^369 + x^368 + x^366 + x^364 + x^363 + x^361 + x^359 + x^356 + x^355 + x^354 + x^353 + x^350 + x^349 + x^344 + x^341 + x^338 + x^337 + x^336 + x^335 + x^332 + x^330 + x^329 + x^328 + x^327 + x^323 + x^322 + x^319 + x^318 + x^315 + x^314 + x^313 + x^309 + x^308 + x^307 + x^306 + x^304 + x^303 + x^301 + x^300 + x^298 + x^296 + x^295 + x^294 + x^292 + x^290 + x^289 + x^288 + x^286 + x^284 + x^282 + x^280 + x^279 + x^278 + x^275 + x^273 + x^271 + x^268 + x^266 + x^262 + x^261 + x^259 + x^258 + x^256 + x^255 + x^254 + x^253 + x^250 + x^245 + x^241 + x^240 + x^239 + x^237 + x^235 + x^234 + x^232 + x^231 + x^229 + x^226 + x^225 + x^221 + x^220 + x^218 + x^217 + x^215 + x^213 + x^211 + x^209 + x^206 + x^205 + x^201 + x^200 + x^196 + x^195 + x^192 + x^189 + x^188 + x^187 + x^186 + x^184 + x^183 + x^181 + x^180 + x^178 + x^177 + x^176 + x^175 + x^174 + x^172 + x^171 + x^169 + x^166 + x^165 + x^162 + x^160 + x^157 + x^154 + x^152 + x^150 + x^149 + x^145 + x^141 + x^138 + x^137 + x^133 + x^131 + x^129 + x^127 + x^125 + x^124 + x^123 + x^120 + x^118 + x^117 + x^115 + x^114 + x^112 + x^109 + x^108 + x^105 + x^102 + x^100 + x^99 + x^97 + x^96 + x^91 + x^90 + x^88 + x^87 + x^86 + x^85 + x^82 + x^80 + x^79 + x^77 + x^75 + x^74 + x^70 + x^66 + x^65 + x^63 + x^62 + x^61 + x^60 + x^59 + x^54 + x^52 + x^50 + x^49 + x^46 + x^42 + x^41 + x^40 + x^39 + x^38 + x^37 + x^36 + x^35 + x^33 + x^31 + x^27 + x^26 + x^22 + x^21 + x^19 + x^16 + x^14 + x^12 + 1
+
+46-48-7 361 x^928 + x^898 + x^870 + x^862 + x^848 + x^837 + x^829 + x^820 + x^815 + x^808 + x^807 + x^806 + x^802 + x^799 + x^798 + x^795 + x^790 + x^788 + x^787 + x^785 + x^776 + x^769 + x^765 + x^762 + x^760 + x^756 + x^755 + x^740 + x^739 + x^737 + x^732 + x^730 + x^727 + x^725 + x^717 + x^715 + x^714 + x^710 + x^709 + x^706 + x^704 + x^695 + x^688 + x^687 + x^686 + x^684 + x^682 + x^680 + x^679 + x^678 + x^676 + x^675 + x^667 + x^664 + x^661 + x^658 + x^657 + x^655 + x^654 + x^653 + x^652 + x^650 + x^649 + x^647 + x^646 + x^644 + x^643 + x^638 + x^637 + x^636 + x^634 + x^633 + x^627 + x^624 + x^623 + x^622 + x^620 + x^619 + x^618 + x^615 + x^612 + x^611 + x^606 + x^604 + x^601 + x^594 + x^591 + x^590 + x^589 + x^588 + x^587 + x^585 + x^583 + x^580 + x^575 + x^574 + x^572 + x^571 + x^569 + x^568 + x^567 + x^564 + x^563 + x^558 + x^557 + x^556 + x^552 + x^551 + x^546 + x^544 + x^542 + x^541 + x^535 + x^534 + x^532 + x^531 + x^530 + x^529 + x^528 + x^526 + x^525 + x^523 + x^521 + x^519 + x^518 + x^516 + x^514 + x^513 + x^506 + x^505 + x^504 + x^499 + x^498 + x^497 + x^496 + x^495 + x^493 + x^491 + x^490 + x^488 + x^487 + x^486 + x^485 + x^484 + x^481 + x^480 + x^477 + x^476 + x^473 + x^472 + x^471 + x^466 + x^465 + x^463 + x^462 + x^461 + x^460 + x^459 + x^455 + x^451 + x^449 + x^448 + x^447 + x^446 + x^444 + x^443 + x^441 + x^440 + x^439 + x^437 + x^431 + x^429 + x^428 + x^426 + x^424 + x^421 + x^420 + x^419 + x^418 + x^417 + x^416 + x^414 + x^411 + x^410 + x^408 + x^407 + x^406 + x^405 + x^403 + x^402 + x^401 + x^400 + x^397 + x^394 + x^392 + x^390 + x^388 + x^382 + x^381 + x^379 + x^378 + x^377 + x^376 + x^374 + x^367 + x^364 + x^363 + x^360 + x^357 + x^356 + x^354 + x^353 + x^352 + x^351 + x^350 + x^348 + x^343 + x^342 + x^341 + x^337 + x^334 + x^333 + x^330 + x^326 + x^316 + x^313 + x^309 + x^306 + x^305 + x^300 + x^299 + x^296 + x^294 + x^293 + x^292 + x^287 + x^285 + x^282 + x^281 + x^278 + x^276 + x^275 + x^271 + x^269 + x^267 + x^263 + x^262 + x^261 + x^260 + x^257 + x^256 + x^255 + x^253 + x^249 + x^248 + x^244 + x^243 + x^242 + x^240 + x^239 + x^238 + x^236 + x^235 + x^234 + x^231 + x^226 + x^224 + x^221 + x^217 + x^216 + x^214 + x^211 + x^210 + x^209 + x^208 + x^206 + x^205 + x^202 + x^200 + x^197 + x^196 + x^195 + x^190 + x^186 + x^184 + x^183 + x^181 + x^176 + x^172 + x^171 + x^167 + x^166 + x^165 + x^164 + x^159 + x^157 + x^154 + x^153 + x^151 + x^150 + x^146 + x^145 + x^144 + x^142 + x^141 + x^140 + x^139 + x^137 + x^136 + x^134 + x^131 + x^130 + x^129 + x^125 + x^124 + x^123 + x^120 + x^118 + x^117 + x^111 + x^110 + x^108 + x^107 + x^106 + x^105 + x^98 + x^96 + x^95 + x^94 + x^92 + x^88 + x^83 + x^81 + x^78 + x^76 + x^72 + x^71 + x^67 + x^66 + x^65 + x^63 + x^60 + x^58 + x^57 + x^56 + x^52 + x^51 + x^49 + x^48 + x^46 + x^44 + x^40 + x^38 + x^34 + x^33 + x^32 + x^31 + x^30 + x^28 + x^20 + 1
+
+49-44-52 361 x^928 + x^898 + x^870 + x^864 + x^842 + x^837 + x^834 + x^812 + x^810 + x^808 + x^804 + x^788 + x^786 + x^783 + x^782 + x^780 + x^778 + x^774 + x^758 + x^756 + x^753 + x^752 + x^734 + x^732 + x^729 + x^727 + x^724 + x^723 + x^722 + x^717 + x^704 + x^702 + x^699 + x^696 + x^693 + x^692 + x^690 + x^680 + x^678 + x^672 + x^667 + x^665 + x^663 + x^662 + x^661 + x^660 + x^650 + x^646 + x^637 + x^636 + x^633 + x^631 + x^626 + x^621 + x^618 + x^616 + x^614 + x^612 + x^611 + x^610 + x^609 + x^605 + x^603 + x^602 + x^601 + x^599 + x^597 + x^596 + x^594 + x^589 + x^588 + x^586 + x^576 + x^575 + x^573 + x^572 + x^571 + x^569 + x^568 + x^565 + x^562 + x^561 + x^560 + x^558 + x^557 + x^555 + x^554 + x^551 + x^549 + x^548 + x^543 + x^542 + x^539 + x^536 + x^532 + x^529 + x^528 + x^527 + x^526 + x^525 + x^518 + x^517 + x^514 + x^513 + x^512 + x^511 + x^509 + x^508 + x^506 + x^505 + x^499 + x^496 + x^495 + x^493 + x^492 + x^491 + x^489 + x^486 + x^483 + x^482 + x^479 + x^477 + x^476 + x^474 + x^468 + x^467 + x^462 + x^461 + x^457 + x^456 + x^454 + x^453 + x^452 + x^451 + x^449 + x^444 + x^442 + x^441 + x^439 + x^438 + x^437 + x^436 + x^432 + x^431 + x^429 + x^428 + x^427 + x^425 + x^424 + x^423 + x^422 + x^420 + x^419 + x^418 + x^416 + x^414 + x^413 + x^409 + x^407 + x^406 + x^404 + x^403 + x^402 + x^401 + x^395 + x^394 + x^393 + x^392 + x^390 + x^389 + x^387 + x^386 + x^384 + x^380 + x^378 + x^377 + x^376 + x^372 + x^371 + x^370 + x^369 + x^365 + x^363 + x^362 + x^361 + x^358 + x^357 + x^356 + x^355 + x^352 + x^351 + x^350 + x^347 + x^346 + x^344 + x^343 + x^342 + x^340 + x^339 + x^338 + x^332 + x^331 + x^328 + x^326 + x^325 + x^323 + x^322 + x^321 + x^319 + x^317 + x^316 + x^314 + x^313 + x^309 + x^305 + x^303 + x^301 + x^300 + x^299 + x^298 + x^297 + x^294 + x^292 + x^290 + x^285 + x^284 + x^282 + x^280 + x^279 + x^278 + x^276 + x^272 + x^267 + x^266 + x^265 + x^264 + x^263 + x^262 + x^259 + x^256 + x^254 + x^253 + x^251 + x^250 + x^249 + x^248 + x^247 + x^245 + x^243 + x^241 + x^240 + x^238 + x^234 + x^231 + x^229 + x^228 + x^227 + x^224 + x^222 + x^221 + x^215 + x^214 + x^211 + x^210 + x^209 + x^207 + x^206 + x^205 + x^204 + x^197 + x^196 + x^194 + x^192 + x^191 + x^189 + x^188 + x^187 + x^186 + x^182 + x^180 + x^178 + x^175 + x^172 + x^168 + x^167 + x^166 + x^163 + x^162 + x^158 + x^154 + x^153 + x^150 + x^148 + x^146 + x^145 + x^144 + x^138 + x^136 + x^132 + x^131 + x^130 + x^129 + x^124 + x^122 + x^120 + x^116 + x^115 + x^113 + x^112 + x^109 + x^108 + x^107 + x^106 + x^103 + x^102 + x^101 + x^99 + x^98 + x^97 + x^96 + x^94 + x^92 + x^90 + x^86 + x^85 + x^84 + x^83 + x^82 + x^80 + x^79 + x^77 + x^76 + x^65 + x^60 + x^59 + x^57 + x^54 + x^52 + x^47 + x^45 + x^44 + x^42 + x^38 + x^37 + x^34 + x^33 + x^31 + x^29 + x^26 + x^25 + x^24 + x^22 + x^21 + x^19 + x^18 + x^17 + x^15 + x^14 + x^12 + x^10 + 1
+
+34-42-39 365 x^928 + x^898 + x^870 + x^860 + x^850 + x^840 + x^831 + x^830 + x^811 + x^808 + x^801 + x^800 + x^792 + x^790 + x^780 + x^778 + x^771 + x^770 + x^762 + x^753 + x^744 + x^742 + x^740 + x^734 + x^720 + x^715 + x^712 + x^710 + x^703 + x^702 + x^694 + x^693 + x^691 + x^688 + x^685 + x^682 + x^680 + x^676 + x^674 + x^672 + x^664 + x^663 + x^662 + x^660 + x^658 + x^657 + x^656 + x^653 + x^652 + x^650 + x^647 + x^646 + x^645 + x^643 + x^637 + x^634 + x^628 + x^627 + x^623 + x^622 + x^618 + x^617 + x^615 + x^614 + x^608 + x^607 + x^604 + x^603 + x^600 + x^597 + x^593 + x^592 + x^589 + x^588 + x^587 + x^586 + x^585 + x^584 + x^579 + x^578 + x^577 + x^574 + x^570 + x^567 + x^565 + x^563 + x^562 + x^560 + x^558 + x^555 + x^550 + x^549 + x^547 + x^544 + x^542 + x^541 + x^536 + x^533 + x^532 + x^529 + x^527 + x^526 + x^521 + x^520 + x^518 + x^517 + x^516 + x^514 + x^510 + x^509 + x^508 + x^506 + x^504 + x^503 + x^502 + x^501 + x^497 + x^496 + x^489 + x^488 + x^487 + x^486 + x^484 + x^481 + x^480 + x^476 + x^475 + x^473 + x^472 + x^471 + x^470 + x^467 + x^466 + x^463 + x^462 + x^459 + x^458 + x^457 + x^456 + x^453 + x^451 + x^450 + x^446 + x^445 + x^444 + x^443 + x^442 + x^439 + x^438 + x^437 + x^436 + x^433 + x^432 + x^430 + x^428 + x^427 + x^425 + x^421 + x^420 + x^413 + x^412 + x^411 + x^408 + x^406 + x^405 + x^404 + x^403 + x^401 + x^399 + x^398 + x^396 + x^391 + x^388 + x^385 + x^381 + x^378 + x^376 + x^375 + x^374 + x^372 + x^370 + x^368 + x^364 + x^363 + x^360 + x^359 + x^357 + x^354 + x^353 + x^350 + x^349 + x^348 + x^347 + x^346 + x^344 + x^343 + x^342 + x^340 + x^339 + x^337 + x^335 + x^334 + x^333 + x^331 + x^330 + x^329 + x^327 + x^326 + x^325 + x^324 + x^323 + x^321 + x^320 + x^317 + x^312 + x^310 + x^309 + x^303 + x^300 + x^298 + x^296 + x^295 + x^292 + x^291 + x^290 + x^288 + x^287 + x^286 + x^285 + x^284 + x^282 + x^278 + x^277 + x^275 + x^274 + x^273 + x^267 + x^266 + x^265 + x^264 + x^263 + x^262 + x^261 + x^260 + x^257 + x^254 + x^250 + x^249 + x^244 + x^243 + x^242 + x^239 + x^238 + x^237 + x^236 + x^231 + x^230 + x^229 + x^228 + x^226 + x^224 + x^223 + x^222 + x^221 + x^220 + x^217 + x^214 + x^213 + x^212 + x^211 + x^208 + x^207 + x^206 + x^205 + x^204 + x^202 + x^198 + x^197 + x^195 + x^194 + x^192 + x^189 + x^187 + x^186 + x^185 + x^181 + x^180 + x^179 + x^178 + x^175 + x^173 + x^170 + x^168 + x^167 + x^166 + x^165 + x^164 + x^157 + x^155 + x^154 + x^150 + x^149 + x^148 + x^144 + x^143 + x^140 + x^138 + x^137 + x^135 + x^134 + x^132 + x^126 + x^124 + x^123 + x^120 + x^119 + x^117 + x^115 + x^113 + x^105 + x^104 + x^102 + x^100 + x^97 + x^96 + x^94 + x^91 + x^88 + x^87 + x^85 + x^84 + x^83 + x^82 + x^80 + x^79 + x^77 + x^76 + x^69 + x^68 + x^64 + x^61 + x^60 + x^55 + x^53 + x^51 + x^50 + x^48 + x^45 + x^44 + x^43 + x^40 + x^39 + x^38 + x^37 + x^36 + x^34 + x^33 + x^30 + x^22 + x^20 + x^19 + x^18 + x^16 + x^14 + 1
+
+34-2-25 367 x^928 + x^898 + x^870 + x^868 + x^866 + x^850 + x^838 + x^832 + x^822 + x^820 + x^808 + x^804 + x^802 + x^797 + x^792 + x^790 + x^788 + x^786 + x^778 + x^770 + x^768 + x^767 + x^760 + x^754 + x^748 + x^747 + x^746 + x^744 + x^738 + x^736 + x^735 + x^728 + x^726 + x^720 + x^717 + x^712 + x^708 + x^696 + x^694 + x^692 + x^690 + x^688 + x^687 + x^685 + x^684 + x^678 + x^677 + x^675 + x^673 + x^669 + x^667 + x^662 + x^658 + x^657 + x^654 + x^652 + x^647 + x^643 + x^642 + x^640 + x^639 + x^638 + x^637 + x^634 + x^633 + x^624 + x^613 + x^612 + x^611 + x^610 + x^609 + x^607 + x^606 + x^603 + x^600 + x^598 + x^597 + x^593 + x^591 + x^590 + x^588 + x^587 + x^586 + x^584 + x^583 + x^582 + x^581 + x^577 + x^576 + x^574 + x^571 + x^570 + x^568 + x^567 + x^564 + x^563 + x^562 + x^560 + x^558 + x^557 + x^554 + x^553 + x^551 + x^549 + x^548 + x^547 + x^546 + x^545 + x^539 + x^538 + x^535 + x^533 + x^531 + x^530 + x^529 + x^527 + x^525 + x^524 + x^523 + x^522 + x^520 + x^517 + x^515 + x^514 + x^511 + x^510 + x^507 + x^506 + x^504 + x^503 + x^500 + x^499 + x^498 + x^496 + x^493 + x^491 + x^490 + x^489 + x^487 + x^485 + x^483 + x^482 + x^480 + x^478 + x^477 + x^474 + x^473 + x^471 + x^469 + x^468 + x^465 + x^464 + x^460 + x^459 + x^457 + x^455 + x^451 + x^450 + x^449 + x^447 + x^446 + x^442 + x^441 + x^438 + x^430 + x^428 + x^427 + x^426 + x^425 + x^421 + x^420 + x^417 + x^416 + x^415 + x^414 + x^411 + x^410 + x^409 + x^406 + x^405 + x^404 + x^402 + x^396 + x^394 + x^393 + x^390 + x^389 + x^388 + x^386 + x^384 + x^382 + x^381 + x^380 + x^379 + x^378 + x^377 + x^376 + x^374 + x^373 + x^372 + x^371 + x^369 + x^366 + x^365 + x^364 + x^363 + x^356 + x^354 + x^352 + x^351 + x^344 + x^342 + x^338 + x^336 + x^335 + x^334 + x^327 + x^323 + x^321 + x^319 + x^318 + x^317 + x^312 + x^308 + x^305 + x^303 + x^302 + x^301 + x^299 + x^298 + x^297 + x^289 + x^286 + x^285 + x^283 + x^277 + x^276 + x^275 + x^272 + x^271 + x^269 + x^268 + x^267 + x^266 + x^263 + x^258 + x^255 + x^254 + x^252 + x^251 + x^247 + x^246 + x^235 + x^233 + x^232 + x^229 + x^226 + x^225 + x^223 + x^220 + x^219 + x^216 + x^212 + x^210 + x^209 + x^208 + x^206 + x^205 + x^204 + x^202 + x^201 + x^200 + x^198 + x^196 + x^193 + x^190 + x^187 + x^185 + x^184 + x^182 + x^180 + x^179 + x^174 + x^173 + x^172 + x^171 + x^169 + x^167 + x^166 + x^165 + x^164 + x^159 + x^158 + x^156 + x^155 + x^154 + x^151 + x^150 + x^149 + x^148 + x^147 + x^146 + x^144 + x^143 + x^141 + x^137 + x^133 + x^132 + x^131 + x^130 + x^129 + x^126 + x^124 + x^123 + x^122 + x^118 + x^112 + x^111 + x^109 + x^108 + x^107 + x^105 + x^104 + x^103 + x^102 + x^99 + x^96 + x^93 + x^92 + x^91 + x^89 + x^86 + x^84 + x^83 + x^82 + x^81 + x^79 + x^77 + x^76 + x^75 + x^71 + x^70 + x^67 + x^65 + x^63 + x^53 + x^49 + x^44 + x^40 + x^38 + x^37 + x^36 + x^35 + x^34 + x^32 + x^31 + x^28 + x^26 + x^25 + x^24 + x^22 + x^18 + x^16 + x^10 + x^8 + x^4 + 1
+
+34-39-1 367 x^928 + x^898 + x^894 + x^874 + x^870 + x^864 + x^855 + x^844 + x^840 + x^835 + x^834 + x^825 + x^820 + x^815 + x^814 + x^808 + x^805 + x^804 + x^801 + x^800 + x^796 + x^790 + x^785 + x^784 + x^778 + x^776 + x^770 + x^766 + x^761 + x^760 + x^756 + x^754 + x^751 + x^750 + x^746 + x^741 + x^740 + x^735 + x^732 + x^731 + x^730 + x^727 + x^724 + x^722 + x^721 + x^720 + x^716 + x^715 + x^712 + x^706 + x^705 + x^700 + x^697 + x^694 + x^692 + x^688 + x^686 + x^685 + x^682 + x^677 + x^676 + x^672 + x^667 + x^664 + x^657 + x^655 + x^653 + x^651 + x^650 + x^648 + x^642 + x^638 + x^632 + x^631 + x^630 + x^628 + x^627 + x^625 + x^622 + x^620 + x^618 + x^617 + x^616 + x^612 + x^611 + x^602 + x^600 + x^598 + x^597 + x^591 + x^588 + x^586 + x^582 + x^581 + x^579 + x^578 + x^577 + x^574 + x^573 + x^572 + x^568 + x^566 + x^564 + x^560 + x^552 + x^541 + x^538 + x^537 + x^535 + x^534 + x^532 + x^531 + x^529 + x^528 + x^523 + x^522 + x^521 + x^519 + x^518 + x^516 + x^515 + x^510 + x^509 + x^508 + x^506 + x^504 + x^500 + x^499 + x^498 + x^497 + x^495 + x^492 + x^490 + x^489 + x^488 + x^484 + x^482 + x^477 + x^475 + x^474 + x^472 + x^471 + x^470 + x^469 + x^467 + x^466 + x^465 + x^464 + x^462 + x^461 + x^460 + x^457 + x^455 + x^454 + x^453 + x^448 + x^447 + x^446 + x^444 + x^443 + x^442 + x^441 + x^440 + x^437 + x^431 + x^430 + x^429 + x^426 + x^424 + x^423 + x^421 + x^419 + x^418 + x^417 + x^416 + x^412 + x^411 + x^409 + x^408 + x^407 + x^406 + x^405 + x^403 + x^402 + x^397 + x^395 + x^394 + x^389 + x^388 + x^384 + x^383 + x^382 + x^380 + x^379 + x^377 + x^376 + x^375 + x^374 + x^373 + x^372 + x^370 + x^369 + x^368 + x^367 + x^366 + x^361 + x^360 + x^359 + x^357 + x^355 + x^353 + x^350 + x^349 + x^344 + x^342 + x^341 + x^340 + x^338 + x^337 + x^336 + x^335 + x^334 + x^333 + x^332 + x^331 + x^329 + x^328 + x^326 + x^321 + x^320 + x^318 + x^317 + x^316 + x^313 + x^311 + x^310 + x^309 + x^306 + x^303 + x^302 + x^300 + x^299 + x^296 + x^295 + x^294 + x^293 + x^292 + x^291 + x^288 + x^287 + x^286 + x^284 + x^279 + x^276 + x^274 + x^270 + x^269 + x^268 + x^265 + x^264 + x^262 + x^259 + x^257 + x^256 + x^255 + x^251 + x^248 + x^247 + x^245 + x^244 + x^243 + x^240 + x^237 + x^234 + x^232 + x^230 + x^227 + x^224 + x^223 + x^219 + x^214 + x^212 + x^206 + x^204 + x^201 + x^198 + x^197 + x^194 + x^192 + x^190 + x^189 + x^186 + x^185 + x^182 + x^179 + x^178 + x^174 + x^172 + x^171 + x^168 + x^166 + x^163 + x^162 + x^161 + x^159 + x^158 + x^154 + x^153 + x^152 + x^151 + x^149 + x^148 + x^146 + x^143 + x^142 + x^140 + x^138 + x^137 + x^135 + x^134 + x^133 + x^132 + x^131 + x^128 + x^126 + x^125 + x^124 + x^123 + x^119 + x^118 + x^116 + x^115 + x^109 + x^108 + x^106 + x^105 + x^103 + x^100 + x^98 + x^91 + x^89 + x^86 + x^84 + x^83 + x^81 + x^79 + x^78 + x^70 + x^69 + x^67 + x^66 + x^65 + x^59 + x^58 + x^56 + x^48 + x^45 + x^43 + x^42 + x^38 + x^37 + x^34 + x^29 + x^26 + x^21 + x^10 + 1
+
+8-38-53 367 x^928 + x^898 + x^870 + x^843 + x^838 + x^833 + x^830 + x^820 + x^816 + x^811 + x^808 + x^800 + x^786 + x^781 + x^778 + x^773 + x^768 + x^760 + x^756 + x^752 + x^750 + x^743 + x^742 + x^738 + x^733 + x^732 + x^730 + x^728 + x^726 + x^723 + x^720 + x^718 + x^711 + x^710 + x^708 + x^700 + x^699 + x^698 + x^696 + x^695 + x^693 + x^691 + x^690 + x^688 + x^686 + x^685 + x^683 + x^681 + x^672 + x^670 + x^667 + x^666 + x^665 + x^664 + x^663 + x^662 + x^661 + x^658 + x^657 + x^655 + x^654 + x^650 + x^648 + x^646 + x^645 + x^644 + x^642 + x^640 + x^639 + x^638 + x^636 + x^634 + x^626 + x^622 + x^620 + x^617 + x^615 + x^614 + x^613 + x^612 + x^606 + x^605 + x^603 + x^600 + x^597 + x^596 + x^592 + x^591 + x^590 + x^589 + x^588 + x^585 + x^584 + x^581 + x^578 + x^577 + x^576 + x^575 + x^574 + x^572 + x^569 + x^568 + x^564 + x^562 + x^561 + x^556 + x^554 + x^551 + x^549 + x^544 + x^543 + x^542 + x^540 + x^539 + x^538 + x^533 + x^532 + x^530 + x^529 + x^527 + x^526 + x^524 + x^521 + x^520 + x^517 + x^515 + x^514 + x^510 + x^507 + x^504 + x^503 + x^502 + x^501 + x^500 + x^499 + x^498 + x^497 + x^495 + x^493 + x^489 + x^487 + x^486 + x^483 + x^482 + x^480 + x^477 + x^474 + x^471 + x^469 + x^468 + x^463 + x^461 + x^459 + x^456 + x^453 + x^450 + x^447 + x^443 + x^442 + x^441 + x^439 + x^438 + x^437 + x^436 + x^435 + x^431 + x^424 + x^422 + x^415 + x^411 + x^410 + x^409 + x^407 + x^406 + x^405 + x^404 + x^401 + x^400 + x^396 + x^395 + x^392 + x^391 + x^389 + x^388 + x^385 + x^382 + x^381 + x^380 + x^379 + x^377 + x^374 + x^369 + x^368 + x^367 + x^366 + x^365 + x^364 + x^359 + x^357 + x^353 + x^351 + x^349 + x^345 + x^344 + x^342 + x^341 + x^340 + x^339 + x^337 + x^335 + x^334 + x^333 + x^331 + x^330 + x^329 + x^327 + x^326 + x^324 + x^323 + x^322 + x^320 + x^319 + x^318 + x^314 + x^313 + x^312 + x^311 + x^309 + x^307 + x^304 + x^303 + x^300 + x^298 + x^294 + x^288 + x^285 + x^284 + x^281 + x^280 + x^279 + x^277 + x^276 + x^275 + x^273 + x^271 + x^270 + x^269 + x^268 + x^266 + x^261 + x^254 + x^253 + x^251 + x^250 + x^249 + x^248 + x^247 + x^245 + x^244 + x^242 + x^240 + x^238 + x^236 + x^233 + x^231 + x^230 + x^227 + x^226 + x^224 + x^223 + x^222 + x^221 + x^220 + x^219 + x^218 + x^216 + x^215 + x^213 + x^212 + x^209 + x^208 + x^207 + x^202 + x^198 + x^195 + x^189 + x^186 + x^183 + x^182 + x^180 + x^179 + x^177 + x^175 + x^172 + x^170 + x^168 + x^167 + x^159 + x^158 + x^154 + x^153 + x^150 + x^149 + x^144 + x^141 + x^140 + x^138 + x^136 + x^135 + x^134 + x^133 + x^132 + x^130 + x^129 + x^126 + x^125 + x^124 + x^123 + x^122 + x^121 + x^117 + x^116 + x^114 + x^113 + x^112 + x^111 + x^110 + x^108 + x^106 + x^105 + x^102 + x^98 + x^97 + x^96 + x^95 + x^92 + x^91 + x^90 + x^87 + x^79 + x^77 + x^74 + x^73 + x^72 + x^69 + x^64 + x^61 + x^60 + x^59 + x^58 + x^57 + x^56 + x^55 + x^53 + x^50 + x^49 + x^47 + x^46 + x^44 + x^43 + x^36 + x^35 + x^30 + x^29 + x^22 + x^16 + 1
+
+40-6-51 369 x^928 + x^898 + x^870 + x^859 + x^840 + x^830 + x^819 + x^790 + x^780 + x^779 + x^771 + x^770 + x^768 + x^761 + x^760 + x^757 + x^752 + x^750 + x^748 + x^742 + x^741 + x^740 + x^739 + x^738 + x^732 + x^728 + x^727 + x^721 + x^719 + x^718 + x^717 + x^712 + x^709 + x^708 + x^702 + x^699 + x^692 + x^690 + x^687 + x^684 + x^678 + x^677 + x^673 + x^672 + x^671 + x^668 + x^666 + x^659 + x^658 + x^657 + x^655 + x^654 + x^653 + x^652 + x^651 + x^648 + x^647 + x^645 + x^644 + x^643 + x^637 + x^636 + x^634 + x^632 + x^631 + x^624 + x^622 + x^621 + x^620 + x^616 + x^614 + x^613 + x^612 + x^611 + x^609 + x^608 + x^607 + x^598 + x^596 + x^594 + x^593 + x^592 + x^591 + x^588 + x^585 + x^583 + x^579 + x^578 + x^576 + x^575 + x^574 + x^573 + x^572 + x^571 + x^570 + x^567 + x^566 + x^563 + x^562 + x^560 + x^557 + x^555 + x^554 + x^549 + x^547 + x^546 + x^544 + x^542 + x^538 + x^537 + x^535 + x^534 + x^533 + x^531 + x^529 + x^527 + x^526 + x^522 + x^520 + x^518 + x^517 + x^515 + x^514 + x^513 + x^511 + x^510 + x^509 + x^508 + x^505 + x^504 + x^500 + x^497 + x^496 + x^494 + x^492 + x^481 + x^477 + x^475 + x^473 + x^471 + x^470 + x^468 + x^467 + x^466 + x^465 + x^464 + x^463 + x^462 + x^460 + x^457 + x^456 + x^453 + x^451 + x^450 + x^449 + x^447 + x^446 + x^444 + x^443 + x^441 + x^436 + x^435 + x^434 + x^429 + x^428 + x^427 + x^423 + x^422 + x^421 + x^419 + x^418 + x^416 + x^414 + x^413 + x^412 + x^410 + x^408 + x^406 + x^405 + x^402 + x^401 + x^400 + x^399 + x^398 + x^396 + x^395 + x^394 + x^393 + x^391 + x^390 + x^388 + x^385 + x^384 + x^382 + x^381 + x^379 + x^378 + x^377 + x^376 + x^375 + x^374 + x^373 + x^372 + x^371 + x^370 + x^367 + x^366 + x^365 + x^363 + x^360 + x^358 + x^355 + x^354 + x^353 + x^352 + x^350 + x^347 + x^344 + x^342 + x^340 + x^339 + x^338 + x^335 + x^334 + x^331 + x^330 + x^328 + x^324 + x^323 + x^322 + x^321 + x^318 + x^316 + x^315 + x^313 + x^307 + x^306 + x^304 + x^303 + x^301 + x^300 + x^299 + x^298 + x^297 + x^290 + x^287 + x^285 + x^283 + x^282 + x^281 + x^280 + x^279 + x^278 + x^276 + x^275 + x^274 + x^270 + x^264 + x^263 + x^262 + x^261 + x^259 + x^258 + x^254 + x^253 + x^252 + x^244 + x^242 + x^241 + x^240 + x^239 + x^237 + x^236 + x^235 + x^230 + x^228 + x^224 + x^220 + x^217 + x^214 + x^210 + x^209 + x^208 + x^206 + x^203 + x^202 + x^201 + x^200 + x^199 + x^196 + x^195 + x^194 + x^192 + x^189 + x^188 + x^186 + x^185 + x^184 + x^181 + x^176 + x^175 + x^173 + x^172 + x^171 + x^170 + x^165 + x^163 + x^161 + x^159 + x^156 + x^154 + x^153 + x^144 + x^143 + x^137 + x^135 + x^134 + x^132 + x^130 + x^129 + x^126 + x^125 + x^122 + x^120 + x^118 + x^114 + x^113 + x^110 + x^109 + x^108 + x^107 + x^98 + x^97 + x^95 + x^92 + x^88 + x^87 + x^86 + x^85 + x^84 + x^83 + x^80 + x^76 + x^74 + x^71 + x^70 + x^69 + x^64 + x^63 + x^62 + x^61 + x^57 + x^53 + x^52 + x^50 + x^46 + x^40 + x^38 + x^37 + x^34 + x^33 + x^32 + x^31 + x^28 + x^25 + x^22 + x^18 + x^6 + 1
+
+48-40-25 371 x^928 + x^898 + x^878 + x^870 + x^851 + x^844 + x^832 + x^828 + x^818 + x^809 + x^808 + x^802 + x^790 + x^782 + x^779 + x^772 + x^755 + x^751 + x^749 + x^744 + x^742 + x^740 + x^738 + x^732 + x^731 + x^728 + x^725 + x^719 + x^718 + x^714 + x^713 + x^712 + x^708 + x^705 + x^695 + x^691 + x^690 + x^688 + x^687 + x^686 + x^684 + x^683 + x^679 + x^676 + x^674 + x^671 + x^668 + x^665 + x^663 + x^662 + x^661 + x^656 + x^655 + x^652 + x^650 + x^649 + x^648 + x^647 + x^646 + x^641 + x^640 + x^638 + x^636 + x^635 + x^633 + x^630 + x^627 + x^626 + x^625 + x^624 + x^621 + x^620 + x^619 + x^618 + x^617 + x^614 + x^613 + x^608 + x^607 + x^606 + x^605 + x^604 + x^603 + x^602 + x^599 + x^597 + x^596 + x^591 + x^589 + x^586 + x^585 + x^584 + x^582 + x^578 + x^576 + x^572 + x^569 + x^566 + x^564 + x^558 + x^555 + x^553 + x^550 + x^549 + x^548 + x^545 + x^543 + x^541 + x^540 + x^538 + x^537 + x^533 + x^530 + x^527 + x^524 + x^523 + x^521 + x^520 + x^519 + x^517 + x^516 + x^515 + x^513 + x^510 + x^504 + x^503 + x^501 + x^500 + x^498 + x^497 + x^496 + x^494 + x^492 + x^491 + x^488 + x^485 + x^482 + x^478 + x^476 + x^474 + x^473 + x^471 + x^469 + x^468 + x^464 + x^461 + x^460 + x^459 + x^454 + x^450 + x^449 + x^448 + x^444 + x^439 + x^438 + x^437 + x^436 + x^435 + x^433 + x^431 + x^428 + x^426 + x^424 + x^420 + x^417 + x^416 + x^413 + x^411 + x^408 + x^407 + x^406 + x^403 + x^400 + x^399 + x^398 + x^397 + x^396 + x^392 + x^390 + x^389 + x^388 + x^387 + x^386 + x^385 + x^381 + x^378 + x^374 + x^370 + x^369 + x^368 + x^367 + x^365 + x^364 + x^359 + x^356 + x^354 + x^350 + x^348 + x^346 + x^344 + x^343 + x^342 + x^340 + x^338 + x^337 + x^334 + x^332 + x^330 + x^329 + x^327 + x^322 + x^317 + x^316 + x^314 + x^311 + x^308 + x^307 + x^301 + x^300 + x^299 + x^296 + x^295 + x^292 + x^291 + x^290 + x^286 + x^284 + x^282 + x^279 + x^278 + x^276 + x^273 + x^270 + x^269 + x^265 + x^263 + x^259 + x^258 + x^257 + x^256 + x^255 + x^253 + x^251 + x^249 + x^247 + x^245 + x^244 + x^243 + x^242 + x^241 + x^240 + x^238 + x^236 + x^231 + x^230 + x^229 + x^228 + x^226 + x^223 + x^221 + x^220 + x^219 + x^218 + x^217 + x^215 + x^214 + x^212 + x^211 + x^210 + x^208 + x^207 + x^206 + x^205 + x^202 + x^200 + x^198 + x^193 + x^192 + x^191 + x^187 + x^186 + x^184 + x^182 + x^179 + x^173 + x^171 + x^169 + x^168 + x^164 + x^163 + x^162 + x^161 + x^157 + x^156 + x^155 + x^154 + x^153 + x^151 + x^149 + x^147 + x^146 + x^145 + x^143 + x^140 + x^137 + x^136 + x^133 + x^127 + x^122 + x^121 + x^119 + x^115 + x^114 + x^112 + x^111 + x^110 + x^108 + x^104 + x^103 + x^101 + x^98 + x^94 + x^88 + x^87 + x^85 + x^83 + x^81 + x^80 + x^79 + x^78 + x^77 + x^75 + x^74 + x^73 + x^70 + x^69 + x^68 + x^67 + x^65 + x^63 + x^62 + x^60 + x^59 + x^58 + x^57 + x^56 + x^54 + x^53 + x^52 + x^50 + x^49 + x^47 + x^46 + x^45 + x^41 + x^39 + x^36 + x^34 + x^33 + x^32 + x^31 + x^30 + x^29 + x^28 + x^26 + x^25 + x^21 + x^16 + x^14 + x^4 + 1
+
+19-22-10 373 x^928 + x^898 + x^870 + x^866 + x^842 + x^836 + x^834 + x^821 + x^808 + x^807 + x^806 + x^804 + x^802 + x^794 + x^792 + x^782 + x^778 + x^777 + x^776 + x^770 + x^766 + x^761 + x^757 + x^753 + x^748 + x^743 + x^739 + x^738 + x^736 + x^735 + x^734 + x^732 + x^728 + x^725 + x^722 + x^721 + x^718 + x^716 + x^713 + x^711 + x^710 + x^709 + x^708 + x^705 + x^703 + x^702 + x^693 + x^686 + x^681 + x^680 + x^677 + x^664 + x^662 + x^659 + x^652 + x^651 + x^649 + x^646 + x^644 + x^643 + x^641 + x^638 + x^636 + x^629 + x^627 + x^625 + x^623 + x^622 + x^619 + x^617 + x^616 + x^615 + x^614 + x^612 + x^611 + x^609 + x^606 + x^605 + x^600 + x^597 + x^596 + x^595 + x^592 + x^591 + x^590 + x^586 + x^582 + x^580 + x^577 + x^576 + x^574 + x^572 + x^570 + x^569 + x^567 + x^565 + x^563 + x^562 + x^560 + x^557 + x^556 + x^555 + x^554 + x^552 + x^549 + x^548 + x^546 + x^545 + x^544 + x^542 + x^540 + x^538 + x^536 + x^534 + x^533 + x^532 + x^530 + x^528 + x^525 + x^520 + x^519 + x^518 + x^516 + x^514 + x^513 + x^511 + x^509 + x^504 + x^501 + x^497 + x^496 + x^495 + x^488 + x^487 + x^485 + x^482 + x^481 + x^480 + x^479 + x^478 + x^476 + x^475 + x^474 + x^472 + x^470 + x^468 + x^466 + x^465 + x^463 + x^458 + x^453 + x^451 + x^449 + x^448 + x^447 + x^446 + x^445 + x^444 + x^443 + x^439 + x^438 + x^437 + x^436 + x^433 + x^428 + x^424 + x^418 + x^417 + x^414 + x^412 + x^411 + x^408 + x^407 + x^406 + x^404 + x^403 + x^401 + x^400 + x^399 + x^396 + x^395 + x^393 + x^390 + x^389 + x^388 + x^387 + x^386 + x^385 + x^384 + x^382 + x^380 + x^379 + x^375 + x^371 + x^370 + x^369 + x^365 + x^363 + x^362 + x^357 + x^355 + x^354 + x^351 + x^348 + x^346 + x^345 + x^344 + x^342 + x^340 + x^338 + x^336 + x^334 + x^331 + x^328 + x^327 + x^326 + x^324 + x^323 + x^322 + x^320 + x^315 + x^308 + x^306 + x^298 + x^295 + x^292 + x^287 + x^286 + x^285 + x^284 + x^282 + x^281 + x^280 + x^279 + x^278 + x^276 + x^274 + x^273 + x^272 + x^270 + x^269 + x^268 + x^267 + x^265 + x^262 + x^258 + x^256 + x^253 + x^252 + x^251 + x^250 + x^246 + x^245 + x^244 + x^243 + x^242 + x^240 + x^239 + x^238 + x^237 + x^235 + x^232 + x^228 + x^226 + x^224 + x^217 + x^215 + x^213 + x^211 + x^210 + x^208 + x^206 + x^201 + x^199 + x^196 + x^195 + x^192 + x^190 + x^187 + x^186 + x^185 + x^184 + x^182 + x^180 + x^178 + x^175 + x^174 + x^173 + x^172 + x^165 + x^160 + x^159 + x^158 + x^157 + x^155 + x^154 + x^153 + x^148 + x^146 + x^145 + x^143 + x^142 + x^137 + x^135 + x^133 + x^132 + x^131 + x^128 + x^127 + x^124 + x^123 + x^122 + x^121 + x^117 + x^115 + x^114 + x^113 + x^112 + x^108 + x^107 + x^106 + x^105 + x^103 + x^102 + x^101 + x^100 + x^94 + x^93 + x^92 + x^89 + x^87 + x^86 + x^85 + x^83 + x^80 + x^79 + x^78 + x^77 + x^75 + x^74 + x^72 + x^70 + x^67 + x^66 + x^62 + x^61 + x^59 + x^58 + x^57 + x^55 + x^51 + x^50 + x^49 + x^42 + x^41 + x^39 + x^36 + x^34 + x^32 + x^30 + x^26 + x^24 + x^23 + x^22 + x^21 + x^18 + x^16 + x^14 + x^10 + x^9 + x^8 + x^2 + 1
+
+52-17-25 375 x^928 + x^898 + x^870 + x^861 + x^860 + x^859 + x^858 + x^849 + x^848 + x^847 + x^846 + x^842 + x^836 + x^835 + x^831 + x^830 + x^829 + x^828 + x^823 + x^822 + x^811 + x^810 + x^808 + x^807 + x^806 + x^804 + x^800 + x^799 + x^793 + x^792 + x^789 + x^788 + x^786 + x^780 + x^778 + x^777 + x^775 + x^774 + x^770 + x^769 + x^768 + x^764 + x^763 + x^762 + x^758 + x^757 + x^756 + x^755 + x^751 + x^750 + x^744 + x^740 + x^739 + x^738 + x^733 + x^731 + x^728 + x^721 + x^720 + x^716 + x^715 + x^714 + x^713 + x^710 + x^709 + x^702 + x^701 + x^697 + x^696 + x^695 + x^692 + x^688 + x^686 + x^684 + x^683 + x^680 + x^679 + x^678 + x^677 + x^674 + x^673 + x^672 + x^665 + x^662 + x^658 + x^654 + x^647 + x^643 + x^636 + x^635 + x^631 + x^628 + x^626 + x^625 + x^622 + x^621 + x^619 + x^618 + x^617 + x^614 + x^613 + x^612 + x^611 + x^609 + x^608 + x^598 + x^595 + x^591 + x^589 + x^588 + x^587 + x^586 + x^584 + x^582 + x^576 + x^574 + x^571 + x^569 + x^567 + x^564 + x^563 + x^560 + x^557 + x^550 + x^549 + x^548 + x^547 + x^546 + x^544 + x^539 + x^537 + x^536 + x^529 + x^527 + x^526 + x^523 + x^522 + x^521 + x^516 + x^513 + x^512 + x^509 + x^508 + x^505 + x^503 + x^502 + x^499 + x^493 + x^492 + x^491 + x^487 + x^486 + x^484 + x^482 + x^479 + x^478 + x^477 + x^475 + x^474 + x^471 + x^468 + x^467 + x^465 + x^463 + x^462 + x^461 + x^460 + x^455 + x^452 + x^445 + x^443 + x^442 + x^437 + x^433 + x^432 + x^429 + x^427 + x^426 + x^424 + x^423 + x^422 + x^421 + x^417 + x^411 + x^410 + x^408 + x^407 + x^403 + x^402 + x^400 + x^399 + x^393 + x^391 + x^390 + x^389 + x^386 + x^384 + x^381 + x^379 + x^375 + x^373 + x^372 + x^369 + x^367 + x^366 + x^364 + x^363 + x^362 + x^361 + x^360 + x^357 + x^356 + x^353 + x^352 + x^348 + x^345 + x^344 + x^342 + x^341 + x^340 + x^335 + x^332 + x^330 + x^329 + x^328 + x^327 + x^322 + x^321 + x^319 + x^318 + x^317 + x^315 + x^312 + x^311 + x^310 + x^308 + x^305 + x^302 + x^300 + x^299 + x^298 + x^297 + x^296 + x^292 + x^290 + x^289 + x^288 + x^286 + x^284 + x^283 + x^282 + x^281 + x^278 + x^277 + x^276 + x^274 + x^272 + x^269 + x^267 + x^263 + x^262 + x^260 + x^259 + x^256 + x^254 + x^253 + x^251 + x^250 + x^249 + x^248 + x^242 + x^241 + x^240 + x^235 + x^234 + x^231 + x^226 + x^225 + x^221 + x^219 + x^214 + x^212 + x^211 + x^209 + x^207 + x^206 + x^205 + x^202 + x^199 + x^198 + x^195 + x^190 + x^189 + x^187 + x^185 + x^182 + x^181 + x^180 + x^179 + x^177 + x^176 + x^175 + x^174 + x^171 + x^169 + x^165 + x^164 + x^163 + x^162 + x^161 + x^160 + x^155 + x^154 + x^153 + x^152 + x^146 + x^145 + x^142 + x^139 + x^137 + x^136 + x^128 + x^127 + x^124 + x^121 + x^120 + x^119 + x^117 + x^114 + x^113 + x^112 + x^110 + x^109 + x^108 + x^104 + x^102 + x^101 + x^99 + x^97 + x^87 + x^85 + x^84 + x^83 + x^82 + x^78 + x^76 + x^73 + x^72 + x^69 + x^64 + x^62 + x^59 + x^52 + x^51 + x^50 + x^49 + x^46 + x^45 + x^44 + x^42 + x^41 + x^40 + x^36 + x^35 + x^33 + x^28 + x^26 + x^25 + x^21 + x^19 + x^13 + x^12 + x^7 + x^6 + 1
+
+35-28-44 377 x^928 + x^898 + x^894 + x^870 + x^859 + x^829 + x^828 + x^825 + x^808 + x^804 + x^800 + x^799 + x^795 + x^794 + x^789 + x^778 + x^774 + x^769 + x^768 + x^759 + x^758 + x^755 + x^754 + x^748 + x^744 + x^739 + x^735 + x^734 + x^727 + x^726 + x^722 + x^718 + x^714 + x^713 + x^709 + x^708 + x^705 + x^704 + x^700 + x^694 + x^691 + x^690 + x^688 + x^687 + x^685 + x^682 + x^681 + x^675 + x^668 + x^665 + x^659 + x^657 + x^656 + x^655 + x^653 + x^652 + x^651 + x^649 + x^647 + x^644 + x^640 + x^638 + x^635 + x^634 + x^631 + x^630 + x^629 + x^628 + x^625 + x^624 + x^619 + x^617 + x^614 + x^613 + x^612 + x^611 + x^610 + x^608 + x^602 + x^599 + x^598 + x^593 + x^592 + x^591 + x^590 + x^586 + x^585 + x^583 + x^582 + x^581 + x^580 + x^579 + x^578 + x^576 + x^575 + x^573 + x^569 + x^566 + x^560 + x^559 + x^558 + x^557 + x^553 + x^552 + x^551 + x^549 + x^542 + x^536 + x^535 + x^533 + x^524 + x^522 + x^521 + x^520 + x^518 + x^517 + x^516 + x^515 + x^512 + x^509 + x^507 + x^506 + x^504 + x^502 + x^500 + x^499 + x^498 + x^497 + x^496 + x^491 + x^489 + x^485 + x^484 + x^483 + x^482 + x^481 + x^480 + x^477 + x^476 + x^474 + x^467 + x^466 + x^465 + x^462 + x^460 + x^459 + x^454 + x^450 + x^447 + x^446 + x^445 + x^443 + x^439 + x^434 + x^433 + x^432 + x^431 + x^430 + x^429 + x^428 + x^427 + x^426 + x^425 + x^424 + x^423 + x^421 + x^419 + x^417 + x^413 + x^412 + x^411 + x^409 + x^408 + x^407 + x^406 + x^405 + x^404 + x^403 + x^401 + x^400 + x^394 + x^389 + x^386 + x^383 + x^381 + x^380 + x^379 + x^378 + x^376 + x^375 + x^373 + x^372 + x^371 + x^369 + x^368 + x^367 + x^366 + x^365 + x^364 + x^362 + x^359 + x^356 + x^349 + x^347 + x^346 + x^345 + x^343 + x^342 + x^341 + x^340 + x^339 + x^338 + x^337 + x^336 + x^335 + x^332 + x^331 + x^330 + x^329 + x^325 + x^324 + x^320 + x^319 + x^318 + x^317 + x^316 + x^315 + x^311 + x^309 + x^307 + x^304 + x^303 + x^301 + x^300 + x^298 + x^297 + x^296 + x^295 + x^294 + x^292 + x^291 + x^289 + x^288 + x^285 + x^283 + x^282 + x^281 + x^274 + x^272 + x^271 + x^269 + x^262 + x^261 + x^260 + x^258 + x^257 + x^252 + x^251 + x^250 + x^249 + x^247 + x^246 + x^244 + x^241 + x^236 + x^234 + x^231 + x^230 + x^227 + x^226 + x^219 + x^218 + x^216 + x^215 + x^213 + x^206 + x^205 + x^204 + x^203 + x^202 + x^201 + x^200 + x^198 + x^196 + x^195 + x^194 + x^193 + x^192 + x^190 + x^186 + x^185 + x^184 + x^182 + x^176 + x^174 + x^167 + x^166 + x^164 + x^163 + x^162 + x^161 + x^159 + x^155 + x^154 + x^153 + x^151 + x^150 + x^146 + x^145 + x^143 + x^140 + x^138 + x^135 + x^131 + x^130 + x^129 + x^125 + x^124 + x^123 + x^118 + x^116 + x^113 + x^110 + x^107 + x^101 + x^100 + x^99 + x^95 + x^94 + x^93 + x^92 + x^91 + x^88 + x^86 + x^82 + x^81 + x^80 + x^79 + x^78 + x^76 + x^75 + x^73 + x^72 + x^71 + x^70 + x^69 + x^68 + x^67 + x^65 + x^63 + x^62 + x^60 + x^58 + x^57 + x^56 + x^55 + x^52 + x^50 + x^48 + x^46 + x^44 + x^42 + x^40 + x^39 + x^38 + x^33 + x^31 + x^30 + x^29 + x^28 + x^27 + x^24 + x^21 + x^16 + x^13 + x^8 + 1
+
+45-7-6 377 x^928 + x^898 + x^897 + x^870 + x^868 + x^854 + x^853 + x^850 + x^836 + x^835 + x^832 + x^821 + x^810 + x^809 + x^808 + x^807 + x^805 + x^803 + x^802 + x^801 + x^798 + x^794 + x^792 + x^791 + x^790 + x^780 + x^778 + x^775 + x^770 + x^767 + x^766 + x^765 + x^764 + x^760 + x^754 + x^750 + x^743 + x^740 + x^737 + x^735 + x^732 + x^726 + x^723 + x^722 + x^721 + x^720 + x^716 + x^714 + x^710 + x^707 + x^706 + x^703 + x^701 + x^700 + x^699 + x^695 + x^691 + x^689 + x^687 + x^686 + x^685 + x^683 + x^680 + x^676 + x^675 + x^672 + x^671 + x^670 + x^668 + x^667 + x^666 + x^665 + x^662 + x^658 + x^655 + x^653 + x^652 + x^648 + x^644 + x^643 + x^642 + x^637 + x^629 + x^628 + x^627 + x^626 + x^624 + x^621 + x^617 + x^616 + x^612 + x^610 + x^609 + x^608 + x^607 + x^603 + x^602 + x^600 + x^595 + x^594 + x^592 + x^591 + x^589 + x^586 + x^585 + x^582 + x^578 + x^576 + x^574 + x^573 + x^571 + x^570 + x^566 + x^563 + x^561 + x^560 + x^558 + x^557 + x^556 + x^555 + x^554 + x^553 + x^552 + x^551 + x^549 + x^548 + x^545 + x^538 + x^533 + x^530 + x^524 + x^520 + x^519 + x^512 + x^509 + x^508 + x^505 + x^503 + x^502 + x^497 + x^495 + x^493 + x^492 + x^486 + x^485 + x^484 + x^482 + x^480 + x^479 + x^477 + x^472 + x^470 + x^469 + x^466 + x^464 + x^462 + x^460 + x^459 + x^458 + x^456 + x^455 + x^454 + x^452 + x^451 + x^448 + x^446 + x^442 + x^441 + x^440 + x^437 + x^431 + x^430 + x^427 + x^426 + x^425 + x^424 + x^423 + x^420 + x^417 + x^415 + x^414 + x^413 + x^412 + x^410 + x^408 + x^406 + x^405 + x^404 + x^403 + x^401 + x^399 + x^395 + x^393 + x^392 + x^384 + x^381 + x^375 + x^370 + x^368 + x^367 + x^364 + x^363 + x^361 + x^360 + x^356 + x^355 + x^354 + x^353 + x^351 + x^349 + x^346 + x^343 + x^341 + x^340 + x^339 + x^335 + x^334 + x^333 + x^330 + x^328 + x^326 + x^325 + x^324 + x^323 + x^319 + x^318 + x^316 + x^315 + x^312 + x^306 + x^303 + x^302 + x^301 + x^299 + x^294 + x^292 + x^291 + x^290 + x^289 + x^283 + x^281 + x^276 + x^275 + x^274 + x^273 + x^271 + x^270 + x^269 + x^268 + x^267 + x^265 + x^264 + x^263 + x^262 + x^261 + x^260 + x^259 + x^258 + x^257 + x^255 + x^254 + x^253 + x^252 + x^250 + x^247 + x^246 + x^245 + x^243 + x^241 + x^240 + x^239 + x^235 + x^228 + x^224 + x^223 + x^220 + x^217 + x^216 + x^215 + x^209 + x^205 + x^204 + x^203 + x^202 + x^197 + x^196 + x^195 + x^192 + x^191 + x^189 + x^187 + x^183 + x^181 + x^180 + x^179 + x^178 + x^173 + x^172 + x^170 + x^165 + x^163 + x^161 + x^159 + x^156 + x^155 + x^153 + x^148 + x^146 + x^141 + x^138 + x^134 + x^133 + x^131 + x^130 + x^127 + x^126 + x^125 + x^123 + x^122 + x^119 + x^117 + x^116 + x^110 + x^109 + x^108 + x^107 + x^106 + x^95 + x^93 + x^92 + x^91 + x^88 + x^87 + x^86 + x^84 + x^82 + x^80 + x^79 + x^76 + x^75 + x^73 + x^72 + x^69 + x^68 + x^64 + x^63 + x^61 + x^59 + x^57 + x^55 + x^54 + x^53 + x^51 + x^49 + x^46 + x^43 + x^41 + x^40 + x^36 + x^35 + x^34 + x^33 + x^31 + x^27 + x^25 + x^23 + x^22 + x^21 + x^19 + x^15 + x^13 + x^12 + x^11 + x^10 + x^9 + x^8 + 1
+
+23-49-24 379 x^928 + x^898 + x^872 + x^870 + x^856 + x^843 + x^842 + x^827 + x^826 + x^824 + x^818 + x^813 + x^812 + x^811 + x^797 + x^796 + x^795 + x^792 + x^789 + x^788 + x^781 + x^780 + x^772 + x^767 + x^765 + x^759 + x^757 + x^752 + x^743 + x^742 + x^741 + x^740 + x^737 + x^735 + x^730 + x^729 + x^728 + x^727 + x^724 + x^722 + x^721 + x^720 + x^718 + x^714 + x^712 + x^710 + x^707 + x^706 + x^704 + x^703 + x^702 + x^700 + x^699 + x^698 + x^696 + x^694 + x^692 + x^691 + x^690 + x^689 + x^688 + x^686 + x^682 + x^681 + x^679 + x^677 + x^675 + x^674 + x^665 + x^663 + x^661 + x^660 + x^657 + x^656 + x^655 + x^651 + x^649 + x^647 + x^646 + x^644 + x^642 + x^640 + x^637 + x^635 + x^633 + x^625 + x^622 + x^620 + x^619 + x^617 + x^616 + x^615 + x^613 + x^612 + x^610 + x^609 + x^607 + x^606 + x^605 + x^601 + x^600 + x^597 + x^596 + x^595 + x^593 + x^592 + x^590 + x^588 + x^584 + x^583 + x^582 + x^579 + x^578 + x^574 + x^571 + x^570 + x^567 + x^566 + x^564 + x^561 + x^560 + x^559 + x^558 + x^554 + x^553 + x^547 + x^543 + x^539 + x^536 + x^535 + x^534 + x^533 + x^529 + x^527 + x^526 + x^525 + x^518 + x^516 + x^515 + x^510 + x^509 + x^508 + x^506 + x^505 + x^504 + x^503 + x^499 + x^498 + x^497 + x^495 + x^493 + x^491 + x^489 + x^488 + x^487 + x^486 + x^485 + x^484 + x^482 + x^479 + x^475 + x^473 + x^472 + x^469 + x^468 + x^464 + x^463 + x^462 + x^459 + x^457 + x^455 + x^453 + x^448 + x^446 + x^444 + x^443 + x^442 + x^438 + x^435 + x^431 + x^429 + x^427 + x^424 + x^423 + x^418 + x^416 + x^414 + x^406 + x^404 + x^403 + x^401 + x^397 + x^396 + x^390 + x^387 + x^384 + x^380 + x^377 + x^375 + x^373 + x^369 + x^366 + x^365 + x^364 + x^358 + x^356 + x^355 + x^354 + x^353 + x^352 + x^348 + x^346 + x^340 + x^338 + x^336 + x^334 + x^329 + x^326 + x^325 + x^322 + x^320 + x^318 + x^312 + x^307 + x^305 + x^302 + x^301 + x^299 + x^297 + x^296 + x^294 + x^293 + x^291 + x^288 + x^287 + x^286 + x^281 + x^278 + x^277 + x^276 + x^274 + x^273 + x^272 + x^271 + x^269 + x^268 + x^267 + x^266 + x^262 + x^261 + x^258 + x^256 + x^255 + x^253 + x^251 + x^250 + x^249 + x^248 + x^247 + x^243 + x^240 + x^237 + x^236 + x^235 + x^233 + x^231 + x^230 + x^223 + x^222 + x^220 + x^218 + x^216 + x^212 + x^211 + x^208 + x^207 + x^205 + x^203 + x^202 + x^201 + x^200 + x^199 + x^198 + x^197 + x^195 + x^193 + x^192 + x^191 + x^187 + x^186 + x^183 + x^181 + x^180 + x^179 + x^176 + x^174 + x^173 + x^169 + x^166 + x^161 + x^159 + x^158 + x^157 + x^156 + x^154 + x^152 + x^151 + x^149 + x^145 + x^144 + x^143 + x^142 + x^141 + x^139 + x^136 + x^135 + x^131 + x^128 + x^127 + x^126 + x^125 + x^123 + x^122 + x^120 + x^118 + x^117 + x^116 + x^114 + x^111 + x^110 + x^108 + x^107 + x^106 + x^103 + x^100 + x^99 + x^97 + x^96 + x^95 + x^93 + x^92 + x^91 + x^90 + x^87 + x^84 + x^81 + x^80 + x^79 + x^78 + x^77 + x^74 + x^73 + x^71 + x^67 + x^64 + x^61 + x^59 + x^58 + x^54 + x^49 + x^47 + x^44 + x^43 + x^41 + x^38 + x^37 + x^33 + x^30 + x^25 + x^17 + x^16 + x^15 + x^14 + x^12 + x^11 + x^8 + x^7 + x^4 + 1
+
+19-18-26 381 x^928 + x^898 + x^870 + x^844 + x^836 + x^832 + x^820 + x^814 + x^808 + x^802 + x^798 + x^794 + x^791 + x^790 + x^784 + x^778 + x^774 + x^770 + x^769 + x^766 + x^764 + x^761 + x^754 + x^748 + x^743 + x^734 + x^732 + x^731 + x^727 + x^726 + x^724 + x^723 + x^721 + x^718 + x^716 + x^715 + x^713 + x^711 + x^709 + x^706 + x^704 + x^703 + x^702 + x^701 + x^700 + x^699 + x^697 + x^696 + x^695 + x^693 + x^692 + x^691 + x^690 + x^685 + x^684 + x^676 + x^674 + x^667 + x^664 + x^663 + x^658 + x^657 + x^656 + x^654 + x^653 + x^651 + x^650 + x^646 + x^645 + x^644 + x^643 + x^639 + x^638 + x^637 + x^633 + x^631 + x^630 + x^627 + x^626 + x^625 + x^624 + x^620 + x^611 + x^610 + x^607 + x^606 + x^604 + x^603 + x^598 + x^597 + x^595 + x^593 + x^590 + x^589 + x^588 + x^586 + x^585 + x^584 + x^582 + x^580 + x^577 + x^575 + x^570 + x^569 + x^568 + x^563 + x^562 + x^561 + x^558 + x^557 + x^556 + x^555 + x^552 + x^551 + x^550 + x^548 + x^547 + x^546 + x^545 + x^542 + x^541 + x^540 + x^539 + x^538 + x^537 + x^535 + x^534 + x^533 + x^531 + x^530 + x^528 + x^523 + x^522 + x^521 + x^517 + x^515 + x^514 + x^512 + x^510 + x^509 + x^508 + x^506 + x^497 + x^494 + x^493 + x^490 + x^487 + x^486 + x^483 + x^481 + x^479 + x^476 + x^474 + x^472 + x^471 + x^467 + x^465 + x^464 + x^463 + x^462 + x^460 + x^456 + x^454 + x^452 + x^450 + x^449 + x^448 + x^447 + x^445 + x^444 + x^440 + x^439 + x^438 + x^437 + x^436 + x^432 + x^431 + x^430 + x^429 + x^428 + x^427 + x^425 + x^424 + x^422 + x^420 + x^419 + x^418 + x^416 + x^414 + x^413 + x^409 + x^407 + x^405 + x^404 + x^402 + x^397 + x^396 + x^392 + x^391 + x^389 + x^386 + x^385 + x^384 + x^381 + x^377 + x^376 + x^373 + x^371 + x^368 + x^366 + x^364 + x^362 + x^360 + x^359 + x^357 + x^355 + x^354 + x^353 + x^352 + x^351 + x^350 + x^349 + x^348 + x^346 + x^343 + x^341 + x^340 + x^338 + x^337 + x^336 + x^334 + x^331 + x^329 + x^328 + x^327 + x^325 + x^324 + x^323 + x^320 + x^316 + x^314 + x^313 + x^311 + x^309 + x^307 + x^306 + x^305 + x^304 + x^302 + x^301 + x^299 + x^297 + x^291 + x^289 + x^288 + x^285 + x^283 + x^282 + x^280 + x^279 + x^272 + x^271 + x^270 + x^269 + x^268 + x^264 + x^263 + x^260 + x^259 + x^257 + x^249 + x^245 + x^242 + x^241 + x^238 + x^234 + x^233 + x^232 + x^230 + x^229 + x^227 + x^226 + x^225 + x^223 + x^221 + x^214 + x^211 + x^210 + x^209 + x^206 + x^205 + x^204 + x^203 + x^201 + x^200 + x^199 + x^197 + x^195 + x^188 + x^186 + x^181 + x^180 + x^177 + x^174 + x^173 + x^171 + x^160 + x^159 + x^158 + x^157 + x^154 + x^148 + x^147 + x^144 + x^142 + x^141 + x^140 + x^139 + x^135 + x^134 + x^129 + x^124 + x^123 + x^120 + x^118 + x^117 + x^116 + x^113 + x^112 + x^110 + x^109 + x^108 + x^107 + x^106 + x^104 + x^103 + x^100 + x^97 + x^95 + x^94 + x^89 + x^86 + x^84 + x^83 + x^79 + x^76 + x^75 + x^73 + x^72 + x^70 + x^67 + x^66 + x^65 + x^63 + x^61 + x^60 + x^59 + x^58 + x^56 + x^53 + x^52 + x^51 + x^50 + x^45 + x^41 + x^40 + x^39 + x^37 + x^36 + x^35 + x^29 + x^26 + x^22 + x^19 + x^18 + x^17 + x^16 + x^13 + x^11 + x^6 + 1
+
+26-3-47 381 x^928 + x^898 + x^878 + x^870 + x^869 + x^860 + x^859 + x^858 + x^850 + x^849 + x^848 + x^840 + x^839 + x^838 + x^830 + x^820 + x^818 + x^810 + x^808 + x^807 + x^798 + x^788 + x^780 + x^778 + x^777 + x^769 + x^767 + x^758 + x^750 + x^740 + x^730 + x^729 + x^728 + x^727 + x^721 + x^720 + x^719 + x^717 + x^716 + x^711 + x^701 + x^700 + x^696 + x^690 + x^689 + x^687 + x^686 + x^681 + x^679 + x^678 + x^676 + x^670 + x^668 + x^667 + x^661 + x^660 + x^657 + x^656 + x^652 + x^650 + x^649 + x^648 + x^647 + x^646 + x^641 + x^638 + x^637 + x^636 + x^632 + x^629 + x^627 + x^625 + x^622 + x^620 + x^619 + x^617 + x^616 + x^610 + x^607 + x^606 + x^602 + x^601 + x^600 + x^599 + x^597 + x^596 + x^592 + x^591 + x^590 + x^588 + x^587 + x^586 + x^585 + x^581 + x^578 + x^576 + x^572 + x^571 + x^570 + x^567 + x^562 + x^560 + x^559 + x^558 + x^557 + x^555 + x^551 + x^550 + x^549 + x^548 + x^546 + x^542 + x^541 + x^536 + x^534 + x^531 + x^530 + x^528 + x^525 + x^523 + x^522 + x^520 + x^519 + x^518 + x^515 + x^514 + x^511 + x^510 + x^509 + x^508 + x^505 + x^504 + x^502 + x^501 + x^500 + x^499 + x^494 + x^493 + x^485 + x^484 + x^481 + x^480 + x^479 + x^477 + x^476 + x^475 + x^473 + x^466 + x^464 + x^462 + x^461 + x^460 + x^458 + x^457 + x^453 + x^447 + x^444 + x^442 + x^441 + x^440 + x^439 + x^438 + x^433 + x^432 + x^429 + x^428 + x^426 + x^425 + x^424 + x^422 + x^421 + x^420 + x^419 + x^418 + x^414 + x^412 + x^411 + x^407 + x^404 + x^401 + x^398 + x^396 + x^393 + x^392 + x^391 + x^389 + x^387 + x^385 + x^383 + x^382 + x^381 + x^380 + x^378 + x^377 + x^374 + x^372 + x^371 + x^368 + x^365 + x^363 + x^362 + x^359 + x^357 + x^356 + x^355 + x^354 + x^350 + x^347 + x^344 + x^343 + x^341 + x^338 + x^337 + x^335 + x^334 + x^333 + x^331 + x^330 + x^329 + x^328 + x^324 + x^322 + x^319 + x^317 + x^314 + x^310 + x^306 + x^300 + x^299 + x^295 + x^294 + x^291 + x^290 + x^289 + x^288 + x^287 + x^286 + x^285 + x^284 + x^282 + x^281 + x^279 + x^278 + x^275 + x^272 + x^271 + x^270 + x^269 + x^266 + x^264 + x^262 + x^260 + x^259 + x^258 + x^254 + x^250 + x^249 + x^247 + x^246 + x^244 + x^243 + x^241 + x^239 + x^237 + x^236 + x^233 + x^232 + x^231 + x^229 + x^227 + x^226 + x^221 + x^220 + x^218 + x^217 + x^216 + x^215 + x^214 + x^213 + x^212 + x^210 + x^209 + x^207 + x^206 + x^202 + x^201 + x^200 + x^199 + x^198 + x^197 + x^195 + x^193 + x^192 + x^189 + x^188 + x^180 + x^176 + x^174 + x^173 + x^172 + x^170 + x^167 + x^165 + x^164 + x^162 + x^160 + x^157 + x^155 + x^153 + x^152 + x^151 + x^149 + x^148 + x^147 + x^144 + x^142 + x^140 + x^139 + x^136 + x^134 + x^133 + x^128 + x^127 + x^124 + x^123 + x^122 + x^121 + x^119 + x^117 + x^115 + x^113 + x^112 + x^110 + x^107 + x^105 + x^101 + x^100 + x^99 + x^98 + x^94 + x^92 + x^91 + x^90 + x^89 + x^87 + x^85 + x^83 + x^81 + x^80 + x^78 + x^77 + x^74 + x^72 + x^71 + x^70 + x^69 + x^65 + x^64 + x^63 + x^62 + x^61 + x^57 + x^56 + x^55 + x^54 + x^53 + x^49 + x^48 + x^42 + x^41 + x^39 + x^36 + x^34 + x^32 + x^31 + x^24 + x^23 + x^21 + x^14 + x^10 + 1
+
+37-33-14 381 x^928 + x^898 + x^874 + x^870 + x^849 + x^845 + x^841 + x^837 + x^836 + x^832 + x^824 + x^820 + x^812 + x^811 + x^804 + x^802 + x^794 + x^789 + x^785 + x^783 + x^781 + x^777 + x^775 + x^771 + x^770 + x^764 + x^761 + x^757 + x^754 + x^751 + x^746 + x^742 + x^741 + x^740 + x^738 + x^736 + x^734 + x^733 + x^731 + x^727 + x^726 + x^725 + x^724 + x^723 + x^721 + x^720 + x^718 + x^717 + x^716 + x^715 + x^714 + x^713 + x^712 + x^711 + x^709 + x^705 + x^704 + x^703 + x^701 + x^695 + x^692 + x^691 + x^690 + x^688 + x^687 + x^686 + x^685 + x^684 + x^682 + x^680 + x^679 + x^676 + x^671 + x^670 + x^665 + x^663 + x^662 + x^661 + x^660 + x^659 + x^653 + x^652 + x^651 + x^650 + x^648 + x^644 + x^643 + x^642 + x^641 + x^637 + x^635 + x^634 + x^631 + x^630 + x^629 + x^627 + x^626 + x^623 + x^622 + x^621 + x^619 + x^617 + x^616 + x^614 + x^613 + x^611 + x^610 + x^603 + x^601 + x^600 + x^599 + x^597 + x^596 + x^594 + x^593 + x^592 + x^591 + x^589 + x^587 + x^585 + x^583 + x^582 + x^579 + x^575 + x^573 + x^571 + x^570 + x^567 + x^566 + x^560 + x^557 + x^556 + x^554 + x^553 + x^552 + x^551 + x^548 + x^546 + x^541 + x^540 + x^538 + x^535 + x^534 + x^531 + x^527 + x^526 + x^525 + x^524 + x^523 + x^517 + x^516 + x^511 + x^509 + x^507 + x^499 + x^496 + x^493 + x^491 + x^490 + x^485 + x^482 + x^481 + x^479 + x^477 + x^475 + x^474 + x^470 + x^469 + x^468 + x^465 + x^462 + x^461 + x^459 + x^458 + x^453 + x^451 + x^446 + x^444 + x^441 + x^436 + x^435 + x^434 + x^432 + x^429 + x^420 + x^419 + x^416 + x^414 + x^411 + x^410 + x^409 + x^407 + x^405 + x^404 + x^403 + x^402 + x^401 + x^397 + x^395 + x^393 + x^392 + x^390 + x^388 + x^384 + x^381 + x^379 + x^376 + x^374 + x^368 + x^367 + x^365 + x^362 + x^361 + x^360 + x^359 + x^357 + x^355 + x^351 + x^349 + x^346 + x^345 + x^344 + x^342 + x^341 + x^339 + x^337 + x^336 + x^335 + x^333 + x^331 + x^326 + x^320 + x^318 + x^316 + x^315 + x^314 + x^313 + x^312 + x^311 + x^310 + x^309 + x^306 + x^304 + x^303 + x^302 + x^301 + x^300 + x^298 + x^297 + x^296 + x^295 + x^294 + x^293 + x^292 + x^290 + x^289 + x^288 + x^284 + x^283 + x^282 + x^278 + x^277 + x^274 + x^273 + x^272 + x^270 + x^266 + x^265 + x^261 + x^258 + x^256 + x^255 + x^254 + x^248 + x^246 + x^245 + x^239 + x^237 + x^234 + x^230 + x^229 + x^225 + x^224 + x^222 + x^221 + x^217 + x^215 + x^214 + x^213 + x^212 + x^208 + x^206 + x^204 + x^203 + x^202 + x^201 + x^199 + x^198 + x^195 + x^194 + x^191 + x^189 + x^188 + x^186 + x^184 + x^182 + x^181 + x^179 + x^177 + x^176 + x^175 + x^171 + x^169 + x^168 + x^162 + x^161 + x^159 + x^157 + x^156 + x^151 + x^150 + x^148 + x^146 + x^145 + x^142 + x^140 + x^139 + x^138 + x^135 + x^134 + x^131 + x^129 + x^126 + x^124 + x^119 + x^118 + x^117 + x^116 + x^108 + x^106 + x^105 + x^103 + x^99 + x^97 + x^93 + x^92 + x^91 + x^90 + x^87 + x^86 + x^84 + x^83 + x^78 + x^76 + x^73 + x^66 + x^65 + x^64 + x^62 + x^61 + x^58 + x^53 + x^52 + x^51 + x^48 + x^47 + x^46 + x^45 + x^44 + x^42 + x^41 + x^38 + x^34 + x^29 + x^28 + x^26 + x^23 + x^16 + x^8 + x^6 + 1
+
+36-46-33 383 x^928 + x^898 + x^870 + x^857 + x^828 + x^827 + x^816 + x^815 + x^809 + x^808 + x^804 + x^797 + x^792 + x^786 + x^785 + x^780 + x^778 + x^775 + x^773 + x^768 + x^767 + x^762 + x^755 + x^751 + x^750 + x^737 + x^734 + x^732 + x^728 + x^727 + x^725 + x^722 + x^716 + x^715 + x^714 + x^710 + x^708 + x^707 + x^704 + x^703 + x^701 + x^698 + x^697 + x^695 + x^689 + x^688 + x^685 + x^681 + x^680 + x^679 + x^678 + x^677 + x^674 + x^665 + x^658 + x^656 + x^651 + x^650 + x^649 + x^648 + x^647 + x^640 + x^637 + x^635 + x^634 + x^633 + x^631 + x^628 + x^626 + x^624 + x^620 + x^619 + x^617 + x^616 + x^610 + x^607 + x^605 + x^603 + x^602 + x^601 + x^598 + x^591 + x^590 + x^587 + x^584 + x^582 + x^580 + x^577 + x^574 + x^573 + x^571 + x^567 + x^563 + x^562 + x^560 + x^559 + x^558 + x^557 + x^555 + x^553 + x^551 + x^550 + x^549 + x^548 + x^547 + x^544 + x^542 + x^540 + x^539 + x^538 + x^537 + x^535 + x^534 + x^533 + x^531 + x^528 + x^527 + x^525 + x^519 + x^517 + x^516 + x^515 + x^510 + x^509 + x^508 + x^507 + x^505 + x^500 + x^499 + x^496 + x^495 + x^494 + x^493 + x^489 + x^488 + x^487 + x^486 + x^485 + x^484 + x^482 + x^480 + x^479 + x^477 + x^475 + x^473 + x^470 + x^468 + x^467 + x^466 + x^465 + x^463 + x^461 + x^460 + x^455 + x^451 + x^450 + x^448 + x^444 + x^443 + x^442 + x^439 + x^438 + x^437 + x^435 + x^434 + x^433 + x^427 + x^426 + x^425 + x^423 + x^421 + x^420 + x^419 + x^418 + x^416 + x^413 + x^411 + x^410 + x^408 + x^407 + x^404 + x^402 + x^400 + x^399 + x^398 + x^397 + x^396 + x^395 + x^394 + x^393 + x^387 + x^386 + x^382 + x^379 + x^378 + x^377 + x^376 + x^375 + x^374 + x^372 + x^371 + x^370 + x^369 + x^366 + x^364 + x^363 + x^362 + x^361 + x^359 + x^358 + x^357 + x^356 + x^355 + x^354 + x^352 + x^347 + x^346 + x^345 + x^344 + x^343 + x^341 + x^340 + x^336 + x^335 + x^332 + x^330 + x^329 + x^328 + x^325 + x^324 + x^323 + x^322 + x^321 + x^320 + x^318 + x^316 + x^315 + x^312 + x^302 + x^301 + x^298 + x^295 + x^288 + x^287 + x^286 + x^285 + x^280 + x^279 + x^278 + x^275 + x^273 + x^272 + x^270 + x^267 + x^266 + x^264 + x^261 + x^259 + x^258 + x^255 + x^253 + x^252 + x^250 + x^249 + x^248 + x^247 + x^244 + x^243 + x^242 + x^241 + x^240 + x^237 + x^236 + x^235 + x^231 + x^230 + x^228 + x^225 + x^224 + x^222 + x^220 + x^218 + x^217 + x^216 + x^215 + x^212 + x^211 + x^205 + x^204 + x^203 + x^201 + x^196 + x^194 + x^193 + x^192 + x^191 + x^190 + x^187 + x^186 + x^184 + x^183 + x^182 + x^180 + x^179 + x^178 + x^174 + x^173 + x^172 + x^164 + x^163 + x^162 + x^161 + x^160 + x^159 + x^158 + x^156 + x^154 + x^153 + x^150 + x^149 + x^148 + x^146 + x^144 + x^143 + x^140 + x^134 + x^131 + x^127 + x^125 + x^124 + x^120 + x^119 + x^118 + x^116 + x^115 + x^113 + x^112 + x^109 + x^108 + x^107 + x^106 + x^103 + x^100 + x^99 + x^97 + x^96 + x^95 + x^94 + x^91 + x^87 + x^86 + x^83 + x^81 + x^80 + x^78 + x^77 + x^75 + x^74 + x^72 + x^71 + x^69 + x^68 + x^66 + x^64 + x^63 + x^59 + x^57 + x^55 + x^53 + x^48 + x^47 + x^44 + x^42 + x^41 + x^40 + x^37 + x^28 + x^27 + x^26 + x^20 + x^18 + x^16 + 1
+
+40-1-13 383 x^928 + x^898 + x^870 + x^864 + x^861 + x^858 + x^855 + x^852 + x^837 + x^834 + x^825 + x^808 + x^804 + x^801 + x^798 + x^792 + x^791 + x^788 + x^785 + x^778 + x^777 + x^774 + x^773 + x^758 + x^755 + x^752 + x^743 + x^740 + x^738 + x^737 + x^735 + x^734 + x^725 + x^721 + x^719 + x^718 + x^716 + x^715 + x^713 + x^710 + x^707 + x^705 + x^704 + x^703 + x^698 + x^695 + x^691 + x^689 + x^686 + x^682 + x^680 + x^678 + x^677 + x^676 + x^674 + x^673 + x^671 + x^668 + x^667 + x^664 + x^662 + x^661 + x^659 + x^658 + x^656 + x^652 + x^650 + x^648 + x^647 + x^645 + x^644 + x^643 + x^642 + x^641 + x^640 + x^636 + x^633 + x^630 + x^629 + x^628 + x^627 + x^626 + x^623 + x^621 + x^618 + x^615 + x^612 + x^608 + x^607 + x^605 + x^603 + x^602 + x^600 + x^598 + x^596 + x^594 + x^593 + x^588 + x^583 + x^582 + x^579 + x^574 + x^573 + x^569 + x^568 + x^567 + x^565 + x^564 + x^562 + x^558 + x^557 + x^556 + x^555 + x^552 + x^551 + x^548 + x^545 + x^544 + x^542 + x^540 + x^537 + x^535 + x^534 + x^533 + x^532 + x^531 + x^530 + x^526 + x^525 + x^524 + x^523 + x^521 + x^520 + x^519 + x^518 + x^517 + x^515 + x^513 + x^509 + x^508 + x^507 + x^502 + x^500 + x^499 + x^496 + x^495 + x^491 + x^489 + x^488 + x^485 + x^482 + x^480 + x^478 + x^476 + x^474 + x^471 + x^468 + x^466 + x^463 + x^462 + x^461 + x^460 + x^459 + x^457 + x^456 + x^453 + x^451 + x^450 + x^447 + x^443 + x^440 + x^439 + x^436 + x^435 + x^434 + x^433 + x^432 + x^426 + x^425 + x^424 + x^422 + x^421 + x^419 + x^417 + x^416 + x^410 + x^409 + x^408 + x^406 + x^405 + x^402 + x^401 + x^399 + x^398 + x^396 + x^389 + x^388 + x^387 + x^385 + x^383 + x^382 + x^381 + x^379 + x^378 + x^377 + x^376 + x^375 + x^373 + x^371 + x^368 + x^366 + x^364 + x^363 + x^360 + x^358 + x^356 + x^355 + x^353 + x^350 + x^349 + x^346 + x^345 + x^344 + x^340 + x^339 + x^338 + x^332 + x^331 + x^329 + x^326 + x^324 + x^323 + x^321 + x^316 + x^315 + x^313 + x^312 + x^310 + x^309 + x^307 + x^306 + x^305 + x^303 + x^302 + x^300 + x^299 + x^296 + x^294 + x^293 + x^292 + x^289 + x^288 + x^286 + x^285 + x^283 + x^282 + x^279 + x^277 + x^274 + x^273 + x^272 + x^270 + x^269 + x^268 + x^267 + x^265 + x^264 + x^261 + x^259 + x^256 + x^251 + x^249 + x^245 + x^241 + x^240 + x^239 + x^238 + x^236 + x^235 + x^234 + x^232 + x^230 + x^226 + x^222 + x^220 + x^217 + x^215 + x^211 + x^210 + x^208 + x^203 + x^200 + x^199 + x^197 + x^195 + x^194 + x^193 + x^190 + x^187 + x^186 + x^184 + x^183 + x^182 + x^178 + x^176 + x^174 + x^169 + x^168 + x^167 + x^164 + x^162 + x^161 + x^160 + x^159 + x^158 + x^154 + x^153 + x^147 + x^142 + x^138 + x^137 + x^129 + x^128 + x^127 + x^126 + x^124 + x^123 + x^121 + x^119 + x^116 + x^115 + x^112 + x^110 + x^109 + x^107 + x^106 + x^103 + x^101 + x^100 + x^99 + x^98 + x^95 + x^94 + x^93 + x^92 + x^91 + x^89 + x^85 + x^83 + x^80 + x^79 + x^77 + x^75 + x^73 + x^72 + x^71 + x^63 + x^61 + x^59 + x^58 + x^57 + x^55 + x^51 + x^48 + x^47 + x^46 + x^45 + x^39 + x^38 + x^37 + x^34 + x^33 + x^32 + x^29 + x^28 + x^25 + x^23 + x^20 + x^17 + x^11 + x^10 + x^7 + 1
+
+46-53-31 383 x^928 + x^898 + x^896 + x^875 + x^870 + x^864 + x^856 + x^854 + x^848 + x^845 + x^834 + x^833 + x^827 + x^817 + x^814 + x^812 + x^808 + x^807 + x^806 + x^804 + x^801 + x^796 + x^794 + x^791 + x^787 + x^786 + x^778 + x^777 + x^776 + x^774 + x^773 + x^772 + x^770 + x^767 + x^765 + x^764 + x^761 + x^757 + x^756 + x^754 + x^746 + x^745 + x^744 + x^741 + x^735 + x^734 + x^730 + x^727 + x^725 + x^723 + x^716 + x^715 + x^714 + x^713 + x^712 + x^705 + x^704 + x^703 + x^702 + x^697 + x^696 + x^692 + x^688 + x^685 + x^684 + x^683 + x^682 + x^681 + x^674 + x^673 + x^672 + x^671 + x^670 + x^667 + x^666 + x^664 + x^663 + x^661 + x^660 + x^658 + x^655 + x^654 + x^653 + x^652 + x^651 + x^650 + x^645 + x^639 + x^637 + x^634 + x^631 + x^630 + x^626 + x^625 + x^624 + x^621 + x^620 + x^618 + x^615 + x^610 + x^608 + x^607 + x^606 + x^605 + x^604 + x^602 + x^596 + x^594 + x^588 + x^586 + x^584 + x^582 + x^580 + x^578 + x^574 + x^573 + x^571 + x^570 + x^568 + x^567 + x^560 + x^553 + x^551 + x^548 + x^545 + x^543 + x^542 + x^538 + x^537 + x^536 + x^534 + x^533 + x^532 + x^530 + x^529 + x^528 + x^523 + x^521 + x^513 + x^512 + x^509 + x^508 + x^505 + x^502 + x^491 + x^490 + x^489 + x^487 + x^481 + x^479 + x^468 + x^466 + x^465 + x^464 + x^461 + x^460 + x^459 + x^457 + x^455 + x^454 + x^453 + x^451 + x^450 + x^444 + x^442 + x^440 + x^438 + x^431 + x^430 + x^429 + x^428 + x^427 + x^426 + x^425 + x^424 + x^423 + x^422 + x^421 + x^416 + x^415 + x^414 + x^412 + x^410 + x^409 + x^408 + x^402 + x^400 + x^399 + x^398 + x^396 + x^395 + x^393 + x^392 + x^391 + x^388 + x^385 + x^384 + x^381 + x^380 + x^379 + x^377 + x^376 + x^374 + x^373 + x^371 + x^368 + x^366 + x^365 + x^364 + x^362 + x^358 + x^357 + x^356 + x^351 + x^348 + x^345 + x^342 + x^339 + x^338 + x^336 + x^334 + x^331 + x^330 + x^328 + x^327 + x^323 + x^320 + x^319 + x^318 + x^312 + x^311 + x^307 + x^306 + x^305 + x^304 + x^303 + x^302 + x^301 + x^298 + x^295 + x^293 + x^292 + x^291 + x^287 + x^286 + x^285 + x^284 + x^283 + x^280 + x^279 + x^278 + x^276 + x^275 + x^271 + x^269 + x^266 + x^264 + x^263 + x^262 + x^260 + x^257 + x^255 + x^254 + x^253 + x^252 + x^251 + x^250 + x^248 + x^242 + x^241 + x^238 + x^234 + x^231 + x^225 + x^223 + x^222 + x^221 + x^220 + x^219 + x^218 + x^217 + x^214 + x^211 + x^209 + x^208 + x^207 + x^206 + x^204 + x^200 + x^196 + x^194 + x^191 + x^188 + x^186 + x^185 + x^182 + x^181 + x^178 + x^176 + x^175 + x^174 + x^169 + x^168 + x^166 + x^164 + x^160 + x^159 + x^158 + x^155 + x^154 + x^153 + x^151 + x^149 + x^147 + x^145 + x^143 + x^138 + x^135 + x^132 + x^131 + x^130 + x^128 + x^127 + x^124 + x^123 + x^121 + x^120 + x^119 + x^117 + x^116 + x^115 + x^112 + x^111 + x^110 + x^109 + x^106 + x^105 + x^104 + x^101 + x^99 + x^96 + x^87 + x^85 + x^84 + x^83 + x^81 + x^80 + x^79 + x^75 + x^73 + x^70 + x^69 + x^68 + x^67 + x^66 + x^63 + x^61 + x^60 + x^58 + x^56 + x^54 + x^53 + x^51 + x^49 + x^47 + x^45 + x^44 + x^43 + x^42 + x^41 + x^39 + x^36 + x^34 + x^31 + x^30 + x^29 + x^27 + x^24 + x^22 + x^14 + x^13 + x^12 + 1
+
+1-41-10 385 x^928 + x^898 + x^879 + x^870 + x^855 + x^850 + x^849 + x^831 + x^826 + x^825 + x^819 + x^816 + x^808 + x^807 + x^802 + x^801 + x^800 + x^796 + x^792 + x^789 + x^777 + x^776 + x^768 + x^766 + x^762 + x^758 + x^756 + x^754 + x^748 + x^746 + x^744 + x^742 + x^738 + x^736 + x^735 + x^733 + x^729 + x^728 + x^725 + x^720 + x^716 + x^710 + x^705 + x^704 + x^701 + x^700 + x^696 + x^688 + x^686 + x^682 + x^681 + x^680 + x^679 + x^678 + x^677 + x^676 + x^675 + x^674 + x^671 + x^670 + x^669 + x^666 + x^665 + x^661 + x^660 + x^658 + x^655 + x^653 + x^652 + x^649 + x^648 + x^645 + x^640 + x^637 + x^633 + x^629 + x^628 + x^624 + x^623 + x^621 + x^620 + x^619 + x^618 + x^617 + x^616 + x^610 + x^609 + x^607 + x^605 + x^604 + x^601 + x^600 + x^595 + x^591 + x^589 + x^586 + x^584 + x^581 + x^579 + x^575 + x^573 + x^569 + x^568 + x^561 + x^559 + x^556 + x^555 + x^546 + x^542 + x^540 + x^538 + x^537 + x^534 + x^533 + x^531 + x^530 + x^528 + x^526 + x^525 + x^523 + x^518 + x^517 + x^513 + x^511 + x^507 + x^497 + x^496 + x^494 + x^493 + x^491 + x^489 + x^488 + x^487 + x^485 + x^484 + x^483 + x^482 + x^479 + x^477 + x^476 + x^475 + x^474 + x^471 + x^470 + x^468 + x^466 + x^465 + x^464 + x^463 + x^462 + x^461 + x^459 + x^458 + x^454 + x^453 + x^452 + x^451 + x^449 + x^447 + x^446 + x^442 + x^441 + x^440 + x^434 + x^431 + x^428 + x^427 + x^426 + x^424 + x^421 + x^418 + x^417 + x^416 + x^414 + x^412 + x^411 + x^408 + x^405 + x^401 + x^400 + x^399 + x^398 + x^395 + x^394 + x^393 + x^392 + x^391 + x^388 + x^386 + x^385 + x^381 + x^380 + x^379 + x^378 + x^376 + x^375 + x^373 + x^372 + x^370 + x^367 + x^366 + x^365 + x^364 + x^361 + x^360 + x^359 + x^356 + x^354 + x^353 + x^349 + x^348 + x^346 + x^344 + x^340 + x^335 + x^332 + x^330 + x^325 + x^324 + x^321 + x^318 + x^316 + x^315 + x^314 + x^312 + x^310 + x^309 + x^307 + x^304 + x^301 + x^300 + x^299 + x^298 + x^297 + x^295 + x^291 + x^290 + x^289 + x^288 + x^287 + x^286 + x^285 + x^284 + x^281 + x^280 + x^276 + x^274 + x^269 + x^268 + x^267 + x^265 + x^264 + x^261 + x^260 + x^259 + x^257 + x^256 + x^255 + x^254 + x^251 + x^250 + x^245 + x^242 + x^239 + x^236 + x^233 + x^229 + x^227 + x^225 + x^223 + x^222 + x^219 + x^217 + x^214 + x^213 + x^210 + x^207 + x^205 + x^204 + x^203 + x^202 + x^201 + x^200 + x^199 + x^198 + x^197 + x^196 + x^195 + x^192 + x^190 + x^189 + x^181 + x^180 + x^178 + x^177 + x^175 + x^174 + x^173 + x^172 + x^169 + x^168 + x^165 + x^162 + x^159 + x^158 + x^154 + x^153 + x^152 + x^150 + x^148 + x^144 + x^143 + x^142 + x^141 + x^139 + x^138 + x^137 + x^133 + x^132 + x^128 + x^127 + x^124 + x^123 + x^122 + x^121 + x^118 + x^116 + x^106 + x^102 + x^101 + x^98 + x^96 + x^92 + x^91 + x^90 + x^89 + x^88 + x^86 + x^85 + x^84 + x^83 + x^81 + x^80 + x^78 + x^76 + x^73 + x^72 + x^71 + x^69 + x^67 + x^66 + x^65 + x^63 + x^58 + x^54 + x^53 + x^52 + x^51 + x^50 + x^47 + x^46 + x^45 + x^44 + x^43 + x^40 + x^39 + x^38 + x^37 + x^34 + x^33 + x^32 + x^30 + x^25 + x^23 + x^21 + x^20 + x^19 + x^17 + x^16 + x^15 + x^12 + x^9 + x^8 + x^4 + 1
+
+11-33-48 385 x^928 + x^898 + x^882 + x^870 + x^860 + x^853 + x^844 + x^835 + x^828 + x^827 + x^822 + x^819 + x^815 + x^811 + x^808 + x^806 + x^805 + x^794 + x^793 + x^786 + x^784 + x^781 + x^778 + x^773 + x^772 + x^769 + x^765 + x^762 + x^760 + x^759 + x^756 + x^755 + x^748 + x^746 + x^743 + x^739 + x^735 + x^734 + x^733 + x^731 + x^729 + x^727 + x^723 + x^718 + x^713 + x^709 + x^707 + x^706 + x^704 + x^702 + x^699 + x^696 + x^693 + x^692 + x^691 + x^686 + x^685 + x^683 + x^679 + x^677 + x^673 + x^670 + x^669 + x^666 + x^657 + x^656 + x^655 + x^649 + x^648 + x^646 + x^641 + x^639 + x^638 + x^635 + x^633 + x^632 + x^630 + x^628 + x^627 + x^625 + x^620 + x^616 + x^614 + x^613 + x^611 + x^610 + x^609 + x^607 + x^606 + x^600 + x^595 + x^593 + x^592 + x^589 + x^587 + x^584 + x^581 + x^580 + x^579 + x^577 + x^572 + x^570 + x^568 + x^567 + x^566 + x^564 + x^560 + x^559 + x^557 + x^555 + x^554 + x^552 + x^551 + x^546 + x^542 + x^538 + x^535 + x^534 + x^533 + x^531 + x^530 + x^528 + x^526 + x^524 + x^523 + x^520 + x^519 + x^511 + x^509 + x^506 + x^504 + x^503 + x^502 + x^501 + x^500 + x^499 + x^498 + x^495 + x^494 + x^491 + x^490 + x^489 + x^488 + x^487 + x^485 + x^484 + x^479 + x^475 + x^473 + x^466 + x^459 + x^457 + x^456 + x^455 + x^454 + x^451 + x^450 + x^449 + x^448 + x^447 + x^446 + x^444 + x^443 + x^442 + x^441 + x^440 + x^433 + x^432 + x^430 + x^428 + x^427 + x^425 + x^423 + x^419 + x^418 + x^417 + x^414 + x^409 + x^408 + x^406 + x^404 + x^402 + x^400 + x^398 + x^397 + x^396 + x^395 + x^393 + x^389 + x^388 + x^385 + x^379 + x^377 + x^375 + x^374 + x^369 + x^365 + x^364 + x^363 + x^362 + x^361 + x^359 + x^355 + x^354 + x^350 + x^348 + x^345 + x^344 + x^339 + x^336 + x^335 + x^334 + x^333 + x^332 + x^331 + x^330 + x^329 + x^328 + x^326 + x^319 + x^318 + x^316 + x^315 + x^314 + x^313 + x^312 + x^309 + x^308 + x^304 + x^303 + x^302 + x^299 + x^298 + x^297 + x^295 + x^294 + x^293 + x^292 + x^291 + x^290 + x^288 + x^285 + x^282 + x^281 + x^279 + x^277 + x^276 + x^274 + x^272 + x^271 + x^270 + x^269 + x^268 + x^267 + x^265 + x^264 + x^262 + x^261 + x^260 + x^257 + x^253 + x^251 + x^250 + x^247 + x^246 + x^243 + x^242 + x^241 + x^240 + x^237 + x^236 + x^233 + x^232 + x^230 + x^229 + x^226 + x^223 + x^222 + x^221 + x^220 + x^217 + x^215 + x^211 + x^210 + x^209 + x^207 + x^206 + x^205 + x^203 + x^201 + x^200 + x^198 + x^196 + x^195 + x^193 + x^189 + x^188 + x^186 + x^184 + x^180 + x^179 + x^177 + x^176 + x^170 + x^168 + x^163 + x^162 + x^160 + x^159 + x^158 + x^157 + x^156 + x^154 + x^151 + x^149 + x^148 + x^145 + x^144 + x^141 + x^140 + x^138 + x^137 + x^136 + x^135 + x^134 + x^133 + x^132 + x^131 + x^130 + x^129 + x^125 + x^124 + x^121 + x^117 + x^116 + x^110 + x^109 + x^108 + x^106 + x^104 + x^103 + x^102 + x^99 + x^98 + x^96 + x^95 + x^93 + x^92 + x^90 + x^89 + x^88 + x^85 + x^83 + x^81 + x^78 + x^76 + x^72 + x^71 + x^70 + x^68 + x^67 + x^66 + x^62 + x^59 + x^58 + x^56 + x^51 + x^48 + x^46 + x^45 + x^44 + x^43 + x^41 + x^40 + x^38 + x^37 + x^35 + x^34 + x^33 + x^32 + x^27 + x^22 + x^19 + x^13 + 1
+
+19-8-4 387 x^928 + x^898 + x^870 + x^844 + x^838 + x^834 + x^828 + x^818 + x^814 + x^806 + x^804 + x^803 + x^797 + x^782 + x^778 + x^776 + x^774 + x^773 + x^772 + x^768 + x^767 + x^764 + x^752 + x^751 + x^745 + x^744 + x^742 + x^740 + x^738 + x^736 + x^733 + x^730 + x^721 + x^718 + x^715 + x^714 + x^710 + x^707 + x^704 + x^702 + x^700 + x^699 + x^698 + x^697 + x^694 + x^692 + x^691 + x^688 + x^686 + x^685 + x^682 + x^676 + x^673 + x^671 + x^670 + x^669 + x^666 + x^662 + x^661 + x^658 + x^656 + x^655 + x^654 + x^652 + x^649 + x^648 + x^647 + x^645 + x^644 + x^642 + x^640 + x^638 + x^636 + x^632 + x^631 + x^630 + x^623 + x^622 + x^621 + x^616 + x^614 + x^612 + x^611 + x^606 + x^605 + x^602 + x^598 + x^597 + x^594 + x^593 + x^591 + x^590 + x^588 + x^587 + x^586 + x^584 + x^582 + x^581 + x^579 + x^577 + x^574 + x^572 + x^571 + x^568 + x^567 + x^566 + x^563 + x^562 + x^560 + x^559 + x^558 + x^556 + x^553 + x^551 + x^550 + x^549 + x^546 + x^545 + x^543 + x^542 + x^538 + x^536 + x^535 + x^534 + x^533 + x^531 + x^530 + x^529 + x^527 + x^525 + x^524 + x^522 + x^521 + x^520 + x^518 + x^517 + x^513 + x^512 + x^510 + x^509 + x^507 + x^506 + x^505 + x^504 + x^501 + x^500 + x^499 + x^493 + x^492 + x^491 + x^489 + x^488 + x^486 + x^485 + x^484 + x^480 + x^479 + x^478 + x^477 + x^474 + x^473 + x^472 + x^470 + x^468 + x^464 + x^462 + x^458 + x^456 + x^455 + x^454 + x^453 + x^452 + x^451 + x^450 + x^449 + x^447 + x^446 + x^445 + x^441 + x^439 + x^438 + x^437 + x^436 + x^434 + x^433 + x^432 + x^431 + x^429 + x^426 + x^425 + x^424 + x^423 + x^421 + x^419 + x^418 + x^416 + x^414 + x^412 + x^410 + x^407 + x^405 + x^404 + x^398 + x^397 + x^394 + x^393 + x^392 + x^391 + x^387 + x^386 + x^385 + x^382 + x^381 + x^379 + x^377 + x^375 + x^374 + x^369 + x^368 + x^365 + x^364 + x^363 + x^362 + x^361 + x^359 + x^358 + x^356 + x^355 + x^352 + x^351 + x^350 + x^345 + x^343 + x^341 + x^340 + x^338 + x^333 + x^331 + x^330 + x^329 + x^328 + x^327 + x^325 + x^324 + x^323 + x^322 + x^318 + x^315 + x^312 + x^310 + x^308 + x^305 + x^304 + x^303 + x^299 + x^296 + x^295 + x^294 + x^290 + x^289 + x^288 + x^285 + x^284 + x^281 + x^280 + x^275 + x^274 + x^273 + x^271 + x^268 + x^266 + x^264 + x^263 + x^262 + x^261 + x^260 + x^258 + x^256 + x^255 + x^254 + x^251 + x^245 + x^240 + x^237 + x^236 + x^231 + x^230 + x^229 + x^228 + x^223 + x^221 + x^219 + x^218 + x^215 + x^210 + x^208 + x^207 + x^206 + x^204 + x^202 + x^197 + x^196 + x^195 + x^194 + x^193 + x^192 + x^187 + x^186 + x^184 + x^183 + x^182 + x^180 + x^178 + x^177 + x^175 + x^174 + x^169 + x^168 + x^166 + x^165 + x^163 + x^160 + x^159 + x^156 + x^155 + x^152 + x^150 + x^145 + x^140 + x^138 + x^137 + x^136 + x^135 + x^134 + x^133 + x^131 + x^128 + x^127 + x^126 + x^122 + x^121 + x^118 + x^117 + x^114 + x^109 + x^105 + x^102 + x^101 + x^100 + x^99 + x^96 + x^94 + x^93 + x^91 + x^90 + x^89 + x^88 + x^87 + x^81 + x^79 + x^76 + x^74 + x^71 + x^70 + x^64 + x^63 + x^61 + x^59 + x^56 + x^55 + x^49 + x^47 + x^46 + x^44 + x^43 + x^40 + x^35 + x^34 + x^33 + x^31 + x^28 + x^26 + x^23 + x^21 + x^18 + x^13 + 1
+
+36-23-57 387 x^928 + x^898 + x^897 + x^890 + x^870 + x^860 + x^859 + x^854 + x^853 + x^846 + x^836 + x^835 + x^824 + x^816 + x^810 + x^809 + x^808 + x^804 + x^802 + x^792 + x^791 + x^785 + x^784 + x^780 + x^778 + x^777 + x^776 + x^775 + x^774 + x^773 + x^765 + x^755 + x^753 + x^748 + x^747 + x^744 + x^742 + x^733 + x^732 + x^728 + x^725 + x^724 + x^721 + x^716 + x^714 + x^713 + x^703 + x^701 + x^700 + x^699 + x^697 + x^693 + x^692 + x^691 + x^690 + x^689 + x^680 + x^679 + x^675 + x^673 + x^672 + x^666 + x^663 + x^662 + x^661 + x^658 + x^656 + x^655 + x^653 + x^652 + x^649 + x^647 + x^645 + x^642 + x^641 + x^639 + x^638 + x^637 + x^633 + x^630 + x^629 + x^625 + x^620 + x^619 + x^614 + x^613 + x^612 + x^611 + x^610 + x^606 + x^605 + x^604 + x^603 + x^601 + x^600 + x^599 + x^597 + x^593 + x^591 + x^589 + x^587 + x^586 + x^584 + x^583 + x^581 + x^579 + x^576 + x^572 + x^571 + x^566 + x^565 + x^563 + x^559 + x^554 + x^552 + x^549 + x^548 + x^545 + x^544 + x^543 + x^540 + x^535 + x^534 + x^533 + x^531 + x^529 + x^524 + x^522 + x^517 + x^516 + x^513 + x^512 + x^511 + x^509 + x^507 + x^506 + x^505 + x^503 + x^502 + x^496 + x^495 + x^494 + x^492 + x^491 + x^490 + x^489 + x^487 + x^478 + x^477 + x^475 + x^474 + x^472 + x^471 + x^470 + x^469 + x^466 + x^463 + x^461 + x^459 + x^458 + x^457 + x^456 + x^455 + x^454 + x^453 + x^452 + x^448 + x^447 + x^446 + x^444 + x^442 + x^440 + x^439 + x^438 + x^437 + x^434 + x^431 + x^428 + x^427 + x^426 + x^425 + x^424 + x^423 + x^414 + x^409 + x^408 + x^407 + x^403 + x^401 + x^400 + x^396 + x^395 + x^394 + x^390 + x^389 + x^388 + x^387 + x^386 + x^379 + x^378 + x^377 + x^375 + x^374 + x^370 + x^366 + x^360 + x^359 + x^358 + x^357 + x^356 + x^355 + x^353 + x^351 + x^350 + x^349 + x^348 + x^347 + x^345 + x^343 + x^342 + x^341 + x^340 + x^339 + x^338 + x^336 + x^335 + x^330 + x^329 + x^327 + x^325 + x^324 + x^323 + x^322 + x^319 + x^318 + x^315 + x^313 + x^309 + x^305 + x^304 + x^302 + x^300 + x^298 + x^296 + x^291 + x^289 + x^286 + x^285 + x^284 + x^283 + x^282 + x^281 + x^279 + x^275 + x^274 + x^272 + x^271 + x^265 + x^264 + x^263 + x^259 + x^258 + x^257 + x^253 + x^252 + x^249 + x^246 + x^245 + x^244 + x^242 + x^239 + x^233 + x^232 + x^231 + x^230 + x^229 + x^228 + x^221 + x^217 + x^216 + x^212 + x^211 + x^209 + x^208 + x^205 + x^202 + x^201 + x^200 + x^199 + x^198 + x^197 + x^196 + x^195 + x^193 + x^192 + x^191 + x^189 + x^187 + x^186 + x^183 + x^182 + x^181 + x^177 + x^174 + x^172 + x^170 + x^166 + x^164 + x^163 + x^162 + x^160 + x^156 + x^155 + x^152 + x^151 + x^147 + x^144 + x^143 + x^142 + x^141 + x^138 + x^137 + x^135 + x^133 + x^130 + x^129 + x^126 + x^125 + x^123 + x^121 + x^120 + x^117 + x^114 + x^112 + x^107 + x^106 + x^103 + x^102 + x^100 + x^98 + x^95 + x^94 + x^93 + x^91 + x^90 + x^89 + x^87 + x^85 + x^84 + x^82 + x^81 + x^80 + x^78 + x^76 + x^75 + x^71 + x^70 + x^69 + x^68 + x^66 + x^65 + x^61 + x^60 + x^59 + x^58 + x^56 + x^55 + x^51 + x^49 + x^48 + x^46 + x^44 + x^42 + x^36 + x^34 + x^33 + x^32 + x^29 + x^24 + x^23 + x^20 + x^14 + x^13 + x^12 + x^11 + x^10 + 1
+
+44-4-19 389 x^928 + x^898 + x^874 + x^870 + x^836 + x^832 + x^824 + x^812 + x^809 + x^802 + x^794 + x^793 + x^789 + x^785 + x^781 + x^766 + x^764 + x^763 + x^762 + x^759 + x^758 + x^751 + x^750 + x^746 + x^744 + x^742 + x^738 + x^734 + x^733 + x^732 + x^729 + x^721 + x^719 + x^716 + x^715 + x^714 + x^713 + x^710 + x^706 + x^705 + x^703 + x^702 + x^700 + x^699 + x^698 + x^696 + x^693 + x^691 + x^690 + x^689 + x^688 + x^684 + x^680 + x^678 + x^677 + x^674 + x^672 + x^669 + x^667 + x^665 + x^663 + x^662 + x^660 + x^659 + x^658 + x^656 + x^652 + x^651 + x^649 + x^646 + x^645 + x^642 + x^641 + x^640 + x^633 + x^632 + x^630 + x^627 + x^626 + x^622 + x^617 + x^612 + x^611 + x^610 + x^606 + x^605 + x^604 + x^603 + x^602 + x^601 + x^599 + x^597 + x^596 + x^594 + x^593 + x^592 + x^591 + x^582 + x^581 + x^580 + x^578 + x^577 + x^575 + x^574 + x^573 + x^568 + x^567 + x^564 + x^560 + x^559 + x^558 + x^556 + x^554 + x^550 + x^548 + x^547 + x^545 + x^544 + x^541 + x^540 + x^539 + x^538 + x^536 + x^535 + x^534 + x^532 + x^531 + x^529 + x^523 + x^521 + x^518 + x^517 + x^516 + x^514 + x^511 + x^510 + x^508 + x^507 + x^505 + x^504 + x^499 + x^498 + x^495 + x^494 + x^492 + x^491 + x^489 + x^488 + x^487 + x^486 + x^484 + x^483 + x^482 + x^481 + x^478 + x^477 + x^476 + x^475 + x^471 + x^470 + x^468 + x^465 + x^464 + x^460 + x^459 + x^455 + x^454 + x^453 + x^451 + x^445 + x^438 + x^434 + x^432 + x^431 + x^430 + x^429 + x^428 + x^427 + x^424 + x^423 + x^419 + x^418 + x^417 + x^416 + x^415 + x^413 + x^411 + x^409 + x^408 + x^406 + x^405 + x^404 + x^403 + x^402 + x^400 + x^397 + x^395 + x^390 + x^389 + x^387 + x^386 + x^385 + x^384 + x^382 + x^380 + x^379 + x^377 + x^376 + x^374 + x^373 + x^370 + x^369 + x^366 + x^365 + x^364 + x^362 + x^360 + x^359 + x^357 + x^356 + x^355 + x^354 + x^352 + x^349 + x^345 + x^342 + x^341 + x^340 + x^338 + x^334 + x^333 + x^326 + x^324 + x^322 + x^321 + x^319 + x^318 + x^317 + x^315 + x^312 + x^311 + x^309 + x^305 + x^304 + x^302 + x^298 + x^297 + x^296 + x^294 + x^293 + x^290 + x^289 + x^287 + x^286 + x^285 + x^279 + x^277 + x^275 + x^273 + x^268 + x^265 + x^264 + x^263 + x^260 + x^258 + x^254 + x^251 + x^249 + x^248 + x^247 + x^245 + x^244 + x^242 + x^241 + x^240 + x^239 + x^232 + x^229 + x^226 + x^225 + x^223 + x^222 + x^220 + x^219 + x^218 + x^215 + x^214 + x^213 + x^212 + x^210 + x^209 + x^206 + x^203 + x^202 + x^199 + x^197 + x^195 + x^194 + x^192 + x^191 + x^189 + x^188 + x^185 + x^184 + x^181 + x^177 + x^176 + x^175 + x^174 + x^172 + x^171 + x^170 + x^169 + x^167 + x^164 + x^162 + x^160 + x^159 + x^157 + x^156 + x^154 + x^153 + x^152 + x^150 + x^148 + x^145 + x^144 + x^139 + x^138 + x^137 + x^136 + x^133 + x^126 + x^124 + x^123 + x^122 + x^121 + x^120 + x^119 + x^113 + x^111 + x^108 + x^105 + x^104 + x^103 + x^102 + x^101 + x^98 + x^97 + x^96 + x^95 + x^92 + x^86 + x^85 + x^83 + x^81 + x^80 + x^77 + x^74 + x^73 + x^72 + x^71 + x^70 + x^68 + x^67 + x^66 + x^64 + x^62 + x^61 + x^60 + x^59 + x^57 + x^53 + x^51 + x^43 + x^41 + x^40 + x^39 + x^35 + x^30 + x^29 + x^27 + x^26 + x^24 + x^20 + x^18 + x^14 + x^6 + 1
+
+8-3-35 389 x^928 + x^898 + x^895 + x^870 + x^865 + x^835 + x^832 + x^824 + x^821 + x^812 + x^810 + x^808 + x^807 + x^805 + x^804 + x^794 + x^791 + x^788 + x^778 + x^777 + x^774 + x^772 + x^771 + x^763 + x^755 + x^752 + x^750 + x^747 + x^746 + x^742 + x^739 + x^733 + x^731 + x^728 + x^725 + x^722 + x^721 + x^720 + x^719 + x^716 + x^714 + x^713 + x^712 + x^711 + x^708 + x^705 + x^704 + x^701 + x^700 + x^698 + x^695 + x^694 + x^692 + x^689 + x^683 + x^680 + x^675 + x^674 + x^670 + x^668 + x^667 + x^664 + x^662 + x^661 + x^658 + x^656 + x^654 + x^651 + x^650 + x^645 + x^643 + x^640 + x^639 + x^637 + x^635 + x^634 + x^633 + x^631 + x^630 + x^628 + x^621 + x^620 + x^616 + x^615 + x^614 + x^613 + x^608 + x^605 + x^604 + x^602 + x^601 + x^598 + x^597 + x^591 + x^590 + x^588 + x^587 + x^581 + x^579 + x^578 + x^577 + x^576 + x^573 + x^572 + x^571 + x^570 + x^569 + x^568 + x^566 + x^564 + x^563 + x^562 + x^559 + x^557 + x^553 + x^550 + x^549 + x^547 + x^546 + x^540 + x^537 + x^536 + x^534 + x^530 + x^527 + x^526 + x^525 + x^524 + x^522 + x^521 + x^520 + x^519 + x^518 + x^510 + x^509 + x^505 + x^504 + x^498 + x^496 + x^493 + x^492 + x^490 + x^489 + x^488 + x^487 + x^484 + x^483 + x^482 + x^481 + x^480 + x^479 + x^477 + x^475 + x^474 + x^472 + x^470 + x^468 + x^465 + x^464 + x^463 + x^461 + x^458 + x^457 + x^455 + x^454 + x^453 + x^452 + x^451 + x^450 + x^448 + x^447 + x^445 + x^441 + x^440 + x^437 + x^435 + x^434 + x^433 + x^432 + x^431 + x^425 + x^421 + x^418 + x^415 + x^413 + x^412 + x^411 + x^410 + x^409 + x^408 + x^404 + x^403 + x^402 + x^399 + x^398 + x^394 + x^393 + x^391 + x^390 + x^389 + x^384 + x^383 + x^381 + x^380 + x^379 + x^378 + x^375 + x^374 + x^372 + x^370 + x^369 + x^367 + x^365 + x^364 + x^363 + x^362 + x^358 + x^357 + x^355 + x^354 + x^353 + x^351 + x^349 + x^347 + x^343 + x^342 + x^338 + x^337 + x^336 + x^334 + x^332 + x^329 + x^328 + x^327 + x^326 + x^323 + x^321 + x^320 + x^319 + x^317 + x^315 + x^311 + x^308 + x^305 + x^304 + x^303 + x^300 + x^298 + x^294 + x^293 + x^292 + x^290 + x^283 + x^281 + x^280 + x^279 + x^276 + x^274 + x^273 + x^269 + x^268 + x^267 + x^266 + x^264 + x^263 + x^259 + x^256 + x^248 + x^247 + x^246 + x^245 + x^244 + x^243 + x^242 + x^241 + x^240 + x^239 + x^235 + x^234 + x^231 + x^228 + x^227 + x^226 + x^225 + x^224 + x^220 + x^219 + x^218 + x^217 + x^216 + x^213 + x^211 + x^210 + x^206 + x^203 + x^200 + x^197 + x^196 + x^195 + x^193 + x^192 + x^191 + x^185 + x^184 + x^180 + x^178 + x^176 + x^175 + x^173 + x^170 + x^169 + x^167 + x^166 + x^165 + x^164 + x^162 + x^161 + x^160 + x^159 + x^154 + x^153 + x^152 + x^147 + x^141 + x^140 + x^138 + x^135 + x^133 + x^132 + x^131 + x^129 + x^127 + x^126 + x^125 + x^119 + x^115 + x^112 + x^111 + x^108 + x^106 + x^99 + x^97 + x^95 + x^94 + x^93 + x^92 + x^91 + x^89 + x^87 + x^84 + x^82 + x^81 + x^78 + x^76 + x^74 + x^69 + x^68 + x^67 + x^65 + x^63 + x^61 + x^58 + x^57 + x^56 + x^55 + x^54 + x^53 + x^51 + x^49 + x^48 + x^47 + x^46 + x^43 + x^40 + x^39 + x^35 + x^34 + x^32 + x^30 + x^28 + x^27 + x^25 + x^24 + x^21 + x^20 + x^15 + x^14 + x^10 + 1
+
+1-12-46 393 x^928 + x^898 + x^896 + x^870 + x^866 + x^836 + x^834 + x^828 + x^826 + x^808 + x^806 + x^804 + x^802 + x^796 + x^794 + x^778 + x^774 + x^767 + x^766 + x^758 + x^756 + x^744 + x^742 + x^740 + x^738 + x^736 + x^732 + x^731 + x^730 + x^727 + x^726 + x^718 + x^712 + x^710 + x^708 + x^707 + x^706 + x^704 + x^703 + x^701 + x^700 + x^699 + x^698 + x^697 + x^696 + x^695 + x^692 + x^686 + x^685 + x^680 + x^676 + x^672 + x^669 + x^668 + x^665 + x^664 + x^662 + x^661 + x^657 + x^656 + x^655 + x^653 + x^647 + x^646 + x^643 + x^640 + x^639 + x^638 + x^635 + x^628 + x^626 + x^623 + x^622 + x^621 + x^615 + x^612 + x^610 + x^609 + x^608 + x^607 + x^605 + x^604 + x^603 + x^602 + x^600 + x^599 + x^598 + x^597 + x^590 + x^589 + x^587 + x^586 + x^584 + x^583 + x^582 + x^581 + x^579 + x^578 + x^577 + x^576 + x^574 + x^573 + x^571 + x^567 + x^563 + x^561 + x^560 + x^559 + x^556 + x^554 + x^550 + x^548 + x^545 + x^544 + x^542 + x^535 + x^530 + x^529 + x^528 + x^526 + x^524 + x^522 + x^521 + x^519 + x^517 + x^516 + x^515 + x^512 + x^508 + x^507 + x^506 + x^505 + x^504 + x^499 + x^498 + x^497 + x^496 + x^495 + x^494 + x^489 + x^488 + x^487 + x^486 + x^484 + x^483 + x^481 + x^477 + x^476 + x^475 + x^474 + x^473 + x^471 + x^469 + x^466 + x^465 + x^464 + x^461 + x^460 + x^459 + x^457 + x^455 + x^452 + x^451 + x^449 + x^448 + x^447 + x^446 + x^445 + x^443 + x^442 + x^440 + x^439 + x^438 + x^433 + x^427 + x^425 + x^424 + x^422 + x^421 + x^419 + x^416 + x^415 + x^414 + x^413 + x^412 + x^408 + x^405 + x^404 + x^403 + x^402 + x^399 + x^398 + x^397 + x^396 + x^394 + x^393 + x^392 + x^391 + x^389 + x^388 + x^387 + x^386 + x^384 + x^381 + x^380 + x^376 + x^375 + x^374 + x^373 + x^366 + x^363 + x^362 + x^359 + x^358 + x^357 + x^356 + x^355 + x^353 + x^352 + x^351 + x^347 + x^344 + x^343 + x^342 + x^341 + x^339 + x^337 + x^336 + x^333 + x^331 + x^329 + x^328 + x^327 + x^326 + x^325 + x^321 + x^320 + x^317 + x^316 + x^315 + x^312 + x^311 + x^310 + x^307 + x^306 + x^303 + x^300 + x^298 + x^296 + x^295 + x^292 + x^291 + x^290 + x^287 + x^283 + x^279 + x^278 + x^277 + x^276 + x^273 + x^272 + x^271 + x^270 + x^269 + x^263 + x^262 + x^257 + x^256 + x^255 + x^254 + x^252 + x^249 + x^247 + x^245 + x^242 + x^241 + x^240 + x^235 + x^234 + x^233 + x^232 + x^231 + x^230 + x^229 + x^227 + x^225 + x^224 + x^223 + x^222 + x^219 + x^218 + x^217 + x^216 + x^215 + x^214 + x^213 + x^211 + x^206 + x^205 + x^203 + x^200 + x^199 + x^196 + x^194 + x^191 + x^186 + x^185 + x^183 + x^180 + x^179 + x^177 + x^176 + x^175 + x^174 + x^172 + x^171 + x^170 + x^169 + x^167 + x^160 + x^159 + x^158 + x^157 + x^156 + x^155 + x^154 + x^152 + x^146 + x^145 + x^144 + x^143 + x^142 + x^141 + x^139 + x^138 + x^137 + x^134 + x^133 + x^129 + x^126 + x^125 + x^124 + x^122 + x^121 + x^119 + x^118 + x^117 + x^113 + x^111 + x^110 + x^109 + x^108 + x^99 + x^98 + x^97 + x^95 + x^93 + x^92 + x^90 + x^85 + x^78 + x^76 + x^75 + x^70 + x^69 + x^65 + x^64 + x^63 + x^62 + x^59 + x^56 + x^54 + x^53 + x^51 + x^50 + x^49 + x^45 + x^44 + x^42 + x^41 + x^39 + x^36 + x^35 + x^34 + x^32 + x^31 + x^30 + x^23 + x^20 + x^16 + x^13 + x^12 + 1
+
+21-29-14 393 x^928 + x^898 + x^885 + x^870 + x^858 + x^856 + x^855 + x^831 + x^829 + x^828 + x^826 + x^815 + x^813 + x^812 + x^808 + x^804 + x^802 + x^801 + x^799 + x^798 + x^796 + x^788 + x^785 + x^778 + x^777 + x^775 + x^774 + x^772 + x^769 + x^768 + x^766 + x^765 + x^758 + x^752 + x^748 + x^747 + x^742 + x^741 + x^739 + x^738 + x^736 + x^735 + x^732 + x^728 + x^726 + x^725 + x^721 + x^718 + x^717 + x^714 + x^712 + x^709 + x^708 + x^706 + x^705 + x^702 + x^701 + x^699 + x^698 + x^694 + x^691 + x^687 + x^685 + x^684 + x^682 + x^681 + x^680 + x^679 + x^676 + x^675 + x^674 + x^671 + x^667 + x^664 + x^658 + x^657 + x^655 + x^653 + x^652 + x^650 + x^649 + x^648 + x^647 + x^646 + x^644 + x^641 + x^640 + x^637 + x^635 + x^632 + x^627 + x^625 + x^623 + x^622 + x^619 + x^618 + x^617 + x^613 + x^610 + x^608 + x^601 + x^595 + x^593 + x^592 + x^586 + x^585 + x^583 + x^582 + x^577 + x^572 + x^571 + x^570 + x^568 + x^565 + x^563 + x^561 + x^559 + x^557 + x^555 + x^553 + x^550 + x^548 + x^545 + x^544 + x^538 + x^537 + x^534 + x^532 + x^529 + x^526 + x^525 + x^521 + x^520 + x^518 + x^512 + x^511 + x^510 + x^508 + x^507 + x^503 + x^501 + x^500 + x^499 + x^498 + x^497 + x^496 + x^494 + x^489 + x^486 + x^485 + x^481 + x^480 + x^477 + x^476 + x^475 + x^466 + x^464 + x^462 + x^461 + x^460 + x^459 + x^458 + x^454 + x^452 + x^451 + x^449 + x^447 + x^446 + x^444 + x^441 + x^440 + x^439 + x^433 + x^431 + x^430 + x^429 + x^427 + x^425 + x^424 + x^422 + x^416 + x^414 + x^412 + x^408 + x^406 + x^403 + x^402 + x^401 + x^399 + x^398 + x^395 + x^393 + x^390 + x^389 + x^387 + x^386 + x^385 + x^384 + x^383 + x^381 + x^380 + x^378 + x^375 + x^374 + x^372 + x^371 + x^370 + x^368 + x^367 + x^362 + x^361 + x^358 + x^356 + x^354 + x^353 + x^351 + x^350 + x^347 + x^346 + x^343 + x^340 + x^339 + x^337 + x^335 + x^331 + x^330 + x^329 + x^328 + x^326 + x^325 + x^323 + x^322 + x^319 + x^318 + x^316 + x^315 + x^311 + x^310 + x^309 + x^308 + x^306 + x^304 + x^303 + x^298 + x^296 + x^295 + x^294 + x^292 + x^291 + x^290 + x^289 + x^287 + x^284 + x^281 + x^280 + x^276 + x^274 + x^272 + x^271 + x^270 + x^268 + x^267 + x^259 + x^258 + x^257 + x^256 + x^255 + x^254 + x^249 + x^248 + x^247 + x^246 + x^244 + x^243 + x^241 + x^240 + x^236 + x^234 + x^233 + x^232 + x^229 + x^224 + x^221 + x^220 + x^217 + x^216 + x^215 + x^213 + x^211 + x^210 + x^208 + x^207 + x^200 + x^199 + x^198 + x^197 + x^196 + x^195 + x^193 + x^192 + x^191 + x^190 + x^185 + x^184 + x^183 + x^181 + x^179 + x^176 + x^173 + x^170 + x^169 + x^168 + x^164 + x^162 + x^160 + x^157 + x^155 + x^154 + x^152 + x^151 + x^150 + x^149 + x^146 + x^144 + x^143 + x^142 + x^140 + x^136 + x^134 + x^132 + x^130 + x^129 + x^128 + x^126 + x^123 + x^120 + x^117 + x^112 + x^111 + x^108 + x^107 + x^105 + x^103 + x^100 + x^99 + x^96 + x^95 + x^91 + x^90 + x^89 + x^87 + x^86 + x^84 + x^83 + x^81 + x^79 + x^78 + x^76 + x^69 + x^68 + x^67 + x^66 + x^62 + x^61 + x^57 + x^56 + x^55 + x^53 + x^52 + x^51 + x^49 + x^48 + x^46 + x^43 + x^40 + x^38 + x^37 + x^36 + x^35 + x^34 + x^33 + x^31 + x^30 + x^29 + x^28 + x^27 + x^26 + x^24 + x^21 + x^20 + x^17 + x^13 + 1
+
+37-29-44 393 x^928 + x^898 + x^885 + x^870 + x^858 + x^856 + x^855 + x^831 + x^829 + x^828 + x^826 + x^815 + x^813 + x^812 + x^808 + x^804 + x^802 + x^801 + x^799 + x^798 + x^796 + x^788 + x^785 + x^778 + x^777 + x^775 + x^774 + x^772 + x^769 + x^768 + x^766 + x^765 + x^758 + x^752 + x^748 + x^747 + x^742 + x^741 + x^739 + x^738 + x^736 + x^735 + x^732 + x^728 + x^726 + x^725 + x^721 + x^718 + x^717 + x^714 + x^712 + x^709 + x^708 + x^706 + x^705 + x^702 + x^701 + x^699 + x^698 + x^694 + x^691 + x^687 + x^685 + x^684 + x^682 + x^681 + x^680 + x^679 + x^676 + x^675 + x^674 + x^671 + x^667 + x^664 + x^658 + x^657 + x^655 + x^653 + x^652 + x^650 + x^649 + x^648 + x^647 + x^646 + x^644 + x^641 + x^640 + x^637 + x^635 + x^632 + x^627 + x^625 + x^623 + x^622 + x^619 + x^618 + x^617 + x^613 + x^610 + x^608 + x^601 + x^595 + x^593 + x^592 + x^586 + x^585 + x^583 + x^582 + x^577 + x^572 + x^571 + x^570 + x^568 + x^565 + x^563 + x^561 + x^559 + x^557 + x^555 + x^553 + x^550 + x^548 + x^545 + x^544 + x^538 + x^537 + x^534 + x^532 + x^529 + x^526 + x^525 + x^521 + x^520 + x^518 + x^512 + x^511 + x^510 + x^508 + x^507 + x^503 + x^501 + x^500 + x^499 + x^498 + x^497 + x^496 + x^494 + x^489 + x^486 + x^485 + x^481 + x^480 + x^477 + x^476 + x^475 + x^466 + x^464 + x^462 + x^461 + x^460 + x^459 + x^458 + x^454 + x^452 + x^451 + x^449 + x^447 + x^446 + x^444 + x^441 + x^440 + x^439 + x^433 + x^431 + x^430 + x^429 + x^427 + x^425 + x^424 + x^422 + x^416 + x^414 + x^412 + x^408 + x^406 + x^403 + x^402 + x^401 + x^399 + x^398 + x^395 + x^393 + x^390 + x^389 + x^387 + x^386 + x^385 + x^384 + x^383 + x^381 + x^380 + x^378 + x^375 + x^374 + x^372 + x^371 + x^370 + x^368 + x^367 + x^362 + x^361 + x^358 + x^356 + x^354 + x^353 + x^351 + x^350 + x^347 + x^346 + x^343 + x^340 + x^339 + x^337 + x^335 + x^331 + x^330 + x^329 + x^328 + x^326 + x^325 + x^323 + x^322 + x^319 + x^318 + x^316 + x^315 + x^311 + x^310 + x^309 + x^308 + x^306 + x^304 + x^303 + x^298 + x^296 + x^295 + x^294 + x^292 + x^291 + x^290 + x^289 + x^287 + x^284 + x^281 + x^280 + x^276 + x^274 + x^272 + x^271 + x^270 + x^268 + x^267 + x^259 + x^258 + x^257 + x^256 + x^255 + x^254 + x^249 + x^248 + x^247 + x^246 + x^244 + x^243 + x^241 + x^240 + x^236 + x^234 + x^233 + x^232 + x^229 + x^224 + x^221 + x^220 + x^217 + x^216 + x^215 + x^213 + x^211 + x^210 + x^208 + x^207 + x^200 + x^199 + x^198 + x^197 + x^196 + x^195 + x^193 + x^192 + x^191 + x^190 + x^185 + x^184 + x^183 + x^181 + x^179 + x^176 + x^173 + x^170 + x^169 + x^168 + x^164 + x^162 + x^160 + x^157 + x^155 + x^154 + x^152 + x^151 + x^150 + x^149 + x^146 + x^144 + x^143 + x^142 + x^140 + x^136 + x^134 + x^132 + x^130 + x^129 + x^128 + x^126 + x^123 + x^120 + x^117 + x^112 + x^111 + x^108 + x^107 + x^105 + x^103 + x^100 + x^99 + x^96 + x^95 + x^91 + x^90 + x^89 + x^87 + x^86 + x^84 + x^83 + x^81 + x^79 + x^78 + x^76 + x^69 + x^68 + x^67 + x^66 + x^62 + x^61 + x^57 + x^56 + x^55 + x^53 + x^52 + x^51 + x^49 + x^48 + x^46 + x^43 + x^40 + x^38 + x^37 + x^36 + x^35 + x^34 + x^33 + x^31 + x^30 + x^29 + x^28 + x^27 + x^26 + x^24 + x^21 + x^20 + x^17 + x^13 + 1
+
+7-48-42 393 x^928 + x^898 + x^892 + x^870 + x^862 + x^843 + x^820 + x^813 + x^808 + x^800 + x^794 + x^784 + x^783 + x^780 + x^778 + x^774 + x^771 + x^770 + x^767 + x^760 + x^757 + x^753 + x^750 + x^748 + x^743 + x^741 + x^740 + x^737 + x^731 + x^727 + x^724 + x^723 + x^718 + x^713 + x^707 + x^705 + x^704 + x^701 + x^700 + x^697 + x^695 + x^693 + x^688 + x^684 + x^683 + x^682 + x^681 + x^678 + x^677 + x^674 + x^671 + x^669 + x^667 + x^664 + x^663 + x^660 + x^653 + x^652 + x^651 + x^650 + x^649 + x^645 + x^644 + x^641 + x^639 + x^638 + x^637 + x^634 + x^633 + x^630 + x^628 + x^625 + x^623 + x^621 + x^620 + x^619 + x^615 + x^612 + x^611 + x^608 + x^607 + x^605 + x^604 + x^603 + x^599 + x^595 + x^593 + x^585 + x^584 + x^581 + x^580 + x^578 + x^577 + x^575 + x^573 + x^572 + x^569 + x^568 + x^565 + x^564 + x^563 + x^561 + x^558 + x^557 + x^551 + x^550 + x^548 + x^547 + x^544 + x^538 + x^537 + x^534 + x^533 + x^532 + x^530 + x^529 + x^524 + x^522 + x^521 + x^519 + x^518 + x^516 + x^515 + x^514 + x^513 + x^512 + x^510 + x^508 + x^506 + x^505 + x^502 + x^501 + x^500 + x^499 + x^496 + x^493 + x^492 + x^491 + x^488 + x^487 + x^483 + x^482 + x^481 + x^479 + x^478 + x^476 + x^475 + x^474 + x^473 + x^472 + x^471 + x^470 + x^469 + x^467 + x^463 + x^460 + x^458 + x^453 + x^452 + x^451 + x^447 + x^446 + x^445 + x^439 + x^435 + x^434 + x^433 + x^432 + x^431 + x^430 + x^428 + x^427 + x^425 + x^421 + x^420 + x^419 + x^417 + x^415 + x^413 + x^412 + x^410 + x^407 + x^406 + x^405 + x^404 + x^402 + x^400 + x^397 + x^395 + x^394 + x^393 + x^392 + x^391 + x^390 + x^388 + x^385 + x^381 + x^378 + x^377 + x^376 + x^374 + x^373 + x^370 + x^369 + x^368 + x^366 + x^365 + x^364 + x^363 + x^361 + x^358 + x^356 + x^355 + x^354 + x^351 + x^350 + x^348 + x^347 + x^344 + x^341 + x^340 + x^337 + x^335 + x^334 + x^329 + x^326 + x^325 + x^324 + x^322 + x^321 + x^319 + x^318 + x^314 + x^312 + x^311 + x^310 + x^309 + x^308 + x^307 + x^303 + x^302 + x^301 + x^298 + x^293 + x^292 + x^291 + x^288 + x^281 + x^280 + x^279 + x^278 + x^275 + x^271 + x^270 + x^267 + x^265 + x^264 + x^263 + x^262 + x^261 + x^260 + x^259 + x^258 + x^257 + x^256 + x^253 + x^252 + x^251 + x^250 + x^249 + x^248 + x^247 + x^244 + x^243 + x^242 + x^240 + x^237 + x^236 + x^233 + x^227 + x^226 + x^224 + x^222 + x^221 + x^220 + x^219 + x^218 + x^217 + x^216 + x^213 + x^212 + x^210 + x^208 + x^207 + x^206 + x^205 + x^202 + x^201 + x^200 + x^197 + x^195 + x^194 + x^193 + x^192 + x^191 + x^190 + x^189 + x^186 + x^184 + x^183 + x^182 + x^181 + x^178 + x^177 + x^176 + x^170 + x^168 + x^167 + x^166 + x^162 + x^159 + x^157 + x^149 + x^148 + x^147 + x^143 + x^141 + x^139 + x^138 + x^136 + x^135 + x^131 + x^127 + x^121 + x^119 + x^117 + x^114 + x^110 + x^109 + x^107 + x^103 + x^99 + x^98 + x^96 + x^95 + x^94 + x^92 + x^90 + x^89 + x^88 + x^87 + x^86 + x^85 + x^84 + x^82 + x^80 + x^79 + x^78 + x^77 + x^76 + x^74 + x^71 + x^69 + x^68 + x^66 + x^64 + x^62 + x^61 + x^58 + x^57 + x^53 + x^50 + x^46 + x^44 + x^43 + x^42 + x^41 + x^40 + x^37 + x^35 + x^34 + x^32 + x^31 + x^29 + x^27 + x^26 + x^25 + x^22 + x^20 + x^16 + x^12 + x^10 + 1
+
+57-51-22 397 x^928 + x^898 + x^895 + x^870 + x^866 + x^865 + x^862 + x^860 + x^857 + x^835 + x^833 + x^832 + x^828 + x^822 + x^819 + x^810 + x^808 + x^805 + x^797 + x^796 + x^791 + x^790 + x^789 + x^786 + x^784 + x^782 + x^781 + x^778 + x^777 + x^773 + x^767 + x^766 + x^762 + x^757 + x^752 + x^743 + x^742 + x^737 + x^734 + x^717 + x^715 + x^713 + x^708 + x^707 + x^706 + x^705 + x^703 + x^702 + x^701 + x^698 + x^696 + x^690 + x^688 + x^685 + x^683 + x^682 + x^680 + x^677 + x^673 + x^671 + x^668 + x^667 + x^666 + x^663 + x^662 + x^661 + x^656 + x^654 + x^653 + x^649 + x^647 + x^646 + x^645 + x^643 + x^637 + x^635 + x^632 + x^630 + x^629 + x^627 + x^626 + x^625 + x^624 + x^622 + x^619 + x^613 + x^610 + x^608 + x^602 + x^597 + x^594 + x^593 + x^591 + x^590 + x^587 + x^586 + x^584 + x^583 + x^582 + x^580 + x^577 + x^575 + x^574 + x^573 + x^570 + x^569 + x^568 + x^562 + x^556 + x^553 + x^552 + x^551 + x^550 + x^547 + x^546 + x^545 + x^543 + x^541 + x^539 + x^538 + x^535 + x^534 + x^533 + x^528 + x^527 + x^526 + x^524 + x^522 + x^521 + x^515 + x^512 + x^509 + x^505 + x^503 + x^502 + x^501 + x^500 + x^499 + x^498 + x^497 + x^493 + x^491 + x^483 + x^480 + x^477 + x^474 + x^473 + x^472 + x^471 + x^470 + x^468 + x^467 + x^463 + x^459 + x^458 + x^457 + x^455 + x^453 + x^452 + x^451 + x^448 + x^447 + x^446 + x^445 + x^444 + x^443 + x^440 + x^439 + x^436 + x^435 + x^434 + x^432 + x^430 + x^429 + x^428 + x^427 + x^426 + x^423 + x^422 + x^421 + x^420 + x^417 + x^416 + x^415 + x^414 + x^413 + x^411 + x^410 + x^407 + x^406 + x^403 + x^401 + x^400 + x^391 + x^390 + x^387 + x^386 + x^385 + x^381 + x^380 + x^379 + x^377 + x^374 + x^373 + x^370 + x^369 + x^362 + x^359 + x^357 + x^356 + x^355 + x^354 + x^349 + x^346 + x^345 + x^344 + x^343 + x^340 + x^339 + x^338 + x^337 + x^336 + x^334 + x^331 + x^330 + x^328 + x^323 + x^322 + x^321 + x^319 + x^318 + x^317 + x^316 + x^314 + x^313 + x^312 + x^311 + x^310 + x^305 + x^303 + x^299 + x^295 + x^294 + x^293 + x^290 + x^289 + x^286 + x^285 + x^284 + x^281 + x^280 + x^278 + x^275 + x^272 + x^271 + x^269 + x^267 + x^266 + x^263 + x^262 + x^261 + x^260 + x^258 + x^257 + x^256 + x^255 + x^254 + x^253 + x^252 + x^251 + x^247 + x^246 + x^241 + x^240 + x^239 + x^238 + x^236 + x^233 + x^232 + x^230 + x^228 + x^224 + x^223 + x^220 + x^216 + x^215 + x^213 + x^212 + x^211 + x^208 + x^206 + x^205 + x^204 + x^201 + x^199 + x^197 + x^195 + x^194 + x^193 + x^191 + x^189 + x^188 + x^187 + x^186 + x^185 + x^184 + x^182 + x^179 + x^178 + x^176 + x^172 + x^171 + x^170 + x^169 + x^168 + x^167 + x^166 + x^163 + x^162 + x^161 + x^160 + x^157 + x^156 + x^155 + x^153 + x^152 + x^148 + x^145 + x^142 + x^140 + x^139 + x^137 + x^134 + x^133 + x^131 + x^123 + x^119 + x^118 + x^114 + x^112 + x^111 + x^110 + x^108 + x^107 + x^105 + x^104 + x^102 + x^99 + x^98 + x^95 + x^94 + x^93 + x^89 + x^88 + x^86 + x^84 + x^82 + x^80 + x^78 + x^76 + x^73 + x^71 + x^70 + x^68 + x^67 + x^66 + x^64 + x^62 + x^60 + x^59 + x^57 + x^53 + x^52 + x^49 + x^48 + x^47 + x^46 + x^40 + x^37 + x^36 + x^35 + x^34 + x^32 + x^31 + x^28 + x^26 + x^25 + x^24 + x^22 + x^20 + x^19 + x^18 + x^15 + x^10 + x^8 + x^5 + 1
+
+41-40-20 399 x^928 + x^898 + x^870 + x^846 + x^844 + x^821 + x^820 + x^816 + x^814 + x^808 + x^804 + x^801 + x^800 + x^798 + x^795 + x^778 + x^771 + x^770 + x^769 + x^768 + x^765 + x^760 + x^749 + x^748 + x^744 + x^743 + x^741 + x^738 + x^734 + x^729 + x^726 + x^719 + x^717 + x^716 + x^715 + x^714 + x^713 + x^712 + x^711 + x^710 + x^709 + x^706 + x^704 + x^703 + x^702 + x^701 + x^694 + x^693 + x^691 + x^690 + x^685 + x^684 + x^682 + x^681 + x^680 + x^678 + x^677 + x^676 + x^675 + x^674 + x^673 + x^671 + x^669 + x^667 + x^665 + x^661 + x^660 + x^659 + x^658 + x^656 + x^652 + x^651 + x^649 + x^648 + x^643 + x^642 + x^639 + x^637 + x^634 + x^631 + x^629 + x^628 + x^624 + x^620 + x^619 + x^618 + x^617 + x^616 + x^615 + x^614 + x^613 + x^611 + x^610 + x^605 + x^604 + x^603 + x^601 + x^599 + x^598 + x^595 + x^594 + x^593 + x^590 + x^589 + x^585 + x^584 + x^583 + x^579 + x^577 + x^575 + x^573 + x^572 + x^571 + x^570 + x^569 + x^566 + x^564 + x^562 + x^561 + x^560 + x^557 + x^555 + x^554 + x^553 + x^552 + x^551 + x^550 + x^549 + x^547 + x^545 + x^542 + x^540 + x^539 + x^538 + x^537 + x^536 + x^535 + x^533 + x^532 + x^530 + x^529 + x^524 + x^518 + x^516 + x^514 + x^513 + x^512 + x^510 + x^509 + x^504 + x^503 + x^501 + x^493 + x^490 + x^489 + x^487 + x^486 + x^485 + x^484 + x^481 + x^479 + x^478 + x^475 + x^473 + x^471 + x^470 + x^468 + x^467 + x^466 + x^462 + x^460 + x^455 + x^454 + x^451 + x^450 + x^449 + x^447 + x^446 + x^445 + x^444 + x^443 + x^442 + x^441 + x^440 + x^439 + x^438 + x^436 + x^430 + x^429 + x^424 + x^423 + x^420 + x^419 + x^418 + x^415 + x^414 + x^413 + x^410 + x^409 + x^408 + x^407 + x^406 + x^405 + x^403 + x^402 + x^400 + x^398 + x^397 + x^396 + x^395 + x^394 + x^392 + x^391 + x^389 + x^387 + x^386 + x^385 + x^383 + x^382 + x^381 + x^379 + x^375 + x^374 + x^369 + x^367 + x^366 + x^365 + x^363 + x^360 + x^359 + x^358 + x^357 + x^355 + x^354 + x^351 + x^339 + x^338 + x^337 + x^336 + x^335 + x^334 + x^332 + x^330 + x^329 + x^323 + x^320 + x^317 + x^315 + x^312 + x^311 + x^309 + x^305 + x^302 + x^301 + x^300 + x^299 + x^298 + x^297 + x^296 + x^295 + x^292 + x^291 + x^288 + x^286 + x^285 + x^284 + x^283 + x^282 + x^280 + x^279 + x^278 + x^273 + x^268 + x^267 + x^264 + x^263 + x^258 + x^257 + x^256 + x^255 + x^254 + x^253 + x^250 + x^249 + x^248 + x^244 + x^243 + x^242 + x^238 + x^237 + x^236 + x^234 + x^233 + x^231 + x^230 + x^222 + x^218 + x^215 + x^214 + x^211 + x^208 + x^206 + x^205 + x^201 + x^200 + x^198 + x^197 + x^195 + x^194 + x^193 + x^191 + x^189 + x^185 + x^182 + x^179 + x^176 + x^174 + x^173 + x^164 + x^163 + x^162 + x^159 + x^158 + x^156 + x^155 + x^152 + x^150 + x^148 + x^142 + x^140 + x^139 + x^138 + x^137 + x^135 + x^134 + x^133 + x^132 + x^131 + x^128 + x^124 + x^122 + x^121 + x^120 + x^119 + x^117 + x^116 + x^114 + x^111 + x^110 + x^108 + x^107 + x^105 + x^104 + x^103 + x^101 + x^95 + x^94 + x^93 + x^91 + x^89 + x^88 + x^87 + x^84 + x^83 + x^82 + x^81 + x^80 + x^79 + x^78 + x^77 + x^76 + x^74 + x^73 + x^72 + x^66 + x^65 + x^64 + x^59 + x^57 + x^56 + x^53 + x^49 + x^47 + x^44 + x^43 + x^39 + x^38 + x^37 + x^34 + x^33 + x^32 + x^31 + x^28 + x^23 + x^22 + x^19 + x^12 + x^8 + 1
+
+55-27-24 399 x^928 + x^898 + x^864 + x^847 + x^846 + x^834 + x^824 + x^818 + x^817 + x^816 + x^812 + x^810 + x^808 + x^806 + x^801 + x^800 + x^795 + x^794 + x^788 + x^783 + x^781 + x^777 + x^776 + x^775 + x^771 + x^765 + x^764 + x^753 + x^750 + x^749 + x^747 + x^746 + x^745 + x^743 + x^742 + x^741 + x^737 + x^734 + x^731 + x^728 + x^726 + x^725 + x^724 + x^721 + x^719 + x^717 + x^716 + x^714 + x^712 + x^706 + x^704 + x^703 + x^702 + x^701 + x^699 + x^698 + x^697 + x^695 + x^694 + x^691 + x^690 + x^688 + x^687 + x^684 + x^683 + x^681 + x^680 + x^673 + x^672 + x^670 + x^667 + x^666 + x^664 + x^663 + x^661 + x^659 + x^657 + x^655 + x^650 + x^649 + x^647 + x^640 + x^639 + x^637 + x^636 + x^634 + x^630 + x^626 + x^625 + x^623 + x^622 + x^620 + x^618 + x^617 + x^615 + x^612 + x^611 + x^609 + x^608 + x^607 + x^605 + x^604 + x^602 + x^600 + x^599 + x^596 + x^594 + x^592 + x^590 + x^587 + x^581 + x^578 + x^576 + x^575 + x^574 + x^570 + x^567 + x^566 + x^565 + x^564 + x^563 + x^561 + x^560 + x^555 + x^554 + x^553 + x^552 + x^551 + x^550 + x^549 + x^548 + x^543 + x^537 + x^536 + x^533 + x^532 + x^531 + x^529 + x^528 + x^527 + x^525 + x^524 + x^523 + x^522 + x^519 + x^518 + x^516 + x^515 + x^514 + x^513 + x^512 + x^511 + x^509 + x^507 + x^505 + x^500 + x^498 + x^497 + x^496 + x^494 + x^489 + x^486 + x^481 + x^480 + x^479 + x^476 + x^471 + x^469 + x^467 + x^466 + x^463 + x^459 + x^455 + x^451 + x^450 + x^449 + x^448 + x^447 + x^445 + x^444 + x^441 + x^440 + x^432 + x^430 + x^429 + x^428 + x^426 + x^424 + x^420 + x^418 + x^416 + x^415 + x^413 + x^411 + x^408 + x^406 + x^405 + x^404 + x^400 + x^398 + x^392 + x^390 + x^387 + x^386 + x^382 + x^379 + x^378 + x^377 + x^376 + x^374 + x^373 + x^371 + x^370 + x^368 + x^367 + x^365 + x^364 + x^363 + x^362 + x^360 + x^358 + x^351 + x^350 + x^344 + x^343 + x^341 + x^340 + x^339 + x^338 + x^337 + x^332 + x^331 + x^329 + x^327 + x^323 + x^321 + x^320 + x^318 + x^317 + x^314 + x^313 + x^312 + x^311 + x^309 + x^308 + x^306 + x^304 + x^301 + x^300 + x^299 + x^296 + x^295 + x^294 + x^291 + x^290 + x^287 + x^286 + x^285 + x^280 + x^275 + x^274 + x^271 + x^270 + x^268 + x^264 + x^263 + x^258 + x^257 + x^256 + x^254 + x^252 + x^249 + x^248 + x^246 + x^245 + x^242 + x^241 + x^239 + x^238 + x^236 + x^233 + x^231 + x^228 + x^226 + x^225 + x^222 + x^219 + x^218 + x^217 + x^216 + x^215 + x^213 + x^210 + x^209 + x^207 + x^205 + x^203 + x^202 + x^198 + x^197 + x^196 + x^193 + x^192 + x^189 + x^188 + x^187 + x^184 + x^183 + x^182 + x^181 + x^179 + x^178 + x^177 + x^175 + x^172 + x^171 + x^170 + x^169 + x^164 + x^162 + x^161 + x^160 + x^159 + x^155 + x^154 + x^152 + x^151 + x^148 + x^147 + x^143 + x^140 + x^139 + x^137 + x^134 + x^133 + x^132 + x^131 + x^126 + x^125 + x^120 + x^119 + x^118 + x^117 + x^113 + x^111 + x^110 + x^108 + x^104 + x^102 + x^101 + x^100 + x^97 + x^96 + x^90 + x^89 + x^85 + x^82 + x^81 + x^77 + x^76 + x^73 + x^69 + x^68 + x^67 + x^65 + x^64 + x^63 + x^62 + x^61 + x^55 + x^54 + x^53 + x^52 + x^49 + x^47 + x^46 + x^40 + x^39 + x^37 + x^36 + x^35 + x^34 + x^33 + x^32 + x^31 + x^29 + x^26 + x^25 + x^24 + x^23 + x^22 + x^19 + x^17 + x^16 + x^12 + x^9 + x^8 + x^5 + 1
+
+39-32-32 401 x^928 + x^898 + x^870 + x^867 + x^842 + x^837 + x^836 + x^832 + x^807 + x^806 + x^805 + x^802 + x^801 + x^780 + x^778 + x^775 + x^773 + x^771 + x^770 + x^768 + x^766 + x^758 + x^752 + x^749 + x^747 + x^740 + x^730 + x^724 + x^721 + x^719 + x^717 + x^716 + x^715 + x^714 + x^713 + x^711 + x^709 + x^708 + x^707 + x^704 + x^702 + x^700 + x^696 + x^693 + x^691 + x^689 + x^687 + x^686 + x^685 + x^683 + x^682 + x^680 + x^679 + x^677 + x^676 + x^674 + x^670 + x^669 + x^668 + x^665 + x^663 + x^661 + x^660 + x^659 + x^655 + x^653 + x^652 + x^651 + x^648 + x^647 + x^646 + x^645 + x^644 + x^642 + x^641 + x^640 + x^639 + x^638 + x^637 + x^635 + x^634 + x^633 + x^632 + x^631 + x^630 + x^625 + x^624 + x^620 + x^618 + x^615 + x^613 + x^611 + x^606 + x^605 + x^604 + x^602 + x^599 + x^597 + x^596 + x^593 + x^592 + x^591 + x^590 + x^589 + x^585 + x^584 + x^583 + x^580 + x^578 + x^577 + x^576 + x^575 + x^574 + x^572 + x^571 + x^570 + x^568 + x^567 + x^566 + x^563 + x^562 + x^560 + x^556 + x^554 + x^552 + x^549 + x^548 + x^547 + x^546 + x^544 + x^538 + x^536 + x^535 + x^534 + x^533 + x^530 + x^529 + x^528 + x^527 + x^526 + x^525 + x^524 + x^521 + x^519 + x^517 + x^516 + x^514 + x^513 + x^512 + x^510 + x^509 + x^507 + x^506 + x^504 + x^502 + x^500 + x^499 + x^498 + x^497 + x^493 + x^492 + x^490 + x^489 + x^485 + x^484 + x^481 + x^476 + x^475 + x^473 + x^467 + x^463 + x^462 + x^461 + x^459 + x^456 + x^453 + x^450 + x^449 + x^448 + x^445 + x^443 + x^442 + x^440 + x^438 + x^436 + x^433 + x^432 + x^431 + x^430 + x^429 + x^427 + x^421 + x^420 + x^419 + x^416 + x^415 + x^414 + x^413 + x^411 + x^410 + x^408 + x^407 + x^406 + x^405 + x^403 + x^400 + x^398 + x^397 + x^396 + x^394 + x^390 + x^389 + x^388 + x^385 + x^384 + x^383 + x^379 + x^376 + x^374 + x^373 + x^372 + x^370 + x^369 + x^368 + x^364 + x^362 + x^358 + x^355 + x^354 + x^353 + x^351 + x^348 + x^347 + x^344 + x^343 + x^339 + x^337 + x^336 + x^334 + x^333 + x^329 + x^328 + x^323 + x^321 + x^320 + x^319 + x^318 + x^317 + x^315 + x^314 + x^311 + x^309 + x^307 + x^306 + x^304 + x^302 + x^300 + x^297 + x^295 + x^294 + x^291 + x^289 + x^287 + x^285 + x^284 + x^283 + x^282 + x^281 + x^280 + x^278 + x^277 + x^276 + x^270 + x^269 + x^268 + x^267 + x^263 + x^261 + x^259 + x^257 + x^255 + x^253 + x^252 + x^250 + x^248 + x^247 + x^245 + x^244 + x^242 + x^241 + x^240 + x^238 + x^234 + x^233 + x^230 + x^227 + x^226 + x^224 + x^220 + x^219 + x^217 + x^216 + x^215 + x^209 + x^208 + x^207 + x^206 + x^205 + x^204 + x^203 + x^201 + x^199 + x^198 + x^197 + x^196 + x^193 + x^191 + x^187 + x^184 + x^183 + x^182 + x^173 + x^172 + x^169 + x^167 + x^166 + x^165 + x^162 + x^161 + x^160 + x^158 + x^157 + x^156 + x^155 + x^154 + x^152 + x^151 + x^149 + x^147 + x^141 + x^138 + x^137 + x^136 + x^135 + x^134 + x^131 + x^129 + x^126 + x^125 + x^122 + x^121 + x^117 + x^116 + x^113 + x^110 + x^109 + x^108 + x^104 + x^102 + x^101 + x^100 + x^98 + x^97 + x^95 + x^94 + x^87 + x^83 + x^82 + x^78 + x^77 + x^74 + x^73 + x^72 + x^70 + x^69 + x^66 + x^65 + x^62 + x^60 + x^55 + x^54 + x^52 + x^51 + x^49 + x^46 + x^45 + x^41 + x^40 + x^37 + x^33 + x^31 + x^29 + x^27 + x^26 + x^24 + x^20 + x^18 + x^17 + x^15 + x^6 + 1
+
+40-7-11 401 x^928 + x^898 + x^897 + x^882 + x^870 + x^866 + x^860 + x^854 + x^852 + x^851 + x^836 + x^832 + x^830 + x^829 + x^826 + x^824 + x^820 + x^814 + x^812 + x^811 + x^808 + x^806 + x^804 + x^800 + x^796 + x^793 + x^792 + x^790 + x^786 + x^780 + x^778 + x^777 + x^774 + x^770 + x^769 + x^767 + x^762 + x^761 + x^760 + x^756 + x^749 + x^748 + x^746 + x^742 + x^736 + x^733 + x^730 + x^728 + x^726 + x^725 + x^724 + x^723 + x^719 + x^718 + x^717 + x^716 + x^715 + x^712 + x^709 + x^708 + x^707 + x^705 + x^701 + x^700 + x^699 + x^698 + x^695 + x^689 + x^688 + x^687 + x^684 + x^683 + x^680 + x^678 + x^675 + x^672 + x^670 + x^669 + x^666 + x^664 + x^663 + x^656 + x^655 + x^654 + x^651 + x^647 + x^641 + x^639 + x^638 + x^636 + x^635 + x^633 + x^632 + x^631 + x^630 + x^629 + x^627 + x^626 + x^625 + x^623 + x^621 + x^620 + x^619 + x^617 + x^613 + x^611 + x^610 + x^609 + x^608 + x^607 + x^606 + x^604 + x^603 + x^600 + x^598 + x^596 + x^595 + x^592 + x^591 + x^590 + x^587 + x^586 + x^585 + x^584 + x^582 + x^581 + x^578 + x^577 + x^576 + x^575 + x^574 + x^569 + x^566 + x^565 + x^564 + x^560 + x^558 + x^557 + x^556 + x^554 + x^552 + x^550 + x^549 + x^548 + x^545 + x^539 + x^538 + x^536 + x^535 + x^534 + x^533 + x^532 + x^527 + x^524 + x^523 + x^522 + x^520 + x^518 + x^517 + x^514 + x^513 + x^512 + x^510 + x^507 + x^504 + x^501 + x^499 + x^497 + x^496 + x^494 + x^492 + x^491 + x^490 + x^489 + x^487 + x^485 + x^483 + x^479 + x^478 + x^477 + x^476 + x^475 + x^473 + x^472 + x^470 + x^469 + x^468 + x^465 + x^464 + x^462 + x^460 + x^457 + x^452 + x^449 + x^448 + x^447 + x^445 + x^443 + x^441 + x^440 + x^436 + x^434 + x^432 + x^430 + x^428 + x^426 + x^424 + x^420 + x^416 + x^415 + x^410 + x^408 + x^407 + x^406 + x^404 + x^397 + x^395 + x^394 + x^390 + x^389 + x^387 + x^384 + x^382 + x^380 + x^374 + x^370 + x^368 + x^366 + x^365 + x^364 + x^362 + x^360 + x^359 + x^358 + x^356 + x^352 + x^350 + x^349 + x^347 + x^346 + x^344 + x^342 + x^341 + x^337 + x^336 + x^332 + x^331 + x^327 + x^325 + x^323 + x^322 + x^320 + x^317 + x^316 + x^315 + x^314 + x^312 + x^309 + x^307 + x^306 + x^305 + x^304 + x^303 + x^301 + x^300 + x^298 + x^296 + x^294 + x^293 + x^290 + x^289 + x^287 + x^285 + x^282 + x^281 + x^279 + x^277 + x^273 + x^265 + x^264 + x^259 + x^258 + x^257 + x^255 + x^254 + x^253 + x^251 + x^250 + x^249 + x^248 + x^247 + x^246 + x^244 + x^237 + x^235 + x^233 + x^232 + x^231 + x^230 + x^229 + x^228 + x^227 + x^225 + x^221 + x^215 + x^214 + x^211 + x^208 + x^206 + x^204 + x^200 + x^199 + x^198 + x^196 + x^192 + x^188 + x^186 + x^185 + x^184 + x^183 + x^181 + x^179 + x^176 + x^175 + x^173 + x^171 + x^170 + x^168 + x^165 + x^164 + x^160 + x^158 + x^155 + x^154 + x^152 + x^151 + x^149 + x^147 + x^144 + x^141 + x^140 + x^139 + x^137 + x^136 + x^133 + x^131 + x^130 + x^128 + x^127 + x^126 + x^125 + x^123 + x^122 + x^121 + x^120 + x^119 + x^117 + x^116 + x^115 + x^112 + x^109 + x^106 + x^102 + x^101 + x^98 + x^92 + x^89 + x^87 + x^86 + x^81 + x^74 + x^72 + x^71 + x^69 + x^65 + x^61 + x^57 + x^55 + x^53 + x^51 + x^50 + x^47 + x^45 + x^44 + x^43 + x^42 + x^40 + x^39 + x^38 + x^37 + x^35 + x^31 + x^30 + x^29 + x^27 + x^24 + x^22 + x^21 + x^20 + x^19 + 1
+
+44-24-27 401 x^928 + x^898 + x^870 + x^858 + x^824 + x^821 + x^820 + x^798 + x^792 + x^791 + x^790 + x^789 + x^784 + x^776 + x^771 + x^770 + x^768 + x^764 + x^762 + x^761 + x^760 + x^759 + x^755 + x^754 + x^751 + x^742 + x^738 + x^735 + x^734 + x^731 + x^730 + x^729 + x^728 + x^725 + x^722 + x^721 + x^715 + x^711 + x^710 + x^706 + x^705 + x^701 + x^700 + x^698 + x^695 + x^692 + x^691 + x^689 + x^686 + x^685 + x^681 + x^676 + x^675 + x^674 + x^672 + x^671 + x^669 + x^668 + x^667 + x^666 + x^665 + x^658 + x^656 + x^654 + x^653 + x^651 + x^650 + x^648 + x^646 + x^644 + x^642 + x^635 + x^634 + x^633 + x^629 + x^626 + x^625 + x^624 + x^622 + x^621 + x^620 + x^618 + x^616 + x^614 + x^612 + x^608 + x^607 + x^606 + x^605 + x^604 + x^603 + x^602 + x^594 + x^593 + x^590 + x^589 + x^588 + x^586 + x^585 + x^584 + x^583 + x^582 + x^580 + x^577 + x^576 + x^575 + x^574 + x^569 + x^568 + x^566 + x^565 + x^564 + x^561 + x^559 + x^556 + x^554 + x^553 + x^552 + x^547 + x^543 + x^542 + x^541 + x^540 + x^539 + x^538 + x^536 + x^535 + x^534 + x^531 + x^530 + x^529 + x^527 + x^526 + x^524 + x^519 + x^514 + x^512 + x^511 + x^507 + x^504 + x^503 + x^502 + x^499 + x^498 + x^494 + x^493 + x^491 + x^489 + x^488 + x^486 + x^485 + x^483 + x^482 + x^480 + x^478 + x^476 + x^473 + x^468 + x^465 + x^463 + x^461 + x^460 + x^459 + x^458 + x^457 + x^455 + x^454 + x^453 + x^452 + x^451 + x^450 + x^449 + x^447 + x^446 + x^445 + x^443 + x^442 + x^439 + x^437 + x^436 + x^435 + x^433 + x^432 + x^429 + x^424 + x^423 + x^421 + x^418 + x^416 + x^412 + x^411 + x^406 + x^404 + x^403 + x^401 + x^400 + x^399 + x^398 + x^397 + x^394 + x^390 + x^388 + x^384 + x^383 + x^382 + x^381 + x^380 + x^378 + x^377 + x^376 + x^374 + x^373 + x^372 + x^368 + x^367 + x^366 + x^363 + x^361 + x^360 + x^359 + x^355 + x^353 + x^351 + x^350 + x^349 + x^348 + x^347 + x^345 + x^344 + x^342 + x^341 + x^340 + x^338 + x^337 + x^334 + x^329 + x^328 + x^326 + x^325 + x^319 + x^316 + x^314 + x^312 + x^311 + x^310 + x^308 + x^307 + x^305 + x^300 + x^296 + x^292 + x^291 + x^290 + x^287 + x^286 + x^284 + x^282 + x^280 + x^279 + x^277 + x^275 + x^274 + x^273 + x^272 + x^269 + x^268 + x^265 + x^264 + x^263 + x^262 + x^261 + x^258 + x^257 + x^256 + x^255 + x^254 + x^253 + x^252 + x^250 + x^249 + x^244 + x^242 + x^239 + x^238 + x^237 + x^235 + x^234 + x^232 + x^231 + x^228 + x^226 + x^225 + x^224 + x^221 + x^220 + x^219 + x^218 + x^216 + x^214 + x^213 + x^211 + x^210 + x^207 + x^205 + x^204 + x^203 + x^202 + x^200 + x^199 + x^198 + x^194 + x^186 + x^185 + x^184 + x^183 + x^182 + x^180 + x^179 + x^177 + x^174 + x^171 + x^169 + x^168 + x^165 + x^164 + x^163 + x^161 + x^159 + x^158 + x^157 + x^154 + x^152 + x^151 + x^148 + x^146 + x^145 + x^144 + x^142 + x^141 + x^139 + x^136 + x^135 + x^134 + x^132 + x^131 + x^130 + x^129 + x^128 + x^127 + x^124 + x^123 + x^120 + x^119 + x^117 + x^116 + x^114 + x^112 + x^106 + x^103 + x^101 + x^100 + x^98 + x^94 + x^93 + x^91 + x^86 + x^83 + x^82 + x^78 + x^76 + x^74 + x^73 + x^71 + x^69 + x^66 + x^65 + x^61 + x^60 + x^59 + x^58 + x^57 + x^56 + x^55 + x^54 + x^47 + x^45 + x^44 + x^43 + x^42 + x^40 + x^39 + x^38 + x^34 + x^31 + x^29 + x^28 + x^19 + x^16 + x^12 + x^6 + 1
+
+10-49-23 403 x^928 + x^900 + x^898 + x^893 + x^872 + x^870 + x^865 + x^858 + x^842 + x^840 + x^835 + x^833 + x^826 + x^823 + x^821 + x^816 + x^814 + x^809 + x^808 + x^807 + x^805 + x^802 + x^796 + x^793 + x^782 + x^780 + x^778 + x^775 + x^772 + x^770 + x^767 + x^766 + x^765 + x^760 + x^758 + x^756 + x^754 + x^753 + x^751 + x^747 + x^744 + x^740 + x^739 + x^738 + x^736 + x^735 + x^732 + x^728 + x^724 + x^723 + x^722 + x^720 + x^718 + x^717 + x^714 + x^712 + x^709 + x^708 + x^707 + x^706 + x^705 + x^702 + x^701 + x^700 + x^698 + x^697 + x^696 + x^694 + x^693 + x^691 + x^689 + x^688 + x^684 + x^682 + x^681 + x^680 + x^679 + x^677 + x^676 + x^674 + x^673 + x^672 + x^670 + x^668 + x^667 + x^666 + x^664 + x^661 + x^658 + x^657 + x^655 + x^652 + x^649 + x^646 + x^645 + x^643 + x^641 + x^640 + x^639 + x^638 + x^636 + x^635 + x^634 + x^632 + x^631 + x^628 + x^623 + x^622 + x^620 + x^619 + x^615 + x^612 + x^610 + x^607 + x^604 + x^602 + x^599 + x^598 + x^596 + x^593 + x^590 + x^588 + x^587 + x^585 + x^582 + x^581 + x^578 + x^576 + x^575 + x^573 + x^571 + x^570 + x^569 + x^568 + x^567 + x^565 + x^564 + x^563 + x^559 + x^557 + x^556 + x^552 + x^550 + x^549 + x^548 + x^546 + x^545 + x^543 + x^537 + x^536 + x^535 + x^534 + x^533 + x^532 + x^529 + x^526 + x^525 + x^523 + x^521 + x^520 + x^518 + x^515 + x^513 + x^512 + x^511 + x^508 + x^503 + x^502 + x^499 + x^498 + x^495 + x^494 + x^493 + x^492 + x^491 + x^480 + x^479 + x^475 + x^474 + x^472 + x^470 + x^469 + x^466 + x^465 + x^460 + x^453 + x^452 + x^451 + x^447 + x^444 + x^443 + x^438 + x^436 + x^431 + x^428 + x^426 + x^424 + x^423 + x^421 + x^420 + x^418 + x^417 + x^414 + x^413 + x^411 + x^410 + x^404 + x^401 + x^396 + x^395 + x^390 + x^389 + x^386 + x^384 + x^380 + x^378 + x^377 + x^376 + x^373 + x^372 + x^371 + x^369 + x^364 + x^361 + x^360 + x^359 + x^357 + x^356 + x^354 + x^353 + x^348 + x^347 + x^346 + x^342 + x^341 + x^339 + x^338 + x^333 + x^332 + x^331 + x^329 + x^328 + x^324 + x^322 + x^320 + x^315 + x^314 + x^312 + x^311 + x^310 + x^307 + x^306 + x^303 + x^295 + x^294 + x^292 + x^289 + x^288 + x^283 + x^281 + x^279 + x^274 + x^272 + x^271 + x^270 + x^268 + x^267 + x^266 + x^265 + x^264 + x^261 + x^258 + x^257 + x^256 + x^255 + x^252 + x^251 + x^248 + x^245 + x^243 + x^242 + x^238 + x^237 + x^236 + x^235 + x^233 + x^232 + x^231 + x^229 + x^228 + x^226 + x^225 + x^224 + x^222 + x^221 + x^220 + x^216 + x^215 + x^213 + x^212 + x^210 + x^209 + x^208 + x^202 + x^200 + x^199 + x^197 + x^194 + x^193 + x^192 + x^191 + x^190 + x^189 + x^187 + x^186 + x^184 + x^183 + x^181 + x^179 + x^178 + x^177 + x^176 + x^174 + x^173 + x^172 + x^171 + x^169 + x^166 + x^164 + x^163 + x^160 + x^158 + x^157 + x^155 + x^152 + x^151 + x^150 + x^148 + x^146 + x^145 + x^143 + x^142 + x^137 + x^133 + x^129 + x^126 + x^118 + x^116 + x^114 + x^113 + x^112 + x^110 + x^106 + x^102 + x^99 + x^98 + x^97 + x^96 + x^92 + x^91 + x^88 + x^86 + x^85 + x^83 + x^82 + x^81 + x^79 + x^78 + x^77 + x^76 + x^73 + x^71 + x^67 + x^66 + x^65 + x^64 + x^63 + x^61 + x^60 + x^58 + x^53 + x^52 + x^51 + x^48 + x^47 + x^44 + x^43 + x^42 + x^41 + x^39 + x^37 + x^36 + x^35 + x^34 + x^33 + x^31 + x^26 + x^21 + x^20 + x^16 + x^10 + x^5 + 1
+
+16-2-49 403 x^928 + x^898 + x^870 + x^858 + x^855 + x^846 + x^831 + x^828 + x^822 + x^818 + x^808 + x^800 + x^798 + x^795 + x^788 + x^786 + x^784 + x^783 + x^776 + x^775 + x^770 + x^768 + x^764 + x^759 + x^753 + x^751 + x^750 + x^746 + x^743 + x^740 + x^736 + x^735 + x^734 + x^724 + x^723 + x^719 + x^712 + x^708 + x^706 + x^703 + x^699 + x^698 + x^696 + x^695 + x^694 + x^693 + x^691 + x^690 + x^688 + x^686 + x^684 + x^683 + x^676 + x^675 + x^673 + x^672 + x^671 + x^670 + x^668 + x^664 + x^663 + x^662 + x^660 + x^655 + x^654 + x^652 + x^649 + x^644 + x^642 + x^636 + x^634 + x^633 + x^623 + x^622 + x^620 + x^619 + x^616 + x^614 + x^613 + x^611 + x^609 + x^608 + x^606 + x^604 + x^603 + x^602 + x^601 + x^600 + x^599 + x^598 + x^596 + x^595 + x^594 + x^592 + x^591 + x^588 + x^586 + x^585 + x^584 + x^583 + x^579 + x^578 + x^577 + x^576 + x^575 + x^574 + x^572 + x^569 + x^562 + x^560 + x^555 + x^553 + x^550 + x^549 + x^548 + x^547 + x^546 + x^545 + x^544 + x^543 + x^542 + x^538 + x^536 + x^533 + x^532 + x^531 + x^530 + x^529 + x^528 + x^527 + x^526 + x^523 + x^518 + x^516 + x^515 + x^511 + x^509 + x^507 + x^503 + x^501 + x^500 + x^498 + x^497 + x^496 + x^494 + x^491 + x^490 + x^487 + x^485 + x^484 + x^483 + x^482 + x^478 + x^477 + x^475 + x^474 + x^472 + x^470 + x^468 + x^467 + x^466 + x^465 + x^464 + x^462 + x^461 + x^460 + x^458 + x^457 + x^456 + x^455 + x^454 + x^453 + x^448 + x^446 + x^444 + x^443 + x^442 + x^441 + x^440 + x^437 + x^436 + x^435 + x^434 + x^433 + x^432 + x^431 + x^430 + x^429 + x^428 + x^427 + x^426 + x^425 + x^422 + x^421 + x^420 + x^419 + x^417 + x^414 + x^413 + x^411 + x^410 + x^406 + x^405 + x^400 + x^399 + x^397 + x^395 + x^394 + x^393 + x^392 + x^391 + x^389 + x^387 + x^382 + x^380 + x^379 + x^377 + x^375 + x^371 + x^370 + x^366 + x^365 + x^364 + x^363 + x^362 + x^358 + x^356 + x^354 + x^353 + x^351 + x^348 + x^346 + x^344 + x^343 + x^342 + x^340 + x^339 + x^337 + x^334 + x^333 + x^332 + x^331 + x^328 + x^327 + x^326 + x^325 + x^324 + x^323 + x^322 + x^321 + x^320 + x^318 + x^317 + x^316 + x^315 + x^314 + x^312 + x^310 + x^306 + x^304 + x^303 + x^301 + x^297 + x^295 + x^293 + x^290 + x^285 + x^283 + x^282 + x^273 + x^271 + x^268 + x^266 + x^262 + x^260 + x^259 + x^258 + x^253 + x^252 + x^251 + x^249 + x^248 + x^246 + x^245 + x^244 + x^243 + x^242 + x^241 + x^240 + x^239 + x^238 + x^237 + x^234 + x^233 + x^231 + x^229 + x^228 + x^227 + x^223 + x^222 + x^217 + x^216 + x^214 + x^213 + x^211 + x^209 + x^208 + x^203 + x^202 + x^201 + x^198 + x^197 + x^196 + x^194 + x^193 + x^189 + x^188 + x^187 + x^183 + x^182 + x^181 + x^177 + x^176 + x^174 + x^170 + x^166 + x^163 + x^162 + x^161 + x^160 + x^158 + x^157 + x^155 + x^153 + x^152 + x^151 + x^149 + x^148 + x^147 + x^146 + x^144 + x^142 + x^141 + x^140 + x^138 + x^132 + x^131 + x^129 + x^128 + x^126 + x^125 + x^123 + x^122 + x^120 + x^119 + x^117 + x^116 + x^115 + x^112 + x^109 + x^107 + x^105 + x^101 + x^97 + x^95 + x^94 + x^92 + x^91 + x^90 + x^87 + x^86 + x^85 + x^83 + x^82 + x^81 + x^79 + x^78 + x^77 + x^73 + x^72 + x^71 + x^68 + x^67 + x^65 + x^64 + x^63 + x^60 + x^58 + x^54 + x^50 + x^45 + x^44 + x^43 + x^42 + x^39 + x^37 + x^26 + x^24 + x^20 + x^16 + x^14 + x^10 + 1
+
+17-2-46 405 x^928 + x^898 + x^870 + x^860 + x^848 + x^831 + x^830 + x^818 + x^812 + x^808 + x^804 + x^801 + x^800 + x^792 + x^791 + x^790 + x^784 + x^780 + x^778 + x^775 + x^774 + x^770 + x^763 + x^762 + x^761 + x^760 + x^756 + x^754 + x^750 + x^748 + x^746 + x^745 + x^736 + x^733 + x^732 + x^731 + x^729 + x^728 + x^726 + x^720 + x^719 + x^712 + x^710 + x^706 + x^703 + x^702 + x^701 + x^700 + x^690 + x^686 + x^682 + x^679 + x^676 + x^675 + x^673 + x^672 + x^671 + x^669 + x^668 + x^666 + x^664 + x^663 + x^658 + x^652 + x^651 + x^648 + x^647 + x^646 + x^645 + x^644 + x^643 + x^642 + x^638 + x^633 + x^628 + x^626 + x^624 + x^623 + x^621 + x^617 + x^616 + x^614 + x^613 + x^611 + x^610 + x^609 + x^607 + x^606 + x^604 + x^599 + x^595 + x^594 + x^593 + x^592 + x^590 + x^589 + x^588 + x^584 + x^580 + x^579 + x^578 + x^577 + x^576 + x^574 + x^573 + x^569 + x^568 + x^567 + x^566 + x^564 + x^563 + x^561 + x^560 + x^559 + x^558 + x^557 + x^555 + x^549 + x^548 + x^547 + x^544 + x^543 + x^542 + x^540 + x^535 + x^534 + x^532 + x^531 + x^530 + x^528 + x^527 + x^526 + x^525 + x^520 + x^519 + x^516 + x^513 + x^510 + x^509 + x^500 + x^499 + x^498 + x^497 + x^496 + x^493 + x^492 + x^490 + x^489 + x^487 + x^484 + x^482 + x^480 + x^479 + x^476 + x^473 + x^471 + x^470 + x^468 + x^467 + x^465 + x^464 + x^463 + x^462 + x^461 + x^460 + x^457 + x^453 + x^452 + x^450 + x^448 + x^447 + x^443 + x^440 + x^439 + x^438 + x^437 + x^431 + x^430 + x^429 + x^428 + x^427 + x^426 + x^424 + x^423 + x^420 + x^418 + x^416 + x^415 + x^408 + x^407 + x^406 + x^405 + x^404 + x^403 + x^397 + x^395 + x^391 + x^389 + x^388 + x^386 + x^384 + x^382 + x^381 + x^380 + x^379 + x^378 + x^375 + x^374 + x^373 + x^372 + x^371 + x^369 + x^368 + x^365 + x^364 + x^363 + x^362 + x^360 + x^359 + x^358 + x^357 + x^353 + x^351 + x^350 + x^345 + x^341 + x^338 + x^336 + x^335 + x^334 + x^332 + x^331 + x^329 + x^328 + x^327 + x^323 + x^321 + x^320 + x^319 + x^317 + x^316 + x^314 + x^313 + x^312 + x^310 + x^308 + x^307 + x^304 + x^303 + x^300 + x^297 + x^295 + x^293 + x^291 + x^289 + x^288 + x^287 + x^285 + x^284 + x^282 + x^280 + x^279 + x^277 + x^273 + x^272 + x^269 + x^268 + x^267 + x^266 + x^265 + x^264 + x^262 + x^260 + x^259 + x^256 + x^255 + x^254 + x^253 + x^249 + x^247 + x^245 + x^243 + x^241 + x^240 + x^239 + x^238 + x^237 + x^236 + x^235 + x^234 + x^232 + x^228 + x^226 + x^225 + x^224 + x^223 + x^220 + x^219 + x^217 + x^209 + x^207 + x^206 + x^204 + x^203 + x^202 + x^201 + x^200 + x^199 + x^195 + x^194 + x^189 + x^187 + x^186 + x^185 + x^184 + x^182 + x^180 + x^178 + x^174 + x^173 + x^172 + x^170 + x^167 + x^166 + x^165 + x^164 + x^162 + x^161 + x^160 + x^159 + x^158 + x^157 + x^156 + x^155 + x^154 + x^153 + x^152 + x^151 + x^147 + x^143 + x^141 + x^138 + x^131 + x^130 + x^129 + x^127 + x^122 + x^121 + x^120 + x^118 + x^117 + x^114 + x^111 + x^109 + x^106 + x^105 + x^104 + x^103 + x^102 + x^101 + x^100 + x^99 + x^98 + x^97 + x^93 + x^92 + x^91 + x^90 + x^88 + x^87 + x^86 + x^82 + x^81 + x^80 + x^79 + x^78 + x^77 + x^75 + x^74 + x^73 + x^72 + x^71 + x^68 + x^59 + x^58 + x^51 + x^50 + x^43 + x^42 + x^40 + x^39 + x^34 + x^27 + x^25 + x^24 + x^23 + x^19 + x^18 + x^17 + x^15 + x^14 + x^13 + x^11 + x^10 + 1
+
+55-23-24 407 x^928 + x^898 + x^894 + x^870 + x^865 + x^849 + x^846 + x^842 + x^834 + x^833 + x^830 + x^826 + x^820 + x^819 + x^816 + x^813 + x^808 + x^804 + x^803 + x^794 + x^782 + x^778 + x^772 + x^769 + x^767 + x^765 + x^764 + x^762 + x^760 + x^759 + x^756 + x^751 + x^745 + x^743 + x^740 + x^739 + x^737 + x^733 + x^730 + x^729 + x^728 + x^726 + x^722 + x^720 + x^718 + x^717 + x^716 + x^713 + x^710 + x^709 + x^708 + x^707 + x^702 + x^699 + x^697 + x^694 + x^692 + x^691 + x^688 + x^687 + x^682 + x^680 + x^679 + x^678 + x^676 + x^675 + x^674 + x^670 + x^668 + x^666 + x^662 + x^661 + x^657 + x^652 + x^651 + x^649 + x^647 + x^646 + x^643 + x^640 + x^639 + x^637 + x^635 + x^634 + x^633 + x^630 + x^618 + x^616 + x^614 + x^613 + x^611 + x^610 + x^609 + x^608 + x^604 + x^603 + x^602 + x^597 + x^593 + x^591 + x^590 + x^585 + x^582 + x^579 + x^575 + x^574 + x^573 + x^572 + x^569 + x^567 + x^566 + x^564 + x^562 + x^561 + x^560 + x^557 + x^556 + x^555 + x^554 + x^551 + x^550 + x^547 + x^545 + x^542 + x^541 + x^539 + x^537 + x^534 + x^531 + x^530 + x^529 + x^528 + x^526 + x^525 + x^523 + x^522 + x^521 + x^520 + x^519 + x^518 + x^517 + x^515 + x^514 + x^513 + x^511 + x^510 + x^509 + x^508 + x^506 + x^505 + x^500 + x^498 + x^492 + x^485 + x^484 + x^480 + x^479 + x^478 + x^477 + x^476 + x^471 + x^470 + x^469 + x^467 + x^465 + x^464 + x^462 + x^458 + x^457 + x^454 + x^453 + x^452 + x^451 + x^450 + x^445 + x^444 + x^443 + x^441 + x^439 + x^437 + x^436 + x^435 + x^433 + x^431 + x^430 + x^429 + x^425 + x^424 + x^421 + x^419 + x^414 + x^411 + x^410 + x^409 + x^408 + x^407 + x^406 + x^405 + x^396 + x^395 + x^394 + x^390 + x^388 + x^385 + x^383 + x^381 + x^379 + x^378 + x^377 + x^376 + x^375 + x^373 + x^371 + x^369 + x^368 + x^367 + x^360 + x^358 + x^353 + x^351 + x^350 + x^348 + x^347 + x^346 + x^344 + x^343 + x^341 + x^338 + x^336 + x^335 + x^334 + x^331 + x^330 + x^329 + x^327 + x^326 + x^324 + x^322 + x^318 + x^314 + x^313 + x^311 + x^307 + x^305 + x^304 + x^302 + x^299 + x^295 + x^294 + x^293 + x^289 + x^284 + x^282 + x^281 + x^277 + x^272 + x^271 + x^270 + x^268 + x^265 + x^262 + x^259 + x^257 + x^254 + x^252 + x^251 + x^250 + x^249 + x^244 + x^243 + x^240 + x^239 + x^237 + x^235 + x^234 + x^233 + x^231 + x^230 + x^227 + x^224 + x^223 + x^220 + x^219 + x^218 + x^217 + x^215 + x^214 + x^213 + x^212 + x^211 + x^210 + x^209 + x^208 + x^207 + x^205 + x^203 + x^201 + x^200 + x^197 + x^193 + x^190 + x^187 + x^185 + x^184 + x^181 + x^180 + x^179 + x^178 + x^177 + x^176 + x^175 + x^173 + x^172 + x^169 + x^168 + x^166 + x^165 + x^162 + x^159 + x^157 + x^156 + x^155 + x^154 + x^153 + x^152 + x^150 + x^146 + x^145 + x^143 + x^142 + x^141 + x^139 + x^138 + x^137 + x^136 + x^135 + x^134 + x^132 + x^129 + x^123 + x^119 + x^115 + x^114 + x^112 + x^108 + x^107 + x^102 + x^100 + x^98 + x^97 + x^95 + x^93 + x^91 + x^90 + x^87 + x^86 + x^85 + x^83 + x^80 + x^79 + x^78 + x^77 + x^75 + x^74 + x^72 + x^69 + x^68 + x^65 + x^64 + x^61 + x^60 + x^59 + x^58 + x^57 + x^56 + x^55 + x^52 + x^51 + x^50 + x^45 + x^44 + x^43 + x^42 + x^41 + x^40 + x^39 + x^38 + x^37 + x^34 + x^33 + x^31 + x^30 + x^29 + x^26 + x^25 + x^23 + x^21 + x^20 + x^19 + x^18 + x^17 + x^13 + x^12 + x^10 + x^8 + x^7 + 1
+
+15-3-26 409 x^928 + x^898 + x^892 + x^870 + x^863 + x^862 + x^858 + x^856 + x^852 + x^833 + x^828 + x^827 + x^826 + x^824 + x^823 + x^820 + x^818 + x^816 + x^812 + x^808 + x^803 + x^801 + x^799 + x^798 + x^797 + x^795 + x^794 + x^792 + x^791 + x^790 + x^788 + x^787 + x^784 + x^783 + x^782 + x^773 + x^772 + x^771 + x^768 + x^767 + x^763 + x^760 + x^757 + x^753 + x^750 + x^746 + x^744 + x^737 + x^732 + x^731 + x^730 + x^729 + x^728 + x^726 + x^725 + x^724 + x^721 + x^717 + x^716 + x^713 + x^711 + x^710 + x^707 + x^706 + x^705 + x^703 + x^702 + x^699 + x^698 + x^697 + x^696 + x^694 + x^692 + x^691 + x^690 + x^689 + x^688 + x^681 + x^678 + x^673 + x^668 + x^666 + x^662 + x^658 + x^657 + x^656 + x^653 + x^651 + x^650 + x^648 + x^644 + x^643 + x^642 + x^641 + x^640 + x^638 + x^636 + x^635 + x^634 + x^633 + x^632 + x^630 + x^628 + x^626 + x^625 + x^623 + x^622 + x^620 + x^618 + x^617 + x^616 + x^614 + x^611 + x^609 + x^607 + x^605 + x^603 + x^596 + x^595 + x^593 + x^592 + x^590 + x^587 + x^586 + x^585 + x^584 + x^583 + x^582 + x^580 + x^577 + x^576 + x^571 + x^569 + x^568 + x^567 + x^565 + x^564 + x^562 + x^561 + x^560 + x^559 + x^558 + x^557 + x^556 + x^555 + x^554 + x^553 + x^552 + x^548 + x^547 + x^546 + x^545 + x^544 + x^542 + x^538 + x^537 + x^534 + x^533 + x^532 + x^529 + x^527 + x^526 + x^524 + x^523 + x^518 + x^517 + x^509 + x^505 + x^503 + x^501 + x^494 + x^493 + x^492 + x^488 + x^485 + x^484 + x^483 + x^480 + x^479 + x^477 + x^475 + x^474 + x^473 + x^472 + x^471 + x^469 + x^467 + x^466 + x^465 + x^464 + x^461 + x^458 + x^456 + x^453 + x^449 + x^446 + x^445 + x^444 + x^443 + x^442 + x^441 + x^440 + x^436 + x^435 + x^432 + x^431 + x^427 + x^426 + x^423 + x^418 + x^415 + x^413 + x^412 + x^411 + x^410 + x^407 + x^406 + x^403 + x^400 + x^398 + x^396 + x^385 + x^383 + x^382 + x^381 + x^375 + x^374 + x^373 + x^364 + x^363 + x^362 + x^360 + x^358 + x^357 + x^355 + x^353 + x^352 + x^350 + x^349 + x^345 + x^344 + x^343 + x^342 + x^340 + x^337 + x^331 + x^329 + x^328 + x^325 + x^324 + x^323 + x^322 + x^315 + x^314 + x^312 + x^311 + x^308 + x^304 + x^303 + x^299 + x^297 + x^295 + x^289 + x^284 + x^282 + x^281 + x^279 + x^278 + x^275 + x^274 + x^273 + x^272 + x^271 + x^270 + x^264 + x^263 + x^262 + x^260 + x^259 + x^258 + x^256 + x^253 + x^252 + x^251 + x^250 + x^248 + x^247 + x^246 + x^245 + x^243 + x^242 + x^240 + x^238 + x^237 + x^234 + x^233 + x^232 + x^231 + x^230 + x^228 + x^221 + x^220 + x^218 + x^213 + x^212 + x^211 + x^210 + x^204 + x^201 + x^200 + x^196 + x^195 + x^194 + x^191 + x^190 + x^189 + x^185 + x^183 + x^181 + x^180 + x^178 + x^176 + x^175 + x^170 + x^168 + x^167 + x^165 + x^164 + x^163 + x^160 + x^159 + x^158 + x^157 + x^156 + x^153 + x^151 + x^150 + x^149 + x^146 + x^145 + x^141 + x^139 + x^138 + x^137 + x^133 + x^132 + x^131 + x^130 + x^129 + x^128 + x^127 + x^125 + x^124 + x^122 + x^121 + x^120 + x^116 + x^115 + x^114 + x^112 + x^110 + x^106 + x^103 + x^101 + x^100 + x^97 + x^96 + x^94 + x^93 + x^92 + x^89 + x^88 + x^87 + x^86 + x^85 + x^84 + x^82 + x^80 + x^77 + x^73 + x^72 + x^71 + x^70 + x^68 + x^67 + x^65 + x^61 + x^60 + x^59 + x^56 + x^55 + x^48 + x^47 + x^42 + x^41 + x^36 + x^35 + x^33 + x^29 + x^27 + x^26 + x^25 + x^18 + x^14 + x^12 + x^10 + x^8 + x^4 + 1
+
+33-51-22 409 x^928 + x^898 + x^886 + x^870 + x^859 + x^858 + x^857 + x^844 + x^842 + x^832 + x^831 + x^830 + x^826 + x^815 + x^812 + x^808 + x^805 + x^804 + x^803 + x^799 + x^798 + x^789 + x^787 + x^786 + x^785 + x^782 + x^777 + x^776 + x^775 + x^771 + x^769 + x^766 + x^763 + x^758 + x^756 + x^752 + x^749 + x^745 + x^744 + x^743 + x^741 + x^739 + x^738 + x^735 + x^734 + x^731 + x^730 + x^721 + x^720 + x^715 + x^714 + x^711 + x^708 + x^705 + x^704 + x^703 + x^700 + x^698 + x^695 + x^693 + x^692 + x^690 + x^689 + x^684 + x^682 + x^681 + x^680 + x^677 + x^676 + x^673 + x^672 + x^671 + x^667 + x^666 + x^662 + x^661 + x^658 + x^656 + x^653 + x^652 + x^650 + x^649 + x^647 + x^646 + x^645 + x^644 + x^642 + x^641 + x^640 + x^638 + x^636 + x^634 + x^633 + x^632 + x^631 + x^629 + x^625 + x^624 + x^623 + x^621 + x^620 + x^619 + x^616 + x^615 + x^614 + x^612 + x^611 + x^609 + x^606 + x^605 + x^602 + x^601 + x^599 + x^596 + x^595 + x^592 + x^591 + x^588 + x^587 + x^586 + x^583 + x^582 + x^578 + x^577 + x^576 + x^574 + x^572 + x^570 + x^566 + x^562 + x^560 + x^555 + x^552 + x^550 + x^546 + x^545 + x^544 + x^543 + x^542 + x^539 + x^537 + x^535 + x^534 + x^533 + x^532 + x^531 + x^530 + x^528 + x^525 + x^524 + x^523 + x^519 + x^516 + x^513 + x^511 + x^509 + x^508 + x^507 + x^506 + x^504 + x^500 + x^499 + x^497 + x^495 + x^494 + x^491 + x^488 + x^487 + x^484 + x^480 + x^479 + x^476 + x^474 + x^472 + x^471 + x^470 + x^469 + x^468 + x^464 + x^463 + x^462 + x^460 + x^459 + x^458 + x^457 + x^456 + x^455 + x^454 + x^451 + x^449 + x^448 + x^447 + x^446 + x^445 + x^441 + x^440 + x^439 + x^437 + x^436 + x^435 + x^431 + x^430 + x^427 + x^423 + x^421 + x^419 + x^412 + x^410 + x^407 + x^406 + x^405 + x^404 + x^402 + x^400 + x^398 + x^396 + x^395 + x^394 + x^392 + x^389 + x^387 + x^386 + x^384 + x^382 + x^381 + x^379 + x^378 + x^377 + x^375 + x^372 + x^370 + x^369 + x^363 + x^361 + x^360 + x^351 + x^350 + x^347 + x^343 + x^342 + x^340 + x^336 + x^328 + x^327 + x^326 + x^325 + x^323 + x^322 + x^321 + x^319 + x^318 + x^315 + x^314 + x^313 + x^312 + x^311 + x^308 + x^307 + x^305 + x^301 + x^299 + x^298 + x^295 + x^293 + x^292 + x^290 + x^289 + x^288 + x^286 + x^284 + x^283 + x^282 + x^280 + x^279 + x^275 + x^273 + x^272 + x^269 + x^266 + x^265 + x^264 + x^255 + x^251 + x^249 + x^248 + x^246 + x^244 + x^243 + x^242 + x^238 + x^237 + x^235 + x^234 + x^232 + x^230 + x^229 + x^228 + x^226 + x^224 + x^222 + x^221 + x^218 + x^213 + x^210 + x^209 + x^208 + x^206 + x^203 + x^200 + x^195 + x^193 + x^189 + x^187 + x^186 + x^185 + x^182 + x^181 + x^179 + x^177 + x^174 + x^173 + x^170 + x^163 + x^160 + x^159 + x^155 + x^154 + x^153 + x^152 + x^151 + x^147 + x^146 + x^143 + x^141 + x^133 + x^130 + x^128 + x^125 + x^123 + x^118 + x^116 + x^115 + x^114 + x^110 + x^108 + x^106 + x^105 + x^104 + x^102 + x^100 + x^98 + x^97 + x^96 + x^95 + x^94 + x^93 + x^92 + x^91 + x^89 + x^85 + x^84 + x^83 + x^82 + x^81 + x^80 + x^78 + x^77 + x^74 + x^72 + x^71 + x^69 + x^67 + x^65 + x^64 + x^63 + x^61 + x^58 + x^56 + x^55 + x^53 + x^52 + x^51 + x^50 + x^48 + x^47 + x^46 + x^45 + x^44 + x^43 + x^40 + x^39 + x^37 + x^36 + x^35 + x^33 + x^32 + x^30 + x^29 + x^28 + x^27 + x^25 + x^23 + x^21 + x^16 + x^13 + x^11 + x^10 + x^8 + 1
+
+23-25-12 411 x^928 + x^898 + x^873 + x^870 + x^852 + x^847 + x^844 + x^842 + x^838 + x^836 + x^831 + x^828 + x^822 + x^821 + x^818 + x^817 + x^816 + x^814 + x^813 + x^812 + x^811 + x^801 + x^800 + x^798 + x^797 + x^796 + x^792 + x^791 + x^790 + x^787 + x^780 + x^776 + x^774 + x^770 + x^768 + x^766 + x^765 + x^762 + x^761 + x^759 + x^758 + x^757 + x^756 + x^755 + x^752 + x^749 + x^748 + x^747 + x^744 + x^741 + x^740 + x^739 + x^737 + x^735 + x^731 + x^730 + x^729 + x^728 + x^726 + x^725 + x^722 + x^720 + x^718 + x^714 + x^712 + x^711 + x^709 + x^708 + x^707 + x^706 + x^705 + x^704 + x^698 + x^694 + x^693 + x^691 + x^689 + x^686 + x^685 + x^682 + x^676 + x^674 + x^670 + x^669 + x^668 + x^667 + x^666 + x^665 + x^662 + x^661 + x^658 + x^655 + x^653 + x^652 + x^650 + x^647 + x^644 + x^643 + x^640 + x^638 + x^637 + x^635 + x^634 + x^632 + x^629 + x^627 + x^626 + x^625 + x^624 + x^619 + x^618 + x^614 + x^612 + x^611 + x^606 + x^604 + x^602 + x^601 + x^595 + x^592 + x^591 + x^590 + x^589 + x^586 + x^585 + x^581 + x^579 + x^578 + x^575 + x^574 + x^573 + x^568 + x^567 + x^565 + x^564 + x^562 + x^560 + x^559 + x^558 + x^555 + x^554 + x^553 + x^552 + x^549 + x^548 + x^546 + x^544 + x^543 + x^542 + x^541 + x^538 + x^533 + x^532 + x^529 + x^527 + x^526 + x^523 + x^522 + x^521 + x^517 + x^511 + x^508 + x^507 + x^506 + x^505 + x^504 + x^502 + x^497 + x^496 + x^494 + x^490 + x^489 + x^486 + x^485 + x^483 + x^482 + x^481 + x^477 + x^475 + x^473 + x^472 + x^471 + x^468 + x^464 + x^462 + x^461 + x^460 + x^459 + x^455 + x^454 + x^453 + x^449 + x^448 + x^447 + x^446 + x^438 + x^437 + x^435 + x^432 + x^429 + x^427 + x^426 + x^424 + x^423 + x^421 + x^419 + x^418 + x^416 + x^415 + x^413 + x^412 + x^410 + x^409 + x^407 + x^406 + x^405 + x^402 + x^401 + x^399 + x^397 + x^396 + x^394 + x^393 + x^390 + x^385 + x^384 + x^383 + x^380 + x^379 + x^378 + x^376 + x^375 + x^374 + x^372 + x^370 + x^368 + x^367 + x^366 + x^365 + x^363 + x^359 + x^357 + x^356 + x^355 + x^354 + x^353 + x^352 + x^351 + x^350 + x^348 + x^345 + x^341 + x^337 + x^335 + x^334 + x^333 + x^325 + x^319 + x^317 + x^316 + x^314 + x^305 + x^301 + x^298 + x^294 + x^293 + x^292 + x^289 + x^284 + x^281 + x^279 + x^272 + x^271 + x^269 + x^268 + x^267 + x^266 + x^264 + x^263 + x^262 + x^261 + x^256 + x^255 + x^254 + x^252 + x^251 + x^249 + x^248 + x^244 + x^242 + x^239 + x^235 + x^234 + x^233 + x^227 + x^226 + x^223 + x^221 + x^220 + x^216 + x^214 + x^211 + x^209 + x^207 + x^205 + x^204 + x^200 + x^198 + x^197 + x^196 + x^193 + x^188 + x^187 + x^185 + x^183 + x^182 + x^181 + x^179 + x^177 + x^175 + x^173 + x^172 + x^170 + x^169 + x^167 + x^163 + x^162 + x^158 + x^157 + x^156 + x^155 + x^154 + x^152 + x^151 + x^150 + x^149 + x^145 + x^144 + x^143 + x^142 + x^140 + x^139 + x^138 + x^136 + x^135 + x^133 + x^131 + x^130 + x^127 + x^126 + x^124 + x^122 + x^120 + x^118 + x^116 + x^114 + x^111 + x^110 + x^106 + x^105 + x^103 + x^102 + x^101 + x^100 + x^99 + x^98 + x^97 + x^95 + x^94 + x^93 + x^92 + x^91 + x^90 + x^86 + x^85 + x^82 + x^81 + x^78 + x^75 + x^70 + x^66 + x^64 + x^63 + x^61 + x^60 + x^55 + x^54 + x^53 + x^52 + x^50 + x^49 + x^46 + x^45 + x^44 + x^41 + x^38 + x^37 + x^36 + x^32 + x^30 + x^29 + x^27 + x^22 + x^18 + x^16 + x^13 + x^9 + x^8 + x^7 + x^5 + 1
+
+36-2-35 411 x^928 + x^898 + x^870 + x^860 + x^850 + x^842 + x^830 + x^824 + x^822 + x^812 + x^808 + x^806 + x^804 + x^794 + x^792 + x^790 + x^786 + x^782 + x^778 + x^776 + x^772 + x^768 + x^764 + x^754 + x^752 + x^747 + x^746 + x^745 + x^742 + x^738 + x^737 + x^736 + x^729 + x^728 + x^725 + x^724 + x^722 + x^721 + x^720 + x^718 + x^716 + x^715 + x^714 + x^712 + x^707 + x^706 + x^704 + x^703 + x^701 + x^699 + x^693 + x^691 + x^689 + x^688 + x^687 + x^684 + x^682 + x^680 + x^674 + x^672 + x^671 + x^669 + x^668 + x^663 + x^662 + x^661 + x^660 + x^659 + x^658 + x^654 + x^652 + x^651 + x^650 + x^649 + x^648 + x^644 + x^642 + x^640 + x^639 + x^638 + x^635 + x^633 + x^632 + x^624 + x^623 + x^620 + x^619 + x^618 + x^617 + x^611 + x^607 + x^606 + x^604 + x^602 + x^601 + x^600 + x^598 + x^596 + x^594 + x^593 + x^589 + x^585 + x^583 + x^580 + x^579 + x^577 + x^576 + x^575 + x^569 + x^568 + x^567 + x^565 + x^564 + x^563 + x^560 + x^558 + x^556 + x^555 + x^553 + x^552 + x^551 + x^549 + x^548 + x^545 + x^542 + x^541 + x^539 + x^536 + x^534 + x^533 + x^530 + x^528 + x^526 + x^524 + x^521 + x^519 + x^517 + x^515 + x^511 + x^510 + x^508 + x^506 + x^505 + x^504 + x^503 + x^502 + x^501 + x^500 + x^499 + x^498 + x^496 + x^494 + x^493 + x^492 + x^491 + x^490 + x^488 + x^487 + x^484 + x^480 + x^478 + x^474 + x^472 + x^471 + x^466 + x^465 + x^464 + x^463 + x^461 + x^459 + x^458 + x^457 + x^454 + x^453 + x^446 + x^445 + x^441 + x^440 + x^439 + x^438 + x^437 + x^436 + x^435 + x^433 + x^428 + x^427 + x^426 + x^425 + x^414 + x^407 + x^406 + x^405 + x^403 + x^402 + x^401 + x^399 + x^398 + x^397 + x^395 + x^393 + x^392 + x^391 + x^390 + x^387 + x^385 + x^384 + x^383 + x^382 + x^379 + x^378 + x^376 + x^374 + x^373 + x^371 + x^370 + x^369 + x^367 + x^365 + x^364 + x^363 + x^359 + x^357 + x^355 + x^354 + x^353 + x^350 + x^346 + x^345 + x^344 + x^343 + x^340 + x^338 + x^337 + x^336 + x^335 + x^330 + x^322 + x^321 + x^320 + x^317 + x^316 + x^311 + x^310 + x^309 + x^308 + x^307 + x^306 + x^305 + x^303 + x^299 + x^296 + x^295 + x^294 + x^293 + x^292 + x^289 + x^288 + x^284 + x^283 + x^282 + x^281 + x^280 + x^278 + x^277 + x^275 + x^269 + x^265 + x^263 + x^260 + x^258 + x^256 + x^255 + x^254 + x^253 + x^252 + x^250 + x^247 + x^246 + x^245 + x^242 + x^241 + x^240 + x^239 + x^234 + x^233 + x^232 + x^230 + x^226 + x^224 + x^222 + x^218 + x^217 + x^216 + x^215 + x^214 + x^213 + x^212 + x^211 + x^208 + x^204 + x^203 + x^202 + x^201 + x^200 + x^199 + x^198 + x^197 + x^194 + x^192 + x^191 + x^184 + x^181 + x^180 + x^178 + x^177 + x^176 + x^175 + x^174 + x^173 + x^171 + x^170 + x^168 + x^166 + x^161 + x^160 + x^157 + x^156 + x^153 + x^149 + x^148 + x^147 + x^145 + x^144 + x^143 + x^139 + x^137 + x^136 + x^134 + x^132 + x^131 + x^130 + x^129 + x^128 + x^127 + x^126 + x^125 + x^118 + x^117 + x^116 + x^115 + x^114 + x^113 + x^111 + x^107 + x^105 + x^104 + x^103 + x^101 + x^99 + x^98 + x^97 + x^96 + x^92 + x^91 + x^90 + x^89 + x^87 + x^86 + x^85 + x^84 + x^83 + x^82 + x^81 + x^79 + x^78 + x^76 + x^72 + x^70 + x^69 + x^68 + x^67 + x^65 + x^64 + x^62 + x^61 + x^58 + x^54 + x^53 + x^52 + x^50 + x^49 + x^48 + x^46 + x^44 + x^43 + x^40 + x^39 + x^38 + x^35 + x^32 + x^31 + x^30 + x^29 + x^28 + x^27 + x^25 + x^24 + x^18 + x^14 + x^10 + 1
+
+55-5-54 411 x^928 + x^898 + x^883 + x^870 + x^867 + x^854 + x^853 + x^840 + x^838 + x^837 + x^836 + x^834 + x^824 + x^822 + x^820 + x^812 + x^811 + x^810 + x^808 + x^807 + x^800 + x^797 + x^796 + x^795 + x^793 + x^792 + x^783 + x^779 + x^777 + x^776 + x^774 + x^770 + x^769 + x^768 + x^764 + x^762 + x^760 + x^754 + x^753 + x^752 + x^751 + x^749 + x^747 + x^746 + x^741 + x^740 + x^739 + x^738 + x^735 + x^734 + x^733 + x^732 + x^730 + x^728 + x^723 + x^721 + x^717 + x^715 + x^712 + x^711 + x^710 + x^709 + x^708 + x^707 + x^706 + x^704 + x^702 + x^701 + x^698 + x^697 + x^696 + x^694 + x^692 + x^690 + x^687 + x^683 + x^682 + x^681 + x^675 + x^674 + x^670 + x^669 + x^667 + x^666 + x^664 + x^663 + x^662 + x^657 + x^655 + x^654 + x^653 + x^652 + x^650 + x^646 + x^645 + x^644 + x^642 + x^637 + x^636 + x^635 + x^630 + x^629 + x^627 + x^626 + x^620 + x^615 + x^614 + x^612 + x^611 + x^610 + x^607 + x^606 + x^605 + x^604 + x^603 + x^601 + x^597 + x^594 + x^592 + x^591 + x^586 + x^584 + x^583 + x^582 + x^579 + x^577 + x^574 + x^573 + x^568 + x^565 + x^564 + x^563 + x^562 + x^557 + x^554 + x^553 + x^552 + x^550 + x^548 + x^546 + x^544 + x^543 + x^542 + x^540 + x^537 + x^536 + x^532 + x^531 + x^530 + x^524 + x^521 + x^520 + x^519 + x^517 + x^516 + x^515 + x^513 + x^512 + x^510 + x^509 + x^507 + x^505 + x^503 + x^502 + x^501 + x^500 + x^497 + x^496 + x^488 + x^486 + x^484 + x^481 + x^480 + x^478 + x^476 + x^475 + x^467 + x^465 + x^464 + x^463 + x^459 + x^458 + x^457 + x^455 + x^453 + x^452 + x^446 + x^445 + x^444 + x^441 + x^440 + x^439 + x^438 + x^434 + x^433 + x^432 + x^431 + x^427 + x^425 + x^421 + x^414 + x^412 + x^411 + x^409 + x^407 + x^406 + x^405 + x^403 + x^401 + x^400 + x^399 + x^398 + x^397 + x^396 + x^395 + x^394 + x^389 + x^385 + x^383 + x^380 + x^377 + x^376 + x^375 + x^374 + x^373 + x^372 + x^370 + x^367 + x^366 + x^365 + x^364 + x^363 + x^362 + x^360 + x^358 + x^356 + x^352 + x^351 + x^350 + x^349 + x^346 + x^342 + x^340 + x^338 + x^336 + x^335 + x^330 + x^329 + x^325 + x^324 + x^323 + x^321 + x^317 + x^314 + x^312 + x^307 + x^304 + x^303 + x^301 + x^298 + x^296 + x^295 + x^294 + x^293 + x^290 + x^289 + x^288 + x^287 + x^286 + x^285 + x^278 + x^277 + x^274 + x^273 + x^272 + x^270 + x^267 + x^265 + x^261 + x^260 + x^259 + x^258 + x^257 + x^256 + x^255 + x^254 + x^252 + x^249 + x^243 + x^241 + x^240 + x^239 + x^238 + x^235 + x^232 + x^231 + x^230 + x^227 + x^226 + x^224 + x^222 + x^221 + x^220 + x^219 + x^215 + x^214 + x^213 + x^211 + x^210 + x^209 + x^207 + x^206 + x^205 + x^200 + x^198 + x^195 + x^193 + x^192 + x^190 + x^186 + x^185 + x^181 + x^178 + x^176 + x^175 + x^172 + x^170 + x^169 + x^168 + x^166 + x^164 + x^158 + x^153 + x^152 + x^150 + x^149 + x^148 + x^147 + x^146 + x^143 + x^142 + x^140 + x^139 + x^136 + x^134 + x^133 + x^128 + x^125 + x^122 + x^121 + x^120 + x^116 + x^115 + x^114 + x^112 + x^111 + x^107 + x^106 + x^103 + x^101 + x^100 + x^99 + x^98 + x^96 + x^95 + x^94 + x^93 + x^92 + x^89 + x^88 + x^87 + x^86 + x^85 + x^84 + x^81 + x^79 + x^77 + x^76 + x^74 + x^72 + x^71 + x^70 + x^69 + x^65 + x^64 + x^62 + x^55 + x^53 + x^49 + x^48 + x^46 + x^44 + x^43 + x^39 + x^38 + x^37 + x^35 + x^33 + x^32 + x^31 + x^29 + x^27 + x^26 + x^24 + x^23 + x^22 + x^20 + x^18 + x^17 + x^8 + 1
+
+14-19-11 415 x^928 + x^898 + x^882 + x^870 + x^863 + x^862 + x^860 + x^854 + x^852 + x^844 + x^843 + x^833 + x^832 + x^825 + x^822 + x^819 + x^817 + x^816 + x^813 + x^811 + x^802 + x^798 + x^797 + x^795 + x^794 + x^790 + x^789 + x^787 + x^786 + x^781 + x^778 + x^776 + x^773 + x^772 + x^771 + x^768 + x^759 + x^754 + x^749 + x^746 + x^744 + x^743 + x^741 + x^740 + x^735 + x^734 + x^733 + x^730 + x^729 + x^725 + x^722 + x^717 + x^714 + x^711 + x^706 + x^705 + x^698 + x^697 + x^695 + x^691 + x^687 + x^686 + x^683 + x^681 + x^675 + x^674 + x^673 + x^672 + x^671 + x^670 + x^667 + x^665 + x^662 + x^661 + x^660 + x^658 + x^657 + x^656 + x^655 + x^654 + x^652 + x^649 + x^648 + x^645 + x^643 + x^642 + x^638 + x^636 + x^635 + x^634 + x^633 + x^632 + x^630 + x^629 + x^627 + x^626 + x^625 + x^624 + x^623 + x^622 + x^620 + x^617 + x^616 + x^615 + x^613 + x^612 + x^611 + x^608 + x^604 + x^603 + x^602 + x^599 + x^598 + x^597 + x^595 + x^594 + x^593 + x^592 + x^591 + x^590 + x^587 + x^586 + x^585 + x^584 + x^582 + x^580 + x^579 + x^578 + x^577 + x^570 + x^569 + x^568 + x^567 + x^566 + x^563 + x^562 + x^560 + x^558 + x^552 + x^550 + x^549 + x^546 + x^544 + x^543 + x^540 + x^537 + x^536 + x^535 + x^533 + x^532 + x^531 + x^530 + x^529 + x^527 + x^526 + x^522 + x^521 + x^519 + x^517 + x^514 + x^513 + x^512 + x^511 + x^510 + x^509 + x^507 + x^506 + x^504 + x^503 + x^502 + x^501 + x^500 + x^499 + x^498 + x^496 + x^494 + x^492 + x^491 + x^489 + x^488 + x^487 + x^485 + x^480 + x^479 + x^478 + x^475 + x^472 + x^463 + x^458 + x^455 + x^453 + x^452 + x^448 + x^443 + x^438 + x^436 + x^435 + x^432 + x^429 + x^428 + x^427 + x^421 + x^420 + x^419 + x^418 + x^417 + x^416 + x^414 + x^412 + x^411 + x^410 + x^406 + x^405 + x^404 + x^402 + x^401 + x^400 + x^399 + x^393 + x^388 + x^387 + x^386 + x^385 + x^384 + x^380 + x^379 + x^378 + x^376 + x^375 + x^373 + x^370 + x^368 + x^367 + x^365 + x^363 + x^362 + x^359 + x^358 + x^357 + x^356 + x^353 + x^350 + x^347 + x^343 + x^342 + x^341 + x^339 + x^338 + x^334 + x^333 + x^327 + x^325 + x^323 + x^321 + x^318 + x^317 + x^314 + x^310 + x^309 + x^308 + x^307 + x^306 + x^305 + x^304 + x^301 + x^300 + x^298 + x^295 + x^292 + x^288 + x^286 + x^285 + x^283 + x^282 + x^281 + x^278 + x^277 + x^275 + x^270 + x^269 + x^263 + x^260 + x^256 + x^254 + x^253 + x^250 + x^249 + x^248 + x^245 + x^244 + x^241 + x^239 + x^237 + x^233 + x^227 + x^225 + x^223 + x^222 + x^220 + x^219 + x^218 + x^216 + x^214 + x^212 + x^207 + x^203 + x^201 + x^200 + x^198 + x^197 + x^196 + x^195 + x^191 + x^189 + x^188 + x^184 + x^183 + x^181 + x^180 + x^179 + x^176 + x^174 + x^173 + x^170 + x^169 + x^168 + x^167 + x^165 + x^164 + x^163 + x^162 + x^161 + x^159 + x^158 + x^157 + x^155 + x^154 + x^152 + x^151 + x^150 + x^147 + x^144 + x^143 + x^142 + x^140 + x^139 + x^138 + x^134 + x^131 + x^130 + x^129 + x^124 + x^123 + x^122 + x^121 + x^120 + x^116 + x^115 + x^114 + x^111 + x^110 + x^108 + x^106 + x^104 + x^103 + x^99 + x^98 + x^95 + x^93 + x^91 + x^87 + x^84 + x^83 + x^80 + x^77 + x^76 + x^75 + x^74 + x^73 + x^70 + x^65 + x^64 + x^63 + x^62 + x^61 + x^57 + x^56 + x^55 + x^53 + x^51 + x^50 + x^49 + x^47 + x^46 + x^45 + x^43 + x^42 + x^41 + x^39 + x^37 + x^36 + x^33 + x^31 + x^29 + x^28 + x^24 + x^23 + x^22 + x^21 + x^18 + x^17 + x^16 + x^11 + x^10 + 1
+
+34-37-5 415 x^928 + x^898 + x^889 + x^874 + x^870 + x^861 + x^846 + x^844 + x^839 + x^835 + x^833 + x^831 + x^818 + x^816 + x^812 + x^809 + x^808 + x^805 + x^804 + x^794 + x^792 + x^790 + x^788 + x^787 + x^784 + x^783 + x^778 + x^776 + x^775 + x^773 + x^772 + x^770 + x^769 + x^768 + x^764 + x^760 + x^759 + x^757 + x^756 + x^755 + x^754 + x^749 + x^748 + x^744 + x^740 + x^737 + x^735 + x^730 + x^729 + x^728 + x^727 + x^726 + x^725 + x^721 + x^720 + x^719 + x^718 + x^716 + x^715 + x^713 + x^712 + x^710 + x^709 + x^706 + x^699 + x^695 + x^689 + x^686 + x^682 + x^681 + x^680 + x^677 + x^674 + x^673 + x^672 + x^671 + x^665 + x^664 + x^663 + x^662 + x^661 + x^660 + x^657 + x^656 + x^651 + x^649 + x^646 + x^640 + x^639 + x^635 + x^634 + x^633 + x^632 + x^629 + x^628 + x^624 + x^623 + x^621 + x^620 + x^616 + x^615 + x^614 + x^613 + x^611 + x^610 + x^609 + x^607 + x^606 + x^605 + x^604 + x^601 + x^599 + x^597 + x^596 + x^595 + x^593 + x^591 + x^590 + x^585 + x^584 + x^583 + x^582 + x^580 + x^577 + x^576 + x^573 + x^569 + x^567 + x^564 + x^560 + x^559 + x^558 + x^557 + x^556 + x^555 + x^552 + x^551 + x^550 + x^547 + x^545 + x^544 + x^542 + x^541 + x^540 + x^539 + x^538 + x^535 + x^534 + x^533 + x^526 + x^523 + x^520 + x^518 + x^517 + x^515 + x^514 + x^513 + x^511 + x^510 + x^509 + x^504 + x^503 + x^502 + x^501 + x^496 + x^495 + x^494 + x^493 + x^492 + x^489 + x^485 + x^484 + x^482 + x^481 + x^478 + x^475 + x^472 + x^469 + x^468 + x^467 + x^465 + x^464 + x^462 + x^460 + x^455 + x^453 + x^452 + x^451 + x^449 + x^448 + x^447 + x^446 + x^445 + x^443 + x^442 + x^441 + x^438 + x^435 + x^434 + x^432 + x^431 + x^430 + x^427 + x^424 + x^423 + x^422 + x^419 + x^412 + x^411 + x^409 + x^408 + x^406 + x^405 + x^404 + x^403 + x^401 + x^400 + x^399 + x^393 + x^390 + x^389 + x^387 + x^385 + x^384 + x^380 + x^378 + x^376 + x^374 + x^372 + x^371 + x^370 + x^369 + x^366 + x^365 + x^360 + x^359 + x^357 + x^350 + x^349 + x^347 + x^346 + x^345 + x^344 + x^342 + x^341 + x^340 + x^337 + x^335 + x^334 + x^332 + x^331 + x^330 + x^328 + x^327 + x^325 + x^323 + x^322 + x^321 + x^320 + x^316 + x^314 + x^310 + x^308 + x^306 + x^305 + x^304 + x^301 + x^300 + x^295 + x^291 + x^290 + x^289 + x^288 + x^287 + x^283 + x^281 + x^280 + x^279 + x^277 + x^274 + x^272 + x^271 + x^268 + x^266 + x^264 + x^263 + x^261 + x^259 + x^255 + x^254 + x^253 + x^250 + x^249 + x^246 + x^244 + x^242 + x^241 + x^237 + x^233 + x^230 + x^229 + x^227 + x^223 + x^222 + x^217 + x^216 + x^208 + x^207 + x^206 + x^205 + x^204 + x^203 + x^198 + x^196 + x^192 + x^191 + x^190 + x^189 + x^188 + x^187 + x^186 + x^185 + x^182 + x^181 + x^180 + x^178 + x^175 + x^171 + x^166 + x^165 + x^164 + x^163 + x^162 + x^161 + x^159 + x^157 + x^156 + x^149 + x^148 + x^146 + x^145 + x^143 + x^142 + x^141 + x^140 + x^139 + x^138 + x^136 + x^135 + x^131 + x^130 + x^129 + x^127 + x^125 + x^124 + x^117 + x^115 + x^113 + x^110 + x^108 + x^107 + x^106 + x^105 + x^103 + x^99 + x^98 + x^95 + x^93 + x^90 + x^87 + x^84 + x^83 + x^81 + x^80 + x^79 + x^78 + x^77 + x^72 + x^71 + x^68 + x^65 + x^64 + x^63 + x^62 + x^59 + x^58 + x^56 + x^55 + x^54 + x^53 + x^52 + x^51 + x^46 + x^45 + x^44 + x^43 + x^40 + x^39 + x^36 + x^35 + x^33 + x^32 + x^31 + x^30 + x^27 + x^25 + x^24 + x^22 + x^18 + x^17 + x^14 + x^13 + x^12 + x^10 + 1
+
+37-3-56 415 x^928 + x^898 + x^878 + x^870 + x^862 + x^860 + x^849 + x^840 + x^831 + x^822 + x^819 + x^818 + x^811 + x^802 + x^801 + x^796 + x^795 + x^794 + x^793 + x^790 + x^789 + x^784 + x^781 + x^780 + x^777 + x^775 + x^772 + x^766 + x^760 + x^758 + x^755 + x^753 + x^752 + x^747 + x^745 + x^744 + x^743 + x^740 + x^738 + x^737 + x^736 + x^732 + x^730 + x^729 + x^728 + x^726 + x^721 + x^716 + x^715 + x^713 + x^712 + x^711 + x^710 + x^709 + x^706 + x^705 + x^702 + x^700 + x^699 + x^698 + x^697 + x^696 + x^693 + x^692 + x^690 + x^687 + x^686 + x^684 + x^683 + x^682 + x^681 + x^680 + x^678 + x^675 + x^674 + x^673 + x^672 + x^670 + x^669 + x^667 + x^664 + x^662 + x^661 + x^660 + x^658 + x^657 + x^656 + x^654 + x^653 + x^652 + x^650 + x^649 + x^648 + x^645 + x^644 + x^641 + x^639 + x^635 + x^634 + x^631 + x^630 + x^629 + x^628 + x^622 + x^621 + x^620 + x^617 + x^616 + x^614 + x^610 + x^609 + x^608 + x^606 + x^604 + x^601 + x^600 + x^598 + x^597 + x^596 + x^593 + x^592 + x^590 + x^588 + x^587 + x^586 + x^585 + x^584 + x^583 + x^579 + x^578 + x^575 + x^574 + x^573 + x^569 + x^568 + x^566 + x^564 + x^563 + x^561 + x^559 + x^557 + x^556 + x^553 + x^552 + x^550 + x^548 + x^546 + x^543 + x^542 + x^541 + x^540 + x^538 + x^537 + x^536 + x^533 + x^532 + x^529 + x^528 + x^527 + x^525 + x^522 + x^520 + x^519 + x^518 + x^517 + x^515 + x^514 + x^513 + x^509 + x^507 + x^506 + x^504 + x^503 + x^502 + x^499 + x^495 + x^494 + x^493 + x^492 + x^490 + x^486 + x^482 + x^481 + x^480 + x^479 + x^477 + x^476 + x^475 + x^474 + x^473 + x^472 + x^470 + x^468 + x^467 + x^463 + x^457 + x^453 + x^451 + x^448 + x^446 + x^445 + x^440 + x^438 + x^437 + x^434 + x^433 + x^432 + x^431 + x^430 + x^425 + x^424 + x^423 + x^417 + x^414 + x^409 + x^407 + x^406 + x^405 + x^402 + x^400 + x^399 + x^398 + x^397 + x^396 + x^395 + x^394 + x^391 + x^389 + x^387 + x^386 + x^384 + x^383 + x^379 + x^377 + x^372 + x^371 + x^369 + x^368 + x^366 + x^365 + x^364 + x^361 + x^359 + x^357 + x^354 + x^351 + x^348 + x^347 + x^340 + x^339 + x^337 + x^336 + x^334 + x^329 + x^327 + x^326 + x^325 + x^322 + x^320 + x^318 + x^315 + x^314 + x^313 + x^312 + x^310 + x^309 + x^308 + x^306 + x^305 + x^301 + x^300 + x^298 + x^294 + x^293 + x^292 + x^291 + x^288 + x^285 + x^284 + x^282 + x^279 + x^275 + x^272 + x^271 + x^270 + x^269 + x^268 + x^266 + x^259 + x^257 + x^254 + x^253 + x^251 + x^250 + x^248 + x^246 + x^244 + x^243 + x^242 + x^238 + x^237 + x^234 + x^233 + x^232 + x^231 + x^230 + x^227 + x^223 + x^222 + x^221 + x^219 + x^216 + x^215 + x^212 + x^207 + x^205 + x^203 + x^200 + x^199 + x^198 + x^196 + x^195 + x^193 + x^191 + x^187 + x^185 + x^183 + x^181 + x^179 + x^178 + x^177 + x^174 + x^171 + x^170 + x^168 + x^166 + x^165 + x^163 + x^160 + x^156 + x^155 + x^154 + x^151 + x^150 + x^149 + x^146 + x^145 + x^142 + x^141 + x^136 + x^135 + x^134 + x^132 + x^128 + x^127 + x^125 + x^121 + x^118 + x^117 + x^116 + x^113 + x^112 + x^111 + x^108 + x^106 + x^105 + x^104 + x^102 + x^101 + x^100 + x^99 + x^96 + x^95 + x^94 + x^89 + x^85 + x^83 + x^81 + x^80 + x^79 + x^69 + x^65 + x^63 + x^62 + x^61 + x^59 + x^58 + x^57 + x^56 + x^52 + x^49 + x^46 + x^45 + x^43 + x^42 + x^41 + x^40 + x^39 + x^38 + x^37 + x^36 + x^33 + x^32 + x^28 + x^24 + x^23 + x^20 + x^18 + x^17 + x^14 + x^11 + x^10 + x^9 + x^8 + 1
+
+55-11-54 417 x^928 + x^898 + x^896 + x^870 + x^867 + x^866 + x^864 + x^853 + x^846 + x^837 + x^836 + x^835 + x^828 + x^826 + x^824 + x^823 + x^817 + x^814 + x^812 + x^810 + x^808 + x^807 + x^806 + x^805 + x^804 + x^803 + x^802 + x^800 + x^796 + x^791 + x^789 + x^786 + x^784 + x^781 + x^780 + x^777 + x^772 + x^771 + x^770 + x^767 + x^762 + x^761 + x^757 + x^753 + x^747 + x^742 + x^740 + x^739 + x^737 + x^736 + x^735 + x^734 + x^733 + x^731 + x^730 + x^725 + x^723 + x^722 + x^717 + x^715 + x^708 + x^707 + x^705 + x^704 + x^703 + x^699 + x^698 + x^695 + x^690 + x^689 + x^686 + x^685 + x^684 + x^682 + x^681 + x^680 + x^678 + x^677 + x^675 + x^669 + x^667 + x^666 + x^665 + x^664 + x^663 + x^662 + x^661 + x^660 + x^658 + x^657 + x^656 + x^655 + x^654 + x^651 + x^650 + x^646 + x^645 + x^643 + x^641 + x^640 + x^639 + x^637 + x^634 + x^633 + x^632 + x^631 + x^627 + x^624 + x^622 + x^620 + x^617 + x^616 + x^615 + x^614 + x^613 + x^608 + x^601 + x^600 + x^599 + x^595 + x^592 + x^591 + x^590 + x^586 + x^580 + x^579 + x^578 + x^577 + x^576 + x^575 + x^571 + x^570 + x^569 + x^567 + x^566 + x^565 + x^564 + x^563 + x^562 + x^561 + x^560 + x^558 + x^557 + x^555 + x^554 + x^553 + x^552 + x^551 + x^550 + x^549 + x^545 + x^543 + x^542 + x^539 + x^537 + x^532 + x^530 + x^526 + x^525 + x^520 + x^519 + x^517 + x^515 + x^513 + x^511 + x^510 + x^508 + x^504 + x^502 + x^501 + x^498 + x^493 + x^492 + x^490 + x^489 + x^488 + x^487 + x^485 + x^484 + x^483 + x^481 + x^480 + x^479 + x^477 + x^475 + x^473 + x^472 + x^469 + x^468 + x^467 + x^466 + x^463 + x^462 + x^461 + x^459 + x^455 + x^453 + x^451 + x^450 + x^449 + x^445 + x^444 + x^443 + x^442 + x^441 + x^440 + x^437 + x^435 + x^434 + x^431 + x^430 + x^429 + x^427 + x^426 + x^422 + x^421 + x^420 + x^413 + x^410 + x^409 + x^408 + x^407 + x^405 + x^403 + x^402 + x^401 + x^397 + x^396 + x^393 + x^389 + x^386 + x^384 + x^380 + x^379 + x^376 + x^373 + x^372 + x^370 + x^369 + x^367 + x^365 + x^364 + x^363 + x^358 + x^356 + x^355 + x^354 + x^353 + x^349 + x^345 + x^342 + x^334 + x^332 + x^331 + x^329 + x^325 + x^324 + x^322 + x^316 + x^315 + x^314 + x^312 + x^310 + x^307 + x^306 + x^298 + x^297 + x^296 + x^294 + x^293 + x^292 + x^288 + x^285 + x^284 + x^283 + x^282 + x^279 + x^273 + x^271 + x^267 + x^262 + x^257 + x^255 + x^253 + x^252 + x^251 + x^250 + x^248 + x^247 + x^245 + x^244 + x^243 + x^240 + x^238 + x^237 + x^236 + x^234 + x^232 + x^229 + x^224 + x^223 + x^222 + x^221 + x^218 + x^216 + x^215 + x^213 + x^211 + x^210 + x^209 + x^207 + x^205 + x^203 + x^202 + x^201 + x^198 + x^195 + x^194 + x^193 + x^192 + x^190 + x^189 + x^187 + x^186 + x^185 + x^184 + x^183 + x^182 + x^181 + x^179 + x^177 + x^176 + x^175 + x^174 + x^172 + x^170 + x^167 + x^160 + x^157 + x^156 + x^153 + x^151 + x^150 + x^149 + x^143 + x^140 + x^137 + x^136 + x^134 + x^133 + x^129 + x^128 + x^124 + x^123 + x^120 + x^118 + x^117 + x^116 + x^115 + x^114 + x^112 + x^111 + x^110 + x^108 + x^105 + x^104 + x^102 + x^101 + x^100 + x^98 + x^97 + x^93 + x^92 + x^91 + x^90 + x^88 + x^87 + x^85 + x^81 + x^79 + x^77 + x^76 + x^74 + x^73 + x^72 + x^70 + x^65 + x^63 + x^62 + x^61 + x^59 + x^55 + x^53 + x^51 + x^50 + x^47 + x^46 + x^45 + x^44 + x^43 + x^40 + x^38 + x^34 + x^32 + x^30 + x^29 + x^28 + x^27 + x^24 + x^22 + x^21 + x^18 + x^17 + x^14 + x^11 + x^4 + 1
+
+30-3-41 419 x^928 + x^906 + x^898 + x^884 + x^879 + x^876 + x^870 + x^862 + x^854 + x^852 + x^849 + x^844 + x^835 + x^832 + x^829 + x^825 + x^822 + x^819 + x^818 + x^813 + x^812 + x^807 + x^805 + x^803 + x^802 + x^798 + x^795 + x^794 + x^792 + x^790 + x^789 + x^788 + x^786 + x^785 + x^778 + x^777 + x^769 + x^768 + x^762 + x^760 + x^753 + x^751 + x^748 + x^747 + x^746 + x^742 + x^738 + x^735 + x^734 + x^733 + x^731 + x^729 + x^726 + x^725 + x^723 + x^719 + x^718 + x^716 + x^713 + x^706 + x^703 + x^702 + x^701 + x^700 + x^699 + x^696 + x^693 + x^690 + x^687 + x^686 + x^685 + x^684 + x^682 + x^679 + x^677 + x^673 + x^672 + x^671 + x^670 + x^664 + x^659 + x^656 + x^653 + x^651 + x^650 + x^647 + x^643 + x^642 + x^639 + x^637 + x^635 + x^633 + x^630 + x^627 + x^625 + x^624 + x^621 + x^616 + x^615 + x^614 + x^613 + x^612 + x^607 + x^604 + x^603 + x^600 + x^597 + x^596 + x^595 + x^593 + x^592 + x^591 + x^588 + x^586 + x^583 + x^581 + x^580 + x^578 + x^575 + x^574 + x^571 + x^569 + x^568 + x^567 + x^566 + x^565 + x^564 + x^562 + x^560 + x^559 + x^558 + x^557 + x^555 + x^554 + x^553 + x^552 + x^550 + x^546 + x^545 + x^543 + x^542 + x^537 + x^535 + x^534 + x^532 + x^530 + x^527 + x^525 + x^523 + x^521 + x^520 + x^512 + x^506 + x^505 + x^504 + x^503 + x^501 + x^500 + x^499 + x^498 + x^497 + x^495 + x^494 + x^493 + x^489 + x^487 + x^485 + x^484 + x^479 + x^478 + x^477 + x^475 + x^474 + x^471 + x^470 + x^469 + x^468 + x^467 + x^466 + x^464 + x^462 + x^459 + x^458 + x^457 + x^456 + x^451 + x^449 + x^448 + x^447 + x^446 + x^443 + x^441 + x^440 + x^439 + x^437 + x^435 + x^434 + x^433 + x^432 + x^431 + x^430 + x^427 + x^425 + x^424 + x^423 + x^420 + x^419 + x^418 + x^417 + x^416 + x^414 + x^412 + x^410 + x^409 + x^405 + x^404 + x^402 + x^401 + x^400 + x^396 + x^394 + x^393 + x^391 + x^390 + x^389 + x^388 + x^387 + x^386 + x^385 + x^380 + x^379 + x^369 + x^368 + x^363 + x^362 + x^361 + x^360 + x^359 + x^355 + x^354 + x^351 + x^347 + x^346 + x^345 + x^342 + x^337 + x^336 + x^332 + x^328 + x^324 + x^322 + x^321 + x^319 + x^318 + x^317 + x^315 + x^312 + x^310 + x^309 + x^307 + x^303 + x^302 + x^300 + x^298 + x^295 + x^289 + x^288 + x^287 + x^286 + x^285 + x^284 + x^283 + x^282 + x^281 + x^276 + x^275 + x^273 + x^272 + x^271 + x^268 + x^265 + x^263 + x^262 + x^260 + x^259 + x^255 + x^254 + x^253 + x^252 + x^249 + x^245 + x^244 + x^243 + x^242 + x^241 + x^240 + x^239 + x^236 + x^235 + x^233 + x^232 + x^231 + x^230 + x^224 + x^223 + x^222 + x^221 + x^218 + x^215 + x^214 + x^213 + x^209 + x^206 + x^204 + x^199 + x^197 + x^196 + x^194 + x^190 + x^186 + x^185 + x^183 + x^182 + x^181 + x^180 + x^179 + x^178 + x^177 + x^176 + x^175 + x^174 + x^173 + x^168 + x^167 + x^166 + x^165 + x^164 + x^163 + x^162 + x^161 + x^159 + x^158 + x^156 + x^155 + x^153 + x^151 + x^148 + x^144 + x^143 + x^142 + x^141 + x^139 + x^136 + x^135 + x^131 + x^129 + x^128 + x^127 + x^126 + x^125 + x^124 + x^123 + x^121 + x^119 + x^118 + x^116 + x^113 + x^111 + x^109 + x^107 + x^106 + x^103 + x^102 + x^100 + x^99 + x^98 + x^96 + x^93 + x^92 + x^90 + x^86 + x^85 + x^83 + x^82 + x^80 + x^76 + x^73 + x^72 + x^71 + x^70 + x^67 + x^66 + x^64 + x^61 + x^60 + x^59 + x^56 + x^53 + x^50 + x^49 + x^45 + x^44 + x^42 + x^39 + x^36 + x^35 + x^30 + x^28 + x^25 + x^22 + x^19 + x^18 + x^17 + x^15 + x^14 + x^11 + x^10 + x^5 + 1
+
+11-45-50 423 x^928 + x^898 + x^891 + x^870 + x^862 + x^861 + x^858 + x^857 + x^854 + x^851 + x^828 + x^825 + x^824 + x^822 + x^818 + x^814 + x^811 + x^808 + x^802 + x^800 + x^798 + x^797 + x^787 + x^786 + x^785 + x^783 + x^782 + x^781 + x^776 + x^772 + x^771 + x^770 + x^768 + x^765 + x^760 + x^758 + x^756 + x^754 + x^750 + x^749 + x^746 + x^742 + x^738 + x^737 + x^736 + x^735 + x^734 + x^732 + x^729 + x^723 + x^719 + x^718 + x^716 + x^715 + x^714 + x^713 + x^708 + x^707 + x^705 + x^704 + x^703 + x^702 + x^701 + x^700 + x^698 + x^697 + x^696 + x^694 + x^692 + x^688 + x^684 + x^683 + x^681 + x^680 + x^678 + x^666 + x^664 + x^663 + x^662 + x^660 + x^659 + x^658 + x^656 + x^654 + x^653 + x^652 + x^651 + x^650 + x^649 + x^647 + x^645 + x^642 + x^641 + x^639 + x^638 + x^637 + x^636 + x^634 + x^632 + x^631 + x^626 + x^625 + x^623 + x^620 + x^617 + x^616 + x^614 + x^612 + x^610 + x^609 + x^607 + x^605 + x^603 + x^601 + x^600 + x^598 + x^597 + x^596 + x^595 + x^594 + x^591 + x^589 + x^588 + x^586 + x^585 + x^584 + x^581 + x^579 + x^578 + x^577 + x^576 + x^575 + x^573 + x^572 + x^570 + x^569 + x^568 + x^566 + x^561 + x^559 + x^558 + x^557 + x^554 + x^552 + x^551 + x^550 + x^549 + x^548 + x^546 + x^544 + x^543 + x^541 + x^540 + x^538 + x^533 + x^531 + x^529 + x^528 + x^523 + x^519 + x^515 + x^512 + x^511 + x^510 + x^508 + x^507 + x^506 + x^501 + x^498 + x^497 + x^496 + x^495 + x^494 + x^492 + x^490 + x^489 + x^488 + x^487 + x^486 + x^485 + x^483 + x^477 + x^476 + x^474 + x^472 + x^470 + x^469 + x^467 + x^465 + x^462 + x^460 + x^458 + x^452 + x^451 + x^449 + x^447 + x^446 + x^445 + x^442 + x^441 + x^440 + x^437 + x^436 + x^434 + x^433 + x^431 + x^428 + x^427 + x^426 + x^425 + x^423 + x^422 + x^420 + x^419 + x^418 + x^417 + x^415 + x^414 + x^413 + x^412 + x^411 + x^409 + x^407 + x^404 + x^403 + x^402 + x^399 + x^398 + x^396 + x^395 + x^392 + x^391 + x^389 + x^388 + x^387 + x^386 + x^385 + x^384 + x^381 + x^379 + x^378 + x^377 + x^375 + x^373 + x^369 + x^367 + x^365 + x^364 + x^362 + x^359 + x^358 + x^357 + x^355 + x^351 + x^348 + x^347 + x^346 + x^345 + x^344 + x^343 + x^335 + x^334 + x^332 + x^328 + x^325 + x^324 + x^321 + x^319 + x^318 + x^316 + x^314 + x^312 + x^311 + x^310 + x^304 + x^300 + x^297 + x^296 + x^294 + x^293 + x^292 + x^291 + x^289 + x^288 + x^285 + x^283 + x^277 + x^276 + x^274 + x^271 + x^270 + x^269 + x^268 + x^265 + x^264 + x^260 + x^259 + x^258 + x^257 + x^256 + x^252 + x^251 + x^249 + x^248 + x^247 + x^246 + x^244 + x^242 + x^238 + x^236 + x^233 + x^232 + x^231 + x^230 + x^229 + x^228 + x^227 + x^222 + x^220 + x^218 + x^214 + x^212 + x^209 + x^208 + x^207 + x^204 + x^203 + x^202 + x^200 + x^193 + x^190 + x^189 + x^188 + x^186 + x^185 + x^183 + x^178 + x^176 + x^174 + x^171 + x^169 + x^168 + x^166 + x^165 + x^163 + x^162 + x^161 + x^158 + x^156 + x^155 + x^154 + x^153 + x^150 + x^147 + x^146 + x^145 + x^141 + x^136 + x^134 + x^132 + x^128 + x^127 + x^126 + x^123 + x^120 + x^119 + x^114 + x^112 + x^111 + x^105 + x^104 + x^101 + x^100 + x^98 + x^97 + x^96 + x^95 + x^94 + x^92 + x^91 + x^88 + x^87 + x^85 + x^84 + x^83 + x^80 + x^78 + x^77 + x^76 + x^74 + x^73 + x^72 + x^68 + x^64 + x^62 + x^61 + x^60 + x^56 + x^55 + x^54 + x^53 + x^50 + x^46 + x^42 + x^41 + x^40 + x^39 + x^36 + x^32 + x^31 + x^30 + x^28 + x^25 + x^24 + x^16 + x^15 + x^14 + x^13 + x^10 + x^9 + x^6 + x^3 + 1
+
+50-19-47 423 x^928 + x^906 + x^898 + x^897 + x^884 + x^876 + x^870 + x^862 + x^854 + x^840 + x^836 + x^835 + x^832 + x^831 + x^830 + x^821 + x^814 + x^813 + x^812 + x^810 + x^808 + x^805 + x^803 + x^796 + x^794 + x^792 + x^791 + x^786 + x^785 + x^783 + x^777 + x^774 + x^773 + x^767 + x^766 + x^764 + x^762 + x^761 + x^760 + x^759 + x^758 + x^754 + x^750 + x^748 + x^747 + x^746 + x^743 + x^742 + x^739 + x^734 + x^732 + x^728 + x^727 + x^724 + x^722 + x^720 + x^718 + x^716 + x^714 + x^713 + x^712 + x^711 + x^709 + x^708 + x^705 + x^704 + x^702 + x^699 + x^698 + x^695 + x^694 + x^693 + x^692 + x^691 + x^688 + x^686 + x^683 + x^682 + x^681 + x^679 + x^676 + x^674 + x^672 + x^671 + x^668 + x^664 + x^663 + x^661 + x^659 + x^657 + x^656 + x^654 + x^652 + x^646 + x^645 + x^641 + x^638 + x^635 + x^634 + x^632 + x^629 + x^628 + x^619 + x^618 + x^617 + x^615 + x^613 + x^612 + x^610 + x^609 + x^607 + x^606 + x^605 + x^604 + x^603 + x^602 + x^598 + x^597 + x^596 + x^595 + x^593 + x^591 + x^590 + x^589 + x^584 + x^583 + x^582 + x^581 + x^580 + x^579 + x^576 + x^575 + x^573 + x^569 + x^568 + x^567 + x^565 + x^564 + x^562 + x^556 + x^554 + x^552 + x^551 + x^550 + x^548 + x^547 + x^546 + x^545 + x^542 + x^541 + x^540 + x^539 + x^537 + x^535 + x^534 + x^532 + x^528 + x^526 + x^525 + x^524 + x^522 + x^521 + x^519 + x^515 + x^513 + x^510 + x^508 + x^507 + x^506 + x^505 + x^504 + x^502 + x^501 + x^500 + x^499 + x^496 + x^495 + x^494 + x^492 + x^490 + x^489 + x^486 + x^485 + x^484 + x^483 + x^481 + x^479 + x^478 + x^476 + x^474 + x^471 + x^469 + x^467 + x^465 + x^463 + x^458 + x^456 + x^455 + x^454 + x^451 + x^449 + x^448 + x^443 + x^442 + x^440 + x^439 + x^437 + x^436 + x^433 + x^432 + x^431 + x^430 + x^428 + x^427 + x^426 + x^425 + x^424 + x^421 + x^420 + x^416 + x^415 + x^413 + x^412 + x^411 + x^410 + x^409 + x^408 + x^406 + x^405 + x^403 + x^400 + x^399 + x^398 + x^396 + x^395 + x^393 + x^391 + x^388 + x^387 + x^386 + x^381 + x^380 + x^377 + x^376 + x^375 + x^374 + x^373 + x^371 + x^370 + x^369 + x^368 + x^361 + x^359 + x^358 + x^357 + x^355 + x^352 + x^350 + x^348 + x^347 + x^346 + x^343 + x^342 + x^339 + x^337 + x^335 + x^334 + x^332 + x^329 + x^325 + x^324 + x^323 + x^322 + x^318 + x^317 + x^315 + x^314 + x^311 + x^310 + x^306 + x^304 + x^300 + x^299 + x^297 + x^295 + x^294 + x^289 + x^286 + x^283 + x^279 + x^278 + x^276 + x^275 + x^273 + x^269 + x^268 + x^266 + x^264 + x^260 + x^258 + x^257 + x^254 + x^252 + x^250 + x^248 + x^247 + x^246 + x^245 + x^241 + x^239 + x^237 + x^236 + x^235 + x^234 + x^232 + x^228 + x^227 + x^226 + x^225 + x^218 + x^215 + x^214 + x^212 + x^211 + x^210 + x^208 + x^206 + x^205 + x^204 + x^203 + x^201 + x^198 + x^196 + x^193 + x^192 + x^190 + x^189 + x^188 + x^184 + x^181 + x^180 + x^178 + x^177 + x^176 + x^175 + x^174 + x^173 + x^171 + x^169 + x^168 + x^166 + x^165 + x^164 + x^162 + x^160 + x^159 + x^158 + x^153 + x^150 + x^148 + x^147 + x^146 + x^143 + x^142 + x^139 + x^136 + x^135 + x^134 + x^133 + x^132 + x^126 + x^124 + x^121 + x^118 + x^116 + x^112 + x^109 + x^108 + x^107 + x^104 + x^101 + x^98 + x^97 + x^95 + x^93 + x^88 + x^86 + x^85 + x^84 + x^83 + x^78 + x^77 + x^73 + x^70 + x^69 + x^68 + x^66 + x^64 + x^63 + x^62 + x^58 + x^57 + x^53 + x^52 + x^50 + x^48 + x^45 + x^43 + x^42 + x^41 + x^40 + x^39 + x^38 + x^33 + x^26 + x^22 + x^21 + x^20 + x^18 + x^17 + x^10 + x^8 + 1
+
+52-27-13 427 x^928 + x^898 + x^870 + x^866 + x^858 + x^855 + x^854 + x^847 + x^844 + x^836 + x^833 + x^832 + x^829 + x^828 + x^825 + x^822 + x^818 + x^817 + x^814 + x^811 + x^808 + x^807 + x^800 + x^799 + x^798 + x^796 + x^795 + x^792 + x^789 + x^781 + x^777 + x^774 + x^770 + x^769 + x^768 + x^767 + x^765 + x^762 + x^759 + x^756 + x^755 + x^754 + x^752 + x^751 + x^748 + x^746 + x^745 + x^744 + x^740 + x^739 + x^738 + x^736 + x^735 + x^734 + x^732 + x^730 + x^729 + x^728 + x^724 + x^721 + x^719 + x^718 + x^717 + x^716 + x^713 + x^712 + x^710 + x^709 + x^706 + x^705 + x^704 + x^702 + x^701 + x^699 + x^698 + x^697 + x^695 + x^693 + x^690 + x^689 + x^687 + x^686 + x^685 + x^683 + x^682 + x^681 + x^680 + x^677 + x^676 + x^675 + x^674 + x^671 + x^669 + x^668 + x^667 + x^666 + x^665 + x^663 + x^660 + x^659 + x^655 + x^654 + x^653 + x^652 + x^650 + x^648 + x^647 + x^643 + x^642 + x^640 + x^639 + x^638 + x^635 + x^634 + x^633 + x^632 + x^630 + x^629 + x^628 + x^626 + x^624 + x^620 + x^618 + x^617 + x^616 + x^615 + x^612 + x^610 + x^607 + x^606 + x^604 + x^603 + x^602 + x^598 + x^597 + x^593 + x^589 + x^588 + x^587 + x^585 + x^583 + x^581 + x^580 + x^579 + x^578 + x^570 + x^569 + x^566 + x^565 + x^564 + x^563 + x^561 + x^559 + x^558 + x^557 + x^556 + x^555 + x^551 + x^550 + x^548 + x^547 + x^545 + x^544 + x^540 + x^539 + x^538 + x^537 + x^536 + x^535 + x^534 + x^532 + x^529 + x^528 + x^527 + x^526 + x^525 + x^524 + x^523 + x^522 + x^519 + x^517 + x^516 + x^515 + x^513 + x^512 + x^511 + x^507 + x^504 + x^502 + x^495 + x^493 + x^492 + x^491 + x^490 + x^489 + x^484 + x^483 + x^481 + x^480 + x^478 + x^466 + x^464 + x^463 + x^460 + x^459 + x^457 + x^455 + x^454 + x^451 + x^450 + x^448 + x^447 + x^435 + x^434 + x^433 + x^432 + x^431 + x^428 + x^424 + x^423 + x^422 + x^421 + x^420 + x^419 + x^414 + x^413 + x^412 + x^411 + x^410 + x^409 + x^407 + x^404 + x^401 + x^396 + x^395 + x^394 + x^391 + x^390 + x^389 + x^388 + x^385 + x^382 + x^379 + x^377 + x^372 + x^370 + x^367 + x^365 + x^362 + x^361 + x^357 + x^355 + x^354 + x^351 + x^349 + x^348 + x^345 + x^343 + x^342 + x^340 + x^338 + x^334 + x^330 + x^328 + x^324 + x^323 + x^320 + x^319 + x^318 + x^317 + x^315 + x^313 + x^310 + x^309 + x^307 + x^303 + x^302 + x^301 + x^300 + x^299 + x^298 + x^297 + x^296 + x^295 + x^292 + x^289 + x^288 + x^287 + x^285 + x^283 + x^280 + x^274 + x^273 + x^271 + x^267 + x^265 + x^264 + x^261 + x^259 + x^258 + x^256 + x^254 + x^253 + x^248 + x^247 + x^244 + x^239 + x^238 + x^237 + x^233 + x^232 + x^230 + x^229 + x^228 + x^227 + x^224 + x^221 + x^217 + x^216 + x^215 + x^214 + x^209 + x^207 + x^206 + x^205 + x^203 + x^201 + x^200 + x^199 + x^196 + x^195 + x^194 + x^192 + x^191 + x^190 + x^189 + x^187 + x^186 + x^182 + x^180 + x^177 + x^176 + x^174 + x^173 + x^170 + x^169 + x^168 + x^167 + x^164 + x^160 + x^154 + x^153 + x^152 + x^148 + x^144 + x^143 + x^142 + x^141 + x^140 + x^139 + x^135 + x^134 + x^133 + x^132 + x^129 + x^125 + x^124 + x^122 + x^121 + x^120 + x^118 + x^117 + x^116 + x^115 + x^112 + x^111 + x^110 + x^109 + x^108 + x^107 + x^106 + x^104 + x^103 + x^101 + x^96 + x^95 + x^93 + x^90 + x^87 + x^86 + x^82 + x^79 + x^77 + x^75 + x^70 + x^68 + x^67 + x^66 + x^62 + x^60 + x^57 + x^54 + x^53 + x^52 + x^51 + x^49 + x^46 + x^45 + x^43 + x^42 + x^41 + x^40 + x^39 + x^38 + x^36 + x^33 + x^31 + x^30 + x^29 + x^27 + x^26 + x^24 + x^22 + x^18 + x^7 + x^6 + 1
+
+54-9-25 433 x^928 + x^898 + x^875 + x^870 + x^860 + x^850 + x^847 + x^840 + x^835 + x^832 + x^822 + x^819 + x^815 + x^812 + x^808 + x^807 + x^805 + x^804 + x^800 + x^797 + x^794 + x^792 + x^791 + x^790 + x^787 + x^785 + x^782 + x^778 + x^777 + x^776 + x^771 + x^770 + x^767 + x^766 + x^764 + x^763 + x^760 + x^759 + x^757 + x^755 + x^754 + x^753 + x^752 + x^748 + x^743 + x^742 + x^739 + x^738 + x^737 + x^735 + x^734 + x^733 + x^731 + x^730 + x^729 + x^725 + x^724 + x^723 + x^720 + x^719 + x^717 + x^716 + x^714 + x^713 + x^711 + x^710 + x^709 + x^706 + x^705 + x^700 + x^699 + x^697 + x^696 + x^695 + x^693 + x^692 + x^691 + x^688 + x^687 + x^686 + x^685 + x^683 + x^682 + x^680 + x^676 + x^671 + x^670 + x^664 + x^663 + x^662 + x^661 + x^660 + x^658 + x^657 + x^656 + x^654 + x^653 + x^649 + x^648 + x^646 + x^645 + x^642 + x^637 + x^635 + x^633 + x^632 + x^630 + x^627 + x^624 + x^623 + x^621 + x^620 + x^619 + x^617 + x^615 + x^614 + x^613 + x^610 + x^609 + x^608 + x^607 + x^604 + x^602 + x^601 + x^600 + x^599 + x^593 + x^592 + x^591 + x^589 + x^585 + x^584 + x^580 + x^576 + x^575 + x^574 + x^570 + x^569 + x^566 + x^565 + x^564 + x^563 + x^562 + x^561 + x^559 + x^558 + x^554 + x^552 + x^551 + x^547 + x^546 + x^545 + x^543 + x^541 + x^540 + x^535 + x^532 + x^531 + x^530 + x^529 + x^525 + x^524 + x^523 + x^521 + x^520 + x^519 + x^518 + x^517 + x^516 + x^515 + x^513 + x^512 + x^510 + x^509 + x^504 + x^503 + x^502 + x^501 + x^500 + x^497 + x^496 + x^494 + x^493 + x^488 + x^487 + x^486 + x^484 + x^482 + x^481 + x^480 + x^479 + x^475 + x^472 + x^465 + x^464 + x^462 + x^461 + x^460 + x^457 + x^456 + x^455 + x^454 + x^452 + x^451 + x^450 + x^449 + x^448 + x^446 + x^445 + x^444 + x^443 + x^441 + x^438 + x^437 + x^436 + x^434 + x^432 + x^430 + x^427 + x^425 + x^424 + x^421 + x^420 + x^419 + x^418 + x^417 + x^414 + x^413 + x^410 + x^409 + x^407 + x^404 + x^403 + x^402 + x^401 + x^400 + x^399 + x^398 + x^396 + x^393 + x^392 + x^391 + x^390 + x^389 + x^385 + x^382 + x^381 + x^380 + x^379 + x^378 + x^375 + x^373 + x^372 + x^367 + x^366 + x^362 + x^358 + x^356 + x^355 + x^354 + x^353 + x^349 + x^348 + x^347 + x^342 + x^340 + x^339 + x^336 + x^334 + x^331 + x^329 + x^328 + x^327 + x^326 + x^325 + x^323 + x^319 + x^317 + x^316 + x^314 + x^313 + x^312 + x^310 + x^309 + x^308 + x^307 + x^302 + x^299 + x^298 + x^297 + x^296 + x^293 + x^291 + x^289 + x^288 + x^286 + x^285 + x^284 + x^282 + x^279 + x^274 + x^272 + x^271 + x^268 + x^266 + x^263 + x^261 + x^258 + x^255 + x^252 + x^251 + x^249 + x^248 + x^247 + x^246 + x^243 + x^242 + x^240 + x^237 + x^236 + x^234 + x^233 + x^232 + x^231 + x^228 + x^226 + x^223 + x^222 + x^221 + x^220 + x^219 + x^217 + x^216 + x^215 + x^213 + x^212 + x^210 + x^205 + x^203 + x^202 + x^199 + x^197 + x^195 + x^194 + x^193 + x^191 + x^189 + x^188 + x^187 + x^184 + x^182 + x^178 + x^173 + x^172 + x^170 + x^169 + x^167 + x^165 + x^162 + x^159 + x^158 + x^157 + x^156 + x^154 + x^149 + x^148 + x^145 + x^144 + x^141 + x^140 + x^135 + x^134 + x^133 + x^131 + x^130 + x^129 + x^127 + x^126 + x^123 + x^120 + x^119 + x^118 + x^117 + x^115 + x^110 + x^108 + x^106 + x^105 + x^104 + x^99 + x^97 + x^95 + x^89 + x^86 + x^84 + x^82 + x^78 + x^75 + x^71 + x^70 + x^69 + x^68 + x^65 + x^63 + x^62 + x^61 + x^59 + x^58 + x^51 + x^50 + x^49 + x^48 + x^47 + x^44 + x^43 + x^42 + x^39 + x^38 + x^37 + x^35 + x^30 + x^27 + x^25 + x^21 + x^19 + x^17 + x^16 + x^13 + x^12 + x^10 + x^8 + x^6 + 1
+
+56-43-35 433 x^928 + x^898 + x^896 + x^871 + x^870 + x^864 + x^848 + x^847 + x^846 + x^841 + x^840 + x^834 + x^833 + x^832 + x^829 + x^821 + x^814 + x^811 + x^808 + x^806 + x^803 + x^798 + x^797 + x^796 + x^792 + x^788 + x^786 + x^784 + x^783 + x^781 + x^779 + x^777 + x^776 + x^774 + x^773 + x^770 + x^769 + x^766 + x^762 + x^760 + x^756 + x^754 + x^752 + x^751 + x^749 + x^746 + x^745 + x^740 + x^737 + x^736 + x^734 + x^730 + x^727 + x^723 + x^721 + x^720 + x^718 + x^716 + x^714 + x^712 + x^709 + x^707 + x^706 + x^705 + x^704 + x^703 + x^702 + x^701 + x^700 + x^699 + x^697 + x^696 + x^695 + x^690 + x^689 + x^687 + x^685 + x^684 + x^682 + x^678 + x^675 + x^672 + x^670 + x^669 + x^668 + x^666 + x^665 + x^663 + x^662 + x^661 + x^659 + x^657 + x^655 + x^651 + x^650 + x^648 + x^646 + x^641 + x^639 + x^634 + x^632 + x^631 + x^630 + x^629 + x^626 + x^625 + x^623 + x^620 + x^619 + x^614 + x^612 + x^610 + x^609 + x^608 + x^607 + x^606 + x^604 + x^603 + x^602 + x^601 + x^600 + x^597 + x^596 + x^595 + x^594 + x^593 + x^591 + x^588 + x^585 + x^584 + x^583 + x^582 + x^581 + x^580 + x^578 + x^576 + x^574 + x^573 + x^572 + x^571 + x^570 + x^569 + x^563 + x^561 + x^560 + x^558 + x^556 + x^553 + x^552 + x^551 + x^550 + x^549 + x^546 + x^545 + x^544 + x^543 + x^542 + x^539 + x^538 + x^537 + x^536 + x^534 + x^532 + x^531 + x^529 + x^523 + x^519 + x^518 + x^517 + x^515 + x^514 + x^513 + x^512 + x^510 + x^509 + x^508 + x^503 + x^502 + x^501 + x^500 + x^499 + x^498 + x^496 + x^495 + x^494 + x^491 + x^490 + x^489 + x^487 + x^486 + x^484 + x^482 + x^481 + x^473 + x^471 + x^468 + x^466 + x^465 + x^464 + x^461 + x^460 + x^457 + x^456 + x^455 + x^453 + x^450 + x^448 + x^444 + x^442 + x^436 + x^435 + x^434 + x^433 + x^432 + x^431 + x^430 + x^429 + x^422 + x^421 + x^420 + x^419 + x^418 + x^417 + x^416 + x^414 + x^413 + x^412 + x^411 + x^409 + x^408 + x^407 + x^406 + x^404 + x^403 + x^402 + x^401 + x^398 + x^395 + x^392 + x^391 + x^389 + x^387 + x^385 + x^380 + x^377 + x^374 + x^372 + x^371 + x^369 + x^366 + x^363 + x^362 + x^361 + x^359 + x^358 + x^356 + x^355 + x^354 + x^353 + x^352 + x^350 + x^349 + x^348 + x^347 + x^345 + x^344 + x^343 + x^336 + x^334 + x^331 + x^330 + x^327 + x^325 + x^324 + x^322 + x^317 + x^310 + x^308 + x^307 + x^304 + x^301 + x^300 + x^299 + x^298 + x^297 + x^293 + x^290 + x^286 + x^284 + x^283 + x^282 + x^281 + x^279 + x^277 + x^275 + x^274 + x^270 + x^269 + x^267 + x^264 + x^262 + x^259 + x^254 + x^253 + x^248 + x^247 + x^245 + x^243 + x^242 + x^241 + x^237 + x^236 + x^232 + x^231 + x^230 + x^229 + x^228 + x^226 + x^225 + x^224 + x^223 + x^221 + x^218 + x^215 + x^214 + x^213 + x^212 + x^210 + x^208 + x^204 + x^202 + x^201 + x^199 + x^196 + x^195 + x^193 + x^192 + x^191 + x^190 + x^186 + x^184 + x^179 + x^178 + x^177 + x^176 + x^175 + x^174 + x^173 + x^171 + x^169 + x^167 + x^166 + x^165 + x^160 + x^158 + x^155 + x^154 + x^153 + x^152 + x^151 + x^150 + x^149 + x^148 + x^147 + x^145 + x^143 + x^140 + x^139 + x^138 + x^134 + x^132 + x^130 + x^129 + x^128 + x^127 + x^120 + x^118 + x^117 + x^115 + x^113 + x^112 + x^109 + x^108 + x^107 + x^106 + x^105 + x^101 + x^100 + x^96 + x^95 + x^94 + x^93 + x^91 + x^89 + x^88 + x^87 + x^85 + x^84 + x^83 + x^82 + x^81 + x^79 + x^77 + x^75 + x^74 + x^73 + x^72 + x^70 + x^68 + x^67 + x^65 + x^64 + x^63 + x^60 + x^58 + x^57 + x^56 + x^54 + x^53 + x^52 + x^50 + x^45 + x^44 + x^43 + x^41 + x^35 + x^30 + x^23 + x^20 + x^18 + x^15 + x^6 + 1
+
+44-9-45 441 x^928 + x^898 + x^890 + x^885 + x^880 + x^872 + x^870 + x^867 + x^860 + x^850 + x^847 + x^842 + x^837 + x^834 + x^830 + x^825 + x^824 + x^817 + x^816 + x^811 + x^808 + x^806 + x^802 + x^800 + x^798 + x^797 + x^794 + x^792 + x^790 + x^787 + x^786 + x^782 + x^778 + x^777 + x^776 + x^774 + x^773 + x^772 + x^771 + x^769 + x^768 + x^767 + x^765 + x^760 + x^759 + x^758 + x^757 + x^754 + x^750 + x^749 + x^747 + x^746 + x^745 + x^743 + x^741 + x^738 + x^737 + x^736 + x^734 + x^732 + x^725 + x^724 + x^722 + x^721 + x^720 + x^717 + x^716 + x^714 + x^713 + x^710 + x^708 + x^707 + x^705 + x^704 + x^702 + x^701 + x^699 + x^698 + x^696 + x^694 + x^692 + x^691 + x^690 + x^686 + x^683 + x^681 + x^679 + x^676 + x^674 + x^673 + x^672 + x^671 + x^668 + x^667 + x^665 + x^664 + x^663 + x^662 + x^661 + x^659 + x^658 + x^657 + x^655 + x^654 + x^652 + x^651 + x^648 + x^644 + x^643 + x^641 + x^640 + x^635 + x^634 + x^633 + x^632 + x^631 + x^630 + x^629 + x^628 + x^624 + x^621 + x^619 + x^618 + x^617 + x^616 + x^614 + x^611 + x^610 + x^608 + x^607 + x^599 + x^598 + x^596 + x^594 + x^590 + x^589 + x^588 + x^587 + x^586 + x^584 + x^581 + x^579 + x^578 + x^577 + x^575 + x^573 + x^572 + x^570 + x^569 + x^568 + x^567 + x^565 + x^564 + x^563 + x^562 + x^561 + x^559 + x^558 + x^554 + x^553 + x^552 + x^551 + x^549 + x^546 + x^544 + x^541 + x^537 + x^536 + x^535 + x^532 + x^531 + x^529 + x^526 + x^517 + x^516 + x^514 + x^511 + x^509 + x^507 + x^502 + x^501 + x^498 + x^497 + x^495 + x^494 + x^493 + x^491 + x^487 + x^486 + x^485 + x^484 + x^483 + x^482 + x^481 + x^480 + x^477 + x^474 + x^473 + x^470 + x^469 + x^467 + x^466 + x^465 + x^463 + x^462 + x^461 + x^460 + x^459 + x^457 + x^455 + x^454 + x^453 + x^451 + x^449 + x^448 + x^446 + x^443 + x^442 + x^440 + x^437 + x^436 + x^435 + x^434 + x^433 + x^431 + x^430 + x^427 + x^423 + x^419 + x^418 + x^414 + x^412 + x^411 + x^410 + x^409 + x^407 + x^406 + x^405 + x^402 + x^397 + x^395 + x^394 + x^389 + x^388 + x^384 + x^381 + x^380 + x^379 + x^378 + x^376 + x^373 + x^372 + x^371 + x^370 + x^368 + x^367 + x^366 + x^365 + x^364 + x^362 + x^361 + x^355 + x^354 + x^352 + x^350 + x^347 + x^345 + x^344 + x^343 + x^342 + x^339 + x^337 + x^335 + x^333 + x^332 + x^329 + x^327 + x^323 + x^322 + x^321 + x^320 + x^319 + x^316 + x^312 + x^310 + x^309 + x^308 + x^307 + x^305 + x^303 + x^302 + x^301 + x^298 + x^294 + x^293 + x^283 + x^282 + x^276 + x^275 + x^274 + x^271 + x^267 + x^264 + x^262 + x^261 + x^259 + x^258 + x^257 + x^256 + x^253 + x^252 + x^251 + x^250 + x^246 + x^245 + x^244 + x^243 + x^242 + x^241 + x^240 + x^238 + x^237 + x^236 + x^235 + x^233 + x^232 + x^229 + x^228 + x^225 + x^224 + x^223 + x^220 + x^216 + x^211 + x^210 + x^207 + x^205 + x^204 + x^202 + x^201 + x^200 + x^197 + x^196 + x^195 + x^194 + x^190 + x^189 + x^185 + x^183 + x^182 + x^181 + x^180 + x^179 + x^177 + x^176 + x^174 + x^173 + x^172 + x^171 + x^168 + x^167 + x^164 + x^163 + x^157 + x^156 + x^152 + x^151 + x^150 + x^148 + x^147 + x^146 + x^143 + x^142 + x^141 + x^140 + x^139 + x^138 + x^137 + x^135 + x^134 + x^133 + x^132 + x^129 + x^128 + x^127 + x^125 + x^122 + x^120 + x^119 + x^113 + x^112 + x^110 + x^109 + x^108 + x^107 + x^106 + x^105 + x^104 + x^101 + x^98 + x^97 + x^96 + x^93 + x^92 + x^91 + x^87 + x^83 + x^80 + x^78 + x^77 + x^74 + x^72 + x^66 + x^64 + x^63 + x^60 + x^59 + x^56 + x^51 + x^50 + x^49 + x^46 + x^43 + x^42 + x^41 + x^39 + x^38 + x^32 + x^31 + x^29 + x^28 + x^26 + x^24 + x^23 + x^21 + x^20 + x^19 + x^18 + x^15 + x^10 + 1
diff --git a/lib/stdlib/test/re_SUITE.erl b/lib/stdlib/test/re_SUITE.erl
index 7b82647416..c9ef9da990 100644
--- a/lib/stdlib/test/re_SUITE.erl
+++ b/lib/stdlib/test/re_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/test/re_SUITE_data/testoutput2 b/lib/stdlib/test/re_SUITE_data/testoutput2
index 811bbefc84..61ed8d9d4e 100644
--- a/lib/stdlib/test/re_SUITE_data/testoutput2
+++ b/lib/stdlib/test/re_SUITE_data/testoutput2
@@ -14705,4 +14705,20 @@ No options
No first char
No need char
+"(?<=(a))\1?b"
+ ab
+ 0: b
+ 1: a
+ aaab
+ 0: ab
+ 1: a
+
+"(?=(a))\1?b"
+ ab
+ 0: ab
+ 1: a
+ aaab
+ 0: ab
+ 1: a
+
/-- End of testinput2 --/
diff --git a/lib/stdlib/test/re_SUITE_data/testoutput5 b/lib/stdlib/test/re_SUITE_data/testoutput5
index bab989ca7e..090e1e1c85 100644
--- a/lib/stdlib/test/re_SUITE_data/testoutput5
+++ b/lib/stdlib/test/re_SUITE_data/testoutput5
@@ -1942,4 +1942,12 @@ Need char = 'z'
0: \x{17f}
0+
+/\C[^\v]+\x80/8
+ [AΏBŀC]
+No match
+
+/\C[^\d]+\x80/8
+ [AΏBŀC]
+No match
+
/-- End of testinput5 --/
diff --git a/lib/stdlib/test/sets_SUITE.erl b/lib/stdlib/test/sets_SUITE.erl
index bec38000b2..2c1b388d52 100644
--- a/lib/stdlib/test/sets_SUITE.erl
+++ b/lib/stdlib/test/sets_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -28,7 +28,7 @@
init_per_testcase/2,end_per_testcase/2,
create/1,add_element/1,del_element/1,
subtract/1,intersection/1,union/1,is_subset/1,
- is_set/1,fold/1,filter/1,
+ is_set/1,is_empty/1,fold/1,filter/1,
take_smallest/1,take_largest/1, iterate/1]).
-include_lib("common_test/include/ct.hrl").
@@ -48,7 +48,7 @@ suite() ->
all() ->
[create, add_element, del_element, subtract,
intersection, union, is_subset, is_set, fold, filter,
- take_smallest, take_largest, iterate].
+ take_smallest, take_largest, iterate, is_empty].
groups() ->
[].
@@ -345,6 +345,17 @@ is_set_1(M) ->
false = M(is_set, {}),
M(empty, []).
+is_empty(Config) when is_list(Config) ->
+ test_all(fun is_empty_1/1).
+
+is_empty_1(M) ->
+ S = M(from_list, [blurf]),
+ Empty = M(empty, []),
+
+ true = M(is_empty, Empty),
+ false = M(is_empty, S),
+ M(empty, []).
+
fold(Config) when is_list(Config) ->
test_all([{0,71},{125,129},{254,259},{510,513},{1023,1025},{9999,10001}],
fun fold_1/2).
diff --git a/lib/stdlib/test/sets_test_lib.erl b/lib/stdlib/test/sets_test_lib.erl
index 9f153822a2..e4d476ba54 100644
--- a/lib/stdlib/test/sets_test_lib.erl
+++ b/lib/stdlib/test/sets_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,7 +32,7 @@ new(Mod, Eq) ->
(from_list, L) -> Mod:from_list(L);
(intersection, {S1,S2}) -> intersection(Mod, Eq, S1, S2);
(intersection, Ss) -> intersection(Mod, Eq, Ss);
- (is_empty, S) -> is_empty(Mod, S);
+ (is_empty, S) -> Mod:is_empty(S);
(is_set, S) -> Mod:is_set(S);
(is_subset, {S,Set}) -> is_subset(Mod, Eq, S, Set);
(iterator, S) -> Mod:iterator(S);
@@ -56,7 +56,7 @@ singleton(Mod, E) ->
add_element(Mod, El, S0) ->
S = Mod:add_element(El, S0),
true = Mod:is_element(El, S),
- false = is_empty(Mod, S),
+ false = Mod:is_empty(S),
true = Mod:is_set(S),
S.
@@ -66,17 +66,10 @@ del_element(Mod, El, S0) ->
true = Mod:is_set(S),
S.
-is_empty(Mod, S) ->
- true = Mod:is_set(S),
- case erlang:function_exported(Mod, is_empty, 1) of
- true -> Mod:is_empty(S);
- false -> Mod:size(S) == 0
- end.
-
intersection(Mod, Equal, S1, S2) ->
S = Mod:intersection(S1, S2),
true = Equal(S, Mod:intersection(S2, S1)),
- Disjoint = is_empty(Mod, S),
+ Disjoint = Mod:is_empty(S),
Disjoint = Mod:is_disjoint(S1, S2),
Disjoint = Mod:is_disjoint(S2, S1),
S.
diff --git a/lib/stdlib/test/shell_SUITE.erl b/lib/stdlib/test/shell_SUITE.erl
index ca85314775..cdb6031b07 100644
--- a/lib/stdlib/test/shell_SUITE.erl
+++ b/lib/stdlib/test/shell_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -2591,7 +2591,7 @@ otp_7184(Config) when is_list(Config) ->
otp_7232(Config) when is_list(Config) ->
Info = <<"qlc:info(qlc:sort(qlc:q([X || X <- [55296,56296]]), "
"{order, fun(A,B)-> A>B end})).">>,
- "qlc:sort([55296,56296],\n"
+ "qlc:sort([55296, 56296],\n"
" [{order,\n"
" fun(A, B) ->\n"
" A > B\n"
@@ -2752,7 +2752,7 @@ otp_10302(Config) when is_list(Config) ->
h().">>,
"ok.\n\"\x{400}\"\nA = \"\x{400}\".\nok.\n"
- "1: io:setopts([{encoding,utf8}])\n-> ok.\n"
+ "1: io:setopts([{encoding, utf8}])\n-> ok.\n"
"2: A = [1024] = \"\x{400}\"\n-> \"\x{400}\"\n"
"3: b()\n-> ok.\nok.\n" = t({Node,Test4}),
@@ -2780,7 +2780,7 @@ otp_10302(Config) when is_list(Config) ->
rpc:call(Node,shell, prompt_func, [default]),
_ = shell:prompt_func(default),
- %% Test lib:format_exception() (cf. OTP-6554)
+ %% Test erl_error:format_exception() (cf. OTP-6554)
Test6 =
<<"begin
A = <<\"\\xaa\">>,
@@ -2967,10 +2967,10 @@ otp_14296(Config) when is_list(Config) ->
R = t(S)
end(),
- %% Test lib:extended_parse_term/1
+ %% Test erl_eval:extended_parse_term/1
TF = fun(S) ->
{ok, Ts, _} = erl_scan:string(S++".", 1, [text]),
- case lib:extended_parse_term(Ts) of
+ case erl_eval:extended_parse_term(Ts) of
{ok, Term} -> Term;
{error, _}=Error -> Error
end
diff --git a/lib/stdlib/test/stdlib.spec b/lib/stdlib/test/stdlib.spec
index 3768e494b2..bf64eae2c7 100644
--- a/lib/stdlib/test/stdlib.spec
+++ b/lib/stdlib/test/stdlib.spec
@@ -1 +1,7 @@
{suites,"../stdlib_test",all}.
+{skip_groups,"../stdlib_test",stdlib_bench_SUITE,
+ [binary,base64,gen_server,gen_statem,unicode],
+ "Benchmark only"}.
+{skip_groups,"../stdlib_test",ets_SUITE,
+ [benchmark],
+ "Benchmark only"}.
diff --git a/lib/stdlib/test/stdlib_bench.spec b/lib/stdlib/test/stdlib_bench.spec
new file mode 100644
index 0000000000..6d665f22b6
--- /dev/null
+++ b/lib/stdlib/test/stdlib_bench.spec
@@ -0,0 +1,11 @@
+%% Needed to compile ,unicode_util_SUITE and string_SUITE...
+{cases,"../stdlib_test",unicode_util_SUITE, []}.
+{cases,"../stdlib_test",string_SUITE, []}.
+{skip_suites,"../stdlib_test",unicode_util_SUITE, "bench only"}.
+{skip_suites,"../stdlib_test",string_SUITE, "bench only"}.
+
+{suites,"../stdlib_test",[stdlib_bench_SUITE]}.
+{skip_groups,"../stdlib_test",stdlib_bench_SUITE,
+ [gen_server_comparison,gen_statem_comparison],
+ "Not a benchmark"}.
+{groups,"../stdlib_test",ets_SUITE,[benchmark]}.
diff --git a/lib/stdlib/test/stdlib_bench_SUITE.erl b/lib/stdlib/test/stdlib_bench_SUITE.erl
new file mode 100644
index 0000000000..3456442088
--- /dev/null
+++ b/lib/stdlib/test/stdlib_bench_SUITE.erl
@@ -0,0 +1,592 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+-module(stdlib_bench_SUITE).
+-compile([export_all, nowarn_export_all]).
+-include_lib("common_test/include/ct.hrl").
+-include_lib("common_test/include/ct_event.hrl").
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+suite() -> [{ct_hooks,[{ts_install_cth,[{nodenames,2}]}]}].
+
+
+all() ->
+ [{group,unicode},{group,base64},{group,binary},
+ {group,gen_server},{group,gen_statem},
+ {group,gen_server_comparison},{group,gen_statem_comparison}].
+
+groups() ->
+ [{unicode,[{repeat,5}],
+ [norm_nfc_list, norm_nfc_deep_l, norm_nfc_binary,
+ string_lexemes_list, string_lexemes_binary
+ ]},
+ %% Only run 1 binary match repeat as it is very slow pre OTP-22.
+ %% The results seem to be stable enough anyway
+ {binary, [{repeat, 1}],
+ [match_single_pattern_no_match,
+ matches_single_pattern_no_match,
+ matches_single_pattern_eventual_match,
+ matches_single_pattern_frequent_match]},
+ {base64,[{repeat,5}],
+ [decode_binary, decode_binary_to_string,
+ decode_list, decode_list_to_string,
+ encode_binary, encode_binary_to_string,
+ encode_list, encode_list_to_string,
+ mime_binary_decode, mime_binary_decode_to_string,
+ mime_list_decode, mime_list_decode_to_string]},
+ {gen_server, [{repeat,5}], cases(gen_server)},
+ {gen_statem, [{repeat,3}], cases(gen_statem)},
+ {gen_server_comparison, [],
+ [single_small, single_medium, single_big,
+ sched_small, sched_medium, sched_big,
+ multi_small, multi_medium, multi_big]},
+ {gen_statem_comparison, [],
+ [single_small, single_big,
+ sched_small, sched_big,
+ multi_small, multi_big]}].
+
+cases(gen_server) ->
+ [simple, simple_timer, simple_mon, simple_timer_mon,
+ generic, generic_timer];
+cases(gen_statem) ->
+ [generic, generic_log, generic_log100, generic_fsm, generic_fsm_transit,
+ generic_statem, generic_statem_log, generic_statem_log100,
+ generic_statem_transit, generic_statem_complex].
+
+init_per_group(gen_server, Config) ->
+ compile_servers(Config),
+ [{benchmark_suite,"stdlib_gen_server"}|Config];
+init_per_group(gen_statem, Config) ->
+ compile_servers(Config),
+ [{benchmark_suite,"stdlib_gen_statem"}|Config];
+init_per_group(gen_server_comparison, Config) ->
+ compile_servers(Config),
+ [{cases,cases(gen_server)},
+ {benchmark_suite,"stdlib_gen_server"}|Config];
+init_per_group(gen_statem_comparison, Config) ->
+ compile_servers(Config),
+ [{cases,cases(gen_statem)},
+ {benchmark_suite,"stdlib_gen_statem"}|Config];
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(Config) ->
+ Config.
+
+init_per_testcase(_Func, Conf) ->
+ Conf.
+
+end_per_testcase(_Func, _Conf) ->
+ ok.
+
+
+compile_servers(Config) ->
+ DataDir = ?config(data_dir, Config),
+ Files = filelib:wildcard(filename:join(DataDir, "{simple,generic}*.erl")),
+ _ = [{ok, _} = compile:file(File) || File <- Files],
+ ok.
+
+comment(Value) ->
+ C = lists:flatten(io_lib:format("~p", [Value])),
+ {comment, C}.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-define(REPEAT_NORM, 5).
+
+norm_nfc_list(Config) ->
+ Bin = norm_data(Config),
+ {_N, Mean, _Stddev, Res} = unicode_util_SUITE:time_count(nfc, list, Bin, ?REPEAT_NORM),
+ comment(report(1000.0*Res / Mean)).
+
+norm_nfc_deep_l(Config) ->
+ Bin = norm_data(Config),
+ {_N, Mean, _Stddev, Res} = unicode_util_SUITE:time_count(nfc, deep_l, Bin, ?REPEAT_NORM),
+ comment(report(1000.0*Res / Mean)).
+
+norm_nfc_binary(Config) ->
+ Bin = norm_data(Config),
+ {_N, Mean, _Stddev, Res} = unicode_util_SUITE:time_count(nfc, binary, Bin, ?REPEAT_NORM),
+ comment(report(1000.0*Res / Mean)).
+
+
+string_lexemes_list(Config) ->
+ %% Use nth_lexeme instead of lexemes to avoid building a result of
+ %% large lists which causes large differences between test runs, gc?
+ Bin = norm_data(Config),
+ Fun = fun(Str) -> string:nth_lexeme(Str, 200000, [$;,$\n,$\r]), 200000 end,
+ {_N, Mean, _Stddev, Res} = string_SUITE:time_func(Fun, list, Bin, 15),
+ comment(report(1000.0*Res / Mean)).
+
+string_lexemes_binary(Config) ->
+ %% Use nth_lexeme instead of lexemes to avoid building a result of
+ %% large lists which causes large differences between test runs, gc?
+ Bin = norm_data(Config),
+ Fun = fun(Str) -> string:nth_lexeme(Str, 200000, [$;,$\n,$\r]), 200000 end,
+ {_N, Mean, _Stddev, Res} = string_SUITE:time_func(Fun, binary, Bin, ?REPEAT_NORM),
+ comment(report(1000.0*Res / Mean)).
+
+%%%
+report(Tps) ->
+ ct_event:notify(#event{name = benchmark_data,
+ data = [{suite,"stdlib_unicode"},{value,round(Tps)}]}),
+ Tps.
+
+norm_data(Config) ->
+ DataDir0 = proplists:get_value(data_dir, Config),
+ DataDir = filename:join(lists:droplast(filename:split(DataDir0))),
+ File = filename:join([DataDir,"unicode_util_SUITE_data","NormalizationTest.txt"]),
+ {ok, Bin} = file:read_file(File),
+ Bin.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+match_single_pattern_no_match(_Config) ->
+ Binary = binary:copy(<<"ugbcfuysabfuqyfikgfsdalpaskfhgjsdgfjwsalp">>, 1000000),
+ comment(test(100, binary, match, [Binary, <<"o">>])).
+
+matches_single_pattern_no_match(_Config) ->
+ Binary = binary:copy(<<"ugbcfuysabfuqyfikgfsdalpaskfhgjsdgfjwsalp">>, 1000000),
+ comment(test(100, binary, matches, [Binary, <<"o">>])).
+
+matches_single_pattern_eventual_match(_Config) ->
+ Binary = binary:copy(<<"ugbcfuysabfuqyfikgfsdalpaskfhgjsdgfjwsal\n">>, 1000000),
+ comment(test(100, binary, matches, [Binary, <<"\n">>])).
+
+matches_single_pattern_frequent_match(_Config) ->
+ Binary = binary:copy(<<"abc\n">>, 1000000),
+ comment(test(100, binary, matches, [Binary, <<"abc">>])).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+decode_binary(_Config) ->
+ comment(test(base64, decode, [encoded_binary()])).
+
+decode_binary_to_string(_Config) ->
+ comment(test(base64, decode_to_string, [encoded_binary()])).
+
+decode_list(_Config) ->
+ comment(test(base64, decode, [encoded_list()])).
+
+decode_list_to_string(_Config) ->
+ comment(test(base64, decode_to_string, [encoded_list()])).
+
+encode_binary(_Config) ->
+ comment(test(base64, encode, [binary()])).
+
+encode_binary_to_string(_Config) ->
+ comment(test(base64, encode_to_string, [binary()])).
+
+encode_list(_Config) ->
+ comment(test(base64, encode, [list()])).
+
+encode_list_to_string(_Config) ->
+ comment(test(base64, encode_to_string, [list()])).
+
+mime_binary_decode(_Config) ->
+ comment(test(base64, mime_decode, [encoded_binary()])).
+
+mime_binary_decode_to_string(_Config) ->
+ comment(test(base64, mime_decode_to_string, [encoded_binary()])).
+
+mime_list_decode(_Config) ->
+ comment(test(base64, mime_decode, [encoded_list()])).
+
+mime_list_decode_to_string(_Config) ->
+ comment(test(base64, mime_decode_to_string, [encoded_list()])).
+
+-define(SIZE, 10000).
+-define(N, 1000).
+
+encoded_binary() ->
+ list_to_binary(encoded_list()).
+
+encoded_list() ->
+ L = random_byte_list(round(?SIZE*0.75)),
+ base64:encode_to_string(L).
+
+binary() ->
+ list_to_binary(list()).
+
+list() ->
+ random_byte_list(?SIZE).
+
+test(Mod, Fun, Args) ->
+ test(?N, Mod, Fun, Args).
+test(Iter, Mod, Fun, Args) ->
+ F = fun() -> loop(Iter, Mod, Fun, Args) end,
+ {Time, ok} = timer:tc(fun() -> lspawn(F) end),
+ report_mfa(Iter, Time, Mod).
+
+loop(0, _M, _F, _A) -> garbage_collect(), ok;
+loop(N, M, F, A) ->
+ _ = apply(M, F, A),
+ loop(N - 1, M, F, A).
+
+lspawn(Fun) ->
+ {Pid, Ref} = spawn_monitor(fun() -> exit(Fun()) end),
+ receive
+ {'DOWN', Ref, process, Pid, Rep} -> Rep
+ end.
+
+report_mfa(Iter, Time, Mod) ->
+ Tps = round((Iter*1000000)/Time),
+ ct_event:notify(#event{name = benchmark_data,
+ data = [{suite, "stdlib_" ++ atom_to_list(Mod)},
+ {value, Tps}]}),
+ Tps.
+
+%% Copied from base64_SUITE.erl.
+
+random_byte_list(N) ->
+ random_byte_list(N, []).
+
+random_byte_list(0, Acc) ->
+ Acc;
+random_byte_list(N, Acc) ->
+ random_byte_list(N-1, [rand:uniform(255)|Acc]).
+
+make_big_binary(N) ->
+ list_to_binary(mbb(N, [])).
+
+mbb(N, Acc) when N > 256 ->
+ B = list_to_binary(lists:seq(0, 255)),
+ mbb(N - 256, [B | Acc]);
+mbb(N, Acc) ->
+ B = list_to_binary(lists:seq(0, N-1)),
+ lists:reverse(Acc, B).
+
+simple(Config) when is_list(Config) ->
+ comment(do_tests(simple, single_small, Config)).
+
+simple_timer(Config) when is_list(Config) ->
+ comment(do_tests(simple_timer, single_small, Config)).
+
+simple_mon(Config) when is_list(Config) ->
+ comment(do_tests(simple_mon, single_small, Config)).
+
+simple_timer_mon(Config) when is_list(Config) ->
+ comment(do_tests(simple_timer_mon, single_small, Config)).
+
+generic(Config) when is_list(Config) ->
+ comment(do_tests(generic, single_small, Config)).
+
+generic_log(Config) when is_list(Config) ->
+ comment(do_tests(generic_log, single_small, Config)).
+
+generic_log100(Config) when is_list(Config) ->
+ comment(do_tests(generic_log100, single_small, Config)).
+
+generic_timer(Config) when is_list(Config) ->
+ comment(do_tests(generic_timer, single_small, Config)).
+
+generic_statem(Config) when is_list(Config) ->
+ comment(do_tests(generic_statem, single_small, Config)).
+
+generic_statem_log(Config) when is_list(Config) ->
+ comment(do_tests(generic_statem_log, single_small, Config)).
+
+generic_statem_log100(Config) when is_list(Config) ->
+ comment(do_tests(generic_statem_log100, single_small, Config)).
+
+generic_statem_transit(Config) when is_list(Config) ->
+ comment(do_tests(generic_statem_transit, single_small, Config)).
+
+generic_statem_complex(Config) when is_list(Config) ->
+ comment(do_tests(generic_statem_complex, single_small, Config)).
+
+generic_fsm(Config) when is_list(Config) ->
+ comment(do_tests(generic_fsm, single_small, Config)).
+
+generic_fsm_transit(Config) when is_list(Config) ->
+ comment(do_tests(generic_fsm_transit, single_small, Config)).
+
+single_small(Config) when is_list(Config) ->
+ comparison(?config(cases, Config), single_small, Config).
+
+single_medium(Config) when is_list(Config) ->
+ comparison(?config(cases, Config), single_medium, Config).
+
+single_big(Config) when is_list(Config) ->
+ comparison(?config(cases, Config), single_big, Config).
+
+sched_small(Config) when is_list(Config) ->
+ comparison(?config(cases, Config), sched_small, Config).
+
+sched_medium(Config) when is_list(Config) ->
+ comparison(?config(cases, Config), sched_medium, Config).
+
+sched_big(Config) when is_list(Config) ->
+ comparison(?config(cases, Config), sched_big, Config).
+
+multi_small(Config) when is_list(Config) ->
+ comparison(?config(cases, Config), multi_small, Config).
+
+multi_medium(Config) when is_list(Config) ->
+ comparison(?config(cases, Config), multi_medium, Config).
+
+multi_big(Config) when is_list(Config) ->
+ comparison(?config(cases, Config), multi_big, Config).
+
+comparison(Cases, Kind, Config) ->
+ Cases = ?config(cases, Config),
+ [RefResult|_] = Results =
+ [do_tests(Case, Kind, Config) || Case <- Cases],
+ Normalized = [norm(Result, RefResult) || Result <- Results],
+ {Parallelism, Message} = bench_params(Kind),
+ Wordsize = erlang:system_info(wordsize),
+ MSize = Wordsize * erts_debug:flat_size(Message),
+ What = io_lib:format("#parallel gen_server instances: ~.4w, "
+ "message flat size: ~.5w bytes",
+ [Parallelism, MSize]),
+ Format =
+ lists:flatten(
+ ["~s: "] ++
+ [[atom_to_list(Case),": ~s "] || Case <- Cases]),
+ C = lists:flatten(io_lib:format(Format, [What] ++ Normalized)),
+ {comment, C}.
+
+norm(T, Ref) ->
+ try Ref / T of
+ Norm ->
+ io_lib:format("~.2f", [Norm])
+ catch error:badarith ->
+ "---"
+ end.
+
+-define(MAX_TIME_SECS, 3). % s
+-define(MAX_TIME, 1000 * ?MAX_TIME_SECS). % ms
+-define(CALLS_PER_LOOP, 5).
+
+do_tests(Test, ParamSet, Config) ->
+ BenchmarkSuite = ?config(benchmark_suite, Config),
+ {Client, ServerMod, ServerArg} = bench(Test),
+ {Parallelism, Message} = bench_params(ParamSet),
+ Fun = create_clients(Message, ServerMod, ServerArg, Client, Parallelism),
+ {TotalLoops, AllPidTime} = run_test(Fun),
+ try ?CALLS_PER_LOOP * round((1000 * TotalLoops) / AllPidTime) of
+ PerSecond ->
+ ct_event:notify(
+ #event{
+ name = benchmark_data,
+ data = [{suite,BenchmarkSuite},{value,PerSecond}]}),
+ PerSecond
+ catch error:badarith ->
+ "Time measurement is not working"
+ end.
+
+-define(COUNTER, n).
+
+simple_client(N, M, P) ->
+ put(?COUNTER, N),
+ _ = simple_server:reply(P, M),
+ _ = simple_server:reply(P, M),
+ _ = simple_server:reply(P, M),
+ _ = simple_server:reply(P, M),
+ _ = simple_server:reply(P, M),
+ simple_client(N+1, M, P).
+
+simple_client_timer(N, M, P) ->
+ put(?COUNTER, N),
+ _ = simple_server_timer:reply(P, M),
+ _ = simple_server_timer:reply(P, M),
+ _ = simple_server_timer:reply(P, M),
+ _ = simple_server_timer:reply(P, M),
+ _ = simple_server_timer:reply(P, M),
+ simple_client_timer(N+1, M, P).
+
+simple_client_mon(N, M, P) ->
+ put(?COUNTER, N),
+ _ = simple_server_mon:reply(P, M),
+ _ = simple_server_mon:reply(P, M),
+ _ = simple_server_mon:reply(P, M),
+ _ = simple_server_mon:reply(P, M),
+ _ = simple_server_mon:reply(P, M),
+ simple_client_mon(N+1, M, P).
+
+simple_client_timer_mon(N, M, P) ->
+ put(?COUNTER, N),
+ _ = simple_server_timer_mon:reply(P, M),
+ _ = simple_server_timer_mon:reply(P, M),
+ _ = simple_server_timer_mon:reply(P, M),
+ _ = simple_server_timer_mon:reply(P, M),
+ _ = simple_server_timer_mon:reply(P, M),
+ simple_client_timer_mon(N+1, M, P).
+
+generic_client(N, M, P) ->
+ put(?COUNTER, N),
+ _ = generic_server:reply(P, M),
+ _ = generic_server:reply(P, M),
+ _ = generic_server:reply(P, M),
+ _ = generic_server:reply(P, M),
+ _ = generic_server:reply(P, M),
+ generic_client(N+1, M, P).
+
+generic_timer_client(N, M, P) ->
+ put(?COUNTER, N),
+ _ = generic_server_timer:reply(P, M),
+ _ = generic_server_timer:reply(P, M),
+ _ = generic_server_timer:reply(P, M),
+ _ = generic_server_timer:reply(P, M),
+ _ = generic_server_timer:reply(P, M),
+ generic_timer_client(N+1, M, P).
+
+generic_statem_client(N, M, P) ->
+ put(?COUNTER, N),
+ _ = generic_statem:reply(P, M),
+ _ = generic_statem:reply(P, M),
+ _ = generic_statem:reply(P, M),
+ _ = generic_statem:reply(P, M),
+ _ = generic_statem:reply(P, M),
+ generic_statem_client(N+1, M, P).
+
+generic_statem_transit_client(N, M, P) ->
+ put(?COUNTER, N),
+ _ = generic_statem:transit(P, M),
+ _ = generic_statem:transit(P, M),
+ _ = generic_statem:transit(P, M),
+ _ = generic_statem:transit(P, M),
+ _ = generic_statem:transit(P, M),
+ generic_statem_transit_client(N+1, M, P).
+
+generic_statem_complex_client(N, M, P) ->
+ put(?COUNTER, N),
+ _ = generic_statem:reply(P, M),
+ _ = generic_statem:reply(P, M),
+ _ = generic_statem:reply(P, M),
+ _ = generic_statem:reply(P, M),
+ _ = generic_statem:reply(P, M),
+ generic_statem_complex_client(N+1, M, P).
+
+generic_fsm_client(N, M, P) ->
+ put(?COUNTER, N),
+ _ = generic_fsm:reply(P, M),
+ _ = generic_fsm:reply(P, M),
+ _ = generic_fsm:reply(P, M),
+ _ = generic_fsm:reply(P, M),
+ _ = generic_fsm:reply(P, M),
+ generic_fsm_client(N+1, M, P).
+
+generic_fsm_transit_client(N, M, P) ->
+ put(?COUNTER, N),
+ _ = generic_fsm:transit(P, M),
+ _ = generic_fsm:transit(P, M),
+ _ = generic_fsm:transit(P, M),
+ _ = generic_fsm:transit(P, M),
+ _ = generic_fsm:transit(P, M),
+ generic_fsm_transit_client(N+1, M, P).
+
+bench(simple) ->
+ {fun simple_client/3, simple_server, term};
+bench(simple_timer) ->
+ {fun simple_client_timer/3, simple_server_timer, term};
+bench(simple_mon) ->
+ {fun simple_client_mon/3, simple_server_mon, term};
+bench(simple_timer_mon) ->
+ {fun simple_client_timer_mon/3, simple_server_timer_mon, term};
+bench(generic) ->
+ {fun generic_client/3, generic_server, [term]};
+bench(generic_log) ->
+ {fun generic_client/3, generic_server, [term,{debug,[log]}]};
+bench(generic_log100) ->
+ {fun generic_client/3, generic_server, [term,{debug,[{log,100}]}]};
+bench(generic_timer) ->
+ {fun generic_timer_client/3, generic_server_timer, term};
+bench(generic_statem) ->
+ {fun generic_statem_client/3, generic_statem, [term]};
+bench(generic_statem_log) ->
+ {fun generic_statem_client/3, generic_statem, [term,{debug,[log]}]};
+bench(generic_statem_log100) ->
+ {fun generic_statem_client/3, generic_statem, [term,{debug,[{log,100}]}]};
+bench(generic_statem_transit) ->
+ {fun generic_statem_transit_client/3, generic_statem, [term]};
+bench(generic_statem_complex) ->
+ {fun generic_statem_complex_client/3, generic_statem_complex, term};
+bench(generic_fsm) ->
+ {fun generic_fsm_client/3, generic_fsm, term};
+bench(generic_fsm_transit) ->
+ {fun generic_fsm_transit_client/3, generic_fsm, term}.
+
+%% -> {Parallelism, MessageTerm}
+bench_params(single_small) -> {1, small()};
+bench_params(single_medium) -> {1, medium()};
+bench_params(single_big) -> {1, big()};
+bench_params(sched_small) -> {parallelism(), small()};
+bench_params(sched_medium) -> {parallelism(), medium()};
+bench_params(sched_big) -> {parallelism(), big()};
+bench_params(multi_small) -> {400, small()};
+bench_params(multi_medium) -> {400, medium()};
+bench_params(multi_big) -> {400, big()}.
+
+small() ->
+ small.
+
+medium() ->
+ lists:seq(1, 50).
+
+big() ->
+ lists:seq(1, 1000).
+
+parallelism() ->
+ case erlang:system_info(multi_scheduling) of
+ enabled -> erlang:system_info(schedulers_online);
+ _ -> 1
+ end.
+
+create_clients(M, ServerMod, ServerArg, Client, Parallel) ->
+ fun() ->
+ ServerPid = ServerMod:start(ServerArg),
+ PidRefs = [spawn_monitor(fun() -> Client(0, M, ServerPid) end) ||
+ _ <- lists:seq(1, Parallel)],
+ timer:sleep(?MAX_TIME),
+ try
+ AllPidsN = collect(PidRefs, []),
+ TotalLoops = lists:sum(AllPidsN),
+ TotalLoops
+ after
+ ok = ServerMod:stop(ServerPid)
+ end
+ end.
+
+collect([], Result) ->
+ Result;
+collect([{Pid, Ref}|PidRefs], Result) ->
+ N = case erlang:process_info(Pid, dictionary) of
+ {dictionary, Dict} ->
+ {?COUNTER, N0} = lists:keyfind(?COUNTER, 1, Dict),
+ N0;
+ undefined -> % Process did not start in ?MAX_TIME_SECS.
+ 0
+ end,
+ exit(Pid, kill),
+ receive {'DOWN', Ref, _, _, _} -> ok end,
+ collect(PidRefs, [N|Result]).
+
+run_test(Test) ->
+ {T1, _} = statistics(runtime),
+ Result = Test(),
+ {T2, _} = statistics(runtime),
+ {Result, T2 - T1}.
diff --git a/lib/stdlib/test/stdlib_bench_SUITE_data/generic_fsm.erl b/lib/stdlib/test/stdlib_bench_SUITE_data/generic_fsm.erl
new file mode 100644
index 0000000000..1abd9b1f2f
--- /dev/null
+++ b/lib/stdlib/test/stdlib_bench_SUITE_data/generic_fsm.erl
@@ -0,0 +1,59 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(generic_fsm).
+
+-export([start/1, reply/2, transit/2, stop/1]).
+
+-export([init/1, terminate/3]).
+-export([state1/3, state2/3]).
+
+-behaviour(gen_fsm).
+
+
+%% API
+
+start(Data) ->
+ {ok, Pid} = gen_fsm:start(?MODULE, Data, []),
+ Pid.
+
+stop(P) ->
+ ok = gen_fsm:stop(P).
+
+reply(S, M) ->
+ gen_fsm:sync_send_event(S, {reply, M}, infinity).
+
+transit(S, M) ->
+ gen_fsm:sync_send_event(S, {transit, M}, infinity).
+
+%% Implementation
+
+init(Data) ->
+ {ok, state1, Data}.
+
+terminate(_Reason, _State, _Data) ->
+ ok.
+
+state1({reply, M}, _From, Data) ->
+ {reply, M, ?FUNCTION_NAME, Data};
+state1({transit, M}, _From, Data) ->
+ {reply, M, state2, Data}.
+
+state2({transit, M}, _From, Data) ->
+ {reply, M, state1, Data}.
diff --git a/lib/stdlib/test/stdlib_bench_SUITE_data/generic_server.erl b/lib/stdlib/test/stdlib_bench_SUITE_data/generic_server.erl
new file mode 100644
index 0000000000..3707d00dee
--- /dev/null
+++ b/lib/stdlib/test/stdlib_bench_SUITE_data/generic_server.erl
@@ -0,0 +1,31 @@
+-module(generic_server).
+
+-export([start/1, reply/2, stop/1]).
+
+-export([handle_call/3, handle_cast/2, init/1, terminate/2]).
+
+-behaviour(gen_server).
+
+-define(GEN_SERVER, gen_server).
+
+start([State|Opts]) ->
+ {ok, Pid} = ?GEN_SERVER:start(?MODULE, State, Opts),
+ Pid.
+
+init(State) ->
+ {ok, State}.
+
+stop(P) ->
+ ok = ?GEN_SERVER:stop(P).
+
+reply(S, M) ->
+ _M = ?GEN_SERVER:call(S, {reply, M}, infinity).
+
+handle_call({reply, M}, _From, State) ->
+ {reply, M, State}.
+
+handle_cast(_Msg, State) ->
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
+ ok.
diff --git a/lib/stdlib/test/stdlib_bench_SUITE_data/generic_server_timer.erl b/lib/stdlib/test/stdlib_bench_SUITE_data/generic_server_timer.erl
new file mode 100644
index 0000000000..0faa30207d
--- /dev/null
+++ b/lib/stdlib/test/stdlib_bench_SUITE_data/generic_server_timer.erl
@@ -0,0 +1,31 @@
+-module(generic_server_timer).
+
+-export([start/1, reply/2, stop/1]).
+
+-export([handle_call/3, handle_cast/2, init/1, terminate/2]).
+
+-behaviour(gen_server).
+
+-define(GEN_SERVER, gen_server).
+
+start(State) ->
+ {ok, Pid} = ?GEN_SERVER:start(?MODULE, State, []),
+ Pid.
+
+init(State) ->
+ {ok, State}.
+
+stop(P) ->
+ ok = ?GEN_SERVER:stop(P).
+
+reply(S, M) ->
+ ?GEN_SERVER:call(S, {reply, M}).
+
+handle_call({reply, M}, _From, State) ->
+ {reply, M, State}.
+
+handle_cast(_Msg, State) ->
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
+ ok.
diff --git a/lib/stdlib/test/stdlib_bench_SUITE_data/generic_statem.erl b/lib/stdlib/test/stdlib_bench_SUITE_data/generic_statem.erl
new file mode 100644
index 0000000000..b106619568
--- /dev/null
+++ b/lib/stdlib/test/stdlib_bench_SUITE_data/generic_statem.erl
@@ -0,0 +1,60 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(generic_statem).
+
+-export([start/1, reply/2, transit/2, stop/1]).
+
+-export([callback_mode/0, init/1]).
+-export([state1/3, state2/3]).
+
+-behaviour(gen_statem).
+
+%% API
+
+start([Data|Opts]) ->
+ {ok, Pid} = gen_statem:start(?MODULE, Data, Opts),
+ Pid.
+
+stop(P) ->
+ ok = gen_statem:stop(P).
+
+reply(S, M) ->
+ gen_statem:call(S, {reply, M}, infinity).
+
+transit(S, M) ->
+ gen_statem:call(S, {transit, M}, infinity).
+
+%% Implementation
+
+callback_mode() ->
+ state_functions.
+
+init(Data) ->
+ {ok, state1, Data}.
+
+state1({call, From}, {reply, M}, Data) ->
+ {keep_state, Data, {reply, From, M}};
+state1({call, From}, {transit, M}, Data) ->
+ {next_state, state2, Data,
+ [{reply, From, M},{state_timeout,5000,5000}]}.
+
+state2({call, From}, {transit, M}, Data) ->
+ {next_state, state1, Data,
+ [{reply, From, M},{state_timeout,5000,5000}]}.
diff --git a/lib/stdlib/test/stdlib_bench_SUITE_data/generic_statem_complex.erl b/lib/stdlib/test/stdlib_bench_SUITE_data/generic_statem_complex.erl
new file mode 100644
index 0000000000..983227d281
--- /dev/null
+++ b/lib/stdlib/test/stdlib_bench_SUITE_data/generic_statem_complex.erl
@@ -0,0 +1,66 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(generic_statem_complex).
+
+-export([start/1, reply/2, stop/1]).
+
+-export([callback_mode/0, init/1]).
+-export([state1/3, state2/3, state3/3]).
+
+-behaviour(gen_statem).
+
+%% API
+
+start(Data) ->
+ {ok, Pid} = gen_statem:start(?MODULE, Data, []),
+ Pid.
+
+stop(P) ->
+ ok = gen_statem:stop(P).
+
+reply(S, M) ->
+ gen_statem:call(S, {reply, M}, infinity).
+
+%% Implementation
+
+callback_mode() ->
+ [state_functions,state_enter].
+
+init(Data) ->
+ {ok, state1, Data}.
+
+state1(enter, _, Data) ->
+ {keep_state, Data,
+ {state_timeout, 5000, t1}};
+state1({call, _From}, {reply, _M}, Data) ->
+ {next_state, state2, Data,
+ [postpone,{next_event,internal,e}]}.
+
+state2(enter, _, _Data) ->
+ keep_state_and_data;
+state2(internal, e, Data) ->
+ {next_state, state3, Data}.
+
+state3(enter, _, Data) ->
+ {keep_state, Data,
+ {state_timeout, 5000, t3}};
+state3({call, From}, {reply, M}, Data) ->
+ {next_state, state1, Data,
+ {reply, From, M}}.
diff --git a/lib/stdlib/test/stdlib_bench_SUITE_data/simple_server.erl b/lib/stdlib/test/stdlib_bench_SUITE_data/simple_server.erl
new file mode 100644
index 0000000000..bd43f686e8
--- /dev/null
+++ b/lib/stdlib/test/stdlib_bench_SUITE_data/simple_server.erl
@@ -0,0 +1,31 @@
+-module(simple_server).
+
+%% Local process. No timer. No monitor.
+
+-export([start/1, reply/2, stop/1]).
+
+start(State) ->
+ spawn(fun() -> loop(State) end).
+
+stop(P) ->
+ P ! {stop, self()},
+ receive
+ ok ->
+ ok
+ end.
+
+loop(S) ->
+ receive
+ {reply, P, M} ->
+ P ! M,
+ loop(S);
+ {stop, P} ->
+ P ! ok
+ end.
+
+reply(P, M) ->
+ P ! {reply, self(), M},
+ receive
+ M ->
+ M
+ end.
diff --git a/lib/stdlib/test/stdlib_bench_SUITE_data/simple_server_mon.erl b/lib/stdlib/test/stdlib_bench_SUITE_data/simple_server_mon.erl
new file mode 100644
index 0000000000..9b5ace5586
--- /dev/null
+++ b/lib/stdlib/test/stdlib_bench_SUITE_data/simple_server_mon.erl
@@ -0,0 +1,33 @@
+-module(simple_server_mon).
+
+%% Local process. No timer. Monitor.
+
+-export([start/1, reply/2, stop/1]).
+
+start(State) ->
+ spawn(fun() -> loop(State) end).
+
+stop(P) ->
+ P ! {stop, self()},
+ receive
+ ok ->
+ ok
+ end.
+
+loop(S) ->
+ receive
+ {reply, P, Mref, M} ->
+ P ! {ok, Mref, M},
+ loop(S);
+ {stop, P} ->
+ P ! ok
+ end.
+
+reply(P, M) ->
+ Mref = erlang:monitor(process, P),
+ P ! {reply, self(), Mref, M},
+ receive
+ {ok, Mref, M} ->
+ erlang:demonitor(Mref, [flush]),
+ ok
+ end.
diff --git a/lib/stdlib/test/stdlib_bench_SUITE_data/simple_server_timer.erl b/lib/stdlib/test/stdlib_bench_SUITE_data/simple_server_timer.erl
new file mode 100644
index 0000000000..82381e1fdf
--- /dev/null
+++ b/lib/stdlib/test/stdlib_bench_SUITE_data/simple_server_timer.erl
@@ -0,0 +1,33 @@
+-module(simple_server_timer).
+
+%% Local process. Timer. No monitor.
+
+-export([start/1, reply/2, stop/1]).
+
+start(State) ->
+ spawn(fun() -> loop(State) end).
+
+stop(P) ->
+ P ! {stop, self()},
+ receive
+ ok ->
+ ok
+ end.
+
+loop(S) ->
+ receive
+ {reply, P, M} ->
+ P ! M,
+ loop(S);
+ {stop, P} ->
+ P ! ok
+ end.
+
+reply(P, M) ->
+ P ! {reply, self(), M},
+ receive
+ M ->
+ M
+ after 100 ->
+ exit(fel)
+ end.
diff --git a/lib/stdlib/test/stdlib_bench_SUITE_data/simple_server_timer_mon.erl b/lib/stdlib/test/stdlib_bench_SUITE_data/simple_server_timer_mon.erl
new file mode 100644
index 0000000000..6124ca29c2
--- /dev/null
+++ b/lib/stdlib/test/stdlib_bench_SUITE_data/simple_server_timer_mon.erl
@@ -0,0 +1,35 @@
+-module(simple_server_timer_mon).
+
+%% Local process. Timer. Monitor.
+
+-export([start/1, reply/2, stop/1]).
+
+start(State) ->
+ spawn(fun() -> loop(State) end).
+
+stop(P) ->
+ P ! {stop, self()},
+ receive
+ ok ->
+ ok
+ end.
+
+loop(S) ->
+ receive
+ {reply, P, Mref, M} ->
+ P ! {ok, Mref, M},
+ loop(S);
+ {stop, P} ->
+ P ! ok
+ end.
+
+reply(P, M) ->
+ Mref = erlang:monitor(process, P),
+ P ! {reply, self(), Mref, M},
+ receive
+ {ok, Mref, M} ->
+ erlang:demonitor(Mref, [flush]),
+ ok
+ after 100 ->
+ exit(fel)
+ end.
diff --git a/lib/stdlib/test/string_SUITE.erl b/lib/stdlib/test/string_SUITE.erl
index 17714b8d4d..c9aadd7f10 100644
--- a/lib/stdlib/test/string_SUITE.erl
+++ b/lib/stdlib/test/string_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -47,7 +47,8 @@
-export([to_upper_to_lower/1]).
%% Run tests when debugging them
--export([debug/0]).
+-export([debug/0, time_func/4]).
+-compile([nowarn_deprecated_function]).
suite() ->
[{ct_hooks,[ts_install_cth]},
@@ -102,6 +103,15 @@ debug() ->
test(?LINE,?FUNCTION_NAME,B,C,D, false),
test(?LINE,?FUNCTION_NAME,hd(C),[B|tl(C)],D, false)).
+-define(TRY(Exp),
+ fun() ->
+ try Exp
+ catch _E:Reason:_ST ->
+ %% io:format("~p:~w: ~p: ~.0p ~p~n",
+ %% [?FUNCTION_NAME, ?LINE,_E,Reason, hd(_ST)]),
+ {'EXIT', Reason}
+ end
+ end()).
is_empty(_) ->
?TEST("", [], true),
@@ -125,6 +135,10 @@ length(_) ->
?TEST(["abc"|<<"abc">>], [], 6),
?TEST(["abc",["def"]], [], 6),
?TEST([<<97/utf8, 778/utf8, 98/utf8>>, [776,111,776]], [], 3), %% åäö in nfd
+
+ InvalidUTF8 = <<192,192>>,
+ {'EXIT', {badarg, _}} = ?TRY(string:length(InvalidUTF8)),
+ {'EXIT', {badarg, _}} = ?TRY(string:length(<<$a, InvalidUTF8/binary, $z>>)),
ok.
equal(_) ->
@@ -225,6 +239,8 @@ to_graphemes(_) ->
true = erlang:length(GCs) =:= erlang:length(string:to_graphemes(NFD)),
true = erlang:length(GCs) =:=
erlang:length(string:to_graphemes(unicode:characters_to_nfc_list(String))),
+
+ {'EXIT', {badarg, _}} = ?TRY(string:to_graphemes(<<$a,192,192,$z>>)),
ok.
reverse(_) ->
@@ -237,6 +253,11 @@ reverse(_) ->
?TEST(Str2, [], lists:reverse(Str2)),
?TEST(Str3, [], lists:reverse(Str3)),
true = string:reverse(Str3) =:= lists:reverse(string:to_graphemes(Str3)),
+
+ InvalidUTF8 = <<192,192>>,
+ {'EXIT', {badarg, _}} = ?TRY(string:reverse(InvalidUTF8)),
+ {'EXIT', {badarg, _}} = ?TRY(string:reverse(<<$a, InvalidUTF8/binary, $z>>)),
+
ok.
slice(_) ->
@@ -257,6 +278,14 @@ slice(_) ->
?TEST([<<"aå"/utf8>>,"äöbcd"], [3,3], "öbc"),
?TEST([<<"aåä"/utf8>>,"öbcd"], [3,10], "öbcd"),
+ InvalidUTF8 = <<192,192>>,
+ [$b, $c|InvalidUTF8] = string:slice(["abc", InvalidUTF8], 1),
+ InvalidUTF8 = string:slice(["abc", InvalidUTF8], 3),
+ {'EXIT', {badarg, _}} = ?TRY(string:slice(["abc", InvalidUTF8], 1, 5)),
+ BadUtf8 = <<$a, InvalidUTF8/binary, "teststring">>,
+ {'EXIT', {badarg, _}} = ?TRY(string:slice(BadUtf8, 2)),
+ {'EXIT', {badarg, _}} = ?TRY(string:slice(BadUtf8, 1, 5)),
+ {'EXIT', {badarg, _}} = ?TRY(string:slice(BadUtf8, 0, 5)),
ok.
pad(_) ->
@@ -269,6 +298,10 @@ pad(_) ->
?TEST(Str, [10, trailing, $.], "Hallå....."),
?TEST(Str++["f"], [10, trailing, $.], "Hallåf...."),
?TEST(Str++[" flåwer"], [10, trailing, $.], "Hallå flåwer"),
+
+ InvalidUTF8 = <<192,192>>,
+ {'EXIT', {badarg, _}} = ?TRY(string:pad(InvalidUTF8, 10, both, $.)),
+ {'EXIT', {badarg, _}} = ?TRY(string:pad(<<$a, InvalidUTF8/binary, $z>>, 10, both, $.)),
ok.
trim(_) ->
@@ -299,6 +332,11 @@ trim(_) ->
?TEST([[<<"!v">>|<<204,128,$v,204,129>>]],[trailing, [[$v,769]]], [$!,$v,768]),
?TEST([[[<<"v">>|<<204,129,118,204,128,118>>],769,118,769]], [trailing, [[118,769]]], [$v,769,$v,768]),
?TEST([<<"vv">>|<<204,128,118,204,128>>], [trailing, [[118,768]]], "v"),
+
+ InvalidUTF8 = <<192,192>>,
+ {'EXIT', {badarg, _}} = ?TRY(string:trim(InvalidUTF8, both, "az")),
+ %% Not checked (using binary search)
+ %% {'EXIT', {badarg, _}} = ?TRY(string:trim(<<$a, $b, InvalidUTF8/binary, $z>>, both, "az")),
ok.
chomp(_) ->
@@ -399,6 +437,13 @@ take(_) ->
?TEST([<<"e">>,778,"åäöe", <<778/utf8>>, $e, 779], [[[$e,778]], true, trailing],
{[$e,778]++"åäöe"++[778], [$e,779]}),
+ InvalidUTF8 = <<192,192>>,
+ {'EXIT', {badarg, _}} = ?TRY(string:take(InvalidUTF8, [$.], false, leading)),
+ %% Not checked (using binary search)
+ %% {'EXIT', {badarg, _}} = ?TRY(string:take(InvalidUTF8, [$.], true, leading)),
+ %% {'EXIT', {badarg, _}} = ?TRY(string:take(InvalidUTF8, [$.], false, trailing)),
+ {'EXIT', {badarg, _}} = ?TRY(string:take(InvalidUTF8, [$.], true, trailing)),
+
ok.
@@ -408,13 +453,18 @@ uppercase(_) ->
?TEST("abc", [], "ABC"),
?TEST("ABC", [], "ABC"),
?TEST("abcdefghiljklmnopqrstvxyzåäö",[], "ABCDEFGHILJKLMNOPQRSTVXYZÅÄÖ"),
- ?TEST("åäö", [], "ÅÄÖ"),
- ?TEST("ÅÄÖ", [], "ÅÄÖ"),
+ ?TEST("åäö ", [], "ÅÄÖ "),
+ ?TEST("ÅÄÖ ", [], "ÅÄÖ "),
?TEST("Michał", [], "MICHAŁ"),
?TEST(["Mic",<<"hał"/utf8>>], [], "MICHAŁ"),
?TEST("ljLJ", [], "LJLJ"),
?TEST("LJlj", [], "LJLJ"),
?TEST("ß sharp s", [], "SS SHARP S"),
+
+ InvalidUTF8 = <<192,192>>,
+ {'EXIT', {badarg, _}} = ?TRY(string:uppercase(InvalidUTF8)),
+ {'EXIT', {badarg, _}} = ?TRY(string:uppercase(<<$a, InvalidUTF8/binary, $z>>)),
+
ok.
lowercase(_) ->
@@ -422,12 +472,16 @@ lowercase(_) ->
?TEST("123", [], "123"),
?TEST("abc", [], "abc"),
?TEST("ABC", [], "abc"),
- ?TEST("åäö", [], "åäö"),
- ?TEST("ÅÄÖ", [], "åäö"),
+ ?TEST("åäö ", [], "åäö "),
+ ?TEST("ÅÄÖ ", [], "åäö "),
?TEST("MICHAŁ", [], "michał"),
?TEST(["Mic",<<"HAŁ"/utf8>>], [], "michał"),
?TEST("ß SHARP S", [], "ß sharp s"),
?TEST("İ I WITH DOT ABOVE", [], "i̇ i with dot above"),
+
+ InvalidUTF8 = <<192,192>>,
+ {'EXIT', {badarg, _}} = ?TRY(string:lowercase(InvalidUTF8)),
+ {'EXIT', {badarg, _}} = ?TRY(string:lowercase(<<$a, InvalidUTF8/binary, $z>>)),
ok.
titlecase(_) ->
@@ -441,6 +495,10 @@ titlecase(_) ->
?TEST("ljLJ", [], "LjLJ"),
?TEST("LJlj", [], "Ljlj"),
?TEST("ß sharp s", [], "Ss sharp s"),
+
+ InvalidUTF8 = <<192,192>>,
+ {'EXIT', {badarg, _}} = ?TRY(string:titlecase(InvalidUTF8)),
+ <<$A, _/binary>> = ?TRY(string:titlecase(<<$a, InvalidUTF8/binary, $z>>)),
ok.
casefold(_) ->
@@ -448,13 +506,17 @@ casefold(_) ->
?TEST("123", [], "123"),
?TEST("abc", [], "abc"),
?TEST("ABC", [], "abc"),
- ?TEST("åäö", [], "åäö"),
- ?TEST("ÅÄÖ", [], "åäö"),
+ ?TEST("åäö ", [], "åäö "),
+ ?TEST("ÅÄÖ ", [], "åäö "),
?TEST("MICHAŁ", [], "michał"),
?TEST(["Mic",<<"HAŁ"/utf8>>], [], "michał"),
?TEST("ß SHARP S", [], "ss sharp s"),
?TEST("ẞ SHARP S", [], "ss sharp s"),
?TEST("İ I WITH DOT ABOVE", [], "i̇ i with dot above"),
+
+ InvalidUTF8 = <<192,192>>,
+ {'EXIT', {badarg, _}} = ?TRY(string:casefold(InvalidUTF8)),
+ {'EXIT', {badarg, _}} = ?TRY(string:casefold(<<$a, InvalidUTF8/binary, $z>>)),
ok.
@@ -739,7 +801,7 @@ meas(Config) ->
_ -> % No scaling, run at most 1.5 min
Tester = spawn(Exec),
receive {test_done, Tester} -> ok
- after 90000 ->
+ after 118000 ->
io:format("Timelimit reached stopping~n",[]),
exit(Tester, die)
end,
@@ -752,20 +814,23 @@ do_measure(DataDir) ->
{ok, Bin} = file:read_file(File),
io:format("~p~n",[byte_size(Bin)]),
Do = fun(Name, Func, Mode) ->
- {N, Mean, Stddev, _} = time_func(Func, Mode, Bin),
- io:format("~15w ~6w ~6.2fms ±~5.2fms #~.2w gc included~n",
+ {N, Mean, Stddev, _} = time_func(Func, Mode, Bin, 20),
+ io:format("~15w ~15w ~8.2fms ±~6.2fms #~.2w gc included~n",
[Name, Mode, Mean/1000, Stddev/1000, N])
end,
Do2 = fun(Name, Func, Mode) ->
- {N, Mean, Stddev, _} = time_func(Func, binary, <<>>),
- io:format("~15w ~6w ~6.2fms ±~5.2fms #~.2w gc included~n",
+ {N, Mean, Stddev, _} = time_func(Func, binary, <<>>, 20),
+ io:format("~15w ~15w ~8.2fms ±~6.2fms #~.2w gc included~n",
[Name, Mode, Mean/1000, Stddev/1000, N])
end,
+ %% lefty_list means a list balanced to the left, like
+ %% [[[30],31],32]. Only some functions check such lists.
+ Modes = [list, lefty_list, binary, {many_lists,1}, {many_lists, 4}],
io:format("----------------------~n"),
Do(old_tokens, fun(Str) -> string:tokens(Str, [$\n,$\r]) end, list),
Tokens = {lexemes, fun(Str) -> string:lexemes(Str, [$\n,$\r]) end},
- [Do(Name,Fun,Mode) || {Name,Fun} <- [Tokens], Mode <- [list, binary]],
+ [Do(Name,Fun,Mode) || {Name,Fun} <- [Tokens], Mode <- Modes],
S0 = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxy.....",
S0B = <<"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxy.....">>,
@@ -809,19 +874,31 @@ do_measure(DataDir) ->
Do2(slice, repeat(fun() -> string:slice(S0, 20, 15) end), list),
Do2(slice, repeat(fun() -> string:slice(S0B, 20, 15) end), binary),
+ LCase = "areaa reare rerar earea reare reare",
+ LCaseB = unicode:characters_to_binary(LCase),
+ UCase = string:uppercase(LCase),
+ UCaseB = unicode:characters_to_binary(UCase),
+
+ Do2(to_upper_0, repeat(fun() -> string:to_upper(UCase) end), list),
+ Do2(uppercase_0, repeat(fun() -> string:uppercase(UCase) end), list),
+ Do2(uppercase_0, repeat(fun() -> string:uppercase(UCaseB) end), binary),
+ Do2(to_upper_a, repeat(fun() -> string:to_upper(LCase) end), list),
+ Do2(uppercase_a, repeat(fun() -> string:uppercase(LCase) end), list),
+ Do2(uppercase_a, repeat(fun() -> string:uppercase(LCaseB) end), binary),
+
io:format("--~n",[]),
NthTokens = {nth_lexemes, fun(Str) -> string:nth_lexeme(Str, 18000, [$\n,$\r]) end},
- [Do(Name,Fun,Mode) || {Name,Fun} <- [NthTokens], Mode <- [list, binary]],
+ [Do(Name,Fun,Mode) || {Name,Fun} <- [NthTokens], Mode <- Modes],
Do2(take_t, repeat(fun() -> string:take(S0, [$.,$y], false, trailing) end), list),
Do2(take_t, repeat(fun() -> string:take(S0B, [$.,$y], false, trailing) end), binary),
Do2(take_tc, repeat(fun() -> string:take(S0, [$x], true, trailing) end), list),
Do2(take_tc, repeat(fun() -> string:take(S0B, [$x], true, trailing) end), binary),
Length = {length, fun(Str) -> string:length(Str) end},
- [Do(Name,Fun,Mode) || {Name,Fun} <- [Length], Mode <- [list, binary]],
+ [Do(Name,Fun,Mode) || {Name,Fun} <- [Length], Mode <- Modes],
Reverse = {reverse, fun(Str) -> string:reverse(Str) end},
- [Do(Name,Fun,Mode) || {Name,Fun} <- [Reverse], Mode <- [list, binary]],
+ [Do(Name,Fun,Mode) || {Name,Fun} <- [Reverse], Mode <- Modes],
ok.
@@ -880,9 +957,9 @@ test_1(Line, Func, Str, Args, Exp) ->
catch
error:Exp ->
ok;
- error:Reason ->
+ error:Reason:Stacktrace ->
io:format("~p:~p: Crash ~p ~p~n",
- [?MODULE,Line, Reason, erlang:get_stacktrace()]),
+ [?MODULE,Line, Reason, Stacktrace]),
exit({error, Func})
end.
@@ -947,10 +1024,10 @@ check_types(Line, Func, [Str|_], Res) ->
io:format("Failed: ~p ~p: ~p ~p~n",[Line, Func, T1, T2]),
io:format(" ~p => ~p~n", [Str, Res]),
error;
- _:Reason ->
- io:format("Crash: ~p in~n ~p~n",[Reason, erlang:get_stacktrace()]),
+ _:Reason:Stacktrace ->
+ io:format("Crash: ~p in~n ~p~n",[Reason, Stacktrace]),
io:format("Failed: ~p ~p: ~p => ~p~n", [Line, Func, Str, Res]),
- exit({Reason, erlang:get_stacktrace()})
+ exit({Reason, Stacktrace})
end.
check_types_1(T, T) ->
@@ -1033,25 +1110,51 @@ needs_check(_) -> true.
%%%% Timer stuff
-time_func(Fun, Mode, Bin) ->
+time_func(Fun, Mode, Bin, Repeat) ->
timer:sleep(100), %% Let emulator catch up and clean things before test runs
Self = self(),
Pid = spawn_link(fun() ->
Str = mode(Mode, Bin),
- Self ! {self(),time_func(0,0,0, Fun, Str, undefined)}
+ Self ! {self(),time_func(0,0,0, Fun, Str, undefined, Repeat)}
end),
receive {Pid,Msg} -> Msg end.
-time_func(N,Sum,SumSq, Fun, Str, _) when N < 20 ->
+time_func(N,Sum,SumSq, Fun, Str, _, Repeat) when N < Repeat ->
{Time, Res} = timer:tc(fun() -> Fun(Str) end),
- time_func(N+1,Sum+Time,SumSq+Time*Time, Fun, Str, Res);
-time_func(N,Sum,SumSq, _, _, Res) ->
+ time_func(N+1,Sum+Time,SumSq+Time*Time, Fun, Str, Res, Repeat);
+time_func(N,Sum,SumSq, _, _, Res, _) ->
Mean = round(Sum / N),
Stdev = round(math:sqrt((SumSq - (Sum*Sum/N))/(N - 1))),
{N, Mean, Stdev, Res}.
mode(binary, Bin) -> Bin;
-mode(list, Bin) -> unicode:characters_to_list(Bin).
+mode(list, Bin) -> unicode:characters_to_list(Bin);
+mode(lefty_list, Bin) ->
+ L = unicode:characters_to_list(Bin),
+ to_left(L);
+mode({many_lists, N}, Bin) ->
+ group(unicode:characters_to_list(Bin), N).
+
+group([], _N) ->
+ [];
+group(L, N) ->
+ try lists:split(N, L) of
+ {L1, L2} ->
+ [L1 | group(L2, N)]
+ catch
+ _:_ ->
+ [L]
+ end.
+
+to_left([]) ->
+ [];
+to_left([H|L]) ->
+ to_left([H], L).
+
+to_left(V, []) ->
+ V;
+to_left(V, [H|L]) ->
+ to_left([V,H], L).
%%
%% Old string lists Test cases starts here.
diff --git a/lib/stdlib/test/supervisor_1.erl b/lib/stdlib/test/supervisor_1.erl
index 419026749b..0d3dc67d3b 100644
--- a/lib/stdlib/test/supervisor_1.erl
+++ b/lib/stdlib/test/supervisor_1.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -42,6 +42,8 @@ start_child(error) ->
set -> gen_server:start_link(?MODULE, error, [])
end;
+start_child({return, Term}) ->
+ Term;
start_child(Extra) ->
{ok, Pid} = gen_server:start_link(?MODULE, normal, []),
diff --git a/lib/stdlib/test/supervisor_SUITE.erl b/lib/stdlib/test/supervisor_SUITE.erl
index cd2c6b0cbb..9370067910 100644
--- a/lib/stdlib/test/supervisor_SUITE.erl
+++ b/lib/stdlib/test/supervisor_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -39,6 +39,9 @@
sup_start_ignore_temporary_child_start_child_simple/1,
sup_start_ignore_permanent_child_start_child_simple/1,
sup_start_error_return/1, sup_start_fail/1,
+ sup_start_child_returns_error/1,
+ sup_start_restart_child_returns_error/1,
+ sup_start_child_returns_error_simple/1,
sup_start_map/1, sup_start_map_simple/1,
sup_start_map_faulty_specs/1,
sup_stop_infinity/1, sup_stop_timeout/1, sup_stop_brutal_kill/1,
@@ -65,14 +68,16 @@
simple_one_for_one_extra/1, simple_one_for_one_shutdown/1]).
%% Misc tests
--export([child_unlink/1, tree/1, count_children/1,
+-export([child_unlink/1, tree/1, count_children/1, count_children_supervisor/1,
count_restarting_children/1, get_callback_module/1,
do_not_save_start_parameters_for_temporary_children/1,
do_not_save_child_specs_for_temporary_children/1,
simple_one_for_one_scale_many_temporary_children/1,
simple_global_supervisor/1, hanging_restart_loop/1,
+ hanging_restart_loop_rest_for_one/1,
hanging_restart_loop_simple/1, code_change/1, code_change_map/1,
- code_change_simple/1, code_change_simple_map/1]).
+ code_change_simple/1, code_change_simple_map/1,
+ order_of_children/1, scale_start_stop_many_children/1]).
%%-------------------------------------------------------------------------
@@ -91,12 +96,15 @@ all() ->
{group, normal_termination},
{group, shutdown_termination},
{group, abnormal_termination}, child_unlink, tree,
- count_children, count_restarting_children, get_callback_module,
+ count_children, count_children_supervisor, count_restarting_children,
+ get_callback_module,
do_not_save_start_parameters_for_temporary_children,
do_not_save_child_specs_for_temporary_children,
simple_one_for_one_scale_many_temporary_children, temporary_bystander,
- simple_global_supervisor, hanging_restart_loop, hanging_restart_loop_simple,
- code_change, code_change_map, code_change_simple, code_change_simple_map].
+ simple_global_supervisor, hanging_restart_loop,
+ hanging_restart_loop_rest_for_one, hanging_restart_loop_simple,
+ code_change, code_change_map, code_change_simple, code_change_simple_map,
+ order_of_children, scale_start_stop_many_children].
groups() ->
[{sup_start, [],
@@ -105,7 +113,10 @@ groups() ->
sup_start_ignore_temporary_child_start_child,
sup_start_ignore_temporary_child_start_child_simple,
sup_start_ignore_permanent_child_start_child_simple,
- sup_start_error_return, sup_start_fail]},
+ sup_start_error_return, sup_start_fail,
+ sup_start_child_returns_error, sup_start_restart_child_returns_error,
+ sup_start_child_returns_error_simple
+ ]},
{sup_start_map, [],
[sup_start_map, sup_start_map_simple, sup_start_map_faulty_specs]},
{sup_stop, [],
@@ -147,6 +158,15 @@ init_per_testcase(_Case, Config) ->
Config.
end_per_testcase(_Case, _Config) ->
+ %% Clean up to avoid unnecessary error reports in the shell
+ case whereis(sup_test) of
+ SupPid when is_pid(SupPid) ->
+ unlink(SupPid),
+ exit(SupPid,shutdown),
+ ok;
+ _ ->
+ error
+ end,
ok.
start_link(InitResult) ->
@@ -274,6 +294,7 @@ sup_start_ignore_permanent_child_start_child_simple(Config)
%% Regression test: check that the supervisor terminates without error.
exit(Pid, shutdown),
check_exit_reason(Pid, shutdown).
+
%%-------------------------------------------------------------------------
%% Tests what happens if init-callback returns a invalid value.
sup_start_error_return(Config) when is_list(Config) ->
@@ -289,6 +310,53 @@ sup_start_fail(Config) when is_list(Config) ->
check_exit_reason(Term).
%%-------------------------------------------------------------------------
+%% Test what happens when the start function for a child returns
+%% {error,Reason} or some other term().
+sup_start_restart_child_returns_error(_Config) ->
+ process_flag(trap_exit, true),
+ Child = {child1, {supervisor_1, start_child, [error]},
+ permanent, 1000, worker, []},
+ {ok, _Pid} = start_link({ok, {{one_for_one, 2, 3600}, [Child]}}),
+
+ ok = supervisor:terminate_child(sup_test, child1),
+ {error,{function_clause,_}} = supervisor:restart_child(sup_test,child1),
+
+ [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test),
+ ok.
+
+%%-------------------------------------------------------------------------
+%% Test what happens when the start function for a child returns
+%% {error,Reason} or some other term().
+sup_start_child_returns_error(_Config) ->
+ process_flag(trap_exit, true),
+ Child1 = {child1, {supervisor_1, start_child, [{return,{error,reason}}]},
+ permanent, 1000, worker, []},
+ Child2 = {child2, {supervisor_1, start_child, [{return,error_reason}]},
+ permanent, 1000, worker, []},
+ {ok, _Pid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
+
+ {error,{reason,_}} = supervisor:start_child(sup_test,Child1),
+ {error,{error_reason,_}} = supervisor:start_child(sup_test,Child2),
+
+ [] = supervisor:which_children(sup_test),
+ ok.
+
+%%-------------------------------------------------------------------------
+%% Test what happens when the start function for a child returns
+%% {error,Reason} - simple_one_for_one
+sup_start_child_returns_error_simple(_Config) ->
+ process_flag(trap_exit, true),
+ Child = {child1, {supervisor_1, start_child, []},
+ permanent, 1000, worker, []},
+ {ok, _Pid} = start_link({ok, {{simple_one_for_one, 2, 3600}, [Child]}}),
+
+ {error,reason} = supervisor:start_child(sup_test,[{return,{error,reason}}]),
+ {error,error_reason} = supervisor:start_child(sup_test,[{return,error_reason}]),
+
+ [] = supervisor:which_children(sup_test),
+ ok.
+
+%%-------------------------------------------------------------------------
%% Tests that the supervisor process starts correctly with map
%% startspec, and that the full childspec can be read.
sup_start_map(Config) when is_list(Config) ->
@@ -468,7 +536,16 @@ extra_return(Config) when is_list(Config) ->
[{child1, CPid3, worker, []}] = supervisor:which_children(sup_test),
[1,1,0,1] = get_child_counts(sup_test),
- ok.
+ %% Check that it can be automatically restarted
+ terminate(CPid3, abnormal),
+ [{child1, CPid4, worker, []}] = supervisor:which_children(sup_test),
+ [1,1,0,1] = get_child_counts(sup_test),
+ if (not is_pid(CPid4)) orelse CPid4=:=CPid3 ->
+ ct:fail({not_restarted,CPid3,CPid4});
+ true ->
+ ok
+ end.
+
%%-------------------------------------------------------------------------
%% Test API functions start_child/2, terminate_child/2, delete_child/2
%% restart_child/2, which_children/1, count_children/1. Only correct
@@ -1140,7 +1217,7 @@ simple_one_for_one(Config) when is_list(Config) ->
[{Id4, Pid4, _, _}|_] = supervisor:which_children(sup_test),
terminate(SupPid, Pid4, Id4, abnormal),
- check_exit([SupPid]).
+ check_exit_reason(SupPid,shutdown).
%%-------------------------------------------------------------------------
@@ -1378,6 +1455,11 @@ tree(Config) when is_list(Config) ->
[?MODULE, {ok, {{one_for_one, 4, 3600}, []}}]},
permanent, infinity,
supervisor, []},
+ ChildSup3 = {supchild3,
+ {supervisor, start_link,
+ [?MODULE, {ok, {{one_for_one, 4, 3600}, []}}]},
+ transient, infinity,
+ supervisor, []},
%% Top supervisor
{ok, SupPid} = start_link({ok, {{one_for_all, 4, 3600}, []}}),
@@ -1385,7 +1467,9 @@ tree(Config) when is_list(Config) ->
%% Child supervisors
{ok, Sup1} = supervisor:start_child(SupPid, ChildSup1),
{ok, Sup2} = supervisor:start_child(SupPid, ChildSup2),
- [2,2,2,0] = get_child_counts(SupPid),
+ {ok, _Sup3} = supervisor:start_child(SupPid, ChildSup3),
+ ok = supervisor:terminate_child(SupPid, supchild3),
+ [3,2,3,0] = get_child_counts(SupPid),
%% Workers
[{_, CPid2, _, _},{_, CPid1, _, _}] =
@@ -1417,16 +1501,21 @@ tree(Config) when is_list(Config) ->
timer:sleep(1000),
- [{supchild2, NewSup2, _, _},{supchild1, NewSup1, _, _}] =
+ [{supchild3, NewSup3, _, _},
+ {supchild2, NewSup2, _, _},
+ {supchild1, NewSup1, _, _}] =
supervisor:which_children(SupPid),
- [2,2,2,0] = get_child_counts(SupPid),
+ [3,3,3,0] = get_child_counts(SupPid),
[{child2, _, _, _},{child1, _, _, _}] =
supervisor:which_children(NewSup1),
[2,2,0,2] = get_child_counts(NewSup1),
[] = supervisor:which_children(NewSup2),
- [0,0,0,0] = get_child_counts(NewSup2).
+ [0,0,0,0] = get_child_counts(NewSup2),
+
+ [] = supervisor:which_children(NewSup3),
+ [0,0,0,0] = get_child_counts(NewSup3).
%%-------------------------------------------------------------------------
%% Test count_children
@@ -1459,6 +1548,36 @@ count_children(Config) when is_list(Config) ->
[1,0,0,0] = get_child_counts(sup_test).
%%-------------------------------------------------------------------------
+%% Test count_children for simple_one_for_one, when children are supervisors
+count_children_supervisor(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ Child = {child, {supervisor_1, start_child, []}, temporary, infinity,
+ supervisor, []},
+ {ok, SupPid} = start_link({ok, {{simple_one_for_one, 2, 3600}, [Child]}}),
+ [supervisor:start_child(sup_test, []) || _Ignore <- lists:seq(1,1000)],
+
+ Children = supervisor:which_children(sup_test),
+ ChildCount = get_child_counts(sup_test),
+
+ [supervisor:start_child(sup_test, []) || _Ignore2 <- lists:seq(1,1000)],
+
+ ChildCount2 = get_child_counts(sup_test),
+ Children2 = supervisor:which_children(sup_test),
+
+ ChildCount3 = get_child_counts(sup_test),
+ Children3 = supervisor:which_children(sup_test),
+
+ 1000 = length(Children),
+ [1,1000,1000,0] = ChildCount,
+ 2000 = length(Children2),
+ [1,2000,2000,0] = ChildCount2,
+ Children3 = Children2,
+ ChildCount3 = ChildCount2,
+
+ [terminate(SupPid, Pid, child, kill) || {undefined, Pid, supervisor, _Modules} <- Children3],
+ [1,0,0,0] = get_child_counts(sup_test).
+
+%%-------------------------------------------------------------------------
%% Test count_children when some children are restarting
count_restarting_children(Config) when is_list(Config) ->
process_flag(trap_exit, true),
@@ -1577,11 +1696,11 @@ dont_save_start_parameters_for_temporary_children(simple_one_for_one = Type) ->
start_children(Sup2, [LargeList], 100),
start_children(Sup3, [LargeList], 100),
- [{memory,Mem1}] = process_info(Sup1, [memory]),
- [{memory,Mem2}] = process_info(Sup2, [memory]),
- [{memory,Mem3}] = process_info(Sup3, [memory]),
+ Size1 = erts_debug:flat_size(sys:get_status(Sup1)),
+ Size2 = erts_debug:flat_size(sys:get_status(Sup2)),
+ Size3 = erts_debug:flat_size(sys:get_status(Sup3)),
- true = (Mem3 < Mem1) and (Mem3 < Mem2),
+ true = (Size3 < Size1) and (Size3 < Size2),
terminate(Sup1, shutdown),
terminate(Sup2, shutdown),
@@ -1605,11 +1724,11 @@ dont_save_start_parameters_for_temporary_children(Type) ->
start_children(Sup2, Transient, 100),
start_children(Sup3, Temporary, 100),
- [{memory,Mem1}] = process_info(Sup1, [memory]),
- [{memory,Mem2}] = process_info(Sup2, [memory]),
- [{memory,Mem3}] = process_info(Sup3, [memory]),
+ Size1 = erts_debug:flat_size(sys:get_status(Sup1)),
+ Size2 = erts_debug:flat_size(sys:get_status(Sup2)),
+ Size3 = erts_debug:flat_size(sys:get_status(Sup3)),
- true = (Mem3 < Mem1) and (Mem3 < Mem2),
+ true = (Size3 < Size1) and (Size3 < Size2),
terminate(Sup1, shutdown),
terminate(Sup2, shutdown),
@@ -1847,6 +1966,61 @@ hanging_restart_loop(Config) when is_list(Config) ->
undefined = whereis(sup_test),
ok.
+hanging_restart_loop_rest_for_one(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ {ok, Pid} = start_link({ok, {{rest_for_one, 8, 10}, []}}),
+ Child1 = {child1, {supervisor_1, start_child, []},
+ permanent, brutal_kill, worker, []},
+ Child2 = {child2, {supervisor_deadlock, start_child, []},
+ permanent, brutal_kill, worker, []},
+ Child3 = {child3, {supervisor_1, start_child, []},
+ permanent, brutal_kill, worker, []},
+
+ %% Ets table with state read by supervisor_deadlock.erl
+ ets:new(supervisor_deadlock,[set,named_table,public]),
+ ets:insert(supervisor_deadlock,{fail_start,false}),
+
+ {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+ {ok, CPid2} = supervisor:start_child(sup_test, Child2),
+ link(CPid2),
+ {ok, _CPid3} = supervisor:start_child(sup_test, Child3),
+
+ ets:insert(supervisor_deadlock,{fail_start,true}),
+ supervisor_deadlock:restart_child(),
+ timer:sleep(2000), % allow restart to happen before proceeding
+
+ {error, already_present} = supervisor:start_child(sup_test, Child2),
+ {error, restarting} = supervisor:restart_child(sup_test, child2),
+ {error, restarting} = supervisor:delete_child(sup_test, child2),
+ [{child3,undefined,worker,[]},
+ {child2,restarting,worker,[]},
+ {child1,CPid1,worker,[]}] = supervisor:which_children(sup_test),
+ [3,1,0,3] = get_child_counts(sup_test),
+
+ ok = supervisor:terminate_child(sup_test, child2),
+ check_exit_reason(CPid2, error),
+ [{child3,undefined,worker,[]},
+ {child2,undefined,worker,[]},
+ {child1,CPid1,worker,[]}] = supervisor:which_children(sup_test),
+
+ ets:insert(supervisor_deadlock,{fail_start,false}),
+ {ok, CPid22} = supervisor:restart_child(sup_test, child2),
+ link(CPid22),
+
+ ets:insert(supervisor_deadlock,{fail_start,true}),
+ supervisor_deadlock:restart_child(),
+ timer:sleep(2000), % allow restart to happen before proceeding
+
+ %% Terminating supervisor.
+ %% OTP-9549 fixes so this does not give a timetrap timeout -
+ %% i.e. that supervisor does not hang in restart loop.
+ terminate(Pid,shutdown),
+
+ %% Check that child died with reason from 'restart' request above
+ check_exit_reason(CPid22, error),
+ undefined = whereis(sup_test),
+ ok.
+
%%-------------------------------------------------------------------------
%% Test that child and supervisor can be shutdown while hanging in
%% restart loop, simple_one_for_one.
@@ -2022,11 +2196,11 @@ code_change_simple(_Config) ->
SimpleChild2 = {child2,{supervisor_1, start_child, []}, permanent,
brutal_kill, worker, []},
- {error, {error, {ok,[_,_]}}} =
+ {error, {error, {ok,{[_,_],_}}}} =
fake_upgrade(SimplePid,{ok,{SimpleFlags,[SimpleChild1,SimpleChild2]}}),
%% Attempt to remove child
- {error, {error, {ok,[]}}} = fake_upgrade(SimplePid,{ok,{SimpleFlags,[]}}),
+ {error, {error, {ok,{[],_}}}} = fake_upgrade(SimplePid,{ok,{SimpleFlags,[]}}),
terminate(SimplePid,shutdown),
ok.
@@ -2047,11 +2221,11 @@ code_change_simple_map(_Config) ->
%% Attempt to add child
SimpleChild2 = #{id=>child2,
start=>{supervisor_1, start_child, []}},
- {error, {error, {ok, [_,_]}}} =
+ {error, {error, {ok, {[_,_],_}}}} =
fake_upgrade(SimplePid,{ok,{SimpleFlags,[SimpleChild1,SimpleChild2]}}),
%% Attempt to remove child
- {error, {error, {ok, []}}} =
+ {error, {error, {ok, {[],_}}}} =
fake_upgrade(SimplePid,{ok,{SimpleFlags,[]}}),
terminate(SimplePid,shutdown),
@@ -2075,6 +2249,155 @@ fake_upgrade(Pid,NewInitReturn) ->
ok = sys:resume(Pid),
R.
+%% Test that children are started in the order they are given, and
+%% terminated in the opposite order
+order_of_children(_Config) ->
+ process_flag(trap_exit, true),
+ %% Use child ids that are not alphabetically storted
+ Id1 = ch7,
+ Id2 = ch3,
+ Id3 = ch10,
+ Id4 = ch2,
+ Id5 = ch5,
+ Children =
+ [{Id, {supervisor_1, start_child, []}, permanent, 1000, worker, []} ||
+ Id <- [Id1,Id2,Id3,Id4,Id5]],
+
+ {ok, SupPid} = start_link({ok, {{rest_for_one, 2, 3600}, Children}}),
+
+
+ %% Check start order (pids are growing)
+ Which1 = supervisor:which_children(sup_test),
+ IsPid = fun({_,P,_,_}) when is_pid(P) -> true; (_) -> false end,
+ true = lists:all(IsPid,Which1),
+ SortedOnPid1 = lists:keysort(2,Which1),
+ [{Id1,Pid1,_,_},
+ {Id2,Pid2,_,_},
+ {Id3,Pid3,_,_},
+ {Id4,Pid4,_,_},
+ {Id5,Pid5,_,_}] = SortedOnPid1,
+
+ TPid = self(),
+ TraceHandler = fun({trace,P,exit,_},{Last,Ps}) when P=:=Last ->
+ TPid ! {exited,lists:reverse([P|Ps])},
+ {Last,Ps};
+ ({trace,P,exit,_},{Last,Ps}) ->
+ {Last,[P|Ps]};
+ (_T,Acc) ->
+ Acc
+ end,
+
+ %% Terminate Pid3 and check that Pid4 and Pid5 are terminated in
+ %% expected order.
+ Expected1 = [Pid5,Pid4],
+ {ok,_} = dbg:tracer(process,{TraceHandler,{Pid4,[]}}),
+ [{ok,[_]} = dbg:p(P,procs) || P <- Expected1],
+ terminate(Pid3, abnormal),
+ receive {exited,ExitedPids1} ->
+ dbg:stop_clear(),
+ case ExitedPids1 of
+ Expected1 -> ok;
+ _ -> ct:fail({faulty_termination_order,
+ {expected,Expected1},
+ {got,ExitedPids1}})
+ end
+ after 3000 ->
+ dbg:stop_clear(),
+ ct:fail({shutdown_fail,timeout})
+ end,
+
+ %% Then check that Id3-5 are started again in correct order
+ Which2 = supervisor:which_children(sup_test),
+ true = lists:all(IsPid,Which2),
+ SortedOnPid2 = lists:keysort(2,Which2),
+ [{Id1,Pid1,_,_},
+ {Id2,Pid2,_,_},
+ {Id3,Pid32,_,_},
+ {Id4,Pid42,_,_},
+ {Id5,Pid52,_,_}] = SortedOnPid2,
+
+ %% Terminate supervisor and check that all children are terminated
+ %% in opposite start order
+ Expected2 = [Pid52,Pid42,Pid32,Pid2,Pid1],
+ {ok,_} = dbg:tracer(process,{TraceHandler,{Pid1,[]}}),
+ [{ok,[_]} = dbg:p(P,procs) || P <- Expected2],
+ exit(SupPid,shutdown),
+ receive {exited,ExitedPids2} ->
+ dbg:stop_clear(),
+ case ExitedPids2 of
+ Expected2 -> ok;
+ _ -> ct:fail({faulty_termination_order,
+ {expected,Expected2},
+ {got,ExitedPids2}})
+ end
+ after 3000 ->
+ dbg:stop_clear(),
+ ct:fail({shutdown_fail,timeout})
+ end,
+ ok.
+
+%% Test that a non-simple supervisor scales well for starting and
+%% stopping many children.
+scale_start_stop_many_children(_Config) ->
+ case erlang:system_info(build_type) of
+ opt -> scale_start_stop_many_children();
+ Other -> {skip,"Run on build type 'opt' only (current: '" ++
+ atom_to_list(Other)++"')"}
+ end.
+
+scale_start_stop_many_children() ->
+ process_flag(trap_exit, true),
+ {ok, _Pid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
+ N1 = 1000,
+ N2 = 100000,
+ Ids1 = lists:seq(1,N1),
+ Ids2 = lists:seq(1,N2),
+ Children1 = [{Id,{supervisor_1,start_child,[]},permanent,1000,worker,[]} ||
+ Id <- Ids1],
+ Children2 = [{Id,{supervisor_1,start_child,[]},permanent,1000,worker,[]} ||
+ Id <- Ids2],
+
+ {StartT1,_} =
+ timer:tc(fun() ->
+ [supervisor:start_child(sup_test,C) || C <- Children1]
+ end),
+ {StopT1,_} =
+ timer:tc(fun() ->
+ [supervisor:terminate_child(sup_test,I) || I <- Ids1]
+ end),
+ ct:log("~w children, start time: ~w ms, stop time: ~w ms",
+ [N1, StartT1 div 1000, StopT1 div 1000]),
+
+ {StartT2,_} =
+ timer:tc(fun() ->
+ [supervisor:start_child(sup_test,C) || C <- Children2]
+ end),
+ {StopT2,_} =
+ timer:tc(fun() ->
+ [supervisor:terminate_child(sup_test,I) || I <- Ids2]
+ end),
+ ct:log("~w children, start time: ~w ms, stop time: ~w ms",
+ [N2, StartT2 div 1000, StopT2 div 1000]),
+
+ %% Scaling should be more or less linear, but allowing a bit more
+ %% to avoid false alarms
+ ScaleLimit = (N2 div N1) * 10,
+ StartScale = StartT2 div StartT1,
+ StopScale = StopT2 div StopT1,
+
+ ct:log("Scale limit: ~w~nStart scale: ~w~nStop scale: ~w",
+ [ScaleLimit, StartScale, StopScale]),
+
+ if StartScale > ScaleLimit ->
+ ct:fail({bad_start_scale,StartScale});
+ StopScale > ScaleLimit ->
+ ct:fail({bad_stop_scale,StopScale});
+ true ->
+ ok
+ end,
+
+ ok.
+
%%-------------------------------------------------------------------------
terminate(Pid, Reason) when Reason =/= supervisor ->
terminate(dummy, Pid, dummy, Reason).
diff --git a/lib/stdlib/test/supervisor_deadlock.erl b/lib/stdlib/test/supervisor_deadlock.erl
index 8d3d1c6f30..f51aecccb2 100644
--- a/lib/stdlib/test/supervisor_deadlock.erl
+++ b/lib/stdlib/test/supervisor_deadlock.erl
@@ -1,5 +1,5 @@
-module(supervisor_deadlock).
--compile(export_all).
+-compile([export_all,nowarn_export_all]).
%%%-----------------------------------------------------------------
diff --git a/lib/stdlib/test/sys_SUITE.erl b/lib/stdlib/test/sys_SUITE.erl
index b44df0fbda..fcc4419569 100644
--- a/lib/stdlib/test/sys_SUITE.erl
+++ b/lib/stdlib/test/sys_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -84,7 +84,7 @@ stats(Config) when is_list(Config) ->
{ok,-44} = public_call(44),
{ok,Stats} = sys:statistics(?server,get),
true = lists:member({messages_in,1}, Stats),
- true = lists:member({messages_out,0}, Stats),
+ true = lists:member({messages_out,1}, Stats),
ok = sys:statistics(?server,false),
{status,_Pid,{module,_Mod},[_PDict,running,Self,_,_]} =
sys:get_status(?server),
@@ -133,7 +133,8 @@ install(Config) when is_list(Config) ->
Master ! {spy_got,{request,Arg},ProcState};
Other ->
io:format("Trigged other=~p\n",[Other])
- end
+ end,
+ func_state
end,
sys:install(?server,{SpyFun,func_state}),
{ok,-1} = (catch public_call(1)),
@@ -142,10 +143,27 @@ install(Config) when is_list(Config) ->
sys:install(?server,{SpyFun,func_state}),
sys:install(?server,{SpyFun,func_state}),
{ok,-3} = (catch public_call(3)),
- sys:remove(?server,SpyFun),
{ok,-4} = (catch public_call(4)),
+ sys:remove(?server,SpyFun),
+ {ok,-5} = (catch public_call(5)),
+ [{spy_got,{request,1},sys_SUITE_server},
+ {spy_got,{request,3},sys_SUITE_server},
+ {spy_got,{request,4},sys_SUITE_server}] = get_messages(),
+
+ sys:install(?server,{id1, SpyFun, func_state}),
+ sys:install(?server,{id1, SpyFun, func_state}), %% should not be installed
+ sys:install(?server,{id2, SpyFun, func_state}),
+ {ok,-1} = (catch public_call(1)),
+ %% We have two SpyFun installed:
[{spy_got,{request,1},sys_SUITE_server},
- {spy_got,{request,3},sys_SUITE_server}] = get_messages(),
+ {spy_got,{request,1},sys_SUITE_server}] = get_messages(),
+ sys:remove(?server, id1),
+ {ok,-1} = (catch public_call(1)),
+ %% We have one SpyFun installed:
+ [{spy_got,{request,1},sys_SUITE_server}] = get_messages(),
+ sys:no_debug(?server),
+ {ok,-1} = (catch public_call(1)),
+ [] = get_messages(),
stop(),
ok.
@@ -201,7 +219,7 @@ spec_proc(Mod) ->
{Mod,system_get_state},{throw,fail}},_}} ->
ok
end,
- ok = sys:terminate(Mod, normal),
+ ok = sync_terminate(Mod),
{ok,_} = Mod:start_link(4),
ok = case catch sys:replace_state(Mod, fun(_) -> {} end) of
{} ->
@@ -210,7 +228,7 @@ spec_proc(Mod) ->
{Mod,system_replace_state},{throw,fail}},_}} ->
ok
end,
- ok = sys:terminate(Mod, normal),
+ ok = sync_terminate(Mod),
{ok,_} = Mod:start_link(4),
StateFun = fun(_) -> error(fail) end,
ok = case catch sys:replace_state(Mod, StateFun) of
@@ -222,7 +240,18 @@ spec_proc(Mod) ->
{'EXIT',{{callback_failed,StateFun,{error,fail}},_}} ->
ok
end,
- ok = sys:terminate(Mod, normal).
+ ok = sync_terminate(Mod).
+
+sync_terminate(Mod) ->
+ P = whereis(Mod),
+ MRef = erlang:monitor(process,P),
+ ok = sys:terminate(Mod, normal),
+ receive
+ {'DOWN',MRef,_,_,normal} ->
+ ok
+ end,
+ undefined = whereis(Mod),
+ ok.
%%%%%%%%%%%%%%%%%%%%
%% Dummy server
diff --git a/lib/stdlib/test/tar_SUITE.erl b/lib/stdlib/test/tar_SUITE.erl
index 4061008812..32a33283d1 100644
--- a/lib/stdlib/test/tar_SUITE.erl
+++ b/lib/stdlib/test/tar_SUITE.erl
@@ -28,7 +28,7 @@
extract_from_open_file/1, symlinks/1, open_add_close/1, cooked_compressed/1,
memory/1,unicode/1,read_other_implementations/1,
sparse/1, init/1, leading_slash/1, dotdot/1,
- roundtrip_metadata/1]).
+ roundtrip_metadata/1, apply_file_info_opts/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("kernel/include/file.hrl").
@@ -42,7 +42,8 @@ all() ->
extract_filtered,
symlinks, open_add_close, cooked_compressed, memory, unicode,
read_other_implementations,
- sparse,init,leading_slash,dotdot,roundtrip_metadata].
+ sparse,init,leading_slash,dotdot,roundtrip_metadata,
+ apply_file_info_opts].
groups() ->
[].
@@ -989,6 +990,31 @@ do_roundtrip_metadata(Dir, File) ->
ok
end.
+apply_file_info_opts(Config) when is_list(Config) ->
+ ok = file:set_cwd(proplists:get_value(priv_dir, Config)),
+
+ ok = file:make_dir("empty_directory"),
+ ok = file:write_file("file", "contents"),
+
+ Opts = [{atime, 0}, {mtime, 0}, {ctime, 0}, {uid, 0}, {gid, 0}],
+ TarFile = "reproducible.tar",
+ {ok, Tar} = erl_tar:open(TarFile, [write]),
+ ok = erl_tar:add(Tar, "file", Opts),
+ ok = erl_tar:add(Tar, "empty_directory", Opts),
+ ok = erl_tar:add(Tar, <<"contents">>, "memory_file", Opts),
+ erl_tar:close(Tar),
+
+ ok = file:make_dir("extracted"),
+ erl_tar:extract(TarFile, [{cwd, "extracted"}]),
+
+ {ok, #file_info{mtime=0}} =
+ file:read_file_info("extracted/empty_directory", [{time, posix}]),
+ {ok, #file_info{mtime=0}} =
+ file:read_file_info("extracted/file", [{time, posix}]),
+ {ok, #file_info{mtime=0}} =
+ file:read_file_info("extracted/memory_file", [{time, posix}]),
+
+ ok.
%% Delete the given list of files.
delete_files([]) -> ok;
diff --git a/lib/stdlib/test/unicode_util_SUITE.erl b/lib/stdlib/test/unicode_util_SUITE.erl
index a89627eba5..6f55f204f4 100644
--- a/lib/stdlib/test/unicode_util_SUITE.erl
+++ b/lib/stdlib/test/unicode_util_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2017. All Rights Reserved.
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,7 +29,9 @@
get/1,
count/1]).
--export([debug/0, id/1, bin_split/1, uc_loaded_size/0]).
+-export([debug/0, id/1, bin_split/1, uc_loaded_size/0,
+ time_count/4 %% Used by stdlib_bench_SUITE
+ ]).
suite() ->
[{ct_hooks,[ts_install_cth]},
@@ -124,20 +126,33 @@ verify_gc(Line0, N, Acc) ->
%io:format("Line: ~s~n",[Line]),
[Data|_Comments] = string:tokens(Line, "#"),
- %io:format("Data: ~w~n",[string:tokens(Data, " \t")]),
+ %% io:format("Data: ~w~n",[string:tokens(Data, " \t")]),
{Str,Res} = gc_test_data(string:tokens(Data, " \t"), [], [[]]),
- try
- Res = fetch(Str, fun unicode_util:gc/1),
- Acc
- catch _Cl:{badmatch, Other} ->
+ %% io:format("InputStr: ~w ~w~n",[Str,unicode:characters_to_binary(Str)]),
+ case verify_gc(Str, Res, N, Line) andalso
+ verify_gc(unicode:characters_to_binary(Str), Res, N, Line0) of
+ true -> Acc;
+ false -> Acc+1
+ end.
+
+verify_gc({error,_,[CP|_]}=Err, _Res, N, Line) ->
+ IsSurrogate = 16#D800 =< CP andalso CP =< 16#DFFF,
+ %% Surrogat is not valid in utf8 encoding only utf16
+ IsSurrogate orelse
+ io:format("~w: ~ts~n Error in unicode:characters_to_binary ~w~n", [N, Line, Err]),
+ IsSurrogate;
+verify_gc(Str, Res, N, Line) ->
+ try fetch(Str, fun unicode_util:gc/1) of
+ Res -> true;
+ Other ->
io:format("Failed: ~p~nInput: ~ts~n\t=> ~w |~ts|~n",[N, Line, Str, Str]),
io:format("Expected: ~p~n", [Res]),
io:format("Got: ~w~n", [Other]),
- Acc+1;
- Cl:R ->
+ false
+ catch Cl:R:Stacktrace ->
io:format("~p: ~ts => |~tp|~n",[N, Line, Str]),
io:format("Expected: ~p~n", [Res]),
- erlang:raise(Cl,R,erlang:get_stacktrace())
+ erlang:raise(Cl,R,Stacktrace)
end.
gc_test_data([[247]|Rest], Str, [First|GCs]) ->
@@ -173,29 +188,29 @@ verify_nfd(Data0, LineNo, _Acc) ->
C3GC = fetch(C1, fun unicode_util:nfd/1),
C3GC = fetch(C2, fun unicode_util:nfd/1),
C3GC = fetch(C3, fun unicode_util:nfd/1)
- catch _Cl:{badmatch, Other} = _R->
+ catch _Cl:{badmatch, Other} = _R: Stacktrace ->
io:format("Failed: ~p~nInput: ~ts~n\t=> ~w |~ts|~n",[LineNo, Data1, C1, C1]),
io:format("Expected: ~ts ~w~n", [C3GC, C3GC]),
io:format("Got: ~ts ~w~n", [Other, Other]),
- erlang:raise(_Cl,_R,erlang:get_stacktrace());
- Cl:R ->
+ erlang:raise(_Cl,_R,Stacktrace);
+ Cl:R:Stacktrace ->
io:format("~p: ~ts => |~tp|~n",[LineNo, Data1, C1]),
io:format("Expected: ~p~n", [C3]),
- erlang:raise(Cl,R,erlang:get_stacktrace())
+ erlang:raise(Cl,R,Stacktrace)
end,
C5GC = fetch(C5, fun unicode_util:gc/1),
try
C5GC = fetch(C4, fun unicode_util:nfd/1),
C5GC = fetch(C5, fun unicode_util:nfd/1)
- catch _Cl2:{badmatch, Other2} = _R2->
+ catch _Cl2:{badmatch, Other2} = _R2:Stacktrace2 ->
io:format("Failed: ~p~nInput: ~ts~n\t=> ~w |~ts|~n",[LineNo, Data1, C1, C1]),
io:format("Expected: ~ts ~w~n", [C5GC, C5GC]),
io:format("Got: ~ts ~w~n", [Other2, Other2]),
- erlang:raise(_Cl2,_R2,erlang:get_stacktrace());
- Cl2:R2 ->
+ erlang:raise(_Cl2,_R2,Stacktrace2);
+ Cl2:R2:Stacktrace2 ->
io:format("~p: ~ts => |~tp|~n",[LineNo, Data1, C1]),
io:format("Expected: ~p~n", [C5]),
- erlang:raise(Cl2,R2,erlang:get_stacktrace())
+ erlang:raise(Cl2,R2,Stacktrace2)
end,
ok.
@@ -216,29 +231,29 @@ verify_nfc(Data0, LineNo, _Acc) ->
C2GC = fetch(C1, fun unicode_util:nfc/1),
C2GC = fetch(C2, fun unicode_util:nfc/1),
C2GC = fetch(C3, fun unicode_util:nfc/1)
- catch _Cl:{badmatch, Other} = _R->
+ catch _Cl:{badmatch, Other} = _R:Stacktrace ->
io:format("Failed: ~p~nInput: ~ts~n\t=> ~w |~ts|~n",[LineNo, Data1, C1, C1]),
io:format("Expected: ~ts ~w~n", [C2GC, C2GC]),
io:format("Got: ~ts ~w~n", [Other, Other]),
- erlang:raise(_Cl,_R,erlang:get_stacktrace());
- Cl:R ->
+ erlang:raise(_Cl,_R,Stacktrace);
+ Cl:R:Stacktrace ->
io:format("~p: ~ts => |~tp|~n",[LineNo, Data1, C1]),
io:format("Expected: ~p~n", [C3]),
- erlang:raise(Cl,R,erlang:get_stacktrace())
+ erlang:raise(Cl,R,Stacktrace)
end,
C4GC = fetch(C4, fun unicode_util:gc/1),
try
C4GC = fetch(C4, fun unicode_util:nfc/1),
C4GC = fetch(C5, fun unicode_util:nfc/1)
- catch _Cl2:{badmatch, Other2} = _R2->
+ catch _Cl2:{badmatch, Other2} = _R2:Stacktrace2 ->
io:format("Failed: ~p~nInput: ~ts~n\t=> ~w |~ts|~n",[LineNo, Data1, C1, C1]),
io:format("Expected: ~ts ~w~n", [C4GC, C4GC]),
io:format("Got: ~ts ~w~n", [Other2, Other2]),
- erlang:raise(_Cl2,_R2,erlang:get_stacktrace());
- Cl2:R2 ->
+ erlang:raise(_Cl2,_R2,Stacktrace2);
+ Cl2:R2:Stacktrace2 ->
io:format("~p: ~ts => |~tp|~n",[LineNo, Data1, C1]),
io:format("Expected: ~p~n", [C5]),
- erlang:raise(Cl2,R2,erlang:get_stacktrace())
+ erlang:raise(Cl2,R2,Stacktrace2)
end,
ok.
@@ -261,15 +276,15 @@ verify_nfkd(Data0, LineNo, _Acc) ->
C5GC = lists:flatten(fetch(C3, fun unicode_util:nfkd/1)),
C5GC = lists:flatten(fetch(C4, fun unicode_util:nfkd/1)),
C5GC = lists:flatten(fetch(C5, fun unicode_util:nfkd/1))
- catch _Cl:{badmatch, Other} = _R->
+ catch _Cl:{badmatch, Other} = _R:Stacktrace ->
io:format("Failed: ~p~nInput: ~ts~n\t=> ~w |~ts|~n",[LineNo, Data1, C5, C5]),
io:format("Expected: ~ts ~w~n", [C5GC, C5GC]),
io:format("Got: ~ts ~w~n", [Other, Other]),
- erlang:raise(_Cl,_R,erlang:get_stacktrace());
- Cl:R ->
+ erlang:raise(_Cl,_R,Stacktrace);
+ Cl:R:Stacktrace ->
io:format("~p: ~ts => |~tp|~n",[LineNo, Data1, C1]),
io:format("Expected: ~p~n", [C3]),
- erlang:raise(Cl,R,erlang:get_stacktrace())
+ erlang:raise(Cl,R,Stacktrace)
end,
ok.
@@ -294,15 +309,15 @@ verify_nfkc(Data0, LineNo, _Acc) ->
C4GC = lists:flatten(fetch(C4, fun unicode_util:nfkc/1)),
C4GC = lists:flatten(fetch(C5, fun unicode_util:nfkc/1))
- catch _Cl:{badmatch, Other} = _R->
+ catch _Cl:{badmatch, Other} = _R:Stacktrace ->
io:format("Failed: ~p~nInput: ~ts~n\t=> ~w |~ts|~n",[LineNo, Data1, C4, C4]),
io:format("Expected: ~ts ~w~n", [C4GC, C4GC]),
io:format("Got: ~ts ~w~n", [Other, Other]),
- erlang:raise(_Cl,_R,erlang:get_stacktrace());
- Cl:R ->
+ erlang:raise(_Cl,_R,Stacktrace);
+ Cl:R:Stacktrace ->
io:format("~p: ~ts => |~tp|~n",[LineNo, Data1, C1]),
io:format("Expected: ~p~n", [C3]),
- erlang:raise(Cl,R,erlang:get_stacktrace())
+ erlang:raise(Cl,R,Stacktrace)
end,
ok.
@@ -334,7 +349,7 @@ do_measure(Config) ->
File = DataDir ++ "/NormalizationTest.txt",
{ok, Bin} = file:read_file(File),
Do = fun(Func, Mode) ->
- {N, Mean, Stddev, Res} = time_count(Func, Mode, Bin),
+ {N, Mean, Stddev, Res} = time_count(Func, Mode, Bin, 10),
io:format("~4w ~6w ~.10w ~.6wms ±~.2wms #~.2w~n",
[Func, Mode, Res, Mean div 1000, Stddev div 1000, N])
end,
@@ -356,19 +371,19 @@ uc_loaded_size([_|Rest]) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-time_count(Fun, Mode, Bin) ->
+time_count(Fun, Mode, Bin, Repeat) ->
timer:sleep(100), %% Let emulator catch up and clean things before test runs
Self = self(),
Pid = spawn_link(fun() ->
Str = mode(Mode, Bin),
- Self ! {self(),do_count(0,0,0, Fun, Str, undefined)}
+ Self ! {self(),do_count(0,0,0, Fun, Str, undefined, Repeat)}
end),
receive {Pid,Msg} -> Msg end.
-do_count(N,Sum,SumSq, Fun, Str, _) when N < 10 ->
+do_count(N,Sum,SumSq, Fun, Str, _, Repeat) when N < Repeat ->
{Time, Res} = do_count(Fun, Str),
- do_count(N+1,Sum+Time,SumSq+Time*Time, Fun, Str, Res);
-do_count(N,Sum,SumSq, _, _, Res) ->
+ do_count(N+1,Sum+Time,SumSq+Time*Time, Fun, Str, Res, Repeat);
+do_count(N,Sum,SumSq, _, _, Res, _) ->
Mean = round(Sum / N),
Stdev = round(math:sqrt((SumSq - (Sum*Sum/N))/(N - 1))),
{N, Mean, Stdev, Res}.
@@ -413,7 +428,15 @@ mode(deep_l, Bin) -> [unicode:characters_to_list(Bin)].
fetch(Str, F) ->
case F(Str) of
[] -> [];
- [CP|R] -> [CP|fetch(R,F)]
+ [CP|R] ->
+ %% If input is a binary R should be binary
+ if is_binary(Str) == false -> ok;
+ is_binary(R); R =:= [] -> ok;
+ true ->
+ io:format("Char: ~tc Tail:~tP~n", [CP,R,10]),
+ exit({bug, F})
+ end,
+ [CP|fetch(R,F)]
end.
%% *Test.txt file helpers
diff --git a/lib/stdlib/test/unicode_util_SUITE_data/GraphemeBreakTest.txt b/lib/stdlib/test/unicode_util_SUITE_data/GraphemeBreakTest.txt
index 4bb4b1369b..6847953c23 100644
--- a/lib/stdlib/test/unicode_util_SUITE_data/GraphemeBreakTest.txt
+++ b/lib/stdlib/test/unicode_util_SUITE_data/GraphemeBreakTest.txt
@@ -1,849 +1,700 @@
-# GraphemeBreakTest-9.0.0.txt
-# Date: 2016-06-02, 18:28:17 GMT
-# © 2016 Unicode®, Inc.
+# GraphemeBreakTest-11.0.0.txt
+# Date: 2018-03-18, 13:30:33 GMT
+# © 2018 Unicode®, Inc.
# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
# For terms of use, see http://www.unicode.org/terms_of_use.html
#
# Unicode Character Database
# For documentation, see http://www.unicode.org/reports/tr44/
#
-# Default Grapheme Break Test
+# Default Grapheme_Cluster_Break Test
#
# Format:
-# <string> (# <comment>)?
-# <string> contains hex Unicode code points, with
-# ÷ wherever there is a break opportunity, and
+# <string> (# <comment>)?
+# <string> contains hex Unicode code points, with
+# ÷ wherever there is a break opportunity, and
# × wherever there is not.
# <comment> the format can change, but currently it shows:
# - the sample character name
# - (x) the Grapheme_Cluster_Break property value for the sample character
-# - [x] the rule that determines whether there is a break or not
+# - [x] the rule that determines whether there is a break or not,
+# as listed in the Rules section of GraphemeBreakTest.html
#
# These samples may be extended or changed in the future.
#
÷ 0020 ÷ 0020 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 0020 × 0308 ÷ 0020 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 0020 × 0308 ÷ 0020 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
÷ 0020 ÷ 000D ÷ # ÷ [0.2] SPACE (Other) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 0020 × 0308 ÷ 000D ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 0020 × 0308 ÷ 000D ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
÷ 0020 ÷ 000A ÷ # ÷ [0.2] SPACE (Other) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 0020 × 0308 ÷ 000A ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 0020 × 0308 ÷ 000A ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
÷ 0020 ÷ 0001 ÷ # ÷ [0.2] SPACE (Other) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 0020 × 0308 ÷ 0001 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 0020 × 0300 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 0020 × 0308 × 0300 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
+÷ 0020 × 0308 ÷ 0001 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 0020 × 034F ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 0020 × 0308 × 034F ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 0020 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 0020 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
÷ 0020 ÷ 0600 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 0020 × 0308 ÷ 0600 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 0020 × 0308 ÷ 0600 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
÷ 0020 × 0903 ÷ # ÷ [0.2] SPACE (Other) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 0020 × 0308 × 0903 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 0020 × 0308 × 0903 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
÷ 0020 ÷ 1100 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 0020 × 0308 ÷ 1100 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 0020 × 0308 ÷ 1100 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ 0020 ÷ 1160 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 0020 × 0308 ÷ 1160 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 0020 × 0308 ÷ 1160 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
÷ 0020 ÷ 11A8 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 0020 × 0308 ÷ 11A8 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 0020 × 0308 ÷ 11A8 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
÷ 0020 ÷ AC00 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 0020 × 0308 ÷ AC00 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 0020 × 0308 ÷ AC00 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
÷ 0020 ÷ AC01 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 0020 × 0308 ÷ AC01 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 0020 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 0020 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 0020 ÷ 261D ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 0020 × 0308 ÷ 261D ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 0020 ÷ 1F3FB ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 0020 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 0020 × 200D ÷ # ÷ [0.2] SPACE (Other) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 0020 × 0308 × 200D ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 0020 ÷ 2764 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 0020 × 0308 ÷ 2764 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 0020 ÷ 1F466 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 0020 × 0308 ÷ 1F466 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
+÷ 0020 × 0308 ÷ AC01 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 0020 ÷ 231A ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 0020 × 0308 ÷ 231A ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 0020 × 0300 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 0020 × 0308 × 0300 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 0020 × 200D ÷ # ÷ [0.2] SPACE (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 0020 × 0308 × 200D ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
÷ 0020 ÷ 0378 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 0020 × 0308 ÷ 0378 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 0020 × 0308 ÷ 0378 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
÷ 0020 ÷ D800 ÷ # ÷ [0.2] SPACE (Other) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 0020 × 0308 ÷ D800 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 0020 × 0308 ÷ D800 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
÷ 000D ÷ 0020 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] SPACE (Other) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 000D ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
÷ 000D ÷ 000D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ 000D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 000D ÷ 0308 ÷ 000D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
÷ 000D × 000A ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) × [3.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ 000A ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 000D ÷ 0308 ÷ 000A ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
÷ 000D ÷ 0001 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 000D ÷ 0300 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 000D ÷ 0308 × 0300 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
+÷ 000D ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 000D ÷ 034F ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 000D ÷ 0308 × 034F ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 000D ÷ 1F1E6 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 000D ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
÷ 000D ÷ 0600 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 000D ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
÷ 000D ÷ 0903 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 000D ÷ 0308 × 0903 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 000D ÷ 0308 × 0903 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
÷ 000D ÷ 1100 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 000D ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ 000D ÷ 1160 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 000D ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
÷ 000D ÷ 11A8 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 000D ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
÷ 000D ÷ AC00 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 000D ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
÷ 000D ÷ AC01 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 000D ÷ 1F1E6 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 000D ÷ 261D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ 261D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 000D ÷ 1F3FB ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ 1F3FB ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 000D ÷ 200D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 000D ÷ 0308 × 200D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 000D ÷ 2764 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ 2764 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 000D ÷ 1F466 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] BOY (EBG) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ 1F466 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
+÷ 000D ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 000D ÷ 231A ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] WATCH (ExtPict) ÷ [0.3]
+÷ 000D ÷ 0308 ÷ 231A ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 000D ÷ 0300 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 000D ÷ 0308 × 0300 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 000D ÷ 200D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 000D ÷ 0308 × 200D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
÷ 000D ÷ 0378 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 000D ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
÷ 000D ÷ D800 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ D800 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 000D ÷ 0308 ÷ D800 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
÷ 000A ÷ 0020 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] SPACE (Other) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 000A ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
÷ 000A ÷ 000D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ 000D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 000A ÷ 0308 ÷ 000D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
÷ 000A ÷ 000A ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ 000A ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 000A ÷ 0308 ÷ 000A ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
÷ 000A ÷ 0001 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 000A ÷ 0300 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 000A ÷ 0308 × 0300 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
+÷ 000A ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 000A ÷ 034F ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 000A ÷ 0308 × 034F ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 000A ÷ 1F1E6 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 000A ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
÷ 000A ÷ 0600 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 000A ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
÷ 000A ÷ 0903 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 000A ÷ 0308 × 0903 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 000A ÷ 0308 × 0903 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
÷ 000A ÷ 1100 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 000A ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ 000A ÷ 1160 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 000A ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
÷ 000A ÷ 11A8 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 000A ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
÷ 000A ÷ AC00 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 000A ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
÷ 000A ÷ AC01 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 000A ÷ 1F1E6 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 000A ÷ 261D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ 261D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 000A ÷ 1F3FB ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ 1F3FB ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 000A ÷ 200D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 000A ÷ 0308 × 200D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 000A ÷ 2764 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ 2764 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 000A ÷ 1F466 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] BOY (EBG) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ 1F466 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
+÷ 000A ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 000A ÷ 231A ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] WATCH (ExtPict) ÷ [0.3]
+÷ 000A ÷ 0308 ÷ 231A ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 000A ÷ 0300 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 000A ÷ 0308 × 0300 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 000A ÷ 200D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 000A ÷ 0308 × 200D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
÷ 000A ÷ 0378 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 000A ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
÷ 000A ÷ D800 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ D800 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 000A ÷ 0308 ÷ D800 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
÷ 0001 ÷ 0020 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] SPACE (Other) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 0001 ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
÷ 0001 ÷ 000D ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ 000D ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 0001 ÷ 0308 ÷ 000D ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
÷ 0001 ÷ 000A ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ 000A ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 0001 ÷ 0308 ÷ 000A ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
÷ 0001 ÷ 0001 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 0001 ÷ 0300 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 0001 ÷ 0308 × 0300 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
+÷ 0001 ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 0001 ÷ 034F ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 0001 ÷ 0308 × 034F ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 0001 ÷ 1F1E6 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 0001 ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
÷ 0001 ÷ 0600 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 0001 ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
÷ 0001 ÷ 0903 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 0001 ÷ 0308 × 0903 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 0001 ÷ 0308 × 0903 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
÷ 0001 ÷ 1100 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 0001 ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ 0001 ÷ 1160 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 0001 ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
÷ 0001 ÷ 11A8 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 0001 ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
÷ 0001 ÷ AC00 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 0001 ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
÷ 0001 ÷ AC01 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 0001 ÷ 1F1E6 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 0001 ÷ 261D ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ 261D ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 0001 ÷ 1F3FB ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ 1F3FB ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 0001 ÷ 200D ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 0001 ÷ 0308 × 200D ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 0001 ÷ 2764 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ 2764 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 0001 ÷ 1F466 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] BOY (EBG) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ 1F466 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
+÷ 0001 ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 0001 ÷ 231A ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] WATCH (ExtPict) ÷ [0.3]
+÷ 0001 ÷ 0308 ÷ 231A ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 0001 ÷ 0300 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 0001 ÷ 0308 × 0300 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 0001 ÷ 200D ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 0001 ÷ 0308 × 200D ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
÷ 0001 ÷ 0378 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 0001 ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
÷ 0001 ÷ D800 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ D800 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 0300 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 0300 × 0308 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 0300 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 0300 × 0308 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 0300 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 0300 × 0308 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 0300 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 0300 × 0308 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 0300 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 0300 × 0308 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 0300 ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 0300 × 0308 ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 0300 × 0903 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 0300 × 0308 × 0903 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 0300 ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 0300 × 0308 ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 0300 ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 0300 × 0308 ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 0300 ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 0300 × 0308 ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 0300 ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 0300 × 0308 ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 0300 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 0300 × 0308 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 0300 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 0300 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 0300 ÷ 261D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 0300 × 0308 ÷ 261D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 0300 ÷ 1F3FB ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 0300 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 0300 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 0300 × 0308 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 0300 ÷ 2764 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 0300 × 0308 ÷ 2764 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 0300 ÷ 1F466 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 0300 × 0308 ÷ 1F466 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 0300 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 0300 × 0308 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 0300 ÷ D800 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 0300 × 0308 ÷ D800 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 0001 ÷ 0308 ÷ D800 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 034F ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 034F × 0308 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 034F ÷ 000D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 034F × 0308 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 034F ÷ 000A ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 034F × 0308 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 034F ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 034F × 0308 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 034F × 034F ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 034F × 0308 × 034F ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 034F ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 034F × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 034F ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 034F × 0308 ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 034F × 0903 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 034F × 0308 × 0903 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 034F ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 034F × 0308 ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 034F ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 034F × 0308 ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 034F ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 034F × 0308 ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 034F ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 034F × 0308 ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 034F ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 034F × 0308 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 034F ÷ 231A ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 034F × 0308 ÷ 231A ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 034F × 0300 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 034F × 0308 × 0300 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 034F × 200D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 034F × 0308 × 200D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 034F ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 034F × 0308 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 034F ÷ D800 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 034F × 0308 ÷ D800 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 1F1E6 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 1F1E6 × 0308 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 1F1E6 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 1F1E6 × 0308 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 1F1E6 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 1F1E6 × 0308 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 1F1E6 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 1F1E6 × 0308 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 1F1E6 × 034F ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 1F1E6 × 0308 × 034F ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 1F1E6 × 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [12.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 1F1E6 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 1F1E6 ÷ 0600 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 1F1E6 × 0308 ÷ 0600 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 1F1E6 × 0903 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 1F1E6 × 0308 × 0903 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 1F1E6 ÷ 1100 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 1F1E6 × 0308 ÷ 1100 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 1F1E6 ÷ 1160 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 1F1E6 × 0308 ÷ 1160 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 1F1E6 ÷ 11A8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 1F1E6 × 0308 ÷ 11A8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 1F1E6 ÷ AC00 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 1F1E6 × 0308 ÷ AC00 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 1F1E6 ÷ AC01 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 1F1E6 × 0308 ÷ AC01 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 1F1E6 ÷ 231A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 1F1E6 × 0308 ÷ 231A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 1F1E6 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 1F1E6 × 0308 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 1F1E6 × 200D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 1F1E6 × 0308 × 200D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 1F1E6 ÷ 0378 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 1F1E6 × 0308 ÷ 0378 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 1F1E6 ÷ D800 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 1F1E6 × 0308 ÷ D800 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
÷ 0600 × 0020 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] SPACE (Other) ÷ [0.3]
-÷ 0600 × 0308 ÷ 0020 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 0600 × 0308 ÷ 0020 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
÷ 0600 ÷ 000D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 0600 × 0308 ÷ 000D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 0600 × 0308 ÷ 000D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
÷ 0600 ÷ 000A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 0600 × 0308 ÷ 000A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 0600 × 0308 ÷ 000A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
÷ 0600 ÷ 0001 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 0600 × 0308 ÷ 0001 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 0600 × 0300 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 0600 × 0308 × 0300 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
+÷ 0600 × 0308 ÷ 0001 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 0600 × 034F ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 0600 × 0308 × 034F ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 0600 × 1F1E6 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 0600 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
÷ 0600 × 0600 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 0600 × 0308 ÷ 0600 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 0600 × 0308 ÷ 0600 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
÷ 0600 × 0903 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 0600 × 0308 × 0903 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 0600 × 0308 × 0903 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
÷ 0600 × 1100 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 0600 × 0308 ÷ 1100 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 0600 × 0308 ÷ 1100 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ 0600 × 1160 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 0600 × 0308 ÷ 1160 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 0600 × 0308 ÷ 1160 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
÷ 0600 × 11A8 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 0600 × 0308 ÷ 11A8 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 0600 × 0308 ÷ 11A8 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
÷ 0600 × AC00 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 0600 × 0308 ÷ AC00 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 0600 × 0308 ÷ AC00 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
÷ 0600 × AC01 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 0600 × 0308 ÷ AC01 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 0600 × 1F1E6 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 0600 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 0600 × 261D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 0600 × 0308 ÷ 261D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 0600 × 1F3FB ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 0600 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 0600 × 200D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 0600 × 0308 × 200D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 0600 × 2764 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 0600 × 0308 ÷ 2764 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 0600 × 1F466 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] BOY (EBG) ÷ [0.3]
-÷ 0600 × 0308 ÷ 1F466 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
+÷ 0600 × 0308 ÷ AC01 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 0600 × 231A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] WATCH (ExtPict) ÷ [0.3]
+÷ 0600 × 0308 ÷ 231A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 0600 × 0300 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 0600 × 0308 × 0300 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 0600 × 200D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 0600 × 0308 × 200D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
÷ 0600 × 0378 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] <reserved-0378> (Other) ÷ [0.3]
-÷ 0600 × 0308 ÷ 0378 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 0600 × 0308 ÷ 0378 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
÷ 0600 ÷ D800 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 0600 × 0308 ÷ D800 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 0600 × 0308 ÷ D800 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
÷ 0903 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 0903 × 0308 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 0903 × 0308 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
÷ 0903 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 0903 × 0308 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 0903 × 0308 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
÷ 0903 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 0903 × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 0903 × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
÷ 0903 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 0903 × 0308 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 0903 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 0903 × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
+÷ 0903 × 0308 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 0903 × 034F ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 0903 × 0308 × 034F ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 0903 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 0903 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
÷ 0903 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 0903 × 0308 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 0903 × 0308 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
÷ 0903 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 0903 × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 0903 × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
÷ 0903 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 0903 × 0308 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 0903 × 0308 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ 0903 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 0903 × 0308 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 0903 × 0308 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
÷ 0903 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 0903 × 0308 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 0903 × 0308 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
÷ 0903 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 0903 × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 0903 × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
÷ 0903 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 0903 × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 0903 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 0903 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 0903 ÷ 261D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 0903 × 0308 ÷ 261D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 0903 ÷ 1F3FB ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 0903 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 0903 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 0903 × 0308 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 0903 ÷ 2764 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 0903 × 0308 ÷ 2764 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 0903 ÷ 1F466 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 0903 × 0308 ÷ 1F466 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
+÷ 0903 × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 0903 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 0903 × 0308 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 0903 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 0903 × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 0903 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 0903 × 0308 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
÷ 0903 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 0903 × 0308 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 0903 × 0308 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
÷ 0903 ÷ D800 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 0903 × 0308 ÷ D800 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 0903 × 0308 ÷ D800 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
÷ 1100 ÷ 0020 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 1100 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 1100 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
÷ 1100 ÷ 000D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 1100 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 1100 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
÷ 1100 ÷ 000A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 1100 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 1100 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
÷ 1100 ÷ 0001 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 1100 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 1100 × 0300 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 1100 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
+÷ 1100 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 1100 × 034F ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 1100 × 0308 × 034F ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 1100 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 1100 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
÷ 1100 ÷ 0600 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 1100 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 1100 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
÷ 1100 × 0903 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 1100 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 1100 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
÷ 1100 × 1100 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 1100 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 1100 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ 1100 × 1160 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 1100 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 1100 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
÷ 1100 ÷ 11A8 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 1100 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 1100 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
÷ 1100 × AC00 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 1100 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 1100 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
÷ 1100 × AC01 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 1100 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 1100 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 1100 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 1100 ÷ 261D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 1100 × 0308 ÷ 261D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 1100 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 1100 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 1100 × 200D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 1100 × 0308 × 200D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 1100 ÷ 2764 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 1100 × 0308 ÷ 2764 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 1100 ÷ 1F466 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 1100 × 0308 ÷ 1F466 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
+÷ 1100 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 1100 ÷ 231A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 1100 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 1100 × 0300 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 1100 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 1100 × 200D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 1100 × 0308 × 200D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
÷ 1100 ÷ 0378 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 1100 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 1100 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
÷ 1100 ÷ D800 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 1100 × 0308 ÷ D800 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 1100 × 0308 ÷ D800 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
÷ 1160 ÷ 0020 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 1160 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 1160 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
÷ 1160 ÷ 000D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 1160 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 1160 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
÷ 1160 ÷ 000A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 1160 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 1160 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
÷ 1160 ÷ 0001 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 1160 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 1160 × 0300 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 1160 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
+÷ 1160 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 1160 × 034F ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 1160 × 0308 × 034F ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 1160 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 1160 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
÷ 1160 ÷ 0600 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 1160 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 1160 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
÷ 1160 × 0903 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 1160 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 1160 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
÷ 1160 ÷ 1100 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 1160 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 1160 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ 1160 × 1160 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [7.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 1160 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 1160 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
÷ 1160 × 11A8 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [7.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 1160 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 1160 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
÷ 1160 ÷ AC00 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 1160 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 1160 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
÷ 1160 ÷ AC01 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 1160 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 1160 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 1160 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 1160 ÷ 261D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 1160 × 0308 ÷ 261D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 1160 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 1160 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 1160 × 200D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 1160 × 0308 × 200D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 1160 ÷ 2764 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 1160 × 0308 ÷ 2764 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 1160 ÷ 1F466 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 1160 × 0308 ÷ 1F466 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
+÷ 1160 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 1160 ÷ 231A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 1160 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 1160 × 0300 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 1160 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 1160 × 200D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 1160 × 0308 × 200D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
÷ 1160 ÷ 0378 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 1160 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 1160 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
÷ 1160 ÷ D800 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 1160 × 0308 ÷ D800 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 1160 × 0308 ÷ D800 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
÷ 11A8 ÷ 0020 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 11A8 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 11A8 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
÷ 11A8 ÷ 000D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 11A8 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 11A8 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
÷ 11A8 ÷ 000A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 11A8 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 11A8 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
÷ 11A8 ÷ 0001 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 11A8 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 11A8 × 0300 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 11A8 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
+÷ 11A8 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 11A8 × 034F ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 11A8 × 0308 × 034F ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 11A8 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 11A8 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
÷ 11A8 ÷ 0600 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 11A8 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 11A8 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
÷ 11A8 × 0903 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 11A8 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 11A8 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
÷ 11A8 ÷ 1100 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 11A8 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 11A8 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ 11A8 ÷ 1160 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 11A8 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 11A8 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
÷ 11A8 × 11A8 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [8.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 11A8 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 11A8 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
÷ 11A8 ÷ AC00 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 11A8 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 11A8 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
÷ 11A8 ÷ AC01 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 11A8 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 11A8 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 11A8 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 11A8 ÷ 261D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 11A8 × 0308 ÷ 261D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 11A8 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 11A8 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 11A8 × 200D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 11A8 × 0308 × 200D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 11A8 ÷ 2764 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 11A8 × 0308 ÷ 2764 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 11A8 ÷ 1F466 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 11A8 × 0308 ÷ 1F466 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
+÷ 11A8 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 11A8 ÷ 231A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 11A8 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 11A8 × 0300 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 11A8 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 11A8 × 200D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 11A8 × 0308 × 200D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
÷ 11A8 ÷ 0378 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 11A8 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 11A8 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
÷ 11A8 ÷ D800 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 11A8 × 0308 ÷ D800 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 11A8 × 0308 ÷ D800 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
÷ AC00 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ AC00 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ AC00 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
÷ AC00 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ AC00 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ AC00 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
÷ AC00 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ AC00 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ AC00 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
÷ AC00 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ AC00 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ AC00 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ AC00 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
+÷ AC00 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ AC00 × 034F ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ AC00 × 0308 × 034F ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ AC00 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ AC00 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
÷ AC00 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ AC00 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ AC00 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
÷ AC00 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ AC00 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ AC00 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
÷ AC00 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ AC00 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ AC00 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ AC00 × 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [7.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ AC00 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ AC00 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
÷ AC00 × 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [7.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ AC00 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ AC00 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
÷ AC00 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ AC00 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ AC00 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
÷ AC00 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ AC00 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ AC00 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ AC00 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ AC00 ÷ 261D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ AC00 × 0308 ÷ 261D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ AC00 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ AC00 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ AC00 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ AC00 × 0308 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ AC00 ÷ 2764 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ AC00 × 0308 ÷ 2764 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ AC00 ÷ 1F466 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ AC00 × 0308 ÷ 1F466 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
+÷ AC00 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ AC00 ÷ 231A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ AC00 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ AC00 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ AC00 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ AC00 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ AC00 × 0308 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
÷ AC00 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ AC00 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ AC00 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
÷ AC00 ÷ D800 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ AC00 × 0308 ÷ D800 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ AC00 × 0308 ÷ D800 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
÷ AC01 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ AC01 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ AC01 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
÷ AC01 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ AC01 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ AC01 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
÷ AC01 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ AC01 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ AC01 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
÷ AC01 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ AC01 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ AC01 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ AC01 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
+÷ AC01 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ AC01 × 034F ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ AC01 × 0308 × 034F ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ AC01 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ AC01 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
÷ AC01 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ AC01 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ AC01 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
÷ AC01 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ AC01 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ AC01 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
÷ AC01 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ AC01 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ AC01 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ AC01 ÷ 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ AC01 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ AC01 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
÷ AC01 × 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [8.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ AC01 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ AC01 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
÷ AC01 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ AC01 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ AC01 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
÷ AC01 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ AC01 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ AC01 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ AC01 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ AC01 ÷ 261D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ AC01 × 0308 ÷ 261D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ AC01 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ AC01 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ AC01 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ AC01 × 0308 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ AC01 ÷ 2764 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ AC01 × 0308 ÷ 2764 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ AC01 ÷ 1F466 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ AC01 × 0308 ÷ 1F466 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
+÷ AC01 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ AC01 ÷ 231A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ AC01 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ AC01 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ AC01 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ AC01 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ AC01 × 0308 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
÷ AC01 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ AC01 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ AC01 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
÷ AC01 ÷ D800 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ AC01 × 0308 ÷ D800 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 1F1E6 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 1F1E6 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 1F1E6 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 1F1E6 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 1F1E6 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 1F1E6 × 0308 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 1F1E6 ÷ 0600 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ 0600 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 1F1E6 × 0903 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 1F1E6 × 0308 × 0903 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 1F1E6 ÷ 1100 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ 1100 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 1F1E6 ÷ 1160 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ 1160 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 1F1E6 ÷ 11A8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ 11A8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 1F1E6 ÷ AC00 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ AC00 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 1F1E6 ÷ AC01 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ AC01 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 1F1E6 × 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [12.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 1F1E6 ÷ 261D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ 261D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 1F1E6 ÷ 1F3FB ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 1F1E6 × 200D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 1F1E6 × 0308 × 200D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 1F1E6 ÷ 2764 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ 2764 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 1F1E6 ÷ 1F466 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ 1F466 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 1F1E6 ÷ 0378 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ 0378 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 1F1E6 ÷ D800 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ D800 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 261D ÷ 0020 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 261D × 0308 ÷ 0020 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 261D ÷ 000D ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 261D × 0308 ÷ 000D ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 261D ÷ 000A ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 261D × 0308 ÷ 000A ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 261D ÷ 0001 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 261D × 0308 ÷ 0001 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 261D × 0300 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 261D × 0308 × 0300 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 261D ÷ 0600 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 261D × 0308 ÷ 0600 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 261D × 0903 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 261D × 0308 × 0903 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 261D ÷ 1100 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 261D × 0308 ÷ 1100 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 261D ÷ 1160 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 261D × 0308 ÷ 1160 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 261D ÷ 11A8 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 261D × 0308 ÷ 11A8 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 261D ÷ AC00 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 261D × 0308 ÷ AC00 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 261D ÷ AC01 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 261D × 0308 ÷ AC01 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 261D ÷ 1F1E6 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 261D × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 261D ÷ 261D ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 261D × 0308 ÷ 261D ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 261D × 1F3FB ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [10.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 261D × 0308 × 1F3FB ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) × [10.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 261D × 200D ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 261D × 0308 × 200D ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 261D ÷ 2764 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 261D × 0308 ÷ 2764 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 261D ÷ 1F466 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 261D × 0308 ÷ 1F466 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 261D ÷ 0378 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 261D × 0308 ÷ 0378 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 261D ÷ D800 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 261D × 0308 ÷ D800 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 1F3FB ÷ 0020 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ 0020 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 1F3FB ÷ 000D ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ 000D ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 1F3FB ÷ 000A ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ 000A ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 1F3FB ÷ 0001 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ 0001 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 1F3FB × 0300 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 1F3FB × 0308 × 0300 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 1F3FB ÷ 0600 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ 0600 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 1F3FB × 0903 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 1F3FB × 0308 × 0903 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 1F3FB ÷ 1100 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ 1100 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 1F3FB ÷ 1160 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ 1160 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 1F3FB ÷ 11A8 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ 11A8 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 1F3FB ÷ AC00 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ AC00 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 1F3FB ÷ AC01 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ AC01 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 1F3FB ÷ 1F1E6 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 1F3FB ÷ 261D ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ 261D ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 1F3FB ÷ 1F3FB ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ 1F3FB ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 1F3FB × 200D ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 1F3FB × 0308 × 200D ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 1F3FB ÷ 2764 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ 2764 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 1F3FB ÷ 1F466 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ 1F466 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 1F3FB ÷ 0378 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ 0378 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 1F3FB ÷ D800 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ D800 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 200D ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 200D × 0308 ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 200D ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 200D × 0308 ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 200D ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 200D × 0308 ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 200D ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 200D × 0308 ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 200D × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 200D × 0308 × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 200D ÷ 0600 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 200D × 0308 ÷ 0600 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 200D × 0903 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 200D × 0308 × 0903 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 200D ÷ 1100 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 200D × 0308 ÷ 1100 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 200D ÷ 1160 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 200D × 0308 ÷ 1160 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 200D ÷ 11A8 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 200D × 0308 ÷ 11A8 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 200D ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 200D × 0308 ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 200D ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 200D × 0308 ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 200D ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 200D × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 200D ÷ 261D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 200D × 0308 ÷ 261D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 200D ÷ 1F3FB ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 200D × 0308 ÷ 1F3FB ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 200D × 200D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 200D × 0308 × 200D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 200D × 2764 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [11.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 200D × 0308 ÷ 2764 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 200D × 1F466 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [11.0] BOY (EBG) ÷ [0.3]
-÷ 200D × 0308 ÷ 1F466 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 200D ÷ 0378 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 200D × 0308 ÷ 0378 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 200D ÷ D800 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 200D × 0308 ÷ D800 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 2764 ÷ 0020 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 2764 × 0308 ÷ 0020 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 2764 ÷ 000D ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 2764 × 0308 ÷ 000D ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 2764 ÷ 000A ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 2764 × 0308 ÷ 000A ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 2764 ÷ 0001 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 2764 × 0308 ÷ 0001 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 2764 × 0300 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 2764 × 0308 × 0300 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 2764 ÷ 0600 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 2764 × 0308 ÷ 0600 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 2764 × 0903 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 2764 × 0308 × 0903 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 2764 ÷ 1100 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 2764 × 0308 ÷ 1100 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 2764 ÷ 1160 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 2764 × 0308 ÷ 1160 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 2764 ÷ 11A8 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 2764 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 2764 ÷ AC00 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 2764 × 0308 ÷ AC00 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 2764 ÷ AC01 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 2764 × 0308 ÷ AC01 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 2764 ÷ 1F1E6 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 2764 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 2764 ÷ 261D ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 2764 × 0308 ÷ 261D ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 2764 ÷ 1F3FB ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 2764 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 2764 × 200D ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 2764 × 0308 × 200D ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 2764 ÷ 2764 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 2764 × 0308 ÷ 2764 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 2764 ÷ 1F466 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 2764 × 0308 ÷ 1F466 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 2764 ÷ 0378 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 2764 × 0308 ÷ 0378 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 2764 ÷ D800 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 2764 × 0308 ÷ D800 ÷ # ÷ [0.2] HEAVY BLACK HEART (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 1F466 ÷ 0020 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 1F466 × 0308 ÷ 0020 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 1F466 ÷ 000D ÷ # ÷ [0.2] BOY (EBG) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 1F466 × 0308 ÷ 000D ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 1F466 ÷ 000A ÷ # ÷ [0.2] BOY (EBG) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 1F466 × 0308 ÷ 000A ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 1F466 ÷ 0001 ÷ # ÷ [0.2] BOY (EBG) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 1F466 × 0308 ÷ 0001 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 1F466 × 0300 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 1F466 × 0308 × 0300 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 1F466 ÷ 0600 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 1F466 × 0308 ÷ 0600 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 1F466 × 0903 ÷ # ÷ [0.2] BOY (EBG) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 1F466 × 0308 × 0903 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 1F466 ÷ 1100 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 1F466 × 0308 ÷ 1100 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 1F466 ÷ 1160 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 1F466 × 0308 ÷ 1160 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 1F466 ÷ 11A8 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 1F466 × 0308 ÷ 11A8 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 1F466 ÷ AC00 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 1F466 × 0308 ÷ AC00 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 1F466 ÷ AC01 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 1F466 × 0308 ÷ AC01 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 1F466 ÷ 1F1E6 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 1F466 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 1F466 ÷ 261D ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 1F466 × 0308 ÷ 261D ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 1F466 × 1F3FB ÷ # ÷ [0.2] BOY (EBG) × [10.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 1F466 × 0308 × 1F3FB ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) × [10.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 1F466 × 200D ÷ # ÷ [0.2] BOY (EBG) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 1F466 × 0308 × 200D ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 1F466 ÷ 2764 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 1F466 × 0308 ÷ 2764 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 1F466 ÷ 1F466 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 1F466 × 0308 ÷ 1F466 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 1F466 ÷ 0378 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 1F466 × 0308 ÷ 0378 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 1F466 ÷ D800 ÷ # ÷ [0.2] BOY (EBG) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 1F466 × 0308 ÷ D800 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ AC01 × 0308 ÷ D800 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 231A ÷ 0020 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 231A × 0308 ÷ 0020 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 231A ÷ 000D ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 231A × 0308 ÷ 000D ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 231A ÷ 000A ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 231A × 0308 ÷ 000A ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 231A ÷ 0001 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 231A × 0308 ÷ 0001 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 231A × 034F ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 231A × 0308 × 034F ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 231A ÷ 1F1E6 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 231A × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 231A ÷ 0600 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 231A × 0308 ÷ 0600 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 231A × 0903 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 231A × 0308 × 0903 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 231A ÷ 1100 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 231A × 0308 ÷ 1100 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 231A ÷ 1160 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 231A × 0308 ÷ 1160 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 231A ÷ 11A8 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 231A × 0308 ÷ 11A8 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 231A ÷ AC00 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 231A × 0308 ÷ AC00 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 231A ÷ AC01 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 231A × 0308 ÷ AC01 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 231A ÷ 231A ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 231A × 0308 ÷ 231A ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 231A × 0300 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 231A × 0308 × 0300 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 231A × 200D ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 231A × 0308 × 200D ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 231A ÷ 0378 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 231A × 0308 ÷ 0378 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 231A ÷ D800 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 231A × 0308 ÷ D800 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 0300 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 0300 × 0308 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 0300 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 0300 × 0308 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 0300 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 0300 × 0308 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 0300 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 0300 × 0308 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 0300 × 034F ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 0300 × 0308 × 034F ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 0300 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 0300 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 0300 ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 0300 × 0308 ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 0300 × 0903 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 0300 × 0308 × 0903 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 0300 ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 0300 × 0308 ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 0300 ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 0300 × 0308 ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 0300 ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 0300 × 0308 ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 0300 ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 0300 × 0308 ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 0300 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 0300 × 0308 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 0300 ÷ 231A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 0300 × 0308 ÷ 231A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 0300 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 0300 × 0308 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 0300 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 0300 × 0308 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 0300 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 0300 × 0308 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 0300 ÷ D800 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 0300 × 0308 ÷ D800 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 200D ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 200D × 0308 ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 200D ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 200D × 0308 ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 200D ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 200D × 0308 ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 200D ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 200D × 0308 ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 200D × 034F ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 200D × 0308 × 034F ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 200D ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 200D × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 200D ÷ 0600 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 200D × 0308 ÷ 0600 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 200D × 0903 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 200D × 0308 × 0903 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 200D ÷ 1100 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 200D × 0308 ÷ 1100 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 200D ÷ 1160 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 200D × 0308 ÷ 1160 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 200D ÷ 11A8 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 200D × 0308 ÷ 11A8 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 200D ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 200D × 0308 ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 200D ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 200D × 0308 ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 200D ÷ 231A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 200D × 0308 ÷ 231A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 200D × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 200D × 0308 × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 200D × 200D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 200D × 0308 × 200D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 200D ÷ 0378 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 200D × 0308 ÷ 0378 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 200D ÷ D800 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 200D × 0308 ÷ D800 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
÷ 0378 ÷ 0020 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 0378 × 0308 ÷ 0020 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 0378 × 0308 ÷ 0020 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
÷ 0378 ÷ 000D ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 0378 × 0308 ÷ 000D ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 0378 × 0308 ÷ 000D ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
÷ 0378 ÷ 000A ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 0378 × 0308 ÷ 000A ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 0378 × 0308 ÷ 000A ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
÷ 0378 ÷ 0001 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 0378 × 0308 ÷ 0001 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 0378 × 0300 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 0378 × 0308 × 0300 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
+÷ 0378 × 0308 ÷ 0001 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 0378 × 034F ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 0378 × 0308 × 034F ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 0378 ÷ 1F1E6 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 0378 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
÷ 0378 ÷ 0600 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 0378 × 0308 ÷ 0600 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 0378 × 0308 ÷ 0600 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
÷ 0378 × 0903 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 0378 × 0308 × 0903 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 0378 × 0308 × 0903 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
÷ 0378 ÷ 1100 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 0378 × 0308 ÷ 1100 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 0378 × 0308 ÷ 1100 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ 0378 ÷ 1160 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 0378 × 0308 ÷ 1160 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 0378 × 0308 ÷ 1160 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
÷ 0378 ÷ 11A8 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 0378 × 0308 ÷ 11A8 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 0378 × 0308 ÷ 11A8 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
÷ 0378 ÷ AC00 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 0378 × 0308 ÷ AC00 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 0378 × 0308 ÷ AC00 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
÷ 0378 ÷ AC01 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 0378 × 0308 ÷ AC01 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 0378 ÷ 1F1E6 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 0378 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 0378 ÷ 261D ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 0378 × 0308 ÷ 261D ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 0378 ÷ 1F3FB ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 0378 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 0378 × 200D ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 0378 × 0308 × 200D ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 0378 ÷ 2764 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 0378 × 0308 ÷ 2764 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 0378 ÷ 1F466 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 0378 × 0308 ÷ 1F466 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
+÷ 0378 × 0308 ÷ AC01 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 0378 ÷ 231A ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 0378 × 0308 ÷ 231A ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 0378 × 0300 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 0378 × 0308 × 0300 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 0378 × 200D ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 0378 × 0308 × 200D ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
÷ 0378 ÷ 0378 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 0378 × 0308 ÷ 0378 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 0378 × 0308 ÷ 0378 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
÷ 0378 ÷ D800 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 0378 × 0308 ÷ D800 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 0378 × 0308 ÷ D800 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
÷ D800 ÷ 0020 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] SPACE (Other) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ D800 ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
÷ D800 ÷ 000D ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ 000D ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ D800 ÷ 0308 ÷ 000D ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
÷ D800 ÷ 000A ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ 000A ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ D800 ÷ 0308 ÷ 000A ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
÷ D800 ÷ 0001 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ D800 ÷ 0300 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ D800 ÷ 0308 × 0300 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
+÷ D800 ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ D800 ÷ 034F ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ D800 ÷ 0308 × 034F ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ D800 ÷ 1F1E6 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ D800 ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
÷ D800 ÷ 0600 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ D800 ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
÷ D800 ÷ 0903 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ D800 ÷ 0308 × 0903 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ D800 ÷ 0308 × 0903 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
÷ D800 ÷ 1100 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ D800 ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ D800 ÷ 1160 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ D800 ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
÷ D800 ÷ 11A8 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ D800 ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
÷ D800 ÷ AC00 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ D800 ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
÷ D800 ÷ AC01 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ D800 ÷ 1F1E6 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ D800 ÷ 261D ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ 261D ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ D800 ÷ 1F3FB ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ 1F3FB ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ D800 ÷ 200D ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ D800 ÷ 0308 × 200D ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ D800 ÷ 2764 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ 2764 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ D800 ÷ 1F466 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] BOY (EBG) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ 1F466 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
+÷ D800 ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ D800 ÷ 231A ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] WATCH (ExtPict) ÷ [0.3]
+÷ D800 ÷ 0308 ÷ 231A ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ D800 ÷ 0300 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ D800 ÷ 0308 × 0300 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ D800 ÷ 200D ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ D800 ÷ 0308 × 200D ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
÷ D800 ÷ 0378 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] <reserved-0378> (Other) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ D800 ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
÷ D800 ÷ D800 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ D800 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 000D × 000A ÷ 0061 ÷ 000A ÷ 0308 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) × [3.0] <LINE FEED (LF)> (LF) ÷ [4.0] LATIN SMALL LETTER A (Other) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [0.3]
-÷ 0061 × 0308 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [0.3]
-÷ 0020 × 200D ÷ 0646 ÷ # ÷ [0.2] SPACE (Other) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] ARABIC LETTER NOON (Other) ÷ [0.3]
-÷ 0646 × 200D ÷ 0020 ÷ # ÷ [0.2] ARABIC LETTER NOON (Other) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ D800 ÷ 0308 ÷ D800 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 000D × 000A ÷ 0061 ÷ 000A ÷ 0308 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) × [3.0] <LINE FEED (LF)> (LF) ÷ [4.0] LATIN SMALL LETTER A (Other) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [0.3]
+÷ 0061 × 0308 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [0.3]
+÷ 0020 × 200D ÷ 0646 ÷ # ÷ [0.2] SPACE (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] ARABIC LETTER NOON (Other) ÷ [0.3]
+÷ 0646 × 200D ÷ 0020 ÷ # ÷ [0.2] ARABIC LETTER NOON (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
÷ 1100 × 1100 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ AC00 × 11A8 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [7.0] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ AC01 × 11A8 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [8.0] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ 1F1E6 × 1F1E7 ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [12.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3]
÷ 0061 ÷ 1F1E6 × 1F1E7 ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3]
-÷ 0061 ÷ 1F1E6 × 1F1E7 × 200D ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3]
-÷ 0061 ÷ 1F1E6 × 200D ÷ 1F1E7 × 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3]
+÷ 0061 ÷ 1F1E6 × 1F1E7 × 200D ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3]
+÷ 0061 ÷ 1F1E6 × 200D ÷ 1F1E7 × 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3]
÷ 0061 ÷ 1F1E6 × 1F1E7 ÷ 1F1E8 × 1F1E9 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER D (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3]
-÷ 0061 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 0061 × 0308 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3]
+÷ 0061 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 0061 × 0308 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3]
÷ 0061 × 0903 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3]
÷ 0061 ÷ 0600 × 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) × [9.2] LATIN SMALL LETTER B (Other) ÷ [0.3]
-÷ 261D × 1F3FB ÷ 261D ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [10.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 1F466 × 1F3FB ÷ # ÷ [0.2] BOY (EBG) × [10.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 200D × 1F466 × 1F3FB ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [11.0] BOY (EBG) × [10.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 200D × 2764 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [11.0] HEAVY BLACK HEART (Glue_After_Zwj) ÷ [0.3]
-÷ 200D × 1F466 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [11.0] BOY (EBG) ÷ [0.3]
-÷ 1F466 ÷ 1F466 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] BOY (EBG) ÷ [0.3]
+÷ 1F476 × 1F3FF ÷ 1F476 ÷ # ÷ [0.2] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) ÷ [999.0] BABY (ExtPict) ÷ [0.3]
+÷ 0061 × 1F3FF ÷ 1F476 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) ÷ [999.0] BABY (ExtPict) ÷ [0.3]
+÷ 0061 × 1F3FF ÷ 1F476 × 200D × 1F6D1 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) ÷ [999.0] BABY (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3]
+÷ 1F476 × 1F3FF × 0308 × 200D × 1F476 × 1F3FF ÷ # ÷ [0.2] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) ÷ [0.3]
+÷ 1F6D1 × 200D × 1F6D1 ÷ # ÷ [0.2] OCTAGONAL SIGN (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3]
+÷ 0061 × 200D ÷ 1F6D1 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3]
+÷ 2701 × 200D × 2701 ÷ # ÷ [0.2] UPPER BLADE SCISSORS (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] UPPER BLADE SCISSORS (Other) ÷ [0.3]
+÷ 0061 × 200D ÷ 2701 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] UPPER BLADE SCISSORS (Other) ÷ [0.3]
#
-# Lines: 822
+# Lines: 672
#
# EOF
diff --git a/lib/stdlib/test/unicode_util_SUITE_data/LineBreakTest.txt b/lib/stdlib/test/unicode_util_SUITE_data/LineBreakTest.txt
index 05efcf5a44..0e9e678a85 100644
--- a/lib/stdlib/test/unicode_util_SUITE_data/LineBreakTest.txt
+++ b/lib/stdlib/test/unicode_util_SUITE_data/LineBreakTest.txt
@@ -1,25 +1,28 @@
-# LineBreakTest-9.0.0.txt
-# Date: 2016-06-18, 00:42:06 GMT
-# © 2016 Unicode®, Inc.
+# LineBreakTest-11.0.0.txt
+# Date: 2018-05-20, 09:03:09 GMT
+# © 2018 Unicode®, Inc.
# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
# For terms of use, see http://www.unicode.org/terms_of_use.html
#
# Unicode Character Database
# For documentation, see http://www.unicode.org/reports/tr44/
#
-# Default Line Break Test
+# Default Line_Break Test
#
# Format:
-# <string> (# <comment>)?
-# <string> contains hex Unicode code points, with
-# ÷ wherever there is a break opportunity, and
+# <string> (# <comment>)?
+# <string> contains hex Unicode code points, with
+# ÷ wherever there is a break opportunity, and
# × wherever there is not.
# <comment> the format can change, but currently it shows:
# - the sample character name
# - (x) the Line_Break property value for the sample character
-# - [x] the rule that determines whether there is a break or not
-# Note: The Line Break tests use tailoring of numbers described in Example 7 of Section 8.2 Examples of Customization.
-# They also differ from the results produced by a pair table implementation in sequences like: ZW SP CL.
+# - [x] the rule that determines whether there is a break or not,
+# as listed in the Rules section of LineBreakTest.html
+#
+# Note:
+# The Line_Break tests use tailoring of numbers described in
+# Example 7 of Section 8.2, "Examples of Customization" of UAX #14.
#
# These samples may be extended or changed in the future.
#
@@ -6239,174 +6242,174 @@
× 0001 × 0020 ÷ 3041 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
× 0001 × 0308 × 3041 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
× 0001 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
-× 200D × 0023 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3]
+× 200D × 0023 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] NUMBER SIGN (AL) ÷ [0.3]
× 200D × 0020 ÷ 0023 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3]
-× 200D × 0308 × 0023 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 0023 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3]
-× 200D ÷ 2014 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3]
+× 200D × 0308 × 0023 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 0023 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3]
+× 200D × 2014 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] EM DASH (B2) ÷ [0.3]
× 200D × 0020 ÷ 2014 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3]
-× 200D × 0308 ÷ 2014 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 2014 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3]
-× 200D × 0009 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3]
+× 200D × 0308 ÷ 2014 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 2014 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3]
+× 200D × 0009 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] <CHARACTER TABULATION> (BA) ÷ [0.3]
× 200D × 0020 ÷ 0009 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3]
-× 200D × 0308 × 0009 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 0009 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3]
-× 200D ÷ 00B4 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3]
+× 200D × 0308 × 0009 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 0009 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3]
+× 200D × 00B4 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] ACUTE ACCENT (BB) ÷ [0.3]
× 200D × 0020 ÷ 00B4 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3]
-× 200D × 0308 ÷ 00B4 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3]
+× 200D × 0308 ÷ 00B4 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3]
× 200D × 000B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3]
× 200D × 0020 × 000B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3]
-× 200D × 0308 × 000B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3]
-× 200D × 0308 × 0020 × 000B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3]
-× 200D ÷ FFFC ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3]
+× 200D × 0308 × 000B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3]
+× 200D × 0308 × 0020 × 000B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3]
+× 200D × FFFC ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3]
× 200D × 0020 ÷ FFFC ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3]
-× 200D × 0308 ÷ FFFC ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ FFFC ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3]
-× 200D × 007D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [13.04] RIGHT CURLY BRACKET (CL) ÷ [0.3]
+× 200D × 0308 ÷ FFFC ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ FFFC ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3]
+× 200D × 007D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] RIGHT CURLY BRACKET (CL) ÷ [0.3]
× 200D × 0020 × 007D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3]
-× 200D × 0308 × 007D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.04] RIGHT CURLY BRACKET (CL) ÷ [0.3]
-× 200D × 0308 × 0020 × 007D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3]
-× 200D × 0029 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [13.04] RIGHT PARENTHESIS (CP) ÷ [0.3]
+× 200D × 0308 × 007D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [13.04] RIGHT CURLY BRACKET (CL) ÷ [0.3]
+× 200D × 0308 × 0020 × 007D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3]
+× 200D × 0029 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] RIGHT PARENTHESIS (CP) ÷ [0.3]
× 200D × 0020 × 0029 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3]
-× 200D × 0308 × 0029 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.04] RIGHT PARENTHESIS (CP) ÷ [0.3]
-× 200D × 0308 × 0020 × 0029 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3]
+× 200D × 0308 × 0029 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [13.04] RIGHT PARENTHESIS (CP) ÷ [0.3]
+× 200D × 0308 × 0020 × 0029 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3]
× 200D × 000D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
× 200D × 0020 × 000D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-× 200D × 0308 × 000D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-× 200D × 0308 × 0020 × 000D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-× 200D × 0021 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3]
+× 200D × 0308 × 000D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+× 200D × 0308 × 0020 × 000D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+× 200D × 0021 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] EXCLAMATION MARK (EX) ÷ [0.3]
× 200D × 0020 × 0021 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3]
-× 200D × 0308 × 0021 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3]
-× 200D × 0308 × 0020 × 0021 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3]
-× 200D × 00A0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [12.3] NO-BREAK SPACE (GL) ÷ [0.3]
+× 200D × 0308 × 0021 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3]
+× 200D × 0308 × 0020 × 0021 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3]
+× 200D × 00A0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] NO-BREAK SPACE (GL) ÷ [0.3]
× 200D × 0020 ÷ 00A0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3]
-× 200D × 0308 × 00A0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.3] NO-BREAK SPACE (GL) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3]
-× 200D ÷ AC00 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3]
+× 200D × 0308 × 00A0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [12.3] NO-BREAK SPACE (GL) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3]
+× 200D × AC00 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] HANGUL SYLLABLE GA (H2) ÷ [0.3]
× 200D × 0020 ÷ AC00 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3]
-× 200D × 0308 ÷ AC00 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ AC00 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3]
-× 200D ÷ AC01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3]
+× 200D × 0308 ÷ AC00 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ AC00 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3]
+× 200D × AC01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] HANGUL SYLLABLE GAG (H3) ÷ [0.3]
× 200D × 0020 ÷ AC01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3]
-× 200D × 0308 ÷ AC01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ AC01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3]
-× 200D × 05D0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3]
+× 200D × 0308 ÷ AC01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ AC01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3]
+× 200D × 05D0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] HEBREW LETTER ALEF (HL) ÷ [0.3]
× 200D × 0020 ÷ 05D0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3]
-× 200D × 0308 × 05D0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3]
-× 200D × 002D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3]
+× 200D × 0308 × 05D0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3]
+× 200D × 002D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] HYPHEN-MINUS (HY) ÷ [0.3]
× 200D × 0020 ÷ 002D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3]
-× 200D × 0308 × 002D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 002D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3]
+× 200D × 0308 × 002D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 002D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3]
× 200D × 231A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] WATCH (ID) ÷ [0.3]
× 200D × 0020 ÷ 231A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3]
-× 200D × 0308 ÷ 231A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 231A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3]
-× 200D × 2024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3]
+× 200D × 0308 ÷ 231A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 231A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3]
+× 200D × 2024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] ONE DOT LEADER (IN) ÷ [0.3]
× 200D × 0020 ÷ 2024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3]
-× 200D × 0308 × 2024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 2024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3]
-× 200D × 002C ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [13.04] COMMA (IS) ÷ [0.3]
+× 200D × 0308 × 2024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 2024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3]
+× 200D × 002C ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMMA (IS) ÷ [0.3]
× 200D × 0020 × 002C ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3]
-× 200D × 0308 × 002C ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.04] COMMA (IS) ÷ [0.3]
-× 200D × 0308 × 0020 × 002C ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3]
-× 200D ÷ 1100 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3]
+× 200D × 0308 × 002C ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [13.04] COMMA (IS) ÷ [0.3]
+× 200D × 0308 × 0020 × 002C ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3]
+× 200D × 1100 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3]
× 200D × 0020 ÷ 1100 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3]
-× 200D × 0308 ÷ 1100 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 1100 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3]
-× 200D ÷ 11A8 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3]
+× 200D × 0308 ÷ 1100 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 1100 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3]
+× 200D × 11A8 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3]
× 200D × 0020 ÷ 11A8 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3]
-× 200D × 0308 ÷ 11A8 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3]
-× 200D ÷ 1160 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3]
+× 200D × 0308 ÷ 11A8 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3]
+× 200D × 1160 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3]
× 200D × 0020 ÷ 1160 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3]
-× 200D × 0308 ÷ 1160 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 1160 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3]
+× 200D × 0308 ÷ 1160 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 1160 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3]
× 200D × 000A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3]
× 200D × 0020 × 000A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-× 200D × 0308 × 000A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-× 200D × 0308 × 0020 × 000A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+× 200D × 0308 × 000A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+× 200D × 0308 × 0020 × 000A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3]
× 200D × 0085 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3]
× 200D × 0020 × 0085 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3]
-× 200D × 0308 × 0085 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3]
-× 200D × 0308 × 0020 × 0085 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3]
-× 200D × 17D6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3]
+× 200D × 0308 × 0085 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3]
+× 200D × 0308 × 0020 × 0085 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3]
+× 200D × 17D6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3]
× 200D × 0020 ÷ 17D6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3]
-× 200D × 0308 × 17D6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3]
-× 200D × 0030 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3]
+× 200D × 0308 × 17D6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3]
+× 200D × 0030 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] DIGIT ZERO (NU) ÷ [0.3]
× 200D × 0020 ÷ 0030 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3]
-× 200D × 0308 × 0030 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 0030 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3]
-× 200D × 0028 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3]
+× 200D × 0308 × 0030 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 0030 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3]
+× 200D × 0028 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] LEFT PARENTHESIS (OP) ÷ [0.3]
× 200D × 0020 ÷ 0028 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3]
-× 200D × 0308 × 0028 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 0028 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3]
-× 200D × 0025 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [24.03] PERCENT SIGN (PO) ÷ [0.3]
+× 200D × 0308 × 0028 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 0028 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3]
+× 200D × 0025 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] PERCENT SIGN (PO) ÷ [0.3]
× 200D × 0020 ÷ 0025 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3]
-× 200D × 0308 × 0025 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [24.03] PERCENT SIGN (PO) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 0025 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3]
-× 200D × 0024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [24.03] DOLLAR SIGN (PR) ÷ [0.3]
+× 200D × 0308 × 0025 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [24.03] PERCENT SIGN (PO) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 0025 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3]
+× 200D × 0024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] DOLLAR SIGN (PR) ÷ [0.3]
× 200D × 0020 ÷ 0024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3]
-× 200D × 0308 × 0024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [24.03] DOLLAR SIGN (PR) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 0024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3]
-× 200D × 0022 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3]
+× 200D × 0308 × 0024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [24.03] DOLLAR SIGN (PR) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 0024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3]
+× 200D × 0022 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] QUOTATION MARK (QU) ÷ [0.3]
× 200D × 0020 ÷ 0022 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3]
-× 200D × 0308 × 0022 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 0022 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3]
+× 200D × 0308 × 0022 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 0022 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3]
× 200D × 0020 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [0.3]
× 200D × 0020 × 0020 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3]
-× 200D × 0308 × 0020 × 0020 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3]
-× 200D × 002F ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [13.04] SOLIDUS (SY) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3]
+× 200D × 0308 × 0020 × 0020 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3]
+× 200D × 002F ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] SOLIDUS (SY) ÷ [0.3]
× 200D × 0020 × 002F ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3]
-× 200D × 0308 × 002F ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.04] SOLIDUS (SY) ÷ [0.3]
-× 200D × 0308 × 0020 × 002F ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3]
-× 200D × 2060 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3]
+× 200D × 0308 × 002F ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [13.04] SOLIDUS (SY) ÷ [0.3]
+× 200D × 0308 × 0020 × 002F ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3]
+× 200D × 2060 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] WORD JOINER (WJ) ÷ [0.3]
× 200D × 0020 × 2060 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3]
-× 200D × 0308 × 2060 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3]
-× 200D × 0308 × 0020 × 2060 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3]
+× 200D × 0308 × 2060 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3]
+× 200D × 0308 × 0020 × 2060 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3]
× 200D × 200B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3]
× 200D × 0020 × 200B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3]
-× 200D × 0308 × 200B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3]
-× 200D × 0308 × 0020 × 200B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3]
-× 200D ÷ 1F1E6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+× 200D × 0308 × 200B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3]
+× 200D × 0308 × 0020 × 200B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3]
+× 200D × 1F1E6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
× 200D × 0020 ÷ 1F1E6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-× 200D × 0308 ÷ 1F1E6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+× 200D × 0308 ÷ 1F1E6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
× 200D × 261D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] WHITE UP POINTING INDEX (EB) ÷ [0.3]
× 200D × 0020 ÷ 261D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3]
-× 200D × 0308 ÷ 261D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 261D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3]
+× 200D × 0308 ÷ 261D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 261D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3]
× 200D × 1F3FB ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3]
× 200D × 0020 ÷ 1F3FB ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3]
-× 200D × 0308 ÷ 1F3FB ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3]
-× 200D × 0001 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3]
+× 200D × 0308 ÷ 1F3FB ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3]
+× 200D × 0001 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] <START OF HEADING> (CM1_CM) ÷ [0.3]
× 200D × 0020 ÷ 0001 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3]
-× 200D × 0308 × 0001 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 0001 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3]
-× 200D × 200D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3]
+× 200D × 0308 × 0001 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 0001 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3]
+× 200D × 200D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3]
× 200D × 0020 ÷ 200D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3]
-× 200D × 0308 × 200D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 200D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3]
-× 200D × 00A7 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3]
+× 200D × 0308 × 200D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 200D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3]
+× 200D × 00A7 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] SECTION SIGN (AI_AL) ÷ [0.3]
× 200D × 0020 ÷ 00A7 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3]
-× 200D × 0308 × 00A7 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3]
-× 200D × 50005 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3]
+× 200D × 0308 × 00A7 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3]
+× 200D × 50005 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] <reserved-50005> (XX_AL) ÷ [0.3]
× 200D × 0020 ÷ 50005 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3]
-× 200D × 0308 × 50005 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 50005 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3]
-× 200D × 0E01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3]
+× 200D × 0308 × 50005 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 50005 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3]
+× 200D × 0E01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3]
× 200D × 0020 ÷ 0E01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3]
-× 200D × 0308 × 0E01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3]
-× 200D × 3041 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
+× 200D × 0308 × 0E01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3]
+× 200D × 3041 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
× 200D × 0020 ÷ 3041 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
-× 200D × 0308 × 3041 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 3041 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
+× 200D × 0308 × 3041 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 3041 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
× 00A7 × 0023 ÷ # × [0.3] SECTION SIGN (AI_AL) × [28.0] NUMBER SIGN (AL) ÷ [0.3]
× 00A7 × 0020 ÷ 0023 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3]
× 00A7 × 0308 × 0023 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3]
@@ -7081,7 +7084,7 @@
× 3041 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
× 000D × 000A ÷ 0061 × 000A ÷ 0308 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) × [5.01] <LINE FEED (LF)> (LF) ÷ [5.03] LATIN SMALL LETTER A (AL) × [6.0] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) ÷ [0.3]
× 0061 × 0308 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [0.3]
-× 0020 ÷ 200D × 0646 ÷ # × [0.3] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [28.0] ARABIC LETTER NOON (AL) ÷ [0.3]
+× 0020 ÷ 200D × 0646 ÷ # × [0.3] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] ARABIC LETTER NOON (AL) ÷ [0.3]
× 0646 × 200D × 0020 ÷ # × [0.3] ARABIC LETTER NOON (AL) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [0.3]
× 000B ÷ 3041 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
× 000D ÷ 3041 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
@@ -7090,8 +7093,8 @@
× 3041 × 2060 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [11.01] WORD JOINER (WJ) ÷ [0.3]
× 2060 × 3041 ÷ # × [0.3] WORD JOINER (WJ) × [11.02] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
× 3041 × 0308 × 00A0 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3]
-× 200D × 00A0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [12.3] NO-BREAK SPACE (GL) ÷ [0.3]
-× 200D × 002F ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [13.04] SOLIDUS (SY) ÷ [0.3]
+× 200D × 00A0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] NO-BREAK SPACE (GL) ÷ [0.3]
+× 200D × 002F ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] SOLIDUS (SY) ÷ [0.3]
× 2014 × 2014 ÷ # × [0.3] EM DASH (B2) × [17.0] EM DASH (B2) ÷ [0.3]
× 3041 ÷ FFFC ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3]
× FFFC ÷ 3041 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.02] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
diff --git a/lib/stdlib/test/unicode_util_SUITE_data/NormalizationTest.txt b/lib/stdlib/test/unicode_util_SUITE_data/NormalizationTest.txt
index e133fa8a78..72a31bcdf1 100644
--- a/lib/stdlib/test/unicode_util_SUITE_data/NormalizationTest.txt
+++ b/lib/stdlib/test/unicode_util_SUITE_data/NormalizationTest.txt
@@ -1,6 +1,6 @@
-# NormalizationTest-9.0.0.txt
-# Date: 2016-04-04, 11:41:55 GMT
-# © 2016 Unicode®, Inc.
+# NormalizationTest-11.0.0.txt
+# Date: 2018-02-19, 18:33:08 GMT
+# © 2018 Unicode®, Inc.
# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
# For terms of use, see http://www.unicode.org/terms_of_use.html
#
@@ -17479,6 +17479,8 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE
0061 07F2 059A 0316 302A 0062;0061 302A 07F2 0316 059A 0062;0061 302A 07F2 0316 059A 0062;0061 302A 07F2 0316 059A 0062;0061 302A 07F2 0316 059A 0062; # (a◌߲◌֚◌̖◌〪b; a◌〪◌߲◌̖◌֚b; a◌〪◌߲◌̖◌֚b; a◌〪◌߲◌̖◌֚b; a◌〪◌߲◌̖◌֚b; ) LATIN SMALL LETTER A, NKO COMBINING NASALIZATION MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B
0061 0315 0300 05AE 07F3 0062;00E0 05AE 07F3 0315 0062;0061 05AE 0300 07F3 0315 0062;00E0 05AE 07F3 0315 0062;0061 05AE 0300 07F3 0315 0062; # (a◌̕◌̀◌֮◌߳b; à◌֮◌߳◌̕b; a◌֮◌̀◌߳◌̕b; à◌֮◌߳◌̕b; a◌֮◌̀◌߳◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, NKO COMBINING DOUBLE DOT ABOVE, LATIN SMALL LETTER B
0061 07F3 0315 0300 05AE 0062;0061 05AE 07F3 0300 0315 0062;0061 05AE 07F3 0300 0315 0062;0061 05AE 07F3 0300 0315 0062;0061 05AE 07F3 0300 0315 0062; # (a◌߳◌̕◌̀◌֮b; a◌֮◌߳◌̀◌̕b; a◌֮◌߳◌̀◌̕b; a◌֮◌߳◌̀◌̕b; a◌֮◌߳◌̀◌̕b; ) LATIN SMALL LETTER A, NKO COMBINING DOUBLE DOT ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
+0061 059A 0316 302A 07FD 0062;0061 302A 0316 07FD 059A 0062;0061 302A 0316 07FD 059A 0062;0061 302A 0316 07FD 059A 0062;0061 302A 0316 07FD 059A 0062; # (a◌֚◌̖◌〪◌߽b; a◌〪◌̖◌߽◌֚b; a◌〪◌̖◌߽◌֚b; a◌〪◌̖◌߽◌֚b; a◌〪◌̖◌߽◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, NKO DANTAYALAN, LATIN SMALL LETTER B
+0061 07FD 059A 0316 302A 0062;0061 302A 07FD 0316 059A 0062;0061 302A 07FD 0316 059A 0062;0061 302A 07FD 0316 059A 0062;0061 302A 07FD 0316 059A 0062; # (a◌߽◌֚◌̖◌〪b; a◌〪◌߽◌̖◌֚b; a◌〪◌߽◌̖◌֚b; a◌〪◌߽◌̖◌֚b; a◌〪◌߽◌̖◌֚b; ) LATIN SMALL LETTER A, NKO DANTAYALAN, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B
0061 0315 0300 05AE 0816 0062;00E0 05AE 0816 0315 0062;0061 05AE 0300 0816 0315 0062;00E0 05AE 0816 0315 0062;0061 05AE 0300 0816 0315 0062; # (a◌̕◌̀◌֮◌ࠖb; à◌֮◌ࠖ◌̕b; a◌֮◌̀◌ࠖ◌̕b; à◌֮◌ࠖ◌̕b; a◌֮◌̀◌ࠖ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SAMARITAN MARK IN, LATIN SMALL LETTER B
0061 0816 0315 0300 05AE 0062;0061 05AE 0816 0300 0315 0062;0061 05AE 0816 0300 0315 0062;0061 05AE 0816 0300 0315 0062;0061 05AE 0816 0300 0315 0062; # (a◌ࠖ◌̕◌̀◌֮b; a◌֮◌ࠖ◌̀◌̕b; a◌֮◌ࠖ◌̀◌̕b; a◌֮◌ࠖ◌̀◌̕b; a◌֮◌ࠖ◌̀◌̕b; ) LATIN SMALL LETTER A, SAMARITAN MARK IN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
0061 0315 0300 05AE 0817 0062;00E0 05AE 0817 0315 0062;0061 05AE 0300 0817 0315 0062;00E0 05AE 0817 0315 0062;0061 05AE 0300 0817 0315 0062; # (a◌̕◌̀◌֮◌ࠗb; à◌֮◌ࠗ◌̕b; a◌֮◌̀◌ࠗ◌̕b; à◌֮◌ࠗ◌̕b; a◌֮◌̀◌ࠗ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SAMARITAN MARK IN-ALAF, LATIN SMALL LETTER B
@@ -17527,6 +17529,8 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE
0061 085A 059A 0316 302A 0062;0061 302A 085A 0316 059A 0062;0061 302A 085A 0316 059A 0062;0061 302A 085A 0316 059A 0062;0061 302A 085A 0316 059A 0062; # (a◌࡚◌֚◌̖◌〪b; a◌〪◌࡚◌̖◌֚b; a◌〪◌࡚◌̖◌֚b; a◌〪◌࡚◌̖◌֚b; a◌〪◌࡚◌̖◌֚b; ) LATIN SMALL LETTER A, MANDAIC VOCALIZATION MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B
0061 059A 0316 302A 085B 0062;0061 302A 0316 085B 059A 0062;0061 302A 0316 085B 059A 0062;0061 302A 0316 085B 059A 0062;0061 302A 0316 085B 059A 0062; # (a◌֚◌̖◌〪◌࡛b; a◌〪◌̖◌࡛◌֚b; a◌〪◌̖◌࡛◌֚b; a◌〪◌̖◌࡛◌֚b; a◌〪◌̖◌࡛◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MANDAIC GEMINATION MARK, LATIN SMALL LETTER B
0061 085B 059A 0316 302A 0062;0061 302A 085B 0316 059A 0062;0061 302A 085B 0316 059A 0062;0061 302A 085B 0316 059A 0062;0061 302A 085B 0316 059A 0062; # (a◌࡛◌֚◌̖◌〪b; a◌〪◌࡛◌̖◌֚b; a◌〪◌࡛◌̖◌֚b; a◌〪◌࡛◌̖◌֚b; a◌〪◌࡛◌̖◌֚b; ) LATIN SMALL LETTER A, MANDAIC GEMINATION MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B
+0061 059A 0316 302A 08D3 0062;0061 302A 0316 08D3 059A 0062;0061 302A 0316 08D3 059A 0062;0061 302A 0316 08D3 059A 0062;0061 302A 0316 08D3 059A 0062; # (a◌֚◌̖◌〪◌࣓b; a◌〪◌̖◌࣓◌֚b; a◌〪◌̖◌࣓◌֚b; a◌〪◌̖◌࣓◌֚b; a◌〪◌̖◌࣓◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, ARABIC SMALL LOW WAW, LATIN SMALL LETTER B
+0061 08D3 059A 0316 302A 0062;0061 302A 08D3 0316 059A 0062;0061 302A 08D3 0316 059A 0062;0061 302A 08D3 0316 059A 0062;0061 302A 08D3 0316 059A 0062; # (a◌࣓◌֚◌̖◌〪b; a◌〪◌࣓◌̖◌֚b; a◌〪◌࣓◌̖◌֚b; a◌〪◌࣓◌̖◌֚b; a◌〪◌࣓◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC SMALL LOW WAW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B
0061 0315 0300 05AE 08D4 0062;00E0 05AE 08D4 0315 0062;0061 05AE 0300 08D4 0315 0062;00E0 05AE 08D4 0315 0062;0061 05AE 0300 08D4 0315 0062; # (a◌̕◌̀◌֮◌ࣔb; à◌֮◌ࣔ◌̕b; a◌֮◌̀◌ࣔ◌̕b; à◌֮◌ࣔ◌̕b; a◌֮◌̀◌ࣔ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH WORD AR-RUB, LATIN SMALL LETTER B
0061 08D4 0315 0300 05AE 0062;0061 05AE 08D4 0300 0315 0062;0061 05AE 08D4 0300 0315 0062;0061 05AE 08D4 0300 0315 0062;0061 05AE 08D4 0300 0315 0062; # (a◌ࣔ◌̕◌̀◌֮b; a◌֮◌ࣔ◌̀◌̕b; a◌֮◌ࣔ◌̀◌̕b; a◌֮◌ࣔ◌̀◌̕b; a◌֮◌ࣔ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH WORD AR-RUB, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
0061 0315 0300 05AE 08D5 0062;00E0 05AE 08D5 0315 0062;0061 05AE 0300 08D5 0315 0062;00E0 05AE 08D5 0315 0062;0061 05AE 0300 08D5 0315 0062; # (a◌̕◌̀◌֮◌ࣕb; à◌֮◌ࣕ◌̕b; a◌֮◌̀◌ࣕ◌̕b; à◌֮◌ࣕ◌̕b; a◌֮◌̀◌ࣕ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH SAD, LATIN SMALL LETTER B
@@ -17629,6 +17633,8 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE
0061 09BC 3099 093C 0334 0062;0061 0334 09BC 093C 3099 0062;0061 0334 09BC 093C 3099 0062;0061 0334 09BC 093C 3099 0062;0061 0334 09BC 093C 3099 0062; # (a◌়◌゙◌़◌̴b; a◌̴◌়◌़◌゙b; a◌̴◌়◌़◌゙b; a◌̴◌়◌़◌゙b; a◌̴◌়◌़◌゙b; ) LATIN SMALL LETTER A, BENGALI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B
0061 05B0 094D 3099 09CD 0062;0061 3099 094D 09CD 05B0 0062;0061 3099 094D 09CD 05B0 0062;0061 3099 094D 09CD 05B0 0062;0061 3099 094D 09CD 05B0 0062; # (a◌ְ◌्◌゙◌্b; a◌゙◌्◌্◌ְb; a◌゙◌्◌্◌ְb; a◌゙◌्◌্◌ְb; a◌゙◌्◌্◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, BENGALI SIGN VIRAMA, LATIN SMALL LETTER B
0061 09CD 05B0 094D 3099 0062;0061 3099 09CD 094D 05B0 0062;0061 3099 09CD 094D 05B0 0062;0061 3099 09CD 094D 05B0 0062;0061 3099 09CD 094D 05B0 0062; # (a◌্◌ְ◌्◌゙b; a◌゙◌্◌्◌ְb; a◌゙◌্◌्◌ְb; a◌゙◌্◌्◌ְb; a◌゙◌্◌्◌ְb; ) LATIN SMALL LETTER A, BENGALI SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
+0061 0315 0300 05AE 09FE 0062;00E0 05AE 09FE 0315 0062;0061 05AE 0300 09FE 0315 0062;00E0 05AE 09FE 0315 0062;0061 05AE 0300 09FE 0315 0062; # (a◌̕◌̀◌֮◌৾b; à◌֮◌৾◌̕b; a◌֮◌̀◌৾◌̕b; à◌֮◌৾◌̕b; a◌֮◌̀◌৾◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, BENGALI SANDHI MARK, LATIN SMALL LETTER B
+0061 09FE 0315 0300 05AE 0062;0061 05AE 09FE 0300 0315 0062;0061 05AE 09FE 0300 0315 0062;0061 05AE 09FE 0300 0315 0062;0061 05AE 09FE 0300 0315 0062; # (a◌৾◌̕◌̀◌֮b; a◌֮◌৾◌̀◌̕b; a◌֮◌৾◌̀◌̕b; a◌֮◌৾◌̀◌̕b; a◌֮◌৾◌̀◌̕b; ) LATIN SMALL LETTER A, BENGALI SANDHI MARK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
0061 3099 093C 0334 0A3C 0062;0061 0334 093C 0A3C 3099 0062;0061 0334 093C 0A3C 3099 0062;0061 0334 093C 0A3C 3099 0062;0061 0334 093C 0A3C 3099 0062; # (a◌゙◌़◌̴◌਼b; a◌̴◌़◌਼◌゙b; a◌̴◌़◌਼◌゙b; a◌̴◌़◌਼◌゙b; a◌̴◌़◌਼◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, GURMUKHI SIGN NUKTA, LATIN SMALL LETTER B
0061 0A3C 3099 093C 0334 0062;0061 0334 0A3C 093C 3099 0062;0061 0334 0A3C 093C 3099 0062;0061 0334 0A3C 093C 3099 0062;0061 0334 0A3C 093C 3099 0062; # (a◌਼◌゙◌़◌̴b; a◌̴◌਼◌़◌゙b; a◌̴◌਼◌़◌゙b; a◌̴◌਼◌़◌゙b; a◌̴◌਼◌़◌゙b; ) LATIN SMALL LETTER A, GURMUKHI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B
0061 05B0 094D 3099 0A4D 0062;0061 3099 094D 0A4D 05B0 0062;0061 3099 094D 0A4D 05B0 0062;0061 3099 094D 0A4D 05B0 0062;0061 3099 094D 0A4D 05B0 0062; # (a◌ְ◌्◌゙◌੍b; a◌゙◌्◌੍◌ְb; a◌゙◌्◌੍◌ְb; a◌゙◌्◌੍◌ְb; a◌゙◌्◌੍◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, GURMUKHI SIGN VIRAMA, LATIN SMALL LETTER B
@@ -17653,6 +17659,10 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE
0061 0CBC 3099 093C 0334 0062;0061 0334 0CBC 093C 3099 0062;0061 0334 0CBC 093C 3099 0062;0061 0334 0CBC 093C 3099 0062;0061 0334 0CBC 093C 3099 0062; # (a◌಼◌゙◌़◌̴b; a◌̴◌಼◌़◌゙b; a◌̴◌಼◌़◌゙b; a◌̴◌಼◌़◌゙b; a◌̴◌಼◌़◌゙b; ) LATIN SMALL LETTER A, KANNADA SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B
0061 05B0 094D 3099 0CCD 0062;0061 3099 094D 0CCD 05B0 0062;0061 3099 094D 0CCD 05B0 0062;0061 3099 094D 0CCD 05B0 0062;0061 3099 094D 0CCD 05B0 0062; # (a◌ְ◌्◌゙◌್b; a◌゙◌्◌್◌ְb; a◌゙◌्◌್◌ְb; a◌゙◌्◌್◌ְb; a◌゙◌्◌್◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, KANNADA SIGN VIRAMA, LATIN SMALL LETTER B
0061 0CCD 05B0 094D 3099 0062;0061 3099 0CCD 094D 05B0 0062;0061 3099 0CCD 094D 05B0 0062;0061 3099 0CCD 094D 05B0 0062;0061 3099 0CCD 094D 05B0 0062; # (a◌್◌ְ◌्◌゙b; a◌゙◌್◌्◌ְb; a◌゙◌್◌्◌ְb; a◌゙◌್◌्◌ְb; a◌゙◌್◌्◌ְb; ) LATIN SMALL LETTER A, KANNADA SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
+0061 05B0 094D 3099 0D3B 0062;0061 3099 094D 0D3B 05B0 0062;0061 3099 094D 0D3B 05B0 0062;0061 3099 094D 0D3B 05B0 0062;0061 3099 094D 0D3B 05B0 0062; # (a◌ְ◌्◌゙◌഻b; a◌゙◌्◌഻◌ְb; a◌゙◌्◌഻◌ְb; a◌゙◌्◌഻◌ְb; a◌゙◌्◌഻◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, MALAYALAM SIGN VERTICAL BAR VIRAMA, LATIN SMALL LETTER B
+0061 0D3B 05B0 094D 3099 0062;0061 3099 0D3B 094D 05B0 0062;0061 3099 0D3B 094D 05B0 0062;0061 3099 0D3B 094D 05B0 0062;0061 3099 0D3B 094D 05B0 0062; # (a◌഻◌ְ◌्◌゙b; a◌゙◌഻◌्◌ְb; a◌゙◌഻◌्◌ְb; a◌゙◌഻◌्◌ְb; a◌゙◌഻◌्◌ְb; ) LATIN SMALL LETTER A, MALAYALAM SIGN VERTICAL BAR VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
+0061 05B0 094D 3099 0D3C 0062;0061 3099 094D 0D3C 05B0 0062;0061 3099 094D 0D3C 05B0 0062;0061 3099 094D 0D3C 05B0 0062;0061 3099 094D 0D3C 05B0 0062; # (a◌ְ◌्◌゙◌഼b; a◌゙◌्◌഼◌ְb; a◌゙◌्◌഼◌ְb; a◌゙◌्◌഼◌ְb; a◌゙◌्◌഼◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, MALAYALAM SIGN CIRCULAR VIRAMA, LATIN SMALL LETTER B
+0061 0D3C 05B0 094D 3099 0062;0061 3099 0D3C 094D 05B0 0062;0061 3099 0D3C 094D 05B0 0062;0061 3099 0D3C 094D 05B0 0062;0061 3099 0D3C 094D 05B0 0062; # (a◌഼◌ְ◌्◌゙b; a◌゙◌഼◌्◌ְb; a◌゙◌഼◌्◌ְb; a◌゙◌഼◌्◌ְb; a◌゙◌഼◌्◌ְb; ) LATIN SMALL LETTER A, MALAYALAM SIGN CIRCULAR VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
0061 05B0 094D 3099 0D4D 0062;0061 3099 094D 0D4D 05B0 0062;0061 3099 094D 0D4D 05B0 0062;0061 3099 094D 0D4D 05B0 0062;0061 3099 094D 0D4D 05B0 0062; # (a◌ְ◌्◌゙◌്b; a◌゙◌्◌്◌ְb; a◌゙◌्◌്◌ְb; a◌゙◌्◌്◌ְb; a◌゙◌्◌്◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, MALAYALAM SIGN VIRAMA, LATIN SMALL LETTER B
0061 0D4D 05B0 094D 3099 0062;0061 3099 0D4D 094D 05B0 0062;0061 3099 0D4D 094D 05B0 0062;0061 3099 0D4D 094D 05B0 0062;0061 3099 0D4D 094D 05B0 0062; # (a◌്◌ְ◌्◌゙b; a◌゙◌്◌्◌ְb; a◌゙◌്◌्◌ְb; a◌゙◌്◌्◌ְb; a◌゙◌്◌्◌ְb; ) LATIN SMALL LETTER A, MALAYALAM SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
0061 05B0 094D 3099 0DCA 0062;0061 3099 094D 0DCA 05B0 0062;0061 3099 094D 0DCA 05B0 0062;0061 3099 094D 0DCA 05B0 0062;0061 3099 094D 0DCA 05B0 0062; # (a◌ְ◌्◌゙◌්b; a◌゙◌्◌්◌ְb; a◌゙◌्◌්◌ְb; a◌゙◌्◌්◌ְb; a◌゙◌्◌්◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, SINHALA SIGN AL-LAKUNA, LATIN SMALL LETTER B
@@ -17999,6 +18009,14 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE
0061 1DF4 0315 0300 05AE 0062;0061 05AE 1DF4 0300 0315 0062;0061 05AE 1DF4 0300 0315 0062;0061 05AE 1DF4 0300 0315 0062;0061 05AE 1DF4 0300 0315 0062; # (a◌ᷴ◌̕◌̀◌֮b; a◌֮◌ᷴ◌̀◌̕b; a◌֮◌ᷴ◌̀◌̕b; a◌֮◌ᷴ◌̀◌̕b; a◌֮◌ᷴ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER U WITH DIAERESIS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
0061 0315 0300 05AE 1DF5 0062;00E0 05AE 1DF5 0315 0062;0061 05AE 0300 1DF5 0315 0062;00E0 05AE 1DF5 0315 0062;0061 05AE 0300 1DF5 0315 0062; # (a◌̕◌̀◌֮◌᷵b; à◌֮◌᷵◌̕b; a◌֮◌̀◌᷵◌̕b; à◌֮◌᷵◌̕b; a◌֮◌̀◌᷵◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING UP TACK ABOVE, LATIN SMALL LETTER B
0061 1DF5 0315 0300 05AE 0062;0061 05AE 1DF5 0300 0315 0062;0061 05AE 1DF5 0300 0315 0062;0061 05AE 1DF5 0300 0315 0062;0061 05AE 1DF5 0300 0315 0062; # (a◌᷵◌̕◌̀◌֮b; a◌֮◌᷵◌̀◌̕b; a◌֮◌᷵◌̀◌̕b; a◌֮◌᷵◌̀◌̕b; a◌֮◌᷵◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING UP TACK ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
+0061 035C 0315 0300 1DF6 0062;00E0 0315 1DF6 035C 0062;0061 0300 0315 1DF6 035C 0062;00E0 0315 1DF6 035C 0062;0061 0300 0315 1DF6 035C 0062; # (a◌͜◌̕◌̀◌᷶b; à◌̕◌᷶◌͜b; a◌̀◌̕◌᷶◌͜b; à◌̕◌᷶◌͜b; a◌̀◌̕◌᷶◌͜b; ) LATIN SMALL LETTER A, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, COMBINING KAVYKA ABOVE RIGHT, LATIN SMALL LETTER B
+0061 1DF6 035C 0315 0300 0062;00E0 1DF6 0315 035C 0062;0061 0300 1DF6 0315 035C 0062;00E0 1DF6 0315 035C 0062;0061 0300 1DF6 0315 035C 0062; # (a◌᷶◌͜◌̕◌̀b; à◌᷶◌̕◌͜b; a◌̀◌᷶◌̕◌͜b; à◌᷶◌̕◌͜b; a◌̀◌᷶◌̕◌͜b; ) LATIN SMALL LETTER A, COMBINING KAVYKA ABOVE RIGHT, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, LATIN SMALL LETTER B
+0061 0300 05AE 1D16D 1DF7 0062;00E0 1D16D 05AE 1DF7 0062;0061 1D16D 05AE 1DF7 0300 0062;00E0 1D16D 05AE 1DF7 0062;0061 1D16D 05AE 1DF7 0300 0062; # (a◌̀◌𝅭֮◌᷷b; à𝅭◌֮◌᷷b; a𝅭◌֮◌᷷◌̀b; à𝅭◌֮◌᷷b; a𝅭◌֮◌᷷◌̀b; ) LATIN SMALL LETTER A, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, COMBINING KAVYKA ABOVE LEFT, LATIN SMALL LETTER B
+0061 1DF7 0300 05AE 1D16D 0062;00E0 1D16D 1DF7 05AE 0062;0061 1D16D 1DF7 05AE 0300 0062;00E0 1D16D 1DF7 05AE 0062;0061 1D16D 1DF7 05AE 0300 0062; # (a◌᷷◌̀◌𝅭֮b; à𝅭◌᷷◌֮b; a𝅭◌᷷◌֮◌̀b; à𝅭◌᷷◌֮b; a𝅭◌᷷◌֮◌̀b; ) LATIN SMALL LETTER A, COMBINING KAVYKA ABOVE LEFT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, LATIN SMALL LETTER B
+0061 0300 05AE 1D16D 1DF8 0062;00E0 1D16D 05AE 1DF8 0062;0061 1D16D 05AE 1DF8 0300 0062;00E0 1D16D 05AE 1DF8 0062;0061 1D16D 05AE 1DF8 0300 0062; # (a◌̀◌𝅭֮◌᷸b; à𝅭◌֮◌᷸b; a𝅭◌֮◌᷸◌̀b; à𝅭◌֮◌᷸b; a𝅭◌֮◌᷸◌̀b; ) LATIN SMALL LETTER A, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, COMBINING DOT ABOVE LEFT, LATIN SMALL LETTER B
+0061 1DF8 0300 05AE 1D16D 0062;00E0 1D16D 1DF8 05AE 0062;0061 1D16D 1DF8 05AE 0300 0062;00E0 1D16D 1DF8 05AE 0062;0061 1D16D 1DF8 05AE 0300 0062; # (a◌᷸◌̀◌𝅭֮b; à𝅭◌᷸◌֮b; a𝅭◌᷸◌֮◌̀b; à𝅭◌᷸◌֮b; a𝅭◌᷸◌֮◌̀b; ) LATIN SMALL LETTER A, COMBINING DOT ABOVE LEFT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, LATIN SMALL LETTER B
+0061 059A 0316 302A 1DF9 0062;0061 302A 0316 1DF9 059A 0062;0061 302A 0316 1DF9 059A 0062;0061 302A 0316 1DF9 059A 0062;0061 302A 0316 1DF9 059A 0062; # (a◌֚◌̖◌〪◌᷹b; a◌〪◌̖◌᷹◌֚b; a◌〪◌̖◌᷹◌֚b; a◌〪◌̖◌᷹◌֚b; a◌〪◌̖◌᷹◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING WIDE INVERTED BRIDGE BELOW, LATIN SMALL LETTER B
+0061 1DF9 059A 0316 302A 0062;0061 302A 1DF9 0316 059A 0062;0061 302A 1DF9 0316 059A 0062;0061 302A 1DF9 0316 059A 0062;0061 302A 1DF9 0316 059A 0062; # (a◌᷹◌֚◌̖◌〪b; a◌〪◌᷹◌̖◌֚b; a◌〪◌᷹◌̖◌֚b; a◌〪◌᷹◌̖◌֚b; a◌〪◌᷹◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING WIDE INVERTED BRIDGE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B
0061 0315 0300 05AE 1DFB 0062;00E0 05AE 1DFB 0315 0062;0061 05AE 0300 1DFB 0315 0062;00E0 05AE 1DFB 0315 0062;0061 05AE 0300 1DFB 0315 0062; # (a◌̕◌̀◌֮◌᷻b; à◌֮◌᷻◌̕b; a◌֮◌̀◌᷻◌̕b; à◌֮◌᷻◌̕b; a◌֮◌̀◌᷻◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DELETION MARK, LATIN SMALL LETTER B
0061 1DFB 0315 0300 05AE 0062;0061 05AE 1DFB 0300 0315 0062;0061 05AE 1DFB 0300 0315 0062;0061 05AE 1DFB 0300 0315 0062;0061 05AE 1DFB 0300 0315 0062; # (a◌᷻◌̕◌̀◌֮b; a◌֮◌᷻◌̀◌̕b; a◌֮◌᷻◌̀◌̕b; a◌֮◌᷻◌̀◌̕b; a◌֮◌᷻◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DELETION MARK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
0061 035D 035C 0315 1DFC 0062;0061 0315 035C 1DFC 035D 0062;0061 0315 035C 1DFC 035D 0062;0061 0315 035C 1DFC 035D 0062;0061 0315 035C 1DFC 035D 0062; # (a◌͝◌͜◌̕◌᷼b; a◌̕◌͜◌᷼◌͝b; a◌̕◌͜◌᷼◌͝b; a◌̕◌͜◌᷼◌͝b; a◌̕◌͜◌᷼◌͝b; ) LATIN SMALL LETTER A, COMBINING DOUBLE BREVE, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING DOUBLE INVERTED BREVE BELOW, LATIN SMALL LETTER B
@@ -18317,6 +18335,36 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE
0061 10AE5 0315 0300 05AE 0062;0061 05AE 10AE5 0300 0315 0062;0061 05AE 10AE5 0300 0315 0062;0061 05AE 10AE5 0300 0315 0062;0061 05AE 10AE5 0300 0315 0062; # (a◌𐫥◌̕◌̀◌֮b; a◌֮◌𐫥◌̀◌̕b; a◌֮◌𐫥◌̀◌̕b; a◌֮◌𐫥◌̀◌̕b; a◌֮◌𐫥◌̀◌̕b; ) LATIN SMALL LETTER A, MANICHAEAN ABBREVIATION MARK ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
0061 059A 0316 302A 10AE6 0062;0061 302A 0316 10AE6 059A 0062;0061 302A 0316 10AE6 059A 0062;0061 302A 0316 10AE6 059A 0062;0061 302A 0316 10AE6 059A 0062; # (a◌֚◌̖◌〪◌𐫦b; a◌〪◌̖◌𐫦◌֚b; a◌〪◌̖◌𐫦◌֚b; a◌〪◌̖◌𐫦◌֚b; a◌〪◌̖◌𐫦◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MANICHAEAN ABBREVIATION MARK BELOW, LATIN SMALL LETTER B
0061 10AE6 059A 0316 302A 0062;0061 302A 10AE6 0316 059A 0062;0061 302A 10AE6 0316 059A 0062;0061 302A 10AE6 0316 059A 0062;0061 302A 10AE6 0316 059A 0062; # (a◌𐫦◌֚◌̖◌〪b; a◌〪◌𐫦◌̖◌֚b; a◌〪◌𐫦◌̖◌֚b; a◌〪◌𐫦◌̖◌֚b; a◌〪◌𐫦◌̖◌֚b; ) LATIN SMALL LETTER A, MANICHAEAN ABBREVIATION MARK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B
+0061 0315 0300 05AE 10D24 0062;00E0 05AE 10D24 0315 0062;0061 05AE 0300 10D24 0315 0062;00E0 05AE 10D24 0315 0062;0061 05AE 0300 10D24 0315 0062; # (a◌̕◌̀◌֮◌𐴤b; à◌֮◌𐴤◌̕b; a◌֮◌̀◌𐴤◌̕b; à◌֮◌𐴤◌̕b; a◌֮◌̀◌𐴤◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HANIFI ROHINGYA SIGN HARBAHAY, LATIN SMALL LETTER B
+0061 10D24 0315 0300 05AE 0062;0061 05AE 10D24 0300 0315 0062;0061 05AE 10D24 0300 0315 0062;0061 05AE 10D24 0300 0315 0062;0061 05AE 10D24 0300 0315 0062; # (a◌𐴤◌̕◌̀◌֮b; a◌֮◌𐴤◌̀◌̕b; a◌֮◌𐴤◌̀◌̕b; a◌֮◌𐴤◌̀◌̕b; a◌֮◌𐴤◌̀◌̕b; ) LATIN SMALL LETTER A, HANIFI ROHINGYA SIGN HARBAHAY, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
+0061 0315 0300 05AE 10D25 0062;00E0 05AE 10D25 0315 0062;0061 05AE 0300 10D25 0315 0062;00E0 05AE 10D25 0315 0062;0061 05AE 0300 10D25 0315 0062; # (a◌̕◌̀◌֮◌𐴥b; à◌֮◌𐴥◌̕b; a◌֮◌̀◌𐴥◌̕b; à◌֮◌𐴥◌̕b; a◌֮◌̀◌𐴥◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HANIFI ROHINGYA SIGN TAHALA, LATIN SMALL LETTER B
+0061 10D25 0315 0300 05AE 0062;0061 05AE 10D25 0300 0315 0062;0061 05AE 10D25 0300 0315 0062;0061 05AE 10D25 0300 0315 0062;0061 05AE 10D25 0300 0315 0062; # (a◌𐴥◌̕◌̀◌֮b; a◌֮◌𐴥◌̀◌̕b; a◌֮◌𐴥◌̀◌̕b; a◌֮◌𐴥◌̀◌̕b; a◌֮◌𐴥◌̀◌̕b; ) LATIN SMALL LETTER A, HANIFI ROHINGYA SIGN TAHALA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
+0061 0315 0300 05AE 10D26 0062;00E0 05AE 10D26 0315 0062;0061 05AE 0300 10D26 0315 0062;00E0 05AE 10D26 0315 0062;0061 05AE 0300 10D26 0315 0062; # (a◌̕◌̀◌֮◌𐴦b; à◌֮◌𐴦◌̕b; a◌֮◌̀◌𐴦◌̕b; à◌֮◌𐴦◌̕b; a◌֮◌̀◌𐴦◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HANIFI ROHINGYA SIGN TANA, LATIN SMALL LETTER B
+0061 10D26 0315 0300 05AE 0062;0061 05AE 10D26 0300 0315 0062;0061 05AE 10D26 0300 0315 0062;0061 05AE 10D26 0300 0315 0062;0061 05AE 10D26 0300 0315 0062; # (a◌𐴦◌̕◌̀◌֮b; a◌֮◌𐴦◌̀◌̕b; a◌֮◌𐴦◌̀◌̕b; a◌֮◌𐴦◌̀◌̕b; a◌֮◌𐴦◌̀◌̕b; ) LATIN SMALL LETTER A, HANIFI ROHINGYA SIGN TANA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
+0061 0315 0300 05AE 10D27 0062;00E0 05AE 10D27 0315 0062;0061 05AE 0300 10D27 0315 0062;00E0 05AE 10D27 0315 0062;0061 05AE 0300 10D27 0315 0062; # (a◌̕◌̀◌֮◌𐴧b; à◌֮◌𐴧◌̕b; a◌֮◌̀◌𐴧◌̕b; à◌֮◌𐴧◌̕b; a◌֮◌̀◌𐴧◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HANIFI ROHINGYA SIGN TASSI, LATIN SMALL LETTER B
+0061 10D27 0315 0300 05AE 0062;0061 05AE 10D27 0300 0315 0062;0061 05AE 10D27 0300 0315 0062;0061 05AE 10D27 0300 0315 0062;0061 05AE 10D27 0300 0315 0062; # (a◌𐴧◌̕◌̀◌֮b; a◌֮◌𐴧◌̀◌̕b; a◌֮◌𐴧◌̀◌̕b; a◌֮◌𐴧◌̀◌̕b; a◌֮◌𐴧◌̀◌̕b; ) LATIN SMALL LETTER A, HANIFI ROHINGYA SIGN TASSI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
+0061 059A 0316 302A 10F46 0062;0061 302A 0316 10F46 059A 0062;0061 302A 0316 10F46 059A 0062;0061 302A 0316 10F46 059A 0062;0061 302A 0316 10F46 059A 0062; # (a◌֚◌̖◌〪◌𐽆b; a◌〪◌̖◌𐽆◌֚b; a◌〪◌̖◌𐽆◌֚b; a◌〪◌̖◌𐽆◌֚b; a◌〪◌̖◌𐽆◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SOGDIAN COMBINING DOT BELOW, LATIN SMALL LETTER B
+0061 10F46 059A 0316 302A 0062;0061 302A 10F46 0316 059A 0062;0061 302A 10F46 0316 059A 0062;0061 302A 10F46 0316 059A 0062;0061 302A 10F46 0316 059A 0062; # (a◌𐽆◌֚◌̖◌〪b; a◌〪◌𐽆◌̖◌֚b; a◌〪◌𐽆◌̖◌֚b; a◌〪◌𐽆◌̖◌֚b; a◌〪◌𐽆◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING DOT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B
+0061 059A 0316 302A 10F47 0062;0061 302A 0316 10F47 059A 0062;0061 302A 0316 10F47 059A 0062;0061 302A 0316 10F47 059A 0062;0061 302A 0316 10F47 059A 0062; # (a◌֚◌̖◌〪◌𐽇b; a◌〪◌̖◌𐽇◌֚b; a◌〪◌̖◌𐽇◌֚b; a◌〪◌̖◌𐽇◌֚b; a◌〪◌̖◌𐽇◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SOGDIAN COMBINING TWO DOTS BELOW, LATIN SMALL LETTER B
+0061 10F47 059A 0316 302A 0062;0061 302A 10F47 0316 059A 0062;0061 302A 10F47 0316 059A 0062;0061 302A 10F47 0316 059A 0062;0061 302A 10F47 0316 059A 0062; # (a◌𐽇◌֚◌̖◌〪b; a◌〪◌𐽇◌̖◌֚b; a◌〪◌𐽇◌̖◌֚b; a◌〪◌𐽇◌̖◌֚b; a◌〪◌𐽇◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING TWO DOTS BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B
+0061 0315 0300 05AE 10F48 0062;00E0 05AE 10F48 0315 0062;0061 05AE 0300 10F48 0315 0062;00E0 05AE 10F48 0315 0062;0061 05AE 0300 10F48 0315 0062; # (a◌̕◌̀◌֮◌𐽈b; à◌֮◌𐽈◌̕b; a◌֮◌̀◌𐽈◌̕b; à◌֮◌𐽈◌̕b; a◌֮◌̀◌𐽈◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SOGDIAN COMBINING DOT ABOVE, LATIN SMALL LETTER B
+0061 10F48 0315 0300 05AE 0062;0061 05AE 10F48 0300 0315 0062;0061 05AE 10F48 0300 0315 0062;0061 05AE 10F48 0300 0315 0062;0061 05AE 10F48 0300 0315 0062; # (a◌𐽈◌̕◌̀◌֮b; a◌֮◌𐽈◌̀◌̕b; a◌֮◌𐽈◌̀◌̕b; a◌֮◌𐽈◌̀◌̕b; a◌֮◌𐽈◌̀◌̕b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING DOT ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
+0061 0315 0300 05AE 10F49 0062;00E0 05AE 10F49 0315 0062;0061 05AE 0300 10F49 0315 0062;00E0 05AE 10F49 0315 0062;0061 05AE 0300 10F49 0315 0062; # (a◌̕◌̀◌֮◌𐽉b; à◌֮◌𐽉◌̕b; a◌֮◌̀◌𐽉◌̕b; à◌֮◌𐽉◌̕b; a◌֮◌̀◌𐽉◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SOGDIAN COMBINING TWO DOTS ABOVE, LATIN SMALL LETTER B
+0061 10F49 0315 0300 05AE 0062;0061 05AE 10F49 0300 0315 0062;0061 05AE 10F49 0300 0315 0062;0061 05AE 10F49 0300 0315 0062;0061 05AE 10F49 0300 0315 0062; # (a◌𐽉◌̕◌̀◌֮b; a◌֮◌𐽉◌̀◌̕b; a◌֮◌𐽉◌̀◌̕b; a◌֮◌𐽉◌̀◌̕b; a◌֮◌𐽉◌̀◌̕b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING TWO DOTS ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
+0061 0315 0300 05AE 10F4A 0062;00E0 05AE 10F4A 0315 0062;0061 05AE 0300 10F4A 0315 0062;00E0 05AE 10F4A 0315 0062;0061 05AE 0300 10F4A 0315 0062; # (a◌̕◌̀◌֮◌𐽊b; à◌֮◌𐽊◌̕b; a◌֮◌̀◌𐽊◌̕b; à◌֮◌𐽊◌̕b; a◌֮◌̀◌𐽊◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SOGDIAN COMBINING CURVE ABOVE, LATIN SMALL LETTER B
+0061 10F4A 0315 0300 05AE 0062;0061 05AE 10F4A 0300 0315 0062;0061 05AE 10F4A 0300 0315 0062;0061 05AE 10F4A 0300 0315 0062;0061 05AE 10F4A 0300 0315 0062; # (a◌𐽊◌̕◌̀◌֮b; a◌֮◌𐽊◌̀◌̕b; a◌֮◌𐽊◌̀◌̕b; a◌֮◌𐽊◌̀◌̕b; a◌֮◌𐽊◌̀◌̕b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING CURVE ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
+0061 059A 0316 302A 10F4B 0062;0061 302A 0316 10F4B 059A 0062;0061 302A 0316 10F4B 059A 0062;0061 302A 0316 10F4B 059A 0062;0061 302A 0316 10F4B 059A 0062; # (a◌֚◌̖◌〪◌𐽋b; a◌〪◌̖◌𐽋◌֚b; a◌〪◌̖◌𐽋◌֚b; a◌〪◌̖◌𐽋◌֚b; a◌〪◌̖◌𐽋◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SOGDIAN COMBINING CURVE BELOW, LATIN SMALL LETTER B
+0061 10F4B 059A 0316 302A 0062;0061 302A 10F4B 0316 059A 0062;0061 302A 10F4B 0316 059A 0062;0061 302A 10F4B 0316 059A 0062;0061 302A 10F4B 0316 059A 0062; # (a◌𐽋◌֚◌̖◌〪b; a◌〪◌𐽋◌̖◌֚b; a◌〪◌𐽋◌̖◌֚b; a◌〪◌𐽋◌̖◌֚b; a◌〪◌𐽋◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING CURVE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B
+0061 0315 0300 05AE 10F4C 0062;00E0 05AE 10F4C 0315 0062;0061 05AE 0300 10F4C 0315 0062;00E0 05AE 10F4C 0315 0062;0061 05AE 0300 10F4C 0315 0062; # (a◌̕◌̀◌֮◌𐽌b; à◌֮◌𐽌◌̕b; a◌֮◌̀◌𐽌◌̕b; à◌֮◌𐽌◌̕b; a◌֮◌̀◌𐽌◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SOGDIAN COMBINING HOOK ABOVE, LATIN SMALL LETTER B
+0061 10F4C 0315 0300 05AE 0062;0061 05AE 10F4C 0300 0315 0062;0061 05AE 10F4C 0300 0315 0062;0061 05AE 10F4C 0300 0315 0062;0061 05AE 10F4C 0300 0315 0062; # (a◌𐽌◌̕◌̀◌֮b; a◌֮◌𐽌◌̀◌̕b; a◌֮◌𐽌◌̀◌̕b; a◌֮◌𐽌◌̀◌̕b; a◌֮◌𐽌◌̀◌̕b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING HOOK ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
+0061 059A 0316 302A 10F4D 0062;0061 302A 0316 10F4D 059A 0062;0061 302A 0316 10F4D 059A 0062;0061 302A 0316 10F4D 059A 0062;0061 302A 0316 10F4D 059A 0062; # (a◌֚◌̖◌〪◌𐽍b; a◌〪◌̖◌𐽍◌֚b; a◌〪◌̖◌𐽍◌֚b; a◌〪◌̖◌𐽍◌֚b; a◌〪◌̖◌𐽍◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SOGDIAN COMBINING HOOK BELOW, LATIN SMALL LETTER B
+0061 10F4D 059A 0316 302A 0062;0061 302A 10F4D 0316 059A 0062;0061 302A 10F4D 0316 059A 0062;0061 302A 10F4D 0316 059A 0062;0061 302A 10F4D 0316 059A 0062; # (a◌𐽍◌֚◌̖◌〪b; a◌〪◌𐽍◌̖◌֚b; a◌〪◌𐽍◌̖◌֚b; a◌〪◌𐽍◌̖◌֚b; a◌〪◌𐽍◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING HOOK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B
+0061 059A 0316 302A 10F4E 0062;0061 302A 0316 10F4E 059A 0062;0061 302A 0316 10F4E 059A 0062;0061 302A 0316 10F4E 059A 0062;0061 302A 0316 10F4E 059A 0062; # (a◌֚◌̖◌〪◌𐽎b; a◌〪◌̖◌𐽎◌֚b; a◌〪◌̖◌𐽎◌֚b; a◌〪◌̖◌𐽎◌֚b; a◌〪◌̖◌𐽎◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SOGDIAN COMBINING LONG HOOK BELOW, LATIN SMALL LETTER B
+0061 10F4E 059A 0316 302A 0062;0061 302A 10F4E 0316 059A 0062;0061 302A 10F4E 0316 059A 0062;0061 302A 10F4E 0316 059A 0062;0061 302A 10F4E 0316 059A 0062; # (a◌𐽎◌֚◌̖◌〪b; a◌〪◌𐽎◌̖◌֚b; a◌〪◌𐽎◌̖◌֚b; a◌〪◌𐽎◌̖◌֚b; a◌〪◌𐽎◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING LONG HOOK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B
+0061 059A 0316 302A 10F4F 0062;0061 302A 0316 10F4F 059A 0062;0061 302A 0316 10F4F 059A 0062;0061 302A 0316 10F4F 059A 0062;0061 302A 0316 10F4F 059A 0062; # (a◌֚◌̖◌〪◌𐽏b; a◌〪◌̖◌𐽏◌֚b; a◌〪◌̖◌𐽏◌֚b; a◌〪◌̖◌𐽏◌֚b; a◌〪◌̖◌𐽏◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SOGDIAN COMBINING RESH BELOW, LATIN SMALL LETTER B
+0061 10F4F 059A 0316 302A 0062;0061 302A 10F4F 0316 059A 0062;0061 302A 10F4F 0316 059A 0062;0061 302A 10F4F 0316 059A 0062;0061 302A 10F4F 0316 059A 0062; # (a◌𐽏◌֚◌̖◌〪b; a◌〪◌𐽏◌̖◌֚b; a◌〪◌𐽏◌̖◌֚b; a◌〪◌𐽏◌̖◌֚b; a◌〪◌𐽏◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING RESH BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B
+0061 059A 0316 302A 10F50 0062;0061 302A 0316 10F50 059A 0062;0061 302A 0316 10F50 059A 0062;0061 302A 0316 10F50 059A 0062;0061 302A 0316 10F50 059A 0062; # (a◌֚◌̖◌〪◌𐽐b; a◌〪◌̖◌𐽐◌֚b; a◌〪◌̖◌𐽐◌֚b; a◌〪◌̖◌𐽐◌֚b; a◌〪◌̖◌𐽐◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SOGDIAN COMBINING STROKE BELOW, LATIN SMALL LETTER B
+0061 10F50 059A 0316 302A 0062;0061 302A 10F50 0316 059A 0062;0061 302A 10F50 0316 059A 0062;0061 302A 10F50 0316 059A 0062;0061 302A 10F50 0316 059A 0062; # (a◌𐽐◌֚◌̖◌〪b; a◌〪◌𐽐◌̖◌֚b; a◌〪◌𐽐◌̖◌֚b; a◌〪◌𐽐◌̖◌֚b; a◌〪◌𐽐◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING STROKE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B
0061 05B0 094D 3099 11046 0062;0061 3099 094D 11046 05B0 0062;0061 3099 094D 11046 05B0 0062;0061 3099 094D 11046 05B0 0062;0061 3099 094D 11046 05B0 0062; # (a◌ְ◌्◌゙◌𑁆b; a◌゙◌्◌𑁆◌ְb; a◌゙◌्◌𑁆◌ְb; a◌゙◌्◌𑁆◌ְb; a◌゙◌्◌𑁆◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, BRAHMI VIRAMA, LATIN SMALL LETTER B
0061 11046 05B0 094D 3099 0062;0061 3099 11046 094D 05B0 0062;0061 3099 11046 094D 05B0 0062;0061 3099 11046 094D 05B0 0062;0061 3099 11046 094D 05B0 0062; # (a◌𑁆◌ְ◌्◌゙b; a◌゙◌𑁆◌्◌ְb; a◌゙◌𑁆◌्◌ְb; a◌゙◌𑁆◌्◌ְb; a◌゙◌𑁆◌्◌ְb; ) LATIN SMALL LETTER A, BRAHMI VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
0061 05B0 094D 3099 1107F 0062;0061 3099 094D 1107F 05B0 0062;0061 3099 094D 1107F 05B0 0062;0061 3099 094D 1107F 05B0 0062;0061 3099 094D 1107F 05B0 0062; # (a◌ְ◌्◌゙◌𑁿b; a◌゙◌्◌𑁿◌ְb; a◌゙◌्◌𑁿◌ְb; a◌゙◌्◌𑁿◌ְb; a◌゙◌्◌𑁿◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, BRAHMI NUMBER JOINER, LATIN SMALL LETTER B
@@ -18349,6 +18397,8 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE
0061 112E9 3099 093C 0334 0062;0061 0334 112E9 093C 3099 0062;0061 0334 112E9 093C 3099 0062;0061 0334 112E9 093C 3099 0062;0061 0334 112E9 093C 3099 0062; # (a◌𑋩◌゙◌़◌̴b; a◌̴◌𑋩◌़◌゙b; a◌̴◌𑋩◌़◌゙b; a◌̴◌𑋩◌़◌゙b; a◌̴◌𑋩◌़◌゙b; ) LATIN SMALL LETTER A, KHUDAWADI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B
0061 05B0 094D 3099 112EA 0062;0061 3099 094D 112EA 05B0 0062;0061 3099 094D 112EA 05B0 0062;0061 3099 094D 112EA 05B0 0062;0061 3099 094D 112EA 05B0 0062; # (a◌ְ◌्◌゙◌𑋪b; a◌゙◌्◌𑋪◌ְb; a◌゙◌्◌𑋪◌ְb; a◌゙◌्◌𑋪◌ְb; a◌゙◌्◌𑋪◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, KHUDAWADI SIGN VIRAMA, LATIN SMALL LETTER B
0061 112EA 05B0 094D 3099 0062;0061 3099 112EA 094D 05B0 0062;0061 3099 112EA 094D 05B0 0062;0061 3099 112EA 094D 05B0 0062;0061 3099 112EA 094D 05B0 0062; # (a◌𑋪◌ְ◌्◌゙b; a◌゙◌𑋪◌्◌ְb; a◌゙◌𑋪◌्◌ְb; a◌゙◌𑋪◌्◌ְb; a◌゙◌𑋪◌्◌ְb; ) LATIN SMALL LETTER A, KHUDAWADI SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
+0061 3099 093C 0334 1133B 0062;0061 0334 093C 1133B 3099 0062;0061 0334 093C 1133B 3099 0062;0061 0334 093C 1133B 3099 0062;0061 0334 093C 1133B 3099 0062; # (a◌゙◌़◌̴◌𑌻b; a◌̴◌़◌𑌻◌゙b; a◌̴◌़◌𑌻◌゙b; a◌̴◌़◌𑌻◌゙b; a◌̴◌़◌𑌻◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, COMBINING BINDU BELOW, LATIN SMALL LETTER B
+0061 1133B 3099 093C 0334 0062;0061 0334 1133B 093C 3099 0062;0061 0334 1133B 093C 3099 0062;0061 0334 1133B 093C 3099 0062;0061 0334 1133B 093C 3099 0062; # (a◌𑌻◌゙◌़◌̴b; a◌̴◌𑌻◌़◌゙b; a◌̴◌𑌻◌़◌゙b; a◌̴◌𑌻◌़◌゙b; a◌̴◌𑌻◌़◌゙b; ) LATIN SMALL LETTER A, COMBINING BINDU BELOW, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B
0061 3099 093C 0334 1133C 0062;0061 0334 093C 1133C 3099 0062;0061 0334 093C 1133C 3099 0062;0061 0334 093C 1133C 3099 0062;0061 0334 093C 1133C 3099 0062; # (a◌゙◌़◌̴◌𑌼b; a◌̴◌़◌𑌼◌゙b; a◌̴◌़◌𑌼◌゙b; a◌̴◌़◌𑌼◌゙b; a◌̴◌़◌𑌼◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, GRANTHA SIGN NUKTA, LATIN SMALL LETTER B
0061 1133C 3099 093C 0334 0062;0061 0334 1133C 093C 3099 0062;0061 0334 1133C 093C 3099 0062;0061 0334 1133C 093C 3099 0062;0061 0334 1133C 093C 3099 0062; # (a◌𑌼◌゙◌़◌̴b; a◌̴◌𑌼◌़◌゙b; a◌̴◌𑌼◌़◌゙b; a◌̴◌𑌼◌़◌゙b; a◌̴◌𑌼◌़◌゙b; ) LATIN SMALL LETTER A, GRANTHA SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B
0061 05B0 094D 3099 1134D 0062;0061 3099 094D 1134D 05B0 0062;0061 3099 094D 1134D 05B0 0062;0061 3099 094D 1134D 05B0 0062;0061 3099 094D 1134D 05B0 0062; # (a◌ְ◌्◌゙𑍍b; a◌゙◌्𑍍◌ְb; a◌゙◌्𑍍◌ְb; a◌゙◌्𑍍◌ְb; a◌゙◌्𑍍◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, GRANTHA SIGN VIRAMA, LATIN SMALL LETTER B
@@ -18381,6 +18431,8 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE
0061 11442 05B0 094D 3099 0062;0061 3099 11442 094D 05B0 0062;0061 3099 11442 094D 05B0 0062;0061 3099 11442 094D 05B0 0062;0061 3099 11442 094D 05B0 0062; # (a◌𑑂◌ְ◌्◌゙b; a◌゙◌𑑂◌्◌ְb; a◌゙◌𑑂◌्◌ְb; a◌゙◌𑑂◌्◌ְb; a◌゙◌𑑂◌्◌ְb; ) LATIN SMALL LETTER A, NEWA SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
0061 3099 093C 0334 11446 0062;0061 0334 093C 11446 3099 0062;0061 0334 093C 11446 3099 0062;0061 0334 093C 11446 3099 0062;0061 0334 093C 11446 3099 0062; # (a◌゙◌़◌̴◌𑑆b; a◌̴◌़◌𑑆◌゙b; a◌̴◌़◌𑑆◌゙b; a◌̴◌़◌𑑆◌゙b; a◌̴◌़◌𑑆◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, NEWA SIGN NUKTA, LATIN SMALL LETTER B
0061 11446 3099 093C 0334 0062;0061 0334 11446 093C 3099 0062;0061 0334 11446 093C 3099 0062;0061 0334 11446 093C 3099 0062;0061 0334 11446 093C 3099 0062; # (a◌𑑆◌゙◌़◌̴b; a◌̴◌𑑆◌़◌゙b; a◌̴◌𑑆◌़◌゙b; a◌̴◌𑑆◌़◌゙b; a◌̴◌𑑆◌़◌゙b; ) LATIN SMALL LETTER A, NEWA SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B
+0061 0315 0300 05AE 1145E 0062;00E0 05AE 1145E 0315 0062;0061 05AE 0300 1145E 0315 0062;00E0 05AE 1145E 0315 0062;0061 05AE 0300 1145E 0315 0062; # (a◌̕◌̀◌֮◌𑑞b; à◌֮◌𑑞◌̕b; a◌֮◌̀◌𑑞◌̕b; à◌֮◌𑑞◌̕b; a◌֮◌̀◌𑑞◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, NEWA SANDHI MARK, LATIN SMALL LETTER B
+0061 1145E 0315 0300 05AE 0062;0061 05AE 1145E 0300 0315 0062;0061 05AE 1145E 0300 0315 0062;0061 05AE 1145E 0300 0315 0062;0061 05AE 1145E 0300 0315 0062; # (a◌𑑞◌̕◌̀◌֮b; a◌֮◌𑑞◌̀◌̕b; a◌֮◌𑑞◌̀◌̕b; a◌֮◌𑑞◌̀◌̕b; a◌֮◌𑑞◌̀◌̕b; ) LATIN SMALL LETTER A, NEWA SANDHI MARK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
0061 05B0 094D 3099 114C2 0062;0061 3099 094D 114C2 05B0 0062;0061 3099 094D 114C2 05B0 0062;0061 3099 094D 114C2 05B0 0062;0061 3099 094D 114C2 05B0 0062; # (a◌ְ◌्◌゙◌𑓂b; a◌゙◌्◌𑓂◌ְb; a◌゙◌्◌𑓂◌ְb; a◌゙◌्◌𑓂◌ְb; a◌゙◌्◌𑓂◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, TIRHUTA SIGN VIRAMA, LATIN SMALL LETTER B
0061 114C2 05B0 094D 3099 0062;0061 3099 114C2 094D 05B0 0062;0061 3099 114C2 094D 05B0 0062;0061 3099 114C2 094D 05B0 0062;0061 3099 114C2 094D 05B0 0062; # (a◌𑓂◌ְ◌्◌゙b; a◌゙◌𑓂◌्◌ְb; a◌゙◌𑓂◌्◌ְb; a◌゙◌𑓂◌्◌ְb; a◌゙◌𑓂◌्◌ְb; ) LATIN SMALL LETTER A, TIRHUTA SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
0061 3099 093C 0334 114C3 0062;0061 0334 093C 114C3 3099 0062;0061 0334 093C 114C3 3099 0062;0061 0334 093C 114C3 3099 0062;0061 0334 093C 114C3 3099 0062; # (a◌゙◌़◌̴◌𑓃b; a◌̴◌़◌𑓃◌゙b; a◌̴◌़◌𑓃◌゙b; a◌̴◌़◌𑓃◌゙b; a◌̴◌़◌𑓃◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, TIRHUTA SIGN NUKTA, LATIN SMALL LETTER B
@@ -18397,8 +18449,26 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE
0061 116B7 3099 093C 0334 0062;0061 0334 116B7 093C 3099 0062;0061 0334 116B7 093C 3099 0062;0061 0334 116B7 093C 3099 0062;0061 0334 116B7 093C 3099 0062; # (a◌𑚷◌゙◌़◌̴b; a◌̴◌𑚷◌़◌゙b; a◌̴◌𑚷◌़◌゙b; a◌̴◌𑚷◌़◌゙b; a◌̴◌𑚷◌़◌゙b; ) LATIN SMALL LETTER A, TAKRI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B
0061 05B0 094D 3099 1172B 0062;0061 3099 094D 1172B 05B0 0062;0061 3099 094D 1172B 05B0 0062;0061 3099 094D 1172B 05B0 0062;0061 3099 094D 1172B 05B0 0062; # (a◌ְ◌्◌゙◌𑜫b; a◌゙◌्◌𑜫◌ְb; a◌゙◌्◌𑜫◌ְb; a◌゙◌्◌𑜫◌ְb; a◌゙◌्◌𑜫◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, AHOM SIGN KILLER, LATIN SMALL LETTER B
0061 1172B 05B0 094D 3099 0062;0061 3099 1172B 094D 05B0 0062;0061 3099 1172B 094D 05B0 0062;0061 3099 1172B 094D 05B0 0062;0061 3099 1172B 094D 05B0 0062; # (a◌𑜫◌ְ◌्◌゙b; a◌゙◌𑜫◌्◌ְb; a◌゙◌𑜫◌्◌ְb; a◌゙◌𑜫◌्◌ְb; a◌゙◌𑜫◌्◌ְb; ) LATIN SMALL LETTER A, AHOM SIGN KILLER, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
+0061 05B0 094D 3099 11839 0062;0061 3099 094D 11839 05B0 0062;0061 3099 094D 11839 05B0 0062;0061 3099 094D 11839 05B0 0062;0061 3099 094D 11839 05B0 0062; # (a◌ְ◌्◌゙◌𑠹b; a◌゙◌्◌𑠹◌ְb; a◌゙◌्◌𑠹◌ְb; a◌゙◌्◌𑠹◌ְb; a◌゙◌्◌𑠹◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DOGRA SIGN VIRAMA, LATIN SMALL LETTER B
+0061 11839 05B0 094D 3099 0062;0061 3099 11839 094D 05B0 0062;0061 3099 11839 094D 05B0 0062;0061 3099 11839 094D 05B0 0062;0061 3099 11839 094D 05B0 0062; # (a◌𑠹◌ְ◌्◌゙b; a◌゙◌𑠹◌्◌ְb; a◌゙◌𑠹◌्◌ְb; a◌゙◌𑠹◌्◌ְb; a◌゙◌𑠹◌्◌ְb; ) LATIN SMALL LETTER A, DOGRA SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
+0061 3099 093C 0334 1183A 0062;0061 0334 093C 1183A 3099 0062;0061 0334 093C 1183A 3099 0062;0061 0334 093C 1183A 3099 0062;0061 0334 093C 1183A 3099 0062; # (a◌゙◌़◌̴◌𑠺b; a◌̴◌़◌𑠺◌゙b; a◌̴◌़◌𑠺◌゙b; a◌̴◌़◌𑠺◌゙b; a◌̴◌़◌𑠺◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, DOGRA SIGN NUKTA, LATIN SMALL LETTER B
+0061 1183A 3099 093C 0334 0062;0061 0334 1183A 093C 3099 0062;0061 0334 1183A 093C 3099 0062;0061 0334 1183A 093C 3099 0062;0061 0334 1183A 093C 3099 0062; # (a◌𑠺◌゙◌़◌̴b; a◌̴◌𑠺◌़◌゙b; a◌̴◌𑠺◌़◌゙b; a◌̴◌𑠺◌़◌゙b; a◌̴◌𑠺◌़◌゙b; ) LATIN SMALL LETTER A, DOGRA SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B
+0061 05B0 094D 3099 11A34 0062;0061 3099 094D 11A34 05B0 0062;0061 3099 094D 11A34 05B0 0062;0061 3099 094D 11A34 05B0 0062;0061 3099 094D 11A34 05B0 0062; # (a◌ְ◌्◌゙◌𑨴b; a◌゙◌्◌𑨴◌ְb; a◌゙◌्◌𑨴◌ְb; a◌゙◌्◌𑨴◌ְb; a◌゙◌्◌𑨴◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, ZANABAZAR SQUARE SIGN VIRAMA, LATIN SMALL LETTER B
+0061 11A34 05B0 094D 3099 0062;0061 3099 11A34 094D 05B0 0062;0061 3099 11A34 094D 05B0 0062;0061 3099 11A34 094D 05B0 0062;0061 3099 11A34 094D 05B0 0062; # (a◌𑨴◌ְ◌्◌゙b; a◌゙◌𑨴◌्◌ְb; a◌゙◌𑨴◌्◌ְb; a◌゙◌𑨴◌्◌ְb; a◌゙◌𑨴◌्◌ְb; ) LATIN SMALL LETTER A, ZANABAZAR SQUARE SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
+0061 05B0 094D 3099 11A47 0062;0061 3099 094D 11A47 05B0 0062;0061 3099 094D 11A47 05B0 0062;0061 3099 094D 11A47 05B0 0062;0061 3099 094D 11A47 05B0 0062; # (a◌ְ◌्◌゙◌𑩇b; a◌゙◌्◌𑩇◌ְb; a◌゙◌्◌𑩇◌ְb; a◌゙◌्◌𑩇◌ְb; a◌゙◌्◌𑩇◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, ZANABAZAR SQUARE SUBJOINER, LATIN SMALL LETTER B
+0061 11A47 05B0 094D 3099 0062;0061 3099 11A47 094D 05B0 0062;0061 3099 11A47 094D 05B0 0062;0061 3099 11A47 094D 05B0 0062;0061 3099 11A47 094D 05B0 0062; # (a◌𑩇◌ְ◌्◌゙b; a◌゙◌𑩇◌्◌ְb; a◌゙◌𑩇◌्◌ְb; a◌゙◌𑩇◌्◌ְb; a◌゙◌𑩇◌्◌ְb; ) LATIN SMALL LETTER A, ZANABAZAR SQUARE SUBJOINER, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
+0061 05B0 094D 3099 11A99 0062;0061 3099 094D 11A99 05B0 0062;0061 3099 094D 11A99 05B0 0062;0061 3099 094D 11A99 05B0 0062;0061 3099 094D 11A99 05B0 0062; # (a◌ְ◌्◌゙◌𑪙b; a◌゙◌्◌𑪙◌ְb; a◌゙◌्◌𑪙◌ְb; a◌゙◌्◌𑪙◌ְb; a◌゙◌्◌𑪙◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, SOYOMBO SUBJOINER, LATIN SMALL LETTER B
+0061 11A99 05B0 094D 3099 0062;0061 3099 11A99 094D 05B0 0062;0061 3099 11A99 094D 05B0 0062;0061 3099 11A99 094D 05B0 0062;0061 3099 11A99 094D 05B0 0062; # (a◌𑪙◌ְ◌्◌゙b; a◌゙◌𑪙◌्◌ְb; a◌゙◌𑪙◌्◌ְb; a◌゙◌𑪙◌्◌ְb; a◌゙◌𑪙◌्◌ְb; ) LATIN SMALL LETTER A, SOYOMBO SUBJOINER, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
0061 05B0 094D 3099 11C3F 0062;0061 3099 094D 11C3F 05B0 0062;0061 3099 094D 11C3F 05B0 0062;0061 3099 094D 11C3F 05B0 0062;0061 3099 094D 11C3F 05B0 0062; # (a◌ְ◌्◌゙◌𑰿b; a◌゙◌्◌𑰿◌ְb; a◌゙◌्◌𑰿◌ְb; a◌゙◌्◌𑰿◌ְb; a◌゙◌्◌𑰿◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, BHAIKSUKI SIGN VIRAMA, LATIN SMALL LETTER B
0061 11C3F 05B0 094D 3099 0062;0061 3099 11C3F 094D 05B0 0062;0061 3099 11C3F 094D 05B0 0062;0061 3099 11C3F 094D 05B0 0062;0061 3099 11C3F 094D 05B0 0062; # (a◌𑰿◌ְ◌्◌゙b; a◌゙◌𑰿◌्◌ְb; a◌゙◌𑰿◌्◌ְb; a◌゙◌𑰿◌्◌ְb; a◌゙◌𑰿◌्◌ְb; ) LATIN SMALL LETTER A, BHAIKSUKI SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
+0061 3099 093C 0334 11D42 0062;0061 0334 093C 11D42 3099 0062;0061 0334 093C 11D42 3099 0062;0061 0334 093C 11D42 3099 0062;0061 0334 093C 11D42 3099 0062; # (a◌゙◌़◌̴◌𑵂b; a◌̴◌़◌𑵂◌゙b; a◌̴◌़◌𑵂◌゙b; a◌̴◌़◌𑵂◌゙b; a◌̴◌़◌𑵂◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, MASARAM GONDI SIGN NUKTA, LATIN SMALL LETTER B
+0061 11D42 3099 093C 0334 0062;0061 0334 11D42 093C 3099 0062;0061 0334 11D42 093C 3099 0062;0061 0334 11D42 093C 3099 0062;0061 0334 11D42 093C 3099 0062; # (a◌𑵂◌゙◌़◌̴b; a◌̴◌𑵂◌़◌゙b; a◌̴◌𑵂◌़◌゙b; a◌̴◌𑵂◌़◌゙b; a◌̴◌𑵂◌़◌゙b; ) LATIN SMALL LETTER A, MASARAM GONDI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B
+0061 05B0 094D 3099 11D44 0062;0061 3099 094D 11D44 05B0 0062;0061 3099 094D 11D44 05B0 0062;0061 3099 094D 11D44 05B0 0062;0061 3099 094D 11D44 05B0 0062; # (a◌ְ◌्◌゙◌𑵄b; a◌゙◌्◌𑵄◌ְb; a◌゙◌्◌𑵄◌ְb; a◌゙◌्◌𑵄◌ְb; a◌゙◌्◌𑵄◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, MASARAM GONDI SIGN HALANTA, LATIN SMALL LETTER B
+0061 11D44 05B0 094D 3099 0062;0061 3099 11D44 094D 05B0 0062;0061 3099 11D44 094D 05B0 0062;0061 3099 11D44 094D 05B0 0062;0061 3099 11D44 094D 05B0 0062; # (a◌𑵄◌ְ◌्◌゙b; a◌゙◌𑵄◌्◌ְb; a◌゙◌𑵄◌्◌ְb; a◌゙◌𑵄◌्◌ְb; a◌゙◌𑵄◌्◌ְb; ) LATIN SMALL LETTER A, MASARAM GONDI SIGN HALANTA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
+0061 05B0 094D 3099 11D45 0062;0061 3099 094D 11D45 05B0 0062;0061 3099 094D 11D45 05B0 0062;0061 3099 094D 11D45 05B0 0062;0061 3099 094D 11D45 05B0 0062; # (a◌ְ◌्◌゙◌𑵅b; a◌゙◌्◌𑵅◌ְb; a◌゙◌्◌𑵅◌ְb; a◌゙◌्◌𑵅◌ְb; a◌゙◌्◌𑵅◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, MASARAM GONDI VIRAMA, LATIN SMALL LETTER B
+0061 11D45 05B0 094D 3099 0062;0061 3099 11D45 094D 05B0 0062;0061 3099 11D45 094D 05B0 0062;0061 3099 11D45 094D 05B0 0062;0061 3099 11D45 094D 05B0 0062; # (a◌𑵅◌ְ◌्◌゙b; a◌゙◌𑵅◌्◌ְb; a◌゙◌𑵅◌्◌ְb; a◌゙◌𑵅◌्◌ְb; a◌゙◌𑵅◌्◌ְb; ) LATIN SMALL LETTER A, MASARAM GONDI VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
+0061 05B0 094D 3099 11D97 0062;0061 3099 094D 11D97 05B0 0062;0061 3099 094D 11D97 05B0 0062;0061 3099 094D 11D97 05B0 0062;0061 3099 094D 11D97 05B0 0062; # (a◌ְ◌्◌゙◌𑶗b; a◌゙◌्◌𑶗◌ְb; a◌゙◌्◌𑶗◌ְb; a◌゙◌्◌𑶗◌ְb; a◌゙◌्◌𑶗◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, GUNJALA GONDI VIRAMA, LATIN SMALL LETTER B
+0061 11D97 05B0 094D 3099 0062;0061 3099 11D97 094D 05B0 0062;0061 3099 11D97 094D 05B0 0062;0061 3099 11D97 094D 05B0 0062;0061 3099 11D97 094D 05B0 0062; # (a◌𑶗◌ְ◌्◌゙b; a◌゙◌𑶗◌्◌ְb; a◌゙◌𑶗◌्◌ְb; a◌゙◌𑶗◌्◌ְb; a◌゙◌𑶗◌्◌ְb; ) LATIN SMALL LETTER A, GUNJALA GONDI VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
0061 093C 0334 16AF0 0062;0061 0334 16AF0 093C 0062;0061 0334 16AF0 093C 0062;0061 0334 16AF0 093C 0062;0061 0334 16AF0 093C 0062; # (a◌़◌̴◌𖫰b; a◌̴◌𖫰◌़b; a◌̴◌𖫰◌़b; a◌̴◌𖫰◌़b; a◌̴◌𖫰◌़b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, BASSA VAH COMBINING HIGH TONE, LATIN SMALL LETTER B
0061 16AF0 093C 0334 0062;0061 16AF0 0334 093C 0062;0061 16AF0 0334 093C 0062;0061 16AF0 0334 093C 0062;0061 16AF0 0334 093C 0062; # (a◌𖫰◌़◌̴b; a◌𖫰◌̴◌़b; a◌𖫰◌̴◌़b; a◌𖫰◌̴◌़b; a◌𖫰◌̴◌़b; ) LATIN SMALL LETTER A, BASSA VAH COMBINING HIGH TONE, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B
0061 093C 0334 16AF1 0062;0061 0334 16AF1 093C 0062;0061 0334 16AF1 093C 0062;0061 0334 16AF1 093C 0062;0061 0334 16AF1 093C 0062; # (a◌़◌̴◌𖫱b; a◌̴◌𖫱◌़b; a◌̴◌𖫱◌़b; a◌̴◌𖫱◌़b; a◌̴◌𖫱◌़b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, BASSA VAH COMBINING LOW TONE, LATIN SMALL LETTER B
diff --git a/lib/stdlib/test/uri_string_SUITE.erl b/lib/stdlib/test/uri_string_SUITE.erl
new file mode 100644
index 0000000000..ddaead9c7c
--- /dev/null
+++ b/lib/stdlib/test/uri_string_SUITE.erl
@@ -0,0 +1,1168 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(uri_string_SUITE).
+
+-include_lib("common_test/include/ct.hrl").
+
+-export([all/0, suite/0,groups/0,
+ normalize/1, normalize_map/1, normalize_return_map/1, normalize_negative/1,
+ normalize_binary_pct_encoded_userinfo/1,
+ normalize_binary_pct_encoded_query/1,
+ normalize_binary_pct_encoded_fragment/1,
+ normalize_pct_encoded_userinfo/1,
+ normalize_pct_encoded_query/1,
+ normalize_pct_encoded_fragment/1,
+ parse_binary_fragment/1, parse_binary_host/1, parse_binary_host_ipv4/1,
+ parse_binary_host_ipv6/1,
+ parse_binary_path/1, parse_binary_pct_encoded_fragment/1, parse_binary_pct_encoded_query/1,
+ parse_binary_pct_encoded_userinfo/1, parse_binary_port/1,
+ parse_binary_query/1, parse_binary_scheme/1, parse_binary_userinfo/1,
+ parse_fragment/1, parse_host/1, parse_host_ipv4/1, parse_host_ipv6/1,
+ parse_path/1, parse_pct_encoded_fragment/1, parse_pct_encoded_query/1,
+ parse_pct_encoded_userinfo/1, parse_port/1,
+ parse_query/1, parse_scheme/1, parse_userinfo/1,
+ parse_list/1, parse_binary/1, parse_mixed/1, parse_relative/1,
+ parse_special/1, parse_special2/1, parse_negative/1,
+ recompose_fragment/1, recompose_parse_fragment/1,
+ recompose_query/1, recompose_parse_query/1,
+ recompose_path/1, recompose_parse_path/1,
+ recompose_autogen/1, parse_recompose_autogen/1,
+ transcode_basic/1, transcode_options/1, transcode_mixed/1, transcode_negative/1,
+ compose_query/1, compose_query_latin1/1, compose_query_negative/1,
+ dissect_query/1, dissect_query_negative/1,
+ interop_query_latin1/1, interop_query_utf8/1,
+ regression_parse/1, regression_recompose/1, regression_normalize/1
+ ]).
+
+
+-define(SCHEME, "foo").
+-define(USERINFO, "åsa").
+-define(USERINFO_ENC, "%C3%A5sa").
+-define(HOST, "älvsjö").
+-define(HOST_ENC, "%C3%A4lvsj%C3%B6").
+-define(IPV6, "::127.0.0.1").
+-define(IPV6_ENC, "[::127.0.0.1]").
+-define(PORT, 8042).
+-define(PORT_ENC, ":8042").
+-define(PATH, "/där").
+-define(PATH_ENC, "/d%C3%A4r").
+-define(QUERY, "name=örn").
+-define(QUERY_ENC, "?name=%C3%B6rn").
+-define(FRAGMENT, "näsa").
+-define(FRAGMENT_ENC, "#n%C3%A4sa").
+
+
+suite() ->
+ [{timetrap,{minutes,1}}].
+
+all() ->
+ [
+ normalize,
+ normalize_map,
+ normalize_return_map,
+ normalize_negative,
+ normalize_binary_pct_encoded_userinfo,
+ normalize_binary_pct_encoded_query,
+ normalize_binary_pct_encoded_fragment,
+ normalize_pct_encoded_userinfo,
+ normalize_pct_encoded_query,
+ normalize_pct_encoded_fragment,
+ parse_binary_scheme,
+ parse_binary_userinfo,
+ parse_binary_pct_encoded_userinfo,
+ parse_binary_host,
+ parse_binary_host_ipv4,
+ parse_binary_host_ipv6,
+ parse_binary_port,
+ parse_binary_path,
+ parse_binary_query,
+ parse_binary_pct_encoded_query,
+ parse_binary_fragment,
+ parse_binary_pct_encoded_fragment,
+ parse_scheme,
+ parse_userinfo,
+ parse_pct_encoded_userinfo,
+ parse_host,
+ parse_host_ipv4,
+ parse_host_ipv6,
+ parse_port,
+ parse_path,
+ parse_query,
+ parse_pct_encoded_query,
+ parse_fragment,
+ parse_pct_encoded_fragment,
+ parse_list,
+ parse_binary,
+ parse_mixed,
+ parse_relative,
+ parse_special,
+ parse_special2,
+ parse_negative,
+ recompose_fragment,
+ recompose_parse_fragment,
+ recompose_query,
+ recompose_parse_query,
+ recompose_path,
+ recompose_parse_path,
+ recompose_autogen,
+ parse_recompose_autogen,
+ transcode_basic,
+ transcode_options,
+ transcode_mixed,
+ transcode_negative,
+ compose_query,
+ compose_query_latin1,
+ compose_query_negative,
+ dissect_query,
+ dissect_query_negative,
+ interop_query_latin1,
+ interop_query_utf8,
+ regression_parse,
+ regression_recompose,
+ regression_normalize
+ ].
+
+groups() ->
+ [].
+
+
+%%-------------------------------------------------------------------------
+%% Helper functions
+%%-------------------------------------------------------------------------
+uri_combinations() ->
+ [[Sch,Usr,Hst,Prt,Pat,Qry,Frg] ||
+ Sch <- [fun update_scheme/1, fun update_scheme_binary/1, none],
+ Usr <- [fun update_userinfo/1, fun update_userinfo_binary/1, none],
+ Hst <- [fun update_host/1, fun update_host_binary/1,
+ fun update_ipv6/1, fun update_ipv6_binary/1, none],
+ Prt <- [fun update_port/1, none],
+ Pat <- [fun update_path/1, fun update_path_binary/1],
+ Qry <- [fun update_query/1,fun update_query_binary/1, none],
+ Frg <- [fun update_fragment/1, fun update_fragment_binary/1, none],
+ not (Usr =:= none andalso Hst =:= none andalso Prt =/= none),
+ not (Usr =/= none andalso Hst =:= none andalso Prt =:= none),
+ not (Usr =/= none andalso Hst =:= none andalso Prt =/= none)].
+
+
+generate_test_vector(Comb) ->
+ Fun = fun (F, {Map, URI}) when is_function(F) -> F({Map, URI});
+ (_, Map) -> Map
+ end,
+ lists:foldl(Fun, {#{}, empty}, Comb).
+
+generate_test_vectors(L) ->
+ lists:map(fun generate_test_vector/1, L).
+
+update_fragment({In, empty}) ->
+ {In#{fragment => ?FRAGMENT}, ?FRAGMENT_ENC};
+update_fragment({In, Out}) when is_list(Out) ->
+ {In#{fragment => ?FRAGMENT}, Out ++ ?FRAGMENT_ENC};
+update_fragment({In, Out}) when is_binary(Out) ->
+ {In#{fragment => ?FRAGMENT}, binary_to_list(Out) ++ ?FRAGMENT_ENC}.
+
+update_fragment_binary({In, empty}) ->
+ {In#{fragment => <<?FRAGMENT/utf8>>}, <<?FRAGMENT_ENC>>};
+update_fragment_binary({In, Out}) when is_list(Out) ->
+ {In#{fragment => <<?FRAGMENT/utf8>>}, Out ++ ?FRAGMENT_ENC};
+update_fragment_binary({In, Out}) when is_binary(Out) ->
+ {In#{fragment => <<?FRAGMENT/utf8>>}, <<Out/binary,?FRAGMENT_ENC>>}.
+
+
+update_query({In, empty}) ->
+ {In#{query => ?QUERY}, ?QUERY_ENC};
+update_query({In, Out}) when is_list(Out) ->
+ {In#{query => ?QUERY}, Out ++ ?QUERY_ENC};
+update_query({In, Out}) when is_binary(Out) ->
+ {In#{query => ?QUERY}, binary_to_list(Out) ++ ?QUERY_ENC}.
+
+update_query_binary({In, empty}) ->
+ {In#{query => <<?QUERY/utf8>>}, <<?QUERY_ENC>>};
+update_query_binary({In, Out}) when is_list(Out) ->
+ {In#{query => <<?QUERY/utf8>>}, Out ++ ?QUERY_ENC};
+update_query_binary({In, Out}) when is_binary(Out) ->
+ {In#{query => <<?QUERY/utf8>>}, <<Out/binary,?QUERY_ENC>>}.
+
+update_path({In, empty}) ->
+ {In#{path => ?PATH}, ?PATH_ENC};
+update_path({In, Out}) when is_list(Out) ->
+ {In#{path => ?PATH}, Out ++ ?PATH_ENC};
+update_path({In, Out}) when is_binary(Out) ->
+ {In#{path => ?PATH}, binary_to_list(Out) ++ ?PATH_ENC}.
+
+update_path_binary({In, empty}) ->
+ {In#{path => <<?PATH/utf8>>}, <<?PATH_ENC>>};
+update_path_binary({In, Out}) when is_list(Out) ->
+ {In#{path => <<?PATH/utf8>>}, Out ++ ?PATH_ENC};
+update_path_binary({In, Out}) when is_binary(Out) ->
+ {In#{path => <<?PATH/utf8>>}, <<Out/binary,?PATH_ENC>>}.
+
+update_port({In, Out}) when is_list(Out) ->
+ {In#{port => ?PORT}, Out ++ ?PORT_ENC};
+update_port({In, Out}) when is_binary(Out) ->
+ {In#{port => ?PORT}, <<Out/binary,?PORT_ENC>>}.
+
+update_host({In, empty}) ->
+ {In#{host => ?HOST}, "//" ++ ?HOST_ENC};
+update_host({In, Out}) when is_list(Out) ->
+ case maps:is_key(userinfo, In) of
+ true -> {In#{host => ?HOST}, Out ++ [$@|?HOST_ENC]};
+ false -> {In#{host => ?HOST}, Out ++ [$/,$/|?HOST_ENC]}
+ end;
+update_host({In, Out}) when is_binary(Out) ->
+ case maps:is_key(userinfo, In) of
+ true -> {In#{host => ?HOST}, binary_to_list(Out) ++ [$@|?HOST_ENC]};
+ false -> {In#{host => ?HOST}, binary_to_list(Out) ++ [$/,$/|?HOST_ENC]}
+ end.
+
+update_host_binary({In, empty}) ->
+ {In#{host => <<?HOST/utf8>>}, <<"//",?HOST_ENC>>};
+update_host_binary({In, Out}) when is_list(Out) ->
+ case maps:is_key(userinfo, In) of
+ true -> {In#{host => <<?HOST/utf8>>}, Out ++ [$@|?HOST_ENC]};
+ false -> {In#{host => <<?HOST/utf8>>}, Out ++ [$/,$/|?HOST_ENC]}
+ end;
+update_host_binary({In, Out}) when is_binary(Out) ->
+ case maps:is_key(userinfo, In) of
+ true -> {In#{host => <<?HOST/utf8>>}, <<Out/binary,$@,?HOST_ENC>>};
+ false-> {In#{host => <<?HOST/utf8>>}, <<Out/binary,"//",?HOST_ENC>>}
+ end.
+
+update_ipv6({In, empty}) ->
+ {In#{host => ?IPV6}, "//" ++ ?IPV6_ENC};
+update_ipv6({In, Out}) when is_list(Out) ->
+ case maps:is_key(userinfo, In) of
+ true -> {In#{host => ?IPV6}, Out ++ [$@|?IPV6_ENC]};
+ false -> {In#{host => ?IPV6}, Out ++ [$/,$/|?IPV6_ENC]}
+ end;
+update_ipv6({In, Out}) when is_binary(Out) ->
+ case maps:is_key(userinfo, In) of
+ true -> {In#{host => ?IPV6}, binary_to_list(Out) ++ [$@|?IPV6_ENC]};
+ false -> {In#{host => ?IPV6}, binary_to_list(Out) ++ [$/,$/|?IPV6_ENC]}
+ end.
+
+update_ipv6_binary({In, empty}) ->
+ {In#{host => <<?IPV6/utf8>>}, <<"//",?IPV6_ENC>>};
+update_ipv6_binary({In, Out}) when is_list(Out) ->
+ case maps:is_key(userinfo, In) of
+ true -> {In#{host => <<?IPV6/utf8>>}, Out ++ [$@|?IPV6_ENC]};
+ false -> {In#{host => <<?IPV6/utf8>>}, Out ++ [$/,$/|?IPV6_ENC]}
+ end;
+update_ipv6_binary({In, Out}) when is_binary(Out) ->
+ case maps:is_key(userinfo, In) of
+ true -> {In#{host => <<?IPV6/utf8>>}, <<Out/binary,$@,?IPV6_ENC>>};
+ false-> {In#{host => <<?IPV6/utf8>>}, <<Out/binary,"//",?IPV6_ENC>>}
+ end.
+
+update_userinfo({In, empty}) ->
+ {In#{userinfo => ?USERINFO}, "//" ++ ?USERINFO_ENC};
+update_userinfo({In, Out}) when is_list(Out) ->
+ {In#{userinfo => ?USERINFO}, Out ++ "//" ++ ?USERINFO_ENC};
+update_userinfo({In, Out}) when is_binary(Out) ->
+ {In#{userinfo => ?USERINFO}, binary_to_list(Out) ++ "//" ++ ?USERINFO_ENC}.
+
+update_userinfo_binary({In, empty}) ->
+ {In#{userinfo => <<?USERINFO/utf8>>}, <<"//",?USERINFO_ENC>>};
+update_userinfo_binary({In, Out}) when is_list(Out) ->
+ {In#{userinfo => <<?USERINFO/utf8>>}, Out ++ "//" ++ ?USERINFO_ENC};
+update_userinfo_binary({In, Out}) when is_binary(Out) ->
+ {In#{userinfo => <<?USERINFO/utf8>>}, <<Out/binary,"//",?USERINFO_ENC>>}.
+
+update_scheme({In, empty}) ->
+ {In#{scheme => ?SCHEME}, ?SCHEME ++ ":"}.
+
+update_scheme_binary({In, empty}) ->
+ {In#{scheme => <<?SCHEME/utf8>>}, <<?SCHEME,$:>>}.
+
+
+%% Test recompose on a generated test vector
+run_test_recompose({#{}, empty}) ->
+ try "" = uri_string:recompose(#{}) of
+ _ -> ok
+ catch
+ _:_ -> error({test_failed, #{}, ""})
+ end;
+run_test_recompose({Map, URI}) ->
+ try URI = uri_string:recompose(Map) of
+ URI -> ok
+ catch
+ _:_ -> error({test_failed, Map, URI})
+ end.
+
+%% Test parse - recompose on a generated test vector
+run_test_parse_recompose({#{}, empty}) ->
+ try "" = uri_string:recompose(uri_string:parse("")) of
+ _ -> ok
+ catch
+ _:_ -> error({test_failed, #{}, ""})
+ end;
+run_test_parse_recompose({Map, URI}) ->
+ try URI = uri_string:recompose(uri_string:parse(URI)) of
+ URI -> ok
+ catch
+ _:_ -> error({test_failed, Map, URI})
+ end.
+
+
+%%-------------------------------------------------------------------------
+%% Parse tests
+%%-------------------------------------------------------------------------
+
+parse_binary_scheme(_Config) ->
+ #{} = uri_string:parse(<<>>),
+ #{path := <<"foo">>} = uri_string:parse(<<"foo">>),
+ #{scheme := <<"foo">>} = uri_string:parse(<<"foo:">>),
+ #{scheme := <<"foo">>, path := <<"bar:nisse">>} = uri_string:parse(<<"foo:bar:nisse">>),
+ #{scheme := <<"foo">>, host := <<"">>} = uri_string:parse(<<"foo://">>),
+ #{scheme := <<"foo">>, host := <<"">>, path := <<"/">>} = uri_string:parse(<<"foo:///">>),
+ #{scheme := <<"foo">>, host := <<"">>, path := <<"//">>} = uri_string:parse(<<"foo:////">>),
+
+ #{path := <<"/">>} = uri_string:parse(<<"/">>),
+ #{host := <<>>} = uri_string:parse(<<"//">>),
+ #{host := <<>>, path := <<"/">>} = uri_string:parse(<<"///">>).
+
+parse_binary_userinfo(_Config) ->
+ #{scheme := <<"user">>, path := <<"password@localhost">>} =
+ uri_string:parse(<<"user:password@localhost">>),
+ #{path := <<"user@">>} = uri_string:parse(<<"user@">>),
+ #{path := <<"/user@">>} = uri_string:parse(<<"/user@">>),
+ #{path := <<"user@localhost">>} = uri_string:parse(<<"user@localhost">>),
+ #{userinfo := <<"user">>, host := <<"localhost">>} = uri_string:parse(<<"//user@localhost">>),
+ #{userinfo := <<"user:password">>, host := <<"localhost">>} =
+ uri_string:parse(<<"//user:password@localhost">>),
+ #{scheme := <<"foo">>, path := <<"/user@">>} =
+ uri_string:parse(<<"foo:/user@">>),
+ #{scheme := <<"foo">>, userinfo := <<"user">>, host := <<"localhost">>} =
+ uri_string:parse(<<"foo://user@localhost">>),
+ #{scheme := <<"foo">>, userinfo := <<"user:password">>, host := <<"localhost">>} =
+ uri_string:parse(<<"foo://user:password@localhost">>).
+
+parse_binary_pct_encoded_userinfo(_Config) ->
+ #{scheme := <<"user">>, path := <<"%E5%90%88@%E6%B0%97%E9%81%93">>} =
+ uri_string:parse(<<"user:%E5%90%88@%E6%B0%97%E9%81%93">>),
+ #{path := <<"%E5%90%88%E6%B0%97%E9%81%93@">>} =
+ uri_string:parse(<<"%E5%90%88%E6%B0%97%E9%81%93@">>),
+ #{path := <<"/%E5%90%88%E6%B0%97%E9%81%93@">>} =
+ uri_string:parse(<<"/%E5%90%88%E6%B0%97%E9%81%93@">>),
+ #{path := <<"%E5%90%88@%E6%B0%97%E9%81%93">>} =
+ uri_string:parse(<<"%E5%90%88@%E6%B0%97%E9%81%93">>),
+ #{userinfo := <<"%E5%90%88">>, host := <<"%E6%B0%97%E9%81%93">>} =
+ uri_string:parse(<<"//%E5%90%88@%E6%B0%97%E9%81%93">>),
+ #{userinfo := <<"%E5%90%88:%E6%B0%97">>, host := <<"%E9%81%93">>} =
+ uri_string:parse(<<"//%E5%90%88:%E6%B0%97@%E9%81%93">>),
+ #{scheme := <<"foo">>, path := <<"/%E5%90%88%E6%B0%97%E9%81%93@">>} =
+ uri_string:parse(<<"foo:/%E5%90%88%E6%B0%97%E9%81%93@">>),
+ #{scheme := <<"foo">>, userinfo := <<"%E5%90%88">>, host := <<"%E6%B0%97%E9%81%93">>} =
+ uri_string:parse(<<"foo://%E5%90%88@%E6%B0%97%E9%81%93">>),
+ #{scheme := <<"foo">>, userinfo := <<"%E5%90%88:%E6%B0%97">>, host := <<"%E9%81%93">>} =
+ uri_string:parse(<<"foo://%E5%90%88:%E6%B0%97@%E9%81%93">>),
+ {error,invalid_uri,"@"} = uri_string:parse(<<"//%E5%90%88@%E6%B0%97%E9%81%93@">>),
+ {error,invalid_uri,":"} = uri_string:parse(<<"foo://%E5%90%88@%E6%B0%97%E9%81%93@">>).
+
+parse_binary_host(_Config) ->
+ #{host := <<"hostname">>} = uri_string:parse(<<"//hostname">>),
+ #{host := <<"hostname">>,scheme := <<"foo">>} = uri_string:parse(<<"foo://hostname">>),
+ #{host := <<"hostname">>,scheme := <<"foo">>, userinfo := <<"user">>} =
+ uri_string:parse(<<"foo://user@hostname">>).
+
+parse_binary_host_ipv4(_Config) ->
+ #{host := <<"127.0.0.1">>} = uri_string:parse(<<"//127.0.0.1">>),
+ #{host := <<"127.0.0.1">>, path := <<"/over/there">>} =
+ uri_string:parse(<<"//127.0.0.1/over/there">>),
+ #{host := <<"127.0.0.1">>, query := <<"name=ferret">>} =
+ uri_string:parse(<<"//127.0.0.1?name=ferret">>),
+ #{host := <<"127.0.0.1">>, fragment := <<"nose">>} = uri_string:parse(<<"//127.0.0.1#nose">>),
+ #{host := <<"127.0.0.x">>,path := <<>>} = uri_string:parse(<<"//127.0.0.x">>),
+ #{host := <<"1227.0.0.1">>,path := <<>>} = uri_string:parse(<<"//1227.0.0.1">>).
+
+parse_binary_host_ipv6(_Config) ->
+ #{host := <<"::127.0.0.1">>} = uri_string:parse(<<"//[::127.0.0.1]">>),
+ #{host := <<"2001:0db8:0000:0000:0000:0000:1428:07ab">>} =
+ uri_string:parse(<<"//[2001:0db8:0000:0000:0000:0000:1428:07ab]">>),
+ #{host := <<"::127.0.0.1">>, path := <<"/over/there">>} =
+ uri_string:parse(<<"//[::127.0.0.1]/over/there">>),
+ #{host := <<"::127.0.0.1">>, query := <<"name=ferret">>} =
+ uri_string:parse(<<"//[::127.0.0.1]?name=ferret">>),
+ #{host := <<"::127.0.0.1">>, fragment := <<"nose">>} =
+ uri_string:parse(<<"//[::127.0.0.1]#nose">>),
+ {error,invalid_uri,"x"} = uri_string:parse(<<"//[::127.0.0.x]">>),
+ {error,invalid_uri,"::1227.0.0.1"} = uri_string:parse(<<"//[::1227.0.0.1]">>),
+ {error,invalid_uri,"G"} = uri_string:parse(<<"//[2001:0db8:0000:0000:0000:0000:1428:G7ab]">>).
+
+parse_binary_port(_Config) ->
+ #{path:= <<"/:8042">>} =
+ uri_string:parse(<<"/:8042">>),
+ #{host:= <<>>, port := 8042} =
+ uri_string:parse(<<"//:8042">>),
+ #{host := <<"example.com">>, port:= 8042} =
+ uri_string:parse(<<"//example.com:8042">>),
+ #{scheme := <<"foo">>, path := <<"/:8042">>} =
+ uri_string:parse(<<"foo:/:8042">>),
+ #{scheme := <<"foo">>, host := <<>>, port := 8042} =
+ uri_string:parse(<<"foo://:8042">>),
+ #{scheme := <<"foo">>, host := <<"example.com">>, port := 8042} =
+ uri_string:parse(<<"foo://example.com:8042">>),
+ {error,invalid_uri,":"} = uri_string:parse(":600"),
+ {error,invalid_uri,"x"} = uri_string:parse("//:8042x").
+
+parse_binary_path(_Config) ->
+ #{path := <<"over/there">>} = uri_string:parse(<<"over/there">>),
+ #{path := <<"/over/there">>} = uri_string:parse(<<"/over/there">>),
+ #{scheme := <<"foo">>, path := <<"/over/there">>} =
+ uri_string:parse(<<"foo:/over/there">>),
+ #{scheme := <<"foo">>, host := <<"example.com">>, path := <<"/over/there">>} =
+ uri_string:parse(<<"foo://example.com/over/there">>),
+ #{scheme := <<"foo">>, host := <<"example.com">>, path := <<"/over/there">>, port := 8042} =
+ uri_string:parse(<<"foo://example.com:8042/over/there">>).
+
+parse_binary_query(_Config) ->
+ #{scheme := <<"foo">>, query := <<"name=ferret">>} =
+ uri_string:parse(<<"foo:?name=ferret">>),
+ #{scheme := <<"foo">>, path:= <<"over/there">>, query := <<"name=ferret">>} =
+ uri_string:parse(<<"foo:over/there?name=ferret">>),
+ #{scheme := <<"foo">>, path:= <<"/over/there">>, query := <<"name=ferret">>} =
+ uri_string:parse(<<"foo:/over/there?name=ferret">>),
+ #{scheme := <<"foo">>, host := <<"example.com">>, query := <<"name=ferret">>} =
+ uri_string:parse(<<"foo://example.com?name=ferret">>),
+ #{scheme := <<"foo">>, host := <<"example.com">>, path := <<"/">>, query := <<"name=ferret">>} =
+ uri_string:parse(<<"foo://example.com/?name=ferret">>),
+
+ #{path := <<>>, query := <<"name=ferret">>} =
+ uri_string:parse(<<"?name=ferret">>),
+ #{path := <<"over/there">>, query := <<"name=ferret">>} =
+ uri_string:parse(<<"over/there?name=ferret">>),
+ #{path := <<"/">>, query := <<"name=ferret">>} =
+ uri_string:parse(<<"/?name=ferret">>),
+ #{path := <<"/over/there">>, query := <<"name=ferret">>} =
+ uri_string:parse(<<"/over/there?name=ferret">>),
+ #{host := <<"example.com">>, query := <<"name=ferret">>} =
+ uri_string:parse(<<"//example.com?name=ferret">>),
+ #{host := <<"example.com">>, path := <<"/">>, query := <<"name=ferret">>} =
+ uri_string:parse(<<"//example.com/?name=ferret">>).
+
+parse_binary_pct_encoded_query(_Config) ->
+ #{scheme := <<"foo">>, host := <<"example.com">>, path := <<"/">>,
+ query := <<"name=%E5%90%88%E6%B0%97%E9%81%93">>} =
+ uri_string:parse(<<"foo://example.com/?name=%E5%90%88%E6%B0%97%E9%81%93">>),
+ #{host := <<"example.com">>, path := <<"/">>, query := <<"name=%E5%90%88%E6%B0%97%E9%81%93">>} =
+ uri_string:parse(<<"//example.com/?name=%E5%90%88%E6%B0%97%E9%81%93">>).
+
+parse_binary_fragment(_Config) ->
+ #{scheme := <<"foo">>, fragment := <<"nose">>} =
+ uri_string:parse(<<"foo:#nose">>),
+ #{scheme := <<"foo">>, path:= <<"over/there">>, fragment := <<"nose">>} =
+ uri_string:parse(<<"foo:over/there#nose">>),
+ #{scheme := <<"foo">>, path:= <<"/over/there">>, fragment := <<"nose">>} =
+ uri_string:parse(<<"foo:/over/there#nose">>),
+ #{scheme := <<"foo">>, host := <<"example.com">>, fragment := <<"nose">>} =
+ uri_string:parse(<<"foo://example.com#nose">>),
+ #{scheme := <<"foo">>, host := <<"example.com">>, path := <<"/">>, fragment := <<"nose">>} =
+ uri_string:parse(<<"foo://example.com/#nose">>),
+ #{scheme := <<"foo">>, host := <<"example.com">>, fragment := <<"nose">>} =
+ uri_string:parse(<<"foo://example.com#nose">>),
+
+ #{fragment := <<"nose">>} =
+ uri_string:parse(<<"#nose">>),
+ #{path := <<"over/there">>, fragment := <<"nose">>} =
+ uri_string:parse(<<"over/there#nose">>),
+ #{path := <<"/">>, fragment := <<"nose">>} =
+ uri_string:parse(<<"/#nose">>),
+ #{path := <<"/over/there">>, fragment := <<"nose">>} =
+ uri_string:parse(<<"/over/there#nose">>),
+ #{host := <<"example.com">>, fragment := <<"nose">>} =
+ uri_string:parse(<<"//example.com#nose">>),
+ #{host := <<"example.com">>, path := <<"/">>, fragment := <<"nose">>} =
+ uri_string:parse(<<"//example.com/#nose">>).
+
+parse_binary_pct_encoded_fragment(_Config) ->
+ #{scheme := <<"foo">>, host := <<"example.com">>,
+ fragment := <<"%E5%90%88%E6%B0%97%E9%81%93">>} =
+ uri_string:parse(<<"foo://example.com#%E5%90%88%E6%B0%97%E9%81%93">>),
+ #{host := <<"example.com">>, path := <<"/">>,
+ fragment := <<"%E5%90%88%E6%B0%97%E9%81%93">>} =
+ uri_string:parse(<<"//example.com/#%E5%90%88%E6%B0%97%E9%81%93">>).
+
+parse_scheme(_Config) ->
+ #{} = uri_string:parse(""),
+ #{path := "foo"} = uri_string:parse("foo"),
+ #{scheme := "foo"} = uri_string:parse("foo:"),
+ #{scheme := "foo", path := "bar:nisse"} = uri_string:parse("foo:bar:nisse"),
+ #{scheme := "foo", host := ""} = uri_string:parse("foo://"),
+ #{scheme := "foo", host := "", path := "/"} = uri_string:parse("foo:///"),
+ #{scheme := "foo", host := "", path := "//"} = uri_string:parse("foo:////"),
+
+ #{path := "/"} = uri_string:parse("/"),
+ #{host := ""} = uri_string:parse("//"),
+ #{host := "", path := "/"} = uri_string:parse("///").
+
+parse_userinfo(_Config) ->
+ #{scheme := "user", path := "password@localhost"} = uri_string:parse("user:password@localhost"),
+ #{path := "user@"} = uri_string:parse("user@"),
+ #{path := "/user@"} = uri_string:parse("/user@"),
+ #{path := "user@localhost"} = uri_string:parse("user@localhost"),
+ #{userinfo := "user", host := "localhost"} = uri_string:parse("//user@localhost"),
+ #{userinfo := "user:password", host := "localhost"} =
+ uri_string:parse("//user:password@localhost"),
+ #{scheme := "foo", path := "/user@"} =
+ uri_string:parse("foo:/user@"),
+ #{scheme := "foo", userinfo := "user", host := "localhost"} =
+ uri_string:parse("foo://user@localhost"),
+ #{scheme := "foo", userinfo := "user:password", host := "localhost"} =
+ uri_string:parse("foo://user:password@localhost").
+
+parse_pct_encoded_userinfo(_Config) ->
+ #{scheme := "user", path := "%E5%90%88@%E6%B0%97%E9%81%93"} =
+ uri_string:parse("user:%E5%90%88@%E6%B0%97%E9%81%93"),
+ #{path := "%E5%90%88%E6%B0%97%E9%81%93@"} =
+ uri_string:parse("%E5%90%88%E6%B0%97%E9%81%93@"),
+ #{path := "/%E5%90%88%E6%B0%97%E9%81%93@"} =
+ uri_string:parse("/%E5%90%88%E6%B0%97%E9%81%93@"),
+ #{path := "%E5%90%88@%E6%B0%97%E9%81%93"} =
+ uri_string:parse("%E5%90%88@%E6%B0%97%E9%81%93"),
+ #{userinfo := "%E5%90%88", host := "%E6%B0%97%E9%81%93"} =
+ uri_string:parse("//%E5%90%88@%E6%B0%97%E9%81%93"),
+ #{userinfo := "%E5%90%88:%E6%B0%97", host := "%E9%81%93"} =
+ uri_string:parse("//%E5%90%88:%E6%B0%97@%E9%81%93"),
+ #{scheme := "foo", path := "/%E5%90%88%E6%B0%97%E9%81%93@"} =
+ uri_string:parse("foo:/%E5%90%88%E6%B0%97%E9%81%93@"),
+ #{scheme := "foo", userinfo := "%E5%90%88", host := "%E6%B0%97%E9%81%93"} =
+ uri_string:parse("foo://%E5%90%88@%E6%B0%97%E9%81%93"),
+ #{scheme := "foo", userinfo := "%E5%90%88:%E6%B0%97", host := "%E9%81%93"} =
+ uri_string:parse("foo://%E5%90%88:%E6%B0%97@%E9%81%93"),
+ {error,invalid_uri,"@"} = uri_string:parse("//%E5%90%88@%E6%B0%97%E9%81%93@"),
+ {error,invalid_uri,":"} = uri_string:parse("foo://%E5%90%88@%E6%B0%97%E9%81%93@").
+
+parse_host(_Config) ->
+ #{host := "hostname"} = uri_string:parse("//hostname"),
+ #{host := "hostname",scheme := "foo"} = uri_string:parse("foo://hostname"),
+ #{host := "hostname",scheme := "foo", userinfo := "user"} =
+ uri_string:parse("foo://user@hostname").
+
+parse_host_ipv4(_Config) ->
+ #{host := "127.0.0.1"} = uri_string:parse("//127.0.0.1"),
+ #{host := "2001:0db8:0000:0000:0000:0000:1428:07ab"} =
+ uri_string:parse("//[2001:0db8:0000:0000:0000:0000:1428:07ab]"),
+ #{host := "127.0.0.1", path := "/over/there"} = uri_string:parse("//127.0.0.1/over/there"),
+ #{host := "127.0.0.1", query := "name=ferret"} = uri_string:parse("//127.0.0.1?name=ferret"),
+ #{host := "127.0.0.1", fragment := "nose"} = uri_string:parse("//127.0.0.1#nose"),
+ #{host := "127.0.0.x",path := []} = uri_string:parse("//127.0.0.x"),
+ #{host := "1227.0.0.1",path := []} = uri_string:parse("//1227.0.0.1").
+
+parse_host_ipv6(_Config) ->
+ #{host := "::127.0.0.1"} = uri_string:parse("//[::127.0.0.1]"),
+ #{host := "::127.0.0.1", path := "/over/there"} = uri_string:parse("//[::127.0.0.1]/over/there"),
+ #{host := "::127.0.0.1", query := "name=ferret"} =
+ uri_string:parse("//[::127.0.0.1]?name=ferret"),
+ #{host := "::127.0.0.1", fragment := "nose"} = uri_string:parse("//[::127.0.0.1]#nose"),
+ {error,invalid_uri,"x"} = uri_string:parse("//[::127.0.0.x]"),
+ {error,invalid_uri,"::1227.0.0.1"} = uri_string:parse("//[::1227.0.0.1]"),
+ {error,invalid_uri,"G"} = uri_string:parse("//[2001:0db8:0000:0000:0000:0000:1428:G7ab]").
+
+parse_port(_Config) ->
+ #{path:= "/:8042"} =
+ uri_string:parse("/:8042"),
+ #{host:= "", port := 8042} =
+ uri_string:parse("//:8042"),
+ #{host := "example.com", port:= 8042} =
+ uri_string:parse("//example.com:8042"),
+ #{scheme := "foo", path := "/:8042"} =
+ uri_string:parse("foo:/:8042"),
+ #{scheme := "foo", host := "", port := 8042} =
+ uri_string:parse("foo://:8042"),
+ #{scheme := "foo", host := "example.com", port := 8042} =
+ uri_string:parse("foo://example.com:8042").
+
+parse_path(_Config) ->
+ #{path := "over/there"} = uri_string:parse("over/there"),
+ #{path := "/over/there"} = uri_string:parse("/over/there"),
+ #{scheme := "foo", path := "/over/there"} =
+ uri_string:parse("foo:/over/there"),
+ #{scheme := "foo", host := "example.com", path := "/over/there"} =
+ uri_string:parse("foo://example.com/over/there"),
+ #{scheme := "foo", host := "example.com", path := "/over/there", port := 8042} =
+ uri_string:parse("foo://example.com:8042/over/there").
+
+parse_query(_Config) ->
+ #{scheme := "foo", query := "name=ferret"} =
+ uri_string:parse("foo:?name=ferret"),
+ #{scheme := "foo", path:= "over/there", query := "name=ferret"} =
+ uri_string:parse("foo:over/there?name=ferret"),
+ #{scheme := "foo", path:= "/over/there", query := "name=ferret"} =
+ uri_string:parse("foo:/over/there?name=ferret"),
+ #{scheme := "foo", host := "example.com", query := "name=ferret"} =
+ uri_string:parse("foo://example.com?name=ferret"),
+ #{scheme := "foo", host := "example.com", path := "/", query := "name=ferret"} =
+ uri_string:parse("foo://example.com/?name=ferret"),
+
+ #{path := "", query := "name=ferret"} =
+ uri_string:parse("?name=ferret"),
+ #{path := "over/there", query := "name=ferret"} =
+ uri_string:parse("over/there?name=ferret"),
+ #{path := "/", query := "name=ferret"} =
+ uri_string:parse("/?name=ferret"),
+ #{path := "/over/there", query := "name=ferret"} =
+ uri_string:parse("/over/there?name=ferret"),
+ #{host := "example.com", query := "name=ferret"} =
+ uri_string:parse("//example.com?name=ferret"),
+ #{host := "example.com", path := "/", query := "name=ferret"} =
+ uri_string:parse("//example.com/?name=ferret").
+
+parse_pct_encoded_query(_Config) ->
+ #{scheme := "foo", host := "example.com", path := "/",
+ query := "name=%E5%90%88%E6%B0%97%E9%81%93"} =
+ uri_string:parse("foo://example.com/?name=%E5%90%88%E6%B0%97%E9%81%93"),
+ #{host := "example.com", path := "/", query := "name=%E5%90%88%E6%B0%97%E9%81%93"} =
+ uri_string:parse("//example.com/?name=%E5%90%88%E6%B0%97%E9%81%93").
+
+parse_fragment(_Config) ->
+ #{scheme := "foo", fragment := "nose"} =
+ uri_string:parse("foo:#nose"),
+ #{scheme := "foo", path:= "over/there", fragment := "nose"} =
+ uri_string:parse("foo:over/there#nose"),
+ #{scheme := "foo", path:= "/over/there", fragment := "nose"} =
+ uri_string:parse("foo:/over/there#nose"),
+ #{scheme := "foo", host := "example.com", fragment := "nose"} =
+ uri_string:parse("foo://example.com#nose"),
+ #{scheme := "foo", host := "example.com", path := "/", fragment := "nose"} =
+ uri_string:parse("foo://example.com/#nose"),
+ #{scheme := "foo", host := "example.com", fragment := "nose"} =
+ uri_string:parse("foo://example.com#nose"),
+
+ #{fragment := "nose"} =
+ uri_string:parse("#nose"),
+ #{path := "over/there", fragment := "nose"} =
+ uri_string:parse("over/there#nose"),
+ #{path := "/", fragment := "nose"} =
+ uri_string:parse("/#nose"),
+ #{path := "/over/there", fragment := "nose"} =
+ uri_string:parse("/over/there#nose"),
+ #{host := "example.com", fragment := "nose"} =
+ uri_string:parse("//example.com#nose"),
+ #{host := "example.com", path := "/", fragment := "nose"} =
+ uri_string:parse("//example.com/#nose").
+
+parse_pct_encoded_fragment(_Config) ->
+ #{scheme := "foo", host := "example.com",
+ fragment := "%E5%90%88%E6%B0%97%E9%81%93"} =
+ uri_string:parse("foo://example.com#%E5%90%88%E6%B0%97%E9%81%93"),
+ #{host := "example.com", path := "/",
+ fragment := "%E5%90%88%E6%B0%97%E9%81%93"} =
+ uri_string:parse("//example.com/#%E5%90%88%E6%B0%97%E9%81%93").
+
+parse_list(_Config) ->
+ #{scheme := "foo", path := "bar:nisse"} = uri_string:parse("foo:bar:nisse"),
+ #{scheme := "foo", host := "example.com", port := 8042,
+ path := "/over/there", query := "name=ferret", fragment := "nose"} =
+ uri_string:parse("foo://example.com:8042/over/there?name=ferret#nose"),
+ #{scheme := "foo", userinfo := "admin:admin", host := "example.com", port := 8042,
+ path := "/over/there", query := "name=ferret", fragment := "nose"} =
+ uri_string:parse("foo://admin:[email protected]:8042/over/there?name=ferret#nose").
+
+parse_binary(_Config) ->
+ #{scheme := <<"foo">>, path := <<"bar:nisse">>} = uri_string:parse(<<"foo:bar:nisse">>),
+ #{scheme := <<"foo">>, host := <<"example.com">>, port := 8042,
+ path := <<"/over/there">>, query := <<"name=ferret">>, fragment := <<"nose">>} =
+ uri_string:parse(<<"foo://example.com:8042/over/there?name=ferret#nose">>),
+ #{scheme := <<"foo">>, userinfo := <<"admin:admin">>, host := <<"example.com">>, port := 8042,
+ path := <<"/over/there">>, query := <<"name=ferret">>, fragment := <<"nose">>} =
+ uri_string:parse(<<"foo://admin:[email protected]:8042/over/there?name=ferret#nose">>).
+
+
+parse_mixed(_Config) ->
+ #{scheme := "foo", path := "bar"} =
+ uri_string:parse(lists:append("fo",<<"o:bar">>)),
+ #{scheme := "foo", path := "bar"} =
+ uri_string:parse(lists:append("foo:b",<<"ar">>)),
+ #{scheme := "foo", path := "bar:bar"} =
+ uri_string:parse([[102],[111,111],<<":bar">>,58,98,97,114]).
+
+parse_relative(_Config) ->
+ #{path := "/path"} =
+ uri_string:parse(lists:append("/pa",<<"th">>)),
+ #{path := "foo"} =
+ uri_string:parse(lists:append("fo",<<"o">>)).
+
+parse_special(_Config) ->
+ #{host := [],query := []} = uri_string:parse("//?"),
+ #{fragment := [],host := []} = uri_string:parse("//#"),
+ #{host := [],query := [],scheme := "foo"} = uri_string:parse("foo://?"),
+ #{fragment := [],host := [],scheme := "foo"} = uri_string:parse("foo://#"),
+ #{host := <<>>, path := <<"/">>} = uri_string:parse(<<"///">>),
+ #{host := <<"hostname">>} = uri_string:parse(<<"//hostname">>),
+ #{host := <<>>, path := <<"/hostname">>} = uri_string:parse(<<"///hostname">>),
+ #{host := [],path := "/",query := []} = uri_string:parse("///?"),
+ #{fragment := [],host := [],path := "/"} = uri_string:parse("///#"),
+ #{host := "foo",query := []} = uri_string:parse("//foo?"),
+ #{fragment := [],host := "foo"} = uri_string:parse("//foo#"),
+ #{host := "foo",path := "/"} = uri_string:parse("//foo/"),
+ #{host := "foo",query := [],scheme := "http"} = uri_string:parse("http://foo?"),
+ #{fragment := [],host := "foo",scheme := "http"} = uri_string:parse("http://foo#"),
+ #{host := "foo",path := "/",scheme := "http"} = uri_string:parse("http://foo/"),
+ #{fragment := [],host := "host",port := 80,scheme := "http"} = uri_string:parse("http://host:80#"),
+ #{host := "host",port := 80,query := [],scheme := "http"} = uri_string:parse("http://host:80?"),
+ #{path := [],query := []} = uri_string:parse("?"),
+ #{path := [],query := "?"} = uri_string:parse("??"),
+ #{path := [],query := "??"} = uri_string:parse("???").
+
+parse_special2(_Config) ->
+ #{host := [],path := "/",port := 1,scheme := "a"} = uri_string:parse("a://:1/"),
+ #{path := "/a/",scheme := "a"} = uri_string:parse("a:/a/"),
+ #{host := [],path := [],userinfo := []} = uri_string:parse("//@"),
+ #{host := [],path := [],scheme := "foo",userinfo := []} = uri_string:parse("foo://@"),
+ #{host := [],path := "/",userinfo := []} = uri_string:parse("//@/"),
+ #{host := [],path := "/",scheme := "foo",userinfo := []} = uri_string:parse("foo://@/"),
+ #{host := "localhost",path := "/",port := undefined} = uri_string:parse("//localhost:/"),
+ #{host := [],path := [],port := undefined} = uri_string:parse("//:").
+
+parse_negative(_Config) ->
+ {error,invalid_uri,"å"} = uri_string:parse("å"),
+ {error,invalid_uri,"å"} = uri_string:parse("aå:/foo"),
+ {error,invalid_uri,":"} = uri_string:parse("foo://usär@host"),
+ {error,invalid_uri,"ö"} = uri_string:parse("//host/path?foö=bar"),
+ {error,invalid_uri,"ö"} = uri_string:parse("//host/path#foö"),
+ {error,invalid_uri,":::127.0.0.1"} = uri_string:parse("//[:::127.0.0.1]"),
+ {error,invalid_uri,"A"} = uri_string:parse("//localhost:A8").
+
+
+%%-------------------------------------------------------------------------
+%% Recompose tests
+%%-------------------------------------------------------------------------
+recompose_fragment(_Config) ->
+ <<?FRAGMENT_ENC>> = uri_string:recompose(#{fragment => <<?FRAGMENT/utf8>>, path => <<>>}),
+ ?FRAGMENT_ENC = uri_string:recompose(#{fragment => ?FRAGMENT, path => ""}).
+
+recompose_parse_fragment(_Config) ->
+ <<?FRAGMENT_ENC>> = uri_string:recompose(uri_string:parse(<<?FRAGMENT_ENC>>)),
+ ?FRAGMENT_ENC = uri_string:recompose(uri_string:parse(?FRAGMENT_ENC)).
+
+recompose_query(_Config) ->
+ <<?QUERY_ENC>> =
+ uri_string:recompose(#{query => <<?QUERY/utf8>>, path => <<>>}),
+ <<?QUERY_ENC?FRAGMENT_ENC>> =
+ uri_string:recompose(#{query => <<?QUERY/utf8>>,
+ fragment => <<?FRAGMENT/utf8>>,
+ path => <<>>}),
+ "?name=%C3%B6rn" =
+ uri_string:recompose(#{query => "name=örn", path => ""}),
+ "?name=%C3%B6rn#n%C3%A4sa" =
+ uri_string:recompose(#{query => "name=örn",
+ fragment => "näsa",
+ path => ""}).
+
+recompose_parse_query(_Config) ->
+ <<"?name=%C3%B6rn">> = uri_string:recompose(uri_string:parse(<<"?name=%C3%B6rn">>)),
+ <<"?name=%C3%B6rn#n%C3%A4sa">> =
+ uri_string:recompose(uri_string:parse(<<"?name=%C3%B6rn#n%C3%A4sa">>)),
+ "?name=%C3%B6rn" = uri_string:recompose(uri_string:parse("?name=%C3%B6rn")),
+ "?name=%C3%B6rn#n%C3%A4sa" = uri_string:recompose(uri_string:parse("?name=%C3%B6rn#n%C3%A4sa")).
+
+recompose_path(_Config) ->
+ <<"/d%C3%A4r">> =
+ uri_string:recompose(#{path => <<"/där"/utf8>>}),
+ <<"/d%C3%A4r#n%C3%A4sa">> =
+ uri_string:recompose(#{path => <<"/där"/utf8>>,
+ fragment => <<"näsa"/utf8>>}),
+ <<"/d%C3%A4r?name=%C3%B6rn">> =
+ uri_string:recompose(#{path => <<"/där"/utf8>>,
+ query => <<"name=örn"/utf8>>}),
+ <<"/d%C3%A4r?name=%C3%B6rn#n%C3%A4sa">> =
+ uri_string:recompose(#{path => <<"/där"/utf8>>,
+ query => <<"name=örn"/utf8>>,
+ fragment => <<"näsa"/utf8>>}),
+
+
+ "/d%C3%A4r" =
+ uri_string:recompose(#{path => "/där"}),
+ "/d%C3%A4r#n%C3%A4sa" =
+ uri_string:recompose(#{path => "/där",
+ fragment => "näsa"}),
+ "/d%C3%A4r?name=%C3%B6rn" =
+ uri_string:recompose(#{path => "/där",
+ query => "name=örn"}),
+ "/d%C3%A4r?name=%C3%B6rn#n%C3%A4sa" =
+ uri_string:recompose(#{path => "/där",
+ query => "name=örn",
+ fragment => "näsa"}).
+
+
+recompose_parse_path(_Config) ->
+ <<"/d%C3%A4r">> =
+ uri_string:recompose(uri_string:parse(<<"/d%C3%A4r">>)),
+ <<"/d%C3%A4r#n%C3%A4sa">> =
+ uri_string:recompose(uri_string:parse(<<"/d%C3%A4r#n%C3%A4sa">>)),
+ <<"/d%C3%A4r?name=%C3%B6rn">> =
+ uri_string:recompose(uri_string:parse(<<"/d%C3%A4r?name=%C3%B6rn">>)),
+
+ "/d%C3%A4r" =
+ uri_string:recompose(uri_string:parse("/d%C3%A4r")),
+ "/d%C3%A4r#n%C3%A4sa" =
+ uri_string:recompose(uri_string:parse("/d%C3%A4r#n%C3%A4sa")),
+ "/d%C3%A4r?name=%C3%B6rn" =
+ uri_string:recompose(uri_string:parse("/d%C3%A4r?name=%C3%B6rn")).
+
+
+recompose_autogen(_Config) ->
+ Tests = generate_test_vectors(uri_combinations()),
+ lists:map(fun run_test_recompose/1, Tests).
+
+parse_recompose_autogen(_Config) ->
+ Tests = generate_test_vectors(uri_combinations()),
+ lists:map(fun run_test_parse_recompose/1, Tests).
+
+transcode_basic(_Config) ->
+ <<"foo%C3%B6bar"/utf8>> =
+ uri_string:transcode(<<"foo%00%00%00%F6bar"/utf32>>, [{in_encoding, utf32},{out_encoding, utf8}]),
+ "foo%C3%B6bar" =
+ uri_string:transcode("foo%00%00%00%F6bar", [{in_encoding, utf32},{out_encoding, utf8}]),
+ <<"foo%00%00%00%F6bar"/utf32>> =
+ uri_string:transcode(<<"foo%C3%B6bar"/utf8>>, [{in_encoding, utf8},{out_encoding, utf32}]),
+ "foo%00%00%00%F6bar" =
+ uri_string:transcode("foo%C3%B6bar", [{in_encoding, utf8},{out_encoding, utf32}]),
+ "foo%C3%B6bar" =
+ uri_string:transcode("foo%F6bar", [{in_encoding, latin1},{out_encoding, utf8}]).
+
+transcode_options(_Config) ->
+ <<"foo%C3%B6bar"/utf8>> =
+ uri_string:transcode(<<"foo%C3%B6bar"/utf8>>, []),
+ <<"foo%C3%B6bar"/utf8>> =
+ uri_string:transcode(<<"foo%00%00%00%F6bar"/utf32>>, [{in_encoding, utf32}]),
+ <<"foo%00%00%00%F6bar"/utf32>> =
+ uri_string:transcode(<<"foo%C3%B6bar"/utf8>>, [{out_encoding, utf32}]).
+
+transcode_mixed(_Config) ->
+ "foo%00%00%00%F6bar" =
+ uri_string:transcode(["foo",<<"%C3%B6"/utf8>>,<<"ba"/utf8>>,"r"], [{out_encoding, utf32}]),
+ "foo%00%00%00%F6bar" =
+ uri_string:transcode(["foo",<<"%C3%"/utf8>>,<<"B6ba"/utf8>>,"r"], [{out_encoding, utf32}]),
+ "foo%C3%B6bar" =
+ uri_string:transcode(["foo%00", <<"%00%0"/utf32>>,<<"0%F"/utf32>>,"6bar"], [{in_encoding, utf32},{out_encoding, utf8}]).
+
+transcode_negative(_Config) ->
+ {error,invalid_percent_encoding,"%BXbar"} =
+ uri_string:transcode(<<"foo%C3%BXbar"/utf8>>, [{in_encoding, utf8},{out_encoding, utf32}]),
+ {error,invalid_input,<<"ö">>} =
+ uri_string:transcode("foo%F6bar", [{in_encoding, utf8},{out_encoding, utf8}]).
+
+compose_query(_Config) ->
+ [] = uri_string:compose_query([]),
+ "foo=1&bar=2" = uri_string:compose_query([{<<"foo">>,"1"}, {"bar", "2"}]),
+ "foo=1&bar" = uri_string:compose_query([{<<"foo">>,"1"}, {"bar", true}]),
+ "foo=1&b%C3%A4r=2" = uri_string:compose_query([{"foo","1"}, {"bär", "2"}],[{encoding,utf8}]),
+ "foo=1&b%C3%A4r=2" = uri_string:compose_query([{"foo","1"}, {"bär", "2"}],[{encoding,unicode}]),
+ "foo=1&b%E4r=2" = uri_string:compose_query([{"foo","1"}, {"bär", "2"}],[{encoding,latin1}]),
+ "foo&b%E4r=2" = uri_string:compose_query([{"foo",true}, {"bär", "2"}],[{encoding,latin1}]),
+ "foo+bar=1&%E5%90%88=2" = uri_string:compose_query([{"foo bar","1"}, {"合", "2"}]),
+ "foo+bar=1&%26%2321512%3B=2" =
+ uri_string:compose_query([{"foo bar","1"}, {"合", "2"}],[{encoding,latin1}]),
+ "foo+bar=1&%C3%B6=2" = uri_string:compose_query([{<<"foo bar">>,<<"1">>}, {"ö", <<"2">>}]),
+ <<"foo+bar=1&%C3%B6=2">> =
+ uri_string:compose_query([{<<"foo bar">>,<<"1">>}, {<<"ö"/utf8>>, <<"2">>}]).
+
+compose_query_latin1(_Config) ->
+ Q = uri_string:compose_query([{"合foö bar","1"}, {"合", "合"}],[{encoding,latin1}]),
+ Q1 = uri_string:transcode(Q, [{in_encoding, latin1}]),
+ [{"合foö bar","1"}, {"合", "合"}] = uri_string:dissect_query(Q1),
+ Q2 = uri_string:compose_query([{<<"合foö bar"/utf8>>,<<"1">>}, {<<"合"/utf8>>, <<"合"/utf8>>}],
+ [{encoding,latin1}]),
+ Q3 = uri_string:transcode(Q2, [{in_encoding, latin1}]),
+ [{<<"合foö bar"/utf8>>,<<"1">>}, {<<"合"/utf8>>, <<"合"/utf8>>}] =
+ uri_string:dissect_query(Q3).
+
+compose_query_negative(_Config) ->
+ {error,invalid_input,4} = uri_string:compose_query([{"",4}]),
+ {error,invalid_input,5} = uri_string:compose_query([{5,""}]),
+ {error,invalid_encoding,utf16} =
+ uri_string:compose_query([{"foo bar","1"}, {<<"ö">>, "2"}],[{encoding,utf16}]).
+
+dissect_query(_Config) ->
+ [] = uri_string:dissect_query(""),
+ [{"foo","1"}, {"amp;bar", "2"}] = uri_string:dissect_query("foo=1&amp;bar=2"),
+ [{"foo","1"}, {"bar", "2"}] = uri_string:dissect_query("foo=1&bar=2"),
+ [{"foo","1;bar=2"}] = uri_string:dissect_query("foo=1;bar=2"),
+ [{"foo","1"}, {"bar", "222"}] = uri_string:dissect_query([<<"foo=1&bar=2">>,"22"]),
+ [{"foo","ö"}, {"bar", "2"}] = uri_string:dissect_query("foo=%C3%B6&bar=2"),
+ [{<<"foo">>,<<"ö"/utf8>>}, {<<"bar">>, <<"2">>}] =
+ uri_string:dissect_query(<<"foo=%C3%B6&bar=2">>),
+ [{"foo bar","1"},{"ö","2"}] =
+ uri_string:dissect_query([<<"foo+bar=1&">>,<<"%C3%B6=2">>]),
+ [{"foo bar","1"},{[21512],"2"}] =
+ uri_string:dissect_query("foo+bar=1&%26%2321512%3B=2"),
+ [{<<"foo bar">>,<<"1">>},{<<"合"/utf8>>,<<"2">>}] =
+ uri_string:dissect_query(<<"foo+bar=1&%26%2321512%3B=2">>),
+ [{"föo bar","1"},{"ö","2"}] =
+ uri_string:dissect_query("föo+bar=1&%C3%B6=2"),
+ [{<<"föo bar"/utf8>>,<<"1">>},{<<"ö"/utf8>>,<<"2">>}] =
+ uri_string:dissect_query(<<"föo+bar=1&%C3%B6=2"/utf8>>),
+ [{"foo1",true},{"bar","2"}] =
+ uri_string:dissect_query("foo1&bar=2"),
+ [{<<"foo1">>,<<"1">>},{<<"bar">>,true}] =
+ uri_string:dissect_query(<<"foo1=1&bar">>).
+
+dissect_query_negative(_Config) ->
+ {error,invalid_percent_encoding,"%XX%B6"} = uri_string:dissect_query("foo=%XX%B6&amp;bar=2"),
+ {error,invalid_input,[153]} =
+ uri_string:dissect_query("foo=%99%B6&amp;bar=2"),
+ {error,invalid_character,"ö"} = uri_string:dissect_query(<<"föo+bar=1&%C3%B6=2">>),
+ {error,invalid_input,<<"ö">>} =
+ uri_string:dissect_query([<<"foo+bar=1&amp;">>,<<"%C3%B6=2ö">>]).
+
+normalize(_Config) ->
+ "/a/g" = uri_string:normalize("/a/b/c/./../../g"),
+ <<"mid/6">> = uri_string:normalize(<<"mid/content=5/../6">>),
+ "http://localhost-%C3%B6rebro/a/g" =
+ uri_string:normalize("http://localhos%74-%c3%b6rebro:80/a/b/c/./../../g"),
+ <<"http://localhost-%C3%B6rebro/a/g">> =
+ uri_string:normalize(<<"http://localhos%74-%c3%b6rebro:80/a/b/c/./../../g">>),
+ <<"https://localhost/">> =
+ uri_string:normalize(<<"https://localhost:443">>),
+ <<"https://localhost:445/">> =
+ uri_string:normalize(<<"https://localhost:445">>),
+ <<"ftp://localhost">> =
+ uri_string:normalize(<<"ftp://localhost:21">>),
+ <<"ssh://localhost">> =
+ uri_string:normalize(<<"ssh://localhost:22">>),
+ <<"sftp://localhost">> =
+ uri_string:normalize(<<"sftp://localhost:22">>),
+ <<"tftp://localhost">> =
+ uri_string:normalize(<<"tftp://localhost:69">>),
+ <<"/foo/%2F/bar">> =
+ uri_string:normalize(<<"/foo/%2f/%62ar">>).
+
+normalize_map(_Config) ->
+ "/a/g" = uri_string:normalize(#{path => "/a/b/c/./../../g"}),
+ <<"mid/6">> = uri_string:normalize(#{path => <<"mid/content=5/../6">>}),
+ "http://localhost-%C3%B6rebro/a/g" =
+ uri_string:normalize(#{scheme => "http",port => 80,path => "/a/b/c/./../../g",
+ host => "localhost-örebro"}),
+ <<"http://localhost-%C3%B6rebro/a/g">> =
+ uri_string:normalize(#{scheme => <<"http">>,port => 80,
+ path => <<"/a/b/c/./../../g">>,
+ host => <<"localhost-örebro"/utf8>>}),
+ <<"https://localhost/">> =
+ uri_string:normalize(#{scheme => <<"https">>,port => 443,path => <<>>,
+ host => <<"localhost">>}),
+ <<"https://localhost:445/">> =
+ uri_string:normalize(#{scheme => <<"https">>,port => 445,path => <<>>,
+ host => <<"localhost">>}),
+ <<"ftp://localhost">> =
+ uri_string:normalize(#{scheme => <<"ftp">>,port => 21,path => <<>>,
+ host => <<"localhost">>}),
+ <<"ssh://localhost">> =
+ uri_string:normalize(#{scheme => <<"ssh">>,port => 22,path => <<>>,
+ host => <<"localhost">>}),
+ <<"sftp://localhost">> =
+ uri_string:normalize(#{scheme => <<"sftp">>,port => 22,path => <<>>,
+ host => <<"localhost">>}),
+ <<"tftp://localhost">> =
+ uri_string:normalize(#{scheme => <<"tftp">>,port => 69,path => <<>>,
+ host => <<"localhost">>}),
+ "/foo/%2F/bar" =
+ uri_string:normalize(#{path => "/foo/%2f/%62ar"}).
+
+normalize_return_map(_Config) ->
+ #{scheme := "http",path := "/a/g",host := "localhost-örebro"} =
+ uri_string:normalize("http://localhos%74-%c3%b6rebro:80/a/b/c/./../../g",
+ [return_map]),
+ #{scheme := <<"http">>,path := <<"/a/g">>, host := <<"localhost-örebro"/utf8>>} =
+ uri_string:normalize(<<"http://localhos%74-%c3%b6rebro:80/a/b/c/./../../g">>,
+ [return_map]),
+ #{scheme := <<"https">>,path := <<"/">>, host := <<"localhost">>} =
+ uri_string:normalize(#{scheme => <<"https">>,port => 443,path => <<>>,
+ host => <<"localhost">>}, [return_map]).
+
+normalize_negative(_Config) ->
+ {error,invalid_uri,":"} =
+ uri_string:normalize("http://local>host"),
+ {error,invalid_uri,":"} =
+ uri_string:normalize(<<"http://local>host">>),
+ {error,invalid_uri,":"} =
+ uri_string:normalize("http://[192.168.0.1]", [return_map]),
+ {error,invalid_uri,":"} =
+ uri_string:normalize(<<"http://[192.168.0.1]">>, [return_map]),
+ {error,invalid_utf8,<<0,0,0,246>>} = uri_string:normalize("//%00%00%00%F6").
+
+normalize_binary_pct_encoded_userinfo(_Config) ->
+ #{scheme := <<"user">>, path := <<"合@気道"/utf8>>} =
+ uri_string:normalize(<<"user:%E5%90%88@%E6%B0%97%E9%81%93">>, [return_map]),
+ #{path := <<"合気道@"/utf8>>} =
+ uri_string:normalize(<<"%E5%90%88%E6%B0%97%E9%81%93@">>, [return_map]),
+ #{path := <<"/合気道@"/utf8>>} =
+ uri_string:normalize(<<"/%E5%90%88%E6%B0%97%E9%81%93@">>, [return_map]),
+ #{path := <<"合@気道"/utf8>>} =
+ uri_string:normalize(<<"%E5%90%88@%E6%B0%97%E9%81%93">>, [return_map]),
+ #{userinfo := <<"合"/utf8>>, host := <<"気道"/utf8>>} =
+ uri_string:normalize(<<"//%E5%90%88@%E6%B0%97%E9%81%93">>, [return_map]),
+ #{userinfo := <<"合:気"/utf8>>, host := <<"道"/utf8>>} =
+ uri_string:normalize(<<"//%E5%90%88:%E6%B0%97@%E9%81%93">>, [return_map]),
+ #{scheme := <<"foo">>, path := <<"/合気道@"/utf8>>} =
+ uri_string:normalize(<<"foo:/%E5%90%88%E6%B0%97%E9%81%93@">>, [return_map]),
+ #{scheme := <<"foo">>, userinfo := <<"合"/utf8>>, host := <<"気道"/utf8>>} =
+ uri_string:normalize(<<"foo://%E5%90%88@%E6%B0%97%E9%81%93">>, [return_map]),
+ #{scheme := <<"foo">>, userinfo := <<"合:気"/utf8>>, host := <<"道"/utf8>>} =
+ uri_string:normalize(<<"foo://%E5%90%88:%E6%B0%97@%E9%81%93">>, [return_map]),
+ {error,invalid_uri,"@"} =
+ uri_string:normalize(<<"//%E5%90%88@%E6%B0%97%E9%81%93@">>, [return_map]),
+ {error,invalid_uri,":"} =
+ uri_string:normalize(<<"foo://%E5%90%88@%E6%B0%97%E9%81%93@">>, [return_map]).
+
+normalize_binary_pct_encoded_query(_Config) ->
+ #{scheme := <<"foo">>, host := <<"example.com">>, path := <<"/">>,
+ query := <<"name=合気道"/utf8>>} =
+ uri_string:normalize(<<"foo://example.com/?name=%E5%90%88%E6%B0%97%E9%81%93">>, [return_map]),
+ #{host := <<"example.com">>, path := <<"/">>, query := <<"name=合気道"/utf8>>} =
+ uri_string:normalize(<<"//example.com/?name=%E5%90%88%E6%B0%97%E9%81%93">>, [return_map]).
+
+normalize_binary_pct_encoded_fragment(_Config) ->
+ #{scheme := <<"foo">>, host := <<"example.com">>, fragment := <<"合気道"/utf8>>} =
+ uri_string:normalize(<<"foo://example.com#%E5%90%88%E6%B0%97%E9%81%93">>, [return_map]),
+ #{host := <<"example.com">>, path := <<"/">>, fragment := <<"合気道"/utf8>>} =
+ uri_string:normalize(<<"//example.com/#%E5%90%88%E6%B0%97%E9%81%93">>, [return_map]).
+
+normalize_pct_encoded_userinfo(_Config) ->
+ #{scheme := "user", path := "合@気道"} =
+ uri_string:normalize("user:%E5%90%88@%E6%B0%97%E9%81%93", [return_map]),
+ #{path := "合気道@"} =
+ uri_string:normalize("%E5%90%88%E6%B0%97%E9%81%93@", [return_map]),
+ #{path := "/合気道@"} =
+ uri_string:normalize("/%E5%90%88%E6%B0%97%E9%81%93@", [return_map]),
+ #{path := "合@気道"} =
+ uri_string:normalize("%E5%90%88@%E6%B0%97%E9%81%93", [return_map]),
+ #{userinfo := "合", host := "気道"} =
+ uri_string:normalize("//%E5%90%88@%E6%B0%97%E9%81%93", [return_map]),
+ #{userinfo := "合:気", host := "道"} =
+ uri_string:normalize("//%E5%90%88:%E6%B0%97@%E9%81%93", [return_map]),
+ #{scheme := "foo", path := "/合気道@"} =
+ uri_string:normalize("foo:/%E5%90%88%E6%B0%97%E9%81%93@", [return_map]),
+ #{scheme := "foo", userinfo := "合", host := "気道"} =
+ uri_string:normalize("foo://%E5%90%88@%E6%B0%97%E9%81%93", [return_map]),
+ #{scheme := "foo", userinfo := "合:気", host := "道"} =
+ uri_string:normalize("foo://%E5%90%88:%E6%B0%97@%E9%81%93", [return_map]),
+ {error,invalid_uri,"@"} =
+ uri_string:normalize("//%E5%90%88@%E6%B0%97%E9%81%93@", [return_map]),
+ {error,invalid_uri,":"} =
+ uri_string:normalize("foo://%E5%90%88@%E6%B0%97%E9%81%93@", [return_map]).
+
+normalize_pct_encoded_query(_Config) ->
+ #{scheme := "foo", host := "example.com", path := "/",
+ query := "name=合気道"} =
+ uri_string:normalize("foo://example.com/?name=%E5%90%88%E6%B0%97%E9%81%93", [return_map]),
+ #{host := "example.com", path := "/", query := "name=合気道"} =
+ uri_string:normalize("//example.com/?name=%E5%90%88%E6%B0%97%E9%81%93", [return_map]).
+
+normalize_pct_encoded_fragment(_Config) ->
+ #{scheme := "foo", host := "example.com", fragment := "合気道"} =
+ uri_string:normalize("foo://example.com#%E5%90%88%E6%B0%97%E9%81%93", [return_map]),
+ #{host := "example.com", path := "/", fragment := "合気道"} =
+ uri_string:normalize("//example.com/#%E5%90%88%E6%B0%97%E9%81%93", [return_map]).
+
+interop_query_utf8(_Config) ->
+ Q = uri_string:compose_query([{"foo bar","1"}, {"合", "2"}]),
+ Uri = uri_string:recompose(#{path => "/", query => Q}),
+ #{query := Q1} = uri_string:parse(Uri),
+ [{"foo bar","1"}, {"合", "2"}] = uri_string:dissect_query(Q1).
+
+interop_query_latin1(_Config) ->
+ Q = uri_string:compose_query([{"foo bar","1"}, {"合", "2"}], [{encoding,latin1}]),
+ Uri = uri_string:recompose(#{path => "/", query => Q}),
+ Uri1 = uri_string:transcode(Uri, [{in_encoding, latin1}]),
+ #{query := Q1} = uri_string:parse(Uri1),
+ [{"foo bar","1"}, {"合", "2"}] = uri_string:dissect_query(Q1).
+
+regression_parse(_Config) ->
+ #{host := "Bar",path := [],scheme := "FOo"} =
+ uri_string:parse("FOo://Bar"),
+ #{host := "bar",path := [],scheme := "foo"} =
+ uri_string:parse("foo://bar"),
+ #{host := "A%2f",path := "/%62ar",scheme := "foo"} =
+ uri_string:parse("foo://A%2f/%62ar"),
+ #{host := "a%2F",path := "/bar",scheme := "foo"} =
+ uri_string:parse("foo://a%2F/bar"),
+ #{host := "%C3%B6",path := [],scheme := "FOo"} =
+ uri_string:parse("FOo://%C3%B6").
+
+regression_recompose(_Config) ->
+ "FOo://Bar" =
+ uri_string:recompose(#{host => "Bar",path => [],scheme => "FOo"}),
+ "foo://bar" =
+ uri_string:recompose(#{host => "bar",path => [],scheme => "foo"}),
+ "foo://A%2f/%62ar" =
+ uri_string:recompose(#{host => "A%2f",path => "/%62ar",scheme => "foo"}),
+ "foo://a%2F/bar" =
+ uri_string:recompose(#{host => "a%2F",path => "/bar",scheme => "foo"}),
+ "FOo://%C3%B6" =
+ uri_string:recompose(#{host => "%C3%B6",path => [],scheme => "FOo"}),
+ "FOo://%C3%B6" =
+ uri_string:recompose(#{host => "ö",path => [],scheme => "FOo"}).
+
+regression_normalize(_Config) ->
+ "foo://bar" =
+ uri_string:normalize("FOo://Bar"),
+ #{host := "bar",path := [],scheme := "foo"} =
+ uri_string:normalize("FOo://Bar", [return_map]),
+
+ "foo://bar" =
+ uri_string:normalize("foo://bar"),
+ #{host := "bar",path := [],scheme := "foo"} =
+ uri_string:normalize("foo://bar", [return_map]),
+
+ "foo://a%2F/bar" =
+ uri_string:normalize("foo://A%2f/%62ar"),
+ #{host := "a%2F",path := "/bar",scheme := "foo"} =
+ uri_string:normalize("foo://A%2f/%62ar", [return_map]),
+
+ "foo://a%2F/bar" =
+ uri_string:normalize("foo://a%2F/bar"),
+ #{host := "a%2F",path := "/bar",scheme := "foo"} =
+ uri_string:normalize("foo://a%2F/bar", [return_map]),
+
+ "foo://%C3%B6" =
+ uri_string:normalize("FOo://%C3%B6"),
+ #{host := "ö",path := [],scheme := "foo"} =
+ uri_string:normalize("FOo://%C3%B6", [return_map]),
+
+
+ "foo://bar" =
+ uri_string:normalize(#{host => "Bar",path => [],scheme => "FOo"}),
+ #{host := "bar",path := [],scheme := "foo"} =
+ uri_string:normalize(#{host => "Bar",path => [],scheme => "FOo"}, [return_map]),
+
+ "foo://bar" =
+ uri_string:normalize(#{host => "bar",path => [],scheme => "foo"}),
+ #{host := "bar",path := [],scheme := "foo"} =
+ uri_string:normalize(#{host => "bar",path => [],scheme => "foo"}, [return_map]),
+
+ "foo://a%2F/bar" =
+ uri_string:normalize(#{host => "A%2f",path => "/%62ar",scheme => "foo"}),
+ #{host := "a%2F",path := "/bar",scheme := "foo"} =
+ uri_string:normalize(#{host => "A%2f",path => "/%62ar",scheme => "foo"}, [return_map]),
+
+ "foo://a%2F/bar" =
+ uri_string:normalize(#{host => "a%2F",path => "/bar",scheme => "foo"}),
+ #{host := "a%2F",path := "/bar",scheme := "foo"} =
+ uri_string:normalize(#{host => "a%2F",path => "/bar",scheme => "foo"}, [return_map]),
+
+ "foo://%C3%B6" =
+ uri_string:normalize(#{host => "%C3%B6",path => [],scheme => "FOo"}),
+ #{host := "ö",path := [],scheme := "foo"} =
+ uri_string:normalize(#{host => "%C3%B6",path => [],scheme => "FOo"}, [return_map]),
+
+ "foo://%C3%B6" =
+ uri_string:normalize(#{host => "ö",path => [],scheme => "FOo"}),
+ #{host := "ö",path := [],scheme := "foo"} =
+ uri_string:normalize(#{host => "ö",path => [],scheme => "FOo"}, [return_map]).
diff --git a/lib/stdlib/test/uri_string_property_test_SUITE.erl b/lib/stdlib/test/uri_string_property_test_SUITE.erl
new file mode 100644
index 0000000000..f1d27924db
--- /dev/null
+++ b/lib/stdlib/test/uri_string_property_test_SUITE.erl
@@ -0,0 +1,44 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(uri_string_property_test_SUITE).
+
+-include_lib("common_test/include/ct.hrl").
+-compile(export_all).
+
+all() -> [recompose, normalize].
+
+init_per_suite(Config) ->
+ ct_property_test:init_per_suite(Config).
+
+end_per_suite(Config) ->
+ Config.
+
+%%%========================================================================
+%%% Test suites
+%%%========================================================================
+recompose(Config) ->
+ ct_property_test:quickcheck(
+ uri_string_recompose:prop_recompose(),
+ Config).
+
+normalize(Config) ->
+ ct_property_test:quickcheck(
+ uri_string_recompose:prop_normalize(),
+ Config).
diff --git a/lib/stdlib/test/zip_SUITE.erl b/lib/stdlib/test/zip_SUITE.erl
index 1dfcda4ed0..081bffa7cb 100644
--- a/lib/stdlib/test/zip_SUITE.erl
+++ b/lib/stdlib/test/zip_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -909,8 +909,7 @@ do_fd_leak(Bad, N) ->
ok ->
do_fd_leak(Bad, N + 1)
catch
- C:R ->
- Stk = erlang:get_stacktrace(),
+ C:R:Stk ->
io:format("Bad error after ~p attempts\n", [N]),
erlang:raise(C, R, Stk)
end.
diff --git a/lib/stdlib/test/zzz_SUITE.erl b/lib/stdlib/test/zzz_SUITE.erl
new file mode 100644
index 0000000000..59c7fd7404
--- /dev/null
+++ b/lib/stdlib/test/zzz_SUITE.erl
@@ -0,0 +1,37 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(zzz_SUITE).
+
+%% The sole purpose of this test suite is for things we want to run last
+%% before the VM terminates.
+
+-export([all/0]).
+
+-export([lc_graph/1]).
+
+
+all() ->
+ [lc_graph].
+
+lc_graph(_Config) ->
+ %% Create "lc_graph" file in current working dir
+ %% if lock checker is enabled.
+ erts_debug:lc_graph(),
+ ok.
diff --git a/lib/stdlib/uc_spec/CaseFolding.txt b/lib/stdlib/uc_spec/CaseFolding.txt
index 372ee68bd8..cce350f49c 100644
--- a/lib/stdlib/uc_spec/CaseFolding.txt
+++ b/lib/stdlib/uc_spec/CaseFolding.txt
@@ -1,6 +1,6 @@
-# CaseFolding-9.0.0.txt
-# Date: 2016-03-02, 18:54:54 GMT
-# © 2016 Unicode®, Inc.
+# CaseFolding-11.0.0.txt
+# Date: 2018-01-31, 08:20:09 GMT
+# © 2018 Unicode®, Inc.
# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
# For terms of use, see http://www.unicode.org/terms_of_use.html
#
@@ -24,7 +24,7 @@
#
# NOTE: case folding does not preserve normalization formats!
#
-# For information on case folding, including how to have case folding
+# For information on case folding, including how to have case folding
# preserve normalization formats, see Section 3.13 Default Case Algorithms in
# The Unicode Standard.
#
@@ -603,6 +603,52 @@
1C86; C; 044A; # CYRILLIC SMALL LETTER TALL HARD SIGN
1C87; C; 0463; # CYRILLIC SMALL LETTER TALL YAT
1C88; C; A64B; # CYRILLIC SMALL LETTER UNBLENDED UK
+1C90; C; 10D0; # GEORGIAN MTAVRULI CAPITAL LETTER AN
+1C91; C; 10D1; # GEORGIAN MTAVRULI CAPITAL LETTER BAN
+1C92; C; 10D2; # GEORGIAN MTAVRULI CAPITAL LETTER GAN
+1C93; C; 10D3; # GEORGIAN MTAVRULI CAPITAL LETTER DON
+1C94; C; 10D4; # GEORGIAN MTAVRULI CAPITAL LETTER EN
+1C95; C; 10D5; # GEORGIAN MTAVRULI CAPITAL LETTER VIN
+1C96; C; 10D6; # GEORGIAN MTAVRULI CAPITAL LETTER ZEN
+1C97; C; 10D7; # GEORGIAN MTAVRULI CAPITAL LETTER TAN
+1C98; C; 10D8; # GEORGIAN MTAVRULI CAPITAL LETTER IN
+1C99; C; 10D9; # GEORGIAN MTAVRULI CAPITAL LETTER KAN
+1C9A; C; 10DA; # GEORGIAN MTAVRULI CAPITAL LETTER LAS
+1C9B; C; 10DB; # GEORGIAN MTAVRULI CAPITAL LETTER MAN
+1C9C; C; 10DC; # GEORGIAN MTAVRULI CAPITAL LETTER NAR
+1C9D; C; 10DD; # GEORGIAN MTAVRULI CAPITAL LETTER ON
+1C9E; C; 10DE; # GEORGIAN MTAVRULI CAPITAL LETTER PAR
+1C9F; C; 10DF; # GEORGIAN MTAVRULI CAPITAL LETTER ZHAR
+1CA0; C; 10E0; # GEORGIAN MTAVRULI CAPITAL LETTER RAE
+1CA1; C; 10E1; # GEORGIAN MTAVRULI CAPITAL LETTER SAN
+1CA2; C; 10E2; # GEORGIAN MTAVRULI CAPITAL LETTER TAR
+1CA3; C; 10E3; # GEORGIAN MTAVRULI CAPITAL LETTER UN
+1CA4; C; 10E4; # GEORGIAN MTAVRULI CAPITAL LETTER PHAR
+1CA5; C; 10E5; # GEORGIAN MTAVRULI CAPITAL LETTER KHAR
+1CA6; C; 10E6; # GEORGIAN MTAVRULI CAPITAL LETTER GHAN
+1CA7; C; 10E7; # GEORGIAN MTAVRULI CAPITAL LETTER QAR
+1CA8; C; 10E8; # GEORGIAN MTAVRULI CAPITAL LETTER SHIN
+1CA9; C; 10E9; # GEORGIAN MTAVRULI CAPITAL LETTER CHIN
+1CAA; C; 10EA; # GEORGIAN MTAVRULI CAPITAL LETTER CAN
+1CAB; C; 10EB; # GEORGIAN MTAVRULI CAPITAL LETTER JIL
+1CAC; C; 10EC; # GEORGIAN MTAVRULI CAPITAL LETTER CIL
+1CAD; C; 10ED; # GEORGIAN MTAVRULI CAPITAL LETTER CHAR
+1CAE; C; 10EE; # GEORGIAN MTAVRULI CAPITAL LETTER XAN
+1CAF; C; 10EF; # GEORGIAN MTAVRULI CAPITAL LETTER JHAN
+1CB0; C; 10F0; # GEORGIAN MTAVRULI CAPITAL LETTER HAE
+1CB1; C; 10F1; # GEORGIAN MTAVRULI CAPITAL LETTER HE
+1CB2; C; 10F2; # GEORGIAN MTAVRULI CAPITAL LETTER HIE
+1CB3; C; 10F3; # GEORGIAN MTAVRULI CAPITAL LETTER WE
+1CB4; C; 10F4; # GEORGIAN MTAVRULI CAPITAL LETTER HAR
+1CB5; C; 10F5; # GEORGIAN MTAVRULI CAPITAL LETTER HOE
+1CB6; C; 10F6; # GEORGIAN MTAVRULI CAPITAL LETTER FI
+1CB7; C; 10F7; # GEORGIAN MTAVRULI CAPITAL LETTER YN
+1CB8; C; 10F8; # GEORGIAN MTAVRULI CAPITAL LETTER ELIFI
+1CB9; C; 10F9; # GEORGIAN MTAVRULI CAPITAL LETTER TURNED GAN
+1CBA; C; 10FA; # GEORGIAN MTAVRULI CAPITAL LETTER AIN
+1CBD; C; 10FD; # GEORGIAN MTAVRULI CAPITAL LETTER AEN
+1CBE; C; 10FE; # GEORGIAN MTAVRULI CAPITAL LETTER HARD SIGN
+1CBF; C; 10FF; # GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN
1E00; C; 1E01; # LATIN CAPITAL LETTER A WITH RING BELOW
1E02; C; 1E03; # LATIN CAPITAL LETTER B WITH DOT ABOVE
1E04; C; 1E05; # LATIN CAPITAL LETTER B WITH DOT BELOW
@@ -1180,6 +1226,7 @@ A7B2; C; 029D; # LATIN CAPITAL LETTER J WITH CROSSED-TAIL
A7B3; C; AB53; # LATIN CAPITAL LETTER CHI
A7B4; C; A7B5; # LATIN CAPITAL LETTER BETA
A7B6; C; A7B7; # LATIN CAPITAL LETTER OMEGA
+A7B8; C; A7B9; # LATIN CAPITAL LETTER U WITH STROKE
AB70; C; 13A0; # CHEROKEE SMALL LETTER A
AB71; C; 13A1; # CHEROKEE SMALL LETTER E
AB72; C; 13A2; # CHEROKEE SMALL LETTER I
@@ -1457,6 +1504,38 @@ FF3A; C; FF5A; # FULLWIDTH LATIN CAPITAL LETTER Z
118BD; C; 118DD; # WARANG CITI CAPITAL LETTER SSUU
118BE; C; 118DE; # WARANG CITI CAPITAL LETTER SII
118BF; C; 118DF; # WARANG CITI CAPITAL LETTER VIYO
+16E40; C; 16E60; # MEDEFAIDRIN CAPITAL LETTER M
+16E41; C; 16E61; # MEDEFAIDRIN CAPITAL LETTER S
+16E42; C; 16E62; # MEDEFAIDRIN CAPITAL LETTER V
+16E43; C; 16E63; # MEDEFAIDRIN CAPITAL LETTER W
+16E44; C; 16E64; # MEDEFAIDRIN CAPITAL LETTER ATIU
+16E45; C; 16E65; # MEDEFAIDRIN CAPITAL LETTER Z
+16E46; C; 16E66; # MEDEFAIDRIN CAPITAL LETTER KP
+16E47; C; 16E67; # MEDEFAIDRIN CAPITAL LETTER P
+16E48; C; 16E68; # MEDEFAIDRIN CAPITAL LETTER T
+16E49; C; 16E69; # MEDEFAIDRIN CAPITAL LETTER G
+16E4A; C; 16E6A; # MEDEFAIDRIN CAPITAL LETTER F
+16E4B; C; 16E6B; # MEDEFAIDRIN CAPITAL LETTER I
+16E4C; C; 16E6C; # MEDEFAIDRIN CAPITAL LETTER K
+16E4D; C; 16E6D; # MEDEFAIDRIN CAPITAL LETTER A
+16E4E; C; 16E6E; # MEDEFAIDRIN CAPITAL LETTER J
+16E4F; C; 16E6F; # MEDEFAIDRIN CAPITAL LETTER E
+16E50; C; 16E70; # MEDEFAIDRIN CAPITAL LETTER B
+16E51; C; 16E71; # MEDEFAIDRIN CAPITAL LETTER C
+16E52; C; 16E72; # MEDEFAIDRIN CAPITAL LETTER U
+16E53; C; 16E73; # MEDEFAIDRIN CAPITAL LETTER YU
+16E54; C; 16E74; # MEDEFAIDRIN CAPITAL LETTER L
+16E55; C; 16E75; # MEDEFAIDRIN CAPITAL LETTER Q
+16E56; C; 16E76; # MEDEFAIDRIN CAPITAL LETTER HP
+16E57; C; 16E77; # MEDEFAIDRIN CAPITAL LETTER NY
+16E58; C; 16E78; # MEDEFAIDRIN CAPITAL LETTER X
+16E59; C; 16E79; # MEDEFAIDRIN CAPITAL LETTER D
+16E5A; C; 16E7A; # MEDEFAIDRIN CAPITAL LETTER OE
+16E5B; C; 16E7B; # MEDEFAIDRIN CAPITAL LETTER N
+16E5C; C; 16E7C; # MEDEFAIDRIN CAPITAL LETTER R
+16E5D; C; 16E7D; # MEDEFAIDRIN CAPITAL LETTER O
+16E5E; C; 16E7E; # MEDEFAIDRIN CAPITAL LETTER AI
+16E5F; C; 16E7F; # MEDEFAIDRIN CAPITAL LETTER Y
1E900; C; 1E922; # ADLAM CAPITAL LETTER ALIF
1E901; C; 1E923; # ADLAM CAPITAL LETTER DAALI
1E902; C; 1E924; # ADLAM CAPITAL LETTER LAAM
diff --git a/lib/stdlib/uc_spec/CompositionExclusions.txt b/lib/stdlib/uc_spec/CompositionExclusions.txt
index 1999ed1328..ea63595bd3 100644
--- a/lib/stdlib/uc_spec/CompositionExclusions.txt
+++ b/lib/stdlib/uc_spec/CompositionExclusions.txt
@@ -1,6 +1,6 @@
-# CompositionExclusions-9.0.0.txt
-# Date: 2016-01-21, 22:00:00 GMT [KW, LI]
-# © 2016 Unicode®, Inc.
+# CompositionExclusions-11.0.0.txt
+# Date: 2017-12-06, 00:00:00 GMT [KW, LI]
+# © 2017 Unicode®, Inc.
# For terms of use, see http://www.unicode.org/terms_of_use.html
#
# Unicode Character Database
diff --git a/lib/stdlib/uc_spec/GraphemeBreakProperty.txt b/lib/stdlib/uc_spec/GraphemeBreakProperty.txt
index c5e94a3762..52052e6e33 100644
--- a/lib/stdlib/uc_spec/GraphemeBreakProperty.txt
+++ b/lib/stdlib/uc_spec/GraphemeBreakProperty.txt
@@ -1,6 +1,6 @@
-# GraphemeBreakProperty-9.0.0.txt
-# Date: 2016-06-03, 22:23:55 GMT
-# © 2016 Unicode®, Inc.
+# GraphemeBreakProperty-11.0.0.txt
+# Date: 2018-03-16, 20:34:02 GMT
+# © 2018 Unicode®, Inc.
# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
# For terms of use, see http://www.unicode.org/terms_of_use.html
#
@@ -24,9 +24,13 @@
08E2 ; Prepend # Cf ARABIC DISPUTED END OF AYAH
0D4E ; Prepend # Lo MALAYALAM LETTER DOT REPH
110BD ; Prepend # Cf KAITHI NUMBER SIGN
+110CD ; Prepend # Cf KAITHI NUMBER SIGN ABOVE
111C2..111C3 ; Prepend # Lo [2] SHARADA SIGN JIHVAMULIYA..SHARADA SIGN UPADHMANIYA
+11A3A ; Prepend # Lo ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA
+11A86..11A89 ; Prepend # Lo [4] SOYOMBO CLUSTER-INITIAL LETTER RA..SOYOMBO CLUSTER-INITIAL LETTER SA
+11D46 ; Prepend # Lo MASARAM GONDI REPHA
-# Total code points: 13
+# Total code points: 20
# ================================================
@@ -92,12 +96,13 @@ E01F0..E0FFF ; Control # Cn [3600] <reserved-E01F0>..<reserved-E0FFF>
0730..074A ; Extend # Mn [27] SYRIAC PTHAHA ABOVE..SYRIAC BARREKH
07A6..07B0 ; Extend # Mn [11] THAANA ABAFILI..THAANA SUKUN
07EB..07F3 ; Extend # Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE
+07FD ; Extend # Mn NKO DANTAYALAN
0816..0819 ; Extend # Mn [4] SAMARITAN MARK IN..SAMARITAN MARK DAGESH
081B..0823 ; Extend # Mn [9] SAMARITAN MARK EPENTHETIC YUT..SAMARITAN VOWEL SIGN A
0825..0827 ; Extend # Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U
0829..082D ; Extend # Mn [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA
0859..085B ; Extend # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK
-08D4..08E1 ; Extend # Mn [14] ARABIC SMALL HIGH WORD AR-RUB..ARABIC SMALL HIGH SIGN SAFHA
+08D3..08E1 ; Extend # Mn [15] ARABIC SMALL LOW WAW..ARABIC SMALL HIGH SIGN SAFHA
08E3..0902 ; Extend # Mn [32] ARABIC TURNED DAMMA BELOW..DEVANAGARI SIGN ANUSVARA
093A ; Extend # Mn DEVANAGARI VOWEL SIGN OE
093C ; Extend # Mn DEVANAGARI SIGN NUKTA
@@ -112,6 +117,7 @@ E01F0..E0FFF ; Control # Cn [3600] <reserved-E01F0>..<reserved-E0FFF>
09CD ; Extend # Mn BENGALI SIGN VIRAMA
09D7 ; Extend # Mc BENGALI AU LENGTH MARK
09E2..09E3 ; Extend # Mn [2] BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL
+09FE ; Extend # Mn BENGALI SANDHI MARK
0A01..0A02 ; Extend # Mn [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI
0A3C ; Extend # Mn GURMUKHI SIGN NUKTA
0A41..0A42 ; Extend # Mn [2] GURMUKHI VOWEL SIGN U..GURMUKHI VOWEL SIGN UU
@@ -126,6 +132,7 @@ E01F0..E0FFF ; Control # Cn [3600] <reserved-E01F0>..<reserved-E0FFF>
0AC7..0AC8 ; Extend # Mn [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI
0ACD ; Extend # Mn GUJARATI SIGN VIRAMA
0AE2..0AE3 ; Extend # Mn [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL
+0AFA..0AFF ; Extend # Mn [6] GUJARATI SIGN SUKUN..GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE
0B01 ; Extend # Mn ORIYA SIGN CANDRABINDU
0B3C ; Extend # Mn ORIYA SIGN NUKTA
0B3E ; Extend # Mc ORIYA VOWEL SIGN AA
@@ -141,6 +148,7 @@ E01F0..E0FFF ; Control # Cn [3600] <reserved-E01F0>..<reserved-E0FFF>
0BCD ; Extend # Mn TAMIL SIGN VIRAMA
0BD7 ; Extend # Mc TAMIL AU LENGTH MARK
0C00 ; Extend # Mn TELUGU SIGN COMBINING CANDRABINDU ABOVE
+0C04 ; Extend # Mn TELUGU SIGN COMBINING ANUSVARA ABOVE
0C3E..0C40 ; Extend # Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II
0C46..0C48 ; Extend # Mn [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI
0C4A..0C4D ; Extend # Mn [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA
@@ -154,7 +162,8 @@ E01F0..E0FFF ; Control # Cn [3600] <reserved-E01F0>..<reserved-E0FFF>
0CCC..0CCD ; Extend # Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA
0CD5..0CD6 ; Extend # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK
0CE2..0CE3 ; Extend # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL
-0D01 ; Extend # Mn MALAYALAM SIGN CANDRABINDU
+0D00..0D01 ; Extend # Mn [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU
+0D3B..0D3C ; Extend # Mn [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA
0D3E ; Extend # Mc MALAYALAM VOWEL SIGN AA
0D41..0D44 ; Extend # Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR
0D4D ; Extend # Mn MALAYALAM SIGN VIRAMA
@@ -243,7 +252,7 @@ E01F0..E0FFF ; Control # Cn [3600] <reserved-E01F0>..<reserved-E0FFF>
1CED ; Extend # Mn VEDIC SIGN TIRYAK
1CF4 ; Extend # Mn VEDIC TONE CANDRA ABOVE
1CF8..1CF9 ; Extend # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE
-1DC0..1DF5 ; Extend # Mn [54] COMBINING DOTTED GRAVE ACCENT..COMBINING UP TACK ABOVE
+1DC0..1DF9 ; Extend # Mn [58] COMBINING DOTTED GRAVE ACCENT..COMBINING WIDE INVERTED BRIDGE BELOW
1DFB..1DFF ; Extend # Mn [5] COMBINING DELETION MARK..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW
200C ; Extend # Cf ZERO WIDTH NON-JOINER
20D0..20DC ; Extend # Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE
@@ -268,6 +277,7 @@ A80B ; Extend # Mn SYLOTI NAGRI SIGN ANUSVARA
A825..A826 ; Extend # Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E
A8C4..A8C5 ; Extend # Mn [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA SIGN CANDRABINDU
A8E0..A8F1 ; Extend # Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA
+A8FF ; Extend # Mn DEVANAGARI VOWEL SIGN AY
A926..A92D ; Extend # Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU
A947..A951 ; Extend # Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R
A980..A982 ; Extend # Mn [3] JAVANESE SIGN PANYANGGA..JAVANESE SIGN LAYAR
@@ -304,6 +314,8 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT
10A38..10A3A ; Extend # Mn [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW
10A3F ; Extend # Mn KHAROSHTHI VIRAMA
10AE5..10AE6 ; Extend # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW
+10D24..10D27 ; Extend # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI
+10F46..10F50 ; Extend # Mn [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW
11001 ; Extend # Mn BRAHMI SIGN ANUSVARA
11038..11046 ; Extend # Mn [15] BRAHMI VOWEL SIGN AA..BRAHMI VIRAMA
1107F..11081 ; Extend # Mn [3] BRAHMI NUMBER JOINER..KAITHI SIGN ANUSVARA
@@ -315,7 +327,7 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT
11173 ; Extend # Mn MAHAJANI SIGN NUKTA
11180..11181 ; Extend # Mn [2] SHARADA SIGN CANDRABINDU..SHARADA SIGN ANUSVARA
111B6..111BE ; Extend # Mn [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O
-111CA..111CC ; Extend # Mn [3] SHARADA SIGN NUKTA..SHARADA EXTRA SHORT VOWEL MARK
+111C9..111CC ; Extend # Mn [4] SHARADA SANDHI MARK..SHARADA EXTRA SHORT VOWEL MARK
1122F..11231 ; Extend # Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI
11234 ; Extend # Mn KHOJKI SIGN ANUSVARA
11236..11237 ; Extend # Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA
@@ -323,7 +335,7 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT
112DF ; Extend # Mn KHUDAWADI SIGN ANUSVARA
112E3..112EA ; Extend # Mn [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA
11300..11301 ; Extend # Mn [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU
-1133C ; Extend # Mn GRANTHA SIGN NUKTA
+1133B..1133C ; Extend # Mn [2] COMBINING BINDU BELOW..GRANTHA SIGN NUKTA
1133E ; Extend # Mc GRANTHA VOWEL SIGN AA
11340 ; Extend # Mn GRANTHA VOWEL SIGN II
11357 ; Extend # Mc GRANTHA AU LENGTH MARK
@@ -332,6 +344,7 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT
11438..1143F ; Extend # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI
11442..11444 ; Extend # Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA
11446 ; Extend # Mn NEWA SIGN NUKTA
+1145E ; Extend # Mn NEWA SANDHI MARK
114B0 ; Extend # Mc TIRHUTA VOWEL SIGN AA
114B3..114B8 ; Extend # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL
114BA ; Extend # Mn TIRHUTA VOWEL SIGN SHORT E
@@ -353,6 +366,16 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT
1171D..1171F ; Extend # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA
11722..11725 ; Extend # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU
11727..1172B ; Extend # Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER
+1182F..11837 ; Extend # Mn [9] DOGRA VOWEL SIGN U..DOGRA SIGN ANUSVARA
+11839..1183A ; Extend # Mn [2] DOGRA SIGN VIRAMA..DOGRA SIGN NUKTA
+11A01..11A0A ; Extend # Mn [10] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL LENGTH MARK
+11A33..11A38 ; Extend # Mn [6] ZANABAZAR SQUARE FINAL CONSONANT MARK..ZANABAZAR SQUARE SIGN ANUSVARA
+11A3B..11A3E ; Extend # Mn [4] ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA
+11A47 ; Extend # Mn ZANABAZAR SQUARE SUBJOINER
+11A51..11A56 ; Extend # Mn [6] SOYOMBO VOWEL SIGN I..SOYOMBO VOWEL SIGN OE
+11A59..11A5B ; Extend # Mn [3] SOYOMBO VOWEL SIGN VOCALIC R..SOYOMBO VOWEL LENGTH MARK
+11A8A..11A96 ; Extend # Mn [13] SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA
+11A98..11A99 ; Extend # Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER
11C30..11C36 ; Extend # Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L
11C38..11C3D ; Extend # Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA
11C3F ; Extend # Mn BHAIKSUKI SIGN VIRAMA
@@ -360,6 +383,15 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT
11CAA..11CB0 ; Extend # Mn [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA
11CB2..11CB3 ; Extend # Mn [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E
11CB5..11CB6 ; Extend # Mn [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU
+11D31..11D36 ; Extend # Mn [6] MASARAM GONDI VOWEL SIGN AA..MASARAM GONDI VOWEL SIGN VOCALIC R
+11D3A ; Extend # Mn MASARAM GONDI VOWEL SIGN E
+11D3C..11D3D ; Extend # Mn [2] MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O
+11D3F..11D45 ; Extend # Mn [7] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI VIRAMA
+11D47 ; Extend # Mn MASARAM GONDI RA-KARA
+11D90..11D91 ; Extend # Mn [2] GUNJALA GONDI VOWEL SIGN EE..GUNJALA GONDI VOWEL SIGN AI
+11D95 ; Extend # Mn GUNJALA GONDI SIGN ANUSVARA
+11D97 ; Extend # Mn GUNJALA GONDI VIRAMA
+11EF3..11EF4 ; Extend # Mn [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U
16AF0..16AF4 ; Extend # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE
16B30..16B36 ; Extend # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM
16F8F..16F92 ; Extend # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW
@@ -384,10 +416,11 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT
1E026..1E02A ; Extend # Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA
1E8D0..1E8D6 ; Extend # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS
1E944..1E94A ; Extend # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA
+1F3FB..1F3FF ; Extend # Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6
E0020..E007F ; Extend # Cf [96] TAG SPACE..CANCEL TAG
E0100..E01EF ; Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
-# Total code points: 1828
+# Total code points: 1948
# ================================================
@@ -472,6 +505,7 @@ E0100..E01EF ; Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
1C34..1C35 ; SpacingMark # Mc [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG
1CE1 ; SpacingMark # Mc VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA
1CF2..1CF3 ; SpacingMark # Mc [2] VEDIC SIGN ARDHAVISARGA..VEDIC SIGN ROTATED ARDHAVISARGA
+1CF7 ; SpacingMark # Mc VEDIC SIGN ATIKRAMA
A823..A824 ; SpacingMark # Mc [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI VOWEL SIGN I
A827 ; SpacingMark # Mc SYLOTI NAGRI VOWEL SIGN OO
A880..A881 ; SpacingMark # Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA
@@ -497,6 +531,7 @@ ABEC ; SpacingMark # Mc MEETEI MAYEK LUM IYEK
110B0..110B2 ; SpacingMark # Mc [3] KAITHI VOWEL SIGN AA..KAITHI VOWEL SIGN II
110B7..110B8 ; SpacingMark # Mc [2] KAITHI VOWEL SIGN O..KAITHI VOWEL SIGN AU
1112C ; SpacingMark # Mc CHAKMA VOWEL SIGN E
+11145..11146 ; SpacingMark # Mc [2] CHAKMA VOWEL SIGN AA..CHAKMA VOWEL SIGN EI
11182 ; SpacingMark # Mc SHARADA SIGN VISARGA
111B3..111B5 ; SpacingMark # Mc [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II
111BF..111C0 ; SpacingMark # Mc [2] SHARADA VOWEL SIGN AU..SHARADA SIGN VIRAMA
@@ -529,16 +564,25 @@ ABEC ; SpacingMark # Mc MEETEI MAYEK LUM IYEK
116B6 ; SpacingMark # Mc TAKRI SIGN VIRAMA
11720..11721 ; SpacingMark # Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA
11726 ; SpacingMark # Mc AHOM VOWEL SIGN E
+1182C..1182E ; SpacingMark # Mc [3] DOGRA VOWEL SIGN AA..DOGRA VOWEL SIGN II
+11838 ; SpacingMark # Mc DOGRA SIGN VISARGA
+11A39 ; SpacingMark # Mc ZANABAZAR SQUARE SIGN VISARGA
+11A57..11A58 ; SpacingMark # Mc [2] SOYOMBO VOWEL SIGN AI..SOYOMBO VOWEL SIGN AU
+11A97 ; SpacingMark # Mc SOYOMBO SIGN VISARGA
11C2F ; SpacingMark # Mc BHAIKSUKI VOWEL SIGN AA
11C3E ; SpacingMark # Mc BHAIKSUKI SIGN VISARGA
11CA9 ; SpacingMark # Mc MARCHEN SUBJOINED LETTER YA
11CB1 ; SpacingMark # Mc MARCHEN VOWEL SIGN I
11CB4 ; SpacingMark # Mc MARCHEN VOWEL SIGN O
+11D8A..11D8E ; SpacingMark # Mc [5] GUNJALA GONDI VOWEL SIGN AA..GUNJALA GONDI VOWEL SIGN UU
+11D93..11D94 ; SpacingMark # Mc [2] GUNJALA GONDI VOWEL SIGN OO..GUNJALA GONDI VOWEL SIGN AU
+11D96 ; SpacingMark # Mc GUNJALA GONDI SIGN VISARGA
+11EF5..11EF6 ; SpacingMark # Mc [2] MAKASAR VOWEL SIGN E..MAKASAR VOWEL SIGN O
16F51..16F7E ; SpacingMark # Mc [46] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN NG
1D166 ; SpacingMark # Mc MUSICAL SYMBOL COMBINING SPRECHGESANG STEM
1D16D ; SpacingMark # Mc MUSICAL SYMBOL COMBINING AUGMENTATION DOT
-# Total code points: 341
+# Total code points: 362
# ================================================
@@ -1371,61 +1415,8 @@ D789..D7A3 ; LVT # Lo [27] HANGUL SYLLABLE HIG..HANGUL SYLLABLE HIH
# ================================================
-261D ; E_Base # So WHITE UP POINTING INDEX
-26F9 ; E_Base # So PERSON WITH BALL
-270A..270D ; E_Base # So [4] RAISED FIST..WRITING HAND
-1F385 ; E_Base # So FATHER CHRISTMAS
-1F3C3..1F3C4 ; E_Base # So [2] RUNNER..SURFER
-1F3CA..1F3CB ; E_Base # So [2] SWIMMER..WEIGHT LIFTER
-1F442..1F443 ; E_Base # So [2] EAR..NOSE
-1F446..1F450 ; E_Base # So [11] WHITE UP POINTING BACKHAND INDEX..OPEN HANDS SIGN
-1F46E ; E_Base # So POLICE OFFICER
-1F470..1F478 ; E_Base # So [9] BRIDE WITH VEIL..PRINCESS
-1F47C ; E_Base # So BABY ANGEL
-1F481..1F483 ; E_Base # So [3] INFORMATION DESK PERSON..DANCER
-1F485..1F487 ; E_Base # So [3] NAIL POLISH..HAIRCUT
-1F4AA ; E_Base # So FLEXED BICEPS
-1F575 ; E_Base # So SLEUTH OR SPY
-1F57A ; E_Base # So MAN DANCING
-1F590 ; E_Base # So RAISED HAND WITH FINGERS SPLAYED
-1F595..1F596 ; E_Base # So [2] REVERSED HAND WITH MIDDLE FINGER EXTENDED..RAISED HAND WITH PART BETWEEN MIDDLE AND RING FINGERS
-1F645..1F647 ; E_Base # So [3] FACE WITH NO GOOD GESTURE..PERSON BOWING DEEPLY
-1F64B..1F64F ; E_Base # So [5] HAPPY PERSON RAISING ONE HAND..PERSON WITH FOLDED HANDS
-1F6A3 ; E_Base # So ROWBOAT
-1F6B4..1F6B6 ; E_Base # So [3] BICYCLIST..PEDESTRIAN
-1F6C0 ; E_Base # So BATH
-1F918..1F91E ; E_Base # So [7] SIGN OF THE HORNS..HAND WITH INDEX AND MIDDLE FINGERS CROSSED
-1F926 ; E_Base # So FACE PALM
-1F930 ; E_Base # So PREGNANT WOMAN
-1F933..1F939 ; E_Base # So [7] SELFIE..JUGGLING
-1F93C..1F93E ; E_Base # So [3] WRESTLERS..HANDBALL
-
-# Total code points: 79
-
-# ================================================
-
-1F3FB..1F3FF ; E_Modifier # Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6
-
-# Total code points: 5
-
-# ================================================
-
200D ; ZWJ # Cf ZERO WIDTH JOINER
# Total code points: 1
-# ================================================
-
-2764 ; Glue_After_Zwj # So HEAVY BLACK HEART
-1F48B ; Glue_After_Zwj # So KISS MARK
-1F5E8 ; Glue_After_Zwj # So LEFT SPEECH BUBBLE
-
-# Total code points: 3
-
-# ================================================
-
-1F466..1F469 ; E_Base_GAZ # So [4] BOY..WOMAN
-
-# Total code points: 4
-
# EOF
diff --git a/lib/stdlib/uc_spec/PropList.txt b/lib/stdlib/uc_spec/PropList.txt
index a8c0da7135..ef86795abe 100644
--- a/lib/stdlib/uc_spec/PropList.txt
+++ b/lib/stdlib/uc_spec/PropList.txt
@@ -1,6 +1,6 @@
-# PropList-9.0.0.txt
-# Date: 2016-06-01, 10:34:30 GMT
-# © 2016 Unicode®, Inc.
+# PropList-11.0.0.txt
+# Date: 2018-03-15, 04:28:35 GMT
+# © 2018 Unicode®, Inc.
# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
# For terms of use, see http://www.unicode.org/terms_of_use.html
#
@@ -125,7 +125,7 @@ FF63 ; Quotation_Mark # Pe HALFWIDTH RIGHT CORNER BRACKET
05C3 ; Terminal_Punctuation # Po HEBREW PUNCTUATION SOF PASUQ
060C ; Terminal_Punctuation # Po ARABIC COMMA
061B ; Terminal_Punctuation # Po ARABIC SEMICOLON
-061F ; Terminal_Punctuation # Po ARABIC QUESTION MARK
+061E..061F ; Terminal_Punctuation # Po [2] ARABIC TRIPLE DOT PUNCTUATION MARK..ARABIC QUESTION MARK
06D4 ; Terminal_Punctuation # Po ARABIC FULL STOP
0700..070A ; Terminal_Punctuation # Po [11] SYRIAC END OF PARAGRAPH..SYRIAC CONTRACTION
070C ; Terminal_Punctuation # Po SYRIAC HARKLEAN METOBELUS
@@ -156,6 +156,8 @@ FF63 ; Quotation_Mark # Pe HALFWIDTH RIGHT CORNER BRACKET
2E2E ; Terminal_Punctuation # Po REVERSED QUESTION MARK
2E3C ; Terminal_Punctuation # Po STENOGRAPHIC FULL STOP
2E41 ; Terminal_Punctuation # Po REVERSED COMMA
+2E4C ; Terminal_Punctuation # Po MEDIEVAL COMMA
+2E4E ; Terminal_Punctuation # Po PUNCTUS ELEVATUS MARK
3001..3002 ; Terminal_Punctuation # Po [2] IDEOGRAPHIC COMMA..IDEOGRAPHIC FULL STOP
A4FE..A4FF ; Terminal_Punctuation # Po [2] LISU PUNCTUATION COMMA..LISU PUNCTUATION FULL STOP
A60D..A60F ; Terminal_Punctuation # Po [3] VAI COMMA..VAI QUESTION MARK
@@ -185,6 +187,7 @@ FF64 ; Terminal_Punctuation # Po HALFWIDTH IDEOGRAPHIC COMMA
10AF0..10AF5 ; Terminal_Punctuation # Po [6] MANICHAEAN PUNCTUATION STAR..MANICHAEAN PUNCTUATION TWO DOTS
10B3A..10B3F ; Terminal_Punctuation # Po [6] TINY TWO DOTS OVER ONE DOT PUNCTUATION..LARGE ONE RING OVER TWO RINGS PUNCTUATION
10B99..10B9C ; Terminal_Punctuation # Po [4] PSALTER PAHLAVI SECTION MARK..PSALTER PAHLAVI FOUR DOTS WITH DOT
+10F55..10F59 ; Terminal_Punctuation # Po [5] SOGDIAN PUNCTUATION TWO VERTICAL BARS..SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT
11047..1104D ; Terminal_Punctuation # Po [7] BRAHMI DANDA..BRAHMI PUNCTUATION LOTUS
110BE..110C1 ; Terminal_Punctuation # Po [4] KAITHI SECTION MARK..KAITHI DOUBLE DANDA
11141..11143 ; Terminal_Punctuation # Po [3] CHAKMA DANDA..CHAKMA QUESTION MARK
@@ -199,17 +202,22 @@ FF64 ; Terminal_Punctuation # Po HALFWIDTH IDEOGRAPHIC COMMA
115C9..115D7 ; Terminal_Punctuation # Po [15] SIDDHAM END OF TEXT MARK..SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES
11641..11642 ; Terminal_Punctuation # Po [2] MODI DANDA..MODI DOUBLE DANDA
1173C..1173E ; Terminal_Punctuation # Po [3] AHOM SIGN SMALL SECTION..AHOM SIGN RULAI
+11A42..11A43 ; Terminal_Punctuation # Po [2] ZANABAZAR SQUARE MARK SHAD..ZANABAZAR SQUARE MARK DOUBLE SHAD
+11A9B..11A9C ; Terminal_Punctuation # Po [2] SOYOMBO MARK SHAD..SOYOMBO MARK DOUBLE SHAD
+11AA1..11AA2 ; Terminal_Punctuation # Po [2] SOYOMBO TERMINAL MARK-1..SOYOMBO TERMINAL MARK-2
11C41..11C43 ; Terminal_Punctuation # Po [3] BHAIKSUKI DANDA..BHAIKSUKI WORD SEPARATOR
11C71 ; Terminal_Punctuation # Po MARCHEN MARK SHAD
+11EF7..11EF8 ; Terminal_Punctuation # Po [2] MAKASAR PASSIMBANG..MAKASAR END OF SECTION
12470..12474 ; Terminal_Punctuation # Po [5] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON
16A6E..16A6F ; Terminal_Punctuation # Po [2] MRO DANDA..MRO DOUBLE DANDA
16AF5 ; Terminal_Punctuation # Po BASSA VAH FULL STOP
16B37..16B39 ; Terminal_Punctuation # Po [3] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN CIM CHEEM
16B44 ; Terminal_Punctuation # Po PAHAWH HMONG SIGN XAUS
+16E97..16E98 ; Terminal_Punctuation # Po [2] MEDEFAIDRIN COMMA..MEDEFAIDRIN FULL STOP
1BC9F ; Terminal_Punctuation # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP
1DA87..1DA8A ; Terminal_Punctuation # Po [4] SIGNWRITING COMMA..SIGNWRITING COLON
-# Total code points: 246
+# Total code points: 264
# ================================================
@@ -471,6 +479,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L
0AC9 ; Other_Alphabetic # Mc GUJARATI VOWEL SIGN CANDRA O
0ACB..0ACC ; Other_Alphabetic # Mc [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU
0AE2..0AE3 ; Other_Alphabetic # Mn [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL
+0AFA..0AFC ; Other_Alphabetic # Mn [3] GUJARATI SIGN SUKUN..GUJARATI SIGN MADDAH
0B01 ; Other_Alphabetic # Mn ORIYA SIGN CANDRABINDU
0B02..0B03 ; Other_Alphabetic # Mc [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA
0B3E ; Other_Alphabetic # Mc ORIYA VOWEL SIGN AA
@@ -508,7 +517,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L
0CCC ; Other_Alphabetic # Mn KANNADA VOWEL SIGN AU
0CD5..0CD6 ; Other_Alphabetic # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK
0CE2..0CE3 ; Other_Alphabetic # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL
-0D01 ; Other_Alphabetic # Mn MALAYALAM SIGN CANDRABINDU
+0D00..0D01 ; Other_Alphabetic # Mn [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU
0D02..0D03 ; Other_Alphabetic # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA
0D3E..0D40 ; Other_Alphabetic # Mc [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II
0D41..0D44 ; Other_Alphabetic # Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR
@@ -657,6 +666,7 @@ FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA
10A01..10A03 ; Other_Alphabetic # Mn [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R
10A05..10A06 ; Other_Alphabetic # Mn [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O
10A0C..10A0F ; Other_Alphabetic # Mn [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA
+10D24..10D27 ; Other_Alphabetic # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI
11000 ; Other_Alphabetic # Mc BRAHMI SIGN CANDRABINDU
11001 ; Other_Alphabetic # Mn BRAHMI SIGN ANUSVARA
11002 ; Other_Alphabetic # Mc BRAHMI SIGN VISARGA
@@ -669,6 +679,7 @@ FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA
11127..1112B ; Other_Alphabetic # Mn [5] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN UU
1112C ; Other_Alphabetic # Mc CHAKMA VOWEL SIGN E
1112D..11132 ; Other_Alphabetic # Mn [6] CHAKMA VOWEL SIGN AI..CHAKMA AU MARK
+11145..11146 ; Other_Alphabetic # Mc [2] CHAKMA VOWEL SIGN AA..CHAKMA VOWEL SIGN EI
11180..11181 ; Other_Alphabetic # Mn [2] SHARADA SIGN CANDRABINDU..SHARADA SIGN ANUSVARA
11182 ; Other_Alphabetic # Mc SHARADA SIGN VISARGA
111B3..111B5 ; Other_Alphabetic # Mc [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II
@@ -726,6 +737,18 @@ FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA
11722..11725 ; Other_Alphabetic # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU
11726 ; Other_Alphabetic # Mc AHOM VOWEL SIGN E
11727..1172A ; Other_Alphabetic # Mn [4] AHOM VOWEL SIGN AW..AHOM VOWEL SIGN AM
+1182C..1182E ; Other_Alphabetic # Mc [3] DOGRA VOWEL SIGN AA..DOGRA VOWEL SIGN II
+1182F..11837 ; Other_Alphabetic # Mn [9] DOGRA VOWEL SIGN U..DOGRA SIGN ANUSVARA
+11838 ; Other_Alphabetic # Mc DOGRA SIGN VISARGA
+11A01..11A0A ; Other_Alphabetic # Mn [10] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL LENGTH MARK
+11A35..11A38 ; Other_Alphabetic # Mn [4] ZANABAZAR SQUARE SIGN CANDRABINDU..ZANABAZAR SQUARE SIGN ANUSVARA
+11A39 ; Other_Alphabetic # Mc ZANABAZAR SQUARE SIGN VISARGA
+11A3B..11A3E ; Other_Alphabetic # Mn [4] ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA
+11A51..11A56 ; Other_Alphabetic # Mn [6] SOYOMBO VOWEL SIGN I..SOYOMBO VOWEL SIGN OE
+11A57..11A58 ; Other_Alphabetic # Mc [2] SOYOMBO VOWEL SIGN AI..SOYOMBO VOWEL SIGN AU
+11A59..11A5B ; Other_Alphabetic # Mn [3] SOYOMBO VOWEL SIGN VOCALIC R..SOYOMBO VOWEL LENGTH MARK
+11A8A..11A96 ; Other_Alphabetic # Mn [13] SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA
+11A97 ; Other_Alphabetic # Mc SOYOMBO SIGN VISARGA
11C2F ; Other_Alphabetic # Mc BHAIKSUKI VOWEL SIGN AA
11C30..11C36 ; Other_Alphabetic # Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L
11C38..11C3D ; Other_Alphabetic # Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA
@@ -737,6 +760,19 @@ FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA
11CB2..11CB3 ; Other_Alphabetic # Mn [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E
11CB4 ; Other_Alphabetic # Mc MARCHEN VOWEL SIGN O
11CB5..11CB6 ; Other_Alphabetic # Mn [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU
+11D31..11D36 ; Other_Alphabetic # Mn [6] MASARAM GONDI VOWEL SIGN AA..MASARAM GONDI VOWEL SIGN VOCALIC R
+11D3A ; Other_Alphabetic # Mn MASARAM GONDI VOWEL SIGN E
+11D3C..11D3D ; Other_Alphabetic # Mn [2] MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O
+11D3F..11D41 ; Other_Alphabetic # Mn [3] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI SIGN VISARGA
+11D43 ; Other_Alphabetic # Mn MASARAM GONDI SIGN CANDRA
+11D47 ; Other_Alphabetic # Mn MASARAM GONDI RA-KARA
+11D8A..11D8E ; Other_Alphabetic # Mc [5] GUNJALA GONDI VOWEL SIGN AA..GUNJALA GONDI VOWEL SIGN UU
+11D90..11D91 ; Other_Alphabetic # Mn [2] GUNJALA GONDI VOWEL SIGN EE..GUNJALA GONDI VOWEL SIGN AI
+11D93..11D94 ; Other_Alphabetic # Mc [2] GUNJALA GONDI VOWEL SIGN OO..GUNJALA GONDI VOWEL SIGN AU
+11D95 ; Other_Alphabetic # Mn GUNJALA GONDI SIGN ANUSVARA
+11D96 ; Other_Alphabetic # Mc GUNJALA GONDI SIGN VISARGA
+11EF3..11EF4 ; Other_Alphabetic # Mn [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U
+11EF5..11EF6 ; Other_Alphabetic # Mc [2] MAKASAR VOWEL SIGN E..MAKASAR VOWEL SIGN O
16B30..16B36 ; Other_Alphabetic # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM
16F51..16F7E ; Other_Alphabetic # Mc [46] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN NG
1BC9E ; Other_Alphabetic # Mn DUPLOYAN DOUBLE MARK
@@ -750,7 +786,7 @@ FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA
1F150..1F169 ; Other_Alphabetic # So [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z
1F170..1F189 ; Other_Alphabetic # So [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z
-# Total code points: 1238
+# Total code points: 1334
# ================================================
@@ -759,18 +795,20 @@ FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA
3021..3029 ; Ideographic # Nl [9] HANGZHOU NUMERAL ONE..HANGZHOU NUMERAL NINE
3038..303A ; Ideographic # Nl [3] HANGZHOU NUMERAL TEN..HANGZHOU NUMERAL THIRTY
3400..4DB5 ; Ideographic # Lo [6582] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DB5
-4E00..9FD5 ; Ideographic # Lo [20950] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FD5
+4E00..9FEF ; Ideographic # Lo [20976] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FEF
F900..FA6D ; Ideographic # Lo [366] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA6D
FA70..FAD9 ; Ideographic # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COMPATIBILITY IDEOGRAPH-FAD9
-17000..187EC ; Ideographic # Lo [6125] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187EC
+17000..187F1 ; Ideographic # Lo [6130] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F1
18800..18AF2 ; Ideographic # Lo [755] TANGUT COMPONENT-001..TANGUT COMPONENT-755
+1B170..1B2FB ; Ideographic # Lo [396] NUSHU CHARACTER-1B170..NUSHU CHARACTER-1B2FB
20000..2A6D6 ; Ideographic # Lo [42711] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6D6
2A700..2B734 ; Ideographic # Lo [4149] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B734
2B740..2B81D ; Ideographic # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D
2B820..2CEA1 ; Ideographic # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1
+2CEB0..2EBE0 ; Ideographic # Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0
2F800..2FA1D ; Ideographic # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D
-# Total code points: 88284
+# Total code points: 96184
# ================================================
@@ -826,12 +864,14 @@ FA70..FAD9 ; Ideographic # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COM
0A4D ; Diacritic # Mn GURMUKHI SIGN VIRAMA
0ABC ; Diacritic # Mn GUJARATI SIGN NUKTA
0ACD ; Diacritic # Mn GUJARATI SIGN VIRAMA
+0AFD..0AFF ; Diacritic # Mn [3] GUJARATI SIGN THREE-DOT NUKTA ABOVE..GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE
0B3C ; Diacritic # Mn ORIYA SIGN NUKTA
0B4D ; Diacritic # Mn ORIYA SIGN VIRAMA
0BCD ; Diacritic # Mn TAMIL SIGN VIRAMA
0C4D ; Diacritic # Mn TELUGU SIGN VIRAMA
0CBC ; Diacritic # Mn KANNADA SIGN NUKTA
0CCD ; Diacritic # Mn KANNADA SIGN VIRAMA
+0D3B..0D3C ; Diacritic # Mn [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA
0D4D ; Diacritic # Mn MALAYALAM SIGN VIRAMA
0DCA ; Diacritic # Mn SINHALA SIGN AL-LAKUNA
0E47..0E4C ; Diacritic # Mn [6] THAI CHARACTER MAITAIKHU..THAI CHARACTER THANTHAKHAT
@@ -871,10 +911,11 @@ FA70..FAD9 ; Ideographic # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COM
1CE2..1CE8 ; Diacritic # Mn [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL
1CED ; Diacritic # Mn VEDIC SIGN TIRYAK
1CF4 ; Diacritic # Mn VEDIC TONE CANDRA ABOVE
+1CF7 ; Diacritic # Mc VEDIC SIGN ATIKRAMA
1CF8..1CF9 ; Diacritic # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE
1D2C..1D6A ; Diacritic # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI
1DC4..1DCF ; Diacritic # Mn [12] COMBINING MACRON-ACUTE..COMBINING ZIGZAG BELOW
-1DF5 ; Diacritic # Mn COMBINING UP TACK ABOVE
+1DF5..1DF9 ; Diacritic # Mn [5] COMBINING UP TACK ABOVE..COMBINING WIDE INVERTED BRIDGE BELOW
1DFD..1DFF ; Diacritic # Mn [3] COMBINING ALMOST EQUAL TO BELOW..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW
1FBD ; Diacritic # Sk GREEK KORONIS
1FBF..1FC1 ; Diacritic # Sk [3] GREEK PSILI..GREEK DIALYTIKA AND PERISPOMENI
@@ -927,6 +968,9 @@ FF9E..FF9F ; Diacritic # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFW
FFE3 ; Diacritic # Sk FULLWIDTH MACRON
102E0 ; Diacritic # Mn COPTIC EPACT THOUSANDS MARK
10AE5..10AE6 ; Diacritic # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW
+10D22..10D23 ; Diacritic # Lo [2] HANIFI ROHINGYA MARK SAKIN..HANIFI ROHINGYA MARK NA KHONNA
+10D24..10D27 ; Diacritic # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI
+10F46..10F50 ; Diacritic # Mn [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW
110B9..110BA ; Diacritic # Mn [2] KAITHI SIGN VIRAMA..KAITHI SIGN NUKTA
11133..11134 ; Diacritic # Mn [2] CHAKMA VIRAMA..CHAKMA MAAYYAA
11173 ; Diacritic # Mn MAHAJANI SIGN NUKTA
@@ -947,7 +991,14 @@ FFE3 ; Diacritic # Sk FULLWIDTH MACRON
116B6 ; Diacritic # Mc TAKRI SIGN VIRAMA
116B7 ; Diacritic # Mn TAKRI SIGN NUKTA
1172B ; Diacritic # Mn AHOM SIGN KILLER
+11839..1183A ; Diacritic # Mn [2] DOGRA SIGN VIRAMA..DOGRA SIGN NUKTA
+11A34 ; Diacritic # Mn ZANABAZAR SQUARE SIGN VIRAMA
+11A47 ; Diacritic # Mn ZANABAZAR SQUARE SUBJOINER
+11A99 ; Diacritic # Mn SOYOMBO SUBJOINER
11C3F ; Diacritic # Mn BHAIKSUKI SIGN VIRAMA
+11D42 ; Diacritic # Mn MASARAM GONDI SIGN NUKTA
+11D44..11D45 ; Diacritic # Mn [2] MASARAM GONDI SIGN HALANTA..MASARAM GONDI VIRAMA
+11D97 ; Diacritic # Mn GUNJALA GONDI VIRAMA
16AF0..16AF4 ; Diacritic # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE
16F8F..16F92 ; Diacritic # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW
16F93..16F9F ; Diacritic # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8
@@ -960,7 +1011,7 @@ FFE3 ; Diacritic # Sk FULLWIDTH MACRON
1E944..1E946 ; Diacritic # Mn [3] ADLAM ALIF LENGTHENER..ADLAM GEMINATION MARK
1E948..1E94A ; Diacritic # Mn [3] ADLAM CONSONANT MODIFIER..ADLAM NUKTA
-# Total code points: 782
+# Total code points: 818
# ================================================
@@ -989,11 +1040,12 @@ AAF3..AAF4 ; Extender # Lm [2] MEETEI MAYEK SYLLABLE REPETITION MARK..MEETE
FF70 ; Extender # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK
1135D ; Extender # Lo GRANTHA SIGN PLUTA
115C6..115C8 ; Extender # Po [3] SIDDHAM REPETITION MARK-1..SIDDHAM REPETITION MARK-3
+11A98 ; Extender # Mn SOYOMBO GEMINATION MARK
16B42..16B43 ; Extender # Lm [2] PAHAWH HMONG SIGN VOS NRUA..PAHAWH HMONG SIGN IB YAM
-16FE0 ; Extender # Lm TANGUT ITERATION MARK
+16FE0..16FE1 ; Extender # Lm [2] TANGUT ITERATION MARK..NUSHU ITERATION MARK
1E944..1E946 ; Extender # Mn [3] ADLAM ALIF LENGTHENER..ADLAM GEMINATION MARK
-# Total code points: 42
+# Total code points: 44
# ================================================
@@ -1105,7 +1157,7 @@ E0020..E007F ; Other_Grapheme_Extend # Cf [96] TAG SPACE..CANCEL TAG
# ================================================
3400..4DB5 ; Unified_Ideograph # Lo [6582] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DB5
-4E00..9FD5 ; Unified_Ideograph # Lo [20950] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FD5
+4E00..9FEF ; Unified_Ideograph # Lo [20976] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FEF
FA0E..FA0F ; Unified_Ideograph # Lo [2] CJK COMPATIBILITY IDEOGRAPH-FA0E..CJK COMPATIBILITY IDEOGRAPH-FA0F
FA11 ; Unified_Ideograph # Lo CJK COMPATIBILITY IDEOGRAPH-FA11
FA13..FA14 ; Unified_Ideograph # Lo [2] CJK COMPATIBILITY IDEOGRAPH-FA13..CJK COMPATIBILITY IDEOGRAPH-FA14
@@ -1117,8 +1169,9 @@ FA27..FA29 ; Unified_Ideograph # Lo [3] CJK COMPATIBILITY IDEOGRAPH-FA27..C
2A700..2B734 ; Unified_Ideograph # Lo [4149] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B734
2B740..2B81D ; Unified_Ideograph # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D
2B820..2CEA1 ; Unified_Ideograph # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1
+2CEB0..2EBE0 ; Unified_Ideograph # Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0
-# Total code points: 80388
+# Total code points: 87887
# ================================================
@@ -1222,10 +1275,13 @@ AABB..AABC ; Logical_Order_Exception # Lo [2] TAI VIET VOWEL AUE..TAI VIET
002E ; Sentence_Terminal # Po FULL STOP
003F ; Sentence_Terminal # Po QUESTION MARK
0589 ; Sentence_Terminal # Po ARMENIAN FULL STOP
-061F ; Sentence_Terminal # Po ARABIC QUESTION MARK
+061E..061F ; Sentence_Terminal # Po [2] ARABIC TRIPLE DOT PUNCTUATION MARK..ARABIC QUESTION MARK
06D4 ; Sentence_Terminal # Po ARABIC FULL STOP
0700..0702 ; Sentence_Terminal # Po [3] SYRIAC END OF PARAGRAPH..SYRIAC SUBLINEAR FULL STOP
07F9 ; Sentence_Terminal # Po NKO EXCLAMATION MARK
+0837 ; Sentence_Terminal # Po SAMARITAN PUNCTUATION MELODIC QITSA
+0839 ; Sentence_Terminal # Po SAMARITAN PUNCTUATION QITSA
+083D..083E ; Sentence_Terminal # Po [2] SAMARITAN PUNCTUATION SOF MASHFAAT..SAMARITAN PUNCTUATION ANNAAU
0964..0965 ; Sentence_Terminal # Po [2] DEVANAGARI DANDA..DEVANAGARI DOUBLE DANDA
104A..104B ; Sentence_Terminal # Po [2] MYANMAR SIGN LITTLE SECTION..MYANMAR SIGN SECTION
1362 ; Sentence_Terminal # Po ETHIOPIC FULL STOP
@@ -1263,6 +1319,7 @@ FF0E ; Sentence_Terminal # Po FULLWIDTH FULL STOP
FF1F ; Sentence_Terminal # Po FULLWIDTH QUESTION MARK
FF61 ; Sentence_Terminal # Po HALFWIDTH IDEOGRAPHIC FULL STOP
10A56..10A57 ; Sentence_Terminal # Po [2] KHAROSHTHI PUNCTUATION DANDA..KHAROSHTHI PUNCTUATION DOUBLE DANDA
+10F55..10F59 ; Sentence_Terminal # Po [5] SOGDIAN PUNCTUATION TWO VERTICAL BARS..SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT
11047..11048 ; Sentence_Terminal # Po [2] BRAHMI DANDA..BRAHMI DOUBLE DANDA
110BE..110C1 ; Sentence_Terminal # Po [4] KAITHI SECTION MARK..KAITHI DOUBLE DANDA
11141..11143 ; Sentence_Terminal # Po [3] CHAKMA DANDA..CHAKMA QUESTION MARK
@@ -1277,15 +1334,19 @@ FF61 ; Sentence_Terminal # Po HALFWIDTH IDEOGRAPHIC FULL STOP
115C9..115D7 ; Sentence_Terminal # Po [15] SIDDHAM END OF TEXT MARK..SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES
11641..11642 ; Sentence_Terminal # Po [2] MODI DANDA..MODI DOUBLE DANDA
1173C..1173E ; Sentence_Terminal # Po [3] AHOM SIGN SMALL SECTION..AHOM SIGN RULAI
+11A42..11A43 ; Sentence_Terminal # Po [2] ZANABAZAR SQUARE MARK SHAD..ZANABAZAR SQUARE MARK DOUBLE SHAD
+11A9B..11A9C ; Sentence_Terminal # Po [2] SOYOMBO MARK SHAD..SOYOMBO MARK DOUBLE SHAD
11C41..11C42 ; Sentence_Terminal # Po [2] BHAIKSUKI DANDA..BHAIKSUKI DOUBLE DANDA
+11EF7..11EF8 ; Sentence_Terminal # Po [2] MAKASAR PASSIMBANG..MAKASAR END OF SECTION
16A6E..16A6F ; Sentence_Terminal # Po [2] MRO DANDA..MRO DOUBLE DANDA
16AF5 ; Sentence_Terminal # Po BASSA VAH FULL STOP
16B37..16B38 ; Sentence_Terminal # Po [2] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN VOS TSHAB CEEB
16B44 ; Sentence_Terminal # Po PAHAWH HMONG SIGN XAUS
+16E98 ; Sentence_Terminal # Po MEDEFAIDRIN FULL STOP
1BC9F ; Sentence_Terminal # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP
1DA88 ; Sentence_Terminal # Po SIGNWRITING FULL STOP
-# Total code points: 124
+# Total code points: 141
# ================================================
@@ -1402,9 +1463,7 @@ E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION S
239B..23B3 ; Pattern_Syntax # Sm [25] LEFT PARENTHESIS UPPER HOOK..SUMMATION BOTTOM
23B4..23DB ; Pattern_Syntax # So [40] TOP SQUARE BRACKET..FUSE
23DC..23E1 ; Pattern_Syntax # Sm [6] TOP PARENTHESIS..BOTTOM TORTOISE SHELL BRACKET
-23E2..23FE ; Pattern_Syntax # So [29] WHITE TRAPEZIUM..POWER SLEEP SYMBOL
-23FF ; Pattern_Syntax # Cn <reserved-23FF>
-2400..2426 ; Pattern_Syntax # So [39] SYMBOL FOR NULL..SYMBOL FOR SUBSTITUTE FORM TWO
+23E2..2426 ; Pattern_Syntax # So [69] WHITE TRAPEZIUM..SYMBOL FOR SUBSTITUTE FORM TWO
2427..243F ; Pattern_Syntax # Cn [25] <reserved-2427>..<reserved-243F>
2440..244A ; Pattern_Syntax # So [11] OCR HOOK..OCR DOUBLE BACKSLASH
244B..245F ; Pattern_Syntax # Cn [21] <reserved-244B>..<reserved-245F>
@@ -1488,14 +1547,10 @@ E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION S
2B74..2B75 ; Pattern_Syntax # Cn [2] <reserved-2B74>..<reserved-2B75>
2B76..2B95 ; Pattern_Syntax # So [32] NORTH WEST TRIANGLE-HEADED ARROW TO BAR..RIGHTWARDS BLACK ARROW
2B96..2B97 ; Pattern_Syntax # Cn [2] <reserved-2B96>..<reserved-2B97>
-2B98..2BB9 ; Pattern_Syntax # So [34] THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD..UP ARROWHEAD IN A RECTANGLE BOX
-2BBA..2BBC ; Pattern_Syntax # Cn [3] <reserved-2BBA>..<reserved-2BBC>
-2BBD..2BC8 ; Pattern_Syntax # So [12] BALLOT BOX WITH LIGHT X..BLACK MEDIUM RIGHT-POINTING TRIANGLE CENTRED
+2B98..2BC8 ; Pattern_Syntax # So [49] THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD..BLACK MEDIUM RIGHT-POINTING TRIANGLE CENTRED
2BC9 ; Pattern_Syntax # Cn <reserved-2BC9>
-2BCA..2BD1 ; Pattern_Syntax # So [8] TOP HALF BLACK CIRCLE..UNCERTAINTY SIGN
-2BD2..2BEB ; Pattern_Syntax # Cn [26] <reserved-2BD2>..<reserved-2BEB>
-2BEC..2BEF ; Pattern_Syntax # So [4] LEFTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS..DOWNWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS
-2BF0..2BFF ; Pattern_Syntax # Cn [16] <reserved-2BF0>..<reserved-2BFF>
+2BCA..2BFE ; Pattern_Syntax # So [53] TOP HALF BLACK CIRCLE..REVERSED RIGHT ANGLE
+2BFF ; Pattern_Syntax # Cn <reserved-2BFF>
2E00..2E01 ; Pattern_Syntax # Po [2] RIGHT ANGLE SUBSTITUTION MARKER..RIGHT ANGLE DOTTED SUBSTITUTION MARKER
2E02 ; Pattern_Syntax # Pi LEFT SUBSTITUTION BRACKET
2E03 ; Pattern_Syntax # Pf RIGHT SUBSTITUTION BRACKET
@@ -1533,8 +1588,8 @@ E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION S
2E40 ; Pattern_Syntax # Pd DOUBLE HYPHEN
2E41 ; Pattern_Syntax # Po REVERSED COMMA
2E42 ; Pattern_Syntax # Ps DOUBLE LOW-REVERSED-9 QUOTATION MARK
-2E43..2E44 ; Pattern_Syntax # Po [2] DASH WITH LEFT UPTURN..DOUBLE SUSPENSION MARK
-2E45..2E7F ; Pattern_Syntax # Cn [59] <reserved-2E45>..<reserved-2E7F>
+2E43..2E4E ; Pattern_Syntax # Po [12] DASH WITH LEFT UPTURN..PUNCTUS ELEVATUS MARK
+2E4F..2E7F ; Pattern_Syntax # Cn [49] <reserved-2E4F>..<reserved-2E7F>
3001..3003 ; Pattern_Syntax # Po [3] IDEOGRAPHIC COMMA..DITTO MARK
3008 ; Pattern_Syntax # Ps LEFT ANGLE BRACKET
3009 ; Pattern_Syntax # Pe RIGHT ANGLE BRACKET
@@ -1573,7 +1628,14 @@ FE45..FE46 ; Pattern_Syntax # Po [2] SESAME DOT..WHITE SESAME DOT
070F ; Prepended_Concatenation_Mark # Cf SYRIAC ABBREVIATION MARK
08E2 ; Prepended_Concatenation_Mark # Cf ARABIC DISPUTED END OF AYAH
110BD ; Prepended_Concatenation_Mark # Cf KAITHI NUMBER SIGN
+110CD ; Prepended_Concatenation_Mark # Cf KAITHI NUMBER SIGN ABOVE
-# Total code points: 10
+# Total code points: 11
+
+# ================================================
+
+1F1E6..1F1FF ; Regional_Indicator # So [26] REGIONAL INDICATOR SYMBOL LETTER A..REGIONAL INDICATOR SYMBOL LETTER Z
+
+# Total code points: 26
# EOF
diff --git a/lib/stdlib/uc_spec/README-UPDATE.txt b/lib/stdlib/uc_spec/README-UPDATE.txt
index d59337e1a5..e1f5c8fcd0 100644
--- a/lib/stdlib/uc_spec/README-UPDATE.txt
+++ b/lib/stdlib/uc_spec/README-UPDATE.txt
@@ -1,7 +1,13 @@
When updating the unicode version copy the necessary files to this
directory.
-
And update the test files in stdlib/test/unicode_util_SUITE_data/*
+Unicode 11 was updated from:
+https://www.unicode.org/Public/11.0.0/ucd/
+https://www.unicode.org/Public/11.0.0/ucd/auxiliary/
+https://www.unicode.org/Public/emoji/11.0/
+
Update the spec_version(..) function in the generator,
gen_unicode_mod.escript
+
+
diff --git a/lib/stdlib/uc_spec/SpecialCasing.txt b/lib/stdlib/uc_spec/SpecialCasing.txt
index b23fa7f768..c90d09acb3 100644
--- a/lib/stdlib/uc_spec/SpecialCasing.txt
+++ b/lib/stdlib/uc_spec/SpecialCasing.txt
@@ -1,6 +1,6 @@
-# SpecialCasing-9.0.0.txt
-# Date: 2016-03-02, 18:55:13 GMT
-# © 2016 Unicode®, Inc.
+# SpecialCasing-11.0.0.txt
+# Date: 2018-02-22, 06:16:47 GMT
+# © 2018 Unicode®, Inc.
# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
# For terms of use, see http://www.unicode.org/terms_of_use.html
#
@@ -121,7 +121,7 @@ FB17; FB17; 0544 056D; 0544 053D; # ARMENIAN SMALL LIGATURE MEN XEH
# The following cases are already in the UnicodeData.txt file, so are only commented here.
-# 0345; 0345; 0345; 0399; # COMBINING GREEK YPOGEGRAMMENI
+# 0345; 0345; 0399; 0399; # COMBINING GREEK YPOGEGRAMMENI
# All letters with YPOGEGRAMMENI (iota-subscript) or PROSGEGRAMMENI (iota adscript)
# have special uppercases.
@@ -197,7 +197,7 @@ FB17; FB17; 0544 056D; 0544 053D; # ARMENIAN SMALL LIGATURE MEN XEH
# ================================================================================
# Conditional Mappings
-# The remainder of this file provides conditional casing data used to produce
+# The remainder of this file provides conditional casing data used to produce
# full case mappings.
# ================================================================================
# Language-Insensitive Mappings
diff --git a/lib/stdlib/uc_spec/UnicodeData.txt b/lib/stdlib/uc_spec/UnicodeData.txt
index a756976461..ec32fafbce 100644
--- a/lib/stdlib/uc_spec/UnicodeData.txt
+++ b/lib/stdlib/uc_spec/UnicodeData.txt
@@ -1362,6 +1362,7 @@
055D;ARMENIAN COMMA;Po;0;L;;;;;N;;;;;
055E;ARMENIAN QUESTION MARK;Po;0;L;;;;;N;;;;;
055F;ARMENIAN ABBREVIATION MARK;Po;0;L;;;;;N;;;;;
+0560;ARMENIAN SMALL LETTER TURNED AYB;Ll;0;L;;;;;N;;;;;
0561;ARMENIAN SMALL LETTER AYB;Ll;0;L;;;;;N;;;0531;;0531
0562;ARMENIAN SMALL LETTER BEN;Ll;0;L;;;;;N;;;0532;;0532
0563;ARMENIAN SMALL LETTER GIM;Ll;0;L;;;;;N;;;0533;;0533
@@ -1401,6 +1402,7 @@
0585;ARMENIAN SMALL LETTER OH;Ll;0;L;;;;;N;;;0555;;0555
0586;ARMENIAN SMALL LETTER FEH;Ll;0;L;;;;;N;;;0556;;0556
0587;ARMENIAN SMALL LIGATURE ECH YIWN;Ll;0;L;<compat> 0565 0582;;;;N;;;;;
+0588;ARMENIAN SMALL LETTER YI WITH STROKE;Ll;0;L;;;;;N;;;;;
0589;ARMENIAN FULL STOP;Po;0;L;;;;;N;ARMENIAN PERIOD;;;;
058A;ARMENIAN HYPHEN;Pd;0;ON;;;;;N;;;;;
058D;RIGHT-FACING ARMENIAN ETERNITY SIGN;So;0;ON;;;;;N;;;;;
@@ -1488,6 +1490,7 @@
05E8;HEBREW LETTER RESH;Lo;0;R;;;;;N;;;;;
05E9;HEBREW LETTER SHIN;Lo;0;R;;;;;N;;;;;
05EA;HEBREW LETTER TAV;Lo;0;R;;;;;N;;;;;
+05EF;HEBREW YOD TRIANGLE;Lo;0;R;;;;;N;;;;;
05F0;HEBREW LIGATURE YIDDISH DOUBLE VAV;Lo;0;R;;;;;N;HEBREW LETTER DOUBLE VAV;;;;
05F1;HEBREW LIGATURE YIDDISH VAV YOD;Lo;0;R;;;;;N;HEBREW LETTER VAV YOD;;;;
05F2;HEBREW LIGATURE YIDDISH DOUBLE YOD;Lo;0;R;;;;;N;HEBREW LETTER DOUBLE YOD;;;;
@@ -1982,6 +1985,9 @@
07F8;NKO COMMA;Po;0;ON;;;;;N;;;;;
07F9;NKO EXCLAMATION MARK;Po;0;ON;;;;;N;;;;;
07FA;NKO LAJANYALAN;Lm;0;R;;;;;N;;;;;
+07FD;NKO DANTAYALAN;Mn;220;NSM;;;;;N;;;;;
+07FE;NKO DOROME SIGN;Sc;0;R;;;;;N;;;;;
+07FF;NKO TAMAN SIGN;Sc;0;R;;;;;N;;;;;
0800;SAMARITAN LETTER ALAF;Lo;0;R;;;;;N;;;;;
0801;SAMARITAN LETTER BIT;Lo;0;R;;;;;N;;;;;
0802;SAMARITAN LETTER GAMAN;Lo;0;R;;;;;N;;;;;
@@ -2072,6 +2078,17 @@
085A;MANDAIC VOCALIZATION MARK;Mn;220;NSM;;;;;N;;;;;
085B;MANDAIC GEMINATION MARK;Mn;220;NSM;;;;;N;;;;;
085E;MANDAIC PUNCTUATION;Po;0;R;;;;;N;;;;;
+0860;SYRIAC LETTER MALAYALAM NGA;Lo;0;AL;;;;;N;;;;;
+0861;SYRIAC LETTER MALAYALAM JA;Lo;0;AL;;;;;N;;;;;
+0862;SYRIAC LETTER MALAYALAM NYA;Lo;0;AL;;;;;N;;;;;
+0863;SYRIAC LETTER MALAYALAM TTA;Lo;0;AL;;;;;N;;;;;
+0864;SYRIAC LETTER MALAYALAM NNA;Lo;0;AL;;;;;N;;;;;
+0865;SYRIAC LETTER MALAYALAM NNNA;Lo;0;AL;;;;;N;;;;;
+0866;SYRIAC LETTER MALAYALAM BHA;Lo;0;AL;;;;;N;;;;;
+0867;SYRIAC LETTER MALAYALAM RA;Lo;0;AL;;;;;N;;;;;
+0868;SYRIAC LETTER MALAYALAM LLA;Lo;0;AL;;;;;N;;;;;
+0869;SYRIAC LETTER MALAYALAM LLLA;Lo;0;AL;;;;;N;;;;;
+086A;SYRIAC LETTER MALAYALAM SSA;Lo;0;AL;;;;;N;;;;;
08A0;ARABIC LETTER BEH WITH SMALL V BELOW;Lo;0;AL;;;;;N;;;;;
08A1;ARABIC LETTER BEH WITH HAMZA ABOVE;Lo;0;AL;;;;;N;;;;;
08A2;ARABIC LETTER JEEM WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
@@ -2101,6 +2118,7 @@
08BB;ARABIC LETTER AFRICAN FEH;Lo;0;AL;;;;;N;;;;;
08BC;ARABIC LETTER AFRICAN QAF;Lo;0;AL;;;;;N;;;;;
08BD;ARABIC LETTER AFRICAN NOON;Lo;0;AL;;;;;N;;;;;
+08D3;ARABIC SMALL LOW WAW;Mn;220;NSM;;;;;N;;;;;
08D4;ARABIC SMALL HIGH WORD AR-RUB;Mn;230;NSM;;;;;N;;;;;
08D5;ARABIC SMALL HIGH SAD;Mn;230;NSM;;;;;N;;;;;
08D6;ARABIC SMALL HIGH AIN;Mn;230;NSM;;;;;N;;;;;
@@ -2366,6 +2384,9 @@
09F9;BENGALI CURRENCY DENOMINATOR SIXTEEN;No;0;L;;;;16;N;;;;;
09FA;BENGALI ISSHAR;So;0;L;;;;;N;;;;;
09FB;BENGALI GANDA MARK;Sc;0;ET;;;;;N;;;;;
+09FC;BENGALI LETTER VEDIC ANUSVARA;Lo;0;L;;;;;N;;;;;
+09FD;BENGALI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;
+09FE;BENGALI SANDHI MARK;Mn;230;NSM;;;;;N;;;;;
0A01;GURMUKHI SIGN ADAK BINDI;Mn;0;NSM;;;;;N;;;;;
0A02;GURMUKHI SIGN BINDI;Mn;0;NSM;;;;;N;;;;;
0A03;GURMUKHI SIGN VISARGA;Mc;0;L;;;;;N;;;;;
@@ -2445,6 +2466,7 @@
0A73;GURMUKHI URA;Lo;0;L;;;;;N;;;;;
0A74;GURMUKHI EK ONKAR;Lo;0;L;;;;;N;;;;;
0A75;GURMUKHI SIGN YAKASH;Mn;0;NSM;;;;;N;;;;;
+0A76;GURMUKHI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;
0A81;GUJARATI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
0A82;GUJARATI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
0A83;GUJARATI SIGN VISARGA;Mc;0;L;;;;;N;;;;;
@@ -2530,6 +2552,12 @@
0AF0;GUJARATI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;
0AF1;GUJARATI RUPEE SIGN;Sc;0;ET;;;;;N;;;;;
0AF9;GUJARATI LETTER ZHA;Lo;0;L;;;;;N;;;;;
+0AFA;GUJARATI SIGN SUKUN;Mn;0;NSM;;;;;N;;;;;
+0AFB;GUJARATI SIGN SHADDA;Mn;0;NSM;;;;;N;;;;;
+0AFC;GUJARATI SIGN MADDAH;Mn;0;NSM;;;;;N;;;;;
+0AFD;GUJARATI SIGN THREE-DOT NUKTA ABOVE;Mn;0;NSM;;;;;N;;;;;
+0AFE;GUJARATI SIGN CIRCLE NUKTA ABOVE;Mn;0;NSM;;;;;N;;;;;
+0AFF;GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE;Mn;0;NSM;;;;;N;;;;;
0B01;ORIYA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
0B02;ORIYA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
0B03;ORIYA SIGN VISARGA;Mc;0;L;;;;;N;;;;;
@@ -2696,6 +2724,7 @@
0C01;TELUGU SIGN CANDRABINDU;Mc;0;L;;;;;N;;;;;
0C02;TELUGU SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
0C03;TELUGU SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0C04;TELUGU SIGN COMBINING ANUSVARA ABOVE;Mn;0;NSM;;;;;N;;;;;
0C05;TELUGU LETTER A;Lo;0;L;;;;;N;;;;;
0C06;TELUGU LETTER AA;Lo;0;L;;;;;N;;;;;
0C07;TELUGU LETTER I;Lo;0;L;;;;;N;;;;;
@@ -2792,6 +2821,7 @@
0C81;KANNADA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
0C82;KANNADA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
0C83;KANNADA SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0C84;KANNADA SIGN SIDDHAM;Po;0;L;;;;;N;;;;;
0C85;KANNADA LETTER A;Lo;0;L;;;;;N;;;;;
0C86;KANNADA LETTER AA;Lo;0;L;;;;;N;;;;;
0C87;KANNADA LETTER I;Lo;0;L;;;;;N;;;;;
@@ -2876,6 +2906,7 @@
0CEF;KANNADA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
0CF1;KANNADA SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;;
0CF2;KANNADA SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;;
+0D00;MALAYALAM SIGN COMBINING ANUSVARA ABOVE;Mn;0;NSM;;;;;N;;;;;
0D01;MALAYALAM SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
0D02;MALAYALAM SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
0D03;MALAYALAM SIGN VISARGA;Mc;0;L;;;;;N;;;;;
@@ -2931,6 +2962,8 @@
0D38;MALAYALAM LETTER SA;Lo;0;L;;;;;N;;;;;
0D39;MALAYALAM LETTER HA;Lo;0;L;;;;;N;;;;;
0D3A;MALAYALAM LETTER TTTA;Lo;0;L;;;;;N;;;;;
+0D3B;MALAYALAM SIGN VERTICAL BAR VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0D3C;MALAYALAM SIGN CIRCULAR VIRAMA;Mn;9;NSM;;;;;N;;;;;
0D3D;MALAYALAM SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;
0D3E;MALAYALAM VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
0D3F;MALAYALAM VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
@@ -3645,54 +3678,54 @@
10C5;GEORGIAN CAPITAL LETTER HOE;Lu;0;L;;;;;N;;;;2D25;
10C7;GEORGIAN CAPITAL LETTER YN;Lu;0;L;;;;;N;;;;2D27;
10CD;GEORGIAN CAPITAL LETTER AEN;Lu;0;L;;;;;N;;;;2D2D;
-10D0;GEORGIAN LETTER AN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER AN;;;;
-10D1;GEORGIAN LETTER BAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER BAN;;;;
-10D2;GEORGIAN LETTER GAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER GAN;;;;
-10D3;GEORGIAN LETTER DON;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER DON;;;;
-10D4;GEORGIAN LETTER EN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER EN;;;;
-10D5;GEORGIAN LETTER VIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER VIN;;;;
-10D6;GEORGIAN LETTER ZEN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ZEN;;;;
-10D7;GEORGIAN LETTER TAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER TAN;;;;
-10D8;GEORGIAN LETTER IN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER IN;;;;
-10D9;GEORGIAN LETTER KAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER KAN;;;;
-10DA;GEORGIAN LETTER LAS;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER LAS;;;;
-10DB;GEORGIAN LETTER MAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER MAN;;;;
-10DC;GEORGIAN LETTER NAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER NAR;;;;
-10DD;GEORGIAN LETTER ON;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ON;;;;
-10DE;GEORGIAN LETTER PAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER PAR;;;;
-10DF;GEORGIAN LETTER ZHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ZHAR;;;;
-10E0;GEORGIAN LETTER RAE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER RAE;;;;
-10E1;GEORGIAN LETTER SAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER SAN;;;;
-10E2;GEORGIAN LETTER TAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER TAR;;;;
-10E3;GEORGIAN LETTER UN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER UN;;;;
-10E4;GEORGIAN LETTER PHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER PHAR;;;;
-10E5;GEORGIAN LETTER KHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER KHAR;;;;
-10E6;GEORGIAN LETTER GHAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER GHAN;;;;
-10E7;GEORGIAN LETTER QAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER QAR;;;;
-10E8;GEORGIAN LETTER SHIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER SHIN;;;;
-10E9;GEORGIAN LETTER CHIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CHIN;;;;
-10EA;GEORGIAN LETTER CAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CAN;;;;
-10EB;GEORGIAN LETTER JIL;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER JIL;;;;
-10EC;GEORGIAN LETTER CIL;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CIL;;;;
-10ED;GEORGIAN LETTER CHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CHAR;;;;
-10EE;GEORGIAN LETTER XAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER XAN;;;;
-10EF;GEORGIAN LETTER JHAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER JHAN;;;;
-10F0;GEORGIAN LETTER HAE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HAE;;;;
-10F1;GEORGIAN LETTER HE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HE;;;;
-10F2;GEORGIAN LETTER HIE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HIE;;;;
-10F3;GEORGIAN LETTER WE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER WE;;;;
-10F4;GEORGIAN LETTER HAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HAR;;;;
-10F5;GEORGIAN LETTER HOE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HOE;;;;
-10F6;GEORGIAN LETTER FI;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER FI;;;;
-10F7;GEORGIAN LETTER YN;Lo;0;L;;;;;N;;;;;
-10F8;GEORGIAN LETTER ELIFI;Lo;0;L;;;;;N;;;;;
-10F9;GEORGIAN LETTER TURNED GAN;Lo;0;L;;;;;N;;;;;
-10FA;GEORGIAN LETTER AIN;Lo;0;L;;;;;N;;;;;
+10D0;GEORGIAN LETTER AN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER AN;;1C90;;10D0
+10D1;GEORGIAN LETTER BAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER BAN;;1C91;;10D1
+10D2;GEORGIAN LETTER GAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER GAN;;1C92;;10D2
+10D3;GEORGIAN LETTER DON;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER DON;;1C93;;10D3
+10D4;GEORGIAN LETTER EN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER EN;;1C94;;10D4
+10D5;GEORGIAN LETTER VIN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER VIN;;1C95;;10D5
+10D6;GEORGIAN LETTER ZEN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER ZEN;;1C96;;10D6
+10D7;GEORGIAN LETTER TAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER TAN;;1C97;;10D7
+10D8;GEORGIAN LETTER IN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER IN;;1C98;;10D8
+10D9;GEORGIAN LETTER KAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER KAN;;1C99;;10D9
+10DA;GEORGIAN LETTER LAS;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER LAS;;1C9A;;10DA
+10DB;GEORGIAN LETTER MAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER MAN;;1C9B;;10DB
+10DC;GEORGIAN LETTER NAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER NAR;;1C9C;;10DC
+10DD;GEORGIAN LETTER ON;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER ON;;1C9D;;10DD
+10DE;GEORGIAN LETTER PAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER PAR;;1C9E;;10DE
+10DF;GEORGIAN LETTER ZHAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER ZHAR;;1C9F;;10DF
+10E0;GEORGIAN LETTER RAE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER RAE;;1CA0;;10E0
+10E1;GEORGIAN LETTER SAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER SAN;;1CA1;;10E1
+10E2;GEORGIAN LETTER TAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER TAR;;1CA2;;10E2
+10E3;GEORGIAN LETTER UN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER UN;;1CA3;;10E3
+10E4;GEORGIAN LETTER PHAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER PHAR;;1CA4;;10E4
+10E5;GEORGIAN LETTER KHAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER KHAR;;1CA5;;10E5
+10E6;GEORGIAN LETTER GHAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER GHAN;;1CA6;;10E6
+10E7;GEORGIAN LETTER QAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER QAR;;1CA7;;10E7
+10E8;GEORGIAN LETTER SHIN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER SHIN;;1CA8;;10E8
+10E9;GEORGIAN LETTER CHIN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER CHIN;;1CA9;;10E9
+10EA;GEORGIAN LETTER CAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER CAN;;1CAA;;10EA
+10EB;GEORGIAN LETTER JIL;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER JIL;;1CAB;;10EB
+10EC;GEORGIAN LETTER CIL;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER CIL;;1CAC;;10EC
+10ED;GEORGIAN LETTER CHAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER CHAR;;1CAD;;10ED
+10EE;GEORGIAN LETTER XAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER XAN;;1CAE;;10EE
+10EF;GEORGIAN LETTER JHAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER JHAN;;1CAF;;10EF
+10F0;GEORGIAN LETTER HAE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HAE;;1CB0;;10F0
+10F1;GEORGIAN LETTER HE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HE;;1CB1;;10F1
+10F2;GEORGIAN LETTER HIE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HIE;;1CB2;;10F2
+10F3;GEORGIAN LETTER WE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER WE;;1CB3;;10F3
+10F4;GEORGIAN LETTER HAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HAR;;1CB4;;10F4
+10F5;GEORGIAN LETTER HOE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HOE;;1CB5;;10F5
+10F6;GEORGIAN LETTER FI;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER FI;;1CB6;;10F6
+10F7;GEORGIAN LETTER YN;Ll;0;L;;;;;N;;;1CB7;;10F7
+10F8;GEORGIAN LETTER ELIFI;Ll;0;L;;;;;N;;;1CB8;;10F8
+10F9;GEORGIAN LETTER TURNED GAN;Ll;0;L;;;;;N;;;1CB9;;10F9
+10FA;GEORGIAN LETTER AIN;Ll;0;L;;;;;N;;;1CBA;;10FA
10FB;GEORGIAN PARAGRAPH SEPARATOR;Po;0;L;;;;;N;;;;;
10FC;MODIFIER LETTER GEORGIAN NAR;Lm;0;L;<super> 10DC;;;;N;;;;;
-10FD;GEORGIAN LETTER AEN;Lo;0;L;;;;;N;;;;;
-10FE;GEORGIAN LETTER HARD SIGN;Lo;0;L;;;;;N;;;;;
-10FF;GEORGIAN LETTER LABIAL SIGN;Lo;0;L;;;;;N;;;;;
+10FD;GEORGIAN LETTER AEN;Ll;0;L;;;;;N;;;1CBD;;10FD
+10FE;GEORGIAN LETTER HARD SIGN;Ll;0;L;;;;;N;;;1CBE;;10FE
+10FF;GEORGIAN LETTER LABIAL SIGN;Ll;0;L;;;;;N;;;1CBF;;10FF
1100;HANGUL CHOSEONG KIYEOK;Lo;0;L;;;;;N;;;;;
1101;HANGUL CHOSEONG SSANGKIYEOK;Lo;0;L;;;;;N;;;;;
1102;HANGUL CHOSEONG NIEUN;Lo;0;L;;;;;N;;;;;
@@ -5491,6 +5524,7 @@
1875;MONGOLIAN LETTER MANCHU RA;Lo;0;L;;;;;N;;;;;
1876;MONGOLIAN LETTER MANCHU FA;Lo;0;L;;;;;N;;;;;
1877;MONGOLIAN LETTER MANCHU ZHA;Lo;0;L;;;;;N;;;;;
+1878;MONGOLIAN LETTER CHA WITH TWO DOTS;Lo;0;L;;;;;N;;;;;
1880;MONGOLIAN LETTER ALI GALI ANUSVARA ONE;Lo;0;L;;;;;N;;;;;
1881;MONGOLIAN LETTER ALI GALI VISARGA ONE;Lo;0;L;;;;;N;;;;;
1882;MONGOLIAN LETTER ALI GALI DAMARU;Lo;0;L;;;;;N;;;;;
@@ -6366,6 +6400,52 @@
1C86;CYRILLIC SMALL LETTER TALL HARD SIGN;Ll;0;L;;;;;N;;;042A;;042A
1C87;CYRILLIC SMALL LETTER TALL YAT;Ll;0;L;;;;;N;;;0462;;0462
1C88;CYRILLIC SMALL LETTER UNBLENDED UK;Ll;0;L;;;;;N;;;A64A;;A64A
+1C90;GEORGIAN MTAVRULI CAPITAL LETTER AN;Lu;0;L;;;;;N;;;;10D0;
+1C91;GEORGIAN MTAVRULI CAPITAL LETTER BAN;Lu;0;L;;;;;N;;;;10D1;
+1C92;GEORGIAN MTAVRULI CAPITAL LETTER GAN;Lu;0;L;;;;;N;;;;10D2;
+1C93;GEORGIAN MTAVRULI CAPITAL LETTER DON;Lu;0;L;;;;;N;;;;10D3;
+1C94;GEORGIAN MTAVRULI CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;10D4;
+1C95;GEORGIAN MTAVRULI CAPITAL LETTER VIN;Lu;0;L;;;;;N;;;;10D5;
+1C96;GEORGIAN MTAVRULI CAPITAL LETTER ZEN;Lu;0;L;;;;;N;;;;10D6;
+1C97;GEORGIAN MTAVRULI CAPITAL LETTER TAN;Lu;0;L;;;;;N;;;;10D7;
+1C98;GEORGIAN MTAVRULI CAPITAL LETTER IN;Lu;0;L;;;;;N;;;;10D8;
+1C99;GEORGIAN MTAVRULI CAPITAL LETTER KAN;Lu;0;L;;;;;N;;;;10D9;
+1C9A;GEORGIAN MTAVRULI CAPITAL LETTER LAS;Lu;0;L;;;;;N;;;;10DA;
+1C9B;GEORGIAN MTAVRULI CAPITAL LETTER MAN;Lu;0;L;;;;;N;;;;10DB;
+1C9C;GEORGIAN MTAVRULI CAPITAL LETTER NAR;Lu;0;L;;;;;N;;;;10DC;
+1C9D;GEORGIAN MTAVRULI CAPITAL LETTER ON;Lu;0;L;;;;;N;;;;10DD;
+1C9E;GEORGIAN MTAVRULI CAPITAL LETTER PAR;Lu;0;L;;;;;N;;;;10DE;
+1C9F;GEORGIAN MTAVRULI CAPITAL LETTER ZHAR;Lu;0;L;;;;;N;;;;10DF;
+1CA0;GEORGIAN MTAVRULI CAPITAL LETTER RAE;Lu;0;L;;;;;N;;;;10E0;
+1CA1;GEORGIAN MTAVRULI CAPITAL LETTER SAN;Lu;0;L;;;;;N;;;;10E1;
+1CA2;GEORGIAN MTAVRULI CAPITAL LETTER TAR;Lu;0;L;;;;;N;;;;10E2;
+1CA3;GEORGIAN MTAVRULI CAPITAL LETTER UN;Lu;0;L;;;;;N;;;;10E3;
+1CA4;GEORGIAN MTAVRULI CAPITAL LETTER PHAR;Lu;0;L;;;;;N;;;;10E4;
+1CA5;GEORGIAN MTAVRULI CAPITAL LETTER KHAR;Lu;0;L;;;;;N;;;;10E5;
+1CA6;GEORGIAN MTAVRULI CAPITAL LETTER GHAN;Lu;0;L;;;;;N;;;;10E6;
+1CA7;GEORGIAN MTAVRULI CAPITAL LETTER QAR;Lu;0;L;;;;;N;;;;10E7;
+1CA8;GEORGIAN MTAVRULI CAPITAL LETTER SHIN;Lu;0;L;;;;;N;;;;10E8;
+1CA9;GEORGIAN MTAVRULI CAPITAL LETTER CHIN;Lu;0;L;;;;;N;;;;10E9;
+1CAA;GEORGIAN MTAVRULI CAPITAL LETTER CAN;Lu;0;L;;;;;N;;;;10EA;
+1CAB;GEORGIAN MTAVRULI CAPITAL LETTER JIL;Lu;0;L;;;;;N;;;;10EB;
+1CAC;GEORGIAN MTAVRULI CAPITAL LETTER CIL;Lu;0;L;;;;;N;;;;10EC;
+1CAD;GEORGIAN MTAVRULI CAPITAL LETTER CHAR;Lu;0;L;;;;;N;;;;10ED;
+1CAE;GEORGIAN MTAVRULI CAPITAL LETTER XAN;Lu;0;L;;;;;N;;;;10EE;
+1CAF;GEORGIAN MTAVRULI CAPITAL LETTER JHAN;Lu;0;L;;;;;N;;;;10EF;
+1CB0;GEORGIAN MTAVRULI CAPITAL LETTER HAE;Lu;0;L;;;;;N;;;;10F0;
+1CB1;GEORGIAN MTAVRULI CAPITAL LETTER HE;Lu;0;L;;;;;N;;;;10F1;
+1CB2;GEORGIAN MTAVRULI CAPITAL LETTER HIE;Lu;0;L;;;;;N;;;;10F2;
+1CB3;GEORGIAN MTAVRULI CAPITAL LETTER WE;Lu;0;L;;;;;N;;;;10F3;
+1CB4;GEORGIAN MTAVRULI CAPITAL LETTER HAR;Lu;0;L;;;;;N;;;;10F4;
+1CB5;GEORGIAN MTAVRULI CAPITAL LETTER HOE;Lu;0;L;;;;;N;;;;10F5;
+1CB6;GEORGIAN MTAVRULI CAPITAL LETTER FI;Lu;0;L;;;;;N;;;;10F6;
+1CB7;GEORGIAN MTAVRULI CAPITAL LETTER YN;Lu;0;L;;;;;N;;;;10F7;
+1CB8;GEORGIAN MTAVRULI CAPITAL LETTER ELIFI;Lu;0;L;;;;;N;;;;10F8;
+1CB9;GEORGIAN MTAVRULI CAPITAL LETTER TURNED GAN;Lu;0;L;;;;;N;;;;10F9;
+1CBA;GEORGIAN MTAVRULI CAPITAL LETTER AIN;Lu;0;L;;;;;N;;;;10FA;
+1CBD;GEORGIAN MTAVRULI CAPITAL LETTER AEN;Lu;0;L;;;;;N;;;;10FD;
+1CBE;GEORGIAN MTAVRULI CAPITAL LETTER HARD SIGN;Lu;0;L;;;;;N;;;;10FE;
+1CBF;GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN;Lu;0;L;;;;;N;;;;10FF;
1CC0;SUNDANESE PUNCTUATION BINDU SURYA;Po;0;L;;;;;N;;;;;
1CC1;SUNDANESE PUNCTUATION BINDU PANGLONG;Po;0;L;;;;;N;;;;;
1CC2;SUNDANESE PUNCTUATION BINDU PURNAMA;Po;0;L;;;;;N;;;;;
@@ -6413,6 +6493,7 @@
1CF4;VEDIC TONE CANDRA ABOVE;Mn;230;NSM;;;;;N;;;;;
1CF5;VEDIC SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;;
1CF6;VEDIC SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;;
+1CF7;VEDIC SIGN ATIKRAMA;Mc;0;L;;;;;N;;;;;
1CF8;VEDIC TONE RING ABOVE;Mn;230;NSM;;;;;N;;;;;
1CF9;VEDIC TONE DOUBLE RING ABOVE;Mn;230;NSM;;;;;N;;;;;
1D00;LATIN LETTER SMALL CAPITAL A;Ll;0;L;;;;;N;;;;;
@@ -6661,6 +6742,10 @@
1DF3;COMBINING LATIN SMALL LETTER O WITH DIAERESIS;Mn;230;NSM;;;;;N;;;;;
1DF4;COMBINING LATIN SMALL LETTER U WITH DIAERESIS;Mn;230;NSM;;;;;N;;;;;
1DF5;COMBINING UP TACK ABOVE;Mn;230;NSM;;;;;N;;;;;
+1DF6;COMBINING KAVYKA ABOVE RIGHT;Mn;232;NSM;;;;;N;;;;;
+1DF7;COMBINING KAVYKA ABOVE LEFT;Mn;228;NSM;;;;;N;;;;;
+1DF8;COMBINING DOT ABOVE LEFT;Mn;228;NSM;;;;;N;;;;;
+1DF9;COMBINING WIDE INVERTED BRIDGE BELOW;Mn;220;NSM;;;;;N;;;;;
1DFB;COMBINING DELETION MARK;Mn;230;NSM;;;;;N;;;;;
1DFC;COMBINING DOUBLE INVERTED BREVE BELOW;Mn;233;NSM;;;;;N;;;;;
1DFD;COMBINING ALMOST EQUAL TO BELOW;Mn;220;NSM;;;;;N;;;;;
@@ -7339,6 +7424,7 @@
20BC;MANAT SIGN;Sc;0;ET;;;;;N;;;;;
20BD;RUBLE SIGN;Sc;0;ET;;;;;N;;;;;
20BE;LARI SIGN;Sc;0;ET;;;;;N;;;;;
+20BF;BITCOIN SIGN;Sc;0;ET;;;;;N;;;;;
20D0;COMBINING LEFT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT HARPOON ABOVE;;;;
20D1;COMBINING RIGHT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RIGHT HARPOON ABOVE;;;;
20D2;COMBINING LONG VERTICAL LINE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG VERTICAL BAR OVERLAY;;;;
@@ -8135,6 +8221,7 @@
23FC;POWER ON-OFF SYMBOL;So;0;ON;;;;;N;;;;;
23FD;POWER ON SYMBOL;So;0;ON;;;;;N;;;;;
23FE;POWER SLEEP SYMBOL;So;0;ON;;;;;N;;;;;
+23FF;OBSERVER EYE SYMBOL;So;0;ON;;;;;N;;;;;
2400;SYMBOL FOR NULL;So;0;ON;;;;;N;GRAPHIC FOR NULL;;;;
2401;SYMBOL FOR START OF HEADING;So;0;ON;;;;;N;GRAPHIC FOR START OF HEADING;;;;
2402;SYMBOL FOR START OF TEXT;So;0;ON;;;;;N;GRAPHIC FOR START OF TEXT;;;;
@@ -9530,7 +9617,7 @@
299E;ANGLE WITH S INSIDE;Sm;0;ON;;;;;Y;;;;;
299F;ACUTE ANGLE;Sm;0;ON;;;;;Y;;;;;
29A0;SPHERICAL ANGLE OPENING LEFT;Sm;0;ON;;;;;Y;;;;;
-29A1;SPHERICAL ANGLE OPENING UP;Sm;0;ON;;;;;Y;;;;;
+29A1;SPHERICAL ANGLE OPENING UP;Sm;0;ON;;;;;N;;;;;
29A2;TURNED ANGLE;Sm;0;ON;;;;;Y;;;;;
29A3;REVERSED ANGLE;Sm;0;ON;;;;;Y;;;;;
29A4;ANGLE WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;;
@@ -10063,6 +10150,9 @@
2BB7;RIBBON ARROW RIGHT DOWN;So;0;ON;;;;;N;;;;;
2BB8;UPWARDS WHITE ARROW FROM BAR WITH HORIZONTAL BAR;So;0;ON;;;;;N;;;;;
2BB9;UP ARROWHEAD IN A RECTANGLE BOX;So;0;ON;;;;;N;;;;;
+2BBA;OVERLAPPING WHITE SQUARES;So;0;ON;;;;;N;;;;;
+2BBB;OVERLAPPING WHITE AND BLACK SQUARES;So;0;ON;;;;;N;;;;;
+2BBC;OVERLAPPING BLACK SQUARES;So;0;ON;;;;;N;;;;;
2BBD;BALLOT BOX WITH LIGHT X;So;0;ON;;;;;N;;;;;
2BBE;CIRCLED X;So;0;ON;;;;;N;;;;;
2BBF;CIRCLED BOLD X;So;0;ON;;;;;N;;;;;
@@ -10083,10 +10173,51 @@
2BCF;ROTATED WHITE FOUR POINTED CUSP;So;0;ON;;;;;N;;;;;
2BD0;SQUARE POSITION INDICATOR;So;0;ON;;;;;N;;;;;
2BD1;UNCERTAINTY SIGN;So;0;ON;;;;;N;;;;;
+2BD2;GROUP MARK;So;0;ON;;;;;N;;;;;
+2BD3;PLUTO FORM TWO;So;0;ON;;;;;N;;;;;
+2BD4;PLUTO FORM THREE;So;0;ON;;;;;N;;;;;
+2BD5;PLUTO FORM FOUR;So;0;ON;;;;;N;;;;;
+2BD6;PLUTO FORM FIVE;So;0;ON;;;;;N;;;;;
+2BD7;TRANSPLUTO;So;0;ON;;;;;N;;;;;
+2BD8;PROSERPINA;So;0;ON;;;;;N;;;;;
+2BD9;ASTRAEA;So;0;ON;;;;;N;;;;;
+2BDA;HYGIEA;So;0;ON;;;;;N;;;;;
+2BDB;PHOLUS;So;0;ON;;;;;N;;;;;
+2BDC;NESSUS;So;0;ON;;;;;N;;;;;
+2BDD;WHITE MOON SELENA;So;0;ON;;;;;N;;;;;
+2BDE;BLACK DIAMOND ON CROSS;So;0;ON;;;;;N;;;;;
+2BDF;TRUE LIGHT MOON ARTA;So;0;ON;;;;;N;;;;;
+2BE0;CUPIDO;So;0;ON;;;;;N;;;;;
+2BE1;HADES;So;0;ON;;;;;N;;;;;
+2BE2;ZEUS;So;0;ON;;;;;N;;;;;
+2BE3;KRONOS;So;0;ON;;;;;N;;;;;
+2BE4;APOLLON;So;0;ON;;;;;N;;;;;
+2BE5;ADMETOS;So;0;ON;;;;;N;;;;;
+2BE6;VULCANUS;So;0;ON;;;;;N;;;;;
+2BE7;POSEIDON;So;0;ON;;;;;N;;;;;
+2BE8;LEFT HALF BLACK STAR;So;0;ON;;;;;N;;;;;
+2BE9;RIGHT HALF BLACK STAR;So;0;ON;;;;;N;;;;;
+2BEA;STAR WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;;
+2BEB;STAR WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;;
2BEC;LEFTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;;
2BED;UPWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;;
2BEE;RIGHTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;;
2BEF;DOWNWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;;
+2BF0;ERIS FORM ONE;So;0;ON;;;;;N;;;;;
+2BF1;ERIS FORM TWO;So;0;ON;;;;;N;;;;;
+2BF2;SEDNA;So;0;ON;;;;;N;;;;;
+2BF3;RUSSIAN ASTROLOGICAL SYMBOL VIGINTILE;So;0;ON;;;;;N;;;;;
+2BF4;RUSSIAN ASTROLOGICAL SYMBOL NOVILE;So;0;ON;;;;;N;;;;;
+2BF5;RUSSIAN ASTROLOGICAL SYMBOL QUINTILE;So;0;ON;;;;;N;;;;;
+2BF6;RUSSIAN ASTROLOGICAL SYMBOL BINOVILE;So;0;ON;;;;;N;;;;;
+2BF7;RUSSIAN ASTROLOGICAL SYMBOL SENTAGON;So;0;ON;;;;;N;;;;;
+2BF8;RUSSIAN ASTROLOGICAL SYMBOL TREDECILE;So;0;ON;;;;;N;;;;;
+2BF9;EQUALS SIGN WITH INFINITY BELOW;So;0;ON;;;;;N;;;;;
+2BFA;UNITED SYMBOL;So;0;ON;;;;;N;;;;;
+2BFB;SEPARATED SYMBOL;So;0;ON;;;;;N;;;;;
+2BFC;DOUBLED SYMBOL;So;0;ON;;;;;N;;;;;
+2BFD;PASSED SYMBOL;So;0;ON;;;;;N;;;;;
+2BFE;REVERSED RIGHT ANGLE;So;0;ON;;;;;Y;;;;;
2C00;GLAGOLITIC CAPITAL LETTER AZU;Lu;0;L;;;;;N;;;;2C30;
2C01;GLAGOLITIC CAPITAL LETTER BUKY;Lu;0;L;;;;;N;;;;2C31;
2C02;GLAGOLITIC CAPITAL LETTER VEDE;Lu;0;L;;;;;N;;;;2C32;
@@ -10615,6 +10746,16 @@
2E42;DOUBLE LOW-REVERSED-9 QUOTATION MARK;Ps;0;ON;;;;;N;;;;;
2E43;DASH WITH LEFT UPTURN;Po;0;ON;;;;;N;;;;;
2E44;DOUBLE SUSPENSION MARK;Po;0;ON;;;;;N;;;;;
+2E45;INVERTED LOW KAVYKA;Po;0;ON;;;;;N;;;;;
+2E46;INVERTED LOW KAVYKA WITH KAVYKA ABOVE;Po;0;ON;;;;;N;;;;;
+2E47;LOW KAVYKA;Po;0;ON;;;;;N;;;;;
+2E48;LOW KAVYKA WITH DOT;Po;0;ON;;;;;N;;;;;
+2E49;DOUBLE STACKED COMMA;Po;0;ON;;;;;N;;;;;
+2E4A;DOTTED SOLIDUS;Po;0;ON;;;;;N;;;;;
+2E4B;TRIPLE DAGGER;Po;0;ON;;;;;N;;;;;
+2E4C;MEDIEVAL COMMA;Po;0;ON;;;;;N;;;;;
+2E4D;PARAGRAPHUS MARK;Po;0;ON;;;;;N;;;;;
+2E4E;PUNCTUS ELEVATUS MARK;Po;0;ON;;;;;N;;;;;
2E80;CJK RADICAL REPEAT;So;0;ON;;;;;N;;;;;
2E81;CJK RADICAL CLIFF;So;0;ON;;;;;N;;;;;
2E82;CJK RADICAL SECOND ONE;So;0;ON;;;;;N;;;;;
@@ -11250,6 +11391,8 @@
312B;BOPOMOFO LETTER NG;Lo;0;L;;;;;N;;;;;
312C;BOPOMOFO LETTER GN;Lo;0;L;;;;;N;;;;;
312D;BOPOMOFO LETTER IH;Lo;0;L;;;;;N;;;;;
+312E;BOPOMOFO LETTER O WITH DOT ABOVE;Lo;0;L;;;;;N;;;;;
+312F;BOPOMOFO LETTER NN;Lo;0;L;;;;;N;;;;;
3131;HANGUL LETTER KIYEOK;Lo;0;L;<compat> 1100;;;;N;HANGUL LETTER GIYEOG;;;;
3132;HANGUL LETTER SSANGKIYEOK;Lo;0;L;<compat> 1101;;;;N;HANGUL LETTER SSANG GIYEOG;;;;
3133;HANGUL LETTER KIYEOK-SIOS;Lo;0;L;<compat> 11AA;;;;N;HANGUL LETTER GIYEOG SIOS;;;;
@@ -12016,7 +12159,7 @@
4DFE;HEXAGRAM FOR AFTER COMPLETION;So;0;ON;;;;;N;;;;;
4DFF;HEXAGRAM FOR BEFORE COMPLETION;So;0;ON;;;;;N;;;;;
4E00;<CJK Ideograph, First>;Lo;0;L;;;;;N;;;;;
-9FD5;<CJK Ideograph, Last>;Lo;0;L;;;;;N;;;;;
+9FEF;<CJK Ideograph, Last>;Lo;0;L;;;;;N;;;;;
A000;YI SYLLABLE IT;Lo;0;L;;;;;N;;;;;
A001;YI SYLLABLE IX;Lo;0;L;;;;;N;;;;;
A002;YI SYLLABLE I;Lo;0;L;;;;;N;;;;;
@@ -13944,6 +14087,7 @@ A7AB;LATIN CAPITAL LETTER REVERSED OPEN E;Lu;0;L;;;;;N;;;;025C;
A7AC;LATIN CAPITAL LETTER SCRIPT G;Lu;0;L;;;;;N;;;;0261;
A7AD;LATIN CAPITAL LETTER L WITH BELT;Lu;0;L;;;;;N;;;;026C;
A7AE;LATIN CAPITAL LETTER SMALL CAPITAL I;Lu;0;L;;;;;N;;;;026A;
+A7AF;LATIN LETTER SMALL CAPITAL Q;Ll;0;L;;;;;N;;;;;
A7B0;LATIN CAPITAL LETTER TURNED K;Lu;0;L;;;;;N;;;;029E;
A7B1;LATIN CAPITAL LETTER TURNED T;Lu;0;L;;;;;N;;;;0287;
A7B2;LATIN CAPITAL LETTER J WITH CROSSED-TAIL;Lu;0;L;;;;;N;;;;029D;
@@ -13952,6 +14096,8 @@ A7B4;LATIN CAPITAL LETTER BETA;Lu;0;L;;;;;N;;;;A7B5;
A7B5;LATIN SMALL LETTER BETA;Ll;0;L;;;;;N;;;A7B4;;A7B4
A7B6;LATIN CAPITAL LETTER OMEGA;Lu;0;L;;;;;N;;;;A7B7;
A7B7;LATIN SMALL LETTER OMEGA;Ll;0;L;;;;;N;;;A7B6;;A7B6
+A7B8;LATIN CAPITAL LETTER U WITH STROKE;Lu;0;L;;;;;N;;;;A7B9;
+A7B9;LATIN SMALL LETTER U WITH STROKE;Ll;0;L;;;;;N;;;A7B8;;A7B8
A7F7;LATIN EPIGRAPHIC LETTER SIDEWAYS I;Lo;0;L;;;;;N;;;;;
A7F8;MODIFIER LETTER CAPITAL H WITH STROKE;Lm;0;L;<super> 0126;;;;N;;;;;
A7F9;MODIFIER LETTER SMALL LIGATURE OE;Lm;0;L;<super> 0153;;;;N;;;;;
@@ -14183,6 +14329,8 @@ A8FA;DEVANAGARI CARET;Po;0;L;;;;;N;;;;;
A8FB;DEVANAGARI HEADSTROKE;Lo;0;L;;;;;N;;;;;
A8FC;DEVANAGARI SIGN SIDDHAM;Po;0;L;;;;;N;;;;;
A8FD;DEVANAGARI JAIN OM;Lo;0;L;;;;;N;;;;;
+A8FE;DEVANAGARI LETTER AY;Lo;0;L;;;;;N;;;;;
+A8FF;DEVANAGARI VOWEL SIGN AY;Mn;0;NSM;;;;;N;;;;;
A900;KAYAH LI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
A901;KAYAH LI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
A902;KAYAH LI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
@@ -17093,6 +17241,9 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
10321;OLD ITALIC NUMERAL FIVE;No;0;L;;;;5;N;;;;;
10322;OLD ITALIC NUMERAL TEN;No;0;L;;;;10;N;;;;;
10323;OLD ITALIC NUMERAL FIFTY;No;0;L;;;;50;N;;;;;
+1032D;OLD ITALIC LETTER YE;Lo;0;L;;;;;N;;;;;
+1032E;OLD ITALIC LETTER NORTHERN TSE;Lo;0;L;;;;;N;;;;;
+1032F;OLD ITALIC LETTER SOUTHERN TSE;Lo;0;L;;;;;N;;;;;
10330;GOTHIC LETTER AHSA;Lo;0;L;;;;;N;;;;;
10331;GOTHIC LETTER BAIRKAN;Lo;0;L;;;;;N;;;;;
10332;GOTHIC LETTER GIBA;Lo;0;L;;;;;N;;;;;
@@ -18324,6 +18475,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
10A31;KHAROSHTHI LETTER HA;Lo;0;R;;;;;N;;;;;
10A32;KHAROSHTHI LETTER KKA;Lo;0;R;;;;;N;;;;;
10A33;KHAROSHTHI LETTER TTTHA;Lo;0;R;;;;;N;;;;;
+10A34;KHAROSHTHI LETTER TTTA;Lo;0;R;;;;;N;;;;;
+10A35;KHAROSHTHI LETTER VHA;Lo;0;R;;;;;N;;;;;
10A38;KHAROSHTHI SIGN BAR ABOVE;Mn;230;NSM;;;;;N;;;;;
10A39;KHAROSHTHI SIGN CAUDA;Mn;1;NSM;;;;;N;;;;;
10A3A;KHAROSHTHI SIGN DOT BELOW;Mn;220;NSM;;;;;N;;;;;
@@ -18336,6 +18489,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
10A45;KHAROSHTHI NUMBER TWENTY;No;0;R;;;;20;N;;;;;
10A46;KHAROSHTHI NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;
10A47;KHAROSHTHI NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;;
+10A48;KHAROSHTHI FRACTION ONE HALF;No;0;R;;;;1/2;N;;;;;
10A50;KHAROSHTHI PUNCTUATION DOT;Po;0;R;;;;;N;;;;;
10A51;KHAROSHTHI PUNCTUATION SMALL CIRCLE;Po;0;R;;;;;N;;;;;
10A52;KHAROSHTHI PUNCTUATION CIRCLE;Po;0;R;;;;;N;;;;;
@@ -18788,6 +18942,56 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
10CFD;OLD HUNGARIAN NUMBER FIFTY;No;0;R;;;;50;N;;;;;
10CFE;OLD HUNGARIAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;
10CFF;OLD HUNGARIAN NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;;
+10D00;HANIFI ROHINGYA LETTER A;Lo;0;AL;;;;;N;;;;;
+10D01;HANIFI ROHINGYA LETTER BA;Lo;0;AL;;;;;N;;;;;
+10D02;HANIFI ROHINGYA LETTER PA;Lo;0;AL;;;;;N;;;;;
+10D03;HANIFI ROHINGYA LETTER TA;Lo;0;AL;;;;;N;;;;;
+10D04;HANIFI ROHINGYA LETTER TTA;Lo;0;AL;;;;;N;;;;;
+10D05;HANIFI ROHINGYA LETTER JA;Lo;0;AL;;;;;N;;;;;
+10D06;HANIFI ROHINGYA LETTER CA;Lo;0;AL;;;;;N;;;;;
+10D07;HANIFI ROHINGYA LETTER HA;Lo;0;AL;;;;;N;;;;;
+10D08;HANIFI ROHINGYA LETTER KHA;Lo;0;AL;;;;;N;;;;;
+10D09;HANIFI ROHINGYA LETTER FA;Lo;0;AL;;;;;N;;;;;
+10D0A;HANIFI ROHINGYA LETTER DA;Lo;0;AL;;;;;N;;;;;
+10D0B;HANIFI ROHINGYA LETTER DDA;Lo;0;AL;;;;;N;;;;;
+10D0C;HANIFI ROHINGYA LETTER RA;Lo;0;AL;;;;;N;;;;;
+10D0D;HANIFI ROHINGYA LETTER RRA;Lo;0;AL;;;;;N;;;;;
+10D0E;HANIFI ROHINGYA LETTER ZA;Lo;0;AL;;;;;N;;;;;
+10D0F;HANIFI ROHINGYA LETTER SA;Lo;0;AL;;;;;N;;;;;
+10D10;HANIFI ROHINGYA LETTER SHA;Lo;0;AL;;;;;N;;;;;
+10D11;HANIFI ROHINGYA LETTER KA;Lo;0;AL;;;;;N;;;;;
+10D12;HANIFI ROHINGYA LETTER GA;Lo;0;AL;;;;;N;;;;;
+10D13;HANIFI ROHINGYA LETTER LA;Lo;0;AL;;;;;N;;;;;
+10D14;HANIFI ROHINGYA LETTER MA;Lo;0;AL;;;;;N;;;;;
+10D15;HANIFI ROHINGYA LETTER NA;Lo;0;AL;;;;;N;;;;;
+10D16;HANIFI ROHINGYA LETTER WA;Lo;0;AL;;;;;N;;;;;
+10D17;HANIFI ROHINGYA LETTER KINNA WA;Lo;0;AL;;;;;N;;;;;
+10D18;HANIFI ROHINGYA LETTER YA;Lo;0;AL;;;;;N;;;;;
+10D19;HANIFI ROHINGYA LETTER KINNA YA;Lo;0;AL;;;;;N;;;;;
+10D1A;HANIFI ROHINGYA LETTER NGA;Lo;0;AL;;;;;N;;;;;
+10D1B;HANIFI ROHINGYA LETTER NYA;Lo;0;AL;;;;;N;;;;;
+10D1C;HANIFI ROHINGYA LETTER VA;Lo;0;AL;;;;;N;;;;;
+10D1D;HANIFI ROHINGYA VOWEL A;Lo;0;AL;;;;;N;;;;;
+10D1E;HANIFI ROHINGYA VOWEL I;Lo;0;AL;;;;;N;;;;;
+10D1F;HANIFI ROHINGYA VOWEL U;Lo;0;AL;;;;;N;;;;;
+10D20;HANIFI ROHINGYA VOWEL E;Lo;0;AL;;;;;N;;;;;
+10D21;HANIFI ROHINGYA VOWEL O;Lo;0;AL;;;;;N;;;;;
+10D22;HANIFI ROHINGYA MARK SAKIN;Lo;0;AL;;;;;N;;;;;
+10D23;HANIFI ROHINGYA MARK NA KHONNA;Lo;0;AL;;;;;N;;;;;
+10D24;HANIFI ROHINGYA SIGN HARBAHAY;Mn;230;NSM;;;;;N;;;;;
+10D25;HANIFI ROHINGYA SIGN TAHALA;Mn;230;NSM;;;;;N;;;;;
+10D26;HANIFI ROHINGYA SIGN TANA;Mn;230;NSM;;;;;N;;;;;
+10D27;HANIFI ROHINGYA SIGN TASSI;Mn;230;NSM;;;;;N;;;;;
+10D30;HANIFI ROHINGYA DIGIT ZERO;Nd;0;AN;;0;0;0;N;;;;;
+10D31;HANIFI ROHINGYA DIGIT ONE;Nd;0;AN;;1;1;1;N;;;;;
+10D32;HANIFI ROHINGYA DIGIT TWO;Nd;0;AN;;2;2;2;N;;;;;
+10D33;HANIFI ROHINGYA DIGIT THREE;Nd;0;AN;;3;3;3;N;;;;;
+10D34;HANIFI ROHINGYA DIGIT FOUR;Nd;0;AN;;4;4;4;N;;;;;
+10D35;HANIFI ROHINGYA DIGIT FIVE;Nd;0;AN;;5;5;5;N;;;;;
+10D36;HANIFI ROHINGYA DIGIT SIX;Nd;0;AN;;6;6;6;N;;;;;
+10D37;HANIFI ROHINGYA DIGIT SEVEN;Nd;0;AN;;7;7;7;N;;;;;
+10D38;HANIFI ROHINGYA DIGIT EIGHT;Nd;0;AN;;8;8;8;N;;;;;
+10D39;HANIFI ROHINGYA DIGIT NINE;Nd;0;AN;;9;9;9;N;;;;;
10E60;RUMI DIGIT ONE;No;0;AN;;;1;1;N;;;;;
10E61;RUMI DIGIT TWO;No;0;AN;;;2;2;N;;;;;
10E62;RUMI DIGIT THREE;No;0;AN;;;3;3;N;;;;;
@@ -18819,6 +19023,88 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
10E7C;RUMI FRACTION ONE QUARTER;No;0;AN;;;;1/4;N;;;;;
10E7D;RUMI FRACTION ONE THIRD;No;0;AN;;;;1/3;N;;;;;
10E7E;RUMI FRACTION TWO THIRDS;No;0;AN;;;;2/3;N;;;;;
+10F00;OLD SOGDIAN LETTER ALEPH;Lo;0;R;;;;;N;;;;;
+10F01;OLD SOGDIAN LETTER FINAL ALEPH;Lo;0;R;;;;;N;;;;;
+10F02;OLD SOGDIAN LETTER BETH;Lo;0;R;;;;;N;;;;;
+10F03;OLD SOGDIAN LETTER FINAL BETH;Lo;0;R;;;;;N;;;;;
+10F04;OLD SOGDIAN LETTER GIMEL;Lo;0;R;;;;;N;;;;;
+10F05;OLD SOGDIAN LETTER HE;Lo;0;R;;;;;N;;;;;
+10F06;OLD SOGDIAN LETTER FINAL HE;Lo;0;R;;;;;N;;;;;
+10F07;OLD SOGDIAN LETTER WAW;Lo;0;R;;;;;N;;;;;
+10F08;OLD SOGDIAN LETTER ZAYIN;Lo;0;R;;;;;N;;;;;
+10F09;OLD SOGDIAN LETTER HETH;Lo;0;R;;;;;N;;;;;
+10F0A;OLD SOGDIAN LETTER YODH;Lo;0;R;;;;;N;;;;;
+10F0B;OLD SOGDIAN LETTER KAPH;Lo;0;R;;;;;N;;;;;
+10F0C;OLD SOGDIAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;;
+10F0D;OLD SOGDIAN LETTER MEM;Lo;0;R;;;;;N;;;;;
+10F0E;OLD SOGDIAN LETTER NUN;Lo;0;R;;;;;N;;;;;
+10F0F;OLD SOGDIAN LETTER FINAL NUN;Lo;0;R;;;;;N;;;;;
+10F10;OLD SOGDIAN LETTER FINAL NUN WITH VERTICAL TAIL;Lo;0;R;;;;;N;;;;;
+10F11;OLD SOGDIAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;;
+10F12;OLD SOGDIAN LETTER AYIN;Lo;0;R;;;;;N;;;;;
+10F13;OLD SOGDIAN LETTER ALTERNATE AYIN;Lo;0;R;;;;;N;;;;;
+10F14;OLD SOGDIAN LETTER PE;Lo;0;R;;;;;N;;;;;
+10F15;OLD SOGDIAN LETTER SADHE;Lo;0;R;;;;;N;;;;;
+10F16;OLD SOGDIAN LETTER FINAL SADHE;Lo;0;R;;;;;N;;;;;
+10F17;OLD SOGDIAN LETTER FINAL SADHE WITH VERTICAL TAIL;Lo;0;R;;;;;N;;;;;
+10F18;OLD SOGDIAN LETTER RESH-AYIN-DALETH;Lo;0;R;;;;;N;;;;;
+10F19;OLD SOGDIAN LETTER SHIN;Lo;0;R;;;;;N;;;;;
+10F1A;OLD SOGDIAN LETTER TAW;Lo;0;R;;;;;N;;;;;
+10F1B;OLD SOGDIAN LETTER FINAL TAW;Lo;0;R;;;;;N;;;;;
+10F1C;OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL;Lo;0;R;;;;;N;;;;;
+10F1D;OLD SOGDIAN NUMBER ONE;No;0;R;;;;1;N;;;;;
+10F1E;OLD SOGDIAN NUMBER TWO;No;0;R;;;;2;N;;;;;
+10F1F;OLD SOGDIAN NUMBER THREE;No;0;R;;;;3;N;;;;;
+10F20;OLD SOGDIAN NUMBER FOUR;No;0;R;;;;4;N;;;;;
+10F21;OLD SOGDIAN NUMBER FIVE;No;0;R;;;;5;N;;;;;
+10F22;OLD SOGDIAN NUMBER TEN;No;0;R;;;;10;N;;;;;
+10F23;OLD SOGDIAN NUMBER TWENTY;No;0;R;;;;20;N;;;;;
+10F24;OLD SOGDIAN NUMBER THIRTY;No;0;R;;;;30;N;;;;;
+10F25;OLD SOGDIAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;
+10F26;OLD SOGDIAN FRACTION ONE HALF;No;0;R;;;;1/2;N;;;;;
+10F27;OLD SOGDIAN LIGATURE AYIN-DALETH;Lo;0;R;;;;;N;;;;;
+10F30;SOGDIAN LETTER ALEPH;Lo;0;AL;;;;;N;;;;;
+10F31;SOGDIAN LETTER BETH;Lo;0;AL;;;;;N;;;;;
+10F32;SOGDIAN LETTER GIMEL;Lo;0;AL;;;;;N;;;;;
+10F33;SOGDIAN LETTER HE;Lo;0;AL;;;;;N;;;;;
+10F34;SOGDIAN LETTER WAW;Lo;0;AL;;;;;N;;;;;
+10F35;SOGDIAN LETTER ZAYIN;Lo;0;AL;;;;;N;;;;;
+10F36;SOGDIAN LETTER HETH;Lo;0;AL;;;;;N;;;;;
+10F37;SOGDIAN LETTER YODH;Lo;0;AL;;;;;N;;;;;
+10F38;SOGDIAN LETTER KAPH;Lo;0;AL;;;;;N;;;;;
+10F39;SOGDIAN LETTER LAMEDH;Lo;0;AL;;;;;N;;;;;
+10F3A;SOGDIAN LETTER MEM;Lo;0;AL;;;;;N;;;;;
+10F3B;SOGDIAN LETTER NUN;Lo;0;AL;;;;;N;;;;;
+10F3C;SOGDIAN LETTER SAMEKH;Lo;0;AL;;;;;N;;;;;
+10F3D;SOGDIAN LETTER AYIN;Lo;0;AL;;;;;N;;;;;
+10F3E;SOGDIAN LETTER PE;Lo;0;AL;;;;;N;;;;;
+10F3F;SOGDIAN LETTER SADHE;Lo;0;AL;;;;;N;;;;;
+10F40;SOGDIAN LETTER RESH-AYIN;Lo;0;AL;;;;;N;;;;;
+10F41;SOGDIAN LETTER SHIN;Lo;0;AL;;;;;N;;;;;
+10F42;SOGDIAN LETTER TAW;Lo;0;AL;;;;;N;;;;;
+10F43;SOGDIAN LETTER FETH;Lo;0;AL;;;;;N;;;;;
+10F44;SOGDIAN LETTER LESH;Lo;0;AL;;;;;N;;;;;
+10F45;SOGDIAN INDEPENDENT SHIN;Lo;0;AL;;;;;N;;;;;
+10F46;SOGDIAN COMBINING DOT BELOW;Mn;220;NSM;;;;;N;;;;;
+10F47;SOGDIAN COMBINING TWO DOTS BELOW;Mn;220;NSM;;;;;N;;;;;
+10F48;SOGDIAN COMBINING DOT ABOVE;Mn;230;NSM;;;;;N;;;;;
+10F49;SOGDIAN COMBINING TWO DOTS ABOVE;Mn;230;NSM;;;;;N;;;;;
+10F4A;SOGDIAN COMBINING CURVE ABOVE;Mn;230;NSM;;;;;N;;;;;
+10F4B;SOGDIAN COMBINING CURVE BELOW;Mn;220;NSM;;;;;N;;;;;
+10F4C;SOGDIAN COMBINING HOOK ABOVE;Mn;230;NSM;;;;;N;;;;;
+10F4D;SOGDIAN COMBINING HOOK BELOW;Mn;220;NSM;;;;;N;;;;;
+10F4E;SOGDIAN COMBINING LONG HOOK BELOW;Mn;220;NSM;;;;;N;;;;;
+10F4F;SOGDIAN COMBINING RESH BELOW;Mn;220;NSM;;;;;N;;;;;
+10F50;SOGDIAN COMBINING STROKE BELOW;Mn;220;NSM;;;;;N;;;;;
+10F51;SOGDIAN NUMBER ONE;No;0;AL;;;;1;N;;;;;
+10F52;SOGDIAN NUMBER TEN;No;0;AL;;;;10;N;;;;;
+10F53;SOGDIAN NUMBER TWENTY;No;0;AL;;;;20;N;;;;;
+10F54;SOGDIAN NUMBER ONE HUNDRED;No;0;AL;;;;100;N;;;;;
+10F55;SOGDIAN PUNCTUATION TWO VERTICAL BARS;Po;0;AL;;;;;N;;;;;
+10F56;SOGDIAN PUNCTUATION TWO VERTICAL BARS WITH DOTS;Po;0;AL;;;;;N;;;;;
+10F57;SOGDIAN PUNCTUATION CIRCLE WITH DOT;Po;0;AL;;;;;N;;;;;
+10F58;SOGDIAN PUNCTUATION TWO CIRCLES WITH DOTS;Po;0;AL;;;;;N;;;;;
+10F59;SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT;Po;0;AL;;;;;N;;;;;
11000;BRAHMI SIGN CANDRABINDU;Mc;0;L;;;;;N;;;;;
11001;BRAHMI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
11002;BRAHMI SIGN VISARGA;Mc;0;L;;;;;N;;;;;
@@ -18994,6 +19280,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
110BF;KAITHI DOUBLE SECTION MARK;Po;0;L;;;;;N;;;;;
110C0;KAITHI DANDA;Po;0;L;;;;;N;;;;;
110C1;KAITHI DOUBLE DANDA;Po;0;L;;;;;N;;;;;
+110CD;KAITHI NUMBER SIGN ABOVE;Cf;0;L;;;;;N;;;;;
110D0;SORA SOMPENG LETTER SAH;Lo;0;L;;;;;N;;;;;
110D1;SORA SOMPENG LETTER TAH;Lo;0;L;;;;;N;;;;;
110D2;SORA SOMPENG LETTER BAH;Lo;0;L;;;;;N;;;;;
@@ -19096,6 +19383,9 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
11141;CHAKMA DANDA;Po;0;L;;;;;N;;;;;
11142;CHAKMA DOUBLE DANDA;Po;0;L;;;;;N;;;;;
11143;CHAKMA QUESTION MARK;Po;0;L;;;;;N;;;;;
+11144;CHAKMA LETTER LHAA;Lo;0;L;;;;;N;;;;;
+11145;CHAKMA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+11146;CHAKMA VOWEL SIGN EI;Mc;0;L;;;;;N;;;;;
11150;MAHAJANI LETTER A;Lo;0;L;;;;;N;;;;;
11151;MAHAJANI LETTER I;Lo;0;L;;;;;N;;;;;
11152;MAHAJANI LETTER U;Lo;0;L;;;;;N;;;;;
@@ -19208,7 +19498,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
111C6;SHARADA DOUBLE DANDA;Po;0;L;;;;;N;;;;;
111C7;SHARADA ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;
111C8;SHARADA SEPARATOR;Po;0;L;;;;;N;;;;;
-111C9;SHARADA SANDHI MARK;Po;0;L;;;;;N;;;;;
+111C9;SHARADA SANDHI MARK;Mn;0;NSM;;;;;N;;;;;
111CA;SHARADA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
111CB;SHARADA VOWEL MODIFIER MARK;Mn;0;NSM;;;;;N;;;;;
111CC;SHARADA EXTRA SHORT VOWEL MARK;Mn;0;NSM;;;;;N;;;;;
@@ -19468,6 +19758,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
11337;GRANTHA LETTER SSA;Lo;0;L;;;;;N;;;;;
11338;GRANTHA LETTER SA;Lo;0;L;;;;;N;;;;;
11339;GRANTHA LETTER HA;Lo;0;L;;;;;N;;;;;
+1133B;COMBINING BINDU BELOW;Mn;7;NSM;;;;;N;;;;;
1133C;GRANTHA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
1133D;GRANTHA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;
1133E;GRANTHA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
@@ -19595,6 +19886,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
11459;NEWA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
1145B;NEWA PLACEHOLDER MARK;Po;0;L;;;;;N;;;;;
1145D;NEWA INSERTION SIGN;Po;0;L;;;;;N;;;;;
+1145E;NEWA SANDHI MARK;Mn;230;NSM;;;;;N;;;;;
11480;TIRHUTA ANJI;Lo;0;L;;;;;N;;;;;
11481;TIRHUTA LETTER A;Lo;0;L;;;;;N;;;;;
11482;TIRHUTA LETTER AA;Lo;0;L;;;;;N;;;;;
@@ -19953,6 +20245,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
11717;AHOM LETTER GHA;Lo;0;L;;;;;N;;;;;
11718;AHOM LETTER BHA;Lo;0;L;;;;;N;;;;;
11719;AHOM LETTER JHA;Lo;0;L;;;;;N;;;;;
+1171A;AHOM LETTER ALTERNATE BA;Lo;0;L;;;;;N;;;;;
1171D;AHOM CONSONANT SIGN MEDIAL LA;Mn;0;NSM;;;;;N;;;;;
1171E;AHOM CONSONANT SIGN MEDIAL RA;Mn;0;NSM;;;;;N;;;;;
1171F;AHOM CONSONANT SIGN MEDIAL LIGATING RA;Mn;0;NSM;;;;;N;;;;;
@@ -19984,6 +20277,66 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1173D;AHOM SIGN SECTION;Po;0;L;;;;;N;;;;;
1173E;AHOM SIGN RULAI;Po;0;L;;;;;N;;;;;
1173F;AHOM SYMBOL VI;So;0;L;;;;;N;;;;;
+11800;DOGRA LETTER A;Lo;0;L;;;;;N;;;;;
+11801;DOGRA LETTER AA;Lo;0;L;;;;;N;;;;;
+11802;DOGRA LETTER I;Lo;0;L;;;;;N;;;;;
+11803;DOGRA LETTER II;Lo;0;L;;;;;N;;;;;
+11804;DOGRA LETTER U;Lo;0;L;;;;;N;;;;;
+11805;DOGRA LETTER UU;Lo;0;L;;;;;N;;;;;
+11806;DOGRA LETTER E;Lo;0;L;;;;;N;;;;;
+11807;DOGRA LETTER AI;Lo;0;L;;;;;N;;;;;
+11808;DOGRA LETTER O;Lo;0;L;;;;;N;;;;;
+11809;DOGRA LETTER AU;Lo;0;L;;;;;N;;;;;
+1180A;DOGRA LETTER KA;Lo;0;L;;;;;N;;;;;
+1180B;DOGRA LETTER KHA;Lo;0;L;;;;;N;;;;;
+1180C;DOGRA LETTER GA;Lo;0;L;;;;;N;;;;;
+1180D;DOGRA LETTER GHA;Lo;0;L;;;;;N;;;;;
+1180E;DOGRA LETTER NGA;Lo;0;L;;;;;N;;;;;
+1180F;DOGRA LETTER CA;Lo;0;L;;;;;N;;;;;
+11810;DOGRA LETTER CHA;Lo;0;L;;;;;N;;;;;
+11811;DOGRA LETTER JA;Lo;0;L;;;;;N;;;;;
+11812;DOGRA LETTER JHA;Lo;0;L;;;;;N;;;;;
+11813;DOGRA LETTER NYA;Lo;0;L;;;;;N;;;;;
+11814;DOGRA LETTER TTA;Lo;0;L;;;;;N;;;;;
+11815;DOGRA LETTER TTHA;Lo;0;L;;;;;N;;;;;
+11816;DOGRA LETTER DDA;Lo;0;L;;;;;N;;;;;
+11817;DOGRA LETTER DDHA;Lo;0;L;;;;;N;;;;;
+11818;DOGRA LETTER NNA;Lo;0;L;;;;;N;;;;;
+11819;DOGRA LETTER TA;Lo;0;L;;;;;N;;;;;
+1181A;DOGRA LETTER THA;Lo;0;L;;;;;N;;;;;
+1181B;DOGRA LETTER DA;Lo;0;L;;;;;N;;;;;
+1181C;DOGRA LETTER DHA;Lo;0;L;;;;;N;;;;;
+1181D;DOGRA LETTER NA;Lo;0;L;;;;;N;;;;;
+1181E;DOGRA LETTER PA;Lo;0;L;;;;;N;;;;;
+1181F;DOGRA LETTER PHA;Lo;0;L;;;;;N;;;;;
+11820;DOGRA LETTER BA;Lo;0;L;;;;;N;;;;;
+11821;DOGRA LETTER BHA;Lo;0;L;;;;;N;;;;;
+11822;DOGRA LETTER MA;Lo;0;L;;;;;N;;;;;
+11823;DOGRA LETTER YA;Lo;0;L;;;;;N;;;;;
+11824;DOGRA LETTER RA;Lo;0;L;;;;;N;;;;;
+11825;DOGRA LETTER LA;Lo;0;L;;;;;N;;;;;
+11826;DOGRA LETTER VA;Lo;0;L;;;;;N;;;;;
+11827;DOGRA LETTER SHA;Lo;0;L;;;;;N;;;;;
+11828;DOGRA LETTER SSA;Lo;0;L;;;;;N;;;;;
+11829;DOGRA LETTER SA;Lo;0;L;;;;;N;;;;;
+1182A;DOGRA LETTER HA;Lo;0;L;;;;;N;;;;;
+1182B;DOGRA LETTER RRA;Lo;0;L;;;;;N;;;;;
+1182C;DOGRA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+1182D;DOGRA VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+1182E;DOGRA VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+1182F;DOGRA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+11830;DOGRA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+11831;DOGRA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+11832;DOGRA VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;
+11833;DOGRA VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+11834;DOGRA VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+11835;DOGRA VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;
+11836;DOGRA VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;
+11837;DOGRA SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+11838;DOGRA SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+11839;DOGRA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+1183A;DOGRA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+1183B;DOGRA ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;
118A0;WARANG CITI CAPITAL LETTER NGAA;Lu;0;L;;;;;N;;;;118C0;
118A1;WARANG CITI CAPITAL LETTER A;Lu;0;L;;;;;N;;;;118C1;
118A2;WARANG CITI CAPITAL LETTER WI;Lu;0;L;;;;;N;;;;118C2;
@@ -20068,6 +20421,159 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
118F1;WARANG CITI NUMBER EIGHTY;No;0;L;;;;80;N;;;;;
118F2;WARANG CITI NUMBER NINETY;No;0;L;;;;90;N;;;;;
118FF;WARANG CITI OM;Lo;0;L;;;;;N;;;;;
+11A00;ZANABAZAR SQUARE LETTER A;Lo;0;L;;;;;N;;;;;
+11A01;ZANABAZAR SQUARE VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+11A02;ZANABAZAR SQUARE VOWEL SIGN UE;Mn;0;NSM;;;;;N;;;;;
+11A03;ZANABAZAR SQUARE VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+11A04;ZANABAZAR SQUARE VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+11A05;ZANABAZAR SQUARE VOWEL SIGN OE;Mn;0;NSM;;;;;N;;;;;
+11A06;ZANABAZAR SQUARE VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;
+11A07;ZANABAZAR SQUARE VOWEL SIGN AI;Mn;0;L;;;;;N;;;;;
+11A08;ZANABAZAR SQUARE VOWEL SIGN AU;Mn;0;L;;;;;N;;;;;
+11A09;ZANABAZAR SQUARE VOWEL SIGN REVERSED I;Mn;0;NSM;;;;;N;;;;;
+11A0A;ZANABAZAR SQUARE VOWEL LENGTH MARK;Mn;0;NSM;;;;;N;;;;;
+11A0B;ZANABAZAR SQUARE LETTER KA;Lo;0;L;;;;;N;;;;;
+11A0C;ZANABAZAR SQUARE LETTER KHA;Lo;0;L;;;;;N;;;;;
+11A0D;ZANABAZAR SQUARE LETTER GA;Lo;0;L;;;;;N;;;;;
+11A0E;ZANABAZAR SQUARE LETTER GHA;Lo;0;L;;;;;N;;;;;
+11A0F;ZANABAZAR SQUARE LETTER NGA;Lo;0;L;;;;;N;;;;;
+11A10;ZANABAZAR SQUARE LETTER CA;Lo;0;L;;;;;N;;;;;
+11A11;ZANABAZAR SQUARE LETTER CHA;Lo;0;L;;;;;N;;;;;
+11A12;ZANABAZAR SQUARE LETTER JA;Lo;0;L;;;;;N;;;;;
+11A13;ZANABAZAR SQUARE LETTER NYA;Lo;0;L;;;;;N;;;;;
+11A14;ZANABAZAR SQUARE LETTER TTA;Lo;0;L;;;;;N;;;;;
+11A15;ZANABAZAR SQUARE LETTER TTHA;Lo;0;L;;;;;N;;;;;
+11A16;ZANABAZAR SQUARE LETTER DDA;Lo;0;L;;;;;N;;;;;
+11A17;ZANABAZAR SQUARE LETTER DDHA;Lo;0;L;;;;;N;;;;;
+11A18;ZANABAZAR SQUARE LETTER NNA;Lo;0;L;;;;;N;;;;;
+11A19;ZANABAZAR SQUARE LETTER TA;Lo;0;L;;;;;N;;;;;
+11A1A;ZANABAZAR SQUARE LETTER THA;Lo;0;L;;;;;N;;;;;
+11A1B;ZANABAZAR SQUARE LETTER DA;Lo;0;L;;;;;N;;;;;
+11A1C;ZANABAZAR SQUARE LETTER DHA;Lo;0;L;;;;;N;;;;;
+11A1D;ZANABAZAR SQUARE LETTER NA;Lo;0;L;;;;;N;;;;;
+11A1E;ZANABAZAR SQUARE LETTER PA;Lo;0;L;;;;;N;;;;;
+11A1F;ZANABAZAR SQUARE LETTER PHA;Lo;0;L;;;;;N;;;;;
+11A20;ZANABAZAR SQUARE LETTER BA;Lo;0;L;;;;;N;;;;;
+11A21;ZANABAZAR SQUARE LETTER BHA;Lo;0;L;;;;;N;;;;;
+11A22;ZANABAZAR SQUARE LETTER MA;Lo;0;L;;;;;N;;;;;
+11A23;ZANABAZAR SQUARE LETTER TSA;Lo;0;L;;;;;N;;;;;
+11A24;ZANABAZAR SQUARE LETTER TSHA;Lo;0;L;;;;;N;;;;;
+11A25;ZANABAZAR SQUARE LETTER DZA;Lo;0;L;;;;;N;;;;;
+11A26;ZANABAZAR SQUARE LETTER DZHA;Lo;0;L;;;;;N;;;;;
+11A27;ZANABAZAR SQUARE LETTER ZHA;Lo;0;L;;;;;N;;;;;
+11A28;ZANABAZAR SQUARE LETTER ZA;Lo;0;L;;;;;N;;;;;
+11A29;ZANABAZAR SQUARE LETTER -A;Lo;0;L;;;;;N;;;;;
+11A2A;ZANABAZAR SQUARE LETTER YA;Lo;0;L;;;;;N;;;;;
+11A2B;ZANABAZAR SQUARE LETTER RA;Lo;0;L;;;;;N;;;;;
+11A2C;ZANABAZAR SQUARE LETTER LA;Lo;0;L;;;;;N;;;;;
+11A2D;ZANABAZAR SQUARE LETTER VA;Lo;0;L;;;;;N;;;;;
+11A2E;ZANABAZAR SQUARE LETTER SHA;Lo;0;L;;;;;N;;;;;
+11A2F;ZANABAZAR SQUARE LETTER SSA;Lo;0;L;;;;;N;;;;;
+11A30;ZANABAZAR SQUARE LETTER SA;Lo;0;L;;;;;N;;;;;
+11A31;ZANABAZAR SQUARE LETTER HA;Lo;0;L;;;;;N;;;;;
+11A32;ZANABAZAR SQUARE LETTER KSSA;Lo;0;L;;;;;N;;;;;
+11A33;ZANABAZAR SQUARE FINAL CONSONANT MARK;Mn;0;NSM;;;;;N;;;;;
+11A34;ZANABAZAR SQUARE SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+11A35;ZANABAZAR SQUARE SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+11A36;ZANABAZAR SQUARE SIGN CANDRABINDU WITH ORNAMENT;Mn;0;NSM;;;;;N;;;;;
+11A37;ZANABAZAR SQUARE SIGN CANDRA WITH ORNAMENT;Mn;0;NSM;;;;;N;;;;;
+11A38;ZANABAZAR SQUARE SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+11A39;ZANABAZAR SQUARE SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+11A3A;ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA;Lo;0;L;;;;;N;;;;;
+11A3B;ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA;Mn;0;NSM;;;;;N;;;;;
+11A3C;ZANABAZAR SQUARE CLUSTER-FINAL LETTER RA;Mn;0;NSM;;;;;N;;;;;
+11A3D;ZANABAZAR SQUARE CLUSTER-FINAL LETTER LA;Mn;0;NSM;;;;;N;;;;;
+11A3E;ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA;Mn;0;NSM;;;;;N;;;;;
+11A3F;ZANABAZAR SQUARE INITIAL HEAD MARK;Po;0;L;;;;;N;;;;;
+11A40;ZANABAZAR SQUARE CLOSING HEAD MARK;Po;0;L;;;;;N;;;;;
+11A41;ZANABAZAR SQUARE MARK TSHEG;Po;0;L;;;;;N;;;;;
+11A42;ZANABAZAR SQUARE MARK SHAD;Po;0;L;;;;;N;;;;;
+11A43;ZANABAZAR SQUARE MARK DOUBLE SHAD;Po;0;L;;;;;N;;;;;
+11A44;ZANABAZAR SQUARE MARK LONG TSHEG;Po;0;L;;;;;N;;;;;
+11A45;ZANABAZAR SQUARE INITIAL DOUBLE-LINED HEAD MARK;Po;0;L;;;;;N;;;;;
+11A46;ZANABAZAR SQUARE CLOSING DOUBLE-LINED HEAD MARK;Po;0;L;;;;;N;;;;;
+11A47;ZANABAZAR SQUARE SUBJOINER;Mn;9;NSM;;;;;N;;;;;
+11A50;SOYOMBO LETTER A;Lo;0;L;;;;;N;;;;;
+11A51;SOYOMBO VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+11A52;SOYOMBO VOWEL SIGN UE;Mn;0;NSM;;;;;N;;;;;
+11A53;SOYOMBO VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+11A54;SOYOMBO VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+11A55;SOYOMBO VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;
+11A56;SOYOMBO VOWEL SIGN OE;Mn;0;NSM;;;;;N;;;;;
+11A57;SOYOMBO VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;
+11A58;SOYOMBO VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;
+11A59;SOYOMBO VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+11A5A;SOYOMBO VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;
+11A5B;SOYOMBO VOWEL LENGTH MARK;Mn;0;NSM;;;;;N;;;;;
+11A5C;SOYOMBO LETTER KA;Lo;0;L;;;;;N;;;;;
+11A5D;SOYOMBO LETTER KHA;Lo;0;L;;;;;N;;;;;
+11A5E;SOYOMBO LETTER GA;Lo;0;L;;;;;N;;;;;
+11A5F;SOYOMBO LETTER GHA;Lo;0;L;;;;;N;;;;;
+11A60;SOYOMBO LETTER NGA;Lo;0;L;;;;;N;;;;;
+11A61;SOYOMBO LETTER CA;Lo;0;L;;;;;N;;;;;
+11A62;SOYOMBO LETTER CHA;Lo;0;L;;;;;N;;;;;
+11A63;SOYOMBO LETTER JA;Lo;0;L;;;;;N;;;;;
+11A64;SOYOMBO LETTER JHA;Lo;0;L;;;;;N;;;;;
+11A65;SOYOMBO LETTER NYA;Lo;0;L;;;;;N;;;;;
+11A66;SOYOMBO LETTER TTA;Lo;0;L;;;;;N;;;;;
+11A67;SOYOMBO LETTER TTHA;Lo;0;L;;;;;N;;;;;
+11A68;SOYOMBO LETTER DDA;Lo;0;L;;;;;N;;;;;
+11A69;SOYOMBO LETTER DDHA;Lo;0;L;;;;;N;;;;;
+11A6A;SOYOMBO LETTER NNA;Lo;0;L;;;;;N;;;;;
+11A6B;SOYOMBO LETTER TA;Lo;0;L;;;;;N;;;;;
+11A6C;SOYOMBO LETTER THA;Lo;0;L;;;;;N;;;;;
+11A6D;SOYOMBO LETTER DA;Lo;0;L;;;;;N;;;;;
+11A6E;SOYOMBO LETTER DHA;Lo;0;L;;;;;N;;;;;
+11A6F;SOYOMBO LETTER NA;Lo;0;L;;;;;N;;;;;
+11A70;SOYOMBO LETTER PA;Lo;0;L;;;;;N;;;;;
+11A71;SOYOMBO LETTER PHA;Lo;0;L;;;;;N;;;;;
+11A72;SOYOMBO LETTER BA;Lo;0;L;;;;;N;;;;;
+11A73;SOYOMBO LETTER BHA;Lo;0;L;;;;;N;;;;;
+11A74;SOYOMBO LETTER MA;Lo;0;L;;;;;N;;;;;
+11A75;SOYOMBO LETTER TSA;Lo;0;L;;;;;N;;;;;
+11A76;SOYOMBO LETTER TSHA;Lo;0;L;;;;;N;;;;;
+11A77;SOYOMBO LETTER DZA;Lo;0;L;;;;;N;;;;;
+11A78;SOYOMBO LETTER ZHA;Lo;0;L;;;;;N;;;;;
+11A79;SOYOMBO LETTER ZA;Lo;0;L;;;;;N;;;;;
+11A7A;SOYOMBO LETTER -A;Lo;0;L;;;;;N;;;;;
+11A7B;SOYOMBO LETTER YA;Lo;0;L;;;;;N;;;;;
+11A7C;SOYOMBO LETTER RA;Lo;0;L;;;;;N;;;;;
+11A7D;SOYOMBO LETTER LA;Lo;0;L;;;;;N;;;;;
+11A7E;SOYOMBO LETTER VA;Lo;0;L;;;;;N;;;;;
+11A7F;SOYOMBO LETTER SHA;Lo;0;L;;;;;N;;;;;
+11A80;SOYOMBO LETTER SSA;Lo;0;L;;;;;N;;;;;
+11A81;SOYOMBO LETTER SA;Lo;0;L;;;;;N;;;;;
+11A82;SOYOMBO LETTER HA;Lo;0;L;;;;;N;;;;;
+11A83;SOYOMBO LETTER KSSA;Lo;0;L;;;;;N;;;;;
+11A86;SOYOMBO CLUSTER-INITIAL LETTER RA;Lo;0;L;;;;;N;;;;;
+11A87;SOYOMBO CLUSTER-INITIAL LETTER LA;Lo;0;L;;;;;N;;;;;
+11A88;SOYOMBO CLUSTER-INITIAL LETTER SHA;Lo;0;L;;;;;N;;;;;
+11A89;SOYOMBO CLUSTER-INITIAL LETTER SA;Lo;0;L;;;;;N;;;;;
+11A8A;SOYOMBO FINAL CONSONANT SIGN G;Mn;0;NSM;;;;;N;;;;;
+11A8B;SOYOMBO FINAL CONSONANT SIGN K;Mn;0;NSM;;;;;N;;;;;
+11A8C;SOYOMBO FINAL CONSONANT SIGN NG;Mn;0;NSM;;;;;N;;;;;
+11A8D;SOYOMBO FINAL CONSONANT SIGN D;Mn;0;NSM;;;;;N;;;;;
+11A8E;SOYOMBO FINAL CONSONANT SIGN N;Mn;0;NSM;;;;;N;;;;;
+11A8F;SOYOMBO FINAL CONSONANT SIGN B;Mn;0;NSM;;;;;N;;;;;
+11A90;SOYOMBO FINAL CONSONANT SIGN M;Mn;0;NSM;;;;;N;;;;;
+11A91;SOYOMBO FINAL CONSONANT SIGN R;Mn;0;NSM;;;;;N;;;;;
+11A92;SOYOMBO FINAL CONSONANT SIGN L;Mn;0;NSM;;;;;N;;;;;
+11A93;SOYOMBO FINAL CONSONANT SIGN SH;Mn;0;NSM;;;;;N;;;;;
+11A94;SOYOMBO FINAL CONSONANT SIGN S;Mn;0;NSM;;;;;N;;;;;
+11A95;SOYOMBO FINAL CONSONANT SIGN -A;Mn;0;NSM;;;;;N;;;;;
+11A96;SOYOMBO SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+11A97;SOYOMBO SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+11A98;SOYOMBO GEMINATION MARK;Mn;0;NSM;;;;;N;;;;;
+11A99;SOYOMBO SUBJOINER;Mn;9;NSM;;;;;N;;;;;
+11A9A;SOYOMBO MARK TSHEG;Po;0;L;;;;;N;;;;;
+11A9B;SOYOMBO MARK SHAD;Po;0;L;;;;;N;;;;;
+11A9C;SOYOMBO MARK DOUBLE SHAD;Po;0;L;;;;;N;;;;;
+11A9D;SOYOMBO MARK PLUTA;Lo;0;L;;;;;N;;;;;
+11A9E;SOYOMBO HEAD MARK WITH MOON AND SUN AND TRIPLE FLAME;Po;0;L;;;;;N;;;;;
+11A9F;SOYOMBO HEAD MARK WITH MOON AND SUN AND FLAME;Po;0;L;;;;;N;;;;;
+11AA0;SOYOMBO HEAD MARK WITH MOON AND SUN;Po;0;L;;;;;N;;;;;
+11AA1;SOYOMBO TERMINAL MARK-1;Po;0;L;;;;;N;;;;;
+11AA2;SOYOMBO TERMINAL MARK-2;Po;0;L;;;;;N;;;;;
11AC0;PAU CIN HAU LETTER PA;Lo;0;L;;;;;N;;;;;
11AC1;PAU CIN HAU LETTER KA;Lo;0;L;;;;;N;;;;;
11AC2;PAU CIN HAU LETTER LA;Lo;0;L;;;;;N;;;;;
@@ -20290,6 +20796,169 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
11CB4;MARCHEN VOWEL SIGN O;Mc;0;L;;;;;N;;;;;
11CB5;MARCHEN SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
11CB6;MARCHEN SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+11D00;MASARAM GONDI LETTER A;Lo;0;L;;;;;N;;;;;
+11D01;MASARAM GONDI LETTER AA;Lo;0;L;;;;;N;;;;;
+11D02;MASARAM GONDI LETTER I;Lo;0;L;;;;;N;;;;;
+11D03;MASARAM GONDI LETTER II;Lo;0;L;;;;;N;;;;;
+11D04;MASARAM GONDI LETTER U;Lo;0;L;;;;;N;;;;;
+11D05;MASARAM GONDI LETTER UU;Lo;0;L;;;;;N;;;;;
+11D06;MASARAM GONDI LETTER E;Lo;0;L;;;;;N;;;;;
+11D08;MASARAM GONDI LETTER AI;Lo;0;L;;;;;N;;;;;
+11D09;MASARAM GONDI LETTER O;Lo;0;L;;;;;N;;;;;
+11D0B;MASARAM GONDI LETTER AU;Lo;0;L;;;;;N;;;;;
+11D0C;MASARAM GONDI LETTER KA;Lo;0;L;;;;;N;;;;;
+11D0D;MASARAM GONDI LETTER KHA;Lo;0;L;;;;;N;;;;;
+11D0E;MASARAM GONDI LETTER GA;Lo;0;L;;;;;N;;;;;
+11D0F;MASARAM GONDI LETTER GHA;Lo;0;L;;;;;N;;;;;
+11D10;MASARAM GONDI LETTER NGA;Lo;0;L;;;;;N;;;;;
+11D11;MASARAM GONDI LETTER CA;Lo;0;L;;;;;N;;;;;
+11D12;MASARAM GONDI LETTER CHA;Lo;0;L;;;;;N;;;;;
+11D13;MASARAM GONDI LETTER JA;Lo;0;L;;;;;N;;;;;
+11D14;MASARAM GONDI LETTER JHA;Lo;0;L;;;;;N;;;;;
+11D15;MASARAM GONDI LETTER NYA;Lo;0;L;;;;;N;;;;;
+11D16;MASARAM GONDI LETTER TTA;Lo;0;L;;;;;N;;;;;
+11D17;MASARAM GONDI LETTER TTHA;Lo;0;L;;;;;N;;;;;
+11D18;MASARAM GONDI LETTER DDA;Lo;0;L;;;;;N;;;;;
+11D19;MASARAM GONDI LETTER DDHA;Lo;0;L;;;;;N;;;;;
+11D1A;MASARAM GONDI LETTER NNA;Lo;0;L;;;;;N;;;;;
+11D1B;MASARAM GONDI LETTER TA;Lo;0;L;;;;;N;;;;;
+11D1C;MASARAM GONDI LETTER THA;Lo;0;L;;;;;N;;;;;
+11D1D;MASARAM GONDI LETTER DA;Lo;0;L;;;;;N;;;;;
+11D1E;MASARAM GONDI LETTER DHA;Lo;0;L;;;;;N;;;;;
+11D1F;MASARAM GONDI LETTER NA;Lo;0;L;;;;;N;;;;;
+11D20;MASARAM GONDI LETTER PA;Lo;0;L;;;;;N;;;;;
+11D21;MASARAM GONDI LETTER PHA;Lo;0;L;;;;;N;;;;;
+11D22;MASARAM GONDI LETTER BA;Lo;0;L;;;;;N;;;;;
+11D23;MASARAM GONDI LETTER BHA;Lo;0;L;;;;;N;;;;;
+11D24;MASARAM GONDI LETTER MA;Lo;0;L;;;;;N;;;;;
+11D25;MASARAM GONDI LETTER YA;Lo;0;L;;;;;N;;;;;
+11D26;MASARAM GONDI LETTER RA;Lo;0;L;;;;;N;;;;;
+11D27;MASARAM GONDI LETTER LA;Lo;0;L;;;;;N;;;;;
+11D28;MASARAM GONDI LETTER VA;Lo;0;L;;;;;N;;;;;
+11D29;MASARAM GONDI LETTER SHA;Lo;0;L;;;;;N;;;;;
+11D2A;MASARAM GONDI LETTER SSA;Lo;0;L;;;;;N;;;;;
+11D2B;MASARAM GONDI LETTER SA;Lo;0;L;;;;;N;;;;;
+11D2C;MASARAM GONDI LETTER HA;Lo;0;L;;;;;N;;;;;
+11D2D;MASARAM GONDI LETTER LLA;Lo;0;L;;;;;N;;;;;
+11D2E;MASARAM GONDI LETTER KSSA;Lo;0;L;;;;;N;;;;;
+11D2F;MASARAM GONDI LETTER JNYA;Lo;0;L;;;;;N;;;;;
+11D30;MASARAM GONDI LETTER TRA;Lo;0;L;;;;;N;;;;;
+11D31;MASARAM GONDI VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;;
+11D32;MASARAM GONDI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+11D33;MASARAM GONDI VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;
+11D34;MASARAM GONDI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+11D35;MASARAM GONDI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+11D36;MASARAM GONDI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+11D3A;MASARAM GONDI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+11D3C;MASARAM GONDI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+11D3D;MASARAM GONDI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;
+11D3F;MASARAM GONDI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;
+11D40;MASARAM GONDI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+11D41;MASARAM GONDI SIGN VISARGA;Mn;0;NSM;;;;;N;;;;;
+11D42;MASARAM GONDI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+11D43;MASARAM GONDI SIGN CANDRA;Mn;0;NSM;;;;;N;;;;;
+11D44;MASARAM GONDI SIGN HALANTA;Mn;9;NSM;;;;;N;;;;;
+11D45;MASARAM GONDI VIRAMA;Mn;9;NSM;;;;;N;;;;;
+11D46;MASARAM GONDI REPHA;Lo;0;L;;;;;N;;;;;
+11D47;MASARAM GONDI RA-KARA;Mn;0;NSM;;;;;N;;;;;
+11D50;MASARAM GONDI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+11D51;MASARAM GONDI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+11D52;MASARAM GONDI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+11D53;MASARAM GONDI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+11D54;MASARAM GONDI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+11D55;MASARAM GONDI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+11D56;MASARAM GONDI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+11D57;MASARAM GONDI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+11D58;MASARAM GONDI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+11D59;MASARAM GONDI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+11D60;GUNJALA GONDI LETTER A;Lo;0;L;;;;;N;;;;;
+11D61;GUNJALA GONDI LETTER AA;Lo;0;L;;;;;N;;;;;
+11D62;GUNJALA GONDI LETTER I;Lo;0;L;;;;;N;;;;;
+11D63;GUNJALA GONDI LETTER II;Lo;0;L;;;;;N;;;;;
+11D64;GUNJALA GONDI LETTER U;Lo;0;L;;;;;N;;;;;
+11D65;GUNJALA GONDI LETTER UU;Lo;0;L;;;;;N;;;;;
+11D67;GUNJALA GONDI LETTER EE;Lo;0;L;;;;;N;;;;;
+11D68;GUNJALA GONDI LETTER AI;Lo;0;L;;;;;N;;;;;
+11D6A;GUNJALA GONDI LETTER OO;Lo;0;L;;;;;N;;;;;
+11D6B;GUNJALA GONDI LETTER AU;Lo;0;L;;;;;N;;;;;
+11D6C;GUNJALA GONDI LETTER YA;Lo;0;L;;;;;N;;;;;
+11D6D;GUNJALA GONDI LETTER VA;Lo;0;L;;;;;N;;;;;
+11D6E;GUNJALA GONDI LETTER BA;Lo;0;L;;;;;N;;;;;
+11D6F;GUNJALA GONDI LETTER BHA;Lo;0;L;;;;;N;;;;;
+11D70;GUNJALA GONDI LETTER MA;Lo;0;L;;;;;N;;;;;
+11D71;GUNJALA GONDI LETTER KA;Lo;0;L;;;;;N;;;;;
+11D72;GUNJALA GONDI LETTER KHA;Lo;0;L;;;;;N;;;;;
+11D73;GUNJALA GONDI LETTER TA;Lo;0;L;;;;;N;;;;;
+11D74;GUNJALA GONDI LETTER THA;Lo;0;L;;;;;N;;;;;
+11D75;GUNJALA GONDI LETTER LA;Lo;0;L;;;;;N;;;;;
+11D76;GUNJALA GONDI LETTER GA;Lo;0;L;;;;;N;;;;;
+11D77;GUNJALA GONDI LETTER GHA;Lo;0;L;;;;;N;;;;;
+11D78;GUNJALA GONDI LETTER DA;Lo;0;L;;;;;N;;;;;
+11D79;GUNJALA GONDI LETTER DHA;Lo;0;L;;;;;N;;;;;
+11D7A;GUNJALA GONDI LETTER NA;Lo;0;L;;;;;N;;;;;
+11D7B;GUNJALA GONDI LETTER CA;Lo;0;L;;;;;N;;;;;
+11D7C;GUNJALA GONDI LETTER CHA;Lo;0;L;;;;;N;;;;;
+11D7D;GUNJALA GONDI LETTER TTA;Lo;0;L;;;;;N;;;;;
+11D7E;GUNJALA GONDI LETTER TTHA;Lo;0;L;;;;;N;;;;;
+11D7F;GUNJALA GONDI LETTER LLA;Lo;0;L;;;;;N;;;;;
+11D80;GUNJALA GONDI LETTER JA;Lo;0;L;;;;;N;;;;;
+11D81;GUNJALA GONDI LETTER JHA;Lo;0;L;;;;;N;;;;;
+11D82;GUNJALA GONDI LETTER DDA;Lo;0;L;;;;;N;;;;;
+11D83;GUNJALA GONDI LETTER DDHA;Lo;0;L;;;;;N;;;;;
+11D84;GUNJALA GONDI LETTER NGA;Lo;0;L;;;;;N;;;;;
+11D85;GUNJALA GONDI LETTER PA;Lo;0;L;;;;;N;;;;;
+11D86;GUNJALA GONDI LETTER PHA;Lo;0;L;;;;;N;;;;;
+11D87;GUNJALA GONDI LETTER HA;Lo;0;L;;;;;N;;;;;
+11D88;GUNJALA GONDI LETTER RA;Lo;0;L;;;;;N;;;;;
+11D89;GUNJALA GONDI LETTER SA;Lo;0;L;;;;;N;;;;;
+11D8A;GUNJALA GONDI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+11D8B;GUNJALA GONDI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+11D8C;GUNJALA GONDI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+11D8D;GUNJALA GONDI VOWEL SIGN U;Mc;0;L;;;;;N;;;;;
+11D8E;GUNJALA GONDI VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;
+11D90;GUNJALA GONDI VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;;
+11D91;GUNJALA GONDI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+11D93;GUNJALA GONDI VOWEL SIGN OO;Mc;0;L;;;;;N;;;;;
+11D94;GUNJALA GONDI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;
+11D95;GUNJALA GONDI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+11D96;GUNJALA GONDI SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+11D97;GUNJALA GONDI VIRAMA;Mn;9;NSM;;;;;N;;;;;
+11D98;GUNJALA GONDI OM;Lo;0;L;;;;;N;;;;;
+11DA0;GUNJALA GONDI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+11DA1;GUNJALA GONDI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+11DA2;GUNJALA GONDI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+11DA3;GUNJALA GONDI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+11DA4;GUNJALA GONDI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+11DA5;GUNJALA GONDI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+11DA6;GUNJALA GONDI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+11DA7;GUNJALA GONDI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+11DA8;GUNJALA GONDI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+11DA9;GUNJALA GONDI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+11EE0;MAKASAR LETTER KA;Lo;0;L;;;;;N;;;;;
+11EE1;MAKASAR LETTER GA;Lo;0;L;;;;;N;;;;;
+11EE2;MAKASAR LETTER NGA;Lo;0;L;;;;;N;;;;;
+11EE3;MAKASAR LETTER PA;Lo;0;L;;;;;N;;;;;
+11EE4;MAKASAR LETTER BA;Lo;0;L;;;;;N;;;;;
+11EE5;MAKASAR LETTER MA;Lo;0;L;;;;;N;;;;;
+11EE6;MAKASAR LETTER TA;Lo;0;L;;;;;N;;;;;
+11EE7;MAKASAR LETTER DA;Lo;0;L;;;;;N;;;;;
+11EE8;MAKASAR LETTER NA;Lo;0;L;;;;;N;;;;;
+11EE9;MAKASAR LETTER CA;Lo;0;L;;;;;N;;;;;
+11EEA;MAKASAR LETTER JA;Lo;0;L;;;;;N;;;;;
+11EEB;MAKASAR LETTER NYA;Lo;0;L;;;;;N;;;;;
+11EEC;MAKASAR LETTER YA;Lo;0;L;;;;;N;;;;;
+11EED;MAKASAR LETTER RA;Lo;0;L;;;;;N;;;;;
+11EEE;MAKASAR LETTER LA;Lo;0;L;;;;;N;;;;;
+11EEF;MAKASAR LETTER VA;Lo;0;L;;;;;N;;;;;
+11EF0;MAKASAR LETTER SA;Lo;0;L;;;;;N;;;;;
+11EF1;MAKASAR LETTER A;Lo;0;L;;;;;N;;;;;
+11EF2;MAKASAR ANGKA;Lo;0;L;;;;;N;;;;;
+11EF3;MAKASAR VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+11EF4;MAKASAR VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+11EF5;MAKASAR VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+11EF6;MAKASAR VOWEL SIGN O;Mc;0;L;;;;;N;;;;;
+11EF7;MAKASAR PASSIMBANG;Po;0;L;;;;;N;;;;;
+11EF8;MAKASAR END OF SECTION;Po;0;L;;;;;N;;;;;
12000;CUNEIFORM SIGN A;Lo;0;L;;;;;N;;;;;
12001;CUNEIFORM SIGN A TIMES A;Lo;0;L;;;;;N;;;;;
12002;CUNEIFORM SIGN A TIMES BAD;Lo;0;L;;;;;N;;;;;
@@ -23953,6 +24622,97 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
16B8D;PAHAWH HMONG CLAN SIGN TSWB;Lo;0;L;;;;;N;;;;;
16B8E;PAHAWH HMONG CLAN SIGN KWM;Lo;0;L;;;;;N;;;;;
16B8F;PAHAWH HMONG CLAN SIGN VWJ;Lo;0;L;;;;;N;;;;;
+16E40;MEDEFAIDRIN CAPITAL LETTER M;Lu;0;L;;;;;N;;;;16E60;
+16E41;MEDEFAIDRIN CAPITAL LETTER S;Lu;0;L;;;;;N;;;;16E61;
+16E42;MEDEFAIDRIN CAPITAL LETTER V;Lu;0;L;;;;;N;;;;16E62;
+16E43;MEDEFAIDRIN CAPITAL LETTER W;Lu;0;L;;;;;N;;;;16E63;
+16E44;MEDEFAIDRIN CAPITAL LETTER ATIU;Lu;0;L;;;;;N;;;;16E64;
+16E45;MEDEFAIDRIN CAPITAL LETTER Z;Lu;0;L;;;;;N;;;;16E65;
+16E46;MEDEFAIDRIN CAPITAL LETTER KP;Lu;0;L;;;;;N;;;;16E66;
+16E47;MEDEFAIDRIN CAPITAL LETTER P;Lu;0;L;;;;;N;;;;16E67;
+16E48;MEDEFAIDRIN CAPITAL LETTER T;Lu;0;L;;;;;N;;;;16E68;
+16E49;MEDEFAIDRIN CAPITAL LETTER G;Lu;0;L;;;;;N;;;;16E69;
+16E4A;MEDEFAIDRIN CAPITAL LETTER F;Lu;0;L;;;;;N;;;;16E6A;
+16E4B;MEDEFAIDRIN CAPITAL LETTER I;Lu;0;L;;;;;N;;;;16E6B;
+16E4C;MEDEFAIDRIN CAPITAL LETTER K;Lu;0;L;;;;;N;;;;16E6C;
+16E4D;MEDEFAIDRIN CAPITAL LETTER A;Lu;0;L;;;;;N;;;;16E6D;
+16E4E;MEDEFAIDRIN CAPITAL LETTER J;Lu;0;L;;;;;N;;;;16E6E;
+16E4F;MEDEFAIDRIN CAPITAL LETTER E;Lu;0;L;;;;;N;;;;16E6F;
+16E50;MEDEFAIDRIN CAPITAL LETTER B;Lu;0;L;;;;;N;;;;16E70;
+16E51;MEDEFAIDRIN CAPITAL LETTER C;Lu;0;L;;;;;N;;;;16E71;
+16E52;MEDEFAIDRIN CAPITAL LETTER U;Lu;0;L;;;;;N;;;;16E72;
+16E53;MEDEFAIDRIN CAPITAL LETTER YU;Lu;0;L;;;;;N;;;;16E73;
+16E54;MEDEFAIDRIN CAPITAL LETTER L;Lu;0;L;;;;;N;;;;16E74;
+16E55;MEDEFAIDRIN CAPITAL LETTER Q;Lu;0;L;;;;;N;;;;16E75;
+16E56;MEDEFAIDRIN CAPITAL LETTER HP;Lu;0;L;;;;;N;;;;16E76;
+16E57;MEDEFAIDRIN CAPITAL LETTER NY;Lu;0;L;;;;;N;;;;16E77;
+16E58;MEDEFAIDRIN CAPITAL LETTER X;Lu;0;L;;;;;N;;;;16E78;
+16E59;MEDEFAIDRIN CAPITAL LETTER D;Lu;0;L;;;;;N;;;;16E79;
+16E5A;MEDEFAIDRIN CAPITAL LETTER OE;Lu;0;L;;;;;N;;;;16E7A;
+16E5B;MEDEFAIDRIN CAPITAL LETTER N;Lu;0;L;;;;;N;;;;16E7B;
+16E5C;MEDEFAIDRIN CAPITAL LETTER R;Lu;0;L;;;;;N;;;;16E7C;
+16E5D;MEDEFAIDRIN CAPITAL LETTER O;Lu;0;L;;;;;N;;;;16E7D;
+16E5E;MEDEFAIDRIN CAPITAL LETTER AI;Lu;0;L;;;;;N;;;;16E7E;
+16E5F;MEDEFAIDRIN CAPITAL LETTER Y;Lu;0;L;;;;;N;;;;16E7F;
+16E60;MEDEFAIDRIN SMALL LETTER M;Ll;0;L;;;;;N;;;16E40;;16E40
+16E61;MEDEFAIDRIN SMALL LETTER S;Ll;0;L;;;;;N;;;16E41;;16E41
+16E62;MEDEFAIDRIN SMALL LETTER V;Ll;0;L;;;;;N;;;16E42;;16E42
+16E63;MEDEFAIDRIN SMALL LETTER W;Ll;0;L;;;;;N;;;16E43;;16E43
+16E64;MEDEFAIDRIN SMALL LETTER ATIU;Ll;0;L;;;;;N;;;16E44;;16E44
+16E65;MEDEFAIDRIN SMALL LETTER Z;Ll;0;L;;;;;N;;;16E45;;16E45
+16E66;MEDEFAIDRIN SMALL LETTER KP;Ll;0;L;;;;;N;;;16E46;;16E46
+16E67;MEDEFAIDRIN SMALL LETTER P;Ll;0;L;;;;;N;;;16E47;;16E47
+16E68;MEDEFAIDRIN SMALL LETTER T;Ll;0;L;;;;;N;;;16E48;;16E48
+16E69;MEDEFAIDRIN SMALL LETTER G;Ll;0;L;;;;;N;;;16E49;;16E49
+16E6A;MEDEFAIDRIN SMALL LETTER F;Ll;0;L;;;;;N;;;16E4A;;16E4A
+16E6B;MEDEFAIDRIN SMALL LETTER I;Ll;0;L;;;;;N;;;16E4B;;16E4B
+16E6C;MEDEFAIDRIN SMALL LETTER K;Ll;0;L;;;;;N;;;16E4C;;16E4C
+16E6D;MEDEFAIDRIN SMALL LETTER A;Ll;0;L;;;;;N;;;16E4D;;16E4D
+16E6E;MEDEFAIDRIN SMALL LETTER J;Ll;0;L;;;;;N;;;16E4E;;16E4E
+16E6F;MEDEFAIDRIN SMALL LETTER E;Ll;0;L;;;;;N;;;16E4F;;16E4F
+16E70;MEDEFAIDRIN SMALL LETTER B;Ll;0;L;;;;;N;;;16E50;;16E50
+16E71;MEDEFAIDRIN SMALL LETTER C;Ll;0;L;;;;;N;;;16E51;;16E51
+16E72;MEDEFAIDRIN SMALL LETTER U;Ll;0;L;;;;;N;;;16E52;;16E52
+16E73;MEDEFAIDRIN SMALL LETTER YU;Ll;0;L;;;;;N;;;16E53;;16E53
+16E74;MEDEFAIDRIN SMALL LETTER L;Ll;0;L;;;;;N;;;16E54;;16E54
+16E75;MEDEFAIDRIN SMALL LETTER Q;Ll;0;L;;;;;N;;;16E55;;16E55
+16E76;MEDEFAIDRIN SMALL LETTER HP;Ll;0;L;;;;;N;;;16E56;;16E56
+16E77;MEDEFAIDRIN SMALL LETTER NY;Ll;0;L;;;;;N;;;16E57;;16E57
+16E78;MEDEFAIDRIN SMALL LETTER X;Ll;0;L;;;;;N;;;16E58;;16E58
+16E79;MEDEFAIDRIN SMALL LETTER D;Ll;0;L;;;;;N;;;16E59;;16E59
+16E7A;MEDEFAIDRIN SMALL LETTER OE;Ll;0;L;;;;;N;;;16E5A;;16E5A
+16E7B;MEDEFAIDRIN SMALL LETTER N;Ll;0;L;;;;;N;;;16E5B;;16E5B
+16E7C;MEDEFAIDRIN SMALL LETTER R;Ll;0;L;;;;;N;;;16E5C;;16E5C
+16E7D;MEDEFAIDRIN SMALL LETTER O;Ll;0;L;;;;;N;;;16E5D;;16E5D
+16E7E;MEDEFAIDRIN SMALL LETTER AI;Ll;0;L;;;;;N;;;16E5E;;16E5E
+16E7F;MEDEFAIDRIN SMALL LETTER Y;Ll;0;L;;;;;N;;;16E5F;;16E5F
+16E80;MEDEFAIDRIN DIGIT ZERO;No;0;L;;;;0;N;;;;;
+16E81;MEDEFAIDRIN DIGIT ONE;No;0;L;;;;1;N;;;;;
+16E82;MEDEFAIDRIN DIGIT TWO;No;0;L;;;;2;N;;;;;
+16E83;MEDEFAIDRIN DIGIT THREE;No;0;L;;;;3;N;;;;;
+16E84;MEDEFAIDRIN DIGIT FOUR;No;0;L;;;;4;N;;;;;
+16E85;MEDEFAIDRIN DIGIT FIVE;No;0;L;;;;5;N;;;;;
+16E86;MEDEFAIDRIN DIGIT SIX;No;0;L;;;;6;N;;;;;
+16E87;MEDEFAIDRIN DIGIT SEVEN;No;0;L;;;;7;N;;;;;
+16E88;MEDEFAIDRIN DIGIT EIGHT;No;0;L;;;;8;N;;;;;
+16E89;MEDEFAIDRIN DIGIT NINE;No;0;L;;;;9;N;;;;;
+16E8A;MEDEFAIDRIN NUMBER TEN;No;0;L;;;;10;N;;;;;
+16E8B;MEDEFAIDRIN NUMBER ELEVEN;No;0;L;;;;11;N;;;;;
+16E8C;MEDEFAIDRIN NUMBER TWELVE;No;0;L;;;;12;N;;;;;
+16E8D;MEDEFAIDRIN NUMBER THIRTEEN;No;0;L;;;;13;N;;;;;
+16E8E;MEDEFAIDRIN NUMBER FOURTEEN;No;0;L;;;;14;N;;;;;
+16E8F;MEDEFAIDRIN NUMBER FIFTEEN;No;0;L;;;;15;N;;;;;
+16E90;MEDEFAIDRIN NUMBER SIXTEEN;No;0;L;;;;16;N;;;;;
+16E91;MEDEFAIDRIN NUMBER SEVENTEEN;No;0;L;;;;17;N;;;;;
+16E92;MEDEFAIDRIN NUMBER EIGHTEEN;No;0;L;;;;18;N;;;;;
+16E93;MEDEFAIDRIN NUMBER NINETEEN;No;0;L;;;;19;N;;;;;
+16E94;MEDEFAIDRIN DIGIT ONE ALTERNATE FORM;No;0;L;;;;1;N;;;;;
+16E95;MEDEFAIDRIN DIGIT TWO ALTERNATE FORM;No;0;L;;;;2;N;;;;;
+16E96;MEDEFAIDRIN DIGIT THREE ALTERNATE FORM;No;0;L;;;;3;N;;;;;
+16E97;MEDEFAIDRIN COMMA;Po;0;L;;;;;N;;;;;
+16E98;MEDEFAIDRIN FULL STOP;Po;0;L;;;;;N;;;;;
+16E99;MEDEFAIDRIN SYMBOL AIVA;Po;0;L;;;;;N;;;;;
+16E9A;MEDEFAIDRIN EXCLAMATION OH;Po;0;L;;;;;N;;;;;
16F00;MIAO LETTER PA;Lo;0;L;;;;;N;;;;;
16F01;MIAO LETTER BA;Lo;0;L;;;;;N;;;;;
16F02;MIAO LETTER YI PA;Lo;0;L;;;;;N;;;;;
@@ -24087,8 +24847,9 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
16F9E;MIAO LETTER REFORMED TONE-6;Lm;0;L;;;;;N;;;;;
16F9F;MIAO LETTER REFORMED TONE-8;Lm;0;L;;;;;N;;;;;
16FE0;TANGUT ITERATION MARK;Lm;0;L;;;;;N;;;;;
+16FE1;NUSHU ITERATION MARK;Lm;0;L;;;;;N;;;;;
17000;<Tangut Ideograph, First>;Lo;0;L;;;;;N;;;;;
-187EC;<Tangut Ideograph, Last>;Lo;0;L;;;;;N;;;;;
+187F1;<Tangut Ideograph, Last>;Lo;0;L;;;;;N;;;;;
18800;TANGUT COMPONENT-001;Lo;0;L;;;;;N;;;;;
18801;TANGUT COMPONENT-002;Lo;0;L;;;;;N;;;;;
18802;TANGUT COMPONENT-003;Lo;0;L;;;;;N;;;;;
@@ -24846,6 +25607,687 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
18AF2;TANGUT COMPONENT-755;Lo;0;L;;;;;N;;;;;
1B000;KATAKANA LETTER ARCHAIC E;Lo;0;L;;;;;N;;;;;
1B001;HIRAGANA LETTER ARCHAIC YE;Lo;0;L;;;;;N;;;;;
+1B002;HENTAIGANA LETTER A-1;Lo;0;L;;;;;N;;;;;
+1B003;HENTAIGANA LETTER A-2;Lo;0;L;;;;;N;;;;;
+1B004;HENTAIGANA LETTER A-3;Lo;0;L;;;;;N;;;;;
+1B005;HENTAIGANA LETTER A-WO;Lo;0;L;;;;;N;;;;;
+1B006;HENTAIGANA LETTER I-1;Lo;0;L;;;;;N;;;;;
+1B007;HENTAIGANA LETTER I-2;Lo;0;L;;;;;N;;;;;
+1B008;HENTAIGANA LETTER I-3;Lo;0;L;;;;;N;;;;;
+1B009;HENTAIGANA LETTER I-4;Lo;0;L;;;;;N;;;;;
+1B00A;HENTAIGANA LETTER U-1;Lo;0;L;;;;;N;;;;;
+1B00B;HENTAIGANA LETTER U-2;Lo;0;L;;;;;N;;;;;
+1B00C;HENTAIGANA LETTER U-3;Lo;0;L;;;;;N;;;;;
+1B00D;HENTAIGANA LETTER U-4;Lo;0;L;;;;;N;;;;;
+1B00E;HENTAIGANA LETTER U-5;Lo;0;L;;;;;N;;;;;
+1B00F;HENTAIGANA LETTER E-2;Lo;0;L;;;;;N;;;;;
+1B010;HENTAIGANA LETTER E-3;Lo;0;L;;;;;N;;;;;
+1B011;HENTAIGANA LETTER E-4;Lo;0;L;;;;;N;;;;;
+1B012;HENTAIGANA LETTER E-5;Lo;0;L;;;;;N;;;;;
+1B013;HENTAIGANA LETTER E-6;Lo;0;L;;;;;N;;;;;
+1B014;HENTAIGANA LETTER O-1;Lo;0;L;;;;;N;;;;;
+1B015;HENTAIGANA LETTER O-2;Lo;0;L;;;;;N;;;;;
+1B016;HENTAIGANA LETTER O-3;Lo;0;L;;;;;N;;;;;
+1B017;HENTAIGANA LETTER KA-1;Lo;0;L;;;;;N;;;;;
+1B018;HENTAIGANA LETTER KA-2;Lo;0;L;;;;;N;;;;;
+1B019;HENTAIGANA LETTER KA-3;Lo;0;L;;;;;N;;;;;
+1B01A;HENTAIGANA LETTER KA-4;Lo;0;L;;;;;N;;;;;
+1B01B;HENTAIGANA LETTER KA-5;Lo;0;L;;;;;N;;;;;
+1B01C;HENTAIGANA LETTER KA-6;Lo;0;L;;;;;N;;;;;
+1B01D;HENTAIGANA LETTER KA-7;Lo;0;L;;;;;N;;;;;
+1B01E;HENTAIGANA LETTER KA-8;Lo;0;L;;;;;N;;;;;
+1B01F;HENTAIGANA LETTER KA-9;Lo;0;L;;;;;N;;;;;
+1B020;HENTAIGANA LETTER KA-10;Lo;0;L;;;;;N;;;;;
+1B021;HENTAIGANA LETTER KA-11;Lo;0;L;;;;;N;;;;;
+1B022;HENTAIGANA LETTER KA-KE;Lo;0;L;;;;;N;;;;;
+1B023;HENTAIGANA LETTER KI-1;Lo;0;L;;;;;N;;;;;
+1B024;HENTAIGANA LETTER KI-2;Lo;0;L;;;;;N;;;;;
+1B025;HENTAIGANA LETTER KI-3;Lo;0;L;;;;;N;;;;;
+1B026;HENTAIGANA LETTER KI-4;Lo;0;L;;;;;N;;;;;
+1B027;HENTAIGANA LETTER KI-5;Lo;0;L;;;;;N;;;;;
+1B028;HENTAIGANA LETTER KI-6;Lo;0;L;;;;;N;;;;;
+1B029;HENTAIGANA LETTER KI-7;Lo;0;L;;;;;N;;;;;
+1B02A;HENTAIGANA LETTER KI-8;Lo;0;L;;;;;N;;;;;
+1B02B;HENTAIGANA LETTER KU-1;Lo;0;L;;;;;N;;;;;
+1B02C;HENTAIGANA LETTER KU-2;Lo;0;L;;;;;N;;;;;
+1B02D;HENTAIGANA LETTER KU-3;Lo;0;L;;;;;N;;;;;
+1B02E;HENTAIGANA LETTER KU-4;Lo;0;L;;;;;N;;;;;
+1B02F;HENTAIGANA LETTER KU-5;Lo;0;L;;;;;N;;;;;
+1B030;HENTAIGANA LETTER KU-6;Lo;0;L;;;;;N;;;;;
+1B031;HENTAIGANA LETTER KU-7;Lo;0;L;;;;;N;;;;;
+1B032;HENTAIGANA LETTER KE-1;Lo;0;L;;;;;N;;;;;
+1B033;HENTAIGANA LETTER KE-2;Lo;0;L;;;;;N;;;;;
+1B034;HENTAIGANA LETTER KE-3;Lo;0;L;;;;;N;;;;;
+1B035;HENTAIGANA LETTER KE-4;Lo;0;L;;;;;N;;;;;
+1B036;HENTAIGANA LETTER KE-5;Lo;0;L;;;;;N;;;;;
+1B037;HENTAIGANA LETTER KE-6;Lo;0;L;;;;;N;;;;;
+1B038;HENTAIGANA LETTER KO-1;Lo;0;L;;;;;N;;;;;
+1B039;HENTAIGANA LETTER KO-2;Lo;0;L;;;;;N;;;;;
+1B03A;HENTAIGANA LETTER KO-3;Lo;0;L;;;;;N;;;;;
+1B03B;HENTAIGANA LETTER KO-KI;Lo;0;L;;;;;N;;;;;
+1B03C;HENTAIGANA LETTER SA-1;Lo;0;L;;;;;N;;;;;
+1B03D;HENTAIGANA LETTER SA-2;Lo;0;L;;;;;N;;;;;
+1B03E;HENTAIGANA LETTER SA-3;Lo;0;L;;;;;N;;;;;
+1B03F;HENTAIGANA LETTER SA-4;Lo;0;L;;;;;N;;;;;
+1B040;HENTAIGANA LETTER SA-5;Lo;0;L;;;;;N;;;;;
+1B041;HENTAIGANA LETTER SA-6;Lo;0;L;;;;;N;;;;;
+1B042;HENTAIGANA LETTER SA-7;Lo;0;L;;;;;N;;;;;
+1B043;HENTAIGANA LETTER SA-8;Lo;0;L;;;;;N;;;;;
+1B044;HENTAIGANA LETTER SI-1;Lo;0;L;;;;;N;;;;;
+1B045;HENTAIGANA LETTER SI-2;Lo;0;L;;;;;N;;;;;
+1B046;HENTAIGANA LETTER SI-3;Lo;0;L;;;;;N;;;;;
+1B047;HENTAIGANA LETTER SI-4;Lo;0;L;;;;;N;;;;;
+1B048;HENTAIGANA LETTER SI-5;Lo;0;L;;;;;N;;;;;
+1B049;HENTAIGANA LETTER SI-6;Lo;0;L;;;;;N;;;;;
+1B04A;HENTAIGANA LETTER SU-1;Lo;0;L;;;;;N;;;;;
+1B04B;HENTAIGANA LETTER SU-2;Lo;0;L;;;;;N;;;;;
+1B04C;HENTAIGANA LETTER SU-3;Lo;0;L;;;;;N;;;;;
+1B04D;HENTAIGANA LETTER SU-4;Lo;0;L;;;;;N;;;;;
+1B04E;HENTAIGANA LETTER SU-5;Lo;0;L;;;;;N;;;;;
+1B04F;HENTAIGANA LETTER SU-6;Lo;0;L;;;;;N;;;;;
+1B050;HENTAIGANA LETTER SU-7;Lo;0;L;;;;;N;;;;;
+1B051;HENTAIGANA LETTER SU-8;Lo;0;L;;;;;N;;;;;
+1B052;HENTAIGANA LETTER SE-1;Lo;0;L;;;;;N;;;;;
+1B053;HENTAIGANA LETTER SE-2;Lo;0;L;;;;;N;;;;;
+1B054;HENTAIGANA LETTER SE-3;Lo;0;L;;;;;N;;;;;
+1B055;HENTAIGANA LETTER SE-4;Lo;0;L;;;;;N;;;;;
+1B056;HENTAIGANA LETTER SE-5;Lo;0;L;;;;;N;;;;;
+1B057;HENTAIGANA LETTER SO-1;Lo;0;L;;;;;N;;;;;
+1B058;HENTAIGANA LETTER SO-2;Lo;0;L;;;;;N;;;;;
+1B059;HENTAIGANA LETTER SO-3;Lo;0;L;;;;;N;;;;;
+1B05A;HENTAIGANA LETTER SO-4;Lo;0;L;;;;;N;;;;;
+1B05B;HENTAIGANA LETTER SO-5;Lo;0;L;;;;;N;;;;;
+1B05C;HENTAIGANA LETTER SO-6;Lo;0;L;;;;;N;;;;;
+1B05D;HENTAIGANA LETTER SO-7;Lo;0;L;;;;;N;;;;;
+1B05E;HENTAIGANA LETTER TA-1;Lo;0;L;;;;;N;;;;;
+1B05F;HENTAIGANA LETTER TA-2;Lo;0;L;;;;;N;;;;;
+1B060;HENTAIGANA LETTER TA-3;Lo;0;L;;;;;N;;;;;
+1B061;HENTAIGANA LETTER TA-4;Lo;0;L;;;;;N;;;;;
+1B062;HENTAIGANA LETTER TI-1;Lo;0;L;;;;;N;;;;;
+1B063;HENTAIGANA LETTER TI-2;Lo;0;L;;;;;N;;;;;
+1B064;HENTAIGANA LETTER TI-3;Lo;0;L;;;;;N;;;;;
+1B065;HENTAIGANA LETTER TI-4;Lo;0;L;;;;;N;;;;;
+1B066;HENTAIGANA LETTER TI-5;Lo;0;L;;;;;N;;;;;
+1B067;HENTAIGANA LETTER TI-6;Lo;0;L;;;;;N;;;;;
+1B068;HENTAIGANA LETTER TI-7;Lo;0;L;;;;;N;;;;;
+1B069;HENTAIGANA LETTER TU-1;Lo;0;L;;;;;N;;;;;
+1B06A;HENTAIGANA LETTER TU-2;Lo;0;L;;;;;N;;;;;
+1B06B;HENTAIGANA LETTER TU-3;Lo;0;L;;;;;N;;;;;
+1B06C;HENTAIGANA LETTER TU-4;Lo;0;L;;;;;N;;;;;
+1B06D;HENTAIGANA LETTER TU-TO;Lo;0;L;;;;;N;;;;;
+1B06E;HENTAIGANA LETTER TE-1;Lo;0;L;;;;;N;;;;;
+1B06F;HENTAIGANA LETTER TE-2;Lo;0;L;;;;;N;;;;;
+1B070;HENTAIGANA LETTER TE-3;Lo;0;L;;;;;N;;;;;
+1B071;HENTAIGANA LETTER TE-4;Lo;0;L;;;;;N;;;;;
+1B072;HENTAIGANA LETTER TE-5;Lo;0;L;;;;;N;;;;;
+1B073;HENTAIGANA LETTER TE-6;Lo;0;L;;;;;N;;;;;
+1B074;HENTAIGANA LETTER TE-7;Lo;0;L;;;;;N;;;;;
+1B075;HENTAIGANA LETTER TE-8;Lo;0;L;;;;;N;;;;;
+1B076;HENTAIGANA LETTER TE-9;Lo;0;L;;;;;N;;;;;
+1B077;HENTAIGANA LETTER TO-1;Lo;0;L;;;;;N;;;;;
+1B078;HENTAIGANA LETTER TO-2;Lo;0;L;;;;;N;;;;;
+1B079;HENTAIGANA LETTER TO-3;Lo;0;L;;;;;N;;;;;
+1B07A;HENTAIGANA LETTER TO-4;Lo;0;L;;;;;N;;;;;
+1B07B;HENTAIGANA LETTER TO-5;Lo;0;L;;;;;N;;;;;
+1B07C;HENTAIGANA LETTER TO-6;Lo;0;L;;;;;N;;;;;
+1B07D;HENTAIGANA LETTER TO-RA;Lo;0;L;;;;;N;;;;;
+1B07E;HENTAIGANA LETTER NA-1;Lo;0;L;;;;;N;;;;;
+1B07F;HENTAIGANA LETTER NA-2;Lo;0;L;;;;;N;;;;;
+1B080;HENTAIGANA LETTER NA-3;Lo;0;L;;;;;N;;;;;
+1B081;HENTAIGANA LETTER NA-4;Lo;0;L;;;;;N;;;;;
+1B082;HENTAIGANA LETTER NA-5;Lo;0;L;;;;;N;;;;;
+1B083;HENTAIGANA LETTER NA-6;Lo;0;L;;;;;N;;;;;
+1B084;HENTAIGANA LETTER NA-7;Lo;0;L;;;;;N;;;;;
+1B085;HENTAIGANA LETTER NA-8;Lo;0;L;;;;;N;;;;;
+1B086;HENTAIGANA LETTER NA-9;Lo;0;L;;;;;N;;;;;
+1B087;HENTAIGANA LETTER NI-1;Lo;0;L;;;;;N;;;;;
+1B088;HENTAIGANA LETTER NI-2;Lo;0;L;;;;;N;;;;;
+1B089;HENTAIGANA LETTER NI-3;Lo;0;L;;;;;N;;;;;
+1B08A;HENTAIGANA LETTER NI-4;Lo;0;L;;;;;N;;;;;
+1B08B;HENTAIGANA LETTER NI-5;Lo;0;L;;;;;N;;;;;
+1B08C;HENTAIGANA LETTER NI-6;Lo;0;L;;;;;N;;;;;
+1B08D;HENTAIGANA LETTER NI-7;Lo;0;L;;;;;N;;;;;
+1B08E;HENTAIGANA LETTER NI-TE;Lo;0;L;;;;;N;;;;;
+1B08F;HENTAIGANA LETTER NU-1;Lo;0;L;;;;;N;;;;;
+1B090;HENTAIGANA LETTER NU-2;Lo;0;L;;;;;N;;;;;
+1B091;HENTAIGANA LETTER NU-3;Lo;0;L;;;;;N;;;;;
+1B092;HENTAIGANA LETTER NE-1;Lo;0;L;;;;;N;;;;;
+1B093;HENTAIGANA LETTER NE-2;Lo;0;L;;;;;N;;;;;
+1B094;HENTAIGANA LETTER NE-3;Lo;0;L;;;;;N;;;;;
+1B095;HENTAIGANA LETTER NE-4;Lo;0;L;;;;;N;;;;;
+1B096;HENTAIGANA LETTER NE-5;Lo;0;L;;;;;N;;;;;
+1B097;HENTAIGANA LETTER NE-6;Lo;0;L;;;;;N;;;;;
+1B098;HENTAIGANA LETTER NE-KO;Lo;0;L;;;;;N;;;;;
+1B099;HENTAIGANA LETTER NO-1;Lo;0;L;;;;;N;;;;;
+1B09A;HENTAIGANA LETTER NO-2;Lo;0;L;;;;;N;;;;;
+1B09B;HENTAIGANA LETTER NO-3;Lo;0;L;;;;;N;;;;;
+1B09C;HENTAIGANA LETTER NO-4;Lo;0;L;;;;;N;;;;;
+1B09D;HENTAIGANA LETTER NO-5;Lo;0;L;;;;;N;;;;;
+1B09E;HENTAIGANA LETTER HA-1;Lo;0;L;;;;;N;;;;;
+1B09F;HENTAIGANA LETTER HA-2;Lo;0;L;;;;;N;;;;;
+1B0A0;HENTAIGANA LETTER HA-3;Lo;0;L;;;;;N;;;;;
+1B0A1;HENTAIGANA LETTER HA-4;Lo;0;L;;;;;N;;;;;
+1B0A2;HENTAIGANA LETTER HA-5;Lo;0;L;;;;;N;;;;;
+1B0A3;HENTAIGANA LETTER HA-6;Lo;0;L;;;;;N;;;;;
+1B0A4;HENTAIGANA LETTER HA-7;Lo;0;L;;;;;N;;;;;
+1B0A5;HENTAIGANA LETTER HA-8;Lo;0;L;;;;;N;;;;;
+1B0A6;HENTAIGANA LETTER HA-9;Lo;0;L;;;;;N;;;;;
+1B0A7;HENTAIGANA LETTER HA-10;Lo;0;L;;;;;N;;;;;
+1B0A8;HENTAIGANA LETTER HA-11;Lo;0;L;;;;;N;;;;;
+1B0A9;HENTAIGANA LETTER HI-1;Lo;0;L;;;;;N;;;;;
+1B0AA;HENTAIGANA LETTER HI-2;Lo;0;L;;;;;N;;;;;
+1B0AB;HENTAIGANA LETTER HI-3;Lo;0;L;;;;;N;;;;;
+1B0AC;HENTAIGANA LETTER HI-4;Lo;0;L;;;;;N;;;;;
+1B0AD;HENTAIGANA LETTER HI-5;Lo;0;L;;;;;N;;;;;
+1B0AE;HENTAIGANA LETTER HI-6;Lo;0;L;;;;;N;;;;;
+1B0AF;HENTAIGANA LETTER HI-7;Lo;0;L;;;;;N;;;;;
+1B0B0;HENTAIGANA LETTER HU-1;Lo;0;L;;;;;N;;;;;
+1B0B1;HENTAIGANA LETTER HU-2;Lo;0;L;;;;;N;;;;;
+1B0B2;HENTAIGANA LETTER HU-3;Lo;0;L;;;;;N;;;;;
+1B0B3;HENTAIGANA LETTER HE-1;Lo;0;L;;;;;N;;;;;
+1B0B4;HENTAIGANA LETTER HE-2;Lo;0;L;;;;;N;;;;;
+1B0B5;HENTAIGANA LETTER HE-3;Lo;0;L;;;;;N;;;;;
+1B0B6;HENTAIGANA LETTER HE-4;Lo;0;L;;;;;N;;;;;
+1B0B7;HENTAIGANA LETTER HE-5;Lo;0;L;;;;;N;;;;;
+1B0B8;HENTAIGANA LETTER HE-6;Lo;0;L;;;;;N;;;;;
+1B0B9;HENTAIGANA LETTER HE-7;Lo;0;L;;;;;N;;;;;
+1B0BA;HENTAIGANA LETTER HO-1;Lo;0;L;;;;;N;;;;;
+1B0BB;HENTAIGANA LETTER HO-2;Lo;0;L;;;;;N;;;;;
+1B0BC;HENTAIGANA LETTER HO-3;Lo;0;L;;;;;N;;;;;
+1B0BD;HENTAIGANA LETTER HO-4;Lo;0;L;;;;;N;;;;;
+1B0BE;HENTAIGANA LETTER HO-5;Lo;0;L;;;;;N;;;;;
+1B0BF;HENTAIGANA LETTER HO-6;Lo;0;L;;;;;N;;;;;
+1B0C0;HENTAIGANA LETTER HO-7;Lo;0;L;;;;;N;;;;;
+1B0C1;HENTAIGANA LETTER HO-8;Lo;0;L;;;;;N;;;;;
+1B0C2;HENTAIGANA LETTER MA-1;Lo;0;L;;;;;N;;;;;
+1B0C3;HENTAIGANA LETTER MA-2;Lo;0;L;;;;;N;;;;;
+1B0C4;HENTAIGANA LETTER MA-3;Lo;0;L;;;;;N;;;;;
+1B0C5;HENTAIGANA LETTER MA-4;Lo;0;L;;;;;N;;;;;
+1B0C6;HENTAIGANA LETTER MA-5;Lo;0;L;;;;;N;;;;;
+1B0C7;HENTAIGANA LETTER MA-6;Lo;0;L;;;;;N;;;;;
+1B0C8;HENTAIGANA LETTER MA-7;Lo;0;L;;;;;N;;;;;
+1B0C9;HENTAIGANA LETTER MI-1;Lo;0;L;;;;;N;;;;;
+1B0CA;HENTAIGANA LETTER MI-2;Lo;0;L;;;;;N;;;;;
+1B0CB;HENTAIGANA LETTER MI-3;Lo;0;L;;;;;N;;;;;
+1B0CC;HENTAIGANA LETTER MI-4;Lo;0;L;;;;;N;;;;;
+1B0CD;HENTAIGANA LETTER MI-5;Lo;0;L;;;;;N;;;;;
+1B0CE;HENTAIGANA LETTER MI-6;Lo;0;L;;;;;N;;;;;
+1B0CF;HENTAIGANA LETTER MI-7;Lo;0;L;;;;;N;;;;;
+1B0D0;HENTAIGANA LETTER MU-1;Lo;0;L;;;;;N;;;;;
+1B0D1;HENTAIGANA LETTER MU-2;Lo;0;L;;;;;N;;;;;
+1B0D2;HENTAIGANA LETTER MU-3;Lo;0;L;;;;;N;;;;;
+1B0D3;HENTAIGANA LETTER MU-4;Lo;0;L;;;;;N;;;;;
+1B0D4;HENTAIGANA LETTER ME-1;Lo;0;L;;;;;N;;;;;
+1B0D5;HENTAIGANA LETTER ME-2;Lo;0;L;;;;;N;;;;;
+1B0D6;HENTAIGANA LETTER ME-MA;Lo;0;L;;;;;N;;;;;
+1B0D7;HENTAIGANA LETTER MO-1;Lo;0;L;;;;;N;;;;;
+1B0D8;HENTAIGANA LETTER MO-2;Lo;0;L;;;;;N;;;;;
+1B0D9;HENTAIGANA LETTER MO-3;Lo;0;L;;;;;N;;;;;
+1B0DA;HENTAIGANA LETTER MO-4;Lo;0;L;;;;;N;;;;;
+1B0DB;HENTAIGANA LETTER MO-5;Lo;0;L;;;;;N;;;;;
+1B0DC;HENTAIGANA LETTER MO-6;Lo;0;L;;;;;N;;;;;
+1B0DD;HENTAIGANA LETTER YA-1;Lo;0;L;;;;;N;;;;;
+1B0DE;HENTAIGANA LETTER YA-2;Lo;0;L;;;;;N;;;;;
+1B0DF;HENTAIGANA LETTER YA-3;Lo;0;L;;;;;N;;;;;
+1B0E0;HENTAIGANA LETTER YA-4;Lo;0;L;;;;;N;;;;;
+1B0E1;HENTAIGANA LETTER YA-5;Lo;0;L;;;;;N;;;;;
+1B0E2;HENTAIGANA LETTER YA-YO;Lo;0;L;;;;;N;;;;;
+1B0E3;HENTAIGANA LETTER YU-1;Lo;0;L;;;;;N;;;;;
+1B0E4;HENTAIGANA LETTER YU-2;Lo;0;L;;;;;N;;;;;
+1B0E5;HENTAIGANA LETTER YU-3;Lo;0;L;;;;;N;;;;;
+1B0E6;HENTAIGANA LETTER YU-4;Lo;0;L;;;;;N;;;;;
+1B0E7;HENTAIGANA LETTER YO-1;Lo;0;L;;;;;N;;;;;
+1B0E8;HENTAIGANA LETTER YO-2;Lo;0;L;;;;;N;;;;;
+1B0E9;HENTAIGANA LETTER YO-3;Lo;0;L;;;;;N;;;;;
+1B0EA;HENTAIGANA LETTER YO-4;Lo;0;L;;;;;N;;;;;
+1B0EB;HENTAIGANA LETTER YO-5;Lo;0;L;;;;;N;;;;;
+1B0EC;HENTAIGANA LETTER YO-6;Lo;0;L;;;;;N;;;;;
+1B0ED;HENTAIGANA LETTER RA-1;Lo;0;L;;;;;N;;;;;
+1B0EE;HENTAIGANA LETTER RA-2;Lo;0;L;;;;;N;;;;;
+1B0EF;HENTAIGANA LETTER RA-3;Lo;0;L;;;;;N;;;;;
+1B0F0;HENTAIGANA LETTER RA-4;Lo;0;L;;;;;N;;;;;
+1B0F1;HENTAIGANA LETTER RI-1;Lo;0;L;;;;;N;;;;;
+1B0F2;HENTAIGANA LETTER RI-2;Lo;0;L;;;;;N;;;;;
+1B0F3;HENTAIGANA LETTER RI-3;Lo;0;L;;;;;N;;;;;
+1B0F4;HENTAIGANA LETTER RI-4;Lo;0;L;;;;;N;;;;;
+1B0F5;HENTAIGANA LETTER RI-5;Lo;0;L;;;;;N;;;;;
+1B0F6;HENTAIGANA LETTER RI-6;Lo;0;L;;;;;N;;;;;
+1B0F7;HENTAIGANA LETTER RI-7;Lo;0;L;;;;;N;;;;;
+1B0F8;HENTAIGANA LETTER RU-1;Lo;0;L;;;;;N;;;;;
+1B0F9;HENTAIGANA LETTER RU-2;Lo;0;L;;;;;N;;;;;
+1B0FA;HENTAIGANA LETTER RU-3;Lo;0;L;;;;;N;;;;;
+1B0FB;HENTAIGANA LETTER RU-4;Lo;0;L;;;;;N;;;;;
+1B0FC;HENTAIGANA LETTER RU-5;Lo;0;L;;;;;N;;;;;
+1B0FD;HENTAIGANA LETTER RU-6;Lo;0;L;;;;;N;;;;;
+1B0FE;HENTAIGANA LETTER RE-1;Lo;0;L;;;;;N;;;;;
+1B0FF;HENTAIGANA LETTER RE-2;Lo;0;L;;;;;N;;;;;
+1B100;HENTAIGANA LETTER RE-3;Lo;0;L;;;;;N;;;;;
+1B101;HENTAIGANA LETTER RE-4;Lo;0;L;;;;;N;;;;;
+1B102;HENTAIGANA LETTER RO-1;Lo;0;L;;;;;N;;;;;
+1B103;HENTAIGANA LETTER RO-2;Lo;0;L;;;;;N;;;;;
+1B104;HENTAIGANA LETTER RO-3;Lo;0;L;;;;;N;;;;;
+1B105;HENTAIGANA LETTER RO-4;Lo;0;L;;;;;N;;;;;
+1B106;HENTAIGANA LETTER RO-5;Lo;0;L;;;;;N;;;;;
+1B107;HENTAIGANA LETTER RO-6;Lo;0;L;;;;;N;;;;;
+1B108;HENTAIGANA LETTER WA-1;Lo;0;L;;;;;N;;;;;
+1B109;HENTAIGANA LETTER WA-2;Lo;0;L;;;;;N;;;;;
+1B10A;HENTAIGANA LETTER WA-3;Lo;0;L;;;;;N;;;;;
+1B10B;HENTAIGANA LETTER WA-4;Lo;0;L;;;;;N;;;;;
+1B10C;HENTAIGANA LETTER WA-5;Lo;0;L;;;;;N;;;;;
+1B10D;HENTAIGANA LETTER WI-1;Lo;0;L;;;;;N;;;;;
+1B10E;HENTAIGANA LETTER WI-2;Lo;0;L;;;;;N;;;;;
+1B10F;HENTAIGANA LETTER WI-3;Lo;0;L;;;;;N;;;;;
+1B110;HENTAIGANA LETTER WI-4;Lo;0;L;;;;;N;;;;;
+1B111;HENTAIGANA LETTER WI-5;Lo;0;L;;;;;N;;;;;
+1B112;HENTAIGANA LETTER WE-1;Lo;0;L;;;;;N;;;;;
+1B113;HENTAIGANA LETTER WE-2;Lo;0;L;;;;;N;;;;;
+1B114;HENTAIGANA LETTER WE-3;Lo;0;L;;;;;N;;;;;
+1B115;HENTAIGANA LETTER WE-4;Lo;0;L;;;;;N;;;;;
+1B116;HENTAIGANA LETTER WO-1;Lo;0;L;;;;;N;;;;;
+1B117;HENTAIGANA LETTER WO-2;Lo;0;L;;;;;N;;;;;
+1B118;HENTAIGANA LETTER WO-3;Lo;0;L;;;;;N;;;;;
+1B119;HENTAIGANA LETTER WO-4;Lo;0;L;;;;;N;;;;;
+1B11A;HENTAIGANA LETTER WO-5;Lo;0;L;;;;;N;;;;;
+1B11B;HENTAIGANA LETTER WO-6;Lo;0;L;;;;;N;;;;;
+1B11C;HENTAIGANA LETTER WO-7;Lo;0;L;;;;;N;;;;;
+1B11D;HENTAIGANA LETTER N-MU-MO-1;Lo;0;L;;;;;N;;;;;
+1B11E;HENTAIGANA LETTER N-MU-MO-2;Lo;0;L;;;;;N;;;;;
+1B170;NUSHU CHARACTER-1B170;Lo;0;L;;;;;N;;;;;
+1B171;NUSHU CHARACTER-1B171;Lo;0;L;;;;;N;;;;;
+1B172;NUSHU CHARACTER-1B172;Lo;0;L;;;;;N;;;;;
+1B173;NUSHU CHARACTER-1B173;Lo;0;L;;;;;N;;;;;
+1B174;NUSHU CHARACTER-1B174;Lo;0;L;;;;;N;;;;;
+1B175;NUSHU CHARACTER-1B175;Lo;0;L;;;;;N;;;;;
+1B176;NUSHU CHARACTER-1B176;Lo;0;L;;;;;N;;;;;
+1B177;NUSHU CHARACTER-1B177;Lo;0;L;;;;;N;;;;;
+1B178;NUSHU CHARACTER-1B178;Lo;0;L;;;;;N;;;;;
+1B179;NUSHU CHARACTER-1B179;Lo;0;L;;;;;N;;;;;
+1B17A;NUSHU CHARACTER-1B17A;Lo;0;L;;;;;N;;;;;
+1B17B;NUSHU CHARACTER-1B17B;Lo;0;L;;;;;N;;;;;
+1B17C;NUSHU CHARACTER-1B17C;Lo;0;L;;;;;N;;;;;
+1B17D;NUSHU CHARACTER-1B17D;Lo;0;L;;;;;N;;;;;
+1B17E;NUSHU CHARACTER-1B17E;Lo;0;L;;;;;N;;;;;
+1B17F;NUSHU CHARACTER-1B17F;Lo;0;L;;;;;N;;;;;
+1B180;NUSHU CHARACTER-1B180;Lo;0;L;;;;;N;;;;;
+1B181;NUSHU CHARACTER-1B181;Lo;0;L;;;;;N;;;;;
+1B182;NUSHU CHARACTER-1B182;Lo;0;L;;;;;N;;;;;
+1B183;NUSHU CHARACTER-1B183;Lo;0;L;;;;;N;;;;;
+1B184;NUSHU CHARACTER-1B184;Lo;0;L;;;;;N;;;;;
+1B185;NUSHU CHARACTER-1B185;Lo;0;L;;;;;N;;;;;
+1B186;NUSHU CHARACTER-1B186;Lo;0;L;;;;;N;;;;;
+1B187;NUSHU CHARACTER-1B187;Lo;0;L;;;;;N;;;;;
+1B188;NUSHU CHARACTER-1B188;Lo;0;L;;;;;N;;;;;
+1B189;NUSHU CHARACTER-1B189;Lo;0;L;;;;;N;;;;;
+1B18A;NUSHU CHARACTER-1B18A;Lo;0;L;;;;;N;;;;;
+1B18B;NUSHU CHARACTER-1B18B;Lo;0;L;;;;;N;;;;;
+1B18C;NUSHU CHARACTER-1B18C;Lo;0;L;;;;;N;;;;;
+1B18D;NUSHU CHARACTER-1B18D;Lo;0;L;;;;;N;;;;;
+1B18E;NUSHU CHARACTER-1B18E;Lo;0;L;;;;;N;;;;;
+1B18F;NUSHU CHARACTER-1B18F;Lo;0;L;;;;;N;;;;;
+1B190;NUSHU CHARACTER-1B190;Lo;0;L;;;;;N;;;;;
+1B191;NUSHU CHARACTER-1B191;Lo;0;L;;;;;N;;;;;
+1B192;NUSHU CHARACTER-1B192;Lo;0;L;;;;;N;;;;;
+1B193;NUSHU CHARACTER-1B193;Lo;0;L;;;;;N;;;;;
+1B194;NUSHU CHARACTER-1B194;Lo;0;L;;;;;N;;;;;
+1B195;NUSHU CHARACTER-1B195;Lo;0;L;;;;;N;;;;;
+1B196;NUSHU CHARACTER-1B196;Lo;0;L;;;;;N;;;;;
+1B197;NUSHU CHARACTER-1B197;Lo;0;L;;;;;N;;;;;
+1B198;NUSHU CHARACTER-1B198;Lo;0;L;;;;;N;;;;;
+1B199;NUSHU CHARACTER-1B199;Lo;0;L;;;;;N;;;;;
+1B19A;NUSHU CHARACTER-1B19A;Lo;0;L;;;;;N;;;;;
+1B19B;NUSHU CHARACTER-1B19B;Lo;0;L;;;;;N;;;;;
+1B19C;NUSHU CHARACTER-1B19C;Lo;0;L;;;;;N;;;;;
+1B19D;NUSHU CHARACTER-1B19D;Lo;0;L;;;;;N;;;;;
+1B19E;NUSHU CHARACTER-1B19E;Lo;0;L;;;;;N;;;;;
+1B19F;NUSHU CHARACTER-1B19F;Lo;0;L;;;;;N;;;;;
+1B1A0;NUSHU CHARACTER-1B1A0;Lo;0;L;;;;;N;;;;;
+1B1A1;NUSHU CHARACTER-1B1A1;Lo;0;L;;;;;N;;;;;
+1B1A2;NUSHU CHARACTER-1B1A2;Lo;0;L;;;;;N;;;;;
+1B1A3;NUSHU CHARACTER-1B1A3;Lo;0;L;;;;;N;;;;;
+1B1A4;NUSHU CHARACTER-1B1A4;Lo;0;L;;;;;N;;;;;
+1B1A5;NUSHU CHARACTER-1B1A5;Lo;0;L;;;;;N;;;;;
+1B1A6;NUSHU CHARACTER-1B1A6;Lo;0;L;;;;;N;;;;;
+1B1A7;NUSHU CHARACTER-1B1A7;Lo;0;L;;;;;N;;;;;
+1B1A8;NUSHU CHARACTER-1B1A8;Lo;0;L;;;;;N;;;;;
+1B1A9;NUSHU CHARACTER-1B1A9;Lo;0;L;;;;;N;;;;;
+1B1AA;NUSHU CHARACTER-1B1AA;Lo;0;L;;;;;N;;;;;
+1B1AB;NUSHU CHARACTER-1B1AB;Lo;0;L;;;;;N;;;;;
+1B1AC;NUSHU CHARACTER-1B1AC;Lo;0;L;;;;;N;;;;;
+1B1AD;NUSHU CHARACTER-1B1AD;Lo;0;L;;;;;N;;;;;
+1B1AE;NUSHU CHARACTER-1B1AE;Lo;0;L;;;;;N;;;;;
+1B1AF;NUSHU CHARACTER-1B1AF;Lo;0;L;;;;;N;;;;;
+1B1B0;NUSHU CHARACTER-1B1B0;Lo;0;L;;;;;N;;;;;
+1B1B1;NUSHU CHARACTER-1B1B1;Lo;0;L;;;;;N;;;;;
+1B1B2;NUSHU CHARACTER-1B1B2;Lo;0;L;;;;;N;;;;;
+1B1B3;NUSHU CHARACTER-1B1B3;Lo;0;L;;;;;N;;;;;
+1B1B4;NUSHU CHARACTER-1B1B4;Lo;0;L;;;;;N;;;;;
+1B1B5;NUSHU CHARACTER-1B1B5;Lo;0;L;;;;;N;;;;;
+1B1B6;NUSHU CHARACTER-1B1B6;Lo;0;L;;;;;N;;;;;
+1B1B7;NUSHU CHARACTER-1B1B7;Lo;0;L;;;;;N;;;;;
+1B1B8;NUSHU CHARACTER-1B1B8;Lo;0;L;;;;;N;;;;;
+1B1B9;NUSHU CHARACTER-1B1B9;Lo;0;L;;;;;N;;;;;
+1B1BA;NUSHU CHARACTER-1B1BA;Lo;0;L;;;;;N;;;;;
+1B1BB;NUSHU CHARACTER-1B1BB;Lo;0;L;;;;;N;;;;;
+1B1BC;NUSHU CHARACTER-1B1BC;Lo;0;L;;;;;N;;;;;
+1B1BD;NUSHU CHARACTER-1B1BD;Lo;0;L;;;;;N;;;;;
+1B1BE;NUSHU CHARACTER-1B1BE;Lo;0;L;;;;;N;;;;;
+1B1BF;NUSHU CHARACTER-1B1BF;Lo;0;L;;;;;N;;;;;
+1B1C0;NUSHU CHARACTER-1B1C0;Lo;0;L;;;;;N;;;;;
+1B1C1;NUSHU CHARACTER-1B1C1;Lo;0;L;;;;;N;;;;;
+1B1C2;NUSHU CHARACTER-1B1C2;Lo;0;L;;;;;N;;;;;
+1B1C3;NUSHU CHARACTER-1B1C3;Lo;0;L;;;;;N;;;;;
+1B1C4;NUSHU CHARACTER-1B1C4;Lo;0;L;;;;;N;;;;;
+1B1C5;NUSHU CHARACTER-1B1C5;Lo;0;L;;;;;N;;;;;
+1B1C6;NUSHU CHARACTER-1B1C6;Lo;0;L;;;;;N;;;;;
+1B1C7;NUSHU CHARACTER-1B1C7;Lo;0;L;;;;;N;;;;;
+1B1C8;NUSHU CHARACTER-1B1C8;Lo;0;L;;;;;N;;;;;
+1B1C9;NUSHU CHARACTER-1B1C9;Lo;0;L;;;;;N;;;;;
+1B1CA;NUSHU CHARACTER-1B1CA;Lo;0;L;;;;;N;;;;;
+1B1CB;NUSHU CHARACTER-1B1CB;Lo;0;L;;;;;N;;;;;
+1B1CC;NUSHU CHARACTER-1B1CC;Lo;0;L;;;;;N;;;;;
+1B1CD;NUSHU CHARACTER-1B1CD;Lo;0;L;;;;;N;;;;;
+1B1CE;NUSHU CHARACTER-1B1CE;Lo;0;L;;;;;N;;;;;
+1B1CF;NUSHU CHARACTER-1B1CF;Lo;0;L;;;;;N;;;;;
+1B1D0;NUSHU CHARACTER-1B1D0;Lo;0;L;;;;;N;;;;;
+1B1D1;NUSHU CHARACTER-1B1D1;Lo;0;L;;;;;N;;;;;
+1B1D2;NUSHU CHARACTER-1B1D2;Lo;0;L;;;;;N;;;;;
+1B1D3;NUSHU CHARACTER-1B1D3;Lo;0;L;;;;;N;;;;;
+1B1D4;NUSHU CHARACTER-1B1D4;Lo;0;L;;;;;N;;;;;
+1B1D5;NUSHU CHARACTER-1B1D5;Lo;0;L;;;;;N;;;;;
+1B1D6;NUSHU CHARACTER-1B1D6;Lo;0;L;;;;;N;;;;;
+1B1D7;NUSHU CHARACTER-1B1D7;Lo;0;L;;;;;N;;;;;
+1B1D8;NUSHU CHARACTER-1B1D8;Lo;0;L;;;;;N;;;;;
+1B1D9;NUSHU CHARACTER-1B1D9;Lo;0;L;;;;;N;;;;;
+1B1DA;NUSHU CHARACTER-1B1DA;Lo;0;L;;;;;N;;;;;
+1B1DB;NUSHU CHARACTER-1B1DB;Lo;0;L;;;;;N;;;;;
+1B1DC;NUSHU CHARACTER-1B1DC;Lo;0;L;;;;;N;;;;;
+1B1DD;NUSHU CHARACTER-1B1DD;Lo;0;L;;;;;N;;;;;
+1B1DE;NUSHU CHARACTER-1B1DE;Lo;0;L;;;;;N;;;;;
+1B1DF;NUSHU CHARACTER-1B1DF;Lo;0;L;;;;;N;;;;;
+1B1E0;NUSHU CHARACTER-1B1E0;Lo;0;L;;;;;N;;;;;
+1B1E1;NUSHU CHARACTER-1B1E1;Lo;0;L;;;;;N;;;;;
+1B1E2;NUSHU CHARACTER-1B1E2;Lo;0;L;;;;;N;;;;;
+1B1E3;NUSHU CHARACTER-1B1E3;Lo;0;L;;;;;N;;;;;
+1B1E4;NUSHU CHARACTER-1B1E4;Lo;0;L;;;;;N;;;;;
+1B1E5;NUSHU CHARACTER-1B1E5;Lo;0;L;;;;;N;;;;;
+1B1E6;NUSHU CHARACTER-1B1E6;Lo;0;L;;;;;N;;;;;
+1B1E7;NUSHU CHARACTER-1B1E7;Lo;0;L;;;;;N;;;;;
+1B1E8;NUSHU CHARACTER-1B1E8;Lo;0;L;;;;;N;;;;;
+1B1E9;NUSHU CHARACTER-1B1E9;Lo;0;L;;;;;N;;;;;
+1B1EA;NUSHU CHARACTER-1B1EA;Lo;0;L;;;;;N;;;;;
+1B1EB;NUSHU CHARACTER-1B1EB;Lo;0;L;;;;;N;;;;;
+1B1EC;NUSHU CHARACTER-1B1EC;Lo;0;L;;;;;N;;;;;
+1B1ED;NUSHU CHARACTER-1B1ED;Lo;0;L;;;;;N;;;;;
+1B1EE;NUSHU CHARACTER-1B1EE;Lo;0;L;;;;;N;;;;;
+1B1EF;NUSHU CHARACTER-1B1EF;Lo;0;L;;;;;N;;;;;
+1B1F0;NUSHU CHARACTER-1B1F0;Lo;0;L;;;;;N;;;;;
+1B1F1;NUSHU CHARACTER-1B1F1;Lo;0;L;;;;;N;;;;;
+1B1F2;NUSHU CHARACTER-1B1F2;Lo;0;L;;;;;N;;;;;
+1B1F3;NUSHU CHARACTER-1B1F3;Lo;0;L;;;;;N;;;;;
+1B1F4;NUSHU CHARACTER-1B1F4;Lo;0;L;;;;;N;;;;;
+1B1F5;NUSHU CHARACTER-1B1F5;Lo;0;L;;;;;N;;;;;
+1B1F6;NUSHU CHARACTER-1B1F6;Lo;0;L;;;;;N;;;;;
+1B1F7;NUSHU CHARACTER-1B1F7;Lo;0;L;;;;;N;;;;;
+1B1F8;NUSHU CHARACTER-1B1F8;Lo;0;L;;;;;N;;;;;
+1B1F9;NUSHU CHARACTER-1B1F9;Lo;0;L;;;;;N;;;;;
+1B1FA;NUSHU CHARACTER-1B1FA;Lo;0;L;;;;;N;;;;;
+1B1FB;NUSHU CHARACTER-1B1FB;Lo;0;L;;;;;N;;;;;
+1B1FC;NUSHU CHARACTER-1B1FC;Lo;0;L;;;;;N;;;;;
+1B1FD;NUSHU CHARACTER-1B1FD;Lo;0;L;;;;;N;;;;;
+1B1FE;NUSHU CHARACTER-1B1FE;Lo;0;L;;;;;N;;;;;
+1B1FF;NUSHU CHARACTER-1B1FF;Lo;0;L;;;;;N;;;;;
+1B200;NUSHU CHARACTER-1B200;Lo;0;L;;;;;N;;;;;
+1B201;NUSHU CHARACTER-1B201;Lo;0;L;;;;;N;;;;;
+1B202;NUSHU CHARACTER-1B202;Lo;0;L;;;;;N;;;;;
+1B203;NUSHU CHARACTER-1B203;Lo;0;L;;;;;N;;;;;
+1B204;NUSHU CHARACTER-1B204;Lo;0;L;;;;;N;;;;;
+1B205;NUSHU CHARACTER-1B205;Lo;0;L;;;;;N;;;;;
+1B206;NUSHU CHARACTER-1B206;Lo;0;L;;;;;N;;;;;
+1B207;NUSHU CHARACTER-1B207;Lo;0;L;;;;;N;;;;;
+1B208;NUSHU CHARACTER-1B208;Lo;0;L;;;;;N;;;;;
+1B209;NUSHU CHARACTER-1B209;Lo;0;L;;;;;N;;;;;
+1B20A;NUSHU CHARACTER-1B20A;Lo;0;L;;;;;N;;;;;
+1B20B;NUSHU CHARACTER-1B20B;Lo;0;L;;;;;N;;;;;
+1B20C;NUSHU CHARACTER-1B20C;Lo;0;L;;;;;N;;;;;
+1B20D;NUSHU CHARACTER-1B20D;Lo;0;L;;;;;N;;;;;
+1B20E;NUSHU CHARACTER-1B20E;Lo;0;L;;;;;N;;;;;
+1B20F;NUSHU CHARACTER-1B20F;Lo;0;L;;;;;N;;;;;
+1B210;NUSHU CHARACTER-1B210;Lo;0;L;;;;;N;;;;;
+1B211;NUSHU CHARACTER-1B211;Lo;0;L;;;;;N;;;;;
+1B212;NUSHU CHARACTER-1B212;Lo;0;L;;;;;N;;;;;
+1B213;NUSHU CHARACTER-1B213;Lo;0;L;;;;;N;;;;;
+1B214;NUSHU CHARACTER-1B214;Lo;0;L;;;;;N;;;;;
+1B215;NUSHU CHARACTER-1B215;Lo;0;L;;;;;N;;;;;
+1B216;NUSHU CHARACTER-1B216;Lo;0;L;;;;;N;;;;;
+1B217;NUSHU CHARACTER-1B217;Lo;0;L;;;;;N;;;;;
+1B218;NUSHU CHARACTER-1B218;Lo;0;L;;;;;N;;;;;
+1B219;NUSHU CHARACTER-1B219;Lo;0;L;;;;;N;;;;;
+1B21A;NUSHU CHARACTER-1B21A;Lo;0;L;;;;;N;;;;;
+1B21B;NUSHU CHARACTER-1B21B;Lo;0;L;;;;;N;;;;;
+1B21C;NUSHU CHARACTER-1B21C;Lo;0;L;;;;;N;;;;;
+1B21D;NUSHU CHARACTER-1B21D;Lo;0;L;;;;;N;;;;;
+1B21E;NUSHU CHARACTER-1B21E;Lo;0;L;;;;;N;;;;;
+1B21F;NUSHU CHARACTER-1B21F;Lo;0;L;;;;;N;;;;;
+1B220;NUSHU CHARACTER-1B220;Lo;0;L;;;;;N;;;;;
+1B221;NUSHU CHARACTER-1B221;Lo;0;L;;;;;N;;;;;
+1B222;NUSHU CHARACTER-1B222;Lo;0;L;;;;;N;;;;;
+1B223;NUSHU CHARACTER-1B223;Lo;0;L;;;;;N;;;;;
+1B224;NUSHU CHARACTER-1B224;Lo;0;L;;;;;N;;;;;
+1B225;NUSHU CHARACTER-1B225;Lo;0;L;;;;;N;;;;;
+1B226;NUSHU CHARACTER-1B226;Lo;0;L;;;;;N;;;;;
+1B227;NUSHU CHARACTER-1B227;Lo;0;L;;;;;N;;;;;
+1B228;NUSHU CHARACTER-1B228;Lo;0;L;;;;;N;;;;;
+1B229;NUSHU CHARACTER-1B229;Lo;0;L;;;;;N;;;;;
+1B22A;NUSHU CHARACTER-1B22A;Lo;0;L;;;;;N;;;;;
+1B22B;NUSHU CHARACTER-1B22B;Lo;0;L;;;;;N;;;;;
+1B22C;NUSHU CHARACTER-1B22C;Lo;0;L;;;;;N;;;;;
+1B22D;NUSHU CHARACTER-1B22D;Lo;0;L;;;;;N;;;;;
+1B22E;NUSHU CHARACTER-1B22E;Lo;0;L;;;;;N;;;;;
+1B22F;NUSHU CHARACTER-1B22F;Lo;0;L;;;;;N;;;;;
+1B230;NUSHU CHARACTER-1B230;Lo;0;L;;;;;N;;;;;
+1B231;NUSHU CHARACTER-1B231;Lo;0;L;;;;;N;;;;;
+1B232;NUSHU CHARACTER-1B232;Lo;0;L;;;;;N;;;;;
+1B233;NUSHU CHARACTER-1B233;Lo;0;L;;;;;N;;;;;
+1B234;NUSHU CHARACTER-1B234;Lo;0;L;;;;;N;;;;;
+1B235;NUSHU CHARACTER-1B235;Lo;0;L;;;;;N;;;;;
+1B236;NUSHU CHARACTER-1B236;Lo;0;L;;;;;N;;;;;
+1B237;NUSHU CHARACTER-1B237;Lo;0;L;;;;;N;;;;;
+1B238;NUSHU CHARACTER-1B238;Lo;0;L;;;;;N;;;;;
+1B239;NUSHU CHARACTER-1B239;Lo;0;L;;;;;N;;;;;
+1B23A;NUSHU CHARACTER-1B23A;Lo;0;L;;;;;N;;;;;
+1B23B;NUSHU CHARACTER-1B23B;Lo;0;L;;;;;N;;;;;
+1B23C;NUSHU CHARACTER-1B23C;Lo;0;L;;;;;N;;;;;
+1B23D;NUSHU CHARACTER-1B23D;Lo;0;L;;;;;N;;;;;
+1B23E;NUSHU CHARACTER-1B23E;Lo;0;L;;;;;N;;;;;
+1B23F;NUSHU CHARACTER-1B23F;Lo;0;L;;;;;N;;;;;
+1B240;NUSHU CHARACTER-1B240;Lo;0;L;;;;;N;;;;;
+1B241;NUSHU CHARACTER-1B241;Lo;0;L;;;;;N;;;;;
+1B242;NUSHU CHARACTER-1B242;Lo;0;L;;;;;N;;;;;
+1B243;NUSHU CHARACTER-1B243;Lo;0;L;;;;;N;;;;;
+1B244;NUSHU CHARACTER-1B244;Lo;0;L;;;;;N;;;;;
+1B245;NUSHU CHARACTER-1B245;Lo;0;L;;;;;N;;;;;
+1B246;NUSHU CHARACTER-1B246;Lo;0;L;;;;;N;;;;;
+1B247;NUSHU CHARACTER-1B247;Lo;0;L;;;;;N;;;;;
+1B248;NUSHU CHARACTER-1B248;Lo;0;L;;;;;N;;;;;
+1B249;NUSHU CHARACTER-1B249;Lo;0;L;;;;;N;;;;;
+1B24A;NUSHU CHARACTER-1B24A;Lo;0;L;;;;;N;;;;;
+1B24B;NUSHU CHARACTER-1B24B;Lo;0;L;;;;;N;;;;;
+1B24C;NUSHU CHARACTER-1B24C;Lo;0;L;;;;;N;;;;;
+1B24D;NUSHU CHARACTER-1B24D;Lo;0;L;;;;;N;;;;;
+1B24E;NUSHU CHARACTER-1B24E;Lo;0;L;;;;;N;;;;;
+1B24F;NUSHU CHARACTER-1B24F;Lo;0;L;;;;;N;;;;;
+1B250;NUSHU CHARACTER-1B250;Lo;0;L;;;;;N;;;;;
+1B251;NUSHU CHARACTER-1B251;Lo;0;L;;;;;N;;;;;
+1B252;NUSHU CHARACTER-1B252;Lo;0;L;;;;;N;;;;;
+1B253;NUSHU CHARACTER-1B253;Lo;0;L;;;;;N;;;;;
+1B254;NUSHU CHARACTER-1B254;Lo;0;L;;;;;N;;;;;
+1B255;NUSHU CHARACTER-1B255;Lo;0;L;;;;;N;;;;;
+1B256;NUSHU CHARACTER-1B256;Lo;0;L;;;;;N;;;;;
+1B257;NUSHU CHARACTER-1B257;Lo;0;L;;;;;N;;;;;
+1B258;NUSHU CHARACTER-1B258;Lo;0;L;;;;;N;;;;;
+1B259;NUSHU CHARACTER-1B259;Lo;0;L;;;;;N;;;;;
+1B25A;NUSHU CHARACTER-1B25A;Lo;0;L;;;;;N;;;;;
+1B25B;NUSHU CHARACTER-1B25B;Lo;0;L;;;;;N;;;;;
+1B25C;NUSHU CHARACTER-1B25C;Lo;0;L;;;;;N;;;;;
+1B25D;NUSHU CHARACTER-1B25D;Lo;0;L;;;;;N;;;;;
+1B25E;NUSHU CHARACTER-1B25E;Lo;0;L;;;;;N;;;;;
+1B25F;NUSHU CHARACTER-1B25F;Lo;0;L;;;;;N;;;;;
+1B260;NUSHU CHARACTER-1B260;Lo;0;L;;;;;N;;;;;
+1B261;NUSHU CHARACTER-1B261;Lo;0;L;;;;;N;;;;;
+1B262;NUSHU CHARACTER-1B262;Lo;0;L;;;;;N;;;;;
+1B263;NUSHU CHARACTER-1B263;Lo;0;L;;;;;N;;;;;
+1B264;NUSHU CHARACTER-1B264;Lo;0;L;;;;;N;;;;;
+1B265;NUSHU CHARACTER-1B265;Lo;0;L;;;;;N;;;;;
+1B266;NUSHU CHARACTER-1B266;Lo;0;L;;;;;N;;;;;
+1B267;NUSHU CHARACTER-1B267;Lo;0;L;;;;;N;;;;;
+1B268;NUSHU CHARACTER-1B268;Lo;0;L;;;;;N;;;;;
+1B269;NUSHU CHARACTER-1B269;Lo;0;L;;;;;N;;;;;
+1B26A;NUSHU CHARACTER-1B26A;Lo;0;L;;;;;N;;;;;
+1B26B;NUSHU CHARACTER-1B26B;Lo;0;L;;;;;N;;;;;
+1B26C;NUSHU CHARACTER-1B26C;Lo;0;L;;;;;N;;;;;
+1B26D;NUSHU CHARACTER-1B26D;Lo;0;L;;;;;N;;;;;
+1B26E;NUSHU CHARACTER-1B26E;Lo;0;L;;;;;N;;;;;
+1B26F;NUSHU CHARACTER-1B26F;Lo;0;L;;;;;N;;;;;
+1B270;NUSHU CHARACTER-1B270;Lo;0;L;;;;;N;;;;;
+1B271;NUSHU CHARACTER-1B271;Lo;0;L;;;;;N;;;;;
+1B272;NUSHU CHARACTER-1B272;Lo;0;L;;;;;N;;;;;
+1B273;NUSHU CHARACTER-1B273;Lo;0;L;;;;;N;;;;;
+1B274;NUSHU CHARACTER-1B274;Lo;0;L;;;;;N;;;;;
+1B275;NUSHU CHARACTER-1B275;Lo;0;L;;;;;N;;;;;
+1B276;NUSHU CHARACTER-1B276;Lo;0;L;;;;;N;;;;;
+1B277;NUSHU CHARACTER-1B277;Lo;0;L;;;;;N;;;;;
+1B278;NUSHU CHARACTER-1B278;Lo;0;L;;;;;N;;;;;
+1B279;NUSHU CHARACTER-1B279;Lo;0;L;;;;;N;;;;;
+1B27A;NUSHU CHARACTER-1B27A;Lo;0;L;;;;;N;;;;;
+1B27B;NUSHU CHARACTER-1B27B;Lo;0;L;;;;;N;;;;;
+1B27C;NUSHU CHARACTER-1B27C;Lo;0;L;;;;;N;;;;;
+1B27D;NUSHU CHARACTER-1B27D;Lo;0;L;;;;;N;;;;;
+1B27E;NUSHU CHARACTER-1B27E;Lo;0;L;;;;;N;;;;;
+1B27F;NUSHU CHARACTER-1B27F;Lo;0;L;;;;;N;;;;;
+1B280;NUSHU CHARACTER-1B280;Lo;0;L;;;;;N;;;;;
+1B281;NUSHU CHARACTER-1B281;Lo;0;L;;;;;N;;;;;
+1B282;NUSHU CHARACTER-1B282;Lo;0;L;;;;;N;;;;;
+1B283;NUSHU CHARACTER-1B283;Lo;0;L;;;;;N;;;;;
+1B284;NUSHU CHARACTER-1B284;Lo;0;L;;;;;N;;;;;
+1B285;NUSHU CHARACTER-1B285;Lo;0;L;;;;;N;;;;;
+1B286;NUSHU CHARACTER-1B286;Lo;0;L;;;;;N;;;;;
+1B287;NUSHU CHARACTER-1B287;Lo;0;L;;;;;N;;;;;
+1B288;NUSHU CHARACTER-1B288;Lo;0;L;;;;;N;;;;;
+1B289;NUSHU CHARACTER-1B289;Lo;0;L;;;;;N;;;;;
+1B28A;NUSHU CHARACTER-1B28A;Lo;0;L;;;;;N;;;;;
+1B28B;NUSHU CHARACTER-1B28B;Lo;0;L;;;;;N;;;;;
+1B28C;NUSHU CHARACTER-1B28C;Lo;0;L;;;;;N;;;;;
+1B28D;NUSHU CHARACTER-1B28D;Lo;0;L;;;;;N;;;;;
+1B28E;NUSHU CHARACTER-1B28E;Lo;0;L;;;;;N;;;;;
+1B28F;NUSHU CHARACTER-1B28F;Lo;0;L;;;;;N;;;;;
+1B290;NUSHU CHARACTER-1B290;Lo;0;L;;;;;N;;;;;
+1B291;NUSHU CHARACTER-1B291;Lo;0;L;;;;;N;;;;;
+1B292;NUSHU CHARACTER-1B292;Lo;0;L;;;;;N;;;;;
+1B293;NUSHU CHARACTER-1B293;Lo;0;L;;;;;N;;;;;
+1B294;NUSHU CHARACTER-1B294;Lo;0;L;;;;;N;;;;;
+1B295;NUSHU CHARACTER-1B295;Lo;0;L;;;;;N;;;;;
+1B296;NUSHU CHARACTER-1B296;Lo;0;L;;;;;N;;;;;
+1B297;NUSHU CHARACTER-1B297;Lo;0;L;;;;;N;;;;;
+1B298;NUSHU CHARACTER-1B298;Lo;0;L;;;;;N;;;;;
+1B299;NUSHU CHARACTER-1B299;Lo;0;L;;;;;N;;;;;
+1B29A;NUSHU CHARACTER-1B29A;Lo;0;L;;;;;N;;;;;
+1B29B;NUSHU CHARACTER-1B29B;Lo;0;L;;;;;N;;;;;
+1B29C;NUSHU CHARACTER-1B29C;Lo;0;L;;;;;N;;;;;
+1B29D;NUSHU CHARACTER-1B29D;Lo;0;L;;;;;N;;;;;
+1B29E;NUSHU CHARACTER-1B29E;Lo;0;L;;;;;N;;;;;
+1B29F;NUSHU CHARACTER-1B29F;Lo;0;L;;;;;N;;;;;
+1B2A0;NUSHU CHARACTER-1B2A0;Lo;0;L;;;;;N;;;;;
+1B2A1;NUSHU CHARACTER-1B2A1;Lo;0;L;;;;;N;;;;;
+1B2A2;NUSHU CHARACTER-1B2A2;Lo;0;L;;;;;N;;;;;
+1B2A3;NUSHU CHARACTER-1B2A3;Lo;0;L;;;;;N;;;;;
+1B2A4;NUSHU CHARACTER-1B2A4;Lo;0;L;;;;;N;;;;;
+1B2A5;NUSHU CHARACTER-1B2A5;Lo;0;L;;;;;N;;;;;
+1B2A6;NUSHU CHARACTER-1B2A6;Lo;0;L;;;;;N;;;;;
+1B2A7;NUSHU CHARACTER-1B2A7;Lo;0;L;;;;;N;;;;;
+1B2A8;NUSHU CHARACTER-1B2A8;Lo;0;L;;;;;N;;;;;
+1B2A9;NUSHU CHARACTER-1B2A9;Lo;0;L;;;;;N;;;;;
+1B2AA;NUSHU CHARACTER-1B2AA;Lo;0;L;;;;;N;;;;;
+1B2AB;NUSHU CHARACTER-1B2AB;Lo;0;L;;;;;N;;;;;
+1B2AC;NUSHU CHARACTER-1B2AC;Lo;0;L;;;;;N;;;;;
+1B2AD;NUSHU CHARACTER-1B2AD;Lo;0;L;;;;;N;;;;;
+1B2AE;NUSHU CHARACTER-1B2AE;Lo;0;L;;;;;N;;;;;
+1B2AF;NUSHU CHARACTER-1B2AF;Lo;0;L;;;;;N;;;;;
+1B2B0;NUSHU CHARACTER-1B2B0;Lo;0;L;;;;;N;;;;;
+1B2B1;NUSHU CHARACTER-1B2B1;Lo;0;L;;;;;N;;;;;
+1B2B2;NUSHU CHARACTER-1B2B2;Lo;0;L;;;;;N;;;;;
+1B2B3;NUSHU CHARACTER-1B2B3;Lo;0;L;;;;;N;;;;;
+1B2B4;NUSHU CHARACTER-1B2B4;Lo;0;L;;;;;N;;;;;
+1B2B5;NUSHU CHARACTER-1B2B5;Lo;0;L;;;;;N;;;;;
+1B2B6;NUSHU CHARACTER-1B2B6;Lo;0;L;;;;;N;;;;;
+1B2B7;NUSHU CHARACTER-1B2B7;Lo;0;L;;;;;N;;;;;
+1B2B8;NUSHU CHARACTER-1B2B8;Lo;0;L;;;;;N;;;;;
+1B2B9;NUSHU CHARACTER-1B2B9;Lo;0;L;;;;;N;;;;;
+1B2BA;NUSHU CHARACTER-1B2BA;Lo;0;L;;;;;N;;;;;
+1B2BB;NUSHU CHARACTER-1B2BB;Lo;0;L;;;;;N;;;;;
+1B2BC;NUSHU CHARACTER-1B2BC;Lo;0;L;;;;;N;;;;;
+1B2BD;NUSHU CHARACTER-1B2BD;Lo;0;L;;;;;N;;;;;
+1B2BE;NUSHU CHARACTER-1B2BE;Lo;0;L;;;;;N;;;;;
+1B2BF;NUSHU CHARACTER-1B2BF;Lo;0;L;;;;;N;;;;;
+1B2C0;NUSHU CHARACTER-1B2C0;Lo;0;L;;;;;N;;;;;
+1B2C1;NUSHU CHARACTER-1B2C1;Lo;0;L;;;;;N;;;;;
+1B2C2;NUSHU CHARACTER-1B2C2;Lo;0;L;;;;;N;;;;;
+1B2C3;NUSHU CHARACTER-1B2C3;Lo;0;L;;;;;N;;;;;
+1B2C4;NUSHU CHARACTER-1B2C4;Lo;0;L;;;;;N;;;;;
+1B2C5;NUSHU CHARACTER-1B2C5;Lo;0;L;;;;;N;;;;;
+1B2C6;NUSHU CHARACTER-1B2C6;Lo;0;L;;;;;N;;;;;
+1B2C7;NUSHU CHARACTER-1B2C7;Lo;0;L;;;;;N;;;;;
+1B2C8;NUSHU CHARACTER-1B2C8;Lo;0;L;;;;;N;;;;;
+1B2C9;NUSHU CHARACTER-1B2C9;Lo;0;L;;;;;N;;;;;
+1B2CA;NUSHU CHARACTER-1B2CA;Lo;0;L;;;;;N;;;;;
+1B2CB;NUSHU CHARACTER-1B2CB;Lo;0;L;;;;;N;;;;;
+1B2CC;NUSHU CHARACTER-1B2CC;Lo;0;L;;;;;N;;;;;
+1B2CD;NUSHU CHARACTER-1B2CD;Lo;0;L;;;;;N;;;;;
+1B2CE;NUSHU CHARACTER-1B2CE;Lo;0;L;;;;;N;;;;;
+1B2CF;NUSHU CHARACTER-1B2CF;Lo;0;L;;;;;N;;;;;
+1B2D0;NUSHU CHARACTER-1B2D0;Lo;0;L;;;;;N;;;;;
+1B2D1;NUSHU CHARACTER-1B2D1;Lo;0;L;;;;;N;;;;;
+1B2D2;NUSHU CHARACTER-1B2D2;Lo;0;L;;;;;N;;;;;
+1B2D3;NUSHU CHARACTER-1B2D3;Lo;0;L;;;;;N;;;;;
+1B2D4;NUSHU CHARACTER-1B2D4;Lo;0;L;;;;;N;;;;;
+1B2D5;NUSHU CHARACTER-1B2D5;Lo;0;L;;;;;N;;;;;
+1B2D6;NUSHU CHARACTER-1B2D6;Lo;0;L;;;;;N;;;;;
+1B2D7;NUSHU CHARACTER-1B2D7;Lo;0;L;;;;;N;;;;;
+1B2D8;NUSHU CHARACTER-1B2D8;Lo;0;L;;;;;N;;;;;
+1B2D9;NUSHU CHARACTER-1B2D9;Lo;0;L;;;;;N;;;;;
+1B2DA;NUSHU CHARACTER-1B2DA;Lo;0;L;;;;;N;;;;;
+1B2DB;NUSHU CHARACTER-1B2DB;Lo;0;L;;;;;N;;;;;
+1B2DC;NUSHU CHARACTER-1B2DC;Lo;0;L;;;;;N;;;;;
+1B2DD;NUSHU CHARACTER-1B2DD;Lo;0;L;;;;;N;;;;;
+1B2DE;NUSHU CHARACTER-1B2DE;Lo;0;L;;;;;N;;;;;
+1B2DF;NUSHU CHARACTER-1B2DF;Lo;0;L;;;;;N;;;;;
+1B2E0;NUSHU CHARACTER-1B2E0;Lo;0;L;;;;;N;;;;;
+1B2E1;NUSHU CHARACTER-1B2E1;Lo;0;L;;;;;N;;;;;
+1B2E2;NUSHU CHARACTER-1B2E2;Lo;0;L;;;;;N;;;;;
+1B2E3;NUSHU CHARACTER-1B2E3;Lo;0;L;;;;;N;;;;;
+1B2E4;NUSHU CHARACTER-1B2E4;Lo;0;L;;;;;N;;;;;
+1B2E5;NUSHU CHARACTER-1B2E5;Lo;0;L;;;;;N;;;;;
+1B2E6;NUSHU CHARACTER-1B2E6;Lo;0;L;;;;;N;;;;;
+1B2E7;NUSHU CHARACTER-1B2E7;Lo;0;L;;;;;N;;;;;
+1B2E8;NUSHU CHARACTER-1B2E8;Lo;0;L;;;;;N;;;;;
+1B2E9;NUSHU CHARACTER-1B2E9;Lo;0;L;;;;;N;;;;;
+1B2EA;NUSHU CHARACTER-1B2EA;Lo;0;L;;;;;N;;;;;
+1B2EB;NUSHU CHARACTER-1B2EB;Lo;0;L;;;;;N;;;;;
+1B2EC;NUSHU CHARACTER-1B2EC;Lo;0;L;;;;;N;;;;;
+1B2ED;NUSHU CHARACTER-1B2ED;Lo;0;L;;;;;N;;;;;
+1B2EE;NUSHU CHARACTER-1B2EE;Lo;0;L;;;;;N;;;;;
+1B2EF;NUSHU CHARACTER-1B2EF;Lo;0;L;;;;;N;;;;;
+1B2F0;NUSHU CHARACTER-1B2F0;Lo;0;L;;;;;N;;;;;
+1B2F1;NUSHU CHARACTER-1B2F1;Lo;0;L;;;;;N;;;;;
+1B2F2;NUSHU CHARACTER-1B2F2;Lo;0;L;;;;;N;;;;;
+1B2F3;NUSHU CHARACTER-1B2F3;Lo;0;L;;;;;N;;;;;
+1B2F4;NUSHU CHARACTER-1B2F4;Lo;0;L;;;;;N;;;;;
+1B2F5;NUSHU CHARACTER-1B2F5;Lo;0;L;;;;;N;;;;;
+1B2F6;NUSHU CHARACTER-1B2F6;Lo;0;L;;;;;N;;;;;
+1B2F7;NUSHU CHARACTER-1B2F7;Lo;0;L;;;;;N;;;;;
+1B2F8;NUSHU CHARACTER-1B2F8;Lo;0;L;;;;;N;;;;;
+1B2F9;NUSHU CHARACTER-1B2F9;Lo;0;L;;;;;N;;;;;
+1B2FA;NUSHU CHARACTER-1B2FA;Lo;0;L;;;;;N;;;;;
+1B2FB;NUSHU CHARACTER-1B2FB;Lo;0;L;;;;;N;;;;;
1BC00;DUPLOYAN LETTER H;Lo;0;L;;;;;N;;;;;
1BC01;DUPLOYAN LETTER X;Lo;0;L;;;;;N;;;;;
1BC02;DUPLOYAN LETTER P;Lo;0;L;;;;;N;;;;;
@@ -25540,6 +26982,26 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1D243;COMBINING GREEK MUSICAL TETRASEME;Mn;230;NSM;;;;;N;;;;;
1D244;COMBINING GREEK MUSICAL PENTASEME;Mn;230;NSM;;;;;N;;;;;
1D245;GREEK MUSICAL LEIMMA;So;0;ON;;;;;N;;;;;
+1D2E0;MAYAN NUMERAL ZERO;No;0;L;;;;0;N;;;;;
+1D2E1;MAYAN NUMERAL ONE;No;0;L;;;;1;N;;;;;
+1D2E2;MAYAN NUMERAL TWO;No;0;L;;;;2;N;;;;;
+1D2E3;MAYAN NUMERAL THREE;No;0;L;;;;3;N;;;;;
+1D2E4;MAYAN NUMERAL FOUR;No;0;L;;;;4;N;;;;;
+1D2E5;MAYAN NUMERAL FIVE;No;0;L;;;;5;N;;;;;
+1D2E6;MAYAN NUMERAL SIX;No;0;L;;;;6;N;;;;;
+1D2E7;MAYAN NUMERAL SEVEN;No;0;L;;;;7;N;;;;;
+1D2E8;MAYAN NUMERAL EIGHT;No;0;L;;;;8;N;;;;;
+1D2E9;MAYAN NUMERAL NINE;No;0;L;;;;9;N;;;;;
+1D2EA;MAYAN NUMERAL TEN;No;0;L;;;;10;N;;;;;
+1D2EB;MAYAN NUMERAL ELEVEN;No;0;L;;;;11;N;;;;;
+1D2EC;MAYAN NUMERAL TWELVE;No;0;L;;;;12;N;;;;;
+1D2ED;MAYAN NUMERAL THIRTEEN;No;0;L;;;;13;N;;;;;
+1D2EE;MAYAN NUMERAL FOURTEEN;No;0;L;;;;14;N;;;;;
+1D2EF;MAYAN NUMERAL FIFTEEN;No;0;L;;;;15;N;;;;;
+1D2F0;MAYAN NUMERAL SIXTEEN;No;0;L;;;;16;N;;;;;
+1D2F1;MAYAN NUMERAL SEVENTEEN;No;0;L;;;;17;N;;;;;
+1D2F2;MAYAN NUMERAL EIGHTEEN;No;0;L;;;;18;N;;;;;
+1D2F3;MAYAN NUMERAL NINETEEN;No;0;L;;;;19;N;;;;;
1D300;MONOGRAM FOR EARTH;So;0;ON;;;;;N;;;;;
1D301;DIGRAM FOR HEAVENLY EARTH;So;0;ON;;;;;N;;;;;
1D302;DIGRAM FOR HUMAN EARTH;So;0;ON;;;;;N;;;;;
@@ -25645,6 +27107,13 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1D36F;COUNTING ROD TENS DIGIT SEVEN;No;0;L;;;;70;N;;;;;
1D370;COUNTING ROD TENS DIGIT EIGHT;No;0;L;;;;80;N;;;;;
1D371;COUNTING ROD TENS DIGIT NINE;No;0;L;;;;90;N;;;;;
+1D372;IDEOGRAPHIC TALLY MARK ONE;No;0;L;;;;1;N;;;;;
+1D373;IDEOGRAPHIC TALLY MARK TWO;No;0;L;;;;2;N;;;;;
+1D374;IDEOGRAPHIC TALLY MARK THREE;No;0;L;;;;3;N;;;;;
+1D375;IDEOGRAPHIC TALLY MARK FOUR;No;0;L;;;;4;N;;;;;
+1D376;IDEOGRAPHIC TALLY MARK FIVE;No;0;L;;;;5;N;;;;;
+1D377;TALLY MARK ONE;No;0;L;;;;1;N;;;;;
+1D378;TALLY MARK FIVE;No;0;L;;;;5;N;;;;;
1D400;MATHEMATICAL BOLD CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
1D401;MATHEMATICAL BOLD CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
1D402;MATHEMATICAL BOLD CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
@@ -27651,6 +29120,74 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1E959;ADLAM DIGIT NINE;Nd;0;R;;9;9;9;N;;;;;
1E95E;ADLAM INITIAL EXCLAMATION MARK;Po;0;R;;;;;N;;;;;
1E95F;ADLAM INITIAL QUESTION MARK;Po;0;R;;;;;N;;;;;
+1EC71;INDIC SIYAQ NUMBER ONE;No;0;AL;;;;1;N;;;;;
+1EC72;INDIC SIYAQ NUMBER TWO;No;0;AL;;;;2;N;;;;;
+1EC73;INDIC SIYAQ NUMBER THREE;No;0;AL;;;;3;N;;;;;
+1EC74;INDIC SIYAQ NUMBER FOUR;No;0;AL;;;;4;N;;;;;
+1EC75;INDIC SIYAQ NUMBER FIVE;No;0;AL;;;;5;N;;;;;
+1EC76;INDIC SIYAQ NUMBER SIX;No;0;AL;;;;6;N;;;;;
+1EC77;INDIC SIYAQ NUMBER SEVEN;No;0;AL;;;;7;N;;;;;
+1EC78;INDIC SIYAQ NUMBER EIGHT;No;0;AL;;;;8;N;;;;;
+1EC79;INDIC SIYAQ NUMBER NINE;No;0;AL;;;;9;N;;;;;
+1EC7A;INDIC SIYAQ NUMBER TEN;No;0;AL;;;;10;N;;;;;
+1EC7B;INDIC SIYAQ NUMBER TWENTY;No;0;AL;;;;20;N;;;;;
+1EC7C;INDIC SIYAQ NUMBER THIRTY;No;0;AL;;;;30;N;;;;;
+1EC7D;INDIC SIYAQ NUMBER FORTY;No;0;AL;;;;40;N;;;;;
+1EC7E;INDIC SIYAQ NUMBER FIFTY;No;0;AL;;;;50;N;;;;;
+1EC7F;INDIC SIYAQ NUMBER SIXTY;No;0;AL;;;;60;N;;;;;
+1EC80;INDIC SIYAQ NUMBER SEVENTY;No;0;AL;;;;70;N;;;;;
+1EC81;INDIC SIYAQ NUMBER EIGHTY;No;0;AL;;;;80;N;;;;;
+1EC82;INDIC SIYAQ NUMBER NINETY;No;0;AL;;;;90;N;;;;;
+1EC83;INDIC SIYAQ NUMBER ONE HUNDRED;No;0;AL;;;;100;N;;;;;
+1EC84;INDIC SIYAQ NUMBER TWO HUNDRED;No;0;AL;;;;200;N;;;;;
+1EC85;INDIC SIYAQ NUMBER THREE HUNDRED;No;0;AL;;;;300;N;;;;;
+1EC86;INDIC SIYAQ NUMBER FOUR HUNDRED;No;0;AL;;;;400;N;;;;;
+1EC87;INDIC SIYAQ NUMBER FIVE HUNDRED;No;0;AL;;;;500;N;;;;;
+1EC88;INDIC SIYAQ NUMBER SIX HUNDRED;No;0;AL;;;;600;N;;;;;
+1EC89;INDIC SIYAQ NUMBER SEVEN HUNDRED;No;0;AL;;;;700;N;;;;;
+1EC8A;INDIC SIYAQ NUMBER EIGHT HUNDRED;No;0;AL;;;;800;N;;;;;
+1EC8B;INDIC SIYAQ NUMBER NINE HUNDRED;No;0;AL;;;;900;N;;;;;
+1EC8C;INDIC SIYAQ NUMBER ONE THOUSAND;No;0;AL;;;;1000;N;;;;;
+1EC8D;INDIC SIYAQ NUMBER TWO THOUSAND;No;0;AL;;;;2000;N;;;;;
+1EC8E;INDIC SIYAQ NUMBER THREE THOUSAND;No;0;AL;;;;3000;N;;;;;
+1EC8F;INDIC SIYAQ NUMBER FOUR THOUSAND;No;0;AL;;;;4000;N;;;;;
+1EC90;INDIC SIYAQ NUMBER FIVE THOUSAND;No;0;AL;;;;5000;N;;;;;
+1EC91;INDIC SIYAQ NUMBER SIX THOUSAND;No;0;AL;;;;6000;N;;;;;
+1EC92;INDIC SIYAQ NUMBER SEVEN THOUSAND;No;0;AL;;;;7000;N;;;;;
+1EC93;INDIC SIYAQ NUMBER EIGHT THOUSAND;No;0;AL;;;;8000;N;;;;;
+1EC94;INDIC SIYAQ NUMBER NINE THOUSAND;No;0;AL;;;;9000;N;;;;;
+1EC95;INDIC SIYAQ NUMBER TEN THOUSAND;No;0;AL;;;;10000;N;;;;;
+1EC96;INDIC SIYAQ NUMBER TWENTY THOUSAND;No;0;AL;;;;20000;N;;;;;
+1EC97;INDIC SIYAQ NUMBER THIRTY THOUSAND;No;0;AL;;;;30000;N;;;;;
+1EC98;INDIC SIYAQ NUMBER FORTY THOUSAND;No;0;AL;;;;40000;N;;;;;
+1EC99;INDIC SIYAQ NUMBER FIFTY THOUSAND;No;0;AL;;;;50000;N;;;;;
+1EC9A;INDIC SIYAQ NUMBER SIXTY THOUSAND;No;0;AL;;;;60000;N;;;;;
+1EC9B;INDIC SIYAQ NUMBER SEVENTY THOUSAND;No;0;AL;;;;70000;N;;;;;
+1EC9C;INDIC SIYAQ NUMBER EIGHTY THOUSAND;No;0;AL;;;;80000;N;;;;;
+1EC9D;INDIC SIYAQ NUMBER NINETY THOUSAND;No;0;AL;;;;90000;N;;;;;
+1EC9E;INDIC SIYAQ NUMBER LAKH;No;0;AL;;;;100000;N;;;;;
+1EC9F;INDIC SIYAQ NUMBER LAKHAN;No;0;AL;;;;200000;N;;;;;
+1ECA0;INDIC SIYAQ LAKH MARK;No;0;AL;;;;100000;N;;;;;
+1ECA1;INDIC SIYAQ NUMBER KAROR;No;0;AL;;;;10000000;N;;;;;
+1ECA2;INDIC SIYAQ NUMBER KARORAN;No;0;AL;;;;20000000;N;;;;;
+1ECA3;INDIC SIYAQ NUMBER PREFIXED ONE;No;0;AL;;;;1;N;;;;;
+1ECA4;INDIC SIYAQ NUMBER PREFIXED TWO;No;0;AL;;;;2;N;;;;;
+1ECA5;INDIC SIYAQ NUMBER PREFIXED THREE;No;0;AL;;;;3;N;;;;;
+1ECA6;INDIC SIYAQ NUMBER PREFIXED FOUR;No;0;AL;;;;4;N;;;;;
+1ECA7;INDIC SIYAQ NUMBER PREFIXED FIVE;No;0;AL;;;;5;N;;;;;
+1ECA8;INDIC SIYAQ NUMBER PREFIXED SIX;No;0;AL;;;;6;N;;;;;
+1ECA9;INDIC SIYAQ NUMBER PREFIXED SEVEN;No;0;AL;;;;7;N;;;;;
+1ECAA;INDIC SIYAQ NUMBER PREFIXED EIGHT;No;0;AL;;;;8;N;;;;;
+1ECAB;INDIC SIYAQ NUMBER PREFIXED NINE;No;0;AL;;;;9;N;;;;;
+1ECAC;INDIC SIYAQ PLACEHOLDER;So;0;AL;;;;;N;;;;;
+1ECAD;INDIC SIYAQ FRACTION ONE QUARTER;No;0;AL;;;;1/4;N;;;;;
+1ECAE;INDIC SIYAQ FRACTION ONE HALF;No;0;AL;;;;1/2;N;;;;;
+1ECAF;INDIC SIYAQ FRACTION THREE QUARTERS;No;0;AL;;;;3/4;N;;;;;
+1ECB0;INDIC SIYAQ RUPEE MARK;Sc;0;AL;;;;;N;;;;;
+1ECB1;INDIC SIYAQ NUMBER ALTERNATE ONE;No;0;AL;;;;1;N;;;;;
+1ECB2;INDIC SIYAQ NUMBER ALTERNATE TWO;No;0;AL;;;;2;N;;;;;
+1ECB3;INDIC SIYAQ NUMBER ALTERNATE TEN THOUSAND;No;0;AL;;;;10000;N;;;;;
+1ECB4;INDIC SIYAQ ALTERNATE LAKH MARK;No;0;AL;;;;100000;N;;;;;
1EE00;ARABIC MATHEMATICAL ALEF;Lo;0;AL;<font> 0627;;;;N;;;;;
1EE01;ARABIC MATHEMATICAL BEH;Lo;0;AL;<font> 0628;;;;N;;;;;
1EE02;ARABIC MATHEMATICAL JEEM;Lo;0;AL;<font> 062C;;;;N;;;;;
@@ -28064,6 +29601,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F12C;CIRCLED ITALIC LATIN CAPITAL LETTER R;So;0;L;<circle> 0052;;;;N;;;;;
1F12D;CIRCLED CD;So;0;L;<circle> 0043 0044;;;;N;;;;;
1F12E;CIRCLED WZ;So;0;L;<circle> 0057 005A;;;;N;;;;;
+1F12F;COPYLEFT SYMBOL;So;0;ON;;;;;N;;;;;
1F130;SQUARED LATIN CAPITAL LETTER A;So;0;L;<square> 0041;;;;N;;;;;
1F131;SQUARED LATIN CAPITAL LETTER B;So;0;L;<square> 0042;;;;N;;;;;
1F132;SQUARED LATIN CAPITAL LETTER C;So;0;L;<square> 0043;;;;N;;;;;
@@ -28269,6 +29807,12 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F248;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557;So;0;L;<compat> 3014 6557 3015;;;;N;;;;;
1F250;CIRCLED IDEOGRAPH ADVANTAGE;So;0;L;<circle> 5F97;;;;N;;;;;
1F251;CIRCLED IDEOGRAPH ACCEPT;So;0;L;<circle> 53EF;;;;N;;;;;
+1F260;ROUNDED SYMBOL FOR FU;So;0;ON;;;;;N;;;;;
+1F261;ROUNDED SYMBOL FOR LU;So;0;ON;;;;;N;;;;;
+1F262;ROUNDED SYMBOL FOR SHOU;So;0;ON;;;;;N;;;;;
+1F263;ROUNDED SYMBOL FOR XI;So;0;ON;;;;;N;;;;;
+1F264;ROUNDED SYMBOL FOR SHUANGXI;So;0;ON;;;;;N;;;;;
+1F265;ROUNDED SYMBOL FOR CAI;So;0;ON;;;;;N;;;;;
1F300;CYCLONE;So;0;ON;;;;;N;;;;;
1F301;FOGGY;So;0;ON;;;;;N;;;;;
1F302;CLOSED UMBRELLA;So;0;ON;;;;;N;;;;;
@@ -29248,6 +30792,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F6D0;PLACE OF WORSHIP;So;0;ON;;;;;N;;;;;
1F6D1;OCTAGONAL SIGN;So;0;ON;;;;;N;;;;;
1F6D2;SHOPPING TROLLEY;So;0;ON;;;;;N;;;;;
+1F6D3;STUPA;So;0;ON;;;;;N;;;;;
+1F6D4;PAGODA;So;0;ON;;;;;N;;;;;
1F6E0;HAMMER AND WRENCH;So;0;ON;;;;;N;;;;;
1F6E1;SHIELD;So;0;ON;;;;;N;;;;;
1F6E2;OIL DRUM;So;0;ON;;;;;N;;;;;
@@ -29268,6 +30814,9 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F6F4;SCOOTER;So;0;ON;;;;;N;;;;;
1F6F5;MOTOR SCOOTER;So;0;ON;;;;;N;;;;;
1F6F6;CANOE;So;0;ON;;;;;N;;;;;
+1F6F7;SLED;So;0;ON;;;;;N;;;;;
+1F6F8;FLYING SAUCER;So;0;ON;;;;;N;;;;;
+1F6F9;SKATEBOARD;So;0;ON;;;;;N;;;;;
1F700;ALCHEMICAL SYMBOL FOR QUINTESSENCE;So;0;ON;;;;;N;;;;;
1F701;ALCHEMICAL SYMBOL FOR AIR;So;0;ON;;;;;N;;;;;
1F702;ALCHEMICAL SYMBOL FOR FIRE;So;0;ON;;;;;N;;;;;
@@ -29469,6 +31018,10 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F7D2;LIGHT TWELVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
1F7D3;HEAVY TWELVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
1F7D4;HEAVY TWELVE POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;;
+1F7D5;CIRCLED TRIANGLE;So;0;ON;;;;;N;;;;;
+1F7D6;NEGATIVE CIRCLED TRIANGLE;So;0;ON;;;;;N;;;;;
+1F7D7;CIRCLED SQUARE;So;0;ON;;;;;N;;;;;
+1F7D8;NEGATIVE CIRCLED SQUARE;So;0;ON;;;;;N;;;;;
1F800;LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;
1F801;UPWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;
1F802;RIGHTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;
@@ -29617,6 +31170,18 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F8AB;RIGHTWARDS FRONT-TILTED SHADOWED WHITE ARROW;So;0;ON;;;;;N;;;;;
1F8AC;WHITE ARROW SHAFT WIDTH ONE;So;0;ON;;;;;N;;;;;
1F8AD;WHITE ARROW SHAFT WIDTH TWO THIRDS;So;0;ON;;;;;N;;;;;
+1F900;CIRCLED CROSS FORMEE WITH FOUR DOTS;So;0;ON;;;;;N;;;;;
+1F901;CIRCLED CROSS FORMEE WITH TWO DOTS;So;0;ON;;;;;N;;;;;
+1F902;CIRCLED CROSS FORMEE;So;0;ON;;;;;N;;;;;
+1F903;LEFT HALF CIRCLE WITH FOUR DOTS;So;0;ON;;;;;N;;;;;
+1F904;LEFT HALF CIRCLE WITH THREE DOTS;So;0;ON;;;;;N;;;;;
+1F905;LEFT HALF CIRCLE WITH TWO DOTS;So;0;ON;;;;;N;;;;;
+1F906;LEFT HALF CIRCLE WITH DOT;So;0;ON;;;;;N;;;;;
+1F907;LEFT HALF CIRCLE;So;0;ON;;;;;N;;;;;
+1F908;DOWNWARD FACING HOOK;So;0;ON;;;;;N;;;;;
+1F909;DOWNWARD FACING NOTCHED HOOK;So;0;ON;;;;;N;;;;;
+1F90A;DOWNWARD FACING HOOK WITH DOT;So;0;ON;;;;;N;;;;;
+1F90B;DOWNWARD FACING NOTCHED HOOK WITH DOT;So;0;ON;;;;;N;;;;;
1F910;ZIPPER-MOUTH FACE;So;0;ON;;;;;N;;;;;
1F911;MONEY-MOUTH FACE;So;0;ON;;;;;N;;;;;
1F912;FACE WITH THERMOMETER;So;0;ON;;;;;N;;;;;
@@ -29632,6 +31197,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F91C;RIGHT-FACING FIST;So;0;ON;;;;;N;;;;;
1F91D;HANDSHAKE;So;0;ON;;;;;N;;;;;
1F91E;HAND WITH INDEX AND MIDDLE FINGERS CROSSED;So;0;ON;;;;;N;;;;;
+1F91F;I LOVE YOU HAND SIGN;So;0;ON;;;;;N;;;;;
1F920;FACE WITH COWBOY HAT;So;0;ON;;;;;N;;;;;
1F921;CLOWN FACE;So;0;ON;;;;;N;;;;;
1F922;NAUSEATED FACE;So;0;ON;;;;;N;;;;;
@@ -29640,7 +31206,17 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F925;LYING FACE;So;0;ON;;;;;N;;;;;
1F926;FACE PALM;So;0;ON;;;;;N;;;;;
1F927;SNEEZING FACE;So;0;ON;;;;;N;;;;;
+1F928;FACE WITH ONE EYEBROW RAISED;So;0;ON;;;;;N;;;;;
+1F929;GRINNING FACE WITH STAR EYES;So;0;ON;;;;;N;;;;;
+1F92A;GRINNING FACE WITH ONE LARGE AND ONE SMALL EYE;So;0;ON;;;;;N;;;;;
+1F92B;FACE WITH FINGER COVERING CLOSED LIPS;So;0;ON;;;;;N;;;;;
+1F92C;SERIOUS FACE WITH SYMBOLS COVERING MOUTH;So;0;ON;;;;;N;;;;;
+1F92D;SMILING FACE WITH SMILING EYES AND HAND COVERING MOUTH;So;0;ON;;;;;N;;;;;
+1F92E;FACE WITH OPEN MOUTH VOMITING;So;0;ON;;;;;N;;;;;
+1F92F;SHOCKED FACE WITH EXPLODING HEAD;So;0;ON;;;;;N;;;;;
1F930;PREGNANT WOMAN;So;0;ON;;;;;N;;;;;
+1F931;BREAST-FEEDING;So;0;ON;;;;;N;;;;;
+1F932;PALMS UP TOGETHER;So;0;ON;;;;;N;;;;;
1F933;SELFIE;So;0;ON;;;;;N;;;;;
1F934;PRINCE;So;0;ON;;;;;N;;;;;
1F935;MAN IN TUXEDO;So;0;ON;;;;;N;;;;;
@@ -29665,6 +31241,10 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F949;THIRD PLACE MEDAL;So;0;ON;;;;;N;;;;;
1F94A;BOXING GLOVE;So;0;ON;;;;;N;;;;;
1F94B;MARTIAL ARTS UNIFORM;So;0;ON;;;;;N;;;;;
+1F94C;CURLING STONE;So;0;ON;;;;;N;;;;;
+1F94D;LACROSSE STICK AND BALL;So;0;ON;;;;;N;;;;;
+1F94E;SOFTBALL;So;0;ON;;;;;N;;;;;
+1F94F;FLYING DISC;So;0;ON;;;;;N;;;;;
1F950;CROISSANT;So;0;ON;;;;;N;;;;;
1F951;AVOCADO;So;0;ON;;;;;N;;;;;
1F952;CUCUMBER;So;0;ON;;;;;N;;;;;
@@ -29680,6 +31260,33 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F95C;PEANUTS;So;0;ON;;;;;N;;;;;
1F95D;KIWIFRUIT;So;0;ON;;;;;N;;;;;
1F95E;PANCAKES;So;0;ON;;;;;N;;;;;
+1F95F;DUMPLING;So;0;ON;;;;;N;;;;;
+1F960;FORTUNE COOKIE;So;0;ON;;;;;N;;;;;
+1F961;TAKEOUT BOX;So;0;ON;;;;;N;;;;;
+1F962;CHOPSTICKS;So;0;ON;;;;;N;;;;;
+1F963;BOWL WITH SPOON;So;0;ON;;;;;N;;;;;
+1F964;CUP WITH STRAW;So;0;ON;;;;;N;;;;;
+1F965;COCONUT;So;0;ON;;;;;N;;;;;
+1F966;BROCCOLI;So;0;ON;;;;;N;;;;;
+1F967;PIE;So;0;ON;;;;;N;;;;;
+1F968;PRETZEL;So;0;ON;;;;;N;;;;;
+1F969;CUT OF MEAT;So;0;ON;;;;;N;;;;;
+1F96A;SANDWICH;So;0;ON;;;;;N;;;;;
+1F96B;CANNED FOOD;So;0;ON;;;;;N;;;;;
+1F96C;LEAFY GREEN;So;0;ON;;;;;N;;;;;
+1F96D;MANGO;So;0;ON;;;;;N;;;;;
+1F96E;MOON CAKE;So;0;ON;;;;;N;;;;;
+1F96F;BAGEL;So;0;ON;;;;;N;;;;;
+1F970;SMILING FACE WITH SMILING EYES AND THREE HEARTS;So;0;ON;;;;;N;;;;;
+1F973;FACE WITH PARTY HORN AND PARTY HAT;So;0;ON;;;;;N;;;;;
+1F974;FACE WITH UNEVEN EYES AND WAVY MOUTH;So;0;ON;;;;;N;;;;;
+1F975;OVERHEATED FACE;So;0;ON;;;;;N;;;;;
+1F976;FREEZING FACE;So;0;ON;;;;;N;;;;;
+1F97A;FACE WITH PLEADING EYES;So;0;ON;;;;;N;;;;;
+1F97C;LAB COAT;So;0;ON;;;;;N;;;;;
+1F97D;GOGGLES;So;0;ON;;;;;N;;;;;
+1F97E;HIKING BOOT;So;0;ON;;;;;N;;;;;
+1F97F;FLAT SHOE;So;0;ON;;;;;N;;;;;
1F980;CRAB;So;0;ON;;;;;N;;;;;
1F981;LION FACE;So;0;ON;;;;;N;;;;;
1F982;SCORPION;So;0;ON;;;;;N;;;;;
@@ -29698,7 +31305,98 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F98F;RHINOCEROS;So;0;ON;;;;;N;;;;;
1F990;SHRIMP;So;0;ON;;;;;N;;;;;
1F991;SQUID;So;0;ON;;;;;N;;;;;
+1F992;GIRAFFE FACE;So;0;ON;;;;;N;;;;;
+1F993;ZEBRA FACE;So;0;ON;;;;;N;;;;;
+1F994;HEDGEHOG;So;0;ON;;;;;N;;;;;
+1F995;SAUROPOD;So;0;ON;;;;;N;;;;;
+1F996;T-REX;So;0;ON;;;;;N;;;;;
+1F997;CRICKET;So;0;ON;;;;;N;;;;;
+1F998;KANGAROO;So;0;ON;;;;;N;;;;;
+1F999;LLAMA;So;0;ON;;;;;N;;;;;
+1F99A;PEACOCK;So;0;ON;;;;;N;;;;;
+1F99B;HIPPOPOTAMUS;So;0;ON;;;;;N;;;;;
+1F99C;PARROT;So;0;ON;;;;;N;;;;;
+1F99D;RACCOON;So;0;ON;;;;;N;;;;;
+1F99E;LOBSTER;So;0;ON;;;;;N;;;;;
+1F99F;MOSQUITO;So;0;ON;;;;;N;;;;;
+1F9A0;MICROBE;So;0;ON;;;;;N;;;;;
+1F9A1;BADGER;So;0;ON;;;;;N;;;;;
+1F9A2;SWAN;So;0;ON;;;;;N;;;;;
+1F9B0;EMOJI COMPONENT RED HAIR;So;0;ON;;;;;N;;;;;
+1F9B1;EMOJI COMPONENT CURLY HAIR;So;0;ON;;;;;N;;;;;
+1F9B2;EMOJI COMPONENT BALD;So;0;ON;;;;;N;;;;;
+1F9B3;EMOJI COMPONENT WHITE HAIR;So;0;ON;;;;;N;;;;;
+1F9B4;BONE;So;0;ON;;;;;N;;;;;
+1F9B5;LEG;So;0;ON;;;;;N;;;;;
+1F9B6;FOOT;So;0;ON;;;;;N;;;;;
+1F9B7;TOOTH;So;0;ON;;;;;N;;;;;
+1F9B8;SUPERHERO;So;0;ON;;;;;N;;;;;
+1F9B9;SUPERVILLAIN;So;0;ON;;;;;N;;;;;
1F9C0;CHEESE WEDGE;So;0;ON;;;;;N;;;;;
+1F9C1;CUPCAKE;So;0;ON;;;;;N;;;;;
+1F9C2;SALT SHAKER;So;0;ON;;;;;N;;;;;
+1F9D0;FACE WITH MONOCLE;So;0;ON;;;;;N;;;;;
+1F9D1;ADULT;So;0;ON;;;;;N;;;;;
+1F9D2;CHILD;So;0;ON;;;;;N;;;;;
+1F9D3;OLDER ADULT;So;0;ON;;;;;N;;;;;
+1F9D4;BEARDED PERSON;So;0;ON;;;;;N;;;;;
+1F9D5;PERSON WITH HEADSCARF;So;0;ON;;;;;N;;;;;
+1F9D6;PERSON IN STEAMY ROOM;So;0;ON;;;;;N;;;;;
+1F9D7;PERSON CLIMBING;So;0;ON;;;;;N;;;;;
+1F9D8;PERSON IN LOTUS POSITION;So;0;ON;;;;;N;;;;;
+1F9D9;MAGE;So;0;ON;;;;;N;;;;;
+1F9DA;FAIRY;So;0;ON;;;;;N;;;;;
+1F9DB;VAMPIRE;So;0;ON;;;;;N;;;;;
+1F9DC;MERPERSON;So;0;ON;;;;;N;;;;;
+1F9DD;ELF;So;0;ON;;;;;N;;;;;
+1F9DE;GENIE;So;0;ON;;;;;N;;;;;
+1F9DF;ZOMBIE;So;0;ON;;;;;N;;;;;
+1F9E0;BRAIN;So;0;ON;;;;;N;;;;;
+1F9E1;ORANGE HEART;So;0;ON;;;;;N;;;;;
+1F9E2;BILLED CAP;So;0;ON;;;;;N;;;;;
+1F9E3;SCARF;So;0;ON;;;;;N;;;;;
+1F9E4;GLOVES;So;0;ON;;;;;N;;;;;
+1F9E5;COAT;So;0;ON;;;;;N;;;;;
+1F9E6;SOCKS;So;0;ON;;;;;N;;;;;
+1F9E7;RED GIFT ENVELOPE;So;0;ON;;;;;N;;;;;
+1F9E8;FIRECRACKER;So;0;ON;;;;;N;;;;;
+1F9E9;JIGSAW PUZZLE PIECE;So;0;ON;;;;;N;;;;;
+1F9EA;TEST TUBE;So;0;ON;;;;;N;;;;;
+1F9EB;PETRI DISH;So;0;ON;;;;;N;;;;;
+1F9EC;DNA DOUBLE HELIX;So;0;ON;;;;;N;;;;;
+1F9ED;COMPASS;So;0;ON;;;;;N;;;;;
+1F9EE;ABACUS;So;0;ON;;;;;N;;;;;
+1F9EF;FIRE EXTINGUISHER;So;0;ON;;;;;N;;;;;
+1F9F0;TOOLBOX;So;0;ON;;;;;N;;;;;
+1F9F1;BRICK;So;0;ON;;;;;N;;;;;
+1F9F2;MAGNET;So;0;ON;;;;;N;;;;;
+1F9F3;LUGGAGE;So;0;ON;;;;;N;;;;;
+1F9F4;LOTION BOTTLE;So;0;ON;;;;;N;;;;;
+1F9F5;SPOOL OF THREAD;So;0;ON;;;;;N;;;;;
+1F9F6;BALL OF YARN;So;0;ON;;;;;N;;;;;
+1F9F7;SAFETY PIN;So;0;ON;;;;;N;;;;;
+1F9F8;TEDDY BEAR;So;0;ON;;;;;N;;;;;
+1F9F9;BROOM;So;0;ON;;;;;N;;;;;
+1F9FA;BASKET;So;0;ON;;;;;N;;;;;
+1F9FB;ROLL OF PAPER;So;0;ON;;;;;N;;;;;
+1F9FC;BAR OF SOAP;So;0;ON;;;;;N;;;;;
+1F9FD;SPONGE;So;0;ON;;;;;N;;;;;
+1F9FE;RECEIPT;So;0;ON;;;;;N;;;;;
+1F9FF;NAZAR AMULET;So;0;ON;;;;;N;;;;;
+1FA60;XIANGQI RED GENERAL;So;0;ON;;;;;N;;;;;
+1FA61;XIANGQI RED MANDARIN;So;0;ON;;;;;N;;;;;
+1FA62;XIANGQI RED ELEPHANT;So;0;ON;;;;;N;;;;;
+1FA63;XIANGQI RED HORSE;So;0;ON;;;;;N;;;;;
+1FA64;XIANGQI RED CHARIOT;So;0;ON;;;;;N;;;;;
+1FA65;XIANGQI RED CANNON;So;0;ON;;;;;N;;;;;
+1FA66;XIANGQI RED SOLDIER;So;0;ON;;;;;N;;;;;
+1FA67;XIANGQI BLACK GENERAL;So;0;ON;;;;;N;;;;;
+1FA68;XIANGQI BLACK MANDARIN;So;0;ON;;;;;N;;;;;
+1FA69;XIANGQI BLACK ELEPHANT;So;0;ON;;;;;N;;;;;
+1FA6A;XIANGQI BLACK HORSE;So;0;ON;;;;;N;;;;;
+1FA6B;XIANGQI BLACK CHARIOT;So;0;ON;;;;;N;;;;;
+1FA6C;XIANGQI BLACK CANNON;So;0;ON;;;;;N;;;;;
+1FA6D;XIANGQI BLACK SOLDIER;So;0;ON;;;;;N;;;;;
20000;<CJK Ideograph Extension B, First>;Lo;0;L;;;;;N;;;;;
2A6D6;<CJK Ideograph Extension B, Last>;Lo;0;L;;;;;N;;;;;
2A700;<CJK Ideograph Extension C, First>;Lo;0;L;;;;;N;;;;;
@@ -29707,6 +31405,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
2B81D;<CJK Ideograph Extension D, Last>;Lo;0;L;;;;;N;;;;;
2B820;<CJK Ideograph Extension E, First>;Lo;0;L;;;;;N;;;;;
2CEA1;<CJK Ideograph Extension E, Last>;Lo;0;L;;;;;N;;;;;
+2CEB0;<CJK Ideograph Extension F, First>;Lo;0;L;;;;;N;;;;;
+2EBE0;<CJK Ideograph Extension F, Last>;Lo;0;L;;;;;N;;;;;
2F800;CJK COMPATIBILITY IDEOGRAPH-2F800;Lo;0;L;4E3D;;;;N;;;;;
2F801;CJK COMPATIBILITY IDEOGRAPH-2F801;Lo;0;L;4E38;;;;N;;;;;
2F802;CJK COMPATIBILITY IDEOGRAPH-2F802;Lo;0;L;4E41;;;;N;;;;;
diff --git a/lib/stdlib/uc_spec/emoji-data.txt b/lib/stdlib/uc_spec/emoji-data.txt
new file mode 100644
index 0000000000..6e66455252
--- /dev/null
+++ b/lib/stdlib/uc_spec/emoji-data.txt
@@ -0,0 +1,714 @@
+# emoji-data.txt
+# Date: 2018-02-07, 07:55:18 GMT
+# © 2018 Unicode®, Inc.
+# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
+# For terms of use, see http://www.unicode.org/terms_of_use.html
+#
+# Emoji Data for UTS #51
+# Version: 11.0
+#
+# For documentation and usage, see http://www.unicode.org/reports/tr51
+#
+# Format:
+# <codepoint(s)> ; <property> # <comments>
+# Note: there is no guarantee as to the structure of whitespace or comments
+#
+# Characters and sequences are listed in code point order. Users should be shown a more natural order.
+# See the CLDR collation order for Emoji.
+
+
+# ================================================
+
+# All omitted code points have Emoji=No
+# @missing: 0000..10FFFF ; Emoji ; No
+
+0023 ; Emoji # 1.1 [1] (#️) number sign
+002A ; Emoji # 1.1 [1] (*️) asterisk
+0030..0039 ; Emoji # 1.1 [10] (0️..9️) digit zero..digit nine
+00A9 ; Emoji # 1.1 [1] (©️) copyright
+00AE ; Emoji # 1.1 [1] (®️) registered
+203C ; Emoji # 1.1 [1] (‼️) double exclamation mark
+2049 ; Emoji # 3.0 [1] (⁉️) exclamation question mark
+2122 ; Emoji # 1.1 [1] (™️) trade mark
+2139 ; Emoji # 3.0 [1] (ℹ️) information
+2194..2199 ; Emoji # 1.1 [6] (↔️..↙️) left-right arrow..down-left arrow
+21A9..21AA ; Emoji # 1.1 [2] (↩️..↪️) right arrow curving left..left arrow curving right
+231A..231B ; Emoji # 1.1 [2] (⌚..⌛) watch..hourglass done
+2328 ; Emoji # 1.1 [1] (⌨️) keyboard
+23CF ; Emoji # 4.0 [1] (⏏️) eject button
+23E9..23F3 ; Emoji # 6.0 [11] (⏩..⏳) fast-forward button..hourglass not done
+23F8..23FA ; Emoji # 7.0 [3] (⏸️..⏺️) pause button..record button
+24C2 ; Emoji # 1.1 [1] (Ⓜ️) circled M
+25AA..25AB ; Emoji # 1.1 [2] (▪️..▫️) black small square..white small square
+25B6 ; Emoji # 1.1 [1] (▶️) play button
+25C0 ; Emoji # 1.1 [1] (◀️) reverse button
+25FB..25FE ; Emoji # 3.2 [4] (◻️..◾) white medium square..black medium-small square
+2600..2604 ; Emoji # 1.1 [5] (☀️..☄️) sun..comet
+260E ; Emoji # 1.1 [1] (☎️) telephone
+2611 ; Emoji # 1.1 [1] (☑️) ballot box with check
+2614..2615 ; Emoji # 4.0 [2] (☔..☕) umbrella with rain drops..hot beverage
+2618 ; Emoji # 4.1 [1] (☘️) shamrock
+261D ; Emoji # 1.1 [1] (☝️) index pointing up
+2620 ; Emoji # 1.1 [1] (☠️) skull and crossbones
+2622..2623 ; Emoji # 1.1 [2] (☢️..☣️) radioactive..biohazard
+2626 ; Emoji # 1.1 [1] (☦️) orthodox cross
+262A ; Emoji # 1.1 [1] (☪️) star and crescent
+262E..262F ; Emoji # 1.1 [2] (☮️..☯️) peace symbol..yin yang
+2638..263A ; Emoji # 1.1 [3] (☸️..☺️) wheel of dharma..smiling face
+2640 ; Emoji # 1.1 [1] (♀️) female sign
+2642 ; Emoji # 1.1 [1] (♂️) male sign
+2648..2653 ; Emoji # 1.1 [12] (♈..♓) Aries..Pisces
+265F..2660 ; Emoji # 1.1 [2] (♟️..♠️) chess pawn..spade suit
+2663 ; Emoji # 1.1 [1] (♣️) club suit
+2665..2666 ; Emoji # 1.1 [2] (♥️..♦️) heart suit..diamond suit
+2668 ; Emoji # 1.1 [1] (♨️) hot springs
+267B ; Emoji # 3.2 [1] (♻️) recycling symbol
+267E..267F ; Emoji # 4.1 [2] (♾️..♿) infinity..wheelchair symbol
+2692..2697 ; Emoji # 4.1 [6] (⚒️..⚗️) hammer and pick..alembic
+2699 ; Emoji # 4.1 [1] (⚙️) gear
+269B..269C ; Emoji # 4.1 [2] (⚛️..⚜️) atom symbol..fleur-de-lis
+26A0..26A1 ; Emoji # 4.0 [2] (⚠️..⚡) warning..high voltage
+26AA..26AB ; Emoji # 4.1 [2] (⚪..⚫) white circle..black circle
+26B0..26B1 ; Emoji # 4.1 [2] (⚰️..⚱️) coffin..funeral urn
+26BD..26BE ; Emoji # 5.2 [2] (⚽..⚾) soccer ball..baseball
+26C4..26C5 ; Emoji # 5.2 [2] (⛄..⛅) snowman without snow..sun behind cloud
+26C8 ; Emoji # 5.2 [1] (⛈️) cloud with lightning and rain
+26CE ; Emoji # 6.0 [1] (⛎) Ophiuchus
+26CF ; Emoji # 5.2 [1] (⛏️) pick
+26D1 ; Emoji # 5.2 [1] (⛑️) rescue worker’s helmet
+26D3..26D4 ; Emoji # 5.2 [2] (⛓️..⛔) chains..no entry
+26E9..26EA ; Emoji # 5.2 [2] (⛩️..⛪) shinto shrine..church
+26F0..26F5 ; Emoji # 5.2 [6] (⛰️..⛵) mountain..sailboat
+26F7..26FA ; Emoji # 5.2 [4] (⛷️..⛺) skier..tent
+26FD ; Emoji # 5.2 [1] (⛽) fuel pump
+2702 ; Emoji # 1.1 [1] (✂️) scissors
+2705 ; Emoji # 6.0 [1] (✅) white heavy check mark
+2708..2709 ; Emoji # 1.1 [2] (✈️..✉️) airplane..envelope
+270A..270B ; Emoji # 6.0 [2] (✊..✋) raised fist..raised hand
+270C..270D ; Emoji # 1.1 [2] (✌️..✍️) victory hand..writing hand
+270F ; Emoji # 1.1 [1] (✏️) pencil
+2712 ; Emoji # 1.1 [1] (✒️) black nib
+2714 ; Emoji # 1.1 [1] (✔️) heavy check mark
+2716 ; Emoji # 1.1 [1] (✖️) heavy multiplication x
+271D ; Emoji # 1.1 [1] (✝️) latin cross
+2721 ; Emoji # 1.1 [1] (✡️) star of David
+2728 ; Emoji # 6.0 [1] (✨) sparkles
+2733..2734 ; Emoji # 1.1 [2] (✳️..✴️) eight-spoked asterisk..eight-pointed star
+2744 ; Emoji # 1.1 [1] (❄️) snowflake
+2747 ; Emoji # 1.1 [1] (❇️) sparkle
+274C ; Emoji # 6.0 [1] (❌) cross mark
+274E ; Emoji # 6.0 [1] (❎) cross mark button
+2753..2755 ; Emoji # 6.0 [3] (❓..❕) question mark..white exclamation mark
+2757 ; Emoji # 5.2 [1] (❗) exclamation mark
+2763..2764 ; Emoji # 1.1 [2] (❣️..❤️) heavy heart exclamation..red heart
+2795..2797 ; Emoji # 6.0 [3] (➕..➗) heavy plus sign..heavy division sign
+27A1 ; Emoji # 1.1 [1] (➡️) right arrow
+27B0 ; Emoji # 6.0 [1] (➰) curly loop
+27BF ; Emoji # 6.0 [1] (➿) double curly loop
+2934..2935 ; Emoji # 3.2 [2] (⤴️..⤵️) right arrow curving up..right arrow curving down
+2B05..2B07 ; Emoji # 4.0 [3] (⬅️..⬇️) left arrow..down arrow
+2B1B..2B1C ; Emoji # 5.1 [2] (⬛..⬜) black large square..white large square
+2B50 ; Emoji # 5.1 [1] (⭐) star
+2B55 ; Emoji # 5.2 [1] (⭕) heavy large circle
+3030 ; Emoji # 1.1 [1] (〰️) wavy dash
+303D ; Emoji # 3.2 [1] (〽️) part alternation mark
+3297 ; Emoji # 1.1 [1] (㊗️) Japanese “congratulations” button
+3299 ; Emoji # 1.1 [1] (㊙️) Japanese “secret” button
+1F004 ; Emoji # 5.1 [1] (🀄) mahjong red dragon
+1F0CF ; Emoji # 6.0 [1] (🃏) joker
+1F170..1F171 ; Emoji # 6.0 [2] (🅰️..🅱️) A button (blood type)..B button (blood type)
+1F17E ; Emoji # 6.0 [1] (🅾️) O button (blood type)
+1F17F ; Emoji # 5.2 [1] (🅿️) P button
+1F18E ; Emoji # 6.0 [1] (🆎) AB button (blood type)
+1F191..1F19A ; Emoji # 6.0 [10] (🆑..🆚) CL button..VS button
+1F1E6..1F1FF ; Emoji # 6.0 [26] (🇦..🇿) regional indicator symbol letter a..regional indicator symbol letter z
+1F201..1F202 ; Emoji # 6.0 [2] (🈁..🈂️) Japanese “here” button..Japanese “service charge” button
+1F21A ; Emoji # 5.2 [1] (🈚) Japanese “free of charge” button
+1F22F ; Emoji # 5.2 [1] (🈯) Japanese “reserved” button
+1F232..1F23A ; Emoji # 6.0 [9] (🈲..🈺) Japanese “prohibited” button..Japanese “open for business” button
+1F250..1F251 ; Emoji # 6.0 [2] (🉐..🉑) Japanese “bargain” button..Japanese “acceptable” button
+1F300..1F320 ; Emoji # 6.0 [33] (🌀..🌠) cyclone..shooting star
+1F321 ; Emoji # 7.0 [1] (🌡️) thermometer
+1F324..1F32C ; Emoji # 7.0 [9] (🌤️..🌬️) sun behind small cloud..wind face
+1F32D..1F32F ; Emoji # 8.0 [3] (🌭..🌯) hot dog..burrito
+1F330..1F335 ; Emoji # 6.0 [6] (🌰..🌵) chestnut..cactus
+1F336 ; Emoji # 7.0 [1] (🌶️) hot pepper
+1F337..1F37C ; Emoji # 6.0 [70] (🌷..🍼) tulip..baby bottle
+1F37D ; Emoji # 7.0 [1] (🍽️) fork and knife with plate
+1F37E..1F37F ; Emoji # 8.0 [2] (🍾..🍿) bottle with popping cork..popcorn
+1F380..1F393 ; Emoji # 6.0 [20] (🎀..🎓) ribbon..graduation cap
+1F396..1F397 ; Emoji # 7.0 [2] (🎖️..🎗️) military medal..reminder ribbon
+1F399..1F39B ; Emoji # 7.0 [3] (🎙️..🎛️) studio microphone..control knobs
+1F39E..1F39F ; Emoji # 7.0 [2] (🎞️..🎟️) film frames..admission tickets
+1F3A0..1F3C4 ; Emoji # 6.0 [37] (🎠..🏄) carousel horse..person surfing
+1F3C5 ; Emoji # 7.0 [1] (🏅) sports medal
+1F3C6..1F3CA ; Emoji # 6.0 [5] (🏆..🏊) trophy..person swimming
+1F3CB..1F3CE ; Emoji # 7.0 [4] (🏋️..🏎️) person lifting weights..racing car
+1F3CF..1F3D3 ; Emoji # 8.0 [5] (🏏..🏓) cricket game..ping pong
+1F3D4..1F3DF ; Emoji # 7.0 [12] (🏔️..🏟️) snow-capped mountain..stadium
+1F3E0..1F3F0 ; Emoji # 6.0 [17] (🏠..🏰) house..castle
+1F3F3..1F3F5 ; Emoji # 7.0 [3] (🏳️..🏵️) white flag..rosette
+1F3F7 ; Emoji # 7.0 [1] (🏷️) label
+1F3F8..1F3FF ; Emoji # 8.0 [8] (🏸..🏿) badminton..dark skin tone
+1F400..1F43E ; Emoji # 6.0 [63] (🐀..🐾) rat..paw prints
+1F43F ; Emoji # 7.0 [1] (🐿️) chipmunk
+1F440 ; Emoji # 6.0 [1] (👀) eyes
+1F441 ; Emoji # 7.0 [1] (👁️) eye
+1F442..1F4F7 ; Emoji # 6.0[182] (👂..📷) ear..camera
+1F4F8 ; Emoji # 7.0 [1] (📸) camera with flash
+1F4F9..1F4FC ; Emoji # 6.0 [4] (📹..📼) video camera..videocassette
+1F4FD ; Emoji # 7.0 [1] (📽️) film projector
+1F4FF ; Emoji # 8.0 [1] (📿) prayer beads
+1F500..1F53D ; Emoji # 6.0 [62] (🔀..🔽) shuffle tracks button..downwards button
+1F549..1F54A ; Emoji # 7.0 [2] (🕉️..🕊️) om..dove
+1F54B..1F54E ; Emoji # 8.0 [4] (🕋..🕎) kaaba..menorah
+1F550..1F567 ; Emoji # 6.0 [24] (🕐..🕧) one o’clock..twelve-thirty
+1F56F..1F570 ; Emoji # 7.0 [2] (🕯️..🕰️) candle..mantelpiece clock
+1F573..1F579 ; Emoji # 7.0 [7] (🕳️..🕹️) hole..joystick
+1F57A ; Emoji # 9.0 [1] (🕺) man dancing
+1F587 ; Emoji # 7.0 [1] (🖇️) linked paperclips
+1F58A..1F58D ; Emoji # 7.0 [4] (🖊️..🖍️) pen..crayon
+1F590 ; Emoji # 7.0 [1] (🖐️) hand with fingers splayed
+1F595..1F596 ; Emoji # 7.0 [2] (🖕..🖖) middle finger..vulcan salute
+1F5A4 ; Emoji # 9.0 [1] (🖤) black heart
+1F5A5 ; Emoji # 7.0 [1] (🖥️) desktop computer
+1F5A8 ; Emoji # 7.0 [1] (🖨️) printer
+1F5B1..1F5B2 ; Emoji # 7.0 [2] (🖱️..🖲️) computer mouse..trackball
+1F5BC ; Emoji # 7.0 [1] (🖼️) framed picture
+1F5C2..1F5C4 ; Emoji # 7.0 [3] (🗂️..🗄️) card index dividers..file cabinet
+1F5D1..1F5D3 ; Emoji # 7.0 [3] (🗑️..🗓️) wastebasket..spiral calendar
+1F5DC..1F5DE ; Emoji # 7.0 [3] (🗜️..🗞️) clamp..rolled-up newspaper
+1F5E1 ; Emoji # 7.0 [1] (🗡️) dagger
+1F5E3 ; Emoji # 7.0 [1] (🗣️) speaking head
+1F5E8 ; Emoji # 7.0 [1] (🗨️) left speech bubble
+1F5EF ; Emoji # 7.0 [1] (🗯️) right anger bubble
+1F5F3 ; Emoji # 7.0 [1] (🗳️) ballot box with ballot
+1F5FA ; Emoji # 7.0 [1] (🗺️) world map
+1F5FB..1F5FF ; Emoji # 6.0 [5] (🗻..🗿) mount fuji..moai
+1F600 ; Emoji # 6.1 [1] (😀) grinning face
+1F601..1F610 ; Emoji # 6.0 [16] (😁..😐) beaming face with smiling eyes..neutral face
+1F611 ; Emoji # 6.1 [1] (😑) expressionless face
+1F612..1F614 ; Emoji # 6.0 [3] (😒..😔) unamused face..pensive face
+1F615 ; Emoji # 6.1 [1] (😕) confused face
+1F616 ; Emoji # 6.0 [1] (😖) confounded face
+1F617 ; Emoji # 6.1 [1] (😗) kissing face
+1F618 ; Emoji # 6.0 [1] (😘) face blowing a kiss
+1F619 ; Emoji # 6.1 [1] (😙) kissing face with smiling eyes
+1F61A ; Emoji # 6.0 [1] (😚) kissing face with closed eyes
+1F61B ; Emoji # 6.1 [1] (😛) face with tongue
+1F61C..1F61E ; Emoji # 6.0 [3] (😜..😞) winking face with tongue..disappointed face
+1F61F ; Emoji # 6.1 [1] (😟) worried face
+1F620..1F625 ; Emoji # 6.0 [6] (😠..😥) angry face..sad but relieved face
+1F626..1F627 ; Emoji # 6.1 [2] (😦..😧) frowning face with open mouth..anguished face
+1F628..1F62B ; Emoji # 6.0 [4] (😨..😫) fearful face..tired face
+1F62C ; Emoji # 6.1 [1] (😬) grimacing face
+1F62D ; Emoji # 6.0 [1] (😭) loudly crying face
+1F62E..1F62F ; Emoji # 6.1 [2] (😮..😯) face with open mouth..hushed face
+1F630..1F633 ; Emoji # 6.0 [4] (😰..😳) anxious face with sweat..flushed face
+1F634 ; Emoji # 6.1 [1] (😴) sleeping face
+1F635..1F640 ; Emoji # 6.0 [12] (😵..🙀) dizzy face..weary cat face
+1F641..1F642 ; Emoji # 7.0 [2] (🙁..🙂) slightly frowning face..slightly smiling face
+1F643..1F644 ; Emoji # 8.0 [2] (🙃..🙄) upside-down face..face with rolling eyes
+1F645..1F64F ; Emoji # 6.0 [11] (🙅..🙏) person gesturing NO..folded hands
+1F680..1F6C5 ; Emoji # 6.0 [70] (🚀..🛅) rocket..left luggage
+1F6CB..1F6CF ; Emoji # 7.0 [5] (🛋️..🛏️) couch and lamp..bed
+1F6D0 ; Emoji # 8.0 [1] (🛐) place of worship
+1F6D1..1F6D2 ; Emoji # 9.0 [2] (🛑..🛒) stop sign..shopping cart
+1F6E0..1F6E5 ; Emoji # 7.0 [6] (🛠️..🛥️) hammer and wrench..motor boat
+1F6E9 ; Emoji # 7.0 [1] (🛩️) small airplane
+1F6EB..1F6EC ; Emoji # 7.0 [2] (🛫..🛬) airplane departure..airplane arrival
+1F6F0 ; Emoji # 7.0 [1] (🛰️) satellite
+1F6F3 ; Emoji # 7.0 [1] (🛳️) passenger ship
+1F6F4..1F6F6 ; Emoji # 9.0 [3] (🛴..🛶) kick scooter..canoe
+1F6F7..1F6F8 ; Emoji # 10.0 [2] (🛷..🛸) sled..flying saucer
+1F6F9 ; Emoji # 11.0 [1] (🛹) skateboard
+1F910..1F918 ; Emoji # 8.0 [9] (🤐..🤘) zipper-mouth face..sign of the horns
+1F919..1F91E ; Emoji # 9.0 [6] (🤙..🤞) call me hand..crossed fingers
+1F91F ; Emoji # 10.0 [1] (🤟) love-you gesture
+1F920..1F927 ; Emoji # 9.0 [8] (🤠..🤧) cowboy hat face..sneezing face
+1F928..1F92F ; Emoji # 10.0 [8] (🤨..🤯) face with raised eyebrow..exploding head
+1F930 ; Emoji # 9.0 [1] (🤰) pregnant woman
+1F931..1F932 ; Emoji # 10.0 [2] (🤱..🤲) breast-feeding..palms up together
+1F933..1F93A ; Emoji # 9.0 [8] (🤳..🤺) selfie..person fencing
+1F93C..1F93E ; Emoji # 9.0 [3] (🤼..🤾) people wrestling..person playing handball
+1F940..1F945 ; Emoji # 9.0 [6] (🥀..🥅) wilted flower..goal net
+1F947..1F94B ; Emoji # 9.0 [5] (🥇..🥋) 1st place medal..martial arts uniform
+1F94C ; Emoji # 10.0 [1] (🥌) curling stone
+1F94D..1F94F ; Emoji # 11.0 [3] (🥍..🥏) lacrosse..flying disc
+1F950..1F95E ; Emoji # 9.0 [15] (🥐..🥞) croissant..pancakes
+1F95F..1F96B ; Emoji # 10.0 [13] (🥟..🥫) dumpling..canned food
+1F96C..1F970 ; Emoji # 11.0 [5] (🥬..🥰) leafy green..smiling face with 3 hearts
+1F973..1F976 ; Emoji # 11.0 [4] (🥳..🥶) partying face..cold face
+1F97A ; Emoji # 11.0 [1] (🥺) pleading face
+1F97C..1F97F ; Emoji # 11.0 [4] (🥼..🥿) lab coat..woman’s flat shoe
+1F980..1F984 ; Emoji # 8.0 [5] (🦀..🦄) crab..unicorn face
+1F985..1F991 ; Emoji # 9.0 [13] (🦅..🦑) eagle..squid
+1F992..1F997 ; Emoji # 10.0 [6] (🦒..🦗) giraffe..cricket
+1F998..1F9A2 ; Emoji # 11.0 [11] (🦘..🦢) kangaroo..swan
+1F9B0..1F9B9 ; Emoji # 11.0 [10] (🦰..🦹) red-haired..supervillain
+1F9C0 ; Emoji # 8.0 [1] (🧀) cheese wedge
+1F9C1..1F9C2 ; Emoji # 11.0 [2] (🧁..🧂) cupcake..salt
+1F9D0..1F9E6 ; Emoji # 10.0 [23] (🧐..🧦) face with monocle..socks
+1F9E7..1F9FF ; Emoji # 11.0 [25] (🧧..🧿) red envelope..nazar amulet
+
+# Total elements: 1250
+
+# ================================================
+
+# All omitted code points have Emoji_Presentation=No
+# @missing: 0000..10FFFF ; Emoji_Presentation ; No
+
+231A..231B ; Emoji_Presentation # 1.1 [2] (⌚..⌛) watch..hourglass done
+23E9..23EC ; Emoji_Presentation # 6.0 [4] (⏩..⏬) fast-forward button..fast down button
+23F0 ; Emoji_Presentation # 6.0 [1] (⏰) alarm clock
+23F3 ; Emoji_Presentation # 6.0 [1] (⏳) hourglass not done
+25FD..25FE ; Emoji_Presentation # 3.2 [2] (◽..◾) white medium-small square..black medium-small square
+2614..2615 ; Emoji_Presentation # 4.0 [2] (☔..☕) umbrella with rain drops..hot beverage
+2648..2653 ; Emoji_Presentation # 1.1 [12] (♈..♓) Aries..Pisces
+267F ; Emoji_Presentation # 4.1 [1] (♿) wheelchair symbol
+2693 ; Emoji_Presentation # 4.1 [1] (⚓) anchor
+26A1 ; Emoji_Presentation # 4.0 [1] (⚡) high voltage
+26AA..26AB ; Emoji_Presentation # 4.1 [2] (⚪..⚫) white circle..black circle
+26BD..26BE ; Emoji_Presentation # 5.2 [2] (⚽..⚾) soccer ball..baseball
+26C4..26C5 ; Emoji_Presentation # 5.2 [2] (⛄..⛅) snowman without snow..sun behind cloud
+26CE ; Emoji_Presentation # 6.0 [1] (⛎) Ophiuchus
+26D4 ; Emoji_Presentation # 5.2 [1] (⛔) no entry
+26EA ; Emoji_Presentation # 5.2 [1] (⛪) church
+26F2..26F3 ; Emoji_Presentation # 5.2 [2] (⛲..⛳) fountain..flag in hole
+26F5 ; Emoji_Presentation # 5.2 [1] (⛵) sailboat
+26FA ; Emoji_Presentation # 5.2 [1] (⛺) tent
+26FD ; Emoji_Presentation # 5.2 [1] (⛽) fuel pump
+2705 ; Emoji_Presentation # 6.0 [1] (✅) white heavy check mark
+270A..270B ; Emoji_Presentation # 6.0 [2] (✊..✋) raised fist..raised hand
+2728 ; Emoji_Presentation # 6.0 [1] (✨) sparkles
+274C ; Emoji_Presentation # 6.0 [1] (❌) cross mark
+274E ; Emoji_Presentation # 6.0 [1] (❎) cross mark button
+2753..2755 ; Emoji_Presentation # 6.0 [3] (❓..❕) question mark..white exclamation mark
+2757 ; Emoji_Presentation # 5.2 [1] (❗) exclamation mark
+2795..2797 ; Emoji_Presentation # 6.0 [3] (➕..➗) heavy plus sign..heavy division sign
+27B0 ; Emoji_Presentation # 6.0 [1] (➰) curly loop
+27BF ; Emoji_Presentation # 6.0 [1] (➿) double curly loop
+2B1B..2B1C ; Emoji_Presentation # 5.1 [2] (⬛..⬜) black large square..white large square
+2B50 ; Emoji_Presentation # 5.1 [1] (⭐) star
+2B55 ; Emoji_Presentation # 5.2 [1] (⭕) heavy large circle
+1F004 ; Emoji_Presentation # 5.1 [1] (🀄) mahjong red dragon
+1F0CF ; Emoji_Presentation # 6.0 [1] (🃏) joker
+1F18E ; Emoji_Presentation # 6.0 [1] (🆎) AB button (blood type)
+1F191..1F19A ; Emoji_Presentation # 6.0 [10] (🆑..🆚) CL button..VS button
+1F1E6..1F1FF ; Emoji_Presentation # 6.0 [26] (🇦..🇿) regional indicator symbol letter a..regional indicator symbol letter z
+1F201 ; Emoji_Presentation # 6.0 [1] (🈁) Japanese “here” button
+1F21A ; Emoji_Presentation # 5.2 [1] (🈚) Japanese “free of charge” button
+1F22F ; Emoji_Presentation # 5.2 [1] (🈯) Japanese “reserved” button
+1F232..1F236 ; Emoji_Presentation # 6.0 [5] (🈲..🈶) Japanese “prohibited” button..Japanese “not free of charge” button
+1F238..1F23A ; Emoji_Presentation # 6.0 [3] (🈸..🈺) Japanese “application” button..Japanese “open for business” button
+1F250..1F251 ; Emoji_Presentation # 6.0 [2] (🉐..🉑) Japanese “bargain” button..Japanese “acceptable” button
+1F300..1F320 ; Emoji_Presentation # 6.0 [33] (🌀..🌠) cyclone..shooting star
+1F32D..1F32F ; Emoji_Presentation # 8.0 [3] (🌭..🌯) hot dog..burrito
+1F330..1F335 ; Emoji_Presentation # 6.0 [6] (🌰..🌵) chestnut..cactus
+1F337..1F37C ; Emoji_Presentation # 6.0 [70] (🌷..🍼) tulip..baby bottle
+1F37E..1F37F ; Emoji_Presentation # 8.0 [2] (🍾..🍿) bottle with popping cork..popcorn
+1F380..1F393 ; Emoji_Presentation # 6.0 [20] (🎀..🎓) ribbon..graduation cap
+1F3A0..1F3C4 ; Emoji_Presentation # 6.0 [37] (🎠..🏄) carousel horse..person surfing
+1F3C5 ; Emoji_Presentation # 7.0 [1] (🏅) sports medal
+1F3C6..1F3CA ; Emoji_Presentation # 6.0 [5] (🏆..🏊) trophy..person swimming
+1F3CF..1F3D3 ; Emoji_Presentation # 8.0 [5] (🏏..🏓) cricket game..ping pong
+1F3E0..1F3F0 ; Emoji_Presentation # 6.0 [17] (🏠..🏰) house..castle
+1F3F4 ; Emoji_Presentation # 7.0 [1] (🏴) black flag
+1F3F8..1F3FF ; Emoji_Presentation # 8.0 [8] (🏸..🏿) badminton..dark skin tone
+1F400..1F43E ; Emoji_Presentation # 6.0 [63] (🐀..🐾) rat..paw prints
+1F440 ; Emoji_Presentation # 6.0 [1] (👀) eyes
+1F442..1F4F7 ; Emoji_Presentation # 6.0[182] (👂..📷) ear..camera
+1F4F8 ; Emoji_Presentation # 7.0 [1] (📸) camera with flash
+1F4F9..1F4FC ; Emoji_Presentation # 6.0 [4] (📹..📼) video camera..videocassette
+1F4FF ; Emoji_Presentation # 8.0 [1] (📿) prayer beads
+1F500..1F53D ; Emoji_Presentation # 6.0 [62] (🔀..🔽) shuffle tracks button..downwards button
+1F54B..1F54E ; Emoji_Presentation # 8.0 [4] (🕋..🕎) kaaba..menorah
+1F550..1F567 ; Emoji_Presentation # 6.0 [24] (🕐..🕧) one o’clock..twelve-thirty
+1F57A ; Emoji_Presentation # 9.0 [1] (🕺) man dancing
+1F595..1F596 ; Emoji_Presentation # 7.0 [2] (🖕..🖖) middle finger..vulcan salute
+1F5A4 ; Emoji_Presentation # 9.0 [1] (🖤) black heart
+1F5FB..1F5FF ; Emoji_Presentation # 6.0 [5] (🗻..🗿) mount fuji..moai
+1F600 ; Emoji_Presentation # 6.1 [1] (😀) grinning face
+1F601..1F610 ; Emoji_Presentation # 6.0 [16] (😁..😐) beaming face with smiling eyes..neutral face
+1F611 ; Emoji_Presentation # 6.1 [1] (😑) expressionless face
+1F612..1F614 ; Emoji_Presentation # 6.0 [3] (😒..😔) unamused face..pensive face
+1F615 ; Emoji_Presentation # 6.1 [1] (😕) confused face
+1F616 ; Emoji_Presentation # 6.0 [1] (😖) confounded face
+1F617 ; Emoji_Presentation # 6.1 [1] (😗) kissing face
+1F618 ; Emoji_Presentation # 6.0 [1] (😘) face blowing a kiss
+1F619 ; Emoji_Presentation # 6.1 [1] (😙) kissing face with smiling eyes
+1F61A ; Emoji_Presentation # 6.0 [1] (😚) kissing face with closed eyes
+1F61B ; Emoji_Presentation # 6.1 [1] (😛) face with tongue
+1F61C..1F61E ; Emoji_Presentation # 6.0 [3] (😜..😞) winking face with tongue..disappointed face
+1F61F ; Emoji_Presentation # 6.1 [1] (😟) worried face
+1F620..1F625 ; Emoji_Presentation # 6.0 [6] (😠..😥) angry face..sad but relieved face
+1F626..1F627 ; Emoji_Presentation # 6.1 [2] (😦..😧) frowning face with open mouth..anguished face
+1F628..1F62B ; Emoji_Presentation # 6.0 [4] (😨..😫) fearful face..tired face
+1F62C ; Emoji_Presentation # 6.1 [1] (😬) grimacing face
+1F62D ; Emoji_Presentation # 6.0 [1] (😭) loudly crying face
+1F62E..1F62F ; Emoji_Presentation # 6.1 [2] (😮..😯) face with open mouth..hushed face
+1F630..1F633 ; Emoji_Presentation # 6.0 [4] (😰..😳) anxious face with sweat..flushed face
+1F634 ; Emoji_Presentation # 6.1 [1] (😴) sleeping face
+1F635..1F640 ; Emoji_Presentation # 6.0 [12] (😵..🙀) dizzy face..weary cat face
+1F641..1F642 ; Emoji_Presentation # 7.0 [2] (🙁..🙂) slightly frowning face..slightly smiling face
+1F643..1F644 ; Emoji_Presentation # 8.0 [2] (🙃..🙄) upside-down face..face with rolling eyes
+1F645..1F64F ; Emoji_Presentation # 6.0 [11] (🙅..🙏) person gesturing NO..folded hands
+1F680..1F6C5 ; Emoji_Presentation # 6.0 [70] (🚀..🛅) rocket..left luggage
+1F6CC ; Emoji_Presentation # 7.0 [1] (🛌) person in bed
+1F6D0 ; Emoji_Presentation # 8.0 [1] (🛐) place of worship
+1F6D1..1F6D2 ; Emoji_Presentation # 9.0 [2] (🛑..🛒) stop sign..shopping cart
+1F6EB..1F6EC ; Emoji_Presentation # 7.0 [2] (🛫..🛬) airplane departure..airplane arrival
+1F6F4..1F6F6 ; Emoji_Presentation # 9.0 [3] (🛴..🛶) kick scooter..canoe
+1F6F7..1F6F8 ; Emoji_Presentation # 10.0 [2] (🛷..🛸) sled..flying saucer
+1F6F9 ; Emoji_Presentation # 11.0 [1] (🛹) skateboard
+1F910..1F918 ; Emoji_Presentation # 8.0 [9] (🤐..🤘) zipper-mouth face..sign of the horns
+1F919..1F91E ; Emoji_Presentation # 9.0 [6] (🤙..🤞) call me hand..crossed fingers
+1F91F ; Emoji_Presentation # 10.0 [1] (🤟) love-you gesture
+1F920..1F927 ; Emoji_Presentation # 9.0 [8] (🤠..🤧) cowboy hat face..sneezing face
+1F928..1F92F ; Emoji_Presentation # 10.0 [8] (🤨..🤯) face with raised eyebrow..exploding head
+1F930 ; Emoji_Presentation # 9.0 [1] (🤰) pregnant woman
+1F931..1F932 ; Emoji_Presentation # 10.0 [2] (🤱..🤲) breast-feeding..palms up together
+1F933..1F93A ; Emoji_Presentation # 9.0 [8] (🤳..🤺) selfie..person fencing
+1F93C..1F93E ; Emoji_Presentation # 9.0 [3] (🤼..🤾) people wrestling..person playing handball
+1F940..1F945 ; Emoji_Presentation # 9.0 [6] (🥀..🥅) wilted flower..goal net
+1F947..1F94B ; Emoji_Presentation # 9.0 [5] (🥇..🥋) 1st place medal..martial arts uniform
+1F94C ; Emoji_Presentation # 10.0 [1] (🥌) curling stone
+1F94D..1F94F ; Emoji_Presentation # 11.0 [3] (🥍..🥏) lacrosse..flying disc
+1F950..1F95E ; Emoji_Presentation # 9.0 [15] (🥐..🥞) croissant..pancakes
+1F95F..1F96B ; Emoji_Presentation # 10.0 [13] (🥟..🥫) dumpling..canned food
+1F96C..1F970 ; Emoji_Presentation # 11.0 [5] (🥬..🥰) leafy green..smiling face with 3 hearts
+1F973..1F976 ; Emoji_Presentation # 11.0 [4] (🥳..🥶) partying face..cold face
+1F97A ; Emoji_Presentation # 11.0 [1] (🥺) pleading face
+1F97C..1F97F ; Emoji_Presentation # 11.0 [4] (🥼..🥿) lab coat..woman’s flat shoe
+1F980..1F984 ; Emoji_Presentation # 8.0 [5] (🦀..🦄) crab..unicorn face
+1F985..1F991 ; Emoji_Presentation # 9.0 [13] (🦅..🦑) eagle..squid
+1F992..1F997 ; Emoji_Presentation # 10.0 [6] (🦒..🦗) giraffe..cricket
+1F998..1F9A2 ; Emoji_Presentation # 11.0 [11] (🦘..🦢) kangaroo..swan
+1F9B0..1F9B9 ; Emoji_Presentation # 11.0 [10] (🦰..🦹) red-haired..supervillain
+1F9C0 ; Emoji_Presentation # 8.0 [1] (🧀) cheese wedge
+1F9C1..1F9C2 ; Emoji_Presentation # 11.0 [2] (🧁..🧂) cupcake..salt
+1F9D0..1F9E6 ; Emoji_Presentation # 10.0 [23] (🧐..🧦) face with monocle..socks
+1F9E7..1F9FF ; Emoji_Presentation # 11.0 [25] (🧧..🧿) red envelope..nazar amulet
+
+# Total elements: 1032
+
+# ================================================
+
+# All omitted code points have Emoji_Modifier=No
+# @missing: 0000..10FFFF ; Emoji_Modifier ; No
+
+1F3FB..1F3FF ; Emoji_Modifier # 8.0 [5] (🏻..🏿) light skin tone..dark skin tone
+
+# Total elements: 5
+
+# ================================================
+
+# All omitted code points have Emoji_Modifier_Base=No
+# @missing: 0000..10FFFF ; Emoji_Modifier_Base ; No
+
+261D ; Emoji_Modifier_Base # 1.1 [1] (☝️) index pointing up
+26F9 ; Emoji_Modifier_Base # 5.2 [1] (⛹️) person bouncing ball
+270A..270B ; Emoji_Modifier_Base # 6.0 [2] (✊..✋) raised fist..raised hand
+270C..270D ; Emoji_Modifier_Base # 1.1 [2] (✌️..✍️) victory hand..writing hand
+1F385 ; Emoji_Modifier_Base # 6.0 [1] (🎅) Santa Claus
+1F3C2..1F3C4 ; Emoji_Modifier_Base # 6.0 [3] (🏂..🏄) snowboarder..person surfing
+1F3C7 ; Emoji_Modifier_Base # 6.0 [1] (🏇) horse racing
+1F3CA ; Emoji_Modifier_Base # 6.0 [1] (🏊) person swimming
+1F3CB..1F3CC ; Emoji_Modifier_Base # 7.0 [2] (🏋️..🏌️) person lifting weights..person golfing
+1F442..1F443 ; Emoji_Modifier_Base # 6.0 [2] (👂..👃) ear..nose
+1F446..1F450 ; Emoji_Modifier_Base # 6.0 [11] (👆..👐) backhand index pointing up..open hands
+1F466..1F469 ; Emoji_Modifier_Base # 6.0 [4] (👦..👩) boy..woman
+1F46E ; Emoji_Modifier_Base # 6.0 [1] (👮) police officer
+1F470..1F478 ; Emoji_Modifier_Base # 6.0 [9] (👰..👸) bride with veil..princess
+1F47C ; Emoji_Modifier_Base # 6.0 [1] (👼) baby angel
+1F481..1F483 ; Emoji_Modifier_Base # 6.0 [3] (💁..💃) person tipping hand..woman dancing
+1F485..1F487 ; Emoji_Modifier_Base # 6.0 [3] (💅..💇) nail polish..person getting haircut
+1F4AA ; Emoji_Modifier_Base # 6.0 [1] (💪) flexed biceps
+1F574..1F575 ; Emoji_Modifier_Base # 7.0 [2] (🕴️..🕵️) man in suit levitating..detective
+1F57A ; Emoji_Modifier_Base # 9.0 [1] (🕺) man dancing
+1F590 ; Emoji_Modifier_Base # 7.0 [1] (🖐️) hand with fingers splayed
+1F595..1F596 ; Emoji_Modifier_Base # 7.0 [2] (🖕..🖖) middle finger..vulcan salute
+1F645..1F647 ; Emoji_Modifier_Base # 6.0 [3] (🙅..🙇) person gesturing NO..person bowing
+1F64B..1F64F ; Emoji_Modifier_Base # 6.0 [5] (🙋..🙏) person raising hand..folded hands
+1F6A3 ; Emoji_Modifier_Base # 6.0 [1] (🚣) person rowing boat
+1F6B4..1F6B6 ; Emoji_Modifier_Base # 6.0 [3] (🚴..🚶) person biking..person walking
+1F6C0 ; Emoji_Modifier_Base # 6.0 [1] (🛀) person taking bath
+1F6CC ; Emoji_Modifier_Base # 7.0 [1] (🛌) person in bed
+1F918 ; Emoji_Modifier_Base # 8.0 [1] (🤘) sign of the horns
+1F919..1F91C ; Emoji_Modifier_Base # 9.0 [4] (🤙..🤜) call me hand..right-facing fist
+1F91E ; Emoji_Modifier_Base # 9.0 [1] (🤞) crossed fingers
+1F91F ; Emoji_Modifier_Base # 10.0 [1] (🤟) love-you gesture
+1F926 ; Emoji_Modifier_Base # 9.0 [1] (🤦) person facepalming
+1F930 ; Emoji_Modifier_Base # 9.0 [1] (🤰) pregnant woman
+1F931..1F932 ; Emoji_Modifier_Base # 10.0 [2] (🤱..🤲) breast-feeding..palms up together
+1F933..1F939 ; Emoji_Modifier_Base # 9.0 [7] (🤳..🤹) selfie..person juggling
+1F93D..1F93E ; Emoji_Modifier_Base # 9.0 [2] (🤽..🤾) person playing water polo..person playing handball
+1F9B5..1F9B6 ; Emoji_Modifier_Base # 11.0 [2] (🦵..🦶) leg..foot
+1F9B8..1F9B9 ; Emoji_Modifier_Base # 11.0 [2] (🦸..🦹) superhero..supervillain
+1F9D1..1F9DD ; Emoji_Modifier_Base # 10.0 [13] (🧑..🧝) adult..elf
+
+# Total elements: 106
+
+# ================================================
+
+# All omitted code points have Emoji_Component=No
+# @missing: 0000..10FFFF ; Emoji_Component ; No
+
+0023 ; Emoji_Component # 1.1 [1] (#️) number sign
+002A ; Emoji_Component # 1.1 [1] (*️) asterisk
+0030..0039 ; Emoji_Component # 1.1 [10] (0️..9️) digit zero..digit nine
+200D ; Emoji_Component # 1.1 [1] (‍) zero width joiner
+20E3 ; Emoji_Component # 3.0 [1] (⃣) combining enclosing keycap
+FE0F ; Emoji_Component # 3.2 [1] () VARIATION SELECTOR-16
+1F1E6..1F1FF ; Emoji_Component # 6.0 [26] (🇦..🇿) regional indicator symbol letter a..regional indicator symbol letter z
+1F3FB..1F3FF ; Emoji_Component # 8.0 [5] (🏻..🏿) light skin tone..dark skin tone
+1F9B0..1F9B3 ; Emoji_Component # 11.0 [4] (🦰..🦳) red-haired..white-haired
+E0020..E007F ; Emoji_Component # 3.1 [96] (󠀠..󠁿) tag space..cancel tag
+
+# Total elements: 146
+
+# ================================================
+
+# All omitted code points have Extended_Pictographic=No
+# @missing: 0000..10FFFF ; Extended_Pictographic ; No
+
+00A9 ; Extended_Pictographic# 1.1 [1] (©️) copyright
+00AE ; Extended_Pictographic# 1.1 [1] (®️) registered
+203C ; Extended_Pictographic# 1.1 [1] (‼️) double exclamation mark
+2049 ; Extended_Pictographic# 3.0 [1] (⁉️) exclamation question mark
+2122 ; Extended_Pictographic# 1.1 [1] (™️) trade mark
+2139 ; Extended_Pictographic# 3.0 [1] (ℹ️) information
+2194..2199 ; Extended_Pictographic# 1.1 [6] (↔️..↙️) left-right arrow..down-left arrow
+21A9..21AA ; Extended_Pictographic# 1.1 [2] (↩️..↪️) right arrow curving left..left arrow curving right
+231A..231B ; Extended_Pictographic# 1.1 [2] (⌚..⌛) watch..hourglass done
+2328 ; Extended_Pictographic# 1.1 [1] (⌨️) keyboard
+2388 ; Extended_Pictographic# 3.0 [1] (⎈️) HELM SYMBOL
+23CF ; Extended_Pictographic# 4.0 [1] (⏏️) eject button
+23E9..23F3 ; Extended_Pictographic# 6.0 [11] (⏩..⏳) fast-forward button..hourglass not done
+23F8..23FA ; Extended_Pictographic# 7.0 [3] (⏸️..⏺️) pause button..record button
+24C2 ; Extended_Pictographic# 1.1 [1] (Ⓜ️) circled M
+25AA..25AB ; Extended_Pictographic# 1.1 [2] (▪️..▫️) black small square..white small square
+25B6 ; Extended_Pictographic# 1.1 [1] (▶️) play button
+25C0 ; Extended_Pictographic# 1.1 [1] (◀️) reverse button
+25FB..25FE ; Extended_Pictographic# 3.2 [4] (◻️..◾) white medium square..black medium-small square
+2600..2605 ; Extended_Pictographic# 1.1 [6] (☀️..★️) sun..BLACK STAR
+2607..2612 ; Extended_Pictographic# 1.1 [12] (☇️..☒️) LIGHTNING..BALLOT BOX WITH X
+2614..2615 ; Extended_Pictographic# 4.0 [2] (☔..☕) umbrella with rain drops..hot beverage
+2616..2617 ; Extended_Pictographic# 3.2 [2] (☖️..☗️) WHITE SHOGI PIECE..BLACK SHOGI PIECE
+2618 ; Extended_Pictographic# 4.1 [1] (☘️) shamrock
+2619 ; Extended_Pictographic# 3.0 [1] (☙️) REVERSED ROTATED FLORAL HEART BULLET
+261A..266F ; Extended_Pictographic# 1.1 [86] (☚️..♯️) BLACK LEFT POINTING INDEX..MUSIC SHARP SIGN
+2670..2671 ; Extended_Pictographic# 3.0 [2] (♰️..♱️) WEST SYRIAC CROSS..EAST SYRIAC CROSS
+2672..267D ; Extended_Pictographic# 3.2 [12] (♲️..♽️) UNIVERSAL RECYCLING SYMBOL..PARTIALLY-RECYCLED PAPER SYMBOL
+267E..267F ; Extended_Pictographic# 4.1 [2] (♾️..♿) infinity..wheelchair symbol
+2680..2685 ; Extended_Pictographic# 3.2 [6] (⚀️..⚅️) DIE FACE-1..DIE FACE-6
+2690..2691 ; Extended_Pictographic# 4.0 [2] (⚐️..⚑️) WHITE FLAG..BLACK FLAG
+2692..269C ; Extended_Pictographic# 4.1 [11] (⚒️..⚜️) hammer and pick..fleur-de-lis
+269D ; Extended_Pictographic# 5.1 [1] (⚝️) OUTLINED WHITE STAR
+269E..269F ; Extended_Pictographic# 5.2 [2] (⚞️..⚟️) THREE LINES CONVERGING RIGHT..THREE LINES CONVERGING LEFT
+26A0..26A1 ; Extended_Pictographic# 4.0 [2] (⚠️..⚡) warning..high voltage
+26A2..26B1 ; Extended_Pictographic# 4.1 [16] (⚢️..⚱️) DOUBLED FEMALE SIGN..funeral urn
+26B2 ; Extended_Pictographic# 5.0 [1] (⚲️) NEUTER
+26B3..26BC ; Extended_Pictographic# 5.1 [10] (⚳️..⚼️) CERES..SESQUIQUADRATE
+26BD..26BF ; Extended_Pictographic# 5.2 [3] (⚽..⚿️) soccer ball..SQUARED KEY
+26C0..26C3 ; Extended_Pictographic# 5.1 [4] (⛀️..⛃️) WHITE DRAUGHTS MAN..BLACK DRAUGHTS KING
+26C4..26CD ; Extended_Pictographic# 5.2 [10] (⛄..⛍️) snowman without snow..DISABLED CAR
+26CE ; Extended_Pictographic# 6.0 [1] (⛎) Ophiuchus
+26CF..26E1 ; Extended_Pictographic# 5.2 [19] (⛏️..⛡️) pick..RESTRICTED LEFT ENTRY-2
+26E2 ; Extended_Pictographic# 6.0 [1] (⛢️) ASTRONOMICAL SYMBOL FOR URANUS
+26E3 ; Extended_Pictographic# 5.2 [1] (⛣️) HEAVY CIRCLE WITH STROKE AND TWO DOTS ABOVE
+26E4..26E7 ; Extended_Pictographic# 6.0 [4] (⛤️..⛧️) PENTAGRAM..INVERTED PENTAGRAM
+26E8..26FF ; Extended_Pictographic# 5.2 [24] (⛨️..⛿️) BLACK CROSS ON SHIELD..WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE
+2700 ; Extended_Pictographic# 7.0 [1] (✀️) BLACK SAFETY SCISSORS
+2701..2704 ; Extended_Pictographic# 1.1 [4] (✁️..✄️) UPPER BLADE SCISSORS..WHITE SCISSORS
+2705 ; Extended_Pictographic# 6.0 [1] (✅) white heavy check mark
+2708..2709 ; Extended_Pictographic# 1.1 [2] (✈️..✉️) airplane..envelope
+270A..270B ; Extended_Pictographic# 6.0 [2] (✊..✋) raised fist..raised hand
+270C..2712 ; Extended_Pictographic# 1.1 [7] (✌️..✒️) victory hand..black nib
+2714 ; Extended_Pictographic# 1.1 [1] (✔️) heavy check mark
+2716 ; Extended_Pictographic# 1.1 [1] (✖️) heavy multiplication x
+271D ; Extended_Pictographic# 1.1 [1] (✝️) latin cross
+2721 ; Extended_Pictographic# 1.1 [1] (✡️) star of David
+2728 ; Extended_Pictographic# 6.0 [1] (✨) sparkles
+2733..2734 ; Extended_Pictographic# 1.1 [2] (✳️..✴️) eight-spoked asterisk..eight-pointed star
+2744 ; Extended_Pictographic# 1.1 [1] (❄️) snowflake
+2747 ; Extended_Pictographic# 1.1 [1] (❇️) sparkle
+274C ; Extended_Pictographic# 6.0 [1] (❌) cross mark
+274E ; Extended_Pictographic# 6.0 [1] (❎) cross mark button
+2753..2755 ; Extended_Pictographic# 6.0 [3] (❓..❕) question mark..white exclamation mark
+2757 ; Extended_Pictographic# 5.2 [1] (❗) exclamation mark
+2763..2767 ; Extended_Pictographic# 1.1 [5] (❣️..❧️) heavy heart exclamation..ROTATED FLORAL HEART BULLET
+2795..2797 ; Extended_Pictographic# 6.0 [3] (➕..➗) heavy plus sign..heavy division sign
+27A1 ; Extended_Pictographic# 1.1 [1] (➡️) right arrow
+27B0 ; Extended_Pictographic# 6.0 [1] (➰) curly loop
+27BF ; Extended_Pictographic# 6.0 [1] (➿) double curly loop
+2934..2935 ; Extended_Pictographic# 3.2 [2] (⤴️..⤵️) right arrow curving up..right arrow curving down
+2B05..2B07 ; Extended_Pictographic# 4.0 [3] (⬅️..⬇️) left arrow..down arrow
+2B1B..2B1C ; Extended_Pictographic# 5.1 [2] (⬛..⬜) black large square..white large square
+2B50 ; Extended_Pictographic# 5.1 [1] (⭐) star
+2B55 ; Extended_Pictographic# 5.2 [1] (⭕) heavy large circle
+3030 ; Extended_Pictographic# 1.1 [1] (〰️) wavy dash
+303D ; Extended_Pictographic# 3.2 [1] (〽️) part alternation mark
+3297 ; Extended_Pictographic# 1.1 [1] (㊗️) Japanese “congratulations” button
+3299 ; Extended_Pictographic# 1.1 [1] (㊙️) Japanese “secret” button
+1F000..1F02B ; Extended_Pictographic# 5.1 [44] (🀀️..🀫️) MAHJONG TILE EAST WIND..MAHJONG TILE BACK
+1F02C..1F02F ; Extended_Pictographic# NA [4] (🀬️..🀯️) <reserved-1F02C>..<reserved-1F02F>
+1F030..1F093 ; Extended_Pictographic# 5.1[100] (🀰️..🂓️) DOMINO TILE HORIZONTAL BACK..DOMINO TILE VERTICAL-06-06
+1F094..1F09F ; Extended_Pictographic# NA [12] (🂔️..🂟️) <reserved-1F094>..<reserved-1F09F>
+1F0A0..1F0AE ; Extended_Pictographic# 6.0 [15] (🂠️..🂮️) PLAYING CARD BACK..PLAYING CARD KING OF SPADES
+1F0AF..1F0B0 ; Extended_Pictographic# NA [2] (🂯️..🂰️) <reserved-1F0AF>..<reserved-1F0B0>
+1F0B1..1F0BE ; Extended_Pictographic# 6.0 [14] (🂱️..🂾️) PLAYING CARD ACE OF HEARTS..PLAYING CARD KING OF HEARTS
+1F0BF ; Extended_Pictographic# 7.0 [1] (🂿️) PLAYING CARD RED JOKER
+1F0C0 ; Extended_Pictographic# NA [1] (🃀️) <reserved-1F0C0>
+1F0C1..1F0CF ; Extended_Pictographic# 6.0 [15] (🃁️..🃏) PLAYING CARD ACE OF DIAMONDS..joker
+1F0D0 ; Extended_Pictographic# NA [1] (🃐️) <reserved-1F0D0>
+1F0D1..1F0DF ; Extended_Pictographic# 6.0 [15] (🃑️..🃟️) PLAYING CARD ACE OF CLUBS..PLAYING CARD WHITE JOKER
+1F0E0..1F0F5 ; Extended_Pictographic# 7.0 [22] (🃠️..🃵️) PLAYING CARD FOOL..PLAYING CARD TRUMP-21
+1F0F6..1F0FF ; Extended_Pictographic# NA [10] (🃶️..🃿️) <reserved-1F0F6>..<reserved-1F0FF>
+1F10D..1F10F ; Extended_Pictographic# NA [3] (🄍️..🄏️) <reserved-1F10D>..<reserved-1F10F>
+1F12F ; Extended_Pictographic# 11.0 [1] (🄯️) COPYLEFT SYMBOL
+1F16C..1F16F ; Extended_Pictographic# NA [4] (🅬️..🅯️) <reserved-1F16C>..<reserved-1F16F>
+1F170..1F171 ; Extended_Pictographic# 6.0 [2] (🅰️..🅱️) A button (blood type)..B button (blood type)
+1F17E ; Extended_Pictographic# 6.0 [1] (🅾️) O button (blood type)
+1F17F ; Extended_Pictographic# 5.2 [1] (🅿️) P button
+1F18E ; Extended_Pictographic# 6.0 [1] (🆎) AB button (blood type)
+1F191..1F19A ; Extended_Pictographic# 6.0 [10] (🆑..🆚) CL button..VS button
+1F1AD..1F1E5 ; Extended_Pictographic# NA [57] (🆭️..🇥️) <reserved-1F1AD>..<reserved-1F1E5>
+1F201..1F202 ; Extended_Pictographic# 6.0 [2] (🈁..🈂️) Japanese “here” button..Japanese “service charge” button
+1F203..1F20F ; Extended_Pictographic# NA [13] (🈃️..🈏️) <reserved-1F203>..<reserved-1F20F>
+1F21A ; Extended_Pictographic# 5.2 [1] (🈚) Japanese “free of charge” button
+1F22F ; Extended_Pictographic# 5.2 [1] (🈯) Japanese “reserved” button
+1F232..1F23A ; Extended_Pictographic# 6.0 [9] (🈲..🈺) Japanese “prohibited” button..Japanese “open for business” button
+1F23C..1F23F ; Extended_Pictographic# NA [4] (🈼️..🈿️) <reserved-1F23C>..<reserved-1F23F>
+1F249..1F24F ; Extended_Pictographic# NA [7] (🉉️..🉏️) <reserved-1F249>..<reserved-1F24F>
+1F250..1F251 ; Extended_Pictographic# 6.0 [2] (🉐..🉑) Japanese “bargain” button..Japanese “acceptable” button
+1F252..1F25F ; Extended_Pictographic# NA [14] (🉒️..🉟️) <reserved-1F252>..<reserved-1F25F>
+1F260..1F265 ; Extended_Pictographic# 10.0 [6] (🉠️..🉥️) ROUNDED SYMBOL FOR FU..ROUNDED SYMBOL FOR CAI
+1F266..1F2FF ; Extended_Pictographic# NA[154] (🉦️..🋿️) <reserved-1F266>..<reserved-1F2FF>
+1F300..1F320 ; Extended_Pictographic# 6.0 [33] (🌀..🌠) cyclone..shooting star
+1F321..1F32C ; Extended_Pictographic# 7.0 [12] (🌡️..🌬️) thermometer..wind face
+1F32D..1F32F ; Extended_Pictographic# 8.0 [3] (🌭..🌯) hot dog..burrito
+1F330..1F335 ; Extended_Pictographic# 6.0 [6] (🌰..🌵) chestnut..cactus
+1F336 ; Extended_Pictographic# 7.0 [1] (🌶️) hot pepper
+1F337..1F37C ; Extended_Pictographic# 6.0 [70] (🌷..🍼) tulip..baby bottle
+1F37D ; Extended_Pictographic# 7.0 [1] (🍽️) fork and knife with plate
+1F37E..1F37F ; Extended_Pictographic# 8.0 [2] (🍾..🍿) bottle with popping cork..popcorn
+1F380..1F393 ; Extended_Pictographic# 6.0 [20] (🎀..🎓) ribbon..graduation cap
+1F394..1F39F ; Extended_Pictographic# 7.0 [12] (🎔️..🎟️) HEART WITH TIP ON THE LEFT..admission tickets
+1F3A0..1F3C4 ; Extended_Pictographic# 6.0 [37] (🎠..🏄) carousel horse..person surfing
+1F3C5 ; Extended_Pictographic# 7.0 [1] (🏅) sports medal
+1F3C6..1F3CA ; Extended_Pictographic# 6.0 [5] (🏆..🏊) trophy..person swimming
+1F3CB..1F3CE ; Extended_Pictographic# 7.0 [4] (🏋️..🏎️) person lifting weights..racing car
+1F3CF..1F3D3 ; Extended_Pictographic# 8.0 [5] (🏏..🏓) cricket game..ping pong
+1F3D4..1F3DF ; Extended_Pictographic# 7.0 [12] (🏔️..🏟️) snow-capped mountain..stadium
+1F3E0..1F3F0 ; Extended_Pictographic# 6.0 [17] (🏠..🏰) house..castle
+1F3F1..1F3F7 ; Extended_Pictographic# 7.0 [7] (🏱️..🏷️) WHITE PENNANT..label
+1F3F8..1F3FA ; Extended_Pictographic# 8.0 [3] (🏸..🏺) badminton..amphora
+1F400..1F43E ; Extended_Pictographic# 6.0 [63] (🐀..🐾) rat..paw prints
+1F43F ; Extended_Pictographic# 7.0 [1] (🐿️) chipmunk
+1F440 ; Extended_Pictographic# 6.0 [1] (👀) eyes
+1F441 ; Extended_Pictographic# 7.0 [1] (👁️) eye
+1F442..1F4F7 ; Extended_Pictographic# 6.0[182] (👂..📷) ear..camera
+1F4F8 ; Extended_Pictographic# 7.0 [1] (📸) camera with flash
+1F4F9..1F4FC ; Extended_Pictographic# 6.0 [4] (📹..📼) video camera..videocassette
+1F4FD..1F4FE ; Extended_Pictographic# 7.0 [2] (📽️..📾️) film projector..PORTABLE STEREO
+1F4FF ; Extended_Pictographic# 8.0 [1] (📿) prayer beads
+1F500..1F53D ; Extended_Pictographic# 6.0 [62] (🔀..🔽) shuffle tracks button..downwards button
+1F546..1F54A ; Extended_Pictographic# 7.0 [5] (🕆️..🕊️) WHITE LATIN CROSS..dove
+1F54B..1F54F ; Extended_Pictographic# 8.0 [5] (🕋..🕏️) kaaba..BOWL OF HYGIEIA
+1F550..1F567 ; Extended_Pictographic# 6.0 [24] (🕐..🕧) one o’clock..twelve-thirty
+1F568..1F579 ; Extended_Pictographic# 7.0 [18] (🕨️..🕹️) RIGHT SPEAKER..joystick
+1F57A ; Extended_Pictographic# 9.0 [1] (🕺) man dancing
+1F57B..1F5A3 ; Extended_Pictographic# 7.0 [41] (🕻️..🖣️) LEFT HAND TELEPHONE RECEIVER..BLACK DOWN POINTING BACKHAND INDEX
+1F5A4 ; Extended_Pictographic# 9.0 [1] (🖤) black heart
+1F5A5..1F5FA ; Extended_Pictographic# 7.0 [86] (🖥️..🗺️) desktop computer..world map
+1F5FB..1F5FF ; Extended_Pictographic# 6.0 [5] (🗻..🗿) mount fuji..moai
+1F600 ; Extended_Pictographic# 6.1 [1] (😀) grinning face
+1F601..1F610 ; Extended_Pictographic# 6.0 [16] (😁..😐) beaming face with smiling eyes..neutral face
+1F611 ; Extended_Pictographic# 6.1 [1] (😑) expressionless face
+1F612..1F614 ; Extended_Pictographic# 6.0 [3] (😒..😔) unamused face..pensive face
+1F615 ; Extended_Pictographic# 6.1 [1] (😕) confused face
+1F616 ; Extended_Pictographic# 6.0 [1] (😖) confounded face
+1F617 ; Extended_Pictographic# 6.1 [1] (😗) kissing face
+1F618 ; Extended_Pictographic# 6.0 [1] (😘) face blowing a kiss
+1F619 ; Extended_Pictographic# 6.1 [1] (😙) kissing face with smiling eyes
+1F61A ; Extended_Pictographic# 6.0 [1] (😚) kissing face with closed eyes
+1F61B ; Extended_Pictographic# 6.1 [1] (😛) face with tongue
+1F61C..1F61E ; Extended_Pictographic# 6.0 [3] (😜..😞) winking face with tongue..disappointed face
+1F61F ; Extended_Pictographic# 6.1 [1] (😟) worried face
+1F620..1F625 ; Extended_Pictographic# 6.0 [6] (😠..😥) angry face..sad but relieved face
+1F626..1F627 ; Extended_Pictographic# 6.1 [2] (😦..😧) frowning face with open mouth..anguished face
+1F628..1F62B ; Extended_Pictographic# 6.0 [4] (😨..😫) fearful face..tired face
+1F62C ; Extended_Pictographic# 6.1 [1] (😬) grimacing face
+1F62D ; Extended_Pictographic# 6.0 [1] (😭) loudly crying face
+1F62E..1F62F ; Extended_Pictographic# 6.1 [2] (😮..😯) face with open mouth..hushed face
+1F630..1F633 ; Extended_Pictographic# 6.0 [4] (😰..😳) anxious face with sweat..flushed face
+1F634 ; Extended_Pictographic# 6.1 [1] (😴) sleeping face
+1F635..1F640 ; Extended_Pictographic# 6.0 [12] (😵..🙀) dizzy face..weary cat face
+1F641..1F642 ; Extended_Pictographic# 7.0 [2] (🙁..🙂) slightly frowning face..slightly smiling face
+1F643..1F644 ; Extended_Pictographic# 8.0 [2] (🙃..🙄) upside-down face..face with rolling eyes
+1F645..1F64F ; Extended_Pictographic# 6.0 [11] (🙅..🙏) person gesturing NO..folded hands
+1F680..1F6C5 ; Extended_Pictographic# 6.0 [70] (🚀..🛅) rocket..left luggage
+1F6C6..1F6CF ; Extended_Pictographic# 7.0 [10] (🛆️..🛏️) TRIANGLE WITH ROUNDED CORNERS..bed
+1F6D0 ; Extended_Pictographic# 8.0 [1] (🛐) place of worship
+1F6D1..1F6D2 ; Extended_Pictographic# 9.0 [2] (🛑..🛒) stop sign..shopping cart
+1F6D3..1F6D4 ; Extended_Pictographic# 10.0 [2] (🛓️..🛔️) STUPA..PAGODA
+1F6D5..1F6DF ; Extended_Pictographic# NA [11] (🛕️..🛟️) <reserved-1F6D5>..<reserved-1F6DF>
+1F6E0..1F6EC ; Extended_Pictographic# 7.0 [13] (🛠️..🛬) hammer and wrench..airplane arrival
+1F6ED..1F6EF ; Extended_Pictographic# NA [3] (🛭️..🛯️) <reserved-1F6ED>..<reserved-1F6EF>
+1F6F0..1F6F3 ; Extended_Pictographic# 7.0 [4] (🛰️..🛳️) satellite..passenger ship
+1F6F4..1F6F6 ; Extended_Pictographic# 9.0 [3] (🛴..🛶) kick scooter..canoe
+1F6F7..1F6F8 ; Extended_Pictographic# 10.0 [2] (🛷..🛸) sled..flying saucer
+1F6F9 ; Extended_Pictographic# 11.0 [1] (🛹) skateboard
+1F6FA..1F6FF ; Extended_Pictographic# NA [6] (🛺️..🛿️) <reserved-1F6FA>..<reserved-1F6FF>
+1F774..1F77F ; Extended_Pictographic# NA [12] (🝴️..🝿️) <reserved-1F774>..<reserved-1F77F>
+1F7D5..1F7D8 ; Extended_Pictographic# 11.0 [4] (🟕️..🟘️) CIRCLED TRIANGLE..NEGATIVE CIRCLED SQUARE
+1F7D9..1F7FF ; Extended_Pictographic# NA [39] (🟙️..🟿️) <reserved-1F7D9>..<reserved-1F7FF>
+1F80C..1F80F ; Extended_Pictographic# NA [4] (🠌️..🠏️) <reserved-1F80C>..<reserved-1F80F>
+1F848..1F84F ; Extended_Pictographic# NA [8] (🡈️..🡏️) <reserved-1F848>..<reserved-1F84F>
+1F85A..1F85F ; Extended_Pictographic# NA [6] (🡚️..🡟️) <reserved-1F85A>..<reserved-1F85F>
+1F888..1F88F ; Extended_Pictographic# NA [8] (🢈️..🢏️) <reserved-1F888>..<reserved-1F88F>
+1F8AE..1F8FF ; Extended_Pictographic# NA [82] (🢮️..🣿️) <reserved-1F8AE>..<reserved-1F8FF>
+1F90C..1F90F ; Extended_Pictographic# NA [4] (🤌️..🤏️) <reserved-1F90C>..<reserved-1F90F>
+1F910..1F918 ; Extended_Pictographic# 8.0 [9] (🤐..🤘) zipper-mouth face..sign of the horns
+1F919..1F91E ; Extended_Pictographic# 9.0 [6] (🤙..🤞) call me hand..crossed fingers
+1F91F ; Extended_Pictographic# 10.0 [1] (🤟) love-you gesture
+1F920..1F927 ; Extended_Pictographic# 9.0 [8] (🤠..🤧) cowboy hat face..sneezing face
+1F928..1F92F ; Extended_Pictographic# 10.0 [8] (🤨..🤯) face with raised eyebrow..exploding head
+1F930 ; Extended_Pictographic# 9.0 [1] (🤰) pregnant woman
+1F931..1F932 ; Extended_Pictographic# 10.0 [2] (🤱..🤲) breast-feeding..palms up together
+1F933..1F93A ; Extended_Pictographic# 9.0 [8] (🤳..🤺) selfie..person fencing
+1F93C..1F93E ; Extended_Pictographic# 9.0 [3] (🤼..🤾) people wrestling..person playing handball
+1F93F ; Extended_Pictographic# NA [1] (🤿️) <reserved-1F93F>
+1F940..1F945 ; Extended_Pictographic# 9.0 [6] (🥀..🥅) wilted flower..goal net
+1F947..1F94B ; Extended_Pictographic# 9.0 [5] (🥇..🥋) 1st place medal..martial arts uniform
+1F94C ; Extended_Pictographic# 10.0 [1] (🥌) curling stone
+1F94D..1F94F ; Extended_Pictographic# 11.0 [3] (🥍..🥏) lacrosse..flying disc
+1F950..1F95E ; Extended_Pictographic# 9.0 [15] (🥐..🥞) croissant..pancakes
+1F95F..1F96B ; Extended_Pictographic# 10.0 [13] (🥟..🥫) dumpling..canned food
+1F96C..1F970 ; Extended_Pictographic# 11.0 [5] (🥬..🥰) leafy green..smiling face with 3 hearts
+1F971..1F972 ; Extended_Pictographic# NA [2] (🥱️..🥲️) <reserved-1F971>..<reserved-1F972>
+1F973..1F976 ; Extended_Pictographic# 11.0 [4] (🥳..🥶) partying face..cold face
+1F977..1F979 ; Extended_Pictographic# NA [3] (🥷️..🥹️) <reserved-1F977>..<reserved-1F979>
+1F97A ; Extended_Pictographic# 11.0 [1] (🥺) pleading face
+1F97B ; Extended_Pictographic# NA [1] (🥻️) <reserved-1F97B>
+1F97C..1F97F ; Extended_Pictographic# 11.0 [4] (🥼..🥿) lab coat..woman’s flat shoe
+1F980..1F984 ; Extended_Pictographic# 8.0 [5] (🦀..🦄) crab..unicorn face
+1F985..1F991 ; Extended_Pictographic# 9.0 [13] (🦅..🦑) eagle..squid
+1F992..1F997 ; Extended_Pictographic# 10.0 [6] (🦒..🦗) giraffe..cricket
+1F998..1F9A2 ; Extended_Pictographic# 11.0 [11] (🦘..🦢) kangaroo..swan
+1F9A3..1F9AF ; Extended_Pictographic# NA [13] (🦣️..🦯️) <reserved-1F9A3>..<reserved-1F9AF>
+1F9B0..1F9B9 ; Extended_Pictographic# 11.0 [10] (🦰..🦹) red-haired..supervillain
+1F9BA..1F9BF ; Extended_Pictographic# NA [6] (🦺️..🦿️) <reserved-1F9BA>..<reserved-1F9BF>
+1F9C0 ; Extended_Pictographic# 8.0 [1] (🧀) cheese wedge
+1F9C1..1F9C2 ; Extended_Pictographic# 11.0 [2] (🧁..🧂) cupcake..salt
+1F9C3..1F9CF ; Extended_Pictographic# NA [13] (🧃️..🧏️) <reserved-1F9C3>..<reserved-1F9CF>
+1F9D0..1F9E6 ; Extended_Pictographic# 10.0 [23] (🧐..🧦) face with monocle..socks
+1F9E7..1F9FF ; Extended_Pictographic# 11.0 [25] (🧧..🧿) red envelope..nazar amulet
+1FA00..1FA5F ; Extended_Pictographic# NA [96] (🨀️..🩟️) <reserved-1FA00>..<reserved-1FA5F>
+1FA60..1FA6D ; Extended_Pictographic# 11.0 [14] (🩠️..🩭️) XIANGQI RED GENERAL..XIANGQI BLACK SOLDIER
+1FA6E..1FFFD ; Extended_Pictographic# NA[1424] (🩮️..🿽️) <reserved-1FA6E>..<reserved-1FFFD>
+
+# Total elements: 3793
+
+#EOF
diff --git a/lib/stdlib/uc_spec/gen_unicode_mod.escript b/lib/stdlib/uc_spec/gen_unicode_mod.escript
index 73c351e1af..de67b18afc 100755..100644
--- a/lib/stdlib/uc_spec/gen_unicode_mod.escript
+++ b/lib/stdlib/uc_spec/gen_unicode_mod.escript
@@ -4,7 +4,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2017. All Rights Reserved.
+%% Copyright Ericsson AB 2017-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -48,13 +48,18 @@ main(_) ->
ok = file:close(ExclF),
%% GraphemeBreakProperty table
+ {ok, Emoji} = file:open("../uc_spec/emoji-data.txt", [read, raw, {read_ahead, 1000000}]),
+ Props00 = foldl(fun parse_properties/2, [], Emoji),
+ %% Filter Extended_Pictographic class which we are interested in.
+ Props0 = [EP || {extended_pictographic, _} = EP <- Props00],
+ ok = file:close(Emoji),
{ok, GBPF} = file:open("../uc_spec/GraphemeBreakProperty.txt", [read, raw, {read_ahead, 1000000}]),
- Props0 = foldl(fun parse_properties/2, [], GBPF),
+ Props1 = foldl(fun parse_properties/2, Props0, GBPF),
ok = file:close(GBPF),
{ok, PropF} = file:open("../uc_spec/PropList.txt", [read, raw, {read_ahead, 1000000}]),
- Props1 = foldl(fun parse_properties/2, Props0, PropF),
+ Props2 = foldl(fun parse_properties/2, Props1, PropF),
ok = file:close(PropF),
- Props = sofs:to_external(sofs:relation_to_family(sofs:relation(Props1))),
+ Props = sofs:to_external(sofs:relation_to_family(sofs:relation(Props2))),
%% Make module
{ok, Out} = file:open(?MOD++".erl", [write]),
@@ -65,7 +70,7 @@ main(_) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
parse_unicode_data(Line0, Acc) ->
- Line = string:strip(Line0, right, $\n),
+ Line = string:chomp(Line0),
[CodePoint,Name,_Cat,Class,_BiDi,Decomp,
_N1,_N2,_N3,_BDMirror,_Uni1,_Iso|Case] = tokens(Line, ";"),
{Dec,Comp} = case to_decomp(Decomp) of
@@ -78,14 +83,14 @@ parse_unicode_data(Line0, Acc) ->
|Acc].
to_class(String) ->
- list_to_integer(string:strip(String, both)).
+ list_to_integer(string:trim(String, both)).
to_decomp("") -> [];
to_decomp("<" ++ Str) ->
- [Tag,Rest] = string:tokens(Str, ">"),
+ [Tag,Rest] = string:lexemes(Str, ">"),
{list_to_atom(Tag), to_decomp(Rest)};
to_decomp(CodePoints) ->
- CPL = string:tokens(CodePoints, " "),
+ CPL = string:lexemes(CodePoints, " "),
[hex_to_int(CP) || CP <- CPL].
to_case(["","",""]) -> [];
@@ -105,20 +110,20 @@ parse_special_casing(Line, Table) ->
array:set(CP, Entry#cp{cs=Case}, Table).
to_scase([Lower,Title,Upper|_]) ->
- {unlist([hex_to_int(CP) || CP <- string:strip(string:tokens(Upper, " "), both)]),
- unlist([hex_to_int(CP) || CP <- string:strip(string:tokens(Lower, " "), both)]),
- unlist([hex_to_int(CP) || CP <- string:strip(string:tokens(Title, " "), both)]),
+ {unlist([hex_to_int(CP) || CP <- string:lexemes(Upper, " ")]),
+ unlist([hex_to_int(CP) || CP <- string:lexemes(Lower, " ")]),
+ unlist([hex_to_int(CP) || CP <- string:lexemes(Title, " ")]),
[]}.
parse_case_folding(Line, Table) ->
[CodePoint, Class0, CaseStr |_Comments] = tokens(Line, ";"),
- Class = string:strip(Class0, both),
+ Class = string:trim(Class0, both),
if Class =:= "T" -> Table; %% Do not support localization yet
Class =:= "S" -> Table; %% Ignore simple
true ->
CP = hex_to_int(CodePoint),
Case = unlist([hex_to_int(CPC) ||
- CPC <- string:strip(string:tokens(CaseStr, " "), both)]),
+ CPC <- string:lexemes(CaseStr, " ")]),
#cp{cs={U,L,T,_}} = Entry = array:get(CP, Table),
array:set(CP, Entry#cp{cs={U,L,T,Case}}, Table)
end.
@@ -170,7 +175,7 @@ gen_header(Fd) ->
io:put_chars(Fd, "-export([spec_version/0, lookup/1, get_case/1]).\n"),
io:put_chars(Fd, "-inline([class/1]).\n"),
io:put_chars(Fd, "-compile(nowarn_unused_vars).\n"),
- io:put_chars(Fd, "-dialyzer({no_improper_lists, [cp/1, gc/1, gc_prepend/2, gc_e_cont/2]}).\n"),
+ io:put_chars(Fd, "-dialyzer({no_improper_lists, [cp/1, gc/1, gc_prepend/2]}).\n"),
io:put_chars(Fd, "-type gc() :: char()|[char()].\n\n\n"),
ok.
@@ -186,7 +191,7 @@ gen_static(Fd) ->
" {U,L} -> #{upper=>U,lower=>L,title=>U,fold=>L};\n"
" {U,L,T,F} -> #{upper=>U,lower=>L,title=>T,fold=>F}\n"
" end.\n\n"),
- io:put_chars(Fd, "spec_version() -> {9,0}.\n\n\n"),
+ io:put_chars(Fd, "spec_version() -> {11,0}.\n\n\n"),
io:put_chars(Fd, "class(Codepoint) -> {CCC,_,_} = unicode_table(Codepoint),\n CCC.\n\n"),
io:put_chars(Fd, "-spec uppercase(unicode:chardata()) -> "
"maybe_improper_list(gc(),unicode:chardata()).\n"),
@@ -197,7 +202,8 @@ gen_static(Fd) ->
io:put_chars(Fd, " {Upper,_} -> [Upper|Str];\n"),
io:put_chars(Fd, " {Upper,_,_,_} -> [Upper|Str]\n"),
io:put_chars(Fd, " end;\n"),
- io:put_chars(Fd, " [] -> []\n"),
+ io:put_chars(Fd, " [] -> [];\n"),
+ io:put_chars(Fd, " {error,Err} -> error({badarg, Err})\n"),
io:put_chars(Fd, " end.\n\n"),
io:put_chars(Fd, "-spec lowercase(unicode:chardata()) -> "
"maybe_improper_list(gc(),unicode:chardata()).\n"),
@@ -208,7 +214,8 @@ gen_static(Fd) ->
io:put_chars(Fd, " {_,Lower} -> [Lower|Str];\n"),
io:put_chars(Fd, " {_,Lower,_,_} -> [Lower|Str]\n"),
io:put_chars(Fd, " end;\n"),
- io:put_chars(Fd, " [] -> []\n"),
+ io:put_chars(Fd, " [] -> [];\n"),
+ io:put_chars(Fd, " {error,Err} -> error({badarg, Err})\n"),
io:put_chars(Fd, " end.\n\n"),
io:put_chars(Fd, "-spec titlecase(unicode:chardata()) -> "
"maybe_improper_list(gc(),unicode:chardata()).\n"),
@@ -219,7 +226,8 @@ gen_static(Fd) ->
io:put_chars(Fd, " {_,_,Title,_} -> [Title|Str];\n"),
io:put_chars(Fd, " {Upper,_} -> [Upper|Str]\n"),
io:put_chars(Fd, " end;\n"),
- io:put_chars(Fd, " [] -> []\n"),
+ io:put_chars(Fd, " [] -> [];\n"),
+ io:put_chars(Fd, " {error,Err} -> error({badarg, Err})\n"),
io:put_chars(Fd, " end.\n\n"),
io:put_chars(Fd, "-spec casefold(unicode:chardata()) -> "
"maybe_improper_list(gc(),unicode:chardata()).\n"),
@@ -230,7 +238,8 @@ gen_static(Fd) ->
io:put_chars(Fd, " {_,_,_,Fold} -> [Fold|Str];\n"),
io:put_chars(Fd, " {_,Lower} -> [Lower|Str]\n"),
io:put_chars(Fd, " end;\n"),
- io:put_chars(Fd, " [] -> []\n"),
+ io:put_chars(Fd, " [] -> [];\n"),
+ io:put_chars(Fd, " {error,Err} -> error({badarg, Err})\n"),
io:put_chars(Fd, " end.\n\n"),
ok.
@@ -455,17 +464,73 @@ gen_cp(Fd) ->
" maybe_improper_list() | {error, unicode:chardata()}.\n"),
io:put_chars(Fd, "cp([C|_]=L) when is_integer(C) -> L;\n"),
io:put_chars(Fd, "cp([List]) -> cp(List);\n"),
- io:put_chars(Fd, "cp([List|R]) ->\n"),
- io:put_chars(Fd, " case cp(List) of\n"),
- io:put_chars(Fd, " [] -> cp(R);\n"),
- io:put_chars(Fd, " [CP] -> [CP|R];\n"),
- io:put_chars(Fd, " [C|R0] -> [C|[R0|R]];\n"),
- io:put_chars(Fd, " {error,Error} -> {error,[Error|R]}\n"),
- io:put_chars(Fd, " end;\n"),
+ io:put_chars(Fd, "cp([List|R]) -> cpl(List, R);\n"),
io:put_chars(Fd, "cp([]) -> [];\n"),
io:put_chars(Fd, "cp(<<C/utf8, R/binary>>) -> [C|R];\n"),
io:put_chars(Fd, "cp(<<>>) -> [];\n"),
- io:put_chars(Fd, "cp(<<R/binary>>) -> {error,R}.\n\n"),
+ io:put_chars(Fd, "cp(<<R/binary>>) -> {error,R}.\n"),
+ io:put_chars(Fd, "\n"),
+ io:put_chars(Fd, "cpl([C], R) when is_integer(C) -> [C|cpl_1_cont(R)];\n"),
+ io:put_chars(Fd, "cpl([C|T], R) when is_integer(C) -> [C|cpl_cont(T, R)];\n"),
+ io:put_chars(Fd, "cpl([List], R) -> cpl(List, R);\n"),
+ io:put_chars(Fd, "cpl([List|T], R) -> cpl(List, [T|R]);\n"),
+ io:put_chars(Fd, "cpl([], R) -> cp(R);\n"),
+ io:put_chars(Fd, "cpl(<<C/utf8, T/binary>>, R) -> [C,T|R];\n"),
+ io:put_chars(Fd, "cpl(<<>>, R) -> cp(R);\n"),
+ io:put_chars(Fd, "cpl(<<B/binary>>, R) -> {error,[B|R]}.\n"),
+ io:put_chars(Fd, "\n"),
+ io:put_chars(Fd, "%%%\n"),
+ io:put_chars(Fd, "\n"),
+ io:put_chars(Fd, "cpl_cont([C|T], R) when is_integer(C) -> [C|cpl_cont2(T, R)];\n"),
+ io:put_chars(Fd, "cpl_cont([L], R) -> cpl_cont(L, R);\n"),
+ io:put_chars(Fd, "cpl_cont([L|T], R) -> cpl_cont(L, [T|R]);\n"),
+ io:put_chars(Fd, "cpl_cont([], R) -> cpl_1_cont(R);\n"),
+ io:put_chars(Fd, "cpl_cont(T, R) -> [T|R].\n"),
+ io:put_chars(Fd, "\n"),
+ io:put_chars(Fd, "cpl_cont2([C|T], R) when is_integer(C) -> [C|cpl_cont3(T, R)];\n"),
+ io:put_chars(Fd, "cpl_cont2([L], R) -> cpl_cont2(L, R);\n"),
+ io:put_chars(Fd, "cpl_cont2([L|T], R) -> cpl_cont2(L, [T|R]);\n"),
+ io:put_chars(Fd, "cpl_cont2([], R) -> cpl_1_cont2(R);\n"),
+ io:put_chars(Fd, "cpl_cont2(T, R) -> [T|R].\n"),
+ io:put_chars(Fd, "\n"),
+ io:put_chars(Fd, "cpl_cont3([C], R) when is_integer(C) -> [C|R];\n"),
+ io:put_chars(Fd, "cpl_cont3([C|T], R) when is_integer(C) -> [C,T|R];\n"),
+ io:put_chars(Fd, "cpl_cont3([L], R) -> cpl_cont3(L, R);\n"),
+ io:put_chars(Fd, "cpl_cont3([L|T], R) -> cpl_cont3(L, [T|R]);\n"),
+ io:put_chars(Fd, "cpl_cont3([], R) -> cpl_1_cont3(R);\n"),
+ io:put_chars(Fd, "cpl_cont3(T, R) -> [T|R].\n"),
+ io:put_chars(Fd, "\n"),
+ io:put_chars(Fd, "%%%\n"),
+ io:put_chars(Fd, "\n"),
+ io:put_chars(Fd, "cpl_1_cont([C|T]) when is_integer(C) -> [C|cpl_1_cont2(T)];\n"),
+ io:put_chars(Fd, "cpl_1_cont([L]) -> cpl_1_cont(L);\n"),
+ io:put_chars(Fd, "cpl_1_cont([L|T]) -> cpl_cont(L, T);\n"),
+ io:put_chars(Fd, "cpl_1_cont(T) -> T.\n"),
+ io:put_chars(Fd, "\n"),
+ io:put_chars(Fd, "cpl_1_cont2([C|T]) when is_integer(C) -> [C|cpl_1_cont3(T)];\n"),
+ io:put_chars(Fd, "cpl_1_cont2([L]) -> cpl_1_cont2(L);\n"),
+ io:put_chars(Fd, "cpl_1_cont2([L|T]) -> cpl_cont2(L, T);\n"),
+ io:put_chars(Fd, "cpl_1_cont2(T) -> T.\n"),
+ io:put_chars(Fd, "\n"),
+ io:put_chars(Fd, "cpl_1_cont3([C|_]=T) when is_integer(C) -> T;\n"),
+ io:put_chars(Fd, "cpl_1_cont3([L]) -> cpl_1_cont3(L);\n"),
+ io:put_chars(Fd, "cpl_1_cont3([L|T]) -> cpl_cont3(L, T);\n"),
+ io:put_chars(Fd, "cpl_1_cont3(T) -> T.\n"),
+ io:put_chars(Fd, "\n"),
+ io:put_chars(Fd, "%%%\n"),
+ io:put_chars(Fd, "\n"),
+ io:put_chars(Fd, "cp_no_bin([C|_]=L) when is_integer(C) -> L;\n"),
+ io:put_chars(Fd, "cp_no_bin([List]) -> cp_no_bin(List);\n"),
+ io:put_chars(Fd, "cp_no_bin([List|R]) -> cp_no_binl(List, R);\n"),
+ io:put_chars(Fd, "cp_no_bin([]) -> [];\n"),
+ io:put_chars(Fd, "cp_no_bin(_) -> binary_found.\n"),
+ io:put_chars(Fd, "\n"),
+ io:put_chars(Fd, "cp_no_binl([C], R) when is_integer(C) -> [C|cpl_1_cont(R)];\n"),
+ io:put_chars(Fd, "cp_no_binl([C|T], R) when is_integer(C) -> [C|cpl_cont(T, R)];\n"),
+ io:put_chars(Fd, "cp_no_binl([List], R) -> cp_no_binl(List, R);\n"),
+ io:put_chars(Fd, "cp_no_binl([List|T], R) -> cp_no_binl(List, [T|R]);\n"),
+ io:put_chars(Fd, "cp_no_binl([], R) -> cp_no_bin(R);\n"),
+ io:put_chars(Fd, "cp_no_binl(_, _) -> binary_found.\n\n"),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -476,11 +541,26 @@ gen_gc(Fd, GBP) ->
"-spec gc(String::unicode:chardata()) ->"
" maybe_improper_list() | {error, unicode:chardata()}.\n"),
io:put_chars(Fd,
- "gc([CP1, CP2|_]=T)\n"
- " when CP1 < 256, CP2 < 256, CP1 =/= $\r -> %% Ascii Fast path\n"
- " T;\n"
+ "gc([]=R) -> R;\n"
+ "gc([CP]=R) when is_integer(CP) -> R;\n"
+ "gc([$\\r=CP|R0]) ->\n"
+ " case cp(R0) of % Don't break CRLF\n"
+ " [$\\n|R1] -> [[$\\r,$\\n]|R1];\n"
+ " T -> [CP|T]\n"
+ " end;\n"
+ "gc([CP1|T1]=T) when CP1 < 256 ->\n"
+ " case T1 of\n"
+ " [CP2|_] when CP2 < 256 -> T; %% Ascii Fast path\n"
+ " _ -> %% Keep the tail binary.\n"
+ " case cp_no_bin(T1) of\n"
+ " [CP2|_]=T3 when CP2 < 256 -> [CP1|T3]; %% Asciii Fast path\n"
+ " binary_found -> gc_1(T);\n"
+ " T4 -> gc_1([CP1|T4])\n"
+ " end\n"
+ " end;\n"
+ "gc(<<>>) -> [];\n"
"gc(<<CP1/utf8, Rest/binary>>) ->\n"
- " if CP1 < 256, CP1 =/= $\r ->\n"
+ " if CP1 < 256, CP1 =/= $\\r ->\n"
" case Rest of\n"
" <<CP2/utf8, _/binary>> when CP2 < 256 -> %% Ascii Fast path\n"
" [CP1|Rest];\n"
@@ -488,40 +568,52 @@ gen_gc(Fd, GBP) ->
" end;\n"
" true -> gc_1([CP1|Rest])\n"
" end;\n"
+ "gc([CP|_]=T) when is_integer(CP) -> gc_1(T);\n"
"gc(Str) ->\n"
- " gc_1(cp(Str)).\n\n"
- "gc_1([$\\r|R0] = R) ->\n"
+ " case cp(Str) of\n"
+ " {error,_}=Error -> Error;\n"
+ " CPs -> gc(CPs)\n"
+ " end.\n"
+ ),
+
+ GenExtP = fun(Range) -> io:format(Fd, "gc_1~s gc_ext_pict(R1,[CP]);\n", [gen_clause(Range)]) end,
+ ExtendedPictographic0 = merge_ranges(maps:get(extended_pictographic,GBP)),
+ %% Pick codepoints below 256 (some data knowledge here)
+ {ExtendedPictographicLow,ExtendedPictographicHigh} =
+ lists:splitwith(fun({Start,undefined}) -> Start < 256 end,ExtendedPictographic0),
+ io:put_chars(Fd,
+ "\ngc_1([$\\r|R0] = R) ->\n"
" case cp(R0) of % Don't break CRLF\n"
" [$\\n|R1] -> [[$\\r,$\\n]|R1];\n"
" _ -> R\n"
- " end;\n"
- %% "gc_1([CP1, CP2|_]=T) when CP1 < 256, CP2 < 256 ->\n"
- %% " T; %% Fast path\n"
- %% "gc_1([CP1|<<CP2/utf8, _/binary>>]=T) when CP1 < 256, CP2 < 256 ->\n"
- %% " T; %% Fast path\n"
- ),
-
- io:put_chars(Fd, "%% Handle control\n"),
+ " end;\n"),
+ io:put_chars(Fd, "\n%% Handle control\n"),
GenControl = fun(Range) -> io:format(Fd, "gc_1~s R0;\n", [gen_clause(Range)]) end,
CRs0 = merge_ranges(maps:get(cr, GBP) ++ maps:get(lf, GBP) ++ maps:get(control, GBP), false),
[R1,R2,R3|Crs] = CRs0,
[GenControl(CP) || CP <- merge_ranges([R1,R2,R3], split), CP =/= {$\r, undefined}],
%%GenControl(R1),GenControl(R2),GenControl(R3),
- io:format(Fd, "gc_1([CP|R]) when CP < 256 -> gc_extend(R,CP);\n", []),
+ io:put_chars(Fd, "\n%% Optimize Latin-1\n"),
+ [GenExtP(CP) || CP <- merge_ranges(ExtendedPictographicLow)],
+
+ io:format(Fd,
+ "gc_1([CP|R]=R0) when CP < 256 ->\n"
+ " case R of\n"
+ " [CP2|_] when CP2 < 256 -> R0;\n"
+ " _ -> gc_extend(cp(R), R, CP)\n"
+ " end;\n",
+ []),
+ io:put_chars(Fd, "\n%% Continue control\n"),
[GenControl(CP) || CP <- Crs],
%% One clause per CP
%% CRs0 = merge_ranges(maps:get(cr, GBP) ++ maps:get(lf, GBP) ++ maps:get(control, GBP)),
%% [GenControl(CP) || CP <- CRs0, CP =/= {$\r, undefined}],
- io:put_chars(Fd, "%% Handle ZWJ\n"),
- GenZWJ = fun(Range) -> io:format(Fd, "gc_1~s gc_zwj(R1, [CP]);\n", [gen_clause(Range)]) end,
- [GenZWJ(CP) || CP <- merge_ranges(maps:get(zwj,GBP))],
-
- io:put_chars(Fd, "%% Handle prepend\n"),
+ io:put_chars(Fd, "\n%% Handle prepend\n"),
GenPrepend = fun(Range) -> io:format(Fd, "gc_1~s gc_prepend(R1, CP);\n", [gen_clause(Range)]) end,
[GenPrepend(CP) || CP <- merge_ranges(maps:get(prepend,GBP))],
- io:put_chars(Fd, "%% Handle Hangul L\n"),
+ io:put_chars(Fd, "\n%% Handle Hangul L\n"),
GenHangulL = fun(Range) -> io:format(Fd, "gc_1~s gc_h_L(R1,[CP]);\n", [gen_clause(Range)]) end,
[GenHangulL(CP) || CP <- merge_ranges(maps:get(l,GBP))],
io:put_chars(Fd, "%% Handle Hangul V\n"),
@@ -531,21 +623,22 @@ gen_gc(Fd, GBP) ->
GenHangulT = fun(Range) -> io:format(Fd, "gc_1~s gc_h_T(R1,[CP]);\n", [gen_clause(Range)]) end,
[GenHangulT(CP) || CP <- merge_ranges(maps:get(t,GBP))],
io:put_chars(Fd, "%% Handle Hangul LV and LVT special, since they are large\n"),
- io:put_chars(Fd, "gc_1([CP|_]=R0) when 44000 < CP, CP < 56000 -> gc_h_lv_lvt(R0, []);\n"),
+ io:put_chars(Fd, "gc_1([CP|_]=R0) when 44000 < CP, CP < 56000 -> gc_h_lv_lvt(R0, R0, []);\n"),
- io:put_chars(Fd, "%% Handle Regional\n"),
- GenRegional = fun(Range) -> io:format(Fd, "gc_1~s gc_regional(R1,[CP]);\n", [gen_clause(Range)]) end,
+ io:put_chars(Fd, "\n%% Handle Regional\n"),
+ GenRegional = fun(Range) -> io:format(Fd, "gc_1~s gc_regional(R1,CP);\n", [gen_clause(Range)]) end,
[GenRegional(CP) || CP <- merge_ranges(maps:get(regional_indicator,GBP))],
- io:put_chars(Fd, "%% Handle E_Base\n"),
- GenEBase = fun(Range) -> io:format(Fd, "gc_1~s gc_e_cont(R1,[CP]);\n", [gen_clause(Range)]) end,
- [GenEBase(CP) || CP <- merge_ranges(maps:get(e_base,GBP))],
- io:put_chars(Fd, "%% Handle EBG\n"),
- GenEBG = fun(Range) -> io:format(Fd, "gc_1~s gc_e_cont(R1,[CP]);\n", [gen_clause(Range)]) end,
- [GenEBG(CP) || CP <- merge_ranges(maps:get(e_base_gaz,GBP))],
-
- io:put_chars(Fd, "gc_1([CP|R]) -> gc_extend(R, CP);\n"),
- io:put_chars(Fd, "gc_1([]) -> [];\n"),
- io:put_chars(Fd, "gc_1({error,_}=Error) -> Error.\n\n"),
+ %% io:put_chars(Fd, "%% Handle E_Base\n"),
+ %% GenEBase = fun(Range) -> io:format(Fd, "gc_1~s gc_e_cont(R1,[CP]);\n", [gen_clause(Range)]) end,
+ %% [GenEBase(CP) || CP <- merge_ranges(maps:get(e_base,GBP))],
+ %% io:put_chars(Fd, "%% Handle EBG\n"),
+ %% GenEBG = fun(Range) -> io:format(Fd, "gc_1~s gc_e_cont(R1,[CP]);\n", [gen_clause(Range)]) end,
+ %% [GenEBG(CP) || CP <- merge_ranges(maps:get(e_base_gaz,GBP))],
+
+ io:put_chars(Fd, "%% Handle extended_pictographic\n"),
+ [GenExtP(CP) || CP <- merge_ranges(ExtendedPictographicHigh)],
+ io:put_chars(Fd, "\n%% default clauses\n"),
+ io:put_chars(Fd, "gc_1([CP|R]) -> gc_extend(cp(R), R, CP).\n\n"),
io:put_chars(Fd, "%% Handle Prepend\n"),
io:put_chars(Fd,
@@ -572,36 +665,24 @@ gen_gc(Fd, GBP) ->
"%% To simplify binary handling in libraries the tail should be kept binary\n"
"%% and not a lookahead CP\n"
),
- io:put_chars(Fd, "gc_extend(T, Acc) ->\n"
- " gc_extend(cp(T), T, Acc).\n\n"),
io:put_chars(Fd,
- "gc_extend([CP|T], T0, Acc0) ->\n"
+ "gc_extend([CP|T], T0, CP0) ->\n"
" case is_extend(CP) of\n"
- " zwj ->\n"
- " case Acc0 of\n"
- " [_|_] -> gc_zwj(T, [CP|Acc0]);\n"
- " Acc -> gc_zwj(T, [CP,Acc])\n"
- " end;\n"
- " true ->\n"
- " case Acc0 of\n"
- " [_|_] -> gc_extend(T, [CP|Acc0]);\n"
- " Acc -> gc_extend(T, [CP,Acc])\n"
- " end;\n"
- " false ->\n"
- " case Acc0 of\n"
- " [Acc] -> [Acc|T0];\n"
- " [_|_]=Acc -> [lists:reverse(Acc)|T0];\n"
- " Acc -> [Acc|T0]\n"
- " end\n"
+ " false -> [CP0|T0]; % losing work done on T\n"
+ " _TrueOrZWJ -> gc_extend2(cp(T), T, [CP,CP0])\n"
" end;\n"
- "gc_extend([], _, Acc0) ->\n"
- " case Acc0 of\n"
- " [_]=Acc -> Acc;\n"
- " [_|_]=Acc -> [lists:reverse(Acc)];\n"
- " Acc -> [Acc]\n"
+ "gc_extend([], _, CP) -> [CP];\n"
+ "gc_extend({error,R}, _, CP) -> [CP|R].\n\n"),
+ io:put_chars(Fd,
+ "gc_extend2([CP|T], T0, Acc) ->\n"
+ " case is_extend(CP) of\n"
+ " false -> [lists:reverse(Acc)|T0]; % losing work done on T\n"
+ " _TrueOrZWJ -> gc_extend2(cp(T), T, [CP|Acc])\n"
" end;\n"
- "gc_extend({error,R}, T, Acc0) ->\n"
- " gc_extend([], T, Acc0) ++ [R].\n\n"
+ "gc_extend2([], _, Acc) ->\n"
+ " [lists:reverse(Acc)];\n"
+ "gc_extend2({error,R}, _, Acc) ->\n"
+ " [lists:reverse(Acc)] ++ [R].\n\n"
),
[ZWJ] = maps:get(zwj, GBP),
GenExtend = fun(R) when R =:= ZWJ -> io:format(Fd, "is_extend~s zwj;\n", [gen_single_clause(ZWJ)]);
@@ -612,57 +693,54 @@ gen_gc(Fd, GBP) ->
io:put_chars(Fd, "is_extend(_) -> false.\n\n"),
io:put_chars(Fd,
- "gc_e_cont(R0, Acc) ->\n"
- " case cp(R0) of\n"
- " [CP|R1] ->\n"
- " case is_extend(CP) of\n"
- " zwj -> gc_zwj(R1, [CP|Acc]);\n"
- " true -> gc_e_cont(R1, [CP|Acc]);\n"
- " false ->\n"
- " case is_emodifier(CP) of\n"
- " true -> [lists:reverse([CP|Acc])|R1];\n"
- " false ->\n"
- " case Acc of\n"
- " [A] -> [A|R0];\n"
- " _ -> [lists:reverse(Acc)|R0]\n"
- " end\n"
- " end\n"
- " end;\n"
- " [] ->\n"
+ "gc_ext_pict(T, Acc) ->\n"
+ " gc_ext_pict(cp(T), T, Acc).\n\n"
+ "gc_ext_pict([CP|R1], T0, Acc) ->\n"
+ " case is_extend(CP) of\n"
+ " zwj -> gc_ext_pict_zwj(cp(R1), R1, [CP|Acc]);\n"
+ " true -> gc_ext_pict(R1, [CP|Acc]);\n"
+ " false ->\n"
" case Acc of\n"
- " [A] -> [A];\n"
- " _ -> [lists:reverse(Acc)]\n"
- " end;\n"
- " {error,R} ->\n"
+ " [A] -> [A|T0];\n"
+ " _ -> [lists:reverse(Acc)|T0]\n"
+ " end\n"
+ " end;\n"
+ "gc_ext_pict([], _T0, Acc) ->\n"
+ " case Acc of\n"
+ " [A] -> [A];\n"
+ " _ -> [lists:reverse(Acc)]\n"
+ " end;\n"
+ "gc_ext_pict({error,R}, T, Acc) ->\n"
+ " gc_ext_pict([], T, Acc) ++ [R].\n\n"),
+ io:put_chars(Fd,
+ "gc_ext_pict_zwj([CP|R1], T0, Acc) ->\n"
+ " case is_ext_pict(CP) of\n"
+ " true -> gc_ext_pict(R1, [CP|Acc]);\n"
+ " false ->\n"
" case Acc of\n"
- " [A] -> [A|R];\n"
- " _ -> [lists:reverse(Acc)|R]\n"
+ " [A] -> [A|T0];\n"
+ " _ -> [lists:reverse(Acc)|T0]\n"
" end\n"
- " end.\n\n"),
-
- GenEMod = fun(Range) -> io:format(Fd, "is_emodifier~s true;\n", [gen_single_clause(Range)]) end,
- EMods = merge_ranges(maps:get(e_modifier, GBP), split),
- [GenEMod(CP) || CP <- EMods],
- io:put_chars(Fd, "is_emodifier(_) -> false.\n\n"),
-
- io:put_chars(Fd, "gc_zwj(R0, Acc) ->\n case cp(R0) of\n"),
- GenZWJGlue = fun(Range) -> io:format(Fd, "~8c~s gc_extend(R1, R0, [CP|Acc]);\n",
- [$\s,gen_case_clause(Range)]) end,
- [GenZWJGlue(CP) || CP <- merge_ranges(maps:get(glue_after_zwj,GBP))],
- GenZWJEBG = fun(Range) -> io:format(Fd, "~8c~s gc_e_cont(R1, [CP|Acc]);\n",
- [$\s,gen_case_clause(Range)]) end,
- [GenZWJEBG(CP) || CP <- merge_ranges(maps:get(e_base_gaz,GBP))],
- io:put_chars(Fd," R1 -> gc_extend(R1, R0, Acc)\n"
- " end.\n\n"),
+ " end;\n"
+ "gc_ext_pict_zwj([], _, Acc) ->\n"
+ " case Acc of\n"
+ " [A] -> [A];\n"
+ " _ -> [lists:reverse(Acc)]\n"
+ " end;\n"
+ "gc_ext_pict_zwj({error,R}, T, Acc) ->\n"
+ " gc_ext_pict_zwj([], T, Acc) ++ [R].\n\n"),
+ GenExtPict = fun(Range) -> io:format(Fd, "is_ext_pict~s true;\n", [gen_single_clause(Range)]) end,
+ [GenExtPict(CP) || CP <- ExtendedPictographic0],
+ io:put_chars(Fd, "is_ext_pict(_) -> false.\n\n"),
%% --------------------
io:put_chars(Fd, "%% Handle Regional\n"),
[{RLess,RLarge}] = merge_ranges(maps:get(regional_indicator,GBP)),
- io:put_chars(Fd,"gc_regional(R0, Acc) ->\n"
+ io:put_chars(Fd,"gc_regional(R0, CP0) ->\n"
" case cp(R0) of\n"),
- io:format(Fd, " [CP|R1] when ~w =< CP,CP =< ~w-> gc_extend(R1,[CP|Acc]);~n",[RLess, RLarge]),
- io:put_chars(Fd," R1 -> gc_extend(R1, R0, Acc)\n"
+ io:format(Fd, " [CP|R1] when ~w =< CP,CP =< ~w-> gc_extend2(cp(R1),R1,[CP,CP0]);~n",[RLess, RLarge]),
+ io:put_chars(Fd," R1 -> gc_extend(R1, R0, CP0)\n"
" end.\n\n"),
%% Special hangul
@@ -674,7 +752,7 @@ gen_gc(Fd, GBP) ->
GenHangulL_2 = fun(Range) -> io:format(Fd, "~8c~s gc_h_V(R1,[CP|Acc]);\n",
[$\s,gen_case_clause(Range)]) end,
[GenHangulL_2(CP) || CP <- merge_ranges(maps:get(v,GBP))],
- io:put_chars(Fd, " R1 -> gc_h_lv_lvt(R1, Acc)\n end.\n\n"),
+ io:put_chars(Fd, " R1 -> gc_h_lv_lvt(R1, R0, Acc)\n end.\n\n"),
io:put_chars(Fd, "%% Handle Hangul V\n"),
io:put_chars(Fd, "gc_h_V(R0, Acc) ->\n case cp(R0) of\n"),
@@ -684,16 +762,23 @@ gen_gc(Fd, GBP) ->
GenHangulV_2 = fun(Range) -> io:format(Fd, "~8c~s gc_h_T(R1,[CP|Acc]);\n",
[$\s,gen_case_clause(Range)]) end,
[GenHangulV_2(CP) || CP <- merge_ranges(maps:get(t,GBP))],
- io:put_chars(Fd, " R1 -> gc_extend(R1, R0, Acc)\n end.\n\n"),
-
+ io:put_chars(Fd,
+ " R1 ->\n"
+ " case Acc of\n"
+ " [CP] -> gc_extend(R1, R0, CP);\n"
+ " _ -> gc_extend2(R1, R0, Acc)\n"
+ " end\n end.\n\n"),
io:put_chars(Fd, "%% Handle Hangul T\n"),
io:put_chars(Fd, "gc_h_T(R0, Acc) ->\n case cp(R0) of\n"),
GenHangulT_1 = fun(Range) -> io:format(Fd, "~8c~s gc_h_T(R1,[CP|Acc]);\n",
[$\s,gen_case_clause(Range)]) end,
[GenHangulT_1(CP) || CP <- merge_ranges(maps:get(t,GBP))],
- io:put_chars(Fd, " R1 -> gc_extend(R1, R0, Acc)\n end.\n\n"),
-
- io:put_chars(Fd, "gc_h_lv_lvt({error,_}=Error, Acc) -> gc_extend(Error, [], Acc);\n"),
+ io:put_chars(Fd,
+ " R1 ->\n"
+ " case Acc of\n"
+ " [CP] -> gc_extend(R1, R0, CP);\n"
+ " _ -> gc_extend2(R1, R0, Acc)\n"
+ " end\n end.\n\n"),
io:put_chars(Fd, "%% Handle Hangul LV\n"),
GenHangulLV = fun(Range) -> io:format(Fd, "gc_h_lv_lvt~s gc_h_V(R1,[CP|Acc]);\n",
[gen_clause2(Range)]) end,
@@ -702,8 +787,10 @@ gen_gc(Fd, GBP) ->
GenHangulLVT = fun(Range) -> io:format(Fd, "gc_h_lv_lvt~s gc_h_T(R1,[CP|Acc]);\n",
[gen_clause2(Range)]) end,
[GenHangulLVT(CP) || CP <- merge_ranges(maps:get(lvt,GBP))],
- io:put_chars(Fd, "gc_h_lv_lvt([CP|R], []) -> gc_extend(R, CP);\n"), %% From gc_1/1
- io:put_chars(Fd, "gc_h_lv_lvt(R, Acc) -> gc_extend(R, Acc).\n\n"),
+ io:put_chars(Fd, "gc_h_lv_lvt([CP|R1], _, []) -> gc_extend(cp(R1), R1, CP);\n"), %% From gc_1/1
+ io:put_chars(Fd, "%% Also handles error tuples\n"),
+ io:put_chars(Fd, "gc_h_lv_lvt(R1, R0, [CP]) -> gc_extend(R1, R0, CP);\n"),
+ io:put_chars(Fd, "gc_h_lv_lvt(R1, R0, Acc) -> gc_extend2(R1, R0, Acc).\n\n"),
ok.
gen_compose_pairs(Fd, ExclData, Data) ->
@@ -804,9 +891,9 @@ gen_clause({R0, R1}) ->
io_lib:format("([CP|R1]=R0) when ~w =< CP, CP =< ~w ->", [R0,R1]).
gen_clause2({R0, undefined}) ->
- io_lib:format("([~w=CP|R1], Acc) ->", [R0]);
+ io_lib:format("([~w=CP|R1], R0, Acc) ->", [R0]);
gen_clause2({R0, R1}) ->
- io_lib:format("([CP|R1], Acc) when ~w =< CP, CP =< ~w ->", [R0,R1]).
+ io_lib:format("([CP|R1], R0, Acc) when ~w =< CP, CP =< ~w ->", [R0,R1]).
gen_case_clause({R0, undefined}) ->
io_lib:format("[~w=CP|R1] ->", [R0]);
@@ -886,10 +973,10 @@ optimize_ranges_1(Rs) ->
hex_to_int([]) -> [];
hex_to_int(HexStr) ->
- list_to_integer(string:strip(HexStr, both), 16).
+ list_to_integer(string:trim(HexStr, both), 16).
to_atom(Str) ->
- list_to_atom(string:to_lower(string:strip(Str, both))).
+ list_to_atom(string:lowercase(string:trim(Str, both))).
foldl(Fun, Acc, Fd) ->
Get = fun() -> file:read_line(Fd) end,
@@ -909,7 +996,7 @@ foldl_1(Fun, Acc, Get) ->
-%% Differs from string:tokens, it returns empty string as token between two delimiters
+%% Differs from string:lexemes, it returns empty string as token between two delimiters
tokens(S, [C]) ->
tokens(lists:reverse(S), C, []).
diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk
index 8391389fc4..07224afdc9 100644
--- a/lib/stdlib/vsn.mk
+++ b/lib/stdlib/vsn.mk
@@ -1 +1 @@
-STDLIB_VSN = 3.4.4
+STDLIB_VSN = 3.9
diff --git a/lib/syntax_tools/doc/demo.erl b/lib/syntax_tools/doc/demo.erl
new file mode 120000
index 0000000000..fe40fb65ec
--- /dev/null
+++ b/lib/syntax_tools/doc/demo.erl
@@ -0,0 +1 @@
+../examples/demo.erl \ No newline at end of file
diff --git a/lib/syntax_tools/doc/overview.edoc b/lib/syntax_tools/doc/overview.edoc
index 3111633a99..7be96f1a55 100644
--- a/lib/syntax_tools/doc/overview.edoc
+++ b/lib/syntax_tools/doc/overview.edoc
@@ -26,7 +26,7 @@ library module {@link prettypr}: this is a powerful and flexible generic
pretty printing library, which is also distributed separately.
For a short demonstration of parsing and pretty-printing, simply
-compile the included module <a href="../examples/demo.erl">`demo.erl'</a>,
+compile the included module <a href="demo.erl">`demo.erl'</a>,
and execute `demo:run()' from the Erlang shell. It will compile the
remaining modules and give you further instructions.
diff --git a/lib/syntax_tools/doc/src/Makefile b/lib/syntax_tools/doc/src/Makefile
index 1ce620b3d6..b799c76177 100644
--- a/lib/syntax_tools/doc/src/Makefile
+++ b/lib/syntax_tools/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2006-2017. All Rights Reserved.
+# Copyright Ericsson AB 2006-2019. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -63,10 +63,11 @@ BOOK_FILES = book.xml
XML_FILES=\
- $(BOOK_FILES) $(XML_CHAPTER_FILES) \
- $(XML_PART_FILES) $(XML_REF3_FILES) $(XML_APPLICATION_FILES) \
+ $(BOOK_FILES) $(XML_PART_FILES) $(XML_APPLICATION_FILES) \
$(XML_NOTES_FILES)
+XML_GEN_FILES = $(XML_REF3_FILES:%=$(XMLDIR)/%) $(XML_CHAPTER_FILES:%=$(XMLDIR)/%)
+
# ----------------------------------------------------
INFO_FILE = ../../info
@@ -81,6 +82,9 @@ HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
+EXAMPLES_DIR = ../../examples
+EXAMPLES = $(EXAMPLES_DIR)/demo.erl
+
SPECS_FILES = $(XML_REF3_FILES:%.xml=$(SPECDIR)/specs_%.xml)
TOP_SPECS_FILE = specs.xml
@@ -108,11 +112,13 @@ html: gifs $(HTML_REF_MAN_FILE)
man: $(MAN3_FILES)
-$(XML_REF3_FILES):
- escript $(DOCGEN)/priv/bin/xml_from_edoc.escript $(SRC_DIR)/$(@:%.xml=%.erl)
+$(XML_REF3_FILES:%=$(XMLDIR)/%):
+ $(gen_verbose)escript $(DOCGEN)/priv/bin/xml_from_edoc.escript \
+ -dir $(XMLDIR) $(SRC_DIR)/$(@:$(XMLDIR)/%.xml=%.erl)
-$(XML_CHAPTER_FILES):
- escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(VSN) -chapter ../overview.edoc
+$(XML_CHAPTER_FILES:%=$(XMLDIR)/%):
+ $(gen_verbose)escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(VSN) \
+ -chapter -dir $(XMLDIR) ../overview.edoc
gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
@@ -122,6 +128,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(XML_REF3_FILES) $(XML_CHAPTER_FILES) *.html
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
@@ -142,5 +149,7 @@ release_docs_spec: docs
$(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
$(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
$(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples"
+ $(INSTALL_DATA) $(EXAMPLES) "$(RELSYSDIR)/doc/html"
release_spec:
diff --git a/lib/syntax_tools/doc/src/notes.xml b/lib/syntax_tools/doc/src/notes.xml
index bd2bcde2c2..a2dd78f280 100644
--- a/lib/syntax_tools/doc/src/notes.xml
+++ b/lib/syntax_tools/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2007</year><year>2017</year>
+ <year>2007</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,6 +32,111 @@
<p>This document describes the changes made to the Syntax_Tools
application.</p>
+<section><title>Syntax_Tools 2.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ All incorrect (that is, all) uses of "can not" has been
+ corrected to "cannot" in source code comments,
+ documentation, examples, and so on.</p>
+ <p>
+ Own Id: OTP-14282 Aux Id: PR-1891 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> Correct links in the documentation. </p>
+ <p>
+ Own Id: OTP-15761</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Syntax_Tools 2.1.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Fix pretty-printing of type funs. </p>
+ <p>
+ Own Id: OTP-15519 Aux Id: ERL-815 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Syntax_Tools 2.1.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix the <c>TypeName</c> type in erl_syntax_lib.</p>
+ <p>
+ Own Id: OTP-15207 Aux Id: PR-1888 </p>
+ </item>
+ <item>
+ <p> Correct unfolding of the stacktrace variable. </p>
+ <p>
+ Own Id: OTP-15291 Aux Id: ERL-719 </p>
+ </item>
+ <item>
+ <p> Correct <c>erl_syntax:revert/1</c> bug regarding the
+ types <c>map()</c> and <c>tuple()</c>. </p>
+ <p>
+ Own Id: OTP-15294</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> Support bitstrings as literals in module
+ <c>erl_syntax</c>. </p>
+ <p>
+ Own Id: OTP-15165 Aux Id: PR-1842 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Syntax_Tools 2.1.5</title>
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Update to use the new string api instead of the old.</p>
+ <p>
+ Own Id: OTP-15036</p>
+ </item>
+ </list>
+ </section>
+</section>
+
+<section><title>Syntax_Tools 2.1.4.1</title>
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Fix a bug regarding reverting map types. </p>
+ <p>
+ Own Id: OTP-15098 Aux Id: ERIERL-177 </p>
+ </item>
+ </list>
+ </section>
+</section>
+
<section><title>Syntax_Tools 2.1.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -83,6 +188,20 @@
</section>
+<section><title>Syntax_Tools 2.1.1.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Fix a bug regarding reverting map types. </p>
+ <p>
+ Own Id: OTP-15098 Aux Id: ERIERL-177 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Syntax_Tools 2.1.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/syntax_tools/src/Makefile b/lib/syntax_tools/src/Makefile
index 8325db45a8..c21d2f49c8 100644
--- a/lib/syntax_tools/src/Makefile
+++ b/lib/syntax_tools/src/Makefile
@@ -75,7 +75,7 @@ $(EBIN)/%.$(EMULATOR):%.erl
# special rules and dependencies to apply the transform to itself
$(EBIN)/merl_transform.beam: $(EBIN)/merl.beam ./merl_transform.beam \
- ../include/merl.hrl \
+ ../include/merl.hrl $(EBIN)/erl_comment_scan.beam \
$(EBIN)/erl_syntax.beam $(EBIN)/erl_syntax_lib.beam
./merl_transform.beam: ./merl_transform.erl $(EBIN)/merl.beam \
../include/merl.hrl
diff --git a/lib/syntax_tools/src/epp_dodger.erl b/lib/syntax_tools/src/epp_dodger.erl
index 0a12e8fd8b..7e741cc649 100644
--- a/lib/syntax_tools/src/epp_dodger.erl
+++ b/lib/syntax_tools/src/epp_dodger.erl
@@ -502,6 +502,10 @@ quickscan_form([{'-', _L}, {atom, La, ifdef} | _Ts]) ->
kill_form(La);
quickscan_form([{'-', _L}, {atom, La, ifndef} | _Ts]) ->
kill_form(La);
+quickscan_form([{'-', _L}, {'if', La} | _Ts]) ->
+ kill_form(La);
+quickscan_form([{'-', _L}, {atom, La, elif} | _Ts]) ->
+ kill_form(La);
quickscan_form([{'-', _L}, {atom, La, else} | _Ts]) ->
kill_form(La);
quickscan_form([{'-', _L}, {atom, La, endif} | _Ts]) ->
@@ -615,8 +619,13 @@ filter_form(T) ->
%% ---------------------------------------------------------------------
%% Normal parsing - try to preserve all information
-normal_parser(Ts, Opt) ->
- rewrite_form(parse_tokens(scan_form(Ts, Opt))).
+normal_parser(Ts0, Opt) ->
+ case scan_form(Ts0, Opt) of
+ Ts when is_list(Ts) ->
+ rewrite_form(parse_tokens(Ts));
+ Node ->
+ Node
+ end.
scan_form([{'-', _L}, {atom, La, define} | Ts], Opt) ->
[{atom, La, ?pp_form}, {'(', La}, {')', La}, {'->', La},
@@ -636,12 +645,26 @@ scan_form([{'-', _L}, {atom, La, ifdef} | Ts], Opt) ->
scan_form([{'-', _L}, {atom, La, ifndef} | Ts], Opt) ->
[{atom, La, ?pp_form}, {'(', La}, {')', La}, {'->', La},
{atom, La, ifndef} | scan_macros(Ts, Opt)];
+scan_form([{'-', _L}, {'if', La} | Ts], Opt) ->
+ [{atom, La, ?pp_form}, {'(', La}, {')', La}, {'->', La},
+ {atom, La, 'if'} | scan_macros(Ts, Opt)];
+scan_form([{'-', _L}, {atom, La, elif} | Ts], Opt) ->
+ [{atom, La, ?pp_form}, {'(', La}, {')', La}, {'->', La},
+ {atom, La, 'elif'} | scan_macros(Ts, Opt)];
scan_form([{'-', _L}, {atom, La, else} | Ts], Opt) ->
[{atom, La, ?pp_form}, {'(', La}, {')', La}, {'->', La},
{atom, La, else} | scan_macros(Ts, Opt)];
scan_form([{'-', _L}, {atom, La, endif} | Ts], Opt) ->
[{atom, La, ?pp_form}, {'(', La}, {')', La}, {'->', La},
{atom, La, endif} | scan_macros(Ts, Opt)];
+scan_form([{'-', _L}, {atom, La, error} | Ts], _Opt) ->
+ Desc = build_info_string("-error", Ts),
+ ErrorInfo = {La, ?MODULE, {error, Desc}},
+ erl_syntax:error_marker(ErrorInfo);
+scan_form([{'-', _L}, {atom, La, warning} | Ts], _Opt) ->
+ Desc = build_info_string("-warning", Ts),
+ ErrorInfo = {La, ?MODULE, {warning, Desc}},
+ erl_syntax:error_marker(ErrorInfo);
scan_form([{'-', L}, {'?', L1}, {Type, _, _}=N | [{'(', _} | _]=Ts], Opt)
when Type =:= atom; Type =:= var ->
%% minus, macro and open parenthesis at start of form - assume that
@@ -657,6 +680,11 @@ scan_form([{'?', L}, {Type, _, _}=N | [{'(', _} | _]=Ts], Opt)
scan_form(Ts, Opt) ->
scan_macros(Ts, Opt).
+build_info_string(Prefix, Ts0) ->
+ Ts = lists:droplast(Ts0),
+ String = lists:droplast(tokens_to_string(Ts)),
+ Prefix ++ " " ++ String ++ ".".
+
scan_macros(Ts, Opt) ->
scan_macros(Ts, [], Opt).
@@ -865,6 +893,10 @@ tokens_to_string([]) ->
format_error(macro_args) ->
errormsg("macro call missing end parenthesis");
+format_error({error, Error}) ->
+ Error;
+format_error({warning, Error}) ->
+ Error;
format_error({unknown, Reason}) ->
errormsg(io_lib:format("unknown error: ~tP", [Reason, 15])).
diff --git a/lib/syntax_tools/src/erl_comment_scan.erl b/lib/syntax_tools/src/erl_comment_scan.erl
index 07e501e553..e3eb95b819 100644
--- a/lib/syntax_tools/src/erl_comment_scan.erl
+++ b/lib/syntax_tools/src/erl_comment_scan.erl
@@ -208,7 +208,7 @@ scan_comment([], Cs1, L, Col, M, Ack) ->
seen_comment(Cs, Cs1, L, Col, M, Ack) ->
%% Compute indentation and strip trailing spaces
N = Col - M,
- Text = lists:reverse(string:strip(Cs1, left)),
+ Text = lists:reverse(string:trim(Cs1, leading)),
Ack1 = [{L, Col + 1, N, Text} | Ack],
scan_lines(Cs, L + 1, 0, 0, Ack1).
diff --git a/lib/syntax_tools/src/erl_prettypr.erl b/lib/syntax_tools/src/erl_prettypr.erl
index 40ddd2b22a..6ad9bec2e6 100644
--- a/lib/syntax_tools/src/erl_prettypr.erl
+++ b/lib/syntax_tools/src/erl_prettypr.erl
@@ -675,7 +675,12 @@ lay_2(Node, Ctxt) ->
%% attribute name, without following parentheses.
Ctxt1 = reset_prec(Ctxt),
Args = erl_syntax:attribute_arguments(Node),
- N = erl_syntax:attribute_name(Node),
+ N = case erl_syntax:attribute_name(Node) of
+ {atom, _, 'if'} ->
+ erl_syntax:variable('if');
+ N0 ->
+ N0
+ end,
D = case attribute_type(Node) of
spec ->
[SpecTuple] = Args,
@@ -774,9 +779,16 @@ lay_2(Node, Ctxt) ->
class_qualifier ->
Ctxt1 = set_prec(Ctxt, max_prec()),
D1 = lay(erl_syntax:class_qualifier_argument(Node), Ctxt1),
- D2 = lay(erl_syntax:class_qualifier_body(Node), Ctxt1),
- beside(D1, beside(text(":"), D2));
-
+ D2 = lay(erl_syntax:class_qualifier_body(Node), Ctxt1),
+ Stacktrace = erl_syntax:class_qualifier_stacktrace(Node),
+ case erl_syntax:variable_name(Stacktrace) of
+ '_' ->
+ beside(D1, beside(text(":"), D2));
+ _ ->
+ D3 = lay(Stacktrace, Ctxt1),
+ beside(D1, beside(beside(text(":"), D2),
+ beside(text(":"), D3)))
+ end;
comment ->
D = stack_comment_lines(
erl_syntax:comment_text(Node)),
@@ -1089,8 +1101,9 @@ lay_2(Node, Ctxt) ->
Ctxt1 = reset_prec(Ctxt),
D1 = lay(erl_syntax:constrained_function_type_body(Node),
Ctxt1),
+ Ctxt2 = Ctxt1#ctxt{clause = undefined},
D2 = lay(erl_syntax:constrained_function_type_argument(Node),
- Ctxt1),
+ Ctxt2),
beside(D1,
beside(floating(text(" when ")), D2));
@@ -1101,7 +1114,7 @@ lay_2(Node, Ctxt) ->
_ ->
{"fun(", ")"}
end,
- Ctxt1 = reset_prec(Ctxt),
+ Ctxt1 = (reset_prec(Ctxt))#ctxt{clause = undefined},
D1 = case erl_syntax:function_type_arguments(Node) of
any_arity ->
text("(...)");
diff --git a/lib/syntax_tools/src/erl_syntax.erl b/lib/syntax_tools/src/erl_syntax.erl
index 9b2b503762..1be644c620 100644
--- a/lib/syntax_tools/src/erl_syntax.erl
+++ b/lib/syntax_tools/src/erl_syntax.erl
@@ -342,8 +342,10 @@
typed_record_field_body/1,
typed_record_field_type/1,
class_qualifier/2,
+ class_qualifier/3,
class_qualifier_argument/1,
class_qualifier_body/1,
+ class_qualifier_stacktrace/1,
tuple/1,
tuple_elements/1,
tuple_size/1,
@@ -3884,7 +3886,7 @@ fold_try_clause({clause, Pos, [P], Guard, Body}) ->
class_qualifier ->
{tuple, Pos, [class_qualifier_argument(P),
class_qualifier_body(P),
- {var, Pos, '_'}]};
+ class_qualifier_stacktrace(P)]};
_ ->
{tuple, Pos, [{atom, Pos, throw}, P, {var, Pos, '_'}]}
end,
@@ -3893,12 +3895,14 @@ fold_try_clause({clause, Pos, [P], Guard, Body}) ->
unfold_try_clauses(Cs) ->
[unfold_try_clause(C) || C <- Cs].
-unfold_try_clause({clause, Pos, [{tuple, _, [{atom, _, throw}, V, _]}],
+unfold_try_clause({clause, Pos, [{tuple, _, [{atom, _, throw},
+ V,
+ {var, _, '_'}]}],
Guard, Body}) ->
{clause, Pos, [V], Guard, Body};
-unfold_try_clause({clause, Pos, [{tuple, _, [C, V, _]}],
+unfold_try_clause({clause, Pos, [{tuple, _, [C, V, Stacktrace]}],
Guard, Body}) ->
- {clause, Pos, [class_qualifier(C, V)], Guard, Body}.
+ {clause, Pos, [class_qualifier(C, V, Stacktrace)], Guard, Body}.
%% =====================================================================
@@ -5324,7 +5328,7 @@ revert_map_type_assoc(Node) ->
Pos = get_pos(Node),
Name = map_type_assoc_name(Node),
Value = map_type_assoc_value(Node),
- {type, Pos, map_type_assoc, [Name, Value]}.
+ {type, Pos, map_field_assoc, [Name, Value]}.
%% =====================================================================
@@ -5382,7 +5386,7 @@ revert_map_type_exact(Node) ->
Pos = get_pos(Node),
Name = map_type_exact_name(Node),
Value = map_type_exact_value(Node),
- {type, Pos, map_type_exact, [Name, Value]}.
+ {type, Pos, map_field_exact, [Name, Value]}.
%% =====================================================================
@@ -5451,8 +5455,12 @@ map_type(Fields) ->
revert_map_type(Node) ->
Pos = get_pos(Node),
- {type, Pos, map, map_type_fields(Node)}.
-
+ case map_type_fields(Node) of
+ any_size ->
+ {type, Pos, map, any};
+ Fields ->
+ {type, Pos, map, Fields}
+ end.
%% =====================================================================
%% @doc Returns the list of field subtrees of a `map_type' node.
@@ -5710,7 +5718,12 @@ tuple_type(Elements) ->
revert_tuple_type(Node) ->
Pos = get_pos(Node),
- {type, Pos, tuple, tuple_type_elements(Node)}.
+ case tuple_type_elements(Node) of
+ any_size ->
+ {type, Pos, tuple, any};
+ TypeElements ->
+ {type, Pos, tuple, TypeElements}
+ end.
%% =====================================================================
@@ -6725,9 +6738,12 @@ try_expr_after(Node) ->
%%
%% @see class_qualifier_argument/1
%% @see class_qualifier_body/1
+%% @see class_qualifier_stacktrace/1
%% @see try_expr/4
--record(class_qualifier, {class :: syntaxTree(), body :: syntaxTree()}).
+-record(class_qualifier, {class :: syntaxTree(),
+ body :: syntaxTree(),
+ stacktrace :: syntaxTree()}).
%% type(Node) = class_qualifier
%% data(Node) = #class_qualifier{class :: Class, body :: Body}
@@ -6737,8 +6753,27 @@ try_expr_after(Node) ->
-spec class_qualifier(syntaxTree(), syntaxTree()) -> syntaxTree().
class_qualifier(Class, Body) ->
+ Underscore = {var, get_pos(Body), '_'},
tree(class_qualifier,
- #class_qualifier{class = Class, body = Body}).
+ #class_qualifier{class = Class, body = Body,
+ stacktrace = Underscore}).
+
+%% =====================================================================
+%% @doc Creates an abstract class qualifier. The result represents
+%% "<code><em>Class</em>:<em>Body</em>:<em>Stacktrace</em></code>".
+%%
+%% @see class_qualifier_argument/1
+%% @see class_qualifier_body/1
+%% @see try_expr/4
+
+-spec class_qualifier(syntaxTree(), syntaxTree(), syntaxTree()) ->
+ syntaxTree().
+
+class_qualifier(Class, Body, Stacktrace) ->
+ tree(class_qualifier,
+ #class_qualifier{class = Class,
+ body = Body,
+ stacktrace = Stacktrace}).
%% =====================================================================
@@ -6763,6 +6798,16 @@ class_qualifier_argument(Node) ->
class_qualifier_body(Node) ->
(data(Node))#class_qualifier.body.
+%% =====================================================================
+%% @doc Returns the stacktrace subtree of a `class_qualifier' node.
+%%
+%% @see class_qualifier/2
+
+-spec class_qualifier_stacktrace(syntaxTree()) -> syntaxTree().
+
+class_qualifier_stacktrace(Node) ->
+ (data(Node))#class_qualifier.stacktrace.
+
%% =====================================================================
%% @doc Creates an abstract "implicit fun" expression. If
@@ -7187,7 +7232,7 @@ macro_arguments(Node) ->
%% @doc Returns the syntax tree corresponding to an Erlang term.
%% `Term' must be a literal term, i.e., one that can be
%% represented as a source code literal. Thus, it may not contain a
-%% process identifier, port, reference, binary or function value as a
+%% process identifier, port, reference or function value as a
%% subterm. The function recognises printable strings, in order to get a
%% compact and readable representation. Evaluation fails with reason
%% `badarg' if `Term' is not a literal term.
@@ -7221,6 +7266,13 @@ abstract(T) when is_map(T) ->
|| {Key,Value} <- maps:to_list(T)]);
abstract(T) when is_binary(T) ->
binary([binary_field(integer(B)) || B <- binary_to_list(T)]);
+abstract(T) when is_bitstring(T) ->
+ S = bit_size(T),
+ ByteS = S div 8,
+ BitS = S rem 8,
+ <<Bin:ByteS/binary, I:BitS>> = T,
+ binary([binary_field(integer(B)) || B <- binary_to_list(Bin)]
+ ++ [binary_field(integer(I), integer(BitS), [])]);
abstract(T) ->
erlang:error({badarg, T}).
@@ -7296,15 +7348,20 @@ concrete(Node) ->
Node0 -> maps:merge(concrete(Node0),M0)
end;
binary ->
- Fs = [revert_binary_field(
- binary_field(binary_field_body(F),
- case binary_field_size(F) of
- none -> none;
- S ->
- revert(S)
- end,
- binary_field_types(F)))
- || F <- binary_fields(Node)],
+ Fs = [begin
+ B = binary_field_body(F),
+ {Body, Size} =
+ case type(B) of
+ size_qualifier ->
+ {size_qualifier_body(B),
+ size_qualifier_argument(B)};
+ _ ->
+ {B, none}
+ end,
+ revert_binary_field(
+ binary_field(Body, Size, binary_field_types(F)))
+ end
+ || F <- binary_fields(Node)],
{value, B, _} =
eval_bits:expr_grp(Fs, [],
fun(F, _) ->
@@ -7377,7 +7434,14 @@ is_literal(T) ->
is_literal_binary_field(F) ->
case binary_field_types(F) of
- [] -> is_literal(binary_field_body(F));
+ [] -> B = binary_field_body(F),
+ case type(B) of
+ size_qualifier ->
+ is_literal(size_qualifier_body(B)) andalso
+ is_literal(size_qualifier_argument(B));
+ _ ->
+ is_literal(B)
+ end;
_ -> false
end.
@@ -7727,8 +7791,9 @@ subtrees(T) ->
catch_expr ->
[[catch_expr_body(T)]];
class_qualifier ->
- [[class_qualifier_argument(T)],
- [class_qualifier_body(T)]];
+ [[class_qualifier_argument(T)],
+ [class_qualifier_body(T)],
+ [class_qualifier_stacktrace(T)]];
clause ->
case clause_guard(T) of
none ->
@@ -7949,6 +8014,7 @@ make_tree(block_expr, [B]) -> block_expr(B);
make_tree(case_expr, [[A], C]) -> case_expr(A, C);
make_tree(catch_expr, [[B]]) -> catch_expr(B);
make_tree(class_qualifier, [[A], [B]]) -> class_qualifier(A, B);
+make_tree(class_qualifier, [[A], [B], [C]]) -> class_qualifier(A, B, C);
make_tree(clause, [P, B]) -> clause(P, none, B);
make_tree(clause, [P, [G], B]) -> clause(P, G, B);
make_tree(cond_expr, [C]) -> cond_expr(C);
diff --git a/lib/syntax_tools/src/erl_syntax_lib.erl b/lib/syntax_tools/src/erl_syntax_lib.erl
index c7f477c4d2..352165893f 100644
--- a/lib/syntax_tools/src/erl_syntax_lib.erl
+++ b/lib/syntax_tools/src/erl_syntax_lib.erl
@@ -1317,6 +1317,8 @@ analyze_attribute(Node) ->
include_lib -> preprocessor;
ifdef -> preprocessor;
ifndef -> preprocessor;
+ 'if' -> preprocessor;
+ elif -> preprocessor;
else -> preprocessor;
endif -> preprocessor;
A ->
@@ -1979,7 +1981,7 @@ analyze_application(Node) ->
%%
%% @see analyze_type_name/1
--type typeName() :: atom() | {module(), atom(), arity()} | {atom(), arity()}.
+-type typeName() :: atom() | {module(), {atom(), arity()}} | {atom(), arity()}.
-spec analyze_type_application(erl_syntax:syntaxTree()) -> typeName().
diff --git a/lib/syntax_tools/src/igor.erl b/lib/syntax_tools/src/igor.erl
index 16e3511734..b712b77e9f 100644
--- a/lib/syntax_tools/src/igor.erl
+++ b/lib/syntax_tools/src/igor.erl
@@ -660,7 +660,7 @@ merge_files1(Files, Opts) ->
%% transitions), code replacement is expected to be detected. Then, if
%% we in the merged code do not check at these points if the
%% <em>target</em> module (the result of the merge) has been replaced,
-%% we can not be sure in general that we will be able to do code
+%% we cannot be sure in general that we will be able to do code
%% replacement of the merged state machine - it could run forever
%% without detecting the code change. Therefore, all such calls must
%% remain remote-calls (detecting code changes), but may call the target
diff --git a/lib/syntax_tools/src/merl_transform.erl b/lib/syntax_tools/src/merl_transform.erl
index b298bc407f..571d7e4d86 100644
--- a/lib/syntax_tools/src/merl_transform.erl
+++ b/lib/syntax_tools/src/merl_transform.erl
@@ -196,7 +196,7 @@ var_name(V) -> V.
var_to_tag(V) when is_integer(V) -> V;
var_to_tag(V) ->
- list_to_atom(string:to_lower(atom_to_list(V))).
+ list_to_atom(string:lowercase(atom_to_list(V))).
pre_expand_case(Expr, Clauses, Line) ->
merl:qquote(Line, "merl:switch(_@expr, _@clauses)",
diff --git a/lib/syntax_tools/test/merl_SUITE.erl b/lib/syntax_tools/test/merl_SUITE.erl
index 52bbd9b3b8..6389ad7738 100644
--- a/lib/syntax_tools/test/merl_SUITE.erl
+++ b/lib/syntax_tools/test/merl_SUITE.erl
@@ -30,13 +30,14 @@
%% Test cases
-export([merl_smoke_test/1,
- transform_parse_error_test/1]).
+ transform_parse_error_test/1, otp_15291/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[merl_smoke_test,
- transform_parse_error_test].
+ transform_parse_error_test,
+ otp_15291].
groups() ->
[].
@@ -101,6 +102,15 @@ transform_parse_error_test(_Config) ->
[?Q("merl:qquote(2, \"{\", [{var, V}])")], []))),
ok.
+otp_15291(_Config) ->
+ C0 = merl:quote("() -> ok"),
+ {clause,1,[],[],[{atom,1,ok}]} = C0,
+ C2 = merl:quote("(_,_) -> ok"),
+ {clause,1,[{var,1,'_'},{var,1,'_'}],[],[{atom,1,ok}]} = C2,
+ C1 = merl:quote("(_) -> ok"),
+ {clause,1,[{var,1,'_'}],[],[{atom,1,ok}]} = C1,
+ ok.
+
%% utilities
f(Ts) when is_list(Ts) ->
diff --git a/lib/syntax_tools/test/syntax_tools_SUITE.erl b/lib/syntax_tools/test/syntax_tools_SUITE.erl
index ae2c67c03e..e1dd1bd73b 100644
--- a/lib/syntax_tools/test/syntax_tools_SUITE.erl
+++ b/lib/syntax_tools/test/syntax_tools_SUITE.erl
@@ -24,15 +24,16 @@
%% Test cases
-export([app_test/1,appup_test/1,smoke_test/1,revert/1,revert_map/1,
- t_abstract_type/1,t_erl_parse_type/1,t_epp_dodger/1,
- t_comment_scan/1,t_igor/1,t_erl_tidy/1]).
+ revert_map_type/1,
+ t_abstract_type/1,t_erl_parse_type/1,t_type/1, t_epp_dodger/1,
+ t_comment_scan/1,t_igor/1,t_erl_tidy/1,t_prettypr/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [app_test,appup_test,smoke_test,revert,revert_map,
- t_abstract_type,t_erl_parse_type,t_epp_dodger,
- t_comment_scan,t_igor,t_erl_tidy].
+ [app_test,appup_test,smoke_test,revert,revert_map,revert_map_type,
+ t_abstract_type,t_erl_parse_type,t_type,t_epp_dodger,
+ t_comment_scan,t_igor,t_erl_tidy,t_prettypr].
groups() ->
[].
@@ -73,7 +74,7 @@ smoke_test_file(File) ->
[print_error_markers(F, File) || F <- Forms],
ok;
{error,Reason} ->
- io:format("~s: ~p\n", [File,Reason]),
+ io:format("~ts: ~p\n", [File,Reason]),
error
end.
@@ -81,7 +82,7 @@ print_error_markers(F, File) ->
case erl_syntax:type(F) of
error_marker ->
{L,M,Info} = erl_syntax:error_marker_info(F),
- io:format("~ts:~p: ~s", [File,L,M:format_error(Info)]);
+ io:format("~ts:~p: ~ts", [File,L,M:format_error(Info)]);
_ ->
ok
end.
@@ -121,10 +122,97 @@ revert_map(Config) when is_list(Config) ->
{map_field_assoc,{atom,17,name},{var,18,'Value'}}}]),
?t:timetrap_cancel(Dog).
-
+%% Testing bug fix for reverting map_field_assoc in types
+revert_map_type(Config) when is_list(Config) ->
+ Dog = ?t:timetrap(?t:minutes(1)),
+ Form1 = {attribute,4,record,
+ {state,
+ [{typed_record_field,
+ {record_field,5,{atom,5,x}},
+ {type,5,map,
+ [{type,5,map_field_exact,[{atom,5,y},{atom,5,z}]}]}}]}},
+ Mapped1 = erl_syntax_lib:map(fun(X) -> X end, Form1),
+ Form1 = erl_syntax:revert(Mapped1),
+ Form2 = {attribute,4,record,
+ {state,
+ [{typed_record_field,
+ {record_field,5,{atom,5,x}},
+ {type,5,map,
+ [{type,5,map_field_assoc,[{atom,5,y},{atom,5,z}]}]}}]}},
+ Mapped2 = erl_syntax_lib:map(fun(X) -> X end, Form2),
+ Form2 = erl_syntax:revert(Mapped2),
+ ?t:timetrap_cancel(Dog).
%% api tests
+t_type(Config) when is_list(Config) ->
+ F0 = fun validate_basic_type/1,
+ Appl0 = fun(Name) ->
+ Atom = erl_syntax:atom(Name),
+ erl_syntax:type_application(none, Atom, [])
+ end,
+ User0 = fun(Name) ->
+ Atom = erl_syntax:atom(Name),
+ erl_syntax:user_type_application(Atom, [])
+ end,
+ ok = validate(F0,[{"tuple()", erl_syntax:tuple_type()}
+ ,{"{}", erl_syntax:tuple_type([])}
+ ,{"integer()", Appl0(integer)}
+ ,{"foo()", User0(foo)}
+ ,{"map()", erl_syntax:map_type()}
+ ,{"#{}", erl_syntax:map_type([])}
+ ,{"1..2", erl_syntax:integer_range_type
+ (erl_syntax:integer(1), erl_syntax:integer(2))}
+ ,{"<<_:1,_:_*2>>", erl_syntax:bitstring_type
+ (erl_syntax:integer(1), erl_syntax:integer(2))}
+ ,{"fun()", erl_syntax:fun_type()}
+ ]),
+
+ F = fun validate_type/1,
+ ok = validate(F,[{"{}", tuple_type, false}
+ ,{"tuple()", tuple_type, true}
+ ,{"{atom()}", tuple_type, false}
+ ,{"{atom(),integer()}", tuple_type, false}
+ ,{"integer()", type_application, false}
+ ,{"foo()", user_type_application, false}
+ ,{"foo(integer())", user_type_application, false}
+ ,{"module:function()", type_application, false}
+ ,{"map()", map_type, true}
+ ,{"#{}", map_type, false}
+ ,{"#{atom() => integer()}", map_type, false}
+ ,{"#{atom() := integer()}", map_type, false}
+ ,{"#r{}", record_type, false}
+ ,{"#r{a :: integer()}", record_type, false}
+ ,{"[]", type_application, false}
+ ,{"nil()", type_application, false}
+ ,{"[atom()]", type_application, false}
+ ,{"1..2", integer_range_type, false}
+ ,{"<<_:1,_:_*2>>", bitstring_type, false}
+ ,{"fun()", fun_type, true}
+ ,{"integer() | atom()", type_union, false}
+ ,{"A :: fun()", annotated_type, false}
+ ,{"fun((...) -> atom())", function_type, false}
+ ,{"fun((integer()) -> atom())", function_type, false}
+ ,{"V", variable, true}
+ ]),
+ ok.
+
+validate_basic_type({String, Tree}) ->
+ ErlT = string_to_type(String),
+ ErlT = erl_syntax:revert(Tree),
+ ok.
+
+validate_type({String, Type, Leaf}) ->
+ ErlT = string_to_type(String),
+ Type = erl_syntax:type(ErlT),
+ Leaf = erl_syntax:is_leaf(ErlT),
+ Tree = erl_syntax_lib:map(fun(Node) -> Node end, ErlT),
+ Type = erl_syntax:type(Tree),
+ _ = erl_syntax:meta(Tree),
+ RevT = erl_syntax:revert(Tree),
+ Type = erl_syntax:type(RevT),
+ ok.
+
t_abstract_type(Config) when is_list(Config) ->
F = fun validate_abstract_type/1,
ok = validate(F,[{hi,atom},
@@ -137,6 +225,7 @@ t_abstract_type(Config) when is_list(Config) ->
{[$a,$b,$c],string},
{"hello world",string},
{<<1,2,3>>,binary},
+ {<<1,2,3:4>>,binary},
{#{a=>1,"b"=>2},map_expr},
{#{#{i=>1}=>1,"b"=>#{v=>2}},map_expr},
{{a,b,c},tuple}]),
@@ -211,6 +300,14 @@ t_comment_scan(Config) when is_list(Config) ->
ok = test_comment_scan(Filenames,DataDir),
ok.
+t_prettypr(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ Filenames = ["type_specs.erl",
+ "specs_and_funs.erl"],
+ ok = test_prettypr(Filenames,DataDir,PrivDir),
+ ok.
+
test_files(Config) ->
DataDir = ?config(data_dir, Config),
[ filename:join(DataDir,Filename) || Filename <- test_files() ].
@@ -218,7 +315,8 @@ test_files(Config) ->
test_files() ->
["syntax_tools_SUITE_test_module.erl",
"syntax_tools_test.erl",
- "type_specs.erl"].
+ "type_specs.erl",
+ "specs_and_funs.erl"].
t_igor(Config) when is_list(Config) ->
DataDir = ?config(data_dir, Config),
@@ -264,12 +362,33 @@ test_comment_scan([File|Files],DataDir) ->
end,
Fs1 = erl_recomment:recomment_forms(Fs0, Comments),
Fs2 = erl_syntax_lib:map(Fun, Fs1),
- io:format("File: ~s~n", [Filename]),
+ io:format("File: ~ts~n", [Filename]),
io:put_chars(erl_prettypr:format(Fs2, [{paper, 120},
{ribbon, 110}])),
test_comment_scan(Files,DataDir).
+test_prettypr([],_,_) -> ok;
+test_prettypr([File|Files],DataDir,PrivDir) ->
+ Filename = filename:join(DataDir,File),
+ io:format("Parsing ~p~n", [Filename]),
+ {ok, Fs0} = epp:parse_file(Filename, [], []),
+ Fs = erl_syntax:form_list(Fs0),
+ PP = erl_prettypr:format(Fs, [{paper, 120}, {ribbon, 110}]),
+ io:put_chars(PP),
+ OutFile = filename:join(PrivDir, File),
+ ok = file:write_file(OutFile,unicode:characters_to_binary(PP)),
+ io:format("Parsing OutFile: ~ts~n", [OutFile]),
+ {ok, Fs2} = epp:parse_file(OutFile, [], []),
+ case [Error || {error, _} = Error <- Fs2] of
+ [] ->
+ ok;
+ Errors ->
+ ?t:fail(Errors)
+ end,
+ test_prettypr(Files,DataDir,PrivDir).
+
+
test_epp_dodger([], _, _) -> ok;
test_epp_dodger([Filename|Files],DataDir,PrivDir) ->
io:format("Parsing ~p~n", [Filename]),
@@ -326,7 +445,7 @@ pretty_print_parse_forms([{Fs0,Type}|FsForms],PrivDir,Filename) ->
{Fs2,{CC,CT}} = erl_syntax_lib:mapfold(Comment,{0,0}, Fs1),
io:format("Commented on ~w cases and ~w tries~n", [CC,CT]),
PP = erl_prettypr:format(Fs2),
- ok = file:write_file(OutFile,iolist_to_binary(PP)),
+ ok = file:write_file(OutFile,unicode:characters_to_binary(PP)),
pretty_print_parse_forms(FsForms,PrivDir,Filename).
@@ -430,6 +549,13 @@ string_to_expr(String) ->
{ok,[Expr]} = erl_parse:parse_exprs(Ts),
Expr.
+string_to_type(String) ->
+ io:format("Str: ~p~n", [String]),
+ {ok,Ts,_} = erl_scan:string("-type foo() :: "++String++".", 0),
+ {ok,Form} = erl_parse:parse_form(Ts),
+ {attribute,_,type,{foo,Type,_NoParms=[]}} = Form,
+ Type.
+
p_run(Test, List) ->
N = erlang:system_info(schedulers),
diff --git a/lib/syntax_tools/test/syntax_tools_SUITE_data/specs_and_funs.erl b/lib/syntax_tools/test/syntax_tools_SUITE_data/specs_and_funs.erl
new file mode 100644
index 0000000000..8dfeaf5a6b
--- /dev/null
+++ b/lib/syntax_tools/test/syntax_tools_SUITE_data/specs_and_funs.erl
@@ -0,0 +1,18 @@
+-module(specs_and_funs).
+
+-export([my_apply/3, two/1]).
+
+%% OTP-15519, ERL-815
+
+-spec my_apply(Fun, Arg, fun((A) -> A)) -> Result when
+ Fun :: fun((Arg) -> Result),
+ Arg :: any(),
+ Result :: any().
+
+my_apply(Fun, Arg, _) ->
+ Fun(Arg).
+
+-spec two(fun((A) -> A)) -> fun((B) -> B).
+
+two(F) ->
+ F(fun(X) -> X end).
diff --git a/lib/syntax_tools/vsn.mk b/lib/syntax_tools/vsn.mk
index 8d37c40742..0ace11772d 100644
--- a/lib/syntax_tools/vsn.mk
+++ b/lib/syntax_tools/vsn.mk
@@ -1 +1 @@
-SYNTAX_TOOLS_VSN = 2.1.4
+SYNTAX_TOOLS_VSN = 2.2
diff --git a/lib/tftp/AUTHORS b/lib/tftp/AUTHORS
new file mode 100644
index 0000000000..71fc97c4e0
--- /dev/null
+++ b/lib/tftp/AUTHORS
@@ -0,0 +1,11 @@
+Original Authors:
+
+Håkan Mattsson - tftp
+
+Contributors:
+
+Ingela Anderton Andin
+Martin Gustafsson
+Johan Blom
+Torbjörn Törnkvist
+Joe Armstrong \ No newline at end of file
diff --git a/lib/tftp/Makefile b/lib/tftp/Makefile
new file mode 100644
index 0000000000..a4559fbc2e
--- /dev/null
+++ b/lib/tftp/Makefile
@@ -0,0 +1,78 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1996-2018. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# %CopyrightEnd%
+#
+#
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Macros
+# ----------------------------------------------------
+
+SUB_DIRECTORIES = src doc/src
+
+include vsn.mk
+VSN = $(TFTP_VSN)
+
+SPECIAL_TARGETS =
+
+DIA_PLT = ./priv/plt/$(APPLICATION).plt
+DIA_ANALYSIS = $(basename $(DIA_PLT)).dialyzer_analysis
+
+
+# ----------------------------------------------------
+# Default Subdir Targets
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_subdir.mk
+
+.PHONY: info gclean dialyzer dialyzer_plt dclean
+
+info:
+ @echo "OS: $(OS)"
+ @echo "DOCB: $(DOCB)"
+ @echo ""
+ @echo "TFTP_VSN: $(TFTP_VSN)"
+ @echo "APP_VSN: $(APP_VSN)"
+ @echo ""
+ @echo "DIA_PLT: $(DIA_PLT)"
+ @echo "DIA_ANALYSIS: $(DIA_ANALYSIS)"
+ @echo ""
+
+gclean:
+ git clean -fXd
+
+dclean:
+ rm -f $(DIA_PLT)
+ rm -f $(DIA_ANALYSIS)
+
+dialyzer_plt: $(DIA_PLT)
+
+$(DIA_PLT):
+ @echo "Building $(APPLICATION) plt file"
+ @dialyzer --build_plt \
+ --output_plt $@ \
+ -r ../$(APPLICATION)/ebin \
+ --output $(DIA_ANALYSIS) \
+ --verbose
+
+dialyzer: $(DIA_PLT)
+ @echo "Running dialyzer on $(APPLICATION)"
+ @dialyzer --plt $< \
+ ../$(APPLICATION)/ebin \
+ --verbose
diff --git a/lib/cosEvent/include/.gitignore b/lib/tftp/doc/html/.gitignore
index e69de29bb2..e69de29bb2 100644
--- a/lib/cosEvent/include/.gitignore
+++ b/lib/tftp/doc/html/.gitignore
diff --git a/lib/cosEvent/test/idl_output/.gitignore b/lib/tftp/doc/man3/.gitignore
index e69de29bb2..e69de29bb2 100644
--- a/lib/cosEvent/test/idl_output/.gitignore
+++ b/lib/tftp/doc/man3/.gitignore
diff --git a/lib/cosEventDomain/doc/html/.gitignore b/lib/tftp/doc/man6/.gitignore
index e69de29bb2..e69de29bb2 100644
--- a/lib/cosEventDomain/doc/html/.gitignore
+++ b/lib/tftp/doc/man6/.gitignore
diff --git a/lib/cosEventDomain/doc/man3/.gitignore b/lib/tftp/doc/pdf/.gitignore
index e69de29bb2..e69de29bb2 100644
--- a/lib/cosEventDomain/doc/man3/.gitignore
+++ b/lib/tftp/doc/pdf/.gitignore
diff --git a/lib/tftp/doc/src/Makefile b/lib/tftp/doc/src/Makefile
new file mode 100644
index 0000000000..5d76799e41
--- /dev/null
+++ b/lib/tftp/doc/src/Makefile
@@ -0,0 +1,155 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# %CopyrightEnd%
+#
+#
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../../vsn.mk
+VSN=$(TFTP_VSN)
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
+
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+XML_APPLICATION_FILES = ref_man.xml
+
+XML_CHAPTER_FILES = \
+ introduction.xml \
+ getting_started.xml \
+ notes.xml
+
+XML_REF3_FILES = \
+ tftp.xml
+
+XML_PART_FILES = \
+ usersguide.xml
+
+BOOK_FILES = book.xml
+
+XML_FILES = \
+ $(BOOK_FILES) \
+ $(XML_CHAPTER_FILES) \
+ $(XML_PART_FILES) \
+ $(XML_REF6_FILES) \
+ $(XML_REF3_FILES) \
+ $(XML_APPLICATION_FILES)
+
+# GIF_FILES = tftp.gif
+
+
+# ----------------------------------------------------
+
+HTML_FILES = \
+ $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \
+ $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html)
+
+INFO_FILE = ../../info
+EXTRA_FILES = \
+ $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html) \
+ $(XML_REF6_FILES:%.xml=$(HTMLDIR)/%.html) \
+ $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html)
+
+MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
+
+HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
+
+TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+XML_FLAGS +=
+DVIPS_FLAGS +=
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+$(HTMLDIR)/%.gif: %.gif
+ $(INSTALL_DATA) $< $@
+
+docs: pdf html man
+
+ldocs: local_docs
+
+$(TOP_PDF_FILE): $(XML_FILES)
+
+pdf: $(TOP_PDF_FILE)
+
+html: gifs $(HTML_REF_MAN_FILE)
+
+clean clean_docs: clean_html clean_man clean_pdf
+ rm -rf $(XMLDIR)
+ rm -f errs core *~
+
+man: $(MAN3_FILES)
+
+gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
+
+debug opt:
+
+clean_pdf:
+ rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
+
+clean_html:
+ rm -rf $(TOP_HTML_FILES) $(HTMLDIR)/*
+
+clean_man:
+ rm -f $(MAN3_FILES)
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_docs_spec: docs
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(HTMLDIR)/* "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
+
+release_spec:
+
+info:
+ @echo "GIF_FILES:\n$(GIF_FILES)"
+ @echo ""
+ @echo "EXTRA_FILES:\n$(EXTRA_FILES)"
+ @echo ""
+ @echo "HTML_FILES:\n$(HTML_FILES)"
+ @echo ""
+ @echo "TOP_HTML_FILES:\n$(TOP_HTML_FILES)"
+ @echo ""
+ @echo "XML_REF3_FILES:\n$(XML_REF3_FILES)"
+ @echo ""
+ @echo "XML_REF6_FILES:\n$(XML_REF6_FILES)"
+ @echo ""
+ @echo "XML_CHAPTER_FILES:\n$(XML_CHAPTER_FILES)"
+ @echo ""
diff --git a/lib/tftp/doc/src/book.xml b/lib/tftp/doc/src/book.xml
new file mode 100644
index 0000000000..c0b551d517
--- /dev/null
+++ b/lib/tftp/doc/src/book.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE book SYSTEM "book.dtd">
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header titlestyle="normal">
+ <copyright>
+ <year>1997</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>TFTP</title>
+ <prepared>Péter Dimitrov</prepared>
+ <docno></docno>
+ <date>2018-03-22</date>
+ <rev>1.0</rev>
+ <file>book.sgml</file>
+ </header>
+ <insidecover>
+ </insidecover>
+ <pagetext>TFTP</pagetext>
+ <preamble>
+ <contents level="2"></contents>
+ </preamble>
+ <parts lift="no">
+ <xi:include href="usersguide.xml"/>
+ </parts>
+ <applications>
+ <xi:include href="ref_man.xml"/>
+ </applications>
+ <releasenotes>
+ <xi:include href="notes.xml"/>
+ </releasenotes>
+ <listofterms></listofterms>
+ <index></index>
+</book>
diff --git a/lib/tftp/doc/src/getting_started.xml b/lib/tftp/doc/src/getting_started.xml
new file mode 100644
index 0000000000..9bce52dbe0
--- /dev/null
+++ b/lib/tftp/doc/src/getting_started.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>1997</year>
+ <year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>Getting Started</title>
+ <prepared></prepared>
+ <docno></docno>
+ <approved></approved>
+ <date></date>
+ <rev></rev>
+ <file>getting_started.xml</file>
+ </header>
+
+ <section>
+ <title>General Information</title>
+ <p>The <seealso marker="tftp#start/1">start/1</seealso> function starts
+ a daemon process listening for UDP packets on a port. When it
+ receives a request for read or write, it spawns a temporary server
+ process handling the transfer.</p>
+ <p>On the client side,
+ function <seealso marker="tftp#read_file/3">read_file/3</seealso>
+ and <seealso marker="tftp#write_file/3">write_file/3</seealso>
+ spawn a temporary client process establishing
+ contact with a TFTP daemon and perform the file transfer.</p>
+ <p><c>tftp</c> uses a callback module to handle the file
+ transfer. Two such callback modules are provided,
+ <c>tftp_binary</c> and <c>tftp_file</c>. See
+ <seealso marker="tftp#read_file/3">read_file/3</seealso> and
+ <seealso marker="tftp#write_file/3">write_file/3</seealso> for details.
+ You can also implement your own callback modules, see
+ <seealso marker="tftp#tftp_callback">CALLBACK FUNCTIONS</seealso>.
+ A callback module provided by
+ the user is registered using option <c>callback</c>, see
+ <seealso marker="tftp#options">DATA TYPES</seealso>.</p>
+ </section>
+
+ <section>
+ <title>Using the TFTP client and server</title>
+ <p>This is a simple example of starting the TFTP server and reading the content
+ of a sample file using the TFTP client.</p>
+
+ <p><em>Step 1.</em> Create a sample file to be used for the transfer:</p>
+ <code>
+ $ echo "Erlang/OTP 21" > file.txt
+ </code>
+
+ <p><em>Step 2.</em> Start the TFTP server:</p>
+ <code type="erl" >
+ 1> {ok, Pid} = tftp:start([{port, 19999}]).
+ <![CDATA[{ok,<0.65.0>}]]>
+ </code>
+
+ <p><em>Step 3.</em> Start the TFTP client (in another shell):</p>
+ <code type="erl" >
+ 1> tftp:read_file("file.txt", binary, [{port, 19999}]).
+ <![CDATA[{ok,<<"Erlang/OTP 21\n">>}]]>
+ </code>
+ </section>
+
+</chapter>
diff --git a/lib/tftp/doc/src/introduction.xml b/lib/tftp/doc/src/introduction.xml
new file mode 100644
index 0000000000..70761db0dc
--- /dev/null
+++ b/lib/tftp/doc/src/introduction.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>1997</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Introduction</title>
+ <prepared>Péter Dimitrov</prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date>2018-03-22</date>
+ <rev>A</rev>
+ <file>introduction.xml</file>
+ </header>
+
+ <section>
+ <title>Purpose</title>
+ <p>The Trivial File Transfer Protocol or TFTP is a very simple protocol
+ used to transfer files.</p>
+ <p>It has been implemented on top of the User Datagram protocol (UDP) so
+ it may be used to move files between machines on different networks
+ implementing UDP. It is designed to be small and easy to implement.
+ Therefore, it lacks most of the features of a regular FTP. The only
+ thing it can do is read and write files (or mail) from/to a remote server.
+ It cannot list directories, and currently has no provisions for user
+ authentication.</p>
+ <p>The <c>tftp</c> application implements the following IETF standards:</p>
+ <list type="bulleted">
+ <item>RFC 1350, The TFTP Protocol (revision 2)</item>
+ <item>RFC 2347, TFTP Option Extension</item>
+ <item>RFC 2348, TFTP Blocksize Option</item>
+ <item>RFC 2349, TFTP Timeout Interval and Transfer Size Options</item>
+ </list>
+ <p>The only feature that not is implemented is the <c>netascii</c> transfer mode.</p>
+ </section>
+
+ <section>
+ <title>Prerequisites</title>
+ <p>It is assumed that the reader is familiar with the Erlang
+ programming language, concepts of OTP, and has a basic
+ understanding of the TFTP protocol.</p>
+ </section>
+</chapter>
diff --git a/lib/tftp/doc/src/notes.xml b/lib/tftp/doc/src/notes.xml
new file mode 100644
index 0000000000..ff6113a89d
--- /dev/null
+++ b/lib/tftp/doc/src/notes.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2002</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>TFTP Release Notes</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date>2018-03-22</date>
+ <rev>A</rev>
+ <file>notes.xml</file>
+ </header>
+
+ <section><title>Tftp 1.0.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>TFTP 1.0</title>
+
+ <section><title>First released version</title>
+ <list>
+ <item>
+ <p>
+ Inets application was split into multiple smaller protocol specific applications.
+ The TFTP application is a standalone TFTP client and server with the same functionality as
+ TFTP in Inets.</p>
+ <p>
+ Own Id: OTP-14113</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+</chapter>
diff --git a/lib/tftp/doc/src/ref_man.xml b/lib/tftp/doc/src/ref_man.xml
new file mode 100644
index 0000000000..41a6cc6d52
--- /dev/null
+++ b/lib/tftp/doc/src/ref_man.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE application SYSTEM "application.dtd">
+
+<application xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header>
+ <copyright>
+ <year>1997</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>TFTP Reference Manual</title>
+ <prepared>Péter Dimitrov</prepared>
+ <docno></docno>
+ <date>2018-03-22</date>
+ <rev>1.0</rev>
+ <file>ref_man.xml</file>
+ </header>
+ <description>
+ <p>The <c>TFTP</c> application.</p>
+ </description>
+ <xi:include href="tftp.xml"/>
+</application>
diff --git a/lib/tftp/doc/src/tftp.xml b/lib/tftp/doc/src/tftp.xml
new file mode 100644
index 0000000000..57d64b7379
--- /dev/null
+++ b/lib/tftp/doc/src/tftp.xml
@@ -0,0 +1,599 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2006</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>tftp</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ </header>
+ <module since="">tftp</module>
+ <modulesummary>Trivial FTP.</modulesummary>
+ <description>
+ <p>Interface module for the <c>tftp</c> application.</p>
+ </description>
+
+ <section>
+ <marker id="options"></marker>
+ <title>DATA TYPES</title>
+ <p><c>ServiceConfig = Options</c></p>
+ <p><c>Options = [option()]</c></p>
+ <p>Most of the options are common for both the client and the server
+ side, but some of them differs a little.
+ The available <c>option()</c>s are as follows:</p>
+ <taglist>
+ <tag><c>{debug, Level}</c></tag>
+ <item>
+ <p><c>Level = none | error | warning | brief | normal | verbose | all</c></p>
+ <p>Controls the level of debug printouts.
+ Default is <c>none</c>.</p>
+ </item>
+ <tag><c>{host, Host}</c></tag>
+ <item>
+ <p><c>Host = hostname()</c>, see
+ <seealso marker="kernel:inet">inet(3)</seealso>.</p>
+ <p>The name or IP address of the host where the TFTP daemon
+ resides. This option is only used by the client.</p>
+ </item>
+ <tag><c>{port, Port}</c></tag>
+ <item>
+ <p><c>Port = int()</c></p>
+ <p>The TFTP port where the daemon listens. Defaults is
+ the standardized number 69. On the server side, it can
+ sometimes make sense to set it to 0, meaning that
+ the daemon just picks a free port (which one is
+ returned by function <c>info/1</c>).</p>
+ <p>If a socket is connected already, option
+ <c>{udp, [{fd, integer()}]}</c> can be used to pass the
+ open file descriptor to <c>gen_udp</c>. This can be automated
+ by using a command-line argument stating the
+ prebound file descriptor number. For example, if the
+ port is 69 and file descriptor 22 is opened by
+ <c>setuid_socket_wrap</c>, the command-line argument
+ "-tftpd_69 22" triggers the prebound file
+ descriptor 22 to be used instead of opening port 69.
+ The UDP option <c>{udp, [{fd, 22}]}</c> is automatically added.
+ See <c>init:get_argument/</c> about command-line arguments and
+ <c>gen_udp:open/2</c> about UDP options.</p>
+ </item>
+ <tag><c>{port_policy, Policy}</c></tag>
+ <item>
+ <p><c>Policy = random | Port | {range, MinPort, MaxPort}</c></p>
+ <p><c>Port = MinPort = MaxPort = int()</c></p>
+ <p>Policy for the selection of the temporary port that is used
+ by the server/client during the file transfer. Default is
+ <c>random</c>, which is the standardized policy. With this
+ policy a randomized free port is used. A single port or a range
+ of ports can be useful if the protocol passes through a
+ firewall.</p>
+ </item>
+ <tag><c>{udp, Options}</c></tag>
+ <item>
+ <p><c>Options = [Opt]</c>, see
+ <seealso marker="kernel:gen_udp#open/1">gen_udp:open/2</seealso>.</p>
+ </item>
+ <tag><c>{use_tsize, Bool}</c></tag>
+ <item>
+ <p><c>Bool = bool()</c></p>
+ <p>Flag for automated use of option <c>tsize</c>. With
+ this set to <c>true</c>, the <c>write_file/3</c> client
+ determines the filesize and sends it to the server as
+ the standardized <c>tsize</c> option. A <c>read_file/3</c>
+ client acquires only a filesize from the server by sending
+ a zero <c>tsize</c>.</p>
+ </item>
+ <tag><c>{max_tsize, MaxTsize}</c></tag>
+ <item>
+ <p><c>MaxTsize = int() | infinity</c></p>
+ <p>Threshold for the maximal filesize in bytes. The transfer
+ is aborted if the limit is exceeded.
+ Default is <c>infinity</c>.</p>
+ </item>
+ <tag><c>{max_conn, MaxConn}</c></tag>
+ <item>
+ <p><c>MaxConn = int() | infinity</c></p>
+ <p>Threshold for the maximal number of active connections.
+ The daemon rejects the setup of new connections if
+ the limit is exceeded. Default is <c>infinity</c>.</p>
+ </item>
+ <tag><c>{TftpKey, TftpVal}</c></tag>
+ <item>
+ <p><c>TftpKey = string()</c> <br></br>
+<c>TftpVal = string()</c></p>
+ <p>Name and value of a TFTP option.</p>
+ </item>
+ <tag><c>{reject, Feature}</c></tag>
+ <item>
+ <p><c>Feature = Mode | TftpKey</c> <br></br>
+<c>&nbsp;Mode = read | write</c> <br></br>
+<c>&nbsp;TftpKey = string()</c></p>
+ <p>Controls which features to reject. This is
+ mostly useful for the server as it can restrict the use
+ of certain TFTP options or read/write access.</p>
+ </item>
+ <tag><c>{callback, {RegExp, Module, State}}</c></tag>
+ <item>
+ <p><c>RegExp = string()</c> <br></br>
+<c>Module = atom()</c> <br></br>
+<c>State = term()</c></p>
+ <p>Registration of a callback module. When a file is to be
+ transferred, its local filename is matched to the regular
+ expressions of the registered callbacks. The first matching
+ callback is used during the transfer. See
+ <seealso marker="#read_file/3">read_file/3</seealso> and
+ <seealso marker="#write_file/3">write_file/3</seealso>.
+ </p>
+ <p>The callback module must implement the <c>tftp</c> behavior, see
+ <seealso marker="#tftp_callback">CALLBACK FUNCTIONS</seealso>.</p>
+ </item>
+
+ <tag><c>{logger, Module}</c></tag>
+ <item>
+ <p><c>Module = module()</c></p>
+
+ <p>Callback module for customized logging of errors, warnings, and
+ info messages. The callback module must implement the
+ <c>tftp_logger</c> behavior, see
+ <seealso marker="#tftp_logger">LOGGER FUNCTIONS</seealso>.
+ The default module is <c>tftp_logger</c>.</p>
+ </item>
+
+ <tag><c>{max_retries, MaxRetries}</c></tag>
+ <item>
+ <p><c>MaxRetries = int()</c></p>
+
+ <p>Threshold for the maximal number of retries. By default
+ the server/client tries to resend a message up to
+ five times when the time-out expires.</p>
+ </item>
+ </taglist>
+ </section>
+
+ <funcs>
+ <func>
+ <name since="">change_config(daemons, Options) -> [{Pid, Result}]</name>
+ <fsummary>Changes configuration for all daemons.
+ </fsummary>
+ <type>
+ <v>Options = [option()]</v>
+ <v>Pid = pid()</v>
+ <v>Result = ok | {error, Reason}</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Changes configuration for all TFTP daemon processes. </p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">change_config(servers, Options) -> [{Pid, Result}]</name>
+ <fsummary>Changes configuration for all servers.
+ </fsummary>
+ <type>
+ <v>Options = [option()]</v>
+ <v>Pid = pid()</v>
+ <v>Result = ok | {error, Reason}</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Changes configuration for all TFTP server processes.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">change_config(Pid, Options) -> Result</name>
+ <fsummary>Changes configuration for a TFTP daemon, server,
+ or client process.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>Options = [option()]</v>
+ <v>Result = ok | {error, Reason}</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Changes configuration for a TFTP daemon, server, or client process.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">info(daemons) -> [{Pid, Options}]</name>
+ <fsummary>Returns information about all daemons.</fsummary>
+ <type>
+ <v>Pid = [pid()]</v>
+ <v>Options = [option()]</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Returns information about all TFTP daemon processes.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">info(servers) -> [{Pid, Options}]</name>
+ <fsummary>Returns information about all servers.</fsummary>
+ <type>
+ <v>Pid = [pid()]</v>
+ <v>Options = [option()]</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Returns information about all TFTP server processes. </p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">info(Pid) -> {ok, Options} | {error, Reason}</name>
+ <fsummary>Returns information about a daemon, server, or client process.</fsummary>
+ <type>
+ <v>Options = [option()]</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Returns information about a TFTP daemon, server, or client process.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">read_file(RemoteFilename, LocalFilename, Options) -> {ok, LastCallbackState} | {error, Reason}</name>
+ <fsummary>Reads a (virtual) file from a TFTP server.</fsummary>
+ <type>
+ <v>RemoteFilename = string()</v>
+ <v>LocalFilename = binary | string()</v>
+ <v>Options = [option()]</v>
+ <v>LastCallbackState = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Reads a (virtual) file <c>RemoteFilename</c> from a TFTP
+ server.</p>
+ <p>If <c>LocalFilename</c> is the atom <c>binary</c>,
+ <c>tftp_binary</c> is used as callback module. It concatenates
+ all transferred blocks and returns them as one single binary
+ in <c>LastCallbackState</c>.</p>
+ <p>If <c>LocalFilename</c> is a string and there are no
+ registered callback modules, <c>tftp_file</c> is used as
+ callback module. It writes each transferred block to the file
+ named <c>LocalFilename</c> and returns the number of
+ transferred bytes in <c>LastCallbackState</c>.</p>
+ <p>If <c>LocalFilename</c> is a string and there are registered
+ callback modules, <c>LocalFilename</c> is tested against
+ the regexps of these and the callback module corresponding to
+ the first match is used, or an error tuple is returned if no
+ matching regexp is found.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">start(Options) -> {ok, Pid} | {error, Reason}</name>
+ <fsummary>Starts a daemon process.</fsummary>
+ <type>
+ <v>Options = [option()]</v>
+ <v>Pid = pid()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Starts a daemon process listening for UDP packets on a
+ port. When it receives a request for read or write, it spawns
+ a temporary server process handling the actual transfer
+ of the (virtual) file.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">write_file(RemoteFilename, LocalFilename, Options) -> {ok, LastCallbackState} | {error, Reason}</name>
+ <fsummary>Writes a (virtual) file to a TFTP server.</fsummary>
+ <type>
+ <v>RemoteFilename = string()</v>
+ <v>LocalFilename = binary() | string()</v>
+ <v>Options = [option()]</v>
+ <v>LastCallbackState = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Writes a (virtual) file <c>RemoteFilename</c> to a TFTP
+ server.</p>
+ <p>If <c>LocalFilename</c> is a binary, <c>tftp_binary</c> is
+ used as callback module. The binary is transferred block by
+ block and the number of transferred bytes is returned in
+ <c>LastCallbackState</c>.</p>
+ <p>If <c>LocalFilename</c> is a string and there are no
+ registered callback modules, <c>tftp_file</c> is used as
+ callback module. It reads the file named <c>LocalFilename</c>
+ block by block and returns the number of transferred bytes
+ in <c>LastCallbackState</c>.</p>
+ <p>If <c>LocalFilename</c> is a string and there are registered
+ callback modules, <c>LocalFilename</c> is tested against
+ the regexps of these and the callback module corresponding to
+ the first match is used, or an error tuple is returned if no
+ matching regexp is found.</p>
+ </desc>
+ </func>
+ </funcs>
+
+ <section>
+ <marker id="tftp_callback"></marker>
+ <title>CALLBACK FUNCTIONS</title>
+ <p>A <c>tftp</c> callback module is to be implemented as a
+ <c>tftp</c> behavior and export the functions listed
+ in the following.</p>
+ <p>On the server side, the callback interaction starts with a call to
+ <c>open/5</c> with the registered initial callback state.
+ <c>open/5</c> is expected to open the (virtual) file. Then either
+ function <c>read/1</c> or <c>write/2</c> is invoked
+ repeatedly, once per transferred block. At each function call,
+ the state returned from the previous call is obtained. When
+ the last block is encountered, function <c>read/1</c> or
+ <c>write/2</c> is expected to close the (virtual) file
+ and return its last state. Function <c>abort/3</c> is only
+ used in error situations. Function <c>prepare/5</c> is not used on
+ the server side.</p>
+ <p>On the client side, the callback interaction is the same, but it
+ starts and ends a bit differently. It starts with a call to
+ <c>prepare/5</c> with the same arguments as <c>open/5</c> takes.
+ <c>prepare/5</c> is expected to validate the TFTP options
+ suggested by the user and to return the subset of them that it
+ accepts. Then the options are sent to the server, which performs
+ the same TFTP option negotiation procedure. The options that are
+ accepted by the server are forwarded to function <c>open/5</c>
+ on the client side. On the client side, function <c>open/5</c>
+ must accept all option as-is or reject the transfer. Then
+ the callback interaction follows the same pattern as described
+ for the server side. When the last block is encountered in
+ <c>read/1</c> or <c>write/2</c>, the returned state is forwarded to
+ the user and returned from <c>read_file</c>/3 or
+ <c>write_file/3</c>.</p>
+
+ <p> If a callback (performing the file access
+ in the TFTP server) takes too long time (more than
+ the double TFTP time-out), the server aborts the
+ connection and sends an error reply to the client.
+ This implies that the server releases resources
+ attached to the connection faster than before. The
+ server simply assumes that the client has given
+ up.</p>
+
+ <p>If the TFTP server receives yet another request from
+ the same client (same host and port) while it
+ already has an active connection to the client, it
+ ignores the new request if the request is
+ equal to the first one (same filename and options).
+ This implies that the (new) client will be served
+ by the already ongoing connection on the server
+ side. By not setting up yet another connection, in
+ parallel with the ongoing one, the server
+ consumes less resources.</p>
+
+ <marker id="prepare"></marker>
+ </section>
+
+ <funcs>
+ <func>
+ <name since="OTP 18.1">Module:abort(Code, Text, State) -> ok</name>
+ <fsummary>Aborts the file transfer.</fsummary>
+ <type>
+ <v>Code = undef | enoent | eacces | enospc</v>
+ <v>&nbsp;&nbsp;| badop | eexist | baduser | badopt</v>
+ <v>&nbsp;&nbsp;| int()</v>
+ <v>Text = string()</v>
+ <v>State = term()</v>
+ </type>
+ <desc>
+ <p>Invoked when the file transfer is aborted.</p>
+ <p>The callback function is expected to clean
+ up its used resources after the aborted file
+ transfer, such as closing open file
+ descriptors and so on. The function is not
+ invoked if any of the other callback
+ functions returns an error, as it is
+ expected that they already have cleaned up
+ the necessary resources. However, it is
+ invoked if the functions fail (crash).</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 18.1">Module:open(Peer, Access, Filename, Mode, SuggestedOptions, State) -> {ok, AcceptedOptions, NewState} | {error, {Code, Text}}</name>
+ <fsummary>Opens a file for read or write access.</fsummary>
+ <type>
+ <v>Peer = {PeerType, PeerHost, PeerPort}</v>
+ <v>PeerType = inet | inet6</v>
+ <v>PeerHost = ip_address()</v>
+ <v>PeerPort = integer()</v>
+ <v>Access = read | write</v>
+ <v>Filename = string()</v>
+ <v>Mode = string()</v>
+ <v>SuggestedOptions = AcceptedOptions = [{Key, Value}]</v>
+ <v>&nbsp;Key = Value = string()</v>
+ <v>State = InitialState | term()</v>
+ <v>&nbsp;InitialState = [] | [{root_dir, string()}]</v>
+ <v>NewState = term()</v>
+ <v>Code = undef | enoent | eacces | enospc</v>
+ <v>&nbsp;&nbsp;| badop | eexist | baduser | badopt</v>
+ <v>&nbsp;&nbsp;| int()</v>
+ <v>Text = string()</v>
+ </type>
+ <desc>
+ <p>Opens a file for read or write access.</p>
+ <p>On the client side, where the <c>open/5</c> call has been
+ preceded by a call to <c>prepare/5</c>, all options must be
+ accepted or rejected.</p>
+ <p>On the server side, where there is no preceding
+ <c>prepare/5</c> call, no new options can be added, but
+ those present in <c>SuggestedOptions</c> can be
+ omitted or replaced with new values in <c>AcceptedOptions</c>.</p>
+
+ <marker id="read"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 18.1">Module:prepare(Peer, Access, Filename, Mode, SuggestedOptions, InitialState) -> {ok, AcceptedOptions, NewState} | {error, {Code, Text}}</name>
+ <fsummary>Prepares to open a file on the client side.</fsummary>
+ <type>
+ <v>Peer = {PeerType, PeerHost, PeerPort}</v>
+ <v>PeerType = inet | inet6</v>
+ <v>PeerHost = ip_address()</v>
+ <v>PeerPort = integer()</v>
+ <v>Access = read | write</v>
+ <v>Filename = string()</v>
+ <v>Mode = string()</v>
+ <v>SuggestedOptions = AcceptedOptions = [{Key, Value}]</v>
+ <v>&nbsp;Key = Value = string()</v>
+ <v>InitialState = [] | [{root_dir, string()}]</v>
+ <v>NewState = term()</v>
+ <v>Code = undef | enoent | eacces | enospc</v>
+ <v>&nbsp;&nbsp;| badop | eexist | baduser | badopt</v>
+ <v>&nbsp;&nbsp;| int()</v>
+ <v>Text = string()</v>
+ </type>
+ <desc>
+ <p>Prepares to open a file on the client side.</p>
+ <p>No new options can be added, but those present in
+ <c>SuggestedOptions</c> can be omitted or replaced with new
+ values in <c>AcceptedOptions</c>.</p>
+ <p>This is followed by a call to <c>open/4</c> before any
+ read/write access is performed. <c>AcceptedOptions</c> is
+ sent to the server, which replies with the options that it
+ accepts. These are then forwarded to <c>open/4</c> as
+ <c>SuggestedOptions</c>.</p>
+
+ <marker id="open"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 18.1">Module:read(State) -> {more, Bin, NewState} | {last, Bin, FileSize} | {error, {Code, Text}}</name>
+ <fsummary>Reads a chunk from the file.</fsummary>
+ <type>
+ <v>State = NewState = term()</v>
+ <v>Bin = binary()</v>
+ <v>FileSize = int()</v>
+ <v>Code = undef | enoent | eacces | enospc</v>
+ <v>&nbsp;&nbsp;| badop | eexist | baduser | badopt</v>
+ <v>&nbsp;&nbsp;| int()</v>
+ <v>Text = string()</v>
+ </type>
+ <desc>
+ <p>Reads a chunk from the file.</p>
+ <p>The callback function is expected to close
+ the file when the last file chunk is
+ encountered. When an error is encountered,
+ the callback function is expected to clean
+ up after the aborted file transfer, such as
+ closing open file descriptors, and so on. In both
+ cases there will be no more calls to any of
+ the callback functions.</p>
+
+ <marker id="write"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 18.1">Module:write(Bin, State) -> {more, NewState} | {last, FileSize} | {error, {Code, Text}}</name>
+ <fsummary>Writes a chunk to the file.</fsummary>
+ <type>
+ <v>Bin = binary()</v>
+ <v>State = NewState = term()</v>
+ <v>FileSize = int()</v>
+ <v>Code = undef | enoent | eacces | enospc</v>
+ <v>&nbsp;&nbsp;| badop | eexist | baduser | badopt</v>
+ <v>&nbsp;&nbsp;| int()</v>
+ <v>Text = string()</v>
+ </type>
+ <desc>
+ <p>Writes a chunk to the file.</p>
+ <p>The callback function is expected to close
+ the file when the last file chunk is
+ encountered. When an error is encountered,
+ the callback function is expected to clean
+ up after the aborted file transfer, such as
+ closing open file descriptors, and so on. In both
+ cases there will be no more calls to any of
+ the callback functions.</p>
+
+ <marker id="abort"></marker>
+ </desc>
+ </func>
+ </funcs>
+
+ <section>
+ <marker id="tftp_logger"></marker>
+ <title>LOGGER FUNCTIONS</title>
+
+ <p>A <c>tftp_logger</c> callback module is to be implemented as a
+ <c>tftp_logger</c> behavior and export the following functions:</p>
+
+ <marker id="error_msg"></marker>
+ </section>
+
+ <funcs>
+ <func>
+ <name since="OTP 18.1">Logger:error_msg(Format, Data) -> ok | exit(Reason)</name>
+ <fsummary>Logs an error message.</fsummary>
+ <type>
+ <v>Format = string()</v>
+ <v>Data = [term()]</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Logs an error message.
+ See <c>error_logger:error_msg/2</c> for details.</p>
+
+ <marker id="warning_msg"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 18.1">Logger:info_msg(Format, Data) -> ok | exit(Reason)</name>
+ <fsummary>Logs an info message.</fsummary>
+ <type>
+ <v>Format = string()</v>
+ <v>Data = [term()]</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Logs an info message.
+ See <c>error_logger:info_msg/2</c> for details.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name since="OTP 18.1">Logger:warning_msg(Format, Data) -> ok | exit(Reason)</name>
+ <fsummary>Logs a warning message.</fsummary>
+ <type>
+ <v>Format = string()</v>
+ <v>Data = [term()]</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Logs a warning message.
+ See <c>error_logger:warning_msg/2</c> for details.</p>
+
+ <marker id="info_msg"></marker>
+ </desc>
+ </func>
+ </funcs>
+</erlref>
+
+
diff --git a/lib/tftp/doc/src/usersguide.xml b/lib/tftp/doc/src/usersguide.xml
new file mode 100644
index 0000000000..eb7f7d17c3
--- /dev/null
+++ b/lib/tftp/doc/src/usersguide.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE part SYSTEM "part.dtd">
+
+<part xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header>
+ <copyright>
+ <year>2004</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>TFTP User's Guide</title>
+ <prepared>Péter Dimitrov</prepared>
+ <docno></docno>
+ <date>2018-03-22</date>
+ <rev>A</rev>
+ <file>part.sgml</file>
+ </header>
+ <description>
+ <p>The <c>TFTP</c> application provides a TFTP client and server.</p>
+ </description>
+ <xi:include href="introduction.xml"/>
+ <xi:include href="getting_started.xml"/>
+</part>
diff --git a/lib/cosEventDomain/doc/man6/.gitignore b/lib/tftp/ebin/.gitignore
index e69de29bb2..e69de29bb2 100644
--- a/lib/cosEventDomain/doc/man6/.gitignore
+++ b/lib/tftp/ebin/.gitignore
diff --git a/lib/tftp/info b/lib/tftp/info
new file mode 100644
index 0000000000..1220454351
--- /dev/null
+++ b/lib/tftp/info
@@ -0,0 +1,2 @@
+group: comm
+short: TFTP application
diff --git a/lib/tftp/src/Makefile b/lib/tftp/src/Makefile
new file mode 100644
index 0000000000..602ae845a4
--- /dev/null
+++ b/lib/tftp/src/Makefile
@@ -0,0 +1,110 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2005-2018. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# %CopyrightEnd%
+#
+#
+
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../vsn.mk
+VSN = $(TFTP_VSN)
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+BEHAVIOUR_MODULES=
+
+MODULES = \
+ tftp \
+ tftp_app \
+ tftp_binary \
+ tftp_engine \
+ tftp_file \
+ tftp_lib \
+ tftp_logger \
+ tftp_sup
+
+HRL_FILES = tftp.hrl
+
+ERL_FILES= \
+ $(MODULES:%=%.erl) \
+ $(BEHAVIOUR_MODULES:%=%.erl)
+
+TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+BEHAVIOUR_TARGET_FILES= $(BEHAVIOUR_MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+APP_FILE= tftp.app
+APPUP_FILE= tftp.appup
+
+APP_SRC= $(APP_FILE).src
+APP_TARGET= $(EBIN)/$(APP_FILE)
+APPUP_SRC= $(APPUP_FILE).src
+APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+$(TARGET_FILES): $(BEHAVIOUR_TARGET_FILES)
+
+debug opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
+
+clean:
+ rm -f $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(BEHAVIOUR_TARGET_FILES)
+ rm -f core
+
+$(APP_TARGET): $(APP_SRC) ../vsn.mk
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
+
+$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
+
+docs:
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec: opt
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(BEHAVIOUR_TARGET_FILES) $(TARGET_FILES) $(APP_TARGET) \
+ $(APPUP_TARGET) "$(RELSYSDIR)/ebin"
+
+release_docs_spec:
+
+info:
+ @echo "APPLICATION = $(APPLICATION)"
+ @echo "ERL_COMPILE_FLAGS = $(ERL_COMPILE_FLAGS)"
diff --git a/lib/tftp/src/tftp.app.src b/lib/tftp/src/tftp.app.src
new file mode 100644
index 0000000000..9e79fe32bf
--- /dev/null
+++ b/lib/tftp/src/tftp.app.src
@@ -0,0 +1,22 @@
+{application, tftp,
+ [{description, "TFTP application"},
+ {vsn, "%VSN%"},
+ {registered, []},
+ {mod, { tftp_app, []}},
+ {applications,
+ [kernel,
+ stdlib
+ ]},
+ {env,[]},
+ {modules, [
+ tftp,
+ tftp_app,
+ tftp_binary,
+ tftp_engine,
+ tftp_file,
+ tftp_lib,
+ tftp_logger,
+ tftp_sup
+ ]},
+ {runtime_dependencies, ["stdlib-3.5","kernel-6.0"]}
+ ]}.
diff --git a/lib/tftp/src/tftp.appup.src b/lib/tftp/src/tftp.appup.src
new file mode 100644
index 0000000000..06a0f0f9dc
--- /dev/null
+++ b/lib/tftp/src/tftp.appup.src
@@ -0,0 +1,26 @@
+%% -*- erlang -*-
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+{"%VSN%",
+ [
+ {<<".*">>,[{restart_application, tftp}]}
+ ],
+ [
+ {<<".*">>,[{restart_application, tftp}]}
+ ]
+}.
diff --git a/lib/tftp/src/tftp.erl b/lib/tftp/src/tftp.erl
new file mode 100644
index 0000000000..31e4c651e8
--- /dev/null
+++ b/lib/tftp/src/tftp.erl
@@ -0,0 +1,409 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+%%%-------------------------------------------------------------------
+%%% File : tftp.erl
+%%% Author : Hakan Mattsson <[email protected]>
+%%% Description : Trivial FTP
+%%% Created : 18 May 2004 by Hakan Mattsson <[email protected]>
+%%%-------------------------------------------------------------------
+%%%
+%%% This is a complete implementation of the following IETF standards:
+%%%
+%%% RFC 1350, The TFTP Protocol (revision 2).
+%%% RFC 2347, TFTP Option Extension.
+%%% RFC 2348, TFTP Blocksize Option.
+%%% RFC 2349, TFTP Timeout Interval and Transfer Size Options.
+%%%
+%%% The only feature that not is implemented in this release is
+%%% the "netascii" transfer mode.
+%%%
+%%% The start/1 function starts a daemon process which, listens for
+%%% UDP packets on a port. When it receives a request for read or
+%%% write it spawns a temporary server process which handles the
+%%% actual transfer of the file. On the client side the read_file/3
+%%% and write_file/3 functions spawns a temporary client process which
+%%% establishes contact with a TFTP daemon and performs the actual
+%%% transfer of the file.
+%%%
+%%% Most of the options are common for both the client and the server
+%%% side, but some of them differs a little. Here are the available
+%%% options:
+%%%
+%%% {debug, Level}
+%%%
+%%% Level = none | error | warning brief | normal | verbose | all
+%%%
+%%% Controls the level of debug printouts. The default is none.
+%%%
+%%% {host, Host}
+%%%
+%%% The name or IP address of the host where the TFTP daemon
+%%% resides. This option is only used by the client. See
+%%% 'inet' about valid host names.
+%%%
+%%% {port, Port}
+%%%
+%%% Port = integer()
+%%%
+%%% The TFTP port where the daemon listens. It defaults to the
+%%% standardized number 69. On the server side it may sometimes
+%%% make sense to set it to 0, which means that the daemon just
+%%% will pick a free port (which is returned by the start/1
+%%% function).
+%%%
+%%% If a socket has somehow already has been connected, the
+%%% {udp, [{fd, integer()}]} option can be used to pass the
+%%% open file descriptor to gen_udp. This can be automated
+%%% a bit by using a command line argument stating the
+%%% prebound file descriptor number. For example, if the
+%%% Port is 69 and the file descriptor 22 has been opened by
+%%% setuid_socket_wrap. Then the command line argument
+%%% "-tftpd_69 22" will trigger the prebound file
+%%% descriptor 22 to be used instead of opening port 69.
+%%% The UDP option {udp, [{fd, 22}]} autmatically be added.
+%%% See init:get_argument/ about command line arguments and
+%%% gen_udp:open/2 about UDP options.
+%%%
+%%% {port_policy, Policy}
+%%%
+%%% Policy = random | Port | {range, MinPort, MaxPort}
+%%% Port = MinPort = MaxPort = integer()
+%%%
+%%% Policy for the selection of the temporary port which is used
+%%% by the server/client during the file transfer. It defaults to
+%%% 'random' which is the standardized policy. With this policy a
+%%% randomized free port used. A single port or a range of ports
+%%% can be useful if the protocol should pass thru a firewall.
+%%%
+%%% {prebound_fd, InitArgFlag}
+%%%
+%%% InitArgFlag = atom()
+%%%
+%%% If a socket has somehow already has been connected, the
+%%% {udp, [{fd, integer()}]} option can be used to pass the
+%%% open file descriptor to gen_udp.
+%%%
+%%% The prebound_fd option makes it possible to pass give the
+%%% file descriptor as a command line argument. The typical
+%%% usage is when used in conjunction with setuid_socket_wrap
+%%% to be able to open privileged sockets. For example if the
+%%% file descriptor 22 has been opened by setuid_socket_wrap
+%%% and you have choosen my_tftp_fd as init argument, the
+%%% command line should like this "erl -my_tftp_fd 22" and
+%%% FileDesc should be set to my_tftpd_fd. This would
+%%% automatically imply {fd, 22} to be set as UDP option.
+%%%
+%%% {udp, UdpOptions}
+%%%
+%%% Options to gen_udp:open/2.
+%%%
+%%% {use_tsize, Bool}
+%%%
+%%% Bool = boolean()
+%%%
+%%% Flag for automated usage of the "tsize" option. With this set
+%%% to true, the write_file/3 client will determine the filesize
+%%% and send it to the server as the standardized "tsize" option.
+%%% A read_file/3 client will just acquire filesize from the
+%%% server by sending a zero "tsize".
+%%%
+%%% {max_tsize, MaxTsize}
+%%%
+%%% MaxTsize = integer() | infinity
+%%%
+%%% Threshold for the maximal filesize in bytes. The transfer will
+%%% be aborted if the limit is exceeded. It defaults to
+%%% 'infinity'.
+%%%
+%%% {max_conn, MaxConn}
+%%%
+%%% MaxConn = integer() | infinity
+%%%
+%%% Threshold for the maximal number of active connections. The
+%%% daemon will reject the setup of new connections if the limit
+%%% is exceeded. It defaults to 'infinity'.
+%%%
+%%% {TftpKey, TftpVal}
+%%%
+%%% TftpKey = string()
+%%% TftpVal = string()
+%%%
+%%% The name and value of a TFTP option.
+%%%
+%%% {reject, Feature}
+%%%
+%%% Feature = Mode | TftpKey
+%%% Mode = read | write
+%%% TftpKey = string()
+%%%
+%%% Control which features that should be rejected.
+%%% This is mostly useful for the server as it may restrict
+%%% usage of certain TFTP options or read/write access.
+%%%
+%%% {callback, {RegExp, Module, State}}
+%%%
+%%% RegExp = string()
+%%% Module = atom()
+%%% State = term()
+%%%
+%%% Registration of a callback module. When a file is to be
+%%% transferred, its local filename will be matched to the
+%%% regular expressions of the registered callbacks. The first
+%%% matching callback will be used the during the transfer.The
+%%% callback module must implement the 'tftp' behaviour.
+%%%
+%%% On the server side the callback interaction starts with a
+%%% call to open/5 with the registered initial callback
+%%% state. open/5 is expected to open the (virtual) file. Then
+%%% either the read/1 or write/2 functions are invoked
+%%% repeatedly, once per transfererred block. At each function
+%%% call the state returned from the previous call is
+%%% obtained. When the last block has been encountered the read/1
+%%% or write/2 functions is expected to close the (virtual)
+%%% file.and return its last state. The abort/3 function is only
+%%% used in error situations. prepare/5 is not used on the server
+%%% side.
+%%%
+%%% On the client side the callback interaction is the same, but
+%%% it starts and ends a bit differently. It starts with a call
+%%% to prepare/5 with the same arguments as open/5
+%%% takes. prepare/5 is expected to validate the TFTP options,
+%%% suggested by the user and return the subset of them that it
+%%% accepts. Then the options is sent to the server which will
+%%% perform the same TFTP option negotiation procedure. The
+%%% options that are accepted by the server is forwarded to the
+%%% open/5 function on the client side. On the client side the
+%%% open/5 function must accept all option as is or reject the
+%%% transfer. Then the callback interaction follows the same
+%%% pattern as described above for the server side. When the last
+%%% block is encountered in read/1 or write/2 the returned stated
+%%% is forwarded to the user and returned from read_file/3 or
+%%% write_file/3.
+%%%-------------------------------------------------------------------
+
+-module(tftp).
+
+%%-------------------------------------------------------------------
+%% Interface
+%%-------------------------------------------------------------------
+
+%% Public functions
+-export([
+ read_file/3,
+ write_file/3,
+ start/1,
+ info/1,
+ change_config/2,
+ start/0,
+ stop/0
+ ]).
+
+%% Application local functions
+-export([
+ start_standalone/1,
+ start_service/1,
+ stop_service/1,
+ services/0,
+ service_info/1
+ ]).
+
+
+-type peer() :: {PeerType :: inet | inet6,
+ PeerHost :: inet:ip_address(),
+ PeerPort :: port()}.
+
+-type access() :: read | write.
+
+-type options() :: [{Key :: string(), Value :: string()}].
+
+-type error_code() :: undef | enoent | eacces | enospc |
+ badop | eexist | baduser | badopt |
+ integer().
+
+-callback prepare(Peer :: peer(),
+ Access :: access(),
+ Filename :: file:name(),
+ Mode :: string(),
+ SuggestedOptions :: options(),
+ InitialState :: [] | [{root_dir, string()}]) ->
+ {ok, AcceptedOptions :: options(), NewState :: term()} |
+ {error, {Code :: error_code(), string()}}.
+
+-callback open(Peer :: peer(),
+ Access :: access(),
+ Filename :: file:name(),
+ Mode :: string(),
+ SuggestedOptions :: options(),
+ State :: [] | [{root_dir, string()}] | term()) ->
+ {ok, AcceptedOptions :: options(), NewState :: term()} |
+ {error, {Code :: error_code(), string()}}.
+
+-callback read(State :: term()) -> {more, binary(), NewState :: term()} |
+ {last, binary(), integer()} |
+ {error, {Code :: error_code(), string()}}.
+
+-callback write(binary(), State :: term()) ->
+ {more, NewState :: term()} |
+ {last, FileSize :: integer()} |
+ {error, {Code :: error_code(), string()}}.
+
+-callback abort(Code :: error_code(), string(), State :: term()) -> 'ok'.
+
+-include("tftp.hrl").
+
+
+%%-------------------------------------------------------------------
+%% read_file(RemoteFilename, LocalFilename, Options) ->
+%% {ok, LastCallbackState} | {error, Reason}
+%%
+%% RemoteFilename = string()
+%% LocalFilename = binary | string()
+%% Options = [option()]
+%% LastCallbackState = term()
+%% Reason = term()
+%%
+%% Reads a (virtual) file from a TFTP server
+%%
+%% If LocalFilename is the atom 'binary', tftp_binary will be used as
+%% callback module. It will concatenate all transferred blocks and
+%% return them as one single binary in the CallbackState.
+%%
+%% When LocalFilename is a string, it will be matched to the
+%% registered callback modules and hopefully one of them will be
+%% selected. By default, tftp_file will be used as callback module. It
+%% will write each transferred block to the file named
+%% LocalFilename. The number of transferred bytes will be returned as
+%% LastCallbackState.
+%%-------------------------------------------------------------------
+
+read_file(RemoteFilename, LocalFilename, Options) ->
+ tftp_engine:client_start(read, RemoteFilename, LocalFilename, Options).
+
+%%-------------------------------------------------------------------
+%% write(RemoteFilename, LocalFilename, Options) ->
+%% {ok, LastCallbackState} | {error, Reason}
+%%
+%% RemoteFilename = string()
+%% LocalFilename = binary() | string()
+%% Options = [option()]
+%% LastCallbackState = term()
+%% Reason = term()
+%%
+%% Writes a (virtual) file to a TFTP server
+%%
+%% If LocalFilename is a binary, tftp_binary will be used as callback
+%% module. The binary will be transferred block by block and the number
+%% of transferred bytes will be returned as LastCallbackState.
+%%
+%% When LocalFilename is a string, it will be matched to the
+%% registered callback modules and hopefully one of them will be
+%% selected. By default, tftp_file will be used as callback module. It
+%% will read the file named LocalFilename block by block. The number
+%% of transferred bytes will be returned as LastCallbackState.
+%%-------------------------------------------------------------------
+
+write_file(RemoteFilename, LocalFilename, Options) ->
+ tftp_engine:client_start(write, RemoteFilename, LocalFilename, Options).
+
+%%-------------------------------------------------------------------
+%% start(Options) -> {ok, Pid} | {error, Reason}
+%%
+%% Options = [option()]
+%% Pid = pid()
+%% Reason = term()
+%%
+%% Starts a daemon process which listens for udp packets on a
+%% port. When it receives a request for read or write it spawns
+%% a temporary server process which handles the actual transfer
+%% of the (virtual) file.
+%%-------------------------------------------------------------------
+
+start(Options) ->
+ tftp_engine:daemon_start(Options).
+
+%%-------------------------------------------------------------------
+%% info(Pid) -> {ok, Options} | {error, Reason}
+%%
+%% Options = [option()]
+%% Reason = term()
+%%
+%% Returns info about a tftp daemon, server or client process
+%%-------------------------------------------------------------------
+
+info(Pid) ->
+ tftp_engine:info(Pid).
+
+%%-------------------------------------------------------------------
+%% change_config(Pid, Options) -> ok | {error, Reason}
+%%
+%% Options = [option()]
+%% Reason = term()
+%%
+%% Changes config for a tftp daemon, server or client process
+%% Must be used with care.
+%%-------------------------------------------------------------------
+
+change_config(Pid, Options) ->
+ tftp_engine:change_config(Pid, Options).
+
+%%-------------------------------------------------------------------
+%% start() -> ok | {error, Reason}
+%%
+%% Reason = term()
+%%
+%% Start the application
+%%-------------------------------------------------------------------
+
+start() ->
+ application:start(tftp).
+
+%%-------------------------------------------------------------------
+%% stop() -> ok | {error, Reason}
+%%
+%% Reason = term()
+%%
+%% Stop the application
+%%-------------------------------------------------------------------
+stop() ->
+ application:stop(tftp).
+
+%%-------------------------------------------------------------------
+%% Inets service behavior
+%%-------------------------------------------------------------------
+
+start_standalone(Options) ->
+ start(Options).
+
+start_service(Options) ->
+ tftp_sup:start_child(Options).
+
+stop_service(Pid) ->
+ tftp_sup:stop_child(Pid).
+
+services() ->
+ tftp_sup:which_children().
+
+service_info(Pid) ->
+ info(Pid).
+
+
+
diff --git a/lib/tftp/src/tftp.hrl b/lib/tftp/src/tftp.hrl
new file mode 100644
index 0000000000..a26aeee389
--- /dev/null
+++ b/lib/tftp/src/tftp.hrl
@@ -0,0 +1,69 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+%%%-------------------------------------------------------------------
+%%% Defines
+%%%-------------------------------------------------------------------
+
+-define(TFTP_DEFAULT_PORT, 69).% Default server port
+
+-define(TFTP_OPCODE_RRQ, 1). % Read request
+-define(TFTP_OPCODE_WRQ, 2). % Write request
+-define(TFTP_OPCODE_DATA, 3). % Data
+-define(TFTP_OPCODE_ACK, 4). % Acknowledgement
+-define(TFTP_OPCODE_ERROR, 5). % Error
+-define(TFTP_OPCODE_OACK, 6). % Option acknowledgment
+
+-define(TFTP_ERROR_UNDEF, 0). % Not defined, see error message (if any)
+-define(TFTP_ERROR_ENOENT, 1). % File not found.
+-define(TFTP_ERROR_EACCES, 2). % Access violation.
+-define(TFTP_ERROR_ENOSPC, 3). % Disk full or allocation exceeded.
+-define(TFTP_ERROR_BADOP, 4). % Illegal TFTP operation.
+-define(TFTP_ERROR_BADBLK, 5). % Unknown transfer ID.
+-define(TFTP_ERROR_EEXIST, 6). % File already exists.
+-define(TFTP_ERROR_BADUSER, 7). % No such user.
+-define(TFTP_ERROR_BADOPT, 8). % Unrequested or illegal option.
+
+-record(tftp_msg_req, {access, filename, mode, options, local_filename}).
+-record(tftp_msg_data, {block_no, data}).
+-record(tftp_msg_ack, {block_no}).
+-record(tftp_msg_error, {code, text, details}).
+-record(tftp_msg_oack, {options}).
+
+-record(config, {parent_pid = self(),
+ udp_socket,
+ udp_options = [binary, {reuseaddr, true}, {active, once}],
+ udp_host = "localhost",
+ udp_port = ?TFTP_DEFAULT_PORT,
+ port_policy = random,
+ use_tsize = false,
+ max_tsize = infinity, % Filesize
+ max_conn = infinity,
+ rejected = [],
+ polite_ack = false,
+ debug_level = none,
+ timeout,
+ user_options = [],
+ callbacks = [],
+ logger = tftp_logger,
+ max_retries = 5}).
+
+-record(callback, {regexp, internal, module, state, block_no, count}).
diff --git a/lib/tftp/src/tftp_app.erl b/lib/tftp/src/tftp_app.erl
new file mode 100644
index 0000000000..80d54c6cbe
--- /dev/null
+++ b/lib/tftp/src/tftp_app.erl
@@ -0,0 +1,56 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+%%%-------------------------------------------------------------------
+%% @doc ftp public API
+%% @end
+%%%-------------------------------------------------------------------
+
+-module(tftp_app).
+
+-behaviour(application).
+
+%% Application callbacks
+-export([start/2, stop/1]).
+
+%%====================================================================
+%% API
+%%====================================================================
+
+start(_StartType, _StartArgs) ->
+ Config = get_configuration(),
+ tftp_sup:start_link(Config).
+
+%%--------------------------------------------------------------------
+stop(_State) ->
+ ok.
+
+%%====================================================================
+%% Internal functions
+%%====================================================================
+
+get_configuration() ->
+ case (catch application:get_env(tftp, services)) of
+ {ok, Services} ->
+ Services;
+ _ ->
+ []
+ end.
diff --git a/lib/tftp/src/tftp_binary.erl b/lib/tftp/src/tftp_binary.erl
new file mode 100644
index 0000000000..3438ba235b
--- /dev/null
+++ b/lib/tftp/src/tftp_binary.erl
@@ -0,0 +1,239 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+%%%-------------------------------------------------------------------
+%%% File : tft_binary.erl
+%%% Author : Hakan Mattsson <[email protected]>
+%%% Description :
+%%%
+%%% Created : 24 May 2004 by Hakan Mattsson <[email protected]>
+%%%-------------------------------------------------------------------
+
+-module(tftp_binary).
+
+%%%-------------------------------------------------------------------
+%%% Interface
+%%%-------------------------------------------------------------------
+
+-behaviour(tftp).
+
+-export([prepare/6, open/6, read/1, write/2, abort/3]).
+
+-record(read_state, {options, blksize, bin, is_native_ascii, is_network_ascii, count}).
+-record(write_state, {options, blksize, list, is_native_ascii, is_network_ascii}).
+
+%%-------------------------------------------------------------------
+%% Prepare
+%%-------------------------------------------------------------------
+
+prepare(_Peer, Access, Filename, Mode, SuggestedOptions, Initial) when is_list(Initial) ->
+ %% Client side
+ IsNativeAscii = is_native_ascii(Initial),
+ case catch handle_options(Access, Filename, Mode, SuggestedOptions, IsNativeAscii) of
+ {ok, IsNetworkAscii, AcceptedOptions} when Access =:= read, is_binary(Filename) ->
+ State = #read_state{options = AcceptedOptions,
+ blksize = lookup_blksize(AcceptedOptions),
+ bin = Filename,
+ is_network_ascii = IsNetworkAscii,
+ count = size(Filename),
+ is_native_ascii = IsNativeAscii},
+ {ok, AcceptedOptions, State};
+ {ok, IsNetworkAscii, AcceptedOptions} when Access =:= write, Filename =:= binary ->
+ State = #write_state{options = AcceptedOptions,
+ blksize = lookup_blksize(AcceptedOptions),
+ list = [],
+ is_network_ascii = IsNetworkAscii,
+ is_native_ascii = IsNativeAscii},
+ {ok, AcceptedOptions, State};
+ {ok, _, _} ->
+ {error, {undef, "Illegal callback usage. Mode and filename is incompatible."}};
+ {error, {Code, Text}} ->
+ {error, {Code, Text}}
+ end;
+prepare(_Peer, _Access, _Bin, _Mode, _SuggestedOptions, _Initial) ->
+ {error, {undef, "Illegal callback options."}}.
+
+%%-------------------------------------------------------------------
+%% Open
+%%-------------------------------------------------------------------
+
+open(Peer, Access, Filename, Mode, SuggestedOptions, Initial) when is_list(Initial) ->
+ %% Server side
+ case prepare(Peer, Access, Filename, Mode, SuggestedOptions, Initial) of
+ {ok, AcceptedOptions, State} ->
+ open(Peer, Access, Filename, Mode, AcceptedOptions, State);
+ {error, {Code, Text}} ->
+ {error, {Code, Text}}
+ end;
+open(_Peer, Access, Filename, Mode, NegotiatedOptions, State) when is_record(State, read_state) ->
+ %% Both sides
+ case catch handle_options(Access, Filename, Mode, NegotiatedOptions, State#read_state.is_native_ascii) of
+ {ok, IsNetworkAscii, Options}
+ when Options =:= NegotiatedOptions,
+ IsNetworkAscii =:= State#read_state.is_network_ascii ->
+ {ok, NegotiatedOptions, State};
+ {error, {Code, Text}} ->
+ {error, {Code, Text}}
+ end;
+open(_Peer, Access, Filename, Mode, NegotiatedOptions, State) when is_record(State, write_state) ->
+ %% Both sides
+ case catch handle_options(Access, Filename, Mode, NegotiatedOptions, State#write_state.is_native_ascii) of
+ {ok, IsNetworkAscii, Options}
+ when Options =:= NegotiatedOptions,
+ IsNetworkAscii =:= State#write_state.is_network_ascii ->
+ {ok, NegotiatedOptions, State};
+ {error, {Code, Text}} ->
+ {error, {Code, Text}}
+ end;
+open(Peer, Access, Filename, Mode, NegotiatedOptions, State) ->
+ %% Handle upgrade from old releases. Please, remove this clause in next release.
+ State2 = upgrade_state(State),
+ open(Peer, Access, Filename, Mode, NegotiatedOptions, State2).
+
+%%-------------------------------------------------------------------
+%% Read
+%%-------------------------------------------------------------------
+
+read(#read_state{bin = Bin} = State) when is_binary(Bin) ->
+ BlkSize = State#read_state.blksize,
+ if
+ size(Bin) >= BlkSize ->
+ <<Block:BlkSize/binary, Bin2/binary>> = Bin,
+ State2 = State#read_state{bin = Bin2},
+ {more, Block, State2};
+ size(Bin) < BlkSize ->
+ {last, Bin, State#read_state.count}
+ end;
+read(State) ->
+ %% Handle upgrade from old releases. Please, remove this clause in next release.
+ State2 = upgrade_state(State),
+ read(State2).
+
+%%-------------------------------------------------------------------
+%% Write
+%%-------------------------------------------------------------------
+
+write(Bin, #write_state{list = List} = State) when is_binary(Bin), is_list(List) ->
+ Size = size(Bin),
+ BlkSize = State#write_state.blksize,
+ if
+ Size =:= BlkSize ->
+ {more, State#write_state{list = [Bin | List]}};
+ Size < BlkSize ->
+ Bin2 = list_to_binary(lists:reverse([Bin | List])),
+ {last, Bin2}
+ end;
+write(Bin, State) ->
+ %% Handle upgrade from old releases. Please, remove this clause in next release.
+ State2 = upgrade_state(State),
+ write(Bin, State2).
+
+%%-------------------------------------------------------------------
+%% Abort
+%%-------------------------------------------------------------------
+
+abort(_Code, _Text, #read_state{bin = Bin} = State)
+ when is_record(State, read_state), is_binary(Bin) ->
+ ok;
+abort(_Code, _Text, #write_state{list = List} = State)
+ when is_record(State, write_state), is_list(List) ->
+ ok;
+abort(Code, Text, State) ->
+ %% Handle upgrade from old releases. Please, remove this clause in next release.
+ State2 = upgrade_state(State),
+ abort(Code, Text, State2).
+
+%%-------------------------------------------------------------------
+%% Process options
+%%-------------------------------------------------------------------
+
+handle_options(Access, Bin, Mode, Options, IsNativeAscii) ->
+ IsNetworkAscii = handle_mode(Mode, IsNativeAscii),
+ Options2 = do_handle_options(Access, Bin, Options),
+ {ok, IsNetworkAscii, Options2}.
+
+handle_mode(Mode, IsNativeAscii) ->
+ case Mode of
+ "netascii" when IsNativeAscii =:= true -> true;
+ "octet" -> false;
+ _ -> throw({error, {badop, "Illegal mode " ++ Mode}})
+ end.
+
+do_handle_options(Access, Bin, [{Key, Val} | T]) ->
+ case Key of
+ "tsize" ->
+ case Access of
+ read when Val =:= "0", is_binary(Bin) ->
+ Tsize = integer_to_list(size(Bin)),
+ [{Key, Tsize} | do_handle_options(Access, Bin, T)];
+ _ ->
+ handle_integer(Access, Bin, Key, Val, T, 0, infinity)
+ end;
+ "blksize" ->
+ handle_integer(Access, Bin, Key, Val, T, 8, 65464);
+ "timeout" ->
+ handle_integer(Access, Bin, Key, Val, T, 1, 255);
+ _ ->
+ do_handle_options(Access, Bin, T)
+ end;
+do_handle_options(_Access, _Bin, []) ->
+ [].
+
+
+handle_integer(Access, Bin, Key, Val, Options, Min, Max) ->
+ case catch list_to_integer(Val) of
+ {'EXIT', _} ->
+ do_handle_options(Access, Bin, Options);
+ Int when Int >= Min, Int =< Max ->
+ [{Key, Val} | do_handle_options(Access, Bin, Options)];
+ Int when Int >= Min, Max =:= infinity ->
+ [{Key, Val} | do_handle_options(Access, Bin, Options)];
+ _Int ->
+ throw({error, {badopt, "Illegal " ++ Key ++ " value " ++ Val}})
+ end.
+
+lookup_blksize(Options) ->
+ case lists:keysearch("blksize", 1, Options) of
+ {value, {_, Val}} ->
+ list_to_integer(Val);
+ false ->
+ 512
+ end.
+
+is_native_ascii([]) ->
+ is_native_ascii();
+is_native_ascii([{native_ascii, Bool}]) ->
+ case Bool of
+ true -> true;
+ false -> false
+ end.
+
+is_native_ascii() ->
+ case os:type() of
+ {win32, _} -> true;
+ _ -> false
+ end.
+
+%% Handle upgrade from old releases. Please, remove this function in next release.
+upgrade_state({read_state, Options, Blksize, Bin, IsNetworkAscii, Count}) ->
+ {read_state, Options, Blksize, Bin, false, IsNetworkAscii, Count};
+upgrade_state({write_state, Options, Blksize, List, IsNetworkAscii}) ->
+ {write_state, Options, Blksize, List, false, IsNetworkAscii}.
diff --git a/lib/tftp/src/tftp_engine.erl b/lib/tftp/src/tftp_engine.erl
new file mode 100644
index 0000000000..78a105bcc8
--- /dev/null
+++ b/lib/tftp/src/tftp_engine.erl
@@ -0,0 +1,1422 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%-------------------------------------------------------------------
+%% Protocol engine for trivial FTP
+%%-------------------------------------------------------------------
+
+-module(tftp_engine).
+
+%%%-------------------------------------------------------------------
+%%% Interface
+%%%-------------------------------------------------------------------
+
+%% application internal functions
+-export([
+ daemon_start/1,
+ daemon_loop/1,
+ daemon_loop/3, %% Handle upgrade from old releases. Please, remove this function in next release.
+ client_start/4,
+ common_loop/6,
+ info/1,
+ change_config/2
+ ]).
+
+%% module internal
+-export([
+ daemon_init/1,
+ server_init/2,
+ client_init/2,
+ wait_for_msg/3,
+ callback/4
+ ]).
+
+%% sys callback functions
+-export([
+ system_continue/3,
+ system_terminate/4,
+ system_code_change/4
+ ]).
+
+-include("tftp.hrl").
+
+-type prep_status() :: 'error' | 'last' | 'more' | 'terminate'.
+
+-record(daemon_state, {config, n_servers, server_tab, file_tab}).
+-record(server_info, {pid, req, peer}).
+-record(file_info, {peer_req, pid}).
+-record(sys_misc, {module, function, arguments}).
+-record(error, {where, code, text, filename}).
+-record(prepared, {status :: prep_status() | 'undefined',
+ result, block_no, next_data, prev_data}).
+-record(transfer_res, {status, decoded_msg, prepared}).
+-define(ERROR(Where, Code, Text, Filename),
+ #error{where = Where, code = Code, text = Text, filename = Filename}).
+
+%%%-------------------------------------------------------------------
+%%% Info
+%%%-------------------------------------------------------------------
+
+info(daemons) ->
+ Daemons = supervisor:which_children(tftp_sup),
+ [{Pid, info(Pid)} || {_, Pid, _, _} <- Daemons];
+info(servers) ->
+ [{Pid, info(Pid)} || {_, {ok, DeamonInfo}} <- info(daemons),
+ {server, Pid} <- DeamonInfo];
+info(ToPid) when is_pid(ToPid) ->
+ call(info, ToPid, timer:seconds(10)).
+
+change_config(daemons, Options) ->
+ Daemons = supervisor:which_children(tftp_sup),
+ [{Pid, change_config(Pid, Options)} || {_, Pid, _, _} <- Daemons];
+change_config(servers, Options) ->
+ [{Pid, change_config(Pid, Options)} || {_, {ok, DeamonInfo}} <- info(daemons),
+ {server, Pid} <- DeamonInfo];
+change_config(ToPid, Options) when is_pid(ToPid) ->
+ BadKeys = [host, port, udp],
+ BadOptions = [{Key, Val} || {Key, Val} <- Options,
+ BadKey <- BadKeys,
+ Key =:= BadKey],
+ case BadOptions of
+ [] ->
+ call({change_config, Options}, ToPid, timer:seconds(10));
+ [{Key, Val} | _] ->
+ {error, {badarg, {Key, Val}}}
+ end.
+
+call(Req, ToPid, Timeout) when is_pid(ToPid) ->
+ Type = process,
+ Ref = erlang:monitor(Type, ToPid),
+ ToPid ! {Req, Ref, self()},
+ receive
+ {Reply, Ref, FromPid} when FromPid =:= ToPid ->
+ erlang:demonitor(Ref, [flush]),
+ Reply;
+ {'DOWN', Ref, Type, FromPid, _Reason} when FromPid =:= ToPid ->
+ {error, timeout}
+ after Timeout ->
+ {error, timeout}
+ end.
+
+reply(Reply, Ref, ToPid) ->
+ ToPid ! {Reply, Ref, self()}.
+
+%%%-------------------------------------------------------------------
+%%% Daemon
+%%%-------------------------------------------------------------------
+
+%% Returns {ok, Port}
+daemon_start(Options) when is_list(Options) ->
+ Config = tftp_lib:parse_config(Options),
+ proc_lib:start_link(?MODULE, daemon_init, [Config], infinity).
+
+daemon_init(Config) when is_record(Config, config),
+ is_pid(Config#config.parent_pid) ->
+ process_flag(trap_exit, true),
+ {Port, UdpOptions} = prepare_daemon_udp(Config),
+ case catch gen_udp:open(Port, UdpOptions) of
+ {ok, Socket} ->
+ {ok, ActualPort} = inet:port(Socket),
+ proc_lib:init_ack({ok, self()}),
+ Config2 = Config#config{udp_socket = Socket,
+ udp_port = ActualPort},
+ print_debug_info(Config2, daemon, open, #tftp_msg_req{filename = ""}),
+ ServerTab = ets:new(tftp_daemon_servers, [{keypos, 2}]),
+ FileTab = ets:new(tftp_daemon_files, [{keypos, 2}]),
+ State = #daemon_state{config = Config2,
+ n_servers = 0,
+ server_tab = ServerTab,
+ file_tab = FileTab},
+ daemon_loop(State);
+ {error, Reason} ->
+ Text = lists:flatten(io_lib:format("UDP open ~p -> ~p", [UdpOptions, Reason])),
+ print_debug_info(Config, daemon, open, ?ERROR(open, undef, Text, "")),
+ exit({gen_udp_open, UdpOptions, Reason});
+ Reason ->
+ Text = lists:flatten(io_lib:format("UDP open ~p -> ~p", [UdpOptions, Reason])),
+ print_debug_info(Config, daemon, open, ?ERROR(open, undef, Text, "")),
+ exit({gen_udp_open, UdpOptions, Reason})
+ end.
+
+prepare_daemon_udp(#config{udp_port = Port, udp_options = UdpOptions} = Config) ->
+ case lists:keymember(fd, 1, UdpOptions) of
+ true ->
+ %% Use explicit fd
+ {Port, UdpOptions};
+ false ->
+ %% Use fd from setuid_socket_wrap, such as -tftpd_69
+ InitArg = list_to_atom("tftpd_" ++ integer_to_list(Port)),
+ case init:get_argument(InitArg) of
+ {ok, [[FdStr]] = Badarg} when is_list(FdStr) ->
+ case catch list_to_integer(FdStr) of
+ Fd when is_integer(Fd) ->
+ {0, [{fd, Fd} | lists:keydelete(ip, 1, UdpOptions)]};
+ {'EXIT', _} ->
+ Text = lists:flatten(io_lib:format("Illegal prebound fd ~p: ~p", [InitArg, Badarg])),
+ print_debug_info(Config, daemon, open, ?ERROR(open, undef, Text, "")),
+ exit({badarg, {prebound_fd, InitArg, Badarg}})
+ end;
+ {ok, Badarg} ->
+ Text = lists:flatten(io_lib:format("Illegal prebound fd ~p: ~p", [InitArg, Badarg])),
+ print_debug_info(Config, daemon, open, ?ERROR(open, undef, Text, "")),
+ exit({badarg, {prebound_fd, InitArg, Badarg}});
+ error ->
+ {Port, UdpOptions}
+ end
+ end.
+
+daemon_loop(DaemonConfig, N, Servers) when is_list(Servers) ->
+ %% Handle upgrade from old releases. Please, remove this function in next release.
+ ServerTab = ets:new(tftp_daemon_servers, [{keypos, 2}]),
+ FileTab = ets:new(tftp_daemon_files, [{keypos, 2}]),
+ State = #daemon_state{config = DaemonConfig,
+ n_servers = N,
+ server_tab = ServerTab,
+ file_tab = FileTab},
+ Req = #tftp_msg_req{filename = dummy},
+ [ets:insert(ServerTab, #server_info{pid = Pid, req = Req, peer = dummy}) || Pid <- Servers],
+ daemon_loop(State).
+
+daemon_loop(#daemon_state{config = DaemonConfig,
+ n_servers = N,
+ server_tab = ServerTab,
+ file_tab = FileTab} = State) when is_record(DaemonConfig, config) ->
+ %% info_msg(DaemonConfig, "=====> TFTP: Daemon #~p\n", [N]), %% XXX
+ receive
+ {info, Ref, FromPid} when is_pid(FromPid) ->
+ Fun = fun(#server_info{pid = Pid}, Acc) -> [{server, Pid} | Acc] end,
+ ServerInfo = ets:foldl(Fun, [], ServerTab),
+ Info = internal_info(DaemonConfig, daemon) ++ [{n_conn, N}] ++ ServerInfo,
+ _ = reply({ok, Info}, Ref, FromPid),
+ ?MODULE:daemon_loop(State);
+ {{change_config, Options}, Ref, FromPid} when is_pid(FromPid) ->
+ case catch tftp_lib:parse_config(Options, DaemonConfig) of
+ {'EXIT', Reason} ->
+ _ = reply({error, Reason}, Ref, FromPid),
+ ?MODULE:daemon_loop(State);
+ DaemonConfig2 when is_record(DaemonConfig2, config) ->
+ _ = reply(ok, Ref, FromPid),
+ ?MODULE:daemon_loop(State#daemon_state{config = DaemonConfig2})
+ end;
+ {udp, Socket, RemoteHost, RemotePort, Bin} when is_binary(Bin) ->
+ _ = inet:setopts(Socket, [{active, once}]),
+ ServerConfig = DaemonConfig#config{parent_pid = self(),
+ udp_host = RemoteHost,
+ udp_port = RemotePort},
+ Msg = (catch tftp_lib:decode_msg(Bin)),
+ print_debug_info(ServerConfig, daemon, recv, Msg),
+ case Msg of
+ Req when is_record(Req, tftp_msg_req),
+ N =< DaemonConfig#config.max_conn ->
+ Peer = peer_info(ServerConfig),
+ PeerReq = {Peer, Req},
+ PeerInfo = lists:flatten(io_lib:format("~p", [Peer])),
+ case ets:lookup(FileTab, PeerReq) of
+ [] ->
+ Args = [ServerConfig, Req],
+ Pid = proc_lib:spawn_link(?MODULE, server_init, Args),
+ ets:insert(ServerTab, #server_info{pid = Pid, req = Req, peer = Peer}),
+ ets:insert(FileTab, #file_info{peer_req = PeerReq, pid = Pid}),
+ ?MODULE:daemon_loop(State#daemon_state{n_servers = N + 1});
+ [#file_info{pid = Pid}] ->
+ %% Yet another request of the file from same peer
+ warning_msg(DaemonConfig, "~p Reuse connection for ~s\n\t~p\n",
+ [Pid, PeerInfo, Req#tftp_msg_req.filename]),
+ ?MODULE:daemon_loop(State)
+ end;
+ Req when is_record(Req, tftp_msg_req) ->
+ Reply = #tftp_msg_error{code = enospc, text = "Too many connections"},
+ Peer = peer_info(ServerConfig),
+ PeerInfo = lists:flatten(io_lib:format("~p", [Peer])),
+ warning_msg(DaemonConfig,
+ "Daemon has too many connections (~p)."
+ "\n\tRejecting request from ~s\n",
+ [N, PeerInfo]),
+ send_msg(ServerConfig, daemon, Reply),
+ ?MODULE:daemon_loop(State);
+ {'EXIT', Reply} when is_record(Reply, tftp_msg_error) ->
+ send_msg(ServerConfig, daemon, Reply),
+ ?MODULE:daemon_loop(State);
+ Req ->
+ Reply = #tftp_msg_error{code = badop,
+ text = "Illegal TFTP operation"},
+ warning_msg(DaemonConfig, "Daemon received: ~p.\n\tfrom ~p:~p",
+ [Req, RemoteHost, RemotePort]),
+ send_msg(ServerConfig, daemon, Reply),
+ ?MODULE:daemon_loop(State)
+ end;
+ {system, From, Msg} ->
+ Misc = #sys_misc{module = ?MODULE, function = daemon_loop, arguments = [State]},
+ sys:handle_system_msg(Msg, From, DaemonConfig#config.parent_pid, ?MODULE, [], Misc);
+ {'EXIT', Pid, Reason} when DaemonConfig#config.parent_pid =:= Pid ->
+ close_port(DaemonConfig, daemon, #tftp_msg_req{filename = ""}),
+ exit(Reason);
+ {'EXIT', Pid, _Reason} = Info ->
+ case ets:lookup(ServerTab, Pid) of
+ [] ->
+ warning_msg(DaemonConfig, "Daemon received: ~p", [Info]),
+ ?MODULE:daemon_loop(State);
+ [#server_info{req = Req, peer = Peer}] ->
+ PeerReq = {Peer, Req},
+ ets:delete(FileTab, PeerReq),
+ ets:delete(ServerTab, Pid),
+ ?MODULE:daemon_loop(State#daemon_state{n_servers = N - 1})
+ end;
+ Info ->
+ warning_msg(DaemonConfig, "Daemon received: ~p", [Info]),
+ ?MODULE:daemon_loop(State)
+ end;
+daemon_loop(#daemon_state{config = Config} = State) ->
+ %% Handle upgrade from old releases. Please, remove this clause in next release.
+ Config2 = upgrade_config(Config),
+ daemon_loop(State#daemon_state{config = Config2}).
+
+upgrade_config({config, ParentPid, UdpSocket, UdpOptions, UdpHost, UdpPort, PortPolicy,
+ UseTsize, MaxTsize, MaxConn, Rejected, PoliteAck, DebugLevel,
+ Timeout, UserOptions, Callbacks}) ->
+ Callbacks2 = tftp_lib:add_default_callbacks(Callbacks),
+ Logger = tftp_logger,
+ MaxRetries = 5,
+ {config, ParentPid, UdpSocket, UdpOptions, UdpHost, UdpPort, PortPolicy,
+ UseTsize, MaxTsize, MaxConn, Rejected, PoliteAck, DebugLevel,
+ Timeout, UserOptions, Callbacks2, Logger, MaxRetries}.
+
+%%%-------------------------------------------------------------------
+%%% Server
+%%%-------------------------------------------------------------------
+
+server_init(Config, Req) when is_record(Config, config),
+ is_pid(Config#config.parent_pid),
+ is_record(Req, tftp_msg_req) ->
+ process_flag(trap_exit, true),
+ %% Config =
+ %% case os:getenv("TFTPDEBUG") of
+ %% false ->
+ %% Config0;
+ %% DebugLevel ->
+ %% Config0#config{debug_level = list_to_atom(DebugLevel)}
+ %% end,
+ SuggestedOptions = Req#tftp_msg_req.options,
+ UdpOptions = Config#config.udp_options,
+ UdpOptions2 = lists:keydelete(fd, 1, UdpOptions),
+ Config1 = Config#config{udp_options = UdpOptions2},
+ Config2 = tftp_lib:parse_config(SuggestedOptions, Config1),
+ SuggestedOptions2 = Config2#config.user_options,
+ Req2 = Req#tftp_msg_req{options = SuggestedOptions2},
+ case open_free_port(Config2, server, Req2) of
+ {ok, Config3} ->
+ Filename = Req#tftp_msg_req.filename,
+ case match_callback(Filename, Config3#config.callbacks) of
+ {ok, Callback} ->
+ print_debug_info(Config3, server, match, Callback),
+ case pre_verify_options(Config3, Req2) of
+ ok ->
+ case callback({open, server_open}, Config3, Callback, Req2) of
+ {Callback2, {ok, AcceptedOptions}} ->
+ {LocalAccess, _} = local_file_access(Req2),
+ OptText = "Internal error. Not allowed to add new options.",
+ case post_verify_options(Config3, Req2, AcceptedOptions, OptText) of
+ {ok, Config4, Req3} when AcceptedOptions =/= [] ->
+ Reply = #tftp_msg_oack{options = AcceptedOptions},
+ BlockNo =
+ case LocalAccess of
+ read -> 0;
+ write -> 1
+ end,
+ {Config5, Callback3, TransferRes} =
+ transfer(Config4, Callback2, Req3, Reply, LocalAccess, BlockNo, #prepared{}),
+ common_loop(Config5, Callback3, Req3, TransferRes, LocalAccess, BlockNo);
+ {ok, Config4, Req3} when LocalAccess =:= write ->
+ BlockNo = 0,
+ common_ack(Config4, Callback2, Req3, LocalAccess, BlockNo, #prepared{});
+ {ok, Config4, Req3} when LocalAccess =:= read ->
+ BlockNo = 0,
+ common_read(Config4, Callback2, Req3, LocalAccess, BlockNo, BlockNo, #prepared{});
+ {error, {Code, Text}} ->
+ {undefined, Error} =
+ callback({abort, {Code, Text}}, Config3, Callback2, Req2),
+ send_msg(Config3, Req, Error),
+ terminate(Config3, Req2, ?ERROR(post_verify_options, Code, Text, Req2#tftp_msg_req.filename))
+ end;
+ {undefined, #tftp_msg_error{code = Code, text = Text} = Error} ->
+ send_msg(Config3, Req, Error),
+ terminate(Config3, Req, ?ERROR(server_open, Code, Text, Req2#tftp_msg_req.filename))
+ end;
+ {error, {Code, Text}} ->
+ {undefined, Error} =
+ callback({abort, {Code, Text}}, Config2, Callback, Req2),
+ send_msg(Config2, Req, Error),
+ terminate(Config2, Req2, ?ERROR(pre_verify_options, Code, Text, Req2#tftp_msg_req.filename))
+ end;
+ {error, #tftp_msg_error{code = Code, text = Text} = Error} ->
+ send_msg(Config3, Req, Error),
+ terminate(Config3, Req, ?ERROR(match_callback, Code, Text, Req2#tftp_msg_req.filename))
+ end;
+ #error{} = Error ->
+ terminate(Config2, Req, Error)
+ end;
+server_init(Config, Req) when is_record(Req, tftp_msg_req) ->
+ Config2 = upgrade_config(Config),
+ server_init(Config2, Req).
+
+%%%-------------------------------------------------------------------
+%%% Client
+%%%-------------------------------------------------------------------
+
+%% LocalFilename = filename() | 'binary' | binary()
+%% Returns {ok, LastCallbackState} | {error, Reason}
+client_start(Access, RemoteFilename, LocalFilename, Options) ->
+ Config = tftp_lib:parse_config(Options),
+ Config2 = Config#config{parent_pid = self(),
+ udp_socket = undefined},
+ Req = #tftp_msg_req{access = Access,
+ filename = RemoteFilename,
+ mode = lookup_mode(Config2#config.user_options),
+ options = Config2#config.user_options,
+ local_filename = LocalFilename},
+ Args = [Config2, Req],
+ case proc_lib:start_link(?MODULE, client_init, Args, infinity) of
+ {ok, LastCallbackState} ->
+ {ok, LastCallbackState};
+ {error, Error} ->
+ {error, Error}
+ end.
+
+client_init(Config, Req) when is_record(Config, config),
+ is_pid(Config#config.parent_pid),
+ is_record(Req, tftp_msg_req) ->
+ process_flag(trap_exit, true),
+ %% Config =
+ %% case os:getenv("TFTPDEBUG") of
+ %% false ->
+ %% Config0;
+ %% "none" ->
+ %% Config0;
+ %% DebugLevel ->
+ %% info_msg(Config, "TFTPDEBUG: ~s\n", [DebugLevel]),
+ %% Config0#config{debug_level = list_to_atom(DebugLevel)}
+ %% end,
+ case open_free_port(Config, client, Req) of
+ {ok, Config2} ->
+ Req2 =
+ case Config2#config.use_tsize of
+ true ->
+ SuggestedOptions = Req#tftp_msg_req.options,
+ SuggestedOptions2 = tftp_lib:replace_val("tsize", "0", SuggestedOptions),
+ Req#tftp_msg_req{options = SuggestedOptions2};
+ false ->
+ Req
+ end,
+ LocalFilename = Req2#tftp_msg_req.local_filename,
+ case match_callback(LocalFilename, Config2#config.callbacks) of
+ {ok, Callback} ->
+ print_debug_info(Config2, client, match, Callback),
+ client_prepare(Config2, Callback, Req2);
+ {error, #tftp_msg_error{code = Code, text = Text}} ->
+ terminate(Config, Req, ?ERROR(match, Code, Text, Req#tftp_msg_req.filename))
+ end;
+ #error{} = Error ->
+ terminate(Config, Req, Error)
+ end.
+
+client_prepare(Config, Callback, Req) when is_record(Req, tftp_msg_req) ->
+ case pre_verify_options(Config, Req) of
+ ok ->
+ case callback({open, client_prepare}, Config, Callback, Req) of
+ {Callback2, {ok, AcceptedOptions}} ->
+ OptText = "Internal error. Not allowed to add new options.",
+ case post_verify_options(Config, Req, AcceptedOptions, OptText) of
+ {ok, Config2, Req2} ->
+ {LocalAccess, _} = local_file_access(Req2),
+ BlockNo = 0,
+ {Config3, Callback3, TransferRes} =
+ transfer(Config2, Callback2, Req2, Req2, LocalAccess, BlockNo, #prepared{}),
+ client_open(Config3, Callback3, Req2, BlockNo, TransferRes);
+ {error, {Code, Text}} ->
+ _ = callback({abort, {Code, Text}}, Config, Callback2, Req),
+ terminate(Config, Req, ?ERROR(post_verify_options, Code, Text, Req#tftp_msg_req.filename))
+ end;
+ {undefined, #tftp_msg_error{code = Code, text = Text}} ->
+ terminate(Config, Req, ?ERROR(client_prepare, Code, Text, Req#tftp_msg_req.filename))
+ end;
+ {error, {Code, Text}} ->
+ _ = callback({abort, {Code, Text}}, Config, Callback, Req),
+ terminate(Config, Req, ?ERROR(pre_verify_options, Code, Text, Req#tftp_msg_req.filename))
+ end.
+
+client_open(Config, Callback, Req, BlockNo, #transfer_res{status = Status, decoded_msg = DecodedMsg, prepared = Prepared}) ->
+ {LocalAccess, _} = local_file_access(Req),
+ case Status of
+ ok when is_record(Prepared, prepared) ->
+ case DecodedMsg of
+ Msg when is_record(Msg, tftp_msg_oack) ->
+ ServerOptions = Msg#tftp_msg_oack.options,
+ OptText = "Protocol violation. Server is not allowed new options",
+ case post_verify_options(Config, Req, ServerOptions, OptText) of
+ {ok, Config2, Req2} ->
+ {Config3, Callback2, Req3} =
+ do_client_open(Config2, Callback, Req2),
+ case LocalAccess of
+ read ->
+ common_read(Config3, Callback2, Req3, LocalAccess, BlockNo, BlockNo, Prepared);
+ write ->
+ common_ack(Config3, Callback2, Req3, LocalAccess, BlockNo, Prepared)
+ end;
+ {error, {Code, Text}} ->
+ {undefined, Error} =
+ callback({abort, {Code, Text}}, Config, Callback, Req),
+ send_msg(Config, Req, Error),
+ terminate(Config, Req, ?ERROR(verify_server_options, Code, Text, Req#tftp_msg_req.filename))
+ end;
+ #tftp_msg_ack{block_no = ActualBlockNo} when LocalAccess =:= read ->
+ Req2 = Req#tftp_msg_req{options = []},
+ {Config2, Callback2, Req2} = do_client_open(Config, Callback, Req2),
+ ExpectedBlockNo = 0,
+ common_read(Config2, Callback2, Req2, LocalAccess, ExpectedBlockNo, ActualBlockNo, Prepared);
+ #tftp_msg_data{block_no = ActualBlockNo, data = Data} when LocalAccess =:= write ->
+ Req2 = Req#tftp_msg_req{options = []},
+ {Config2, Callback2, Req2} = do_client_open(Config, Callback, Req2),
+ ExpectedBlockNo = 1,
+ common_write(Config2, Callback2, Req2, LocalAccess, ExpectedBlockNo, ActualBlockNo, Data, Prepared);
+ %% #tftp_msg_error{code = Code, text = Text} when Req#tftp_msg_req.options =/= [] ->
+ %% %% Retry without options
+ %% callback({abort, {Code, Text}}, Config, Callback, Req),
+ %% Req2 = Req#tftp_msg_req{options = []},
+ %% client_prepare(Config, Callback, Req2);
+ #tftp_msg_error{code = Code, text = Text} ->
+ _ = callback({abort, {Code, Text}}, Config, Callback, Req),
+ terminate(Config, Req, ?ERROR(client_open, Code, Text, Req#tftp_msg_req.filename));
+ {'EXIT', #tftp_msg_error{code = Code, text = Text}} ->
+ _ = callback({abort, {Code, Text}}, Config, Callback, Req),
+ terminate(Config, Req, ?ERROR(client_open, Code, Text, Req#tftp_msg_req.filename));
+ Msg when is_tuple(Msg) ->
+ Code = badop,
+ Text = "Illegal TFTP operation",
+ {undefined, Error} =
+ callback({abort, {Code, Text}}, Config, Callback, Req),
+ send_msg(Config, Req, Error),
+ Text2 = lists:flatten([Text, ". ", io_lib:format("~p", [element(1, Msg)])]),
+ terminate(Config, Req, ?ERROR(client_open, Code, Text2, Req#tftp_msg_req.filename))
+ end;
+ error when is_record(Prepared, tftp_msg_error) ->
+ #tftp_msg_error{code = Code, text = Text} = Prepared,
+ _ = callback({abort, {Code, Text}}, Config, Callback, Req),
+ terminate(Config, Req, ?ERROR(client_open, Code, Text, Req#tftp_msg_req.filename))
+ end.
+
+do_client_open(Config, Callback, Req) ->
+ case callback({open, client_open}, Config, Callback, Req) of
+ {Callback2, {ok, FinalOptions}} ->
+ OptText = "Internal error. Not allowed to change options.",
+ case post_verify_options(Config, Req, FinalOptions, OptText) of
+ {ok, Config2, Req2} ->
+ {Config2, Callback2, Req2};
+ {error, {Code, Text}} ->
+ {undefined, Error} =
+ callback({abort, {Code, Text}}, Config, Callback2, Req),
+ send_msg(Config, Req, Error),
+ terminate(Config, Req, ?ERROR(post_verify_options, Code, Text, Req#tftp_msg_req.filename))
+ end;
+ {undefined, #tftp_msg_error{code = Code, text = Text} = Error} ->
+ send_msg(Config, Req, Error),
+ terminate(Config, Req, ?ERROR(client_open, Code, Text, Req#tftp_msg_req.filename))
+ end.
+
+%%%-------------------------------------------------------------------
+%%% Common loop for both client and server
+%%%-------------------------------------------------------------------
+
+common_loop(Config, Callback, Req, #transfer_res{status = Status, decoded_msg = DecodedMsg, prepared = Prepared}, LocalAccess, ExpectedBlockNo)
+ when is_record(Config, config)->
+ %% Config =
+ %% case os:getenv("TFTPMAX") of
+ %% false ->
+ %% Config0;
+ %% MaxBlockNoStr when Config0#config.debug_level =/= none ->
+ %% case list_to_integer(MaxBlockNoStr) of
+ %% MaxBlockNo when ExpectedBlockNo > MaxBlockNo ->
+ %% info_msg(Config, "TFTPMAX: ~p\n", [MaxBlockNo]),
+ %% info_msg(Config, "TFTPDEBUG: none\n", []),
+ %% Config0#config{debug_level = none};
+ %% _ ->
+ %% Config0
+ %% end;
+ %% _MaxBlockNoStr ->
+ %% Config0
+ %% end,
+ case Status of
+ ok when is_record(Prepared, prepared) ->
+ case DecodedMsg of
+ #tftp_msg_ack{block_no = ActualBlockNo} when LocalAccess =:= read ->
+ common_read(Config, Callback, Req, LocalAccess, ExpectedBlockNo, ActualBlockNo, Prepared);
+ #tftp_msg_data{block_no = ActualBlockNo, data = Data} when LocalAccess =:= write ->
+ common_write(Config, Callback, Req, LocalAccess, ExpectedBlockNo, ActualBlockNo, Data, Prepared);
+ #tftp_msg_error{code = Code, text = Text} ->
+ _ = callback({abort, {Code, Text}}, Config, Callback, Req),
+ terminate(Config, Req, ?ERROR(common_loop, Code, Text, Req#tftp_msg_req.filename));
+ {'EXIT', #tftp_msg_error{code = Code, text = Text} = Error} ->
+ _ = callback({abort, {Code, Text}}, Config, Callback, Req),
+ send_msg(Config, Req, Error),
+ terminate(Config, Req, ?ERROR(common_loop, Code, Text, Req#tftp_msg_req.filename));
+ Msg when is_tuple(Msg) ->
+ Code = badop,
+ Text = "Illegal TFTP operation",
+ {undefined, Error} =
+ callback({abort, {Code, Text}}, Config, Callback, Req),
+ send_msg(Config, Req, Error),
+ Text2 = lists:flatten([Text, ". ", io_lib:format("~p", [element(1, Msg)])]),
+ terminate(Config, Req, ?ERROR(common_loop, Code, Text2, Req#tftp_msg_req.filename))
+ end;
+ error when is_record(Prepared, tftp_msg_error) ->
+ #tftp_msg_error{code = Code, text = Text} = Prepared,
+ send_msg(Config, Req, Prepared),
+ terminate(Config, Req, ?ERROR(transfer, Code, Text, Req#tftp_msg_req.filename))
+ end;
+common_loop(Config, Callback, Req, TransferRes, LocalAccess, ExpectedBlockNo) ->
+ %% Handle upgrade from old releases. Please, remove this clause in next release.
+ Config2 = upgrade_config(Config),
+ common_loop(Config2, Callback, Req, TransferRes, LocalAccess, ExpectedBlockNo).
+
+-spec common_read(#config{}, #callback{}, _, 'read', _, _, #prepared{}) -> no_return().
+
+common_read(Config, _, Req, _, _, _, #prepared{status = terminate, result = Result}) ->
+ terminate(Config, Req, {ok, Result});
+common_read(Config, Callback, Req, LocalAccess, ExpectedBlockNo, ActualBlockNo, Prepared)
+ when ActualBlockNo =:= ExpectedBlockNo, is_record(Prepared, prepared) ->
+ case early_read(Config, Callback, Req, LocalAccess, ActualBlockNo, Prepared) of
+ {Callback2, #prepared{status = more, next_data = Data} = Prepared2} when is_binary(Data) ->
+ Prepared3 = Prepared2#prepared{prev_data = Data, next_data = undefined},
+ do_common_read(Config, Callback2, Req, LocalAccess, ActualBlockNo, Data, Prepared3);
+ {undefined, #prepared{status = last, next_data = Data} = Prepared2} when is_binary(Data) ->
+ Prepared3 = Prepared2#prepared{status = terminate},
+ do_common_read(Config, undefined, Req, LocalAccess, ActualBlockNo, Data, Prepared3);
+ {undefined, #prepared{status = error, result = Error}} ->
+ #tftp_msg_error{code = Code, text = Text} = Error,
+ send_msg(Config, Req, Error),
+ terminate(Config, Req, ?ERROR(read, Code, Text, Req#tftp_msg_req.filename))
+ end;
+common_read(Config, Callback, Req, LocalAccess, ExpectedBlockNo, ActualBlockNo, Prepared)
+ when ActualBlockNo =:= (ExpectedBlockNo - 1), is_record(Prepared, prepared) ->
+ case Prepared of
+ #prepared{status = more, prev_data = Data} when is_binary(Data) ->
+ do_common_read(Config, Callback, Req, LocalAccess, ActualBlockNo, Data, Prepared);
+ #prepared{status = last, prev_data = Data} when is_binary(Data) ->
+ do_common_read(Config, Callback, Req, LocalAccess, ActualBlockNo, Data, Prepared);
+ #prepared{status = error, result = Error} ->
+ #tftp_msg_error{code = Code, text = Text} = Error,
+ send_msg(Config, Req, Error),
+ terminate(Config, Req, ?ERROR(read, Code, Text, Req#tftp_msg_req.filename))
+ end;
+common_read(Config, Callback, Req, LocalAccess, ExpectedBlockNo, ActualBlockNo, Prepared)
+ when ActualBlockNo =< ExpectedBlockNo, is_record(Prepared, prepared) ->
+ %% error_logger:error_msg("TFTP READ ~s: Expected block ~p but got block ~p - IGNORED\n",
+ %% [Req#tftp_msg_req.filename, ExpectedBlockNo, ActualBlockNo]),
+ case Prepared of
+ #prepared{status = more, prev_data = Data} when is_binary(Data) ->
+ Reply = #tftp_msg_data{block_no = ExpectedBlockNo, data = Data},
+ {Config2, Callback2, TransferRes} =
+ wait_for_msg_and_handle_timeout(Config, Callback, Req, Reply, LocalAccess, ExpectedBlockNo, Prepared),
+ ?MODULE:common_loop(Config2, Callback2, Req, TransferRes, LocalAccess, ExpectedBlockNo);
+ #prepared{status = last, prev_data = Data} when is_binary(Data) ->
+ Reply = #tftp_msg_data{block_no = ExpectedBlockNo, data = Data},
+ {Config2, Callback2, TransferRes} =
+ wait_for_msg_and_handle_timeout(Config, Callback, Req, Reply, LocalAccess, ExpectedBlockNo, Prepared),
+ ?MODULE:common_loop(Config2, Callback2, Req, TransferRes, LocalAccess, ExpectedBlockNo);
+ #prepared{status = error, result = Error} ->
+ #tftp_msg_error{code = Code, text = Text} = Error,
+ send_msg(Config, Req, Error),
+ terminate(Config, Req, ?ERROR(read, Code, Text, Req#tftp_msg_req.filename))
+ end;
+common_read(Config, Callback, Req, _LocalAccess, ExpectedBlockNo, ActualBlockNo, Prepared)
+ when is_record(Prepared, prepared) ->
+ Code = badblk,
+ Text = "Unknown transfer ID = " ++
+ integer_to_list(ActualBlockNo) ++ " (" ++ integer_to_list(ExpectedBlockNo) ++ ")",
+ {undefined, Error} =
+ callback({abort, {Code, Text}}, Config, Callback, Req),
+ send_msg(Config, Req, Error),
+ terminate(Config, Req, ?ERROR(read, Code, Text, Req#tftp_msg_req.filename)).
+
+-spec do_common_read(#config{}, #callback{} | undefined, _, 'read', integer(), binary(), #prepared{}) -> no_return().
+
+do_common_read(Config, Callback, Req, LocalAccess, BlockNo, Data, Prepared)
+ when is_binary(Data), is_record(Prepared, prepared) ->
+ NextBlockNo = (BlockNo + 1) rem 65536,
+ Reply = #tftp_msg_data{block_no = NextBlockNo, data = Data},
+ {Config2, Callback2, TransferRes} =
+ transfer(Config, Callback, Req, Reply, LocalAccess, NextBlockNo, Prepared),
+ ?MODULE:common_loop(Config2, Callback2, Req, TransferRes, LocalAccess, NextBlockNo).
+
+-spec common_write(#config{}, #callback{}, _, 'write', integer(), integer(), _, #prepared{}) -> no_return().
+
+common_write(Config, _, Req, _, _, _, _, #prepared{status = terminate, result = Result}) ->
+ terminate(Config, Req, {ok, Result});
+common_write(Config, Callback, Req, LocalAccess, ExpectedBlockNo, ActualBlockNo, Data, Prepared)
+ when ActualBlockNo =:= ExpectedBlockNo, is_binary(Data), is_record(Prepared, prepared) ->
+ case callback({write, Data}, Config, Callback, Req) of
+ {Callback2, #prepared{status = more} = Prepared2} ->
+ common_ack(Config, Callback2, Req, LocalAccess, ActualBlockNo, Prepared2);
+ {undefined, #prepared{status = last, result = Result} = Prepared2} ->
+ Config2 = pre_terminate(Config, Req, {ok, Result}),
+ Prepared3 = Prepared2#prepared{status = terminate},
+ common_ack(Config2, undefined, Req, LocalAccess, ActualBlockNo, Prepared3);
+ {undefined, #prepared{status = error, result = Error}} ->
+ #tftp_msg_error{code = Code, text = Text} = Error,
+ send_msg(Config, Req, Error),
+ terminate(Config, Req, ?ERROR(write, Code, Text, Req#tftp_msg_req.filename))
+ end;
+common_write(Config, Callback, Req, LocalAccess, ExpectedBlockNo, ActualBlockNo, Data, Prepared)
+ when ActualBlockNo =:= (ExpectedBlockNo - 1), is_binary(Data), is_record(Prepared, prepared) ->
+ common_ack(Config, Callback, Req, LocalAccess, ExpectedBlockNo - 1, Prepared);
+common_write(Config, Callback, Req, LocalAccess, ExpectedBlockNo, ActualBlockNo, Data, Prepared)
+ when ActualBlockNo =< ExpectedBlockNo, is_binary(Data), is_record(Prepared, prepared) ->
+ %% error_logger:error_msg("TFTP WRITE ~s: Expected block ~p but got block ~p - IGNORED\n",
+ %% [Req#tftp_msg_req.filename, ExpectedBlockNo, ActualBlockNo]),
+ Reply = #tftp_msg_ack{block_no = ExpectedBlockNo},
+ {Config2, Callback2, TransferRes} =
+ wait_for_msg_and_handle_timeout(Config, Callback, Req, Reply, LocalAccess, ExpectedBlockNo, Prepared),
+ ?MODULE:common_loop(Config2, Callback2, Req, TransferRes, LocalAccess, ExpectedBlockNo);
+common_write(Config, Callback, Req, _, ExpectedBlockNo, ActualBlockNo, Data, Prepared)
+ when is_binary(Data), is_record(Prepared, prepared) ->
+ Code = badblk,
+ Text = "Unknown transfer ID = " ++
+ integer_to_list(ActualBlockNo) ++ " (" ++ integer_to_list(ExpectedBlockNo) ++ ")",
+ {undefined, Error} =
+ callback({abort, {Code, Text}}, Config, Callback, Req),
+ send_msg(Config, Req, Error),
+ terminate(Config, Req, ?ERROR(write, Code, Text, Req#tftp_msg_req.filename)).
+
+common_ack(Config, Callback, Req, LocalAccess, BlockNo, Prepared)
+ when is_record(Prepared, prepared) ->
+ Reply = #tftp_msg_ack{block_no = BlockNo},
+ NextBlockNo = (BlockNo + 1) rem 65536,
+ {Config2, Callback2, TransferRes} =
+ transfer(Config, Callback, Req, Reply, LocalAccess, NextBlockNo, Prepared),
+ ?MODULE:common_loop(Config2, Callback2, Req, TransferRes, LocalAccess, NextBlockNo).
+
+pre_terminate(Config, Req, Result) ->
+ if
+ Req#tftp_msg_req.local_filename =/= undefined,
+ Config#config.parent_pid =/= undefined ->
+ proc_lib:init_ack(Result),
+ unlink(Config#config.parent_pid),
+ Config#config{parent_pid = undefined, polite_ack = true};
+ true ->
+ Config#config{polite_ack = true}
+ end.
+
+-spec terminate(#config{}, #tftp_msg_req{}, {'ok', _} | #error{}) -> no_return().
+
+terminate(Config, Req, Result) ->
+ Result2 =
+ case Result of
+ {ok, _} ->
+ Result;
+ #error{where = Where, code = Code, text = Text} = Error ->
+ print_debug_info(Config, Req, Where, Error#error{filename = Req#tftp_msg_req.filename}),
+ {error, {Where, Code, Text}}
+ end,
+ if
+ Config#config.parent_pid =:= undefined ->
+ close_port(Config, client, Req),
+ exit(normal);
+ Req#tftp_msg_req.local_filename =/= undefined ->
+ %% Client
+ close_port(Config, client, Req),
+ proc_lib:init_ack(Result2),
+ unlink(Config#config.parent_pid),
+ exit(normal);
+ true ->
+ %% Server
+ close_port(Config, server, Req),
+ exit(shutdown)
+ end.
+
+close_port(Config, Who, Req) when is_record(Req, tftp_msg_req) ->
+ case Config#config.udp_socket of
+ undefined ->
+ ignore;
+ Socket ->
+ print_debug_info(Config, Who, close, Req),
+ gen_udp:close(Socket)
+ end.
+
+open_free_port(Config, Who, Req) when is_record(Config, config), is_record(Req, tftp_msg_req) ->
+ UdpOptions = Config#config.udp_options,
+ case Config#config.port_policy of
+ random ->
+ %% BUGBUG: Should be a random port
+ case catch gen_udp:open(0, UdpOptions) of
+ {ok, Socket} ->
+ Config2 = Config#config{udp_socket = Socket},
+ print_debug_info(Config2, Who, open, Req),
+ {ok, Config2};
+ {error, Reason} ->
+ Text = lists:flatten(io_lib:format("UDP open ~p -> ~p", [[0 | UdpOptions], Reason])),
+ ?ERROR(open, undef, Text, Req#tftp_msg_req.filename);
+ {'EXIT', _} = Reason ->
+ Text = lists:flatten(io_lib:format("UDP open ~p -> ~p", [[0 | UdpOptions], Reason])),
+ ?ERROR(open, undef, Text, Req#tftp_msg_req.filename)
+ end;
+ {range, Port, Max} when Port =< Max ->
+ case catch gen_udp:open(Port, UdpOptions) of
+ {ok, Socket} ->
+ Config2 = Config#config{udp_socket = Socket},
+ print_debug_info(Config2, Who, open, Req),
+ {ok, Config2};
+ {error, eaddrinuse} ->
+ PortPolicy = {range, Port + 1, Max},
+ Config2 = Config#config{port_policy = PortPolicy},
+ open_free_port(Config2, Who, Req);
+ {error, Reason} ->
+ Text = lists:flatten(io_lib:format("UDP open ~p -> ~p", [[Port | UdpOptions], Reason])),
+ ?ERROR(open, undef, Text, Req#tftp_msg_req.filename);
+ {'EXIT', _} = Reason->
+ Text = lists:flatten(io_lib:format("UDP open ~p -> ~p", [[Port | UdpOptions], Reason])),
+ ?ERROR(open, undef, Text, Req#tftp_msg_req.filename)
+ end;
+ {range, Port, _Max} ->
+ Reason = "Port range exhausted",
+ Text = lists:flatten(io_lib:format("UDP open ~p -> ~p", [[Port | UdpOptions], Reason])),
+ ?ERROR(Who, undef, Text, Req#tftp_msg_req.filename)
+ end.
+
+%%-------------------------------------------------------------------
+%% Transfer
+%%-------------------------------------------------------------------
+
+%% Returns {Config, Callback, #transfer_res{}}
+transfer(Config, Callback, Req, Msg, LocalAccess, NextBlockNo, Prepared)
+ when is_record(Prepared, prepared) ->
+ IoList = tftp_lib:encode_msg(Msg),
+ Retries = Config#config.max_retries + 1,
+ do_transfer(Config, Callback, Req, Msg, IoList, LocalAccess, NextBlockNo, Prepared, Retries).
+
+do_transfer(Config, Callback, Req, Msg, IoList, LocalAccess, NextBlockNo, Prepared, Retries)
+ when is_record(Prepared, prepared), is_integer(Retries), Retries >= 0 ->
+ case do_send_msg(Config, Req, Msg, IoList) of
+ ok ->
+ {Callback2, Prepared2} =
+ early_read(Config, Callback, Req, LocalAccess, NextBlockNo, Prepared),
+ do_wait_for_msg_and_handle_timeout(Config, Callback2, Req, Msg, IoList, LocalAccess, NextBlockNo, Prepared2, Retries);
+ {error, _Reason} when Retries > 0 ->
+ Retries2 = 0, % Just retry once when send fails
+ do_transfer(Config, Callback, Req, Msg, IoList, LocalAccess, NextBlockNo, Prepared, Retries2);
+ {error, Reason} ->
+ Code = undef,
+ Text = lists:flatten(io_lib:format("Transfer failed - giving up -> ~p", [Reason])),
+ Error = #tftp_msg_error{code = Code, text = Text},
+ {Config, Callback, #transfer_res{status = error, prepared = Error}}
+ end.
+
+wait_for_msg_and_handle_timeout(Config, Callback, Req, Msg, LocalAccess, NextBlockNo, Prepared) ->
+ IoList = tftp_lib:encode_msg(Msg),
+ Retries = Config#config.max_retries + 1,
+ do_wait_for_msg_and_handle_timeout(Config, Callback, Req, Msg, IoList, LocalAccess, NextBlockNo, Prepared, Retries).
+
+do_wait_for_msg_and_handle_timeout(Config, Callback, Req, Msg, IoList, LocalAccess, NextBlockNo, Prepared, Retries) ->
+ Code = undef,
+ Text = "Transfer timed out.",
+ case wait_for_msg(Config, Callback, Req) of
+ timeout when Config#config.polite_ack =:= true ->
+ do_send_msg(Config, Req, Msg, IoList),
+ case Prepared of
+ #prepared{status = terminate, result = Result} ->
+ terminate(Config, Req, {ok, Result});
+ #prepared{} ->
+ terminate(Config, Req, ?ERROR(transfer, Code, Text, Req#tftp_msg_req.filename))
+ end;
+ timeout when Retries > 0 ->
+ Retries2 = Retries - 1,
+ do_transfer(Config, Callback, Req, Msg, IoList, LocalAccess, NextBlockNo, Prepared, Retries2);
+ timeout ->
+ Error = #tftp_msg_error{code = Code, text = Text},
+ {Config, Callback, #transfer_res{status = error, prepared = Error}};
+ {Config2, DecodedMsg} ->
+ {Config2, Callback, #transfer_res{status = ok, decoded_msg = DecodedMsg, prepared = Prepared}}
+ end.
+
+send_msg(Config, Req, Msg) ->
+ case catch tftp_lib:encode_msg(Msg) of
+ {'EXIT', Reason} ->
+ Code = undef,
+ Text = "Internal error. Encode failed",
+ Msg2 = #tftp_msg_error{code = Code, text = Text, details = Reason},
+ send_msg(Config, Req, Msg2);
+ IoList ->
+ do_send_msg(Config, Req, Msg, IoList)
+ end.
+
+do_send_msg(#config{udp_socket = Socket, udp_host = RemoteHost, udp_port = RemotePort} = Config, Req, Msg, IoList) ->
+ %% {ok, LocalPort} = inet:port(Socket),
+ %% if
+ %% LocalPort =/= ?TFTP_DEFAULT_PORT ->
+ %% ok;
+ %% true ->
+ %% print_debug_info(Config#config{debug_level = all}, Req, send, Msg),
+ %% error(Config,
+ %% "Daemon replies from the default port (~p)\n\t to ~p:~p\n\t¨~p\n",
+ %% [LocalPort, RemoteHost, RemotePort, Msg])
+ %% end,
+
+ print_debug_info(Config, Req, send, Msg),
+
+ %% case os:getenv("TFTPDUMP") of
+ %% false ->
+ %% ignore;
+ %% DumpPath ->
+ %% trace_udp_send(Req, Msg, IoList, DumpPath)
+ %% end,
+ Res = gen_udp:send(Socket, RemoteHost, RemotePort, IoList),
+ case Res of
+ ok ->
+ ok;
+ {error, einval = Reason} ->
+ error_msg(Config,
+ "Stacktrace; ~p\n gen_udp:send(~p, ~p, ~p, ~p) -> ~p\n",
+ [erlang:get_stacktrace(), Socket, RemoteHost, RemotePort, IoList, {error, Reason}]);
+ {error, Reason} ->
+ {error, Reason}
+ end.
+
+%% trace_udp_send(#tftp_msg_req{filename = [$/ | RelFile]} = Req, Msg, IoList, DumpPath) ->
+%% trace_udp_send(Req#tftp_msg_req{filename = RelFile}, Msg, IoList, DumpPath);
+%% trace_udp_send(#tftp_msg_req{filename = RelFile},
+%% #tftp_msg_data{block_no = BlockNo, data = Data},
+%% _IoList,
+%% DumpPath) ->
+%% File = filename:join([DumpPath, RelFile, "block" ++ string:right(integer_to_list(BlockNo), 5, $0) ++ ".dump"]),
+%% if
+%% (BlockNo rem 1000) =:= 1 ->
+%% info_msg(Config, "TFTPDUMP: Data ~s\n", [File]);
+%% true ->
+%% ignore
+%% end,
+%% ok = filelib:ensure_dir(File),
+%% ok = file:write_file(File, Data);
+%% trace_udp_send(#tftp_msg_req{filename = RelFile}, Msg, _IoList, _DumpPath) ->
+%% info_msg(Config, "TFTPDUMP: No data ~s -> ~p\n", [RelFile, element(1, Msg)]).
+
+wait_for_msg(Config, Callback, Req) ->
+ receive
+ {udp, Socket, RemoteHost, RemotePort, Bin}
+ when is_binary(Bin), Callback#callback.block_no =:= undefined ->
+ %% Client prepare
+ _ = inet:setopts(Socket, [{active, once}]),
+ Config2 = Config#config{udp_host = RemoteHost,
+ udp_port = RemotePort},
+ DecodedMsg = (catch tftp_lib:decode_msg(Bin)),
+ print_debug_info(Config2, Req, recv, DecodedMsg),
+ {Config2, DecodedMsg};
+ {udp, Socket, Host, Port, Bin} when is_binary(Bin),
+ Config#config.udp_host =:= Host,
+ Config#config.udp_port =:= Port ->
+ _ = inet:setopts(Socket, [{active, once}]),
+ DecodedMsg = (catch tftp_lib:decode_msg(Bin)),
+ print_debug_info(Config, Req, recv, DecodedMsg),
+ {Config, DecodedMsg};
+ {info, Ref, FromPid} when is_pid(FromPid) ->
+ Type =
+ case Req#tftp_msg_req.local_filename =/= undefined of
+ true -> client;
+ false -> server
+ end,
+ Info = internal_info(Config, Type),
+ _ = reply({ok, Info}, Ref, FromPid),
+ wait_for_msg(Config, Callback, Req);
+ {{change_config, Options}, Ref, FromPid} when is_pid(FromPid) ->
+ case catch tftp_lib:parse_config(Options, Config) of
+ {'EXIT', Reason} ->
+ _ = reply({error, Reason}, Ref, FromPid),
+ wait_for_msg(Config, Callback, Req);
+ Config2 when is_record(Config2, config) ->
+ _ = reply(ok, Ref, FromPid),
+ wait_for_msg(Config2, Callback, Req)
+ end;
+ {system, From, Msg} ->
+ Misc = #sys_misc{module = ?MODULE, function = wait_for_msg, arguments = [Config, Callback, Req]},
+ sys:handle_system_msg(Msg, From, Config#config.parent_pid, ?MODULE, [], Misc);
+ {'EXIT', Pid, _Reason} when Config#config.parent_pid =:= Pid ->
+ Code = undef,
+ Text = "Parent exited.",
+ terminate(Config, Req, ?ERROR(wait_for_msg, Code, Text, Req#tftp_msg_req.filename));
+ Msg when Req#tftp_msg_req.local_filename =/= undefined ->
+ warning_msg(Config, "Client received : ~p", [Msg]),
+ wait_for_msg(Config, Callback, Req);
+ Msg when Req#tftp_msg_req.local_filename =:= undefined ->
+ warning_msg(Config, "Server received : ~p", [Msg]),
+ wait_for_msg(Config, Callback, Req)
+ after Config#config.timeout * 1000 ->
+ print_debug_info(Config, Req, recv, timeout),
+ timeout
+ end.
+
+early_read(Config, Callback, Req, LocalAccess, _NextBlockNo,
+ #prepared{status = Status, next_data = NextData, prev_data = PrevData} = Prepared) ->
+ if
+ Status =/= terminate,
+ LocalAccess =:= read,
+ Callback#callback.block_no =/= undefined,
+ NextData =:= undefined ->
+ case callback(read, Config, Callback, Req) of
+ {undefined, Error} when is_record(Error, tftp_msg_error) ->
+ {undefined, Error};
+ {Callback2, Prepared2} when is_record(Prepared2, prepared)->
+ {Callback2, Prepared2#prepared{prev_data = PrevData}}
+ end;
+ true ->
+ {Callback, Prepared}
+ end.
+
+%%-------------------------------------------------------------------
+%% Callback
+%%-------------------------------------------------------------------
+
+callback(Access, Config, Callback, Req) ->
+ {Callback2, Result} =
+ do_callback(Access, Config, Callback, Req),
+ print_debug_info(Config, Req, call, {Callback2, Result}),
+ {Callback2, Result}.
+
+do_callback(read = Fun, Config, Callback, Req)
+ when is_record(Config, config),
+ is_record(Callback, callback),
+ is_record(Req, tftp_msg_req) ->
+ Args = [Callback#callback.state],
+ NextBlockNo = Callback#callback.block_no + 1,
+ case catch safe_apply(Callback#callback.module, Fun, Args) of
+ {more, Bin, NewState} when is_binary(Bin) ->
+ Count = Callback#callback.count + size(Bin),
+ Callback2 = Callback#callback{state = NewState,
+ block_no = NextBlockNo,
+ count = Count},
+ Prepared = #prepared{status = more,
+ result = undefined,
+ block_no = NextBlockNo,
+ next_data = Bin},
+ verify_count(Config, Callback2, Req, Prepared);
+ {last, Bin, Result} when is_binary(Bin) ->
+ Prepared = #prepared{status = last,
+ result = Result,
+ block_no = NextBlockNo,
+ next_data = Bin},
+ {undefined, Prepared};
+ {error, {Code, Text}} ->
+ Error = #tftp_msg_error{code = Code, text = Text},
+ Prepared = #prepared{status = error,
+ result = Error},
+ {undefined, Prepared};
+ Illegal ->
+ Code = undef,
+ Text = "Internal error. File handler error.",
+ callback({abort, {Code, Text, Illegal}}, Config, Callback, Req)
+ end;
+do_callback({write = Fun, Bin}, Config, Callback, Req)
+ when is_record(Config, config),
+ is_record(Callback, callback),
+ is_record(Req, tftp_msg_req),
+ is_binary(Bin) ->
+ Args = [Bin, Callback#callback.state],
+ NextBlockNo = Callback#callback.block_no + 1,
+ case catch safe_apply(Callback#callback.module, Fun, Args) of
+ {more, NewState} ->
+ Count = Callback#callback.count + size(Bin),
+ Callback2 = Callback#callback{state = NewState,
+ block_no = NextBlockNo,
+ count = Count},
+ Prepared = #prepared{status = more,
+ block_no = NextBlockNo},
+ verify_count(Config, Callback2, Req, Prepared);
+ {last, Result} ->
+ Prepared = #prepared{status = last,
+ result = Result,
+ block_no = NextBlockNo},
+ {undefined, Prepared};
+ {error, {Code, Text}} ->
+ Error = #tftp_msg_error{code = Code, text = Text},
+ Prepared = #prepared{status = error,
+ result = Error},
+ {undefined, Prepared};
+ Illegal ->
+ Code = undef,
+ Text = "Internal error. File handler error.",
+ callback({abort, {Code, Text, Illegal}}, Config, Callback, Req)
+ end;
+do_callback({open, Type}, Config, Callback, Req)
+ when is_record(Config, config),
+ is_record(Callback, callback),
+ is_record(Req, tftp_msg_req) ->
+ {Access, Filename} = local_file_access(Req),
+ {Fun, BlockNo} =
+ case Type of
+ client_prepare -> {prepare, undefined};
+ client_open -> {open, 0};
+ server_open -> {open, 0}
+ end,
+ Mod = Callback#callback.module,
+ Args = [Access,
+ Filename,
+ Req#tftp_msg_req.mode,
+ Req#tftp_msg_req.options,
+ Callback#callback.state],
+ PeerInfo = peer_info(Config),
+ _ = fast_ensure_loaded(Mod),
+ Args2 =
+ case erlang:function_exported(Mod, Fun, length(Args)) of
+ true -> Args;
+ false -> [PeerInfo | Args]
+ end,
+ case catch safe_apply(Mod, Fun, Args2) of
+ {ok, AcceptedOptions, NewState} ->
+ Callback2 = Callback#callback{state = NewState,
+ block_no = BlockNo,
+ count = 0},
+ {Callback2, {ok, AcceptedOptions}};
+ {error, {Code, Text}} ->
+ {undefined, #tftp_msg_error{code = Code, text = Text}};
+ Illegal ->
+ Code = undef,
+ Text = "Internal error. File handler error.",
+ callback({abort, {Code, Text, Illegal}}, Config, Callback, Req)
+ end;
+do_callback({abort, {Code, Text}}, Config, Callback, Req) ->
+ Error = #tftp_msg_error{code = Code, text = Text},
+ do_callback({abort, Error}, Config, Callback, Req);
+do_callback({abort, {Code, Text, Details}}, Config, Callback, Req) ->
+ Error = #tftp_msg_error{code = Code, text = Text, details = Details},
+ do_callback({abort, Error}, Config, Callback, Req);
+do_callback({abort = Fun, #tftp_msg_error{code = Code, text = Text} = Error}, Config, Callback, Req)
+ when is_record(Config, config),
+ is_record(Callback, callback),
+ is_record(Req, tftp_msg_req) ->
+ Args = [Code, Text, Callback#callback.state],
+ catch safe_apply(Callback#callback.module, Fun, Args),
+ {undefined, Error};
+do_callback({abort, Error}, _Config, undefined, _Req) when is_record(Error, tftp_msg_error) ->
+ {undefined, Error}.
+
+peer_info(#config{udp_host = Host, udp_port = Port}) ->
+ if
+ is_tuple(Host), size(Host) =:= 4 ->
+ {inet, tftp_lib:host_to_string(Host), Port};
+ is_tuple(Host), size(Host) =:= 8 ->
+ {inet6, tftp_lib:host_to_string(Host), Port};
+ true ->
+ {undefined, Host, Port}
+ end.
+
+match_callback(Filename, Callbacks) ->
+ if
+ Filename =:= binary ->
+ lookup_callback_mod(tftp_binary, Callbacks);
+ is_binary(Filename) ->
+ lookup_callback_mod(tftp_binary, Callbacks);
+ true ->
+ do_match_callback(Filename, Callbacks)
+ end.
+
+do_match_callback(Filename, [C | Tail]) when is_record(C, callback) ->
+ case catch re:run(Filename, C#callback.internal, [{capture, none}]) of
+ match ->
+ {ok, C};
+ nomatch ->
+ do_match_callback(Filename, Tail);
+ Details ->
+ Code = baduser,
+ Text = "Internal error. File handler not found",
+ {error, #tftp_msg_error{code = Code, text = Text, details = Details}}
+ end;
+do_match_callback(Filename, []) ->
+ Code = baduser,
+ Text = "Internal error. File handler not found",
+ {error, #tftp_msg_error{code = Code, text = Text, details = Filename}}.
+
+lookup_callback_mod(Mod, Callbacks) ->
+ {value, C} = lists:keysearch(Mod, #callback.module, Callbacks),
+ {ok, C}.
+
+verify_count(Config, Callback, Req, Result) ->
+ case Config#config.max_tsize of
+ infinity ->
+ {Callback, Result};
+ Max when Callback#callback.count =< Max ->
+ {Callback, Result};
+ _Max ->
+ Code = enospc,
+ Text = "Too large file.",
+ callback({abort, {Code, Text}}, Config, Callback, Req)
+ end.
+
+%%-------------------------------------------------------------------
+%% Miscellaneous
+%%-------------------------------------------------------------------
+
+internal_info(Config, Type) when is_record(Config, config) ->
+ {ok, ActualPort} = inet:port(Config#config.udp_socket),
+ [
+ {type, Type},
+ {host, tftp_lib:host_to_string(Config#config.udp_host)},
+ {port, Config#config.udp_port},
+ {local_port, ActualPort},
+ {port_policy, Config#config.port_policy},
+ {udp, Config#config.udp_options},
+ {use_tsize, Config#config.use_tsize},
+ {max_tsize, Config#config.max_tsize},
+ {max_conn, Config#config.max_conn},
+ {rejected, Config#config.rejected},
+ {timeout, Config#config.timeout},
+ {polite_ack, Config#config.polite_ack},
+ {debug, Config#config.debug_level},
+ {parent_pid, Config#config.parent_pid}
+ ] ++ Config#config.user_options ++ Config#config.callbacks.
+
+local_file_access(#tftp_msg_req{access = Access,
+ local_filename = Local,
+ filename = Filename}) ->
+ case Local =:= undefined of
+ true ->
+ %% Server side
+ {Access, Filename};
+ false ->
+ %% Client side
+ case Access of
+ read -> {write, Local};
+ write -> {read, Local}
+ end
+ end.
+
+pre_verify_options(Config, Req) ->
+ Options = Req#tftp_msg_req.options,
+ case catch verify_reject(Config, Req, Options) of
+ ok ->
+ case verify_integer("tsize", 0, Config#config.max_tsize, Options) of
+ true ->
+ case verify_integer("blksize", 0, 65464, Options) of
+ true ->
+ ok;
+ false ->
+ {error, {badopt, "Too large blksize"}}
+ end;
+ false ->
+ {error, {badopt, "Too large tsize"}}
+ end;
+ {error, Reason} ->
+ {error, Reason}
+ end.
+
+post_verify_options(Config, Req, NewOptions, Text) ->
+ OldOptions = Req#tftp_msg_req.options,
+ BadOptions =
+ [Key || {Key, _Val} <- NewOptions,
+ not lists:keymember(Key, 1, OldOptions)],
+ case BadOptions =:= [] of
+ true ->
+ Config2 = Config#config{timeout = lookup_timeout(NewOptions)},
+ Req2 = Req#tftp_msg_req{options = NewOptions},
+ {ok, Config2, Req2};
+ false ->
+ {error, {badopt, Text}}
+ end.
+
+verify_reject(Config, Req, Options) ->
+ Access = Req#tftp_msg_req.access,
+ Rejected = Config#config.rejected,
+ case lists:member(Access, Rejected) of
+ true ->
+ {error, {eacces, atom_to_list(Access) ++ " mode not allowed"}};
+ false ->
+ [throw({error, {badopt, Key ++ " not allowed"}}) ||
+ {Key, _} <- Options, lists:member(Key, Rejected)],
+ ok
+ end.
+
+lookup_timeout(Options) ->
+ case lists:keysearch("timeout", 1, Options) of
+ {value, {_, Val}} ->
+ list_to_integer(Val);
+ false ->
+ 3
+ end.
+
+lookup_mode(Options) ->
+ case lists:keysearch("mode", 1, Options) of
+ {value, {_, Val}} ->
+ Val;
+ false ->
+ "octet"
+ end.
+
+verify_integer(Key, Min, Max, Options) ->
+ case lists:keysearch(Key, 1, Options) of
+ {value, {_, Val}} when is_list(Val) ->
+ case catch list_to_integer(Val) of
+ {'EXIT', _} ->
+ false;
+ Int when Int >= Min, is_integer(Min),
+ Max =:= infinity ->
+ true;
+ Int when Int >= Min, is_integer(Min),
+ Int =< Max, is_integer(Max) ->
+ true;
+ _ ->
+ false
+ end;
+ false ->
+ true
+ end.
+
+error_msg(#config{logger = Logger, debug_level = _Level}, F, A) ->
+ safe_apply(Logger, error_msg, [F, A]).
+
+warning_msg(#config{logger = Logger, debug_level = Level}, F, A) ->
+ case Level of
+ none -> ok;
+ error -> ok;
+ _ -> safe_apply(Logger, warning_msg, [F, A])
+ end.
+
+info_msg(#config{logger = Logger}, F, A) ->
+ safe_apply(Logger, info_msg, [F, A]).
+
+safe_apply(Mod, Fun, Args) ->
+ _ = fast_ensure_loaded(Mod),
+ apply(Mod, Fun, Args).
+
+fast_ensure_loaded(Mod) ->
+ case erlang:function_exported(Mod, module_info, 0) of
+ true ->
+ ok;
+ false ->
+ Res = code:load_file(Mod),
+ %% io:format("tftp: code:load_file(~p) -> ~p\n", [Mod, Res]), %% XXX
+ Res
+ end.
+
+print_debug_info(#config{debug_level = Level} = Config, Who, Where, Data) ->
+ if
+ Level =:= none ->
+ ok;
+ is_record(Data, error) ->
+ do_print_debug_info(Config, Who, Where, Data);
+ Level =:= warning ->
+ ok;
+ Level =:= error ->
+ ok;
+ Level =:= all ->
+ do_print_debug_info(Config, Who, Where, Data);
+ Where =:= open ->
+ do_print_debug_info(Config, Who, Where, Data);
+ Where =:= close ->
+ do_print_debug_info(Config, Who, Where, Data);
+ Level =:= brief ->
+ ok;
+ Where =/= recv, Where =/= send ->
+ ok;
+ is_record(Data, tftp_msg_data), Level =:= normal ->
+ ok;
+ is_record(Data, tftp_msg_ack), Level =:= normal ->
+ ok;
+ true ->
+ do_print_debug_info(Config, Who, Where, Data)
+ end.
+
+do_print_debug_info(Config, Who, Where, #tftp_msg_data{data = Bin} = Msg) when is_binary(Bin) ->
+ Msg2 = Msg#tftp_msg_data{data = {bytes, size(Bin)}},
+ do_print_debug_info(Config, Who, Where, Msg2);
+do_print_debug_info(Config, Who, Where, #tftp_msg_req{local_filename = Filename} = Msg) when is_binary(Filename) ->
+ Msg2 = Msg#tftp_msg_req{local_filename = binary},
+ do_print_debug_info(Config, Who, Where, Msg2);
+do_print_debug_info(Config, Who, Where, Data) ->
+ Local =
+ case catch inet:port(Config#config.udp_socket) of
+ {'EXIT', _Reason} ->
+ 0;
+ {ok, Port} ->
+ Port
+ end,
+ %% Remote = Config#config.udp_port,
+ PeerInfo = lists:flatten(io_lib:format("~p", [peer_info(Config)])),
+ Side =
+ if
+ is_record(Who, tftp_msg_req),
+ Who#tftp_msg_req.local_filename =/= undefined ->
+ client;
+ is_record(Who, tftp_msg_req),
+ Who#tftp_msg_req.local_filename =:= undefined ->
+ server;
+ is_atom(Who) ->
+ Who
+ end,
+ case {Where, Data} of
+ {_, #error{where = Where, code = Code, text = Text, filename = Filename}} ->
+ do_format(Config, Side, Local, "error ~s ->\n\t~p ~p\n\t~p ~p: ~s\n",
+ [PeerInfo, self(), Filename, Where, Code, Text]);
+ {open, #tftp_msg_req{filename = Filename}} ->
+ do_format(Config, Side, Local, "open ~s ->\n\t~p ~p\n",
+ [PeerInfo, self(), Filename]);
+ {close, #tftp_msg_req{filename = Filename}} ->
+ do_format(Config, Side, Local, "close ~s ->\n\t~p ~p\n",
+ [PeerInfo, self(), Filename]);
+ {recv, _} ->
+ do_format(Config, Side, Local, "recv ~s <-\n\t~p\n",
+ [PeerInfo, Data]);
+ {send, _} ->
+ do_format(Config, Side, Local, "send ~s ->\n\t~p\n",
+ [PeerInfo, Data]);
+ {match, _} when is_record(Data, callback) ->
+ Mod = Data#callback.module,
+ State = Data#callback.state,
+ do_format(Config, Side, Local, "match ~s ~p =>\n\t~p\n",
+ [PeerInfo, Mod, State]);
+ {call, _} ->
+ case Data of
+ {Callback, _Result} when is_record(Callback, callback) ->
+ Mod = Callback#callback.module,
+ State = Callback#callback.state,
+ do_format(Config, Side, Local, "call ~s ~p =>\n\t~p\n",
+ [PeerInfo, Mod, State]);
+ {undefined, Result} ->
+ do_format(Config, Side, Local, "call ~s result =>\n\t~p\n",
+ [PeerInfo, Result])
+ end
+ end.
+
+do_format(Config, Side, Local, Format, Args) ->
+ info_msg(Config, "~p(~p): " ++ Format, [Side, Local | Args]).
+
+%%-------------------------------------------------------------------
+%% System upgrade
+%%-------------------------------------------------------------------
+
+system_continue(_Parent, _Debug, #sys_misc{module = Mod, function = Fun, arguments = Args}) ->
+ apply(Mod, Fun, Args);
+system_continue(Parent, Debug, {Fun, Args}) ->
+ %% Handle upgrade from old releases. Please, remove this clause in next release.
+ system_continue(Parent, Debug, #sys_misc{module = ?MODULE, function = Fun, arguments = Args}).
+
+-spec system_terminate(_, _, _, #sys_misc{} | {_, _}) -> no_return().
+
+system_terminate(Reason, _Parent, _Debug, #sys_misc{}) ->
+ exit(Reason);
+system_terminate(Reason, Parent, Debug, {Fun, Args}) ->
+ %% Handle upgrade from old releases. Please, remove this clause in next release.
+ system_terminate(Reason, Parent, Debug, #sys_misc{module = ?MODULE, function = Fun, arguments = Args}).
+
+system_code_change({Fun, Args}, _Module, _OldVsn, _Extra) ->
+ {ok, {Fun, Args}}.
diff --git a/lib/tftp/src/tftp_file.erl b/lib/tftp/src/tftp_file.erl
new file mode 100644
index 0000000000..5922fc9418
--- /dev/null
+++ b/lib/tftp/src/tftp_file.erl
@@ -0,0 +1,390 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+%%%-------------------------------------------------------------------
+%%% File : tft_file.erl
+%%% Author : Hakan Mattsson <[email protected]>
+%%% Description :
+%%%
+%%% Created : 24 May 2004 by Hakan Mattsson <[email protected]>
+%%%-------------------------------------------------------------------
+
+-module(tftp_file).
+
+%%%-------------------------------------------------------------------
+%%% Interface
+%%%-------------------------------------------------------------------
+
+-behaviour(tftp).
+
+-export([prepare/6, open/6, read/1, write/2, abort/3]).
+
+%%%-------------------------------------------------------------------
+%%% Defines
+%%%-------------------------------------------------------------------
+
+-include_lib("kernel/include/file.hrl").
+
+-record(initial,
+ {filename,
+ is_native_ascii}).
+
+-record(state,
+ {access,
+ filename,
+ is_native_ascii,
+ is_network_ascii,
+ root_dir,
+ options,
+ blksize,
+ fd,
+ count,
+ buffer}).
+
+%%-------------------------------------------------------------------
+%% prepare(Peer, Access, Filename, Mode, SuggestedOptions, InitialState) ->
+%% {ok, AcceptedOptions, NewState} | {error, Code, Text}
+%%
+%% Peer = {PeerType, PeerHost, PeerPort}
+%% PeerType = inet | inet6
+%% PeerHost = ip_address()
+%% PeerPort = integer()
+%% Acess = read | write
+%% Filename = string()
+%% Mode = string()
+%% SuggestedOptions = [{Key, Value}]
+%% AcceptedOptions = [{Key, Value}]
+%% Key = string()
+%% Value = string()
+%% InitialState = [] | [{root_dir, string()}]
+%% NewState = term()
+%% Code = undef | enoent | eacces | enospc |
+%% badop | eexist | baduser | badopt |
+%% integer()
+%% Text = string()
+%%
+%% Prepares open of a file on the client side.
+%%
+%% Will be followed by a call to open/4 before any read/write access
+%% is performed. The AcceptedOptions will be sent to the server which
+%% will reply with those options that it accepts. The options that are
+%% accepted by the server will be forwarded to open/4 as SuggestedOptions.
+%%
+%% No new options may be added, but the ones that are present as
+%% SuggestedOptions may be omitted or replaced with new values
+%% in the AcceptedOptions.
+%%-------------------------------------------------------------------
+
+prepare(_Peer, Access, Filename, Mode, SuggestedOptions, Initial) when is_list(Initial) ->
+ %% Client side
+ case catch handle_options(Access, Filename, Mode, SuggestedOptions, Initial) of
+ {ok, Filename2, IsNativeAscii, IsNetworkAscii, AcceptedOptions} ->
+ State = #state{access = Access,
+ filename = Filename2,
+ is_native_ascii = IsNativeAscii,
+ is_network_ascii = IsNetworkAscii,
+ options = AcceptedOptions,
+ blksize = lookup_blksize(AcceptedOptions),
+ count = 0,
+ buffer = []},
+ {ok, AcceptedOptions, State};
+ {error, {Code, Text}} ->
+ {error, {Code, Text}}
+ end.
+
+%% ---------------------------------------------------------
+%% open(Peer, Access, Filename, Mode, SuggestedOptions, State) ->
+%% {ok, AcceptedOptions, NewState} | {error, Code, Text}
+%%
+%% Peer = {PeerType, PeerHost, PeerPort}
+%% PeerType = inet | inet6
+%% PeerHost = ip_address()
+%% PeerPort = integer()
+%% Acess = read | write
+%% Filename = string()
+%% Mode = string()
+%% SuggestedOptions = [{Key, Value}]
+%% AcceptedOptions = [{Key, Value}]
+%% Key = string()
+%% Value = string()
+%% State = InitialState | #state{}
+%% InitialState = [] | [{root_dir, string()}]
+%% NewState = term()
+%% Code = undef | enoent | eacces | enospc |
+%% badop | eexist | baduser | badopt |
+%% integer()
+%% Text = string()
+%%
+%% Opens a file for read or write access.
+%%
+%% On the client side where the open/4 call has been preceeded by a
+%% call to prepare/4, all options must be accepted or rejected.
+%% On the server side, where there are no preceeding prepare/4 call,
+%% noo new options may be added, but the ones that are present as
+%% SuggestedOptions may be omitted or replaced with new values
+%% in the AcceptedOptions.
+%%-------------------------------------------------------------------
+
+open(Peer, Access, Filename, Mode, SuggestedOptions, Initial) when is_list(Initial) ->
+ %% Server side
+ case prepare(Peer, Access, Filename, Mode, SuggestedOptions, Initial) of
+ {ok, AcceptedOptions, State} ->
+ open(Peer, Access, Filename, Mode, AcceptedOptions, State);
+ {error, {Code, Text}} ->
+ {error, {Code, Text}}
+ end;
+open(_Peer, Access, Filename, Mode, NegotiatedOptions, State) when is_record(State, state) ->
+ %% Both sides
+ case catch handle_options(Access, Filename, Mode, NegotiatedOptions, State) of
+ {ok, _Filename2, _IsNativeAscii, _IsNetworkAscii, Options}
+ when Options =:= NegotiatedOptions ->
+ do_open(State);
+ {error, {Code, Text}} ->
+ {error, {Code, Text}}
+ end;
+open(Peer, Access, Filename, Mode, NegotiatedOptions, State) ->
+ %% Handle upgrade from old releases. Please, remove this clause in next release.
+ State2 = upgrade_state(State),
+ open(Peer, Access, Filename, Mode, NegotiatedOptions, State2).
+
+do_open(State) when is_record(State, state) ->
+ case file:open(State#state.filename, file_options(State)) of
+ {ok, Fd} ->
+ {ok, State#state.options, State#state{fd = Fd}};
+ {error, Reason} when is_atom(Reason) ->
+ {error, file_error(Reason)}
+ end.
+
+file_options(State) ->
+ case State#state.access of
+ read -> [read, read_ahead, raw, binary];
+ write -> [write, delayed_write, raw, binary]
+ end.
+
+file_error(Reason) when is_atom(Reason) ->
+ Details = file:format_error(Reason),
+ case Reason of
+ eexist -> {Reason, Details};
+ enoent -> {Reason, Details};
+ eacces -> {Reason, Details};
+ eperm -> {eacces, Details};
+ enospc -> {Reason, Details};
+ _ -> {undef, Details ++ " (" ++ atom_to_list(Reason) ++ ")"}
+ end.
+
+%%-------------------------------------------------------------------
+%% read(State) ->
+%% {more, Bin, NewState} | {last, Bin, FileSize} | {error, {Code, Text}}
+%%
+%% State = term()
+%% NewState = term()
+%% Bin = binary()
+%% FileSize = integer()
+%% Code = undef | enoent | eacces | enospc |
+%% badop | eexist | baduser | badopt |
+%% integer()
+%% Text = string()
+%%
+%% Reads a chunk from the file
+%%
+%% The file is automatically closed when the last chunk is read.
+%%-------------------------------------------------------------------
+
+read(#state{access = read} = State) ->
+ BlkSize = State#state.blksize,
+ case file:read(State#state.fd, BlkSize) of
+ {ok, Bin} when is_binary(Bin), size(Bin) =:= BlkSize ->
+ Count = State#state.count + size(Bin),
+ {more, Bin, State#state{count = Count}};
+ {ok, Bin} when is_binary(Bin), size(Bin) < BlkSize ->
+ _ = file:close(State#state.fd),
+ Count = State#state.count + size(Bin),
+ {last, Bin, Count};
+ eof ->
+ {last, <<>>, State#state.count};
+ {error, Reason} ->
+ _ = file:close(State#state.fd),
+ {error, file_error(Reason)}
+ end;
+read(State) ->
+ %% Handle upgrade from old releases. Please, remove this clause in next release.
+ State2 = upgrade_state(State),
+ read(State2).
+
+%%-------------------------------------------------------------------
+%% write(Bin, State) ->
+%% {more, NewState} | {last, FileSize} | {error, {Code, Text}}
+%%
+%% State = term()
+%% NewState = term()
+%% Bin = binary()
+%% FileSize = integer()
+%% Code = undef | enoent | eacces | enospc |
+%% badop | eexist | baduser | badopt |
+%% integer()
+%% Text = string()
+%%
+%% Writes a chunk to the file
+%%
+%% The file is automatically closed when the last chunk is written
+%%-------------------------------------------------------------------
+
+write(Bin, #state{access = write} = State) when is_binary(Bin) ->
+ Size = size(Bin),
+ BlkSize = State#state.blksize,
+ case file:write(State#state.fd, Bin) of
+ ok when Size =:= BlkSize->
+ Count = State#state.count + Size,
+ {more, State#state{count = Count}};
+ ok when Size < BlkSize->
+ _ = file:close(State#state.fd),
+ Count = State#state.count + Size,
+ {last, Count};
+ {error, Reason} ->
+ _ = file:close(State#state.fd),
+ _ = file:delete(State#state.filename),
+ {error, file_error(Reason)}
+ end;
+write(Bin, State) ->
+ %% Handle upgrade from old releases. Please, remove this clause in next release.
+ State2 = upgrade_state(State),
+ write(Bin, State2).
+
+%%-------------------------------------------------------------------
+%% abort(Code, Text, State) -> ok
+%%
+%% State = term()
+%% Code = undef | enoent | eacces | enospc |
+%% badop | eexist | baduser | badopt |
+%% badblk | integer()
+%% Text = string()
+%%
+%% Aborts the file transfer
+%%-------------------------------------------------------------------
+
+abort(_Code, _Text, #state{fd = Fd, access = Access} = State) ->
+ _ = file:close(Fd),
+ case Access of
+ write ->
+ ok = file:delete(State#state.filename);
+ read ->
+ ok
+ end.
+
+%%-------------------------------------------------------------------
+%% Process options
+%%-------------------------------------------------------------------
+
+handle_options(Access, Filename, Mode, Options, Initial) ->
+ I = #initial{filename = Filename, is_native_ascii = is_native_ascii()},
+ {Filename2, IsNativeAscii} = handle_initial(Initial, I),
+ IsNetworkAscii = handle_mode(Mode, IsNativeAscii),
+ Options2 = do_handle_options(Access, Filename2, Options),
+ {ok, Filename2, IsNativeAscii, IsNetworkAscii, Options2}.
+
+handle_mode(Mode, IsNativeAscii) ->
+ case Mode of
+ "netascii" when IsNativeAscii =:= true -> true;
+ "octet" -> false;
+ _ -> throw({error, {badop, "Illegal mode " ++ Mode}})
+ end.
+
+handle_initial([{root_dir, Dir} | Initial], I) ->
+ case catch filename_join(Dir, I#initial.filename) of
+ {'EXIT', _} ->
+ throw({error, {badop, "Internal error. root_dir is not a string"}});
+ Filename2 ->
+ handle_initial(Initial, I#initial{filename = Filename2})
+ end;
+handle_initial([{native_ascii, Bool} | Initial], I) ->
+ case Bool of
+ true -> handle_initial(Initial, I#initial{is_native_ascii = true});
+ false -> handle_initial(Initial, I#initial{is_native_ascii = false})
+ end;
+handle_initial([], I) when is_record(I, initial) ->
+ {I#initial.filename, I#initial.is_native_ascii};
+handle_initial(State, _) when is_record(State, state) ->
+ {State#state.filename, State#state.is_native_ascii}.
+
+filename_join(Dir, Filename) ->
+ case filename:pathtype(Filename) of
+ absolute ->
+ [_ | RelFilename] = filename:split(Filename),
+ filename:join([Dir, RelFilename]);
+ _ ->
+ filename:join([Dir, Filename])
+ end.
+
+do_handle_options(Access, Filename, [{Key, Val} | T]) ->
+ case Key of
+ "tsize" ->
+ case Access of
+ read when Val =:= "0" ->
+ case file:read_file_info(Filename) of
+ {ok, FI} ->
+ Tsize = integer_to_list(FI#file_info.size),
+ [{Key, Tsize} | do_handle_options(Access, Filename, T)];
+ {error, _} ->
+ do_handle_options(Access, Filename, T)
+ end;
+ _ ->
+ handle_integer(Access, Filename, Key, Val, T, 0, infinity)
+ end;
+ "blksize" ->
+ handle_integer(Access, Filename, Key, Val, T, 8, 65464);
+ "timeout" ->
+ handle_integer(Access, Filename, Key, Val, T, 1, 255);
+ _ ->
+ do_handle_options(Access, Filename, T)
+ end;
+do_handle_options(_Access, _Filename, []) ->
+ [].
+
+
+handle_integer(Access, Filename, Key, Val, Options, Min, Max) ->
+ case catch list_to_integer(Val) of
+ {'EXIT', _} ->
+ do_handle_options(Access, Filename, Options);
+ Int when Int >= Min, Int =< Max ->
+ [{Key, Val} | do_handle_options(Access, Filename, Options)];
+ Int when Int >= Min, Max =:= infinity ->
+ [{Key, Val} | do_handle_options(Access, Filename, Options)];
+ _Int ->
+ throw({error, {badopt, "Illegal " ++ Key ++ " value " ++ Val}})
+ end.
+
+lookup_blksize(Options) ->
+ case lists:keysearch("blksize", 1, Options) of
+ {value, {_, Val}} ->
+ list_to_integer(Val);
+ false ->
+ 512
+ end.
+
+is_native_ascii() ->
+ case os:type() of
+ {win32, _} -> true;
+ _ -> false
+ end.
+
+%% Handle upgrade from old releases. Please, remove this function in next release.
+upgrade_state({state, Access, Filename, RootDir, Options, BlkSize, Fd, Count, Buffer}) ->
+ {state, Access, Filename, false, false, RootDir, Options, BlkSize, Fd, Count, Buffer}.
diff --git a/lib/tftp/src/tftp_lib.erl b/lib/tftp/src/tftp_lib.erl
new file mode 100644
index 0000000000..407a273f58
--- /dev/null
+++ b/lib/tftp/src/tftp_lib.erl
@@ -0,0 +1,474 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+%%%-------------------------------------------------------------------
+%%% File : tftp_lib.erl
+%%% Author : Hakan Mattsson <[email protected]>
+%%% Description : Option parsing, decode, encode etc.
+%%%
+%%% Created : 18 May 2004 by Hakan Mattsson <[email protected]>
+%%%-------------------------------------------------------------------
+
+-module(tftp_lib).
+
+%%-------------------------------------------------------------------
+%% Interface
+%%-------------------------------------------------------------------
+
+%% application internal functions
+-export([
+ parse_config/1,
+ parse_config/2,
+ decode_msg/1,
+ encode_msg/1,
+ replace_val/3,
+ to_lower/1,
+ host_to_string/1,
+ add_default_callbacks/1
+ ]).
+
+%%-------------------------------------------------------------------
+%% Defines
+%%-------------------------------------------------------------------
+
+-include("tftp.hrl").
+
+-define(LOWER(Char),
+ if
+ Char >= $A, Char =< $Z ->
+ Char - ($A - $a);
+ true ->
+ Char
+ end).
+
+%%-------------------------------------------------------------------
+%% Config
+%%-------------------------------------------------------------------
+
+parse_config(Options) ->
+ parse_config(Options, #config{}).
+
+parse_config(Options, Config) ->
+ do_parse_config(Options, Config).
+
+do_parse_config([{Key, Val} | Tail], Config) when is_record(Config, config) ->
+ case Key of
+ debug ->
+ if
+ Val =:= 0; Val =:= none ->
+ do_parse_config(Tail, Config#config{debug_level = none});
+ Val =:= 1; Val =:= error ->
+ do_parse_config(Tail, Config#config{debug_level = error});
+ Val =:= 2; Val =:= warning ->
+ do_parse_config(Tail, Config#config{debug_level = warning});
+ Val =:= 3; Val =:= brief ->
+ do_parse_config(Tail, Config#config{debug_level = brief});
+ Val =:= 4; Val =:= normal ->
+ do_parse_config(Tail, Config#config{debug_level = normal});
+ Val =:= 5; Val =:= verbose ->
+ do_parse_config(Tail, Config#config{debug_level = verbose});
+ Val =:= 6; Val =:= all ->
+ do_parse_config(Tail, Config#config{debug_level = all});
+ true ->
+ exit({badarg, {Key, Val}})
+ end;
+ host ->
+ if
+ is_list(Val) ->
+ do_parse_config(Tail, Config#config{udp_host = Val});
+ is_tuple(Val), size(Val) =:= 4 ->
+ do_parse_config(Tail, Config#config{udp_host = Val});
+ is_tuple(Val), size(Val) =:= 8 ->
+ do_parse_config(Tail, Config#config{udp_host = Val});
+ true ->
+ exit({badarg, {Key, Val}})
+ end;
+ port ->
+ if
+ is_integer(Val), Val >= 0 ->
+ Config2 = Config#config{udp_port = Val, udp_options = Config#config.udp_options},
+ do_parse_config(Tail, Config2);
+ true ->
+ exit({badarg, {Key, Val}})
+ end;
+ port_policy ->
+ case Val of
+ random ->
+ do_parse_config(Tail, Config#config{port_policy = Val});
+ 0 ->
+ do_parse_config(Tail, Config#config{port_policy = random});
+ MinMax when is_integer(MinMax), MinMax > 0 ->
+ do_parse_config(Tail, Config#config{port_policy = {range, MinMax, MinMax}});
+ {range, Min, Max} when Max >= Min,
+ is_integer(Min), Min > 0,
+ is_integer(Max), Max > 0 ->
+ do_parse_config(Tail, Config#config{port_policy = Val});
+ true ->
+ exit({badarg, {Key, Val}})
+ end;
+ udp when is_list(Val) ->
+ Fun =
+ fun({K, V}, List) when K /= active ->
+ replace_val(K, V, List);
+ (V, List) when V /= list, V /= binary ->
+ List ++ [V];
+ (V, _List) ->
+ exit({badarg, {udp, [V]}})
+ end,
+ UdpOptions = lists:foldl(Fun, Config#config.udp_options, Val),
+ do_parse_config(Tail, Config#config{udp_options = UdpOptions});
+ use_tsize ->
+ case Val of
+ true ->
+ do_parse_config(Tail, Config#config{use_tsize = Val});
+ false ->
+ do_parse_config(Tail, Config#config{use_tsize = Val});
+ _ ->
+ exit({badarg, {Key, Val}})
+ end;
+ max_tsize ->
+ if
+ Val =:= infinity ->
+ do_parse_config(Tail, Config#config{max_tsize = Val});
+ is_integer(Val), Val >= 0 ->
+ do_parse_config(Tail, Config#config{max_tsize = Val});
+ true ->
+ exit({badarg, {Key, Val}})
+ end;
+ max_conn ->
+ if
+ Val =:= infinity ->
+ do_parse_config(Tail, Config#config{max_conn = Val});
+ is_integer(Val), Val > 0 ->
+ do_parse_config(Tail, Config#config{max_conn = Val});
+ true ->
+ exit({badarg, {Key, Val}})
+ end;
+ _ when is_list(Key), is_list(Val) ->
+ Key2 = to_lower(Key),
+ Val2 = to_lower(Val),
+ TftpOptions = replace_val(Key2, Val2, Config#config.user_options),
+ do_parse_config(Tail, Config#config{user_options = TftpOptions});
+ reject ->
+ case Val of
+ read ->
+ Rejected = [Val | Config#config.rejected],
+ do_parse_config(Tail, Config#config{rejected = Rejected});
+ write ->
+ Rejected = [Val | Config#config.rejected],
+ do_parse_config(Tail, Config#config{rejected = Rejected});
+ _ when is_list(Val) ->
+ Rejected = [Val | Config#config.rejected],
+ do_parse_config(Tail, Config#config{rejected = Rejected});
+ _ ->
+ exit({badarg, {Key, Val}})
+ end;
+ callback ->
+ case Val of
+ {RegExp, Mod, State} when is_list(RegExp), is_atom(Mod) ->
+ case re:compile(RegExp) of
+ {ok, Internal} ->
+ Callback = #callback{regexp = RegExp,
+ internal = Internal,
+ module = Mod,
+ state = State},
+ Callbacks = Config#config.callbacks ++ [Callback],
+ do_parse_config(Tail, Config#config{callbacks = Callbacks});
+ {error, Reason} ->
+ exit({badarg, {Key, Val}, Reason})
+ end;
+ _ ->
+ exit({badarg, {Key, Val}})
+ end;
+ logger ->
+ if
+ is_atom(Val) ->
+ do_parse_config(Tail, Config#config{logger = Val});
+ true ->
+ exit({badarg, {Key, Val}})
+ end;
+ max_retries ->
+ if
+ is_integer(Val), Val > 0 ->
+ do_parse_config(Tail, Config#config{max_retries = Val});
+ true ->
+ exit({badarg, {Key, Val}})
+ end;
+ _ ->
+ exit({badarg, {Key, Val}})
+ end;
+do_parse_config([], #config{udp_host = Host,
+ udp_options = UdpOptions,
+ user_options = UserOptions,
+ callbacks = Callbacks} = Config) ->
+ IsInet6 = lists:member(inet6, UdpOptions),
+ IsInet = lists:member(inet, UdpOptions),
+ Host2 =
+ if
+ (IsInet and not IsInet6); (not IsInet and not IsInet6) ->
+ case inet:getaddr(Host, inet) of
+ {ok, Addr} ->
+ Addr;
+ {error, Reason} ->
+ exit({badarg, {host, Reason}})
+ end;
+ (IsInet6 and not IsInet) ->
+ case inet:getaddr(Host, inet6) of
+ {ok, Addr} ->
+ Addr;
+ {error, Reason} ->
+ exit({badarg, {host, Reason}})
+ end;
+ true ->
+ %% Conflicting options
+ exit({badarg, {udp, [inet]}})
+ end,
+ UdpOptions2 = lists:reverse(UdpOptions),
+ TftpOptions = lists:reverse(UserOptions),
+ Callbacks2 = add_default_callbacks(Callbacks),
+ Config#config{udp_host = Host2,
+ udp_options = UdpOptions2,
+ user_options = TftpOptions,
+ callbacks = Callbacks2};
+do_parse_config(Options, Config) when is_record(Config, config) ->
+ exit({badarg, Options}).
+
+add_default_callbacks(Callbacks) ->
+ RegExp = "",
+ {ok, Internal} = re:compile(RegExp),
+ File = #callback{regexp = RegExp,
+ internal = Internal,
+ module = tftp_file,
+ state = []},
+ Bin = #callback{regexp = RegExp,
+ internal = Internal,
+ module = tftp_binary,
+ state = []},
+ Callbacks ++ [File, Bin].
+
+host_to_string(Host) ->
+ case Host of
+ String when is_list(String) ->
+ String;
+ {A1, A2, A3, A4} -> % inet
+ lists:concat([A1, ".", A2, ".", A3, ".",A4]);
+ {A1, A2, A3, A4, A5, A6, A7, A8} -> % inet6
+ lists:concat([
+ int16_to_hex(A1), "::",
+ int16_to_hex(A2), "::",
+ int16_to_hex(A3), "::",
+ int16_to_hex(A4), "::",
+ int16_to_hex(A5), "::",
+ int16_to_hex(A6), "::",
+ int16_to_hex(A7), "::",
+ int16_to_hex(A8)
+ ])
+ end.
+
+int16_to_hex(0) ->
+ [$0];
+int16_to_hex(I) ->
+ N1 = ((I bsr 8) band 16#ff),
+ N2 = (I band 16#ff),
+ [code_character(N1 div 16), code_character(N1 rem 16),
+ code_character(N2 div 16), code_character(N2 rem 16)].
+
+code_character(N) when N < 10 ->
+ $0 + N;
+code_character(N) ->
+ $A + (N - 10).
+
+%%-------------------------------------------------------------------
+%% Decode
+%%-------------------------------------------------------------------
+
+decode_msg(Bin) when is_binary(Bin) ->
+ case Bin of
+ <<?TFTP_OPCODE_RRQ:16/integer, Tail/binary>> ->
+ case decode_strings(Tail, [keep_case, lower_case]) of
+ [Filename, Mode | Strings] ->
+ Options = decode_options(Strings),
+ #tftp_msg_req{access = read,
+ filename = Filename,
+ mode = to_lower(Mode),
+ options = Options};
+ [_Filename | _Strings] ->
+ exit(#tftp_msg_error{code = undef,
+ text = "Missing mode"});
+ _ ->
+ exit(#tftp_msg_error{code = undef,
+ text = "Missing filename"})
+ end;
+ <<?TFTP_OPCODE_WRQ:16/integer, Tail/binary>> ->
+ case decode_strings(Tail, [keep_case, lower_case]) of
+ [Filename, Mode | Strings] ->
+ Options = decode_options(Strings),
+ #tftp_msg_req{access = write,
+ filename = Filename,
+ mode = to_lower(Mode),
+ options = Options};
+ [_Filename | _Strings] ->
+ exit(#tftp_msg_error{code = undef,
+ text = "Missing mode"});
+ _ ->
+ exit(#tftp_msg_error{code = undef,
+ text = "Missing filename"})
+ end;
+ <<?TFTP_OPCODE_DATA:16/integer, SeqNo:16/integer, Data/binary>> ->
+ #tftp_msg_data{block_no = SeqNo, data = Data};
+ <<?TFTP_OPCODE_ACK:16/integer, SeqNo:16/integer>> ->
+ #tftp_msg_ack{block_no = SeqNo};
+ <<?TFTP_OPCODE_ERROR:16/integer, ErrorCode:16/integer, Tail/binary>> ->
+ case decode_strings(Tail, [keep_case]) of
+ [ErrorText] ->
+ ErrorCode2 = decode_error_code(ErrorCode),
+ #tftp_msg_error{code = ErrorCode2,
+ text = ErrorText};
+ _ ->
+ exit(#tftp_msg_error{code = undef,
+ text = "Trailing garbage"})
+ end;
+ <<?TFTP_OPCODE_OACK:16/integer, Tail/binary>> ->
+ Strings = decode_strings(Tail, [lower_case]),
+ Options = decode_options(Strings),
+ #tftp_msg_oack{options = Options};
+ _ ->
+ exit(#tftp_msg_error{code = undef,
+ text = "Invalid syntax"})
+ end.
+
+decode_strings(Bin, Cases) when is_binary(Bin), is_list(Cases) ->
+ do_decode_strings(Bin, Cases, []).
+
+do_decode_strings(<<>>, _Cases, Strings) ->
+ lists:reverse(Strings);
+do_decode_strings(Bin, [Case | Cases], Strings) ->
+ {String, Tail} = decode_string(Bin, Case, []),
+ if
+ Cases =:= [] ->
+ do_decode_strings(Tail, [Case], [String | Strings]);
+ true ->
+ do_decode_strings(Tail, Cases, [String | Strings])
+ end.
+
+decode_string(<<Char:8/integer, Tail/binary>>, Case, String) ->
+ if
+ Char =:= 0 ->
+ {lists:reverse(String), Tail};
+ Case =:= keep_case ->
+ decode_string(Tail, Case, [Char | String]);
+ Case =:= lower_case ->
+ Char2 = ?LOWER(Char),
+ decode_string(Tail, Case, [Char2 | String])
+ end;
+decode_string(<<>>, _Case, _String) ->
+ exit(#tftp_msg_error{code = undef, text = "Trailing null missing"}).
+
+decode_options([Key, Value | Strings]) ->
+ [{to_lower(Key), Value} | decode_options(Strings)];
+decode_options([]) ->
+ [].
+
+decode_error_code(Int) ->
+ case Int of
+ ?TFTP_ERROR_UNDEF -> undef;
+ ?TFTP_ERROR_ENOENT -> enoent;
+ ?TFTP_ERROR_EACCES -> eacces;
+ ?TFTP_ERROR_ENOSPC -> enospc;
+ ?TFTP_ERROR_BADOP -> badop;
+ ?TFTP_ERROR_BADBLK -> badblk;
+ ?TFTP_ERROR_EEXIST -> eexist;
+ ?TFTP_ERROR_BADUSER -> baduser;
+ ?TFTP_ERROR_BADOPT -> badopt;
+ Int when is_integer(Int), Int >= 0, Int =< 65535 -> Int;
+ _ -> exit(#tftp_msg_error{code = undef, text = "Error code outside range."})
+ end.
+
+%%-------------------------------------------------------------------
+%% Encode
+%%-------------------------------------------------------------------
+
+encode_msg(#tftp_msg_req{access = Access,
+ filename = Filename,
+ mode = Mode,
+ options = Options}) ->
+ OpCode = case Access of
+ read -> ?TFTP_OPCODE_RRQ;
+ write -> ?TFTP_OPCODE_WRQ
+ end,
+ [
+ <<OpCode:16/integer>>,
+ Filename,
+ 0,
+ Mode,
+ 0,
+ [[Key, 0, Val, 0] || {Key, Val} <- Options]
+ ];
+encode_msg(#tftp_msg_data{block_no = BlockNo, data = Data}) when BlockNo =< 65535 ->
+ [
+ <<?TFTP_OPCODE_DATA:16/integer, BlockNo:16/integer>>,
+ Data
+ ];
+encode_msg(#tftp_msg_ack{block_no = BlockNo}) when BlockNo =< 65535 ->
+ <<?TFTP_OPCODE_ACK:16/integer, BlockNo:16/integer>>;
+encode_msg(#tftp_msg_error{code = Code, text = Text}) ->
+ IntCode = encode_error_code(Code),
+ [
+ <<?TFTP_OPCODE_ERROR:16/integer, IntCode:16/integer>>,
+ Text,
+ 0
+ ];
+encode_msg(#tftp_msg_oack{options = Options}) ->
+ [
+ <<?TFTP_OPCODE_OACK:16/integer>>,
+ [[Key, 0, Val, 0] || {Key, Val} <- Options]
+ ].
+
+encode_error_code(Code) ->
+ case Code of
+ undef -> ?TFTP_ERROR_UNDEF;
+ enoent -> ?TFTP_ERROR_ENOENT;
+ eacces -> ?TFTP_ERROR_EACCES;
+ enospc -> ?TFTP_ERROR_ENOSPC;
+ badop -> ?TFTP_ERROR_BADOP;
+ badblk -> ?TFTP_ERROR_BADBLK;
+ eexist -> ?TFTP_ERROR_EEXIST;
+ baduser -> ?TFTP_ERROR_BADUSER;
+ badopt -> ?TFTP_ERROR_BADOPT;
+ Int when is_integer(Int), Int >= 0, Int =< 65535 -> Int
+ end.
+
+%%-------------------------------------------------------------------
+%% Miscellaneous
+%%-------------------------------------------------------------------
+
+replace_val(Key, Val, List) ->
+ case lists:keysearch(Key, 1, List) of
+ false ->
+ List ++ [{Key, Val}];
+ {value, {_, OldVal}} when OldVal =:= Val ->
+ List;
+ {value, {_, _}} ->
+ lists:keyreplace(Key, 1, List, {Key, Val})
+ end.
+
+to_lower(Chars) ->
+ [?LOWER(Char) || Char <- Chars].
diff --git a/lib/tftp/src/tftp_logger.erl b/lib/tftp/src/tftp_logger.erl
new file mode 100644
index 0000000000..548ed509dc
--- /dev/null
+++ b/lib/tftp/src/tftp_logger.erl
@@ -0,0 +1,99 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+-module(tftp_logger).
+
+%%-------------------------------------------------------------------
+%% Interface
+%%-------------------------------------------------------------------
+
+%% public functions
+-export([
+ error_msg/2,
+ warning_msg/2,
+ info_msg/2
+ ]).
+
+-export([behaviour_info/1]).
+
+behaviour_info(callbacks) ->
+ [{error_msg, 2}, {warning_msg, 2}, {info_msg, 2}];
+behaviour_info(_) ->
+ undefined.
+
+%%-------------------------------------------------------------------
+%% error_msg(Format, Data) -> ok | exit(Reason)
+%%
+%% Format = string()
+%% Data = [term()]
+%% Reason = term()
+%%
+%% Log an error message
+%%-------------------------------------------------------------------
+
+error_msg(Format, Data) ->
+ {Format2, Data2} = add_timestamp(Format, Data),
+ error_logger:error_msg(Format2, Data2).
+
+%%-------------------------------------------------------------------
+%% warning_msg(Format, Data) -> ok | exit(Reason)
+%%
+%% Format = string()
+%% Data = [term()]
+%% Reason = term()
+%%
+%% Log a warning message
+%%-------------------------------------------------------------------
+
+warning_msg(Format, Data) ->
+ {Format2, Data2} = add_timestamp(Format, Data),
+ error_logger:warning_msg(Format2, Data2).
+
+%%-------------------------------------------------------------------
+%% info_msg(Format, Data) -> ok | exit(Reason)
+%%
+%% Format = string()
+%% Data = [term()]
+%% Reason = term()
+%%
+%% Log an info message
+%%-------------------------------------------------------------------
+
+info_msg(Format, Data) ->
+ {Format2, Data2} = add_timestamp(Format, Data),
+ io:format(Format2, Data2).
+
+%%-------------------------------------------------------------------
+%% Add timestamp to log message
+%%-------------------------------------------------------------------
+
+add_timestamp(Format, Data) ->
+ Time = erlang:timestamp(),
+ {{_Y, _Mo, _D}, {H, Mi, S}} = calendar:now_to_universal_time(Time),
+ %% {"~p-~s-~sT~s:~s:~sZ,~6.6.0w tftp: " ++ Format ++ "\n",
+ %% [Y, t(Mo), t(D), t(H), t(Mi), t(S), MicroSecs | Data]}.
+ {"~s:~s:~s tftp: " ++ Format, [t(H), t(Mi), t(S) | Data]}.
+
+%% Convert 9 to "09".
+t(Int) ->
+ case integer_to_list(Int) of
+ [Single] -> [$0, Single];
+ Multi -> Multi
+ end.
diff --git a/lib/tftp/src/tftp_sup.erl b/lib/tftp/src/tftp_sup.erl
new file mode 100644
index 0000000000..13b753612b
--- /dev/null
+++ b/lib/tftp/src/tftp_sup.erl
@@ -0,0 +1,111 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+%%----------------------------------------------------------------------
+%% Purpose: The top supervisor for tftp
+%%----------------------------------------------------------------------
+
+-module(tftp_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/1,
+ start_child/1,
+ stop_child/1,
+ which_children/0]).
+
+%% Supervisor callback
+-export([init/1]).
+
+%%%=========================================================================
+%%% API
+%%%=========================================================================
+
+start_link(TftpServices) ->
+ supervisor:start_link({local, ?MODULE}, ?MODULE, [TftpServices]).
+
+start_child(Options) ->
+ KillAfter = default_kill_after(),
+ ChildSpec = worker_spec(KillAfter, Options),
+ supervisor:start_child(?MODULE, ChildSpec).
+
+stop_child(Pid) when is_pid(Pid) ->
+ Children = supervisor:which_children(?MODULE),
+ case [Id || {Id, P, _Type, _Modules} <- Children, P =:= Pid] of
+ [] ->
+ {error, not_found};
+ [Id] ->
+ case supervisor:terminate_child(?MODULE, Id) of
+ ok ->
+ supervisor:delete_child(?MODULE, Id);
+ {error, not_found} ->
+ supervisor:delete_child(?MODULE, Id);
+ {error, Reason} ->
+ {error, Reason}
+ end
+ end.
+
+which_children() ->
+ Children = supervisor:which_children(?MODULE),
+ [{tftpd, Pid} || {_Id, Pid, _Type, _Modules} <- Children, Pid =/= undefined].
+
+%%%=========================================================================
+%%% Supervisor callback
+%%%=========================================================================
+
+init([Services]) when is_list(Services) ->
+ RestartStrategy = one_for_one,
+ MaxR = 10,
+ MaxT = 3600,
+ KillAfter = default_kill_after(),
+ Children = [worker_spec(KillAfter, Options) || {tftpd, Options} <- Services],
+ {ok, {{RestartStrategy, MaxR, MaxT}, Children}}.
+
+%%%=========================================================================
+%%% Internal functions
+%%%=========================================================================
+
+worker_spec(KillAfter, Options) ->
+ Modules = [proc_lib, tftp, tftp_engine],
+ KA = supervisor_timeout(KillAfter),
+ Name = unique_name(Options),
+ {Name, {tftp, start, [Options]}, permanent, KA, worker, Modules}.
+
+unique_name(Options) ->
+ case lists:keysearch(port, 1, Options) of
+ {value, {_, Port}} when is_integer(Port), Port > 0 ->
+ {tftpd, Port};
+ _ ->
+ {tftpd, erlang:unique_integer([positive])}
+ end.
+
+default_kill_after() ->
+ timer:seconds(3).
+
+%% supervisor_spec(Name) ->
+%% {Name, {Name, start, []}, permanent, infinity, supervisor,
+%% [Name, supervisor]}.
+
+-ifdef(debug_shutdown).
+supervisor_timeout(_KillAfter) -> timer:hours(24).
+-else.
+supervisor_timeout(KillAfter) -> KillAfter.
+-endif.
diff --git a/lib/tftp/test/Makefile b/lib/tftp/test/Makefile
new file mode 100644
index 0000000000..99f36256b0
--- /dev/null
+++ b/lib/tftp/test/Makefile
@@ -0,0 +1,250 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# %CopyrightEnd%
+#
+#
+# For an outline of how this all_SUITE_data stuff works, see the
+# make file ../../ssl/test/Makefile.
+#
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../vsn.mk
+VSN = $(TFTP_VSN)
+
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
+
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+INCLUDES = -I. \
+ -I$(ERL_TOP)/lib/tftp/src
+
+CP = cp
+
+ifeq ($(TESTROOT_DIR),)
+TESTROOT_DIR = /ldisk/tests/$(USER)/tftp
+endif
+
+ifeq ($(TFTP_DATA_DIR),)
+TFTP_DATA_DIR = $(TESTROOT_DIR)/data_dir
+endif
+
+ifeq ($(TFTP_PRIV_DIR),)
+TFTP_PRIV_DIR = $(TESTROOT_DIR)/priv_dir
+endif
+
+TFTP_FLAGS = -Dtftp__data_dir='"$(TFTP_DATA_DIR)"' \
+ -Dtftp_priv_dir='"$(TFTP_PRIV_DIR)"'
+
+
+###
+### test suite debug flags
+###
+ifeq ($(TFTP_DEBUG_CLIENT),)
+ TFTP_DEBUG_CLIENT = y
+endif
+
+ifeq ($(TFTP_DEBUG_CLIENT),)
+ TFTP_FLAGS += -Dtftp_debug_client
+endif
+
+ifeq ($(TFTP_TRACE_CLIENT),)
+ TFTP_DEBUG_CLIENT = y
+endif
+
+ifeq ($(TFTP_TRACE_CLIENT),y)
+ TFTP_FLAGS += -Dtftp_trace_client
+endif
+
+ifneq ($(TFTP_DEBUG),)
+ TFTP_DEBUG = s
+endif
+
+ifeq ($(TFTP_DEBUG),l)
+ TFTP_FLAGS += -Dtftp_log
+endif
+
+ifeq ($(TFTP_DEBUG),d)
+ TFTP_FLAGS += -Dtftp_debug -Dtftp_log
+endif
+
+
+TFTP_FLAGS += -pa ../tftp/ebin
+
+TFTP_ROOT = ../tftp
+
+MODULES = \
+ tftp_SUITE \
+ tftp_test_lib
+
+
+EBIN = .
+
+HRL_FILES = \
+ ../src/tftp.hrl \
+ tftp_test_lib.hrl
+
+ERL_FILES = $(MODULES:%=%.erl)
+
+SOURCE = $(ERL_FILES) $(HRL_FILES)
+
+TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+TFTP_SPECS = tftp.spec tftp_bench.spec
+COVER_FILE = tftp.cover
+TFTP_FILES = tftp.config $(TFTP_SPECS)
+
+
+TFTP_DATADIRS = tftp_SUITE_data
+
+DATADIRS = $(TFTP_DATADIRS)
+
+EMAKEFILE = Emakefile
+MAKE_EMAKE = $(wildcard $(ERL_TOP)/make/make_emakefile)
+
+ifeq ($(MAKE_EMAKE),)
+BUILDTARGET = $(TARGET_FILES)
+RELTEST_FILES = $(COVER_FILE) $(TFTP_SPECS) $(SOURCE)
+else
+BUILDTARGET = emakebuild
+RELTEST_FILES = $(EMAKEFILE) $(COVER_FILE) $(TFTP_SPECS) $(SOURCE)
+endif
+
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+
+RELTESTSYSDIR = "$(RELEASE_PATH)/tftp_test"
+RELTESTSYSALLDATADIR = $(RELTESTSYSDIR)/all_SUITE_data
+RELTESTSYSBINDIR = $(RELTESTSYSALLDATADIR)/bin
+
+
+# ----------------------------------------------------
+# FLAGS
+# The path to the test_server ebin dir is needed when
+# running the target "targets".
+# ----------------------------------------------------
+ERL_COMPILE_FLAGS += \
+ $(INCLUDES) \
+ $(TFTP_FLAGS)
+
+# ----------------------------------------------------
+# Targets
+# erl -sname kalle -pa ../ebin
+# If you intend to run the test suite locally (private), then
+# there is some requirements:
+# 1) TFTP_PRIV_DIR must be created
+# ----------------------------------------------------
+
+tests debug opt: $(BUILDTARGET)
+
+targets: $(TARGET_FILES)
+
+.PHONY: emakebuild
+
+emakebuild: $(EMAKEFILE)
+
+$(EMAKEFILE):
+ $(MAKE_EMAKE) $(ERL_COMPILE_FLAGS) -o$(EBIN) '*_SUITE_make' | grep -v Warning > $(EMAKEFILE)
+ $(MAKE_EMAKE) $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES) | grep -v Warning >> $(EMAKEFILE)
+
+clean:
+ rm -f $(EMAKEFILE)
+ rm -f $(TARGET_FILES)
+ rm -f core *~
+
+docs:
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec: opt
+ $(INSTALL_DIR) "$(RELSYSDIR)/test"
+ $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) "$(RELSYSDIR)/test"
+ $(INSTALL_DATA) $(TFTP_FILES) "$(RELSYSDIR)/test"
+ @for d in $(DATADIRS); do \
+ echo "installing data dir $$d"; \
+ if test -f $$d/TAR.exclude; then \
+ echo $$d/TAR.exclude2 > $$d/TAR.exclude2; \
+ cat $$d/TAR.exclude >> $$d/TAR.exclude2; \
+ find $$d -name '*.contrib*' >> $$d/TAR.exclude2; \
+ find $$d -name '*.keep*' >> $$d/TAR.exclude2; \
+ find $$d -name '*.mkelem*' >> $$d/TAR.exclude2; \
+ find $$d -name '*~' >> $$d/TAR.exclude2; \
+ find $$d -name 'erl_crash.dump' >> $$d/TAR.exclude2; \
+ find $$d -name 'core' >> $$d/TAR.exclude2; \
+ find $$d -name '.cmake.state' >> $$d/TAR.exclude2; \
+ tar cfX - $$d/TAR.exclude2 $$d | (cd "$(RELSYSDIR)/test"; tar xf -); \
+ else \
+ tar cf - $$d | (cd "$(RELSYSDIR)/test"; tar xf -); \
+ fi; \
+ done
+
+release_tests_spec: opt
+ $(INSTALL_DIR) $(RELTESTSYSDIR)
+ $(INSTALL_DATA) $(RELTEST_FILES) $(RELTESTSYSDIR)
+ chmod -R u+w $(RELTESTSYSDIR)
+ tar chf - $(DATADIRS) | (cd $(RELTESTSYSDIR); tar xf -)
+ $(INSTALL_DIR) $(RELTESTSYSALLDATADIR)
+ $(INSTALL_DIR) $(RELTESTSYSBINDIR)
+ chmod -R +x $(RELTESTSYSBINDIR)
+ $(INSTALL_DIR) $(RELTESTSYSALLDATADIR)/win32/lib
+
+release_docs_spec:
+
+info:
+ @echo "MAKE_EMAKE = $(MAKE_EMAKE)"
+ @echo "EMAKEFILE = $(EMAKEFILE)"
+ @echo "BUILDTARGET = $(BUILDTARGET)"
+ @echo ""
+ @echo "MODULES = $(MODULES)"
+ @echo "ERL_FILES = $(ERL_FILES)"
+ @echo "SOURCE = $(SOURCE)"
+ @echo "TARGET_FILES = $(TARGET_FILES)"
+ @echo ""
+ @echo "TFTP_SPECS = $(TFTP_SPECS)"
+ @echo "TFTP_FILES = $(TFTP_FILES)"
+ @echo ""
+ @echo "RELEASE_PATH = "$(RELEASE_PATH)""
+ @echo "RELSYSDIR = "$(RELSYSDIR)""
+ @echo "RELTESTSYSDIR = $(RELTESTSYSDIR)"
+ @echo "RELTESTSYSALLDATADIR = $(RELTESTSYSALLDATADIR)"
+ @echo "RELTESTSYSBINDIR = $(RELTESTSYSBINDIR)"
+ @echo ""
+ @echo "DATADIRS = $(DATADIRS)"
+ @echo "REL_DATADIRS = $(REL_DATADIRS)"
+ @echo ""
+ @echo "TFTP_DATA_DIR = $(TFTP_DATA_DIR)"
+ @echo "TFTP_PRIV_DIR = $(TFTP_PRIV_DIR)"
+ @echo "TFTP_ROOT = $(TFTP_ROOT)"
+ @echo "TFTP_FLAGS = $(TFTP_FLAGS)"
+
+
diff --git a/lib/tftp/test/tftp.config b/lib/tftp/test/tftp.config
new file mode 100644
index 0000000000..2600237da9
--- /dev/null
+++ b/lib/tftp/test/tftp.config
@@ -0,0 +1 @@
+[]. \ No newline at end of file
diff --git a/lib/tftp/test/tftp.cover b/lib/tftp/test/tftp.cover
new file mode 100644
index 0000000000..22ef5d0dda
--- /dev/null
+++ b/lib/tftp/test/tftp.cover
@@ -0,0 +1,2 @@
+{incl_app,tftp,details}.
+
diff --git a/lib/tftp/test/tftp.spec b/lib/tftp/test/tftp.spec
new file mode 100644
index 0000000000..f3537bc652
--- /dev/null
+++ b/lib/tftp/test/tftp.spec
@@ -0,0 +1 @@
+{suites,"../tftp_test", all}.
diff --git a/lib/tftp/test/tftp_SUITE.erl b/lib/tftp/test/tftp_SUITE.erl
new file mode 100644
index 0000000000..a0f6cb1ca4
--- /dev/null
+++ b/lib/tftp/test/tftp_SUITE.erl
@@ -0,0 +1,1001 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(tftp_SUITE).
+
+-compile(export_all).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Includes and defines
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-include_lib("common_test/include/ct.hrl").
+-include("tftp_test_lib.hrl").
+
+-define(START_DAEMON(Port, Options),
+ begin
+ {ok, Pid} = ?VERIFY({ok, _Pid}, tftp:start([{port, Port} | Options])),
+ if
+ Port == 0 ->
+ {ok, ActualOptions} = ?IGNORE(tftp:info(Pid)),
+ {value, {port, ActualPort}} =
+ lists:keysearch(port, 1, ActualOptions),
+ {ActualPort, Pid};
+ true ->
+ {Port, Pid}
+ end
+ end).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% API
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+t() ->
+ tftp_test_lib:t([{?MODULE, all}]).
+
+t(Cases) ->
+ tftp_test_lib:t(Cases, default_config()).
+
+t(Cases, Config) ->
+ tftp_test_lib:t(Cases, Config).
+
+default_config() ->
+ [].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Test server callbacks
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+init_per_testcase(Case, Config) ->
+ tftp_test_lib:init_per_testcase(Case, Config).
+
+end_per_testcase(Case, Config) when is_list(Config) ->
+ tftp_test_lib:end_per_testcase(Case, Config).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Top test case
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [
+ simple,
+ extra,
+ reuse_connection,
+ resend_client,
+ resend_server,
+ large_file,
+ app,
+ appup,
+ start_tftpd
+ ].
+
+groups() ->
+ [].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+
+app() ->
+ [{doc, "Test that the tftp app file is ok"}].
+app(Config) when is_list(Config) ->
+ ok = ?t:app_test(tftp).
+
+%%--------------------------------------------------------------------
+appup() ->
+ [{doc, "Test that the tftp appup file is ok"}].
+appup(Config) when is_list(Config) ->
+ ok = ?t:appup_test(tftp).
+
+start_tftpd() ->
+ [{doc, "Start/stop of tfpd service"}].
+start_tftpd(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ ok = tftp:start(),
+ {ok, Pid0} = tftp:start_service([{host, "localhost"}, {port, 0}]),
+ Pids0 = [ServicePid || {_, ServicePid} <- tftp:services()],
+ true = lists:member(Pid0, Pids0),
+ {ok, [_|_]} = tftp:service_info(Pid0),
+ tftp:stop_service(Pid0),
+ ct:sleep(100),
+ Pids1 = [ServicePid || {_, ServicePid} <- tftp:services()],
+ false = lists:member(Pid0, Pids1),
+
+ {ok, Pid1} =
+ tftp:start_standalone([{host, "localhost"}, {port, 0}]),
+ Pids2 = [ServicePid || {_, ServicePid} <- tftp:services()],
+ false = lists:member(Pid1, Pids2),
+ %% Standalone service is not supervised
+ {error,not_found} = tftp:stop_service(Pid1),
+ ok = tftp:stop(),
+
+ application:load(tftp),
+ application:set_env(tftp, services, [{tftpd, [{host, "localhost"},
+ {port, 0}]}]),
+ ok = tftp:start(),
+ 1 = length(tftp:services()),
+ application:unset_env(tftp, services),
+ ok = tftp:stop().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Simple
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+simple(doc) ->
+ ["Start the daemon and perform simple a read and write."];
+simple(suite) ->
+ [];
+simple(Config) when is_list(Config) ->
+ ?VERIFY(ok, application:start(tftp)),
+
+ {Port, DaemonPid} = ?IGNORE(?START_DAEMON(0, [{debug, brief}])),
+
+ %% Read fail
+ RemoteFilename = "tftp_temporary_remote_test_file.txt",
+ LocalFilename = "tftp_temporary_local_test_file.txt",
+ Blob = list_to_binary(lists:duplicate(2000, $1)),
+ %% Blob = <<"Some file contents\n">>,
+ Size = size(Blob),
+ ?IGNORE(file:delete(RemoteFilename)),
+ ?VERIFY({error, {client_open, enoent, _}},
+ tftp:read_file(RemoteFilename, binary, [{port, Port}])),
+
+ %% Write and read
+ ?VERIFY({ok, Size}, tftp:write_file(RemoteFilename, Blob, [{port, Port}])),
+ ?VERIFY({ok, Blob}, tftp:read_file(RemoteFilename, binary, [{port, Port}])),
+ ?IGNORE(file:delete(LocalFilename)),
+ ?VERIFY({ok, Size}, tftp:read_file(RemoteFilename, LocalFilename, [{port, Port}])),
+
+ %% Cleanup
+ unlink(DaemonPid),
+ exit(DaemonPid, kill),
+ ?VERIFY(ok, file:delete(LocalFilename)),
+ ?VERIFY(ok, file:delete(RemoteFilename)),
+ ?VERIFY(ok, application:stop(tftp)),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Extra
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+extra(doc) ->
+ ["Verify new stuff for IS 1.2."];
+extra(suite) ->
+ [];
+extra(Config) when is_list(Config) ->
+ ?VERIFY({'EXIT', {badarg,{fake_key, fake_flag}}},
+ tftp:start([{port, 0}, {fake_key, fake_flag}])),
+
+ {Port, DaemonPid} = ?IGNORE(?START_DAEMON(0, [{debug, brief}])),
+
+ RemoteFilename = "tftp_extra_temporary_remote_test_file.txt",
+ LocalFilename = "tftp_extra_temporary_local_test_file.txt",
+ Blob = <<"Some file contents\n">>,
+ Size = size(Blob),
+ Host = "127.0.0.1",
+ Peer = {inet, Host, Port},
+ Generic =
+ [
+ {state, []},
+ {prepare, fun extra_prepare/6},
+ {open, fun extra_open/6},
+ {read, fun extra_read/1},
+ {write, fun extra_write/2},
+ {abort, fun extra_abort/3 }
+ ],
+ Options = [{host, Host},
+ {port, Port},
+ %%{ debug,all},
+ {callback, {".*", tftp_test_lib, Generic}}],
+ ?VERIFY(ok, file:write_file(LocalFilename, Blob)),
+ ?VERIFY({ok, [{count, Size}, Peer]},
+ tftp:write_file(RemoteFilename, LocalFilename, Options)),
+ ?VERIFY(ok, file:delete(LocalFilename)),
+
+ ?VERIFY({ok,[{bin, Blob}, Peer]},
+ tftp:read_file(RemoteFilename, LocalFilename, Options)),
+
+ %% Cleanup
+ unlink(DaemonPid),
+ exit(DaemonPid, kill),
+ ?VERIFY(ok, file:delete(LocalFilename)),
+ ?VERIFY(ok, file:delete(RemoteFilename)),
+ ok.
+
+-record(extra_state, {file, blksize, count, acc, peer}).
+
+%%-------------------------------------------------------------------
+%% Prepare
+%%-------------------------------------------------------------------
+
+extra_prepare(Peer, Access, LocalFilename, Mode, SuggestedOptions, []) ->
+ %% Client side
+ BlkSize = list_to_integer(tftp_test_lib:lookup_option("blksize", "512", SuggestedOptions)),
+ State = #extra_state{blksize = BlkSize, peer = Peer},
+ extra_open(Peer, Access, LocalFilename, Mode, SuggestedOptions, State),
+ {ok, SuggestedOptions, State};
+extra_prepare(_Peer, _Access, _Bin, _Mode, _SuggestedOptions, _Initial) ->
+ {error, {undef, "Illegal callback options."}}.
+
+%%-------------------------------------------------------------------
+%% Open
+%%-------------------------------------------------------------------
+
+extra_open(Peer, Access, LocalFilename, Mode, SuggestedOptions, []) ->
+ %% Server side
+ case extra_prepare(Peer, Access, LocalFilename, Mode, SuggestedOptions, []) of
+ {ok, AcceptedOptions, []} ->
+ BlkSize = list_to_integer(tftp_test_lib:lookup_option("blksize", "512", AcceptedOptions)),
+ State = #extra_state{blksize = BlkSize, peer = Peer},
+ extra_open(Peer, Access, LocalFilename, Mode, AcceptedOptions, State);
+ {error, {Code, Text}} ->
+ {error, {Code, Text}}
+ end;
+extra_open(_Peer, Access, LocalFilename, _Mode, NegotiatedOptions, #extra_state{} = State) ->
+ {File, Acc} =
+ case Access of
+ read ->
+ if
+ is_binary(LocalFilename) ->
+ {undefined, LocalFilename};
+ is_list(LocalFilename) ->
+ {ok, Bin} = file:read_file(LocalFilename),
+ {LocalFilename, Bin}
+ end;
+ write ->
+ {LocalFilename, []}
+ end,
+ %% Both sides
+ State2 = State#extra_state{file = File, acc = Acc, count = 0},
+ {ok, NegotiatedOptions, State2}.
+
+%%-------------------------------------------------------------------
+%% Read
+%%-------------------------------------------------------------------
+
+extra_read(#extra_state{acc = Bin} = State) when is_binary(Bin) ->
+ BlkSize = State#extra_state.blksize,
+ Count = State#extra_state.count + size(Bin),
+ if
+ size(Bin) >= BlkSize ->
+ <<Block:BlkSize/binary, Bin2/binary>> = Bin,
+ State2 = State#extra_state{acc = Bin2, count = Count},
+ {more, Block, State2};
+ size(Bin) < BlkSize ->
+ Res = [{count, Count}, State#extra_state.peer],
+ {last, Bin, Res}
+ end.
+
+%%-------------------------------------------------------------------
+%% Write
+%%-------------------------------------------------------------------
+
+extra_write(Bin, #extra_state{acc = List} = State) when is_binary(Bin), is_list(List) ->
+ Size = size(Bin),
+ BlkSize = State#extra_state.blksize,
+ if
+ Size == BlkSize ->
+ {more, State#extra_state{acc = [Bin | List]}};
+ Size < BlkSize ->
+ Bin2 = list_to_binary(lists:reverse([Bin | List])),
+ Res = [{bin, Bin2}, State#extra_state.peer],
+ file:write_file(State#extra_state.file, Bin2),
+ {last, Res}
+ end.
+
+%%-------------------------------------------------------------------
+%% Abort
+%%-------------------------------------------------------------------
+
+extra_abort(_Code, _Text, #extra_state{}) ->
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Re-send client
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+resend_client(doc) ->
+ ["Verify that the server behaves correctly when the client re-sends packets."];
+resend_client(suite) ->
+ [];
+resend_client(Config) when is_list(Config) ->
+ Host = {127, 0, 0, 1},
+ {Port, DaemonPid} = ?IGNORE(?START_DAEMON(0, [{debug, all}])),
+
+ ?VERIFY(ok, resend_read_client(Host, Port, 10)),
+ ?VERIFY(ok, resend_read_client(Host, Port, 512)),
+ ?VERIFY(ok, resend_read_client(Host, Port, 1025)),
+
+ ?VERIFY(ok, resend_write_client(Host, Port, 10)),
+ ?VERIFY(ok, resend_write_client(Host, Port, 512)),
+ ?VERIFY(ok, resend_write_client(Host, Port, 1025)),
+
+ %% Cleanup
+ unlink(DaemonPid),
+ exit(DaemonPid, kill),
+ ok.
+
+resend_read_client(Host, Port, BlkSize) ->
+ RemoteFilename = "tftp_resend_read_client.tmp",
+ Block1 = lists:duplicate(BlkSize, $1),
+ Block2 = lists:duplicate(BlkSize, $2),
+ Block3 = lists:duplicate(BlkSize, $3),
+ Block4 = lists:duplicate(BlkSize, $4),
+ Block5 = lists:duplicate(BlkSize, $5),
+ Blocks = [Block1, Block2, Block3, Block4, Block5],
+ Blob = list_to_binary(Blocks),
+ ?VERIFY(ok, file:write_file(RemoteFilename, Blob)),
+
+ Timeout = timer:seconds(3),
+ ?VERIFY(timeout, recv(0)),
+
+ %% Open socket
+ {ok, Socket} = ?VERIFY({ok, _}, gen_udp:open(0, [binary, {reuseaddr, true}, {active, true}])),
+
+ ReadList = [0, 1, RemoteFilename, 0, "octet", 0],
+ Data1Bin = list_to_binary([0, 3, 0, 1 | Block1]),
+ NewPort =
+ if
+ BlkSize =:= 512 ->
+ %% Send READ
+ ReadBin = list_to_binary(ReadList),
+ ?VERIFY(ok, gen_udp:send(Socket, Host, Port, ReadBin)),
+
+ %% Sleep a while in order to provoke the server to re-send the packet
+ timer:sleep(Timeout + timer:seconds(1)),
+
+ %% Recv DATA #1 (the packet that the server think that we have lost)
+ {udp, _, _, NewPort0, _} = ?VERIFY({udp, Socket, Host, _, Data1Bin}, recv(Timeout)),
+ NewPort0;
+ true ->
+ %% Send READ
+ BlkSizeList = integer_to_list(BlkSize),
+ Options = ["blksize", 0, BlkSizeList, 0],
+ ReadBin = list_to_binary([ReadList | Options]),
+ ?VERIFY(ok, gen_udp:send(Socket, Host, Port, ReadBin)),
+
+ %% Recv OACK
+ OptionAckBin = list_to_binary([0, 6 | Options]),
+ {udp, _, _, NewPort0, _} = ?VERIFY({udp, Socket, Host, _, OptionAckBin}, recv(Timeout)),
+
+ %% Send ACK #0
+ Ack0Bin = <<0, 4, 0, 0>>,
+ ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort0, Ack0Bin)),
+
+ %% Send ACK #0 AGAIN (pretend that we timed out)
+ timer:sleep(timer:seconds(1)),
+ ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort0, Ack0Bin)),
+
+ %% Recv DATA #1 (the packet that the server think that we have lost)
+ ?VERIFY({udp, Socket, Host, NewPort0, Data1Bin}, recv(Timeout)),
+ NewPort0
+ end,
+
+ %% Recv DATA #1 AGAIN (the re-sent package)
+ ?VERIFY({udp, Socket, Host, NewPort, Data1Bin}, recv(Timeout)),
+
+ %% Send ACK #1
+ Ack1Bin = <<0, 4, 0, 1>>,
+ ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack1Bin)),
+
+ %% Recv DATA #2
+ Data2Bin = list_to_binary([0, 3, 0, 2 | Block2]),
+ ?VERIFY({udp, Socket, Host, NewPort, Data2Bin}, recv(Timeout)),
+
+ %% Send ACK #2
+ Ack2Bin = <<0, 4, 0, 2>>,
+ ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack2Bin)),
+
+ %% Recv DATA #3
+ Data3Bin = list_to_binary([0, 3, 0, 3 | Block3]),
+ ?VERIFY({udp, Socket, Host, NewPort, Data3Bin}, recv(Timeout)),
+
+ %% Send ACK #3
+ Ack3Bin = <<0, 4, 0, 3>>,
+ ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack3Bin)),
+
+ %% Send ACK #3 AGAIN (pretend that we timed out)
+ timer:sleep(timer:seconds(1)),
+ ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack3Bin)),
+
+ %% Recv DATA #4 (the packet that the server think that we have lost)
+ Data4Bin = list_to_binary([0, 3, 0, 4 | Block4]),
+ ?VERIFY({udp, Socket, Host, NewPort, Data4Bin}, recv(Timeout)),
+
+ %% Recv DATA #4 AGAIN (the re-sent package)
+ ?VERIFY({udp, Socket, Host, NewPort, Data4Bin}, recv(Timeout)),
+
+ %% Send ACK #2 which is out of range
+ ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack2Bin)),
+
+ %% Send ACK #4
+ Ack4Bin = <<0, 4, 0, 4>>,
+ ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack4Bin)),
+
+ %% Recv DATA #5
+ Data5Bin = list_to_binary([0, 3, 0, 5 | Block5]),
+ ?VERIFY({udp, Socket, Host, NewPort, Data5Bin}, recv(Timeout)),
+
+ %% Send ACK #5
+ Ack5Bin = <<0, 4, 0, 5>>,
+ ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack5Bin)),
+
+ %% Close socket
+ ?VERIFY(ok, gen_udp:close(Socket)),
+
+ ?VERIFY(timeout, recv(Timeout)),
+ ?VERIFY(ok, file:delete(RemoteFilename)),
+ ok.
+
+resend_write_client(Host, Port, BlkSize) ->
+ RemoteFilename = "tftp_resend_write_client.tmp",
+ Block1 = lists:duplicate(BlkSize, $1),
+ Block2 = lists:duplicate(BlkSize, $2),
+ Block3 = lists:duplicate(BlkSize, $3),
+ Block4 = lists:duplicate(BlkSize, $4),
+ Block5 = lists:duplicate(BlkSize, $5),
+ Blocks = [Block1, Block2, Block3, Block4, Block5],
+ Blob = list_to_binary(Blocks),
+ ?IGNORE(file:delete(RemoteFilename)),
+ ?VERIFY({error, enoent}, file:read_file(RemoteFilename)),
+
+ Timeout = timer:seconds(3),
+ ?VERIFY(timeout, recv(0)),
+
+ %% Open socket
+ {ok, Socket} = ?VERIFY({ok, _}, gen_udp:open(0, [binary, {reuseaddr, true}, {active, true}])),
+
+ WriteList = [0, 2, RemoteFilename, 0, "octet", 0],
+ NewPort =
+ if
+ BlkSize =:= 512 ->
+ %% Send WRITE
+ WriteBin = list_to_binary(WriteList),
+ ?VERIFY(ok, gen_udp:send(Socket, Host, Port, WriteBin)),
+
+ %% Sleep a while in order to provoke the server to re-send the packet
+ timer:sleep(Timeout + timer:seconds(1)),
+
+ %% Recv ACK #0 (the packet that the server think that we have lost)
+ Ack0Bin = <<0, 4, 0, 0>>,
+ ?VERIFY({udp, Socket, Host, _, Ack0Bin}, recv(Timeout)),
+
+ %% Recv ACK #0 AGAIN (the re-sent package)
+ {udp, _, _, NewPort0, _} = ?VERIFY({udp, Socket, Host, _, Ack0Bin}, recv(Timeout)),
+ NewPort0;
+ true ->
+ %% Send WRITE
+ BlkSizeList = integer_to_list(BlkSize),
+ WriteBin = list_to_binary([WriteList, "blksize", 0, BlkSizeList, 0]),
+ ?VERIFY(ok, gen_udp:send(Socket, Host, Port, WriteBin)),
+
+ %% Sleep a while in order to provoke the server to re-send the packet
+ timer:sleep(timer:seconds(1)),
+
+ %% Recv OACK (the packet that the server think that we have lost)
+ OptionAckBin = list_to_binary([0, 6, "blksize",0, BlkSizeList, 0]),
+ ?VERIFY({udp, Socket, Host, _, OptionAckBin}, recv(Timeout)),
+
+ %% Recv OACK AGAIN (the re-sent package)
+ {udp, _, _, NewPort0, _} = ?VERIFY({udp, Socket, Host, _, OptionAckBin}, recv(Timeout)),
+ NewPort0
+ end,
+
+ %% Send DATA #1
+ Data1Bin = list_to_binary([0, 3, 0, 1 | Block1]),
+ ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Data1Bin)),
+
+ %% Recv ACK #1
+ Ack1Bin = <<0, 4, 0, 1>>,
+ ?VERIFY({udp, Socket, Host, NewPort, Ack1Bin}, recv(Timeout)),
+
+ %% Send DATA #2
+ Data2Bin = list_to_binary([0, 3, 0, 2 | Block2]),
+ ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Data2Bin)),
+
+ %% Recv ACK #2
+ Ack2Bin = <<0, 4, 0, 2>>,
+ ?VERIFY({udp, Socket, Host, NewPort, Ack2Bin}, recv(Timeout)),
+
+ %% Send DATA #3
+ Data3Bin = list_to_binary([0, 3, 0, 3 | Block3]),
+ ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Data3Bin)),
+
+ %% Recv ACK #3
+ Ack3Bin = <<0, 4, 0, 3>>,
+ ?VERIFY({udp, Socket, Host, NewPort, Ack3Bin}, recv(Timeout)),
+
+ %% Send DATA #3 AGAIN (pretend that we timed out)
+ timer:sleep(timer:seconds(1)),
+ ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Data3Bin)),
+
+ %% Recv ACK #3 AGAIN (the packet that the server think that we have lost)
+ ?VERIFY({udp, Socket, Host, NewPort, Ack3Bin}, recv(Timeout)),
+
+ %% Send DATA #2 which is out of range
+ ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Data2Bin)),
+
+ %% Send DATA #4
+ Data4Bin = list_to_binary([0, 3, 0, 4 | Block4]),
+ ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Data4Bin)),
+
+ %% Recv ACK #4
+ Ack4Bin = <<0, 4, 0, 4>>,
+ ?VERIFY({udp, Socket, Host, NewPort, Ack4Bin}, recv(Timeout)),
+
+ %% Send DATA #5
+ Data5Bin = list_to_binary([0, 3, 0, 5 | Block5]),
+ ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Data5Bin)),
+
+ %% Recv ACK #5
+ Ack5Bin = <<0, 4, 0, 5>>,
+ ?VERIFY({udp, Socket, Host, NewPort, Ack5Bin}, recv(Timeout)),
+
+ %% Close socket
+ ?VERIFY(ok, gen_udp:close(Socket)),
+
+ ?VERIFY(timeout, recv(Timeout)),
+ ?VERIFY({ok, Blob}, file:read_file(RemoteFilename)),
+ ?VERIFY(ok, file:delete(RemoteFilename)),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Re-send server
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+resend_server(doc) ->
+ ["Verify that the server behaves correctly when the server re-sends packets."];
+resend_server(suite) ->
+ [];
+resend_server(Config) when is_list(Config) ->
+ Host = {127, 0, 0, 1},
+
+ ?VERIFY(ok, resend_read_server(Host, 10)),
+ ?VERIFY(ok, resend_read_server(Host, 512)),
+ ?VERIFY(ok, resend_read_server(Host, 1025)),
+
+ ?VERIFY(ok, resend_write_server(Host, 10)),
+ ?VERIFY(ok, resend_write_server(Host, 512)),
+ ?VERIFY(ok, resend_write_server(Host, 1025)),
+ ok.
+
+resend_read_server(Host, BlkSize) ->
+ RemoteFilename = "tftp_resend_read_server.tmp",
+ Block1 = lists:duplicate(BlkSize, $1),
+ Block2 = lists:duplicate(BlkSize, $2),
+ Block3 = lists:duplicate(BlkSize, $3),
+ Block4 = lists:duplicate(BlkSize, $4),
+ Block5 = lists:duplicate(BlkSize, $5),
+ Block6 = [],
+ Blocks = [Block1, Block2, Block3, Block4, Block5, Block6],
+ Blob = list_to_binary(Blocks),
+
+ Timeout = timer:seconds(3),
+ ?VERIFY(timeout, recv(0)),
+
+ %% Open daemon socket
+ {ok, DaemonSocket} = ?VERIFY({ok, _}, gen_udp:open(0, [binary, {reuseaddr, true}, {active, true}])),
+ {ok, DaemonPort} = ?IGNORE(inet:port(DaemonSocket)),
+
+ %% Open server socket
+ {ok, ServerSocket} = ?VERIFY({ok, _}, gen_udp:open(0, [binary, {reuseaddr, true}, {active, true}])),
+ ?IGNORE(inet:port(ServerSocket)),
+
+ %% Prepare client process
+ ReplyTo = self(),
+ ClientFun =
+ fun(Extra) ->
+ Options = [{port, DaemonPort}, {debug, brief}] ++ Extra,
+ Res = ?VERIFY({ok, Blob}, tftp:read_file(RemoteFilename, binary, Options)),
+ ReplyTo ! {self(), {tftp_client_reply, Res}},
+ exit(normal)
+ end,
+
+ ReadList = [0, 1, RemoteFilename, 0, "octet", 0],
+ Data1Bin = list_to_binary([0, 3, 0, 1 | Block1]),
+ Ack1Bin = <<0, 4, 0, 1>>,
+ {ClientPort, ClientPid} =
+ if
+ BlkSize =:= 512 ->
+ %% Start client process
+ ClientPid0 = spawn_link(fun() -> ClientFun([]) end),
+
+ %% Recv READ
+ ReadBin = list_to_binary(ReadList),
+ {udp, _, _, ClientPort0, _} = ?VERIFY({udp, DaemonSocket, Host, _, ReadBin}, recv(Timeout)),
+
+ %% Send DATA #1
+ ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort0, Data1Bin)),
+
+ %% Sleep a while in order to provoke the client to re-send the packet
+ timer:sleep(Timeout + timer:seconds(1)),
+
+ %% Recv ACK #1 (the packet that the server think that we have lost)
+ ?VERIFY({udp, ServerSocket, Host, ClientPort0, Ack1Bin}, recv(Timeout)),
+
+ %% Recv ACK #1 AGAIN (the re-sent package)
+ ?VERIFY({udp, ServerSocket, Host, _, Ack1Bin}, recv(Timeout)),
+ {ClientPort0, ClientPid0};
+ true ->
+ %% Start client process
+ BlkSizeList = integer_to_list(BlkSize),
+ ClientPid0 = spawn_link(fun() -> ClientFun([{"blksize", BlkSizeList}]) end),
+
+ %% Recv READ
+ Options = ["blksize", 0, BlkSizeList, 0],
+ ReadBin = list_to_binary([ReadList | Options]),
+ {udp, _, _, ClientPort0, _} = ?VERIFY({udp, DaemonSocket, Host, _, ReadBin}, recv(Timeout)),
+
+ %% Send OACK
+ BlkSizeList = integer_to_list(BlkSize),
+ OptionAckBin = list_to_binary([0, 6, "blksize",0, BlkSizeList, 0]),
+ ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort0, OptionAckBin)),
+
+ %% Sleep a while in order to provoke the client to re-send the packet
+ timer:sleep(Timeout + timer:seconds(1)),
+
+ %% Recv ACK #0 (the packet that the server think that we have lost)
+ Ack0Bin = <<0, 4, 0, 0>>,
+ ?VERIFY({udp, ServerSocket, Host, ClientPort0, Ack0Bin}, recv(Timeout)),
+
+ %% Recv ACK #0 AGAIN (the re-sent package)
+ ?VERIFY({udp, ServerSocket, Host, ClientPort0, Ack0Bin}, recv(Timeout)),
+
+ %% Send DATA #1
+ ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort0, Data1Bin)),
+
+ %% Recv ACK #1
+ ?VERIFY({udp, ServerSocket, Host, _, Ack1Bin}, recv(Timeout)),
+ {ClientPort0, ClientPid0}
+ end,
+
+ %% Send DATA #2
+ Data2Bin = list_to_binary([0, 3, 0, 2 | Block2]),
+ ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Data2Bin)),
+
+ %% Recv ACK #2
+ Ack2Bin = <<0, 4, 0, 2>>,
+ ?VERIFY({udp, ServerSocket, Host, ClientPort, Ack2Bin}, recv(Timeout)),
+
+ %% Send DATA #3
+ Data3Bin = list_to_binary([0, 3, 0, 3 | Block3]),
+ ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Data3Bin)),
+
+ %% Recv ACK #3
+ Ack3Bin = <<0, 4, 0, 3>>,
+ ?VERIFY({udp, ServerSocket, Host, ClientPort, Ack3Bin}, recv(Timeout)),
+
+ %% Send DATA #3 AGAIN (pretend that we timed out)
+ timer:sleep(timer:seconds(1)),
+ ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Data3Bin)),
+
+ %% Recv ACK #3 AGAIN (the packet that the server think that we have lost)
+ ?VERIFY({udp, ServerSocket, Host, ClientPort, Ack3Bin}, recv(Timeout)),
+
+ %% Send DATA #4
+ Data4Bin = list_to_binary([0, 3, 0, 4 | Block4]),
+ ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Data4Bin)),
+
+ %% Recv ACK #4
+ Ack4Bin = <<0, 4, 0, 4>>,
+ ?VERIFY({udp, ServerSocket, Host, ClientPort, Ack4Bin}, recv(Timeout)),
+
+ %% Send DATA #3 which is out of range
+ ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Data3Bin)),
+
+ %% Send DATA #5
+ Data5Bin = list_to_binary([0, 3, 0, 5 | Block5]),
+ ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Data5Bin)),
+
+ %% Recv ACK #5
+ Ack5Bin = <<0, 4, 0, 5>>,
+ ?VERIFY({udp, ServerSocket, Host, ClientPort, Ack5Bin}, recv(Timeout)),
+
+ %% Send DATA #6
+ Data6Bin = list_to_binary([0, 3, 0, 6 | Block6]),
+ ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Data6Bin)),
+
+ %% Close daemon and server sockets
+ ?VERIFY(ok, gen_udp:close(ServerSocket)),
+ ?VERIFY(ok, gen_udp:close(DaemonSocket)),
+
+ ?VERIFY({ClientPid, {tftp_client_reply, {ok, Blob}}}, recv(Timeout)),
+
+ ?VERIFY(timeout, recv(Timeout)),
+ ok.
+
+resend_write_server(Host, BlkSize) ->
+ RemoteFilename = "tftp_resend_write_server.tmp",
+ Block1 = lists:duplicate(BlkSize, $1),
+ Block2 = lists:duplicate(BlkSize, $2),
+ Block3 = lists:duplicate(BlkSize, $3),
+ Block4 = lists:duplicate(BlkSize, $4),
+ Block5 = lists:duplicate(BlkSize, $5),
+ Block6 = [],
+ Blocks = [Block1, Block2, Block3, Block4, Block5, Block6],
+ Blob = list_to_binary(Blocks),
+ Size = size(Blob),
+
+ Timeout = timer:seconds(3),
+ ?VERIFY(timeout, recv(0)),
+
+ %% Open daemon socket
+ {ok, DaemonSocket} = ?VERIFY({ok, _}, gen_udp:open(0, [binary, {reuseaddr, true}, {active, true}])),
+ {ok, DaemonPort} = ?IGNORE(inet:port(DaemonSocket)),
+
+ %% Open server socket
+ {ok, ServerSocket} = ?VERIFY({ok, _}, gen_udp:open(0, [binary, {reuseaddr, true}, {active, true}])),
+ ?IGNORE(inet:port(ServerSocket)),
+
+ %% Prepare client process
+ ReplyTo = self(),
+ ClientFun =
+ fun(Extra) ->
+ Options = [{port, DaemonPort}, {debug, brief}] ++ Extra,
+ Res = ?VERIFY({ok, Size}, tftp:write_file(RemoteFilename, Blob, Options)),
+ ReplyTo ! {self(), {tftp_client_reply, Res}},
+ exit(normal)
+ end,
+
+ WriteList = [0, 2, RemoteFilename, 0, "octet", 0],
+ Data1Bin = list_to_binary([0, 3, 0, 1 | Block1]),
+ {ClientPort, ClientPid} =
+ if
+ BlkSize =:= 512 ->
+ %% Start client process
+ ClientPid0 = spawn_link(fun() -> ClientFun([]) end),
+
+ %% Recv WRITE
+ WriteBin = list_to_binary(WriteList),
+ io:format("WriteBin ~p\n", [WriteBin]),
+ {udp, _, _, ClientPort0, _} = ?VERIFY({udp, DaemonSocket, Host, _, WriteBin}, recv(Timeout)),
+
+ %% Send ACK #1
+ Ack0Bin = <<0, 4, 0, 0>>,
+ ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort0, Ack0Bin)),
+
+ %% Sleep a while in order to provoke the client to re-send the packet
+ timer:sleep(Timeout + timer:seconds(1)),
+
+ %% Recv DATA #1 (the packet that the server think that we have lost)
+ ?VERIFY({udp, ServerSocket, Host, ClientPort0, Data1Bin}, recv(Timeout)),
+
+ %% Recv DATA #1 AGAIN (the re-sent package)
+ ?VERIFY({udp, ServerSocket, Host, _, Data1Bin}, recv(Timeout)),
+ {ClientPort0, ClientPid0};
+ true ->
+ %% Start client process
+ BlkSizeList = integer_to_list(BlkSize),
+ ClientPid0 = spawn_link(fun() -> ClientFun([{"blksize", BlkSizeList}]) end),
+
+ %% Recv WRITE
+ Options = ["blksize", 0, BlkSizeList, 0],
+ WriteBin = list_to_binary([WriteList | Options]),
+ {udp, _, _, ClientPort0, _} = ?VERIFY({udp, DaemonSocket, Host, _, WriteBin}, recv(Timeout)),
+
+ %% Send OACK
+ BlkSizeList = integer_to_list(BlkSize),
+ OptionAckBin = list_to_binary([0, 6, "blksize",0, BlkSizeList, 0]),
+ ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort0, OptionAckBin)),
+
+ %% Sleep a while in order to provoke the client to re-send the packet
+ timer:sleep(Timeout + timer:seconds(1)),
+
+ %% Recv DATA #1 (the packet that the server think that we have lost)
+ ?VERIFY({udp, ServerSocket, Host, ClientPort0, Data1Bin}, recv(Timeout)),
+
+ %% Recv DATA #1 AGAIN (the re-sent package)
+ ?VERIFY({udp, ServerSocket, Host, ClientPort0, Data1Bin}, recv(Timeout)),
+ {ClientPort0, ClientPid0}
+ end,
+
+ %% Send ACK #1
+ Ack1Bin = <<0, 4, 0, 1>>,
+ ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Ack1Bin)),
+
+ %% Recv DATA #2
+ Data2Bin = list_to_binary([0, 3, 0, 2 | Block2]),
+ ?VERIFY({udp, ServerSocket, Host, ClientPort, Data2Bin}, recv(Timeout)),
+
+ %% Send ACK #2
+ Ack2Bin = <<0, 4, 0, 2>>,
+ ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Ack2Bin)),
+
+ %% Recv DATA #3
+ Data3Bin = list_to_binary([0, 3, 0, 3 | Block3]),
+ ?VERIFY({udp, ServerSocket, Host, ClientPort, Data3Bin}, recv(Timeout)),
+
+ %% Send ACK #3
+ Ack3Bin = <<0, 4, 0, 3>>,
+ ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Ack3Bin)),
+
+ %% Send ACK #3 AGAIN (pretend that we timed out)
+ timer:sleep(timer:seconds(1)),
+ ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Ack3Bin)),
+
+ %% Recv DATA #4 (the packet that the server think that we have lost)
+ Data4Bin = list_to_binary([0, 3, 0, 4 | Block4]),
+ ?VERIFY({udp, ServerSocket, Host, ClientPort, Data4Bin}, recv(Timeout)),
+
+ %% Recv DATA #4 AGAIN (the re-sent package)
+ ?VERIFY({udp, ServerSocket, Host, ClientPort, Data4Bin}, recv(Timeout)),
+
+ %% Send ACK #4
+ Ack4Bin = <<0, 4, 0, 4>>,
+ ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Ack4Bin)),
+
+ %% Recv DATA #5
+ Data5Bin = list_to_binary([0, 3, 0, 5 | Block5]),
+ ?VERIFY({udp, ServerSocket, Host, ClientPort, Data5Bin}, recv(Timeout)),
+
+ %% Send ACK #3 which is out of range
+ ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Ack3Bin)),
+
+ %% Send ACK #5
+ Ack5Bin = <<0, 4, 0, 5>>,
+ ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Ack5Bin)),
+
+ %% Recv DATA #6
+ Data6Bin = list_to_binary([0, 3, 0, 6 | Block6]),
+ ?VERIFY({udp, ServerSocket, Host, ClientPort, Data6Bin}, recv(Timeout)),
+
+ %% Send ACK #6
+ Ack6Bin = <<0, 4, 0, 6>>,
+ ?VERIFY(ok, gen_udp:send(ServerSocket, Host, ClientPort, Ack6Bin)),
+
+ %% Close daemon and server sockets
+ ?VERIFY(ok, gen_udp:close(ServerSocket)),
+ ?VERIFY(ok, gen_udp:close(DaemonSocket)),
+
+ ?VERIFY({ClientPid, {tftp_client_reply, {ok, Size}}}, recv(Timeout)),
+
+ ?VERIFY(timeout, recv(Timeout)),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+reuse_connection(doc) ->
+ ["Verify that the server can reuse an ongiong connection when same client resends request."];
+reuse_connection(suite) ->
+ [];
+reuse_connection(Config) when is_list(Config) ->
+ Host = {127, 0, 0, 1},
+ {Port, DaemonPid} = ?IGNORE(?START_DAEMON(0, [{debug, all}])),
+
+ RemoteFilename = "reuse_connection.tmp",
+ BlkSize = 512,
+ Block1 = lists:duplicate(BlkSize, $1),
+ Block2 = lists:duplicate(BlkSize div 2, $2),
+ Blocks = [Block1, Block2],
+ Blob = list_to_binary(Blocks),
+ ?VERIFY(ok, file:write_file(RemoteFilename, Blob)),
+
+ Seconds = 3,
+ Timeout = timer:seconds(Seconds),
+ ?VERIFY(timeout, recv(0)),
+
+ %% Open socket
+ {ok, Socket} = ?VERIFY({ok, _}, gen_udp:open(0, [binary, {reuseaddr, true}, {active, true}])),
+
+ ReadList = [0, 1, RemoteFilename, 0, "octet", 0],
+ Data1Bin = list_to_binary([0, 3, 0, 1 | Block1]),
+
+ %% Send READ
+ TimeoutList = integer_to_list(Seconds),
+ Options = ["timeout", 0, TimeoutList, 0],
+ ReadBin = list_to_binary([ReadList | Options]),
+ ?VERIFY(ok, gen_udp:send(Socket, Host, Port, ReadBin)),
+
+ %% Send yet another READ for same file
+ ?VERIFY(ok, gen_udp:send(Socket, Host, Port, ReadBin)),
+
+ %% Recv OACK
+ OptionAckBin = list_to_binary([0, 6 | Options]),
+ {udp, _, _, NewPort, _} = ?VERIFY({udp, Socket, Host, _, OptionAckBin}, recv(Timeout)),
+
+ %% Send ACK #0
+ Ack0Bin = <<0, 4, 0, 0>>,
+ ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack0Bin)),
+
+ %% Recv DATA #1
+ ?VERIFY({udp, Socket, Host, NewPort, Data1Bin}, recv(Timeout)),
+
+ %% Send ACK #1
+ Ack1Bin = <<0, 4, 0, 1>>,
+ ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack1Bin)),
+
+ %% Recv DATA #2
+ Data2Bin = list_to_binary([0, 3, 0, 2 | Block2]),
+ ?VERIFY({udp, Socket, Host, NewPort, Data2Bin}, recv(Timeout)),
+
+ %% Send ACK #2
+ Ack2Bin = <<0, 4, 0, 2>>,
+ ?VERIFY(ok, gen_udp:send(Socket, Host, NewPort, Ack2Bin)),
+
+ %% Close socket
+ ?VERIFY(ok, gen_udp:close(Socket)),
+
+ ?VERIFY(timeout, recv(Timeout)),
+ ?VERIFY(ok, file:delete(RemoteFilename)),
+
+ %% Cleanup
+ unlink(DaemonPid),
+ exit(DaemonPid, kill),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Large file: transfer > 65535 blocks
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+large_file(doc) ->
+ ["Start the daemon and test transfer of files greater than 32M."];
+large_file(suite) ->
+ [];
+large_file(Config) when is_list(Config) ->
+ ?VERIFY(ok, application:start(tftp)),
+
+ {Port, DaemonPid} = ?IGNORE(?START_DAEMON(0, [{debug, brief}])),
+
+ %% Read fail
+ RemoteFilename = "tftp_temporary_large_file_remote_test_file.txt",
+ LocalFilename = "tftp_temporary_large_file_local_test_file.txt",
+
+ {ok, FH} = file:open(LocalFilename, [write,exclusive]),
+ {ok, Size} = file:position(FH, {eof, 2*512*65535}),
+ ok = file:truncate(FH),
+ ?IGNORE(file:close(FH)),
+
+ %% Write and read
+ ?VERIFY({ok, Size}, tftp:write_file(RemoteFilename, LocalFilename, [{port, Port}])),
+ ?IGNORE(file:delete(LocalFilename)),
+ ?VERIFY({ok, Size}, tftp:read_file(RemoteFilename, LocalFilename, [{port, Port}])),
+
+ %% Cleanup
+ unlink(DaemonPid),
+ exit(DaemonPid, kill),
+ ?VERIFY(ok, file:delete(LocalFilename)),
+ ?VERIFY(ok, file:delete(RemoteFilename)),
+ ?VERIFY(ok, application:stop(tftp)),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Goodies
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+recv(Timeout) ->
+ receive
+ Msg ->
+ Msg
+ after Timeout ->
+ timeout
+ end.
diff --git a/lib/tftp/test/tftp_bench.spec b/lib/tftp/test/tftp_bench.spec
new file mode 100644
index 0000000000..43fa385c85
--- /dev/null
+++ b/lib/tftp/test/tftp_bench.spec
@@ -0,0 +1 @@
+{suites,"../tftp_test",[]}.
diff --git a/lib/tftp/test/tftp_test_lib.erl b/lib/tftp/test/tftp_test_lib.erl
new file mode 100644
index 0000000000..04534228c2
--- /dev/null
+++ b/lib/tftp/test/tftp_test_lib.erl
@@ -0,0 +1,308 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(tftp_test_lib).
+
+-compile(export_all).
+
+-include("tftp_test_lib.hrl").
+
+%%
+%% -----
+%%
+
+init_per_testcase(_Case, Config) when is_list(Config) ->
+ io:format("\n ", []),
+ ?IGNORE(application:stop(tftp)),
+ Config.
+
+end_per_testcase(_Case, Config) when is_list(Config) ->
+ ?IGNORE(application:stop(tftp)),
+ Config.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Infrastructure for test suite
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+error(Actual, Mod, Line) ->
+ (catch global:send(tftp_global_logger, {failed, Mod, Line})),
+ log("<ERROR> Bad result: ~p\n", [Actual], Mod, Line),
+ Label = lists:concat([Mod, "(", Line, ") unexpected result"]),
+ et:report_event(60, Mod, Mod, Label,
+ [{line, Mod, Line}, {error, Actual}]),
+ case global:whereis_name(tftp_test_case_sup) of
+ undefined ->
+ ignore;
+ Pid ->
+ Fail = #'REASON'{mod = Mod, line = Line, desc = Actual},
+ Pid ! {fail, self(), Fail}
+ end,
+ Actual.
+
+log(Format, Args, Mod, Line) ->
+ case global:whereis_name(tftp_global_logger) of
+ undefined ->
+ io:format(user, "~p(~p): " ++ Format,
+ [Mod, Line] ++ Args);
+ Pid ->
+ io:format(Pid, "~p(~p): " ++ Format,
+ [Mod, Line] ++ Args)
+ end.
+
+default_config() ->
+ [].
+
+t() ->
+ t([{?MODULE, all}]).
+
+t(Cases) ->
+ t(Cases, default_config()).
+
+t(Cases, Config) ->
+ process_flag(trap_exit, true),
+ Res = lists:flatten(do_test(Cases, Config)),
+ io:format("Res: ~p\n", [Res]),
+ display_result(Res),
+ Res.
+
+do_test({Mod, Fun}, Config) when is_atom(Mod), is_atom(Fun) ->
+ case catch apply(Mod, Fun, [suite]) of
+ [] ->
+ io:format("Eval: ~p:", [{Mod, Fun}]),
+ Res = eval(Mod, Fun, Config),
+ {R, _, _} = Res,
+ io:format(" ~p\n", [R]),
+ Res;
+
+ Cases when is_list(Cases) ->
+ io:format("Expand: ~p ...\n", [{Mod, Fun}]),
+ Map = fun(Case) when is_atom(Case)-> {Mod, Case};
+ (Case) -> Case
+ end,
+ do_test(lists:map(Map, Cases), Config);
+
+ {req, _, {conf, Init, Cases, Finish}} ->
+ case (catch apply(Mod, Init, [Config])) of
+ Conf when is_list(Conf) ->
+ io:format("Expand: ~p ...\n", [{Mod, Fun}]),
+ Map = fun(Case) when is_atom(Case)-> {Mod, Case};
+ (Case) -> Case
+ end,
+ Res = do_test(lists:map(Map, Cases), Conf),
+ (catch apply(Mod, Finish, [Conf])),
+ Res;
+
+ {'EXIT', {skipped, Reason}} ->
+ io:format(" => skipping: ~p\n", [Reason]),
+ [{skipped, {Mod, Fun}, Reason}];
+
+ Error ->
+ io:format(" => failed: ~p\n", [Error]),
+ [{failed, {Mod, Fun}, Error}]
+ end;
+
+ {'EXIT', {undef, _}} ->
+ io:format("Undefined: ~p\n", [{Mod, Fun}]),
+ [{nyi, {Mod, Fun}, ok}];
+
+ Error ->
+ io:format("Ignoring: ~p: ~p\n", [{Mod, Fun}, Error]),
+ [{failed, {Mod, Fun}, Error}]
+ end;
+do_test(Mod, Config) when is_atom(Mod) ->
+ Res = do_test({Mod, all}, Config),
+ Res;
+do_test(Cases, Config) when is_list(Cases) ->
+ [do_test(Case, Config) || Case <- Cases];
+do_test(Bad, _Config) ->
+ [{badarg, Bad, ok}].
+
+eval(Mod, Fun, Config) ->
+ TestCase = {?MODULE, Mod, Fun},
+ Label = lists:concat(["TEST CASE: ", Fun]),
+ et:report_event(40, ?MODULE, Mod, Label ++ " started",
+ [TestCase, Config]),
+ global:register_name(tftp_test_case_sup, self()),
+ Flag = process_flag(trap_exit, true),
+ Config2 = Mod:init_per_testcase(Fun, Config),
+ Pid = spawn_link(?MODULE, do_eval, [self(), Mod, Fun, Config2]),
+ R = wait_for_evaluator(Pid, Mod, Fun, Config2, []),
+ Mod:end_per_testcase(Fun, Config2),
+ global:unregister_name(tftp_test_case_sup),
+ process_flag(trap_exit, Flag),
+ R.
+
+wait_for_evaluator(Pid, Mod, Fun, Config, Errors) ->
+ TestCase = {?MODULE, Mod, Fun},
+ Label = lists:concat(["TEST CASE: ", Fun]),
+ receive
+ {done, Pid, ok} when Errors == [] ->
+ et:report_event(40, Mod, ?MODULE, Label ++ " ok",
+ [TestCase, Config]),
+ {ok, {Mod, Fun}, Errors};
+ {done, Pid, {ok, _}} when Errors == [] ->
+ et:report_event(40, Mod, ?MODULE, Label ++ " ok",
+ [TestCase, Config]),
+ {ok, {Mod, Fun}, Errors};
+ {done, Pid, Fail} ->
+ et:report_event(20, Mod, ?MODULE, Label ++ " failed",
+ [TestCase, Config, {return, Fail}, Errors]),
+ {failed, {Mod,Fun}, Fail};
+ {'EXIT', Pid, {skipped, Reason}} ->
+ et:report_event(20, Mod, ?MODULE, Label ++ " skipped",
+ [TestCase, Config, {skipped, Reason}]),
+ {skipped, {Mod, Fun}, Errors};
+ {'EXIT', Pid, Reason} ->
+ et:report_event(20, Mod, ?MODULE, Label ++ " crashed",
+ [TestCase, Config, {'EXIT', Reason}]),
+ {crashed, {Mod, Fun}, [{'EXIT', Reason} | Errors]};
+ {fail, Pid, Reason} ->
+ wait_for_evaluator(Pid, Mod, Fun, Config, Errors ++ [Reason])
+ end.
+
+do_eval(ReplyTo, Mod, Fun, Config) ->
+ case (catch apply(Mod, Fun, [Config])) of
+ {'EXIT', {skipped, Reason}} ->
+ ReplyTo ! {'EXIT', self(), {skipped, Reason}};
+ Other ->
+ ReplyTo ! {done, self(), Other}
+ end,
+ unlink(ReplyTo),
+ exit(shutdown).
+
+display_result([]) ->
+ io:format("OK\n", []);
+display_result(Res) when is_list(Res) ->
+ Ok = [MF || {ok, MF, _} <- Res],
+ Nyi = [MF || {nyi, MF, _} <- Res],
+ Skipped = [{MF, Reason} || {skipped, MF, Reason} <- Res],
+ Failed = [{MF, Reason} || {failed, MF, Reason} <- Res],
+ Crashed = [{MF, Reason} || {crashed, MF, Reason} <- Res],
+ display_summary(Ok, Nyi, Skipped, Failed, Crashed),
+ display_skipped(Skipped),
+ display_failed(Failed),
+ display_crashed(Crashed).
+
+display_summary(Ok, Nyi, Skipped, Failed, Crashed) ->
+ io:format("\nTest case summary:\n", []),
+ display_summary(Ok, "successful"),
+ display_summary(Nyi, "not yet implemented"),
+ display_summary(Skipped, "skipped"),
+ display_summary(Failed, "failed"),
+ display_summary(Crashed, "crashed"),
+ io:format("\n", []).
+
+display_summary(Res, Info) ->
+ io:format(" ~w test cases ~s\n", [length(Res), Info]).
+
+display_skipped([]) ->
+ ok;
+display_skipped(Skipped) ->
+ io:format("Skipped test cases:\n", []),
+ F = fun({MF, Reason}) -> io:format(" ~p => ~p\n", [MF, Reason]) end,
+ lists:foreach(F, Skipped),
+ io:format("\n", []).
+
+
+display_failed([]) ->
+ ok;
+display_failed(Failed) ->
+ io:format("Failed test cases:\n", []),
+ F = fun({MF, Reason}) -> io:format(" ~p => ~p\n", [MF, Reason]) end,
+ lists:foreach(F, Failed),
+ io:format("\n", []).
+
+display_crashed([]) ->
+ ok;
+display_crashed(Crashed) ->
+ io:format("Crashed test cases:\n", []),
+ F = fun({MF, Reason}) -> io:format(" ~p => ~p\n", [MF, Reason]) end,
+ lists:foreach(F, Crashed),
+ io:format("\n", []).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% generic callback
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-record(generic_state, {state, prepare, open, read, write, abort}).
+
+prepare(Peer, Access, LocalFilename, Mode, SuggestedOptions, Initial) when is_list(Initial) ->
+ State = lookup_option(state, mandatory, Initial),
+ Prepare = lookup_option(prepare, mandatory, Initial),
+ Open = lookup_option(open, mandatory, Initial),
+ Read = lookup_option(read, mandatory, Initial),
+ Write = lookup_option(write, mandatory, Initial),
+ Abort = lookup_option(abort, mandatory, Initial),
+ case Prepare(Peer, Access, LocalFilename, Mode, SuggestedOptions, State) of
+ {ok, AcceptedOptions, NewState} ->
+ {ok,
+ AcceptedOptions,
+ #generic_state{state = NewState,
+ prepare = Prepare,
+ open = Open,
+ read = Read,
+ write = Write,
+ abort = Abort}};
+ Other ->
+ Other
+ end.
+
+open(Peer, Access, LocalFilename, Mode, SuggestedOptions, Initial) when is_list(Initial) ->
+ case prepare(Peer, Access, LocalFilename, Mode, SuggestedOptions, Initial) of
+ {ok, SuggestedOptions2, GenericState} ->
+ open(Peer, Access, LocalFilename, Mode, SuggestedOptions2, GenericState);
+ Other ->
+ Other
+ end;
+open(Peer, Access, LocalFilename, Mode, SuggestedOptions, #generic_state{state = State, open = Open} = GenericState) ->
+ case Open(Peer, Access, LocalFilename, Mode, SuggestedOptions, State) of
+ {ok, SuggestedOptions2, NewState} ->
+ {ok, SuggestedOptions2, GenericState#generic_state{state = NewState}};
+ Other ->
+ Other
+ end.
+
+read(#generic_state{state = State, read = Read} = GenericState) ->
+ case Read(State) of
+ {more, DataBlock, NewState} ->
+ {more, DataBlock, GenericState#generic_state{state = NewState}};
+ Other ->
+ Other
+ end.
+
+write(DataBlock, #generic_state{state = State, write = Write} = GenericState) ->
+ case Write(DataBlock, State) of
+ {more, NewState} ->
+ {more, GenericState#generic_state{state = NewState}};
+ Other ->
+ Other
+ end.
+
+abort(Code, Text, #generic_state{state = State, abort = Abort}) ->
+ Abort(Code, Text, State).
+
+lookup_option(Key, Default, Options) ->
+ case lists:keysearch(Key, 1, Options) of
+ {value, {_, Val}} ->
+ Val;
+ false ->
+ Default
+ end.
+
diff --git a/lib/tftp/test/tftp_test_lib.hrl b/lib/tftp/test/tftp_test_lib.hrl
new file mode 100644
index 0000000000..eb8ed77fc1
--- /dev/null
+++ b/lib/tftp/test/tftp_test_lib.hrl
@@ -0,0 +1,44 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-record('REASON', {mod, line, desc}).
+
+-define(LOG(Format, Args),
+ tftp_test_lib:log(Format, Args, ?MODULE, ?LINE)).
+
+-define(ERROR(Reason),
+ tftp_test_lib:error(Reason, ?MODULE, ?LINE)).
+
+-define(VERIFY(Expected, Expr),
+ fun() ->
+ AcTuAlReS = (catch (Expr)),
+ case AcTuAlReS of
+ Expected -> ?LOG("Ok, ~p\n", [AcTuAlReS]);
+ _ -> ?ERROR(AcTuAlReS)
+ end,
+ AcTuAlReS
+ end()).
+
+-define(IGNORE(Expr),
+ fun() ->
+ AcTuAlReS = (catch (Expr)),
+ ?LOG("Ok, ~p\n", [AcTuAlReS]),
+ AcTuAlReS
+ end()).
diff --git a/lib/tftp/vsn.mk b/lib/tftp/vsn.mk
new file mode 100644
index 0000000000..1a547fbe9b
--- /dev/null
+++ b/lib/tftp/vsn.mk
@@ -0,0 +1,24 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2001-2018. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# %CopyrightEnd%
+
+APPLICATION = tftp
+TFTP_VSN = 1.0.1
+PRE_VSN =
+APP_VSN = "$(APPLICATION)-$(TFTP_VSN)$(PRE_VSN)"
diff --git a/lib/tools/c_src/Makefile.in b/lib/tools/c_src/Makefile.in
index cfe91917f8..289322b6fa 100644
--- a/lib/tools/c_src/Makefile.in
+++ b/lib/tools/c_src/Makefile.in
@@ -29,7 +29,6 @@ CC=@CC@
LD=@LD@
AR=@AR@
RANLIB=@RANLIB@
-RM=@RM@
MKDIR=@MKDIR@
INSTALL=@INSTALL@
INSTALL_DIR=@INSTALL_DIR@
@@ -158,9 +157,9 @@ $(ERTS_LIB):
docs:
clean:
- $(RM) -rf ../obj/*
- $(RM) -rf ../bin/*
- $(RM) -f ./*~
+ $(RM) -r ../obj/*
+ $(RM) -r ../bin/*
+ $(RM) ./*~
.PHONY: all erts_lib docs clean
diff --git a/lib/tools/doc/specs/.gitignore b/lib/tools/doc/specs/.gitignore
new file mode 100644
index 0000000000..322eebcb06
--- /dev/null
+++ b/lib/tools/doc/specs/.gitignore
@@ -0,0 +1 @@
+specs_*.xml
diff --git a/lib/tools/doc/src/Makefile b/lib/tools/doc/src/Makefile
index b554781382..5ff4fe3113 100644
--- a/lib/tools/doc/src/Makefile
+++ b/lib/tools/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2017. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -84,11 +84,20 @@ HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
+SPECS_FILES = $(XML_REF3_FILES:%.xml=$(SPECDIR)/specs_%.xml)
+
+TOP_SPECS_FILE = specs.xml
+
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
XML_FLAGS +=
+TOOLS_SRC=$(ERL_TOP)/lib/tools/src
+TOOLS_INCLUDE=$(ERL_TOP)/lib/tools/include
+
+SPECS_FLAGS = -I$(TOOLS_SRC) -I$(TOOLS_INCLUDE)
+
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
@@ -111,10 +120,16 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
+ rm -f $(SPECDIR)/*
rm -f errs core *~
+# erlang_mode doesn't have erlang source so we generate a dummy file for it.
+$(SPECDIR)/specs_erlang_mode.xml:
+ echo '<module name="erlang_mode"/>' > $(SPECDIR)/specs_erlang_mode.xml
+
# ----------------------------------------------------
# Release Target
# ----------------------------------------------------
diff --git a/lib/tools/doc/src/cover.xml b/lib/tools/doc/src/cover.xml
index 15cd784253..e9f782977d 100644
--- a/lib/tools/doc/src/cover.xml
+++ b/lib/tools/doc/src/cover.xml
@@ -30,7 +30,7 @@
<date></date>
<rev></rev>
</header>
- <module>cover</module>
+ <module since="">cover</module>
<modulesummary>A Coverage Analysis Tool for Erlang</modulesummary>
<description>
<p>The module <c>cover</c> provides a set of functions for coverage
@@ -115,7 +115,7 @@
</description>
<funcs>
<func>
- <name>start() -> {ok,Pid} | {error,Reason}</name>
+ <name since="">start() -> {ok,Pid} | {error,Reason}</name>
<fsummary>Start Cover.</fsummary>
<type>
<v>Pid = pid()</v>
@@ -128,21 +128,33 @@
</desc>
</func>
<func>
- <name>start(Nodes) -> {ok,StartedNodes} | {error,not_main_node}</name>
+ <name since="OTP 22.0">local_only() -> ok | {error,too_late}</name>
+ <fsummary>Only support running Cover on the local node.</fsummary>
+ <desc>
+ <p>Only support running Cover on the local node. This function
+ must be called before any modules have been compiled or any
+ nodes added. When running in this mode, modules will be Cover
+ compiled in a more efficient way, but the resulting code will
+ only work on the same node they were compiled on.</p>
+ </desc>
+ </func>
+ <func>
+ <name since="">start(Nodes) -> {ok,StartedNodes} | {error,not_main_node} | {error,local_only}</name>
<fsummary>Start Cover on remote nodes.</fsummary>
<type>
<v>Nodes = StartedNodes = [atom()]</v>
</type>
<desc>
<p>Starts a Cover server on the each of given nodes, and loads
- all cover compiled modules.</p>
+ all cover compiled modules. This call will fail if
+ <c>cover:local_only/0</c> has been called.</p>
</desc>
</func>
<func>
- <name>compile(ModFiles) -> Result | [Result]</name>
- <name>compile(ModFiles, Options) -> Result | [Result]</name>
- <name>compile_module(ModFiles) -> Result | [Result]</name>
- <name>compile_module(ModFiles, Options) -> Result | [Result]</name>
+ <name since="">compile(ModFiles) -> Result | [Result]</name>
+ <name since="">compile(ModFiles, Options) -> Result | [Result]</name>
+ <name since="">compile_module(ModFiles) -> Result | [Result]</name>
+ <name since="">compile_module(ModFiles, Options) -> Result | [Result]</name>
<fsummary>Compile one or more modules for Cover analysis.</fsummary>
<type>
<v>ModFiles = ModFile | [ModFile]</v>
@@ -176,9 +188,9 @@
</desc>
</func>
<func>
- <name>compile_directory() -> [Result] | {error,Reason}</name>
- <name>compile_directory(Dir) -> [Result] | {error,Reason}</name>
- <name>compile_directory(Dir, Options) -> [Result] | {error,Reason}</name>
+ <name since="">compile_directory() -> [Result] | {error,Reason}</name>
+ <name since="">compile_directory(Dir) -> [Result] | {error,Reason}</name>
+ <name since="">compile_directory(Dir, Options) -> [Result] | {error,Reason}</name>
<fsummary>Compile all modules in a directory for Cover analysis.</fsummary>
<type>
<v>Dir = string()</v>
@@ -199,7 +211,7 @@
</desc>
</func>
<func>
- <name>compile_beam(ModFiles) -> Result | [Result]</name>
+ <name since="">compile_beam(ModFiles) -> Result | [Result]</name>
<fsummary>Compile one or more modules for Cover analysis, using existing beam(s).</fsummary>
<type>
<v>ModFiles = ModFile | [ModFile]</v>
@@ -234,15 +246,15 @@
<c>{already_cover_compiled,no_beam_found,Module}</c> is
returned.</p>
<p><c>{error,BeamFile}</c> is returned if the compiled code
- can not be loaded on the node.</p>
+ cannot be loaded on the node.</p>
<p>If a list of <c>ModFiles</c> is given as input, a list
of <c>Result</c> will be returned. The order of the returned
list is undefined.</p>
</desc>
</func>
<func>
- <name>compile_beam_directory() -> [Result] | {error,Reason}</name>
- <name>compile_beam_directory(Dir) -> [Result] | {error,Reason}</name>
+ <name since="">compile_beam_directory() -> [Result] | {error,Reason}</name>
+ <name since="">compile_beam_directory(Dir) -> [Result] | {error,Reason}</name>
<fsummary>Compile all .beam files in a directory for Cover analysis.</fsummary>
<type>
<v>Dir = string()</v>
@@ -260,14 +272,14 @@
</desc>
</func>
<func>
- <name>analyse() -> {result,Ok,Fail} | {error,not_main_node}</name>
- <name>analyse(Modules) -> OneResult | {result,Ok,Fail} | {error,not_main_node}</name>
- <name>analyse(Analysis) -> {result,Ok,Fail} | {error,not_main_node}</name>
- <name>analyse(Level) -> {result,Ok,Fail} | {error,not_main_node}</name>
- <name>analyse(Modules, Analysis) -> OneResult | {result,Ok,Fail} | {error,not_main_node}</name>
- <name>analyse(Modules, Level) -> OneResult | {result,Ok,Fail} | {error,not_main_node}</name>
- <name>analyse(Analysis, Level) -> {result,Ok,Fail} | {error,not_main_node}</name>
- <name>analyse(Modules, Analysis, Level) -> OneResult | {result,Ok,Fail} | {error,not_main_node}</name>
+ <name since="OTP 18.0">analyse() -> {result,Ok,Fail} | {error,not_main_node}</name>
+ <name since="">analyse(Modules) -> OneResult | {result,Ok,Fail} | {error,not_main_node}</name>
+ <name since="">analyse(Analysis) -> {result,Ok,Fail} | {error,not_main_node}</name>
+ <name since="">analyse(Level) -> {result,Ok,Fail} | {error,not_main_node}</name>
+ <name since="">analyse(Modules, Analysis) -> OneResult | {result,Ok,Fail} | {error,not_main_node}</name>
+ <name since="">analyse(Modules, Level) -> OneResult | {result,Ok,Fail} | {error,not_main_node}</name>
+ <name since="">analyse(Analysis, Level) -> {result,Ok,Fail} | {error,not_main_node}</name>
+ <name since="">analyse(Modules, Analysis, Level) -> OneResult | {result,Ok,Fail} | {error,not_main_node}</name>
<fsummary>Analyse one or more Cover compiled modules.</fsummary>
<type>
<v>Modules = Module | [Module]</v>
@@ -305,10 +317,10 @@
</desc>
</func>
<func>
- <name>analyse_to_file() -> {result,Ok,Fail} | {error,not_main_node}</name>
- <name>analyse_to_file(Modules) -> Answer | {result,Ok,Fail} | {error,not_main_node}</name>
- <name>analyse_to_file(Options) -> {result,Ok,Fail} | {error,not_main_node}</name>
- <name>analyse_to_file(Modules,Options) -> Answer | {result,Ok,Fail} | {error,not_main_node}</name>
+ <name since="OTP 18.0">analyse_to_file() -> {result,Ok,Fail} | {error,not_main_node}</name>
+ <name since="">analyse_to_file(Modules) -> Answer | {result,Ok,Fail} | {error,not_main_node}</name>
+ <name since="">analyse_to_file(Options) -> {result,Ok,Fail} | {error,not_main_node}</name>
+ <name since="">analyse_to_file(Modules,Options) -> Answer | {result,Ok,Fail} | {error,not_main_node}</name>
<fsummary>Detailed coverage analysis of one or more Cover compiled modules.</fsummary>
<type>
<v>Modules = Module | [Module]</v>
@@ -359,10 +371,10 @@
</desc>
</func>
<func>
- <name>async_analyse_to_file(Module) -> </name>
- <name>async_analyse_to_file(Module,Options) -> </name>
- <name>async_analyse_to_file(Module, OutFile) -> </name>
- <name>async_analyse_to_file(Module, OutFile, Options) -> pid()</name>
+ <name since="OTP R14B02">async_analyse_to_file(Module) -> </name>
+ <name since="OTP R14B02">async_analyse_to_file(Module,Options) -> </name>
+ <name since="OTP R14B02">async_analyse_to_file(Module, OutFile) -> </name>
+ <name since="OTP R14B02">async_analyse_to_file(Module, OutFile, Options) -> pid()</name>
<fsummary>Asynchronous call to analyse_to_file.</fsummary>
<type>
<v>Module = atom()</v>
@@ -384,7 +396,7 @@
</desc>
</func>
<func>
- <name>modules() -> [Module] | {error,not_main_node}</name>
+ <name since="">modules() -> [Module] | {error,not_main_node}</name>
<fsummary>Return all Cover compiled modules.</fsummary>
<type>
<v>Module = atom()</v>
@@ -395,7 +407,7 @@
</desc>
</func>
<func>
- <name>imported_modules() -> [Module] | {error,not_main_node}</name>
+ <name since="">imported_modules() -> [Module] | {error,not_main_node}</name>
<fsummary>Return all modules for which there are imported data.</fsummary>
<type>
<v>Module = atom()</v>
@@ -406,7 +418,7 @@
</desc>
</func>
<func>
- <name>imported() -> [File] | {error,not_main_node}</name>
+ <name since="">imported() -> [File] | {error,not_main_node}</name>
<fsummary>Return all imported files.</fsummary>
<type>
<v>File = string()</v>
@@ -416,7 +428,7 @@
</desc>
</func>
<func>
- <name>which_nodes() -> [Node] | {error,not_main_node}</name>
+ <name since="">which_nodes() -> [Node] | {error,not_main_node}</name>
<fsummary>Return all nodes that are part of the coverage analysis.</fsummary>
<type>
<v>Node = atom()</v>
@@ -428,7 +440,7 @@
</desc>
</func>
<func>
- <name>is_compiled(Module) -> {file,File} | false | {error,not_main_node}</name>
+ <name since="">is_compiled(Module) -> {file,File} | false | {error,not_main_node}</name>
<fsummary>Check if a module is Cover compiled.</fsummary>
<type>
<v>Module = atom()</v>
@@ -442,8 +454,8 @@
</desc>
</func>
<func>
- <name>reset(Module) -></name>
- <name>reset() -> ok | {error,not_main_node}</name>
+ <name since="">reset(Module) -></name>
+ <name since="">reset() -> ok | {error,not_main_node}</name>
<fsummary>Reset coverage data for Cover compiled modules.</fsummary>
<type>
<v>Module = atom()</v>
@@ -458,8 +470,8 @@
</desc>
</func>
<func>
- <name>export(ExportFile)</name>
- <name>export(ExportFile,Module) -> ok | {error,Reason}</name>
+ <name since="">export(ExportFile)</name>
+ <name since="">export(ExportFile,Module) -> ok | {error,Reason}</name>
<fsummary>Reset coverage data for Cover compiled modules.</fsummary>
<type>
<v>ExportFile = string()</v>
@@ -470,7 +482,7 @@
<p>Exports the current coverage data for <c>Module</c> to the
file <c>ExportFile</c>. It is recommended to name the
<c>ExportFile</c> with the extension <c>.coverdata</c>, since
- other filenames can not be read by the web based interface to
+ other filenames cannot be read by the web based interface to
cover.</p>
<p>If <c>Module</c> is not given, data for all Cover compiled
or earlier imported modules is exported.</p>
@@ -480,7 +492,7 @@
</desc>
</func>
<func>
- <name>import(ExportFile) -> ok | {error,Reason}</name>
+ <name since="">import(ExportFile) -> ok | {error,Reason}</name>
<fsummary>Reset coverage data for Cover compiled modules.</fsummary>
<type>
<v>ExportFile = string()</v>
@@ -496,7 +508,7 @@
<p>Coverage data from several export files can be imported
into one system. The coverage data is then added up when
analysing.</p>
- <p>Coverage data for a module can not be imported from the
+ <p>Coverage data for a module cannot be imported from the
same file twice unless the module is first reset or
compiled. The check is based on the filename, so you can
easily fool the system by renaming your export file.</p>
@@ -504,14 +516,14 @@
</desc>
</func>
<func>
- <name>stop() -> ok | {error,not_main_node}</name>
+ <name since="">stop() -> ok | {error,not_main_node}</name>
<fsummary>Stop Cover.</fsummary>
<desc>
<p>Stops the Cover server and unloads all Cover compiled code.</p>
</desc>
</func>
<func>
- <name>stop(Nodes) -> ok | {error,not_main_node}</name>
+ <name since="">stop(Nodes) -> ok | {error,not_main_node}</name>
<fsummary>Stop Cover on remote nodes.</fsummary>
<type>
<v>Nodes = [atom()]</v>
@@ -523,7 +535,7 @@
</desc>
</func>
<func>
- <name>flush(Nodes) -> ok | {error,not_main_node}</name>
+ <name since="OTP R16B">flush(Nodes) -> ok | {error,not_main_node}</name>
<fsummary>Collect cover data from remote nodes.</fsummary>
<type>
<v>Nodes = [atom()]</v>
diff --git a/lib/tools/doc/src/cprof.xml b/lib/tools/doc/src/cprof.xml
index df0acbe617..b6af8b6d28 100644
--- a/lib/tools/doc/src/cprof.xml
+++ b/lib/tools/doc/src/cprof.xml
@@ -34,7 +34,7 @@
<rev>PA1</rev>
<file>cprof.sgml</file>
</header>
- <module>cprof</module>
+ <module since="">cprof</module>
<modulesummary>A simple Call Count Profiling Tool using breakpoints for minimal runtime performance impact.</modulesummary>
<description>
<p>The <c>cprof</c> module is used to profile a program
@@ -65,10 +65,10 @@
</description>
<funcs>
<func>
- <name>analyse() -> {AllCallCount, ModAnalysisList}</name>
- <name>analyse(Limit) -> {AllCallCount, ModAnalysisList}</name>
- <name>analyse(Mod) -> ModAnalysis</name>
- <name>analyse(Mod, Limit) -> ModAnalysis</name>
+ <name since="">analyse() -> {AllCallCount, ModAnalysisList}</name>
+ <name since="">analyse(Limit) -> {AllCallCount, ModAnalysisList}</name>
+ <name since="">analyse(Mod) -> ModAnalysis</name>
+ <name since="">analyse(Mod, Limit) -> ModAnalysis</name>
<fsummary>Collect and analyse call counters.</fsummary>
<type>
<v>Limit = integer()</v>
@@ -122,7 +122,7 @@
</desc>
</func>
<func>
- <name>pause() -> integer()</name>
+ <name since="">pause() -> integer()</name>
<fsummary>Pause running call count trace for all functions.</fsummary>
<desc>
<p>Pause call count tracing for all functions in all modules
@@ -137,9 +137,9 @@
</desc>
</func>
<func>
- <name>pause(FuncSpec) -> integer()</name>
- <name>pause(Mod, Func) -> integer()</name>
- <name>pause(Mod, Func, Arity) -> integer()</name>
+ <name since="">pause(FuncSpec) -> integer()</name>
+ <name since="">pause(Mod, Func) -> integer()</name>
+ <name since="">pause(Mod, Func, Arity) -> integer()</name>
<fsummary>Pause running call count trace for matching functions.</fsummary>
<type>
<v>FuncSpec = Mod | {Mod,Func,Arity}, {FS}</v>
@@ -167,10 +167,10 @@
</desc>
</func>
<func>
- <name>restart() -> integer()</name>
- <name>restart(FuncSpec) -> integer()</name>
- <name>restart(Mod, Func) -> integer()</name>
- <name>restart(Mod, Func, Arity) -> integer()</name>
+ <name since="">restart() -> integer()</name>
+ <name since="">restart(FuncSpec) -> integer()</name>
+ <name since="">restart(Mod, Func) -> integer()</name>
+ <name since="">restart(Mod, Func, Arity) -> integer()</name>
<fsummary>Restart existing call counters for matching functions.</fsummary>
<type>
<v>FuncSpec = Mod | {Mod,Func,Arity}, {FS}</v>
@@ -197,7 +197,7 @@
</desc>
</func>
<func>
- <name>start() -> integer()</name>
+ <name since="">start() -> integer()</name>
<fsummary>Start call count tracing for all functions.</fsummary>
<desc>
<p>Start call count tracing for all functions in all modules,
@@ -212,9 +212,9 @@
</desc>
</func>
<func>
- <name>start(FuncSpec) -> integer()</name>
- <name>start(Mod, Func) -> integer()</name>
- <name>start(Mod, Func, Arity) -> integer()</name>
+ <name since="">start(FuncSpec) -> integer()</name>
+ <name since="">start(Mod, Func) -> integer()</name>
+ <name since="">start(Mod, Func, Arity) -> integer()</name>
<fsummary>Start call count tracing for matching functions.</fsummary>
<type>
<v>FuncSpec = Mod | {Mod,Func,Arity}, {FS}</v>
@@ -240,7 +240,7 @@
</desc>
</func>
<func>
- <name>stop() -> integer()</name>
+ <name since="">stop() -> integer()</name>
<fsummary>Stop call count tracing for all functions.</fsummary>
<desc>
<p>Stop call count tracing for all functions in all modules,
@@ -255,9 +255,9 @@
</desc>
</func>
<func>
- <name>stop(FuncSpec) -> integer()</name>
- <name>stop(Mod, Func) -> integer()</name>
- <name>stop(Mod, Func, Arity) -> integer()</name>
+ <name since="">stop(FuncSpec) -> integer()</name>
+ <name since="">stop(Mod, Func) -> integer()</name>
+ <name since="">stop(Mod, Func, Arity) -> integer()</name>
<fsummary>Stop call count tracing for matching functions.</fsummary>
<type>
<v>FuncSpec = Mod | {Mod,Func,Arity}, {FS}</v>
diff --git a/lib/tools/doc/src/eprof.xml b/lib/tools/doc/src/eprof.xml
index f098b7d39e..c9e4edd991 100644
--- a/lib/tools/doc/src/eprof.xml
+++ b/lib/tools/doc/src/eprof.xml
@@ -28,7 +28,7 @@
<date></date>
<rev></rev>
</header>
- <module>eprof</module>
+ <module since="">eprof</module>
<modulesummary>A Time Profiling Tool for Erlang</modulesummary>
<description>
<p>The module <c>eprof</c> provides a set of functions for time
@@ -40,7 +40,7 @@
</description>
<funcs>
<func>
- <name>start() -> {ok,Pid} | {error,Reason}</name>
+ <name since="">start() -> {ok,Pid} | {error,Reason}</name>
<fsummary>Start Eprof.</fsummary>
<type>
<v>Pid = pid()</v>
@@ -51,9 +51,9 @@
</desc>
</func>
<func>
- <name>start_profiling(Rootset) -> profiling | {error, Reason}</name>
- <name>start_profiling(Rootset,Pattern) -> profiling | {error, Reason}</name>
- <name>start_profiling(Rootset,Pattern,Options) -> profiling | {error, Reason}</name>
+ <name since="">start_profiling(Rootset) -> profiling | {error, Reason}</name>
+ <name since="OTP R14B">start_profiling(Rootset,Pattern) -> profiling | {error, Reason}</name>
+ <name since="OTP R16B01">start_profiling(Rootset,Pattern,Options) -> profiling | {error, Reason}</name>
<fsummary>Start profiling.</fsummary>
<type>
<v>Rootset = [atom() | pid()]</v>
@@ -79,7 +79,7 @@
</desc>
</func>
<func>
- <name>stop_profiling() -> profiling_stopped | profiling_already_stopped</name>
+ <name since="">stop_profiling() -> profiling_stopped | profiling_already_stopped</name>
<fsummary>Stop profiling.</fsummary>
<desc>
<p>Stops profiling started with <c>start_profiling/1</c> or
@@ -87,14 +87,14 @@
</desc>
</func>
<func>
- <name>profile(Fun) -> profiling | {error, Reason}</name>
- <name>profile(Fun, Options) -> profiling | {error, Reason}</name>
- <name>profile(Rootset) -> profiling | {error, Reason}</name>
- <name>profile(Rootset,Fun) -> {ok, Value} | {error,Reason}</name>
- <name>profile(Rootset,Fun,Pattern) -> {ok, Value} | {error, Reason}</name>
- <name>profile(Rootset,Module,Function,Args) -> {ok, Value} | {error, Reason}</name>
- <name>profile(Rootset,Module,Function,Args,Pattern) -> {ok, Value} | {error, Reason}</name>
- <name>profile(Rootset,Module,Function,Args,Pattern,Options) -> {ok, Value} | {error, Reason}</name>
+ <name since="">profile(Fun) -> profiling | {error, Reason}</name>
+ <name since="">profile(Fun, Options) -> profiling | {error, Reason}</name>
+ <name since="">profile(Rootset) -> profiling | {error, Reason}</name>
+ <name since="">profile(Rootset,Fun) -> {ok, Value} | {error,Reason}</name>
+ <name since="OTP R14B">profile(Rootset,Fun,Pattern) -> {ok, Value} | {error, Reason}</name>
+ <name since="">profile(Rootset,Module,Function,Args) -> {ok, Value} | {error, Reason}</name>
+ <name since="OTP R14B">profile(Rootset,Module,Function,Args,Pattern) -> {ok, Value} | {error, Reason}</name>
+ <name since="OTP R16B01">profile(Rootset,Module,Function,Args,Pattern,Options) -> {ok, Value} | {error, Reason}</name>
<fsummary>Start profiling.</fsummary>
<type>
<v>Rootset = [atom() | pid()]</v>
@@ -128,9 +128,9 @@
</desc>
</func>
<func>
- <name>analyze() -> ok</name>
- <name>analyze(Type) -> ok</name>
- <name>analyze(Type,Options) -> ok</name>
+ <name since="OTP R14B">analyze() -> ok</name>
+ <name since="OTP R14B">analyze(Type) -> ok</name>
+ <name since="OTP R14B">analyze(Type,Options) -> ok</name>
<fsummary>Display profiling results per process.</fsummary>
<type>
<v>Type = procs | total</v>
@@ -152,7 +152,7 @@
</desc>
</func>
<func>
- <name>log(File) -> ok</name>
+ <name since="">log(File) -> ok</name>
<fsummary>Activate logging of <c>eprof</c>printouts.</fsummary>
<type>
<v>File = atom() | string()</v>
@@ -164,7 +164,7 @@
</desc>
</func>
<func>
- <name>stop() -> stopped</name>
+ <name since="">stop() -> stopped</name>
<fsummary>Stop Eprof.</fsummary>
<desc>
<p>Stops the Eprof server.</p>
diff --git a/lib/tools/doc/src/fprof.xml b/lib/tools/doc/src/fprof.xml
index 4c9e48045e..4bb8862016 100644
--- a/lib/tools/doc/src/fprof.xml
+++ b/lib/tools/doc/src/fprof.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2001</year><year>2016</year>
+ <year>2001</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,7 +32,7 @@
<rev>PA1</rev>
<file>fprof.sgml</file>
</header>
- <module>fprof</module>
+ <module since="">fprof</module>
<modulesummary>A Time Profiling Tool using trace to file for minimal runtime performance impact.</modulesummary>
<description>
<p>This module is used to profile a program
@@ -101,7 +101,7 @@
</description>
<funcs>
<func>
- <name>start() -> {ok, Pid} | {error, {already_started, Pid}}</name>
+ <name since="">start() -> {ok, Pid} | {error, {already_started, Pid}}</name>
<fsummary>Starts the <c>fprof</c>&nbsp;server.</fsummary>
<type>
<v>Pid = pid()</v>
@@ -117,14 +117,14 @@
</desc>
</func>
<func>
- <name>stop() -> ok</name>
+ <name since="">stop() -> ok</name>
<fsummary>Same as <c>stop(normal)</c>.</fsummary>
<desc>
<p>Same as <c>stop(normal)</c>.</p>
</desc>
</func>
<func>
- <name>stop(Reason) -> ok</name>
+ <name since="">stop(Reason) -> ok</name>
<fsummary>Stops the <c>fprof</c>&nbsp;server.</fsummary>
<type>
<v>Reason = term()</v>
@@ -149,7 +149,7 @@
</desc>
</func>
<func>
- <name>apply(Func, Args) -> term()</name>
+ <name since="">apply(Func, Args) -> term()</name>
<fsummary>Same as <c>apply(Func, Args, [])</c>.</fsummary>
<type>
<v>Func = function() | {Module, Function}</v>
@@ -162,7 +162,7 @@
</desc>
</func>
<func>
- <name>apply(Module, Function, Args) -> term()</name>
+ <name since="">apply(Module, Function, Args) -> term()</name>
<fsummary>Same as <c>apply({Module, Function}, Args, [])</c>.</fsummary>
<type>
<v>Args = [term()]</v>
@@ -174,7 +174,7 @@
</desc>
</func>
<func>
- <name>apply(Func, Args, OptionList) -> term()</name>
+ <name since="">apply(Func, Args, OptionList) -> term()</name>
<fsummary>Calls <c>erlang:apply(Func, Args)</c>surrounded by<c>trace([start | OptionList])</c>and<c>trace(stop)</c>.</fsummary>
<type>
<v>Func = function() | {Module, Function}</v>
@@ -210,7 +210,7 @@
</desc>
</func>
<func>
- <name>apply(Module, Function, Args, OptionList) -> term()</name>
+ <name since="">apply(Module, Function, Args, OptionList) -> term()</name>
<fsummary>Same as <c>apply({Module, Function}, Args, OptionList)</c>.</fsummary>
<type>
<v>Module = atom()</v>
@@ -228,7 +228,7 @@
</desc>
</func>
<func>
- <name>trace(start, Filename) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
+ <name since="">trace(start, Filename) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
<fsummary>Same as <c>trace([start, {file, Filename}])</c>.</fsummary>
<type>
<v>Reason = term()</v>
@@ -238,7 +238,7 @@
</desc>
</func>
<func>
- <name>trace(verbose, Filename) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
+ <name since="">trace(verbose, Filename) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
<fsummary>Same as <c>trace([start, verbose, {file, Filename}])</c>.</fsummary>
<type>
<v>Reason = term()</v>
@@ -249,7 +249,7 @@
</desc>
</func>
<func>
- <name>trace(OptionName, OptionValue) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
+ <name since="">trace(OptionName, OptionValue) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
<fsummary>Same as <c>trace([{OptionName, OptionValue}])</c>.</fsummary>
<type>
<v>OptionName = atom()</v>
@@ -262,7 +262,7 @@
</desc>
</func>
<func>
- <name>trace(verbose) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
+ <name since="">trace(verbose) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
<fsummary>Same as <c>trace([start, verbose])</c>.</fsummary>
<type>
<v>Reason = term()</v>
@@ -272,7 +272,7 @@
</desc>
</func>
<func>
- <name>trace(OptionName) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
+ <name since="">trace(OptionName) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
<fsummary>Same as <c>trace([OptionName])</c>.</fsummary>
<type>
<v>OptionName = atom()</v>
@@ -283,7 +283,7 @@
</desc>
</func>
<func>
- <name>trace({OptionName, OptionValue}) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
+ <name since="">trace({OptionName, OptionValue}) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
<fsummary>Same as <c>trace([{OptionName, OptionValue}])</c>.</fsummary>
<type>
<v>OptionName = atom()</v>
@@ -296,7 +296,7 @@
</desc>
</func>
<func>
- <name>trace([Option]) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
+ <name since="">trace([Option]) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
<fsummary>Starts or stops tracing.</fsummary>
<type>
<v>Option = start | stop | {procs, PidSpec} | {procs, [PidSpec]} | verbose | {verbose, bool()} | file | {file, Filename} | {tracer, Tracer}</v>
@@ -328,10 +328,16 @@
purposes. This option is only
allowed with the <c>start</c> option.</item>
<tag><c>cpu_time</c>| <c>{cpu_time, bool()}</c></tag>
- <item>The options <c>cpu_time</c> or <c>{cpu_time, true></c>
+ <item>The options <c>cpu_time</c> or <c>{cpu_time, true}</c>
makes the timestamps in the trace be in CPU time instead
of wallclock time which is the default. This option is
- only allowed with the <c>start</c> option.</item>
+ only allowed with the <c>start</c> option.
+ <warning><p>Getting correct values out of cpu_time can be difficult.
+ The best way to get correct values is to run using a single
+ scheduler and bind that scheduler to a specific CPU,
+ i.e. <c>erl +S 1 +sbt db</c>.</p>
+ </warning>
+ </item>
<tag><c>{procs, PidSpec}</c>| <c>{procs, [PidSpec]}</c></tag>
<item>Specifies which processes that shall be traced. If
this option is not given, the calling process is
@@ -354,7 +360,7 @@
</desc>
</func>
<func>
- <name>profile() -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
+ <name since="">profile() -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
<fsummary>Same as <c>profile([])</c>.</fsummary>
<type>
<v>Reason = term()</v>
@@ -364,7 +370,7 @@
</desc>
</func>
<func>
- <name>profile(OptionName, OptionValue) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
+ <name since="">profile(OptionName, OptionValue) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
<fsummary>Same as <c>profile([{OptionName, OptionValue}])</c>.</fsummary>
<type>
<v>OptionName = atom()</v>
@@ -377,7 +383,7 @@
</desc>
</func>
<func>
- <name>profile(OptionName) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
+ <name since="">profile(OptionName) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
<fsummary>Same as <c>profile([OptionName])</c>.</fsummary>
<type>
<v>OptionName = atom()</v>
@@ -388,7 +394,7 @@
</desc>
</func>
<func>
- <name>profile({OptionName, OptionValue}) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
+ <name since="">profile({OptionName, OptionValue}) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
<fsummary>Same as <c>profile([{OptionName, OptionValue}])</c>.</fsummary>
<type>
<v>OptionName = atom()</v>
@@ -401,7 +407,7 @@
</desc>
</func>
<func>
- <name>profile([Option]) -> ok | {ok, Tracer} | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
+ <name since="">profile([Option]) -> ok | {ok, Tracer} | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
<fsummary>Compiles a trace into raw profile data held by the <c>fprof</c>&nbsp;server.</fsummary>
<type>
<v>Option = file | {file, Filename} | dump | {dump, Dump} | append | start | stop</v>
@@ -459,7 +465,7 @@
</desc>
</func>
<func>
- <name>analyse() -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
+ <name since="">analyse() -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
<fsummary>Same as <c>analyse([])</c>.</fsummary>
<type>
<v>Reason = term()</v>
@@ -469,7 +475,7 @@
</desc>
</func>
<func>
- <name>analyse(OptionName, OptionValue) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
+ <name since="">analyse(OptionName, OptionValue) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
<fsummary>Same as <c>analyse([{OptionName, OptionValue}])</c>.</fsummary>
<type>
<v>OptionName = atom()</v>
@@ -482,7 +488,7 @@
</desc>
</func>
<func>
- <name>analyse(OptionName) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
+ <name since="">analyse(OptionName) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
<fsummary>Same as <c>analyse([OptionName])</c>.</fsummary>
<type>
<v>OptionName = atom()</v>
@@ -493,7 +499,7 @@
</desc>
</func>
<func>
- <name>analyse({OptionName, OptionValue}) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
+ <name since="">analyse({OptionName, OptionValue}) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
<fsummary>Same as <c>analyse([{OptionName, OptionValue}])</c>.</fsummary>
<type>
<v>OptionName = atom()</v>
@@ -506,7 +512,7 @@
</desc>
</func>
<func>
- <name>analyse([Option]) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
+ <name since="">analyse([Option]) -> ok | {error, Reason} | {'EXIT', ServerPid, Reason}</name>
<fsummary>Analyses raw profile data in the <c>fprof</c>&nbsp;server.</fsummary>
<type>
<v>Option = dest | {dest, Dest} | append | {cols, Cols} | callers | {callers, bool()} | no_callers | {sort, SortSpec} | totals | {totals, bool()} | details | {details, bool()} | no_details</v>
diff --git a/lib/tools/doc/src/instrument.xml b/lib/tools/doc/src/instrument.xml
index bb6f9b6100..7e9cbaebb0 100644
--- a/lib/tools/doc/src/instrument.xml
+++ b/lib/tools/doc/src/instrument.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1998</year><year>2016</year>
+ <year>1998</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,7 +32,7 @@
<rev>PA1</rev>
<file>instrument.sgml</file>
</header>
- <module>instrument</module>
+ <module since="">instrument</module>
<modulesummary>Analysis and Utility Functions for Instrumentation</modulesummary>
<description>
<p>The module <c>instrument</c> contains support for studying the resource
@@ -41,387 +41,193 @@
<note>
<p>Note that this whole module is experimental, and the representations
used as well as the functionality is likely to change in the future.</p>
- <p>The <c>instrument</c> module interface was slightly changed in
- Erlang/OTP R9C.</p>
</note>
- <p>To start an Erlang runtime system with instrumentation, use the
- <c>+Mi*</c> set of command-line arguments to the <c>erl</c> command (see
- the erts_alloc(3) and erl(1) man pages).</p>
- <p>The basic object of study in the case of memory allocation is a memory
- allocation map. A memory allocation map contains a list of descriptors
- for each allocated memory block. Currently, a descriptor is a 4-tuple</p>
- <pre>
- {TypeNo, Address, Size, PidDesc} </pre>
- <p>where <c>TypeNo</c> is the memory block type number, <c>Address</c>
- is its place in memory, and <c>Size</c> is its size, in bytes.
- <c>PidDesc</c> is either a tuple <c>{X,Y,Z}</c> identifying the
- process which was executing when the block was allocated, or
- <c>undefined</c> if no process was executing. The pid tuple
- <c>{X,Y,Z}</c> can be transformed into a real pid by usage of the
- <c>c:pid/3</c> function.</p>
- <p>Various details about memory allocation:</p>
- <p>Memory blocks are allocated both on the heap segment and on other memory
- segments. This can cause the instrumentation functionality to report
- very large holes. Currently the instrumentation functionality doesn't
- provide any support for distinguishing between holes between memory
- segments, and holes between allocated blocks inside memory segments.
- The current size of the process cannot be obtained from within Erlang,
- but can be seen with one of the system statistics tools, e.g.,
- <c>ps</c> or <c>top</c>. The Solaris utility <c>pmap</c> can be
- useful. It reports currently mapped memory segments. </p>
- <p>Overhead for instrumentation: When the emulator has been started with
- the <seealso marker="erts:erts_alloc#Mim">"+Mim true"</seealso>
- flag, each block is preceded by a 24 bytes large
- header on a 32-bit machine and a 48 bytes large header on a 64-bit
- machine. When the emulator has been started with the
- <seealso marker="erts:erts_alloc#Mis">"+Mis true"</seealso>
- flag, each block is preceded by an 8 bytes large header. These are the header
- sizes used by the Erlang 5.3/OTP R9C emulator. Other versions of the
- emulator may use other header sizes. The function
- <seealso marker="#block_header_size/1">block_header_size/1</seealso>
- can be used for retrieving the header size used for a specific memory
- allocation map. The time overhead for managing the instrumentation
- data is small.</p>
- <p>Sizes presented by the instrumentation functionality are (by the
- emulator) requested sizes, i.e. neither instrumentation headers nor
- headers used by allocators are included.</p>
</description>
+ <datatypes>
+ <datatype>
+ <name name="block_histogram"/>
+ <desc>
+ <p>A histogram of block sizes where each interval's upper bound is
+ twice as high as the one before it.</p>
+ <p>The upper bound of the first interval is provided by the function
+ that returned the histogram, and the last interval has no upper
+ bound.</p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="allocation_summary"/>
+ <desc>
+ <p>A summary of allocated block sizes (including their headers) grouped
+ by their <c><anno>Origin</anno></c> and <c><anno>Type</anno></c>.</p>
+ <p><c><anno>Origin</anno></c> is generally which NIF or driver that
+ allocated the blocks, or 'system' if it could not be determined.</p>
+ <p><c><anno>Type</anno></c> is the allocation category that the blocks
+ belong to, e.g. <c>db_term</c>, <c>message</c> or <c>binary</c>.</p>
+ <p>If one or more carriers could not be scanned in full without harming
+ the responsiveness of the system, <c><anno>UnscannedSize</anno></c>
+ is the number of bytes that had to be skipped.</p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="carrier_info_list"/>
+ <desc>
+ <p><c><anno>AllocatorType</anno></c> is the type of the allocator that
+ employs this carrier.</p>
+ <p><c><anno>TotalSize</anno></c> is the total size of the carrier,
+ including its header.</p>
+ <p><c><anno>AllocatedSize</anno></c> is the combined size of the
+ carrier's allocated blocks, including their headers.</p>
+ <p><c><anno>AllocatedCount</anno></c> is the number of allocated
+ blocks in the carrier.</p>
+ <p><c><anno>InPool</anno></c> is whether the carrier is in the
+ migration pool.</p>
+ <p><c><anno>FreeBlocks</anno></c> is a histogram of the free block
+ sizes in the carrier.</p>
+ <p>If the carrier could not be scanned in full without harming the
+ responsiveness of the system, <c><anno>UnscannedSize</anno></c> is
+ the number of bytes that had to be skipped.</p>
+ </desc>
+ </datatype>
+ </datatypes>
<funcs>
+
<func>
- <name>allocator_descr(MemoryData, TypeNo) -> AllocDescr | invalid_type | "unknown"</name>
- <fsummary>Returns a allocator description</fsummary>
- <type>
- <v>MemoryData = {term(), AllocList}</v>
- <v>AllocList = [Desc]</v>
- <v>Desc = {int(), int(), int(), PidDesc}</v>
- <v>PidDesc = {int(), int(), int()} | undefined</v>
- <v>TypeNo = int()</v>
- <v>AllocDescr = atom() | string()</v>
- </type>
- <desc>
- <p>Returns the allocator description of the allocator that
- manages memory blocks of type number <c>TypeNo</c> used in
- <c>MemoryData</c>.
- Valid <c>TypeNo</c>s are in the range returned by
- <seealso marker="#type_no_range/1">type_no_range/1</seealso> on
- this specific memory allocation map. If <c>TypeNo</c> is an
- invalid integer, <c>invalid_type</c> is returned.</p>
- </desc>
- </func>
- <func>
- <name>block_header_size(MemoryData) -> int()</name>
- <fsummary>Returns the memory block header size used by the emulator that generated the memory allocation map</fsummary>
- <type>
- <v>MemoryData = {term(), AllocList}</v>
- <v>AllocList = [Desc]</v>
- <v>Desc = {int(), int(), int(), PidDesc}</v>
- <v>PidDesc = {int(), int(), int()} | undefined</v>
- </type>
- <desc>
- <marker id="block_header_size_1"></marker>
- <p>Returns the memory block header size used by the
- emulator that generated the memory allocation map. The block
- header size may differ between different emulators.</p>
- </desc>
- </func>
- <func>
- <name>class_descr(MemoryData, TypeNo) -> ClassDescr | invalid_type | "unknown"</name>
- <fsummary>Returns a allocator description</fsummary>
- <type>
- <v>MemoryData = {term(), AllocList}</v>
- <v>AllocList = [Desc]</v>
- <v>Desc = {int(), int(), int(), PidDesc}</v>
- <v>PidDesc = {int(), int(), int()} | undefined</v>
- <v>TypeNo = int()</v>
- <v>ClassDescr = atom() | string()</v>
- </type>
- <desc>
- <p>Returns the class description of the class that
- the type number <c>TypeNo</c> used in <c>MemoryData</c> belongs
- to.
- Valid <c>TypeNo</c>s are in the range returned by
- <seealso marker="#type_no_range/1">type_no_range/1</seealso> on
- this specific memory allocation map. If <c>TypeNo</c> is an
- invalid integer, <c>invalid_type</c> is returned.</p>
- </desc>
- </func>
- <func>
- <name>descr(MemoryData) -> DescrMemoryData</name>
- <fsummary>Replace type numbers in memory allocation map with type descriptions</fsummary>
- <type>
- <v>MemoryData = {term(), AllocList}</v>
- <v>AllocList = [Desc]</v>
- <v>Desc = {int(), int(), int(), PidDesc}</v>
- <v>PidDesc = {int(), int(), int()} | undefined</v>
- <v>DescrMemoryData = {term(), DescrAllocList}</v>
- <v>DescrAllocList = [DescrDesc]</v>
- <v>DescrDesc = {TypeDescr, int(), int(), DescrPidDesc}</v>
- <v>TypeDescr = atom() | string()</v>
- <v>DescrPidDesc = pid() | undefined</v>
- </type>
- <desc>
- <p>Returns a memory allocation map where the type numbers (first
- element of <c>Desc</c>) have been replaced by type descriptions,
- and pid tuples (fourth element of <c>Desc</c>) have been
- replaced by real pids.</p>
- </desc>
- </func>
- <func>
- <name>holes(MemoryData) -> ok</name>
- <fsummary>Print out the sizes of unused memory blocks</fsummary>
- <type>
- <v>MemoryData = {term(), AllocList}</v>
- <v>AllocList = [Desc]</v>
- <v>Desc = {int(), int(), int(), PidDesc}</v>
- <v>PidDesc = {int(), int(), int()} | undefined</v>
- </type>
- <desc>
- <p>Prints out the size of each hole (i.e., the space between
- allocated blocks) on the terminal. <em>NOTE:</em> Really large holes
- are probably holes between memory segments.
- The memory allocation map has to be sorted (see
- <seealso marker="#sort/1">sort/1</seealso>).</p>
- </desc>
- </func>
- <func>
- <name>mem_limits(MemoryData) -> {Low, High}</name>
- <fsummary>Return lowest and highest memory address used</fsummary>
- <type>
- <v>MemoryData = {term(), AllocList}</v>
- <v>AllocList = [Desc]</v>
- <v>Desc = {int(), int(), int(), PidDesc}</v>
- <v>PidDesc = {int(), int(), int()} | undefined</v>
- <v>Low = High = int()</v>
- </type>
- <desc>
- <p>Returns a tuple <c>{Low, High}</c> indicating
- the lowest and highest address used.
- The memory allocation map has to be sorted (see
- <seealso marker="#sort/1">sort/1</seealso>).</p>
- </desc>
- </func>
- <func>
- <name>memory_data() -> MemoryData | false</name>
- <fsummary>Return the current memory allocation map</fsummary>
- <type>
- <v>MemoryData = {term(), AllocList}</v>
- <v>AllocList = [Desc]</v>
- <v>Desc = {int(), int(), int(), PidDesc}</v>
- <v>PidDesc = {int(), int(), int()} | undefined</v>
- </type>
- <desc>
- <p>Returns <c>MemoryData</c> (a the memory allocation map)
- if the emulator has been started with the "<c>+Mim true</c>"
- command-line argument; otherwise, <c>false</c>. <em>NOTE:</em><c>memory_data/0</c> blocks execution of other processes while
- the data is collected. The time it takes to collect the data can
- be substantial.</p>
- </desc>
- </func>
- <func>
- <name>memory_status(StatusType) -> [StatusInfo] | false</name>
- <fsummary>Return current memory allocation status</fsummary>
- <type>
- <v>StatusType = total | allocators | classes | types</v>
- <v>StatusInfo = {About, [Info]}</v>
- <v>About = atom()</v>
- <v>Info = {InfoName, Current, MaxSinceLast, MaxEver}</v>
- <v>InfoName = sizes|blocks</v>
- <v>Current = int()</v>
- <v>MaxSinceLast = int()</v>
- <v>MaxEver = int()</v>
- </type>
- <desc>
- <p>Returns a list of <c>StatusInfo</c> if the emulator has been
- started with the "<c>+Mis true</c>" or "<c>+Mim true</c>"
- command-line argument; otherwise, <c>false</c>. </p>
- <p>See the
- <seealso marker="#read_memory_status/1">read_memory_status/1</seealso>
- function for a description of the <c>StatusInfo</c> term.</p>
- </desc>
- </func>
- <func>
- <name>read_memory_data(File) -> MemoryData | {error, Reason}</name>
- <fsummary>Read memory allocation map</fsummary>
- <type>
- <v>File = string()</v>
- <v>MemoryData = {term(), AllocList}</v>
- <v>AllocList = [Desc]</v>
- <v>Desc = {int(), int(), int(), PidDesc}</v>
- <v>PidDesc = {int(), int(), int()} | undefined</v>
- </type>
+ <name name="allocations" arity="0" since="OTP 21.0"/>
+ <fsummary>Return a summary of all allocations in the system.</fsummary>
<desc>
- <marker id="read_memory_data_1"></marker>
- <p>Reads a memory allocation map from the file <c>File</c> and
- returns it. The file is assumed to have been created by
- <c>store_memory_data/1</c>. The error codes are the same as for
- <c>file:consult/1</c>.</p>
+ <p>Shorthand for
+ <seealso marker="#allocations/1"><c>allocations(#{})</c>.</seealso></p>
</desc>
</func>
+
<func>
- <name>read_memory_status(File) -> MemoryStatus | {error, Reason}</name>
- <fsummary>Read memory allocation status from a file</fsummary>
- <type>
- <v>File = string()</v>
- <v>MemoryStatus = [{StatusType, [StatusInfo]}]</v>
- <v>StatusType = total | allocators | classes | types</v>
- <v>StatusInfo = {About, [Info]}</v>
- <v>About = atom()</v>
- <v>Info = {InfoName, Current, MaxSinceLast, MaxEver}</v>
- <v>InfoName = sizes|blocks</v>
- <v>Current = int()</v>
- <v>MaxSinceLast = int()</v>
- <v>MaxEver = int()</v>
- </type>
- <desc>
- <marker id="read_memory_status_1"></marker>
- <p>Reads memory allocation status from the file <c>File</c> and
- returns it. The file is assumed to have been created by
- <c>store_memory_status/1</c>. The error codes are the same as
- for <c>file:consult/1</c>.</p>
- <p>When <c>StatusType</c> is <c>allocators</c>, <c>About</c> is
- the allocator that the information is about. When
- <c>StatusType</c> is <c>types</c>, <c>About</c> is
- the memory block type that the information is about. Memory
- block types are not described other than by their name and may
- vary between emulators. When <c>StatusType</c> is <c>classes</c>,
- <c>About</c> is the memory block type class that information is
- presented about. Memory block types are classified after their
- use. Currently the following classes exist:</p>
+ <name name="allocations" arity="1" since="OTP 21.0"/>
+ <fsummary>Return a summary of all allocations filtered by allocator type
+ and scheduler id.</fsummary>
+ <desc>
+ <p>Returns a summary of all tagged allocations in the system,
+ optionally filtered by allocator type and scheduler id.</p>
+ <p>Only binaries and allocations made by NIFs and drivers are tagged by
+ default, but this can be configured an a per-allocator basis with the
+ <seealso marker="erts:erts_alloc#M_atags"><c>+M&lt;S&gt;atags</c>
+ </seealso> emulator option.</p>
+ <p>If the specified allocator types are not enabled, the call will fail
+ with <c>{error, not_enabled}</c>.</p>
+ <p>The following options can be used:</p>
<taglist>
- <tag><c>process_data</c></tag>
- <item>Erlang process specific data.</item>
- <tag><c>binary_data</c></tag>
- <item>Erlang binaries.</item>
- <tag><c>atom_data</c></tag>
- <item>Erlang atoms.</item>
- <tag><c>code_data</c></tag>
- <item>Erlang code.</item>
- <tag><c>system_data</c></tag>
- <item>Other data used by the system</item>
+ <tag><c>allocator_types</c></tag>
+ <item>
+ <p>The allocator types that will be searched. Note that blocks can
+ move freely between allocator types, so restricting the search to
+ certain allocators may return unexpected types (e.g. process
+ heaps when searching binary_alloc), or hide blocks that were
+ migrated out.</p>
+ <p>Defaults to all <c>alloc_util</c> allocators.</p>
+ </item>
+ <tag><c>scheduler_ids</c></tag>
+ <item>
+ <p>The scheduler ids whose allocator instances will be searched. A
+ scheduler id of 0 will refer to the global instance that is not
+ tied to any particular scheduler. Defaults to all schedulers and
+ the global instance.</p>
+ </item>
+ <tag><c>histogram_start</c></tag>
+ <item>
+ <p>The upper bound of the first interval in the allocated block
+ size histograms. Defaults to 128.</p>
+ </item>
+ <tag><c>histogram_width</c></tag>
+ <item>
+ <p>The number of intervals in the allocated block size histograms.
+ Defaults to 18.</p>
+ </item>
</taglist>
- <p>When <c>InfoName</c> is <c>sizes</c>, <c>Current</c>,
- <c>MaxSinceLast</c>, and <c>MaxEver</c> are, respectively, current
- size, maximum size since last call to
- <c>store_memory_status/1</c> or <c>memory_status/1</c> with the
- specific <c>StatusType</c>, and maximum size since the emulator
- was started. When <c>InfoName</c> is <c>blocks</c>, <c>Current</c>,
- <c>MaxSinceLast</c>, and <c>MaxEver</c> are, respectively, current
- number of blocks, maximum number of blocks since last call to
- <c>store_memory_status/1</c> or <c>memory_status/1</c> with the
- specific <c>StatusType</c>, and maximum number of blocks since the
- emulator was started. </p>
- <p><em>NOTE:</em>A memory block is accounted for at
- "the first level" allocator. E.g. <c>fix_alloc</c> allocates its
- memory pools via <c>ll_alloc</c>. When a <c>fix_alloc</c> block
- is allocated, neither the block nor the pool in which it resides
- are accounted for as memory allocated via <c>ll_alloc</c> even
- though it is.</p>
- </desc>
- </func>
- <func>
- <name>sort(MemoryData) -> MemoryData</name>
- <fsummary>Sort the memory allocation list</fsummary>
- <type>
- <v>MemoryData = {term(), AllocList}</v>
- <v>AllocList = [Desc]</v>
- <v>Desc = {int(), int(), int(), PidDesc}</v>
- <v>PidDesc = {int(), int(), int()} | undefined</v>
- </type>
- <desc>
- <marker id="sort_1"></marker>
- <p>Sorts a memory allocation map so that the addresses are in
- ascending order.</p>
- </desc>
- </func>
- <func>
- <name>store_memory_data(File) -> true|false</name>
- <fsummary>Store the current memory allocation map on a file</fsummary>
- <type>
- <v>File = string()</v>
- </type>
- <desc>
- <p>Stores the current memory allocation map on the file
- <c>File</c>. Returns <c>true</c> if the emulator has been
- started with the "<c>+Mim true</c>" command-line argument, and
- the map was successfully stored; otherwise, <c>false</c>. The
- contents of the file can later be read using
- <seealso marker="#read_memory_data/1">read_memory_data/1</seealso>.
- <em>NOTE:</em><c>store_memory_data/0</c> blocks execution of
- other processes while the data is collected. The time it takes
- to collect the data can be substantial.</p>
- </desc>
- </func>
- <func>
- <name>store_memory_status(File) -> true|false</name>
- <fsummary>Store the current memory allocation status on a file</fsummary>
- <type>
- <v>File = string()</v>
- </type>
- <desc>
- <p>Stores the current memory status on the file
- <c>File</c>. Returns <c>true</c> if the emulator has been
- started with the "<c>+Mis true</c>", or "<c>+Mim true</c>"
- command-line arguments, and the data was successfully stored;
- otherwise, <c>false</c>. The contents of the file can later be
- read using
- <seealso marker="#read_memory_status/1">read_memory_status/1</seealso>.</p>
- </desc>
- </func>
- <func>
- <name>sum_blocks(MemoryData) -> int()</name>
- <fsummary>Return the total amount of memory used</fsummary>
- <type>
- <v>MemoryData = {term(), AllocList}</v>
- <v>AllocList = [Desc]</v>
- <v>Desc = {int(), int(), int(), PidDesc}</v>
- <v>PidDesc = {int(), int(), int()} | undefined</v>
- </type>
- <desc>
- <p>Returns the total size of the memory blocks in the list.</p>
+ <p><em>Example:</em></p>
+ <code type="none"><![CDATA[
+> instrument:allocations(#{ histogram_start => 128, histogram_width => 15 }).
+{ok,{128,0,
+ #{udp_inet =>
+ #{driver_event_state => {0,0,0,0,0,0,0,0,0,1,0,0,0,0,0}},
+ system =>
+ #{heap => {0,0,0,0,20,4,2,2,2,3,0,1,0,0,1},
+ db_term => {271,3,1,52,80,1,0,0,0,0,0,0,0,0,0},
+ code => {0,0,0,5,3,6,11,22,19,20,10,2,1,0,0},
+ binary => {18,0,0,0,7,0,0,1,0,0,0,0,0,0,0},
+ message => {0,40,78,2,2,0,0,0,0,0,0,0,0,0,0},
+ ... }
+ spawn_forker =>
+ #{driver_select_data_state =>
+ {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}},
+ ram_file_drv => #{drv_binary => {0,0,0,0,0,0,1,0,0,0,0,0,0,0,0}},
+ prim_file =>
+ #{process_specific_data => {2,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ nif_trap_export_entry => {0,4,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ monitor_extended => {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ drv_binary => {0,0,0,0,0,0,1,0,3,5,0,0,0,1,0},
+ binary => {0,4,0,0,0,0,0,0,0,0,0,0,0,0,0}},
+ prim_buffer =>
+ #{nif_internal => {0,4,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ binary => {0,4,0,0,0,0,0,0,0,0,0,0,0,0,0}}}}}
+ ]]></code>
</desc>
</func>
+
<func>
- <name>type_descr(MemoryData, TypeNo) -> TypeDescr | invalid_type</name>
- <fsummary>Returns a type description</fsummary>
- <type>
- <v>MemoryData = {term(), AllocList}</v>
- <v>AllocList = [Desc]</v>
- <v>Desc = {int(), int(), int(), PidDesc}</v>
- <v>PidDesc = {int(), int(), int()} | undefined</v>
- <v>TypeNo = int()</v>
- <v>TypeDescr = atom() | string()</v>
- </type>
+ <name name="carriers" arity="0" since="OTP 21.0"/>
+ <fsummary>Return a list of all carriers in the system.</fsummary>
<desc>
- <p>Returns the type description of a type number used in
- <c>MemoryData</c>.
- Valid <c>TypeNo</c>s are in the range returned by
- <seealso marker="#type_no_range/1">type_no_range/1</seealso> on
- this specific memory allocation map. If <c>TypeNo</c> is an
- invalid integer, <c>invalid_type</c> is returned.</p>
+ <p>Shorthand for
+ <seealso marker="#carriers/1"><c>carriers(#{})</c>.</seealso></p>
</desc>
</func>
+
<func>
- <name>type_no_range(MemoryData) -> {Min, Max}</name>
- <fsummary>Returns the memory block type numbers</fsummary>
- <type>
- <v>MemoryData = {term(), AllocList}</v>
- <v>AllocList = [Desc]</v>
- <v>Desc = {int(), int(), int(), PidDesc}</v>
- <v>PidDesc = {int(), int(), int()} | undefined</v>
- <v>Min = int()</v>
- <v>Max = int()</v>
- </type>
+ <name name="carriers" arity="1" since="OTP 21.0"/>
+ <fsummary>Return a list of all carriers filtered by allocator type and
+ scheduler id.</fsummary>
<desc>
- <marker id="type_no_range_1"></marker>
- <p>Returns the memory block type number range used in
- <c>MemoryData</c>. When the memory allocation map was generated
- by an Erlang 5.3/OTP R9C or newer emulator, all integers <c>T</c>
- that satisfy <c>Min</c> &lt;= <c>T</c> &lt;= <c>Max</c> are
- valid type numbers. When the memory allocation map was generated
- by a pre Erlang 5.3/OTP R9C emulator, all integers in the
- range are <em>not</em> valid type numbers.</p>
+ <p>Returns a summary of all carriers in the system, optionally filtered
+ by allocator type and scheduler id.</p>
+ <p>If the specified allocator types are not enabled, the call will fail
+ with <c>{error, not_enabled}</c>.</p>
+ <p>The following options can be used:</p>
+ <taglist>
+ <tag><c>allocator_types</c></tag>
+ <item>
+ <p>The allocator types that will be searched. Defaults to all
+ <c>alloc_util</c> allocators.</p>
+ </item>
+ <tag><c>scheduler_ids</c></tag>
+ <item>
+ <p>The scheduler ids whose allocator instances will be searched. A
+ scheduler id of 0 will refer to the global instance that is not
+ tied to any particular scheduler. Defaults to all schedulers and
+ the global instance.</p>
+ </item>
+ <tag><c>histogram_start</c></tag>
+ <item>
+ <p>The upper bound of the first interval in the free block size
+ histograms. Defaults to 512.</p>
+ </item>
+ <tag><c>histogram_width</c></tag>
+ <item>
+ <p>The number of intervals in the free block size histograms.
+ Defaults to 14.</p>
+ </item>
+ </taglist>
+ <p><em>Example:</em></p>
+ <code type="none"><![CDATA[
+> instrument:carriers(#{ histogram_start => 512, histogram_width => 8 }).
+{ok,{512,
+ [{ll_alloc,1048576,0,1048344,71,false,{0,0,0,0,0,0,0,0}},
+ {binary_alloc,1048576,0,324640,13,false,{3,0,0,1,0,0,0,2}},
+ {eheap_alloc,2097152,0,1037200,45,false,{2,1,1,3,4,3,2,2}},
+ {fix_alloc,32768,0,29544,82,false,{22,0,0,0,0,0,0,0}},
+ {...}|...]}}
+ ]]></code>
</desc>
</func>
+
</funcs>
<section>
diff --git a/lib/tools/doc/src/lcnt.xml b/lib/tools/doc/src/lcnt.xml
index 0c24375b91..1d434decfc 100644
--- a/lib/tools/doc/src/lcnt.xml
+++ b/lib/tools/doc/src/lcnt.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2009</year>
- <year>2017</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -34,7 +34,7 @@
<rev>PA1</rev>
<file>lcnt.xml</file>
</header>
- <module>lcnt</module>
+ <module since="OTP R13B04">lcnt</module>
<modulesummary>A runtime system Lock Profiling tool.</modulesummary>
<description>
<p>The <c>lcnt</c> module is used to profile the internal ethread locks in the
@@ -71,7 +71,7 @@
<funcs>
<func>
- <name>start() -> {ok, Pid} | {error, {already_started, Pid}} </name>
+ <name since="OTP R13B04">start() -> {ok, Pid} | {error, {already_started, Pid}} </name>
<fsummary>Starts the lock profiler server.</fsummary>
<type>
<v>Pid = pid()</v>
@@ -84,7 +84,7 @@
</func>
<func>
- <name>stop() -> ok</name>
+ <name since="OTP R13B04">stop() -> ok</name>
<fsummary>Stops the lock profiler server.</fsummary>
<desc>
<p>Stops the lock profiler server.</p>
@@ -92,13 +92,13 @@
</func>
<func>
- <name>collect() -> ok</name>
+ <name since="OTP R13B04">collect() -> ok</name>
<fsummary>Same as <c>collect(node())</c>.</fsummary>
<desc><p>Same as <c>collect(node())</c>.</p></desc>
</func>
<func>
- <name>collect(Node) -> ok</name>
+ <name since="OTP R13B04">collect(Node) -> ok</name>
<fsummary>Collects lock statistics from the runtime system.</fsummary>
<type>
<v>Node = node()</v>
@@ -113,13 +113,13 @@
</func>
<func>
- <name>clear() -> ok</name>
+ <name since="OTP R13B04">clear() -> ok</name>
<fsummary>Same as <c>clear(node())</c>.</fsummary>
<desc><p>Same as <c>clear(node())</c>.</p></desc>
</func>
<func>
- <name>clear(Node) -> ok</name>
+ <name since="OTP R13B04">clear(Node) -> ok</name>
<fsummary>Clears the internal lock statistics from runtime system.</fsummary>
<type>
<v>Node = node()</v>
@@ -133,12 +133,12 @@
</desc>
</func>
<func>
- <name>conflicts() -> ok</name>
+ <name since="OTP R13B04">conflicts() -> ok</name>
<fsummary>Same as <c>conflicts([])</c>.</fsummary>
<desc><p>Same as <c>conflicts([])</c>.</p></desc>
</func>
<func>
- <name>conflicts([Option]) -> ok</name>
+ <name since="OTP R13B04">conflicts([Option]) -> ok</name>
<fsummary>Prints a list of internal lock counters.</fsummary>
<type>
<v>Option = {sort, Sort} | {reverse, bool()} | {thresholds, [Thresholds]} | {print, [Print | {Print, integer()}]} | {max_locks, MaxLocks} | {combine, bool()}</v>
@@ -154,14 +154,14 @@
</func>
<func>
- <name>locations() -> ok</name>
+ <name since="OTP R13B04">locations() -> ok</name>
<fsummary>Same as <c>locations([])</c>.</fsummary>
<desc>
<p>Same as <c>locations([])</c>.</p>
</desc>
</func>
<func>
- <name>locations([Option]) -> ok</name>
+ <name since="OTP R13B04">locations([Option]) -> ok</name>
<fsummary>Prints a list of internal lock counters by source code locations.</fsummary>
<type>
<v>Option = {sort, Sort} | {thresholds, [Thresholds]} | {print, [Print | {Print, integer()}]} | {max_locks, MaxLocks} | {combine, bool()}</v>
@@ -177,12 +177,12 @@
</func>
<func>
- <name>inspect(Lock) -> ok</name>
+ <name since="OTP R13B04">inspect(Lock) -> ok</name>
<fsummary>Same as <c>inspect(Lock, [])</c>.</fsummary>
<desc><p>Same as <c>inspect(Lock, [])</c>.</p></desc>
</func>
<func>
- <name>inspect(Lock, [Option]) -> ok</name>
+ <name since="OTP R13B04">inspect(Lock, [Option]) -> ok</name>
<fsummary>Prints a list of internal lock counters for a specific lock.</fsummary>
<type>
<v>Lock = Name | {Name, Id | [Id]}</v>
@@ -268,7 +268,7 @@
</func>
<func>
- <name>information() -> ok</name>
+ <name since="OTP R13B04">information() -> ok</name>
<fsummary>Prints lcnt server state and generic information about collected lock statistics.</fsummary>
<desc>
<p>Prints lcnt server state and generic information about collected lock statistics.</p>
@@ -276,7 +276,7 @@
</func>
<func>
- <name>swap_pid_keys() -> ok</name>
+ <name since="OTP R13B04">swap_pid_keys() -> ok</name>
<fsummary>Swaps places on <c>Name</c> and <c>Id</c> space for ports and processes.</fsummary>
<desc>
<p>Swaps places on <c>Name</c> and <c>Id</c> space for ports and processes.</p>
@@ -284,7 +284,7 @@
</func>
<func>
- <name>load(Filename) -> ok</name>
+ <name since="OTP R13B04">load(Filename) -> ok</name>
<fsummary>Restores previously saved data to the server.</fsummary>
<type>
<v>Filename = filename()</v>
@@ -295,7 +295,7 @@
</func>
<func>
- <name>save(Filename) -> ok</name>
+ <name since="OTP R13B04">save(Filename) -> ok</name>
<fsummary>Saves the collected data to file.</fsummary>
<type>
<v>Filename = filename()</v>
@@ -312,7 +312,7 @@
</section>
<funcs>
<func>
- <name>apply(Fun) -> term()</name>
+ <name since="OTP R13B04">apply(Fun) -> term()</name>
<fsummary>Same as <c>apply(Fun, [])</c>.</fsummary>
<type>
<v>Fun = fun()</v>
@@ -322,7 +322,7 @@
</desc>
</func>
<func>
- <name>apply(Fun, Args) -> term()</name>
+ <name since="OTP R13B04">apply(Fun, Args) -> term()</name>
<fsummary>Same as <c>apply(Module, Function, Args)</c>.</fsummary>
<type>
<v>Fun = fun()</v>
@@ -333,7 +333,7 @@
</desc>
</func>
<func>
- <name>apply(Module, Function, Args) -> term()</name>
+ <name since="OTP R13B04">apply(Module, Function, Args) -> term()</name>
<fsummary>Clears counters, applies function and collects the profiling results.</fsummary>
<type>
<v>Module = atom()</v>
@@ -358,12 +358,12 @@
</func>
<func>
- <name>pid(Id, Serial) -> pid()</name>
+ <name since="OTP R13B04">pid(Id, Serial) -> pid()</name>
<fsummary>Same as <c>pid(node(), Id, Serial)</c>.</fsummary>
<desc><p>Same as <c>pid(node(), Id, Serial)</c>.</p></desc>
</func>
<func>
- <name>pid(Node, Id, Serial) -> pid()</name>
+ <name since="OTP R13B04">pid(Node, Id, Serial) -> pid()</name>
<fsummary>Creates a process id with creation 0.</fsummary>
<type>
<v>Node = node()</v>
@@ -376,12 +376,12 @@
</func>
<func>
- <name>port(Id) -> port()</name>
+ <name since="OTP R13B04">port(Id) -> port()</name>
<fsummary>Same as <c>port(node(), Id)</c>.</fsummary>
<desc><p>Same as <c>port(node(), Id)</c>.</p></desc>
</func>
<func>
- <name>port(Node, Id) -> port()</name>
+ <name since="OTP R13B04">port(Node, Id) -> port()</name>
<fsummary>Creates a port id with creation 0.</fsummary>
<type>
<v>Node = node()</v>
@@ -399,12 +399,12 @@
<funcs>
<func>
- <name>rt_collect() -> [lock_counter_data()]</name>
+ <name since="OTP R13B04">rt_collect() -> [lock_counter_data()]</name>
<fsummary>Same as <c>rt_collect(node())</c>.</fsummary>
<desc> <p>Same as <c>rt_collect(node())</c>.</p> </desc>
</func>
<func>
- <name>rt_collect(Node) -> [lock_counter_data()]</name>
+ <name since="OTP R13B04">rt_collect(Node) -> [lock_counter_data()]</name>
<fsummary>Returns a list of raw lock counter data.</fsummary>
<type>
<v>Node = node()</v>
@@ -413,12 +413,12 @@
</func>
<func>
- <name>rt_clear() -> ok</name>
+ <name since="OTP R13B04">rt_clear() -> ok</name>
<fsummary>Same as <c>rt_clear(node())</c>.</fsummary>
<desc> <p>Same as <c>rt_clear(node())</c>.</p> </desc>
</func>
<func>
- <name>rt_clear(Node) -> ok</name>
+ <name since="OTP R13B04">rt_clear(Node) -> ok</name>
<fsummary>Clears the internal counters.</fsummary>
<type>
<v>Node = node()</v>
@@ -427,13 +427,13 @@
</func>
<func>
- <name>rt_mask() -> [category_atom()]</name>
+ <name since="OTP 20.1">rt_mask() -> [category_atom()]</name>
<fsummary>Same as <c>rt_mask(node())</c>.</fsummary>
<desc><p>Same as <c>rt_mask(node())</c>.</p></desc>
</func>
<func>
- <name>rt_mask(Node) -> [category_atom()]</name>
+ <name since="OTP 20.1">rt_mask(Node) -> [category_atom()]</name>
<fsummary>Returns the current lock category mask.</fsummary>
<type>
<v>Node = node()</v>
@@ -447,7 +447,7 @@
</func>
<func>
- <name>rt_mask(Categories) -> ok | {error, copy_save_enabled}</name>
+ <name since="OTP 20.1">rt_mask(Categories) -> ok | {error, copy_save_enabled}</name>
<fsummary>Same as <c>rt_mask(node(), Categories)</c>.</fsummary>
<type>
<v>Categories = [atom()]</v>
@@ -456,7 +456,7 @@
</func>
<func>
- <name>rt_mask(Node, Categories) -> ok | {error, copy_save_enabled}</name>
+ <name since="OTP 20.1">rt_mask(Node, Categories) -> ok | {error, copy_save_enabled}</name>
<fsummary>Changes the lock category mask.</fsummary>
<type>
<v>Node = node()</v>
@@ -489,12 +489,12 @@
</func>
<func>
- <name>rt_opt({Type, bool()}) -> bool()</name>
+ <name since="OTP R13B04">rt_opt({Type, bool()}) -> bool()</name>
<fsummary>Same as <c>rt_opt(node(), {Type, Opt})</c>.</fsummary>
<desc> <p>Same as <c>rt_opt(node(), {Type, Opt})</c>.</p> </desc>
</func>
<func>
- <name>rt_opt(Node, {Type, bool()}) -> bool()</name>
+ <name since="OTP R13B04">rt_opt(Node, {Type, bool()}) -> bool()</name>
<fsummary>Changes the lock counter behavior and returns the previous behaviour.</fsummary>
<type>
<v>Node = node()</v>
diff --git a/lib/tools/doc/src/make.xml b/lib/tools/doc/src/make.xml
index 123fcd4afc..322d77323f 100644
--- a/lib/tools/doc/src/make.xml
+++ b/lib/tools/doc/src/make.xml
@@ -30,7 +30,7 @@
<date></date>
<rev></rev>
</header>
- <module>make</module>
+ <module since="">make</module>
<modulesummary>A Make Utility for Erlang</modulesummary>
<description>
<p>The module <c>make</c> provides a set of functions similar to
@@ -38,8 +38,8 @@
</description>
<funcs>
<func>
- <name>all() -> up_to_date | error</name>
- <name>all(Options) -> up_to_date | error</name>
+ <name since="">all() -> up_to_date | error</name>
+ <name since="">all(Options) -> up_to_date | error</name>
<fsummary>Compile a set of modules.</fsummary>
<type>
<v>Options = [Option]</v>
@@ -87,8 +87,8 @@
</desc>
</func>
<func>
- <name>files(ModFiles) -> up_to_date | error</name>
- <name>files(ModFiles, Options) -> up_to_date | error</name>
+ <name since="">files(ModFiles) -> up_to_date | error</name>
+ <name since="">files(ModFiles, Options) -> up_to_date | error</name>
<fsummary>Compile a set of modules.</fsummary>
<type>
<v>ModFiles = [Module | File]</v>
@@ -145,5 +145,10 @@ Modules.
{'*',[debug_info]}. </code>
<p></p>
</section>
+
+ <section>
+ <title>See Also</title>
+ <p><seealso marker="compiler:compile"><c>compile(3)</c></seealso></p>
+ </section>
</erlref>
diff --git a/lib/tools/doc/src/notes.xml b/lib/tools/doc/src/notes.xml
index 45f276c09e..fd41e2cbeb 100644
--- a/lib/tools/doc/src/notes.xml
+++ b/lib/tools/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,6 +31,161 @@
</header>
<p>This document describes the changes made to the Tools application.</p>
+<section><title>Tools 3.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Add <c>cprof</c> and <c>tags</c> modules to .app file so
+ that they are included in releases.</p>
+ <p>
+ Own Id: OTP-15534 Aux Id: PR-2078 </p>
+ </item>
+ <item>
+ <p>
+ Improved documentation parsing in emacs erldoc
+ functionality.</p>
+ <p>
+ Own Id: OTP-15699 Aux Id: PR-2184 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>The <c>cover</c> tool now uses the <c>counters</c>
+ module instead of <c>ets</c> for updating the counters
+ for how many times a line has been executed. By default,
+ Cover will work with distributed nodes, but a new
+ function <c>cover:local_only/0</c> allows running the
+ Cover in a restricted but faster local-only mode.</p>
+ <p>The increase in speed will vary depending on the type
+ of code being cover-compiled, but as an example, the
+ compiler test suite runs more than twice as fast with the
+ new Cover.</p>
+ <p>
+ Own Id: OTP-15575</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Tools 3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Minor fixes for <c>make clean</c>.</p>
+ <p>
+ Own Id: OTP-15657</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ In the HTML file generated by
+ <c>cover:analyse_to_file/1,2</c>, a link is now added to
+ the line number. This makes it easier to share pointers
+ to specific lines.</p>
+ <p>
+ Own Id: OTP-15541</p>
+ </item>
+ <item>
+ <p>
+ Uncovered lines are now marked with a sad face,
+ <c>:-(</c>, in the HTML output from
+ <c>cover:analyse_to_file/1,2</c>. This is to make these
+ lines easier to find by search.</p>
+ <p>
+ Own Id: OTP-15542</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Tools 3.0.2</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Remove emacs warnings and added more tests.</p>
+ <p>
+ Own Id: OTP-15476</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Tools 3.0.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The HTML pages generated by cover:analyse_to_file/1 and
+ related functions is improved for readability.</p>
+ <p>
+ Own Id: OTP-15213 Aux Id: PR-1807 </p>
+ </item>
+ <item>
+ <p>
+ Add alignment functionality in emacs.</p>
+ <p>
+ Own Id: OTP-15239 Aux Id: PR-1728 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Tools 3.0</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>Added <c>instrument:allocations</c> and
+ <c>instrument:carriers</c> for retrieving information
+ about memory utilization and fragmentation.</p>
+ <p>The old <c>instrument</c> interface has been removed,
+ as have the related options <c>+Mim</c> and
+ <c>+Mis</c>.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14961</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Tools 2.11.2.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Minor fixes for <c>make clean</c>.</p>
+ <p>
+ Own Id: OTP-15657</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Tools 2.11.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -1808,4 +1963,3 @@
</section>
</section>
</chapter>
-
diff --git a/lib/tools/doc/src/specs.xml b/lib/tools/doc/src/specs.xml
new file mode 100644
index 0000000000..0b5b7b171c
--- /dev/null
+++ b/lib/tools/doc/src/specs.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<specs xmlns:xi="http://www.w3.org/2001/XInclude">
+ <xi:include href="../specs/specs_fprof.xml"/>
+ <xi:include href="../specs/specs_make.xml"/>
+ <xi:include href="../specs/specs_lcnt.xml"/>
+ <xi:include href="../specs/specs_eprof.xml"/>
+ <xi:include href="../specs/specs_tags.xml"/>
+ <xi:include href="../specs/specs_cover.xml"/>
+ <xi:include href="../specs/specs_xref.xml"/>
+ <xi:include href="../specs/specs_instrument.xml"/>
+ <xi:include href="../specs/specs_erlang_mode.xml"/>
+</specs>
diff --git a/lib/tools/doc/src/tags.xml b/lib/tools/doc/src/tags.xml
index ea0ae5cc4d..90a8b28177 100644
--- a/lib/tools/doc/src/tags.xml
+++ b/lib/tools/doc/src/tags.xml
@@ -32,7 +32,7 @@
<rev>A</rev>
<file>tags.sgml</file>
</header>
- <module>tags</module>
+ <module since="">tags</module>
<modulesummary>Generate Emacs TAGS file from Erlang source files</modulesummary>
<description>
<p>A <c>TAGS</c> file is used by Emacs to find function and variable
@@ -42,14 +42,14 @@
</description>
<funcs>
<func>
- <name>file(File [, Options])</name>
+ <name since="">file(File [, Options])</name>
<fsummary>Create a <c>TAGS</c>file for the file <c>File</c>.</fsummary>
<desc>
<p>Create a <c>TAGS</c> file for the file <c>File</c>.</p>
</desc>
</func>
<func>
- <name>files(FileList [, Options])</name>
+ <name since="">files(FileList [, Options])</name>
<fsummary>Create a TAGS file for the files in the list<c>FileList</c>.</fsummary>
<desc>
<p>Create a TAGS file for the files in the list
@@ -57,7 +57,7 @@
</desc>
</func>
<func>
- <name>dir(Dir [, Options])</name>
+ <name since="">dir(Dir [, Options])</name>
<fsummary>Create a TAGS file for all files in directory<c>Dir</c>.</fsummary>
<desc>
<p>Create a TAGS file for all files in directory
@@ -65,7 +65,7 @@
</desc>
</func>
<func>
- <name>dirs(DirList [, Options])</name>
+ <name since="">dirs(DirList [, Options])</name>
<fsummary>Create a TAGS file for all files in any directory in<c>DirList</c>.</fsummary>
<desc>
<p>Create a TAGS file for all files in any directory in
@@ -73,7 +73,7 @@
</desc>
</func>
<func>
- <name>subdir(Dir [, Options])</name>
+ <name since="">subdir(Dir [, Options])</name>
<fsummary>Descend recursively down the directory <c>Dir</c>and create a <c>TAGS</c>file based on all files found.</fsummary>
<desc>
<p>Descend recursively down the directory <c>Dir</c> and
@@ -81,7 +81,7 @@
</desc>
</func>
<func>
- <name>subdirs(DirList [, Options])</name>
+ <name since="">subdirs(DirList [, Options])</name>
<fsummary>Descend recursively down all the directories in<c>DirList</c>and create a <c>TAGS</c>file based on all files found.</fsummary>
<desc>
<p>Descend recursively down all the directories in
@@ -90,7 +90,7 @@
</desc>
</func>
<func>
- <name>root([Options])</name>
+ <name since="">root([Options])</name>
<fsummary>Create a <c>TAGS</c>file covering all files in the Erlang distribution.</fsummary>
<desc>
<p>Create a <c>TAGS</c> file covering all files in
diff --git a/lib/tools/doc/src/xref.xml b/lib/tools/doc/src/xref.xml
index 6f833246ad..ab3641a52f 100644
--- a/lib/tools/doc/src/xref.xml
+++ b/lib/tools/doc/src/xref.xml
@@ -32,7 +32,7 @@
<rev>PA1</rev>
<file>xref.sgml</file>
</header>
- <module>xref</module>
+ <module since="">xref</module>
<modulesummary>A Cross Reference Tool for analyzing dependencies between functions, modules, applications and releases.</modulesummary>
<description>
<p>Xref is a cross reference tool that can be used for finding
@@ -729,7 +729,7 @@ xref() = atom() | pid() </pre>
</description>
<funcs>
<func>
- <name>add_application(Xref, Directory [, Options]) -> {ok, application()} | Error</name>
+ <name since="">add_application(Xref, Directory [, Options]) -> {ok, application()} | Error</name>
<fsummary>Add the modules of an application.</fsummary>
<type>
<v>Directory = directory()</v>
@@ -761,7 +761,7 @@ xref() = atom() | pid() </pre>
</desc>
</func>
<func>
- <name>add_directory(Xref, Directory [, Options]) -> {ok, Modules} | Error</name>
+ <name since="">add_directory(Xref, Directory [, Options]) -> {ok, Modules} | Error</name>
<fsummary>Add the modules in a directory.</fsummary>
<type>
<v>Directory = directory()</v>
@@ -791,7 +791,7 @@ xref() = atom() | pid() </pre>
</desc>
</func>
<func>
- <name>add_module(Xref, File [, Options]) -> {ok, module()} | Error</name>
+ <name since="">add_module(Xref, File [, Options]) -> {ok, module()} | Error</name>
<fsummary>Add a module.</fsummary>
<type>
<v>Error = {error, module(), Reason}</v>
@@ -814,7 +814,7 @@ xref() = atom() | pid() </pre>
</desc>
</func>
<func>
- <name>add_release(Xref, Directory [, Options]) -> {ok, release()} | Error</name>
+ <name since="">add_release(Xref, Directory [, Options]) -> {ok, release()} | Error</name>
<fsummary>Add the modules of a release.</fsummary>
<type>
<v>Directory = directory()</v>
@@ -849,7 +849,7 @@ xref() = atom() | pid() </pre>
</desc>
</func>
<func>
- <name>analyze(Xref, Analysis [, Options]) -> {ok, Answer} | Error</name>
+ <name since="">analyze(Xref, Analysis [, Options]) -> {ok, Answer} | Error</name>
<fsummary>Evaluate a predefined analysis.</fsummary>
<type>
<v>Analysis = undefined_function_calls | undefined_functions | locals_not_used | exports_not_used | deprecated_function_calls | {deprecated_function_calls, DeprFlag} | deprecated_functions | {deprecated_functions, DeprFlag} | {call, FuncSpec} | {use, FuncSpec} | {module_call, ModSpec} | {module_use, ModSpec} | {application_call, AppSpec} | {application_use, AppSpec} | {release_call, RelSpec} | {release_use, RelSpec}</v>
@@ -939,7 +939,7 @@ Evaluates a predefined analysis.
</desc>
</func>
<func>
- <name>d(Directory) -> [DebugInfoResult] | [NoDebugInfoResult] | Error</name>
+ <name since="">d(Directory) -> [DebugInfoResult] | [NoDebugInfoResult] | Error</name>
<fsummary>Check the modules in a directory using the code path.</fsummary>
<type>
<v>Directory = directory()</v>
@@ -979,8 +979,8 @@ Evaluates a predefined analysis.
</desc>
</func>
<func>
- <name>forget(Xref) -> ok</name>
- <name>forget(Xref, Variables) -> ok | Error</name>
+ <name since="">forget(Xref) -> ok</name>
+ <name since="">forget(Xref, Variables) -> ok | Error</name>
<fsummary>Remove user variables and their values.</fsummary>
<type>
<v>Error = {error, module(), Reason}</v>
@@ -994,7 +994,7 @@ Evaluates a predefined analysis.
</desc>
</func>
<func>
- <name>format_error(Error) -> Chars</name>
+ <name since="">format_error(Error) -> Chars</name>
<fsummary>Return an English description of an Xref error reply.</fsummary>
<type>
<v>Error = {error, module(), term()}</v>
@@ -1008,8 +1008,8 @@ Evaluates a predefined analysis.
</desc>
</func>
<func>
- <name>get_default(Xref) -> [{Option, Value}]</name>
- <name>get_default(Xref, Option) -> {ok, Value} | Error</name>
+ <name since="">get_default(Xref) -> [{Option, Value}]</name>
+ <name since="">get_default(Xref, Option) -> {ok, Value} | Error</name>
<fsummary>Return the default values of options.</fsummary>
<type>
<v>Error = {error, module(), Reason}</v>
@@ -1023,7 +1023,7 @@ Evaluates a predefined analysis.
</desc>
</func>
<func>
- <name>get_library_path(Xref) -> {ok, LibraryPath}</name>
+ <name since="">get_library_path(Xref) -> {ok, LibraryPath}</name>
<fsummary>Return the library path.</fsummary>
<type>
<v>LibraryPath = library_path()</v>
@@ -1034,9 +1034,9 @@ Evaluates a predefined analysis.
</desc>
</func>
<func>
- <name>info(Xref) -> [Info]</name>
- <name>info(Xref, Category) -> [{Item, [Info]}]</name>
- <name>info(Xref, Category, Items) -> [{Item, [Info]}]</name>
+ <name since="">info(Xref) -> [Info]</name>
+ <name since="">info(Xref, Category) -> [{Item, [Info]}]</name>
+ <name since="">info(Xref, Category, Items) -> [{Item, [Info]}]</name>
<fsummary>Return information about an Xref server.</fsummary>
<type>
<v>Application = [] | [application()]</v>
@@ -1220,8 +1220,8 @@ Evaluates a predefined analysis.
</desc>
</func>
<func>
- <name>m(Module) -> [DebugInfoResult] | [NoDebugInfoResult] | Error</name>
- <name>m(File) -> [DebugInfoResult] | [NoDebugInfoResult] | Error</name>
+ <name since="">m(Module) -> [DebugInfoResult] | [NoDebugInfoResult] | Error</name>
+ <name since="">m(File) -> [DebugInfoResult] | [NoDebugInfoResult] | Error</name>
<fsummary>Check a module using the code path.</fsummary>
<type>
<v>DebugInfoResult = {deprecated, [funcall()]} | {undefined, [funcall()]} | {unused, [mfa()]}</v>
@@ -1263,7 +1263,7 @@ Evaluates a predefined analysis.
</desc>
</func>
<func>
- <name>q(Xref, Query [, Options]) -> {ok, Answer} | Error</name>
+ <name since="">q(Xref, Query [, Options]) -> {ok, Answer} | Error</name>
<fsummary>Evaluate a query.</fsummary>
<type>
<v>Answer = false | [constant()] | [Call] | [Component] | int() | [DefineAt] | [CallAt] | [AllLines]</v>
@@ -1322,7 +1322,7 @@ Evaluates a predefined analysis.
</desc>
</func>
<func>
- <name>remove_application(Xref, Applications) -> ok | Error</name>
+ <name since="">remove_application(Xref, Applications) -> ok | Error</name>
<fsummary>Remove applications and their modules.</fsummary>
<type>
<v>Applications = application() | [application()]</v>
@@ -1335,7 +1335,7 @@ Evaluates a predefined analysis.
</desc>
</func>
<func>
- <name>remove_module(Xref, Modules) -> ok | Error</name>
+ <name since="">remove_module(Xref, Modules) -> ok | Error</name>
<fsummary>Remove analyzed modules.</fsummary>
<type>
<v>Error = {error, module(), Reason}</v>
@@ -1348,7 +1348,7 @@ Evaluates a predefined analysis.
</desc>
</func>
<func>
- <name>remove_release(Xref, Releases) -> ok | Error</name>
+ <name since="">remove_release(Xref, Releases) -> ok | Error</name>
<fsummary>Remove releases and their applications and modules.</fsummary>
<type>
<v>Error = {error, module(), Reason}</v>
@@ -1363,7 +1363,7 @@ Evaluates a predefined analysis.
</desc>
</func>
<func>
- <name>replace_application(Xref, Application, Directory [, Options]) -> {ok, application()} | Error</name>
+ <name since="">replace_application(Xref, Application, Directory [, Options]) -> {ok, application()} | Error</name>
<fsummary>Replace an application's modules.</fsummary>
<type>
<v>Application = application()</v>
@@ -1384,7 +1384,7 @@ Evaluates a predefined analysis.
</desc>
</func>
<func>
- <name>replace_module(Xref, Module, File [, Options]) -> {ok, module()} | Error</name>
+ <name since="">replace_module(Xref, Module, File [, Options]) -> {ok, module()} | Error</name>
<fsummary>Replace an analyzed module.</fsummary>
<type>
<v>Error = {error, module(), Reason}</v>
@@ -1409,8 +1409,8 @@ Evaluates a predefined analysis.
</desc>
</func>
<func>
- <name>set_default(Xref, Option, Value) -> {ok, OldValue} | Error</name>
- <name>set_default(Xref, OptionValues) -> ok | Error</name>
+ <name since="">set_default(Xref, Option, Value) -> {ok, OldValue} | Error</name>
+ <name since="">set_default(Xref, OptionValues) -> ok | Error</name>
<fsummary>Set the default values of options.</fsummary>
<type>
<v>Error = {error, module(), Reason}</v>
@@ -1435,7 +1435,7 @@ Evaluates a predefined analysis.
</desc>
</func>
<func>
- <name>set_library_path(Xref, LibraryPath [, Options]) -> ok | Error</name>
+ <name since="">set_library_path(Xref, LibraryPath [, Options]) -> ok | Error</name>
<fsummary>Set the library path and finds the library modules.</fsummary>
<type>
<v>Error = {error, module(), Reason}</v>
@@ -1469,7 +1469,7 @@ Evaluates a predefined analysis.
</desc>
</func>
<func>
- <name>start(NameOrOptions) -> Return</name>
+ <name since="">start(NameOrOptions) -> Return</name>
<fsummary>Create an Xref server.</fsummary>
<type>
<v>NameOrOptions = Name | Options</v>
@@ -1487,7 +1487,7 @@ Evaluates a predefined analysis.
</desc>
</func>
<func>
- <name>start(Name, Options) -> Return</name>
+ <name since="">start(Name, Options) -> Return</name>
<fsummary>Create an Xref server.</fsummary>
<type>
<v>Name = atom()</v>
@@ -1504,7 +1504,7 @@ Evaluates a predefined analysis.
</desc>
</func>
<func>
- <name>stop(Xref)</name>
+ <name since="">stop(Xref)</name>
<fsummary>Delete an Xref server.</fsummary>
<type>
<v>Xref = xref()</v>
@@ -1514,7 +1514,7 @@ Evaluates a predefined analysis.
</desc>
</func>
<func>
- <name>update(Xref [, Options]) -> {ok, Modules} | Error</name>
+ <name since="">update(Xref [, Options]) -> {ok, Modules} | Error</name>
<fsummary>Replace newly compiled analyzed modules.</fsummary>
<type>
<v>Error = {error, module(), Reason}</v>
@@ -1534,7 +1534,7 @@ Evaluates a predefined analysis.
</desc>
</func>
<func>
- <name>variables(Xref [, Options]) -> {ok, [VariableInfo]}</name>
+ <name since="">variables(Xref [, Options]) -> {ok, [VariableInfo]}</name>
<fsummary>Return the names of variables.</fsummary>
<type>
<v>Options = [Option] | Option</v>
diff --git a/lib/tools/emacs/Makefile b/lib/tools/emacs/Makefile
index ea4d6cb723..b7775d1c8c 100644
--- a/lib/tools/emacs/Makefile
+++ b/lib/tools/emacs/Makefile
@@ -46,6 +46,7 @@ EMACS_FILES= \
erlang-eunit \
erlang-edoc \
erlang-flymake \
+ erlang-test \
erlang
README_FILES= README
diff --git a/lib/tools/emacs/erlang-edoc.el b/lib/tools/emacs/erlang-edoc.el
index d0dcc81028..ea1e263faf 100644
--- a/lib/tools/emacs/erlang-edoc.el
+++ b/lib/tools/emacs/erlang-edoc.el
@@ -28,6 +28,7 @@
(defcustom erlang-edoc-indent-level 2
"Indentation level of xhtml in Erlang edoc."
+ :type '(integer)
:safe 'integerp
:group 'erlang)
diff --git a/lib/tools/emacs/erlang-eunit.el b/lib/tools/emacs/erlang-eunit.el
index 38c40927f4..53543d7b01 100644
--- a/lib/tools/emacs/erlang-eunit.el
+++ b/lib/tools/emacs/erlang-eunit.el
@@ -23,6 +23,7 @@
(eval-when-compile
(require 'cl))
+(require 'erlang)
(defvar erlang-eunit-src-candidate-dirs '("../src" ".")
"*Name of directories which to search for source files matching
@@ -331,8 +332,7 @@ With prefix arg, compiles for debug and runs tests with the verbose flag set."
t)
(apply test-fun test-args)
(if under-cover
- (save-excursion
- (set-buffer (find-file-noselect src-filename))
+ (with-current-buffer (find-file-noselect src-filename)
(erlang-eunit-analyze-coverage)))))))
(defun erlang-eunit-compile-and-run-module-tests-under-cover ()
@@ -348,8 +348,7 @@ With prefix arg, compiles for debug and runs tests with the verbose flag set."
(defun erlang-eunit-compile-file (file-path &optional under-cover)
(if (file-readable-p file-path)
- (save-excursion
- (set-buffer (find-file-noselect file-path))
+ (with-current-buffer (find-file-noselect file-path)
;; In order to run a code coverage analysis on a
;; module, we have two options:
;;
@@ -376,8 +375,7 @@ With prefix arg, compiles for debug and runs tests with the verbose flag set."
(error msg))))
(defun erlang-eunit-last-compilation-successful-p ()
- (save-excursion
- (set-buffer inferior-erlang-buffer)
+ (with-current-buffer inferior-erlang-buffer
(goto-char compilation-parsing-end)
(erlang-eunit-all-list-elems-fulfill-p
(lambda (re) (let ((continue t)
diff --git a/lib/tools/emacs/erlang-pkg.el b/lib/tools/emacs/erlang-pkg.el
index 02d6bebbf4..7e95e4050e 100644
--- a/lib/tools/emacs/erlang-pkg.el
+++ b/lib/tools/emacs/erlang-pkg.el
@@ -1,3 +1,6 @@
(define-package "erlang" "2.7.0"
"Erlang major mode"
'((emacs "24.1")))
+;; Local Variables:
+;; no-byte-compile: t
+;; End:
diff --git a/lib/tools/emacs/erlang-skels.el b/lib/tools/emacs/erlang-skels.el
index 534f50ab33..3ebc6e8e1e 100644
--- a/lib/tools/emacs/erlang-skels.el
+++ b/lib/tools/emacs/erlang-skels.el
@@ -1985,7 +1985,7 @@ configured off."
The first character of DD is space if the value is less than 10."
(let ((date (current-time-string)))
(format "%2d %s %s"
- (string-to-int (substring date 8 10))
+ (string-to-number (substring date 8 10))
(substring date 4 7)
(substring date -4))))
diff --git a/lib/tools/emacs/erlang-test.el b/lib/tools/emacs/erlang-test.el
index efe3d515e9..fbdd298da3 100644
--- a/lib/tools/emacs/erlang-test.el
+++ b/lib/tools/emacs/erlang-test.el
@@ -29,7 +29,7 @@
;; This library require GNU Emacs 25 or later.
;;
-;; There are two ways to run emacs unit tests.
+;; There are three ways to run the erlang emacs unit tests.
;;
;; 1. Within a running emacs process. Load this file. Then to run
;; all defined test cases:
@@ -49,11 +49,22 @@
;;
;; The -L option adds a directory to the load-path. It should be the
;; directory containing erlang.el and erlang-test.el.
+;;
+;; 3. Run the emacs_SUITE. The testcases tests_interpreted/1 and
+;; tests_compiled/1 in this suite are using the second method. One
+;; way to run this suite is with the ct_run tool, for example like the
+;; following when standing at the OTP repo top directory:
+;;
+;; ct_run -suite lib/tools/test/emacs_SUITE
+;;
+;; Note that this creates a lot of html log files in the current
+;; directory.
;;; Code:
+(eval-when-compile
+ (require 'cl))
(require 'ert)
-(require 'cl-lib)
(require 'erlang)
(defvar erlang-test-code
@@ -63,7 +74,7 @@
("SYMBOL" . "-define(SYMBOL, value).")
("MACRO" . "-define(MACRO(X), X + X).")
("struct" . "-record(struct, {until,maps,are,everywhere}).")
- ("function". "function() -> #struct{}."))
+ ("function" . "function() -> #struct{}."))
"Alist of erlang test code.
Each entry have the format (TAGNAME . ERLANG_CODE). If TAGNAME
is nil there is no definitions in the ERLANG_CODE. The
@@ -116,8 +127,8 @@ concatenated to form an erlang file to test on.")
(defun erlang-test-create-erlang-file (erlang-file)
(with-temp-file erlang-file
- (cl-loop for (_ . code) in erlang-test-code
- do (insert code "\n"))))
+ (loop for (_ . code) in erlang-test-code
+ do (insert code "\n"))))
(defun erlang-test-compile-tags (erlang-file tags-file)
(should (zerop (call-process "etags" nil nil nil
@@ -132,19 +143,20 @@ concatenated to form an erlang file to test on.")
(sort (erlang-expected-completion-table) #'string-lessp))))
(defun erlang-expected-completion-table ()
- (append (cl-loop for (symbol . _) in erlang-test-code
- when (stringp symbol)
- append (list symbol (concat "erlang_test:" symbol)))
+ (append (loop for (symbol . _) in erlang-test-code
+ when (stringp symbol)
+ append (list symbol (concat "erlang_test:" symbol)))
(list "erlang_test:" "erlang_test:module_info")))
(defun erlang-test-xref-find-definitions (erlang-file erlang-buffer)
- (cl-loop for (tagname . code) in erlang-test-code
- for line = 1 then (1+ line)
- do (when tagname
- (switch-to-buffer erlang-buffer)
- (erlang-test-xref-jump tagname erlang-file line)
- (erlang-test-xref-jump (concat "erlang_test:" tagname)
- erlang-file line)))
+ (loop for (tagname . code) in erlang-test-code
+ for line = 1 then (1+ line)
+ do (when tagname
+ (switch-to-buffer erlang-buffer)
+ (erlang-test-xref-jump tagname erlang-file line)
+ (when (string-equal tagname "function")
+ (erlang-test-xref-jump (concat "erlang_test:" tagname)
+ erlang-file line))))
(erlang-test-xref-jump "erlang_test:" erlang-file 1))
(defun erlang-test-xref-jump (id expected-file expected-line)
@@ -213,27 +225,27 @@ concatenated to form an erlang file to test on.")
(ert-deftest erlang-test-parse-id ()
- (cl-loop for id-string in '("fun/10"
- "qualified-function module:fun/10"
- "record reko"
- "macro _SYMBOL"
- "macro MACRO/10"
- "module modula"
- "macro"
- nil)
- for id-list in '((nil nil "fun" 10)
- (qualified-function "module" "fun" 10)
- (record nil "reko" nil)
- (macro nil "_SYMBOL" nil)
- (macro nil "MACRO" 10)
- (module nil "modula" nil)
- (nil nil "macro" nil)
- nil)
- for id-list2 = (erlang-id-to-list id-string)
- do (should (equal id-list id-list2))
- for id-string2 = (erlang-id-to-string id-list)
- do (should (equal id-string id-string2))
- collect id-list2))
+ (loop for id-string in '("fun/10"
+ "qualified-function module:fun/10"
+ "record reko"
+ "macro _SYMBOL"
+ "macro MACRO/10"
+ "module modula"
+ "macro"
+ nil)
+ for id-list in '((nil nil "fun" 10)
+ (qualified-function "module" "fun" 10)
+ (record nil "reko" nil)
+ (macro nil "_SYMBOL" nil)
+ (macro nil "MACRO" 10)
+ (module nil "modula" nil)
+ (nil nil "macro" nil)
+ nil)
+ for id-list2 = (erlang-id-to-list id-string)
+ do (should (equal id-list id-list2))
+ for id-string2 = (erlang-id-to-string id-list)
+ do (should (equal id-string id-string2))
+ collect id-list2))
(provide 'erlang-test)
diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el
index e4166053d5..0b3a2319e2 100644
--- a/lib/tools/emacs/erlang.el
+++ b/lib/tools/emacs/erlang.el
@@ -4,12 +4,12 @@
;; Author: Anders Lindgren
;; Keywords: erlang, languages, processes
;; Date: 2011-12-11
-;; Version: 2.8.1
+;; Version: 2.8.2
;; Package-Requires: ((emacs "24.1"))
;; %CopyrightBegin%
;;
-;; Copyright Ericsson AB 1996-2017. All Rights Reserved.
+;; Copyright Ericsson AB 1996-2018. All Rights Reserved.
;;
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
@@ -77,6 +77,9 @@
;;; Code:
(eval-when-compile (require 'cl))
+(require 'align)
+(require 'comint)
+(require 'tempo)
;; Variables:
@@ -84,7 +87,7 @@
"The Erlang programming language."
:group 'languages)
-(defconst erlang-version "2.8.1"
+(defconst erlang-version "2.8.2"
"The version number of Erlang mode.")
(defcustom erlang-root-dir nil
@@ -333,6 +336,7 @@ when a new function header is generated. When nil, no blank line is
inserted between the current line and the new header. When bound to a
number it represents the number of blank lines which should be
inserted."
+ :type '(restricted-sexp :match-alternatives (integerp 'nil))
:group 'erlang)
(defvar erlang-electric-semicolon-criteria
@@ -498,6 +502,13 @@ regardless of where in the line point is when the TAB command is used."
:type 'boolean
:safe 'booleanp)
+(defcustom erlang-max-files-to-visit-for-refining-xrefs 32
+ "Upper limit how many files to visit for checking arity.
+When `nil' there is no limit."
+ :group 'erlang
+ :type '(restricted-sexp :match-alternatives (integerp 'nil))
+ :safe (lambda (val) (or (eq val nil) (integerp val))))
+
(defvar erlang-man-inhibit (eq system-type 'windows-nt)
"Inhibit the creation of the Erlang Manual Pages menu.
@@ -804,6 +815,7 @@ resulting regexp is surrounded by \\_< and \\_>."
"is_integer"
"is_list"
"is_map"
+ "is_map_key"
"is_number"
"is_pid"
"is_port"
@@ -825,6 +837,7 @@ resulting regexp is surrounded by \\_< and \\_>."
"list_to_tuple"
"load_module"
"make_ref"
+ "map_get"
"map_size"
"max"
"min"
@@ -884,8 +897,6 @@ resulting regexp is surrounded by \\_< and \\_>."
"alloc_sizes"
"append"
"append_element"
- "await_proc_exit"
- "await_sched_wall_time_modifications"
"bump_reductions"
"call_on_load_function"
"cancel_timer"
@@ -895,16 +906,17 @@ resulting regexp is surrounded by \\_< and \\_>."
"decode_packet"
"delay_trap"
"delete_element"
- "dexit"
- "dgroup_leader"
"display"
"display_nl"
"display_string"
- "dist_exit"
- "dlink"
+ "dist_get_stat"
+ "dist_ctrl_get_data"
+ "dist_ctrl_get_data_notification"
+ "dist_ctrl_get_opt"
+ "dist_ctrl_input_handler"
+ "dist_ctrl_put_data"
+ "dist_ctrl_set_opt"
"dmonitor_node"
- "dmonitor_p"
- "dsend"
"dt_append_vm_tag_data"
"dt_get_tag"
"dt_get_tag_data"
@@ -912,8 +924,8 @@ resulting regexp is surrounded by \\_< and \\_>."
"dt_put_tag"
"dt_restore_tag"
"dt_spread_tag"
- "dunlink"
"convert_time_unit"
+ "exit_signal"
"external_size"
"finish_after_on_load"
"finish_loading"
@@ -924,7 +936,6 @@ resulting regexp is surrounded by \\_< and \\_>."
"function_exported"
"garbage_collect_message_area"
"gather_gc_info_result"
- "gather_sched_wall_time_result"
"get_cookie"
"get_module_info"
"get_stacktrace"
@@ -1407,6 +1418,19 @@ Other commands:
(add-function :before-until (local 'eldoc-documentation-function)
#'erldoc-eldoc-function))
(run-hooks 'erlang-mode-hook)
+
+ ;; Align maps.
+ (add-to-list 'align-rules-list
+ '(erlang-maps
+ (regexp . "\\(\\s-*\\)\\(=>\\)\\s-*")
+ (modes . '(erlang-mode))
+ (repeat . t)))
+ ;; Align records and :: specs
+ (add-to-list 'align-rules-list
+ '(erlang-record-specs
+ (regexp . "\\(\\s-*\\)\\(=\\).*\\(::\\)*\\s-*")
+ (modes . '(erlang-mode))
+ (repeat . t)))
(if (zerop (buffer-size))
(run-hooks 'erlang-new-file-hook)))
@@ -1699,10 +1723,10 @@ Personal extensions could be added to `erlang-menu-personal-items'.
This function should be called if any variable describing the
menu configuration is changed."
- (erlang-menu-install "Erlang" erlang-menu-items erlang-mode-map t))
+ (erlang-menu-install "Erlang" erlang-menu-items erlang-mode-map))
-(defun erlang-menu-install (name items keymap &optional popup)
+(defun erlang-menu-install (name items keymap)
"Install a menu in Emacs based on an abstract description.
NAME is the name of the menu.
@@ -3672,32 +3696,40 @@ When an identifier is found return a list with 4 elements:
module or nil.
2. Module - Module name string or nil. In case of a
-qualified-function a search fails if no entries with correct
-module are found. For other kinds the module is just a
-preference. If no matching entries are found the search will be
-retried without regard to module.
+qualified-function the module is explicitly specified (like
+module:fun()) and the search fails if no entries with correct
+module are found. For other kinds the module is guessed: either
+fetched from import statements or it is assumed to be the local
+module. In these cases the module is just a preference. If no
+matching entries are found the search will be retried without
+regard to module.
3. Name - String name of function, module, record or macro.
4. Arity - Integer in case of functions and macros if the number
of arguments could be found, otherwise nil."
(save-excursion
- (save-match-data
- (if (eq (char-syntax (following-char)) ? )
- (skip-chars-backward " \t"))
- (skip-chars-backward "[:word:]_:'")
- (cond ((looking-at erlang-module-function-regexp)
- (erlang-get-qualified-function-id-at-point))
- ((looking-at (concat erlang-atom-regexp ":"))
- (erlang-get-module-id-at-point))
- ((looking-at erlang-name-regexp)
- (erlang-get-some-other-id-at-point))))))
-
-(defun erlang-get-qualified-function-id-at-point ()
+ (let (case-fold-search)
+ (save-match-data
+ (if (eq (char-syntax (following-char)) ? )
+ (skip-chars-backward " \t"))
+ (skip-chars-backward "[:word:]_:'")
+ (cond ((and (eq (preceding-char) ??)
+ (looking-at (concat "\\(MODULE\\):" erlang-atom-regexp)))
+ (erlang-get-qualified-function-id-at-point (erlang-get-module)))
+ ((looking-at erlang-module-function-regexp)
+ (erlang-get-qualified-function-id-at-point))
+ ((looking-at (concat erlang-atom-regexp ":"))
+ (erlang-get-module-id-at-point))
+ ((looking-at erlang-name-regexp)
+ (erlang-get-some-other-id-at-point)))))))
+
+(defun erlang-get-qualified-function-id-at-point (&optional module)
(let ((kind 'qualified-function)
- (module (erlang-remove-quotes
- (buffer-substring-no-properties
- (match-beginning 1) (match-end 1))))
+ (module (or module
+ (erlang-remove-quotes
+ (buffer-substring-no-properties
+ (match-beginning 1) (match-end 1)))))
(name (erlang-remove-quotes
(buffer-substring-no-properties
(match-beginning (1+ erlang-atom-regexp-matches))
@@ -3807,7 +3839,8 @@ of arguments could be found, otherwise nil."
(let ((case-fold-search nil)) ; force string matching to be case sensitive
(if (and (stringp str)
(not (string-match (eval-when-compile
- (concat "\\`" erlang-atom-regexp "\\'")) str)))
+ (concat "\\`" erlang-atom-regexp "\\'"))
+ str)))
(progn
(setq str (replace-regexp-in-string "'" "\\'" str t t ))
(concat "'" str "'"))
@@ -4195,22 +4228,18 @@ Return t if criteria fulfilled, nil otherwise."
nil)))))
-(defun erlang-in-literal (&optional lim)
+(defun erlang-in-literal ()
"Test if point is in string, quoted atom or comment.
Return one of the three atoms `atom', `string', and `comment'.
Should the point be inside none of the above mentioned types of
context, nil is returned."
(save-excursion
- (let* ((lim (or lim (save-excursion
- (erlang-beginning-of-clause)
- (point))))
- (state (funcall (symbol-function 'syntax-ppss))))
- (cond
- ((eq (nth 3 state) ?') 'atom)
- ((nth 3 state) 'string)
- ((nth 4 state) 'comment)
- (t nil)))))
+ (let ((state (funcall (symbol-function 'syntax-ppss))))
+ (cond ((eq (nth 3 state) ?') 'atom)
+ ((nth 3 state) 'string)
+ ((nth 4 state) 'comment)
+ (t nil)))))
(defun erlang-at-end-of-function-p ()
@@ -4865,15 +4894,36 @@ about Erlang modules."
;; The backend below is a wrapper around the built-in etags backend.
;; It adds awareness of the module:tag syntax in a similar way that is
;; done above for the old etags commands.
+;;
+;; In addition arity is also considered when jumping to definitions.
+;; There is however currently no information about arity in the TAGS
+;; file. Also two functions with the same name but different arity
+;; _sometimes_ get one TAGS entry each and sometimes are joined in one
+;; single entry. If they are directly consecutive they will be
+;; joined. If there are other functions etc in between then they will
+;; get one entry each.
+;;
+;; These limitations are present in both the etags program shipped
+;; with GNU Emacs and the tags.erl program in this repository.
+;;
+;; Therefore erlang.el must complement the information in TAGS by
+;; visiting files and checking arity. When searching for popular
+;; function names (like init, handle_call etc) in a big TAGS file
+;; (like one indexing this repository) this may be quite
+;; time-consuming. There exists therefore an upper limit for the
+;; number of files to visit (called
+;; `erlang-max-files-to-visit-for-refining-xrefs').
+;;
+;; As mentioned this xref implementation is based on the etags xref
+;; implementation. But in the cases where arity is considered the
+;; etags information structures (class xref-etags-location) will be
+;; translated to our own structures which include arity (class
+;; erlang-xref-location). This translation is started in the function
+;; `erlang-refine-xrefs'.
-(defvar erlang-current-arity nil
- "The arity of the function currently being searched.
-
-There is no information about arity in the TAGS file.
-Consecutive functions with same name but different arity will
-only get one entry in the TAGS file. Matching TAGS entries are
-therefore selected without regarding arity. The arity is
-considered first when it is time to jump to the definition.")
+;; I mention this as a head up that some of the functions below deal
+;; with xref items with xref-etags-location and some deal with xref
+;; items with erlang-xref-location.
(defun erlang-etags--xref-backend () 'erlang-etags)
@@ -4881,127 +4931,80 @@ considered first when it is time to jump to the definition.")
(when (locate-library (symbol-name feature))
(require feature)))
-(and (erlang-soft-require 'xref)
- (erlang-soft-require 'cl-generic)
- (erlang-soft-require 'eieio)
- (erlang-soft-require 'etags)
- ;; The purpose of using eval here is to avoid compilation
- ;; warnings in emacsen without cl-defmethod etc.
- (eval
- '(progn
- (cl-defmethod xref-backend-identifier-at-point
- ((_backend (eql erlang-etags)))
- (if (eq this-command 'xref-find-references)
- (if (use-region-p)
- (buffer-substring-no-properties (region-beginning)
- (region-end))
- (thing-at-point 'symbol))
- (erlang-id-to-string (erlang-get-identifier-at-point))))
-
- (cl-defmethod xref-backend-definitions
- ((_backend (eql erlang-etags)) identifier)
- (erlang-xref-find-definitions identifier))
-
- (cl-defmethod xref-backend-apropos
- ((_backend (eql erlang-etags)) identifier)
- (erlang-xref-find-definitions identifier t))
-
- (cl-defmethod xref-backend-identifier-completion-table
- ((_backend (eql erlang-etags)))
- (let ((erlang-replace-etags-tags-completion-table t))
- (tags-completion-table)))
-
- (defclass erlang-xref-location (xref-etags-location) ())
-
- (defun erlang-convert-xrefs (xrefs)
- (mapcar (lambda (xref)
- (oset xref location (erlang-make-location
- (oref xref location)))
- xref)
- xrefs))
-
- (defun erlang-make-location (etags-location)
- (with-slots (tag-info file) etags-location
- (make-instance 'erlang-xref-location :tag-info tag-info
- :file file)))
-
- (cl-defmethod xref-location-marker ((locus erlang-xref-location))
- (with-slots (tag-info file) locus
- (with-current-buffer (find-file-noselect file)
- (save-excursion
- (or (erlang-goto-tag-location-by-arity tag-info)
- (etags-goto-tag-location tag-info))
- ;; Reset erlang-current-arity. We want to jump to
- ;; correct arity in the first attempt. That is now
- ;; done. Possible remaining jumps will be from
- ;; entries in the *xref* buffer and then we want to
- ;; ignore the arity. (Alternatively we could remove
- ;; all but one xref entry per file when we know the
- ;; arity).
- (setq erlang-current-arity nil)
- (point-marker)))))
-
- (defun erlang-xref-context (xref)
- (with-slots (tag-info) (xref-item-location xref)
- (car tag-info))))))
-
-
-(defun erlang-goto-tag-location-by-arity (tag-info)
- (when erlang-current-arity
- (let* ((tag-text (car tag-info))
- (tag-pos (cdr (cdr tag-info)))
- (tag-line (car (cdr tag-info)))
- (regexp (erlang-tag-info-regexp tag-text))
- (startpos (or tag-pos
- (when tag-line
- (goto-char (point-min))
- (forward-line (1- tag-line))
- (point))
- (point-min))))
- (setq startpos (max (- startpos 2000)
- (point-min)))
- (goto-char startpos)
- (let ((pos (or (erlang-search-by-arity regexp)
- (unless (eq startpos (point-min))
- (goto-char (point-min))
- (erlang-search-by-arity regexp)))))
- (when pos
- (goto-char pos)
- t)))))
-
-(defun erlang-tag-info-regexp (tag-text)
- (concat "^"
- (regexp-quote tag-text)
- ;; Erlang function entries in TAGS includes the opening
- ;; parenthesis for the argument list. Erlang macro entries
- ;; do not. Add it here in order to end up in correct
- ;; position for erlang-get-arity.
- (if (string-prefix-p "-define" tag-text)
- "\\s-*("
- "")))
-
-(defun erlang-search-by-arity (regexp)
- (let (pos)
- (while (and (null pos)
- (re-search-forward regexp nil t))
- (when (eq erlang-current-arity (save-excursion (erlang-get-arity)))
- (setq pos (point-at-bol))))
- pos))
-
-
+(when (and (erlang-soft-require 'xref)
+ (erlang-soft-require 'cl-generic)
+ (erlang-soft-require 'eieio)
+ (erlang-soft-require 'etags))
+ ;; The purpose of using eval here is to avoid compilation
+ ;; warnings in emacsen without cl-defmethod etc.
+ (eval
+ '(progn
+ (cl-defmethod xref-backend-identifier-at-point ((_backend
+ (eql erlang-etags)))
+ (if (eq this-command 'xref-find-references)
+ (if (use-region-p)
+ (buffer-substring-no-properties (region-beginning)
+ (region-end))
+ (thing-at-point 'symbol))
+ (erlang-id-to-string (erlang-get-identifier-at-point))))
+
+ (cl-defmethod xref-backend-definitions ((_backend (eql erlang-etags))
+ identifier)
+ (erlang-xref-find-definitions identifier))
+
+ (cl-defmethod xref-backend-apropos ((_backend (eql erlang-etags))
+ identifier)
+ (erlang-xref-find-definitions identifier t))
+
+ (cl-defmethod xref-backend-identifier-completion-table
+ ((_backend (eql erlang-etags)))
+ (let ((erlang-replace-etags-tags-completion-table t))
+ (tags-completion-table)))
+
+ (defclass erlang-xref-location (xref-file-location)
+ ((arity :type fixnum :initarg :arity
+ :reader erlang-xref-location-arity))
+ :documentation "An erlang location is a file location plus arity.")
+
+ ;; This method definition only calls the superclass which is
+ ;; the default behaviour if it was not defined. It is only
+ ;; needed for "upgrade" purposes. In version 2.8.1 of
+ ;; erlang.el this method was defined differently and in case
+ ;; user switch to a new erlang.el without restarting Emacs
+ ;; this method needs to be redefined.
+ (cl-defmethod xref-location-marker ((locus erlang-xref-location))
+ (cl-call-next-method locus)))))
+
+;; If this function returns a single xref the user will jump to that
+;; directly. If two or more xrefs are returned a *xref* window is
+;; displayed and the user can choose where to jump. Hence we want to
+;; return a single xref when we are pretty sure that is where the user
+;; wants to go. Otherwise return all possible xrefs but sort them so
+;; that xrefs in the local file is first and if arity is known sort
+;; the xrefs with matching arity before others.
+
+;; Note that the arity sorting work may partly be undone later when
+;; the hits are presented in the *xref* buffer since they then will be
+;; grouped together by file. Ie when one file have one hit with
+;; correct arity and others with wrong arity these hits will be
+;; grouped together and may end up before hits with correct arity.
(defun erlang-xref-find-definitions (identifier &optional is-regexp)
(erlang-with-id (kind module name arity) identifier
- (setq erlang-current-arity arity)
(cond ((eq kind 'module)
(erlang-xref-find-definitions-module name))
+ ((eq kind 'qualified-function)
+ (erlang-xref-find-definitions-qualified-function module
+ name
+ arity
+ is-regexp))
(module
- (erlang-xref-find-definitions-module-tag module
+ (erlang-xref-find-definitions-module-tag kind
+ module
name
- (eq kind
- 'qualified-function)
+ arity
is-regexp))
(t
- (erlang-xref-find-definitions-tag kind name is-regexp)))))
+ (erlang-xref-find-definitions-tag kind name arity is-regexp)))))
(defun erlang-xref-find-definitions-module (module)
(and (fboundp 'xref-make)
@@ -5026,62 +5029,252 @@ considered first when it is time to jump to the definition.")
(setq files (cdr files))))))
(nreverse xrefs))))
-(defun erlang-visit-tags-table-buffer (cont cbuf)
- (if (< emacs-major-version 26)
- (visit-tags-table-buffer cont)
- (visit-tags-table-buffer cont cbuf)))
-
-(defun erlang-xref-find-definitions-module-tag (module
+(defun erlang-xref-find-definitions-qualified-function (module
+ tag
+ arity
+ is-regexp)
+ "Find definitions of TAG in MODULE preferably with arity ARITY.
+If one single perfect match was found return only that (ignoring
+other definitions matching TAG). If IS-REGEXP is non-nil then
+TAG is a regexp."
+ (let* ((xrefs (when (fboundp 'etags--xref-find-definitions)
+ (etags--xref-find-definitions tag is-regexp)))
+ (xrefs-split (erlang-split-xrefs-on-module xrefs module))
+ (module-xrefs (car xrefs-split))
+ (module-xrefs (erlang-refine-xrefs module-xrefs
+ 'qualified-function
+ tag
+ is-regexp)))
+ (or (erlang-single-arity-match module-xrefs arity)
+ (erlang-sort-by-arity module-xrefs arity))))
+
+
+;; We will end up here when erlang-get-some-other-id-at-point either
+;; found module among the import statements or module is just the
+;; current local file.
+(defun erlang-xref-find-definitions-module-tag (kind
+ module
tag
- is-qualified
+ arity
is-regexp)
- "Find definitions of TAG and filter away definitions outside of
-MODULE. If IS-QUALIFIED is nil and no definitions was found inside
-the MODULE then return any definitions found outside. If
-IS-REGEXP is non-nil then TAG is a regexp."
- (and (fboundp 'etags--xref-find-definitions)
- (fboundp 'erlang-convert-xrefs)
- (let ((xrefs (erlang-convert-xrefs
- (etags--xref-find-definitions tag is-regexp)))
- xrefs-in-module)
- (dolist (xref xrefs)
- (when (string-equal module (erlang-xref-module xref))
- (push xref xrefs-in-module)))
- (cond (is-qualified xrefs-in-module)
- (xrefs-in-module xrefs-in-module)
- (t xrefs)))))
-
-(defun erlang-xref-find-definitions-tag (kind tag is-regexp)
- "Find all definitions of TAG and reorder them so that
-definitions in the currently visited file comes first."
- (and (fboundp 'etags--xref-find-definitions)
- (fboundp 'erlang-convert-xrefs)
- (let* ((current-file (and (buffer-file-name)
- (file-truename (buffer-file-name))))
- (regexp (erlang-etags-regexp kind tag is-regexp))
- (xrefs (erlang-convert-xrefs
- (etags--xref-find-definitions regexp t)))
- local-xrefs non-local-xrefs)
- (while xrefs
- (let ((xref (car xrefs)))
- (if (string-equal (erlang-xref-truename-file xref)
- current-file)
- (push xref local-xrefs)
- (push xref non-local-xrefs))
- (setq xrefs (cdr xrefs))))
- (append (reverse local-xrefs)
- (reverse non-local-xrefs)))))
+ "Find definitions of TAG preferably in MODULE and with arity ARITY.
+Return definitions outside MODULE if none are found inside. If
+IS-REGEXP is non-nil then TAG is a regexp.
+
+If one single perfect match was found return only that (ignoring
+other definitions matching TAG)."
+ (let* ((xrefs (when (fboundp 'etags--xref-find-definitions)
+ (etags--xref-find-definitions tag is-regexp)))
+ (xrefs-split (erlang-split-xrefs-on-module xrefs module))
+ (module-xrefs (car xrefs-split))
+ (module-xrefs (erlang-refine-xrefs module-xrefs
+ kind
+ tag
+ is-regexp)))
+ (or (erlang-single-arity-match module-xrefs arity)
+ (erlang-xref-find-definitions-tag kind tag arity is-regexp xrefs))))
+
+(defun erlang-xref-find-definitions-tag (kind
+ tag
+ arity
+ is-regexp
+ &optional xrefs)
+ "Find definitions of TAG preferably in local file and with arity ARITY.
+If one single perfect match was found return only that (ignoring
+other definitions matching TAG). If no such local match was
+found then look for a matching BIF in the same way. If IS-REGEXP
+is non-nil then TAG is a regexp."
+ (let* ((regexp (erlang-etags-regexp kind tag is-regexp))
+ (xrefs (or xrefs
+ (when (fboundp 'etags--xref-find-definitions)
+ (etags--xref-find-definitions regexp t))))
+ (xrefs-split (erlang-split-xrefs xrefs))
+ (local-xrefs (car xrefs-split))
+ (local-xrefs (erlang-refine-xrefs local-xrefs
+ kind
+ tag
+ is-regexp))
+ (bif-xrefs (cadr xrefs-split))
+ (other-xrefs (caddr xrefs-split)))
+ (or (erlang-single-arity-match local-xrefs arity)
+ ;; No local match, look for a matching BIF.
+ (progn
+ (setq bif-xrefs (erlang-refine-xrefs bif-xrefs
+ kind
+ tag
+ is-regexp))
+ (erlang-single-arity-match bif-xrefs arity))
+ (progn
+ (setq other-xrefs (erlang-refine-xrefs other-xrefs
+ kind
+ tag
+ is-regexp))
+ (and (null local-xrefs)
+ (null bif-xrefs)
+ ;; No local of BIF matches at all. Is there a single
+ ;; arity match among the rest?
+ (erlang-single-arity-match other-xrefs arity)))
+ (append (erlang-sort-by-arity local-xrefs arity)
+ (erlang-sort-by-arity bif-xrefs arity)
+ (erlang-sort-by-arity other-xrefs arity)))))
+
+
+(defun erlang-refine-xrefs (xrefs kind tag is-regexp)
+ (if (or (memq kind '(record module))
+ ;; No support for apropos here.
+ is-regexp
+ (erlang-too-many-files-in-xrefs xrefs))
+ xrefs
+ (when (and xrefs
+ (fboundp 'xref-item-location)
+ (fboundp 'xref-location-group)
+ (fboundp 'slot-value))
+ (let (files)
+ (cl-loop for xref in xrefs
+ for loc = (xref-item-location xref)
+ for file = (xref-location-group loc)
+ do (pushnew file files :test 'string-equal))
+ (or (cl-loop for file in files
+ append (erlang-xrefs-in-file file kind tag is-regexp))
+ ;; Failed for some reason. Pretend like it is raining and
+ ;; return the unrefined xrefs.
+ xrefs)))))
+
+(defun erlang-too-many-files-in-xrefs (xrefs)
+ (and erlang-max-files-to-visit-for-refining-xrefs
+ (let ((files-to-visit (delete-dups
+ (mapcar #'erlang-xref-truename-file
+ xrefs))))
+ (if (< (length files-to-visit)
+ erlang-max-files-to-visit-for-refining-xrefs)
+ nil
+ (message (concat "Too many hits to consider arity (see "
+ "`erlang-max-files-to-visit-for-refining-xrefs')"))
+ t))))
+
+(defun erlang-xrefs-in-file (file kind tag is-regexp)
+ (when (fboundp 'make-instance)
+ (with-current-buffer (find-file-noselect file)
+ (save-excursion
+ (goto-char (point-min))
+ (let ((regexp (concat ; "^"
+ (erlang-etags-regexp kind tag is-regexp)
+ "\\s *("))
+ last-arity)
+ (cl-loop while (re-search-forward regexp nil t)
+ for name = (match-string-no-properties 1)
+ for arity = (save-excursion
+ (erlang-get-arity))
+ for loc = (make-instance 'erlang-xref-location
+ :file file
+ :line (line-number-at-pos)
+ :column 0
+ :arity arity)
+ for sum = (erlang-xref-summary kind name arity)
+ when (and arity
+ (not (eq arity last-arity)))
+ collect (make-instance 'xref-item
+ :summary sum
+ :location loc)
+ do (setq last-arity arity)))))))
+
+(defun erlang-xref-summary (kind tag arity)
+ (format "%s%s%s"
+ (if (memq kind '(record macro module))
+ (format "%s " kind)
+ "")
+ tag
+ (if arity (format "/%s" arity) "")))
+
+(defun erlang-single-arity-match (xrefs wanted-arity)
+ "Attempt to find one perfect match.
+
+If we have all information needed to consider arity then return a
+single perfect match or nothing. If there are more than one
+match nothing is returned.
+
+If we don't have all information needed to consider arity just
+return XREFS as is."
+ (if (erlang-should-consider-arity-p xrefs wanted-arity)
+ (let ((nr-matches 0)
+ match)
+ (while (and xrefs
+ (< nr-matches 2))
+ (let* ((xref (car xrefs))
+ (arity (erlang-xref-arity xref)))
+ (when (eq arity wanted-arity)
+ (setq match xref
+ nr-matches (1+ nr-matches)))
+ (setq xrefs (cdr xrefs))))
+ (when (eq nr-matches 1)
+ (list match)))
+ (when (eq (length xrefs) 1)
+ xrefs)))
+
+(defun erlang-sort-by-arity (xrefs wanted-arity)
+ (if (erlang-should-consider-arity-p xrefs wanted-arity)
+ (let (matches non-matches)
+ (while xrefs
+ (let* ((xref (car xrefs))
+ (arity (erlang-xref-arity xref)))
+ (push xref (if (eq arity wanted-arity)
+ matches
+ non-matches))
+ (setq xrefs (cdr xrefs))))
+ (append (reverse matches) (reverse non-matches) xrefs))
+ xrefs))
+
+(defun erlang-should-consider-arity-p (xrefs wanted-arity)
+ (and wanted-arity
+ xrefs
+ (fboundp 'erlang-xref-location-p)
+ (fboundp 'xref-item-location)
+ (erlang-xref-location-p (xref-item-location (car xrefs)))))
(defun erlang-etags-regexp (kind tag is-regexp)
- (let ((tag-regexp (if is-regexp
- tag
- (regexp-quote tag))))
- (cond ((eq kind 'record)
- (concat "-record\\s-*(\\s-*" tag-regexp))
- ((eq kind 'macro)
- (concat "-define\\s-*(\\s-*" tag-regexp))
- (t tag-regexp))))
-
+ (let ((tag-regexp (concat "\\("
+ (if is-regexp
+ tag
+ (regexp-quote tag))
+ "\\)")))
+ (concat (if is-regexp "" "^")
+ (cond ((eq kind 'record)
+ (concat "-record\\s-*(\\s-*" tag-regexp))
+ ((eq kind 'macro)
+ (concat "-define\\s-*(\\s-*" tag-regexp))
+ (t
+ tag-regexp))
+ (if is-regexp "" "\\_>"))))
+
+(defun erlang-xref-arity (xref)
+ (and (fboundp 'erlang-xref-location-arity)
+ (fboundp 'xref-item-location)
+ (erlang-xref-location-arity (xref-item-location xref))))
+
+(defun erlang-split-xrefs-on-module (xrefs module)
+ (let (local-xrefs non-local-xrefs)
+ (dolist (xref xrefs)
+ (if (string-equal (erlang-xref-module xref)
+ module)
+ (push xref local-xrefs)
+ (push xref non-local-xrefs)))
+ (cons (reverse local-xrefs)
+ (reverse non-local-xrefs))))
+
+(defun erlang-split-xrefs (xrefs)
+ (let ((current-file (and (buffer-file-name)
+ (file-truename (buffer-file-name))))
+ local-xrefs bif-xrefs other-xrefs)
+ (dolist (xref xrefs)
+ (cond ((string-equal (erlang-xref-truename-file xref) current-file)
+ (push xref local-xrefs))
+ ((string-equal (erlang-xref-module xref) "erlang")
+ (push xref bif-xrefs))
+ (t
+ (push xref other-xrefs))))
+ (list (reverse local-xrefs)
+ (reverse bif-xrefs)
+ (reverse other-xrefs))))
(defun erlang-xref-module (xref)
(erlang-get-module-from-file-name (erlang-xref-file xref)))
@@ -5096,7 +5289,13 @@ definitions in the currently visited file comes first."
(fboundp 'xref-item-location)
(xref-location-group (xref-item-location xref))))
-
+(defun erlang-visit-tags-table-buffer (cont cbuf)
+ (if (< emacs-major-version 26)
+ (visit-tags-table-buffer cont)
+ ;; Remove this with-no-warnings when Emacs 26 is the required
+ ;; version minimum.
+ (with-no-warnings
+ (visit-tags-table-buffer cont cbuf))))
;;;
;;; Prepare for other methods to run an Erlang slave process.
@@ -5524,7 +5723,7 @@ Return the position after the newly inserted command."
(+ insert-point insert-length)))
-(defun inferior-erlang-strip-delete (&optional s)
+(defun inferior-erlang-strip-delete (&optional _s)
"Remove `^H' (delete) and the characters it was supposed to remove."
(interactive)
(if (and (boundp 'comint-last-input-end)
@@ -5542,7 +5741,7 @@ Return the position after the newly inserted command."
;; Basically `comint-strip-ctrl-m', with a few extra checks.
-(defun inferior-erlang-strip-ctrl-m (&optional string)
+(defun inferior-erlang-strip-ctrl-m (&optional _string)
"Strip trailing `^M' characters from the current output group."
(interactive)
(if (and (boundp 'comint-last-input-end)
@@ -5579,8 +5778,8 @@ There exists two workarounds for this bug:
(let* ((dir (inferior-erlang-compile-outdir))
(noext (substring (erlang-local-buffer-file-name) 0 -4))
(opts (append (list (cons 'outdir dir))
- (if current-prefix-arg
- (list 'debug_info 'export_all))
+ (when arg
+ (list 'debug_info 'export_all))
erlang-compile-extra-opts))
end)
(with-current-buffer inferior-erlang-buffer
@@ -5629,7 +5828,6 @@ unless the optional NO-DISPLAY is non-nil."
(defun inferior-erlang-compute-compile-command (module-name opts)
(let ((ccfn erlang-compile-command-function-alist)
- (res (inferior-erlang-compute-erl-compile-command module-name opts))
ccfn-entry
done
result)
diff --git a/lib/tools/emacs/erlang_appwiz.el b/lib/tools/emacs/erlang_appwiz.el
index ecbce66f47..b71c180739 100644
--- a/lib/tools/emacs/erlang_appwiz.el
+++ b/lib/tools/emacs/erlang_appwiz.el
@@ -103,6 +103,10 @@
;;
;;
+(defvar appwiz-erlang-modulename "foo")
+(defvar appwiz-erlang-ext "_work")
+
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Erlang application wizard
@@ -245,13 +249,6 @@ creating the root directory and for naming application files."
(insert "Application specification file for " name ".")
(save-buffer)))
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;; These are setq:ed
-;;
-
-(defvar appwiz-erlang-modulename "foo")
-(defvar appwiz-erlang-ext "_work")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
@@ -468,7 +465,7 @@ Call the function `erlang-menu-init' after modifying this variable.")
The first character of DD is *not* space if the value is less than 10."
(let ((date (current-time-string)))
(format "%d %s %s"
- (string-to-int (substring date 8 10))
+ (string-to-number (substring date 8 10))
(substring date 4 7)
(substring date -4))))
diff --git a/lib/tools/emacs/erldoc.el b/lib/tools/emacs/erldoc.el
index 770ab299ee..bc16d7a14d 100644
--- a/lib/tools/emacs/erldoc.el
+++ b/lib/tools/emacs/erldoc.el
@@ -89,6 +89,13 @@ up the indexing."
:type 'file
:group 'erldoc)
+(defcustom erldoc-no-signature-function #'ignore
+ "Notification function called if no function signature was found."
+ :type '(choice (function-item :tag "Ignore" ignore)
+ (function-item :tag "Warn" warn)
+ (function-item :tag "Error" error))
+ :group 'erldoc)
+
(defun erldoc-strip-string (s)
(let* ((re "[ \t\n\r\f\v\u00a0]+")
(from (if (string-match (concat "\\`" re) s) (match-end 0) 0))
@@ -212,11 +219,21 @@ up the indexing."
;; Get the full function signature.
(when (and (eq (car-safe d) 'a)
(gethash (erldoc-dom-get-attribute d 'name) table))
- (push (append (gethash (erldoc-dom-get-attribute d 'name) table)
- (list (funcall span-content
- (or (erldoc-dom-get-element d 'span)
- (cadr (memq d erldoc-dom-walk-siblings))))))
- entries))
+ (let* ((name (erldoc-dom-get-attribute d 'name))
+ (mfa-url (gethash name table))
+ (mfa (car mfa-url))
+ (sig (or (funcall span-content d)
+ (funcall span-content
+ (or (erldoc-dom-get-element d 'span)
+ (cadr
+ (memq d erldoc-dom-walk-siblings))))
+ (progn
+ (funcall erldoc-no-signature-function
+ "erldoc-parse-man: no sig for %s"
+ mfa)
+ nil))))
+ (push (append mfa-url (list sig))
+ entries)))
;; Get data types
(when (and (eq (car-safe d) 'a)
(string-prefix-p "type-"
@@ -280,7 +297,7 @@ up the indexing."
(unless (file-exists-p of)
(erldoc-parse-all erldoc-man-index of))
(unless (string= erldoc-output-file of)
- (make-symbolic-link of erldoc-output-file))))
+ (make-symbolic-link (expand-file-name of) erldoc-output-file))))
(setq erldoc-lookup-table
(with-temp-buffer
(insert-file-contents erldoc-output-file)
@@ -356,9 +373,12 @@ up the indexing."
(sigs))
(maphash (lambda (k v)
(when (string-match re k)
- (push (cons (string-to-number (match-string 1 k))
- (cdr (erldoc-tokenize-signature (cadr v))))
- sigs)))
+ (if (cadr v)
+ (push (cons (string-to-number (match-string 1 k))
+ (cdr (erldoc-tokenize-signature (cadr v))))
+ sigs)
+ (funcall erldoc-no-signature-function
+ "erldoc-format-signature: No sig for %s" k))))
(erldoc-lookup-table))
(when sigs
;; Mostly single return type but there are exceptions such as
diff --git a/lib/tools/priv/styles.css b/lib/tools/priv/styles.css
new file mode 100644
index 0000000000..84f00be9fd
--- /dev/null
+++ b/lib/tools/priv/styles.css
@@ -0,0 +1,96 @@
+body {
+ font: 14px/1.6 "Helvetica Neue", Helvetica, Arial, sans-serif;
+ margin: 0;
+ padding: 0;
+ color: #000;
+ border-top: 2px solid #ddd;
+ background-color: #fff;
+
+ min-height: 100%;
+ display: flex;
+ flex-direction: column;
+}
+
+h1 {
+ width: 100%;
+ border-bottom: 1px solid #eee;
+ margin-bottom: 0;
+ font-weight: 100;
+ font-size: 1.1em;
+ letter-spacing: 1px;
+}
+
+h1 code {
+ font-size: 0.96em;
+}
+
+code {
+ font: 12px monospace;
+}
+
+footer {
+ background: #eee;
+ width: 100%;
+ padding: 10px 0;
+ text-align: right;
+ border-top: 1px solid #ddd;
+ display: flex;
+ flex: 1;
+ order: 2;
+ justify-content: center;
+}
+
+table {
+ width: 100%;
+ margin-top: 10px;
+ border-collapse: collapse;
+ border: 1px solid #cbcbcb;
+ color: #000;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+}
+table thead {
+ display: none;
+}
+table td.line,
+table td.line a,
+table td.hits {
+ width: 20px;
+ background: #eaeaea;
+ text-align: center;
+ text-decoration: none;
+ font-size: 11px;
+ padding: 0 10px;
+ color: #949494;
+}
+table td.hits {
+ width: 10px;
+ text-align: right;
+ padding: 2px 5px;
+ color: rgba(0, 0, 0, 0.6);
+ background-color: #f0f0f0;
+}
+tr.miss td.line,
+tr.miss td.line a,
+tr.miss td.hits {
+ background-color: #ffdce0;
+ border-color: #fdaeb7;
+}
+tr.miss td {
+ background-color: #ffeef0;
+}
+tr.hit td.line,
+tr.hit td.line a,
+tr.hit td.hits {
+ background-color: #cdffd8;
+ border-color: #bef5cb;
+}
+tr.hit td {
+ background-color: #e6ffed;
+}
+td.source {
+ padding-left: 15px;
+ line-height: 15px;
+ white-space: pre;
+ font: 12px monospace;
+}
diff --git a/lib/tools/src/Makefile b/lib/tools/src/Makefile
index 032bd612db..cc5bee9a8f 100644
--- a/lib/tools/src/Makefile
+++ b/lib/tools/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2016. All Rights Reserved.
+# Copyright Ericsson AB 1996-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -72,6 +72,9 @@ APP_TARGET = $(EBIN)/$(APP_FILE)
APPUP_SRC = $(APPUP_FILE).src
APPUP_TARGET = $(EBIN)/$(APPUP_FILE)
+PRIVDIR = ../priv
+CSS = $(PRIVDIR)/styles.css
+
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
@@ -110,5 +113,7 @@ release_spec: opt
$(INSTALL_DIR) "$(RELSYSDIR)/ebin"
$(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) \
"$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv"
+ $(INSTALL_DATA) $(CSS) "$(RELSYSDIR)/priv"
release_docs_spec:
diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl
index 4e64d7aa4e..8fe866cb69 100644
--- a/lib/tools/src/cover.erl
+++ b/lib/tools/src/cover.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@
%% This module implements the Erlang coverage tool.
%%
%% ARCHITECTURE
+%%
%% The coverage tool consists of one process on each node involved in
%% coverage analysis. The process is registered as 'cover_server'
%% (?SERVER). The cover_server on the 'main' node is in charge, and
@@ -30,45 +31,62 @@
%% 'DOWN' message for another cover_server, it marks the node as
%% 'lost'. If a nodeup is received for a lost node the main node
%% ensures that the cover compiled modules are loaded again. If the
-%% remote node was alive during the disconnected periode, cover data
-%% for this periode will also be included in the analysis.
+%% remote node was alive during the disconnected period, cover data
+%% for this period will also be included in the analysis.
%%
%% The cover_server process on the main node is implemented by the
%% functions init_main/1 and main_process_loop/1. The cover_server on
%% the remote nodes are implemented by the functions init_remote/2 and
%% remote_process_loop/1.
%%
+%% COUNTERS
+%%
+%% The 'counters' modules is used for counting how many time each line
+%% executed. Each cover-compiled module will have its own array of
+%% counters.
+%%
+%% The counter reference for module Module is stored in a persistent
+%% term with the key {cover,Module}.
+%%
+%% When the cover:local_only/0 function has been called, the reference
+%% for the counter array will be compiled into each cover-compiled
+%% module directly (instead of retrieving it from a persistent term).
+%% That will be faster, but the resulting code can be only be used on
+%% the main node.
+%%
%% TABLES
-%% Each nodes has two tables: cover_internal_data_table (?COVER_TABLE) and.
-%% cover_internal_clause_table (?COVER_CLAUSE_TABLE).
-%% ?COVER_TABLE contains the bump data i.e. the data about which lines
-%% have been executed how many times.
+%%
+%% Each node has two tables: ?COVER_MAPPING_TABLE and ?COVER_CLAUSE_TABLE.
+%% ?COVER_MAPPING_TABLE maps from a #bump{} record to an index in the
+%% counter array for the module. It is used both during instrumentation
+%% of cover-compiled modules and when collecting the counter values.
+%%
%% ?COVER_CLAUSE_TABLE contains information about which clauses in which modules
%% cover is currently collecting statistics.
-%%
-%% The main node owns tables named
-%% 'cover_collected_remote_data_table' (?COLLECTION_TABLE) and
-%% 'cover_collected_remote_clause_table' (?COLLECTION_CLAUSE_TABLE).
-%% These tables contain data which is collected from remote nodes (either when a
-%% remote node is stopped with cover:stop/1 or when analysing). When
-%% analysing, data is even moved from the COVER tables on the main
-%% node to the COLLECTION tables.
%%
-%% The main node also has a table named 'cover_binary_code_table'
-%% (?BINARY_TABLE). This table contains the binary code for each cover
-%% compiled module. This is necessary so that the code can be loaded
-%% on remote nodes that are started after the compilation.
+%% The main node owns the tables ?COLLECTION_TABLE and
+%% ?COLLECTION_CLAUSE_TABLE. The counter data is consolidated into those
+%% tables from the counters on both the main node and from remote nodes.
+%% This consolidation is done when a remote node is stopped with
+%% cover:stop/1 or just before starting an analysis.
+%%
+%% The main node also has a table named ?BINARY_TABLE. This table
+%% contains the abstract code code for each cover-compiled
+%% module. This is necessary so that the code can be loaded on remote
+%% nodes that are started after the compilation.
%%
%% PARALLELISM
+%%
%% To take advantage of SMP when doing the cover analysis both the data
%% collection and analysis has been parallelized. One process is spawned for
%% each node when collecting data, and on the remote node when collecting data
%% one process is spawned per module.
%%
-%% When analyzing data it is possible to issue multiple analyse(_to_file)/X
-%% calls at once. They are however all calls (for backwards compatibility
-%% reasons) so the user of cover will have to spawn several processes to to the
-%% calls ( or use async_analyse_to_file ).
+%% When analyzing data it is possible to issue multiple
+%% analyse(_to_file)/X calls at once. They are, however, all calls
+%% (for backwards compatibility reasons), so the user of cover will
+%% have to spawn several processes to to the calls (or use
+%% async_analyse_to_file/X).
%%
%% External exports
@@ -89,7 +107,8 @@
modules/0, imported/0, imported_modules/0, which_nodes/0, is_compiled/1,
reset/1, reset/0,
flush/1,
- stop/0, stop/1]).
+ stop/0, stop/1,
+ local_only/0]).
-export([remote_start/1,get_main_node/0]).
%% Used internally to ensure we upgrade the code to the latest version.
@@ -98,9 +117,16 @@
-record(main_state, {compiled=[], % [{Module,File}]
imported=[], % [{Module,File,ImportFile}]
stopper, % undefined | pid()
+ local_only=false, % true | false
nodes=[], % [Node]
lost_nodes=[]}). % [Node]
+-record(remote_data, {module,
+ file,
+ code,
+ mapping,
+ clauses}).
+
-record(remote_state, {compiled=[], % [{Module,File}]
main_node}). % atom()
@@ -126,11 +152,12 @@
is_guard=false % boolean
}).
--define(COVER_TABLE, 'cover_internal_data_table').
+-define(COVER_MAPPING_TABLE, 'cover_internal_mapping_table').
-define(COVER_CLAUSE_TABLE, 'cover_internal_clause_table').
-define(BINARY_TABLE, 'cover_binary_code_table').
-define(COLLECTION_TABLE, 'cover_collected_remote_data_table').
-define(COLLECTION_CLAUSE_TABLE, 'cover_collected_remote_clause_table').
+
-define(TAG, cover_compiled).
-define(SERVER, cover_server).
@@ -144,6 +171,8 @@
end).
-define(SPAWN_DBG(Tag,Value),put(Tag,Value)).
+-define(STYLESHEET, "styles.css").
+-define(TOOLS_APP, tools).
-include_lib("stdlib/include/ms_transform.hrl").
@@ -184,6 +213,11 @@ start(Node) when is_atom(Node) ->
start(Nodes) ->
call({start_nodes,remove_myself(Nodes,[])}).
+%% local_only() -> ok | {error,too_late}
+
+local_only() ->
+ call(local_only).
+
%% compile(ModFiles) ->
%% compile(ModFiles, Options) ->
%% compile_module(ModFiles) -> Result
@@ -253,15 +287,8 @@ compile_directory(Dir, Options) when is_list(Dir), is_list(Options) ->
compile_modules(Files,Options) ->
Options2 = filter_options(Options),
- %% compile_modules(Files,Options2,[]).
call({compile, Files, Options2}).
-%% compile_modules([File|Files], Options, Result) ->
-%% R = call({compile, File, Options}),
-%% compile_modules(Files,Options,[R|Result]);
-%% compile_modules([],_Opts,Result) ->
-%% lists:reverse(Result).
-
filter_options(Options) ->
lists:filter(fun(Option) ->
case Option of
@@ -559,16 +586,6 @@ flush(Nodes) ->
get_main_node() ->
call(get_main_node).
-%% bump(Module, Function, Arity, Clause, Line)
-%% Module = Function = atom()
-%% Arity = Clause = Line = integer()
-%% This function is inserted into Cover compiled modules, once for each
-%% executable line.
-%bump(Module, Function, Arity, Clause, Line) ->
-% Key = #bump{module=Module, function=Function, arity=Arity, clause=Clause,
-% line=Line},
-% ets:update_counter(?COVER_TABLE, Key, 1).
-
call(Request) ->
Ref = erlang:monitor(process,?SERVER),
receive {'DOWN', Ref, _Type, _Object, noproc} ->
@@ -629,10 +646,8 @@ remote_reply(MainNode,Reply) ->
init_main(Starter) ->
register(?SERVER,self()),
- %% Having write concurrancy here gives a 40% performance boost
- %% when collect/1 is called.
- ?COVER_TABLE = ets:new(?COVER_TABLE, [set, public, named_table,
- {write_concurrency, true}]),
+ ?COVER_MAPPING_TABLE = ets:new(?COVER_MAPPING_TABLE,
+ [ordered_set, public, named_table]),
?COVER_CLAUSE_TABLE = ets:new(?COVER_CLAUSE_TABLE, [set, public,
named_table]),
?BINARY_TABLE = ets:new(?BINARY_TABLE, [set, public, named_table]),
@@ -646,10 +661,26 @@ init_main(Starter) ->
main_process_loop(State) ->
receive
+ {From, local_only} ->
+ case State of
+ #main_state{compiled=[],nodes=[]} ->
+ reply(From, ok),
+ main_process_loop(State#main_state{local_only=true});
+ #main_state{} ->
+ reply(From, {error,too_late}),
+ main_process_loop(State)
+ end;
+
{From, {start_nodes,Nodes}} ->
- {StartedNodes,State1} = do_start_nodes(Nodes, State),
- reply(From, {ok,StartedNodes}),
- main_process_loop(State1);
+ case State#main_state.local_only of
+ false ->
+ {StartedNodes,State1} = do_start_nodes(Nodes, State),
+ reply(From, {ok,StartedNodes}),
+ main_process_loop(State1);
+ true ->
+ reply(From, {error,local_only}),
+ main_process_loop(State)
+ end;
{From, {compile, Files, Options}} ->
{R,S} = do_compile(Files, Options, State),
@@ -740,11 +771,12 @@ main_process_loop(State) ->
end,
State#main_state.nodes),
reload_originals(State#main_state.compiled),
- ets:delete(?COVER_TABLE),
+ ets:delete(?COVER_MAPPING_TABLE),
ets:delete(?COVER_CLAUSE_TABLE),
ets:delete(?BINARY_TABLE),
ets:delete(?COLLECTION_TABLE),
ets:delete(?COLLECTION_CLAUSE_TABLE),
+ delete_all_counters(),
unregister(?SERVER),
reply(From, ok);
@@ -876,10 +908,8 @@ main_process_loop(State) ->
init_remote(Starter,MainNode) ->
register(?SERVER,self()),
- %% write_concurrency here makes otp_8270 break :(
- ?COVER_TABLE = ets:new(?COVER_TABLE, [set, public, named_table
- %,{write_concurrency, true}
- ]),
+ ?COVER_MAPPING_TABLE = ets:new(?COVER_MAPPING_TABLE,
+ [ordered_set, public, named_table]),
?COVER_CLAUSE_TABLE = ets:new(?COVER_CLAUSE_TABLE, [set, public,
named_table]),
Starter ! {self(),started},
@@ -902,7 +932,7 @@ remote_process_loop(State) ->
remote_process_loop(State#remote_state{compiled=Compiled});
{remote,reset,Module} ->
- do_reset(Module),
+ reset_counters(Module),
remote_reply(State#remote_state.main_node, ok),
remote_process_loop(State);
@@ -923,8 +953,9 @@ remote_process_loop(State) ->
{remote,stop} ->
reload_originals(State#remote_state.compiled),
- ets:delete(?COVER_TABLE),
+ ets:delete(?COVER_MAPPING_TABLE),
ets:delete(?COVER_CLAUSE_TABLE),
+ delete_all_counters(),
unregister(?SERVER),
ok; % not replying since 'DOWN' message will be received anyway
@@ -959,28 +990,12 @@ remote_process_loop(State) ->
end.
do_collect(Modules, CollectorPid, From) ->
- _ = pmap(
- fun(Module) ->
- Pattern = {#bump{module=Module, _='_'}, '$1'},
- MatchSpec = [{Pattern,[{'=/=','$1',0}],['$_']}],
- Match = ets:select(?COVER_TABLE,MatchSpec,?CHUNK_SIZE),
- send_chunks(Match, CollectorPid, [])
- end,Modules),
+ _ = pmap(fun(Module) ->
+ send_counters(Module, CollectorPid)
+ end, Modules),
CollectorPid ! done,
remote_reply(From, ok).
-send_chunks('$end_of_table', _CollectorPid, Mons) ->
- get_downs(Mons);
-send_chunks({Chunk,Continuation}, CollectorPid, Mons) ->
- Mon = spawn_monitor(
- fun() ->
- lists:foreach(fun({Bump,_N}) ->
- ets:insert(?COVER_TABLE, {Bump,0})
- end,
- Chunk) end),
- send_chunk(CollectorPid,Chunk),
- send_chunks(ets:select(Continuation), CollectorPid, [Mon|Mons]).
-
send_chunk(CollectorPid,Chunk) ->
CollectorPid ! {chunk,Chunk,self()},
receive continue -> ok end.
@@ -1019,10 +1034,15 @@ do_reload_original(Module) ->
ignore
end.
-load_compiled([{Module,File,Binary,InitialTable}|Compiled],Acc) ->
- %% Make sure the #bump{} records are available *before* the
- %% module is loaded.
- insert_initial_data(InitialTable),
+load_compiled([Data|Compiled],Acc) ->
+ %% Make sure the #bump{} records and counters are available *before*
+ %% compiling and loading the code.
+ #remote_data{module=Module,file=File,code=Beam,
+ mapping=InitialMapping,clauses=InitialClauses} = Data,
+ ets:insert(?COVER_MAPPING_TABLE, InitialMapping),
+ ets:insert(?COVER_CLAUSE_TABLE, InitialClauses),
+ maybe_create_counters(Module, true),
+
Sticky = case code:is_sticky(Module) of
true ->
code:unstick_mod(Module),
@@ -1030,7 +1050,7 @@ load_compiled([{Module,File,Binary,InitialTable}|Compiled],Acc) ->
false ->
false
end,
- NewAcc = case code:load_binary(Module, ?TAG, Binary) of
+ NewAcc = case code:load_binary(Module, ?TAG, Beam) of
{module,Module} ->
add_compiled(Module, File, Acc);
_ ->
@@ -1045,16 +1065,6 @@ load_compiled([{Module,File,Binary,InitialTable}|Compiled],Acc) ->
load_compiled([],Acc) ->
Acc.
-insert_initial_data([Item|Items]) when is_atom(element(1,Item)) ->
- ets:insert(?COVER_CLAUSE_TABLE, Item),
- insert_initial_data(Items);
-insert_initial_data([Item|Items]) ->
- ets:insert(?COVER_TABLE, Item),
- insert_initial_data(Items);
-insert_initial_data([]) ->
- ok.
-
-
unload([Module|Modules]) ->
do_clear(Module),
do_reload_original(Module),
@@ -1175,7 +1185,7 @@ get_downs_r([]) ->
[];
get_downs_r(Mons) ->
receive
- {'DOWN', Ref, _Type, Pid, R={_,_,_,_}} ->
+ {'DOWN', Ref, _Type, Pid, #remote_data{}=R} ->
[R|get_downs_r(lists:delete({Pid,Ref},Mons))];
{'DOWN', Ref, _Type, Pid, Reason} = Down ->
case lists:member({Pid,Ref},Mons) of
@@ -1194,19 +1204,13 @@ get_downs_r(Mons) ->
%% Binary is the beam code for the module and InitialTable is the initial
%% data to insert in ?COVER_TABLE.
get_data_for_remote_loading({Module,File}) ->
- [{Module,Binary}] = ets:lookup(?BINARY_TABLE,Module),
+ [{Module,Code}] = ets:lookup(?BINARY_TABLE, Module),
%%! The InitialTable list will be long if the module is big - what to do??
- InitialBumps = ets:select(?COVER_TABLE,ms(Module)),
+ Mapping = counters_mapping_table(Module),
InitialClauses = ets:lookup(?COVER_CLAUSE_TABLE,Module),
- {Module,File,Binary,InitialBumps ++ InitialClauses}.
-
-%% Create a match spec which returns the clause info {Module,InitInfo} and
-%% all #bump keys for the given module with 0 number of calls.
-ms(Module) ->
- ets:fun2ms(fun({Key,_}) when Key#bump.module=:=Module ->
- {Key,0}
- end).
+ #remote_data{module=Module,file=File,code=Code,
+ mapping=Mapping,clauses=InitialClauses}.
%% Unload modules on remote nodes
remote_unload(Nodes,UnloadedModules) ->
@@ -1462,7 +1466,7 @@ get_compiled_still_loaded(Nodes,Compiled0) ->
do_compile_beams(ModsAndFiles, State) ->
Result0 = pmap(fun({ok,Module,File}) ->
- do_compile_beam(Module,File,State);
+ do_compile_beam(Module, File, State);
(Error) ->
Error
end,
@@ -1474,8 +1478,10 @@ do_compile_beams(ModsAndFiles, State) ->
do_compile_beam(Module,BeamFile0,State) ->
case get_beam_file(Module,BeamFile0,State#main_state.compiled) of
{ok,BeamFile} ->
+ LocalOnly = State#main_state.local_only,
UserOptions = get_compile_options(Module,BeamFile),
- case do_compile_beam1(Module,BeamFile,UserOptions) of
+ case do_compile_beam1(Module,BeamFile,
+ UserOptions,LocalOnly) of
{ok, Module} ->
{ok,Module,BeamFile};
error ->
@@ -1501,41 +1507,39 @@ fix_state_and_result([],State,Acc) ->
do_compile(Files, Options, State) ->
+ LocalOnly = State#main_state.local_only,
Result0 = pmap(fun(File) ->
- do_compile(File, Options)
+ do_compile1(File, Options, LocalOnly)
end,
Files),
Compiled = [{M,F} || {ok,M,F} <- Result0],
remote_load_compiled(State#main_state.nodes,Compiled),
fix_state_and_result(Result0,State,[]).
-do_compile(File, Options) ->
- case do_compile1(File, Options) of
+do_compile1(File, Options, LocalOnly) ->
+ case do_compile2(File, Options, LocalOnly) of
{ok, Module} ->
{ok,Module,File};
error ->
{error,File}
end.
-%% do_compile1(File, Options) -> {ok,Module} | error
-do_compile1(File, UserOptions) ->
+%% do_compile2(File, Options) -> {ok,Module} | error
+do_compile2(File, UserOptions, LocalOnly) ->
Options = [debug_info,binary,report_errors,report_warnings] ++ UserOptions,
case compile:file(File, Options) of
{ok, Module, Binary} ->
- do_compile_beam1(Module,Binary,UserOptions);
+ do_compile_beam1(Module,Binary,UserOptions,LocalOnly);
error ->
error
end.
%% Beam is a binary or a .beam file name
-do_compile_beam1(Module,Beam,UserOptions) ->
+do_compile_beam1(Module,Beam,UserOptions,LocalOnly) ->
%% Clear database
do_clear(Module),
- %% Extract the abstract format and insert calls to bump/6 at
- %% every executable line and, as a side effect, initiate
- %% the database
-
+ %% Extract the abstract format.
case get_abstract_code(Module, Beam) of
no_abstract_code=E ->
{error,E};
@@ -1545,7 +1549,8 @@ do_compile_beam1(Module,Beam,UserOptions) ->
Forms0 = epp:interpret_file_attribute(Code),
case find_main_filename(Forms0) of
{ok,MainFile} ->
- do_compile_beam2(Module,Beam,UserOptions,Forms0,MainFile);
+ do_compile_beam2(Module,Beam,UserOptions,
+ Forms0,MainFile,LocalOnly);
Error ->
Error
end;
@@ -1564,26 +1569,35 @@ get_abstract_code(Module, Beam) ->
Error -> Error
end.
-do_compile_beam2(Module,Beam,UserOptions,Forms0,MainFile) ->
- {Forms,Vars} = transform(Forms0, Module, MainFile),
+do_compile_beam2(Module,Beam,UserOptions,Forms0,MainFile,LocalOnly) ->
+ init_counter_mapping(Module),
+
+ %% Instrument the abstract code by inserting
+ %% calls to update the counters.
+ {Forms,Vars} = transform(Forms0, Module, MainFile, LocalOnly),
+
+ %% Create counters.
+ maybe_create_counters(Module, not LocalOnly),
%% We need to recover the source from the compilation
%% info otherwise the newly compiled module will have
%% source pointing to the current directory
SourceInfo = get_source_info(Module, Beam),
- %% Compile and load the result
+ %% Compile and load the result.
%% It's necessary to check the result of loading since it may
- %% fail, for example if Module resides in a sticky directory
- {ok, Module, Binary} = compile:forms(Forms, SourceInfo ++ UserOptions),
+ %% fail, for example if Module resides in a sticky directory.
+ Options = SourceInfo ++ UserOptions,
+ {ok, Module, Binary} = compile:forms(Forms, Options),
+
case code:load_binary(Module, ?TAG, Binary) of
{module, Module} ->
- %% Store info about all function clauses in database
+ %% Store info about all function clauses in database.
InitInfo = lists:reverse(Vars#vars.init_info),
ets:insert(?COVER_CLAUSE_TABLE, {Module, InitInfo}),
- %% Store binary code so it can be loaded on remote nodes
+ %% Store binary code so it can be loaded on remote nodes.
ets:insert(?BINARY_TABLE, {Module, Binary}),
{ok, Module};
@@ -1615,11 +1629,12 @@ get_compile_info(Module, Beam) ->
[]
end.
-transform(Code, Module, MainFile) ->
+transform(Code, Module, MainFile, LocalOnly) ->
Vars0 = #vars{module=Module},
- {ok,MungedForms,Vars} = transform_2(Code,[],Vars0,MainFile,on),
+ {ok,MungedForms0,Vars} = transform_2(Code, [], Vars0, MainFile, on),
+ MungedForms = patch_code(Module, MungedForms0, LocalOnly),
{MungedForms,Vars}.
-
+
%% Helpfunction which returns the first found file-attribute, which can
%% be interpreted as the name of the main erlang source file.
find_main_filename([{attribute,_,file,{MainFile,_}}|_]) ->
@@ -1786,19 +1801,7 @@ munge_body([Expr|Body], Vars, MungedBody, LastExprBumpLines) ->
MungedExprs1 = [MungedExpr|MungedBody1],
munge_body(Body, Vars3, MungedExprs1, NewBumps);
false ->
- ets:insert(?COVER_TABLE, {#bump{module = Vars#vars.module,
- function = Vars#vars.function,
- arity = Vars#vars.arity,
- clause = Vars#vars.clause,
- line = Line},
- 0}),
Bump = bump_call(Vars, Line),
-% Bump = {call, 0, {remote, 0, {atom,0,cover}, {atom,0,bump}},
-% [{atom, 0, Vars#vars.module},
-% {atom, 0, Vars#vars.function},
-% {integer, 0, Vars#vars.arity},
-% {integer, 0, Vars#vars.clause},
-% {integer, 0, Line}]},
Lines2 = [Line|Lines],
{MungedExpr, Vars2} = munge_expr(Expr, Vars#vars{lines=Lines2}),
NewBumps = new_bumps(Vars2, Vars),
@@ -1853,8 +1856,10 @@ maybe_fix_last_expr(MungedExprs, Vars, LastExprBumpLines) ->
last_expr_needs_fixing(Vars, LastExprBumpLines) ->
case common_elems(Vars#vars.no_bump_lines, LastExprBumpLines) of
- [Line] -> {yes, Line};
- _ -> no
+ [Line] ->
+ {yes, Line};
+ _ ->
+ no
end.
fix_last_expr([MungedExpr|MungedExprs], Line, Vars) ->
@@ -1919,9 +1924,7 @@ fix_cls([Cl | Cls], Line, Bump) ->
bumps_line(E, L) ->
try bumps_line1(E, L) catch true -> true end.
-bumps_line1({call,_,{remote,_,{atom,_,ets},{atom,_,update_counter}},
- [{atom,_,?COVER_TABLE},{tuple,_,[_,_,_,_,_,{integer,_,Line}]},_]},
- Line) ->
+bumps_line1({'BUMP',Line,_}, Line) ->
throw(true);
bumps_line1([E | Es], Line) ->
bumps_line1(E, Line),
@@ -1931,19 +1934,12 @@ bumps_line1(T, Line) when is_tuple(T) ->
bumps_line1(_, _) ->
false.
-%%% End of fix of last expression.
-
+%% Insert a place holder for the call to counters:add/3 in the
+%% abstract code.
bump_call(Vars, Line) ->
- A = erl_anno:new(0),
- {call,A,{remote,A,{atom,A,ets},{atom,A,update_counter}},
- [{atom,A,?COVER_TABLE},
- {tuple,A,[{atom,A,?BUMP_REC_NAME},
- {atom,A,Vars#vars.module},
- {atom,A,Vars#vars.function},
- {integer,A,Vars#vars.arity},
- {integer,A,Vars#vars.clause},
- {integer,A,Line}]},
- {integer,A,1}]}.
+ {'BUMP',Line,counter_index(Vars, Line)}.
+
+%%% End of fix of last expression.
munge_expr({match,Line,ExprL,ExprR}, Vars) ->
{MungedExprL, Vars2} = munge_expr(ExprL, Vars),
@@ -2103,6 +2099,159 @@ subtract(L1, L2) ->
common_elems(L1, L2) ->
[E || E <- L1, lists:member(E, L2)].
+%%%--Counters------------------------------------------------------------
+
+init_counter_mapping(Mod) ->
+ true = ets:insert_new(?COVER_MAPPING_TABLE, {Mod,0}),
+ ok.
+
+counter_index(Vars, Line) ->
+ #vars{module=Mod,function=F,arity=A,clause=C} = Vars,
+ Key = #bump{module=Mod,function=F,arity=A,
+ clause=C,line=Line},
+ case ets:lookup(?COVER_MAPPING_TABLE, Key) of
+ [] ->
+ Index = ets:update_counter(?COVER_MAPPING_TABLE,
+ Mod, {2,1}),
+ true = ets:insert(?COVER_MAPPING_TABLE, {Key,Index}),
+ Index;
+ [{Key,Index}] ->
+ Index
+ end.
+
+%% Create the counter array and store as a persistent term.
+maybe_create_counters(Mod, true) ->
+ Cref = create_counters(Mod),
+ Key = {?MODULE,Mod},
+ persistent_term:put(Key, Cref),
+ ok;
+maybe_create_counters(_Mod, false) ->
+ ok.
+
+create_counters(Mod) ->
+ Size0 = ets:lookup_element(?COVER_MAPPING_TABLE, Mod, 2),
+ Size = max(1, Size0), %Size must not be 0.
+ Cref = counters:new(Size, [write_concurrency]),
+ ets:insert(?COVER_MAPPING_TABLE, {{counters,Mod},Cref}),
+ Cref.
+
+patch_code(Mod, Forms, false) ->
+ A = erl_anno:new(0),
+ AbstrKey = {tuple,A,[{atom,A,?MODULE},{atom,A,Mod}]},
+ patch_code1(Forms, {distributed,AbstrKey});
+patch_code(Mod, Forms, true) ->
+ Cref = create_counters(Mod),
+ AbstrCref = cid_to_abstract(Cref),
+ patch_code1(Forms, {local_only,AbstrCref}).
+
+%% Go through the abstract code and replace 'BUMP' forms
+%% with the actual code to increment the counters.
+patch_code1({'BUMP',_Line,Index}, {distributed,AbstrKey}) ->
+ %% Replace with counters:add(persistent_term:get(Key), Index, 1).
+ %% This code will work on any node.
+ A = element(2, AbstrKey),
+ GetCref = {call,A,{remote,A,{atom,A,persistent_term},{atom,A,get}},
+ [AbstrKey]},
+ {call,A,{remote,A,{atom,A,counters},{atom,A,add}},
+ [GetCref,{integer,A,Index},{integer,A,1}]};
+patch_code1({'BUMP',_Line,Index}, {local_only,AbstrCref}) ->
+ %% Replace with counters:add(Cref, Index, 1). This code
+ %% will only work on the local node.
+ A = element(2, AbstrCref),
+ {call,A,{remote,A,{atom,A,counters},{atom,A,add}},
+ [AbstrCref,{integer,A,Index},{integer,A,1}]};
+patch_code1({clauses,Cs}, Key) ->
+ {clauses,[patch_code1(El, Key) || El <- Cs]};
+patch_code1([_|_]=List, Key) ->
+ [patch_code1(El, Key) || El <- List];
+patch_code1(Tuple, Key) when tuple_size(Tuple) >= 3 ->
+ Acc = [element(2, Tuple),element(1, Tuple)],
+ patch_code_tuple(3, tuple_size(Tuple), Tuple, Key, Acc);
+patch_code1(Other, _Key) ->
+ Other.
+
+patch_code_tuple(I, Size, Tuple, Key, Acc) when I =< Size ->
+ El = patch_code1(element(I, Tuple), Key),
+ patch_code_tuple(I + 1, Size, Tuple, Key, [El|Acc]);
+patch_code_tuple(_I, _Size, _Tuple, _Key, Acc) ->
+ list_to_tuple(lists:reverse(Acc)).
+
+%% Don't try this at home! Assumes knowledge of the internal
+%% representation of a counter ref.
+cid_to_abstract(Cref0) ->
+ A = erl_anno:new(0),
+ %% Disable dialyzer warning for breaking opacity.
+ Cref = binary_to_term(term_to_binary(Cref0)),
+ {write_concurrency,Ref} = Cref,
+ {tuple,A,[{atom,A,write_concurrency},{integer,A,Ref}]}.
+
+%% Called on the remote node. Collect and send counters to
+%% the main node. Also zero the counters.
+send_counters(Mod, CollectorPid) ->
+ Process = fun(Chunk) -> send_chunk(CollectorPid, Chunk) end,
+ move_counters(Mod, Process).
+
+%% Called on the main node. Collect the counters and consolidate
+%% them into the collection table. Also zero the counters.
+move_counters(Mod) ->
+ move_counters(Mod, fun insert_in_collection_table/1).
+
+move_counters(Mod, Process) ->
+ Pattern = {#bump{module=Mod,_='_'},'_'},
+ Matches = ets:match_object(?COVER_MAPPING_TABLE, Pattern, ?CHUNK_SIZE),
+ Cref = get_counters_ref(Mod),
+ move_counters1(Matches, Cref, Process).
+
+move_counters1({Mappings,Continuation}, Cref, Process) ->
+ Move = fun({Key,Index}) ->
+ Count = counters:get(Cref, Index),
+ ok = counters:sub(Cref, Index, Count),
+ {Key,Count}
+ end,
+ Process(lists:map(Move, Mappings)),
+ move_counters1(ets:match_object(Continuation), Cref, Process);
+move_counters1('$end_of_table', _Cref, _Process) ->
+ ok.
+
+counters_mapping_table(Mod) ->
+ Mapping = counters_mapping(Mod),
+ Cref = get_counters_ref(Mod),
+ #{size:=Size} = counters:info(Cref),
+ [{Mod,Size}|Mapping].
+
+get_counters_ref(Mod) ->
+ ets:lookup_element(?COVER_MAPPING_TABLE, {counters,Mod}, 2).
+
+counters_mapping(Mod) ->
+ Pattern = {#bump{module=Mod,_='_'},'_'},
+ ets:match_object(?COVER_MAPPING_TABLE, Pattern).
+
+clear_counters(Mod) ->
+ _ = persistent_term:erase({?MODULE,Mod}),
+ ets:delete(?COVER_MAPPING_TABLE, Mod),
+ Pattern = {#bump{module=Mod,_='_'},'_'},
+ _ = ets:match_delete(?COVER_MAPPING_TABLE, Pattern),
+ ok.
+
+%% Reset counters (set counters to 0).
+reset_counters(Mod) ->
+ Pattern = {#bump{module=Mod,_='_'},'$1'},
+ MatchSpec = [{Pattern,[],['$1']}],
+ Matches = ets:select(?COVER_MAPPING_TABLE,
+ MatchSpec, ?CHUNK_SIZE),
+ Cref = get_counters_ref(Mod),
+ reset_counters1(Matches, Cref).
+
+reset_counters1({Indices,Continuation}, Cref) ->
+ _ = [counters:put(Cref, N, 0) || N <- Indices],
+ reset_counters1(ets:select(Continuation), Cref);
+reset_counters1('$end_of_table', _Cref) ->
+ ok.
+
+delete_all_counters() ->
+ _ = [persistent_term:erase(Key) || {?MODULE,_}=Key <- persistent_term:get()],
+ ok.
+
%%%--Analysis------------------------------------------------------------
%% Collect data for all modules
@@ -2138,20 +2287,7 @@ collect(Module,Clauses,Nodes) ->
%% ?COLLECTION_TABLE. Resetting data in ?COVER_TABLE
move_modules({Module,Clauses}) ->
ets:insert(?COLLECTION_CLAUSE_TABLE,{Module,Clauses}),
- Pattern = {#bump{module=Module, _='_'}, '_'},
- MatchSpec = [{Pattern,[],['$_']}],
- Match = ets:select(?COVER_TABLE,MatchSpec,?CHUNK_SIZE),
- do_move_module(Match).
-
-do_move_module({Bumps,Continuation}) ->
- lists:foreach(fun({Key,Val}) ->
- ets:insert(?COVER_TABLE, {Key,0}),
- insert_in_collection_table(Key,Val)
- end,
- Bumps),
- do_move_module(ets:select(Continuation));
-do_move_module('$end_of_table') ->
- ok.
+ move_counters(Module).
%% Given a .beam file, find the .erl file. Look first in same directory as
%% the .beam file, then in ../src, then in compile info.
@@ -2415,20 +2551,8 @@ do_analyse_to_file1(Module, OutFile, ErlFile, HTML) ->
case file:open(OutFile, [write,raw,delayed_write]) of
{ok, OutFd} ->
Enc = encoding(ErlFile),
- if HTML ->
- Header =
- ["<!DOCTYPE HTML PUBLIC "
- "\"-//W3C//DTD HTML 3.2 Final//EN\">\n"
- "<html>\n"
- "<head>\n"
- "<meta http-equiv=\"Content-Type\""
- " content=\"text/html; charset=",
- html_encoding(Enc),"\"/>\n"
- "<title>",OutFile,"</title>\n"
- "</head>"
- "<body style='background-color: white;"
- " color: black'>\n"
- "<pre>\n"],
+ if HTML ->
+ Header = create_header(OutFile, Enc),
H1Bin = unicode:characters_to_binary(Header,Enc,Enc),
ok = file:write(OutFd,H1Bin);
true -> ok
@@ -2439,20 +2563,25 @@ do_analyse_to_file1(Module, OutFile, ErlFile, HTML) ->
Timestamp =
io_lib:format("~p-~s-~s at ~s:~s:~s",
[Y,
- string:right(integer_to_list(Mo), 2, $0),
- string:right(integer_to_list(D), 2, $0),
- string:right(integer_to_list(H), 2, $0),
- string:right(integer_to_list(Mi), 2, $0),
- string:right(integer_to_list(S), 2, $0)]),
-
- H2Bin = unicode:characters_to_binary(
- ["File generated from ",ErlFile," by COVER ",
- Timestamp,"\n\n"
- "**************************************"
- "**************************************"
- "\n\n"],
- Enc, Enc),
- ok = file:write(OutFd, H2Bin),
+ string:pad(integer_to_list(Mo), 2, leading, $0),
+ string:pad(integer_to_list(D), 2, leading, $0),
+ string:pad(integer_to_list(H), 2, leading, $0),
+ string:pad(integer_to_list(Mi), 2, leading, $0),
+ string:pad(integer_to_list(S), 2, leading, $0)]),
+
+ OutFileInfo =
+ if HTML ->
+ create_footer(ErlFile, Timestamp);
+ true ->
+ ["File generated from ",ErlFile," by COVER ",
+ Timestamp, "\n\n",
+ "**************************************"
+ "**************************************"
+ "\n\n"]
+ end,
+
+ H2Bin = unicode:characters_to_binary(OutFileInfo,Enc,Enc),
+ ok = file:write(OutFd, H2Bin),
Pattern = {#bump{module=Module,line='$1',_='_'},'$2'},
MS = [{Pattern,[{is_integer,'$1'},{'>','$1',0}],[{{'$1','$2'}}]}],
@@ -2462,7 +2591,7 @@ do_analyse_to_file1(Module, OutFile, ErlFile, HTML) ->
print_lines(Module, CovLines, InFd, OutFd, 1, HTML),
if HTML ->
- ok = file:write(OutFd, "</pre>\n</body>\n</html>\n");
+ ok = file:write(OutFd, close_html());
true -> ok
end,
@@ -2497,14 +2626,13 @@ print_lines(Module, CovLines, InFd, OutFd, L, HTML) ->
case CovLines of
[{L,N}|CovLines1] ->
if N=:=0, HTML=:=true ->
- LineNoNL = Line -- "\n",
- Str = " 0",
- %%Str = string:right("0", 6, 32),
- RedLine = ["<font color=red>",Str,fill1(),
- LineNoNL,"</font>\n"],
- ok = file:write(OutFd, RedLine);
+ MissedLine = table_row("miss", Line, L, N),
+ ok = file:write(OutFd, MissedLine);
+ HTML=:=true ->
+ HitLine = table_row("hit", Line, L, N),
+ ok = file:write(OutFd, HitLine);
N < 1000000 ->
- Str = string:right(integer_to_list(N), 6, 32),
+ Str = string:pad(integer_to_list(N), 6, leading, $\s),
ok = file:write(OutFd, [Str,fill1(),Line]);
N < 10000000 ->
Str = integer_to_list(N),
@@ -2515,7 +2643,11 @@ print_lines(Module, CovLines, InFd, OutFd, L, HTML) ->
end,
print_lines(Module, CovLines1, InFd, OutFd, L+1, HTML);
_ -> %Including comment lines
- ok = file:write(OutFd, [tab(),Line]),
+ NonCoveredContent =
+ if HTML -> table_row(Line, L);
+ true -> [tab(),Line]
+ end,
+ ok = file:write(OutFd, NonCoveredContent),
print_lines(Module, CovLines, InFd, OutFd, L+1, HTML)
end
end.
@@ -2525,6 +2657,61 @@ fill1() -> "..| ".
fill2() -> ".| ".
fill3() -> "| ".
+%% HTML sections
+create_header(OutFile, Enc) ->
+ ["<!doctype html>\n"
+ "<html>\n"
+ "<head>\n"
+ "<meta charset=\"",html_encoding(Enc),"\">\n"
+ "<title>",OutFile,"</title>\n"
+ "<style>"] ++
+ read_stylesheet() ++
+ ["</style>\n",
+ "</head>\n"
+ "<body>\n"
+ "<h1><code>",OutFile,"</code></h1>\n"].
+
+create_footer(ErlFile, Timestamp) ->
+ ["<footer><p>File generated from <code>",ErlFile,
+ "</code> by <a href=\"http://erlang.org/doc/man/cover.html\">cover</a> at ",
+ Timestamp,"</p></footer>\n<table>\n<tbody>\n"].
+
+close_html() ->
+ ["</tbody>\n",
+ "<thead>\n",
+ "<tr>\n",
+ "<th>Line</th>\n",
+ "<th>Hits</th>\n",
+ "<th>Source</th>\n",
+ "</tr>\n",
+ "</thead>\n",
+ "</table>\n",
+ "</body>\n"
+ "</html>\n"].
+
+table_row(CssClass, Line, L, N) ->
+ ["<tr class=\"",CssClass,"\">\n", table_data(Line, L, N)].
+table_row(Line, L) ->
+ ["<tr>\n", table_data(Line, L, "")].
+
+table_data(Line, L, N) ->
+ LineNoNL = Line -- "\n",
+ ["<td class=\"line\" id=\"L",integer_to_list(L),"\">",
+ "<a href=\"#L",integer_to_list(L),"\">",
+ integer_to_list(L),
+ "</a></td>\n",
+ "<td class=\"hits\">",maybe_integer_to_list(N),"</td>\n",
+ "<td class=\"source\"><code>",LineNoNL,"</code></td>\n</tr>\n"].
+
+maybe_integer_to_list(0) -> "<pre style=\"display: inline;\">:-(</pre>";
+maybe_integer_to_list(N) when is_integer(N) -> integer_to_list(N);
+maybe_integer_to_list(_) -> "".
+
+read_stylesheet() ->
+ PrivDir = code:priv_dir(?TOOLS_APP),
+ {ok, Css} = file:read_file(filename:join(PrivDir, ?STYLESHEET)),
+ [Css].
+
%%%--Export--------------------------------------------------------------
do_export(Module, OutFile, From, State) ->
case file:open(OutFile,[write,binary,raw,delayed_write]) of
@@ -2656,7 +2843,7 @@ get_term(Fd) ->
%% Reset main node and all remote nodes
do_reset_main_node(Module,Nodes) ->
- do_reset(Module),
+ reset_counters(Module),
do_reset_collection_table(Module),
remote_reset(Module,Nodes).
@@ -2664,27 +2851,9 @@ do_reset_collection_table(Module) ->
ets:delete(?COLLECTION_CLAUSE_TABLE,Module),
ets:match_delete(?COLLECTION_TABLE, {#bump{module=Module},'_'}).
-%% do_reset(Module) -> ok
-%% The reset is done on ?CHUNK_SIZE number of bumps to avoid building
-%% long lists in the case of very large modules
-do_reset(Module) ->
- Pattern = {#bump{module=Module, _='_'}, '$1'},
- MatchSpec = [{Pattern,[{'=/=','$1',0}],['$_']}],
- Match = ets:select(?COVER_TABLE,MatchSpec,?CHUNK_SIZE),
- do_reset2(Match).
-
-do_reset2({Bumps,Continuation}) ->
- lists:foreach(fun({Bump,_N}) ->
- ets:insert(?COVER_TABLE, {Bump,0})
- end,
- Bumps),
- do_reset2(ets:select(Continuation));
-do_reset2('$end_of_table') ->
- ok.
-
do_clear(Module) ->
ets:match_delete(?COVER_CLAUSE_TABLE, {Module,'_'}),
- ets:match_delete(?COVER_TABLE, {#bump{module=Module},'_'}),
+ clear_counters(Module),
case lists:member(?COLLECTION_TABLE, ets:all()) of
true ->
%% We're on the main node
diff --git a/lib/tools/src/eprof.erl b/lib/tools/src/eprof.erl
index 535ddbcd04..86e3d3a8b8 100644
--- a/lib/tools/src/eprof.erl
+++ b/lib/tools/src/eprof.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,11 +26,11 @@
-export([start/0,
stop/0,
- dump/0,
+ dump/0, dump_data/0,
start_profiling/1, start_profiling/2, start_profiling/3,
profile/1, profile/2, profile/3, profile/4, profile/5,
stop_profiling/0,
- analyze/0, analyze/1, analyze/2,
+ analyze/0, analyze/1, analyze/2, analyze/4,
log/1]).
%% Internal exports
@@ -117,6 +117,9 @@ profile(Rootset, M, F, A, Pattern, Options) ->
dump() ->
gen_server:call(?MODULE, dump, infinity).
+dump_data() ->
+ gen_server:call(?MODULE, dump_data, infinity).
+
log(File) ->
gen_server:call(?MODULE, {logfile, File}, infinity).
@@ -151,22 +154,18 @@ init([]) ->
%% analyze
-handle_call({analyze, _, _}, _, #state{ bpd = #bpd{ p = {0,nil}, us = 0, n = 0} = Bpd } = S) when is_record(Bpd, bpd) ->
+handle_call(
+ {analyze, _, _}, _,
+ #state{ bpd = #bpd{ p = {0,nil}, us = 0, n = 0 } } = S) ->
{reply, nothing_to_analyze, S};
-handle_call({analyze, procs, Opts}, _, #state{ bpd = #bpd{ p = Ps, us = Tus} = Bpd, fd = Fd} = S) when is_record(Bpd, bpd) ->
- lists:foreach(fun
- ({Pid, Mfas}) ->
- {Pn, Pus} = sum_bp_total_n_us(Mfas),
- format(Fd, "~n****** Process ~w -- ~s % of profiled time *** ~n", [Pid, s("~.2f", [100.0*divide(Pus,Tus)])]),
- print_bp_mfa(Mfas, {Pn,Pus}, Fd, Opts),
- ok
- end, gb_trees:to_list(Ps)),
- {reply, ok, S};
+handle_call({analyze, procs, Opts}, _, #state{ bpd = Bpd, fd = Fd } = S)
+ when is_record(Bpd, bpd) ->
+ {reply, analyze(Fd, procs, Opts, Bpd), S};
-handle_call({analyze, total, Opts}, _, #state{ bpd = #bpd{ mfa = Mfas, n = Tn, us = Tus} = Bpd, fd = Fd} = S) when is_record(Bpd, bpd) ->
- print_bp_mfa(Mfas, {Tn, Tus}, Fd, Opts),
- {reply, ok, S};
+handle_call({analyze, total, Opts}, _, #state{ bpd = Bpd, fd = Fd } = S)
+ when is_record(Bpd, bpd) ->
+ {reply, analyze(Fd, total, Opts, Bpd), S};
handle_call({analyze, Type, _Opts}, _, S) ->
{reply, {error, {undefined, Type}}, S};
@@ -260,6 +259,10 @@ handle_call({logfile, File}, _From, #state{ fd = OldFd } = S) ->
handle_call(dump, _From, #state{ bpd = Bpd } = S) when is_record(Bpd, bpd) ->
{reply, gb_trees:to_list(Bpd#bpd.p), S};
+handle_call(dump_data, _, #state{ bpd = #bpd{} = Bpd } = S)
+ when is_record(Bpd, bpd) ->
+ {reply, Bpd, S};
+
handle_call(stop, _FromTag, S) ->
{stop, normal, stopped, S}.
@@ -438,6 +441,23 @@ collect_bpdfp(Mfa, Tree, Data) ->
{PTno + Ni, PTuso + Time, Ti1}
end, {0,0, Tree}, Data).
+
+
+analyze(Fd, procs, Opts, #bpd{ p = Ps, us = Tus }) ->
+ lists:foreach(
+ fun
+ ({Pid, Mfas}) ->
+ {Pn, Pus} = sum_bp_total_n_us(Mfas),
+ format(
+ Fd,
+ "~n****** Process ~w -- ~s % of profiled time *** ~n",
+ [Pid, s("~.2f", [100.0*divide(Pus, Tus)])]),
+ print_bp_mfa(Mfas, {Pn,Pus}, Fd, Opts),
+ ok
+ end, gb_trees:to_list(Ps));
+analyze(Fd, total, Opts, #bpd{ mfa = Mfas, n = Tn, us = Tus } ) ->
+ print_bp_mfa(Mfas, {Tn, Tus}, Fd, Opts).
+
%% manipulators
sort_mfa(Bpfs, mfa) when is_list(Bpfs) ->
lists:sort(fun
diff --git a/lib/tools/src/fprof.erl b/lib/tools/src/fprof.erl
index fb657c2928..36d4828861 100644
--- a/lib/tools/src/fprof.erl
+++ b/lib/tools/src/fprof.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1242,8 +1242,7 @@ spawn_3step(Spawn, FunPrelude, FunAck, FunBody)
catch Child ! {Parent, Ref, Go},
Result
catch
- Class:Reason ->
- Stacktrace = erlang:get_stacktrace(),
+ Class:Reason:Stacktrace ->
catch exit(Child, kill),
erlang:raise(Class, Reason, Stacktrace)
end;
diff --git a/lib/tools/src/instrument.erl b/lib/tools/src/instrument.erl
index 055f4a7afb..0203fefe13 100644
--- a/lib/tools/src/instrument.erl
+++ b/lib/tools/src/instrument.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -19,410 +19,140 @@
%%
-module(instrument).
--export([holes/1, mem_limits/1, memory_data/0, read_memory_data/1,
- sort/1, store_memory_data/1, sum_blocks/1,
- descr/1, type_descr/2, allocator_descr/2, class_descr/2,
- type_no_range/1, block_header_size/1, store_memory_status/1,
- read_memory_status/1, memory_status/1]).
-
-
--define(OLD_INFO_SIZE, 32). %% (sizeof(mem_link) in pre R9C utils.c)
-
--define(IHMARKER(H), element(1, H)).
--define(VSN(H), element(2, H)).
--define(INFO_SIZE(H), element(3, H)).
--define(TYPEMAP(H), element(4, H)).
-
--define(IHDR(H), is_tuple(H), ?IHMARKER(H) =:= instr_hdr).
--define(IHDRVSN(H, V), ?IHDR(H), ?VSN(H) =:= V).
-
-memory_data() ->
- case catch erlang:system_info(allocated) of
- {'EXIT',{Error,_}} ->
- erlang:error(Error, []);
- {'EXIT',Error} ->
- erlang:error(Error, []);
- Res ->
- Res
+-export([allocations/0, allocations/1,
+ carriers/0, carriers/1]).
+
+-type block_histogram() :: tuple().
+
+-type allocation_summary() ::
+ {HistogramStart :: non_neg_integer(),
+ UnscannedSize :: non_neg_integer(),
+ Allocations :: #{ Origin :: atom() =>
+ #{ Type :: atom() => block_histogram() }}}.
+
+-spec allocations() -> {ok, Result} | {error, Reason} when
+ Result :: allocation_summary(),
+ Reason :: not_enabled.
+allocations() ->
+ allocations(#{}).
+
+-spec allocations(Options) -> {ok, Result} | {error, Reason} when
+ Result :: allocation_summary(),
+ Reason :: not_enabled,
+ Options :: #{ scheduler_ids => list(non_neg_integer()),
+ allocator_types => list(atom()),
+ histogram_start => pos_integer(),
+ histogram_width => pos_integer() }.
+allocations(Options) ->
+ Ref = make_ref(),
+
+ Defaults = #{ scheduler_ids => lists:seq(0, erlang:system_info(schedulers)),
+ allocator_types => erlang:system_info(alloc_util_allocators),
+ histogram_start => 128,
+ histogram_width => 18 },
+
+ {HistStart, MsgCount} =
+ dispatch_gather(maps:merge(Defaults, Options), Ref,
+ fun erts_internal:gather_alloc_histograms/1),
+
+ alloc_hist_receive(HistStart, MsgCount, Ref).
+
+alloc_hist_receive(_HistStart, 0, _Ref) ->
+ {error, not_enabled};
+alloc_hist_receive(HistStart, MsgCount, Ref) when MsgCount > 0 ->
+ {Unscanned, Histograms} = alloc_hist_receive_1(MsgCount, Ref, 0, #{}),
+ {ok, {HistStart, Unscanned, Histograms}}.
+
+alloc_hist_receive_1(0, _Ref, Unscanned, Result) ->
+ {Unscanned, Result};
+alloc_hist_receive_1(MsgCount, Ref, Unscanned0, Result0) ->
+ receive
+ {Ref, Unscanned, Tags} ->
+ Result = lists:foldl(fun alloc_hist_fold_result/2, Result0, Tags),
+ alloc_hist_receive_1(MsgCount - 1, Ref, Unscanned0 + Unscanned, Result)
end.
-store_memory_data(File) ->
- case catch erlang:system_info({allocated, File}) of
- {'EXIT',{Error,_}} ->
- erlang:error(Error, [File]);
- {'EXIT',Error} ->
- erlang:error(Error, [File]);
- Res ->
- Res
+alloc_hist_fold_result({Id, Type, BlockHist}, Result0) ->
+ IdAllocs0 = maps:get(Id, Result0, #{}),
+ MergedHists = case maps:find(Type, IdAllocs0) of
+ {ok, PrevHist} ->
+ alloc_hist_merge_hist(tuple_size(BlockHist),
+ BlockHist,
+ PrevHist);
+ error ->
+ BlockHist
+ end,
+ IdAllocs = IdAllocs0#{ Type => MergedHists },
+ Result0#{ Id => IdAllocs }.
+
+alloc_hist_merge_hist(0, A, _B) ->
+ A;
+alloc_hist_merge_hist(Index, A, B) ->
+ Merged = setelement(Index, A, element(Index, A) + element(Index, B)),
+ alloc_hist_merge_hist(Index - 1, Merged, B).
+
+-type carrier_info_list() ::
+ {HistogramStart :: non_neg_integer(),
+ Carriers :: [{AllocatorType :: atom(),
+ TotalSize :: non_neg_integer(),
+ UnscannedSize :: non_neg_integer(),
+ AllocatedSize :: non_neg_integer(),
+ AllocatedCount :: non_neg_integer(),
+ InPool :: boolean(),
+ FreeBlocks :: block_histogram()}]}.
+
+-spec carriers() -> {ok, Result} | {error, Reason} when
+ Result :: carrier_info_list(),
+ Reason :: not_enabled.
+carriers() ->
+ carriers(#{}).
+
+-spec carriers(Options) -> {ok, Result} | {error, Reason} when
+ Result :: carrier_info_list(),
+ Reason :: not_enabled,
+ Options :: #{ scheduler_ids => list(non_neg_integer()),
+ allocator_types => list(atom()),
+ histogram_start => pos_integer(),
+ histogram_width => pos_integer() }.
+carriers(Options) ->
+ Ref = make_ref(),
+
+ Defaults = #{ scheduler_ids => lists:seq(0, erlang:system_info(schedulers)),
+ allocator_types => erlang:system_info(alloc_util_allocators),
+ histogram_start => 512,
+ histogram_width => 14 },
+
+ {HistStart, MsgCount} =
+ dispatch_gather(maps:merge(Defaults, Options), Ref,
+ fun erts_internal:gather_carrier_info/1),
+
+ carrier_info_receive(HistStart, MsgCount, Ref).
+
+carrier_info_receive(_HistStart, 0, _Ref) ->
+ {error, not_enabled};
+carrier_info_receive(HistStart, MsgCount, Ref) ->
+ {ok, {HistStart, carrier_info_receive_1(MsgCount, Ref, [])}}.
+
+carrier_info_receive_1(0, _Ref, Result) ->
+ lists:flatten(Result);
+carrier_info_receive_1(MsgCount, Ref, Result0) ->
+ receive
+ {Ref, Carriers} ->
+ carrier_info_receive_1(MsgCount - 1, Ref, [Carriers, Result0])
end.
-memory_status(Type) when is_atom(Type) ->
- case catch erlang:system_info({allocated, status, Type}) of
- {'EXIT',{Error,_}} ->
- erlang:error(Error, [Type]);
- {'EXIT',Error} ->
- erlang:error(Error, [Type]);
- Res ->
- Res
- end;
-memory_status(Type) ->
- erlang:error(badarg, [Type]).
-
-store_memory_status(File) when is_list(File) ->
- case catch erlang:system_info({allocated, status, File}) of
- {'EXIT',{Error,_}} ->
- erlang:error(Error, [File]);
- {'EXIT',Error} ->
- erlang:error(Error, [File]);
- Res ->
- Res
- end;
-store_memory_status(File) ->
- erlang:error(badarg, [File]).
-
-read_memory_data(File) when is_list(File) ->
- case file:consult(File) of
- {ok, [Hdr|MD]} when ?IHDR(Hdr) ->
- {Hdr, MD};
- {ok, [{T,A,S,undefined}|_] = MD} when is_integer(T),
- is_integer(A),
- is_integer(S) ->
- {{instr_hdr, 1, ?OLD_INFO_SIZE}, MD};
- {ok, [{T,A,S,{X,Y,Z}}|_] = MD} when is_integer(T),
- is_integer(A),
- is_integer(S),
- is_integer(X),
- is_integer(Y),
- is_integer(Z) ->
- {{instr_hdr, 1, ?OLD_INFO_SIZE}, MD};
- {ok, _} ->
- {error, eio};
- Error ->
- Error
- end;
-read_memory_data(File) ->
- erlang:error(badarg, [File]).
-
-read_memory_status(File) when is_list(File) ->
- case file:consult(File) of
- {ok, [{instr_vsn, _}|Stat]} ->
- Stat;
- {ok, _} ->
- {error, eio};
- Error ->
- Error
- end;
-read_memory_status(File) ->
- erlang:error(badarg, [File]).
-
-holes({Hdr, MD}) when ?IHDR(Hdr) ->
- check_holes(?INFO_SIZE(Hdr), MD).
-
-check_holes(_ISz, []) ->
- ok;
-check_holes(ISz, [E | L]) ->
- check_holes(ISz, E, L).
-
-check_holes(_ISz, _E1, []) ->
- io:format("~n");
-check_holes(ISz, E1, [E2 | Rest]) ->
- check_hole(ISz, E1, E2),
- check_holes(ISz, E2, Rest).
-
-check_hole(ISz, {_,P1,S1,_}, {_,P2,_,_}) ->
- End = P1+S1,
- Hole = P2 - (End + ISz),
- if
- Hole =< 7 ->
- ok;
- true ->
- io:format(" ~p", [Hole])
- end.
-
-sum_blocks({Hdr, L}) when ?IHDR(Hdr) ->
- lists:foldl(fun({_,_,S,_}, Sum) -> S+Sum end,
- 0,
- L).
-
-mem_limits({Hdr, L}) when ?IHDR(Hdr) ->
- {_, P1, _, _} = hd(L),
- {_, P2, S2, _} = lists:last(L),
- {P1, P2+S2}.
-
-sort({Hdr, MD}) when ?IHDR(Hdr) ->
- {Hdr, lists:keysort(2, MD)}.
-
-descr({Hdr, MD} = ID) when ?IHDR(Hdr) ->
- {Hdr, lists:map(fun ({TN, Addr, Sz, {0, N, S}}) ->
- {type_descr(ID, TN),
- Addr,
- Sz,
- list_to_pid("<0."
- ++ integer_to_list(N)
- ++ "."
- ++ integer_to_list(S)
- ++ ">")};
- ({TN, Addr, Sz, undefined}) ->
- {type_descr(ID, TN),
- Addr,
- Sz,
- undefined}
- end,
- MD)}.
-
-block_header_size({Hdr, _}) when ?IHDR(Hdr) ->
- ?INFO_SIZE(Hdr).
-
-type_descr({Hdr, _}, TypeNo) when ?IHDRVSN(Hdr, 2),
- is_integer(TypeNo) ->
- case catch element(1, element(TypeNo, ?TYPEMAP(Hdr))) of
- {'EXIT', _} -> invalid_type;
- Type -> Type
- end;
-type_descr({Hdr, _}, TypeNo) when ?IHDRVSN(Hdr, 1),
- is_integer(TypeNo) ->
- type_string(TypeNo).
-
-
-allocator_descr({Hdr, _}, TypeNo) when ?IHDRVSN(Hdr, 2), is_integer(TypeNo) ->
- case catch element(2, element(TypeNo, ?TYPEMAP(Hdr))) of
- {'EXIT', _} -> invalid_type;
- Type -> Type
- end;
-allocator_descr({Hdr, _}, TypeNo) when ?IHDRVSN(Hdr, 1), is_integer(TypeNo) ->
- "unknown".
-
-class_descr({Hdr, _}, TypeNo) when ?IHDRVSN(Hdr, 2), is_integer(TypeNo) ->
- case catch element(3, element(TypeNo, ?TYPEMAP(Hdr))) of
- {'EXIT', _} -> invalid_type;
- Type -> Type
- end;
-class_descr({Hdr, _}, TypeNo) when ?IHDRVSN(Hdr, 1), is_integer(TypeNo) ->
- "unknown".
-
-type_no_range({Hdr, _}) when ?IHDRVSN(Hdr, 2) ->
- {1, tuple_size(?TYPEMAP(Hdr))};
-type_no_range({Hdr, _}) when ?IHDRVSN(Hdr, 1) ->
- {-1, 1000}.
-
-type_string(-1) ->
- "unknown";
-type_string(1) ->
- "atom text";
-type_string(11) ->
- "atom desc";
-type_string(2) ->
- "bignum (big_to_list)";
-type_string(31) ->
- "fixalloc";
-type_string(32) ->
- "unknown fixalloc block";
-type_string(33) ->
- "message buffer";
-type_string(34) ->
- "message link";
-type_string(4) ->
- "estack";
-type_string(40) ->
- "db table vec";
-type_string(41) ->
- "db tree select buffer";
-type_string(43) ->
- "db hash select buffer";
-type_string(44) ->
- "db hash select list";
-type_string(45) ->
- "db match prog stack";
-type_string(46) ->
- "db match prog heap data";
-type_string(47) ->
- "db temp buffer";
-type_string(48) ->
- "db error";
-type_string(49) ->
- "db error info";
-type_string(50) ->
- "db trans tab";
-type_string(51) ->
- "db segment";
-type_string(52) ->
- "db term";
-type_string(53) ->
- "db add_counter";
-type_string(54) ->
- "db segment table";
-type_string(55) ->
- "db table (fix)";
-type_string(56) ->
- "db bindings";
-type_string(57) ->
- "db counter";
-type_string(58) ->
- "db trace vec";
-type_string(59) ->
- "db fixed deletion";
-type_string(60) ->
- "binary (external.c)";
-type_string(61) ->
- "binary";
-type_string(62) ->
- "procbin (fix)";
-type_string(70) ->
- "driver alloc (io.c)";
-type_string(71) ->
- "binary (io.c)";
-type_string(72) ->
- "binary vec (io.c)";
-type_string(73) ->
- "binary vec 2 (io.c)";
-type_string(74) ->
- "io vec (io.c)";
-type_string(75) ->
- "io vec 2 (io.c)";
-type_string(76) ->
- "temp io buffer (io.c)";
-type_string(77) ->
- "temp io buffer 2 (io.c)";
-type_string(78) ->
- "line buffer (io.c)";
-type_string(8) ->
- "heap";
-type_string(801) ->
- "heap (1)";
-type_string(802) ->
- "heap (2)";
-type_string(803) ->
- "heap (3)";
-type_string(804) ->
- "heap (4)";
-type_string(805) ->
- "heap (5)";
-type_string(821) ->
- "heap fragment (1)";
-type_string(822) ->
- "heap fragment (2)";
-type_string(830) ->
- "sequential store buffer (for vectors)";
-type_string(91) ->
- "process table";
-type_string(92) ->
- "process desc";
-type_string(110) ->
- "hash buckets";
-type_string(111) ->
- "hash table";
-type_string(120) ->
- "index init";
-type_string(121) ->
- "index table";
-type_string(130) ->
- "temp buffer";
-type_string(140) ->
- "timer wheel";
-type_string(150) ->
- "distribution cache";
-type_string(151) ->
- "dmem";
-type_string(152) ->
- "distribution table";
-type_string(153) ->
- "distribution table buckets";
-type_string(154) ->
- "distribution table entry";
-type_string(155) ->
- "node table";
-type_string(156) ->
- "node table buckets";
-type_string(157) ->
- "node table entry";
-type_string(160) ->
- "port table";
-type_string(161) ->
- "driver entry";
-type_string(162) ->
- "port setup";
-type_string(163) ->
- "port wait";
-type_string(170) ->
- "module";
-type_string(171) ->
- "fundef";
-type_string(180) ->
- "file table";
-type_string(181) ->
- "driver table";
-type_string(182) ->
- "poll struct";
-type_string(190) ->
- "inet driver";
-type_string(200) ->
- "efile driver";
-type_string(210) ->
- "gc root set";
-type_string(220) ->
- "breakpoint data";
-type_string(230) ->
- "async queue";
-type_string(231) ->
- "async (exit)";
-type_string(232) ->
- "async (driver)";
-type_string(240) ->
- "bits buffer";
-type_string(241) ->
- "bits temp buffer";
-type_string(250) ->
- "modules (loader)";
-type_string(251) ->
- "code (loader)";
-type_string(252) ->
- "atom tab (loader)";
-type_string(253) ->
- "import tab (loader)";
-type_string(254) ->
- "export tab (loader)";
-type_string(255) ->
- "lable tab (loader)";
-type_string(256) ->
- "gen op (loader)";
-type_string(257) ->
- "gen op args (loader)";
-type_string(258) ->
- "gen op args 2 (loader)";
-type_string(259) ->
- "gen op args 3 (loader)";
-type_string(260) ->
- "lambdas (loader)";
-type_string(261) ->
- "temp int buffer (loader)";
-type_string(262) ->
- "temp heap (loader)";
-type_string(280) ->
- "dist ctrl msg buffer";
-type_string(281) ->
- "dist_buf";
-type_string(290) ->
- "call trace buffer";
-type_string(300) ->
- "bif timer rec";
-type_string(310) ->
- "argument registers";
-type_string(320) ->
- "compressed binary temp buffer";
-type_string(330) ->
- "term_to_binary temp buffer";
-type_string(340) ->
- "proc dict";
-type_string(350) ->
- "trace to port temp buffer";
-type_string(360) ->
- "lists subtract temp buffer";
-type_string(370) ->
- "link (lh)";
-type_string(380) ->
- "port call buffer";
-type_string(400) ->
- "definite_alloc block";
-type_string(_) ->
- invalid_type.
-
+dispatch_gather(#{ allocator_types := AllocatorTypes,
+ scheduler_ids := SchedulerIds,
+ histogram_start := HistStart,
+ histogram_width := HistWidth }, Ref, Gather)
+ when is_list(AllocatorTypes),
+ is_list(SchedulerIds),
+ HistStart >= 1, HistStart =< (1 bsl 28),
+ HistWidth >= 1, HistWidth =< 32 ->
+ MsgCount = lists:sum(
+ [Gather({AllocatorType, SchedId, HistWidth, HistStart, Ref}) ||
+ SchedId <- SchedulerIds,
+ AllocatorType <- AllocatorTypes]),
+ {HistStart, MsgCount};
+dispatch_gather(_, _, _) ->
+ error(badarg).
diff --git a/lib/tools/src/lcnt.erl b/lib/tools/src/lcnt.erl
index d0152a4915..ee6057e4f5 100644
--- a/lib/tools/src/lcnt.erl
+++ b/lib/tools/src/lcnt.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -125,7 +125,7 @@
%% -------------------------------------------------------------------- %%
start() -> gen_server:start({local, ?MODULE}, ?MODULE, [], []).
-stop() -> gen_server:call(?MODULE, stop, infinity).
+stop() -> gen_server:stop(?MODULE, normal, infinity).
init([]) -> {ok, #state{ locks = [], duration = 0 } }.
start_internal() ->
@@ -442,9 +442,6 @@ handle_call({save, Filename}, _From, State) ->
{reply, {error, Error}, State}
end;
-handle_call(stop, _From, State) ->
- {stop, normal, ok, State};
-
handle_call(Command, _From, State) ->
{reply, {error, {undefined, Command}}, State}.
diff --git a/lib/tools/src/tools.app.src b/lib/tools/src/tools.app.src
index f8c6aa22cb..f0e0fc4bec 100644
--- a/lib/tools/src/tools.app.src
+++ b/lib/tools/src/tools.app.src
@@ -21,11 +21,13 @@
[{description, "DEVTOOLS CXC 138 16"},
{vsn, "%VSN%"},
{modules, [cover,
+ cprof,
eprof,
fprof,
instrument,
lcnt,
make,
+ tags,
xref,
xref_base,
xref_compiler,
diff --git a/lib/tools/src/xref.erl b/lib/tools/src/xref.erl
index 32efa36fa2..466ec7d331 100644
--- a/lib/tools/src/xref.erl
+++ b/lib/tools/src/xref.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -182,7 +182,9 @@ split_args(Opts) ->
end.
stop(Name) ->
- gen_server:call(Name, stop, infinity).
+ try gen_server:call(Name, stop, infinity)
+ after catch unregister(Name) % ensure the name is gone
+ end.
add_release(Name, Dir) ->
gen_server:call(Name, {add_release, Dir}, infinity).
diff --git a/lib/tools/src/xref_utils.erl b/lib/tools/src/xref_utils.erl
index 02e207d40c..eca751337b 100644
--- a/lib/tools/src/xref_utils.erl
+++ b/lib/tools/src/xref_utils.erl
@@ -557,12 +557,9 @@ subdir(Dir, SubDir, true) ->
%% Avoid "App-01.01" - the zeroes will be lost.
filename2appl(File) ->
- Pos = string:rstr(File, "-"),
- true = Pos > 1,
- V = string:sub_string(File, Pos+1),
- true = string:len(V) > 0,
- VsnT = string:tokens(V, "."),
- ApplName = string:sub_string(File, 1, Pos-1),
+ [ApplName, V] = string:split(File, "-", trailing),
+ true = string:length(V) > 0,
+ VsnT = string:lexemes(V, "."),
Vsn = [list_to_integer(Vsn) || Vsn <- VsnT],
{list_to_atom(ApplName),Vsn}.
diff --git a/lib/tools/test/Makefile b/lib/tools/test/Makefile
index 2b7b17afb3..7a0a941ccc 100644
--- a/lib/tools/test/Makefile
+++ b/lib/tools/test/Makefile
@@ -32,6 +32,7 @@ MODULES = \
make_SUITE \
tools_SUITE \
xref_SUITE \
+ prof_bench_SUITE \
ignore_cores
ERL_FILES= $(MODULES:%=%.erl)
@@ -41,7 +42,7 @@ INSTALL_PROGS= $(TARGET_FILES)
EMAKEFILE=Emakefile
-SPEC_FILES= tools.spec
+SPEC_FILES= tools.spec tools_bench.spec
COVER_FILE = tools.cover
# ----------------------------------------------------
diff --git a/lib/tools/test/cover_SUITE.erl b/lib/tools/test/cover_SUITE.erl
index 161b0105b9..ee58fd7a10 100644
--- a/lib/tools/test/cover_SUITE.erl
+++ b/lib/tools/test/cover_SUITE.erl
@@ -24,7 +24,8 @@
-include_lib("common_test/include/ct.hrl").
suite() ->
- [{ct_hooks,[ts_install_cth]}].
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap,{minutes,5}}].
all() ->
NoStartStop = [eif,otp_5305,otp_5418,otp_7095,otp_8273,
@@ -35,7 +36,8 @@ all() ->
distribution, reconnect, die_and_reconnect,
dont_reconnect_after_stop, stop_node_after_disconnect,
export_import, otp_5031, otp_6115,
- otp_8270, otp_10979_hanging_node, otp_14817],
+ otp_8270, otp_10979_hanging_node, otp_14817,
+ local_only],
case whereis(cover_server) of
undefined ->
[coverage,StartStop ++ NoStartStop];
@@ -1742,6 +1744,40 @@ otp_13289(Config) ->
ok = file:delete(File),
ok.
+local_only(Config) ->
+ ok = file:set_cwd(proplists:get_value(data_dir, Config)),
+
+ %% Trying restricting to local nodes too late.
+ cover:start(),
+ {ok,a} = cover:compile(a),
+ [a] = cover:modules(),
+ {error,too_late} = cover:local_only(),
+ cover:stop(),
+
+ %% Now test local only mode.
+ cover:start(),
+ ok = cover:local_only(),
+ [] = cover:modules(),
+ {ok,a} = cover:compile(a),
+ [a] = cover:modules(),
+ done = a:start(5),
+ {ok, {a,{17,2}}} = cover:analyse(a, coverage, module),
+ {ok, [{{a,exit_kalle,0},{1,0}},
+ {{a,loop,3},{5,1}},
+ {{a,pong,1},{1,0}},
+ {{a,start,1},{6,0}},
+ {{a,stop,1},{0,1}},
+ {{a,trycatch,1},{4,0}}]} =
+ cover:analyse(a, coverage, function),
+
+ %% Make sure that it is not possible to run cover on
+ %% slave nodes.
+ {ok,Name} = test_server:start_node(?FUNCTION_NAME, slave, []),
+ {error,local_only} = cover:start([Name]),
+ test_server:stop_node(Name),
+
+ ok.
+
%%--Auxiliary------------------------------------------------------------
analyse_expr(Expr, Config) ->
diff --git a/lib/tools/test/emacs_SUITE.erl b/lib/tools/test/emacs_SUITE.erl
index f4e78da667..73270e6ed6 100644
--- a/lib/tools/test/emacs_SUITE.erl
+++ b/lib/tools/test/emacs_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,18 +23,28 @@
-export([all/0, init_per_testcase/2, end_per_testcase/2]).
--export([bif_highlight/1, indent/1]).
+-export([bif_highlight/1,
+ load_interpreted/1, compile_and_load/1,
+ indent/1,
+ tests_interpreted/1, tests_compiled/1
+ ]).
all() ->
- [bif_highlight, indent].
+ [bif_highlight, load_interpreted, compile_and_load,
+ indent,
+ tests_interpreted, tests_compiled
+ ].
-init_per_testcase(_Case, Config) ->
+init_per_testcase(Case, Config) ->
ErlangEl = filename:join([code:lib_dir(tools),"emacs","erlang.el"]),
case file:read_file_info(ErlangEl) of
- {ok, _} ->
- [{el, ErlangEl}|Config];
- _ ->
- {skip, "Could not find erlang.el"}
+ {ok, _} ->
+ case Case =:= bif_highlight orelse emacs_version_ok(24.1) of
+ false -> {skip, "Old or no emacs found"};
+ _ -> [{el, ErlangEl}|Config]
+ end;
+ _ ->
+ {skip, "Could not find erlang.el"}
end.
end_per_testcase(_Case, _Config) ->
@@ -46,54 +56,124 @@ bif_highlight(Config) ->
%% All auto-imported bifs
IntBifs = lists:usort(
- [F || {F,A} <- erlang:module_info(exports),
- erl_internal:bif(F,A)]),
+ [F || {F,A} <- erlang:module_info(exports),
+ erl_internal:bif(F,A)]),
%% all bif which need erlang: prefix and are not operands
ExtBifs = lists:usort(
- [F || {F,A} <- erlang:module_info(exports),
- not erl_internal:bif(F,A) andalso
- not is_atom(catch erl_internal:op_type(F,A))]),
+ [F || {F,A} <- erlang:module_info(exports),
+ not erl_internal:bif(F,A) andalso
+ not is_atom(catch erl_internal:op_type(F,A))]),
check_bif_highlight(Bin, <<"erlang-int-bifs">>, IntBifs),
check_bif_highlight(Bin, <<"erlang-ext-bifs">>, ExtBifs).
-
+
check_bif_highlight(Bin, Tag, Compare) ->
- [_H,IntMatch,_T] =
- re:split(Bin,<<"defvar ",Tag/binary,
- "[^(]*\\(([^)]*)">>,[]),
- EmacsIntBifs = [list_to_atom(S) ||
- S <- string:tokens(binary_to_list(IntMatch)," '\"\n")],
-
- ct:log("Emacs ~p",[EmacsIntBifs]),
- ct:log("Int ~p",[Compare]),
-
- ct:log("Diff1 ~p",[Compare -- EmacsIntBifs]),
- ct:log("Diff2 ~p",[EmacsIntBifs -- Compare]),
- [] = Compare -- EmacsIntBifs,
- [] = EmacsIntBifs -- Compare.
-
+ [_H,Match,_T] =
+ re:split(Bin,<<"defvar ",Tag/binary,
+ "[^(]*\\(([^)]*)">>,[]),
+ EmacsBifs = [list_to_atom(S) ||
+ S <- string:tokens(binary_to_list(Match)," '\"\n")],
+
+ ct:log("Comparing ~s", [Tag]),
+ ct:log("Emacs ~p",[EmacsBifs]),
+ ct:log("Erlang ~p",[Compare]),
+
+ ct:log("Only in Erlang ~p",[Compare -- EmacsBifs]),
+ ct:log("Only in Emacs ~p",[EmacsBifs -- Compare]),
+ [] = Compare -- EmacsBifs,
+ [] = EmacsBifs -- Compare.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-indent(Config) ->
- case emacs_version_ok() of
+load_interpreted(_Config) ->
+ _ = emacs(["-l erlang.el -f erlang-mode"]),
+ ok.
+
+compile_and_load(_Config) ->
+ Dir = emacs_dir(),
+ Files0 = filelib:wildcard("*.el", Dir),
+ Files = case emacs_version_ok(24.3) of
+ %% erldoc.el depends on cl-lib which was introduced in 24.3.
+ false -> Files0 -- ["erldoc.el"];
+ _ -> Files0
+ end,
+ Unforgiving =
+ case emacs_version_ok(24) of
+ Ver when Ver < 25 ->
+ "";
+ Ver when Ver < 26 ->
+ %% Workaround byte-compile-error-on-warn which seem broken in
+ %% Emacs 25.
+ "\"(advice-add #'display-warning :after "
+ "(lambda (_ f _ _) (error \"%s\" f)))\"";
+ _ ->
+ "\"(setq byte-compile-error-on-warn t)\""
+ end,
+ %% Add files here whenever they are cleaned of warnings.
+ NoWarn = ["erlang.el", "erlang-test.el", "erlang-edoc.el", "erlang-start.el", "erldoc.el"],
+ Compile = fun(File) ->
+ Pedantic = case lists:member(File, NoWarn) andalso Unforgiving /= "" of
+ true -> ["--eval ", Unforgiving, " "];
+ false -> " "
+ end,
+ emacs([Pedantic,
+ " -f batch-byte-compile ", dquote(filename:join(Dir, File))]),
+ true
+ end,
+ lists:foreach(Compile, Files),
+ emacs(["-l erlang.elc -f erlang-mode"]),
+ ok.
+
+tests_interpreted(_Config) ->
+ case emacs_version_ok(25) of
+ false -> {skip, "Old or no emacs found"};
+ _ ->
+ emacs(["-l erlang.el ",
+ "-l erlang-test.el -f ert-run-tests-batch-and-exit"]),
+ ok
+ end.
+
+tests_compiled(_Config) ->
+ case emacs_version_ok(25) of
false -> {skip, "Old or no emacs found"};
- true ->
- Def = filename:dirname(code:which(?MODULE)) ++ "/" ++ ?MODULE_STRING ++ "_data",
- Dir = proplists:get_value(data_dir, Config, Def),
- OrigFs = filelib:wildcard(Dir ++ "/*"),
- io:format("Dir: ~s~nFs: ~p~n", [Dir, OrigFs]),
- Fs = [{File, unindent(File)} || File <- OrigFs,
- filename:extension(File) =:= ""],
- Indent = fun emacs/1,
- [Indent(File) || {_, File} <- Fs],
- Res = [diff(Orig, File) || {Orig, File} <- Fs],
- [file:delete(File) || {ok, File} <- Res], %% Cleanup
- [] = [Fail || {fail, Fail} <- Res],
+ _ ->
+ emacs(["-l erlang.elc ",
+ "-l erlang-test.elc -f ert-run-tests-batch-and-exit"]),
ok
end.
+
+dquote(Str) ->
+ "\"" ++ Str ++ "\"".
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+indent(Config) ->
+ Def = filename:dirname(code:which(?MODULE))
+ ++ "/"
+ ++ ?MODULE_STRING
+ ++ "_data",
+ Dir = proplists:get_value(data_dir, Config, Def),
+ OrigFs = filelib:wildcard(Dir ++ "/*"),
+ io:format("Dir: ~s~nFs: ~p~n", [Dir, OrigFs]),
+ Fs = [{File, unindent(File)} || File <- OrigFs,
+ filename:extension(File) =:= ""],
+ Indent = fun(File) ->
+ emacs([
+ File, " ",
+ "--eval '(indent-region (point-min) (point-max) nil)' ",
+ "--eval '(save-buffer 0)'"
+ ]),
+ ok
+ end,
+ [Indent(File) || {_, File} <- Fs],
+ Res = [diff(Orig, File) || {Orig, File} <- Fs],
+ [file:delete(File) || {ok, File} <- Res], %% Cleanup
+ [] = [Fail || {fail, Fail} <- Res],
+ ok.
+
unindent(Input) ->
Output = Input ++ ".erl",
{ok, Bin} = file:read_file(Input),
@@ -112,14 +192,15 @@ diff(Orig, File) ->
{fail, File}
end.
-emacs_version_ok() ->
- case os:cmd("emacs --version | head -1") of
+emacs_version_ok(AcceptVer) ->
+ VersionLine = os:cmd("emacs --version | head -1"),
+ io:format("~s~n", [VersionLine]),
+ case VersionLine of
"GNU Emacs " ++ Ver ->
case string:to_float(Ver) of
- {Vsn, _} when Vsn >= 24.1 ->
- true;
+ {Vsn, _} when Vsn >= AcceptVer ->
+ Vsn;
_ ->
- io:format("Emacs version fail~n~s~n~n",[Ver]),
false
end;
Res ->
@@ -127,16 +208,19 @@ emacs_version_ok() ->
false
end.
-emacs(File) ->
- EmacsErlDir = filename:join([code:lib_dir(tools), "emacs"]),
+emacs(EmacsCmds) when is_list(EmacsCmds) ->
Cmd = ["emacs ",
"--batch --quick ",
- "--directory ", EmacsErlDir, " ",
- "--eval \"(require 'erlang-start)\" ",
- File, " ",
- "--eval '(indent-region (point-min) (point-max) nil)' ",
- "--eval '(save-buffer 0)'"
- ],
- _Res = os:cmd(Cmd),
- % io:format("cmd ~s:~n=> ~s~n", [Cmd, _Res]),
- ok.
+ "--directory ", dquote(emacs_dir()), " ",
+ "--eval \"(require 'erlang-start)\" "
+ | EmacsCmds],
+ Res0 = os:cmd(Cmd ++ " ; echo $?"),
+ Rows = string:lexemes(Res0, ["\r\n", $\n]),
+ Res = lists:last(Rows),
+ Output = string:join(lists:droplast(Rows), "\n"),
+ io:format("Cmd ~ts:~n => ~s ~ts~n", [Cmd, Res, Output]),
+ "0" = Res,
+ Output.
+
+emacs_dir() ->
+ filename:join([code:lib_dir(tools), "emacs"]).
diff --git a/lib/tools/test/eprof_SUITE_data/eed.erl b/lib/tools/test/eprof_SUITE_data/eed.erl
index 5f2a21aa60..9fe49c6f5c 100644
--- a/lib/tools/test/eprof_SUITE_data/eed.erl
+++ b/lib/tools/test/eprof_SUITE_data/eed.erl
@@ -54,7 +54,7 @@ edit(Name) ->
loop(St0) ->
{ok, St1, Cmd} = get_line(St0),
- case catch command(lib:nonl(Cmd), St1) of
+ case catch command(nonl(Cmd), St1) of
{'EXIT', Reason} ->
%% XXX Should clear outstanding global command here.
loop(print_error({'EXIT', Reason}, St1));
@@ -66,6 +66,10 @@ loop(St0) ->
loop(St2)
end.
+nonl([$\n]) -> [];
+nonl([]) -> [];
+nonl([H|T]) -> [H|nonl(T)].
+
command(Cmd, St) ->
case parse_command(Cmd, St) of
quit ->
diff --git a/lib/tools/test/fprof_SUITE.erl b/lib/tools/test/fprof_SUITE.erl
index 8fd164a4b3..ae0e7253ad 100644
--- a/lib/tools/test/fprof_SUITE.erl
+++ b/lib/tools/test/fprof_SUITE.erl
@@ -51,7 +51,7 @@
suite() ->
[{ct_hooks,[ts_install_cth]},
- {timetrap,{seconds,60}}].
+ {timetrap,{seconds,240}}].
all() ->
case test_server:is_native(fprof_SUITE) of
@@ -571,7 +571,7 @@ seq_r(Start, Stop, Succ, R) ->
create_file_slow(Name, N) when is_integer(N), N >= 0 ->
{ok, FD} =
- file:open(Name, [raw, write, delayed_write, binary]),
+ file:open(Name, [raw, write, binary]),
if N > 256 ->
ok = file:write(FD,
lists:map(fun (X) -> <<X:32/unsigned>> end,
diff --git a/lib/tools/test/instrument_SUITE.erl b/lib/tools/test/instrument_SUITE.erl
index f37d28c277..f474669836 100644
--- a/lib/tools/test/instrument_SUITE.erl
+++ b/lib/tools/test/instrument_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -20,98 +20,361 @@
-module(instrument_SUITE).
-export([all/0, suite/0]).
--export(['+Mim true'/1, '+Mis true'/1]).
+
+-export([allocations_enabled/1, allocations_disabled/1, allocations_ramv/1,
+ carriers_enabled/1, carriers_disabled/1]).
+
+-export([test_all_alloc/2, test_per_alloc/2, test_format/3, test_abort/1,
+ generate_test_blocks/0, churn_memory/0]).
-include_lib("common_test/include/ct.hrl").
suite() ->
[{ct_hooks,[ts_install_cth]},
- {timetrap,{seconds,10}}].
+ {timetrap,{minutes,5}}].
all() ->
- ['+Mim true', '+Mis true'].
-
-
-%% Check that memory data can be read and processed
-'+Mim true'(Config) when is_list(Config) ->
- Node = start_slave("+Mim true"),
- MD = rpc:call(Node, instrument, memory_data, []),
- [{total,[{sizes,S1,S2,S3},{blocks,B1,B2,B3}]}]
- = rpc:call(Node, instrument, memory_status, [total]),
- stop_slave(Node),
- true = S1 =< S2,
- true = S2 =< S3,
- true = B1 =< B2,
- true = B2 =< B3,
- MDS = instrument:sort(MD),
- {Low, High} = instrument:mem_limits(MDS),
- true = Low < High,
- {_, AL} = MDS,
- SumBlocks = instrument:sum_blocks(MD),
- case SumBlocks of
- N when is_integer(N) ->
- N = lists:foldl(fun ({_,_,Size,_}, Sum) ->
- Size+Sum
- end, 0, AL),
- true = N =< S3;
- Other ->
- ct:fail(Other)
+ [allocations_enabled, allocations_disabled, allocations_ramv,
+ carriers_enabled, carriers_disabled].
+
+-define(GENERATED_SBC_BLOCK_COUNT, 1000).
+-define(GENERATED_MBC_BLOCK_COUNT, ?GENERATED_SBC_BLOCK_COUNT).
+
+-define(GENERATED_BLOCK_COUNT, (?GENERATED_SBC_BLOCK_COUNT +
+ ?GENERATED_MBC_BLOCK_COUNT)).
+-define(GENERATED_CARRIER_COUNT, ?GENERATED_SBC_BLOCK_COUNT).
+
+allocations_test(Args, Plain, PerAlloc) ->
+ run_test(Args, fun(Node) ->
+ ok = rpc:call(Node, ?MODULE, test_all_alloc,
+ [fun instrument:allocations/0, Plain]),
+ ok = rpc:call(Node, ?MODULE, test_per_alloc,
+ [fun instrument:allocations/1, PerAlloc]),
+ ok = rpc:call(Node, ?MODULE, test_format,
+ [#{ histogram_start => 512,
+ histogram_width => 4 },
+ fun instrument:allocations/1,
+ fun verify_allocations_output/2]),
+ ok = rpc:call(Node, ?MODULE, test_abort,
+ [fun erts_internal:gather_alloc_histograms/1])
+ end).
+
+allocations_enabled(Config) when is_list(Config) ->
+ allocations_test("+Meamax +Muatags true",
+ fun verify_allocations_enabled/1,
+ fun verify_allocations_enabled/2).
+
+allocations_disabled(Config) when is_list(Config) ->
+ allocations_test("+Meamax +Muatags false",
+ fun verify_allocations_disabled/1,
+ fun verify_allocations_disabled/2).
+
+allocations_ramv(Config) when is_list(Config) ->
+ allocations_test("+Meamax +Muatags true +Muramv true",
+ fun verify_allocations_enabled/1,
+ fun verify_allocations_enabled/2).
+
+verify_allocations_disabled(_AllocType, Result) ->
+ verify_allocations_disabled(Result).
+
+verify_allocations_disabled({ok, {_HistStart, _UnscannedBytes, Allocs}}) ->
+ true = Allocs =:= #{};
+verify_allocations_disabled({error, not_enabled}) ->
+ ok.
+
+%% Skip types that have unstable results or are unaffected by +Muatags
+verify_allocations_enabled(literal_alloc, _Result) -> ok;
+verify_allocations_enabled(exec_alloc, _Result) -> ok;
+verify_allocations_enabled(temp_alloc, _Result) -> ok;
+verify_allocations_enabled(sl_alloc, _Result) -> ok;
+verify_allocations_enabled(_AllocType, Result) ->
+ verify_allocations_enabled(Result).
+
+verify_allocations_enabled({ok, {_HistStart, _UnscannedBytes, Allocs}}) ->
+ true = Allocs =/= #{}.
+
+verify_allocations_output(#{}, {ok, {_, _, Allocs}}) when Allocs =:= #{} ->
+ %% This happens when the allocator is enabled but tagging is disabled. If
+ %% there's an error that causes Allocs to always be empty when enabled it
+ %% will be caught by verify_allocations_enabled.
+ ok;
+verify_allocations_output(#{}, {error, not_enabled}) ->
+ ok;
+verify_allocations_output(#{ histogram_start := HistStart,
+ histogram_width := HistWidth },
+ {ok, {HistStart, _UnscannedBytes, ByOrigin}}) ->
+ AllHistograms = lists:flatten([maps:values(ByType) ||
+ ByType <- maps:values(ByOrigin)]),
+
+ %% Do the histograms look alright?
+ HistogramSet = ordsets:from_list(AllHistograms),
+ Verified = [H || H <- HistogramSet,
+ tuple_size(H) =:= HistWidth,
+ hist_sum(H) >= 1],
+ [] = ordsets:subtract(HistogramSet, Verified),
+
+ %% Do we have at least as many blocks as we've generated?
+ BlockCount = lists:foldl(fun(Hist, Acc) ->
+ hist_sum(Hist) + Acc
+ end, 0, AllHistograms),
+ GenTotalBlockCount = ?GENERATED_BLOCK_COUNT,
+ GenSBCBlockCount = ?GENERATED_SBC_BLOCK_COUNT,
+ if
+ BlockCount < GenSBCBlockCount ->
+ ct:fail("Found ~p blocks, required at least ~p (SB)." ,
+ [BlockCount, GenSBCBlockCount]);
+ BlockCount >= GenTotalBlockCount ->
+ ct:pal("Found ~p blocks, expected at least ~p (SB + MB).",
+ [BlockCount, GenTotalBlockCount]);
+ BlockCount < GenTotalBlockCount ->
+ ct:pal("Found ~p blocks, expected at least ~p (SB + MB), but this "
+ "may be due to MBCs being skipped if they're about to be "
+ "scanned just as they're fetched from the carrier pool.",
+ [BlockCount, GenTotalBlockCount])
end,
- lists:foldl(
- fun ({TDescr,Addr,Size,Proc}, MinAddr) ->
- true = TDescr /= invalid_type,
- true = is_integer(TDescr),
- true = is_integer(Addr),
- true = is_integer(Size),
- true = Addr >= MinAddr,
- case Proc of
- {0, Number, Serial} ->
- true = is_integer(Number),
- true = is_integer(Serial);
- undefined ->
- ok;
- BadProc ->
- ct:fail({badproc, BadProc})
- end,
- NextMinAddr = Addr+Size,
- true = NextMinAddr =< High,
- NextMinAddr
- end, Low, AL),
- {_, DAL} = instrument:descr(MDS),
- lists:foreach(
- fun ({TDescr,_,_,Proc}) ->
- true = TDescr /= invalid_type,
- true = is_atom(TDescr) orelse is_list(TDescr),
- true = is_pid(Proc) orelse Proc == undefined
- end, DAL),
- ASL = lists:map(fun ({_,A,S,_}) -> {A,S} end, AL),
- ASL = lists:map(fun ({_,A,S,_}) -> {A,S} end, DAL),
- instrument:holes(MDS),
- {comment, "total status - sum of blocks = " ++ integer_to_list(S1-SumBlocks)}.
-
-%% Check that memory data can be read and processed
-'+Mis true'(Config) when is_list(Config) ->
- Node = start_slave("+Mis true"),
- [{total,[{sizes,S1,S2,S3},{blocks,B1,B2,B3}]}]
- = rpc:call(Node, instrument, memory_status, [total]),
- true = S1 =< S2,
- true = S2 =< S3,
- true = B1 =< B2,
- true = B2 =< B3,
- true = is_list(rpc:call(Node,instrument,memory_status,[allocators])),
- true = is_list(rpc:call(Node,instrument,memory_status,[classes])),
- true = is_list(rpc:call(Node,instrument,memory_status,[types])),
+
ok.
+%% %% %% %% %% %%
+
+carriers_test(Args, Plain, PerAlloc) ->
+ run_test(Args, fun(Node) ->
+ ok = rpc:call(Node, ?MODULE, test_all_alloc,
+ [fun instrument:carriers/0, Plain]),
+ ok = rpc:call(Node, ?MODULE, test_per_alloc,
+ [fun instrument:carriers/1, PerAlloc]),
+ ok = rpc:call(Node, ?MODULE, test_format,
+ [#{ histogram_start => 1024,
+ histogram_width => 4 },
+ fun instrument:carriers/1,
+ fun verify_carriers_output/2]),
+ ok = rpc:call(Node, ?MODULE, test_abort,
+ [fun erts_internal:gather_carrier_info/1])
+ end).
+
+carriers_enabled(Config) when is_list(Config) ->
+ carriers_test("+Meamax",
+ fun verify_carriers_enabled/1,
+ fun verify_carriers_enabled/2).
+
+carriers_disabled(Config) when is_list(Config) ->
+ carriers_test("+Meamin",
+ fun verify_carriers_disabled/1,
+ fun verify_carriers_disabled/2).
+
+verify_carriers_disabled(_AllocType, Result) ->
+ verify_carriers_disabled(Result).
+
+verify_carriers_disabled({error, not_enabled}) ->
+ ok;
+verify_carriers_disabled({ok, {_HistStart, Carriers}}) ->
+ verify_carriers_disabled_1(Carriers).
+
+verify_carriers_disabled_1([]) ->
+ ok;
+%% literal_alloc, exec_alloc, and temp_alloc can't be disabled, so we have to
+%% accept their presence in carriers_disabled/test_all_alloc.
+verify_carriers_disabled_1([Carrier | Rest]) when
+ element(1, Carrier) =:= literal_alloc;
+ element(1, Carrier) =:= exec_alloc;
+ element(1, Carrier) =:= temp_alloc ->
+ verify_carriers_disabled_1(Rest).
+
+%% exec_alloc only has a carrier if it's actually used.
+verify_carriers_enabled(exec_alloc, _Result) -> ok;
+verify_carriers_enabled(_AllocType, Result) -> verify_carriers_enabled(Result).
+
+verify_carriers_enabled({ok, {_HistStart, Carriers}}) when Carriers =/= [] ->
+ ok.
+
+verify_carriers_output(#{ histogram_start := HistStart,
+ histogram_width := HistWidth },
+ {ok, {HistStart, AllCarriers}}) ->
+
+ %% Do the carriers look alright?
+ CarrierSet = ordsets:from_list(AllCarriers),
+ Verified = [C || {AllocType,
+ TotalSize,
+ UnscannedSize,
+ AllocatedSize,
+ AllocatedCount,
+ InPool,
+ FreeBlockHist} = C <- CarrierSet,
+ is_atom(AllocType),
+ is_integer(TotalSize), TotalSize >= 1,
+ is_integer(UnscannedSize), UnscannedSize < TotalSize,
+ UnscannedSize >= 0,
+ is_integer(AllocatedSize), AllocatedSize < TotalSize,
+ AllocatedSize >= 0,
+ is_integer(AllocatedCount), AllocatedCount =< AllocatedSize,
+ AllocatedCount >= 0,
+ is_boolean(InPool),
+ tuple_size(FreeBlockHist) =:= HistWidth,
+ carrier_block_check(AllocatedCount, FreeBlockHist)],
+ [] = ordsets:subtract(CarrierSet, Verified),
+
+ %% Do we have at least as many carriers as we've generated?
+ CarrierCount = length(AllCarriers),
+ GenSBCCount = ?GENERATED_SBC_BLOCK_COUNT,
+ if
+ CarrierCount < GenSBCCount ->
+ ct:fail("Carrier count is ~p, expected at least ~p (SBC).",
+ [CarrierCount, GenSBCCount]);
+ CarrierCount >= GenSBCCount ->
+ ct:pal("Found ~p carriers, required at least ~p (SBC)." ,
+ [CarrierCount, GenSBCCount])
+ end,
+
+ ok;
+verify_carriers_output(#{}, {error, not_enabled}) ->
+ ok.
+
+carrier_block_check(AllocCount, FreeHist) ->
+ %% A carrier must contain at least one block, and th. number of free blocks
+ %% must not exceed the number of allocated blocks + 1.
+ FreeCount = hist_sum(FreeHist),
+
+ (AllocCount + FreeCount) >= 1 andalso FreeCount =< (AllocCount + 1).
+
+%% %% %% %% %% %%
+
+test_all_alloc(Gather, Verify) ->
+ Verify(Gather()),
+ ok.
+
+test_per_alloc(Gather, Verify) ->
+ [begin
+ Verify(T, Gather(#{ allocator_types => [T] }))
+ end || T <- erlang:system_info(alloc_util_allocators)],
+ ok.
+
+test_format(#{ allocator_types := _ }, _, _) ->
+ error(badarg);
+test_format(Options0, Gather, Verify) ->
+ %% We limit format checking to binary_alloc since we generated the test
+ %% vectors there.
+ Options = Options0#{ allocator_types => [binary_alloc] },
+ Verify(Options, Gather(Options)),
+ ok.
+
+test_abort(Gather) ->
+ %% There's no way for us to tell whether this actually aborted or ran to
+ %% completion, but it might catch a few segfaults.
+ %% This testcase is mostly useful when run in an debug emulator as it needs
+ %% the modified reduction count to trigger the odd trap scenarios
+ Runner = self(),
+ Ref = make_ref(),
+ spawn_opt(fun() ->
+ [begin
+ Ref2 = make_ref(),
+ [Gather({Type, SchedId, 1, 1, Ref2}) ||
+ Type <- erlang:system_info(alloc_util_allocators),
+ SchedId <- lists:seq(0, erlang:system_info(schedulers))]
+ end || _ <- lists:seq(1,100)],
+ Runner ! Ref
+ end, [{priority, max}]),
+ receive
+ Ref -> ok
+ end.
+
+hist_sum(H) -> hist_sum_1(H, tuple_size(H), 0).
+hist_sum_1(_H, 0, A) -> A;
+hist_sum_1(H, N, A) -> hist_sum_1(H, N - 1, element(N, H) + A).
+
+%%
+
+run_test(Args0, Test) ->
+ %% Override single-block carrier threshold for binaries to ensure we have
+ %% coverage for that path. generate_test_blocks builds a few binaries that
+ %% crosses this threshold.
+ %%
+ %% We also set the abandon carrier threshold to 70% to provoke more
+ %% activity in the carrier pool.
+ Args = Args0 ++ " +MBsbct 1 +Muacul 70",
+ Node = start_slave(Args),
+
+ ok = rpc:call(Node, ?MODULE, generate_test_blocks, []),
+ ok = Test(Node),
+
+ ok = rpc:call(Node, ?MODULE, churn_memory, []),
+ ok = Test(Node),
+
+ true = test_server:stop_node(Node).
+
start_slave(Args) ->
MicroSecs = erlang:monotonic_time(),
Name = "instr" ++ integer_to_list(MicroSecs),
Pa = filename:dirname(code:which(?MODULE)),
- {ok, Node} = test_server:start_node(list_to_atom(Name),
- slave,
- [{args, "-pa " ++ Pa ++ " " ++ Args}]),
+
+ %% We pass arguments through ZFLAGS as the nightly tests rotate
+ %% +Meamax/+Meamin which breaks the _enabled and _disabled tests unless
+ %% overridden.
+ ZFlags = os:getenv("ERL_ZFLAGS", ""),
+ {ok, Node} = try
+ os:putenv("ERL_ZFLAGS", ZFlags ++ [" " | Args]),
+ test_server:start_node(list_to_atom(Name),
+ slave,
+ [{args, "-pa " ++ Pa}])
+ after
+ os:putenv("ERL_ZFLAGS", ZFlags)
+ end,
Node.
+generate_test_blocks() ->
+ Runner = self(),
+ Ref = make_ref(),
+ spawn(fun() ->
+ %% We've set the single-block carrier threshold to 1KB so one
+ %% ought to land in a SBC and the other in a MBC. Both are kept
+ %% alive forever.
+ SBCs = [<<I, 0:(1 bsl 10)/unit:8>> ||
+ I <- lists:seq(1, ?GENERATED_SBC_BLOCK_COUNT)],
+ MBCs = [<<I, 0:64/unit:8>> ||
+ I <- lists:seq(1, ?GENERATED_MBC_BLOCK_COUNT)],
+ Runner ! Ref,
+ receive
+ gurka -> gaffel ! {SBCs, MBCs}
+ end
+ end),
+ receive
+ Ref -> ok
+ end.
-stop_slave(Node) ->
- true = test_server:stop_node(Node).
+churn_memory() ->
+ %% All processes spawned from here on have 'low' priority to avoid starving
+ %% others (e.g. the rpc process) which could cause the test to time out.
+ [begin
+ churn_list_to_binary(),
+ churn_processes(),
+ churn_ets()
+ end || _ <- lists:seq(1, erlang:system_info(schedulers))],
+ ok.
+
+churn_processes() ->
+ Pid = spawn_opt(fun churn_processes/0, [{priority, low}]),
+ [Pid ! <<I, 0:128/unit:8>> || I <- lists:seq(1, 128)].
+
+%% Nearly all types have a few allocations at all times but sl_alloc is
+%% often empty. list_to_binary on large inputs will yield and spill the
+%% state into an 'estack' which is allocated through sl_alloc.
+%%
+%% This is inherently unstable so we skip the verification step for this
+%% type, but there's still a point to hammering it.
+churn_list_to_binary() ->
+ List = binary_to_list(<<0:(1 bsl 20)/unit:8>>),
+ spawn_opt(fun() -> churn_list_to_binary_1(List) end, [{priority, low}]).
+
+churn_list_to_binary_1(List) ->
+ _ = id(list_to_binary(List)),
+ churn_list_to_binary_1(List).
+
+churn_ets() ->
+ spawn_opt(fun() -> churn_ets_1(ets:new(gurka, [])) end, [{priority, low}]).
+
+churn_ets_1(Tab) ->
+ ets:insert(Tab, {gaffel, lists:seq(1, 16)}),
+ ets:delete_all_objects(Tab),
+ churn_ets_1(Tab).
+
+id(I) ->
+ I.
diff --git a/lib/tools/test/lcnt_SUITE.erl b/lib/tools/test/lcnt_SUITE.erl
index a79572a742..8a2f6bfc89 100644
--- a/lib/tools/test/lcnt_SUITE.erl
+++ b/lib/tools/test/lcnt_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/tools/test/prof_bench_SUITE.erl b/lib/tools/test/prof_bench_SUITE.erl
new file mode 100644
index 0000000000..50d0ba9cd9
--- /dev/null
+++ b/lib/tools/test/prof_bench_SUITE.erl
@@ -0,0 +1,126 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(prof_bench_SUITE).
+
+-include_lib("common_test/include/ct_event.hrl").
+
+%% Test server framework exports
+-export([all/0, suite/0, init_per_suite/1, end_per_suite/1]).
+
+-export([overhead/1]).
+
+%%%---------------------------------------------------------------------
+%%% Test suites
+%%%---------------------------------------------------------------------
+
+
+suite() ->
+ [{timetrap,{minutes,10}}].
+
+all() ->
+ [overhead].
+
+init_per_suite(Config) ->
+ case {test_server:is_native(fprof_SUITE) or
+ (lists:any(fun(M) -> test_server:is_native(M) end, modules())) or
+ (whereis(cover_server) =/= undefined),
+ erlang:system_info(wordsize)}
+ of
+ {true, _} -> {skip, "Native or cover code"};
+ {_, 4} -> {skip, "Can't run on 32-bit as files will be large"};
+ {false, 8} -> Config
+ end.
+
+end_per_suite(Config) ->
+ LogFile = filename:join(proplists:get_value(priv_dir, Config), "fprof.trace"),
+ file:delete(LogFile),
+ ok.
+
+%%%---------------------------------------------------------------------
+
+%% ct:run_test([{suite, prof_bench_SUITE}]).
+overhead(Config) ->
+ LogFile = filename:join(proplists:get_value(priv_dir, Config), "fprof.trace"),
+ SofsCopy = filename:join(proplists:get_value(data_dir, Config), "sofs_copy.erl"),
+ TC = fun() -> compile:file(SofsCopy, [binary]) end,
+ _Warmup = timer:tc(TC),
+
+ {NormTime,{ok, sofs_copy, _}} = timer:tc(TC),
+ {FProfTime,{ok,sofs_copy,_}} = fprof:apply(timer, tc, [TC], [{file, LogFile}]),
+ ct:pal("FProf: ~p Norm: ~p Ratio: ~p",[FProfTime, NormTime, NormTime / FProfTime * 100]),
+ {ok,{EProfTime,{ok,sofs_copy,_}}} = eprof:profile([], timer, tc, [TC]),
+ ct:pal("EProf: ~p Norm: ~p Ratio: ~p",[EProfTime, NormTime, NormTime / EProfTime * 100]),
+ {CProfTime,{ok,sofs_copy,_}} = cprof_apply(timer, tc, [TC]),
+ ct:pal("CProf: ~p Norm: ~p Ratio: ~p",[CProfTime, NormTime, NormTime / CProfTime * 100]),
+ {CoverTime,{ok,sofs_copy,_}} = cover_apply(timer, tc, [TC]),
+ ct:pal("Cover: ~p Norm: ~p Ratio: ~p",[CoverTime, NormTime, NormTime / CoverTime * 100]),
+
+ ct_event:notify(#event{name = benchmark_data,
+ data = [{name, fprof_overhead},
+ {value, NormTime / FProfTime * 100}]}),
+ ct_event:notify(#event{name = benchmark_data,
+ data = [{name, eprof_overhead},
+ {value, NormTime / EProfTime * 100}]}),
+ ct_event:notify(#event{name = benchmark_data,
+ data = [{name, cprof_overhead},
+ {value, NormTime / CProfTime * 100}]}),
+ ct_event:notify(#event{name = benchmark_data,
+ data = [{name, cover_overhead},
+ {value, NormTime / CoverTime * 100}]}).
+
+%% overhead(Config) ->
+%% LogFile = filename:join(proplists:get_value(priv_dir, Config), "fprof.trace"),
+%% SofsCopy = filename:join(proplists:get_value(data_dir, Config), "sofs_copy.erl"),
+%% TC = fun() -> compile:file(SofsCopy, [binary]) end,
+%% _Warmup = timer:tc(TC),
+
+%% [{ok,{EProfTime,{ok,sofs_copy,_}}} = eprof:profile([], timer, tc, [TC])
+%% || _ <- lists:seq(1,10)],
+%% %% [fprof:apply(timer, tc, [TC], [{file, LogFile}]) || _ <- lists:seq(1,10)],
+%% {FProfTime,{ok,sofs_copy,_}} = fprof:apply(timer, tc, [TC], [{file, LogFile}]),
+%% {NormTime,{ok, sofs_copy, _}} = timer:tc(TC),
+
+ %% ct:pal("FProf: ~p Norm: ~p Ratio: ~p",[FProfTime, NormTime, FProfTime / NormTime]).
+
+cprof_apply(M, F, A) ->
+ cprof:start(),
+ Res = apply(M, F, A),
+ cprof:stop(),
+ Res.
+
+cover_apply(M, F, A) ->
+ cover:start(),
+ catch cover:local_only(),
+ Modules = modules(),
+ [code:unstick_mod(Mod) || Mod <- Modules],
+ cover:compile_beam(Modules),
+ [code:stick_mod(Mod) || Mod <- Modules],
+ Res = apply(M, F, A),
+ cover:stop(),
+ Res.
+
+modules() ->
+ application:load(compiler),
+ {ok, CompilerModules} = application:get_key(compiler, modules),
+ %% Only cover compile a subset of the stdlib modules
+ StdlibModules = [erl_parse, erl_expand_records, erl_lint, gb_trees, gb_sets, sofs,
+ beam_lib, dict, epp, erl_anno, erl_bits,
+ orddict, ordsets, sets, string, unicode, unicode_util],
+ CompilerModules ++ StdlibModules.
diff --git a/lib/tools/test/prof_bench_SUITE_data/sofs_copy.erl b/lib/tools/test/prof_bench_SUITE_data/sofs_copy.erl
new file mode 100644
index 0000000000..2a9b19177e
--- /dev/null
+++ b/lib/tools/test/prof_bench_SUITE_data/sofs_copy.erl
@@ -0,0 +1,2809 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(sofs_copy).
+
+-export([from_term/1, from_term/2, from_external/2, empty_set/0,
+ is_type/1, set/1, set/2, from_sets/1, relation/1, relation/2,
+ a_function/1, a_function/2, family/1, family/2,
+ to_external/1, type/1, to_sets/1, no_elements/1,
+ specification/2, union/2, intersection/2, difference/2,
+ symdiff/2, symmetric_partition/2, product/1, product/2,
+ constant_function/2, is_equal/2, is_subset/2, is_sofs_set/1,
+ is_set/1, is_empty_set/1, is_disjoint/2]).
+
+-export([union/1, intersection/1, canonical_relation/1]).
+
+-export([relation_to_family/1, domain/1, range/1, field/1,
+ relative_product/1, relative_product/2, relative_product1/2,
+ converse/1, image/2, inverse_image/2, strict_relation/1,
+ weak_relation/1, extension/3, is_a_function/1]).
+
+-export([composite/2, inverse/1]).
+
+-export([restriction/2, restriction/3, drestriction/2, drestriction/3,
+ substitution/2, projection/2, partition/1, partition/2,
+ partition/3, multiple_relative_product/2, join/4]).
+
+-export([family_to_relation/1, family_specification/2,
+ union_of_family/1, intersection_of_family/1,
+ family_union/1, family_intersection/1,
+ family_domain/1, family_range/1, family_field/1,
+ family_union/2, family_intersection/2, family_difference/2,
+ partition_family/2, family_projection/2]).
+
+-export([family_to_digraph/1, family_to_digraph/2,
+ digraph_to_family/1, digraph_to_family/2]).
+
+%% Shorter names of some functions.
+-export([fam2rel/1, rel2fam/1]).
+
+-import(lists,
+ [any/2, append/1, flatten/1, foreach/2,
+ keysort/2, last/1, map/2, mapfoldl/3, member/2, merge/2,
+ reverse/1, reverse/2, sort/1, umerge/1, umerge/2, usort/1]).
+
+-compile({inline, [{family_to_relation,1}, {relation_to_family,1}]}).
+
+-compile({inline, [{rel,2},{a_func,2},{fam,2},{term2set,2}]}).
+
+-compile({inline, [{external_fun,1},{element_type,1}]}).
+
+-compile({inline,
+ [{unify_types,2}, {match_types,2},
+ {test_rel,3}, {symdiff,3},
+ {subst,3}]}).
+
+-compile({inline, [{fam_binop,3}]}).
+
+%% Nope, no is_member, del_member or add_member.
+%%
+%% See also "Naive Set Theory" by Paul R. Halmos.
+%%
+%% By convention, erlang:error/1 is called from exported functions.
+
+-define(TAG, 'Set').
+-define(ORDTAG, 'OrdSet').
+
+-record(?TAG, {data = [] :: list(), type = type :: term()}).
+-record(?ORDTAG, {orddata = {} :: tuple() | atom(),
+ ordtype = type :: term()}).
+
+-define(LIST(S), (S)#?TAG.data).
+-define(TYPE(S), (S)#?TAG.type).
+-define(SET(L, T), #?TAG{data = L, type = T}).
+-define(IS_SET(S), is_record(S, ?TAG)).
+-define(IS_UNTYPED_SET(S), ?TYPE(S) =:= ?ANYTYPE).
+
+%% Ordered sets and atoms:
+-define(ORDDATA(S), (S)#?ORDTAG.orddata).
+-define(ORDTYPE(S), (S)#?ORDTAG.ordtype).
+-define(ORDSET(L, T), #?ORDTAG{orddata = L, ordtype = T}).
+-define(IS_ORDSET(S), is_record(S, ?ORDTAG)).
+-define(ATOM_TYPE, atom).
+-define(IS_ATOM_TYPE(T), is_atom(T)). % true for ?ANYTYPE...
+
+%% When IS_SET is true:
+-define(ANYTYPE, '_').
+-define(BINREL(X, Y), {X, Y}).
+-define(IS_RELATION(R), is_tuple(R)).
+-define(REL_ARITY(R), tuple_size(R)).
+-define(REL_TYPE(I, R), element(I, R)).
+-define(SET_OF(X), [X]).
+-define(IS_SET_OF(X), is_list(X)).
+-define(FAMILY(X, Y), ?BINREL(X, ?SET_OF(Y))).
+
+-export_type([anyset/0, binary_relation/0, external_set/0, a_function/0,
+ family/0, relation/0, set_of_sets/0, set_fun/0, spec_fun/0,
+ type/0]).
+-export_type([ordset/0, a_set/0]).
+
+-type(anyset() :: ordset() | a_set()).
+-type(binary_relation() :: relation()).
+-type(external_set() :: term()).
+-type(a_function() :: relation()).
+-type(family() :: a_function()).
+-opaque(ordset() :: #?ORDTAG{}).
+-type(relation() :: a_set()).
+-opaque(a_set() :: #?TAG{}).
+-type(set_of_sets() :: a_set()).
+-type(set_fun() :: pos_integer()
+ | {external, fun((external_set()) -> external_set())}
+ | fun((anyset()) -> anyset())).
+-type(spec_fun() :: {external, fun((external_set()) -> boolean())}
+ | fun((anyset()) -> boolean())).
+-type(type() :: term()).
+
+-type(tuple_of(_T) :: tuple()).
+
+%%
+%% Exported functions
+%%
+
+%%%
+%%% Create sets
+%%%
+
+-spec(from_term(Term) -> AnySet when
+ AnySet :: anyset(),
+ Term :: term()).
+from_term(T) ->
+ Type = case T of
+ _ when is_list(T) -> [?ANYTYPE];
+ _ -> ?ANYTYPE
+ end,
+ try setify(T, Type)
+ catch _:_ -> erlang:error(badarg)
+ end.
+
+-spec(from_term(Term, Type) -> AnySet when
+ AnySet :: anyset(),
+ Term :: term(),
+ Type :: type()).
+from_term(L, T) ->
+ case is_type(T) of
+ true ->
+ try setify(L, T)
+ catch _:_ -> erlang:error(badarg)
+ end;
+ false ->
+ erlang:error(badarg)
+ end.
+
+-spec(from_external(ExternalSet, Type) -> AnySet when
+ ExternalSet :: external_set(),
+ AnySet :: anyset(),
+ Type :: type()).
+from_external(L, ?SET_OF(Type)) ->
+ ?SET(L, Type);
+from_external(T, Type) ->
+ ?ORDSET(T, Type).
+
+-spec(empty_set() -> Set when
+ Set :: a_set()).
+empty_set() ->
+ ?SET([], ?ANYTYPE).
+
+-spec(is_type(Term) -> Bool when
+ Bool :: boolean(),
+ Term :: term()).
+is_type(Atom) when ?IS_ATOM_TYPE(Atom), Atom =/= ?ANYTYPE ->
+ true;
+is_type(?SET_OF(T)) ->
+ is_element_type(T);
+is_type(T) when tuple_size(T) > 0 ->
+ is_types(tuple_size(T), T);
+is_type(_T) ->
+ false.
+
+-spec(set(Terms) -> Set when
+ Set :: a_set(),
+ Terms :: [term()]).
+set(L) ->
+ try usort(L) of
+ SL -> ?SET(SL, ?ATOM_TYPE)
+ catch _:_ -> erlang:error(badarg)
+ end.
+
+-spec(set(Terms, Type) -> Set when
+ Set :: a_set(),
+ Terms :: [term()],
+ Type :: type()).
+set(L, ?SET_OF(Type)) when ?IS_ATOM_TYPE(Type), Type =/= ?ANYTYPE ->
+ try usort(L) of
+ SL -> ?SET(SL, Type)
+ catch _:_ -> erlang:error(badarg)
+ end;
+set(L, ?SET_OF(_) = T) ->
+ try setify(L, T)
+ catch _:_ -> erlang:error(badarg)
+ end;
+set(_, _) ->
+ erlang:error(badarg).
+
+-spec(from_sets(ListOfSets) -> Set when
+ Set :: a_set(),
+ ListOfSets :: [anyset()];
+ (TupleOfSets) -> Ordset when
+ Ordset :: ordset(),
+ TupleOfSets :: tuple_of(anyset())).
+from_sets(Ss) when is_list(Ss) ->
+ case set_of_sets(Ss, [], ?ANYTYPE) of
+ {error, Error} ->
+ erlang:error(Error);
+ Set ->
+ Set
+ end;
+from_sets(Tuple) when is_tuple(Tuple) ->
+ case ordset_of_sets(tuple_to_list(Tuple), [], []) of
+ error ->
+ erlang:error(badarg);
+ Set ->
+ Set
+ end;
+from_sets(_) ->
+ erlang:error(badarg).
+
+-spec(relation(Tuples) -> Relation when
+ Relation :: relation(),
+ Tuples :: [tuple()]).
+relation([]) ->
+ ?SET([], ?BINREL(?ATOM_TYPE, ?ATOM_TYPE));
+relation(Ts = [T | _]) when is_tuple(T) ->
+ try rel(Ts, tuple_size(T))
+ catch _:_ -> erlang:error(badarg)
+ end;
+relation(_) ->
+ erlang:error(badarg).
+
+-spec(relation(Tuples, Type) -> Relation when
+ N :: integer(),
+ Type :: N | type(),
+ Relation :: relation(),
+ Tuples :: [tuple()]).
+relation(Ts, TS) ->
+ try rel(Ts, TS)
+ catch _:_ -> erlang:error(badarg)
+ end.
+
+-spec(a_function(Tuples) -> Function when
+ Function :: a_function(),
+ Tuples :: [tuple()]).
+a_function(Ts) ->
+ try func(Ts, ?BINREL(?ATOM_TYPE, ?ATOM_TYPE)) of
+ Bad when is_atom(Bad) ->
+ erlang:error(Bad);
+ Set ->
+ Set
+ catch _:_ -> erlang:error(badarg)
+ end.
+
+-spec(a_function(Tuples, Type) -> Function when
+ Function :: a_function(),
+ Tuples :: [tuple()],
+ Type :: type()).
+a_function(Ts, T) ->
+ try a_func(Ts, T) of
+ Bad when is_atom(Bad) ->
+ erlang:error(Bad);
+ Set ->
+ Set
+ catch _:_ -> erlang:error(badarg)
+ end.
+
+-spec(family(Tuples) -> Family when
+ Family :: family(),
+ Tuples :: [tuple()]).
+family(Ts) ->
+ try fam2(Ts, ?FAMILY(?ATOM_TYPE, ?ATOM_TYPE)) of
+ Bad when is_atom(Bad) ->
+ erlang:error(Bad);
+ Set ->
+ Set
+ catch _:_ -> erlang:error(badarg)
+ end.
+
+-spec(family(Tuples, Type) -> Family when
+ Family :: family(),
+ Tuples :: [tuple()],
+ Type :: type()).
+family(Ts, T) ->
+ try fam(Ts, T) of
+ Bad when is_atom(Bad) ->
+ erlang:error(Bad);
+ Set ->
+ Set
+ catch _:_ -> erlang:error(badarg)
+ end.
+
+%%%
+%%% Functions on sets.
+%%%
+
+-spec(to_external(AnySet) -> ExternalSet when
+ ExternalSet :: external_set(),
+ AnySet :: anyset()).
+to_external(S) when ?IS_SET(S) ->
+ ?LIST(S);
+to_external(S) when ?IS_ORDSET(S) ->
+ ?ORDDATA(S).
+
+-spec(type(AnySet) -> Type when
+ AnySet :: anyset(),
+ Type :: type()).
+type(S) when ?IS_SET(S) ->
+ ?SET_OF(?TYPE(S));
+type(S) when ?IS_ORDSET(S) ->
+ ?ORDTYPE(S).
+
+-spec(to_sets(ASet) -> Sets when
+ ASet :: a_set() | ordset(),
+ Sets :: tuple_of(AnySet) | [AnySet],
+ AnySet :: anyset()).
+to_sets(S) when ?IS_SET(S) ->
+ case ?TYPE(S) of
+ ?SET_OF(Type) -> list_of_sets(?LIST(S), Type, []);
+ Type -> list_of_ordsets(?LIST(S), Type, [])
+ end;
+to_sets(S) when ?IS_ORDSET(S), is_tuple(?ORDTYPE(S)) ->
+ tuple_of_sets(tuple_to_list(?ORDDATA(S)), tuple_to_list(?ORDTYPE(S)), []);
+to_sets(S) when ?IS_ORDSET(S) ->
+ erlang:error(badarg).
+
+-spec(no_elements(ASet) -> NoElements when
+ ASet :: a_set() | ordset(),
+ NoElements :: non_neg_integer()).
+no_elements(S) when ?IS_SET(S) ->
+ length(?LIST(S));
+no_elements(S) when ?IS_ORDSET(S), is_tuple(?ORDTYPE(S)) ->
+ tuple_size(?ORDDATA(S));
+no_elements(S) when ?IS_ORDSET(S) ->
+ erlang:error(badarg).
+
+-spec(specification(Fun, Set1) -> Set2 when
+ Fun :: spec_fun(),
+ Set1 :: a_set(),
+ Set2 :: a_set()).
+specification(Fun, S) when ?IS_SET(S) ->
+ Type = ?TYPE(S),
+ R = case external_fun(Fun) of
+ false ->
+ spec(?LIST(S), Fun, element_type(Type), []);
+ XFun ->
+ specification(?LIST(S), XFun, [])
+ end,
+ case R of
+ SL when is_list(SL) ->
+ ?SET(SL, Type);
+ Bad ->
+ erlang:error(Bad)
+ end.
+
+-spec(union(Set1, Set2) -> Set3 when
+ Set1 :: a_set(),
+ Set2 :: a_set(),
+ Set3 :: a_set()).
+union(S1, S2) when ?IS_SET(S1), ?IS_SET(S2) ->
+ case unify_types(?TYPE(S1), ?TYPE(S2)) of
+ [] -> erlang:error(type_mismatch);
+ Type -> ?SET(umerge(?LIST(S1), ?LIST(S2)), Type)
+ end.
+
+-spec(intersection(Set1, Set2) -> Set3 when
+ Set1 :: a_set(),
+ Set2 :: a_set(),
+ Set3 :: a_set()).
+intersection(S1, S2) when ?IS_SET(S1), ?IS_SET(S2) ->
+ case unify_types(?TYPE(S1), ?TYPE(S2)) of
+ [] -> erlang:error(type_mismatch);
+ Type -> ?SET(intersection(?LIST(S1), ?LIST(S2), []), Type)
+ end.
+
+-spec(difference(Set1, Set2) -> Set3 when
+ Set1 :: a_set(),
+ Set2 :: a_set(),
+ Set3 :: a_set()).
+difference(S1, S2) when ?IS_SET(S1), ?IS_SET(S2) ->
+ case unify_types(?TYPE(S1), ?TYPE(S2)) of
+ [] -> erlang:error(type_mismatch);
+ Type -> ?SET(difference(?LIST(S1), ?LIST(S2), []), Type)
+ end.
+
+-spec(symdiff(Set1, Set2) -> Set3 when
+ Set1 :: a_set(),
+ Set2 :: a_set(),
+ Set3 :: a_set()).
+symdiff(S1, S2) when ?IS_SET(S1), ?IS_SET(S2) ->
+ case unify_types(?TYPE(S1), ?TYPE(S2)) of
+ [] -> erlang:error(type_mismatch);
+ Type -> ?SET(symdiff(?LIST(S1), ?LIST(S2), []), Type)
+ end.
+
+-spec(symmetric_partition(Set1, Set2) -> {Set3, Set4, Set5} when
+ Set1 :: a_set(),
+ Set2 :: a_set(),
+ Set3 :: a_set(),
+ Set4 :: a_set(),
+ Set5 :: a_set()).
+symmetric_partition(S1, S2) when ?IS_SET(S1), ?IS_SET(S2) ->
+ case unify_types(?TYPE(S1), ?TYPE(S2)) of
+ [] -> erlang:error(type_mismatch);
+ Type -> sympart(?LIST(S1), ?LIST(S2), [], [], [], Type)
+ end.
+
+-spec(product(Set1, Set2) -> BinRel when
+ BinRel :: binary_relation(),
+ Set1 :: a_set(),
+ Set2 :: a_set()).
+product(S1, S2) when ?IS_SET(S1), ?IS_SET(S2) ->
+ if
+ ?TYPE(S1) =:= ?ANYTYPE -> S1;
+ ?TYPE(S2) =:= ?ANYTYPE -> S2;
+ true ->
+ F = fun(E) -> {0, E} end,
+ T = ?BINREL(?TYPE(S1), ?TYPE(S2)),
+ ?SET(relprod(map(F, ?LIST(S1)), map(F, ?LIST(S2))), T)
+ end.
+
+-spec(product(TupleOfSets) -> Relation when
+ Relation :: relation(),
+ TupleOfSets :: tuple_of(a_set())).
+product({S1, S2}) ->
+ product(S1, S2);
+product(T) when is_tuple(T) ->
+ Ss = tuple_to_list(T),
+ try sets_to_list(Ss) of
+ [] ->
+ erlang:error(badarg);
+ L ->
+ Type = types(Ss, []),
+ case member([], L) of
+ true ->
+ empty_set();
+ false ->
+ ?SET(reverse(prod(L, [], [])), Type)
+ end
+ catch _:_ -> erlang:error(badarg)
+ end.
+
+-spec(constant_function(Set, AnySet) -> Function when
+ AnySet :: anyset(),
+ Function :: a_function(),
+ Set :: a_set()).
+constant_function(S, E) when ?IS_SET(S) ->
+ case {?TYPE(S), is_sofs_set(E)} of
+ {?ANYTYPE, true} -> S;
+ {Type, true} ->
+ NType = ?BINREL(Type, type(E)),
+ ?SET(constant_function(?LIST(S), to_external(E), []), NType);
+ _ -> erlang:error(badarg)
+ end;
+constant_function(S, _) when ?IS_ORDSET(S) ->
+ erlang:error(badarg).
+
+-spec(is_equal(AnySet1, AnySet2) -> Bool when
+ AnySet1 :: anyset(),
+ AnySet2 :: anyset(),
+ Bool :: boolean()).
+is_equal(S1, S2) when ?IS_SET(S1), ?IS_SET(S2) ->
+ case match_types(?TYPE(S1), ?TYPE(S2)) of
+ true -> ?LIST(S1) == ?LIST(S2);
+ false -> erlang:error(type_mismatch)
+ end;
+is_equal(S1, S2) when ?IS_ORDSET(S1), ?IS_ORDSET(S2) ->
+ case match_types(?ORDTYPE(S1), ?ORDTYPE(S2)) of
+ true -> ?ORDDATA(S1) == ?ORDDATA(S2);
+ false -> erlang:error(type_mismatch)
+ end;
+is_equal(S1, S2) when ?IS_SET(S1), ?IS_ORDSET(S2) ->
+ erlang:error(type_mismatch);
+is_equal(S1, S2) when ?IS_ORDSET(S1), ?IS_SET(S2) ->
+ erlang:error(type_mismatch).
+
+-spec(is_subset(Set1, Set2) -> Bool when
+ Bool :: boolean(),
+ Set1 :: a_set(),
+ Set2 :: a_set()).
+is_subset(S1, S2) when ?IS_SET(S1), ?IS_SET(S2) ->
+ case match_types(?TYPE(S1), ?TYPE(S2)) of
+ true -> subset(?LIST(S1), ?LIST(S2));
+ false -> erlang:error(type_mismatch)
+ end.
+
+-spec(is_sofs_set(Term) -> Bool when
+ Bool :: boolean(),
+ Term :: term()).
+is_sofs_set(S) when ?IS_SET(S) ->
+ true;
+is_sofs_set(S) when ?IS_ORDSET(S) ->
+ true;
+is_sofs_set(_S) ->
+ false.
+
+-spec(is_set(AnySet) -> Bool when
+ AnySet :: anyset(),
+ Bool :: boolean()).
+is_set(S) when ?IS_SET(S) ->
+ true;
+is_set(S) when ?IS_ORDSET(S) ->
+ false.
+
+-spec(is_empty_set(AnySet) -> Bool when
+ AnySet :: anyset(),
+ Bool :: boolean()).
+is_empty_set(S) when ?IS_SET(S) ->
+ ?LIST(S) =:= [];
+is_empty_set(S) when ?IS_ORDSET(S) ->
+ false.
+
+-spec(is_disjoint(Set1, Set2) -> Bool when
+ Bool :: boolean(),
+ Set1 :: a_set(),
+ Set2 :: a_set()).
+is_disjoint(S1, S2) when ?IS_SET(S1), ?IS_SET(S2) ->
+ case match_types(?TYPE(S1), ?TYPE(S2)) of
+ true ->
+ case ?LIST(S1) of
+ [] -> true;
+ [A | As] -> disjoint(?LIST(S2), A, As)
+ end;
+ false -> erlang:error(type_mismatch)
+ end.
+
+%%%
+%%% Functions on set-of-sets.
+%%%
+
+-spec(union(SetOfSets) -> Set when
+ Set :: a_set(),
+ SetOfSets :: set_of_sets()).
+union(Sets) when ?IS_SET(Sets) ->
+ case ?TYPE(Sets) of
+ ?SET_OF(Type) -> ?SET(lunion(?LIST(Sets)), Type);
+ ?ANYTYPE -> Sets;
+ _ -> erlang:error(badarg)
+ end.
+
+-spec(intersection(SetOfSets) -> Set when
+ Set :: a_set(),
+ SetOfSets :: set_of_sets()).
+intersection(Sets) when ?IS_SET(Sets) ->
+ case ?LIST(Sets) of
+ [] -> erlang:error(badarg);
+ [L | Ls] ->
+ case ?TYPE(Sets) of
+ ?SET_OF(Type) ->
+ ?SET(lintersection(Ls, L), Type);
+ _ -> erlang:error(badarg)
+ end
+ end.
+
+-spec(canonical_relation(SetOfSets) -> BinRel when
+ BinRel :: binary_relation(),
+ SetOfSets :: set_of_sets()).
+canonical_relation(Sets) when ?IS_SET(Sets) ->
+ ST = ?TYPE(Sets),
+ case ST of
+ ?SET_OF(?ANYTYPE) -> empty_set();
+ ?SET_OF(Type) ->
+ ?SET(can_rel(?LIST(Sets), []), ?BINREL(Type, ST));
+ ?ANYTYPE -> Sets;
+ _ -> erlang:error(badarg)
+ end.
+
+%%%
+%%% Functions on binary relations only.
+%%%
+
+-spec(rel2fam(BinRel) -> Family when
+ Family :: family(),
+ BinRel :: binary_relation()).
+rel2fam(R) ->
+ relation_to_family(R).
+
+-spec(relation_to_family(BinRel) -> Family when
+ Family :: family(),
+ BinRel :: binary_relation()).
+%% Inlined.
+relation_to_family(R) when ?IS_SET(R) ->
+ case ?TYPE(R) of
+ ?BINREL(DT, RT) ->
+ ?SET(rel2family(?LIST(R)), ?FAMILY(DT, RT));
+ ?ANYTYPE -> R;
+ _Else -> erlang:error(badarg)
+ end.
+
+-spec(domain(BinRel) -> Set when
+ BinRel :: binary_relation(),
+ Set :: a_set()).
+domain(R) when ?IS_SET(R) ->
+ case ?TYPE(R) of
+ ?BINREL(DT, _) -> ?SET(dom(?LIST(R)), DT);
+ ?ANYTYPE -> R;
+ _Else -> erlang:error(badarg)
+ end.
+
+-spec(range(BinRel) -> Set when
+ BinRel :: binary_relation(),
+ Set :: a_set()).
+range(R) when ?IS_SET(R) ->
+ case ?TYPE(R) of
+ ?BINREL(_, RT) -> ?SET(ran(?LIST(R), []), RT);
+ ?ANYTYPE -> R;
+ _ -> erlang:error(badarg)
+ end.
+
+-spec(field(BinRel) -> Set when
+ BinRel :: binary_relation(),
+ Set :: a_set()).
+%% In "Introduction to LOGIC", Suppes defines the field of a binary
+%% relation to be the union of the domain and the range (or
+%% counterdomain).
+field(R) ->
+ union(domain(R), range(R)).
+
+-spec(relative_product(ListOfBinRels) -> BinRel2 when
+ ListOfBinRels :: [BinRel, ...],
+ BinRel :: binary_relation(),
+ BinRel2 :: binary_relation()).
+%% The following clause is kept for backward compatibility.
+%% The list is due to Dialyzer's specs.
+relative_product(RT) when is_tuple(RT) ->
+ relative_product(tuple_to_list(RT));
+relative_product(RL) when is_list(RL) ->
+ case relprod_n(RL, foo, false, false) of
+ {error, Reason} ->
+ erlang:error(Reason);
+ Reply ->
+ Reply
+ end.
+
+-spec(relative_product(ListOfBinRels, BinRel1) -> BinRel2 when
+ ListOfBinRels :: [BinRel, ...],
+ BinRel :: binary_relation(),
+ BinRel1 :: binary_relation(),
+ BinRel2 :: binary_relation();
+ (BinRel1, BinRel2) -> BinRel3 when
+ BinRel1 :: binary_relation(),
+ BinRel2 :: binary_relation(),
+ BinRel3 :: binary_relation()).
+relative_product(R1, R2) when ?IS_SET(R1), ?IS_SET(R2) ->
+ relative_product1(converse(R1), R2);
+%% The following clause is kept for backward compatibility.
+%% The list is due to Dialyzer's specs.
+relative_product(RT, R) when is_tuple(RT), ?IS_SET(R) ->
+ relative_product(tuple_to_list(RT), R);
+relative_product(RL, R) when is_list(RL), ?IS_SET(R) ->
+ EmptyR = case ?TYPE(R) of
+ ?BINREL(_, _) -> ?LIST(R) =:= [];
+ ?ANYTYPE -> true;
+ _ -> erlang:error(badarg)
+ end,
+ case relprod_n(RL, R, EmptyR, true) of
+ {error, Reason} ->
+ erlang:error(Reason);
+ Reply ->
+ Reply
+ end.
+
+-spec(relative_product1(BinRel1, BinRel2) -> BinRel3 when
+ BinRel1 :: binary_relation(),
+ BinRel2 :: binary_relation(),
+ BinRel3 :: binary_relation()).
+relative_product1(R1, R2) when ?IS_SET(R1), ?IS_SET(R2) ->
+ {DTR1, RTR1} = case ?TYPE(R1) of
+ ?BINREL(_, _) = R1T -> R1T;
+ ?ANYTYPE -> {?ANYTYPE, ?ANYTYPE};
+ _ -> erlang:error(badarg)
+ end,
+ {DTR2, RTR2} = case ?TYPE(R2) of
+ ?BINREL(_, _) = R2T -> R2T;
+ ?ANYTYPE -> {?ANYTYPE, ?ANYTYPE};
+ _ -> erlang:error(badarg)
+ end,
+ case match_types(DTR1, DTR2) of
+ true when DTR1 =:= ?ANYTYPE -> R1;
+ true when DTR2 =:= ?ANYTYPE -> R2;
+ true -> ?SET(relprod(?LIST(R1), ?LIST(R2)), ?BINREL(RTR1, RTR2));
+ false -> erlang:error(type_mismatch)
+ end.
+
+-spec(converse(BinRel1) -> BinRel2 when
+ BinRel1 :: binary_relation(),
+ BinRel2 :: binary_relation()).
+converse(R) when ?IS_SET(R) ->
+ case ?TYPE(R) of
+ ?BINREL(DT, RT) -> ?SET(converse(?LIST(R), []), ?BINREL(RT, DT));
+ ?ANYTYPE -> R;
+ _ -> erlang:error(badarg)
+ end.
+
+-spec(image(BinRel, Set1) -> Set2 when
+ BinRel :: binary_relation(),
+ Set1 :: a_set(),
+ Set2 :: a_set()).
+image(R, S) when ?IS_SET(R), ?IS_SET(S) ->
+ case ?TYPE(R) of
+ ?BINREL(DT, RT) ->
+ case match_types(DT, ?TYPE(S)) of
+ true ->
+ ?SET(usort(restrict(?LIST(S), ?LIST(R))), RT);
+ false ->
+ erlang:error(type_mismatch)
+ end;
+ ?ANYTYPE -> R;
+ _ -> erlang:error(badarg)
+ end.
+
+-spec(inverse_image(BinRel, Set1) -> Set2 when
+ BinRel :: binary_relation(),
+ Set1 :: a_set(),
+ Set2 :: a_set()).
+inverse_image(R, S) when ?IS_SET(R), ?IS_SET(S) ->
+ case ?TYPE(R) of
+ ?BINREL(DT, RT) ->
+ case match_types(RT, ?TYPE(S)) of
+ true ->
+ NL = restrict(?LIST(S), converse(?LIST(R), [])),
+ ?SET(usort(NL), DT);
+ false ->
+ erlang:error(type_mismatch)
+ end;
+ ?ANYTYPE -> R;
+ _ -> erlang:error(badarg)
+ end.
+
+-spec(strict_relation(BinRel1) -> BinRel2 when
+ BinRel1 :: binary_relation(),
+ BinRel2 :: binary_relation()).
+strict_relation(R) when ?IS_SET(R) ->
+ case ?TYPE(R) of
+ Type = ?BINREL(_, _) ->
+ ?SET(strict(?LIST(R), []), Type);
+ ?ANYTYPE -> R;
+ _ -> erlang:error(badarg)
+ end.
+
+-spec(weak_relation(BinRel1) -> BinRel2 when
+ BinRel1 :: binary_relation(),
+ BinRel2 :: binary_relation()).
+weak_relation(R) when ?IS_SET(R) ->
+ case ?TYPE(R) of
+ ?BINREL(DT, RT) ->
+ case unify_types(DT, RT) of
+ [] ->
+ erlang:error(badarg);
+ Type ->
+ ?SET(weak(?LIST(R)), ?BINREL(Type, Type))
+ end;
+ ?ANYTYPE -> R;
+ _ -> erlang:error(badarg)
+ end.
+
+-spec(extension(BinRel1, Set, AnySet) -> BinRel2 when
+ AnySet :: anyset(),
+ BinRel1 :: binary_relation(),
+ BinRel2 :: binary_relation(),
+ Set :: a_set()).
+extension(R, S, E) when ?IS_SET(R), ?IS_SET(S) ->
+ case {?TYPE(R), ?TYPE(S), is_sofs_set(E)} of
+ {T=?BINREL(DT, RT), ST, true} ->
+ case match_types(DT, ST) and match_types(RT, type(E)) of
+ false ->
+ erlang:error(type_mismatch);
+ true ->
+ RL = ?LIST(R),
+ case extc([], ?LIST(S), to_external(E), RL) of
+ [] ->
+ R;
+ L ->
+ ?SET(merge(RL, reverse(L)), T)
+ end
+ end;
+ {?ANYTYPE, ?ANYTYPE, true} ->
+ R;
+ {?ANYTYPE, ST, true} ->
+ case type(E) of
+ ?SET_OF(?ANYTYPE) ->
+ R;
+ ET ->
+ ?SET([], ?BINREL(ST, ET))
+ end;
+ {_, _, true} ->
+ erlang:error(badarg)
+ end.
+
+-spec(is_a_function(BinRel) -> Bool when
+ Bool :: boolean(),
+ BinRel :: binary_relation()).
+is_a_function(R) when ?IS_SET(R) ->
+ case ?TYPE(R) of
+ ?BINREL(_, _) ->
+ case ?LIST(R) of
+ [] -> true;
+ [{V,_} | Es] -> is_a_func(Es, V)
+ end;
+ ?ANYTYPE -> true;
+ _ -> erlang:error(badarg)
+ end.
+
+-spec(restriction(BinRel1, Set) -> BinRel2 when
+ BinRel1 :: binary_relation(),
+ BinRel2 :: binary_relation(),
+ Set :: a_set()).
+restriction(Relation, Set) ->
+ restriction(1, Relation, Set).
+
+-spec(drestriction(BinRel1, Set) -> BinRel2 when
+ BinRel1 :: binary_relation(),
+ BinRel2 :: binary_relation(),
+ Set :: a_set()).
+drestriction(Relation, Set) ->
+ drestriction(1, Relation, Set).
+
+%%%
+%%% Functions on functions only.
+%%%
+
+-spec(composite(Function1, Function2) -> Function3 when
+ Function1 :: a_function(),
+ Function2 :: a_function(),
+ Function3 :: a_function()).
+composite(Fn1, Fn2) when ?IS_SET(Fn1), ?IS_SET(Fn2) ->
+ ?BINREL(DTF1, RTF1) = case ?TYPE(Fn1)of
+ ?BINREL(_, _) = F1T -> F1T;
+ ?ANYTYPE -> {?ANYTYPE, ?ANYTYPE};
+ _ -> erlang:error(badarg)
+ end,
+ ?BINREL(DTF2, RTF2) = case ?TYPE(Fn2) of
+ ?BINREL(_, _) = F2T -> F2T;
+ ?ANYTYPE -> {?ANYTYPE, ?ANYTYPE};
+ _ -> erlang:error(badarg)
+ end,
+ case match_types(RTF1, DTF2) of
+ true when DTF1 =:= ?ANYTYPE -> Fn1;
+ true when DTF2 =:= ?ANYTYPE -> Fn2;
+ true ->
+ case comp(?LIST(Fn1), ?LIST(Fn2)) of
+ SL when is_list(SL) ->
+ ?SET(sort(SL), ?BINREL(DTF1, RTF2));
+ Bad ->
+ erlang:error(Bad)
+ end;
+ false -> erlang:error(type_mismatch)
+ end.
+
+-spec(inverse(Function1) -> Function2 when
+ Function1 :: a_function(),
+ Function2 :: a_function()).
+inverse(Fn) when ?IS_SET(Fn) ->
+ case ?TYPE(Fn) of
+ ?BINREL(DT, RT) ->
+ case inverse1(?LIST(Fn)) of
+ SL when is_list(SL) ->
+ ?SET(SL, ?BINREL(RT, DT));
+ Bad ->
+ erlang:error(Bad)
+ end;
+ ?ANYTYPE -> Fn;
+ _ -> erlang:error(badarg)
+ end.
+
+%%%
+%%% Functions on relations (binary or other).
+%%%
+
+-spec(restriction(SetFun, Set1, Set2) -> Set3 when
+ SetFun :: set_fun(),
+ Set1 :: a_set(),
+ Set2 :: a_set(),
+ Set3 :: a_set()).
+%% Equivalent to range(restriction(inverse(substitution(Fun, S1)), S2)).
+restriction(I, R, S) when is_integer(I), ?IS_SET(R), ?IS_SET(S) ->
+ RT = ?TYPE(R),
+ ST = ?TYPE(S),
+ case check_for_sort(RT, I) of
+ empty ->
+ R;
+ error ->
+ erlang:error(badarg);
+ Sort ->
+ RL = ?LIST(R),
+ case {match_types(?REL_TYPE(I, RT), ST), ?LIST(S)} of
+ {true, _SL} when RL =:= [] ->
+ R;
+ {true, []} ->
+ ?SET([], RT);
+ {true, [E | Es]} when Sort =:= false -> % I =:= 1
+ ?SET(reverse(restrict_n(I, RL, E, Es, [])), RT);
+ {true, [E | Es]} ->
+ ?SET(sort(restrict_n(I, keysort(I, RL), E, Es, [])), RT);
+ {false, _SL} ->
+ erlang:error(type_mismatch)
+ end
+ end;
+restriction(SetFun, S1, S2) when ?IS_SET(S1), ?IS_SET(S2) ->
+ Type1 = ?TYPE(S1),
+ Type2 = ?TYPE(S2),
+ SL1 = ?LIST(S1),
+ case external_fun(SetFun) of
+ false when Type2 =:= ?ANYTYPE ->
+ S2;
+ false ->
+ case subst(SL1, SetFun, element_type(Type1)) of
+ {NSL, NewType} -> % NewType can be ?ANYTYPE
+ case match_types(NewType, Type2) of
+ true ->
+ NL = sort(restrict(?LIST(S2), converse(NSL, []))),
+ ?SET(NL, Type1);
+ false ->
+ erlang:error(type_mismatch)
+ end;
+ Bad ->
+ erlang:error(Bad)
+ end;
+ _ when Type1 =:= ?ANYTYPE ->
+ S1;
+ _XFun when ?IS_SET_OF(Type1) ->
+ erlang:error(badarg);
+ XFun ->
+ FunT = XFun(Type1),
+ try check_fun(Type1, XFun, FunT) of
+ Sort ->
+ case match_types(FunT, Type2) of
+ true ->
+ R1 = inverse_substitution(SL1, XFun, Sort),
+ ?SET(sort(Sort, restrict(?LIST(S2), R1)), Type1);
+ false ->
+ erlang:error(type_mismatch)
+ end
+ catch _:_ -> erlang:error(badarg)
+ end
+ end.
+
+-spec(drestriction(SetFun, Set1, Set2) -> Set3 when
+ SetFun :: set_fun(),
+ Set1 :: a_set(),
+ Set2 :: a_set(),
+ Set3 :: a_set()).
+drestriction(I, R, S) when is_integer(I), ?IS_SET(R), ?IS_SET(S) ->
+ RT = ?TYPE(R),
+ ST = ?TYPE(S),
+ case check_for_sort(RT, I) of
+ empty ->
+ R;
+ error ->
+ erlang:error(badarg);
+ Sort ->
+ RL = ?LIST(R),
+ case {match_types(?REL_TYPE(I, RT), ST), ?LIST(S)} of
+ {true, []} ->
+ R;
+ {true, _SL} when RL =:= [] ->
+ R;
+ {true, [E | Es]} when Sort =:= false -> % I =:= 1
+ ?SET(diff_restrict_n(I, RL, E, Es, []), RT);
+ {true, [E | Es]} ->
+ ?SET(diff_restrict_n(I, keysort(I, RL), E, Es, []), RT);
+ {false, _SL} ->
+ erlang:error(type_mismatch)
+ end
+ end;
+drestriction(SetFun, S1, S2) when ?IS_SET(S1), ?IS_SET(S2) ->
+ Type1 = ?TYPE(S1),
+ Type2 = ?TYPE(S2),
+ SL1 = ?LIST(S1),
+ case external_fun(SetFun) of
+ false when Type2 =:= ?ANYTYPE ->
+ S1;
+ false ->
+ case subst(SL1, SetFun, element_type(Type1)) of
+ {NSL, NewType} -> % NewType can be ?ANYTYPE
+ case match_types(NewType, Type2) of
+ true ->
+ SL2 = ?LIST(S2),
+ NL = sort(diff_restrict(SL2, converse(NSL, []))),
+ ?SET(NL, Type1);
+ false ->
+ erlang:error(type_mismatch)
+ end;
+ Bad ->
+ erlang:error(Bad)
+ end;
+ _ when Type1 =:= ?ANYTYPE ->
+ S1;
+ _XFun when ?IS_SET_OF(Type1) ->
+ erlang:error(badarg);
+ XFun ->
+ FunT = XFun(Type1),
+ try check_fun(Type1, XFun, FunT) of
+ Sort ->
+ case match_types(FunT, Type2) of
+ true ->
+ R1 = inverse_substitution(SL1, XFun, Sort),
+ SL2 = ?LIST(S2),
+ ?SET(sort(Sort, diff_restrict(SL2, R1)), Type1);
+ false ->
+ erlang:error(type_mismatch)
+ end
+ catch _:_ -> erlang:error(badarg)
+ end
+ end.
+
+-spec(projection(SetFun, Set1) -> Set2 when
+ SetFun :: set_fun(),
+ Set1 :: a_set(),
+ Set2 :: a_set()).
+projection(I, Set) when is_integer(I), ?IS_SET(Set) ->
+ Type = ?TYPE(Set),
+ case check_for_sort(Type, I) of
+ empty ->
+ Set;
+ error ->
+ erlang:error(badarg);
+ _ when I =:= 1 ->
+ ?SET(projection1(?LIST(Set)), ?REL_TYPE(I, Type));
+ _ ->
+ ?SET(projection_n(?LIST(Set), I, []), ?REL_TYPE(I, Type))
+ end;
+projection(Fun, Set) ->
+ range(substitution(Fun, Set)).
+
+-spec(substitution(SetFun, Set1) -> Set2 when
+ SetFun :: set_fun(),
+ Set1 :: a_set(),
+ Set2 :: a_set()).
+substitution(I, Set) when is_integer(I), ?IS_SET(Set) ->
+ Type = ?TYPE(Set),
+ case check_for_sort(Type, I) of
+ empty ->
+ Set;
+ error ->
+ erlang:error(badarg);
+ _Sort ->
+ NType = ?REL_TYPE(I, Type),
+ NSL = substitute_element(?LIST(Set), I, []),
+ ?SET(NSL, ?BINREL(Type, NType))
+ end;
+substitution(SetFun, Set) when ?IS_SET(Set) ->
+ Type = ?TYPE(Set),
+ L = ?LIST(Set),
+ case external_fun(SetFun) of
+ false when L =/= [] ->
+ case subst(L, SetFun, element_type(Type)) of
+ {SL, NewType} ->
+ ?SET(reverse(SL), ?BINREL(Type, NewType));
+ Bad ->
+ erlang:error(Bad)
+ end;
+ false ->
+ empty_set();
+ _ when Type =:= ?ANYTYPE ->
+ empty_set();
+ _XFun when ?IS_SET_OF(Type) ->
+ erlang:error(badarg);
+ XFun ->
+ FunT = XFun(Type),
+ try check_fun(Type, XFun, FunT) of
+ _Sort ->
+ SL = substitute(L, XFun, []),
+ ?SET(SL, ?BINREL(Type, FunT))
+ catch _:_ -> erlang:error(badarg)
+ end
+ end.
+
+-spec(partition(SetOfSets) -> Partition when
+ SetOfSets :: set_of_sets(),
+ Partition :: a_set()).
+partition(Sets) ->
+ F1 = relation_to_family(canonical_relation(Sets)),
+ F2 = relation_to_family(converse(F1)),
+ range(F2).
+
+-spec(partition(SetFun, Set) -> Partition when
+ SetFun :: set_fun(),
+ Partition :: a_set(),
+ Set :: a_set()).
+partition(I, Set) when is_integer(I), ?IS_SET(Set) ->
+ Type = ?TYPE(Set),
+ case check_for_sort(Type, I) of
+ empty ->
+ Set;
+ error ->
+ erlang:error(badarg);
+ false -> % I =:= 1
+ ?SET(partition_n(I, ?LIST(Set)), ?SET_OF(Type));
+ true ->
+ ?SET(partition_n(I, keysort(I, ?LIST(Set))), ?SET_OF(Type))
+ end;
+partition(Fun, Set) ->
+ range(partition_family(Fun, Set)).
+
+-spec(partition(SetFun, Set1, Set2) -> {Set3, Set4} when
+ SetFun :: set_fun(),
+ Set1 :: a_set(),
+ Set2 :: a_set(),
+ Set3 :: a_set(),
+ Set4 :: a_set()).
+partition(I, R, S) when is_integer(I), ?IS_SET(R), ?IS_SET(S) ->
+ RT = ?TYPE(R),
+ ST = ?TYPE(S),
+ case check_for_sort(RT, I) of
+ empty ->
+ {R, R};
+ error ->
+ erlang:error(badarg);
+ Sort ->
+ RL = ?LIST(R),
+ case {match_types(?REL_TYPE(I, RT), ST), ?LIST(S)} of
+ {true, _SL} when RL =:= [] ->
+ {R, R};
+ {true, []} ->
+ {?SET([], RT), R};
+ {true, [E | Es]} when Sort =:= false -> % I =:= 1
+ [L1 | L2] = partition3_n(I, RL, E, Es, [], []),
+ {?SET(L1, RT), ?SET(L2, RT)};
+ {true, [E | Es]} ->
+ [L1 | L2] = partition3_n(I, keysort(I,RL), E, Es, [], []),
+ {?SET(L1, RT), ?SET(L2, RT)};
+ {false, _SL} ->
+ erlang:error(type_mismatch)
+ end
+ end;
+partition(SetFun, S1, S2) when ?IS_SET(S1), ?IS_SET(S2) ->
+ Type1 = ?TYPE(S1),
+ Type2 = ?TYPE(S2),
+ SL1 = ?LIST(S1),
+ case external_fun(SetFun) of
+ false when Type2 =:= ?ANYTYPE ->
+ {S2, S1};
+ false ->
+ case subst(SL1, SetFun, element_type(Type1)) of
+ {NSL, NewType} -> % NewType can be ?ANYTYPE
+ case match_types(NewType, Type2) of
+ true ->
+ R1 = converse(NSL, []),
+ [L1 | L2] = partition3(?LIST(S2), R1),
+ {?SET(sort(L1), Type1), ?SET(sort(L2), Type1)};
+ false ->
+ erlang:error(type_mismatch)
+ end;
+ Bad ->
+ erlang:error(Bad)
+ end;
+ _ when Type1 =:= ?ANYTYPE ->
+ {S1, S1};
+ _XFun when ?IS_SET_OF(Type1) ->
+ erlang:error(badarg);
+ XFun ->
+ FunT = XFun(Type1),
+ try check_fun(Type1, XFun, FunT) of
+ Sort ->
+ case match_types(FunT, Type2) of
+ true ->
+ R1 = inverse_substitution(SL1, XFun, Sort),
+ [L1 | L2] = partition3(?LIST(S2), R1),
+ {?SET(sort(L1), Type1), ?SET(sort(L2), Type1)};
+ false ->
+ erlang:error(type_mismatch)
+ end
+ catch _:_ -> erlang:error(badarg)
+ end
+ end.
+
+-spec(multiple_relative_product(TupleOfBinRels, BinRel1) -> BinRel2 when
+ TupleOfBinRels :: tuple_of(BinRel),
+ BinRel :: binary_relation(),
+ BinRel1 :: binary_relation(),
+ BinRel2 :: binary_relation()).
+multiple_relative_product(T, R) when is_tuple(T), ?IS_SET(R) ->
+ case test_rel(R, tuple_size(T), eq) of
+ true when ?TYPE(R) =:= ?ANYTYPE ->
+ empty_set();
+ true ->
+ MProd = mul_relprod(tuple_to_list(T), 1, R),
+ relative_product(MProd);
+ false ->
+ erlang:error(badarg)
+ end.
+
+-spec(join(Relation1, I, Relation2, J) -> Relation3 when
+ Relation1 :: relation(),
+ Relation2 :: relation(),
+ Relation3 :: relation(),
+ I :: pos_integer(),
+ J :: pos_integer()).
+join(R1, I1, R2, I2)
+ when ?IS_SET(R1), ?IS_SET(R2), is_integer(I1), is_integer(I2) ->
+ case test_rel(R1, I1, lte) and test_rel(R2, I2, lte) of
+ false -> erlang:error(badarg);
+ true when ?TYPE(R1) =:= ?ANYTYPE -> R1;
+ true when ?TYPE(R2) =:= ?ANYTYPE -> R2;
+ true ->
+ L1 = ?LIST(raise_element(R1, I1)),
+ L2 = ?LIST(raise_element(R2, I2)),
+ T = relprod1(L1, L2),
+ F = case (I1 =:= 1) and (I2 =:= 1) of
+ true ->
+ fun({X,Y}) -> join_element(X, Y) end;
+ false ->
+ fun({X,Y}) ->
+ list_to_tuple(join_element(X, Y, I2))
+ end
+ end,
+ ?SET(replace(T, F, []), F({?TYPE(R1), ?TYPE(R2)}))
+ end.
+
+%% Inlined.
+test_rel(R, I, C) ->
+ case ?TYPE(R) of
+ Rel when ?IS_RELATION(Rel), C =:= eq, I =:= ?REL_ARITY(Rel) -> true;
+ Rel when ?IS_RELATION(Rel), C =:= lte, I>=1, I =< ?REL_ARITY(Rel) ->
+ true;
+ ?ANYTYPE -> true;
+ _ -> false
+ end.
+
+%%%
+%%% Family functions
+%%%
+
+-spec(fam2rel(Family) -> BinRel when
+ Family :: family(),
+ BinRel :: binary_relation()).
+fam2rel(F) ->
+ family_to_relation(F).
+
+-spec(family_to_relation(Family) -> BinRel when
+ Family :: family(),
+ BinRel :: binary_relation()).
+%% Inlined.
+family_to_relation(F) when ?IS_SET(F) ->
+ case ?TYPE(F) of
+ ?FAMILY(DT, RT) ->
+ ?SET(family2rel(?LIST(F), []), ?BINREL(DT, RT));
+ ?ANYTYPE -> F;
+ _ -> erlang:error(badarg)
+ end.
+
+-spec(family_specification(Fun, Family1) -> Family2 when
+ Fun :: spec_fun(),
+ Family1 :: family(),
+ Family2 :: family()).
+family_specification(Fun, F) when ?IS_SET(F) ->
+ case ?TYPE(F) of
+ ?FAMILY(_DT, Type) = FType ->
+ R = case external_fun(Fun) of
+ false ->
+ fam_spec(?LIST(F), Fun, Type, []);
+ XFun ->
+ fam_specification(?LIST(F), XFun, [])
+ end,
+ case R of
+ SL when is_list(SL) ->
+ ?SET(SL, FType);
+ Bad ->
+ erlang:error(Bad)
+ end;
+ ?ANYTYPE -> F;
+ _ -> erlang:error(badarg)
+ end.
+
+-spec(union_of_family(Family) -> Set when
+ Family :: family(),
+ Set :: a_set()).
+union_of_family(F) when ?IS_SET(F) ->
+ case ?TYPE(F) of
+ ?FAMILY(_DT, Type) ->
+ ?SET(un_of_fam(?LIST(F), []), Type);
+ ?ANYTYPE -> F;
+ _ -> erlang:error(badarg)
+ end.
+
+-spec(intersection_of_family(Family) -> Set when
+ Family :: family(),
+ Set :: a_set()).
+intersection_of_family(F) when ?IS_SET(F) ->
+ case ?TYPE(F) of
+ ?FAMILY(_DT, Type) ->
+ case int_of_fam(?LIST(F)) of
+ FU when is_list(FU) ->
+ ?SET(FU, Type);
+ Bad ->
+ erlang:error(Bad)
+ end;
+ _ -> erlang:error(badarg)
+ end.
+
+-spec(family_union(Family1) -> Family2 when
+ Family1 :: family(),
+ Family2 :: family()).
+family_union(F) when ?IS_SET(F) ->
+ case ?TYPE(F) of
+ ?FAMILY(DT, ?SET_OF(Type)) ->
+ ?SET(fam_un(?LIST(F), []), ?FAMILY(DT, Type));
+ ?ANYTYPE -> F;
+ _ -> erlang:error(badarg)
+ end.
+
+-spec(family_intersection(Family1) -> Family2 when
+ Family1 :: family(),
+ Family2 :: family()).
+family_intersection(F) when ?IS_SET(F) ->
+ case ?TYPE(F) of
+ ?FAMILY(DT, ?SET_OF(Type)) ->
+ case fam_int(?LIST(F), []) of
+ FU when is_list(FU) ->
+ ?SET(FU, ?FAMILY(DT, Type));
+ Bad ->
+ erlang:error(Bad)
+ end;
+ ?ANYTYPE -> F;
+ _ -> erlang:error(badarg)
+ end.
+
+-spec(family_domain(Family1) -> Family2 when
+ Family1 :: family(),
+ Family2 :: family()).
+family_domain(F) when ?IS_SET(F) ->
+ case ?TYPE(F) of
+ ?FAMILY(FDT, ?BINREL(DT, _)) ->
+ ?SET(fam_dom(?LIST(F), []), ?FAMILY(FDT, DT));
+ ?ANYTYPE -> F;
+ ?FAMILY(_, ?ANYTYPE) -> F;
+ _ -> erlang:error(badarg)
+ end.
+
+-spec(family_range(Family1) -> Family2 when
+ Family1 :: family(),
+ Family2 :: family()).
+family_range(F) when ?IS_SET(F) ->
+ case ?TYPE(F) of
+ ?FAMILY(DT, ?BINREL(_, RT)) ->
+ ?SET(fam_ran(?LIST(F), []), ?FAMILY(DT, RT));
+ ?ANYTYPE -> F;
+ ?FAMILY(_, ?ANYTYPE) -> F;
+ _ -> erlang:error(badarg)
+ end.
+
+-spec(family_field(Family1) -> Family2 when
+ Family1 :: family(),
+ Family2 :: family()).
+family_field(F) ->
+ family_union(family_domain(F), family_range(F)).
+
+-spec(family_union(Family1, Family2) -> Family3 when
+ Family1 :: family(),
+ Family2 :: family(),
+ Family3 :: family()).
+family_union(F1, F2) ->
+ fam_binop(F1, F2, fun fam_union/3).
+
+-spec(family_intersection(Family1, Family2) -> Family3 when
+ Family1 :: family(),
+ Family2 :: family(),
+ Family3 :: family()).
+family_intersection(F1, F2) ->
+ fam_binop(F1, F2, fun fam_intersect/3).
+
+-spec(family_difference(Family1, Family2) -> Family3 when
+ Family1 :: family(),
+ Family2 :: family(),
+ Family3 :: family()).
+family_difference(F1, F2) ->
+ fam_binop(F1, F2, fun fam_difference/3).
+
+%% Inlined.
+fam_binop(F1, F2, FF) when ?IS_SET(F1), ?IS_SET(F2) ->
+ case unify_types(?TYPE(F1), ?TYPE(F2)) of
+ [] ->
+ erlang:error(type_mismatch);
+ ?ANYTYPE ->
+ F1;
+ Type = ?FAMILY(_, _) ->
+ ?SET(FF(?LIST(F1), ?LIST(F2), []), Type);
+ _ -> erlang:error(badarg)
+ end.
+
+-spec(partition_family(SetFun, Set) -> Family when
+ Family :: family(),
+ SetFun :: set_fun(),
+ Set :: a_set()).
+partition_family(I, Set) when is_integer(I), ?IS_SET(Set) ->
+ Type = ?TYPE(Set),
+ case check_for_sort(Type, I) of
+ empty ->
+ Set;
+ error ->
+ erlang:error(badarg);
+ false -> % when I =:= 1
+ ?SET(fam_partition_n(I, ?LIST(Set)),
+ ?BINREL(?REL_TYPE(I, Type), ?SET_OF(Type)));
+ true ->
+ ?SET(fam_partition_n(I, keysort(I, ?LIST(Set))),
+ ?BINREL(?REL_TYPE(I, Type), ?SET_OF(Type)))
+ end;
+partition_family(SetFun, Set) when ?IS_SET(Set) ->
+ Type = ?TYPE(Set),
+ SL = ?LIST(Set),
+ case external_fun(SetFun) of
+ false when SL =/= [] ->
+ case subst(SL, SetFun, element_type(Type)) of
+ {NSL, NewType} ->
+ P = fam_partition(converse(NSL, []), true),
+ ?SET(reverse(P), ?BINREL(NewType, ?SET_OF(Type)));
+ Bad ->
+ erlang:error(Bad)
+ end;
+ false ->
+ empty_set();
+ _ when Type =:= ?ANYTYPE ->
+ empty_set();
+ _XFun when ?IS_SET_OF(Type) ->
+ erlang:error(badarg);
+ XFun ->
+ DType = XFun(Type),
+ try check_fun(Type, XFun, DType) of
+ Sort ->
+ Ts = inverse_substitution(?LIST(Set), XFun, Sort),
+ P = fam_partition(Ts, Sort),
+ ?SET(reverse(P), ?BINREL(DType, ?SET_OF(Type)))
+ catch _:_ -> erlang:error(badarg)
+ end
+ end.
+
+-spec(family_projection(SetFun, Family1) -> Family2 when
+ SetFun :: set_fun(),
+ Family1 :: family(),
+ Family2 :: family()).
+family_projection(SetFun, F) when ?IS_SET(F) ->
+ case ?TYPE(F) of
+ ?FAMILY(_, _) when [] =:= ?LIST(F) ->
+ empty_set();
+ ?FAMILY(DT, Type) ->
+ case external_fun(SetFun) of
+ false ->
+ case fam_proj(?LIST(F), SetFun, Type, ?ANYTYPE, []) of
+ {SL, NewType} ->
+ ?SET(SL, ?BINREL(DT, NewType));
+ Bad ->
+ erlang:error(Bad)
+ end;
+ _ ->
+ erlang:error(badarg)
+ end;
+ ?ANYTYPE -> F;
+ _ -> erlang:error(badarg)
+ end.
+
+%%%
+%%% Digraph functions
+%%%
+
+-spec(family_to_digraph(Family) -> Graph when
+ Graph :: digraph:graph(),
+ Family :: family()).
+family_to_digraph(F) when ?IS_SET(F) ->
+ case ?TYPE(F) of
+ ?FAMILY(_, _) -> fam2digraph(F, digraph:new());
+ ?ANYTYPE -> digraph:new();
+ _Else -> erlang:error(badarg)
+ end.
+
+-spec(family_to_digraph(Family, GraphType) -> Graph when
+ Graph :: digraph:graph(),
+ Family :: family(),
+ GraphType :: [digraph:d_type()]).
+family_to_digraph(F, Type) when ?IS_SET(F) ->
+ case ?TYPE(F) of
+ ?FAMILY(_, _) -> ok;
+ ?ANYTYPE -> ok;
+ _Else -> erlang:error(badarg)
+ end,
+ try digraph:new(Type) of
+ G -> case catch fam2digraph(F, G) of
+ {error, Reason} ->
+ true = digraph:delete(G),
+ erlang:error(Reason);
+ _ ->
+ G
+ end
+ catch
+ error:badarg -> erlang:error(badarg)
+ end.
+
+-spec(digraph_to_family(Graph) -> Family when
+ Graph :: digraph:graph(),
+ Family :: family()).
+digraph_to_family(G) ->
+ try digraph_family(G) of
+ L -> ?SET(L, ?FAMILY(?ATOM_TYPE, ?ATOM_TYPE))
+ catch _:_ -> erlang:error(badarg)
+ end.
+
+-spec(digraph_to_family(Graph, Type) -> Family when
+ Graph :: digraph:graph(),
+ Family :: family(),
+ Type :: type()).
+digraph_to_family(G, T) ->
+ case {is_type(T), T} of
+ {true, ?SET_OF(?FAMILY(_,_) = Type)} ->
+ try digraph_family(G) of
+ L -> ?SET(L, Type)
+ catch _:_ -> erlang:error(badarg)
+ end;
+ _ ->
+ erlang:error(badarg)
+ end.
+
+%%
+%% Local functions
+%%
+
+%% Type = OrderedSetType
+%% | SetType
+%% | atom() except '_'
+%% OrderedSetType = {Type, ..., Type}
+%% SetType = [ElementType] % list of exactly one element
+%% ElementType = '_' % any type (implies empty set)
+%% | Type
+
+is_types(0, _T) ->
+ true;
+is_types(I, T) ->
+ case is_type(?REL_TYPE(I, T)) of
+ true -> is_types(I-1, T);
+ false -> false
+ end.
+
+is_element_type(?ANYTYPE) ->
+ true;
+is_element_type(T) ->
+ is_type(T).
+
+set_of_sets([S | Ss], L, T0) when ?IS_SET(S) ->
+ case unify_types([?TYPE(S)], T0) of
+ [] -> {error, type_mismatch};
+ Type -> set_of_sets(Ss, [?LIST(S) | L], Type)
+ end;
+set_of_sets([S | Ss], L, T0) when ?IS_ORDSET(S) ->
+ case unify_types(?ORDTYPE(S), T0) of
+ [] -> {error, type_mismatch};
+ Type -> set_of_sets(Ss, [?ORDDATA(S) | L], Type)
+ end;
+set_of_sets([], L, T) ->
+ ?SET(usort(L), T);
+set_of_sets(_, _L, _T) ->
+ {error, badarg}.
+
+ordset_of_sets([S | Ss], L, T) when ?IS_SET(S) ->
+ ordset_of_sets(Ss, [?LIST(S) | L], [[?TYPE(S)] | T]);
+ordset_of_sets([S | Ss], L, T) when ?IS_ORDSET(S) ->
+ ordset_of_sets(Ss, [?ORDDATA(S) | L], [?ORDTYPE(S) | T]);
+ordset_of_sets([], L, T) ->
+ ?ORDSET(list_to_tuple(reverse(L)), list_to_tuple(reverse(T)));
+ordset_of_sets(_, _L, _T) ->
+ error.
+
+%% Inlined.
+rel(Ts, [Type]) ->
+ case is_type(Type) and atoms_only(Type, 1) of
+ true ->
+ rel(Ts, tuple_size(Type), Type);
+ false ->
+ rel_type(Ts, [], Type)
+ end;
+rel(Ts, Sz) ->
+ rel(Ts, Sz, erlang:make_tuple(Sz, ?ATOM_TYPE)).
+
+atoms_only(Type, I) when ?IS_ATOM_TYPE(?REL_TYPE(I, Type)) ->
+ atoms_only(Type, I+1);
+atoms_only(Type, I) when I > tuple_size(Type), ?IS_RELATION(Type) ->
+ true;
+atoms_only(_Type, _I) ->
+ false.
+
+rel(Ts, Sz, Type) when Sz >= 1 ->
+ SL = usort(Ts),
+ rel(SL, SL, Sz, Type).
+
+rel([T | Ts], L, Sz, Type) when tuple_size(T) =:= Sz ->
+ rel(Ts, L, Sz, Type);
+rel([], L, _Sz, Type) ->
+ ?SET(L, Type).
+
+rel_type([E | Ts], L, Type) ->
+ {NType, NE} = make_element(E, Type, Type),
+ rel_type(Ts, [NE | L], NType);
+rel_type([], [], ?ANYTYPE) ->
+ empty_set();
+rel_type([], SL, Type) when ?IS_RELATION(Type) ->
+ ?SET(usort(SL), Type).
+
+%% Inlined.
+a_func(Ts, T) ->
+ case {T, is_type(T)} of
+ {[?BINREL(DT, RT) = Type], true} when ?IS_ATOM_TYPE(DT),
+ ?IS_ATOM_TYPE(RT) ->
+ func(Ts, Type);
+ {[Type], true} ->
+ func_type(Ts, [], Type, fun(?BINREL(_,_)) -> true end)
+ end.
+
+func(L0, Type) ->
+ L = usort(L0),
+ func(L, L, L, Type).
+
+func([{X,_} | Ts], X0, L, Type) when X /= X0 ->
+ func(Ts, X, L, Type);
+func([{X,_} | _Ts], X0, _L, _Type) when X == X0 ->
+ bad_function;
+func([], _X0, L, Type) ->
+ ?SET(L, Type).
+
+%% Inlined.
+fam(Ts, T) ->
+ case {T, is_type(T)} of
+ {[?FAMILY(DT, RT) = Type], true} when ?IS_ATOM_TYPE(DT),
+ ?IS_ATOM_TYPE(RT) ->
+ fam2(Ts, Type);
+ {[Type], true} ->
+ func_type(Ts, [], Type, fun(?FAMILY(_,_)) -> true end)
+ end.
+
+fam2([], Type) ->
+ ?SET([], Type);
+fam2(Ts, Type) ->
+ fam2(sort(Ts), Ts, [], Type).
+
+fam2([{I,L} | T], I0, SL, Type) when I /= I0 ->
+ fam2(T, I, [{I,usort(L)} | SL], Type);
+fam2([{I,L} | T], I0, SL, Type) when I == I0 ->
+ case {usort(L), SL} of
+ {NL, [{_I,NL1} | _]} when NL == NL1 ->
+ fam2(T, I0, SL, Type);
+ _ ->
+ bad_function
+ end;
+fam2([], _I0, SL, Type) ->
+ ?SET(reverse(SL), Type).
+
+func_type([E | T], SL, Type, F) ->
+ {NType, NE} = make_element(E, Type, Type),
+ func_type(T, [NE | SL], NType, F);
+func_type([], [], ?ANYTYPE, _F) ->
+ empty_set();
+func_type([], SL, Type, F) ->
+ true = F(Type),
+ NL = usort(SL),
+ check_function(NL, ?SET(NL, Type)).
+
+setify(L, ?SET_OF(Atom)) when ?IS_ATOM_TYPE(Atom), Atom =/= ?ANYTYPE ->
+ ?SET(usort(L), Atom);
+setify(L, ?SET_OF(Type0)) ->
+ try is_no_lists(Type0) of
+ N when is_integer(N) ->
+ rel(L, N, Type0);
+ Sizes ->
+ make_oset(L, Sizes, L, Type0)
+ catch
+ _:_ ->
+ {?SET_OF(Type), Set} = create(L, Type0, Type0, []),
+ ?SET(Set, Type)
+ end;
+setify(E, Type0) ->
+ {Type, OrdSet} = make_element(E, Type0, Type0),
+ ?ORDSET(OrdSet, Type).
+
+is_no_lists(T) when is_tuple(T) ->
+ Sz = tuple_size(T),
+ is_no_lists(T, Sz, Sz, []).
+
+is_no_lists(_T, 0, Sz, []) ->
+ Sz;
+is_no_lists(_T, 0, Sz, L) ->
+ {Sz, L};
+is_no_lists(T, I, Sz, L) when ?IS_ATOM_TYPE(?REL_TYPE(I, T)) ->
+ is_no_lists(T, I-1, Sz, L);
+is_no_lists(T, I, Sz, L) ->
+ is_no_lists(T, I-1, Sz, [{I,is_no_lists(?REL_TYPE(I, T))} | L]).
+
+create([E | Es], T, T0, L) ->
+ {NT, S} = make_element(E, T, T0),
+ create(Es, NT, T0, [S | L]);
+create([], T, _T0, L) ->
+ {?SET_OF(T), usort(L)}.
+
+make_element(C, ?ANYTYPE, _T0) ->
+ make_element(C);
+make_element(C, Atom, ?ANYTYPE) when ?IS_ATOM_TYPE(Atom),
+ not is_list(C), not is_tuple(C) ->
+ {Atom, C};
+make_element(C, Atom, Atom) when ?IS_ATOM_TYPE(Atom) ->
+ {Atom, C};
+make_element(T, TT, ?ANYTYPE) when tuple_size(T) =:= tuple_size(TT) ->
+ make_tuple(tuple_to_list(T), tuple_to_list(TT), [], [], ?ANYTYPE);
+make_element(T, TT, T0) when tuple_size(T) =:= tuple_size(TT) ->
+ make_tuple(tuple_to_list(T), tuple_to_list(TT), [], [], tuple_to_list(T0));
+make_element(L, [LT], ?ANYTYPE) when is_list(L) ->
+ create(L, LT, ?ANYTYPE, []);
+make_element(L, [LT], [T0]) when is_list(L) ->
+ create(L, LT, T0, []).
+
+make_tuple([E | Es], [T | Ts], NT, L, T0) when T0 =:= ?ANYTYPE ->
+ {ET, ES} = make_element(E, T, T0),
+ make_tuple(Es, Ts, [ET | NT], [ES | L], T0);
+make_tuple([E | Es], [T | Ts], NT, L, [T0 | T0s]) ->
+ {ET, ES} = make_element(E, T, T0),
+ make_tuple(Es, Ts, [ET | NT], [ES | L], T0s);
+make_tuple([], [], NT, L, _T0s) when NT =/= [] ->
+ {list_to_tuple(reverse(NT)), list_to_tuple(reverse(L))}.
+
+%% Derive type.
+make_element(C) when not is_list(C), not is_tuple(C) ->
+ {?ATOM_TYPE, C};
+make_element(T) when is_tuple(T) ->
+ make_tuple(tuple_to_list(T), [], []);
+make_element(L) when is_list(L) ->
+ create(L, ?ANYTYPE, ?ANYTYPE, []).
+
+make_tuple([E | Es], T, L) ->
+ {ET, ES} = make_element(E),
+ make_tuple(Es, [ET | T], [ES | L]);
+make_tuple([], T, L) when T =/= [] ->
+ {list_to_tuple(reverse(T)), list_to_tuple(reverse(L))}.
+
+make_oset([T | Ts], Szs, L, Type) ->
+ true = test_oset(Szs, T, T),
+ make_oset(Ts, Szs, L, Type);
+make_oset([], _Szs, L, Type) ->
+ ?SET(usort(L), Type).
+
+%% Optimization. Avoid re-building (nested) tuples.
+test_oset({Sz,Args}, T, T0) when tuple_size(T) =:= Sz ->
+ test_oset_args(Args, T, T0);
+test_oset(Sz, T, _T0) when tuple_size(T) =:= Sz ->
+ true.
+
+test_oset_args([{Arg,Szs} | Ss], T, T0) ->
+ true = test_oset(Szs, ?REL_TYPE(Arg, T), T0),
+ test_oset_args(Ss, T, T0);
+test_oset_args([], _T, _T0) ->
+ true.
+
+list_of_sets([S | Ss], Type, L) ->
+ list_of_sets(Ss, Type, [?SET(S, Type) | L]);
+list_of_sets([], _Type, L) ->
+ reverse(L).
+
+list_of_ordsets([S | Ss], Type, L) ->
+ list_of_ordsets(Ss, Type, [?ORDSET(S, Type) | L]);
+list_of_ordsets([], _Type, L) ->
+ reverse(L).
+
+tuple_of_sets([S | Ss], [?SET_OF(Type) | Types], L) ->
+ tuple_of_sets(Ss, Types, [?SET(S, Type) | L]);
+tuple_of_sets([S | Ss], [Type | Types], L) ->
+ tuple_of_sets(Ss, Types, [?ORDSET(S, Type) | L]);
+tuple_of_sets([], [], L) ->
+ list_to_tuple(reverse(L)).
+
+spec([E | Es], Fun, Type, L) ->
+ case Fun(term2set(E, Type)) of
+ true ->
+ spec(Es, Fun, Type, [E | L]);
+ false ->
+ spec(Es, Fun, Type, L);
+ _ ->
+ badarg
+ end;
+spec([], _Fun, _Type, L) ->
+ reverse(L).
+
+specification([E | Es], Fun, L) ->
+ case Fun(E) of
+ true ->
+ specification(Es, Fun, [E | L]);
+ false ->
+ specification(Es, Fun, L);
+ _ ->
+ badarg
+ end;
+specification([], _Fun, L) ->
+ reverse(L).
+
+%% Elements from the first list are kept.
+intersection([H1 | T1], [H2 | T2], L) when H1 < H2 ->
+ intersection1(T1, T2, L, H2);
+intersection([H1 | T1], [H2 | T2], L) when H1 == H2 ->
+ intersection(T1, T2, [H1 | L]);
+intersection([H1 | T1], [_H2 | T2], L) ->
+ intersection2(T1, T2, L, H1);
+intersection(_, _, L) ->
+ reverse(L).
+
+intersection1([H1 | T1], T2, L, H2) when H1 < H2 ->
+ intersection1(T1, T2, L, H2);
+intersection1([H1 | T1], T2, L, H2) when H1 == H2 ->
+ intersection(T1, T2, [H1 | L]);
+intersection1([H1 | T1], T2, L, _H2) ->
+ intersection2(T1, T2, L, H1);
+intersection1(_, _, L, _) ->
+ reverse(L).
+
+intersection2(T1, [H2 | T2], L, H1) when H1 > H2 ->
+ intersection2(T1, T2, L, H1);
+intersection2(T1, [H2 | T2], L, H1) when H1 == H2 ->
+ intersection(T1, T2, [H1 | L]);
+intersection2(T1, [H2 | T2], L, _H1) ->
+ intersection1(T1, T2, L, H2);
+intersection2(_, _, L, _) ->
+ reverse(L).
+
+difference([H1 | T1], [H2 | T2], L) when H1 < H2 ->
+ diff(T1, T2, [H1 | L], H2);
+difference([H1 | T1], [H2 | T2], L) when H1 == H2 ->
+ difference(T1, T2, L);
+difference([H1 | T1], [_H2 | T2], L) ->
+ diff2(T1, T2, L, H1);
+difference(L1, _, L) ->
+ reverse(L, L1).
+
+diff([H1 | T1], T2, L, H2) when H1 < H2 ->
+ diff(T1, T2, [H1 | L], H2);
+diff([H1 | T1], T2, L, H2) when H1 == H2 ->
+ difference(T1, T2, L);
+diff([H1 | T1], T2, L, _H2) ->
+ diff2(T1, T2, L, H1);
+diff(_, _, L, _) ->
+ reverse(L).
+
+diff2(T1, [H2 | T2], L, H1) when H1 > H2 ->
+ diff2(T1, T2, L, H1);
+diff2(T1, [H2 | T2], L, H1) when H1 == H2 ->
+ difference(T1, T2, L);
+diff2(T1, [H2 | T2], L, H1) ->
+ diff(T1, T2, [H1 | L], H2);
+diff2(T1, _, L, H1) ->
+ reverse(L, [H1 | T1]).
+
+symdiff([H1 | T1], T2, L) ->
+ symdiff2(T1, T2, L, H1);
+symdiff(_, T2, L) ->
+ reverse(L, T2).
+
+symdiff1([H1 | T1], T2, L, H2) when H1 < H2 ->
+ symdiff1(T1, T2, [H1 | L], H2);
+symdiff1([H1 | T1], T2, L, H2) when H1 == H2 ->
+ symdiff(T1, T2, L);
+symdiff1([H1 | T1], T2, L, H2) ->
+ symdiff2(T1, T2, [H2 | L], H1);
+symdiff1(_, T2, L, H2) ->
+ reverse(L, [H2 | T2]).
+
+symdiff2(T1, [H2 | T2], L, H1) when H1 > H2 ->
+ symdiff2(T1, T2, [H2 | L], H1);
+symdiff2(T1, [H2 | T2], L, H1) when H1 == H2 ->
+ symdiff(T1, T2, L);
+symdiff2(T1, [H2 | T2], L, H1) ->
+ symdiff1(T1, T2, [H1 | L], H2);
+symdiff2(T1, _, L, H1) ->
+ reverse(L, [H1 | T1]).
+
+sympart([H1 | T1], [H2 | T2], L1, L12, L2, T) when H1 < H2 ->
+ sympart1(T1, T2, [H1 | L1], L12, L2, T, H2);
+sympart([H1 | T1], [H2 | T2], L1, L12, L2, T) when H1 == H2 ->
+ sympart(T1, T2, L1, [H1 | L12], L2, T);
+sympart([H1 | T1], [H2 | T2], L1, L12, L2, T) ->
+ sympart2(T1, T2, L1, L12, [H2 | L2], T, H1);
+sympart(S1, [], L1, L12, L2, T) ->
+ {?SET(reverse(L1, S1), T),
+ ?SET(reverse(L12), T),
+ ?SET(reverse(L2), T)};
+sympart(_, S2, L1, L12, L2, T) ->
+ {?SET(reverse(L1), T),
+ ?SET(reverse(L12), T),
+ ?SET(reverse(L2, S2), T)}.
+
+sympart1([H1 | T1], T2, L1, L12, L2, T, H2) when H1 < H2 ->
+ sympart1(T1, T2, [H1 | L1], L12, L2, T, H2);
+sympart1([H1 | T1], T2, L1, L12, L2, T, H2) when H1 == H2 ->
+ sympart(T1, T2, L1, [H1 | L12], L2, T);
+sympart1([H1 | T1], T2, L1, L12, L2, T, H2) ->
+ sympart2(T1, T2, L1, L12, [H2 | L2], T, H1);
+sympart1(_, T2, L1, L12, L2, T, H2) ->
+ {?SET(reverse(L1), T),
+ ?SET(reverse(L12), T),
+ ?SET(reverse(L2, [H2 | T2]), T)}.
+
+sympart2(T1, [H2 | T2], L1, L12, L2, T, H1) when H1 > H2 ->
+ sympart2(T1, T2, L1, L12, [H2 | L2], T, H1);
+sympart2(T1, [H2 | T2], L1, L12, L2, T, H1) when H1 == H2 ->
+ sympart(T1, T2, L1, [H1 | L12], L2, T);
+sympart2(T1, [H2 | T2], L1, L12, L2, T, H1) ->
+ sympart1(T1, T2, [H1 | L1], L12, L2, T, H2);
+sympart2(T1, _, L1, L12, L2, T, H1) ->
+ {?SET(reverse(L1, [H1 | T1]), T),
+ ?SET(reverse(L12), T),
+ ?SET(reverse(L2), T)}.
+
+prod([[E | Es] | Xs], T, L) ->
+ prod(Es, Xs, T, prod(Xs, [E | T], L));
+prod([], T, L) ->
+ [list_to_tuple(reverse(T)) | L].
+
+prod([E | Es], Xs, T, L) ->
+ prod(Es, Xs, T, prod(Xs, [E | T], L));
+prod([], _Xs, _E, L) ->
+ L.
+
+constant_function([E | Es], X, L) ->
+ constant_function(Es, X, [{E,X} | L]);
+constant_function([], _X, L) ->
+ reverse(L).
+
+subset([H1 | T1], [H2 | T2]) when H1 > H2 ->
+ subset(T1, T2, H1);
+subset([H1 | T1], [H2 | T2]) when H1 == H2 ->
+ subset(T1, T2);
+subset(L1, _) ->
+ L1 =:= [].
+
+subset(T1, [H2 | T2], H1) when H1 > H2 ->
+ subset(T1, T2, H1);
+subset(T1, [H2 | T2], H1) when H1 == H2 ->
+ subset(T1, T2);
+subset(_, _, _) ->
+ false.
+
+disjoint([B | Bs], A, As) when A < B ->
+ disjoint(As, B, Bs);
+disjoint([B | _Bs], A, _As) when A == B ->
+ false;
+disjoint([_B | Bs], A, As) ->
+ disjoint(Bs, A, As);
+disjoint(_Bs, _A, _As) ->
+ true.
+
+%% Append sets that come in order, then "merge".
+lunion([[_] = S]) -> % optimization
+ S;
+lunion([[] | Ls]) ->
+ lunion(Ls);
+lunion([S | Ss]) ->
+ umerge(lunion(Ss, last(S), [S], []));
+lunion([]) ->
+ [].
+
+lunion([[E] = S | Ss], Last, SL, Ls) when E > Last -> % optimization
+ lunion(Ss, E, [S | SL], Ls);
+lunion([S | Ss], Last, SL, Ls) when hd(S) > Last ->
+ lunion(Ss, last(S), [S | SL], Ls);
+lunion([S | Ss], _Last, SL, Ls) ->
+ lunion(Ss, last(S), [S], [append(reverse(SL)) | Ls]);
+lunion([], _Last, SL, Ls) ->
+ [append(reverse(SL)) | Ls].
+
+%% The empty list is always the first list, if present.
+lintersection(_, []) ->
+ [];
+lintersection([S | Ss], S0) ->
+ lintersection(Ss, intersection(S, S0, []));
+lintersection([], S) ->
+ S.
+
+can_rel([S | Ss], L) ->
+ can_rel(Ss, L, S, S);
+can_rel([], L) ->
+ sort(L).
+
+can_rel(Ss, L, [E | Es], S) ->
+ can_rel(Ss, [{E, S} | L], Es, S);
+can_rel(Ss, L, _, _S) ->
+ can_rel(Ss, L).
+
+rel2family([{X,Y} | S]) ->
+ rel2fam(S, X, [Y], []);
+rel2family([]) ->
+ [].
+
+rel2fam([{X,Y} | S], X0, YL, L) when X0 == X ->
+ rel2fam(S, X0, [Y | YL], L);
+rel2fam([{X,Y} | S], X0, [A,B | YL], L) -> % optimization
+ rel2fam(S, X, [Y], [{X0,reverse(YL,[B,A])} | L]);
+rel2fam([{X,Y} | S], X0, YL, L) ->
+ rel2fam(S, X, [Y], [{X0,YL} | L]);
+rel2fam([], X, YL, L) ->
+ reverse([{X,reverse(YL)} | L]).
+
+dom([{X,_} | Es]) ->
+ dom([], X, Es);
+dom([] = L) ->
+ L.
+
+dom(L, X, [{X1,_} | Es]) when X == X1 ->
+ dom(L, X, Es);
+dom(L, X, [{Y,_} | Es]) ->
+ dom([X | L], Y, Es);
+dom(L, X, []) ->
+ reverse(L, [X]).
+
+ran([{_,Y} | Es], L) ->
+ ran(Es, [Y | L]);
+ran([], L) ->
+ usort(L).
+
+relprod(A, B) ->
+ usort(relprod1(A, B)).
+
+relprod1([{Ay,Ax} | A], B) ->
+ relprod1(B, Ay, Ax, A, []);
+relprod1(_A, _B) ->
+ [].
+
+relprod1([{Bx,_By} | B], Ay, Ax, A, L) when Ay > Bx ->
+ relprod1(B, Ay, Ax, A, L);
+relprod1([{Bx,By} | B], Ay, Ax, A, L) when Ay == Bx ->
+ relprod(B, Bx, By, A, [{Ax,By} | L], Ax, B, Ay);
+relprod1([{Bx,By} | B], _Ay, _Ax, A, L) ->
+ relprod2(B, Bx, By, A, L);
+relprod1(_B, _Ay, _Ax, _A, L) ->
+ L.
+
+relprod2(B, Bx, By, [{Ay, _Ax} | A], L) when Ay < Bx ->
+ relprod2(B, Bx, By, A, L);
+relprod2(B, Bx, By, [{Ay, Ax} | A], L) when Ay == Bx ->
+ relprod(B, Bx, By, A, [{Ax,By} | L], Ax, B, Ay);
+relprod2(B, _Bx, _By, [{Ay, Ax} | A], L) ->
+ relprod1(B, Ay, Ax, A, L);
+relprod2(_, _, _, _, L) ->
+ L.
+
+relprod(B0, Bx0, By0, A0, L, Ax, [{Bx,By} | B], Ay) when Ay == Bx ->
+ relprod(B0, Bx0, By0, A0, [{Ax,By} | L], Ax, B, Ay);
+relprod(B0, Bx0, By0, A0, L, _Ax, _B, _Ay) ->
+ relprod2(B0, Bx0, By0, A0, L).
+
+relprod_n([], _R, _EmptyG, _IsR) ->
+ {error, badarg};
+relprod_n(RL, R, EmptyR, IsR) ->
+ case domain_type(RL, ?ANYTYPE) of
+ Error = {error, _Reason} ->
+ Error;
+ DType ->
+ Empty = any(fun is_empty_set/1, RL) or EmptyR,
+ RType = range_type(RL, []),
+ Type = ?BINREL(DType, RType),
+ Prod =
+ case Empty of
+ true when DType =:= ?ANYTYPE; RType =:= ?ANYTYPE ->
+ empty_set();
+ true ->
+ ?SET([], Type);
+ false ->
+ TL = ?LIST((relprod_n(RL))),
+ Sz = length(RL),
+ Fun = fun({X,A}) -> {X, flat(Sz, A, [])} end,
+ ?SET(map(Fun, TL), Type)
+ end,
+ case IsR of
+ true -> relative_product(Prod, R);
+ false -> Prod
+ end
+ end.
+
+relprod_n([R | Rs]) ->
+ relprod_n(Rs, R).
+
+relprod_n([], R) ->
+ R;
+relprod_n([R | Rs], R0) ->
+ T = raise_element(R0, 1),
+ R1 = relative_product1(T, R),
+ NR = projection({external, fun({{X,A},AS}) -> {X,{A,AS}} end}, R1),
+ relprod_n(Rs, NR).
+
+flat(1, A, L) ->
+ list_to_tuple([A | L]);
+flat(N, {T,A}, L) ->
+ flat(N-1, T, [A | L]).
+
+domain_type([T | Ts], T0) when ?IS_SET(T) ->
+ case ?TYPE(T) of
+ ?BINREL(DT, _RT) ->
+ case unify_types(DT, T0) of
+ [] -> {error, type_mismatch};
+ T1 -> domain_type(Ts, T1)
+ end;
+ ?ANYTYPE ->
+ domain_type(Ts, T0);
+ _ -> {error, badarg}
+ end;
+domain_type([], T0) ->
+ T0.
+
+range_type([T | Ts], L) ->
+ case ?TYPE(T) of
+ ?BINREL(_DT, RT) ->
+ range_type(Ts, [RT | L]);
+ ?ANYTYPE ->
+ ?ANYTYPE
+ end;
+range_type([], L) ->
+ list_to_tuple(reverse(L)).
+
+converse([{A,B} | X], L) ->
+ converse(X, [{B,A} | L]);
+converse([], L) ->
+ sort(L).
+
+strict([{E1,E2} | Es], L) when E1 == E2 ->
+ strict(Es, L);
+strict([E | Es], L) ->
+ strict(Es, [E | L]);
+strict([], L) ->
+ reverse(L).
+
+weak(Es) ->
+ %% Not very efficient...
+ weak(Es, ran(Es, []), []).
+
+weak(Es=[{X,_} | _], [Y | Ys], L) when X > Y ->
+ weak(Es, Ys, [{Y,Y} | L]);
+weak(Es=[{X,_} | _], [Y | Ys], L) when X == Y ->
+ weak(Es, Ys, L);
+weak([E={X,Y} | Es], Ys, L) when X > Y ->
+ weak1(Es, Ys, [E | L], X);
+weak([E={X,Y} | Es], Ys, L) when X == Y ->
+ weak2(Es, Ys, [E | L], X);
+weak([E={X,_Y} | Es], Ys, L) -> % when X < _Y
+ weak2(Es, Ys, [E, {X,X} | L], X);
+weak([], [Y | Ys], L) ->
+ weak([], Ys, [{Y,Y} | L]);
+weak([], [], L) ->
+ reverse(L).
+
+weak1([E={X,Y} | Es], Ys, L, X0) when X > Y, X == X0 ->
+ weak1(Es, Ys, [E | L], X);
+weak1([E={X,Y} | Es], Ys, L, X0) when X == Y, X == X0 ->
+ weak2(Es, Ys, [E | L], X);
+weak1([E={X,_Y} | Es], Ys, L, X0) when X == X0 -> % when X < Y
+ weak2(Es, Ys, [E, {X,X} | L], X);
+weak1(Es, Ys, L, X) ->
+ weak(Es, Ys, [{X,X} | L]).
+
+weak2([E={X,_Y} | Es], Ys, L, X0) when X == X0 -> % when X < _Y
+ weak2(Es, Ys, [E | L], X);
+weak2(Es, Ys, L, _X) ->
+ weak(Es, Ys, L).
+
+extc(L, [D | Ds], C, Ts) ->
+ extc(L, Ds, C, Ts, D);
+extc(L, [], _C, _Ts) ->
+ L.
+
+extc(L, Ds, C, [{X,_Y} | Ts], D) when X < D ->
+ extc(L, Ds, C, Ts, D);
+extc(L, Ds, C, [{X,_Y} | Ts], D) when X == D ->
+ extc(L, Ds, C, Ts);
+extc(L, Ds, C, [{X,_Y} | Ts], D) ->
+ extc2([{D,C} | L], Ds, C, Ts, X);
+extc(L, Ds, C, [], D) ->
+ extc_tail([{D,C} | L], Ds, C).
+
+extc2(L, [D | Ds], C, Ts, X) when X > D ->
+ extc2([{D,C} | L], Ds, C, Ts, X);
+extc2(L, [D | Ds], C, Ts, X) when X == D ->
+ extc(L, Ds, C, Ts);
+extc2(L, [D | Ds], C, Ts, _X) ->
+ extc(L, Ds, C, Ts, D);
+extc2(L, [], _C, _Ts, _X) ->
+ L.
+
+extc_tail(L, [D | Ds], C) ->
+ extc_tail([{D,C} | L], Ds, C);
+extc_tail(L, [], _C) ->
+ L.
+
+is_a_func([{E,_} | Es], E0) when E /= E0 ->
+ is_a_func(Es, E);
+is_a_func(L, _E) ->
+ L =:= [].
+
+restrict_n(I, [T | Ts], Key, Keys, L) ->
+ case element(I, T) of
+ K when K < Key ->
+ restrict_n(I, Ts, Key, Keys, L);
+ K when K == Key ->
+ restrict_n(I, Ts, Key, Keys, [T | L]);
+ K ->
+ restrict_n(I, K, Ts, Keys, L, T)
+ end;
+restrict_n(_I, _Ts, _Key, _Keys, L) ->
+ L.
+
+restrict_n(I, K, Ts, [Key | Keys], L, E) when K > Key ->
+ restrict_n(I, K, Ts, Keys, L, E);
+restrict_n(I, K, Ts, [Key | Keys], L, E) when K == Key ->
+ restrict_n(I, Ts, Key, Keys, [E | L]);
+restrict_n(I, _K, Ts, [Key | Keys], L, _E) ->
+ restrict_n(I, Ts, Key, Keys, L);
+restrict_n(_I, _K, _Ts, _Keys, L, _E) ->
+ L.
+
+restrict([Key | Keys], Tuples) ->
+ restrict(Tuples, Key, Keys, []);
+restrict(_Keys, _Tuples) ->
+ [].
+
+restrict([{K,_E} | Ts], Key, Keys, L) when K < Key ->
+ restrict(Ts, Key, Keys, L);
+restrict([{K,E} | Ts], Key, Keys, L) when K == Key ->
+ restrict(Ts, Key, Keys, [E | L]);
+restrict([{K,E} | Ts], _Key, Keys, L) ->
+ restrict(Ts, K, Keys, L, E);
+restrict(_Ts, _Key, _Keys, L) ->
+ L.
+
+restrict(Ts, K, [Key | Keys], L, E) when K > Key ->
+ restrict(Ts, K, Keys, L, E);
+restrict(Ts, K, [Key | Keys], L, E) when K == Key ->
+ restrict(Ts, Key, Keys, [E | L]);
+restrict(Ts, _K, [Key | Keys], L, _E) ->
+ restrict(Ts, Key, Keys, L);
+restrict(_Ts, _K, _Keys, L, _E) ->
+ L.
+
+diff_restrict_n(I, [T | Ts], Key, Keys, L) ->
+ case element(I, T) of
+ K when K < Key ->
+ diff_restrict_n(I, Ts, Key, Keys, [T | L]);
+ K when K == Key ->
+ diff_restrict_n(I, Ts, Key, Keys, L);
+ K ->
+ diff_restrict_n(I, K, Ts, Keys, L, T)
+ end;
+diff_restrict_n(I, _Ts, _Key, _Keys, L) when I =:= 1 ->
+ reverse(L);
+diff_restrict_n(_I, _Ts, _Key, _Keys, L) ->
+ sort(L).
+
+diff_restrict_n(I, K, Ts, [Key | Keys], L, T) when K > Key ->
+ diff_restrict_n(I, K, Ts, Keys, L, T);
+diff_restrict_n(I, K, Ts, [Key | Keys], L, _T) when K == Key ->
+ diff_restrict_n(I, Ts, Key, Keys, L);
+diff_restrict_n(I, _K, Ts, [Key | Keys], L, T) ->
+ diff_restrict_n(I, Ts, Key, Keys, [T | L]);
+diff_restrict_n(I, _K, Ts, _Keys, L, T) when I =:= 1 ->
+ reverse(L, [T | Ts]);
+diff_restrict_n(_I, _K, Ts, _Keys, L, T) ->
+ sort([T | Ts ++ L]).
+
+diff_restrict([Key | Keys], Tuples) ->
+ diff_restrict(Tuples, Key, Keys, []);
+diff_restrict(_Keys, Tuples) ->
+ diff_restrict_tail(Tuples, []).
+
+diff_restrict([{K,E} | Ts], Key, Keys, L) when K < Key ->
+ diff_restrict(Ts, Key, Keys, [E | L]);
+diff_restrict([{K,_E} | Ts], Key, Keys, L) when K == Key ->
+ diff_restrict(Ts, Key, Keys, L);
+diff_restrict([{K,E} | Ts], _Key, Keys, L) ->
+ diff_restrict(Ts, K, Keys, L, E);
+diff_restrict(_Ts, _Key, _Keys, L) ->
+ L.
+
+diff_restrict(Ts, K, [Key | Keys], L, E) when K > Key ->
+ diff_restrict(Ts, K, Keys, L, E);
+diff_restrict(Ts, K, [Key | Keys], L, _E) when K == Key ->
+ diff_restrict(Ts, Key, Keys, L);
+diff_restrict(Ts, _K, [Key | Keys], L, E) ->
+ diff_restrict(Ts, Key, Keys, [E | L]);
+diff_restrict(Ts, _K, _Keys, L, E) ->
+ diff_restrict_tail(Ts, [E | L]).
+
+diff_restrict_tail([{_K,E} | Ts], L) ->
+ diff_restrict_tail(Ts, [E | L]);
+diff_restrict_tail(_Ts, L) ->
+ L.
+
+comp([], B) ->
+ check_function(B, []);
+comp(_A, []) ->
+ bad_function;
+comp(A0, [{Bx,By} | B]) ->
+ A = converse(A0, []),
+ check_function(A0, comp1(A, B, [], Bx, By)).
+
+comp1([{Ay,Ax} | A], B, L, Bx, By) when Ay == Bx ->
+ comp1(A, B, [{Ax,By} | L], Bx, By);
+comp1([{Ay,Ax} | A], B, L, Bx, _By) when Ay > Bx ->
+ comp2(A, B, L, Bx, Ay, Ax);
+comp1([{Ay,_Ax} | _A], _B, _L, Bx, _By) when Ay < Bx ->
+ bad_function;
+comp1([], B, L, Bx, _By) ->
+ check_function(Bx, B, L).
+
+comp2(A, [{Bx,_By} | B], L, Bx0, Ay, Ax) when Ay > Bx, Bx /= Bx0 ->
+ comp2(A, B, L, Bx, Ay, Ax);
+comp2(A, [{Bx,By} | B], L, _Bx0, Ay, Ax) when Ay == Bx ->
+ comp1(A, B, [{Ax,By} | L], Bx, By);
+comp2(_A, _B, _L, _Bx0, _Ay, _Ax) ->
+ bad_function.
+
+inverse1([{A,B} | X]) ->
+ inverse(X, A, [{B,A}]);
+inverse1([]) ->
+ [].
+
+inverse([{A,B} | X], A0, L) when A0 /= A ->
+ inverse(X, A, [{B,A} | L]);
+inverse([{A,_B} | _X], A0, _L) when A0 == A ->
+ bad_function;
+inverse([], _A0, L) ->
+ SL = [{V,_} | Es] = sort(L),
+ case is_a_func(Es, V) of
+ true -> SL;
+ false -> bad_function
+ end.
+
+%% Inlined.
+external_fun({external, Function}) when is_atom(Function) ->
+ false;
+external_fun({external, Fun}) ->
+ Fun;
+external_fun(_) ->
+ false.
+
+%% Inlined.
+element_type(?SET_OF(Type)) -> Type;
+element_type(Type) -> Type.
+
+subst(Ts, Fun, Type) ->
+ subst(Ts, Fun, Type, ?ANYTYPE, []).
+
+subst([T | Ts], Fun, Type, NType, L) ->
+ case setfun(T, Fun, Type, NType) of
+ {SD, ST} -> subst(Ts, Fun, Type, ST, [{T, SD} | L]);
+ Bad -> Bad
+ end;
+subst([], _Fun, _Type, NType, L) ->
+ {L, NType}.
+
+projection1([E | Es]) ->
+ projection1([], element(1, E), Es);
+projection1([] = L) ->
+ L.
+
+projection1(L, X, [E | Es]) ->
+ case element(1, E) of
+ X1 when X == X1 -> projection1(L, X, Es);
+ X1 -> projection1([X | L], X1, Es)
+ end;
+projection1(L, X, []) ->
+ reverse(L, [X]).
+
+projection_n([E | Es], I, L) ->
+ projection_n(Es, I, [element(I, E) | L]);
+projection_n([], _I, L) ->
+ usort(L).
+
+substitute_element([T | Ts], I, L) ->
+ substitute_element(Ts, I, [{T, element(I, T)} | L]);
+substitute_element(_, _I, L) ->
+ reverse(L).
+
+substitute([T | Ts], Fun, L) ->
+ substitute(Ts, Fun, [{T, Fun(T)} | L]);
+substitute(_, _Fun, L) ->
+ reverse(L).
+
+partition_n(I, [E | Ts]) ->
+ partition_n(I, Ts, element(I, E), [E], []);
+partition_n(_I, []) ->
+ [].
+
+partition_n(I, [E | Ts], K, Es, P) ->
+ case {element(I, E), Es} of
+ {K1, _} when K == K1 ->
+ partition_n(I, Ts, K, [E | Es], P);
+ {K1, [_]} -> % optimization
+ partition_n(I, Ts, K1, [E], [Es | P]);
+ {K1, _} ->
+ partition_n(I, Ts, K1, [E], [reverse(Es) | P])
+ end;
+partition_n(I, [], _K, Es, P) when I > 1 ->
+ sort([reverse(Es) | P]);
+partition_n(_I, [], _K, [_] = Es, P) -> % optimization
+ reverse(P, [Es]);
+partition_n(_I, [], _K, Es, P) ->
+ reverse(P, [reverse(Es)]).
+
+partition3_n(I, [T | Ts], Key, Keys, L1, L2) ->
+ case element(I, T) of
+ K when K < Key ->
+ partition3_n(I, Ts, Key, Keys, L1, [T | L2]);
+ K when K == Key ->
+ partition3_n(I, Ts, Key, Keys, [T | L1], L2);
+ K ->
+ partition3_n(I, K, Ts, Keys, L1, L2, T)
+ end;
+partition3_n(I, _Ts, _Key, _Keys, L1, L2) when I =:= 1 ->
+ [reverse(L1) | reverse(L2)];
+partition3_n(_I, _Ts, _Key, _Keys, L1, L2) ->
+ [sort(L1) | sort(L2)].
+
+partition3_n(I, K, Ts, [Key | Keys], L1, L2, T) when K > Key ->
+ partition3_n(I, K, Ts, Keys, L1, L2, T);
+partition3_n(I, K, Ts, [Key | Keys], L1, L2, T) when K == Key ->
+ partition3_n(I, Ts, Key, Keys, [T | L1], L2);
+partition3_n(I, _K, Ts, [Key | Keys], L1, L2, T) ->
+ partition3_n(I, Ts, Key, Keys, L1, [T | L2]);
+partition3_n(I, _K, Ts, _Keys, L1, L2, T) when I =:= 1 ->
+ [reverse(L1) | reverse(L2, [T | Ts])];
+partition3_n(_I, _K, Ts, _Keys, L1, L2, T) ->
+ [sort(L1) | sort([T | Ts ++ L2])].
+
+partition3([Key | Keys], Tuples) ->
+ partition3(Tuples, Key, Keys, [], []);
+partition3(_Keys, Tuples) ->
+ partition3_tail(Tuples, [], []).
+
+partition3([{K,E} | Ts], Key, Keys, L1, L2) when K < Key ->
+ partition3(Ts, Key, Keys, L1, [E | L2]);
+partition3([{K,E} | Ts], Key, Keys, L1, L2) when K == Key ->
+ partition3(Ts, Key, Keys, [E | L1], L2);
+partition3([{K,E} | Ts], _Key, Keys, L1, L2) ->
+ partition3(Ts, K, Keys, L1, L2, E);
+partition3(_Ts, _Key, _Keys, L1, L2) ->
+ [L1 | L2].
+
+partition3(Ts, K, [Key | Keys], L1, L2, E) when K > Key ->
+ partition3(Ts, K, Keys, L1, L2, E);
+partition3(Ts, K, [Key | Keys], L1, L2, E) when K == Key ->
+ partition3(Ts, Key, Keys, [E | L1], L2);
+partition3(Ts, _K, [Key | Keys], L1, L2, E) ->
+ partition3(Ts, Key, Keys, L1, [E | L2]);
+partition3(Ts, _K, _Keys, L1, L2, E) ->
+ partition3_tail(Ts, L1, [E | L2]).
+
+partition3_tail([{_K,E} | Ts], L1, L2) ->
+ partition3_tail(Ts, L1, [E | L2]);
+partition3_tail(_Ts, L1, L2) ->
+ [L1 | L2].
+
+replace([E | Es], F, L) ->
+ replace(Es, F, [F(E) | L]);
+replace(_, _F, L) ->
+ sort(L).
+
+mul_relprod([T | Ts], I, R) when ?IS_SET(T) ->
+ P = raise_element(R, I),
+ F = relative_product1(P, T),
+ [F | mul_relprod(Ts, I+1, R)];
+mul_relprod([], _I, _R) ->
+ [].
+
+raise_element(R, I) ->
+ L = sort(I =/= 1, rearr(?LIST(R), I, [])),
+ Type = ?TYPE(R),
+ ?SET(L, ?BINREL(?REL_TYPE(I, Type), Type)).
+
+rearr([E | Es], I, L) ->
+ rearr(Es, I, [{element(I, E), E} | L]);
+rearr([], _I, L) ->
+ L.
+
+join_element(E1, E2) ->
+ [_ | L2] = tuple_to_list(E2),
+ list_to_tuple(tuple_to_list(E1) ++ L2).
+
+join_element(E1, E2, I2) ->
+ tuple_to_list(E1) ++ join_element2(tuple_to_list(E2), 1, I2).
+
+join_element2([B | Bs], C, I2) when C =/= I2 ->
+ [B | join_element2(Bs, C+1, I2)];
+join_element2([_ | Bs], _C, _I2) ->
+ Bs.
+
+family2rel([{X,S} | F], L) ->
+ fam2rel(F, L, X, S);
+family2rel([], L) ->
+ reverse(L).
+
+fam2rel(F, L, X, [Y | Ys]) ->
+ fam2rel(F, [{X,Y} | L], X, Ys);
+fam2rel(F, L, _X, _) ->
+ family2rel(F, L).
+
+fam_spec([{_,S}=E | F], Fun, Type, L) ->
+ case Fun(?SET(S, Type)) of
+ true ->
+ fam_spec(F, Fun, Type, [E | L]);
+ false ->
+ fam_spec(F, Fun, Type, L);
+ _ ->
+ badarg
+ end;
+fam_spec([], _Fun, _Type, L) ->
+ reverse(L).
+
+fam_specification([{_,S}=E | F], Fun, L) ->
+ case Fun(S) of
+ true ->
+ fam_specification(F, Fun, [E | L]);
+ false ->
+ fam_specification(F, Fun, L);
+ _ ->
+ badarg
+ end;
+fam_specification([], _Fun, L) ->
+ reverse(L).
+
+un_of_fam([{_X,S} | F], L) ->
+ un_of_fam(F, [S | L]);
+un_of_fam([], L) ->
+ lunion(sort(L)).
+
+int_of_fam([{_,S} | F]) ->
+ int_of_fam(F, [S]);
+int_of_fam([]) ->
+ badarg.
+
+int_of_fam([{_,S} | F], L) ->
+ int_of_fam(F, [S | L]);
+int_of_fam([], [L | Ls]) ->
+ lintersection(Ls, L).
+
+fam_un([{X,S} | F], L) ->
+ fam_un(F, [{X, lunion(S)} | L]);
+fam_un([], L) ->
+ reverse(L).
+
+fam_int([{X, [S | Ss]} | F], L) ->
+ fam_int(F, [{X, lintersection(Ss, S)} | L]);
+fam_int([{_X,[]} | _F], _L) ->
+ badarg;
+fam_int([], L) ->
+ reverse(L).
+
+fam_dom([{X,S} | F], L) ->
+ fam_dom(F, [{X, dom(S)} | L]);
+fam_dom([], L) ->
+ reverse(L).
+
+fam_ran([{X,S} | F], L) ->
+ fam_ran(F, [{X, ran(S, [])} | L]);
+fam_ran([], L) ->
+ reverse(L).
+
+fam_union(F1 = [{A,_AS} | _AL], [B1={B,_BS} | BL], L) when A > B ->
+ fam_union(F1, BL, [B1 | L]);
+fam_union([{A,AS} | AL], [{B,BS} | BL], L) when A == B ->
+ fam_union(AL, BL, [{A, umerge(AS, BS)} | L]);
+fam_union([A1 | AL], F2, L) ->
+ fam_union(AL, F2, [A1 | L]);
+fam_union(_, F2, L) ->
+ reverse(L, F2).
+
+fam_intersect(F1 = [{A,_AS} | _AL], [{B,_BS} | BL], L) when A > B ->
+ fam_intersect(F1, BL, L);
+fam_intersect([{A,AS} | AL], [{B,BS} | BL], L) when A == B ->
+ fam_intersect(AL, BL, [{A, intersection(AS, BS, [])} | L]);
+fam_intersect([_A1 | AL], F2, L) ->
+ fam_intersect(AL, F2, L);
+fam_intersect(_, _, L) ->
+ reverse(L).
+
+fam_difference(F1 = [{A,_AS} | _AL], [{B,_BS} | BL], L) when A > B ->
+ fam_difference(F1, BL, L);
+fam_difference([{A,AS} | AL], [{B,BS} | BL], L) when A == B ->
+ fam_difference(AL, BL, [{A, difference(AS, BS, [])} | L]);
+fam_difference([A1 | AL], F2, L) ->
+ fam_difference(AL, F2, [A1 | L]);
+fam_difference(F1, _, L) ->
+ reverse(L, F1).
+
+check_function([{X,_} | XL], R) ->
+ check_function(X, XL, R);
+check_function([], R) ->
+ R.
+
+check_function(X0, [{X,_} | XL], R) when X0 /= X ->
+ check_function(X, XL, R);
+check_function(X0, [{X,_} | _XL], _R) when X0 == X ->
+ bad_function;
+check_function(_X0, [], R) ->
+ R.
+
+fam_partition_n(I, [E | Ts]) ->
+ fam_partition_n(I, Ts, element(I, E), [E], []);
+fam_partition_n(_I, []) ->
+ [].
+
+fam_partition_n(I, [E | Ts], K, Es, P) ->
+ case {element(I, E), Es} of
+ {K1, _} when K == K1 ->
+ fam_partition_n(I, Ts, K, [E | Es], P);
+ {K1, [_]} -> % optimization
+ fam_partition_n(I, Ts, K1, [E], [{K,Es} | P]);
+ {K1, _} ->
+ fam_partition_n(I, Ts, K1, [E], [{K,reverse(Es)} | P])
+ end;
+fam_partition_n(_I, [], K, [_] = Es, P) -> % optimization
+ reverse(P, [{K,Es}]);
+fam_partition_n(_I, [], K, Es, P) ->
+ reverse(P, [{K,reverse(Es)}]).
+
+fam_partition([{K,Vs} | Ts], Sort) ->
+ fam_partition(Ts, K, [Vs], [], Sort);
+fam_partition([], _Sort) ->
+ [].
+
+fam_partition([{K1,V} | Ts], K, Vs, P, S) when K1 == K ->
+ fam_partition(Ts, K, [V | Vs], P, S);
+fam_partition([{K1,V} | Ts], K, [_] = Vs, P, S) -> % optimization
+ fam_partition(Ts, K1, [V], [{K, Vs} | P], S);
+fam_partition([{K1,V} | Ts], K, Vs, P, S) ->
+ fam_partition(Ts, K1, [V], [{K, sort(S, Vs)} | P], S);
+fam_partition([], K, [_] = Vs, P, _S) -> % optimization
+ [{K, Vs} | P];
+fam_partition([], K, Vs, P, S) ->
+ [{K, sort(S, Vs)} | P].
+
+fam_proj([{X,S} | F], Fun, Type, NType, L) ->
+ case setfun(S, Fun, Type, NType) of
+ {SD, ST} -> fam_proj(F, Fun, Type, ST, [{X, SD} | L]);
+ Bad -> Bad
+ end;
+fam_proj([], _Fun, _Type, NType, L) ->
+ {reverse(L), NType}.
+
+setfun(T, Fun, Type, NType) ->
+ case Fun(term2set(T, Type)) of
+ NS when ?IS_SET(NS) ->
+ case unify_types(NType, ?SET_OF(?TYPE(NS))) of
+ [] -> type_mismatch;
+ NT -> {?LIST(NS), NT}
+ end;
+ NS when ?IS_ORDSET(NS) ->
+ case unify_types(NType, NT = ?ORDTYPE(NS)) of
+ [] -> type_mismatch;
+ NT -> {?ORDDATA(NS), NT}
+ end;
+ _ ->
+ badarg
+ end.
+
+%% Inlined.
+term2set(L, Type) when is_list(L) ->
+ ?SET(L, Type);
+term2set(T, Type) ->
+ ?ORDSET(T, Type).
+
+fam2digraph(F, G) ->
+ Fun = fun({From, ToL}) ->
+ digraph:add_vertex(G, From),
+ Fun2 = fun(To) ->
+ digraph:add_vertex(G, To),
+ case digraph:add_edge(G, From, To) of
+ {error, {bad_edge, _}} ->
+ throw({error, cyclic});
+ _ ->
+ true
+ end
+ end,
+ foreach(Fun2, ToL)
+ end,
+ foreach(Fun, to_external(F)),
+ G.
+
+digraph_family(G) ->
+ Vs = sort(digraph:vertices(G)),
+ digraph_fam(Vs, Vs, G, []).
+
+digraph_fam([V | Vs], V0, G, L) when V /= V0 ->
+ Ns = sort(digraph:out_neighbours(G, V)),
+ digraph_fam(Vs, V, G, [{V,Ns} | L]);
+digraph_fam([], _V0, _G, L) ->
+ reverse(L).
+
+%% -> boolean()
+check_fun(T, F, FunT) ->
+ true = is_type(FunT),
+ {NT, _MaxI} = number_tuples(T, 1),
+ L = flatten(tuple2list(F(NT))),
+ has_hole(L, 1).
+
+number_tuples(T, N) when is_tuple(T) ->
+ {L, NN} = mapfoldl(fun number_tuples/2, N, tuple_to_list(T)),
+ {list_to_tuple(L), NN};
+number_tuples(_, N) ->
+ {N, N+1}.
+
+tuple2list(T) when is_tuple(T) ->
+ map(fun tuple2list/1, tuple_to_list(T));
+tuple2list(C) ->
+ [C].
+
+has_hole([I | Is], I0) when I =< I0 -> has_hole(Is, erlang:max(I+1, I0));
+has_hole(Is, _I) -> Is =/= [].
+
+%% Optimization. Same as check_fun/3, but for integers.
+check_for_sort(T, _I) when T =:= ?ANYTYPE ->
+ empty;
+check_for_sort(T, I) when ?IS_RELATION(T), I =< ?REL_ARITY(T), I >= 1 ->
+ I > 1;
+check_for_sort(_T, _I) ->
+ error.
+
+inverse_substitution(L, Fun, Sort) ->
+ %% One easily sees that the inverse of the tuples created by
+ %% applying Fun need to be sorted iff the tuples created by Fun
+ %% need to be sorted.
+ sort(Sort, fun_rearr(L, Fun, [])).
+
+fun_rearr([E | Es], Fun, L) ->
+ fun_rearr(Es, Fun, [{Fun(E), E} | L]);
+fun_rearr([], _Fun, L) ->
+ L.
+
+sets_to_list(Ss) ->
+ map(fun(S) when ?IS_SET(S) -> ?LIST(S) end, Ss).
+
+types([], L) ->
+ list_to_tuple(reverse(L));
+types([S | _Ss], _L) when ?TYPE(S) =:= ?ANYTYPE ->
+ ?ANYTYPE;
+types([S | Ss], L) ->
+ types(Ss, [?TYPE(S) | L]).
+
+%% Inlined.
+unify_types(T, T) -> T;
+unify_types(Type1, Type2) ->
+ catch unify_types1(Type1, Type2).
+
+unify_types1(Atom, Atom) when ?IS_ATOM_TYPE(Atom) ->
+ Atom;
+unify_types1(?ANYTYPE, Type) ->
+ Type;
+unify_types1(Type, ?ANYTYPE) ->
+ Type;
+unify_types1(?SET_OF(Type1), ?SET_OF(Type2)) ->
+ [unify_types1(Type1, Type2)];
+unify_types1(T1, T2) when tuple_size(T1) =:= tuple_size(T2) ->
+ unify_typesl(tuple_size(T1), T1, T2, []);
+unify_types1(_T1, _T2) ->
+ throw([]).
+
+unify_typesl(0, _T1, _T2, L) ->
+ list_to_tuple(L);
+unify_typesl(N, T1, T2, L) ->
+ T = unify_types1(?REL_TYPE(N, T1), ?REL_TYPE(N, T2)),
+ unify_typesl(N-1, T1, T2, [T | L]).
+
+%% inlined.
+match_types(T, T) -> true;
+match_types(Type1, Type2) -> match_types1(Type1, Type2).
+
+match_types1(Atom, Atom) when ?IS_ATOM_TYPE(Atom) ->
+ true;
+match_types1(?ANYTYPE, _) ->
+ true;
+match_types1(_, ?ANYTYPE) ->
+ true;
+match_types1(?SET_OF(Type1), ?SET_OF(Type2)) ->
+ match_types1(Type1, Type2);
+match_types1(T1, T2) when tuple_size(T1) =:= tuple_size(T2) ->
+ match_typesl(tuple_size(T1), T1, T2);
+match_types1(_T1, _T2) ->
+ false.
+
+match_typesl(0, _T1, _T2) ->
+ true;
+match_typesl(N, T1, T2) ->
+ case match_types1(?REL_TYPE(N, T1), ?REL_TYPE(N, T2)) of
+ true -> match_typesl(N-1, T1, T2);
+ false -> false
+ end.
+
+sort(true, L) ->
+ sort(L);
+sort(false, L) ->
+ reverse(L).
diff --git a/lib/tools/test/tools_bench.spec b/lib/tools/test/tools_bench.spec
new file mode 100644
index 0000000000..ef08fd68a8
--- /dev/null
+++ b/lib/tools/test/tools_bench.spec
@@ -0,0 +1 @@
+{suites,"../tools_test",[prof_bench_SUITE]}.
diff --git a/lib/tools/test/xref_SUITE.erl b/lib/tools/test/xref_SUITE.erl
index d651cbcfee..da4f56c09b 100644
--- a/lib/tools/test/xref_SUITE.erl
+++ b/lib/tools/test/xref_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1112,27 +1112,16 @@ read_expected(Version) ->
{POS7+2,{FF,{erlang,spawn_opt,4}}},
{POS8+1,{FF,{hej,san,1}}},
{POS8+4,{FF,{a,b,1}}},
- {POS8+4,{FF,{erlang,apply,2}}},
- {POS8+5,{FF,{erlang,apply,2}}},
{POS8+6,{FF,{m,f,1}}},
{POS9+1,{FF,{read,bi,0}}},
{POS9+2,{FF,{a,b,1}}},
- {POS9+2,{FF,{erlang,apply,2}}},
- {POS9+3,{FF,{erlang,apply,2}}},
- {POS9+4,{FF,{erlang,apply,2}}},
{POS9+4,{FF,{erlang,not_a_function,1}}},
{POS9+5,{FF,{mod,func,2}}},
{POS9+6,{FF,{erlang,apply,1}}},
- {POS9+7,{FF,{erlang,apply,2}}},
{POS9+7,{FF,{math,add3,1}}},
{POS9+8,{FF,{q,f,1}}},
- {POS10+4,{FF,{erlang,apply,2}}},
{POS10+5,{FF,{mod1,fun1,1}}},
- {POS11+6,{FF,{erlang,apply,2}}},
- {POS12+1,{FF,{erlang,apply,2}}},
- {POS12+4,{FF,{erlang,apply,2}}},
{POS12+5,{FF,{m3,f3,2}}},
- {POS12+7,{FF,{erlang,apply,2}}},
{POS13+1,{FF,{dm,df,1}}},
{POS13+6,{{read,bi,0},{foo,module_info,0}}},
{POS13+7,{{read,bi,0},{read,module_info,0}}},
@@ -1162,15 +1151,26 @@ read_expected(Version) ->
{POS3+3, {FF,{erlang,spawn_link,3}}},
{POS3+4, {FF,{erlang,spawn_link,3}}},
{POS6+4, {FF,{erlang,spawn,3}}},
+ {POS8+4,{FF,{erlang,apply,2}}},
+ {POS8+5,{FF,{erlang,apply,2}}},
{POS8+6,{FF,{erlang,apply,3}}},
{POS8+7,{FF,{erlang,apply,3}}},
{POS9+1,{FF,{erlang,apply,3}}},
+ {POS9+2,{FF,{erlang,apply,2}}},
+ {POS9+3,{FF,{erlang,apply,2}}},
+ {POS9+4,{FF,{erlang,apply,2}}},
{POS9+5,{FF,{erlang,apply,3}}},
+ {POS9+7,{FF,{erlang,apply,2}}},
+ {POS10+4,{FF,{erlang,apply,2}}},
{POS11+1,{FF,{erlang,apply,3}}},
{POS11+2,{FF,{erlang,apply,3}}},
{POS11+3,{FF,{erlang,apply,3}}},
{POS11+4,{FF,{erlang,apply,3}}},
+ {POS11+6,{FF,{erlang,apply,2}}},
+ {POS12+1,{FF,{erlang,apply,2}}},
+ {POS12+4,{FF,{erlang,apply,2}}},
{POS12+5,{FF,{erlang,apply,3}}},
+ {POS12+7,{FF,{erlang,apply,2}}},
{POS12+8,{FF,{erlang,apply,3}}},
{POS13+5, {{read,bi,0},{erlang,length,1}}},
{POS14+3, {{read,bi,0},{erlang,length,1}}}],
@@ -2233,18 +2233,18 @@ variables(Conf) when is_list(Conf) ->
{{error, _, _}, _} = xref_base:variables(S108, [{verbose,false}]),
{ok, S109} = xref_base:set_library_path(S108, [], [{verbose,false}]),
- Tabs = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
{ok, S110} = eval("Eplus := closure E, TT := Eplus",
'closure()', S109),
{{ok, [{user, ['Eplus','TT']}]}, S111} = xref_base:variables(S110),
{ok, S112} = xref_base:forget(S111, ['TT','Eplus']),
- true = Tabs =:= length(ets:all()),
+ true = NoOfTables =:= erlang:system_info(ets_count),
{ok, NS0} = eval("Eplus := closure E", 'closure()', S112),
{{ok, [{user, ['Eplus']}]}, NS} = xref_base:variables(NS0),
ok = xref_base:delete(NS),
- true = Tabs =:= length(ets:all()),
+ true = NoOfTables =:= erlang:system_info(ets_count),
ok = file:delete(Beam),
ok.
diff --git a/lib/tools/vsn.mk b/lib/tools/vsn.mk
index f9723c0f9b..191a458c62 100644
--- a/lib/tools/vsn.mk
+++ b/lib/tools/vsn.mk
@@ -1 +1 @@
-TOOLS_VSN = 2.11.2
+TOOLS_VSN = 3.2
diff --git a/lib/wx/api_gen/gen_util.erl b/lib/wx/api_gen/gen_util.erl
index 5e2f405498..d27a9ae548 100644
--- a/lib/wx/api_gen/gen_util.erl
+++ b/lib/wx/api_gen/gen_util.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -106,8 +106,8 @@ check_diff(Diff) ->
throw:_ -> diff;
error:{badmatch,_} ->
diff;
- _:What ->
- io:format("~p:~p: ~p ~p~n", [?MODULE,?LINE, What, erlang:get_stacktrace()]),
+ _:What:Stacktrace ->
+ io:format("~p:~p: ~p ~p~n", [?MODULE,?LINE, What, Stacktrace]),
diff
end.
diff --git a/lib/wx/api_gen/gl_gen.erl b/lib/wx/api_gen/gl_gen.erl
index 7e3766a43b..c0509ed802 100644
--- a/lib/wx/api_gen/gl_gen.erl
+++ b/lib/wx/api_gen/gl_gen.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -47,9 +47,9 @@ safe(What, QuitOnErr) ->
What(),
io:format("Completed successfully~n~n", []),
QuitOnErr andalso gen_util:halt(0)
- catch Err:Reason ->
+ catch Err:Reason:Stacktrace ->
io:format("Error ~p: ~p:~p~n ~p~n",
- [get(current_func),Err,Reason,erlang:get_stacktrace()]),
+ [get(current_func),Err,Reason,Stacktrace]),
(catch gen_util:close()),
timer:sleep(1999),
QuitOnErr andalso gen_util:halt(1)
diff --git a/lib/wx/api_gen/gl_gen_erl.erl b/lib/wx/api_gen/gl_gen_erl.erl
index 45f5fd8f4c..e62d182a37 100644
--- a/lib/wx/api_gen/gl_gen_erl.erl
+++ b/lib/wx/api_gen/gl_gen_erl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -246,8 +246,8 @@ gen_types(Where) ->
gen_export(F) ->
try gen_export_1(F)
- catch E:R ->
- io:format("Crash ~p:~p in ~p ~n",[E,R, erlang:get_stacktrace()]),
+ catch E:R:S ->
+ io:format("Crash ~p:~p in ~p ~n",[E,R,S]),
io:format("Func = ~p~n ~p", [F, get(F)])
end.
@@ -489,8 +489,8 @@ doc_return_types2(T, Ps) ->
doc_arg_type(#arg{name=Name,type=T}) ->
try
erl_arg_name(Name) ++ " :: " ++ doc_arg_type2(T)
- catch _:Error ->
- io:format("Error spec: ~p ~p~n~p~n",[Name, Error, erlang:get_stacktrace()]),
+ catch _:Error:Stacktrace ->
+ io:format("Error spec: ~p ~p~n~p~n",[Name, Error, Stacktrace]),
exit(error)
end.
diff --git a/lib/wx/api_gen/gl_scan_doc.erl b/lib/wx/api_gen/gl_scan_doc.erl
index 6ed5438608..c793d4940e 100644
--- a/lib/wx/api_gen/gl_scan_doc.erl
+++ b/lib/wx/api_gen/gl_scan_doc.erl
@@ -2,7 +2,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/api_gen/wx_extra/added_func.h b/lib/wx/api_gen/wx_extra/added_func.h
index bffe391140..28fecbf454 100644
--- a/lib/wx/api_gen/wx_extra/added_func.h
+++ b/lib/wx/api_gen/wx_extra/added_func.h
@@ -44,3 +44,9 @@ class wxWindowGTK {
public:
double GetContentScaleFactor();
};
+
+class wxDisplay {
+ public:
+ // get the resolution of this monitor in pixels per inch
+ wxSize GetPPI() const;
+};
diff --git a/lib/wx/api_gen/wx_extra/wxGraphicsRenderer.c_src b/lib/wx/api_gen/wx_extra/wxGraphicsRenderer.c_src
new file mode 100644
index 0000000000..4718525dd6
--- /dev/null
+++ b/lib/wx/api_gen/wx_extra/wxGraphicsRenderer.c_src
@@ -0,0 +1,58 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+
+<<CreatePen
+case ~s: { // wxGraphicsRenderer::CreatePen taylormade
+ wxGraphicsRenderer *This = (wxGraphicsRenderer *) getPtr(bp,memenv); bp += 4;
+ wxPen *pen = (wxPen *) getPtr(bp,memenv); bp += 4;
+ if(!This) throw wxe_badarg(0);
+#if !wxCHECK_VERSION(3,1,1)
+ wxGraphicsPen * Result = new wxGraphicsPen(This->CreatePen(*pen)); newPtr((void *) Result,4, memenv);
+ rt.addRef(getRef((void *)Result,memenv), "wxGraphicsPen");
+ break;
+#else
+ wxGraphicsPenInfo info = wxGraphicsPenInfo()
+ .Colour(pen->GetColour())
+ .Width(pen->GetWidth())
+ .Style(pen->GetStyle())
+ .Join(pen->GetJoin())
+ .Cap(pen->GetCap())
+ ;
+
+ if ( info.GetStyle() == wxPENSTYLE_USER_DASH )
+ {
+ wxDash *dashes;
+ if ( int nb_dashes = pen->GetDashes(&dashes) )
+ info.Dashes(nb_dashes, dashes);
+ }
+
+ if ( info.GetStyle() == wxPENSTYLE_STIPPLE )
+ {
+ if ( wxBitmap* const stipple = pen->GetStipple() )
+ info.Stipple(*stipple);
+ }
+ wxGraphicsPen * Result = new wxGraphicsPen(This->CreatePen(info));
+ newPtr((void *) Result,4, memenv);
+ rt.addRef(getRef((void *)Result,memenv), "wxGraphicsPen");
+ break;
+#endif
+}
+CreatePen>>
diff --git a/lib/wx/api_gen/wx_gen.erl b/lib/wx/api_gen/wx_gen.erl
index aadfe4b111..8a00498319 100644
--- a/lib/wx/api_gen/wx_gen.erl
+++ b/lib/wx/api_gen/wx_gen.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -47,9 +47,9 @@ safe(What, QuitOnErr) ->
What(),
io:format("Completed successfully~n~n", []),
QuitOnErr andalso gen_util:halt(0)
- catch Err:Reason ->
+ catch Err:Reason:Stacktrace ->
io:format("Error in ~p ~p~n", [get(current_class),get(current_func)]),
- erlang:display({Err,Reason, erlang:get_stacktrace()}),
+ erlang:display({Err,Reason,Stacktrace}),
catch gen_util:close(),
QuitOnErr andalso gen_util:halt(1)
end.
@@ -93,9 +93,10 @@ mangle_info(E={not_const,List}) ->
put(not_const, [atom_to_list(M) || M <- List]),
E;
mangle_info(E={gvars,List}) ->
- A2L = fun({N,{T,C}}) -> {atom_to_list(N), {T,atom_to_list(C)}};
+ A2L = fun({N,{test_if,C}}) -> {atom_to_list(N), {test_if,C}};
+ ({N,{T,C}}) -> {atom_to_list(N), {T,atom_to_list(C)}};
({N,C}) -> {atom_to_list(N), atom_to_list(C)}
- end,
+ end,
put(gvars, map(A2L,List)),
E;
mangle_info({class,CN,P,O,FL}) ->
@@ -700,8 +701,13 @@ parse_type2(["wxe_cb"|R],Info,Opts, T) ->
parse_type2(R,Info,Opts,T#type{name=int,base=wxe_cb});
parse_type2([const|R],Info,Opts,T=#type{mod=Mod}) ->
parse_type2(R,Info,Opts,T#type{mod=[const|Mod]});
-parse_type2(["unsigned"|R],Info,Opts,T=#type{mod=Mod}) ->
- parse_type2(R,Info,Opts,T#type{mod=[unsigned|Mod]});
+parse_type2(["unsigned"|R],Info,Opts,T=#type{mod=Mod}) ->
+ case T#type.base of
+ undefined ->
+ parse_type2(R,Info,Opts,T#type{name=int, base=int, mod=[unsigned|Mod]});
+ _ ->
+ parse_type2(R,Info,Opts,T#type{mod=[unsigned|Mod]})
+ end;
parse_type2(["int"|R],Info,Opts, T) ->
parse_type2(R,Info,Opts,T#type{name=int,base=int});
parse_type2(["wxByte"|R],Info,Opts, T) ->
diff --git a/lib/wx/api_gen/wx_gen_cpp.erl b/lib/wx/api_gen/wx_gen_cpp.erl
index 573abfa9b8..c6f2534380 100644
--- a/lib/wx/api_gen/wx_gen_cpp.erl
+++ b/lib/wx/api_gen/wx_gen_cpp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -995,8 +995,13 @@ build_ret_types(Type,Ps) ->
end,
lists:foldl(Calc, Free, Ps).
-build_ret(Name,_,#type{base={class,Class},single=true}) ->
- w(" rt.addRef(getRef((void *)~s,memenv), \"~s\");~n",[Name,Class]);
+build_ret(Name,_D,#type{base={class,Class},single=true}=_T) ->
+ case Class of
+ "wxGraphicsContext" ->
+ w(" rt.addRef(getRef((void *)~s,memenv,8), \"~s\");~n",[Name,Class]);
+ _ ->
+ w(" rt.addRef(getRef((void *)~s,memenv), \"~s\");~n",[Name,Class])
+ end;
build_ret(Name,_,#type{name="wxTreeItemId",single=true}) ->
w(" rt.add((wxUIntPtr *) ~s.m_pItem);~n",[Name]);
build_ret(Name,_,#type{name="wxTreeItemIdValue",single=true}) ->
@@ -1127,6 +1132,15 @@ build_gvar({Name, {address,Class}, _Id}, Cnt) ->
w(" rt.addAtom(\"~s\"); rt.addRef(getRef((void *)&~s,memenv), \"~s\");~n",[Name,Name,Class]),
w(" rt.addTupleCount(2);~n"),
Cnt+1;
+build_gvar({Name, {test_if,Test}, _Id}, Cnt) ->
+ w("#if ~s~n", [Test]),
+ w(" rt.addAtom(\"~s\"); rt.addInt(~s);~n", [Name, Name]),
+ w(" rt.addTupleCount(2);~n"),
+ w("#else~n", []),
+ w(" rt.addAtom(\"~s\"); rt.addAtom(\"undefined\");~n", [Name]),
+ w(" rt.addTupleCount(2);~n"),
+ w("#endif~n", []),
+ Cnt+1;
build_gvar({Name, Class, _Id}, Cnt) ->
w(" rt.addAtom(\"~s\"); rt.addRef(getRef((void *)~s,memenv),\"~s\");~n",[Name,Name,Class]),
w(" rt.addTupleCount(2);~n"),
@@ -1151,6 +1165,7 @@ gen_macros() ->
w("#include <wx/fontdlg.h>~n"),
w("#include <wx/progdlg.h>~n"),
w("#include <wx/printdlg.h>~n"),
+ w("#include <wx/display.h>~n"),
w("#include <wx/dcbuffer.h>~n"),
w("#include <wx/dcmirror.h>~n"),
w("#include <wx/glcanvas.h>~n"),
@@ -1162,6 +1177,7 @@ gen_macros() ->
w("#include <wx/sashwin.h>~n"),
w("#include <wx/laywin.h>~n"),
w("#include <wx/graphics.h>~n"),
+ w("#include <wx/dcgraph.h>~n"),
w("#include <wx/aui/aui.h>~n"),
w("#include <wx/datectrl.h>~n"),
w("#include <wx/filepicker.h>~n"),
@@ -1316,8 +1332,10 @@ encode_events(Evs) ->
w(" } else {~n"),
w(" send_res = rt.send();~n"),
w(" if(cb->skip) event->Skip();~n"),
- #class{id=MouseId} = lists:keyfind("wxMouseEvent", #class.name, Evs),
- w(" if(app->recurse_level < 1 && Etype->cID != ~p) {~n", [MouseId]),
+ #class{id=SizeId} = lists:keyfind("wxSizeEvent", #class.name, Evs),
+ #class{id=MoveId} = lists:keyfind("wxMoveEvent", #class.name, Evs),
+ w(" if(app->recurse_level < 1 && (Etype->cID == ~w || Etype->cID == ~w)) {~n",
+ [SizeId, MoveId]),
w(" app->recurse_level++;~n"),
w(" app->dispatch_cmds();~n"),
w(" app->recurse_level--;~n"),
diff --git a/lib/wx/api_gen/wx_gen_erl.erl b/lib/wx/api_gen/wx_gen_erl.erl
index e272c08d90..797533309b 100644
--- a/lib/wx/api_gen/wx_gen_erl.erl
+++ b/lib/wx/api_gen/wx_gen_erl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1106,7 +1106,7 @@ gen_enums_ints() ->
w("-define(wxDefaultSize, {-1,-1}).~n", []),
w("-define(wxDefaultPosition, {-1,-1}).~n", []),
w("~n%% Global Variables~n", []),
- [w("-define(~s, wxe_util:get_const(~s)).~n", [Gvar, Gvar]) ||
+ [w("-define(~s, wxe_util:get_const(~s)).~n", [qoute_atom(Gvar), qoute_atom(Gvar)]) ||
{Gvar,_,_Id} <- get(gvars)],
w("~n%% Enum and defines~n", []),
foldl(fun(Enum= #enum{vals=Vals}, Done) when Vals =/= [] ->
@@ -1115,6 +1115,11 @@ gen_enums_ints() ->
end, gb_sets:empty(), lists:sort(Enums)),
close().
+qoute_atom([Char|_]=Str) when Char < $a ->
+ "'" ++ Str ++ "'";
+qoute_atom(Str) ->
+ Str.
+
build_enum_ints(#enum{from=From, vals=Vals},Done) ->
case From of
{File, undefined, [$@|_]} ->
diff --git a/lib/wx/api_gen/wxapi.conf b/lib/wx/api_gen/wxapi.conf
index 146c9fecc7..9707fedf67 100644
--- a/lib/wx/api_gen/wxapi.conf
+++ b/lib/wx/api_gen/wxapi.conf
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -27,7 +27,7 @@
{not_const, [wxHAS_INT64,wxBYTE_ORDER,wxRETAINED,
wxFONTENCODING_UTF32,wxFONTENCODING_UTF16,
wxDEFAULT_CONTROL_BORDER,wxMOD_CMD,
- wxMAJOR_VERSION, wxMINOR_VERSION,
+ wxMAJOR_VERSION, wxMINOR_VERSION,
wxRELEASE_NUMBER,wxSUBRELEASE_NUMBER,wxBETA_NUMBER,
%%
wxALWAYS_NATIVE_DOUBLE_BUFFER,
@@ -37,16 +37,30 @@
wxCURSOR_DEFAULT,
wxCURSOR_ARROWWAIT,
wxCURSOR_MAX,
- wxLanguage
+ wxLanguage,
+ wxFONTWEIGHT_NORMAL,
+ wxFONTWEIGHT_LIGHT,
+ wxFONTWEIGHT_BOLD,
+ wxFONTWEIGHT_MAX
]}.
-{gvars,
+{gvars,
[
{wxITALIC_FONT, wxFont},
{wxNORMAL_FONT, wxFont},
{wxSMALL_FONT, wxFont},
{wxSWISS_FONT, wxFont},
-
+
+ %% Added (enum) values in 3.1.2
+ {wxFONTWEIGHT_INVALID, {test_if, "wxCHECK_VERSION(3,1,2)"}},
+ {wxFONTWEIGHT_THIN, {test_if, "wxCHECK_VERSION(3,1,2)"}},
+ {wxFONTWEIGHT_EXTRALIGHT, {test_if, "wxCHECK_VERSION(3,1,2)"}},
+ {wxFONTWEIGHT_MEDIUM, {test_if, "wxCHECK_VERSION(3,1,2)"}},
+ {wxFONTWEIGHT_SEMIBOLD, {test_if, "wxCHECK_VERSION(3,1,2)"}},
+ {wxFONTWEIGHT_EXTRABOLD, {test_if, "wxCHECK_VERSION(3,1,2)"}},
+ {wxFONTWEIGHT_HEAVY, {test_if, "wxCHECK_VERSION(3,1,2)"}},
+ {wxFONTWEIGHT_EXTRAHEAVY, {test_if, "wxCHECK_VERSION(3,1,2)"}},
+
{wxBLACK_DASHED_PEN, wxPen},
{wxBLACK_PEN, wxPen},
{wxCYAN_PEN, wxPen},
@@ -87,7 +101,27 @@
{wxNullPen, {address,wxPen}},
{wxNullBrush, {address,wxBrush}},
{wxNullPalette, {address,wxPalette}},
- {wxNullFont, {address,wxFont}}]}.
+ {wxNullFont, {address,wxFont}},
+
+ %% New enums needed for gl contexts not static numbers
+ {'WX_GL_SAMPLE_BUFFERS', {test_if, "wxCHECK_VERSION(3,0,0)"}},
+ {'WX_GL_SAMPLES', {test_if, "wxCHECK_VERSION(3,0,0)"}},
+ {'WX_GL_FRAMEBUFFER_SRGB', {test_if, "wxCHECK_VERSION(3,1,0)"}},
+ {'WX_GL_CORE_PROFILE', {test_if, "wxCHECK_VERSION(3,0,3)"}},
+ {'WX_GL_MAJOR_VERSION', {test_if, "wxCHECK_VERSION(3,0,3)"}},
+ {'WX_GL_MINOR_VERSION', {test_if, "wxCHECK_VERSION(3,0,3)"}},
+ {'wx_GL_COMPAT_PROFILE', {test_if, "wxCHECK_VERSION(3,1,0)"}},
+ {'WX_GL_FORWARD_COMPAT', {test_if, "wxCHECK_VERSION(3,1,0)"}},
+ {'WX_GL_ES2', {test_if, "wxCHECK_VERSION(3,1,0)"}},
+ {'WX_GL_DEBUG', {test_if, "wxCHECK_VERSION(3,1,0)"}},
+ {'WX_GL_ROBUST_ACCESS', {test_if, "wxCHECK_VERSION(3,1,0)"}},
+ {'WX_GL_NO_RESET_NOTIFY', {test_if, "wxCHECK_VERSION(3,1,0)"}},
+ {'WX_GL_LOSE_ON_RESET', {test_if, "wxCHECK_VERSION(3,1,0)"}},
+ {'WX_GL_RESET_ISOLATION', {test_if, "wxCHECK_VERSION(3,1,0)"}},
+ {'WX_GL_RELEASE_FLUSH', {test_if, "wxCHECK_VERSION(3,1,0)"}},
+ {'WX_GL_RELEASE_NONE', {test_if, "wxCHECK_VERSION(3,1,0)"}}
+ ]}.
+
{enum, wxBackgroundStyle, "wxBG_STYLE_"}.
{enum, wxWindowVariant, "wxWINDOW_VARIANT_"}.
{enum, wxBitmapType, "wxBITMAP_TYPE_"}.
@@ -433,7 +467,8 @@
{class, wxGraphicsRenderer, object, [{ifdef, wxUSE_GRAPHICS_CONTEXT}],
['GetDefaultRenderer','CreateContext',
%%'CreateContextFromNativeContext', 'CreateContextFromNativeWindow',
- 'CreatePen','CreateBrush',
+ {'CreatePen', [{where, taylormade}]},
+ 'CreateBrush',
{'CreateLinearGradientBrush', [{deprecated, "!wxCHECK_VERSION(2,9,0)"}]},
{'CreateRadialGradientBrush', [{deprecated, "!wxCHECK_VERSION(2,9,0)"}]},
'CreateFont',
@@ -1995,3 +2030,17 @@
['GetPosition', 'GetNumberOfFiles',
{'GetFiles', [{return, [{single, {list, 'm_noFiles'}}]}]}
]}.
+
+
+{class, wxDisplay, root, [{ifdef, wxUSE_DISPLAY}],
+ ['wxDisplay', '~wxDisplay',
+ 'IsOk',
+ {'GetClientArea', [{test_if, "wxCHECK_VERSION(2,8,12)"}]},
+ 'GetGeometry', 'GetName', 'IsPrimary',
+ 'GetCount', 'GetFromPoint', 'GetFromWindow',
+ {'GetPPI', [{test_if, "wxCHECK_VERSION(3,1,2)"}]}
+ ]}.
+
+{class, wxGCDC, wxDC, [{ifdef, wxUSE_GRAPHICS_CONTEXT}],
+ ['wxGCDC', '~wxGCDC', 'GetGraphicsContext', 'SetGraphicsContext'
+ ]}.
diff --git a/lib/wx/c_src/Makefile.in b/lib/wx/c_src/Makefile.in
index daa8afce83..8ec64bea7e 100644
--- a/lib/wx/c_src/Makefile.in
+++ b/lib/wx/c_src/Makefile.in
@@ -181,6 +181,7 @@ release_spec: opt
$(INSTALL_DIR) "$(RELSYSDIR)/priv"
$(INSTALL_DATA) ../priv/erlang-logo32.png "$(RELSYSDIR)/priv/"
$(INSTALL_DATA) ../priv/erlang-logo64.png "$(RELSYSDIR)/priv/"
+ $(INSTALL_DATA) ../priv/erlang-logo128.png "$(RELSYSDIR)/priv/"
$(INSTALL_PROGRAM) $(TARGET_DIR)/wxe_driver$(SO_EXT) "$(RELSYSDIR)/priv/"
$(INSTALL_PROGRAM) $(TARGET_DIR)/erl_gl$(SO_EXT) "$(RELSYSDIR)/priv/"
diff --git a/lib/wx/c_src/gen/wxe_derived_dest.h b/lib/wx/c_src/gen/wxe_derived_dest.h
index fc0ae0d9fc..a7114eb188 100644
--- a/lib/wx/c_src/gen/wxe_derived_dest.h
+++ b/lib/wx/c_src/gen/wxe_derived_dest.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -799,3 +799,11 @@ class EwxDCOverlay : public wxDCOverlay {
EwxDCOverlay(wxOverlay& overlay,wxWindowDC * dc) : wxDCOverlay(overlay,dc) {};
};
+#if wxUSE_GRAPHICS_CONTEXT
+class EwxGCDC : public wxGCDC {
+ public: ~EwxGCDC() {((WxeApp *)wxTheApp)->clearPtr(this);};
+ EwxGCDC(const wxWindowDC& dc) : wxGCDC(dc) {};
+ EwxGCDC() : wxGCDC() {};
+};
+#endif // wxUSE_GRAPHICS_CONTEXT
+
diff --git a/lib/wx/c_src/gen/wxe_events.cpp b/lib/wx/c_src/gen/wxe_events.cpp
index 01787c8a64..8c3283a670 100644
--- a/lib/wx/c_src/gen/wxe_events.cpp
+++ b/lib/wx/c_src/gen/wxe_events.cpp
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2019. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -910,7 +910,7 @@ case 238: {// wxDropFilesEvent
} else {
send_res = rt.send();
if(cb->skip) event->Skip();
- if(app->recurse_level < 1 && Etype->cID != 168) {
+ if(app->recurse_level < 1 && (Etype->cID == 171 || Etype->cID == 172)) {
app->recurse_level++;
app->dispatch_cmds();
app->recurse_level--;
diff --git a/lib/wx/c_src/gen/wxe_funcs.cpp b/lib/wx/c_src/gen/wxe_funcs.cpp
index a47d602337..32e4bf855b 100644
--- a/lib/wx/c_src/gen/wxe_funcs.cpp
+++ b/lib/wx/c_src/gen/wxe_funcs.cpp
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -6147,18 +6147,18 @@ case wxGraphicsObject_IsNull: { // wxGraphicsObject::IsNull
case wxGraphicsContext_Create_1_1: { // wxGraphicsContext::Create
wxWindowDC * dc = (wxWindowDC *) getPtr(bp,memenv); bp += 4;
wxGraphicsContext * Result = (wxGraphicsContext*)wxGraphicsContext::Create(*dc);
- rt.addRef(getRef((void *)Result,memenv), "wxGraphicsContext");
+ rt.addRef(getRef((void *)Result,memenv,8), "wxGraphicsContext");
break;
}
case wxGraphicsContext_Create_1_0: { // wxGraphicsContext::Create
wxWindow *window = (wxWindow *) getPtr(bp,memenv); bp += 4;
wxGraphicsContext * Result = (wxGraphicsContext*)wxGraphicsContext::Create(window);
- rt.addRef(getRef((void *)Result,memenv), "wxGraphicsContext");
+ rt.addRef(getRef((void *)Result,memenv,8), "wxGraphicsContext");
break;
}
case wxGraphicsContext_Create_0: { // wxGraphicsContext::Create
wxGraphicsContext * Result = (wxGraphicsContext*)wxGraphicsContext::Create();
- rt.addRef(getRef((void *)Result,memenv), "wxGraphicsContext");
+ rt.addRef(getRef((void *)Result,memenv,8), "wxGraphicsContext");
break;
}
case wxGraphicsContext_CreatePen: { // wxGraphicsContext::CreatePen
@@ -6999,7 +6999,7 @@ case wxGraphicsRenderer_CreateContext_1_1: { // wxGraphicsRenderer::CreateContex
wxWindowDC * dc = (wxWindowDC *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
wxGraphicsContext * Result = (wxGraphicsContext*)This->CreateContext(*dc);
- rt.addRef(getRef((void *)Result,memenv), "wxGraphicsContext");
+ rt.addRef(getRef((void *)Result,memenv,8), "wxGraphicsContext");
break;
}
case wxGraphicsRenderer_CreateContext_1_0: { // wxGraphicsRenderer::CreateContext
@@ -7007,16 +7007,44 @@ case wxGraphicsRenderer_CreateContext_1_0: { // wxGraphicsRenderer::CreateContex
wxWindow *window = (wxWindow *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
wxGraphicsContext * Result = (wxGraphicsContext*)This->CreateContext(window);
- rt.addRef(getRef((void *)Result,memenv), "wxGraphicsContext");
+ rt.addRef(getRef((void *)Result,memenv,8), "wxGraphicsContext");
break;
}
-case wxGraphicsRenderer_CreatePen: { // wxGraphicsRenderer::CreatePen
+
+case wxGraphicsRenderer_CreatePen: { // wxGraphicsRenderer::CreatePen taylormade
wxGraphicsRenderer *This = (wxGraphicsRenderer *) getPtr(bp,memenv); bp += 4;
wxPen *pen = (wxPen *) getPtr(bp,memenv); bp += 4;
if(!This) throw wxe_badarg(0);
- wxGraphicsPen * Result = new wxGraphicsPen(This->CreatePen(*pen)); newPtr((void *) Result,4, memenv);;
+#if !wxCHECK_VERSION(3,1,1)
+ wxGraphicsPen * Result = new wxGraphicsPen(This->CreatePen(*pen)); newPtr((void *) Result,4, memenv);
+ rt.addRef(getRef((void *)Result,memenv), "wxGraphicsPen");
+ break;
+#else
+ wxGraphicsPenInfo info = wxGraphicsPenInfo()
+ .Colour(pen->GetColour())
+ .Width(pen->GetWidth())
+ .Style(pen->GetStyle())
+ .Join(pen->GetJoin())
+ .Cap(pen->GetCap())
+ ;
+
+ if ( info.GetStyle() == wxPENSTYLE_USER_DASH )
+ {
+ wxDash *dashes;
+ if ( int nb_dashes = pen->GetDashes(&dashes) )
+ info.Dashes(nb_dashes, dashes);
+ }
+
+ if ( info.GetStyle() == wxPENSTYLE_STIPPLE )
+ {
+ if ( wxBitmap* const stipple = pen->GetStipple() )
+ info.Stipple(*stipple);
+ }
+ wxGraphicsPen * Result = new wxGraphicsPen(This->CreatePen(info));
+ newPtr((void *) Result,4, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxGraphicsPen");
break;
+#endif
}
case wxGraphicsRenderer_CreateBrush: { // wxGraphicsRenderer::CreateBrush
wxGraphicsRenderer *This = (wxGraphicsRenderer *) getPtr(bp,memenv); bp += 4;
@@ -32085,6 +32113,120 @@ case wxDropFilesEvent_GetFiles: { // wxDropFilesEvent::GetFiles
rt.add(tmpArrayStr);
break;
}
+#if wxUSE_DISPLAY
+case wxDisplay_new: { // wxDisplay::wxDisplay
+ int n=0;
+ while( * (int*) bp) { switch (* (int*) bp) {
+ case 1: {bp += 4;
+ n = (int)*(unsigned int *) bp; bp += 4;
+ } break;
+ }};
+ wxDisplay * Result = new wxDisplay(n);
+ newPtr((void *) Result, 239, memenv);
+ rt.addRef(getRef((void *)Result,memenv), "wxDisplay");
+ break;
+}
+case wxDisplay_destruct: { // wxDisplay::~wxDisplay
+ wxDisplay *This = (wxDisplay *) getPtr(bp,memenv); bp += 4;
+ if(This) { ((WxeApp *) wxTheApp)->clearPtr((void *) This);
+ delete This;}
+ break;
+}
+case wxDisplay_IsOk: { // wxDisplay::IsOk
+ wxDisplay *This = (wxDisplay *) getPtr(bp,memenv); bp += 4;
+ if(!This) throw wxe_badarg(0);
+ bool Result = This->IsOk();
+ rt.addBool(Result);
+ break;
+}
+#if wxCHECK_VERSION(2,8,12)
+case wxDisplay_GetClientArea: { // wxDisplay::GetClientArea
+ wxDisplay *This = (wxDisplay *) getPtr(bp,memenv); bp += 4;
+ if(!This) throw wxe_badarg(0);
+ wxRect Result = This->GetClientArea();
+ rt.add(Result);
+ break;
+}
+#endif
+case wxDisplay_GetGeometry: { // wxDisplay::GetGeometry
+ wxDisplay *This = (wxDisplay *) getPtr(bp,memenv); bp += 4;
+ if(!This) throw wxe_badarg(0);
+ wxRect Result = This->GetGeometry();
+ rt.add(Result);
+ break;
+}
+case wxDisplay_GetName: { // wxDisplay::GetName
+ wxDisplay *This = (wxDisplay *) getPtr(bp,memenv); bp += 4;
+ if(!This) throw wxe_badarg(0);
+ wxString Result = This->GetName();
+ rt.add(Result);
+ break;
+}
+case wxDisplay_IsPrimary: { // wxDisplay::IsPrimary
+ wxDisplay *This = (wxDisplay *) getPtr(bp,memenv); bp += 4;
+ if(!This) throw wxe_badarg(0);
+ bool Result = This->IsPrimary();
+ rt.addBool(Result);
+ break;
+}
+case wxDisplay_GetCount: { // wxDisplay::GetCount
+ int Result = wxDisplay::GetCount();
+ rt.addUint(Result);
+ break;
+}
+case wxDisplay_GetFromPoint: { // wxDisplay::GetFromPoint
+ int * ptX = (int *) bp; bp += 4;
+ int * ptY = (int *) bp; bp += 4;
+ wxPoint pt = wxPoint(*ptX,*ptY);
+ int Result = wxDisplay::GetFromPoint(pt);
+ rt.addInt(Result);
+ break;
+}
+case wxDisplay_GetFromWindow: { // wxDisplay::GetFromWindow
+ wxWindow *window = (wxWindow *) getPtr(bp,memenv); bp += 4;
+ int Result = wxDisplay::GetFromWindow(window);
+ rt.addInt(Result);
+ break;
+}
+#if wxCHECK_VERSION(3,1,2)
+case wxDisplay_GetPPI: { // wxDisplay::GetPPI
+ wxDisplay *This = (wxDisplay *) getPtr(bp,memenv); bp += 4;
+ if(!This) throw wxe_badarg(0);
+ wxSize Result = This->GetPPI();
+ rt.add(Result);
+ break;
+}
+#endif
+#endif // wxUSE_DISPLAY
+#if wxUSE_GRAPHICS_CONTEXT
+case wxGCDC_new_1: { // wxGCDC::wxGCDC
+ wxWindowDC *dc = (wxWindowDC *) getPtr(bp,memenv); bp += 4;
+ wxGCDC * Result = new EwxGCDC(*dc);
+ newPtr((void *) Result, 8, memenv);
+ rt.addRef(getRef((void *)Result,memenv), "wxGCDC");
+ break;
+}
+case wxGCDC_new_0: { // wxGCDC::wxGCDC
+ wxGCDC * Result = new EwxGCDC();
+ newPtr((void *) Result, 8, memenv);
+ rt.addRef(getRef((void *)Result,memenv), "wxGCDC");
+ break;
+}
+case wxGCDC_GetGraphicsContext: { // wxGCDC::GetGraphicsContext
+ wxGCDC *This = (wxGCDC *) getPtr(bp,memenv); bp += 4;
+ if(!This) throw wxe_badarg(0);
+ wxGraphicsContext * Result = (wxGraphicsContext*)This->GetGraphicsContext();
+ rt.addRef(getRef((void *)Result,memenv,8), "wxGraphicsContext");
+ break;
+}
+case wxGCDC_SetGraphicsContext: { // wxGCDC::SetGraphicsContext
+ wxGCDC *This = (wxGCDC *) getPtr(bp,memenv); bp += 4;
+ wxGraphicsContext *ctx = (wxGraphicsContext *) getPtr(bp,memenv); bp += 4;
+ if(!This) throw wxe_badarg(0);
+ This->SetGraphicsContext(ctx);
+ break;
+}
+#endif // wxUSE_GRAPHICS_CONTEXT
default: {
wxeReturn error = wxeReturn(WXE_DRV_PORT, Ecmd.caller, false); error.addAtom("_wxe_error_");
error.addInt((int) op);
@@ -32146,6 +32288,7 @@ bool WxeApp::delete_object(void *ptr, wxeRefData *refd) {
case 231: delete (EwxLocale *) ptr; return false;
case 236: delete (wxOverlay *) ptr; break;
case 237: delete (EwxDCOverlay *) ptr; return false;
+ case 239: delete (wxDisplay *) ptr; break;
default: delete (wxObject *) ptr; return false;
}
return true;
diff --git a/lib/wx/c_src/gen/wxe_init.cpp b/lib/wx/c_src/gen/wxe_init.cpp
index 1e432e34ce..5a52d69003 100644
--- a/lib/wx/c_src/gen/wxe_init.cpp
+++ b/lib/wx/c_src/gen/wxe_init.cpp
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2015. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -55,6 +55,14 @@ void WxeApp::init_nonconsts(wxeMemEnv *memenv, ErlDrvTermData caller) {
rt.addTupleCount(2);
rt.addAtom("wxFONTENCODING_UTF32"); rt.addInt(wxFONTENCODING_UTF32);
rt.addTupleCount(2);
+ rt.addAtom("wxFONTWEIGHT_BOLD"); rt.addInt(wxFONTWEIGHT_BOLD);
+ rt.addTupleCount(2);
+ rt.addAtom("wxFONTWEIGHT_LIGHT"); rt.addInt(wxFONTWEIGHT_LIGHT);
+ rt.addTupleCount(2);
+ rt.addAtom("wxFONTWEIGHT_MAX"); rt.addInt(wxFONTWEIGHT_MAX);
+ rt.addTupleCount(2);
+ rt.addAtom("wxFONTWEIGHT_NORMAL"); rt.addInt(wxFONTWEIGHT_NORMAL);
+ rt.addTupleCount(2);
rt.addAtom("wxMOD_CMD"); rt.addInt(wxMOD_CMD);
rt.addTupleCount(2);
rt.addAtom("wxLANGUAGE_ABKHAZIAN"); rt.addInt(wxLANGUAGE_ABKHAZIAN);
@@ -529,6 +537,111 @@ void WxeApp::init_nonconsts(wxeMemEnv *memenv, ErlDrvTermData caller) {
rt.addTupleCount(2);
rt.addAtom("wxCURSOR_MAX"); rt.addInt(wxCURSOR_MAX);
rt.addTupleCount(2);
+#if wxCHECK_VERSION(3,0,3)
+ rt.addAtom("WX_GL_CORE_PROFILE"); rt.addInt(WX_GL_CORE_PROFILE);
+ rt.addTupleCount(2);
+#else
+ rt.addAtom("WX_GL_CORE_PROFILE"); rt.addAtom("undefined");
+ rt.addTupleCount(2);
+#endif
+#if wxCHECK_VERSION(3,1,0)
+ rt.addAtom("WX_GL_DEBUG"); rt.addInt(WX_GL_DEBUG);
+ rt.addTupleCount(2);
+#else
+ rt.addAtom("WX_GL_DEBUG"); rt.addAtom("undefined");
+ rt.addTupleCount(2);
+#endif
+#if wxCHECK_VERSION(3,1,0)
+ rt.addAtom("WX_GL_ES2"); rt.addInt(WX_GL_ES2);
+ rt.addTupleCount(2);
+#else
+ rt.addAtom("WX_GL_ES2"); rt.addAtom("undefined");
+ rt.addTupleCount(2);
+#endif
+#if wxCHECK_VERSION(3,1,0)
+ rt.addAtom("WX_GL_FORWARD_COMPAT"); rt.addInt(WX_GL_FORWARD_COMPAT);
+ rt.addTupleCount(2);
+#else
+ rt.addAtom("WX_GL_FORWARD_COMPAT"); rt.addAtom("undefined");
+ rt.addTupleCount(2);
+#endif
+#if wxCHECK_VERSION(3,1,0)
+ rt.addAtom("WX_GL_FRAMEBUFFER_SRGB"); rt.addInt(WX_GL_FRAMEBUFFER_SRGB);
+ rt.addTupleCount(2);
+#else
+ rt.addAtom("WX_GL_FRAMEBUFFER_SRGB"); rt.addAtom("undefined");
+ rt.addTupleCount(2);
+#endif
+#if wxCHECK_VERSION(3,1,0)
+ rt.addAtom("WX_GL_LOSE_ON_RESET"); rt.addInt(WX_GL_LOSE_ON_RESET);
+ rt.addTupleCount(2);
+#else
+ rt.addAtom("WX_GL_LOSE_ON_RESET"); rt.addAtom("undefined");
+ rt.addTupleCount(2);
+#endif
+#if wxCHECK_VERSION(3,0,3)
+ rt.addAtom("WX_GL_MAJOR_VERSION"); rt.addInt(WX_GL_MAJOR_VERSION);
+ rt.addTupleCount(2);
+#else
+ rt.addAtom("WX_GL_MAJOR_VERSION"); rt.addAtom("undefined");
+ rt.addTupleCount(2);
+#endif
+#if wxCHECK_VERSION(3,0,3)
+ rt.addAtom("WX_GL_MINOR_VERSION"); rt.addInt(WX_GL_MINOR_VERSION);
+ rt.addTupleCount(2);
+#else
+ rt.addAtom("WX_GL_MINOR_VERSION"); rt.addAtom("undefined");
+ rt.addTupleCount(2);
+#endif
+#if wxCHECK_VERSION(3,1,0)
+ rt.addAtom("WX_GL_NO_RESET_NOTIFY"); rt.addInt(WX_GL_NO_RESET_NOTIFY);
+ rt.addTupleCount(2);
+#else
+ rt.addAtom("WX_GL_NO_RESET_NOTIFY"); rt.addAtom("undefined");
+ rt.addTupleCount(2);
+#endif
+#if wxCHECK_VERSION(3,1,0)
+ rt.addAtom("WX_GL_RELEASE_FLUSH"); rt.addInt(WX_GL_RELEASE_FLUSH);
+ rt.addTupleCount(2);
+#else
+ rt.addAtom("WX_GL_RELEASE_FLUSH"); rt.addAtom("undefined");
+ rt.addTupleCount(2);
+#endif
+#if wxCHECK_VERSION(3,1,0)
+ rt.addAtom("WX_GL_RELEASE_NONE"); rt.addInt(WX_GL_RELEASE_NONE);
+ rt.addTupleCount(2);
+#else
+ rt.addAtom("WX_GL_RELEASE_NONE"); rt.addAtom("undefined");
+ rt.addTupleCount(2);
+#endif
+#if wxCHECK_VERSION(3,1,0)
+ rt.addAtom("WX_GL_RESET_ISOLATION"); rt.addInt(WX_GL_RESET_ISOLATION);
+ rt.addTupleCount(2);
+#else
+ rt.addAtom("WX_GL_RESET_ISOLATION"); rt.addAtom("undefined");
+ rt.addTupleCount(2);
+#endif
+#if wxCHECK_VERSION(3,1,0)
+ rt.addAtom("WX_GL_ROBUST_ACCESS"); rt.addInt(WX_GL_ROBUST_ACCESS);
+ rt.addTupleCount(2);
+#else
+ rt.addAtom("WX_GL_ROBUST_ACCESS"); rt.addAtom("undefined");
+ rt.addTupleCount(2);
+#endif
+#if wxCHECK_VERSION(3,0,0)
+ rt.addAtom("WX_GL_SAMPLES"); rt.addInt(WX_GL_SAMPLES);
+ rt.addTupleCount(2);
+#else
+ rt.addAtom("WX_GL_SAMPLES"); rt.addAtom("undefined");
+ rt.addTupleCount(2);
+#endif
+#if wxCHECK_VERSION(3,0,0)
+ rt.addAtom("WX_GL_SAMPLE_BUFFERS"); rt.addInt(WX_GL_SAMPLE_BUFFERS);
+ rt.addTupleCount(2);
+#else
+ rt.addAtom("WX_GL_SAMPLE_BUFFERS"); rt.addAtom("undefined");
+ rt.addTupleCount(2);
+#endif
rt.addAtom("wxBLACK"); rt.add(*(wxBLACK));
rt.addTupleCount(2);
rt.addAtom("wxBLACK_BRUSH"); rt.addRef(getRef((void *)wxBLACK_BRUSH,memenv),"wxBrush");
@@ -549,6 +662,62 @@ void WxeApp::init_nonconsts(wxeMemEnv *memenv, ErlDrvTermData caller) {
rt.addTupleCount(2);
rt.addAtom("wxCYAN_PEN"); rt.addRef(getRef((void *)wxCYAN_PEN,memenv),"wxPen");
rt.addTupleCount(2);
+#if wxCHECK_VERSION(3,1,2)
+ rt.addAtom("wxFONTWEIGHT_EXTRABOLD"); rt.addInt(wxFONTWEIGHT_EXTRABOLD);
+ rt.addTupleCount(2);
+#else
+ rt.addAtom("wxFONTWEIGHT_EXTRABOLD"); rt.addAtom("undefined");
+ rt.addTupleCount(2);
+#endif
+#if wxCHECK_VERSION(3,1,2)
+ rt.addAtom("wxFONTWEIGHT_EXTRAHEAVY"); rt.addInt(wxFONTWEIGHT_EXTRAHEAVY);
+ rt.addTupleCount(2);
+#else
+ rt.addAtom("wxFONTWEIGHT_EXTRAHEAVY"); rt.addAtom("undefined");
+ rt.addTupleCount(2);
+#endif
+#if wxCHECK_VERSION(3,1,2)
+ rt.addAtom("wxFONTWEIGHT_EXTRALIGHT"); rt.addInt(wxFONTWEIGHT_EXTRALIGHT);
+ rt.addTupleCount(2);
+#else
+ rt.addAtom("wxFONTWEIGHT_EXTRALIGHT"); rt.addAtom("undefined");
+ rt.addTupleCount(2);
+#endif
+#if wxCHECK_VERSION(3,1,2)
+ rt.addAtom("wxFONTWEIGHT_HEAVY"); rt.addInt(wxFONTWEIGHT_HEAVY);
+ rt.addTupleCount(2);
+#else
+ rt.addAtom("wxFONTWEIGHT_HEAVY"); rt.addAtom("undefined");
+ rt.addTupleCount(2);
+#endif
+#if wxCHECK_VERSION(3,1,2)
+ rt.addAtom("wxFONTWEIGHT_INVALID"); rt.addInt(wxFONTWEIGHT_INVALID);
+ rt.addTupleCount(2);
+#else
+ rt.addAtom("wxFONTWEIGHT_INVALID"); rt.addAtom("undefined");
+ rt.addTupleCount(2);
+#endif
+#if wxCHECK_VERSION(3,1,2)
+ rt.addAtom("wxFONTWEIGHT_MEDIUM"); rt.addInt(wxFONTWEIGHT_MEDIUM);
+ rt.addTupleCount(2);
+#else
+ rt.addAtom("wxFONTWEIGHT_MEDIUM"); rt.addAtom("undefined");
+ rt.addTupleCount(2);
+#endif
+#if wxCHECK_VERSION(3,1,2)
+ rt.addAtom("wxFONTWEIGHT_SEMIBOLD"); rt.addInt(wxFONTWEIGHT_SEMIBOLD);
+ rt.addTupleCount(2);
+#else
+ rt.addAtom("wxFONTWEIGHT_SEMIBOLD"); rt.addAtom("undefined");
+ rt.addTupleCount(2);
+#endif
+#if wxCHECK_VERSION(3,1,2)
+ rt.addAtom("wxFONTWEIGHT_THIN"); rt.addInt(wxFONTWEIGHT_THIN);
+ rt.addTupleCount(2);
+#else
+ rt.addAtom("wxFONTWEIGHT_THIN"); rt.addAtom("undefined");
+ rt.addTupleCount(2);
+#endif
rt.addAtom("wxGREEN"); rt.add(*(wxGREEN));
rt.addTupleCount(2);
rt.addAtom("wxGREEN_BRUSH"); rt.addRef(getRef((void *)wxGREEN_BRUSH,memenv),"wxBrush");
@@ -611,7 +780,14 @@ void WxeApp::init_nonconsts(wxeMemEnv *memenv, ErlDrvTermData caller) {
rt.addTupleCount(2);
rt.addAtom("wxWHITE_PEN"); rt.addRef(getRef((void *)wxWHITE_PEN,memenv),"wxPen");
rt.addTupleCount(2);
- rt.endList(293);
+#if wxCHECK_VERSION(3,1,0)
+ rt.addAtom("wx_GL_COMPAT_PROFILE"); rt.addInt(wx_GL_COMPAT_PROFILE);
+ rt.addTupleCount(2);
+#else
+ rt.addAtom("wx_GL_COMPAT_PROFILE"); rt.addAtom("undefined");
+ rt.addTupleCount(2);
+#endif
+ rt.endList(321);
rt.addTupleCount(2);
rt.send();
}
diff --git a/lib/wx/c_src/gen/wxe_macros.h b/lib/wx/c_src/gen/wxe_macros.h
index 4c8e52def2..c23e8a83bd 100644
--- a/lib/wx/c_src/gen/wxe_macros.h
+++ b/lib/wx/c_src/gen/wxe_macros.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -35,6 +35,7 @@
#include <wx/fontdlg.h>
#include <wx/progdlg.h>
#include <wx/printdlg.h>
+#include <wx/display.h>
#include <wx/dcbuffer.h>
#include <wx/dcmirror.h>
#include <wx/glcanvas.h>
@@ -46,6 +47,7 @@
#include <wx/sashwin.h>
#include <wx/laywin.h>
#include <wx/graphics.h>
+#include <wx/dcgraph.h>
#include <wx/aui/aui.h>
#include <wx/datectrl.h>
#include <wx/filepicker.h>
@@ -3426,5 +3428,21 @@
#define wxDropFilesEvent_GetPosition 3597
#define wxDropFilesEvent_GetNumberOfFiles 3598
#define wxDropFilesEvent_GetFiles 3599
+#define wxDisplay_new 3600
+#define wxDisplay_destruct 3601
+#define wxDisplay_IsOk 3602
+#define wxDisplay_GetClientArea 3603
+#define wxDisplay_GetGeometry 3604
+#define wxDisplay_GetName 3605
+#define wxDisplay_IsPrimary 3606
+#define wxDisplay_GetCount 3607
+#define wxDisplay_GetFromPoint 3608
+#define wxDisplay_GetFromWindow 3609
+#define wxDisplay_GetPPI 3610
+#define wxGCDC_new_1 3611
+#define wxGCDC_new_0 3612
+#define wxGCDC_destruct 3613
+#define wxGCDC_GetGraphicsContext 3614
+#define wxGCDC_SetGraphicsContext 3615
diff --git a/lib/wx/c_src/wxe_driver.c b/lib/wx/c_src/wxe_driver.c
index 26ae3564e7..c9d299e0df 100644
--- a/lib/wx/c_src/wxe_driver.c
+++ b/lib/wx/c_src/wxe_driver.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -38,10 +38,8 @@
#define TEMP_BINARY_SIZE 512
-static ErlDrvData wxe_driver_start(ErlDrvPort port, char *buff);
-static int wxe_driver_load(void);
+static ErlDrvData wxe_driver_start(ErlDrvPort port, char *command);
static void wxe_driver_stop(ErlDrvData handle);
-static void wxe_driver_unload(void);
static ErlDrvSSizeT wxe_driver_control(ErlDrvData handle,
unsigned int command,
char* buf, ErlDrvSizeT count,
@@ -63,30 +61,30 @@ char * erl_wx_privdir;
** The driver struct
*/
static ErlDrvEntry wxe_driver_entry = {
- wxe_driver_load, /* F_PTR init, called at loading */
- wxe_driver_start, /* L_PTR start, called when port is opened */
- wxe_driver_stop, /* F_PTR stop, called when port is closed */
- NULL, /* F_PTR output, called when erlang has sent */
- NULL, /* F_PTR ready_input, called when input descriptor
- ready */
- NULL, /* F_PTR ready_output, called when output
- descriptor ready */
- "wxe_driver", /* char *driver_name, the argument to open_port */
- wxe_driver_unload, /* F_PTR finish, called when unloaded */
- NULL, /* void * that is not used (BC) */
- wxe_driver_control, /* F_PTR control, port_control callback */
- NULL, /* F_PTR timeout, reserved */
- standard_outputv, /* F_PTR outputv, reserved */
- NULL, /* async */
- NULL, /* flush */
- wxe_driver_call, /* call */
- NULL, /* Event */
+ NULL, /* F_PTR init, called at loading */
+ wxe_driver_start, /* L_PTR start, called when port is opened */
+ wxe_driver_stop, /* F_PTR stop, called when port is closed */
+ NULL, /* F_PTR output, called when erlang has sent */
+ NULL, /* F_PTR ready_input, called when
+ input descriptor ready */
+ NULL, /* F_PTR ready_output, called when
+ output descriptor ready */
+ "wxe_driver", /* char *driver_name, the argument to open_port */
+ NULL, /* F_PTR finish, called when unloaded */
+ NULL, /* void * that is not used (BC) */
+ wxe_driver_control, /* F_PTR control, port_control callback */
+ NULL, /* F_PTR timeout, reserved */
+ standard_outputv, /* F_PTR outputv, reserved */
+ NULL, /* async */
+ NULL, /* flush */
+ wxe_driver_call, /* call */
+ NULL, /* Event */
ERL_DRV_EXTENDED_MARKER,
ERL_DRV_EXTENDED_MAJOR_VERSION,
ERL_DRV_EXTENDED_MINOR_VERSION,
- ERL_DRV_FLAG_USE_PORT_LOCKING, /* Port lock */
- NULL, /* Reserved Handle */
- wxe_process_died, /* Process Exited */
+ ERL_DRV_FLAG_USE_PORT_LOCKING, /* Port lock */
+ NULL, /* Reserved Handle */
+ wxe_process_died, /* Process Exited */
};
DRIVER_INIT(wxe_driver)
@@ -94,60 +92,56 @@ DRIVER_INIT(wxe_driver)
return &wxe_driver_entry;
}
-int wxe_driver_load()
-{
- if(load_native_gui())
- return 0;
- else
- return -1;
-}
-
ErlDrvPort WXE_DRV_PORT_HANDLE = 0;
ErlDrvTermData WXE_DRV_PORT = 0;
static ErlDrvData
-wxe_driver_start(ErlDrvPort port, char *buff)
-{
- wxe_data *data;
-
- data = (wxe_data *) malloc(sizeof(wxe_data));
- wxe_debug = 0;
-
- if (data == NULL) {
- fprintf(stderr, " Couldn't alloc mem\r\n");
- return(ERL_DRV_ERROR_GENERAL); /* ENOMEM */
- } else {
- ErlDrvTermData term_port = driver_mk_port(port);
- set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY);
- data->driver_data = NULL;
- data->bin = (WXEBinRef*) driver_alloc(sizeof(WXEBinRef)*DEF_BINS);
- data->bin[0].from = 0;
- data->bin[1].from = 0;
- data->bin[2].from = 0;
- data->max_bins = DEF_BINS;
- data->port_handle = port;
- data->port = term_port;
- data->pdl = driver_pdl_create(port);
- if(WXE_DRV_PORT_HANDLE == 0) {
- for(; *buff != 32; buff++);
- buff++;
- erl_wx_privdir = strdup(buff);
-
- WXE_DRV_PORT_HANDLE = port;
- WXE_DRV_PORT = term_port;
- wxe_master = data;
- if(!(start_native_gui(data) == 1))
- return(ERL_DRV_ERROR_GENERAL); /* ENOMEM */
- } else {
- meta_command(CREATE_PORT,data);
- }
- return (ErlDrvData) data;
- }
+wxe_driver_start(ErlDrvPort port, char *command)
+{
+ wxe_data *data;
+
+ data = (wxe_data *) malloc(sizeof(wxe_data));
+ wxe_debug = 0;
+
+ if (data == NULL) {
+ fprintf(stderr, " Couldn't alloc mem\r\n");
+ return(ERL_DRV_ERROR_GENERAL); /* ENOMEM */
+ } else {
+ ErlDrvTermData term_port = driver_mk_port(port);
+ set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY);
+ data->driver_data = NULL;
+ data->bin = (WXEBinRef*) driver_alloc(sizeof(WXEBinRef)*DEF_BINS);
+ data->bin[0].from = 0;
+ data->bin[1].from = 0;
+ data->bin[2].from = 0;
+ data->max_bins = DEF_BINS;
+ data->port_handle = port;
+ data->port = term_port;
+ data->pdl = driver_pdl_create(port);
+ if(WXE_DRV_PORT_HANDLE == 0) {
+ char *first_space = strchr(command, ' ');
+ if (first_space) {
+ char *priv_dir = first_space + 1;
+ erl_wx_privdir = strdup(priv_dir);
+
+ WXE_DRV_PORT_HANDLE = port;
+ WXE_DRV_PORT = term_port;
+ wxe_master = data;
+ if(start_native_gui(data) != 1)
+ return ERL_DRV_ERROR_GENERAL; /* ENOMEM */
+ } else {
+ return ERL_DRV_ERROR_BADARG;
+ }
+ } else {
+ meta_command(CREATE_PORT, data);
+ }
+ return (ErlDrvData) data;
+ }
}
static void
wxe_driver_stop(ErlDrvData handle)
-{
+{
wxe_data *sd = ((wxe_data *)handle);
if(sd->port_handle != WXE_DRV_PORT_HANDLE) {
// fprintf(stderr, "%s:%d: STOP \r\n", __FILE__,__LINE__);
@@ -155,18 +149,11 @@ wxe_driver_stop(ErlDrvData handle)
} else {
// fprintf(stderr, "%s:%d: STOP \r\n", __FILE__,__LINE__);
stop_native_gui(wxe_master);
- unload_native_gui();
free(wxe_master);
wxe_master = NULL;
}
}
-static void
-wxe_driver_unload(void)
-{
- // fprintf(stderr, "%s:%d: UNLOAD \r\n", __FILE__,__LINE__);
-}
-
static ErlDrvSSizeT
wxe_driver_control(ErlDrvData handle, unsigned op,
char* buf, ErlDrvSizeT count,
@@ -194,7 +181,7 @@ wxe_driver_call(ErlDrvData handle, unsigned int command,
if (len > rlen)
*res = driver_alloc(len);
memcpy((void *) *res, (void *) buf, len);
- return len;
+ return len;
}
@@ -219,20 +206,20 @@ standard_outputv(ErlDrvData drv_data, ErlIOVec* ev)
int i, max;
for(i = 0; i < sd->max_bins; i++) {
- if(sd->bin[i].from == 0) {
- binref = &sd->bin[i];
- break;
- }
+ if(sd->bin[i].from == 0) {
+ binref = &sd->bin[i];
+ break;
+ }
}
if(binref == NULL) { /* realloc */
- max = sd->max_bins + DEF_BINS;
- driver_realloc(sd->bin, sizeof(WXEBinRef)*max);
- for(i=sd->max_bins; i < max; i++) {
- sd->bin[i].from = 0;
- }
- binref = &sd->bin[sd->max_bins];
- sd->max_bins = max;
+ max = sd->max_bins + DEF_BINS;
+ driver_realloc(sd->bin, sizeof(WXEBinRef)*max);
+ for(i=sd->max_bins; i < max; i++) {
+ sd->bin[i].from = 0;
+ }
+ binref = &sd->bin[sd->max_bins];
+ sd->max_bins = max;
}
if(ev->size > 0) {
diff --git a/lib/wx/c_src/wxe_driver.h b/lib/wx/c_src/wxe_driver.h
index f9bca049c8..6d6a67fa85 100644
--- a/lib/wx/c_src/wxe_driver.h
+++ b/lib/wx/c_src/wxe_driver.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -56,10 +56,8 @@ typedef struct wxe_data_def {
void init_glexts(wxe_data*);
-int load_native_gui();
int start_native_gui(wxe_data *sd);
void stop_native_gui(wxe_data *sd);
-void unload_native_gui();
#define FUNC_CALL 13
#define CREATE_PORT 14
diff --git a/lib/wx/c_src/wxe_helpers.cpp b/lib/wx/c_src/wxe_helpers.cpp
index d1f607d2af..47955494f9 100644
--- a/lib/wx/c_src/wxe_helpers.cpp
+++ b/lib/wx/c_src/wxe_helpers.cpp
@@ -101,7 +101,7 @@ wxeCommand * wxeFifo::Peek(unsigned int *i)
}
-void wxeFifo::Add(int fc, char * cbuf,int buflen, wxe_data *sd)
+int wxeFifo::Add(int fc, char * cbuf,int buflen, wxe_data *sd)
{
unsigned int pos;
wxeCommand *curr;
@@ -144,6 +144,7 @@ void wxeFifo::Add(int fc, char * cbuf,int buflen, wxe_data *sd)
} else { // No-op only PING currently
curr->buffer = NULL;
}
+ return m_n;
}
void wxeFifo::Append(wxeCommand *orig)
diff --git a/lib/wx/c_src/wxe_helpers.h b/lib/wx/c_src/wxe_helpers.h
index 70ffccdc13..a6c00e5aca 100644
--- a/lib/wx/c_src/wxe_helpers.h
+++ b/lib/wx/c_src/wxe_helpers.h
@@ -63,7 +63,7 @@ class wxeFifo {
wxeFifo(unsigned int size);
virtual ~wxeFifo();
- void Add(int fc, char * cbuf,int buflen, wxe_data *);
+ int Add(int fc, char * cbuf,int buflen, wxe_data *);
void Append(wxeCommand *Other);
wxeCommand * Get();
diff --git a/lib/wx/c_src/wxe_impl.cpp b/lib/wx/c_src/wxe_impl.cpp
index 1510866f09..43b5476073 100644
--- a/lib/wx/c_src/wxe_impl.cpp
+++ b/lib/wx/c_src/wxe_impl.cpp
@@ -70,7 +70,7 @@ void push_command(int op,char * buf,int len, wxe_data *sd)
/* fprintf(stderr, "Op %d %d [%ld] %d\r\n", op, (int) driver_caller(sd->port_handle),
wxe_batch->size(), wxe_batch_caller),fflush(stderr); */
erl_drv_mutex_lock(wxe_batch_locker_m);
- wxe_queue->Add(op, buf, len, sd);
+ int n = wxe_queue->Add(op, buf, len, sd);
if(wxe_needs_signal) {
// wx-thread is waiting on batch end in cond_wait
@@ -79,7 +79,7 @@ void push_command(int op,char * buf,int len, wxe_data *sd)
} else {
// wx-thread is waiting gui-events
erl_drv_mutex_unlock(wxe_batch_locker_m);
- wxWakeUpIdle();
+ if(n < 2) wxWakeUpIdle();
}
}
@@ -267,7 +267,7 @@ int WxeApp::dispatch_cmds()
return more;
}
-#define BREAK_BATCH 10000
+#define CHECK_EVENTS 10000
int WxeApp::dispatch(wxeFifo * batch)
{
@@ -278,13 +278,14 @@ int WxeApp::dispatch(wxeFifo * batch)
erl_drv_mutex_lock(wxe_batch_locker_m);
while(true) {
while((event = batch->Get()) != NULL) {
+ wait += 1;
erl_drv_mutex_unlock(wxe_batch_locker_m);
switch(event->op) {
case WXE_BATCH_END:
if(blevel>0) {
blevel--;
if(blevel==0)
- wait += BREAK_BATCH/4;
+ wait += CHECK_EVENTS/4;
}
break;
case WXE_BATCH_BEGIN:
@@ -314,21 +315,18 @@ int WxeApp::dispatch(wxeFifo * batch)
break;
}
event->Delete();
+ if(wait > CHECK_EVENTS)
+ return 1; // Let wx check for events
erl_drv_mutex_lock(wxe_batch_locker_m);
batch->Cleanup();
}
- if(blevel <= 0 || wait >= BREAK_BATCH) {
+ if(blevel <= 0) {
erl_drv_mutex_unlock(wxe_batch_locker_m);
- if(blevel > 0) {
- return 1; // We are still in a batch but we can let wx check for events
- } else {
- return 0;
- }
+ return 0;
}
// sleep until something happens
// fprintf(stderr, "%s:%d sleep %d %d %d\r\n", __FILE__, __LINE__, batch->m_n, blevel, wait);fflush(stderr);
wxe_needs_signal = 1;
- wait += 1;
while(batch->m_n == 0) {
erl_drv_cond_wait(wxe_batch_locker_c, wxe_batch_locker_m);
}
@@ -591,7 +589,7 @@ int WxeApp::newPtr(void * ptr, int type, wxeMemEnv *memenv) {
return ref;
}
-int WxeApp::getRef(void * ptr, wxeMemEnv *memenv) {
+int WxeApp::getRef(void * ptr, wxeMemEnv *memenv, int type) {
if(!ptr) return 0; // NULL and zero is the same
ptrMap::iterator it = ptr2ref.find(ptr);
if(it != ptr2ref.end()) {
@@ -618,7 +616,7 @@ int WxeApp::getRef(void * ptr, wxeMemEnv *memenv) {
}
memenv->ref2ptr[ref] = ptr;
- ptr2ref[ptr] = new wxeRefData(ref, 0, false, memenv);
+ ptr2ref[ptr] = new wxeRefData(ref, type, false, memenv);
return ref;
}
diff --git a/lib/wx/c_src/wxe_impl.h b/lib/wx/c_src/wxe_impl.h
index 140a2bd36a..69cc81c429 100644
--- a/lib/wx/c_src/wxe_impl.h
+++ b/lib/wx/c_src/wxe_impl.h
@@ -84,7 +84,7 @@ public:
wxeMemEnv * getMemEnv(ErlDrvTermData port);
int newPtr(void * ptr, int type, wxeMemEnv *memenv);
- int getRef(void * ptr, wxeMemEnv *memenv);
+ int getRef(void * ptr, wxeMemEnv *memenv, int type = 0);
void * getPtr(char * bp, wxeMemEnv *memenv);
void clearPtr(void *ptr);
wxeRefData * getRefData(void *ptr);
diff --git a/lib/wx/c_src/wxe_main.cpp b/lib/wx/c_src/wxe_main.cpp
index c7565e33bd..5b65d8a59b 100644
--- a/lib/wx/c_src/wxe_main.cpp
+++ b/lib/wx/c_src/wxe_main.cpp
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2014-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2014-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -59,15 +59,9 @@ void *wxe_main_loop(void * );
* START AND STOP of driver thread
* ************************************************************/
-int load_native_gui()
-{
- return 1;
-}
-
int start_native_gui(wxe_data *sd)
{
int res;
- ErlDrvThreadOpts *opts = NULL;
wxe_status_m = erl_drv_mutex_create((char *) "wxe_status_m");
wxe_status_c = erl_drv_cond_create((char *)"wxe_status_c");
@@ -79,7 +73,7 @@ int start_native_gui(wxe_data *sd)
res = erl_drv_steal_main_thread((char *)"wxwidgets",
&wxe_thread,wxe_main_loop,(void *) sd->pdl,NULL);
#else
- opts = erl_drv_thread_opts_create((char *)"wx thread");
+ ErlDrvThreadOpts *opts = erl_drv_thread_opts_create((char *)"wx thread");
opts->suggested_stack_size = 8192;
res = erl_drv_thread_create((char *)"wxwidgets",
&wxe_thread,wxe_main_loop,(void *) sd->pdl,opts);
@@ -116,11 +110,6 @@ void stop_native_gui(wxe_data *sd)
erl_drv_cond_destroy(wxe_batch_locker_c);
}
-void unload_native_gui()
-{
-
-}
-
/* ************************************************************
* wxWidgets Thread
* ************************************************************/
diff --git a/lib/wx/c_src/wxe_ps_init.c b/lib/wx/c_src/wxe_ps_init.c
index e6b677d469..62c7c51c13 100644
--- a/lib/wx/c_src/wxe_ps_init.c
+++ b/lib/wx/c_src/wxe_ps_init.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -61,19 +61,36 @@ int is_packaged_app() {
void * wxe_ps_init2() {
NSAutoreleasePool *pool;
ProcessSerialNumber psn;
+ size_t app_len = 127;
+ char app_title_buf[128];
+ char * app_title;
+ size_t app_icon_len = 1023;
+ char app_icon_buf[1024];
+ char * app_icon;
// Setup and enable gui
pool = [[NSAutoreleasePool alloc] init];
-
+
if( !is_packaged_app() ) {
// Undocumented function (but no documented way of doing this exists)
- char *app_title = getenv("WX_APP_TITLE");
+ int res = erl_drv_getenv("WX_APP_TITLE", app_title_buf, &app_len);
+ if (res >= 0) {
+ app_title = app_title_buf;
+ } else {
+ app_title = NULL;
+ }
if(!GetCurrentProcess(&psn)) {
CPSSetProcessName(&psn, app_title?app_title:"Erlang");
}
- // Load and set icon
+ // Enable setting custom application icon for Mac OS X
+ res = erl_drv_getenv("WX_APP_ICON", app_icon_buf, &app_icon_len);
NSMutableString *file = [[NSMutableString alloc] init];
- [file appendFormat:@"%s/%s", erl_wx_privdir, "erlang-logo64.png"];
+ if (res >= 0) {
+ [file appendFormat:@"%s", app_icon_buf];
+ } else {
+ [file appendFormat:@"%s/%s", erl_wx_privdir, "erlang-logo128.png"];
+ }
+ // Load and set icon
NSImage *icon = [[NSImage alloc] initWithContentsOfFile: file];
[NSApp setApplicationIconImage: icon];
};
diff --git a/lib/wx/doc/overview.edoc b/lib/wx/doc/overview.edoc
index 054016f515..843a9c1320 100644
--- a/lib/wx/doc/overview.edoc
+++ b/lib/wx/doc/overview.edoc
@@ -218,7 +218,7 @@ the <em>fun</em> returns.
The callbacks are always invoked by another process and have
exclusive usage of the GUI when invoked. This means that a callback <em>fun</em>
-can not use the process dictionary and should not make calls to other
+cannot use the process dictionary and should not make calls to other
processes. Calls to another process inside a callback <em>fun</em> may cause a
deadlock if the other process is waiting on completion of his call to
the GUI.
diff --git a/lib/wx/doc/src/Makefile b/lib/wx/doc/src/Makefile
index a76740adf1..f66d63f63b 100644
--- a/lib/wx/doc/src/Makefile
+++ b/lib/wx/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2008-2017. All Rights Reserved.
+# Copyright Ericsson AB 2008-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -46,9 +46,13 @@ XML_NOTES_FILES = notes.xml
BOOK_FILES = book.xml
XML_FILES = \
- $(BOOK_FILES) $(XML_CHAPTER_FILES) \
- $(XML_PART_FILES) $(XML_REF3_FILES) \
- $(XML_NOTES_FILES) $(XML_APPLICATION_FILES)
+ $(BOOK_FILES) \
+ $(XML_PART_FILES) $(XML_NOTES_FILES)
+
+XML_GEN_FILES = \
+ $(XML_CHAPTER_FILES:%=$(XMLDIR)/%) \
+ $(XML_REF3_FILES:%=$(XMLDIR)/%) \
+ $(XML_APPLICATION_FILES:%=$(XMLDIR)/%)
# ----------------------------------------------------
INFO_FILE = ../../info
@@ -93,32 +97,37 @@ gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
xml: $(XML_REF3_FILES) $(XML_CHAPTER_FILES)
ref_man.xml: ref_man.xml.src
- @echo Preparing ref_man.xml
- @cat ref_man.xml.src > ref_man.xml
+ @echo Preparing $@
+ @cat ref_man.xml.src > $@
@for d in $(ModsNoExt); do \
- echo " <xi:include href=\"$$d.xml\"/>" >> ref_man.xml ; \
+ echo " <xi:include href=\"$$d.xml\"/>" >> $@ ; \
done
- @echo "</application>" >> ref_man.xml
- @echo
+ @echo "</application>" >> $@
-$(ErlMods:%.erl=%.xml): ../../src/$(@:%.xml=%.erl)
- escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(VSN) -preprocess true -sort_functions false ../../src/$(@:%.xml=%.erl)
+$(ErlMods:%.erl=$(XMLDIR)/%.xml):
+ $(gen_verbose)escript $(DOCGEN)/priv/bin/xml_from_edoc.escript \
+ -def vsn $(VSN) -preprocess true -sort_functions false -dir $(XMLDIR) \
+ ../../src/$(@:$(XMLDIR)/%.xml=%.erl)
-$(GenMods:%.erl=%.xml): ../../src/gen/$(@:%.xml=%.erl)
- escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(VSN) -i ../../src -preprocess true -sort_functions false ../../src/gen/$(@:%.xml=%.erl)
+$(GenMods:%.erl=$(XMLDIR)/%.xml):
+ $(gen_verbose)escript $(DOCGEN)/priv/bin/xml_from_edoc.escript \
+ -def vsn $(VSN) -i ../../src -preprocess true -sort_functions false -dir $(XMLDIR) \
+ ../../src/gen/$(@:$(XMLDIR)/%.xml=%.erl)
-$(XML_CHAPTER_FILES): ../overview.edoc
- escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(VSN) -chapter ../overview.edoc
+$(XML_CHAPTER_FILES:%=$(XMLDIR)/%): ../overview.edoc
+ $(gen_verbose)escript $(DOCGEN)/priv/bin/xml_from_edoc.escript \
+ -def vsn $(VSN) -chapter -dir $(XMLDIR) $<
debug opt:
clean clean_docs:
- rm -rf $(HTMLDIR)/*
+ rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f $(SPECDIR)/*
rm -f errs core *~ ../html/edoc-info
- rm -f $(XML_REF3_FILES) $(XML_CHAPTER_FILES) *.html
+ rm -f $(XML_GEN_FILES) *.html
# ----------------------------------------------------
# Release Target
diff --git a/lib/wx/doc/src/notes.xml b/lib/wx/doc/src/notes.xml
index 69ea906ec0..0c3374091d 100644
--- a/lib/wx/doc/src/notes.xml
+++ b/lib/wx/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2009</year><year>2017</year>
+ <year>2009</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,6 +32,89 @@
<p>This document describes the changes made to the wxErlang
application.</p>
+<section><title>Wx 1.8.8</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ All incorrect (that is, all) uses of "can not" has been
+ corrected to "cannot" in source code comments,
+ documentation, examples, and so on.</p>
+ <p>
+ Own Id: OTP-14282 Aux Id: PR-1891 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Wx 1.8.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved support for wxWidgets 3.1.3 which have changed
+ <c>wxFONTWEIGTH</c>, also added <c>wxGCDC</c> and
+ <c>wxDisplay</c> modules.</p>
+ <p>
+ Fixed a crash on Mojave and check for events more often.</p>
+ <p>
+ Own Id: OTP-15587</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Wx 1.8.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed delayed delete bug which caused wx applications to
+ crash on Mojave.</p>
+ <p>
+ Own Id: OTP-15426 Aux Id: ERL-755 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Wx 1.8.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed compilation warning on Darwin.</p>
+ <p>
+ Own Id: OTP-15230 Aux Id: PR-1860 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Wx 1.8.4</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Changed implementation so wx can now be built towards
+ wxWidgets-3.1.1.</p>
+ <p>
+ Own Id: OTP-15027</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Wx 1.8.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/wx/examples/demo/demo.erl b/lib/wx/examples/demo/demo.erl
index 8fb70ad7b0..8f3291305b 100644
--- a/lib/wx/examples/demo/demo.erl
+++ b/lib/wx/examples/demo/demo.erl
@@ -411,7 +411,7 @@ find(Ed) ->
keyWords() ->
L = ["after","begin","case","try","cond","catch","andalso","orelse",
- "end","fun","if","let","of","query","receive","when","bnot","not",
+ "end","fun","if","let","of","receive","when","bnot","not",
"div","rem","band","and","bor","bxor","bsl","bsr","or","xor"],
lists:flatten([K ++ " " || K <- L] ++ [0]).
diff --git a/lib/wx/examples/demo/ex_aui.erl b/lib/wx/examples/demo/ex_aui.erl
index d8fc0021f1..49fa86f630 100644
--- a/lib/wx/examples/demo/ex_aui.erl
+++ b/lib/wx/examples/demo/ex_aui.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -87,8 +87,7 @@ do_init(Config) ->
wxAuiManager:update(Manager),
process_flag(trap_exit, true),
{Panel, #state{parent=Panel, config=Config, aui=Manager}}
- catch Class:Reason ->
- ST = erlang:get_stacktrace(),
+ catch Class:Reason:ST ->
io:format("AUI Crashed ~p ~p~n",[Reason, ST]),
wxAuiManager:unInit(Manager),
wxAuiManager:destroy(Manager),
diff --git a/lib/wx/examples/demo/ex_graphicsContext.erl b/lib/wx/examples/demo/ex_graphicsContext.erl
index 1193578037..1e6ffce18d 100644
--- a/lib/wx/examples/demo/ex_graphicsContext.erl
+++ b/lib/wx/examples/demo/ex_graphicsContext.erl
@@ -74,7 +74,7 @@ do_init(Config) ->
pen = Pen, brush = Brush, font = Font}}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Sync events i.e. from callbacks must return ok, it can not return a new state.
+%% Sync events i.e. from callbacks must return ok, it cannot return a new state.
%% Do the redrawing here.
handle_sync_event(#wx{event = #wxPaint{}},_,
#state{win=Win, pen = Pen, brush = Brush, font = Font}) ->
diff --git a/lib/wx/examples/simple/hello.erl b/lib/wx/examples/simple/hello.erl
index bf870c6f3e..8491a20af5 100644
--- a/lib/wx/examples/simple/hello.erl
+++ b/lib/wx/examples/simple/hello.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/examples/simple/hello2.erl b/lib/wx/examples/simple/hello2.erl
index b9da622b6b..07a9a56b7d 100644
--- a/lib/wx/examples/simple/hello2.erl
+++ b/lib/wx/examples/simple/hello2.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -33,7 +33,7 @@
init/1, handle_info/2, handle_event/2, handle_call/3,
code_change/3, terminate/2]).
--behavoiur(wx_object).
+-behaviour(wx_object).
-record(state, {win}).
diff --git a/lib/wx/examples/simple/menu.erl b/lib/wx/examples/simple/menu.erl
index 93573fb97d..7c0400bd1e 100644
--- a/lib/wx/examples/simple/menu.erl
+++ b/lib/wx/examples/simple/menu.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/examples/simple/minimal.erl b/lib/wx/examples/simple/minimal.erl
index 346f86433a..45efc06462 100644
--- a/lib/wx/examples/simple/minimal.erl
+++ b/lib/wx/examples/simple/minimal.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/examples/sudoku/sudoku.erl b/lib/wx/examples/sudoku/sudoku.erl
index 353f90d86f..a6a8d07e57 100644
--- a/lib/wx/examples/sudoku/sudoku.erl
+++ b/lib/wx/examples/sudoku/sudoku.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/examples/sudoku/sudoku_game.erl b/lib/wx/examples/sudoku/sudoku_game.erl
index aa15c05653..6463583e0f 100644
--- a/lib/wx/examples/sudoku/sudoku_game.erl
+++ b/lib/wx/examples/sudoku/sudoku_game.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/examples/sudoku/sudoku_gui.erl b/lib/wx/examples/sudoku/sudoku_gui.erl
index 4c4ad83cd7..e436bf2909 100644
--- a/lib/wx/examples/sudoku/sudoku_gui.erl
+++ b/lib/wx/examples/sudoku/sudoku_gui.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/examples/xrc/xrc.erl b/lib/wx/examples/xrc/xrc.erl
index 7e967777d2..a64e1f33ef 100644
--- a/lib/wx/examples/xrc/xrc.erl
+++ b/lib/wx/examples/xrc/xrc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/include/wx.hrl b/lib/wx/include/wx.hrl
index a14cc89cee..2c145595ee 100644
--- a/lib/wx/include/wx.hrl
+++ b/lib/wx/include/wx.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -373,6 +373,21 @@
-define(wxDefaultPosition, {-1,-1}).
%% Global Variables
+-define('WX_GL_CORE_PROFILE', wxe_util:get_const('WX_GL_CORE_PROFILE')).
+-define('WX_GL_DEBUG', wxe_util:get_const('WX_GL_DEBUG')).
+-define('WX_GL_ES2', wxe_util:get_const('WX_GL_ES2')).
+-define('WX_GL_FORWARD_COMPAT', wxe_util:get_const('WX_GL_FORWARD_COMPAT')).
+-define('WX_GL_FRAMEBUFFER_SRGB', wxe_util:get_const('WX_GL_FRAMEBUFFER_SRGB')).
+-define('WX_GL_LOSE_ON_RESET', wxe_util:get_const('WX_GL_LOSE_ON_RESET')).
+-define('WX_GL_MAJOR_VERSION', wxe_util:get_const('WX_GL_MAJOR_VERSION')).
+-define('WX_GL_MINOR_VERSION', wxe_util:get_const('WX_GL_MINOR_VERSION')).
+-define('WX_GL_NO_RESET_NOTIFY', wxe_util:get_const('WX_GL_NO_RESET_NOTIFY')).
+-define('WX_GL_RELEASE_FLUSH', wxe_util:get_const('WX_GL_RELEASE_FLUSH')).
+-define('WX_GL_RELEASE_NONE', wxe_util:get_const('WX_GL_RELEASE_NONE')).
+-define('WX_GL_RESET_ISOLATION', wxe_util:get_const('WX_GL_RESET_ISOLATION')).
+-define('WX_GL_ROBUST_ACCESS', wxe_util:get_const('WX_GL_ROBUST_ACCESS')).
+-define('WX_GL_SAMPLES', wxe_util:get_const('WX_GL_SAMPLES')).
+-define('WX_GL_SAMPLE_BUFFERS', wxe_util:get_const('WX_GL_SAMPLE_BUFFERS')).
-define(wxBLACK, wxe_util:get_const(wxBLACK)).
-define(wxBLACK_BRUSH, wxe_util:get_const(wxBLACK_BRUSH)).
-define(wxBLACK_DASHED_PEN, wxe_util:get_const(wxBLACK_DASHED_PEN)).
@@ -383,6 +398,14 @@
-define(wxCYAN, wxe_util:get_const(wxCYAN)).
-define(wxCYAN_BRUSH, wxe_util:get_const(wxCYAN_BRUSH)).
-define(wxCYAN_PEN, wxe_util:get_const(wxCYAN_PEN)).
+-define(wxFONTWEIGHT_EXTRABOLD, wxe_util:get_const(wxFONTWEIGHT_EXTRABOLD)).
+-define(wxFONTWEIGHT_EXTRAHEAVY, wxe_util:get_const(wxFONTWEIGHT_EXTRAHEAVY)).
+-define(wxFONTWEIGHT_EXTRALIGHT, wxe_util:get_const(wxFONTWEIGHT_EXTRALIGHT)).
+-define(wxFONTWEIGHT_HEAVY, wxe_util:get_const(wxFONTWEIGHT_HEAVY)).
+-define(wxFONTWEIGHT_INVALID, wxe_util:get_const(wxFONTWEIGHT_INVALID)).
+-define(wxFONTWEIGHT_MEDIUM, wxe_util:get_const(wxFONTWEIGHT_MEDIUM)).
+-define(wxFONTWEIGHT_SEMIBOLD, wxe_util:get_const(wxFONTWEIGHT_SEMIBOLD)).
+-define(wxFONTWEIGHT_THIN, wxe_util:get_const(wxFONTWEIGHT_THIN)).
-define(wxGREEN, wxe_util:get_const(wxGREEN)).
-define(wxGREEN_BRUSH, wxe_util:get_const(wxGREEN_BRUSH)).
-define(wxGREEN_PEN, wxe_util:get_const(wxGREEN_PEN)).
@@ -414,6 +437,7 @@
-define(wxWHITE, wxe_util:get_const(wxWHITE)).
-define(wxWHITE_BRUSH, wxe_util:get_const(wxWHITE_BRUSH)).
-define(wxWHITE_PEN, wxe_util:get_const(wxWHITE_PEN)).
+-define(wx_GL_COMPAT_PROFILE, wxe_util:get_const(wx_GL_COMPAT_PROFILE)).
%% Enum and defines
% From class wxAuiManager
@@ -1669,10 +1693,10 @@
-define(wxFONTSTYLE_SLANT, ?wxSLANT).
-define(wxFONTSTYLE_MAX, (?wxSLANT+1)).
% From "font.h": wxFontWeight
--define(wxFONTWEIGHT_NORMAL, ?wxNORMAL).
--define(wxFONTWEIGHT_LIGHT, ?wxLIGHT).
--define(wxFONTWEIGHT_BOLD, ?wxBOLD).
--define(wxFONTWEIGHT_MAX, (?wxBOLD+1)).
+-define(wxFONTWEIGHT_NORMAL, wxe_util:get_const(wxFONTWEIGHT_NORMAL)).
+-define(wxFONTWEIGHT_LIGHT, wxe_util:get_const(wxFONTWEIGHT_LIGHT)).
+-define(wxFONTWEIGHT_BOLD, wxe_util:get_const(wxFONTWEIGHT_BOLD)).
+-define(wxFONTWEIGHT_MAX, wxe_util:get_const(wxFONTWEIGHT_MAX)).
% From "fontenc.h": wxFontEncoding
-define(wxFONTENCODING_SYSTEM, -1).
-define(wxFONTENCODING_DEFAULT, 0).
diff --git a/lib/wx/src/Makefile b/lib/wx/src/Makefile
index 21b45af2c4..52f4008e0a 100644
--- a/lib/wx/src/Makefile
+++ b/lib/wx/src/Makefile
@@ -111,10 +111,10 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk Makefile
# Rules
$(EBIN)/%.beam: $(ESRC)/%.erl $(HEADER_FILES)
- $(V_ERLC) -W -bbeam $(ERL_FLAGS) $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
+ $(V_ERLC) -W -bbeam $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
$(EBIN)/%.beam: $(EGEN)/%.erl $(HEADER_FILES)
- $(V_ERLC) -W -bbeam $(ERL_FLAGS) $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
+ $(V_ERLC) -W -bbeam $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
# ----------------------------------------------------
# Release Target
diff --git a/lib/wx/src/gen/wxDisplay.erl b/lib/wx/src/gen/wxDisplay.erl
new file mode 100644
index 0000000000..b6a2bf22ac
--- /dev/null
+++ b/lib/wx/src/gen/wxDisplay.erl
@@ -0,0 +1,131 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%% This file is generated DO NOT EDIT
+
+%% @doc See external documentation: <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxdisplay.html">wxDisplay</a>.
+%% @type wxDisplay(). An object reference, The representation is internal
+%% and can be changed without notice. It can't be used for comparsion
+%% stored on disc or distributed for use on other nodes.
+
+-module(wxDisplay).
+-include("wxe.hrl").
+-export([destroy/1,getClientArea/1,getCount/0,getFromPoint/1,getFromWindow/1,
+ getGeometry/1,getName/1,getPPI/1,isOk/1,isPrimary/1,new/0,new/1]).
+
+%% inherited exports
+-export([parent_class/1]).
+
+-export_type([wxDisplay/0]).
+%% @hidden
+parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
+
+-type wxDisplay() :: wx:wx_object().
+%% @equiv new([])
+-spec new() -> wxDisplay().
+
+new() ->
+ new([]).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxdisplay.html#wxdisplaywxdisplay">external documentation</a>.
+-spec new([Option]) -> wxDisplay() when
+ Option :: {'n', integer()}.
+new(Options)
+ when is_list(Options) ->
+ MOpts = fun({n, N}, Acc) -> [<<1:32/?UI,N:32/?UI>>|Acc];
+ (BadOpt, _) -> erlang:error({badoption, BadOpt}) end,
+ BinOpt = list_to_binary(lists:foldl(MOpts, [<<0:32>>], Options)),
+ wxe_util:construct(?wxDisplay_new,
+ <<BinOpt/binary>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxdisplay.html#wxdisplayisok">external documentation</a>.
+-spec isOk(This) -> boolean() when
+ This::wxDisplay().
+isOk(#wx_ref{type=ThisT,ref=ThisRef}) ->
+ ?CLASS(ThisT,wxDisplay),
+ wxe_util:call(?wxDisplay_IsOk,
+ <<ThisRef:32/?UI>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxdisplay.html#wxdisplaygetclientarea">external documentation</a>.
+-spec getClientArea(This) -> {X::integer(), Y::integer(), W::integer(), H::integer()} when
+ This::wxDisplay().
+getClientArea(#wx_ref{type=ThisT,ref=ThisRef}) ->
+ ?CLASS(ThisT,wxDisplay),
+ wxe_util:call(?wxDisplay_GetClientArea,
+ <<ThisRef:32/?UI>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxdisplay.html#wxdisplaygetgeometry">external documentation</a>.
+-spec getGeometry(This) -> {X::integer(), Y::integer(), W::integer(), H::integer()} when
+ This::wxDisplay().
+getGeometry(#wx_ref{type=ThisT,ref=ThisRef}) ->
+ ?CLASS(ThisT,wxDisplay),
+ wxe_util:call(?wxDisplay_GetGeometry,
+ <<ThisRef:32/?UI>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxdisplay.html#wxdisplaygetname">external documentation</a>.
+-spec getName(This) -> unicode:charlist() when
+ This::wxDisplay().
+getName(#wx_ref{type=ThisT,ref=ThisRef}) ->
+ ?CLASS(ThisT,wxDisplay),
+ wxe_util:call(?wxDisplay_GetName,
+ <<ThisRef:32/?UI>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxdisplay.html#wxdisplayisprimary">external documentation</a>.
+-spec isPrimary(This) -> boolean() when
+ This::wxDisplay().
+isPrimary(#wx_ref{type=ThisT,ref=ThisRef}) ->
+ ?CLASS(ThisT,wxDisplay),
+ wxe_util:call(?wxDisplay_IsPrimary,
+ <<ThisRef:32/?UI>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxdisplay.html#wxdisplaygetcount">external documentation</a>.
+-spec getCount() -> integer().
+getCount() ->
+ wxe_util:call(?wxDisplay_GetCount,
+ <<>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxdisplay.html#wxdisplaygetfrompoint">external documentation</a>.
+-spec getFromPoint(Pt) -> integer() when
+ Pt::{X::integer(), Y::integer()}.
+getFromPoint({PtX,PtY})
+ when is_integer(PtX),is_integer(PtY) ->
+ wxe_util:call(?wxDisplay_GetFromPoint,
+ <<PtX:32/?UI,PtY:32/?UI>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxdisplay.html#wxdisplaygetfromwindow">external documentation</a>.
+-spec getFromWindow(Window) -> integer() when
+ Window::wxWindow:wxWindow().
+getFromWindow(#wx_ref{type=WindowT,ref=WindowRef}) ->
+ ?CLASS(WindowT,wxWindow),
+ wxe_util:call(?wxDisplay_GetFromWindow,
+ <<WindowRef:32/?UI>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxdisplay.html#wxdisplaygetppi">external documentation</a>.
+-spec getPPI(This) -> {W::integer(), H::integer()} when
+ This::wxDisplay().
+getPPI(#wx_ref{type=ThisT,ref=ThisRef}) ->
+ ?CLASS(ThisT,wxDisplay),
+ wxe_util:call(?wxDisplay_GetPPI,
+ <<ThisRef:32/?UI>>).
+
+%% @doc Destroys this object, do not use object again
+-spec destroy(This::wxDisplay()) -> 'ok'.
+destroy(Obj=#wx_ref{type=Type}) ->
+ ?CLASS(Type,wxDisplay),
+ wxe_util:destroy(?wxDisplay_destruct,Obj),
+ ok.
diff --git a/lib/wx/src/gen/wxGCDC.erl b/lib/wx/src/gen/wxGCDC.erl
new file mode 100644
index 0000000000..467013b14e
--- /dev/null
+++ b/lib/wx/src/gen/wxGCDC.erl
@@ -0,0 +1,287 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%% This file is generated DO NOT EDIT
+
+%% @doc See external documentation: <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxgcdc.html">wxGCDC</a>.
+%% <p>This class is derived (and can use functions) from:
+%% <br />{@link wxDC}
+%% </p>
+%% @type wxGCDC(). An object reference, The representation is internal
+%% and can be changed without notice. It can't be used for comparsion
+%% stored on disc or distributed for use on other nodes.
+
+-module(wxGCDC).
+-include("wxe.hrl").
+-export([destroy/1,getGraphicsContext/1,new/0,new/1,setGraphicsContext/2]).
+
+%% inherited exports
+-export([blit/5,blit/6,calcBoundingBox/3,clear/1,computeScaleAndOrigin/1,crossHair/2,
+ destroyClippingRegion/1,deviceToLogicalX/2,deviceToLogicalXRel/2,
+ deviceToLogicalY/2,deviceToLogicalYRel/2,drawArc/4,drawBitmap/3,drawBitmap/4,
+ drawCheckMark/2,drawCircle/3,drawEllipse/2,drawEllipse/3,drawEllipticArc/5,
+ drawIcon/3,drawLabel/3,drawLabel/4,drawLine/3,drawLines/2,drawLines/3,
+ drawPoint/2,drawPolygon/2,drawPolygon/3,drawRectangle/2,drawRectangle/3,
+ drawRotatedText/4,drawRoundedRectangle/3,drawRoundedRectangle/4,
+ drawText/3,endDoc/1,endPage/1,floodFill/3,floodFill/4,getBackground/1,
+ getBackgroundMode/1,getBrush/1,getCharHeight/1,getCharWidth/1,getClippingBox/1,
+ getFont/1,getLayoutDirection/1,getLogicalFunction/1,getMapMode/1,
+ getMultiLineTextExtent/2,getMultiLineTextExtent/3,getPPI/1,getPartialTextExtents/2,
+ getPen/1,getPixel/2,getSize/1,getSizeMM/1,getTextBackground/1,getTextExtent/2,
+ getTextExtent/3,getTextForeground/1,getUserScale/1,gradientFillConcentric/4,
+ gradientFillConcentric/5,gradientFillLinear/4,gradientFillLinear/5,
+ isOk/1,logicalToDeviceX/2,logicalToDeviceXRel/2,logicalToDeviceY/2,
+ logicalToDeviceYRel/2,maxX/1,maxY/1,minX/1,minY/1,parent_class/1,resetBoundingBox/1,
+ setAxisOrientation/3,setBackground/2,setBackgroundMode/2,setBrush/2,
+ setClippingRegion/2,setClippingRegion/3,setDeviceOrigin/3,setFont/2,
+ setLayoutDirection/2,setLogicalFunction/2,setMapMode/2,setPalette/2,
+ setPen/2,setTextBackground/2,setTextForeground/2,setUserScale/3,startDoc/2,
+ startPage/1]).
+
+-export_type([wxGCDC/0]).
+-compile([{nowarn_deprecated_function, {wxDC,computeScaleAndOrigin,1}}]).
+
+%% @hidden
+parent_class(wxDC) -> true;
+parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
+
+-type wxGCDC() :: wx:wx_object().
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxgcdc.html#wxgcdcwxgcdc">external documentation</a>.
+-spec new() -> wxGCDC().
+new() ->
+ wxe_util:construct(?wxGCDC_new_0,
+ <<>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxgcdc.html#wxgcdcwxgcdc">external documentation</a>.
+-spec new(Dc) -> wxGCDC() when
+ Dc::wxWindowDC:wxWindowDC().
+new(#wx_ref{type=DcT,ref=DcRef}) ->
+ ?CLASS(DcT,wxWindowDC),
+ wxe_util:construct(?wxGCDC_new_1,
+ <<DcRef:32/?UI>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxgcdc.html#wxgcdcgetgraphicscontext">external documentation</a>.
+-spec getGraphicsContext(This) -> wxGraphicsContext:wxGraphicsContext() when
+ This::wxGCDC().
+getGraphicsContext(#wx_ref{type=ThisT,ref=ThisRef}) ->
+ ?CLASS(ThisT,wxGCDC),
+ wxe_util:call(?wxGCDC_GetGraphicsContext,
+ <<ThisRef:32/?UI>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxgcdc.html#wxgcdcsetgraphicscontext">external documentation</a>.
+-spec setGraphicsContext(This, Ctx) -> 'ok' when
+ This::wxGCDC(), Ctx::wxGraphicsContext:wxGraphicsContext().
+setGraphicsContext(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=CtxT,ref=CtxRef}) ->
+ ?CLASS(ThisT,wxGCDC),
+ ?CLASS(CtxT,wxGraphicsContext),
+ wxe_util:cast(?wxGCDC_SetGraphicsContext,
+ <<ThisRef:32/?UI,CtxRef:32/?UI>>).
+
+%% @doc Destroys this object, do not use object again
+-spec destroy(This::wxGCDC()) -> 'ok'.
+destroy(Obj=#wx_ref{type=Type}) ->
+ ?CLASS(Type,wxGCDC),
+ wxe_util:destroy(?DESTROY_OBJECT,Obj),
+ ok.
+ %% From wxDC
+%% @hidden
+startPage(This) -> wxDC:startPage(This).
+%% @hidden
+startDoc(This,Message) -> wxDC:startDoc(This,Message).
+%% @hidden
+setUserScale(This,X,Y) -> wxDC:setUserScale(This,X,Y).
+%% @hidden
+setTextForeground(This,Colour) -> wxDC:setTextForeground(This,Colour).
+%% @hidden
+setTextBackground(This,Colour) -> wxDC:setTextBackground(This,Colour).
+%% @hidden
+setPen(This,Pen) -> wxDC:setPen(This,Pen).
+%% @hidden
+setPalette(This,Palette) -> wxDC:setPalette(This,Palette).
+%% @hidden
+setMapMode(This,Mode) -> wxDC:setMapMode(This,Mode).
+%% @hidden
+setLogicalFunction(This,Function) -> wxDC:setLogicalFunction(This,Function).
+%% @hidden
+setLayoutDirection(This,Dir) -> wxDC:setLayoutDirection(This,Dir).
+%% @hidden
+setFont(This,Font) -> wxDC:setFont(This,Font).
+%% @hidden
+setDeviceOrigin(This,X,Y) -> wxDC:setDeviceOrigin(This,X,Y).
+%% @hidden
+setClippingRegion(This,Pt,Sz) -> wxDC:setClippingRegion(This,Pt,Sz).
+%% @hidden
+setClippingRegion(This,Region) -> wxDC:setClippingRegion(This,Region).
+%% @hidden
+setBrush(This,Brush) -> wxDC:setBrush(This,Brush).
+%% @hidden
+setBackgroundMode(This,Mode) -> wxDC:setBackgroundMode(This,Mode).
+%% @hidden
+setBackground(This,Brush) -> wxDC:setBackground(This,Brush).
+%% @hidden
+setAxisOrientation(This,XLeftRight,YBottomUp) -> wxDC:setAxisOrientation(This,XLeftRight,YBottomUp).
+%% @hidden
+resetBoundingBox(This) -> wxDC:resetBoundingBox(This).
+%% @hidden
+isOk(This) -> wxDC:isOk(This).
+%% @hidden
+minY(This) -> wxDC:minY(This).
+%% @hidden
+minX(This) -> wxDC:minX(This).
+%% @hidden
+maxY(This) -> wxDC:maxY(This).
+%% @hidden
+maxX(This) -> wxDC:maxX(This).
+%% @hidden
+logicalToDeviceYRel(This,Y) -> wxDC:logicalToDeviceYRel(This,Y).
+%% @hidden
+logicalToDeviceY(This,Y) -> wxDC:logicalToDeviceY(This,Y).
+%% @hidden
+logicalToDeviceXRel(This,X) -> wxDC:logicalToDeviceXRel(This,X).
+%% @hidden
+logicalToDeviceX(This,X) -> wxDC:logicalToDeviceX(This,X).
+%% @hidden
+gradientFillLinear(This,Rect,InitialColour,DestColour, Options) -> wxDC:gradientFillLinear(This,Rect,InitialColour,DestColour, Options).
+%% @hidden
+gradientFillLinear(This,Rect,InitialColour,DestColour) -> wxDC:gradientFillLinear(This,Rect,InitialColour,DestColour).
+%% @hidden
+gradientFillConcentric(This,Rect,InitialColour,DestColour,CircleCenter) -> wxDC:gradientFillConcentric(This,Rect,InitialColour,DestColour,CircleCenter).
+%% @hidden
+gradientFillConcentric(This,Rect,InitialColour,DestColour) -> wxDC:gradientFillConcentric(This,Rect,InitialColour,DestColour).
+%% @hidden
+getUserScale(This) -> wxDC:getUserScale(This).
+%% @hidden
+getTextForeground(This) -> wxDC:getTextForeground(This).
+%% @hidden
+getTextExtent(This,String, Options) -> wxDC:getTextExtent(This,String, Options).
+%% @hidden
+getTextExtent(This,String) -> wxDC:getTextExtent(This,String).
+%% @hidden
+getTextBackground(This) -> wxDC:getTextBackground(This).
+%% @hidden
+getSizeMM(This) -> wxDC:getSizeMM(This).
+%% @hidden
+getSize(This) -> wxDC:getSize(This).
+%% @hidden
+getPPI(This) -> wxDC:getPPI(This).
+%% @hidden
+getPixel(This,Pt) -> wxDC:getPixel(This,Pt).
+%% @hidden
+getPen(This) -> wxDC:getPen(This).
+%% @hidden
+getPartialTextExtents(This,Text) -> wxDC:getPartialTextExtents(This,Text).
+%% @hidden
+getMultiLineTextExtent(This,String, Options) -> wxDC:getMultiLineTextExtent(This,String, Options).
+%% @hidden
+getMultiLineTextExtent(This,String) -> wxDC:getMultiLineTextExtent(This,String).
+%% @hidden
+getMapMode(This) -> wxDC:getMapMode(This).
+%% @hidden
+getLogicalFunction(This) -> wxDC:getLogicalFunction(This).
+%% @hidden
+getLayoutDirection(This) -> wxDC:getLayoutDirection(This).
+%% @hidden
+getFont(This) -> wxDC:getFont(This).
+%% @hidden
+getClippingBox(This) -> wxDC:getClippingBox(This).
+%% @hidden
+getCharWidth(This) -> wxDC:getCharWidth(This).
+%% @hidden
+getCharHeight(This) -> wxDC:getCharHeight(This).
+%% @hidden
+getBrush(This) -> wxDC:getBrush(This).
+%% @hidden
+getBackgroundMode(This) -> wxDC:getBackgroundMode(This).
+%% @hidden
+getBackground(This) -> wxDC:getBackground(This).
+%% @hidden
+floodFill(This,Pt,Col, Options) -> wxDC:floodFill(This,Pt,Col, Options).
+%% @hidden
+floodFill(This,Pt,Col) -> wxDC:floodFill(This,Pt,Col).
+%% @hidden
+endPage(This) -> wxDC:endPage(This).
+%% @hidden
+endDoc(This) -> wxDC:endDoc(This).
+%% @hidden
+drawText(This,Text,Pt) -> wxDC:drawText(This,Text,Pt).
+%% @hidden
+drawRoundedRectangle(This,Pt,Sz,Radius) -> wxDC:drawRoundedRectangle(This,Pt,Sz,Radius).
+%% @hidden
+drawRoundedRectangle(This,R,Radius) -> wxDC:drawRoundedRectangle(This,R,Radius).
+%% @hidden
+drawRotatedText(This,Text,Pt,Angle) -> wxDC:drawRotatedText(This,Text,Pt,Angle).
+%% @hidden
+drawRectangle(This,Pt,Sz) -> wxDC:drawRectangle(This,Pt,Sz).
+%% @hidden
+drawRectangle(This,Rect) -> wxDC:drawRectangle(This,Rect).
+%% @hidden
+drawPoint(This,Pt) -> wxDC:drawPoint(This,Pt).
+%% @hidden
+drawPolygon(This,Points, Options) -> wxDC:drawPolygon(This,Points, Options).
+%% @hidden
+drawPolygon(This,Points) -> wxDC:drawPolygon(This,Points).
+%% @hidden
+drawLines(This,Points, Options) -> wxDC:drawLines(This,Points, Options).
+%% @hidden
+drawLines(This,Points) -> wxDC:drawLines(This,Points).
+%% @hidden
+drawLine(This,Pt1,Pt2) -> wxDC:drawLine(This,Pt1,Pt2).
+%% @hidden
+drawLabel(This,Text,Rect, Options) -> wxDC:drawLabel(This,Text,Rect, Options).
+%% @hidden
+drawLabel(This,Text,Rect) -> wxDC:drawLabel(This,Text,Rect).
+%% @hidden
+drawIcon(This,Icon,Pt) -> wxDC:drawIcon(This,Icon,Pt).
+%% @hidden
+drawEllipticArc(This,Pt,Sz,Sa,Ea) -> wxDC:drawEllipticArc(This,Pt,Sz,Sa,Ea).
+%% @hidden
+drawEllipse(This,Pt,Sz) -> wxDC:drawEllipse(This,Pt,Sz).
+%% @hidden
+drawEllipse(This,Rect) -> wxDC:drawEllipse(This,Rect).
+%% @hidden
+drawCircle(This,Pt,Radius) -> wxDC:drawCircle(This,Pt,Radius).
+%% @hidden
+drawCheckMark(This,Rect) -> wxDC:drawCheckMark(This,Rect).
+%% @hidden
+drawBitmap(This,Bmp,Pt, Options) -> wxDC:drawBitmap(This,Bmp,Pt, Options).
+%% @hidden
+drawBitmap(This,Bmp,Pt) -> wxDC:drawBitmap(This,Bmp,Pt).
+%% @hidden
+drawArc(This,Pt1,Pt2,Centre) -> wxDC:drawArc(This,Pt1,Pt2,Centre).
+%% @hidden
+deviceToLogicalYRel(This,Y) -> wxDC:deviceToLogicalYRel(This,Y).
+%% @hidden
+deviceToLogicalY(This,Y) -> wxDC:deviceToLogicalY(This,Y).
+%% @hidden
+deviceToLogicalXRel(This,X) -> wxDC:deviceToLogicalXRel(This,X).
+%% @hidden
+deviceToLogicalX(This,X) -> wxDC:deviceToLogicalX(This,X).
+%% @hidden
+destroyClippingRegion(This) -> wxDC:destroyClippingRegion(This).
+%% @hidden
+crossHair(This,Pt) -> wxDC:crossHair(This,Pt).
+%% @hidden
+computeScaleAndOrigin(This) -> wxDC:computeScaleAndOrigin(This).
+%% @hidden
+clear(This) -> wxDC:clear(This).
+%% @hidden
+calcBoundingBox(This,X,Y) -> wxDC:calcBoundingBox(This,X,Y).
+%% @hidden
+blit(This,DestPt,Sz,Source,SrcPt, Options) -> wxDC:blit(This,DestPt,Sz,Source,SrcPt, Options).
+%% @hidden
+blit(This,DestPt,Sz,Source,SrcPt) -> wxDC:blit(This,DestPt,Sz,Source,SrcPt).
diff --git a/lib/wx/src/gen/wxe_debug.hrl b/lib/wx/src/gen/wxe_debug.hrl
index 533f9f2df0..b64a1b4c61 100644
--- a/lib/wx/src/gen/wxe_debug.hrl
+++ b/lib/wx/src/gen/wxe_debug.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -3377,6 +3377,22 @@ wxdebug_table() ->
{3597, {wxDropFilesEvent, getPosition, 0}},
{3598, {wxDropFilesEvent, getNumberOfFiles, 0}},
{3599, {wxDropFilesEvent, getFiles, 0}},
+ {3600, {wxDisplay, new, 1}},
+ {3601, {wxDisplay, destruct, 0}},
+ {3602, {wxDisplay, isOk, 0}},
+ {3603, {wxDisplay, getClientArea, 0}},
+ {3604, {wxDisplay, getGeometry, 0}},
+ {3605, {wxDisplay, getName, 0}},
+ {3606, {wxDisplay, isPrimary, 0}},
+ {3607, {wxDisplay, getCount, 0}},
+ {3608, {wxDisplay, getFromPoint, 1}},
+ {3609, {wxDisplay, getFromWindow, 1}},
+ {3610, {wxDisplay, getPPI, 0}},
+ {3611, {wxGCDC, new_1, 1}},
+ {3612, {wxGCDC, new_0, 0}},
+ {3613, {wxGCDC, destruct, 0}},
+ {3614, {wxGCDC, getGraphicsContext, 0}},
+ {3615, {wxGCDC, setGraphicsContext, 1}},
{-1, {mod, func, -1}}
].
diff --git a/lib/wx/src/gen/wxe_funcs.hrl b/lib/wx/src/gen/wxe_funcs.hrl
index 14b5545676..030f7f117d 100644
--- a/lib/wx/src/gen/wxe_funcs.hrl
+++ b/lib/wx/src/gen/wxe_funcs.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -3374,3 +3374,19 @@
-define(wxDropFilesEvent_GetPosition, 3597).
-define(wxDropFilesEvent_GetNumberOfFiles, 3598).
-define(wxDropFilesEvent_GetFiles, 3599).
+-define(wxDisplay_new, 3600).
+-define(wxDisplay_destruct, 3601).
+-define(wxDisplay_IsOk, 3602).
+-define(wxDisplay_GetClientArea, 3603).
+-define(wxDisplay_GetGeometry, 3604).
+-define(wxDisplay_GetName, 3605).
+-define(wxDisplay_IsPrimary, 3606).
+-define(wxDisplay_GetCount, 3607).
+-define(wxDisplay_GetFromPoint, 3608).
+-define(wxDisplay_GetFromWindow, 3609).
+-define(wxDisplay_GetPPI, 3610).
+-define(wxGCDC_new_1, 3611).
+-define(wxGCDC_new_0, 3612).
+-define(wxGCDC_destruct, 3613).
+-define(wxGCDC_GetGraphicsContext, 3614).
+-define(wxGCDC_SetGraphicsContext, 3615).
diff --git a/lib/wx/src/wx.erl b/lib/wx/src/wx.erl
index 34bf06cf46..a20758c826 100644
--- a/lib/wx/src/wx.erl
+++ b/lib/wx/src/wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -183,7 +183,7 @@ batch(Fun) ->
ok = wxe_util:cast(?BATCH_BEGIN, <<>>),
try Fun()
catch
- error:W -> erlang:exit({W, erlang:get_stacktrace()});
+ error:W:S -> erlang:exit({W, S});
throw:W -> erlang:throw(W);
exit:W -> erlang:exit(W)
after
@@ -196,7 +196,7 @@ foreach(Fun, List) ->
ok = wxe_util:cast(?BATCH_BEGIN, <<>>),
try lists:foreach(Fun, List)
catch
- error:W -> erlang:exit({W, erlang:get_stacktrace()});
+ error:W:S -> erlang:exit({W, S});
throw:W -> erlang:throw(W);
exit:W -> erlang:exit(W)
after
@@ -209,7 +209,7 @@ map(Fun, List) ->
ok = wxe_util:cast(?BATCH_BEGIN, <<>>),
try lists:map(Fun, List)
catch
- error:W -> erlang:exit({W, erlang:get_stacktrace()});
+ error:W:S -> erlang:exit({W, S});
throw:W -> erlang:throw(W);
exit:W -> erlang:exit(W)
after
@@ -222,7 +222,7 @@ foldl(Fun, Acc, List) ->
ok = wxe_util:cast(?BATCH_BEGIN, <<>>),
try lists:foldl(Fun, Acc, List)
catch
- error:W -> erlang:exit({W, erlang:get_stacktrace()});
+ error:W:S -> erlang:exit({W, S});
throw:W -> erlang:throw(W);
exit:W -> erlang:exit(W)
after
@@ -235,7 +235,7 @@ foldr(Fun, Acc, List) ->
ok = wxe_util:cast(?BATCH_BEGIN, <<>>),
try lists:foldr(Fun, Acc, List)
catch
- error:W -> erlang:exit({W, erlang:get_stacktrace()});
+ error:W:S -> erlang:exit({W, S});
throw:W -> erlang:throw(W);
exit:W -> erlang:exit(W)
after
diff --git a/lib/wx/src/wxe_master.erl b/lib/wx/src/wxe_master.erl
index ce859b3eb3..edef6b3613 100644
--- a/lib/wx/src/wxe_master.erl
+++ b/lib/wx/src/wxe_master.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -122,16 +122,9 @@ init([SilentStart]) ->
erlang:error(not_smp)
end,
- case os:type() of
- {win32,_} -> %% Needed for mingwm10.dll
- Path = os:getenv("PATH"),
- os:putenv("PATH", PrivDir ++ ";" ++ Path);
- _ -> ok
- end,
-
case erl_ddll:load_driver(PrivDir,DriverName) of
ok -> ok;
- {error, What} ->
+ {error, What} ->
wxe_util:opt_error_log(SilentStart,
"WX Failed loading ~p@~p ~n",
[DriverName,PrivDir]),
@@ -139,8 +132,8 @@ init([SilentStart]) ->
erlang:error({load_driver,Str})
end,
process_flag(trap_exit, true),
- DriverWithArgs = DriverName ++ " " ++ code:priv_dir(wx) ++ [0],
-
+ DriverWithArgs = DriverName ++ " " ++ code:priv_dir(wx),
+
try
Port = open_port({spawn, DriverWithArgs},[binary]),
wx_debug_info = ets:new(wx_debug_info, [named_table]),
diff --git a/lib/wx/src/wxe_server.erl b/lib/wx/src/wxe_server.erl
index 58fcaf8f23..e241a11e8b 100644
--- a/lib/wx/src/wxe_server.erl
+++ b/lib/wx/src/wxe_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -283,10 +283,10 @@ invoke_callback(Pid, Ev, Ref) ->
Return -> exit({bad_return, Return})
end
end
- catch _:Reason ->
+ catch _:Reason:Stacktrace ->
wxEvent:skip(Ref),
?log("Callback fun crashed with {'EXIT, ~p, ~p}~n",
- [Reason, erlang:get_stacktrace()])
+ [Reason, Stacktrace])
end,
wxe_util:cast(?WXE_CB_RETURN, <<>>)
end,
@@ -299,9 +299,9 @@ invoke_callback_fun(Fun) ->
Return = Fun(),
true = is_binary(Return),
Return
- catch _:Reason ->
+ catch _:Reason:Stacktrace ->
?log("Callback fun crashed with {'EXIT, ~p, ~p}~n",
- [Reason, erlang:get_stacktrace()]),
+ [Reason, Stacktrace]),
<<>>
end,
wxe_util:cast(?WXE_CB_RETURN, Res).
diff --git a/lib/wx/test/wx_app_SUITE.erl b/lib/wx/test/wx_app_SUITE.erl
index a5202d8448..99c8ef0416 100644
--- a/lib/wx/test/wx_app_SUITE.erl
+++ b/lib/wx/test/wx_app_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/test/wx_class_SUITE.erl b/lib/wx/test/wx_class_SUITE.erl
index 6d314ab8fc..56749ba72b 100644
--- a/lib/wx/test/wx_class_SUITE.erl
+++ b/lib/wx/test/wx_class_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -618,7 +618,7 @@ lang_env() ->
Env0 = os:getenv(),
Env = [[R,"\n"]||R <- Env0],
%%io:format("~p~n",[lists:sort(Env)]),
- Opts = [global, multiline, {capture, all, list}],
+ Opts = [global, multiline, {capture, all, list}, unicode],
format_env(re:run(Env, "LC_ALL.*", Opts)),
format_env(re:run(Env, "^LANG.*=.*$", Opts)),
ok.
diff --git a/lib/wx/test/wx_event_SUITE.erl b/lib/wx/test/wx_event_SUITE.erl
index a564f89e58..1cc194d569 100644
--- a/lib/wx/test/wx_event_SUITE.erl
+++ b/lib/wx/test/wx_event_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -347,9 +347,9 @@ connect_in_callback(Config) ->
%% such that new events are not fired until the previous
%% callback have returned.
- %% That means that a callback can not wait for other events
+ %% That means that a callback cannot wait for other events
%% in receive since they will not come.
- %% It also means that you can not attach a new callback directly from
+ %% It also means that you cannot attach a new callback directly from
%% the callback since that callback will be removed when the temporary
%% process that executes the outer callback (may) die(s) before the callback
%% is invoked
diff --git a/lib/wx/test/wx_opengl_SUITE.erl b/lib/wx/test/wx_opengl_SUITE.erl
index 19ea731dfb..053740ed8b 100644
--- a/lib/wx/test/wx_opengl_SUITE.erl
+++ b/lib/wx/test/wx_opengl_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/test/wx_test_lib.erl b/lib/wx/test/wx_test_lib.erl
index af508ff490..7bf2bb11bb 100644
--- a/lib/wx/test/wx_test_lib.erl
+++ b/lib/wx/test/wx_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/test/wx_xtra_SUITE.erl b/lib/wx/test/wx_xtra_SUITE.erl
index 486843ec63..8142d9566f 100644
--- a/lib/wx/test/wx_xtra_SUITE.erl
+++ b/lib/wx/test/wx_xtra_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/test/wxt b/lib/wx/test/wxt
index e720ed94f4..94513e88e9 100755
--- a/lib/wx/test/wxt
+++ b/lib/wx/test/wxt
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2008-2016. All Rights Reserved.
+# Copyright Ericsson AB 2008-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -18,7 +18,7 @@
#
# %CopyrightEnd%
#
-# Usage: mt <args to erlang startup script>
+# Usage: wxt <args to erlang startup script>
log=test_log_$$
latest=test_log_latest
@@ -27,7 +27,7 @@ erlcmd="erl -sname test_server -smp -pa ../ebin $p $args -wx_test_verbose true -
echo "Give the following command in order to see the outcome:"
echo ""
-echo " less test_log$$"
+echo " less $log"
rm "$latest" 2>/dev/null
ln -s "$log" "$latest"
diff --git a/lib/wx/test/wxt.erl b/lib/wx/test/wxt.erl
index 2b380606d5..280443404f 100644
--- a/lib/wx/test/wxt.erl
+++ b/lib/wx/test/wxt.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/vsn.mk b/lib/wx/vsn.mk
index 7da4529c98..91d15de3a9 100644
--- a/lib/wx/vsn.mk
+++ b/lib/wx/vsn.mk
@@ -1 +1 @@
-WX_VSN = 1.8.3
+WX_VSN = 1.8.8
diff --git a/lib/xmerl/doc/src/Makefile b/lib/xmerl/doc/src/Makefile
index 7d0b0b2392..0def492246 100644
--- a/lib/xmerl/doc/src/Makefile
+++ b/lib/xmerl/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2017. All Rights Reserved.
+# Copyright Ericsson AB 2004-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -54,10 +54,9 @@ XMERL_MODULES = \
XML_APPLICATION_FILES = ref_man.xml
-XMERL_XML_FILES = $(XMERL_MODULES:=.xml)
+XMERL_XML_FILES = $(XMERL_MODULES:%=$(XMLDIR)/%.xml)
-XML_REF3_FILES = $(XMERL_XML_FILES) \
- xmerl_sax_parser.xml
+XML_REF3_FILES = xmerl_sax_parser.xml
XML_PART_FILES = \
part.xml
@@ -65,9 +64,10 @@ XML_PART_FILES = \
XML_REF6_FILES =
XML_CHAPTER_FILES = \
- xmerl_ug.xml \
notes.xml
+XML_CHAPTER_GEN_FILES = \
+ $(XMLDIR)/xmerl_ug.xml
HTML_EXAMPLE_FILES = \
xmerl_examples.html \
@@ -89,6 +89,8 @@ XML_FILES= \
$(BOOK_FILES) $(XML_CHAPTER_FILES) \
$(XML_PART_FILES) $(XML_REF3_FILES) $(XML_APPLICATION_FILES)
+XML_GEN_FILES = $(XMERL_XML_FILES) $(XML_CHAPTER_GEN_FILES)
+
# ----------------------------------------------------
INFO_FILE = ../../info
@@ -97,7 +99,7 @@ HTML_FILES = $(XML_REF_MAN:%.xml=$(HTMLDIR)/%.html) \
$(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html)
-MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
+MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) $(XMERL_MODULES:%=$(MAN3DIR)/%.3)
MAN6_FILES = $(XML_REF6_FILES:%_app.xml=$(MAN6DIR)/%.6)
HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
@@ -126,7 +128,7 @@ pdf: $(TOP_PDF_FILE)
html: gifs $(HTML_REF_MAN_FILE)
$(XMERL_XML_FILES):
- escript $(DOCGEN)/priv/bin/xml_from_edoc.escript $(XMERL_DIR)/$(@:%.xml=%.erl)
+ $(gen_verbose)escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -dir $(XMLDIR) $(XMERL_DIR)/$(@:$(XMLDIR)/%.xml=%.erl)
man: $(MAN3_FILES) $(MAN6_FILES)
@@ -138,6 +140,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(MAN6DIR)/*
rm -f $(XMERL_XML_FILES)
diff --git a/lib/xmerl/doc/src/notes.xml b/lib/xmerl/doc/src/notes.xml
index f62a8dc53d..37973d0dba 100644
--- a/lib/xmerl/doc/src/notes.xml
+++ b/lib/xmerl/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,6 +32,103 @@
<p>This document describes the changes made to the Xmerl application.</p>
+<section><title>Xmerl 1.3.21</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A typo in an error printout has been fixed.</p>
+ <p>
+ Own Id: OTP-14703 Aux Id: PR-1964 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Xmerl 1.3.20</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Handling of character references in attributes are fixed.</p>
+ <p>
+ Own Id: OTP-15684 Aux Id: ERL-837 </p>
+ </item>
+ <item>
+ <p>
+ Normalization of whitespace characters in attributes are
+ fixed so it works when character references are used.</p>
+ <p>
+ Own Id: OTP-15685 Aux Id: ERL-475 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Xmerl 1.3.19</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>The charset detection parsing crash in some cases when
+ the XML directive is not syntactic correct.</p>
+ <p>
+ Own Id: OTP-15492 Aux Id: ERIERL-283 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Xmerl 1.3.18</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Xmerl 1.3.17</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix typos in documentation.</p>
+ <p>
+ Own Id: OTP-15039</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Xmerl 1.3.16.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>The charset detection parsing crash in some cases when
+ the XML directive is not syntactic correct.</p>
+ <p>
+ Own Id: OTP-15492 Aux Id: ERIERL-283 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Xmerl 1.3.16</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -1382,4 +1479,3 @@
</section>
</section>
</chapter>
-
diff --git a/lib/xmerl/doc/src/xmerl_sax_parser.xml b/lib/xmerl/doc/src/xmerl_sax_parser.xml
index 8ea197e209..2390779028 100644
--- a/lib/xmerl/doc/src/xmerl_sax_parser.xml
+++ b/lib/xmerl/doc/src/xmerl_sax_parser.xml
@@ -31,7 +31,7 @@
<rev></rev>
</header>
- <module>xmerl_sax_parser</module>
+ <module since="">xmerl_sax_parser</module>
<modulesummary>XML SAX parser API</modulesummary>
<description>
@@ -325,7 +325,7 @@
<funcs>
<func>
- <name>file(Filename, Options) -> Result</name>
+ <name since="">file(Filename, Options) -> Result</name>
<fsummary>Parse file containing an XML document.</fsummary>
<type>
<v>Filename = string()</v>
@@ -347,7 +347,7 @@
</func>
<func>
- <name>stream(Xml, Options) -> Result</name>
+ <name since="">stream(Xml, Options) -> Result</name>
<fsummary>Parse a stream containing an XML document.</fsummary>
<type>
<v>Xml = unicode_binary() | latin1_binary() | [unicode_char()]</v>
@@ -381,7 +381,7 @@
<funcs>
<func>
- <name>ContinuationFun(State) -> {NewBytes, NewState}</name>
+ <name since="">ContinuationFun(State) -> {NewBytes, NewState}</name>
<fsummary>Continuation call back function.</fsummary>
<type>
<v>State = NewState = term()</v>
@@ -402,7 +402,7 @@
</func>
<func>
- <name>EventFun(Event, Location, State) -> NewState</name>
+ <name since="">EventFun(Event, Location, State) -> NewState</name>
<fsummary>Event call back function.</fsummary>
<type>
<v>Event = event()</v>
diff --git a/lib/xmerl/src/xmerl_sax_parser.erl b/lib/xmerl/src/xmerl_sax_parser.erl
index e383c4c349..fe836fd8cd 100644
--- a/lib/xmerl/src/xmerl_sax_parser.erl
+++ b/lib/xmerl/src/xmerl_sax_parser.erl
@@ -1,8 +1,8 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
+%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
@@ -14,13 +14,13 @@
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
-%%
+%%
%% %CopyrightEnd%
%%----------------------------------------------------------------------
%% File : xmerl_sax_parser.erl
%% Description : XML SAX parse API module.
%%
-%% Created : 4 Jun 2008
+%% Created : 4 Jun 2008
%%----------------------------------------------------------------------
-module(xmerl_sax_parser).
@@ -72,9 +72,9 @@ file(Name,Options) ->
CL = filename:absname(Dir),
File = filename:basename(Name),
ContinuationFun = fun default_continuation_cb/1,
- Res = stream(<<>>,
+ Res = stream(<<>>,
[{continuation_fun, ContinuationFun},
- {continuation_state, FD},
+ {continuation_state, FD},
{current_location, CL},
{entity, File}
|Options],
@@ -101,39 +101,39 @@ stream(Xml, Options, InputType) when is_list(Xml), is_list(Options) ->
State = parse_options(Options, initial_state()),
case State#xmerl_sax_parser_state.file_type of
dtd ->
- xmerl_sax_parser_list:parse_dtd(Xml,
+ xmerl_sax_parser_list:parse_dtd(Xml,
State#xmerl_sax_parser_state{encoding = list,
input_type = InputType});
normal ->
- xmerl_sax_parser_list:parse(Xml,
+ xmerl_sax_parser_list:parse(Xml,
State#xmerl_sax_parser_state{encoding = list,
input_type = InputType})
end;
stream(Xml, Options, InputType) when is_binary(Xml), is_list(Options) ->
- case parse_options(Options, initial_state()) of
+ case parse_options(Options, initial_state()) of
{error, Reason} -> {error, Reason};
State ->
- ParseFunction =
+ ParseFunction =
case State#xmerl_sax_parser_state.file_type of
dtd ->
parse_dtd;
normal ->
parse
end,
- try
+ try
{Xml1, State1} = detect_charset(Xml, State),
parse_binary(Xml1,
State1#xmerl_sax_parser_state{input_type = InputType},
ParseFunction)
catch
throw:{fatal_error, {State2, Reason}} ->
- {fatal_error,
+ {fatal_error,
{
State2#xmerl_sax_parser_state.current_location,
- State2#xmerl_sax_parser_state.entity,
+ State2#xmerl_sax_parser_state.entity,
1
},
- Reason, [],
+ Reason, [],
State2#xmerl_sax_parser_state.event_state}
end
end.
@@ -157,7 +157,7 @@ parse_binary(Xml, #xmerl_sax_parser_state{encoding={utf16,big}}=State, F) ->
xmerl_sax_parser_utf16be:F(Xml, State);
parse_binary(Xml, #xmerl_sax_parser_state{encoding=latin1}=State, F) ->
xmerl_sax_parser_latin1:F(Xml, State);
-parse_binary(_, #xmerl_sax_parser_state{encoding=Enc}, State) ->
+parse_binary(_, #xmerl_sax_parser_state{encoding=Enc}, State) ->
?fatal_error(State, lists:flatten(io_lib:format("Charcter set ~p not supported", [Enc]))).
%%----------------------------------------------------------------------
@@ -177,9 +177,9 @@ initial_state() ->
%%----------------------------------------------------------------------
%% Function: parse_options(Options, State)
%% Input: Options = [Option]
-%% Option = {event_state, term()} | {event_fun, fun()} |
+%% Option = {event_state, term()} | {event_fun, fun()} |
%% {continuation_state, term()} | {continuation_fun, fun()} |
-%% {encoding, Encoding} | {file_type, FT}
+%% {encoding, Encoding} | {file_type, FT}
%% FT = normal | dtd
%% Encoding = utf8 | utf16le | utf16be | list | iso8859
%% State = #xmerl_sax_parser_state{}
@@ -200,7 +200,7 @@ parse_options([{file_type, FT} |Options], State) when FT==normal; FT==dtd ->
parse_options(Options, State#xmerl_sax_parser_state{file_type = FT});
parse_options([{encoding, E} |Options], State) ->
case check_encoding_option(E) of
- {error, Reason} ->
+ {error, Reason} ->
{error, Reason};
Enc ->
parse_options(Options, State#xmerl_sax_parser_state{encoding = Enc})
@@ -231,7 +231,7 @@ check_encoding_option(E) ->
%% Description: Detects which character set is used in a binary stream.
%%----------------------------------------------------------------------
detect_charset(<<>>, #xmerl_sax_parser_state{continuation_fun = undefined} = State) ->
- ?fatal_error(State, "Can't detect character encoding due to lack of indata");
+ ?fatal_error(State, "Can't detect character encoding due to lack of indata");
detect_charset(<<>>, State) ->
cf(<<>>, State, fun detect_charset/2);
detect_charset(Bytes, State) ->
@@ -269,22 +269,14 @@ detect_charset_1(<<16#3C, 16#3F, 16#78, 16#6D>> = Xml, State) ->
cf(Xml, State, fun detect_charset_1/2);
detect_charset_1(<<16#3C, 16#3F, 16#78, 16#6D, 16#6C, Xml2/binary>>, State) ->
{Xml3, State1} = read_until_end_of_xml_directive(Xml2, State),
- case parse_xml_directive(Xml3) of
- {error, Reason} ->
- ?fatal_error(State, Reason);
- AttrList ->
- case lists:keysearch("encoding", 1, AttrList) of
- {value, {_, E}} ->
- case convert_encoding(E) of
- {error, Reason} ->
- ?fatal_error(State, Reason);
- Enc ->
- {<<16#3C, 16#3F, 16#78, 16#6D, 16#6C, Xml3/binary>>,
- State1#xmerl_sax_parser_state{encoding=Enc}}
- end;
- _ ->
- {<<16#3C, 16#3F, 16#78, 16#6D, 16#6C, Xml3/binary>>, State1}
- end
+ AttrList = parse_xml_directive(Xml3, State),
+ case lists:keysearch("encoding", 1, AttrList) of
+ {value, {_, E}} ->
+ Enc = convert_encoding(E, State),
+ {<<16#3C, 16#3F, 16#78, 16#6D, 16#6C, Xml3/binary>>,
+ State1#xmerl_sax_parser_state{encoding=Enc}};
+ _ ->
+ {<<16#3C, 16#3F, 16#78, 16#6D, 16#6C, Xml3/binary>>, State1}
end;
detect_charset_1(Xml, State) ->
{Xml, State}.
@@ -295,7 +287,7 @@ detect_charset_1(Xml, State) ->
%% Output: utf8 | iso8859
%% Description: Converting 7,8 bit and utf8 encoding strings to internal format.
%%----------------------------------------------------------------------
-convert_encoding(Enc) -> %% Just for 7,8 bit + utf8
+convert_encoding(Enc, State) -> %% Just for 7,8 bit + utf8
case string:to_lower(Enc) of
"utf-8" -> utf8;
"us-ascii" -> utf8;
@@ -309,19 +301,19 @@ convert_encoding(Enc) -> %% Just for 7,8 bit + utf8
"iso-8859-7" -> latin1;
"iso-8859-8" -> latin1;
"iso-8859-9" -> latin1;
- _ -> {error, "Unknown encoding: " ++ Enc}
+ _ -> ?fatal_error(State, "Unknown encoding: " ++ Enc)
end.
%%----------------------------------------------------------------------
%% Function: parse_xml_directive(Xml)
%% Input: Xml = binary()
%% Acc = list()
-%% Output:
+%% Output:
%% Description: Parsing the xml declaration from the input stream.
%%----------------------------------------------------------------------
-parse_xml_directive(<<C, Rest/binary>>) when ?is_whitespace(C) ->
- parse_xml_directive_1(Rest, []).
-
+parse_xml_directive(<<C, Rest/binary>>, State) when ?is_whitespace(C) ->
+ parse_xml_directive_1(Rest, [], State).
+
%%----------------------------------------------------------------------
%% Function: parse_xml_directive_1(Xml, Acc) -> [{Name, Value}]
%% Input: Xml = binary()
@@ -331,20 +323,20 @@ parse_xml_directive(<<C, Rest/binary>>) when ?is_whitespace(C) ->
%% Output: see above
%% Description: Parsing the xml declaration from the input stream.
%%----------------------------------------------------------------------
-parse_xml_directive_1(<<C, Rest/binary>>, Acc) when ?is_whitespace(C) ->
- parse_xml_directive_1(Rest, Acc);
-parse_xml_directive_1(<<"?>", _/binary>>, Acc) ->
+parse_xml_directive_1(<<C, Rest/binary>>, Acc, State) when ?is_whitespace(C) ->
+ parse_xml_directive_1(Rest, Acc, State);
+parse_xml_directive_1(<<"?>", _/binary>>, Acc, _State) ->
Acc;
-parse_xml_directive_1(<<C, Rest/binary>>, Acc) when 97 =< C, C =< 122 ->
+parse_xml_directive_1(<<C, Rest/binary>>, Acc, State) when 97 =< C, C =< 122 ->
{Name, Rest1} = parse_name(Rest, [C]),
- Rest2 = parse_eq(Rest1),
- {Value, Rest3} = parse_value(Rest2),
- parse_xml_directive_1(Rest3, [{Name, Value} |Acc]);
-parse_xml_directive_1(_, _) ->
- {error, "Unknown attribute in xml directive"}.
+ Rest2 = parse_eq(Rest1, State),
+ {Value, Rest3} = parse_value(Rest2, State),
+ parse_xml_directive_1(Rest3, [{Name, Value} |Acc], State);
+parse_xml_directive_1(_, _, State) ->
+ ?fatal_error(State, "Unknown attribute in xml directive").
%%----------------------------------------------------------------------
-%% Function: parse_xml_directive_1(Xml, Acc) -> Name
+%% Function: parse_name(Xml, Acc) -> Name
%% Input: Xml = binary()
%% Acc = string()
%% Output: Name = string()
@@ -361,10 +353,12 @@ parse_name(Rest, Acc) ->
%% Output: Rest = binary()
%% Description: Reads an '=' from the stream.
%%----------------------------------------------------------------------
-parse_eq(<<C, Rest/binary>>) when ?is_whitespace(C) ->
- parse_eq(Rest);
-parse_eq(<<"=", Rest/binary>>) ->
- Rest.
+parse_eq(<<C, Rest/binary>>, State) when ?is_whitespace(C) ->
+ parse_eq(Rest, State);
+parse_eq(<<"=", Rest/binary>>, _State) ->
+ Rest;
+parse_eq(_, State) ->
+ ?fatal_error(State, "expecting = or whitespace").
%%----------------------------------------------------------------------
%% Function: parse_value(Xml) -> {Value, Rest}
@@ -373,10 +367,12 @@ parse_eq(<<"=", Rest/binary>>) ->
%% Rest = binary()
%% Description: Parsing an attribute value from the stream.
%%----------------------------------------------------------------------
-parse_value(<<C, Rest/binary>>) when ?is_whitespace(C) ->
- parse_value(Rest);
-parse_value(<<C, Rest/binary>>) when C == $'; C == $" ->
- parse_value_1(Rest, C, []).
+parse_value(<<C, Rest/binary>>, State) when ?is_whitespace(C) ->
+ parse_value(Rest, State);
+parse_value(<<C, Rest/binary>>, _State) when C == $'; C == $" ->
+ parse_value_1(Rest, C, []);
+parse_value(_, State) ->
+ ?fatal_error(State, "\', \" or whitespace expected").
%%----------------------------------------------------------------------
%% Function: parse_value_1(Xml, Stop, Acc) -> {Value, Rest}
@@ -431,7 +427,7 @@ read_until_end_of_xml_directive(Rest, State) ->
nomatch ->
case cf(Rest, State) of
{<<>>, _} ->
- ?fatal_error(State, "Can't detect character encoding due to lack of indata");
+ ?fatal_error(State, "Can't detect character encoding due to lack of indata");
{NewBytes, NewState} ->
read_until_end_of_xml_directive(NewBytes, NewState)
end;
@@ -450,9 +446,9 @@ read_until_end_of_xml_directive(Rest, State) ->
%% input stream and calls the fun in NextCall.
%%----------------------------------------------------------------------
cf(_Rest, #xmerl_sax_parser_state{continuation_fun = undefined} = State) ->
- ?fatal_error(State, "Continuation function undefined");
+ ?fatal_error(State, "Continuation function undefined");
cf(Rest, #xmerl_sax_parser_state{continuation_fun = CFun, continuation_state = CState} = State) ->
- Result =
+ Result =
try
CFun(CState)
catch
@@ -463,9 +459,9 @@ cf(Rest, #xmerl_sax_parser_state{continuation_fun = CFun, continuation_state = C
end,
case Result of
{<<>>, _} ->
- ?fatal_error(State, "Can't detect character encoding due to lack of indata");
+ ?fatal_error(State, "Can't detect character encoding due to lack of indata");
{NewBytes, NewContState} ->
- {<<Rest/binary, NewBytes/binary>>,
+ {<<Rest/binary, NewBytes/binary>>,
State#xmerl_sax_parser_state{continuation_state = NewContState}}
end.
@@ -479,10 +475,10 @@ cf(Rest, #xmerl_sax_parser_state{continuation_fun = CFun, continuation_state = C
%% input stream and calls the fun in NextCall.
%%----------------------------------------------------------------------
cf(_Rest, #xmerl_sax_parser_state{continuation_fun = undefined} = State, _) ->
- ?fatal_error(State, "Continuation function undefined");
-cf(Rest, #xmerl_sax_parser_state{continuation_fun = CFun, continuation_state = CState} = State,
+ ?fatal_error(State, "Continuation function undefined");
+cf(Rest, #xmerl_sax_parser_state{continuation_fun = CFun, continuation_state = CState} = State,
NextCall) ->
- Result =
+ Result =
try
CFun(CState)
catch
@@ -493,8 +489,8 @@ cf(Rest, #xmerl_sax_parser_state{continuation_fun = CFun, continuation_state = C
end,
case Result of
{<<>>, _} ->
- ?fatal_error(State, "Can't detect character encoding due to lack of indata");
+ ?fatal_error(State, "Can't detect character encoding due to lack of indata");
{NewBytes, NewContState} ->
- NextCall(<<Rest/binary, NewBytes/binary>>,
+ NextCall(<<Rest/binary, NewBytes/binary>>,
State#xmerl_sax_parser_state{continuation_state = NewContState})
end.
diff --git a/lib/xmerl/src/xmerl_sax_parser_base.erlsrc b/lib/xmerl/src/xmerl_sax_parser_base.erlsrc
index 1dca9608cb..ef753c7148 100644
--- a/lib/xmerl/src/xmerl_sax_parser_base.erlsrc
+++ b/lib/xmerl/src/xmerl_sax_parser_base.erlsrc
@@ -3679,7 +3679,7 @@ create_tempfile(Template) ->
false ->
case os:getenv("TEMP") of
false ->
- throw({error, "Variabel TMP or TEMP doesn't exist"});
+ throw({error, "Variable TMP or TEMP doesn't exist"});
P2 ->
P2
end;
diff --git a/lib/xmerl/src/xmerl_scan.erl b/lib/xmerl/src/xmerl_scan.erl
index a1f6ad4e2c..d76ed5c820 100644
--- a/lib/xmerl/src/xmerl_scan.erl
+++ b/lib/xmerl/src/xmerl_scan.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -279,7 +279,7 @@ int_file_decl(F, Options,_ExtCharset) ->
%% @spec string(Text::list()) -> {xmlElement(),Rest}
%% Rest = list()
-%% @equiv string(Test, [])
+%% @equiv string(Text, [])
string(Str) ->
string(Str, []).
@@ -2410,15 +2410,22 @@ scan_att_chars("&" ++ T, S0, Delim, Acc, TmpAcc,AT,IsNorm) -> % Reference
true ->
scan_att_chars(T1,S1,Delim,[ExpRef|Acc],[ExpRef|TmpAcc],AT,IsNorm);
_ ->
- Ch = string_to_char_set(S#xmerl_scanner.encoding, ExpRef),
case T of
"#" ++ _ ->
%% normalization rules (sec 3.3.3) require that for
%% character references, the referenced character be
%% added directly to the normalized value
- scan_att_chars(T1, S1, Delim, Ch ++ Acc,TmpAcc, AT,IsNorm);
+ {T2,S2,IsNorm2} =
+ if
+ ?whitespace(hd(ExpRef)) ->
+ normalize(T1, S1, IsNorm);
+ true ->
+ {T1, S1, IsNorm}
+ end,
+ scan_att_chars(T2, S2, Delim, ExpRef ++ Acc, TmpAcc, AT, IsNorm2);
_ ->
- scan_att_chars(Ch ++ T1, S1, Delim, Acc,TmpAcc, AT,IsNorm)
+ Ch = string_to_char_set(S#xmerl_scanner.encoding, ExpRef),
+ scan_att_chars(Ch ++ T1, S1, Delim, Acc, TmpAcc, AT, IsNorm)
end
end;
scan_att_chars("<" ++ _T, S0, _Delim, _Acc,_, _,_) -> % Tags not allowed here
@@ -3964,7 +3971,7 @@ normalize(T,S,IsNorm) ->
{_,T,S} ->
{T,S,IsNorm};
{_,T1,S1} ->
- {T1,S1,true}
+ normalize(T1,S1,true)
end.
diff --git a/lib/xmerl/src/xmerl_xsd.erl b/lib/xmerl/src/xmerl_xsd.erl
index a89b3159ec..2836bb0e5b 100644
--- a/lib/xmerl/src/xmerl_xsd.erl
+++ b/lib/xmerl/src/xmerl_xsd.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,7 +18,7 @@
%% %CopyrightEnd%
%%
-%% @doc Interface module for XML Schema vlidation.
+%% @doc Interface module for XML Schema validation.
%% It handles the W3.org
%% <a href="http://www.w3.org/XML/Schema#dev">specifications</a>
%% of XML Schema second edition 28 october 2004. For an introduction to
diff --git a/lib/xmerl/test/xmerl_SUITE_data/eventp/CMOM.xml b/lib/xmerl/test/xmerl_SUITE_data/eventp/CMOM.xml
index 7c64046897..0379c18214 100644
--- a/lib/xmerl/test/xmerl_SUITE_data/eventp/CMOM.xml
+++ b/lib/xmerl/test/xmerl_SUITE_data/eventp/CMOM.xml
@@ -276,7 +276,7 @@
</exception>
<exception name="UpgradeNotPossibleException">
- <description>Before an upgrade is started it was found that the upgrade can not take place. A possible reason is that the upgrade package that is running in the node is not in the upgrade window of this upgrade package. </description>
+ <description>Before an upgrade is started it was found that the upgrade cannot take place. A possible reason is that the upgrade package that is running in the node is not in the upgrade window of this upgrade package. </description>
<exceptionParameter name="message">
<dataType>
<string/>
@@ -1703,7 +1703,7 @@ Example:
<exception name="NoSuchAttributeException">
<description>Exception thrown when an MO attribute is requested to be accessed but the access
-method for the is not defined (the attribute can not be accessed)</description>
+method for the is not defined (the attribute cannot be accessed)</description>
</exception>
<exception name="MoCardinalityViolationException">
@@ -3125,7 +3125,7 @@ active = Synchronization is used in system clock generation.
<description>RefState can have the following values:
failed = synchronization reference is not capable to perform its required tasks.
degraded = capability of synchronization reference to perform its required tasks is degraded e.g. because of signal level degradation. This value is only applicable for traffic carrying (ET physical path termination) synchronization references. Note: attribute degradationIsFault controls whether synchronization reference degradation is interpreted as a synchronization reference fault or not.
-lossOfTracking = system clock regulation algorithm on TU board can not follow the 8kHz synchronization reference signal either because of the poor quality of the signal or because of a HW fault at TU board. If all synchronization references repeatedly end up to state lossOfTracking, fault is likely in TU HW.
+lossOfTracking = system clock regulation algorithm on TU board cannot follow the 8kHz synchronization reference signal either because of the poor quality of the signal or because of a HW fault at TU board. If all synchronization references repeatedly end up to state lossOfTracking, fault is likely in TU HW.
ok = synchronization reference is capable of performing its required tasks.
</description>
<enumMember name="failed">
@@ -10264,7 +10264,7 @@ Note! This attribute cannot have a value larger than for 'egressAtmPcr'.</descri
<attribute name="ingressAtmMcr">
<description>Ingress minimum desired cell rate (cells/s).
-Only positive vaues allowed. This attribute is mandatory only when serviceCategory is UBR+.
+Only positive values allowed. This attribute is mandatory only when serviceCategory is UBR+.
Note! When 'serviceCategory' is set to CBR or UBR this attribute has no relevance and the value submitted is ignored by the system.
@@ -11270,7 +11270,7 @@ Note! This action requires a transaction.</description>
The changing of the IP address with operation assignIpAddress might cause interruption of the communication if the network management tool is connected via the ethernet link.
-Note: The EthernetLink MO can not be deleted!
+Note: The EthernetLink MO cannot be deleted!
Note: The performance monitoring counters in the EthernetLink MO has a "Wrap-around time" of approximately 2 hours.
</description>
@@ -11532,8 +11532,8 @@ Note! This action requires a transaction.</description>
<description>This MO holds the IP routing table.
The IpRoutingTable MO is automatically created when the Ip MO is created.
-The IpRoutingTable MO can not be created manually.
-The IpRoutingTable MO can not be deleted.
+The IpRoutingTable MO cannot be created manually.
+The IpRoutingTable MO cannot be deleted.
</description>
<systemCreated/>
<attribute name="userLabel">
@@ -12967,7 +12967,7 @@ Note! When using fractional atm, timeslot 1 must be a part of the fraction.
Note! ETM1 does not support EPD and PPD
-Note! ETM1 does not have a proper buffer management. Thus fairness of UBR+ traffic can not be guaranteed and shaping on UBR+ traffic is not possible.
+Note! ETM1 does not have a proper buffer management. Thus fairness of UBR+ traffic cannot be guaranteed and shaping on UBR+ traffic is not possible.
Note! The number of VCC TP+VPC TP with performance monitoring enabled (i.e. PM mode &lt;&gt; off) is restricted to 1 per port.
</description>
@@ -13371,7 +13371,7 @@ Struct element description :
-Date is in string format, max length is 40. Format for date is: weekday month date hour:min:seconds year.
-Status is in string format, max length is 40.
-Note! The identity can not be the same as name. Identity should contain the product identity.
+Note! The identity cannot be the same as name. Identity should contain the product identity.
</description>
@@ -13562,7 +13562,7 @@ Note! For comment and operatorName spaces (' ') are also allowed within the stri
This action does not require a transaction.
-Note! The configurationVersionName and identity can not be the same. The identity should be the product identity.
+Note! The configurationVersionName and identity cannot be the same. The identity should be the product identity.
</description>
<returnType>
<void/>
@@ -17367,7 +17367,7 @@ NOTE: There is a restriction of a maximum of 32 Mtp2Tp's per MP.</description>
<attribute name="mtp2ProfileItuId">
<description>Reference to a Mtp2ProfileItu MO.
-Note: The bitRate can not be changed.</description>
+Note: The bitRate cannot be changed.</description>
<mandatory/>
<noNotification/>
<dataType>
@@ -17566,7 +17566,7 @@ NOTE: There is a restriction of a maximum of 32 Mtp2Tp's per MP.</description>
<attribute name="mtp2ProfileAnsiId">
<description>Reference to a Mtp2ProfileAnsi MO.
-Note: The bitRate can not be changed.</description>
+Note: The bitRate cannot be changed.</description>
<mandatory/>
<noNotification/>
<dataType>
@@ -21777,7 +21777,7 @@ Each E1/DS1/J1 channel can suport up to 2 VP connections.
The ET-MC41 board support one biderectional F4/F5 PM flow per E1 channel.
-Note! The ETMC41 supports IMA. However the E1 ports being part of the same IMA group can not be selected randomly.
+Note! The ETMC41 supports IMA. However the E1 ports being part of the same IMA group cannot be selected randomly.
Note! The number of VCC TP+VPC TP with performance monitoring enabled (i.e. PM mode &lt;&gt; off) is restricted to 1 / port
@@ -21883,7 +21883,7 @@ NOTE: There is a restriction of a maximum of 32 Mtp2Tp's per MP.
<attribute name="mtp2ProfileChinaId">
<description>Reference to a Mtp2ProfileChina MO.
-Note: The bitRate can not be changed.</description>
+Note: The bitRate cannot be changed.</description>
<mandatory/>
<noNotification/>
<dataType>
diff --git a/lib/xmerl/test/xmerl_SUITE_data/eventp/CelloMOM.xml b/lib/xmerl/test/xmerl_SUITE_data/eventp/CelloMOM.xml
index 8f8cf54505..3b9ccac0f4 100644
--- a/lib/xmerl/test/xmerl_SUITE_data/eventp/CelloMOM.xml
+++ b/lib/xmerl/test/xmerl_SUITE_data/eventp/CelloMOM.xml
@@ -276,7 +276,7 @@
</exception>
<exception name="UpgradeNotPossibleException">
- <description>Before an upgrade is started it was found that the upgrade can not take place. A possible reason is that the upgrade package that is running in the node is not in the upgrade window of this upgrade package. </description>
+ <description>Before an upgrade is started it was found that the upgrade cannot take place. A possible reason is that the upgrade package that is running in the node is not in the upgrade window of this upgrade package. </description>
<exceptionParameter name="message">
<dataType>
<string/>
@@ -1703,7 +1703,7 @@ Example:
<exception name="NoSuchAttributeException">
<description>Exception thrown when an MO attribute is requested to be accessed but the access
-method for the is not defined (the attribute can not be accessed)</description>
+method for the is not defined (the attribute cannot be accessed)</description>
</exception>
<exception name="MoCardinalityViolationException">
@@ -3125,7 +3125,7 @@ active = Synchronization is used in system clock generation.
<description>RefState can have the following values:
failed = synchronization reference is not capable to perform its required tasks.
degraded = capability of synchronization reference to perform its required tasks is degraded e.g. because of signal level degradation. This value is only applicable for traffic carrying (ET physical path termination) synchronization references. Note: attribute degradationIsFault controls whether synchronization reference degradation is interpreted as a synchronization reference fault or not.
-lossOfTracking = system clock regulation algorithm on TU board can not follow the 8kHz synchronization reference signal either because of the poor quality of the signal or because of a HW fault at TU board. If all synchronization references repeatedly end up to state lossOfTracking, fault is likely in TU HW.
+lossOfTracking = system clock regulation algorithm on TU board cannot follow the 8kHz synchronization reference signal either because of the poor quality of the signal or because of a HW fault at TU board. If all synchronization references repeatedly end up to state lossOfTracking, fault is likely in TU HW.
ok = synchronization reference is capable of performing its required tasks.
</description>
<enumMember name="failed">
@@ -10264,7 +10264,7 @@ Note! This attribute cannot have a value larger than for 'egressAtmPcr'.</descri
<attribute name="ingressAtmMcr">
<description>Ingress minimum desired cell rate (cells/s).
-Only positive vaues allowed. This attribute is mandatory only when serviceCategory is UBR+.
+Only positive values allowed. This attribute is mandatory only when serviceCategory is UBR+.
Note! When 'serviceCategory' is set to CBR or UBR this attribute has no relevance and the value submitted is ignored by the system.
@@ -11270,7 +11270,7 @@ Note! This action requires a transaction.</description>
The changing of the IP address with operation assignIpAddress might cause interruption of the communication if the network management tool is connected via the ethernet link.
-Note: The EthernetLink MO can not be deleted!
+Note: The EthernetLink MO cannot be deleted!
Note: The performance monitoring counters in the EthernetLink MO has a "Wrap-around time" of approximately 2 hours.
</description>
@@ -11532,8 +11532,8 @@ Note! This action requires a transaction.</description>
<description>This MO holds the IP routing table.
The IpRoutingTable MO is automatically created when the Ip MO is created.
-The IpRoutingTable MO can not be created manually.
-The IpRoutingTable MO can not be deleted.
+The IpRoutingTable MO cannot be created manually.
+The IpRoutingTable MO cannot be deleted.
</description>
<systemCreated/>
<attribute name="userLabel">
@@ -12967,7 +12967,7 @@ Note! When using fractional atm, timeslot 1 must be a part of the fraction.
Note! ETM1 does not support EPD and PPD
-Note! ETM1 does not have a proper buffer management. Thus fairness of UBR+ traffic can not be guaranteed and shaping on UBR+ traffic is not possible.
+Note! ETM1 does not have a proper buffer management. Thus fairness of UBR+ traffic cannot be guaranteed and shaping on UBR+ traffic is not possible.
Note! The number of VCC TP+VPC TP with performance monitoring enabled (i.e. PM mode &lt;&gt; off) is restricted to 1 per port.
</description>
@@ -13371,7 +13371,7 @@ Struct element description :
-Date is in string format, max length is 40. Format for date is: weekday month date hour:min:seconds year.
-Status is in string format, max length is 40.
-Note! The identity can not be the same as name. Identity should contain the product identity.
+Note! The identity cannot be the same as name. Identity should contain the product identity.
</description>
@@ -13562,7 +13562,7 @@ Note! For comment and operatorName spaces (' ') are also allowed within the stri
This action does not require a transaction.
-Note! The configurationVersionName and identity can not be the same. The identity should be the product identity.
+Note! The configurationVersionName and identity cannot be the same. The identity should be the product identity.
</description>
<returnType>
<void/>
@@ -17367,7 +17367,7 @@ NOTE: There is a restriction of a maximum of 32 Mtp2Tp's per MP.</description>
<attribute name="mtp2ProfileItuId">
<description>Reference to a Mtp2ProfileItu MO.
-Note: The bitRate can not be changed.</description>
+Note: The bitRate cannot be changed.</description>
<mandatory/>
<noNotification/>
<dataType>
@@ -17566,7 +17566,7 @@ NOTE: There is a restriction of a maximum of 32 Mtp2Tp's per MP.</description>
<attribute name="mtp2ProfileAnsiId">
<description>Reference to a Mtp2ProfileAnsi MO.
-Note: The bitRate can not be changed.</description>
+Note: The bitRate cannot be changed.</description>
<mandatory/>
<noNotification/>
<dataType>
@@ -21777,7 +21777,7 @@ Each E1/DS1/J1 channel can suport up to 2 VP connections.
The ET-MC41 board support one biderectional F4/F5 PM flow per E1 channel.
-Note! The ETMC41 supports IMA. However the E1 ports being part of the same IMA group can not be selected randomly.
+Note! The ETMC41 supports IMA. However the E1 ports being part of the same IMA group cannot be selected randomly.
Note! The number of VCC TP+VPC TP with performance monitoring enabled (i.e. PM mode &lt;&gt; off) is restricted to 1 / port
@@ -21883,7 +21883,7 @@ NOTE: There is a restriction of a maximum of 32 Mtp2Tp's per MP.
<attribute name="mtp2ProfileChinaId">
<description>Reference to a Mtp2ProfileChina MO.
-Note: The bitRate can not be changed.</description>
+Note: The bitRate cannot be changed.</description>
<mandatory/>
<noNotification/>
<dataType>
diff --git a/lib/xmerl/test/xmerl_xsd_lib.erl b/lib/xmerl/test/xmerl_xsd_lib.erl
index 6006cf500f..39300cd6cb 100644
--- a/lib/xmerl/test/xmerl_xsd_lib.erl
+++ b/lib/xmerl/test/xmerl_xsd_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -94,8 +94,9 @@ return_results2({NewFail, NewSuccess, NewMal, NewNotMal}, NumSucc, SkippedN, Tot
_ -> io_lib:format("These ~p skipped tests were malicious, but succeeds now: ~p~n",
[length(NewNotMal), NewNotMal])
end,
- ct:comment(io_lib:format("~p successful tests, ~p skipped tests of totally ~p test cases. ~n" ++
- NFComm ++ NSComm ++ NMComm ++ NNMComm, [NumSucc, SkippedN, TotN])),
+ ct:comment(io_lib:format("~p successful tests, ~p skipped tests of totally ~p test cases. ~n~ts",
+ [NumSucc, SkippedN, TotN,
+ NFComm ++ NSComm ++ NMComm ++ NNMComm])),
[] = NewFail.
%% return_results2(Diff,{STErrs,STOther},{ITErrs,ITOther},TotN) ->
diff --git a/lib/xmerl/vsn.mk b/lib/xmerl/vsn.mk
index ddff0c8894..08696606e6 100644
--- a/lib/xmerl/vsn.mk
+++ b/lib/xmerl/vsn.mk
@@ -1 +1 @@
-XMERL_VSN = 1.3.16
+XMERL_VSN = 1.3.21